From 9146b9b261c34f476c9f83934e6da6a463ad51c7 Mon Sep 17 00:00:00 2001 From: bushing Date: Mon, 8 Dec 2008 05:17:03 +0000 Subject: [PATCH] set svn:eol-style=native for Externals/**.cpp git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@1440 8ced0084-cf51-0410-be5f-012b33b47a6e --- Externals/Bochs_disasm/PowerPCDisasm.cpp | 4494 +-- Externals/Bochs_disasm/stdafx.cpp | 16 +- Externals/wxWidgets/include/wx/arrimpl.cpp | 240 +- Externals/wxWidgets/include/wx/listimpl.cpp | 78 +- Externals/wxWidgets/include/wx/thrimpl.cpp | 660 +- Externals/wxWidgets/src/common/accesscmn.cpp | 52 +- Externals/wxWidgets/src/common/anidecod.cpp | 690 +- Externals/wxWidgets/src/common/animatecmn.cpp | 206 +- Externals/wxWidgets/src/common/appbase.cpp | 1692 +- Externals/wxWidgets/src/common/appcmn.cpp | 1382 +- Externals/wxWidgets/src/common/arcall.cpp | 82 +- Externals/wxWidgets/src/common/arcfind.cpp | 86 +- Externals/wxWidgets/src/common/archive.cpp | 196 +- Externals/wxWidgets/src/common/artprov.cpp | 676 +- Externals/wxWidgets/src/common/artstd.cpp | 534 +- Externals/wxWidgets/src/common/bmpbase.cpp | 422 +- Externals/wxWidgets/src/common/bookctrl.cpp | 994 +- Externals/wxWidgets/src/common/choiccmn.cpp | 110 +- Externals/wxWidgets/src/common/clipcmn.cpp | 126 +- Externals/wxWidgets/src/common/clntdata.cpp | 166 +- .../wxWidgets/src/common/clrpickercmn.cpp | 298 +- Externals/wxWidgets/src/common/cmdline.cpp | 2494 +- Externals/wxWidgets/src/common/cmdproc.cpp | 650 +- Externals/wxWidgets/src/common/cmndata.cpp | 1314 +- Externals/wxWidgets/src/common/colourcmn.cpp | 252 +- Externals/wxWidgets/src/common/combocmn.cpp | 4604 ++-- Externals/wxWidgets/src/common/config.cpp | 980 +- Externals/wxWidgets/src/common/containr.cpp | 1356 +- Externals/wxWidgets/src/common/convauto.cpp | 428 +- Externals/wxWidgets/src/common/cshelp.cpp | 1024 +- Externals/wxWidgets/src/common/ctrlcmn.cpp | 376 +- Externals/wxWidgets/src/common/ctrlsub.cpp | 394 +- Externals/wxWidgets/src/common/datacmn.cpp | 166 +- Externals/wxWidgets/src/common/datavcmn.cpp | 1822 +- Externals/wxWidgets/src/common/datetime.cpp | 9260 +++---- Externals/wxWidgets/src/common/datstrm.cpp | 1490 +- Externals/wxWidgets/src/common/db.cpp | 9048 +++--- Externals/wxWidgets/src/common/dbgrid.cpp | 1454 +- Externals/wxWidgets/src/common/dbtable.cpp | 5892 ++-- Externals/wxWidgets/src/common/dcbase.cpp | 2318 +- Externals/wxWidgets/src/common/dcbufcmn.cpp | 190 +- Externals/wxWidgets/src/common/dcgraph.cpp | 2052 +- Externals/wxWidgets/src/common/debugrpt.cpp | 1396 +- Externals/wxWidgets/src/common/dircmn.cpp | 714 +- Externals/wxWidgets/src/common/dlgcmn.cpp | 1130 +- Externals/wxWidgets/src/common/dndcmn.cpp | 62 +- Externals/wxWidgets/src/common/dobjcmn.cpp | 1034 +- Externals/wxWidgets/src/common/docmdi.cpp | 408 +- Externals/wxWidgets/src/common/docview.cpp | 4970 ++-- Externals/wxWidgets/src/common/dpycmn.cpp | 538 +- Externals/wxWidgets/src/common/dseldlg.cpp | 110 +- Externals/wxWidgets/src/common/dummy.cpp | 64 +- Externals/wxWidgets/src/common/dynarray.cpp | 1054 +- Externals/wxWidgets/src/common/dynlib.cpp | 646 +- Externals/wxWidgets/src/common/dynload.cpp | 724 +- Externals/wxWidgets/src/common/effects.cpp | 248 +- Externals/wxWidgets/src/common/emptydmy.cpp | 6 +- Externals/wxWidgets/src/common/encconv.cpp | 1062 +- Externals/wxWidgets/src/common/event.cpp | 2980 +- Externals/wxWidgets/src/common/evtloopcmn.cpp | 344 +- Externals/wxWidgets/src/common/execcmn.cpp | 244 +- Externals/wxWidgets/src/common/fddlgcmn.cpp | 204 +- Externals/wxWidgets/src/common/ffile.cpp | 536 +- Externals/wxWidgets/src/common/file.cpp | 1118 +- Externals/wxWidgets/src/common/fileback.cpp | 676 +- Externals/wxWidgets/src/common/fileconf.cpp | 4262 +-- Externals/wxWidgets/src/common/filefn.cpp | 4216 +-- Externals/wxWidgets/src/common/filename.cpp | 5074 ++-- .../wxWidgets/src/common/filepickercmn.cpp | 448 +- Externals/wxWidgets/src/common/filesys.cpp | 1368 +- Externals/wxWidgets/src/common/filtall.cpp | 72 +- Externals/wxWidgets/src/common/filtfind.cpp | 86 +- Externals/wxWidgets/src/common/fldlgcmn.cpp | 696 +- Externals/wxWidgets/src/common/fmapbase.cpp | 1474 +- Externals/wxWidgets/src/common/fontcmn.cpp | 1568 +- .../wxWidgets/src/common/fontenumcmn.cpp | 262 +- Externals/wxWidgets/src/common/fontmap.cpp | 1038 +- Externals/wxWidgets/src/common/fontmgrcmn.cpp | 690 +- .../wxWidgets/src/common/fontpickercmn.cpp | 362 +- Externals/wxWidgets/src/common/framecmn.cpp | 1180 +- Externals/wxWidgets/src/common/fs_arc.cpp | 1066 +- Externals/wxWidgets/src/common/fs_filter.cpp | 184 +- Externals/wxWidgets/src/common/fs_inet.cpp | 334 +- Externals/wxWidgets/src/common/fs_mem.cpp | 576 +- Externals/wxWidgets/src/common/ftp.cpp | 2016 +- Externals/wxWidgets/src/common/gaugecmn.cpp | 312 +- Externals/wxWidgets/src/common/gbsizer.cpp | 1568 +- Externals/wxWidgets/src/common/gdicmn.cpp | 1742 +- Externals/wxWidgets/src/common/geometry.cpp | 728 +- Externals/wxWidgets/src/common/gifdecod.cpp | 1812 +- Externals/wxWidgets/src/common/graphcmn.cpp | 1538 +- Externals/wxWidgets/src/common/hash.cpp | 2154 +- Externals/wxWidgets/src/common/hashmap.cpp | 304 +- Externals/wxWidgets/src/common/helpbase.cpp | 56 +- Externals/wxWidgets/src/common/http.cpp | 844 +- Externals/wxWidgets/src/common/iconbndl.cpp | 284 +- Externals/wxWidgets/src/common/imagall.cpp | 128 +- Externals/wxWidgets/src/common/imagbmp.cpp | 2712 +- Externals/wxWidgets/src/common/image.cpp | 6256 ++--- Externals/wxWidgets/src/common/imagfill.cpp | 616 +- Externals/wxWidgets/src/common/imaggif.cpp | 210 +- Externals/wxWidgets/src/common/imagiff.cpp | 1588 +- Externals/wxWidgets/src/common/imagjpeg.cpp | 960 +- Externals/wxWidgets/src/common/imagpcx.cpp | 1000 +- Externals/wxWidgets/src/common/imagpng.cpp | 1736 +- Externals/wxWidgets/src/common/imagpnm.cpp | 402 +- Externals/wxWidgets/src/common/imagtga.cpp | 1500 +- Externals/wxWidgets/src/common/imagtiff.cpp | 1030 +- Externals/wxWidgets/src/common/imagxpm.cpp | 448 +- Externals/wxWidgets/src/common/init.cpp | 1004 +- Externals/wxWidgets/src/common/intl.cpp | 7556 +++--- Externals/wxWidgets/src/common/ipcbase.cpp | 176 +- Externals/wxWidgets/src/common/layout.cpp | 2052 +- Externals/wxWidgets/src/common/lboxcmn.cpp | 294 +- Externals/wxWidgets/src/common/list.cpp | 1536 +- .../wxWidgets/src/common/listctrlcmn.cpp | 108 +- Externals/wxWidgets/src/common/log.cpp | 1676 +- Externals/wxWidgets/src/common/longlong.cpp | 2726 +- Externals/wxWidgets/src/common/matrix.cpp | 1202 +- .../wxWidgets/src/common/mediactrlcmn.cpp | 1118 +- Externals/wxWidgets/src/common/memory.cpp | 2296 +- Externals/wxWidgets/src/common/menucmn.cpp | 2330 +- Externals/wxWidgets/src/common/mimecmn.cpp | 1504 +- Externals/wxWidgets/src/common/module.cpp | 404 +- Externals/wxWidgets/src/common/msgout.cpp | 444 +- Externals/wxWidgets/src/common/mstream.cpp | 348 +- Externals/wxWidgets/src/common/nbkbase.cpp | 168 +- Externals/wxWidgets/src/common/object.cpp | 730 +- Externals/wxWidgets/src/common/overlaycmn.cpp | 394 +- Externals/wxWidgets/src/common/paper.cpp | 746 +- Externals/wxWidgets/src/common/pickerbase.cpp | 350 +- Externals/wxWidgets/src/common/platinfo.cpp | 672 +- Externals/wxWidgets/src/common/popupcmn.cpp | 1190 +- Externals/wxWidgets/src/common/powercmn.cpp | 118 +- Externals/wxWidgets/src/common/prntbase.cpp | 3522 +-- Externals/wxWidgets/src/common/process.cpp | 344 +- Externals/wxWidgets/src/common/protocol.cpp | 430 +- Externals/wxWidgets/src/common/quantize.cpp | 3308 +-- Externals/wxWidgets/src/common/radiocmn.cpp | 588 +- Externals/wxWidgets/src/common/regex.cpp | 1372 +- Externals/wxWidgets/src/common/rendcmn.cpp | 416 +- Externals/wxWidgets/src/common/rgncmn.cpp | 384 +- Externals/wxWidgets/src/common/sckaddr.cpp | 698 +- Externals/wxWidgets/src/common/sckfile.cpp | 114 +- Externals/wxWidgets/src/common/sckipc.cpp | 1538 +- Externals/wxWidgets/src/common/sckstrm.cpp | 270 +- Externals/wxWidgets/src/common/settcmn.cpp | 176 +- Externals/wxWidgets/src/common/sizer.cpp | 4522 +-- Externals/wxWidgets/src/common/socket.cpp | 2840 +- .../src/common/socketevtdispatch.cpp | 678 +- Externals/wxWidgets/src/common/srchcmn.cpp | 84 +- Externals/wxWidgets/src/common/sstream.cpp | 470 +- Externals/wxWidgets/src/common/statbar.cpp | 736 +- Externals/wxWidgets/src/common/stdpbase.cpp | 344 +- Externals/wxWidgets/src/common/stockitem.cpp | 556 +- Externals/wxWidgets/src/common/stopwatch.cpp | 744 +- Externals/wxWidgets/src/common/strconv.cpp | 7394 ++--- Externals/wxWidgets/src/common/stream.cpp | 2776 +- Externals/wxWidgets/src/common/string.cpp | 5264 ++-- Externals/wxWidgets/src/common/sysopt.cpp | 222 +- Externals/wxWidgets/src/common/tarstrm.cpp | 3058 +-- Externals/wxWidgets/src/common/taskbarcmn.cpp | 108 +- Externals/wxWidgets/src/common/tbarbase.cpp | 1492 +- Externals/wxWidgets/src/common/textbuf.cpp | 568 +- Externals/wxWidgets/src/common/textcmn.cpp | 1106 +- Externals/wxWidgets/src/common/textfile.cpp | 590 +- Externals/wxWidgets/src/common/timercmn.cpp | 176 +- Externals/wxWidgets/src/common/tokenzr.cpp | 458 +- Externals/wxWidgets/src/common/toplvcmn.cpp | 862 +- Externals/wxWidgets/src/common/treebase.cpp | 478 +- Externals/wxWidgets/src/common/txtstrm.cpp | 1040 +- Externals/wxWidgets/src/common/uri.cpp | 2596 +- Externals/wxWidgets/src/common/url.cpp | 1066 +- Externals/wxWidgets/src/common/utilscmn.cpp | 2824 +- Externals/wxWidgets/src/common/valgen.cpp | 1182 +- Externals/wxWidgets/src/common/validate.cpp | 90 +- Externals/wxWidgets/src/common/valtext.cpp | 688 +- Externals/wxWidgets/src/common/variant.cpp | 4060 +-- Externals/wxWidgets/src/common/wfstream.cpp | 812 +- Externals/wxWidgets/src/common/wincmn.cpp | 6410 ++--- Externals/wxWidgets/src/common/wxchar.cpp | 4574 ++-- Externals/wxWidgets/src/common/xpmdecod.cpp | 1628 +- Externals/wxWidgets/src/common/xti.cpp | 1534 +- Externals/wxWidgets/src/common/xtistrm.cpp | 1694 +- Externals/wxWidgets/src/common/xtixml.cpp | 1076 +- Externals/wxWidgets/src/common/zipstrm.cpp | 4850 ++-- Externals/wxWidgets/src/common/zstream.cpp | 856 +- Externals/wxWidgets/src/generic/aboutdlgg.cpp | 490 +- Externals/wxWidgets/src/generic/accel.cpp | 440 +- Externals/wxWidgets/src/generic/animateg.cpp | 1380 +- Externals/wxWidgets/src/generic/bmpcboxg.cpp | 954 +- Externals/wxWidgets/src/generic/busyinfo.cpp | 270 +- Externals/wxWidgets/src/generic/buttonbar.cpp | 1110 +- Externals/wxWidgets/src/generic/calctrl.cpp | 3676 +-- Externals/wxWidgets/src/generic/caret.cpp | 566 +- Externals/wxWidgets/src/generic/choicbkg.cpp | 656 +- Externals/wxWidgets/src/generic/choicdgg.cpp | 1112 +- .../wxWidgets/src/generic/clrpickerg.cpp | 264 +- Externals/wxWidgets/src/generic/collpaneg.cpp | 614 +- Externals/wxWidgets/src/generic/colour.cpp | 144 +- Externals/wxWidgets/src/generic/colrdlgg.cpp | 1172 +- Externals/wxWidgets/src/generic/combog.cpp | 966 +- Externals/wxWidgets/src/generic/datavgen.cpp | 3822 +-- Externals/wxWidgets/src/generic/datectlg.cpp | 1076 +- Externals/wxWidgets/src/generic/dbgrptg.cpp | 1050 +- Externals/wxWidgets/src/generic/dcpsg.cpp | 4528 +-- Externals/wxWidgets/src/generic/dirctrlg.cpp | 3414 +-- Externals/wxWidgets/src/generic/dirdlgg.cpp | 738 +- Externals/wxWidgets/src/generic/dragimgg.cpp | 1148 +- Externals/wxWidgets/src/generic/fdrepdlg.cpp | 582 +- Externals/wxWidgets/src/generic/filedlgg.cpp | 3290 +-- .../wxWidgets/src/generic/filepickerg.cpp | 172 +- Externals/wxWidgets/src/generic/fontdlgg.cpp | 1246 +- .../wxWidgets/src/generic/fontpickerg.cpp | 240 +- Externals/wxWidgets/src/generic/graphicc.cpp | 3020 +-- Externals/wxWidgets/src/generic/grid.cpp | 22644 ++++++++-------- Externals/wxWidgets/src/generic/gridctrl.cpp | 810 +- Externals/wxWidgets/src/generic/gridsel.cpp | 2354 +- Externals/wxWidgets/src/generic/helpext.cpp | 970 +- Externals/wxWidgets/src/generic/htmllbox.cpp | 1364 +- Externals/wxWidgets/src/generic/hyperlink.cpp | 568 +- Externals/wxWidgets/src/generic/icon.cpp | 90 +- Externals/wxWidgets/src/generic/imaglist.cpp | 552 +- Externals/wxWidgets/src/generic/laywin.cpp | 682 +- Externals/wxWidgets/src/generic/listbkg.cpp | 832 +- Externals/wxWidgets/src/generic/listctrl.cpp | 11908 ++++---- Externals/wxWidgets/src/generic/logg.cpp | 2458 +- Externals/wxWidgets/src/generic/mask.cpp | 152 +- Externals/wxWidgets/src/generic/mdig.cpp | 1640 +- Externals/wxWidgets/src/generic/msgdlgg.cpp | 318 +- Externals/wxWidgets/src/generic/notebook.cpp | 1524 +- Externals/wxWidgets/src/generic/numdlgg.cpp | 368 +- Externals/wxWidgets/src/generic/odcombo.cpp | 2202 +- Externals/wxWidgets/src/generic/paletteg.cpp | 290 +- Externals/wxWidgets/src/generic/panelg.cpp | 360 +- Externals/wxWidgets/src/generic/printps.cpp | 740 +- Externals/wxWidgets/src/generic/prntdlgg.cpp | 2200 +- Externals/wxWidgets/src/generic/progdlgg.cpp | 1346 +- Externals/wxWidgets/src/generic/propdlg.cpp | 452 +- Externals/wxWidgets/src/generic/regiong.cpp | 3838 +-- Externals/wxWidgets/src/generic/renderg.cpp | 1356 +- Externals/wxWidgets/src/generic/sashwin.cpp | 1416 +- Externals/wxWidgets/src/generic/scrlwing.cpp | 2950 +- Externals/wxWidgets/src/generic/selstore.cpp | 432 +- Externals/wxWidgets/src/generic/spinctlg.cpp | 782 +- Externals/wxWidgets/src/generic/splash.cpp | 402 +- Externals/wxWidgets/src/generic/splitter.cpp | 2098 +- Externals/wxWidgets/src/generic/srchctlg.cpp | 2432 +- Externals/wxWidgets/src/generic/statline.cpp | 176 +- Externals/wxWidgets/src/generic/statusbr.cpp | 974 +- Externals/wxWidgets/src/generic/tabg.cpp | 2580 +- Externals/wxWidgets/src/generic/textdlgg.cpp | 370 +- Externals/wxWidgets/src/generic/timer.cpp | 566 +- Externals/wxWidgets/src/generic/tipdlg.cpp | 694 +- Externals/wxWidgets/src/generic/tipwin.cpp | 760 +- Externals/wxWidgets/src/generic/toolbkg.cpp | 884 +- Externals/wxWidgets/src/generic/treebkg.cpp | 1582 +- Externals/wxWidgets/src/generic/treectlg.cpp | 7392 ++--- Externals/wxWidgets/src/generic/vlbox.cpp | 1306 +- Externals/wxWidgets/src/generic/vscroll.cpp | 1038 +- Externals/wxWidgets/src/generic/wizard.cpp | 1754 +- Externals/wxWidgets/src/msw/aboutdlg.cpp | 140 +- Externals/wxWidgets/src/msw/accel.cpp | 334 +- Externals/wxWidgets/src/msw/app.cpp | 1594 +- Externals/wxWidgets/src/msw/basemsw.cpp | 146 +- Externals/wxWidgets/src/msw/bitmap.cpp | 3612 +-- Externals/wxWidgets/src/msw/bmpbuttn.cpp | 1292 +- Externals/wxWidgets/src/msw/brush.cpp | 654 +- Externals/wxWidgets/src/msw/button.cpp | 1780 +- Externals/wxWidgets/src/msw/caret.cpp | 376 +- Externals/wxWidgets/src/msw/checkbox.cpp | 1176 +- Externals/wxWidgets/src/msw/checklst.cpp | 1076 +- Externals/wxWidgets/src/msw/choice.cpp | 1604 +- Externals/wxWidgets/src/msw/clipbrd.cpp | 1862 +- Externals/wxWidgets/src/msw/colordlg.cpp | 448 +- Externals/wxWidgets/src/msw/colour.cpp | 180 +- Externals/wxWidgets/src/msw/combo.cpp | 1482 +- Externals/wxWidgets/src/msw/combobox.cpp | 1616 +- Externals/wxWidgets/src/msw/control.cpp | 966 +- Externals/wxWidgets/src/msw/crashrpt.cpp | 766 +- Externals/wxWidgets/src/msw/cursor.cpp | 814 +- Externals/wxWidgets/src/msw/data.cpp | 36 +- Externals/wxWidgets/src/msw/datectrl.cpp | 736 +- Externals/wxWidgets/src/msw/dc.cpp | 5552 ++-- Externals/wxWidgets/src/msw/dcclient.cpp | 714 +- Externals/wxWidgets/src/msw/dcmemory.cpp | 388 +- Externals/wxWidgets/src/msw/dcprint.cpp | 968 +- Externals/wxWidgets/src/msw/dcscreen.cpp | 76 +- Externals/wxWidgets/src/msw/dde.cpp | 2190 +- Externals/wxWidgets/src/msw/debughlp.cpp | 1534 +- Externals/wxWidgets/src/msw/dialog.cpp | 994 +- Externals/wxWidgets/src/msw/dialup.cpp | 2676 +- Externals/wxWidgets/src/msw/dib.cpp | 1628 +- Externals/wxWidgets/src/msw/dir.cpp | 808 +- Externals/wxWidgets/src/msw/dirdlg.cpp | 502 +- Externals/wxWidgets/src/msw/display.cpp | 2080 +- Externals/wxWidgets/src/msw/dlmsw.cpp | 674 +- Externals/wxWidgets/src/msw/dragimag.cpp | 916 +- Externals/wxWidgets/src/msw/enhmeta.cpp | 920 +- Externals/wxWidgets/src/msw/evtloop.cpp | 592 +- Externals/wxWidgets/src/msw/fdrepdlg.cpp | 1092 +- Externals/wxWidgets/src/msw/filedlg.cpp | 1110 +- Externals/wxWidgets/src/msw/font.cpp | 2244 +- Externals/wxWidgets/src/msw/fontdlg.cpp | 262 +- Externals/wxWidgets/src/msw/fontenum.cpp | 584 +- Externals/wxWidgets/src/msw/fontutil.cpp | 588 +- Externals/wxWidgets/src/msw/frame.cpp | 2326 +- Externals/wxWidgets/src/msw/gauge95.cpp | 552 +- Externals/wxWidgets/src/msw/gdiimage.cpp | 1218 +- Externals/wxWidgets/src/msw/gdiobj.cpp | 120 +- Externals/wxWidgets/src/msw/glcanvas.cpp | 1330 +- Externals/wxWidgets/src/msw/graphics.cpp | 3146 +-- Externals/wxWidgets/src/msw/gsocket.cpp | 3138 +-- Externals/wxWidgets/src/msw/gsockmsw.cpp | 974 +- Externals/wxWidgets/src/msw/helpbest.cpp | 206 +- Externals/wxWidgets/src/msw/helpchm.cpp | 504 +- Externals/wxWidgets/src/msw/helpwin.cpp | 252 +- Externals/wxWidgets/src/msw/icon.cpp | 316 +- Externals/wxWidgets/src/msw/imaglist.cpp | 804 +- Externals/wxWidgets/src/msw/iniconf.cpp | 914 +- Externals/wxWidgets/src/msw/joystick.cpp | 1254 +- Externals/wxWidgets/src/msw/listbox.cpp | 1638 +- Externals/wxWidgets/src/msw/listctrl.cpp | 6424 ++--- Externals/wxWidgets/src/msw/main.cpp | 818 +- Externals/wxWidgets/src/msw/mdi.cpp | 3000 +- Externals/wxWidgets/src/msw/mediactrl.cpp | 8344 +++--- Externals/wxWidgets/src/msw/mediactrl_am.cpp | 4546 ++-- Externals/wxWidgets/src/msw/mediactrl_qt.cpp | 2624 +- .../wxWidgets/src/msw/mediactrl_wmp10.cpp | 3024 +-- Externals/wxWidgets/src/msw/menu.cpp | 2792 +- Externals/wxWidgets/src/msw/menuitem.cpp | 892 +- Externals/wxWidgets/src/msw/metafile.cpp | 1066 +- Externals/wxWidgets/src/msw/mimetype.cpp | 1700 +- Externals/wxWidgets/src/msw/minifram.cpp | 50 +- Externals/wxWidgets/src/msw/msgdlg.cpp | 308 +- Externals/wxWidgets/src/msw/mslu.cpp | 496 +- Externals/wxWidgets/src/msw/nativdlg.cpp | 660 +- Externals/wxWidgets/src/msw/notebook.cpp | 2898 +- Externals/wxWidgets/src/msw/ole/access.cpp | 4000 +-- Externals/wxWidgets/src/msw/ole/activex.cpp | 2316 +- Externals/wxWidgets/src/msw/ole/automtn.cpp | 1882 +- Externals/wxWidgets/src/msw/ole/dataobj.cpp | 2654 +- Externals/wxWidgets/src/msw/ole/dropsrc.cpp | 496 +- Externals/wxWidgets/src/msw/ole/droptgt.cpp | 1140 +- Externals/wxWidgets/src/msw/ole/oleutils.cpp | 640 +- Externals/wxWidgets/src/msw/ole/uuid.cpp | 344 +- Externals/wxWidgets/src/msw/ownerdrw.cpp | 984 +- Externals/wxWidgets/src/msw/palette.cpp | 318 +- Externals/wxWidgets/src/msw/pen.cpp | 774 +- Externals/wxWidgets/src/msw/penwin.cpp | 228 +- Externals/wxWidgets/src/msw/popupwin.cpp | 226 +- Externals/wxWidgets/src/msw/power.cpp | 224 +- Externals/wxWidgets/src/msw/printdlg.cpp | 2110 +- Externals/wxWidgets/src/msw/printwin.cpp | 894 +- Externals/wxWidgets/src/msw/radiobox.cpp | 1762 +- Externals/wxWidgets/src/msw/radiobut.cpp | 654 +- Externals/wxWidgets/src/msw/regconf.cpp | 1462 +- Externals/wxWidgets/src/msw/region.cpp | 936 +- Externals/wxWidgets/src/msw/registry.cpp | 2856 +- Externals/wxWidgets/src/msw/renderer.cpp | 1418 +- Externals/wxWidgets/src/msw/scrolbar.cpp | 684 +- Externals/wxWidgets/src/msw/settings.cpp | 976 +- Externals/wxWidgets/src/msw/slider95.cpp | 1372 +- Externals/wxWidgets/src/msw/snglinst.cpp | 260 +- Externals/wxWidgets/src/msw/sound.cpp | 418 +- Externals/wxWidgets/src/msw/spinbutt.cpp | 680 +- Externals/wxWidgets/src/msw/spinctrl.cpp | 1416 +- Externals/wxWidgets/src/msw/stackwalk.cpp | 822 +- Externals/wxWidgets/src/msw/statbmp.cpp | 668 +- Externals/wxWidgets/src/msw/statbox.cpp | 1140 +- Externals/wxWidgets/src/msw/statbr95.cpp | 834 +- Externals/wxWidgets/src/msw/statline.cpp | 262 +- Externals/wxWidgets/src/msw/stattext.cpp | 444 +- Externals/wxWidgets/src/msw/stdpaths.cpp | 688 +- Externals/wxWidgets/src/msw/tabctrl.cpp | 864 +- Externals/wxWidgets/src/msw/taskbar.cpp | 654 +- Externals/wxWidgets/src/msw/tbar95.cpp | 3594 +-- Externals/wxWidgets/src/msw/textctrl.cpp | 5938 ++-- Externals/wxWidgets/src/msw/tglbtn.cpp | 340 +- Externals/wxWidgets/src/msw/thread.cpp | 2828 +- Externals/wxWidgets/src/msw/timer.cpp | 326 +- Externals/wxWidgets/src/msw/tooltip.cpp | 912 +- Externals/wxWidgets/src/msw/toplevel.cpp | 2574 +- Externals/wxWidgets/src/msw/treectrl.cpp | 6308 ++--- Externals/wxWidgets/src/msw/urlmsw.cpp | 470 +- Externals/wxWidgets/src/msw/utils.cpp | 3152 +-- Externals/wxWidgets/src/msw/utilsexc.cpp | 1912 +- Externals/wxWidgets/src/msw/utilsgui.cpp | 1006 +- Externals/wxWidgets/src/msw/uxtheme.cpp | 354 +- Externals/wxWidgets/src/msw/volume.cpp | 1216 +- .../wxWidgets/src/msw/wince/checklst.cpp | 850 +- .../wxWidgets/src/msw/wince/choicece.cpp | 1176 +- Externals/wxWidgets/src/msw/wince/crt.cpp | 144 +- .../wxWidgets/src/msw/wince/filedlgwce.cpp | 266 +- .../wxWidgets/src/msw/wince/filefnwce.cpp | 422 +- Externals/wxWidgets/src/msw/wince/helpwce.cpp | 246 +- Externals/wxWidgets/src/msw/wince/menuce.cpp | 554 +- Externals/wxWidgets/src/msw/wince/net.cpp | 370 +- Externals/wxWidgets/src/msw/wince/tbarwce.cpp | 1302 +- .../wxWidgets/src/msw/wince/textctrlce.cpp | 2428 +- Externals/wxWidgets/src/msw/wince/time.cpp | 1524 +- Externals/wxWidgets/src/msw/window.cpp | 13700 +++++----- 402 files changed, 295007 insertions(+), 295007 deletions(-) diff --git a/Externals/Bochs_disasm/PowerPCDisasm.cpp b/Externals/Bochs_disasm/PowerPCDisasm.cpp index 62de0995a8..9d2265c061 100644 --- a/Externals/Bochs_disasm/PowerPCDisasm.cpp +++ b/Externals/Bochs_disasm/PowerPCDisasm.cpp @@ -1,2247 +1,2247 @@ -/* $VER: ppc_disasm.c V1.1 (19.02.2000) -* -* Disassembler module for the PowerPC microprocessor family -* Copyright (c) 1998-2000 Frank Wille -* -* ppc_disasm.c is freeware and may be freely redistributed as long as -* no modifications are made and nothing is charged for it. -* Non-commercial usage is allowed without any restrictions. -* EVERY PRODUCT OR PROGRAM DERIVED DIRECTLY FROM MY SOURCE MAY NOT BE -* SOLD COMMERCIALLY WITHOUT PERMISSION FROM THE AUTHOR. -* -* -* v1.2 (31.07.2003) org -* modified for IBM PowerPC Gekko. -* v1.1 (19.02.2000) phx -* fabs wasn't recognized. -* v1.0 (30.01.2000) phx -* stfsx, stfdx, lfsx, lfdx, stfsux, stfdux, lfsux, lfdux, etc. -* printed "rd,ra,rb" as operands instead "fd,ra,rb". -* v0.4 (01.06.1999) phx -* 'stwm' shoud have been 'stmw'. -* v0.3 (17.11.1998) phx -* The OE-types (e.g. addo, subfeo, etc.) didn't work for all -* instructions. -* AA-form branches have an absolute destination. -* addze and subfze must not have a third operand. -* sc was not recognized. -* v0.2 (29.05.1998) phx -* Sign error. SUBI got negative immediate values. -* v0.1 (23.05.1998) phx -* First version, which implements all PowerPC instructions. -* v0.0 (09.05.1998) phx -* File created. -*/ -#include -#include -#include -#include - -#include "PowerPCDisasm.h" - -namespace PPCDisasm -{ - - /* version/revision */ -#define PPCDISASM_VER 1 -#define PPCDISASM_REV 1 - - - /* typedefs */ - typedef unsigned long ppc_word; - -#undef BIGENDIAN -#undef LITTTLEENDIAN - /* endianess */ -#define LITTLEENDIAN 0 - - - /* general defines */ -#define PPCIDXMASK 0xfc000000 -#define PPCIDX2MASK 0x000007fe -#define PPCDMASK 0x03e00000 -#define PPCAMASK 0x001f0000 -#define PPCBMASK 0x0000f800 -#define PPCCMASK 0x000007c0 -#define PPCMMASK 0x0000003e -#define PPCCRDMASK 0x03800000 -#define PPCCRAMASK 0x001c0000 -#define PPCLMASK 0x00600000 -#define PPCOE 0x00000400 - -#define PPCIDXSH 26 -#define PPCDSH 21 -#define PPCASH 16 -#define PPCBSH 11 -#define PPCCSH 6 -#define PPCMSH 1 -#define PPCCRDSH 23 -#define PPCCRASH 18 -#define PPCLSH 21 -#define PPCIDX2SH 1 - -#define PPCGETIDX(x) (((x)&PPCIDXMASK)>>PPCIDXSH) -#define PPCGETD(x) (((x)&PPCDMASK)>>PPCDSH) -#define PPCGETA(x) (((x)&PPCAMASK)>>PPCASH) -#define PPCGETB(x) (((x)&PPCBMASK)>>PPCBSH) -#define PPCGETC(x) (((x)&PPCCMASK)>>PPCCSH) -#define PPCGETM(x) (((x)&PPCMMASK)>>PPCMSH) -#define PPCGETCRD(x) (((x)&PPCCRDMASK)>>PPCCRDSH) -#define PPCGETCRA(x) (((x)&PPCCRAMASK)>>PPCCRASH) -#define PPCGETL(x) (((x)&PPCLMASK)>>PPCLSH) -#define PPCGETIDX2(x) (((x)&PPCIDX2MASK)>>PPCIDX2SH) - - - /* Disassembler structure, the interface to the application */ - - struct DisasmPara_PPC { - ppc_word *instr; /* pointer to instruction to disassemble */ - ppc_word *iaddr; /* instr.addr., usually the same as instr */ - char *opcode; /* buffer for opcode, min. 10 chars. */ - char *operands; /* operand buffer, min. 24 chars. */ - /* changed by disassembler: */ - unsigned char type; /* type of instruction, see below */ - unsigned char flags; /* additional flags */ - unsigned short sreg; /* register in load/store instructions */ - ppc_word displacement; /* branch- or load/store displacement */ - }; - -#define PPCINSTR_OTHER 0 /* no additional info for other instr. */ -#define PPCINSTR_BRANCH 1 /* branch dest. = PC+displacement */ -#define PPCINSTR_LDST 2 /* load/store instruction: displ(sreg) */ -#define PPCINSTR_IMM 3 /* 16-bit immediate val. in displacement */ - -#define PPCF_ILLEGAL (1<<0) /* illegal PowerPC instruction */ -#define PPCF_UNSIGNED (1<<1) /* unsigned immediate instruction */ -#define PPCF_SUPER (1<<2) /* supervisor level instruction */ -#define PPCF_64 (1<<3) /* 64-bit only instruction */ - - - /* ppc_disasm.o prototypes */ -#ifndef PPC_DISASM_C - extern ppc_word *PPC_Disassemble(struct DisasmPara_PPC *); -#endif - - - static const char *trap_condition[32] = { - NULL,"lgt","llt",NULL,"eq","lge","lle",NULL, - "gt",NULL,NULL,NULL,"ge",NULL,NULL,NULL, - "lt",NULL,NULL,NULL,"le",NULL,NULL,NULL, - "ne",NULL,NULL,NULL,NULL,NULL,NULL,NULL - }; - - static const char *cmpname[4] = { - "cmpw","cmpd","cmplw","cmpld" - }; - - static const char *b_ext[4] = { - "","l","a","la" - }; - - static const char *b_condition[8] = { - "ge","le","ne","ns","lt","gt","eq","so" - }; - - static const char *b_decr[16] = { - "nzf","zf",NULL,NULL,"nzt","zt",NULL,NULL, - "nz","z",NULL,NULL,"nz","z",NULL,NULL - }; - - static const char *regsel[2] = { - "","r" - }; - - static const char *oesel[2] = { - "","o" - }; - - static const char *rcsel[2] = { - "","." - }; - - static const char *ldstnames[] = { - "lwz","lwzu","lbz","lbzu","stw","stwu","stb","stbu","lhz","lhzu", - "lha","lhau","sth","sthu","lmw","stmw","lfs","lfsu","lfd","lfdu", - "stfs","stfsu","stfd","stfdu" - }; - - static const char *regnames[] = { - "r0", "sp", "rtoc", "r3", "r4", "r5", "r6", "r7", - "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", - "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", - "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31" - }; - - static const char *spr_name(int i) - { - static char def[8]; - - switch(i) - { - case 1: return "XER"; - case 8: return "LR"; - case 9: return "CTR"; - case 18: return "DSIR"; - case 19: return "DAR"; - case 22: return "DEC"; - case 25: return "SDR1"; - case 26: return "SRR0"; - case 27: return "SRR1"; - case 272: return "SPRG0"; - case 273: return "SPRG1"; - case 274: return "SPRG2"; - case 275: return "SPRG3"; - case 282: return "EAR"; - case 287: return "PVR"; - case 528: return "IBAT0U"; - case 529: return "IBAT0L"; - case 530: return "IBAT1U"; - case 531: return "IBAT1L"; - case 532: return "IBAT2U"; - case 533: return "IBAT2L"; - case 534: return "IBAT3U"; - case 535: return "IBAT3L"; - case 536: return "DBAT0U"; - case 537: return "DBAT0L"; - case 538: return "DBAT1U"; - case 539: return "DBAT1L"; - case 540: return "DBAT2U"; - case 541: return "DBAT2L"; - case 542: return "DBAT3U"; - case 543: return "DBAT3L"; - case 912: return "GQR0"; - case 913: return "GQR1"; - case 914: return "GQR2"; - case 915: return "GQR3"; - case 916: return "GQR4"; - case 917: return "GQR5"; - case 918: return "GQR6"; - case 919: return "GQR7"; - case 920: return "HID2"; - case 921: return "WPAR"; - case 922: return "DMA_U"; - case 923: return "DMA_L"; - case 936: return "UMMCR0"; - case 937: return "UPMC1"; - case 938: return "UPMC2"; - case 939: return "USIA"; - case 940: return "UMMCR1"; - case 941: return "UPMC3"; - case 942: return "UPMC4"; - case 943: return "USDA"; - case 952: return "MMCR0"; - case 953: return "PMC1"; - case 954: return "PMC2"; - case 955: return "SIA"; - case 956: return "MMCR1"; - case 957: return "PMC3"; - case 958: return "PMC4"; - case 959: return "SDA"; - case 1008: return "HID0"; - case 1009: return "HID1"; - case 1010: return "IABR"; - case 1013: return "DABR"; - case 1017: return "L2CR"; - case 1019: return "ICTC"; - case 1020: return "THRM1"; - case 1021: return "THRM2"; - case 1022: return "THRM3"; - } - - sprintf(def, "%i", i); - return def; - } - - static void ierror(const char *errtxt,...) - /* display internal error and quit program */ - { - va_list vl; - - fprintf(stderr,"\nINTERNAL ERROR (PPC disassembler): "); - va_start(vl,errtxt); - vfprintf(stderr,errtxt,vl); - va_end(vl); - fprintf(stderr,".\nAborting.\n"); - exit(1); - } - - - static ppc_word swapda(ppc_word w) - { - return ((w&0xfc00ffff)|((w&PPCAMASK)<<5)|((w&PPCDMASK)>>5)); - } - - - static ppc_word swapab(ppc_word w) - { - return ((w&0xffe007ff)|((w&PPCBMASK)<<5)|((w&PPCAMASK)>>5)); - } - - - static void ill(struct DisasmPara_PPC *dp,ppc_word in) - { - // strcpy(dp->opcode,".word"); - // sprintf(dp->operands,"0x%08lx",(unsigned long)in); - - strcpy(dp->opcode,""); - sprintf(dp->operands,""); - - dp->flags |= PPCF_ILLEGAL; - } - - - static void imm(struct DisasmPara_PPC *dp,ppc_word in,int uimm,int type,int hex) - /* Generate immediate instruction operand. */ - /* type 0: D-mode, D,A,imm */ - /* type 1: S-mode, A,S,imm */ - /* type 2: S/D register is ignored (trap,cmpi) */ - /* type 3: A register is ignored (li) */ - { - int i = (int)(in & 0xffff); - - dp->type = PPCINSTR_IMM; - if (!uimm) { - if (i > 0x7fff) - i -= 0x10000; - } - else - dp->flags |= PPCF_UNSIGNED; - dp->displacement = i; - - switch (type) { - case 0: - sprintf(dp->operands,"%s, %s, %d",regnames[(int)PPCGETD(in)],regnames[(int)PPCGETA(in)],i); - break; - case 1: - if(hex) - sprintf(dp->operands,"%s, %s, 0x%.4X",regnames[(int)PPCGETA(in)],regnames[(int)PPCGETD(in)],i); - else - sprintf(dp->operands,"%s, %s, %d",regnames[(int)PPCGETA(in)],regnames[(int)PPCGETD(in)],i); - break; - case 2: - sprintf(dp->operands,"%s, %d",regnames[(int)PPCGETA(in)],i); - break; - case 3: - if(hex) - sprintf(dp->operands,"%s, 0x%.4X",regnames[(int)PPCGETD(in)],i); - else - sprintf(dp->operands,"%s, %d",regnames[(int)PPCGETD(in)],i); - break; - default: - ierror("imm(): Wrong type"); - break; - } - } - - - static void ra_rb(char *s,ppc_word in) - { - sprintf(s,"%s, %s",regnames[(int)PPCGETA(in)],regnames[(int)PPCGETB(in)]); - } - - - static char *rd_ra_rb(char *s,ppc_word in,int mask) - { - static const char *fmt = "%s, "; - - if (mask) { - if (mask & 4) - s += sprintf(s,fmt,regnames[(int)PPCGETD(in)]); - if (mask & 2) - s += sprintf(s,fmt,regnames[(int)PPCGETA(in)]); - if (mask & 1) - s += sprintf(s,fmt,regnames[(int)PPCGETB(in)]); - *--s = '\0'; - *--s = '\0'; - } - else - *s = '\0'; - return (s); - } - - - static char *fd_ra_rb(char *s,ppc_word in,int mask) - { - static const char *ffmt = "f%d,"; - static const char *rfmt = "%s,"; - - if (mask) { - if (mask & 4) - s += sprintf(s,ffmt,(int)PPCGETD(in)); - if (mask & 2) - s += sprintf(s,rfmt,regnames[(int)PPCGETA(in)]); - if (mask & 1) - s += sprintf(s,rfmt,regnames[(int)PPCGETB(in)]); - *--s = '\0'; - } - else - *s = '\0'; - return (s); - } - - - static void trapi(struct DisasmPara_PPC *dp,ppc_word in,unsigned char dmode) - { - const char *cnd; - - if (cnd = trap_condition[PPCGETD(in)]) { - dp->flags |= dmode; - sprintf(dp->opcode,"t%c%s",dmode?'d':'w',cnd); - imm(dp,in,0,2,0); - } - else - ill(dp,in); - } - - - static void cmpi(struct DisasmPara_PPC *dp,ppc_word in,int uimm) - { - char *oper = dp->operands; - int i = (int)PPCGETL(in); - - if (i < 2) { - if (i) - dp->flags |= PPCF_64; - sprintf(dp->opcode,"%si",cmpname[uimm*2+i]); - if (i = (int)PPCGETCRD(in)) { - sprintf(oper,"cr%c,",'0'+i); - dp->operands += 4; - } - imm(dp,in,uimm,2,0); - dp->operands = oper; - } - else - ill(dp,in); - } - - - static void addi(struct DisasmPara_PPC *dp,ppc_word in,const char *ext) - { - if ((in&0x08000000) && !PPCGETA(in)) { - sprintf(dp->opcode,"l%s",ext); /* li, lis */ - if(!strcmp(ext, "i")) - imm(dp,in,0,3,0); - else - imm(dp,in,1,3,1); - } - else { - sprintf(dp->opcode,"%s%s",(in&0x8000)?"sub":"add",ext); - if (in & 0x8000) - in = (in^0xffff) + 1; - imm(dp,in,1,0,0); - } - } - - - static int branch(struct DisasmPara_PPC *dp,ppc_word in, const char *bname,int aform,int bdisp) - /* build a branch instr. and return number of chars written to operand */ - { - int bo = (int)PPCGETD(in); - int bi = (int)PPCGETA(in); - char y = (char)(bo & 1); - int opercnt = 0; - const char *ext = b_ext[aform*2+(int)(in&1)]; - - if (bdisp < 0) - y ^= 1; - y = y ? '+':'-'; - - if (bo & 4) { - /* standard case - no decrement */ - if (bo & 16) { - /* branch always */ - if (PPCGETIDX(in) != 16) { - sprintf(dp->opcode,"b%s%s",bname,ext); - } - else { - sprintf(dp->opcode,"bc%s",ext); - opercnt = sprintf(dp->operands,"%d, %d",bo,bi); - } - } - else { - /* branch conditional */ - sprintf(dp->opcode,"b%s%s%s%c",b_condition[((bo&8)>>1)+(bi&3)], - bname,ext,y); - if (bi >= 4) - opercnt = sprintf(dp->operands,"cr%d",bi>>2); - } - } - - else { - /* CTR is decremented and checked */ - sprintf(dp->opcode,"bd%s%s%s%c",b_decr[bo>>1],bname,ext,y); - if (!(bo & 16)) - opercnt = sprintf(dp->operands,"%d",bi); - } - - return (opercnt); - } - - - static void bc(struct DisasmPara_PPC *dp,ppc_word in) - { - unsigned long d = (int)(in & 0xfffc); - int offs; - char *oper = dp->operands; - - if(d & 0x8000) d |= 0xffff0000; - - if (offs = branch(dp,in,"",(in&2)?1:0,d)) { - oper += offs; - *oper++ = ','; - } - if (in & 2) /* AA ? */ - sprintf(dp->operands,"->0x%.8X",(unsigned long)d); - else - sprintf(oper,"->0x%.8X",(unsigned long)(*dp->iaddr) + d); - dp->type = PPCINSTR_BRANCH; - dp->displacement = (ppc_word)d; - } - - - static void bli(struct DisasmPara_PPC *dp,ppc_word in) - { - unsigned long d = (unsigned long)(in & 0x3fffffc); - - if(d & 0x02000000) d |= 0xfc000000; - - sprintf(dp->opcode,"b%s",b_ext[in&3]); - if (in & 2) /* AA ? */ - sprintf(dp->operands,"->0x%.8X",(unsigned long)d); - else - sprintf(dp->operands,"->0x%.8X",(unsigned long)(*dp->iaddr) + d); - dp->type = PPCINSTR_BRANCH; - dp->displacement = (ppc_word)d; - } - - - static void mcrf(struct DisasmPara_PPC *dp,ppc_word in,char c) - { - if (!(in & 0x0063f801)) { - sprintf(dp->opcode,"mcrf%c",c); - sprintf(dp->operands,"cr%d, cr%d",(int)PPCGETCRD(in),(int)PPCGETCRA(in)); - } - else - ill(dp,in); - } - - - static void crop(struct DisasmPara_PPC *dp,ppc_word in,const char *n1,const char *n2) - { - int crd = (int)PPCGETD(in); - int cra = (int)PPCGETA(in); - int crb = (int)PPCGETB(in); - - if (!(in & 1)) { - sprintf(dp->opcode,"cr%s",(cra==crb && n2)?n2:n1); - if (cra == crb && n2) - sprintf(dp->operands,"%d, %d",crd,cra); - else - sprintf(dp->operands,"%d, %d, %d",crd,cra,crb); - } - else - ill(dp,in); - } - - - static void nooper(struct DisasmPara_PPC *dp,ppc_word in,const char *name, - unsigned char dmode) - { - if (in & (PPCDMASK|PPCAMASK|PPCBMASK|1)) { - ill(dp,in); - } - else { - dp->flags |= dmode; - strcpy(dp->opcode,name); - } - } - - - static unsigned int Helper_Mask(int mb, int me) - { - //first make 001111111111111 part - unsigned int begin = 0xFFFFFFFF >> mb; - //then make 000000000001111 part, which is used to flip the bits of the first one - unsigned int end = me < 31 ? (0xFFFFFFFF >> (me + 1)) : 0; - //do the bitflip - unsigned int mask = begin ^ end; - //and invert if backwards - if (me < mb) - return ~mask; - else - return mask; - } - - - static void rlw(struct DisasmPara_PPC *dp,ppc_word in,const char *name,int i) - { - int s = (int)PPCGETD(in); - int a = (int)PPCGETA(in); - int bsh = (int)PPCGETB(in); - int mb = (int)PPCGETC(in); - int me = (int)PPCGETM(in); - - - - sprintf(dp->opcode,"rlw%s%c",name,in&1?'.':'\0'); - sprintf(dp->operands,"%s, %s, %s%d, %d, %d (%08x)",regnames[a],regnames[s],regsel[i],bsh,mb,me,Helper_Mask(mb, me)); - } - - - static void ori(struct DisasmPara_PPC *dp,ppc_word in,const char *name) - { - strcpy(dp->opcode,name); - imm(dp,in,1,1,1); - } - - - static void rld(struct DisasmPara_PPC *dp,ppc_word in,const char *name,int i) - { - int s = (int)PPCGETD(in); - int a = (int)PPCGETA(in); - int bsh = i ? (int)PPCGETB(in) : (int)(((in&2)<<4)+PPCGETB(in)); - int m = (int)(in&0x7e0)>>5; - - dp->flags |= PPCF_64; - sprintf(dp->opcode,"rld%s%c",name,in&1?'.':'\0'); - sprintf(dp->operands,"%s, %s, %s%d, %d",regnames[a],regnames[s],regsel[i],bsh,m); - } - - - static void cmp(struct DisasmPara_PPC *dp,ppc_word in) - { - char *oper = dp->operands; - int i = (int)PPCGETL(in); - - if (i < 2) { - if (i) - dp->flags |= PPCF_64; - strcpy(dp->opcode,cmpname[((in&PPCIDX2MASK)?2:0)+i]); - if (i = (int)PPCGETCRD(in)) - oper += sprintf(oper,"cr%c,",'0'+i); - ra_rb(oper,in); - } - else - ill(dp,in); - } - - - static void trap(struct DisasmPara_PPC *dp,ppc_word in,unsigned char dmode) - { - const char *cnd; - int to = (int)PPCGETD(in); - - if (cnd = trap_condition[to]) { - dp->flags |= dmode; - sprintf(dp->opcode,"t%c%s",dmode?'d':'w',cnd); - ra_rb(dp->operands,in); - } - else { - if (to == 31) { - if (dmode) { - dp->flags |= dmode; - strcpy(dp->opcode,"td"); - strcpy(dp->operands,"31,0,0"); - } - else - strcpy(dp->opcode,"trap"); - } - else - ill(dp,in); - } - } - - - static void dab(struct DisasmPara_PPC *dp,ppc_word in,const char *name,int mask, - int smode,int chkoe,int chkrc,unsigned char dmode) - /* standard instruction: xxxx rD,rA,rB */ - { - if (chkrc>=0 && ((in&1)!=(unsigned)chkrc)) { - ill(dp,in); - } - else { - dp->flags |= dmode; - if (smode) - in = swapda(in); /* rA,rS,rB */ - sprintf(dp->opcode,"%s%s%s",name, - oesel[chkoe&&(in&PPCOE)],rcsel[(chkrc<0)&&(in&1)]); - rd_ra_rb(dp->operands,in,mask); - } - } - - - static void rrn(struct DisasmPara_PPC *dp,ppc_word in,const char *name, - int smode,int chkoe,int chkrc,unsigned char dmode) - /* Last operand is no register: xxxx rD,rA,NB */ - { - char *s; - - if (chkrc>=0 && ((in&1)!=(unsigned)chkrc)) { - ill(dp,in); - } - else { - dp->flags |= dmode; - if (smode) - in = swapda(in); /* rA,rS,NB */ - sprintf(dp->opcode,"%s%s%s",name, - oesel[chkoe&&(in&PPCOE)],rcsel[(chkrc<0)&&(in&1)]); - s = rd_ra_rb(dp->operands,in,6); - sprintf(s,",%d",(int)PPCGETB(in)); - } - } - - - static void mtcr(struct DisasmPara_PPC *dp,ppc_word in) - { - int s = (int)PPCGETD(in); - int crm = (int)(in&0x000ff000)>>12; - char *oper = dp->operands; - - if (in & 0x00100801) { - ill(dp,in); - } - else { - sprintf(dp->opcode,"mtcr%c",crm==0xff?'\0':'f'); - if (crm != 0xff) - oper += sprintf(oper,"0x%02x,",crm); - sprintf(oper,"%s",regnames[s]); - } - } - - - static void msr(struct DisasmPara_PPC *dp,ppc_word in,int smode) - { - int s = (int)PPCGETD(in); - int sr = (int)(in&0x000f0000)>>16; - - if (in & 0x0010f801) { - ill(dp,in); - } - else { - dp->flags |= PPCF_SUPER; - sprintf(dp->opcode,"m%csr",smode?'t':'f'); - if (smode) - sprintf(dp->operands,"%d, %s",sr,regnames[s]); - else - sprintf(dp->operands,"%s, %d",regnames[s],sr); - } - } - - - static void mspr(struct DisasmPara_PPC *dp,ppc_word in,int smode) - { - int d = (int)PPCGETD(in); - int spr = (int)((PPCGETB(in)<<5)+PPCGETA(in)); - int fmt = 0; - const char *x; - - if (in & 1) { - ill(dp,in); - } - - else { - if (spr!=1 && spr!=8 && spr!=9) - dp->flags |= PPCF_SUPER; - switch (spr) { - case 1: - x = "xer"; - break; - case 8: - x = "lr"; - break; - case 9: - x = "ctr"; - break; - default: - x = "spr"; - fmt = 1; - break; - } - - sprintf(dp->opcode,"m%c%s",smode?'t':'f',x); - if (fmt) { - if (smode) - sprintf(dp->operands,"%s, %s",spr_name(spr),regnames[d]); - else - sprintf(dp->operands,"%s, %s",regnames[d],spr_name(spr)); - } - else - sprintf(dp->operands,"%s",regnames[d]); - } - } - - - static void mtb(struct DisasmPara_PPC *dp,ppc_word in) - { - int d = (int)PPCGETD(in); - int tbr = (int)((PPCGETB(in)<<5)+PPCGETA(in)); - char *s = dp->operands; - char x; - - if (in & 1) { - ill(dp,in); - } - - else { - s += sprintf(s,"%s",regnames[d]); - switch (tbr) { - case 268: - x = 'l'; - break; - case 269: - x = 'u'; - break; - default: - x = '\0'; - dp->flags |= PPCF_SUPER; - sprintf(s,",%d",tbr); - break; - } - sprintf(dp->opcode,"mftb%c",x); - } - } - - - static void sradi(struct DisasmPara_PPC *dp,ppc_word in) - { - int s = (int)PPCGETD(in); - int a = (int)PPCGETA(in); - int bsh = (int)(((in&2)<<4)+PPCGETB(in)); - - dp->flags |= PPCF_64; - sprintf(dp->opcode,"sradi%c",in&1?'.':'\0'); - sprintf(dp->operands,"%s, %s, %d",regnames[a],regnames[s],bsh); - } - - static const char *ldst_offs(unsigned long val) - { - static char buf[8]; - - if(val == 0) - { - return "0"; - } - else - { - if(val & 0x8000) - { - sprintf(buf, "-0x%.4X", ((~val) & 0xffff) + 1); - } - else - { - sprintf(buf, "0x%.4X", val); - } - - return buf; - } - } - - static void ldst(struct DisasmPara_PPC *dp,ppc_word in,const char *name, - char reg,unsigned char dmode) - { - int s = (int)PPCGETD(in); - int a = (int)PPCGETA(in); - int d = (ppc_word)(in & 0xffff); - - dp->type = PPCINSTR_LDST; - dp->flags |= dmode; - dp->sreg = (short)a; - // if (d >= 0x8000) - // d -= 0x10000; - dp->displacement = (ppc_word)d; - strcpy(dp->opcode,name); - if(reg == 'r') - { - sprintf(dp->operands,"%s, %s (%s)", regnames[s], ldst_offs(d), regnames[a]); - } - else - { - sprintf(dp->operands,"%c%d, %s (%s)",reg,s, ldst_offs(d), regnames[a]); - } - } - - - static void fdabc(struct DisasmPara_PPC *dp,ppc_word in, const char *name, - int mask,unsigned char dmode) - /* standard floating point instruction: xxxx fD,fA,fC,fB */ - { - static const char *fmt = "f%d,"; - char *s = dp->operands; - int err = 0; - - dp->flags |= dmode; - sprintf(dp->opcode,"f%s%s",name,rcsel[in&1]); - s += sprintf(s,fmt,(int)PPCGETD(in)); - if (mask & 4) - s += sprintf(s,fmt,(int)PPCGETA(in)); - else - err |= (int)PPCGETA(in); - if (mask & 2) - s += sprintf(s,fmt,(int)PPCGETC(in)); - else if (PPCGETC(in)) - err |= (int)PPCGETC(in); - if (mask & 1) - s += sprintf(s,fmt,(int)PPCGETB(in)); - else if (!(mask&8)) - err |= (int)PPCGETB(in); - *(s-1) = '\0'; - if (err) - ill(dp,in); - } - - - static void fdab(struct DisasmPara_PPC *dp,ppc_word in,const char *name,int mask) - /* indexed float instruction: xxxx fD,rA,rB */ - { - strcpy(dp->opcode,name); - fd_ra_rb(dp->operands,in,mask); - } - - - static void fcmp(struct DisasmPara_PPC *dp,ppc_word in,char c) - { - if (in & 0x00600001) { - ill(dp,in); - } - else { - sprintf(dp->opcode,"fcmp%c",c); - sprintf(dp->operands,"cr%d,f%d,f%d",(int)PPCGETCRD(in), - (int)PPCGETA(in),(int)PPCGETB(in)); - } - } - - - static void mtfsb(struct DisasmPara_PPC *dp,ppc_word in,int n) - { - if (in & (PPCAMASK|PPCBMASK)) { - ill(dp,in); - } - else { - sprintf(dp->opcode,"mtfsb%d%s",n,rcsel[in&1]); - sprintf(dp->operands,"%d",(int)PPCGETD(in)); - } - } - - - ////////////////////////////////////////////////////////////////////////////////// - //PAIRED - ////////////////////////////////////////////////////////////////////////////////// - - /* - sprintf(buf, "psq_lx", FD); - sprintf(buf, "psq_stx", FD); - sprintf(buf, "psq_lux", FD); - sprintf(buf, "psq_stux", FD); - */ -#define RA ((inst >> 16) & 0x1f) -#define RB ((inst >> 11) & 0x1f) -#define RC ((inst >> 6) & 0x1f) -#define RD ((inst >> 21) & 0x1f) -#define RS ((inst >> 21) & 0x1f) -#define FA ((inst >> 16) & 0x1f) -#define FB ((inst >> 11) & 0x1f) -#define FC ((inst >> 6) & 0x1f) -#define FD ((inst >> 21) & 0x1f) -#define FS ((inst >> 21) & 0x1f) -#define IMM (inst & 0xffff) -#define UIMM (inst & 0xffff) -#define OFS (inst & 0xffff) -#define OPCD ((inst >> 26) & 0x3f) -#define XO_10 ((inst >> 1) & 0x3ff) -#define XO_9 ((inst >> 1) & 0x1ff) -#define XO_5 ((inst >> 1) & 0x1f) -#define Rc (inst & 1) -#define SH ((inst >> 11) & 0x1f) -#define MB ((inst >> 6) & 0x1f) -#define ME ((inst >> 1) & 0x1f) -#define OE ((inst >> 10) & 1) -#define TO ((inst >> 21) & 0x1f) -#define CRFD ((inst >> 23) & 0x7) -#define CRFS ((inst >> 18) & 0x7) -#define CRBD ((inst >> 21) & 0x1f) -#define CRBA ((inst >> 16) & 0x1f) -#define CRBB ((inst >> 11) & 0x1f) -#define L ((inst >> 21) & 1) -#define NB ((inst >> 11) & 0x1f) -#define AA ((inst >> 1) & 1) -#define LK (inst & 1) -#define LI ((inst >> 2) & 0xffffff) -#define BO ((inst >> 21) & 0x1f) -#define BI ((inst >> 16) & 0x1f) -#define BD ((inst >> 2) & 0x3fff) - -#define MTFSFI_IMM ((inst >> 12) & 0xf) -#define FM ((inst >> 17) & 0xff) -#define SR ((inst >> 16) & 0xf) -#define SPR ((inst >> 11) & 0x3ff) -#define TBR ((inst >> 11) & 0x3ff) -#define CRM ((inst >> 12) & 0xff) - inline int SEX12(unsigned int x) - { - return x & 0x800 ? (x|0xFFFFF000) : x; - } - - static void ps(struct DisasmPara_PPC *dp,ppc_word inst) - { - ppc_word pc = *dp->iaddr; - char *op = dp->opcode; - char *pr = dp->operands; - switch((inst>>1)&0x1F) - { - case 6: - strcpy(op, "ps_lux"); - sprintf(pr, "p%u, (r%u + r%u)", FD, RA, RB); - return; - - case 18: - strcpy(op, "ps_div"); - sprintf(pr, "p%u, p%u/p%u", FD, FA, FB); - return; - case 20: - strcpy(op, "ps_sub"); - sprintf(pr, "p%u, p%u-p%u", FD, FA, FB); - return; - case 21: - strcpy(op, "ps_add"); - sprintf(pr, "p%u, p%u+p%u", FD, FA, FB); - return; - case 23: - strcpy(op, "ps_sel"); - sprintf(pr, "p%u>=0?p%u:p%u", FD, FA, FC, FB); - return; - case 24: - strcpy(op, "ps_res"); - sprintf(pr, "p%u, (1/p%u)", FD, FB); - return; - - case 25: - strcpy(op, "ps_mul"); - sprintf(pr, "p%u, p%u*p%u", FD, FA, FC); - return; - - case 26: //rsqrte - strcpy(op, "ps_rsqrte"); - sprintf(pr, "p%u, p%u", FD, FB); - return; - case 28: //msub - strcpy(op, "ps_msub"); - sprintf(pr, "p%u, p%u*p%u-p%u", FD, FA, FC, FB); - return; - case 29: //madd - strcpy(op, "ps_madd"); - sprintf(pr, "p%u, p%u*p%u+p%u", FD, FA, FC, FB); - return; - case 30: //nmsub - strcpy(op, "ps_nmsub"); - sprintf(pr, "p%u, -(p%u*p%u-p%u)", FD, FA, FC, FB); - return; - case 31: //nmadd - strcpy(op, "ps_nmadd"); - sprintf(pr, "p%u, -(p%u*p%u+p%u)", FD, FA, FC, FB); - return; - case 10: - strcpy(op, "ps_sum0"); - sprintf(pr, "p%u, 0=p%u+p%u, 1=p%u", FD, FA, FB, FC); - return; - case 11: - strcpy(op, "ps_sum1"); - sprintf(pr, "p%u, 0=p%u, 1=p%u+p%u", FD, FC, FA, FB); - return; - case 12: - strcpy(op, "ps_muls0"); - sprintf(pr, "p%u, p%u*p%u[0]", FD, FA, FC); - return; - case 13: - strcpy(op, "ps_muls1"); - sprintf(pr, "p%u, p%u*p%u[1]", FD, FA, FC); - return; - case 14: - strcpy(op, "ps_madds0"); - sprintf(pr, "p%u, p%u*p%u[0]+p%u", FD, FA, FC, FB); - return; - case 15: - strcpy(op, "ps_madds1"); - sprintf(pr, "p%u, p%u*p%u[1]+p%u", FD, FA, FC, FB); - return; - } - - switch((inst>>1)&0x3FF) - { - //10-bit suckers (?) - case 40: //nmadd - strcpy(op, "ps_neg"); - sprintf(pr, "p%u, -p%u", FD, FB); - return; - case 72: //nmadd - strcpy(op, "ps_mr"); - sprintf(pr, "p%u, p%u", FD, FB); - return; - case 136: - strcpy(op, "ps_nabs"); - sprintf(pr, "p%u, -|p%u|", FD, FB); - return; - case 264: - strcpy(op, "ps_abs"); - sprintf(pr, "p%u, |p%u|", FD, FB); - return; - case 0: - strcpy(op, "ps_cmpu0"); - sprintf(pr, "ps_cmpu0", FD); - return; - case 32: - strcpy(op,"ps_cmpq0"); - sprintf(pr, "ps_cmpo0", FD); - return; - case 64: - strcpy(op,"ps_cmpu1"); - sprintf(pr, "ps_cmpu1", FD); - return; - case 96: - strcpy(op,"ps_cmpo1"); - sprintf(pr, "ps_cmpo1", FD); - return; - case 528: - strcpy(op,"ps_merge00"); - sprintf(pr, "p%u, p%u[0],p%u[0]", FD, FA, FB); - return; - case 560: - strcpy(op,"ps_merge01"); - sprintf(pr, "p%u, p%u[0],p%u[1]", FD, FA, FB); - return; - case 592: - strcpy(op,"ps_merge10"); - sprintf(pr, "p%u, p%u[1],p%u[0]", FD, FA, FB); - return; - case 624: - strcpy(op,"ps_merge11"); - sprintf(pr, "p%u, p%u[1],p%u[1]", FD, FA, FB); - return; - case 1014: - strcpy(op,"dcbz_l"); - sprintf(pr, ""); - return; - } - - // default: - sprintf(op, "ps_%i",((inst>>1)&0x1f)); - strcpy(pr,"---"); - return; - } - - static void ps_mem(struct DisasmPara_PPC *dp,ppc_word inst) - { - ppc_word pc = *dp->iaddr; - char *op = dp->opcode; - char *pr = dp->operands; - switch(PPCGETIDX(inst)) - { - case 56: - strcpy(op,"psq_l"); - sprintf(pr, "p%u, %i(r%u)", RS, SEX12(inst&0xFFF), RA); - break; - case 57: - strcpy(op,"psq_lu"); - sprintf(pr, "", FD); - break; - case 60: - strcpy(op,"psq_st"); - sprintf(pr, "%i(r%u), p%u", SEX12(inst&0xFFF), RA, RS); - break; - case 61: - strcpy(op,"psq_stu"); - sprintf(pr, "r%u, p%u ?", RA, RS); - break; - } - } - - - ppc_word *PPC_Disassemble(struct DisasmPara_PPC *dp) - /* Disassemble PPC instruction and return a pointer to the next */ - /* instruction, or NULL if an error occured. */ - { - ppc_word in = *(dp->instr); - - if (dp->opcode==NULL || dp->operands==NULL) - return (NULL); /* no buffers */ - -#if LITTLEENDIAN - in = (in & 0xff)<<24 | (in & 0xff00)<<8 | (in & 0xff0000)>>8 | - (in & 0xff000000)>>24; -#endif - dp->type = PPCINSTR_OTHER; - dp->flags = 0; - *(dp->operands) = 0; - - switch (PPCGETIDX(in)) - { - case 1: - sprintf(dp->opcode,"HLE"); - //HLE call - break; - case 2: - trapi(dp,in,PPCF_64); /* tdi */ - break; - - case 3: - trapi(dp,in,0); /* twi */ - break; - case 4: - ps(dp,in); - break; - case 56: - case 57: - case 60: - case 61: - ps_mem(dp,in); - break; - - - case 7: - strcpy(dp->opcode,"mulli"); - imm(dp,in,0,0,0); - break; - - case 8: - strcpy(dp->opcode,"subfic"); - imm(dp,in,0,0,0); - break; - - case 10: - cmpi(dp,in,1); /* cmpli */ - break; - - case 11: - cmpi(dp,in,0); /* cmpi */ - break; - - case 12: - addi(dp,in,"ic"); /* addic */ - break; - - case 13: - addi(dp,in,"ic."); /* addic. */ - break; - - case 14: - addi(dp,in,"i"); /* addi */ - break; - - case 15: - addi(dp,in,"is"); /* addis */ - break; - - case 16: - bc(dp,in); - break; - - case 17: - if ((in & ~PPCIDXMASK) == 2) - strcpy(dp->opcode,"sc"); - else - ill(dp,in); - break; - - case 18: - bli(dp,in); - break; - - case 19: - switch (PPCGETIDX2(in)) { - case 0: - mcrf(dp,in,'\0'); /* mcrf */ - break; - - case 16: - branch(dp,in,"lr",0,0); /* bclr */ - break; - - case 33: - crop(dp,in,"nor","not"); /* crnor */ - break; - - case 50: - nooper(dp,in,"rfi",PPCF_SUPER); - break; - - case 129: - crop(dp,in,"andc",NULL); /* crandc */ - break; - - case 150: - nooper(dp,in,"isync",0); - break; - - case 193: - crop(dp,in,"xor","clr"); /* crxor */ - break; - - case 225: - crop(dp,in,"nand",NULL); /* crnand */ - break; - - case 257: - crop(dp,in,"and",NULL); /* crand */ - break; - - case 289: - crop(dp,in,"eqv","set"); /* creqv */ - break; - - case 417: - crop(dp,in,"orc",NULL); /* crorc */ - break; - - case 449: - crop(dp,in,"or","move"); /* cror */ - break; - - case 528: - branch(dp,in,"ctr",0,0); /* bcctr */ - break; - - default: - ill(dp,in); - break; - } - break; - - case 20: - rlw(dp,in,"imi",0); /* rlwimi */ - break; - - case 21: - rlw(dp,in,"inm",0); /* rlwinm */ - break; - - case 23: - rlw(dp,in,"nm",1); /* rlwnm */ - break; - - case 24: - if (in & ~PPCIDXMASK) - ori(dp,in,"ori"); - else - strcpy(dp->opcode,"nop"); - break; - - case 25: - ori(dp,in,"oris"); - break; - - case 26: - ori(dp,in,"xori"); - break; - - case 27: - ori(dp,in,"xoris"); - break; - - case 28: - ori(dp,in,"andi."); - break; - - case 29: - ori(dp,in,"andis."); - break; - - case 30: - switch (in & 0x1c) { - case 0: - rld(dp,in,"icl",0); /* rldicl */ - break; - case 1: - rld(dp,in,"icr",0); /* rldicr */ - break; - case 2: - rld(dp,in,"ic",0); /* rldic */ - break; - case 3: - rld(dp,in,"imi",0); /* rldimi */ - break; - case 4: - rld(dp,in,in&2?"cl":"cr",1); /* rldcl, rldcr */ - break; - default: - ill(dp,in); - break; - } - break; - - case 31: - switch (PPCGETIDX2(in)) { - case 0: - case 32: - if (in & 1) - ill(dp,in); - else - cmp(dp,in); /* cmp, cmpl */ - break; - - case 4: - if (in & 1) - ill(dp,in); - else - trap(dp,in,0); /* tw */ - break; - - case 8: - case (PPCOE>>1)+8: - dab(dp,swapab(in),"subc",7,0,1,-1,0); - break; - - case 9: - dab(dp,in,"mulhdu",7,0,0,-1,PPCF_64); - break; - - case 10: - case (PPCOE>>1)+10: - dab(dp,in,"addc",7,0,1,-1,0); - break; - - case 11: - dab(dp,in,"mulhwu",7,0,0,-1,0); - break; - - case 19: - if (in & (PPCAMASK|PPCBMASK)) - ill(dp,in); - else - dab(dp,in,"mfcr",4,0,0,0,0); - break; - - case 20: - dab(dp,in,"lwarx",7,0,0,0,0); - break; - - case 21: - dab(dp,in,"ldx",7,0,0,0,PPCF_64); - break; - - case 23: - dab(dp,in,"lwzx",7,0,0,0,0); - break; - - case 24: - dab(dp,in,"slw",7,1,0,-1,0); - break; - - case 26: - if (in & PPCBMASK) - ill(dp,in); - else - dab(dp,in,"cntlzw",6,1,0,-1,0); - break; - - case 27: - dab(dp,in,"sld",7,1,0,-1,PPCF_64); - break; - - case 28: - dab(dp,in,"and",7,1,0,-1,0); - break; - - case 40: - case (PPCOE>>1)+40: - dab(dp,swapab(in),"sub",7,0,1,-1,0); - break; - - case 53: - dab(dp,in,"ldux",7,0,0,0,PPCF_64); - break; - - case 54: - if (in & PPCDMASK) - ill(dp,in); - else - dab(dp,in,"dcbst",3,0,0,0,0); - break; - - case 55: - dab(dp,in,"lwzux",7,0,0,0,0); - break; - - case 58: - if (in & PPCBMASK) - ill(dp,in); - else - dab(dp,in,"cntlzd",6,1,0,-1,PPCF_64); - break; - - case 60: - dab(dp,in,"andc",7,1,0,-1,0); - break; - - case 68: - trap(dp,in,PPCF_64); /* td */ - break; - - case 73: - dab(dp,in,"mulhd",7,0,0,-1,PPCF_64); - break; - - case 75: - dab(dp,in,"mulhw",7,0,0,-1,0); - break; - - case 83: - if (in & (PPCAMASK|PPCBMASK)) - ill(dp,in); - else - dab(dp,in,"mfmsr",4,0,0,0,PPCF_SUPER); - break; - - case 84: - dab(dp,in,"ldarx",7,0,0,0,PPCF_64); - break; - - case 86: - if (in & PPCDMASK) - ill(dp,in); - else - dab(dp,in,"dcbf",3,0,0,0,0); - break; - - case 87: - dab(dp,in,"lbzx",7,0,0,0,0); - break; - - case 104: - case (PPCOE>>1)+104: - if (in & PPCBMASK) - ill(dp,in); - else - dab(dp,in,"neg",6,0,1,-1,0); - break; - - case 119: - dab(dp,in,"lbzux",7,0,0,0,0); - break; - - case 124: - if (PPCGETD(in) == PPCGETB(in)) - dab(dp,in,"not",6,1,0,-1,0); - else - dab(dp,in,"nor",7,1,0,-1,0); - break; - - case 136: - case (PPCOE>>1)+136: - dab(dp,in,"subfe",7,0,1,-1,0); - break; - - case 138: - case (PPCOE>>1)+138: - dab(dp,in,"adde",7,0,1,-1,0); - break; - - case 144: - mtcr(dp,in); - break; - - case 146: - if (in & (PPCAMASK|PPCBMASK)) - ill(dp,in); - else - dab(dp,in,"mtmsr",4,0,0,0,PPCF_SUPER); - break; - - case 149: - dab(dp,in,"stdx",7,0,0,0,PPCF_64); - break; - - case 150: - dab(dp,in,"stwcx.",7,0,0,1,0); - break; - - case 151: - dab(dp,in,"stwx",7,0,0,0,0); - break; - - case 181: - dab(dp,in,"stdux",7,0,0,0,PPCF_64); - break; - - case 183: - dab(dp,in,"stwux",7,0,0,0,0); - break; - - case 200: - case (PPCOE>>1)+200: - if (in & PPCBMASK) - ill(dp,in); - else - dab(dp,in,"subfze",6,0,1,-1,0); - break; - - case 202: - case (PPCOE>>1)+202: - if (in & PPCBMASK) - ill(dp,in); - else - dab(dp,in,"addze",6,0,1,-1,0); - break; - - case 210: - msr(dp,in,1); /* mfsr */ - break; - - case 214: - dab(dp,in,"stdcx.",7,0,0,1,PPCF_64); - break; - - case 215: - dab(dp,in,"stbx",7,0,0,0,0); - break; - - case 232: - case (PPCOE>>1)+232: - if (in & PPCBMASK) - ill(dp,in); - else - dab(dp,in,"subfme",6,0,1,-1,0); - break; - - case 233: - case (PPCOE>>1)+233: - dab(dp,in,"mulld",7,0,1,-1,PPCF_64); - break; - - case 234: - case (PPCOE>>1)+234: - if (in & PPCBMASK) - ill(dp,in); - else - dab(dp,in,"addme",6,0,1,-1,0); - break; - - case 235: - case (PPCOE>>1)+235: - dab(dp,in,"mullw",7,0,1,-1,0); - break; - - case 242: - if (in & PPCAMASK) - ill(dp,in); - else - dab(dp,in,"mtsrin",5,0,0,0,PPCF_SUPER); - break; - - case 246: - if (in & PPCDMASK) - ill(dp,in); - else - dab(dp,in,"dcbtst",3,0,0,0,0); - break; - - case 247: - dab(dp,in,"stbux",7,0,0,0,0); - break; - - case 266: - case (PPCOE>>1)+266: - dab(dp,in,"add",7,0,1,-1,0); - break; - - case 278: - if (in & PPCDMASK) - ill(dp,in); - else - dab(dp,in,"dcbt",3,0,0,0,0); - break; - - case 279: - dab(dp,in,"lhzx",7,0,0,0,0); - break; - - case 284: - dab(dp,in,"eqv",7,1,0,-1,0); - break; - - case 306: - if (in & (PPCDMASK|PPCAMASK)) - ill(dp,in); - else - dab(dp,in,"tlbie",1,0,0,0,PPCF_SUPER); - break; - - case 310: - dab(dp,in,"eciwx",7,0,0,0,0); - break; - - case 311: - dab(dp,in,"lhzux",7,0,0,0,0); - break; - - case 316: - dab(dp,in,"xor",7,1,0,-1,0); - break; - - case 339: - mspr(dp,in,0); /* mfspr */ - break; - - case 341: - dab(dp,in,"lwax",7,0,0,0,PPCF_64); - break; - - case 343: - dab(dp,in,"lhax",7,0,0,0,0); - break; - - case 370: - nooper(dp,in,"tlbia",PPCF_SUPER); - break; - - case 371: - mtb(dp,in); /* mftb */ - break; - - case 373: - dab(dp,in,"lwaux",7,0,0,0,PPCF_64); - break; - - case 375: - dab(dp,in,"lhaux",7,0,0,0,0); - break; - - case 407: - dab(dp,in,"sthx",7,0,0,0,0); - break; - - case 412: - dab(dp,in,"orc",7,1,0,-1,0); - break; - - case 413: - sradi(dp,in); /* sradi */ - break; - - case 434: - if (in & (PPCDMASK|PPCAMASK)) - ill(dp,in); - else - dab(dp,in,"slbie",1,0,0,0,PPCF_SUPER|PPCF_64); - break; - - case 438: - dab(dp,in,"ecowx",7,0,0,0,0); - break; - - case 439: - dab(dp,in,"sthux",7,0,0,0,0); - break; - - case 444: - if (PPCGETD(in) == PPCGETB(in)) - dab(dp,in,"mr",6,1,0,-1,0); - else - dab(dp,in,"or",7,1,0,-1,0); - break; - - case 457: - case (PPCOE>>1)+457: - dab(dp,in,"divdu",7,0,1,-1,PPCF_64); - break; - - case 459: - case (PPCOE>>1)+459: - dab(dp,in,"divwu",7,0,1,-1,0); - break; - - case 467: - mspr(dp,in,1); /* mtspr */ - break; - - case 470: - if (in & PPCDMASK) - ill(dp,in); - else - dab(dp,in,"dcbi",3,0,0,0,0); - break; - - case 476: - dab(dp,in,"nand",7,1,0,-1,0); - break; - - case 489: - case (PPCOE>>1)+489: - dab(dp,in,"divd",7,0,1,-1,PPCF_64); - break; - - case 491: - case (PPCOE>>1)+491: - dab(dp,in,"divw",7,0,1,-1,0); - break; - - case 498: - nooper(dp,in,"slbia",PPCF_SUPER|PPCF_64); - break; - - case 512: - if (in & 0x007ff801) - ill(dp,in); - else { - strcpy(dp->opcode,"mcrxr"); - sprintf(dp->operands,"cr%d",(int)PPCGETCRD(in)); - } - break; - - case 533: - dab(dp,in,"lswx",7,0,0,0,0); - break; - - case 534: - dab(dp,in,"lwbrx",7,0,0,0,0); - break; - - case 535: - fdab(dp,in,"lfsx",7); - break; - - case 536: - dab(dp,in,"srw",7,1,0,-1,0); - break; - - case 539: - dab(dp,in,"srd",7,1,0,-1,PPCF_64); - break; - - case 566: - nooper(dp,in,"tlbsync",PPCF_SUPER); - break; - - case 567: - fdab(dp,in,"lfsux",7); - break; - - case 595: - msr(dp,in,0); /* mfsr */ - break; - - case 597: - rrn(dp,in,"lswi",0,0,0,0); - break; - - case 598: - nooper(dp,in,"sync",PPCF_SUPER); - break; - - case 599: - fdab(dp,in,"lfdx",7); - break; - - case 631: - fdab(dp,in,"lfdux",7); - break; - - case 659: - if (in & PPCAMASK) - ill(dp,in); - else - dab(dp,in,"mfsrin",5,0,0,0,PPCF_SUPER); - break; - - case 661: - dab(dp,in,"stswx",7,0,0,0,0); - break; - - case 662: - dab(dp,in,"stwbrx",7,0,0,0,0); - break; - - case 663: - fdab(dp,in,"stfsx",7); - break; - - case 695: - fdab(dp,in,"stfsux",7); - break; - - case 725: - rrn(dp,in,"stswi",0,0,0,0); - break; - - case 727: - fdab(dp,in,"stfdx",7); - break; - - case 759: - fdab(dp,in,"stfdux",7); - break; - - case 790: - dab(dp,in,"lhbrx",7,0,0,0,0); - break; - - case 792: - dab(dp,in,"sraw",7,1,0,-1,0); - break; - - case 794: - dab(dp,in,"srad",7,1,0,-1,PPCF_64); - break; - - case 824: - rrn(dp,in,"srawi",1,0,-1,0); - break; - - case 854: - nooper(dp,in,"eieio",PPCF_SUPER); - break; - - case 918: - dab(dp,in,"sthbrx",7,0,0,0,0); - break; - - case 922: - if (in & PPCBMASK) - ill(dp,in); - else - dab(dp,in,"extsh",6,1,0,-1,0); - break; - - case 954: - if (in & PPCBMASK) - ill(dp,in); - else - dab(dp,in,"extsb",6,1,0,-1,0); - break; - - case 982: - if (in & PPCDMASK) - ill(dp,in); - else - dab(dp,in,"icbi",3,0,0,0,0); - break; - - case 983: - fdab(dp,in,"stfiwx",7); - break; - - case 986: - if (in & PPCBMASK) - ill(dp,in); - else - dab(dp,in,"extsw",6,1,0,-1,PPCF_64); - break; - - case 1014: - if (in & PPCDMASK) - ill(dp,in); - else - dab(dp,in,"dcbz",3,0,0,0,0); - break; - - default: - ill(dp,in); - break; - } - break; - - case 32: - case 33: - case 34: - case 35: - case 36: - case 37: - case 38: - case 39: - case 40: - case 41: - case 42: - case 43: - case 44: - case 45: - case 46: - case 47: - ldst(dp,in,ldstnames[PPCGETIDX(in)-32],'r',0); - break; - - case 48: - case 49: - case 50: - case 51: - case 52: - case 53: - case 54: - case 55: - ldst(dp,in,ldstnames[PPCGETIDX(in)-32],'f',0); - break; - - case 58: - switch (in & 3) { - case 0: - ldst(dp,in&~3,"ld",'r',PPCF_64); - break; - case 1: - ldst(dp,in&~3,"ldu",'r',PPCF_64); - break; - case 2: - ldst(dp,in&~3,"lwa",'r',PPCF_64); - break; - default: - ill(dp,in); - break; - } - break; - - case 59: - switch (in & 0x3e) { - case 36: - fdabc(dp,in,"divs",6,0); - break; - - case 40: - fdabc(dp,in,"subs",6,0); - break; - - case 42: - fdabc(dp,in,"adds",6,0); - break; - - case 44: - fdabc(dp,in,"sqrts",2,0); - break; - - case 48: - fdabc(dp,in,"res",2,0); - break; - - case 50: - fdabc(dp,in,"muls",5,0); - break; - - case 56: - fdabc(dp,in,"msubs",7,0); - break; - - case 58: - fdabc(dp,in,"madds",7,0); - break; - - case 60: - fdabc(dp,in,"nmsubs",7,0); - break; - - case 62: - fdabc(dp,in,"nmadds",7,0); - break; - - default: - ill(dp,in); - break; - } - break; - - case 62: - switch (in & 3) { - case 0: - ldst(dp,in&~3,"std",'r',PPCF_64); - break; - case 1: - ldst(dp,in&~3,"stdu",'r',PPCF_64); - break; - default: - ill(dp,in); - break; - } - break; - - case 63: - if (in & 32) { - switch (in & 0x1e) { - case 4: - fdabc(dp,in,"div",6,0); - break; - - case 8: - fdabc(dp,in,"sub",6,0); - break; - - case 10: - fdabc(dp,in,"add",6,0); - break; - - case 12: - fdabc(dp,in,"sqrt",2,0); - break; - - case 14: - fdabc(dp,in,"sel",7,0); - break; - - case 18: - fdabc(dp,in,"mul",5,0); - break; - - case 20: - fdabc(dp,in,"rsqrte",2,0); - break; - - case 24: - fdabc(dp,in,"msub",7,0); - break; - - case 26: - fdabc(dp,in,"madd",7,0); - break; - - case 28: - fdabc(dp,in,"nmsub",7,0); - break; - - case 30: - fdabc(dp,in,"nmadd",7,0); - break; - - default: - ill(dp,in); - break; - } - } - - else { - switch (PPCGETIDX2(in)) { - case 0: - fcmp(dp,in,'u'); - break; - - case 12: - fdabc(dp,in,"rsp",10,0); - break; - - case 14: - fdabc(dp,in,"ctiw",10,0); - break; - - case 15: - fdabc(dp,in,"ctiwz",10,0); - break; - - case 32: - fcmp(dp,in,'o'); - break; - - case 38: - mtfsb(dp,in,1); - break; - - case 40: - fdabc(dp,in,"neg",10,0); - break; - - case 64: - mcrf(dp,in,'s'); /* mcrfs */ - break; - - case 70: - mtfsb(dp,in,0); - break; - - case 72: - fdabc(dp,in,"mr",10,0); - break; - - case 134: - if (!(in & 0x006f0800)) { - sprintf(dp->opcode,"mtfsfi%s",rcsel[in&1]); - sprintf(dp->operands,"cr%d,%d",(int)PPCGETCRD(in), - (int)(in & 0xf000)>>12); - } - else - ill(dp,in); - break; - - case 136: - fdabc(dp,in,"nabs",10,0); - break; - - case 264: - fdabc(dp,in,"abs",10,0); - break; - - case 583: - if (in & (PPCAMASK|PPCBMASK)) - ill(dp,in); - else - dab(dp,in,"mffs",4,0,0,-1,0); - break; - - case 711: - if (!(in & 0x02010000)) { - sprintf(dp->opcode,"mtfsf%s",rcsel[in&1]); - sprintf(dp->operands,"0x%x,%d", - (unsigned)(in & 0x01fe)>>17,(int)PPCGETB(in)); - } - else - ill(dp,in); - break; - - case 814: - fdabc(dp,in,"fctid",10,PPCF_64); - break; - - case 815: - fdabc(dp,in,"fctidz",10,PPCF_64); - break; - - case 846: - fdabc(dp,in,"fcfid",10,PPCF_64); - break; - - default: - ill(dp,in); - break; - } - } - break; - - default: - ill(dp,in); - break; - } - return (dp->instr + 1); - } -} - -// --------------------------------------------------------------------------- - -// simplified interface - -const char *DisassembleGekko(unsigned int opcode, unsigned int curInstAddr) -{ - char opcodeStr[64], operandStr[64]; - PPCDisasm::DisasmPara_PPC dp; - static char buf[128]; - static unsigned int opc, adr; - - opc = opcode; - adr = curInstAddr; - - dp.opcode = opcodeStr; - dp.operands = operandStr; - dp.instr = (PPCDisasm::ppc_word *)&opc; - dp.iaddr = (PPCDisasm::ppc_word *)&adr; - - PPCDisasm::PPC_Disassemble(&dp); - - //sprintf(buf, "%-10s %s", opcodeStr, operandStr); - sprintf(buf, "%s\t%s", opcodeStr, operandStr); - return buf; -} - - -static const char *gprnames[] = -{ - "r00", "r01", "r02", "r03", "r04", "r05", "r06", "r07", - "r08", "r09", "r10", "r11", "r12", "r13", "r14", "r15", - "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", - "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31" -}; - -const char *GetGRPName(unsigned int index) -{ - if (index < 32) - return gprnames[index]; - return 0; -} +/* $VER: ppc_disasm.c V1.1 (19.02.2000) +* +* Disassembler module for the PowerPC microprocessor family +* Copyright (c) 1998-2000 Frank Wille +* +* ppc_disasm.c is freeware and may be freely redistributed as long as +* no modifications are made and nothing is charged for it. +* Non-commercial usage is allowed without any restrictions. +* EVERY PRODUCT OR PROGRAM DERIVED DIRECTLY FROM MY SOURCE MAY NOT BE +* SOLD COMMERCIALLY WITHOUT PERMISSION FROM THE AUTHOR. +* +* +* v1.2 (31.07.2003) org +* modified for IBM PowerPC Gekko. +* v1.1 (19.02.2000) phx +* fabs wasn't recognized. +* v1.0 (30.01.2000) phx +* stfsx, stfdx, lfsx, lfdx, stfsux, stfdux, lfsux, lfdux, etc. +* printed "rd,ra,rb" as operands instead "fd,ra,rb". +* v0.4 (01.06.1999) phx +* 'stwm' shoud have been 'stmw'. +* v0.3 (17.11.1998) phx +* The OE-types (e.g. addo, subfeo, etc.) didn't work for all +* instructions. +* AA-form branches have an absolute destination. +* addze and subfze must not have a third operand. +* sc was not recognized. +* v0.2 (29.05.1998) phx +* Sign error. SUBI got negative immediate values. +* v0.1 (23.05.1998) phx +* First version, which implements all PowerPC instructions. +* v0.0 (09.05.1998) phx +* File created. +*/ +#include +#include +#include +#include + +#include "PowerPCDisasm.h" + +namespace PPCDisasm +{ + + /* version/revision */ +#define PPCDISASM_VER 1 +#define PPCDISASM_REV 1 + + + /* typedefs */ + typedef unsigned long ppc_word; + +#undef BIGENDIAN +#undef LITTTLEENDIAN + /* endianess */ +#define LITTLEENDIAN 0 + + + /* general defines */ +#define PPCIDXMASK 0xfc000000 +#define PPCIDX2MASK 0x000007fe +#define PPCDMASK 0x03e00000 +#define PPCAMASK 0x001f0000 +#define PPCBMASK 0x0000f800 +#define PPCCMASK 0x000007c0 +#define PPCMMASK 0x0000003e +#define PPCCRDMASK 0x03800000 +#define PPCCRAMASK 0x001c0000 +#define PPCLMASK 0x00600000 +#define PPCOE 0x00000400 + +#define PPCIDXSH 26 +#define PPCDSH 21 +#define PPCASH 16 +#define PPCBSH 11 +#define PPCCSH 6 +#define PPCMSH 1 +#define PPCCRDSH 23 +#define PPCCRASH 18 +#define PPCLSH 21 +#define PPCIDX2SH 1 + +#define PPCGETIDX(x) (((x)&PPCIDXMASK)>>PPCIDXSH) +#define PPCGETD(x) (((x)&PPCDMASK)>>PPCDSH) +#define PPCGETA(x) (((x)&PPCAMASK)>>PPCASH) +#define PPCGETB(x) (((x)&PPCBMASK)>>PPCBSH) +#define PPCGETC(x) (((x)&PPCCMASK)>>PPCCSH) +#define PPCGETM(x) (((x)&PPCMMASK)>>PPCMSH) +#define PPCGETCRD(x) (((x)&PPCCRDMASK)>>PPCCRDSH) +#define PPCGETCRA(x) (((x)&PPCCRAMASK)>>PPCCRASH) +#define PPCGETL(x) (((x)&PPCLMASK)>>PPCLSH) +#define PPCGETIDX2(x) (((x)&PPCIDX2MASK)>>PPCIDX2SH) + + + /* Disassembler structure, the interface to the application */ + + struct DisasmPara_PPC { + ppc_word *instr; /* pointer to instruction to disassemble */ + ppc_word *iaddr; /* instr.addr., usually the same as instr */ + char *opcode; /* buffer for opcode, min. 10 chars. */ + char *operands; /* operand buffer, min. 24 chars. */ + /* changed by disassembler: */ + unsigned char type; /* type of instruction, see below */ + unsigned char flags; /* additional flags */ + unsigned short sreg; /* register in load/store instructions */ + ppc_word displacement; /* branch- or load/store displacement */ + }; + +#define PPCINSTR_OTHER 0 /* no additional info for other instr. */ +#define PPCINSTR_BRANCH 1 /* branch dest. = PC+displacement */ +#define PPCINSTR_LDST 2 /* load/store instruction: displ(sreg) */ +#define PPCINSTR_IMM 3 /* 16-bit immediate val. in displacement */ + +#define PPCF_ILLEGAL (1<<0) /* illegal PowerPC instruction */ +#define PPCF_UNSIGNED (1<<1) /* unsigned immediate instruction */ +#define PPCF_SUPER (1<<2) /* supervisor level instruction */ +#define PPCF_64 (1<<3) /* 64-bit only instruction */ + + + /* ppc_disasm.o prototypes */ +#ifndef PPC_DISASM_C + extern ppc_word *PPC_Disassemble(struct DisasmPara_PPC *); +#endif + + + static const char *trap_condition[32] = { + NULL,"lgt","llt",NULL,"eq","lge","lle",NULL, + "gt",NULL,NULL,NULL,"ge",NULL,NULL,NULL, + "lt",NULL,NULL,NULL,"le",NULL,NULL,NULL, + "ne",NULL,NULL,NULL,NULL,NULL,NULL,NULL + }; + + static const char *cmpname[4] = { + "cmpw","cmpd","cmplw","cmpld" + }; + + static const char *b_ext[4] = { + "","l","a","la" + }; + + static const char *b_condition[8] = { + "ge","le","ne","ns","lt","gt","eq","so" + }; + + static const char *b_decr[16] = { + "nzf","zf",NULL,NULL,"nzt","zt",NULL,NULL, + "nz","z",NULL,NULL,"nz","z",NULL,NULL + }; + + static const char *regsel[2] = { + "","r" + }; + + static const char *oesel[2] = { + "","o" + }; + + static const char *rcsel[2] = { + "","." + }; + + static const char *ldstnames[] = { + "lwz","lwzu","lbz","lbzu","stw","stwu","stb","stbu","lhz","lhzu", + "lha","lhau","sth","sthu","lmw","stmw","lfs","lfsu","lfd","lfdu", + "stfs","stfsu","stfd","stfdu" + }; + + static const char *regnames[] = { + "r0", "sp", "rtoc", "r3", "r4", "r5", "r6", "r7", + "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", + "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", + "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31" + }; + + static const char *spr_name(int i) + { + static char def[8]; + + switch(i) + { + case 1: return "XER"; + case 8: return "LR"; + case 9: return "CTR"; + case 18: return "DSIR"; + case 19: return "DAR"; + case 22: return "DEC"; + case 25: return "SDR1"; + case 26: return "SRR0"; + case 27: return "SRR1"; + case 272: return "SPRG0"; + case 273: return "SPRG1"; + case 274: return "SPRG2"; + case 275: return "SPRG3"; + case 282: return "EAR"; + case 287: return "PVR"; + case 528: return "IBAT0U"; + case 529: return "IBAT0L"; + case 530: return "IBAT1U"; + case 531: return "IBAT1L"; + case 532: return "IBAT2U"; + case 533: return "IBAT2L"; + case 534: return "IBAT3U"; + case 535: return "IBAT3L"; + case 536: return "DBAT0U"; + case 537: return "DBAT0L"; + case 538: return "DBAT1U"; + case 539: return "DBAT1L"; + case 540: return "DBAT2U"; + case 541: return "DBAT2L"; + case 542: return "DBAT3U"; + case 543: return "DBAT3L"; + case 912: return "GQR0"; + case 913: return "GQR1"; + case 914: return "GQR2"; + case 915: return "GQR3"; + case 916: return "GQR4"; + case 917: return "GQR5"; + case 918: return "GQR6"; + case 919: return "GQR7"; + case 920: return "HID2"; + case 921: return "WPAR"; + case 922: return "DMA_U"; + case 923: return "DMA_L"; + case 936: return "UMMCR0"; + case 937: return "UPMC1"; + case 938: return "UPMC2"; + case 939: return "USIA"; + case 940: return "UMMCR1"; + case 941: return "UPMC3"; + case 942: return "UPMC4"; + case 943: return "USDA"; + case 952: return "MMCR0"; + case 953: return "PMC1"; + case 954: return "PMC2"; + case 955: return "SIA"; + case 956: return "MMCR1"; + case 957: return "PMC3"; + case 958: return "PMC4"; + case 959: return "SDA"; + case 1008: return "HID0"; + case 1009: return "HID1"; + case 1010: return "IABR"; + case 1013: return "DABR"; + case 1017: return "L2CR"; + case 1019: return "ICTC"; + case 1020: return "THRM1"; + case 1021: return "THRM2"; + case 1022: return "THRM3"; + } + + sprintf(def, "%i", i); + return def; + } + + static void ierror(const char *errtxt,...) + /* display internal error and quit program */ + { + va_list vl; + + fprintf(stderr,"\nINTERNAL ERROR (PPC disassembler): "); + va_start(vl,errtxt); + vfprintf(stderr,errtxt,vl); + va_end(vl); + fprintf(stderr,".\nAborting.\n"); + exit(1); + } + + + static ppc_word swapda(ppc_word w) + { + return ((w&0xfc00ffff)|((w&PPCAMASK)<<5)|((w&PPCDMASK)>>5)); + } + + + static ppc_word swapab(ppc_word w) + { + return ((w&0xffe007ff)|((w&PPCBMASK)<<5)|((w&PPCAMASK)>>5)); + } + + + static void ill(struct DisasmPara_PPC *dp,ppc_word in) + { + // strcpy(dp->opcode,".word"); + // sprintf(dp->operands,"0x%08lx",(unsigned long)in); + + strcpy(dp->opcode,""); + sprintf(dp->operands,""); + + dp->flags |= PPCF_ILLEGAL; + } + + + static void imm(struct DisasmPara_PPC *dp,ppc_word in,int uimm,int type,int hex) + /* Generate immediate instruction operand. */ + /* type 0: D-mode, D,A,imm */ + /* type 1: S-mode, A,S,imm */ + /* type 2: S/D register is ignored (trap,cmpi) */ + /* type 3: A register is ignored (li) */ + { + int i = (int)(in & 0xffff); + + dp->type = PPCINSTR_IMM; + if (!uimm) { + if (i > 0x7fff) + i -= 0x10000; + } + else + dp->flags |= PPCF_UNSIGNED; + dp->displacement = i; + + switch (type) { + case 0: + sprintf(dp->operands,"%s, %s, %d",regnames[(int)PPCGETD(in)],regnames[(int)PPCGETA(in)],i); + break; + case 1: + if(hex) + sprintf(dp->operands,"%s, %s, 0x%.4X",regnames[(int)PPCGETA(in)],regnames[(int)PPCGETD(in)],i); + else + sprintf(dp->operands,"%s, %s, %d",regnames[(int)PPCGETA(in)],regnames[(int)PPCGETD(in)],i); + break; + case 2: + sprintf(dp->operands,"%s, %d",regnames[(int)PPCGETA(in)],i); + break; + case 3: + if(hex) + sprintf(dp->operands,"%s, 0x%.4X",regnames[(int)PPCGETD(in)],i); + else + sprintf(dp->operands,"%s, %d",regnames[(int)PPCGETD(in)],i); + break; + default: + ierror("imm(): Wrong type"); + break; + } + } + + + static void ra_rb(char *s,ppc_word in) + { + sprintf(s,"%s, %s",regnames[(int)PPCGETA(in)],regnames[(int)PPCGETB(in)]); + } + + + static char *rd_ra_rb(char *s,ppc_word in,int mask) + { + static const char *fmt = "%s, "; + + if (mask) { + if (mask & 4) + s += sprintf(s,fmt,regnames[(int)PPCGETD(in)]); + if (mask & 2) + s += sprintf(s,fmt,regnames[(int)PPCGETA(in)]); + if (mask & 1) + s += sprintf(s,fmt,regnames[(int)PPCGETB(in)]); + *--s = '\0'; + *--s = '\0'; + } + else + *s = '\0'; + return (s); + } + + + static char *fd_ra_rb(char *s,ppc_word in,int mask) + { + static const char *ffmt = "f%d,"; + static const char *rfmt = "%s,"; + + if (mask) { + if (mask & 4) + s += sprintf(s,ffmt,(int)PPCGETD(in)); + if (mask & 2) + s += sprintf(s,rfmt,regnames[(int)PPCGETA(in)]); + if (mask & 1) + s += sprintf(s,rfmt,regnames[(int)PPCGETB(in)]); + *--s = '\0'; + } + else + *s = '\0'; + return (s); + } + + + static void trapi(struct DisasmPara_PPC *dp,ppc_word in,unsigned char dmode) + { + const char *cnd; + + if (cnd = trap_condition[PPCGETD(in)]) { + dp->flags |= dmode; + sprintf(dp->opcode,"t%c%s",dmode?'d':'w',cnd); + imm(dp,in,0,2,0); + } + else + ill(dp,in); + } + + + static void cmpi(struct DisasmPara_PPC *dp,ppc_word in,int uimm) + { + char *oper = dp->operands; + int i = (int)PPCGETL(in); + + if (i < 2) { + if (i) + dp->flags |= PPCF_64; + sprintf(dp->opcode,"%si",cmpname[uimm*2+i]); + if (i = (int)PPCGETCRD(in)) { + sprintf(oper,"cr%c,",'0'+i); + dp->operands += 4; + } + imm(dp,in,uimm,2,0); + dp->operands = oper; + } + else + ill(dp,in); + } + + + static void addi(struct DisasmPara_PPC *dp,ppc_word in,const char *ext) + { + if ((in&0x08000000) && !PPCGETA(in)) { + sprintf(dp->opcode,"l%s",ext); /* li, lis */ + if(!strcmp(ext, "i")) + imm(dp,in,0,3,0); + else + imm(dp,in,1,3,1); + } + else { + sprintf(dp->opcode,"%s%s",(in&0x8000)?"sub":"add",ext); + if (in & 0x8000) + in = (in^0xffff) + 1; + imm(dp,in,1,0,0); + } + } + + + static int branch(struct DisasmPara_PPC *dp,ppc_word in, const char *bname,int aform,int bdisp) + /* build a branch instr. and return number of chars written to operand */ + { + int bo = (int)PPCGETD(in); + int bi = (int)PPCGETA(in); + char y = (char)(bo & 1); + int opercnt = 0; + const char *ext = b_ext[aform*2+(int)(in&1)]; + + if (bdisp < 0) + y ^= 1; + y = y ? '+':'-'; + + if (bo & 4) { + /* standard case - no decrement */ + if (bo & 16) { + /* branch always */ + if (PPCGETIDX(in) != 16) { + sprintf(dp->opcode,"b%s%s",bname,ext); + } + else { + sprintf(dp->opcode,"bc%s",ext); + opercnt = sprintf(dp->operands,"%d, %d",bo,bi); + } + } + else { + /* branch conditional */ + sprintf(dp->opcode,"b%s%s%s%c",b_condition[((bo&8)>>1)+(bi&3)], + bname,ext,y); + if (bi >= 4) + opercnt = sprintf(dp->operands,"cr%d",bi>>2); + } + } + + else { + /* CTR is decremented and checked */ + sprintf(dp->opcode,"bd%s%s%s%c",b_decr[bo>>1],bname,ext,y); + if (!(bo & 16)) + opercnt = sprintf(dp->operands,"%d",bi); + } + + return (opercnt); + } + + + static void bc(struct DisasmPara_PPC *dp,ppc_word in) + { + unsigned long d = (int)(in & 0xfffc); + int offs; + char *oper = dp->operands; + + if(d & 0x8000) d |= 0xffff0000; + + if (offs = branch(dp,in,"",(in&2)?1:0,d)) { + oper += offs; + *oper++ = ','; + } + if (in & 2) /* AA ? */ + sprintf(dp->operands,"->0x%.8X",(unsigned long)d); + else + sprintf(oper,"->0x%.8X",(unsigned long)(*dp->iaddr) + d); + dp->type = PPCINSTR_BRANCH; + dp->displacement = (ppc_word)d; + } + + + static void bli(struct DisasmPara_PPC *dp,ppc_word in) + { + unsigned long d = (unsigned long)(in & 0x3fffffc); + + if(d & 0x02000000) d |= 0xfc000000; + + sprintf(dp->opcode,"b%s",b_ext[in&3]); + if (in & 2) /* AA ? */ + sprintf(dp->operands,"->0x%.8X",(unsigned long)d); + else + sprintf(dp->operands,"->0x%.8X",(unsigned long)(*dp->iaddr) + d); + dp->type = PPCINSTR_BRANCH; + dp->displacement = (ppc_word)d; + } + + + static void mcrf(struct DisasmPara_PPC *dp,ppc_word in,char c) + { + if (!(in & 0x0063f801)) { + sprintf(dp->opcode,"mcrf%c",c); + sprintf(dp->operands,"cr%d, cr%d",(int)PPCGETCRD(in),(int)PPCGETCRA(in)); + } + else + ill(dp,in); + } + + + static void crop(struct DisasmPara_PPC *dp,ppc_word in,const char *n1,const char *n2) + { + int crd = (int)PPCGETD(in); + int cra = (int)PPCGETA(in); + int crb = (int)PPCGETB(in); + + if (!(in & 1)) { + sprintf(dp->opcode,"cr%s",(cra==crb && n2)?n2:n1); + if (cra == crb && n2) + sprintf(dp->operands,"%d, %d",crd,cra); + else + sprintf(dp->operands,"%d, %d, %d",crd,cra,crb); + } + else + ill(dp,in); + } + + + static void nooper(struct DisasmPara_PPC *dp,ppc_word in,const char *name, + unsigned char dmode) + { + if (in & (PPCDMASK|PPCAMASK|PPCBMASK|1)) { + ill(dp,in); + } + else { + dp->flags |= dmode; + strcpy(dp->opcode,name); + } + } + + + static unsigned int Helper_Mask(int mb, int me) + { + //first make 001111111111111 part + unsigned int begin = 0xFFFFFFFF >> mb; + //then make 000000000001111 part, which is used to flip the bits of the first one + unsigned int end = me < 31 ? (0xFFFFFFFF >> (me + 1)) : 0; + //do the bitflip + unsigned int mask = begin ^ end; + //and invert if backwards + if (me < mb) + return ~mask; + else + return mask; + } + + + static void rlw(struct DisasmPara_PPC *dp,ppc_word in,const char *name,int i) + { + int s = (int)PPCGETD(in); + int a = (int)PPCGETA(in); + int bsh = (int)PPCGETB(in); + int mb = (int)PPCGETC(in); + int me = (int)PPCGETM(in); + + + + sprintf(dp->opcode,"rlw%s%c",name,in&1?'.':'\0'); + sprintf(dp->operands,"%s, %s, %s%d, %d, %d (%08x)",regnames[a],regnames[s],regsel[i],bsh,mb,me,Helper_Mask(mb, me)); + } + + + static void ori(struct DisasmPara_PPC *dp,ppc_word in,const char *name) + { + strcpy(dp->opcode,name); + imm(dp,in,1,1,1); + } + + + static void rld(struct DisasmPara_PPC *dp,ppc_word in,const char *name,int i) + { + int s = (int)PPCGETD(in); + int a = (int)PPCGETA(in); + int bsh = i ? (int)PPCGETB(in) : (int)(((in&2)<<4)+PPCGETB(in)); + int m = (int)(in&0x7e0)>>5; + + dp->flags |= PPCF_64; + sprintf(dp->opcode,"rld%s%c",name,in&1?'.':'\0'); + sprintf(dp->operands,"%s, %s, %s%d, %d",regnames[a],regnames[s],regsel[i],bsh,m); + } + + + static void cmp(struct DisasmPara_PPC *dp,ppc_word in) + { + char *oper = dp->operands; + int i = (int)PPCGETL(in); + + if (i < 2) { + if (i) + dp->flags |= PPCF_64; + strcpy(dp->opcode,cmpname[((in&PPCIDX2MASK)?2:0)+i]); + if (i = (int)PPCGETCRD(in)) + oper += sprintf(oper,"cr%c,",'0'+i); + ra_rb(oper,in); + } + else + ill(dp,in); + } + + + static void trap(struct DisasmPara_PPC *dp,ppc_word in,unsigned char dmode) + { + const char *cnd; + int to = (int)PPCGETD(in); + + if (cnd = trap_condition[to]) { + dp->flags |= dmode; + sprintf(dp->opcode,"t%c%s",dmode?'d':'w',cnd); + ra_rb(dp->operands,in); + } + else { + if (to == 31) { + if (dmode) { + dp->flags |= dmode; + strcpy(dp->opcode,"td"); + strcpy(dp->operands,"31,0,0"); + } + else + strcpy(dp->opcode,"trap"); + } + else + ill(dp,in); + } + } + + + static void dab(struct DisasmPara_PPC *dp,ppc_word in,const char *name,int mask, + int smode,int chkoe,int chkrc,unsigned char dmode) + /* standard instruction: xxxx rD,rA,rB */ + { + if (chkrc>=0 && ((in&1)!=(unsigned)chkrc)) { + ill(dp,in); + } + else { + dp->flags |= dmode; + if (smode) + in = swapda(in); /* rA,rS,rB */ + sprintf(dp->opcode,"%s%s%s",name, + oesel[chkoe&&(in&PPCOE)],rcsel[(chkrc<0)&&(in&1)]); + rd_ra_rb(dp->operands,in,mask); + } + } + + + static void rrn(struct DisasmPara_PPC *dp,ppc_word in,const char *name, + int smode,int chkoe,int chkrc,unsigned char dmode) + /* Last operand is no register: xxxx rD,rA,NB */ + { + char *s; + + if (chkrc>=0 && ((in&1)!=(unsigned)chkrc)) { + ill(dp,in); + } + else { + dp->flags |= dmode; + if (smode) + in = swapda(in); /* rA,rS,NB */ + sprintf(dp->opcode,"%s%s%s",name, + oesel[chkoe&&(in&PPCOE)],rcsel[(chkrc<0)&&(in&1)]); + s = rd_ra_rb(dp->operands,in,6); + sprintf(s,",%d",(int)PPCGETB(in)); + } + } + + + static void mtcr(struct DisasmPara_PPC *dp,ppc_word in) + { + int s = (int)PPCGETD(in); + int crm = (int)(in&0x000ff000)>>12; + char *oper = dp->operands; + + if (in & 0x00100801) { + ill(dp,in); + } + else { + sprintf(dp->opcode,"mtcr%c",crm==0xff?'\0':'f'); + if (crm != 0xff) + oper += sprintf(oper,"0x%02x,",crm); + sprintf(oper,"%s",regnames[s]); + } + } + + + static void msr(struct DisasmPara_PPC *dp,ppc_word in,int smode) + { + int s = (int)PPCGETD(in); + int sr = (int)(in&0x000f0000)>>16; + + if (in & 0x0010f801) { + ill(dp,in); + } + else { + dp->flags |= PPCF_SUPER; + sprintf(dp->opcode,"m%csr",smode?'t':'f'); + if (smode) + sprintf(dp->operands,"%d, %s",sr,regnames[s]); + else + sprintf(dp->operands,"%s, %d",regnames[s],sr); + } + } + + + static void mspr(struct DisasmPara_PPC *dp,ppc_word in,int smode) + { + int d = (int)PPCGETD(in); + int spr = (int)((PPCGETB(in)<<5)+PPCGETA(in)); + int fmt = 0; + const char *x; + + if (in & 1) { + ill(dp,in); + } + + else { + if (spr!=1 && spr!=8 && spr!=9) + dp->flags |= PPCF_SUPER; + switch (spr) { + case 1: + x = "xer"; + break; + case 8: + x = "lr"; + break; + case 9: + x = "ctr"; + break; + default: + x = "spr"; + fmt = 1; + break; + } + + sprintf(dp->opcode,"m%c%s",smode?'t':'f',x); + if (fmt) { + if (smode) + sprintf(dp->operands,"%s, %s",spr_name(spr),regnames[d]); + else + sprintf(dp->operands,"%s, %s",regnames[d],spr_name(spr)); + } + else + sprintf(dp->operands,"%s",regnames[d]); + } + } + + + static void mtb(struct DisasmPara_PPC *dp,ppc_word in) + { + int d = (int)PPCGETD(in); + int tbr = (int)((PPCGETB(in)<<5)+PPCGETA(in)); + char *s = dp->operands; + char x; + + if (in & 1) { + ill(dp,in); + } + + else { + s += sprintf(s,"%s",regnames[d]); + switch (tbr) { + case 268: + x = 'l'; + break; + case 269: + x = 'u'; + break; + default: + x = '\0'; + dp->flags |= PPCF_SUPER; + sprintf(s,",%d",tbr); + break; + } + sprintf(dp->opcode,"mftb%c",x); + } + } + + + static void sradi(struct DisasmPara_PPC *dp,ppc_word in) + { + int s = (int)PPCGETD(in); + int a = (int)PPCGETA(in); + int bsh = (int)(((in&2)<<4)+PPCGETB(in)); + + dp->flags |= PPCF_64; + sprintf(dp->opcode,"sradi%c",in&1?'.':'\0'); + sprintf(dp->operands,"%s, %s, %d",regnames[a],regnames[s],bsh); + } + + static const char *ldst_offs(unsigned long val) + { + static char buf[8]; + + if(val == 0) + { + return "0"; + } + else + { + if(val & 0x8000) + { + sprintf(buf, "-0x%.4X", ((~val) & 0xffff) + 1); + } + else + { + sprintf(buf, "0x%.4X", val); + } + + return buf; + } + } + + static void ldst(struct DisasmPara_PPC *dp,ppc_word in,const char *name, + char reg,unsigned char dmode) + { + int s = (int)PPCGETD(in); + int a = (int)PPCGETA(in); + int d = (ppc_word)(in & 0xffff); + + dp->type = PPCINSTR_LDST; + dp->flags |= dmode; + dp->sreg = (short)a; + // if (d >= 0x8000) + // d -= 0x10000; + dp->displacement = (ppc_word)d; + strcpy(dp->opcode,name); + if(reg == 'r') + { + sprintf(dp->operands,"%s, %s (%s)", regnames[s], ldst_offs(d), regnames[a]); + } + else + { + sprintf(dp->operands,"%c%d, %s (%s)",reg,s, ldst_offs(d), regnames[a]); + } + } + + + static void fdabc(struct DisasmPara_PPC *dp,ppc_word in, const char *name, + int mask,unsigned char dmode) + /* standard floating point instruction: xxxx fD,fA,fC,fB */ + { + static const char *fmt = "f%d,"; + char *s = dp->operands; + int err = 0; + + dp->flags |= dmode; + sprintf(dp->opcode,"f%s%s",name,rcsel[in&1]); + s += sprintf(s,fmt,(int)PPCGETD(in)); + if (mask & 4) + s += sprintf(s,fmt,(int)PPCGETA(in)); + else + err |= (int)PPCGETA(in); + if (mask & 2) + s += sprintf(s,fmt,(int)PPCGETC(in)); + else if (PPCGETC(in)) + err |= (int)PPCGETC(in); + if (mask & 1) + s += sprintf(s,fmt,(int)PPCGETB(in)); + else if (!(mask&8)) + err |= (int)PPCGETB(in); + *(s-1) = '\0'; + if (err) + ill(dp,in); + } + + + static void fdab(struct DisasmPara_PPC *dp,ppc_word in,const char *name,int mask) + /* indexed float instruction: xxxx fD,rA,rB */ + { + strcpy(dp->opcode,name); + fd_ra_rb(dp->operands,in,mask); + } + + + static void fcmp(struct DisasmPara_PPC *dp,ppc_word in,char c) + { + if (in & 0x00600001) { + ill(dp,in); + } + else { + sprintf(dp->opcode,"fcmp%c",c); + sprintf(dp->operands,"cr%d,f%d,f%d",(int)PPCGETCRD(in), + (int)PPCGETA(in),(int)PPCGETB(in)); + } + } + + + static void mtfsb(struct DisasmPara_PPC *dp,ppc_word in,int n) + { + if (in & (PPCAMASK|PPCBMASK)) { + ill(dp,in); + } + else { + sprintf(dp->opcode,"mtfsb%d%s",n,rcsel[in&1]); + sprintf(dp->operands,"%d",(int)PPCGETD(in)); + } + } + + + ////////////////////////////////////////////////////////////////////////////////// + //PAIRED + ////////////////////////////////////////////////////////////////////////////////// + + /* + sprintf(buf, "psq_lx", FD); + sprintf(buf, "psq_stx", FD); + sprintf(buf, "psq_lux", FD); + sprintf(buf, "psq_stux", FD); + */ +#define RA ((inst >> 16) & 0x1f) +#define RB ((inst >> 11) & 0x1f) +#define RC ((inst >> 6) & 0x1f) +#define RD ((inst >> 21) & 0x1f) +#define RS ((inst >> 21) & 0x1f) +#define FA ((inst >> 16) & 0x1f) +#define FB ((inst >> 11) & 0x1f) +#define FC ((inst >> 6) & 0x1f) +#define FD ((inst >> 21) & 0x1f) +#define FS ((inst >> 21) & 0x1f) +#define IMM (inst & 0xffff) +#define UIMM (inst & 0xffff) +#define OFS (inst & 0xffff) +#define OPCD ((inst >> 26) & 0x3f) +#define XO_10 ((inst >> 1) & 0x3ff) +#define XO_9 ((inst >> 1) & 0x1ff) +#define XO_5 ((inst >> 1) & 0x1f) +#define Rc (inst & 1) +#define SH ((inst >> 11) & 0x1f) +#define MB ((inst >> 6) & 0x1f) +#define ME ((inst >> 1) & 0x1f) +#define OE ((inst >> 10) & 1) +#define TO ((inst >> 21) & 0x1f) +#define CRFD ((inst >> 23) & 0x7) +#define CRFS ((inst >> 18) & 0x7) +#define CRBD ((inst >> 21) & 0x1f) +#define CRBA ((inst >> 16) & 0x1f) +#define CRBB ((inst >> 11) & 0x1f) +#define L ((inst >> 21) & 1) +#define NB ((inst >> 11) & 0x1f) +#define AA ((inst >> 1) & 1) +#define LK (inst & 1) +#define LI ((inst >> 2) & 0xffffff) +#define BO ((inst >> 21) & 0x1f) +#define BI ((inst >> 16) & 0x1f) +#define BD ((inst >> 2) & 0x3fff) + +#define MTFSFI_IMM ((inst >> 12) & 0xf) +#define FM ((inst >> 17) & 0xff) +#define SR ((inst >> 16) & 0xf) +#define SPR ((inst >> 11) & 0x3ff) +#define TBR ((inst >> 11) & 0x3ff) +#define CRM ((inst >> 12) & 0xff) + inline int SEX12(unsigned int x) + { + return x & 0x800 ? (x|0xFFFFF000) : x; + } + + static void ps(struct DisasmPara_PPC *dp,ppc_word inst) + { + ppc_word pc = *dp->iaddr; + char *op = dp->opcode; + char *pr = dp->operands; + switch((inst>>1)&0x1F) + { + case 6: + strcpy(op, "ps_lux"); + sprintf(pr, "p%u, (r%u + r%u)", FD, RA, RB); + return; + + case 18: + strcpy(op, "ps_div"); + sprintf(pr, "p%u, p%u/p%u", FD, FA, FB); + return; + case 20: + strcpy(op, "ps_sub"); + sprintf(pr, "p%u, p%u-p%u", FD, FA, FB); + return; + case 21: + strcpy(op, "ps_add"); + sprintf(pr, "p%u, p%u+p%u", FD, FA, FB); + return; + case 23: + strcpy(op, "ps_sel"); + sprintf(pr, "p%u>=0?p%u:p%u", FD, FA, FC, FB); + return; + case 24: + strcpy(op, "ps_res"); + sprintf(pr, "p%u, (1/p%u)", FD, FB); + return; + + case 25: + strcpy(op, "ps_mul"); + sprintf(pr, "p%u, p%u*p%u", FD, FA, FC); + return; + + case 26: //rsqrte + strcpy(op, "ps_rsqrte"); + sprintf(pr, "p%u, p%u", FD, FB); + return; + case 28: //msub + strcpy(op, "ps_msub"); + sprintf(pr, "p%u, p%u*p%u-p%u", FD, FA, FC, FB); + return; + case 29: //madd + strcpy(op, "ps_madd"); + sprintf(pr, "p%u, p%u*p%u+p%u", FD, FA, FC, FB); + return; + case 30: //nmsub + strcpy(op, "ps_nmsub"); + sprintf(pr, "p%u, -(p%u*p%u-p%u)", FD, FA, FC, FB); + return; + case 31: //nmadd + strcpy(op, "ps_nmadd"); + sprintf(pr, "p%u, -(p%u*p%u+p%u)", FD, FA, FC, FB); + return; + case 10: + strcpy(op, "ps_sum0"); + sprintf(pr, "p%u, 0=p%u+p%u, 1=p%u", FD, FA, FB, FC); + return; + case 11: + strcpy(op, "ps_sum1"); + sprintf(pr, "p%u, 0=p%u, 1=p%u+p%u", FD, FC, FA, FB); + return; + case 12: + strcpy(op, "ps_muls0"); + sprintf(pr, "p%u, p%u*p%u[0]", FD, FA, FC); + return; + case 13: + strcpy(op, "ps_muls1"); + sprintf(pr, "p%u, p%u*p%u[1]", FD, FA, FC); + return; + case 14: + strcpy(op, "ps_madds0"); + sprintf(pr, "p%u, p%u*p%u[0]+p%u", FD, FA, FC, FB); + return; + case 15: + strcpy(op, "ps_madds1"); + sprintf(pr, "p%u, p%u*p%u[1]+p%u", FD, FA, FC, FB); + return; + } + + switch((inst>>1)&0x3FF) + { + //10-bit suckers (?) + case 40: //nmadd + strcpy(op, "ps_neg"); + sprintf(pr, "p%u, -p%u", FD, FB); + return; + case 72: //nmadd + strcpy(op, "ps_mr"); + sprintf(pr, "p%u, p%u", FD, FB); + return; + case 136: + strcpy(op, "ps_nabs"); + sprintf(pr, "p%u, -|p%u|", FD, FB); + return; + case 264: + strcpy(op, "ps_abs"); + sprintf(pr, "p%u, |p%u|", FD, FB); + return; + case 0: + strcpy(op, "ps_cmpu0"); + sprintf(pr, "ps_cmpu0", FD); + return; + case 32: + strcpy(op,"ps_cmpq0"); + sprintf(pr, "ps_cmpo0", FD); + return; + case 64: + strcpy(op,"ps_cmpu1"); + sprintf(pr, "ps_cmpu1", FD); + return; + case 96: + strcpy(op,"ps_cmpo1"); + sprintf(pr, "ps_cmpo1", FD); + return; + case 528: + strcpy(op,"ps_merge00"); + sprintf(pr, "p%u, p%u[0],p%u[0]", FD, FA, FB); + return; + case 560: + strcpy(op,"ps_merge01"); + sprintf(pr, "p%u, p%u[0],p%u[1]", FD, FA, FB); + return; + case 592: + strcpy(op,"ps_merge10"); + sprintf(pr, "p%u, p%u[1],p%u[0]", FD, FA, FB); + return; + case 624: + strcpy(op,"ps_merge11"); + sprintf(pr, "p%u, p%u[1],p%u[1]", FD, FA, FB); + return; + case 1014: + strcpy(op,"dcbz_l"); + sprintf(pr, ""); + return; + } + + // default: + sprintf(op, "ps_%i",((inst>>1)&0x1f)); + strcpy(pr,"---"); + return; + } + + static void ps_mem(struct DisasmPara_PPC *dp,ppc_word inst) + { + ppc_word pc = *dp->iaddr; + char *op = dp->opcode; + char *pr = dp->operands; + switch(PPCGETIDX(inst)) + { + case 56: + strcpy(op,"psq_l"); + sprintf(pr, "p%u, %i(r%u)", RS, SEX12(inst&0xFFF), RA); + break; + case 57: + strcpy(op,"psq_lu"); + sprintf(pr, "", FD); + break; + case 60: + strcpy(op,"psq_st"); + sprintf(pr, "%i(r%u), p%u", SEX12(inst&0xFFF), RA, RS); + break; + case 61: + strcpy(op,"psq_stu"); + sprintf(pr, "r%u, p%u ?", RA, RS); + break; + } + } + + + ppc_word *PPC_Disassemble(struct DisasmPara_PPC *dp) + /* Disassemble PPC instruction and return a pointer to the next */ + /* instruction, or NULL if an error occured. */ + { + ppc_word in = *(dp->instr); + + if (dp->opcode==NULL || dp->operands==NULL) + return (NULL); /* no buffers */ + +#if LITTLEENDIAN + in = (in & 0xff)<<24 | (in & 0xff00)<<8 | (in & 0xff0000)>>8 | + (in & 0xff000000)>>24; +#endif + dp->type = PPCINSTR_OTHER; + dp->flags = 0; + *(dp->operands) = 0; + + switch (PPCGETIDX(in)) + { + case 1: + sprintf(dp->opcode,"HLE"); + //HLE call + break; + case 2: + trapi(dp,in,PPCF_64); /* tdi */ + break; + + case 3: + trapi(dp,in,0); /* twi */ + break; + case 4: + ps(dp,in); + break; + case 56: + case 57: + case 60: + case 61: + ps_mem(dp,in); + break; + + + case 7: + strcpy(dp->opcode,"mulli"); + imm(dp,in,0,0,0); + break; + + case 8: + strcpy(dp->opcode,"subfic"); + imm(dp,in,0,0,0); + break; + + case 10: + cmpi(dp,in,1); /* cmpli */ + break; + + case 11: + cmpi(dp,in,0); /* cmpi */ + break; + + case 12: + addi(dp,in,"ic"); /* addic */ + break; + + case 13: + addi(dp,in,"ic."); /* addic. */ + break; + + case 14: + addi(dp,in,"i"); /* addi */ + break; + + case 15: + addi(dp,in,"is"); /* addis */ + break; + + case 16: + bc(dp,in); + break; + + case 17: + if ((in & ~PPCIDXMASK) == 2) + strcpy(dp->opcode,"sc"); + else + ill(dp,in); + break; + + case 18: + bli(dp,in); + break; + + case 19: + switch (PPCGETIDX2(in)) { + case 0: + mcrf(dp,in,'\0'); /* mcrf */ + break; + + case 16: + branch(dp,in,"lr",0,0); /* bclr */ + break; + + case 33: + crop(dp,in,"nor","not"); /* crnor */ + break; + + case 50: + nooper(dp,in,"rfi",PPCF_SUPER); + break; + + case 129: + crop(dp,in,"andc",NULL); /* crandc */ + break; + + case 150: + nooper(dp,in,"isync",0); + break; + + case 193: + crop(dp,in,"xor","clr"); /* crxor */ + break; + + case 225: + crop(dp,in,"nand",NULL); /* crnand */ + break; + + case 257: + crop(dp,in,"and",NULL); /* crand */ + break; + + case 289: + crop(dp,in,"eqv","set"); /* creqv */ + break; + + case 417: + crop(dp,in,"orc",NULL); /* crorc */ + break; + + case 449: + crop(dp,in,"or","move"); /* cror */ + break; + + case 528: + branch(dp,in,"ctr",0,0); /* bcctr */ + break; + + default: + ill(dp,in); + break; + } + break; + + case 20: + rlw(dp,in,"imi",0); /* rlwimi */ + break; + + case 21: + rlw(dp,in,"inm",0); /* rlwinm */ + break; + + case 23: + rlw(dp,in,"nm",1); /* rlwnm */ + break; + + case 24: + if (in & ~PPCIDXMASK) + ori(dp,in,"ori"); + else + strcpy(dp->opcode,"nop"); + break; + + case 25: + ori(dp,in,"oris"); + break; + + case 26: + ori(dp,in,"xori"); + break; + + case 27: + ori(dp,in,"xoris"); + break; + + case 28: + ori(dp,in,"andi."); + break; + + case 29: + ori(dp,in,"andis."); + break; + + case 30: + switch (in & 0x1c) { + case 0: + rld(dp,in,"icl",0); /* rldicl */ + break; + case 1: + rld(dp,in,"icr",0); /* rldicr */ + break; + case 2: + rld(dp,in,"ic",0); /* rldic */ + break; + case 3: + rld(dp,in,"imi",0); /* rldimi */ + break; + case 4: + rld(dp,in,in&2?"cl":"cr",1); /* rldcl, rldcr */ + break; + default: + ill(dp,in); + break; + } + break; + + case 31: + switch (PPCGETIDX2(in)) { + case 0: + case 32: + if (in & 1) + ill(dp,in); + else + cmp(dp,in); /* cmp, cmpl */ + break; + + case 4: + if (in & 1) + ill(dp,in); + else + trap(dp,in,0); /* tw */ + break; + + case 8: + case (PPCOE>>1)+8: + dab(dp,swapab(in),"subc",7,0,1,-1,0); + break; + + case 9: + dab(dp,in,"mulhdu",7,0,0,-1,PPCF_64); + break; + + case 10: + case (PPCOE>>1)+10: + dab(dp,in,"addc",7,0,1,-1,0); + break; + + case 11: + dab(dp,in,"mulhwu",7,0,0,-1,0); + break; + + case 19: + if (in & (PPCAMASK|PPCBMASK)) + ill(dp,in); + else + dab(dp,in,"mfcr",4,0,0,0,0); + break; + + case 20: + dab(dp,in,"lwarx",7,0,0,0,0); + break; + + case 21: + dab(dp,in,"ldx",7,0,0,0,PPCF_64); + break; + + case 23: + dab(dp,in,"lwzx",7,0,0,0,0); + break; + + case 24: + dab(dp,in,"slw",7,1,0,-1,0); + break; + + case 26: + if (in & PPCBMASK) + ill(dp,in); + else + dab(dp,in,"cntlzw",6,1,0,-1,0); + break; + + case 27: + dab(dp,in,"sld",7,1,0,-1,PPCF_64); + break; + + case 28: + dab(dp,in,"and",7,1,0,-1,0); + break; + + case 40: + case (PPCOE>>1)+40: + dab(dp,swapab(in),"sub",7,0,1,-1,0); + break; + + case 53: + dab(dp,in,"ldux",7,0,0,0,PPCF_64); + break; + + case 54: + if (in & PPCDMASK) + ill(dp,in); + else + dab(dp,in,"dcbst",3,0,0,0,0); + break; + + case 55: + dab(dp,in,"lwzux",7,0,0,0,0); + break; + + case 58: + if (in & PPCBMASK) + ill(dp,in); + else + dab(dp,in,"cntlzd",6,1,0,-1,PPCF_64); + break; + + case 60: + dab(dp,in,"andc",7,1,0,-1,0); + break; + + case 68: + trap(dp,in,PPCF_64); /* td */ + break; + + case 73: + dab(dp,in,"mulhd",7,0,0,-1,PPCF_64); + break; + + case 75: + dab(dp,in,"mulhw",7,0,0,-1,0); + break; + + case 83: + if (in & (PPCAMASK|PPCBMASK)) + ill(dp,in); + else + dab(dp,in,"mfmsr",4,0,0,0,PPCF_SUPER); + break; + + case 84: + dab(dp,in,"ldarx",7,0,0,0,PPCF_64); + break; + + case 86: + if (in & PPCDMASK) + ill(dp,in); + else + dab(dp,in,"dcbf",3,0,0,0,0); + break; + + case 87: + dab(dp,in,"lbzx",7,0,0,0,0); + break; + + case 104: + case (PPCOE>>1)+104: + if (in & PPCBMASK) + ill(dp,in); + else + dab(dp,in,"neg",6,0,1,-1,0); + break; + + case 119: + dab(dp,in,"lbzux",7,0,0,0,0); + break; + + case 124: + if (PPCGETD(in) == PPCGETB(in)) + dab(dp,in,"not",6,1,0,-1,0); + else + dab(dp,in,"nor",7,1,0,-1,0); + break; + + case 136: + case (PPCOE>>1)+136: + dab(dp,in,"subfe",7,0,1,-1,0); + break; + + case 138: + case (PPCOE>>1)+138: + dab(dp,in,"adde",7,0,1,-1,0); + break; + + case 144: + mtcr(dp,in); + break; + + case 146: + if (in & (PPCAMASK|PPCBMASK)) + ill(dp,in); + else + dab(dp,in,"mtmsr",4,0,0,0,PPCF_SUPER); + break; + + case 149: + dab(dp,in,"stdx",7,0,0,0,PPCF_64); + break; + + case 150: + dab(dp,in,"stwcx.",7,0,0,1,0); + break; + + case 151: + dab(dp,in,"stwx",7,0,0,0,0); + break; + + case 181: + dab(dp,in,"stdux",7,0,0,0,PPCF_64); + break; + + case 183: + dab(dp,in,"stwux",7,0,0,0,0); + break; + + case 200: + case (PPCOE>>1)+200: + if (in & PPCBMASK) + ill(dp,in); + else + dab(dp,in,"subfze",6,0,1,-1,0); + break; + + case 202: + case (PPCOE>>1)+202: + if (in & PPCBMASK) + ill(dp,in); + else + dab(dp,in,"addze",6,0,1,-1,0); + break; + + case 210: + msr(dp,in,1); /* mfsr */ + break; + + case 214: + dab(dp,in,"stdcx.",7,0,0,1,PPCF_64); + break; + + case 215: + dab(dp,in,"stbx",7,0,0,0,0); + break; + + case 232: + case (PPCOE>>1)+232: + if (in & PPCBMASK) + ill(dp,in); + else + dab(dp,in,"subfme",6,0,1,-1,0); + break; + + case 233: + case (PPCOE>>1)+233: + dab(dp,in,"mulld",7,0,1,-1,PPCF_64); + break; + + case 234: + case (PPCOE>>1)+234: + if (in & PPCBMASK) + ill(dp,in); + else + dab(dp,in,"addme",6,0,1,-1,0); + break; + + case 235: + case (PPCOE>>1)+235: + dab(dp,in,"mullw",7,0,1,-1,0); + break; + + case 242: + if (in & PPCAMASK) + ill(dp,in); + else + dab(dp,in,"mtsrin",5,0,0,0,PPCF_SUPER); + break; + + case 246: + if (in & PPCDMASK) + ill(dp,in); + else + dab(dp,in,"dcbtst",3,0,0,0,0); + break; + + case 247: + dab(dp,in,"stbux",7,0,0,0,0); + break; + + case 266: + case (PPCOE>>1)+266: + dab(dp,in,"add",7,0,1,-1,0); + break; + + case 278: + if (in & PPCDMASK) + ill(dp,in); + else + dab(dp,in,"dcbt",3,0,0,0,0); + break; + + case 279: + dab(dp,in,"lhzx",7,0,0,0,0); + break; + + case 284: + dab(dp,in,"eqv",7,1,0,-1,0); + break; + + case 306: + if (in & (PPCDMASK|PPCAMASK)) + ill(dp,in); + else + dab(dp,in,"tlbie",1,0,0,0,PPCF_SUPER); + break; + + case 310: + dab(dp,in,"eciwx",7,0,0,0,0); + break; + + case 311: + dab(dp,in,"lhzux",7,0,0,0,0); + break; + + case 316: + dab(dp,in,"xor",7,1,0,-1,0); + break; + + case 339: + mspr(dp,in,0); /* mfspr */ + break; + + case 341: + dab(dp,in,"lwax",7,0,0,0,PPCF_64); + break; + + case 343: + dab(dp,in,"lhax",7,0,0,0,0); + break; + + case 370: + nooper(dp,in,"tlbia",PPCF_SUPER); + break; + + case 371: + mtb(dp,in); /* mftb */ + break; + + case 373: + dab(dp,in,"lwaux",7,0,0,0,PPCF_64); + break; + + case 375: + dab(dp,in,"lhaux",7,0,0,0,0); + break; + + case 407: + dab(dp,in,"sthx",7,0,0,0,0); + break; + + case 412: + dab(dp,in,"orc",7,1,0,-1,0); + break; + + case 413: + sradi(dp,in); /* sradi */ + break; + + case 434: + if (in & (PPCDMASK|PPCAMASK)) + ill(dp,in); + else + dab(dp,in,"slbie",1,0,0,0,PPCF_SUPER|PPCF_64); + break; + + case 438: + dab(dp,in,"ecowx",7,0,0,0,0); + break; + + case 439: + dab(dp,in,"sthux",7,0,0,0,0); + break; + + case 444: + if (PPCGETD(in) == PPCGETB(in)) + dab(dp,in,"mr",6,1,0,-1,0); + else + dab(dp,in,"or",7,1,0,-1,0); + break; + + case 457: + case (PPCOE>>1)+457: + dab(dp,in,"divdu",7,0,1,-1,PPCF_64); + break; + + case 459: + case (PPCOE>>1)+459: + dab(dp,in,"divwu",7,0,1,-1,0); + break; + + case 467: + mspr(dp,in,1); /* mtspr */ + break; + + case 470: + if (in & PPCDMASK) + ill(dp,in); + else + dab(dp,in,"dcbi",3,0,0,0,0); + break; + + case 476: + dab(dp,in,"nand",7,1,0,-1,0); + break; + + case 489: + case (PPCOE>>1)+489: + dab(dp,in,"divd",7,0,1,-1,PPCF_64); + break; + + case 491: + case (PPCOE>>1)+491: + dab(dp,in,"divw",7,0,1,-1,0); + break; + + case 498: + nooper(dp,in,"slbia",PPCF_SUPER|PPCF_64); + break; + + case 512: + if (in & 0x007ff801) + ill(dp,in); + else { + strcpy(dp->opcode,"mcrxr"); + sprintf(dp->operands,"cr%d",(int)PPCGETCRD(in)); + } + break; + + case 533: + dab(dp,in,"lswx",7,0,0,0,0); + break; + + case 534: + dab(dp,in,"lwbrx",7,0,0,0,0); + break; + + case 535: + fdab(dp,in,"lfsx",7); + break; + + case 536: + dab(dp,in,"srw",7,1,0,-1,0); + break; + + case 539: + dab(dp,in,"srd",7,1,0,-1,PPCF_64); + break; + + case 566: + nooper(dp,in,"tlbsync",PPCF_SUPER); + break; + + case 567: + fdab(dp,in,"lfsux",7); + break; + + case 595: + msr(dp,in,0); /* mfsr */ + break; + + case 597: + rrn(dp,in,"lswi",0,0,0,0); + break; + + case 598: + nooper(dp,in,"sync",PPCF_SUPER); + break; + + case 599: + fdab(dp,in,"lfdx",7); + break; + + case 631: + fdab(dp,in,"lfdux",7); + break; + + case 659: + if (in & PPCAMASK) + ill(dp,in); + else + dab(dp,in,"mfsrin",5,0,0,0,PPCF_SUPER); + break; + + case 661: + dab(dp,in,"stswx",7,0,0,0,0); + break; + + case 662: + dab(dp,in,"stwbrx",7,0,0,0,0); + break; + + case 663: + fdab(dp,in,"stfsx",7); + break; + + case 695: + fdab(dp,in,"stfsux",7); + break; + + case 725: + rrn(dp,in,"stswi",0,0,0,0); + break; + + case 727: + fdab(dp,in,"stfdx",7); + break; + + case 759: + fdab(dp,in,"stfdux",7); + break; + + case 790: + dab(dp,in,"lhbrx",7,0,0,0,0); + break; + + case 792: + dab(dp,in,"sraw",7,1,0,-1,0); + break; + + case 794: + dab(dp,in,"srad",7,1,0,-1,PPCF_64); + break; + + case 824: + rrn(dp,in,"srawi",1,0,-1,0); + break; + + case 854: + nooper(dp,in,"eieio",PPCF_SUPER); + break; + + case 918: + dab(dp,in,"sthbrx",7,0,0,0,0); + break; + + case 922: + if (in & PPCBMASK) + ill(dp,in); + else + dab(dp,in,"extsh",6,1,0,-1,0); + break; + + case 954: + if (in & PPCBMASK) + ill(dp,in); + else + dab(dp,in,"extsb",6,1,0,-1,0); + break; + + case 982: + if (in & PPCDMASK) + ill(dp,in); + else + dab(dp,in,"icbi",3,0,0,0,0); + break; + + case 983: + fdab(dp,in,"stfiwx",7); + break; + + case 986: + if (in & PPCBMASK) + ill(dp,in); + else + dab(dp,in,"extsw",6,1,0,-1,PPCF_64); + break; + + case 1014: + if (in & PPCDMASK) + ill(dp,in); + else + dab(dp,in,"dcbz",3,0,0,0,0); + break; + + default: + ill(dp,in); + break; + } + break; + + case 32: + case 33: + case 34: + case 35: + case 36: + case 37: + case 38: + case 39: + case 40: + case 41: + case 42: + case 43: + case 44: + case 45: + case 46: + case 47: + ldst(dp,in,ldstnames[PPCGETIDX(in)-32],'r',0); + break; + + case 48: + case 49: + case 50: + case 51: + case 52: + case 53: + case 54: + case 55: + ldst(dp,in,ldstnames[PPCGETIDX(in)-32],'f',0); + break; + + case 58: + switch (in & 3) { + case 0: + ldst(dp,in&~3,"ld",'r',PPCF_64); + break; + case 1: + ldst(dp,in&~3,"ldu",'r',PPCF_64); + break; + case 2: + ldst(dp,in&~3,"lwa",'r',PPCF_64); + break; + default: + ill(dp,in); + break; + } + break; + + case 59: + switch (in & 0x3e) { + case 36: + fdabc(dp,in,"divs",6,0); + break; + + case 40: + fdabc(dp,in,"subs",6,0); + break; + + case 42: + fdabc(dp,in,"adds",6,0); + break; + + case 44: + fdabc(dp,in,"sqrts",2,0); + break; + + case 48: + fdabc(dp,in,"res",2,0); + break; + + case 50: + fdabc(dp,in,"muls",5,0); + break; + + case 56: + fdabc(dp,in,"msubs",7,0); + break; + + case 58: + fdabc(dp,in,"madds",7,0); + break; + + case 60: + fdabc(dp,in,"nmsubs",7,0); + break; + + case 62: + fdabc(dp,in,"nmadds",7,0); + break; + + default: + ill(dp,in); + break; + } + break; + + case 62: + switch (in & 3) { + case 0: + ldst(dp,in&~3,"std",'r',PPCF_64); + break; + case 1: + ldst(dp,in&~3,"stdu",'r',PPCF_64); + break; + default: + ill(dp,in); + break; + } + break; + + case 63: + if (in & 32) { + switch (in & 0x1e) { + case 4: + fdabc(dp,in,"div",6,0); + break; + + case 8: + fdabc(dp,in,"sub",6,0); + break; + + case 10: + fdabc(dp,in,"add",6,0); + break; + + case 12: + fdabc(dp,in,"sqrt",2,0); + break; + + case 14: + fdabc(dp,in,"sel",7,0); + break; + + case 18: + fdabc(dp,in,"mul",5,0); + break; + + case 20: + fdabc(dp,in,"rsqrte",2,0); + break; + + case 24: + fdabc(dp,in,"msub",7,0); + break; + + case 26: + fdabc(dp,in,"madd",7,0); + break; + + case 28: + fdabc(dp,in,"nmsub",7,0); + break; + + case 30: + fdabc(dp,in,"nmadd",7,0); + break; + + default: + ill(dp,in); + break; + } + } + + else { + switch (PPCGETIDX2(in)) { + case 0: + fcmp(dp,in,'u'); + break; + + case 12: + fdabc(dp,in,"rsp",10,0); + break; + + case 14: + fdabc(dp,in,"ctiw",10,0); + break; + + case 15: + fdabc(dp,in,"ctiwz",10,0); + break; + + case 32: + fcmp(dp,in,'o'); + break; + + case 38: + mtfsb(dp,in,1); + break; + + case 40: + fdabc(dp,in,"neg",10,0); + break; + + case 64: + mcrf(dp,in,'s'); /* mcrfs */ + break; + + case 70: + mtfsb(dp,in,0); + break; + + case 72: + fdabc(dp,in,"mr",10,0); + break; + + case 134: + if (!(in & 0x006f0800)) { + sprintf(dp->opcode,"mtfsfi%s",rcsel[in&1]); + sprintf(dp->operands,"cr%d,%d",(int)PPCGETCRD(in), + (int)(in & 0xf000)>>12); + } + else + ill(dp,in); + break; + + case 136: + fdabc(dp,in,"nabs",10,0); + break; + + case 264: + fdabc(dp,in,"abs",10,0); + break; + + case 583: + if (in & (PPCAMASK|PPCBMASK)) + ill(dp,in); + else + dab(dp,in,"mffs",4,0,0,-1,0); + break; + + case 711: + if (!(in & 0x02010000)) { + sprintf(dp->opcode,"mtfsf%s",rcsel[in&1]); + sprintf(dp->operands,"0x%x,%d", + (unsigned)(in & 0x01fe)>>17,(int)PPCGETB(in)); + } + else + ill(dp,in); + break; + + case 814: + fdabc(dp,in,"fctid",10,PPCF_64); + break; + + case 815: + fdabc(dp,in,"fctidz",10,PPCF_64); + break; + + case 846: + fdabc(dp,in,"fcfid",10,PPCF_64); + break; + + default: + ill(dp,in); + break; + } + } + break; + + default: + ill(dp,in); + break; + } + return (dp->instr + 1); + } +} + +// --------------------------------------------------------------------------- + +// simplified interface + +const char *DisassembleGekko(unsigned int opcode, unsigned int curInstAddr) +{ + char opcodeStr[64], operandStr[64]; + PPCDisasm::DisasmPara_PPC dp; + static char buf[128]; + static unsigned int opc, adr; + + opc = opcode; + adr = curInstAddr; + + dp.opcode = opcodeStr; + dp.operands = operandStr; + dp.instr = (PPCDisasm::ppc_word *)&opc; + dp.iaddr = (PPCDisasm::ppc_word *)&adr; + + PPCDisasm::PPC_Disassemble(&dp); + + //sprintf(buf, "%-10s %s", opcodeStr, operandStr); + sprintf(buf, "%s\t%s", opcodeStr, operandStr); + return buf; +} + + +static const char *gprnames[] = +{ + "r00", "r01", "r02", "r03", "r04", "r05", "r06", "r07", + "r08", "r09", "r10", "r11", "r12", "r13", "r14", "r15", + "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", + "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31" +}; + +const char *GetGRPName(unsigned int index) +{ + if (index < 32) + return gprnames[index]; + return 0; +} diff --git a/Externals/Bochs_disasm/stdafx.cpp b/Externals/Bochs_disasm/stdafx.cpp index 4b64ea625d..ce48aa1c24 100644 --- a/Externals/Bochs_disasm/stdafx.cpp +++ b/Externals/Bochs_disasm/stdafx.cpp @@ -1,8 +1,8 @@ -// stdafx.cpp : source file that includes just the standard includes -// Bochs_disasm.pch will be the pre-compiled header -// stdafx.obj will contain the pre-compiled type information - -#include "stdafx.h" - -// TODO: reference any additional headers you need in STDAFX.H -// and not in this file +// stdafx.cpp : source file that includes just the standard includes +// Bochs_disasm.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" + +// TODO: reference any additional headers you need in STDAFX.H +// and not in this file diff --git a/Externals/wxWidgets/include/wx/arrimpl.cpp b/Externals/wxWidgets/include/wx/arrimpl.cpp index 37b26314ad..33e25091b9 100644 --- a/Externals/wxWidgets/include/wx/arrimpl.cpp +++ b/Externals/wxWidgets/include/wx/arrimpl.cpp @@ -1,120 +1,120 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: wx/arrimpl.cpp -// Purpose: helper file for implementation of dynamic lists -// Author: Vadim Zeitlin -// Modified by: -// Created: 16.10.97 -// RCS-ID: $Id: arrimpl.cpp 34241 2005-05-22 12:10:55Z JS $ -// Copyright: (c) 1997 Vadim Zeitlin -// Licence: wxWindows license -/////////////////////////////////////////////////////////////////////////////// - -/***************************************************************************** - * Purpose: implements methods of "template" class declared in * - * DECLARE_OBJARRAY macro and which couldn't be implemented inline * - * (because they need the full definition of type T in scope) * - * * - * Usage: 1) #include dynarray.h * - * 2) WX_DECLARE_OBJARRAY * - * 3) #include arrimpl.cpp * - * 4) WX_DEFINE_OBJARRAY * - *****************************************************************************/ - -// needed to resolve the conflict between global T and macro parameter T - -#define _WX_ERROR_REMOVE2(x) wxT("bad index in ") wxT(#x) wxT("::RemoveAt()") - -// macro implements remaining (not inline) methods of template list -// (it's private to this file) -#undef _DEFINE_OBJARRAY -#define _DEFINE_OBJARRAY(T, name) \ -name::~name() \ -{ \ - Empty(); \ -} \ - \ -void name::DoCopy(const name& src) \ -{ \ - for ( size_t ui = 0; ui < src.size(); ui++ ) \ - Add(src[ui]); \ -} \ - \ -name& name::operator=(const name& src) \ -{ \ - Empty(); \ - DoCopy(src); \ - \ - return *this; \ -} \ - \ -name::name(const name& src) : wxArrayPtrVoid() \ -{ \ - DoCopy(src); \ -} \ - \ -void name::DoEmpty() \ -{ \ - for ( size_t ui = 0; ui < size(); ui++ ) \ - delete (T*)base_array::operator[](ui); \ -} \ - \ -void name::RemoveAt(size_t uiIndex, size_t nRemove) \ -{ \ - wxCHECK_RET( uiIndex < size(), _WX_ERROR_REMOVE2(name) ); \ - \ - for (size_t i = 0; i < nRemove; i++ ) \ - delete (T*)base_array::operator[](uiIndex + i); \ - \ - base_array::erase(begin() + uiIndex, begin() + uiIndex + nRemove); \ -} \ - \ -void name::Add(const T& item, size_t nInsert) \ -{ \ - if (nInsert == 0) \ - return; \ - T* pItem = new T(item); \ - size_t nOldSize = size(); \ - if ( pItem != NULL ) \ - base_array::insert(end(), nInsert, pItem); \ - for (size_t i = 1; i < nInsert; i++) \ - base_array::operator[](nOldSize + i) = new T(item); \ -} \ - \ -void name::Insert(const T& item, size_t uiIndex, size_t nInsert) \ -{ \ - if (nInsert == 0) \ - return; \ - T* pItem = new T(item); \ - if ( pItem != NULL ) \ - base_array::insert(begin() + uiIndex, nInsert, pItem); \ - for (size_t i = 1; i < nInsert; i++) \ - base_array::operator[](uiIndex + i) = new T(item); \ -} \ - \ -int name::Index(const T& Item, bool bFromEnd) const \ -{ \ - if ( bFromEnd ) { \ - if ( size() > 0 ) { \ - size_t ui = size() - 1; \ - do { \ - if ( (T*)base_array::operator[](ui) == &Item ) \ - return wx_static_cast(int, ui); \ - ui--; \ - } \ - while ( ui != 0 ); \ - } \ - } \ - else { \ - for( size_t ui = 0; ui < size(); ui++ ) { \ - if( (T*)base_array::operator[](ui) == &Item ) \ - return wx_static_cast(int, ui); \ - } \ - } \ - \ - return wxNOT_FOUND; \ -} - -// redefine the macro so that now it will generate the class implementation -// old value would provoke a compile-time error if this file is not included -#undef WX_DEFINE_OBJARRAY -#define WX_DEFINE_OBJARRAY(name) _DEFINE_OBJARRAY(_wxObjArray##name, name) +/////////////////////////////////////////////////////////////////////////////// +// Name: wx/arrimpl.cpp +// Purpose: helper file for implementation of dynamic lists +// Author: Vadim Zeitlin +// Modified by: +// Created: 16.10.97 +// RCS-ID: $Id: arrimpl.cpp 34241 2005-05-22 12:10:55Z JS $ +// Copyright: (c) 1997 Vadim Zeitlin +// Licence: wxWindows license +/////////////////////////////////////////////////////////////////////////////// + +/***************************************************************************** + * Purpose: implements methods of "template" class declared in * + * DECLARE_OBJARRAY macro and which couldn't be implemented inline * + * (because they need the full definition of type T in scope) * + * * + * Usage: 1) #include dynarray.h * + * 2) WX_DECLARE_OBJARRAY * + * 3) #include arrimpl.cpp * + * 4) WX_DEFINE_OBJARRAY * + *****************************************************************************/ + +// needed to resolve the conflict between global T and macro parameter T + +#define _WX_ERROR_REMOVE2(x) wxT("bad index in ") wxT(#x) wxT("::RemoveAt()") + +// macro implements remaining (not inline) methods of template list +// (it's private to this file) +#undef _DEFINE_OBJARRAY +#define _DEFINE_OBJARRAY(T, name) \ +name::~name() \ +{ \ + Empty(); \ +} \ + \ +void name::DoCopy(const name& src) \ +{ \ + for ( size_t ui = 0; ui < src.size(); ui++ ) \ + Add(src[ui]); \ +} \ + \ +name& name::operator=(const name& src) \ +{ \ + Empty(); \ + DoCopy(src); \ + \ + return *this; \ +} \ + \ +name::name(const name& src) : wxArrayPtrVoid() \ +{ \ + DoCopy(src); \ +} \ + \ +void name::DoEmpty() \ +{ \ + for ( size_t ui = 0; ui < size(); ui++ ) \ + delete (T*)base_array::operator[](ui); \ +} \ + \ +void name::RemoveAt(size_t uiIndex, size_t nRemove) \ +{ \ + wxCHECK_RET( uiIndex < size(), _WX_ERROR_REMOVE2(name) ); \ + \ + for (size_t i = 0; i < nRemove; i++ ) \ + delete (T*)base_array::operator[](uiIndex + i); \ + \ + base_array::erase(begin() + uiIndex, begin() + uiIndex + nRemove); \ +} \ + \ +void name::Add(const T& item, size_t nInsert) \ +{ \ + if (nInsert == 0) \ + return; \ + T* pItem = new T(item); \ + size_t nOldSize = size(); \ + if ( pItem != NULL ) \ + base_array::insert(end(), nInsert, pItem); \ + for (size_t i = 1; i < nInsert; i++) \ + base_array::operator[](nOldSize + i) = new T(item); \ +} \ + \ +void name::Insert(const T& item, size_t uiIndex, size_t nInsert) \ +{ \ + if (nInsert == 0) \ + return; \ + T* pItem = new T(item); \ + if ( pItem != NULL ) \ + base_array::insert(begin() + uiIndex, nInsert, pItem); \ + for (size_t i = 1; i < nInsert; i++) \ + base_array::operator[](uiIndex + i) = new T(item); \ +} \ + \ +int name::Index(const T& Item, bool bFromEnd) const \ +{ \ + if ( bFromEnd ) { \ + if ( size() > 0 ) { \ + size_t ui = size() - 1; \ + do { \ + if ( (T*)base_array::operator[](ui) == &Item ) \ + return wx_static_cast(int, ui); \ + ui--; \ + } \ + while ( ui != 0 ); \ + } \ + } \ + else { \ + for( size_t ui = 0; ui < size(); ui++ ) { \ + if( (T*)base_array::operator[](ui) == &Item ) \ + return wx_static_cast(int, ui); \ + } \ + } \ + \ + return wxNOT_FOUND; \ +} + +// redefine the macro so that now it will generate the class implementation +// old value would provoke a compile-time error if this file is not included +#undef WX_DEFINE_OBJARRAY +#define WX_DEFINE_OBJARRAY(name) _DEFINE_OBJARRAY(_wxObjArray##name, name) diff --git a/Externals/wxWidgets/include/wx/listimpl.cpp b/Externals/wxWidgets/include/wx/listimpl.cpp index d05fda13ed..d43cfe99ad 100644 --- a/Externals/wxWidgets/include/wx/listimpl.cpp +++ b/Externals/wxWidgets/include/wx/listimpl.cpp @@ -1,39 +1,39 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: listimpl.cpp -// Purpose: second-part of macro based implementation of template lists -// Author: Vadim Zeitlin -// Modified by: -// Created: 16/11/98 -// RCS-ID: $Id: listimpl.cpp 38893 2006-04-24 17:59:10Z VZ $ -// Copyright: (c) 1998 Vadim Zeitlin -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -#if wxUSE_STL - -#undef WX_DEFINE_LIST -#define WX_DEFINE_LIST(name) \ - void _WX_LIST_HELPER_##name::DeleteFunction( _WX_LIST_ITEM_TYPE_##name X )\ - { \ - delete X; \ - } \ - name::BaseListType name::EmptyList; - -#else // !wxUSE_STL - - #define _DEFINE_LIST(T, name) \ - void wx##name##Node::DeleteData() \ - { \ - delete (T *)GetData(); \ - } - - // redefine the macro so that now it will generate the class implementation - // old value would provoke a compile-time error if this file is not included - #undef WX_DEFINE_LIST - #define WX_DEFINE_LIST(name) _DEFINE_LIST(_WX_LIST_ITEM_TYPE_##name, name) - - // don't pollute preprocessor's name space - //#undef _DEFINE_LIST - -#endif // wxUSE_STL/!wxUSE_STL - +///////////////////////////////////////////////////////////////////////////// +// Name: listimpl.cpp +// Purpose: second-part of macro based implementation of template lists +// Author: Vadim Zeitlin +// Modified by: +// Created: 16/11/98 +// RCS-ID: $Id: listimpl.cpp 38893 2006-04-24 17:59:10Z VZ $ +// Copyright: (c) 1998 Vadim Zeitlin +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#if wxUSE_STL + +#undef WX_DEFINE_LIST +#define WX_DEFINE_LIST(name) \ + void _WX_LIST_HELPER_##name::DeleteFunction( _WX_LIST_ITEM_TYPE_##name X )\ + { \ + delete X; \ + } \ + name::BaseListType name::EmptyList; + +#else // !wxUSE_STL + + #define _DEFINE_LIST(T, name) \ + void wx##name##Node::DeleteData() \ + { \ + delete (T *)GetData(); \ + } + + // redefine the macro so that now it will generate the class implementation + // old value would provoke a compile-time error if this file is not included + #undef WX_DEFINE_LIST + #define WX_DEFINE_LIST(name) _DEFINE_LIST(_WX_LIST_ITEM_TYPE_##name, name) + + // don't pollute preprocessor's name space + //#undef _DEFINE_LIST + +#endif // wxUSE_STL/!wxUSE_STL + diff --git a/Externals/wxWidgets/include/wx/thrimpl.cpp b/Externals/wxWidgets/include/wx/thrimpl.cpp index 5034b1ea73..d8226ecddc 100644 --- a/Externals/wxWidgets/include/wx/thrimpl.cpp +++ b/Externals/wxWidgets/include/wx/thrimpl.cpp @@ -1,330 +1,330 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: include/wx/thrimpl.cpp -// Purpose: common part of wxThread Implementations -// Author: Vadim Zeitlin -// Modified by: -// Created: 04.06.02 (extracted from src/*/thread.cpp files) -// RCS-ID: $Id: thrimpl.cpp 42206 2006-10-21 16:06:11Z VZ $ -// Copyright: (c) Vadim Zeitlin (2002) -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// this file is supposed to be included only by the various thread.cpp - -// ---------------------------------------------------------------------------- -// wxMutex -// ---------------------------------------------------------------------------- - -wxMutex::wxMutex(wxMutexType mutexType) -{ - m_internal = new wxMutexInternal(mutexType); - - if ( !m_internal->IsOk() ) - { - delete m_internal; - m_internal = NULL; - } -} - -wxMutex::~wxMutex() -{ - delete m_internal; -} - -bool wxMutex::IsOk() const -{ - return m_internal != NULL; -} - -wxMutexError wxMutex::Lock() -{ - wxCHECK_MSG( m_internal, wxMUTEX_INVALID, - _T("wxMutex::Lock(): not initialized") ); - - return m_internal->Lock(); -} - -wxMutexError wxMutex::TryLock() -{ - wxCHECK_MSG( m_internal, wxMUTEX_INVALID, - _T("wxMutex::TryLock(): not initialized") ); - - return m_internal->TryLock(); -} - -wxMutexError wxMutex::Unlock() -{ - wxCHECK_MSG( m_internal, wxMUTEX_INVALID, - _T("wxMutex::Unlock(): not initialized") ); - - return m_internal->Unlock(); -} - -// -------------------------------------------------------------------------- -// wxConditionInternal -// -------------------------------------------------------------------------- - -// Win32 and OS/2 don't have explicit support for the POSIX condition -// variables and their events/event semaphores have quite different semantics, -// so we reimplement the conditions from scratch using the mutexes and -// semaphores -#if defined(__WXMSW__) || defined(__OS2__) || defined(__EMX__) - -class wxConditionInternal -{ -public: - wxConditionInternal(wxMutex& mutex); - - bool IsOk() const { return m_mutex.IsOk() && m_semaphore.IsOk(); } - - wxCondError Wait(); - wxCondError WaitTimeout(unsigned long milliseconds); - - wxCondError Signal(); - wxCondError Broadcast(); - -private: - // the number of threads currently waiting for this condition - LONG m_numWaiters; - - // the critical section protecting m_numWaiters - wxCriticalSection m_csWaiters; - - wxMutex& m_mutex; - wxSemaphore m_semaphore; - - DECLARE_NO_COPY_CLASS(wxConditionInternal) -}; - -wxConditionInternal::wxConditionInternal(wxMutex& mutex) - : m_mutex(mutex) -{ - // another thread can't access it until we return from ctor, so no need to - // protect access to m_numWaiters here - m_numWaiters = 0; -} - -wxCondError wxConditionInternal::Wait() -{ - // increment the number of waiters - { - wxCriticalSectionLocker lock(m_csWaiters); - m_numWaiters++; - } - - m_mutex.Unlock(); - - // a potential race condition can occur here - // - // after a thread increments m_numWaiters, and unlocks the mutex and before - // the semaphore.Wait() is called, if another thread can cause a signal to - // be generated - // - // this race condition is handled by using a semaphore and incrementing the - // semaphore only if m_numWaiters is greater that zero since the semaphore, - // can 'remember' signals the race condition will not occur - - // wait ( if necessary ) and decrement semaphore - wxSemaError err = m_semaphore.Wait(); - m_mutex.Lock(); - - if ( err == wxSEMA_NO_ERROR ) - return wxCOND_NO_ERROR; - else if ( err == wxSEMA_TIMEOUT ) - return wxCOND_TIMEOUT; - else - return wxCOND_MISC_ERROR; -} - -wxCondError wxConditionInternal::WaitTimeout(unsigned long milliseconds) -{ - { - wxCriticalSectionLocker lock(m_csWaiters); - m_numWaiters++; - } - - m_mutex.Unlock(); - - // a race condition can occur at this point in the code - // - // please see the comments in Wait(), for details - - wxSemaError err = m_semaphore.WaitTimeout(milliseconds); - - if ( err == wxSEMA_TIMEOUT ) - { - // another potential race condition exists here it is caused when a - // 'waiting' thread times out, and returns from WaitForSingleObject, - // but has not yet decremented m_numWaiters - // - // at this point if another thread calls signal() then the semaphore - // will be incremented, but the waiting thread will miss it. - // - // to handle this particular case, the waiting thread calls - // WaitForSingleObject again with a timeout of 0, after locking - // m_csWaiters. This call does not block because of the zero - // timeout, but will allow the waiting thread to catch the missed - // signals. - wxCriticalSectionLocker lock(m_csWaiters); - - wxSemaError err2 = m_semaphore.WaitTimeout(0); - - if ( err2 != wxSEMA_NO_ERROR ) - { - m_numWaiters--; - } - } - - m_mutex.Lock(); - - return err == wxSEMA_NO_ERROR ? wxCOND_NO_ERROR - : err == wxSEMA_TIMEOUT ? wxCOND_TIMEOUT - : wxCOND_MISC_ERROR; -} - -wxCondError wxConditionInternal::Signal() -{ - wxCriticalSectionLocker lock(m_csWaiters); - - if ( m_numWaiters > 0 ) - { - // increment the semaphore by 1 - if ( m_semaphore.Post() != wxSEMA_NO_ERROR ) - return wxCOND_MISC_ERROR; - - m_numWaiters--; - } - - return wxCOND_NO_ERROR; -} - -wxCondError wxConditionInternal::Broadcast() -{ - wxCriticalSectionLocker lock(m_csWaiters); - - while ( m_numWaiters > 0 ) - { - if ( m_semaphore.Post() != wxSEMA_NO_ERROR ) - return wxCOND_MISC_ERROR; - - m_numWaiters--; - } - - return wxCOND_NO_ERROR; -} - -#endif // MSW or OS2 - -// ---------------------------------------------------------------------------- -// wxCondition -// ---------------------------------------------------------------------------- - -wxCondition::wxCondition(wxMutex& mutex) -{ - m_internal = new wxConditionInternal(mutex); - - if ( !m_internal->IsOk() ) - { - delete m_internal; - m_internal = NULL; - } -} - -wxCondition::~wxCondition() -{ - delete m_internal; -} - -bool wxCondition::IsOk() const -{ - return m_internal != NULL; -} - -wxCondError wxCondition::Wait() -{ - wxCHECK_MSG( m_internal, wxCOND_INVALID, - _T("wxCondition::Wait(): not initialized") ); - - return m_internal->Wait(); -} - -wxCondError wxCondition::WaitTimeout(unsigned long milliseconds) -{ - wxCHECK_MSG( m_internal, wxCOND_INVALID, - _T("wxCondition::Wait(): not initialized") ); - - return m_internal->WaitTimeout(milliseconds); -} - -wxCondError wxCondition::Signal() -{ - wxCHECK_MSG( m_internal, wxCOND_INVALID, - _T("wxCondition::Signal(): not initialized") ); - - return m_internal->Signal(); -} - -wxCondError wxCondition::Broadcast() -{ - wxCHECK_MSG( m_internal, wxCOND_INVALID, - _T("wxCondition::Broadcast(): not initialized") ); - - return m_internal->Broadcast(); -} - -// -------------------------------------------------------------------------- -// wxSemaphore -// -------------------------------------------------------------------------- - -wxSemaphore::wxSemaphore(int initialcount, int maxcount) -{ - m_internal = new wxSemaphoreInternal( initialcount, maxcount ); - if ( !m_internal->IsOk() ) - { - delete m_internal; - m_internal = NULL; - } -} - -wxSemaphore::~wxSemaphore() -{ - delete m_internal; -} - -bool wxSemaphore::IsOk() const -{ - return m_internal != NULL; -} - -wxSemaError wxSemaphore::Wait() -{ - wxCHECK_MSG( m_internal, wxSEMA_INVALID, - _T("wxSemaphore::Wait(): not initialized") ); - - return m_internal->Wait(); -} - -wxSemaError wxSemaphore::TryWait() -{ - wxCHECK_MSG( m_internal, wxSEMA_INVALID, - _T("wxSemaphore::TryWait(): not initialized") ); - - return m_internal->TryWait(); -} - -wxSemaError wxSemaphore::WaitTimeout(unsigned long milliseconds) -{ - wxCHECK_MSG( m_internal, wxSEMA_INVALID, - _T("wxSemaphore::WaitTimeout(): not initialized") ); - - return m_internal->WaitTimeout(milliseconds); -} - -wxSemaError wxSemaphore::Post() -{ - wxCHECK_MSG( m_internal, wxSEMA_INVALID, - _T("wxSemaphore::Post(): not initialized") ); - - return m_internal->Post(); -} - +///////////////////////////////////////////////////////////////////////////// +// Name: include/wx/thrimpl.cpp +// Purpose: common part of wxThread Implementations +// Author: Vadim Zeitlin +// Modified by: +// Created: 04.06.02 (extracted from src/*/thread.cpp files) +// RCS-ID: $Id: thrimpl.cpp 42206 2006-10-21 16:06:11Z VZ $ +// Copyright: (c) Vadim Zeitlin (2002) +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// this file is supposed to be included only by the various thread.cpp + +// ---------------------------------------------------------------------------- +// wxMutex +// ---------------------------------------------------------------------------- + +wxMutex::wxMutex(wxMutexType mutexType) +{ + m_internal = new wxMutexInternal(mutexType); + + if ( !m_internal->IsOk() ) + { + delete m_internal; + m_internal = NULL; + } +} + +wxMutex::~wxMutex() +{ + delete m_internal; +} + +bool wxMutex::IsOk() const +{ + return m_internal != NULL; +} + +wxMutexError wxMutex::Lock() +{ + wxCHECK_MSG( m_internal, wxMUTEX_INVALID, + _T("wxMutex::Lock(): not initialized") ); + + return m_internal->Lock(); +} + +wxMutexError wxMutex::TryLock() +{ + wxCHECK_MSG( m_internal, wxMUTEX_INVALID, + _T("wxMutex::TryLock(): not initialized") ); + + return m_internal->TryLock(); +} + +wxMutexError wxMutex::Unlock() +{ + wxCHECK_MSG( m_internal, wxMUTEX_INVALID, + _T("wxMutex::Unlock(): not initialized") ); + + return m_internal->Unlock(); +} + +// -------------------------------------------------------------------------- +// wxConditionInternal +// -------------------------------------------------------------------------- + +// Win32 and OS/2 don't have explicit support for the POSIX condition +// variables and their events/event semaphores have quite different semantics, +// so we reimplement the conditions from scratch using the mutexes and +// semaphores +#if defined(__WXMSW__) || defined(__OS2__) || defined(__EMX__) + +class wxConditionInternal +{ +public: + wxConditionInternal(wxMutex& mutex); + + bool IsOk() const { return m_mutex.IsOk() && m_semaphore.IsOk(); } + + wxCondError Wait(); + wxCondError WaitTimeout(unsigned long milliseconds); + + wxCondError Signal(); + wxCondError Broadcast(); + +private: + // the number of threads currently waiting for this condition + LONG m_numWaiters; + + // the critical section protecting m_numWaiters + wxCriticalSection m_csWaiters; + + wxMutex& m_mutex; + wxSemaphore m_semaphore; + + DECLARE_NO_COPY_CLASS(wxConditionInternal) +}; + +wxConditionInternal::wxConditionInternal(wxMutex& mutex) + : m_mutex(mutex) +{ + // another thread can't access it until we return from ctor, so no need to + // protect access to m_numWaiters here + m_numWaiters = 0; +} + +wxCondError wxConditionInternal::Wait() +{ + // increment the number of waiters + { + wxCriticalSectionLocker lock(m_csWaiters); + m_numWaiters++; + } + + m_mutex.Unlock(); + + // a potential race condition can occur here + // + // after a thread increments m_numWaiters, and unlocks the mutex and before + // the semaphore.Wait() is called, if another thread can cause a signal to + // be generated + // + // this race condition is handled by using a semaphore and incrementing the + // semaphore only if m_numWaiters is greater that zero since the semaphore, + // can 'remember' signals the race condition will not occur + + // wait ( if necessary ) and decrement semaphore + wxSemaError err = m_semaphore.Wait(); + m_mutex.Lock(); + + if ( err == wxSEMA_NO_ERROR ) + return wxCOND_NO_ERROR; + else if ( err == wxSEMA_TIMEOUT ) + return wxCOND_TIMEOUT; + else + return wxCOND_MISC_ERROR; +} + +wxCondError wxConditionInternal::WaitTimeout(unsigned long milliseconds) +{ + { + wxCriticalSectionLocker lock(m_csWaiters); + m_numWaiters++; + } + + m_mutex.Unlock(); + + // a race condition can occur at this point in the code + // + // please see the comments in Wait(), for details + + wxSemaError err = m_semaphore.WaitTimeout(milliseconds); + + if ( err == wxSEMA_TIMEOUT ) + { + // another potential race condition exists here it is caused when a + // 'waiting' thread times out, and returns from WaitForSingleObject, + // but has not yet decremented m_numWaiters + // + // at this point if another thread calls signal() then the semaphore + // will be incremented, but the waiting thread will miss it. + // + // to handle this particular case, the waiting thread calls + // WaitForSingleObject again with a timeout of 0, after locking + // m_csWaiters. This call does not block because of the zero + // timeout, but will allow the waiting thread to catch the missed + // signals. + wxCriticalSectionLocker lock(m_csWaiters); + + wxSemaError err2 = m_semaphore.WaitTimeout(0); + + if ( err2 != wxSEMA_NO_ERROR ) + { + m_numWaiters--; + } + } + + m_mutex.Lock(); + + return err == wxSEMA_NO_ERROR ? wxCOND_NO_ERROR + : err == wxSEMA_TIMEOUT ? wxCOND_TIMEOUT + : wxCOND_MISC_ERROR; +} + +wxCondError wxConditionInternal::Signal() +{ + wxCriticalSectionLocker lock(m_csWaiters); + + if ( m_numWaiters > 0 ) + { + // increment the semaphore by 1 + if ( m_semaphore.Post() != wxSEMA_NO_ERROR ) + return wxCOND_MISC_ERROR; + + m_numWaiters--; + } + + return wxCOND_NO_ERROR; +} + +wxCondError wxConditionInternal::Broadcast() +{ + wxCriticalSectionLocker lock(m_csWaiters); + + while ( m_numWaiters > 0 ) + { + if ( m_semaphore.Post() != wxSEMA_NO_ERROR ) + return wxCOND_MISC_ERROR; + + m_numWaiters--; + } + + return wxCOND_NO_ERROR; +} + +#endif // MSW or OS2 + +// ---------------------------------------------------------------------------- +// wxCondition +// ---------------------------------------------------------------------------- + +wxCondition::wxCondition(wxMutex& mutex) +{ + m_internal = new wxConditionInternal(mutex); + + if ( !m_internal->IsOk() ) + { + delete m_internal; + m_internal = NULL; + } +} + +wxCondition::~wxCondition() +{ + delete m_internal; +} + +bool wxCondition::IsOk() const +{ + return m_internal != NULL; +} + +wxCondError wxCondition::Wait() +{ + wxCHECK_MSG( m_internal, wxCOND_INVALID, + _T("wxCondition::Wait(): not initialized") ); + + return m_internal->Wait(); +} + +wxCondError wxCondition::WaitTimeout(unsigned long milliseconds) +{ + wxCHECK_MSG( m_internal, wxCOND_INVALID, + _T("wxCondition::Wait(): not initialized") ); + + return m_internal->WaitTimeout(milliseconds); +} + +wxCondError wxCondition::Signal() +{ + wxCHECK_MSG( m_internal, wxCOND_INVALID, + _T("wxCondition::Signal(): not initialized") ); + + return m_internal->Signal(); +} + +wxCondError wxCondition::Broadcast() +{ + wxCHECK_MSG( m_internal, wxCOND_INVALID, + _T("wxCondition::Broadcast(): not initialized") ); + + return m_internal->Broadcast(); +} + +// -------------------------------------------------------------------------- +// wxSemaphore +// -------------------------------------------------------------------------- + +wxSemaphore::wxSemaphore(int initialcount, int maxcount) +{ + m_internal = new wxSemaphoreInternal( initialcount, maxcount ); + if ( !m_internal->IsOk() ) + { + delete m_internal; + m_internal = NULL; + } +} + +wxSemaphore::~wxSemaphore() +{ + delete m_internal; +} + +bool wxSemaphore::IsOk() const +{ + return m_internal != NULL; +} + +wxSemaError wxSemaphore::Wait() +{ + wxCHECK_MSG( m_internal, wxSEMA_INVALID, + _T("wxSemaphore::Wait(): not initialized") ); + + return m_internal->Wait(); +} + +wxSemaError wxSemaphore::TryWait() +{ + wxCHECK_MSG( m_internal, wxSEMA_INVALID, + _T("wxSemaphore::TryWait(): not initialized") ); + + return m_internal->TryWait(); +} + +wxSemaError wxSemaphore::WaitTimeout(unsigned long milliseconds) +{ + wxCHECK_MSG( m_internal, wxSEMA_INVALID, + _T("wxSemaphore::WaitTimeout(): not initialized") ); + + return m_internal->WaitTimeout(milliseconds); +} + +wxSemaError wxSemaphore::Post() +{ + wxCHECK_MSG( m_internal, wxSEMA_INVALID, + _T("wxSemaphore::Post(): not initialized") ); + + return m_internal->Post(); +} + diff --git a/Externals/wxWidgets/src/common/accesscmn.cpp b/Externals/wxWidgets/src/common/accesscmn.cpp index 14135977e9..1684258225 100644 --- a/Externals/wxWidgets/src/common/accesscmn.cpp +++ b/Externals/wxWidgets/src/common/accesscmn.cpp @@ -1,26 +1,26 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: common/accesscmn.cpp -// Author: Julian Smart -// Modified by: -// Created: 2003-02-12 -// RCS-ID: $Id: accesscmn.cpp 35650 2005-09-23 12:56:45Z MR $ -// Copyright: (c) Julian Smart -// Licence: wxWindows licence -/////////////////////////////////////////////////////////////////////////////// - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_ACCESSIBILITY - -#include "wx/access.h" - -#endif - +/////////////////////////////////////////////////////////////////////////////// +// Name: common/accesscmn.cpp +// Author: Julian Smart +// Modified by: +// Created: 2003-02-12 +// RCS-ID: $Id: accesscmn.cpp 35650 2005-09-23 12:56:45Z MR $ +// Copyright: (c) Julian Smart +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_ACCESSIBILITY + +#include "wx/access.h" + +#endif + diff --git a/Externals/wxWidgets/src/common/anidecod.cpp b/Externals/wxWidgets/src/common/anidecod.cpp index f10817c583..4a905f8021 100644 --- a/Externals/wxWidgets/src/common/anidecod.cpp +++ b/Externals/wxWidgets/src/common/anidecod.cpp @@ -1,345 +1,345 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/anidecod.cpp -// Purpose: wxANIDecoder, ANI reader for wxImage and wxAnimation -// Author: Francesco Montorsi -// RCS-ID: $Id: anidecod.cpp 43898 2006-12-10 14:18:37Z VZ $ -// Copyright: (c) Francesco Montorsi -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_STREAMS && wxUSE_ICO_CUR - -#include "wx/anidecod.h" - -#ifndef WX_PRECOMP - #include "wx/palette.h" -#endif - -#include -#include - -// static -wxCURHandler wxANIDecoder::sm_handler; - -//--------------------------------------------------------------------------- -// wxANIFrameInfo -//--------------------------------------------------------------------------- - -class wxANIFrameInfo -{ -public: - wxANIFrameInfo(unsigned int delay = 0, int idx = -1) - { m_delay=delay; m_imageIndex=idx; } - - unsigned int m_delay; - int m_imageIndex; -}; - -#include "wx/arrimpl.cpp" // this is a magic incantation which must be done! -WX_DEFINE_OBJARRAY(wxImageArray) - -#include "wx/arrimpl.cpp" // this is a magic incantation which must be done! -WX_DEFINE_OBJARRAY(wxANIFrameInfoArray) - - -//--------------------------------------------------------------------------- -// wxANIDecoder -//--------------------------------------------------------------------------- - -wxANIDecoder::wxANIDecoder() -{ -} - -wxANIDecoder::~wxANIDecoder() -{ -} - -bool wxANIDecoder::ConvertToImage(unsigned int frame, wxImage *image) const -{ - unsigned int idx = m_info[frame].m_imageIndex; - *image = m_images[idx]; // copy - return image->IsOk(); -} - - -//--------------------------------------------------------------------------- -// Data accessors -//--------------------------------------------------------------------------- - -wxSize wxANIDecoder::GetFrameSize(unsigned int WXUNUSED(frame)) const -{ - // all frames are of the same size... - return m_szAnimation; -} - -wxPoint wxANIDecoder::GetFramePosition(unsigned int WXUNUSED(frame)) const -{ - // all frames are of the same size... - return wxPoint(0,0); -} - -wxAnimationDisposal wxANIDecoder::GetDisposalMethod(unsigned int WXUNUSED(frame)) const -{ - // this disposal is implicit for all frames inside an ANI file - return wxANIM_TOBACKGROUND; -} - -long wxANIDecoder::GetDelay(unsigned int frame) const -{ - return m_info[frame].m_delay; -} - -wxColour wxANIDecoder::GetTransparentColour(unsigned int frame) const -{ - unsigned int idx = m_info[frame].m_imageIndex; - - if (!m_images[idx].HasMask()) - return wxNullColour; - - return wxColour(m_images[idx].GetMaskRed(), - m_images[idx].GetMaskGreen(), - m_images[idx].GetMaskBlue()); -} - - -//--------------------------------------------------------------------------- -// ANI reading and decoding -//--------------------------------------------------------------------------- - -bool wxANIDecoder::CanRead(wxInputStream& stream) const -{ - wxInt32 FCC1, FCC2; - wxUint32 datalen ; - - wxInt32 riff32; - memcpy( &riff32, "RIFF", 4 ); - wxInt32 list32; - memcpy( &list32, "LIST", 4 ); - wxInt32 ico32; - memcpy( &ico32, "icon", 4 ); - wxInt32 anih32; - memcpy( &anih32, "anih", 4 ); - - stream.SeekI(0); - if ( !stream.Read(&FCC1, 4) ) - return false; - - if ( FCC1 != riff32 ) - return false; - - // we have a riff file: - while ( stream.IsOk() ) - { - if ( FCC1 == anih32 ) - return true; // found the ANIH chunk - this should be an ANI file - - // we always have a data size: - stream.Read(&datalen, 4); - datalen = wxINT32_SWAP_ON_BE(datalen) ; - - // data should be padded to make even number of bytes - if (datalen % 2 == 1) datalen ++ ; - - // now either data or a FCC: - if ( (FCC1 == riff32) || (FCC1 == list32) ) - { - stream.Read(&FCC2, 4); - } - else - { - stream.SeekI(stream.TellI() + datalen); - } - - // try to read next data chunk: - if ( !stream.Read(&FCC1, 4) ) - { - // reading failed -- either EOF or IO error, bail out anyhow - return false; - } - } - - return false; -} - -// the "anih" RIFF chunk -struct wxANIHeader -{ - wxInt32 cbSizeOf; // Num bytes in AniHeader (36 bytes) - wxInt32 cFrames; // Number of unique Icons in this cursor - wxInt32 cSteps; // Number of Blits before the animation cycles - wxInt32 cx; // width of the frames - wxInt32 cy; // height of the frames - wxInt32 cBitCount; // bit depth - wxInt32 cPlanes; // 1 - wxInt32 JifRate; // Default Jiffies (1/60th of a second) if rate chunk not present. - wxInt32 flags; // Animation Flag (see AF_ constants) - - // ANI files are always little endian so we need to swap bytes on big - // endian architectures -#ifdef WORDS_BIGENDIAN - void AdjustEndianness() - { - // this works because all our fields are wxInt32 and they must be - // packed without holes between them (if they're not, they wouldn't map - // to the file header!) - wxInt32 * const start = (wxInt32 *)this; - wxInt32 * const end = start + sizeof(wxANIHeader)/sizeof(wxInt32); - for ( wxInt32 *p = start; p != end; p++ ) - { - *p = wxINT32_SWAP_ALWAYS(*p); - } - } -#else - void AdjustEndianness() { } -#endif -}; - -bool wxANIDecoder::Load( wxInputStream& stream ) -{ - wxInt32 FCC1, FCC2; - wxUint32 datalen; - unsigned int globaldelay=0; - - wxInt32 riff32; - memcpy( &riff32, "RIFF", 4 ); - wxInt32 list32; - memcpy( &list32, "LIST", 4 ); - wxInt32 ico32; - memcpy( &ico32, "icon", 4 ); - wxInt32 anih32; - memcpy( &anih32, "anih", 4 ); - wxInt32 rate32; - memcpy( &rate32, "rate", 4 ); - wxInt32 seq32; - memcpy( &seq32, "seq ", 4 ); - - stream.SeekI(0); - stream.Read(&FCC1, 4); - if ( FCC1 != riff32 ) - return false; - - m_nFrames = 0; - m_szAnimation = wxDefaultSize; - - m_images.Clear(); - m_info.Clear(); - - // we have a riff file: - while ( stream.IsOk() ) - { - // we always have a data size: - stream.Read(&datalen, 4); - datalen = wxINT32_SWAP_ON_BE(datalen); - - //data should be padded to make even number of bytes - if (datalen % 2 == 1) datalen++; - - // now either data or a FCC: - if ( (FCC1 == riff32) || (FCC1 == list32) ) - { - stream.Read(&FCC2, 4); - } - else if ( FCC1 == anih32 ) - { - if ( datalen != sizeof(wxANIHeader) ) - return false; - - if (m_nFrames > 0) - return false; // already parsed an ani header? - - struct wxANIHeader header; - stream.Read(&header, sizeof(wxANIHeader)); - header.AdjustEndianness(); - - // we should have a global frame size - m_szAnimation = wxSize(header.cx, header.cy); - - // save interesting info from the header - m_nFrames = header.cSteps; // NB: not cFrames!! - if ( m_nFrames == 0 ) - return false; - - globaldelay = header.JifRate * 1000 / 60; - - m_images.Alloc(header.cFrames); - m_info.Add(wxANIFrameInfo(), m_nFrames); - } - else if ( FCC1 == rate32 ) - { - // did we already process the anih32 chunk? - if (m_nFrames == 0) - return false; // rate chunks should always be placed after anih chunk - - wxASSERT(m_info.GetCount() == m_nFrames); - for (unsigned int i=0; i +#include + +// static +wxCURHandler wxANIDecoder::sm_handler; + +//--------------------------------------------------------------------------- +// wxANIFrameInfo +//--------------------------------------------------------------------------- + +class wxANIFrameInfo +{ +public: + wxANIFrameInfo(unsigned int delay = 0, int idx = -1) + { m_delay=delay; m_imageIndex=idx; } + + unsigned int m_delay; + int m_imageIndex; +}; + +#include "wx/arrimpl.cpp" // this is a magic incantation which must be done! +WX_DEFINE_OBJARRAY(wxImageArray) + +#include "wx/arrimpl.cpp" // this is a magic incantation which must be done! +WX_DEFINE_OBJARRAY(wxANIFrameInfoArray) + + +//--------------------------------------------------------------------------- +// wxANIDecoder +//--------------------------------------------------------------------------- + +wxANIDecoder::wxANIDecoder() +{ +} + +wxANIDecoder::~wxANIDecoder() +{ +} + +bool wxANIDecoder::ConvertToImage(unsigned int frame, wxImage *image) const +{ + unsigned int idx = m_info[frame].m_imageIndex; + *image = m_images[idx]; // copy + return image->IsOk(); +} + + +//--------------------------------------------------------------------------- +// Data accessors +//--------------------------------------------------------------------------- + +wxSize wxANIDecoder::GetFrameSize(unsigned int WXUNUSED(frame)) const +{ + // all frames are of the same size... + return m_szAnimation; +} + +wxPoint wxANIDecoder::GetFramePosition(unsigned int WXUNUSED(frame)) const +{ + // all frames are of the same size... + return wxPoint(0,0); +} + +wxAnimationDisposal wxANIDecoder::GetDisposalMethod(unsigned int WXUNUSED(frame)) const +{ + // this disposal is implicit for all frames inside an ANI file + return wxANIM_TOBACKGROUND; +} + +long wxANIDecoder::GetDelay(unsigned int frame) const +{ + return m_info[frame].m_delay; +} + +wxColour wxANIDecoder::GetTransparentColour(unsigned int frame) const +{ + unsigned int idx = m_info[frame].m_imageIndex; + + if (!m_images[idx].HasMask()) + return wxNullColour; + + return wxColour(m_images[idx].GetMaskRed(), + m_images[idx].GetMaskGreen(), + m_images[idx].GetMaskBlue()); +} + + +//--------------------------------------------------------------------------- +// ANI reading and decoding +//--------------------------------------------------------------------------- + +bool wxANIDecoder::CanRead(wxInputStream& stream) const +{ + wxInt32 FCC1, FCC2; + wxUint32 datalen ; + + wxInt32 riff32; + memcpy( &riff32, "RIFF", 4 ); + wxInt32 list32; + memcpy( &list32, "LIST", 4 ); + wxInt32 ico32; + memcpy( &ico32, "icon", 4 ); + wxInt32 anih32; + memcpy( &anih32, "anih", 4 ); + + stream.SeekI(0); + if ( !stream.Read(&FCC1, 4) ) + return false; + + if ( FCC1 != riff32 ) + return false; + + // we have a riff file: + while ( stream.IsOk() ) + { + if ( FCC1 == anih32 ) + return true; // found the ANIH chunk - this should be an ANI file + + // we always have a data size: + stream.Read(&datalen, 4); + datalen = wxINT32_SWAP_ON_BE(datalen) ; + + // data should be padded to make even number of bytes + if (datalen % 2 == 1) datalen ++ ; + + // now either data or a FCC: + if ( (FCC1 == riff32) || (FCC1 == list32) ) + { + stream.Read(&FCC2, 4); + } + else + { + stream.SeekI(stream.TellI() + datalen); + } + + // try to read next data chunk: + if ( !stream.Read(&FCC1, 4) ) + { + // reading failed -- either EOF or IO error, bail out anyhow + return false; + } + } + + return false; +} + +// the "anih" RIFF chunk +struct wxANIHeader +{ + wxInt32 cbSizeOf; // Num bytes in AniHeader (36 bytes) + wxInt32 cFrames; // Number of unique Icons in this cursor + wxInt32 cSteps; // Number of Blits before the animation cycles + wxInt32 cx; // width of the frames + wxInt32 cy; // height of the frames + wxInt32 cBitCount; // bit depth + wxInt32 cPlanes; // 1 + wxInt32 JifRate; // Default Jiffies (1/60th of a second) if rate chunk not present. + wxInt32 flags; // Animation Flag (see AF_ constants) + + // ANI files are always little endian so we need to swap bytes on big + // endian architectures +#ifdef WORDS_BIGENDIAN + void AdjustEndianness() + { + // this works because all our fields are wxInt32 and they must be + // packed without holes between them (if they're not, they wouldn't map + // to the file header!) + wxInt32 * const start = (wxInt32 *)this; + wxInt32 * const end = start + sizeof(wxANIHeader)/sizeof(wxInt32); + for ( wxInt32 *p = start; p != end; p++ ) + { + *p = wxINT32_SWAP_ALWAYS(*p); + } + } +#else + void AdjustEndianness() { } +#endif +}; + +bool wxANIDecoder::Load( wxInputStream& stream ) +{ + wxInt32 FCC1, FCC2; + wxUint32 datalen; + unsigned int globaldelay=0; + + wxInt32 riff32; + memcpy( &riff32, "RIFF", 4 ); + wxInt32 list32; + memcpy( &list32, "LIST", 4 ); + wxInt32 ico32; + memcpy( &ico32, "icon", 4 ); + wxInt32 anih32; + memcpy( &anih32, "anih", 4 ); + wxInt32 rate32; + memcpy( &rate32, "rate", 4 ); + wxInt32 seq32; + memcpy( &seq32, "seq ", 4 ); + + stream.SeekI(0); + stream.Read(&FCC1, 4); + if ( FCC1 != riff32 ) + return false; + + m_nFrames = 0; + m_szAnimation = wxDefaultSize; + + m_images.Clear(); + m_info.Clear(); + + // we have a riff file: + while ( stream.IsOk() ) + { + // we always have a data size: + stream.Read(&datalen, 4); + datalen = wxINT32_SWAP_ON_BE(datalen); + + //data should be padded to make even number of bytes + if (datalen % 2 == 1) datalen++; + + // now either data or a FCC: + if ( (FCC1 == riff32) || (FCC1 == list32) ) + { + stream.Read(&FCC2, 4); + } + else if ( FCC1 == anih32 ) + { + if ( datalen != sizeof(wxANIHeader) ) + return false; + + if (m_nFrames > 0) + return false; // already parsed an ani header? + + struct wxANIHeader header; + stream.Read(&header, sizeof(wxANIHeader)); + header.AdjustEndianness(); + + // we should have a global frame size + m_szAnimation = wxSize(header.cx, header.cy); + + // save interesting info from the header + m_nFrames = header.cSteps; // NB: not cFrames!! + if ( m_nFrames == 0 ) + return false; + + globaldelay = header.JifRate * 1000 / 60; + + m_images.Alloc(header.cFrames); + m_info.Add(wxANIFrameInfo(), m_nFrames); + } + else if ( FCC1 == rate32 ) + { + // did we already process the anih32 chunk? + if (m_nFrames == 0) + return false; // rate chunks should always be placed after anih chunk + + wxASSERT(m_info.GetCount() == m_nFrames); + for (unsigned int i=0; i -// License: wxWindows license -/////////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// for compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#ifndef WX_PRECOMP - #ifdef __WXMSW__ - #include "wx/msw/wrapwin.h" // includes windows.h for MessageBox() - #endif - #include "wx/list.h" - #include "wx/app.h" - #include "wx/intl.h" - #include "wx/log.h" - #include "wx/utils.h" -#endif //WX_PRECOMP - -#include "wx/apptrait.h" -#include "wx/cmdline.h" -#include "wx/confbase.h" -#include "wx/filename.h" -#include "wx/msgout.h" -#include "wx/tokenzr.h" - -#if !defined(__WXMSW__) || defined(__WXMICROWIN__) - #include // for SIGTRAP used by wxTrap() -#endif //Win/Unix - -#if wxUSE_FONTMAP - #include "wx/fontmap.h" -#endif // wxUSE_FONTMAP - -#if defined(__DARWIN__) && defined(_MSL_USING_MW_C_HEADERS) && _MSL_USING_MW_C_HEADERS - // For MacTypes.h for Debugger function - #include -#endif - -#if defined(__WXMAC__) - #ifdef __DARWIN__ - #include - #else - #include "wx/mac/private.h" // includes mac headers - #endif -#endif // __WXMAC__ - -#ifdef __WXDEBUG__ - #if wxUSE_STACKWALKER - #include "wx/stackwalk.h" - #ifdef __WXMSW__ - #include "wx/msw/debughlp.h" - #endif - #endif // wxUSE_STACKWALKER - - #include "wx/recguard.h" -#endif // __WXDEBUG__ - -// wxABI_VERSION can be defined when compiling applications but it should be -// left undefined when compiling the library itself, it is then set to its -// default value in version.h -#if wxABI_VERSION != wxMAJOR_VERSION * 10000 + wxMINOR_VERSION * 100 + 99 -#error "wxABI_VERSION should not be defined when compiling the library" -#endif - -// ---------------------------------------------------------------------------- -// private functions prototypes -// ---------------------------------------------------------------------------- - -#ifdef __WXDEBUG__ - // really just show the assert dialog - static bool DoShowAssertDialog(const wxString& msg); - - // prepare for showing the assert dialog, use the given traits or - // DoShowAssertDialog() as last fallback to really show it - static - void ShowAssertDialog(const wxChar *szFile, - int nLine, - const wxChar *szFunc, - const wxChar *szCond, - const wxChar *szMsg, - wxAppTraits *traits = NULL); - - // turn on the trace masks specified in the env variable WXTRACE - static void LINKAGEMODE SetTraceMasks(); -#endif // __WXDEBUG__ - -// ---------------------------------------------------------------------------- -// global vars -// ---------------------------------------------------------------------------- - -wxAppConsole *wxAppConsole::ms_appInstance = NULL; - -wxAppInitializerFunction wxAppConsole::ms_appInitFn = NULL; - -// ============================================================================ -// wxAppConsole implementation -// ============================================================================ - -// ---------------------------------------------------------------------------- -// ctor/dtor -// ---------------------------------------------------------------------------- - -wxAppConsole::wxAppConsole() -{ - m_traits = NULL; - - ms_appInstance = this; - -#ifdef __WXDEBUG__ - SetTraceMasks(); -#if wxUSE_UNICODE - // In unicode mode the SetTraceMasks call can cause an apptraits to be - // created, but since we are still in the constructor the wrong kind will - // be created for GUI apps. Destroy it so it can be created again later. - delete m_traits; - m_traits = NULL; -#endif -#endif -} - -wxAppConsole::~wxAppConsole() -{ - delete m_traits; -} - -// ---------------------------------------------------------------------------- -// initilization/cleanup -// ---------------------------------------------------------------------------- - -bool wxAppConsole::Initialize(int& argcOrig, wxChar **argvOrig) -{ - // remember the command line arguments - argc = argcOrig; - argv = argvOrig; - -#ifndef __WXPALMOS__ - if ( m_appName.empty() && argv ) - { - // the application name is, by default, the name of its executable file - wxFileName::SplitPath(argv[0], NULL, &m_appName, NULL); - } -#endif - - return true; -} - -void wxAppConsole::CleanUp() -{ -} - -// ---------------------------------------------------------------------------- -// OnXXX() callbacks -// ---------------------------------------------------------------------------- - -bool wxAppConsole::OnInit() -{ -#if wxUSE_CMDLINE_PARSER - wxCmdLineParser parser(argc, argv); - - OnInitCmdLine(parser); - - bool cont; - switch ( parser.Parse(false /* don't show usage */) ) - { - case -1: - cont = OnCmdLineHelp(parser); - break; - - case 0: - cont = OnCmdLineParsed(parser); - break; - - default: - cont = OnCmdLineError(parser); - break; - } - - if ( !cont ) - return false; -#endif // wxUSE_CMDLINE_PARSER - - return true; -} - -int wxAppConsole::OnExit() -{ -#if wxUSE_CONFIG - // delete the config object if any (don't use Get() here, but Set() - // because Get() could create a new config object) - delete wxConfigBase::Set((wxConfigBase *) NULL); -#endif // wxUSE_CONFIG - - return 0; -} - -void wxAppConsole::Exit() -{ - exit(-1); -} - -// ---------------------------------------------------------------------------- -// traits stuff -// ---------------------------------------------------------------------------- - -wxAppTraits *wxAppConsole::CreateTraits() -{ - return new wxConsoleAppTraits; -} - -wxAppTraits *wxAppConsole::GetTraits() -{ - // FIXME-MT: protect this with a CS? - if ( !m_traits ) - { - m_traits = CreateTraits(); - - wxASSERT_MSG( m_traits, _T("wxApp::CreateTraits() failed?") ); - } - - return m_traits; -} - -// we must implement CreateXXX() in wxApp itself for backwards compatibility -#if WXWIN_COMPATIBILITY_2_4 - -#if wxUSE_LOG - -wxLog *wxAppConsole::CreateLogTarget() -{ - wxAppTraits *traits = GetTraits(); - return traits ? traits->CreateLogTarget() : NULL; -} - -#endif // wxUSE_LOG - -wxMessageOutput *wxAppConsole::CreateMessageOutput() -{ - wxAppTraits *traits = GetTraits(); - return traits ? traits->CreateMessageOutput() : NULL; -} - -#endif // WXWIN_COMPATIBILITY_2_4 - -// ---------------------------------------------------------------------------- -// event processing -// ---------------------------------------------------------------------------- - -void wxAppConsole::ProcessPendingEvents() -{ -#if wxUSE_THREADS - if ( !wxPendingEventsLocker ) - return; -#endif - - // ensure that we're the only thread to modify the pending events list - wxENTER_CRIT_SECT( *wxPendingEventsLocker ); - - if ( !wxPendingEvents ) - { - wxLEAVE_CRIT_SECT( *wxPendingEventsLocker ); - return; - } - - // iterate until the list becomes empty - wxList::compatibility_iterator node = wxPendingEvents->GetFirst(); - while (node) - { - wxEvtHandler *handler = (wxEvtHandler *)node->GetData(); - wxPendingEvents->Erase(node); - - // In ProcessPendingEvents(), new handlers might be add - // and we can safely leave the critical section here. - wxLEAVE_CRIT_SECT( *wxPendingEventsLocker ); - - handler->ProcessPendingEvents(); - - wxENTER_CRIT_SECT( *wxPendingEventsLocker ); - - node = wxPendingEvents->GetFirst(); - } - - wxLEAVE_CRIT_SECT( *wxPendingEventsLocker ); -} - -int wxAppConsole::FilterEvent(wxEvent& WXUNUSED(event)) -{ - // process the events normally by default - return -1; -} - -// ---------------------------------------------------------------------------- -// exception handling -// ---------------------------------------------------------------------------- - -#if wxUSE_EXCEPTIONS - -void -wxAppConsole::HandleEvent(wxEvtHandler *handler, - wxEventFunction func, - wxEvent& event) const -{ - // by default, simply call the handler - (handler->*func)(event); -} - -#endif // wxUSE_EXCEPTIONS - -// ---------------------------------------------------------------------------- -// cmd line parsing -// ---------------------------------------------------------------------------- - -#if wxUSE_CMDLINE_PARSER - -#define OPTION_VERBOSE _T("verbose") - -void wxAppConsole::OnInitCmdLine(wxCmdLineParser& parser) -{ - // the standard command line options - static const wxCmdLineEntryDesc cmdLineDesc[] = - { - { - wxCMD_LINE_SWITCH, - _T("h"), - _T("help"), - gettext_noop("show this help message"), - wxCMD_LINE_VAL_NONE, - wxCMD_LINE_OPTION_HELP - }, - -#if wxUSE_LOG - { - wxCMD_LINE_SWITCH, - wxEmptyString, - OPTION_VERBOSE, - gettext_noop("generate verbose log messages"), - wxCMD_LINE_VAL_NONE, - 0x0 - }, -#endif // wxUSE_LOG - - // terminator - { - wxCMD_LINE_NONE, - wxEmptyString, - wxEmptyString, - wxEmptyString, - wxCMD_LINE_VAL_NONE, - 0x0 - } - }; - - parser.SetDesc(cmdLineDesc); -} - -bool wxAppConsole::OnCmdLineParsed(wxCmdLineParser& parser) -{ -#if wxUSE_LOG - if ( parser.Found(OPTION_VERBOSE) ) - { - wxLog::SetVerbose(true); - } -#else - wxUnusedVar(parser); -#endif // wxUSE_LOG - - return true; -} - -bool wxAppConsole::OnCmdLineHelp(wxCmdLineParser& parser) -{ - parser.Usage(); - - return false; -} - -bool wxAppConsole::OnCmdLineError(wxCmdLineParser& parser) -{ - parser.Usage(); - - return false; -} - -#endif // wxUSE_CMDLINE_PARSER - -// ---------------------------------------------------------------------------- -// debugging support -// ---------------------------------------------------------------------------- - -/* static */ -bool wxAppConsole::CheckBuildOptions(const char *optionsSignature, - const char *componentName) -{ -#if 0 // can't use wxLogTrace, not up and running yet - printf("checking build options object '%s' (ptr %p) in '%s'\n", - optionsSignature, optionsSignature, componentName); -#endif - - if ( strcmp(optionsSignature, WX_BUILD_OPTIONS_SIGNATURE) != 0 ) - { - wxString lib = wxString::FromAscii(WX_BUILD_OPTIONS_SIGNATURE); - wxString prog = wxString::FromAscii(optionsSignature); - wxString progName = wxString::FromAscii(componentName); - wxString msg; - - msg.Printf(_T("Mismatch between the program and library build versions detected.\nThe library used %s,\nand %s used %s."), - lib.c_str(), progName.c_str(), prog.c_str()); - - wxLogFatalError(msg.c_str()); - - // normally wxLogFatalError doesn't return - return false; - } -#undef wxCMP - - return true; -} - -#ifdef __WXDEBUG__ - -void wxAppConsole::OnAssertFailure(const wxChar *file, - int line, - const wxChar *func, - const wxChar *cond, - const wxChar *msg) -{ - ShowAssertDialog(file, line, func, cond, msg, GetTraits()); -} - -void wxAppConsole::OnAssert(const wxChar *file, - int line, - const wxChar *cond, - const wxChar *msg) -{ - OnAssertFailure(file, line, NULL, cond, msg); -} - -#endif // __WXDEBUG__ - -#if WXWIN_COMPATIBILITY_2_4 - -bool wxAppConsole::CheckBuildOptions(const wxBuildOptions& buildOptions) -{ - return CheckBuildOptions(buildOptions.m_signature, "your program"); -} - -#endif - -// ============================================================================ -// other classes implementations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// wxConsoleAppTraitsBase -// ---------------------------------------------------------------------------- - -#if wxUSE_LOG - -wxLog *wxConsoleAppTraitsBase::CreateLogTarget() -{ - return new wxLogStderr; -} - -#endif // wxUSE_LOG - -wxMessageOutput *wxConsoleAppTraitsBase::CreateMessageOutput() -{ - return new wxMessageOutputStderr; -} - -#if wxUSE_FONTMAP - -wxFontMapper *wxConsoleAppTraitsBase::CreateFontMapper() -{ - return (wxFontMapper *)new wxFontMapperBase; -} - -#endif // wxUSE_FONTMAP - -wxRendererNative *wxConsoleAppTraitsBase::CreateRenderer() -{ - // console applications don't use renderers - return NULL; -} - -#ifdef __WXDEBUG__ -bool wxConsoleAppTraitsBase::ShowAssertDialog(const wxString& msg) -{ - return wxAppTraitsBase::ShowAssertDialog(msg); -} -#endif - -bool wxConsoleAppTraitsBase::HasStderr() -{ - // console applications always have stderr, even under Mac/Windows - return true; -} - -void wxConsoleAppTraitsBase::ScheduleForDestroy(wxObject *object) -{ - delete object; -} - -void wxConsoleAppTraitsBase::RemoveFromPendingDelete(wxObject * WXUNUSED(object)) -{ - // nothing to do -} - -#if wxUSE_SOCKETS -GSocketGUIFunctionsTable* wxConsoleAppTraitsBase::GetSocketGUIFunctionsTable() -{ - return NULL; -} -#endif - -// ---------------------------------------------------------------------------- -// wxAppTraits -// ---------------------------------------------------------------------------- - -#ifdef __WXDEBUG__ - -bool wxAppTraitsBase::ShowAssertDialog(const wxString& msgOriginal) -{ - wxString msg = msgOriginal; - -#if wxUSE_STACKWALKER -#if !defined(__WXMSW__) - // on Unix stack frame generation may take some time, depending on the - // size of the executable mainly... warn the user that we are working - wxFprintf(stderr, wxT("[Debug] Generating a stack trace... please wait")); - fflush(stderr); -#endif - - const wxString stackTrace = GetAssertStackTrace(); - if ( !stackTrace.empty() ) - msg << _T("\n\nCall stack:\n") << stackTrace; -#endif // wxUSE_STACKWALKER - - return DoShowAssertDialog(msg); -} - -#if wxUSE_STACKWALKER -wxString wxAppTraitsBase::GetAssertStackTrace() -{ - wxString stackTrace; - - class StackDump : public wxStackWalker - { - public: - StackDump() { } - - const wxString& GetStackTrace() const { return m_stackTrace; } - - protected: - virtual void OnStackFrame(const wxStackFrame& frame) - { - m_stackTrace << wxString::Format - ( - _T("[%02d] "), - wx_truncate_cast(int, frame.GetLevel()) - ); - - wxString name = frame.GetName(); - if ( !name.empty() ) - { - m_stackTrace << wxString::Format(_T("%-40s"), name.c_str()); - } - else - { - m_stackTrace << wxString::Format(_T("%p"), frame.GetAddress()); - } - - if ( frame.HasSourceLocation() ) - { - m_stackTrace << _T('\t') - << frame.GetFileName() - << _T(':') - << frame.GetLine(); - } - - m_stackTrace << _T('\n'); - } - - private: - wxString m_stackTrace; - }; - - // don't show more than maxLines or we could get a dialog too tall to be - // shown on screen: 20 should be ok everywhere as even with 15 pixel high - // characters it is still only 300 pixels... - static const int maxLines = 20; - - StackDump dump; - dump.Walk(2, maxLines); // don't show OnAssert() call itself - stackTrace = dump.GetStackTrace(); - - const int count = stackTrace.Freq(wxT('\n')); - for ( int i = 0; i < count - maxLines; i++ ) - stackTrace = stackTrace.BeforeLast(wxT('\n')); - - return stackTrace; -} -#endif // wxUSE_STACKWALKER - - -#endif // __WXDEBUG__ - -// ============================================================================ -// global functions implementation -// ============================================================================ - -void wxExit() -{ - if ( wxTheApp ) - { - wxTheApp->Exit(); - } - else - { - // what else can we do? - exit(-1); - } -} - -void wxWakeUpIdle() -{ - if ( wxTheApp ) - { - wxTheApp->WakeUpIdle(); - } - //else: do nothing, what can we do? -} - -#ifdef __WXDEBUG__ - -// wxASSERT() helper -bool wxAssertIsEqual(int x, int y) -{ - return x == y; -} - -// break into the debugger -void wxTrap() -{ -#if defined(__WXMSW__) && !defined(__WXMICROWIN__) - DebugBreak(); -#elif defined(__WXMAC__) && !defined(__DARWIN__) - #if __powerc - Debugger(); - #else - SysBreak(); - #endif -#elif defined(_MSL_USING_MW_C_HEADERS) && _MSL_USING_MW_C_HEADERS - Debugger(); -#elif defined(__UNIX__) - raise(SIGTRAP); -#else - // TODO -#endif // Win/Unix -} - -// this function is called when an assert fails -void wxOnAssert(const wxChar *szFile, - int nLine, - const char *szFunc, - const wxChar *szCond, - const wxChar *szMsg) -{ - // FIXME MT-unsafe - static int s_bInAssert = 0; - - wxRecursionGuard guard(s_bInAssert); - if ( guard.IsInside() ) - { - // can't use assert here to avoid infinite loops, so just trap - wxTrap(); - - return; - } - - // __FUNCTION__ is always in ASCII, convert it to wide char if needed - const wxString strFunc = wxString::FromAscii(szFunc); - - if ( !wxTheApp ) - { - // by default, show the assert dialog box -- we can't customize this - // behaviour - ShowAssertDialog(szFile, nLine, strFunc, szCond, szMsg); - } - else - { - // let the app process it as it wants - wxTheApp->OnAssertFailure(szFile, nLine, strFunc, szCond, szMsg); - } -} - -#endif // __WXDEBUG__ - -// ============================================================================ -// private functions implementation -// ============================================================================ - -#ifdef __WXDEBUG__ - -static void LINKAGEMODE SetTraceMasks() -{ -#if wxUSE_LOG - wxString mask; - if ( wxGetEnv(wxT("WXTRACE"), &mask) ) - { - wxStringTokenizer tkn(mask, wxT(",;:")); - while ( tkn.HasMoreTokens() ) - wxLog::AddTraceMask(tkn.GetNextToken()); - } -#endif // wxUSE_LOG -} - -bool DoShowAssertDialog(const wxString& msg) -{ - // under MSW we can show the dialog even in the console mode -#if defined(__WXMSW__) && !defined(__WXMICROWIN__) - wxString msgDlg(msg); - - // this message is intentionally not translated -- it is for - // developpers only - msgDlg += wxT("\nDo you want to stop the program?\n") - wxT("You can also choose [Cancel] to suppress ") - wxT("further warnings."); - - switch ( ::MessageBox(NULL, msgDlg, _T("wxWidgets Debug Alert"), - MB_YESNOCANCEL | MB_ICONSTOP ) ) - { - case IDYES: - wxTrap(); - break; - - case IDCANCEL: - // stop the asserts - return true; - - //case IDNO: nothing to do - } -#else // !__WXMSW__ - wxFprintf(stderr, wxT("%s\n"), msg.c_str()); - fflush(stderr); - - // TODO: ask the user to enter "Y" or "N" on the console? - wxTrap(); -#endif // __WXMSW__/!__WXMSW__ - - // continue with the asserts - return false; -} - -// show the assert modal dialog -static -void ShowAssertDialog(const wxChar *szFile, - int nLine, - const wxChar *szFunc, - const wxChar *szCond, - const wxChar *szMsg, - wxAppTraits *traits) -{ - // this variable can be set to true to suppress "assert failure" messages - static bool s_bNoAsserts = false; - - wxString msg; - msg.reserve(2048); - - // make life easier for people using VC++ IDE by using this format: like - // this, clicking on the message will take us immediately to the place of - // the failed assert - msg.Printf(wxT("%s(%d): assert \"%s\" failed"), szFile, nLine, szCond); - - // add the function name, if any - if ( szFunc && *szFunc ) - msg << _T(" in ") << szFunc << _T("()"); - - // and the message itself - if ( szMsg ) - { - msg << _T(": ") << szMsg; - } - else // no message given - { - msg << _T('.'); - } - -#if wxUSE_THREADS - // if we are not in the main thread, output the assert directly and trap - // since dialogs cannot be displayed - if ( !wxThread::IsMain() ) - { - msg += wxT(" [in child thread]"); - -#if defined(__WXMSW__) && !defined(__WXMICROWIN__) - msg << wxT("\r\n"); - OutputDebugString(msg ); -#else - // send to stderr - wxFprintf(stderr, wxT("%s\n"), msg.c_str()); - fflush(stderr); -#endif - // He-e-e-e-elp!! we're asserting in a child thread - wxTrap(); - } - else -#endif // wxUSE_THREADS - - if ( !s_bNoAsserts ) - { - // send it to the normal log destination - wxLogDebug(_T("%s"), msg.c_str()); - - if ( traits ) - { - // delegate showing assert dialog (if possible) to that class - s_bNoAsserts = traits->ShowAssertDialog(msg); - } - else // no traits object - { - // fall back to the function of last resort - s_bNoAsserts = DoShowAssertDialog(msg); - } - } -} - -#endif // __WXDEBUG__ +/////////////////////////////////////////////////////////////////////////////// +// Name: src/common/appbase.cpp +// Purpose: implements wxAppConsole class +// Author: Vadim Zeitlin +// Modified by: +// Created: 19.06.2003 (extracted from common/appcmn.cpp) +// RCS-ID: $Id: appbase.cpp 52093 2008-02-25 13:43:07Z VZ $ +// Copyright: (c) 2003 Vadim Zeitlin +// License: wxWindows license +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// for compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#ifndef WX_PRECOMP + #ifdef __WXMSW__ + #include "wx/msw/wrapwin.h" // includes windows.h for MessageBox() + #endif + #include "wx/list.h" + #include "wx/app.h" + #include "wx/intl.h" + #include "wx/log.h" + #include "wx/utils.h" +#endif //WX_PRECOMP + +#include "wx/apptrait.h" +#include "wx/cmdline.h" +#include "wx/confbase.h" +#include "wx/filename.h" +#include "wx/msgout.h" +#include "wx/tokenzr.h" + +#if !defined(__WXMSW__) || defined(__WXMICROWIN__) + #include // for SIGTRAP used by wxTrap() +#endif //Win/Unix + +#if wxUSE_FONTMAP + #include "wx/fontmap.h" +#endif // wxUSE_FONTMAP + +#if defined(__DARWIN__) && defined(_MSL_USING_MW_C_HEADERS) && _MSL_USING_MW_C_HEADERS + // For MacTypes.h for Debugger function + #include +#endif + +#if defined(__WXMAC__) + #ifdef __DARWIN__ + #include + #else + #include "wx/mac/private.h" // includes mac headers + #endif +#endif // __WXMAC__ + +#ifdef __WXDEBUG__ + #if wxUSE_STACKWALKER + #include "wx/stackwalk.h" + #ifdef __WXMSW__ + #include "wx/msw/debughlp.h" + #endif + #endif // wxUSE_STACKWALKER + + #include "wx/recguard.h" +#endif // __WXDEBUG__ + +// wxABI_VERSION can be defined when compiling applications but it should be +// left undefined when compiling the library itself, it is then set to its +// default value in version.h +#if wxABI_VERSION != wxMAJOR_VERSION * 10000 + wxMINOR_VERSION * 100 + 99 +#error "wxABI_VERSION should not be defined when compiling the library" +#endif + +// ---------------------------------------------------------------------------- +// private functions prototypes +// ---------------------------------------------------------------------------- + +#ifdef __WXDEBUG__ + // really just show the assert dialog + static bool DoShowAssertDialog(const wxString& msg); + + // prepare for showing the assert dialog, use the given traits or + // DoShowAssertDialog() as last fallback to really show it + static + void ShowAssertDialog(const wxChar *szFile, + int nLine, + const wxChar *szFunc, + const wxChar *szCond, + const wxChar *szMsg, + wxAppTraits *traits = NULL); + + // turn on the trace masks specified in the env variable WXTRACE + static void LINKAGEMODE SetTraceMasks(); +#endif // __WXDEBUG__ + +// ---------------------------------------------------------------------------- +// global vars +// ---------------------------------------------------------------------------- + +wxAppConsole *wxAppConsole::ms_appInstance = NULL; + +wxAppInitializerFunction wxAppConsole::ms_appInitFn = NULL; + +// ============================================================================ +// wxAppConsole implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// ctor/dtor +// ---------------------------------------------------------------------------- + +wxAppConsole::wxAppConsole() +{ + m_traits = NULL; + + ms_appInstance = this; + +#ifdef __WXDEBUG__ + SetTraceMasks(); +#if wxUSE_UNICODE + // In unicode mode the SetTraceMasks call can cause an apptraits to be + // created, but since we are still in the constructor the wrong kind will + // be created for GUI apps. Destroy it so it can be created again later. + delete m_traits; + m_traits = NULL; +#endif +#endif +} + +wxAppConsole::~wxAppConsole() +{ + delete m_traits; +} + +// ---------------------------------------------------------------------------- +// initilization/cleanup +// ---------------------------------------------------------------------------- + +bool wxAppConsole::Initialize(int& argcOrig, wxChar **argvOrig) +{ + // remember the command line arguments + argc = argcOrig; + argv = argvOrig; + +#ifndef __WXPALMOS__ + if ( m_appName.empty() && argv ) + { + // the application name is, by default, the name of its executable file + wxFileName::SplitPath(argv[0], NULL, &m_appName, NULL); + } +#endif + + return true; +} + +void wxAppConsole::CleanUp() +{ +} + +// ---------------------------------------------------------------------------- +// OnXXX() callbacks +// ---------------------------------------------------------------------------- + +bool wxAppConsole::OnInit() +{ +#if wxUSE_CMDLINE_PARSER + wxCmdLineParser parser(argc, argv); + + OnInitCmdLine(parser); + + bool cont; + switch ( parser.Parse(false /* don't show usage */) ) + { + case -1: + cont = OnCmdLineHelp(parser); + break; + + case 0: + cont = OnCmdLineParsed(parser); + break; + + default: + cont = OnCmdLineError(parser); + break; + } + + if ( !cont ) + return false; +#endif // wxUSE_CMDLINE_PARSER + + return true; +} + +int wxAppConsole::OnExit() +{ +#if wxUSE_CONFIG + // delete the config object if any (don't use Get() here, but Set() + // because Get() could create a new config object) + delete wxConfigBase::Set((wxConfigBase *) NULL); +#endif // wxUSE_CONFIG + + return 0; +} + +void wxAppConsole::Exit() +{ + exit(-1); +} + +// ---------------------------------------------------------------------------- +// traits stuff +// ---------------------------------------------------------------------------- + +wxAppTraits *wxAppConsole::CreateTraits() +{ + return new wxConsoleAppTraits; +} + +wxAppTraits *wxAppConsole::GetTraits() +{ + // FIXME-MT: protect this with a CS? + if ( !m_traits ) + { + m_traits = CreateTraits(); + + wxASSERT_MSG( m_traits, _T("wxApp::CreateTraits() failed?") ); + } + + return m_traits; +} + +// we must implement CreateXXX() in wxApp itself for backwards compatibility +#if WXWIN_COMPATIBILITY_2_4 + +#if wxUSE_LOG + +wxLog *wxAppConsole::CreateLogTarget() +{ + wxAppTraits *traits = GetTraits(); + return traits ? traits->CreateLogTarget() : NULL; +} + +#endif // wxUSE_LOG + +wxMessageOutput *wxAppConsole::CreateMessageOutput() +{ + wxAppTraits *traits = GetTraits(); + return traits ? traits->CreateMessageOutput() : NULL; +} + +#endif // WXWIN_COMPATIBILITY_2_4 + +// ---------------------------------------------------------------------------- +// event processing +// ---------------------------------------------------------------------------- + +void wxAppConsole::ProcessPendingEvents() +{ +#if wxUSE_THREADS + if ( !wxPendingEventsLocker ) + return; +#endif + + // ensure that we're the only thread to modify the pending events list + wxENTER_CRIT_SECT( *wxPendingEventsLocker ); + + if ( !wxPendingEvents ) + { + wxLEAVE_CRIT_SECT( *wxPendingEventsLocker ); + return; + } + + // iterate until the list becomes empty + wxList::compatibility_iterator node = wxPendingEvents->GetFirst(); + while (node) + { + wxEvtHandler *handler = (wxEvtHandler *)node->GetData(); + wxPendingEvents->Erase(node); + + // In ProcessPendingEvents(), new handlers might be add + // and we can safely leave the critical section here. + wxLEAVE_CRIT_SECT( *wxPendingEventsLocker ); + + handler->ProcessPendingEvents(); + + wxENTER_CRIT_SECT( *wxPendingEventsLocker ); + + node = wxPendingEvents->GetFirst(); + } + + wxLEAVE_CRIT_SECT( *wxPendingEventsLocker ); +} + +int wxAppConsole::FilterEvent(wxEvent& WXUNUSED(event)) +{ + // process the events normally by default + return -1; +} + +// ---------------------------------------------------------------------------- +// exception handling +// ---------------------------------------------------------------------------- + +#if wxUSE_EXCEPTIONS + +void +wxAppConsole::HandleEvent(wxEvtHandler *handler, + wxEventFunction func, + wxEvent& event) const +{ + // by default, simply call the handler + (handler->*func)(event); +} + +#endif // wxUSE_EXCEPTIONS + +// ---------------------------------------------------------------------------- +// cmd line parsing +// ---------------------------------------------------------------------------- + +#if wxUSE_CMDLINE_PARSER + +#define OPTION_VERBOSE _T("verbose") + +void wxAppConsole::OnInitCmdLine(wxCmdLineParser& parser) +{ + // the standard command line options + static const wxCmdLineEntryDesc cmdLineDesc[] = + { + { + wxCMD_LINE_SWITCH, + _T("h"), + _T("help"), + gettext_noop("show this help message"), + wxCMD_LINE_VAL_NONE, + wxCMD_LINE_OPTION_HELP + }, + +#if wxUSE_LOG + { + wxCMD_LINE_SWITCH, + wxEmptyString, + OPTION_VERBOSE, + gettext_noop("generate verbose log messages"), + wxCMD_LINE_VAL_NONE, + 0x0 + }, +#endif // wxUSE_LOG + + // terminator + { + wxCMD_LINE_NONE, + wxEmptyString, + wxEmptyString, + wxEmptyString, + wxCMD_LINE_VAL_NONE, + 0x0 + } + }; + + parser.SetDesc(cmdLineDesc); +} + +bool wxAppConsole::OnCmdLineParsed(wxCmdLineParser& parser) +{ +#if wxUSE_LOG + if ( parser.Found(OPTION_VERBOSE) ) + { + wxLog::SetVerbose(true); + } +#else + wxUnusedVar(parser); +#endif // wxUSE_LOG + + return true; +} + +bool wxAppConsole::OnCmdLineHelp(wxCmdLineParser& parser) +{ + parser.Usage(); + + return false; +} + +bool wxAppConsole::OnCmdLineError(wxCmdLineParser& parser) +{ + parser.Usage(); + + return false; +} + +#endif // wxUSE_CMDLINE_PARSER + +// ---------------------------------------------------------------------------- +// debugging support +// ---------------------------------------------------------------------------- + +/* static */ +bool wxAppConsole::CheckBuildOptions(const char *optionsSignature, + const char *componentName) +{ +#if 0 // can't use wxLogTrace, not up and running yet + printf("checking build options object '%s' (ptr %p) in '%s'\n", + optionsSignature, optionsSignature, componentName); +#endif + + if ( strcmp(optionsSignature, WX_BUILD_OPTIONS_SIGNATURE) != 0 ) + { + wxString lib = wxString::FromAscii(WX_BUILD_OPTIONS_SIGNATURE); + wxString prog = wxString::FromAscii(optionsSignature); + wxString progName = wxString::FromAscii(componentName); + wxString msg; + + msg.Printf(_T("Mismatch between the program and library build versions detected.\nThe library used %s,\nand %s used %s."), + lib.c_str(), progName.c_str(), prog.c_str()); + + wxLogFatalError(msg.c_str()); + + // normally wxLogFatalError doesn't return + return false; + } +#undef wxCMP + + return true; +} + +#ifdef __WXDEBUG__ + +void wxAppConsole::OnAssertFailure(const wxChar *file, + int line, + const wxChar *func, + const wxChar *cond, + const wxChar *msg) +{ + ShowAssertDialog(file, line, func, cond, msg, GetTraits()); +} + +void wxAppConsole::OnAssert(const wxChar *file, + int line, + const wxChar *cond, + const wxChar *msg) +{ + OnAssertFailure(file, line, NULL, cond, msg); +} + +#endif // __WXDEBUG__ + +#if WXWIN_COMPATIBILITY_2_4 + +bool wxAppConsole::CheckBuildOptions(const wxBuildOptions& buildOptions) +{ + return CheckBuildOptions(buildOptions.m_signature, "your program"); +} + +#endif + +// ============================================================================ +// other classes implementations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// wxConsoleAppTraitsBase +// ---------------------------------------------------------------------------- + +#if wxUSE_LOG + +wxLog *wxConsoleAppTraitsBase::CreateLogTarget() +{ + return new wxLogStderr; +} + +#endif // wxUSE_LOG + +wxMessageOutput *wxConsoleAppTraitsBase::CreateMessageOutput() +{ + return new wxMessageOutputStderr; +} + +#if wxUSE_FONTMAP + +wxFontMapper *wxConsoleAppTraitsBase::CreateFontMapper() +{ + return (wxFontMapper *)new wxFontMapperBase; +} + +#endif // wxUSE_FONTMAP + +wxRendererNative *wxConsoleAppTraitsBase::CreateRenderer() +{ + // console applications don't use renderers + return NULL; +} + +#ifdef __WXDEBUG__ +bool wxConsoleAppTraitsBase::ShowAssertDialog(const wxString& msg) +{ + return wxAppTraitsBase::ShowAssertDialog(msg); +} +#endif + +bool wxConsoleAppTraitsBase::HasStderr() +{ + // console applications always have stderr, even under Mac/Windows + return true; +} + +void wxConsoleAppTraitsBase::ScheduleForDestroy(wxObject *object) +{ + delete object; +} + +void wxConsoleAppTraitsBase::RemoveFromPendingDelete(wxObject * WXUNUSED(object)) +{ + // nothing to do +} + +#if wxUSE_SOCKETS +GSocketGUIFunctionsTable* wxConsoleAppTraitsBase::GetSocketGUIFunctionsTable() +{ + return NULL; +} +#endif + +// ---------------------------------------------------------------------------- +// wxAppTraits +// ---------------------------------------------------------------------------- + +#ifdef __WXDEBUG__ + +bool wxAppTraitsBase::ShowAssertDialog(const wxString& msgOriginal) +{ + wxString msg = msgOriginal; + +#if wxUSE_STACKWALKER +#if !defined(__WXMSW__) + // on Unix stack frame generation may take some time, depending on the + // size of the executable mainly... warn the user that we are working + wxFprintf(stderr, wxT("[Debug] Generating a stack trace... please wait")); + fflush(stderr); +#endif + + const wxString stackTrace = GetAssertStackTrace(); + if ( !stackTrace.empty() ) + msg << _T("\n\nCall stack:\n") << stackTrace; +#endif // wxUSE_STACKWALKER + + return DoShowAssertDialog(msg); +} + +#if wxUSE_STACKWALKER +wxString wxAppTraitsBase::GetAssertStackTrace() +{ + wxString stackTrace; + + class StackDump : public wxStackWalker + { + public: + StackDump() { } + + const wxString& GetStackTrace() const { return m_stackTrace; } + + protected: + virtual void OnStackFrame(const wxStackFrame& frame) + { + m_stackTrace << wxString::Format + ( + _T("[%02d] "), + wx_truncate_cast(int, frame.GetLevel()) + ); + + wxString name = frame.GetName(); + if ( !name.empty() ) + { + m_stackTrace << wxString::Format(_T("%-40s"), name.c_str()); + } + else + { + m_stackTrace << wxString::Format(_T("%p"), frame.GetAddress()); + } + + if ( frame.HasSourceLocation() ) + { + m_stackTrace << _T('\t') + << frame.GetFileName() + << _T(':') + << frame.GetLine(); + } + + m_stackTrace << _T('\n'); + } + + private: + wxString m_stackTrace; + }; + + // don't show more than maxLines or we could get a dialog too tall to be + // shown on screen: 20 should be ok everywhere as even with 15 pixel high + // characters it is still only 300 pixels... + static const int maxLines = 20; + + StackDump dump; + dump.Walk(2, maxLines); // don't show OnAssert() call itself + stackTrace = dump.GetStackTrace(); + + const int count = stackTrace.Freq(wxT('\n')); + for ( int i = 0; i < count - maxLines; i++ ) + stackTrace = stackTrace.BeforeLast(wxT('\n')); + + return stackTrace; +} +#endif // wxUSE_STACKWALKER + + +#endif // __WXDEBUG__ + +// ============================================================================ +// global functions implementation +// ============================================================================ + +void wxExit() +{ + if ( wxTheApp ) + { + wxTheApp->Exit(); + } + else + { + // what else can we do? + exit(-1); + } +} + +void wxWakeUpIdle() +{ + if ( wxTheApp ) + { + wxTheApp->WakeUpIdle(); + } + //else: do nothing, what can we do? +} + +#ifdef __WXDEBUG__ + +// wxASSERT() helper +bool wxAssertIsEqual(int x, int y) +{ + return x == y; +} + +// break into the debugger +void wxTrap() +{ +#if defined(__WXMSW__) && !defined(__WXMICROWIN__) + DebugBreak(); +#elif defined(__WXMAC__) && !defined(__DARWIN__) + #if __powerc + Debugger(); + #else + SysBreak(); + #endif +#elif defined(_MSL_USING_MW_C_HEADERS) && _MSL_USING_MW_C_HEADERS + Debugger(); +#elif defined(__UNIX__) + raise(SIGTRAP); +#else + // TODO +#endif // Win/Unix +} + +// this function is called when an assert fails +void wxOnAssert(const wxChar *szFile, + int nLine, + const char *szFunc, + const wxChar *szCond, + const wxChar *szMsg) +{ + // FIXME MT-unsafe + static int s_bInAssert = 0; + + wxRecursionGuard guard(s_bInAssert); + if ( guard.IsInside() ) + { + // can't use assert here to avoid infinite loops, so just trap + wxTrap(); + + return; + } + + // __FUNCTION__ is always in ASCII, convert it to wide char if needed + const wxString strFunc = wxString::FromAscii(szFunc); + + if ( !wxTheApp ) + { + // by default, show the assert dialog box -- we can't customize this + // behaviour + ShowAssertDialog(szFile, nLine, strFunc, szCond, szMsg); + } + else + { + // let the app process it as it wants + wxTheApp->OnAssertFailure(szFile, nLine, strFunc, szCond, szMsg); + } +} + +#endif // __WXDEBUG__ + +// ============================================================================ +// private functions implementation +// ============================================================================ + +#ifdef __WXDEBUG__ + +static void LINKAGEMODE SetTraceMasks() +{ +#if wxUSE_LOG + wxString mask; + if ( wxGetEnv(wxT("WXTRACE"), &mask) ) + { + wxStringTokenizer tkn(mask, wxT(",;:")); + while ( tkn.HasMoreTokens() ) + wxLog::AddTraceMask(tkn.GetNextToken()); + } +#endif // wxUSE_LOG +} + +bool DoShowAssertDialog(const wxString& msg) +{ + // under MSW we can show the dialog even in the console mode +#if defined(__WXMSW__) && !defined(__WXMICROWIN__) + wxString msgDlg(msg); + + // this message is intentionally not translated -- it is for + // developpers only + msgDlg += wxT("\nDo you want to stop the program?\n") + wxT("You can also choose [Cancel] to suppress ") + wxT("further warnings."); + + switch ( ::MessageBox(NULL, msgDlg, _T("wxWidgets Debug Alert"), + MB_YESNOCANCEL | MB_ICONSTOP ) ) + { + case IDYES: + wxTrap(); + break; + + case IDCANCEL: + // stop the asserts + return true; + + //case IDNO: nothing to do + } +#else // !__WXMSW__ + wxFprintf(stderr, wxT("%s\n"), msg.c_str()); + fflush(stderr); + + // TODO: ask the user to enter "Y" or "N" on the console? + wxTrap(); +#endif // __WXMSW__/!__WXMSW__ + + // continue with the asserts + return false; +} + +// show the assert modal dialog +static +void ShowAssertDialog(const wxChar *szFile, + int nLine, + const wxChar *szFunc, + const wxChar *szCond, + const wxChar *szMsg, + wxAppTraits *traits) +{ + // this variable can be set to true to suppress "assert failure" messages + static bool s_bNoAsserts = false; + + wxString msg; + msg.reserve(2048); + + // make life easier for people using VC++ IDE by using this format: like + // this, clicking on the message will take us immediately to the place of + // the failed assert + msg.Printf(wxT("%s(%d): assert \"%s\" failed"), szFile, nLine, szCond); + + // add the function name, if any + if ( szFunc && *szFunc ) + msg << _T(" in ") << szFunc << _T("()"); + + // and the message itself + if ( szMsg ) + { + msg << _T(": ") << szMsg; + } + else // no message given + { + msg << _T('.'); + } + +#if wxUSE_THREADS + // if we are not in the main thread, output the assert directly and trap + // since dialogs cannot be displayed + if ( !wxThread::IsMain() ) + { + msg += wxT(" [in child thread]"); + +#if defined(__WXMSW__) && !defined(__WXMICROWIN__) + msg << wxT("\r\n"); + OutputDebugString(msg ); +#else + // send to stderr + wxFprintf(stderr, wxT("%s\n"), msg.c_str()); + fflush(stderr); +#endif + // He-e-e-e-elp!! we're asserting in a child thread + wxTrap(); + } + else +#endif // wxUSE_THREADS + + if ( !s_bNoAsserts ) + { + // send it to the normal log destination + wxLogDebug(_T("%s"), msg.c_str()); + + if ( traits ) + { + // delegate showing assert dialog (if possible) to that class + s_bNoAsserts = traits->ShowAssertDialog(msg); + } + else // no traits object + { + // fall back to the function of last resort + s_bNoAsserts = DoShowAssertDialog(msg); + } + } +} + +#endif // __WXDEBUG__ diff --git a/Externals/wxWidgets/src/common/appcmn.cpp b/Externals/wxWidgets/src/common/appcmn.cpp index c5ef802e99..bc1a30c11f 100644 --- a/Externals/wxWidgets/src/common/appcmn.cpp +++ b/Externals/wxWidgets/src/common/appcmn.cpp @@ -1,691 +1,691 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/appcmn.cpp -// Purpose: wxAppConsole and wxAppBase methods common to all platforms -// Author: Vadim Zeitlin -// Modified by: -// Created: 18.10.99 -// RCS-ID: $Id: appcmn.cpp 47229 2007-07-08 05:31:32Z PC $ -// Copyright: (c) Vadim Zeitlin -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// --------------------------------------------------------------------------- -// headers -// --------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#if defined(__BORLANDC__) - #pragma hdrstop -#endif - -#ifndef WX_PRECOMP - #include "wx/app.h" - #include "wx/window.h" - #include "wx/bitmap.h" - #include "wx/log.h" - #include "wx/msgdlg.h" - #include "wx/confbase.h" - #include "wx/utils.h" -#endif - -#include "wx/apptrait.h" -#include "wx/cmdline.h" -#include "wx/evtloop.h" -#include "wx/msgout.h" -#include "wx/thread.h" -#include "wx/vidmode.h" -#include "wx/ptr_scpd.h" - -#ifdef __WXDEBUG__ - #if wxUSE_STACKWALKER - #include "wx/stackwalk.h" - #endif // wxUSE_STACKWALKER -#endif // __WXDEBUG__ - -#if defined(__WXMSW__) - #include "wx/msw/private.h" // includes windows.h for LOGFONT -#endif - -#if defined(__WXMAC__) - #include "wx/mac/private.h" -#endif - -#if wxUSE_FONTMAP - #include "wx/fontmap.h" -#endif // wxUSE_FONTMAP - -// DLL options compatibility check: -#include "wx/build.h" -WX_CHECK_BUILD_OPTIONS("wxCore") - -WXDLLIMPEXP_DATA_CORE(wxList) wxPendingDelete; - -// ---------------------------------------------------------------------------- -// wxEventLoopPtr -// ---------------------------------------------------------------------------- - -// this defines wxEventLoopPtr -wxDEFINE_TIED_SCOPED_PTR_TYPE(wxEventLoop) - -// ============================================================================ -// wxAppBase implementation -// ============================================================================ - -// ---------------------------------------------------------------------------- -// initialization -// ---------------------------------------------------------------------------- - -wxAppBase::wxAppBase() -{ - m_topWindow = (wxWindow *)NULL; - - m_useBestVisual = false; - m_forceTrueColour = false; - - m_isActive = true; - - m_mainLoop = NULL; - - // We don't want to exit the app if the user code shows a dialog from its - // OnInit() -- but this is what would happen if we set m_exitOnFrameDelete - // to Yes initially as this dialog would be the last top level window. - // OTOH, if we set it to No initially we'll have to overwrite it with Yes - // when we enter our OnRun() because we do want the default behaviour from - // then on. But this would be a problem if the user code calls - // SetExitOnFrameDelete(false) from OnInit(). - // - // So we use the special "Later" value which is such that - // GetExitOnFrameDelete() returns false for it but which we know we can - // safely (i.e. without losing the effect of the users SetExitOnFrameDelete - // call) overwrite in OnRun() - m_exitOnFrameDelete = Later; -} - -bool wxAppBase::Initialize(int& argcOrig, wxChar **argvOrig) -{ - if ( !wxAppConsole::Initialize(argcOrig, argvOrig) ) - return false; - -#if wxUSE_THREADS - wxPendingEventsLocker = new wxCriticalSection; -#endif - - wxInitializeStockLists(); - - wxBitmap::InitStandardHandlers(); - - return true; -} - -// ---------------------------------------------------------------------------- -// cleanup -// ---------------------------------------------------------------------------- - -wxAppBase::~wxAppBase() -{ - // this destructor is required for Darwin -} - -void wxAppBase::CleanUp() -{ - // clean up all the pending objects - DeletePendingObjects(); - - // and any remaining TLWs (they remove themselves from wxTopLevelWindows - // when destroyed, so iterate until none are left) - while ( !wxTopLevelWindows.empty() ) - { - // do not use Destroy() here as it only puts the TLW in pending list - // but we want to delete them now - delete wxTopLevelWindows.GetFirst()->GetData(); - } - - // undo everything we did in Initialize() above - wxBitmap::CleanUpHandlers(); - - wxStockGDI::DeleteAll(); - - wxDeleteStockLists(); - - delete wxTheColourDatabase; - wxTheColourDatabase = NULL; - - delete wxPendingEvents; - wxPendingEvents = NULL; - -#if wxUSE_THREADS - delete wxPendingEventsLocker; - wxPendingEventsLocker = NULL; - - #if wxUSE_VALIDATORS - // If we don't do the following, we get an apparent memory leak. - ((wxEvtHandler&) wxDefaultValidator).ClearEventLocker(); - #endif // wxUSE_VALIDATORS -#endif // wxUSE_THREADS -} - -// ---------------------------------------------------------------------------- -// various accessors -// ---------------------------------------------------------------------------- - -wxWindow* wxAppBase::GetTopWindow() const -{ - wxWindow* window = m_topWindow; - if (window == NULL && wxTopLevelWindows.GetCount() > 0) - window = wxTopLevelWindows.GetFirst()->GetData(); - return window; -} - -wxVideoMode wxAppBase::GetDisplayMode() const -{ - return wxVideoMode(); -} - -wxLayoutDirection wxAppBase::GetLayoutDirection() const -{ -#if wxUSE_INTL - const wxLocale *const locale = wxGetLocale(); - if ( locale ) - { - const wxLanguageInfo *const - info = wxLocale::GetLanguageInfo(locale->GetLanguage()); - - if ( info ) - return info->LayoutDirection; - } -#endif // wxUSE_INTL - - // we don't know - return wxLayout_Default; -} - -#if wxUSE_CMDLINE_PARSER - -// ---------------------------------------------------------------------------- -// GUI-specific command line options handling -// ---------------------------------------------------------------------------- - -#define OPTION_THEME _T("theme") -#define OPTION_MODE _T("mode") - -void wxAppBase::OnInitCmdLine(wxCmdLineParser& parser) -{ - // first add the standard non GUI options - wxAppConsole::OnInitCmdLine(parser); - - // the standard command line options - static const wxCmdLineEntryDesc cmdLineGUIDesc[] = - { -#ifdef __WXUNIVERSAL__ - { - wxCMD_LINE_OPTION, - wxEmptyString, - OPTION_THEME, - gettext_noop("specify the theme to use"), - wxCMD_LINE_VAL_STRING, - 0x0 - }, -#endif // __WXUNIVERSAL__ - -#if defined(__WXMGL__) - // VS: this is not specific to wxMGL, all fullscreen (framebuffer) ports - // should provide this option. That's why it is in common/appcmn.cpp - // and not mgl/app.cpp - { - wxCMD_LINE_OPTION, - wxEmptyString, - OPTION_MODE, - gettext_noop("specify display mode to use (e.g. 640x480-16)"), - wxCMD_LINE_VAL_STRING, - 0x0 - }, -#endif // __WXMGL__ - - // terminator - { - wxCMD_LINE_NONE, - wxEmptyString, - wxEmptyString, - wxEmptyString, - wxCMD_LINE_VAL_NONE, - 0x0 - } - }; - - parser.SetDesc(cmdLineGUIDesc); -} - -bool wxAppBase::OnCmdLineParsed(wxCmdLineParser& parser) -{ -#ifdef __WXUNIVERSAL__ - wxString themeName; - if ( parser.Found(OPTION_THEME, &themeName) ) - { - wxTheme *theme = wxTheme::Create(themeName); - if ( !theme ) - { - wxLogError(_("Unsupported theme '%s'."), themeName.c_str()); - return false; - } - - // Delete the defaultly created theme and set the new theme. - delete wxTheme::Get(); - wxTheme::Set(theme); - } -#endif // __WXUNIVERSAL__ - -#if defined(__WXMGL__) - wxString modeDesc; - if ( parser.Found(OPTION_MODE, &modeDesc) ) - { - unsigned w, h, bpp; - if ( wxSscanf(modeDesc.c_str(), _T("%ux%u-%u"), &w, &h, &bpp) != 3 ) - { - wxLogError(_("Invalid display mode specification '%s'."), modeDesc.c_str()); - return false; - } - - if ( !SetDisplayMode(wxVideoMode(w, h, bpp)) ) - return false; - } -#endif // __WXMGL__ - - return wxAppConsole::OnCmdLineParsed(parser); -} - -#endif // wxUSE_CMDLINE_PARSER - -// ---------------------------------------------------------------------------- -// main event loop implementation -// ---------------------------------------------------------------------------- - -int wxAppBase::MainLoop() -{ - wxEventLoopTiedPtr mainLoop(&m_mainLoop, new wxEventLoop); - - return m_mainLoop->Run(); -} - -void wxAppBase::ExitMainLoop() -{ - // we should exit from the main event loop, not just any currently active - // (e.g. modal dialog) event loop - if ( m_mainLoop && m_mainLoop->IsRunning() ) - { - m_mainLoop->Exit(0); - } -} - -bool wxAppBase::Pending() -{ - // use the currently active message loop here, not m_mainLoop, because if - // we're showing a modal dialog (with its own event loop) currently the - // main event loop is not running anyhow - wxEventLoop * const loop = wxEventLoop::GetActive(); - - return loop && loop->Pending(); -} - -bool wxAppBase::Dispatch() -{ - // see comment in Pending() - wxEventLoop * const loop = wxEventLoop::GetActive(); - - return loop && loop->Dispatch(); -} - -// ---------------------------------------------------------------------------- -// OnXXX() hooks -// ---------------------------------------------------------------------------- - -bool wxAppBase::OnInitGui() -{ -#ifdef __WXUNIVERSAL__ - if ( !wxTheme::Get() && !wxTheme::CreateDefault() ) - return false; -#endif // __WXUNIVERSAL__ - - return true; -} - -int wxAppBase::OnRun() -{ - // see the comment in ctor: if the initial value hasn't been changed, use - // the default Yes from now on - if ( m_exitOnFrameDelete == Later ) - { - m_exitOnFrameDelete = Yes; - } - //else: it has been changed, assume the user knows what he is doing - - return MainLoop(); -} - -int wxAppBase::OnExit() -{ -#ifdef __WXUNIVERSAL__ - delete wxTheme::Set(NULL); -#endif // __WXUNIVERSAL__ - - return wxAppConsole::OnExit(); -} - -void wxAppBase::Exit() -{ - ExitMainLoop(); -} - -wxAppTraits *wxAppBase::CreateTraits() -{ - return new wxGUIAppTraits; -} - -// ---------------------------------------------------------------------------- -// misc -// ---------------------------------------------------------------------------- - -void wxAppBase::SetActive(bool active, wxWindow * WXUNUSED(lastFocus)) -{ - if ( active == m_isActive ) - return; - - m_isActive = active; - - wxActivateEvent event(wxEVT_ACTIVATE_APP, active); - event.SetEventObject(this); - - (void)ProcessEvent(event); -} - -// ---------------------------------------------------------------------------- -// idle handling -// ---------------------------------------------------------------------------- - -void wxAppBase::DeletePendingObjects() -{ - wxList::compatibility_iterator node = wxPendingDelete.GetFirst(); - while (node) - { - wxObject *obj = node->GetData(); - - // remove it from the list first so that if we get back here somehow - // during the object deletion (e.g. wxYield called from its dtor) we - // wouldn't try to delete it the second time - if ( wxPendingDelete.Member(obj) ) - wxPendingDelete.Erase(node); - - delete obj; - - // Deleting one object may have deleted other pending - // objects, so start from beginning of list again. - node = wxPendingDelete.GetFirst(); - } -} - -// Returns true if more time is needed. -bool wxAppBase::ProcessIdle() -{ - // process pending wx events before sending idle events - ProcessPendingEvents(); - - wxIdleEvent event; - bool needMore = false; - wxWindowList::compatibility_iterator node = wxTopLevelWindows.GetFirst(); - while (node) - { - wxWindow* win = node->GetData(); - if (SendIdleEvents(win, event)) - needMore = true; - node = node->GetNext(); - } - - event.SetEventObject(this); - (void) ProcessEvent(event); - if (event.MoreRequested()) - needMore = true; - - // 'Garbage' collection of windows deleted with Close(). - DeletePendingObjects(); - -#if wxUSE_LOG - // flush the logged messages if any - wxLog::FlushActive(); -#endif - - wxUpdateUIEvent::ResetUpdateTime(); - - return needMore; -} - -// Send idle event to window and all subwindows -bool wxAppBase::SendIdleEvents(wxWindow* win, wxIdleEvent& event) -{ - bool needMore = false; - - win->OnInternalIdle(); - - if (wxIdleEvent::CanSend(win)) - { - event.SetEventObject(win); - win->GetEventHandler()->ProcessEvent(event); - - if (event.MoreRequested()) - needMore = true; - } - wxWindowList::compatibility_iterator node = win->GetChildren().GetFirst(); - while ( node ) - { - wxWindow *child = node->GetData(); - if (SendIdleEvents(child, event)) - needMore = true; - - node = node->GetNext(); - } - - return needMore; -} - -void wxAppBase::OnIdle(wxIdleEvent& WXUNUSED(event)) -{ -} - -// ---------------------------------------------------------------------------- -// exceptions support -// ---------------------------------------------------------------------------- - -#if wxUSE_EXCEPTIONS - -bool wxAppBase::OnExceptionInMainLoop() -{ - throw; - - // some compilers are too stupid to know that we never return after throw -#if defined(__DMC__) || (defined(_MSC_VER) && _MSC_VER < 1200) - return false; -#endif -} - -#endif // wxUSE_EXCEPTIONS - -// ---------------------------------------------------------------------------- -// wxGUIAppTraitsBase -// ---------------------------------------------------------------------------- - -#if wxUSE_LOG - -wxLog *wxGUIAppTraitsBase::CreateLogTarget() -{ -#if wxUSE_LOGGUI - return new wxLogGui; -#else - // we must have something! - return new wxLogStderr; -#endif -} - -#endif // wxUSE_LOG - -wxMessageOutput *wxGUIAppTraitsBase::CreateMessageOutput() -{ - // The standard way of printing help on command line arguments (app --help) - // is (according to common practice): - // - console apps: to stderr (on any platform) - // - GUI apps: stderr on Unix platforms (!) - // message box under Windows and others -#ifdef __UNIX__ - return new wxMessageOutputStderr; -#else // !__UNIX__ - // wxMessageOutputMessageBox doesn't work under Motif - #ifdef __WXMOTIF__ - return new wxMessageOutputLog; - #else - return new wxMessageOutputMessageBox; - #endif -#endif // __UNIX__/!__UNIX__ -} - -#if wxUSE_FONTMAP - -wxFontMapper *wxGUIAppTraitsBase::CreateFontMapper() -{ - return new wxFontMapper; -} - -#endif // wxUSE_FONTMAP - -wxRendererNative *wxGUIAppTraitsBase::CreateRenderer() -{ - // use the default native renderer by default - return NULL; -} - -#ifdef __WXDEBUG__ - -bool wxGUIAppTraitsBase::ShowAssertDialog(const wxString& msg) -{ -#if defined(__WXMSW__) || !wxUSE_MSGDLG - // under MSW we prefer to use the base class version using ::MessageBox() - // even if wxMessageBox() is available because it has less chances to - // double fault our app than our wxMessageBox() - return wxAppTraitsBase::ShowAssertDialog(msg); -#else // wxUSE_MSGDLG - wxString msgDlg = msg; - -#if wxUSE_STACKWALKER - // on Unix stack frame generation may take some time, depending on the - // size of the executable mainly... warn the user that we are working - wxFprintf(stderr, wxT("[Debug] Generating a stack trace... please wait")); - fflush(stderr); - - const wxString stackTrace = GetAssertStackTrace(); - if ( !stackTrace.empty() ) - msgDlg << _T("\n\nCall stack:\n") << stackTrace; -#endif // wxUSE_STACKWALKER - - // this message is intentionally not translated -- it is for - // developpers only - msgDlg += wxT("\nDo you want to stop the program?\n") - wxT("You can also choose [Cancel] to suppress ") - wxT("further warnings."); - -#ifdef __WXMAC__ - // in order to avoid reentrancy problems, use the lowest alert API available - CFOptionFlags exitButton; - wxMacCFStringHolder cfText(msgDlg); - OSStatus err = CFUserNotificationDisplayAlert( - 0, kAlertStopAlert, NULL, NULL, NULL, CFSTR("wxWidgets Debug Alert"), cfText, - CFSTR("Yes"), CFSTR("No"), CFSTR("Cancel"), &exitButton ); - if ( err == noErr ) - { - switch( exitButton ) - { - case 0 : // yes - wxTrap(); - break; - case 2 : // cancel - // no more asserts - return true; - case 1 : // no -> nothing to do - break ; - } - } -#else - switch ( wxMessageBox(msgDlg, wxT("wxWidgets Debug Alert"), - wxYES_NO | wxCANCEL | wxICON_STOP ) ) - { - case wxYES: - wxTrap(); - break; - - case wxCANCEL: - // no more asserts - return true; - - //case wxNO: nothing to do - } -#endif - return false; -#endif // !wxUSE_MSGDLG/wxUSE_MSGDLG -} - -#endif // __WXDEBUG__ - -bool wxGUIAppTraitsBase::HasStderr() -{ - // we consider that under Unix stderr always goes somewhere, even if the - // user doesn't always see it under GUI desktops -#ifdef __UNIX__ - return true; -#else - return false; -#endif -} - -void wxGUIAppTraitsBase::ScheduleForDestroy(wxObject *object) -{ - if ( !wxPendingDelete.Member(object) ) - wxPendingDelete.Append(object); -} - -void wxGUIAppTraitsBase::RemoveFromPendingDelete(wxObject *object) -{ - wxPendingDelete.DeleteObject(object); -} - -#if wxUSE_SOCKETS - -#if defined(__WINDOWS__) - #include "wx/msw/gsockmsw.h" -#elif defined(__UNIX__) || defined(__DARWIN__) || defined(__OS2__) - #include "wx/unix/gsockunx.h" -#elif defined(__WXMAC__) - #include - #define OTUNIXERRORS 1 - #include - #include - #include - - #include "wx/mac/gsockmac.h" -#else - #error "Must include correct GSocket header here" -#endif - -GSocketGUIFunctionsTable* wxGUIAppTraitsBase::GetSocketGUIFunctionsTable() -{ -#if defined(__WXMAC__) && !defined(__DARWIN__) - // NB: wxMac CFM does not have any GUI-specific functions in gsocket.c and - // so it doesn't need this table at all - return NULL; -#else // !__WXMAC__ || __DARWIN__ - static GSocketGUIFunctionsTableConcrete table; - return &table; -#endif // !__WXMAC__ || __DARWIN__ -} - -#endif +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/appcmn.cpp +// Purpose: wxAppConsole and wxAppBase methods common to all platforms +// Author: Vadim Zeitlin +// Modified by: +// Created: 18.10.99 +// RCS-ID: $Id: appcmn.cpp 47229 2007-07-08 05:31:32Z PC $ +// Copyright: (c) Vadim Zeitlin +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// --------------------------------------------------------------------------- +// headers +// --------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#if defined(__BORLANDC__) + #pragma hdrstop +#endif + +#ifndef WX_PRECOMP + #include "wx/app.h" + #include "wx/window.h" + #include "wx/bitmap.h" + #include "wx/log.h" + #include "wx/msgdlg.h" + #include "wx/confbase.h" + #include "wx/utils.h" +#endif + +#include "wx/apptrait.h" +#include "wx/cmdline.h" +#include "wx/evtloop.h" +#include "wx/msgout.h" +#include "wx/thread.h" +#include "wx/vidmode.h" +#include "wx/ptr_scpd.h" + +#ifdef __WXDEBUG__ + #if wxUSE_STACKWALKER + #include "wx/stackwalk.h" + #endif // wxUSE_STACKWALKER +#endif // __WXDEBUG__ + +#if defined(__WXMSW__) + #include "wx/msw/private.h" // includes windows.h for LOGFONT +#endif + +#if defined(__WXMAC__) + #include "wx/mac/private.h" +#endif + +#if wxUSE_FONTMAP + #include "wx/fontmap.h" +#endif // wxUSE_FONTMAP + +// DLL options compatibility check: +#include "wx/build.h" +WX_CHECK_BUILD_OPTIONS("wxCore") + +WXDLLIMPEXP_DATA_CORE(wxList) wxPendingDelete; + +// ---------------------------------------------------------------------------- +// wxEventLoopPtr +// ---------------------------------------------------------------------------- + +// this defines wxEventLoopPtr +wxDEFINE_TIED_SCOPED_PTR_TYPE(wxEventLoop) + +// ============================================================================ +// wxAppBase implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// initialization +// ---------------------------------------------------------------------------- + +wxAppBase::wxAppBase() +{ + m_topWindow = (wxWindow *)NULL; + + m_useBestVisual = false; + m_forceTrueColour = false; + + m_isActive = true; + + m_mainLoop = NULL; + + // We don't want to exit the app if the user code shows a dialog from its + // OnInit() -- but this is what would happen if we set m_exitOnFrameDelete + // to Yes initially as this dialog would be the last top level window. + // OTOH, if we set it to No initially we'll have to overwrite it with Yes + // when we enter our OnRun() because we do want the default behaviour from + // then on. But this would be a problem if the user code calls + // SetExitOnFrameDelete(false) from OnInit(). + // + // So we use the special "Later" value which is such that + // GetExitOnFrameDelete() returns false for it but which we know we can + // safely (i.e. without losing the effect of the users SetExitOnFrameDelete + // call) overwrite in OnRun() + m_exitOnFrameDelete = Later; +} + +bool wxAppBase::Initialize(int& argcOrig, wxChar **argvOrig) +{ + if ( !wxAppConsole::Initialize(argcOrig, argvOrig) ) + return false; + +#if wxUSE_THREADS + wxPendingEventsLocker = new wxCriticalSection; +#endif + + wxInitializeStockLists(); + + wxBitmap::InitStandardHandlers(); + + return true; +} + +// ---------------------------------------------------------------------------- +// cleanup +// ---------------------------------------------------------------------------- + +wxAppBase::~wxAppBase() +{ + // this destructor is required for Darwin +} + +void wxAppBase::CleanUp() +{ + // clean up all the pending objects + DeletePendingObjects(); + + // and any remaining TLWs (they remove themselves from wxTopLevelWindows + // when destroyed, so iterate until none are left) + while ( !wxTopLevelWindows.empty() ) + { + // do not use Destroy() here as it only puts the TLW in pending list + // but we want to delete them now + delete wxTopLevelWindows.GetFirst()->GetData(); + } + + // undo everything we did in Initialize() above + wxBitmap::CleanUpHandlers(); + + wxStockGDI::DeleteAll(); + + wxDeleteStockLists(); + + delete wxTheColourDatabase; + wxTheColourDatabase = NULL; + + delete wxPendingEvents; + wxPendingEvents = NULL; + +#if wxUSE_THREADS + delete wxPendingEventsLocker; + wxPendingEventsLocker = NULL; + + #if wxUSE_VALIDATORS + // If we don't do the following, we get an apparent memory leak. + ((wxEvtHandler&) wxDefaultValidator).ClearEventLocker(); + #endif // wxUSE_VALIDATORS +#endif // wxUSE_THREADS +} + +// ---------------------------------------------------------------------------- +// various accessors +// ---------------------------------------------------------------------------- + +wxWindow* wxAppBase::GetTopWindow() const +{ + wxWindow* window = m_topWindow; + if (window == NULL && wxTopLevelWindows.GetCount() > 0) + window = wxTopLevelWindows.GetFirst()->GetData(); + return window; +} + +wxVideoMode wxAppBase::GetDisplayMode() const +{ + return wxVideoMode(); +} + +wxLayoutDirection wxAppBase::GetLayoutDirection() const +{ +#if wxUSE_INTL + const wxLocale *const locale = wxGetLocale(); + if ( locale ) + { + const wxLanguageInfo *const + info = wxLocale::GetLanguageInfo(locale->GetLanguage()); + + if ( info ) + return info->LayoutDirection; + } +#endif // wxUSE_INTL + + // we don't know + return wxLayout_Default; +} + +#if wxUSE_CMDLINE_PARSER + +// ---------------------------------------------------------------------------- +// GUI-specific command line options handling +// ---------------------------------------------------------------------------- + +#define OPTION_THEME _T("theme") +#define OPTION_MODE _T("mode") + +void wxAppBase::OnInitCmdLine(wxCmdLineParser& parser) +{ + // first add the standard non GUI options + wxAppConsole::OnInitCmdLine(parser); + + // the standard command line options + static const wxCmdLineEntryDesc cmdLineGUIDesc[] = + { +#ifdef __WXUNIVERSAL__ + { + wxCMD_LINE_OPTION, + wxEmptyString, + OPTION_THEME, + gettext_noop("specify the theme to use"), + wxCMD_LINE_VAL_STRING, + 0x0 + }, +#endif // __WXUNIVERSAL__ + +#if defined(__WXMGL__) + // VS: this is not specific to wxMGL, all fullscreen (framebuffer) ports + // should provide this option. That's why it is in common/appcmn.cpp + // and not mgl/app.cpp + { + wxCMD_LINE_OPTION, + wxEmptyString, + OPTION_MODE, + gettext_noop("specify display mode to use (e.g. 640x480-16)"), + wxCMD_LINE_VAL_STRING, + 0x0 + }, +#endif // __WXMGL__ + + // terminator + { + wxCMD_LINE_NONE, + wxEmptyString, + wxEmptyString, + wxEmptyString, + wxCMD_LINE_VAL_NONE, + 0x0 + } + }; + + parser.SetDesc(cmdLineGUIDesc); +} + +bool wxAppBase::OnCmdLineParsed(wxCmdLineParser& parser) +{ +#ifdef __WXUNIVERSAL__ + wxString themeName; + if ( parser.Found(OPTION_THEME, &themeName) ) + { + wxTheme *theme = wxTheme::Create(themeName); + if ( !theme ) + { + wxLogError(_("Unsupported theme '%s'."), themeName.c_str()); + return false; + } + + // Delete the defaultly created theme and set the new theme. + delete wxTheme::Get(); + wxTheme::Set(theme); + } +#endif // __WXUNIVERSAL__ + +#if defined(__WXMGL__) + wxString modeDesc; + if ( parser.Found(OPTION_MODE, &modeDesc) ) + { + unsigned w, h, bpp; + if ( wxSscanf(modeDesc.c_str(), _T("%ux%u-%u"), &w, &h, &bpp) != 3 ) + { + wxLogError(_("Invalid display mode specification '%s'."), modeDesc.c_str()); + return false; + } + + if ( !SetDisplayMode(wxVideoMode(w, h, bpp)) ) + return false; + } +#endif // __WXMGL__ + + return wxAppConsole::OnCmdLineParsed(parser); +} + +#endif // wxUSE_CMDLINE_PARSER + +// ---------------------------------------------------------------------------- +// main event loop implementation +// ---------------------------------------------------------------------------- + +int wxAppBase::MainLoop() +{ + wxEventLoopTiedPtr mainLoop(&m_mainLoop, new wxEventLoop); + + return m_mainLoop->Run(); +} + +void wxAppBase::ExitMainLoop() +{ + // we should exit from the main event loop, not just any currently active + // (e.g. modal dialog) event loop + if ( m_mainLoop && m_mainLoop->IsRunning() ) + { + m_mainLoop->Exit(0); + } +} + +bool wxAppBase::Pending() +{ + // use the currently active message loop here, not m_mainLoop, because if + // we're showing a modal dialog (with its own event loop) currently the + // main event loop is not running anyhow + wxEventLoop * const loop = wxEventLoop::GetActive(); + + return loop && loop->Pending(); +} + +bool wxAppBase::Dispatch() +{ + // see comment in Pending() + wxEventLoop * const loop = wxEventLoop::GetActive(); + + return loop && loop->Dispatch(); +} + +// ---------------------------------------------------------------------------- +// OnXXX() hooks +// ---------------------------------------------------------------------------- + +bool wxAppBase::OnInitGui() +{ +#ifdef __WXUNIVERSAL__ + if ( !wxTheme::Get() && !wxTheme::CreateDefault() ) + return false; +#endif // __WXUNIVERSAL__ + + return true; +} + +int wxAppBase::OnRun() +{ + // see the comment in ctor: if the initial value hasn't been changed, use + // the default Yes from now on + if ( m_exitOnFrameDelete == Later ) + { + m_exitOnFrameDelete = Yes; + } + //else: it has been changed, assume the user knows what he is doing + + return MainLoop(); +} + +int wxAppBase::OnExit() +{ +#ifdef __WXUNIVERSAL__ + delete wxTheme::Set(NULL); +#endif // __WXUNIVERSAL__ + + return wxAppConsole::OnExit(); +} + +void wxAppBase::Exit() +{ + ExitMainLoop(); +} + +wxAppTraits *wxAppBase::CreateTraits() +{ + return new wxGUIAppTraits; +} + +// ---------------------------------------------------------------------------- +// misc +// ---------------------------------------------------------------------------- + +void wxAppBase::SetActive(bool active, wxWindow * WXUNUSED(lastFocus)) +{ + if ( active == m_isActive ) + return; + + m_isActive = active; + + wxActivateEvent event(wxEVT_ACTIVATE_APP, active); + event.SetEventObject(this); + + (void)ProcessEvent(event); +} + +// ---------------------------------------------------------------------------- +// idle handling +// ---------------------------------------------------------------------------- + +void wxAppBase::DeletePendingObjects() +{ + wxList::compatibility_iterator node = wxPendingDelete.GetFirst(); + while (node) + { + wxObject *obj = node->GetData(); + + // remove it from the list first so that if we get back here somehow + // during the object deletion (e.g. wxYield called from its dtor) we + // wouldn't try to delete it the second time + if ( wxPendingDelete.Member(obj) ) + wxPendingDelete.Erase(node); + + delete obj; + + // Deleting one object may have deleted other pending + // objects, so start from beginning of list again. + node = wxPendingDelete.GetFirst(); + } +} + +// Returns true if more time is needed. +bool wxAppBase::ProcessIdle() +{ + // process pending wx events before sending idle events + ProcessPendingEvents(); + + wxIdleEvent event; + bool needMore = false; + wxWindowList::compatibility_iterator node = wxTopLevelWindows.GetFirst(); + while (node) + { + wxWindow* win = node->GetData(); + if (SendIdleEvents(win, event)) + needMore = true; + node = node->GetNext(); + } + + event.SetEventObject(this); + (void) ProcessEvent(event); + if (event.MoreRequested()) + needMore = true; + + // 'Garbage' collection of windows deleted with Close(). + DeletePendingObjects(); + +#if wxUSE_LOG + // flush the logged messages if any + wxLog::FlushActive(); +#endif + + wxUpdateUIEvent::ResetUpdateTime(); + + return needMore; +} + +// Send idle event to window and all subwindows +bool wxAppBase::SendIdleEvents(wxWindow* win, wxIdleEvent& event) +{ + bool needMore = false; + + win->OnInternalIdle(); + + if (wxIdleEvent::CanSend(win)) + { + event.SetEventObject(win); + win->GetEventHandler()->ProcessEvent(event); + + if (event.MoreRequested()) + needMore = true; + } + wxWindowList::compatibility_iterator node = win->GetChildren().GetFirst(); + while ( node ) + { + wxWindow *child = node->GetData(); + if (SendIdleEvents(child, event)) + needMore = true; + + node = node->GetNext(); + } + + return needMore; +} + +void wxAppBase::OnIdle(wxIdleEvent& WXUNUSED(event)) +{ +} + +// ---------------------------------------------------------------------------- +// exceptions support +// ---------------------------------------------------------------------------- + +#if wxUSE_EXCEPTIONS + +bool wxAppBase::OnExceptionInMainLoop() +{ + throw; + + // some compilers are too stupid to know that we never return after throw +#if defined(__DMC__) || (defined(_MSC_VER) && _MSC_VER < 1200) + return false; +#endif +} + +#endif // wxUSE_EXCEPTIONS + +// ---------------------------------------------------------------------------- +// wxGUIAppTraitsBase +// ---------------------------------------------------------------------------- + +#if wxUSE_LOG + +wxLog *wxGUIAppTraitsBase::CreateLogTarget() +{ +#if wxUSE_LOGGUI + return new wxLogGui; +#else + // we must have something! + return new wxLogStderr; +#endif +} + +#endif // wxUSE_LOG + +wxMessageOutput *wxGUIAppTraitsBase::CreateMessageOutput() +{ + // The standard way of printing help on command line arguments (app --help) + // is (according to common practice): + // - console apps: to stderr (on any platform) + // - GUI apps: stderr on Unix platforms (!) + // message box under Windows and others +#ifdef __UNIX__ + return new wxMessageOutputStderr; +#else // !__UNIX__ + // wxMessageOutputMessageBox doesn't work under Motif + #ifdef __WXMOTIF__ + return new wxMessageOutputLog; + #else + return new wxMessageOutputMessageBox; + #endif +#endif // __UNIX__/!__UNIX__ +} + +#if wxUSE_FONTMAP + +wxFontMapper *wxGUIAppTraitsBase::CreateFontMapper() +{ + return new wxFontMapper; +} + +#endif // wxUSE_FONTMAP + +wxRendererNative *wxGUIAppTraitsBase::CreateRenderer() +{ + // use the default native renderer by default + return NULL; +} + +#ifdef __WXDEBUG__ + +bool wxGUIAppTraitsBase::ShowAssertDialog(const wxString& msg) +{ +#if defined(__WXMSW__) || !wxUSE_MSGDLG + // under MSW we prefer to use the base class version using ::MessageBox() + // even if wxMessageBox() is available because it has less chances to + // double fault our app than our wxMessageBox() + return wxAppTraitsBase::ShowAssertDialog(msg); +#else // wxUSE_MSGDLG + wxString msgDlg = msg; + +#if wxUSE_STACKWALKER + // on Unix stack frame generation may take some time, depending on the + // size of the executable mainly... warn the user that we are working + wxFprintf(stderr, wxT("[Debug] Generating a stack trace... please wait")); + fflush(stderr); + + const wxString stackTrace = GetAssertStackTrace(); + if ( !stackTrace.empty() ) + msgDlg << _T("\n\nCall stack:\n") << stackTrace; +#endif // wxUSE_STACKWALKER + + // this message is intentionally not translated -- it is for + // developpers only + msgDlg += wxT("\nDo you want to stop the program?\n") + wxT("You can also choose [Cancel] to suppress ") + wxT("further warnings."); + +#ifdef __WXMAC__ + // in order to avoid reentrancy problems, use the lowest alert API available + CFOptionFlags exitButton; + wxMacCFStringHolder cfText(msgDlg); + OSStatus err = CFUserNotificationDisplayAlert( + 0, kAlertStopAlert, NULL, NULL, NULL, CFSTR("wxWidgets Debug Alert"), cfText, + CFSTR("Yes"), CFSTR("No"), CFSTR("Cancel"), &exitButton ); + if ( err == noErr ) + { + switch( exitButton ) + { + case 0 : // yes + wxTrap(); + break; + case 2 : // cancel + // no more asserts + return true; + case 1 : // no -> nothing to do + break ; + } + } +#else + switch ( wxMessageBox(msgDlg, wxT("wxWidgets Debug Alert"), + wxYES_NO | wxCANCEL | wxICON_STOP ) ) + { + case wxYES: + wxTrap(); + break; + + case wxCANCEL: + // no more asserts + return true; + + //case wxNO: nothing to do + } +#endif + return false; +#endif // !wxUSE_MSGDLG/wxUSE_MSGDLG +} + +#endif // __WXDEBUG__ + +bool wxGUIAppTraitsBase::HasStderr() +{ + // we consider that under Unix stderr always goes somewhere, even if the + // user doesn't always see it under GUI desktops +#ifdef __UNIX__ + return true; +#else + return false; +#endif +} + +void wxGUIAppTraitsBase::ScheduleForDestroy(wxObject *object) +{ + if ( !wxPendingDelete.Member(object) ) + wxPendingDelete.Append(object); +} + +void wxGUIAppTraitsBase::RemoveFromPendingDelete(wxObject *object) +{ + wxPendingDelete.DeleteObject(object); +} + +#if wxUSE_SOCKETS + +#if defined(__WINDOWS__) + #include "wx/msw/gsockmsw.h" +#elif defined(__UNIX__) || defined(__DARWIN__) || defined(__OS2__) + #include "wx/unix/gsockunx.h" +#elif defined(__WXMAC__) + #include + #define OTUNIXERRORS 1 + #include + #include + #include + + #include "wx/mac/gsockmac.h" +#else + #error "Must include correct GSocket header here" +#endif + +GSocketGUIFunctionsTable* wxGUIAppTraitsBase::GetSocketGUIFunctionsTable() +{ +#if defined(__WXMAC__) && !defined(__DARWIN__) + // NB: wxMac CFM does not have any GUI-specific functions in gsocket.c and + // so it doesn't need this table at all + return NULL; +#else // !__WXMAC__ || __DARWIN__ + static GSocketGUIFunctionsTableConcrete table; + return &table; +#endif // !__WXMAC__ || __DARWIN__ +} + +#endif diff --git a/Externals/wxWidgets/src/common/arcall.cpp b/Externals/wxWidgets/src/common/arcall.cpp index a66ea703db..bedf19becd 100644 --- a/Externals/wxWidgets/src/common/arcall.cpp +++ b/Externals/wxWidgets/src/common/arcall.cpp @@ -1,41 +1,41 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/arcall.cpp -// Purpose: wxArchive link all archive streams -// Author: Mike Wetherell -// RCS-ID: $Id: arcall.cpp 42508 2006-10-27 09:53:38Z MW $ -// Copyright: (c) 2006 Mike Wetherell -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_ARCHIVE_STREAMS - -#if wxUSE_ZIPSTREAM -#include "wx/zipstrm.h" -#endif -#if wxUSE_TARSTREAM -#include "wx/tarstrm.h" -#endif - -// Reference archive classes to ensure they are linked into a statically -// linked program that uses Find or GetFirst to look for an archive handler. -// It is in its own file so that the user can override this behaviour by -// providing their own implementation. - -void wxUseArchiveClasses() -{ -#if wxUSE_ZIPSTREAM - wxZipClassFactory(); -#endif -#if wxUSE_TARSTREAM - wxTarClassFactory(); -#endif -} - -#endif // wxUSE_ARCHIVE_STREAMS +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/arcall.cpp +// Purpose: wxArchive link all archive streams +// Author: Mike Wetherell +// RCS-ID: $Id: arcall.cpp 42508 2006-10-27 09:53:38Z MW $ +// Copyright: (c) 2006 Mike Wetherell +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_ARCHIVE_STREAMS + +#if wxUSE_ZIPSTREAM +#include "wx/zipstrm.h" +#endif +#if wxUSE_TARSTREAM +#include "wx/tarstrm.h" +#endif + +// Reference archive classes to ensure they are linked into a statically +// linked program that uses Find or GetFirst to look for an archive handler. +// It is in its own file so that the user can override this behaviour by +// providing their own implementation. + +void wxUseArchiveClasses() +{ +#if wxUSE_ZIPSTREAM + wxZipClassFactory(); +#endif +#if wxUSE_TARSTREAM + wxTarClassFactory(); +#endif +} + +#endif // wxUSE_ARCHIVE_STREAMS diff --git a/Externals/wxWidgets/src/common/arcfind.cpp b/Externals/wxWidgets/src/common/arcfind.cpp index f983993fc2..c105dc640c 100644 --- a/Externals/wxWidgets/src/common/arcfind.cpp +++ b/Externals/wxWidgets/src/common/arcfind.cpp @@ -1,43 +1,43 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/arcfind.cpp -// Purpose: Streams for archive formats -// Author: Mike Wetherell -// RCS-ID: $Id: arcfind.cpp 42508 2006-10-27 09:53:38Z MW $ -// Copyright: (c) Mike Wetherell -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_ARCHIVE_STREAMS - -#include "wx/archive.h" - -// These functions are in a separate file so that statically linked apps -// that do not call them to search for archive handlers will only link in -// the archive classes they use. - -const wxArchiveClassFactory * -wxArchiveClassFactory::Find(const wxChar *protocol, wxStreamProtocolType type) -{ - for (const wxArchiveClassFactory *f = GetFirst(); f; f = f->GetNext()) - if (f->CanHandle(protocol, type)) - return f; - - return NULL; -} - -// static -const wxArchiveClassFactory *wxArchiveClassFactory::GetFirst() -{ - if (!sm_first) - wxUseArchiveClasses(); - return sm_first; -} - -#endif // wxUSE_ARCHIVE_STREAMS +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/arcfind.cpp +// Purpose: Streams for archive formats +// Author: Mike Wetherell +// RCS-ID: $Id: arcfind.cpp 42508 2006-10-27 09:53:38Z MW $ +// Copyright: (c) Mike Wetherell +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_ARCHIVE_STREAMS + +#include "wx/archive.h" + +// These functions are in a separate file so that statically linked apps +// that do not call them to search for archive handlers will only link in +// the archive classes they use. + +const wxArchiveClassFactory * +wxArchiveClassFactory::Find(const wxChar *protocol, wxStreamProtocolType type) +{ + for (const wxArchiveClassFactory *f = GetFirst(); f; f = f->GetNext()) + if (f->CanHandle(protocol, type)) + return f; + + return NULL; +} + +// static +const wxArchiveClassFactory *wxArchiveClassFactory::GetFirst() +{ + if (!sm_first) + wxUseArchiveClasses(); + return sm_first; +} + +#endif // wxUSE_ARCHIVE_STREAMS diff --git a/Externals/wxWidgets/src/common/archive.cpp b/Externals/wxWidgets/src/common/archive.cpp index 512e3d7382..1c2dfdb44c 100644 --- a/Externals/wxWidgets/src/common/archive.cpp +++ b/Externals/wxWidgets/src/common/archive.cpp @@ -1,98 +1,98 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/archive.cpp -// Purpose: Streams for archive formats -// Author: Mike Wetherell -// RCS-ID: $Id: archive.cpp 42508 2006-10-27 09:53:38Z MW $ -// Copyright: (c) Mike Wetherell -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_STREAMS && wxUSE_ARCHIVE_STREAMS - -#include "wx/archive.h" - -IMPLEMENT_ABSTRACT_CLASS(wxArchiveEntry, wxObject) -IMPLEMENT_ABSTRACT_CLASS(wxArchiveClassFactory, wxFilterClassFactoryBase) - - -///////////////////////////////////////////////////////////////////////////// -// wxArchiveInputStream - -wxArchiveInputStream::wxArchiveInputStream(wxInputStream& stream, - wxMBConv& conv) - : wxFilterInputStream(stream), - m_conv(conv) -{ -} - -wxArchiveInputStream::wxArchiveInputStream(wxInputStream *stream, - wxMBConv& conv) - : wxFilterInputStream(stream), - m_conv(conv) -{ -} - - -///////////////////////////////////////////////////////////////////////////// -// wxArchiveOutputStream - -wxArchiveOutputStream::wxArchiveOutputStream(wxOutputStream& stream, - wxMBConv& conv) - : wxFilterOutputStream(stream), - m_conv(conv) -{ -} - -wxArchiveOutputStream::wxArchiveOutputStream(wxOutputStream *stream, - wxMBConv& conv) - : wxFilterOutputStream(stream), - m_conv(conv) -{ -} - - -///////////////////////////////////////////////////////////////////////////// -// wxArchiveEntry - -void wxArchiveEntry::SetNotifier(wxArchiveNotifier& notifier) -{ - UnsetNotifier(); - m_notifier = ¬ifier; - m_notifier->OnEntryUpdated(*this); -} - -wxArchiveEntry& wxArchiveEntry::operator=(const wxArchiveEntry& WXUNUSED(e)) -{ - m_notifier = NULL; - return *this; -} - - -///////////////////////////////////////////////////////////////////////////// -// wxArchiveClassFactory - -wxArchiveClassFactory *wxArchiveClassFactory::sm_first = NULL; - -void wxArchiveClassFactory::Remove() -{ - if (m_next != this) - { - wxArchiveClassFactory **pp = &sm_first; - - while (*pp != this) - pp = &(*pp)->m_next; - - *pp = m_next; - - m_next = this; - } -} - -#endif // wxUSE_STREAMS && wxUSE_ARCHIVE_STREAMS +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/archive.cpp +// Purpose: Streams for archive formats +// Author: Mike Wetherell +// RCS-ID: $Id: archive.cpp 42508 2006-10-27 09:53:38Z MW $ +// Copyright: (c) Mike Wetherell +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_STREAMS && wxUSE_ARCHIVE_STREAMS + +#include "wx/archive.h" + +IMPLEMENT_ABSTRACT_CLASS(wxArchiveEntry, wxObject) +IMPLEMENT_ABSTRACT_CLASS(wxArchiveClassFactory, wxFilterClassFactoryBase) + + +///////////////////////////////////////////////////////////////////////////// +// wxArchiveInputStream + +wxArchiveInputStream::wxArchiveInputStream(wxInputStream& stream, + wxMBConv& conv) + : wxFilterInputStream(stream), + m_conv(conv) +{ +} + +wxArchiveInputStream::wxArchiveInputStream(wxInputStream *stream, + wxMBConv& conv) + : wxFilterInputStream(stream), + m_conv(conv) +{ +} + + +///////////////////////////////////////////////////////////////////////////// +// wxArchiveOutputStream + +wxArchiveOutputStream::wxArchiveOutputStream(wxOutputStream& stream, + wxMBConv& conv) + : wxFilterOutputStream(stream), + m_conv(conv) +{ +} + +wxArchiveOutputStream::wxArchiveOutputStream(wxOutputStream *stream, + wxMBConv& conv) + : wxFilterOutputStream(stream), + m_conv(conv) +{ +} + + +///////////////////////////////////////////////////////////////////////////// +// wxArchiveEntry + +void wxArchiveEntry::SetNotifier(wxArchiveNotifier& notifier) +{ + UnsetNotifier(); + m_notifier = ¬ifier; + m_notifier->OnEntryUpdated(*this); +} + +wxArchiveEntry& wxArchiveEntry::operator=(const wxArchiveEntry& WXUNUSED(e)) +{ + m_notifier = NULL; + return *this; +} + + +///////////////////////////////////////////////////////////////////////////// +// wxArchiveClassFactory + +wxArchiveClassFactory *wxArchiveClassFactory::sm_first = NULL; + +void wxArchiveClassFactory::Remove() +{ + if (m_next != this) + { + wxArchiveClassFactory **pp = &sm_first; + + while (*pp != this) + pp = &(*pp)->m_next; + + *pp = m_next; + + m_next = this; + } +} + +#endif // wxUSE_STREAMS && wxUSE_ARCHIVE_STREAMS diff --git a/Externals/wxWidgets/src/common/artprov.cpp b/Externals/wxWidgets/src/common/artprov.cpp index 591abcbbec..23d2830e26 100644 --- a/Externals/wxWidgets/src/common/artprov.cpp +++ b/Externals/wxWidgets/src/common/artprov.cpp @@ -1,338 +1,338 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/artprov.cpp -// Purpose: wxArtProvider class -// Author: Vaclav Slavik -// Modified by: -// Created: 18/03/2002 -// RCS-ID: $Id: artprov.cpp 41398 2006-09-23 20:16:18Z VZ $ -// Copyright: (c) Vaclav Slavik -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// --------------------------------------------------------------------------- -// headers -// --------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#if defined(__BORLANDC__) - #pragma hdrstop -#endif - -#include "wx/artprov.h" - -#ifndef WX_PRECOMP - #include "wx/list.h" - #include "wx/log.h" - #include "wx/hashmap.h" - #include "wx/image.h" - #include "wx/module.h" -#endif - -// =========================================================================== -// implementation -// =========================================================================== - -#include "wx/listimpl.cpp" -WX_DECLARE_LIST(wxArtProvider, wxArtProvidersList); -WX_DEFINE_LIST(wxArtProvidersList) - -// ---------------------------------------------------------------------------- -// Cache class - stores already requested bitmaps -// ---------------------------------------------------------------------------- - -WX_DECLARE_EXPORTED_STRING_HASH_MAP(wxBitmap, wxArtProviderBitmapsHash); - -class WXDLLEXPORT wxArtProviderCache -{ -public: - bool GetBitmap(const wxString& full_id, wxBitmap* bmp); - void PutBitmap(const wxString& full_id, const wxBitmap& bmp) - { m_bitmapsHash[full_id] = bmp; } - - void Clear(); - - static wxString ConstructHashID(const wxArtID& id, - const wxArtClient& client, - const wxSize& size); - -private: - wxArtProviderBitmapsHash m_bitmapsHash; -}; - -bool wxArtProviderCache::GetBitmap(const wxString& full_id, wxBitmap* bmp) -{ - wxArtProviderBitmapsHash::iterator entry = m_bitmapsHash.find(full_id); - if ( entry == m_bitmapsHash.end() ) - { - return false; - } - else - { - *bmp = entry->second; - return true; - } -} - -void wxArtProviderCache::Clear() -{ - m_bitmapsHash.clear(); -} - -/*static*/ wxString wxArtProviderCache::ConstructHashID( - const wxArtID& id, const wxArtClient& client, - const wxSize& size) -{ - wxString str; - str.Printf(wxT("%s-%s-%i-%i"), id.c_str(), client.c_str(), size.x, size.y); - return str; -} - - -// ============================================================================ -// wxArtProvider class -// ============================================================================ - -IMPLEMENT_ABSTRACT_CLASS(wxArtProvider, wxObject) - -wxArtProvidersList *wxArtProvider::sm_providers = NULL; -wxArtProviderCache *wxArtProvider::sm_cache = NULL; - -// ---------------------------------------------------------------------------- -// wxArtProvider ctors/dtor -// ---------------------------------------------------------------------------- - -wxArtProvider::~wxArtProvider() -{ - Remove(this); -} - -// ---------------------------------------------------------------------------- -// wxArtProvider operations on provider stack -// ---------------------------------------------------------------------------- - -/*static*/ void wxArtProvider::CommonAddingProvider() -{ - if ( !sm_providers ) - { - sm_providers = new wxArtProvidersList; - sm_cache = new wxArtProviderCache; - } - - sm_cache->Clear(); -} - -/*static*/ void wxArtProvider::Push(wxArtProvider *provider) -{ - CommonAddingProvider(); - sm_providers->Insert(provider); -} - -/*static*/ void wxArtProvider::Insert(wxArtProvider *provider) -{ - CommonAddingProvider(); - sm_providers->Append(provider); -} - -/*static*/ bool wxArtProvider::Pop() -{ - wxCHECK_MSG( sm_providers, false, _T("no wxArtProvider exists") ); - wxCHECK_MSG( !sm_providers->empty(), false, _T("wxArtProviders stack is empty") ); - - delete sm_providers->GetFirst()->GetData(); - sm_cache->Clear(); - return true; -} - -/*static*/ bool wxArtProvider::Remove(wxArtProvider *provider) -{ - wxCHECK_MSG( sm_providers, false, _T("no wxArtProvider exists") ); - - if ( sm_providers->DeleteObject(provider) ) - { - sm_cache->Clear(); - return true; - } - - return false; -} - -/*static*/ bool wxArtProvider::Delete(wxArtProvider *provider) -{ - // provider will remove itself from the stack in its dtor - delete provider; - - return true; -} - -/*static*/ void wxArtProvider::CleanUpProviders() -{ - if ( sm_providers ) - { - while ( !sm_providers->empty() ) - delete *sm_providers->begin(); - - delete sm_providers; - sm_providers = NULL; - - delete sm_cache; - sm_cache = NULL; - } -} - -// ---------------------------------------------------------------------------- -// wxArtProvider: retrieving bitmaps/icons -// ---------------------------------------------------------------------------- - -/*static*/ wxBitmap wxArtProvider::GetBitmap(const wxArtID& id, - const wxArtClient& client, - const wxSize& size) -{ - // safety-check against writing client,id,size instead of id,client,size: - wxASSERT_MSG( client.Last() == _T('C'), _T("invalid 'client' parameter") ); - - wxCHECK_MSG( sm_providers, wxNullBitmap, _T("no wxArtProvider exists") ); - - wxString hashId = wxArtProviderCache::ConstructHashID(id, client, size); - - wxBitmap bmp; - if ( !sm_cache->GetBitmap(hashId, &bmp) ) - { - for (wxArtProvidersList::compatibility_iterator node = sm_providers->GetFirst(); - node; node = node->GetNext()) - { - bmp = node->GetData()->CreateBitmap(id, client, size); - if ( bmp.Ok() ) - { -#if wxUSE_IMAGE && (!defined(__WXMSW__) || wxUSE_WXDIB) - if ( size != wxDefaultSize && - (bmp.GetWidth() != size.x || bmp.GetHeight() != size.y) ) - { - wxImage img = bmp.ConvertToImage(); - img.Rescale(size.x, size.y); - bmp = wxBitmap(img); - } -#endif - break; - } - } - - sm_cache->PutBitmap(hashId, bmp); - } - - return bmp; -} - -/*static*/ wxIcon wxArtProvider::GetIcon(const wxArtID& id, - const wxArtClient& client, - const wxSize& size) -{ - wxCHECK_MSG( sm_providers, wxNullIcon, _T("no wxArtProvider exists") ); - - wxBitmap bmp = GetBitmap(id, client, size); - if ( !bmp.Ok() ) - return wxNullIcon; - - wxIcon icon; - icon.CopyFromBitmap(bmp); - return icon; -} - -#if defined(__WXGTK20__) && !defined(__WXUNIVERSAL__) - #include "wx/gtk/private.h" - extern GtkIconSize wxArtClientToIconSize(const wxArtClient& client); -#endif // defined(__WXGTK20__) && !defined(__WXUNIVERSAL__) - -/*static*/ wxSize wxArtProvider::GetSizeHint(const wxArtClient& client, - bool platform_dependent) -{ - if (!platform_dependent) - { - wxArtProvidersList::compatibility_iterator node = sm_providers->GetFirst(); - if (node) - return node->GetData()->DoGetSizeHint(client); - } - - // else return platform dependent size - -#if defined(__WXGTK20__) && !defined(__WXUNIVERSAL__) - // Gtk has specific sizes for each client, see artgtk.cpp - GtkIconSize gtk_size = wxArtClientToIconSize(client); - // no size hints for this client - if (gtk_size == GTK_ICON_SIZE_INVALID) - return wxDefaultSize; - gint width, height; - gtk_icon_size_lookup( gtk_size, &width, &height); - return wxSize(width, height); -#else // !GTK+ 2 - // NB: These size hints may have to be adjusted per platform - if (client == wxART_TOOLBAR) - return wxSize(16, 15); - else if (client == wxART_MENU) - return wxSize(16, 15); - else if (client == wxART_FRAME_ICON) - return wxSize(16, 15); - else if (client == wxART_CMN_DIALOG || client == wxART_MESSAGE_BOX) - return wxSize(32, 32); - else if (client == wxART_HELP_BROWSER) - return wxSize(16, 15); - else if (client == wxART_BUTTON) - return wxSize(16, 15); - else // wxART_OTHER or perhaps a user's client, no specified size - return wxDefaultSize; -#endif // GTK+ 2/else -} - -// ---------------------------------------------------------------------------- -// deprecated wxArtProvider methods -// ---------------------------------------------------------------------------- - -#if WXWIN_COMPATIBILITY_2_6 - -/* static */ void wxArtProvider::PushProvider(wxArtProvider *provider) -{ - Push(provider); -} - -/* static */ void wxArtProvider::InsertProvider(wxArtProvider *provider) -{ - Insert(provider); -} - -/* static */ bool wxArtProvider::PopProvider() -{ - return Pop(); -} - -/* static */ bool wxArtProvider::RemoveProvider(wxArtProvider *provider) -{ - // RemoveProvider() used to delete the provider being removed so this is - // not a typo, we must call Delete() and not Remove() here - return Delete(provider); -} - -#endif // WXWIN_COMPATIBILITY_2_6 - -// ============================================================================ -// wxArtProviderModule -// ============================================================================ - -class wxArtProviderModule: public wxModule -{ -public: - bool OnInit() - { - wxArtProvider::InitStdProvider(); - wxArtProvider::InitNativeProvider(); - return true; - } - void OnExit() - { - wxArtProvider::CleanUpProviders(); - } - - DECLARE_DYNAMIC_CLASS(wxArtProviderModule) -}; - -IMPLEMENT_DYNAMIC_CLASS(wxArtProviderModule, wxModule) +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/artprov.cpp +// Purpose: wxArtProvider class +// Author: Vaclav Slavik +// Modified by: +// Created: 18/03/2002 +// RCS-ID: $Id: artprov.cpp 41398 2006-09-23 20:16:18Z VZ $ +// Copyright: (c) Vaclav Slavik +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// --------------------------------------------------------------------------- +// headers +// --------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#if defined(__BORLANDC__) + #pragma hdrstop +#endif + +#include "wx/artprov.h" + +#ifndef WX_PRECOMP + #include "wx/list.h" + #include "wx/log.h" + #include "wx/hashmap.h" + #include "wx/image.h" + #include "wx/module.h" +#endif + +// =========================================================================== +// implementation +// =========================================================================== + +#include "wx/listimpl.cpp" +WX_DECLARE_LIST(wxArtProvider, wxArtProvidersList); +WX_DEFINE_LIST(wxArtProvidersList) + +// ---------------------------------------------------------------------------- +// Cache class - stores already requested bitmaps +// ---------------------------------------------------------------------------- + +WX_DECLARE_EXPORTED_STRING_HASH_MAP(wxBitmap, wxArtProviderBitmapsHash); + +class WXDLLEXPORT wxArtProviderCache +{ +public: + bool GetBitmap(const wxString& full_id, wxBitmap* bmp); + void PutBitmap(const wxString& full_id, const wxBitmap& bmp) + { m_bitmapsHash[full_id] = bmp; } + + void Clear(); + + static wxString ConstructHashID(const wxArtID& id, + const wxArtClient& client, + const wxSize& size); + +private: + wxArtProviderBitmapsHash m_bitmapsHash; +}; + +bool wxArtProviderCache::GetBitmap(const wxString& full_id, wxBitmap* bmp) +{ + wxArtProviderBitmapsHash::iterator entry = m_bitmapsHash.find(full_id); + if ( entry == m_bitmapsHash.end() ) + { + return false; + } + else + { + *bmp = entry->second; + return true; + } +} + +void wxArtProviderCache::Clear() +{ + m_bitmapsHash.clear(); +} + +/*static*/ wxString wxArtProviderCache::ConstructHashID( + const wxArtID& id, const wxArtClient& client, + const wxSize& size) +{ + wxString str; + str.Printf(wxT("%s-%s-%i-%i"), id.c_str(), client.c_str(), size.x, size.y); + return str; +} + + +// ============================================================================ +// wxArtProvider class +// ============================================================================ + +IMPLEMENT_ABSTRACT_CLASS(wxArtProvider, wxObject) + +wxArtProvidersList *wxArtProvider::sm_providers = NULL; +wxArtProviderCache *wxArtProvider::sm_cache = NULL; + +// ---------------------------------------------------------------------------- +// wxArtProvider ctors/dtor +// ---------------------------------------------------------------------------- + +wxArtProvider::~wxArtProvider() +{ + Remove(this); +} + +// ---------------------------------------------------------------------------- +// wxArtProvider operations on provider stack +// ---------------------------------------------------------------------------- + +/*static*/ void wxArtProvider::CommonAddingProvider() +{ + if ( !sm_providers ) + { + sm_providers = new wxArtProvidersList; + sm_cache = new wxArtProviderCache; + } + + sm_cache->Clear(); +} + +/*static*/ void wxArtProvider::Push(wxArtProvider *provider) +{ + CommonAddingProvider(); + sm_providers->Insert(provider); +} + +/*static*/ void wxArtProvider::Insert(wxArtProvider *provider) +{ + CommonAddingProvider(); + sm_providers->Append(provider); +} + +/*static*/ bool wxArtProvider::Pop() +{ + wxCHECK_MSG( sm_providers, false, _T("no wxArtProvider exists") ); + wxCHECK_MSG( !sm_providers->empty(), false, _T("wxArtProviders stack is empty") ); + + delete sm_providers->GetFirst()->GetData(); + sm_cache->Clear(); + return true; +} + +/*static*/ bool wxArtProvider::Remove(wxArtProvider *provider) +{ + wxCHECK_MSG( sm_providers, false, _T("no wxArtProvider exists") ); + + if ( sm_providers->DeleteObject(provider) ) + { + sm_cache->Clear(); + return true; + } + + return false; +} + +/*static*/ bool wxArtProvider::Delete(wxArtProvider *provider) +{ + // provider will remove itself from the stack in its dtor + delete provider; + + return true; +} + +/*static*/ void wxArtProvider::CleanUpProviders() +{ + if ( sm_providers ) + { + while ( !sm_providers->empty() ) + delete *sm_providers->begin(); + + delete sm_providers; + sm_providers = NULL; + + delete sm_cache; + sm_cache = NULL; + } +} + +// ---------------------------------------------------------------------------- +// wxArtProvider: retrieving bitmaps/icons +// ---------------------------------------------------------------------------- + +/*static*/ wxBitmap wxArtProvider::GetBitmap(const wxArtID& id, + const wxArtClient& client, + const wxSize& size) +{ + // safety-check against writing client,id,size instead of id,client,size: + wxASSERT_MSG( client.Last() == _T('C'), _T("invalid 'client' parameter") ); + + wxCHECK_MSG( sm_providers, wxNullBitmap, _T("no wxArtProvider exists") ); + + wxString hashId = wxArtProviderCache::ConstructHashID(id, client, size); + + wxBitmap bmp; + if ( !sm_cache->GetBitmap(hashId, &bmp) ) + { + for (wxArtProvidersList::compatibility_iterator node = sm_providers->GetFirst(); + node; node = node->GetNext()) + { + bmp = node->GetData()->CreateBitmap(id, client, size); + if ( bmp.Ok() ) + { +#if wxUSE_IMAGE && (!defined(__WXMSW__) || wxUSE_WXDIB) + if ( size != wxDefaultSize && + (bmp.GetWidth() != size.x || bmp.GetHeight() != size.y) ) + { + wxImage img = bmp.ConvertToImage(); + img.Rescale(size.x, size.y); + bmp = wxBitmap(img); + } +#endif + break; + } + } + + sm_cache->PutBitmap(hashId, bmp); + } + + return bmp; +} + +/*static*/ wxIcon wxArtProvider::GetIcon(const wxArtID& id, + const wxArtClient& client, + const wxSize& size) +{ + wxCHECK_MSG( sm_providers, wxNullIcon, _T("no wxArtProvider exists") ); + + wxBitmap bmp = GetBitmap(id, client, size); + if ( !bmp.Ok() ) + return wxNullIcon; + + wxIcon icon; + icon.CopyFromBitmap(bmp); + return icon; +} + +#if defined(__WXGTK20__) && !defined(__WXUNIVERSAL__) + #include "wx/gtk/private.h" + extern GtkIconSize wxArtClientToIconSize(const wxArtClient& client); +#endif // defined(__WXGTK20__) && !defined(__WXUNIVERSAL__) + +/*static*/ wxSize wxArtProvider::GetSizeHint(const wxArtClient& client, + bool platform_dependent) +{ + if (!platform_dependent) + { + wxArtProvidersList::compatibility_iterator node = sm_providers->GetFirst(); + if (node) + return node->GetData()->DoGetSizeHint(client); + } + + // else return platform dependent size + +#if defined(__WXGTK20__) && !defined(__WXUNIVERSAL__) + // Gtk has specific sizes for each client, see artgtk.cpp + GtkIconSize gtk_size = wxArtClientToIconSize(client); + // no size hints for this client + if (gtk_size == GTK_ICON_SIZE_INVALID) + return wxDefaultSize; + gint width, height; + gtk_icon_size_lookup( gtk_size, &width, &height); + return wxSize(width, height); +#else // !GTK+ 2 + // NB: These size hints may have to be adjusted per platform + if (client == wxART_TOOLBAR) + return wxSize(16, 15); + else if (client == wxART_MENU) + return wxSize(16, 15); + else if (client == wxART_FRAME_ICON) + return wxSize(16, 15); + else if (client == wxART_CMN_DIALOG || client == wxART_MESSAGE_BOX) + return wxSize(32, 32); + else if (client == wxART_HELP_BROWSER) + return wxSize(16, 15); + else if (client == wxART_BUTTON) + return wxSize(16, 15); + else // wxART_OTHER or perhaps a user's client, no specified size + return wxDefaultSize; +#endif // GTK+ 2/else +} + +// ---------------------------------------------------------------------------- +// deprecated wxArtProvider methods +// ---------------------------------------------------------------------------- + +#if WXWIN_COMPATIBILITY_2_6 + +/* static */ void wxArtProvider::PushProvider(wxArtProvider *provider) +{ + Push(provider); +} + +/* static */ void wxArtProvider::InsertProvider(wxArtProvider *provider) +{ + Insert(provider); +} + +/* static */ bool wxArtProvider::PopProvider() +{ + return Pop(); +} + +/* static */ bool wxArtProvider::RemoveProvider(wxArtProvider *provider) +{ + // RemoveProvider() used to delete the provider being removed so this is + // not a typo, we must call Delete() and not Remove() here + return Delete(provider); +} + +#endif // WXWIN_COMPATIBILITY_2_6 + +// ============================================================================ +// wxArtProviderModule +// ============================================================================ + +class wxArtProviderModule: public wxModule +{ +public: + bool OnInit() + { + wxArtProvider::InitStdProvider(); + wxArtProvider::InitNativeProvider(); + return true; + } + void OnExit() + { + wxArtProvider::CleanUpProviders(); + } + + DECLARE_DYNAMIC_CLASS(wxArtProviderModule) +}; + +IMPLEMENT_DYNAMIC_CLASS(wxArtProviderModule, wxModule) diff --git a/Externals/wxWidgets/src/common/artstd.cpp b/Externals/wxWidgets/src/common/artstd.cpp index 6075ae8f23..c50aae5f67 100644 --- a/Externals/wxWidgets/src/common/artstd.cpp +++ b/Externals/wxWidgets/src/common/artstd.cpp @@ -1,267 +1,267 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/artstd.cpp -// Purpose: stock wxArtProvider instance with default wxWin art -// Author: Vaclav Slavik -// Modified by: -// Created: 18/03/2002 -// RCS-ID: $Id: artstd.cpp 52561 2008-03-16 00:36:37Z VS $ -// Copyright: (c) Vaclav Slavik -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// --------------------------------------------------------------------------- -// headers -// --------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#if defined(__BORLANDC__) - #pragma hdrstop -#endif - -#ifndef WX_PRECOMP - #include "wx/image.h" -#endif - -#include "wx/artprov.h" - -// ---------------------------------------------------------------------------- -// wxDefaultArtProvider -// ---------------------------------------------------------------------------- - -class wxDefaultArtProvider : public wxArtProvider -{ -protected: - virtual wxBitmap CreateBitmap(const wxArtID& id, const wxArtClient& client, - const wxSize& size); -}; - -// ---------------------------------------------------------------------------- -// helper macros -// ---------------------------------------------------------------------------- - -// Standard macro for getting a resource from XPM file: -#define ART(artId, xpmRc) \ - if ( id == artId ) return wxBitmap(xpmRc##_xpm); - -// There are two ways of getting the standard icon: either via XPMs or via -// wxIcon ctor. This depends on the platform: -#if defined(__WXUNIVERSAL__) - #define CREATE_STD_ICON(iconId, xpmRc) return wxNullBitmap; -#elif defined(__WXGTK__) || defined(__WXMOTIF__) - #define CREATE_STD_ICON(iconId, xpmRc) return wxBitmap(xpmRc##_xpm); -#else - #define CREATE_STD_ICON(iconId, xpmRc) \ - { \ - wxIcon icon(_T(iconId)); \ - wxBitmap bmp; \ - bmp.CopyFromIcon(icon); \ - return bmp; \ - } -#endif - -// Macro used in CreateBitmap to get wxICON_FOO icons: -#define ART_MSGBOX(artId, iconId, xpmRc) \ - if ( id == artId ) \ - { \ - CREATE_STD_ICON(#iconId, xpmRc) \ - } - -// ---------------------------------------------------------------------------- -// wxArtProvider::InitStdProvider -// ---------------------------------------------------------------------------- - -/*static*/ void wxArtProvider::InitStdProvider() -{ - wxArtProvider::Push(new wxDefaultArtProvider); -} - -#if !defined(__WXGTK20__) || defined(__WXUNIVERSAL__) -/*static*/ void wxArtProvider::InitNativeProvider() -{ -} -#endif - - -// ---------------------------------------------------------------------------- -// XPMs with the art -// ---------------------------------------------------------------------------- - - -#if defined(__WXGTK__) - #include "../../art/gtk/info.xpm" - #include "../../art/gtk/error.xpm" - #include "../../art/gtk/warning.xpm" - #include "../../art/gtk/question.xpm" -#elif defined(__WXMOTIF__) - #include "../../art/motif/info.xpm" - #include "../../art/motif/error.xpm" - #include "../../art/motif/warning.xpm" - #include "../../art/motif/question.xpm" -#endif - -#if wxUSE_HTML - #include "../../art/htmsidep.xpm" - #include "../../art/htmoptns.xpm" - #include "../../art/htmbook.xpm" - #include "../../art/htmfoldr.xpm" - #include "../../art/htmpage.xpm" -#endif // wxUSE_HTML - -#include "../../art/missimg.xpm" -#include "../../art/addbookm.xpm" -#include "../../art/delbookm.xpm" -#include "../../art/back.xpm" -#include "../../art/forward.xpm" -#include "../../art/up.xpm" -#include "../../art/down.xpm" -#include "../../art/toparent.xpm" -#include "../../art/fileopen.xpm" -#include "../../art/print.xpm" -#include "../../art/helpicon.xpm" -#include "../../art/tipicon.xpm" -#include "../../art/home.xpm" -#include "../../art/repview.xpm" -#include "../../art/listview.xpm" -#include "../../art/new_dir.xpm" -#include "../../art/harddisk.xpm" -#include "../../art/cdrom.xpm" -#include "../../art/floppy.xpm" -#include "../../art/removable.xpm" -#include "../../art/folder.xpm" -#include "../../art/folder_open.xpm" -#include "../../art/dir_up.xpm" -#include "../../art/exefile.xpm" -#include "../../art/deffile.xpm" -#include "../../art/tick.xpm" -#include "../../art/cross.xpm" - -#include "../../art/filesave.xpm" -#include "../../art/filesaveas.xpm" -#include "../../art/copy.xpm" -#include "../../art/cut.xpm" -#include "../../art/paste.xpm" -#include "../../art/delete.xpm" -#include "../../art/new.xpm" -#include "../../art/undo.xpm" -#include "../../art/redo.xpm" -#include "../../art/quit.xpm" -#include "../../art/find.xpm" -#include "../../art/findrepl.xpm" - - - -wxBitmap wxDefaultArtProvider_CreateBitmap(const wxArtID& id) -{ - // wxMessageBox icons: - ART_MSGBOX(wxART_ERROR, wxICON_ERROR, error) - ART_MSGBOX(wxART_INFORMATION, wxICON_INFORMATION, info) - ART_MSGBOX(wxART_WARNING, wxICON_WARNING, warning) - ART_MSGBOX(wxART_QUESTION, wxICON_QUESTION, question) - - // standard icons: -#if wxUSE_HTML - ART(wxART_HELP_SIDE_PANEL, htmsidep) - ART(wxART_HELP_SETTINGS, htmoptns) - ART(wxART_HELP_BOOK, htmbook) - ART(wxART_HELP_FOLDER, htmfoldr) - ART(wxART_HELP_PAGE, htmpage) -#endif // wxUSE_HTML - ART(wxART_MISSING_IMAGE, missimg) - ART(wxART_ADD_BOOKMARK, addbookm) - ART(wxART_DEL_BOOKMARK, delbookm) - ART(wxART_GO_BACK, back) - ART(wxART_GO_FORWARD, forward) - ART(wxART_GO_UP, up) - ART(wxART_GO_DOWN, down) - ART(wxART_GO_TO_PARENT, toparent) - ART(wxART_GO_HOME, home) - ART(wxART_FILE_OPEN, fileopen) - ART(wxART_PRINT, print) - ART(wxART_HELP, helpicon) - ART(wxART_TIP, tipicon) - ART(wxART_REPORT_VIEW, repview) - ART(wxART_LIST_VIEW, listview) - ART(wxART_NEW_DIR, new_dir) - ART(wxART_HARDDISK, harddisk) - ART(wxART_FLOPPY, floppy) - ART(wxART_CDROM, cdrom) - ART(wxART_REMOVABLE, removable) - ART(wxART_FOLDER, folder) - ART(wxART_FOLDER_OPEN, folder_open) - ART(wxART_GO_DIR_UP, dir_up) - ART(wxART_EXECUTABLE_FILE, exefile) - ART(wxART_NORMAL_FILE, deffile) - ART(wxART_TICK_MARK, tick) - ART(wxART_CROSS_MARK, cross) - - ART(wxART_FILE_SAVE, filesave) - ART(wxART_FILE_SAVE_AS, filesaveas) - ART(wxART_COPY, copy) - ART(wxART_CUT, cut) - ART(wxART_PASTE, paste) - ART(wxART_DELETE, delete) - ART(wxART_UNDO, undo) - ART(wxART_REDO, redo) - ART(wxART_QUIT, quit) - ART(wxART_FIND, find) - ART(wxART_FIND_AND_REPLACE, findrepl) - ART(wxART_NEW, new) - - - return wxNullBitmap; -} - -// ---------------------------------------------------------------------------- -// CreateBitmap routine -// ---------------------------------------------------------------------------- - -wxBitmap wxDefaultArtProvider::CreateBitmap(const wxArtID& id, - const wxArtClient& client, - const wxSize& reqSize) -{ - wxBitmap bmp = wxDefaultArtProvider_CreateBitmap(id); - -#if wxUSE_IMAGE && (!defined(__WXMSW__) || wxUSE_WXDIB) - if (bmp.Ok()) - { - // fit into transparent image with desired size hint from the client - if (reqSize == wxDefaultSize) - { - // find out if there is a desired size for this client - wxSize bestSize = GetSizeHint(client); - if (bestSize != wxDefaultSize) - { - int bmp_w = bmp.GetWidth(); - int bmp_h = bmp.GetHeight(); - - if ((bmp_h < bestSize.x) && (bmp_w < bestSize.y)) - { - // the caller wants default size, which is larger than - // the image we have; to avoid degrading it visually by - // scaling it up, paste it into transparent image instead: - wxPoint offset((bestSize.x - bmp_w)/2, (bestSize.y - bmp_h)/2); - wxImage img = bmp.ConvertToImage(); - img.Resize(bestSize, offset); - bmp = wxBitmap(img); - } - else // scale (down or mixed, but not up) - { - wxImage img = bmp.ConvertToImage(); - bmp = wxBitmap - ( - img.Scale(bestSize.x, bestSize.y, - wxIMAGE_QUALITY_HIGH) - ); - } - } - } - } -#else - wxUnusedVar(client); - wxUnusedVar(reqSize); -#endif // wxUSE_IMAGE - - return bmp; -} +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/artstd.cpp +// Purpose: stock wxArtProvider instance with default wxWin art +// Author: Vaclav Slavik +// Modified by: +// Created: 18/03/2002 +// RCS-ID: $Id: artstd.cpp 52561 2008-03-16 00:36:37Z VS $ +// Copyright: (c) Vaclav Slavik +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// --------------------------------------------------------------------------- +// headers +// --------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#if defined(__BORLANDC__) + #pragma hdrstop +#endif + +#ifndef WX_PRECOMP + #include "wx/image.h" +#endif + +#include "wx/artprov.h" + +// ---------------------------------------------------------------------------- +// wxDefaultArtProvider +// ---------------------------------------------------------------------------- + +class wxDefaultArtProvider : public wxArtProvider +{ +protected: + virtual wxBitmap CreateBitmap(const wxArtID& id, const wxArtClient& client, + const wxSize& size); +}; + +// ---------------------------------------------------------------------------- +// helper macros +// ---------------------------------------------------------------------------- + +// Standard macro for getting a resource from XPM file: +#define ART(artId, xpmRc) \ + if ( id == artId ) return wxBitmap(xpmRc##_xpm); + +// There are two ways of getting the standard icon: either via XPMs or via +// wxIcon ctor. This depends on the platform: +#if defined(__WXUNIVERSAL__) + #define CREATE_STD_ICON(iconId, xpmRc) return wxNullBitmap; +#elif defined(__WXGTK__) || defined(__WXMOTIF__) + #define CREATE_STD_ICON(iconId, xpmRc) return wxBitmap(xpmRc##_xpm); +#else + #define CREATE_STD_ICON(iconId, xpmRc) \ + { \ + wxIcon icon(_T(iconId)); \ + wxBitmap bmp; \ + bmp.CopyFromIcon(icon); \ + return bmp; \ + } +#endif + +// Macro used in CreateBitmap to get wxICON_FOO icons: +#define ART_MSGBOX(artId, iconId, xpmRc) \ + if ( id == artId ) \ + { \ + CREATE_STD_ICON(#iconId, xpmRc) \ + } + +// ---------------------------------------------------------------------------- +// wxArtProvider::InitStdProvider +// ---------------------------------------------------------------------------- + +/*static*/ void wxArtProvider::InitStdProvider() +{ + wxArtProvider::Push(new wxDefaultArtProvider); +} + +#if !defined(__WXGTK20__) || defined(__WXUNIVERSAL__) +/*static*/ void wxArtProvider::InitNativeProvider() +{ +} +#endif + + +// ---------------------------------------------------------------------------- +// XPMs with the art +// ---------------------------------------------------------------------------- + + +#if defined(__WXGTK__) + #include "../../art/gtk/info.xpm" + #include "../../art/gtk/error.xpm" + #include "../../art/gtk/warning.xpm" + #include "../../art/gtk/question.xpm" +#elif defined(__WXMOTIF__) + #include "../../art/motif/info.xpm" + #include "../../art/motif/error.xpm" + #include "../../art/motif/warning.xpm" + #include "../../art/motif/question.xpm" +#endif + +#if wxUSE_HTML + #include "../../art/htmsidep.xpm" + #include "../../art/htmoptns.xpm" + #include "../../art/htmbook.xpm" + #include "../../art/htmfoldr.xpm" + #include "../../art/htmpage.xpm" +#endif // wxUSE_HTML + +#include "../../art/missimg.xpm" +#include "../../art/addbookm.xpm" +#include "../../art/delbookm.xpm" +#include "../../art/back.xpm" +#include "../../art/forward.xpm" +#include "../../art/up.xpm" +#include "../../art/down.xpm" +#include "../../art/toparent.xpm" +#include "../../art/fileopen.xpm" +#include "../../art/print.xpm" +#include "../../art/helpicon.xpm" +#include "../../art/tipicon.xpm" +#include "../../art/home.xpm" +#include "../../art/repview.xpm" +#include "../../art/listview.xpm" +#include "../../art/new_dir.xpm" +#include "../../art/harddisk.xpm" +#include "../../art/cdrom.xpm" +#include "../../art/floppy.xpm" +#include "../../art/removable.xpm" +#include "../../art/folder.xpm" +#include "../../art/folder_open.xpm" +#include "../../art/dir_up.xpm" +#include "../../art/exefile.xpm" +#include "../../art/deffile.xpm" +#include "../../art/tick.xpm" +#include "../../art/cross.xpm" + +#include "../../art/filesave.xpm" +#include "../../art/filesaveas.xpm" +#include "../../art/copy.xpm" +#include "../../art/cut.xpm" +#include "../../art/paste.xpm" +#include "../../art/delete.xpm" +#include "../../art/new.xpm" +#include "../../art/undo.xpm" +#include "../../art/redo.xpm" +#include "../../art/quit.xpm" +#include "../../art/find.xpm" +#include "../../art/findrepl.xpm" + + + +wxBitmap wxDefaultArtProvider_CreateBitmap(const wxArtID& id) +{ + // wxMessageBox icons: + ART_MSGBOX(wxART_ERROR, wxICON_ERROR, error) + ART_MSGBOX(wxART_INFORMATION, wxICON_INFORMATION, info) + ART_MSGBOX(wxART_WARNING, wxICON_WARNING, warning) + ART_MSGBOX(wxART_QUESTION, wxICON_QUESTION, question) + + // standard icons: +#if wxUSE_HTML + ART(wxART_HELP_SIDE_PANEL, htmsidep) + ART(wxART_HELP_SETTINGS, htmoptns) + ART(wxART_HELP_BOOK, htmbook) + ART(wxART_HELP_FOLDER, htmfoldr) + ART(wxART_HELP_PAGE, htmpage) +#endif // wxUSE_HTML + ART(wxART_MISSING_IMAGE, missimg) + ART(wxART_ADD_BOOKMARK, addbookm) + ART(wxART_DEL_BOOKMARK, delbookm) + ART(wxART_GO_BACK, back) + ART(wxART_GO_FORWARD, forward) + ART(wxART_GO_UP, up) + ART(wxART_GO_DOWN, down) + ART(wxART_GO_TO_PARENT, toparent) + ART(wxART_GO_HOME, home) + ART(wxART_FILE_OPEN, fileopen) + ART(wxART_PRINT, print) + ART(wxART_HELP, helpicon) + ART(wxART_TIP, tipicon) + ART(wxART_REPORT_VIEW, repview) + ART(wxART_LIST_VIEW, listview) + ART(wxART_NEW_DIR, new_dir) + ART(wxART_HARDDISK, harddisk) + ART(wxART_FLOPPY, floppy) + ART(wxART_CDROM, cdrom) + ART(wxART_REMOVABLE, removable) + ART(wxART_FOLDER, folder) + ART(wxART_FOLDER_OPEN, folder_open) + ART(wxART_GO_DIR_UP, dir_up) + ART(wxART_EXECUTABLE_FILE, exefile) + ART(wxART_NORMAL_FILE, deffile) + ART(wxART_TICK_MARK, tick) + ART(wxART_CROSS_MARK, cross) + + ART(wxART_FILE_SAVE, filesave) + ART(wxART_FILE_SAVE_AS, filesaveas) + ART(wxART_COPY, copy) + ART(wxART_CUT, cut) + ART(wxART_PASTE, paste) + ART(wxART_DELETE, delete) + ART(wxART_UNDO, undo) + ART(wxART_REDO, redo) + ART(wxART_QUIT, quit) + ART(wxART_FIND, find) + ART(wxART_FIND_AND_REPLACE, findrepl) + ART(wxART_NEW, new) + + + return wxNullBitmap; +} + +// ---------------------------------------------------------------------------- +// CreateBitmap routine +// ---------------------------------------------------------------------------- + +wxBitmap wxDefaultArtProvider::CreateBitmap(const wxArtID& id, + const wxArtClient& client, + const wxSize& reqSize) +{ + wxBitmap bmp = wxDefaultArtProvider_CreateBitmap(id); + +#if wxUSE_IMAGE && (!defined(__WXMSW__) || wxUSE_WXDIB) + if (bmp.Ok()) + { + // fit into transparent image with desired size hint from the client + if (reqSize == wxDefaultSize) + { + // find out if there is a desired size for this client + wxSize bestSize = GetSizeHint(client); + if (bestSize != wxDefaultSize) + { + int bmp_w = bmp.GetWidth(); + int bmp_h = bmp.GetHeight(); + + if ((bmp_h < bestSize.x) && (bmp_w < bestSize.y)) + { + // the caller wants default size, which is larger than + // the image we have; to avoid degrading it visually by + // scaling it up, paste it into transparent image instead: + wxPoint offset((bestSize.x - bmp_w)/2, (bestSize.y - bmp_h)/2); + wxImage img = bmp.ConvertToImage(); + img.Resize(bestSize, offset); + bmp = wxBitmap(img); + } + else // scale (down or mixed, but not up) + { + wxImage img = bmp.ConvertToImage(); + bmp = wxBitmap + ( + img.Scale(bestSize.x, bestSize.y, + wxIMAGE_QUALITY_HIGH) + ); + } + } + } + } +#else + wxUnusedVar(client); + wxUnusedVar(reqSize); +#endif // wxUSE_IMAGE + + return bmp; +} diff --git a/Externals/wxWidgets/src/common/bmpbase.cpp b/Externals/wxWidgets/src/common/bmpbase.cpp index a1d7c60aa2..0c7edd3ac2 100644 --- a/Externals/wxWidgets/src/common/bmpbase.cpp +++ b/Externals/wxWidgets/src/common/bmpbase.cpp @@ -1,211 +1,211 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/bmpbase.cpp -// Purpose: wxBitmapBase -// Author: VaclavSlavik -// Created: 2001/04/11 -// RCS-ID: $Id: bmpbase.cpp 42752 2006-10-30 19:26:48Z VZ $ -// Copyright: (c) 2001, Vaclav Slavik -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#include "wx/bitmap.h" - -#ifndef WX_PRECOMP - #include "wx/colour.h" - #include "wx/icon.h" - #include "wx/image.h" -#endif // WX_PRECOMP - -// ---------------------------------------------------------------------------- -// wxVariant support -// ---------------------------------------------------------------------------- - -#if wxUSE_VARIANT -IMPLEMENT_VARIANT_OBJECT_EXPORTED_SHALLOWCMP(wxBitmap,WXDLLEXPORT) -IMPLEMENT_VARIANT_OBJECT_EXPORTED_SHALLOWCMP(wxIcon,WXDLLEXPORT) -#endif - -// ---------------------------------------------------------------------------- -// wxBitmapBase -// ---------------------------------------------------------------------------- - -#if wxUSE_BITMAP_BASE - -#ifndef WX_PRECOMP - #include "wx/log.h" - #include "wx/utils.h" - #include "wx/palette.h" - #include "wx/module.h" -#endif // WX_PRECOMP - - -IMPLEMENT_ABSTRACT_CLASS(wxBitmapBase, wxGDIObject) -IMPLEMENT_ABSTRACT_CLASS(wxBitmapHandlerBase,wxObject) - -wxList wxBitmapBase::sm_handlers; - -void wxBitmapBase::AddHandler(wxBitmapHandlerBase *handler) -{ - sm_handlers.Append(handler); -} - -void wxBitmapBase::InsertHandler(wxBitmapHandlerBase *handler) -{ - sm_handlers.Insert(handler); -} - -bool wxBitmapBase::RemoveHandler(const wxString& name) -{ - wxBitmapHandler *handler = FindHandler(name); - if ( handler ) - { - sm_handlers.DeleteObject(handler); - return true; - } - else - return false; -} - -wxBitmapHandler *wxBitmapBase::FindHandler(const wxString& name) -{ - wxList::compatibility_iterator node = sm_handlers.GetFirst(); - while ( node ) - { - wxBitmapHandler *handler = (wxBitmapHandler *)node->GetData(); - if ( handler->GetName() == name ) - return handler; - node = node->GetNext(); - } - return NULL; -} - -wxBitmapHandler *wxBitmapBase::FindHandler(const wxString& extension, wxBitmapType bitmapType) -{ - wxList::compatibility_iterator node = sm_handlers.GetFirst(); - while ( node ) - { - wxBitmapHandler *handler = (wxBitmapHandler *)node->GetData(); - if ( handler->GetExtension() == extension && - (bitmapType == wxBITMAP_TYPE_ANY || handler->GetType() == bitmapType) ) - return handler; - node = node->GetNext(); - } - return NULL; -} - -wxBitmapHandler *wxBitmapBase::FindHandler(wxBitmapType bitmapType) -{ - wxList::compatibility_iterator node = sm_handlers.GetFirst(); - while ( node ) - { - wxBitmapHandler *handler = (wxBitmapHandler *)node->GetData(); - if (handler->GetType() == bitmapType) - return handler; - node = node->GetNext(); - } - return NULL; -} - -void wxBitmapBase::CleanUpHandlers() -{ - wxList::compatibility_iterator node = sm_handlers.GetFirst(); - while ( node ) - { - wxBitmapHandler *handler = (wxBitmapHandler *)node->GetData(); - wxList::compatibility_iterator next = node->GetNext(); - delete handler; - sm_handlers.Erase(node); - node = next; - } -} - -bool wxBitmapHandlerBase::Create(wxBitmap*, const void*, long, int, int, int) -{ - return false; -} - -bool wxBitmapHandlerBase::LoadFile(wxBitmap*, const wxString&, long, int, int) -{ - return false; -} - -bool wxBitmapHandlerBase::SaveFile(const wxBitmap*, const wxString&, int, const wxPalette*) -{ - return false; -} - -class wxBitmapBaseModule: public wxModule -{ -DECLARE_DYNAMIC_CLASS(wxBitmapBaseModule) -public: - wxBitmapBaseModule() {} - bool OnInit() { wxBitmap::InitStandardHandlers(); return true; } - void OnExit() { wxBitmap::CleanUpHandlers(); } -}; - -IMPLEMENT_DYNAMIC_CLASS(wxBitmapBaseModule, wxModule) - -#endif // wxUSE_BITMAP_BASE - -// ---------------------------------------------------------------------------- -// wxBitmap common -// ---------------------------------------------------------------------------- - -#if !(defined(__WXGTK__) || defined(__WXMOTIF__) || defined(__WXX11__)) - -wxBitmap::wxBitmap(const char* const* bits) -{ - wxCHECK2_MSG(bits != NULL, return, wxT("invalid bitmap data")); - -#if wxUSE_IMAGE && wxUSE_XPM - wxImage image(bits); - wxCHECK2_MSG(image.Ok(), return, wxT("invalid bitmap data")); - - *this = wxBitmap(image); -#else - wxFAIL_MSG(_T("creating bitmaps from XPMs not supported")); -#endif // wxUSE_IMAGE && wxUSE_XPM -} -#endif // !(defined(__WXGTK__) || defined(__WXMOTIF__) || defined(__WXX11__)) - -// ---------------------------------------------------------------------------- -// wxMaskBase -// ---------------------------------------------------------------------------- - -bool wxMaskBase::Create(const wxBitmap& bitmap, const wxColour& colour) -{ - FreeData(); - - return InitFromColour(bitmap, colour); -} - -#if wxUSE_PALETTE - -bool wxMaskBase::Create(const wxBitmap& bitmap, int paletteIndex) -{ - wxPalette *pal = bitmap.GetPalette(); - - wxCHECK_MSG( pal, false, - wxT("Cannot create mask from palette index of a bitmap without palette") ); - - unsigned char r,g,b; - pal->GetRGB(paletteIndex, &r, &g, &b); - - return Create(bitmap, wxColour(r, g, b)); -} - -#endif // wxUSE_PALETTE - -bool wxMaskBase::Create(const wxBitmap& bitmap) -{ - FreeData(); - - return InitFromMonoBitmap(bitmap); -} +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/bmpbase.cpp +// Purpose: wxBitmapBase +// Author: VaclavSlavik +// Created: 2001/04/11 +// RCS-ID: $Id: bmpbase.cpp 42752 2006-10-30 19:26:48Z VZ $ +// Copyright: (c) 2001, Vaclav Slavik +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#include "wx/bitmap.h" + +#ifndef WX_PRECOMP + #include "wx/colour.h" + #include "wx/icon.h" + #include "wx/image.h" +#endif // WX_PRECOMP + +// ---------------------------------------------------------------------------- +// wxVariant support +// ---------------------------------------------------------------------------- + +#if wxUSE_VARIANT +IMPLEMENT_VARIANT_OBJECT_EXPORTED_SHALLOWCMP(wxBitmap,WXDLLEXPORT) +IMPLEMENT_VARIANT_OBJECT_EXPORTED_SHALLOWCMP(wxIcon,WXDLLEXPORT) +#endif + +// ---------------------------------------------------------------------------- +// wxBitmapBase +// ---------------------------------------------------------------------------- + +#if wxUSE_BITMAP_BASE + +#ifndef WX_PRECOMP + #include "wx/log.h" + #include "wx/utils.h" + #include "wx/palette.h" + #include "wx/module.h" +#endif // WX_PRECOMP + + +IMPLEMENT_ABSTRACT_CLASS(wxBitmapBase, wxGDIObject) +IMPLEMENT_ABSTRACT_CLASS(wxBitmapHandlerBase,wxObject) + +wxList wxBitmapBase::sm_handlers; + +void wxBitmapBase::AddHandler(wxBitmapHandlerBase *handler) +{ + sm_handlers.Append(handler); +} + +void wxBitmapBase::InsertHandler(wxBitmapHandlerBase *handler) +{ + sm_handlers.Insert(handler); +} + +bool wxBitmapBase::RemoveHandler(const wxString& name) +{ + wxBitmapHandler *handler = FindHandler(name); + if ( handler ) + { + sm_handlers.DeleteObject(handler); + return true; + } + else + return false; +} + +wxBitmapHandler *wxBitmapBase::FindHandler(const wxString& name) +{ + wxList::compatibility_iterator node = sm_handlers.GetFirst(); + while ( node ) + { + wxBitmapHandler *handler = (wxBitmapHandler *)node->GetData(); + if ( handler->GetName() == name ) + return handler; + node = node->GetNext(); + } + return NULL; +} + +wxBitmapHandler *wxBitmapBase::FindHandler(const wxString& extension, wxBitmapType bitmapType) +{ + wxList::compatibility_iterator node = sm_handlers.GetFirst(); + while ( node ) + { + wxBitmapHandler *handler = (wxBitmapHandler *)node->GetData(); + if ( handler->GetExtension() == extension && + (bitmapType == wxBITMAP_TYPE_ANY || handler->GetType() == bitmapType) ) + return handler; + node = node->GetNext(); + } + return NULL; +} + +wxBitmapHandler *wxBitmapBase::FindHandler(wxBitmapType bitmapType) +{ + wxList::compatibility_iterator node = sm_handlers.GetFirst(); + while ( node ) + { + wxBitmapHandler *handler = (wxBitmapHandler *)node->GetData(); + if (handler->GetType() == bitmapType) + return handler; + node = node->GetNext(); + } + return NULL; +} + +void wxBitmapBase::CleanUpHandlers() +{ + wxList::compatibility_iterator node = sm_handlers.GetFirst(); + while ( node ) + { + wxBitmapHandler *handler = (wxBitmapHandler *)node->GetData(); + wxList::compatibility_iterator next = node->GetNext(); + delete handler; + sm_handlers.Erase(node); + node = next; + } +} + +bool wxBitmapHandlerBase::Create(wxBitmap*, const void*, long, int, int, int) +{ + return false; +} + +bool wxBitmapHandlerBase::LoadFile(wxBitmap*, const wxString&, long, int, int) +{ + return false; +} + +bool wxBitmapHandlerBase::SaveFile(const wxBitmap*, const wxString&, int, const wxPalette*) +{ + return false; +} + +class wxBitmapBaseModule: public wxModule +{ +DECLARE_DYNAMIC_CLASS(wxBitmapBaseModule) +public: + wxBitmapBaseModule() {} + bool OnInit() { wxBitmap::InitStandardHandlers(); return true; } + void OnExit() { wxBitmap::CleanUpHandlers(); } +}; + +IMPLEMENT_DYNAMIC_CLASS(wxBitmapBaseModule, wxModule) + +#endif // wxUSE_BITMAP_BASE + +// ---------------------------------------------------------------------------- +// wxBitmap common +// ---------------------------------------------------------------------------- + +#if !(defined(__WXGTK__) || defined(__WXMOTIF__) || defined(__WXX11__)) + +wxBitmap::wxBitmap(const char* const* bits) +{ + wxCHECK2_MSG(bits != NULL, return, wxT("invalid bitmap data")); + +#if wxUSE_IMAGE && wxUSE_XPM + wxImage image(bits); + wxCHECK2_MSG(image.Ok(), return, wxT("invalid bitmap data")); + + *this = wxBitmap(image); +#else + wxFAIL_MSG(_T("creating bitmaps from XPMs not supported")); +#endif // wxUSE_IMAGE && wxUSE_XPM +} +#endif // !(defined(__WXGTK__) || defined(__WXMOTIF__) || defined(__WXX11__)) + +// ---------------------------------------------------------------------------- +// wxMaskBase +// ---------------------------------------------------------------------------- + +bool wxMaskBase::Create(const wxBitmap& bitmap, const wxColour& colour) +{ + FreeData(); + + return InitFromColour(bitmap, colour); +} + +#if wxUSE_PALETTE + +bool wxMaskBase::Create(const wxBitmap& bitmap, int paletteIndex) +{ + wxPalette *pal = bitmap.GetPalette(); + + wxCHECK_MSG( pal, false, + wxT("Cannot create mask from palette index of a bitmap without palette") ); + + unsigned char r,g,b; + pal->GetRGB(paletteIndex, &r, &g, &b); + + return Create(bitmap, wxColour(r, g, b)); +} + +#endif // wxUSE_PALETTE + +bool wxMaskBase::Create(const wxBitmap& bitmap) +{ + FreeData(); + + return InitFromMonoBitmap(bitmap); +} diff --git a/Externals/wxWidgets/src/common/bookctrl.cpp b/Externals/wxWidgets/src/common/bookctrl.cpp index a64fc9eade..ca6c2a5900 100644 --- a/Externals/wxWidgets/src/common/bookctrl.cpp +++ b/Externals/wxWidgets/src/common/bookctrl.cpp @@ -1,497 +1,497 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: src/common/bookctrl.cpp -// Purpose: wxBookCtrlBase implementation -// Author: Vadim Zeitlin -// Modified by: -// Created: 19.08.03 -// RCS-ID: $Id: bookctrl.cpp 53783 2008-05-27 14:15:14Z SC $ -// Copyright: (c) 2003 Vadim Zeitlin -// Licence: wxWindows licence -/////////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_BOOKCTRL - -#include "wx/imaglist.h" - -#include "wx/bookctrl.h" - -// ============================================================================ -// implementation -// ============================================================================ - -// ---------------------------------------------------------------------------- -// event table -// ---------------------------------------------------------------------------- - -IMPLEMENT_ABSTRACT_CLASS(wxBookCtrlBase, wxControl) - -BEGIN_EVENT_TABLE(wxBookCtrlBase, wxControl) - EVT_SIZE(wxBookCtrlBase::OnSize) -#if wxUSE_HELP - EVT_HELP(wxID_ANY, wxBookCtrlBase::OnHelp) -#endif // wxUSE_HELP -END_EVENT_TABLE() - -// ---------------------------------------------------------------------------- -// constructors and destructors -// ---------------------------------------------------------------------------- - -void wxBookCtrlBase::Init() -{ - m_bookctrl = NULL; - m_imageList = NULL; - m_ownsImageList = false; - m_fitToCurrentPage = false; - -#if defined(__WXWINCE__) - m_internalBorder = 1; -#else - m_internalBorder = 5; -#endif - - m_controlMargin = 0; - m_controlSizer = NULL; -} - -bool -wxBookCtrlBase::Create(wxWindow *parent, - wxWindowID id, - const wxPoint& pos, - const wxSize& size, - long style, - const wxString& name) -{ - return wxControl::Create - ( - parent, - id, - pos, - size, - style, - wxDefaultValidator, - name - ); -} - -wxBookCtrlBase::~wxBookCtrlBase() -{ - if ( m_ownsImageList ) - { - // may be NULL, ok - delete m_imageList; - } -} - -// ---------------------------------------------------------------------------- -// image list -// ---------------------------------------------------------------------------- - -void wxBookCtrlBase::SetImageList(wxImageList *imageList) -{ - if ( m_ownsImageList ) - { - // may be NULL, ok - delete m_imageList; - - m_ownsImageList = false; - } - - m_imageList = imageList; -} - -void wxBookCtrlBase::AssignImageList(wxImageList* imageList) -{ - SetImageList(imageList); - - m_ownsImageList = true; -} - -// ---------------------------------------------------------------------------- -// geometry -// ---------------------------------------------------------------------------- - -void wxBookCtrlBase::DoInvalidateBestSize() -{ - // notice that it is not necessary to invalidate our own best size - // explicitly if we have m_bookctrl as it will already invalidate the best - // size of its parent when its own size is invalidated and its parent is - // this control - if ( m_bookctrl ) - m_bookctrl->InvalidateBestSize(); - else - wxControl::InvalidateBestSize(); -} - -void wxBookCtrlBase::SetPageSize(const wxSize& size) -{ - SetClientSize(CalcSizeFromPage(size)); -} - -wxSize wxBookCtrlBase::DoGetBestSize() const -{ - wxSize bestSize; - - // iterate over all pages, get the largest width and height - const size_t nCount = m_pages.size(); - for ( size_t nPage = 0; nPage < nCount; nPage++ ) - { - const wxWindow * const pPage = m_pages[nPage]; - if( pPage ) - { - wxSize childBestSize(pPage->GetBestSize()); - - if ( childBestSize.x > bestSize.x ) - bestSize.x = childBestSize.x; - - if ( childBestSize.y > bestSize.y ) - bestSize.y = childBestSize.y; - } - } - - if (m_fitToCurrentPage && GetCurrentPage()) - bestSize = GetCurrentPage()->GetBestSize(); - - // convert display area to window area, adding the size necessary for the - // tabs - wxSize best = CalcSizeFromPage(bestSize); - CacheBestSize(best); - return best; -} - -wxRect wxBookCtrlBase::GetPageRect() const -{ - const wxSize size = GetControllerSize(); - - wxPoint pt; - wxRect rectPage(pt, GetClientSize()); - - switch ( GetWindowStyle() & wxBK_ALIGN_MASK ) - { - default: - wxFAIL_MSG( _T("unexpected alignment") ); - // fall through - - case wxBK_TOP: - rectPage.y = size.y + GetInternalBorder(); - // fall through - - case wxBK_BOTTOM: - rectPage.height -= size.y + GetInternalBorder(); - if (rectPage.height < 0) - rectPage.height = 0; - break; - - case wxBK_LEFT: - rectPage.x = size.x + GetInternalBorder(); - // fall through - - case wxBK_RIGHT: - rectPage.width -= size.x + GetInternalBorder(); - if (rectPage.width < 0) - rectPage.width = 0; - break; - } - - return rectPage; -} - -// Lay out controls -void wxBookCtrlBase::DoSize() -{ - if ( !m_bookctrl ) - { - // we're not fully created yet or OnSize() should be hidden by derived class - return; - } - - if (GetSizer()) - Layout(); - else - { - // resize controller and the page area to fit inside our new size - const wxSize sizeClient( GetClientSize() ), - sizeBorder( m_bookctrl->GetSize() - m_bookctrl->GetClientSize() ), - sizeCtrl( GetControllerSize() ); - - m_bookctrl->SetClientSize( sizeCtrl.x - sizeBorder.x, sizeCtrl.y - sizeBorder.y ); - // if this changes the visibility of the scrollbars the best size changes, relayout in this case - wxSize sizeCtrl2 = GetControllerSize(); - if ( sizeCtrl != sizeCtrl2 ) - { - wxSize sizeBorder2 = m_bookctrl->GetSize() - m_bookctrl->GetClientSize(); - m_bookctrl->SetClientSize( sizeCtrl2.x - sizeBorder2.x, sizeCtrl2.y - sizeBorder2.y ); - } - - const wxSize sizeNew = m_bookctrl->GetSize(); - wxPoint posCtrl; - switch ( GetWindowStyle() & wxBK_ALIGN_MASK ) - { - default: - wxFAIL_MSG( _T("unexpected alignment") ); - // fall through - - case wxBK_TOP: - case wxBK_LEFT: - // posCtrl is already ok - break; - - case wxBK_BOTTOM: - posCtrl.y = sizeClient.y - sizeNew.y; - break; - - case wxBK_RIGHT: - posCtrl.x = sizeClient.x - sizeNew.x; - break; - } - - if ( m_bookctrl->GetPosition() != posCtrl ) - m_bookctrl->Move(posCtrl); - } - - // resize all pages to fit the new control size - const wxRect pageRect = GetPageRect(); - const unsigned pagesCount = m_pages.Count(); - for ( unsigned int i = 0; i < pagesCount; ++i ) - { - wxWindow * const page = m_pages[i]; - if ( !page ) - { - wxASSERT_MSG( AllowNullPage(), - _T("Null page in a control that does not allow null pages?") ); - continue; - } - - page->SetSize(pageRect); - } -} - -void wxBookCtrlBase::OnSize(wxSizeEvent& event) -{ - event.Skip(); - - DoSize(); -} - -wxSize wxBookCtrlBase::GetControllerSize() const -{ - if(!m_bookctrl) - return wxSize(0,0); - - const wxSize sizeClient = GetClientSize(), - sizeBorder = m_bookctrl->GetSize() - m_bookctrl->GetClientSize(), - sizeCtrl = m_bookctrl->GetBestSize() + sizeBorder; - - wxSize size; - - if ( IsVertical() ) - { - size.x = sizeClient.x; - size.y = sizeCtrl.y; - } - else // left/right aligned - { - size.x = sizeCtrl.x; - size.y = sizeClient.y; - } - - return size; -} - -// ---------------------------------------------------------------------------- -// miscellaneous stuff -// ---------------------------------------------------------------------------- - -#if wxUSE_HELP - -void wxBookCtrlBase::OnHelp(wxHelpEvent& event) -{ - // determine where does this even originate from to avoid redirecting it - // back to the page which generated it (resulting in an infinite loop) - - // notice that we have to check in the hard(er) way instead of just testing - // if the event object == this because the book control can have other - // subcontrols inside it (e.g. wxSpinButton in case of a notebook in wxUniv) - wxWindow *source = wxStaticCast(event.GetEventObject(), wxWindow); - while ( source && source != this && source->GetParent() != this ) - { - source = source->GetParent(); - } - - if ( source && m_pages.Index(source) == wxNOT_FOUND ) - { - // this event is for the book control itself, redirect it to the - // corresponding page - wxWindow *page = NULL; - - if ( event.GetOrigin() == wxHelpEvent::Origin_HelpButton ) - { - // show help for the page under the mouse - const int pagePos = HitTest(ScreenToClient(event.GetPosition())); - - if ( pagePos != wxNOT_FOUND) - { - page = GetPage((size_t)pagePos); - } - } - else // event from keyboard or unknown source - { - // otherwise show the current page help - page = GetCurrentPage(); - } - - if ( page ) - { - // change event object to the page to avoid infinite recursion if - // we get this event ourselves if the page doesn't handle it - event.SetEventObject(page); - - if ( page->GetEventHandler()->ProcessEvent(event) ) - { - // don't call event.Skip() - return; - } - } - } - //else: event coming from one of our pages already - - event.Skip(); -} - -#endif // wxUSE_HELP - -// ---------------------------------------------------------------------------- -// pages management -// ---------------------------------------------------------------------------- - -bool -wxBookCtrlBase::InsertPage(size_t nPage, - wxWindow *page, - const wxString& WXUNUSED(text), - bool WXUNUSED(bSelect), - int WXUNUSED(imageId)) -{ - wxCHECK_MSG( page || AllowNullPage(), false, - _T("NULL page in wxBookCtrlBase::InsertPage()") ); - wxCHECK_MSG( nPage <= m_pages.size(), false, - _T("invalid page index in wxBookCtrlBase::InsertPage()") ); - - m_pages.Insert(page, nPage); - if ( page ) - page->SetSize(GetPageRect()); - - DoInvalidateBestSize(); - - return true; -} - -bool wxBookCtrlBase::DeletePage(size_t nPage) -{ - wxWindow *page = DoRemovePage(nPage); - if ( !(page || AllowNullPage()) ) - return false; - - // delete NULL is harmless - delete page; - - return true; -} - -wxWindow *wxBookCtrlBase::DoRemovePage(size_t nPage) -{ - wxCHECK_MSG( nPage < m_pages.size(), NULL, - _T("invalid page index in wxBookCtrlBase::DoRemovePage()") ); - - wxWindow *pageRemoved = m_pages[nPage]; - m_pages.RemoveAt(nPage); - DoInvalidateBestSize(); - - return pageRemoved; -} - -int wxBookCtrlBase::GetNextPage(bool forward) const -{ - int nPage; - - int nMax = GetPageCount(); - if ( nMax-- ) // decrement it to get the last valid index - { - int nSel = GetSelection(); - - // change selection wrapping if it becomes invalid - nPage = forward ? nSel == nMax ? 0 - : nSel + 1 - : nSel == 0 ? nMax - : nSel - 1; - } - else // notebook is empty, no next page - { - nPage = wxNOT_FOUND; - } - - return nPage; -} - -int wxBookCtrlBase::DoSetSelection(size_t n, int flags) -{ - wxCHECK_MSG( n < GetPageCount(), wxNOT_FOUND, - wxT("invalid page index in wxBookCtrlBase::DoSetSelection()") ); - - const int oldSel = GetSelection(); - - if ( n != (size_t)oldSel ) - { - wxBookCtrlBaseEvent *event = CreatePageChangingEvent(); - bool allowed = false; - - if ( flags & SetSelection_SendEvent ) - { - event->SetSelection(n); - event->SetOldSelection(oldSel); - event->SetEventObject(this); - - allowed = !GetEventHandler()->ProcessEvent(*event) || event->IsAllowed(); - } - - if ( !(flags & SetSelection_SendEvent) || allowed) - { - if ( oldSel != wxNOT_FOUND ) - m_pages[oldSel]->Hide(); - - wxWindow *page = m_pages[n]; - page->SetSize(GetPageRect()); - page->Show(); - - // change selection now to ignore the selection change event - UpdateSelectedPage(n); - - if ( flags & SetSelection_SendEvent ) - { - // program allows the page change - MakeChangedEvent(*event); - (void)GetEventHandler()->ProcessEvent(*event); - } - } - - delete event; - } - - return oldSel; -} - - -#endif // wxUSE_BOOKCTRL +/////////////////////////////////////////////////////////////////////////////// +// Name: src/common/bookctrl.cpp +// Purpose: wxBookCtrlBase implementation +// Author: Vadim Zeitlin +// Modified by: +// Created: 19.08.03 +// RCS-ID: $Id: bookctrl.cpp 53783 2008-05-27 14:15:14Z SC $ +// Copyright: (c) 2003 Vadim Zeitlin +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_BOOKCTRL + +#include "wx/imaglist.h" + +#include "wx/bookctrl.h" + +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// event table +// ---------------------------------------------------------------------------- + +IMPLEMENT_ABSTRACT_CLASS(wxBookCtrlBase, wxControl) + +BEGIN_EVENT_TABLE(wxBookCtrlBase, wxControl) + EVT_SIZE(wxBookCtrlBase::OnSize) +#if wxUSE_HELP + EVT_HELP(wxID_ANY, wxBookCtrlBase::OnHelp) +#endif // wxUSE_HELP +END_EVENT_TABLE() + +// ---------------------------------------------------------------------------- +// constructors and destructors +// ---------------------------------------------------------------------------- + +void wxBookCtrlBase::Init() +{ + m_bookctrl = NULL; + m_imageList = NULL; + m_ownsImageList = false; + m_fitToCurrentPage = false; + +#if defined(__WXWINCE__) + m_internalBorder = 1; +#else + m_internalBorder = 5; +#endif + + m_controlMargin = 0; + m_controlSizer = NULL; +} + +bool +wxBookCtrlBase::Create(wxWindow *parent, + wxWindowID id, + const wxPoint& pos, + const wxSize& size, + long style, + const wxString& name) +{ + return wxControl::Create + ( + parent, + id, + pos, + size, + style, + wxDefaultValidator, + name + ); +} + +wxBookCtrlBase::~wxBookCtrlBase() +{ + if ( m_ownsImageList ) + { + // may be NULL, ok + delete m_imageList; + } +} + +// ---------------------------------------------------------------------------- +// image list +// ---------------------------------------------------------------------------- + +void wxBookCtrlBase::SetImageList(wxImageList *imageList) +{ + if ( m_ownsImageList ) + { + // may be NULL, ok + delete m_imageList; + + m_ownsImageList = false; + } + + m_imageList = imageList; +} + +void wxBookCtrlBase::AssignImageList(wxImageList* imageList) +{ + SetImageList(imageList); + + m_ownsImageList = true; +} + +// ---------------------------------------------------------------------------- +// geometry +// ---------------------------------------------------------------------------- + +void wxBookCtrlBase::DoInvalidateBestSize() +{ + // notice that it is not necessary to invalidate our own best size + // explicitly if we have m_bookctrl as it will already invalidate the best + // size of its parent when its own size is invalidated and its parent is + // this control + if ( m_bookctrl ) + m_bookctrl->InvalidateBestSize(); + else + wxControl::InvalidateBestSize(); +} + +void wxBookCtrlBase::SetPageSize(const wxSize& size) +{ + SetClientSize(CalcSizeFromPage(size)); +} + +wxSize wxBookCtrlBase::DoGetBestSize() const +{ + wxSize bestSize; + + // iterate over all pages, get the largest width and height + const size_t nCount = m_pages.size(); + for ( size_t nPage = 0; nPage < nCount; nPage++ ) + { + const wxWindow * const pPage = m_pages[nPage]; + if( pPage ) + { + wxSize childBestSize(pPage->GetBestSize()); + + if ( childBestSize.x > bestSize.x ) + bestSize.x = childBestSize.x; + + if ( childBestSize.y > bestSize.y ) + bestSize.y = childBestSize.y; + } + } + + if (m_fitToCurrentPage && GetCurrentPage()) + bestSize = GetCurrentPage()->GetBestSize(); + + // convert display area to window area, adding the size necessary for the + // tabs + wxSize best = CalcSizeFromPage(bestSize); + CacheBestSize(best); + return best; +} + +wxRect wxBookCtrlBase::GetPageRect() const +{ + const wxSize size = GetControllerSize(); + + wxPoint pt; + wxRect rectPage(pt, GetClientSize()); + + switch ( GetWindowStyle() & wxBK_ALIGN_MASK ) + { + default: + wxFAIL_MSG( _T("unexpected alignment") ); + // fall through + + case wxBK_TOP: + rectPage.y = size.y + GetInternalBorder(); + // fall through + + case wxBK_BOTTOM: + rectPage.height -= size.y + GetInternalBorder(); + if (rectPage.height < 0) + rectPage.height = 0; + break; + + case wxBK_LEFT: + rectPage.x = size.x + GetInternalBorder(); + // fall through + + case wxBK_RIGHT: + rectPage.width -= size.x + GetInternalBorder(); + if (rectPage.width < 0) + rectPage.width = 0; + break; + } + + return rectPage; +} + +// Lay out controls +void wxBookCtrlBase::DoSize() +{ + if ( !m_bookctrl ) + { + // we're not fully created yet or OnSize() should be hidden by derived class + return; + } + + if (GetSizer()) + Layout(); + else + { + // resize controller and the page area to fit inside our new size + const wxSize sizeClient( GetClientSize() ), + sizeBorder( m_bookctrl->GetSize() - m_bookctrl->GetClientSize() ), + sizeCtrl( GetControllerSize() ); + + m_bookctrl->SetClientSize( sizeCtrl.x - sizeBorder.x, sizeCtrl.y - sizeBorder.y ); + // if this changes the visibility of the scrollbars the best size changes, relayout in this case + wxSize sizeCtrl2 = GetControllerSize(); + if ( sizeCtrl != sizeCtrl2 ) + { + wxSize sizeBorder2 = m_bookctrl->GetSize() - m_bookctrl->GetClientSize(); + m_bookctrl->SetClientSize( sizeCtrl2.x - sizeBorder2.x, sizeCtrl2.y - sizeBorder2.y ); + } + + const wxSize sizeNew = m_bookctrl->GetSize(); + wxPoint posCtrl; + switch ( GetWindowStyle() & wxBK_ALIGN_MASK ) + { + default: + wxFAIL_MSG( _T("unexpected alignment") ); + // fall through + + case wxBK_TOP: + case wxBK_LEFT: + // posCtrl is already ok + break; + + case wxBK_BOTTOM: + posCtrl.y = sizeClient.y - sizeNew.y; + break; + + case wxBK_RIGHT: + posCtrl.x = sizeClient.x - sizeNew.x; + break; + } + + if ( m_bookctrl->GetPosition() != posCtrl ) + m_bookctrl->Move(posCtrl); + } + + // resize all pages to fit the new control size + const wxRect pageRect = GetPageRect(); + const unsigned pagesCount = m_pages.Count(); + for ( unsigned int i = 0; i < pagesCount; ++i ) + { + wxWindow * const page = m_pages[i]; + if ( !page ) + { + wxASSERT_MSG( AllowNullPage(), + _T("Null page in a control that does not allow null pages?") ); + continue; + } + + page->SetSize(pageRect); + } +} + +void wxBookCtrlBase::OnSize(wxSizeEvent& event) +{ + event.Skip(); + + DoSize(); +} + +wxSize wxBookCtrlBase::GetControllerSize() const +{ + if(!m_bookctrl) + return wxSize(0,0); + + const wxSize sizeClient = GetClientSize(), + sizeBorder = m_bookctrl->GetSize() - m_bookctrl->GetClientSize(), + sizeCtrl = m_bookctrl->GetBestSize() + sizeBorder; + + wxSize size; + + if ( IsVertical() ) + { + size.x = sizeClient.x; + size.y = sizeCtrl.y; + } + else // left/right aligned + { + size.x = sizeCtrl.x; + size.y = sizeClient.y; + } + + return size; +} + +// ---------------------------------------------------------------------------- +// miscellaneous stuff +// ---------------------------------------------------------------------------- + +#if wxUSE_HELP + +void wxBookCtrlBase::OnHelp(wxHelpEvent& event) +{ + // determine where does this even originate from to avoid redirecting it + // back to the page which generated it (resulting in an infinite loop) + + // notice that we have to check in the hard(er) way instead of just testing + // if the event object == this because the book control can have other + // subcontrols inside it (e.g. wxSpinButton in case of a notebook in wxUniv) + wxWindow *source = wxStaticCast(event.GetEventObject(), wxWindow); + while ( source && source != this && source->GetParent() != this ) + { + source = source->GetParent(); + } + + if ( source && m_pages.Index(source) == wxNOT_FOUND ) + { + // this event is for the book control itself, redirect it to the + // corresponding page + wxWindow *page = NULL; + + if ( event.GetOrigin() == wxHelpEvent::Origin_HelpButton ) + { + // show help for the page under the mouse + const int pagePos = HitTest(ScreenToClient(event.GetPosition())); + + if ( pagePos != wxNOT_FOUND) + { + page = GetPage((size_t)pagePos); + } + } + else // event from keyboard or unknown source + { + // otherwise show the current page help + page = GetCurrentPage(); + } + + if ( page ) + { + // change event object to the page to avoid infinite recursion if + // we get this event ourselves if the page doesn't handle it + event.SetEventObject(page); + + if ( page->GetEventHandler()->ProcessEvent(event) ) + { + // don't call event.Skip() + return; + } + } + } + //else: event coming from one of our pages already + + event.Skip(); +} + +#endif // wxUSE_HELP + +// ---------------------------------------------------------------------------- +// pages management +// ---------------------------------------------------------------------------- + +bool +wxBookCtrlBase::InsertPage(size_t nPage, + wxWindow *page, + const wxString& WXUNUSED(text), + bool WXUNUSED(bSelect), + int WXUNUSED(imageId)) +{ + wxCHECK_MSG( page || AllowNullPage(), false, + _T("NULL page in wxBookCtrlBase::InsertPage()") ); + wxCHECK_MSG( nPage <= m_pages.size(), false, + _T("invalid page index in wxBookCtrlBase::InsertPage()") ); + + m_pages.Insert(page, nPage); + if ( page ) + page->SetSize(GetPageRect()); + + DoInvalidateBestSize(); + + return true; +} + +bool wxBookCtrlBase::DeletePage(size_t nPage) +{ + wxWindow *page = DoRemovePage(nPage); + if ( !(page || AllowNullPage()) ) + return false; + + // delete NULL is harmless + delete page; + + return true; +} + +wxWindow *wxBookCtrlBase::DoRemovePage(size_t nPage) +{ + wxCHECK_MSG( nPage < m_pages.size(), NULL, + _T("invalid page index in wxBookCtrlBase::DoRemovePage()") ); + + wxWindow *pageRemoved = m_pages[nPage]; + m_pages.RemoveAt(nPage); + DoInvalidateBestSize(); + + return pageRemoved; +} + +int wxBookCtrlBase::GetNextPage(bool forward) const +{ + int nPage; + + int nMax = GetPageCount(); + if ( nMax-- ) // decrement it to get the last valid index + { + int nSel = GetSelection(); + + // change selection wrapping if it becomes invalid + nPage = forward ? nSel == nMax ? 0 + : nSel + 1 + : nSel == 0 ? nMax + : nSel - 1; + } + else // notebook is empty, no next page + { + nPage = wxNOT_FOUND; + } + + return nPage; +} + +int wxBookCtrlBase::DoSetSelection(size_t n, int flags) +{ + wxCHECK_MSG( n < GetPageCount(), wxNOT_FOUND, + wxT("invalid page index in wxBookCtrlBase::DoSetSelection()") ); + + const int oldSel = GetSelection(); + + if ( n != (size_t)oldSel ) + { + wxBookCtrlBaseEvent *event = CreatePageChangingEvent(); + bool allowed = false; + + if ( flags & SetSelection_SendEvent ) + { + event->SetSelection(n); + event->SetOldSelection(oldSel); + event->SetEventObject(this); + + allowed = !GetEventHandler()->ProcessEvent(*event) || event->IsAllowed(); + } + + if ( !(flags & SetSelection_SendEvent) || allowed) + { + if ( oldSel != wxNOT_FOUND ) + m_pages[oldSel]->Hide(); + + wxWindow *page = m_pages[n]; + page->SetSize(GetPageRect()); + page->Show(); + + // change selection now to ignore the selection change event + UpdateSelectedPage(n); + + if ( flags & SetSelection_SendEvent ) + { + // program allows the page change + MakeChangedEvent(*event); + (void)GetEventHandler()->ProcessEvent(*event); + } + } + + delete event; + } + + return oldSel; +} + + +#endif // wxUSE_BOOKCTRL diff --git a/Externals/wxWidgets/src/common/choiccmn.cpp b/Externals/wxWidgets/src/common/choiccmn.cpp index 94481b9141..7febe79e6e 100644 --- a/Externals/wxWidgets/src/common/choiccmn.cpp +++ b/Externals/wxWidgets/src/common/choiccmn.cpp @@ -1,55 +1,55 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/choiccmn.cpp -// Purpose: common (to all ports) wxChoice functions -// Author: Vadim Zeitlin -// Modified by: -// Created: 26.07.99 -// RCS-ID: $Id: choiccmn.cpp 39470 2006-05-30 07:34:30Z ABX $ -// Copyright: (c) wxWidgets team -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_CHOICE - -#include "wx/choice.h" - -#ifndef WX_PRECOMP -#endif - -const wxChar wxChoiceNameStr[] = wxT("choice"); - -// ============================================================================ -// implementation -// ============================================================================ - -wxChoiceBase::~wxChoiceBase() -{ - // this destructor is required for Darwin -} - -// ---------------------------------------------------------------------------- -// misc -// ---------------------------------------------------------------------------- - -void wxChoiceBase::Command(wxCommandEvent& event) -{ - SetSelection(event.GetInt()); - (void)ProcessEvent(event); -} - -#endif // wxUSE_CHOICE +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/choiccmn.cpp +// Purpose: common (to all ports) wxChoice functions +// Author: Vadim Zeitlin +// Modified by: +// Created: 26.07.99 +// RCS-ID: $Id: choiccmn.cpp 39470 2006-05-30 07:34:30Z ABX $ +// Copyright: (c) wxWidgets team +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_CHOICE + +#include "wx/choice.h" + +#ifndef WX_PRECOMP +#endif + +const wxChar wxChoiceNameStr[] = wxT("choice"); + +// ============================================================================ +// implementation +// ============================================================================ + +wxChoiceBase::~wxChoiceBase() +{ + // this destructor is required for Darwin +} + +// ---------------------------------------------------------------------------- +// misc +// ---------------------------------------------------------------------------- + +void wxChoiceBase::Command(wxCommandEvent& event) +{ + SetSelection(event.GetInt()); + (void)ProcessEvent(event); +} + +#endif // wxUSE_CHOICE diff --git a/Externals/wxWidgets/src/common/clipcmn.cpp b/Externals/wxWidgets/src/common/clipcmn.cpp index d4912cf8e1..2421c48fe2 100644 --- a/Externals/wxWidgets/src/common/clipcmn.cpp +++ b/Externals/wxWidgets/src/common/clipcmn.cpp @@ -1,63 +1,63 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/clipcmn.cpp -// Purpose: common (to all ports) wxClipboard functions -// Author: Robert Roebling -// Modified by: -// Created: 28.06.99 -// RCS-ID: $Id: clipcmn.cpp 40943 2006-08-31 19:31:43Z ABX $ -// Copyright: (c) Robert Roebling -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_CLIPBOARD - -#include "wx/clipbrd.h" - -#ifndef WX_PRECOMP - #include "wx/module.h" -#endif - -static wxClipboard *gs_clipboard = NULL; - -/*static*/ wxClipboard *wxClipboardBase::Get() -{ - if ( !gs_clipboard ) - { - gs_clipboard = new wxClipboard; - } - return gs_clipboard; -} - -// ---------------------------------------------------------------------------- -// wxClipboardModule: module responsible for destroying the global clipboard -// object -// ---------------------------------------------------------------------------- - -class wxClipboardModule : public wxModule -{ -public: - bool OnInit() { return true; } - void OnExit() { wxDELETE(gs_clipboard); } - -private: - DECLARE_DYNAMIC_CLASS(wxClipboardModule) -}; - -IMPLEMENT_DYNAMIC_CLASS(wxClipboardModule, wxModule) - -#endif // wxUSE_CLIPBOARD +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/clipcmn.cpp +// Purpose: common (to all ports) wxClipboard functions +// Author: Robert Roebling +// Modified by: +// Created: 28.06.99 +// RCS-ID: $Id: clipcmn.cpp 40943 2006-08-31 19:31:43Z ABX $ +// Copyright: (c) Robert Roebling +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_CLIPBOARD + +#include "wx/clipbrd.h" + +#ifndef WX_PRECOMP + #include "wx/module.h" +#endif + +static wxClipboard *gs_clipboard = NULL; + +/*static*/ wxClipboard *wxClipboardBase::Get() +{ + if ( !gs_clipboard ) + { + gs_clipboard = new wxClipboard; + } + return gs_clipboard; +} + +// ---------------------------------------------------------------------------- +// wxClipboardModule: module responsible for destroying the global clipboard +// object +// ---------------------------------------------------------------------------- + +class wxClipboardModule : public wxModule +{ +public: + bool OnInit() { return true; } + void OnExit() { wxDELETE(gs_clipboard); } + +private: + DECLARE_DYNAMIC_CLASS(wxClipboardModule) +}; + +IMPLEMENT_DYNAMIC_CLASS(wxClipboardModule, wxModule) + +#endif // wxUSE_CLIPBOARD diff --git a/Externals/wxWidgets/src/common/clntdata.cpp b/Externals/wxWidgets/src/common/clntdata.cpp index f097259f86..d226f15b33 100644 --- a/Externals/wxWidgets/src/common/clntdata.cpp +++ b/Externals/wxWidgets/src/common/clntdata.cpp @@ -1,83 +1,83 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: common/clntdata.cpp -// Purpose: A mixin class for holding a wxClientData or void pointer -// Author: Robin Dunn -// Modified by: -// Created: 9-Oct-2001 -// RCS-ID: $Id: clntdata.cpp 35650 2005-09-23 12:56:45Z MR $ -// Copyright: (c) wxWidgets team -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#include "wx/clntdata.h" - - -// ---------------------------------------------------------------------------- - - -wxClientDataContainer::wxClientDataContainer() -{ - // no client data (yet) - m_clientData = NULL; - m_clientDataType = wxClientData_None; -} - -wxClientDataContainer::~wxClientDataContainer() -{ - // we only delete object data, not untyped - if ( m_clientDataType == wxClientData_Object ) - delete m_clientObject; -} - -void wxClientDataContainer::DoSetClientObject( wxClientData *data ) -{ - wxASSERT_MSG( m_clientDataType != wxClientData_Void, - wxT("can't have both object and void client data") ); - - if ( m_clientObject ) - delete m_clientObject; - - m_clientObject = data; - m_clientDataType = wxClientData_Object; -} - -wxClientData *wxClientDataContainer::DoGetClientObject() const -{ - // it's not an error to call GetClientObject() on a window which doesn't - // have client data at all - NULL will be returned - wxASSERT_MSG( m_clientDataType != wxClientData_Void, - wxT("this window doesn't have object client data") ); - - return m_clientObject; -} - -void wxClientDataContainer::DoSetClientData( void *data ) -{ - wxASSERT_MSG( m_clientDataType != wxClientData_Object, - wxT("can't have both object and void client data") ); - - m_clientData = data; - m_clientDataType = wxClientData_Void; -} - -void *wxClientDataContainer::DoGetClientData() const -{ - // it's not an error to call GetClientData() on a window which doesn't have - // client data at all - NULL will be returned - wxASSERT_MSG( m_clientDataType != wxClientData_Object, - wxT("this window doesn't have void client data") ); - - return m_clientData; -} - - -// ---------------------------------------------------------------------------- - - +///////////////////////////////////////////////////////////////////////////// +// Name: common/clntdata.cpp +// Purpose: A mixin class for holding a wxClientData or void pointer +// Author: Robin Dunn +// Modified by: +// Created: 9-Oct-2001 +// RCS-ID: $Id: clntdata.cpp 35650 2005-09-23 12:56:45Z MR $ +// Copyright: (c) wxWidgets team +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#include "wx/clntdata.h" + + +// ---------------------------------------------------------------------------- + + +wxClientDataContainer::wxClientDataContainer() +{ + // no client data (yet) + m_clientData = NULL; + m_clientDataType = wxClientData_None; +} + +wxClientDataContainer::~wxClientDataContainer() +{ + // we only delete object data, not untyped + if ( m_clientDataType == wxClientData_Object ) + delete m_clientObject; +} + +void wxClientDataContainer::DoSetClientObject( wxClientData *data ) +{ + wxASSERT_MSG( m_clientDataType != wxClientData_Void, + wxT("can't have both object and void client data") ); + + if ( m_clientObject ) + delete m_clientObject; + + m_clientObject = data; + m_clientDataType = wxClientData_Object; +} + +wxClientData *wxClientDataContainer::DoGetClientObject() const +{ + // it's not an error to call GetClientObject() on a window which doesn't + // have client data at all - NULL will be returned + wxASSERT_MSG( m_clientDataType != wxClientData_Void, + wxT("this window doesn't have object client data") ); + + return m_clientObject; +} + +void wxClientDataContainer::DoSetClientData( void *data ) +{ + wxASSERT_MSG( m_clientDataType != wxClientData_Object, + wxT("can't have both object and void client data") ); + + m_clientData = data; + m_clientDataType = wxClientData_Void; +} + +void *wxClientDataContainer::DoGetClientData() const +{ + // it's not an error to call GetClientData() on a window which doesn't have + // client data at all - NULL will be returned + wxASSERT_MSG( m_clientDataType != wxClientData_Object, + wxT("this window doesn't have void client data") ); + + return m_clientData; +} + + +// ---------------------------------------------------------------------------- + + diff --git a/Externals/wxWidgets/src/common/clrpickercmn.cpp b/Externals/wxWidgets/src/common/clrpickercmn.cpp index b62f6fc2bd..8e21d7f6ef 100644 --- a/Externals/wxWidgets/src/common/clrpickercmn.cpp +++ b/Externals/wxWidgets/src/common/clrpickercmn.cpp @@ -1,149 +1,149 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: src/common/clrpickercmn.cpp -// Purpose: wxColourPickerCtrl class implementation -// Author: Francesco Montorsi (readapted code written by Vadim Zeitlin) -// Modified by: -// Created: 15/04/2006 -// RCS-ID: $Id: clrpickercmn.cpp 42219 2006-10-21 19:53:05Z PC $ -// Copyright: (c) Vadim Zeitlin, Francesco Montorsi -// Licence: wxWindows licence -/////////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_COLOURPICKERCTRL - -#include "wx/clrpicker.h" - -#ifndef WX_PRECOMP - #include "wx/textctrl.h" -#endif - -const wxChar wxColourPickerCtrlNameStr[] = wxT("colourpicker"); -const wxChar wxColourPickerWidgetNameStr[] = wxT("colourpickerwidget"); - -// ============================================================================ -// implementation -// ============================================================================ - -DEFINE_EVENT_TYPE(wxEVT_COMMAND_COLOURPICKER_CHANGED) -IMPLEMENT_DYNAMIC_CLASS(wxColourPickerCtrl, wxPickerBase) -IMPLEMENT_DYNAMIC_CLASS(wxColourPickerEvent, wxEvent) - -// ---------------------------------------------------------------------------- -// wxColourPickerCtrl -// ---------------------------------------------------------------------------- - -#define M_PICKER ((wxColourPickerWidget*)m_picker) - -bool wxColourPickerCtrl::Create( wxWindow *parent, wxWindowID id, - const wxColour &col, - const wxPoint &pos, const wxSize &size, - long style, const wxValidator& validator, - const wxString &name ) -{ - if (!wxPickerBase::CreateBase(parent, id, col.GetAsString(), pos, size, - style, validator, name)) - return false; - - // we are not interested to the ID of our picker as we connect - // to its "changed" event dynamically... - m_picker = new wxColourPickerWidget(this, wxID_ANY, col, - wxDefaultPosition, wxDefaultSize, - GetPickerStyle(style)); - - // complete sizer creation - wxPickerBase::PostCreation(); - - m_picker->Connect(wxEVT_COMMAND_COLOURPICKER_CHANGED, - wxColourPickerEventHandler(wxColourPickerCtrl::OnColourChange), - NULL, this); - - return true; -} - -void wxColourPickerCtrl::SetColour(const wxColour &col) -{ - M_PICKER->SetColour(col); - UpdateTextCtrlFromPicker(); -} - -bool wxColourPickerCtrl::SetColour(const wxString &text) -{ - wxColour col(text); // smart wxString->wxColour conversion - if ( !col.Ok() ) - return false; - M_PICKER->SetColour(col); - UpdateTextCtrlFromPicker(); - - return true; -} - -void wxColourPickerCtrl::UpdatePickerFromTextCtrl() -{ - wxASSERT(m_text); - - if (m_bIgnoreNextTextCtrlUpdate) - { - // ignore this update - m_bIgnoreNextTextCtrlUpdate = false; - return; - } - - // wxString -> wxColour conversion - wxColour col(m_text->GetValue()); - if ( !col.Ok() ) - return; // invalid user input - - if (M_PICKER->GetColour() != col) - { - M_PICKER->SetColour(col); - - // fire an event - wxColourPickerEvent event(this, GetId(), col); - GetEventHandler()->ProcessEvent(event); - } -} - -void wxColourPickerCtrl::UpdateTextCtrlFromPicker() -{ - if (!m_text) - return; // no textctrl to update - - // NOTE: this SetValue() will generate an unwanted wxEVT_COMMAND_TEXT_UPDATED - // which will trigger a unneeded UpdateFromTextCtrl(); thus before using - // SetValue() we set the m_bIgnoreNextTextCtrlUpdate flag... - m_bIgnoreNextTextCtrlUpdate = true; - m_text->SetValue(M_PICKER->GetColour().GetAsString()); -} - - - -// ---------------------------------------------------------------------------- -// wxColourPickerCtrl - event handlers -// ---------------------------------------------------------------------------- - -void wxColourPickerCtrl::OnColourChange(wxColourPickerEvent &ev) -{ - UpdateTextCtrlFromPicker(); - - // the wxColourPickerWidget sent us a colour-change notification. - // forward this event to our parent - wxColourPickerEvent event(this, GetId(), ev.GetColour()); - GetEventHandler()->ProcessEvent(event); -} - -#endif // wxUSE_COLOURPICKERCTRL +/////////////////////////////////////////////////////////////////////////////// +// Name: src/common/clrpickercmn.cpp +// Purpose: wxColourPickerCtrl class implementation +// Author: Francesco Montorsi (readapted code written by Vadim Zeitlin) +// Modified by: +// Created: 15/04/2006 +// RCS-ID: $Id: clrpickercmn.cpp 42219 2006-10-21 19:53:05Z PC $ +// Copyright: (c) Vadim Zeitlin, Francesco Montorsi +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_COLOURPICKERCTRL + +#include "wx/clrpicker.h" + +#ifndef WX_PRECOMP + #include "wx/textctrl.h" +#endif + +const wxChar wxColourPickerCtrlNameStr[] = wxT("colourpicker"); +const wxChar wxColourPickerWidgetNameStr[] = wxT("colourpickerwidget"); + +// ============================================================================ +// implementation +// ============================================================================ + +DEFINE_EVENT_TYPE(wxEVT_COMMAND_COLOURPICKER_CHANGED) +IMPLEMENT_DYNAMIC_CLASS(wxColourPickerCtrl, wxPickerBase) +IMPLEMENT_DYNAMIC_CLASS(wxColourPickerEvent, wxEvent) + +// ---------------------------------------------------------------------------- +// wxColourPickerCtrl +// ---------------------------------------------------------------------------- + +#define M_PICKER ((wxColourPickerWidget*)m_picker) + +bool wxColourPickerCtrl::Create( wxWindow *parent, wxWindowID id, + const wxColour &col, + const wxPoint &pos, const wxSize &size, + long style, const wxValidator& validator, + const wxString &name ) +{ + if (!wxPickerBase::CreateBase(parent, id, col.GetAsString(), pos, size, + style, validator, name)) + return false; + + // we are not interested to the ID of our picker as we connect + // to its "changed" event dynamically... + m_picker = new wxColourPickerWidget(this, wxID_ANY, col, + wxDefaultPosition, wxDefaultSize, + GetPickerStyle(style)); + + // complete sizer creation + wxPickerBase::PostCreation(); + + m_picker->Connect(wxEVT_COMMAND_COLOURPICKER_CHANGED, + wxColourPickerEventHandler(wxColourPickerCtrl::OnColourChange), + NULL, this); + + return true; +} + +void wxColourPickerCtrl::SetColour(const wxColour &col) +{ + M_PICKER->SetColour(col); + UpdateTextCtrlFromPicker(); +} + +bool wxColourPickerCtrl::SetColour(const wxString &text) +{ + wxColour col(text); // smart wxString->wxColour conversion + if ( !col.Ok() ) + return false; + M_PICKER->SetColour(col); + UpdateTextCtrlFromPicker(); + + return true; +} + +void wxColourPickerCtrl::UpdatePickerFromTextCtrl() +{ + wxASSERT(m_text); + + if (m_bIgnoreNextTextCtrlUpdate) + { + // ignore this update + m_bIgnoreNextTextCtrlUpdate = false; + return; + } + + // wxString -> wxColour conversion + wxColour col(m_text->GetValue()); + if ( !col.Ok() ) + return; // invalid user input + + if (M_PICKER->GetColour() != col) + { + M_PICKER->SetColour(col); + + // fire an event + wxColourPickerEvent event(this, GetId(), col); + GetEventHandler()->ProcessEvent(event); + } +} + +void wxColourPickerCtrl::UpdateTextCtrlFromPicker() +{ + if (!m_text) + return; // no textctrl to update + + // NOTE: this SetValue() will generate an unwanted wxEVT_COMMAND_TEXT_UPDATED + // which will trigger a unneeded UpdateFromTextCtrl(); thus before using + // SetValue() we set the m_bIgnoreNextTextCtrlUpdate flag... + m_bIgnoreNextTextCtrlUpdate = true; + m_text->SetValue(M_PICKER->GetColour().GetAsString()); +} + + + +// ---------------------------------------------------------------------------- +// wxColourPickerCtrl - event handlers +// ---------------------------------------------------------------------------- + +void wxColourPickerCtrl::OnColourChange(wxColourPickerEvent &ev) +{ + UpdateTextCtrlFromPicker(); + + // the wxColourPickerWidget sent us a colour-change notification. + // forward this event to our parent + wxColourPickerEvent event(this, GetId(), ev.GetColour()); + GetEventHandler()->ProcessEvent(event); +} + +#endif // wxUSE_COLOURPICKERCTRL diff --git a/Externals/wxWidgets/src/common/cmdline.cpp b/Externals/wxWidgets/src/common/cmdline.cpp index 52c5c2a13d..23ed34222c 100644 --- a/Externals/wxWidgets/src/common/cmdline.cpp +++ b/Externals/wxWidgets/src/common/cmdline.cpp @@ -1,1247 +1,1247 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: src/common/cmdline.cpp -// Purpose: wxCmdLineParser implementation -// Author: Vadim Zeitlin -// Modified by: -// Created: 05.01.00 -// RCS-ID: $Id: cmdline.cpp 42197 2006-10-21 14:04:27Z VZ $ -// Copyright: (c) 2000 Vadim Zeitlin -// Licence: wxWindows licence -/////////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#ifndef WX_PRECOMP - #include "wx/dynarray.h" - #include "wx/string.h" - #include "wx/log.h" - #include "wx/intl.h" - #include "wx/app.h" -#endif //WX_PRECOMP - -#include "wx/cmdline.h" - -#if wxUSE_CMDLINE_PARSER - -#include - -#include "wx/datetime.h" -#include "wx/msgout.h" -#include "wx/filename.h" - -// ---------------------------------------------------------------------------- -// private functions -// ---------------------------------------------------------------------------- - -static wxString GetTypeName(wxCmdLineParamType type); - -static wxString GetOptionName(const wxChar *p, const wxChar *allowedChars); - -static wxString GetShortOptionName(const wxChar *p); - -static wxString GetLongOptionName(const wxChar *p); - -// ---------------------------------------------------------------------------- -// private structs -// ---------------------------------------------------------------------------- - -// an internal representation of an option -struct wxCmdLineOption -{ - wxCmdLineOption(wxCmdLineEntryType k, - const wxString& shrt, - const wxString& lng, - const wxString& desc, - wxCmdLineParamType typ, - int fl) - { - wxASSERT_MSG( !shrt.empty() || !lng.empty(), - _T("option should have at least one name") ); - - wxASSERT_MSG - ( - GetShortOptionName(shrt).Len() == shrt.Len(), - wxT("Short option contains invalid characters") - ); - - wxASSERT_MSG - ( - GetLongOptionName(lng).Len() == lng.Len(), - wxT("Long option contains invalid characters") - ); - - - kind = k; - - shortName = shrt; - longName = lng; - description = desc; - - type = typ; - flags = fl; - - m_hasVal = false; - } - - // can't use union easily here, so just store all possible data fields, we - // don't waste much (might still use union later if the number of supported - // types increases, so always use the accessor functions and don't access - // the fields directly!) - - void Check(wxCmdLineParamType WXUNUSED_UNLESS_DEBUG(typ)) const - { - wxASSERT_MSG( type == typ, _T("type mismatch in wxCmdLineOption") ); - } - - long GetLongVal() const - { Check(wxCMD_LINE_VAL_NUMBER); return m_longVal; } - const wxString& GetStrVal() const - { Check(wxCMD_LINE_VAL_STRING); return m_strVal; } -#if wxUSE_DATETIME - const wxDateTime& GetDateVal() const - { Check(wxCMD_LINE_VAL_DATE); return m_dateVal; } -#endif // wxUSE_DATETIME - - void SetLongVal(long val) - { Check(wxCMD_LINE_VAL_NUMBER); m_longVal = val; m_hasVal = true; } - void SetStrVal(const wxString& val) - { Check(wxCMD_LINE_VAL_STRING); m_strVal = val; m_hasVal = true; } -#if wxUSE_DATETIME - void SetDateVal(const wxDateTime& val) - { Check(wxCMD_LINE_VAL_DATE); m_dateVal = val; m_hasVal = true; } -#endif // wxUSE_DATETIME - - void SetHasValue(bool hasValue = true) { m_hasVal = hasValue; } - bool HasValue() const { return m_hasVal; } - -public: - wxCmdLineEntryType kind; - wxString shortName, - longName, - description; - wxCmdLineParamType type; - int flags; - -private: - bool m_hasVal; - - long m_longVal; - wxString m_strVal; -#if wxUSE_DATETIME - wxDateTime m_dateVal; -#endif // wxUSE_DATETIME -}; - -struct wxCmdLineParam -{ - wxCmdLineParam(const wxString& desc, - wxCmdLineParamType typ, - int fl) - : description(desc) - { - type = typ; - flags = fl; - } - - wxString description; - wxCmdLineParamType type; - int flags; -}; - -WX_DECLARE_OBJARRAY(wxCmdLineOption, wxArrayOptions); -WX_DECLARE_OBJARRAY(wxCmdLineParam, wxArrayParams); - -#include "wx/arrimpl.cpp" - -WX_DEFINE_OBJARRAY(wxArrayOptions) -WX_DEFINE_OBJARRAY(wxArrayParams) - -// the parser internal state -struct wxCmdLineParserData -{ - // options - wxString m_switchChars; // characters which may start an option - bool m_enableLongOptions; // true if long options are enabled - wxString m_logo; // some extra text to show in Usage() - - // cmd line data - wxArrayString m_arguments; // == argv, argc == m_arguments.GetCount() - wxArrayOptions m_options; // all possible options and switchrs - wxArrayParams m_paramDesc; // description of all possible params - wxArrayString m_parameters; // all params found - - // methods - wxCmdLineParserData(); - void SetArguments(int argc, char **argv); -#if wxUSE_UNICODE - void SetArguments(int argc, wxChar **argv); -#endif // wxUSE_UNICODE - void SetArguments(const wxString& cmdline); - - int FindOption(const wxString& name); - int FindOptionByLongName(const wxString& name); -}; - -// ============================================================================ -// implementation -// ============================================================================ - -// ---------------------------------------------------------------------------- -// wxCmdLineParserData -// ---------------------------------------------------------------------------- - -wxCmdLineParserData::wxCmdLineParserData() -{ - m_enableLongOptions = true; -#ifdef __UNIX_LIKE__ - m_switchChars = _T("-"); -#else // !Unix - m_switchChars = _T("/-"); -#endif -} - -void wxCmdLineParserData::SetArguments(int argc, char **argv) -{ - m_arguments.clear(); - - for ( int n = 0; n < argc; n++ ) - { - m_arguments.push_back(wxString::FromAscii(argv[n])); - } -} - -#if wxUSE_UNICODE - -void wxCmdLineParserData::SetArguments(int argc, wxChar **argv) -{ - m_arguments.clear(); - - for ( int n = 0; n < argc; n++ ) - { - m_arguments.push_back(argv[n]); - } -} - -#endif // wxUSE_UNICODE - -void wxCmdLineParserData::SetArguments(const wxString& cmdLine) -{ - m_arguments.clear(); - - if(wxTheApp && wxTheApp->argc > 0) - m_arguments.push_back(wxTheApp->argv[0]); - else - m_arguments.push_back(wxEmptyString); - - wxArrayString args = wxCmdLineParser::ConvertStringToArgs(cmdLine); - - WX_APPEND_ARRAY(m_arguments, args); -} - -int wxCmdLineParserData::FindOption(const wxString& name) -{ - if ( !name.empty() ) - { - size_t count = m_options.GetCount(); - for ( size_t n = 0; n < count; n++ ) - { - if ( m_options[n].shortName == name ) - { - // found - return n; - } - } - } - - return wxNOT_FOUND; -} - -int wxCmdLineParserData::FindOptionByLongName(const wxString& name) -{ - size_t count = m_options.GetCount(); - for ( size_t n = 0; n < count; n++ ) - { - if ( m_options[n].longName == name ) - { - // found - return n; - } - } - - return wxNOT_FOUND; -} - -// ---------------------------------------------------------------------------- -// construction and destruction -// ---------------------------------------------------------------------------- - -void wxCmdLineParser::Init() -{ - m_data = new wxCmdLineParserData; -} - -void wxCmdLineParser::SetCmdLine(int argc, char **argv) -{ - m_data->SetArguments(argc, argv); -} - -#if wxUSE_UNICODE - -void wxCmdLineParser::SetCmdLine(int argc, wxChar **argv) -{ - m_data->SetArguments(argc, argv); -} - -#endif // wxUSE_UNICODE - -void wxCmdLineParser::SetCmdLine(const wxString& cmdline) -{ - m_data->SetArguments(cmdline); -} - -wxCmdLineParser::~wxCmdLineParser() -{ - delete m_data; -} - -// ---------------------------------------------------------------------------- -// options -// ---------------------------------------------------------------------------- - -void wxCmdLineParser::SetSwitchChars(const wxString& switchChars) -{ - m_data->m_switchChars = switchChars; -} - -void wxCmdLineParser::EnableLongOptions(bool enable) -{ - m_data->m_enableLongOptions = enable; -} - -bool wxCmdLineParser::AreLongOptionsEnabled() -{ - return m_data->m_enableLongOptions; -} - -void wxCmdLineParser::SetLogo(const wxString& logo) -{ - m_data->m_logo = logo; -} - -// ---------------------------------------------------------------------------- -// command line construction -// ---------------------------------------------------------------------------- - -void wxCmdLineParser::SetDesc(const wxCmdLineEntryDesc *desc) -{ - for ( ;; desc++ ) - { - switch ( desc->kind ) - { - case wxCMD_LINE_SWITCH: - AddSwitch(desc->shortName, desc->longName, desc->description, - desc->flags); - break; - - case wxCMD_LINE_OPTION: - AddOption(desc->shortName, desc->longName, desc->description, - desc->type, desc->flags); - break; - - case wxCMD_LINE_PARAM: - AddParam(desc->description, desc->type, desc->flags); - break; - - default: - wxFAIL_MSG( _T("unknown command line entry type") ); - // still fall through - - case wxCMD_LINE_NONE: - return; - } - } -} - -void wxCmdLineParser::AddSwitch(const wxString& shortName, - const wxString& longName, - const wxString& desc, - int flags) -{ - wxASSERT_MSG( m_data->FindOption(shortName) == wxNOT_FOUND, - _T("duplicate switch") ); - - wxCmdLineOption *option = new wxCmdLineOption(wxCMD_LINE_SWITCH, - shortName, longName, desc, - wxCMD_LINE_VAL_NONE, flags); - - m_data->m_options.Add(option); -} - -void wxCmdLineParser::AddOption(const wxString& shortName, - const wxString& longName, - const wxString& desc, - wxCmdLineParamType type, - int flags) -{ - wxASSERT_MSG( m_data->FindOption(shortName) == wxNOT_FOUND, - _T("duplicate option") ); - - wxCmdLineOption *option = new wxCmdLineOption(wxCMD_LINE_OPTION, - shortName, longName, desc, - type, flags); - - m_data->m_options.Add(option); -} - -void wxCmdLineParser::AddParam(const wxString& desc, - wxCmdLineParamType type, - int flags) -{ - // do some consistency checks: a required parameter can't follow an - // optional one and nothing should follow a parameter with MULTIPLE flag -#ifdef __WXDEBUG__ - if ( !m_data->m_paramDesc.IsEmpty() ) - { - wxCmdLineParam& param = m_data->m_paramDesc.Last(); - - wxASSERT_MSG( !(param.flags & wxCMD_LINE_PARAM_MULTIPLE), - _T("all parameters after the one with wxCMD_LINE_PARAM_MULTIPLE style will be ignored") ); - - if ( !(flags & wxCMD_LINE_PARAM_OPTIONAL) ) - { - wxASSERT_MSG( !(param.flags & wxCMD_LINE_PARAM_OPTIONAL), - _T("a required parameter can't follow an optional one") ); - } - } -#endif // Debug - - wxCmdLineParam *param = new wxCmdLineParam(desc, type, flags); - - m_data->m_paramDesc.Add(param); -} - -// ---------------------------------------------------------------------------- -// access to parse command line -// ---------------------------------------------------------------------------- - -bool wxCmdLineParser::Found(const wxString& name) const -{ - int i = m_data->FindOption(name); - if ( i == wxNOT_FOUND ) - i = m_data->FindOptionByLongName(name); - - wxCHECK_MSG( i != wxNOT_FOUND, false, _T("unknown switch") ); - - wxCmdLineOption& opt = m_data->m_options[(size_t)i]; - if ( !opt.HasValue() ) - return false; - - return true; -} - -bool wxCmdLineParser::Found(const wxString& name, wxString *value) const -{ - int i = m_data->FindOption(name); - if ( i == wxNOT_FOUND ) - i = m_data->FindOptionByLongName(name); - - wxCHECK_MSG( i != wxNOT_FOUND, false, _T("unknown option") ); - - wxCmdLineOption& opt = m_data->m_options[(size_t)i]; - if ( !opt.HasValue() ) - return false; - - wxCHECK_MSG( value, false, _T("NULL pointer in wxCmdLineOption::Found") ); - - *value = opt.GetStrVal(); - - return true; -} - -bool wxCmdLineParser::Found(const wxString& name, long *value) const -{ - int i = m_data->FindOption(name); - if ( i == wxNOT_FOUND ) - i = m_data->FindOptionByLongName(name); - - wxCHECK_MSG( i != wxNOT_FOUND, false, _T("unknown option") ); - - wxCmdLineOption& opt = m_data->m_options[(size_t)i]; - if ( !opt.HasValue() ) - return false; - - wxCHECK_MSG( value, false, _T("NULL pointer in wxCmdLineOption::Found") ); - - *value = opt.GetLongVal(); - - return true; -} - -#if wxUSE_DATETIME -bool wxCmdLineParser::Found(const wxString& name, wxDateTime *value) const -{ - int i = m_data->FindOption(name); - if ( i == wxNOT_FOUND ) - i = m_data->FindOptionByLongName(name); - - wxCHECK_MSG( i != wxNOT_FOUND, false, _T("unknown option") ); - - wxCmdLineOption& opt = m_data->m_options[(size_t)i]; - if ( !opt.HasValue() ) - return false; - - wxCHECK_MSG( value, false, _T("NULL pointer in wxCmdLineOption::Found") ); - - *value = opt.GetDateVal(); - - return true; -} -#endif // wxUSE_DATETIME - -size_t wxCmdLineParser::GetParamCount() const -{ - return m_data->m_parameters.size(); -} - -wxString wxCmdLineParser::GetParam(size_t n) const -{ - wxCHECK_MSG( n < GetParamCount(), wxEmptyString, _T("invalid param index") ); - - return m_data->m_parameters[n]; -} - -// Resets switches and options -void wxCmdLineParser::Reset() -{ - for ( size_t i = 0; i < m_data->m_options.Count(); i++ ) - { - wxCmdLineOption& opt = m_data->m_options[i]; - opt.SetHasValue(false); - } -} - - -// ---------------------------------------------------------------------------- -// the real work is done here -// ---------------------------------------------------------------------------- - -int wxCmdLineParser::Parse(bool showUsage) -{ - bool maybeOption = true; // can the following arg be an option? - bool ok = true; // true until an error is detected - bool helpRequested = false; // true if "-h" was given - bool hadRepeatableParam = false; // true if found param with MULTIPLE flag - - size_t currentParam = 0; // the index in m_paramDesc - - size_t countParam = m_data->m_paramDesc.GetCount(); - wxString errorMsg; - - Reset(); - - // parse everything - wxString arg; - size_t count = m_data->m_arguments.size(); - for ( size_t n = 1; ok && (n < count); n++ ) // 0 is program name - { - arg = m_data->m_arguments[n]; - - // special case: "--" should be discarded and all following arguments - // should be considered as parameters, even if they start with '-' and - // not like options (this is POSIX-like) - if ( arg == _T("--") ) - { - maybeOption = false; - - continue; - } - - // empty argument or just '-' is not an option but a parameter - if ( maybeOption && arg.length() > 1 && - wxStrchr(m_data->m_switchChars, arg[0u]) ) - { - bool isLong; - wxString name; - int optInd = wxNOT_FOUND; // init to suppress warnings - - // an option or a switch: find whether it's a long or a short one - if ( arg[0u] == _T('-') && arg[1u] == _T('-') ) - { - // a long one - isLong = true; - - // Skip leading "--" - const wxChar *p = arg.c_str() + 2; - - bool longOptionsEnabled = AreLongOptionsEnabled(); - - name = GetLongOptionName(p); - - if (longOptionsEnabled) - { - optInd = m_data->FindOptionByLongName(name); - if ( optInd == wxNOT_FOUND ) - { - errorMsg << wxString::Format(_("Unknown long option '%s'"), name.c_str()) - << _T('\n'); - } - } - else - { - optInd = wxNOT_FOUND; // Sanity check - - // Print the argument including leading "--" - name.Prepend( wxT("--") ); - errorMsg << wxString::Format(_("Unknown option '%s'"), name.c_str()) - << _T('\n'); - } - - } - else // not a long option - { - isLong = false; - - // a short one: as they can be cumulated, we try to find the - // longest substring which is a valid option - const wxChar *p = arg.c_str() + 1; - - name = GetShortOptionName(p); - - size_t len = name.length(); - do - { - if ( len == 0 ) - { - // we couldn't find a valid option name in the - // beginning of this string - errorMsg << wxString::Format(_("Unknown option '%s'"), name.c_str()) - << _T('\n'); - - break; - } - else - { - optInd = m_data->FindOption(name.Left(len)); - - // will try with one character less the next time - len--; - } - } - while ( optInd == wxNOT_FOUND ); - - len++; // compensates extra len-- above - if ( (optInd != wxNOT_FOUND) && (len != name.length()) ) - { - // first of all, the option name is only part of this - // string - name = name.Left(len); - - // our option is only part of this argument, there is - // something else in it - it is either the value of this - // option or other switches if it is a switch - if ( m_data->m_options[(size_t)optInd].kind - == wxCMD_LINE_SWITCH ) - { - // pretend that all the rest of the argument is the - // next argument, in fact - wxString arg2 = arg[0u]; - arg2 += arg.Mid(len + 1); // +1 for leading '-' - - m_data->m_arguments.insert - (m_data->m_arguments.begin() + n + 1, arg2); - count++; - } - //else: it's our value, we'll deal with it below - } - } - - if ( optInd == wxNOT_FOUND ) - { - ok = false; - - continue; // will break, in fact - } - - // look at what follows: - - // +1 for leading '-' - const wxChar *p = arg.c_str() + 1 + name.length(); - if ( isLong ) - p++; // for another leading '-' - - wxCmdLineOption& opt = m_data->m_options[(size_t)optInd]; - if ( opt.kind == wxCMD_LINE_SWITCH ) - { - // we must check that there is no value following the switch - if ( *p != _T('\0') ) - { - errorMsg << wxString::Format(_("Unexpected characters following option '%s'."), name.c_str()) - << _T('\n'); - ok = false; - } - else // no value, as expected - { - // nothing more to do - opt.SetHasValue(); - - if ( opt.flags & wxCMD_LINE_OPTION_HELP ) - { - helpRequested = true; - - // it's not an error, but we still stop here - ok = false; - } - } - } - else // it's an option. not a switch - { - // get the value - if ( isLong ) - { - if ( *p++ != _T('=') ) - { - errorMsg << wxString::Format(_("Option '%s' requires a value, '=' expected."), name.c_str()) - << _T('\n'); - - ok = false; - } - } - else // short option - { - switch ( *p ) - { - case _T('='): - case _T(':'): - // the value follows - p++; - break; - - case 0: - // the value is in the next argument - if ( ++n == count ) - { - // ... but there is none - errorMsg << wxString::Format(_("Option '%s' requires a value."), - name.c_str()) - << _T('\n'); - - ok = false; - } - else - { - // ... take it from there - p = m_data->m_arguments[n].c_str(); - } - break; - - default: - // the value is right here: this may be legal or - // not depending on the option style - if ( opt.flags & wxCMD_LINE_NEEDS_SEPARATOR ) - { - errorMsg << wxString::Format(_("Separator expected after the option '%s'."), - name.c_str()) - << _T('\n'); - - ok = false; - } - } - } - - if ( ok ) - { - wxString value = p; - switch ( opt.type ) - { - default: - wxFAIL_MSG( _T("unknown option type") ); - // still fall through - - case wxCMD_LINE_VAL_STRING: - opt.SetStrVal(value); - break; - - case wxCMD_LINE_VAL_NUMBER: - { - long val; - if ( value.ToLong(&val) ) - { - opt.SetLongVal(val); - } - else - { - errorMsg << wxString::Format(_("'%s' is not a correct numeric value for option '%s'."), - value.c_str(), name.c_str()) - << _T('\n'); - - ok = false; - } - } - break; - -#if wxUSE_DATETIME - case wxCMD_LINE_VAL_DATE: - { - wxDateTime dt; - const wxChar *res = dt.ParseDate(value); - if ( !res || *res ) - { - errorMsg << wxString::Format(_("Option '%s': '%s' cannot be converted to a date."), - name.c_str(), value.c_str()) - << _T('\n'); - - ok = false; - } - else - { - opt.SetDateVal(dt); - } - } - break; -#endif // wxUSE_DATETIME - } - } - } - } - else // not an option, must be a parameter - { - if ( currentParam < countParam ) - { - wxCmdLineParam& param = m_data->m_paramDesc[currentParam]; - - // TODO check the param type - - m_data->m_parameters.push_back(arg); - - if ( !(param.flags & wxCMD_LINE_PARAM_MULTIPLE) ) - { - currentParam++; - } - else - { - wxASSERT_MSG( currentParam == countParam - 1, - _T("all parameters after the one with wxCMD_LINE_PARAM_MULTIPLE style are ignored") ); - - // remember that we did have this last repeatable parameter - hadRepeatableParam = true; - } - } - else - { - errorMsg << wxString::Format(_("Unexpected parameter '%s'"), arg.c_str()) - << _T('\n'); - - ok = false; - } - } - } - - // verify that all mandatory options were given - if ( ok ) - { - size_t countOpt = m_data->m_options.GetCount(); - for ( size_t n = 0; ok && (n < countOpt); n++ ) - { - wxCmdLineOption& opt = m_data->m_options[n]; - if ( (opt.flags & wxCMD_LINE_OPTION_MANDATORY) && !opt.HasValue() ) - { - wxString optName; - if ( !opt.longName ) - { - optName = opt.shortName; - } - else - { - if ( AreLongOptionsEnabled() ) - { - optName.Printf( _("%s (or %s)"), - opt.shortName.c_str(), - opt.longName.c_str() ); - } - else - { - optName.Printf( wxT("%s"), - opt.shortName.c_str() ); - } - } - - errorMsg << wxString::Format(_("The value for the option '%s' must be specified."), - optName.c_str()) - << _T('\n'); - - ok = false; - } - } - - for ( ; ok && (currentParam < countParam); currentParam++ ) - { - wxCmdLineParam& param = m_data->m_paramDesc[currentParam]; - if ( (currentParam == countParam - 1) && - (param.flags & wxCMD_LINE_PARAM_MULTIPLE) && - hadRepeatableParam ) - { - // special case: currentParam wasn't incremented, but we did - // have it, so don't give error - continue; - } - - if ( !(param.flags & wxCMD_LINE_PARAM_OPTIONAL) ) - { - errorMsg << wxString::Format(_("The required parameter '%s' was not specified."), - param.description.c_str()) - << _T('\n'); - - ok = false; - } - } - } - - // if there was an error during parsing the command line, show this error - // and also the usage message if it had been requested - if ( !ok && (!errorMsg.empty() || (helpRequested && showUsage)) ) - { - wxMessageOutput* msgOut = wxMessageOutput::Get(); - if ( msgOut ) - { - wxString usage; - if ( showUsage ) - usage = GetUsageString(); - - msgOut->Printf( wxT("%s%s"), usage.c_str(), errorMsg.c_str() ); - } - else - { - wxFAIL_MSG( _T("no wxMessageOutput object?") ); - } - } - - return ok ? 0 : helpRequested ? -1 : 1; -} - -// ---------------------------------------------------------------------------- -// give the usage message -// ---------------------------------------------------------------------------- - -void wxCmdLineParser::Usage() -{ - wxMessageOutput* msgOut = wxMessageOutput::Get(); - if ( msgOut ) - { - msgOut->Printf( wxT("%s"), GetUsageString().c_str() ); - } - else - { - wxFAIL_MSG( _T("no wxMessageOutput object?") ); - } -} - -wxString wxCmdLineParser::GetUsageString() -{ - wxString appname; - if ( m_data->m_arguments.empty() ) - { - if ( wxTheApp ) - appname = wxTheApp->GetAppName(); - } - else // use argv[0] - { - appname = wxFileName(m_data->m_arguments[0]).GetName(); - } - - // we construct the brief cmd line desc on the fly, but not the detailed - // help message below because we want to align the options descriptions - // and for this we must first know the longest one of them - wxString usage; - wxArrayString namesOptions, descOptions; - - if ( !m_data->m_logo.empty() ) - { - usage << m_data->m_logo << _T('\n'); - } - - usage << wxString::Format(_("Usage: %s"), appname.c_str()); - - // the switch char is usually '-' but this can be changed with - // SetSwitchChars() and then the first one of possible chars is used - wxChar chSwitch = !m_data->m_switchChars ? _T('-') - : m_data->m_switchChars[0u]; - - bool areLongOptionsEnabled = AreLongOptionsEnabled(); - size_t n, count = m_data->m_options.GetCount(); - for ( n = 0; n < count; n++ ) - { - wxCmdLineOption& opt = m_data->m_options[n]; - - usage << _T(' '); - if ( !(opt.flags & wxCMD_LINE_OPTION_MANDATORY) ) - { - usage << _T('['); - } - - if ( !opt.shortName.empty() ) - { - usage << chSwitch << opt.shortName; - } - else if ( areLongOptionsEnabled && !opt.longName.empty() ) - { - usage << _T("--") << opt.longName; - } - else - { - if (!opt.longName.empty()) - { - wxFAIL_MSG( wxT("option with only a long name while long ") - wxT("options are disabled") ); - } - else - { - wxFAIL_MSG( _T("option without neither short nor long name") ); - } - } - - wxString option; - - if ( !opt.shortName.empty() ) - { - option << _T(" ") << chSwitch << opt.shortName; - } - - if ( areLongOptionsEnabled && !opt.longName.empty() ) - { - option << (option.empty() ? _T(" ") : _T(", ")) - << _T("--") << opt.longName; - } - - if ( opt.kind != wxCMD_LINE_SWITCH ) - { - wxString val; - val << _T('<') << GetTypeName(opt.type) << _T('>'); - usage << _T(' ') << val; - option << (!opt.longName ? _T(':') : _T('=')) << val; - } - - if ( !(opt.flags & wxCMD_LINE_OPTION_MANDATORY) ) - { - usage << _T(']'); - } - - namesOptions.push_back(option); - descOptions.push_back(opt.description); - } - - count = m_data->m_paramDesc.GetCount(); - for ( n = 0; n < count; n++ ) - { - wxCmdLineParam& param = m_data->m_paramDesc[n]; - - usage << _T(' '); - if ( param.flags & wxCMD_LINE_PARAM_OPTIONAL ) - { - usage << _T('['); - } - - usage << param.description; - - if ( param.flags & wxCMD_LINE_PARAM_MULTIPLE ) - { - usage << _T("..."); - } - - if ( param.flags & wxCMD_LINE_PARAM_OPTIONAL ) - { - usage << _T(']'); - } - } - - usage << _T('\n'); - - // now construct the detailed help message - size_t len, lenMax = 0; - count = namesOptions.size(); - for ( n = 0; n < count; n++ ) - { - len = namesOptions[n].length(); - if ( len > lenMax ) - lenMax = len; - } - - for ( n = 0; n < count; n++ ) - { - len = namesOptions[n].length(); - usage << namesOptions[n] - << wxString(_T(' '), lenMax - len) << _T('\t') - << descOptions[n] - << _T('\n'); - } - - return usage; -} - -// ---------------------------------------------------------------------------- -// private functions -// ---------------------------------------------------------------------------- - -static wxString GetTypeName(wxCmdLineParamType type) -{ - wxString s; - switch ( type ) - { - default: - wxFAIL_MSG( _T("unknown option type") ); - // still fall through - - case wxCMD_LINE_VAL_STRING: - s = _("str"); - break; - - case wxCMD_LINE_VAL_NUMBER: - s = _("num"); - break; - - case wxCMD_LINE_VAL_DATE: - s = _("date"); - break; - } - - return s; -} - -/* -Returns a string which is equal to the string pointed to by p, but up to the -point where p contains an character that's not allowed. -Allowable characters are letters and numbers, and characters pointed to by -the parameter allowedChars. - -For example, if p points to "abcde-@-_", and allowedChars is "-_", -this function returns "abcde-". -*/ -static wxString GetOptionName(const wxChar *p, - const wxChar *allowedChars) -{ - wxString argName; - - while ( *p && (wxIsalnum(*p) || wxStrchr(allowedChars, *p)) ) - { - argName += *p++; - } - - return argName; -} - -// Besides alphanumeric characters, short and long options can -// have other characters. - -// A short option additionally can have these -#define wxCMD_LINE_CHARS_ALLOWED_BY_SHORT_OPTION wxT("_?") - -// A long option can have the same characters as a short option and a '-'. -#define wxCMD_LINE_CHARS_ALLOWED_BY_LONG_OPTION \ - wxCMD_LINE_CHARS_ALLOWED_BY_SHORT_OPTION wxT("-") - -static wxString GetShortOptionName(const wxChar *p) -{ - return GetOptionName(p, wxCMD_LINE_CHARS_ALLOWED_BY_SHORT_OPTION); -} - -static wxString GetLongOptionName(const wxChar *p) -{ - return GetOptionName(p, wxCMD_LINE_CHARS_ALLOWED_BY_LONG_OPTION); -} - -#endif // wxUSE_CMDLINE_PARSER - -// ---------------------------------------------------------------------------- -// global functions -// ---------------------------------------------------------------------------- - -/* - This function is mainly used under Windows (as under Unix we always get the - command line arguments as argc/argv anyhow) and so it tries to follow - Windows conventions for the command line handling, not Unix ones. For - instance, backslash is not special except when it precedes double quote when - it does quote it. - */ - -/* static */ -wxArrayString wxCmdLineParser::ConvertStringToArgs(const wxChar *p) -{ - wxArrayString args; - - wxString arg; - arg.reserve(1024); - - bool isInsideQuotes = false; - for ( ;; ) - { - // skip white space - while ( *p == _T(' ') || *p == _T('\t') ) - p++; - - // anything left? - if ( *p == _T('\0') ) - break; - - // parse this parameter - bool endParam = false; - bool lastBS = false; - for ( arg.clear(); !endParam; p++ ) - { - switch ( *p ) - { - case _T('"'): - if ( !lastBS ) - { - isInsideQuotes = !isInsideQuotes; - - // don't put quote in arg - continue; - } - //else: quote has no special meaning but the backslash - // still remains -- makes no sense but this is what - // Windows does - break; - - case _T(' '): - case _T('\t'): - // backslash does *not* quote the space, only quotes do - if ( isInsideQuotes ) - { - // skip assignment below - break; - } - // fall through - - case _T('\0'): - endParam = true; - - break; - } - - if ( endParam ) - { - break; - } - - lastBS = *p == _T('\\'); - - arg += *p; - } - - args.push_back(arg); - } - - return args; -} +/////////////////////////////////////////////////////////////////////////////// +// Name: src/common/cmdline.cpp +// Purpose: wxCmdLineParser implementation +// Author: Vadim Zeitlin +// Modified by: +// Created: 05.01.00 +// RCS-ID: $Id: cmdline.cpp 42197 2006-10-21 14:04:27Z VZ $ +// Copyright: (c) 2000 Vadim Zeitlin +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#ifndef WX_PRECOMP + #include "wx/dynarray.h" + #include "wx/string.h" + #include "wx/log.h" + #include "wx/intl.h" + #include "wx/app.h" +#endif //WX_PRECOMP + +#include "wx/cmdline.h" + +#if wxUSE_CMDLINE_PARSER + +#include + +#include "wx/datetime.h" +#include "wx/msgout.h" +#include "wx/filename.h" + +// ---------------------------------------------------------------------------- +// private functions +// ---------------------------------------------------------------------------- + +static wxString GetTypeName(wxCmdLineParamType type); + +static wxString GetOptionName(const wxChar *p, const wxChar *allowedChars); + +static wxString GetShortOptionName(const wxChar *p); + +static wxString GetLongOptionName(const wxChar *p); + +// ---------------------------------------------------------------------------- +// private structs +// ---------------------------------------------------------------------------- + +// an internal representation of an option +struct wxCmdLineOption +{ + wxCmdLineOption(wxCmdLineEntryType k, + const wxString& shrt, + const wxString& lng, + const wxString& desc, + wxCmdLineParamType typ, + int fl) + { + wxASSERT_MSG( !shrt.empty() || !lng.empty(), + _T("option should have at least one name") ); + + wxASSERT_MSG + ( + GetShortOptionName(shrt).Len() == shrt.Len(), + wxT("Short option contains invalid characters") + ); + + wxASSERT_MSG + ( + GetLongOptionName(lng).Len() == lng.Len(), + wxT("Long option contains invalid characters") + ); + + + kind = k; + + shortName = shrt; + longName = lng; + description = desc; + + type = typ; + flags = fl; + + m_hasVal = false; + } + + // can't use union easily here, so just store all possible data fields, we + // don't waste much (might still use union later if the number of supported + // types increases, so always use the accessor functions and don't access + // the fields directly!) + + void Check(wxCmdLineParamType WXUNUSED_UNLESS_DEBUG(typ)) const + { + wxASSERT_MSG( type == typ, _T("type mismatch in wxCmdLineOption") ); + } + + long GetLongVal() const + { Check(wxCMD_LINE_VAL_NUMBER); return m_longVal; } + const wxString& GetStrVal() const + { Check(wxCMD_LINE_VAL_STRING); return m_strVal; } +#if wxUSE_DATETIME + const wxDateTime& GetDateVal() const + { Check(wxCMD_LINE_VAL_DATE); return m_dateVal; } +#endif // wxUSE_DATETIME + + void SetLongVal(long val) + { Check(wxCMD_LINE_VAL_NUMBER); m_longVal = val; m_hasVal = true; } + void SetStrVal(const wxString& val) + { Check(wxCMD_LINE_VAL_STRING); m_strVal = val; m_hasVal = true; } +#if wxUSE_DATETIME + void SetDateVal(const wxDateTime& val) + { Check(wxCMD_LINE_VAL_DATE); m_dateVal = val; m_hasVal = true; } +#endif // wxUSE_DATETIME + + void SetHasValue(bool hasValue = true) { m_hasVal = hasValue; } + bool HasValue() const { return m_hasVal; } + +public: + wxCmdLineEntryType kind; + wxString shortName, + longName, + description; + wxCmdLineParamType type; + int flags; + +private: + bool m_hasVal; + + long m_longVal; + wxString m_strVal; +#if wxUSE_DATETIME + wxDateTime m_dateVal; +#endif // wxUSE_DATETIME +}; + +struct wxCmdLineParam +{ + wxCmdLineParam(const wxString& desc, + wxCmdLineParamType typ, + int fl) + : description(desc) + { + type = typ; + flags = fl; + } + + wxString description; + wxCmdLineParamType type; + int flags; +}; + +WX_DECLARE_OBJARRAY(wxCmdLineOption, wxArrayOptions); +WX_DECLARE_OBJARRAY(wxCmdLineParam, wxArrayParams); + +#include "wx/arrimpl.cpp" + +WX_DEFINE_OBJARRAY(wxArrayOptions) +WX_DEFINE_OBJARRAY(wxArrayParams) + +// the parser internal state +struct wxCmdLineParserData +{ + // options + wxString m_switchChars; // characters which may start an option + bool m_enableLongOptions; // true if long options are enabled + wxString m_logo; // some extra text to show in Usage() + + // cmd line data + wxArrayString m_arguments; // == argv, argc == m_arguments.GetCount() + wxArrayOptions m_options; // all possible options and switchrs + wxArrayParams m_paramDesc; // description of all possible params + wxArrayString m_parameters; // all params found + + // methods + wxCmdLineParserData(); + void SetArguments(int argc, char **argv); +#if wxUSE_UNICODE + void SetArguments(int argc, wxChar **argv); +#endif // wxUSE_UNICODE + void SetArguments(const wxString& cmdline); + + int FindOption(const wxString& name); + int FindOptionByLongName(const wxString& name); +}; + +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// wxCmdLineParserData +// ---------------------------------------------------------------------------- + +wxCmdLineParserData::wxCmdLineParserData() +{ + m_enableLongOptions = true; +#ifdef __UNIX_LIKE__ + m_switchChars = _T("-"); +#else // !Unix + m_switchChars = _T("/-"); +#endif +} + +void wxCmdLineParserData::SetArguments(int argc, char **argv) +{ + m_arguments.clear(); + + for ( int n = 0; n < argc; n++ ) + { + m_arguments.push_back(wxString::FromAscii(argv[n])); + } +} + +#if wxUSE_UNICODE + +void wxCmdLineParserData::SetArguments(int argc, wxChar **argv) +{ + m_arguments.clear(); + + for ( int n = 0; n < argc; n++ ) + { + m_arguments.push_back(argv[n]); + } +} + +#endif // wxUSE_UNICODE + +void wxCmdLineParserData::SetArguments(const wxString& cmdLine) +{ + m_arguments.clear(); + + if(wxTheApp && wxTheApp->argc > 0) + m_arguments.push_back(wxTheApp->argv[0]); + else + m_arguments.push_back(wxEmptyString); + + wxArrayString args = wxCmdLineParser::ConvertStringToArgs(cmdLine); + + WX_APPEND_ARRAY(m_arguments, args); +} + +int wxCmdLineParserData::FindOption(const wxString& name) +{ + if ( !name.empty() ) + { + size_t count = m_options.GetCount(); + for ( size_t n = 0; n < count; n++ ) + { + if ( m_options[n].shortName == name ) + { + // found + return n; + } + } + } + + return wxNOT_FOUND; +} + +int wxCmdLineParserData::FindOptionByLongName(const wxString& name) +{ + size_t count = m_options.GetCount(); + for ( size_t n = 0; n < count; n++ ) + { + if ( m_options[n].longName == name ) + { + // found + return n; + } + } + + return wxNOT_FOUND; +} + +// ---------------------------------------------------------------------------- +// construction and destruction +// ---------------------------------------------------------------------------- + +void wxCmdLineParser::Init() +{ + m_data = new wxCmdLineParserData; +} + +void wxCmdLineParser::SetCmdLine(int argc, char **argv) +{ + m_data->SetArguments(argc, argv); +} + +#if wxUSE_UNICODE + +void wxCmdLineParser::SetCmdLine(int argc, wxChar **argv) +{ + m_data->SetArguments(argc, argv); +} + +#endif // wxUSE_UNICODE + +void wxCmdLineParser::SetCmdLine(const wxString& cmdline) +{ + m_data->SetArguments(cmdline); +} + +wxCmdLineParser::~wxCmdLineParser() +{ + delete m_data; +} + +// ---------------------------------------------------------------------------- +// options +// ---------------------------------------------------------------------------- + +void wxCmdLineParser::SetSwitchChars(const wxString& switchChars) +{ + m_data->m_switchChars = switchChars; +} + +void wxCmdLineParser::EnableLongOptions(bool enable) +{ + m_data->m_enableLongOptions = enable; +} + +bool wxCmdLineParser::AreLongOptionsEnabled() +{ + return m_data->m_enableLongOptions; +} + +void wxCmdLineParser::SetLogo(const wxString& logo) +{ + m_data->m_logo = logo; +} + +// ---------------------------------------------------------------------------- +// command line construction +// ---------------------------------------------------------------------------- + +void wxCmdLineParser::SetDesc(const wxCmdLineEntryDesc *desc) +{ + for ( ;; desc++ ) + { + switch ( desc->kind ) + { + case wxCMD_LINE_SWITCH: + AddSwitch(desc->shortName, desc->longName, desc->description, + desc->flags); + break; + + case wxCMD_LINE_OPTION: + AddOption(desc->shortName, desc->longName, desc->description, + desc->type, desc->flags); + break; + + case wxCMD_LINE_PARAM: + AddParam(desc->description, desc->type, desc->flags); + break; + + default: + wxFAIL_MSG( _T("unknown command line entry type") ); + // still fall through + + case wxCMD_LINE_NONE: + return; + } + } +} + +void wxCmdLineParser::AddSwitch(const wxString& shortName, + const wxString& longName, + const wxString& desc, + int flags) +{ + wxASSERT_MSG( m_data->FindOption(shortName) == wxNOT_FOUND, + _T("duplicate switch") ); + + wxCmdLineOption *option = new wxCmdLineOption(wxCMD_LINE_SWITCH, + shortName, longName, desc, + wxCMD_LINE_VAL_NONE, flags); + + m_data->m_options.Add(option); +} + +void wxCmdLineParser::AddOption(const wxString& shortName, + const wxString& longName, + const wxString& desc, + wxCmdLineParamType type, + int flags) +{ + wxASSERT_MSG( m_data->FindOption(shortName) == wxNOT_FOUND, + _T("duplicate option") ); + + wxCmdLineOption *option = new wxCmdLineOption(wxCMD_LINE_OPTION, + shortName, longName, desc, + type, flags); + + m_data->m_options.Add(option); +} + +void wxCmdLineParser::AddParam(const wxString& desc, + wxCmdLineParamType type, + int flags) +{ + // do some consistency checks: a required parameter can't follow an + // optional one and nothing should follow a parameter with MULTIPLE flag +#ifdef __WXDEBUG__ + if ( !m_data->m_paramDesc.IsEmpty() ) + { + wxCmdLineParam& param = m_data->m_paramDesc.Last(); + + wxASSERT_MSG( !(param.flags & wxCMD_LINE_PARAM_MULTIPLE), + _T("all parameters after the one with wxCMD_LINE_PARAM_MULTIPLE style will be ignored") ); + + if ( !(flags & wxCMD_LINE_PARAM_OPTIONAL) ) + { + wxASSERT_MSG( !(param.flags & wxCMD_LINE_PARAM_OPTIONAL), + _T("a required parameter can't follow an optional one") ); + } + } +#endif // Debug + + wxCmdLineParam *param = new wxCmdLineParam(desc, type, flags); + + m_data->m_paramDesc.Add(param); +} + +// ---------------------------------------------------------------------------- +// access to parse command line +// ---------------------------------------------------------------------------- + +bool wxCmdLineParser::Found(const wxString& name) const +{ + int i = m_data->FindOption(name); + if ( i == wxNOT_FOUND ) + i = m_data->FindOptionByLongName(name); + + wxCHECK_MSG( i != wxNOT_FOUND, false, _T("unknown switch") ); + + wxCmdLineOption& opt = m_data->m_options[(size_t)i]; + if ( !opt.HasValue() ) + return false; + + return true; +} + +bool wxCmdLineParser::Found(const wxString& name, wxString *value) const +{ + int i = m_data->FindOption(name); + if ( i == wxNOT_FOUND ) + i = m_data->FindOptionByLongName(name); + + wxCHECK_MSG( i != wxNOT_FOUND, false, _T("unknown option") ); + + wxCmdLineOption& opt = m_data->m_options[(size_t)i]; + if ( !opt.HasValue() ) + return false; + + wxCHECK_MSG( value, false, _T("NULL pointer in wxCmdLineOption::Found") ); + + *value = opt.GetStrVal(); + + return true; +} + +bool wxCmdLineParser::Found(const wxString& name, long *value) const +{ + int i = m_data->FindOption(name); + if ( i == wxNOT_FOUND ) + i = m_data->FindOptionByLongName(name); + + wxCHECK_MSG( i != wxNOT_FOUND, false, _T("unknown option") ); + + wxCmdLineOption& opt = m_data->m_options[(size_t)i]; + if ( !opt.HasValue() ) + return false; + + wxCHECK_MSG( value, false, _T("NULL pointer in wxCmdLineOption::Found") ); + + *value = opt.GetLongVal(); + + return true; +} + +#if wxUSE_DATETIME +bool wxCmdLineParser::Found(const wxString& name, wxDateTime *value) const +{ + int i = m_data->FindOption(name); + if ( i == wxNOT_FOUND ) + i = m_data->FindOptionByLongName(name); + + wxCHECK_MSG( i != wxNOT_FOUND, false, _T("unknown option") ); + + wxCmdLineOption& opt = m_data->m_options[(size_t)i]; + if ( !opt.HasValue() ) + return false; + + wxCHECK_MSG( value, false, _T("NULL pointer in wxCmdLineOption::Found") ); + + *value = opt.GetDateVal(); + + return true; +} +#endif // wxUSE_DATETIME + +size_t wxCmdLineParser::GetParamCount() const +{ + return m_data->m_parameters.size(); +} + +wxString wxCmdLineParser::GetParam(size_t n) const +{ + wxCHECK_MSG( n < GetParamCount(), wxEmptyString, _T("invalid param index") ); + + return m_data->m_parameters[n]; +} + +// Resets switches and options +void wxCmdLineParser::Reset() +{ + for ( size_t i = 0; i < m_data->m_options.Count(); i++ ) + { + wxCmdLineOption& opt = m_data->m_options[i]; + opt.SetHasValue(false); + } +} + + +// ---------------------------------------------------------------------------- +// the real work is done here +// ---------------------------------------------------------------------------- + +int wxCmdLineParser::Parse(bool showUsage) +{ + bool maybeOption = true; // can the following arg be an option? + bool ok = true; // true until an error is detected + bool helpRequested = false; // true if "-h" was given + bool hadRepeatableParam = false; // true if found param with MULTIPLE flag + + size_t currentParam = 0; // the index in m_paramDesc + + size_t countParam = m_data->m_paramDesc.GetCount(); + wxString errorMsg; + + Reset(); + + // parse everything + wxString arg; + size_t count = m_data->m_arguments.size(); + for ( size_t n = 1; ok && (n < count); n++ ) // 0 is program name + { + arg = m_data->m_arguments[n]; + + // special case: "--" should be discarded and all following arguments + // should be considered as parameters, even if they start with '-' and + // not like options (this is POSIX-like) + if ( arg == _T("--") ) + { + maybeOption = false; + + continue; + } + + // empty argument or just '-' is not an option but a parameter + if ( maybeOption && arg.length() > 1 && + wxStrchr(m_data->m_switchChars, arg[0u]) ) + { + bool isLong; + wxString name; + int optInd = wxNOT_FOUND; // init to suppress warnings + + // an option or a switch: find whether it's a long or a short one + if ( arg[0u] == _T('-') && arg[1u] == _T('-') ) + { + // a long one + isLong = true; + + // Skip leading "--" + const wxChar *p = arg.c_str() + 2; + + bool longOptionsEnabled = AreLongOptionsEnabled(); + + name = GetLongOptionName(p); + + if (longOptionsEnabled) + { + optInd = m_data->FindOptionByLongName(name); + if ( optInd == wxNOT_FOUND ) + { + errorMsg << wxString::Format(_("Unknown long option '%s'"), name.c_str()) + << _T('\n'); + } + } + else + { + optInd = wxNOT_FOUND; // Sanity check + + // Print the argument including leading "--" + name.Prepend( wxT("--") ); + errorMsg << wxString::Format(_("Unknown option '%s'"), name.c_str()) + << _T('\n'); + } + + } + else // not a long option + { + isLong = false; + + // a short one: as they can be cumulated, we try to find the + // longest substring which is a valid option + const wxChar *p = arg.c_str() + 1; + + name = GetShortOptionName(p); + + size_t len = name.length(); + do + { + if ( len == 0 ) + { + // we couldn't find a valid option name in the + // beginning of this string + errorMsg << wxString::Format(_("Unknown option '%s'"), name.c_str()) + << _T('\n'); + + break; + } + else + { + optInd = m_data->FindOption(name.Left(len)); + + // will try with one character less the next time + len--; + } + } + while ( optInd == wxNOT_FOUND ); + + len++; // compensates extra len-- above + if ( (optInd != wxNOT_FOUND) && (len != name.length()) ) + { + // first of all, the option name is only part of this + // string + name = name.Left(len); + + // our option is only part of this argument, there is + // something else in it - it is either the value of this + // option or other switches if it is a switch + if ( m_data->m_options[(size_t)optInd].kind + == wxCMD_LINE_SWITCH ) + { + // pretend that all the rest of the argument is the + // next argument, in fact + wxString arg2 = arg[0u]; + arg2 += arg.Mid(len + 1); // +1 for leading '-' + + m_data->m_arguments.insert + (m_data->m_arguments.begin() + n + 1, arg2); + count++; + } + //else: it's our value, we'll deal with it below + } + } + + if ( optInd == wxNOT_FOUND ) + { + ok = false; + + continue; // will break, in fact + } + + // look at what follows: + + // +1 for leading '-' + const wxChar *p = arg.c_str() + 1 + name.length(); + if ( isLong ) + p++; // for another leading '-' + + wxCmdLineOption& opt = m_data->m_options[(size_t)optInd]; + if ( opt.kind == wxCMD_LINE_SWITCH ) + { + // we must check that there is no value following the switch + if ( *p != _T('\0') ) + { + errorMsg << wxString::Format(_("Unexpected characters following option '%s'."), name.c_str()) + << _T('\n'); + ok = false; + } + else // no value, as expected + { + // nothing more to do + opt.SetHasValue(); + + if ( opt.flags & wxCMD_LINE_OPTION_HELP ) + { + helpRequested = true; + + // it's not an error, but we still stop here + ok = false; + } + } + } + else // it's an option. not a switch + { + // get the value + if ( isLong ) + { + if ( *p++ != _T('=') ) + { + errorMsg << wxString::Format(_("Option '%s' requires a value, '=' expected."), name.c_str()) + << _T('\n'); + + ok = false; + } + } + else // short option + { + switch ( *p ) + { + case _T('='): + case _T(':'): + // the value follows + p++; + break; + + case 0: + // the value is in the next argument + if ( ++n == count ) + { + // ... but there is none + errorMsg << wxString::Format(_("Option '%s' requires a value."), + name.c_str()) + << _T('\n'); + + ok = false; + } + else + { + // ... take it from there + p = m_data->m_arguments[n].c_str(); + } + break; + + default: + // the value is right here: this may be legal or + // not depending on the option style + if ( opt.flags & wxCMD_LINE_NEEDS_SEPARATOR ) + { + errorMsg << wxString::Format(_("Separator expected after the option '%s'."), + name.c_str()) + << _T('\n'); + + ok = false; + } + } + } + + if ( ok ) + { + wxString value = p; + switch ( opt.type ) + { + default: + wxFAIL_MSG( _T("unknown option type") ); + // still fall through + + case wxCMD_LINE_VAL_STRING: + opt.SetStrVal(value); + break; + + case wxCMD_LINE_VAL_NUMBER: + { + long val; + if ( value.ToLong(&val) ) + { + opt.SetLongVal(val); + } + else + { + errorMsg << wxString::Format(_("'%s' is not a correct numeric value for option '%s'."), + value.c_str(), name.c_str()) + << _T('\n'); + + ok = false; + } + } + break; + +#if wxUSE_DATETIME + case wxCMD_LINE_VAL_DATE: + { + wxDateTime dt; + const wxChar *res = dt.ParseDate(value); + if ( !res || *res ) + { + errorMsg << wxString::Format(_("Option '%s': '%s' cannot be converted to a date."), + name.c_str(), value.c_str()) + << _T('\n'); + + ok = false; + } + else + { + opt.SetDateVal(dt); + } + } + break; +#endif // wxUSE_DATETIME + } + } + } + } + else // not an option, must be a parameter + { + if ( currentParam < countParam ) + { + wxCmdLineParam& param = m_data->m_paramDesc[currentParam]; + + // TODO check the param type + + m_data->m_parameters.push_back(arg); + + if ( !(param.flags & wxCMD_LINE_PARAM_MULTIPLE) ) + { + currentParam++; + } + else + { + wxASSERT_MSG( currentParam == countParam - 1, + _T("all parameters after the one with wxCMD_LINE_PARAM_MULTIPLE style are ignored") ); + + // remember that we did have this last repeatable parameter + hadRepeatableParam = true; + } + } + else + { + errorMsg << wxString::Format(_("Unexpected parameter '%s'"), arg.c_str()) + << _T('\n'); + + ok = false; + } + } + } + + // verify that all mandatory options were given + if ( ok ) + { + size_t countOpt = m_data->m_options.GetCount(); + for ( size_t n = 0; ok && (n < countOpt); n++ ) + { + wxCmdLineOption& opt = m_data->m_options[n]; + if ( (opt.flags & wxCMD_LINE_OPTION_MANDATORY) && !opt.HasValue() ) + { + wxString optName; + if ( !opt.longName ) + { + optName = opt.shortName; + } + else + { + if ( AreLongOptionsEnabled() ) + { + optName.Printf( _("%s (or %s)"), + opt.shortName.c_str(), + opt.longName.c_str() ); + } + else + { + optName.Printf( wxT("%s"), + opt.shortName.c_str() ); + } + } + + errorMsg << wxString::Format(_("The value for the option '%s' must be specified."), + optName.c_str()) + << _T('\n'); + + ok = false; + } + } + + for ( ; ok && (currentParam < countParam); currentParam++ ) + { + wxCmdLineParam& param = m_data->m_paramDesc[currentParam]; + if ( (currentParam == countParam - 1) && + (param.flags & wxCMD_LINE_PARAM_MULTIPLE) && + hadRepeatableParam ) + { + // special case: currentParam wasn't incremented, but we did + // have it, so don't give error + continue; + } + + if ( !(param.flags & wxCMD_LINE_PARAM_OPTIONAL) ) + { + errorMsg << wxString::Format(_("The required parameter '%s' was not specified."), + param.description.c_str()) + << _T('\n'); + + ok = false; + } + } + } + + // if there was an error during parsing the command line, show this error + // and also the usage message if it had been requested + if ( !ok && (!errorMsg.empty() || (helpRequested && showUsage)) ) + { + wxMessageOutput* msgOut = wxMessageOutput::Get(); + if ( msgOut ) + { + wxString usage; + if ( showUsage ) + usage = GetUsageString(); + + msgOut->Printf( wxT("%s%s"), usage.c_str(), errorMsg.c_str() ); + } + else + { + wxFAIL_MSG( _T("no wxMessageOutput object?") ); + } + } + + return ok ? 0 : helpRequested ? -1 : 1; +} + +// ---------------------------------------------------------------------------- +// give the usage message +// ---------------------------------------------------------------------------- + +void wxCmdLineParser::Usage() +{ + wxMessageOutput* msgOut = wxMessageOutput::Get(); + if ( msgOut ) + { + msgOut->Printf( wxT("%s"), GetUsageString().c_str() ); + } + else + { + wxFAIL_MSG( _T("no wxMessageOutput object?") ); + } +} + +wxString wxCmdLineParser::GetUsageString() +{ + wxString appname; + if ( m_data->m_arguments.empty() ) + { + if ( wxTheApp ) + appname = wxTheApp->GetAppName(); + } + else // use argv[0] + { + appname = wxFileName(m_data->m_arguments[0]).GetName(); + } + + // we construct the brief cmd line desc on the fly, but not the detailed + // help message below because we want to align the options descriptions + // and for this we must first know the longest one of them + wxString usage; + wxArrayString namesOptions, descOptions; + + if ( !m_data->m_logo.empty() ) + { + usage << m_data->m_logo << _T('\n'); + } + + usage << wxString::Format(_("Usage: %s"), appname.c_str()); + + // the switch char is usually '-' but this can be changed with + // SetSwitchChars() and then the first one of possible chars is used + wxChar chSwitch = !m_data->m_switchChars ? _T('-') + : m_data->m_switchChars[0u]; + + bool areLongOptionsEnabled = AreLongOptionsEnabled(); + size_t n, count = m_data->m_options.GetCount(); + for ( n = 0; n < count; n++ ) + { + wxCmdLineOption& opt = m_data->m_options[n]; + + usage << _T(' '); + if ( !(opt.flags & wxCMD_LINE_OPTION_MANDATORY) ) + { + usage << _T('['); + } + + if ( !opt.shortName.empty() ) + { + usage << chSwitch << opt.shortName; + } + else if ( areLongOptionsEnabled && !opt.longName.empty() ) + { + usage << _T("--") << opt.longName; + } + else + { + if (!opt.longName.empty()) + { + wxFAIL_MSG( wxT("option with only a long name while long ") + wxT("options are disabled") ); + } + else + { + wxFAIL_MSG( _T("option without neither short nor long name") ); + } + } + + wxString option; + + if ( !opt.shortName.empty() ) + { + option << _T(" ") << chSwitch << opt.shortName; + } + + if ( areLongOptionsEnabled && !opt.longName.empty() ) + { + option << (option.empty() ? _T(" ") : _T(", ")) + << _T("--") << opt.longName; + } + + if ( opt.kind != wxCMD_LINE_SWITCH ) + { + wxString val; + val << _T('<') << GetTypeName(opt.type) << _T('>'); + usage << _T(' ') << val; + option << (!opt.longName ? _T(':') : _T('=')) << val; + } + + if ( !(opt.flags & wxCMD_LINE_OPTION_MANDATORY) ) + { + usage << _T(']'); + } + + namesOptions.push_back(option); + descOptions.push_back(opt.description); + } + + count = m_data->m_paramDesc.GetCount(); + for ( n = 0; n < count; n++ ) + { + wxCmdLineParam& param = m_data->m_paramDesc[n]; + + usage << _T(' '); + if ( param.flags & wxCMD_LINE_PARAM_OPTIONAL ) + { + usage << _T('['); + } + + usage << param.description; + + if ( param.flags & wxCMD_LINE_PARAM_MULTIPLE ) + { + usage << _T("..."); + } + + if ( param.flags & wxCMD_LINE_PARAM_OPTIONAL ) + { + usage << _T(']'); + } + } + + usage << _T('\n'); + + // now construct the detailed help message + size_t len, lenMax = 0; + count = namesOptions.size(); + for ( n = 0; n < count; n++ ) + { + len = namesOptions[n].length(); + if ( len > lenMax ) + lenMax = len; + } + + for ( n = 0; n < count; n++ ) + { + len = namesOptions[n].length(); + usage << namesOptions[n] + << wxString(_T(' '), lenMax - len) << _T('\t') + << descOptions[n] + << _T('\n'); + } + + return usage; +} + +// ---------------------------------------------------------------------------- +// private functions +// ---------------------------------------------------------------------------- + +static wxString GetTypeName(wxCmdLineParamType type) +{ + wxString s; + switch ( type ) + { + default: + wxFAIL_MSG( _T("unknown option type") ); + // still fall through + + case wxCMD_LINE_VAL_STRING: + s = _("str"); + break; + + case wxCMD_LINE_VAL_NUMBER: + s = _("num"); + break; + + case wxCMD_LINE_VAL_DATE: + s = _("date"); + break; + } + + return s; +} + +/* +Returns a string which is equal to the string pointed to by p, but up to the +point where p contains an character that's not allowed. +Allowable characters are letters and numbers, and characters pointed to by +the parameter allowedChars. + +For example, if p points to "abcde-@-_", and allowedChars is "-_", +this function returns "abcde-". +*/ +static wxString GetOptionName(const wxChar *p, + const wxChar *allowedChars) +{ + wxString argName; + + while ( *p && (wxIsalnum(*p) || wxStrchr(allowedChars, *p)) ) + { + argName += *p++; + } + + return argName; +} + +// Besides alphanumeric characters, short and long options can +// have other characters. + +// A short option additionally can have these +#define wxCMD_LINE_CHARS_ALLOWED_BY_SHORT_OPTION wxT("_?") + +// A long option can have the same characters as a short option and a '-'. +#define wxCMD_LINE_CHARS_ALLOWED_BY_LONG_OPTION \ + wxCMD_LINE_CHARS_ALLOWED_BY_SHORT_OPTION wxT("-") + +static wxString GetShortOptionName(const wxChar *p) +{ + return GetOptionName(p, wxCMD_LINE_CHARS_ALLOWED_BY_SHORT_OPTION); +} + +static wxString GetLongOptionName(const wxChar *p) +{ + return GetOptionName(p, wxCMD_LINE_CHARS_ALLOWED_BY_LONG_OPTION); +} + +#endif // wxUSE_CMDLINE_PARSER + +// ---------------------------------------------------------------------------- +// global functions +// ---------------------------------------------------------------------------- + +/* + This function is mainly used under Windows (as under Unix we always get the + command line arguments as argc/argv anyhow) and so it tries to follow + Windows conventions for the command line handling, not Unix ones. For + instance, backslash is not special except when it precedes double quote when + it does quote it. + */ + +/* static */ +wxArrayString wxCmdLineParser::ConvertStringToArgs(const wxChar *p) +{ + wxArrayString args; + + wxString arg; + arg.reserve(1024); + + bool isInsideQuotes = false; + for ( ;; ) + { + // skip white space + while ( *p == _T(' ') || *p == _T('\t') ) + p++; + + // anything left? + if ( *p == _T('\0') ) + break; + + // parse this parameter + bool endParam = false; + bool lastBS = false; + for ( arg.clear(); !endParam; p++ ) + { + switch ( *p ) + { + case _T('"'): + if ( !lastBS ) + { + isInsideQuotes = !isInsideQuotes; + + // don't put quote in arg + continue; + } + //else: quote has no special meaning but the backslash + // still remains -- makes no sense but this is what + // Windows does + break; + + case _T(' '): + case _T('\t'): + // backslash does *not* quote the space, only quotes do + if ( isInsideQuotes ) + { + // skip assignment below + break; + } + // fall through + + case _T('\0'): + endParam = true; + + break; + } + + if ( endParam ) + { + break; + } + + lastBS = *p == _T('\\'); + + arg += *p; + } + + args.push_back(arg); + } + + return args; +} diff --git a/Externals/wxWidgets/src/common/cmdproc.cpp b/Externals/wxWidgets/src/common/cmdproc.cpp index d51fca3610..5a2556fc30 100644 --- a/Externals/wxWidgets/src/common/cmdproc.cpp +++ b/Externals/wxWidgets/src/common/cmdproc.cpp @@ -1,325 +1,325 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: src/common/cmdproc.cpp -// Purpose: wxCommand and wxCommandProcessor classes -// Author: Julian Smart (extracted from docview.h by VZ) -// Modified by: -// Created: 05.11.00 -// RCS-ID: $Id: cmdproc.cpp 35650 2005-09-23 12:56:45Z MR $ -// Copyright: (c) wxWidgets team -// Licence: wxWindows licence -/////////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#ifndef WX_PRECOMP - #include "wx/intl.h" - #include "wx/string.h" - #include "wx/menu.h" -#endif //WX_PRECOMP - -#include "wx/cmdproc.h" - -// ============================================================================ -// implementation -// ============================================================================ - -IMPLEMENT_CLASS(wxCommand, wxObject) -IMPLEMENT_DYNAMIC_CLASS(wxCommandProcessor, wxObject) - -// ---------------------------------------------------------------------------- -// wxCommand -// ---------------------------------------------------------------------------- - -wxCommand::wxCommand(bool canUndoIt, const wxString& name) -{ - m_canUndo = canUndoIt; - m_commandName = name; -} - -// ---------------------------------------------------------------------------- -// Command processor -// ---------------------------------------------------------------------------- - -wxCommandProcessor::wxCommandProcessor(int maxCommands) -{ - m_maxNoCommands = maxCommands; -#if wxUSE_MENUS - m_commandEditMenu = (wxMenu *) NULL; -#endif // wxUSE_MENUS - m_undoAccelerator = wxT("\tCtrl+Z"); - m_redoAccelerator = wxT("\tCtrl+Y"); - - m_lastSavedCommand = - m_currentCommand = wxList::compatibility_iterator(); -} - -wxCommandProcessor::~wxCommandProcessor() -{ - ClearCommands(); -} - -bool wxCommandProcessor::DoCommand(wxCommand& cmd) -{ - return cmd.Do(); -} - -bool wxCommandProcessor::UndoCommand(wxCommand& cmd) -{ - return cmd.Undo(); -} - -// Pass a command to the processor. The processor calls Do(); -// if successful, is appended to the command history unless -// storeIt is false. -bool wxCommandProcessor::Submit(wxCommand *command, bool storeIt) -{ - wxCHECK_MSG( command, false, _T("no command in wxCommandProcessor::Submit") ); - - if ( !DoCommand(*command) ) - { - // the user code expects the command to be deleted anyhow - delete command; - - return false; - } - - if ( storeIt ) - Store(command); - else - delete command; - - return true; -} - -void wxCommandProcessor::Store(wxCommand *command) -{ - wxCHECK_RET( command, _T("no command in wxCommandProcessor::Store") ); - - if ( (int)m_commands.GetCount() == m_maxNoCommands ) - { - wxList::compatibility_iterator firstNode = m_commands.GetFirst(); - wxCommand *firstCommand = (wxCommand *)firstNode->GetData(); - delete firstCommand; - m_commands.Erase(firstNode); - - // Make sure m_lastSavedCommand won't point to freed memory - if ( m_lastSavedCommand == firstNode ) - m_lastSavedCommand = wxList::compatibility_iterator(); - } - - // Correct a bug: we must chop off the current 'branch' - // so that we're at the end of the command list. - if (!m_currentCommand) - ClearCommands(); - else - { - wxList::compatibility_iterator node = m_currentCommand->GetNext(); - while (node) - { - wxList::compatibility_iterator next = node->GetNext(); - delete (wxCommand *)node->GetData(); - m_commands.Erase(node); - - // Make sure m_lastSavedCommand won't point to freed memory - if ( m_lastSavedCommand == node ) - m_lastSavedCommand = wxList::compatibility_iterator(); - - node = next; - } - } - - m_commands.Append(command); - m_currentCommand = m_commands.GetLast(); - SetMenuStrings(); -} - -bool wxCommandProcessor::Undo() -{ - wxCommand *command = GetCurrentCommand(); - if ( command && command->CanUndo() ) - { - if ( UndoCommand(*command) ) - { - m_currentCommand = m_currentCommand->GetPrevious(); - SetMenuStrings(); - return true; - } - } - - return false; -} - -bool wxCommandProcessor::Redo() -{ - wxCommand *redoCommand = (wxCommand *) NULL; - wxList::compatibility_iterator redoNode -#if !wxUSE_STL - = NULL // just to avoid warnings -#endif // !wxUSE_STL - ; - - if ( m_currentCommand ) - { - // is there anything to redo? - if ( m_currentCommand->GetNext() ) - { - redoCommand = (wxCommand *)m_currentCommand->GetNext()->GetData(); - redoNode = m_currentCommand->GetNext(); - } - } - else // no current command, redo the first one - { - if (m_commands.GetCount() > 0) - { - redoCommand = (wxCommand *)m_commands.GetFirst()->GetData(); - redoNode = m_commands.GetFirst(); - } - } - - if (redoCommand) - { - bool success = DoCommand(*redoCommand); - if (success) - { - m_currentCommand = redoNode; - SetMenuStrings(); - return true; - } - } - return false; -} - -bool wxCommandProcessor::CanUndo() const -{ - wxCommand *command = GetCurrentCommand(); - - return command && command->CanUndo(); -} - -bool wxCommandProcessor::CanRedo() const -{ - if (m_currentCommand && !m_currentCommand->GetNext()) - return false; - - if (m_currentCommand && m_currentCommand->GetNext()) - return true; - - if (!m_currentCommand && (m_commands.GetCount() > 0)) - return true; - - return false; -} - -void wxCommandProcessor::Initialize() -{ - m_currentCommand = m_commands.GetLast(); - SetMenuStrings(); -} - -void wxCommandProcessor::SetMenuStrings() -{ -#if wxUSE_MENUS - if (m_commandEditMenu) - { - wxString undoLabel = GetUndoMenuLabel(); - wxString redoLabel = GetRedoMenuLabel(); - - m_commandEditMenu->SetLabel(wxID_UNDO, undoLabel); - m_commandEditMenu->Enable(wxID_UNDO, CanUndo()); - - m_commandEditMenu->SetLabel(wxID_REDO, redoLabel); - m_commandEditMenu->Enable(wxID_REDO, CanRedo()); - } -#endif // wxUSE_MENUS -} - -// Gets the current Undo menu label. -wxString wxCommandProcessor::GetUndoMenuLabel() const -{ - wxString buf; - if (m_currentCommand) - { - wxCommand *command = (wxCommand *)m_currentCommand->GetData(); - wxString commandName(command->GetName()); - if (commandName.empty()) commandName = _("Unnamed command"); - bool canUndo = command->CanUndo(); - if (canUndo) - buf = wxString(_("&Undo ")) + commandName + m_undoAccelerator; - else - buf = wxString(_("Can't &Undo ")) + commandName + m_undoAccelerator; - } - else - { - buf = _("&Undo") + m_undoAccelerator; - } - - return buf; -} - -// Gets the current Undo menu label. -wxString wxCommandProcessor::GetRedoMenuLabel() const -{ - wxString buf; - if (m_currentCommand) - { - // We can redo, if we're not at the end of the history. - if (m_currentCommand->GetNext()) - { - wxCommand *redoCommand = (wxCommand *)m_currentCommand->GetNext()->GetData(); - wxString redoCommandName(redoCommand->GetName()); - if (redoCommandName.empty()) redoCommandName = _("Unnamed command"); - buf = wxString(_("&Redo ")) + redoCommandName + m_redoAccelerator; - } - else - { - buf = _("&Redo") + m_redoAccelerator; - } - } - else - { - if (m_commands.GetCount() == 0) - { - buf = _("&Redo") + m_redoAccelerator; - } - else - { - // currentCommand is NULL but there are commands: this means that - // we've undone to the start of the list, but can redo the first. - wxCommand *redoCommand = (wxCommand *)m_commands.GetFirst()->GetData(); - wxString redoCommandName(redoCommand->GetName()); - if (redoCommandName.empty()) redoCommandName = _("Unnamed command"); - buf = wxString(_("&Redo ")) + redoCommandName + m_redoAccelerator; - } - } - return buf; -} - -void wxCommandProcessor::ClearCommands() -{ - wxList::compatibility_iterator node = m_commands.GetFirst(); - while (node) - { - wxCommand *command = (wxCommand *)node->GetData(); - delete command; - m_commands.Erase(node); - node = m_commands.GetFirst(); - } - - m_currentCommand = wxList::compatibility_iterator(); - m_lastSavedCommand = wxList::compatibility_iterator(); -} - - +/////////////////////////////////////////////////////////////////////////////// +// Name: src/common/cmdproc.cpp +// Purpose: wxCommand and wxCommandProcessor classes +// Author: Julian Smart (extracted from docview.h by VZ) +// Modified by: +// Created: 05.11.00 +// RCS-ID: $Id: cmdproc.cpp 35650 2005-09-23 12:56:45Z MR $ +// Copyright: (c) wxWidgets team +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#ifndef WX_PRECOMP + #include "wx/intl.h" + #include "wx/string.h" + #include "wx/menu.h" +#endif //WX_PRECOMP + +#include "wx/cmdproc.h" + +// ============================================================================ +// implementation +// ============================================================================ + +IMPLEMENT_CLASS(wxCommand, wxObject) +IMPLEMENT_DYNAMIC_CLASS(wxCommandProcessor, wxObject) + +// ---------------------------------------------------------------------------- +// wxCommand +// ---------------------------------------------------------------------------- + +wxCommand::wxCommand(bool canUndoIt, const wxString& name) +{ + m_canUndo = canUndoIt; + m_commandName = name; +} + +// ---------------------------------------------------------------------------- +// Command processor +// ---------------------------------------------------------------------------- + +wxCommandProcessor::wxCommandProcessor(int maxCommands) +{ + m_maxNoCommands = maxCommands; +#if wxUSE_MENUS + m_commandEditMenu = (wxMenu *) NULL; +#endif // wxUSE_MENUS + m_undoAccelerator = wxT("\tCtrl+Z"); + m_redoAccelerator = wxT("\tCtrl+Y"); + + m_lastSavedCommand = + m_currentCommand = wxList::compatibility_iterator(); +} + +wxCommandProcessor::~wxCommandProcessor() +{ + ClearCommands(); +} + +bool wxCommandProcessor::DoCommand(wxCommand& cmd) +{ + return cmd.Do(); +} + +bool wxCommandProcessor::UndoCommand(wxCommand& cmd) +{ + return cmd.Undo(); +} + +// Pass a command to the processor. The processor calls Do(); +// if successful, is appended to the command history unless +// storeIt is false. +bool wxCommandProcessor::Submit(wxCommand *command, bool storeIt) +{ + wxCHECK_MSG( command, false, _T("no command in wxCommandProcessor::Submit") ); + + if ( !DoCommand(*command) ) + { + // the user code expects the command to be deleted anyhow + delete command; + + return false; + } + + if ( storeIt ) + Store(command); + else + delete command; + + return true; +} + +void wxCommandProcessor::Store(wxCommand *command) +{ + wxCHECK_RET( command, _T("no command in wxCommandProcessor::Store") ); + + if ( (int)m_commands.GetCount() == m_maxNoCommands ) + { + wxList::compatibility_iterator firstNode = m_commands.GetFirst(); + wxCommand *firstCommand = (wxCommand *)firstNode->GetData(); + delete firstCommand; + m_commands.Erase(firstNode); + + // Make sure m_lastSavedCommand won't point to freed memory + if ( m_lastSavedCommand == firstNode ) + m_lastSavedCommand = wxList::compatibility_iterator(); + } + + // Correct a bug: we must chop off the current 'branch' + // so that we're at the end of the command list. + if (!m_currentCommand) + ClearCommands(); + else + { + wxList::compatibility_iterator node = m_currentCommand->GetNext(); + while (node) + { + wxList::compatibility_iterator next = node->GetNext(); + delete (wxCommand *)node->GetData(); + m_commands.Erase(node); + + // Make sure m_lastSavedCommand won't point to freed memory + if ( m_lastSavedCommand == node ) + m_lastSavedCommand = wxList::compatibility_iterator(); + + node = next; + } + } + + m_commands.Append(command); + m_currentCommand = m_commands.GetLast(); + SetMenuStrings(); +} + +bool wxCommandProcessor::Undo() +{ + wxCommand *command = GetCurrentCommand(); + if ( command && command->CanUndo() ) + { + if ( UndoCommand(*command) ) + { + m_currentCommand = m_currentCommand->GetPrevious(); + SetMenuStrings(); + return true; + } + } + + return false; +} + +bool wxCommandProcessor::Redo() +{ + wxCommand *redoCommand = (wxCommand *) NULL; + wxList::compatibility_iterator redoNode +#if !wxUSE_STL + = NULL // just to avoid warnings +#endif // !wxUSE_STL + ; + + if ( m_currentCommand ) + { + // is there anything to redo? + if ( m_currentCommand->GetNext() ) + { + redoCommand = (wxCommand *)m_currentCommand->GetNext()->GetData(); + redoNode = m_currentCommand->GetNext(); + } + } + else // no current command, redo the first one + { + if (m_commands.GetCount() > 0) + { + redoCommand = (wxCommand *)m_commands.GetFirst()->GetData(); + redoNode = m_commands.GetFirst(); + } + } + + if (redoCommand) + { + bool success = DoCommand(*redoCommand); + if (success) + { + m_currentCommand = redoNode; + SetMenuStrings(); + return true; + } + } + return false; +} + +bool wxCommandProcessor::CanUndo() const +{ + wxCommand *command = GetCurrentCommand(); + + return command && command->CanUndo(); +} + +bool wxCommandProcessor::CanRedo() const +{ + if (m_currentCommand && !m_currentCommand->GetNext()) + return false; + + if (m_currentCommand && m_currentCommand->GetNext()) + return true; + + if (!m_currentCommand && (m_commands.GetCount() > 0)) + return true; + + return false; +} + +void wxCommandProcessor::Initialize() +{ + m_currentCommand = m_commands.GetLast(); + SetMenuStrings(); +} + +void wxCommandProcessor::SetMenuStrings() +{ +#if wxUSE_MENUS + if (m_commandEditMenu) + { + wxString undoLabel = GetUndoMenuLabel(); + wxString redoLabel = GetRedoMenuLabel(); + + m_commandEditMenu->SetLabel(wxID_UNDO, undoLabel); + m_commandEditMenu->Enable(wxID_UNDO, CanUndo()); + + m_commandEditMenu->SetLabel(wxID_REDO, redoLabel); + m_commandEditMenu->Enable(wxID_REDO, CanRedo()); + } +#endif // wxUSE_MENUS +} + +// Gets the current Undo menu label. +wxString wxCommandProcessor::GetUndoMenuLabel() const +{ + wxString buf; + if (m_currentCommand) + { + wxCommand *command = (wxCommand *)m_currentCommand->GetData(); + wxString commandName(command->GetName()); + if (commandName.empty()) commandName = _("Unnamed command"); + bool canUndo = command->CanUndo(); + if (canUndo) + buf = wxString(_("&Undo ")) + commandName + m_undoAccelerator; + else + buf = wxString(_("Can't &Undo ")) + commandName + m_undoAccelerator; + } + else + { + buf = _("&Undo") + m_undoAccelerator; + } + + return buf; +} + +// Gets the current Undo menu label. +wxString wxCommandProcessor::GetRedoMenuLabel() const +{ + wxString buf; + if (m_currentCommand) + { + // We can redo, if we're not at the end of the history. + if (m_currentCommand->GetNext()) + { + wxCommand *redoCommand = (wxCommand *)m_currentCommand->GetNext()->GetData(); + wxString redoCommandName(redoCommand->GetName()); + if (redoCommandName.empty()) redoCommandName = _("Unnamed command"); + buf = wxString(_("&Redo ")) + redoCommandName + m_redoAccelerator; + } + else + { + buf = _("&Redo") + m_redoAccelerator; + } + } + else + { + if (m_commands.GetCount() == 0) + { + buf = _("&Redo") + m_redoAccelerator; + } + else + { + // currentCommand is NULL but there are commands: this means that + // we've undone to the start of the list, but can redo the first. + wxCommand *redoCommand = (wxCommand *)m_commands.GetFirst()->GetData(); + wxString redoCommandName(redoCommand->GetName()); + if (redoCommandName.empty()) redoCommandName = _("Unnamed command"); + buf = wxString(_("&Redo ")) + redoCommandName + m_redoAccelerator; + } + } + return buf; +} + +void wxCommandProcessor::ClearCommands() +{ + wxList::compatibility_iterator node = m_commands.GetFirst(); + while (node) + { + wxCommand *command = (wxCommand *)node->GetData(); + delete command; + m_commands.Erase(node); + node = m_commands.GetFirst(); + } + + m_currentCommand = wxList::compatibility_iterator(); + m_lastSavedCommand = wxList::compatibility_iterator(); +} + + diff --git a/Externals/wxWidgets/src/common/cmndata.cpp b/Externals/wxWidgets/src/common/cmndata.cpp index 8d937b9fb1..b5940a8d4e 100644 --- a/Externals/wxWidgets/src/common/cmndata.cpp +++ b/Externals/wxWidgets/src/common/cmndata.cpp @@ -1,657 +1,657 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/cmndata.cpp -// Purpose: Common GDI data -// Author: Julian Smart -// Modified by: -// Created: 01/02/97 -// RCS-ID: $Id: cmndata.cpp 43762 2006-12-03 15:26:01Z SC $ -// Copyright: (c) Julian Smart -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#include "wx/cmndata.h" - -#ifndef WX_PRECOMP - #if defined(__WXMSW__) - #include "wx/msw/wrapcdlg.h" - #endif // MSW - #include - #include "wx/string.h" - #include "wx/utils.h" - #include "wx/app.h" - #include "wx/log.h" - #include "wx/gdicmn.h" -#endif - -#include "wx/prntbase.h" -#include "wx/printdlg.h" - -#if wxUSE_FONTDLG - #include "wx/fontdlg.h" -#endif // wxUSE_FONTDLG - -#if wxUSE_PRINTING_ARCHITECTURE - -#include "wx/paper.h" - -#if defined(__WXMAC__) - #include "wx/mac/private/print.h" -#endif - -IMPLEMENT_DYNAMIC_CLASS(wxPrintData, wxObject) -IMPLEMENT_DYNAMIC_CLASS(wxPrintDialogData, wxObject) -IMPLEMENT_DYNAMIC_CLASS(wxPageSetupDialogData, wxObject) - -#endif // wxUSE_PRINTING_ARCHITECTURE - -IMPLEMENT_DYNAMIC_CLASS(wxFontData, wxObject) -IMPLEMENT_DYNAMIC_CLASS(wxColourData, wxObject) - -// ============================================================================ -// implementation -// ============================================================================ - -// ---------------------------------------------------------------------------- -// wxColourData -// ---------------------------------------------------------------------------- - -wxColourData::wxColourData() -{ - m_chooseFull = false; - m_dataColour.Set(0,0,0); - // m_custColours are wxNullColours initially -} - -wxColourData::wxColourData(const wxColourData& data) - : wxObject() -{ - (*this) = data; -} - -wxColourData::~wxColourData() -{ -} - -void wxColourData::SetCustomColour(int i, const wxColour& colour) -{ - wxCHECK_RET( (i >= 0 && i < 16), _T("custom colour index out of range") ); - - m_custColours[i] = colour; -} - -wxColour wxColourData::GetCustomColour(int i) -{ - wxCHECK_MSG( (i >= 0 && i < 16), wxColour(0,0,0), - _T("custom colour index out of range") ); - - return m_custColours[i]; -} - -void wxColourData::operator=(const wxColourData& data) -{ - int i; - for (i = 0; i < 16; i++) - m_custColours[i] = data.m_custColours[i]; - - m_dataColour = (wxColour&)data.m_dataColour; - m_chooseFull = data.m_chooseFull; -} - -// ---------------------------------------------------------------------------- -// Font data -// ---------------------------------------------------------------------------- - -wxFontData::wxFontData() -{ - // Intialize colour to black. - m_fontColour = wxNullColour; - - m_showHelp = false; - m_allowSymbols = true; - m_enableEffects = true; - m_minSize = 0; - m_maxSize = 0; - - m_encoding = wxFONTENCODING_SYSTEM; -} - -wxFontData::~wxFontData() -{ -} - -#if wxUSE_FONTDLG - -wxFontDialogBase::~wxFontDialogBase() -{ -} - -#endif // wxUSE_FONTDLG - -#if wxUSE_PRINTING_ARCHITECTURE -// ---------------------------------------------------------------------------- -// Print data -// ---------------------------------------------------------------------------- - -wxPrintData::wxPrintData() -{ - m_bin = wxPRINTBIN_DEFAULT; - m_media = wxPRINTMEDIA_DEFAULT; - m_printMode = wxPRINT_MODE_PRINTER; - m_printOrientation = wxPORTRAIT; - m_printOrientationReversed = false; - m_printNoCopies = 1; - m_printCollate = false; - - // New, 24/3/99 - m_printerName = wxEmptyString; - m_colour = true; - m_duplexMode = wxDUPLEX_SIMPLEX; - m_printQuality = wxPRINT_QUALITY_HIGH; - - // we intentionally don't initialize paper id and size at all, like this - // the default system settings will be used for them - m_paperId = wxPAPER_NONE; - m_paperSize = wxDefaultSize; - - m_privData = NULL; - m_privDataLen = 0; - - m_nativeData = wxPrintFactory::GetFactory()->CreatePrintNativeData(); -} - -wxPrintData::wxPrintData(const wxPrintData& printData) - : wxObject() -{ - m_nativeData = NULL; - m_privData = NULL; - (*this) = printData; -} - -void wxPrintData::SetPrivData( char *privData, int len ) -{ - if (m_privData) - { - delete [] m_privData; - m_privData = NULL; - } - m_privDataLen = len; - if (m_privDataLen > 0) - { - m_privData = new char[m_privDataLen]; - memcpy( m_privData, privData, m_privDataLen ); - } -} - -wxPrintData::~wxPrintData() -{ - m_nativeData->m_ref--; - if (m_nativeData->m_ref == 0) - delete m_nativeData; - - if (m_privData) - delete [] m_privData; -} - -void wxPrintData::ConvertToNative() -{ - m_nativeData->TransferFrom( *this ) ; -} - -void wxPrintData::ConvertFromNative() -{ - m_nativeData->TransferTo( *this ) ; -} - -void wxPrintData::operator=(const wxPrintData& data) -{ - m_printNoCopies = data.m_printNoCopies; - m_printCollate = data.m_printCollate; - m_printOrientation = data.m_printOrientation; - m_printOrientationReversed = data.m_printOrientationReversed; - m_printerName = data.m_printerName; - m_colour = data.m_colour; - m_duplexMode = data.m_duplexMode; - m_printQuality = data.m_printQuality; - m_paperId = data.m_paperId; - m_paperSize = data.m_paperSize; - m_bin = data.m_bin; - m_media = data.m_media; - m_printMode = data.m_printMode; - m_filename = data.m_filename; - - // UnRef old m_nativeData - if (m_nativeData) - { - m_nativeData->m_ref--; - if (m_nativeData->m_ref == 0) - delete m_nativeData; - } - // Set Ref new one - m_nativeData = data.GetNativeData(); - m_nativeData->m_ref++; - - if (m_privData) - { - delete [] m_privData; - m_privData = NULL; - } - m_privDataLen = data.GetPrivDataLen(); - if (m_privDataLen > 0) - { - m_privData = new char[m_privDataLen]; - memcpy( m_privData, data.GetPrivData(), m_privDataLen ); - } -} - -// Is this data OK for showing the print dialog? -bool wxPrintData::IsOk() const -{ - m_nativeData->TransferFrom( *this ); - - return m_nativeData->Ok(); -} - -// What should happen here? wxPostScriptPrintNativeData is not -// defined unless all this is true on MSW. -#if WXWIN_COMPATIBILITY_2_4 && wxUSE_PRINTING_ARCHITECTURE && (!defined(__WXMSW__) || wxUSE_POSTSCRIPT_ARCHITECTURE_IN_MSW) - -#include "wx/generic/prntdlgg.h" - -#if wxUSE_POSTSCRIPT - #define WXUNUSED_WITHOUT_PS(name) name -#else - #define WXUNUSED_WITHOUT_PS(name) WXUNUSED(name) -#endif - -wxString wxPrintData::GetPrinterCommand() const -{ -#if wxUSE_POSTSCRIPT - if (m_nativeData && wxIsKindOf(m_nativeData,wxPostScriptPrintNativeData)) - return ((wxPostScriptPrintNativeData*)m_nativeData)->GetPrinterCommand(); -#endif - return wxEmptyString; -} - -wxString wxPrintData::GetPrinterOptions() const -{ -#if wxUSE_POSTSCRIPT - if (m_nativeData && wxIsKindOf(m_nativeData,wxPostScriptPrintNativeData)) - return ((wxPostScriptPrintNativeData*)m_nativeData)->GetPrinterOptions(); -#endif - return wxEmptyString; -} - -wxString wxPrintData::GetPreviewCommand() const -{ -#if wxUSE_POSTSCRIPT - if (m_nativeData && wxIsKindOf(m_nativeData,wxPostScriptPrintNativeData)) - return ((wxPostScriptPrintNativeData*)m_nativeData)->GetPreviewCommand(); -#endif - return wxEmptyString; -} - -wxString wxPrintData::GetFontMetricPath() const -{ -#if wxUSE_POSTSCRIPT - if (m_nativeData && wxIsKindOf(m_nativeData,wxPostScriptPrintNativeData)) - return ((wxPostScriptPrintNativeData*)m_nativeData)->GetFontMetricPath(); -#endif - return wxEmptyString; -} - -double wxPrintData::GetPrinterScaleX() const -{ -#if wxUSE_POSTSCRIPT - if (m_nativeData && wxIsKindOf(m_nativeData,wxPostScriptPrintNativeData)) - return ((wxPostScriptPrintNativeData*)m_nativeData)->GetPrinterScaleX(); -#endif - return 1.0; -} - -double wxPrintData::GetPrinterScaleY() const -{ -#if wxUSE_POSTSCRIPT - if (m_nativeData && wxIsKindOf(m_nativeData,wxPostScriptPrintNativeData)) - return ((wxPostScriptPrintNativeData*)m_nativeData)->GetPrinterScaleY(); -#endif - return 1.0; -} - -long wxPrintData::GetPrinterTranslateX() const -{ -#if wxUSE_POSTSCRIPT - if (m_nativeData && wxIsKindOf(m_nativeData,wxPostScriptPrintNativeData)) - return ((wxPostScriptPrintNativeData*)m_nativeData)->GetPrinterTranslateX(); -#endif - return 0; -} - -long wxPrintData::GetPrinterTranslateY() const -{ -#if wxUSE_POSTSCRIPT - if (m_nativeData && wxIsKindOf(m_nativeData,wxPostScriptPrintNativeData)) - return ((wxPostScriptPrintNativeData*)m_nativeData)->GetPrinterTranslateY(); -#endif - return 0; -} - -void wxPrintData::SetPrinterCommand(const wxString& WXUNUSED_WITHOUT_PS(command)) -{ -#if wxUSE_POSTSCRIPT - if (m_nativeData && wxIsKindOf(m_nativeData,wxPostScriptPrintNativeData)) - ((wxPostScriptPrintNativeData*)m_nativeData)->SetPrinterCommand( command ); -#endif -} - -void wxPrintData::SetPrinterOptions(const wxString& WXUNUSED_WITHOUT_PS(options)) -{ -#if wxUSE_POSTSCRIPT - if (m_nativeData && wxIsKindOf(m_nativeData,wxPostScriptPrintNativeData)) - ((wxPostScriptPrintNativeData*)m_nativeData)->SetPrinterOptions( options ); -#endif -} - -void wxPrintData::SetPreviewCommand(const wxString& WXUNUSED_WITHOUT_PS(command)) -{ -#if wxUSE_POSTSCRIPT - if (m_nativeData && wxIsKindOf(m_nativeData,wxPostScriptPrintNativeData)) - ((wxPostScriptPrintNativeData*)m_nativeData)->SetPreviewCommand( command ); -#endif -} - -void wxPrintData::SetFontMetricPath(const wxString& WXUNUSED_WITHOUT_PS(path)) -{ -#if wxUSE_POSTSCRIPT - if (m_nativeData && wxIsKindOf(m_nativeData,wxPostScriptPrintNativeData)) - ((wxPostScriptPrintNativeData*)m_nativeData)->SetFontMetricPath( path ); -#endif -} - -void wxPrintData::SetPrinterScaleX(double WXUNUSED_WITHOUT_PS(x)) -{ -#if wxUSE_POSTSCRIPT - if (m_nativeData && wxIsKindOf(m_nativeData,wxPostScriptPrintNativeData)) - ((wxPostScriptPrintNativeData*)m_nativeData)->SetPrinterScaleX( x ); -#endif -} - -void wxPrintData::SetPrinterScaleY(double WXUNUSED_WITHOUT_PS(y)) -{ -#if wxUSE_POSTSCRIPT - if (m_nativeData && wxIsKindOf(m_nativeData,wxPostScriptPrintNativeData)) - ((wxPostScriptPrintNativeData*)m_nativeData)->SetPrinterScaleY( y ); -#endif -} - -void wxPrintData::SetPrinterScaling(double WXUNUSED_WITHOUT_PS(x), double WXUNUSED_WITHOUT_PS(y)) -{ -#if wxUSE_POSTSCRIPT - if (m_nativeData && wxIsKindOf(m_nativeData,wxPostScriptPrintNativeData)) - ((wxPostScriptPrintNativeData*)m_nativeData)->SetPrinterScaling( x, y ); -#endif -} - -void wxPrintData::SetPrinterTranslateX(long WXUNUSED_WITHOUT_PS(x)) -{ -#if wxUSE_POSTSCRIPT - if (m_nativeData && wxIsKindOf(m_nativeData,wxPostScriptPrintNativeData)) - ((wxPostScriptPrintNativeData*)m_nativeData)->SetPrinterTranslateX( x ); -#endif -} - -void wxPrintData::SetPrinterTranslateY(long WXUNUSED_WITHOUT_PS(y)) -{ -#if wxUSE_POSTSCRIPT - if (m_nativeData && wxIsKindOf(m_nativeData,wxPostScriptPrintNativeData)) - ((wxPostScriptPrintNativeData*)m_nativeData)->SetPrinterTranslateY( y ); -#endif -} - -void wxPrintData::SetPrinterTranslation(long WXUNUSED_WITHOUT_PS(x), long WXUNUSED_WITHOUT_PS(y)) -{ -#if wxUSE_POSTSCRIPT - if (m_nativeData && wxIsKindOf(m_nativeData,wxPostScriptPrintNativeData)) - ((wxPostScriptPrintNativeData*)m_nativeData)->SetPrinterTranslation( x, y ); -#endif -} -#endif - -// ---------------------------------------------------------------------------- -// Print dialog data -// ---------------------------------------------------------------------------- - -wxPrintDialogData::wxPrintDialogData() -{ - m_printFromPage = 0; - m_printToPage = 0; - m_printMinPage = 0; - m_printMaxPage = 0; - m_printNoCopies = 1; - m_printAllPages = false; - m_printCollate = false; - m_printToFile = false; - m_printSelection = false; - m_printEnableSelection = false; - m_printEnablePageNumbers = true; - - wxPrintFactory* factory = wxPrintFactory::GetFactory(); - m_printEnablePrintToFile = ! factory->HasOwnPrintToFile(); - - m_printEnableHelp = false; -#if WXWIN_COMPATIBILITY_2_4 - m_printSetupDialog = false; -#endif -} - -wxPrintDialogData::wxPrintDialogData(const wxPrintDialogData& dialogData) - : wxObject() -{ - (*this) = dialogData; -} - -wxPrintDialogData::wxPrintDialogData(const wxPrintData& printData) -{ - m_printFromPage = 1; - m_printToPage = 0; - m_printMinPage = 1; - m_printMaxPage = 9999; - m_printNoCopies = 1; - m_printAllPages = false; - m_printCollate = false; - m_printToFile = false; - m_printSelection = false; - m_printEnableSelection = false; - m_printEnablePageNumbers = true; - m_printEnablePrintToFile = true; - m_printEnableHelp = false; -#if WXWIN_COMPATIBILITY_2_4 - m_printSetupDialog = false; -#endif - m_printData = printData; -} - -wxPrintDialogData::~wxPrintDialogData() -{ -} - -void wxPrintDialogData::operator=(const wxPrintDialogData& data) -{ - m_printFromPage = data.m_printFromPage; - m_printToPage = data.m_printToPage; - m_printMinPage = data.m_printMinPage; - m_printMaxPage = data.m_printMaxPage; - m_printNoCopies = data.m_printNoCopies; - m_printAllPages = data.m_printAllPages; - m_printCollate = data.m_printCollate; - m_printToFile = data.m_printToFile; - m_printSelection = data.m_printSelection; - m_printEnableSelection = data.m_printEnableSelection; - m_printEnablePageNumbers = data.m_printEnablePageNumbers; - m_printEnableHelp = data.m_printEnableHelp; - m_printEnablePrintToFile = data.m_printEnablePrintToFile; -#if WXWIN_COMPATIBILITY_2_4 - m_printSetupDialog = data.m_printSetupDialog; -#endif - m_printData = data.m_printData; -} - -void wxPrintDialogData::operator=(const wxPrintData& data) -{ - m_printData = data; -} - -// ---------------------------------------------------------------------------- -// wxPageSetupDialogData -// ---------------------------------------------------------------------------- - -wxPageSetupDialogData::wxPageSetupDialogData() -{ - m_paperSize = wxSize(0,0); - - CalculatePaperSizeFromId(); - - m_minMarginTopLeft = - m_minMarginBottomRight = - m_marginTopLeft = - m_marginBottomRight = wxPoint(0,0); - - // Flags - m_defaultMinMargins = false; - m_enableMargins = true; - m_enableOrientation = true; - m_enablePaper = true; - m_enablePrinter = true; - m_enableHelp = false; - m_getDefaultInfo = false; -} - -wxPageSetupDialogData::wxPageSetupDialogData(const wxPageSetupDialogData& dialogData) - : wxObject() -{ - (*this) = dialogData; -} - -wxPageSetupDialogData::wxPageSetupDialogData(const wxPrintData& printData) -{ - m_paperSize = wxSize(0,0); - m_minMarginTopLeft = - m_minMarginBottomRight = - m_marginTopLeft = - m_marginBottomRight = wxPoint(0,0); - - // Flags - m_defaultMinMargins = false; - m_enableMargins = true; - m_enableOrientation = true; - m_enablePaper = true; - m_enablePrinter = true; - m_enableHelp = false; - m_getDefaultInfo = false; - - m_printData = printData; - - // The wxPrintData paper size overrides these values, unless the size cannot - // be found. - CalculatePaperSizeFromId(); -} - -wxPageSetupDialogData::~wxPageSetupDialogData() -{ -} - -wxPageSetupDialogData& wxPageSetupDialogData::operator=(const wxPageSetupDialogData& data) -{ - m_paperSize = data.m_paperSize; - m_minMarginTopLeft = data.m_minMarginTopLeft; - m_minMarginBottomRight = data.m_minMarginBottomRight; - m_marginTopLeft = data.m_marginTopLeft; - m_marginBottomRight = data.m_marginBottomRight; - m_defaultMinMargins = data.m_defaultMinMargins; - m_enableMargins = data.m_enableMargins; - m_enableOrientation = data.m_enableOrientation; - m_enablePaper = data.m_enablePaper; - m_enablePrinter = data.m_enablePrinter; - m_getDefaultInfo = data.m_getDefaultInfo; - m_enableHelp = data.m_enableHelp; - - m_printData = data.m_printData; - - return *this; -} - -wxPageSetupDialogData& wxPageSetupDialogData::operator=(const wxPrintData& data) -{ - m_printData = data; - CalculatePaperSizeFromId(); - - return *this; -} - -// If a corresponding paper type is found in the paper database, will set the m_printData -// paper size id member as well. -void wxPageSetupDialogData::SetPaperSize(const wxSize& sz) -{ - m_paperSize = sz; - - CalculateIdFromPaperSize(); -} - -// Sets the wxPrintData id, plus the paper width/height if found in the paper database. -void wxPageSetupDialogData::SetPaperSize(wxPaperSize id) -{ - m_printData.SetPaperId(id); - - CalculatePaperSizeFromId(); -} - -void wxPageSetupDialogData::SetPrintData(const wxPrintData& printData) -{ - m_printData = printData; - CalculatePaperSizeFromId(); -} - -// Use paper size defined in this object to set the wxPrintData -// paper id -void wxPageSetupDialogData::CalculateIdFromPaperSize() -{ - wxASSERT_MSG( (wxThePrintPaperDatabase != (wxPrintPaperDatabase*) NULL), - wxT("wxThePrintPaperDatabase should not be NULL. Do not create global print dialog data objects.") ); - - wxSize sz = GetPaperSize(); - - wxPaperSize id = wxThePrintPaperDatabase->GetSize(wxSize(sz.x* 10, sz.y * 10)); - if (id != wxPAPER_NONE) - { - m_printData.SetPaperId(id); - } -} - -// Use paper id in wxPrintData to set this object's paper size -void wxPageSetupDialogData::CalculatePaperSizeFromId() -{ - wxASSERT_MSG( (wxThePrintPaperDatabase != (wxPrintPaperDatabase*) NULL), - wxT("wxThePrintPaperDatabase should not be NULL. Do not create global print dialog data objects.") ); - - wxSize sz = wxThePrintPaperDatabase->GetSize(m_printData.GetPaperId()); - - // sz is in 10ths of a mm, while paper size is in mm - m_paperSize.x = sz.x / 10; - m_paperSize.y = sz.y / 10; -} - -#endif // wxUSE_PRINTING_ARCHITECTURE +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/cmndata.cpp +// Purpose: Common GDI data +// Author: Julian Smart +// Modified by: +// Created: 01/02/97 +// RCS-ID: $Id: cmndata.cpp 43762 2006-12-03 15:26:01Z SC $ +// Copyright: (c) Julian Smart +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#include "wx/cmndata.h" + +#ifndef WX_PRECOMP + #if defined(__WXMSW__) + #include "wx/msw/wrapcdlg.h" + #endif // MSW + #include + #include "wx/string.h" + #include "wx/utils.h" + #include "wx/app.h" + #include "wx/log.h" + #include "wx/gdicmn.h" +#endif + +#include "wx/prntbase.h" +#include "wx/printdlg.h" + +#if wxUSE_FONTDLG + #include "wx/fontdlg.h" +#endif // wxUSE_FONTDLG + +#if wxUSE_PRINTING_ARCHITECTURE + +#include "wx/paper.h" + +#if defined(__WXMAC__) + #include "wx/mac/private/print.h" +#endif + +IMPLEMENT_DYNAMIC_CLASS(wxPrintData, wxObject) +IMPLEMENT_DYNAMIC_CLASS(wxPrintDialogData, wxObject) +IMPLEMENT_DYNAMIC_CLASS(wxPageSetupDialogData, wxObject) + +#endif // wxUSE_PRINTING_ARCHITECTURE + +IMPLEMENT_DYNAMIC_CLASS(wxFontData, wxObject) +IMPLEMENT_DYNAMIC_CLASS(wxColourData, wxObject) + +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// wxColourData +// ---------------------------------------------------------------------------- + +wxColourData::wxColourData() +{ + m_chooseFull = false; + m_dataColour.Set(0,0,0); + // m_custColours are wxNullColours initially +} + +wxColourData::wxColourData(const wxColourData& data) + : wxObject() +{ + (*this) = data; +} + +wxColourData::~wxColourData() +{ +} + +void wxColourData::SetCustomColour(int i, const wxColour& colour) +{ + wxCHECK_RET( (i >= 0 && i < 16), _T("custom colour index out of range") ); + + m_custColours[i] = colour; +} + +wxColour wxColourData::GetCustomColour(int i) +{ + wxCHECK_MSG( (i >= 0 && i < 16), wxColour(0,0,0), + _T("custom colour index out of range") ); + + return m_custColours[i]; +} + +void wxColourData::operator=(const wxColourData& data) +{ + int i; + for (i = 0; i < 16; i++) + m_custColours[i] = data.m_custColours[i]; + + m_dataColour = (wxColour&)data.m_dataColour; + m_chooseFull = data.m_chooseFull; +} + +// ---------------------------------------------------------------------------- +// Font data +// ---------------------------------------------------------------------------- + +wxFontData::wxFontData() +{ + // Intialize colour to black. + m_fontColour = wxNullColour; + + m_showHelp = false; + m_allowSymbols = true; + m_enableEffects = true; + m_minSize = 0; + m_maxSize = 0; + + m_encoding = wxFONTENCODING_SYSTEM; +} + +wxFontData::~wxFontData() +{ +} + +#if wxUSE_FONTDLG + +wxFontDialogBase::~wxFontDialogBase() +{ +} + +#endif // wxUSE_FONTDLG + +#if wxUSE_PRINTING_ARCHITECTURE +// ---------------------------------------------------------------------------- +// Print data +// ---------------------------------------------------------------------------- + +wxPrintData::wxPrintData() +{ + m_bin = wxPRINTBIN_DEFAULT; + m_media = wxPRINTMEDIA_DEFAULT; + m_printMode = wxPRINT_MODE_PRINTER; + m_printOrientation = wxPORTRAIT; + m_printOrientationReversed = false; + m_printNoCopies = 1; + m_printCollate = false; + + // New, 24/3/99 + m_printerName = wxEmptyString; + m_colour = true; + m_duplexMode = wxDUPLEX_SIMPLEX; + m_printQuality = wxPRINT_QUALITY_HIGH; + + // we intentionally don't initialize paper id and size at all, like this + // the default system settings will be used for them + m_paperId = wxPAPER_NONE; + m_paperSize = wxDefaultSize; + + m_privData = NULL; + m_privDataLen = 0; + + m_nativeData = wxPrintFactory::GetFactory()->CreatePrintNativeData(); +} + +wxPrintData::wxPrintData(const wxPrintData& printData) + : wxObject() +{ + m_nativeData = NULL; + m_privData = NULL; + (*this) = printData; +} + +void wxPrintData::SetPrivData( char *privData, int len ) +{ + if (m_privData) + { + delete [] m_privData; + m_privData = NULL; + } + m_privDataLen = len; + if (m_privDataLen > 0) + { + m_privData = new char[m_privDataLen]; + memcpy( m_privData, privData, m_privDataLen ); + } +} + +wxPrintData::~wxPrintData() +{ + m_nativeData->m_ref--; + if (m_nativeData->m_ref == 0) + delete m_nativeData; + + if (m_privData) + delete [] m_privData; +} + +void wxPrintData::ConvertToNative() +{ + m_nativeData->TransferFrom( *this ) ; +} + +void wxPrintData::ConvertFromNative() +{ + m_nativeData->TransferTo( *this ) ; +} + +void wxPrintData::operator=(const wxPrintData& data) +{ + m_printNoCopies = data.m_printNoCopies; + m_printCollate = data.m_printCollate; + m_printOrientation = data.m_printOrientation; + m_printOrientationReversed = data.m_printOrientationReversed; + m_printerName = data.m_printerName; + m_colour = data.m_colour; + m_duplexMode = data.m_duplexMode; + m_printQuality = data.m_printQuality; + m_paperId = data.m_paperId; + m_paperSize = data.m_paperSize; + m_bin = data.m_bin; + m_media = data.m_media; + m_printMode = data.m_printMode; + m_filename = data.m_filename; + + // UnRef old m_nativeData + if (m_nativeData) + { + m_nativeData->m_ref--; + if (m_nativeData->m_ref == 0) + delete m_nativeData; + } + // Set Ref new one + m_nativeData = data.GetNativeData(); + m_nativeData->m_ref++; + + if (m_privData) + { + delete [] m_privData; + m_privData = NULL; + } + m_privDataLen = data.GetPrivDataLen(); + if (m_privDataLen > 0) + { + m_privData = new char[m_privDataLen]; + memcpy( m_privData, data.GetPrivData(), m_privDataLen ); + } +} + +// Is this data OK for showing the print dialog? +bool wxPrintData::IsOk() const +{ + m_nativeData->TransferFrom( *this ); + + return m_nativeData->Ok(); +} + +// What should happen here? wxPostScriptPrintNativeData is not +// defined unless all this is true on MSW. +#if WXWIN_COMPATIBILITY_2_4 && wxUSE_PRINTING_ARCHITECTURE && (!defined(__WXMSW__) || wxUSE_POSTSCRIPT_ARCHITECTURE_IN_MSW) + +#include "wx/generic/prntdlgg.h" + +#if wxUSE_POSTSCRIPT + #define WXUNUSED_WITHOUT_PS(name) name +#else + #define WXUNUSED_WITHOUT_PS(name) WXUNUSED(name) +#endif + +wxString wxPrintData::GetPrinterCommand() const +{ +#if wxUSE_POSTSCRIPT + if (m_nativeData && wxIsKindOf(m_nativeData,wxPostScriptPrintNativeData)) + return ((wxPostScriptPrintNativeData*)m_nativeData)->GetPrinterCommand(); +#endif + return wxEmptyString; +} + +wxString wxPrintData::GetPrinterOptions() const +{ +#if wxUSE_POSTSCRIPT + if (m_nativeData && wxIsKindOf(m_nativeData,wxPostScriptPrintNativeData)) + return ((wxPostScriptPrintNativeData*)m_nativeData)->GetPrinterOptions(); +#endif + return wxEmptyString; +} + +wxString wxPrintData::GetPreviewCommand() const +{ +#if wxUSE_POSTSCRIPT + if (m_nativeData && wxIsKindOf(m_nativeData,wxPostScriptPrintNativeData)) + return ((wxPostScriptPrintNativeData*)m_nativeData)->GetPreviewCommand(); +#endif + return wxEmptyString; +} + +wxString wxPrintData::GetFontMetricPath() const +{ +#if wxUSE_POSTSCRIPT + if (m_nativeData && wxIsKindOf(m_nativeData,wxPostScriptPrintNativeData)) + return ((wxPostScriptPrintNativeData*)m_nativeData)->GetFontMetricPath(); +#endif + return wxEmptyString; +} + +double wxPrintData::GetPrinterScaleX() const +{ +#if wxUSE_POSTSCRIPT + if (m_nativeData && wxIsKindOf(m_nativeData,wxPostScriptPrintNativeData)) + return ((wxPostScriptPrintNativeData*)m_nativeData)->GetPrinterScaleX(); +#endif + return 1.0; +} + +double wxPrintData::GetPrinterScaleY() const +{ +#if wxUSE_POSTSCRIPT + if (m_nativeData && wxIsKindOf(m_nativeData,wxPostScriptPrintNativeData)) + return ((wxPostScriptPrintNativeData*)m_nativeData)->GetPrinterScaleY(); +#endif + return 1.0; +} + +long wxPrintData::GetPrinterTranslateX() const +{ +#if wxUSE_POSTSCRIPT + if (m_nativeData && wxIsKindOf(m_nativeData,wxPostScriptPrintNativeData)) + return ((wxPostScriptPrintNativeData*)m_nativeData)->GetPrinterTranslateX(); +#endif + return 0; +} + +long wxPrintData::GetPrinterTranslateY() const +{ +#if wxUSE_POSTSCRIPT + if (m_nativeData && wxIsKindOf(m_nativeData,wxPostScriptPrintNativeData)) + return ((wxPostScriptPrintNativeData*)m_nativeData)->GetPrinterTranslateY(); +#endif + return 0; +} + +void wxPrintData::SetPrinterCommand(const wxString& WXUNUSED_WITHOUT_PS(command)) +{ +#if wxUSE_POSTSCRIPT + if (m_nativeData && wxIsKindOf(m_nativeData,wxPostScriptPrintNativeData)) + ((wxPostScriptPrintNativeData*)m_nativeData)->SetPrinterCommand( command ); +#endif +} + +void wxPrintData::SetPrinterOptions(const wxString& WXUNUSED_WITHOUT_PS(options)) +{ +#if wxUSE_POSTSCRIPT + if (m_nativeData && wxIsKindOf(m_nativeData,wxPostScriptPrintNativeData)) + ((wxPostScriptPrintNativeData*)m_nativeData)->SetPrinterOptions( options ); +#endif +} + +void wxPrintData::SetPreviewCommand(const wxString& WXUNUSED_WITHOUT_PS(command)) +{ +#if wxUSE_POSTSCRIPT + if (m_nativeData && wxIsKindOf(m_nativeData,wxPostScriptPrintNativeData)) + ((wxPostScriptPrintNativeData*)m_nativeData)->SetPreviewCommand( command ); +#endif +} + +void wxPrintData::SetFontMetricPath(const wxString& WXUNUSED_WITHOUT_PS(path)) +{ +#if wxUSE_POSTSCRIPT + if (m_nativeData && wxIsKindOf(m_nativeData,wxPostScriptPrintNativeData)) + ((wxPostScriptPrintNativeData*)m_nativeData)->SetFontMetricPath( path ); +#endif +} + +void wxPrintData::SetPrinterScaleX(double WXUNUSED_WITHOUT_PS(x)) +{ +#if wxUSE_POSTSCRIPT + if (m_nativeData && wxIsKindOf(m_nativeData,wxPostScriptPrintNativeData)) + ((wxPostScriptPrintNativeData*)m_nativeData)->SetPrinterScaleX( x ); +#endif +} + +void wxPrintData::SetPrinterScaleY(double WXUNUSED_WITHOUT_PS(y)) +{ +#if wxUSE_POSTSCRIPT + if (m_nativeData && wxIsKindOf(m_nativeData,wxPostScriptPrintNativeData)) + ((wxPostScriptPrintNativeData*)m_nativeData)->SetPrinterScaleY( y ); +#endif +} + +void wxPrintData::SetPrinterScaling(double WXUNUSED_WITHOUT_PS(x), double WXUNUSED_WITHOUT_PS(y)) +{ +#if wxUSE_POSTSCRIPT + if (m_nativeData && wxIsKindOf(m_nativeData,wxPostScriptPrintNativeData)) + ((wxPostScriptPrintNativeData*)m_nativeData)->SetPrinterScaling( x, y ); +#endif +} + +void wxPrintData::SetPrinterTranslateX(long WXUNUSED_WITHOUT_PS(x)) +{ +#if wxUSE_POSTSCRIPT + if (m_nativeData && wxIsKindOf(m_nativeData,wxPostScriptPrintNativeData)) + ((wxPostScriptPrintNativeData*)m_nativeData)->SetPrinterTranslateX( x ); +#endif +} + +void wxPrintData::SetPrinterTranslateY(long WXUNUSED_WITHOUT_PS(y)) +{ +#if wxUSE_POSTSCRIPT + if (m_nativeData && wxIsKindOf(m_nativeData,wxPostScriptPrintNativeData)) + ((wxPostScriptPrintNativeData*)m_nativeData)->SetPrinterTranslateY( y ); +#endif +} + +void wxPrintData::SetPrinterTranslation(long WXUNUSED_WITHOUT_PS(x), long WXUNUSED_WITHOUT_PS(y)) +{ +#if wxUSE_POSTSCRIPT + if (m_nativeData && wxIsKindOf(m_nativeData,wxPostScriptPrintNativeData)) + ((wxPostScriptPrintNativeData*)m_nativeData)->SetPrinterTranslation( x, y ); +#endif +} +#endif + +// ---------------------------------------------------------------------------- +// Print dialog data +// ---------------------------------------------------------------------------- + +wxPrintDialogData::wxPrintDialogData() +{ + m_printFromPage = 0; + m_printToPage = 0; + m_printMinPage = 0; + m_printMaxPage = 0; + m_printNoCopies = 1; + m_printAllPages = false; + m_printCollate = false; + m_printToFile = false; + m_printSelection = false; + m_printEnableSelection = false; + m_printEnablePageNumbers = true; + + wxPrintFactory* factory = wxPrintFactory::GetFactory(); + m_printEnablePrintToFile = ! factory->HasOwnPrintToFile(); + + m_printEnableHelp = false; +#if WXWIN_COMPATIBILITY_2_4 + m_printSetupDialog = false; +#endif +} + +wxPrintDialogData::wxPrintDialogData(const wxPrintDialogData& dialogData) + : wxObject() +{ + (*this) = dialogData; +} + +wxPrintDialogData::wxPrintDialogData(const wxPrintData& printData) +{ + m_printFromPage = 1; + m_printToPage = 0; + m_printMinPage = 1; + m_printMaxPage = 9999; + m_printNoCopies = 1; + m_printAllPages = false; + m_printCollate = false; + m_printToFile = false; + m_printSelection = false; + m_printEnableSelection = false; + m_printEnablePageNumbers = true; + m_printEnablePrintToFile = true; + m_printEnableHelp = false; +#if WXWIN_COMPATIBILITY_2_4 + m_printSetupDialog = false; +#endif + m_printData = printData; +} + +wxPrintDialogData::~wxPrintDialogData() +{ +} + +void wxPrintDialogData::operator=(const wxPrintDialogData& data) +{ + m_printFromPage = data.m_printFromPage; + m_printToPage = data.m_printToPage; + m_printMinPage = data.m_printMinPage; + m_printMaxPage = data.m_printMaxPage; + m_printNoCopies = data.m_printNoCopies; + m_printAllPages = data.m_printAllPages; + m_printCollate = data.m_printCollate; + m_printToFile = data.m_printToFile; + m_printSelection = data.m_printSelection; + m_printEnableSelection = data.m_printEnableSelection; + m_printEnablePageNumbers = data.m_printEnablePageNumbers; + m_printEnableHelp = data.m_printEnableHelp; + m_printEnablePrintToFile = data.m_printEnablePrintToFile; +#if WXWIN_COMPATIBILITY_2_4 + m_printSetupDialog = data.m_printSetupDialog; +#endif + m_printData = data.m_printData; +} + +void wxPrintDialogData::operator=(const wxPrintData& data) +{ + m_printData = data; +} + +// ---------------------------------------------------------------------------- +// wxPageSetupDialogData +// ---------------------------------------------------------------------------- + +wxPageSetupDialogData::wxPageSetupDialogData() +{ + m_paperSize = wxSize(0,0); + + CalculatePaperSizeFromId(); + + m_minMarginTopLeft = + m_minMarginBottomRight = + m_marginTopLeft = + m_marginBottomRight = wxPoint(0,0); + + // Flags + m_defaultMinMargins = false; + m_enableMargins = true; + m_enableOrientation = true; + m_enablePaper = true; + m_enablePrinter = true; + m_enableHelp = false; + m_getDefaultInfo = false; +} + +wxPageSetupDialogData::wxPageSetupDialogData(const wxPageSetupDialogData& dialogData) + : wxObject() +{ + (*this) = dialogData; +} + +wxPageSetupDialogData::wxPageSetupDialogData(const wxPrintData& printData) +{ + m_paperSize = wxSize(0,0); + m_minMarginTopLeft = + m_minMarginBottomRight = + m_marginTopLeft = + m_marginBottomRight = wxPoint(0,0); + + // Flags + m_defaultMinMargins = false; + m_enableMargins = true; + m_enableOrientation = true; + m_enablePaper = true; + m_enablePrinter = true; + m_enableHelp = false; + m_getDefaultInfo = false; + + m_printData = printData; + + // The wxPrintData paper size overrides these values, unless the size cannot + // be found. + CalculatePaperSizeFromId(); +} + +wxPageSetupDialogData::~wxPageSetupDialogData() +{ +} + +wxPageSetupDialogData& wxPageSetupDialogData::operator=(const wxPageSetupDialogData& data) +{ + m_paperSize = data.m_paperSize; + m_minMarginTopLeft = data.m_minMarginTopLeft; + m_minMarginBottomRight = data.m_minMarginBottomRight; + m_marginTopLeft = data.m_marginTopLeft; + m_marginBottomRight = data.m_marginBottomRight; + m_defaultMinMargins = data.m_defaultMinMargins; + m_enableMargins = data.m_enableMargins; + m_enableOrientation = data.m_enableOrientation; + m_enablePaper = data.m_enablePaper; + m_enablePrinter = data.m_enablePrinter; + m_getDefaultInfo = data.m_getDefaultInfo; + m_enableHelp = data.m_enableHelp; + + m_printData = data.m_printData; + + return *this; +} + +wxPageSetupDialogData& wxPageSetupDialogData::operator=(const wxPrintData& data) +{ + m_printData = data; + CalculatePaperSizeFromId(); + + return *this; +} + +// If a corresponding paper type is found in the paper database, will set the m_printData +// paper size id member as well. +void wxPageSetupDialogData::SetPaperSize(const wxSize& sz) +{ + m_paperSize = sz; + + CalculateIdFromPaperSize(); +} + +// Sets the wxPrintData id, plus the paper width/height if found in the paper database. +void wxPageSetupDialogData::SetPaperSize(wxPaperSize id) +{ + m_printData.SetPaperId(id); + + CalculatePaperSizeFromId(); +} + +void wxPageSetupDialogData::SetPrintData(const wxPrintData& printData) +{ + m_printData = printData; + CalculatePaperSizeFromId(); +} + +// Use paper size defined in this object to set the wxPrintData +// paper id +void wxPageSetupDialogData::CalculateIdFromPaperSize() +{ + wxASSERT_MSG( (wxThePrintPaperDatabase != (wxPrintPaperDatabase*) NULL), + wxT("wxThePrintPaperDatabase should not be NULL. Do not create global print dialog data objects.") ); + + wxSize sz = GetPaperSize(); + + wxPaperSize id = wxThePrintPaperDatabase->GetSize(wxSize(sz.x* 10, sz.y * 10)); + if (id != wxPAPER_NONE) + { + m_printData.SetPaperId(id); + } +} + +// Use paper id in wxPrintData to set this object's paper size +void wxPageSetupDialogData::CalculatePaperSizeFromId() +{ + wxASSERT_MSG( (wxThePrintPaperDatabase != (wxPrintPaperDatabase*) NULL), + wxT("wxThePrintPaperDatabase should not be NULL. Do not create global print dialog data objects.") ); + + wxSize sz = wxThePrintPaperDatabase->GetSize(m_printData.GetPaperId()); + + // sz is in 10ths of a mm, while paper size is in mm + m_paperSize.x = sz.x / 10; + m_paperSize.y = sz.y / 10; +} + +#endif // wxUSE_PRINTING_ARCHITECTURE diff --git a/Externals/wxWidgets/src/common/colourcmn.cpp b/Externals/wxWidgets/src/common/colourcmn.cpp index 0bd34c8c90..5851dfcdf3 100644 --- a/Externals/wxWidgets/src/common/colourcmn.cpp +++ b/Externals/wxWidgets/src/common/colourcmn.cpp @@ -1,126 +1,126 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/colourcmn.cpp -// Purpose: wxColourBase implementation -// Author: Francesco Montorsi -// Modified by: -// Created: 20/4/2006 -// RCS-ID: $Id: colourcmn.cpp 41538 2006-09-30 20:45:15Z RR $ -// Copyright: (c) Francesco Montorsi -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#include "wx/colour.h" - -#ifndef WX_PRECOMP - #include "wx/log.h" - #include "wx/utils.h" - #include "wx/gdicmn.h" -#endif - -#if wxUSE_VARIANT -IMPLEMENT_VARIANT_OBJECT_EXPORTED(wxColour,WXDLLEXPORT) -#endif - -// ============================================================================ -// wxString <-> wxColour conversions -// ============================================================================ - -bool wxColourBase::FromString(const wxChar *str) -{ - if ( str == NULL || str[0] == wxT('\0')) - return false; // invalid or empty string - - if ( wxStrncmp(str, wxT("RGB"), 3) == 0 || - wxStrncmp(str, wxT("rgb"), 3) == 0 ) - { - // CSS-like RGB specification - // according to http://www.w3.org/TR/REC-CSS2/syndata.html#color-units - // values outside 0-255 range are allowed but should be clipped - int red, green, blue; - if (wxSscanf(&str[3], wxT("(%d, %d, %d)"), &red, &green, &blue) != 3) - return false; - - Set((unsigned char)wxClip(red,0,255), - (unsigned char)wxClip(green,0,255), - (unsigned char)wxClip(blue,0,255)); - } - else if ( str[0] == wxT('#') && wxStrlen(str) == 7 ) - { - // hexadecimal prefixed with # (HTML syntax) - unsigned long tmp; - if (wxSscanf(&str[1], wxT("%lx"), &tmp) != 1) - return false; - - Set((unsigned char)(tmp >> 16), - (unsigned char)(tmp >> 8), - (unsigned char)tmp); - } - else if (wxTheColourDatabase) // a colour name ? - { - // we can't do - // *this = wxTheColourDatabase->Find(str) - // because this place can be called from constructor - // and 'this' could not be available yet - wxColour clr = wxTheColourDatabase->Find(str); - if (clr.Ok()) - Set((unsigned char)clr.Red(), - (unsigned char)clr.Green(), - (unsigned char)clr.Blue()); - } - - if (Ok()) - return true; - - wxLogDebug(wxT("wxColour::Set - couldn't set to colour string '%s'"), str); - return false; -} - -wxString wxColourBase::GetAsString(long flags) const -{ - wxString colName; - - if (flags & wxC2S_NAME) - colName = wxTheColourDatabase->FindName((const wxColour &)(*this)).MakeLower(); - - if ( colName.empty() && (flags & wxC2S_CSS_SYNTAX) ) - { - // no name for this colour; return it in CSS syntax - colName.Printf(wxT("rgb(%d, %d, %d)"), - Red(), Green(), Blue()); - } - else if ( colName.empty() && (flags & wxC2S_HTML_SYNTAX) ) - { - // no name for this colour; return it in HTML syntax - colName.Printf(wxT("#%02X%02X%02X"), - Red(), Green(), Blue()); - } - - // this function always returns a non-empty string - wxASSERT_MSG(!colName.empty(), - wxT("Invalid wxColour -> wxString conversion flags")); - - return colName; -} - -#if WXWIN_COMPATIBILITY_2_6 - -// static -wxColour wxColourBase::CreateByName(const wxString& name) -{ - return wxColour(name); -} - -void wxColourBase::InitFromName(const wxString& col) -{ - Set(col); -} - -#endif // WXWIN_COMPATIBILITY_2_6 +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/colourcmn.cpp +// Purpose: wxColourBase implementation +// Author: Francesco Montorsi +// Modified by: +// Created: 20/4/2006 +// RCS-ID: $Id: colourcmn.cpp 41538 2006-09-30 20:45:15Z RR $ +// Copyright: (c) Francesco Montorsi +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#include "wx/colour.h" + +#ifndef WX_PRECOMP + #include "wx/log.h" + #include "wx/utils.h" + #include "wx/gdicmn.h" +#endif + +#if wxUSE_VARIANT +IMPLEMENT_VARIANT_OBJECT_EXPORTED(wxColour,WXDLLEXPORT) +#endif + +// ============================================================================ +// wxString <-> wxColour conversions +// ============================================================================ + +bool wxColourBase::FromString(const wxChar *str) +{ + if ( str == NULL || str[0] == wxT('\0')) + return false; // invalid or empty string + + if ( wxStrncmp(str, wxT("RGB"), 3) == 0 || + wxStrncmp(str, wxT("rgb"), 3) == 0 ) + { + // CSS-like RGB specification + // according to http://www.w3.org/TR/REC-CSS2/syndata.html#color-units + // values outside 0-255 range are allowed but should be clipped + int red, green, blue; + if (wxSscanf(&str[3], wxT("(%d, %d, %d)"), &red, &green, &blue) != 3) + return false; + + Set((unsigned char)wxClip(red,0,255), + (unsigned char)wxClip(green,0,255), + (unsigned char)wxClip(blue,0,255)); + } + else if ( str[0] == wxT('#') && wxStrlen(str) == 7 ) + { + // hexadecimal prefixed with # (HTML syntax) + unsigned long tmp; + if (wxSscanf(&str[1], wxT("%lx"), &tmp) != 1) + return false; + + Set((unsigned char)(tmp >> 16), + (unsigned char)(tmp >> 8), + (unsigned char)tmp); + } + else if (wxTheColourDatabase) // a colour name ? + { + // we can't do + // *this = wxTheColourDatabase->Find(str) + // because this place can be called from constructor + // and 'this' could not be available yet + wxColour clr = wxTheColourDatabase->Find(str); + if (clr.Ok()) + Set((unsigned char)clr.Red(), + (unsigned char)clr.Green(), + (unsigned char)clr.Blue()); + } + + if (Ok()) + return true; + + wxLogDebug(wxT("wxColour::Set - couldn't set to colour string '%s'"), str); + return false; +} + +wxString wxColourBase::GetAsString(long flags) const +{ + wxString colName; + + if (flags & wxC2S_NAME) + colName = wxTheColourDatabase->FindName((const wxColour &)(*this)).MakeLower(); + + if ( colName.empty() && (flags & wxC2S_CSS_SYNTAX) ) + { + // no name for this colour; return it in CSS syntax + colName.Printf(wxT("rgb(%d, %d, %d)"), + Red(), Green(), Blue()); + } + else if ( colName.empty() && (flags & wxC2S_HTML_SYNTAX) ) + { + // no name for this colour; return it in HTML syntax + colName.Printf(wxT("#%02X%02X%02X"), + Red(), Green(), Blue()); + } + + // this function always returns a non-empty string + wxASSERT_MSG(!colName.empty(), + wxT("Invalid wxColour -> wxString conversion flags")); + + return colName; +} + +#if WXWIN_COMPATIBILITY_2_6 + +// static +wxColour wxColourBase::CreateByName(const wxString& name) +{ + return wxColour(name); +} + +void wxColourBase::InitFromName(const wxString& col) +{ + Set(col); +} + +#endif // WXWIN_COMPATIBILITY_2_6 diff --git a/Externals/wxWidgets/src/common/combocmn.cpp b/Externals/wxWidgets/src/common/combocmn.cpp index 0af24efd3c..86bd1e01ef 100644 --- a/Externals/wxWidgets/src/common/combocmn.cpp +++ b/Externals/wxWidgets/src/common/combocmn.cpp @@ -1,2302 +1,2302 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/combocmn.cpp -// Purpose: wxComboCtrlBase -// Author: Jaakko Salli -// Modified by: -// Created: Apr-30-2006 -// RCS-ID: $Id: combocmn.cpp 45512 2007-04-16 20:51:27Z RD $ -// Copyright: (c) 2005 Jaakko Salli -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_COMBOCTRL - -#include "wx/combobox.h" - -#ifndef WX_PRECOMP - #include "wx/app.h" - #include "wx/log.h" - #include "wx/dcclient.h" - #include "wx/settings.h" - #include "wx/dialog.h" - #include "wx/timer.h" -#endif - -#include "wx/tooltip.h" - -#include "wx/combo.h" - - - -// constants -// ---------------------------------------------------------------------------- - -#define DEFAULT_DROPBUTTON_WIDTH 19 - -#define BMP_BUTTON_MARGIN 4 - -#define DEFAULT_POPUP_HEIGHT 400 - -#define DEFAULT_TEXT_INDENT 3 - -#define COMBO_MARGIN 2 // spacing right of wxTextCtrl - - -#if defined(__WXMSW__) - -#define USE_TRANSIENT_POPUP 1 // Use wxPopupWindowTransient (preferred, if it works properly on platform) -#define TRANSIENT_POPUPWIN_IS_PERFECT 0 // wxPopupTransientWindow works, its child can have focus, and common - // native controls work on it like normal. -#define POPUPWIN_IS_PERFECT 0 // Same, but for non-transient popup window. -#define TEXTCTRL_TEXT_CENTERED 0 // 1 if text in textctrl is vertically centered -#define FOCUS_RING 0 // No focus ring on wxMSW - -//#undef wxUSE_POPUPWIN -//#define wxUSE_POPUPWIN 0 - -#elif defined(__WXGTK__) - -// NB: It is not recommended to use wxDialog as popup on wxGTK, because of -// this bug: If wxDialog is hidden, its position becomes corrupt -// between hide and next show, but without internal coordinates being -// reflected (or something like that - atleast commenting out ->Hide() -// seemed to eliminate the position change). - -#define USE_TRANSIENT_POPUP 1 // Use wxPopupWindowTransient (preferred, if it works properly on platform) -#define TRANSIENT_POPUPWIN_IS_PERFECT 0 // wxPopupTransientWindow works, its child can have focus, and common - // native controls work on it like normal. -#define POPUPWIN_IS_PERFECT 1 // Same, but for non-transient popup window. -#define TEXTCTRL_TEXT_CENTERED 1 // 1 if text in textctrl is vertically centered -#define FOCUS_RING 0 // No focus ring on wxGTK - -#elif defined(__WXMAC__) - -#define USE_TRANSIENT_POPUP 0 // Use wxPopupWindowTransient (preferred, if it works properly on platform) -#define TRANSIENT_POPUPWIN_IS_PERFECT 0 // wxPopupTransientWindow works, its child can have focus, and common - // native controls work on it like normal. -#define POPUPWIN_IS_PERFECT 0 // Same, but for non-transient popup window. -#define TEXTCTRL_TEXT_CENTERED 1 // 1 if text in textctrl is vertically centered -#define FOCUS_RING 3 // Reserve room for the textctrl's focus ring to display - -#undef DEFAULT_DROPBUTTON_WIDTH -#define DEFAULT_DROPBUTTON_WIDTH 22 -#undef COMBO_MARGIN -#define COMBO_MARGIN FOCUS_RING - -#else - -#define USE_TRANSIENT_POPUP 0 // Use wxPopupWindowTransient (preferred, if it works properly on platform) -#define TRANSIENT_POPUPWIN_IS_PERFECT 0 // wxPopupTransientWindow works, its child can have focus, and common - // native controls work on it like normal. -#define POPUPWIN_IS_PERFECT 0 // Same, but for non-transient popup window. -#define TEXTCTRL_TEXT_CENTERED 1 // 1 if text in textctrl is vertically centered -#define FOCUS_RING 0 - -#endif - - -// Popupwin is really only supported on wxMSW (not WINCE) and wxGTK, regardless -// what the wxUSE_POPUPWIN says. -// FIXME: Why isn't wxUSE_POPUPWIN reliable any longer? (it was in wxW2.6.2) -#if (!defined(__WXMSW__) && !defined(__WXGTK__)) || defined(__WXWINCE__) -#undef wxUSE_POPUPWIN -#define wxUSE_POPUPWIN 0 -#endif - - -#if wxUSE_POPUPWIN - #include "wx/popupwin.h" -#else - #undef USE_TRANSIENT_POPUP - #define USE_TRANSIENT_POPUP 0 -#endif - - -// Define different types of popup windows -enum -{ - POPUPWIN_NONE = 0, - POPUPWIN_WXPOPUPTRANSIENTWINDOW = 1, - POPUPWIN_WXPOPUPWINDOW = 2, - POPUPWIN_WXDIALOG = 3 -}; - - -#if USE_TRANSIENT_POPUP - // wxPopupTransientWindow is implemented - - #define wxComboPopupWindowBase wxPopupTransientWindow - #define PRIMARY_POPUP_TYPE POPUPWIN_WXPOPUPTRANSIENTWINDOW - #define USES_WXPOPUPTRANSIENTWINDOW 1 - - #if TRANSIENT_POPUPWIN_IS_PERFECT - // - #elif POPUPWIN_IS_PERFECT - #define wxComboPopupWindowBase2 wxPopupWindow - #define SECONDARY_POPUP_TYPE POPUPWIN_WXPOPUPWINDOW - #define USES_WXPOPUPWINDOW 1 - #else - #define wxComboPopupWindowBase2 wxDialog - #define SECONDARY_POPUP_TYPE POPUPWIN_WXDIALOG - #define USES_WXDIALOG 1 - #endif - -#elif wxUSE_POPUPWIN - // wxPopupWindow (but not wxPopupTransientWindow) is properly implemented - - #define wxComboPopupWindowBase wxPopupWindow - #define PRIMARY_POPUP_TYPE POPUPWIN_WXPOPUPWINDOW - #define USES_WXPOPUPWINDOW 1 - - #if !POPUPWIN_IS_PERFECT - #define wxComboPopupWindowBase2 wxDialog - #define SECONDARY_POPUP_TYPE POPUPWIN_WXDIALOG - #define USES_WXDIALOG 1 - #endif - -#else - // wxPopupWindow is not implemented - - #define wxComboPopupWindowBase wxDialog - #define PRIMARY_POPUP_TYPE POPUPWIN_WXDIALOG - #define USES_WXDIALOG 1 - -#endif - - -#ifndef USES_WXPOPUPTRANSIENTWINDOW - #define USES_WXPOPUPTRANSIENTWINDOW 0 -#endif - -#ifndef USES_WXPOPUPWINDOW - #define USES_WXPOPUPWINDOW 0 -#endif - -#ifndef USES_WXDIALOG - #define USES_WXDIALOG 0 -#endif - - -#if USES_WXPOPUPWINDOW - #define INSTALL_TOPLEV_HANDLER 1 -#else - #define INSTALL_TOPLEV_HANDLER 0 -#endif - - -// -// ** TODO ** -// * wxComboPopupWindow for external use (ie. replace old wxUniv wxPopupComboWindow) -// - - -// ---------------------------------------------------------------------------- -// wxComboFrameEventHandler takes care of hiding the popup when events happen -// in its top level parent. -// ---------------------------------------------------------------------------- - -#if INSTALL_TOPLEV_HANDLER - -// -// This will no longer be necessary after wxTransientPopupWindow -// works well on all platforms. -// - -class wxComboFrameEventHandler : public wxEvtHandler -{ -public: - wxComboFrameEventHandler( wxComboCtrlBase* pCb ); - virtual ~wxComboFrameEventHandler(); - - void OnPopup(); - - void OnIdle( wxIdleEvent& event ); - void OnMouseEvent( wxMouseEvent& event ); - void OnActivate( wxActivateEvent& event ); - void OnResize( wxSizeEvent& event ); - void OnMove( wxMoveEvent& event ); - void OnMenuEvent( wxMenuEvent& event ); - void OnClose( wxCloseEvent& event ); - -protected: - wxWindow* m_focusStart; - wxComboCtrlBase* m_combo; - -private: - DECLARE_EVENT_TABLE() -}; - -BEGIN_EVENT_TABLE(wxComboFrameEventHandler, wxEvtHandler) - EVT_IDLE(wxComboFrameEventHandler::OnIdle) - EVT_LEFT_DOWN(wxComboFrameEventHandler::OnMouseEvent) - EVT_RIGHT_DOWN(wxComboFrameEventHandler::OnMouseEvent) - EVT_SIZE(wxComboFrameEventHandler::OnResize) - EVT_MOVE(wxComboFrameEventHandler::OnMove) - EVT_MENU_HIGHLIGHT(wxID_ANY,wxComboFrameEventHandler::OnMenuEvent) - EVT_MENU_OPEN(wxComboFrameEventHandler::OnMenuEvent) - EVT_ACTIVATE(wxComboFrameEventHandler::OnActivate) - EVT_CLOSE(wxComboFrameEventHandler::OnClose) -END_EVENT_TABLE() - -wxComboFrameEventHandler::wxComboFrameEventHandler( wxComboCtrlBase* combo ) - : wxEvtHandler() -{ - m_combo = combo; -} - -wxComboFrameEventHandler::~wxComboFrameEventHandler() -{ -} - -void wxComboFrameEventHandler::OnPopup() -{ - m_focusStart = ::wxWindow::FindFocus(); -} - -void wxComboFrameEventHandler::OnIdle( wxIdleEvent& event ) -{ - wxWindow* winFocused = ::wxWindow::FindFocus(); - - wxWindow* popup = m_combo->GetPopupControl()->GetControl(); - wxWindow* winpopup = m_combo->GetPopupWindow(); - - if ( - winFocused != m_focusStart && - winFocused != popup && - winFocused->GetParent() != popup && - winFocused != winpopup && - winFocused->GetParent() != winpopup && - winFocused != m_combo && - winFocused != m_combo->GetButton() // GTK (atleast) requires this - ) - { - m_combo->HidePopup(); - } - - event.Skip(); -} - -void wxComboFrameEventHandler::OnMenuEvent( wxMenuEvent& event ) -{ - m_combo->HidePopup(); - event.Skip(); -} - -void wxComboFrameEventHandler::OnMouseEvent( wxMouseEvent& event ) -{ - m_combo->HidePopup(); - event.Skip(); -} - -void wxComboFrameEventHandler::OnClose( wxCloseEvent& event ) -{ - m_combo->HidePopup(); - event.Skip(); -} - -void wxComboFrameEventHandler::OnActivate( wxActivateEvent& event ) -{ - m_combo->HidePopup(); - event.Skip(); -} - -void wxComboFrameEventHandler::OnResize( wxSizeEvent& event ) -{ - m_combo->HidePopup(); - event.Skip(); -} - -void wxComboFrameEventHandler::OnMove( wxMoveEvent& event ) -{ - m_combo->HidePopup(); - event.Skip(); -} - -#endif // INSTALL_TOPLEV_HANDLER - -// ---------------------------------------------------------------------------- -// wxComboPopupWindow is, in essence, wxPopupWindow customized for -// wxComboCtrl. -// ---------------------------------------------------------------------------- - -class wxComboPopupWindow : public wxComboPopupWindowBase -{ -public: - - wxComboPopupWindow( wxComboCtrlBase *parent, - int style ) - #if USES_WXPOPUPWINDOW || USES_WXPOPUPTRANSIENTWINDOW - : wxComboPopupWindowBase(parent,style) - #else - : wxComboPopupWindowBase(parent, - wxID_ANY, - wxEmptyString, - wxPoint(-21,-21), - wxSize(20,20), - style) - #endif - { - m_inShow = 0; - } - -#if USES_WXPOPUPTRANSIENTWINDOW - virtual bool Show( bool show ); - virtual bool ProcessLeftDown(wxMouseEvent& event); -protected: - virtual void OnDismiss(); -#endif - -private: - wxByte m_inShow; -}; - - -#if USES_WXPOPUPTRANSIENTWINDOW -bool wxComboPopupWindow::Show( bool show ) -{ - // Guard against recursion - if ( m_inShow ) - return wxComboPopupWindowBase::Show(show); - - m_inShow++; - - wxASSERT( IsKindOf(CLASSINFO(wxPopupTransientWindow)) ); - - wxPopupTransientWindow* ptw = (wxPopupTransientWindow*) this; - wxComboCtrlBase* combo = (wxComboCtrlBase*) GetParent(); - - if ( show != ptw->IsShown() ) - { - if ( show ) - ptw->Popup(combo->GetPopupControl()->GetControl()); - else - ptw->Dismiss(); - } - - m_inShow--; - - return true; -} - -bool wxComboPopupWindow::ProcessLeftDown(wxMouseEvent& event) -{ - return wxPopupTransientWindow::ProcessLeftDown(event); -} - -// First thing that happens when a transient popup closes is that this method gets called. -void wxComboPopupWindow::OnDismiss() -{ - wxComboCtrlBase* combo = (wxComboCtrlBase*) GetParent(); - wxASSERT_MSG( combo->IsKindOf(CLASSINFO(wxComboCtrlBase)), - wxT("parent might not be wxComboCtrl, but check IMPLEMENT_DYNAMIC_CLASS(2) macro for correctness") ); - - combo->OnPopupDismiss(); -} -#endif // USES_WXPOPUPTRANSIENTWINDOW - - -// ---------------------------------------------------------------------------- -// wxComboPopupWindowEvtHandler does bulk of the custom event handling -// of a popup window. It is separate so we can have different types -// of popup windows. -// ---------------------------------------------------------------------------- - -class wxComboPopupWindowEvtHandler : public wxEvtHandler -{ -public: - - wxComboPopupWindowEvtHandler( wxComboCtrlBase *parent ) - { - m_combo = parent; - } - - void OnSizeEvent( wxSizeEvent& event ); - void OnKeyEvent(wxKeyEvent& event); -#if USES_WXDIALOG - void OnActivate( wxActivateEvent& event ); -#endif - -private: - wxComboCtrlBase* m_combo; - - DECLARE_EVENT_TABLE() -}; - - -BEGIN_EVENT_TABLE(wxComboPopupWindowEvtHandler, wxEvtHandler) - EVT_KEY_DOWN(wxComboPopupWindowEvtHandler::OnKeyEvent) - EVT_KEY_UP(wxComboPopupWindowEvtHandler::OnKeyEvent) -#if USES_WXDIALOG - EVT_ACTIVATE(wxComboPopupWindowEvtHandler::OnActivate) -#endif - EVT_SIZE(wxComboPopupWindowEvtHandler::OnSizeEvent) -END_EVENT_TABLE() - - -void wxComboPopupWindowEvtHandler::OnSizeEvent( wxSizeEvent& WXUNUSED(event) ) -{ - // Block the event so that the popup control does not get auto-resized. -} - -void wxComboPopupWindowEvtHandler::OnKeyEvent( wxKeyEvent& event ) -{ - // Relay keyboard event to the main child controls - wxWindowList children = m_combo->GetPopupWindow()->GetChildren(); - wxWindowList::iterator node = children.begin(); - wxWindow* child = (wxWindow*)*node; - child->AddPendingEvent(event); -} - -#if USES_WXDIALOG -void wxComboPopupWindowEvtHandler::OnActivate( wxActivateEvent& event ) -{ - if ( !event.GetActive() ) - { - // Tell combo control that we are dismissed. - m_combo->HidePopup(); - - event.Skip(); - } -} -#endif - - -// ---------------------------------------------------------------------------- -// wxComboPopup -// -// ---------------------------------------------------------------------------- - -wxComboPopup::~wxComboPopup() -{ -} - -void wxComboPopup::OnPopup() -{ -} - -void wxComboPopup::OnDismiss() -{ -} - -wxSize wxComboPopup::GetAdjustedSize( int minWidth, - int prefHeight, - int WXUNUSED(maxHeight) ) -{ - return wxSize(minWidth,prefHeight); -} - -void wxComboPopup::DefaultPaintComboControl( wxComboCtrlBase* combo, - wxDC& dc, const wxRect& rect ) -{ - if ( combo->GetWindowStyle() & wxCB_READONLY ) // ie. no textctrl - { - combo->PrepareBackground(dc,rect,0); - - dc.DrawText( combo->GetValue(), - rect.x + combo->GetTextIndent(), - (rect.height-dc.GetCharHeight())/2 + rect.y ); - } -} - -void wxComboPopup::PaintComboControl( wxDC& dc, const wxRect& rect ) -{ - DefaultPaintComboControl(m_combo,dc,rect); -} - -void wxComboPopup::OnComboKeyEvent( wxKeyEvent& event ) -{ - event.Skip(); -} - -void wxComboPopup::OnComboDoubleClick() -{ -} - -void wxComboPopup::SetStringValue( const wxString& WXUNUSED(value) ) -{ -} - -bool wxComboPopup::LazyCreate() -{ - return false; -} - -void wxComboPopup::Dismiss() -{ - m_combo->HidePopup(); -} - -// ---------------------------------------------------------------------------- -// input handling -// ---------------------------------------------------------------------------- - -// -// This is pushed to the event handler queue of the child textctrl. -// -class wxComboBoxExtraInputHandler : public wxEvtHandler -{ -public: - - wxComboBoxExtraInputHandler( wxComboCtrlBase* combo ) - : wxEvtHandler() - { - m_combo = combo; - } - virtual ~wxComboBoxExtraInputHandler() { } - void OnKey(wxKeyEvent& event); - void OnFocus(wxFocusEvent& event); - -protected: - wxComboCtrlBase* m_combo; - -private: - DECLARE_EVENT_TABLE() -}; - - -BEGIN_EVENT_TABLE(wxComboBoxExtraInputHandler, wxEvtHandler) - EVT_KEY_DOWN(wxComboBoxExtraInputHandler::OnKey) - EVT_SET_FOCUS(wxComboBoxExtraInputHandler::OnFocus) -END_EVENT_TABLE() - - -void wxComboBoxExtraInputHandler::OnKey(wxKeyEvent& event) -{ - // Let the wxComboCtrl event handler have a go first. - wxComboCtrlBase* combo = m_combo; - wxObject* prevObj = event.GetEventObject(); - - event.SetId(combo->GetId()); - event.SetEventObject(combo); - combo->GetEventHandler()->ProcessEvent(event); - - event.SetId(((wxWindow*)prevObj)->GetId()); - event.SetEventObject(prevObj); -} - -void wxComboBoxExtraInputHandler::OnFocus(wxFocusEvent& event) -{ - // FIXME: This code does run when control is clicked, - // yet on Windows it doesn't select all the text. - if ( !(m_combo->GetInternalFlags() & wxCC_NO_TEXT_AUTO_SELECT) ) - { - if ( m_combo->GetTextCtrl() ) - m_combo->GetTextCtrl()->SelectAll(); - else - m_combo->SetSelection(-1,-1); - } - - // Send focus indication to parent. - // NB: This is needed for cases where the textctrl gets focus - // instead of its parent. While this may trigger multiple - // wxEVT_SET_FOCUSes (since m_text->SetFocus is called - // from combo's focus event handler), they should be quite - // harmless. - wxFocusEvent evt2(wxEVT_SET_FOCUS,m_combo->GetId()); - evt2.SetEventObject(m_combo); - m_combo->GetEventHandler()->ProcessEvent(evt2); - - event.Skip(); -} - - -// -// This is pushed to the event handler queue of the control in popup. -// - -class wxComboPopupExtraEventHandler : public wxEvtHandler -{ -public: - - wxComboPopupExtraEventHandler( wxComboCtrlBase* combo ) - : wxEvtHandler() - { - m_combo = combo; - m_beenInside = false; - } - virtual ~wxComboPopupExtraEventHandler() { } - - void OnMouseEvent( wxMouseEvent& event ); - - // Called from wxComboCtrlBase::OnPopupDismiss - void OnPopupDismiss() - { - m_beenInside = false; - } - -protected: - wxComboCtrlBase* m_combo; - - bool m_beenInside; - -private: - DECLARE_EVENT_TABLE() -}; - - -BEGIN_EVENT_TABLE(wxComboPopupExtraEventHandler, wxEvtHandler) - EVT_MOUSE_EVENTS(wxComboPopupExtraEventHandler::OnMouseEvent) -END_EVENT_TABLE() - - -void wxComboPopupExtraEventHandler::OnMouseEvent( wxMouseEvent& event ) -{ - wxPoint pt = event.GetPosition(); - wxSize sz = m_combo->GetPopupControl()->GetControl()->GetClientSize(); - int evtType = event.GetEventType(); - bool isInside = pt.x >= 0 && pt.y >= 0 && pt.x < sz.x && pt.y < sz.y; - - if ( evtType == wxEVT_MOTION || - evtType == wxEVT_LEFT_DOWN || - evtType == wxEVT_RIGHT_DOWN ) - { - // Block motion and click events outside the popup - if ( !isInside || !m_combo->IsPopupShown() ) - { - event.Skip(false); - return; - } - } - else if ( evtType == wxEVT_LEFT_UP ) - { - if ( !m_combo->IsPopupShown() ) - { - event.Skip(false); - return; - } - - if ( !m_beenInside ) - { - if ( isInside ) - { - m_beenInside = true; - } - else - { - // - // Some mouse events to popup that happen outside it, before cursor - // has been inside the popu, need to be ignored by it but relayed to - // the dropbutton. - // - wxWindow* btn = m_combo->GetButton(); - if ( btn ) - btn->GetEventHandler()->AddPendingEvent(event); - else - m_combo->GetEventHandler()->AddPendingEvent(event); - - return; - } - - event.Skip(); - } - } - - event.Skip(); -} - -// ---------------------------------------------------------------------------- -// wxComboCtrlBase -// ---------------------------------------------------------------------------- - - -BEGIN_EVENT_TABLE(wxComboCtrlBase, wxControl) - EVT_TEXT(wxID_ANY,wxComboCtrlBase::OnTextCtrlEvent) - EVT_SIZE(wxComboCtrlBase::OnSizeEvent) - EVT_SET_FOCUS(wxComboCtrlBase::OnFocusEvent) - EVT_KILL_FOCUS(wxComboCtrlBase::OnFocusEvent) - EVT_IDLE(wxComboCtrlBase::OnIdleEvent) - //EVT_BUTTON(wxID_ANY,wxComboCtrlBase::OnButtonClickEvent) - EVT_KEY_DOWN(wxComboCtrlBase::OnKeyEvent) - EVT_TEXT_ENTER(wxID_ANY,wxComboCtrlBase::OnTextCtrlEvent) - EVT_SYS_COLOUR_CHANGED(wxComboCtrlBase::OnSysColourChanged) -END_EVENT_TABLE() - - -IMPLEMENT_ABSTRACT_CLASS(wxComboCtrlBase, wxControl) - -void wxComboCtrlBase::Init() -{ - m_winPopup = (wxWindow *)NULL; - m_popup = (wxWindow *)NULL; - m_popupWinState = Hidden; - m_btn = (wxWindow*) NULL; - m_text = (wxTextCtrl*) NULL; - m_popupInterface = (wxComboPopup*) NULL; - - m_popupExtraHandler = (wxEvtHandler*) NULL; - m_textEvtHandler = (wxEvtHandler*) NULL; - -#if INSTALL_TOPLEV_HANDLER - m_toplevEvtHandler = (wxEvtHandler*) NULL; -#endif - - m_mainCtrlWnd = this; - - m_heightPopup = -1; - m_widthMinPopup = -1; - m_anchorSide = 0; - m_widthCustomPaint = 0; - m_widthCustomBorder = 0; - - m_btnState = 0; - m_btnWidDefault = 0; - m_blankButtonBg = false; - m_ignoreEvtText = 0; - m_popupWinType = POPUPWIN_NONE; - m_btnWid = m_btnHei = -1; - m_btnSide = wxRIGHT; - m_btnSpacingX = 0; - - m_extLeft = 0; - m_extRight = 0; - m_absIndent = -1; - m_iFlags = 0; - m_timeCanAcceptClick = 0; - - m_resetFocus = false; -} - -bool wxComboCtrlBase::Create(wxWindow *parent, - wxWindowID id, - const wxString& value, - const wxPoint& pos, - const wxSize& size, - long style, - const wxValidator& validator, - const wxString& name) -{ - if ( !wxControl::Create(parent, - id, - pos, - size, - style | wxWANTS_CHARS, - validator, - name) ) - return false; - - m_valueString = value; - - // Get colours - OnThemeChange(); - m_absIndent = GetNativeTextIndent(); - - m_iFlags |= wxCC_IFLAG_CREATED; - - // If x and y indicate valid size, wxSizeEvent won't be - // emitted automatically, so we need to add artifical one. - if ( size.x > 0 && size.y > 0 ) - { - wxSizeEvent evt(size,GetId()); - GetEventHandler()->AddPendingEvent(evt); - } - - return true; -} - -void wxComboCtrlBase::InstallInputHandlers() -{ - if ( m_text ) - { - m_textEvtHandler = new wxComboBoxExtraInputHandler(this); - m_text->PushEventHandler(m_textEvtHandler); - } -} - -void -wxComboCtrlBase::CreateTextCtrl(int style, const wxValidator& validator) -{ - if ( !(m_windowStyle & wxCB_READONLY) ) - { - if ( m_text ) - m_text->Destroy(); - - // wxTE_PROCESS_TAB is needed because on Windows, wxTAB_TRAVERSAL is - // not used by the wxPropertyGrid and therefore the tab is processed by - // looking at ancestors to see if they have wxTAB_TRAVERSAL. The - // navigation event is then sent to the wrong window. - style |= wxTE_PROCESS_TAB; - - if ( HasFlag(wxTE_PROCESS_ENTER) ) - style |= wxTE_PROCESS_ENTER; - - // Ignore EVT_TEXT generated by the constructor (but only - // if the event redirector already exists) - // NB: This must be " = 1" instead of "++"; - if ( m_textEvtHandler ) - m_ignoreEvtText = 1; - else - m_ignoreEvtText = 0; - - m_text = new wxTextCtrl(this, wxID_ANY, m_valueString, - wxDefaultPosition, wxSize(10,-1), - style, validator); - } -} - -void wxComboCtrlBase::OnThemeChange() -{ - // Leave the default bg on the Mac so the area used by the focus ring will - // be the correct colour and themed brush. Instead we'll use - // wxSYS_COLOUR_WINDOW in the EVT_PAINT handler as needed. -#ifndef __WXMAC__ - SetOwnBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW)); -#endif -} - -wxComboCtrlBase::~wxComboCtrlBase() -{ - if ( HasCapture() ) - ReleaseMouse(); - -#if INSTALL_TOPLEV_HANDLER - delete ((wxComboFrameEventHandler*)m_toplevEvtHandler); - m_toplevEvtHandler = (wxEvtHandler*) NULL; -#endif - - DestroyPopup(); - - if ( m_text ) - m_text->RemoveEventHandler(m_textEvtHandler); - - delete m_textEvtHandler; -} - - -// ---------------------------------------------------------------------------- -// geometry stuff -// ---------------------------------------------------------------------------- - -// Recalculates button and textctrl areas -void wxComboCtrlBase::CalculateAreas( int btnWidth ) -{ - wxSize sz = GetClientSize(); - int customBorder = m_widthCustomBorder; - int btnBorder; // border for button only - - // check if button should really be outside the border: we'll do it it if - // its platform default or bitmap+pushbutton background is used, but not if - // there is vertical size adjustment or horizontal spacing. - if ( ( (m_iFlags & wxCC_BUTTON_OUTSIDE_BORDER) || - (m_bmpNormal.Ok() && m_blankButtonBg) ) && - m_btnSpacingX == 0 && - m_btnHei <= 0 ) - { - m_iFlags |= wxCC_IFLAG_BUTTON_OUTSIDE; - btnBorder = 0; - } - else - { - m_iFlags &= ~(wxCC_IFLAG_BUTTON_OUTSIDE); - btnBorder = customBorder; - } - - // Defaul indentation - if ( m_absIndent < 0 ) - m_absIndent = GetNativeTextIndent(); - - int butWidth = btnWidth; - - if ( butWidth <= 0 ) - butWidth = m_btnWidDefault; - else - m_btnWidDefault = butWidth; - - if ( butWidth <= 0 ) - return; - - int butHeight = sz.y - btnBorder*2; - - // Adjust button width - if ( m_btnWid > 0 ) - butWidth = m_btnWid; - else - { - // Adjust button width to match aspect ratio - // (but only if control is smaller than best size). - int bestHeight = GetBestSize().y; - int height = GetSize().y; - - if ( height < bestHeight ) - { - // Make very small buttons square, as it makes - // them accommodate arrow image better and still - // looks decent. - if ( height > 18 ) - butWidth = (height*butWidth)/bestHeight; - else - butWidth = butHeight; - } - } - - // Adjust button height - if ( m_btnHei > 0 ) - butHeight = m_btnHei; - - // Use size of normal bitmap if... - // It is larger - // OR - // button width is set to default and blank button bg is not drawn - if ( m_bmpNormal.Ok() ) - { - int bmpReqWidth = m_bmpNormal.GetWidth(); - int bmpReqHeight = m_bmpNormal.GetHeight(); - - // If drawing blank button background, we need to add some margin. - if ( m_blankButtonBg ) - { - bmpReqWidth += BMP_BUTTON_MARGIN*2; - bmpReqHeight += BMP_BUTTON_MARGIN*2; - } - - if ( butWidth < bmpReqWidth || ( m_btnWid == 0 && !m_blankButtonBg ) ) - butWidth = bmpReqWidth; - if ( butHeight < bmpReqHeight || ( m_btnHei == 0 && !m_blankButtonBg ) ) - butHeight = bmpReqHeight; - - // Need to fix height? - if ( (sz.y-(customBorder*2)) < butHeight && btnWidth == 0 ) - { - int newY = butHeight+(customBorder*2); - SetClientSize(wxDefaultCoord,newY); - sz.y = newY; - } - } - - int butAreaWid = butWidth + (m_btnSpacingX*2); - - m_btnSize.x = butWidth; - m_btnSize.y = butHeight; - - m_btnArea.x = ( m_btnSide==wxRIGHT ? sz.x - butAreaWid - btnBorder : btnBorder ); - m_btnArea.y = btnBorder + FOCUS_RING; - m_btnArea.width = butAreaWid; - m_btnArea.height = sz.y - ((btnBorder+FOCUS_RING)*2); - - m_tcArea.x = ( m_btnSide==wxRIGHT ? 0 : butAreaWid ) + customBorder + FOCUS_RING; - m_tcArea.y = customBorder + FOCUS_RING; - m_tcArea.width = sz.x - butAreaWid - (customBorder*2) - (FOCUS_RING*2); - m_tcArea.height = sz.y - ((customBorder+FOCUS_RING)*2); - -/* - if ( m_text ) - { - ::wxMessageBox(wxString::Format(wxT("ButtonArea (%i,%i,%i,%i)\n"),m_btnArea.x,m_btnArea.y,m_btnArea.width,m_btnArea.height) + - wxString::Format(wxT("TextCtrlArea (%i,%i,%i,%i)"),m_tcArea.x,m_tcArea.y,m_tcArea.width,m_tcArea.height)); - } -*/ -} - -void wxComboCtrlBase::PositionTextCtrl( int textCtrlXAdjust, int textCtrlYAdjust ) -{ - if ( !m_text ) - return; - -#if !TEXTCTRL_TEXT_CENTERED - - wxSize sz = GetClientSize(); - - int customBorder = m_widthCustomBorder; - if ( (m_text->GetWindowStyleFlag() & wxBORDER_MASK) == wxNO_BORDER ) - { - // Centre textctrl - int tcSizeY = m_text->GetBestSize().y; - int diff = sz.y - tcSizeY; - int y = textCtrlYAdjust + (diff/2); - - if ( y < customBorder ) - y = customBorder; - - m_text->SetSize( m_tcArea.x + m_widthCustomPaint + m_absIndent + textCtrlXAdjust, - y, - m_tcArea.width - COMBO_MARGIN - - (textCtrlXAdjust + m_widthCustomPaint + m_absIndent), - -1 ); - - // Make sure textctrl doesn't exceed the bottom custom border - wxSize tsz = m_text->GetSize(); - diff = (y + tsz.y) - (sz.y - customBorder); - if ( diff >= 0 ) - { - tsz.y = tsz.y - diff - 1; - m_text->SetSize(tsz); - } - } - else -#else // TEXTCTRL_TEXT_CENTERED - wxUnusedVar(textCtrlXAdjust); - wxUnusedVar(textCtrlYAdjust); -#endif // !TEXTCTRL_TEXT_CENTERED/TEXTCTRL_TEXT_CENTERED - { - // If it has border, have textctrl will the entire text field. - m_text->SetSize( m_tcArea.x + m_widthCustomPaint, - m_tcArea.y, - m_tcArea.width - m_widthCustomPaint, - m_tcArea.height ); - } -} - -wxSize wxComboCtrlBase::DoGetBestSize() const -{ - wxSize sizeText(150,0); - - if ( m_text ) - sizeText = m_text->GetBestSize(); - - // TODO: Better method to calculate close-to-native control height. - - int fhei; - if ( m_font.Ok() ) - fhei = (m_font.GetPointSize()*2) + 5; - else if ( wxNORMAL_FONT->Ok() ) - fhei = (wxNORMAL_FONT->GetPointSize()*2) + 5; - else - fhei = sizeText.y + 4; - - // Need to force height to accomodate bitmap? - int btnSizeY = m_btnSize.y; - if ( m_bmpNormal.Ok() && fhei < btnSizeY ) - fhei = btnSizeY; - - // Control height doesn't depend on border -/* - // Add border - int border = m_windowStyle & wxBORDER_MASK; - if ( border == wxSIMPLE_BORDER ) - fhei += 2; - else if ( border == wxNO_BORDER ) - fhei += (m_widthCustomBorder*2); - else - // Sunken etc. - fhei += 4; -*/ - - // Final adjustments -#ifdef __WXGTK__ - fhei += 1; -#endif - -#ifdef __WXMAC__ - // these are the numbers from the HIG: - switch ( m_windowVariant ) - { - case wxWINDOW_VARIANT_NORMAL: - default : - fhei = 22; - break; - case wxWINDOW_VARIANT_SMALL: - fhei = 19; - break; - case wxWINDOW_VARIANT_MINI: - fhei = 15; - break; - } -#endif - - fhei += 2 * FOCUS_RING; - int width = sizeText.x + FOCUS_RING + COMBO_MARGIN + DEFAULT_DROPBUTTON_WIDTH; - - wxSize ret(width, fhei); - CacheBestSize(ret); - return ret; -} - -void wxComboCtrlBase::OnSizeEvent( wxSizeEvent& event ) -{ - if ( !IsCreated() ) - return; - - // defined by actual wxComboCtrls - OnResize(); - - event.Skip(); -} - -// ---------------------------------------------------------------------------- -// standard operations -// ---------------------------------------------------------------------------- - -bool wxComboCtrlBase::Enable(bool enable) -{ - if ( !wxControl::Enable(enable) ) - return false; - - if ( m_btn ) - m_btn->Enable(enable); - if ( m_text ) - m_text->Enable(enable); - - return true; -} - -bool wxComboCtrlBase::Show(bool show) -{ - if ( !wxControl::Show(show) ) - return false; - - if (m_btn) - m_btn->Show(show); - - if (m_text) - m_text->Show(show); - - return true; -} - -bool wxComboCtrlBase::SetFont ( const wxFont& font ) -{ - if ( !wxControl::SetFont(font) ) - return false; - - if (m_text) - m_text->SetFont(font); - - return true; -} - -#if wxUSE_TOOLTIPS -void wxComboCtrlBase::DoSetToolTip(wxToolTip *tooltip) -{ - wxControl::DoSetToolTip(tooltip); - - // Set tool tip for button and text box - if ( tooltip ) - { - const wxString &tip = tooltip->GetTip(); - if ( m_text ) m_text->SetToolTip(tip); - if ( m_btn ) m_btn->SetToolTip(tip); - } - else - { - if ( m_text ) m_text->SetToolTip( (wxToolTip*) NULL ); - if ( m_btn ) m_btn->SetToolTip( (wxToolTip*) NULL ); - } -} -#endif // wxUSE_TOOLTIPS - -#if wxUSE_VALIDATORS -void wxComboCtrlBase::SetValidator(const wxValidator& validator) -{ - wxTextCtrl* textCtrl = GetTextCtrl(); - - if ( textCtrl ) - textCtrl->SetValidator( validator ); -} - -wxValidator* wxComboCtrlBase::GetValidator() -{ - wxTextCtrl* textCtrl = GetTextCtrl(); - - if ( textCtrl ) - return textCtrl->GetValidator(); - - return wxControl::GetValidator(); -} -#endif // wxUSE_VALIDATORS - -// ---------------------------------------------------------------------------- -// painting -// ---------------------------------------------------------------------------- - -#if (!defined(__WXMSW__)) || defined(__WXUNIVERSAL__) -// prepare combo box background on area in a way typical on platform -void wxComboCtrlBase::PrepareBackground( wxDC& dc, const wxRect& rect, int flags ) const -{ - wxSize sz = GetClientSize(); - bool isEnabled; - bool isFocused; // also selected - - // For smaller size control (and for disabled background) use less spacing - int focusSpacingX; - int focusSpacingY; - - if ( !(flags & wxCONTROL_ISSUBMENU) ) - { - // Drawing control - isEnabled = IsEnabled(); - isFocused = ShouldDrawFocus(); - - // Windows-style: for smaller size control (and for disabled background) use less spacing - focusSpacingX = isEnabled ? 2 : 1; - focusSpacingY = sz.y > (GetCharHeight()+2) && isEnabled ? 2 : 1; - } - else - { - // Drawing a list item - isEnabled = true; // they are never disabled - isFocused = flags & wxCONTROL_SELECTED ? true : false; - - focusSpacingX = 0; - focusSpacingY = 0; - } - - // Set the background sub-rectangle for selection, disabled etc - wxRect selRect(rect); - selRect.y += focusSpacingY; - selRect.height -= (focusSpacingY*2); - - int wcp = 0; - - if ( !(flags & wxCONTROL_ISSUBMENU) ) - wcp += m_widthCustomPaint; - - selRect.x += wcp + focusSpacingX; - selRect.width -= wcp + (focusSpacingX*2); - - wxColour bgCol; - - if ( isEnabled ) - { - // If popup is hidden and this control is focused, - // then draw the focus-indicator (selbgcolor background etc.). - if ( isFocused ) - { - dc.SetTextForeground( wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT) ); - bgCol = wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT); - } - else - { - dc.SetTextForeground( wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT) ); -#ifndef __WXMAC__ // see note in OnThemeChange - bgCol = GetBackgroundColour(); -#else - bgCol = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW); -#endif - } - } - else - { - dc.SetTextForeground( wxSystemSettings::GetColour(wxSYS_COLOUR_GRAYTEXT) ); -#ifndef __WXMAC__ // see note in OnThemeChange - bgCol = GetBackgroundColour(); -#else - bgCol = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW); -#endif - } - - dc.SetBrush( bgCol ); - dc.SetPen( bgCol ); - dc.DrawRectangle( selRect ); - - // Don't clip exactly to the selection rectangle so we can draw - // to the non-selected area in front of it. - wxRect clipRect(rect.x,rect.y, - (selRect.x+selRect.width)-rect.x,rect.height); - dc.SetClippingRegion(clipRect); -} -#else -// Save the library size a bit for platforms that re-implement this. -void wxComboCtrlBase::PrepareBackground( wxDC&, const wxRect&, int ) const -{ -} -#endif - -void wxComboCtrlBase::DrawButton( wxDC& dc, const wxRect& rect, int paintBg ) -{ - int drawState = m_btnState; - -#ifdef __WXGTK__ - if ( GetPopupWindowState() >= Animating ) - drawState |= wxCONTROL_PRESSED; -#endif - - wxRect drawRect(rect.x+m_btnSpacingX, - rect.y+((rect.height-m_btnSize.y)/2), - m_btnSize.x, - m_btnSize.y); - - // Make sure area is not larger than the control - if ( drawRect.y < rect.y ) - drawRect.y = rect.y; - if ( drawRect.height > rect.height ) - drawRect.height = rect.height; - - bool enabled = IsEnabled(); - - if ( !enabled ) - drawState |= wxCONTROL_DISABLED; - - if ( !m_bmpNormal.Ok() ) - { - // Need to clear button background even if m_btn is present - if ( paintBg ) - { - wxColour bgCol; - - if ( m_iFlags & wxCC_IFLAG_BUTTON_OUTSIDE ) - bgCol = GetParent()->GetBackgroundColour(); - else - bgCol = GetBackgroundColour(); - - dc.SetBrush(bgCol); - dc.SetPen(bgCol); - dc.DrawRectangle(rect); - } - - // Draw standard button - wxRendererNative::Get().DrawComboBoxDropButton(this, - dc, - drawRect, - drawState); - } - else - { - // Draw bitmap - - wxBitmap* pBmp; - - if ( !enabled ) - pBmp = &m_bmpDisabled; - else if ( m_btnState & wxCONTROL_PRESSED ) - pBmp = &m_bmpPressed; - else if ( m_btnState & wxCONTROL_CURRENT ) - pBmp = &m_bmpHover; - else - pBmp = &m_bmpNormal; - - if ( m_blankButtonBg ) - { - // If using blank button background, we need to clear its background - // with button face colour instead of colour for rest of the control. - if ( paintBg ) - { - wxColour bgCol = GetParent()->GetBackgroundColour(); //wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE); - //wxColour bgCol = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW); - dc.SetPen(bgCol); - dc.SetBrush(bgCol); - dc.DrawRectangle(rect); - } - - wxRendererNative::Get().DrawPushButton(this, - dc, - drawRect, - drawState); - - } - else - - { - // Need to clear button background even if m_btn is present - // (assume non-button background was cleared just before this call so brushes are good) - if ( paintBg ) - dc.DrawRectangle(rect); - } - - // Draw bitmap centered in drawRect - dc.DrawBitmap(*pBmp, - drawRect.x + (drawRect.width-pBmp->GetWidth())/2, - drawRect.y + (drawRect.height-pBmp->GetHeight())/2, - true); - } -} - -void wxComboCtrlBase::RecalcAndRefresh() -{ - if ( IsCreated() ) - { - wxSizeEvent evt(GetSize(),GetId()); - GetEventHandler()->ProcessEvent(evt); - Refresh(); - } -} - -// ---------------------------------------------------------------------------- -// miscellaneous event handlers -// ---------------------------------------------------------------------------- - -void wxComboCtrlBase::OnTextCtrlEvent(wxCommandEvent& event) -{ - if ( event.GetEventType() == wxEVT_COMMAND_TEXT_UPDATED ) - { - if ( m_ignoreEvtText > 0 ) - { - m_ignoreEvtText--; - return; - } - } - - // Change event id, object and string before relaying it forward - event.SetId(GetId()); - wxString s = event.GetString(); - event.SetEventObject(this); - event.SetString(s); - event.Skip(); -} - -// call if cursor is on button area or mouse is captured for the button -bool wxComboCtrlBase::HandleButtonMouseEvent( wxMouseEvent& event, - int flags ) -{ - int type = event.GetEventType(); - - if ( type == wxEVT_MOTION ) - { - if ( flags & wxCC_MF_ON_BUTTON ) - { - if ( !(m_btnState & wxCONTROL_CURRENT) ) - { - // Mouse hover begins - m_btnState |= wxCONTROL_CURRENT; - if ( HasCapture() ) // Retain pressed state. - m_btnState |= wxCONTROL_PRESSED; - Refresh(); - } - } - else if ( (m_btnState & wxCONTROL_CURRENT) ) - { - // Mouse hover ends - m_btnState &= ~(wxCONTROL_CURRENT|wxCONTROL_PRESSED); - Refresh(); - } - } - else if ( type == wxEVT_LEFT_DOWN || type == wxEVT_LEFT_DCLICK ) - { - if ( flags & (wxCC_MF_ON_CLICK_AREA|wxCC_MF_ON_BUTTON) ) - { - m_btnState |= wxCONTROL_PRESSED; - Refresh(); - - if ( !(m_iFlags & wxCC_POPUP_ON_MOUSE_UP) ) - OnButtonClick(); - else - // If showing popup now, do not capture mouse or there will be interference - CaptureMouse(); - } - } - else if ( type == wxEVT_LEFT_UP ) - { - - // Only accept event if mouse was left-press was previously accepted - if ( HasCapture() ) - ReleaseMouse(); - - if ( m_btnState & wxCONTROL_PRESSED ) - { - // If mouse was inside, fire the click event. - if ( m_iFlags & wxCC_POPUP_ON_MOUSE_UP ) - { - if ( flags & (wxCC_MF_ON_CLICK_AREA|wxCC_MF_ON_BUTTON) ) - OnButtonClick(); - } - - m_btnState &= ~(wxCONTROL_PRESSED); - Refresh(); - } - } - else if ( type == wxEVT_LEAVE_WINDOW ) - { - if ( m_btnState & (wxCONTROL_CURRENT|wxCONTROL_PRESSED) ) - { - m_btnState &= ~(wxCONTROL_CURRENT); - - // Mouse hover ends - if ( IsPopupWindowState(Hidden) ) - { - m_btnState &= ~(wxCONTROL_PRESSED); - Refresh(); - } - } - } - else - return false; - - return true; -} - -// returns true if event was consumed or filtered -bool wxComboCtrlBase::PreprocessMouseEvent( wxMouseEvent& event, - int WXUNUSED(flags) ) -{ - wxLongLong t = ::wxGetLocalTimeMillis(); - int evtType = event.GetEventType(); - -#if USES_WXPOPUPWINDOW || USES_WXDIALOG - if ( m_popupWinType != POPUPWIN_WXPOPUPTRANSIENTWINDOW ) - { - if ( IsPopupWindowState(Visible) && - ( evtType == wxEVT_LEFT_DOWN || evtType == wxEVT_RIGHT_DOWN ) ) - { - HidePopup(); - return true; - } - } -#endif - - // Filter out clicks on button immediately after popup dismiss (Windows like behaviour) - if ( evtType == wxEVT_LEFT_DOWN && t < m_timeCanAcceptClick ) - { - event.SetEventType(0); - return true; - } - - return false; -} - -void wxComboCtrlBase::HandleNormalMouseEvent( wxMouseEvent& event ) -{ - int evtType = event.GetEventType(); - - if ( (evtType == wxEVT_LEFT_DOWN || evtType == wxEVT_LEFT_DCLICK) && - (m_windowStyle & wxCB_READONLY) ) - { - if ( GetPopupWindowState() >= Animating ) - { - #if USES_WXPOPUPWINDOW - // Click here always hides the popup. - if ( m_popupWinType == POPUPWIN_WXPOPUPWINDOW ) - HidePopup(); - #endif - } - else - { - if ( !(m_windowStyle & wxCC_SPECIAL_DCLICK) ) - { - // In read-only mode, clicking the text is the - // same as clicking the button. - OnButtonClick(); - } - else if ( /*evtType == wxEVT_LEFT_UP || */evtType == wxEVT_LEFT_DCLICK ) - { - //if ( m_popupInterface->CycleValue() ) - // Refresh(); - if ( m_popupInterface ) - m_popupInterface->OnComboDoubleClick(); - } - } - } - else - if ( IsPopupShown() ) - { - // relay (some) mouse events to the popup - if ( evtType == wxEVT_MOUSEWHEEL ) - m_popup->AddPendingEvent(event); - } - else if ( evtType ) - event.Skip(); -} - -void wxComboCtrlBase::OnKeyEvent(wxKeyEvent& event) -{ - if ( IsPopupShown() ) - { - // pass it to the popped up control - GetPopupControl()->GetControl()->AddPendingEvent(event); - } - else // no popup - { - int keycode = event.GetKeyCode(); - - if ( keycode == WXK_TAB ) - { - wxNavigationKeyEvent evt; - - wxWindow* mainCtrl = GetMainWindowOfCompositeControl(); - - evt.SetFlags(wxNavigationKeyEvent::FromTab| - (!event.ShiftDown() ? wxNavigationKeyEvent::IsForward - : wxNavigationKeyEvent::IsBackward)); - evt.SetEventObject(mainCtrl); - evt.SetCurrentFocus(mainCtrl); - mainCtrl->GetParent()->GetEventHandler()->AddPendingEvent(evt); - return; - } - - if ( IsKeyPopupToggle(event) ) - { - OnButtonClick(); - return; - } - - int comboStyle = GetWindowStyle(); - wxComboPopup* popupInterface = GetPopupControl(); - - if ( !popupInterface ) - { - event.Skip(); - return; - } - - if ( (comboStyle & wxCB_READONLY) || - (keycode != WXK_RIGHT && keycode != WXK_LEFT) ) - { - popupInterface->OnComboKeyEvent(event); - } - else - event.Skip(); - } -} - -void wxComboCtrlBase::OnFocusEvent( wxFocusEvent& event ) -{ - if ( event.GetEventType() == wxEVT_SET_FOCUS ) - { - wxWindow* tc = GetTextCtrl(); - if ( tc && tc != DoFindFocus() ) -#ifdef __WXMAC__ - m_resetFocus = true; -#else - tc->SetFocus(); -#endif - } - - Refresh(); -} - -void wxComboCtrlBase::OnIdleEvent( wxIdleEvent& WXUNUSED(event) ) -{ - if ( m_resetFocus ) - { - m_resetFocus = false; - wxWindow* tc = GetTextCtrl(); - if ( tc ) - tc->SetFocus(); - } -} - -void wxComboCtrlBase::OnSysColourChanged(wxSysColourChangedEvent& WXUNUSED(event)) -{ - OnThemeChange(); - // indentation may also have changed - if ( !(m_iFlags & wxCC_IFLAG_INDENT_SET) ) - m_absIndent = GetNativeTextIndent(); - RecalcAndRefresh(); -} - -// ---------------------------------------------------------------------------- -// popup handling -// ---------------------------------------------------------------------------- - -// Create popup window and the child control -void wxComboCtrlBase::CreatePopup() -{ - wxComboPopup* popupInterface = m_popupInterface; - wxWindow* popup; - - if ( !m_winPopup ) - { -#ifdef wxComboPopupWindowBase2 - if ( m_iFlags & wxCC_IFLAG_USE_ALT_POPUP ) - { - #if !USES_WXDIALOG - m_winPopup = new wxComboPopupWindowBase2( this, wxNO_BORDER ); - #else - m_winPopup = new wxComboPopupWindowBase2( this, wxID_ANY, wxEmptyString, - wxPoint(-21,-21), wxSize(20, 20), - wxNO_BORDER ); - #endif - m_popupWinType = SECONDARY_POPUP_TYPE; - } - else -#endif - { - m_winPopup = new wxComboPopupWindow( this, wxNO_BORDER ); - m_popupWinType = PRIMARY_POPUP_TYPE; - } - m_popupWinEvtHandler = new wxComboPopupWindowEvtHandler(this); - m_winPopup->PushEventHandler(m_popupWinEvtHandler); - } - - popupInterface->Create(m_winPopup); - m_popup = popup = popupInterface->GetControl(); - - m_popupExtraHandler = new wxComboPopupExtraEventHandler(this); - popup->PushEventHandler( m_popupExtraHandler ); - - // This may be helpful on some platforms - // (eg. it bypasses a wxGTK popupwindow bug where - // window is not initially hidden when it should be) - m_winPopup->Hide(); - - popupInterface->m_iFlags |= wxCP_IFLAG_CREATED; -} - -// Destroy popup window and the child control -void wxComboCtrlBase::DestroyPopup() -{ - HidePopup(); - - if ( m_popup ) - m_popup->RemoveEventHandler(m_popupExtraHandler); - - delete m_popupExtraHandler; - - delete m_popupInterface; - - if ( m_winPopup ) - { - m_winPopup->RemoveEventHandler(m_popupWinEvtHandler); - delete m_popupWinEvtHandler; - m_popupWinEvtHandler = NULL; - m_winPopup->Destroy(); - } - - m_popupExtraHandler = (wxEvtHandler*) NULL; - m_popupInterface = (wxComboPopup*) NULL; - m_winPopup = (wxWindow*) NULL; - m_popup = (wxWindow*) NULL; -} - -void wxComboCtrlBase::DoSetPopupControl(wxComboPopup* iface) -{ - wxCHECK_RET( iface, wxT("no popup interface set for wxComboCtrl") ); - - DestroyPopup(); - - iface->InitBase(this); - iface->Init(); - - m_popupInterface = iface; - - if ( !iface->LazyCreate() ) - { - CreatePopup(); - } - else - { - m_popup = (wxWindow*) NULL; - } - - // This must be done after creation - if ( m_valueString.length() ) - { - iface->SetStringValue(m_valueString); - //Refresh(); - } -} - -// Ensures there is atleast the default popup -void wxComboCtrlBase::EnsurePopupControl() -{ - if ( !m_popupInterface ) - SetPopupControl(NULL); -} - -void wxComboCtrlBase::OnButtonClick() -{ - // Derived classes can override this method for totally custom - // popup action - ShowPopup(); -} - -void wxComboCtrlBase::ShowPopup() -{ - EnsurePopupControl(); - wxCHECK_RET( !IsPopupWindowState(Visible), wxT("popup window already shown") ); - - if ( IsPopupWindowState(Animating) ) - return; - - SetFocus(); - - // Space above and below - int screenHeight; - wxPoint scrPos; - int spaceAbove; - int spaceBelow; - int maxHeightPopup; - wxSize ctrlSz = GetSize(); - - screenHeight = wxSystemSettings::GetMetric( wxSYS_SCREEN_Y ); - scrPos = GetParent()->ClientToScreen(GetPosition()); - - spaceAbove = scrPos.y; - spaceBelow = screenHeight - spaceAbove - ctrlSz.y; - - maxHeightPopup = spaceBelow; - if ( spaceAbove > spaceBelow ) - maxHeightPopup = spaceAbove; - - // Width - int widthPopup = ctrlSz.x + m_extLeft + m_extRight; - - if ( widthPopup < m_widthMinPopup ) - widthPopup = m_widthMinPopup; - - wxWindow* winPopup = m_winPopup; - wxWindow* popup; - - // Need to disable tab traversal of parent - // - // NB: This is to fix a bug in wxMSW. In theory it could also be fixed - // by, for instance, adding check to window.cpp:wxWindowMSW::MSWProcessMessage - // that if transient popup is open, then tab traversal is to be ignored. - // However, I think this code would still be needed for cases where - // transient popup doesn't work yet (wxWinCE?). - wxWindow* parent = GetParent(); - int parentFlags = parent->GetWindowStyle(); - if ( parentFlags & wxTAB_TRAVERSAL ) - { - parent->SetWindowStyle( parentFlags & ~(wxTAB_TRAVERSAL) ); - m_iFlags |= wxCC_IFLAG_PARENT_TAB_TRAVERSAL; - } - - if ( !winPopup ) - { - CreatePopup(); - winPopup = m_winPopup; - popup = m_popup; - } - else - { - popup = m_popup; - } - - winPopup->Enable(); - - wxASSERT( !m_popup || m_popup == popup ); // Consistency check. - - wxSize adjustedSize = m_popupInterface->GetAdjustedSize(widthPopup, - m_heightPopup<=0?DEFAULT_POPUP_HEIGHT:m_heightPopup, - maxHeightPopup); - - popup->SetSize(adjustedSize); - popup->Move(0,0); - m_popupInterface->OnPopup(); - - // - // Reposition and resize popup window - // - - wxSize szp = popup->GetSize(); - - int popupX; - int popupY = scrPos.y + ctrlSz.y; - - // Default anchor is wxLEFT - int anchorSide = m_anchorSide; - if ( !anchorSide ) - anchorSide = wxLEFT; - - int rightX = scrPos.x + ctrlSz.x + m_extRight - szp.x; - int leftX = scrPos.x - m_extLeft; - - if ( wxTheApp->GetLayoutDirection() == wxLayout_RightToLeft ) - leftX -= ctrlSz.x; - - int screenWidth = wxSystemSettings::GetMetric( wxSYS_SCREEN_X ); - - // If there is not enough horizontal space, anchor on the other side. - // If there is no space even then, place the popup at x 0. - if ( anchorSide == wxRIGHT ) - { - if ( rightX < 0 ) - { - if ( (leftX+szp.x) < screenWidth ) - anchorSide = wxLEFT; - else - anchorSide = 0; - } - } - else - { - if ( (leftX+szp.x) >= screenWidth ) - { - if ( rightX >= 0 ) - anchorSide = wxRIGHT; - else - anchorSide = 0; - } - } - - // Select x coordinate according to the anchor side - if ( anchorSide == wxRIGHT ) - popupX = rightX; - else if ( anchorSide == wxLEFT ) - popupX = leftX; - else - popupX = 0; - - int showFlags = CanDeferShow; - - if ( spaceBelow < szp.y ) - { - popupY = scrPos.y - szp.y; - showFlags |= ShowAbove; - } - -#if INSTALL_TOPLEV_HANDLER - // Put top level window event handler into place - if ( m_popupWinType == POPUPWIN_WXPOPUPWINDOW ) - { - if ( !m_toplevEvtHandler ) - m_toplevEvtHandler = new wxComboFrameEventHandler(this); - - wxWindow* toplev = ::wxGetTopLevelParent( this ); - wxASSERT( toplev ); - ((wxComboFrameEventHandler*)m_toplevEvtHandler)->OnPopup(); - toplev->PushEventHandler( m_toplevEvtHandler ); - } -#endif - - // Set string selection (must be this way instead of SetStringSelection) - if ( m_text ) - { - if ( !(m_iFlags & wxCC_NO_TEXT_AUTO_SELECT) ) - m_text->SelectAll(); - - m_popupInterface->SetStringValue( m_text->GetValue() ); - } - else - { - // This is neede since focus/selection indication may change when popup is shown - Refresh(); - } - - // This must be after SetStringValue - m_popupWinState = Animating; - - wxRect popupWinRect( popupX, popupY, szp.x, szp.y ); - - m_popup = popup; - if ( (m_iFlags & wxCC_IFLAG_DISABLE_POPUP_ANIM) || - AnimateShow( popupWinRect, showFlags ) ) - { - DoShowPopup( popupWinRect, showFlags ); - } -} - -bool wxComboCtrlBase::AnimateShow( const wxRect& WXUNUSED(rect), int WXUNUSED(flags) ) -{ - return true; -} - -void wxComboCtrlBase::DoShowPopup( const wxRect& rect, int WXUNUSED(flags) ) -{ - wxWindow* winPopup = m_winPopup; - - if ( IsPopupWindowState(Animating) ) - { - // Make sure the popup window is shown in the right position. - // Should not matter even if animation already did this. - - // Some platforms (GTK) may like SetSize and Move to be separate - // (though the bug was probably fixed). - winPopup->SetSize( rect ); - - winPopup->Show(); - - m_popupWinState = Visible; - } - else if ( IsPopupWindowState(Hidden) ) - { - // Animation was aborted - - wxASSERT( !winPopup->IsShown() ); - - m_popupWinState = Hidden; - } -} - -void wxComboCtrlBase::OnPopupDismiss() -{ - // Just in case, avoid double dismiss - if ( IsPopupWindowState(Hidden) ) - return; - - // This must be set before focus - otherwise there will be recursive - // OnPopupDismisses. - m_popupWinState = Hidden; - - //SetFocus(); - m_winPopup->Disable(); - - // Inform popup control itself - m_popupInterface->OnDismiss(); - - if ( m_popupExtraHandler ) - ((wxComboPopupExtraEventHandler*)m_popupExtraHandler)->OnPopupDismiss(); - -#if INSTALL_TOPLEV_HANDLER - // Remove top level window event handler - if ( m_toplevEvtHandler ) - { - wxWindow* toplev = ::wxGetTopLevelParent( this ); - if ( toplev ) - toplev->RemoveEventHandler( m_toplevEvtHandler ); - } -#endif - - m_timeCanAcceptClick = ::wxGetLocalTimeMillis(); - - if ( m_popupWinType == POPUPWIN_WXPOPUPTRANSIENTWINDOW ) - m_timeCanAcceptClick += 150; - - // If cursor not on dropdown button, then clear its state - // (technically not required by all ports, but do it for all just in case) - if ( !m_btnArea.Contains(ScreenToClient(::wxGetMousePosition())) ) - m_btnState = 0; - - // Return parent's tab traversal flag. - // See ShowPopup for notes. - if ( m_iFlags & wxCC_IFLAG_PARENT_TAB_TRAVERSAL ) - { - wxWindow* parent = GetParent(); - parent->SetWindowStyle( parent->GetWindowStyle() | wxTAB_TRAVERSAL ); - m_iFlags &= ~(wxCC_IFLAG_PARENT_TAB_TRAVERSAL); - } - - // refresh control (necessary even if m_text) - Refresh(); - - SetFocus(); -} - -void wxComboCtrlBase::HidePopup() -{ - // Should be able to call this without popup interface - if ( IsPopupWindowState(Hidden) ) - return; - - // transfer value and show it in textctrl, if any - if ( !IsPopupWindowState(Animating) ) - SetValue( m_popupInterface->GetStringValue() ); - - m_winPopup->Hide(); - - OnPopupDismiss(); -} - -// ---------------------------------------------------------------------------- -// customization methods -// ---------------------------------------------------------------------------- - -void wxComboCtrlBase::SetButtonPosition( int width, int height, - int side, int spacingX ) -{ - m_btnWid = width; - m_btnHei = height; - m_btnSide = side; - m_btnSpacingX = spacingX; - - RecalcAndRefresh(); -} - -wxSize wxComboCtrlBase::GetButtonSize() -{ - if ( m_btnSize.x > 0 ) - return m_btnSize; - - wxSize retSize(m_btnWid,m_btnHei); - - // Need to call CalculateAreas now if button size is - // is not explicitly specified. - if ( retSize.x <= 0 || retSize.y <= 0) - { - OnResize(); - - retSize = m_btnSize; - } - - return retSize; -} - -void wxComboCtrlBase::SetButtonBitmaps( const wxBitmap& bmpNormal, - bool blankButtonBg, - const wxBitmap& bmpPressed, - const wxBitmap& bmpHover, - const wxBitmap& bmpDisabled ) -{ - m_bmpNormal = bmpNormal; - m_blankButtonBg = blankButtonBg; - - if ( bmpPressed.Ok() ) - m_bmpPressed = bmpPressed; - else - m_bmpPressed = bmpNormal; - - if ( bmpHover.Ok() ) - m_bmpHover = bmpHover; - else - m_bmpHover = bmpNormal; - - if ( bmpDisabled.Ok() ) - m_bmpDisabled = bmpDisabled; - else - m_bmpDisabled = bmpNormal; - - RecalcAndRefresh(); -} - -void wxComboCtrlBase::SetCustomPaintWidth( int width ) -{ - if ( m_text ) - { - // move textctrl accordingly - wxRect r = m_text->GetRect(); - int inc = width - m_widthCustomPaint; - r.x += inc; - r.width -= inc; - m_text->SetSize( r ); - } - - m_widthCustomPaint = width; - - RecalcAndRefresh(); -} - -void wxComboCtrlBase::SetTextIndent( int indent ) -{ - if ( indent < 0 ) - { - m_absIndent = GetNativeTextIndent(); - m_iFlags &= ~(wxCC_IFLAG_INDENT_SET); - } - else - { - m_absIndent = indent; - m_iFlags |= wxCC_IFLAG_INDENT_SET; - } - - RecalcAndRefresh(); -} - -wxCoord wxComboCtrlBase::GetNativeTextIndent() const -{ - return DEFAULT_TEXT_INDENT; -} - -// ---------------------------------------------------------------------------- -// methods forwarded to wxTextCtrl -// ---------------------------------------------------------------------------- - -wxString wxComboCtrlBase::GetValue() const -{ - if ( m_text ) - return m_text->GetValue(); - return m_valueString; -} - -void wxComboCtrlBase::SetValueWithEvent(const wxString& value, bool withEvent) -{ - if ( m_text ) - { - if ( !withEvent ) - m_ignoreEvtText++; - - m_text->SetValue(value); - if ( !(m_iFlags & wxCC_NO_TEXT_AUTO_SELECT) ) - m_text->SelectAll(); - } - - // Since wxComboPopup may want to paint the combo as well, we need - // to set the string value here (as well as sometimes in ShowPopup). - if ( m_valueString != value ) - { - m_valueString = value; - - EnsurePopupControl(); - - if (m_popupInterface) - m_popupInterface->SetStringValue(value); - } - - Refresh(); -} - -void wxComboCtrlBase::SetValue(const wxString& value) -{ - SetValueWithEvent(value, false); -} - -// In this SetValue variant wxComboPopup::SetStringValue is not called -void wxComboCtrlBase::SetText(const wxString& value) -{ - // Unlike in SetValue(), this must be called here or - // the behaviour will no be consistent in readonlys. - EnsurePopupControl(); - - m_valueString = value; - - if ( m_text ) - { - m_ignoreEvtText++; - m_text->SetValue( value ); - } - - Refresh(); -} - -void wxComboCtrlBase::Copy() -{ - if ( m_text ) - m_text->Copy(); -} - -void wxComboCtrlBase::Cut() -{ - if ( m_text ) - m_text->Cut(); -} - -void wxComboCtrlBase::Paste() -{ - if ( m_text ) - m_text->Paste(); -} - -void wxComboCtrlBase::SetInsertionPoint(long pos) -{ - if ( m_text ) - m_text->SetInsertionPoint(pos); -} - -void wxComboCtrlBase::SetInsertionPointEnd() -{ - if ( m_text ) - m_text->SetInsertionPointEnd(); -} - -long wxComboCtrlBase::GetInsertionPoint() const -{ - if ( m_text ) - return m_text->GetInsertionPoint(); - - return 0; -} - -long wxComboCtrlBase::GetLastPosition() const -{ - if ( m_text ) - return m_text->GetLastPosition(); - - return 0; -} - -void wxComboCtrlBase::Replace(long from, long to, const wxString& value) -{ - if ( m_text ) - m_text->Replace(from, to, value); -} - -void wxComboCtrlBase::Remove(long from, long to) -{ - if ( m_text ) - m_text->Remove(from, to); -} - -void wxComboCtrlBase::SetSelection(long from, long to) -{ - if ( m_text ) - m_text->SetSelection(from, to); -} - -void wxComboCtrlBase::Undo() -{ - if ( m_text ) - m_text->Undo(); -} - -#endif // wxUSE_COMBOCTRL +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/combocmn.cpp +// Purpose: wxComboCtrlBase +// Author: Jaakko Salli +// Modified by: +// Created: Apr-30-2006 +// RCS-ID: $Id: combocmn.cpp 45512 2007-04-16 20:51:27Z RD $ +// Copyright: (c) 2005 Jaakko Salli +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_COMBOCTRL + +#include "wx/combobox.h" + +#ifndef WX_PRECOMP + #include "wx/app.h" + #include "wx/log.h" + #include "wx/dcclient.h" + #include "wx/settings.h" + #include "wx/dialog.h" + #include "wx/timer.h" +#endif + +#include "wx/tooltip.h" + +#include "wx/combo.h" + + + +// constants +// ---------------------------------------------------------------------------- + +#define DEFAULT_DROPBUTTON_WIDTH 19 + +#define BMP_BUTTON_MARGIN 4 + +#define DEFAULT_POPUP_HEIGHT 400 + +#define DEFAULT_TEXT_INDENT 3 + +#define COMBO_MARGIN 2 // spacing right of wxTextCtrl + + +#if defined(__WXMSW__) + +#define USE_TRANSIENT_POPUP 1 // Use wxPopupWindowTransient (preferred, if it works properly on platform) +#define TRANSIENT_POPUPWIN_IS_PERFECT 0 // wxPopupTransientWindow works, its child can have focus, and common + // native controls work on it like normal. +#define POPUPWIN_IS_PERFECT 0 // Same, but for non-transient popup window. +#define TEXTCTRL_TEXT_CENTERED 0 // 1 if text in textctrl is vertically centered +#define FOCUS_RING 0 // No focus ring on wxMSW + +//#undef wxUSE_POPUPWIN +//#define wxUSE_POPUPWIN 0 + +#elif defined(__WXGTK__) + +// NB: It is not recommended to use wxDialog as popup on wxGTK, because of +// this bug: If wxDialog is hidden, its position becomes corrupt +// between hide and next show, but without internal coordinates being +// reflected (or something like that - atleast commenting out ->Hide() +// seemed to eliminate the position change). + +#define USE_TRANSIENT_POPUP 1 // Use wxPopupWindowTransient (preferred, if it works properly on platform) +#define TRANSIENT_POPUPWIN_IS_PERFECT 0 // wxPopupTransientWindow works, its child can have focus, and common + // native controls work on it like normal. +#define POPUPWIN_IS_PERFECT 1 // Same, but for non-transient popup window. +#define TEXTCTRL_TEXT_CENTERED 1 // 1 if text in textctrl is vertically centered +#define FOCUS_RING 0 // No focus ring on wxGTK + +#elif defined(__WXMAC__) + +#define USE_TRANSIENT_POPUP 0 // Use wxPopupWindowTransient (preferred, if it works properly on platform) +#define TRANSIENT_POPUPWIN_IS_PERFECT 0 // wxPopupTransientWindow works, its child can have focus, and common + // native controls work on it like normal. +#define POPUPWIN_IS_PERFECT 0 // Same, but for non-transient popup window. +#define TEXTCTRL_TEXT_CENTERED 1 // 1 if text in textctrl is vertically centered +#define FOCUS_RING 3 // Reserve room for the textctrl's focus ring to display + +#undef DEFAULT_DROPBUTTON_WIDTH +#define DEFAULT_DROPBUTTON_WIDTH 22 +#undef COMBO_MARGIN +#define COMBO_MARGIN FOCUS_RING + +#else + +#define USE_TRANSIENT_POPUP 0 // Use wxPopupWindowTransient (preferred, if it works properly on platform) +#define TRANSIENT_POPUPWIN_IS_PERFECT 0 // wxPopupTransientWindow works, its child can have focus, and common + // native controls work on it like normal. +#define POPUPWIN_IS_PERFECT 0 // Same, but for non-transient popup window. +#define TEXTCTRL_TEXT_CENTERED 1 // 1 if text in textctrl is vertically centered +#define FOCUS_RING 0 + +#endif + + +// Popupwin is really only supported on wxMSW (not WINCE) and wxGTK, regardless +// what the wxUSE_POPUPWIN says. +// FIXME: Why isn't wxUSE_POPUPWIN reliable any longer? (it was in wxW2.6.2) +#if (!defined(__WXMSW__) && !defined(__WXGTK__)) || defined(__WXWINCE__) +#undef wxUSE_POPUPWIN +#define wxUSE_POPUPWIN 0 +#endif + + +#if wxUSE_POPUPWIN + #include "wx/popupwin.h" +#else + #undef USE_TRANSIENT_POPUP + #define USE_TRANSIENT_POPUP 0 +#endif + + +// Define different types of popup windows +enum +{ + POPUPWIN_NONE = 0, + POPUPWIN_WXPOPUPTRANSIENTWINDOW = 1, + POPUPWIN_WXPOPUPWINDOW = 2, + POPUPWIN_WXDIALOG = 3 +}; + + +#if USE_TRANSIENT_POPUP + // wxPopupTransientWindow is implemented + + #define wxComboPopupWindowBase wxPopupTransientWindow + #define PRIMARY_POPUP_TYPE POPUPWIN_WXPOPUPTRANSIENTWINDOW + #define USES_WXPOPUPTRANSIENTWINDOW 1 + + #if TRANSIENT_POPUPWIN_IS_PERFECT + // + #elif POPUPWIN_IS_PERFECT + #define wxComboPopupWindowBase2 wxPopupWindow + #define SECONDARY_POPUP_TYPE POPUPWIN_WXPOPUPWINDOW + #define USES_WXPOPUPWINDOW 1 + #else + #define wxComboPopupWindowBase2 wxDialog + #define SECONDARY_POPUP_TYPE POPUPWIN_WXDIALOG + #define USES_WXDIALOG 1 + #endif + +#elif wxUSE_POPUPWIN + // wxPopupWindow (but not wxPopupTransientWindow) is properly implemented + + #define wxComboPopupWindowBase wxPopupWindow + #define PRIMARY_POPUP_TYPE POPUPWIN_WXPOPUPWINDOW + #define USES_WXPOPUPWINDOW 1 + + #if !POPUPWIN_IS_PERFECT + #define wxComboPopupWindowBase2 wxDialog + #define SECONDARY_POPUP_TYPE POPUPWIN_WXDIALOG + #define USES_WXDIALOG 1 + #endif + +#else + // wxPopupWindow is not implemented + + #define wxComboPopupWindowBase wxDialog + #define PRIMARY_POPUP_TYPE POPUPWIN_WXDIALOG + #define USES_WXDIALOG 1 + +#endif + + +#ifndef USES_WXPOPUPTRANSIENTWINDOW + #define USES_WXPOPUPTRANSIENTWINDOW 0 +#endif + +#ifndef USES_WXPOPUPWINDOW + #define USES_WXPOPUPWINDOW 0 +#endif + +#ifndef USES_WXDIALOG + #define USES_WXDIALOG 0 +#endif + + +#if USES_WXPOPUPWINDOW + #define INSTALL_TOPLEV_HANDLER 1 +#else + #define INSTALL_TOPLEV_HANDLER 0 +#endif + + +// +// ** TODO ** +// * wxComboPopupWindow for external use (ie. replace old wxUniv wxPopupComboWindow) +// + + +// ---------------------------------------------------------------------------- +// wxComboFrameEventHandler takes care of hiding the popup when events happen +// in its top level parent. +// ---------------------------------------------------------------------------- + +#if INSTALL_TOPLEV_HANDLER + +// +// This will no longer be necessary after wxTransientPopupWindow +// works well on all platforms. +// + +class wxComboFrameEventHandler : public wxEvtHandler +{ +public: + wxComboFrameEventHandler( wxComboCtrlBase* pCb ); + virtual ~wxComboFrameEventHandler(); + + void OnPopup(); + + void OnIdle( wxIdleEvent& event ); + void OnMouseEvent( wxMouseEvent& event ); + void OnActivate( wxActivateEvent& event ); + void OnResize( wxSizeEvent& event ); + void OnMove( wxMoveEvent& event ); + void OnMenuEvent( wxMenuEvent& event ); + void OnClose( wxCloseEvent& event ); + +protected: + wxWindow* m_focusStart; + wxComboCtrlBase* m_combo; + +private: + DECLARE_EVENT_TABLE() +}; + +BEGIN_EVENT_TABLE(wxComboFrameEventHandler, wxEvtHandler) + EVT_IDLE(wxComboFrameEventHandler::OnIdle) + EVT_LEFT_DOWN(wxComboFrameEventHandler::OnMouseEvent) + EVT_RIGHT_DOWN(wxComboFrameEventHandler::OnMouseEvent) + EVT_SIZE(wxComboFrameEventHandler::OnResize) + EVT_MOVE(wxComboFrameEventHandler::OnMove) + EVT_MENU_HIGHLIGHT(wxID_ANY,wxComboFrameEventHandler::OnMenuEvent) + EVT_MENU_OPEN(wxComboFrameEventHandler::OnMenuEvent) + EVT_ACTIVATE(wxComboFrameEventHandler::OnActivate) + EVT_CLOSE(wxComboFrameEventHandler::OnClose) +END_EVENT_TABLE() + +wxComboFrameEventHandler::wxComboFrameEventHandler( wxComboCtrlBase* combo ) + : wxEvtHandler() +{ + m_combo = combo; +} + +wxComboFrameEventHandler::~wxComboFrameEventHandler() +{ +} + +void wxComboFrameEventHandler::OnPopup() +{ + m_focusStart = ::wxWindow::FindFocus(); +} + +void wxComboFrameEventHandler::OnIdle( wxIdleEvent& event ) +{ + wxWindow* winFocused = ::wxWindow::FindFocus(); + + wxWindow* popup = m_combo->GetPopupControl()->GetControl(); + wxWindow* winpopup = m_combo->GetPopupWindow(); + + if ( + winFocused != m_focusStart && + winFocused != popup && + winFocused->GetParent() != popup && + winFocused != winpopup && + winFocused->GetParent() != winpopup && + winFocused != m_combo && + winFocused != m_combo->GetButton() // GTK (atleast) requires this + ) + { + m_combo->HidePopup(); + } + + event.Skip(); +} + +void wxComboFrameEventHandler::OnMenuEvent( wxMenuEvent& event ) +{ + m_combo->HidePopup(); + event.Skip(); +} + +void wxComboFrameEventHandler::OnMouseEvent( wxMouseEvent& event ) +{ + m_combo->HidePopup(); + event.Skip(); +} + +void wxComboFrameEventHandler::OnClose( wxCloseEvent& event ) +{ + m_combo->HidePopup(); + event.Skip(); +} + +void wxComboFrameEventHandler::OnActivate( wxActivateEvent& event ) +{ + m_combo->HidePopup(); + event.Skip(); +} + +void wxComboFrameEventHandler::OnResize( wxSizeEvent& event ) +{ + m_combo->HidePopup(); + event.Skip(); +} + +void wxComboFrameEventHandler::OnMove( wxMoveEvent& event ) +{ + m_combo->HidePopup(); + event.Skip(); +} + +#endif // INSTALL_TOPLEV_HANDLER + +// ---------------------------------------------------------------------------- +// wxComboPopupWindow is, in essence, wxPopupWindow customized for +// wxComboCtrl. +// ---------------------------------------------------------------------------- + +class wxComboPopupWindow : public wxComboPopupWindowBase +{ +public: + + wxComboPopupWindow( wxComboCtrlBase *parent, + int style ) + #if USES_WXPOPUPWINDOW || USES_WXPOPUPTRANSIENTWINDOW + : wxComboPopupWindowBase(parent,style) + #else + : wxComboPopupWindowBase(parent, + wxID_ANY, + wxEmptyString, + wxPoint(-21,-21), + wxSize(20,20), + style) + #endif + { + m_inShow = 0; + } + +#if USES_WXPOPUPTRANSIENTWINDOW + virtual bool Show( bool show ); + virtual bool ProcessLeftDown(wxMouseEvent& event); +protected: + virtual void OnDismiss(); +#endif + +private: + wxByte m_inShow; +}; + + +#if USES_WXPOPUPTRANSIENTWINDOW +bool wxComboPopupWindow::Show( bool show ) +{ + // Guard against recursion + if ( m_inShow ) + return wxComboPopupWindowBase::Show(show); + + m_inShow++; + + wxASSERT( IsKindOf(CLASSINFO(wxPopupTransientWindow)) ); + + wxPopupTransientWindow* ptw = (wxPopupTransientWindow*) this; + wxComboCtrlBase* combo = (wxComboCtrlBase*) GetParent(); + + if ( show != ptw->IsShown() ) + { + if ( show ) + ptw->Popup(combo->GetPopupControl()->GetControl()); + else + ptw->Dismiss(); + } + + m_inShow--; + + return true; +} + +bool wxComboPopupWindow::ProcessLeftDown(wxMouseEvent& event) +{ + return wxPopupTransientWindow::ProcessLeftDown(event); +} + +// First thing that happens when a transient popup closes is that this method gets called. +void wxComboPopupWindow::OnDismiss() +{ + wxComboCtrlBase* combo = (wxComboCtrlBase*) GetParent(); + wxASSERT_MSG( combo->IsKindOf(CLASSINFO(wxComboCtrlBase)), + wxT("parent might not be wxComboCtrl, but check IMPLEMENT_DYNAMIC_CLASS(2) macro for correctness") ); + + combo->OnPopupDismiss(); +} +#endif // USES_WXPOPUPTRANSIENTWINDOW + + +// ---------------------------------------------------------------------------- +// wxComboPopupWindowEvtHandler does bulk of the custom event handling +// of a popup window. It is separate so we can have different types +// of popup windows. +// ---------------------------------------------------------------------------- + +class wxComboPopupWindowEvtHandler : public wxEvtHandler +{ +public: + + wxComboPopupWindowEvtHandler( wxComboCtrlBase *parent ) + { + m_combo = parent; + } + + void OnSizeEvent( wxSizeEvent& event ); + void OnKeyEvent(wxKeyEvent& event); +#if USES_WXDIALOG + void OnActivate( wxActivateEvent& event ); +#endif + +private: + wxComboCtrlBase* m_combo; + + DECLARE_EVENT_TABLE() +}; + + +BEGIN_EVENT_TABLE(wxComboPopupWindowEvtHandler, wxEvtHandler) + EVT_KEY_DOWN(wxComboPopupWindowEvtHandler::OnKeyEvent) + EVT_KEY_UP(wxComboPopupWindowEvtHandler::OnKeyEvent) +#if USES_WXDIALOG + EVT_ACTIVATE(wxComboPopupWindowEvtHandler::OnActivate) +#endif + EVT_SIZE(wxComboPopupWindowEvtHandler::OnSizeEvent) +END_EVENT_TABLE() + + +void wxComboPopupWindowEvtHandler::OnSizeEvent( wxSizeEvent& WXUNUSED(event) ) +{ + // Block the event so that the popup control does not get auto-resized. +} + +void wxComboPopupWindowEvtHandler::OnKeyEvent( wxKeyEvent& event ) +{ + // Relay keyboard event to the main child controls + wxWindowList children = m_combo->GetPopupWindow()->GetChildren(); + wxWindowList::iterator node = children.begin(); + wxWindow* child = (wxWindow*)*node; + child->AddPendingEvent(event); +} + +#if USES_WXDIALOG +void wxComboPopupWindowEvtHandler::OnActivate( wxActivateEvent& event ) +{ + if ( !event.GetActive() ) + { + // Tell combo control that we are dismissed. + m_combo->HidePopup(); + + event.Skip(); + } +} +#endif + + +// ---------------------------------------------------------------------------- +// wxComboPopup +// +// ---------------------------------------------------------------------------- + +wxComboPopup::~wxComboPopup() +{ +} + +void wxComboPopup::OnPopup() +{ +} + +void wxComboPopup::OnDismiss() +{ +} + +wxSize wxComboPopup::GetAdjustedSize( int minWidth, + int prefHeight, + int WXUNUSED(maxHeight) ) +{ + return wxSize(minWidth,prefHeight); +} + +void wxComboPopup::DefaultPaintComboControl( wxComboCtrlBase* combo, + wxDC& dc, const wxRect& rect ) +{ + if ( combo->GetWindowStyle() & wxCB_READONLY ) // ie. no textctrl + { + combo->PrepareBackground(dc,rect,0); + + dc.DrawText( combo->GetValue(), + rect.x + combo->GetTextIndent(), + (rect.height-dc.GetCharHeight())/2 + rect.y ); + } +} + +void wxComboPopup::PaintComboControl( wxDC& dc, const wxRect& rect ) +{ + DefaultPaintComboControl(m_combo,dc,rect); +} + +void wxComboPopup::OnComboKeyEvent( wxKeyEvent& event ) +{ + event.Skip(); +} + +void wxComboPopup::OnComboDoubleClick() +{ +} + +void wxComboPopup::SetStringValue( const wxString& WXUNUSED(value) ) +{ +} + +bool wxComboPopup::LazyCreate() +{ + return false; +} + +void wxComboPopup::Dismiss() +{ + m_combo->HidePopup(); +} + +// ---------------------------------------------------------------------------- +// input handling +// ---------------------------------------------------------------------------- + +// +// This is pushed to the event handler queue of the child textctrl. +// +class wxComboBoxExtraInputHandler : public wxEvtHandler +{ +public: + + wxComboBoxExtraInputHandler( wxComboCtrlBase* combo ) + : wxEvtHandler() + { + m_combo = combo; + } + virtual ~wxComboBoxExtraInputHandler() { } + void OnKey(wxKeyEvent& event); + void OnFocus(wxFocusEvent& event); + +protected: + wxComboCtrlBase* m_combo; + +private: + DECLARE_EVENT_TABLE() +}; + + +BEGIN_EVENT_TABLE(wxComboBoxExtraInputHandler, wxEvtHandler) + EVT_KEY_DOWN(wxComboBoxExtraInputHandler::OnKey) + EVT_SET_FOCUS(wxComboBoxExtraInputHandler::OnFocus) +END_EVENT_TABLE() + + +void wxComboBoxExtraInputHandler::OnKey(wxKeyEvent& event) +{ + // Let the wxComboCtrl event handler have a go first. + wxComboCtrlBase* combo = m_combo; + wxObject* prevObj = event.GetEventObject(); + + event.SetId(combo->GetId()); + event.SetEventObject(combo); + combo->GetEventHandler()->ProcessEvent(event); + + event.SetId(((wxWindow*)prevObj)->GetId()); + event.SetEventObject(prevObj); +} + +void wxComboBoxExtraInputHandler::OnFocus(wxFocusEvent& event) +{ + // FIXME: This code does run when control is clicked, + // yet on Windows it doesn't select all the text. + if ( !(m_combo->GetInternalFlags() & wxCC_NO_TEXT_AUTO_SELECT) ) + { + if ( m_combo->GetTextCtrl() ) + m_combo->GetTextCtrl()->SelectAll(); + else + m_combo->SetSelection(-1,-1); + } + + // Send focus indication to parent. + // NB: This is needed for cases where the textctrl gets focus + // instead of its parent. While this may trigger multiple + // wxEVT_SET_FOCUSes (since m_text->SetFocus is called + // from combo's focus event handler), they should be quite + // harmless. + wxFocusEvent evt2(wxEVT_SET_FOCUS,m_combo->GetId()); + evt2.SetEventObject(m_combo); + m_combo->GetEventHandler()->ProcessEvent(evt2); + + event.Skip(); +} + + +// +// This is pushed to the event handler queue of the control in popup. +// + +class wxComboPopupExtraEventHandler : public wxEvtHandler +{ +public: + + wxComboPopupExtraEventHandler( wxComboCtrlBase* combo ) + : wxEvtHandler() + { + m_combo = combo; + m_beenInside = false; + } + virtual ~wxComboPopupExtraEventHandler() { } + + void OnMouseEvent( wxMouseEvent& event ); + + // Called from wxComboCtrlBase::OnPopupDismiss + void OnPopupDismiss() + { + m_beenInside = false; + } + +protected: + wxComboCtrlBase* m_combo; + + bool m_beenInside; + +private: + DECLARE_EVENT_TABLE() +}; + + +BEGIN_EVENT_TABLE(wxComboPopupExtraEventHandler, wxEvtHandler) + EVT_MOUSE_EVENTS(wxComboPopupExtraEventHandler::OnMouseEvent) +END_EVENT_TABLE() + + +void wxComboPopupExtraEventHandler::OnMouseEvent( wxMouseEvent& event ) +{ + wxPoint pt = event.GetPosition(); + wxSize sz = m_combo->GetPopupControl()->GetControl()->GetClientSize(); + int evtType = event.GetEventType(); + bool isInside = pt.x >= 0 && pt.y >= 0 && pt.x < sz.x && pt.y < sz.y; + + if ( evtType == wxEVT_MOTION || + evtType == wxEVT_LEFT_DOWN || + evtType == wxEVT_RIGHT_DOWN ) + { + // Block motion and click events outside the popup + if ( !isInside || !m_combo->IsPopupShown() ) + { + event.Skip(false); + return; + } + } + else if ( evtType == wxEVT_LEFT_UP ) + { + if ( !m_combo->IsPopupShown() ) + { + event.Skip(false); + return; + } + + if ( !m_beenInside ) + { + if ( isInside ) + { + m_beenInside = true; + } + else + { + // + // Some mouse events to popup that happen outside it, before cursor + // has been inside the popu, need to be ignored by it but relayed to + // the dropbutton. + // + wxWindow* btn = m_combo->GetButton(); + if ( btn ) + btn->GetEventHandler()->AddPendingEvent(event); + else + m_combo->GetEventHandler()->AddPendingEvent(event); + + return; + } + + event.Skip(); + } + } + + event.Skip(); +} + +// ---------------------------------------------------------------------------- +// wxComboCtrlBase +// ---------------------------------------------------------------------------- + + +BEGIN_EVENT_TABLE(wxComboCtrlBase, wxControl) + EVT_TEXT(wxID_ANY,wxComboCtrlBase::OnTextCtrlEvent) + EVT_SIZE(wxComboCtrlBase::OnSizeEvent) + EVT_SET_FOCUS(wxComboCtrlBase::OnFocusEvent) + EVT_KILL_FOCUS(wxComboCtrlBase::OnFocusEvent) + EVT_IDLE(wxComboCtrlBase::OnIdleEvent) + //EVT_BUTTON(wxID_ANY,wxComboCtrlBase::OnButtonClickEvent) + EVT_KEY_DOWN(wxComboCtrlBase::OnKeyEvent) + EVT_TEXT_ENTER(wxID_ANY,wxComboCtrlBase::OnTextCtrlEvent) + EVT_SYS_COLOUR_CHANGED(wxComboCtrlBase::OnSysColourChanged) +END_EVENT_TABLE() + + +IMPLEMENT_ABSTRACT_CLASS(wxComboCtrlBase, wxControl) + +void wxComboCtrlBase::Init() +{ + m_winPopup = (wxWindow *)NULL; + m_popup = (wxWindow *)NULL; + m_popupWinState = Hidden; + m_btn = (wxWindow*) NULL; + m_text = (wxTextCtrl*) NULL; + m_popupInterface = (wxComboPopup*) NULL; + + m_popupExtraHandler = (wxEvtHandler*) NULL; + m_textEvtHandler = (wxEvtHandler*) NULL; + +#if INSTALL_TOPLEV_HANDLER + m_toplevEvtHandler = (wxEvtHandler*) NULL; +#endif + + m_mainCtrlWnd = this; + + m_heightPopup = -1; + m_widthMinPopup = -1; + m_anchorSide = 0; + m_widthCustomPaint = 0; + m_widthCustomBorder = 0; + + m_btnState = 0; + m_btnWidDefault = 0; + m_blankButtonBg = false; + m_ignoreEvtText = 0; + m_popupWinType = POPUPWIN_NONE; + m_btnWid = m_btnHei = -1; + m_btnSide = wxRIGHT; + m_btnSpacingX = 0; + + m_extLeft = 0; + m_extRight = 0; + m_absIndent = -1; + m_iFlags = 0; + m_timeCanAcceptClick = 0; + + m_resetFocus = false; +} + +bool wxComboCtrlBase::Create(wxWindow *parent, + wxWindowID id, + const wxString& value, + const wxPoint& pos, + const wxSize& size, + long style, + const wxValidator& validator, + const wxString& name) +{ + if ( !wxControl::Create(parent, + id, + pos, + size, + style | wxWANTS_CHARS, + validator, + name) ) + return false; + + m_valueString = value; + + // Get colours + OnThemeChange(); + m_absIndent = GetNativeTextIndent(); + + m_iFlags |= wxCC_IFLAG_CREATED; + + // If x and y indicate valid size, wxSizeEvent won't be + // emitted automatically, so we need to add artifical one. + if ( size.x > 0 && size.y > 0 ) + { + wxSizeEvent evt(size,GetId()); + GetEventHandler()->AddPendingEvent(evt); + } + + return true; +} + +void wxComboCtrlBase::InstallInputHandlers() +{ + if ( m_text ) + { + m_textEvtHandler = new wxComboBoxExtraInputHandler(this); + m_text->PushEventHandler(m_textEvtHandler); + } +} + +void +wxComboCtrlBase::CreateTextCtrl(int style, const wxValidator& validator) +{ + if ( !(m_windowStyle & wxCB_READONLY) ) + { + if ( m_text ) + m_text->Destroy(); + + // wxTE_PROCESS_TAB is needed because on Windows, wxTAB_TRAVERSAL is + // not used by the wxPropertyGrid and therefore the tab is processed by + // looking at ancestors to see if they have wxTAB_TRAVERSAL. The + // navigation event is then sent to the wrong window. + style |= wxTE_PROCESS_TAB; + + if ( HasFlag(wxTE_PROCESS_ENTER) ) + style |= wxTE_PROCESS_ENTER; + + // Ignore EVT_TEXT generated by the constructor (but only + // if the event redirector already exists) + // NB: This must be " = 1" instead of "++"; + if ( m_textEvtHandler ) + m_ignoreEvtText = 1; + else + m_ignoreEvtText = 0; + + m_text = new wxTextCtrl(this, wxID_ANY, m_valueString, + wxDefaultPosition, wxSize(10,-1), + style, validator); + } +} + +void wxComboCtrlBase::OnThemeChange() +{ + // Leave the default bg on the Mac so the area used by the focus ring will + // be the correct colour and themed brush. Instead we'll use + // wxSYS_COLOUR_WINDOW in the EVT_PAINT handler as needed. +#ifndef __WXMAC__ + SetOwnBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW)); +#endif +} + +wxComboCtrlBase::~wxComboCtrlBase() +{ + if ( HasCapture() ) + ReleaseMouse(); + +#if INSTALL_TOPLEV_HANDLER + delete ((wxComboFrameEventHandler*)m_toplevEvtHandler); + m_toplevEvtHandler = (wxEvtHandler*) NULL; +#endif + + DestroyPopup(); + + if ( m_text ) + m_text->RemoveEventHandler(m_textEvtHandler); + + delete m_textEvtHandler; +} + + +// ---------------------------------------------------------------------------- +// geometry stuff +// ---------------------------------------------------------------------------- + +// Recalculates button and textctrl areas +void wxComboCtrlBase::CalculateAreas( int btnWidth ) +{ + wxSize sz = GetClientSize(); + int customBorder = m_widthCustomBorder; + int btnBorder; // border for button only + + // check if button should really be outside the border: we'll do it it if + // its platform default or bitmap+pushbutton background is used, but not if + // there is vertical size adjustment or horizontal spacing. + if ( ( (m_iFlags & wxCC_BUTTON_OUTSIDE_BORDER) || + (m_bmpNormal.Ok() && m_blankButtonBg) ) && + m_btnSpacingX == 0 && + m_btnHei <= 0 ) + { + m_iFlags |= wxCC_IFLAG_BUTTON_OUTSIDE; + btnBorder = 0; + } + else + { + m_iFlags &= ~(wxCC_IFLAG_BUTTON_OUTSIDE); + btnBorder = customBorder; + } + + // Defaul indentation + if ( m_absIndent < 0 ) + m_absIndent = GetNativeTextIndent(); + + int butWidth = btnWidth; + + if ( butWidth <= 0 ) + butWidth = m_btnWidDefault; + else + m_btnWidDefault = butWidth; + + if ( butWidth <= 0 ) + return; + + int butHeight = sz.y - btnBorder*2; + + // Adjust button width + if ( m_btnWid > 0 ) + butWidth = m_btnWid; + else + { + // Adjust button width to match aspect ratio + // (but only if control is smaller than best size). + int bestHeight = GetBestSize().y; + int height = GetSize().y; + + if ( height < bestHeight ) + { + // Make very small buttons square, as it makes + // them accommodate arrow image better and still + // looks decent. + if ( height > 18 ) + butWidth = (height*butWidth)/bestHeight; + else + butWidth = butHeight; + } + } + + // Adjust button height + if ( m_btnHei > 0 ) + butHeight = m_btnHei; + + // Use size of normal bitmap if... + // It is larger + // OR + // button width is set to default and blank button bg is not drawn + if ( m_bmpNormal.Ok() ) + { + int bmpReqWidth = m_bmpNormal.GetWidth(); + int bmpReqHeight = m_bmpNormal.GetHeight(); + + // If drawing blank button background, we need to add some margin. + if ( m_blankButtonBg ) + { + bmpReqWidth += BMP_BUTTON_MARGIN*2; + bmpReqHeight += BMP_BUTTON_MARGIN*2; + } + + if ( butWidth < bmpReqWidth || ( m_btnWid == 0 && !m_blankButtonBg ) ) + butWidth = bmpReqWidth; + if ( butHeight < bmpReqHeight || ( m_btnHei == 0 && !m_blankButtonBg ) ) + butHeight = bmpReqHeight; + + // Need to fix height? + if ( (sz.y-(customBorder*2)) < butHeight && btnWidth == 0 ) + { + int newY = butHeight+(customBorder*2); + SetClientSize(wxDefaultCoord,newY); + sz.y = newY; + } + } + + int butAreaWid = butWidth + (m_btnSpacingX*2); + + m_btnSize.x = butWidth; + m_btnSize.y = butHeight; + + m_btnArea.x = ( m_btnSide==wxRIGHT ? sz.x - butAreaWid - btnBorder : btnBorder ); + m_btnArea.y = btnBorder + FOCUS_RING; + m_btnArea.width = butAreaWid; + m_btnArea.height = sz.y - ((btnBorder+FOCUS_RING)*2); + + m_tcArea.x = ( m_btnSide==wxRIGHT ? 0 : butAreaWid ) + customBorder + FOCUS_RING; + m_tcArea.y = customBorder + FOCUS_RING; + m_tcArea.width = sz.x - butAreaWid - (customBorder*2) - (FOCUS_RING*2); + m_tcArea.height = sz.y - ((customBorder+FOCUS_RING)*2); + +/* + if ( m_text ) + { + ::wxMessageBox(wxString::Format(wxT("ButtonArea (%i,%i,%i,%i)\n"),m_btnArea.x,m_btnArea.y,m_btnArea.width,m_btnArea.height) + + wxString::Format(wxT("TextCtrlArea (%i,%i,%i,%i)"),m_tcArea.x,m_tcArea.y,m_tcArea.width,m_tcArea.height)); + } +*/ +} + +void wxComboCtrlBase::PositionTextCtrl( int textCtrlXAdjust, int textCtrlYAdjust ) +{ + if ( !m_text ) + return; + +#if !TEXTCTRL_TEXT_CENTERED + + wxSize sz = GetClientSize(); + + int customBorder = m_widthCustomBorder; + if ( (m_text->GetWindowStyleFlag() & wxBORDER_MASK) == wxNO_BORDER ) + { + // Centre textctrl + int tcSizeY = m_text->GetBestSize().y; + int diff = sz.y - tcSizeY; + int y = textCtrlYAdjust + (diff/2); + + if ( y < customBorder ) + y = customBorder; + + m_text->SetSize( m_tcArea.x + m_widthCustomPaint + m_absIndent + textCtrlXAdjust, + y, + m_tcArea.width - COMBO_MARGIN - + (textCtrlXAdjust + m_widthCustomPaint + m_absIndent), + -1 ); + + // Make sure textctrl doesn't exceed the bottom custom border + wxSize tsz = m_text->GetSize(); + diff = (y + tsz.y) - (sz.y - customBorder); + if ( diff >= 0 ) + { + tsz.y = tsz.y - diff - 1; + m_text->SetSize(tsz); + } + } + else +#else // TEXTCTRL_TEXT_CENTERED + wxUnusedVar(textCtrlXAdjust); + wxUnusedVar(textCtrlYAdjust); +#endif // !TEXTCTRL_TEXT_CENTERED/TEXTCTRL_TEXT_CENTERED + { + // If it has border, have textctrl will the entire text field. + m_text->SetSize( m_tcArea.x + m_widthCustomPaint, + m_tcArea.y, + m_tcArea.width - m_widthCustomPaint, + m_tcArea.height ); + } +} + +wxSize wxComboCtrlBase::DoGetBestSize() const +{ + wxSize sizeText(150,0); + + if ( m_text ) + sizeText = m_text->GetBestSize(); + + // TODO: Better method to calculate close-to-native control height. + + int fhei; + if ( m_font.Ok() ) + fhei = (m_font.GetPointSize()*2) + 5; + else if ( wxNORMAL_FONT->Ok() ) + fhei = (wxNORMAL_FONT->GetPointSize()*2) + 5; + else + fhei = sizeText.y + 4; + + // Need to force height to accomodate bitmap? + int btnSizeY = m_btnSize.y; + if ( m_bmpNormal.Ok() && fhei < btnSizeY ) + fhei = btnSizeY; + + // Control height doesn't depend on border +/* + // Add border + int border = m_windowStyle & wxBORDER_MASK; + if ( border == wxSIMPLE_BORDER ) + fhei += 2; + else if ( border == wxNO_BORDER ) + fhei += (m_widthCustomBorder*2); + else + // Sunken etc. + fhei += 4; +*/ + + // Final adjustments +#ifdef __WXGTK__ + fhei += 1; +#endif + +#ifdef __WXMAC__ + // these are the numbers from the HIG: + switch ( m_windowVariant ) + { + case wxWINDOW_VARIANT_NORMAL: + default : + fhei = 22; + break; + case wxWINDOW_VARIANT_SMALL: + fhei = 19; + break; + case wxWINDOW_VARIANT_MINI: + fhei = 15; + break; + } +#endif + + fhei += 2 * FOCUS_RING; + int width = sizeText.x + FOCUS_RING + COMBO_MARGIN + DEFAULT_DROPBUTTON_WIDTH; + + wxSize ret(width, fhei); + CacheBestSize(ret); + return ret; +} + +void wxComboCtrlBase::OnSizeEvent( wxSizeEvent& event ) +{ + if ( !IsCreated() ) + return; + + // defined by actual wxComboCtrls + OnResize(); + + event.Skip(); +} + +// ---------------------------------------------------------------------------- +// standard operations +// ---------------------------------------------------------------------------- + +bool wxComboCtrlBase::Enable(bool enable) +{ + if ( !wxControl::Enable(enable) ) + return false; + + if ( m_btn ) + m_btn->Enable(enable); + if ( m_text ) + m_text->Enable(enable); + + return true; +} + +bool wxComboCtrlBase::Show(bool show) +{ + if ( !wxControl::Show(show) ) + return false; + + if (m_btn) + m_btn->Show(show); + + if (m_text) + m_text->Show(show); + + return true; +} + +bool wxComboCtrlBase::SetFont ( const wxFont& font ) +{ + if ( !wxControl::SetFont(font) ) + return false; + + if (m_text) + m_text->SetFont(font); + + return true; +} + +#if wxUSE_TOOLTIPS +void wxComboCtrlBase::DoSetToolTip(wxToolTip *tooltip) +{ + wxControl::DoSetToolTip(tooltip); + + // Set tool tip for button and text box + if ( tooltip ) + { + const wxString &tip = tooltip->GetTip(); + if ( m_text ) m_text->SetToolTip(tip); + if ( m_btn ) m_btn->SetToolTip(tip); + } + else + { + if ( m_text ) m_text->SetToolTip( (wxToolTip*) NULL ); + if ( m_btn ) m_btn->SetToolTip( (wxToolTip*) NULL ); + } +} +#endif // wxUSE_TOOLTIPS + +#if wxUSE_VALIDATORS +void wxComboCtrlBase::SetValidator(const wxValidator& validator) +{ + wxTextCtrl* textCtrl = GetTextCtrl(); + + if ( textCtrl ) + textCtrl->SetValidator( validator ); +} + +wxValidator* wxComboCtrlBase::GetValidator() +{ + wxTextCtrl* textCtrl = GetTextCtrl(); + + if ( textCtrl ) + return textCtrl->GetValidator(); + + return wxControl::GetValidator(); +} +#endif // wxUSE_VALIDATORS + +// ---------------------------------------------------------------------------- +// painting +// ---------------------------------------------------------------------------- + +#if (!defined(__WXMSW__)) || defined(__WXUNIVERSAL__) +// prepare combo box background on area in a way typical on platform +void wxComboCtrlBase::PrepareBackground( wxDC& dc, const wxRect& rect, int flags ) const +{ + wxSize sz = GetClientSize(); + bool isEnabled; + bool isFocused; // also selected + + // For smaller size control (and for disabled background) use less spacing + int focusSpacingX; + int focusSpacingY; + + if ( !(flags & wxCONTROL_ISSUBMENU) ) + { + // Drawing control + isEnabled = IsEnabled(); + isFocused = ShouldDrawFocus(); + + // Windows-style: for smaller size control (and for disabled background) use less spacing + focusSpacingX = isEnabled ? 2 : 1; + focusSpacingY = sz.y > (GetCharHeight()+2) && isEnabled ? 2 : 1; + } + else + { + // Drawing a list item + isEnabled = true; // they are never disabled + isFocused = flags & wxCONTROL_SELECTED ? true : false; + + focusSpacingX = 0; + focusSpacingY = 0; + } + + // Set the background sub-rectangle for selection, disabled etc + wxRect selRect(rect); + selRect.y += focusSpacingY; + selRect.height -= (focusSpacingY*2); + + int wcp = 0; + + if ( !(flags & wxCONTROL_ISSUBMENU) ) + wcp += m_widthCustomPaint; + + selRect.x += wcp + focusSpacingX; + selRect.width -= wcp + (focusSpacingX*2); + + wxColour bgCol; + + if ( isEnabled ) + { + // If popup is hidden and this control is focused, + // then draw the focus-indicator (selbgcolor background etc.). + if ( isFocused ) + { + dc.SetTextForeground( wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT) ); + bgCol = wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT); + } + else + { + dc.SetTextForeground( wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT) ); +#ifndef __WXMAC__ // see note in OnThemeChange + bgCol = GetBackgroundColour(); +#else + bgCol = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW); +#endif + } + } + else + { + dc.SetTextForeground( wxSystemSettings::GetColour(wxSYS_COLOUR_GRAYTEXT) ); +#ifndef __WXMAC__ // see note in OnThemeChange + bgCol = GetBackgroundColour(); +#else + bgCol = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW); +#endif + } + + dc.SetBrush( bgCol ); + dc.SetPen( bgCol ); + dc.DrawRectangle( selRect ); + + // Don't clip exactly to the selection rectangle so we can draw + // to the non-selected area in front of it. + wxRect clipRect(rect.x,rect.y, + (selRect.x+selRect.width)-rect.x,rect.height); + dc.SetClippingRegion(clipRect); +} +#else +// Save the library size a bit for platforms that re-implement this. +void wxComboCtrlBase::PrepareBackground( wxDC&, const wxRect&, int ) const +{ +} +#endif + +void wxComboCtrlBase::DrawButton( wxDC& dc, const wxRect& rect, int paintBg ) +{ + int drawState = m_btnState; + +#ifdef __WXGTK__ + if ( GetPopupWindowState() >= Animating ) + drawState |= wxCONTROL_PRESSED; +#endif + + wxRect drawRect(rect.x+m_btnSpacingX, + rect.y+((rect.height-m_btnSize.y)/2), + m_btnSize.x, + m_btnSize.y); + + // Make sure area is not larger than the control + if ( drawRect.y < rect.y ) + drawRect.y = rect.y; + if ( drawRect.height > rect.height ) + drawRect.height = rect.height; + + bool enabled = IsEnabled(); + + if ( !enabled ) + drawState |= wxCONTROL_DISABLED; + + if ( !m_bmpNormal.Ok() ) + { + // Need to clear button background even if m_btn is present + if ( paintBg ) + { + wxColour bgCol; + + if ( m_iFlags & wxCC_IFLAG_BUTTON_OUTSIDE ) + bgCol = GetParent()->GetBackgroundColour(); + else + bgCol = GetBackgroundColour(); + + dc.SetBrush(bgCol); + dc.SetPen(bgCol); + dc.DrawRectangle(rect); + } + + // Draw standard button + wxRendererNative::Get().DrawComboBoxDropButton(this, + dc, + drawRect, + drawState); + } + else + { + // Draw bitmap + + wxBitmap* pBmp; + + if ( !enabled ) + pBmp = &m_bmpDisabled; + else if ( m_btnState & wxCONTROL_PRESSED ) + pBmp = &m_bmpPressed; + else if ( m_btnState & wxCONTROL_CURRENT ) + pBmp = &m_bmpHover; + else + pBmp = &m_bmpNormal; + + if ( m_blankButtonBg ) + { + // If using blank button background, we need to clear its background + // with button face colour instead of colour for rest of the control. + if ( paintBg ) + { + wxColour bgCol = GetParent()->GetBackgroundColour(); //wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE); + //wxColour bgCol = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW); + dc.SetPen(bgCol); + dc.SetBrush(bgCol); + dc.DrawRectangle(rect); + } + + wxRendererNative::Get().DrawPushButton(this, + dc, + drawRect, + drawState); + + } + else + + { + // Need to clear button background even if m_btn is present + // (assume non-button background was cleared just before this call so brushes are good) + if ( paintBg ) + dc.DrawRectangle(rect); + } + + // Draw bitmap centered in drawRect + dc.DrawBitmap(*pBmp, + drawRect.x + (drawRect.width-pBmp->GetWidth())/2, + drawRect.y + (drawRect.height-pBmp->GetHeight())/2, + true); + } +} + +void wxComboCtrlBase::RecalcAndRefresh() +{ + if ( IsCreated() ) + { + wxSizeEvent evt(GetSize(),GetId()); + GetEventHandler()->ProcessEvent(evt); + Refresh(); + } +} + +// ---------------------------------------------------------------------------- +// miscellaneous event handlers +// ---------------------------------------------------------------------------- + +void wxComboCtrlBase::OnTextCtrlEvent(wxCommandEvent& event) +{ + if ( event.GetEventType() == wxEVT_COMMAND_TEXT_UPDATED ) + { + if ( m_ignoreEvtText > 0 ) + { + m_ignoreEvtText--; + return; + } + } + + // Change event id, object and string before relaying it forward + event.SetId(GetId()); + wxString s = event.GetString(); + event.SetEventObject(this); + event.SetString(s); + event.Skip(); +} + +// call if cursor is on button area or mouse is captured for the button +bool wxComboCtrlBase::HandleButtonMouseEvent( wxMouseEvent& event, + int flags ) +{ + int type = event.GetEventType(); + + if ( type == wxEVT_MOTION ) + { + if ( flags & wxCC_MF_ON_BUTTON ) + { + if ( !(m_btnState & wxCONTROL_CURRENT) ) + { + // Mouse hover begins + m_btnState |= wxCONTROL_CURRENT; + if ( HasCapture() ) // Retain pressed state. + m_btnState |= wxCONTROL_PRESSED; + Refresh(); + } + } + else if ( (m_btnState & wxCONTROL_CURRENT) ) + { + // Mouse hover ends + m_btnState &= ~(wxCONTROL_CURRENT|wxCONTROL_PRESSED); + Refresh(); + } + } + else if ( type == wxEVT_LEFT_DOWN || type == wxEVT_LEFT_DCLICK ) + { + if ( flags & (wxCC_MF_ON_CLICK_AREA|wxCC_MF_ON_BUTTON) ) + { + m_btnState |= wxCONTROL_PRESSED; + Refresh(); + + if ( !(m_iFlags & wxCC_POPUP_ON_MOUSE_UP) ) + OnButtonClick(); + else + // If showing popup now, do not capture mouse or there will be interference + CaptureMouse(); + } + } + else if ( type == wxEVT_LEFT_UP ) + { + + // Only accept event if mouse was left-press was previously accepted + if ( HasCapture() ) + ReleaseMouse(); + + if ( m_btnState & wxCONTROL_PRESSED ) + { + // If mouse was inside, fire the click event. + if ( m_iFlags & wxCC_POPUP_ON_MOUSE_UP ) + { + if ( flags & (wxCC_MF_ON_CLICK_AREA|wxCC_MF_ON_BUTTON) ) + OnButtonClick(); + } + + m_btnState &= ~(wxCONTROL_PRESSED); + Refresh(); + } + } + else if ( type == wxEVT_LEAVE_WINDOW ) + { + if ( m_btnState & (wxCONTROL_CURRENT|wxCONTROL_PRESSED) ) + { + m_btnState &= ~(wxCONTROL_CURRENT); + + // Mouse hover ends + if ( IsPopupWindowState(Hidden) ) + { + m_btnState &= ~(wxCONTROL_PRESSED); + Refresh(); + } + } + } + else + return false; + + return true; +} + +// returns true if event was consumed or filtered +bool wxComboCtrlBase::PreprocessMouseEvent( wxMouseEvent& event, + int WXUNUSED(flags) ) +{ + wxLongLong t = ::wxGetLocalTimeMillis(); + int evtType = event.GetEventType(); + +#if USES_WXPOPUPWINDOW || USES_WXDIALOG + if ( m_popupWinType != POPUPWIN_WXPOPUPTRANSIENTWINDOW ) + { + if ( IsPopupWindowState(Visible) && + ( evtType == wxEVT_LEFT_DOWN || evtType == wxEVT_RIGHT_DOWN ) ) + { + HidePopup(); + return true; + } + } +#endif + + // Filter out clicks on button immediately after popup dismiss (Windows like behaviour) + if ( evtType == wxEVT_LEFT_DOWN && t < m_timeCanAcceptClick ) + { + event.SetEventType(0); + return true; + } + + return false; +} + +void wxComboCtrlBase::HandleNormalMouseEvent( wxMouseEvent& event ) +{ + int evtType = event.GetEventType(); + + if ( (evtType == wxEVT_LEFT_DOWN || evtType == wxEVT_LEFT_DCLICK) && + (m_windowStyle & wxCB_READONLY) ) + { + if ( GetPopupWindowState() >= Animating ) + { + #if USES_WXPOPUPWINDOW + // Click here always hides the popup. + if ( m_popupWinType == POPUPWIN_WXPOPUPWINDOW ) + HidePopup(); + #endif + } + else + { + if ( !(m_windowStyle & wxCC_SPECIAL_DCLICK) ) + { + // In read-only mode, clicking the text is the + // same as clicking the button. + OnButtonClick(); + } + else if ( /*evtType == wxEVT_LEFT_UP || */evtType == wxEVT_LEFT_DCLICK ) + { + //if ( m_popupInterface->CycleValue() ) + // Refresh(); + if ( m_popupInterface ) + m_popupInterface->OnComboDoubleClick(); + } + } + } + else + if ( IsPopupShown() ) + { + // relay (some) mouse events to the popup + if ( evtType == wxEVT_MOUSEWHEEL ) + m_popup->AddPendingEvent(event); + } + else if ( evtType ) + event.Skip(); +} + +void wxComboCtrlBase::OnKeyEvent(wxKeyEvent& event) +{ + if ( IsPopupShown() ) + { + // pass it to the popped up control + GetPopupControl()->GetControl()->AddPendingEvent(event); + } + else // no popup + { + int keycode = event.GetKeyCode(); + + if ( keycode == WXK_TAB ) + { + wxNavigationKeyEvent evt; + + wxWindow* mainCtrl = GetMainWindowOfCompositeControl(); + + evt.SetFlags(wxNavigationKeyEvent::FromTab| + (!event.ShiftDown() ? wxNavigationKeyEvent::IsForward + : wxNavigationKeyEvent::IsBackward)); + evt.SetEventObject(mainCtrl); + evt.SetCurrentFocus(mainCtrl); + mainCtrl->GetParent()->GetEventHandler()->AddPendingEvent(evt); + return; + } + + if ( IsKeyPopupToggle(event) ) + { + OnButtonClick(); + return; + } + + int comboStyle = GetWindowStyle(); + wxComboPopup* popupInterface = GetPopupControl(); + + if ( !popupInterface ) + { + event.Skip(); + return; + } + + if ( (comboStyle & wxCB_READONLY) || + (keycode != WXK_RIGHT && keycode != WXK_LEFT) ) + { + popupInterface->OnComboKeyEvent(event); + } + else + event.Skip(); + } +} + +void wxComboCtrlBase::OnFocusEvent( wxFocusEvent& event ) +{ + if ( event.GetEventType() == wxEVT_SET_FOCUS ) + { + wxWindow* tc = GetTextCtrl(); + if ( tc && tc != DoFindFocus() ) +#ifdef __WXMAC__ + m_resetFocus = true; +#else + tc->SetFocus(); +#endif + } + + Refresh(); +} + +void wxComboCtrlBase::OnIdleEvent( wxIdleEvent& WXUNUSED(event) ) +{ + if ( m_resetFocus ) + { + m_resetFocus = false; + wxWindow* tc = GetTextCtrl(); + if ( tc ) + tc->SetFocus(); + } +} + +void wxComboCtrlBase::OnSysColourChanged(wxSysColourChangedEvent& WXUNUSED(event)) +{ + OnThemeChange(); + // indentation may also have changed + if ( !(m_iFlags & wxCC_IFLAG_INDENT_SET) ) + m_absIndent = GetNativeTextIndent(); + RecalcAndRefresh(); +} + +// ---------------------------------------------------------------------------- +// popup handling +// ---------------------------------------------------------------------------- + +// Create popup window and the child control +void wxComboCtrlBase::CreatePopup() +{ + wxComboPopup* popupInterface = m_popupInterface; + wxWindow* popup; + + if ( !m_winPopup ) + { +#ifdef wxComboPopupWindowBase2 + if ( m_iFlags & wxCC_IFLAG_USE_ALT_POPUP ) + { + #if !USES_WXDIALOG + m_winPopup = new wxComboPopupWindowBase2( this, wxNO_BORDER ); + #else + m_winPopup = new wxComboPopupWindowBase2( this, wxID_ANY, wxEmptyString, + wxPoint(-21,-21), wxSize(20, 20), + wxNO_BORDER ); + #endif + m_popupWinType = SECONDARY_POPUP_TYPE; + } + else +#endif + { + m_winPopup = new wxComboPopupWindow( this, wxNO_BORDER ); + m_popupWinType = PRIMARY_POPUP_TYPE; + } + m_popupWinEvtHandler = new wxComboPopupWindowEvtHandler(this); + m_winPopup->PushEventHandler(m_popupWinEvtHandler); + } + + popupInterface->Create(m_winPopup); + m_popup = popup = popupInterface->GetControl(); + + m_popupExtraHandler = new wxComboPopupExtraEventHandler(this); + popup->PushEventHandler( m_popupExtraHandler ); + + // This may be helpful on some platforms + // (eg. it bypasses a wxGTK popupwindow bug where + // window is not initially hidden when it should be) + m_winPopup->Hide(); + + popupInterface->m_iFlags |= wxCP_IFLAG_CREATED; +} + +// Destroy popup window and the child control +void wxComboCtrlBase::DestroyPopup() +{ + HidePopup(); + + if ( m_popup ) + m_popup->RemoveEventHandler(m_popupExtraHandler); + + delete m_popupExtraHandler; + + delete m_popupInterface; + + if ( m_winPopup ) + { + m_winPopup->RemoveEventHandler(m_popupWinEvtHandler); + delete m_popupWinEvtHandler; + m_popupWinEvtHandler = NULL; + m_winPopup->Destroy(); + } + + m_popupExtraHandler = (wxEvtHandler*) NULL; + m_popupInterface = (wxComboPopup*) NULL; + m_winPopup = (wxWindow*) NULL; + m_popup = (wxWindow*) NULL; +} + +void wxComboCtrlBase::DoSetPopupControl(wxComboPopup* iface) +{ + wxCHECK_RET( iface, wxT("no popup interface set for wxComboCtrl") ); + + DestroyPopup(); + + iface->InitBase(this); + iface->Init(); + + m_popupInterface = iface; + + if ( !iface->LazyCreate() ) + { + CreatePopup(); + } + else + { + m_popup = (wxWindow*) NULL; + } + + // This must be done after creation + if ( m_valueString.length() ) + { + iface->SetStringValue(m_valueString); + //Refresh(); + } +} + +// Ensures there is atleast the default popup +void wxComboCtrlBase::EnsurePopupControl() +{ + if ( !m_popupInterface ) + SetPopupControl(NULL); +} + +void wxComboCtrlBase::OnButtonClick() +{ + // Derived classes can override this method for totally custom + // popup action + ShowPopup(); +} + +void wxComboCtrlBase::ShowPopup() +{ + EnsurePopupControl(); + wxCHECK_RET( !IsPopupWindowState(Visible), wxT("popup window already shown") ); + + if ( IsPopupWindowState(Animating) ) + return; + + SetFocus(); + + // Space above and below + int screenHeight; + wxPoint scrPos; + int spaceAbove; + int spaceBelow; + int maxHeightPopup; + wxSize ctrlSz = GetSize(); + + screenHeight = wxSystemSettings::GetMetric( wxSYS_SCREEN_Y ); + scrPos = GetParent()->ClientToScreen(GetPosition()); + + spaceAbove = scrPos.y; + spaceBelow = screenHeight - spaceAbove - ctrlSz.y; + + maxHeightPopup = spaceBelow; + if ( spaceAbove > spaceBelow ) + maxHeightPopup = spaceAbove; + + // Width + int widthPopup = ctrlSz.x + m_extLeft + m_extRight; + + if ( widthPopup < m_widthMinPopup ) + widthPopup = m_widthMinPopup; + + wxWindow* winPopup = m_winPopup; + wxWindow* popup; + + // Need to disable tab traversal of parent + // + // NB: This is to fix a bug in wxMSW. In theory it could also be fixed + // by, for instance, adding check to window.cpp:wxWindowMSW::MSWProcessMessage + // that if transient popup is open, then tab traversal is to be ignored. + // However, I think this code would still be needed for cases where + // transient popup doesn't work yet (wxWinCE?). + wxWindow* parent = GetParent(); + int parentFlags = parent->GetWindowStyle(); + if ( parentFlags & wxTAB_TRAVERSAL ) + { + parent->SetWindowStyle( parentFlags & ~(wxTAB_TRAVERSAL) ); + m_iFlags |= wxCC_IFLAG_PARENT_TAB_TRAVERSAL; + } + + if ( !winPopup ) + { + CreatePopup(); + winPopup = m_winPopup; + popup = m_popup; + } + else + { + popup = m_popup; + } + + winPopup->Enable(); + + wxASSERT( !m_popup || m_popup == popup ); // Consistency check. + + wxSize adjustedSize = m_popupInterface->GetAdjustedSize(widthPopup, + m_heightPopup<=0?DEFAULT_POPUP_HEIGHT:m_heightPopup, + maxHeightPopup); + + popup->SetSize(adjustedSize); + popup->Move(0,0); + m_popupInterface->OnPopup(); + + // + // Reposition and resize popup window + // + + wxSize szp = popup->GetSize(); + + int popupX; + int popupY = scrPos.y + ctrlSz.y; + + // Default anchor is wxLEFT + int anchorSide = m_anchorSide; + if ( !anchorSide ) + anchorSide = wxLEFT; + + int rightX = scrPos.x + ctrlSz.x + m_extRight - szp.x; + int leftX = scrPos.x - m_extLeft; + + if ( wxTheApp->GetLayoutDirection() == wxLayout_RightToLeft ) + leftX -= ctrlSz.x; + + int screenWidth = wxSystemSettings::GetMetric( wxSYS_SCREEN_X ); + + // If there is not enough horizontal space, anchor on the other side. + // If there is no space even then, place the popup at x 0. + if ( anchorSide == wxRIGHT ) + { + if ( rightX < 0 ) + { + if ( (leftX+szp.x) < screenWidth ) + anchorSide = wxLEFT; + else + anchorSide = 0; + } + } + else + { + if ( (leftX+szp.x) >= screenWidth ) + { + if ( rightX >= 0 ) + anchorSide = wxRIGHT; + else + anchorSide = 0; + } + } + + // Select x coordinate according to the anchor side + if ( anchorSide == wxRIGHT ) + popupX = rightX; + else if ( anchorSide == wxLEFT ) + popupX = leftX; + else + popupX = 0; + + int showFlags = CanDeferShow; + + if ( spaceBelow < szp.y ) + { + popupY = scrPos.y - szp.y; + showFlags |= ShowAbove; + } + +#if INSTALL_TOPLEV_HANDLER + // Put top level window event handler into place + if ( m_popupWinType == POPUPWIN_WXPOPUPWINDOW ) + { + if ( !m_toplevEvtHandler ) + m_toplevEvtHandler = new wxComboFrameEventHandler(this); + + wxWindow* toplev = ::wxGetTopLevelParent( this ); + wxASSERT( toplev ); + ((wxComboFrameEventHandler*)m_toplevEvtHandler)->OnPopup(); + toplev->PushEventHandler( m_toplevEvtHandler ); + } +#endif + + // Set string selection (must be this way instead of SetStringSelection) + if ( m_text ) + { + if ( !(m_iFlags & wxCC_NO_TEXT_AUTO_SELECT) ) + m_text->SelectAll(); + + m_popupInterface->SetStringValue( m_text->GetValue() ); + } + else + { + // This is neede since focus/selection indication may change when popup is shown + Refresh(); + } + + // This must be after SetStringValue + m_popupWinState = Animating; + + wxRect popupWinRect( popupX, popupY, szp.x, szp.y ); + + m_popup = popup; + if ( (m_iFlags & wxCC_IFLAG_DISABLE_POPUP_ANIM) || + AnimateShow( popupWinRect, showFlags ) ) + { + DoShowPopup( popupWinRect, showFlags ); + } +} + +bool wxComboCtrlBase::AnimateShow( const wxRect& WXUNUSED(rect), int WXUNUSED(flags) ) +{ + return true; +} + +void wxComboCtrlBase::DoShowPopup( const wxRect& rect, int WXUNUSED(flags) ) +{ + wxWindow* winPopup = m_winPopup; + + if ( IsPopupWindowState(Animating) ) + { + // Make sure the popup window is shown in the right position. + // Should not matter even if animation already did this. + + // Some platforms (GTK) may like SetSize and Move to be separate + // (though the bug was probably fixed). + winPopup->SetSize( rect ); + + winPopup->Show(); + + m_popupWinState = Visible; + } + else if ( IsPopupWindowState(Hidden) ) + { + // Animation was aborted + + wxASSERT( !winPopup->IsShown() ); + + m_popupWinState = Hidden; + } +} + +void wxComboCtrlBase::OnPopupDismiss() +{ + // Just in case, avoid double dismiss + if ( IsPopupWindowState(Hidden) ) + return; + + // This must be set before focus - otherwise there will be recursive + // OnPopupDismisses. + m_popupWinState = Hidden; + + //SetFocus(); + m_winPopup->Disable(); + + // Inform popup control itself + m_popupInterface->OnDismiss(); + + if ( m_popupExtraHandler ) + ((wxComboPopupExtraEventHandler*)m_popupExtraHandler)->OnPopupDismiss(); + +#if INSTALL_TOPLEV_HANDLER + // Remove top level window event handler + if ( m_toplevEvtHandler ) + { + wxWindow* toplev = ::wxGetTopLevelParent( this ); + if ( toplev ) + toplev->RemoveEventHandler( m_toplevEvtHandler ); + } +#endif + + m_timeCanAcceptClick = ::wxGetLocalTimeMillis(); + + if ( m_popupWinType == POPUPWIN_WXPOPUPTRANSIENTWINDOW ) + m_timeCanAcceptClick += 150; + + // If cursor not on dropdown button, then clear its state + // (technically not required by all ports, but do it for all just in case) + if ( !m_btnArea.Contains(ScreenToClient(::wxGetMousePosition())) ) + m_btnState = 0; + + // Return parent's tab traversal flag. + // See ShowPopup for notes. + if ( m_iFlags & wxCC_IFLAG_PARENT_TAB_TRAVERSAL ) + { + wxWindow* parent = GetParent(); + parent->SetWindowStyle( parent->GetWindowStyle() | wxTAB_TRAVERSAL ); + m_iFlags &= ~(wxCC_IFLAG_PARENT_TAB_TRAVERSAL); + } + + // refresh control (necessary even if m_text) + Refresh(); + + SetFocus(); +} + +void wxComboCtrlBase::HidePopup() +{ + // Should be able to call this without popup interface + if ( IsPopupWindowState(Hidden) ) + return; + + // transfer value and show it in textctrl, if any + if ( !IsPopupWindowState(Animating) ) + SetValue( m_popupInterface->GetStringValue() ); + + m_winPopup->Hide(); + + OnPopupDismiss(); +} + +// ---------------------------------------------------------------------------- +// customization methods +// ---------------------------------------------------------------------------- + +void wxComboCtrlBase::SetButtonPosition( int width, int height, + int side, int spacingX ) +{ + m_btnWid = width; + m_btnHei = height; + m_btnSide = side; + m_btnSpacingX = spacingX; + + RecalcAndRefresh(); +} + +wxSize wxComboCtrlBase::GetButtonSize() +{ + if ( m_btnSize.x > 0 ) + return m_btnSize; + + wxSize retSize(m_btnWid,m_btnHei); + + // Need to call CalculateAreas now if button size is + // is not explicitly specified. + if ( retSize.x <= 0 || retSize.y <= 0) + { + OnResize(); + + retSize = m_btnSize; + } + + return retSize; +} + +void wxComboCtrlBase::SetButtonBitmaps( const wxBitmap& bmpNormal, + bool blankButtonBg, + const wxBitmap& bmpPressed, + const wxBitmap& bmpHover, + const wxBitmap& bmpDisabled ) +{ + m_bmpNormal = bmpNormal; + m_blankButtonBg = blankButtonBg; + + if ( bmpPressed.Ok() ) + m_bmpPressed = bmpPressed; + else + m_bmpPressed = bmpNormal; + + if ( bmpHover.Ok() ) + m_bmpHover = bmpHover; + else + m_bmpHover = bmpNormal; + + if ( bmpDisabled.Ok() ) + m_bmpDisabled = bmpDisabled; + else + m_bmpDisabled = bmpNormal; + + RecalcAndRefresh(); +} + +void wxComboCtrlBase::SetCustomPaintWidth( int width ) +{ + if ( m_text ) + { + // move textctrl accordingly + wxRect r = m_text->GetRect(); + int inc = width - m_widthCustomPaint; + r.x += inc; + r.width -= inc; + m_text->SetSize( r ); + } + + m_widthCustomPaint = width; + + RecalcAndRefresh(); +} + +void wxComboCtrlBase::SetTextIndent( int indent ) +{ + if ( indent < 0 ) + { + m_absIndent = GetNativeTextIndent(); + m_iFlags &= ~(wxCC_IFLAG_INDENT_SET); + } + else + { + m_absIndent = indent; + m_iFlags |= wxCC_IFLAG_INDENT_SET; + } + + RecalcAndRefresh(); +} + +wxCoord wxComboCtrlBase::GetNativeTextIndent() const +{ + return DEFAULT_TEXT_INDENT; +} + +// ---------------------------------------------------------------------------- +// methods forwarded to wxTextCtrl +// ---------------------------------------------------------------------------- + +wxString wxComboCtrlBase::GetValue() const +{ + if ( m_text ) + return m_text->GetValue(); + return m_valueString; +} + +void wxComboCtrlBase::SetValueWithEvent(const wxString& value, bool withEvent) +{ + if ( m_text ) + { + if ( !withEvent ) + m_ignoreEvtText++; + + m_text->SetValue(value); + if ( !(m_iFlags & wxCC_NO_TEXT_AUTO_SELECT) ) + m_text->SelectAll(); + } + + // Since wxComboPopup may want to paint the combo as well, we need + // to set the string value here (as well as sometimes in ShowPopup). + if ( m_valueString != value ) + { + m_valueString = value; + + EnsurePopupControl(); + + if (m_popupInterface) + m_popupInterface->SetStringValue(value); + } + + Refresh(); +} + +void wxComboCtrlBase::SetValue(const wxString& value) +{ + SetValueWithEvent(value, false); +} + +// In this SetValue variant wxComboPopup::SetStringValue is not called +void wxComboCtrlBase::SetText(const wxString& value) +{ + // Unlike in SetValue(), this must be called here or + // the behaviour will no be consistent in readonlys. + EnsurePopupControl(); + + m_valueString = value; + + if ( m_text ) + { + m_ignoreEvtText++; + m_text->SetValue( value ); + } + + Refresh(); +} + +void wxComboCtrlBase::Copy() +{ + if ( m_text ) + m_text->Copy(); +} + +void wxComboCtrlBase::Cut() +{ + if ( m_text ) + m_text->Cut(); +} + +void wxComboCtrlBase::Paste() +{ + if ( m_text ) + m_text->Paste(); +} + +void wxComboCtrlBase::SetInsertionPoint(long pos) +{ + if ( m_text ) + m_text->SetInsertionPoint(pos); +} + +void wxComboCtrlBase::SetInsertionPointEnd() +{ + if ( m_text ) + m_text->SetInsertionPointEnd(); +} + +long wxComboCtrlBase::GetInsertionPoint() const +{ + if ( m_text ) + return m_text->GetInsertionPoint(); + + return 0; +} + +long wxComboCtrlBase::GetLastPosition() const +{ + if ( m_text ) + return m_text->GetLastPosition(); + + return 0; +} + +void wxComboCtrlBase::Replace(long from, long to, const wxString& value) +{ + if ( m_text ) + m_text->Replace(from, to, value); +} + +void wxComboCtrlBase::Remove(long from, long to) +{ + if ( m_text ) + m_text->Remove(from, to); +} + +void wxComboCtrlBase::SetSelection(long from, long to) +{ + if ( m_text ) + m_text->SetSelection(from, to); +} + +void wxComboCtrlBase::Undo() +{ + if ( m_text ) + m_text->Undo(); +} + +#endif // wxUSE_COMBOCTRL diff --git a/Externals/wxWidgets/src/common/config.cpp b/Externals/wxWidgets/src/common/config.cpp index 1079e46be5..ce169563f7 100644 --- a/Externals/wxWidgets/src/common/config.cpp +++ b/Externals/wxWidgets/src/common/config.cpp @@ -1,490 +1,490 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: src/common/config.cpp -// Purpose: implementation of wxConfigBase class -// Author: Vadim Zeitlin -// Modified by: -// Created: 07.04.98 -// RCS-ID: $Id: config.cpp 50711 2007-12-15 02:57:58Z VZ $ -// Copyright: (c) 1997 Karsten Ballueder Ballueder@usa.net -// Vadim Zeitlin -// Licence: wxWindows licence -/////////////////////////////////////////////////////////////////////////////// - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif //__BORLANDC__ - -#ifndef wxUSE_CONFIG_NATIVE - #define wxUSE_CONFIG_NATIVE 1 -#endif - -#include "wx/config.h" - -#ifndef WX_PRECOMP - #include "wx/intl.h" - #include "wx/log.h" - #include "wx/app.h" - #include "wx/utils.h" - #include "wx/arrstr.h" - #include "wx/math.h" -#endif //WX_PRECOMP - -#if wxUSE_CONFIG && ((wxUSE_FILE && wxUSE_TEXTFILE) || wxUSE_CONFIG_NATIVE) - -#include "wx/file.h" - -#include -#include -#include // for INT_MAX - -// ---------------------------------------------------------------------------- -// global and class static variables -// ---------------------------------------------------------------------------- - -wxConfigBase *wxConfigBase::ms_pConfig = NULL; -bool wxConfigBase::ms_bAutoCreate = true; - -// ============================================================================ -// implementation -// ============================================================================ - -// ---------------------------------------------------------------------------- -// wxConfigBase -// ---------------------------------------------------------------------------- - -// Not all args will always be used by derived classes, but including them all -// in each class ensures compatibility. -wxConfigBase::wxConfigBase(const wxString& appName, - const wxString& vendorName, - const wxString& WXUNUSED(localFilename), - const wxString& WXUNUSED(globalFilename), - long style) - : m_appName(appName), m_vendorName(vendorName), m_style(style) -{ - m_bExpandEnvVars = true; - m_bRecordDefaults = false; -} - -wxConfigBase::~wxConfigBase() -{ - // required here for Darwin -} - -wxConfigBase *wxConfigBase::Set(wxConfigBase *pConfig) -{ - wxConfigBase *pOld = ms_pConfig; - ms_pConfig = pConfig; - return pOld; -} - -wxConfigBase *wxConfigBase::Create() -{ - if ( ms_bAutoCreate && ms_pConfig == NULL ) { - ms_pConfig = - #if defined(__WXMSW__) && wxUSE_CONFIG_NATIVE - new wxRegConfig(wxTheApp->GetAppName(), wxTheApp->GetVendorName()); - #elif defined(__WXPALMOS__) && wxUSE_CONFIG_NATIVE - new wxPrefConfig(wxTheApp->GetAppName()); - #else // either we're under Unix or wish to use files even under Windows - new wxFileConfig(wxTheApp->GetAppName()); - #endif - } - - return ms_pConfig; -} - -// ---------------------------------------------------------------------------- -// wxConfigBase reading entries -// ---------------------------------------------------------------------------- - -// implement both Read() overloads for the given type in terms of DoRead() -#define IMPLEMENT_READ_FOR_TYPE(name, type, deftype, extra) \ - bool wxConfigBase::Read(const wxString& key, type *val) const \ - { \ - wxCHECK_MSG( val, false, _T("wxConfig::Read(): NULL parameter") ); \ - \ - if ( !DoRead##name(key, val) ) \ - return false; \ - \ - *val = extra(*val); \ - \ - return true; \ - } \ - \ - bool wxConfigBase::Read(const wxString& key, \ - type *val, \ - deftype defVal) const \ - { \ - wxCHECK_MSG( val, false, _T("wxConfig::Read(): NULL parameter") ); \ - \ - bool read = DoRead##name(key, val); \ - if ( !read ) \ - { \ - if ( IsRecordingDefaults() ) \ - { \ - ((wxConfigBase *)this)->DoWrite##name(key, defVal); \ - } \ - \ - *val = defVal; \ - } \ - \ - *val = extra(*val); \ - \ - return read; \ - } - - -IMPLEMENT_READ_FOR_TYPE(String, wxString, const wxString&, ExpandEnvVars) -IMPLEMENT_READ_FOR_TYPE(Long, long, long, long) -IMPLEMENT_READ_FOR_TYPE(Int, int, int, int) -IMPLEMENT_READ_FOR_TYPE(Double, double, double, double) -IMPLEMENT_READ_FOR_TYPE(Bool, bool, bool, bool) - -#undef IMPLEMENT_READ_FOR_TYPE - -// the DoReadXXX() for the other types have implementation in the base class -// but can be overridden in the derived ones -bool wxConfigBase::DoReadInt(const wxString& key, int *pi) const -{ - wxCHECK_MSG( pi, false, _T("wxConfig::Read(): NULL parameter") ); - - long l; - if ( !DoReadLong(key, &l) ) - return false; - - wxASSERT_MSG( l < INT_MAX, _T("overflow in wxConfig::DoReadInt") ); - - *pi = (int)l; - - return true; -} - -bool wxConfigBase::DoReadBool(const wxString& key, bool* val) const -{ - wxCHECK_MSG( val, false, _T("wxConfig::Read(): NULL parameter") ); - - long l; - if ( !DoReadLong(key, &l) ) - return false; - - wxASSERT_MSG( l == 0 || l == 1, _T("bad bool value in wxConfig::DoReadInt") ); - - *val = l != 0; - - return true; -} - -bool wxConfigBase::DoReadDouble(const wxString& key, double* val) const -{ - wxString str; - if ( Read(key, &str) ) - { - return str.ToDouble(val); - } - - return false; -} - -// string reading helper -wxString wxConfigBase::ExpandEnvVars(const wxString& str) const -{ - wxString tmp; // Required for BC++ - if (IsExpandingEnvVars()) - tmp = wxExpandEnvVars(str); - else - tmp = str; - return tmp; -} - -// ---------------------------------------------------------------------------- -// wxConfigBase writing -// ---------------------------------------------------------------------------- - -bool wxConfigBase::DoWriteDouble(const wxString& key, double val) -{ - return DoWriteString(key, wxString::Format(_T("%g"), val)); -} - -bool wxConfigBase::DoWriteInt(const wxString& key, int value) -{ - return DoWriteLong(key, (long)value); -} - -bool wxConfigBase::DoWriteBool(const wxString& key, bool value) -{ - return DoWriteLong(key, value ? 1l : 0l); -} - -// ---------------------------------------------------------------------------- -// wxConfigPathChanger -// ---------------------------------------------------------------------------- - -wxConfigPathChanger::wxConfigPathChanger(const wxConfigBase *pContainer, - const wxString& strEntry) -{ - m_bChanged = false; - m_pContainer = (wxConfigBase *)pContainer; - - // the path is everything which precedes the last slash - wxString strPath = strEntry.BeforeLast(wxCONFIG_PATH_SEPARATOR); - - // except in the special case of "/keyname" when there is nothing before "/" - if ( strPath.empty() && - ((!strEntry.empty()) && strEntry[0] == wxCONFIG_PATH_SEPARATOR) ) - { - strPath = wxCONFIG_PATH_SEPARATOR; - } - - if ( !strPath.empty() ) - { - if ( m_pContainer->GetPath() != strPath ) - { - // we do change the path so restore it later - m_bChanged = true; - - /* JACS: work around a memory bug that causes an assert - when using wxRegConfig, related to reference-counting. - Can be reproduced by removing (const wxChar*) below and - adding the following code to the config sample OnInit under - Windows: - - pConfig->SetPath(wxT("MySettings")); - pConfig->SetPath(wxT("..")); - int value; - pConfig->Read(_T("MainWindowX"), & value); - */ - m_strOldPath = (const wxChar*) m_pContainer->GetPath(); - if ( *m_strOldPath.c_str() != wxCONFIG_PATH_SEPARATOR ) - m_strOldPath += wxCONFIG_PATH_SEPARATOR; - m_pContainer->SetPath(strPath); - } - - // in any case, use the just the name, not full path - m_strName = strEntry.AfterLast(wxCONFIG_PATH_SEPARATOR); - } - else { - // it's a name only, without path - nothing to do - m_strName = strEntry; - } -} - -void wxConfigPathChanger::UpdateIfDeleted() -{ - // we don't have to do anything at all if we didn't change the path - if ( !m_bChanged ) - return; - - // find the deepest still existing parent path of the original path - while ( !m_pContainer->HasGroup(m_strOldPath) ) - { - m_strOldPath = m_strOldPath.BeforeLast(wxCONFIG_PATH_SEPARATOR); - if ( m_strOldPath.empty() ) - m_strOldPath = wxCONFIG_PATH_SEPARATOR; - } -} - -wxConfigPathChanger::~wxConfigPathChanger() -{ - // only restore path if it was changed - if ( m_bChanged ) { - m_pContainer->SetPath(m_strOldPath); - } -} - -// this is a wxConfig method but it's mainly used with wxConfigPathChanger -/* static */ -wxString wxConfigBase::RemoveTrailingSeparator(const wxString& key) -{ - wxString path(key); - - // don't remove the only separator from a root group path! - while ( path.length() > 1 ) - { - if ( *path.rbegin() != wxCONFIG_PATH_SEPARATOR ) - break; - - path.erase(path.end() - 1); - } - - return path; -} - -#endif // wxUSE_CONFIG - -// ---------------------------------------------------------------------------- -// static & global functions -// ---------------------------------------------------------------------------- - -// understands both Unix and Windows (but only under Windows) environment -// variables expansion: i.e. $var, $(var) and ${var} are always understood -// and in addition under Windows %var% is also. - -// don't change the values the enum elements: they must be equal -// to the matching [closing] delimiter. -enum Bracket -{ - Bracket_None, - Bracket_Normal = ')', - Bracket_Curly = '}', -#ifdef __WXMSW__ - Bracket_Windows = '%', // yeah, Windows people are a bit strange ;-) -#endif - Bracket_Max -}; - -wxString wxExpandEnvVars(const wxString& str) -{ - wxString strResult; - strResult.Alloc(str.length()); - - size_t m; - for ( size_t n = 0; n < str.length(); n++ ) { - switch ( str[n] ) { -#ifdef __WXMSW__ - case wxT('%'): -#endif //WINDOWS - case wxT('$'): - { - Bracket bracket; - #ifdef __WXMSW__ - if ( str[n] == wxT('%') ) - bracket = Bracket_Windows; - else - #endif //WINDOWS - if ( n == str.length() - 1 ) { - bracket = Bracket_None; - } - else { - switch ( str[n + 1] ) { - case wxT('('): - bracket = Bracket_Normal; - n++; // skip the bracket - break; - - case wxT('{'): - bracket = Bracket_Curly; - n++; // skip the bracket - break; - - default: - bracket = Bracket_None; - } - } - - m = n + 1; - - while ( m < str.length() && (wxIsalnum(str[m]) || str[m] == wxT('_')) ) - m++; - - wxString strVarName(str.c_str() + n + 1, m - n - 1); - -#ifdef __WXWINCE__ - const wxChar *pszValue = NULL; -#else - // NB: use wxGetEnv instead of wxGetenv as otherwise variables - // set through wxSetEnv may not be read correctly! - const wxChar *pszValue = NULL; - wxString tmp; - if (wxGetEnv(strVarName, &tmp)) - pszValue = tmp; -#endif - if ( pszValue != NULL ) { - strResult += pszValue; - } - else { - // variable doesn't exist => don't change anything - #ifdef __WXMSW__ - if ( bracket != Bracket_Windows ) - #endif - if ( bracket != Bracket_None ) - strResult << str[n - 1]; - strResult << str[n] << strVarName; - } - - // check the closing bracket - if ( bracket != Bracket_None ) { - if ( m == str.length() || str[m] != (wxChar)bracket ) { - // under MSW it's common to have '%' characters in the registry - // and it's annoying to have warnings about them each time, so - // ignroe them silently if they are not used for env vars - // - // under Unix, OTOH, this warning could be useful for the user to - // understand why isn't the variable expanded as intended - #ifndef __WXMSW__ - wxLogWarning(_("Environment variables expansion failed: missing '%c' at position %u in '%s'."), - (char)bracket, (unsigned int) (m + 1), str.c_str()); - #endif // __WXMSW__ - } - else { - // skip closing bracket unless the variables wasn't expanded - if ( pszValue == NULL ) - strResult << (wxChar)bracket; - m++; - } - } - - n = m - 1; // skip variable name - } - break; - - case '\\': - // backslash can be used to suppress special meaning of % and $ - if ( n != str.length() - 1 && - (str[n + 1] == wxT('%') || str[n + 1] == wxT('$')) ) { - strResult += str[++n]; - - break; - } - //else: fall through - - default: - strResult += str[n]; - } - } - - return strResult; -} - -// this function is used to properly interpret '..' in path -void wxSplitPath(wxArrayString& aParts, const wxChar *sz) -{ - aParts.clear(); - - wxString strCurrent; - const wxChar *pc = sz; - for ( ;; ) { - if ( *pc == wxT('\0') || *pc == wxCONFIG_PATH_SEPARATOR ) { - if ( strCurrent == wxT(".") ) { - // ignore - } - else if ( strCurrent == wxT("..") ) { - // go up one level - if ( aParts.size() == 0 ) - wxLogWarning(_("'%s' has extra '..', ignored."), sz); - else - aParts.erase(aParts.end() - 1); - - strCurrent.Empty(); - } - else if ( !strCurrent.empty() ) { - aParts.push_back(strCurrent); - strCurrent.Empty(); - } - //else: - // could log an error here, but we prefer to ignore extra '/' - - if ( *pc == wxT('\0') ) - break; - } - else - strCurrent += *pc; - - pc++; - } -} +/////////////////////////////////////////////////////////////////////////////// +// Name: src/common/config.cpp +// Purpose: implementation of wxConfigBase class +// Author: Vadim Zeitlin +// Modified by: +// Created: 07.04.98 +// RCS-ID: $Id: config.cpp 50711 2007-12-15 02:57:58Z VZ $ +// Copyright: (c) 1997 Karsten Ballueder Ballueder@usa.net +// Vadim Zeitlin +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif //__BORLANDC__ + +#ifndef wxUSE_CONFIG_NATIVE + #define wxUSE_CONFIG_NATIVE 1 +#endif + +#include "wx/config.h" + +#ifndef WX_PRECOMP + #include "wx/intl.h" + #include "wx/log.h" + #include "wx/app.h" + #include "wx/utils.h" + #include "wx/arrstr.h" + #include "wx/math.h" +#endif //WX_PRECOMP + +#if wxUSE_CONFIG && ((wxUSE_FILE && wxUSE_TEXTFILE) || wxUSE_CONFIG_NATIVE) + +#include "wx/file.h" + +#include +#include +#include // for INT_MAX + +// ---------------------------------------------------------------------------- +// global and class static variables +// ---------------------------------------------------------------------------- + +wxConfigBase *wxConfigBase::ms_pConfig = NULL; +bool wxConfigBase::ms_bAutoCreate = true; + +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// wxConfigBase +// ---------------------------------------------------------------------------- + +// Not all args will always be used by derived classes, but including them all +// in each class ensures compatibility. +wxConfigBase::wxConfigBase(const wxString& appName, + const wxString& vendorName, + const wxString& WXUNUSED(localFilename), + const wxString& WXUNUSED(globalFilename), + long style) + : m_appName(appName), m_vendorName(vendorName), m_style(style) +{ + m_bExpandEnvVars = true; + m_bRecordDefaults = false; +} + +wxConfigBase::~wxConfigBase() +{ + // required here for Darwin +} + +wxConfigBase *wxConfigBase::Set(wxConfigBase *pConfig) +{ + wxConfigBase *pOld = ms_pConfig; + ms_pConfig = pConfig; + return pOld; +} + +wxConfigBase *wxConfigBase::Create() +{ + if ( ms_bAutoCreate && ms_pConfig == NULL ) { + ms_pConfig = + #if defined(__WXMSW__) && wxUSE_CONFIG_NATIVE + new wxRegConfig(wxTheApp->GetAppName(), wxTheApp->GetVendorName()); + #elif defined(__WXPALMOS__) && wxUSE_CONFIG_NATIVE + new wxPrefConfig(wxTheApp->GetAppName()); + #else // either we're under Unix or wish to use files even under Windows + new wxFileConfig(wxTheApp->GetAppName()); + #endif + } + + return ms_pConfig; +} + +// ---------------------------------------------------------------------------- +// wxConfigBase reading entries +// ---------------------------------------------------------------------------- + +// implement both Read() overloads for the given type in terms of DoRead() +#define IMPLEMENT_READ_FOR_TYPE(name, type, deftype, extra) \ + bool wxConfigBase::Read(const wxString& key, type *val) const \ + { \ + wxCHECK_MSG( val, false, _T("wxConfig::Read(): NULL parameter") ); \ + \ + if ( !DoRead##name(key, val) ) \ + return false; \ + \ + *val = extra(*val); \ + \ + return true; \ + } \ + \ + bool wxConfigBase::Read(const wxString& key, \ + type *val, \ + deftype defVal) const \ + { \ + wxCHECK_MSG( val, false, _T("wxConfig::Read(): NULL parameter") ); \ + \ + bool read = DoRead##name(key, val); \ + if ( !read ) \ + { \ + if ( IsRecordingDefaults() ) \ + { \ + ((wxConfigBase *)this)->DoWrite##name(key, defVal); \ + } \ + \ + *val = defVal; \ + } \ + \ + *val = extra(*val); \ + \ + return read; \ + } + + +IMPLEMENT_READ_FOR_TYPE(String, wxString, const wxString&, ExpandEnvVars) +IMPLEMENT_READ_FOR_TYPE(Long, long, long, long) +IMPLEMENT_READ_FOR_TYPE(Int, int, int, int) +IMPLEMENT_READ_FOR_TYPE(Double, double, double, double) +IMPLEMENT_READ_FOR_TYPE(Bool, bool, bool, bool) + +#undef IMPLEMENT_READ_FOR_TYPE + +// the DoReadXXX() for the other types have implementation in the base class +// but can be overridden in the derived ones +bool wxConfigBase::DoReadInt(const wxString& key, int *pi) const +{ + wxCHECK_MSG( pi, false, _T("wxConfig::Read(): NULL parameter") ); + + long l; + if ( !DoReadLong(key, &l) ) + return false; + + wxASSERT_MSG( l < INT_MAX, _T("overflow in wxConfig::DoReadInt") ); + + *pi = (int)l; + + return true; +} + +bool wxConfigBase::DoReadBool(const wxString& key, bool* val) const +{ + wxCHECK_MSG( val, false, _T("wxConfig::Read(): NULL parameter") ); + + long l; + if ( !DoReadLong(key, &l) ) + return false; + + wxASSERT_MSG( l == 0 || l == 1, _T("bad bool value in wxConfig::DoReadInt") ); + + *val = l != 0; + + return true; +} + +bool wxConfigBase::DoReadDouble(const wxString& key, double* val) const +{ + wxString str; + if ( Read(key, &str) ) + { + return str.ToDouble(val); + } + + return false; +} + +// string reading helper +wxString wxConfigBase::ExpandEnvVars(const wxString& str) const +{ + wxString tmp; // Required for BC++ + if (IsExpandingEnvVars()) + tmp = wxExpandEnvVars(str); + else + tmp = str; + return tmp; +} + +// ---------------------------------------------------------------------------- +// wxConfigBase writing +// ---------------------------------------------------------------------------- + +bool wxConfigBase::DoWriteDouble(const wxString& key, double val) +{ + return DoWriteString(key, wxString::Format(_T("%g"), val)); +} + +bool wxConfigBase::DoWriteInt(const wxString& key, int value) +{ + return DoWriteLong(key, (long)value); +} + +bool wxConfigBase::DoWriteBool(const wxString& key, bool value) +{ + return DoWriteLong(key, value ? 1l : 0l); +} + +// ---------------------------------------------------------------------------- +// wxConfigPathChanger +// ---------------------------------------------------------------------------- + +wxConfigPathChanger::wxConfigPathChanger(const wxConfigBase *pContainer, + const wxString& strEntry) +{ + m_bChanged = false; + m_pContainer = (wxConfigBase *)pContainer; + + // the path is everything which precedes the last slash + wxString strPath = strEntry.BeforeLast(wxCONFIG_PATH_SEPARATOR); + + // except in the special case of "/keyname" when there is nothing before "/" + if ( strPath.empty() && + ((!strEntry.empty()) && strEntry[0] == wxCONFIG_PATH_SEPARATOR) ) + { + strPath = wxCONFIG_PATH_SEPARATOR; + } + + if ( !strPath.empty() ) + { + if ( m_pContainer->GetPath() != strPath ) + { + // we do change the path so restore it later + m_bChanged = true; + + /* JACS: work around a memory bug that causes an assert + when using wxRegConfig, related to reference-counting. + Can be reproduced by removing (const wxChar*) below and + adding the following code to the config sample OnInit under + Windows: + + pConfig->SetPath(wxT("MySettings")); + pConfig->SetPath(wxT("..")); + int value; + pConfig->Read(_T("MainWindowX"), & value); + */ + m_strOldPath = (const wxChar*) m_pContainer->GetPath(); + if ( *m_strOldPath.c_str() != wxCONFIG_PATH_SEPARATOR ) + m_strOldPath += wxCONFIG_PATH_SEPARATOR; + m_pContainer->SetPath(strPath); + } + + // in any case, use the just the name, not full path + m_strName = strEntry.AfterLast(wxCONFIG_PATH_SEPARATOR); + } + else { + // it's a name only, without path - nothing to do + m_strName = strEntry; + } +} + +void wxConfigPathChanger::UpdateIfDeleted() +{ + // we don't have to do anything at all if we didn't change the path + if ( !m_bChanged ) + return; + + // find the deepest still existing parent path of the original path + while ( !m_pContainer->HasGroup(m_strOldPath) ) + { + m_strOldPath = m_strOldPath.BeforeLast(wxCONFIG_PATH_SEPARATOR); + if ( m_strOldPath.empty() ) + m_strOldPath = wxCONFIG_PATH_SEPARATOR; + } +} + +wxConfigPathChanger::~wxConfigPathChanger() +{ + // only restore path if it was changed + if ( m_bChanged ) { + m_pContainer->SetPath(m_strOldPath); + } +} + +// this is a wxConfig method but it's mainly used with wxConfigPathChanger +/* static */ +wxString wxConfigBase::RemoveTrailingSeparator(const wxString& key) +{ + wxString path(key); + + // don't remove the only separator from a root group path! + while ( path.length() > 1 ) + { + if ( *path.rbegin() != wxCONFIG_PATH_SEPARATOR ) + break; + + path.erase(path.end() - 1); + } + + return path; +} + +#endif // wxUSE_CONFIG + +// ---------------------------------------------------------------------------- +// static & global functions +// ---------------------------------------------------------------------------- + +// understands both Unix and Windows (but only under Windows) environment +// variables expansion: i.e. $var, $(var) and ${var} are always understood +// and in addition under Windows %var% is also. + +// don't change the values the enum elements: they must be equal +// to the matching [closing] delimiter. +enum Bracket +{ + Bracket_None, + Bracket_Normal = ')', + Bracket_Curly = '}', +#ifdef __WXMSW__ + Bracket_Windows = '%', // yeah, Windows people are a bit strange ;-) +#endif + Bracket_Max +}; + +wxString wxExpandEnvVars(const wxString& str) +{ + wxString strResult; + strResult.Alloc(str.length()); + + size_t m; + for ( size_t n = 0; n < str.length(); n++ ) { + switch ( str[n] ) { +#ifdef __WXMSW__ + case wxT('%'): +#endif //WINDOWS + case wxT('$'): + { + Bracket bracket; + #ifdef __WXMSW__ + if ( str[n] == wxT('%') ) + bracket = Bracket_Windows; + else + #endif //WINDOWS + if ( n == str.length() - 1 ) { + bracket = Bracket_None; + } + else { + switch ( str[n + 1] ) { + case wxT('('): + bracket = Bracket_Normal; + n++; // skip the bracket + break; + + case wxT('{'): + bracket = Bracket_Curly; + n++; // skip the bracket + break; + + default: + bracket = Bracket_None; + } + } + + m = n + 1; + + while ( m < str.length() && (wxIsalnum(str[m]) || str[m] == wxT('_')) ) + m++; + + wxString strVarName(str.c_str() + n + 1, m - n - 1); + +#ifdef __WXWINCE__ + const wxChar *pszValue = NULL; +#else + // NB: use wxGetEnv instead of wxGetenv as otherwise variables + // set through wxSetEnv may not be read correctly! + const wxChar *pszValue = NULL; + wxString tmp; + if (wxGetEnv(strVarName, &tmp)) + pszValue = tmp; +#endif + if ( pszValue != NULL ) { + strResult += pszValue; + } + else { + // variable doesn't exist => don't change anything + #ifdef __WXMSW__ + if ( bracket != Bracket_Windows ) + #endif + if ( bracket != Bracket_None ) + strResult << str[n - 1]; + strResult << str[n] << strVarName; + } + + // check the closing bracket + if ( bracket != Bracket_None ) { + if ( m == str.length() || str[m] != (wxChar)bracket ) { + // under MSW it's common to have '%' characters in the registry + // and it's annoying to have warnings about them each time, so + // ignroe them silently if they are not used for env vars + // + // under Unix, OTOH, this warning could be useful for the user to + // understand why isn't the variable expanded as intended + #ifndef __WXMSW__ + wxLogWarning(_("Environment variables expansion failed: missing '%c' at position %u in '%s'."), + (char)bracket, (unsigned int) (m + 1), str.c_str()); + #endif // __WXMSW__ + } + else { + // skip closing bracket unless the variables wasn't expanded + if ( pszValue == NULL ) + strResult << (wxChar)bracket; + m++; + } + } + + n = m - 1; // skip variable name + } + break; + + case '\\': + // backslash can be used to suppress special meaning of % and $ + if ( n != str.length() - 1 && + (str[n + 1] == wxT('%') || str[n + 1] == wxT('$')) ) { + strResult += str[++n]; + + break; + } + //else: fall through + + default: + strResult += str[n]; + } + } + + return strResult; +} + +// this function is used to properly interpret '..' in path +void wxSplitPath(wxArrayString& aParts, const wxChar *sz) +{ + aParts.clear(); + + wxString strCurrent; + const wxChar *pc = sz; + for ( ;; ) { + if ( *pc == wxT('\0') || *pc == wxCONFIG_PATH_SEPARATOR ) { + if ( strCurrent == wxT(".") ) { + // ignore + } + else if ( strCurrent == wxT("..") ) { + // go up one level + if ( aParts.size() == 0 ) + wxLogWarning(_("'%s' has extra '..', ignored."), sz); + else + aParts.erase(aParts.end() - 1); + + strCurrent.Empty(); + } + else if ( !strCurrent.empty() ) { + aParts.push_back(strCurrent); + strCurrent.Empty(); + } + //else: + // could log an error here, but we prefer to ignore extra '/' + + if ( *pc == wxT('\0') ) + break; + } + else + strCurrent += *pc; + + pc++; + } +} diff --git a/Externals/wxWidgets/src/common/containr.cpp b/Externals/wxWidgets/src/common/containr.cpp index 275ffb5747..ffa9ce975d 100644 --- a/Externals/wxWidgets/src/common/containr.cpp +++ b/Externals/wxWidgets/src/common/containr.cpp @@ -1,678 +1,678 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: src/common/containr.cpp -// Purpose: implementation of wxControlContainer -// Author: Vadim Zeitlin -// Modified by: -// Created: 06.08.01 -// RCS-ID: $Id: containr.cpp 44273 2007-01-21 01:21:45Z VZ $ -// Copyright: (c) 2001 Vadim Zeitlin -// License: wxWindows licence -/////////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#ifndef WX_PRECOMP - #include "wx/log.h" - #include "wx/event.h" - #include "wx/window.h" - #include "wx/scrolbar.h" - #include "wx/radiobut.h" - #include "wx/containr.h" -#endif //WX_PRECOMP - -// trace mask for focus messages -#define TRACE_FOCUS _T("focus") - -// ============================================================================ -// implementation -// ============================================================================ - -wxControlContainer::wxControlContainer(wxWindow *winParent) -{ - m_winParent = winParent; - m_winLastFocused = NULL; - m_inSetFocus = false; -} - -bool wxControlContainer::AcceptsFocus() const -{ - // if we're not shown or disabled, we can't accept focus - if ( m_winParent->IsShown() && m_winParent->IsEnabled() ) - { - // otherwise we can accept focus either if we have no children at all - // (in this case we're probably not used as a container) or only when - // at least one child will accept focus - wxWindowList::compatibility_iterator node = m_winParent->GetChildren().GetFirst(); - if ( !node ) - return true; - -#ifdef __WXMAC__ - // wxMac has eventually the two scrollbars as children, they don't count - // as real children in the algorithm mentioned above - bool hasRealChildren = false ; -#endif - - while ( node ) - { - wxWindow *child = node->GetData(); - node = node->GetNext(); - -#ifdef __WXMAC__ - if ( m_winParent->MacIsWindowScrollbar( child ) ) - continue; - hasRealChildren = true ; -#endif - if ( child->AcceptsFocus() ) - { - return true; - } - } - -#ifdef __WXMAC__ - if ( !hasRealChildren ) - return true ; -#endif - } - - return false; -} - -void wxControlContainer::SetLastFocus(wxWindow *win) -{ - // the panel itself should never get the focus at all but if it does happen - // temporarily (as it seems to do under wxGTK), at the very least don't - // forget our previous m_winLastFocused - if ( win != m_winParent ) - { - // if we're setting the focus - if ( win ) - { - // find the last _immediate_ child which got focus - wxWindow *winParent = win; - while ( winParent != m_winParent ) - { - win = winParent; - winParent = win->GetParent(); - - // Yes, this can happen, though in a totally pathological case. - // like when detaching a menubar from a frame with a child - // which has pushed itself as an event handler for the menubar. - // (under wxGTK) - - wxASSERT_MSG( winParent, - _T("Setting last focus for a window that is not our child?") ); - } - } - - m_winLastFocused = win; - - if ( win ) - { - wxLogTrace(TRACE_FOCUS, _T("Set last focus to %s(%s)"), - win->GetClassInfo()->GetClassName(), - win->GetLabel().c_str()); - } - else - { - wxLogTrace(TRACE_FOCUS, _T("No more last focus")); - } - } - - // propagate the last focus upwards so that our parent can set focus back - // to us if it loses it now and regains later - wxWindow *parent = m_winParent->GetParent(); - if ( parent ) - { - wxChildFocusEvent eventFocus(m_winParent); - parent->GetEventHandler()->ProcessEvent(eventFocus); - } -} - -// -------------------------------------------------------------------- -// The following four functions are used to find other radio buttons -// within the same group. Used by wxSetFocusToChild on wxMSW -// -------------------------------------------------------------------- - -#ifdef __WXMSW__ - -wxRadioButton* wxGetPreviousButtonInGroup(wxRadioButton *btn) -{ - if ( btn->HasFlag(wxRB_GROUP) || btn->HasFlag(wxRB_SINGLE) ) - return NULL; - - const wxWindowList& siblings = btn->GetParent()->GetChildren(); - wxWindowList::compatibility_iterator nodeThis = siblings.Find(btn); - wxCHECK_MSG( nodeThis, NULL, _T("radio button not a child of its parent?") ); - - // Iterate over all previous siblings until we find the next radio button - wxWindowList::compatibility_iterator nodeBefore = nodeThis->GetPrevious(); - wxRadioButton *prevBtn = 0; - while (nodeBefore) - { - prevBtn = wxDynamicCast(nodeBefore->GetData(), wxRadioButton); - if (prevBtn) - break; - - nodeBefore = nodeBefore->GetPrevious(); - } - - if (!prevBtn || prevBtn->HasFlag(wxRB_SINGLE)) - { - // no more buttons in group - return NULL; - } - - return prevBtn; -} - -wxRadioButton* wxGetNextButtonInGroup(wxRadioButton *btn) -{ - if (btn->HasFlag(wxRB_SINGLE)) - return NULL; - - const wxWindowList& siblings = btn->GetParent()->GetChildren(); - wxWindowList::compatibility_iterator nodeThis = siblings.Find(btn); - wxCHECK_MSG( nodeThis, NULL, _T("radio button not a child of its parent?") ); - - // Iterate over all previous siblings until we find the next radio button - wxWindowList::compatibility_iterator nodeNext = nodeThis->GetNext(); - wxRadioButton *nextBtn = 0; - while (nodeNext) - { - nextBtn = wxDynamicCast(nodeNext->GetData(), wxRadioButton); - if (nextBtn) - break; - - nodeNext = nodeNext->GetNext(); - } - - if ( !nextBtn || nextBtn->HasFlag(wxRB_GROUP) || nextBtn->HasFlag(wxRB_SINGLE) ) - { - // no more buttons or the first button of the next group - return NULL; - } - - return nextBtn; -} - -wxRadioButton* wxGetFirstButtonInGroup(wxRadioButton *btn) -{ - while (true) - { - wxRadioButton* prevBtn = wxGetPreviousButtonInGroup(btn); - if (!prevBtn) - return btn; - - btn = prevBtn; - } -} - -wxRadioButton* wxGetLastButtonInGroup(wxRadioButton *btn) -{ - while (true) - { - wxRadioButton* nextBtn = wxGetNextButtonInGroup(btn); - if (!nextBtn) - return btn; - - btn = nextBtn; - } -} - -wxRadioButton* wxGetSelectedButtonInGroup(wxRadioButton *btn) -{ - // Find currently selected button - if (btn->GetValue()) - return btn; - - if (btn->HasFlag(wxRB_SINGLE)) - return NULL; - - wxRadioButton *selBtn; - - // First check all previous buttons - for (selBtn = wxGetPreviousButtonInGroup(btn); selBtn; selBtn = wxGetPreviousButtonInGroup(selBtn)) - if (selBtn->GetValue()) - return selBtn; - - // Now all following buttons - for (selBtn = wxGetNextButtonInGroup(btn); selBtn; selBtn = wxGetNextButtonInGroup(selBtn)) - if (selBtn->GetValue()) - return selBtn; - - return NULL; -} - -#endif // __WXMSW__ - -// ---------------------------------------------------------------------------- -// Keyboard handling - this is the place where the TAB traversal logic is -// implemented. As this code is common to all ports, this ensures consistent -// behaviour even if we don't specify how exactly the wxNavigationKeyEvent are -// generated and this is done in platform specific code which also ensures that -// we can follow the given platform standards. -// ---------------------------------------------------------------------------- - -void wxControlContainer::HandleOnNavigationKey( wxNavigationKeyEvent& event ) -{ - wxWindow *parent = m_winParent->GetParent(); - - // the event is propagated downwards if the event emitter was our parent - bool goingDown = event.GetEventObject() == parent; - - const wxWindowList& children = m_winParent->GetChildren(); - - // if we have exactly one notebook-like child window (actually it could be - // any window that returns true from its HasMultiplePages()), then - // [Shift-]Ctrl-Tab and Ctrl-PageUp/Down keys should iterate over its pages - // even if the focus is outside of the control because this is how the - // standard MSW properties dialogs behave and we do it under other platforms - // as well because it seems like a good idea -- but we can always put this - // block inside "#ifdef __WXMSW__" if it's not suitable there - if ( event.IsWindowChange() && !goingDown ) - { - // check if we have a unique notebook-like child - wxWindow *bookctrl = NULL; - for ( wxWindowList::const_iterator i = children.begin(), - end = children.end(); - i != end; - ++i ) - { - wxWindow * const window = *i; - if ( window->HasMultiplePages() ) - { - if ( bookctrl ) - { - // this is the second book-like control already so don't do - // anything as we don't know which one should have its page - // changed - bookctrl = NULL; - break; - } - - bookctrl = window; - } - } - - if ( bookctrl ) - { - // make sure that we don't bubble up the event again from the book - // control resulting in infinite recursion - wxNavigationKeyEvent eventCopy(event); - eventCopy.SetEventObject(m_winParent); - if ( bookctrl->GetEventHandler()->ProcessEvent(eventCopy) ) - return; - } - } - - // there is not much to do if we don't have children and we're not - // interested in "notebook page change" events here - if ( !children.GetCount() || event.IsWindowChange() ) - { - // let the parent process it unless it already comes from our parent - // of we don't have any - if ( goingDown || - !parent || !parent->GetEventHandler()->ProcessEvent(event) ) - { - event.Skip(); - } - - return; - } - - // where are we going? - const bool forward = event.GetDirection(); - - // the node of the children list from which we should start looking for the - // next acceptable child - wxWindowList::compatibility_iterator node, start_node; - - // we should start from the first/last control and not from the one which - // had focus the last time if we're propagating the event downwards because - // for our parent we look like a single control - if ( goingDown ) - { - // just to be sure it's not used (normally this is not necessary, but - // doesn't hurt neither) - m_winLastFocused = (wxWindow *)NULL; - - // start from first or last depending on where we're going - node = forward ? children.GetFirst() : children.GetLast(); - } - else // going up - { - // try to find the child which has the focus currently - - // the event emitter might have done this for us - wxWindow *winFocus = event.GetCurrentFocus(); - - // but if not, we might know where the focus was ourselves - if (!winFocus) - winFocus = m_winLastFocused; - - // if still no luck, do it the hard way - if (!winFocus) - winFocus = wxWindow::FindFocus(); - - if ( winFocus ) - { -#ifdef __WXMSW__ - // If we are in a radio button group, start from the first item in the - // group - if ( event.IsFromTab() && wxIsKindOf(winFocus, wxRadioButton ) ) - winFocus = wxGetFirstButtonInGroup((wxRadioButton*)winFocus); -#endif - // ok, we found the focus - now is it our child? - start_node = children.Find( winFocus ); - } - - if ( !start_node && m_winLastFocused ) - { - // window which has focus isn't our child, fall back to the one - // which had the focus the last time - start_node = children.Find( m_winLastFocused ); - } - - // if we still didn't find anything, we should start with the first one - if ( !start_node ) - { - start_node = children.GetFirst(); - } - - // and the first child which we can try setting focus to is the next or - // the previous one - node = forward ? start_node->GetNext() : start_node->GetPrevious(); - } - - // we want to cycle over all elements passing by NULL - for ( ;; ) - { - // don't go into infinite loop - if ( start_node && node && node == start_node ) - break; - - // Have we come to the last or first item on the panel? - if ( !node ) - { - if ( !start_node ) - { - // exit now as otherwise we'd loop forever - break; - } - - if ( !goingDown ) - { - // Check if our (maybe grand) parent is another panel: if this - // is the case, they will know what to do with this navigation - // key and so give them the chance to process it instead of - // looping inside this panel (normally, the focus will go to - // the next/previous item after this panel in the parent - // panel). - wxWindow *focussed_child_of_parent = m_winParent; - while ( parent ) - { - // we don't want to tab into a different dialog or frame - if ( focussed_child_of_parent->IsTopLevel() ) - break; - - event.SetCurrentFocus( focussed_child_of_parent ); - if ( parent->GetEventHandler()->ProcessEvent( event ) ) - return; - - focussed_child_of_parent = parent; - - parent = parent->GetParent(); - } - } - //else: as the focus came from our parent, we definitely don't want - // to send it back to it! - - // no, we are not inside another panel so process this ourself - node = forward ? children.GetFirst() : children.GetLast(); - - continue; - } - - wxWindow *child = node->GetData(); - -#ifdef __WXMSW__ - if ( event.IsFromTab() ) - { - if ( wxIsKindOf(child, wxRadioButton) ) - { - // only radio buttons with either wxRB_GROUP or wxRB_SINGLE - // can be tabbed to - if ( child->HasFlag(wxRB_GROUP) ) - { - // need to tab into the active button within a group - wxRadioButton *rb = wxGetSelectedButtonInGroup((wxRadioButton*)child); - if ( rb ) - child = rb; - } - else if ( !child->HasFlag(wxRB_SINGLE) ) - { - node = forward ? node->GetNext() : node->GetPrevious(); - continue; - } - } - } - else if ( m_winLastFocused && - wxIsKindOf(m_winLastFocused, wxRadioButton) && - !m_winLastFocused->HasFlag(wxRB_SINGLE) ) - { - // cursor keys don't navigate out of a radio button group so - // find the correct radio button to focus - if ( forward ) - { - child = wxGetNextButtonInGroup((wxRadioButton*)m_winLastFocused); - if ( !child ) - { - // no next button in group, set it to the first button - child = wxGetFirstButtonInGroup((wxRadioButton*)m_winLastFocused); - } - } - else - { - child = wxGetPreviousButtonInGroup((wxRadioButton*)m_winLastFocused); - if ( !child ) - { - // no previous button in group, set it to the last button - child = wxGetLastButtonInGroup((wxRadioButton*)m_winLastFocused); - } - } - - if ( child == m_winLastFocused ) - { - // must be a group consisting of only one button therefore - // no need to send a navigation event - event.Skip(false); - return; - } - } -#endif // __WXMSW__ - - if ( child->AcceptsFocusFromKeyboard() ) - { - // if we're setting the focus to a child panel we should prevent it - // from giving it to the child which had the focus the last time - // and instead give it to the first/last child depending from which - // direction we're coming - event.SetEventObject(m_winParent); - - // disable propagation for this call as otherwise the event might - // bounce back to us. - wxPropagationDisabler disableProp(event); - if ( !child->GetEventHandler()->ProcessEvent(event) ) - { - // set it first in case SetFocusFromKbd() results in focus - // change too - m_winLastFocused = child; - - // everything is simple: just give focus to it - child->SetFocusFromKbd(); - } - //else: the child manages its focus itself - - event.Skip( false ); - - return; - } - - node = forward ? node->GetNext() : node->GetPrevious(); - } - - // we cycled through all of our children and none of them wanted to accept - // focus - event.Skip(); -} - -void wxControlContainer::HandleOnWindowDestroy(wxWindowBase *child) -{ - if ( child == m_winLastFocused ) - m_winLastFocused = NULL; -} - -// ---------------------------------------------------------------------------- -// focus handling -// ---------------------------------------------------------------------------- - -bool wxControlContainer::DoSetFocus() -{ - wxLogTrace(TRACE_FOCUS, _T("SetFocus on wxPanel 0x%p."), - m_winParent->GetHandle()); - - if (m_inSetFocus) - return true; - - // when the panel gets the focus we move the focus to either the last - // window that had the focus or the first one that can get it unless the - // focus had been already set to some other child - - wxWindow *win = wxWindow::FindFocus(); - while ( win ) - { - if ( win == m_winParent ) - { - // our child already has focus, don't take it away from it - return true; - } - - if ( win->IsTopLevel() ) - { - // don't look beyond the first top level parent - useless and - // unnecessary - break; - } - - win = win->GetParent(); - } - - // protect against infinite recursion: - m_inSetFocus = true; - - bool ret = SetFocusToChild(); - - m_inSetFocus = false; - - return ret; -} - -void wxControlContainer::HandleOnFocus(wxFocusEvent& event) -{ - wxLogTrace(TRACE_FOCUS, _T("OnFocus on wxPanel 0x%p, name: %s"), - m_winParent->GetHandle(), - m_winParent->GetName().c_str() ); - - DoSetFocus(); - - event.Skip(); -} - -bool wxControlContainer::SetFocusToChild() -{ - return wxSetFocusToChild(m_winParent, &m_winLastFocused); -} - -// ---------------------------------------------------------------------------- -// SetFocusToChild(): this function is used by wxPanel but also by wxFrame in -// wxMSW, this is why it is outside of wxControlContainer class -// ---------------------------------------------------------------------------- - -bool wxSetFocusToChild(wxWindow *win, wxWindow **childLastFocused) -{ - wxCHECK_MSG( win, false, _T("wxSetFocusToChild(): invalid window") ); - wxCHECK_MSG( childLastFocused, false, - _T("wxSetFocusToChild(): NULL child poonter") ); - - if ( *childLastFocused ) - { - // It might happen that the window got reparented - if ( (*childLastFocused)->GetParent() == win ) - { - wxLogTrace(TRACE_FOCUS, - _T("SetFocusToChild() => last child (0x%p)."), - (*childLastFocused)->GetHandle()); - - // not SetFocusFromKbd(): we're restoring focus back to the old - // window and not setting it as the result of a kbd action - (*childLastFocused)->SetFocus(); - return true; - } - else - { - // it doesn't count as such any more - *childLastFocused = (wxWindow *)NULL; - } - } - - // set the focus to the first child who wants it - wxWindowList::compatibility_iterator node = win->GetChildren().GetFirst(); - while ( node ) - { - wxWindow *child = node->GetData(); - node = node->GetNext(); - -#ifdef __WXMAC__ - if ( child->GetParent()->MacIsWindowScrollbar( child ) ) - continue; -#endif - - if ( child->AcceptsFocusFromKeyboard() && !child->IsTopLevel() ) - { -#ifdef __WXMSW__ - // If a radiobutton is the first focusable child, search for the - // selected radiobutton in the same group - wxRadioButton* btn = wxDynamicCast(child, wxRadioButton); - if (btn) - { - wxRadioButton* selected = wxGetSelectedButtonInGroup(btn); - if (selected) - child = selected; - } -#endif - - wxLogTrace(TRACE_FOCUS, - _T("SetFocusToChild() => first child (0x%p)."), - child->GetHandle()); - - *childLastFocused = child; - child->SetFocusFromKbd(); - return true; - } - } - - return false; -} +/////////////////////////////////////////////////////////////////////////////// +// Name: src/common/containr.cpp +// Purpose: implementation of wxControlContainer +// Author: Vadim Zeitlin +// Modified by: +// Created: 06.08.01 +// RCS-ID: $Id: containr.cpp 44273 2007-01-21 01:21:45Z VZ $ +// Copyright: (c) 2001 Vadim Zeitlin +// License: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#ifndef WX_PRECOMP + #include "wx/log.h" + #include "wx/event.h" + #include "wx/window.h" + #include "wx/scrolbar.h" + #include "wx/radiobut.h" + #include "wx/containr.h" +#endif //WX_PRECOMP + +// trace mask for focus messages +#define TRACE_FOCUS _T("focus") + +// ============================================================================ +// implementation +// ============================================================================ + +wxControlContainer::wxControlContainer(wxWindow *winParent) +{ + m_winParent = winParent; + m_winLastFocused = NULL; + m_inSetFocus = false; +} + +bool wxControlContainer::AcceptsFocus() const +{ + // if we're not shown or disabled, we can't accept focus + if ( m_winParent->IsShown() && m_winParent->IsEnabled() ) + { + // otherwise we can accept focus either if we have no children at all + // (in this case we're probably not used as a container) or only when + // at least one child will accept focus + wxWindowList::compatibility_iterator node = m_winParent->GetChildren().GetFirst(); + if ( !node ) + return true; + +#ifdef __WXMAC__ + // wxMac has eventually the two scrollbars as children, they don't count + // as real children in the algorithm mentioned above + bool hasRealChildren = false ; +#endif + + while ( node ) + { + wxWindow *child = node->GetData(); + node = node->GetNext(); + +#ifdef __WXMAC__ + if ( m_winParent->MacIsWindowScrollbar( child ) ) + continue; + hasRealChildren = true ; +#endif + if ( child->AcceptsFocus() ) + { + return true; + } + } + +#ifdef __WXMAC__ + if ( !hasRealChildren ) + return true ; +#endif + } + + return false; +} + +void wxControlContainer::SetLastFocus(wxWindow *win) +{ + // the panel itself should never get the focus at all but if it does happen + // temporarily (as it seems to do under wxGTK), at the very least don't + // forget our previous m_winLastFocused + if ( win != m_winParent ) + { + // if we're setting the focus + if ( win ) + { + // find the last _immediate_ child which got focus + wxWindow *winParent = win; + while ( winParent != m_winParent ) + { + win = winParent; + winParent = win->GetParent(); + + // Yes, this can happen, though in a totally pathological case. + // like when detaching a menubar from a frame with a child + // which has pushed itself as an event handler for the menubar. + // (under wxGTK) + + wxASSERT_MSG( winParent, + _T("Setting last focus for a window that is not our child?") ); + } + } + + m_winLastFocused = win; + + if ( win ) + { + wxLogTrace(TRACE_FOCUS, _T("Set last focus to %s(%s)"), + win->GetClassInfo()->GetClassName(), + win->GetLabel().c_str()); + } + else + { + wxLogTrace(TRACE_FOCUS, _T("No more last focus")); + } + } + + // propagate the last focus upwards so that our parent can set focus back + // to us if it loses it now and regains later + wxWindow *parent = m_winParent->GetParent(); + if ( parent ) + { + wxChildFocusEvent eventFocus(m_winParent); + parent->GetEventHandler()->ProcessEvent(eventFocus); + } +} + +// -------------------------------------------------------------------- +// The following four functions are used to find other radio buttons +// within the same group. Used by wxSetFocusToChild on wxMSW +// -------------------------------------------------------------------- + +#ifdef __WXMSW__ + +wxRadioButton* wxGetPreviousButtonInGroup(wxRadioButton *btn) +{ + if ( btn->HasFlag(wxRB_GROUP) || btn->HasFlag(wxRB_SINGLE) ) + return NULL; + + const wxWindowList& siblings = btn->GetParent()->GetChildren(); + wxWindowList::compatibility_iterator nodeThis = siblings.Find(btn); + wxCHECK_MSG( nodeThis, NULL, _T("radio button not a child of its parent?") ); + + // Iterate over all previous siblings until we find the next radio button + wxWindowList::compatibility_iterator nodeBefore = nodeThis->GetPrevious(); + wxRadioButton *prevBtn = 0; + while (nodeBefore) + { + prevBtn = wxDynamicCast(nodeBefore->GetData(), wxRadioButton); + if (prevBtn) + break; + + nodeBefore = nodeBefore->GetPrevious(); + } + + if (!prevBtn || prevBtn->HasFlag(wxRB_SINGLE)) + { + // no more buttons in group + return NULL; + } + + return prevBtn; +} + +wxRadioButton* wxGetNextButtonInGroup(wxRadioButton *btn) +{ + if (btn->HasFlag(wxRB_SINGLE)) + return NULL; + + const wxWindowList& siblings = btn->GetParent()->GetChildren(); + wxWindowList::compatibility_iterator nodeThis = siblings.Find(btn); + wxCHECK_MSG( nodeThis, NULL, _T("radio button not a child of its parent?") ); + + // Iterate over all previous siblings until we find the next radio button + wxWindowList::compatibility_iterator nodeNext = nodeThis->GetNext(); + wxRadioButton *nextBtn = 0; + while (nodeNext) + { + nextBtn = wxDynamicCast(nodeNext->GetData(), wxRadioButton); + if (nextBtn) + break; + + nodeNext = nodeNext->GetNext(); + } + + if ( !nextBtn || nextBtn->HasFlag(wxRB_GROUP) || nextBtn->HasFlag(wxRB_SINGLE) ) + { + // no more buttons or the first button of the next group + return NULL; + } + + return nextBtn; +} + +wxRadioButton* wxGetFirstButtonInGroup(wxRadioButton *btn) +{ + while (true) + { + wxRadioButton* prevBtn = wxGetPreviousButtonInGroup(btn); + if (!prevBtn) + return btn; + + btn = prevBtn; + } +} + +wxRadioButton* wxGetLastButtonInGroup(wxRadioButton *btn) +{ + while (true) + { + wxRadioButton* nextBtn = wxGetNextButtonInGroup(btn); + if (!nextBtn) + return btn; + + btn = nextBtn; + } +} + +wxRadioButton* wxGetSelectedButtonInGroup(wxRadioButton *btn) +{ + // Find currently selected button + if (btn->GetValue()) + return btn; + + if (btn->HasFlag(wxRB_SINGLE)) + return NULL; + + wxRadioButton *selBtn; + + // First check all previous buttons + for (selBtn = wxGetPreviousButtonInGroup(btn); selBtn; selBtn = wxGetPreviousButtonInGroup(selBtn)) + if (selBtn->GetValue()) + return selBtn; + + // Now all following buttons + for (selBtn = wxGetNextButtonInGroup(btn); selBtn; selBtn = wxGetNextButtonInGroup(selBtn)) + if (selBtn->GetValue()) + return selBtn; + + return NULL; +} + +#endif // __WXMSW__ + +// ---------------------------------------------------------------------------- +// Keyboard handling - this is the place where the TAB traversal logic is +// implemented. As this code is common to all ports, this ensures consistent +// behaviour even if we don't specify how exactly the wxNavigationKeyEvent are +// generated and this is done in platform specific code which also ensures that +// we can follow the given platform standards. +// ---------------------------------------------------------------------------- + +void wxControlContainer::HandleOnNavigationKey( wxNavigationKeyEvent& event ) +{ + wxWindow *parent = m_winParent->GetParent(); + + // the event is propagated downwards if the event emitter was our parent + bool goingDown = event.GetEventObject() == parent; + + const wxWindowList& children = m_winParent->GetChildren(); + + // if we have exactly one notebook-like child window (actually it could be + // any window that returns true from its HasMultiplePages()), then + // [Shift-]Ctrl-Tab and Ctrl-PageUp/Down keys should iterate over its pages + // even if the focus is outside of the control because this is how the + // standard MSW properties dialogs behave and we do it under other platforms + // as well because it seems like a good idea -- but we can always put this + // block inside "#ifdef __WXMSW__" if it's not suitable there + if ( event.IsWindowChange() && !goingDown ) + { + // check if we have a unique notebook-like child + wxWindow *bookctrl = NULL; + for ( wxWindowList::const_iterator i = children.begin(), + end = children.end(); + i != end; + ++i ) + { + wxWindow * const window = *i; + if ( window->HasMultiplePages() ) + { + if ( bookctrl ) + { + // this is the second book-like control already so don't do + // anything as we don't know which one should have its page + // changed + bookctrl = NULL; + break; + } + + bookctrl = window; + } + } + + if ( bookctrl ) + { + // make sure that we don't bubble up the event again from the book + // control resulting in infinite recursion + wxNavigationKeyEvent eventCopy(event); + eventCopy.SetEventObject(m_winParent); + if ( bookctrl->GetEventHandler()->ProcessEvent(eventCopy) ) + return; + } + } + + // there is not much to do if we don't have children and we're not + // interested in "notebook page change" events here + if ( !children.GetCount() || event.IsWindowChange() ) + { + // let the parent process it unless it already comes from our parent + // of we don't have any + if ( goingDown || + !parent || !parent->GetEventHandler()->ProcessEvent(event) ) + { + event.Skip(); + } + + return; + } + + // where are we going? + const bool forward = event.GetDirection(); + + // the node of the children list from which we should start looking for the + // next acceptable child + wxWindowList::compatibility_iterator node, start_node; + + // we should start from the first/last control and not from the one which + // had focus the last time if we're propagating the event downwards because + // for our parent we look like a single control + if ( goingDown ) + { + // just to be sure it's not used (normally this is not necessary, but + // doesn't hurt neither) + m_winLastFocused = (wxWindow *)NULL; + + // start from first or last depending on where we're going + node = forward ? children.GetFirst() : children.GetLast(); + } + else // going up + { + // try to find the child which has the focus currently + + // the event emitter might have done this for us + wxWindow *winFocus = event.GetCurrentFocus(); + + // but if not, we might know where the focus was ourselves + if (!winFocus) + winFocus = m_winLastFocused; + + // if still no luck, do it the hard way + if (!winFocus) + winFocus = wxWindow::FindFocus(); + + if ( winFocus ) + { +#ifdef __WXMSW__ + // If we are in a radio button group, start from the first item in the + // group + if ( event.IsFromTab() && wxIsKindOf(winFocus, wxRadioButton ) ) + winFocus = wxGetFirstButtonInGroup((wxRadioButton*)winFocus); +#endif + // ok, we found the focus - now is it our child? + start_node = children.Find( winFocus ); + } + + if ( !start_node && m_winLastFocused ) + { + // window which has focus isn't our child, fall back to the one + // which had the focus the last time + start_node = children.Find( m_winLastFocused ); + } + + // if we still didn't find anything, we should start with the first one + if ( !start_node ) + { + start_node = children.GetFirst(); + } + + // and the first child which we can try setting focus to is the next or + // the previous one + node = forward ? start_node->GetNext() : start_node->GetPrevious(); + } + + // we want to cycle over all elements passing by NULL + for ( ;; ) + { + // don't go into infinite loop + if ( start_node && node && node == start_node ) + break; + + // Have we come to the last or first item on the panel? + if ( !node ) + { + if ( !start_node ) + { + // exit now as otherwise we'd loop forever + break; + } + + if ( !goingDown ) + { + // Check if our (maybe grand) parent is another panel: if this + // is the case, they will know what to do with this navigation + // key and so give them the chance to process it instead of + // looping inside this panel (normally, the focus will go to + // the next/previous item after this panel in the parent + // panel). + wxWindow *focussed_child_of_parent = m_winParent; + while ( parent ) + { + // we don't want to tab into a different dialog or frame + if ( focussed_child_of_parent->IsTopLevel() ) + break; + + event.SetCurrentFocus( focussed_child_of_parent ); + if ( parent->GetEventHandler()->ProcessEvent( event ) ) + return; + + focussed_child_of_parent = parent; + + parent = parent->GetParent(); + } + } + //else: as the focus came from our parent, we definitely don't want + // to send it back to it! + + // no, we are not inside another panel so process this ourself + node = forward ? children.GetFirst() : children.GetLast(); + + continue; + } + + wxWindow *child = node->GetData(); + +#ifdef __WXMSW__ + if ( event.IsFromTab() ) + { + if ( wxIsKindOf(child, wxRadioButton) ) + { + // only radio buttons with either wxRB_GROUP or wxRB_SINGLE + // can be tabbed to + if ( child->HasFlag(wxRB_GROUP) ) + { + // need to tab into the active button within a group + wxRadioButton *rb = wxGetSelectedButtonInGroup((wxRadioButton*)child); + if ( rb ) + child = rb; + } + else if ( !child->HasFlag(wxRB_SINGLE) ) + { + node = forward ? node->GetNext() : node->GetPrevious(); + continue; + } + } + } + else if ( m_winLastFocused && + wxIsKindOf(m_winLastFocused, wxRadioButton) && + !m_winLastFocused->HasFlag(wxRB_SINGLE) ) + { + // cursor keys don't navigate out of a radio button group so + // find the correct radio button to focus + if ( forward ) + { + child = wxGetNextButtonInGroup((wxRadioButton*)m_winLastFocused); + if ( !child ) + { + // no next button in group, set it to the first button + child = wxGetFirstButtonInGroup((wxRadioButton*)m_winLastFocused); + } + } + else + { + child = wxGetPreviousButtonInGroup((wxRadioButton*)m_winLastFocused); + if ( !child ) + { + // no previous button in group, set it to the last button + child = wxGetLastButtonInGroup((wxRadioButton*)m_winLastFocused); + } + } + + if ( child == m_winLastFocused ) + { + // must be a group consisting of only one button therefore + // no need to send a navigation event + event.Skip(false); + return; + } + } +#endif // __WXMSW__ + + if ( child->AcceptsFocusFromKeyboard() ) + { + // if we're setting the focus to a child panel we should prevent it + // from giving it to the child which had the focus the last time + // and instead give it to the first/last child depending from which + // direction we're coming + event.SetEventObject(m_winParent); + + // disable propagation for this call as otherwise the event might + // bounce back to us. + wxPropagationDisabler disableProp(event); + if ( !child->GetEventHandler()->ProcessEvent(event) ) + { + // set it first in case SetFocusFromKbd() results in focus + // change too + m_winLastFocused = child; + + // everything is simple: just give focus to it + child->SetFocusFromKbd(); + } + //else: the child manages its focus itself + + event.Skip( false ); + + return; + } + + node = forward ? node->GetNext() : node->GetPrevious(); + } + + // we cycled through all of our children and none of them wanted to accept + // focus + event.Skip(); +} + +void wxControlContainer::HandleOnWindowDestroy(wxWindowBase *child) +{ + if ( child == m_winLastFocused ) + m_winLastFocused = NULL; +} + +// ---------------------------------------------------------------------------- +// focus handling +// ---------------------------------------------------------------------------- + +bool wxControlContainer::DoSetFocus() +{ + wxLogTrace(TRACE_FOCUS, _T("SetFocus on wxPanel 0x%p."), + m_winParent->GetHandle()); + + if (m_inSetFocus) + return true; + + // when the panel gets the focus we move the focus to either the last + // window that had the focus or the first one that can get it unless the + // focus had been already set to some other child + + wxWindow *win = wxWindow::FindFocus(); + while ( win ) + { + if ( win == m_winParent ) + { + // our child already has focus, don't take it away from it + return true; + } + + if ( win->IsTopLevel() ) + { + // don't look beyond the first top level parent - useless and + // unnecessary + break; + } + + win = win->GetParent(); + } + + // protect against infinite recursion: + m_inSetFocus = true; + + bool ret = SetFocusToChild(); + + m_inSetFocus = false; + + return ret; +} + +void wxControlContainer::HandleOnFocus(wxFocusEvent& event) +{ + wxLogTrace(TRACE_FOCUS, _T("OnFocus on wxPanel 0x%p, name: %s"), + m_winParent->GetHandle(), + m_winParent->GetName().c_str() ); + + DoSetFocus(); + + event.Skip(); +} + +bool wxControlContainer::SetFocusToChild() +{ + return wxSetFocusToChild(m_winParent, &m_winLastFocused); +} + +// ---------------------------------------------------------------------------- +// SetFocusToChild(): this function is used by wxPanel but also by wxFrame in +// wxMSW, this is why it is outside of wxControlContainer class +// ---------------------------------------------------------------------------- + +bool wxSetFocusToChild(wxWindow *win, wxWindow **childLastFocused) +{ + wxCHECK_MSG( win, false, _T("wxSetFocusToChild(): invalid window") ); + wxCHECK_MSG( childLastFocused, false, + _T("wxSetFocusToChild(): NULL child poonter") ); + + if ( *childLastFocused ) + { + // It might happen that the window got reparented + if ( (*childLastFocused)->GetParent() == win ) + { + wxLogTrace(TRACE_FOCUS, + _T("SetFocusToChild() => last child (0x%p)."), + (*childLastFocused)->GetHandle()); + + // not SetFocusFromKbd(): we're restoring focus back to the old + // window and not setting it as the result of a kbd action + (*childLastFocused)->SetFocus(); + return true; + } + else + { + // it doesn't count as such any more + *childLastFocused = (wxWindow *)NULL; + } + } + + // set the focus to the first child who wants it + wxWindowList::compatibility_iterator node = win->GetChildren().GetFirst(); + while ( node ) + { + wxWindow *child = node->GetData(); + node = node->GetNext(); + +#ifdef __WXMAC__ + if ( child->GetParent()->MacIsWindowScrollbar( child ) ) + continue; +#endif + + if ( child->AcceptsFocusFromKeyboard() && !child->IsTopLevel() ) + { +#ifdef __WXMSW__ + // If a radiobutton is the first focusable child, search for the + // selected radiobutton in the same group + wxRadioButton* btn = wxDynamicCast(child, wxRadioButton); + if (btn) + { + wxRadioButton* selected = wxGetSelectedButtonInGroup(btn); + if (selected) + child = selected; + } +#endif + + wxLogTrace(TRACE_FOCUS, + _T("SetFocusToChild() => first child (0x%p)."), + child->GetHandle()); + + *childLastFocused = child; + child->SetFocusFromKbd(); + return true; + } + } + + return false; +} diff --git a/Externals/wxWidgets/src/common/convauto.cpp b/Externals/wxWidgets/src/common/convauto.cpp index 540f180ffe..3205b7bea6 100644 --- a/Externals/wxWidgets/src/common/convauto.cpp +++ b/Externals/wxWidgets/src/common/convauto.cpp @@ -1,214 +1,214 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: src/common/convauto.cpp -// Purpose: implementation of wxConvAuto -// Author: Vadim Zeitlin -// Created: 2006-04-04 -// RCS-ID: $Id: convauto.cpp 38570 2006-04-05 14:37:47Z VZ $ -// Copyright: (c) 2006 Vadim Zeitlin -// Licence: wxWindows licence -/////////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// for compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_WCHAR_T - -#ifndef WX_PRECOMP -#endif //WX_PRECOMP - -#include "wx/convauto.h" - -// ============================================================================ -// implementation -// ============================================================================ - -/* static */ -wxConvAuto::BOMType wxConvAuto::DetectBOM(const char *src, size_t srcLen) -{ - if ( srcLen < 2 ) - { - // minimal BOM is 2 bytes so bail out immediately and simplify the code - // below which wouldn't need to check for length for UTF-16 cases - return BOM_None; - } - - // examine the buffer for BOM presence - // - // see http://www.unicode.org/faq/utf_bom.html#BOM - switch ( *src++ ) - { - case '\0': - // could only be big endian UTF-32 (00 00 FE FF) - if ( srcLen >= 4 && - src[0] == '\0' && - src[1] == '\xfe' && - src[2] == '\xff' ) - { - return BOM_UTF32BE; - } - break; - - case '\xfe': - // could only be big endian UTF-16 (FE FF) - if ( *src++ == '\xff' ) - { - return BOM_UTF16BE; - } - break; - - case '\xff': - // could be either little endian UTF-16 or UTF-32, both start - // with FF FE - if ( *src++ == '\xfe' ) - { - return srcLen >= 4 && src[0] == '\0' && src[1] == '\0' - ? BOM_UTF32LE - : BOM_UTF16LE; - } - break; - - case '\xef': - // is this UTF-8 BOM (EF BB BF)? - if ( srcLen >= 3 && src[0] == '\xbb' && src[1] == '\xbf' ) - { - return BOM_UTF8; - } - break; - } - - return BOM_None; -} - -void wxConvAuto::InitFromBOM(BOMType bomType) -{ - m_consumedBOM = false; - - switch ( bomType ) - { - case BOM_UTF32BE: - m_conv = new wxMBConvUTF32BE; - m_ownsConv = true; - break; - - case BOM_UTF32LE: - m_conv = new wxMBConvUTF32LE; - m_ownsConv = true; - break; - - case BOM_UTF16BE: - m_conv = new wxMBConvUTF16BE; - m_ownsConv = true; - break; - - case BOM_UTF16LE: - m_conv = new wxMBConvUTF16LE; - m_ownsConv = true; - break; - - case BOM_UTF8: - m_conv = &wxConvUTF8; - m_ownsConv = false; - break; - - default: - wxFAIL_MSG( _T("unexpected BOM type") ); - // fall through: still need to create something - - case BOM_None: - InitWithDefault(); - m_consumedBOM = true; // as there is nothing to consume - } -} - -void wxConvAuto::SkipBOM(const char **src, size_t *len) const -{ - int ofs; - switch ( m_bomType ) - { - case BOM_UTF32BE: - case BOM_UTF32LE: - ofs = 4; - break; - - case BOM_UTF16BE: - case BOM_UTF16LE: - ofs = 2; - break; - - case BOM_UTF8: - ofs = 3; - break; - - default: - wxFAIL_MSG( _T("unexpected BOM type") ); - // fall through: still need to create something - - case BOM_None: - ofs = 0; - } - - *src += ofs; - if ( *len != (size_t)-1 ) - *len -= ofs; -} - -void wxConvAuto::InitFromInput(const char **src, size_t *len) -{ - m_bomType = DetectBOM(*src, *len); - InitFromBOM(m_bomType); - SkipBOM(src, len); -} - -size_t -wxConvAuto::ToWChar(wchar_t *dst, size_t dstLen, - const char *src, size_t srcLen) const -{ - // we check BOM and create the appropriate conversion the first time we're - // called but we also need to ensure that the BOM is skipped not only - // during this initial call but also during the first call with non-NULL - // dst as typically we're first called with NULL dst to calculate the - // needed buffer size - wxConvAuto *self = wx_const_cast(wxConvAuto *, this); - if ( !m_conv ) - { - self->InitFromInput(&src, &srcLen); - if ( dst ) - self->m_consumedBOM = true; - } - - if ( !m_consumedBOM && dst ) - { - self->m_consumedBOM = true; - SkipBOM(&src, &srcLen); - } - - return m_conv->ToWChar(dst, dstLen, src, srcLen); -} - -size_t -wxConvAuto::FromWChar(char *dst, size_t dstLen, - const wchar_t *src, size_t srcLen) const -{ - if ( !m_conv ) - { - // default to UTF-8 for the multibyte output - wx_const_cast(wxConvAuto *, this)->InitWithDefault(); - } - - return m_conv->FromWChar(dst, dstLen, src, srcLen); -} - -#endif // wxUSE_WCHAR_T - +/////////////////////////////////////////////////////////////////////////////// +// Name: src/common/convauto.cpp +// Purpose: implementation of wxConvAuto +// Author: Vadim Zeitlin +// Created: 2006-04-04 +// RCS-ID: $Id: convauto.cpp 38570 2006-04-05 14:37:47Z VZ $ +// Copyright: (c) 2006 Vadim Zeitlin +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// for compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_WCHAR_T + +#ifndef WX_PRECOMP +#endif //WX_PRECOMP + +#include "wx/convauto.h" + +// ============================================================================ +// implementation +// ============================================================================ + +/* static */ +wxConvAuto::BOMType wxConvAuto::DetectBOM(const char *src, size_t srcLen) +{ + if ( srcLen < 2 ) + { + // minimal BOM is 2 bytes so bail out immediately and simplify the code + // below which wouldn't need to check for length for UTF-16 cases + return BOM_None; + } + + // examine the buffer for BOM presence + // + // see http://www.unicode.org/faq/utf_bom.html#BOM + switch ( *src++ ) + { + case '\0': + // could only be big endian UTF-32 (00 00 FE FF) + if ( srcLen >= 4 && + src[0] == '\0' && + src[1] == '\xfe' && + src[2] == '\xff' ) + { + return BOM_UTF32BE; + } + break; + + case '\xfe': + // could only be big endian UTF-16 (FE FF) + if ( *src++ == '\xff' ) + { + return BOM_UTF16BE; + } + break; + + case '\xff': + // could be either little endian UTF-16 or UTF-32, both start + // with FF FE + if ( *src++ == '\xfe' ) + { + return srcLen >= 4 && src[0] == '\0' && src[1] == '\0' + ? BOM_UTF32LE + : BOM_UTF16LE; + } + break; + + case '\xef': + // is this UTF-8 BOM (EF BB BF)? + if ( srcLen >= 3 && src[0] == '\xbb' && src[1] == '\xbf' ) + { + return BOM_UTF8; + } + break; + } + + return BOM_None; +} + +void wxConvAuto::InitFromBOM(BOMType bomType) +{ + m_consumedBOM = false; + + switch ( bomType ) + { + case BOM_UTF32BE: + m_conv = new wxMBConvUTF32BE; + m_ownsConv = true; + break; + + case BOM_UTF32LE: + m_conv = new wxMBConvUTF32LE; + m_ownsConv = true; + break; + + case BOM_UTF16BE: + m_conv = new wxMBConvUTF16BE; + m_ownsConv = true; + break; + + case BOM_UTF16LE: + m_conv = new wxMBConvUTF16LE; + m_ownsConv = true; + break; + + case BOM_UTF8: + m_conv = &wxConvUTF8; + m_ownsConv = false; + break; + + default: + wxFAIL_MSG( _T("unexpected BOM type") ); + // fall through: still need to create something + + case BOM_None: + InitWithDefault(); + m_consumedBOM = true; // as there is nothing to consume + } +} + +void wxConvAuto::SkipBOM(const char **src, size_t *len) const +{ + int ofs; + switch ( m_bomType ) + { + case BOM_UTF32BE: + case BOM_UTF32LE: + ofs = 4; + break; + + case BOM_UTF16BE: + case BOM_UTF16LE: + ofs = 2; + break; + + case BOM_UTF8: + ofs = 3; + break; + + default: + wxFAIL_MSG( _T("unexpected BOM type") ); + // fall through: still need to create something + + case BOM_None: + ofs = 0; + } + + *src += ofs; + if ( *len != (size_t)-1 ) + *len -= ofs; +} + +void wxConvAuto::InitFromInput(const char **src, size_t *len) +{ + m_bomType = DetectBOM(*src, *len); + InitFromBOM(m_bomType); + SkipBOM(src, len); +} + +size_t +wxConvAuto::ToWChar(wchar_t *dst, size_t dstLen, + const char *src, size_t srcLen) const +{ + // we check BOM and create the appropriate conversion the first time we're + // called but we also need to ensure that the BOM is skipped not only + // during this initial call but also during the first call with non-NULL + // dst as typically we're first called with NULL dst to calculate the + // needed buffer size + wxConvAuto *self = wx_const_cast(wxConvAuto *, this); + if ( !m_conv ) + { + self->InitFromInput(&src, &srcLen); + if ( dst ) + self->m_consumedBOM = true; + } + + if ( !m_consumedBOM && dst ) + { + self->m_consumedBOM = true; + SkipBOM(&src, &srcLen); + } + + return m_conv->ToWChar(dst, dstLen, src, srcLen); +} + +size_t +wxConvAuto::FromWChar(char *dst, size_t dstLen, + const wchar_t *src, size_t srcLen) const +{ + if ( !m_conv ) + { + // default to UTF-8 for the multibyte output + wx_const_cast(wxConvAuto *, this)->InitWithDefault(); + } + + return m_conv->FromWChar(dst, dstLen, src, srcLen); +} + +#endif // wxUSE_WCHAR_T + diff --git a/Externals/wxWidgets/src/common/cshelp.cpp b/Externals/wxWidgets/src/common/cshelp.cpp index 181fd53b38..6bd3d5cc00 100644 --- a/Externals/wxWidgets/src/common/cshelp.cpp +++ b/Externals/wxWidgets/src/common/cshelp.cpp @@ -1,512 +1,512 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/cshelp.cpp -// Purpose: Context sensitive help class implementation -// Author: Julian Smart, Vadim Zeitlin -// Modified by: -// Created: 08/09/2000 -// RCS-ID: $Id: cshelp.cpp 52329 2008-03-05 13:20:26Z VZ $ -// Copyright: (c) 2000 Julian Smart, Vadim Zeitlin -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_HELP - -#ifndef WX_PRECOMP - #include "wx/app.h" - #include "wx/module.h" -#endif - -#include "wx/tipwin.h" -#include "wx/cshelp.h" - -#if wxUSE_MS_HTML_HELP - #include "wx/msw/helpchm.h" // for ShowContextHelpPopup - #include "wx/utils.h" // for wxGetMousePosition() -#endif - -// ---------------------------------------------------------------------------- -// wxContextHelpEvtHandler private class -// ---------------------------------------------------------------------------- - -// This class exists in order to eat events until the left mouse button is -// pressed -class wxContextHelpEvtHandler: public wxEvtHandler -{ -public: - wxContextHelpEvtHandler(wxContextHelp* contextHelp) - { - m_contextHelp = contextHelp; - } - - virtual bool ProcessEvent(wxEvent& event); - -//// Data - wxContextHelp* m_contextHelp; - - DECLARE_NO_COPY_CLASS(wxContextHelpEvtHandler) -}; - -// ============================================================================ -// implementation -// ============================================================================ - -// ---------------------------------------------------------------------------- -// wxContextHelp -// ---------------------------------------------------------------------------- - -/* - * Invokes context-sensitive help - */ - - -IMPLEMENT_DYNAMIC_CLASS(wxContextHelp, wxObject) - -wxContextHelp::wxContextHelp(wxWindow* win, bool beginHelp) -{ - m_inHelp = false; - - if (beginHelp) - BeginContextHelp(win); -} - -wxContextHelp::~wxContextHelp() -{ - if (m_inHelp) - EndContextHelp(); -} - -// Not currently needed, but on some systems capture may not work as -// expected so we'll leave it here for now. -#ifdef __WXMOTIF__ -static void wxPushOrPopEventHandlers(wxContextHelp* help, wxWindow* win, bool push) -{ - if (push) - win->PushEventHandler(new wxContextHelpEvtHandler(help)); - else - win->PopEventHandler(true); - - wxWindowList::compatibility_iterator node = win->GetChildren().GetFirst(); - while (node) - { - wxWindow* child = node->GetData(); - wxPushOrPopEventHandlers(help, child, push); - - node = node->GetNext(); - } -} -#endif - -// Begin 'context help mode' -bool wxContextHelp::BeginContextHelp(wxWindow* win) -{ - if (!win) - win = wxTheApp->GetTopWindow(); - if (!win) - return false; - - wxCursor cursor(wxCURSOR_QUESTION_ARROW); - wxCursor oldCursor = win->GetCursor(); - win->SetCursor(cursor); - -#ifdef __WXMAC__ - wxSetCursor(cursor); -#endif - - m_status = false; - -#ifdef __WXMOTIF__ - wxPushOrPopEventHandlers(this, win, true); -#else - win->PushEventHandler(new wxContextHelpEvtHandler(this)); -#endif - - win->CaptureMouse(); - - EventLoop(); - - win->ReleaseMouse(); - -#ifdef __WXMOTIF__ - wxPushOrPopEventHandlers(this, win, false); -#else - win->PopEventHandler(true); -#endif - - win->SetCursor(oldCursor); - -#ifdef __WXMAC__ - wxSetCursor(wxNullCursor); -#endif - - if (m_status) - { - wxPoint pt; - wxWindow* winAtPtr = wxFindWindowAtPointer(pt); - -#if 0 - if (winAtPtr) - { - printf("Picked %s (%d)\n", winAtPtr->GetName().c_str(), - winAtPtr->GetId()); - } -#endif - - if (winAtPtr) - DispatchEvent(winAtPtr, pt); - } - - return true; -} - -bool wxContextHelp::EndContextHelp() -{ - m_inHelp = false; - - return true; -} - -bool wxContextHelp::EventLoop() -{ - m_inHelp = true; - - while ( m_inHelp ) - { - if (wxTheApp->Pending()) - { - wxTheApp->Dispatch(); - } - else - { - wxTheApp->ProcessIdle(); - } - } - - return true; -} - -bool wxContextHelpEvtHandler::ProcessEvent(wxEvent& event) -{ - if (event.GetEventType() == wxEVT_LEFT_DOWN) - { - m_contextHelp->SetStatus(true); - m_contextHelp->EndContextHelp(); - return true; - } - - if ((event.GetEventType() == wxEVT_CHAR) || - (event.GetEventType() == wxEVT_KEY_DOWN) || - (event.GetEventType() == wxEVT_ACTIVATE) || - (event.GetEventType() == wxEVT_MOUSE_CAPTURE_CHANGED)) - { - // May have already been set to true by a left-click - //m_contextHelp->SetStatus(false); - m_contextHelp->EndContextHelp(); - return true; - } - - if ((event.GetEventType() == wxEVT_PAINT) || - (event.GetEventType() == wxEVT_ERASE_BACKGROUND)) - { - event.Skip(); - return false; - } - - return true; -} - -// Dispatch the help event to the relevant window -bool wxContextHelp::DispatchEvent(wxWindow* win, const wxPoint& pt) -{ - wxCHECK_MSG( win, false, _T("win parameter can't be NULL") ); - - wxHelpEvent helpEvent(wxEVT_HELP, win->GetId(), pt, - wxHelpEvent::Origin_HelpButton); - helpEvent.SetEventObject(win); - - return win->GetEventHandler()->ProcessEvent(helpEvent); -} - -// ---------------------------------------------------------------------------- -// wxContextHelpButton -// ---------------------------------------------------------------------------- - -/* - * wxContextHelpButton - * You can add this to your dialogs (especially on non-Windows platforms) - * to put the application into context help mode. - */ - -#ifndef __WXPM__ - -static const char * csquery_xpm[] = { -"12 11 2 1", -" c None", -". c #000000", -" ", -" .... ", -" .. .. ", -" .. .. ", -" .. ", -" .. ", -" .. ", -" ", -" .. ", -" .. ", -" "}; - -#endif - -IMPLEMENT_CLASS(wxContextHelpButton, wxBitmapButton) - -BEGIN_EVENT_TABLE(wxContextHelpButton, wxBitmapButton) - EVT_BUTTON(wxID_CONTEXT_HELP, wxContextHelpButton::OnContextHelp) -END_EVENT_TABLE() - -wxContextHelpButton::wxContextHelpButton(wxWindow* parent, - wxWindowID id, - const wxPoint& pos, - const wxSize& size, - long style) -#if defined(__WXPM__) - : wxBitmapButton(parent, id, wxBitmap(wxCSQUERY_BITMAP - ,wxBITMAP_TYPE_RESOURCE - ), - pos, size, style) -#else - : wxBitmapButton(parent, id, wxBitmap(csquery_xpm), - pos, size, style) -#endif -{ -} - -void wxContextHelpButton::OnContextHelp(wxCommandEvent& WXUNUSED(event)) -{ - wxContextHelp contextHelp(GetParent()); -} - -// ---------------------------------------------------------------------------- -// wxHelpProvider -// ---------------------------------------------------------------------------- - -wxHelpProvider *wxHelpProvider::ms_helpProvider = (wxHelpProvider *)NULL; - -// trivial implementation of some methods which we don't want to make pure -// virtual for convenience - -void wxHelpProvider::AddHelp(wxWindowBase * WXUNUSED(window), - const wxString& WXUNUSED(text)) -{ -} - -void wxHelpProvider::AddHelp(wxWindowID WXUNUSED(id), - const wxString& WXUNUSED(text)) -{ -} - -// removes the association -void wxHelpProvider::RemoveHelp(wxWindowBase* WXUNUSED(window)) -{ -} - -wxHelpProvider::~wxHelpProvider() -{ -} - -wxString wxHelpProvider::GetHelpTextMaybeAtPoint(wxWindowBase *window) -{ - if ( m_helptextAtPoint != wxDefaultPosition || - m_helptextOrigin != wxHelpEvent::Origin_Unknown ) - { - wxCHECK_MSG( window, wxEmptyString, _T("window must not be NULL") ); - - wxPoint pt = m_helptextAtPoint; - wxHelpEvent::Origin origin = m_helptextOrigin; - - m_helptextAtPoint = wxDefaultPosition; - m_helptextOrigin = wxHelpEvent::Origin_Unknown; - - return window->GetHelpTextAtPoint(pt, origin); - } - - return GetHelp(window); -} - -// ---------------------------------------------------------------------------- -// wxSimpleHelpProvider -// ---------------------------------------------------------------------------- - -#define WINHASH_KEY(w) wxPtrToUInt(w) - -wxString wxSimpleHelpProvider::GetHelp(const wxWindowBase *window) -{ - wxSimpleHelpProviderHashMap::iterator it = m_hashWindows.find(WINHASH_KEY(window)); - - if ( it == m_hashWindows.end() ) - { - it = m_hashIds.find(window->GetId()); - if ( it == m_hashIds.end() ) - return wxEmptyString; - } - - return it->second; -} - -void wxSimpleHelpProvider::AddHelp(wxWindowBase *window, const wxString& text) -{ - m_hashWindows.erase(WINHASH_KEY(window)); - m_hashWindows[WINHASH_KEY(window)] = text; -} - -void wxSimpleHelpProvider::AddHelp(wxWindowID id, const wxString& text) -{ - wxSimpleHelpProviderHashMap::key_type key = (wxSimpleHelpProviderHashMap::key_type)id; - m_hashIds.erase(key); - m_hashIds[key] = text; -} - -// removes the association -void wxSimpleHelpProvider::RemoveHelp(wxWindowBase* window) -{ - m_hashWindows.erase(WINHASH_KEY(window)); -} - -bool wxSimpleHelpProvider::ShowHelp(wxWindowBase *window) -{ -#if wxUSE_MS_HTML_HELP || wxUSE_TIPWINDOW -#if wxUSE_MS_HTML_HELP - // m_helptextAtPoint will be reset by GetHelpTextMaybeAtPoint(), stash it - const wxPoint posTooltip = m_helptextAtPoint; -#endif // wxUSE_MS_HTML_HELP - - const wxString text = GetHelpTextMaybeAtPoint(window); - - if ( !text.empty() ) - { - // use the native help popup style if it's available -#if wxUSE_MS_HTML_HELP - if ( !wxCHMHelpController::ShowContextHelpPopup - ( - text, - posTooltip, - (wxWindow *)window - ) ) -#endif // wxUSE_MS_HTML_HELP - { -#if wxUSE_TIPWINDOW - static wxTipWindow* s_tipWindow = NULL; - - if ( s_tipWindow ) - { - // Prevent s_tipWindow being nulled in OnIdle, thereby removing - // the chance for the window to be closed by ShowHelp - s_tipWindow->SetTipWindowPtr(NULL); - s_tipWindow->Close(); - } - - s_tipWindow = new wxTipWindow((wxWindow *)window, text, - 100, &s_tipWindow); -#else // !wxUSE_TIPWINDOW - // we tried wxCHMHelpController but it failed and we don't have - // wxTipWindow to fall back on, so - return false; -#endif // wxUSE_TIPWINDOW - } - - return true; - } -#else // !wxUSE_MS_HTML_HELP && !wxUSE_TIPWINDOW - wxUnusedVar(window); -#endif // wxUSE_MS_HTML_HELP || wxUSE_TIPWINDOW - - return false; -} - -// ---------------------------------------------------------------------------- -// wxHelpControllerHelpProvider -// ---------------------------------------------------------------------------- - -wxHelpControllerHelpProvider::wxHelpControllerHelpProvider(wxHelpControllerBase* hc) -{ - m_helpController = hc; -} - -bool wxHelpControllerHelpProvider::ShowHelp(wxWindowBase *window) -{ - const wxString text = GetHelpTextMaybeAtPoint(window); - - if ( text.empty() ) - return false; - - if ( m_helpController ) - { - // if it's a numeric topic, show it - long topic; - if ( text.ToLong(&topic) ) - return m_helpController->DisplayContextPopup(topic); - - // otherwise show the text directly - if ( m_helpController->DisplayTextPopup(text, wxGetMousePosition()) ) - return true; - } - - // if there is no help controller or it's not capable of showing the help, - // fallback to the default method - return wxSimpleHelpProvider::ShowHelp(window); -} - -// Convenience function for turning context id into wxString -wxString wxContextId(int id) -{ - return wxString::Format(_T("%d"), id); -} - -// ---------------------------------------------------------------------------- -// wxHelpProviderModule: module responsible for cleaning up help provider. -// ---------------------------------------------------------------------------- - -class wxHelpProviderModule : public wxModule -{ -public: - bool OnInit(); - void OnExit(); - -private: - DECLARE_DYNAMIC_CLASS(wxHelpProviderModule) -}; - -IMPLEMENT_DYNAMIC_CLASS(wxHelpProviderModule, wxModule) - -bool wxHelpProviderModule::OnInit() -{ - // Probably we don't want to do anything by default, - // since it could pull in extra code - // wxHelpProvider::Set(new wxSimpleHelpProvider); - - return true; -} - -void wxHelpProviderModule::OnExit() -{ - if (wxHelpProvider::Get()) - { - delete wxHelpProvider::Get(); - wxHelpProvider::Set(NULL); - } -} - -#endif // wxUSE_HELP +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/cshelp.cpp +// Purpose: Context sensitive help class implementation +// Author: Julian Smart, Vadim Zeitlin +// Modified by: +// Created: 08/09/2000 +// RCS-ID: $Id: cshelp.cpp 52329 2008-03-05 13:20:26Z VZ $ +// Copyright: (c) 2000 Julian Smart, Vadim Zeitlin +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_HELP + +#ifndef WX_PRECOMP + #include "wx/app.h" + #include "wx/module.h" +#endif + +#include "wx/tipwin.h" +#include "wx/cshelp.h" + +#if wxUSE_MS_HTML_HELP + #include "wx/msw/helpchm.h" // for ShowContextHelpPopup + #include "wx/utils.h" // for wxGetMousePosition() +#endif + +// ---------------------------------------------------------------------------- +// wxContextHelpEvtHandler private class +// ---------------------------------------------------------------------------- + +// This class exists in order to eat events until the left mouse button is +// pressed +class wxContextHelpEvtHandler: public wxEvtHandler +{ +public: + wxContextHelpEvtHandler(wxContextHelp* contextHelp) + { + m_contextHelp = contextHelp; + } + + virtual bool ProcessEvent(wxEvent& event); + +//// Data + wxContextHelp* m_contextHelp; + + DECLARE_NO_COPY_CLASS(wxContextHelpEvtHandler) +}; + +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// wxContextHelp +// ---------------------------------------------------------------------------- + +/* + * Invokes context-sensitive help + */ + + +IMPLEMENT_DYNAMIC_CLASS(wxContextHelp, wxObject) + +wxContextHelp::wxContextHelp(wxWindow* win, bool beginHelp) +{ + m_inHelp = false; + + if (beginHelp) + BeginContextHelp(win); +} + +wxContextHelp::~wxContextHelp() +{ + if (m_inHelp) + EndContextHelp(); +} + +// Not currently needed, but on some systems capture may not work as +// expected so we'll leave it here for now. +#ifdef __WXMOTIF__ +static void wxPushOrPopEventHandlers(wxContextHelp* help, wxWindow* win, bool push) +{ + if (push) + win->PushEventHandler(new wxContextHelpEvtHandler(help)); + else + win->PopEventHandler(true); + + wxWindowList::compatibility_iterator node = win->GetChildren().GetFirst(); + while (node) + { + wxWindow* child = node->GetData(); + wxPushOrPopEventHandlers(help, child, push); + + node = node->GetNext(); + } +} +#endif + +// Begin 'context help mode' +bool wxContextHelp::BeginContextHelp(wxWindow* win) +{ + if (!win) + win = wxTheApp->GetTopWindow(); + if (!win) + return false; + + wxCursor cursor(wxCURSOR_QUESTION_ARROW); + wxCursor oldCursor = win->GetCursor(); + win->SetCursor(cursor); + +#ifdef __WXMAC__ + wxSetCursor(cursor); +#endif + + m_status = false; + +#ifdef __WXMOTIF__ + wxPushOrPopEventHandlers(this, win, true); +#else + win->PushEventHandler(new wxContextHelpEvtHandler(this)); +#endif + + win->CaptureMouse(); + + EventLoop(); + + win->ReleaseMouse(); + +#ifdef __WXMOTIF__ + wxPushOrPopEventHandlers(this, win, false); +#else + win->PopEventHandler(true); +#endif + + win->SetCursor(oldCursor); + +#ifdef __WXMAC__ + wxSetCursor(wxNullCursor); +#endif + + if (m_status) + { + wxPoint pt; + wxWindow* winAtPtr = wxFindWindowAtPointer(pt); + +#if 0 + if (winAtPtr) + { + printf("Picked %s (%d)\n", winAtPtr->GetName().c_str(), + winAtPtr->GetId()); + } +#endif + + if (winAtPtr) + DispatchEvent(winAtPtr, pt); + } + + return true; +} + +bool wxContextHelp::EndContextHelp() +{ + m_inHelp = false; + + return true; +} + +bool wxContextHelp::EventLoop() +{ + m_inHelp = true; + + while ( m_inHelp ) + { + if (wxTheApp->Pending()) + { + wxTheApp->Dispatch(); + } + else + { + wxTheApp->ProcessIdle(); + } + } + + return true; +} + +bool wxContextHelpEvtHandler::ProcessEvent(wxEvent& event) +{ + if (event.GetEventType() == wxEVT_LEFT_DOWN) + { + m_contextHelp->SetStatus(true); + m_contextHelp->EndContextHelp(); + return true; + } + + if ((event.GetEventType() == wxEVT_CHAR) || + (event.GetEventType() == wxEVT_KEY_DOWN) || + (event.GetEventType() == wxEVT_ACTIVATE) || + (event.GetEventType() == wxEVT_MOUSE_CAPTURE_CHANGED)) + { + // May have already been set to true by a left-click + //m_contextHelp->SetStatus(false); + m_contextHelp->EndContextHelp(); + return true; + } + + if ((event.GetEventType() == wxEVT_PAINT) || + (event.GetEventType() == wxEVT_ERASE_BACKGROUND)) + { + event.Skip(); + return false; + } + + return true; +} + +// Dispatch the help event to the relevant window +bool wxContextHelp::DispatchEvent(wxWindow* win, const wxPoint& pt) +{ + wxCHECK_MSG( win, false, _T("win parameter can't be NULL") ); + + wxHelpEvent helpEvent(wxEVT_HELP, win->GetId(), pt, + wxHelpEvent::Origin_HelpButton); + helpEvent.SetEventObject(win); + + return win->GetEventHandler()->ProcessEvent(helpEvent); +} + +// ---------------------------------------------------------------------------- +// wxContextHelpButton +// ---------------------------------------------------------------------------- + +/* + * wxContextHelpButton + * You can add this to your dialogs (especially on non-Windows platforms) + * to put the application into context help mode. + */ + +#ifndef __WXPM__ + +static const char * csquery_xpm[] = { +"12 11 2 1", +" c None", +". c #000000", +" ", +" .... ", +" .. .. ", +" .. .. ", +" .. ", +" .. ", +" .. ", +" ", +" .. ", +" .. ", +" "}; + +#endif + +IMPLEMENT_CLASS(wxContextHelpButton, wxBitmapButton) + +BEGIN_EVENT_TABLE(wxContextHelpButton, wxBitmapButton) + EVT_BUTTON(wxID_CONTEXT_HELP, wxContextHelpButton::OnContextHelp) +END_EVENT_TABLE() + +wxContextHelpButton::wxContextHelpButton(wxWindow* parent, + wxWindowID id, + const wxPoint& pos, + const wxSize& size, + long style) +#if defined(__WXPM__) + : wxBitmapButton(parent, id, wxBitmap(wxCSQUERY_BITMAP + ,wxBITMAP_TYPE_RESOURCE + ), + pos, size, style) +#else + : wxBitmapButton(parent, id, wxBitmap(csquery_xpm), + pos, size, style) +#endif +{ +} + +void wxContextHelpButton::OnContextHelp(wxCommandEvent& WXUNUSED(event)) +{ + wxContextHelp contextHelp(GetParent()); +} + +// ---------------------------------------------------------------------------- +// wxHelpProvider +// ---------------------------------------------------------------------------- + +wxHelpProvider *wxHelpProvider::ms_helpProvider = (wxHelpProvider *)NULL; + +// trivial implementation of some methods which we don't want to make pure +// virtual for convenience + +void wxHelpProvider::AddHelp(wxWindowBase * WXUNUSED(window), + const wxString& WXUNUSED(text)) +{ +} + +void wxHelpProvider::AddHelp(wxWindowID WXUNUSED(id), + const wxString& WXUNUSED(text)) +{ +} + +// removes the association +void wxHelpProvider::RemoveHelp(wxWindowBase* WXUNUSED(window)) +{ +} + +wxHelpProvider::~wxHelpProvider() +{ +} + +wxString wxHelpProvider::GetHelpTextMaybeAtPoint(wxWindowBase *window) +{ + if ( m_helptextAtPoint != wxDefaultPosition || + m_helptextOrigin != wxHelpEvent::Origin_Unknown ) + { + wxCHECK_MSG( window, wxEmptyString, _T("window must not be NULL") ); + + wxPoint pt = m_helptextAtPoint; + wxHelpEvent::Origin origin = m_helptextOrigin; + + m_helptextAtPoint = wxDefaultPosition; + m_helptextOrigin = wxHelpEvent::Origin_Unknown; + + return window->GetHelpTextAtPoint(pt, origin); + } + + return GetHelp(window); +} + +// ---------------------------------------------------------------------------- +// wxSimpleHelpProvider +// ---------------------------------------------------------------------------- + +#define WINHASH_KEY(w) wxPtrToUInt(w) + +wxString wxSimpleHelpProvider::GetHelp(const wxWindowBase *window) +{ + wxSimpleHelpProviderHashMap::iterator it = m_hashWindows.find(WINHASH_KEY(window)); + + if ( it == m_hashWindows.end() ) + { + it = m_hashIds.find(window->GetId()); + if ( it == m_hashIds.end() ) + return wxEmptyString; + } + + return it->second; +} + +void wxSimpleHelpProvider::AddHelp(wxWindowBase *window, const wxString& text) +{ + m_hashWindows.erase(WINHASH_KEY(window)); + m_hashWindows[WINHASH_KEY(window)] = text; +} + +void wxSimpleHelpProvider::AddHelp(wxWindowID id, const wxString& text) +{ + wxSimpleHelpProviderHashMap::key_type key = (wxSimpleHelpProviderHashMap::key_type)id; + m_hashIds.erase(key); + m_hashIds[key] = text; +} + +// removes the association +void wxSimpleHelpProvider::RemoveHelp(wxWindowBase* window) +{ + m_hashWindows.erase(WINHASH_KEY(window)); +} + +bool wxSimpleHelpProvider::ShowHelp(wxWindowBase *window) +{ +#if wxUSE_MS_HTML_HELP || wxUSE_TIPWINDOW +#if wxUSE_MS_HTML_HELP + // m_helptextAtPoint will be reset by GetHelpTextMaybeAtPoint(), stash it + const wxPoint posTooltip = m_helptextAtPoint; +#endif // wxUSE_MS_HTML_HELP + + const wxString text = GetHelpTextMaybeAtPoint(window); + + if ( !text.empty() ) + { + // use the native help popup style if it's available +#if wxUSE_MS_HTML_HELP + if ( !wxCHMHelpController::ShowContextHelpPopup + ( + text, + posTooltip, + (wxWindow *)window + ) ) +#endif // wxUSE_MS_HTML_HELP + { +#if wxUSE_TIPWINDOW + static wxTipWindow* s_tipWindow = NULL; + + if ( s_tipWindow ) + { + // Prevent s_tipWindow being nulled in OnIdle, thereby removing + // the chance for the window to be closed by ShowHelp + s_tipWindow->SetTipWindowPtr(NULL); + s_tipWindow->Close(); + } + + s_tipWindow = new wxTipWindow((wxWindow *)window, text, + 100, &s_tipWindow); +#else // !wxUSE_TIPWINDOW + // we tried wxCHMHelpController but it failed and we don't have + // wxTipWindow to fall back on, so + return false; +#endif // wxUSE_TIPWINDOW + } + + return true; + } +#else // !wxUSE_MS_HTML_HELP && !wxUSE_TIPWINDOW + wxUnusedVar(window); +#endif // wxUSE_MS_HTML_HELP || wxUSE_TIPWINDOW + + return false; +} + +// ---------------------------------------------------------------------------- +// wxHelpControllerHelpProvider +// ---------------------------------------------------------------------------- + +wxHelpControllerHelpProvider::wxHelpControllerHelpProvider(wxHelpControllerBase* hc) +{ + m_helpController = hc; +} + +bool wxHelpControllerHelpProvider::ShowHelp(wxWindowBase *window) +{ + const wxString text = GetHelpTextMaybeAtPoint(window); + + if ( text.empty() ) + return false; + + if ( m_helpController ) + { + // if it's a numeric topic, show it + long topic; + if ( text.ToLong(&topic) ) + return m_helpController->DisplayContextPopup(topic); + + // otherwise show the text directly + if ( m_helpController->DisplayTextPopup(text, wxGetMousePosition()) ) + return true; + } + + // if there is no help controller or it's not capable of showing the help, + // fallback to the default method + return wxSimpleHelpProvider::ShowHelp(window); +} + +// Convenience function for turning context id into wxString +wxString wxContextId(int id) +{ + return wxString::Format(_T("%d"), id); +} + +// ---------------------------------------------------------------------------- +// wxHelpProviderModule: module responsible for cleaning up help provider. +// ---------------------------------------------------------------------------- + +class wxHelpProviderModule : public wxModule +{ +public: + bool OnInit(); + void OnExit(); + +private: + DECLARE_DYNAMIC_CLASS(wxHelpProviderModule) +}; + +IMPLEMENT_DYNAMIC_CLASS(wxHelpProviderModule, wxModule) + +bool wxHelpProviderModule::OnInit() +{ + // Probably we don't want to do anything by default, + // since it could pull in extra code + // wxHelpProvider::Set(new wxSimpleHelpProvider); + + return true; +} + +void wxHelpProviderModule::OnExit() +{ + if (wxHelpProvider::Get()) + { + delete wxHelpProvider::Get(); + wxHelpProvider::Set(NULL); + } +} + +#endif // wxUSE_HELP diff --git a/Externals/wxWidgets/src/common/ctrlcmn.cpp b/Externals/wxWidgets/src/common/ctrlcmn.cpp index a10e48160a..9326835e9c 100644 --- a/Externals/wxWidgets/src/common/ctrlcmn.cpp +++ b/Externals/wxWidgets/src/common/ctrlcmn.cpp @@ -1,188 +1,188 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/ctrlcmn.cpp -// Purpose: wxControl common interface -// Author: Vadim Zeitlin -// Modified by: -// Created: 26.07.99 -// RCS-ID: $Id: ctrlcmn.cpp 40329 2006-07-25 18:40:04Z VZ $ -// Copyright: (c) wxWidgets team -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_CONTROLS - -#include "wx/control.h" - -#ifndef WX_PRECOMP - #include "wx/log.h" - #include "wx/radiobut.h" - #include "wx/statbmp.h" - #include "wx/bitmap.h" - #include "wx/utils.h" // for wxStripMenuCodes() -#endif - -const wxChar wxControlNameStr[] = wxT("control"); - -// ============================================================================ -// implementation -// ============================================================================ - -wxControlBase::~wxControlBase() -{ - // this destructor is required for Darwin -} - -bool wxControlBase::Create(wxWindow *parent, - wxWindowID id, - const wxPoint &pos, - const wxSize &size, - long style, - const wxValidator& wxVALIDATOR_PARAM(validator), - const wxString &name) -{ - bool ret = wxWindow::Create(parent, id, pos, size, style, name); - -#if wxUSE_VALIDATORS - if ( ret ) - SetValidator(validator); -#endif // wxUSE_VALIDATORS - - return ret; -} - -bool wxControlBase::CreateControl(wxWindowBase *parent, - wxWindowID id, - const wxPoint& pos, - const wxSize& size, - long style, - const wxValidator& validator, - const wxString& name) -{ - // even if it's possible to create controls without parents in some port, - // it should surely be discouraged because it doesn't work at all under - // Windows - wxCHECK_MSG( parent, false, wxT("all controls must have parents") ); - - if ( !CreateBase(parent, id, pos, size, style, validator, name) ) - return false; - - parent->AddChild(this); - - return true; -} - -/* static */ -wxString wxControlBase::GetLabelText(const wxString& label) -{ - // we don't want strip the TABs here, just the mnemonics - return wxStripMenuCodes(label, wxStrip_Mnemonics); -} - -void wxControlBase::Command(wxCommandEvent& event) -{ - (void)GetEventHandler()->ProcessEvent(event); -} - -void wxControlBase::InitCommandEvent(wxCommandEvent& event) const -{ - event.SetEventObject((wxControlBase *)this); // const_cast - - // event.SetId(GetId()); -- this is usuall done in the event ctor - - switch ( m_clientDataType ) - { - case wxClientData_Void: - event.SetClientData(GetClientData()); - break; - - case wxClientData_Object: - event.SetClientObject(GetClientObject()); - break; - - case wxClientData_None: - // nothing to do - ; - } -} - - -void wxControlBase::SetLabel( const wxString &label ) -{ - InvalidateBestSize(); - wxWindow::SetLabel(label); -} - -bool wxControlBase::SetFont(const wxFont& font) -{ - InvalidateBestSize(); - return wxWindow::SetFont(font); -} - -// wxControl-specific processing after processing the update event -void wxControlBase::DoUpdateWindowUI(wxUpdateUIEvent& event) -{ - // call inherited - wxWindowBase::DoUpdateWindowUI(event); - - // update label - if ( event.GetSetText() ) - { - if ( event.GetText() != GetLabel() ) - SetLabel(event.GetText()); - } - - // Unfortunately we don't yet have common base class for - // wxRadioButton, so we handle updates of radiobuttons here. - // TODO: If once wxRadioButtonBase will exist, move this code there. -#if wxUSE_RADIOBTN - if ( event.GetSetChecked() ) - { - wxRadioButton *radiobtn = wxDynamicCastThis(wxRadioButton); - if ( radiobtn ) - radiobtn->SetValue(event.GetChecked()); - } -#endif // wxUSE_RADIOBTN -} - -// ---------------------------------------------------------------------------- -// wxStaticBitmap -// ---------------------------------------------------------------------------- - -#if wxUSE_STATBMP - -wxStaticBitmapBase::~wxStaticBitmapBase() -{ - // this destructor is required for Darwin -} - -wxSize wxStaticBitmapBase::DoGetBestSize() const -{ - wxSize best; - wxBitmap bmp = GetBitmap(); - if ( bmp.Ok() ) - best = wxSize(bmp.GetWidth(), bmp.GetHeight()); - else - // this is completely arbitrary - best = wxSize(16, 16); - CacheBestSize(best); - return best; -} - -#endif // wxUSE_STATBMP - -#endif // wxUSE_CONTROLS +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/ctrlcmn.cpp +// Purpose: wxControl common interface +// Author: Vadim Zeitlin +// Modified by: +// Created: 26.07.99 +// RCS-ID: $Id: ctrlcmn.cpp 40329 2006-07-25 18:40:04Z VZ $ +// Copyright: (c) wxWidgets team +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_CONTROLS + +#include "wx/control.h" + +#ifndef WX_PRECOMP + #include "wx/log.h" + #include "wx/radiobut.h" + #include "wx/statbmp.h" + #include "wx/bitmap.h" + #include "wx/utils.h" // for wxStripMenuCodes() +#endif + +const wxChar wxControlNameStr[] = wxT("control"); + +// ============================================================================ +// implementation +// ============================================================================ + +wxControlBase::~wxControlBase() +{ + // this destructor is required for Darwin +} + +bool wxControlBase::Create(wxWindow *parent, + wxWindowID id, + const wxPoint &pos, + const wxSize &size, + long style, + const wxValidator& wxVALIDATOR_PARAM(validator), + const wxString &name) +{ + bool ret = wxWindow::Create(parent, id, pos, size, style, name); + +#if wxUSE_VALIDATORS + if ( ret ) + SetValidator(validator); +#endif // wxUSE_VALIDATORS + + return ret; +} + +bool wxControlBase::CreateControl(wxWindowBase *parent, + wxWindowID id, + const wxPoint& pos, + const wxSize& size, + long style, + const wxValidator& validator, + const wxString& name) +{ + // even if it's possible to create controls without parents in some port, + // it should surely be discouraged because it doesn't work at all under + // Windows + wxCHECK_MSG( parent, false, wxT("all controls must have parents") ); + + if ( !CreateBase(parent, id, pos, size, style, validator, name) ) + return false; + + parent->AddChild(this); + + return true; +} + +/* static */ +wxString wxControlBase::GetLabelText(const wxString& label) +{ + // we don't want strip the TABs here, just the mnemonics + return wxStripMenuCodes(label, wxStrip_Mnemonics); +} + +void wxControlBase::Command(wxCommandEvent& event) +{ + (void)GetEventHandler()->ProcessEvent(event); +} + +void wxControlBase::InitCommandEvent(wxCommandEvent& event) const +{ + event.SetEventObject((wxControlBase *)this); // const_cast + + // event.SetId(GetId()); -- this is usuall done in the event ctor + + switch ( m_clientDataType ) + { + case wxClientData_Void: + event.SetClientData(GetClientData()); + break; + + case wxClientData_Object: + event.SetClientObject(GetClientObject()); + break; + + case wxClientData_None: + // nothing to do + ; + } +} + + +void wxControlBase::SetLabel( const wxString &label ) +{ + InvalidateBestSize(); + wxWindow::SetLabel(label); +} + +bool wxControlBase::SetFont(const wxFont& font) +{ + InvalidateBestSize(); + return wxWindow::SetFont(font); +} + +// wxControl-specific processing after processing the update event +void wxControlBase::DoUpdateWindowUI(wxUpdateUIEvent& event) +{ + // call inherited + wxWindowBase::DoUpdateWindowUI(event); + + // update label + if ( event.GetSetText() ) + { + if ( event.GetText() != GetLabel() ) + SetLabel(event.GetText()); + } + + // Unfortunately we don't yet have common base class for + // wxRadioButton, so we handle updates of radiobuttons here. + // TODO: If once wxRadioButtonBase will exist, move this code there. +#if wxUSE_RADIOBTN + if ( event.GetSetChecked() ) + { + wxRadioButton *radiobtn = wxDynamicCastThis(wxRadioButton); + if ( radiobtn ) + radiobtn->SetValue(event.GetChecked()); + } +#endif // wxUSE_RADIOBTN +} + +// ---------------------------------------------------------------------------- +// wxStaticBitmap +// ---------------------------------------------------------------------------- + +#if wxUSE_STATBMP + +wxStaticBitmapBase::~wxStaticBitmapBase() +{ + // this destructor is required for Darwin +} + +wxSize wxStaticBitmapBase::DoGetBestSize() const +{ + wxSize best; + wxBitmap bmp = GetBitmap(); + if ( bmp.Ok() ) + best = wxSize(bmp.GetWidth(), bmp.GetHeight()); + else + // this is completely arbitrary + best = wxSize(16, 16); + CacheBestSize(best); + return best; +} + +#endif // wxUSE_STATBMP + +#endif // wxUSE_CONTROLS diff --git a/Externals/wxWidgets/src/common/ctrlsub.cpp b/Externals/wxWidgets/src/common/ctrlsub.cpp index 4a036d39b2..387b174cc2 100644 --- a/Externals/wxWidgets/src/common/ctrlsub.cpp +++ b/Externals/wxWidgets/src/common/ctrlsub.cpp @@ -1,197 +1,197 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: src/common/ctrlsub.cpp -// Purpose: wxItemContainer implementation -// Author: Vadim Zeitlin -// Modified by: -// Created: 22.10.99 -// RCS-ID: $Id: ctrlsub.cpp 39077 2006-05-06 19:05:50Z VZ $ -// Copyright: (c) wxWidgets team -// Licence: wxWindows licence -/////////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_CONTROLS - -#ifndef WX_PRECOMP - #include "wx/ctrlsub.h" - #include "wx/arrstr.h" -#endif - -IMPLEMENT_ABSTRACT_CLASS(wxControlWithItems, wxControl) - -// ============================================================================ -// wxItemContainerImmutable implementation -// ============================================================================ - -wxItemContainerImmutable::~wxItemContainerImmutable() -{ - // this destructor is required for Darwin -} - -// ---------------------------------------------------------------------------- -// selection -// ---------------------------------------------------------------------------- - -wxString wxItemContainerImmutable::GetStringSelection() const -{ - wxString s; - - int sel = GetSelection(); - if ( sel != wxNOT_FOUND ) - s = GetString((unsigned int)sel); - - return s; -} - -bool wxItemContainerImmutable::SetStringSelection(const wxString& s) -{ - const int sel = FindString(s); - if ( sel == wxNOT_FOUND ) - return false; - - SetSelection(sel); - - return true; -} - -wxArrayString wxItemContainerImmutable::GetStrings() const -{ - wxArrayString result; - - const unsigned int count = GetCount(); - result.Alloc(count); - for ( unsigned int n = 0; n < count; n++ ) - result.Add(GetString(n)); - - return result; -} - -// ============================================================================ -// wxItemContainer implementation -// ============================================================================ - -wxItemContainer::~wxItemContainer() -{ - // this destructor is required for Darwin -} - -// ---------------------------------------------------------------------------- -// appending items -// ---------------------------------------------------------------------------- - -void wxItemContainer::Append(const wxArrayString& strings) -{ - const size_t count = strings.GetCount(); - for ( size_t n = 0; n < count; n++ ) - { - Append(strings[n]); - } -} - -int wxItemContainer::Insert(const wxString& item, unsigned int pos, void *clientData) -{ - int n = DoInsert(item, pos); - if ( n != wxNOT_FOUND ) - SetClientData(n, clientData); - - return n; -} - -int wxItemContainer::Insert(const wxString& item, unsigned int pos, wxClientData *clientData) -{ - int n = DoInsert(item, pos); - if ( n != wxNOT_FOUND ) - SetClientObject(n, clientData); - - return n; -} - -// ---------------------------------------------------------------------------- -// client data -// ---------------------------------------------------------------------------- - -void wxItemContainer::SetClientObject(unsigned int n, wxClientData *data) -{ - wxASSERT_MSG( m_clientDataItemsType != wxClientData_Void, - wxT("can't have both object and void client data") ); - - // when we call SetClientObject() for the first time, m_clientDataItemsType - // is still wxClientData_None and so calling DoGetItemClientObject() would - // fail (in addition to being useless) - don't do it - if ( m_clientDataItemsType == wxClientData_Object ) - { - wxClientData *clientDataOld = DoGetItemClientObject(n); - if ( clientDataOld ) - delete clientDataOld; - } - else // m_clientDataItemsType == wxClientData_None - { - // now we have object client data - m_clientDataItemsType = wxClientData_Object; - } - - DoSetItemClientObject(n, data); -} - -wxClientData *wxItemContainer::GetClientObject(unsigned int n) const -{ - wxASSERT_MSG( m_clientDataItemsType == wxClientData_Object, - wxT("this window doesn't have object client data") ); - - return DoGetItemClientObject(n); -} - -void wxItemContainer::SetClientData(unsigned int n, void *data) -{ - wxASSERT_MSG( m_clientDataItemsType != wxClientData_Object, - wxT("can't have both object and void client data") ); - - DoSetItemClientData(n, data); - m_clientDataItemsType = wxClientData_Void; -} - -void *wxItemContainer::GetClientData(unsigned int n) const -{ - wxASSERT_MSG( m_clientDataItemsType == wxClientData_Void, - wxT("this window doesn't have void client data") ); - - return DoGetItemClientData(n); -} - -// ============================================================================ -// wxControlWithItems implementation -// ============================================================================ - -void wxControlWithItems::InitCommandEventWithItems(wxCommandEvent& event, int n) -{ - InitCommandEvent(event); - - if ( n != wxNOT_FOUND ) - { - if ( HasClientObjectData() ) - event.SetClientObject(GetClientObject(n)); - else if ( HasClientUntypedData() ) - event.SetClientData(GetClientData(n)); - } -} - -wxControlWithItems::~wxControlWithItems() -{ - // this destructor is required for Darwin -} - -#endif // wxUSE_CONTROLS +/////////////////////////////////////////////////////////////////////////////// +// Name: src/common/ctrlsub.cpp +// Purpose: wxItemContainer implementation +// Author: Vadim Zeitlin +// Modified by: +// Created: 22.10.99 +// RCS-ID: $Id: ctrlsub.cpp 39077 2006-05-06 19:05:50Z VZ $ +// Copyright: (c) wxWidgets team +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_CONTROLS + +#ifndef WX_PRECOMP + #include "wx/ctrlsub.h" + #include "wx/arrstr.h" +#endif + +IMPLEMENT_ABSTRACT_CLASS(wxControlWithItems, wxControl) + +// ============================================================================ +// wxItemContainerImmutable implementation +// ============================================================================ + +wxItemContainerImmutable::~wxItemContainerImmutable() +{ + // this destructor is required for Darwin +} + +// ---------------------------------------------------------------------------- +// selection +// ---------------------------------------------------------------------------- + +wxString wxItemContainerImmutable::GetStringSelection() const +{ + wxString s; + + int sel = GetSelection(); + if ( sel != wxNOT_FOUND ) + s = GetString((unsigned int)sel); + + return s; +} + +bool wxItemContainerImmutable::SetStringSelection(const wxString& s) +{ + const int sel = FindString(s); + if ( sel == wxNOT_FOUND ) + return false; + + SetSelection(sel); + + return true; +} + +wxArrayString wxItemContainerImmutable::GetStrings() const +{ + wxArrayString result; + + const unsigned int count = GetCount(); + result.Alloc(count); + for ( unsigned int n = 0; n < count; n++ ) + result.Add(GetString(n)); + + return result; +} + +// ============================================================================ +// wxItemContainer implementation +// ============================================================================ + +wxItemContainer::~wxItemContainer() +{ + // this destructor is required for Darwin +} + +// ---------------------------------------------------------------------------- +// appending items +// ---------------------------------------------------------------------------- + +void wxItemContainer::Append(const wxArrayString& strings) +{ + const size_t count = strings.GetCount(); + for ( size_t n = 0; n < count; n++ ) + { + Append(strings[n]); + } +} + +int wxItemContainer::Insert(const wxString& item, unsigned int pos, void *clientData) +{ + int n = DoInsert(item, pos); + if ( n != wxNOT_FOUND ) + SetClientData(n, clientData); + + return n; +} + +int wxItemContainer::Insert(const wxString& item, unsigned int pos, wxClientData *clientData) +{ + int n = DoInsert(item, pos); + if ( n != wxNOT_FOUND ) + SetClientObject(n, clientData); + + return n; +} + +// ---------------------------------------------------------------------------- +// client data +// ---------------------------------------------------------------------------- + +void wxItemContainer::SetClientObject(unsigned int n, wxClientData *data) +{ + wxASSERT_MSG( m_clientDataItemsType != wxClientData_Void, + wxT("can't have both object and void client data") ); + + // when we call SetClientObject() for the first time, m_clientDataItemsType + // is still wxClientData_None and so calling DoGetItemClientObject() would + // fail (in addition to being useless) - don't do it + if ( m_clientDataItemsType == wxClientData_Object ) + { + wxClientData *clientDataOld = DoGetItemClientObject(n); + if ( clientDataOld ) + delete clientDataOld; + } + else // m_clientDataItemsType == wxClientData_None + { + // now we have object client data + m_clientDataItemsType = wxClientData_Object; + } + + DoSetItemClientObject(n, data); +} + +wxClientData *wxItemContainer::GetClientObject(unsigned int n) const +{ + wxASSERT_MSG( m_clientDataItemsType == wxClientData_Object, + wxT("this window doesn't have object client data") ); + + return DoGetItemClientObject(n); +} + +void wxItemContainer::SetClientData(unsigned int n, void *data) +{ + wxASSERT_MSG( m_clientDataItemsType != wxClientData_Object, + wxT("can't have both object and void client data") ); + + DoSetItemClientData(n, data); + m_clientDataItemsType = wxClientData_Void; +} + +void *wxItemContainer::GetClientData(unsigned int n) const +{ + wxASSERT_MSG( m_clientDataItemsType == wxClientData_Void, + wxT("this window doesn't have void client data") ); + + return DoGetItemClientData(n); +} + +// ============================================================================ +// wxControlWithItems implementation +// ============================================================================ + +void wxControlWithItems::InitCommandEventWithItems(wxCommandEvent& event, int n) +{ + InitCommandEvent(event); + + if ( n != wxNOT_FOUND ) + { + if ( HasClientObjectData() ) + event.SetClientObject(GetClientObject(n)); + else if ( HasClientUntypedData() ) + event.SetClientData(GetClientData(n)); + } +} + +wxControlWithItems::~wxControlWithItems() +{ + // this destructor is required for Darwin +} + +#endif // wxUSE_CONTROLS diff --git a/Externals/wxWidgets/src/common/datacmn.cpp b/Externals/wxWidgets/src/common/datacmn.cpp index 55d665ca52..e82b5ead59 100644 --- a/Externals/wxWidgets/src/common/datacmn.cpp +++ b/Externals/wxWidgets/src/common/datacmn.cpp @@ -1,83 +1,83 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: common/datacmn.cpp -// Purpose: contains definitions of various global wxWidgets variables -// Author: Vadim Zeitlin -// Modified by: -// Created: 10.04.03 (from src/*/data.cpp files) -// RCS-ID: $Id: datacmn.cpp 43874 2006-12-09 14:52:59Z VZ $ -// Copyright: (c) 1997-2002 wxWidgets development team -// License: wxWindows license -/////////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#ifndef WX_PRECOMP -#endif // WX_PRECOMP - -#include "wx/accel.h" - -// ============================================================================ -// implementation -// ============================================================================ - -// 'Null' objects -#if wxUSE_ACCEL -wxAcceleratorTable wxNullAcceleratorTable; -#endif // wxUSE_ACCEL - -// Default window names -extern WXDLLEXPORT_DATA(const wxChar) wxButtonNameStr[] = wxT("button"); -extern WXDLLEXPORT_DATA(const wxChar) wxCheckBoxNameStr[] = wxT("check"); -extern WXDLLEXPORT_DATA(const wxChar) wxComboBoxNameStr[] = wxT("comboBox"); -extern WXDLLEXPORT_DATA(const wxChar) wxDialogNameStr[] = wxT("dialog"); -extern WXDLLEXPORT_DATA(const wxChar) wxFrameNameStr[] = wxT("frame"); -extern WXDLLEXPORT_DATA(const wxChar) wxStaticBoxNameStr[] = wxT("groupBox"); -extern WXDLLEXPORT_DATA(const wxChar) wxListBoxNameStr[] = wxT("listBox"); -extern WXDLLEXPORT_DATA(const wxChar) wxStaticLineNameStr[] = wxT("staticLine"); -extern WXDLLEXPORT_DATA(const wxChar) wxStaticTextNameStr[] = wxT("staticText"); -extern WXDLLEXPORT_DATA(const wxChar) wxStaticBitmapNameStr[] = wxT("staticBitmap"); -extern WXDLLEXPORT_DATA(const wxChar) wxNotebookNameStr[] = wxT("notebook"); -extern WXDLLEXPORT_DATA(const wxChar) wxPanelNameStr[] = wxT("panel"); -extern WXDLLEXPORT_DATA(const wxChar) wxRadioBoxNameStr[] = wxT("radioBox"); -extern WXDLLEXPORT_DATA(const wxChar) wxRadioButtonNameStr[] = wxT("radioButton"); -extern WXDLLEXPORT_DATA(const wxChar) wxBitmapRadioButtonNameStr[] = wxT("radioButton"); -extern WXDLLEXPORT_DATA(const wxChar) wxScrollBarNameStr[] = wxT("scrollBar"); -extern WXDLLEXPORT_DATA(const wxChar) wxSliderNameStr[] = wxT("slider"); -extern WXDLLEXPORT_DATA(const wxChar) wxStatusLineNameStr[] = wxT("status_line"); -extern WXDLLEXPORT_DATA(const wxChar) wxTextCtrlNameStr[] = wxT("text"); -extern WXDLLEXPORT_DATA(const wxChar) wxTreeCtrlNameStr[] = wxT("treeCtrl"); -extern WXDLLEXPORT_DATA(const wxChar) wxToolBarNameStr[] = wxT("toolbar"); - -// Default messages -extern WXDLLEXPORT_DATA(const wxChar) wxMessageBoxCaptionStr[] = wxT("Message"); -extern WXDLLEXPORT_DATA(const wxChar) wxFileSelectorPromptStr[] = wxT("Select a file"); -extern WXDLLEXPORT_DATA(const wxChar) wxDirSelectorPromptStr[] = wxT("Select a directory"); - -// Other default strings -extern WXDLLEXPORT_DATA(const wxChar) wxFileSelectorDefaultWildcardStr[] = -#if defined(__WXMSW__) || defined(__OS2__) - wxT("*.*") -#else // Unix/Mac - wxT("*") -#endif - ; -extern WXDLLEXPORT_DATA(const wxChar) wxDirDialogNameStr[] = wxT("wxDirCtrl"); -extern WXDLLEXPORT_DATA(const wxChar) wxDirDialogDefaultFolderStr[] = wxT("/"); - -extern WXDLLEXPORT_DATA(const wxChar) wxFileDialogNameStr[] = wxT("filedlg"); -#if defined(__WXMSW__) || defined(__OS2__) -WXDLLEXPORT_DATA(const wxChar *) wxUserResourceStr = wxT("TEXT"); -#endif +/////////////////////////////////////////////////////////////////////////////// +// Name: common/datacmn.cpp +// Purpose: contains definitions of various global wxWidgets variables +// Author: Vadim Zeitlin +// Modified by: +// Created: 10.04.03 (from src/*/data.cpp files) +// RCS-ID: $Id: datacmn.cpp 43874 2006-12-09 14:52:59Z VZ $ +// Copyright: (c) 1997-2002 wxWidgets development team +// License: wxWindows license +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#ifndef WX_PRECOMP +#endif // WX_PRECOMP + +#include "wx/accel.h" + +// ============================================================================ +// implementation +// ============================================================================ + +// 'Null' objects +#if wxUSE_ACCEL +wxAcceleratorTable wxNullAcceleratorTable; +#endif // wxUSE_ACCEL + +// Default window names +extern WXDLLEXPORT_DATA(const wxChar) wxButtonNameStr[] = wxT("button"); +extern WXDLLEXPORT_DATA(const wxChar) wxCheckBoxNameStr[] = wxT("check"); +extern WXDLLEXPORT_DATA(const wxChar) wxComboBoxNameStr[] = wxT("comboBox"); +extern WXDLLEXPORT_DATA(const wxChar) wxDialogNameStr[] = wxT("dialog"); +extern WXDLLEXPORT_DATA(const wxChar) wxFrameNameStr[] = wxT("frame"); +extern WXDLLEXPORT_DATA(const wxChar) wxStaticBoxNameStr[] = wxT("groupBox"); +extern WXDLLEXPORT_DATA(const wxChar) wxListBoxNameStr[] = wxT("listBox"); +extern WXDLLEXPORT_DATA(const wxChar) wxStaticLineNameStr[] = wxT("staticLine"); +extern WXDLLEXPORT_DATA(const wxChar) wxStaticTextNameStr[] = wxT("staticText"); +extern WXDLLEXPORT_DATA(const wxChar) wxStaticBitmapNameStr[] = wxT("staticBitmap"); +extern WXDLLEXPORT_DATA(const wxChar) wxNotebookNameStr[] = wxT("notebook"); +extern WXDLLEXPORT_DATA(const wxChar) wxPanelNameStr[] = wxT("panel"); +extern WXDLLEXPORT_DATA(const wxChar) wxRadioBoxNameStr[] = wxT("radioBox"); +extern WXDLLEXPORT_DATA(const wxChar) wxRadioButtonNameStr[] = wxT("radioButton"); +extern WXDLLEXPORT_DATA(const wxChar) wxBitmapRadioButtonNameStr[] = wxT("radioButton"); +extern WXDLLEXPORT_DATA(const wxChar) wxScrollBarNameStr[] = wxT("scrollBar"); +extern WXDLLEXPORT_DATA(const wxChar) wxSliderNameStr[] = wxT("slider"); +extern WXDLLEXPORT_DATA(const wxChar) wxStatusLineNameStr[] = wxT("status_line"); +extern WXDLLEXPORT_DATA(const wxChar) wxTextCtrlNameStr[] = wxT("text"); +extern WXDLLEXPORT_DATA(const wxChar) wxTreeCtrlNameStr[] = wxT("treeCtrl"); +extern WXDLLEXPORT_DATA(const wxChar) wxToolBarNameStr[] = wxT("toolbar"); + +// Default messages +extern WXDLLEXPORT_DATA(const wxChar) wxMessageBoxCaptionStr[] = wxT("Message"); +extern WXDLLEXPORT_DATA(const wxChar) wxFileSelectorPromptStr[] = wxT("Select a file"); +extern WXDLLEXPORT_DATA(const wxChar) wxDirSelectorPromptStr[] = wxT("Select a directory"); + +// Other default strings +extern WXDLLEXPORT_DATA(const wxChar) wxFileSelectorDefaultWildcardStr[] = +#if defined(__WXMSW__) || defined(__OS2__) + wxT("*.*") +#else // Unix/Mac + wxT("*") +#endif + ; +extern WXDLLEXPORT_DATA(const wxChar) wxDirDialogNameStr[] = wxT("wxDirCtrl"); +extern WXDLLEXPORT_DATA(const wxChar) wxDirDialogDefaultFolderStr[] = wxT("/"); + +extern WXDLLEXPORT_DATA(const wxChar) wxFileDialogNameStr[] = wxT("filedlg"); +#if defined(__WXMSW__) || defined(__OS2__) +WXDLLEXPORT_DATA(const wxChar *) wxUserResourceStr = wxT("TEXT"); +#endif diff --git a/Externals/wxWidgets/src/common/datavcmn.cpp b/Externals/wxWidgets/src/common/datavcmn.cpp index 1af370d643..00c4cc26fb 100644 --- a/Externals/wxWidgets/src/common/datavcmn.cpp +++ b/Externals/wxWidgets/src/common/datavcmn.cpp @@ -1,911 +1,911 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/datavcmn.cpp -// Purpose: wxDataViewCtrl base classes and common parts -// Author: Robert Roebling -// Created: 2006/02/20 -// RCS-ID: $Id: datavcmn.cpp 41670 2006-10-07 14:15:53Z RR $ -// Copyright: (c) 2006, Robert Roebling -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_DATAVIEWCTRL - -#include "wx/dataview.h" - -#ifndef WX_PRECOMP - #include "wx/log.h" -#endif - -const wxChar wxDataViewCtrlNameStr[] = wxT("dataviewCtrl"); - -// --------------------------------------------------------- -// wxDataViewModel -// --------------------------------------------------------- - -IMPLEMENT_ABSTRACT_CLASS(wxDataViewModel, wxObject) - -// --------------------------------------------------------- -// wxDataViewListModel -// --------------------------------------------------------- - -IMPLEMENT_ABSTRACT_CLASS(wxDataViewListModel, wxDataViewModel) - -wxDataViewListModel::wxDataViewListModel() -{ - m_viewingColumns.DeleteContents( true ); - m_notifiers.DeleteContents( true ); -} - -wxDataViewListModel::~wxDataViewListModel() -{ -} - -bool wxDataViewListModel::RowAppended() -{ - bool ret = true; - - wxList::compatibility_iterator node = m_notifiers.GetFirst(); - while (node) - { - wxDataViewListModelNotifier* notifier = (wxDataViewListModelNotifier*) node->GetData(); - if (!notifier->RowAppended()) - ret = false; - node = node->GetNext(); - } - - return ret; -} - -bool wxDataViewListModel::RowPrepended() -{ - bool ret = true; - - wxList::compatibility_iterator node = m_notifiers.GetFirst(); - while (node) - { - wxDataViewListModelNotifier* notifier = (wxDataViewListModelNotifier*) node->GetData(); - if (!notifier->RowPrepended()) - ret = false; - node = node->GetNext(); - } - - return ret; -} - -bool wxDataViewListModel::RowInserted( unsigned int before ) -{ - bool ret = true; - - wxList::compatibility_iterator node = m_notifiers.GetFirst(); - while (node) - { - wxDataViewListModelNotifier* notifier = (wxDataViewListModelNotifier*) node->GetData(); - if (!notifier->RowInserted(before)) - ret = false; - node = node->GetNext(); - } - - return ret; -} - -bool wxDataViewListModel::RowDeleted( unsigned int row ) -{ - bool ret = true; - - wxList::compatibility_iterator node = m_notifiers.GetFirst(); - while (node) - { - wxDataViewListModelNotifier* notifier = (wxDataViewListModelNotifier*) node->GetData(); - if (!notifier->RowDeleted( row )) - ret = false; - node = node->GetNext(); - } - - return ret; -} - -bool wxDataViewListModel::RowChanged( unsigned int row ) -{ - bool ret = true; - - wxList::compatibility_iterator node = m_notifiers.GetFirst(); - while (node) - { - wxDataViewListModelNotifier* notifier = (wxDataViewListModelNotifier*) node->GetData(); - if (!notifier->RowChanged( row )) - ret = false; - node = node->GetNext(); - } - - return ret; -} - -bool wxDataViewListModel::ValueChanged( unsigned int col, unsigned int row ) -{ - bool ret = true; - - wxList::compatibility_iterator node = m_notifiers.GetFirst(); - while (node) - { - wxDataViewListModelNotifier* notifier = (wxDataViewListModelNotifier*) node->GetData(); - if (!notifier->ValueChanged( col, row )) - ret = false; - node = node->GetNext(); - } - - return ret; -} - -bool wxDataViewListModel::RowsReordered( unsigned int *new_order ) -{ - bool ret = true; - - wxList::compatibility_iterator node = m_notifiers.GetFirst(); - while (node) - { - wxDataViewListModelNotifier* notifier = (wxDataViewListModelNotifier*) node->GetData(); - if (!notifier->RowsReordered( new_order )) - ret = false; - node = node->GetNext(); - } - - return ret; -} - -bool wxDataViewListModel::Cleared() -{ - bool ret = true; - - wxList::compatibility_iterator node = m_notifiers.GetFirst(); - while (node) - { - wxDataViewListModelNotifier* notifier = (wxDataViewListModelNotifier*) node->GetData(); - if (!notifier->Cleared()) - ret = false; - node = node->GetNext(); - } - - return ret; -} - -void wxDataViewListModel::AddViewingColumn( wxDataViewColumn *view_column, unsigned int model_column ) -{ - m_viewingColumns.Append( new wxDataViewViewingColumn( view_column, model_column ) ); -} - -void wxDataViewListModel::RemoveViewingColumn( wxDataViewColumn *column ) -{ - wxList::compatibility_iterator node = m_viewingColumns.GetFirst(); - while (node) - { - wxDataViewViewingColumn* tmp = (wxDataViewViewingColumn*) node->GetData(); - - if (tmp->m_viewColumn == column) - { - m_viewingColumns.DeleteObject( tmp ); - return; - } - - node = node->GetNext(); - } -} - -void wxDataViewListModel::AddNotifier( wxDataViewListModelNotifier *notifier ) -{ - m_notifiers.Append( notifier ); - notifier->SetOwner( this ); -} - -void wxDataViewListModel::RemoveNotifier( wxDataViewListModelNotifier *notifier ) -{ - m_notifiers.DeleteObject( notifier ); -} - -// --------------------------------------------------------- -// wxDataViewSortedListModelNotifier -// --------------------------------------------------------- - -class wxDataViewSortedListModelNotifier: public wxDataViewListModelNotifier -{ -public: - wxDataViewSortedListModelNotifier( wxDataViewSortedListModel *model ) - { m_model = model; } - - virtual bool RowAppended() - { return m_model->ChildRowAppended(); } - - virtual bool RowPrepended() - { return m_model->ChildRowPrepended(); } - - virtual bool RowInserted( unsigned int before ) - { return m_model->ChildRowInserted( before ); } - - virtual bool RowDeleted( unsigned int row ) - { return m_model->ChildRowDeleted( row ); } - - virtual bool RowChanged( unsigned int row ) - { return m_model->ChildRowChanged( row ); } - - virtual bool ValueChanged( unsigned int col, unsigned int row ) - { return m_model->ChildValueChanged( col, row); } - - virtual bool RowsReordered( unsigned int *new_order ) - { return m_model->ChildRowsReordered( new_order ); } - - virtual bool Cleared() - { return m_model->ChildCleared(); } - - wxDataViewSortedListModel *m_model; -}; - -// --------------------------------------------------------- -// wxDataViewSortedListModel compare function -// --------------------------------------------------------- - -int wxCALLBACK wxDataViewListModelSortedDefaultCompare - (unsigned int row1, unsigned int row2, unsigned int col, wxDataViewListModel* model ) -{ - wxVariant value1,value2; - model->GetValue( value1, col, row1 ); - model->GetValue( value2, col, row2 ); - if (value1.GetType() == wxT("string")) - { - wxString str1 = value1.GetString(); - wxString str2 = value2.GetString(); - return str1.Cmp( str2 ); - } - if (value1.GetType() == wxT("long")) - { - long l1 = value1.GetLong(); - long l2 = value2.GetLong(); - return l1-l2; - } - if (value1.GetType() == wxT("double")) - { - double d1 = value1.GetDouble(); - double d2 = value2.GetDouble(); - if (d1 == d2) return 0; - if (d1 < d2) return 1; - return -1; - } - if (value1.GetType() == wxT("datetime")) - { - wxDateTime dt1 = value1.GetDateTime(); - wxDateTime dt2 = value2.GetDateTime(); - if (dt1.IsEqualTo(dt2)) return 0; - if (dt1.IsEarlierThan(dt2)) return 1; - return -1; - } - - return 0; -} - -int wxCALLBACK wxDataViewListModelSortedDefaultCompareDescending - (unsigned int row1, unsigned int row2, unsigned int col, wxDataViewListModel* model ) -{ - return wxDataViewListModelSortedDefaultCompare( row2, row1, col, model ); -} - -static wxDataViewListModelCompare s_CmpFunc; -static wxDataViewListModel *s_CmpModel; -static unsigned int s_CmpCol; - -int LINKAGEMODE wxDataViewIntermediateCmp( unsigned int row1, unsigned int row2 ) -{ - return s_CmpFunc( row1, row2, s_CmpCol, s_CmpModel ); -} - -// --------------------------------------------------------- -// wxDataViewSortedListModel -// --------------------------------------------------------- - -IMPLEMENT_ABSTRACT_CLASS(wxDataViewSortedListModel, wxDataViewListModel) - -wxDataViewSortedListModel::wxDataViewSortedListModel( wxDataViewListModel *child ) : - m_array( wxDataViewIntermediateCmp ) -{ - m_child = child; - - m_ascending = true; - - m_notifierOnChild = new wxDataViewSortedListModelNotifier( this ); - m_child->AddNotifier( m_notifierOnChild ); - - Resort(); -} - -wxDataViewSortedListModel::~wxDataViewSortedListModel() -{ - m_child->RemoveNotifier( m_notifierOnChild ); -} - -// FIXME -void wxDataViewSortedListModel::InitStatics() -{ - s_CmpCol = 0; - s_CmpModel = m_child; - if (m_ascending) - s_CmpFunc = wxDataViewListModelSortedDefaultCompare; - else - s_CmpFunc = wxDataViewListModelSortedDefaultCompareDescending; -} - -void wxDataViewSortedListModel::Resort() -{ - InitStatics(); - - m_array.Clear(); - unsigned int n = m_child->GetNumberOfRows(); - unsigned int i; - for (i = 0; i < n; i++) - m_array.Add( i ); -} - -#if 0 -static void Dump( wxDataViewListModel *model, unsigned int col ) -{ - unsigned int n = model->GetNumberOfRows(); - unsigned int i; - for (i = 0; i < n; i++) - { - wxVariant variant; - model->GetValue( variant, col, i ); - wxString tmp; - tmp = variant.GetString(); - wxPrintf( wxT("%d: %s\n"), (int) i, tmp.c_str() ); - } -} -#endif - -bool wxDataViewSortedListModel::ChildRowAppended() -{ - // no need to fix up array - - unsigned int len = m_array.GetCount(); - - unsigned int pos = m_array.Add( len ); - - if (pos == 0) - return wxDataViewListModel::RowPrepended(); - - if (pos == len) - return wxDataViewListModel::RowAppended(); - - return wxDataViewListModel::RowInserted( pos ); -} - -bool wxDataViewSortedListModel::ChildRowPrepended() -{ - // fix up array - unsigned int i; - unsigned int len = m_array.GetCount(); - for (i = 0; i < len; i++) - { - unsigned int value = m_array[i]; - m_array[i] = value+1; - } - - unsigned int pos = m_array.Add( 0 ); - - if (pos == 0) - return wxDataViewListModel::RowPrepended(); - - if (pos == len) - return wxDataViewListModel::RowAppended(); - - return wxDataViewListModel::RowInserted( pos ); -} - -bool wxDataViewSortedListModel::ChildRowInserted( unsigned int before ) -{ - // fix up array - unsigned int i; - unsigned int len = m_array.GetCount(); - for (i = 0; i < len; i++) - { - unsigned int value = m_array[i]; - if (value >= before) - m_array[i] = value+1; - } - - unsigned int pos = m_array.Add( before ); - - if (pos == 0) - return wxDataViewListModel::RowPrepended(); - - if (pos == len) - return wxDataViewListModel::RowAppended(); - - return wxDataViewListModel::RowInserted( pos ); -} - -bool wxDataViewSortedListModel::ChildRowDeleted( unsigned int row ) -{ - unsigned int i; - unsigned int len = m_array.GetCount(); - int pos = -1; - for (i = 0; i < len; i++) - { - unsigned int value = m_array[i]; - if (value == row) - { - // delete later - pos = (int) i; - } - else - { - // Fix up array - if (value > row) - m_array[i] = value-1; - } - } - - if (pos == -1) - return false; // we should probably assert - - // remove - m_array.RemoveAt( (unsigned int) pos ); - - return wxDataViewListModel::RowDeleted( (unsigned int) pos); -} - -bool wxDataViewSortedListModel::ChildRowChanged( unsigned int row ) -{ - unsigned int i; - unsigned int len = m_array.GetCount(); - - // Remove and readd sorted. Find out at which - // position it was and where it ended. - unsigned int start_pos = 0,end_pos = 0; - for (i = 0; i < len; i++) - if (m_array[i] == row) - { - start_pos = i; - break; - } - m_array.RemoveAt( start_pos ); - m_array.Add( row ); - - for (i = 0; i < len; i++) - if (m_array[i] == row) - { - end_pos = i; - break; - } - - if (end_pos == start_pos) - return wxDataViewListModel::RowChanged( start_pos ); - - // Create an array where order[old] -> new_pos, so that - // if nothing changed order[0] -> 0 etc. - unsigned int *order = new unsigned int[ len ]; - // Fill up initial values. - for (i = 0; i < len; i++) - order[i] = i; - - if (start_pos < end_pos) - { - for (i = start_pos; i < end_pos; i++) - order[i] = order[i+1]; - order[end_pos] = start_pos; - } - else - { - for (i = end_pos; i > start_pos; i--) - order[i] = order[i-1]; - order[start_pos] = end_pos; - } - - wxDataViewListModel::RowsReordered( order ); - - delete [] order; - - return true; -} - -bool wxDataViewSortedListModel::ChildValueChanged( unsigned int col, unsigned int row ) -{ - unsigned int i; - unsigned int len = m_array.GetCount(); - - // Remove and readd sorted. Find out at which - // position it was and where it ended. - unsigned int start_pos = 0,end_pos = 0; - for (i = 0; i < len; i++) - if (m_array[i] == row) - { - start_pos = i; - break; - } - m_array.RemoveAt( start_pos ); - m_array.Add( row ); - - for (i = 0; i < len; i++) - if (m_array[i] == row) - { - end_pos = i; - break; - } - - if (end_pos == start_pos) - return wxDataViewListModel::ValueChanged( col, start_pos ); - - // Create an array where order[old] -> new_pos, so that - // if nothing changed order[0] -> 0 etc. - unsigned int *order = new unsigned int[ len ]; - // Fill up initial values. - for (i = 0; i < len; i++) - order[i] = i; - - if (start_pos < end_pos) - { - for (i = start_pos; i < end_pos; i++) - order[i] = order[i+1]; - order[end_pos] = start_pos; - } - else - { - for (i = end_pos; i > start_pos; i--) - order[i] = order[i-1]; - order[start_pos] = end_pos; - } - - wxDataViewListModel::RowsReordered( order ); - - delete [] order; - - return true; -} - -bool wxDataViewSortedListModel::ChildRowsReordered( unsigned int *WXUNUSED(new_order) ) -{ - // Nothing needs to be done. If the sort criteria - // of this list don't change, the order of the - // items of the child list isn't relevant. - return true; -} - -bool wxDataViewSortedListModel::ChildCleared() -{ - return wxDataViewListModel::Cleared(); -} - -unsigned int wxDataViewSortedListModel::GetNumberOfRows() -{ - return m_array.GetCount(); -} - -unsigned int wxDataViewSortedListModel::GetNumberOfCols() -{ - return m_child->GetNumberOfCols(); -} - -wxString wxDataViewSortedListModel::GetColType( unsigned int col ) -{ - return m_child->GetColType( col ); -} - -void wxDataViewSortedListModel::GetValue( wxVariant &variant, unsigned int col, unsigned int row ) -{ - unsigned int child_row = m_array[row]; - m_child->GetValue( variant, col, child_row ); -} - -bool wxDataViewSortedListModel::SetValue( wxVariant &variant, unsigned int col, unsigned int row ) -{ - unsigned int child_row = m_array[row]; - bool ret = m_child->SetValue( variant, col, child_row ); - - // Do nothing here as the change in the - // child model will be reported back. - - return ret; -} - -bool wxDataViewSortedListModel::RowAppended() -{ - // you can only append - bool ret = m_child->RowAppended(); - - // Do nothing here as the change in the - // child model will be reported back. - - return ret; -} - -bool wxDataViewSortedListModel::RowPrepended() -{ - // you can only append - bool ret = m_child->RowAppended(); - - // Do nothing here as the change in the - // child model will be reported back. - - return ret; -} - -bool wxDataViewSortedListModel::RowInserted( unsigned int WXUNUSED(before) ) -{ - // you can only append - bool ret = m_child->RowAppended(); - - // Do nothing here as the change in the - // child model will be reported back. - - return ret; -} - -bool wxDataViewSortedListModel::RowDeleted( unsigned int row ) -{ - unsigned int child_row = m_array[row]; - - bool ret = m_child->RowDeleted( child_row ); - - // Do nothing here as the change in the - // child model will be reported back. - - return ret; -} - -bool wxDataViewSortedListModel::RowChanged( unsigned int row ) -{ - unsigned int child_row = m_array[row]; - bool ret = m_child->RowChanged( child_row ); - - // Do nothing here as the change in the - // child model will be reported back. - - return ret; -} - -bool wxDataViewSortedListModel::ValueChanged( unsigned int col, unsigned int row ) -{ - unsigned int child_row = m_array[row]; - bool ret = m_child->ValueChanged( col, child_row ); - - // Do nothing here as the change in the - // child model will be reported back. - - return ret; -} - -bool wxDataViewSortedListModel::RowsReordered( unsigned int *WXUNUSED(new_order) ) -{ - // We sort them ourselves. - - return false; -} - -bool wxDataViewSortedListModel::Cleared() -{ - bool ret = m_child->Cleared(); - - // Do nothing here as the change in the - // child model will be reported back. - - return ret; -} - -// --------------------------------------------------------- -// wxDataViewRendererBase -// --------------------------------------------------------- - -IMPLEMENT_ABSTRACT_CLASS(wxDataViewRendererBase, wxObject) - -wxDataViewRendererBase::wxDataViewRendererBase( const wxString &varianttype, wxDataViewCellMode mode ) -{ - m_variantType = varianttype; - m_mode = mode; -} - -// --------------------------------------------------------- -// wxDataViewColumnBase -// --------------------------------------------------------- - -IMPLEMENT_ABSTRACT_CLASS(wxDataViewColumnBase, wxObject) - -wxDataViewColumnBase::wxDataViewColumnBase(const wxString& title, - wxDataViewRenderer *renderer, - unsigned int model_column, - int WXUNUSED(width), - int flags ) -{ - m_renderer = renderer; - m_model_column = model_column; - m_flags = flags; - m_title = title; - m_owner = NULL; - m_renderer->SetOwner( (wxDataViewColumn*) this ); -} - -wxDataViewColumnBase::wxDataViewColumnBase(const wxBitmap& bitmap, - wxDataViewRenderer *renderer, - unsigned int model_column, - int WXUNUSED(width), - int flags ) -{ - m_renderer = renderer; - m_model_column = model_column; - m_flags = flags; - m_bitmap = bitmap; - m_owner = NULL; - m_renderer->SetOwner( (wxDataViewColumn*) this ); -} - -wxDataViewColumnBase::~wxDataViewColumnBase() -{ - if (m_renderer) - delete m_renderer; - - if (GetOwner()) - { - GetOwner()->GetModel()->RemoveViewingColumn( (wxDataViewColumn*) this ); - } -} - -void wxDataViewColumnBase::SetTitle( const wxString &title ) -{ - m_title = title; -} - -wxString wxDataViewColumnBase::GetTitle() -{ - return m_title; -} - -void wxDataViewColumnBase::SetBitmap( const wxBitmap &bitmap ) -{ - m_bitmap = bitmap; -} - -const wxBitmap &wxDataViewColumnBase::GetBitmap() -{ - return m_bitmap; -} - -// --------------------------------------------------------- -// wxDataViewCtrlBase -// --------------------------------------------------------- - -IMPLEMENT_ABSTRACT_CLASS(wxDataViewCtrlBase, wxControl) - -wxDataViewCtrlBase::wxDataViewCtrlBase() -{ - m_model = NULL; - m_cols.DeleteContents( true ); -} - -wxDataViewCtrlBase::~wxDataViewCtrlBase() -{ -} - -bool wxDataViewCtrlBase::AssociateModel( wxDataViewListModel *model ) -{ - m_model = model; - - return true; -} - -wxDataViewListModel* wxDataViewCtrlBase::GetModel() -{ - return m_model; -} - -bool wxDataViewCtrlBase::AppendTextColumn( const wxString &label, unsigned int model_column, - wxDataViewCellMode mode, int width ) -{ - return AppendColumn( new wxDataViewColumn( label, - new wxDataViewTextRenderer( wxT("string"), mode ), model_column, width ) ); -} - -bool wxDataViewCtrlBase::AppendToggleColumn( const wxString &label, unsigned int model_column, - wxDataViewCellMode mode, int width ) -{ - return AppendColumn( new wxDataViewColumn( label, - new wxDataViewToggleRenderer( wxT("bool"), mode ), model_column, width ) ); -} - -bool wxDataViewCtrlBase::AppendProgressColumn( const wxString &label, unsigned int model_column, - wxDataViewCellMode mode, int width ) -{ - return AppendColumn( new wxDataViewColumn( label, - new wxDataViewProgressRenderer( wxEmptyString, wxT("long"), mode ), model_column, width ) ); -} - -bool wxDataViewCtrlBase::AppendDateColumn( const wxString &label, unsigned int model_column, - wxDataViewCellMode mode, int width ) -{ - return AppendColumn( new wxDataViewColumn( label, - new wxDataViewDateRenderer( wxT("datetime"), mode), model_column, width ) ); -} - -bool wxDataViewCtrlBase::AppendBitmapColumn( const wxString &label, unsigned int model_column, - wxDataViewCellMode mode, int width ) -{ - return AppendColumn( new wxDataViewColumn( label, - new wxDataViewBitmapRenderer( wxT("wxBitmap"), mode ), model_column, width ) ); -} - -bool wxDataViewCtrlBase::AppendTextColumn( const wxBitmap &label, unsigned int model_column, - wxDataViewCellMode mode, int width ) -{ - return AppendColumn( new wxDataViewColumn( label, - new wxDataViewTextRenderer( wxT("string"), mode ), model_column, width ) ); -} - -bool wxDataViewCtrlBase::AppendToggleColumn( const wxBitmap &label, unsigned int model_column, - wxDataViewCellMode mode, int width ) -{ - return AppendColumn( new wxDataViewColumn( label, - new wxDataViewToggleRenderer( wxT("bool"), mode ), model_column, width ) ); -} - -bool wxDataViewCtrlBase::AppendProgressColumn( const wxBitmap &label, unsigned int model_column, - wxDataViewCellMode mode, int width ) -{ - return AppendColumn( new wxDataViewColumn( label, - new wxDataViewProgressRenderer( wxEmptyString, wxT("long"), mode ), model_column, width ) ); -} - -bool wxDataViewCtrlBase::AppendDateColumn( const wxBitmap &label, unsigned int model_column, - wxDataViewCellMode mode, int width ) -{ - return AppendColumn( new wxDataViewColumn( label, - new wxDataViewDateRenderer( wxT("datetime"), mode ), model_column, width ) ); -} - -bool wxDataViewCtrlBase::AppendBitmapColumn( const wxBitmap &label, unsigned int model_column, - wxDataViewCellMode mode, int width ) -{ - return AppendColumn( new wxDataViewColumn( label, - new wxDataViewBitmapRenderer( wxT("wxBitmap"), mode ), model_column, width ) ); -} - -bool wxDataViewCtrlBase::AppendColumn( wxDataViewColumn *col ) -{ - m_cols.Append( (wxObject*) col ); - col->SetOwner( (wxDataViewCtrl*) this ); - m_model->AddViewingColumn( col, col->GetModelColumn() ); - return true; -} - -unsigned int wxDataViewCtrlBase::GetNumberOfColumns() -{ - return m_cols.GetCount(); -} - -bool wxDataViewCtrlBase::DeleteColumn( unsigned int WXUNUSED(pos) ) -{ - return false; -} - -bool wxDataViewCtrlBase::ClearColumns() -{ - return false; -} - -wxDataViewColumn* wxDataViewCtrlBase::GetColumn( unsigned int pos ) -{ - return (wxDataViewColumn*) m_cols[ pos ]; -} - -// --------------------------------------------------------- -// wxDataViewEvent -// --------------------------------------------------------- - -IMPLEMENT_DYNAMIC_CLASS(wxDataViewEvent,wxNotifyEvent) - -DEFINE_EVENT_TYPE(wxEVT_COMMAND_DATAVIEW_ROW_SELECTED) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_DATAVIEW_ROW_ACTIVATED) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_DATAVIEW_COLUMN_HEADER_CLICK) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_DATAVIEW_COLUMN_HEADER_RIGHT_CLICK) - - -#endif +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/datavcmn.cpp +// Purpose: wxDataViewCtrl base classes and common parts +// Author: Robert Roebling +// Created: 2006/02/20 +// RCS-ID: $Id: datavcmn.cpp 41670 2006-10-07 14:15:53Z RR $ +// Copyright: (c) 2006, Robert Roebling +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_DATAVIEWCTRL + +#include "wx/dataview.h" + +#ifndef WX_PRECOMP + #include "wx/log.h" +#endif + +const wxChar wxDataViewCtrlNameStr[] = wxT("dataviewCtrl"); + +// --------------------------------------------------------- +// wxDataViewModel +// --------------------------------------------------------- + +IMPLEMENT_ABSTRACT_CLASS(wxDataViewModel, wxObject) + +// --------------------------------------------------------- +// wxDataViewListModel +// --------------------------------------------------------- + +IMPLEMENT_ABSTRACT_CLASS(wxDataViewListModel, wxDataViewModel) + +wxDataViewListModel::wxDataViewListModel() +{ + m_viewingColumns.DeleteContents( true ); + m_notifiers.DeleteContents( true ); +} + +wxDataViewListModel::~wxDataViewListModel() +{ +} + +bool wxDataViewListModel::RowAppended() +{ + bool ret = true; + + wxList::compatibility_iterator node = m_notifiers.GetFirst(); + while (node) + { + wxDataViewListModelNotifier* notifier = (wxDataViewListModelNotifier*) node->GetData(); + if (!notifier->RowAppended()) + ret = false; + node = node->GetNext(); + } + + return ret; +} + +bool wxDataViewListModel::RowPrepended() +{ + bool ret = true; + + wxList::compatibility_iterator node = m_notifiers.GetFirst(); + while (node) + { + wxDataViewListModelNotifier* notifier = (wxDataViewListModelNotifier*) node->GetData(); + if (!notifier->RowPrepended()) + ret = false; + node = node->GetNext(); + } + + return ret; +} + +bool wxDataViewListModel::RowInserted( unsigned int before ) +{ + bool ret = true; + + wxList::compatibility_iterator node = m_notifiers.GetFirst(); + while (node) + { + wxDataViewListModelNotifier* notifier = (wxDataViewListModelNotifier*) node->GetData(); + if (!notifier->RowInserted(before)) + ret = false; + node = node->GetNext(); + } + + return ret; +} + +bool wxDataViewListModel::RowDeleted( unsigned int row ) +{ + bool ret = true; + + wxList::compatibility_iterator node = m_notifiers.GetFirst(); + while (node) + { + wxDataViewListModelNotifier* notifier = (wxDataViewListModelNotifier*) node->GetData(); + if (!notifier->RowDeleted( row )) + ret = false; + node = node->GetNext(); + } + + return ret; +} + +bool wxDataViewListModel::RowChanged( unsigned int row ) +{ + bool ret = true; + + wxList::compatibility_iterator node = m_notifiers.GetFirst(); + while (node) + { + wxDataViewListModelNotifier* notifier = (wxDataViewListModelNotifier*) node->GetData(); + if (!notifier->RowChanged( row )) + ret = false; + node = node->GetNext(); + } + + return ret; +} + +bool wxDataViewListModel::ValueChanged( unsigned int col, unsigned int row ) +{ + bool ret = true; + + wxList::compatibility_iterator node = m_notifiers.GetFirst(); + while (node) + { + wxDataViewListModelNotifier* notifier = (wxDataViewListModelNotifier*) node->GetData(); + if (!notifier->ValueChanged( col, row )) + ret = false; + node = node->GetNext(); + } + + return ret; +} + +bool wxDataViewListModel::RowsReordered( unsigned int *new_order ) +{ + bool ret = true; + + wxList::compatibility_iterator node = m_notifiers.GetFirst(); + while (node) + { + wxDataViewListModelNotifier* notifier = (wxDataViewListModelNotifier*) node->GetData(); + if (!notifier->RowsReordered( new_order )) + ret = false; + node = node->GetNext(); + } + + return ret; +} + +bool wxDataViewListModel::Cleared() +{ + bool ret = true; + + wxList::compatibility_iterator node = m_notifiers.GetFirst(); + while (node) + { + wxDataViewListModelNotifier* notifier = (wxDataViewListModelNotifier*) node->GetData(); + if (!notifier->Cleared()) + ret = false; + node = node->GetNext(); + } + + return ret; +} + +void wxDataViewListModel::AddViewingColumn( wxDataViewColumn *view_column, unsigned int model_column ) +{ + m_viewingColumns.Append( new wxDataViewViewingColumn( view_column, model_column ) ); +} + +void wxDataViewListModel::RemoveViewingColumn( wxDataViewColumn *column ) +{ + wxList::compatibility_iterator node = m_viewingColumns.GetFirst(); + while (node) + { + wxDataViewViewingColumn* tmp = (wxDataViewViewingColumn*) node->GetData(); + + if (tmp->m_viewColumn == column) + { + m_viewingColumns.DeleteObject( tmp ); + return; + } + + node = node->GetNext(); + } +} + +void wxDataViewListModel::AddNotifier( wxDataViewListModelNotifier *notifier ) +{ + m_notifiers.Append( notifier ); + notifier->SetOwner( this ); +} + +void wxDataViewListModel::RemoveNotifier( wxDataViewListModelNotifier *notifier ) +{ + m_notifiers.DeleteObject( notifier ); +} + +// --------------------------------------------------------- +// wxDataViewSortedListModelNotifier +// --------------------------------------------------------- + +class wxDataViewSortedListModelNotifier: public wxDataViewListModelNotifier +{ +public: + wxDataViewSortedListModelNotifier( wxDataViewSortedListModel *model ) + { m_model = model; } + + virtual bool RowAppended() + { return m_model->ChildRowAppended(); } + + virtual bool RowPrepended() + { return m_model->ChildRowPrepended(); } + + virtual bool RowInserted( unsigned int before ) + { return m_model->ChildRowInserted( before ); } + + virtual bool RowDeleted( unsigned int row ) + { return m_model->ChildRowDeleted( row ); } + + virtual bool RowChanged( unsigned int row ) + { return m_model->ChildRowChanged( row ); } + + virtual bool ValueChanged( unsigned int col, unsigned int row ) + { return m_model->ChildValueChanged( col, row); } + + virtual bool RowsReordered( unsigned int *new_order ) + { return m_model->ChildRowsReordered( new_order ); } + + virtual bool Cleared() + { return m_model->ChildCleared(); } + + wxDataViewSortedListModel *m_model; +}; + +// --------------------------------------------------------- +// wxDataViewSortedListModel compare function +// --------------------------------------------------------- + +int wxCALLBACK wxDataViewListModelSortedDefaultCompare + (unsigned int row1, unsigned int row2, unsigned int col, wxDataViewListModel* model ) +{ + wxVariant value1,value2; + model->GetValue( value1, col, row1 ); + model->GetValue( value2, col, row2 ); + if (value1.GetType() == wxT("string")) + { + wxString str1 = value1.GetString(); + wxString str2 = value2.GetString(); + return str1.Cmp( str2 ); + } + if (value1.GetType() == wxT("long")) + { + long l1 = value1.GetLong(); + long l2 = value2.GetLong(); + return l1-l2; + } + if (value1.GetType() == wxT("double")) + { + double d1 = value1.GetDouble(); + double d2 = value2.GetDouble(); + if (d1 == d2) return 0; + if (d1 < d2) return 1; + return -1; + } + if (value1.GetType() == wxT("datetime")) + { + wxDateTime dt1 = value1.GetDateTime(); + wxDateTime dt2 = value2.GetDateTime(); + if (dt1.IsEqualTo(dt2)) return 0; + if (dt1.IsEarlierThan(dt2)) return 1; + return -1; + } + + return 0; +} + +int wxCALLBACK wxDataViewListModelSortedDefaultCompareDescending + (unsigned int row1, unsigned int row2, unsigned int col, wxDataViewListModel* model ) +{ + return wxDataViewListModelSortedDefaultCompare( row2, row1, col, model ); +} + +static wxDataViewListModelCompare s_CmpFunc; +static wxDataViewListModel *s_CmpModel; +static unsigned int s_CmpCol; + +int LINKAGEMODE wxDataViewIntermediateCmp( unsigned int row1, unsigned int row2 ) +{ + return s_CmpFunc( row1, row2, s_CmpCol, s_CmpModel ); +} + +// --------------------------------------------------------- +// wxDataViewSortedListModel +// --------------------------------------------------------- + +IMPLEMENT_ABSTRACT_CLASS(wxDataViewSortedListModel, wxDataViewListModel) + +wxDataViewSortedListModel::wxDataViewSortedListModel( wxDataViewListModel *child ) : + m_array( wxDataViewIntermediateCmp ) +{ + m_child = child; + + m_ascending = true; + + m_notifierOnChild = new wxDataViewSortedListModelNotifier( this ); + m_child->AddNotifier( m_notifierOnChild ); + + Resort(); +} + +wxDataViewSortedListModel::~wxDataViewSortedListModel() +{ + m_child->RemoveNotifier( m_notifierOnChild ); +} + +// FIXME +void wxDataViewSortedListModel::InitStatics() +{ + s_CmpCol = 0; + s_CmpModel = m_child; + if (m_ascending) + s_CmpFunc = wxDataViewListModelSortedDefaultCompare; + else + s_CmpFunc = wxDataViewListModelSortedDefaultCompareDescending; +} + +void wxDataViewSortedListModel::Resort() +{ + InitStatics(); + + m_array.Clear(); + unsigned int n = m_child->GetNumberOfRows(); + unsigned int i; + for (i = 0; i < n; i++) + m_array.Add( i ); +} + +#if 0 +static void Dump( wxDataViewListModel *model, unsigned int col ) +{ + unsigned int n = model->GetNumberOfRows(); + unsigned int i; + for (i = 0; i < n; i++) + { + wxVariant variant; + model->GetValue( variant, col, i ); + wxString tmp; + tmp = variant.GetString(); + wxPrintf( wxT("%d: %s\n"), (int) i, tmp.c_str() ); + } +} +#endif + +bool wxDataViewSortedListModel::ChildRowAppended() +{ + // no need to fix up array + + unsigned int len = m_array.GetCount(); + + unsigned int pos = m_array.Add( len ); + + if (pos == 0) + return wxDataViewListModel::RowPrepended(); + + if (pos == len) + return wxDataViewListModel::RowAppended(); + + return wxDataViewListModel::RowInserted( pos ); +} + +bool wxDataViewSortedListModel::ChildRowPrepended() +{ + // fix up array + unsigned int i; + unsigned int len = m_array.GetCount(); + for (i = 0; i < len; i++) + { + unsigned int value = m_array[i]; + m_array[i] = value+1; + } + + unsigned int pos = m_array.Add( 0 ); + + if (pos == 0) + return wxDataViewListModel::RowPrepended(); + + if (pos == len) + return wxDataViewListModel::RowAppended(); + + return wxDataViewListModel::RowInserted( pos ); +} + +bool wxDataViewSortedListModel::ChildRowInserted( unsigned int before ) +{ + // fix up array + unsigned int i; + unsigned int len = m_array.GetCount(); + for (i = 0; i < len; i++) + { + unsigned int value = m_array[i]; + if (value >= before) + m_array[i] = value+1; + } + + unsigned int pos = m_array.Add( before ); + + if (pos == 0) + return wxDataViewListModel::RowPrepended(); + + if (pos == len) + return wxDataViewListModel::RowAppended(); + + return wxDataViewListModel::RowInserted( pos ); +} + +bool wxDataViewSortedListModel::ChildRowDeleted( unsigned int row ) +{ + unsigned int i; + unsigned int len = m_array.GetCount(); + int pos = -1; + for (i = 0; i < len; i++) + { + unsigned int value = m_array[i]; + if (value == row) + { + // delete later + pos = (int) i; + } + else + { + // Fix up array + if (value > row) + m_array[i] = value-1; + } + } + + if (pos == -1) + return false; // we should probably assert + + // remove + m_array.RemoveAt( (unsigned int) pos ); + + return wxDataViewListModel::RowDeleted( (unsigned int) pos); +} + +bool wxDataViewSortedListModel::ChildRowChanged( unsigned int row ) +{ + unsigned int i; + unsigned int len = m_array.GetCount(); + + // Remove and readd sorted. Find out at which + // position it was and where it ended. + unsigned int start_pos = 0,end_pos = 0; + for (i = 0; i < len; i++) + if (m_array[i] == row) + { + start_pos = i; + break; + } + m_array.RemoveAt( start_pos ); + m_array.Add( row ); + + for (i = 0; i < len; i++) + if (m_array[i] == row) + { + end_pos = i; + break; + } + + if (end_pos == start_pos) + return wxDataViewListModel::RowChanged( start_pos ); + + // Create an array where order[old] -> new_pos, so that + // if nothing changed order[0] -> 0 etc. + unsigned int *order = new unsigned int[ len ]; + // Fill up initial values. + for (i = 0; i < len; i++) + order[i] = i; + + if (start_pos < end_pos) + { + for (i = start_pos; i < end_pos; i++) + order[i] = order[i+1]; + order[end_pos] = start_pos; + } + else + { + for (i = end_pos; i > start_pos; i--) + order[i] = order[i-1]; + order[start_pos] = end_pos; + } + + wxDataViewListModel::RowsReordered( order ); + + delete [] order; + + return true; +} + +bool wxDataViewSortedListModel::ChildValueChanged( unsigned int col, unsigned int row ) +{ + unsigned int i; + unsigned int len = m_array.GetCount(); + + // Remove and readd sorted. Find out at which + // position it was and where it ended. + unsigned int start_pos = 0,end_pos = 0; + for (i = 0; i < len; i++) + if (m_array[i] == row) + { + start_pos = i; + break; + } + m_array.RemoveAt( start_pos ); + m_array.Add( row ); + + for (i = 0; i < len; i++) + if (m_array[i] == row) + { + end_pos = i; + break; + } + + if (end_pos == start_pos) + return wxDataViewListModel::ValueChanged( col, start_pos ); + + // Create an array where order[old] -> new_pos, so that + // if nothing changed order[0] -> 0 etc. + unsigned int *order = new unsigned int[ len ]; + // Fill up initial values. + for (i = 0; i < len; i++) + order[i] = i; + + if (start_pos < end_pos) + { + for (i = start_pos; i < end_pos; i++) + order[i] = order[i+1]; + order[end_pos] = start_pos; + } + else + { + for (i = end_pos; i > start_pos; i--) + order[i] = order[i-1]; + order[start_pos] = end_pos; + } + + wxDataViewListModel::RowsReordered( order ); + + delete [] order; + + return true; +} + +bool wxDataViewSortedListModel::ChildRowsReordered( unsigned int *WXUNUSED(new_order) ) +{ + // Nothing needs to be done. If the sort criteria + // of this list don't change, the order of the + // items of the child list isn't relevant. + return true; +} + +bool wxDataViewSortedListModel::ChildCleared() +{ + return wxDataViewListModel::Cleared(); +} + +unsigned int wxDataViewSortedListModel::GetNumberOfRows() +{ + return m_array.GetCount(); +} + +unsigned int wxDataViewSortedListModel::GetNumberOfCols() +{ + return m_child->GetNumberOfCols(); +} + +wxString wxDataViewSortedListModel::GetColType( unsigned int col ) +{ + return m_child->GetColType( col ); +} + +void wxDataViewSortedListModel::GetValue( wxVariant &variant, unsigned int col, unsigned int row ) +{ + unsigned int child_row = m_array[row]; + m_child->GetValue( variant, col, child_row ); +} + +bool wxDataViewSortedListModel::SetValue( wxVariant &variant, unsigned int col, unsigned int row ) +{ + unsigned int child_row = m_array[row]; + bool ret = m_child->SetValue( variant, col, child_row ); + + // Do nothing here as the change in the + // child model will be reported back. + + return ret; +} + +bool wxDataViewSortedListModel::RowAppended() +{ + // you can only append + bool ret = m_child->RowAppended(); + + // Do nothing here as the change in the + // child model will be reported back. + + return ret; +} + +bool wxDataViewSortedListModel::RowPrepended() +{ + // you can only append + bool ret = m_child->RowAppended(); + + // Do nothing here as the change in the + // child model will be reported back. + + return ret; +} + +bool wxDataViewSortedListModel::RowInserted( unsigned int WXUNUSED(before) ) +{ + // you can only append + bool ret = m_child->RowAppended(); + + // Do nothing here as the change in the + // child model will be reported back. + + return ret; +} + +bool wxDataViewSortedListModel::RowDeleted( unsigned int row ) +{ + unsigned int child_row = m_array[row]; + + bool ret = m_child->RowDeleted( child_row ); + + // Do nothing here as the change in the + // child model will be reported back. + + return ret; +} + +bool wxDataViewSortedListModel::RowChanged( unsigned int row ) +{ + unsigned int child_row = m_array[row]; + bool ret = m_child->RowChanged( child_row ); + + // Do nothing here as the change in the + // child model will be reported back. + + return ret; +} + +bool wxDataViewSortedListModel::ValueChanged( unsigned int col, unsigned int row ) +{ + unsigned int child_row = m_array[row]; + bool ret = m_child->ValueChanged( col, child_row ); + + // Do nothing here as the change in the + // child model will be reported back. + + return ret; +} + +bool wxDataViewSortedListModel::RowsReordered( unsigned int *WXUNUSED(new_order) ) +{ + // We sort them ourselves. + + return false; +} + +bool wxDataViewSortedListModel::Cleared() +{ + bool ret = m_child->Cleared(); + + // Do nothing here as the change in the + // child model will be reported back. + + return ret; +} + +// --------------------------------------------------------- +// wxDataViewRendererBase +// --------------------------------------------------------- + +IMPLEMENT_ABSTRACT_CLASS(wxDataViewRendererBase, wxObject) + +wxDataViewRendererBase::wxDataViewRendererBase( const wxString &varianttype, wxDataViewCellMode mode ) +{ + m_variantType = varianttype; + m_mode = mode; +} + +// --------------------------------------------------------- +// wxDataViewColumnBase +// --------------------------------------------------------- + +IMPLEMENT_ABSTRACT_CLASS(wxDataViewColumnBase, wxObject) + +wxDataViewColumnBase::wxDataViewColumnBase(const wxString& title, + wxDataViewRenderer *renderer, + unsigned int model_column, + int WXUNUSED(width), + int flags ) +{ + m_renderer = renderer; + m_model_column = model_column; + m_flags = flags; + m_title = title; + m_owner = NULL; + m_renderer->SetOwner( (wxDataViewColumn*) this ); +} + +wxDataViewColumnBase::wxDataViewColumnBase(const wxBitmap& bitmap, + wxDataViewRenderer *renderer, + unsigned int model_column, + int WXUNUSED(width), + int flags ) +{ + m_renderer = renderer; + m_model_column = model_column; + m_flags = flags; + m_bitmap = bitmap; + m_owner = NULL; + m_renderer->SetOwner( (wxDataViewColumn*) this ); +} + +wxDataViewColumnBase::~wxDataViewColumnBase() +{ + if (m_renderer) + delete m_renderer; + + if (GetOwner()) + { + GetOwner()->GetModel()->RemoveViewingColumn( (wxDataViewColumn*) this ); + } +} + +void wxDataViewColumnBase::SetTitle( const wxString &title ) +{ + m_title = title; +} + +wxString wxDataViewColumnBase::GetTitle() +{ + return m_title; +} + +void wxDataViewColumnBase::SetBitmap( const wxBitmap &bitmap ) +{ + m_bitmap = bitmap; +} + +const wxBitmap &wxDataViewColumnBase::GetBitmap() +{ + return m_bitmap; +} + +// --------------------------------------------------------- +// wxDataViewCtrlBase +// --------------------------------------------------------- + +IMPLEMENT_ABSTRACT_CLASS(wxDataViewCtrlBase, wxControl) + +wxDataViewCtrlBase::wxDataViewCtrlBase() +{ + m_model = NULL; + m_cols.DeleteContents( true ); +} + +wxDataViewCtrlBase::~wxDataViewCtrlBase() +{ +} + +bool wxDataViewCtrlBase::AssociateModel( wxDataViewListModel *model ) +{ + m_model = model; + + return true; +} + +wxDataViewListModel* wxDataViewCtrlBase::GetModel() +{ + return m_model; +} + +bool wxDataViewCtrlBase::AppendTextColumn( const wxString &label, unsigned int model_column, + wxDataViewCellMode mode, int width ) +{ + return AppendColumn( new wxDataViewColumn( label, + new wxDataViewTextRenderer( wxT("string"), mode ), model_column, width ) ); +} + +bool wxDataViewCtrlBase::AppendToggleColumn( const wxString &label, unsigned int model_column, + wxDataViewCellMode mode, int width ) +{ + return AppendColumn( new wxDataViewColumn( label, + new wxDataViewToggleRenderer( wxT("bool"), mode ), model_column, width ) ); +} + +bool wxDataViewCtrlBase::AppendProgressColumn( const wxString &label, unsigned int model_column, + wxDataViewCellMode mode, int width ) +{ + return AppendColumn( new wxDataViewColumn( label, + new wxDataViewProgressRenderer( wxEmptyString, wxT("long"), mode ), model_column, width ) ); +} + +bool wxDataViewCtrlBase::AppendDateColumn( const wxString &label, unsigned int model_column, + wxDataViewCellMode mode, int width ) +{ + return AppendColumn( new wxDataViewColumn( label, + new wxDataViewDateRenderer( wxT("datetime"), mode), model_column, width ) ); +} + +bool wxDataViewCtrlBase::AppendBitmapColumn( const wxString &label, unsigned int model_column, + wxDataViewCellMode mode, int width ) +{ + return AppendColumn( new wxDataViewColumn( label, + new wxDataViewBitmapRenderer( wxT("wxBitmap"), mode ), model_column, width ) ); +} + +bool wxDataViewCtrlBase::AppendTextColumn( const wxBitmap &label, unsigned int model_column, + wxDataViewCellMode mode, int width ) +{ + return AppendColumn( new wxDataViewColumn( label, + new wxDataViewTextRenderer( wxT("string"), mode ), model_column, width ) ); +} + +bool wxDataViewCtrlBase::AppendToggleColumn( const wxBitmap &label, unsigned int model_column, + wxDataViewCellMode mode, int width ) +{ + return AppendColumn( new wxDataViewColumn( label, + new wxDataViewToggleRenderer( wxT("bool"), mode ), model_column, width ) ); +} + +bool wxDataViewCtrlBase::AppendProgressColumn( const wxBitmap &label, unsigned int model_column, + wxDataViewCellMode mode, int width ) +{ + return AppendColumn( new wxDataViewColumn( label, + new wxDataViewProgressRenderer( wxEmptyString, wxT("long"), mode ), model_column, width ) ); +} + +bool wxDataViewCtrlBase::AppendDateColumn( const wxBitmap &label, unsigned int model_column, + wxDataViewCellMode mode, int width ) +{ + return AppendColumn( new wxDataViewColumn( label, + new wxDataViewDateRenderer( wxT("datetime"), mode ), model_column, width ) ); +} + +bool wxDataViewCtrlBase::AppendBitmapColumn( const wxBitmap &label, unsigned int model_column, + wxDataViewCellMode mode, int width ) +{ + return AppendColumn( new wxDataViewColumn( label, + new wxDataViewBitmapRenderer( wxT("wxBitmap"), mode ), model_column, width ) ); +} + +bool wxDataViewCtrlBase::AppendColumn( wxDataViewColumn *col ) +{ + m_cols.Append( (wxObject*) col ); + col->SetOwner( (wxDataViewCtrl*) this ); + m_model->AddViewingColumn( col, col->GetModelColumn() ); + return true; +} + +unsigned int wxDataViewCtrlBase::GetNumberOfColumns() +{ + return m_cols.GetCount(); +} + +bool wxDataViewCtrlBase::DeleteColumn( unsigned int WXUNUSED(pos) ) +{ + return false; +} + +bool wxDataViewCtrlBase::ClearColumns() +{ + return false; +} + +wxDataViewColumn* wxDataViewCtrlBase::GetColumn( unsigned int pos ) +{ + return (wxDataViewColumn*) m_cols[ pos ]; +} + +// --------------------------------------------------------- +// wxDataViewEvent +// --------------------------------------------------------- + +IMPLEMENT_DYNAMIC_CLASS(wxDataViewEvent,wxNotifyEvent) + +DEFINE_EVENT_TYPE(wxEVT_COMMAND_DATAVIEW_ROW_SELECTED) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_DATAVIEW_ROW_ACTIVATED) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_DATAVIEW_COLUMN_HEADER_CLICK) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_DATAVIEW_COLUMN_HEADER_RIGHT_CLICK) + + +#endif diff --git a/Externals/wxWidgets/src/common/datetime.cpp b/Externals/wxWidgets/src/common/datetime.cpp index d5c5cebcdd..616d6463c2 100644 --- a/Externals/wxWidgets/src/common/datetime.cpp +++ b/Externals/wxWidgets/src/common/datetime.cpp @@ -1,4630 +1,4630 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: src/common/datetime.cpp -// Purpose: implementation of time/date related classes -// Author: Vadim Zeitlin -// Modified by: -// Created: 11.05.99 -// RCS-ID: $Id: datetime.cpp 53900 2008-06-01 14:37:26Z VZ $ -// Copyright: (c) 1999 Vadim Zeitlin -// parts of code taken from sndcal library by Scott E. Lee: -// -// Copyright 1993-1995, Scott E. Lee, all rights reserved. -// Permission granted to use, copy, modify, distribute and sell -// so long as the above copyright and this permission statement -// are retained in all copies. -// -// Licence: wxWindows licence -/////////////////////////////////////////////////////////////////////////////// - -/* - * Implementation notes: - * - * 1. the time is stored as a 64bit integer containing the signed number of - * milliseconds since Jan 1. 1970 (the Unix Epoch) - so it is always - * expressed in GMT. - * - * 2. the range is thus something about 580 million years, but due to current - * algorithms limitations, only dates from Nov 24, 4714BC are handled - * - * 3. standard ANSI C functions are used to do time calculations whenever - * possible, i.e. when the date is in the range Jan 1, 1970 to 2038 - * - * 4. otherwise, the calculations are done by converting the date to/from JDN - * first (the range limitation mentioned above comes from here: the - * algorithm used by Scott E. Lee's code only works for positive JDNs, more - * or less) - * - * 5. the object constructed for the given DD-MM-YYYY HH:MM:SS corresponds to - * this moment in local time and may be converted to the object - * corresponding to the same date/time in another time zone by using - * ToTimezone() - * - * 6. the conversions to the current (or any other) timezone are done when the - * internal time representation is converted to the broken-down one in - * wxDateTime::Tm. - */ - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if !defined(wxUSE_DATETIME) || wxUSE_DATETIME - -#ifndef WX_PRECOMP - #ifdef __WXMSW__ - #include "wx/msw/wrapwin.h" - #endif - #include "wx/string.h" - #include "wx/log.h" - #include "wx/intl.h" - #include "wx/stopwatch.h" // for wxGetLocalTimeMillis() - #include "wx/module.h" -#endif // WX_PRECOMP - -#include "wx/thread.h" -#include "wx/tokenzr.h" - -#include - -#ifdef __WINDOWS__ - #include - #ifndef __WXWINCE__ - #include - #endif -#endif - -#include "wx/datetime.h" - -const long wxDateTime::TIME_T_FACTOR = 1000l; - -#if wxUSE_EXTENDED_RTTI - -template<> void wxStringReadValue(const wxString &s , wxDateTime &data ) -{ - data.ParseFormat(s,wxT("%Y-%m-%d %H:%M:%S")) ; -} - -template<> void wxStringWriteValue(wxString &s , const wxDateTime &data ) -{ - s = data.Format(wxT("%Y-%m-%d %H:%M:%S")) ; -} - -wxCUSTOM_TYPE_INFO(wxDateTime, wxToStringConverter , wxFromStringConverter) - -#endif - -// -// ---------------------------------------------------------------------------- -// conditional compilation -// ---------------------------------------------------------------------------- - -#if defined(HAVE_STRPTIME) && defined(__GLIBC__) && \ - ((__GLIBC__ == 2) && (__GLIBC_MINOR__ == 0)) - // glibc 2.0.7 strptime() is broken - the following snippet causes it to - // crash (instead of just failing): - // - // strncpy(buf, "Tue Dec 21 20:25:40 1999", 128); - // strptime(buf, "%x", &tm); - // - // so don't use it - #undef HAVE_STRPTIME -#endif // broken strptime() - -#if defined(HAVE_STRPTIME) && defined(__DARWIN__) && defined(_MSL_USING_MW_C_HEADERS) && _MSL_USING_MW_C_HEADERS - // configure detects strptime as linkable because it's in the OS X - // System library but MSL headers don't declare it. - -// char *strptime(const char *, const char *, struct tm *); - // However, we DON'T want to just provide it here because we would - // crash and/or overwrite data when strptime from OS X tries - // to fill in MW's struct tm which is two fields shorter (no TZ stuff) - // So for now let's just say we don't have strptime - #undef HAVE_STRPTIME -#endif - -#if defined(__MWERKS__) && wxUSE_UNICODE - #include -#endif - -// define a special symbol for VC8 instead of writing tests for 1400 repeatedly -#ifdef __VISUALC__ - #if __VISUALC__ >= 1400 - #define __VISUALC8__ - #endif -#endif - -#if !defined(WX_TIMEZONE) && !defined(WX_GMTOFF_IN_TM) - #if defined(__WXPALMOS__) - #define WX_GMTOFF_IN_TM - #elif defined(__BORLANDC__) || defined(__MINGW32__) || defined(__VISAGECPP__) - #define WX_TIMEZONE _timezone - #elif defined(__MWERKS__) - long wxmw_timezone = 28800; - #define WX_TIMEZONE wxmw_timezone - #elif defined(__DJGPP__) || defined(__WINE__) - #include - #include - static long wxGetTimeZone() - { - static long timezone = MAXLONG; // invalid timezone - if (timezone == MAXLONG) - { - struct timeb tb; - ftime(&tb); - timezone = tb.timezone; - } - return timezone; - } - #define WX_TIMEZONE wxGetTimeZone() - #elif defined(__DARWIN__) - #define WX_GMTOFF_IN_TM - #elif defined(__WXWINCE__) && defined(__VISUALC8__) - // _timezone is not present in dynamic run-time library - #if 0 - // Solution (1): use the function equivalent of _timezone - static long wxGetTimeZone() - { - static long s_Timezone = MAXLONG; // invalid timezone - if (s_Timezone == MAXLONG) - { - int t; - _get_timezone(& t); - s_Timezone = (long) t; - } - return s_Timezone; - } - #define WX_TIMEZONE wxGetTimeZone() - #elif 1 - // Solution (2): using GetTimeZoneInformation - static long wxGetTimeZone() - { - static long timezone = MAXLONG; // invalid timezone - if (timezone == MAXLONG) - { - TIME_ZONE_INFORMATION tzi; - ::GetTimeZoneInformation(&tzi); - timezone = tzi.Bias; - } - return timezone; - } - #define WX_TIMEZONE wxGetTimeZone() - #endif - #else // unknown platform - try timezone - #define WX_TIMEZONE timezone - #endif -#endif // !WX_TIMEZONE && !WX_GMTOFF_IN_TM - -// everyone has strftime except Win CE unless VC8 is used -#if !defined(__WXWINCE__) || defined(__VISUALC8__) - #define HAVE_STRFTIME -#endif - -// NB: VC8 safe time functions could/should be used for wxMSW as well probably -#if defined(__WXWINCE__) && defined(__VISUALC8__) - -struct tm *wxLocaltime_r(const time_t *t, struct tm* tm) -{ - __time64_t t64 = *t; - return _localtime64_s(tm, &t64) == 0 ? tm : NULL; -} - -struct tm *wxGmtime_r(const time_t* t, struct tm* tm) -{ - __time64_t t64 = *t; - return _gmtime64_s(tm, &t64) == 0 ? tm : NULL; -} - -#else // !wxWinCE with VC8 - -#if (!defined(HAVE_LOCALTIME_R) || !defined(HAVE_GMTIME_R)) && wxUSE_THREADS && !defined(__WINDOWS__) -static wxMutex timeLock; -#endif - -#ifndef HAVE_LOCALTIME_R -struct tm *wxLocaltime_r(const time_t* ticks, struct tm* temp) -{ -#if wxUSE_THREADS && !defined(__WINDOWS__) - // No need to waste time with a mutex on windows since it's using - // thread local storage for localtime anyway. - wxMutexLocker locker(timeLock); -#endif - - // Borland CRT crashes when passed 0 ticks for some reason, see SF bug 1704438 -#ifdef __BORLANDC__ - if ( !*ticks ) - return NULL; -#endif - - const tm * const t = localtime(ticks); - if ( !t ) - return NULL; - - memcpy(temp, t, sizeof(struct tm)); - return temp; -} -#endif // !HAVE_LOCALTIME_R - -#ifndef HAVE_GMTIME_R -struct tm *wxGmtime_r(const time_t* ticks, struct tm* temp) -{ -#if wxUSE_THREADS && !defined(__WINDOWS__) - // No need to waste time with a mutex on windows since it's - // using thread local storage for gmtime anyway. - wxMutexLocker locker(timeLock); -#endif - -#ifdef __BORLANDC__ - if ( !*ticks ) - return NULL; -#endif - - const tm * const t = gmtime(ticks); - if ( !t ) - return NULL; - - memcpy(temp, gmtime(ticks), sizeof(struct tm)); - return temp; -} -#endif // !HAVE_GMTIME_R - -#endif // wxWinCE with VC8/other platforms - -// ---------------------------------------------------------------------------- -// macros -// ---------------------------------------------------------------------------- - -// debugging helper: just a convenient replacement of wxCHECK() -#define wxDATETIME_CHECK(expr, msg) \ - wxCHECK2_MSG(expr, *this = wxInvalidDateTime; return *this, msg) - -// ---------------------------------------------------------------------------- -// private classes -// ---------------------------------------------------------------------------- - -class wxDateTimeHolidaysModule : public wxModule -{ -public: - virtual bool OnInit() - { - wxDateTimeHolidayAuthority::AddAuthority(new wxDateTimeWorkDays); - - return true; - } - - virtual void OnExit() - { - wxDateTimeHolidayAuthority::ClearAllAuthorities(); - wxDateTimeHolidayAuthority::ms_authorities.clear(); - } - -private: - DECLARE_DYNAMIC_CLASS(wxDateTimeHolidaysModule) -}; - -IMPLEMENT_DYNAMIC_CLASS(wxDateTimeHolidaysModule, wxModule) - -// ---------------------------------------------------------------------------- -// constants -// ---------------------------------------------------------------------------- - -// some trivial ones -static const int MONTHS_IN_YEAR = 12; - -static const int SEC_PER_MIN = 60; - -static const int MIN_PER_HOUR = 60; - -static const int HOURS_PER_DAY = 24; - -static const long SECONDS_PER_DAY = 86400l; - -static const int DAYS_PER_WEEK = 7; - -static const long MILLISECONDS_PER_DAY = 86400000l; - -// this is the integral part of JDN of the midnight of Jan 1, 1970 -// (i.e. JDN(Jan 1, 1970) = 2440587.5) -static const long EPOCH_JDN = 2440587l; - -// used only in asserts -#ifdef __WXDEBUG__ -// the date of JDN -0.5 (as we don't work with fractional parts, this is the -// reference date for us) is Nov 24, 4714BC -static const int JDN_0_YEAR = -4713; -static const int JDN_0_MONTH = wxDateTime::Nov; -static const int JDN_0_DAY = 24; -#endif // __WXDEBUG__ - -// the constants used for JDN calculations -static const long JDN_OFFSET = 32046l; -static const long DAYS_PER_5_MONTHS = 153l; -static const long DAYS_PER_4_YEARS = 1461l; -static const long DAYS_PER_400_YEARS = 146097l; - -// this array contains the cumulated number of days in all previous months for -// normal and leap years -static const wxDateTime::wxDateTime_t gs_cumulatedDays[2][MONTHS_IN_YEAR] = -{ - { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 }, - { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 } -}; - -// ---------------------------------------------------------------------------- -// global data -// ---------------------------------------------------------------------------- - -const wxChar * wxDefaultDateTimeFormat = wxT("%c"); -const wxChar * wxDefaultTimeSpanFormat = wxT("%H:%M:%S"); - -// in the fine tradition of ANSI C we use our equivalent of (time_t)-1 to -// indicate an invalid wxDateTime object -const wxDateTime wxDefaultDateTime; - -wxDateTime::Country wxDateTime::ms_country = wxDateTime::Country_Unknown; - -// ---------------------------------------------------------------------------- -// private functions -// ---------------------------------------------------------------------------- - -// debugger helper: shows what the date really is -#ifdef __WXDEBUG__ -extern const wxChar *wxDumpDate(const wxDateTime* dt) -{ - static wxChar buf[128]; - - wxStrcpy(buf, dt->Format(_T("%Y-%m-%d (%a) %H:%M:%S"))); - - return buf; -} -#endif // Debug - -// get the number of days in the given month of the given year -static inline -wxDateTime::wxDateTime_t GetNumOfDaysInMonth(int year, wxDateTime::Month month) -{ - // the number of days in month in Julian/Gregorian calendar: the first line - // is for normal years, the second one is for the leap ones - static wxDateTime::wxDateTime_t daysInMonth[2][MONTHS_IN_YEAR] = - { - { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, - { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } - }; - - return daysInMonth[wxDateTime::IsLeapYear(year)][month]; -} - -// returns the time zone in the C sense, i.e. the difference UTC - local -// (in seconds) -static int GetTimeZone() -{ - // set to true when the timezone is set - static bool s_timezoneSet = false; - static long gmtoffset = LONG_MAX; // invalid timezone - - // ensure that the timezone variable is set by calling wxLocaltime_r - if ( !s_timezoneSet ) - { - // just call wxLocaltime_r() instead of figuring out whether this - // system supports tzset(), _tzset() or something else - time_t t = 0; - struct tm tm; - - wxLocaltime_r(&t, &tm); - s_timezoneSet = true; - -#ifdef WX_GMTOFF_IN_TM - // note that GMT offset is the opposite of time zone and so to return - // consistent results in both WX_GMTOFF_IN_TM and !WX_GMTOFF_IN_TM - // cases we have to negate it - gmtoffset = -tm.tm_gmtoff; -#else // !WX_GMTOFF_IN_TM - gmtoffset = WX_TIMEZONE; -#endif // WX_GMTOFF_IN_TM/!WX_GMTOFF_IN_TM - } - - return (int)gmtoffset; -} - -// return the integral part of the JDN for the midnight of the given date (to -// get the real JDN you need to add 0.5, this is, in fact, JDN of the -// noon of the previous day) -static long GetTruncatedJDN(wxDateTime::wxDateTime_t day, - wxDateTime::Month mon, - int year) -{ - // CREDIT: code below is by Scott E. Lee (but bugs are mine) - - // check the date validity - wxASSERT_MSG( - (year > JDN_0_YEAR) || - ((year == JDN_0_YEAR) && (mon > JDN_0_MONTH)) || - ((year == JDN_0_YEAR) && (mon == JDN_0_MONTH) && (day >= JDN_0_DAY)), - _T("date out of range - can't convert to JDN") - ); - - // make the year positive to avoid problems with negative numbers division - year += 4800; - - // months are counted from March here - int month; - if ( mon >= wxDateTime::Mar ) - { - month = mon - 2; - } - else - { - month = mon + 10; - year--; - } - - // now we can simply add all the contributions together - return ((year / 100) * DAYS_PER_400_YEARS) / 4 - + ((year % 100) * DAYS_PER_4_YEARS) / 4 - + (month * DAYS_PER_5_MONTHS + 2) / 5 - + day - - JDN_OFFSET; -} - -#ifdef HAVE_STRFTIME - -// this function is a wrapper around strftime(3) adding error checking -static wxString CallStrftime(const wxChar *format, const tm* tm) -{ - wxChar buf[4096]; - // Create temp wxString here to work around mingw/cygwin bug 1046059 - // http://sourceforge.net/tracker/?func=detail&atid=102435&aid=1046059&group_id=2435 - wxString s; - - if ( !wxStrftime(buf, WXSIZEOF(buf), format, tm) ) - { - // buffer is too small? - wxFAIL_MSG(_T("strftime() failed")); - } - - s = buf; - return s; -} - -#endif // HAVE_STRFTIME - -#ifdef HAVE_STRPTIME - -#if wxUSE_UNIX && !defined(HAVE_STRPTIME_DECL) - // configure detected that we had strptime() but not its declaration, - // provide it ourselves - extern "C" char *strptime(const char *, const char *, struct tm *); -#endif - -// Unicode-friendly strptime() wrapper -static const wxChar * -CallStrptime(const wxChar *input, const char *fmt, tm *tm) -{ - // the problem here is that strptime() returns pointer into the string we - // passed to it while we're really interested in the pointer into the - // original, Unicode, string so we try to transform the pointer back -#if wxUSE_UNICODE - wxCharBuffer inputMB(wxConvertWX2MB(input)); -#else // ASCII - const char * const inputMB = input; -#endif // Unicode/Ascii - - const char *result = strptime(inputMB, fmt, tm); - if ( !result ) - return NULL; - -#if wxUSE_UNICODE - // FIXME: this is wrong in presence of surrogates &c - return input + (result - inputMB.data()); -#else // ASCII - return result; -#endif // Unicode/Ascii -} - -#endif // HAVE_STRPTIME - -// if year and/or month have invalid values, replace them with the current ones -static void ReplaceDefaultYearMonthWithCurrent(int *year, - wxDateTime::Month *month) -{ - struct tm *tmNow = NULL; - struct tm tmstruct; - - if ( *year == wxDateTime::Inv_Year ) - { - tmNow = wxDateTime::GetTmNow(&tmstruct); - - *year = 1900 + tmNow->tm_year; - } - - if ( *month == wxDateTime::Inv_Month ) - { - if ( !tmNow ) - tmNow = wxDateTime::GetTmNow(&tmstruct); - - *month = (wxDateTime::Month)tmNow->tm_mon; - } -} - -// fll the struct tm with default values -static void InitTm(struct tm& tm) -{ - // struct tm may have etxra fields (undocumented and with unportable - // names) which, nevertheless, must be set to 0 - memset(&tm, 0, sizeof(struct tm)); - - tm.tm_mday = 1; // mday 0 is invalid - tm.tm_year = 76; // any valid year - tm.tm_isdst = -1; // auto determine -} - -// parsing helpers -// --------------- - -// return the month if the string is a month name or Inv_Month otherwise -static wxDateTime::Month GetMonthFromName(const wxString& name, int flags) -{ - wxDateTime::Month mon; - for ( mon = wxDateTime::Jan; mon < wxDateTime::Inv_Month; wxNextMonth(mon) ) - { - // case-insensitive comparison either one of or with both abbreviated - // and not versions - if ( flags & wxDateTime::Name_Full ) - { - if ( name.CmpNoCase(wxDateTime:: - GetMonthName(mon, wxDateTime::Name_Full)) == 0 ) - { - break; - } - } - - if ( flags & wxDateTime::Name_Abbr ) - { - if ( name.CmpNoCase(wxDateTime:: - GetMonthName(mon, wxDateTime::Name_Abbr)) == 0 ) - { - break; - } - } - } - - return mon; -} - -// return the weekday if the string is a weekday name or Inv_WeekDay otherwise -static wxDateTime::WeekDay GetWeekDayFromName(const wxString& name, int flags) -{ - wxDateTime::WeekDay wd; - for ( wd = wxDateTime::Sun; wd < wxDateTime::Inv_WeekDay; wxNextWDay(wd) ) - { - // case-insensitive comparison either one of or with both abbreviated - // and not versions - if ( flags & wxDateTime::Name_Full ) - { - if ( name.CmpNoCase(wxDateTime:: - GetWeekDayName(wd, wxDateTime::Name_Full)) == 0 ) - { - break; - } - } - - if ( flags & wxDateTime::Name_Abbr ) - { - if ( name.CmpNoCase(wxDateTime:: - GetWeekDayName(wd, wxDateTime::Name_Abbr)) == 0 ) - { - break; - } - } - } - - return wd; -} - -/* static */ -struct tm *wxDateTime::GetTmNow(struct tm *tmstruct) -{ - time_t t = GetTimeNow(); - return wxLocaltime_r(&t, tmstruct); -} - -// scans all digits (but no more than len) and returns the resulting number -static bool GetNumericToken(size_t len, const wxChar*& p, unsigned long *number) -{ - size_t n = 1; - wxString s; - while ( wxIsdigit(*p) ) - { - s += *p++; - - if ( len && ++n > len ) - break; - } - - return !s.empty() && s.ToULong(number); -} - -// scans all alphabetic characters and returns the resulting string -static wxString GetAlphaToken(const wxChar*& p) -{ - wxString s; - while ( wxIsalpha(*p) ) - { - s += *p++; - } - - return s; -} - -// ============================================================================ -// implementation of wxDateTime -// ============================================================================ - -// ---------------------------------------------------------------------------- -// struct Tm -// ---------------------------------------------------------------------------- - -wxDateTime::Tm::Tm() -{ - year = (wxDateTime_t)wxDateTime::Inv_Year; - mon = wxDateTime::Inv_Month; - mday = 0; - hour = min = sec = msec = 0; - wday = wxDateTime::Inv_WeekDay; -} - -wxDateTime::Tm::Tm(const struct tm& tm, const TimeZone& tz) - : m_tz(tz) -{ - msec = 0; - sec = (wxDateTime::wxDateTime_t)tm.tm_sec; - min = (wxDateTime::wxDateTime_t)tm.tm_min; - hour = (wxDateTime::wxDateTime_t)tm.tm_hour; - mday = (wxDateTime::wxDateTime_t)tm.tm_mday; - mon = (wxDateTime::Month)tm.tm_mon; - year = 1900 + tm.tm_year; - wday = (wxDateTime::wxDateTime_t)tm.tm_wday; - yday = (wxDateTime::wxDateTime_t)tm.tm_yday; -} - -bool wxDateTime::Tm::IsValid() const -{ - // we allow for the leap seconds, although we don't use them (yet) - return (year != wxDateTime::Inv_Year) && (mon != wxDateTime::Inv_Month) && - (mday <= GetNumOfDaysInMonth(year, mon)) && - (hour < 24) && (min < 60) && (sec < 62) && (msec < 1000); -} - -void wxDateTime::Tm::ComputeWeekDay() -{ - // compute the week day from day/month/year: we use the dumbest algorithm - // possible: just compute our JDN and then use the (simple to derive) - // formula: weekday = (JDN + 1.5) % 7 - wday = (wxDateTime::wxDateTime_t)((GetTruncatedJDN(mday, mon, year) + 2) % 7); -} - -void wxDateTime::Tm::AddMonths(int monDiff) -{ - // normalize the months field - while ( monDiff < -mon ) - { - year--; - - monDiff += MONTHS_IN_YEAR; - } - - while ( monDiff + mon >= MONTHS_IN_YEAR ) - { - year++; - - monDiff -= MONTHS_IN_YEAR; - } - - mon = (wxDateTime::Month)(mon + monDiff); - - wxASSERT_MSG( mon >= 0 && mon < MONTHS_IN_YEAR, _T("logic error") ); - - // NB: we don't check here that the resulting date is valid, this function - // is private and the caller must check it if needed -} - -void wxDateTime::Tm::AddDays(int dayDiff) -{ - // normalize the days field - while ( dayDiff + mday < 1 ) - { - AddMonths(-1); - - dayDiff += GetNumOfDaysInMonth(year, mon); - } - - mday = (wxDateTime::wxDateTime_t)( mday + dayDiff ); - while ( mday > GetNumOfDaysInMonth(year, mon) ) - { - mday -= GetNumOfDaysInMonth(year, mon); - - AddMonths(1); - } - - wxASSERT_MSG( mday > 0 && mday <= GetNumOfDaysInMonth(year, mon), - _T("logic error") ); -} - -// ---------------------------------------------------------------------------- -// class TimeZone -// ---------------------------------------------------------------------------- - -wxDateTime::TimeZone::TimeZone(wxDateTime::TZ tz) -{ - switch ( tz ) - { - case wxDateTime::Local: - // get the offset from C RTL: it returns the difference GMT-local - // while we want to have the offset _from_ GMT, hence the '-' - m_offset = -GetTimeZone(); - break; - - case wxDateTime::GMT_12: - case wxDateTime::GMT_11: - case wxDateTime::GMT_10: - case wxDateTime::GMT_9: - case wxDateTime::GMT_8: - case wxDateTime::GMT_7: - case wxDateTime::GMT_6: - case wxDateTime::GMT_5: - case wxDateTime::GMT_4: - case wxDateTime::GMT_3: - case wxDateTime::GMT_2: - case wxDateTime::GMT_1: - m_offset = -3600*(wxDateTime::GMT0 - tz); - break; - - case wxDateTime::GMT0: - case wxDateTime::GMT1: - case wxDateTime::GMT2: - case wxDateTime::GMT3: - case wxDateTime::GMT4: - case wxDateTime::GMT5: - case wxDateTime::GMT6: - case wxDateTime::GMT7: - case wxDateTime::GMT8: - case wxDateTime::GMT9: - case wxDateTime::GMT10: - case wxDateTime::GMT11: - case wxDateTime::GMT12: - case wxDateTime::GMT13: - m_offset = 3600*(tz - wxDateTime::GMT0); - break; - - case wxDateTime::A_CST: - // Central Standard Time in use in Australia = UTC + 9.5 - m_offset = 60l*(9*MIN_PER_HOUR + MIN_PER_HOUR/2); - break; - - default: - wxFAIL_MSG( _T("unknown time zone") ); - } -} - -// ---------------------------------------------------------------------------- -// static functions -// ---------------------------------------------------------------------------- - -/* static */ -bool wxDateTime::IsLeapYear(int year, wxDateTime::Calendar cal) -{ - if ( year == Inv_Year ) - year = GetCurrentYear(); - - if ( cal == Gregorian ) - { - // in Gregorian calendar leap years are those divisible by 4 except - // those divisible by 100 unless they're also divisible by 400 - // (in some countries, like Russia and Greece, additional corrections - // exist, but they won't manifest themselves until 2700) - return (year % 4 == 0) && ((year % 100 != 0) || (year % 400 == 0)); - } - else if ( cal == Julian ) - { - // in Julian calendar the rule is simpler - return year % 4 == 0; - } - else - { - wxFAIL_MSG(_T("unknown calendar")); - - return false; - } -} - -/* static */ -int wxDateTime::GetCentury(int year) -{ - return year > 0 ? year / 100 : year / 100 - 1; -} - -/* static */ -int wxDateTime::ConvertYearToBC(int year) -{ - // year 0 is BC 1 - return year > 0 ? year : year - 1; -} - -/* static */ -int wxDateTime::GetCurrentYear(wxDateTime::Calendar cal) -{ - switch ( cal ) - { - case Gregorian: - return Now().GetYear(); - - case Julian: - wxFAIL_MSG(_T("TODO")); - break; - - default: - wxFAIL_MSG(_T("unsupported calendar")); - break; - } - - return Inv_Year; -} - -/* static */ -wxDateTime::Month wxDateTime::GetCurrentMonth(wxDateTime::Calendar cal) -{ - switch ( cal ) - { - case Gregorian: - return Now().GetMonth(); - - case Julian: - wxFAIL_MSG(_T("TODO")); - break; - - default: - wxFAIL_MSG(_T("unsupported calendar")); - break; - } - - return Inv_Month; -} - -/* static */ -wxDateTime::wxDateTime_t wxDateTime::GetNumberOfDays(int year, Calendar cal) -{ - if ( year == Inv_Year ) - { - // take the current year if none given - year = GetCurrentYear(); - } - - switch ( cal ) - { - case Gregorian: - case Julian: - return IsLeapYear(year) ? 366 : 365; - - default: - wxFAIL_MSG(_T("unsupported calendar")); - break; - } - - return 0; -} - -/* static */ -wxDateTime::wxDateTime_t wxDateTime::GetNumberOfDays(wxDateTime::Month month, - int year, - wxDateTime::Calendar cal) -{ - wxCHECK_MSG( month < MONTHS_IN_YEAR, 0, _T("invalid month") ); - - if ( cal == Gregorian || cal == Julian ) - { - if ( year == Inv_Year ) - { - // take the current year if none given - year = GetCurrentYear(); - } - - return GetNumOfDaysInMonth(year, month); - } - else - { - wxFAIL_MSG(_T("unsupported calendar")); - - return 0; - } -} - -/* static */ -wxString wxDateTime::GetMonthName(wxDateTime::Month month, - wxDateTime::NameFlags flags) -{ - wxCHECK_MSG( month != Inv_Month, wxEmptyString, _T("invalid month") ); -#ifdef HAVE_STRFTIME - // notice that we must set all the fields to avoid confusing libc (GNU one - // gets confused to a crash if we don't do this) - tm tm; - InitTm(tm); - tm.tm_mon = month; - - return CallStrftime(flags == Name_Abbr ? _T("%b") : _T("%B"), &tm); -#else // !HAVE_STRFTIME - wxString ret; - switch(month) - { - case Jan: - ret = (flags == Name_Abbr ? wxT("Jan"): wxT("January")); - break; - case Feb: - ret = (flags == Name_Abbr ? wxT("Feb"): wxT("Febuary")); - break; - case Mar: - ret = (flags == Name_Abbr ? wxT("Mar"): wxT("March")); - break; - case Apr: - ret = (flags == Name_Abbr ? wxT("Apr"): wxT("April")); - break; - case May: - ret = (flags == Name_Abbr ? wxT("May"): wxT("May")); - break; - case Jun: - ret = (flags == Name_Abbr ? wxT("Jun"): wxT("June")); - break; - case Jul: - ret = (flags == Name_Abbr ? wxT("Jul"): wxT("July")); - break; - case Aug: - ret = (flags == Name_Abbr ? wxT("Aug"): wxT("August")); - break; - case Sep: - ret = (flags == Name_Abbr ? wxT("Sep"): wxT("September")); - break; - case Oct: - ret = (flags == Name_Abbr ? wxT("Oct"): wxT("October")); - break; - case Nov: - ret = (flags == Name_Abbr ? wxT("Nov"): wxT("November")); - break; - case Dec: - ret = (flags == Name_Abbr ? wxT("Dec"): wxT("December")); - break; - } - return ret; -#endif // HAVE_STRFTIME/!HAVE_STRFTIME -} - -/* static */ -wxString wxDateTime::GetWeekDayName(wxDateTime::WeekDay wday, - wxDateTime::NameFlags flags) -{ - wxCHECK_MSG( wday != Inv_WeekDay, wxEmptyString, _T("invalid weekday") ); -#ifdef HAVE_STRFTIME - // take some arbitrary Sunday (but notice that the day should be such that - // after adding wday to it below we still have a valid date, e.g. don't - // take 28 here!) - tm tm; - InitTm(tm); - tm.tm_mday = 21; - tm.tm_mon = Nov; - tm.tm_year = 99; - - // and offset it by the number of days needed to get the correct wday - tm.tm_mday += wday; - - // call mktime() to normalize it... - (void)mktime(&tm); - - // ... and call strftime() - return CallStrftime(flags == Name_Abbr ? _T("%a") : _T("%A"), &tm); -#else // !HAVE_STRFTIME - wxString ret; - switch(wday) - { - case Sun: - ret = (flags == Name_Abbr ? wxT("Sun") : wxT("Sunday")); - break; - case Mon: - ret = (flags == Name_Abbr ? wxT("Mon") : wxT("Monday")); - break; - case Tue: - ret = (flags == Name_Abbr ? wxT("Tue") : wxT("Tuesday")); - break; - case Wed: - ret = (flags == Name_Abbr ? wxT("Wed") : wxT("Wednesday")); - break; - case Thu: - ret = (flags == Name_Abbr ? wxT("Thu") : wxT("Thursday")); - break; - case Fri: - ret = (flags == Name_Abbr ? wxT("Fri") : wxT("Friday")); - break; - case Sat: - ret = (flags == Name_Abbr ? wxT("Sat") : wxT("Saturday")); - break; - } - return ret; -#endif // HAVE_STRFTIME/!HAVE_STRFTIME -} - -/* static */ -void wxDateTime::GetAmPmStrings(wxString *am, wxString *pm) -{ - tm tm; - InitTm(tm); - wxChar buffer[64]; - // @Note: Do not call 'CallStrftime' here! CallStrftime checks the return code - // and causes an assertion failed if the buffer is to small (which is good) - OR - - // if strftime does not return anything because the format string is invalid - OR - - // if there are no 'am' / 'pm' tokens defined for the current locale (which is not good). - // wxDateTime::ParseTime will try several different formats to parse the time. - // As a result, GetAmPmStrings might get called, even if the current locale - // does not define any 'am' / 'pm' tokens. In this case, wxStrftime would - // assert, even though it is a perfectly legal use. - if ( am ) - { - if (wxStrftime(buffer, sizeof(buffer)/sizeof(wxChar), _T("%p"), &tm) > 0) - *am = wxString(buffer); - else - *am = wxString(); - } - if ( pm ) - { - tm.tm_hour = 13; - if (wxStrftime(buffer, sizeof(buffer)/sizeof(wxChar), _T("%p"), &tm) > 0) - *pm = wxString(buffer); - else - *pm = wxString(); - } -} - -// ---------------------------------------------------------------------------- -// Country stuff: date calculations depend on the country (DST, work days, -// ...), so we need to know which rules to follow. -// ---------------------------------------------------------------------------- - -/* static */ -wxDateTime::Country wxDateTime::GetCountry() -{ - // TODO use LOCALE_ICOUNTRY setting under Win32 -#ifndef __WXWINCE__ - if ( ms_country == Country_Unknown ) - { - // try to guess from the time zone name - time_t t = time(NULL); - struct tm tmstruct; - struct tm *tm = wxLocaltime_r(&t, &tmstruct); - - wxString tz = CallStrftime(_T("%Z"), tm); - if ( tz == _T("WET") || tz == _T("WEST") ) - { - ms_country = UK; - } - else if ( tz == _T("CET") || tz == _T("CEST") ) - { - ms_country = Country_EEC; - } - else if ( tz == _T("MSK") || tz == _T("MSD") ) - { - ms_country = Russia; - } - else if ( tz == _T("AST") || tz == _T("ADT") || - tz == _T("EST") || tz == _T("EDT") || - tz == _T("CST") || tz == _T("CDT") || - tz == _T("MST") || tz == _T("MDT") || - tz == _T("PST") || tz == _T("PDT") ) - { - ms_country = USA; - } - else - { - // well, choose a default one - ms_country = USA; - } - } -#else // __WXWINCE__ - ms_country = USA; -#endif // !__WXWINCE__/__WXWINCE__ - - return ms_country; -} - -/* static */ -void wxDateTime::SetCountry(wxDateTime::Country country) -{ - ms_country = country; -} - -/* static */ -bool wxDateTime::IsWestEuropeanCountry(Country country) -{ - if ( country == Country_Default ) - { - country = GetCountry(); - } - - return (Country_WesternEurope_Start <= country) && - (country <= Country_WesternEurope_End); -} - -// ---------------------------------------------------------------------------- -// DST calculations: we use 3 different rules for the West European countries, -// USA and for the rest of the world. This is undoubtedly false for many -// countries, but I lack the necessary info (and the time to gather it), -// please add the other rules here! -// ---------------------------------------------------------------------------- - -/* static */ -bool wxDateTime::IsDSTApplicable(int year, Country country) -{ - if ( year == Inv_Year ) - { - // take the current year if none given - year = GetCurrentYear(); - } - - if ( country == Country_Default ) - { - country = GetCountry(); - } - - switch ( country ) - { - case USA: - case UK: - // DST was first observed in the US and UK during WWI, reused - // during WWII and used again since 1966 - return year >= 1966 || - (year >= 1942 && year <= 1945) || - (year == 1918 || year == 1919); - - default: - // assume that it started after WWII - return year > 1950; - } -} - -/* static */ -wxDateTime wxDateTime::GetBeginDST(int year, Country country) -{ - if ( year == Inv_Year ) - { - // take the current year if none given - year = GetCurrentYear(); - } - - if ( country == Country_Default ) - { - country = GetCountry(); - } - - if ( !IsDSTApplicable(year, country) ) - { - return wxInvalidDateTime; - } - - wxDateTime dt; - - if ( IsWestEuropeanCountry(country) || (country == Russia) ) - { - // DST begins at 1 a.m. GMT on the last Sunday of March - if ( !dt.SetToLastWeekDay(Sun, Mar, year) ) - { - // weird... - wxFAIL_MSG( _T("no last Sunday in March?") ); - } - - dt += wxTimeSpan::Hours(1); - - // disable DST tests because it could result in an infinite recursion! - dt.MakeGMT(true); - } - else switch ( country ) - { - case USA: - switch ( year ) - { - case 1918: - case 1919: - // don't know for sure - assume it was in effect all year - - case 1943: - case 1944: - case 1945: - dt.Set(1, Jan, year); - break; - - case 1942: - // DST was installed Feb 2, 1942 by the Congress - dt.Set(2, Feb, year); - break; - - // Oil embargo changed the DST period in the US - case 1974: - dt.Set(6, Jan, 1974); - break; - - case 1975: - dt.Set(23, Feb, 1975); - break; - - default: - // before 1986, DST begun on the last Sunday of April, but - // in 1986 Reagan changed it to begin at 2 a.m. of the - // first Sunday in April - if ( year < 1986 ) - { - if ( !dt.SetToLastWeekDay(Sun, Apr, year) ) - { - // weird... - wxFAIL_MSG( _T("no first Sunday in April?") ); - } - } - else - { - if ( !dt.SetToWeekDay(Sun, 1, Apr, year) ) - { - // weird... - wxFAIL_MSG( _T("no first Sunday in April?") ); - } - } - - dt += wxTimeSpan::Hours(2); - - // TODO what about timezone?? - } - - break; - - default: - // assume Mar 30 as the start of the DST for the rest of the world - // - totally bogus, of course - dt.Set(30, Mar, year); - } - - return dt; -} - -/* static */ -wxDateTime wxDateTime::GetEndDST(int year, Country country) -{ - if ( year == Inv_Year ) - { - // take the current year if none given - year = GetCurrentYear(); - } - - if ( country == Country_Default ) - { - country = GetCountry(); - } - - if ( !IsDSTApplicable(year, country) ) - { - return wxInvalidDateTime; - } - - wxDateTime dt; - - if ( IsWestEuropeanCountry(country) || (country == Russia) ) - { - // DST ends at 1 a.m. GMT on the last Sunday of October - if ( !dt.SetToLastWeekDay(Sun, Oct, year) ) - { - // weirder and weirder... - wxFAIL_MSG( _T("no last Sunday in October?") ); - } - - dt += wxTimeSpan::Hours(1); - - // disable DST tests because it could result in an infinite recursion! - dt.MakeGMT(true); - } - else switch ( country ) - { - case USA: - switch ( year ) - { - case 1918: - case 1919: - // don't know for sure - assume it was in effect all year - - case 1943: - case 1944: - dt.Set(31, Dec, year); - break; - - case 1945: - // the time was reset after the end of the WWII - dt.Set(30, Sep, year); - break; - - default: - // DST ends at 2 a.m. on the last Sunday of October - if ( !dt.SetToLastWeekDay(Sun, Oct, year) ) - { - // weirder and weirder... - wxFAIL_MSG( _T("no last Sunday in October?") ); - } - - dt += wxTimeSpan::Hours(2); - - // TODO what about timezone?? - } - break; - - default: - // assume October 26th as the end of the DST - totally bogus too - dt.Set(26, Oct, year); - } - - return dt; -} - -// ---------------------------------------------------------------------------- -// constructors and assignment operators -// ---------------------------------------------------------------------------- - -// return the current time with ms precision -/* static */ wxDateTime wxDateTime::UNow() -{ - return wxDateTime(wxGetLocalTimeMillis()); -} - -// the values in the tm structure contain the local time -wxDateTime& wxDateTime::Set(const struct tm& tm) -{ - struct tm tm2(tm); - time_t timet = mktime(&tm2); - - if ( timet == (time_t)-1 ) - { - // mktime() rather unintuitively fails for Jan 1, 1970 if the hour is - // less than timezone - try to make it work for this case - if ( tm2.tm_year == 70 && tm2.tm_mon == 0 && tm2.tm_mday == 1 ) - { - return Set((time_t)( - GetTimeZone() + - tm2.tm_hour * MIN_PER_HOUR * SEC_PER_MIN + - tm2.tm_min * SEC_PER_MIN + - tm2.tm_sec)); - } - - wxFAIL_MSG( _T("mktime() failed") ); - - *this = wxInvalidDateTime; - - return *this; - } - else - { - return Set(timet); - } -} - -wxDateTime& wxDateTime::Set(wxDateTime_t hour, - wxDateTime_t minute, - wxDateTime_t second, - wxDateTime_t millisec) -{ - // we allow seconds to be 61 to account for the leap seconds, even if we - // don't use them really - wxDATETIME_CHECK( hour < 24 && - second < 62 && - minute < 60 && - millisec < 1000, - _T("Invalid time in wxDateTime::Set()") ); - - // get the current date from system - struct tm tmstruct; - struct tm *tm = GetTmNow(&tmstruct); - - wxDATETIME_CHECK( tm, _T("wxLocaltime_r() failed") ); - - // make a copy so it isn't clobbered by the call to mktime() below - struct tm tm1(*tm); - - // adjust the time - tm1.tm_hour = hour; - tm1.tm_min = minute; - tm1.tm_sec = second; - - // and the DST in case it changes on this date - struct tm tm2(tm1); - mktime(&tm2); - if ( tm2.tm_isdst != tm1.tm_isdst ) - tm1.tm_isdst = tm2.tm_isdst; - - (void)Set(tm1); - - // and finally adjust milliseconds - return SetMillisecond(millisec); -} - -wxDateTime& wxDateTime::Set(wxDateTime_t day, - Month month, - int year, - wxDateTime_t hour, - wxDateTime_t minute, - wxDateTime_t second, - wxDateTime_t millisec) -{ - wxDATETIME_CHECK( hour < 24 && - second < 62 && - minute < 60 && - millisec < 1000, - _T("Invalid time in wxDateTime::Set()") ); - - ReplaceDefaultYearMonthWithCurrent(&year, &month); - - wxDATETIME_CHECK( (0 < day) && (day <= GetNumberOfDays(month, year)), - _T("Invalid date in wxDateTime::Set()") ); - - // the range of time_t type (inclusive) - static const int yearMinInRange = 1970; - static const int yearMaxInRange = 2037; - - // test only the year instead of testing for the exact end of the Unix - // time_t range - it doesn't bring anything to do more precise checks - if ( year >= yearMinInRange && year <= yearMaxInRange ) - { - // use the standard library version if the date is in range - this is - // probably more efficient than our code - struct tm tm; - tm.tm_year = year - 1900; - tm.tm_mon = month; - tm.tm_mday = day; - tm.tm_hour = hour; - tm.tm_min = minute; - tm.tm_sec = second; - tm.tm_isdst = -1; // mktime() will guess it - - (void)Set(tm); - - // and finally adjust milliseconds - if (IsValid()) - SetMillisecond(millisec); - - return *this; - } - else - { - // do time calculations ourselves: we want to calculate the number of - // milliseconds between the given date and the epoch - - // get the JDN for the midnight of this day - m_time = GetTruncatedJDN(day, month, year); - m_time -= EPOCH_JDN; - m_time *= SECONDS_PER_DAY * TIME_T_FACTOR; - - // JDN corresponds to GMT, we take localtime - Add(wxTimeSpan(hour, minute, second + GetTimeZone(), millisec)); - } - - return *this; -} - -wxDateTime& wxDateTime::Set(double jdn) -{ - // so that m_time will be 0 for the midnight of Jan 1, 1970 which is jdn - // EPOCH_JDN + 0.5 - jdn -= EPOCH_JDN + 0.5; - - m_time.Assign(jdn*MILLISECONDS_PER_DAY); - - // JDNs always are in UTC, so we don't need any adjustments for time zone - - return *this; -} - -wxDateTime& wxDateTime::ResetTime() -{ - Tm tm = GetTm(); - - if ( tm.hour || tm.min || tm.sec || tm.msec ) - { - tm.msec = - tm.sec = - tm.min = - tm.hour = 0; - - Set(tm); - } - - return *this; -} - -wxDateTime wxDateTime::GetDateOnly() const -{ - Tm tm = GetTm(); - tm.msec = - tm.sec = - tm.min = - tm.hour = 0; - return wxDateTime(tm); -} - -// ---------------------------------------------------------------------------- -// DOS Date and Time Format functions -// ---------------------------------------------------------------------------- -// the dos date and time value is an unsigned 32 bit value in the format: -// YYYYYYYMMMMDDDDDhhhhhmmmmmmsssss -// -// Y = year offset from 1980 (0-127) -// M = month (1-12) -// D = day of month (1-31) -// h = hour (0-23) -// m = minute (0-59) -// s = bisecond (0-29) each bisecond indicates two seconds -// ---------------------------------------------------------------------------- - -wxDateTime& wxDateTime::SetFromDOS(unsigned long ddt) -{ - struct tm tm; - InitTm(tm); - - long year = ddt & 0xFE000000; - year >>= 25; - year += 80; - tm.tm_year = year; - - long month = ddt & 0x1E00000; - month >>= 21; - month -= 1; - tm.tm_mon = month; - - long day = ddt & 0x1F0000; - day >>= 16; - tm.tm_mday = day; - - long hour = ddt & 0xF800; - hour >>= 11; - tm.tm_hour = hour; - - long minute = ddt & 0x7E0; - minute >>= 5; - tm.tm_min = minute; - - long second = ddt & 0x1F; - tm.tm_sec = second * 2; - - return Set(mktime(&tm)); -} - -unsigned long wxDateTime::GetAsDOS() const -{ - unsigned long ddt; - time_t ticks = GetTicks(); - struct tm tmstruct; - struct tm *tm = wxLocaltime_r(&ticks, &tmstruct); - wxCHECK_MSG( tm, ULONG_MAX, _T("time can't be represented in DOS format") ); - - long year = tm->tm_year; - year -= 80; - year <<= 25; - - long month = tm->tm_mon; - month += 1; - month <<= 21; - - long day = tm->tm_mday; - day <<= 16; - - long hour = tm->tm_hour; - hour <<= 11; - - long minute = tm->tm_min; - minute <<= 5; - - long second = tm->tm_sec; - second /= 2; - - ddt = year | month | day | hour | minute | second; - return ddt; -} - -// ---------------------------------------------------------------------------- -// time_t <-> broken down time conversions -// ---------------------------------------------------------------------------- - -wxDateTime::Tm wxDateTime::GetTm(const TimeZone& tz) const -{ - wxASSERT_MSG( IsValid(), _T("invalid wxDateTime") ); - - time_t time = GetTicks(); - if ( time != (time_t)-1 ) - { - // use C RTL functions - struct tm tmstruct; - tm *tm; - if ( tz.GetOffset() == -GetTimeZone() ) - { - // we are working with local time - tm = wxLocaltime_r(&time, &tmstruct); - - // should never happen - wxCHECK_MSG( tm, Tm(), _T("wxLocaltime_r() failed") ); - } - else - { - time += (time_t)tz.GetOffset(); -#if defined(__VMS__) || defined(__WATCOMC__) // time is unsigned so avoid warning - int time2 = (int) time; - if ( time2 >= 0 ) -#else - if ( time >= 0 ) -#endif - { - tm = wxGmtime_r(&time, &tmstruct); - - // should never happen - wxCHECK_MSG( tm, Tm(), _T("wxGmtime_r() failed") ); - } - else - { - tm = (struct tm *)NULL; - } - } - - if ( tm ) - { - // adjust the milliseconds - Tm tm2(*tm, tz); - long timeOnly = (m_time % MILLISECONDS_PER_DAY).ToLong(); - tm2.msec = (wxDateTime_t)(timeOnly % 1000); - return tm2; - } - //else: use generic code below - } - - // remember the time and do the calculations with the date only - this - // eliminates rounding errors of the floating point arithmetics - - wxLongLong timeMidnight = m_time + tz.GetOffset() * 1000; - - long timeOnly = (timeMidnight % MILLISECONDS_PER_DAY).ToLong(); - - // we want to always have positive time and timeMidnight to be really - // the midnight before it - if ( timeOnly < 0 ) - { - timeOnly = MILLISECONDS_PER_DAY + timeOnly; - } - - timeMidnight -= timeOnly; - - // calculate the Gregorian date from JDN for the midnight of our date: - // this will yield day, month (in 1..12 range) and year - - // actually, this is the JDN for the noon of the previous day - long jdn = (timeMidnight / MILLISECONDS_PER_DAY).ToLong() + EPOCH_JDN; - - // CREDIT: code below is by Scott E. Lee (but bugs are mine) - - wxASSERT_MSG( jdn > -2, _T("JDN out of range") ); - - // calculate the century - long temp = (jdn + JDN_OFFSET) * 4 - 1; - long century = temp / DAYS_PER_400_YEARS; - - // then the year and day of year (1 <= dayOfYear <= 366) - temp = ((temp % DAYS_PER_400_YEARS) / 4) * 4 + 3; - long year = (century * 100) + (temp / DAYS_PER_4_YEARS); - long dayOfYear = (temp % DAYS_PER_4_YEARS) / 4 + 1; - - // and finally the month and day of the month - temp = dayOfYear * 5 - 3; - long month = temp / DAYS_PER_5_MONTHS; - long day = (temp % DAYS_PER_5_MONTHS) / 5 + 1; - - // month is counted from March - convert to normal - if ( month < 10 ) - { - month += 3; - } - else - { - year += 1; - month -= 9; - } - - // year is offset by 4800 - year -= 4800; - - // check that the algorithm gave us something reasonable - wxASSERT_MSG( (0 < month) && (month <= 12), _T("invalid month") ); - wxASSERT_MSG( (1 <= day) && (day < 32), _T("invalid day") ); - - // construct Tm from these values - Tm tm; - tm.year = (int)year; - tm.mon = (Month)(month - 1); // algorithm yields 1 for January, not 0 - tm.mday = (wxDateTime_t)day; - tm.msec = (wxDateTime_t)(timeOnly % 1000); - timeOnly -= tm.msec; - timeOnly /= 1000; // now we have time in seconds - - tm.sec = (wxDateTime_t)(timeOnly % SEC_PER_MIN); - timeOnly -= tm.sec; - timeOnly /= SEC_PER_MIN; // now we have time in minutes - - tm.min = (wxDateTime_t)(timeOnly % MIN_PER_HOUR); - timeOnly -= tm.min; - - tm.hour = (wxDateTime_t)(timeOnly / MIN_PER_HOUR); - - return tm; -} - -wxDateTime& wxDateTime::SetYear(int year) -{ - wxASSERT_MSG( IsValid(), _T("invalid wxDateTime") ); - - Tm tm(GetTm()); - tm.year = year; - Set(tm); - - return *this; -} - -wxDateTime& wxDateTime::SetMonth(Month month) -{ - wxASSERT_MSG( IsValid(), _T("invalid wxDateTime") ); - - Tm tm(GetTm()); - tm.mon = month; - Set(tm); - - return *this; -} - -wxDateTime& wxDateTime::SetDay(wxDateTime_t mday) -{ - wxASSERT_MSG( IsValid(), _T("invalid wxDateTime") ); - - Tm tm(GetTm()); - tm.mday = mday; - Set(tm); - - return *this; -} - -wxDateTime& wxDateTime::SetHour(wxDateTime_t hour) -{ - wxASSERT_MSG( IsValid(), _T("invalid wxDateTime") ); - - Tm tm(GetTm()); - tm.hour = hour; - Set(tm); - - return *this; -} - -wxDateTime& wxDateTime::SetMinute(wxDateTime_t min) -{ - wxASSERT_MSG( IsValid(), _T("invalid wxDateTime") ); - - Tm tm(GetTm()); - tm.min = min; - Set(tm); - - return *this; -} - -wxDateTime& wxDateTime::SetSecond(wxDateTime_t sec) -{ - wxASSERT_MSG( IsValid(), _T("invalid wxDateTime") ); - - Tm tm(GetTm()); - tm.sec = sec; - Set(tm); - - return *this; -} - -wxDateTime& wxDateTime::SetMillisecond(wxDateTime_t millisecond) -{ - wxASSERT_MSG( IsValid(), _T("invalid wxDateTime") ); - - // we don't need to use GetTm() for this one - m_time -= m_time % 1000l; - m_time += millisecond; - - return *this; -} - -// ---------------------------------------------------------------------------- -// wxDateTime arithmetics -// ---------------------------------------------------------------------------- - -wxDateTime& wxDateTime::Add(const wxDateSpan& diff) -{ - Tm tm(GetTm()); - - tm.year += diff.GetYears(); - tm.AddMonths(diff.GetMonths()); - - // check that the resulting date is valid - if ( tm.mday > GetNumOfDaysInMonth(tm.year, tm.mon) ) - { - // We suppose that when adding one month to Jan 31 we want to get Feb - // 28 (or 29), i.e. adding a month to the last day of the month should - // give the last day of the next month which is quite logical. - // - // Unfortunately, there is no logic way to understand what should - // Jan 30 + 1 month be - Feb 28 too or Feb 27 (assuming non leap year)? - // We make it Feb 28 (last day too), but it is highly questionable. - tm.mday = GetNumOfDaysInMonth(tm.year, tm.mon); - } - - tm.AddDays(diff.GetTotalDays()); - - Set(tm); - - wxASSERT_MSG( IsSameTime(tm), - _T("Add(wxDateSpan) shouldn't modify time") ); - - return *this; -} - -// ---------------------------------------------------------------------------- -// Weekday and monthday stuff -// ---------------------------------------------------------------------------- - -// convert Sun, Mon, ..., Sat into 6, 0, ..., 5 -static inline int ConvertWeekDayToMondayBase(int wd) -{ - return wd == wxDateTime::Sun ? 6 : wd - 1; -} - -/* static */ -wxDateTime -wxDateTime::SetToWeekOfYear(int year, wxDateTime_t numWeek, WeekDay wd) -{ - wxASSERT_MSG( numWeek > 0, - _T("invalid week number: weeks are counted from 1") ); - - // Jan 4 always lies in the 1st week of the year - wxDateTime dt(4, Jan, year); - dt.SetToWeekDayInSameWeek(wd); - dt += wxDateSpan::Weeks(numWeek - 1); - - return dt; -} - -#if WXWIN_COMPATIBILITY_2_6 -// use a separate function to avoid warnings about using deprecated -// SetToTheWeek in GetWeek below -static wxDateTime -SetToTheWeek(int year, - wxDateTime::wxDateTime_t numWeek, - wxDateTime::WeekDay weekday, - wxDateTime::WeekFlags flags) -{ - // Jan 4 always lies in the 1st week of the year - wxDateTime dt(4, wxDateTime::Jan, year); - dt.SetToWeekDayInSameWeek(weekday, flags); - dt += wxDateSpan::Weeks(numWeek - 1); - - return dt; -} - -bool wxDateTime::SetToTheWeek(wxDateTime_t numWeek, - WeekDay weekday, - WeekFlags flags) -{ - int year = GetYear(); - *this = ::SetToTheWeek(year, numWeek, weekday, flags); - if ( GetYear() != year ) - { - // oops... numWeek was too big - return false; - } - - return true; -} - -wxDateTime wxDateTime::GetWeek(wxDateTime_t numWeek, - WeekDay weekday, - WeekFlags flags) const -{ - return ::SetToTheWeek(GetYear(), numWeek, weekday, flags); -} -#endif // WXWIN_COMPATIBILITY_2_6 - -wxDateTime& wxDateTime::SetToLastMonthDay(Month month, - int year) -{ - // take the current month/year if none specified - if ( year == Inv_Year ) - year = GetYear(); - if ( month == Inv_Month ) - month = GetMonth(); - - return Set(GetNumOfDaysInMonth(year, month), month, year); -} - -wxDateTime& wxDateTime::SetToWeekDayInSameWeek(WeekDay weekday, WeekFlags flags) -{ - wxDATETIME_CHECK( weekday != Inv_WeekDay, _T("invalid weekday") ); - - int wdayDst = weekday, - wdayThis = GetWeekDay(); - if ( wdayDst == wdayThis ) - { - // nothing to do - return *this; - } - - if ( flags == Default_First ) - { - flags = GetCountry() == USA ? Sunday_First : Monday_First; - } - - // the logic below based on comparing weekday and wdayThis works if Sun (0) - // is the first day in the week, but breaks down for Monday_First case so - // we adjust the week days in this case - if ( flags == Monday_First ) - { - if ( wdayThis == Sun ) - wdayThis += 7; - if ( wdayDst == Sun ) - wdayDst += 7; - } - //else: Sunday_First, nothing to do - - // go forward or back in time to the day we want - if ( wdayDst < wdayThis ) - { - return Subtract(wxDateSpan::Days(wdayThis - wdayDst)); - } - else // weekday > wdayThis - { - return Add(wxDateSpan::Days(wdayDst - wdayThis)); - } -} - -wxDateTime& wxDateTime::SetToNextWeekDay(WeekDay weekday) -{ - wxDATETIME_CHECK( weekday != Inv_WeekDay, _T("invalid weekday") ); - - int diff; - WeekDay wdayThis = GetWeekDay(); - if ( weekday == wdayThis ) - { - // nothing to do - return *this; - } - else if ( weekday < wdayThis ) - { - // need to advance a week - diff = 7 - (wdayThis - weekday); - } - else // weekday > wdayThis - { - diff = weekday - wdayThis; - } - - return Add(wxDateSpan::Days(diff)); -} - -wxDateTime& wxDateTime::SetToPrevWeekDay(WeekDay weekday) -{ - wxDATETIME_CHECK( weekday != Inv_WeekDay, _T("invalid weekday") ); - - int diff; - WeekDay wdayThis = GetWeekDay(); - if ( weekday == wdayThis ) - { - // nothing to do - return *this; - } - else if ( weekday > wdayThis ) - { - // need to go to previous week - diff = 7 - (weekday - wdayThis); - } - else // weekday < wdayThis - { - diff = wdayThis - weekday; - } - - return Subtract(wxDateSpan::Days(diff)); -} - -bool wxDateTime::SetToWeekDay(WeekDay weekday, - int n, - Month month, - int year) -{ - wxCHECK_MSG( weekday != Inv_WeekDay, false, _T("invalid weekday") ); - - // we don't check explicitly that -5 <= n <= 5 because we will return false - // anyhow in such case - but may be should still give an assert for it? - - // take the current month/year if none specified - ReplaceDefaultYearMonthWithCurrent(&year, &month); - - wxDateTime dt; - - // TODO this probably could be optimised somehow... - - if ( n > 0 ) - { - // get the first day of the month - dt.Set(1, month, year); - - // get its wday - WeekDay wdayFirst = dt.GetWeekDay(); - - // go to the first weekday of the month - int diff = weekday - wdayFirst; - if ( diff < 0 ) - diff += 7; - - // add advance n-1 weeks more - diff += 7*(n - 1); - - dt += wxDateSpan::Days(diff); - } - else // count from the end of the month - { - // get the last day of the month - dt.SetToLastMonthDay(month, year); - - // get its wday - WeekDay wdayLast = dt.GetWeekDay(); - - // go to the last weekday of the month - int diff = wdayLast - weekday; - if ( diff < 0 ) - diff += 7; - - // and rewind n-1 weeks from there - diff += 7*(-n - 1); - - dt -= wxDateSpan::Days(diff); - } - - // check that it is still in the same month - if ( dt.GetMonth() == month ) - { - *this = dt; - - return true; - } - else - { - // no such day in this month - return false; - } -} - -static inline -wxDateTime::wxDateTime_t GetDayOfYearFromTm(const wxDateTime::Tm& tm) -{ - return (wxDateTime::wxDateTime_t)(gs_cumulatedDays[wxDateTime::IsLeapYear(tm.year)][tm.mon] + tm.mday); -} - -wxDateTime::wxDateTime_t wxDateTime::GetDayOfYear(const TimeZone& tz) const -{ - return GetDayOfYearFromTm(GetTm(tz)); -} - -wxDateTime::wxDateTime_t -wxDateTime::GetWeekOfYear(wxDateTime::WeekFlags flags, const TimeZone& tz) const -{ - if ( flags == Default_First ) - { - flags = GetCountry() == USA ? Sunday_First : Monday_First; - } - - Tm tm(GetTm(tz)); - wxDateTime_t nDayInYear = GetDayOfYearFromTm(tm); - - int wdTarget = GetWeekDay(tz); - int wdYearStart = wxDateTime(1, Jan, GetYear()).GetWeekDay(); - int week; - if ( flags == Sunday_First ) - { - // FIXME: First week is not calculated correctly. - week = (nDayInYear - wdTarget + 7) / 7; - if ( wdYearStart == Wed || wdYearStart == Thu ) - week++; - } - else // week starts with monday - { - // adjust the weekdays to non-US style. - wdYearStart = ConvertWeekDayToMondayBase(wdYearStart); - wdTarget = ConvertWeekDayToMondayBase(wdTarget); - - // quoting from http://www.cl.cam.ac.uk/~mgk25/iso-time.html: - // - // Week 01 of a year is per definition the first week that has the - // Thursday in this year, which is equivalent to the week that - // contains the fourth day of January. In other words, the first - // week of a new year is the week that has the majority of its - // days in the new year. Week 01 might also contain days from the - // previous year and the week before week 01 of a year is the last - // week (52 or 53) of the previous year even if it contains days - // from the new year. A week starts with Monday (day 1) and ends - // with Sunday (day 7). - // - - // if Jan 1 is Thursday or less, it is in the first week of this year - if ( wdYearStart < 4 ) - { - // count the number of entire weeks between Jan 1 and this date - week = (nDayInYear + wdYearStart + 6 - wdTarget)/7; - - // be careful to check for overflow in the next year - if ( week == 53 && tm.mday - wdTarget > 28 ) - week = 1; - } - else // Jan 1 is in the last week of the previous year - { - // check if we happen to be at the last week of previous year: - if ( tm.mon == Jan && tm.mday < 8 - wdYearStart ) - week = wxDateTime(31, Dec, GetYear()-1).GetWeekOfYear(); - else - week = (nDayInYear + wdYearStart - 1 - wdTarget)/7; - } - } - - return (wxDateTime::wxDateTime_t)week; -} - -wxDateTime::wxDateTime_t wxDateTime::GetWeekOfMonth(wxDateTime::WeekFlags flags, - const TimeZone& tz) const -{ - Tm tm = GetTm(tz); - wxDateTime dtMonthStart = wxDateTime(1, tm.mon, tm.year); - int nWeek = GetWeekOfYear(flags) - dtMonthStart.GetWeekOfYear(flags) + 1; - if ( nWeek < 0 ) - { - // this may happen for January when Jan, 1 is the last week of the - // previous year - nWeek += IsLeapYear(tm.year - 1) ? 53 : 52; - } - - return (wxDateTime::wxDateTime_t)nWeek; -} - -wxDateTime& wxDateTime::SetToYearDay(wxDateTime::wxDateTime_t yday) -{ - int year = GetYear(); - wxDATETIME_CHECK( (0 < yday) && (yday <= GetNumberOfDays(year)), - _T("invalid year day") ); - - bool isLeap = IsLeapYear(year); - for ( Month mon = Jan; mon < Inv_Month; wxNextMonth(mon) ) - { - // for Dec, we can't compare with gs_cumulatedDays[mon + 1], but we - // don't need it neither - because of the CHECK above we know that - // yday lies in December then - if ( (mon == Dec) || (yday <= gs_cumulatedDays[isLeap][mon + 1]) ) - { - Set((wxDateTime::wxDateTime_t)(yday - gs_cumulatedDays[isLeap][mon]), mon, year); - - break; - } - } - - return *this; -} - -// ---------------------------------------------------------------------------- -// Julian day number conversion and related stuff -// ---------------------------------------------------------------------------- - -double wxDateTime::GetJulianDayNumber() const -{ - return m_time.ToDouble() / MILLISECONDS_PER_DAY + EPOCH_JDN + 0.5; -} - -double wxDateTime::GetRataDie() const -{ - // March 1 of the year 0 is Rata Die day -306 and JDN 1721119.5 - return GetJulianDayNumber() - 1721119.5 - 306; -} - -// ---------------------------------------------------------------------------- -// timezone and DST stuff -// ---------------------------------------------------------------------------- - -int wxDateTime::IsDST(wxDateTime::Country country) const -{ - wxCHECK_MSG( country == Country_Default, -1, - _T("country support not implemented") ); - - // use the C RTL for the dates in the standard range - time_t timet = GetTicks(); - if ( timet != (time_t)-1 ) - { - struct tm tmstruct; - tm *tm = wxLocaltime_r(&timet, &tmstruct); - - wxCHECK_MSG( tm, -1, _T("wxLocaltime_r() failed") ); - - return tm->tm_isdst; - } - else - { - int year = GetYear(); - - if ( !IsDSTApplicable(year, country) ) - { - // no DST time in this year in this country - return -1; - } - - return IsBetween(GetBeginDST(year, country), GetEndDST(year, country)); - } -} - -wxDateTime& wxDateTime::MakeTimezone(const TimeZone& tz, bool noDST) -{ - long secDiff = GetTimeZone() + tz.GetOffset(); - - // we need to know whether DST is or not in effect for this date unless - // the test disabled by the caller - if ( !noDST && (IsDST() == 1) ) - { - // FIXME we assume that the DST is always shifted by 1 hour - secDiff -= 3600; - } - - return Add(wxTimeSpan::Seconds(secDiff)); -} - -wxDateTime& wxDateTime::MakeFromTimezone(const TimeZone& tz, bool noDST) -{ - long secDiff = GetTimeZone() + tz.GetOffset(); - - // we need to know whether DST is or not in effect for this date unless - // the test disabled by the caller - if ( !noDST && (IsDST() == 1) ) - { - // FIXME we assume that the DST is always shifted by 1 hour - secDiff -= 3600; - } - - return Subtract(wxTimeSpan::Seconds(secDiff)); -} - -// ---------------------------------------------------------------------------- -// wxDateTime to/from text representations -// ---------------------------------------------------------------------------- - -wxString wxDateTime::Format(const wxChar *format, const TimeZone& tz) const -{ - wxCHECK_MSG( format, wxEmptyString, _T("NULL format in wxDateTime::Format") ); - - time_t time = GetTicks(); - - // we have to use our own implementation if the date is out of range of - // strftime() or if we use non standard specificators -#ifdef HAVE_STRFTIME - if ( (time != (time_t)-1) && !wxStrstr(format, _T("%l")) ) - { - // use strftime() - struct tm tmstruct; - struct tm *tm; - if ( tz.GetOffset() == -GetTimeZone() ) - { - // we are working with local time - tm = wxLocaltime_r(&time, &tmstruct); - - // should never happen - wxCHECK_MSG( tm, wxEmptyString, _T("wxLocaltime_r() failed") ); - } - else - { - time += (int)tz.GetOffset(); - -#if defined(__VMS__) || defined(__WATCOMC__) // time is unsigned so avoid warning - int time2 = (int) time; - if ( time2 >= 0 ) -#else - if ( time >= 0 ) -#endif - { - tm = wxGmtime_r(&time, &tmstruct); - - // should never happen - wxCHECK_MSG( tm, wxEmptyString, _T("wxGmtime_r() failed") ); - } - else - { - tm = (struct tm *)NULL; - } - } - - if ( tm ) - { - return CallStrftime(format, tm); - } - } - //else: use generic code below -#endif // HAVE_STRFTIME - - // we only parse ANSI C format specifications here, no POSIX 2 - // complications, no GNU extensions but we do add support for a "%l" format - // specifier allowing to get the number of milliseconds - Tm tm = GetTm(tz); - - // used for calls to strftime() when we only deal with time - struct tm tmTimeOnly; - tmTimeOnly.tm_hour = tm.hour; - tmTimeOnly.tm_min = tm.min; - tmTimeOnly.tm_sec = tm.sec; - tmTimeOnly.tm_wday = 0; - tmTimeOnly.tm_yday = 0; - tmTimeOnly.tm_mday = 1; // any date will do - tmTimeOnly.tm_mon = 0; - tmTimeOnly.tm_year = 76; - tmTimeOnly.tm_isdst = 0; // no DST, we adjust for tz ourselves - - wxString tmp, res, fmt; - for ( const wxChar *p = format; *p; p++ ) - { - if ( *p != _T('%') ) - { - // copy as is - res += *p; - - continue; - } - - // set the default format - switch ( *++p ) - { - case _T('Y'): // year has 4 digits - fmt = _T("%04d"); - break; - - case _T('j'): // day of year has 3 digits - case _T('l'): // milliseconds have 3 digits - fmt = _T("%03d"); - break; - - case _T('w'): // week day as number has only one - fmt = _T("%d"); - break; - - default: - // it's either another valid format specifier in which case - // the format is "%02d" (for all the rest) or we have the - // field width preceding the format in which case it will - // override the default format anyhow - fmt = _T("%02d"); - } - - bool restart = true; - while ( restart ) - { - restart = false; - - // start of the format specification - switch ( *p ) - { - case _T('a'): // a weekday name - case _T('A'): - // second parameter should be true for abbreviated names - res += GetWeekDayName(tm.GetWeekDay(), - *p == _T('a') ? Name_Abbr : Name_Full); - break; - - case _T('b'): // a month name - case _T('B'): - res += GetMonthName(tm.mon, - *p == _T('b') ? Name_Abbr : Name_Full); - break; - - case _T('c'): // locale default date and time representation - case _T('x'): // locale default date representation -#ifdef HAVE_STRFTIME - // - // the problem: there is no way to know what do these format - // specifications correspond to for the current locale. - // - // the solution: use a hack and still use strftime(): first - // find the YEAR which is a year in the strftime() range (1970 - // - 2038) whose Jan 1 falls on the same week day as the Jan 1 - // of the real year. Then make a copy of the format and - // replace all occurrences of YEAR in it with some unique - // string not appearing anywhere else in it, then use - // strftime() to format the date in year YEAR and then replace - // YEAR back by the real year and the unique replacement - // string back with YEAR. Notice that "all occurrences of YEAR" - // means all occurrences of 4 digit as well as 2 digit form! - // - // the bugs: we assume that neither of %c nor %x contains any - // fields which may change between the YEAR and real year. For - // example, the week number (%U, %W) and the day number (%j) - // will change if one of these years is leap and the other one - // is not! - { - // find the YEAR: normally, for any year X, Jan 1 or the - // year X + 28 is the same weekday as Jan 1 of X (because - // the weekday advances by 1 for each normal X and by 2 - // for each leap X, hence by 5 every 4 years or by 35 - // which is 0 mod 7 every 28 years) but this rule breaks - // down if there are years between X and Y which are - // divisible by 4 but not leap (i.e. divisible by 100 but - // not 400), hence the correction. - - int yearReal = GetYear(tz); - int mod28 = yearReal % 28; - - // be careful to not go too far - we risk to leave the - // supported range - int year; - if ( mod28 < 10 ) - { - year = 1988 + mod28; // 1988 == 0 (mod 28) - } - else - { - year = 1970 + mod28 - 10; // 1970 == 10 (mod 28) - } - - int nCentury = year / 100, - nCenturyReal = yearReal / 100; - - // need to adjust for the years divisble by 400 which are - // not leap but are counted like leap ones if we just take - // the number of centuries in between for nLostWeekDays - int nLostWeekDays = (nCentury - nCenturyReal) - - (nCentury / 4 - nCenturyReal / 4); - - // we have to gain back the "lost" weekdays: note that the - // effect of this loop is to not do anything to - // nLostWeekDays (which we won't use any more), but to - // (indirectly) set the year correctly - while ( (nLostWeekDays % 7) != 0 ) - { - nLostWeekDays += year++ % 4 ? 1 : 2; - } - - // Keep year below 2000 so the 2digit year number - // can never match the month or day of the month - if (year>=2000) year-=28; - // at any rate, we couldn't go further than 1988 + 9 + 28! - wxASSERT_MSG( year < 2030, - _T("logic error in wxDateTime::Format") ); - - wxString strYear, strYear2; - strYear.Printf(_T("%d"), year); - strYear2.Printf(_T("%d"), year % 100); - - // find four strings not occurring in format (this is surely - // not the optimal way of doing it... improvements welcome!) - wxString fmt2 = format; - wxString replacement,replacement2,replacement3,replacement4; - for (int rnr=1; rnr<5 ; rnr++) - { - wxString r = (wxChar)-rnr; - while ( fmt2.Find(r) != wxNOT_FOUND ) - { - r << (wxChar)-rnr; - } - - switch (rnr) - { - case 1: replacement=r; break; - case 2: replacement2=r; break; - case 3: replacement3=r; break; - case 4: replacement4=r; break; - } - } - // replace all occurrences of year with it - bool wasReplaced = fmt2.Replace(strYear, replacement) > 0; - // evaluation order ensures we always attempt the replacement. - wasReplaced = (fmt2.Replace(strYear2, replacement2) > 0) || wasReplaced; - - // use strftime() to format the same date but in supported - // year - // - // NB: we assume that strftime() doesn't check for the - // date validity and will happily format the date - // corresponding to Feb 29 of a non leap year (which - // may happen if yearReal was leap and year is not) - struct tm tmAdjusted; - InitTm(tmAdjusted); - tmAdjusted.tm_hour = tm.hour; - tmAdjusted.tm_min = tm.min; - tmAdjusted.tm_sec = tm.sec; - tmAdjusted.tm_wday = tm.GetWeekDay(); - tmAdjusted.tm_yday = GetDayOfYear(); - tmAdjusted.tm_mday = tm.mday; - tmAdjusted.tm_mon = tm.mon; - tmAdjusted.tm_year = year - 1900; - tmAdjusted.tm_isdst = 0; // no DST, already adjusted - wxString str = CallStrftime(*p == _T('c') ? _T("%c") - : _T("%x"), - &tmAdjusted); - - // now replace the occurrence of 1999 with the real year - // we do this in two stages to stop the 2 digit year - // matching any substring of the 4 digit year. - // Any day,month hours and minutes components should be safe due - // to ensuring the range of the years. - wxString strYearReal, strYearReal2; - strYearReal.Printf(_T("%04d"), yearReal); - strYearReal2.Printf(_T("%02d"), yearReal % 100); - str.Replace(strYear, replacement3); - str.Replace(strYear2,replacement4); - str.Replace(replacement3, strYearReal); - str.Replace(replacement4, strYearReal2); - - // and replace back all occurrences of replacement string - if ( wasReplaced ) - { - str.Replace(replacement2, strYear2); - str.Replace(replacement, strYear); - } - - res += str; - } -#else // !HAVE_STRFTIME - // Use "%m/%d/%y %H:%M:%S" format instead - res += wxString::Format(wxT("%02d/%02d/%04d %02d:%02d:%02d"), - tm.mon+1,tm.mday, tm.year, tm.hour, tm.min, tm.sec); -#endif // HAVE_STRFTIME/!HAVE_STRFTIME - break; - - case _T('d'): // day of a month (01-31) - res += wxString::Format(fmt, tm.mday); - break; - - case _T('H'): // hour in 24h format (00-23) - res += wxString::Format(fmt, tm.hour); - break; - - case _T('I'): // hour in 12h format (01-12) - { - // 24h -> 12h, 0h -> 12h too - int hour12 = tm.hour > 12 ? tm.hour - 12 - : tm.hour ? tm.hour : 12; - res += wxString::Format(fmt, hour12); - } - break; - - case _T('j'): // day of the year - res += wxString::Format(fmt, GetDayOfYear(tz)); - break; - - case _T('l'): // milliseconds (NOT STANDARD) - res += wxString::Format(fmt, GetMillisecond(tz)); - break; - - case _T('m'): // month as a number (01-12) - res += wxString::Format(fmt, tm.mon + 1); - break; - - case _T('M'): // minute as a decimal number (00-59) - res += wxString::Format(fmt, tm.min); - break; - - case _T('p'): // AM or PM string -#ifdef HAVE_STRFTIME - res += CallStrftime(_T("%p"), &tmTimeOnly); -#else // !HAVE_STRFTIME - res += (tmTimeOnly.tm_hour > 12) ? wxT("pm") : wxT("am"); -#endif // HAVE_STRFTIME/!HAVE_STRFTIME - break; - - case _T('S'): // second as a decimal number (00-61) - res += wxString::Format(fmt, tm.sec); - break; - - case _T('U'): // week number in the year (Sunday 1st week day) - res += wxString::Format(fmt, GetWeekOfYear(Sunday_First, tz)); - break; - - case _T('W'): // week number in the year (Monday 1st week day) - res += wxString::Format(fmt, GetWeekOfYear(Monday_First, tz)); - break; - - case _T('w'): // weekday as a number (0-6), Sunday = 0 - res += wxString::Format(fmt, tm.GetWeekDay()); - break; - - // case _T('x'): -- handled with "%c" - - case _T('X'): // locale default time representation - // just use strftime() to format the time for us -#ifdef HAVE_STRFTIME - res += CallStrftime(_T("%X"), &tmTimeOnly); -#else // !HAVE_STRFTIME - res += wxString::Format(wxT("%02d:%02d:%02d"),tm.hour, tm.min, tm.sec); -#endif // HAVE_STRFTIME/!HAVE_STRFTIME - break; - - case _T('y'): // year without century (00-99) - res += wxString::Format(fmt, tm.year % 100); - break; - - case _T('Y'): // year with century - res += wxString::Format(fmt, tm.year); - break; - - case _T('Z'): // timezone name -#ifdef HAVE_STRFTIME - res += CallStrftime(_T("%Z"), &tmTimeOnly); -#endif - break; - - default: - // is it the format width? - fmt.Empty(); - while ( *p == _T('-') || *p == _T('+') || - *p == _T(' ') || wxIsdigit(*p) ) - { - fmt += *p; - } - - if ( !fmt.empty() ) - { - // we've only got the flags and width so far in fmt - fmt.Prepend(_T('%')); - fmt.Append(_T('d')); - - restart = true; - - break; - } - - // no, it wasn't the width - wxFAIL_MSG(_T("unknown format specificator")); - - // fall through and just copy it nevertheless - - case _T('%'): // a percent sign - res += *p; - break; - - case 0: // the end of string - wxFAIL_MSG(_T("missing format at the end of string")); - - // just put the '%' which was the last char in format - res += _T('%'); - break; - } - } - } - - return res; -} - -// this function parses a string in (strict) RFC 822 format: see the section 5 -// of the RFC for the detailed description, but briefly it's something of the -// form "Sat, 18 Dec 1999 00:48:30 +0100" -// -// this function is "strict" by design - it must reject anything except true -// RFC822 time specs. -// -// TODO a great candidate for using reg exps -const wxChar *wxDateTime::ParseRfc822Date(const wxChar* date) -{ - wxCHECK_MSG( date, (wxChar *)NULL, _T("NULL pointer in wxDateTime::Parse") ); - - const wxChar *p = date; - const wxChar *comma = wxStrchr(p, _T(',')); - if ( comma ) - { - // the part before comma is the weekday - - // skip it for now - we don't use but might check that it really - // corresponds to the specfied date - p = comma + 1; - - if ( *p != _T(' ') ) - { - wxLogDebug(_T("no space after weekday in RFC822 time spec")); - - return (wxChar *)NULL; - } - - p++; // skip space - } - - // the following 1 or 2 digits are the day number - if ( !wxIsdigit(*p) ) - { - wxLogDebug(_T("day number expected in RFC822 time spec, none found")); - - return (wxChar *)NULL; - } - - wxDateTime_t day = (wxDateTime_t)(*p++ - _T('0')); - if ( wxIsdigit(*p) ) - { - day *= 10; - day = (wxDateTime_t)(day + (*p++ - _T('0'))); - } - - if ( *p++ != _T(' ') ) - { - return (wxChar *)NULL; - } - - // the following 3 letters specify the month - wxString monName(p, 3); - Month mon; - if ( monName == _T("Jan") ) - mon = Jan; - else if ( monName == _T("Feb") ) - mon = Feb; - else if ( monName == _T("Mar") ) - mon = Mar; - else if ( monName == _T("Apr") ) - mon = Apr; - else if ( monName == _T("May") ) - mon = May; - else if ( monName == _T("Jun") ) - mon = Jun; - else if ( monName == _T("Jul") ) - mon = Jul; - else if ( monName == _T("Aug") ) - mon = Aug; - else if ( monName == _T("Sep") ) - mon = Sep; - else if ( monName == _T("Oct") ) - mon = Oct; - else if ( monName == _T("Nov") ) - mon = Nov; - else if ( monName == _T("Dec") ) - mon = Dec; - else - { - wxLogDebug(_T("Invalid RFC 822 month name '%s'"), monName.c_str()); - - return (wxChar *)NULL; - } - - p += 3; - - if ( *p++ != _T(' ') ) - { - return (wxChar *)NULL; - } - - // next is the year - if ( !wxIsdigit(*p) ) - { - // no year? - return (wxChar *)NULL; - } - - int year = *p++ - _T('0'); - - if ( !wxIsdigit(*p) ) - { - // should have at least 2 digits in the year - return (wxChar *)NULL; - } - - year *= 10; - year += *p++ - _T('0'); - - // is it a 2 digit year (as per original RFC 822) or a 4 digit one? - if ( wxIsdigit(*p) ) - { - year *= 10; - year += *p++ - _T('0'); - - if ( !wxIsdigit(*p) ) - { - // no 3 digit years please - return (wxChar *)NULL; - } - - year *= 10; - year += *p++ - _T('0'); - } - - if ( *p++ != _T(' ') ) - { - return (wxChar *)NULL; - } - - // time is in the format hh:mm:ss and seconds are optional - if ( !wxIsdigit(*p) ) - { - return (wxChar *)NULL; - } - - wxDateTime_t hour = (wxDateTime_t)(*p++ - _T('0')); - - if ( !wxIsdigit(*p) ) - { - return (wxChar *)NULL; - } - - hour *= 10; - hour = (wxDateTime_t)(hour + (*p++ - _T('0'))); - - if ( *p++ != _T(':') ) - { - return (wxChar *)NULL; - } - - if ( !wxIsdigit(*p) ) - { - return (wxChar *)NULL; - } - - wxDateTime_t min = (wxDateTime_t)(*p++ - _T('0')); - - if ( !wxIsdigit(*p) ) - { - return (wxChar *)NULL; - } - - min *= 10; - min = (wxDateTime_t)(min + *p++ - _T('0')); - - wxDateTime_t sec = 0; - if ( *p == _T(':') ) - { - p++; - if ( !wxIsdigit(*p) ) - { - return (wxChar *)NULL; - } - - sec = (wxDateTime_t)(*p++ - _T('0')); - - if ( !wxIsdigit(*p) ) - { - return (wxChar *)NULL; - } - - sec *= 10; - sec = (wxDateTime_t)(sec + *p++ - _T('0')); - } - - if ( *p++ != _T(' ') ) - { - return (wxChar *)NULL; - } - - // and now the interesting part: the timezone - int offset wxDUMMY_INITIALIZE(0); - if ( *p == _T('-') || *p == _T('+') ) - { - // the explicit offset given: it has the form of hhmm - bool plus = *p++ == _T('+'); - - if ( !wxIsdigit(*p) || !wxIsdigit(*(p + 1)) ) - { - return (wxChar *)NULL; - } - - // hours - offset = MIN_PER_HOUR*(10*(*p - _T('0')) + (*(p + 1) - _T('0'))); - - p += 2; - - if ( !wxIsdigit(*p) || !wxIsdigit(*(p + 1)) ) - { - return (wxChar *)NULL; - } - - // minutes - offset += 10*(*p - _T('0')) + (*(p + 1) - _T('0')); - - if ( !plus ) - { - offset = -offset; - } - - p += 2; - } - else - { - // the symbolic timezone given: may be either military timezone or one - // of standard abbreviations - if ( !*(p + 1) ) - { - // military: Z = UTC, J unused, A = -1, ..., Y = +12 - static const int offsets[26] = - { - //A B C D E F G H I J K L M - -1, -2, -3, -4, -5, -6, -7, -8, -9, 0, -10, -11, -12, - //N O P R Q S T U V W Z Y Z - +1, +2, +3, +4, +5, +6, +7, +8, +9, +10, +11, +12, 0 - }; - - if ( *p < _T('A') || *p > _T('Z') || *p == _T('J') ) - { - wxLogDebug(_T("Invalid militaty timezone '%c'"), *p); - - return (wxChar *)NULL; - } - - offset = offsets[*p++ - _T('A')]; - } - else - { - // abbreviation - wxString tz = p; - if ( tz == _T("UT") || tz == _T("UTC") || tz == _T("GMT") ) - offset = 0; - else if ( tz == _T("AST") ) - offset = AST - GMT0; - else if ( tz == _T("ADT") ) - offset = ADT - GMT0; - else if ( tz == _T("EST") ) - offset = EST - GMT0; - else if ( tz == _T("EDT") ) - offset = EDT - GMT0; - else if ( tz == _T("CST") ) - offset = CST - GMT0; - else if ( tz == _T("CDT") ) - offset = CDT - GMT0; - else if ( tz == _T("MST") ) - offset = MST - GMT0; - else if ( tz == _T("MDT") ) - offset = MDT - GMT0; - else if ( tz == _T("PST") ) - offset = PST - GMT0; - else if ( tz == _T("PDT") ) - offset = PDT - GMT0; - else - { - wxLogDebug(_T("Unknown RFC 822 timezone '%s'"), p); - - return (wxChar *)NULL; - } - - p += tz.length(); - } - - // make it minutes - offset *= MIN_PER_HOUR; - } - - // the spec was correct, construct the date from the values we found - Set(day, mon, year, hour, min, sec); - MakeFromTimezone(TimeZone::Make(offset*SEC_PER_MIN)); - - return p; -} - -#ifdef __WINDOWS__ - -// returns the string containing strftime() format used for short dates in the -// current locale or an empty string -static wxString GetLocaleDateFormat() -{ - wxString fmtWX; - - // there is no setlocale() under Windows CE, so just always query the - // system there -#ifndef __WXWINCE__ - if ( strcmp(setlocale(LC_ALL, NULL), "C") != 0 ) -#endif - { - // The locale was programatically set to non-C. We assume that this was - // done using wxLocale, in which case thread's current locale is also - // set to correct LCID value and we can use GetLocaleInfo to determine - // the correct formatting string: -#ifdef __WXWINCE__ - LCID lcid = LOCALE_USER_DEFAULT; -#else - LCID lcid = GetThreadLocale(); -#endif - // according to MSDN 80 chars is max allowed for short date format - wxChar fmt[81]; - if ( ::GetLocaleInfo(lcid, LOCALE_SSHORTDATE, fmt, WXSIZEOF(fmt)) ) - { - wxChar chLast = _T('\0'); - size_t lastCount = 0; - for ( const wxChar *p = fmt; /* NUL handled inside */; p++ ) - { - if ( *p == chLast ) - { - lastCount++; - continue; - } - - switch ( *p ) - { - // these characters come in groups, start counting them - case _T('d'): - case _T('M'): - case _T('y'): - case _T('g'): - chLast = *p; - lastCount = 1; - break; - - default: - // first deal with any special characters we have had - if ( lastCount ) - { - switch ( chLast ) - { - case _T('d'): - switch ( lastCount ) - { - case 1: // d - case 2: // dd - // these two are the same as we - // don't distinguish between 1 and - // 2 digits for days - fmtWX += _T("%d"); - break; - - case 3: // ddd - fmtWX += _T("%a"); - break; - - case 4: // dddd - fmtWX += _T("%A"); - break; - - default: - wxFAIL_MSG( _T("too many 'd's") ); - } - break; - - case _T('M'): - switch ( lastCount ) - { - case 1: // M - case 2: // MM - // as for 'd' and 'dd' above - fmtWX += _T("%m"); - break; - - case 3: - fmtWX += _T("%b"); - break; - - case 4: - fmtWX += _T("%B"); - break; - - default: - wxFAIL_MSG( _T("too many 'M's") ); - } - break; - - case _T('y'): - switch ( lastCount ) - { - case 1: // y - case 2: // yy - fmtWX += _T("%y"); - break; - - case 4: // yyyy - fmtWX += _T("%Y"); - break; - - default: - wxFAIL_MSG( _T("wrong number of 'y's") ); - } - break; - - case _T('g'): - // strftime() doesn't have era string, - // ignore this format - wxASSERT_MSG( lastCount <= 2, - _T("too many 'g's") ); - break; - - default: - wxFAIL_MSG( _T("unreachable") ); - } - - chLast = _T('\0'); - lastCount = 0; - } - - // not a special character so must be just a separator, - // treat as is - if ( *p != _T('\0') ) - { - if ( *p == _T('%') ) - { - // this one needs to be escaped - fmtWX += _T('%'); - } - - fmtWX += *p; - } - } - - if ( *p == _T('\0') ) - break; - } - } - //else: GetLocaleInfo() failed, leave fmtDate value unchanged and - // try our luck with the default formats - } - //else: default C locale, default formats should work - - return fmtWX; -} - -#endif // __WINDOWS__ - -const wxChar *wxDateTime::ParseFormat(const wxChar *date, - const wxChar *format, - const wxDateTime& dateDef) -{ - wxCHECK_MSG( date && format, (wxChar *)NULL, - _T("NULL pointer in wxDateTime::ParseFormat()") ); - - wxString str; - unsigned long num; - - // what fields have we found? - bool haveWDay = false, - haveYDay = false, - haveDay = false, - haveMon = false, - haveYear = false, - haveHour = false, - haveMin = false, - haveSec = false; - - bool hourIsIn12hFormat = false, // or in 24h one? - isPM = false; // AM by default - - // and the value of the items we have (init them to get rid of warnings) - wxDateTime_t sec = 0, - min = 0, - hour = 0; - WeekDay wday = Inv_WeekDay; - wxDateTime_t yday = 0, - mday = 0; - wxDateTime::Month mon = Inv_Month; - int year = 0; - - const wxChar *input = date; - for ( const wxChar *fmt = format; *fmt; fmt++ ) - { - if ( *fmt != _T('%') ) - { - if ( wxIsspace(*fmt) ) - { - // a white space in the format string matches 0 or more white - // spaces in the input - while ( wxIsspace(*input) ) - { - input++; - } - } - else // !space - { - // any other character (not whitespace, not '%') must be - // matched by itself in the input - if ( *input++ != *fmt ) - { - // no match - return (wxChar *)NULL; - } - } - - // done with this format char - continue; - } - - // start of a format specification - - // parse the optional width - size_t width = 0; - while ( wxIsdigit(*++fmt) ) - { - width *= 10; - width += *fmt - _T('0'); - } - - // the default widths for the various fields - if ( !width ) - { - switch ( *fmt ) - { - case _T('Y'): // year has 4 digits - width = 4; - break; - - case _T('j'): // day of year has 3 digits - case _T('l'): // milliseconds have 3 digits - width = 3; - break; - - case _T('w'): // week day as number has only one - width = 1; - break; - - default: - // default for all other fields - width = 2; - } - } - - // then the format itself - switch ( *fmt ) - { - case _T('a'): // a weekday name - case _T('A'): - { - int flag = *fmt == _T('a') ? Name_Abbr : Name_Full; - wday = GetWeekDayFromName(GetAlphaToken(input), flag); - if ( wday == Inv_WeekDay ) - { - // no match - return (wxChar *)NULL; - } - } - haveWDay = true; - break; - - case _T('b'): // a month name - case _T('B'): - { - int flag = *fmt == _T('b') ? Name_Abbr : Name_Full; - mon = GetMonthFromName(GetAlphaToken(input), flag); - if ( mon == Inv_Month ) - { - // no match - return (wxChar *)NULL; - } - } - haveMon = true; - break; - - case _T('c'): // locale default date and time representation - { - wxDateTime dt; - - // this is the format which corresponds to ctime() output - // and strptime("%c") should parse it, so try it first - static const wxChar *fmtCtime = _T("%a %b %d %H:%M:%S %Y"); - - const wxChar *result = dt.ParseFormat(input, fmtCtime); - if ( !result ) - { - result = dt.ParseFormat(input, _T("%x %X")); - } - - if ( !result ) - { - result = dt.ParseFormat(input, _T("%X %x")); - } - - if ( !result ) - { - // we've tried everything and still no match - return (wxChar *)NULL; - } - - Tm tm = dt.GetTm(); - - haveDay = haveMon = haveYear = - haveHour = haveMin = haveSec = true; - - hour = tm.hour; - min = tm.min; - sec = tm.sec; - - year = tm.year; - mon = tm.mon; - mday = tm.mday; - - input = result; - } - break; - - case _T('d'): // day of a month (01-31) - if ( !GetNumericToken(width, input, &num) || - (num > 31) || (num < 1) ) - { - // no match - return (wxChar *)NULL; - } - - // we can't check whether the day range is correct yet, will - // do it later - assume ok for now - haveDay = true; - mday = (wxDateTime_t)num; - break; - - case _T('H'): // hour in 24h format (00-23) - if ( !GetNumericToken(width, input, &num) || (num > 23) ) - { - // no match - return (wxChar *)NULL; - } - - haveHour = true; - hour = (wxDateTime_t)num; - break; - - case _T('I'): // hour in 12h format (01-12) - if ( !GetNumericToken(width, input, &num) || !num || (num > 12) ) - { - // no match - return (wxChar *)NULL; - } - - haveHour = true; - hourIsIn12hFormat = true; - hour = (wxDateTime_t)(num % 12); // 12 should be 0 - break; - - case _T('j'): // day of the year - if ( !GetNumericToken(width, input, &num) || !num || (num > 366) ) - { - // no match - return (wxChar *)NULL; - } - - haveYDay = true; - yday = (wxDateTime_t)num; - break; - - case _T('m'): // month as a number (01-12) - if ( !GetNumericToken(width, input, &num) || !num || (num > 12) ) - { - // no match - return (wxChar *)NULL; - } - - haveMon = true; - mon = (Month)(num - 1); - break; - - case _T('M'): // minute as a decimal number (00-59) - if ( !GetNumericToken(width, input, &num) || (num > 59) ) - { - // no match - return (wxChar *)NULL; - } - - haveMin = true; - min = (wxDateTime_t)num; - break; - - case _T('p'): // AM or PM string - { - wxString am, pm, token = GetAlphaToken(input); - - GetAmPmStrings(&am, &pm); - if (am.empty() && pm.empty()) - return (wxChar *)NULL; // no am/pm strings defined - if ( token.CmpNoCase(pm) == 0 ) - { - isPM = true; - } - else if ( token.CmpNoCase(am) != 0 ) - { - // no match - return (wxChar *)NULL; - } - } - break; - - case _T('r'): // time as %I:%M:%S %p - { - wxDateTime dt; - input = dt.ParseFormat(input, _T("%I:%M:%S %p")); - if ( !input ) - { - // no match - return (wxChar *)NULL; - } - - haveHour = haveMin = haveSec = true; - - Tm tm = dt.GetTm(); - hour = tm.hour; - min = tm.min; - sec = tm.sec; - } - break; - - case _T('R'): // time as %H:%M - { - wxDateTime dt; - input = dt.ParseFormat(input, _T("%H:%M")); - if ( !input ) - { - // no match - return (wxChar *)NULL; - } - - haveHour = haveMin = true; - - Tm tm = dt.GetTm(); - hour = tm.hour; - min = tm.min; - } - break; - - case _T('S'): // second as a decimal number (00-61) - if ( !GetNumericToken(width, input, &num) || (num > 61) ) - { - // no match - return (wxChar *)NULL; - } - - haveSec = true; - sec = (wxDateTime_t)num; - break; - - case _T('T'): // time as %H:%M:%S - { - wxDateTime dt; - input = dt.ParseFormat(input, _T("%H:%M:%S")); - if ( !input ) - { - // no match - return (wxChar *)NULL; - } - - haveHour = haveMin = haveSec = true; - - Tm tm = dt.GetTm(); - hour = tm.hour; - min = tm.min; - sec = tm.sec; - } - break; - - case _T('w'): // weekday as a number (0-6), Sunday = 0 - if ( !GetNumericToken(width, input, &num) || (wday > 6) ) - { - // no match - return (wxChar *)NULL; - } - - haveWDay = true; - wday = (WeekDay)num; - break; - - case _T('x'): // locale default date representation -#ifdef HAVE_STRPTIME - // try using strptime() -- it may fail even if the input is - // correct but the date is out of range, so we will fall back - // to our generic code anyhow - { - struct tm tm; - - const wxChar *result = CallStrptime(input, "%x", &tm); - if ( result ) - { - input = result; - - haveDay = haveMon = haveYear = true; - - year = 1900 + tm.tm_year; - mon = (Month)tm.tm_mon; - mday = tm.tm_mday; - - break; - } - } -#endif // HAVE_STRPTIME - - { - wxDateTime dt; - wxString fmtDate, - fmtDateAlt; - -#ifdef __WINDOWS__ - // The above doesn't work for all locales, try to query - // Windows for the right way of formatting the date: - fmtDate = GetLocaleDateFormat(); - if ( fmtDate.empty() ) -#endif - { - if ( IsWestEuropeanCountry(GetCountry()) || - GetCountry() == Russia ) - { - fmtDate = _T("%d/%m/%y"); - fmtDateAlt = _T("%m/%d/%y"); - } - else // assume USA - { - fmtDate = _T("%m/%d/%y"); - fmtDateAlt = _T("%d/%m/%y"); - } - } - - const wxChar *result = dt.ParseFormat(input, fmtDate); - - if ( !result && !fmtDateAlt.empty() ) - { - // ok, be nice and try another one - result = dt.ParseFormat(input, fmtDateAlt); - } - - if ( !result ) - { - // bad luck - return (wxChar *)NULL; - } - - Tm tm = dt.GetTm(); - - haveDay = haveMon = haveYear = true; - - year = tm.year; - mon = tm.mon; - mday = tm.mday; - - input = result; - } - - break; - - case _T('X'): // locale default time representation -#ifdef HAVE_STRPTIME - { - // use strptime() to do it for us (FIXME !Unicode friendly) - struct tm tm; - input = CallStrptime(input, "%X", &tm); - if ( !input ) - { - return (wxChar *)NULL; - } - - haveHour = haveMin = haveSec = true; - - hour = tm.tm_hour; - min = tm.tm_min; - sec = tm.tm_sec; - } -#else // !HAVE_STRPTIME - // TODO under Win32 we can query the LOCALE_ITIME system - // setting which says whether the default time format is - // 24 or 12 hour - { - // try to parse what follows as "%H:%M:%S" and, if this - // fails, as "%I:%M:%S %p" - this should catch the most - // common cases - wxDateTime dt; - - const wxChar *result = dt.ParseFormat(input, _T("%T")); - if ( !result ) - { - result = dt.ParseFormat(input, _T("%r")); - } - - if ( !result ) - { - // no match - return (wxChar *)NULL; - } - - haveHour = haveMin = haveSec = true; - - Tm tm = dt.GetTm(); - hour = tm.hour; - min = tm.min; - sec = tm.sec; - - input = result; - } -#endif // HAVE_STRPTIME/!HAVE_STRPTIME - break; - - case _T('y'): // year without century (00-99) - if ( !GetNumericToken(width, input, &num) || (num > 99) ) - { - // no match - return (wxChar *)NULL; - } - - haveYear = true; - - // TODO should have an option for roll over date instead of - // hard coding it here - year = (num > 30 ? 1900 : 2000) + (wxDateTime_t)num; - break; - - case _T('Y'): // year with century - if ( !GetNumericToken(width, input, &num) ) - { - // no match - return (wxChar *)NULL; - } - - haveYear = true; - year = (wxDateTime_t)num; - break; - - case _T('Z'): // timezone name - wxFAIL_MSG(_T("TODO")); - break; - - case _T('%'): // a percent sign - if ( *input++ != _T('%') ) - { - // no match - return (wxChar *)NULL; - } - break; - - case 0: // the end of string - wxFAIL_MSG(_T("unexpected format end")); - - // fall through - - default: // not a known format spec - return (wxChar *)NULL; - } - } - - // format matched, try to construct a date from what we have now - Tm tmDef; - if ( dateDef.IsValid() ) - { - // take this date as default - tmDef = dateDef.GetTm(); - } - else if ( IsValid() ) - { - // if this date is valid, don't change it - tmDef = GetTm(); - } - else - { - // no default and this date is invalid - fall back to Today() - tmDef = Today().GetTm(); - } - - Tm tm = tmDef; - - // set the date - if ( haveYear ) - { - tm.year = year; - } - - // TODO we don't check here that the values are consistent, if both year - // day and month/day were found, we just ignore the year day and we - // also always ignore the week day - if ( haveMon && haveDay ) - { - if ( mday > GetNumOfDaysInMonth(tm.year, mon) ) - { - wxLogDebug(_T("bad month day in wxDateTime::ParseFormat")); - - return (wxChar *)NULL; - } - - tm.mon = mon; - tm.mday = mday; - } - else if ( haveYDay ) - { - if ( yday > GetNumberOfDays(tm.year) ) - { - wxLogDebug(_T("bad year day in wxDateTime::ParseFormat")); - - return (wxChar *)NULL; - } - - Tm tm2 = wxDateTime(1, Jan, tm.year).SetToYearDay(yday).GetTm(); - - tm.mon = tm2.mon; - tm.mday = tm2.mday; - } - - // deal with AM/PM - if ( haveHour && hourIsIn12hFormat && isPM ) - { - // translate to 24hour format - hour += 12; - } - //else: either already in 24h format or no translation needed - - // set the time - if ( haveHour ) - { - tm.hour = hour; - } - - if ( haveMin ) - { - tm.min = min; - } - - if ( haveSec ) - { - tm.sec = sec; - } - - Set(tm); - - // finally check that the week day is consistent -- if we had it - if ( haveWDay && GetWeekDay() != wday ) - { - wxLogDebug(_T("inconsistsnet week day in wxDateTime::ParseFormat()")); - - return NULL; - } - - return input; -} - -const wxChar *wxDateTime::ParseDateTime(const wxChar *date) -{ - wxCHECK_MSG( date, (wxChar *)NULL, _T("NULL pointer in wxDateTime::Parse") ); - - // Set to current day and hour, so strings like '14:00' becomes today at - // 14, not some other random date - wxDateTime dtDate = wxDateTime::Today(); - wxDateTime dtTime = wxDateTime::Today(); - - const wxChar* pchTime; - - // Try to parse the beginning of the string as a date - const wxChar* pchDate = dtDate.ParseDate(date); - - // We got a date in the beginning, see if there is a time specified after the date - if ( pchDate ) - { - // Skip spaces, as the ParseTime() function fails on spaces - while ( wxIsspace(*pchDate) ) - pchDate++; - - pchTime = dtTime.ParseTime(pchDate); - } - else // no date in the beginning - { - // check and see if we have a time followed by a date - pchTime = dtTime.ParseTime(date); - if ( pchTime ) - { - while ( wxIsspace(*pchTime) ) - pchTime++; - - pchDate = dtDate.ParseDate(pchTime); - } - } - - // If we have a date specified, set our own data to the same date - if ( !pchDate || !pchTime ) - return NULL; - - Set(dtDate.GetDay(), dtDate.GetMonth(), dtDate.GetYear(), - dtTime.GetHour(), dtTime.GetMinute(), dtTime.GetSecond(), - dtTime.GetMillisecond()); - - // Return endpoint of scan - return pchDate > pchTime ? pchDate : pchTime; -} - -const wxChar *wxDateTime::ParseDate(const wxChar *date) -{ - // this is a simplified version of ParseDateTime() which understands only - // "today" (for wxDate compatibility) and digits only otherwise (and not - // all esoteric constructions ParseDateTime() knows about) - - wxCHECK_MSG( date, (wxChar *)NULL, _T("NULL pointer in wxDateTime::Parse") ); - - const wxChar *p = date; - while ( wxIsspace(*p) ) - p++; - - // some special cases - static struct - { - const wxChar *str; - int dayDiffFromToday; - } literalDates[] = - { - { wxTRANSLATE("today"), 0 }, - { wxTRANSLATE("yesterday"), -1 }, - { wxTRANSLATE("tomorrow"), 1 }, - }; - - for ( size_t n = 0; n < WXSIZEOF(literalDates); n++ ) - { - const wxString dateStr = wxGetTranslation(literalDates[n].str); - size_t len = dateStr.length(); - if ( wxStrlen(p) >= len ) - { - wxString str(p, len); - if ( str.CmpNoCase(dateStr) == 0 ) - { - // nothing can follow this, so stop here - p += len; - - int dayDiffFromToday = literalDates[n].dayDiffFromToday; - *this = Today(); - if ( dayDiffFromToday ) - { - *this += wxDateSpan::Days(dayDiffFromToday); - } - - return p; - } - } - } - - // We try to guess what we have here: for each new (numeric) token, we - // determine if it can be a month, day or a year. Of course, there is an - // ambiguity as some numbers may be days as well as months, so we also - // have the ability to back track. - - // what do we have? - bool haveDay = false, // the months day? - haveWDay = false, // the day of week? - haveMon = false, // the month? - haveYear = false; // the year? - - // and the value of the items we have (init them to get rid of warnings) - WeekDay wday = Inv_WeekDay; - wxDateTime_t day = 0; - wxDateTime::Month mon = Inv_Month; - int year = 0; - - // tokenize the string - size_t nPosCur = 0; - static const wxChar *dateDelimiters = _T(".,/-\t\r\n "); - wxStringTokenizer tok(p, dateDelimiters); - while ( tok.HasMoreTokens() ) - { - wxString token = tok.GetNextToken(); - if ( !token ) - continue; - - // is it a number? - unsigned long val; - if ( token.ToULong(&val) ) - { - // guess what this number is - - bool isDay = false, - isMonth = false, - isYear = false; - - if ( !haveMon && val > 0 && val <= 12 ) - { - // assume it is month - isMonth = true; - } - else // not the month - { - if ( haveDay ) - { - // this can only be the year - isYear = true; - } - else // may be either day or year - { - // use a leap year if we don't have the year yet to allow - // dates like 2/29/1976 which would be rejected otherwise - wxDateTime_t max_days = (wxDateTime_t)( - haveMon - ? GetNumOfDaysInMonth(haveYear ? year : 1976, mon) - : 31 - ); - - // can it be day? - if ( (val == 0) || (val > (unsigned long)max_days) ) - { - // no - isYear = true; - } - else // yes, suppose it's the day - { - isDay = true; - } - } - } - - if ( isYear ) - { - if ( haveYear ) - break; - - haveYear = true; - - year = (wxDateTime_t)val; - } - else if ( isDay ) - { - if ( haveDay ) - break; - - haveDay = true; - - day = (wxDateTime_t)val; - } - else if ( isMonth ) - { - haveMon = true; - - mon = (Month)(val - 1); - } - } - else // not a number - { - // be careful not to overwrite the current mon value - Month mon2 = GetMonthFromName(token, Name_Full | Name_Abbr); - if ( mon2 != Inv_Month ) - { - // it's a month - if ( haveMon ) - { - // but we already have a month - maybe we guessed wrong? - if ( !haveDay ) - { - // no need to check in month range as always < 12, but - // the days are counted from 1 unlike the months - day = (wxDateTime_t)(mon + 1); - haveDay = true; - } - else - { - // could possible be the year (doesn't the year come - // before the month in the japanese format?) (FIXME) - break; - } - } - - mon = mon2; - - haveMon = true; - } - else // not a valid month name - { - WeekDay wday2 = GetWeekDayFromName(token, Name_Full | Name_Abbr); - if ( wday2 != Inv_WeekDay ) - { - // a week day - if ( haveWDay ) - { - break; - } - - wday = wday2; - - haveWDay = true; - } - else // not a valid weekday name - { - // try the ordinals - static const wxChar *ordinals[] = - { - wxTRANSLATE("first"), - wxTRANSLATE("second"), - wxTRANSLATE("third"), - wxTRANSLATE("fourth"), - wxTRANSLATE("fifth"), - wxTRANSLATE("sixth"), - wxTRANSLATE("seventh"), - wxTRANSLATE("eighth"), - wxTRANSLATE("ninth"), - wxTRANSLATE("tenth"), - wxTRANSLATE("eleventh"), - wxTRANSLATE("twelfth"), - wxTRANSLATE("thirteenth"), - wxTRANSLATE("fourteenth"), - wxTRANSLATE("fifteenth"), - wxTRANSLATE("sixteenth"), - wxTRANSLATE("seventeenth"), - wxTRANSLATE("eighteenth"), - wxTRANSLATE("nineteenth"), - wxTRANSLATE("twentieth"), - // that's enough - otherwise we'd have problems with - // composite (or not) ordinals - }; - - size_t n; - for ( n = 0; n < WXSIZEOF(ordinals); n++ ) - { - if ( token.CmpNoCase(ordinals[n]) == 0 ) - { - break; - } - } - - if ( n == WXSIZEOF(ordinals) ) - { - // stop here - something unknown - break; - } - - // it's a day - if ( haveDay ) - { - // don't try anything here (as in case of numeric day - // above) - the symbolic day spec should always - // precede the month/year - break; - } - - haveDay = true; - - day = (wxDateTime_t)(n + 1); - } - } - } - - nPosCur = tok.GetPosition(); - } - - // either no more tokens or the scan was stopped by something we couldn't - // parse - in any case, see if we can construct a date from what we have - if ( !haveDay && !haveWDay ) - { - wxLogDebug(_T("ParseDate: no day, no weekday hence no date.")); - - return NULL; - } - - if ( haveWDay && (haveMon || haveYear || haveDay) && - !(haveDay && haveMon && haveYear) ) - { - // without adjectives (which we don't support here) the week day only - // makes sense completely separately or with the full date - // specification (what would "Wed 1999" mean?) - return NULL; - } - - if ( !haveWDay && haveYear && !(haveDay && haveMon) ) - { - // may be we have month and day instead of day and year? - if ( haveDay && !haveMon ) - { - if ( day <= 12 ) - { - // exchange day and month - mon = (wxDateTime::Month)(day - 1); - - // we're in the current year then - if ( (year > 0) && (year <= (int)GetNumOfDaysInMonth(Inv_Year, mon)) ) - { - day = (wxDateTime_t)year; - - haveMon = true; - haveYear = false; - } - //else: no, can't exchange, leave haveMon == false - } - } - - if ( !haveMon ) - { - // if we give the year, month and day must be given too - wxLogDebug(_T("ParseDate: day and month should be specified if year is.")); - - return NULL; - } - } - - if ( !haveMon ) - { - mon = GetCurrentMonth(); - } - - if ( !haveYear ) - { - year = GetCurrentYear(); - } - - if ( haveDay ) - { - // normally we check the day above but the check is optimistic in case - // we find the day before its month/year so we have to redo it now - if ( day > GetNumOfDaysInMonth(year, mon) ) - return NULL; - - Set(day, mon, year); - - if ( haveWDay ) - { - // check that it is really the same - if ( GetWeekDay() != wday ) - { - // inconsistency detected - wxLogDebug(_T("ParseDate: inconsistent day/weekday.")); - - return (wxChar *)NULL; - } - } - } - else // haveWDay - { - *this = Today(); - - SetToWeekDayInSameWeek(wday); - } - - // return the pointer to the first unparsed char - p += nPosCur; - if ( nPosCur && wxStrchr(dateDelimiters, *(p - 1)) ) - { - // if we couldn't parse the token after the delimiter, put back the - // delimiter as well - p--; - } - - return p; -} - -const wxChar *wxDateTime::ParseTime(const wxChar *time) -{ - wxCHECK_MSG( time, (wxChar *)NULL, _T("NULL pointer in wxDateTime::Parse") ); - - // first try some extra things - static const struct - { - const wxChar *name; - wxDateTime_t hour; - } stdTimes[] = - { - { wxTRANSLATE("noon"), 12 }, - { wxTRANSLATE("midnight"), 00 }, - // anything else? - }; - - for ( size_t n = 0; n < WXSIZEOF(stdTimes); n++ ) - { - wxString timeString = wxGetTranslation(stdTimes[n].name); - size_t len = timeString.length(); - if ( timeString.CmpNoCase(wxString(time, len)) == 0 ) - { - // casts required by DigitalMars - Set(stdTimes[n].hour, wxDateTime_t(0), wxDateTime_t(0)); - - return time + len; - } - } - - // try all time formats we may think about in the order from longest to - // shortest - - // 12hour with AM/PM? - const wxChar *result = ParseFormat(time, _T("%I:%M:%S %p")); - - if ( !result ) - { - // normally, it's the same, but why not try it? - result = ParseFormat(time, _T("%H:%M:%S")); - } - - if ( !result ) - { - // 12hour with AM/PM but without seconds? - result = ParseFormat(time, _T("%I:%M %p")); - } - - if ( !result ) - { - // without seconds? - result = ParseFormat(time, _T("%H:%M")); - } - - if ( !result ) - { - // just the hour and AM/PM? - result = ParseFormat(time, _T("%I %p")); - } - - if ( !result ) - { - // just the hour? - result = ParseFormat(time, _T("%H")); - } - - if ( !result ) - { - // parse the standard format: normally it is one of the formats above - // but it may be set to something completely different by the user - result = ParseFormat(time, _T("%X")); - } - - // TODO: parse timezones - - return result; -} - -// ---------------------------------------------------------------------------- -// Workdays and holidays support -// ---------------------------------------------------------------------------- - -bool wxDateTime::IsWorkDay(Country WXUNUSED(country)) const -{ - return !wxDateTimeHolidayAuthority::IsHoliday(*this); -} - -// ============================================================================ -// wxDateSpan -// ============================================================================ - -wxDateSpan WXDLLIMPEXP_BASE operator*(int n, const wxDateSpan& ds) -{ - wxDateSpan ds1(ds); - return ds1.Multiply(n); -} - -// ============================================================================ -// wxTimeSpan -// ============================================================================ - -wxTimeSpan WXDLLIMPEXP_BASE operator*(int n, const wxTimeSpan& ts) -{ - return wxTimeSpan(ts).Multiply(n); -} - -// this enum is only used in wxTimeSpan::Format() below but we can't declare -// it locally to the method as it provokes an internal compiler error in egcs -// 2.91.60 when building with -O2 -enum TimeSpanPart -{ - Part_Week, - Part_Day, - Part_Hour, - Part_Min, - Part_Sec, - Part_MSec -}; - -// not all strftime(3) format specifiers make sense here because, for example, -// a time span doesn't have a year nor a timezone -// -// Here are the ones which are supported (all of them are supported by strftime -// as well): -// %H hour in 24 hour format -// %M minute (00 - 59) -// %S second (00 - 59) -// %% percent sign -// -// Also, for MFC CTimeSpan compatibility, we support -// %D number of days -// -// And, to be better than MFC :-), we also have -// %E number of wEeks -// %l milliseconds (000 - 999) -wxString wxTimeSpan::Format(const wxChar *format) const -{ - wxCHECK_MSG( format, wxEmptyString, _T("NULL format in wxTimeSpan::Format") ); - - wxString str; - str.Alloc(wxStrlen(format)); - - // Suppose we have wxTimeSpan ts(1 /* hour */, 2 /* min */, 3 /* sec */) - // - // Then, of course, ts.Format("%H:%M:%S") must return "01:02:03", but the - // question is what should ts.Format("%S") do? The code here returns "3273" - // in this case (i.e. the total number of seconds, not just seconds % 60) - // because, for me, this call means "give me entire time interval in - // seconds" and not "give me the seconds part of the time interval" - // - // If we agree that it should behave like this, it is clear that the - // interpretation of each format specifier depends on the presence of the - // other format specs in the string: if there was "%H" before "%M", we - // should use GetMinutes() % 60, otherwise just GetMinutes() &c - - // we remember the most important unit found so far - TimeSpanPart partBiggest = Part_MSec; - - for ( const wxChar *pch = format; *pch; pch++ ) - { - wxChar ch = *pch; - - if ( ch == _T('%') ) - { - // the start of the format specification of the printf() below - wxString fmtPrefix(_T('%')); - - // the number - long n; - - // the number of digits for the format string, 0 if unused - unsigned digits = 0; - - ch = *++pch; // get the format spec char - switch ( ch ) - { - default: - wxFAIL_MSG( _T("invalid format character") ); - // fall through - - case _T('%'): - str += ch; - - // skip the part below switch - continue; - - case _T('D'): - n = GetDays(); - if ( partBiggest < Part_Day ) - { - n %= DAYS_PER_WEEK; - } - else - { - partBiggest = Part_Day; - } - break; - - case _T('E'): - partBiggest = Part_Week; - n = GetWeeks(); - break; - - case _T('H'): - n = GetHours(); - if ( partBiggest < Part_Hour ) - { - if ( n < 0 ) - { - // the sign has already been taken into account - // when outputting the biggest part - n = -n; - } - - n %= HOURS_PER_DAY; - } - else - { - partBiggest = Part_Hour; - } - - digits = 2; - break; - - case _T('l'): - n = GetMilliseconds().ToLong(); - if ( partBiggest < Part_MSec ) - { - if ( n < 0 ) - n = -n; - - n %= 1000; - } - //else: no need to reset partBiggest to Part_MSec, it is - // the least significant one anyhow - - digits = 3; - break; - - case _T('M'): - n = GetMinutes(); - if ( partBiggest < Part_Min ) - { - if ( n < 0 ) - n = -n; - - n %= MIN_PER_HOUR; - } - else - { - partBiggest = Part_Min; - } - - digits = 2; - break; - - case _T('S'): - n = GetSeconds().ToLong(); - if ( partBiggest < Part_Sec ) - { - if ( n < 0 ) - n = -n; - - n %= SEC_PER_MIN; - } - else - { - partBiggest = Part_Sec; - } - - digits = 2; - break; - } - - if ( digits ) - { - // negative numbers need one extra position for '-' display - if ( n < 0 ) - digits++; - - fmtPrefix << _T("0") << digits; - } - - str += wxString::Format(fmtPrefix + _T("ld"), n); - } - else - { - // normal character, just copy - str += ch; - } - } - - return str; -} - -// ============================================================================ -// wxDateTimeHolidayAuthority and related classes -// ============================================================================ - -#include "wx/arrimpl.cpp" - -WX_DEFINE_OBJARRAY(wxDateTimeArray) - -static int wxCMPFUNC_CONV -wxDateTimeCompareFunc(wxDateTime **first, wxDateTime **second) -{ - wxDateTime dt1 = **first, - dt2 = **second; - - return dt1 == dt2 ? 0 : dt1 < dt2 ? -1 : +1; -} - -// ---------------------------------------------------------------------------- -// wxDateTimeHolidayAuthority -// ---------------------------------------------------------------------------- - -wxHolidayAuthoritiesArray wxDateTimeHolidayAuthority::ms_authorities; - -/* static */ -bool wxDateTimeHolidayAuthority::IsHoliday(const wxDateTime& dt) -{ - size_t count = ms_authorities.size(); - for ( size_t n = 0; n < count; n++ ) - { - if ( ms_authorities[n]->DoIsHoliday(dt) ) - { - return true; - } - } - - return false; -} - -/* static */ -size_t -wxDateTimeHolidayAuthority::GetHolidaysInRange(const wxDateTime& dtStart, - const wxDateTime& dtEnd, - wxDateTimeArray& holidays) -{ - wxDateTimeArray hol; - - holidays.Clear(); - - const size_t countAuth = ms_authorities.size(); - for ( size_t nAuth = 0; nAuth < countAuth; nAuth++ ) - { - ms_authorities[nAuth]->DoGetHolidaysInRange(dtStart, dtEnd, hol); - - WX_APPEND_ARRAY(holidays, hol); - } - - holidays.Sort(wxDateTimeCompareFunc); - - return holidays.size(); -} - -/* static */ -void wxDateTimeHolidayAuthority::ClearAllAuthorities() -{ - WX_CLEAR_ARRAY(ms_authorities); -} - -/* static */ -void wxDateTimeHolidayAuthority::AddAuthority(wxDateTimeHolidayAuthority *auth) -{ - ms_authorities.push_back(auth); -} - -wxDateTimeHolidayAuthority::~wxDateTimeHolidayAuthority() -{ - // required here for Darwin -} - -// ---------------------------------------------------------------------------- -// wxDateTimeWorkDays -// ---------------------------------------------------------------------------- - -bool wxDateTimeWorkDays::DoIsHoliday(const wxDateTime& dt) const -{ - wxDateTime::WeekDay wd = dt.GetWeekDay(); - - return (wd == wxDateTime::Sun) || (wd == wxDateTime::Sat); -} - -size_t wxDateTimeWorkDays::DoGetHolidaysInRange(const wxDateTime& dtStart, - const wxDateTime& dtEnd, - wxDateTimeArray& holidays) const -{ - if ( dtStart > dtEnd ) - { - wxFAIL_MSG( _T("invalid date range in GetHolidaysInRange") ); - - return 0u; - } - - holidays.Empty(); - - // instead of checking all days, start with the first Sat after dtStart and - // end with the last Sun before dtEnd - wxDateTime dtSatFirst = dtStart.GetNextWeekDay(wxDateTime::Sat), - dtSatLast = dtEnd.GetPrevWeekDay(wxDateTime::Sat), - dtSunFirst = dtStart.GetNextWeekDay(wxDateTime::Sun), - dtSunLast = dtEnd.GetPrevWeekDay(wxDateTime::Sun), - dt; - - for ( dt = dtSatFirst; dt <= dtSatLast; dt += wxDateSpan::Week() ) - { - holidays.Add(dt); - } - - for ( dt = dtSunFirst; dt <= dtSunLast; dt += wxDateSpan::Week() ) - { - holidays.Add(dt); - } - - return holidays.GetCount(); -} - -// ============================================================================ -// other helper functions -// ============================================================================ - -// ---------------------------------------------------------------------------- -// iteration helpers: can be used to write a for loop over enum variable like -// this: -// for ( m = wxDateTime::Jan; m < wxDateTime::Inv_Month; wxNextMonth(m) ) -// ---------------------------------------------------------------------------- - -WXDLLIMPEXP_BASE void wxNextMonth(wxDateTime::Month& m) -{ - wxASSERT_MSG( m < wxDateTime::Inv_Month, _T("invalid month") ); - - // no wrapping or the for loop above would never end! - m = (wxDateTime::Month)(m + 1); -} - -WXDLLIMPEXP_BASE void wxPrevMonth(wxDateTime::Month& m) -{ - wxASSERT_MSG( m < wxDateTime::Inv_Month, _T("invalid month") ); - - m = m == wxDateTime::Jan ? wxDateTime::Inv_Month - : (wxDateTime::Month)(m - 1); -} - -WXDLLIMPEXP_BASE void wxNextWDay(wxDateTime::WeekDay& wd) -{ - wxASSERT_MSG( wd < wxDateTime::Inv_WeekDay, _T("invalid week day") ); - - // no wrapping or the for loop above would never end! - wd = (wxDateTime::WeekDay)(wd + 1); -} - -WXDLLIMPEXP_BASE void wxPrevWDay(wxDateTime::WeekDay& wd) -{ - wxASSERT_MSG( wd < wxDateTime::Inv_WeekDay, _T("invalid week day") ); - - wd = wd == wxDateTime::Sun ? wxDateTime::Inv_WeekDay - : (wxDateTime::WeekDay)(wd - 1); -} - -#endif // wxUSE_DATETIME +/////////////////////////////////////////////////////////////////////////////// +// Name: src/common/datetime.cpp +// Purpose: implementation of time/date related classes +// Author: Vadim Zeitlin +// Modified by: +// Created: 11.05.99 +// RCS-ID: $Id: datetime.cpp 53900 2008-06-01 14:37:26Z VZ $ +// Copyright: (c) 1999 Vadim Zeitlin +// parts of code taken from sndcal library by Scott E. Lee: +// +// Copyright 1993-1995, Scott E. Lee, all rights reserved. +// Permission granted to use, copy, modify, distribute and sell +// so long as the above copyright and this permission statement +// are retained in all copies. +// +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +/* + * Implementation notes: + * + * 1. the time is stored as a 64bit integer containing the signed number of + * milliseconds since Jan 1. 1970 (the Unix Epoch) - so it is always + * expressed in GMT. + * + * 2. the range is thus something about 580 million years, but due to current + * algorithms limitations, only dates from Nov 24, 4714BC are handled + * + * 3. standard ANSI C functions are used to do time calculations whenever + * possible, i.e. when the date is in the range Jan 1, 1970 to 2038 + * + * 4. otherwise, the calculations are done by converting the date to/from JDN + * first (the range limitation mentioned above comes from here: the + * algorithm used by Scott E. Lee's code only works for positive JDNs, more + * or less) + * + * 5. the object constructed for the given DD-MM-YYYY HH:MM:SS corresponds to + * this moment in local time and may be converted to the object + * corresponding to the same date/time in another time zone by using + * ToTimezone() + * + * 6. the conversions to the current (or any other) timezone are done when the + * internal time representation is converted to the broken-down one in + * wxDateTime::Tm. + */ + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if !defined(wxUSE_DATETIME) || wxUSE_DATETIME + +#ifndef WX_PRECOMP + #ifdef __WXMSW__ + #include "wx/msw/wrapwin.h" + #endif + #include "wx/string.h" + #include "wx/log.h" + #include "wx/intl.h" + #include "wx/stopwatch.h" // for wxGetLocalTimeMillis() + #include "wx/module.h" +#endif // WX_PRECOMP + +#include "wx/thread.h" +#include "wx/tokenzr.h" + +#include + +#ifdef __WINDOWS__ + #include + #ifndef __WXWINCE__ + #include + #endif +#endif + +#include "wx/datetime.h" + +const long wxDateTime::TIME_T_FACTOR = 1000l; + +#if wxUSE_EXTENDED_RTTI + +template<> void wxStringReadValue(const wxString &s , wxDateTime &data ) +{ + data.ParseFormat(s,wxT("%Y-%m-%d %H:%M:%S")) ; +} + +template<> void wxStringWriteValue(wxString &s , const wxDateTime &data ) +{ + s = data.Format(wxT("%Y-%m-%d %H:%M:%S")) ; +} + +wxCUSTOM_TYPE_INFO(wxDateTime, wxToStringConverter , wxFromStringConverter) + +#endif + +// +// ---------------------------------------------------------------------------- +// conditional compilation +// ---------------------------------------------------------------------------- + +#if defined(HAVE_STRPTIME) && defined(__GLIBC__) && \ + ((__GLIBC__ == 2) && (__GLIBC_MINOR__ == 0)) + // glibc 2.0.7 strptime() is broken - the following snippet causes it to + // crash (instead of just failing): + // + // strncpy(buf, "Tue Dec 21 20:25:40 1999", 128); + // strptime(buf, "%x", &tm); + // + // so don't use it + #undef HAVE_STRPTIME +#endif // broken strptime() + +#if defined(HAVE_STRPTIME) && defined(__DARWIN__) && defined(_MSL_USING_MW_C_HEADERS) && _MSL_USING_MW_C_HEADERS + // configure detects strptime as linkable because it's in the OS X + // System library but MSL headers don't declare it. + +// char *strptime(const char *, const char *, struct tm *); + // However, we DON'T want to just provide it here because we would + // crash and/or overwrite data when strptime from OS X tries + // to fill in MW's struct tm which is two fields shorter (no TZ stuff) + // So for now let's just say we don't have strptime + #undef HAVE_STRPTIME +#endif + +#if defined(__MWERKS__) && wxUSE_UNICODE + #include +#endif + +// define a special symbol for VC8 instead of writing tests for 1400 repeatedly +#ifdef __VISUALC__ + #if __VISUALC__ >= 1400 + #define __VISUALC8__ + #endif +#endif + +#if !defined(WX_TIMEZONE) && !defined(WX_GMTOFF_IN_TM) + #if defined(__WXPALMOS__) + #define WX_GMTOFF_IN_TM + #elif defined(__BORLANDC__) || defined(__MINGW32__) || defined(__VISAGECPP__) + #define WX_TIMEZONE _timezone + #elif defined(__MWERKS__) + long wxmw_timezone = 28800; + #define WX_TIMEZONE wxmw_timezone + #elif defined(__DJGPP__) || defined(__WINE__) + #include + #include + static long wxGetTimeZone() + { + static long timezone = MAXLONG; // invalid timezone + if (timezone == MAXLONG) + { + struct timeb tb; + ftime(&tb); + timezone = tb.timezone; + } + return timezone; + } + #define WX_TIMEZONE wxGetTimeZone() + #elif defined(__DARWIN__) + #define WX_GMTOFF_IN_TM + #elif defined(__WXWINCE__) && defined(__VISUALC8__) + // _timezone is not present in dynamic run-time library + #if 0 + // Solution (1): use the function equivalent of _timezone + static long wxGetTimeZone() + { + static long s_Timezone = MAXLONG; // invalid timezone + if (s_Timezone == MAXLONG) + { + int t; + _get_timezone(& t); + s_Timezone = (long) t; + } + return s_Timezone; + } + #define WX_TIMEZONE wxGetTimeZone() + #elif 1 + // Solution (2): using GetTimeZoneInformation + static long wxGetTimeZone() + { + static long timezone = MAXLONG; // invalid timezone + if (timezone == MAXLONG) + { + TIME_ZONE_INFORMATION tzi; + ::GetTimeZoneInformation(&tzi); + timezone = tzi.Bias; + } + return timezone; + } + #define WX_TIMEZONE wxGetTimeZone() + #endif + #else // unknown platform - try timezone + #define WX_TIMEZONE timezone + #endif +#endif // !WX_TIMEZONE && !WX_GMTOFF_IN_TM + +// everyone has strftime except Win CE unless VC8 is used +#if !defined(__WXWINCE__) || defined(__VISUALC8__) + #define HAVE_STRFTIME +#endif + +// NB: VC8 safe time functions could/should be used for wxMSW as well probably +#if defined(__WXWINCE__) && defined(__VISUALC8__) + +struct tm *wxLocaltime_r(const time_t *t, struct tm* tm) +{ + __time64_t t64 = *t; + return _localtime64_s(tm, &t64) == 0 ? tm : NULL; +} + +struct tm *wxGmtime_r(const time_t* t, struct tm* tm) +{ + __time64_t t64 = *t; + return _gmtime64_s(tm, &t64) == 0 ? tm : NULL; +} + +#else // !wxWinCE with VC8 + +#if (!defined(HAVE_LOCALTIME_R) || !defined(HAVE_GMTIME_R)) && wxUSE_THREADS && !defined(__WINDOWS__) +static wxMutex timeLock; +#endif + +#ifndef HAVE_LOCALTIME_R +struct tm *wxLocaltime_r(const time_t* ticks, struct tm* temp) +{ +#if wxUSE_THREADS && !defined(__WINDOWS__) + // No need to waste time with a mutex on windows since it's using + // thread local storage for localtime anyway. + wxMutexLocker locker(timeLock); +#endif + + // Borland CRT crashes when passed 0 ticks for some reason, see SF bug 1704438 +#ifdef __BORLANDC__ + if ( !*ticks ) + return NULL; +#endif + + const tm * const t = localtime(ticks); + if ( !t ) + return NULL; + + memcpy(temp, t, sizeof(struct tm)); + return temp; +} +#endif // !HAVE_LOCALTIME_R + +#ifndef HAVE_GMTIME_R +struct tm *wxGmtime_r(const time_t* ticks, struct tm* temp) +{ +#if wxUSE_THREADS && !defined(__WINDOWS__) + // No need to waste time with a mutex on windows since it's + // using thread local storage for gmtime anyway. + wxMutexLocker locker(timeLock); +#endif + +#ifdef __BORLANDC__ + if ( !*ticks ) + return NULL; +#endif + + const tm * const t = gmtime(ticks); + if ( !t ) + return NULL; + + memcpy(temp, gmtime(ticks), sizeof(struct tm)); + return temp; +} +#endif // !HAVE_GMTIME_R + +#endif // wxWinCE with VC8/other platforms + +// ---------------------------------------------------------------------------- +// macros +// ---------------------------------------------------------------------------- + +// debugging helper: just a convenient replacement of wxCHECK() +#define wxDATETIME_CHECK(expr, msg) \ + wxCHECK2_MSG(expr, *this = wxInvalidDateTime; return *this, msg) + +// ---------------------------------------------------------------------------- +// private classes +// ---------------------------------------------------------------------------- + +class wxDateTimeHolidaysModule : public wxModule +{ +public: + virtual bool OnInit() + { + wxDateTimeHolidayAuthority::AddAuthority(new wxDateTimeWorkDays); + + return true; + } + + virtual void OnExit() + { + wxDateTimeHolidayAuthority::ClearAllAuthorities(); + wxDateTimeHolidayAuthority::ms_authorities.clear(); + } + +private: + DECLARE_DYNAMIC_CLASS(wxDateTimeHolidaysModule) +}; + +IMPLEMENT_DYNAMIC_CLASS(wxDateTimeHolidaysModule, wxModule) + +// ---------------------------------------------------------------------------- +// constants +// ---------------------------------------------------------------------------- + +// some trivial ones +static const int MONTHS_IN_YEAR = 12; + +static const int SEC_PER_MIN = 60; + +static const int MIN_PER_HOUR = 60; + +static const int HOURS_PER_DAY = 24; + +static const long SECONDS_PER_DAY = 86400l; + +static const int DAYS_PER_WEEK = 7; + +static const long MILLISECONDS_PER_DAY = 86400000l; + +// this is the integral part of JDN of the midnight of Jan 1, 1970 +// (i.e. JDN(Jan 1, 1970) = 2440587.5) +static const long EPOCH_JDN = 2440587l; + +// used only in asserts +#ifdef __WXDEBUG__ +// the date of JDN -0.5 (as we don't work with fractional parts, this is the +// reference date for us) is Nov 24, 4714BC +static const int JDN_0_YEAR = -4713; +static const int JDN_0_MONTH = wxDateTime::Nov; +static const int JDN_0_DAY = 24; +#endif // __WXDEBUG__ + +// the constants used for JDN calculations +static const long JDN_OFFSET = 32046l; +static const long DAYS_PER_5_MONTHS = 153l; +static const long DAYS_PER_4_YEARS = 1461l; +static const long DAYS_PER_400_YEARS = 146097l; + +// this array contains the cumulated number of days in all previous months for +// normal and leap years +static const wxDateTime::wxDateTime_t gs_cumulatedDays[2][MONTHS_IN_YEAR] = +{ + { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 }, + { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 } +}; + +// ---------------------------------------------------------------------------- +// global data +// ---------------------------------------------------------------------------- + +const wxChar * wxDefaultDateTimeFormat = wxT("%c"); +const wxChar * wxDefaultTimeSpanFormat = wxT("%H:%M:%S"); + +// in the fine tradition of ANSI C we use our equivalent of (time_t)-1 to +// indicate an invalid wxDateTime object +const wxDateTime wxDefaultDateTime; + +wxDateTime::Country wxDateTime::ms_country = wxDateTime::Country_Unknown; + +// ---------------------------------------------------------------------------- +// private functions +// ---------------------------------------------------------------------------- + +// debugger helper: shows what the date really is +#ifdef __WXDEBUG__ +extern const wxChar *wxDumpDate(const wxDateTime* dt) +{ + static wxChar buf[128]; + + wxStrcpy(buf, dt->Format(_T("%Y-%m-%d (%a) %H:%M:%S"))); + + return buf; +} +#endif // Debug + +// get the number of days in the given month of the given year +static inline +wxDateTime::wxDateTime_t GetNumOfDaysInMonth(int year, wxDateTime::Month month) +{ + // the number of days in month in Julian/Gregorian calendar: the first line + // is for normal years, the second one is for the leap ones + static wxDateTime::wxDateTime_t daysInMonth[2][MONTHS_IN_YEAR] = + { + { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, + { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } + }; + + return daysInMonth[wxDateTime::IsLeapYear(year)][month]; +} + +// returns the time zone in the C sense, i.e. the difference UTC - local +// (in seconds) +static int GetTimeZone() +{ + // set to true when the timezone is set + static bool s_timezoneSet = false; + static long gmtoffset = LONG_MAX; // invalid timezone + + // ensure that the timezone variable is set by calling wxLocaltime_r + if ( !s_timezoneSet ) + { + // just call wxLocaltime_r() instead of figuring out whether this + // system supports tzset(), _tzset() or something else + time_t t = 0; + struct tm tm; + + wxLocaltime_r(&t, &tm); + s_timezoneSet = true; + +#ifdef WX_GMTOFF_IN_TM + // note that GMT offset is the opposite of time zone and so to return + // consistent results in both WX_GMTOFF_IN_TM and !WX_GMTOFF_IN_TM + // cases we have to negate it + gmtoffset = -tm.tm_gmtoff; +#else // !WX_GMTOFF_IN_TM + gmtoffset = WX_TIMEZONE; +#endif // WX_GMTOFF_IN_TM/!WX_GMTOFF_IN_TM + } + + return (int)gmtoffset; +} + +// return the integral part of the JDN for the midnight of the given date (to +// get the real JDN you need to add 0.5, this is, in fact, JDN of the +// noon of the previous day) +static long GetTruncatedJDN(wxDateTime::wxDateTime_t day, + wxDateTime::Month mon, + int year) +{ + // CREDIT: code below is by Scott E. Lee (but bugs are mine) + + // check the date validity + wxASSERT_MSG( + (year > JDN_0_YEAR) || + ((year == JDN_0_YEAR) && (mon > JDN_0_MONTH)) || + ((year == JDN_0_YEAR) && (mon == JDN_0_MONTH) && (day >= JDN_0_DAY)), + _T("date out of range - can't convert to JDN") + ); + + // make the year positive to avoid problems with negative numbers division + year += 4800; + + // months are counted from March here + int month; + if ( mon >= wxDateTime::Mar ) + { + month = mon - 2; + } + else + { + month = mon + 10; + year--; + } + + // now we can simply add all the contributions together + return ((year / 100) * DAYS_PER_400_YEARS) / 4 + + ((year % 100) * DAYS_PER_4_YEARS) / 4 + + (month * DAYS_PER_5_MONTHS + 2) / 5 + + day + - JDN_OFFSET; +} + +#ifdef HAVE_STRFTIME + +// this function is a wrapper around strftime(3) adding error checking +static wxString CallStrftime(const wxChar *format, const tm* tm) +{ + wxChar buf[4096]; + // Create temp wxString here to work around mingw/cygwin bug 1046059 + // http://sourceforge.net/tracker/?func=detail&atid=102435&aid=1046059&group_id=2435 + wxString s; + + if ( !wxStrftime(buf, WXSIZEOF(buf), format, tm) ) + { + // buffer is too small? + wxFAIL_MSG(_T("strftime() failed")); + } + + s = buf; + return s; +} + +#endif // HAVE_STRFTIME + +#ifdef HAVE_STRPTIME + +#if wxUSE_UNIX && !defined(HAVE_STRPTIME_DECL) + // configure detected that we had strptime() but not its declaration, + // provide it ourselves + extern "C" char *strptime(const char *, const char *, struct tm *); +#endif + +// Unicode-friendly strptime() wrapper +static const wxChar * +CallStrptime(const wxChar *input, const char *fmt, tm *tm) +{ + // the problem here is that strptime() returns pointer into the string we + // passed to it while we're really interested in the pointer into the + // original, Unicode, string so we try to transform the pointer back +#if wxUSE_UNICODE + wxCharBuffer inputMB(wxConvertWX2MB(input)); +#else // ASCII + const char * const inputMB = input; +#endif // Unicode/Ascii + + const char *result = strptime(inputMB, fmt, tm); + if ( !result ) + return NULL; + +#if wxUSE_UNICODE + // FIXME: this is wrong in presence of surrogates &c + return input + (result - inputMB.data()); +#else // ASCII + return result; +#endif // Unicode/Ascii +} + +#endif // HAVE_STRPTIME + +// if year and/or month have invalid values, replace them with the current ones +static void ReplaceDefaultYearMonthWithCurrent(int *year, + wxDateTime::Month *month) +{ + struct tm *tmNow = NULL; + struct tm tmstruct; + + if ( *year == wxDateTime::Inv_Year ) + { + tmNow = wxDateTime::GetTmNow(&tmstruct); + + *year = 1900 + tmNow->tm_year; + } + + if ( *month == wxDateTime::Inv_Month ) + { + if ( !tmNow ) + tmNow = wxDateTime::GetTmNow(&tmstruct); + + *month = (wxDateTime::Month)tmNow->tm_mon; + } +} + +// fll the struct tm with default values +static void InitTm(struct tm& tm) +{ + // struct tm may have etxra fields (undocumented and with unportable + // names) which, nevertheless, must be set to 0 + memset(&tm, 0, sizeof(struct tm)); + + tm.tm_mday = 1; // mday 0 is invalid + tm.tm_year = 76; // any valid year + tm.tm_isdst = -1; // auto determine +} + +// parsing helpers +// --------------- + +// return the month if the string is a month name or Inv_Month otherwise +static wxDateTime::Month GetMonthFromName(const wxString& name, int flags) +{ + wxDateTime::Month mon; + for ( mon = wxDateTime::Jan; mon < wxDateTime::Inv_Month; wxNextMonth(mon) ) + { + // case-insensitive comparison either one of or with both abbreviated + // and not versions + if ( flags & wxDateTime::Name_Full ) + { + if ( name.CmpNoCase(wxDateTime:: + GetMonthName(mon, wxDateTime::Name_Full)) == 0 ) + { + break; + } + } + + if ( flags & wxDateTime::Name_Abbr ) + { + if ( name.CmpNoCase(wxDateTime:: + GetMonthName(mon, wxDateTime::Name_Abbr)) == 0 ) + { + break; + } + } + } + + return mon; +} + +// return the weekday if the string is a weekday name or Inv_WeekDay otherwise +static wxDateTime::WeekDay GetWeekDayFromName(const wxString& name, int flags) +{ + wxDateTime::WeekDay wd; + for ( wd = wxDateTime::Sun; wd < wxDateTime::Inv_WeekDay; wxNextWDay(wd) ) + { + // case-insensitive comparison either one of or with both abbreviated + // and not versions + if ( flags & wxDateTime::Name_Full ) + { + if ( name.CmpNoCase(wxDateTime:: + GetWeekDayName(wd, wxDateTime::Name_Full)) == 0 ) + { + break; + } + } + + if ( flags & wxDateTime::Name_Abbr ) + { + if ( name.CmpNoCase(wxDateTime:: + GetWeekDayName(wd, wxDateTime::Name_Abbr)) == 0 ) + { + break; + } + } + } + + return wd; +} + +/* static */ +struct tm *wxDateTime::GetTmNow(struct tm *tmstruct) +{ + time_t t = GetTimeNow(); + return wxLocaltime_r(&t, tmstruct); +} + +// scans all digits (but no more than len) and returns the resulting number +static bool GetNumericToken(size_t len, const wxChar*& p, unsigned long *number) +{ + size_t n = 1; + wxString s; + while ( wxIsdigit(*p) ) + { + s += *p++; + + if ( len && ++n > len ) + break; + } + + return !s.empty() && s.ToULong(number); +} + +// scans all alphabetic characters and returns the resulting string +static wxString GetAlphaToken(const wxChar*& p) +{ + wxString s; + while ( wxIsalpha(*p) ) + { + s += *p++; + } + + return s; +} + +// ============================================================================ +// implementation of wxDateTime +// ============================================================================ + +// ---------------------------------------------------------------------------- +// struct Tm +// ---------------------------------------------------------------------------- + +wxDateTime::Tm::Tm() +{ + year = (wxDateTime_t)wxDateTime::Inv_Year; + mon = wxDateTime::Inv_Month; + mday = 0; + hour = min = sec = msec = 0; + wday = wxDateTime::Inv_WeekDay; +} + +wxDateTime::Tm::Tm(const struct tm& tm, const TimeZone& tz) + : m_tz(tz) +{ + msec = 0; + sec = (wxDateTime::wxDateTime_t)tm.tm_sec; + min = (wxDateTime::wxDateTime_t)tm.tm_min; + hour = (wxDateTime::wxDateTime_t)tm.tm_hour; + mday = (wxDateTime::wxDateTime_t)tm.tm_mday; + mon = (wxDateTime::Month)tm.tm_mon; + year = 1900 + tm.tm_year; + wday = (wxDateTime::wxDateTime_t)tm.tm_wday; + yday = (wxDateTime::wxDateTime_t)tm.tm_yday; +} + +bool wxDateTime::Tm::IsValid() const +{ + // we allow for the leap seconds, although we don't use them (yet) + return (year != wxDateTime::Inv_Year) && (mon != wxDateTime::Inv_Month) && + (mday <= GetNumOfDaysInMonth(year, mon)) && + (hour < 24) && (min < 60) && (sec < 62) && (msec < 1000); +} + +void wxDateTime::Tm::ComputeWeekDay() +{ + // compute the week day from day/month/year: we use the dumbest algorithm + // possible: just compute our JDN and then use the (simple to derive) + // formula: weekday = (JDN + 1.5) % 7 + wday = (wxDateTime::wxDateTime_t)((GetTruncatedJDN(mday, mon, year) + 2) % 7); +} + +void wxDateTime::Tm::AddMonths(int monDiff) +{ + // normalize the months field + while ( monDiff < -mon ) + { + year--; + + monDiff += MONTHS_IN_YEAR; + } + + while ( monDiff + mon >= MONTHS_IN_YEAR ) + { + year++; + + monDiff -= MONTHS_IN_YEAR; + } + + mon = (wxDateTime::Month)(mon + monDiff); + + wxASSERT_MSG( mon >= 0 && mon < MONTHS_IN_YEAR, _T("logic error") ); + + // NB: we don't check here that the resulting date is valid, this function + // is private and the caller must check it if needed +} + +void wxDateTime::Tm::AddDays(int dayDiff) +{ + // normalize the days field + while ( dayDiff + mday < 1 ) + { + AddMonths(-1); + + dayDiff += GetNumOfDaysInMonth(year, mon); + } + + mday = (wxDateTime::wxDateTime_t)( mday + dayDiff ); + while ( mday > GetNumOfDaysInMonth(year, mon) ) + { + mday -= GetNumOfDaysInMonth(year, mon); + + AddMonths(1); + } + + wxASSERT_MSG( mday > 0 && mday <= GetNumOfDaysInMonth(year, mon), + _T("logic error") ); +} + +// ---------------------------------------------------------------------------- +// class TimeZone +// ---------------------------------------------------------------------------- + +wxDateTime::TimeZone::TimeZone(wxDateTime::TZ tz) +{ + switch ( tz ) + { + case wxDateTime::Local: + // get the offset from C RTL: it returns the difference GMT-local + // while we want to have the offset _from_ GMT, hence the '-' + m_offset = -GetTimeZone(); + break; + + case wxDateTime::GMT_12: + case wxDateTime::GMT_11: + case wxDateTime::GMT_10: + case wxDateTime::GMT_9: + case wxDateTime::GMT_8: + case wxDateTime::GMT_7: + case wxDateTime::GMT_6: + case wxDateTime::GMT_5: + case wxDateTime::GMT_4: + case wxDateTime::GMT_3: + case wxDateTime::GMT_2: + case wxDateTime::GMT_1: + m_offset = -3600*(wxDateTime::GMT0 - tz); + break; + + case wxDateTime::GMT0: + case wxDateTime::GMT1: + case wxDateTime::GMT2: + case wxDateTime::GMT3: + case wxDateTime::GMT4: + case wxDateTime::GMT5: + case wxDateTime::GMT6: + case wxDateTime::GMT7: + case wxDateTime::GMT8: + case wxDateTime::GMT9: + case wxDateTime::GMT10: + case wxDateTime::GMT11: + case wxDateTime::GMT12: + case wxDateTime::GMT13: + m_offset = 3600*(tz - wxDateTime::GMT0); + break; + + case wxDateTime::A_CST: + // Central Standard Time in use in Australia = UTC + 9.5 + m_offset = 60l*(9*MIN_PER_HOUR + MIN_PER_HOUR/2); + break; + + default: + wxFAIL_MSG( _T("unknown time zone") ); + } +} + +// ---------------------------------------------------------------------------- +// static functions +// ---------------------------------------------------------------------------- + +/* static */ +bool wxDateTime::IsLeapYear(int year, wxDateTime::Calendar cal) +{ + if ( year == Inv_Year ) + year = GetCurrentYear(); + + if ( cal == Gregorian ) + { + // in Gregorian calendar leap years are those divisible by 4 except + // those divisible by 100 unless they're also divisible by 400 + // (in some countries, like Russia and Greece, additional corrections + // exist, but they won't manifest themselves until 2700) + return (year % 4 == 0) && ((year % 100 != 0) || (year % 400 == 0)); + } + else if ( cal == Julian ) + { + // in Julian calendar the rule is simpler + return year % 4 == 0; + } + else + { + wxFAIL_MSG(_T("unknown calendar")); + + return false; + } +} + +/* static */ +int wxDateTime::GetCentury(int year) +{ + return year > 0 ? year / 100 : year / 100 - 1; +} + +/* static */ +int wxDateTime::ConvertYearToBC(int year) +{ + // year 0 is BC 1 + return year > 0 ? year : year - 1; +} + +/* static */ +int wxDateTime::GetCurrentYear(wxDateTime::Calendar cal) +{ + switch ( cal ) + { + case Gregorian: + return Now().GetYear(); + + case Julian: + wxFAIL_MSG(_T("TODO")); + break; + + default: + wxFAIL_MSG(_T("unsupported calendar")); + break; + } + + return Inv_Year; +} + +/* static */ +wxDateTime::Month wxDateTime::GetCurrentMonth(wxDateTime::Calendar cal) +{ + switch ( cal ) + { + case Gregorian: + return Now().GetMonth(); + + case Julian: + wxFAIL_MSG(_T("TODO")); + break; + + default: + wxFAIL_MSG(_T("unsupported calendar")); + break; + } + + return Inv_Month; +} + +/* static */ +wxDateTime::wxDateTime_t wxDateTime::GetNumberOfDays(int year, Calendar cal) +{ + if ( year == Inv_Year ) + { + // take the current year if none given + year = GetCurrentYear(); + } + + switch ( cal ) + { + case Gregorian: + case Julian: + return IsLeapYear(year) ? 366 : 365; + + default: + wxFAIL_MSG(_T("unsupported calendar")); + break; + } + + return 0; +} + +/* static */ +wxDateTime::wxDateTime_t wxDateTime::GetNumberOfDays(wxDateTime::Month month, + int year, + wxDateTime::Calendar cal) +{ + wxCHECK_MSG( month < MONTHS_IN_YEAR, 0, _T("invalid month") ); + + if ( cal == Gregorian || cal == Julian ) + { + if ( year == Inv_Year ) + { + // take the current year if none given + year = GetCurrentYear(); + } + + return GetNumOfDaysInMonth(year, month); + } + else + { + wxFAIL_MSG(_T("unsupported calendar")); + + return 0; + } +} + +/* static */ +wxString wxDateTime::GetMonthName(wxDateTime::Month month, + wxDateTime::NameFlags flags) +{ + wxCHECK_MSG( month != Inv_Month, wxEmptyString, _T("invalid month") ); +#ifdef HAVE_STRFTIME + // notice that we must set all the fields to avoid confusing libc (GNU one + // gets confused to a crash if we don't do this) + tm tm; + InitTm(tm); + tm.tm_mon = month; + + return CallStrftime(flags == Name_Abbr ? _T("%b") : _T("%B"), &tm); +#else // !HAVE_STRFTIME + wxString ret; + switch(month) + { + case Jan: + ret = (flags == Name_Abbr ? wxT("Jan"): wxT("January")); + break; + case Feb: + ret = (flags == Name_Abbr ? wxT("Feb"): wxT("Febuary")); + break; + case Mar: + ret = (flags == Name_Abbr ? wxT("Mar"): wxT("March")); + break; + case Apr: + ret = (flags == Name_Abbr ? wxT("Apr"): wxT("April")); + break; + case May: + ret = (flags == Name_Abbr ? wxT("May"): wxT("May")); + break; + case Jun: + ret = (flags == Name_Abbr ? wxT("Jun"): wxT("June")); + break; + case Jul: + ret = (flags == Name_Abbr ? wxT("Jul"): wxT("July")); + break; + case Aug: + ret = (flags == Name_Abbr ? wxT("Aug"): wxT("August")); + break; + case Sep: + ret = (flags == Name_Abbr ? wxT("Sep"): wxT("September")); + break; + case Oct: + ret = (flags == Name_Abbr ? wxT("Oct"): wxT("October")); + break; + case Nov: + ret = (flags == Name_Abbr ? wxT("Nov"): wxT("November")); + break; + case Dec: + ret = (flags == Name_Abbr ? wxT("Dec"): wxT("December")); + break; + } + return ret; +#endif // HAVE_STRFTIME/!HAVE_STRFTIME +} + +/* static */ +wxString wxDateTime::GetWeekDayName(wxDateTime::WeekDay wday, + wxDateTime::NameFlags flags) +{ + wxCHECK_MSG( wday != Inv_WeekDay, wxEmptyString, _T("invalid weekday") ); +#ifdef HAVE_STRFTIME + // take some arbitrary Sunday (but notice that the day should be such that + // after adding wday to it below we still have a valid date, e.g. don't + // take 28 here!) + tm tm; + InitTm(tm); + tm.tm_mday = 21; + tm.tm_mon = Nov; + tm.tm_year = 99; + + // and offset it by the number of days needed to get the correct wday + tm.tm_mday += wday; + + // call mktime() to normalize it... + (void)mktime(&tm); + + // ... and call strftime() + return CallStrftime(flags == Name_Abbr ? _T("%a") : _T("%A"), &tm); +#else // !HAVE_STRFTIME + wxString ret; + switch(wday) + { + case Sun: + ret = (flags == Name_Abbr ? wxT("Sun") : wxT("Sunday")); + break; + case Mon: + ret = (flags == Name_Abbr ? wxT("Mon") : wxT("Monday")); + break; + case Tue: + ret = (flags == Name_Abbr ? wxT("Tue") : wxT("Tuesday")); + break; + case Wed: + ret = (flags == Name_Abbr ? wxT("Wed") : wxT("Wednesday")); + break; + case Thu: + ret = (flags == Name_Abbr ? wxT("Thu") : wxT("Thursday")); + break; + case Fri: + ret = (flags == Name_Abbr ? wxT("Fri") : wxT("Friday")); + break; + case Sat: + ret = (flags == Name_Abbr ? wxT("Sat") : wxT("Saturday")); + break; + } + return ret; +#endif // HAVE_STRFTIME/!HAVE_STRFTIME +} + +/* static */ +void wxDateTime::GetAmPmStrings(wxString *am, wxString *pm) +{ + tm tm; + InitTm(tm); + wxChar buffer[64]; + // @Note: Do not call 'CallStrftime' here! CallStrftime checks the return code + // and causes an assertion failed if the buffer is to small (which is good) - OR - + // if strftime does not return anything because the format string is invalid - OR - + // if there are no 'am' / 'pm' tokens defined for the current locale (which is not good). + // wxDateTime::ParseTime will try several different formats to parse the time. + // As a result, GetAmPmStrings might get called, even if the current locale + // does not define any 'am' / 'pm' tokens. In this case, wxStrftime would + // assert, even though it is a perfectly legal use. + if ( am ) + { + if (wxStrftime(buffer, sizeof(buffer)/sizeof(wxChar), _T("%p"), &tm) > 0) + *am = wxString(buffer); + else + *am = wxString(); + } + if ( pm ) + { + tm.tm_hour = 13; + if (wxStrftime(buffer, sizeof(buffer)/sizeof(wxChar), _T("%p"), &tm) > 0) + *pm = wxString(buffer); + else + *pm = wxString(); + } +} + +// ---------------------------------------------------------------------------- +// Country stuff: date calculations depend on the country (DST, work days, +// ...), so we need to know which rules to follow. +// ---------------------------------------------------------------------------- + +/* static */ +wxDateTime::Country wxDateTime::GetCountry() +{ + // TODO use LOCALE_ICOUNTRY setting under Win32 +#ifndef __WXWINCE__ + if ( ms_country == Country_Unknown ) + { + // try to guess from the time zone name + time_t t = time(NULL); + struct tm tmstruct; + struct tm *tm = wxLocaltime_r(&t, &tmstruct); + + wxString tz = CallStrftime(_T("%Z"), tm); + if ( tz == _T("WET") || tz == _T("WEST") ) + { + ms_country = UK; + } + else if ( tz == _T("CET") || tz == _T("CEST") ) + { + ms_country = Country_EEC; + } + else if ( tz == _T("MSK") || tz == _T("MSD") ) + { + ms_country = Russia; + } + else if ( tz == _T("AST") || tz == _T("ADT") || + tz == _T("EST") || tz == _T("EDT") || + tz == _T("CST") || tz == _T("CDT") || + tz == _T("MST") || tz == _T("MDT") || + tz == _T("PST") || tz == _T("PDT") ) + { + ms_country = USA; + } + else + { + // well, choose a default one + ms_country = USA; + } + } +#else // __WXWINCE__ + ms_country = USA; +#endif // !__WXWINCE__/__WXWINCE__ + + return ms_country; +} + +/* static */ +void wxDateTime::SetCountry(wxDateTime::Country country) +{ + ms_country = country; +} + +/* static */ +bool wxDateTime::IsWestEuropeanCountry(Country country) +{ + if ( country == Country_Default ) + { + country = GetCountry(); + } + + return (Country_WesternEurope_Start <= country) && + (country <= Country_WesternEurope_End); +} + +// ---------------------------------------------------------------------------- +// DST calculations: we use 3 different rules for the West European countries, +// USA and for the rest of the world. This is undoubtedly false for many +// countries, but I lack the necessary info (and the time to gather it), +// please add the other rules here! +// ---------------------------------------------------------------------------- + +/* static */ +bool wxDateTime::IsDSTApplicable(int year, Country country) +{ + if ( year == Inv_Year ) + { + // take the current year if none given + year = GetCurrentYear(); + } + + if ( country == Country_Default ) + { + country = GetCountry(); + } + + switch ( country ) + { + case USA: + case UK: + // DST was first observed in the US and UK during WWI, reused + // during WWII and used again since 1966 + return year >= 1966 || + (year >= 1942 && year <= 1945) || + (year == 1918 || year == 1919); + + default: + // assume that it started after WWII + return year > 1950; + } +} + +/* static */ +wxDateTime wxDateTime::GetBeginDST(int year, Country country) +{ + if ( year == Inv_Year ) + { + // take the current year if none given + year = GetCurrentYear(); + } + + if ( country == Country_Default ) + { + country = GetCountry(); + } + + if ( !IsDSTApplicable(year, country) ) + { + return wxInvalidDateTime; + } + + wxDateTime dt; + + if ( IsWestEuropeanCountry(country) || (country == Russia) ) + { + // DST begins at 1 a.m. GMT on the last Sunday of March + if ( !dt.SetToLastWeekDay(Sun, Mar, year) ) + { + // weird... + wxFAIL_MSG( _T("no last Sunday in March?") ); + } + + dt += wxTimeSpan::Hours(1); + + // disable DST tests because it could result in an infinite recursion! + dt.MakeGMT(true); + } + else switch ( country ) + { + case USA: + switch ( year ) + { + case 1918: + case 1919: + // don't know for sure - assume it was in effect all year + + case 1943: + case 1944: + case 1945: + dt.Set(1, Jan, year); + break; + + case 1942: + // DST was installed Feb 2, 1942 by the Congress + dt.Set(2, Feb, year); + break; + + // Oil embargo changed the DST period in the US + case 1974: + dt.Set(6, Jan, 1974); + break; + + case 1975: + dt.Set(23, Feb, 1975); + break; + + default: + // before 1986, DST begun on the last Sunday of April, but + // in 1986 Reagan changed it to begin at 2 a.m. of the + // first Sunday in April + if ( year < 1986 ) + { + if ( !dt.SetToLastWeekDay(Sun, Apr, year) ) + { + // weird... + wxFAIL_MSG( _T("no first Sunday in April?") ); + } + } + else + { + if ( !dt.SetToWeekDay(Sun, 1, Apr, year) ) + { + // weird... + wxFAIL_MSG( _T("no first Sunday in April?") ); + } + } + + dt += wxTimeSpan::Hours(2); + + // TODO what about timezone?? + } + + break; + + default: + // assume Mar 30 as the start of the DST for the rest of the world + // - totally bogus, of course + dt.Set(30, Mar, year); + } + + return dt; +} + +/* static */ +wxDateTime wxDateTime::GetEndDST(int year, Country country) +{ + if ( year == Inv_Year ) + { + // take the current year if none given + year = GetCurrentYear(); + } + + if ( country == Country_Default ) + { + country = GetCountry(); + } + + if ( !IsDSTApplicable(year, country) ) + { + return wxInvalidDateTime; + } + + wxDateTime dt; + + if ( IsWestEuropeanCountry(country) || (country == Russia) ) + { + // DST ends at 1 a.m. GMT on the last Sunday of October + if ( !dt.SetToLastWeekDay(Sun, Oct, year) ) + { + // weirder and weirder... + wxFAIL_MSG( _T("no last Sunday in October?") ); + } + + dt += wxTimeSpan::Hours(1); + + // disable DST tests because it could result in an infinite recursion! + dt.MakeGMT(true); + } + else switch ( country ) + { + case USA: + switch ( year ) + { + case 1918: + case 1919: + // don't know for sure - assume it was in effect all year + + case 1943: + case 1944: + dt.Set(31, Dec, year); + break; + + case 1945: + // the time was reset after the end of the WWII + dt.Set(30, Sep, year); + break; + + default: + // DST ends at 2 a.m. on the last Sunday of October + if ( !dt.SetToLastWeekDay(Sun, Oct, year) ) + { + // weirder and weirder... + wxFAIL_MSG( _T("no last Sunday in October?") ); + } + + dt += wxTimeSpan::Hours(2); + + // TODO what about timezone?? + } + break; + + default: + // assume October 26th as the end of the DST - totally bogus too + dt.Set(26, Oct, year); + } + + return dt; +} + +// ---------------------------------------------------------------------------- +// constructors and assignment operators +// ---------------------------------------------------------------------------- + +// return the current time with ms precision +/* static */ wxDateTime wxDateTime::UNow() +{ + return wxDateTime(wxGetLocalTimeMillis()); +} + +// the values in the tm structure contain the local time +wxDateTime& wxDateTime::Set(const struct tm& tm) +{ + struct tm tm2(tm); + time_t timet = mktime(&tm2); + + if ( timet == (time_t)-1 ) + { + // mktime() rather unintuitively fails for Jan 1, 1970 if the hour is + // less than timezone - try to make it work for this case + if ( tm2.tm_year == 70 && tm2.tm_mon == 0 && tm2.tm_mday == 1 ) + { + return Set((time_t)( + GetTimeZone() + + tm2.tm_hour * MIN_PER_HOUR * SEC_PER_MIN + + tm2.tm_min * SEC_PER_MIN + + tm2.tm_sec)); + } + + wxFAIL_MSG( _T("mktime() failed") ); + + *this = wxInvalidDateTime; + + return *this; + } + else + { + return Set(timet); + } +} + +wxDateTime& wxDateTime::Set(wxDateTime_t hour, + wxDateTime_t minute, + wxDateTime_t second, + wxDateTime_t millisec) +{ + // we allow seconds to be 61 to account for the leap seconds, even if we + // don't use them really + wxDATETIME_CHECK( hour < 24 && + second < 62 && + minute < 60 && + millisec < 1000, + _T("Invalid time in wxDateTime::Set()") ); + + // get the current date from system + struct tm tmstruct; + struct tm *tm = GetTmNow(&tmstruct); + + wxDATETIME_CHECK( tm, _T("wxLocaltime_r() failed") ); + + // make a copy so it isn't clobbered by the call to mktime() below + struct tm tm1(*tm); + + // adjust the time + tm1.tm_hour = hour; + tm1.tm_min = minute; + tm1.tm_sec = second; + + // and the DST in case it changes on this date + struct tm tm2(tm1); + mktime(&tm2); + if ( tm2.tm_isdst != tm1.tm_isdst ) + tm1.tm_isdst = tm2.tm_isdst; + + (void)Set(tm1); + + // and finally adjust milliseconds + return SetMillisecond(millisec); +} + +wxDateTime& wxDateTime::Set(wxDateTime_t day, + Month month, + int year, + wxDateTime_t hour, + wxDateTime_t minute, + wxDateTime_t second, + wxDateTime_t millisec) +{ + wxDATETIME_CHECK( hour < 24 && + second < 62 && + minute < 60 && + millisec < 1000, + _T("Invalid time in wxDateTime::Set()") ); + + ReplaceDefaultYearMonthWithCurrent(&year, &month); + + wxDATETIME_CHECK( (0 < day) && (day <= GetNumberOfDays(month, year)), + _T("Invalid date in wxDateTime::Set()") ); + + // the range of time_t type (inclusive) + static const int yearMinInRange = 1970; + static const int yearMaxInRange = 2037; + + // test only the year instead of testing for the exact end of the Unix + // time_t range - it doesn't bring anything to do more precise checks + if ( year >= yearMinInRange && year <= yearMaxInRange ) + { + // use the standard library version if the date is in range - this is + // probably more efficient than our code + struct tm tm; + tm.tm_year = year - 1900; + tm.tm_mon = month; + tm.tm_mday = day; + tm.tm_hour = hour; + tm.tm_min = minute; + tm.tm_sec = second; + tm.tm_isdst = -1; // mktime() will guess it + + (void)Set(tm); + + // and finally adjust milliseconds + if (IsValid()) + SetMillisecond(millisec); + + return *this; + } + else + { + // do time calculations ourselves: we want to calculate the number of + // milliseconds between the given date and the epoch + + // get the JDN for the midnight of this day + m_time = GetTruncatedJDN(day, month, year); + m_time -= EPOCH_JDN; + m_time *= SECONDS_PER_DAY * TIME_T_FACTOR; + + // JDN corresponds to GMT, we take localtime + Add(wxTimeSpan(hour, minute, second + GetTimeZone(), millisec)); + } + + return *this; +} + +wxDateTime& wxDateTime::Set(double jdn) +{ + // so that m_time will be 0 for the midnight of Jan 1, 1970 which is jdn + // EPOCH_JDN + 0.5 + jdn -= EPOCH_JDN + 0.5; + + m_time.Assign(jdn*MILLISECONDS_PER_DAY); + + // JDNs always are in UTC, so we don't need any adjustments for time zone + + return *this; +} + +wxDateTime& wxDateTime::ResetTime() +{ + Tm tm = GetTm(); + + if ( tm.hour || tm.min || tm.sec || tm.msec ) + { + tm.msec = + tm.sec = + tm.min = + tm.hour = 0; + + Set(tm); + } + + return *this; +} + +wxDateTime wxDateTime::GetDateOnly() const +{ + Tm tm = GetTm(); + tm.msec = + tm.sec = + tm.min = + tm.hour = 0; + return wxDateTime(tm); +} + +// ---------------------------------------------------------------------------- +// DOS Date and Time Format functions +// ---------------------------------------------------------------------------- +// the dos date and time value is an unsigned 32 bit value in the format: +// YYYYYYYMMMMDDDDDhhhhhmmmmmmsssss +// +// Y = year offset from 1980 (0-127) +// M = month (1-12) +// D = day of month (1-31) +// h = hour (0-23) +// m = minute (0-59) +// s = bisecond (0-29) each bisecond indicates two seconds +// ---------------------------------------------------------------------------- + +wxDateTime& wxDateTime::SetFromDOS(unsigned long ddt) +{ + struct tm tm; + InitTm(tm); + + long year = ddt & 0xFE000000; + year >>= 25; + year += 80; + tm.tm_year = year; + + long month = ddt & 0x1E00000; + month >>= 21; + month -= 1; + tm.tm_mon = month; + + long day = ddt & 0x1F0000; + day >>= 16; + tm.tm_mday = day; + + long hour = ddt & 0xF800; + hour >>= 11; + tm.tm_hour = hour; + + long minute = ddt & 0x7E0; + minute >>= 5; + tm.tm_min = minute; + + long second = ddt & 0x1F; + tm.tm_sec = second * 2; + + return Set(mktime(&tm)); +} + +unsigned long wxDateTime::GetAsDOS() const +{ + unsigned long ddt; + time_t ticks = GetTicks(); + struct tm tmstruct; + struct tm *tm = wxLocaltime_r(&ticks, &tmstruct); + wxCHECK_MSG( tm, ULONG_MAX, _T("time can't be represented in DOS format") ); + + long year = tm->tm_year; + year -= 80; + year <<= 25; + + long month = tm->tm_mon; + month += 1; + month <<= 21; + + long day = tm->tm_mday; + day <<= 16; + + long hour = tm->tm_hour; + hour <<= 11; + + long minute = tm->tm_min; + minute <<= 5; + + long second = tm->tm_sec; + second /= 2; + + ddt = year | month | day | hour | minute | second; + return ddt; +} + +// ---------------------------------------------------------------------------- +// time_t <-> broken down time conversions +// ---------------------------------------------------------------------------- + +wxDateTime::Tm wxDateTime::GetTm(const TimeZone& tz) const +{ + wxASSERT_MSG( IsValid(), _T("invalid wxDateTime") ); + + time_t time = GetTicks(); + if ( time != (time_t)-1 ) + { + // use C RTL functions + struct tm tmstruct; + tm *tm; + if ( tz.GetOffset() == -GetTimeZone() ) + { + // we are working with local time + tm = wxLocaltime_r(&time, &tmstruct); + + // should never happen + wxCHECK_MSG( tm, Tm(), _T("wxLocaltime_r() failed") ); + } + else + { + time += (time_t)tz.GetOffset(); +#if defined(__VMS__) || defined(__WATCOMC__) // time is unsigned so avoid warning + int time2 = (int) time; + if ( time2 >= 0 ) +#else + if ( time >= 0 ) +#endif + { + tm = wxGmtime_r(&time, &tmstruct); + + // should never happen + wxCHECK_MSG( tm, Tm(), _T("wxGmtime_r() failed") ); + } + else + { + tm = (struct tm *)NULL; + } + } + + if ( tm ) + { + // adjust the milliseconds + Tm tm2(*tm, tz); + long timeOnly = (m_time % MILLISECONDS_PER_DAY).ToLong(); + tm2.msec = (wxDateTime_t)(timeOnly % 1000); + return tm2; + } + //else: use generic code below + } + + // remember the time and do the calculations with the date only - this + // eliminates rounding errors of the floating point arithmetics + + wxLongLong timeMidnight = m_time + tz.GetOffset() * 1000; + + long timeOnly = (timeMidnight % MILLISECONDS_PER_DAY).ToLong(); + + // we want to always have positive time and timeMidnight to be really + // the midnight before it + if ( timeOnly < 0 ) + { + timeOnly = MILLISECONDS_PER_DAY + timeOnly; + } + + timeMidnight -= timeOnly; + + // calculate the Gregorian date from JDN for the midnight of our date: + // this will yield day, month (in 1..12 range) and year + + // actually, this is the JDN for the noon of the previous day + long jdn = (timeMidnight / MILLISECONDS_PER_DAY).ToLong() + EPOCH_JDN; + + // CREDIT: code below is by Scott E. Lee (but bugs are mine) + + wxASSERT_MSG( jdn > -2, _T("JDN out of range") ); + + // calculate the century + long temp = (jdn + JDN_OFFSET) * 4 - 1; + long century = temp / DAYS_PER_400_YEARS; + + // then the year and day of year (1 <= dayOfYear <= 366) + temp = ((temp % DAYS_PER_400_YEARS) / 4) * 4 + 3; + long year = (century * 100) + (temp / DAYS_PER_4_YEARS); + long dayOfYear = (temp % DAYS_PER_4_YEARS) / 4 + 1; + + // and finally the month and day of the month + temp = dayOfYear * 5 - 3; + long month = temp / DAYS_PER_5_MONTHS; + long day = (temp % DAYS_PER_5_MONTHS) / 5 + 1; + + // month is counted from March - convert to normal + if ( month < 10 ) + { + month += 3; + } + else + { + year += 1; + month -= 9; + } + + // year is offset by 4800 + year -= 4800; + + // check that the algorithm gave us something reasonable + wxASSERT_MSG( (0 < month) && (month <= 12), _T("invalid month") ); + wxASSERT_MSG( (1 <= day) && (day < 32), _T("invalid day") ); + + // construct Tm from these values + Tm tm; + tm.year = (int)year; + tm.mon = (Month)(month - 1); // algorithm yields 1 for January, not 0 + tm.mday = (wxDateTime_t)day; + tm.msec = (wxDateTime_t)(timeOnly % 1000); + timeOnly -= tm.msec; + timeOnly /= 1000; // now we have time in seconds + + tm.sec = (wxDateTime_t)(timeOnly % SEC_PER_MIN); + timeOnly -= tm.sec; + timeOnly /= SEC_PER_MIN; // now we have time in minutes + + tm.min = (wxDateTime_t)(timeOnly % MIN_PER_HOUR); + timeOnly -= tm.min; + + tm.hour = (wxDateTime_t)(timeOnly / MIN_PER_HOUR); + + return tm; +} + +wxDateTime& wxDateTime::SetYear(int year) +{ + wxASSERT_MSG( IsValid(), _T("invalid wxDateTime") ); + + Tm tm(GetTm()); + tm.year = year; + Set(tm); + + return *this; +} + +wxDateTime& wxDateTime::SetMonth(Month month) +{ + wxASSERT_MSG( IsValid(), _T("invalid wxDateTime") ); + + Tm tm(GetTm()); + tm.mon = month; + Set(tm); + + return *this; +} + +wxDateTime& wxDateTime::SetDay(wxDateTime_t mday) +{ + wxASSERT_MSG( IsValid(), _T("invalid wxDateTime") ); + + Tm tm(GetTm()); + tm.mday = mday; + Set(tm); + + return *this; +} + +wxDateTime& wxDateTime::SetHour(wxDateTime_t hour) +{ + wxASSERT_MSG( IsValid(), _T("invalid wxDateTime") ); + + Tm tm(GetTm()); + tm.hour = hour; + Set(tm); + + return *this; +} + +wxDateTime& wxDateTime::SetMinute(wxDateTime_t min) +{ + wxASSERT_MSG( IsValid(), _T("invalid wxDateTime") ); + + Tm tm(GetTm()); + tm.min = min; + Set(tm); + + return *this; +} + +wxDateTime& wxDateTime::SetSecond(wxDateTime_t sec) +{ + wxASSERT_MSG( IsValid(), _T("invalid wxDateTime") ); + + Tm tm(GetTm()); + tm.sec = sec; + Set(tm); + + return *this; +} + +wxDateTime& wxDateTime::SetMillisecond(wxDateTime_t millisecond) +{ + wxASSERT_MSG( IsValid(), _T("invalid wxDateTime") ); + + // we don't need to use GetTm() for this one + m_time -= m_time % 1000l; + m_time += millisecond; + + return *this; +} + +// ---------------------------------------------------------------------------- +// wxDateTime arithmetics +// ---------------------------------------------------------------------------- + +wxDateTime& wxDateTime::Add(const wxDateSpan& diff) +{ + Tm tm(GetTm()); + + tm.year += diff.GetYears(); + tm.AddMonths(diff.GetMonths()); + + // check that the resulting date is valid + if ( tm.mday > GetNumOfDaysInMonth(tm.year, tm.mon) ) + { + // We suppose that when adding one month to Jan 31 we want to get Feb + // 28 (or 29), i.e. adding a month to the last day of the month should + // give the last day of the next month which is quite logical. + // + // Unfortunately, there is no logic way to understand what should + // Jan 30 + 1 month be - Feb 28 too or Feb 27 (assuming non leap year)? + // We make it Feb 28 (last day too), but it is highly questionable. + tm.mday = GetNumOfDaysInMonth(tm.year, tm.mon); + } + + tm.AddDays(diff.GetTotalDays()); + + Set(tm); + + wxASSERT_MSG( IsSameTime(tm), + _T("Add(wxDateSpan) shouldn't modify time") ); + + return *this; +} + +// ---------------------------------------------------------------------------- +// Weekday and monthday stuff +// ---------------------------------------------------------------------------- + +// convert Sun, Mon, ..., Sat into 6, 0, ..., 5 +static inline int ConvertWeekDayToMondayBase(int wd) +{ + return wd == wxDateTime::Sun ? 6 : wd - 1; +} + +/* static */ +wxDateTime +wxDateTime::SetToWeekOfYear(int year, wxDateTime_t numWeek, WeekDay wd) +{ + wxASSERT_MSG( numWeek > 0, + _T("invalid week number: weeks are counted from 1") ); + + // Jan 4 always lies in the 1st week of the year + wxDateTime dt(4, Jan, year); + dt.SetToWeekDayInSameWeek(wd); + dt += wxDateSpan::Weeks(numWeek - 1); + + return dt; +} + +#if WXWIN_COMPATIBILITY_2_6 +// use a separate function to avoid warnings about using deprecated +// SetToTheWeek in GetWeek below +static wxDateTime +SetToTheWeek(int year, + wxDateTime::wxDateTime_t numWeek, + wxDateTime::WeekDay weekday, + wxDateTime::WeekFlags flags) +{ + // Jan 4 always lies in the 1st week of the year + wxDateTime dt(4, wxDateTime::Jan, year); + dt.SetToWeekDayInSameWeek(weekday, flags); + dt += wxDateSpan::Weeks(numWeek - 1); + + return dt; +} + +bool wxDateTime::SetToTheWeek(wxDateTime_t numWeek, + WeekDay weekday, + WeekFlags flags) +{ + int year = GetYear(); + *this = ::SetToTheWeek(year, numWeek, weekday, flags); + if ( GetYear() != year ) + { + // oops... numWeek was too big + return false; + } + + return true; +} + +wxDateTime wxDateTime::GetWeek(wxDateTime_t numWeek, + WeekDay weekday, + WeekFlags flags) const +{ + return ::SetToTheWeek(GetYear(), numWeek, weekday, flags); +} +#endif // WXWIN_COMPATIBILITY_2_6 + +wxDateTime& wxDateTime::SetToLastMonthDay(Month month, + int year) +{ + // take the current month/year if none specified + if ( year == Inv_Year ) + year = GetYear(); + if ( month == Inv_Month ) + month = GetMonth(); + + return Set(GetNumOfDaysInMonth(year, month), month, year); +} + +wxDateTime& wxDateTime::SetToWeekDayInSameWeek(WeekDay weekday, WeekFlags flags) +{ + wxDATETIME_CHECK( weekday != Inv_WeekDay, _T("invalid weekday") ); + + int wdayDst = weekday, + wdayThis = GetWeekDay(); + if ( wdayDst == wdayThis ) + { + // nothing to do + return *this; + } + + if ( flags == Default_First ) + { + flags = GetCountry() == USA ? Sunday_First : Monday_First; + } + + // the logic below based on comparing weekday and wdayThis works if Sun (0) + // is the first day in the week, but breaks down for Monday_First case so + // we adjust the week days in this case + if ( flags == Monday_First ) + { + if ( wdayThis == Sun ) + wdayThis += 7; + if ( wdayDst == Sun ) + wdayDst += 7; + } + //else: Sunday_First, nothing to do + + // go forward or back in time to the day we want + if ( wdayDst < wdayThis ) + { + return Subtract(wxDateSpan::Days(wdayThis - wdayDst)); + } + else // weekday > wdayThis + { + return Add(wxDateSpan::Days(wdayDst - wdayThis)); + } +} + +wxDateTime& wxDateTime::SetToNextWeekDay(WeekDay weekday) +{ + wxDATETIME_CHECK( weekday != Inv_WeekDay, _T("invalid weekday") ); + + int diff; + WeekDay wdayThis = GetWeekDay(); + if ( weekday == wdayThis ) + { + // nothing to do + return *this; + } + else if ( weekday < wdayThis ) + { + // need to advance a week + diff = 7 - (wdayThis - weekday); + } + else // weekday > wdayThis + { + diff = weekday - wdayThis; + } + + return Add(wxDateSpan::Days(diff)); +} + +wxDateTime& wxDateTime::SetToPrevWeekDay(WeekDay weekday) +{ + wxDATETIME_CHECK( weekday != Inv_WeekDay, _T("invalid weekday") ); + + int diff; + WeekDay wdayThis = GetWeekDay(); + if ( weekday == wdayThis ) + { + // nothing to do + return *this; + } + else if ( weekday > wdayThis ) + { + // need to go to previous week + diff = 7 - (weekday - wdayThis); + } + else // weekday < wdayThis + { + diff = wdayThis - weekday; + } + + return Subtract(wxDateSpan::Days(diff)); +} + +bool wxDateTime::SetToWeekDay(WeekDay weekday, + int n, + Month month, + int year) +{ + wxCHECK_MSG( weekday != Inv_WeekDay, false, _T("invalid weekday") ); + + // we don't check explicitly that -5 <= n <= 5 because we will return false + // anyhow in such case - but may be should still give an assert for it? + + // take the current month/year if none specified + ReplaceDefaultYearMonthWithCurrent(&year, &month); + + wxDateTime dt; + + // TODO this probably could be optimised somehow... + + if ( n > 0 ) + { + // get the first day of the month + dt.Set(1, month, year); + + // get its wday + WeekDay wdayFirst = dt.GetWeekDay(); + + // go to the first weekday of the month + int diff = weekday - wdayFirst; + if ( diff < 0 ) + diff += 7; + + // add advance n-1 weeks more + diff += 7*(n - 1); + + dt += wxDateSpan::Days(diff); + } + else // count from the end of the month + { + // get the last day of the month + dt.SetToLastMonthDay(month, year); + + // get its wday + WeekDay wdayLast = dt.GetWeekDay(); + + // go to the last weekday of the month + int diff = wdayLast - weekday; + if ( diff < 0 ) + diff += 7; + + // and rewind n-1 weeks from there + diff += 7*(-n - 1); + + dt -= wxDateSpan::Days(diff); + } + + // check that it is still in the same month + if ( dt.GetMonth() == month ) + { + *this = dt; + + return true; + } + else + { + // no such day in this month + return false; + } +} + +static inline +wxDateTime::wxDateTime_t GetDayOfYearFromTm(const wxDateTime::Tm& tm) +{ + return (wxDateTime::wxDateTime_t)(gs_cumulatedDays[wxDateTime::IsLeapYear(tm.year)][tm.mon] + tm.mday); +} + +wxDateTime::wxDateTime_t wxDateTime::GetDayOfYear(const TimeZone& tz) const +{ + return GetDayOfYearFromTm(GetTm(tz)); +} + +wxDateTime::wxDateTime_t +wxDateTime::GetWeekOfYear(wxDateTime::WeekFlags flags, const TimeZone& tz) const +{ + if ( flags == Default_First ) + { + flags = GetCountry() == USA ? Sunday_First : Monday_First; + } + + Tm tm(GetTm(tz)); + wxDateTime_t nDayInYear = GetDayOfYearFromTm(tm); + + int wdTarget = GetWeekDay(tz); + int wdYearStart = wxDateTime(1, Jan, GetYear()).GetWeekDay(); + int week; + if ( flags == Sunday_First ) + { + // FIXME: First week is not calculated correctly. + week = (nDayInYear - wdTarget + 7) / 7; + if ( wdYearStart == Wed || wdYearStart == Thu ) + week++; + } + else // week starts with monday + { + // adjust the weekdays to non-US style. + wdYearStart = ConvertWeekDayToMondayBase(wdYearStart); + wdTarget = ConvertWeekDayToMondayBase(wdTarget); + + // quoting from http://www.cl.cam.ac.uk/~mgk25/iso-time.html: + // + // Week 01 of a year is per definition the first week that has the + // Thursday in this year, which is equivalent to the week that + // contains the fourth day of January. In other words, the first + // week of a new year is the week that has the majority of its + // days in the new year. Week 01 might also contain days from the + // previous year and the week before week 01 of a year is the last + // week (52 or 53) of the previous year even if it contains days + // from the new year. A week starts with Monday (day 1) and ends + // with Sunday (day 7). + // + + // if Jan 1 is Thursday or less, it is in the first week of this year + if ( wdYearStart < 4 ) + { + // count the number of entire weeks between Jan 1 and this date + week = (nDayInYear + wdYearStart + 6 - wdTarget)/7; + + // be careful to check for overflow in the next year + if ( week == 53 && tm.mday - wdTarget > 28 ) + week = 1; + } + else // Jan 1 is in the last week of the previous year + { + // check if we happen to be at the last week of previous year: + if ( tm.mon == Jan && tm.mday < 8 - wdYearStart ) + week = wxDateTime(31, Dec, GetYear()-1).GetWeekOfYear(); + else + week = (nDayInYear + wdYearStart - 1 - wdTarget)/7; + } + } + + return (wxDateTime::wxDateTime_t)week; +} + +wxDateTime::wxDateTime_t wxDateTime::GetWeekOfMonth(wxDateTime::WeekFlags flags, + const TimeZone& tz) const +{ + Tm tm = GetTm(tz); + wxDateTime dtMonthStart = wxDateTime(1, tm.mon, tm.year); + int nWeek = GetWeekOfYear(flags) - dtMonthStart.GetWeekOfYear(flags) + 1; + if ( nWeek < 0 ) + { + // this may happen for January when Jan, 1 is the last week of the + // previous year + nWeek += IsLeapYear(tm.year - 1) ? 53 : 52; + } + + return (wxDateTime::wxDateTime_t)nWeek; +} + +wxDateTime& wxDateTime::SetToYearDay(wxDateTime::wxDateTime_t yday) +{ + int year = GetYear(); + wxDATETIME_CHECK( (0 < yday) && (yday <= GetNumberOfDays(year)), + _T("invalid year day") ); + + bool isLeap = IsLeapYear(year); + for ( Month mon = Jan; mon < Inv_Month; wxNextMonth(mon) ) + { + // for Dec, we can't compare with gs_cumulatedDays[mon + 1], but we + // don't need it neither - because of the CHECK above we know that + // yday lies in December then + if ( (mon == Dec) || (yday <= gs_cumulatedDays[isLeap][mon + 1]) ) + { + Set((wxDateTime::wxDateTime_t)(yday - gs_cumulatedDays[isLeap][mon]), mon, year); + + break; + } + } + + return *this; +} + +// ---------------------------------------------------------------------------- +// Julian day number conversion and related stuff +// ---------------------------------------------------------------------------- + +double wxDateTime::GetJulianDayNumber() const +{ + return m_time.ToDouble() / MILLISECONDS_PER_DAY + EPOCH_JDN + 0.5; +} + +double wxDateTime::GetRataDie() const +{ + // March 1 of the year 0 is Rata Die day -306 and JDN 1721119.5 + return GetJulianDayNumber() - 1721119.5 - 306; +} + +// ---------------------------------------------------------------------------- +// timezone and DST stuff +// ---------------------------------------------------------------------------- + +int wxDateTime::IsDST(wxDateTime::Country country) const +{ + wxCHECK_MSG( country == Country_Default, -1, + _T("country support not implemented") ); + + // use the C RTL for the dates in the standard range + time_t timet = GetTicks(); + if ( timet != (time_t)-1 ) + { + struct tm tmstruct; + tm *tm = wxLocaltime_r(&timet, &tmstruct); + + wxCHECK_MSG( tm, -1, _T("wxLocaltime_r() failed") ); + + return tm->tm_isdst; + } + else + { + int year = GetYear(); + + if ( !IsDSTApplicable(year, country) ) + { + // no DST time in this year in this country + return -1; + } + + return IsBetween(GetBeginDST(year, country), GetEndDST(year, country)); + } +} + +wxDateTime& wxDateTime::MakeTimezone(const TimeZone& tz, bool noDST) +{ + long secDiff = GetTimeZone() + tz.GetOffset(); + + // we need to know whether DST is or not in effect for this date unless + // the test disabled by the caller + if ( !noDST && (IsDST() == 1) ) + { + // FIXME we assume that the DST is always shifted by 1 hour + secDiff -= 3600; + } + + return Add(wxTimeSpan::Seconds(secDiff)); +} + +wxDateTime& wxDateTime::MakeFromTimezone(const TimeZone& tz, bool noDST) +{ + long secDiff = GetTimeZone() + tz.GetOffset(); + + // we need to know whether DST is or not in effect for this date unless + // the test disabled by the caller + if ( !noDST && (IsDST() == 1) ) + { + // FIXME we assume that the DST is always shifted by 1 hour + secDiff -= 3600; + } + + return Subtract(wxTimeSpan::Seconds(secDiff)); +} + +// ---------------------------------------------------------------------------- +// wxDateTime to/from text representations +// ---------------------------------------------------------------------------- + +wxString wxDateTime::Format(const wxChar *format, const TimeZone& tz) const +{ + wxCHECK_MSG( format, wxEmptyString, _T("NULL format in wxDateTime::Format") ); + + time_t time = GetTicks(); + + // we have to use our own implementation if the date is out of range of + // strftime() or if we use non standard specificators +#ifdef HAVE_STRFTIME + if ( (time != (time_t)-1) && !wxStrstr(format, _T("%l")) ) + { + // use strftime() + struct tm tmstruct; + struct tm *tm; + if ( tz.GetOffset() == -GetTimeZone() ) + { + // we are working with local time + tm = wxLocaltime_r(&time, &tmstruct); + + // should never happen + wxCHECK_MSG( tm, wxEmptyString, _T("wxLocaltime_r() failed") ); + } + else + { + time += (int)tz.GetOffset(); + +#if defined(__VMS__) || defined(__WATCOMC__) // time is unsigned so avoid warning + int time2 = (int) time; + if ( time2 >= 0 ) +#else + if ( time >= 0 ) +#endif + { + tm = wxGmtime_r(&time, &tmstruct); + + // should never happen + wxCHECK_MSG( tm, wxEmptyString, _T("wxGmtime_r() failed") ); + } + else + { + tm = (struct tm *)NULL; + } + } + + if ( tm ) + { + return CallStrftime(format, tm); + } + } + //else: use generic code below +#endif // HAVE_STRFTIME + + // we only parse ANSI C format specifications here, no POSIX 2 + // complications, no GNU extensions but we do add support for a "%l" format + // specifier allowing to get the number of milliseconds + Tm tm = GetTm(tz); + + // used for calls to strftime() when we only deal with time + struct tm tmTimeOnly; + tmTimeOnly.tm_hour = tm.hour; + tmTimeOnly.tm_min = tm.min; + tmTimeOnly.tm_sec = tm.sec; + tmTimeOnly.tm_wday = 0; + tmTimeOnly.tm_yday = 0; + tmTimeOnly.tm_mday = 1; // any date will do + tmTimeOnly.tm_mon = 0; + tmTimeOnly.tm_year = 76; + tmTimeOnly.tm_isdst = 0; // no DST, we adjust for tz ourselves + + wxString tmp, res, fmt; + for ( const wxChar *p = format; *p; p++ ) + { + if ( *p != _T('%') ) + { + // copy as is + res += *p; + + continue; + } + + // set the default format + switch ( *++p ) + { + case _T('Y'): // year has 4 digits + fmt = _T("%04d"); + break; + + case _T('j'): // day of year has 3 digits + case _T('l'): // milliseconds have 3 digits + fmt = _T("%03d"); + break; + + case _T('w'): // week day as number has only one + fmt = _T("%d"); + break; + + default: + // it's either another valid format specifier in which case + // the format is "%02d" (for all the rest) or we have the + // field width preceding the format in which case it will + // override the default format anyhow + fmt = _T("%02d"); + } + + bool restart = true; + while ( restart ) + { + restart = false; + + // start of the format specification + switch ( *p ) + { + case _T('a'): // a weekday name + case _T('A'): + // second parameter should be true for abbreviated names + res += GetWeekDayName(tm.GetWeekDay(), + *p == _T('a') ? Name_Abbr : Name_Full); + break; + + case _T('b'): // a month name + case _T('B'): + res += GetMonthName(tm.mon, + *p == _T('b') ? Name_Abbr : Name_Full); + break; + + case _T('c'): // locale default date and time representation + case _T('x'): // locale default date representation +#ifdef HAVE_STRFTIME + // + // the problem: there is no way to know what do these format + // specifications correspond to for the current locale. + // + // the solution: use a hack and still use strftime(): first + // find the YEAR which is a year in the strftime() range (1970 + // - 2038) whose Jan 1 falls on the same week day as the Jan 1 + // of the real year. Then make a copy of the format and + // replace all occurrences of YEAR in it with some unique + // string not appearing anywhere else in it, then use + // strftime() to format the date in year YEAR and then replace + // YEAR back by the real year and the unique replacement + // string back with YEAR. Notice that "all occurrences of YEAR" + // means all occurrences of 4 digit as well as 2 digit form! + // + // the bugs: we assume that neither of %c nor %x contains any + // fields which may change between the YEAR and real year. For + // example, the week number (%U, %W) and the day number (%j) + // will change if one of these years is leap and the other one + // is not! + { + // find the YEAR: normally, for any year X, Jan 1 or the + // year X + 28 is the same weekday as Jan 1 of X (because + // the weekday advances by 1 for each normal X and by 2 + // for each leap X, hence by 5 every 4 years or by 35 + // which is 0 mod 7 every 28 years) but this rule breaks + // down if there are years between X and Y which are + // divisible by 4 but not leap (i.e. divisible by 100 but + // not 400), hence the correction. + + int yearReal = GetYear(tz); + int mod28 = yearReal % 28; + + // be careful to not go too far - we risk to leave the + // supported range + int year; + if ( mod28 < 10 ) + { + year = 1988 + mod28; // 1988 == 0 (mod 28) + } + else + { + year = 1970 + mod28 - 10; // 1970 == 10 (mod 28) + } + + int nCentury = year / 100, + nCenturyReal = yearReal / 100; + + // need to adjust for the years divisble by 400 which are + // not leap but are counted like leap ones if we just take + // the number of centuries in between for nLostWeekDays + int nLostWeekDays = (nCentury - nCenturyReal) - + (nCentury / 4 - nCenturyReal / 4); + + // we have to gain back the "lost" weekdays: note that the + // effect of this loop is to not do anything to + // nLostWeekDays (which we won't use any more), but to + // (indirectly) set the year correctly + while ( (nLostWeekDays % 7) != 0 ) + { + nLostWeekDays += year++ % 4 ? 1 : 2; + } + + // Keep year below 2000 so the 2digit year number + // can never match the month or day of the month + if (year>=2000) year-=28; + // at any rate, we couldn't go further than 1988 + 9 + 28! + wxASSERT_MSG( year < 2030, + _T("logic error in wxDateTime::Format") ); + + wxString strYear, strYear2; + strYear.Printf(_T("%d"), year); + strYear2.Printf(_T("%d"), year % 100); + + // find four strings not occurring in format (this is surely + // not the optimal way of doing it... improvements welcome!) + wxString fmt2 = format; + wxString replacement,replacement2,replacement3,replacement4; + for (int rnr=1; rnr<5 ; rnr++) + { + wxString r = (wxChar)-rnr; + while ( fmt2.Find(r) != wxNOT_FOUND ) + { + r << (wxChar)-rnr; + } + + switch (rnr) + { + case 1: replacement=r; break; + case 2: replacement2=r; break; + case 3: replacement3=r; break; + case 4: replacement4=r; break; + } + } + // replace all occurrences of year with it + bool wasReplaced = fmt2.Replace(strYear, replacement) > 0; + // evaluation order ensures we always attempt the replacement. + wasReplaced = (fmt2.Replace(strYear2, replacement2) > 0) || wasReplaced; + + // use strftime() to format the same date but in supported + // year + // + // NB: we assume that strftime() doesn't check for the + // date validity and will happily format the date + // corresponding to Feb 29 of a non leap year (which + // may happen if yearReal was leap and year is not) + struct tm tmAdjusted; + InitTm(tmAdjusted); + tmAdjusted.tm_hour = tm.hour; + tmAdjusted.tm_min = tm.min; + tmAdjusted.tm_sec = tm.sec; + tmAdjusted.tm_wday = tm.GetWeekDay(); + tmAdjusted.tm_yday = GetDayOfYear(); + tmAdjusted.tm_mday = tm.mday; + tmAdjusted.tm_mon = tm.mon; + tmAdjusted.tm_year = year - 1900; + tmAdjusted.tm_isdst = 0; // no DST, already adjusted + wxString str = CallStrftime(*p == _T('c') ? _T("%c") + : _T("%x"), + &tmAdjusted); + + // now replace the occurrence of 1999 with the real year + // we do this in two stages to stop the 2 digit year + // matching any substring of the 4 digit year. + // Any day,month hours and minutes components should be safe due + // to ensuring the range of the years. + wxString strYearReal, strYearReal2; + strYearReal.Printf(_T("%04d"), yearReal); + strYearReal2.Printf(_T("%02d"), yearReal % 100); + str.Replace(strYear, replacement3); + str.Replace(strYear2,replacement4); + str.Replace(replacement3, strYearReal); + str.Replace(replacement4, strYearReal2); + + // and replace back all occurrences of replacement string + if ( wasReplaced ) + { + str.Replace(replacement2, strYear2); + str.Replace(replacement, strYear); + } + + res += str; + } +#else // !HAVE_STRFTIME + // Use "%m/%d/%y %H:%M:%S" format instead + res += wxString::Format(wxT("%02d/%02d/%04d %02d:%02d:%02d"), + tm.mon+1,tm.mday, tm.year, tm.hour, tm.min, tm.sec); +#endif // HAVE_STRFTIME/!HAVE_STRFTIME + break; + + case _T('d'): // day of a month (01-31) + res += wxString::Format(fmt, tm.mday); + break; + + case _T('H'): // hour in 24h format (00-23) + res += wxString::Format(fmt, tm.hour); + break; + + case _T('I'): // hour in 12h format (01-12) + { + // 24h -> 12h, 0h -> 12h too + int hour12 = tm.hour > 12 ? tm.hour - 12 + : tm.hour ? tm.hour : 12; + res += wxString::Format(fmt, hour12); + } + break; + + case _T('j'): // day of the year + res += wxString::Format(fmt, GetDayOfYear(tz)); + break; + + case _T('l'): // milliseconds (NOT STANDARD) + res += wxString::Format(fmt, GetMillisecond(tz)); + break; + + case _T('m'): // month as a number (01-12) + res += wxString::Format(fmt, tm.mon + 1); + break; + + case _T('M'): // minute as a decimal number (00-59) + res += wxString::Format(fmt, tm.min); + break; + + case _T('p'): // AM or PM string +#ifdef HAVE_STRFTIME + res += CallStrftime(_T("%p"), &tmTimeOnly); +#else // !HAVE_STRFTIME + res += (tmTimeOnly.tm_hour > 12) ? wxT("pm") : wxT("am"); +#endif // HAVE_STRFTIME/!HAVE_STRFTIME + break; + + case _T('S'): // second as a decimal number (00-61) + res += wxString::Format(fmt, tm.sec); + break; + + case _T('U'): // week number in the year (Sunday 1st week day) + res += wxString::Format(fmt, GetWeekOfYear(Sunday_First, tz)); + break; + + case _T('W'): // week number in the year (Monday 1st week day) + res += wxString::Format(fmt, GetWeekOfYear(Monday_First, tz)); + break; + + case _T('w'): // weekday as a number (0-6), Sunday = 0 + res += wxString::Format(fmt, tm.GetWeekDay()); + break; + + // case _T('x'): -- handled with "%c" + + case _T('X'): // locale default time representation + // just use strftime() to format the time for us +#ifdef HAVE_STRFTIME + res += CallStrftime(_T("%X"), &tmTimeOnly); +#else // !HAVE_STRFTIME + res += wxString::Format(wxT("%02d:%02d:%02d"),tm.hour, tm.min, tm.sec); +#endif // HAVE_STRFTIME/!HAVE_STRFTIME + break; + + case _T('y'): // year without century (00-99) + res += wxString::Format(fmt, tm.year % 100); + break; + + case _T('Y'): // year with century + res += wxString::Format(fmt, tm.year); + break; + + case _T('Z'): // timezone name +#ifdef HAVE_STRFTIME + res += CallStrftime(_T("%Z"), &tmTimeOnly); +#endif + break; + + default: + // is it the format width? + fmt.Empty(); + while ( *p == _T('-') || *p == _T('+') || + *p == _T(' ') || wxIsdigit(*p) ) + { + fmt += *p; + } + + if ( !fmt.empty() ) + { + // we've only got the flags and width so far in fmt + fmt.Prepend(_T('%')); + fmt.Append(_T('d')); + + restart = true; + + break; + } + + // no, it wasn't the width + wxFAIL_MSG(_T("unknown format specificator")); + + // fall through and just copy it nevertheless + + case _T('%'): // a percent sign + res += *p; + break; + + case 0: // the end of string + wxFAIL_MSG(_T("missing format at the end of string")); + + // just put the '%' which was the last char in format + res += _T('%'); + break; + } + } + } + + return res; +} + +// this function parses a string in (strict) RFC 822 format: see the section 5 +// of the RFC for the detailed description, but briefly it's something of the +// form "Sat, 18 Dec 1999 00:48:30 +0100" +// +// this function is "strict" by design - it must reject anything except true +// RFC822 time specs. +// +// TODO a great candidate for using reg exps +const wxChar *wxDateTime::ParseRfc822Date(const wxChar* date) +{ + wxCHECK_MSG( date, (wxChar *)NULL, _T("NULL pointer in wxDateTime::Parse") ); + + const wxChar *p = date; + const wxChar *comma = wxStrchr(p, _T(',')); + if ( comma ) + { + // the part before comma is the weekday + + // skip it for now - we don't use but might check that it really + // corresponds to the specfied date + p = comma + 1; + + if ( *p != _T(' ') ) + { + wxLogDebug(_T("no space after weekday in RFC822 time spec")); + + return (wxChar *)NULL; + } + + p++; // skip space + } + + // the following 1 or 2 digits are the day number + if ( !wxIsdigit(*p) ) + { + wxLogDebug(_T("day number expected in RFC822 time spec, none found")); + + return (wxChar *)NULL; + } + + wxDateTime_t day = (wxDateTime_t)(*p++ - _T('0')); + if ( wxIsdigit(*p) ) + { + day *= 10; + day = (wxDateTime_t)(day + (*p++ - _T('0'))); + } + + if ( *p++ != _T(' ') ) + { + return (wxChar *)NULL; + } + + // the following 3 letters specify the month + wxString monName(p, 3); + Month mon; + if ( monName == _T("Jan") ) + mon = Jan; + else if ( monName == _T("Feb") ) + mon = Feb; + else if ( monName == _T("Mar") ) + mon = Mar; + else if ( monName == _T("Apr") ) + mon = Apr; + else if ( monName == _T("May") ) + mon = May; + else if ( monName == _T("Jun") ) + mon = Jun; + else if ( monName == _T("Jul") ) + mon = Jul; + else if ( monName == _T("Aug") ) + mon = Aug; + else if ( monName == _T("Sep") ) + mon = Sep; + else if ( monName == _T("Oct") ) + mon = Oct; + else if ( monName == _T("Nov") ) + mon = Nov; + else if ( monName == _T("Dec") ) + mon = Dec; + else + { + wxLogDebug(_T("Invalid RFC 822 month name '%s'"), monName.c_str()); + + return (wxChar *)NULL; + } + + p += 3; + + if ( *p++ != _T(' ') ) + { + return (wxChar *)NULL; + } + + // next is the year + if ( !wxIsdigit(*p) ) + { + // no year? + return (wxChar *)NULL; + } + + int year = *p++ - _T('0'); + + if ( !wxIsdigit(*p) ) + { + // should have at least 2 digits in the year + return (wxChar *)NULL; + } + + year *= 10; + year += *p++ - _T('0'); + + // is it a 2 digit year (as per original RFC 822) or a 4 digit one? + if ( wxIsdigit(*p) ) + { + year *= 10; + year += *p++ - _T('0'); + + if ( !wxIsdigit(*p) ) + { + // no 3 digit years please + return (wxChar *)NULL; + } + + year *= 10; + year += *p++ - _T('0'); + } + + if ( *p++ != _T(' ') ) + { + return (wxChar *)NULL; + } + + // time is in the format hh:mm:ss and seconds are optional + if ( !wxIsdigit(*p) ) + { + return (wxChar *)NULL; + } + + wxDateTime_t hour = (wxDateTime_t)(*p++ - _T('0')); + + if ( !wxIsdigit(*p) ) + { + return (wxChar *)NULL; + } + + hour *= 10; + hour = (wxDateTime_t)(hour + (*p++ - _T('0'))); + + if ( *p++ != _T(':') ) + { + return (wxChar *)NULL; + } + + if ( !wxIsdigit(*p) ) + { + return (wxChar *)NULL; + } + + wxDateTime_t min = (wxDateTime_t)(*p++ - _T('0')); + + if ( !wxIsdigit(*p) ) + { + return (wxChar *)NULL; + } + + min *= 10; + min = (wxDateTime_t)(min + *p++ - _T('0')); + + wxDateTime_t sec = 0; + if ( *p == _T(':') ) + { + p++; + if ( !wxIsdigit(*p) ) + { + return (wxChar *)NULL; + } + + sec = (wxDateTime_t)(*p++ - _T('0')); + + if ( !wxIsdigit(*p) ) + { + return (wxChar *)NULL; + } + + sec *= 10; + sec = (wxDateTime_t)(sec + *p++ - _T('0')); + } + + if ( *p++ != _T(' ') ) + { + return (wxChar *)NULL; + } + + // and now the interesting part: the timezone + int offset wxDUMMY_INITIALIZE(0); + if ( *p == _T('-') || *p == _T('+') ) + { + // the explicit offset given: it has the form of hhmm + bool plus = *p++ == _T('+'); + + if ( !wxIsdigit(*p) || !wxIsdigit(*(p + 1)) ) + { + return (wxChar *)NULL; + } + + // hours + offset = MIN_PER_HOUR*(10*(*p - _T('0')) + (*(p + 1) - _T('0'))); + + p += 2; + + if ( !wxIsdigit(*p) || !wxIsdigit(*(p + 1)) ) + { + return (wxChar *)NULL; + } + + // minutes + offset += 10*(*p - _T('0')) + (*(p + 1) - _T('0')); + + if ( !plus ) + { + offset = -offset; + } + + p += 2; + } + else + { + // the symbolic timezone given: may be either military timezone or one + // of standard abbreviations + if ( !*(p + 1) ) + { + // military: Z = UTC, J unused, A = -1, ..., Y = +12 + static const int offsets[26] = + { + //A B C D E F G H I J K L M + -1, -2, -3, -4, -5, -6, -7, -8, -9, 0, -10, -11, -12, + //N O P R Q S T U V W Z Y Z + +1, +2, +3, +4, +5, +6, +7, +8, +9, +10, +11, +12, 0 + }; + + if ( *p < _T('A') || *p > _T('Z') || *p == _T('J') ) + { + wxLogDebug(_T("Invalid militaty timezone '%c'"), *p); + + return (wxChar *)NULL; + } + + offset = offsets[*p++ - _T('A')]; + } + else + { + // abbreviation + wxString tz = p; + if ( tz == _T("UT") || tz == _T("UTC") || tz == _T("GMT") ) + offset = 0; + else if ( tz == _T("AST") ) + offset = AST - GMT0; + else if ( tz == _T("ADT") ) + offset = ADT - GMT0; + else if ( tz == _T("EST") ) + offset = EST - GMT0; + else if ( tz == _T("EDT") ) + offset = EDT - GMT0; + else if ( tz == _T("CST") ) + offset = CST - GMT0; + else if ( tz == _T("CDT") ) + offset = CDT - GMT0; + else if ( tz == _T("MST") ) + offset = MST - GMT0; + else if ( tz == _T("MDT") ) + offset = MDT - GMT0; + else if ( tz == _T("PST") ) + offset = PST - GMT0; + else if ( tz == _T("PDT") ) + offset = PDT - GMT0; + else + { + wxLogDebug(_T("Unknown RFC 822 timezone '%s'"), p); + + return (wxChar *)NULL; + } + + p += tz.length(); + } + + // make it minutes + offset *= MIN_PER_HOUR; + } + + // the spec was correct, construct the date from the values we found + Set(day, mon, year, hour, min, sec); + MakeFromTimezone(TimeZone::Make(offset*SEC_PER_MIN)); + + return p; +} + +#ifdef __WINDOWS__ + +// returns the string containing strftime() format used for short dates in the +// current locale or an empty string +static wxString GetLocaleDateFormat() +{ + wxString fmtWX; + + // there is no setlocale() under Windows CE, so just always query the + // system there +#ifndef __WXWINCE__ + if ( strcmp(setlocale(LC_ALL, NULL), "C") != 0 ) +#endif + { + // The locale was programatically set to non-C. We assume that this was + // done using wxLocale, in which case thread's current locale is also + // set to correct LCID value and we can use GetLocaleInfo to determine + // the correct formatting string: +#ifdef __WXWINCE__ + LCID lcid = LOCALE_USER_DEFAULT; +#else + LCID lcid = GetThreadLocale(); +#endif + // according to MSDN 80 chars is max allowed for short date format + wxChar fmt[81]; + if ( ::GetLocaleInfo(lcid, LOCALE_SSHORTDATE, fmt, WXSIZEOF(fmt)) ) + { + wxChar chLast = _T('\0'); + size_t lastCount = 0; + for ( const wxChar *p = fmt; /* NUL handled inside */; p++ ) + { + if ( *p == chLast ) + { + lastCount++; + continue; + } + + switch ( *p ) + { + // these characters come in groups, start counting them + case _T('d'): + case _T('M'): + case _T('y'): + case _T('g'): + chLast = *p; + lastCount = 1; + break; + + default: + // first deal with any special characters we have had + if ( lastCount ) + { + switch ( chLast ) + { + case _T('d'): + switch ( lastCount ) + { + case 1: // d + case 2: // dd + // these two are the same as we + // don't distinguish between 1 and + // 2 digits for days + fmtWX += _T("%d"); + break; + + case 3: // ddd + fmtWX += _T("%a"); + break; + + case 4: // dddd + fmtWX += _T("%A"); + break; + + default: + wxFAIL_MSG( _T("too many 'd's") ); + } + break; + + case _T('M'): + switch ( lastCount ) + { + case 1: // M + case 2: // MM + // as for 'd' and 'dd' above + fmtWX += _T("%m"); + break; + + case 3: + fmtWX += _T("%b"); + break; + + case 4: + fmtWX += _T("%B"); + break; + + default: + wxFAIL_MSG( _T("too many 'M's") ); + } + break; + + case _T('y'): + switch ( lastCount ) + { + case 1: // y + case 2: // yy + fmtWX += _T("%y"); + break; + + case 4: // yyyy + fmtWX += _T("%Y"); + break; + + default: + wxFAIL_MSG( _T("wrong number of 'y's") ); + } + break; + + case _T('g'): + // strftime() doesn't have era string, + // ignore this format + wxASSERT_MSG( lastCount <= 2, + _T("too many 'g's") ); + break; + + default: + wxFAIL_MSG( _T("unreachable") ); + } + + chLast = _T('\0'); + lastCount = 0; + } + + // not a special character so must be just a separator, + // treat as is + if ( *p != _T('\0') ) + { + if ( *p == _T('%') ) + { + // this one needs to be escaped + fmtWX += _T('%'); + } + + fmtWX += *p; + } + } + + if ( *p == _T('\0') ) + break; + } + } + //else: GetLocaleInfo() failed, leave fmtDate value unchanged and + // try our luck with the default formats + } + //else: default C locale, default formats should work + + return fmtWX; +} + +#endif // __WINDOWS__ + +const wxChar *wxDateTime::ParseFormat(const wxChar *date, + const wxChar *format, + const wxDateTime& dateDef) +{ + wxCHECK_MSG( date && format, (wxChar *)NULL, + _T("NULL pointer in wxDateTime::ParseFormat()") ); + + wxString str; + unsigned long num; + + // what fields have we found? + bool haveWDay = false, + haveYDay = false, + haveDay = false, + haveMon = false, + haveYear = false, + haveHour = false, + haveMin = false, + haveSec = false; + + bool hourIsIn12hFormat = false, // or in 24h one? + isPM = false; // AM by default + + // and the value of the items we have (init them to get rid of warnings) + wxDateTime_t sec = 0, + min = 0, + hour = 0; + WeekDay wday = Inv_WeekDay; + wxDateTime_t yday = 0, + mday = 0; + wxDateTime::Month mon = Inv_Month; + int year = 0; + + const wxChar *input = date; + for ( const wxChar *fmt = format; *fmt; fmt++ ) + { + if ( *fmt != _T('%') ) + { + if ( wxIsspace(*fmt) ) + { + // a white space in the format string matches 0 or more white + // spaces in the input + while ( wxIsspace(*input) ) + { + input++; + } + } + else // !space + { + // any other character (not whitespace, not '%') must be + // matched by itself in the input + if ( *input++ != *fmt ) + { + // no match + return (wxChar *)NULL; + } + } + + // done with this format char + continue; + } + + // start of a format specification + + // parse the optional width + size_t width = 0; + while ( wxIsdigit(*++fmt) ) + { + width *= 10; + width += *fmt - _T('0'); + } + + // the default widths for the various fields + if ( !width ) + { + switch ( *fmt ) + { + case _T('Y'): // year has 4 digits + width = 4; + break; + + case _T('j'): // day of year has 3 digits + case _T('l'): // milliseconds have 3 digits + width = 3; + break; + + case _T('w'): // week day as number has only one + width = 1; + break; + + default: + // default for all other fields + width = 2; + } + } + + // then the format itself + switch ( *fmt ) + { + case _T('a'): // a weekday name + case _T('A'): + { + int flag = *fmt == _T('a') ? Name_Abbr : Name_Full; + wday = GetWeekDayFromName(GetAlphaToken(input), flag); + if ( wday == Inv_WeekDay ) + { + // no match + return (wxChar *)NULL; + } + } + haveWDay = true; + break; + + case _T('b'): // a month name + case _T('B'): + { + int flag = *fmt == _T('b') ? Name_Abbr : Name_Full; + mon = GetMonthFromName(GetAlphaToken(input), flag); + if ( mon == Inv_Month ) + { + // no match + return (wxChar *)NULL; + } + } + haveMon = true; + break; + + case _T('c'): // locale default date and time representation + { + wxDateTime dt; + + // this is the format which corresponds to ctime() output + // and strptime("%c") should parse it, so try it first + static const wxChar *fmtCtime = _T("%a %b %d %H:%M:%S %Y"); + + const wxChar *result = dt.ParseFormat(input, fmtCtime); + if ( !result ) + { + result = dt.ParseFormat(input, _T("%x %X")); + } + + if ( !result ) + { + result = dt.ParseFormat(input, _T("%X %x")); + } + + if ( !result ) + { + // we've tried everything and still no match + return (wxChar *)NULL; + } + + Tm tm = dt.GetTm(); + + haveDay = haveMon = haveYear = + haveHour = haveMin = haveSec = true; + + hour = tm.hour; + min = tm.min; + sec = tm.sec; + + year = tm.year; + mon = tm.mon; + mday = tm.mday; + + input = result; + } + break; + + case _T('d'): // day of a month (01-31) + if ( !GetNumericToken(width, input, &num) || + (num > 31) || (num < 1) ) + { + // no match + return (wxChar *)NULL; + } + + // we can't check whether the day range is correct yet, will + // do it later - assume ok for now + haveDay = true; + mday = (wxDateTime_t)num; + break; + + case _T('H'): // hour in 24h format (00-23) + if ( !GetNumericToken(width, input, &num) || (num > 23) ) + { + // no match + return (wxChar *)NULL; + } + + haveHour = true; + hour = (wxDateTime_t)num; + break; + + case _T('I'): // hour in 12h format (01-12) + if ( !GetNumericToken(width, input, &num) || !num || (num > 12) ) + { + // no match + return (wxChar *)NULL; + } + + haveHour = true; + hourIsIn12hFormat = true; + hour = (wxDateTime_t)(num % 12); // 12 should be 0 + break; + + case _T('j'): // day of the year + if ( !GetNumericToken(width, input, &num) || !num || (num > 366) ) + { + // no match + return (wxChar *)NULL; + } + + haveYDay = true; + yday = (wxDateTime_t)num; + break; + + case _T('m'): // month as a number (01-12) + if ( !GetNumericToken(width, input, &num) || !num || (num > 12) ) + { + // no match + return (wxChar *)NULL; + } + + haveMon = true; + mon = (Month)(num - 1); + break; + + case _T('M'): // minute as a decimal number (00-59) + if ( !GetNumericToken(width, input, &num) || (num > 59) ) + { + // no match + return (wxChar *)NULL; + } + + haveMin = true; + min = (wxDateTime_t)num; + break; + + case _T('p'): // AM or PM string + { + wxString am, pm, token = GetAlphaToken(input); + + GetAmPmStrings(&am, &pm); + if (am.empty() && pm.empty()) + return (wxChar *)NULL; // no am/pm strings defined + if ( token.CmpNoCase(pm) == 0 ) + { + isPM = true; + } + else if ( token.CmpNoCase(am) != 0 ) + { + // no match + return (wxChar *)NULL; + } + } + break; + + case _T('r'): // time as %I:%M:%S %p + { + wxDateTime dt; + input = dt.ParseFormat(input, _T("%I:%M:%S %p")); + if ( !input ) + { + // no match + return (wxChar *)NULL; + } + + haveHour = haveMin = haveSec = true; + + Tm tm = dt.GetTm(); + hour = tm.hour; + min = tm.min; + sec = tm.sec; + } + break; + + case _T('R'): // time as %H:%M + { + wxDateTime dt; + input = dt.ParseFormat(input, _T("%H:%M")); + if ( !input ) + { + // no match + return (wxChar *)NULL; + } + + haveHour = haveMin = true; + + Tm tm = dt.GetTm(); + hour = tm.hour; + min = tm.min; + } + break; + + case _T('S'): // second as a decimal number (00-61) + if ( !GetNumericToken(width, input, &num) || (num > 61) ) + { + // no match + return (wxChar *)NULL; + } + + haveSec = true; + sec = (wxDateTime_t)num; + break; + + case _T('T'): // time as %H:%M:%S + { + wxDateTime dt; + input = dt.ParseFormat(input, _T("%H:%M:%S")); + if ( !input ) + { + // no match + return (wxChar *)NULL; + } + + haveHour = haveMin = haveSec = true; + + Tm tm = dt.GetTm(); + hour = tm.hour; + min = tm.min; + sec = tm.sec; + } + break; + + case _T('w'): // weekday as a number (0-6), Sunday = 0 + if ( !GetNumericToken(width, input, &num) || (wday > 6) ) + { + // no match + return (wxChar *)NULL; + } + + haveWDay = true; + wday = (WeekDay)num; + break; + + case _T('x'): // locale default date representation +#ifdef HAVE_STRPTIME + // try using strptime() -- it may fail even if the input is + // correct but the date is out of range, so we will fall back + // to our generic code anyhow + { + struct tm tm; + + const wxChar *result = CallStrptime(input, "%x", &tm); + if ( result ) + { + input = result; + + haveDay = haveMon = haveYear = true; + + year = 1900 + tm.tm_year; + mon = (Month)tm.tm_mon; + mday = tm.tm_mday; + + break; + } + } +#endif // HAVE_STRPTIME + + { + wxDateTime dt; + wxString fmtDate, + fmtDateAlt; + +#ifdef __WINDOWS__ + // The above doesn't work for all locales, try to query + // Windows for the right way of formatting the date: + fmtDate = GetLocaleDateFormat(); + if ( fmtDate.empty() ) +#endif + { + if ( IsWestEuropeanCountry(GetCountry()) || + GetCountry() == Russia ) + { + fmtDate = _T("%d/%m/%y"); + fmtDateAlt = _T("%m/%d/%y"); + } + else // assume USA + { + fmtDate = _T("%m/%d/%y"); + fmtDateAlt = _T("%d/%m/%y"); + } + } + + const wxChar *result = dt.ParseFormat(input, fmtDate); + + if ( !result && !fmtDateAlt.empty() ) + { + // ok, be nice and try another one + result = dt.ParseFormat(input, fmtDateAlt); + } + + if ( !result ) + { + // bad luck + return (wxChar *)NULL; + } + + Tm tm = dt.GetTm(); + + haveDay = haveMon = haveYear = true; + + year = tm.year; + mon = tm.mon; + mday = tm.mday; + + input = result; + } + + break; + + case _T('X'): // locale default time representation +#ifdef HAVE_STRPTIME + { + // use strptime() to do it for us (FIXME !Unicode friendly) + struct tm tm; + input = CallStrptime(input, "%X", &tm); + if ( !input ) + { + return (wxChar *)NULL; + } + + haveHour = haveMin = haveSec = true; + + hour = tm.tm_hour; + min = tm.tm_min; + sec = tm.tm_sec; + } +#else // !HAVE_STRPTIME + // TODO under Win32 we can query the LOCALE_ITIME system + // setting which says whether the default time format is + // 24 or 12 hour + { + // try to parse what follows as "%H:%M:%S" and, if this + // fails, as "%I:%M:%S %p" - this should catch the most + // common cases + wxDateTime dt; + + const wxChar *result = dt.ParseFormat(input, _T("%T")); + if ( !result ) + { + result = dt.ParseFormat(input, _T("%r")); + } + + if ( !result ) + { + // no match + return (wxChar *)NULL; + } + + haveHour = haveMin = haveSec = true; + + Tm tm = dt.GetTm(); + hour = tm.hour; + min = tm.min; + sec = tm.sec; + + input = result; + } +#endif // HAVE_STRPTIME/!HAVE_STRPTIME + break; + + case _T('y'): // year without century (00-99) + if ( !GetNumericToken(width, input, &num) || (num > 99) ) + { + // no match + return (wxChar *)NULL; + } + + haveYear = true; + + // TODO should have an option for roll over date instead of + // hard coding it here + year = (num > 30 ? 1900 : 2000) + (wxDateTime_t)num; + break; + + case _T('Y'): // year with century + if ( !GetNumericToken(width, input, &num) ) + { + // no match + return (wxChar *)NULL; + } + + haveYear = true; + year = (wxDateTime_t)num; + break; + + case _T('Z'): // timezone name + wxFAIL_MSG(_T("TODO")); + break; + + case _T('%'): // a percent sign + if ( *input++ != _T('%') ) + { + // no match + return (wxChar *)NULL; + } + break; + + case 0: // the end of string + wxFAIL_MSG(_T("unexpected format end")); + + // fall through + + default: // not a known format spec + return (wxChar *)NULL; + } + } + + // format matched, try to construct a date from what we have now + Tm tmDef; + if ( dateDef.IsValid() ) + { + // take this date as default + tmDef = dateDef.GetTm(); + } + else if ( IsValid() ) + { + // if this date is valid, don't change it + tmDef = GetTm(); + } + else + { + // no default and this date is invalid - fall back to Today() + tmDef = Today().GetTm(); + } + + Tm tm = tmDef; + + // set the date + if ( haveYear ) + { + tm.year = year; + } + + // TODO we don't check here that the values are consistent, if both year + // day and month/day were found, we just ignore the year day and we + // also always ignore the week day + if ( haveMon && haveDay ) + { + if ( mday > GetNumOfDaysInMonth(tm.year, mon) ) + { + wxLogDebug(_T("bad month day in wxDateTime::ParseFormat")); + + return (wxChar *)NULL; + } + + tm.mon = mon; + tm.mday = mday; + } + else if ( haveYDay ) + { + if ( yday > GetNumberOfDays(tm.year) ) + { + wxLogDebug(_T("bad year day in wxDateTime::ParseFormat")); + + return (wxChar *)NULL; + } + + Tm tm2 = wxDateTime(1, Jan, tm.year).SetToYearDay(yday).GetTm(); + + tm.mon = tm2.mon; + tm.mday = tm2.mday; + } + + // deal with AM/PM + if ( haveHour && hourIsIn12hFormat && isPM ) + { + // translate to 24hour format + hour += 12; + } + //else: either already in 24h format or no translation needed + + // set the time + if ( haveHour ) + { + tm.hour = hour; + } + + if ( haveMin ) + { + tm.min = min; + } + + if ( haveSec ) + { + tm.sec = sec; + } + + Set(tm); + + // finally check that the week day is consistent -- if we had it + if ( haveWDay && GetWeekDay() != wday ) + { + wxLogDebug(_T("inconsistsnet week day in wxDateTime::ParseFormat()")); + + return NULL; + } + + return input; +} + +const wxChar *wxDateTime::ParseDateTime(const wxChar *date) +{ + wxCHECK_MSG( date, (wxChar *)NULL, _T("NULL pointer in wxDateTime::Parse") ); + + // Set to current day and hour, so strings like '14:00' becomes today at + // 14, not some other random date + wxDateTime dtDate = wxDateTime::Today(); + wxDateTime dtTime = wxDateTime::Today(); + + const wxChar* pchTime; + + // Try to parse the beginning of the string as a date + const wxChar* pchDate = dtDate.ParseDate(date); + + // We got a date in the beginning, see if there is a time specified after the date + if ( pchDate ) + { + // Skip spaces, as the ParseTime() function fails on spaces + while ( wxIsspace(*pchDate) ) + pchDate++; + + pchTime = dtTime.ParseTime(pchDate); + } + else // no date in the beginning + { + // check and see if we have a time followed by a date + pchTime = dtTime.ParseTime(date); + if ( pchTime ) + { + while ( wxIsspace(*pchTime) ) + pchTime++; + + pchDate = dtDate.ParseDate(pchTime); + } + } + + // If we have a date specified, set our own data to the same date + if ( !pchDate || !pchTime ) + return NULL; + + Set(dtDate.GetDay(), dtDate.GetMonth(), dtDate.GetYear(), + dtTime.GetHour(), dtTime.GetMinute(), dtTime.GetSecond(), + dtTime.GetMillisecond()); + + // Return endpoint of scan + return pchDate > pchTime ? pchDate : pchTime; +} + +const wxChar *wxDateTime::ParseDate(const wxChar *date) +{ + // this is a simplified version of ParseDateTime() which understands only + // "today" (for wxDate compatibility) and digits only otherwise (and not + // all esoteric constructions ParseDateTime() knows about) + + wxCHECK_MSG( date, (wxChar *)NULL, _T("NULL pointer in wxDateTime::Parse") ); + + const wxChar *p = date; + while ( wxIsspace(*p) ) + p++; + + // some special cases + static struct + { + const wxChar *str; + int dayDiffFromToday; + } literalDates[] = + { + { wxTRANSLATE("today"), 0 }, + { wxTRANSLATE("yesterday"), -1 }, + { wxTRANSLATE("tomorrow"), 1 }, + }; + + for ( size_t n = 0; n < WXSIZEOF(literalDates); n++ ) + { + const wxString dateStr = wxGetTranslation(literalDates[n].str); + size_t len = dateStr.length(); + if ( wxStrlen(p) >= len ) + { + wxString str(p, len); + if ( str.CmpNoCase(dateStr) == 0 ) + { + // nothing can follow this, so stop here + p += len; + + int dayDiffFromToday = literalDates[n].dayDiffFromToday; + *this = Today(); + if ( dayDiffFromToday ) + { + *this += wxDateSpan::Days(dayDiffFromToday); + } + + return p; + } + } + } + + // We try to guess what we have here: for each new (numeric) token, we + // determine if it can be a month, day or a year. Of course, there is an + // ambiguity as some numbers may be days as well as months, so we also + // have the ability to back track. + + // what do we have? + bool haveDay = false, // the months day? + haveWDay = false, // the day of week? + haveMon = false, // the month? + haveYear = false; // the year? + + // and the value of the items we have (init them to get rid of warnings) + WeekDay wday = Inv_WeekDay; + wxDateTime_t day = 0; + wxDateTime::Month mon = Inv_Month; + int year = 0; + + // tokenize the string + size_t nPosCur = 0; + static const wxChar *dateDelimiters = _T(".,/-\t\r\n "); + wxStringTokenizer tok(p, dateDelimiters); + while ( tok.HasMoreTokens() ) + { + wxString token = tok.GetNextToken(); + if ( !token ) + continue; + + // is it a number? + unsigned long val; + if ( token.ToULong(&val) ) + { + // guess what this number is + + bool isDay = false, + isMonth = false, + isYear = false; + + if ( !haveMon && val > 0 && val <= 12 ) + { + // assume it is month + isMonth = true; + } + else // not the month + { + if ( haveDay ) + { + // this can only be the year + isYear = true; + } + else // may be either day or year + { + // use a leap year if we don't have the year yet to allow + // dates like 2/29/1976 which would be rejected otherwise + wxDateTime_t max_days = (wxDateTime_t)( + haveMon + ? GetNumOfDaysInMonth(haveYear ? year : 1976, mon) + : 31 + ); + + // can it be day? + if ( (val == 0) || (val > (unsigned long)max_days) ) + { + // no + isYear = true; + } + else // yes, suppose it's the day + { + isDay = true; + } + } + } + + if ( isYear ) + { + if ( haveYear ) + break; + + haveYear = true; + + year = (wxDateTime_t)val; + } + else if ( isDay ) + { + if ( haveDay ) + break; + + haveDay = true; + + day = (wxDateTime_t)val; + } + else if ( isMonth ) + { + haveMon = true; + + mon = (Month)(val - 1); + } + } + else // not a number + { + // be careful not to overwrite the current mon value + Month mon2 = GetMonthFromName(token, Name_Full | Name_Abbr); + if ( mon2 != Inv_Month ) + { + // it's a month + if ( haveMon ) + { + // but we already have a month - maybe we guessed wrong? + if ( !haveDay ) + { + // no need to check in month range as always < 12, but + // the days are counted from 1 unlike the months + day = (wxDateTime_t)(mon + 1); + haveDay = true; + } + else + { + // could possible be the year (doesn't the year come + // before the month in the japanese format?) (FIXME) + break; + } + } + + mon = mon2; + + haveMon = true; + } + else // not a valid month name + { + WeekDay wday2 = GetWeekDayFromName(token, Name_Full | Name_Abbr); + if ( wday2 != Inv_WeekDay ) + { + // a week day + if ( haveWDay ) + { + break; + } + + wday = wday2; + + haveWDay = true; + } + else // not a valid weekday name + { + // try the ordinals + static const wxChar *ordinals[] = + { + wxTRANSLATE("first"), + wxTRANSLATE("second"), + wxTRANSLATE("third"), + wxTRANSLATE("fourth"), + wxTRANSLATE("fifth"), + wxTRANSLATE("sixth"), + wxTRANSLATE("seventh"), + wxTRANSLATE("eighth"), + wxTRANSLATE("ninth"), + wxTRANSLATE("tenth"), + wxTRANSLATE("eleventh"), + wxTRANSLATE("twelfth"), + wxTRANSLATE("thirteenth"), + wxTRANSLATE("fourteenth"), + wxTRANSLATE("fifteenth"), + wxTRANSLATE("sixteenth"), + wxTRANSLATE("seventeenth"), + wxTRANSLATE("eighteenth"), + wxTRANSLATE("nineteenth"), + wxTRANSLATE("twentieth"), + // that's enough - otherwise we'd have problems with + // composite (or not) ordinals + }; + + size_t n; + for ( n = 0; n < WXSIZEOF(ordinals); n++ ) + { + if ( token.CmpNoCase(ordinals[n]) == 0 ) + { + break; + } + } + + if ( n == WXSIZEOF(ordinals) ) + { + // stop here - something unknown + break; + } + + // it's a day + if ( haveDay ) + { + // don't try anything here (as in case of numeric day + // above) - the symbolic day spec should always + // precede the month/year + break; + } + + haveDay = true; + + day = (wxDateTime_t)(n + 1); + } + } + } + + nPosCur = tok.GetPosition(); + } + + // either no more tokens or the scan was stopped by something we couldn't + // parse - in any case, see if we can construct a date from what we have + if ( !haveDay && !haveWDay ) + { + wxLogDebug(_T("ParseDate: no day, no weekday hence no date.")); + + return NULL; + } + + if ( haveWDay && (haveMon || haveYear || haveDay) && + !(haveDay && haveMon && haveYear) ) + { + // without adjectives (which we don't support here) the week day only + // makes sense completely separately or with the full date + // specification (what would "Wed 1999" mean?) + return NULL; + } + + if ( !haveWDay && haveYear && !(haveDay && haveMon) ) + { + // may be we have month and day instead of day and year? + if ( haveDay && !haveMon ) + { + if ( day <= 12 ) + { + // exchange day and month + mon = (wxDateTime::Month)(day - 1); + + // we're in the current year then + if ( (year > 0) && (year <= (int)GetNumOfDaysInMonth(Inv_Year, mon)) ) + { + day = (wxDateTime_t)year; + + haveMon = true; + haveYear = false; + } + //else: no, can't exchange, leave haveMon == false + } + } + + if ( !haveMon ) + { + // if we give the year, month and day must be given too + wxLogDebug(_T("ParseDate: day and month should be specified if year is.")); + + return NULL; + } + } + + if ( !haveMon ) + { + mon = GetCurrentMonth(); + } + + if ( !haveYear ) + { + year = GetCurrentYear(); + } + + if ( haveDay ) + { + // normally we check the day above but the check is optimistic in case + // we find the day before its month/year so we have to redo it now + if ( day > GetNumOfDaysInMonth(year, mon) ) + return NULL; + + Set(day, mon, year); + + if ( haveWDay ) + { + // check that it is really the same + if ( GetWeekDay() != wday ) + { + // inconsistency detected + wxLogDebug(_T("ParseDate: inconsistent day/weekday.")); + + return (wxChar *)NULL; + } + } + } + else // haveWDay + { + *this = Today(); + + SetToWeekDayInSameWeek(wday); + } + + // return the pointer to the first unparsed char + p += nPosCur; + if ( nPosCur && wxStrchr(dateDelimiters, *(p - 1)) ) + { + // if we couldn't parse the token after the delimiter, put back the + // delimiter as well + p--; + } + + return p; +} + +const wxChar *wxDateTime::ParseTime(const wxChar *time) +{ + wxCHECK_MSG( time, (wxChar *)NULL, _T("NULL pointer in wxDateTime::Parse") ); + + // first try some extra things + static const struct + { + const wxChar *name; + wxDateTime_t hour; + } stdTimes[] = + { + { wxTRANSLATE("noon"), 12 }, + { wxTRANSLATE("midnight"), 00 }, + // anything else? + }; + + for ( size_t n = 0; n < WXSIZEOF(stdTimes); n++ ) + { + wxString timeString = wxGetTranslation(stdTimes[n].name); + size_t len = timeString.length(); + if ( timeString.CmpNoCase(wxString(time, len)) == 0 ) + { + // casts required by DigitalMars + Set(stdTimes[n].hour, wxDateTime_t(0), wxDateTime_t(0)); + + return time + len; + } + } + + // try all time formats we may think about in the order from longest to + // shortest + + // 12hour with AM/PM? + const wxChar *result = ParseFormat(time, _T("%I:%M:%S %p")); + + if ( !result ) + { + // normally, it's the same, but why not try it? + result = ParseFormat(time, _T("%H:%M:%S")); + } + + if ( !result ) + { + // 12hour with AM/PM but without seconds? + result = ParseFormat(time, _T("%I:%M %p")); + } + + if ( !result ) + { + // without seconds? + result = ParseFormat(time, _T("%H:%M")); + } + + if ( !result ) + { + // just the hour and AM/PM? + result = ParseFormat(time, _T("%I %p")); + } + + if ( !result ) + { + // just the hour? + result = ParseFormat(time, _T("%H")); + } + + if ( !result ) + { + // parse the standard format: normally it is one of the formats above + // but it may be set to something completely different by the user + result = ParseFormat(time, _T("%X")); + } + + // TODO: parse timezones + + return result; +} + +// ---------------------------------------------------------------------------- +// Workdays and holidays support +// ---------------------------------------------------------------------------- + +bool wxDateTime::IsWorkDay(Country WXUNUSED(country)) const +{ + return !wxDateTimeHolidayAuthority::IsHoliday(*this); +} + +// ============================================================================ +// wxDateSpan +// ============================================================================ + +wxDateSpan WXDLLIMPEXP_BASE operator*(int n, const wxDateSpan& ds) +{ + wxDateSpan ds1(ds); + return ds1.Multiply(n); +} + +// ============================================================================ +// wxTimeSpan +// ============================================================================ + +wxTimeSpan WXDLLIMPEXP_BASE operator*(int n, const wxTimeSpan& ts) +{ + return wxTimeSpan(ts).Multiply(n); +} + +// this enum is only used in wxTimeSpan::Format() below but we can't declare +// it locally to the method as it provokes an internal compiler error in egcs +// 2.91.60 when building with -O2 +enum TimeSpanPart +{ + Part_Week, + Part_Day, + Part_Hour, + Part_Min, + Part_Sec, + Part_MSec +}; + +// not all strftime(3) format specifiers make sense here because, for example, +// a time span doesn't have a year nor a timezone +// +// Here are the ones which are supported (all of them are supported by strftime +// as well): +// %H hour in 24 hour format +// %M minute (00 - 59) +// %S second (00 - 59) +// %% percent sign +// +// Also, for MFC CTimeSpan compatibility, we support +// %D number of days +// +// And, to be better than MFC :-), we also have +// %E number of wEeks +// %l milliseconds (000 - 999) +wxString wxTimeSpan::Format(const wxChar *format) const +{ + wxCHECK_MSG( format, wxEmptyString, _T("NULL format in wxTimeSpan::Format") ); + + wxString str; + str.Alloc(wxStrlen(format)); + + // Suppose we have wxTimeSpan ts(1 /* hour */, 2 /* min */, 3 /* sec */) + // + // Then, of course, ts.Format("%H:%M:%S") must return "01:02:03", but the + // question is what should ts.Format("%S") do? The code here returns "3273" + // in this case (i.e. the total number of seconds, not just seconds % 60) + // because, for me, this call means "give me entire time interval in + // seconds" and not "give me the seconds part of the time interval" + // + // If we agree that it should behave like this, it is clear that the + // interpretation of each format specifier depends on the presence of the + // other format specs in the string: if there was "%H" before "%M", we + // should use GetMinutes() % 60, otherwise just GetMinutes() &c + + // we remember the most important unit found so far + TimeSpanPart partBiggest = Part_MSec; + + for ( const wxChar *pch = format; *pch; pch++ ) + { + wxChar ch = *pch; + + if ( ch == _T('%') ) + { + // the start of the format specification of the printf() below + wxString fmtPrefix(_T('%')); + + // the number + long n; + + // the number of digits for the format string, 0 if unused + unsigned digits = 0; + + ch = *++pch; // get the format spec char + switch ( ch ) + { + default: + wxFAIL_MSG( _T("invalid format character") ); + // fall through + + case _T('%'): + str += ch; + + // skip the part below switch + continue; + + case _T('D'): + n = GetDays(); + if ( partBiggest < Part_Day ) + { + n %= DAYS_PER_WEEK; + } + else + { + partBiggest = Part_Day; + } + break; + + case _T('E'): + partBiggest = Part_Week; + n = GetWeeks(); + break; + + case _T('H'): + n = GetHours(); + if ( partBiggest < Part_Hour ) + { + if ( n < 0 ) + { + // the sign has already been taken into account + // when outputting the biggest part + n = -n; + } + + n %= HOURS_PER_DAY; + } + else + { + partBiggest = Part_Hour; + } + + digits = 2; + break; + + case _T('l'): + n = GetMilliseconds().ToLong(); + if ( partBiggest < Part_MSec ) + { + if ( n < 0 ) + n = -n; + + n %= 1000; + } + //else: no need to reset partBiggest to Part_MSec, it is + // the least significant one anyhow + + digits = 3; + break; + + case _T('M'): + n = GetMinutes(); + if ( partBiggest < Part_Min ) + { + if ( n < 0 ) + n = -n; + + n %= MIN_PER_HOUR; + } + else + { + partBiggest = Part_Min; + } + + digits = 2; + break; + + case _T('S'): + n = GetSeconds().ToLong(); + if ( partBiggest < Part_Sec ) + { + if ( n < 0 ) + n = -n; + + n %= SEC_PER_MIN; + } + else + { + partBiggest = Part_Sec; + } + + digits = 2; + break; + } + + if ( digits ) + { + // negative numbers need one extra position for '-' display + if ( n < 0 ) + digits++; + + fmtPrefix << _T("0") << digits; + } + + str += wxString::Format(fmtPrefix + _T("ld"), n); + } + else + { + // normal character, just copy + str += ch; + } + } + + return str; +} + +// ============================================================================ +// wxDateTimeHolidayAuthority and related classes +// ============================================================================ + +#include "wx/arrimpl.cpp" + +WX_DEFINE_OBJARRAY(wxDateTimeArray) + +static int wxCMPFUNC_CONV +wxDateTimeCompareFunc(wxDateTime **first, wxDateTime **second) +{ + wxDateTime dt1 = **first, + dt2 = **second; + + return dt1 == dt2 ? 0 : dt1 < dt2 ? -1 : +1; +} + +// ---------------------------------------------------------------------------- +// wxDateTimeHolidayAuthority +// ---------------------------------------------------------------------------- + +wxHolidayAuthoritiesArray wxDateTimeHolidayAuthority::ms_authorities; + +/* static */ +bool wxDateTimeHolidayAuthority::IsHoliday(const wxDateTime& dt) +{ + size_t count = ms_authorities.size(); + for ( size_t n = 0; n < count; n++ ) + { + if ( ms_authorities[n]->DoIsHoliday(dt) ) + { + return true; + } + } + + return false; +} + +/* static */ +size_t +wxDateTimeHolidayAuthority::GetHolidaysInRange(const wxDateTime& dtStart, + const wxDateTime& dtEnd, + wxDateTimeArray& holidays) +{ + wxDateTimeArray hol; + + holidays.Clear(); + + const size_t countAuth = ms_authorities.size(); + for ( size_t nAuth = 0; nAuth < countAuth; nAuth++ ) + { + ms_authorities[nAuth]->DoGetHolidaysInRange(dtStart, dtEnd, hol); + + WX_APPEND_ARRAY(holidays, hol); + } + + holidays.Sort(wxDateTimeCompareFunc); + + return holidays.size(); +} + +/* static */ +void wxDateTimeHolidayAuthority::ClearAllAuthorities() +{ + WX_CLEAR_ARRAY(ms_authorities); +} + +/* static */ +void wxDateTimeHolidayAuthority::AddAuthority(wxDateTimeHolidayAuthority *auth) +{ + ms_authorities.push_back(auth); +} + +wxDateTimeHolidayAuthority::~wxDateTimeHolidayAuthority() +{ + // required here for Darwin +} + +// ---------------------------------------------------------------------------- +// wxDateTimeWorkDays +// ---------------------------------------------------------------------------- + +bool wxDateTimeWorkDays::DoIsHoliday(const wxDateTime& dt) const +{ + wxDateTime::WeekDay wd = dt.GetWeekDay(); + + return (wd == wxDateTime::Sun) || (wd == wxDateTime::Sat); +} + +size_t wxDateTimeWorkDays::DoGetHolidaysInRange(const wxDateTime& dtStart, + const wxDateTime& dtEnd, + wxDateTimeArray& holidays) const +{ + if ( dtStart > dtEnd ) + { + wxFAIL_MSG( _T("invalid date range in GetHolidaysInRange") ); + + return 0u; + } + + holidays.Empty(); + + // instead of checking all days, start with the first Sat after dtStart and + // end with the last Sun before dtEnd + wxDateTime dtSatFirst = dtStart.GetNextWeekDay(wxDateTime::Sat), + dtSatLast = dtEnd.GetPrevWeekDay(wxDateTime::Sat), + dtSunFirst = dtStart.GetNextWeekDay(wxDateTime::Sun), + dtSunLast = dtEnd.GetPrevWeekDay(wxDateTime::Sun), + dt; + + for ( dt = dtSatFirst; dt <= dtSatLast; dt += wxDateSpan::Week() ) + { + holidays.Add(dt); + } + + for ( dt = dtSunFirst; dt <= dtSunLast; dt += wxDateSpan::Week() ) + { + holidays.Add(dt); + } + + return holidays.GetCount(); +} + +// ============================================================================ +// other helper functions +// ============================================================================ + +// ---------------------------------------------------------------------------- +// iteration helpers: can be used to write a for loop over enum variable like +// this: +// for ( m = wxDateTime::Jan; m < wxDateTime::Inv_Month; wxNextMonth(m) ) +// ---------------------------------------------------------------------------- + +WXDLLIMPEXP_BASE void wxNextMonth(wxDateTime::Month& m) +{ + wxASSERT_MSG( m < wxDateTime::Inv_Month, _T("invalid month") ); + + // no wrapping or the for loop above would never end! + m = (wxDateTime::Month)(m + 1); +} + +WXDLLIMPEXP_BASE void wxPrevMonth(wxDateTime::Month& m) +{ + wxASSERT_MSG( m < wxDateTime::Inv_Month, _T("invalid month") ); + + m = m == wxDateTime::Jan ? wxDateTime::Inv_Month + : (wxDateTime::Month)(m - 1); +} + +WXDLLIMPEXP_BASE void wxNextWDay(wxDateTime::WeekDay& wd) +{ + wxASSERT_MSG( wd < wxDateTime::Inv_WeekDay, _T("invalid week day") ); + + // no wrapping or the for loop above would never end! + wd = (wxDateTime::WeekDay)(wd + 1); +} + +WXDLLIMPEXP_BASE void wxPrevWDay(wxDateTime::WeekDay& wd) +{ + wxASSERT_MSG( wd < wxDateTime::Inv_WeekDay, _T("invalid week day") ); + + wd = wd == wxDateTime::Sun ? wxDateTime::Inv_WeekDay + : (wxDateTime::WeekDay)(wd - 1); +} + +#endif // wxUSE_DATETIME diff --git a/Externals/wxWidgets/src/common/datstrm.cpp b/Externals/wxWidgets/src/common/datstrm.cpp index 28f496562b..fd16e9223d 100644 --- a/Externals/wxWidgets/src/common/datstrm.cpp +++ b/Externals/wxWidgets/src/common/datstrm.cpp @@ -1,745 +1,745 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/datstrm.cpp -// Purpose: Data stream classes -// Author: Guilhem Lavaux -// Modified by: Mickael Gilabert -// Created: 28/06/98 -// RCS-ID: $Id: datstrm.cpp 53028 2008-04-05 17:28:32Z VZ $ -// Copyright: (c) Guilhem Lavaux -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_STREAMS - -#include "wx/datstrm.h" - -#ifndef WX_PRECOMP - #include "wx/math.h" -#endif //WX_PRECOMP - -// --------------------------------------------------------------------------- -// wxDataInputStream -// --------------------------------------------------------------------------- - -#if wxUSE_UNICODE -wxDataInputStream::wxDataInputStream(wxInputStream& s, const wxMBConv& conv) - : m_input(&s), m_be_order(false), m_conv(conv.Clone()) -#else -wxDataInputStream::wxDataInputStream(wxInputStream& s) - : m_input(&s), m_be_order(false) -#endif -{ -} - -wxDataInputStream::~wxDataInputStream() -{ -#if wxUSE_UNICODE - delete m_conv; -#endif // wxUSE_UNICODE -} - -#if wxHAS_INT64 -wxUint64 wxDataInputStream::Read64() -{ - wxUint64 tmp; - Read64(&tmp, 1); - return tmp; -} -#endif // wxHAS_INT64 - -wxUint32 wxDataInputStream::Read32() -{ - wxUint32 i32; - - m_input->Read(&i32, 4); - - if (m_be_order) - return wxUINT32_SWAP_ON_LE(i32); - else - return wxUINT32_SWAP_ON_BE(i32); -} - -wxUint16 wxDataInputStream::Read16() -{ - wxUint16 i16; - - m_input->Read(&i16, 2); - - if (m_be_order) - return wxUINT16_SWAP_ON_LE(i16); - else - return wxUINT16_SWAP_ON_BE(i16); -} - -wxUint8 wxDataInputStream::Read8() -{ - wxUint8 buf; - - m_input->Read(&buf, 1); - return (wxUint8)buf; -} - -double wxDataInputStream::ReadDouble() -{ -#if wxUSE_APPLE_IEEE - char buf[10]; - - m_input->Read(buf, 10); - return ConvertFromIeeeExtended((const wxInt8 *)buf); -#else - return 0.0; -#endif -} - -wxString wxDataInputStream::ReadString() -{ - wxString ret; - - const size_t len = Read32(); - if ( len > 0 ) - { -#if wxUSE_UNICODE - wxCharBuffer tmp(len + 1); - if ( tmp ) - { - m_input->Read(tmp.data(), len); - tmp.data()[len] = '\0'; - ret = m_conv->cMB2WX(tmp.data()); - } -#else - wxStringBuffer buf(ret, len); - if ( buf ) - m_input->Read(buf, len); -#endif - } - - return ret; -} - -#if wxUSE_LONGLONG - -template -static -void DoReadLL(T *buffer, size_t size, wxInputStream *input, bool be_order) -{ - typedef T DataType; - unsigned char *pchBuffer = new unsigned char[size * 8]; - // TODO: Check for overflow when size is of type uint and is > than 512m - input->Read(pchBuffer, size * 8); - size_t idx_base = 0; - if ( be_order ) - { - for ( size_t uiIndex = 0; uiIndex != size; ++uiIndex ) - { - buffer[uiIndex] = 0l; - for ( unsigned ui = 0; ui != 8; ++ui ) - { - buffer[uiIndex] = buffer[uiIndex] * 256l + - DataType((unsigned long) pchBuffer[idx_base + ui]); - } - - idx_base += 8; - } - } - else // little endian - { - for ( size_t uiIndex=0; uiIndex!=size; ++uiIndex ) - { - buffer[uiIndex] = 0l; - for ( unsigned ui=0; ui!=8; ++ui ) - buffer[uiIndex] = buffer[uiIndex] * 256l + - DataType((unsigned long) pchBuffer[idx_base + 7 - ui]); - idx_base += 8; - } - } - delete[] pchBuffer; -} - -template -static void DoWriteLL(const T *buffer, size_t size, wxOutputStream *output, bool be_order) -{ - typedef T DataType; - unsigned char *pchBuffer = new unsigned char[size * 8]; - size_t idx_base = 0; - if ( be_order ) - { - for ( size_t uiIndex = 0; uiIndex != size; ++uiIndex ) - { - DataType i64 = buffer[uiIndex]; - for ( unsigned ui = 0; ui != 8; ++ui ) - { - pchBuffer[idx_base + 7 - ui] = - (unsigned char) (i64.GetLo() & 255l); - i64 >>= 8l; - } - - idx_base += 8; - } - } - else // little endian - { - for ( size_t uiIndex=0; uiIndex != size; ++uiIndex ) - { - DataType i64 = buffer[uiIndex]; - for (unsigned ui=0; ui!=8; ++ui) - { - pchBuffer[idx_base + ui] = - (unsigned char) (i64.GetLo() & 255l); - i64 >>= 8l; - } - - idx_base += 8; - } - } - - // TODO: Check for overflow when size is of type uint and is > than 512m - output->Write(pchBuffer, size * 8); - delete[] pchBuffer; -} - -#endif // wxUSE_LONGLONG - -#ifdef wxLongLong_t - -template -static -void DoReadI64(T *buffer, size_t size, wxInputStream *input, bool be_order) -{ - typedef T DataType; - unsigned char *pchBuffer = (unsigned char*) buffer; - // TODO: Check for overflow when size is of type uint and is > than 512m - input->Read(pchBuffer, size * 8); - if ( be_order ) - { - for ( wxUint32 i = 0; i < size; i++ ) - { - DataType v = wxUINT64_SWAP_ON_LE(*buffer); - *(buffer++) = v; - } - } - else // little endian - { - for ( wxUint32 i=0; i -static -void DoWriteI64(const T *buffer, size_t size, wxOutputStream *output, bool be_order) -{ - typedef T DataType; - if ( be_order ) - { - for ( size_t i = 0; i < size; i++ ) - { - DataType i64 = wxUINT64_SWAP_ON_LE(*buffer); - buffer++; - output->Write(&i64, 8); - } - } - else // little endian - { - for ( size_t i=0; i < size; i++ ) - { - DataType i64 = wxUINT64_SWAP_ON_BE(*buffer); - buffer++; - output->Write(&i64, 8); - } - } -} - -#endif // wxLongLong_t - - -#if wxHAS_INT64 -void wxDataInputStream::Read64(wxUint64 *buffer, size_t size) -{ -#ifndef wxLongLong_t - DoReadLL(buffer, size, m_input, m_be_order); -#else - DoReadI64(buffer, size, m_input, m_be_order); -#endif -} - -void wxDataInputStream::Read64(wxInt64 *buffer, size_t size) -{ -#ifndef wxLongLong_t - DoReadLL(buffer, size, m_input, m_be_order); -#else - DoReadI64(buffer, size, m_input, m_be_order); -#endif -} -#endif // wxHAS_INT64 - -#if defined(wxLongLong_t) && wxUSE_LONGLONG -void wxDataInputStream::Read64(wxULongLong *buffer, size_t size) -{ - DoReadLL(buffer, size, m_input, m_be_order); -} - -void wxDataInputStream::Read64(wxLongLong *buffer, size_t size) -{ - DoReadLL(buffer, size, m_input, m_be_order); -} -#endif // wxLongLong_t - -#if wxUSE_LONGLONG -void wxDataInputStream::ReadLL(wxULongLong *buffer, size_t size) -{ - DoReadLL(buffer, size, m_input, m_be_order); -} - -void wxDataInputStream::ReadLL(wxLongLong *buffer, size_t size) -{ - DoReadLL(buffer, size, m_input, m_be_order); -} - -wxLongLong wxDataInputStream::ReadLL(void) -{ - wxLongLong ll; - DoReadLL(&ll, (size_t)1, m_input, m_be_order); - return ll; -} -#endif // wxUSE_LONGLONG - -void wxDataInputStream::Read32(wxUint32 *buffer, size_t size) -{ - m_input->Read(buffer, size * 4); - - if (m_be_order) - { - for (wxUint32 i=0; iRead(buffer, size * 2); - - if (m_be_order) - { - for (wxUint32 i=0; iRead(buffer, size); -} - -void wxDataInputStream::ReadDouble(double *buffer, size_t size) -{ - for (wxUint32 i=0; i>(wxString& s) -{ - s = ReadString(); - return *this; -} - -wxDataInputStream& wxDataInputStream::operator>>(wxInt8& c) -{ - c = (wxInt8)Read8(); - return *this; -} - -wxDataInputStream& wxDataInputStream::operator>>(wxInt16& i) -{ - i = (wxInt16)Read16(); - return *this; -} - -wxDataInputStream& wxDataInputStream::operator>>(wxInt32& i) -{ - i = (wxInt32)Read32(); - return *this; -} - -wxDataInputStream& wxDataInputStream::operator>>(wxUint8& c) -{ - c = Read8(); - return *this; -} - -wxDataInputStream& wxDataInputStream::operator>>(wxUint16& i) -{ - i = Read16(); - return *this; -} - -wxDataInputStream& wxDataInputStream::operator>>(wxUint32& i) -{ - i = Read32(); - return *this; -} - -#if wxHAS_INT64 -wxDataInputStream& wxDataInputStream::operator>>(wxUint64& i) -{ - i = Read64(); - return *this; -} - -wxDataInputStream& wxDataInputStream::operator>>(wxInt64& i) -{ - i = Read64(); - return *this; -} -#endif // wxHAS_INT64 - -#if defined(wxLongLong_t) && wxUSE_LONGLONG -wxDataInputStream& wxDataInputStream::operator>>(wxULongLong& i) -{ - i = ReadLL(); - return *this; -} - -wxDataInputStream& wxDataInputStream::operator>>(wxLongLong& i) -{ - i = ReadLL(); - return *this; -} -#endif // wxLongLong_t - -wxDataInputStream& wxDataInputStream::operator>>(double& i) -{ - i = ReadDouble(); - return *this; -} - -wxDataInputStream& wxDataInputStream::operator>>(float& f) -{ - f = (float)ReadDouble(); - return *this; -} - -// --------------------------------------------------------------------------- -// wxDataOutputStream -// --------------------------------------------------------------------------- - -#if wxUSE_UNICODE -wxDataOutputStream::wxDataOutputStream(wxOutputStream& s, const wxMBConv& conv) - : m_output(&s), m_be_order(false), m_conv(conv.Clone()) -#else -wxDataOutputStream::wxDataOutputStream(wxOutputStream& s) - : m_output(&s), m_be_order(false) -#endif -{ -} - -wxDataOutputStream::~wxDataOutputStream() -{ -#if wxUSE_UNICODE - delete m_conv; -#endif // wxUSE_UNICODE -} - -#if wxHAS_INT64 -void wxDataOutputStream::Write64(wxUint64 i) -{ - Write64(&i, 1); -} - -void wxDataOutputStream::Write64(wxInt64 i) -{ - Write64(&i, 1); -} -#endif // wxHAS_INT64 - -void wxDataOutputStream::Write32(wxUint32 i) -{ - wxUint32 i32; - - if (m_be_order) - i32 = wxUINT32_SWAP_ON_LE(i); - else - i32 = wxUINT32_SWAP_ON_BE(i); - m_output->Write(&i32, 4); -} - -void wxDataOutputStream::Write16(wxUint16 i) -{ - wxUint16 i16; - - if (m_be_order) - i16 = wxUINT16_SWAP_ON_LE(i); - else - i16 = wxUINT16_SWAP_ON_BE(i); - - m_output->Write(&i16, 2); -} - -void wxDataOutputStream::Write8(wxUint8 i) -{ - m_output->Write(&i, 1); -} - -void wxDataOutputStream::WriteString(const wxString& string) -{ -#if wxUSE_UNICODE - const wxWX2MBbuf buf = string.mb_str(*m_conv); -#else - const wxWX2MBbuf buf = string.mb_str(); -#endif - size_t len = strlen(buf); - Write32(len); - if (len > 0) - m_output->Write(buf, len); -} - -void wxDataOutputStream::WriteDouble(double d) -{ - char buf[10]; - -#if wxUSE_APPLE_IEEE - ConvertToIeeeExtended(d, (wxInt8 *)buf); -#else -#if !defined(__VMS__) && !defined(__GNUG__) -# pragma warning "wxDataOutputStream::WriteDouble() not using IeeeExtended - will not work!" -#endif - buf[0] = '\0'; -#endif - m_output->Write(buf, 10); -} - -#if wxHAS_INT64 -void wxDataOutputStream::Write64(const wxUint64 *buffer, size_t size) -{ -#ifndef wxLongLong_t - DoWriteLL(buffer, size, m_output, m_be_order); -#else - DoWriteI64(buffer, size, m_output, m_be_order); -#endif -} - -void wxDataOutputStream::Write64(const wxInt64 *buffer, size_t size) -{ -#ifndef wxLongLong_t - DoWriteLL(buffer, size, m_output, m_be_order); -#else - DoWriteI64(buffer, size, m_output, m_be_order); -#endif -} -#endif // wxHAS_INT64 - -#if defined(wxLongLong_t) && wxUSE_LONGLONG -void wxDataOutputStream::Write64(const wxULongLong *buffer, size_t size) -{ - DoWriteLL(buffer, size, m_output, m_be_order); -} - -void wxDataOutputStream::Write64(const wxLongLong *buffer, size_t size) -{ - DoWriteLL(buffer, size, m_output, m_be_order); -} -#endif // wxLongLong_t - -#if wxUSE_LONGLONG -void wxDataOutputStream::WriteLL(const wxULongLong *buffer, size_t size) -{ - DoWriteLL(buffer, size, m_output, m_be_order); -} - -void wxDataOutputStream::WriteLL(const wxLongLong *buffer, size_t size) -{ - DoWriteLL(buffer, size, m_output, m_be_order); -} - -void wxDataOutputStream::WriteLL(const wxLongLong &ll) -{ - WriteLL(&ll, 1); -} - -void wxDataOutputStream::WriteLL(const wxULongLong &ll) -{ - WriteLL(&ll, 1); -} -#endif // wxUSE_LONGLONG - -void wxDataOutputStream::Write32(const wxUint32 *buffer, size_t size) -{ - if (m_be_order) - { - for (wxUint32 i=0; iWrite(&i32, 4); - } - } - else - { - for (wxUint32 i=0; iWrite(&i32, 4); - } - } -} - -void wxDataOutputStream::Write16(const wxUint16 *buffer, size_t size) -{ - if (m_be_order) - { - for (wxUint32 i=0; iWrite(&i16, 2); - } - } - else - { - for (wxUint32 i=0; iWrite(&i16, 2); - } - } -} - -void wxDataOutputStream::Write8(const wxUint8 *buffer, size_t size) -{ - m_output->Write(buffer, size); -} - -void wxDataOutputStream::WriteDouble(const double *buffer, size_t size) -{ - for (wxUint32 i=0; iWrite((const char *)string, wxStrlen(string)*sizeof(wxChar)); - return *this; -} - -wxDataOutputStream& wxDataOutputStream::operator<<(const wxString& string) -{ - WriteString(string); - return *this; -} - -wxDataOutputStream& wxDataOutputStream::operator<<(wxInt8 c) -{ - Write8((wxUint8)c); - return *this; -} - -wxDataOutputStream& wxDataOutputStream::operator<<(wxInt16 i) -{ - Write16((wxUint16)i); - return *this; -} - -wxDataOutputStream& wxDataOutputStream::operator<<(wxInt32 i) -{ - Write32((wxUint32)i); - return *this; -} - -wxDataOutputStream& wxDataOutputStream::operator<<(wxUint8 c) -{ - Write8(c); - return *this; -} - -wxDataOutputStream& wxDataOutputStream::operator<<(wxUint16 i) -{ - Write16(i); - return *this; -} - -wxDataOutputStream& wxDataOutputStream::operator<<(wxUint32 i) -{ - Write32(i); - return *this; -} - -#if wxHAS_INT64 -wxDataOutputStream& wxDataOutputStream::operator<<(wxUint64 i) -{ - Write64(i); - return *this; -} - -wxDataOutputStream& wxDataOutputStream::operator<<(wxInt64 i) -{ - Write64(i); - return *this; -} -#endif // wxHAS_INT64 - -#if defined(wxLongLong_t) && wxUSE_LONGLONG -wxDataOutputStream& wxDataOutputStream::operator<<(const wxULongLong &i) -{ - WriteLL(i); - return *this; -} - -wxDataOutputStream& wxDataOutputStream::operator<<(const wxLongLong &i) -{ - WriteLL(i); - return *this; -} -#endif // wxLongLong_t - -wxDataOutputStream& wxDataOutputStream::operator<<(double f) -{ - WriteDouble(f); - return *this; -} - -wxDataOutputStream& wxDataOutputStream::operator<<(float f) -{ - WriteDouble((double)f); - return *this; -} - -#endif - // wxUSE_STREAMS +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/datstrm.cpp +// Purpose: Data stream classes +// Author: Guilhem Lavaux +// Modified by: Mickael Gilabert +// Created: 28/06/98 +// RCS-ID: $Id: datstrm.cpp 53028 2008-04-05 17:28:32Z VZ $ +// Copyright: (c) Guilhem Lavaux +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_STREAMS + +#include "wx/datstrm.h" + +#ifndef WX_PRECOMP + #include "wx/math.h" +#endif //WX_PRECOMP + +// --------------------------------------------------------------------------- +// wxDataInputStream +// --------------------------------------------------------------------------- + +#if wxUSE_UNICODE +wxDataInputStream::wxDataInputStream(wxInputStream& s, const wxMBConv& conv) + : m_input(&s), m_be_order(false), m_conv(conv.Clone()) +#else +wxDataInputStream::wxDataInputStream(wxInputStream& s) + : m_input(&s), m_be_order(false) +#endif +{ +} + +wxDataInputStream::~wxDataInputStream() +{ +#if wxUSE_UNICODE + delete m_conv; +#endif // wxUSE_UNICODE +} + +#if wxHAS_INT64 +wxUint64 wxDataInputStream::Read64() +{ + wxUint64 tmp; + Read64(&tmp, 1); + return tmp; +} +#endif // wxHAS_INT64 + +wxUint32 wxDataInputStream::Read32() +{ + wxUint32 i32; + + m_input->Read(&i32, 4); + + if (m_be_order) + return wxUINT32_SWAP_ON_LE(i32); + else + return wxUINT32_SWAP_ON_BE(i32); +} + +wxUint16 wxDataInputStream::Read16() +{ + wxUint16 i16; + + m_input->Read(&i16, 2); + + if (m_be_order) + return wxUINT16_SWAP_ON_LE(i16); + else + return wxUINT16_SWAP_ON_BE(i16); +} + +wxUint8 wxDataInputStream::Read8() +{ + wxUint8 buf; + + m_input->Read(&buf, 1); + return (wxUint8)buf; +} + +double wxDataInputStream::ReadDouble() +{ +#if wxUSE_APPLE_IEEE + char buf[10]; + + m_input->Read(buf, 10); + return ConvertFromIeeeExtended((const wxInt8 *)buf); +#else + return 0.0; +#endif +} + +wxString wxDataInputStream::ReadString() +{ + wxString ret; + + const size_t len = Read32(); + if ( len > 0 ) + { +#if wxUSE_UNICODE + wxCharBuffer tmp(len + 1); + if ( tmp ) + { + m_input->Read(tmp.data(), len); + tmp.data()[len] = '\0'; + ret = m_conv->cMB2WX(tmp.data()); + } +#else + wxStringBuffer buf(ret, len); + if ( buf ) + m_input->Read(buf, len); +#endif + } + + return ret; +} + +#if wxUSE_LONGLONG + +template +static +void DoReadLL(T *buffer, size_t size, wxInputStream *input, bool be_order) +{ + typedef T DataType; + unsigned char *pchBuffer = new unsigned char[size * 8]; + // TODO: Check for overflow when size is of type uint and is > than 512m + input->Read(pchBuffer, size * 8); + size_t idx_base = 0; + if ( be_order ) + { + for ( size_t uiIndex = 0; uiIndex != size; ++uiIndex ) + { + buffer[uiIndex] = 0l; + for ( unsigned ui = 0; ui != 8; ++ui ) + { + buffer[uiIndex] = buffer[uiIndex] * 256l + + DataType((unsigned long) pchBuffer[idx_base + ui]); + } + + idx_base += 8; + } + } + else // little endian + { + for ( size_t uiIndex=0; uiIndex!=size; ++uiIndex ) + { + buffer[uiIndex] = 0l; + for ( unsigned ui=0; ui!=8; ++ui ) + buffer[uiIndex] = buffer[uiIndex] * 256l + + DataType((unsigned long) pchBuffer[idx_base + 7 - ui]); + idx_base += 8; + } + } + delete[] pchBuffer; +} + +template +static void DoWriteLL(const T *buffer, size_t size, wxOutputStream *output, bool be_order) +{ + typedef T DataType; + unsigned char *pchBuffer = new unsigned char[size * 8]; + size_t idx_base = 0; + if ( be_order ) + { + for ( size_t uiIndex = 0; uiIndex != size; ++uiIndex ) + { + DataType i64 = buffer[uiIndex]; + for ( unsigned ui = 0; ui != 8; ++ui ) + { + pchBuffer[idx_base + 7 - ui] = + (unsigned char) (i64.GetLo() & 255l); + i64 >>= 8l; + } + + idx_base += 8; + } + } + else // little endian + { + for ( size_t uiIndex=0; uiIndex != size; ++uiIndex ) + { + DataType i64 = buffer[uiIndex]; + for (unsigned ui=0; ui!=8; ++ui) + { + pchBuffer[idx_base + ui] = + (unsigned char) (i64.GetLo() & 255l); + i64 >>= 8l; + } + + idx_base += 8; + } + } + + // TODO: Check for overflow when size is of type uint and is > than 512m + output->Write(pchBuffer, size * 8); + delete[] pchBuffer; +} + +#endif // wxUSE_LONGLONG + +#ifdef wxLongLong_t + +template +static +void DoReadI64(T *buffer, size_t size, wxInputStream *input, bool be_order) +{ + typedef T DataType; + unsigned char *pchBuffer = (unsigned char*) buffer; + // TODO: Check for overflow when size is of type uint and is > than 512m + input->Read(pchBuffer, size * 8); + if ( be_order ) + { + for ( wxUint32 i = 0; i < size; i++ ) + { + DataType v = wxUINT64_SWAP_ON_LE(*buffer); + *(buffer++) = v; + } + } + else // little endian + { + for ( wxUint32 i=0; i +static +void DoWriteI64(const T *buffer, size_t size, wxOutputStream *output, bool be_order) +{ + typedef T DataType; + if ( be_order ) + { + for ( size_t i = 0; i < size; i++ ) + { + DataType i64 = wxUINT64_SWAP_ON_LE(*buffer); + buffer++; + output->Write(&i64, 8); + } + } + else // little endian + { + for ( size_t i=0; i < size; i++ ) + { + DataType i64 = wxUINT64_SWAP_ON_BE(*buffer); + buffer++; + output->Write(&i64, 8); + } + } +} + +#endif // wxLongLong_t + + +#if wxHAS_INT64 +void wxDataInputStream::Read64(wxUint64 *buffer, size_t size) +{ +#ifndef wxLongLong_t + DoReadLL(buffer, size, m_input, m_be_order); +#else + DoReadI64(buffer, size, m_input, m_be_order); +#endif +} + +void wxDataInputStream::Read64(wxInt64 *buffer, size_t size) +{ +#ifndef wxLongLong_t + DoReadLL(buffer, size, m_input, m_be_order); +#else + DoReadI64(buffer, size, m_input, m_be_order); +#endif +} +#endif // wxHAS_INT64 + +#if defined(wxLongLong_t) && wxUSE_LONGLONG +void wxDataInputStream::Read64(wxULongLong *buffer, size_t size) +{ + DoReadLL(buffer, size, m_input, m_be_order); +} + +void wxDataInputStream::Read64(wxLongLong *buffer, size_t size) +{ + DoReadLL(buffer, size, m_input, m_be_order); +} +#endif // wxLongLong_t + +#if wxUSE_LONGLONG +void wxDataInputStream::ReadLL(wxULongLong *buffer, size_t size) +{ + DoReadLL(buffer, size, m_input, m_be_order); +} + +void wxDataInputStream::ReadLL(wxLongLong *buffer, size_t size) +{ + DoReadLL(buffer, size, m_input, m_be_order); +} + +wxLongLong wxDataInputStream::ReadLL(void) +{ + wxLongLong ll; + DoReadLL(&ll, (size_t)1, m_input, m_be_order); + return ll; +} +#endif // wxUSE_LONGLONG + +void wxDataInputStream::Read32(wxUint32 *buffer, size_t size) +{ + m_input->Read(buffer, size * 4); + + if (m_be_order) + { + for (wxUint32 i=0; iRead(buffer, size * 2); + + if (m_be_order) + { + for (wxUint32 i=0; iRead(buffer, size); +} + +void wxDataInputStream::ReadDouble(double *buffer, size_t size) +{ + for (wxUint32 i=0; i>(wxString& s) +{ + s = ReadString(); + return *this; +} + +wxDataInputStream& wxDataInputStream::operator>>(wxInt8& c) +{ + c = (wxInt8)Read8(); + return *this; +} + +wxDataInputStream& wxDataInputStream::operator>>(wxInt16& i) +{ + i = (wxInt16)Read16(); + return *this; +} + +wxDataInputStream& wxDataInputStream::operator>>(wxInt32& i) +{ + i = (wxInt32)Read32(); + return *this; +} + +wxDataInputStream& wxDataInputStream::operator>>(wxUint8& c) +{ + c = Read8(); + return *this; +} + +wxDataInputStream& wxDataInputStream::operator>>(wxUint16& i) +{ + i = Read16(); + return *this; +} + +wxDataInputStream& wxDataInputStream::operator>>(wxUint32& i) +{ + i = Read32(); + return *this; +} + +#if wxHAS_INT64 +wxDataInputStream& wxDataInputStream::operator>>(wxUint64& i) +{ + i = Read64(); + return *this; +} + +wxDataInputStream& wxDataInputStream::operator>>(wxInt64& i) +{ + i = Read64(); + return *this; +} +#endif // wxHAS_INT64 + +#if defined(wxLongLong_t) && wxUSE_LONGLONG +wxDataInputStream& wxDataInputStream::operator>>(wxULongLong& i) +{ + i = ReadLL(); + return *this; +} + +wxDataInputStream& wxDataInputStream::operator>>(wxLongLong& i) +{ + i = ReadLL(); + return *this; +} +#endif // wxLongLong_t + +wxDataInputStream& wxDataInputStream::operator>>(double& i) +{ + i = ReadDouble(); + return *this; +} + +wxDataInputStream& wxDataInputStream::operator>>(float& f) +{ + f = (float)ReadDouble(); + return *this; +} + +// --------------------------------------------------------------------------- +// wxDataOutputStream +// --------------------------------------------------------------------------- + +#if wxUSE_UNICODE +wxDataOutputStream::wxDataOutputStream(wxOutputStream& s, const wxMBConv& conv) + : m_output(&s), m_be_order(false), m_conv(conv.Clone()) +#else +wxDataOutputStream::wxDataOutputStream(wxOutputStream& s) + : m_output(&s), m_be_order(false) +#endif +{ +} + +wxDataOutputStream::~wxDataOutputStream() +{ +#if wxUSE_UNICODE + delete m_conv; +#endif // wxUSE_UNICODE +} + +#if wxHAS_INT64 +void wxDataOutputStream::Write64(wxUint64 i) +{ + Write64(&i, 1); +} + +void wxDataOutputStream::Write64(wxInt64 i) +{ + Write64(&i, 1); +} +#endif // wxHAS_INT64 + +void wxDataOutputStream::Write32(wxUint32 i) +{ + wxUint32 i32; + + if (m_be_order) + i32 = wxUINT32_SWAP_ON_LE(i); + else + i32 = wxUINT32_SWAP_ON_BE(i); + m_output->Write(&i32, 4); +} + +void wxDataOutputStream::Write16(wxUint16 i) +{ + wxUint16 i16; + + if (m_be_order) + i16 = wxUINT16_SWAP_ON_LE(i); + else + i16 = wxUINT16_SWAP_ON_BE(i); + + m_output->Write(&i16, 2); +} + +void wxDataOutputStream::Write8(wxUint8 i) +{ + m_output->Write(&i, 1); +} + +void wxDataOutputStream::WriteString(const wxString& string) +{ +#if wxUSE_UNICODE + const wxWX2MBbuf buf = string.mb_str(*m_conv); +#else + const wxWX2MBbuf buf = string.mb_str(); +#endif + size_t len = strlen(buf); + Write32(len); + if (len > 0) + m_output->Write(buf, len); +} + +void wxDataOutputStream::WriteDouble(double d) +{ + char buf[10]; + +#if wxUSE_APPLE_IEEE + ConvertToIeeeExtended(d, (wxInt8 *)buf); +#else +#if !defined(__VMS__) && !defined(__GNUG__) +# pragma warning "wxDataOutputStream::WriteDouble() not using IeeeExtended - will not work!" +#endif + buf[0] = '\0'; +#endif + m_output->Write(buf, 10); +} + +#if wxHAS_INT64 +void wxDataOutputStream::Write64(const wxUint64 *buffer, size_t size) +{ +#ifndef wxLongLong_t + DoWriteLL(buffer, size, m_output, m_be_order); +#else + DoWriteI64(buffer, size, m_output, m_be_order); +#endif +} + +void wxDataOutputStream::Write64(const wxInt64 *buffer, size_t size) +{ +#ifndef wxLongLong_t + DoWriteLL(buffer, size, m_output, m_be_order); +#else + DoWriteI64(buffer, size, m_output, m_be_order); +#endif +} +#endif // wxHAS_INT64 + +#if defined(wxLongLong_t) && wxUSE_LONGLONG +void wxDataOutputStream::Write64(const wxULongLong *buffer, size_t size) +{ + DoWriteLL(buffer, size, m_output, m_be_order); +} + +void wxDataOutputStream::Write64(const wxLongLong *buffer, size_t size) +{ + DoWriteLL(buffer, size, m_output, m_be_order); +} +#endif // wxLongLong_t + +#if wxUSE_LONGLONG +void wxDataOutputStream::WriteLL(const wxULongLong *buffer, size_t size) +{ + DoWriteLL(buffer, size, m_output, m_be_order); +} + +void wxDataOutputStream::WriteLL(const wxLongLong *buffer, size_t size) +{ + DoWriteLL(buffer, size, m_output, m_be_order); +} + +void wxDataOutputStream::WriteLL(const wxLongLong &ll) +{ + WriteLL(&ll, 1); +} + +void wxDataOutputStream::WriteLL(const wxULongLong &ll) +{ + WriteLL(&ll, 1); +} +#endif // wxUSE_LONGLONG + +void wxDataOutputStream::Write32(const wxUint32 *buffer, size_t size) +{ + if (m_be_order) + { + for (wxUint32 i=0; iWrite(&i32, 4); + } + } + else + { + for (wxUint32 i=0; iWrite(&i32, 4); + } + } +} + +void wxDataOutputStream::Write16(const wxUint16 *buffer, size_t size) +{ + if (m_be_order) + { + for (wxUint32 i=0; iWrite(&i16, 2); + } + } + else + { + for (wxUint32 i=0; iWrite(&i16, 2); + } + } +} + +void wxDataOutputStream::Write8(const wxUint8 *buffer, size_t size) +{ + m_output->Write(buffer, size); +} + +void wxDataOutputStream::WriteDouble(const double *buffer, size_t size) +{ + for (wxUint32 i=0; iWrite((const char *)string, wxStrlen(string)*sizeof(wxChar)); + return *this; +} + +wxDataOutputStream& wxDataOutputStream::operator<<(const wxString& string) +{ + WriteString(string); + return *this; +} + +wxDataOutputStream& wxDataOutputStream::operator<<(wxInt8 c) +{ + Write8((wxUint8)c); + return *this; +} + +wxDataOutputStream& wxDataOutputStream::operator<<(wxInt16 i) +{ + Write16((wxUint16)i); + return *this; +} + +wxDataOutputStream& wxDataOutputStream::operator<<(wxInt32 i) +{ + Write32((wxUint32)i); + return *this; +} + +wxDataOutputStream& wxDataOutputStream::operator<<(wxUint8 c) +{ + Write8(c); + return *this; +} + +wxDataOutputStream& wxDataOutputStream::operator<<(wxUint16 i) +{ + Write16(i); + return *this; +} + +wxDataOutputStream& wxDataOutputStream::operator<<(wxUint32 i) +{ + Write32(i); + return *this; +} + +#if wxHAS_INT64 +wxDataOutputStream& wxDataOutputStream::operator<<(wxUint64 i) +{ + Write64(i); + return *this; +} + +wxDataOutputStream& wxDataOutputStream::operator<<(wxInt64 i) +{ + Write64(i); + return *this; +} +#endif // wxHAS_INT64 + +#if defined(wxLongLong_t) && wxUSE_LONGLONG +wxDataOutputStream& wxDataOutputStream::operator<<(const wxULongLong &i) +{ + WriteLL(i); + return *this; +} + +wxDataOutputStream& wxDataOutputStream::operator<<(const wxLongLong &i) +{ + WriteLL(i); + return *this; +} +#endif // wxLongLong_t + +wxDataOutputStream& wxDataOutputStream::operator<<(double f) +{ + WriteDouble(f); + return *this; +} + +wxDataOutputStream& wxDataOutputStream::operator<<(float f) +{ + WriteDouble((double)f); + return *this; +} + +#endif + // wxUSE_STREAMS diff --git a/Externals/wxWidgets/src/common/db.cpp b/Externals/wxWidgets/src/common/db.cpp index 9fedf0bd13..9517fd91b4 100644 --- a/Externals/wxWidgets/src/common/db.cpp +++ b/Externals/wxWidgets/src/common/db.cpp @@ -1,4524 +1,4524 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: src/common/db.cpp -// Purpose: Implementation of the wxDb class. The wxDb class represents a connection -// to an ODBC data source. The wxDb class allows operations on the data -// source such as opening and closing the data source. -// Author: Doug Card -// Modified by: George Tasker -// Bart Jourquin -// Mark Johnson, wxWindows@mj10777.de -// Mods: Dec, 1998: -// -Added support for SQL statement logging and database cataloging -// Mods: April, 1999 -// -Added QUERY_ONLY mode support to reduce default number of cursors -// -Added additional SQL logging code -// -Added DEBUG-ONLY tracking of wxTable objects to detect orphaned DB connections -// -Set ODBC option to only read committed writes to the DB so all -// databases operate the same in that respect -// Created: 9.96 -// RCS-ID: $Id: db.cpp 52489 2008-03-14 14:14:57Z JS $ -// Copyright: (c) 1996 Remstar International, Inc. -// Licence: wxWindows licence -/////////////////////////////////////////////////////////////////////////////// - -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_ODBC - -#ifndef WX_PRECOMP - #include "wx/object.h" - #include "wx/list.h" - #include "wx/string.h" - #include "wx/utils.h" - #include "wx/log.h" - #include "wx/app.h" -#endif - -#ifdef DBDEBUG_CONSOLE - #include "wx/ioswrap.h" -#endif - -#include "wx/filefn.h" -#include "wx/wxchar.h" - -#include -#include -#include -#include -#include - -#include "wx/db.h" - -// DLL options compatibility check: -WX_CHECK_BUILD_OPTIONS("wxODBC") - -WXDLLIMPEXP_DATA_ODBC(wxDbList*) PtrBegDbList = 0; - -wxChar const *SQL_LOG_FILENAME = wxT("sqllog.txt"); -wxChar const *SQL_CATALOG_FILENAME = wxT("catalog.txt"); - -#ifdef __WXDEBUG__ - #include "wx/thread.h" - - extern wxList TablesInUse; -#if wxUSE_THREADS - extern wxCriticalSection csTablesInUse; -#endif // wxUSE_THREADS -#endif - -// SQL Log defaults to be used by GetDbConnection -wxDbSqlLogState SQLLOGstate = sqlLogOFF; - -static wxString SQLLOGfn = SQL_LOG_FILENAME; - -// The wxDb::errorList is copied to this variable when the wxDb object -// is closed. This way, the error list is still available after the -// database object is closed. This is necessary if the database -// connection fails so the calling application can show the operator -// why the connection failed. Note: as each wxDb object is closed, it -// will overwrite the errors of the previously destroyed wxDb object in -// this variable. NOTE: This occurs during a CLOSE, not a FREEing of the -// connection -wxChar DBerrorList[DB_MAX_ERROR_HISTORY][DB_MAX_ERROR_MSG_LEN+1]; - - -// This type defines the return row-struct form -// SQLTablePrivileges, and is used by wxDB::TablePrivileges. -typedef struct -{ - wxChar tableQual[128+1]; - wxChar tableOwner[128+1]; - wxChar tableName[128+1]; - wxChar grantor[128+1]; - wxChar grantee[128+1]; - wxChar privilege[128+1]; - wxChar grantable[3+1]; -} wxDbTablePrivilegeInfo; - - -/********** wxDbConnectInf Constructor - form 1 **********/ -wxDbConnectInf::wxDbConnectInf() -{ - Henv = 0; - freeHenvOnDestroy = false; - - Initialize(); -} // Constructor - - -/********** wxDbConnectInf Constructor - form 2 **********/ -wxDbConnectInf::wxDbConnectInf(HENV henv, const wxString &dsn, const wxString &userID, - const wxString &password, const wxString &defaultDir, - const wxString &fileType, const wxString &description) -{ - Henv = 0; - freeHenvOnDestroy = false; - - Initialize(); - - if (henv) - SetHenv(henv); - else - AllocHenv(); - - SetDsn(dsn); - SetUserID(userID); - SetPassword(password); - SetDescription(description); - SetFileType(fileType); - SetDefaultDir(defaultDir); -} // wxDbConnectInf Constructor - - -wxDbConnectInf::~wxDbConnectInf() -{ - if (freeHenvOnDestroy) - { - FreeHenv(); - } -} // wxDbConnectInf Destructor - - - -/********** wxDbConnectInf::Initialize() **********/ -bool wxDbConnectInf::Initialize() -{ - freeHenvOnDestroy = false; - - if (freeHenvOnDestroy && Henv) - FreeHenv(); - - Henv = 0; - Dsn[0] = 0; - Uid[0] = 0; - AuthStr[0] = 0; - ConnectionStr[0] = 0; - Description.Empty(); - FileType.Empty(); - DefaultDir.Empty(); - - useConnectionStr = false; - - return true; -} // wxDbConnectInf::Initialize() - - -/********** wxDbConnectInf::AllocHenv() **********/ -bool wxDbConnectInf::AllocHenv() -{ - // This is here to help trap if you are getting a new henv - // without releasing an existing henv - wxASSERT(!Henv); - - // Initialize the ODBC Environment for Database Operations - if (SQLAllocEnv(&Henv) != SQL_SUCCESS) - { - wxLogDebug(wxT("A problem occurred while trying to get a connection to the data source")); - return false; - } - - freeHenvOnDestroy = true; - - return true; -} // wxDbConnectInf::AllocHenv() - - -void wxDbConnectInf::FreeHenv() -{ - wxASSERT(Henv); - - if (Henv) - SQLFreeEnv(Henv); - - Henv = 0; - freeHenvOnDestroy = false; - -} // wxDbConnectInf::FreeHenv() - - -void wxDbConnectInf::SetDsn(const wxString &dsn) -{ - wxASSERT(dsn.length() < WXSIZEOF(Dsn)); - - wxStrncpy(Dsn, dsn, WXSIZEOF(Dsn)-1); - Dsn[WXSIZEOF(Dsn)-1] = 0; // Prevent buffer overrun -} // wxDbConnectInf::SetDsn() - - -void wxDbConnectInf::SetUserID(const wxString &uid) -{ - wxASSERT(uid.length() < WXSIZEOF(Uid)); - wxStrncpy(Uid, uid, WXSIZEOF(Uid)-1); - Uid[WXSIZEOF(Uid)-1] = 0; // Prevent buffer overrun -} // wxDbConnectInf::SetUserID() - - -void wxDbConnectInf::SetPassword(const wxString &password) -{ - wxASSERT(password.length() < WXSIZEOF(AuthStr)); - - wxStrncpy(AuthStr, password, WXSIZEOF(AuthStr)-1); - AuthStr[WXSIZEOF(AuthStr)-1] = 0; // Prevent buffer overrun -} // wxDbConnectInf::SetPassword() - -void wxDbConnectInf::SetConnectionStr(const wxString &connectStr) -{ - wxASSERT(connectStr.length() < WXSIZEOF(ConnectionStr)); - - useConnectionStr = wxStrlen(connectStr) > 0; - - wxStrncpy(ConnectionStr, connectStr, WXSIZEOF(ConnectionStr)-1); - ConnectionStr[WXSIZEOF(ConnectionStr)-1] = 0; // Prevent buffer overrun -} // wxDbConnectInf::SetConnectionStr() - - -/********** wxDbColFor Constructor **********/ -wxDbColFor::wxDbColFor() -{ - Initialize(); -} // wxDbColFor::wxDbColFor() - - -/********** wxDbColFor::Initialize() **********/ -void wxDbColFor::Initialize() -{ - s_Field.Empty(); - int i; - for (i=0; i<7; i++) - { - s_Format[i].Empty(); - s_Amount[i].Empty(); - i_Amount[i] = 0; - } - i_Nation = 0; // 0=EU, 1=UK, 2=International, 3=US - i_dbDataType = 0; - i_sqlDataType = 0; - Format(1,DB_DATA_TYPE_VARCHAR,0,0,0); // the Function that does the work -} // wxDbColFor::Initialize() - - -/********** wxDbColFor::Format() **********/ -int wxDbColFor::Format(int Nation, int dbDataType, SWORD sqlDataType, - short columnLength, short decimalDigits) -{ - // ---------------------------------------------------------------------------------------- - // -- 19991224 : mj10777 : Create - // There is still a lot of work to do here, but it is a start - // It handles all the basic data-types that I have run into up to now - // The main work will have be with Dates and float Formatting - // (US 1,000.00 ; EU 1.000,00) - // There are wxWindow plans for locale support and the new wxDateTime. If - // they define some constants (wxEUROPEAN) that can be gloably used, - // they should be used here. - // ---------------------------------------------------------------------------------------- - // There should also be a function to scan in a string to fill the variable - // ---------------------------------------------------------------------------------------- - wxString tempStr; - i_Nation = Nation; // 0 = timestamp , 1=EU, 2=UK, 3=International, 4=US - i_dbDataType = dbDataType; - i_sqlDataType = sqlDataType; - s_Field.Printf(wxT("%s%d"),s_Amount[1].c_str(),i_Amount[1]); // OK for VARCHAR, INTEGER and FLOAT - - if (i_dbDataType == 0) // Filter unsupported dbDataTypes - { - if ((i_sqlDataType == SQL_VARCHAR) -#if wxUSE_UNICODE - #if defined(SQL_WCHAR) - || (i_sqlDataType == SQL_WCHAR) - #endif - #if defined(SQL_WVARCHAR) - || (i_sqlDataType == SQL_WVARCHAR) - #endif -#endif - || (i_sqlDataType == SQL_LONGVARCHAR)) - i_dbDataType = DB_DATA_TYPE_VARCHAR; - if ((i_sqlDataType == SQL_C_DATE) || (i_sqlDataType == SQL_C_TIMESTAMP)) - i_dbDataType = DB_DATA_TYPE_DATE; - if (i_sqlDataType == SQL_C_BIT) - i_dbDataType = DB_DATA_TYPE_INTEGER; - if (i_sqlDataType == SQL_NUMERIC) - i_dbDataType = DB_DATA_TYPE_VARCHAR; // glt - ??? is this right? - if (i_sqlDataType == SQL_REAL) - i_dbDataType = DB_DATA_TYPE_FLOAT; - if (i_sqlDataType == SQL_C_BINARY) - i_dbDataType = DB_DATA_TYPE_BLOB; - } - - if ((i_dbDataType == DB_DATA_TYPE_INTEGER) && (i_sqlDataType == SQL_C_DOUBLE)) - { // DBASE Numeric - i_dbDataType = DB_DATA_TYPE_FLOAT; - } - - switch(i_dbDataType) // TBD: Still a lot of proper formatting to do - { - case DB_DATA_TYPE_VARCHAR: - s_Field = wxT("%s"); - break; - case DB_DATA_TYPE_INTEGER: - s_Field = wxT("%d"); - break; - case DB_DATA_TYPE_FLOAT: - if (decimalDigits == 0) - decimalDigits = 2; - tempStr.Printf(wxT("%%%d.%d"), columnLength, decimalDigits); - s_Field.Printf(wxT("%sf"), tempStr.c_str()); - break; - case DB_DATA_TYPE_DATE: - if (i_Nation == 0) // timestamp YYYY-MM-DD HH:MM:SS.SSS (tested for SYBASE) - { - s_Field = wxT("%04d-%02d-%02d %02d:%02d:%02d.%03d"); - } - if (i_Nation == 1) // European DD.MM.YYYY HH:MM:SS.SSS - { - s_Field = wxT("%02d.%02d.%04d %02d:%02d:%02d.%03d"); - } - if (i_Nation == 2) // UK DD/MM/YYYY HH:MM:SS.SSS - { - s_Field = wxT("%02d/%02d/%04d %02d:%02d:%02d.%03d"); - } - if (i_Nation == 3) // International YYYY-MM-DD HH:MM:SS.SSS - { - s_Field = wxT("%04d-%02d-%02d %02d:%02d:%02d.%03d"); - } - if (i_Nation == 4) // US MM/DD/YYYY HH:MM:SS.SSS - { - s_Field = wxT("%02d/%02d/%04d %02d:%02d:%02d.%03d"); - } - break; - case DB_DATA_TYPE_BLOB: - s_Field.Printf(wxT("Unable to format(%d)-SQL(%d)"), dbDataType,sqlDataType); // - break; - default: - s_Field.Printf(wxT("Unknown Format(%d)-SQL(%d)"), dbDataType,sqlDataType); // - break; - }; - return TRUE; -} // wxDbColFor::Format() - - -/********** wxDbColInf Constructor **********/ -wxDbColInf::wxDbColInf() -{ - Initialize(); -} // wxDbColInf::wxDbColInf() - - -/********** wxDbColInf Destructor ********/ -wxDbColInf::~wxDbColInf() -{ - if (pColFor) - delete pColFor; - pColFor = NULL; -} // wxDbColInf::~wxDbColInf() - - -bool wxDbColInf::Initialize() -{ - catalog[0] = 0; - schema[0] = 0; - tableName[0] = 0; - colName[0] = 0; - sqlDataType = 0; - typeName[0] = 0; - columnLength = 0; - bufferSize = 0; - decimalDigits = 0; - numPrecRadix = 0; - nullable = 0; - remarks[0] = 0; - dbDataType = 0; - PkCol = 0; - PkTableName[0] = 0; - FkCol = 0; - FkTableName[0] = 0; - pColFor = NULL; - - return true; -} // wxDbColInf::Initialize() - - -/********** wxDbTableInf Constructor ********/ -wxDbTableInf::wxDbTableInf() -{ - Initialize(); -} // wxDbTableInf::wxDbTableInf() - - -/********** wxDbTableInf Constructor ********/ -wxDbTableInf::~wxDbTableInf() -{ - if (pColInf) - delete [] pColInf; - pColInf = NULL; -} // wxDbTableInf::~wxDbTableInf() - - -bool wxDbTableInf::Initialize() -{ - tableName[0] = 0; - tableType[0] = 0; - tableRemarks[0] = 0; - numCols = 0; - pColInf = NULL; - - return true; -} // wxDbTableInf::Initialize() - - -/********** wxDbInf Constructor *************/ -wxDbInf::wxDbInf() -{ - Initialize(); -} // wxDbInf::wxDbInf() - - -/********** wxDbInf Destructor *************/ -wxDbInf::~wxDbInf() -{ - if (pTableInf) - delete [] pTableInf; - pTableInf = NULL; -} // wxDbInf::~wxDbInf() - - -/********** wxDbInf::Initialize() *************/ -bool wxDbInf::Initialize() -{ - catalog[0] = 0; - schema[0] = 0; - numTables = 0; - pTableInf = NULL; - - return true; -} // wxDbInf::Initialize() - - -/********** wxDb Constructor **********/ -wxDb::wxDb(const HENV &aHenv, bool FwdOnlyCursors) -{ - // Copy the HENV into the db class - henv = aHenv; - fwdOnlyCursors = FwdOnlyCursors; - - initialize(); -} // wxDb::wxDb() - - -/********** wxDb Destructor **********/ -wxDb::~wxDb() -{ - wxASSERT_MSG(!IsCached(),wxT("Cached connections must not be manually deleted, use\nwxDbFreeConnection() or wxDbCloseConnections().")); - - if (IsOpen()) - { - Close(); - } -} // wxDb destructor - - - -/********** PRIVATE! wxDb::initialize PRIVATE! **********/ -/********** wxDb::initialize() **********/ -void wxDb::initialize() -/* - * Private member function that sets all wxDb member variables to - * known values at creation of the wxDb - */ -{ - int i; - - fpSqlLog = 0; // Sql Log file pointer - sqlLogState = sqlLogOFF; // By default, logging is turned off - nTables = 0; - dbmsType = dbmsUNIDENTIFIED; - - wxStrcpy(sqlState,wxEmptyString); - wxStrcpy(errorMsg,wxEmptyString); - nativeError = cbErrorMsg = 0; - for (i = 0; i < DB_MAX_ERROR_HISTORY; i++) - wxStrcpy(errorList[i], wxEmptyString); - - // Init typeInf structures - typeInfVarchar.TypeName.Empty(); - typeInfVarchar.FsqlType = 0; - typeInfVarchar.Precision = 0; - typeInfVarchar.CaseSensitive = 0; - typeInfVarchar.MaximumScale = 0; - - typeInfInteger.TypeName.Empty(); - typeInfInteger.FsqlType = 0; - typeInfInteger.Precision = 0; - typeInfInteger.CaseSensitive = 0; - typeInfInteger.MaximumScale = 0; - - typeInfFloat.TypeName.Empty(); - typeInfFloat.FsqlType = 0; - typeInfFloat.Precision = 0; - typeInfFloat.CaseSensitive = 0; - typeInfFloat.MaximumScale = 0; - - typeInfDate.TypeName.Empty(); - typeInfDate.FsqlType = 0; - typeInfDate.Precision = 0; - typeInfDate.CaseSensitive = 0; - typeInfDate.MaximumScale = 0; - - typeInfBlob.TypeName.Empty(); - typeInfBlob.FsqlType = 0; - typeInfBlob.Precision = 0; - typeInfBlob.CaseSensitive = 0; - typeInfBlob.MaximumScale = 0; - - typeInfMemo.TypeName.Empty(); - typeInfMemo.FsqlType = 0; - typeInfMemo.Precision = 0; - typeInfMemo.CaseSensitive = 0; - typeInfMemo.MaximumScale = 0; - - // Error reporting is turned OFF by default - silent = true; - - // Allocate a data source connection handle - if (SQLAllocConnect(henv, &hdbc) != SQL_SUCCESS) - DispAllErrors(henv); - - // Initialize the db status flag - DB_STATUS = 0; - - // Mark database as not open as of yet - dbIsOpen = false; - dbIsCached = false; - dbOpenedWithConnectionString = false; -} // wxDb::initialize() - - -/********** PRIVATE! wxDb::convertUserID PRIVATE! **********/ -// -// NOTE: Return value from this function MUST be copied -// immediately, as the value is not good after -// this function has left scope. -// -const wxChar *wxDb::convertUserID(const wxChar *userID, wxString &UserID) -{ - if (userID) - { - if (!wxStrlen(userID)) - UserID = uid; - else - UserID = userID; - } - else - UserID.Empty(); - - // dBase does not use user names, and some drivers fail if you try to pass one - if ( Dbms() == dbmsDBASE - || Dbms() == dbmsXBASE_SEQUITER ) - UserID.Empty(); - - // Some databases require user names to be specified in uppercase, - // so force the name to uppercase - if ((Dbms() == dbmsORACLE) || - (Dbms() == dbmsMAXDB)) - UserID = UserID.Upper(); - - return UserID.c_str(); -} // wxDb::convertUserID() - - -bool wxDb::determineDataTypes(bool failOnDataTypeUnsupported) -{ - size_t iIndex; - - // These are the possible SQL types we check for use against the datasource we are connected - // to for the purpose of determining which data type to use for the basic character strings - // column types - // - // NOTE: The first type in this enumeration that is determined to be supported by the - // datasource/driver is the one that will be used. - SWORD PossibleSqlCharTypes[] = { -#if wxUSE_UNICODE && defined(SQL_WVARCHAR) - SQL_WVARCHAR, -#endif - SQL_VARCHAR, -#if wxUSE_UNICODE && defined(SQL_WVARCHAR) - SQL_WCHAR, -#endif - SQL_CHAR - }; - - // These are the possible SQL types we check for use against the datasource we are connected - // to for the purpose of determining which data type to use for the basic non-floating point - // column types - // - // NOTE: The first type in this enumeration that is determined to be supported by the - // datasource/driver is the one that will be used. - SWORD PossibleSqlIntegerTypes[] = { - SQL_INTEGER - }; - - // These are the possible SQL types we check for use against the datasource we are connected - // to for the purpose of determining which data type to use for the basic floating point number - // column types - // - // NOTE: The first type in this enumeration that is determined to be supported by the - // datasource/driver is the one that will be used. - SWORD PossibleSqlFloatTypes[] = { - SQL_DOUBLE, - SQL_REAL, - SQL_FLOAT, - SQL_DECIMAL, - SQL_NUMERIC - }; - - // These are the possible SQL types we check for use agains the datasource we are connected - // to for the purpose of determining which data type to use for the date/time column types - // - // NOTE: The first type in this enumeration that is determined to be supported by the - // datasource/driver is the one that will be used. - SWORD PossibleSqlDateTypes[] = { - SQL_TIMESTAMP, - SQL_DATE, -#ifdef SQL_DATETIME - SQL_DATETIME -#endif - }; - - // These are the possible SQL types we check for use agains the datasource we are connected - // to for the purpose of determining which data type to use for the BLOB column types. - // - // NOTE: The first type in this enumeration that is determined to be supported by the - // datasource/driver is the one that will be used. - SWORD PossibleSqlBlobTypes[] = { - SQL_LONGVARBINARY, - SQL_VARBINARY - }; - - // These are the possible SQL types we check for use agains the datasource we are connected - // to for the purpose of determining which data type to use for the MEMO column types - // (a type which allow to store large strings; like VARCHAR just with a bigger precision) - // - // NOTE: The first type in this enumeration that is determined to be supported by the - // datasource/driver is the one that will be used. - SWORD PossibleSqlMemoTypes[] = { - SQL_LONGVARCHAR, - }; - - - // Query the data source regarding data type information - - // - // The way it was determined which SQL data types to use was by calling SQLGetInfo - // for all of the possible SQL data types to see which ones were supported. If - // a type is not supported, the SQLFetch() that's called from getDataTypeInfo() - // fails with SQL_NO_DATA_FOUND. This is ugly because I'm sure the three SQL data - // types I've selected below will not always be what we want. These are just - // what happened to work against an Oracle 7/Intersolv combination. The following is - // a complete list of the results I got back against the Oracle 7 database: - // - // SQL_BIGINT SQL_NO_DATA_FOUND - // SQL_BINARY SQL_NO_DATA_FOUND - // SQL_BIT SQL_NO_DATA_FOUND - // SQL_CHAR type name = 'CHAR', Precision = 255 - // SQL_DATE SQL_NO_DATA_FOUND - // SQL_DECIMAL type name = 'NUMBER', Precision = 38 - // SQL_DOUBLE type name = 'NUMBER', Precision = 15 - // SQL_FLOAT SQL_NO_DATA_FOUND - // SQL_INTEGER SQL_NO_DATA_FOUND - // SQL_LONGVARBINARY type name = 'LONG RAW', Precision = 2 billion - // SQL_LONGVARCHAR type name = 'LONG', Precision = 2 billion - // SQL_NUMERIC SQL_NO_DATA_FOUND - // SQL_REAL SQL_NO_DATA_FOUND - // SQL_SMALLINT SQL_NO_DATA_FOUND - // SQL_TIME SQL_NO_DATA_FOUND - // SQL_TIMESTAMP type name = 'DATE', Precision = 19 - // SQL_VARBINARY type name = 'RAW', Precision = 255 - // SQL_VARCHAR type name = 'VARCHAR2', Precision = 2000 - // ===================================================================== - // Results from a Microsoft Access 7.0 db, using a driver from Microsoft - // - // SQL_VARCHAR type name = 'TEXT', Precision = 255 - // SQL_TIMESTAMP type name = 'DATETIME' - // SQL_DECIMAL SQL_NO_DATA_FOUND - // SQL_NUMERIC type name = 'CURRENCY', Precision = 19 - // SQL_FLOAT SQL_NO_DATA_FOUND - // SQL_REAL type name = 'SINGLE', Precision = 7 - // SQL_DOUBLE type name = 'DOUBLE', Precision = 15 - // SQL_INTEGER type name = 'LONG', Precision = 10 - - // Query the data source for info about itself - if (!getDbInfo(failOnDataTypeUnsupported)) - return false; - - // --------------- Varchar - (Variable length character string) --------------- - for (iIndex = 0; iIndex < WXSIZEOF(PossibleSqlCharTypes) && - !getDataTypeInfo(PossibleSqlCharTypes[iIndex], typeInfVarchar); ++iIndex) - {} - - if (iIndex < WXSIZEOF(PossibleSqlCharTypes)) - typeInfVarchar.FsqlType = PossibleSqlCharTypes[iIndex]; - else if (failOnDataTypeUnsupported) - return false; - - // --------------- Float --------------- - for (iIndex = 0; iIndex < WXSIZEOF(PossibleSqlFloatTypes) && - !getDataTypeInfo(PossibleSqlFloatTypes[iIndex], typeInfFloat); ++iIndex) - {} - - if (iIndex < WXSIZEOF(PossibleSqlFloatTypes)) - typeInfFloat.FsqlType = PossibleSqlFloatTypes[iIndex]; - else if (failOnDataTypeUnsupported) - return false; - - // --------------- Integer ------------- - for (iIndex = 0; iIndex < WXSIZEOF(PossibleSqlIntegerTypes) && - !getDataTypeInfo(PossibleSqlIntegerTypes[iIndex], typeInfInteger); ++iIndex) - {} - - if (iIndex < WXSIZEOF(PossibleSqlIntegerTypes)) - typeInfInteger.FsqlType = PossibleSqlIntegerTypes[iIndex]; - else if (failOnDataTypeUnsupported) - { - // If no non-floating point data types are supported, we'll - // use the type assigned for floats to store integers as well - if (!getDataTypeInfo(typeInfFloat.FsqlType, typeInfInteger)) - { - if (failOnDataTypeUnsupported) - return false; - } - else - typeInfInteger.FsqlType = typeInfFloat.FsqlType; - } - - // --------------- Date/Time --------------- - for (iIndex = 0; iIndex < WXSIZEOF(PossibleSqlDateTypes) && - !getDataTypeInfo(PossibleSqlDateTypes[iIndex], typeInfDate); ++iIndex) - {} - - if (iIndex < WXSIZEOF(PossibleSqlDateTypes)) - typeInfDate.FsqlType = PossibleSqlDateTypes[iIndex]; - else if (failOnDataTypeUnsupported) - return false; - - // --------------- BLOB --------------- - for (iIndex = 0; iIndex < WXSIZEOF(PossibleSqlBlobTypes) && - !getDataTypeInfo(PossibleSqlBlobTypes[iIndex], typeInfBlob); ++iIndex) - {} - - if (iIndex < WXSIZEOF(PossibleSqlBlobTypes)) - typeInfBlob.FsqlType = PossibleSqlBlobTypes[iIndex]; - else if (failOnDataTypeUnsupported) - return false; - - // --------------- MEMO --------------- - for (iIndex = 0; iIndex < WXSIZEOF(PossibleSqlMemoTypes) && - !getDataTypeInfo(PossibleSqlMemoTypes[iIndex], typeInfMemo); ++iIndex) - {} - - if (iIndex < WXSIZEOF(PossibleSqlMemoTypes)) - typeInfMemo.FsqlType = PossibleSqlMemoTypes[iIndex]; - else if (failOnDataTypeUnsupported) - return false; - - return true; -} // wxDb::determineDataTypes - - -bool wxDb::open(bool failOnDataTypeUnsupported) -{ -/* - If using Intersolv branded ODBC drivers, this is the place where you would substitute - your branded driver license information - - SQLSetConnectOption(hdbc, 1041, (UDWORD) wxEmptyString); - SQLSetConnectOption(hdbc, 1042, (UDWORD) wxEmptyString); -*/ - - // Mark database as open - dbIsOpen = true; - - // Allocate a statement handle for the database connection - if (SQLAllocStmt(hdbc, &hstmt) != SQL_SUCCESS) - return(DispAllErrors(henv, hdbc)); - - // Set Connection Options - if (!setConnectionOptions()) - return false; - - if (!determineDataTypes(failOnDataTypeUnsupported)) - return false; - -#ifdef DBDEBUG_CONSOLE - cout << wxT("VARCHAR DATA TYPE: ") << typeInfVarchar.TypeName << endl; - cout << wxT("INTEGER DATA TYPE: ") << typeInfInteger.TypeName << endl; - cout << wxT("FLOAT DATA TYPE: ") << typeInfFloat.TypeName << endl; - cout << wxT("DATE DATA TYPE: ") << typeInfDate.TypeName << endl; - cout << wxT("BLOB DATA TYPE: ") << typeInfBlob.TypeName << endl; - cout << wxT("MEMO DATA TYPE: ") << typeInfMemo.TypeName << endl; - cout << endl; -#endif - - // Completed Successfully - return true; -} - -bool wxDb::Open(const wxString& inConnectStr, bool failOnDataTypeUnsupported) -{ - wxASSERT(inConnectStr.length()); - return Open(inConnectStr, NULL, failOnDataTypeUnsupported); -} - -bool wxDb::Open(const wxString& inConnectStr, SQLHWND parentWnd, bool failOnDataTypeUnsupported) -{ - dsn = wxEmptyString; - uid = wxEmptyString; - authStr = wxEmptyString; - - RETCODE retcode; - - if (!FwdOnlyCursors()) - { - // Specify that the ODBC cursor library be used, if needed. This must be - // specified before the connection is made. - retcode = SQLSetConnectOption(hdbc, SQL_ODBC_CURSORS, SQL_CUR_USE_IF_NEEDED); - -#ifdef DBDEBUG_CONSOLE - if (retcode == SQL_SUCCESS) - cout << wxT("SQLSetConnectOption(CURSOR_LIB) successful") << endl; - else - cout << wxT("SQLSetConnectOption(CURSOR_LIB) failed") << endl; -#else - wxUnusedVar(retcode); -#endif - } - - // Connect to the data source - SQLTCHAR outConnectBuffer[SQL_MAX_CONNECTSTR_LEN+1]; // MS recommends at least 1k buffer - short outConnectBufferLen; - - inConnectionStr = inConnectStr; - - retcode = SQLDriverConnect(hdbc, parentWnd, (SQLTCHAR FAR *)inConnectionStr.c_str(), - (SWORD)inConnectionStr.length(), (SQLTCHAR FAR *)outConnectBuffer, - WXSIZEOF(outConnectBuffer), &outConnectBufferLen, SQL_DRIVER_COMPLETE ); - - if ((retcode != SQL_SUCCESS) && - (retcode != SQL_SUCCESS_WITH_INFO)) - return(DispAllErrors(henv, hdbc)); - - outConnectBuffer[outConnectBufferLen] = 0; - outConnectionStr = outConnectBuffer; - dbOpenedWithConnectionString = true; - - return open(failOnDataTypeUnsupported); -} - -/********** wxDb::Open() **********/ -bool wxDb::Open(const wxString &Dsn, const wxString &Uid, const wxString &AuthStr, bool failOnDataTypeUnsupported) -{ - wxASSERT(!Dsn.empty()); - dsn = Dsn; - uid = Uid; - authStr = AuthStr; - - inConnectionStr = wxEmptyString; - outConnectionStr = wxEmptyString; - - RETCODE retcode; - - if (!FwdOnlyCursors()) - { - // Specify that the ODBC cursor library be used, if needed. This must be - // specified before the connection is made. - retcode = SQLSetConnectOption(hdbc, SQL_ODBC_CURSORS, SQL_CUR_USE_IF_NEEDED); - -#ifdef DBDEBUG_CONSOLE - if (retcode == SQL_SUCCESS) - cout << wxT("SQLSetConnectOption(CURSOR_LIB) successful") << endl; - else - cout << wxT("SQLSetConnectOption(CURSOR_LIB) failed") << endl; -#else - wxUnusedVar( retcode ); -#endif - } - - // Connect to the data source - retcode = SQLConnect(hdbc, (SQLTCHAR FAR *) dsn.c_str(), SQL_NTS, - (SQLTCHAR FAR *) uid.c_str(), SQL_NTS, - (SQLTCHAR FAR *) authStr.c_str(), SQL_NTS); - - if ((retcode != SQL_SUCCESS) && - (retcode != SQL_SUCCESS_WITH_INFO)) - return(DispAllErrors(henv, hdbc)); - - return open(failOnDataTypeUnsupported); - -} // wxDb::Open() - - -bool wxDb::Open(wxDbConnectInf *dbConnectInf, bool failOnDataTypeUnsupported) -{ - wxASSERT(dbConnectInf); - - // Use the connection string if one is present - if (dbConnectInf->UseConnectionStr()) - return Open(dbConnectInf->GetConnectionStr(), failOnDataTypeUnsupported); - else - return Open(dbConnectInf->GetDsn(), dbConnectInf->GetUserID(), - dbConnectInf->GetPassword(), failOnDataTypeUnsupported); -} // wxDb::Open() - - -bool wxDb::Open(wxDb *copyDb) -{ - dsn = copyDb->GetDatasourceName(); - uid = copyDb->GetUsername(); - authStr = copyDb->GetPassword(); - inConnectionStr = copyDb->GetConnectionInStr(); - outConnectionStr = copyDb->GetConnectionOutStr(); - - RETCODE retcode; - - if (!FwdOnlyCursors()) - { - // Specify that the ODBC cursor library be used, if needed. This must be - // specified before the connection is made. - retcode = SQLSetConnectOption(hdbc, SQL_ODBC_CURSORS, SQL_CUR_USE_IF_NEEDED); - -#ifdef DBDEBUG_CONSOLE - if (retcode == SQL_SUCCESS) - cout << wxT("SQLSetConnectOption(CURSOR_LIB) successful") << endl; - else - cout << wxT("SQLSetConnectOption(CURSOR_LIB) failed") << endl; -#else - wxUnusedVar( retcode ); -#endif - } - - if (copyDb->OpenedWithConnectionString()) - { - // Connect to the data source - SQLTCHAR outConnectBuffer[SQL_MAX_CONNECTSTR_LEN+1]; - short outConnectBufferLen; - - inConnectionStr = copyDb->GetConnectionInStr(); - - retcode = SQLDriverConnect(hdbc, NULL, (SQLTCHAR FAR *)inConnectionStr.c_str(), - (SWORD)inConnectionStr.length(), (SQLTCHAR FAR *)outConnectBuffer, - WXSIZEOF(outConnectBuffer), &outConnectBufferLen, SQL_DRIVER_COMPLETE); - - if ((retcode != SQL_SUCCESS) && - (retcode != SQL_SUCCESS_WITH_INFO)) - return(DispAllErrors(henv, hdbc)); - - outConnectBuffer[outConnectBufferLen] = 0; - outConnectionStr = outConnectBuffer; - dbOpenedWithConnectionString = true; - } - else - { - // Connect to the data source - retcode = SQLConnect(hdbc, (SQLTCHAR FAR *) dsn.c_str(), SQL_NTS, - (SQLTCHAR FAR *) uid.c_str(), SQL_NTS, - (SQLTCHAR FAR *) authStr.c_str(), SQL_NTS); - } - - if ((retcode != SQL_SUCCESS) && - (retcode != SQL_SUCCESS_WITH_INFO)) - return(DispAllErrors(henv, hdbc)); - -/* - If using Intersolv branded ODBC drivers, this is the place where you would substitute - your branded driver license information - - SQLSetConnectOption(hdbc, 1041, (UDWORD) wxEmptyString); - SQLSetConnectOption(hdbc, 1042, (UDWORD) wxEmptyString); -*/ - - // Mark database as open - dbIsOpen = true; - - // Allocate a statement handle for the database connection - if (SQLAllocStmt(hdbc, &hstmt) != SQL_SUCCESS) - return(DispAllErrors(henv, hdbc)); - - // Set Connection Options - if (!setConnectionOptions()) - return false; - - // Instead of Querying the data source for info about itself, it can just be copied - // from the wxDb instance that was passed in (copyDb). - wxStrcpy(dbInf.serverName,copyDb->dbInf.serverName); - wxStrcpy(dbInf.databaseName,copyDb->dbInf.databaseName); - wxStrcpy(dbInf.dbmsName,copyDb->dbInf.dbmsName); - wxStrcpy(dbInf.dbmsVer,copyDb->dbInf.dbmsVer); - dbInf.maxConnections = copyDb->dbInf.maxConnections; - dbInf.maxStmts = copyDb->dbInf.maxStmts; - wxStrcpy(dbInf.driverName,copyDb->dbInf.driverName); - wxStrcpy(dbInf.odbcVer,copyDb->dbInf.odbcVer); - wxStrcpy(dbInf.drvMgrOdbcVer,copyDb->dbInf.drvMgrOdbcVer); - wxStrcpy(dbInf.driverVer,copyDb->dbInf.driverVer); - dbInf.apiConfLvl = copyDb->dbInf.apiConfLvl; - dbInf.cliConfLvl = copyDb->dbInf.cliConfLvl; - dbInf.sqlConfLvl = copyDb->dbInf.sqlConfLvl; - wxStrcpy(dbInf.outerJoins,copyDb->dbInf.outerJoins); - wxStrcpy(dbInf.procedureSupport,copyDb->dbInf.procedureSupport); - wxStrcpy(dbInf.accessibleTables,copyDb->dbInf.accessibleTables); - dbInf.cursorCommitBehavior = copyDb->dbInf.cursorCommitBehavior; - dbInf.cursorRollbackBehavior = copyDb->dbInf.cursorRollbackBehavior; - dbInf.supportNotNullClause = copyDb->dbInf.supportNotNullClause; - wxStrcpy(dbInf.supportIEF,copyDb->dbInf.supportIEF); - dbInf.txnIsolation = copyDb->dbInf.txnIsolation; - dbInf.txnIsolationOptions = copyDb->dbInf.txnIsolationOptions; - dbInf.fetchDirections = copyDb->dbInf.fetchDirections; - dbInf.lockTypes = copyDb->dbInf.lockTypes; - dbInf.posOperations = copyDb->dbInf.posOperations; - dbInf.posStmts = copyDb->dbInf.posStmts; - dbInf.scrollConcurrency = copyDb->dbInf.scrollConcurrency; - dbInf.scrollOptions = copyDb->dbInf.scrollOptions; - dbInf.staticSensitivity = copyDb->dbInf.staticSensitivity; - dbInf.txnCapable = copyDb->dbInf.txnCapable; - dbInf.loginTimeout = copyDb->dbInf.loginTimeout; - - // VARCHAR = Variable length character string - typeInfVarchar.FsqlType = copyDb->typeInfVarchar.FsqlType; - typeInfVarchar.TypeName = copyDb->typeInfVarchar.TypeName; - typeInfVarchar.Precision = copyDb->typeInfVarchar.Precision; - typeInfVarchar.CaseSensitive = copyDb->typeInfVarchar.CaseSensitive; - typeInfVarchar.MaximumScale = copyDb->typeInfVarchar.MaximumScale; - - // Float - typeInfFloat.FsqlType = copyDb->typeInfFloat.FsqlType; - typeInfFloat.TypeName = copyDb->typeInfFloat.TypeName; - typeInfFloat.Precision = copyDb->typeInfFloat.Precision; - typeInfFloat.CaseSensitive = copyDb->typeInfFloat.CaseSensitive; - typeInfFloat.MaximumScale = copyDb->typeInfFloat.MaximumScale; - - // Integer - typeInfInteger.FsqlType = copyDb->typeInfInteger.FsqlType; - typeInfInteger.TypeName = copyDb->typeInfInteger.TypeName; - typeInfInteger.Precision = copyDb->typeInfInteger.Precision; - typeInfInteger.CaseSensitive = copyDb->typeInfInteger.CaseSensitive; - typeInfInteger.MaximumScale = copyDb->typeInfInteger.MaximumScale; - - // Date/Time - typeInfDate.FsqlType = copyDb->typeInfDate.FsqlType; - typeInfDate.TypeName = copyDb->typeInfDate.TypeName; - typeInfDate.Precision = copyDb->typeInfDate.Precision; - typeInfDate.CaseSensitive = copyDb->typeInfDate.CaseSensitive; - typeInfDate.MaximumScale = copyDb->typeInfDate.MaximumScale; - - // Blob - typeInfBlob.FsqlType = copyDb->typeInfBlob.FsqlType; - typeInfBlob.TypeName = copyDb->typeInfBlob.TypeName; - typeInfBlob.Precision = copyDb->typeInfBlob.Precision; - typeInfBlob.CaseSensitive = copyDb->typeInfBlob.CaseSensitive; - typeInfBlob.MaximumScale = copyDb->typeInfBlob.MaximumScale; - - // Memo - typeInfMemo.FsqlType = copyDb->typeInfMemo.FsqlType; - typeInfMemo.TypeName = copyDb->typeInfMemo.TypeName; - typeInfMemo.Precision = copyDb->typeInfMemo.Precision; - typeInfMemo.CaseSensitive = copyDb->typeInfMemo.CaseSensitive; - typeInfMemo.MaximumScale = copyDb->typeInfMemo.MaximumScale; - -#ifdef DBDEBUG_CONSOLE - cout << wxT("VARCHAR DATA TYPE: ") << typeInfVarchar.TypeName << endl; - cout << wxT("INTEGER DATA TYPE: ") << typeInfInteger.TypeName << endl; - cout << wxT("FLOAT DATA TYPE: ") << typeInfFloat.TypeName << endl; - cout << wxT("DATE DATA TYPE: ") << typeInfDate.TypeName << endl; - cout << wxT("BLOB DATA TYPE: ") << typeInfBlob.TypeName << endl; - cout << wxT("MEMO DATA TYPE: ") << typeInfMemo.TypeName << endl; - cout << endl; -#endif - - // Completed Successfully - return true; -} // wxDb::Open() 2 - - -/********** wxDb::setConnectionOptions() **********/ -bool wxDb::setConnectionOptions(void) -/* - * NOTE: The Intersolv/Oracle 7 driver was "Not Capable" of setting the login timeout. - */ -{ - SWORD cb; - - // I need to get the DBMS name here, because some of the connection options - // are database specific and need to call the Dbms() function. - RETCODE retcode; - - retcode = SQLGetInfo(hdbc, SQL_DBMS_NAME, (UCHAR *) dbInf.dbmsName, sizeof(dbInf.dbmsName), &cb); - if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO) - return(DispAllErrors(henv, hdbc)); - - /* retcode = */ SQLSetConnectOption(hdbc, SQL_AUTOCOMMIT, SQL_AUTOCOMMIT_OFF); - /* retcode = */ SQLSetConnectOption(hdbc, SQL_OPT_TRACE, SQL_OPT_TRACE_OFF); -// SQLSetConnectOption(hdbc, SQL_TXN_ISOLATION, SQL_TXN_READ_COMMITTED); // No dirty reads - - // By default, MS Sql Server closes cursors on commit and rollback. The following - // call to SQLSetConnectOption() is needed to force SQL Server to preserve cursors - // after a transaction. This is a driver specific option and is not part of the - // ODBC standard. Note: this behavior is specific to the ODBC interface to SQL Server. - // The database settings don't have any effect one way or the other. - if (Dbms() == dbmsMS_SQL_SERVER) - { - const long SQL_PRESERVE_CURSORS = 1204L; - const long SQL_PC_ON = 1L; - /* retcode = */ SQLSetConnectOption(hdbc, SQL_PRESERVE_CURSORS, SQL_PC_ON); - } - - // Display the connection options to verify them -#ifdef DBDEBUG_CONSOLE - long l; - cout << wxT("****** CONNECTION OPTIONS ******") << endl; - - retcode = SQLGetConnectOption(hdbc, SQL_AUTOCOMMIT, &l); - if (retcode != SQL_SUCCESS) - return(DispAllErrors(henv, hdbc)); - cout << wxT("AUTOCOMMIT: ") << (l == SQL_AUTOCOMMIT_OFF ? "OFF" : "ON") << endl; - - retcode = SQLGetConnectOption(hdbc, SQL_ODBC_CURSORS, &l); - if (retcode != SQL_SUCCESS) - return(DispAllErrors(henv, hdbc)); - cout << wxT("ODBC CURSORS: "); - switch(l) - { - case(SQL_CUR_USE_IF_NEEDED): - cout << wxT("SQL_CUR_USE_IF_NEEDED"); - break; - case(SQL_CUR_USE_ODBC): - cout << wxT("SQL_CUR_USE_ODBC"); - break; - case(SQL_CUR_USE_DRIVER): - cout << wxT("SQL_CUR_USE_DRIVER"); - break; - } - cout << endl; - - retcode = SQLGetConnectOption(hdbc, SQL_OPT_TRACE, &l) - if (retcode != SQL_SUCCESS) - return(DispAllErrors(henv, hdbc)); - cout << wxT("TRACING: ") << (l == SQL_OPT_TRACE_OFF ? wxT("OFF") : wxT("ON")) << endl; - - cout << endl; -#endif - - // Completed Successfully - return true; - -} // wxDb::setConnectionOptions() - - -/********** wxDb::getDbInfo() **********/ -bool wxDb::getDbInfo(bool failOnDataTypeUnsupported) -{ - SWORD cb; - RETCODE retcode; - - retcode = SQLGetInfo(hdbc, SQL_SERVER_NAME, (UCHAR*) dbInf.serverName, sizeof(dbInf.serverName), &cb); - if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO ) - { - DispAllErrors(henv, hdbc); - if (failOnDataTypeUnsupported) - return false; - } - - retcode = SQLGetInfo(hdbc, SQL_DATABASE_NAME, (UCHAR*) dbInf.databaseName, sizeof(dbInf.databaseName), &cb); - if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO ) - { - DispAllErrors(henv, hdbc); - if (failOnDataTypeUnsupported) - return false; - } - - retcode = SQLGetInfo(hdbc, SQL_DBMS_NAME, (UCHAR*) dbInf.dbmsName, sizeof(dbInf.dbmsName), &cb); - if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO ) - { - DispAllErrors(henv, hdbc); - if (failOnDataTypeUnsupported) - return false; - } - - // 16-Mar-1999 - // After upgrading to MSVC6, the original 20 char buffer below was insufficient, - // causing database connectivity to fail in some cases. - retcode = SQLGetInfo(hdbc, SQL_DBMS_VER, (UCHAR*) dbInf.dbmsVer, sizeof(dbInf.dbmsVer), &cb); - if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO ) - { - DispAllErrors(henv, hdbc); - if (failOnDataTypeUnsupported) - return false; - } - - retcode = SQLGetInfo(hdbc, SQL_ACTIVE_CONNECTIONS, (UCHAR*) &dbInf.maxConnections, sizeof(dbInf.maxConnections), &cb); - if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO ) - { - DispAllErrors(henv, hdbc); - if (failOnDataTypeUnsupported) - return false; - } - - retcode = SQLGetInfo(hdbc, SQL_ACTIVE_STATEMENTS, (UCHAR*) &dbInf.maxStmts, sizeof(dbInf.maxStmts), &cb); - if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO ) - { - DispAllErrors(henv, hdbc); - if (failOnDataTypeUnsupported) - return false; - } - - retcode = SQLGetInfo(hdbc, SQL_DRIVER_NAME, (UCHAR*) dbInf.driverName, sizeof(dbInf.driverName), &cb); - if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO ) - { - DispAllErrors(henv, hdbc); - if (failOnDataTypeUnsupported) - return false; - } - - retcode = SQLGetInfo(hdbc, SQL_DRIVER_ODBC_VER, (UCHAR*) dbInf.odbcVer, sizeof(dbInf.odbcVer), &cb); - if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO ) - { - DispAllErrors(henv, hdbc); - if (failOnDataTypeUnsupported) - return false; - } - - retcode = SQLGetInfo(hdbc, SQL_ODBC_VER, (UCHAR*) dbInf.drvMgrOdbcVer, sizeof(dbInf.drvMgrOdbcVer), &cb); - if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO) - { - DispAllErrors(henv, hdbc); - if (failOnDataTypeUnsupported) - return false; - } - - retcode = SQLGetInfo(hdbc, SQL_DRIVER_VER, (UCHAR*) dbInf.driverVer, sizeof(dbInf.driverVer), &cb); - if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO ) - { - DispAllErrors(henv, hdbc); - if (failOnDataTypeUnsupported) - return false; - } - - retcode = SQLGetInfo(hdbc, SQL_ODBC_API_CONFORMANCE, (UCHAR*) &dbInf.apiConfLvl, sizeof(dbInf.apiConfLvl), &cb); - if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO ) - { - DispAllErrors(henv, hdbc); - if (failOnDataTypeUnsupported) - return false; - } - - retcode = SQLGetInfo(hdbc, SQL_ODBC_SAG_CLI_CONFORMANCE, (UCHAR*) &dbInf.cliConfLvl, sizeof(dbInf.cliConfLvl), &cb); - if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO ) - { - // Not all drivers support this call - Nick Gorham(unixODBC) - dbInf.cliConfLvl = 0; - DispAllErrors(henv, hdbc); - if (failOnDataTypeUnsupported) - return false; - } - - retcode = SQLGetInfo(hdbc, SQL_ODBC_SQL_CONFORMANCE, (UCHAR*) &dbInf.sqlConfLvl, sizeof(dbInf.sqlConfLvl), &cb); - if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO ) - { - DispAllErrors(henv, hdbc); - if (failOnDataTypeUnsupported) - return false; - } - - retcode = SQLGetInfo(hdbc, SQL_OUTER_JOINS, (UCHAR*) dbInf.outerJoins, sizeof(dbInf.outerJoins), &cb); - if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO ) - { - DispAllErrors(henv, hdbc); - if (failOnDataTypeUnsupported) - return false; - } - - retcode = SQLGetInfo(hdbc, SQL_PROCEDURES, (UCHAR*) dbInf.procedureSupport, sizeof(dbInf.procedureSupport), &cb); - if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO ) - { - DispAllErrors(henv, hdbc); - if (failOnDataTypeUnsupported) - return false; - } - - retcode = SQLGetInfo(hdbc, SQL_ACCESSIBLE_TABLES, (UCHAR*) dbInf.accessibleTables, sizeof(dbInf.accessibleTables), &cb); - if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO ) - { - DispAllErrors(henv, hdbc); - if (failOnDataTypeUnsupported) - return false; - } - - retcode = SQLGetInfo(hdbc, SQL_CURSOR_COMMIT_BEHAVIOR, (UCHAR*) &dbInf.cursorCommitBehavior, sizeof(dbInf.cursorCommitBehavior), &cb); - if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO ) - { - DispAllErrors(henv, hdbc); - if (failOnDataTypeUnsupported) - return false; - } - - retcode = SQLGetInfo(hdbc, SQL_CURSOR_ROLLBACK_BEHAVIOR, (UCHAR*) &dbInf.cursorRollbackBehavior, sizeof(dbInf.cursorRollbackBehavior), &cb); - if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO ) - { - DispAllErrors(henv, hdbc); - if (failOnDataTypeUnsupported) - return false; - } - - retcode = SQLGetInfo(hdbc, SQL_NON_NULLABLE_COLUMNS, (UCHAR*) &dbInf.supportNotNullClause, sizeof(dbInf.supportNotNullClause), &cb); - if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO ) - { - DispAllErrors(henv, hdbc); - if (failOnDataTypeUnsupported) - return false; - } - - retcode = SQLGetInfo(hdbc, SQL_ODBC_SQL_OPT_IEF, (UCHAR*) dbInf.supportIEF, sizeof(dbInf.supportIEF), &cb); - if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO ) - { - DispAllErrors(henv, hdbc); - if (failOnDataTypeUnsupported) - return false; - } - - retcode = SQLGetInfo(hdbc, SQL_DEFAULT_TXN_ISOLATION, (UCHAR*) &dbInf.txnIsolation, sizeof(dbInf.txnIsolation), &cb); - if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO ) - { - DispAllErrors(henv, hdbc); - if (failOnDataTypeUnsupported) - return false; - } - - retcode = SQLGetInfo(hdbc, SQL_TXN_ISOLATION_OPTION, (UCHAR*) &dbInf.txnIsolationOptions, sizeof(dbInf.txnIsolationOptions), &cb); - if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO ) - { - DispAllErrors(henv, hdbc); - if (failOnDataTypeUnsupported) - return false; - } - - retcode = SQLGetInfo(hdbc, SQL_FETCH_DIRECTION, (UCHAR*) &dbInf.fetchDirections, sizeof(dbInf.fetchDirections), &cb); - if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO ) - { - DispAllErrors(henv, hdbc); - if (failOnDataTypeUnsupported) - return false; - } - - retcode = SQLGetInfo(hdbc, SQL_LOCK_TYPES, (UCHAR*) &dbInf.lockTypes, sizeof(dbInf.lockTypes), &cb); - if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO ) - { - DispAllErrors(henv, hdbc); - if (failOnDataTypeUnsupported) - return false; - } - - retcode = SQLGetInfo(hdbc, SQL_POS_OPERATIONS, (UCHAR*) &dbInf.posOperations, sizeof(dbInf.posOperations), &cb); - if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO ) - { - DispAllErrors(henv, hdbc); - if (failOnDataTypeUnsupported) - return false; - } - - retcode = SQLGetInfo(hdbc, SQL_POSITIONED_STATEMENTS, (UCHAR*) &dbInf.posStmts, sizeof(dbInf.posStmts), &cb); - if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO ) - { - DispAllErrors(henv, hdbc); - if (failOnDataTypeUnsupported) - return false; - } - - retcode = SQLGetInfo(hdbc, SQL_SCROLL_CONCURRENCY, (UCHAR*) &dbInf.scrollConcurrency, sizeof(dbInf.scrollConcurrency), &cb); - if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO ) - { - DispAllErrors(henv, hdbc); - if (failOnDataTypeUnsupported) - return false; - } - - retcode = SQLGetInfo(hdbc, SQL_SCROLL_OPTIONS, (UCHAR*) &dbInf.scrollOptions, sizeof(dbInf.scrollOptions), &cb); - if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO ) - { - DispAllErrors(henv, hdbc); - if (failOnDataTypeUnsupported) - return false; - } - - retcode = SQLGetInfo(hdbc, SQL_STATIC_SENSITIVITY, (UCHAR*) &dbInf.staticSensitivity, sizeof(dbInf.staticSensitivity), &cb); - if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO ) - { - DispAllErrors(henv, hdbc); - if (failOnDataTypeUnsupported) - return false; - } - - retcode = SQLGetInfo(hdbc, SQL_TXN_CAPABLE, (UCHAR*) &dbInf.txnCapable, sizeof(dbInf.txnCapable), &cb); - if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO ) - { - DispAllErrors(henv, hdbc); - if (failOnDataTypeUnsupported) - return false; - } - - retcode = SQLGetInfo(hdbc, SQL_LOGIN_TIMEOUT, (UCHAR*) &dbInf.loginTimeout, sizeof(dbInf.loginTimeout), &cb); - if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO ) - { - DispAllErrors(henv, hdbc); - if (failOnDataTypeUnsupported) - return false; - } - -#ifdef DBDEBUG_CONSOLE - cout << wxT("***** DATA SOURCE INFORMATION *****") << endl; - cout << wxT(wxT("SERVER Name: ") << dbInf.serverName << endl; - cout << wxT("DBMS Name: ") << dbInf.dbmsName << wxT("; DBMS Version: ") << dbInf.dbmsVer << endl; - cout << wxT("ODBC Version: ") << dbInf.odbcVer << wxT("; Driver Version: ") << dbInf.driverVer << endl; - - cout << wxT("API Conf. Level: "); - switch(dbInf.apiConfLvl) - { - case SQL_OAC_NONE: cout << wxT("None"); break; - case SQL_OAC_LEVEL1: cout << wxT("Level 1"); break; - case SQL_OAC_LEVEL2: cout << wxT("Level 2"); break; - } - cout << endl; - - cout << wxT("SAG CLI Conf. Level: "); - switch(dbInf.cliConfLvl) - { - case SQL_OSCC_NOT_COMPLIANT: cout << wxT("Not Compliant"); break; - case SQL_OSCC_COMPLIANT: cout << wxT("Compliant"); break; - } - cout << endl; - - cout << wxT("SQL Conf. Level: "); - switch(dbInf.sqlConfLvl) - { - case SQL_OSC_MINIMUM: cout << wxT("Minimum Grammar"); break; - case SQL_OSC_CORE: cout << wxT("Core Grammar"); break; - case SQL_OSC_EXTENDED: cout << wxT("Extended Grammar"); break; - } - cout << endl; - - cout << wxT("Max. Connections: ") << dbInf.maxConnections << endl; - cout << wxT("Outer Joins: ") << dbInf.outerJoins << endl; - cout << wxT("Support for Procedures: ") << dbInf.procedureSupport << endl; - cout << wxT("All tables accessible : ") << dbInf.accessibleTables << endl; - cout << wxT("Cursor COMMIT Behavior: "); - switch(dbInf.cursorCommitBehavior) - { - case SQL_CB_DELETE: cout << wxT("Delete cursors"); break; - case SQL_CB_CLOSE: cout << wxT("Close cursors"); break; - case SQL_CB_PRESERVE: cout << wxT("Preserve cursors"); break; - } - cout << endl; - - cout << wxT("Cursor ROLLBACK Behavior: "); - switch(dbInf.cursorRollbackBehavior) - { - case SQL_CB_DELETE: cout << wxT("Delete cursors"); break; - case SQL_CB_CLOSE: cout << wxT("Close cursors"); break; - case SQL_CB_PRESERVE: cout << wxT("Preserve cursors"); break; - } - cout << endl; - - cout << wxT("Support NOT NULL clause: "); - switch(dbInf.supportNotNullClause) - { - case SQL_NNC_NULL: cout << wxT("No"); break; - case SQL_NNC_NON_NULL: cout << wxT("Yes"); break; - } - cout << endl; - - cout << wxT("Support IEF (Ref. Integrity): ") << dbInf.supportIEF << endl; - cout << wxT("Login Timeout: ") << dbInf.loginTimeout << endl; - - cout << endl << endl << wxT("more ...") << endl; - getchar(); - - cout << wxT("Default Transaction Isolation: "; - switch(dbInf.txnIsolation) - { - case SQL_TXN_READ_UNCOMMITTED: cout << wxT("Read Uncommitted"); break; - case SQL_TXN_READ_COMMITTED: cout << wxT("Read Committed"); break; - case SQL_TXN_REPEATABLE_READ: cout << wxT("Repeatable Read"); break; - case SQL_TXN_SERIALIZABLE: cout << wxT("Serializable"); break; -#ifdef ODBC_V20 - case SQL_TXN_VERSIONING: cout << wxT("Versioning"); break; -#endif - } - cout << endl; - - cout << wxT("Transaction Isolation Options: "); - if (dbInf.txnIsolationOptions & SQL_TXN_READ_UNCOMMITTED) - cout << wxT("Read Uncommitted, "); - if (dbInf.txnIsolationOptions & SQL_TXN_READ_COMMITTED) - cout << wxT("Read Committed, "); - if (dbInf.txnIsolationOptions & SQL_TXN_REPEATABLE_READ) - cout << wxT("Repeatable Read, "); - if (dbInf.txnIsolationOptions & SQL_TXN_SERIALIZABLE) - cout << wxT("Serializable, "); -#ifdef ODBC_V20 - if (dbInf.txnIsolationOptions & SQL_TXN_VERSIONING) - cout << wxT("Versioning"); -#endif - cout << endl; - - cout << wxT("Fetch Directions Supported:") << endl << wxT(" "); - if (dbInf.fetchDirections & SQL_FD_FETCH_NEXT) - cout << wxT("Next, "); - if (dbInf.fetchDirections & SQL_FD_FETCH_PRIOR) - cout << wxT("Prev, "); - if (dbInf.fetchDirections & SQL_FD_FETCH_FIRST) - cout << wxT("First, "); - if (dbInf.fetchDirections & SQL_FD_FETCH_LAST) - cout << wxT("Last, "); - if (dbInf.fetchDirections & SQL_FD_FETCH_ABSOLUTE) - cout << wxT("Absolute, "); - if (dbInf.fetchDirections & SQL_FD_FETCH_RELATIVE) - cout << wxT("Relative, "); -#ifdef ODBC_V20 - if (dbInf.fetchDirections & SQL_FD_FETCH_RESUME) - cout << wxT("Resume, "); -#endif - if (dbInf.fetchDirections & SQL_FD_FETCH_BOOKMARK) - cout << wxT("Bookmark"); - cout << endl; - - cout << wxT("Lock Types Supported (SQLSetPos): "); - if (dbInf.lockTypes & SQL_LCK_NO_CHANGE) - cout << wxT("No Change, "); - if (dbInf.lockTypes & SQL_LCK_EXCLUSIVE) - cout << wxT("Exclusive, "); - if (dbInf.lockTypes & SQL_LCK_UNLOCK) - cout << wxT("UnLock"); - cout << endl; - - cout << wxT("Position Operations Supported (SQLSetPos): "); - if (dbInf.posOperations & SQL_POS_POSITION) - cout << wxT("Position, "); - if (dbInf.posOperations & SQL_POS_REFRESH) - cout << wxT("Refresh, "); - if (dbInf.posOperations & SQL_POS_UPDATE) - cout << wxT("Upd, ")); - if (dbInf.posOperations & SQL_POS_DELETE) - cout << wxT("Del, "); - if (dbInf.posOperations & SQL_POS_ADD) - cout << wxT("Add"); - cout << endl; - - cout << wxT("Positioned Statements Supported: "); - if (dbInf.posStmts & SQL_PS_POSITIONED_DELETE) - cout << wxT("Pos delete, "); - if (dbInf.posStmts & SQL_PS_POSITIONED_UPDATE) - cout << wxT("Pos update, "); - if (dbInf.posStmts & SQL_PS_SELECT_FOR_UPDATE) - cout << wxT("Select for update"); - cout << endl; - - cout << wxT("Scroll Concurrency: "); - if (dbInf.scrollConcurrency & SQL_SCCO_READ_ONLY) - cout << wxT("Read Only, "); - if (dbInf.scrollConcurrency & SQL_SCCO_LOCK) - cout << wxT("Lock, "); - if (dbInf.scrollConcurrency & SQL_SCCO_OPT_ROWVER) - cout << wxT("Opt. Rowver, "); - if (dbInf.scrollConcurrency & SQL_SCCO_OPT_VALUES) - cout << wxT("Opt. Values"); - cout << endl; - - cout << wxT("Scroll Options: "); - if (dbInf.scrollOptions & SQL_SO_FORWARD_ONLY) - cout << wxT("Fwd Only, "); - if (dbInf.scrollOptions & SQL_SO_STATIC) - cout << wxT("Static, "); - if (dbInf.scrollOptions & SQL_SO_KEYSET_DRIVEN) - cout << wxT("Keyset Driven, "); - if (dbInf.scrollOptions & SQL_SO_DYNAMIC) - cout << wxT("Dynamic, "); - if (dbInf.scrollOptions & SQL_SO_MIXED) - cout << wxT("Mixed"); - cout << endl; - - cout << wxT("Static Sensitivity: "); - if (dbInf.staticSensitivity & SQL_SS_ADDITIONS) - cout << wxT("Additions, "); - if (dbInf.staticSensitivity & SQL_SS_DELETIONS) - cout << wxT("Deletions, "); - if (dbInf.staticSensitivity & SQL_SS_UPDATES) - cout << wxT("Updates"); - cout << endl; - - cout << wxT("Transaction Capable?: "); - switch(dbInf.txnCapable) - { - case SQL_TC_NONE: cout << wxT("No"); break; - case SQL_TC_DML: cout << wxT("DML Only"); break; - case SQL_TC_DDL_COMMIT: cout << wxT("DDL Commit"); break; - case SQL_TC_DDL_IGNORE: cout << wxT("DDL Ignore"); break; - case SQL_TC_ALL: cout << wxT("DDL & DML"); break; - } - cout << endl; - - cout << endl; -#endif - - // Completed Successfully - return true; - -} // wxDb::getDbInfo() - - -/********** wxDb::getDataTypeInfo() **********/ -bool wxDb::getDataTypeInfo(SWORD fSqlType, wxDbSqlTypeInfo &structSQLTypeInfo) -{ -/* - * fSqlType will be something like SQL_VARCHAR. This parameter determines - * the data type inf. is gathered for. - * - * wxDbSqlTypeInfo is a structure that is filled in with data type information, - */ - RETCODE retcode; - SQLLEN cbRet; - - // Get information about the data type specified - if (SQLGetTypeInfo(hstmt, fSqlType) != SQL_SUCCESS) - return(DispAllErrors(henv, hdbc, hstmt)); - - // Fetch the record - retcode = SQLFetch(hstmt); - if (retcode != SQL_SUCCESS) - { -#ifdef DBDEBUG_CONSOLE - if (retcode == SQL_NO_DATA_FOUND) - cout << wxT("SQL_NO_DATA_FOUND fetching information about data type.") << endl; -#endif - DispAllErrors(henv, hdbc, hstmt); - SQLFreeStmt(hstmt, SQL_CLOSE); - return false; - } - - wxChar typeName[DB_TYPE_NAME_LEN+1]; - - // Obtain columns from the record - if (SQLGetData(hstmt, 1, SQL_C_WXCHAR, typeName, sizeof(typeName), &cbRet) != SQL_SUCCESS) - return(DispAllErrors(henv, hdbc, hstmt)); - - structSQLTypeInfo.TypeName = typeName; - - // BJO 20000503: no more needed with new GetColumns... -#if OLD_GETCOLUMNS - // BJO 991209 - if (Dbms() == dbmsMY_SQL) - { - if (structSQLTypeInfo.TypeName == wxT("middleint")) - structSQLTypeInfo.TypeName = wxT("mediumint"); - else if (structSQLTypeInfo.TypeName == wxT("middleint unsigned")) - structSQLTypeInfo.TypeName = wxT("mediumint unsigned"); - else if (structSQLTypeInfo.TypeName == wxT("integer")) - structSQLTypeInfo.TypeName = wxT("int"); - else if (structSQLTypeInfo.TypeName == wxT("integer unsigned")) - structSQLTypeInfo.TypeName = wxT("int unsigned"); - else if (structSQLTypeInfo.TypeName == wxT("middleint")) - structSQLTypeInfo.TypeName = wxT("mediumint"); - else if (structSQLTypeInfo.TypeName == wxT("varchar")) - structSQLTypeInfo.TypeName = wxT("char"); - } - - // BJO 20000427 : OpenLink driver - if (!wxStrncmp(dbInf.driverName, wxT("oplodbc"), 7) || - !wxStrncmp(dbInf.driverName, wxT("OLOD"), 4)) - { - if (structSQLTypeInfo.TypeName == wxT("double precision")) - structSQLTypeInfo.TypeName = wxT("real"); - } -#endif - - if (SQLGetData(hstmt, 3, SQL_C_LONG, (UCHAR*) &structSQLTypeInfo.Precision, 0, &cbRet) != SQL_SUCCESS) - return(DispAllErrors(henv, hdbc, hstmt)); - if (SQLGetData(hstmt, 8, SQL_C_SHORT, (UCHAR*) &structSQLTypeInfo.CaseSensitive, 0, &cbRet) != SQL_SUCCESS) - return(DispAllErrors(henv, hdbc, hstmt)); -// if (SQLGetData(hstmt, 14, SQL_C_SHORT, (UCHAR*) &structSQLTypeInfo.MinimumScale, 0, &cbRet) != SQL_SUCCESS) -// return(DispAllErrors(henv, hdbc, hstmt)); - - if (SQLGetData(hstmt, 15, SQL_C_SHORT,(UCHAR*) &structSQLTypeInfo.MaximumScale, 0, &cbRet) != SQL_SUCCESS) - return(DispAllErrors(henv, hdbc, hstmt)); - - if (structSQLTypeInfo.MaximumScale < 0) - structSQLTypeInfo.MaximumScale = 0; - - // Close the statement handle which closes open cursors - if (SQLFreeStmt(hstmt, SQL_CLOSE) != SQL_SUCCESS) - return(DispAllErrors(henv, hdbc, hstmt)); - - // Completed Successfully - return true; - -} // wxDb::getDataTypeInfo() - - -/********** wxDb::Close() **********/ -void wxDb::Close(void) -{ - // Close the Sql Log file - if (fpSqlLog) - { - fclose(fpSqlLog); - fpSqlLog = 0; - } - - // Free statement handle - if (dbIsOpen) - { - if (SQLFreeStmt(hstmt, SQL_DROP) != SQL_SUCCESS) - DispAllErrors(henv, hdbc); - } - - // Disconnect from the datasource - if (SQLDisconnect(hdbc) != SQL_SUCCESS) - DispAllErrors(henv, hdbc); - - // Free the connection to the datasource - if (SQLFreeConnect(hdbc) != SQL_SUCCESS) - DispAllErrors(henv, hdbc); - - // There should be zero Ctable objects still connected to this db object - wxASSERT(nTables == 0); - -#ifdef __WXDEBUG__ - { -#if wxUSE_THREADS - wxCriticalSectionLocker lock(csTablesInUse); -#endif // wxUSE_THREADS - wxTablesInUse *tiu; - wxList::compatibility_iterator pNode; - pNode = TablesInUse.GetFirst(); - wxString s,s2; - while (pNode) - { - tiu = (wxTablesInUse *)pNode->GetData(); - if (tiu->pDb == this) - { - s.Printf(wxT("(%-20s) tableID:[%6lu] pDb:[%p]"), - tiu->tableName, tiu->tableID, wx_static_cast(void*, tiu->pDb)); - s2.Printf(wxT("Orphaned table found using pDb:[%p]"), wx_static_cast(void*, this)); - wxLogDebug(s.c_str(),s2.c_str()); - } - pNode = pNode->GetNext(); - } - } -#endif - - // Copy the error messages to a global variable - int i; - for (i = 0; i < DB_MAX_ERROR_HISTORY; i++) - wxStrcpy(DBerrorList[i], errorList[i]); - - dbmsType = dbmsUNIDENTIFIED; - dbIsOpen = false; - -} // wxDb::Close() - - -/********** wxDb::CommitTrans() **********/ -bool wxDb::CommitTrans(void) -{ - if (this) - { - // Commit the transaction - if (SQLTransact(henv, hdbc, SQL_COMMIT) != SQL_SUCCESS) - return(DispAllErrors(henv, hdbc)); - } - - // Completed successfully - return true; - -} // wxDb::CommitTrans() - - -/********** wxDb::RollbackTrans() **********/ -bool wxDb::RollbackTrans(void) -{ - // Rollback the transaction - if (SQLTransact(henv, hdbc, SQL_ROLLBACK) != SQL_SUCCESS) - return(DispAllErrors(henv, hdbc)); - - // Completed successfully - return true; - -} // wxDb::RollbackTrans() - - -/********** wxDb::DispAllErrors() **********/ -bool wxDb::DispAllErrors(HENV aHenv, HDBC aHdbc, HSTMT aHstmt) -/* - * This function is called internally whenever an error condition prevents the user's - * request from being executed. This function will query the datasource as to the - * actual error(s) that just occurred on the previous request of the datasource. - * - * The function will retrieve each error condition from the datasource and - * Printf the codes/text values into a string which it then logs via logError(). - * If in DBDEBUG_CONSOLE mode, the constructed string will be displayed in the console - * window and program execution will be paused until the user presses a key. - * - * This function always returns false, so that functions which call this function - * can have a line like "return (DispAllErrors(henv, hdbc));" to indicate the failure - * of the user's request, so that the calling code can then process the error message log. - */ -{ - wxString odbcErrMsg; - - while (SQLError(aHenv, aHdbc, aHstmt, (SQLTCHAR FAR *) sqlState, &nativeError, (SQLTCHAR FAR *) errorMsg, SQL_MAX_MESSAGE_LENGTH - 1, &cbErrorMsg) == SQL_SUCCESS) - { - odbcErrMsg.Printf(wxT("SQL State = %s\nNative Error Code = %li\nError Message = %s\n"), - sqlState, (long)nativeError, errorMsg); - logError(odbcErrMsg, sqlState); - if (!silent) - { -#ifdef DBDEBUG_CONSOLE - // When run in console mode, use standard out to display errors. - cout << odbcErrMsg.c_str() << endl; - cout << wxT("Press any key to continue...") << endl; - getchar(); -#endif - -#ifdef __WXDEBUG__ - wxLogDebug(odbcErrMsg,wxT("ODBC DEBUG MESSAGE from DispAllErrors()")); -#endif - } - } - - return false; // This function always returns false. - -} // wxDb::DispAllErrors() - - -/********** wxDb::GetNextError() **********/ -bool wxDb::GetNextError(HENV aHenv, HDBC aHdbc, HSTMT aHstmt) -{ - if (SQLError(aHenv, aHdbc, aHstmt, (SQLTCHAR FAR *) sqlState, &nativeError, (SQLTCHAR FAR *) errorMsg, SQL_MAX_MESSAGE_LENGTH - 1, &cbErrorMsg) == SQL_SUCCESS) - return true; - else - return false; - -} // wxDb::GetNextError() - - -/********** wxDb::DispNextError() **********/ -void wxDb::DispNextError(void) -{ - wxString odbcErrMsg; - - odbcErrMsg.Printf(wxT("SQL State = %s\nNative Error Code = %li\nError Message = %s\n"), - sqlState, (long)nativeError, errorMsg); - logError(odbcErrMsg, sqlState); - - if (silent) - return; - -#ifdef DBDEBUG_CONSOLE - // When run in console mode, use standard out to display errors. - cout << odbcErrMsg.c_str() << endl; - cout << wxT("Press any key to continue...") << endl; - getchar(); -#endif - -#ifdef __WXDEBUG__ - wxLogDebug(odbcErrMsg,wxT("ODBC DEBUG MESSAGE")); -#endif // __WXDEBUG__ - -} // wxDb::DispNextError() - - -/********** wxDb::logError() **********/ -void wxDb::logError(const wxString &errMsg, const wxString &SQLState) -{ - wxASSERT(errMsg.length()); - - static int pLast = -1; - int dbStatus; - - if (++pLast == DB_MAX_ERROR_HISTORY) - { - int i; - for (i = 0; i < DB_MAX_ERROR_HISTORY-1; i++) - wxStrcpy(errorList[i], errorList[i+1]); - pLast--; - } - - wxStrncpy(errorList[pLast], errMsg, DB_MAX_ERROR_MSG_LEN); - errorList[pLast][DB_MAX_ERROR_MSG_LEN-1] = 0; - - if (SQLState.length()) - if ((dbStatus = TranslateSqlState(SQLState)) != DB_ERR_FUNCTION_SEQUENCE_ERROR) - DB_STATUS = dbStatus; - - // Add the errmsg to the sql log - WriteSqlLog(errMsg); - -} // wxDb::logError() - - -/**********wxDb::TranslateSqlState() **********/ -int wxDb::TranslateSqlState(const wxString &SQLState) -{ - if (!wxStrcmp(SQLState, wxT("01000"))) - return(DB_ERR_GENERAL_WARNING); - if (!wxStrcmp(SQLState, wxT("01002"))) - return(DB_ERR_DISCONNECT_ERROR); - if (!wxStrcmp(SQLState, wxT("01004"))) - return(DB_ERR_DATA_TRUNCATED); - if (!wxStrcmp(SQLState, wxT("01006"))) - return(DB_ERR_PRIV_NOT_REVOKED); - if (!wxStrcmp(SQLState, wxT("01S00"))) - return(DB_ERR_INVALID_CONN_STR_ATTR); - if (!wxStrcmp(SQLState, wxT("01S01"))) - return(DB_ERR_ERROR_IN_ROW); - if (!wxStrcmp(SQLState, wxT("01S02"))) - return(DB_ERR_OPTION_VALUE_CHANGED); - if (!wxStrcmp(SQLState, wxT("01S03"))) - return(DB_ERR_NO_ROWS_UPD_OR_DEL); - if (!wxStrcmp(SQLState, wxT("01S04"))) - return(DB_ERR_MULTI_ROWS_UPD_OR_DEL); - if (!wxStrcmp(SQLState, wxT("07001"))) - return(DB_ERR_WRONG_NO_OF_PARAMS); - if (!wxStrcmp(SQLState, wxT("07006"))) - return(DB_ERR_DATA_TYPE_ATTR_VIOL); - if (!wxStrcmp(SQLState, wxT("08001"))) - return(DB_ERR_UNABLE_TO_CONNECT); - if (!wxStrcmp(SQLState, wxT("08002"))) - return(DB_ERR_CONNECTION_IN_USE); - if (!wxStrcmp(SQLState, wxT("08003"))) - return(DB_ERR_CONNECTION_NOT_OPEN); - if (!wxStrcmp(SQLState, wxT("08004"))) - return(DB_ERR_REJECTED_CONNECTION); - if (!wxStrcmp(SQLState, wxT("08007"))) - return(DB_ERR_CONN_FAIL_IN_TRANS); - if (!wxStrcmp(SQLState, wxT("08S01"))) - return(DB_ERR_COMM_LINK_FAILURE); - if (!wxStrcmp(SQLState, wxT("21S01"))) - return(DB_ERR_INSERT_VALUE_LIST_MISMATCH); - if (!wxStrcmp(SQLState, wxT("21S02"))) - return(DB_ERR_DERIVED_TABLE_MISMATCH); - if (!wxStrcmp(SQLState, wxT("22001"))) - return(DB_ERR_STRING_RIGHT_TRUNC); - if (!wxStrcmp(SQLState, wxT("22003"))) - return(DB_ERR_NUMERIC_VALUE_OUT_OF_RNG); - if (!wxStrcmp(SQLState, wxT("22005"))) - return(DB_ERR_ERROR_IN_ASSIGNMENT); - if (!wxStrcmp(SQLState, wxT("22008"))) - return(DB_ERR_DATETIME_FLD_OVERFLOW); - if (!wxStrcmp(SQLState, wxT("22012"))) - return(DB_ERR_DIVIDE_BY_ZERO); - if (!wxStrcmp(SQLState, wxT("22026"))) - return(DB_ERR_STR_DATA_LENGTH_MISMATCH); - if (!wxStrcmp(SQLState, wxT("23000"))) - return(DB_ERR_INTEGRITY_CONSTRAINT_VIOL); - if (!wxStrcmp(SQLState, wxT("24000"))) - return(DB_ERR_INVALID_CURSOR_STATE); - if (!wxStrcmp(SQLState, wxT("25000"))) - return(DB_ERR_INVALID_TRANS_STATE); - if (!wxStrcmp(SQLState, wxT("28000"))) - return(DB_ERR_INVALID_AUTH_SPEC); - if (!wxStrcmp(SQLState, wxT("34000"))) - return(DB_ERR_INVALID_CURSOR_NAME); - if (!wxStrcmp(SQLState, wxT("37000"))) - return(DB_ERR_SYNTAX_ERROR_OR_ACCESS_VIOL); - if (!wxStrcmp(SQLState, wxT("3C000"))) - return(DB_ERR_DUPLICATE_CURSOR_NAME); - if (!wxStrcmp(SQLState, wxT("40001"))) - return(DB_ERR_SERIALIZATION_FAILURE); - if (!wxStrcmp(SQLState, wxT("42000"))) - return(DB_ERR_SYNTAX_ERROR_OR_ACCESS_VIOL2); - if (!wxStrcmp(SQLState, wxT("70100"))) - return(DB_ERR_OPERATION_ABORTED); - if (!wxStrcmp(SQLState, wxT("IM001"))) - return(DB_ERR_UNSUPPORTED_FUNCTION); - if (!wxStrcmp(SQLState, wxT("IM002"))) - return(DB_ERR_NO_DATA_SOURCE); - if (!wxStrcmp(SQLState, wxT("IM003"))) - return(DB_ERR_DRIVER_LOAD_ERROR); - if (!wxStrcmp(SQLState, wxT("IM004"))) - return(DB_ERR_SQLALLOCENV_FAILED); - if (!wxStrcmp(SQLState, wxT("IM005"))) - return(DB_ERR_SQLALLOCCONNECT_FAILED); - if (!wxStrcmp(SQLState, wxT("IM006"))) - return(DB_ERR_SQLSETCONNECTOPTION_FAILED); - if (!wxStrcmp(SQLState, wxT("IM007"))) - return(DB_ERR_NO_DATA_SOURCE_DLG_PROHIB); - if (!wxStrcmp(SQLState, wxT("IM008"))) - return(DB_ERR_DIALOG_FAILED); - if (!wxStrcmp(SQLState, wxT("IM009"))) - return(DB_ERR_UNABLE_TO_LOAD_TRANSLATION_DLL); - if (!wxStrcmp(SQLState, wxT("IM010"))) - return(DB_ERR_DATA_SOURCE_NAME_TOO_LONG); - if (!wxStrcmp(SQLState, wxT("IM011"))) - return(DB_ERR_DRIVER_NAME_TOO_LONG); - if (!wxStrcmp(SQLState, wxT("IM012"))) - return(DB_ERR_DRIVER_KEYWORD_SYNTAX_ERROR); - if (!wxStrcmp(SQLState, wxT("IM013"))) - return(DB_ERR_TRACE_FILE_ERROR); - if (!wxStrcmp(SQLState, wxT("S0001"))) - return(DB_ERR_TABLE_OR_VIEW_ALREADY_EXISTS); - if (!wxStrcmp(SQLState, wxT("S0002"))) - return(DB_ERR_TABLE_NOT_FOUND); - if (!wxStrcmp(SQLState, wxT("S0011"))) - return(DB_ERR_INDEX_ALREADY_EXISTS); - if (!wxStrcmp(SQLState, wxT("S0012"))) - return(DB_ERR_INDEX_NOT_FOUND); - if (!wxStrcmp(SQLState, wxT("S0021"))) - return(DB_ERR_COLUMN_ALREADY_EXISTS); - if (!wxStrcmp(SQLState, wxT("S0022"))) - return(DB_ERR_COLUMN_NOT_FOUND); - if (!wxStrcmp(SQLState, wxT("S0023"))) - return(DB_ERR_NO_DEFAULT_FOR_COLUMN); - if (!wxStrcmp(SQLState, wxT("S1000"))) - return(DB_ERR_GENERAL_ERROR); - if (!wxStrcmp(SQLState, wxT("S1001"))) - return(DB_ERR_MEMORY_ALLOCATION_FAILURE); - if (!wxStrcmp(SQLState, wxT("S1002"))) - return(DB_ERR_INVALID_COLUMN_NUMBER); - if (!wxStrcmp(SQLState, wxT("S1003"))) - return(DB_ERR_PROGRAM_TYPE_OUT_OF_RANGE); - if (!wxStrcmp(SQLState, wxT("S1004"))) - return(DB_ERR_SQL_DATA_TYPE_OUT_OF_RANGE); - if (!wxStrcmp(SQLState, wxT("S1008"))) - return(DB_ERR_OPERATION_CANCELLED); - if (!wxStrcmp(SQLState, wxT("S1009"))) - return(DB_ERR_INVALID_ARGUMENT_VALUE); - if (!wxStrcmp(SQLState, wxT("S1010"))) - return(DB_ERR_FUNCTION_SEQUENCE_ERROR); - if (!wxStrcmp(SQLState, wxT("S1011"))) - return(DB_ERR_OPERATION_INVALID_AT_THIS_TIME); - if (!wxStrcmp(SQLState, wxT("S1012"))) - return(DB_ERR_INVALID_TRANS_OPERATION_CODE); - if (!wxStrcmp(SQLState, wxT("S1015"))) - return(DB_ERR_NO_CURSOR_NAME_AVAIL); - if (!wxStrcmp(SQLState, wxT("S1090"))) - return(DB_ERR_INVALID_STR_OR_BUF_LEN); - if (!wxStrcmp(SQLState, wxT("S1091"))) - return(DB_ERR_DESCRIPTOR_TYPE_OUT_OF_RANGE); - if (!wxStrcmp(SQLState, wxT("S1092"))) - return(DB_ERR_OPTION_TYPE_OUT_OF_RANGE); - if (!wxStrcmp(SQLState, wxT("S1093"))) - return(DB_ERR_INVALID_PARAM_NO); - if (!wxStrcmp(SQLState, wxT("S1094"))) - return(DB_ERR_INVALID_SCALE_VALUE); - if (!wxStrcmp(SQLState, wxT("S1095"))) - return(DB_ERR_FUNCTION_TYPE_OUT_OF_RANGE); - if (!wxStrcmp(SQLState, wxT("S1096"))) - return(DB_ERR_INF_TYPE_OUT_OF_RANGE); - if (!wxStrcmp(SQLState, wxT("S1097"))) - return(DB_ERR_COLUMN_TYPE_OUT_OF_RANGE); - if (!wxStrcmp(SQLState, wxT("S1098"))) - return(DB_ERR_SCOPE_TYPE_OUT_OF_RANGE); - if (!wxStrcmp(SQLState, wxT("S1099"))) - return(DB_ERR_NULLABLE_TYPE_OUT_OF_RANGE); - if (!wxStrcmp(SQLState, wxT("S1100"))) - return(DB_ERR_UNIQUENESS_OPTION_TYPE_OUT_OF_RANGE); - if (!wxStrcmp(SQLState, wxT("S1101"))) - return(DB_ERR_ACCURACY_OPTION_TYPE_OUT_OF_RANGE); - if (!wxStrcmp(SQLState, wxT("S1103"))) - return(DB_ERR_DIRECTION_OPTION_OUT_OF_RANGE); - if (!wxStrcmp(SQLState, wxT("S1104"))) - return(DB_ERR_INVALID_PRECISION_VALUE); - if (!wxStrcmp(SQLState, wxT("S1105"))) - return(DB_ERR_INVALID_PARAM_TYPE); - if (!wxStrcmp(SQLState, wxT("S1106"))) - return(DB_ERR_FETCH_TYPE_OUT_OF_RANGE); - if (!wxStrcmp(SQLState, wxT("S1107"))) - return(DB_ERR_ROW_VALUE_OUT_OF_RANGE); - if (!wxStrcmp(SQLState, wxT("S1108"))) - return(DB_ERR_CONCURRENCY_OPTION_OUT_OF_RANGE); - if (!wxStrcmp(SQLState, wxT("S1109"))) - return(DB_ERR_INVALID_CURSOR_POSITION); - if (!wxStrcmp(SQLState, wxT("S1110"))) - return(DB_ERR_INVALID_DRIVER_COMPLETION); - if (!wxStrcmp(SQLState, wxT("S1111"))) - return(DB_ERR_INVALID_BOOKMARK_VALUE); - if (!wxStrcmp(SQLState, wxT("S1C00"))) - return(DB_ERR_DRIVER_NOT_CAPABLE); - if (!wxStrcmp(SQLState, wxT("S1T00"))) - return(DB_ERR_TIMEOUT_EXPIRED); - - // No match - return(0); - -} // wxDb::TranslateSqlState() - - -/********** wxDb::Grant() **********/ -bool wxDb::Grant(int privileges, const wxString &tableName, const wxString &userList) -{ - wxString sqlStmt; - - // Build the grant statement - sqlStmt = wxT("GRANT "); - if (privileges == DB_GRANT_ALL) - sqlStmt += wxT("ALL"); - else - { - int c = 0; - if (privileges & DB_GRANT_SELECT) - { - sqlStmt += wxT("SELECT"); - c++; - } - if (privileges & DB_GRANT_INSERT) - { - if (c++) - sqlStmt += wxT(", "); - sqlStmt += wxT("INSERT"); - } - if (privileges & DB_GRANT_UPDATE) - { - if (c++) - sqlStmt += wxT(", "); - sqlStmt += wxT("UPDATE"); - } - if (privileges & DB_GRANT_DELETE) - { - if (c++) - sqlStmt += wxT(", "); - sqlStmt += wxT("DELETE"); - } - } - - sqlStmt += wxT(" ON "); - sqlStmt += SQLTableName(tableName); - sqlStmt += wxT(" TO "); - sqlStmt += userList; - -#ifdef DBDEBUG_CONSOLE - cout << endl << sqlStmt.c_str() << endl; -#endif - - WriteSqlLog(sqlStmt); - - return(ExecSql(sqlStmt)); - -} // wxDb::Grant() - - -/********** wxDb::CreateView() **********/ -bool wxDb::CreateView(const wxString &viewName, const wxString &colList, - const wxString &pSqlStmt, bool attemptDrop) -{ - wxString sqlStmt; - - // Drop the view first - if (attemptDrop && !DropView(viewName)) - return false; - - // Build the create view statement - sqlStmt = wxT("CREATE VIEW "); - sqlStmt += viewName; - - if (colList.length()) - { - sqlStmt += wxT(" ("); - sqlStmt += colList; - sqlStmt += wxT(")"); - } - - sqlStmt += wxT(" AS "); - sqlStmt += pSqlStmt; - - WriteSqlLog(sqlStmt); - -#ifdef DBDEBUG_CONSOLE - cout << sqlStmt.c_str() << endl; -#endif - - return(ExecSql(sqlStmt)); - -} // wxDb::CreateView() - - -/********** wxDb::DropView() **********/ -bool wxDb::DropView(const wxString &viewName) -{ -/* - * NOTE: This function returns true if the View does not exist, but - * only for identified databases. Code will need to be added - * below for any other databases when those databases are defined - * to handle this situation consistently - */ - wxString sqlStmt; - - sqlStmt.Printf(wxT("DROP VIEW %s"), viewName.c_str()); - - WriteSqlLog(sqlStmt); - -#ifdef DBDEBUG_CONSOLE - cout << endl << sqlStmt.c_str() << endl; -#endif - - if (SQLExecDirect(hstmt, (SQLTCHAR FAR *) sqlStmt.c_str(), SQL_NTS) != SQL_SUCCESS) - { - // Check for "Base table not found" error and ignore - GetNextError(henv, hdbc, hstmt); - if (wxStrcmp(sqlState,wxT("S0002"))) // "Base table not found" - { - // Check for product specific error codes - if (!((Dbms() == dbmsSYBASE_ASA && !wxStrcmp(sqlState,wxT("42000"))))) // 5.x (and lower?) - { - DispNextError(); - DispAllErrors(henv, hdbc, hstmt); - RollbackTrans(); - return false; - } - } - } - - // Commit the transaction - if (!CommitTrans()) - return false; - - return true; - -} // wxDb::DropView() - - -/********** wxDb::ExecSql() **********/ -bool wxDb::ExecSql(const wxString &pSqlStmt) -{ - RETCODE retcode; - - SQLFreeStmt(hstmt, SQL_CLOSE); - - retcode = SQLExecDirect(hstmt, (SQLTCHAR FAR *) pSqlStmt.c_str(), SQL_NTS); - if (retcode == SQL_SUCCESS || - (Dbms() == dbmsDB2 && (retcode == SQL_SUCCESS_WITH_INFO || retcode == SQL_NO_DATA_FOUND))) - { - return true; - } - else - { - DispAllErrors(henv, hdbc, hstmt); - return false; - } - -} // wxDb::ExecSql() - - -/********** wxDb::ExecSql() with column info **********/ -bool wxDb::ExecSql(const wxString &pSqlStmt, wxDbColInf** columns, short& numcols) -{ - //execute the statement first - if (!ExecSql(pSqlStmt)) - return false; - - SWORD noCols; - if (SQLNumResultCols(hstmt, &noCols) != SQL_SUCCESS) - { - DispAllErrors(henv, hdbc, hstmt); - return false; - } - - if (noCols == 0) - return false; - else - numcols = noCols; - - // Get column information - short colNum; - wxChar name[DB_MAX_COLUMN_NAME_LEN+1]; - SWORD Sword; - SQLLEN Sqllen; - wxDbColInf* pColInf = new wxDbColInf[noCols]; - - // Fill in column information (name, datatype) - for (colNum = 0; colNum < noCols; colNum++) - { - if (SQLColAttributes(hstmt, (UWORD)(colNum+1), SQL_COLUMN_NAME, - name, sizeof(name), - &Sword, &Sqllen) != SQL_SUCCESS) - { - DispAllErrors(henv, hdbc, hstmt); - delete[] pColInf; - return false; - } - - wxStrncpy(pColInf[colNum].colName, name, DB_MAX_COLUMN_NAME_LEN); - pColInf[colNum].colName[DB_MAX_COLUMN_NAME_LEN] = 0; // Prevent buffer overrun - - if (SQLColAttributes(hstmt, (UWORD)(colNum+1), SQL_COLUMN_TYPE, - NULL, 0, &Sword, &Sqllen) != SQL_SUCCESS) - { - DispAllErrors(henv, hdbc, hstmt); - delete[] pColInf; - return false; - } - - switch (Sqllen) - { -#if wxUSE_UNICODE - #if defined(SQL_WCHAR) - case SQL_WCHAR: - #endif - #if defined(SQL_WVARCHAR) - case SQL_WVARCHAR: - #endif -#endif - case SQL_VARCHAR: - case SQL_CHAR: - pColInf[colNum].dbDataType = DB_DATA_TYPE_VARCHAR; - break; - case SQL_LONGVARCHAR: - pColInf[colNum].dbDataType = DB_DATA_TYPE_MEMO; - break; - case SQL_TINYINT: - case SQL_SMALLINT: - case SQL_INTEGER: - case SQL_BIT: - pColInf[colNum].dbDataType = DB_DATA_TYPE_INTEGER; - break; - case SQL_DOUBLE: - case SQL_DECIMAL: - case SQL_NUMERIC: - case SQL_FLOAT: - case SQL_REAL: - pColInf[colNum].dbDataType = DB_DATA_TYPE_FLOAT; - break; - case SQL_DATE: - case SQL_TIMESTAMP: - pColInf[colNum].dbDataType = DB_DATA_TYPE_DATE; - break; - case SQL_BINARY: - pColInf[colNum].dbDataType = DB_DATA_TYPE_BLOB; - break; -#ifdef __WXDEBUG__ - default: - wxString errMsg; - errMsg.Printf(wxT("SQL Data type %ld currently not supported by wxWidgets"), (long)Sqllen); - wxLogDebug(errMsg,wxT("ODBC DEBUG MESSAGE")); -#endif - } - } - - *columns = pColInf; - return true; -} // wxDb::ExecSql() - -/********** wxDb::GetNext() **********/ -bool wxDb::GetNext(void) -{ - if (SQLFetch(hstmt) == SQL_SUCCESS) - return true; - else - { - DispAllErrors(henv, hdbc, hstmt); - return false; - } - -} // wxDb::GetNext() - - -/********** wxDb::GetData() **********/ -bool wxDb::GetData(UWORD colNo, SWORD cType, PTR pData, SDWORD maxLen, SQLLEN FAR *cbReturned) -{ - wxASSERT(pData); - wxASSERT(cbReturned); - - long bufferSize = maxLen; - - if (cType == SQL_C_WXCHAR) - bufferSize = maxLen * sizeof(wxChar); - - if (SQLGetData(hstmt, colNo, cType, pData, bufferSize, cbReturned) == SQL_SUCCESS) - return true; - else - { - DispAllErrors(henv, hdbc, hstmt); - return false; - } - -} // wxDb::GetData() - - -/********** wxDb::GetKeyFields() **********/ -int wxDb::GetKeyFields(const wxString &tableName, wxDbColInf* colInf, UWORD noCols) -{ - wxChar szPkTable[DB_MAX_TABLE_NAME_LEN+1]; /* Primary key table name */ - wxChar szFkTable[DB_MAX_TABLE_NAME_LEN+1]; /* Foreign key table name */ - SWORD iKeySeq; - wxChar szPkCol[DB_MAX_COLUMN_NAME_LEN+1]; /* Primary key column */ - wxChar szFkCol[DB_MAX_COLUMN_NAME_LEN+1]; /* Foreign key column */ - SQLRETURN retcode; - SQLLEN cb; - SWORD i; - wxString tempStr; - /* - * ----------------------------------------------------------------------- - * -- 19991224 : mj10777 : Create ------ - * -- : Three things are done and stored here : ------ - * -- : 1) which Column(s) is/are Primary Key(s) ------ - * -- : 2) which tables use this Key as a Foreign Key ------ - * -- : 3) which columns are Foreign Key and the name ------ - * -- : of the Table where the Key is the Primary Key ----- - * -- : Called from GetColumns(const wxString &tableName, ------ - * -- int *numCols,const wxChar *userID ) ------ - * ----------------------------------------------------------------------- - */ - - /*---------------------------------------------------------------------*/ - /* Get the names of the columns in the primary key. */ - /*---------------------------------------------------------------------*/ - retcode = SQLPrimaryKeys(hstmt, - NULL, 0, /* Catalog name */ - NULL, 0, /* Schema name */ - (SQLTCHAR FAR *) tableName.c_str(), SQL_NTS); /* Table name */ - - /*---------------------------------------------------------------------*/ - /* Fetch and display the result set. This will be a list of the */ - /* columns in the primary key of the tableName table. */ - /*---------------------------------------------------------------------*/ - while ((retcode == SQL_SUCCESS) || (retcode == SQL_SUCCESS_WITH_INFO)) - { - retcode = SQLFetch(hstmt); - if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) - { - GetData( 4, SQL_C_WXCHAR, szPkCol, DB_MAX_COLUMN_NAME_LEN+1, &cb); - GetData( 5, SQL_C_SSHORT, &iKeySeq, 0, &cb); - //------- - for (i=0;iGetColumns(tableList, userID); - * if (colInf) - * { - * // Use the column inf - * ....... - * // Destroy the memory - * delete [] colInf; - * } - * - * userID is evaluated in the following manner: - * userID == NULL ... UserID is ignored - * userID == "" ... UserID set equal to 'this->uid' - * userID != "" ... UserID set equal to 'userID' - * - * NOTE: ALL column bindings associated with this wxDb instance are unbound - * by this function. This function should use its own wxDb instance - * to avoid undesired unbinding of columns. - */ -{ - UWORD noCols = 0; - UWORD colNo = 0; - wxDbColInf *colInf = 0; - - RETCODE retcode; - SQLLEN cb; - - wxString TableName; - - wxString UserID; - convertUserID(userID,UserID); - - // Pass 1 - Determine how many columns there are. - // Pass 2 - Allocate the wxDbColInf array and fill in - // the array with the column information. - int pass; - for (pass = 1; pass <= 2; pass++) - { - if (pass == 2) - { - if (noCols == 0) // Probably a bogus table name(s) - break; - // Allocate n wxDbColInf objects to hold the column information - colInf = new wxDbColInf[noCols+1]; - if (!colInf) - break; - // Mark the end of the array - wxStrcpy(colInf[noCols].tableName, wxEmptyString); - wxStrcpy(colInf[noCols].colName, wxEmptyString); - colInf[noCols].sqlDataType = 0; - } - // Loop through each table name - int tbl; - for (tbl = 0; tableName[tbl]; tbl++) - { - TableName = tableName[tbl]; - // Oracle and Interbase table names are uppercase only, so force - // the name to uppercase just in case programmer forgot to do this - if ((Dbms() == dbmsORACLE) || - (Dbms() == dbmsFIREBIRD) || - (Dbms() == dbmsINTERBASE)) - TableName = TableName.Upper(); - - SQLFreeStmt(hstmt, SQL_CLOSE); - - // MySQL, SQLServer, and Access cannot accept a user name when looking up column names, so we - // use the call below that leaves out the user name - if (!UserID.empty() && - Dbms() != dbmsMY_SQL && - Dbms() != dbmsACCESS && - Dbms() != dbmsMS_SQL_SERVER) - { - retcode = SQLColumns(hstmt, - NULL, 0, // All qualifiers - (SQLTCHAR *) UserID.c_str(), SQL_NTS, // Owner - (SQLTCHAR *) TableName.c_str(), SQL_NTS, - NULL, 0); // All columns - } - else - { - retcode = SQLColumns(hstmt, - NULL, 0, // All qualifiers - NULL, 0, // Owner - (SQLTCHAR *) TableName.c_str(), SQL_NTS, - NULL, 0); // All columns - } - if (retcode != SQL_SUCCESS) - { // Error occurred, abort - DispAllErrors(henv, hdbc, hstmt); - if (colInf) - delete [] colInf; - SQLFreeStmt(hstmt, SQL_CLOSE); - return(0); - } - - while ((retcode = SQLFetch(hstmt)) == SQL_SUCCESS) - { - if (pass == 1) // First pass, just add up the number of columns - noCols++; - else // Pass 2; Fill in the array of structures - { - if (colNo < noCols) // Some extra error checking to prevent memory overwrites - { - // NOTE: Only the ODBC 1.x fields are retrieved - GetData( 1, SQL_C_WXCHAR, (UCHAR*) colInf[colNo].catalog, 128+1, &cb); - GetData( 2, SQL_C_WXCHAR, (UCHAR*) colInf[colNo].schema, 128+1, &cb); - GetData( 3, SQL_C_WXCHAR, (UCHAR*) colInf[colNo].tableName, DB_MAX_TABLE_NAME_LEN+1, &cb); - GetData( 4, SQL_C_WXCHAR, (UCHAR*) colInf[colNo].colName, DB_MAX_COLUMN_NAME_LEN+1, &cb); - GetData( 5, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].sqlDataType, 0, &cb); - GetData( 6, SQL_C_WXCHAR, (UCHAR*) colInf[colNo].typeName, 128+1, &cb); - GetData( 7, SQL_C_SLONG, (UCHAR*) &colInf[colNo].columnLength, 0, &cb); - GetData( 8, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].bufferSize, 0, &cb); - GetData( 9, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].decimalDigits,0, &cb); - GetData(10, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].numPrecRadix, 0, &cb); - GetData(11, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].nullable, 0, &cb); - GetData(12, SQL_C_WXCHAR, (UCHAR*) colInf[colNo].remarks, 254+1, &cb); - - // Determine the wxDb data type that is used to represent the native data type of this data source - colInf[colNo].dbDataType = 0; - if (!wxStricmp(typeInfVarchar.TypeName,colInf[colNo].typeName)) - { -#ifdef _IODBC_ - // IODBC does not return a correct columnLength, so we set - // columnLength = bufferSize if no column length was returned - // IODBC returns the columnLength in bufferSize. (bug) - if (colInf[colNo].columnLength < 1) - { - colInf[colNo].columnLength = colInf[colNo].bufferSize; - } -#endif - colInf[colNo].dbDataType = DB_DATA_TYPE_VARCHAR; - } - else if (!wxStricmp(typeInfInteger.TypeName, colInf[colNo].typeName)) - colInf[colNo].dbDataType = DB_DATA_TYPE_INTEGER; - else if (!wxStricmp(typeInfFloat.TypeName, colInf[colNo].typeName)) - colInf[colNo].dbDataType = DB_DATA_TYPE_FLOAT; - else if (!wxStricmp(typeInfDate.TypeName, colInf[colNo].typeName)) - colInf[colNo].dbDataType = DB_DATA_TYPE_DATE; - else if (!wxStricmp(typeInfBlob.TypeName, colInf[colNo].typeName)) - colInf[colNo].dbDataType = DB_DATA_TYPE_BLOB; - colNo++; - } - } - } - if (retcode != SQL_NO_DATA_FOUND) - { // Error occurred, abort - DispAllErrors(henv, hdbc, hstmt); - if (colInf) - delete [] colInf; - SQLFreeStmt(hstmt, SQL_CLOSE); - return(0); - } - } - } - - SQLFreeStmt(hstmt, SQL_CLOSE); - return colInf; - -} // wxDb::GetColumns() - - -/********** wxDb::GetColumns() **********/ - -wxDbColInf *wxDb::GetColumns(const wxString &tableName, UWORD *numCols, const wxChar *userID) -// -// Same as the above GetColumns() function except this one gets columns -// only for a single table, and if 'numCols' is not NULL, the number of -// columns stored in the returned wxDbColInf is set in '*numCols' -// -// userID is evaluated in the following manner: -// userID == NULL ... UserID is ignored -// userID == "" ... UserID set equal to 'this->uid' -// userID != "" ... UserID set equal to 'userID' -// -// NOTE: ALL column bindings associated with this wxDb instance are unbound -// by this function. This function should use its own wxDb instance -// to avoid undesired unbinding of columns. - -{ - UWORD noCols = 0; - UWORD colNo = 0; - wxDbColInf *colInf = 0; - - RETCODE retcode; - SQLLEN cb; - - wxString TableName; - - wxString UserID; - convertUserID(userID,UserID); - - // Pass 1 - Determine how many columns there are. - // Pass 2 - Allocate the wxDbColInf array and fill in - // the array with the column information. - int pass; - for (pass = 1; pass <= 2; pass++) - { - if (pass == 2) - { - if (noCols == 0) // Probably a bogus table name(s) - break; - // Allocate n wxDbColInf objects to hold the column information - colInf = new wxDbColInf[noCols+1]; - if (!colInf) - break; - // Mark the end of the array - wxStrcpy(colInf[noCols].tableName, wxEmptyString); - wxStrcpy(colInf[noCols].colName, wxEmptyString); - colInf[noCols].sqlDataType = 0; - } - - TableName = tableName; - // Oracle and Interbase table names are uppercase only, so force - // the name to uppercase just in case programmer forgot to do this - if ((Dbms() == dbmsORACLE) || - (Dbms() == dbmsFIREBIRD) || - (Dbms() == dbmsINTERBASE)) - TableName = TableName.Upper(); - - SQLFreeStmt(hstmt, SQL_CLOSE); - - // MySQL, SQLServer, and Access cannot accept a user name when looking up column names, so we - // use the call below that leaves out the user name - if (!UserID.empty() && - Dbms() != dbmsMY_SQL && - Dbms() != dbmsACCESS && - Dbms() != dbmsMS_SQL_SERVER) - { - retcode = SQLColumns(hstmt, - NULL, 0, // All qualifiers - (SQLTCHAR *) UserID.c_str(), SQL_NTS, // Owner - (SQLTCHAR *) TableName.c_str(), SQL_NTS, - NULL, 0); // All columns - } - else - { - retcode = SQLColumns(hstmt, - NULL, 0, // All qualifiers - NULL, 0, // Owner - (SQLTCHAR *) TableName.c_str(), SQL_NTS, - NULL, 0); // All columns - } - if (retcode != SQL_SUCCESS) - { // Error occurred, abort - DispAllErrors(henv, hdbc, hstmt); - if (colInf) - delete [] colInf; - SQLFreeStmt(hstmt, SQL_CLOSE); - if (numCols) - *numCols = 0; - return(0); - } - - while ((retcode = SQLFetch(hstmt)) == SQL_SUCCESS) - { - if (pass == 1) // First pass, just add up the number of columns - noCols++; - else // Pass 2; Fill in the array of structures - { - if (colNo < noCols) // Some extra error checking to prevent memory overwrites - { - // NOTE: Only the ODBC 1.x fields are retrieved - GetData( 1, SQL_C_WXCHAR, (UCHAR*) colInf[colNo].catalog, 128+1, &cb); - GetData( 2, SQL_C_WXCHAR, (UCHAR*) colInf[colNo].schema, 128+1, &cb); - GetData( 3, SQL_C_WXCHAR, (UCHAR*) colInf[colNo].tableName, DB_MAX_TABLE_NAME_LEN+1, &cb); - GetData( 4, SQL_C_WXCHAR, (UCHAR*) colInf[colNo].colName, DB_MAX_COLUMN_NAME_LEN+1, &cb); - GetData( 5, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].sqlDataType, 0, &cb); - GetData( 6, SQL_C_WXCHAR, (UCHAR*) colInf[colNo].typeName, 128+1, &cb); - GetData( 7, SQL_C_SLONG, (UCHAR*) &colInf[colNo].columnLength, 0, &cb); - // BJO 991214 : SQL_C_SSHORT instead of SQL_C_SLONG, otherwise fails on Sparc (probably all 64 bit architectures) - GetData( 8, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].bufferSize, 0, &cb); - GetData( 9, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].decimalDigits,0, &cb); - GetData(10, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].numPrecRadix, 0, &cb); - GetData(11, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].nullable, 0, &cb); - GetData(12, SQL_C_WXCHAR, (UCHAR*) colInf[colNo].remarks, 254+1, &cb); - // Start Values for Primary/Foriegn Key (=No) - colInf[colNo].PkCol = 0; // Primary key column 0=No; 1= First Key, 2 = Second Key etc. - colInf[colNo].PkTableName[0] = 0; // Tablenames where Primary Key is used as a Foreign Key - colInf[colNo].FkCol = 0; // Foreign key column 0=No; 1= First Key, 2 = Second Key etc. - colInf[colNo].FkTableName[0] = 0; // Foreign key table name - - // BJO 20000428 : Virtuoso returns type names with upper cases! - if (Dbms() == dbmsVIRTUOSO) - { - wxString s = colInf[colNo].typeName; - s = s.MakeLower(); - wxStrcmp(colInf[colNo].typeName, s.c_str()); - } - - // Determine the wxDb data type that is used to represent the native data type of this data source - colInf[colNo].dbDataType = 0; - if (!wxStricmp(typeInfVarchar.TypeName, colInf[colNo].typeName)) - { -#ifdef _IODBC_ - // IODBC does not return a correct columnLength, so we set - // columnLength = bufferSize if no column length was returned - // IODBC returns the columnLength in bufferSize. (bug) - if (colInf[colNo].columnLength < 1) - { - colInf[colNo].columnLength = colInf[colNo].bufferSize; - } -#endif - - colInf[colNo].dbDataType = DB_DATA_TYPE_VARCHAR; - } - else if (!wxStricmp(typeInfInteger.TypeName, colInf[colNo].typeName)) - colInf[colNo].dbDataType = DB_DATA_TYPE_INTEGER; - else if (!wxStricmp(typeInfFloat.TypeName, colInf[colNo].typeName)) - colInf[colNo].dbDataType = DB_DATA_TYPE_FLOAT; - else if (!wxStricmp(typeInfDate.TypeName, colInf[colNo].typeName)) - colInf[colNo].dbDataType = DB_DATA_TYPE_DATE; - else if (!wxStricmp(typeInfBlob.TypeName, colInf[colNo].typeName)) - colInf[colNo].dbDataType = DB_DATA_TYPE_BLOB; - - colNo++; - } - } - } - if (retcode != SQL_NO_DATA_FOUND) - { // Error occurred, abort - DispAllErrors(henv, hdbc, hstmt); - if (colInf) - delete [] colInf; - SQLFreeStmt(hstmt, SQL_CLOSE); - if (numCols) - *numCols = 0; - return(0); - } - } - - SQLFreeStmt(hstmt, SQL_CLOSE); - - // Store Primary and Foriegn Keys - GetKeyFields(tableName,colInf,noCols); - - if (numCols) - *numCols = noCols; - return colInf; - -} // wxDb::GetColumns() - - -#else // New GetColumns - - -/* - BJO 20000503 - These are tentative new GetColumns members which should be more database - independent and which always returns the columns in the order they were - created. - - - The first one (wxDbColInf *wxDb::GetColumns(wxChar *tableName[], const - wxChar* userID)) calls the second implementation for each separate table - before merging the results. This makes the code easier to maintain as - only one member (the second) makes the real work - - wxDbColInf *wxDb::GetColumns(const wxString &tableName, int *numCols, const - wxChar *userID) is a little bit improved - - It doesn't anymore rely on the type-name to find out which database-type - each column has - - It ends by sorting the columns, so that they are returned in the same - order they were created -*/ - -typedef struct -{ - UWORD noCols; - wxDbColInf *colInf; -} _TableColumns; - - -wxDbColInf *wxDb::GetColumns(wxChar *tableName[], const wxChar *userID) -{ - int i, j; - // The last array element of the tableName[] argument must be zero (null). - // This is how the end of the array is detected. - - UWORD noCols = 0; - - // How many tables ? - int tbl; - for (tbl = 0 ; tableName[tbl]; tbl++); - - // Create a table to maintain the columns for each separate table - _TableColumns *TableColumns = new _TableColumns[tbl]; - - // Fill the table - for (i = 0 ; i < tbl ; i++) - - { - TableColumns[i].colInf = GetColumns(tableName[i], &TableColumns[i].noCols, userID); - if (TableColumns[i].colInf == NULL) - return NULL; - noCols += TableColumns[i].noCols; - } - - // Now merge all the separate table infos - wxDbColInf *colInf = new wxDbColInf[noCols+1]; - - // Mark the end of the array - wxStrcpy(colInf[noCols].tableName, wxEmptyString); - wxStrcpy(colInf[noCols].colName, wxEmptyString); - colInf[noCols].sqlDataType = 0; - - // Merge ... - int offset = 0; - - for (i = 0 ; i < tbl ; i++) - { - for (j = 0 ; j < TableColumns[i].noCols ; j++) - { - colInf[offset++] = TableColumns[i].colInf[j]; - } - } - - delete [] TableColumns; - - return colInf; -} // wxDb::GetColumns() -- NEW - - -wxDbColInf *wxDb::GetColumns(const wxString &tableName, int *numCols, const wxChar *userID) -// -// Same as the above GetColumns() function except this one gets columns -// only for a single table, and if 'numCols' is not NULL, the number of -// columns stored in the returned wxDbColInf is set in '*numCols' -// -// userID is evaluated in the following manner: -// userID == NULL ... UserID is ignored -// userID == "" ... UserID set equal to 'this->uid' -// userID != "" ... UserID set equal to 'userID' -// -// NOTE: ALL column bindings associated with this wxDb instance are unbound -// by this function. This function should use its own wxDb instance -// to avoid undesired unbinding of columns. -{ - UWORD noCols = 0; - UWORD colNo = 0; - wxDbColInf *colInf = 0; - - RETCODE retcode; - SDWORD cb; - - wxString TableName; - - wxString UserID; - convertUserID(userID,UserID); - - // Pass 1 - Determine how many columns there are. - // Pass 2 - Allocate the wxDbColInf array and fill in - // the array with the column information. - int pass; - for (pass = 1; pass <= 2; pass++) - { - if (pass == 2) - { - if (noCols == 0) // Probably a bogus table name(s) - break; - // Allocate n wxDbColInf objects to hold the column information - colInf = new wxDbColInf[noCols+1]; - if (!colInf) - break; - // Mark the end of the array - wxStrcpy(colInf[noCols].tableName, wxEmptyString); - wxStrcpy(colInf[noCols].colName, wxEmptyString); - colInf[noCols].sqlDataType = 0; - } - - TableName = tableName; - // Oracle and Interbase table names are uppercase only, so force - // the name to uppercase just in case programmer forgot to do this - if ((Dbms() == dbmsORACLE) || - (Dbms() == dbmsFIREBIRD) || - (Dbms() == dbmsINTERBASE)) - TableName = TableName.Upper(); - - SQLFreeStmt(hstmt, SQL_CLOSE); - - // MySQL, SQLServer, and Access cannot accept a user name when looking up column names, so we - // use the call below that leaves out the user name - if (!UserID.empty() && - Dbms() != dbmsMY_SQL && - Dbms() != dbmsACCESS && - Dbms() != dbmsMS_SQL_SERVER) - { - retcode = SQLColumns(hstmt, - NULL, 0, // All qualifiers - (UCHAR *) UserID.c_str(), SQL_NTS, // Owner - (UCHAR *) TableName.c_str(), SQL_NTS, - NULL, 0); // All columns - } - else - { - retcode = SQLColumns(hstmt, - NULL, 0, // All qualifiers - NULL, 0, // Owner - (UCHAR *) TableName.c_str(), SQL_NTS, - NULL, 0); // All columns - } - if (retcode != SQL_SUCCESS) - { // Error occurred, abort - DispAllErrors(henv, hdbc, hstmt); - if (colInf) - delete [] colInf; - SQLFreeStmt(hstmt, SQL_CLOSE); - if (numCols) - *numCols = 0; - return(0); - } - - while ((retcode = SQLFetch(hstmt)) == SQL_SUCCESS) - { - if (pass == 1) // First pass, just add up the number of columns - noCols++; - else // Pass 2; Fill in the array of structures - { - if (colNo < noCols) // Some extra error checking to prevent memory overwrites - { - // NOTE: Only the ODBC 1.x fields are retrieved - GetData( 1, SQL_C_WXCHAR, (UCHAR*) colInf[colNo].catalog, 128+1, &cb); - GetData( 2, SQL_C_WXCHAR, (UCHAR*) colInf[colNo].schema, 128+1, &cb); - GetData( 3, SQL_C_WXCHAR, (UCHAR*) colInf[colNo].tableName, DB_MAX_TABLE_NAME_LEN+1, &cb); - GetData( 4, SQL_C_WXCHAR, (UCHAR*) colInf[colNo].colName, DB_MAX_COLUMN_NAME_LEN+1, &cb); - GetData( 5, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].sqlDataType, 0, &cb); - GetData( 6, SQL_C_WXCHAR, (UCHAR*) colInf[colNo].typeName, 128+1, &cb); - GetData( 7, SQL_C_SLONG, (UCHAR*) &colInf[colNo].columnLength, 0, &cb); - GetData( 8, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].bufferSize, 0, &cb); - GetData( 9, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].decimalDigits,0, &cb); - GetData(10, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].numPrecRadix, 0, &cb); - GetData(11, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].nullable, 0, &cb); - GetData(12, SQL_C_WXCHAR, (UCHAR*) colInf[colNo].remarks, 254+1, &cb); - // Start Values for Primary/Foriegn Key (=No) - colInf[colNo].PkCol = 0; // Primary key column 0=No; 1= First Key, 2 = Second Key etc. - colInf[colNo].PkTableName[0] = 0; // Tablenames where Primary Key is used as a Foreign Key - colInf[colNo].FkCol = 0; // Foreign key column 0=No; 1= First Key, 2 = Second Key etc. - colInf[colNo].FkTableName[0] = 0; // Foreign key table name - -#ifdef _IODBC_ - // IODBC does not return a correct columnLength, so we set - // columnLength = bufferSize if no column length was returned - // IODBC returns the columnLength in bufferSize. (bug) - if (colInf[colNo].columnLength < 1) - { - colInf[colNo].columnLength = colInf[colNo].bufferSize; - } -#endif - - // Determine the wxDb data type that is used to represent the native data type of this data source - colInf[colNo].dbDataType = 0; - // Get the intern datatype - switch (colInf[colNo].sqlDataType) - { -#if wxUSE_UNICODE - #if defined(SQL_WCHAR) - case SQL_WCHAR: - #endif - #if defined(SQL_WVARCHAR) - case SQL_WVARCHAR: - #endif -#endif - case SQL_VARCHAR: - case SQL_CHAR: - colInf[colNo].dbDataType = DB_DATA_TYPE_VARCHAR; - break; - case SQL_LONGVARCHAR: - colInf[colNo].dbDataType = DB_DATA_TYPE_MEMO; - break; - case SQL_TINYINT: - case SQL_SMALLINT: - case SQL_INTEGER: - case SQL_BIT: - colInf[colNo].dbDataType = DB_DATA_TYPE_INTEGER; - break; - case SQL_DOUBLE: - case SQL_DECIMAL: - case SQL_NUMERIC: - case SQL_FLOAT: - case SQL_REAL: - colInf[colNo].dbDataType = DB_DATA_TYPE_FLOAT; - break; - case SQL_DATE: - case SQL_TIMESTAMP: - colInf[colNo].dbDataType = DB_DATA_TYPE_DATE; - break; - case SQL_BINARY: - colInf[colNo].dbDataType = DB_DATA_TYPE_BLOB; - break; -#ifdef __WXDEBUG__ - default: - wxString errMsg; - errMsg.Printf(wxT("SQL Data type %d currently not supported by wxWidgets"), colInf[colNo].sqlDataType); - wxLogDebug(errMsg,wxT("ODBC DEBUG MESSAGE")); -#endif - } - colNo++; - } - } - } - if (retcode != SQL_NO_DATA_FOUND) - { // Error occurred, abort - DispAllErrors(henv, hdbc, hstmt); - if (colInf) - delete [] colInf; - SQLFreeStmt(hstmt, SQL_CLOSE); - if (numCols) - *numCols = 0; - return(0); - } - } - - SQLFreeStmt(hstmt, SQL_CLOSE); - - // Store Primary and Foreign Keys - GetKeyFields(tableName,colInf,noCols); - - /////////////////////////////////////////////////////////////////////////// - // Now sort the the columns in order to make them appear in the right order - /////////////////////////////////////////////////////////////////////////// - - // Build a generic SELECT statement which returns 0 rows - wxString Stmt; - - Stmt.Printf(wxT("select * from \"%s\" where 0=1"), tableName); - - // Execute query - if (SQLExecDirect(hstmt, (UCHAR FAR *) Stmt.c_str(), SQL_NTS) != SQL_SUCCESS) - { - DispAllErrors(henv, hdbc, hstmt); - return NULL; - } - - // Get the number of result columns - if (SQLNumResultCols (hstmt, &noCols) != SQL_SUCCESS) - { - DispAllErrors(henv, hdbc, hstmt); - return NULL; - } - - if (noCols == 0) // Probably a bogus table name - return NULL; - - // Get the name - int i; - short colNum; - UCHAR name[100]; - SWORD Sword; - SDWORD Sdword; - for (colNum = 0; colNum < noCols; colNum++) - { - if (SQLColAttributes(hstmt,colNum+1, SQL_COLUMN_NAME, - name, sizeof(name), - &Sword, &Sdword) != SQL_SUCCESS) - { - DispAllErrors(henv, hdbc, hstmt); - return NULL; - } - - wxString Name1 = name; - Name1 = Name1.Upper(); - - // Where is this name in the array ? - for (i = colNum ; i < noCols ; i++) - { - wxString Name2 = colInf[i].colName; - Name2 = Name2.Upper(); - if (Name2 == Name1) - { - if (colNum != i) // swap to sort - { - wxDbColInf tmpColInf = colInf[colNum]; - colInf[colNum] = colInf[i]; - colInf[i] = tmpColInf; - } - break; - } - } - } - SQLFreeStmt(hstmt, SQL_CLOSE); - - /////////////////////////////////////////////////////////////////////////// - // End sorting - /////////////////////////////////////////////////////////////////////////// - - if (numCols) - *numCols = noCols; - return colInf; - -} // wxDb::GetColumns() - - -#endif // #else OLD_GETCOLUMNS - - -/********** wxDb::GetColumnCount() **********/ -int wxDb::GetColumnCount(const wxString &tableName, const wxChar *userID) -/* - * Returns a count of how many columns are in a table. - * If an error occurs in computing the number of columns - * this function will return a -1 for the count - * - * userID is evaluated in the following manner: - * userID == NULL ... UserID is ignored - * userID == "" ... UserID set equal to 'this->uid' - * userID != "" ... UserID set equal to 'userID' - * - * NOTE: ALL column bindings associated with this wxDb instance are unbound - * by this function. This function should use its own wxDb instance - * to avoid undesired unbinding of columns. - */ -{ - UWORD noCols = 0; - - RETCODE retcode; - - wxString TableName; - - wxString UserID; - convertUserID(userID,UserID); - - TableName = tableName; - // Oracle and Interbase table names are uppercase only, so force - // the name to uppercase just in case programmer forgot to do this - if ((Dbms() == dbmsORACLE) || - (Dbms() == dbmsFIREBIRD) || - (Dbms() == dbmsINTERBASE)) - TableName = TableName.Upper(); - - SQLFreeStmt(hstmt, SQL_CLOSE); - - // MySQL, SQLServer, and Access cannot accept a user name when looking up column names, so we - // use the call below that leaves out the user name - if (!UserID.empty() && - Dbms() != dbmsMY_SQL && - Dbms() != dbmsACCESS && - Dbms() != dbmsMS_SQL_SERVER) - { - retcode = SQLColumns(hstmt, - NULL, 0, // All qualifiers - (SQLTCHAR *) UserID.c_str(), SQL_NTS, // Owner - (SQLTCHAR *) TableName.c_str(), SQL_NTS, - NULL, 0); // All columns - } - else - { - retcode = SQLColumns(hstmt, - NULL, 0, // All qualifiers - NULL, 0, // Owner - (SQLTCHAR *) TableName.c_str(), SQL_NTS, - NULL, 0); // All columns - } - if (retcode != SQL_SUCCESS) - { // Error occurred, abort - DispAllErrors(henv, hdbc, hstmt); - SQLFreeStmt(hstmt, SQL_CLOSE); - return(-1); - } - - // Count the columns - while ((retcode = SQLFetch(hstmt)) == SQL_SUCCESS) - noCols++; - - if (retcode != SQL_NO_DATA_FOUND) - { // Error occurred, abort - DispAllErrors(henv, hdbc, hstmt); - SQLFreeStmt(hstmt, SQL_CLOSE); - return(-1); - } - - SQLFreeStmt(hstmt, SQL_CLOSE); - return noCols; - -} // wxDb::GetColumnCount() - - -/********** wxDb::GetCatalog() *******/ -wxDbInf *wxDb::GetCatalog(const wxChar *userID) -/* - * --------------------------------------------------------------------- - * -- 19991203 : mj10777 : Create ------ - * -- : Creates a wxDbInf with Tables / Cols Array ------ - * -- : uses SQLTables and fills pTableInf; ------ - * -- : pColInf is set to NULL and numCols to 0; ------ - * -- : returns pDbInf (wxDbInf) ------ - * -- - if unsuccessful (pDbInf == NULL) ------ - * -- : pColInf can be filled with GetColumns(..); ------ - * -- : numCols can be filled with GetColumnCount(..); ------ - * --------------------------------------------------------------------- - * - * userID is evaluated in the following manner: - * userID == NULL ... UserID is ignored - * userID == "" ... UserID set equal to 'this->uid' - * userID != "" ... UserID set equal to 'userID' - * - * NOTE: ALL column bindings associated with this wxDb instance are unbound - * by this function. This function should use its own wxDb instance - * to avoid undesired unbinding of columns. - */ -{ - int noTab = 0; // Counter while filling table entries - int pass; - RETCODE retcode; - SQLLEN cb; - wxString tblNameSave; - - wxString UserID; - convertUserID(userID,UserID); - - //------------------------------------------------------------- - // Create the Database Array of catalog entries - - wxDbInf *pDbInf = new wxDbInf; - - //------------------------------------------------------------- - // Table Information - // Pass 1 - Determine how many Tables there are. - // Pass 2 - Create the Table array and fill it - // - Create the Cols array = NULL - //------------------------------------------------------------- - - for (pass = 1; pass <= 2; pass++) - { - SQLFreeStmt(hstmt, SQL_CLOSE); // Close if Open - tblNameSave.Empty(); - - if (!UserID.empty() && - Dbms() != dbmsMY_SQL && - Dbms() != dbmsACCESS && - Dbms() != dbmsMS_SQL_SERVER) - { - retcode = SQLTables(hstmt, - NULL, 0, // All qualifiers - (SQLTCHAR *) UserID.c_str(), SQL_NTS, // User specified - NULL, 0, // All tables - NULL, 0); // All columns - } - else - { - retcode = SQLTables(hstmt, - NULL, 0, // All qualifiers - NULL, 0, // User specified - NULL, 0, // All tables - NULL, 0); // All columns - } - - if (retcode != SQL_SUCCESS) - { - DispAllErrors(henv, hdbc, hstmt); - pDbInf = NULL; - SQLFreeStmt(hstmt, SQL_CLOSE); - return pDbInf; - } - - while ((retcode = SQLFetch(hstmt)) == SQL_SUCCESS) // Table Information - { - if (pass == 1) // First pass, just count the Tables - { - if (pDbInf->numTables == 0) - { - GetData( 1, SQL_C_WXCHAR, (UCHAR*) pDbInf->catalog, 128+1, &cb); - GetData( 2, SQL_C_WXCHAR, (UCHAR*) pDbInf->schema, 128+1, &cb); - } - pDbInf->numTables++; // Counter for Tables - } // if (pass == 1) - if (pass == 2) // Create and fill the Table entries - { - if (pDbInf->pTableInf == NULL) // Has the Table Array been created - { // no, then create the Array - pDbInf->pTableInf = new wxDbTableInf[pDbInf->numTables]; - noTab = 0; - } // if (pDbInf->pTableInf == NULL) // Has the Table Array been created - - GetData( 3, SQL_C_WXCHAR, (UCHAR*) (pDbInf->pTableInf+noTab)->tableName, DB_MAX_TABLE_NAME_LEN+1, &cb); - GetData( 4, SQL_C_WXCHAR, (UCHAR*) (pDbInf->pTableInf+noTab)->tableType, 30+1, &cb); - GetData( 5, SQL_C_WXCHAR, (UCHAR*) (pDbInf->pTableInf+noTab)->tableRemarks, 254+1, &cb); - - noTab++; - } // if - } // while - } // for - SQLFreeStmt(hstmt, SQL_CLOSE); - - // Query how many columns are in each table - for (noTab=0;noTabnumTables;noTab++) - { - (pDbInf->pTableInf+noTab)->numCols = (UWORD)GetColumnCount((pDbInf->pTableInf+noTab)->tableName,UserID); - } - - return pDbInf; - -} // wxDb::GetCatalog() - - -/********** wxDb::Catalog() **********/ -bool wxDb::Catalog(const wxChar *userID, const wxString &fileName) -/* - * Creates the text file specified in 'filename' which will contain - * a minimal data dictionary of all tables accessible by the user specified - * in 'userID' - * - * userID is evaluated in the following manner: - * userID == NULL ... UserID is ignored - * userID == "" ... UserID set equal to 'this->uid' - * userID != "" ... UserID set equal to 'userID' - * - * NOTE: ALL column bindings associated with this wxDb instance are unbound - * by this function. This function should use its own wxDb instance - * to avoid undesired unbinding of columns. - */ -{ - wxASSERT(fileName.length()); - - RETCODE retcode; - SQLLEN cb; - wxChar tblName[DB_MAX_TABLE_NAME_LEN+1]; - wxString tblNameSave; - wxChar colName[DB_MAX_COLUMN_NAME_LEN+1]; - SWORD sqlDataType; - wxChar typeName[30+1]; - SDWORD precision, length; - - FILE *fp = wxFopen(fileName.c_str(),wxT("wt")); - if (fp == NULL) - return false; - - SQLFreeStmt(hstmt, SQL_CLOSE); - - wxString UserID; - convertUserID(userID,UserID); - - if (!UserID.empty() && - Dbms() != dbmsMY_SQL && - Dbms() != dbmsACCESS && - Dbms() != dbmsFIREBIRD && - Dbms() != dbmsINTERBASE && - Dbms() != dbmsMS_SQL_SERVER) - { - retcode = SQLColumns(hstmt, - NULL, 0, // All qualifiers - (SQLTCHAR *) UserID.c_str(), SQL_NTS, // User specified - NULL, 0, // All tables - NULL, 0); // All columns - } - else - { - retcode = SQLColumns(hstmt, - NULL, 0, // All qualifiers - NULL, 0, // User specified - NULL, 0, // All tables - NULL, 0); // All columns - } - if (retcode != SQL_SUCCESS) - { - DispAllErrors(henv, hdbc, hstmt); - fclose(fp); - return false; - } - - wxString outStr; - tblNameSave.Empty(); - int cnt = 0; - - while (true) - { - retcode = SQLFetch(hstmt); - if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO) - break; - - GetData(3,SQL_C_WXCHAR, (UCHAR *) tblName, DB_MAX_TABLE_NAME_LEN+1, &cb); - GetData(4,SQL_C_WXCHAR, (UCHAR *) colName, DB_MAX_COLUMN_NAME_LEN+1,&cb); - GetData(5,SQL_C_SSHORT, (UCHAR *)&sqlDataType, 0, &cb); - GetData(6,SQL_C_WXCHAR, (UCHAR *) typeName, sizeof(typeName), &cb); - GetData(7,SQL_C_SLONG, (UCHAR *)&precision, 0, &cb); - GetData(8,SQL_C_SLONG, (UCHAR *)&length, 0, &cb); - - if (wxStrcmp(tblName, tblNameSave.c_str())) - { - if (cnt) - wxFputs(wxT("\n"), fp); - wxFputs(wxT("================================ "), fp); - wxFputs(wxT("================================ "), fp); - wxFputs(wxT("===================== "), fp); - wxFputs(wxT("========= "), fp); - wxFputs(wxT("=========\n"), fp); - outStr.Printf(wxT("%-32s %-32s %-21s %9s %9s\n"), - wxT("TABLE NAME"), wxT("COLUMN NAME"), wxT("DATA TYPE"), wxT("PRECISION"), wxT("LENGTH")); - wxFputs(outStr.c_str(), fp); - wxFputs(wxT("================================ "), fp); - wxFputs(wxT("================================ "), fp); - wxFputs(wxT("===================== "), fp); - wxFputs(wxT("========= "), fp); - wxFputs(wxT("=========\n"), fp); - tblNameSave = tblName; - } - - outStr.Printf(wxT("%-32s %-32s (%04d)%-15s %9ld %9ld\n"), - tblName, colName, sqlDataType, typeName, precision, length); - if (wxFputs(outStr.c_str(), fp) == EOF) - { - SQLFreeStmt(hstmt, SQL_CLOSE); - fclose(fp); - return false; - } - cnt++; - } - - if (retcode != SQL_NO_DATA_FOUND) - DispAllErrors(henv, hdbc, hstmt); - - SQLFreeStmt(hstmt, SQL_CLOSE); - - fclose(fp); - return(retcode == SQL_NO_DATA_FOUND); - -} // wxDb::Catalog() - - -bool wxDb::TableExists(const wxString &tableName, const wxChar *userID, const wxString &tablePath) -/* - * Table name can refer to a table, view, alias or synonym. Returns true - * if the object exists in the database. This function does not indicate - * whether or not the user has privleges to query or perform other functions - * on the table. - * - * userID is evaluated in the following manner: - * userID == NULL ... UserID is ignored - * userID == "" ... UserID set equal to 'this->uid' - * userID != "" ... UserID set equal to 'userID' - */ -{ - wxASSERT(tableName.length()); - - wxString TableName; - - if (Dbms() == dbmsDBASE) - { - wxString dbName; - if (tablePath.length()) - dbName.Printf(wxT("%s/%s.dbf"), tablePath.c_str(), tableName.c_str()); - else - dbName.Printf(wxT("%s.dbf"), tableName.c_str()); - - bool exists; - exists = wxFileExists(dbName); - return exists; - } - - wxString UserID; - convertUserID(userID,UserID); - - TableName = tableName; - // Oracle and Interbase table names are uppercase only, so force - // the name to uppercase just in case programmer forgot to do this - if ((Dbms() == dbmsORACLE) || - (Dbms() == dbmsFIREBIRD) || - (Dbms() == dbmsINTERBASE)) - TableName = TableName.Upper(); - - SQLFreeStmt(hstmt, SQL_CLOSE); - RETCODE retcode; - - // Some databases cannot accept a user name when looking up table names, - // so we use the call below that leaves out the user name - if (!UserID.empty() && - Dbms() != dbmsMY_SQL && - Dbms() != dbmsACCESS && - Dbms() != dbmsMS_SQL_SERVER && - Dbms() != dbmsDB2 && - Dbms() != dbmsFIREBIRD && - Dbms() != dbmsINTERBASE && - Dbms() != dbmsPERVASIVE_SQL) - { - retcode = SQLTables(hstmt, - NULL, 0, // All qualifiers - (SQLTCHAR *) UserID.c_str(), SQL_NTS, // Only tables owned by this user - (SQLTCHAR FAR *)TableName.c_str(), SQL_NTS, - NULL, 0); // All table types - } - else - { - retcode = SQLTables(hstmt, - NULL, 0, // All qualifiers - NULL, 0, // All owners - (SQLTCHAR FAR *)TableName.c_str(), SQL_NTS, - NULL, 0); // All table types - } - if (retcode != SQL_SUCCESS) - return(DispAllErrors(henv, hdbc, hstmt)); - - retcode = SQLFetch(hstmt); - if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO) - { - SQLFreeStmt(hstmt, SQL_CLOSE); - return(DispAllErrors(henv, hdbc, hstmt)); - } - - SQLFreeStmt(hstmt, SQL_CLOSE); - - return true; - -} // wxDb::TableExists() - - -/********** wxDb::TablePrivileges() **********/ -bool wxDb::TablePrivileges(const wxString &tableName, const wxString &priv, const wxChar *userID, - const wxChar *schema, const wxString &WXUNUSED(tablePath)) -{ - wxASSERT(tableName.length()); - - wxDbTablePrivilegeInfo result; - SQLLEN cbRetVal; - RETCODE retcode; - - // We probably need to be able to dynamically set this based on - // the driver type, and state. - wxChar curRole[]=wxT("public"); - - wxString TableName; - - wxString UserID,Schema; - convertUserID(userID,UserID); - convertUserID(schema,Schema); - - TableName = tableName; - // Oracle and Interbase table names are uppercase only, so force - // the name to uppercase just in case programmer forgot to do this - if ((Dbms() == dbmsORACLE) || - (Dbms() == dbmsFIREBIRD) || - (Dbms() == dbmsINTERBASE)) - TableName = TableName.Upper(); - - SQLFreeStmt(hstmt, SQL_CLOSE); - - // Some databases cannot accept a user name when looking up table names, - // so we use the call below that leaves out the user name - if (!Schema.empty() && - Dbms() != dbmsMY_SQL && - Dbms() != dbmsACCESS && - Dbms() != dbmsMS_SQL_SERVER) - { - retcode = SQLTablePrivileges(hstmt, - NULL, 0, // Catalog - (SQLTCHAR FAR *)Schema.c_str(), SQL_NTS, // Schema - (SQLTCHAR FAR *)TableName.c_str(), SQL_NTS); - } - else - { - retcode = SQLTablePrivileges(hstmt, - NULL, 0, // Catalog - NULL, 0, // Schema - (SQLTCHAR FAR *)TableName.c_str(), SQL_NTS); - } - -#ifdef DBDEBUG_CONSOLE - wxFprintf(stderr ,wxT("SQLTablePrivileges() returned %i \n"),retcode); -#endif - - if ((retcode != SQL_SUCCESS) && (retcode != SQL_SUCCESS_WITH_INFO)) - return (DispAllErrors(henv, hdbc, hstmt)); - - bool failed = false; - retcode = SQLFetch(hstmt); - while (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) - { - if (SQLGetData(hstmt, 1, SQL_C_WXCHAR, (UCHAR*) result.tableQual, sizeof(result.tableQual), &cbRetVal) != SQL_SUCCESS) - failed = true; - - if (!failed && SQLGetData(hstmt, 2, SQL_C_WXCHAR, (UCHAR*) result.tableOwner, sizeof(result.tableOwner), &cbRetVal) != SQL_SUCCESS) - failed = true; - - if (!failed && SQLGetData(hstmt, 3, SQL_C_WXCHAR, (UCHAR*) result.tableName, sizeof(result.tableName), &cbRetVal) != SQL_SUCCESS) - failed = true; - - if (!failed && SQLGetData(hstmt, 4, SQL_C_WXCHAR, (UCHAR*) result.grantor, sizeof(result.grantor), &cbRetVal) != SQL_SUCCESS) - failed = true; - - if (!failed && SQLGetData(hstmt, 5, SQL_C_WXCHAR, (UCHAR*) result.grantee, sizeof(result.grantee), &cbRetVal) != SQL_SUCCESS) - failed = true; - - if (!failed && SQLGetData(hstmt, 6, SQL_C_WXCHAR, (UCHAR*) result.privilege, sizeof(result.privilege), &cbRetVal) != SQL_SUCCESS) - failed = true; - - if (!failed && SQLGetData(hstmt, 7, SQL_C_WXCHAR, (UCHAR*) result.grantable, sizeof(result.grantable), &cbRetVal) != SQL_SUCCESS) - failed = true; - - if (failed) - { - return(DispAllErrors(henv, hdbc, hstmt)); - } -#ifdef DBDEBUG_CONSOLE - wxFprintf(stderr,wxT("Scanning %s privilege on table %s.%s granted by %s to %s\n"), - result.privilege,result.tableOwner,result.tableName, - result.grantor, result.grantee); -#endif - - if (UserID.IsSameAs(result.tableOwner,false)) - { - SQLFreeStmt(hstmt, SQL_CLOSE); - return true; - } - - if (UserID.IsSameAs(result.grantee,false) && - !wxStrcmp(result.privilege,priv)) - { - SQLFreeStmt(hstmt, SQL_CLOSE); - return true; - } - - if (!wxStrcmp(result.grantee,curRole) && - !wxStrcmp(result.privilege,priv)) - { - SQLFreeStmt(hstmt, SQL_CLOSE); - return true; - } - - retcode = SQLFetch(hstmt); - } - - SQLFreeStmt(hstmt, SQL_CLOSE); - return false; - -} // wxDb::TablePrivileges - - -const wxString wxDb::SQLTableName(const wxChar *tableName) -{ - wxString TableName; - - if (Dbms() == dbmsACCESS) - TableName = _T("\""); - TableName += tableName; - if (Dbms() == dbmsACCESS) - TableName += _T("\""); - - return TableName; -} // wxDb::SQLTableName() - - -const wxString wxDb::SQLColumnName(const wxChar *colName) -{ - wxString ColName; - - if (Dbms() == dbmsACCESS) - ColName = _T("\""); - ColName += colName; - if (Dbms() == dbmsACCESS) - ColName += _T("\""); - - return ColName; -} // wxDb::SQLColumnName() - - -/********** wxDb::SetSqlLogging() **********/ -bool wxDb::SetSqlLogging(wxDbSqlLogState state, const wxString &filename, bool append) -{ - wxASSERT(state == sqlLogON || state == sqlLogOFF); - wxASSERT(state == sqlLogOFF || filename.length()); - - if (state == sqlLogON) - { - if (fpSqlLog == 0) - { - fpSqlLog = wxFopen(filename.c_str(), (append ? wxT("at") : wxT("wt"))); - if (fpSqlLog == NULL) - return false; - } - } - else // sqlLogOFF - { - if (fpSqlLog) - { - if (fclose(fpSqlLog)) - return false; - fpSqlLog = 0; - } - } - - sqlLogState = state; - return true; - -} // wxDb::SetSqlLogging() - - -/********** wxDb::WriteSqlLog() **********/ -bool wxDb::WriteSqlLog(const wxString &logMsg) -{ - wxASSERT(logMsg.length()); - - if (fpSqlLog == 0 || sqlLogState == sqlLogOFF) - return false; - - if (wxFputs(wxT("\n"), fpSqlLog) == EOF) - return false; - if (wxFputs(logMsg, fpSqlLog) == EOF) - return false; - if (wxFputs(wxT("\n"), fpSqlLog) == EOF) - return false; - - return true; - -} // wxDb::WriteSqlLog() - - -/********** wxDb::Dbms() **********/ -wxDBMS wxDb::Dbms(void) -/* - * Be aware that not all database engines use the exact same syntax, and not - * every ODBC compliant database is compliant to the same level of compliancy. - * Some manufacturers support the minimum Level 1 compliancy, and others up - * through Level 3. Others support subsets of features for levels above 1. - * - * If you find an inconsistency between the wxDb class and a specific database - * engine, and an identifier to this section, and special handle the database in - * the area where behavior is non-conforming with the other databases. - * - * - * NOTES ABOUT ISSUES SPECIFIC TO EACH DATABASE ENGINE - * --------------------------------------------------- - * - * ORACLE - * - Currently the only database supported by the class to support VIEWS - * - * DBASE - * - Does not support the SQL_TIMESTAMP structure - * - Supports only one cursor and one connect (apparently? with Microsoft driver only?) - * - Does not automatically create the primary index if the 'keyField' param of SetColDef - * is true. The user must create ALL indexes from their program. - * - Table names can only be 8 characters long - * - Column names can only be 10 characters long - * - * SYBASE (all) - * - To lock a record during QUERY functions, the reserved word 'HOLDLOCK' must be added - * after every table name involved in the query/join if that tables matching record(s) - * are to be locked - * - Ignores the keywords 'FOR UPDATE'. Use the HOLDLOCK functionality described above - * - * SYBASE (Enterprise) - * - If a column is part of the Primary Key, the column cannot be NULL - * - Maximum row size is somewhere in the neighborhood of 1920 bytes - * - * MY_SQL - * - If a column is part of the Primary Key, the column cannot be NULL - * - Cannot support selecting for update [::CanSelectForUpdate()]. Always returns FALSE - * - Columns that are part of primary or secondary keys must be defined as being NOT NULL - * when they are created. Some code is added in ::CreateIndex to try to adjust the - * column definition if it is not defined correctly, but it is experimental - * - Does not support sub-queries in SQL statements - * - * POSTGRES - * - Does not support the keywords 'ASC' or 'DESC' as of release v6.5.0 - * - Does not support sub-queries in SQL statements - * - * DB2 - * - Primary keys must be declared as NOT NULL - * - Table and index names must not be longer than 13 characters in length (technically - * table names can be up to 18 characters, but the primary index is created using the - * base table name plus "_PIDX", so the limit if the table has a primary index is 13. - * - * PERVASIVE SQL - * - * INTERBASE - * - Columns that are part of primary keys must be defined as being NOT NULL - * when they are created. Some code is added in ::CreateIndex to try to adjust the - * column definition if it is not defined correctly, but it is experimental - */ -{ - // Should only need to do this once for each new database connection - // so return the value we already determined it to be to save time - // and lots of string comparisons - if (dbmsType != dbmsUNIDENTIFIED) - return(dbmsType); - -#ifdef DBDEBUG_CONSOLE - // When run in console mode, use standard out to display errors. - cout << "Database connecting to: " << dbInf.dbmsName << endl; -#endif // DBDEBUG_CONSOLE - - wxLogDebug(wxT("Database connecting to: ")); - wxLogDebug(dbInf.dbmsName); - - wxChar baseName[25+1]; - wxStrncpy(baseName, dbInf.dbmsName, 25); - baseName[25] = 0; - - // RGG 20001025 : add support for Interbase - // GT : Integrated to base classes on 20001121 - if (!wxStricmp(dbInf.dbmsName,wxT("Interbase"))) - return((wxDBMS)(dbmsType = dbmsINTERBASE)); - - // BJO 20000428 : add support for Virtuoso - if (!wxStricmp(dbInf.dbmsName,wxT("OpenLink Virtuoso VDBMS"))) - return((wxDBMS)(dbmsType = dbmsVIRTUOSO)); - - if (!wxStricmp(dbInf.dbmsName,wxT("Adaptive Server Anywhere"))) - return((wxDBMS)(dbmsType = dbmsSYBASE_ASA)); - - // BJO 20000427 : The "SQL Server" string is also returned by SQLServer when - // connected through an OpenLink driver. - // Is it also returned by Sybase Adapatitve server? - // OpenLink driver name is OLOD3032.DLL for msw and oplodbc.so for unix - if (!wxStricmp(dbInf.dbmsName,wxT("SQL Server"))) - { - if (!wxStrncmp(dbInf.driverName, wxT("oplodbc"), 7) || - !wxStrncmp(dbInf.driverName, wxT("OLOD"), 4)) - return ((wxDBMS)(dbmsMS_SQL_SERVER)); - else - return ((wxDBMS)(dbmsType = dbmsSYBASE_ASE)); - } - - if (!wxStricmp(dbInf.dbmsName,wxT("Microsoft SQL Server"))) - return((wxDBMS)(dbmsType = dbmsMS_SQL_SERVER)); - - baseName[10] = 0; - if (!wxStricmp(baseName,wxT("PostgreSQL"))) // v6.5.0 - return((wxDBMS)(dbmsType = dbmsPOSTGRES)); - - baseName[9] = 0; - if (!wxStricmp(baseName,wxT("Pervasive"))) - return((wxDBMS)(dbmsType = dbmsPERVASIVE_SQL)); - - baseName[8] = 0; - if (!wxStricmp(baseName,wxT("Informix"))) - return((wxDBMS)(dbmsType = dbmsINFORMIX)); - - if (!wxStricmp(baseName,wxT("Firebird"))) - return((wxDBMS)(dbmsType = dbmsFIREBIRD)); - - baseName[6] = 0; - if (!wxStricmp(baseName,wxT("Oracle"))) - return((wxDBMS)(dbmsType = dbmsORACLE)); - if (!wxStricmp(baseName,wxT("ACCESS"))) - return((wxDBMS)(dbmsType = dbmsACCESS)); - if (!wxStricmp(baseName,wxT("Sybase"))) - return((wxDBMS)(dbmsType = dbmsSYBASE_ASE)); - - baseName[5] = 0; - if (!wxStricmp(baseName,wxT("DBASE"))) - return((wxDBMS)(dbmsType = dbmsDBASE)); - if (!wxStricmp(baseName,wxT("xBase"))) - return((wxDBMS)(dbmsType = dbmsXBASE_SEQUITER)); - if (!wxStricmp(baseName,wxT("MySQL"))) - return((wxDBMS)(dbmsType = dbmsMY_SQL)); - if (!wxStricmp(baseName,wxT("MaxDB"))) - return((wxDBMS)(dbmsType = dbmsMAXDB)); - - baseName[3] = 0; - if (!wxStricmp(baseName,wxT("DB2"))) - return((wxDBMS)(dbmsType = dbmsDB2)); - - return((wxDBMS)(dbmsType = dbmsUNIDENTIFIED)); - -} // wxDb::Dbms() - - -bool wxDb::ModifyColumn(const wxString &tableName, const wxString &columnName, - int dataType, ULONG columnLength, - const wxString &optionalParam) -{ - wxASSERT(tableName.length()); - wxASSERT(columnName.length()); - wxASSERT((dataType == DB_DATA_TYPE_VARCHAR && columnLength > 0) || - dataType != DB_DATA_TYPE_VARCHAR); - - // Must specify a columnLength if modifying a VARCHAR type column - if (dataType == DB_DATA_TYPE_VARCHAR && !columnLength) - return false; - - wxString dataTypeName; - wxString sqlStmt; - wxString alterSlashModify; - - switch(dataType) - { - case DB_DATA_TYPE_VARCHAR : - dataTypeName = typeInfVarchar.TypeName; - break; - case DB_DATA_TYPE_INTEGER : - dataTypeName = typeInfInteger.TypeName; - break; - case DB_DATA_TYPE_FLOAT : - dataTypeName = typeInfFloat.TypeName; - break; - case DB_DATA_TYPE_DATE : - dataTypeName = typeInfDate.TypeName; - break; - case DB_DATA_TYPE_BLOB : - dataTypeName = typeInfBlob.TypeName; - break; - default: - return false; - } - - // Set the modify or alter syntax depending on the type of database connected to - switch (Dbms()) - { - case dbmsORACLE : - alterSlashModify = _T("MODIFY"); - break; - case dbmsMS_SQL_SERVER : - alterSlashModify = _T("ALTER COLUMN"); - break; - case dbmsUNIDENTIFIED : - return false; - case dbmsSYBASE_ASA : - case dbmsSYBASE_ASE : - case dbmsMY_SQL : - case dbmsPOSTGRES : - case dbmsACCESS : - case dbmsDBASE : - case dbmsXBASE_SEQUITER : - default : - alterSlashModify = _T("MODIFY"); - break; - } - - // create the SQL statement - if ( Dbms() == dbmsMY_SQL ) - { - sqlStmt.Printf(wxT("ALTER TABLE %s %s %s %s"), tableName.c_str(), alterSlashModify.c_str(), - columnName.c_str(), dataTypeName.c_str()); - } - else - { - sqlStmt.Printf(wxT("ALTER TABLE \"%s\" \"%s\" \"%s\" %s"), tableName.c_str(), alterSlashModify.c_str(), - columnName.c_str(), dataTypeName.c_str()); - } - - // For varchars only, append the size of the column - if (dataType == DB_DATA_TYPE_VARCHAR && - (Dbms() != dbmsMY_SQL || dataTypeName != _T("text"))) - { - wxString s; - s.Printf(wxT("(%lu)"), columnLength); - sqlStmt += s; - } - - // for passing things like "NOT NULL" - if (optionalParam.length()) - { - sqlStmt += wxT(" "); - sqlStmt += optionalParam; - } - - return ExecSql(sqlStmt); - -} // wxDb::ModifyColumn() - -/********** wxDb::EscapeSqlChars() **********/ -wxString wxDb::EscapeSqlChars(const wxString& valueOrig) -{ - wxString value(valueOrig); - switch (Dbms()) - { - case dbmsACCESS: - // Access doesn't seem to care about backslashes, so only escape single quotes. - value.Replace(wxT("'"), wxT("''")); - break; - - default: - // All the others are supposed to be the same for now, add special - // handling for them if necessary - value.Replace(wxT("\\"), wxT("\\\\")); - value.Replace(wxT("'"), wxT("\\'")); - break; - } - - return value; -} // wxDb::EscapeSqlChars() - - -/********** wxDbGetConnection() **********/ -wxDb WXDLLIMPEXP_ODBC *wxDbGetConnection(wxDbConnectInf *pDbConfig, bool FwdOnlyCursors) -{ - wxDbList *pList; - - // Used to keep a pointer to a DB connection that matches the requested - // DSN and FwdOnlyCursors settings, even if it is not FREE, so that the - // data types can be copied from it (using the wxDb::Open(wxDb *) function) - // rather than having to re-query the datasource to get all the values - // using the wxDb::Open(Dsn,Uid,AuthStr) function - wxDb *matchingDbConnection = NULL; - - // Scan the linked list searching for an available database connection - // that's already been opened but is currently not in use. - for (pList = PtrBegDbList; pList; pList = pList->PtrNext) - { - // The database connection must be for the same datasource - // name and must currently not be in use. - if (pList->Free && - (pList->PtrDb->FwdOnlyCursors() == FwdOnlyCursors)) - { - if (pDbConfig->UseConnectionStr()) - { - if (pList->PtrDb->OpenedWithConnectionString() && - (!wxStrcmp(pDbConfig->GetConnectionStr(), pList->ConnectionStr))) - { - // Found a free connection - pList->Free = false; - return(pList->PtrDb); - } - } - else - { - if (!pList->PtrDb->OpenedWithConnectionString() && - (!wxStrcmp(pDbConfig->GetDsn(), pList->Dsn))) - { - // Found a free connection - pList->Free = false; - return(pList->PtrDb); - } - } - } - - if (pDbConfig->UseConnectionStr()) - { - if (!wxStrcmp(pDbConfig->GetConnectionStr(), pList->ConnectionStr)) - matchingDbConnection = pList->PtrDb; - } - else - { - if (!wxStrcmp(pDbConfig->GetDsn(), pList->Dsn) && - !wxStrcmp(pDbConfig->GetUserID(), pList->Uid) && - !wxStrcmp(pDbConfig->GetPassword(), pList->AuthStr)) - matchingDbConnection = pList->PtrDb; - } - } - - // No available connections. A new connection must be made and - // appended to the end of the linked list. - if (PtrBegDbList) - { - // Find the end of the list - for (pList = PtrBegDbList; pList->PtrNext; pList = pList->PtrNext); - // Append a new list item - pList->PtrNext = new wxDbList; - pList->PtrNext->PtrPrev = pList; - pList = pList->PtrNext; - } - else // Empty list - { - // Create the first node on the list - pList = PtrBegDbList = new wxDbList; - pList->PtrPrev = 0; - } - - // Initialize new node in the linked list - pList->PtrNext = 0; - pList->Free = false; - pList->Dsn = pDbConfig->GetDsn(); - pList->Uid = pDbConfig->GetUserID(); - pList->AuthStr = pDbConfig->GetPassword(); - pList->ConnectionStr = pDbConfig->GetConnectionStr(); - - pList->PtrDb = new wxDb(pDbConfig->GetHenv(), FwdOnlyCursors); - - bool opened; - - if (!matchingDbConnection) - { - if (pDbConfig->UseConnectionStr()) - { - opened = pList->PtrDb->Open(pDbConfig->GetConnectionStr()); - } - else - { - opened = pList->PtrDb->Open(pDbConfig->GetDsn(), pDbConfig->GetUserID(), pDbConfig->GetPassword()); - } - } - else - opened = pList->PtrDb->Open(matchingDbConnection); - - // Connect to the datasource - if (opened) - { - pList->PtrDb->setCached(true); // Prevent a user from deleting a cached connection - pList->PtrDb->SetSqlLogging(SQLLOGstate, SQLLOGfn, true); - return(pList->PtrDb); - } - else // Unable to connect, destroy list item - { - if (pList->PtrPrev) - pList->PtrPrev->PtrNext = 0; - else - PtrBegDbList = 0; // Empty list again - - pList->PtrDb->CommitTrans(); // Commit any open transactions on wxDb object - pList->PtrDb->Close(); // Close the wxDb object - delete pList->PtrDb; // Deletes the wxDb object - delete pList; // Deletes the linked list object - return(0); - } - -} // wxDbGetConnection() - - -/********** wxDbFreeConnection() **********/ -bool WXDLLIMPEXP_ODBC wxDbFreeConnection(wxDb *pDb) -{ - wxDbList *pList; - - // Scan the linked list searching for the database connection - for (pList = PtrBegDbList; pList; pList = pList->PtrNext) - { - if (pList->PtrDb == pDb) // Found it, now free it!!! - return (pList->Free = true); - } - - // Never found the database object, return failure - return false; - -} // wxDbFreeConnection() - - -/********** wxDbCloseConnections() **********/ -void WXDLLIMPEXP_ODBC wxDbCloseConnections(void) -{ - wxDbList *pList, *pNext; - - // Traverse the linked list closing database connections and freeing memory as I go. - for (pList = PtrBegDbList; pList; pList = pNext) - { - pNext = pList->PtrNext; // Save the pointer to next - pList->PtrDb->CommitTrans(); // Commit any open transactions on wxDb object - pList->PtrDb->Close(); // Close the wxDb object - pList->PtrDb->setCached(false); // Allows deletion of the wxDb instance - delete pList->PtrDb; // Deletes the wxDb object - delete pList; // Deletes the linked list object - } - - // Mark the list as empty - PtrBegDbList = 0; - -} // wxDbCloseConnections() - - -/********** wxDbConnectionsInUse() **********/ -int WXDLLIMPEXP_ODBC wxDbConnectionsInUse(void) -{ - wxDbList *pList; - int cnt = 0; - - // Scan the linked list counting db connections that are currently in use - for (pList = PtrBegDbList; pList; pList = pList->PtrNext) - { - if (pList->Free == false) - cnt++; - } - - return(cnt); - -} // wxDbConnectionsInUse() - - - -/********** wxDbLogExtendedErrorMsg() **********/ -// DEBUG ONLY function -const wxChar WXDLLIMPEXP_ODBC *wxDbLogExtendedErrorMsg(const wxChar *userText, - wxDb *pDb, - const wxChar *ErrFile, - int ErrLine) -{ - static wxString msg; - msg = userText; - - wxString tStr; - - if (ErrFile || ErrLine) - { - msg += wxT("File: "); - msg += ErrFile; - msg += wxT(" Line: "); - tStr.Printf(wxT("%d"),ErrLine); - msg += tStr.c_str(); - msg += wxT("\n"); - } - - msg.Append (wxT("\nODBC errors:\n")); - msg += wxT("\n"); - - // Display errors for this connection - int i; - for (i = 0; i < DB_MAX_ERROR_HISTORY; i++) - { - if (pDb->errorList[i]) - { - msg.Append(pDb->errorList[i]); - if (wxStrcmp(pDb->errorList[i], wxEmptyString) != 0) - msg.Append(wxT("\n")); - // Clear the errmsg buffer so the next error will not - // end up showing the previous error that have occurred - wxStrcpy(pDb->errorList[i], wxEmptyString); - } - } - msg += wxT("\n"); - - wxLogDebug(msg.c_str()); - - return msg.c_str(); -} // wxDbLogExtendedErrorMsg() - - -/********** wxDbSqlLog() **********/ -bool wxDbSqlLog(wxDbSqlLogState state, const wxChar *filename) -{ - bool append = false; - wxDbList *pList; - - for (pList = PtrBegDbList; pList; pList = pList->PtrNext) - { - if (!pList->PtrDb->SetSqlLogging(state,filename,append)) - return false; - append = true; - } - - SQLLOGstate = state; - SQLLOGfn = filename; - - return true; - -} // wxDbSqlLog() - - -#if 0 -/********** wxDbCreateDataSource() **********/ -int wxDbCreateDataSource(const wxString &driverName, const wxString &dsn, const wxString &description, - bool sysDSN, const wxString &defDir, wxWindow *parent) -/* - * !!!! ONLY FUNCTIONAL UNDER MSW with VC6 !!!! - * Very rudimentary creation of an ODBC data source. - * - * ODBC driver must be ODBC 3.0 compliant to use this function - */ -{ - int result = FALSE; - -//!!!! ONLY FUNCTIONAL UNDER MSW with VC6 !!!! -#ifdef __VISUALC__ - int dsnLocation; - wxString setupStr; - - if (sysDSN) - dsnLocation = ODBC_ADD_SYS_DSN; - else - dsnLocation = ODBC_ADD_DSN; - - // NOTE: The decimal 2 is an invalid character in all keyword pairs - // so that is why I used it, as wxString does not deal well with - // embedded nulls in strings - setupStr.Printf(wxT("DSN=%s%cDescription=%s%cDefaultDir=%s%c"),dsn,2,description,2,defDir,2); - - // Replace the separator from above with the '\0' separator needed - // by the SQLConfigDataSource() function - int k; - do - { - k = setupStr.Find((wxChar)2,true); - if (k != wxNOT_FOUND) - setupStr[(UINT)k] = wxT('\0'); - } - while (k != wxNOT_FOUND); - - result = SQLConfigDataSource((HWND)parent->GetHWND(), dsnLocation, - driverName, setupStr.c_str()); - - if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) - { - // check for errors caused by ConfigDSN based functions - DWORD retcode = 0; - WORD cb; - wxChar errMsg[SQL_MAX_MESSAGE_LENGTH]; - errMsg[0] = wxT('\0'); - - // This function is only supported in ODBC drivers v3.0 compliant and above - SQLInstallerError(1,&retcode,errMsg,SQL_MAX_MESSAGE_LENGTH-1,&cb); - if (retcode) - { -#ifdef DBDEBUG_CONSOLE - // When run in console mode, use standard out to display errors. - cout << errMsg << endl; - cout << wxT("Press any key to continue...") << endl; - getchar(); -#endif // DBDEBUG_CONSOLE - -#ifdef __WXDEBUG__ - wxLogDebug(errMsg,wxT("ODBC DEBUG MESSAGE")); -#endif // __WXDEBUG__ - } - } - else - result = TRUE; -#else - // Using iODBC/unixODBC or some other compiler which does not support the APIs - // necessary to use this function, so this function is not supported -#ifdef __WXDEBUG__ - wxLogDebug(wxT("wxDbCreateDataSource() not available except under VC++/MSW"),wxT("ODBC DEBUG MESSAGE")); -#endif - result = FALSE; -#endif // __VISUALC__ - - return result; - -} // wxDbCreateDataSource() -#endif - - -/********** wxDbGetDataSource() **********/ -bool wxDbGetDataSource(HENV henv, wxChar *Dsn, SWORD DsnMaxLength, wxChar *DsDesc, - SWORD DsDescMaxLength, UWORD direction) -/* - * Dsn and DsDesc will contain the data source name and data source - * description upon return - */ -{ - SWORD cb1,cb2; - SWORD lengthDsn = (SWORD)(DsnMaxLength*sizeof(wxChar)); - SWORD lengthDsDesc = (SWORD)(DsDescMaxLength*sizeof(wxChar)); - - if (SQLDataSources(henv, direction, (SQLTCHAR FAR *) Dsn, lengthDsn, &cb1, - (SQLTCHAR FAR *) DsDesc, lengthDsDesc, &cb2) == SQL_SUCCESS) - return true; - else - return false; - -} // wxDbGetDataSource() - - -// Change this to 0 to remove use of all deprecated functions -#if wxODBC_BACKWARD_COMPATABILITY -/******************************************************************** - ******************************************************************** - * - * The following functions are all DEPRECATED and are included for - * backward compatibility reasons only - * - ******************************************************************** - ********************************************************************/ -bool SqlLog(sqlLog state, const wxChar *filename) -{ - return wxDbSqlLog((enum wxDbSqlLogState)state, filename); -} -/***** DEPRECATED: use wxGetDataSource() *****/ -bool GetDataSource(HENV henv, char *Dsn, SWORD DsnMax, char *DsDesc, SWORD DsDescMax, - UWORD direction) -{ - return wxDbGetDataSource(henv, Dsn, DsnMax, DsDesc, DsDescMax, direction); -} -/***** DEPRECATED: use wxDbGetConnection() *****/ -wxDb WXDLLIMPEXP_ODBC *GetDbConnection(DbStuff *pDbStuff, bool FwdOnlyCursors) -{ - return wxDbGetConnection((wxDbConnectInf *)pDbStuff, FwdOnlyCursors); -} -/***** DEPRECATED: use wxDbFreeConnection() *****/ -bool WXDLLIMPEXP_ODBC FreeDbConnection(wxDb *pDb) -{ - return wxDbFreeConnection(pDb); -} -/***** DEPRECATED: use wxDbCloseConnections() *****/ -void WXDLLIMPEXP_ODBC CloseDbConnections(void) -{ - wxDbCloseConnections(); -} -/***** DEPRECATED: use wxDbConnectionsInUse() *****/ -int WXDLLIMPEXP_ODBC NumberDbConnectionsInUse(void) -{ - return wxDbConnectionsInUse(); -} -#endif - - -#endif - // wxUSE_ODBC +/////////////////////////////////////////////////////////////////////////////// +// Name: src/common/db.cpp +// Purpose: Implementation of the wxDb class. The wxDb class represents a connection +// to an ODBC data source. The wxDb class allows operations on the data +// source such as opening and closing the data source. +// Author: Doug Card +// Modified by: George Tasker +// Bart Jourquin +// Mark Johnson, wxWindows@mj10777.de +// Mods: Dec, 1998: +// -Added support for SQL statement logging and database cataloging +// Mods: April, 1999 +// -Added QUERY_ONLY mode support to reduce default number of cursors +// -Added additional SQL logging code +// -Added DEBUG-ONLY tracking of wxTable objects to detect orphaned DB connections +// -Set ODBC option to only read committed writes to the DB so all +// databases operate the same in that respect +// Created: 9.96 +// RCS-ID: $Id: db.cpp 52489 2008-03-14 14:14:57Z JS $ +// Copyright: (c) 1996 Remstar International, Inc. +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_ODBC + +#ifndef WX_PRECOMP + #include "wx/object.h" + #include "wx/list.h" + #include "wx/string.h" + #include "wx/utils.h" + #include "wx/log.h" + #include "wx/app.h" +#endif + +#ifdef DBDEBUG_CONSOLE + #include "wx/ioswrap.h" +#endif + +#include "wx/filefn.h" +#include "wx/wxchar.h" + +#include +#include +#include +#include +#include + +#include "wx/db.h" + +// DLL options compatibility check: +WX_CHECK_BUILD_OPTIONS("wxODBC") + +WXDLLIMPEXP_DATA_ODBC(wxDbList*) PtrBegDbList = 0; + +wxChar const *SQL_LOG_FILENAME = wxT("sqllog.txt"); +wxChar const *SQL_CATALOG_FILENAME = wxT("catalog.txt"); + +#ifdef __WXDEBUG__ + #include "wx/thread.h" + + extern wxList TablesInUse; +#if wxUSE_THREADS + extern wxCriticalSection csTablesInUse; +#endif // wxUSE_THREADS +#endif + +// SQL Log defaults to be used by GetDbConnection +wxDbSqlLogState SQLLOGstate = sqlLogOFF; + +static wxString SQLLOGfn = SQL_LOG_FILENAME; + +// The wxDb::errorList is copied to this variable when the wxDb object +// is closed. This way, the error list is still available after the +// database object is closed. This is necessary if the database +// connection fails so the calling application can show the operator +// why the connection failed. Note: as each wxDb object is closed, it +// will overwrite the errors of the previously destroyed wxDb object in +// this variable. NOTE: This occurs during a CLOSE, not a FREEing of the +// connection +wxChar DBerrorList[DB_MAX_ERROR_HISTORY][DB_MAX_ERROR_MSG_LEN+1]; + + +// This type defines the return row-struct form +// SQLTablePrivileges, and is used by wxDB::TablePrivileges. +typedef struct +{ + wxChar tableQual[128+1]; + wxChar tableOwner[128+1]; + wxChar tableName[128+1]; + wxChar grantor[128+1]; + wxChar grantee[128+1]; + wxChar privilege[128+1]; + wxChar grantable[3+1]; +} wxDbTablePrivilegeInfo; + + +/********** wxDbConnectInf Constructor - form 1 **********/ +wxDbConnectInf::wxDbConnectInf() +{ + Henv = 0; + freeHenvOnDestroy = false; + + Initialize(); +} // Constructor + + +/********** wxDbConnectInf Constructor - form 2 **********/ +wxDbConnectInf::wxDbConnectInf(HENV henv, const wxString &dsn, const wxString &userID, + const wxString &password, const wxString &defaultDir, + const wxString &fileType, const wxString &description) +{ + Henv = 0; + freeHenvOnDestroy = false; + + Initialize(); + + if (henv) + SetHenv(henv); + else + AllocHenv(); + + SetDsn(dsn); + SetUserID(userID); + SetPassword(password); + SetDescription(description); + SetFileType(fileType); + SetDefaultDir(defaultDir); +} // wxDbConnectInf Constructor + + +wxDbConnectInf::~wxDbConnectInf() +{ + if (freeHenvOnDestroy) + { + FreeHenv(); + } +} // wxDbConnectInf Destructor + + + +/********** wxDbConnectInf::Initialize() **********/ +bool wxDbConnectInf::Initialize() +{ + freeHenvOnDestroy = false; + + if (freeHenvOnDestroy && Henv) + FreeHenv(); + + Henv = 0; + Dsn[0] = 0; + Uid[0] = 0; + AuthStr[0] = 0; + ConnectionStr[0] = 0; + Description.Empty(); + FileType.Empty(); + DefaultDir.Empty(); + + useConnectionStr = false; + + return true; +} // wxDbConnectInf::Initialize() + + +/********** wxDbConnectInf::AllocHenv() **********/ +bool wxDbConnectInf::AllocHenv() +{ + // This is here to help trap if you are getting a new henv + // without releasing an existing henv + wxASSERT(!Henv); + + // Initialize the ODBC Environment for Database Operations + if (SQLAllocEnv(&Henv) != SQL_SUCCESS) + { + wxLogDebug(wxT("A problem occurred while trying to get a connection to the data source")); + return false; + } + + freeHenvOnDestroy = true; + + return true; +} // wxDbConnectInf::AllocHenv() + + +void wxDbConnectInf::FreeHenv() +{ + wxASSERT(Henv); + + if (Henv) + SQLFreeEnv(Henv); + + Henv = 0; + freeHenvOnDestroy = false; + +} // wxDbConnectInf::FreeHenv() + + +void wxDbConnectInf::SetDsn(const wxString &dsn) +{ + wxASSERT(dsn.length() < WXSIZEOF(Dsn)); + + wxStrncpy(Dsn, dsn, WXSIZEOF(Dsn)-1); + Dsn[WXSIZEOF(Dsn)-1] = 0; // Prevent buffer overrun +} // wxDbConnectInf::SetDsn() + + +void wxDbConnectInf::SetUserID(const wxString &uid) +{ + wxASSERT(uid.length() < WXSIZEOF(Uid)); + wxStrncpy(Uid, uid, WXSIZEOF(Uid)-1); + Uid[WXSIZEOF(Uid)-1] = 0; // Prevent buffer overrun +} // wxDbConnectInf::SetUserID() + + +void wxDbConnectInf::SetPassword(const wxString &password) +{ + wxASSERT(password.length() < WXSIZEOF(AuthStr)); + + wxStrncpy(AuthStr, password, WXSIZEOF(AuthStr)-1); + AuthStr[WXSIZEOF(AuthStr)-1] = 0; // Prevent buffer overrun +} // wxDbConnectInf::SetPassword() + +void wxDbConnectInf::SetConnectionStr(const wxString &connectStr) +{ + wxASSERT(connectStr.length() < WXSIZEOF(ConnectionStr)); + + useConnectionStr = wxStrlen(connectStr) > 0; + + wxStrncpy(ConnectionStr, connectStr, WXSIZEOF(ConnectionStr)-1); + ConnectionStr[WXSIZEOF(ConnectionStr)-1] = 0; // Prevent buffer overrun +} // wxDbConnectInf::SetConnectionStr() + + +/********** wxDbColFor Constructor **********/ +wxDbColFor::wxDbColFor() +{ + Initialize(); +} // wxDbColFor::wxDbColFor() + + +/********** wxDbColFor::Initialize() **********/ +void wxDbColFor::Initialize() +{ + s_Field.Empty(); + int i; + for (i=0; i<7; i++) + { + s_Format[i].Empty(); + s_Amount[i].Empty(); + i_Amount[i] = 0; + } + i_Nation = 0; // 0=EU, 1=UK, 2=International, 3=US + i_dbDataType = 0; + i_sqlDataType = 0; + Format(1,DB_DATA_TYPE_VARCHAR,0,0,0); // the Function that does the work +} // wxDbColFor::Initialize() + + +/********** wxDbColFor::Format() **********/ +int wxDbColFor::Format(int Nation, int dbDataType, SWORD sqlDataType, + short columnLength, short decimalDigits) +{ + // ---------------------------------------------------------------------------------------- + // -- 19991224 : mj10777 : Create + // There is still a lot of work to do here, but it is a start + // It handles all the basic data-types that I have run into up to now + // The main work will have be with Dates and float Formatting + // (US 1,000.00 ; EU 1.000,00) + // There are wxWindow plans for locale support and the new wxDateTime. If + // they define some constants (wxEUROPEAN) that can be gloably used, + // they should be used here. + // ---------------------------------------------------------------------------------------- + // There should also be a function to scan in a string to fill the variable + // ---------------------------------------------------------------------------------------- + wxString tempStr; + i_Nation = Nation; // 0 = timestamp , 1=EU, 2=UK, 3=International, 4=US + i_dbDataType = dbDataType; + i_sqlDataType = sqlDataType; + s_Field.Printf(wxT("%s%d"),s_Amount[1].c_str(),i_Amount[1]); // OK for VARCHAR, INTEGER and FLOAT + + if (i_dbDataType == 0) // Filter unsupported dbDataTypes + { + if ((i_sqlDataType == SQL_VARCHAR) +#if wxUSE_UNICODE + #if defined(SQL_WCHAR) + || (i_sqlDataType == SQL_WCHAR) + #endif + #if defined(SQL_WVARCHAR) + || (i_sqlDataType == SQL_WVARCHAR) + #endif +#endif + || (i_sqlDataType == SQL_LONGVARCHAR)) + i_dbDataType = DB_DATA_TYPE_VARCHAR; + if ((i_sqlDataType == SQL_C_DATE) || (i_sqlDataType == SQL_C_TIMESTAMP)) + i_dbDataType = DB_DATA_TYPE_DATE; + if (i_sqlDataType == SQL_C_BIT) + i_dbDataType = DB_DATA_TYPE_INTEGER; + if (i_sqlDataType == SQL_NUMERIC) + i_dbDataType = DB_DATA_TYPE_VARCHAR; // glt - ??? is this right? + if (i_sqlDataType == SQL_REAL) + i_dbDataType = DB_DATA_TYPE_FLOAT; + if (i_sqlDataType == SQL_C_BINARY) + i_dbDataType = DB_DATA_TYPE_BLOB; + } + + if ((i_dbDataType == DB_DATA_TYPE_INTEGER) && (i_sqlDataType == SQL_C_DOUBLE)) + { // DBASE Numeric + i_dbDataType = DB_DATA_TYPE_FLOAT; + } + + switch(i_dbDataType) // TBD: Still a lot of proper formatting to do + { + case DB_DATA_TYPE_VARCHAR: + s_Field = wxT("%s"); + break; + case DB_DATA_TYPE_INTEGER: + s_Field = wxT("%d"); + break; + case DB_DATA_TYPE_FLOAT: + if (decimalDigits == 0) + decimalDigits = 2; + tempStr.Printf(wxT("%%%d.%d"), columnLength, decimalDigits); + s_Field.Printf(wxT("%sf"), tempStr.c_str()); + break; + case DB_DATA_TYPE_DATE: + if (i_Nation == 0) // timestamp YYYY-MM-DD HH:MM:SS.SSS (tested for SYBASE) + { + s_Field = wxT("%04d-%02d-%02d %02d:%02d:%02d.%03d"); + } + if (i_Nation == 1) // European DD.MM.YYYY HH:MM:SS.SSS + { + s_Field = wxT("%02d.%02d.%04d %02d:%02d:%02d.%03d"); + } + if (i_Nation == 2) // UK DD/MM/YYYY HH:MM:SS.SSS + { + s_Field = wxT("%02d/%02d/%04d %02d:%02d:%02d.%03d"); + } + if (i_Nation == 3) // International YYYY-MM-DD HH:MM:SS.SSS + { + s_Field = wxT("%04d-%02d-%02d %02d:%02d:%02d.%03d"); + } + if (i_Nation == 4) // US MM/DD/YYYY HH:MM:SS.SSS + { + s_Field = wxT("%02d/%02d/%04d %02d:%02d:%02d.%03d"); + } + break; + case DB_DATA_TYPE_BLOB: + s_Field.Printf(wxT("Unable to format(%d)-SQL(%d)"), dbDataType,sqlDataType); // + break; + default: + s_Field.Printf(wxT("Unknown Format(%d)-SQL(%d)"), dbDataType,sqlDataType); // + break; + }; + return TRUE; +} // wxDbColFor::Format() + + +/********** wxDbColInf Constructor **********/ +wxDbColInf::wxDbColInf() +{ + Initialize(); +} // wxDbColInf::wxDbColInf() + + +/********** wxDbColInf Destructor ********/ +wxDbColInf::~wxDbColInf() +{ + if (pColFor) + delete pColFor; + pColFor = NULL; +} // wxDbColInf::~wxDbColInf() + + +bool wxDbColInf::Initialize() +{ + catalog[0] = 0; + schema[0] = 0; + tableName[0] = 0; + colName[0] = 0; + sqlDataType = 0; + typeName[0] = 0; + columnLength = 0; + bufferSize = 0; + decimalDigits = 0; + numPrecRadix = 0; + nullable = 0; + remarks[0] = 0; + dbDataType = 0; + PkCol = 0; + PkTableName[0] = 0; + FkCol = 0; + FkTableName[0] = 0; + pColFor = NULL; + + return true; +} // wxDbColInf::Initialize() + + +/********** wxDbTableInf Constructor ********/ +wxDbTableInf::wxDbTableInf() +{ + Initialize(); +} // wxDbTableInf::wxDbTableInf() + + +/********** wxDbTableInf Constructor ********/ +wxDbTableInf::~wxDbTableInf() +{ + if (pColInf) + delete [] pColInf; + pColInf = NULL; +} // wxDbTableInf::~wxDbTableInf() + + +bool wxDbTableInf::Initialize() +{ + tableName[0] = 0; + tableType[0] = 0; + tableRemarks[0] = 0; + numCols = 0; + pColInf = NULL; + + return true; +} // wxDbTableInf::Initialize() + + +/********** wxDbInf Constructor *************/ +wxDbInf::wxDbInf() +{ + Initialize(); +} // wxDbInf::wxDbInf() + + +/********** wxDbInf Destructor *************/ +wxDbInf::~wxDbInf() +{ + if (pTableInf) + delete [] pTableInf; + pTableInf = NULL; +} // wxDbInf::~wxDbInf() + + +/********** wxDbInf::Initialize() *************/ +bool wxDbInf::Initialize() +{ + catalog[0] = 0; + schema[0] = 0; + numTables = 0; + pTableInf = NULL; + + return true; +} // wxDbInf::Initialize() + + +/********** wxDb Constructor **********/ +wxDb::wxDb(const HENV &aHenv, bool FwdOnlyCursors) +{ + // Copy the HENV into the db class + henv = aHenv; + fwdOnlyCursors = FwdOnlyCursors; + + initialize(); +} // wxDb::wxDb() + + +/********** wxDb Destructor **********/ +wxDb::~wxDb() +{ + wxASSERT_MSG(!IsCached(),wxT("Cached connections must not be manually deleted, use\nwxDbFreeConnection() or wxDbCloseConnections().")); + + if (IsOpen()) + { + Close(); + } +} // wxDb destructor + + + +/********** PRIVATE! wxDb::initialize PRIVATE! **********/ +/********** wxDb::initialize() **********/ +void wxDb::initialize() +/* + * Private member function that sets all wxDb member variables to + * known values at creation of the wxDb + */ +{ + int i; + + fpSqlLog = 0; // Sql Log file pointer + sqlLogState = sqlLogOFF; // By default, logging is turned off + nTables = 0; + dbmsType = dbmsUNIDENTIFIED; + + wxStrcpy(sqlState,wxEmptyString); + wxStrcpy(errorMsg,wxEmptyString); + nativeError = cbErrorMsg = 0; + for (i = 0; i < DB_MAX_ERROR_HISTORY; i++) + wxStrcpy(errorList[i], wxEmptyString); + + // Init typeInf structures + typeInfVarchar.TypeName.Empty(); + typeInfVarchar.FsqlType = 0; + typeInfVarchar.Precision = 0; + typeInfVarchar.CaseSensitive = 0; + typeInfVarchar.MaximumScale = 0; + + typeInfInteger.TypeName.Empty(); + typeInfInteger.FsqlType = 0; + typeInfInteger.Precision = 0; + typeInfInteger.CaseSensitive = 0; + typeInfInteger.MaximumScale = 0; + + typeInfFloat.TypeName.Empty(); + typeInfFloat.FsqlType = 0; + typeInfFloat.Precision = 0; + typeInfFloat.CaseSensitive = 0; + typeInfFloat.MaximumScale = 0; + + typeInfDate.TypeName.Empty(); + typeInfDate.FsqlType = 0; + typeInfDate.Precision = 0; + typeInfDate.CaseSensitive = 0; + typeInfDate.MaximumScale = 0; + + typeInfBlob.TypeName.Empty(); + typeInfBlob.FsqlType = 0; + typeInfBlob.Precision = 0; + typeInfBlob.CaseSensitive = 0; + typeInfBlob.MaximumScale = 0; + + typeInfMemo.TypeName.Empty(); + typeInfMemo.FsqlType = 0; + typeInfMemo.Precision = 0; + typeInfMemo.CaseSensitive = 0; + typeInfMemo.MaximumScale = 0; + + // Error reporting is turned OFF by default + silent = true; + + // Allocate a data source connection handle + if (SQLAllocConnect(henv, &hdbc) != SQL_SUCCESS) + DispAllErrors(henv); + + // Initialize the db status flag + DB_STATUS = 0; + + // Mark database as not open as of yet + dbIsOpen = false; + dbIsCached = false; + dbOpenedWithConnectionString = false; +} // wxDb::initialize() + + +/********** PRIVATE! wxDb::convertUserID PRIVATE! **********/ +// +// NOTE: Return value from this function MUST be copied +// immediately, as the value is not good after +// this function has left scope. +// +const wxChar *wxDb::convertUserID(const wxChar *userID, wxString &UserID) +{ + if (userID) + { + if (!wxStrlen(userID)) + UserID = uid; + else + UserID = userID; + } + else + UserID.Empty(); + + // dBase does not use user names, and some drivers fail if you try to pass one + if ( Dbms() == dbmsDBASE + || Dbms() == dbmsXBASE_SEQUITER ) + UserID.Empty(); + + // Some databases require user names to be specified in uppercase, + // so force the name to uppercase + if ((Dbms() == dbmsORACLE) || + (Dbms() == dbmsMAXDB)) + UserID = UserID.Upper(); + + return UserID.c_str(); +} // wxDb::convertUserID() + + +bool wxDb::determineDataTypes(bool failOnDataTypeUnsupported) +{ + size_t iIndex; + + // These are the possible SQL types we check for use against the datasource we are connected + // to for the purpose of determining which data type to use for the basic character strings + // column types + // + // NOTE: The first type in this enumeration that is determined to be supported by the + // datasource/driver is the one that will be used. + SWORD PossibleSqlCharTypes[] = { +#if wxUSE_UNICODE && defined(SQL_WVARCHAR) + SQL_WVARCHAR, +#endif + SQL_VARCHAR, +#if wxUSE_UNICODE && defined(SQL_WVARCHAR) + SQL_WCHAR, +#endif + SQL_CHAR + }; + + // These are the possible SQL types we check for use against the datasource we are connected + // to for the purpose of determining which data type to use for the basic non-floating point + // column types + // + // NOTE: The first type in this enumeration that is determined to be supported by the + // datasource/driver is the one that will be used. + SWORD PossibleSqlIntegerTypes[] = { + SQL_INTEGER + }; + + // These are the possible SQL types we check for use against the datasource we are connected + // to for the purpose of determining which data type to use for the basic floating point number + // column types + // + // NOTE: The first type in this enumeration that is determined to be supported by the + // datasource/driver is the one that will be used. + SWORD PossibleSqlFloatTypes[] = { + SQL_DOUBLE, + SQL_REAL, + SQL_FLOAT, + SQL_DECIMAL, + SQL_NUMERIC + }; + + // These are the possible SQL types we check for use agains the datasource we are connected + // to for the purpose of determining which data type to use for the date/time column types + // + // NOTE: The first type in this enumeration that is determined to be supported by the + // datasource/driver is the one that will be used. + SWORD PossibleSqlDateTypes[] = { + SQL_TIMESTAMP, + SQL_DATE, +#ifdef SQL_DATETIME + SQL_DATETIME +#endif + }; + + // These are the possible SQL types we check for use agains the datasource we are connected + // to for the purpose of determining which data type to use for the BLOB column types. + // + // NOTE: The first type in this enumeration that is determined to be supported by the + // datasource/driver is the one that will be used. + SWORD PossibleSqlBlobTypes[] = { + SQL_LONGVARBINARY, + SQL_VARBINARY + }; + + // These are the possible SQL types we check for use agains the datasource we are connected + // to for the purpose of determining which data type to use for the MEMO column types + // (a type which allow to store large strings; like VARCHAR just with a bigger precision) + // + // NOTE: The first type in this enumeration that is determined to be supported by the + // datasource/driver is the one that will be used. + SWORD PossibleSqlMemoTypes[] = { + SQL_LONGVARCHAR, + }; + + + // Query the data source regarding data type information + + // + // The way it was determined which SQL data types to use was by calling SQLGetInfo + // for all of the possible SQL data types to see which ones were supported. If + // a type is not supported, the SQLFetch() that's called from getDataTypeInfo() + // fails with SQL_NO_DATA_FOUND. This is ugly because I'm sure the three SQL data + // types I've selected below will not always be what we want. These are just + // what happened to work against an Oracle 7/Intersolv combination. The following is + // a complete list of the results I got back against the Oracle 7 database: + // + // SQL_BIGINT SQL_NO_DATA_FOUND + // SQL_BINARY SQL_NO_DATA_FOUND + // SQL_BIT SQL_NO_DATA_FOUND + // SQL_CHAR type name = 'CHAR', Precision = 255 + // SQL_DATE SQL_NO_DATA_FOUND + // SQL_DECIMAL type name = 'NUMBER', Precision = 38 + // SQL_DOUBLE type name = 'NUMBER', Precision = 15 + // SQL_FLOAT SQL_NO_DATA_FOUND + // SQL_INTEGER SQL_NO_DATA_FOUND + // SQL_LONGVARBINARY type name = 'LONG RAW', Precision = 2 billion + // SQL_LONGVARCHAR type name = 'LONG', Precision = 2 billion + // SQL_NUMERIC SQL_NO_DATA_FOUND + // SQL_REAL SQL_NO_DATA_FOUND + // SQL_SMALLINT SQL_NO_DATA_FOUND + // SQL_TIME SQL_NO_DATA_FOUND + // SQL_TIMESTAMP type name = 'DATE', Precision = 19 + // SQL_VARBINARY type name = 'RAW', Precision = 255 + // SQL_VARCHAR type name = 'VARCHAR2', Precision = 2000 + // ===================================================================== + // Results from a Microsoft Access 7.0 db, using a driver from Microsoft + // + // SQL_VARCHAR type name = 'TEXT', Precision = 255 + // SQL_TIMESTAMP type name = 'DATETIME' + // SQL_DECIMAL SQL_NO_DATA_FOUND + // SQL_NUMERIC type name = 'CURRENCY', Precision = 19 + // SQL_FLOAT SQL_NO_DATA_FOUND + // SQL_REAL type name = 'SINGLE', Precision = 7 + // SQL_DOUBLE type name = 'DOUBLE', Precision = 15 + // SQL_INTEGER type name = 'LONG', Precision = 10 + + // Query the data source for info about itself + if (!getDbInfo(failOnDataTypeUnsupported)) + return false; + + // --------------- Varchar - (Variable length character string) --------------- + for (iIndex = 0; iIndex < WXSIZEOF(PossibleSqlCharTypes) && + !getDataTypeInfo(PossibleSqlCharTypes[iIndex], typeInfVarchar); ++iIndex) + {} + + if (iIndex < WXSIZEOF(PossibleSqlCharTypes)) + typeInfVarchar.FsqlType = PossibleSqlCharTypes[iIndex]; + else if (failOnDataTypeUnsupported) + return false; + + // --------------- Float --------------- + for (iIndex = 0; iIndex < WXSIZEOF(PossibleSqlFloatTypes) && + !getDataTypeInfo(PossibleSqlFloatTypes[iIndex], typeInfFloat); ++iIndex) + {} + + if (iIndex < WXSIZEOF(PossibleSqlFloatTypes)) + typeInfFloat.FsqlType = PossibleSqlFloatTypes[iIndex]; + else if (failOnDataTypeUnsupported) + return false; + + // --------------- Integer ------------- + for (iIndex = 0; iIndex < WXSIZEOF(PossibleSqlIntegerTypes) && + !getDataTypeInfo(PossibleSqlIntegerTypes[iIndex], typeInfInteger); ++iIndex) + {} + + if (iIndex < WXSIZEOF(PossibleSqlIntegerTypes)) + typeInfInteger.FsqlType = PossibleSqlIntegerTypes[iIndex]; + else if (failOnDataTypeUnsupported) + { + // If no non-floating point data types are supported, we'll + // use the type assigned for floats to store integers as well + if (!getDataTypeInfo(typeInfFloat.FsqlType, typeInfInteger)) + { + if (failOnDataTypeUnsupported) + return false; + } + else + typeInfInteger.FsqlType = typeInfFloat.FsqlType; + } + + // --------------- Date/Time --------------- + for (iIndex = 0; iIndex < WXSIZEOF(PossibleSqlDateTypes) && + !getDataTypeInfo(PossibleSqlDateTypes[iIndex], typeInfDate); ++iIndex) + {} + + if (iIndex < WXSIZEOF(PossibleSqlDateTypes)) + typeInfDate.FsqlType = PossibleSqlDateTypes[iIndex]; + else if (failOnDataTypeUnsupported) + return false; + + // --------------- BLOB --------------- + for (iIndex = 0; iIndex < WXSIZEOF(PossibleSqlBlobTypes) && + !getDataTypeInfo(PossibleSqlBlobTypes[iIndex], typeInfBlob); ++iIndex) + {} + + if (iIndex < WXSIZEOF(PossibleSqlBlobTypes)) + typeInfBlob.FsqlType = PossibleSqlBlobTypes[iIndex]; + else if (failOnDataTypeUnsupported) + return false; + + // --------------- MEMO --------------- + for (iIndex = 0; iIndex < WXSIZEOF(PossibleSqlMemoTypes) && + !getDataTypeInfo(PossibleSqlMemoTypes[iIndex], typeInfMemo); ++iIndex) + {} + + if (iIndex < WXSIZEOF(PossibleSqlMemoTypes)) + typeInfMemo.FsqlType = PossibleSqlMemoTypes[iIndex]; + else if (failOnDataTypeUnsupported) + return false; + + return true; +} // wxDb::determineDataTypes + + +bool wxDb::open(bool failOnDataTypeUnsupported) +{ +/* + If using Intersolv branded ODBC drivers, this is the place where you would substitute + your branded driver license information + + SQLSetConnectOption(hdbc, 1041, (UDWORD) wxEmptyString); + SQLSetConnectOption(hdbc, 1042, (UDWORD) wxEmptyString); +*/ + + // Mark database as open + dbIsOpen = true; + + // Allocate a statement handle for the database connection + if (SQLAllocStmt(hdbc, &hstmt) != SQL_SUCCESS) + return(DispAllErrors(henv, hdbc)); + + // Set Connection Options + if (!setConnectionOptions()) + return false; + + if (!determineDataTypes(failOnDataTypeUnsupported)) + return false; + +#ifdef DBDEBUG_CONSOLE + cout << wxT("VARCHAR DATA TYPE: ") << typeInfVarchar.TypeName << endl; + cout << wxT("INTEGER DATA TYPE: ") << typeInfInteger.TypeName << endl; + cout << wxT("FLOAT DATA TYPE: ") << typeInfFloat.TypeName << endl; + cout << wxT("DATE DATA TYPE: ") << typeInfDate.TypeName << endl; + cout << wxT("BLOB DATA TYPE: ") << typeInfBlob.TypeName << endl; + cout << wxT("MEMO DATA TYPE: ") << typeInfMemo.TypeName << endl; + cout << endl; +#endif + + // Completed Successfully + return true; +} + +bool wxDb::Open(const wxString& inConnectStr, bool failOnDataTypeUnsupported) +{ + wxASSERT(inConnectStr.length()); + return Open(inConnectStr, NULL, failOnDataTypeUnsupported); +} + +bool wxDb::Open(const wxString& inConnectStr, SQLHWND parentWnd, bool failOnDataTypeUnsupported) +{ + dsn = wxEmptyString; + uid = wxEmptyString; + authStr = wxEmptyString; + + RETCODE retcode; + + if (!FwdOnlyCursors()) + { + // Specify that the ODBC cursor library be used, if needed. This must be + // specified before the connection is made. + retcode = SQLSetConnectOption(hdbc, SQL_ODBC_CURSORS, SQL_CUR_USE_IF_NEEDED); + +#ifdef DBDEBUG_CONSOLE + if (retcode == SQL_SUCCESS) + cout << wxT("SQLSetConnectOption(CURSOR_LIB) successful") << endl; + else + cout << wxT("SQLSetConnectOption(CURSOR_LIB) failed") << endl; +#else + wxUnusedVar(retcode); +#endif + } + + // Connect to the data source + SQLTCHAR outConnectBuffer[SQL_MAX_CONNECTSTR_LEN+1]; // MS recommends at least 1k buffer + short outConnectBufferLen; + + inConnectionStr = inConnectStr; + + retcode = SQLDriverConnect(hdbc, parentWnd, (SQLTCHAR FAR *)inConnectionStr.c_str(), + (SWORD)inConnectionStr.length(), (SQLTCHAR FAR *)outConnectBuffer, + WXSIZEOF(outConnectBuffer), &outConnectBufferLen, SQL_DRIVER_COMPLETE ); + + if ((retcode != SQL_SUCCESS) && + (retcode != SQL_SUCCESS_WITH_INFO)) + return(DispAllErrors(henv, hdbc)); + + outConnectBuffer[outConnectBufferLen] = 0; + outConnectionStr = outConnectBuffer; + dbOpenedWithConnectionString = true; + + return open(failOnDataTypeUnsupported); +} + +/********** wxDb::Open() **********/ +bool wxDb::Open(const wxString &Dsn, const wxString &Uid, const wxString &AuthStr, bool failOnDataTypeUnsupported) +{ + wxASSERT(!Dsn.empty()); + dsn = Dsn; + uid = Uid; + authStr = AuthStr; + + inConnectionStr = wxEmptyString; + outConnectionStr = wxEmptyString; + + RETCODE retcode; + + if (!FwdOnlyCursors()) + { + // Specify that the ODBC cursor library be used, if needed. This must be + // specified before the connection is made. + retcode = SQLSetConnectOption(hdbc, SQL_ODBC_CURSORS, SQL_CUR_USE_IF_NEEDED); + +#ifdef DBDEBUG_CONSOLE + if (retcode == SQL_SUCCESS) + cout << wxT("SQLSetConnectOption(CURSOR_LIB) successful") << endl; + else + cout << wxT("SQLSetConnectOption(CURSOR_LIB) failed") << endl; +#else + wxUnusedVar( retcode ); +#endif + } + + // Connect to the data source + retcode = SQLConnect(hdbc, (SQLTCHAR FAR *) dsn.c_str(), SQL_NTS, + (SQLTCHAR FAR *) uid.c_str(), SQL_NTS, + (SQLTCHAR FAR *) authStr.c_str(), SQL_NTS); + + if ((retcode != SQL_SUCCESS) && + (retcode != SQL_SUCCESS_WITH_INFO)) + return(DispAllErrors(henv, hdbc)); + + return open(failOnDataTypeUnsupported); + +} // wxDb::Open() + + +bool wxDb::Open(wxDbConnectInf *dbConnectInf, bool failOnDataTypeUnsupported) +{ + wxASSERT(dbConnectInf); + + // Use the connection string if one is present + if (dbConnectInf->UseConnectionStr()) + return Open(dbConnectInf->GetConnectionStr(), failOnDataTypeUnsupported); + else + return Open(dbConnectInf->GetDsn(), dbConnectInf->GetUserID(), + dbConnectInf->GetPassword(), failOnDataTypeUnsupported); +} // wxDb::Open() + + +bool wxDb::Open(wxDb *copyDb) +{ + dsn = copyDb->GetDatasourceName(); + uid = copyDb->GetUsername(); + authStr = copyDb->GetPassword(); + inConnectionStr = copyDb->GetConnectionInStr(); + outConnectionStr = copyDb->GetConnectionOutStr(); + + RETCODE retcode; + + if (!FwdOnlyCursors()) + { + // Specify that the ODBC cursor library be used, if needed. This must be + // specified before the connection is made. + retcode = SQLSetConnectOption(hdbc, SQL_ODBC_CURSORS, SQL_CUR_USE_IF_NEEDED); + +#ifdef DBDEBUG_CONSOLE + if (retcode == SQL_SUCCESS) + cout << wxT("SQLSetConnectOption(CURSOR_LIB) successful") << endl; + else + cout << wxT("SQLSetConnectOption(CURSOR_LIB) failed") << endl; +#else + wxUnusedVar( retcode ); +#endif + } + + if (copyDb->OpenedWithConnectionString()) + { + // Connect to the data source + SQLTCHAR outConnectBuffer[SQL_MAX_CONNECTSTR_LEN+1]; + short outConnectBufferLen; + + inConnectionStr = copyDb->GetConnectionInStr(); + + retcode = SQLDriverConnect(hdbc, NULL, (SQLTCHAR FAR *)inConnectionStr.c_str(), + (SWORD)inConnectionStr.length(), (SQLTCHAR FAR *)outConnectBuffer, + WXSIZEOF(outConnectBuffer), &outConnectBufferLen, SQL_DRIVER_COMPLETE); + + if ((retcode != SQL_SUCCESS) && + (retcode != SQL_SUCCESS_WITH_INFO)) + return(DispAllErrors(henv, hdbc)); + + outConnectBuffer[outConnectBufferLen] = 0; + outConnectionStr = outConnectBuffer; + dbOpenedWithConnectionString = true; + } + else + { + // Connect to the data source + retcode = SQLConnect(hdbc, (SQLTCHAR FAR *) dsn.c_str(), SQL_NTS, + (SQLTCHAR FAR *) uid.c_str(), SQL_NTS, + (SQLTCHAR FAR *) authStr.c_str(), SQL_NTS); + } + + if ((retcode != SQL_SUCCESS) && + (retcode != SQL_SUCCESS_WITH_INFO)) + return(DispAllErrors(henv, hdbc)); + +/* + If using Intersolv branded ODBC drivers, this is the place where you would substitute + your branded driver license information + + SQLSetConnectOption(hdbc, 1041, (UDWORD) wxEmptyString); + SQLSetConnectOption(hdbc, 1042, (UDWORD) wxEmptyString); +*/ + + // Mark database as open + dbIsOpen = true; + + // Allocate a statement handle for the database connection + if (SQLAllocStmt(hdbc, &hstmt) != SQL_SUCCESS) + return(DispAllErrors(henv, hdbc)); + + // Set Connection Options + if (!setConnectionOptions()) + return false; + + // Instead of Querying the data source for info about itself, it can just be copied + // from the wxDb instance that was passed in (copyDb). + wxStrcpy(dbInf.serverName,copyDb->dbInf.serverName); + wxStrcpy(dbInf.databaseName,copyDb->dbInf.databaseName); + wxStrcpy(dbInf.dbmsName,copyDb->dbInf.dbmsName); + wxStrcpy(dbInf.dbmsVer,copyDb->dbInf.dbmsVer); + dbInf.maxConnections = copyDb->dbInf.maxConnections; + dbInf.maxStmts = copyDb->dbInf.maxStmts; + wxStrcpy(dbInf.driverName,copyDb->dbInf.driverName); + wxStrcpy(dbInf.odbcVer,copyDb->dbInf.odbcVer); + wxStrcpy(dbInf.drvMgrOdbcVer,copyDb->dbInf.drvMgrOdbcVer); + wxStrcpy(dbInf.driverVer,copyDb->dbInf.driverVer); + dbInf.apiConfLvl = copyDb->dbInf.apiConfLvl; + dbInf.cliConfLvl = copyDb->dbInf.cliConfLvl; + dbInf.sqlConfLvl = copyDb->dbInf.sqlConfLvl; + wxStrcpy(dbInf.outerJoins,copyDb->dbInf.outerJoins); + wxStrcpy(dbInf.procedureSupport,copyDb->dbInf.procedureSupport); + wxStrcpy(dbInf.accessibleTables,copyDb->dbInf.accessibleTables); + dbInf.cursorCommitBehavior = copyDb->dbInf.cursorCommitBehavior; + dbInf.cursorRollbackBehavior = copyDb->dbInf.cursorRollbackBehavior; + dbInf.supportNotNullClause = copyDb->dbInf.supportNotNullClause; + wxStrcpy(dbInf.supportIEF,copyDb->dbInf.supportIEF); + dbInf.txnIsolation = copyDb->dbInf.txnIsolation; + dbInf.txnIsolationOptions = copyDb->dbInf.txnIsolationOptions; + dbInf.fetchDirections = copyDb->dbInf.fetchDirections; + dbInf.lockTypes = copyDb->dbInf.lockTypes; + dbInf.posOperations = copyDb->dbInf.posOperations; + dbInf.posStmts = copyDb->dbInf.posStmts; + dbInf.scrollConcurrency = copyDb->dbInf.scrollConcurrency; + dbInf.scrollOptions = copyDb->dbInf.scrollOptions; + dbInf.staticSensitivity = copyDb->dbInf.staticSensitivity; + dbInf.txnCapable = copyDb->dbInf.txnCapable; + dbInf.loginTimeout = copyDb->dbInf.loginTimeout; + + // VARCHAR = Variable length character string + typeInfVarchar.FsqlType = copyDb->typeInfVarchar.FsqlType; + typeInfVarchar.TypeName = copyDb->typeInfVarchar.TypeName; + typeInfVarchar.Precision = copyDb->typeInfVarchar.Precision; + typeInfVarchar.CaseSensitive = copyDb->typeInfVarchar.CaseSensitive; + typeInfVarchar.MaximumScale = copyDb->typeInfVarchar.MaximumScale; + + // Float + typeInfFloat.FsqlType = copyDb->typeInfFloat.FsqlType; + typeInfFloat.TypeName = copyDb->typeInfFloat.TypeName; + typeInfFloat.Precision = copyDb->typeInfFloat.Precision; + typeInfFloat.CaseSensitive = copyDb->typeInfFloat.CaseSensitive; + typeInfFloat.MaximumScale = copyDb->typeInfFloat.MaximumScale; + + // Integer + typeInfInteger.FsqlType = copyDb->typeInfInteger.FsqlType; + typeInfInteger.TypeName = copyDb->typeInfInteger.TypeName; + typeInfInteger.Precision = copyDb->typeInfInteger.Precision; + typeInfInteger.CaseSensitive = copyDb->typeInfInteger.CaseSensitive; + typeInfInteger.MaximumScale = copyDb->typeInfInteger.MaximumScale; + + // Date/Time + typeInfDate.FsqlType = copyDb->typeInfDate.FsqlType; + typeInfDate.TypeName = copyDb->typeInfDate.TypeName; + typeInfDate.Precision = copyDb->typeInfDate.Precision; + typeInfDate.CaseSensitive = copyDb->typeInfDate.CaseSensitive; + typeInfDate.MaximumScale = copyDb->typeInfDate.MaximumScale; + + // Blob + typeInfBlob.FsqlType = copyDb->typeInfBlob.FsqlType; + typeInfBlob.TypeName = copyDb->typeInfBlob.TypeName; + typeInfBlob.Precision = copyDb->typeInfBlob.Precision; + typeInfBlob.CaseSensitive = copyDb->typeInfBlob.CaseSensitive; + typeInfBlob.MaximumScale = copyDb->typeInfBlob.MaximumScale; + + // Memo + typeInfMemo.FsqlType = copyDb->typeInfMemo.FsqlType; + typeInfMemo.TypeName = copyDb->typeInfMemo.TypeName; + typeInfMemo.Precision = copyDb->typeInfMemo.Precision; + typeInfMemo.CaseSensitive = copyDb->typeInfMemo.CaseSensitive; + typeInfMemo.MaximumScale = copyDb->typeInfMemo.MaximumScale; + +#ifdef DBDEBUG_CONSOLE + cout << wxT("VARCHAR DATA TYPE: ") << typeInfVarchar.TypeName << endl; + cout << wxT("INTEGER DATA TYPE: ") << typeInfInteger.TypeName << endl; + cout << wxT("FLOAT DATA TYPE: ") << typeInfFloat.TypeName << endl; + cout << wxT("DATE DATA TYPE: ") << typeInfDate.TypeName << endl; + cout << wxT("BLOB DATA TYPE: ") << typeInfBlob.TypeName << endl; + cout << wxT("MEMO DATA TYPE: ") << typeInfMemo.TypeName << endl; + cout << endl; +#endif + + // Completed Successfully + return true; +} // wxDb::Open() 2 + + +/********** wxDb::setConnectionOptions() **********/ +bool wxDb::setConnectionOptions(void) +/* + * NOTE: The Intersolv/Oracle 7 driver was "Not Capable" of setting the login timeout. + */ +{ + SWORD cb; + + // I need to get the DBMS name here, because some of the connection options + // are database specific and need to call the Dbms() function. + RETCODE retcode; + + retcode = SQLGetInfo(hdbc, SQL_DBMS_NAME, (UCHAR *) dbInf.dbmsName, sizeof(dbInf.dbmsName), &cb); + if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO) + return(DispAllErrors(henv, hdbc)); + + /* retcode = */ SQLSetConnectOption(hdbc, SQL_AUTOCOMMIT, SQL_AUTOCOMMIT_OFF); + /* retcode = */ SQLSetConnectOption(hdbc, SQL_OPT_TRACE, SQL_OPT_TRACE_OFF); +// SQLSetConnectOption(hdbc, SQL_TXN_ISOLATION, SQL_TXN_READ_COMMITTED); // No dirty reads + + // By default, MS Sql Server closes cursors on commit and rollback. The following + // call to SQLSetConnectOption() is needed to force SQL Server to preserve cursors + // after a transaction. This is a driver specific option and is not part of the + // ODBC standard. Note: this behavior is specific to the ODBC interface to SQL Server. + // The database settings don't have any effect one way or the other. + if (Dbms() == dbmsMS_SQL_SERVER) + { + const long SQL_PRESERVE_CURSORS = 1204L; + const long SQL_PC_ON = 1L; + /* retcode = */ SQLSetConnectOption(hdbc, SQL_PRESERVE_CURSORS, SQL_PC_ON); + } + + // Display the connection options to verify them +#ifdef DBDEBUG_CONSOLE + long l; + cout << wxT("****** CONNECTION OPTIONS ******") << endl; + + retcode = SQLGetConnectOption(hdbc, SQL_AUTOCOMMIT, &l); + if (retcode != SQL_SUCCESS) + return(DispAllErrors(henv, hdbc)); + cout << wxT("AUTOCOMMIT: ") << (l == SQL_AUTOCOMMIT_OFF ? "OFF" : "ON") << endl; + + retcode = SQLGetConnectOption(hdbc, SQL_ODBC_CURSORS, &l); + if (retcode != SQL_SUCCESS) + return(DispAllErrors(henv, hdbc)); + cout << wxT("ODBC CURSORS: "); + switch(l) + { + case(SQL_CUR_USE_IF_NEEDED): + cout << wxT("SQL_CUR_USE_IF_NEEDED"); + break; + case(SQL_CUR_USE_ODBC): + cout << wxT("SQL_CUR_USE_ODBC"); + break; + case(SQL_CUR_USE_DRIVER): + cout << wxT("SQL_CUR_USE_DRIVER"); + break; + } + cout << endl; + + retcode = SQLGetConnectOption(hdbc, SQL_OPT_TRACE, &l) + if (retcode != SQL_SUCCESS) + return(DispAllErrors(henv, hdbc)); + cout << wxT("TRACING: ") << (l == SQL_OPT_TRACE_OFF ? wxT("OFF") : wxT("ON")) << endl; + + cout << endl; +#endif + + // Completed Successfully + return true; + +} // wxDb::setConnectionOptions() + + +/********** wxDb::getDbInfo() **********/ +bool wxDb::getDbInfo(bool failOnDataTypeUnsupported) +{ + SWORD cb; + RETCODE retcode; + + retcode = SQLGetInfo(hdbc, SQL_SERVER_NAME, (UCHAR*) dbInf.serverName, sizeof(dbInf.serverName), &cb); + if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO ) + { + DispAllErrors(henv, hdbc); + if (failOnDataTypeUnsupported) + return false; + } + + retcode = SQLGetInfo(hdbc, SQL_DATABASE_NAME, (UCHAR*) dbInf.databaseName, sizeof(dbInf.databaseName), &cb); + if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO ) + { + DispAllErrors(henv, hdbc); + if (failOnDataTypeUnsupported) + return false; + } + + retcode = SQLGetInfo(hdbc, SQL_DBMS_NAME, (UCHAR*) dbInf.dbmsName, sizeof(dbInf.dbmsName), &cb); + if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO ) + { + DispAllErrors(henv, hdbc); + if (failOnDataTypeUnsupported) + return false; + } + + // 16-Mar-1999 + // After upgrading to MSVC6, the original 20 char buffer below was insufficient, + // causing database connectivity to fail in some cases. + retcode = SQLGetInfo(hdbc, SQL_DBMS_VER, (UCHAR*) dbInf.dbmsVer, sizeof(dbInf.dbmsVer), &cb); + if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO ) + { + DispAllErrors(henv, hdbc); + if (failOnDataTypeUnsupported) + return false; + } + + retcode = SQLGetInfo(hdbc, SQL_ACTIVE_CONNECTIONS, (UCHAR*) &dbInf.maxConnections, sizeof(dbInf.maxConnections), &cb); + if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO ) + { + DispAllErrors(henv, hdbc); + if (failOnDataTypeUnsupported) + return false; + } + + retcode = SQLGetInfo(hdbc, SQL_ACTIVE_STATEMENTS, (UCHAR*) &dbInf.maxStmts, sizeof(dbInf.maxStmts), &cb); + if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO ) + { + DispAllErrors(henv, hdbc); + if (failOnDataTypeUnsupported) + return false; + } + + retcode = SQLGetInfo(hdbc, SQL_DRIVER_NAME, (UCHAR*) dbInf.driverName, sizeof(dbInf.driverName), &cb); + if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO ) + { + DispAllErrors(henv, hdbc); + if (failOnDataTypeUnsupported) + return false; + } + + retcode = SQLGetInfo(hdbc, SQL_DRIVER_ODBC_VER, (UCHAR*) dbInf.odbcVer, sizeof(dbInf.odbcVer), &cb); + if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO ) + { + DispAllErrors(henv, hdbc); + if (failOnDataTypeUnsupported) + return false; + } + + retcode = SQLGetInfo(hdbc, SQL_ODBC_VER, (UCHAR*) dbInf.drvMgrOdbcVer, sizeof(dbInf.drvMgrOdbcVer), &cb); + if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO) + { + DispAllErrors(henv, hdbc); + if (failOnDataTypeUnsupported) + return false; + } + + retcode = SQLGetInfo(hdbc, SQL_DRIVER_VER, (UCHAR*) dbInf.driverVer, sizeof(dbInf.driverVer), &cb); + if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO ) + { + DispAllErrors(henv, hdbc); + if (failOnDataTypeUnsupported) + return false; + } + + retcode = SQLGetInfo(hdbc, SQL_ODBC_API_CONFORMANCE, (UCHAR*) &dbInf.apiConfLvl, sizeof(dbInf.apiConfLvl), &cb); + if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO ) + { + DispAllErrors(henv, hdbc); + if (failOnDataTypeUnsupported) + return false; + } + + retcode = SQLGetInfo(hdbc, SQL_ODBC_SAG_CLI_CONFORMANCE, (UCHAR*) &dbInf.cliConfLvl, sizeof(dbInf.cliConfLvl), &cb); + if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO ) + { + // Not all drivers support this call - Nick Gorham(unixODBC) + dbInf.cliConfLvl = 0; + DispAllErrors(henv, hdbc); + if (failOnDataTypeUnsupported) + return false; + } + + retcode = SQLGetInfo(hdbc, SQL_ODBC_SQL_CONFORMANCE, (UCHAR*) &dbInf.sqlConfLvl, sizeof(dbInf.sqlConfLvl), &cb); + if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO ) + { + DispAllErrors(henv, hdbc); + if (failOnDataTypeUnsupported) + return false; + } + + retcode = SQLGetInfo(hdbc, SQL_OUTER_JOINS, (UCHAR*) dbInf.outerJoins, sizeof(dbInf.outerJoins), &cb); + if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO ) + { + DispAllErrors(henv, hdbc); + if (failOnDataTypeUnsupported) + return false; + } + + retcode = SQLGetInfo(hdbc, SQL_PROCEDURES, (UCHAR*) dbInf.procedureSupport, sizeof(dbInf.procedureSupport), &cb); + if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO ) + { + DispAllErrors(henv, hdbc); + if (failOnDataTypeUnsupported) + return false; + } + + retcode = SQLGetInfo(hdbc, SQL_ACCESSIBLE_TABLES, (UCHAR*) dbInf.accessibleTables, sizeof(dbInf.accessibleTables), &cb); + if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO ) + { + DispAllErrors(henv, hdbc); + if (failOnDataTypeUnsupported) + return false; + } + + retcode = SQLGetInfo(hdbc, SQL_CURSOR_COMMIT_BEHAVIOR, (UCHAR*) &dbInf.cursorCommitBehavior, sizeof(dbInf.cursorCommitBehavior), &cb); + if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO ) + { + DispAllErrors(henv, hdbc); + if (failOnDataTypeUnsupported) + return false; + } + + retcode = SQLGetInfo(hdbc, SQL_CURSOR_ROLLBACK_BEHAVIOR, (UCHAR*) &dbInf.cursorRollbackBehavior, sizeof(dbInf.cursorRollbackBehavior), &cb); + if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO ) + { + DispAllErrors(henv, hdbc); + if (failOnDataTypeUnsupported) + return false; + } + + retcode = SQLGetInfo(hdbc, SQL_NON_NULLABLE_COLUMNS, (UCHAR*) &dbInf.supportNotNullClause, sizeof(dbInf.supportNotNullClause), &cb); + if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO ) + { + DispAllErrors(henv, hdbc); + if (failOnDataTypeUnsupported) + return false; + } + + retcode = SQLGetInfo(hdbc, SQL_ODBC_SQL_OPT_IEF, (UCHAR*) dbInf.supportIEF, sizeof(dbInf.supportIEF), &cb); + if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO ) + { + DispAllErrors(henv, hdbc); + if (failOnDataTypeUnsupported) + return false; + } + + retcode = SQLGetInfo(hdbc, SQL_DEFAULT_TXN_ISOLATION, (UCHAR*) &dbInf.txnIsolation, sizeof(dbInf.txnIsolation), &cb); + if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO ) + { + DispAllErrors(henv, hdbc); + if (failOnDataTypeUnsupported) + return false; + } + + retcode = SQLGetInfo(hdbc, SQL_TXN_ISOLATION_OPTION, (UCHAR*) &dbInf.txnIsolationOptions, sizeof(dbInf.txnIsolationOptions), &cb); + if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO ) + { + DispAllErrors(henv, hdbc); + if (failOnDataTypeUnsupported) + return false; + } + + retcode = SQLGetInfo(hdbc, SQL_FETCH_DIRECTION, (UCHAR*) &dbInf.fetchDirections, sizeof(dbInf.fetchDirections), &cb); + if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO ) + { + DispAllErrors(henv, hdbc); + if (failOnDataTypeUnsupported) + return false; + } + + retcode = SQLGetInfo(hdbc, SQL_LOCK_TYPES, (UCHAR*) &dbInf.lockTypes, sizeof(dbInf.lockTypes), &cb); + if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO ) + { + DispAllErrors(henv, hdbc); + if (failOnDataTypeUnsupported) + return false; + } + + retcode = SQLGetInfo(hdbc, SQL_POS_OPERATIONS, (UCHAR*) &dbInf.posOperations, sizeof(dbInf.posOperations), &cb); + if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO ) + { + DispAllErrors(henv, hdbc); + if (failOnDataTypeUnsupported) + return false; + } + + retcode = SQLGetInfo(hdbc, SQL_POSITIONED_STATEMENTS, (UCHAR*) &dbInf.posStmts, sizeof(dbInf.posStmts), &cb); + if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO ) + { + DispAllErrors(henv, hdbc); + if (failOnDataTypeUnsupported) + return false; + } + + retcode = SQLGetInfo(hdbc, SQL_SCROLL_CONCURRENCY, (UCHAR*) &dbInf.scrollConcurrency, sizeof(dbInf.scrollConcurrency), &cb); + if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO ) + { + DispAllErrors(henv, hdbc); + if (failOnDataTypeUnsupported) + return false; + } + + retcode = SQLGetInfo(hdbc, SQL_SCROLL_OPTIONS, (UCHAR*) &dbInf.scrollOptions, sizeof(dbInf.scrollOptions), &cb); + if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO ) + { + DispAllErrors(henv, hdbc); + if (failOnDataTypeUnsupported) + return false; + } + + retcode = SQLGetInfo(hdbc, SQL_STATIC_SENSITIVITY, (UCHAR*) &dbInf.staticSensitivity, sizeof(dbInf.staticSensitivity), &cb); + if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO ) + { + DispAllErrors(henv, hdbc); + if (failOnDataTypeUnsupported) + return false; + } + + retcode = SQLGetInfo(hdbc, SQL_TXN_CAPABLE, (UCHAR*) &dbInf.txnCapable, sizeof(dbInf.txnCapable), &cb); + if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO ) + { + DispAllErrors(henv, hdbc); + if (failOnDataTypeUnsupported) + return false; + } + + retcode = SQLGetInfo(hdbc, SQL_LOGIN_TIMEOUT, (UCHAR*) &dbInf.loginTimeout, sizeof(dbInf.loginTimeout), &cb); + if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO ) + { + DispAllErrors(henv, hdbc); + if (failOnDataTypeUnsupported) + return false; + } + +#ifdef DBDEBUG_CONSOLE + cout << wxT("***** DATA SOURCE INFORMATION *****") << endl; + cout << wxT(wxT("SERVER Name: ") << dbInf.serverName << endl; + cout << wxT("DBMS Name: ") << dbInf.dbmsName << wxT("; DBMS Version: ") << dbInf.dbmsVer << endl; + cout << wxT("ODBC Version: ") << dbInf.odbcVer << wxT("; Driver Version: ") << dbInf.driverVer << endl; + + cout << wxT("API Conf. Level: "); + switch(dbInf.apiConfLvl) + { + case SQL_OAC_NONE: cout << wxT("None"); break; + case SQL_OAC_LEVEL1: cout << wxT("Level 1"); break; + case SQL_OAC_LEVEL2: cout << wxT("Level 2"); break; + } + cout << endl; + + cout << wxT("SAG CLI Conf. Level: "); + switch(dbInf.cliConfLvl) + { + case SQL_OSCC_NOT_COMPLIANT: cout << wxT("Not Compliant"); break; + case SQL_OSCC_COMPLIANT: cout << wxT("Compliant"); break; + } + cout << endl; + + cout << wxT("SQL Conf. Level: "); + switch(dbInf.sqlConfLvl) + { + case SQL_OSC_MINIMUM: cout << wxT("Minimum Grammar"); break; + case SQL_OSC_CORE: cout << wxT("Core Grammar"); break; + case SQL_OSC_EXTENDED: cout << wxT("Extended Grammar"); break; + } + cout << endl; + + cout << wxT("Max. Connections: ") << dbInf.maxConnections << endl; + cout << wxT("Outer Joins: ") << dbInf.outerJoins << endl; + cout << wxT("Support for Procedures: ") << dbInf.procedureSupport << endl; + cout << wxT("All tables accessible : ") << dbInf.accessibleTables << endl; + cout << wxT("Cursor COMMIT Behavior: "); + switch(dbInf.cursorCommitBehavior) + { + case SQL_CB_DELETE: cout << wxT("Delete cursors"); break; + case SQL_CB_CLOSE: cout << wxT("Close cursors"); break; + case SQL_CB_PRESERVE: cout << wxT("Preserve cursors"); break; + } + cout << endl; + + cout << wxT("Cursor ROLLBACK Behavior: "); + switch(dbInf.cursorRollbackBehavior) + { + case SQL_CB_DELETE: cout << wxT("Delete cursors"); break; + case SQL_CB_CLOSE: cout << wxT("Close cursors"); break; + case SQL_CB_PRESERVE: cout << wxT("Preserve cursors"); break; + } + cout << endl; + + cout << wxT("Support NOT NULL clause: "); + switch(dbInf.supportNotNullClause) + { + case SQL_NNC_NULL: cout << wxT("No"); break; + case SQL_NNC_NON_NULL: cout << wxT("Yes"); break; + } + cout << endl; + + cout << wxT("Support IEF (Ref. Integrity): ") << dbInf.supportIEF << endl; + cout << wxT("Login Timeout: ") << dbInf.loginTimeout << endl; + + cout << endl << endl << wxT("more ...") << endl; + getchar(); + + cout << wxT("Default Transaction Isolation: "; + switch(dbInf.txnIsolation) + { + case SQL_TXN_READ_UNCOMMITTED: cout << wxT("Read Uncommitted"); break; + case SQL_TXN_READ_COMMITTED: cout << wxT("Read Committed"); break; + case SQL_TXN_REPEATABLE_READ: cout << wxT("Repeatable Read"); break; + case SQL_TXN_SERIALIZABLE: cout << wxT("Serializable"); break; +#ifdef ODBC_V20 + case SQL_TXN_VERSIONING: cout << wxT("Versioning"); break; +#endif + } + cout << endl; + + cout << wxT("Transaction Isolation Options: "); + if (dbInf.txnIsolationOptions & SQL_TXN_READ_UNCOMMITTED) + cout << wxT("Read Uncommitted, "); + if (dbInf.txnIsolationOptions & SQL_TXN_READ_COMMITTED) + cout << wxT("Read Committed, "); + if (dbInf.txnIsolationOptions & SQL_TXN_REPEATABLE_READ) + cout << wxT("Repeatable Read, "); + if (dbInf.txnIsolationOptions & SQL_TXN_SERIALIZABLE) + cout << wxT("Serializable, "); +#ifdef ODBC_V20 + if (dbInf.txnIsolationOptions & SQL_TXN_VERSIONING) + cout << wxT("Versioning"); +#endif + cout << endl; + + cout << wxT("Fetch Directions Supported:") << endl << wxT(" "); + if (dbInf.fetchDirections & SQL_FD_FETCH_NEXT) + cout << wxT("Next, "); + if (dbInf.fetchDirections & SQL_FD_FETCH_PRIOR) + cout << wxT("Prev, "); + if (dbInf.fetchDirections & SQL_FD_FETCH_FIRST) + cout << wxT("First, "); + if (dbInf.fetchDirections & SQL_FD_FETCH_LAST) + cout << wxT("Last, "); + if (dbInf.fetchDirections & SQL_FD_FETCH_ABSOLUTE) + cout << wxT("Absolute, "); + if (dbInf.fetchDirections & SQL_FD_FETCH_RELATIVE) + cout << wxT("Relative, "); +#ifdef ODBC_V20 + if (dbInf.fetchDirections & SQL_FD_FETCH_RESUME) + cout << wxT("Resume, "); +#endif + if (dbInf.fetchDirections & SQL_FD_FETCH_BOOKMARK) + cout << wxT("Bookmark"); + cout << endl; + + cout << wxT("Lock Types Supported (SQLSetPos): "); + if (dbInf.lockTypes & SQL_LCK_NO_CHANGE) + cout << wxT("No Change, "); + if (dbInf.lockTypes & SQL_LCK_EXCLUSIVE) + cout << wxT("Exclusive, "); + if (dbInf.lockTypes & SQL_LCK_UNLOCK) + cout << wxT("UnLock"); + cout << endl; + + cout << wxT("Position Operations Supported (SQLSetPos): "); + if (dbInf.posOperations & SQL_POS_POSITION) + cout << wxT("Position, "); + if (dbInf.posOperations & SQL_POS_REFRESH) + cout << wxT("Refresh, "); + if (dbInf.posOperations & SQL_POS_UPDATE) + cout << wxT("Upd, ")); + if (dbInf.posOperations & SQL_POS_DELETE) + cout << wxT("Del, "); + if (dbInf.posOperations & SQL_POS_ADD) + cout << wxT("Add"); + cout << endl; + + cout << wxT("Positioned Statements Supported: "); + if (dbInf.posStmts & SQL_PS_POSITIONED_DELETE) + cout << wxT("Pos delete, "); + if (dbInf.posStmts & SQL_PS_POSITIONED_UPDATE) + cout << wxT("Pos update, "); + if (dbInf.posStmts & SQL_PS_SELECT_FOR_UPDATE) + cout << wxT("Select for update"); + cout << endl; + + cout << wxT("Scroll Concurrency: "); + if (dbInf.scrollConcurrency & SQL_SCCO_READ_ONLY) + cout << wxT("Read Only, "); + if (dbInf.scrollConcurrency & SQL_SCCO_LOCK) + cout << wxT("Lock, "); + if (dbInf.scrollConcurrency & SQL_SCCO_OPT_ROWVER) + cout << wxT("Opt. Rowver, "); + if (dbInf.scrollConcurrency & SQL_SCCO_OPT_VALUES) + cout << wxT("Opt. Values"); + cout << endl; + + cout << wxT("Scroll Options: "); + if (dbInf.scrollOptions & SQL_SO_FORWARD_ONLY) + cout << wxT("Fwd Only, "); + if (dbInf.scrollOptions & SQL_SO_STATIC) + cout << wxT("Static, "); + if (dbInf.scrollOptions & SQL_SO_KEYSET_DRIVEN) + cout << wxT("Keyset Driven, "); + if (dbInf.scrollOptions & SQL_SO_DYNAMIC) + cout << wxT("Dynamic, "); + if (dbInf.scrollOptions & SQL_SO_MIXED) + cout << wxT("Mixed"); + cout << endl; + + cout << wxT("Static Sensitivity: "); + if (dbInf.staticSensitivity & SQL_SS_ADDITIONS) + cout << wxT("Additions, "); + if (dbInf.staticSensitivity & SQL_SS_DELETIONS) + cout << wxT("Deletions, "); + if (dbInf.staticSensitivity & SQL_SS_UPDATES) + cout << wxT("Updates"); + cout << endl; + + cout << wxT("Transaction Capable?: "); + switch(dbInf.txnCapable) + { + case SQL_TC_NONE: cout << wxT("No"); break; + case SQL_TC_DML: cout << wxT("DML Only"); break; + case SQL_TC_DDL_COMMIT: cout << wxT("DDL Commit"); break; + case SQL_TC_DDL_IGNORE: cout << wxT("DDL Ignore"); break; + case SQL_TC_ALL: cout << wxT("DDL & DML"); break; + } + cout << endl; + + cout << endl; +#endif + + // Completed Successfully + return true; + +} // wxDb::getDbInfo() + + +/********** wxDb::getDataTypeInfo() **********/ +bool wxDb::getDataTypeInfo(SWORD fSqlType, wxDbSqlTypeInfo &structSQLTypeInfo) +{ +/* + * fSqlType will be something like SQL_VARCHAR. This parameter determines + * the data type inf. is gathered for. + * + * wxDbSqlTypeInfo is a structure that is filled in with data type information, + */ + RETCODE retcode; + SQLLEN cbRet; + + // Get information about the data type specified + if (SQLGetTypeInfo(hstmt, fSqlType) != SQL_SUCCESS) + return(DispAllErrors(henv, hdbc, hstmt)); + + // Fetch the record + retcode = SQLFetch(hstmt); + if (retcode != SQL_SUCCESS) + { +#ifdef DBDEBUG_CONSOLE + if (retcode == SQL_NO_DATA_FOUND) + cout << wxT("SQL_NO_DATA_FOUND fetching information about data type.") << endl; +#endif + DispAllErrors(henv, hdbc, hstmt); + SQLFreeStmt(hstmt, SQL_CLOSE); + return false; + } + + wxChar typeName[DB_TYPE_NAME_LEN+1]; + + // Obtain columns from the record + if (SQLGetData(hstmt, 1, SQL_C_WXCHAR, typeName, sizeof(typeName), &cbRet) != SQL_SUCCESS) + return(DispAllErrors(henv, hdbc, hstmt)); + + structSQLTypeInfo.TypeName = typeName; + + // BJO 20000503: no more needed with new GetColumns... +#if OLD_GETCOLUMNS + // BJO 991209 + if (Dbms() == dbmsMY_SQL) + { + if (structSQLTypeInfo.TypeName == wxT("middleint")) + structSQLTypeInfo.TypeName = wxT("mediumint"); + else if (structSQLTypeInfo.TypeName == wxT("middleint unsigned")) + structSQLTypeInfo.TypeName = wxT("mediumint unsigned"); + else if (structSQLTypeInfo.TypeName == wxT("integer")) + structSQLTypeInfo.TypeName = wxT("int"); + else if (structSQLTypeInfo.TypeName == wxT("integer unsigned")) + structSQLTypeInfo.TypeName = wxT("int unsigned"); + else if (structSQLTypeInfo.TypeName == wxT("middleint")) + structSQLTypeInfo.TypeName = wxT("mediumint"); + else if (structSQLTypeInfo.TypeName == wxT("varchar")) + structSQLTypeInfo.TypeName = wxT("char"); + } + + // BJO 20000427 : OpenLink driver + if (!wxStrncmp(dbInf.driverName, wxT("oplodbc"), 7) || + !wxStrncmp(dbInf.driverName, wxT("OLOD"), 4)) + { + if (structSQLTypeInfo.TypeName == wxT("double precision")) + structSQLTypeInfo.TypeName = wxT("real"); + } +#endif + + if (SQLGetData(hstmt, 3, SQL_C_LONG, (UCHAR*) &structSQLTypeInfo.Precision, 0, &cbRet) != SQL_SUCCESS) + return(DispAllErrors(henv, hdbc, hstmt)); + if (SQLGetData(hstmt, 8, SQL_C_SHORT, (UCHAR*) &structSQLTypeInfo.CaseSensitive, 0, &cbRet) != SQL_SUCCESS) + return(DispAllErrors(henv, hdbc, hstmt)); +// if (SQLGetData(hstmt, 14, SQL_C_SHORT, (UCHAR*) &structSQLTypeInfo.MinimumScale, 0, &cbRet) != SQL_SUCCESS) +// return(DispAllErrors(henv, hdbc, hstmt)); + + if (SQLGetData(hstmt, 15, SQL_C_SHORT,(UCHAR*) &structSQLTypeInfo.MaximumScale, 0, &cbRet) != SQL_SUCCESS) + return(DispAllErrors(henv, hdbc, hstmt)); + + if (structSQLTypeInfo.MaximumScale < 0) + structSQLTypeInfo.MaximumScale = 0; + + // Close the statement handle which closes open cursors + if (SQLFreeStmt(hstmt, SQL_CLOSE) != SQL_SUCCESS) + return(DispAllErrors(henv, hdbc, hstmt)); + + // Completed Successfully + return true; + +} // wxDb::getDataTypeInfo() + + +/********** wxDb::Close() **********/ +void wxDb::Close(void) +{ + // Close the Sql Log file + if (fpSqlLog) + { + fclose(fpSqlLog); + fpSqlLog = 0; + } + + // Free statement handle + if (dbIsOpen) + { + if (SQLFreeStmt(hstmt, SQL_DROP) != SQL_SUCCESS) + DispAllErrors(henv, hdbc); + } + + // Disconnect from the datasource + if (SQLDisconnect(hdbc) != SQL_SUCCESS) + DispAllErrors(henv, hdbc); + + // Free the connection to the datasource + if (SQLFreeConnect(hdbc) != SQL_SUCCESS) + DispAllErrors(henv, hdbc); + + // There should be zero Ctable objects still connected to this db object + wxASSERT(nTables == 0); + +#ifdef __WXDEBUG__ + { +#if wxUSE_THREADS + wxCriticalSectionLocker lock(csTablesInUse); +#endif // wxUSE_THREADS + wxTablesInUse *tiu; + wxList::compatibility_iterator pNode; + pNode = TablesInUse.GetFirst(); + wxString s,s2; + while (pNode) + { + tiu = (wxTablesInUse *)pNode->GetData(); + if (tiu->pDb == this) + { + s.Printf(wxT("(%-20s) tableID:[%6lu] pDb:[%p]"), + tiu->tableName, tiu->tableID, wx_static_cast(void*, tiu->pDb)); + s2.Printf(wxT("Orphaned table found using pDb:[%p]"), wx_static_cast(void*, this)); + wxLogDebug(s.c_str(),s2.c_str()); + } + pNode = pNode->GetNext(); + } + } +#endif + + // Copy the error messages to a global variable + int i; + for (i = 0; i < DB_MAX_ERROR_HISTORY; i++) + wxStrcpy(DBerrorList[i], errorList[i]); + + dbmsType = dbmsUNIDENTIFIED; + dbIsOpen = false; + +} // wxDb::Close() + + +/********** wxDb::CommitTrans() **********/ +bool wxDb::CommitTrans(void) +{ + if (this) + { + // Commit the transaction + if (SQLTransact(henv, hdbc, SQL_COMMIT) != SQL_SUCCESS) + return(DispAllErrors(henv, hdbc)); + } + + // Completed successfully + return true; + +} // wxDb::CommitTrans() + + +/********** wxDb::RollbackTrans() **********/ +bool wxDb::RollbackTrans(void) +{ + // Rollback the transaction + if (SQLTransact(henv, hdbc, SQL_ROLLBACK) != SQL_SUCCESS) + return(DispAllErrors(henv, hdbc)); + + // Completed successfully + return true; + +} // wxDb::RollbackTrans() + + +/********** wxDb::DispAllErrors() **********/ +bool wxDb::DispAllErrors(HENV aHenv, HDBC aHdbc, HSTMT aHstmt) +/* + * This function is called internally whenever an error condition prevents the user's + * request from being executed. This function will query the datasource as to the + * actual error(s) that just occurred on the previous request of the datasource. + * + * The function will retrieve each error condition from the datasource and + * Printf the codes/text values into a string which it then logs via logError(). + * If in DBDEBUG_CONSOLE mode, the constructed string will be displayed in the console + * window and program execution will be paused until the user presses a key. + * + * This function always returns false, so that functions which call this function + * can have a line like "return (DispAllErrors(henv, hdbc));" to indicate the failure + * of the user's request, so that the calling code can then process the error message log. + */ +{ + wxString odbcErrMsg; + + while (SQLError(aHenv, aHdbc, aHstmt, (SQLTCHAR FAR *) sqlState, &nativeError, (SQLTCHAR FAR *) errorMsg, SQL_MAX_MESSAGE_LENGTH - 1, &cbErrorMsg) == SQL_SUCCESS) + { + odbcErrMsg.Printf(wxT("SQL State = %s\nNative Error Code = %li\nError Message = %s\n"), + sqlState, (long)nativeError, errorMsg); + logError(odbcErrMsg, sqlState); + if (!silent) + { +#ifdef DBDEBUG_CONSOLE + // When run in console mode, use standard out to display errors. + cout << odbcErrMsg.c_str() << endl; + cout << wxT("Press any key to continue...") << endl; + getchar(); +#endif + +#ifdef __WXDEBUG__ + wxLogDebug(odbcErrMsg,wxT("ODBC DEBUG MESSAGE from DispAllErrors()")); +#endif + } + } + + return false; // This function always returns false. + +} // wxDb::DispAllErrors() + + +/********** wxDb::GetNextError() **********/ +bool wxDb::GetNextError(HENV aHenv, HDBC aHdbc, HSTMT aHstmt) +{ + if (SQLError(aHenv, aHdbc, aHstmt, (SQLTCHAR FAR *) sqlState, &nativeError, (SQLTCHAR FAR *) errorMsg, SQL_MAX_MESSAGE_LENGTH - 1, &cbErrorMsg) == SQL_SUCCESS) + return true; + else + return false; + +} // wxDb::GetNextError() + + +/********** wxDb::DispNextError() **********/ +void wxDb::DispNextError(void) +{ + wxString odbcErrMsg; + + odbcErrMsg.Printf(wxT("SQL State = %s\nNative Error Code = %li\nError Message = %s\n"), + sqlState, (long)nativeError, errorMsg); + logError(odbcErrMsg, sqlState); + + if (silent) + return; + +#ifdef DBDEBUG_CONSOLE + // When run in console mode, use standard out to display errors. + cout << odbcErrMsg.c_str() << endl; + cout << wxT("Press any key to continue...") << endl; + getchar(); +#endif + +#ifdef __WXDEBUG__ + wxLogDebug(odbcErrMsg,wxT("ODBC DEBUG MESSAGE")); +#endif // __WXDEBUG__ + +} // wxDb::DispNextError() + + +/********** wxDb::logError() **********/ +void wxDb::logError(const wxString &errMsg, const wxString &SQLState) +{ + wxASSERT(errMsg.length()); + + static int pLast = -1; + int dbStatus; + + if (++pLast == DB_MAX_ERROR_HISTORY) + { + int i; + for (i = 0; i < DB_MAX_ERROR_HISTORY-1; i++) + wxStrcpy(errorList[i], errorList[i+1]); + pLast--; + } + + wxStrncpy(errorList[pLast], errMsg, DB_MAX_ERROR_MSG_LEN); + errorList[pLast][DB_MAX_ERROR_MSG_LEN-1] = 0; + + if (SQLState.length()) + if ((dbStatus = TranslateSqlState(SQLState)) != DB_ERR_FUNCTION_SEQUENCE_ERROR) + DB_STATUS = dbStatus; + + // Add the errmsg to the sql log + WriteSqlLog(errMsg); + +} // wxDb::logError() + + +/**********wxDb::TranslateSqlState() **********/ +int wxDb::TranslateSqlState(const wxString &SQLState) +{ + if (!wxStrcmp(SQLState, wxT("01000"))) + return(DB_ERR_GENERAL_WARNING); + if (!wxStrcmp(SQLState, wxT("01002"))) + return(DB_ERR_DISCONNECT_ERROR); + if (!wxStrcmp(SQLState, wxT("01004"))) + return(DB_ERR_DATA_TRUNCATED); + if (!wxStrcmp(SQLState, wxT("01006"))) + return(DB_ERR_PRIV_NOT_REVOKED); + if (!wxStrcmp(SQLState, wxT("01S00"))) + return(DB_ERR_INVALID_CONN_STR_ATTR); + if (!wxStrcmp(SQLState, wxT("01S01"))) + return(DB_ERR_ERROR_IN_ROW); + if (!wxStrcmp(SQLState, wxT("01S02"))) + return(DB_ERR_OPTION_VALUE_CHANGED); + if (!wxStrcmp(SQLState, wxT("01S03"))) + return(DB_ERR_NO_ROWS_UPD_OR_DEL); + if (!wxStrcmp(SQLState, wxT("01S04"))) + return(DB_ERR_MULTI_ROWS_UPD_OR_DEL); + if (!wxStrcmp(SQLState, wxT("07001"))) + return(DB_ERR_WRONG_NO_OF_PARAMS); + if (!wxStrcmp(SQLState, wxT("07006"))) + return(DB_ERR_DATA_TYPE_ATTR_VIOL); + if (!wxStrcmp(SQLState, wxT("08001"))) + return(DB_ERR_UNABLE_TO_CONNECT); + if (!wxStrcmp(SQLState, wxT("08002"))) + return(DB_ERR_CONNECTION_IN_USE); + if (!wxStrcmp(SQLState, wxT("08003"))) + return(DB_ERR_CONNECTION_NOT_OPEN); + if (!wxStrcmp(SQLState, wxT("08004"))) + return(DB_ERR_REJECTED_CONNECTION); + if (!wxStrcmp(SQLState, wxT("08007"))) + return(DB_ERR_CONN_FAIL_IN_TRANS); + if (!wxStrcmp(SQLState, wxT("08S01"))) + return(DB_ERR_COMM_LINK_FAILURE); + if (!wxStrcmp(SQLState, wxT("21S01"))) + return(DB_ERR_INSERT_VALUE_LIST_MISMATCH); + if (!wxStrcmp(SQLState, wxT("21S02"))) + return(DB_ERR_DERIVED_TABLE_MISMATCH); + if (!wxStrcmp(SQLState, wxT("22001"))) + return(DB_ERR_STRING_RIGHT_TRUNC); + if (!wxStrcmp(SQLState, wxT("22003"))) + return(DB_ERR_NUMERIC_VALUE_OUT_OF_RNG); + if (!wxStrcmp(SQLState, wxT("22005"))) + return(DB_ERR_ERROR_IN_ASSIGNMENT); + if (!wxStrcmp(SQLState, wxT("22008"))) + return(DB_ERR_DATETIME_FLD_OVERFLOW); + if (!wxStrcmp(SQLState, wxT("22012"))) + return(DB_ERR_DIVIDE_BY_ZERO); + if (!wxStrcmp(SQLState, wxT("22026"))) + return(DB_ERR_STR_DATA_LENGTH_MISMATCH); + if (!wxStrcmp(SQLState, wxT("23000"))) + return(DB_ERR_INTEGRITY_CONSTRAINT_VIOL); + if (!wxStrcmp(SQLState, wxT("24000"))) + return(DB_ERR_INVALID_CURSOR_STATE); + if (!wxStrcmp(SQLState, wxT("25000"))) + return(DB_ERR_INVALID_TRANS_STATE); + if (!wxStrcmp(SQLState, wxT("28000"))) + return(DB_ERR_INVALID_AUTH_SPEC); + if (!wxStrcmp(SQLState, wxT("34000"))) + return(DB_ERR_INVALID_CURSOR_NAME); + if (!wxStrcmp(SQLState, wxT("37000"))) + return(DB_ERR_SYNTAX_ERROR_OR_ACCESS_VIOL); + if (!wxStrcmp(SQLState, wxT("3C000"))) + return(DB_ERR_DUPLICATE_CURSOR_NAME); + if (!wxStrcmp(SQLState, wxT("40001"))) + return(DB_ERR_SERIALIZATION_FAILURE); + if (!wxStrcmp(SQLState, wxT("42000"))) + return(DB_ERR_SYNTAX_ERROR_OR_ACCESS_VIOL2); + if (!wxStrcmp(SQLState, wxT("70100"))) + return(DB_ERR_OPERATION_ABORTED); + if (!wxStrcmp(SQLState, wxT("IM001"))) + return(DB_ERR_UNSUPPORTED_FUNCTION); + if (!wxStrcmp(SQLState, wxT("IM002"))) + return(DB_ERR_NO_DATA_SOURCE); + if (!wxStrcmp(SQLState, wxT("IM003"))) + return(DB_ERR_DRIVER_LOAD_ERROR); + if (!wxStrcmp(SQLState, wxT("IM004"))) + return(DB_ERR_SQLALLOCENV_FAILED); + if (!wxStrcmp(SQLState, wxT("IM005"))) + return(DB_ERR_SQLALLOCCONNECT_FAILED); + if (!wxStrcmp(SQLState, wxT("IM006"))) + return(DB_ERR_SQLSETCONNECTOPTION_FAILED); + if (!wxStrcmp(SQLState, wxT("IM007"))) + return(DB_ERR_NO_DATA_SOURCE_DLG_PROHIB); + if (!wxStrcmp(SQLState, wxT("IM008"))) + return(DB_ERR_DIALOG_FAILED); + if (!wxStrcmp(SQLState, wxT("IM009"))) + return(DB_ERR_UNABLE_TO_LOAD_TRANSLATION_DLL); + if (!wxStrcmp(SQLState, wxT("IM010"))) + return(DB_ERR_DATA_SOURCE_NAME_TOO_LONG); + if (!wxStrcmp(SQLState, wxT("IM011"))) + return(DB_ERR_DRIVER_NAME_TOO_LONG); + if (!wxStrcmp(SQLState, wxT("IM012"))) + return(DB_ERR_DRIVER_KEYWORD_SYNTAX_ERROR); + if (!wxStrcmp(SQLState, wxT("IM013"))) + return(DB_ERR_TRACE_FILE_ERROR); + if (!wxStrcmp(SQLState, wxT("S0001"))) + return(DB_ERR_TABLE_OR_VIEW_ALREADY_EXISTS); + if (!wxStrcmp(SQLState, wxT("S0002"))) + return(DB_ERR_TABLE_NOT_FOUND); + if (!wxStrcmp(SQLState, wxT("S0011"))) + return(DB_ERR_INDEX_ALREADY_EXISTS); + if (!wxStrcmp(SQLState, wxT("S0012"))) + return(DB_ERR_INDEX_NOT_FOUND); + if (!wxStrcmp(SQLState, wxT("S0021"))) + return(DB_ERR_COLUMN_ALREADY_EXISTS); + if (!wxStrcmp(SQLState, wxT("S0022"))) + return(DB_ERR_COLUMN_NOT_FOUND); + if (!wxStrcmp(SQLState, wxT("S0023"))) + return(DB_ERR_NO_DEFAULT_FOR_COLUMN); + if (!wxStrcmp(SQLState, wxT("S1000"))) + return(DB_ERR_GENERAL_ERROR); + if (!wxStrcmp(SQLState, wxT("S1001"))) + return(DB_ERR_MEMORY_ALLOCATION_FAILURE); + if (!wxStrcmp(SQLState, wxT("S1002"))) + return(DB_ERR_INVALID_COLUMN_NUMBER); + if (!wxStrcmp(SQLState, wxT("S1003"))) + return(DB_ERR_PROGRAM_TYPE_OUT_OF_RANGE); + if (!wxStrcmp(SQLState, wxT("S1004"))) + return(DB_ERR_SQL_DATA_TYPE_OUT_OF_RANGE); + if (!wxStrcmp(SQLState, wxT("S1008"))) + return(DB_ERR_OPERATION_CANCELLED); + if (!wxStrcmp(SQLState, wxT("S1009"))) + return(DB_ERR_INVALID_ARGUMENT_VALUE); + if (!wxStrcmp(SQLState, wxT("S1010"))) + return(DB_ERR_FUNCTION_SEQUENCE_ERROR); + if (!wxStrcmp(SQLState, wxT("S1011"))) + return(DB_ERR_OPERATION_INVALID_AT_THIS_TIME); + if (!wxStrcmp(SQLState, wxT("S1012"))) + return(DB_ERR_INVALID_TRANS_OPERATION_CODE); + if (!wxStrcmp(SQLState, wxT("S1015"))) + return(DB_ERR_NO_CURSOR_NAME_AVAIL); + if (!wxStrcmp(SQLState, wxT("S1090"))) + return(DB_ERR_INVALID_STR_OR_BUF_LEN); + if (!wxStrcmp(SQLState, wxT("S1091"))) + return(DB_ERR_DESCRIPTOR_TYPE_OUT_OF_RANGE); + if (!wxStrcmp(SQLState, wxT("S1092"))) + return(DB_ERR_OPTION_TYPE_OUT_OF_RANGE); + if (!wxStrcmp(SQLState, wxT("S1093"))) + return(DB_ERR_INVALID_PARAM_NO); + if (!wxStrcmp(SQLState, wxT("S1094"))) + return(DB_ERR_INVALID_SCALE_VALUE); + if (!wxStrcmp(SQLState, wxT("S1095"))) + return(DB_ERR_FUNCTION_TYPE_OUT_OF_RANGE); + if (!wxStrcmp(SQLState, wxT("S1096"))) + return(DB_ERR_INF_TYPE_OUT_OF_RANGE); + if (!wxStrcmp(SQLState, wxT("S1097"))) + return(DB_ERR_COLUMN_TYPE_OUT_OF_RANGE); + if (!wxStrcmp(SQLState, wxT("S1098"))) + return(DB_ERR_SCOPE_TYPE_OUT_OF_RANGE); + if (!wxStrcmp(SQLState, wxT("S1099"))) + return(DB_ERR_NULLABLE_TYPE_OUT_OF_RANGE); + if (!wxStrcmp(SQLState, wxT("S1100"))) + return(DB_ERR_UNIQUENESS_OPTION_TYPE_OUT_OF_RANGE); + if (!wxStrcmp(SQLState, wxT("S1101"))) + return(DB_ERR_ACCURACY_OPTION_TYPE_OUT_OF_RANGE); + if (!wxStrcmp(SQLState, wxT("S1103"))) + return(DB_ERR_DIRECTION_OPTION_OUT_OF_RANGE); + if (!wxStrcmp(SQLState, wxT("S1104"))) + return(DB_ERR_INVALID_PRECISION_VALUE); + if (!wxStrcmp(SQLState, wxT("S1105"))) + return(DB_ERR_INVALID_PARAM_TYPE); + if (!wxStrcmp(SQLState, wxT("S1106"))) + return(DB_ERR_FETCH_TYPE_OUT_OF_RANGE); + if (!wxStrcmp(SQLState, wxT("S1107"))) + return(DB_ERR_ROW_VALUE_OUT_OF_RANGE); + if (!wxStrcmp(SQLState, wxT("S1108"))) + return(DB_ERR_CONCURRENCY_OPTION_OUT_OF_RANGE); + if (!wxStrcmp(SQLState, wxT("S1109"))) + return(DB_ERR_INVALID_CURSOR_POSITION); + if (!wxStrcmp(SQLState, wxT("S1110"))) + return(DB_ERR_INVALID_DRIVER_COMPLETION); + if (!wxStrcmp(SQLState, wxT("S1111"))) + return(DB_ERR_INVALID_BOOKMARK_VALUE); + if (!wxStrcmp(SQLState, wxT("S1C00"))) + return(DB_ERR_DRIVER_NOT_CAPABLE); + if (!wxStrcmp(SQLState, wxT("S1T00"))) + return(DB_ERR_TIMEOUT_EXPIRED); + + // No match + return(0); + +} // wxDb::TranslateSqlState() + + +/********** wxDb::Grant() **********/ +bool wxDb::Grant(int privileges, const wxString &tableName, const wxString &userList) +{ + wxString sqlStmt; + + // Build the grant statement + sqlStmt = wxT("GRANT "); + if (privileges == DB_GRANT_ALL) + sqlStmt += wxT("ALL"); + else + { + int c = 0; + if (privileges & DB_GRANT_SELECT) + { + sqlStmt += wxT("SELECT"); + c++; + } + if (privileges & DB_GRANT_INSERT) + { + if (c++) + sqlStmt += wxT(", "); + sqlStmt += wxT("INSERT"); + } + if (privileges & DB_GRANT_UPDATE) + { + if (c++) + sqlStmt += wxT(", "); + sqlStmt += wxT("UPDATE"); + } + if (privileges & DB_GRANT_DELETE) + { + if (c++) + sqlStmt += wxT(", "); + sqlStmt += wxT("DELETE"); + } + } + + sqlStmt += wxT(" ON "); + sqlStmt += SQLTableName(tableName); + sqlStmt += wxT(" TO "); + sqlStmt += userList; + +#ifdef DBDEBUG_CONSOLE + cout << endl << sqlStmt.c_str() << endl; +#endif + + WriteSqlLog(sqlStmt); + + return(ExecSql(sqlStmt)); + +} // wxDb::Grant() + + +/********** wxDb::CreateView() **********/ +bool wxDb::CreateView(const wxString &viewName, const wxString &colList, + const wxString &pSqlStmt, bool attemptDrop) +{ + wxString sqlStmt; + + // Drop the view first + if (attemptDrop && !DropView(viewName)) + return false; + + // Build the create view statement + sqlStmt = wxT("CREATE VIEW "); + sqlStmt += viewName; + + if (colList.length()) + { + sqlStmt += wxT(" ("); + sqlStmt += colList; + sqlStmt += wxT(")"); + } + + sqlStmt += wxT(" AS "); + sqlStmt += pSqlStmt; + + WriteSqlLog(sqlStmt); + +#ifdef DBDEBUG_CONSOLE + cout << sqlStmt.c_str() << endl; +#endif + + return(ExecSql(sqlStmt)); + +} // wxDb::CreateView() + + +/********** wxDb::DropView() **********/ +bool wxDb::DropView(const wxString &viewName) +{ +/* + * NOTE: This function returns true if the View does not exist, but + * only for identified databases. Code will need to be added + * below for any other databases when those databases are defined + * to handle this situation consistently + */ + wxString sqlStmt; + + sqlStmt.Printf(wxT("DROP VIEW %s"), viewName.c_str()); + + WriteSqlLog(sqlStmt); + +#ifdef DBDEBUG_CONSOLE + cout << endl << sqlStmt.c_str() << endl; +#endif + + if (SQLExecDirect(hstmt, (SQLTCHAR FAR *) sqlStmt.c_str(), SQL_NTS) != SQL_SUCCESS) + { + // Check for "Base table not found" error and ignore + GetNextError(henv, hdbc, hstmt); + if (wxStrcmp(sqlState,wxT("S0002"))) // "Base table not found" + { + // Check for product specific error codes + if (!((Dbms() == dbmsSYBASE_ASA && !wxStrcmp(sqlState,wxT("42000"))))) // 5.x (and lower?) + { + DispNextError(); + DispAllErrors(henv, hdbc, hstmt); + RollbackTrans(); + return false; + } + } + } + + // Commit the transaction + if (!CommitTrans()) + return false; + + return true; + +} // wxDb::DropView() + + +/********** wxDb::ExecSql() **********/ +bool wxDb::ExecSql(const wxString &pSqlStmt) +{ + RETCODE retcode; + + SQLFreeStmt(hstmt, SQL_CLOSE); + + retcode = SQLExecDirect(hstmt, (SQLTCHAR FAR *) pSqlStmt.c_str(), SQL_NTS); + if (retcode == SQL_SUCCESS || + (Dbms() == dbmsDB2 && (retcode == SQL_SUCCESS_WITH_INFO || retcode == SQL_NO_DATA_FOUND))) + { + return true; + } + else + { + DispAllErrors(henv, hdbc, hstmt); + return false; + } + +} // wxDb::ExecSql() + + +/********** wxDb::ExecSql() with column info **********/ +bool wxDb::ExecSql(const wxString &pSqlStmt, wxDbColInf** columns, short& numcols) +{ + //execute the statement first + if (!ExecSql(pSqlStmt)) + return false; + + SWORD noCols; + if (SQLNumResultCols(hstmt, &noCols) != SQL_SUCCESS) + { + DispAllErrors(henv, hdbc, hstmt); + return false; + } + + if (noCols == 0) + return false; + else + numcols = noCols; + + // Get column information + short colNum; + wxChar name[DB_MAX_COLUMN_NAME_LEN+1]; + SWORD Sword; + SQLLEN Sqllen; + wxDbColInf* pColInf = new wxDbColInf[noCols]; + + // Fill in column information (name, datatype) + for (colNum = 0; colNum < noCols; colNum++) + { + if (SQLColAttributes(hstmt, (UWORD)(colNum+1), SQL_COLUMN_NAME, + name, sizeof(name), + &Sword, &Sqllen) != SQL_SUCCESS) + { + DispAllErrors(henv, hdbc, hstmt); + delete[] pColInf; + return false; + } + + wxStrncpy(pColInf[colNum].colName, name, DB_MAX_COLUMN_NAME_LEN); + pColInf[colNum].colName[DB_MAX_COLUMN_NAME_LEN] = 0; // Prevent buffer overrun + + if (SQLColAttributes(hstmt, (UWORD)(colNum+1), SQL_COLUMN_TYPE, + NULL, 0, &Sword, &Sqllen) != SQL_SUCCESS) + { + DispAllErrors(henv, hdbc, hstmt); + delete[] pColInf; + return false; + } + + switch (Sqllen) + { +#if wxUSE_UNICODE + #if defined(SQL_WCHAR) + case SQL_WCHAR: + #endif + #if defined(SQL_WVARCHAR) + case SQL_WVARCHAR: + #endif +#endif + case SQL_VARCHAR: + case SQL_CHAR: + pColInf[colNum].dbDataType = DB_DATA_TYPE_VARCHAR; + break; + case SQL_LONGVARCHAR: + pColInf[colNum].dbDataType = DB_DATA_TYPE_MEMO; + break; + case SQL_TINYINT: + case SQL_SMALLINT: + case SQL_INTEGER: + case SQL_BIT: + pColInf[colNum].dbDataType = DB_DATA_TYPE_INTEGER; + break; + case SQL_DOUBLE: + case SQL_DECIMAL: + case SQL_NUMERIC: + case SQL_FLOAT: + case SQL_REAL: + pColInf[colNum].dbDataType = DB_DATA_TYPE_FLOAT; + break; + case SQL_DATE: + case SQL_TIMESTAMP: + pColInf[colNum].dbDataType = DB_DATA_TYPE_DATE; + break; + case SQL_BINARY: + pColInf[colNum].dbDataType = DB_DATA_TYPE_BLOB; + break; +#ifdef __WXDEBUG__ + default: + wxString errMsg; + errMsg.Printf(wxT("SQL Data type %ld currently not supported by wxWidgets"), (long)Sqllen); + wxLogDebug(errMsg,wxT("ODBC DEBUG MESSAGE")); +#endif + } + } + + *columns = pColInf; + return true; +} // wxDb::ExecSql() + +/********** wxDb::GetNext() **********/ +bool wxDb::GetNext(void) +{ + if (SQLFetch(hstmt) == SQL_SUCCESS) + return true; + else + { + DispAllErrors(henv, hdbc, hstmt); + return false; + } + +} // wxDb::GetNext() + + +/********** wxDb::GetData() **********/ +bool wxDb::GetData(UWORD colNo, SWORD cType, PTR pData, SDWORD maxLen, SQLLEN FAR *cbReturned) +{ + wxASSERT(pData); + wxASSERT(cbReturned); + + long bufferSize = maxLen; + + if (cType == SQL_C_WXCHAR) + bufferSize = maxLen * sizeof(wxChar); + + if (SQLGetData(hstmt, colNo, cType, pData, bufferSize, cbReturned) == SQL_SUCCESS) + return true; + else + { + DispAllErrors(henv, hdbc, hstmt); + return false; + } + +} // wxDb::GetData() + + +/********** wxDb::GetKeyFields() **********/ +int wxDb::GetKeyFields(const wxString &tableName, wxDbColInf* colInf, UWORD noCols) +{ + wxChar szPkTable[DB_MAX_TABLE_NAME_LEN+1]; /* Primary key table name */ + wxChar szFkTable[DB_MAX_TABLE_NAME_LEN+1]; /* Foreign key table name */ + SWORD iKeySeq; + wxChar szPkCol[DB_MAX_COLUMN_NAME_LEN+1]; /* Primary key column */ + wxChar szFkCol[DB_MAX_COLUMN_NAME_LEN+1]; /* Foreign key column */ + SQLRETURN retcode; + SQLLEN cb; + SWORD i; + wxString tempStr; + /* + * ----------------------------------------------------------------------- + * -- 19991224 : mj10777 : Create ------ + * -- : Three things are done and stored here : ------ + * -- : 1) which Column(s) is/are Primary Key(s) ------ + * -- : 2) which tables use this Key as a Foreign Key ------ + * -- : 3) which columns are Foreign Key and the name ------ + * -- : of the Table where the Key is the Primary Key ----- + * -- : Called from GetColumns(const wxString &tableName, ------ + * -- int *numCols,const wxChar *userID ) ------ + * ----------------------------------------------------------------------- + */ + + /*---------------------------------------------------------------------*/ + /* Get the names of the columns in the primary key. */ + /*---------------------------------------------------------------------*/ + retcode = SQLPrimaryKeys(hstmt, + NULL, 0, /* Catalog name */ + NULL, 0, /* Schema name */ + (SQLTCHAR FAR *) tableName.c_str(), SQL_NTS); /* Table name */ + + /*---------------------------------------------------------------------*/ + /* Fetch and display the result set. This will be a list of the */ + /* columns in the primary key of the tableName table. */ + /*---------------------------------------------------------------------*/ + while ((retcode == SQL_SUCCESS) || (retcode == SQL_SUCCESS_WITH_INFO)) + { + retcode = SQLFetch(hstmt); + if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) + { + GetData( 4, SQL_C_WXCHAR, szPkCol, DB_MAX_COLUMN_NAME_LEN+1, &cb); + GetData( 5, SQL_C_SSHORT, &iKeySeq, 0, &cb); + //------- + for (i=0;iGetColumns(tableList, userID); + * if (colInf) + * { + * // Use the column inf + * ....... + * // Destroy the memory + * delete [] colInf; + * } + * + * userID is evaluated in the following manner: + * userID == NULL ... UserID is ignored + * userID == "" ... UserID set equal to 'this->uid' + * userID != "" ... UserID set equal to 'userID' + * + * NOTE: ALL column bindings associated with this wxDb instance are unbound + * by this function. This function should use its own wxDb instance + * to avoid undesired unbinding of columns. + */ +{ + UWORD noCols = 0; + UWORD colNo = 0; + wxDbColInf *colInf = 0; + + RETCODE retcode; + SQLLEN cb; + + wxString TableName; + + wxString UserID; + convertUserID(userID,UserID); + + // Pass 1 - Determine how many columns there are. + // Pass 2 - Allocate the wxDbColInf array and fill in + // the array with the column information. + int pass; + for (pass = 1; pass <= 2; pass++) + { + if (pass == 2) + { + if (noCols == 0) // Probably a bogus table name(s) + break; + // Allocate n wxDbColInf objects to hold the column information + colInf = new wxDbColInf[noCols+1]; + if (!colInf) + break; + // Mark the end of the array + wxStrcpy(colInf[noCols].tableName, wxEmptyString); + wxStrcpy(colInf[noCols].colName, wxEmptyString); + colInf[noCols].sqlDataType = 0; + } + // Loop through each table name + int tbl; + for (tbl = 0; tableName[tbl]; tbl++) + { + TableName = tableName[tbl]; + // Oracle and Interbase table names are uppercase only, so force + // the name to uppercase just in case programmer forgot to do this + if ((Dbms() == dbmsORACLE) || + (Dbms() == dbmsFIREBIRD) || + (Dbms() == dbmsINTERBASE)) + TableName = TableName.Upper(); + + SQLFreeStmt(hstmt, SQL_CLOSE); + + // MySQL, SQLServer, and Access cannot accept a user name when looking up column names, so we + // use the call below that leaves out the user name + if (!UserID.empty() && + Dbms() != dbmsMY_SQL && + Dbms() != dbmsACCESS && + Dbms() != dbmsMS_SQL_SERVER) + { + retcode = SQLColumns(hstmt, + NULL, 0, // All qualifiers + (SQLTCHAR *) UserID.c_str(), SQL_NTS, // Owner + (SQLTCHAR *) TableName.c_str(), SQL_NTS, + NULL, 0); // All columns + } + else + { + retcode = SQLColumns(hstmt, + NULL, 0, // All qualifiers + NULL, 0, // Owner + (SQLTCHAR *) TableName.c_str(), SQL_NTS, + NULL, 0); // All columns + } + if (retcode != SQL_SUCCESS) + { // Error occurred, abort + DispAllErrors(henv, hdbc, hstmt); + if (colInf) + delete [] colInf; + SQLFreeStmt(hstmt, SQL_CLOSE); + return(0); + } + + while ((retcode = SQLFetch(hstmt)) == SQL_SUCCESS) + { + if (pass == 1) // First pass, just add up the number of columns + noCols++; + else // Pass 2; Fill in the array of structures + { + if (colNo < noCols) // Some extra error checking to prevent memory overwrites + { + // NOTE: Only the ODBC 1.x fields are retrieved + GetData( 1, SQL_C_WXCHAR, (UCHAR*) colInf[colNo].catalog, 128+1, &cb); + GetData( 2, SQL_C_WXCHAR, (UCHAR*) colInf[colNo].schema, 128+1, &cb); + GetData( 3, SQL_C_WXCHAR, (UCHAR*) colInf[colNo].tableName, DB_MAX_TABLE_NAME_LEN+1, &cb); + GetData( 4, SQL_C_WXCHAR, (UCHAR*) colInf[colNo].colName, DB_MAX_COLUMN_NAME_LEN+1, &cb); + GetData( 5, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].sqlDataType, 0, &cb); + GetData( 6, SQL_C_WXCHAR, (UCHAR*) colInf[colNo].typeName, 128+1, &cb); + GetData( 7, SQL_C_SLONG, (UCHAR*) &colInf[colNo].columnLength, 0, &cb); + GetData( 8, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].bufferSize, 0, &cb); + GetData( 9, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].decimalDigits,0, &cb); + GetData(10, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].numPrecRadix, 0, &cb); + GetData(11, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].nullable, 0, &cb); + GetData(12, SQL_C_WXCHAR, (UCHAR*) colInf[colNo].remarks, 254+1, &cb); + + // Determine the wxDb data type that is used to represent the native data type of this data source + colInf[colNo].dbDataType = 0; + if (!wxStricmp(typeInfVarchar.TypeName,colInf[colNo].typeName)) + { +#ifdef _IODBC_ + // IODBC does not return a correct columnLength, so we set + // columnLength = bufferSize if no column length was returned + // IODBC returns the columnLength in bufferSize. (bug) + if (colInf[colNo].columnLength < 1) + { + colInf[colNo].columnLength = colInf[colNo].bufferSize; + } +#endif + colInf[colNo].dbDataType = DB_DATA_TYPE_VARCHAR; + } + else if (!wxStricmp(typeInfInteger.TypeName, colInf[colNo].typeName)) + colInf[colNo].dbDataType = DB_DATA_TYPE_INTEGER; + else if (!wxStricmp(typeInfFloat.TypeName, colInf[colNo].typeName)) + colInf[colNo].dbDataType = DB_DATA_TYPE_FLOAT; + else if (!wxStricmp(typeInfDate.TypeName, colInf[colNo].typeName)) + colInf[colNo].dbDataType = DB_DATA_TYPE_DATE; + else if (!wxStricmp(typeInfBlob.TypeName, colInf[colNo].typeName)) + colInf[colNo].dbDataType = DB_DATA_TYPE_BLOB; + colNo++; + } + } + } + if (retcode != SQL_NO_DATA_FOUND) + { // Error occurred, abort + DispAllErrors(henv, hdbc, hstmt); + if (colInf) + delete [] colInf; + SQLFreeStmt(hstmt, SQL_CLOSE); + return(0); + } + } + } + + SQLFreeStmt(hstmt, SQL_CLOSE); + return colInf; + +} // wxDb::GetColumns() + + +/********** wxDb::GetColumns() **********/ + +wxDbColInf *wxDb::GetColumns(const wxString &tableName, UWORD *numCols, const wxChar *userID) +// +// Same as the above GetColumns() function except this one gets columns +// only for a single table, and if 'numCols' is not NULL, the number of +// columns stored in the returned wxDbColInf is set in '*numCols' +// +// userID is evaluated in the following manner: +// userID == NULL ... UserID is ignored +// userID == "" ... UserID set equal to 'this->uid' +// userID != "" ... UserID set equal to 'userID' +// +// NOTE: ALL column bindings associated with this wxDb instance are unbound +// by this function. This function should use its own wxDb instance +// to avoid undesired unbinding of columns. + +{ + UWORD noCols = 0; + UWORD colNo = 0; + wxDbColInf *colInf = 0; + + RETCODE retcode; + SQLLEN cb; + + wxString TableName; + + wxString UserID; + convertUserID(userID,UserID); + + // Pass 1 - Determine how many columns there are. + // Pass 2 - Allocate the wxDbColInf array and fill in + // the array with the column information. + int pass; + for (pass = 1; pass <= 2; pass++) + { + if (pass == 2) + { + if (noCols == 0) // Probably a bogus table name(s) + break; + // Allocate n wxDbColInf objects to hold the column information + colInf = new wxDbColInf[noCols+1]; + if (!colInf) + break; + // Mark the end of the array + wxStrcpy(colInf[noCols].tableName, wxEmptyString); + wxStrcpy(colInf[noCols].colName, wxEmptyString); + colInf[noCols].sqlDataType = 0; + } + + TableName = tableName; + // Oracle and Interbase table names are uppercase only, so force + // the name to uppercase just in case programmer forgot to do this + if ((Dbms() == dbmsORACLE) || + (Dbms() == dbmsFIREBIRD) || + (Dbms() == dbmsINTERBASE)) + TableName = TableName.Upper(); + + SQLFreeStmt(hstmt, SQL_CLOSE); + + // MySQL, SQLServer, and Access cannot accept a user name when looking up column names, so we + // use the call below that leaves out the user name + if (!UserID.empty() && + Dbms() != dbmsMY_SQL && + Dbms() != dbmsACCESS && + Dbms() != dbmsMS_SQL_SERVER) + { + retcode = SQLColumns(hstmt, + NULL, 0, // All qualifiers + (SQLTCHAR *) UserID.c_str(), SQL_NTS, // Owner + (SQLTCHAR *) TableName.c_str(), SQL_NTS, + NULL, 0); // All columns + } + else + { + retcode = SQLColumns(hstmt, + NULL, 0, // All qualifiers + NULL, 0, // Owner + (SQLTCHAR *) TableName.c_str(), SQL_NTS, + NULL, 0); // All columns + } + if (retcode != SQL_SUCCESS) + { // Error occurred, abort + DispAllErrors(henv, hdbc, hstmt); + if (colInf) + delete [] colInf; + SQLFreeStmt(hstmt, SQL_CLOSE); + if (numCols) + *numCols = 0; + return(0); + } + + while ((retcode = SQLFetch(hstmt)) == SQL_SUCCESS) + { + if (pass == 1) // First pass, just add up the number of columns + noCols++; + else // Pass 2; Fill in the array of structures + { + if (colNo < noCols) // Some extra error checking to prevent memory overwrites + { + // NOTE: Only the ODBC 1.x fields are retrieved + GetData( 1, SQL_C_WXCHAR, (UCHAR*) colInf[colNo].catalog, 128+1, &cb); + GetData( 2, SQL_C_WXCHAR, (UCHAR*) colInf[colNo].schema, 128+1, &cb); + GetData( 3, SQL_C_WXCHAR, (UCHAR*) colInf[colNo].tableName, DB_MAX_TABLE_NAME_LEN+1, &cb); + GetData( 4, SQL_C_WXCHAR, (UCHAR*) colInf[colNo].colName, DB_MAX_COLUMN_NAME_LEN+1, &cb); + GetData( 5, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].sqlDataType, 0, &cb); + GetData( 6, SQL_C_WXCHAR, (UCHAR*) colInf[colNo].typeName, 128+1, &cb); + GetData( 7, SQL_C_SLONG, (UCHAR*) &colInf[colNo].columnLength, 0, &cb); + // BJO 991214 : SQL_C_SSHORT instead of SQL_C_SLONG, otherwise fails on Sparc (probably all 64 bit architectures) + GetData( 8, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].bufferSize, 0, &cb); + GetData( 9, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].decimalDigits,0, &cb); + GetData(10, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].numPrecRadix, 0, &cb); + GetData(11, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].nullable, 0, &cb); + GetData(12, SQL_C_WXCHAR, (UCHAR*) colInf[colNo].remarks, 254+1, &cb); + // Start Values for Primary/Foriegn Key (=No) + colInf[colNo].PkCol = 0; // Primary key column 0=No; 1= First Key, 2 = Second Key etc. + colInf[colNo].PkTableName[0] = 0; // Tablenames where Primary Key is used as a Foreign Key + colInf[colNo].FkCol = 0; // Foreign key column 0=No; 1= First Key, 2 = Second Key etc. + colInf[colNo].FkTableName[0] = 0; // Foreign key table name + + // BJO 20000428 : Virtuoso returns type names with upper cases! + if (Dbms() == dbmsVIRTUOSO) + { + wxString s = colInf[colNo].typeName; + s = s.MakeLower(); + wxStrcmp(colInf[colNo].typeName, s.c_str()); + } + + // Determine the wxDb data type that is used to represent the native data type of this data source + colInf[colNo].dbDataType = 0; + if (!wxStricmp(typeInfVarchar.TypeName, colInf[colNo].typeName)) + { +#ifdef _IODBC_ + // IODBC does not return a correct columnLength, so we set + // columnLength = bufferSize if no column length was returned + // IODBC returns the columnLength in bufferSize. (bug) + if (colInf[colNo].columnLength < 1) + { + colInf[colNo].columnLength = colInf[colNo].bufferSize; + } +#endif + + colInf[colNo].dbDataType = DB_DATA_TYPE_VARCHAR; + } + else if (!wxStricmp(typeInfInteger.TypeName, colInf[colNo].typeName)) + colInf[colNo].dbDataType = DB_DATA_TYPE_INTEGER; + else if (!wxStricmp(typeInfFloat.TypeName, colInf[colNo].typeName)) + colInf[colNo].dbDataType = DB_DATA_TYPE_FLOAT; + else if (!wxStricmp(typeInfDate.TypeName, colInf[colNo].typeName)) + colInf[colNo].dbDataType = DB_DATA_TYPE_DATE; + else if (!wxStricmp(typeInfBlob.TypeName, colInf[colNo].typeName)) + colInf[colNo].dbDataType = DB_DATA_TYPE_BLOB; + + colNo++; + } + } + } + if (retcode != SQL_NO_DATA_FOUND) + { // Error occurred, abort + DispAllErrors(henv, hdbc, hstmt); + if (colInf) + delete [] colInf; + SQLFreeStmt(hstmt, SQL_CLOSE); + if (numCols) + *numCols = 0; + return(0); + } + } + + SQLFreeStmt(hstmt, SQL_CLOSE); + + // Store Primary and Foriegn Keys + GetKeyFields(tableName,colInf,noCols); + + if (numCols) + *numCols = noCols; + return colInf; + +} // wxDb::GetColumns() + + +#else // New GetColumns + + +/* + BJO 20000503 + These are tentative new GetColumns members which should be more database + independent and which always returns the columns in the order they were + created. + + - The first one (wxDbColInf *wxDb::GetColumns(wxChar *tableName[], const + wxChar* userID)) calls the second implementation for each separate table + before merging the results. This makes the code easier to maintain as + only one member (the second) makes the real work + - wxDbColInf *wxDb::GetColumns(const wxString &tableName, int *numCols, const + wxChar *userID) is a little bit improved + - It doesn't anymore rely on the type-name to find out which database-type + each column has + - It ends by sorting the columns, so that they are returned in the same + order they were created +*/ + +typedef struct +{ + UWORD noCols; + wxDbColInf *colInf; +} _TableColumns; + + +wxDbColInf *wxDb::GetColumns(wxChar *tableName[], const wxChar *userID) +{ + int i, j; + // The last array element of the tableName[] argument must be zero (null). + // This is how the end of the array is detected. + + UWORD noCols = 0; + + // How many tables ? + int tbl; + for (tbl = 0 ; tableName[tbl]; tbl++); + + // Create a table to maintain the columns for each separate table + _TableColumns *TableColumns = new _TableColumns[tbl]; + + // Fill the table + for (i = 0 ; i < tbl ; i++) + + { + TableColumns[i].colInf = GetColumns(tableName[i], &TableColumns[i].noCols, userID); + if (TableColumns[i].colInf == NULL) + return NULL; + noCols += TableColumns[i].noCols; + } + + // Now merge all the separate table infos + wxDbColInf *colInf = new wxDbColInf[noCols+1]; + + // Mark the end of the array + wxStrcpy(colInf[noCols].tableName, wxEmptyString); + wxStrcpy(colInf[noCols].colName, wxEmptyString); + colInf[noCols].sqlDataType = 0; + + // Merge ... + int offset = 0; + + for (i = 0 ; i < tbl ; i++) + { + for (j = 0 ; j < TableColumns[i].noCols ; j++) + { + colInf[offset++] = TableColumns[i].colInf[j]; + } + } + + delete [] TableColumns; + + return colInf; +} // wxDb::GetColumns() -- NEW + + +wxDbColInf *wxDb::GetColumns(const wxString &tableName, int *numCols, const wxChar *userID) +// +// Same as the above GetColumns() function except this one gets columns +// only for a single table, and if 'numCols' is not NULL, the number of +// columns stored in the returned wxDbColInf is set in '*numCols' +// +// userID is evaluated in the following manner: +// userID == NULL ... UserID is ignored +// userID == "" ... UserID set equal to 'this->uid' +// userID != "" ... UserID set equal to 'userID' +// +// NOTE: ALL column bindings associated with this wxDb instance are unbound +// by this function. This function should use its own wxDb instance +// to avoid undesired unbinding of columns. +{ + UWORD noCols = 0; + UWORD colNo = 0; + wxDbColInf *colInf = 0; + + RETCODE retcode; + SDWORD cb; + + wxString TableName; + + wxString UserID; + convertUserID(userID,UserID); + + // Pass 1 - Determine how many columns there are. + // Pass 2 - Allocate the wxDbColInf array and fill in + // the array with the column information. + int pass; + for (pass = 1; pass <= 2; pass++) + { + if (pass == 2) + { + if (noCols == 0) // Probably a bogus table name(s) + break; + // Allocate n wxDbColInf objects to hold the column information + colInf = new wxDbColInf[noCols+1]; + if (!colInf) + break; + // Mark the end of the array + wxStrcpy(colInf[noCols].tableName, wxEmptyString); + wxStrcpy(colInf[noCols].colName, wxEmptyString); + colInf[noCols].sqlDataType = 0; + } + + TableName = tableName; + // Oracle and Interbase table names are uppercase only, so force + // the name to uppercase just in case programmer forgot to do this + if ((Dbms() == dbmsORACLE) || + (Dbms() == dbmsFIREBIRD) || + (Dbms() == dbmsINTERBASE)) + TableName = TableName.Upper(); + + SQLFreeStmt(hstmt, SQL_CLOSE); + + // MySQL, SQLServer, and Access cannot accept a user name when looking up column names, so we + // use the call below that leaves out the user name + if (!UserID.empty() && + Dbms() != dbmsMY_SQL && + Dbms() != dbmsACCESS && + Dbms() != dbmsMS_SQL_SERVER) + { + retcode = SQLColumns(hstmt, + NULL, 0, // All qualifiers + (UCHAR *) UserID.c_str(), SQL_NTS, // Owner + (UCHAR *) TableName.c_str(), SQL_NTS, + NULL, 0); // All columns + } + else + { + retcode = SQLColumns(hstmt, + NULL, 0, // All qualifiers + NULL, 0, // Owner + (UCHAR *) TableName.c_str(), SQL_NTS, + NULL, 0); // All columns + } + if (retcode != SQL_SUCCESS) + { // Error occurred, abort + DispAllErrors(henv, hdbc, hstmt); + if (colInf) + delete [] colInf; + SQLFreeStmt(hstmt, SQL_CLOSE); + if (numCols) + *numCols = 0; + return(0); + } + + while ((retcode = SQLFetch(hstmt)) == SQL_SUCCESS) + { + if (pass == 1) // First pass, just add up the number of columns + noCols++; + else // Pass 2; Fill in the array of structures + { + if (colNo < noCols) // Some extra error checking to prevent memory overwrites + { + // NOTE: Only the ODBC 1.x fields are retrieved + GetData( 1, SQL_C_WXCHAR, (UCHAR*) colInf[colNo].catalog, 128+1, &cb); + GetData( 2, SQL_C_WXCHAR, (UCHAR*) colInf[colNo].schema, 128+1, &cb); + GetData( 3, SQL_C_WXCHAR, (UCHAR*) colInf[colNo].tableName, DB_MAX_TABLE_NAME_LEN+1, &cb); + GetData( 4, SQL_C_WXCHAR, (UCHAR*) colInf[colNo].colName, DB_MAX_COLUMN_NAME_LEN+1, &cb); + GetData( 5, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].sqlDataType, 0, &cb); + GetData( 6, SQL_C_WXCHAR, (UCHAR*) colInf[colNo].typeName, 128+1, &cb); + GetData( 7, SQL_C_SLONG, (UCHAR*) &colInf[colNo].columnLength, 0, &cb); + GetData( 8, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].bufferSize, 0, &cb); + GetData( 9, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].decimalDigits,0, &cb); + GetData(10, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].numPrecRadix, 0, &cb); + GetData(11, SQL_C_SSHORT, (UCHAR*) &colInf[colNo].nullable, 0, &cb); + GetData(12, SQL_C_WXCHAR, (UCHAR*) colInf[colNo].remarks, 254+1, &cb); + // Start Values for Primary/Foriegn Key (=No) + colInf[colNo].PkCol = 0; // Primary key column 0=No; 1= First Key, 2 = Second Key etc. + colInf[colNo].PkTableName[0] = 0; // Tablenames where Primary Key is used as a Foreign Key + colInf[colNo].FkCol = 0; // Foreign key column 0=No; 1= First Key, 2 = Second Key etc. + colInf[colNo].FkTableName[0] = 0; // Foreign key table name + +#ifdef _IODBC_ + // IODBC does not return a correct columnLength, so we set + // columnLength = bufferSize if no column length was returned + // IODBC returns the columnLength in bufferSize. (bug) + if (colInf[colNo].columnLength < 1) + { + colInf[colNo].columnLength = colInf[colNo].bufferSize; + } +#endif + + // Determine the wxDb data type that is used to represent the native data type of this data source + colInf[colNo].dbDataType = 0; + // Get the intern datatype + switch (colInf[colNo].sqlDataType) + { +#if wxUSE_UNICODE + #if defined(SQL_WCHAR) + case SQL_WCHAR: + #endif + #if defined(SQL_WVARCHAR) + case SQL_WVARCHAR: + #endif +#endif + case SQL_VARCHAR: + case SQL_CHAR: + colInf[colNo].dbDataType = DB_DATA_TYPE_VARCHAR; + break; + case SQL_LONGVARCHAR: + colInf[colNo].dbDataType = DB_DATA_TYPE_MEMO; + break; + case SQL_TINYINT: + case SQL_SMALLINT: + case SQL_INTEGER: + case SQL_BIT: + colInf[colNo].dbDataType = DB_DATA_TYPE_INTEGER; + break; + case SQL_DOUBLE: + case SQL_DECIMAL: + case SQL_NUMERIC: + case SQL_FLOAT: + case SQL_REAL: + colInf[colNo].dbDataType = DB_DATA_TYPE_FLOAT; + break; + case SQL_DATE: + case SQL_TIMESTAMP: + colInf[colNo].dbDataType = DB_DATA_TYPE_DATE; + break; + case SQL_BINARY: + colInf[colNo].dbDataType = DB_DATA_TYPE_BLOB; + break; +#ifdef __WXDEBUG__ + default: + wxString errMsg; + errMsg.Printf(wxT("SQL Data type %d currently not supported by wxWidgets"), colInf[colNo].sqlDataType); + wxLogDebug(errMsg,wxT("ODBC DEBUG MESSAGE")); +#endif + } + colNo++; + } + } + } + if (retcode != SQL_NO_DATA_FOUND) + { // Error occurred, abort + DispAllErrors(henv, hdbc, hstmt); + if (colInf) + delete [] colInf; + SQLFreeStmt(hstmt, SQL_CLOSE); + if (numCols) + *numCols = 0; + return(0); + } + } + + SQLFreeStmt(hstmt, SQL_CLOSE); + + // Store Primary and Foreign Keys + GetKeyFields(tableName,colInf,noCols); + + /////////////////////////////////////////////////////////////////////////// + // Now sort the the columns in order to make them appear in the right order + /////////////////////////////////////////////////////////////////////////// + + // Build a generic SELECT statement which returns 0 rows + wxString Stmt; + + Stmt.Printf(wxT("select * from \"%s\" where 0=1"), tableName); + + // Execute query + if (SQLExecDirect(hstmt, (UCHAR FAR *) Stmt.c_str(), SQL_NTS) != SQL_SUCCESS) + { + DispAllErrors(henv, hdbc, hstmt); + return NULL; + } + + // Get the number of result columns + if (SQLNumResultCols (hstmt, &noCols) != SQL_SUCCESS) + { + DispAllErrors(henv, hdbc, hstmt); + return NULL; + } + + if (noCols == 0) // Probably a bogus table name + return NULL; + + // Get the name + int i; + short colNum; + UCHAR name[100]; + SWORD Sword; + SDWORD Sdword; + for (colNum = 0; colNum < noCols; colNum++) + { + if (SQLColAttributes(hstmt,colNum+1, SQL_COLUMN_NAME, + name, sizeof(name), + &Sword, &Sdword) != SQL_SUCCESS) + { + DispAllErrors(henv, hdbc, hstmt); + return NULL; + } + + wxString Name1 = name; + Name1 = Name1.Upper(); + + // Where is this name in the array ? + for (i = colNum ; i < noCols ; i++) + { + wxString Name2 = colInf[i].colName; + Name2 = Name2.Upper(); + if (Name2 == Name1) + { + if (colNum != i) // swap to sort + { + wxDbColInf tmpColInf = colInf[colNum]; + colInf[colNum] = colInf[i]; + colInf[i] = tmpColInf; + } + break; + } + } + } + SQLFreeStmt(hstmt, SQL_CLOSE); + + /////////////////////////////////////////////////////////////////////////// + // End sorting + /////////////////////////////////////////////////////////////////////////// + + if (numCols) + *numCols = noCols; + return colInf; + +} // wxDb::GetColumns() + + +#endif // #else OLD_GETCOLUMNS + + +/********** wxDb::GetColumnCount() **********/ +int wxDb::GetColumnCount(const wxString &tableName, const wxChar *userID) +/* + * Returns a count of how many columns are in a table. + * If an error occurs in computing the number of columns + * this function will return a -1 for the count + * + * userID is evaluated in the following manner: + * userID == NULL ... UserID is ignored + * userID == "" ... UserID set equal to 'this->uid' + * userID != "" ... UserID set equal to 'userID' + * + * NOTE: ALL column bindings associated with this wxDb instance are unbound + * by this function. This function should use its own wxDb instance + * to avoid undesired unbinding of columns. + */ +{ + UWORD noCols = 0; + + RETCODE retcode; + + wxString TableName; + + wxString UserID; + convertUserID(userID,UserID); + + TableName = tableName; + // Oracle and Interbase table names are uppercase only, so force + // the name to uppercase just in case programmer forgot to do this + if ((Dbms() == dbmsORACLE) || + (Dbms() == dbmsFIREBIRD) || + (Dbms() == dbmsINTERBASE)) + TableName = TableName.Upper(); + + SQLFreeStmt(hstmt, SQL_CLOSE); + + // MySQL, SQLServer, and Access cannot accept a user name when looking up column names, so we + // use the call below that leaves out the user name + if (!UserID.empty() && + Dbms() != dbmsMY_SQL && + Dbms() != dbmsACCESS && + Dbms() != dbmsMS_SQL_SERVER) + { + retcode = SQLColumns(hstmt, + NULL, 0, // All qualifiers + (SQLTCHAR *) UserID.c_str(), SQL_NTS, // Owner + (SQLTCHAR *) TableName.c_str(), SQL_NTS, + NULL, 0); // All columns + } + else + { + retcode = SQLColumns(hstmt, + NULL, 0, // All qualifiers + NULL, 0, // Owner + (SQLTCHAR *) TableName.c_str(), SQL_NTS, + NULL, 0); // All columns + } + if (retcode != SQL_SUCCESS) + { // Error occurred, abort + DispAllErrors(henv, hdbc, hstmt); + SQLFreeStmt(hstmt, SQL_CLOSE); + return(-1); + } + + // Count the columns + while ((retcode = SQLFetch(hstmt)) == SQL_SUCCESS) + noCols++; + + if (retcode != SQL_NO_DATA_FOUND) + { // Error occurred, abort + DispAllErrors(henv, hdbc, hstmt); + SQLFreeStmt(hstmt, SQL_CLOSE); + return(-1); + } + + SQLFreeStmt(hstmt, SQL_CLOSE); + return noCols; + +} // wxDb::GetColumnCount() + + +/********** wxDb::GetCatalog() *******/ +wxDbInf *wxDb::GetCatalog(const wxChar *userID) +/* + * --------------------------------------------------------------------- + * -- 19991203 : mj10777 : Create ------ + * -- : Creates a wxDbInf with Tables / Cols Array ------ + * -- : uses SQLTables and fills pTableInf; ------ + * -- : pColInf is set to NULL and numCols to 0; ------ + * -- : returns pDbInf (wxDbInf) ------ + * -- - if unsuccessful (pDbInf == NULL) ------ + * -- : pColInf can be filled with GetColumns(..); ------ + * -- : numCols can be filled with GetColumnCount(..); ------ + * --------------------------------------------------------------------- + * + * userID is evaluated in the following manner: + * userID == NULL ... UserID is ignored + * userID == "" ... UserID set equal to 'this->uid' + * userID != "" ... UserID set equal to 'userID' + * + * NOTE: ALL column bindings associated with this wxDb instance are unbound + * by this function. This function should use its own wxDb instance + * to avoid undesired unbinding of columns. + */ +{ + int noTab = 0; // Counter while filling table entries + int pass; + RETCODE retcode; + SQLLEN cb; + wxString tblNameSave; + + wxString UserID; + convertUserID(userID,UserID); + + //------------------------------------------------------------- + // Create the Database Array of catalog entries + + wxDbInf *pDbInf = new wxDbInf; + + //------------------------------------------------------------- + // Table Information + // Pass 1 - Determine how many Tables there are. + // Pass 2 - Create the Table array and fill it + // - Create the Cols array = NULL + //------------------------------------------------------------- + + for (pass = 1; pass <= 2; pass++) + { + SQLFreeStmt(hstmt, SQL_CLOSE); // Close if Open + tblNameSave.Empty(); + + if (!UserID.empty() && + Dbms() != dbmsMY_SQL && + Dbms() != dbmsACCESS && + Dbms() != dbmsMS_SQL_SERVER) + { + retcode = SQLTables(hstmt, + NULL, 0, // All qualifiers + (SQLTCHAR *) UserID.c_str(), SQL_NTS, // User specified + NULL, 0, // All tables + NULL, 0); // All columns + } + else + { + retcode = SQLTables(hstmt, + NULL, 0, // All qualifiers + NULL, 0, // User specified + NULL, 0, // All tables + NULL, 0); // All columns + } + + if (retcode != SQL_SUCCESS) + { + DispAllErrors(henv, hdbc, hstmt); + pDbInf = NULL; + SQLFreeStmt(hstmt, SQL_CLOSE); + return pDbInf; + } + + while ((retcode = SQLFetch(hstmt)) == SQL_SUCCESS) // Table Information + { + if (pass == 1) // First pass, just count the Tables + { + if (pDbInf->numTables == 0) + { + GetData( 1, SQL_C_WXCHAR, (UCHAR*) pDbInf->catalog, 128+1, &cb); + GetData( 2, SQL_C_WXCHAR, (UCHAR*) pDbInf->schema, 128+1, &cb); + } + pDbInf->numTables++; // Counter for Tables + } // if (pass == 1) + if (pass == 2) // Create and fill the Table entries + { + if (pDbInf->pTableInf == NULL) // Has the Table Array been created + { // no, then create the Array + pDbInf->pTableInf = new wxDbTableInf[pDbInf->numTables]; + noTab = 0; + } // if (pDbInf->pTableInf == NULL) // Has the Table Array been created + + GetData( 3, SQL_C_WXCHAR, (UCHAR*) (pDbInf->pTableInf+noTab)->tableName, DB_MAX_TABLE_NAME_LEN+1, &cb); + GetData( 4, SQL_C_WXCHAR, (UCHAR*) (pDbInf->pTableInf+noTab)->tableType, 30+1, &cb); + GetData( 5, SQL_C_WXCHAR, (UCHAR*) (pDbInf->pTableInf+noTab)->tableRemarks, 254+1, &cb); + + noTab++; + } // if + } // while + } // for + SQLFreeStmt(hstmt, SQL_CLOSE); + + // Query how many columns are in each table + for (noTab=0;noTabnumTables;noTab++) + { + (pDbInf->pTableInf+noTab)->numCols = (UWORD)GetColumnCount((pDbInf->pTableInf+noTab)->tableName,UserID); + } + + return pDbInf; + +} // wxDb::GetCatalog() + + +/********** wxDb::Catalog() **********/ +bool wxDb::Catalog(const wxChar *userID, const wxString &fileName) +/* + * Creates the text file specified in 'filename' which will contain + * a minimal data dictionary of all tables accessible by the user specified + * in 'userID' + * + * userID is evaluated in the following manner: + * userID == NULL ... UserID is ignored + * userID == "" ... UserID set equal to 'this->uid' + * userID != "" ... UserID set equal to 'userID' + * + * NOTE: ALL column bindings associated with this wxDb instance are unbound + * by this function. This function should use its own wxDb instance + * to avoid undesired unbinding of columns. + */ +{ + wxASSERT(fileName.length()); + + RETCODE retcode; + SQLLEN cb; + wxChar tblName[DB_MAX_TABLE_NAME_LEN+1]; + wxString tblNameSave; + wxChar colName[DB_MAX_COLUMN_NAME_LEN+1]; + SWORD sqlDataType; + wxChar typeName[30+1]; + SDWORD precision, length; + + FILE *fp = wxFopen(fileName.c_str(),wxT("wt")); + if (fp == NULL) + return false; + + SQLFreeStmt(hstmt, SQL_CLOSE); + + wxString UserID; + convertUserID(userID,UserID); + + if (!UserID.empty() && + Dbms() != dbmsMY_SQL && + Dbms() != dbmsACCESS && + Dbms() != dbmsFIREBIRD && + Dbms() != dbmsINTERBASE && + Dbms() != dbmsMS_SQL_SERVER) + { + retcode = SQLColumns(hstmt, + NULL, 0, // All qualifiers + (SQLTCHAR *) UserID.c_str(), SQL_NTS, // User specified + NULL, 0, // All tables + NULL, 0); // All columns + } + else + { + retcode = SQLColumns(hstmt, + NULL, 0, // All qualifiers + NULL, 0, // User specified + NULL, 0, // All tables + NULL, 0); // All columns + } + if (retcode != SQL_SUCCESS) + { + DispAllErrors(henv, hdbc, hstmt); + fclose(fp); + return false; + } + + wxString outStr; + tblNameSave.Empty(); + int cnt = 0; + + while (true) + { + retcode = SQLFetch(hstmt); + if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO) + break; + + GetData(3,SQL_C_WXCHAR, (UCHAR *) tblName, DB_MAX_TABLE_NAME_LEN+1, &cb); + GetData(4,SQL_C_WXCHAR, (UCHAR *) colName, DB_MAX_COLUMN_NAME_LEN+1,&cb); + GetData(5,SQL_C_SSHORT, (UCHAR *)&sqlDataType, 0, &cb); + GetData(6,SQL_C_WXCHAR, (UCHAR *) typeName, sizeof(typeName), &cb); + GetData(7,SQL_C_SLONG, (UCHAR *)&precision, 0, &cb); + GetData(8,SQL_C_SLONG, (UCHAR *)&length, 0, &cb); + + if (wxStrcmp(tblName, tblNameSave.c_str())) + { + if (cnt) + wxFputs(wxT("\n"), fp); + wxFputs(wxT("================================ "), fp); + wxFputs(wxT("================================ "), fp); + wxFputs(wxT("===================== "), fp); + wxFputs(wxT("========= "), fp); + wxFputs(wxT("=========\n"), fp); + outStr.Printf(wxT("%-32s %-32s %-21s %9s %9s\n"), + wxT("TABLE NAME"), wxT("COLUMN NAME"), wxT("DATA TYPE"), wxT("PRECISION"), wxT("LENGTH")); + wxFputs(outStr.c_str(), fp); + wxFputs(wxT("================================ "), fp); + wxFputs(wxT("================================ "), fp); + wxFputs(wxT("===================== "), fp); + wxFputs(wxT("========= "), fp); + wxFputs(wxT("=========\n"), fp); + tblNameSave = tblName; + } + + outStr.Printf(wxT("%-32s %-32s (%04d)%-15s %9ld %9ld\n"), + tblName, colName, sqlDataType, typeName, precision, length); + if (wxFputs(outStr.c_str(), fp) == EOF) + { + SQLFreeStmt(hstmt, SQL_CLOSE); + fclose(fp); + return false; + } + cnt++; + } + + if (retcode != SQL_NO_DATA_FOUND) + DispAllErrors(henv, hdbc, hstmt); + + SQLFreeStmt(hstmt, SQL_CLOSE); + + fclose(fp); + return(retcode == SQL_NO_DATA_FOUND); + +} // wxDb::Catalog() + + +bool wxDb::TableExists(const wxString &tableName, const wxChar *userID, const wxString &tablePath) +/* + * Table name can refer to a table, view, alias or synonym. Returns true + * if the object exists in the database. This function does not indicate + * whether or not the user has privleges to query or perform other functions + * on the table. + * + * userID is evaluated in the following manner: + * userID == NULL ... UserID is ignored + * userID == "" ... UserID set equal to 'this->uid' + * userID != "" ... UserID set equal to 'userID' + */ +{ + wxASSERT(tableName.length()); + + wxString TableName; + + if (Dbms() == dbmsDBASE) + { + wxString dbName; + if (tablePath.length()) + dbName.Printf(wxT("%s/%s.dbf"), tablePath.c_str(), tableName.c_str()); + else + dbName.Printf(wxT("%s.dbf"), tableName.c_str()); + + bool exists; + exists = wxFileExists(dbName); + return exists; + } + + wxString UserID; + convertUserID(userID,UserID); + + TableName = tableName; + // Oracle and Interbase table names are uppercase only, so force + // the name to uppercase just in case programmer forgot to do this + if ((Dbms() == dbmsORACLE) || + (Dbms() == dbmsFIREBIRD) || + (Dbms() == dbmsINTERBASE)) + TableName = TableName.Upper(); + + SQLFreeStmt(hstmt, SQL_CLOSE); + RETCODE retcode; + + // Some databases cannot accept a user name when looking up table names, + // so we use the call below that leaves out the user name + if (!UserID.empty() && + Dbms() != dbmsMY_SQL && + Dbms() != dbmsACCESS && + Dbms() != dbmsMS_SQL_SERVER && + Dbms() != dbmsDB2 && + Dbms() != dbmsFIREBIRD && + Dbms() != dbmsINTERBASE && + Dbms() != dbmsPERVASIVE_SQL) + { + retcode = SQLTables(hstmt, + NULL, 0, // All qualifiers + (SQLTCHAR *) UserID.c_str(), SQL_NTS, // Only tables owned by this user + (SQLTCHAR FAR *)TableName.c_str(), SQL_NTS, + NULL, 0); // All table types + } + else + { + retcode = SQLTables(hstmt, + NULL, 0, // All qualifiers + NULL, 0, // All owners + (SQLTCHAR FAR *)TableName.c_str(), SQL_NTS, + NULL, 0); // All table types + } + if (retcode != SQL_SUCCESS) + return(DispAllErrors(henv, hdbc, hstmt)); + + retcode = SQLFetch(hstmt); + if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO) + { + SQLFreeStmt(hstmt, SQL_CLOSE); + return(DispAllErrors(henv, hdbc, hstmt)); + } + + SQLFreeStmt(hstmt, SQL_CLOSE); + + return true; + +} // wxDb::TableExists() + + +/********** wxDb::TablePrivileges() **********/ +bool wxDb::TablePrivileges(const wxString &tableName, const wxString &priv, const wxChar *userID, + const wxChar *schema, const wxString &WXUNUSED(tablePath)) +{ + wxASSERT(tableName.length()); + + wxDbTablePrivilegeInfo result; + SQLLEN cbRetVal; + RETCODE retcode; + + // We probably need to be able to dynamically set this based on + // the driver type, and state. + wxChar curRole[]=wxT("public"); + + wxString TableName; + + wxString UserID,Schema; + convertUserID(userID,UserID); + convertUserID(schema,Schema); + + TableName = tableName; + // Oracle and Interbase table names are uppercase only, so force + // the name to uppercase just in case programmer forgot to do this + if ((Dbms() == dbmsORACLE) || + (Dbms() == dbmsFIREBIRD) || + (Dbms() == dbmsINTERBASE)) + TableName = TableName.Upper(); + + SQLFreeStmt(hstmt, SQL_CLOSE); + + // Some databases cannot accept a user name when looking up table names, + // so we use the call below that leaves out the user name + if (!Schema.empty() && + Dbms() != dbmsMY_SQL && + Dbms() != dbmsACCESS && + Dbms() != dbmsMS_SQL_SERVER) + { + retcode = SQLTablePrivileges(hstmt, + NULL, 0, // Catalog + (SQLTCHAR FAR *)Schema.c_str(), SQL_NTS, // Schema + (SQLTCHAR FAR *)TableName.c_str(), SQL_NTS); + } + else + { + retcode = SQLTablePrivileges(hstmt, + NULL, 0, // Catalog + NULL, 0, // Schema + (SQLTCHAR FAR *)TableName.c_str(), SQL_NTS); + } + +#ifdef DBDEBUG_CONSOLE + wxFprintf(stderr ,wxT("SQLTablePrivileges() returned %i \n"),retcode); +#endif + + if ((retcode != SQL_SUCCESS) && (retcode != SQL_SUCCESS_WITH_INFO)) + return (DispAllErrors(henv, hdbc, hstmt)); + + bool failed = false; + retcode = SQLFetch(hstmt); + while (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) + { + if (SQLGetData(hstmt, 1, SQL_C_WXCHAR, (UCHAR*) result.tableQual, sizeof(result.tableQual), &cbRetVal) != SQL_SUCCESS) + failed = true; + + if (!failed && SQLGetData(hstmt, 2, SQL_C_WXCHAR, (UCHAR*) result.tableOwner, sizeof(result.tableOwner), &cbRetVal) != SQL_SUCCESS) + failed = true; + + if (!failed && SQLGetData(hstmt, 3, SQL_C_WXCHAR, (UCHAR*) result.tableName, sizeof(result.tableName), &cbRetVal) != SQL_SUCCESS) + failed = true; + + if (!failed && SQLGetData(hstmt, 4, SQL_C_WXCHAR, (UCHAR*) result.grantor, sizeof(result.grantor), &cbRetVal) != SQL_SUCCESS) + failed = true; + + if (!failed && SQLGetData(hstmt, 5, SQL_C_WXCHAR, (UCHAR*) result.grantee, sizeof(result.grantee), &cbRetVal) != SQL_SUCCESS) + failed = true; + + if (!failed && SQLGetData(hstmt, 6, SQL_C_WXCHAR, (UCHAR*) result.privilege, sizeof(result.privilege), &cbRetVal) != SQL_SUCCESS) + failed = true; + + if (!failed && SQLGetData(hstmt, 7, SQL_C_WXCHAR, (UCHAR*) result.grantable, sizeof(result.grantable), &cbRetVal) != SQL_SUCCESS) + failed = true; + + if (failed) + { + return(DispAllErrors(henv, hdbc, hstmt)); + } +#ifdef DBDEBUG_CONSOLE + wxFprintf(stderr,wxT("Scanning %s privilege on table %s.%s granted by %s to %s\n"), + result.privilege,result.tableOwner,result.tableName, + result.grantor, result.grantee); +#endif + + if (UserID.IsSameAs(result.tableOwner,false)) + { + SQLFreeStmt(hstmt, SQL_CLOSE); + return true; + } + + if (UserID.IsSameAs(result.grantee,false) && + !wxStrcmp(result.privilege,priv)) + { + SQLFreeStmt(hstmt, SQL_CLOSE); + return true; + } + + if (!wxStrcmp(result.grantee,curRole) && + !wxStrcmp(result.privilege,priv)) + { + SQLFreeStmt(hstmt, SQL_CLOSE); + return true; + } + + retcode = SQLFetch(hstmt); + } + + SQLFreeStmt(hstmt, SQL_CLOSE); + return false; + +} // wxDb::TablePrivileges + + +const wxString wxDb::SQLTableName(const wxChar *tableName) +{ + wxString TableName; + + if (Dbms() == dbmsACCESS) + TableName = _T("\""); + TableName += tableName; + if (Dbms() == dbmsACCESS) + TableName += _T("\""); + + return TableName; +} // wxDb::SQLTableName() + + +const wxString wxDb::SQLColumnName(const wxChar *colName) +{ + wxString ColName; + + if (Dbms() == dbmsACCESS) + ColName = _T("\""); + ColName += colName; + if (Dbms() == dbmsACCESS) + ColName += _T("\""); + + return ColName; +} // wxDb::SQLColumnName() + + +/********** wxDb::SetSqlLogging() **********/ +bool wxDb::SetSqlLogging(wxDbSqlLogState state, const wxString &filename, bool append) +{ + wxASSERT(state == sqlLogON || state == sqlLogOFF); + wxASSERT(state == sqlLogOFF || filename.length()); + + if (state == sqlLogON) + { + if (fpSqlLog == 0) + { + fpSqlLog = wxFopen(filename.c_str(), (append ? wxT("at") : wxT("wt"))); + if (fpSqlLog == NULL) + return false; + } + } + else // sqlLogOFF + { + if (fpSqlLog) + { + if (fclose(fpSqlLog)) + return false; + fpSqlLog = 0; + } + } + + sqlLogState = state; + return true; + +} // wxDb::SetSqlLogging() + + +/********** wxDb::WriteSqlLog() **********/ +bool wxDb::WriteSqlLog(const wxString &logMsg) +{ + wxASSERT(logMsg.length()); + + if (fpSqlLog == 0 || sqlLogState == sqlLogOFF) + return false; + + if (wxFputs(wxT("\n"), fpSqlLog) == EOF) + return false; + if (wxFputs(logMsg, fpSqlLog) == EOF) + return false; + if (wxFputs(wxT("\n"), fpSqlLog) == EOF) + return false; + + return true; + +} // wxDb::WriteSqlLog() + + +/********** wxDb::Dbms() **********/ +wxDBMS wxDb::Dbms(void) +/* + * Be aware that not all database engines use the exact same syntax, and not + * every ODBC compliant database is compliant to the same level of compliancy. + * Some manufacturers support the minimum Level 1 compliancy, and others up + * through Level 3. Others support subsets of features for levels above 1. + * + * If you find an inconsistency between the wxDb class and a specific database + * engine, and an identifier to this section, and special handle the database in + * the area where behavior is non-conforming with the other databases. + * + * + * NOTES ABOUT ISSUES SPECIFIC TO EACH DATABASE ENGINE + * --------------------------------------------------- + * + * ORACLE + * - Currently the only database supported by the class to support VIEWS + * + * DBASE + * - Does not support the SQL_TIMESTAMP structure + * - Supports only one cursor and one connect (apparently? with Microsoft driver only?) + * - Does not automatically create the primary index if the 'keyField' param of SetColDef + * is true. The user must create ALL indexes from their program. + * - Table names can only be 8 characters long + * - Column names can only be 10 characters long + * + * SYBASE (all) + * - To lock a record during QUERY functions, the reserved word 'HOLDLOCK' must be added + * after every table name involved in the query/join if that tables matching record(s) + * are to be locked + * - Ignores the keywords 'FOR UPDATE'. Use the HOLDLOCK functionality described above + * + * SYBASE (Enterprise) + * - If a column is part of the Primary Key, the column cannot be NULL + * - Maximum row size is somewhere in the neighborhood of 1920 bytes + * + * MY_SQL + * - If a column is part of the Primary Key, the column cannot be NULL + * - Cannot support selecting for update [::CanSelectForUpdate()]. Always returns FALSE + * - Columns that are part of primary or secondary keys must be defined as being NOT NULL + * when they are created. Some code is added in ::CreateIndex to try to adjust the + * column definition if it is not defined correctly, but it is experimental + * - Does not support sub-queries in SQL statements + * + * POSTGRES + * - Does not support the keywords 'ASC' or 'DESC' as of release v6.5.0 + * - Does not support sub-queries in SQL statements + * + * DB2 + * - Primary keys must be declared as NOT NULL + * - Table and index names must not be longer than 13 characters in length (technically + * table names can be up to 18 characters, but the primary index is created using the + * base table name plus "_PIDX", so the limit if the table has a primary index is 13. + * + * PERVASIVE SQL + * + * INTERBASE + * - Columns that are part of primary keys must be defined as being NOT NULL + * when they are created. Some code is added in ::CreateIndex to try to adjust the + * column definition if it is not defined correctly, but it is experimental + */ +{ + // Should only need to do this once for each new database connection + // so return the value we already determined it to be to save time + // and lots of string comparisons + if (dbmsType != dbmsUNIDENTIFIED) + return(dbmsType); + +#ifdef DBDEBUG_CONSOLE + // When run in console mode, use standard out to display errors. + cout << "Database connecting to: " << dbInf.dbmsName << endl; +#endif // DBDEBUG_CONSOLE + + wxLogDebug(wxT("Database connecting to: ")); + wxLogDebug(dbInf.dbmsName); + + wxChar baseName[25+1]; + wxStrncpy(baseName, dbInf.dbmsName, 25); + baseName[25] = 0; + + // RGG 20001025 : add support for Interbase + // GT : Integrated to base classes on 20001121 + if (!wxStricmp(dbInf.dbmsName,wxT("Interbase"))) + return((wxDBMS)(dbmsType = dbmsINTERBASE)); + + // BJO 20000428 : add support for Virtuoso + if (!wxStricmp(dbInf.dbmsName,wxT("OpenLink Virtuoso VDBMS"))) + return((wxDBMS)(dbmsType = dbmsVIRTUOSO)); + + if (!wxStricmp(dbInf.dbmsName,wxT("Adaptive Server Anywhere"))) + return((wxDBMS)(dbmsType = dbmsSYBASE_ASA)); + + // BJO 20000427 : The "SQL Server" string is also returned by SQLServer when + // connected through an OpenLink driver. + // Is it also returned by Sybase Adapatitve server? + // OpenLink driver name is OLOD3032.DLL for msw and oplodbc.so for unix + if (!wxStricmp(dbInf.dbmsName,wxT("SQL Server"))) + { + if (!wxStrncmp(dbInf.driverName, wxT("oplodbc"), 7) || + !wxStrncmp(dbInf.driverName, wxT("OLOD"), 4)) + return ((wxDBMS)(dbmsMS_SQL_SERVER)); + else + return ((wxDBMS)(dbmsType = dbmsSYBASE_ASE)); + } + + if (!wxStricmp(dbInf.dbmsName,wxT("Microsoft SQL Server"))) + return((wxDBMS)(dbmsType = dbmsMS_SQL_SERVER)); + + baseName[10] = 0; + if (!wxStricmp(baseName,wxT("PostgreSQL"))) // v6.5.0 + return((wxDBMS)(dbmsType = dbmsPOSTGRES)); + + baseName[9] = 0; + if (!wxStricmp(baseName,wxT("Pervasive"))) + return((wxDBMS)(dbmsType = dbmsPERVASIVE_SQL)); + + baseName[8] = 0; + if (!wxStricmp(baseName,wxT("Informix"))) + return((wxDBMS)(dbmsType = dbmsINFORMIX)); + + if (!wxStricmp(baseName,wxT("Firebird"))) + return((wxDBMS)(dbmsType = dbmsFIREBIRD)); + + baseName[6] = 0; + if (!wxStricmp(baseName,wxT("Oracle"))) + return((wxDBMS)(dbmsType = dbmsORACLE)); + if (!wxStricmp(baseName,wxT("ACCESS"))) + return((wxDBMS)(dbmsType = dbmsACCESS)); + if (!wxStricmp(baseName,wxT("Sybase"))) + return((wxDBMS)(dbmsType = dbmsSYBASE_ASE)); + + baseName[5] = 0; + if (!wxStricmp(baseName,wxT("DBASE"))) + return((wxDBMS)(dbmsType = dbmsDBASE)); + if (!wxStricmp(baseName,wxT("xBase"))) + return((wxDBMS)(dbmsType = dbmsXBASE_SEQUITER)); + if (!wxStricmp(baseName,wxT("MySQL"))) + return((wxDBMS)(dbmsType = dbmsMY_SQL)); + if (!wxStricmp(baseName,wxT("MaxDB"))) + return((wxDBMS)(dbmsType = dbmsMAXDB)); + + baseName[3] = 0; + if (!wxStricmp(baseName,wxT("DB2"))) + return((wxDBMS)(dbmsType = dbmsDB2)); + + return((wxDBMS)(dbmsType = dbmsUNIDENTIFIED)); + +} // wxDb::Dbms() + + +bool wxDb::ModifyColumn(const wxString &tableName, const wxString &columnName, + int dataType, ULONG columnLength, + const wxString &optionalParam) +{ + wxASSERT(tableName.length()); + wxASSERT(columnName.length()); + wxASSERT((dataType == DB_DATA_TYPE_VARCHAR && columnLength > 0) || + dataType != DB_DATA_TYPE_VARCHAR); + + // Must specify a columnLength if modifying a VARCHAR type column + if (dataType == DB_DATA_TYPE_VARCHAR && !columnLength) + return false; + + wxString dataTypeName; + wxString sqlStmt; + wxString alterSlashModify; + + switch(dataType) + { + case DB_DATA_TYPE_VARCHAR : + dataTypeName = typeInfVarchar.TypeName; + break; + case DB_DATA_TYPE_INTEGER : + dataTypeName = typeInfInteger.TypeName; + break; + case DB_DATA_TYPE_FLOAT : + dataTypeName = typeInfFloat.TypeName; + break; + case DB_DATA_TYPE_DATE : + dataTypeName = typeInfDate.TypeName; + break; + case DB_DATA_TYPE_BLOB : + dataTypeName = typeInfBlob.TypeName; + break; + default: + return false; + } + + // Set the modify or alter syntax depending on the type of database connected to + switch (Dbms()) + { + case dbmsORACLE : + alterSlashModify = _T("MODIFY"); + break; + case dbmsMS_SQL_SERVER : + alterSlashModify = _T("ALTER COLUMN"); + break; + case dbmsUNIDENTIFIED : + return false; + case dbmsSYBASE_ASA : + case dbmsSYBASE_ASE : + case dbmsMY_SQL : + case dbmsPOSTGRES : + case dbmsACCESS : + case dbmsDBASE : + case dbmsXBASE_SEQUITER : + default : + alterSlashModify = _T("MODIFY"); + break; + } + + // create the SQL statement + if ( Dbms() == dbmsMY_SQL ) + { + sqlStmt.Printf(wxT("ALTER TABLE %s %s %s %s"), tableName.c_str(), alterSlashModify.c_str(), + columnName.c_str(), dataTypeName.c_str()); + } + else + { + sqlStmt.Printf(wxT("ALTER TABLE \"%s\" \"%s\" \"%s\" %s"), tableName.c_str(), alterSlashModify.c_str(), + columnName.c_str(), dataTypeName.c_str()); + } + + // For varchars only, append the size of the column + if (dataType == DB_DATA_TYPE_VARCHAR && + (Dbms() != dbmsMY_SQL || dataTypeName != _T("text"))) + { + wxString s; + s.Printf(wxT("(%lu)"), columnLength); + sqlStmt += s; + } + + // for passing things like "NOT NULL" + if (optionalParam.length()) + { + sqlStmt += wxT(" "); + sqlStmt += optionalParam; + } + + return ExecSql(sqlStmt); + +} // wxDb::ModifyColumn() + +/********** wxDb::EscapeSqlChars() **********/ +wxString wxDb::EscapeSqlChars(const wxString& valueOrig) +{ + wxString value(valueOrig); + switch (Dbms()) + { + case dbmsACCESS: + // Access doesn't seem to care about backslashes, so only escape single quotes. + value.Replace(wxT("'"), wxT("''")); + break; + + default: + // All the others are supposed to be the same for now, add special + // handling for them if necessary + value.Replace(wxT("\\"), wxT("\\\\")); + value.Replace(wxT("'"), wxT("\\'")); + break; + } + + return value; +} // wxDb::EscapeSqlChars() + + +/********** wxDbGetConnection() **********/ +wxDb WXDLLIMPEXP_ODBC *wxDbGetConnection(wxDbConnectInf *pDbConfig, bool FwdOnlyCursors) +{ + wxDbList *pList; + + // Used to keep a pointer to a DB connection that matches the requested + // DSN and FwdOnlyCursors settings, even if it is not FREE, so that the + // data types can be copied from it (using the wxDb::Open(wxDb *) function) + // rather than having to re-query the datasource to get all the values + // using the wxDb::Open(Dsn,Uid,AuthStr) function + wxDb *matchingDbConnection = NULL; + + // Scan the linked list searching for an available database connection + // that's already been opened but is currently not in use. + for (pList = PtrBegDbList; pList; pList = pList->PtrNext) + { + // The database connection must be for the same datasource + // name and must currently not be in use. + if (pList->Free && + (pList->PtrDb->FwdOnlyCursors() == FwdOnlyCursors)) + { + if (pDbConfig->UseConnectionStr()) + { + if (pList->PtrDb->OpenedWithConnectionString() && + (!wxStrcmp(pDbConfig->GetConnectionStr(), pList->ConnectionStr))) + { + // Found a free connection + pList->Free = false; + return(pList->PtrDb); + } + } + else + { + if (!pList->PtrDb->OpenedWithConnectionString() && + (!wxStrcmp(pDbConfig->GetDsn(), pList->Dsn))) + { + // Found a free connection + pList->Free = false; + return(pList->PtrDb); + } + } + } + + if (pDbConfig->UseConnectionStr()) + { + if (!wxStrcmp(pDbConfig->GetConnectionStr(), pList->ConnectionStr)) + matchingDbConnection = pList->PtrDb; + } + else + { + if (!wxStrcmp(pDbConfig->GetDsn(), pList->Dsn) && + !wxStrcmp(pDbConfig->GetUserID(), pList->Uid) && + !wxStrcmp(pDbConfig->GetPassword(), pList->AuthStr)) + matchingDbConnection = pList->PtrDb; + } + } + + // No available connections. A new connection must be made and + // appended to the end of the linked list. + if (PtrBegDbList) + { + // Find the end of the list + for (pList = PtrBegDbList; pList->PtrNext; pList = pList->PtrNext); + // Append a new list item + pList->PtrNext = new wxDbList; + pList->PtrNext->PtrPrev = pList; + pList = pList->PtrNext; + } + else // Empty list + { + // Create the first node on the list + pList = PtrBegDbList = new wxDbList; + pList->PtrPrev = 0; + } + + // Initialize new node in the linked list + pList->PtrNext = 0; + pList->Free = false; + pList->Dsn = pDbConfig->GetDsn(); + pList->Uid = pDbConfig->GetUserID(); + pList->AuthStr = pDbConfig->GetPassword(); + pList->ConnectionStr = pDbConfig->GetConnectionStr(); + + pList->PtrDb = new wxDb(pDbConfig->GetHenv(), FwdOnlyCursors); + + bool opened; + + if (!matchingDbConnection) + { + if (pDbConfig->UseConnectionStr()) + { + opened = pList->PtrDb->Open(pDbConfig->GetConnectionStr()); + } + else + { + opened = pList->PtrDb->Open(pDbConfig->GetDsn(), pDbConfig->GetUserID(), pDbConfig->GetPassword()); + } + } + else + opened = pList->PtrDb->Open(matchingDbConnection); + + // Connect to the datasource + if (opened) + { + pList->PtrDb->setCached(true); // Prevent a user from deleting a cached connection + pList->PtrDb->SetSqlLogging(SQLLOGstate, SQLLOGfn, true); + return(pList->PtrDb); + } + else // Unable to connect, destroy list item + { + if (pList->PtrPrev) + pList->PtrPrev->PtrNext = 0; + else + PtrBegDbList = 0; // Empty list again + + pList->PtrDb->CommitTrans(); // Commit any open transactions on wxDb object + pList->PtrDb->Close(); // Close the wxDb object + delete pList->PtrDb; // Deletes the wxDb object + delete pList; // Deletes the linked list object + return(0); + } + +} // wxDbGetConnection() + + +/********** wxDbFreeConnection() **********/ +bool WXDLLIMPEXP_ODBC wxDbFreeConnection(wxDb *pDb) +{ + wxDbList *pList; + + // Scan the linked list searching for the database connection + for (pList = PtrBegDbList; pList; pList = pList->PtrNext) + { + if (pList->PtrDb == pDb) // Found it, now free it!!! + return (pList->Free = true); + } + + // Never found the database object, return failure + return false; + +} // wxDbFreeConnection() + + +/********** wxDbCloseConnections() **********/ +void WXDLLIMPEXP_ODBC wxDbCloseConnections(void) +{ + wxDbList *pList, *pNext; + + // Traverse the linked list closing database connections and freeing memory as I go. + for (pList = PtrBegDbList; pList; pList = pNext) + { + pNext = pList->PtrNext; // Save the pointer to next + pList->PtrDb->CommitTrans(); // Commit any open transactions on wxDb object + pList->PtrDb->Close(); // Close the wxDb object + pList->PtrDb->setCached(false); // Allows deletion of the wxDb instance + delete pList->PtrDb; // Deletes the wxDb object + delete pList; // Deletes the linked list object + } + + // Mark the list as empty + PtrBegDbList = 0; + +} // wxDbCloseConnections() + + +/********** wxDbConnectionsInUse() **********/ +int WXDLLIMPEXP_ODBC wxDbConnectionsInUse(void) +{ + wxDbList *pList; + int cnt = 0; + + // Scan the linked list counting db connections that are currently in use + for (pList = PtrBegDbList; pList; pList = pList->PtrNext) + { + if (pList->Free == false) + cnt++; + } + + return(cnt); + +} // wxDbConnectionsInUse() + + + +/********** wxDbLogExtendedErrorMsg() **********/ +// DEBUG ONLY function +const wxChar WXDLLIMPEXP_ODBC *wxDbLogExtendedErrorMsg(const wxChar *userText, + wxDb *pDb, + const wxChar *ErrFile, + int ErrLine) +{ + static wxString msg; + msg = userText; + + wxString tStr; + + if (ErrFile || ErrLine) + { + msg += wxT("File: "); + msg += ErrFile; + msg += wxT(" Line: "); + tStr.Printf(wxT("%d"),ErrLine); + msg += tStr.c_str(); + msg += wxT("\n"); + } + + msg.Append (wxT("\nODBC errors:\n")); + msg += wxT("\n"); + + // Display errors for this connection + int i; + for (i = 0; i < DB_MAX_ERROR_HISTORY; i++) + { + if (pDb->errorList[i]) + { + msg.Append(pDb->errorList[i]); + if (wxStrcmp(pDb->errorList[i], wxEmptyString) != 0) + msg.Append(wxT("\n")); + // Clear the errmsg buffer so the next error will not + // end up showing the previous error that have occurred + wxStrcpy(pDb->errorList[i], wxEmptyString); + } + } + msg += wxT("\n"); + + wxLogDebug(msg.c_str()); + + return msg.c_str(); +} // wxDbLogExtendedErrorMsg() + + +/********** wxDbSqlLog() **********/ +bool wxDbSqlLog(wxDbSqlLogState state, const wxChar *filename) +{ + bool append = false; + wxDbList *pList; + + for (pList = PtrBegDbList; pList; pList = pList->PtrNext) + { + if (!pList->PtrDb->SetSqlLogging(state,filename,append)) + return false; + append = true; + } + + SQLLOGstate = state; + SQLLOGfn = filename; + + return true; + +} // wxDbSqlLog() + + +#if 0 +/********** wxDbCreateDataSource() **********/ +int wxDbCreateDataSource(const wxString &driverName, const wxString &dsn, const wxString &description, + bool sysDSN, const wxString &defDir, wxWindow *parent) +/* + * !!!! ONLY FUNCTIONAL UNDER MSW with VC6 !!!! + * Very rudimentary creation of an ODBC data source. + * + * ODBC driver must be ODBC 3.0 compliant to use this function + */ +{ + int result = FALSE; + +//!!!! ONLY FUNCTIONAL UNDER MSW with VC6 !!!! +#ifdef __VISUALC__ + int dsnLocation; + wxString setupStr; + + if (sysDSN) + dsnLocation = ODBC_ADD_SYS_DSN; + else + dsnLocation = ODBC_ADD_DSN; + + // NOTE: The decimal 2 is an invalid character in all keyword pairs + // so that is why I used it, as wxString does not deal well with + // embedded nulls in strings + setupStr.Printf(wxT("DSN=%s%cDescription=%s%cDefaultDir=%s%c"),dsn,2,description,2,defDir,2); + + // Replace the separator from above with the '\0' separator needed + // by the SQLConfigDataSource() function + int k; + do + { + k = setupStr.Find((wxChar)2,true); + if (k != wxNOT_FOUND) + setupStr[(UINT)k] = wxT('\0'); + } + while (k != wxNOT_FOUND); + + result = SQLConfigDataSource((HWND)parent->GetHWND(), dsnLocation, + driverName, setupStr.c_str()); + + if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) + { + // check for errors caused by ConfigDSN based functions + DWORD retcode = 0; + WORD cb; + wxChar errMsg[SQL_MAX_MESSAGE_LENGTH]; + errMsg[0] = wxT('\0'); + + // This function is only supported in ODBC drivers v3.0 compliant and above + SQLInstallerError(1,&retcode,errMsg,SQL_MAX_MESSAGE_LENGTH-1,&cb); + if (retcode) + { +#ifdef DBDEBUG_CONSOLE + // When run in console mode, use standard out to display errors. + cout << errMsg << endl; + cout << wxT("Press any key to continue...") << endl; + getchar(); +#endif // DBDEBUG_CONSOLE + +#ifdef __WXDEBUG__ + wxLogDebug(errMsg,wxT("ODBC DEBUG MESSAGE")); +#endif // __WXDEBUG__ + } + } + else + result = TRUE; +#else + // Using iODBC/unixODBC or some other compiler which does not support the APIs + // necessary to use this function, so this function is not supported +#ifdef __WXDEBUG__ + wxLogDebug(wxT("wxDbCreateDataSource() not available except under VC++/MSW"),wxT("ODBC DEBUG MESSAGE")); +#endif + result = FALSE; +#endif // __VISUALC__ + + return result; + +} // wxDbCreateDataSource() +#endif + + +/********** wxDbGetDataSource() **********/ +bool wxDbGetDataSource(HENV henv, wxChar *Dsn, SWORD DsnMaxLength, wxChar *DsDesc, + SWORD DsDescMaxLength, UWORD direction) +/* + * Dsn and DsDesc will contain the data source name and data source + * description upon return + */ +{ + SWORD cb1,cb2; + SWORD lengthDsn = (SWORD)(DsnMaxLength*sizeof(wxChar)); + SWORD lengthDsDesc = (SWORD)(DsDescMaxLength*sizeof(wxChar)); + + if (SQLDataSources(henv, direction, (SQLTCHAR FAR *) Dsn, lengthDsn, &cb1, + (SQLTCHAR FAR *) DsDesc, lengthDsDesc, &cb2) == SQL_SUCCESS) + return true; + else + return false; + +} // wxDbGetDataSource() + + +// Change this to 0 to remove use of all deprecated functions +#if wxODBC_BACKWARD_COMPATABILITY +/******************************************************************** + ******************************************************************** + * + * The following functions are all DEPRECATED and are included for + * backward compatibility reasons only + * + ******************************************************************** + ********************************************************************/ +bool SqlLog(sqlLog state, const wxChar *filename) +{ + return wxDbSqlLog((enum wxDbSqlLogState)state, filename); +} +/***** DEPRECATED: use wxGetDataSource() *****/ +bool GetDataSource(HENV henv, char *Dsn, SWORD DsnMax, char *DsDesc, SWORD DsDescMax, + UWORD direction) +{ + return wxDbGetDataSource(henv, Dsn, DsnMax, DsDesc, DsDescMax, direction); +} +/***** DEPRECATED: use wxDbGetConnection() *****/ +wxDb WXDLLIMPEXP_ODBC *GetDbConnection(DbStuff *pDbStuff, bool FwdOnlyCursors) +{ + return wxDbGetConnection((wxDbConnectInf *)pDbStuff, FwdOnlyCursors); +} +/***** DEPRECATED: use wxDbFreeConnection() *****/ +bool WXDLLIMPEXP_ODBC FreeDbConnection(wxDb *pDb) +{ + return wxDbFreeConnection(pDb); +} +/***** DEPRECATED: use wxDbCloseConnections() *****/ +void WXDLLIMPEXP_ODBC CloseDbConnections(void) +{ + wxDbCloseConnections(); +} +/***** DEPRECATED: use wxDbConnectionsInUse() *****/ +int WXDLLIMPEXP_ODBC NumberDbConnectionsInUse(void) +{ + return wxDbConnectionsInUse(); +} +#endif + + +#endif + // wxUSE_ODBC diff --git a/Externals/wxWidgets/src/common/dbgrid.cpp b/Externals/wxWidgets/src/common/dbgrid.cpp index dd56bdd0b5..3a01b6c1eb 100644 --- a/Externals/wxWidgets/src/common/dbgrid.cpp +++ b/Externals/wxWidgets/src/common/dbgrid.cpp @@ -1,727 +1,727 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: src/common/dbgrid.cpp -// Purpose: Displays a wxDbTable in a wxGrid. -// Author: Roger Gammans, Paul Gammans -// Modified by: -// Created: -// RCS-ID: $Id: dbgrid.cpp 43769 2006-12-03 18:20:28Z VZ $ -// Copyright: (c) 1999 The Computer Surgery (roger@computer-surgery.co.uk) -// Licence: wxWindows licence -/////////////////////////////////////////////////////////////////////////////// -// Branched From : dbgrid.cpp,v 1.18 2000/12/19 13:00:58 -/////////////////////////////////////////////////////////////////////////////// - -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_ODBC && wxUSE_GRID - -#ifndef WX_PRECOMP - #include "wx/textctrl.h" - #include "wx/dc.h" - #include "wx/app.h" -#endif // WX_PRECOMP - -#include "wx/generic/gridctrl.h" -#include "wx/dbgrid.h" - -// DLL options compatibility check: -WX_CHECK_BUILD_OPTIONS("wxDbGrid") - - -wxDbGridCellAttrProvider::wxDbGridCellAttrProvider() -{ - m_data=NULL; - m_ColInfo=NULL; -} - -wxDbGridCellAttrProvider::wxDbGridCellAttrProvider(wxDbTable *tab, wxDbGridColInfoBase* ColInfo) -{ - m_data=tab; - m_ColInfo=ColInfo; -} - -wxDbGridCellAttrProvider::~wxDbGridCellAttrProvider() -{ -} - -wxGridCellAttr *wxDbGridCellAttrProvider::GetAttr(int row, int col, - wxGridCellAttr::wxAttrKind kind) const -{ - wxGridCellAttr *attr = wxGridCellAttrProvider::GetAttr(row,col,kind); - - if (m_data && m_ColInfo && (m_data->GetNumberOfColumns() > m_ColInfo[col].DbCol)) - { - //FIXME: this test could. - // ??::InsertPending == m_data->get_ModifiedStatus() - // and if InsertPending use colDef[].InsertAllowed - if (!(m_data->GetColDefs()[(m_ColInfo[col].DbCol)].Updateable)) - { - switch(kind) - { - case (wxGridCellAttr::Any): - if (!attr) - { - attr = new wxGridCellAttr; - // Store so we don't keep creating / deleting this... - wxDbGridCellAttrProvider * self = wxConstCast(this, wxDbGridCellAttrProvider) ; - attr->IncRef(); - self->SetColAttr(attr, col); - attr->SetReadOnly(); - } - else - { - //We now must check what we were returned. and do the right thing (tm) - wxGridCellAttr::wxAttrKind attrkind = attr->GetKind(); - if ((attrkind == (wxGridCellAttr::Default)) || (attrkind == (wxGridCellAttr::Cell)) || - (attrkind == (wxGridCellAttr::Col))) - { - wxGridCellAttr *attrtomerge = attr; - attr = new wxGridCellAttr; - attr->SetKind(wxGridCellAttr::Merged); - attr->MergeWith(attrtomerge); - attr->SetReadOnly(); - attrtomerge->DecRef(); - } - attr->SetReadOnly(); - } - break; - case (wxGridCellAttr::Col): - //As we must have a Coll, and were setting Coll attributes - // we can based on wxdbTable's so just set RO if attr valid - if (!attr) - { - attr = new wxGridCellAttr; - wxDbGridCellAttrProvider * self = wxConstCast(this, wxDbGridCellAttrProvider) ; - attr->IncRef(); - self->SetColAttr(attr, col); - } - attr->SetReadOnly(); - break; - default: - //Dont add RO for... - // wxGridCellAttr::Cell - Not required, will inherit on merge from row. - // wxGridCellAttr::Row - If wxDbtable ever supports row locking could add - // support to make RO on a row basis also. - // wxGridCellAttr::Default - Don't edit this ! or all cell with a attr will become readonly - // wxGridCellAttr::Merged - This should never be asked for. - break; - } - } - - } - return attr; -} - -void wxDbGridCellAttrProvider::AssignDbTable(wxDbTable *tab) -{ - m_data = tab; -} - -wxDbGridTableBase::wxDbGridTableBase(wxDbTable *tab, wxDbGridColInfo* ColInfo, - int count, bool takeOwnership) : - m_keys(), - m_data(tab), - m_dbowner(takeOwnership), - m_rowmodified(false) -{ - - if (count == wxUSE_QUERY) - { - m_rowtotal = m_data ? m_data->Count() : 0; - } - else - { - m_rowtotal = count; - } -// m_keys.Size(m_rowtotal); - m_row = -1; - if (ColInfo) - { - m_nocols = ColInfo->Length(); - m_ColInfo = new wxDbGridColInfoBase[m_nocols]; - //Do Copy. - wxDbGridColInfo *ptr = ColInfo; - int i =0; - while (ptr && i < m_nocols) - { - m_ColInfo[i] = ptr->m_data; - ptr = ptr->m_next; - i++; - } -#ifdef __WXDEBUG__ - if (ptr) - { - wxLogDebug(wxT("NoCols over length after traversing %i items"),i); - } - if (i < m_nocols) - { - wxLogDebug(wxT("NoCols under length after traversing %i items"),i); - } -#endif - } -} - -wxDbGridTableBase::~wxDbGridTableBase() -{ - wxDbGridCellAttrProvider *provider; - - //Can't check for update here as - - //FIXME: should i remove m_ColInfo and m_data from m_attrProvider if a wxDbGridAttrProvider -// if ((provider = dynamic_cast(GetAttrProvider()))) - // Using C casting for now until we can support dynamic_cast with wxWidgets - provider = (wxDbGridCellAttrProvider *)(GetAttrProvider()); - if (provider) - { - provider->AssignDbTable(NULL); - } - delete [] m_ColInfo; - - Writeback(); - if (m_dbowner) - { - delete m_data; - } -} - -bool wxDbGridTableBase::CanHaveAttributes() -{ - if (!GetAttrProvider()) - { - // use the default attr provider by default - SetAttrProvider(new wxDbGridCellAttrProvider(m_data, m_ColInfo)); - } - return true; -} - - -bool wxDbGridTableBase::AssignDbTable(wxDbTable *tab, int count, bool takeOwnership) -{ - wxDbGridCellAttrProvider *provider; - - //Remove Information from grid about old data - if (GetView()) - { - wxGrid *grid = GetView(); - grid->BeginBatch(); - grid->ClearSelection(); - if (grid->IsCellEditControlEnabled()) - { - grid->DisableCellEditControl(); - } - wxGridTableMessage msg(this, wxGRIDTABLE_NOTIFY_ROWS_DELETED,0,m_rowtotal); - grid->ProcessTableMessage(msg); - } - - //reset our internals... - Writeback(); - if (m_dbowner) - { - delete m_data; - } - m_keys.Empty(); - m_data = tab; - //FIXME: Remove dynamic_cast before sumision to wxwin -// if ((provider = dynamic_cast (GetAttrProvider()))) - // Using C casting for now until we can support dynamic_cast with wxWidgets - provider = (wxDbGridCellAttrProvider *)(GetAttrProvider()); - if (provider) - { - provider->AssignDbTable(m_data); - } - - if (count == wxUSE_QUERY) - { - m_rowtotal = m_data ? m_data->Count() : 0; - } - else - { - m_rowtotal = count; - } - m_row = -1; - - //Add Information to grid about new data - if (GetView()) - { - wxGrid * grid = GetView(); - wxGridTableMessage msg(this, wxGRIDTABLE_NOTIFY_ROWS_APPENDED, m_rowtotal); - grid->ProcessTableMessage(msg); - grid->EndBatch(); - } - m_dbowner = takeOwnership; - m_rowmodified = false; - return true; -} - -wxString wxDbGridTableBase::GetTypeName(int WXUNUSED(row), int col) -{ - if (GetNumberCols() > col) - { - if (m_ColInfo[col].wxtypename == wxGRID_VALUE_DBAUTO) - { - if (m_data->GetNumberOfColumns() <= m_ColInfo[col].DbCol) - { - wxFAIL_MSG (_T("You can not use wxGRID_VALUE_DBAUTO for virtual columns")); - } - switch(m_data->GetColDefs()[(m_ColInfo[col].DbCol)].SqlCtype) - { - case SQL_C_CHAR: -#ifdef SQL_C_WCHAR - case SQL_C_WCHAR: -#endif - return wxGRID_VALUE_STRING; - case SQL_C_SHORT: - case SQL_C_SSHORT: - return wxGRID_VALUE_NUMBER; - case SQL_C_USHORT: - return wxGRID_VALUE_NUMBER; - case SQL_C_LONG: - case SQL_C_SLONG: - return wxGRID_VALUE_NUMBER; - case SQL_C_ULONG: - return wxGRID_VALUE_NUMBER; - case SQL_C_FLOAT: - return wxGRID_VALUE_FLOAT; - case SQL_C_DOUBLE: - return wxGRID_VALUE_FLOAT; - case SQL_C_DATE: - return wxGRID_VALUE_DATETIME; - case SQL_C_TIME: - return wxGRID_VALUE_DATETIME; - case SQL_C_TIMESTAMP: - return wxGRID_VALUE_DATETIME; - default: - return wxGRID_VALUE_STRING; - } - } - else - { - return m_ColInfo[col].wxtypename; - } - } - wxFAIL_MSG (_T("unknown column")); - return wxString(); -} - -bool wxDbGridTableBase::CanGetValueAs(int row, int col, const wxString& typeName) -{ - wxLogDebug(wxT("CanGetValueAs() on %i,%i"),row,col); - //Is this needed? As it will be validated on GetValueAsXXXX - ValidateRow(row); - - if (typeName == wxGRID_VALUE_STRING) - { - //FIXME ummm What about blob field etc. - return true; - } - - if (m_data->IsColNull((UWORD)m_ColInfo[col].DbCol)) - { - return false; - } - - if (m_data->GetNumberOfColumns() <= m_ColInfo[col].DbCol) - { - //If a virtual column then we can't find it's type. we have to - // return false to get using wxVariant. - return false; - } - int sqltype = m_data->GetColDefs()[(m_ColInfo[col].DbCol)].SqlCtype; - - if (typeName == wxGRID_VALUE_DATETIME) - { - if ((sqltype == SQL_C_DATE) || - (sqltype == SQL_C_TIME) || - (sqltype == SQL_C_TIMESTAMP)) - { - return true; - } - return false; - } - if (typeName == wxGRID_VALUE_NUMBER) - { - if ((sqltype == SQL_C_SSHORT) || - (sqltype == SQL_C_USHORT) || - (sqltype == SQL_C_SLONG) || - (sqltype == SQL_C_ULONG)) - { - return true; - } - return false; - } - if (typeName == wxGRID_VALUE_FLOAT) - { - if ((sqltype == SQL_C_SSHORT) || - (sqltype == SQL_C_USHORT) || - (sqltype == SQL_C_SLONG) || - (sqltype == SQL_C_ULONG) || - (sqltype == SQL_C_FLOAT) || - (sqltype == SQL_C_DOUBLE)) - { - return true; - } - return false; - } - return false; -} - -bool wxDbGridTableBase::CanSetValueAs(int WXUNUSED(row), int col, const wxString& typeName) -{ - if (typeName == wxGRID_VALUE_STRING) - { - //FIXME ummm What about blob field etc. - return true; - } - - if (!(m_data->GetColDefs()[(m_ColInfo[col].DbCol)].Updateable)) - { - return false; - } - - if (m_data->GetNumberOfColumns() <= m_ColInfo[col].DbCol) - { - //If a virtual column then we can't find it's type. we have to faulse to - //get using wxVairent. - return false; - } - - int sqltype = m_data->GetColDefs()[(m_ColInfo[col].DbCol)].SqlCtype; - if (typeName == wxGRID_VALUE_DATETIME) - { - if ((sqltype == SQL_C_DATE) || - (sqltype == SQL_C_TIME) || - (sqltype == SQL_C_TIMESTAMP)) - { - return true; - } - return false; - } - if (typeName == wxGRID_VALUE_NUMBER) - { - if ((sqltype == SQL_C_SSHORT) || - (sqltype == SQL_C_USHORT) || - (sqltype == SQL_C_SLONG) || - (sqltype == SQL_C_ULONG)) - { - return true; - } - return false; - } - if (typeName == wxGRID_VALUE_FLOAT) - { - if ((sqltype == SQL_C_SSHORT) || - (sqltype == SQL_C_USHORT) || - (sqltype == SQL_C_SLONG) || - (sqltype == SQL_C_ULONG) || - (sqltype == SQL_C_FLOAT) || - (sqltype == SQL_C_DOUBLE)) - { - return true; - } - return false; - } - return false; -} - -long wxDbGridTableBase::GetValueAsLong(int row, int col) -{ - ValidateRow(row); - - if (m_data->GetNumberOfColumns() <= m_ColInfo[col].DbCol) - { - wxFAIL_MSG (_T("You can not use GetValueAsLong for virtual columns")); - return 0; - } - int sqltype = m_data->GetColDefs()[(m_ColInfo[col].DbCol)].SqlCtype; - if ((sqltype == SQL_C_SSHORT) || - (sqltype == SQL_C_USHORT) || - (sqltype == SQL_C_SLONG) || - (sqltype == SQL_C_ULONG)) - { - wxVariant val = m_data->GetColumn(m_ColInfo[col].DbCol); - return val.GetLong(); - } - wxFAIL_MSG (_T("unknown column, ")); - return 0; -} - -double wxDbGridTableBase::GetValueAsDouble(int row, int col) -{ - wxLogDebug(wxT("GetValueAsDouble() on %i,%i"),row,col); - ValidateRow(row); - - if (m_data->GetNumberOfColumns() <= m_ColInfo[col].DbCol) - { - wxFAIL_MSG (_T("You can not use GetValueAsDouble for virtual columns")); - return 0.0; - } - int sqltype = m_data->GetColDefs()[(m_ColInfo[col].DbCol)].SqlCtype; - if ((sqltype == SQL_C_SSHORT) || - (sqltype == SQL_C_USHORT) || - (sqltype == SQL_C_SLONG) || - (sqltype == SQL_C_ULONG) || - (sqltype == SQL_C_FLOAT) || - (sqltype == SQL_C_DOUBLE)) - { - wxVariant val = m_data->GetColumn(m_ColInfo[col].DbCol); - return val.GetDouble(); - } - wxFAIL_MSG (_T("unknown column")); - return 0.0; -} - -bool wxDbGridTableBase::GetValueAsBool(int row, int col) -{ - wxLogDebug(wxT("GetValueAsBool() on %i,%i"),row,col); - ValidateRow(row); - - if (m_data->GetNumberOfColumns() <= m_ColInfo[col].DbCol) - { - wxFAIL_MSG (_T("You can not use GetValueAsBool for virtual columns")); - return 0; - } - int sqltype = m_data->GetColDefs()[(m_ColInfo[col].DbCol)].SqlCtype; - if ((sqltype == SQL_C_SSHORT) || - (sqltype == SQL_C_USHORT) || - (sqltype == SQL_C_SLONG) || - (sqltype == SQL_C_ULONG)) - { - wxVariant val = m_data->GetColumn(m_ColInfo[col].DbCol); - return val.GetBool(); - } - wxFAIL_MSG (_T("unknown column, ")); - return 0; -} - -void* wxDbGridTableBase::GetValueAsCustom(int row, int col, const wxString& typeName) -{ - wxLogDebug(wxT("GetValueAsCustom() on %i,%i"),row,col); - ValidateRow(row); - - if (m_data->GetNumberOfColumns() <= m_ColInfo[col].DbCol) - { - wxFAIL_MSG (_T("You can not use GetValueAsCustom for virtual columns")); - return NULL; - } - if (m_data->IsColNull((UWORD)m_ColInfo[col].DbCol)) - return NULL; - - if (typeName == wxGRID_VALUE_DATETIME) - { - wxDbColDef *pColDefs = m_data->GetColDefs(); - int sqltype = pColDefs[(m_ColInfo[col].DbCol)].SqlCtype; - - if ((sqltype == SQL_C_DATE) || - (sqltype == SQL_C_TIME) || - (sqltype == SQL_C_TIMESTAMP)) - { - wxVariant val = m_data->GetColumn(m_ColInfo[col].DbCol); - return new wxDateTime(val.GetDateTime()); - } - } - wxFAIL_MSG (_T("unknown column data type ")); - return NULL; -} - - -void wxDbGridTableBase::SetValueAsCustom(int row, int col, const wxString& typeName, void* value) -{ - wxLogDebug(wxT("SetValueAsCustom() on %i,%i"),row,col); - ValidateRow(row); - - if (m_data->GetNumberOfColumns() <= m_ColInfo[col].DbCol) - { - wxFAIL_MSG (_T("You can not use SetValueAsCustom for virtual columns")); - return; - } - - if (typeName == wxGRID_VALUE_DATETIME) - { - int sqltype = m_data->GetColDefs()[(m_ColInfo[col].DbCol)].SqlCtype; - if ((sqltype == SQL_C_DATE) || - (sqltype == SQL_C_TIME) || - (sqltype == SQL_C_TIMESTAMP)) - { - //FIXME: you can't dynamic_cast from (void *) - //wxDateTime *date = wxDynamicCast(value, wxDateTime); - wxDateTime *date = (wxDateTime *)value; - if (!date) - { - wxFAIL_MSG (_T("Failed to convert data")); - return; - } - wxVariant val(date); - m_rowmodified = true; - m_data->SetColumn(m_ColInfo[col].DbCol,val); - } - } - wxFAIL_MSG (_T("unknown column data type")); - return ; -} - - -wxString wxDbGridTableBase::GetColLabelValue(int col) -{ - if (GetNumberCols() > col) - { - return m_ColInfo[col].Title; - } - wxFAIL_MSG (_T("unknown column")); - return wxString(); -} - -bool wxDbGridTableBase::IsEmptyCell(int row, int col) -{ - wxLogDebug(wxT("IsEmtpyCell on %i,%i"),row,col); - - ValidateRow(row); - return m_data->IsColNull((UWORD)m_ColInfo[col].DbCol); -} - - -wxString wxDbGridTableBase::GetValue(int row, int col) -{ - wxLogDebug(wxT("GetValue() on %i,%i"),row,col); - - ValidateRow(row); - wxVariant val = m_data->GetColumn(m_ColInfo[col].DbCol); - wxLogDebug(wxT("\tReturning \"%s\"\n"),val.GetString().c_str()); - - return val.GetString(); -} - - -void wxDbGridTableBase::SetValue(int row, int col,const wxString& value) -{ - wxLogDebug(wxT("SetValue() on %i,%i"),row,col); - - ValidateRow(row); - wxVariant val(value); - - m_rowmodified = true; - m_data->SetColumn(m_ColInfo[col].DbCol,val); -} - - -void wxDbGridTableBase::SetValueAsLong(int row, int col, long value) -{ - wxLogDebug(wxT("SetValueAsLong() on %i,%i"),row,col); - - ValidateRow(row); - wxVariant val(value); - - m_rowmodified = true; - m_data->SetColumn(m_ColInfo[col].DbCol,val); -} - - -void wxDbGridTableBase::SetValueAsDouble(int row, int col, double value) -{ - wxLogDebug(wxT("SetValueAsDouble() on %i,%i"),row,col); - - ValidateRow(row); - wxVariant val(value); - - m_rowmodified = true; - m_data->SetColumn(m_ColInfo[col].DbCol,val); - -} - - -void wxDbGridTableBase::SetValueAsBool(int row, int col, bool value) -{ - wxLogDebug(wxT("SetValueAsBool() on %i,%i"),row,col); - - ValidateRow(row); - wxVariant val(value); - - m_rowmodified = true; - m_data->SetColumn(m_ColInfo[col].DbCol,val); -} - - -void wxDbGridTableBase::ValidateRow(int row) -{ - wxLogDebug(wxT("ValidateRow(%i) currently on row (%i). Array count = %lu"), - row, m_row, (unsigned long)m_keys.GetCount()); - - if (row == m_row) - return; - Writeback(); - - //We add to row as Count is unsigned! - if ((unsigned)(row+1) > m_keys.GetCount()) - { - wxLogDebug(wxT("\trow key unknown")); - // Extend Array, iterate through data filling with keys - m_data->SetRowMode(wxDbTable::WX_ROW_MODE_QUERY); - int trow; - for (trow = m_keys.GetCount(); trow <= row; trow++) - { - wxLogDebug(wxT("Fetching row %i.."), trow); - bool ret = m_data->GetNext(); - - wxLogDebug(wxT(" ...success=(%i)"),ret); - GenericKey k = m_data->GetKey(); - m_keys.Add(k); - } - m_row = row; - } - else - { - wxLogDebug(wxT("\trow key known centering data")); - GenericKey k = m_keys.Item(row); - m_data->SetRowMode(wxDbTable::WX_ROW_MODE_INDIVIDUAL); - m_data->ClearMemberVars(); - m_data->SetKey(k); - if (!m_data->QueryOnKeyFields()) - { - wxDbLogExtendedErrorMsg(_T("ODBC error during Query()\n\n"), m_data->GetDb(),__TFILE__,__LINE__); - } - - m_data->GetNext(); - - m_row = row; - } - m_rowmodified = false; -} - -bool wxDbGridTableBase::Writeback() const -{ - if (!m_rowmodified) - { - return true; - } - - bool result=true; - wxLogDebug(wxT("\trow key unknown")); - -// FIXME: this code requires dbtable support for record status -#if 0 - switch (m_data->get_ModifiedStatus()) - { - case wxDbTable::UpdatePending: - result = m_data->Update(); - break; - case wxDbTable::InsertPending: - result = (m_data->Insert() == SQL_SUCCESS); - break; - default: - //Nothing - break; - } -#else - wxLogDebug(wxT("WARNING : Row writeback not implemented ")); -#endif - return result; -} - -#include "wx/arrimpl.cpp" - -WX_DEFINE_EXPORTED_OBJARRAY(keyarray) - -#endif // wxUSE_GRID && wxUSE_ODBC +/////////////////////////////////////////////////////////////////////////////// +// Name: src/common/dbgrid.cpp +// Purpose: Displays a wxDbTable in a wxGrid. +// Author: Roger Gammans, Paul Gammans +// Modified by: +// Created: +// RCS-ID: $Id: dbgrid.cpp 43769 2006-12-03 18:20:28Z VZ $ +// Copyright: (c) 1999 The Computer Surgery (roger@computer-surgery.co.uk) +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// +// Branched From : dbgrid.cpp,v 1.18 2000/12/19 13:00:58 +/////////////////////////////////////////////////////////////////////////////// + +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_ODBC && wxUSE_GRID + +#ifndef WX_PRECOMP + #include "wx/textctrl.h" + #include "wx/dc.h" + #include "wx/app.h" +#endif // WX_PRECOMP + +#include "wx/generic/gridctrl.h" +#include "wx/dbgrid.h" + +// DLL options compatibility check: +WX_CHECK_BUILD_OPTIONS("wxDbGrid") + + +wxDbGridCellAttrProvider::wxDbGridCellAttrProvider() +{ + m_data=NULL; + m_ColInfo=NULL; +} + +wxDbGridCellAttrProvider::wxDbGridCellAttrProvider(wxDbTable *tab, wxDbGridColInfoBase* ColInfo) +{ + m_data=tab; + m_ColInfo=ColInfo; +} + +wxDbGridCellAttrProvider::~wxDbGridCellAttrProvider() +{ +} + +wxGridCellAttr *wxDbGridCellAttrProvider::GetAttr(int row, int col, + wxGridCellAttr::wxAttrKind kind) const +{ + wxGridCellAttr *attr = wxGridCellAttrProvider::GetAttr(row,col,kind); + + if (m_data && m_ColInfo && (m_data->GetNumberOfColumns() > m_ColInfo[col].DbCol)) + { + //FIXME: this test could. + // ??::InsertPending == m_data->get_ModifiedStatus() + // and if InsertPending use colDef[].InsertAllowed + if (!(m_data->GetColDefs()[(m_ColInfo[col].DbCol)].Updateable)) + { + switch(kind) + { + case (wxGridCellAttr::Any): + if (!attr) + { + attr = new wxGridCellAttr; + // Store so we don't keep creating / deleting this... + wxDbGridCellAttrProvider * self = wxConstCast(this, wxDbGridCellAttrProvider) ; + attr->IncRef(); + self->SetColAttr(attr, col); + attr->SetReadOnly(); + } + else + { + //We now must check what we were returned. and do the right thing (tm) + wxGridCellAttr::wxAttrKind attrkind = attr->GetKind(); + if ((attrkind == (wxGridCellAttr::Default)) || (attrkind == (wxGridCellAttr::Cell)) || + (attrkind == (wxGridCellAttr::Col))) + { + wxGridCellAttr *attrtomerge = attr; + attr = new wxGridCellAttr; + attr->SetKind(wxGridCellAttr::Merged); + attr->MergeWith(attrtomerge); + attr->SetReadOnly(); + attrtomerge->DecRef(); + } + attr->SetReadOnly(); + } + break; + case (wxGridCellAttr::Col): + //As we must have a Coll, and were setting Coll attributes + // we can based on wxdbTable's so just set RO if attr valid + if (!attr) + { + attr = new wxGridCellAttr; + wxDbGridCellAttrProvider * self = wxConstCast(this, wxDbGridCellAttrProvider) ; + attr->IncRef(); + self->SetColAttr(attr, col); + } + attr->SetReadOnly(); + break; + default: + //Dont add RO for... + // wxGridCellAttr::Cell - Not required, will inherit on merge from row. + // wxGridCellAttr::Row - If wxDbtable ever supports row locking could add + // support to make RO on a row basis also. + // wxGridCellAttr::Default - Don't edit this ! or all cell with a attr will become readonly + // wxGridCellAttr::Merged - This should never be asked for. + break; + } + } + + } + return attr; +} + +void wxDbGridCellAttrProvider::AssignDbTable(wxDbTable *tab) +{ + m_data = tab; +} + +wxDbGridTableBase::wxDbGridTableBase(wxDbTable *tab, wxDbGridColInfo* ColInfo, + int count, bool takeOwnership) : + m_keys(), + m_data(tab), + m_dbowner(takeOwnership), + m_rowmodified(false) +{ + + if (count == wxUSE_QUERY) + { + m_rowtotal = m_data ? m_data->Count() : 0; + } + else + { + m_rowtotal = count; + } +// m_keys.Size(m_rowtotal); + m_row = -1; + if (ColInfo) + { + m_nocols = ColInfo->Length(); + m_ColInfo = new wxDbGridColInfoBase[m_nocols]; + //Do Copy. + wxDbGridColInfo *ptr = ColInfo; + int i =0; + while (ptr && i < m_nocols) + { + m_ColInfo[i] = ptr->m_data; + ptr = ptr->m_next; + i++; + } +#ifdef __WXDEBUG__ + if (ptr) + { + wxLogDebug(wxT("NoCols over length after traversing %i items"),i); + } + if (i < m_nocols) + { + wxLogDebug(wxT("NoCols under length after traversing %i items"),i); + } +#endif + } +} + +wxDbGridTableBase::~wxDbGridTableBase() +{ + wxDbGridCellAttrProvider *provider; + + //Can't check for update here as + + //FIXME: should i remove m_ColInfo and m_data from m_attrProvider if a wxDbGridAttrProvider +// if ((provider = dynamic_cast(GetAttrProvider()))) + // Using C casting for now until we can support dynamic_cast with wxWidgets + provider = (wxDbGridCellAttrProvider *)(GetAttrProvider()); + if (provider) + { + provider->AssignDbTable(NULL); + } + delete [] m_ColInfo; + + Writeback(); + if (m_dbowner) + { + delete m_data; + } +} + +bool wxDbGridTableBase::CanHaveAttributes() +{ + if (!GetAttrProvider()) + { + // use the default attr provider by default + SetAttrProvider(new wxDbGridCellAttrProvider(m_data, m_ColInfo)); + } + return true; +} + + +bool wxDbGridTableBase::AssignDbTable(wxDbTable *tab, int count, bool takeOwnership) +{ + wxDbGridCellAttrProvider *provider; + + //Remove Information from grid about old data + if (GetView()) + { + wxGrid *grid = GetView(); + grid->BeginBatch(); + grid->ClearSelection(); + if (grid->IsCellEditControlEnabled()) + { + grid->DisableCellEditControl(); + } + wxGridTableMessage msg(this, wxGRIDTABLE_NOTIFY_ROWS_DELETED,0,m_rowtotal); + grid->ProcessTableMessage(msg); + } + + //reset our internals... + Writeback(); + if (m_dbowner) + { + delete m_data; + } + m_keys.Empty(); + m_data = tab; + //FIXME: Remove dynamic_cast before sumision to wxwin +// if ((provider = dynamic_cast (GetAttrProvider()))) + // Using C casting for now until we can support dynamic_cast with wxWidgets + provider = (wxDbGridCellAttrProvider *)(GetAttrProvider()); + if (provider) + { + provider->AssignDbTable(m_data); + } + + if (count == wxUSE_QUERY) + { + m_rowtotal = m_data ? m_data->Count() : 0; + } + else + { + m_rowtotal = count; + } + m_row = -1; + + //Add Information to grid about new data + if (GetView()) + { + wxGrid * grid = GetView(); + wxGridTableMessage msg(this, wxGRIDTABLE_NOTIFY_ROWS_APPENDED, m_rowtotal); + grid->ProcessTableMessage(msg); + grid->EndBatch(); + } + m_dbowner = takeOwnership; + m_rowmodified = false; + return true; +} + +wxString wxDbGridTableBase::GetTypeName(int WXUNUSED(row), int col) +{ + if (GetNumberCols() > col) + { + if (m_ColInfo[col].wxtypename == wxGRID_VALUE_DBAUTO) + { + if (m_data->GetNumberOfColumns() <= m_ColInfo[col].DbCol) + { + wxFAIL_MSG (_T("You can not use wxGRID_VALUE_DBAUTO for virtual columns")); + } + switch(m_data->GetColDefs()[(m_ColInfo[col].DbCol)].SqlCtype) + { + case SQL_C_CHAR: +#ifdef SQL_C_WCHAR + case SQL_C_WCHAR: +#endif + return wxGRID_VALUE_STRING; + case SQL_C_SHORT: + case SQL_C_SSHORT: + return wxGRID_VALUE_NUMBER; + case SQL_C_USHORT: + return wxGRID_VALUE_NUMBER; + case SQL_C_LONG: + case SQL_C_SLONG: + return wxGRID_VALUE_NUMBER; + case SQL_C_ULONG: + return wxGRID_VALUE_NUMBER; + case SQL_C_FLOAT: + return wxGRID_VALUE_FLOAT; + case SQL_C_DOUBLE: + return wxGRID_VALUE_FLOAT; + case SQL_C_DATE: + return wxGRID_VALUE_DATETIME; + case SQL_C_TIME: + return wxGRID_VALUE_DATETIME; + case SQL_C_TIMESTAMP: + return wxGRID_VALUE_DATETIME; + default: + return wxGRID_VALUE_STRING; + } + } + else + { + return m_ColInfo[col].wxtypename; + } + } + wxFAIL_MSG (_T("unknown column")); + return wxString(); +} + +bool wxDbGridTableBase::CanGetValueAs(int row, int col, const wxString& typeName) +{ + wxLogDebug(wxT("CanGetValueAs() on %i,%i"),row,col); + //Is this needed? As it will be validated on GetValueAsXXXX + ValidateRow(row); + + if (typeName == wxGRID_VALUE_STRING) + { + //FIXME ummm What about blob field etc. + return true; + } + + if (m_data->IsColNull((UWORD)m_ColInfo[col].DbCol)) + { + return false; + } + + if (m_data->GetNumberOfColumns() <= m_ColInfo[col].DbCol) + { + //If a virtual column then we can't find it's type. we have to + // return false to get using wxVariant. + return false; + } + int sqltype = m_data->GetColDefs()[(m_ColInfo[col].DbCol)].SqlCtype; + + if (typeName == wxGRID_VALUE_DATETIME) + { + if ((sqltype == SQL_C_DATE) || + (sqltype == SQL_C_TIME) || + (sqltype == SQL_C_TIMESTAMP)) + { + return true; + } + return false; + } + if (typeName == wxGRID_VALUE_NUMBER) + { + if ((sqltype == SQL_C_SSHORT) || + (sqltype == SQL_C_USHORT) || + (sqltype == SQL_C_SLONG) || + (sqltype == SQL_C_ULONG)) + { + return true; + } + return false; + } + if (typeName == wxGRID_VALUE_FLOAT) + { + if ((sqltype == SQL_C_SSHORT) || + (sqltype == SQL_C_USHORT) || + (sqltype == SQL_C_SLONG) || + (sqltype == SQL_C_ULONG) || + (sqltype == SQL_C_FLOAT) || + (sqltype == SQL_C_DOUBLE)) + { + return true; + } + return false; + } + return false; +} + +bool wxDbGridTableBase::CanSetValueAs(int WXUNUSED(row), int col, const wxString& typeName) +{ + if (typeName == wxGRID_VALUE_STRING) + { + //FIXME ummm What about blob field etc. + return true; + } + + if (!(m_data->GetColDefs()[(m_ColInfo[col].DbCol)].Updateable)) + { + return false; + } + + if (m_data->GetNumberOfColumns() <= m_ColInfo[col].DbCol) + { + //If a virtual column then we can't find it's type. we have to faulse to + //get using wxVairent. + return false; + } + + int sqltype = m_data->GetColDefs()[(m_ColInfo[col].DbCol)].SqlCtype; + if (typeName == wxGRID_VALUE_DATETIME) + { + if ((sqltype == SQL_C_DATE) || + (sqltype == SQL_C_TIME) || + (sqltype == SQL_C_TIMESTAMP)) + { + return true; + } + return false; + } + if (typeName == wxGRID_VALUE_NUMBER) + { + if ((sqltype == SQL_C_SSHORT) || + (sqltype == SQL_C_USHORT) || + (sqltype == SQL_C_SLONG) || + (sqltype == SQL_C_ULONG)) + { + return true; + } + return false; + } + if (typeName == wxGRID_VALUE_FLOAT) + { + if ((sqltype == SQL_C_SSHORT) || + (sqltype == SQL_C_USHORT) || + (sqltype == SQL_C_SLONG) || + (sqltype == SQL_C_ULONG) || + (sqltype == SQL_C_FLOAT) || + (sqltype == SQL_C_DOUBLE)) + { + return true; + } + return false; + } + return false; +} + +long wxDbGridTableBase::GetValueAsLong(int row, int col) +{ + ValidateRow(row); + + if (m_data->GetNumberOfColumns() <= m_ColInfo[col].DbCol) + { + wxFAIL_MSG (_T("You can not use GetValueAsLong for virtual columns")); + return 0; + } + int sqltype = m_data->GetColDefs()[(m_ColInfo[col].DbCol)].SqlCtype; + if ((sqltype == SQL_C_SSHORT) || + (sqltype == SQL_C_USHORT) || + (sqltype == SQL_C_SLONG) || + (sqltype == SQL_C_ULONG)) + { + wxVariant val = m_data->GetColumn(m_ColInfo[col].DbCol); + return val.GetLong(); + } + wxFAIL_MSG (_T("unknown column, ")); + return 0; +} + +double wxDbGridTableBase::GetValueAsDouble(int row, int col) +{ + wxLogDebug(wxT("GetValueAsDouble() on %i,%i"),row,col); + ValidateRow(row); + + if (m_data->GetNumberOfColumns() <= m_ColInfo[col].DbCol) + { + wxFAIL_MSG (_T("You can not use GetValueAsDouble for virtual columns")); + return 0.0; + } + int sqltype = m_data->GetColDefs()[(m_ColInfo[col].DbCol)].SqlCtype; + if ((sqltype == SQL_C_SSHORT) || + (sqltype == SQL_C_USHORT) || + (sqltype == SQL_C_SLONG) || + (sqltype == SQL_C_ULONG) || + (sqltype == SQL_C_FLOAT) || + (sqltype == SQL_C_DOUBLE)) + { + wxVariant val = m_data->GetColumn(m_ColInfo[col].DbCol); + return val.GetDouble(); + } + wxFAIL_MSG (_T("unknown column")); + return 0.0; +} + +bool wxDbGridTableBase::GetValueAsBool(int row, int col) +{ + wxLogDebug(wxT("GetValueAsBool() on %i,%i"),row,col); + ValidateRow(row); + + if (m_data->GetNumberOfColumns() <= m_ColInfo[col].DbCol) + { + wxFAIL_MSG (_T("You can not use GetValueAsBool for virtual columns")); + return 0; + } + int sqltype = m_data->GetColDefs()[(m_ColInfo[col].DbCol)].SqlCtype; + if ((sqltype == SQL_C_SSHORT) || + (sqltype == SQL_C_USHORT) || + (sqltype == SQL_C_SLONG) || + (sqltype == SQL_C_ULONG)) + { + wxVariant val = m_data->GetColumn(m_ColInfo[col].DbCol); + return val.GetBool(); + } + wxFAIL_MSG (_T("unknown column, ")); + return 0; +} + +void* wxDbGridTableBase::GetValueAsCustom(int row, int col, const wxString& typeName) +{ + wxLogDebug(wxT("GetValueAsCustom() on %i,%i"),row,col); + ValidateRow(row); + + if (m_data->GetNumberOfColumns() <= m_ColInfo[col].DbCol) + { + wxFAIL_MSG (_T("You can not use GetValueAsCustom for virtual columns")); + return NULL; + } + if (m_data->IsColNull((UWORD)m_ColInfo[col].DbCol)) + return NULL; + + if (typeName == wxGRID_VALUE_DATETIME) + { + wxDbColDef *pColDefs = m_data->GetColDefs(); + int sqltype = pColDefs[(m_ColInfo[col].DbCol)].SqlCtype; + + if ((sqltype == SQL_C_DATE) || + (sqltype == SQL_C_TIME) || + (sqltype == SQL_C_TIMESTAMP)) + { + wxVariant val = m_data->GetColumn(m_ColInfo[col].DbCol); + return new wxDateTime(val.GetDateTime()); + } + } + wxFAIL_MSG (_T("unknown column data type ")); + return NULL; +} + + +void wxDbGridTableBase::SetValueAsCustom(int row, int col, const wxString& typeName, void* value) +{ + wxLogDebug(wxT("SetValueAsCustom() on %i,%i"),row,col); + ValidateRow(row); + + if (m_data->GetNumberOfColumns() <= m_ColInfo[col].DbCol) + { + wxFAIL_MSG (_T("You can not use SetValueAsCustom for virtual columns")); + return; + } + + if (typeName == wxGRID_VALUE_DATETIME) + { + int sqltype = m_data->GetColDefs()[(m_ColInfo[col].DbCol)].SqlCtype; + if ((sqltype == SQL_C_DATE) || + (sqltype == SQL_C_TIME) || + (sqltype == SQL_C_TIMESTAMP)) + { + //FIXME: you can't dynamic_cast from (void *) + //wxDateTime *date = wxDynamicCast(value, wxDateTime); + wxDateTime *date = (wxDateTime *)value; + if (!date) + { + wxFAIL_MSG (_T("Failed to convert data")); + return; + } + wxVariant val(date); + m_rowmodified = true; + m_data->SetColumn(m_ColInfo[col].DbCol,val); + } + } + wxFAIL_MSG (_T("unknown column data type")); + return ; +} + + +wxString wxDbGridTableBase::GetColLabelValue(int col) +{ + if (GetNumberCols() > col) + { + return m_ColInfo[col].Title; + } + wxFAIL_MSG (_T("unknown column")); + return wxString(); +} + +bool wxDbGridTableBase::IsEmptyCell(int row, int col) +{ + wxLogDebug(wxT("IsEmtpyCell on %i,%i"),row,col); + + ValidateRow(row); + return m_data->IsColNull((UWORD)m_ColInfo[col].DbCol); +} + + +wxString wxDbGridTableBase::GetValue(int row, int col) +{ + wxLogDebug(wxT("GetValue() on %i,%i"),row,col); + + ValidateRow(row); + wxVariant val = m_data->GetColumn(m_ColInfo[col].DbCol); + wxLogDebug(wxT("\tReturning \"%s\"\n"),val.GetString().c_str()); + + return val.GetString(); +} + + +void wxDbGridTableBase::SetValue(int row, int col,const wxString& value) +{ + wxLogDebug(wxT("SetValue() on %i,%i"),row,col); + + ValidateRow(row); + wxVariant val(value); + + m_rowmodified = true; + m_data->SetColumn(m_ColInfo[col].DbCol,val); +} + + +void wxDbGridTableBase::SetValueAsLong(int row, int col, long value) +{ + wxLogDebug(wxT("SetValueAsLong() on %i,%i"),row,col); + + ValidateRow(row); + wxVariant val(value); + + m_rowmodified = true; + m_data->SetColumn(m_ColInfo[col].DbCol,val); +} + + +void wxDbGridTableBase::SetValueAsDouble(int row, int col, double value) +{ + wxLogDebug(wxT("SetValueAsDouble() on %i,%i"),row,col); + + ValidateRow(row); + wxVariant val(value); + + m_rowmodified = true; + m_data->SetColumn(m_ColInfo[col].DbCol,val); + +} + + +void wxDbGridTableBase::SetValueAsBool(int row, int col, bool value) +{ + wxLogDebug(wxT("SetValueAsBool() on %i,%i"),row,col); + + ValidateRow(row); + wxVariant val(value); + + m_rowmodified = true; + m_data->SetColumn(m_ColInfo[col].DbCol,val); +} + + +void wxDbGridTableBase::ValidateRow(int row) +{ + wxLogDebug(wxT("ValidateRow(%i) currently on row (%i). Array count = %lu"), + row, m_row, (unsigned long)m_keys.GetCount()); + + if (row == m_row) + return; + Writeback(); + + //We add to row as Count is unsigned! + if ((unsigned)(row+1) > m_keys.GetCount()) + { + wxLogDebug(wxT("\trow key unknown")); + // Extend Array, iterate through data filling with keys + m_data->SetRowMode(wxDbTable::WX_ROW_MODE_QUERY); + int trow; + for (trow = m_keys.GetCount(); trow <= row; trow++) + { + wxLogDebug(wxT("Fetching row %i.."), trow); + bool ret = m_data->GetNext(); + + wxLogDebug(wxT(" ...success=(%i)"),ret); + GenericKey k = m_data->GetKey(); + m_keys.Add(k); + } + m_row = row; + } + else + { + wxLogDebug(wxT("\trow key known centering data")); + GenericKey k = m_keys.Item(row); + m_data->SetRowMode(wxDbTable::WX_ROW_MODE_INDIVIDUAL); + m_data->ClearMemberVars(); + m_data->SetKey(k); + if (!m_data->QueryOnKeyFields()) + { + wxDbLogExtendedErrorMsg(_T("ODBC error during Query()\n\n"), m_data->GetDb(),__TFILE__,__LINE__); + } + + m_data->GetNext(); + + m_row = row; + } + m_rowmodified = false; +} + +bool wxDbGridTableBase::Writeback() const +{ + if (!m_rowmodified) + { + return true; + } + + bool result=true; + wxLogDebug(wxT("\trow key unknown")); + +// FIXME: this code requires dbtable support for record status +#if 0 + switch (m_data->get_ModifiedStatus()) + { + case wxDbTable::UpdatePending: + result = m_data->Update(); + break; + case wxDbTable::InsertPending: + result = (m_data->Insert() == SQL_SUCCESS); + break; + default: + //Nothing + break; + } +#else + wxLogDebug(wxT("WARNING : Row writeback not implemented ")); +#endif + return result; +} + +#include "wx/arrimpl.cpp" + +WX_DEFINE_EXPORTED_OBJARRAY(keyarray) + +#endif // wxUSE_GRID && wxUSE_ODBC diff --git a/Externals/wxWidgets/src/common/dbtable.cpp b/Externals/wxWidgets/src/common/dbtable.cpp index 8038ee69f5..292b4390d2 100644 --- a/Externals/wxWidgets/src/common/dbtable.cpp +++ b/Externals/wxWidgets/src/common/dbtable.cpp @@ -1,2946 +1,2946 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: src/common/dbtable.cpp -// Purpose: Implementation of the wxDbTable class. -// Author: Doug Card -// Modified by: George Tasker -// Bart Jourquin -// Mark Johnson -// Created: 9.96 -// RCS-ID: $Id: dbtable.cpp 48685 2007-09-14 19:02:28Z VZ $ -// Copyright: (c) 1996 Remstar International, Inc. -// Licence: wxWindows licence -/////////////////////////////////////////////////////////////////////////////// - -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_ODBC - -#ifndef WX_PRECOMP - #include "wx/object.h" - #include "wx/list.h" - #include "wx/string.h" - #include "wx/utils.h" - #include "wx/log.h" -#endif - -#ifdef DBDEBUG_CONSOLE -#if wxUSE_IOSTREAMH - #include -#else - #include -#endif - #include "wx/ioswrap.h" -#endif - -#include "wx/filefn.h" - -#include -#include -#include - -#include "wx/dbtable.h" - -#ifdef __UNIX__ -// The HPUX preprocessor lines below were commented out on 8/20/97 -// because macros.h currently redefines DEBUG and is unneeded. -// # ifdef HPUX -// # include -// # endif -# ifdef LINUX -# include -# endif -#endif - -ULONG lastTableID = 0; - - -#ifdef __WXDEBUG__ - #include "wx/thread.h" - - wxList TablesInUse; -#if wxUSE_THREADS - wxCriticalSection csTablesInUse; -#endif // wxUSE_THREADS -#endif - - -void csstrncpyt(wxChar *target, const wxChar *source, int n) -{ - while ( (*target++ = *source++) != '\0' && --n != 0 ) - ; - - *target = '\0'; -} - - - -/********** wxDbColDef::wxDbColDef() Constructor **********/ -wxDbColDef::wxDbColDef() -{ - Initialize(); -} // Constructor - - -bool wxDbColDef::Initialize() -{ - ColName[0] = 0; - DbDataType = DB_DATA_TYPE_INTEGER; - SqlCtype = SQL_C_LONG; - PtrDataObj = NULL; - SzDataObj = 0; - KeyField = false; - Updateable = false; - InsertAllowed = false; - DerivedCol = false; - CbValue = 0; - Null = false; - - return true; -} // wxDbColDef::Initialize() - - -/********** wxDbTable::wxDbTable() Constructor **********/ -wxDbTable::wxDbTable(wxDb *pwxDb, const wxString &tblName, const UWORD numColumns, - const wxString &qryTblName, bool qryOnly, const wxString &tblPath) -{ - if (!initialize(pwxDb, tblName, numColumns, qryTblName, qryOnly, tblPath)) - cleanup(); -} // wxDbTable::wxDbTable() - - -/***** DEPRECATED: use wxDbTable::wxDbTable() format above *****/ -#if WXWIN_COMPATIBILITY_2_4 -wxDbTable::wxDbTable(wxDb *pwxDb, const wxString &tblName, const UWORD numColumns, - const wxChar *qryTblName, bool qryOnly, const wxString &tblPath) -{ - wxString tempQryTblName; - tempQryTblName = qryTblName; - if (!initialize(pwxDb, tblName, numColumns, tempQryTblName, qryOnly, tblPath)) - cleanup(); -} // wxDbTable::wxDbTable() -#endif // WXWIN_COMPATIBILITY_2_4 - - -/********** wxDbTable::~wxDbTable() **********/ -wxDbTable::~wxDbTable() -{ - this->cleanup(); -} // wxDbTable::~wxDbTable() - - -bool wxDbTable::initialize(wxDb *pwxDb, const wxString &tblName, const UWORD numColumns, - const wxString &qryTblName, bool qryOnly, const wxString &tblPath) -{ - // Initializing member variables - pDb = pwxDb; // Pointer to the wxDb object - henv = 0; - hdbc = 0; - hstmt = 0; - m_hstmtGridQuery = 0; - hstmtDefault = 0; // Initialized below - hstmtCount = 0; // Initialized first time it is needed - hstmtInsert = 0; - hstmtDelete = 0; - hstmtUpdate = 0; - hstmtInternal = 0; - colDefs = 0; - tableID = 0; - m_numCols = numColumns; // Number of columns in the table - where.Empty(); // Where clause - orderBy.Empty(); // Order By clause - from.Empty(); // From clause - selectForUpdate = false; // SELECT ... FOR UPDATE; Indicates whether to include the FOR UPDATE phrase - queryOnly = qryOnly; - insertable = true; - tablePath.Empty(); - tableName.Empty(); - queryTableName.Empty(); - - wxASSERT(tblName.length()); - wxASSERT(pDb); - - if (!pDb) - return false; - - tableName = tblName; // Table Name - if ((pDb->Dbms() == dbmsORACLE) || - (pDb->Dbms() == dbmsFIREBIRD) || - (pDb->Dbms() == dbmsINTERBASE)) - tableName = tableName.Upper(); - - if (tblPath.length()) - tablePath = tblPath; // Table Path - used for dBase files - else - tablePath.Empty(); - - if (qryTblName.length()) // Name of the table/view to query - queryTableName = qryTblName; - else - queryTableName = tblName; - - if ((pDb->Dbms() == dbmsORACLE) || - (pDb->Dbms() == dbmsFIREBIRD) || - (pDb->Dbms() == dbmsINTERBASE)) - queryTableName = queryTableName.Upper(); - - pDb->incrementTableCount(); - - wxString s; - tableID = ++lastTableID; - s.Printf(wxT("wxDbTable constructor (%-20s) tableID:[%6lu] pDb:[%p]"), - tblName.c_str(), tableID, wx_static_cast(void*, pDb)); - -#ifdef __WXDEBUG__ - wxTablesInUse *tableInUse; - tableInUse = new wxTablesInUse(); - tableInUse->tableName = tblName; - tableInUse->tableID = tableID; - tableInUse->pDb = pDb; - { -#if wxUSE_THREADS - wxCriticalSectionLocker lock(csTablesInUse); -#endif // wxUSE_THREADS - TablesInUse.Append(tableInUse); - } -#endif - - pDb->WriteSqlLog(s); - - // Grab the HENV and HDBC from the wxDb object - henv = pDb->GetHENV(); - hdbc = pDb->GetHDBC(); - - // Allocate space for column definitions - if (m_numCols) - colDefs = new wxDbColDef[m_numCols]; // Points to the first column definition - - // Allocate statement handles for the table - if (!queryOnly) - { - // Allocate a separate statement handle for performing inserts - if (SQLAllocStmt(hdbc, &hstmtInsert) != SQL_SUCCESS) - pDb->DispAllErrors(henv, hdbc); - // Allocate a separate statement handle for performing deletes - if (SQLAllocStmt(hdbc, &hstmtDelete) != SQL_SUCCESS) - pDb->DispAllErrors(henv, hdbc); - // Allocate a separate statement handle for performing updates - if (SQLAllocStmt(hdbc, &hstmtUpdate) != SQL_SUCCESS) - pDb->DispAllErrors(henv, hdbc); - } - // Allocate a separate statement handle for internal use - if (SQLAllocStmt(hdbc, &hstmtInternal) != SQL_SUCCESS) - pDb->DispAllErrors(henv, hdbc); - - // Set the cursor type for the statement handles - cursorType = SQL_CURSOR_STATIC; - - if (SQLSetStmtOption(hstmtInternal, SQL_CURSOR_TYPE, cursorType) != SQL_SUCCESS) - { - // Check to see if cursor type is supported - pDb->GetNextError(henv, hdbc, hstmtInternal); - if (! wxStrcmp(pDb->sqlState, wxT("01S02"))) // Option Value Changed - { - // Datasource does not support static cursors. Driver - // will substitute a cursor type. Call SQLGetStmtOption() - // to determine which cursor type was selected. - if (SQLGetStmtOption(hstmtInternal, SQL_CURSOR_TYPE, &cursorType) != SQL_SUCCESS) - pDb->DispAllErrors(henv, hdbc, hstmtInternal); -#ifdef DBDEBUG_CONSOLE - cout << wxT("Static cursor changed to: "); - switch(cursorType) - { - case SQL_CURSOR_FORWARD_ONLY: - cout << wxT("Forward Only"); - break; - case SQL_CURSOR_STATIC: - cout << wxT("Static"); - break; - case SQL_CURSOR_KEYSET_DRIVEN: - cout << wxT("Keyset Driven"); - break; - case SQL_CURSOR_DYNAMIC: - cout << wxT("Dynamic"); - break; - } - cout << endl << endl; -#endif - // BJO20000425 - if (pDb->FwdOnlyCursors() && cursorType != SQL_CURSOR_FORWARD_ONLY) - { - // Force the use of a forward only cursor... - cursorType = SQL_CURSOR_FORWARD_ONLY; - if (SQLSetStmtOption(hstmtInternal, SQL_CURSOR_TYPE, cursorType) != SQL_SUCCESS) - { - // Should never happen - pDb->GetNextError(henv, hdbc, hstmtInternal); - return false; - } - } - } - else - { - pDb->DispNextError(); - pDb->DispAllErrors(henv, hdbc, hstmtInternal); - } - } -#ifdef DBDEBUG_CONSOLE - else - cout << wxT("Cursor Type set to STATIC") << endl << endl; -#endif - - if (!queryOnly) - { - // Set the cursor type for the INSERT statement handle - if (SQLSetStmtOption(hstmtInsert, SQL_CURSOR_TYPE, SQL_CURSOR_FORWARD_ONLY) != SQL_SUCCESS) - pDb->DispAllErrors(henv, hdbc, hstmtInsert); - // Set the cursor type for the DELETE statement handle - if (SQLSetStmtOption(hstmtDelete, SQL_CURSOR_TYPE, SQL_CURSOR_FORWARD_ONLY) != SQL_SUCCESS) - pDb->DispAllErrors(henv, hdbc, hstmtDelete); - // Set the cursor type for the UPDATE statement handle - if (SQLSetStmtOption(hstmtUpdate, SQL_CURSOR_TYPE, SQL_CURSOR_FORWARD_ONLY) != SQL_SUCCESS) - pDb->DispAllErrors(henv, hdbc, hstmtUpdate); - } - - // Make the default cursor the active cursor - hstmtDefault = GetNewCursor(false,false); - wxASSERT(hstmtDefault); - hstmt = *hstmtDefault; - - return true; - -} // wxDbTable::initialize() - - -void wxDbTable::cleanup() -{ - wxString s; - if (pDb) - { - s.Printf(wxT("wxDbTable destructor (%-20s) tableID:[%6lu] pDb:[%p]"), - tableName.c_str(), tableID, wx_static_cast(void*, pDb)); - pDb->WriteSqlLog(s); - } - -#ifdef __WXDEBUG__ - if (tableID) - { - bool found = false; - - wxList::compatibility_iterator pNode; - { -#if wxUSE_THREADS - wxCriticalSectionLocker lock(csTablesInUse); -#endif // wxUSE_THREADS - pNode = TablesInUse.GetFirst(); - while (!found && pNode) - { - if (((wxTablesInUse *)pNode->GetData())->tableID == tableID) - { - found = true; - delete (wxTablesInUse *)pNode->GetData(); - TablesInUse.Erase(pNode); - } - else - pNode = pNode->GetNext(); - } - } - if (!found) - { - wxString msg; - msg.Printf(wxT("Unable to find the tableID in the linked\nlist of tables in use.\n\n%s"),s.c_str()); - wxLogDebug (msg,wxT("NOTICE...")); - } - } -#endif - - // Decrement the wxDb table count - if (pDb) - pDb->decrementTableCount(); - - // Delete memory allocated for column definitions - if (colDefs) - delete [] colDefs; - - // Free statement handles - if (!queryOnly) - { - if (hstmtInsert) - { -/* -ODBC 3.0 says to use this form - if (SQLFreeHandle(*hstmtDel, SQL_DROP) != SQL_SUCCESS) -*/ - if (SQLFreeStmt(hstmtInsert, SQL_DROP) != SQL_SUCCESS) - pDb->DispAllErrors(henv, hdbc); - } - - if (hstmtDelete) - { -/* -ODBC 3.0 says to use this form - if (SQLFreeHandle(*hstmtDel, SQL_DROP) != SQL_SUCCESS) -*/ - if (SQLFreeStmt(hstmtDelete, SQL_DROP) != SQL_SUCCESS) - pDb->DispAllErrors(henv, hdbc); - } - - if (hstmtUpdate) - { -/* -ODBC 3.0 says to use this form - if (SQLFreeHandle(*hstmtDel, SQL_DROP) != SQL_SUCCESS) -*/ - if (SQLFreeStmt(hstmtUpdate, SQL_DROP) != SQL_SUCCESS) - pDb->DispAllErrors(henv, hdbc); - } - } - - if (hstmtInternal) - { - if (SQLFreeStmt(hstmtInternal, SQL_DROP) != SQL_SUCCESS) - pDb->DispAllErrors(henv, hdbc); - } - - // Delete dynamically allocated cursors - if (hstmtDefault) - DeleteCursor(hstmtDefault); - - if (hstmtCount) - DeleteCursor(hstmtCount); - - if (m_hstmtGridQuery) - DeleteCursor(m_hstmtGridQuery); - -} // wxDbTable::cleanup() - - -/***************************** PRIVATE FUNCTIONS *****************************/ - - -void wxDbTable::setCbValueForColumn(int columnIndex) -{ - switch(colDefs[columnIndex].DbDataType) - { - case DB_DATA_TYPE_VARCHAR: - case DB_DATA_TYPE_MEMO: - if (colDefs[columnIndex].Null) - colDefs[columnIndex].CbValue = SQL_NULL_DATA; - else - colDefs[columnIndex].CbValue = SQL_NTS; - break; - case DB_DATA_TYPE_INTEGER: - if (colDefs[columnIndex].Null) - colDefs[columnIndex].CbValue = SQL_NULL_DATA; - else - colDefs[columnIndex].CbValue = 0; - break; - case DB_DATA_TYPE_FLOAT: - if (colDefs[columnIndex].Null) - colDefs[columnIndex].CbValue = SQL_NULL_DATA; - else - colDefs[columnIndex].CbValue = 0; - break; - case DB_DATA_TYPE_DATE: - if (colDefs[columnIndex].Null) - colDefs[columnIndex].CbValue = SQL_NULL_DATA; - else - colDefs[columnIndex].CbValue = 0; - break; - case DB_DATA_TYPE_BLOB: - if (colDefs[columnIndex].Null) - colDefs[columnIndex].CbValue = SQL_NULL_DATA; - else - if (colDefs[columnIndex].SqlCtype == SQL_C_WXCHAR) - colDefs[columnIndex].CbValue = SQL_NTS; - else - colDefs[columnIndex].CbValue = SQL_LEN_DATA_AT_EXEC(colDefs[columnIndex].SzDataObj); - break; - } -} - -/********** wxDbTable::bindParams() **********/ -bool wxDbTable::bindParams(bool forUpdate) -{ - wxASSERT(!queryOnly); - if (queryOnly) - return false; - - SWORD fSqlType = 0; - SDWORD precision = 0; - SWORD scale = 0; - - // Bind each column of the table that should be bound - // to a parameter marker - int i; - UWORD colNumber; - - for (i=0, colNumber=1; i < m_numCols; i++) - { - if (forUpdate) - { - if (!colDefs[i].Updateable) - continue; - } - else - { - if (!colDefs[i].InsertAllowed) - continue; - } - - switch(colDefs[i].DbDataType) - { - case DB_DATA_TYPE_VARCHAR: - fSqlType = pDb->GetTypeInfVarchar().FsqlType; - precision = colDefs[i].SzDataObj; - scale = 0; - break; - case DB_DATA_TYPE_MEMO: - fSqlType = pDb->GetTypeInfMemo().FsqlType; - precision = colDefs[i].SzDataObj; - scale = 0; - break; - case DB_DATA_TYPE_INTEGER: - fSqlType = pDb->GetTypeInfInteger().FsqlType; - precision = pDb->GetTypeInfInteger().Precision; - scale = 0; - break; - case DB_DATA_TYPE_FLOAT: - fSqlType = pDb->GetTypeInfFloat().FsqlType; - precision = pDb->GetTypeInfFloat().Precision; - scale = pDb->GetTypeInfFloat().MaximumScale; - // SQL Sybase Anywhere v5.5 returned a negative number for the - // MaxScale. This caused ODBC to kick out an error on ibscale. - // I check for this here and set the scale = precision. - //if (scale < 0) - // scale = (short) precision; - break; - case DB_DATA_TYPE_DATE: - fSqlType = pDb->GetTypeInfDate().FsqlType; - precision = pDb->GetTypeInfDate().Precision; - scale = 0; - break; - case DB_DATA_TYPE_BLOB: - fSqlType = pDb->GetTypeInfBlob().FsqlType; - precision = colDefs[i].SzDataObj; - scale = 0; - break; - } - - setCbValueForColumn(i); - - if (forUpdate) - { - if (SQLBindParameter(hstmtUpdate, colNumber++, SQL_PARAM_INPUT, colDefs[i].SqlCtype, - fSqlType, precision, scale, (UCHAR*) colDefs[i].PtrDataObj, - precision+1, &colDefs[i].CbValue) != SQL_SUCCESS) - { - return(pDb->DispAllErrors(henv, hdbc, hstmtUpdate)); - } - } - else - { - if (SQLBindParameter(hstmtInsert, colNumber++, SQL_PARAM_INPUT, colDefs[i].SqlCtype, - fSqlType, precision, scale, (UCHAR*) colDefs[i].PtrDataObj, - precision+1, &colDefs[i].CbValue) != SQL_SUCCESS) - { - return(pDb->DispAllErrors(henv, hdbc, hstmtInsert)); - } - } - } - - // Completed successfully - return true; - -} // wxDbTable::bindParams() - - -/********** wxDbTable::bindInsertParams() **********/ -bool wxDbTable::bindInsertParams(void) -{ - return bindParams(false); -} // wxDbTable::bindInsertParams() - - -/********** wxDbTable::bindUpdateParams() **********/ -bool wxDbTable::bindUpdateParams(void) -{ - return bindParams(true); -} // wxDbTable::bindUpdateParams() - - -/********** wxDbTable::bindCols() **********/ -bool wxDbTable::bindCols(HSTMT cursor) -{ - // Bind each column of the table to a memory address for fetching data - UWORD i; - for (i = 0; i < m_numCols; i++) - { - if (SQLBindCol(cursor, (UWORD)(i+1), colDefs[i].SqlCtype, (UCHAR*) colDefs[i].PtrDataObj, - colDefs[i].SzDataObj, &colDefs[i].CbValue ) != SQL_SUCCESS) - return (pDb->DispAllErrors(henv, hdbc, cursor)); - } - - // Completed successfully - return true; -} // wxDbTable::bindCols() - - -/********** wxDbTable::getRec() **********/ -bool wxDbTable::getRec(UWORD fetchType) -{ - RETCODE retcode; - - if (!pDb->FwdOnlyCursors()) - { - // Fetch the NEXT, PREV, FIRST or LAST record, depending on fetchType - SQLULEN cRowsFetched; - UWORD rowStatus; - - retcode = SQLExtendedFetch(hstmt, fetchType, 0, &cRowsFetched, &rowStatus); - if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO) - { - if (retcode == SQL_NO_DATA_FOUND) - return false; - else - return(pDb->DispAllErrors(henv, hdbc, hstmt)); - } - else - { - // Set the Null member variable to indicate the Null state - // of each column just read in. - int i; - for (i = 0; i < m_numCols; i++) - colDefs[i].Null = (colDefs[i].CbValue == SQL_NULL_DATA); - } - } - else - { - // Fetch the next record from the record set - retcode = SQLFetch(hstmt); - if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO) - { - if (retcode == SQL_NO_DATA_FOUND) - return false; - else - return(pDb->DispAllErrors(henv, hdbc, hstmt)); - } - else - { - // Set the Null member variable to indicate the Null state - // of each column just read in. - int i; - for (i = 0; i < m_numCols; i++) - colDefs[i].Null = (colDefs[i].CbValue == SQL_NULL_DATA); - } - } - - // Completed successfully - return true; - -} // wxDbTable::getRec() - - -/********** wxDbTable::execDelete() **********/ -bool wxDbTable::execDelete(const wxString &pSqlStmt) -{ - RETCODE retcode; - - // Execute the DELETE statement - retcode = SQLExecDirect(hstmtDelete, (SQLTCHAR FAR *) pSqlStmt.c_str(), SQL_NTS); - - if (retcode == SQL_SUCCESS || - retcode == SQL_NO_DATA_FOUND || - retcode == SQL_SUCCESS_WITH_INFO) - { - // Record deleted successfully - return true; - } - - // Problem deleting record - return(pDb->DispAllErrors(henv, hdbc, hstmtDelete)); - -} // wxDbTable::execDelete() - - -/********** wxDbTable::execUpdate() **********/ -bool wxDbTable::execUpdate(const wxString &pSqlStmt) -{ - RETCODE retcode; - - // Execute the UPDATE statement - retcode = SQLExecDirect(hstmtUpdate, (SQLTCHAR FAR *) pSqlStmt.c_str(), SQL_NTS); - - if (retcode == SQL_SUCCESS || - retcode == SQL_NO_DATA_FOUND || - retcode == SQL_SUCCESS_WITH_INFO) - { - // Record updated successfully - return true; - } - else if (retcode == SQL_NEED_DATA) - { - PTR pParmID; - retcode = SQLParamData(hstmtUpdate, &pParmID); - while (retcode == SQL_NEED_DATA) - { - // Find the parameter - int i; - for (i=0; i < m_numCols; i++) - { - if (colDefs[i].PtrDataObj == pParmID) - { - // We found it. Store the parameter. - retcode = SQLPutData(hstmtUpdate, pParmID, colDefs[i].SzDataObj); - if (retcode != SQL_SUCCESS) - { - pDb->DispNextError(); - return pDb->DispAllErrors(henv, hdbc, hstmtUpdate); - } - break; - } - } - retcode = SQLParamData(hstmtUpdate, &pParmID); - } - if (retcode == SQL_SUCCESS || - retcode == SQL_NO_DATA_FOUND || - retcode == SQL_SUCCESS_WITH_INFO) - { - // Record updated successfully - return true; - } - } - - // Problem updating record - return(pDb->DispAllErrors(henv, hdbc, hstmtUpdate)); - -} // wxDbTable::execUpdate() - - -/********** wxDbTable::query() **********/ -bool wxDbTable::query(int queryType, bool forUpdate, bool distinct, const wxString &pSqlStmt) -{ - wxString sqlStmt; - - if (forUpdate) - // The user may wish to select for update, but the DBMS may not be capable - selectForUpdate = CanSelectForUpdate(); - else - selectForUpdate = false; - - // Set the SQL SELECT string - if (queryType != DB_SELECT_STATEMENT) // A select statement was not passed in, - { // so generate a select statement. - BuildSelectStmt(sqlStmt, queryType, distinct); - pDb->WriteSqlLog(sqlStmt); - } - - // Make sure the cursor is closed first - if (!CloseCursor(hstmt)) - return false; - - // Execute the SQL SELECT statement - int retcode; - retcode = SQLExecDirect(hstmt, (SQLTCHAR FAR *) (queryType == DB_SELECT_STATEMENT ? pSqlStmt.c_str() : sqlStmt.c_str()), SQL_NTS); - if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO) - return(pDb->DispAllErrors(henv, hdbc, hstmt)); - - // Completed successfully - return true; - -} // wxDbTable::query() - - -/***************************** PUBLIC FUNCTIONS *****************************/ - - -/********** wxDbTable::Open() **********/ -bool wxDbTable::Open(bool checkPrivileges, bool checkTableExists) -{ - if (!pDb) - return false; - - int i; - wxString sqlStmt; - wxString s; - - // Calculate the maximum size of the concatenated - // keys for use with wxDbGrid - m_keysize = 0; - for (i=0; i < m_numCols; i++) - { - if (colDefs[i].KeyField) - { - m_keysize += colDefs[i].SzDataObj; - } - } - - s.Empty(); - - bool exists = true; - if (checkTableExists) - { - if (pDb->Dbms() == dbmsPOSTGRES) - exists = pDb->TableExists(tableName, NULL, tablePath); - else - exists = pDb->TableExists(tableName, pDb->GetUsername(), tablePath); - } - - // Verify that the table exists in the database - if (!exists) - { - s = wxT("Table/view does not exist in the database"); - if ( *(pDb->dbInf.accessibleTables) == wxT('Y')) - s += wxT(", or you have no permissions.\n"); - else - s += wxT(".\n"); - } - else if (checkPrivileges) - { - // Verify the user has rights to access the table. - bool hasPrivs wxDUMMY_INITIALIZE(true); - - if (pDb->Dbms() == dbmsPOSTGRES) - hasPrivs = pDb->TablePrivileges(tableName, wxT("SELECT"), pDb->GetUsername(), NULL, tablePath); - else - hasPrivs = pDb->TablePrivileges(tableName, wxT("SELECT"), pDb->GetUsername(), pDb->GetUsername(), tablePath); - - if (!hasPrivs) - s = wxT("Connecting user does not have sufficient privileges to access this table.\n"); - } - - if (!s.empty()) - { - wxString p; - - if (!tablePath.empty()) - p.Printf(wxT("Error opening '%s/%s'.\n"),tablePath.c_str(),tableName.c_str()); - else - p.Printf(wxT("Error opening '%s'.\n"), tableName.c_str()); - - p += s; - pDb->LogError(p.GetData()); - - return false; - } - - // Bind the member variables for field exchange between - // the wxDbTable object and the ODBC record. - if (!queryOnly) - { - if (!bindInsertParams()) // Inserts - return false; - - if (!bindUpdateParams()) // Updates - return false; - } - - if (!bindCols(*hstmtDefault)) // Selects - return false; - - if (!bindCols(hstmtInternal)) // Internal use only - return false; - - /* - * Do NOT bind the hstmtCount cursor!!! - */ - - // Build an insert statement using parameter markers - if (!queryOnly && m_numCols > 0) - { - bool needComma = false; - sqlStmt.Printf(wxT("INSERT INTO %s ("), - pDb->SQLTableName(tableName.c_str()).c_str()); - for (i = 0; i < m_numCols; i++) - { - if (! colDefs[i].InsertAllowed) - continue; - if (needComma) - sqlStmt += wxT(","); - sqlStmt += pDb->SQLColumnName(colDefs[i].ColName); - needComma = true; - } - needComma = false; - sqlStmt += wxT(") VALUES ("); - - int insertableCount = 0; - - for (i = 0; i < m_numCols; i++) - { - if (! colDefs[i].InsertAllowed) - continue; - if (needComma) - sqlStmt += wxT(","); - sqlStmt += wxT("?"); - needComma = true; - insertableCount++; - } - sqlStmt += wxT(")"); - - // Prepare the insert statement for execution - if (insertableCount) - { - if (SQLPrepare(hstmtInsert, (SQLTCHAR FAR *) sqlStmt.c_str(), SQL_NTS) != SQL_SUCCESS) - return(pDb->DispAllErrors(henv, hdbc, hstmtInsert)); - } - else - insertable = false; - } - - // Completed successfully - return true; - -} // wxDbTable::Open() - - -/********** wxDbTable::Query() **********/ -bool wxDbTable::Query(bool forUpdate, bool distinct) -{ - - return(query(DB_SELECT_WHERE, forUpdate, distinct)); - -} // wxDbTable::Query() - - -/********** wxDbTable::QueryBySqlStmt() **********/ -bool wxDbTable::QueryBySqlStmt(const wxString &pSqlStmt) -{ - pDb->WriteSqlLog(pSqlStmt); - - return(query(DB_SELECT_STATEMENT, false, false, pSqlStmt)); - -} // wxDbTable::QueryBySqlStmt() - - -/********** wxDbTable::QueryMatching() **********/ -bool wxDbTable::QueryMatching(bool forUpdate, bool distinct) -{ - - return(query(DB_SELECT_MATCHING, forUpdate, distinct)); - -} // wxDbTable::QueryMatching() - - -/********** wxDbTable::QueryOnKeyFields() **********/ -bool wxDbTable::QueryOnKeyFields(bool forUpdate, bool distinct) -{ - - return(query(DB_SELECT_KEYFIELDS, forUpdate, distinct)); - -} // wxDbTable::QueryOnKeyFields() - - -/********** wxDbTable::GetPrev() **********/ -bool wxDbTable::GetPrev(void) -{ - if (pDb->FwdOnlyCursors()) - { - wxFAIL_MSG(wxT("GetPrev()::Backward scrolling cursors are not enabled for this instance of wxDbTable")); - return false; - } - else - return(getRec(SQL_FETCH_PRIOR)); - -} // wxDbTable::GetPrev() - - -/********** wxDbTable::operator-- **********/ -bool wxDbTable::operator--(int) -{ - if (pDb->FwdOnlyCursors()) - { - wxFAIL_MSG(wxT("operator--:Backward scrolling cursors are not enabled for this instance of wxDbTable")); - return false; - } - else - return(getRec(SQL_FETCH_PRIOR)); - -} // wxDbTable::operator-- - - -/********** wxDbTable::GetFirst() **********/ -bool wxDbTable::GetFirst(void) -{ - if (pDb->FwdOnlyCursors()) - { - wxFAIL_MSG(wxT("GetFirst():Backward scrolling cursors are not enabled for this instance of wxDbTable")); - return false; - } - else - return(getRec(SQL_FETCH_FIRST)); - -} // wxDbTable::GetFirst() - - -/********** wxDbTable::GetLast() **********/ -bool wxDbTable::GetLast(void) -{ - if (pDb->FwdOnlyCursors()) - { - wxFAIL_MSG(wxT("GetLast()::Backward scrolling cursors are not enabled for this instance of wxDbTable")); - return false; - } - else - return(getRec(SQL_FETCH_LAST)); - -} // wxDbTable::GetLast() - - -/********** wxDbTable::BuildDeleteStmt() **********/ -void wxDbTable::BuildDeleteStmt(wxString &pSqlStmt, int typeOfDel, const wxString &pWhereClause) -{ - wxASSERT(!queryOnly); - if (queryOnly) - return; - - wxString whereClause; - - whereClause.Empty(); - - // Handle the case of DeleteWhere() and the where clause is blank. It should - // delete all records from the database in this case. - if (typeOfDel == DB_DEL_WHERE && (pWhereClause.length() == 0)) - { - pSqlStmt.Printf(wxT("DELETE FROM %s"), - pDb->SQLTableName(tableName.c_str()).c_str()); - return; - } - - pSqlStmt.Printf(wxT("DELETE FROM %s WHERE "), - pDb->SQLTableName(tableName.c_str()).c_str()); - - // Append the WHERE clause to the SQL DELETE statement - switch(typeOfDel) - { - case DB_DEL_KEYFIELDS: - // If the datasource supports the ROWID column, build - // the where on ROWID for efficiency purposes. - // e.g. DELETE FROM PARTS WHERE ROWID = '111.222.333' - if (CanUpdateByROWID()) - { - SQLLEN cb; - wxChar rowid[wxDB_ROWID_LEN+1]; - - // Get the ROWID value. If not successful retreiving the ROWID, - // simply fall down through the code and build the WHERE clause - // based on the key fields. - if (SQLGetData(hstmt, (UWORD)(m_numCols+1), SQL_C_WXCHAR, (UCHAR*) rowid, sizeof(rowid), &cb) == SQL_SUCCESS) - { - pSqlStmt += wxT("ROWID = '"); - pSqlStmt += rowid; - pSqlStmt += wxT("'"); - break; - } - } - // Unable to delete by ROWID, so build a WHERE - // clause based on the keyfields. - BuildWhereClause(whereClause, DB_WHERE_KEYFIELDS); - pSqlStmt += whereClause; - break; - case DB_DEL_WHERE: - pSqlStmt += pWhereClause; - break; - case DB_DEL_MATCHING: - BuildWhereClause(whereClause, DB_WHERE_MATCHING); - pSqlStmt += whereClause; - break; - } - -} // BuildDeleteStmt() - - -/***** DEPRECATED: use wxDbTable::BuildDeleteStmt(wxString &....) form *****/ -void wxDbTable::BuildDeleteStmt(wxChar *pSqlStmt, int typeOfDel, const wxString &pWhereClause) -{ - wxString tempSqlStmt; - BuildDeleteStmt(tempSqlStmt, typeOfDel, pWhereClause); - wxStrcpy(pSqlStmt, tempSqlStmt); -} // wxDbTable::BuildDeleteStmt() - - -/********** wxDbTable::BuildSelectStmt() **********/ -void wxDbTable::BuildSelectStmt(wxString &pSqlStmt, int typeOfSelect, bool distinct) -{ - wxString whereClause; - whereClause.Empty(); - - // Build a select statement to query the database - pSqlStmt = wxT("SELECT "); - - // SELECT DISTINCT values only? - if (distinct) - pSqlStmt += wxT("DISTINCT "); - - // Was a FROM clause specified to join tables to the base table? - // Available for ::Query() only!!! - bool appendFromClause = false; -#if wxODBC_BACKWARD_COMPATABILITY - if (typeOfSelect == DB_SELECT_WHERE && from && wxStrlen(from)) - appendFromClause = true; -#else - if (typeOfSelect == DB_SELECT_WHERE && from.length()) - appendFromClause = true; -#endif - - // Add the column list - int i; - wxString tStr; - for (i = 0; i < m_numCols; i++) - { - tStr = colDefs[i].ColName; - // If joining tables, the base table column names must be qualified to avoid ambiguity - if ((appendFromClause || pDb->Dbms() == dbmsACCESS) && tStr.Find(wxT('.')) == wxNOT_FOUND) - { - pSqlStmt += pDb->SQLTableName(queryTableName.c_str()); - pSqlStmt += wxT("."); - } - pSqlStmt += pDb->SQLColumnName(colDefs[i].ColName); - if (i + 1 < m_numCols) - pSqlStmt += wxT(","); - } - - // If the datasource supports ROWID, get this column as well. Exception: Don't retrieve - // the ROWID if querying distinct records. The rowid will always be unique. - if (!distinct && CanUpdateByROWID()) - { - // If joining tables, the base table column names must be qualified to avoid ambiguity - if (appendFromClause || pDb->Dbms() == dbmsACCESS) - { - pSqlStmt += wxT(","); - pSqlStmt += pDb->SQLTableName(queryTableName); - pSqlStmt += wxT(".ROWID"); - } - else - pSqlStmt += wxT(",ROWID"); - } - - // Append the FROM tablename portion - pSqlStmt += wxT(" FROM "); - pSqlStmt += pDb->SQLTableName(queryTableName); -// pSqlStmt += queryTableName; - - // Sybase uses the HOLDLOCK keyword to lock a record during query. - // The HOLDLOCK keyword follows the table name in the from clause. - // Each table in the from clause must specify HOLDLOCK or - // NOHOLDLOCK (the default). Note: The "FOR UPDATE" clause - // is parsed but ignored in SYBASE Transact-SQL. - if (selectForUpdate && (pDb->Dbms() == dbmsSYBASE_ASA || pDb->Dbms() == dbmsSYBASE_ASE)) - pSqlStmt += wxT(" HOLDLOCK"); - - if (appendFromClause) - pSqlStmt += from; - - // Append the WHERE clause. Either append the where clause for the class - // or build a where clause. The typeOfSelect determines this. - switch(typeOfSelect) - { - case DB_SELECT_WHERE: -#if wxODBC_BACKWARD_COMPATABILITY - if (where && wxStrlen(where)) // May not want a where clause!!! -#else - if (where.length()) // May not want a where clause!!! -#endif - { - pSqlStmt += wxT(" WHERE "); - pSqlStmt += where; - } - break; - case DB_SELECT_KEYFIELDS: - BuildWhereClause(whereClause, DB_WHERE_KEYFIELDS); - if (whereClause.length()) - { - pSqlStmt += wxT(" WHERE "); - pSqlStmt += whereClause; - } - break; - case DB_SELECT_MATCHING: - BuildWhereClause(whereClause, DB_WHERE_MATCHING); - if (whereClause.length()) - { - pSqlStmt += wxT(" WHERE "); - pSqlStmt += whereClause; - } - break; - } - - // Append the ORDER BY clause -#if wxODBC_BACKWARD_COMPATABILITY - if (orderBy && wxStrlen(orderBy)) -#else - if (orderBy.length()) -#endif - { - pSqlStmt += wxT(" ORDER BY "); - pSqlStmt += orderBy; - } - - // SELECT FOR UPDATE if told to do so and the datasource is capable. Sybase - // parses the FOR UPDATE clause but ignores it. See the comment above on the - // HOLDLOCK for Sybase. - if (selectForUpdate && CanSelectForUpdate()) - pSqlStmt += wxT(" FOR UPDATE"); - -} // wxDbTable::BuildSelectStmt() - - -/***** DEPRECATED: use wxDbTable::BuildSelectStmt(wxString &....) form *****/ -void wxDbTable::BuildSelectStmt(wxChar *pSqlStmt, int typeOfSelect, bool distinct) -{ - wxString tempSqlStmt; - BuildSelectStmt(tempSqlStmt, typeOfSelect, distinct); - wxStrcpy(pSqlStmt, tempSqlStmt); -} // wxDbTable::BuildSelectStmt() - - -/********** wxDbTable::BuildUpdateStmt() **********/ -void wxDbTable::BuildUpdateStmt(wxString &pSqlStmt, int typeOfUpdate, const wxString &pWhereClause) -{ - wxASSERT(!queryOnly); - if (queryOnly) - return; - - wxString whereClause; - whereClause.Empty(); - - bool firstColumn = true; - - pSqlStmt.Printf(wxT("UPDATE %s SET "), - pDb->SQLTableName(tableName.c_str()).c_str()); - - // Append a list of columns to be updated - int i; - for (i = 0; i < m_numCols; i++) - { - // Only append Updateable columns - if (colDefs[i].Updateable) - { - if (!firstColumn) - pSqlStmt += wxT(","); - else - firstColumn = false; - - pSqlStmt += pDb->SQLColumnName(colDefs[i].ColName); -// pSqlStmt += colDefs[i].ColName; - pSqlStmt += wxT(" = ?"); - } - } - - // Append the WHERE clause to the SQL UPDATE statement - pSqlStmt += wxT(" WHERE "); - switch(typeOfUpdate) - { - case DB_UPD_KEYFIELDS: - // If the datasource supports the ROWID column, build - // the where on ROWID for efficiency purposes. - // e.g. UPDATE PARTS SET Col1 = ?, Col2 = ? WHERE ROWID = '111.222.333' - if (CanUpdateByROWID()) - { - SQLLEN cb; - wxChar rowid[wxDB_ROWID_LEN+1]; - - // Get the ROWID value. If not successful retreiving the ROWID, - // simply fall down through the code and build the WHERE clause - // based on the key fields. - if (SQLGetData(hstmt, (UWORD)(m_numCols+1), SQL_C_WXCHAR, (UCHAR*) rowid, sizeof(rowid), &cb) == SQL_SUCCESS) - { - pSqlStmt += wxT("ROWID = '"); - pSqlStmt += rowid; - pSqlStmt += wxT("'"); - break; - } - } - // Unable to delete by ROWID, so build a WHERE - // clause based on the keyfields. - BuildWhereClause(whereClause, DB_WHERE_KEYFIELDS); - pSqlStmt += whereClause; - break; - case DB_UPD_WHERE: - pSqlStmt += pWhereClause; - break; - } -} // BuildUpdateStmt() - - -/***** DEPRECATED: use wxDbTable::BuildUpdateStmt(wxString &....) form *****/ -void wxDbTable::BuildUpdateStmt(wxChar *pSqlStmt, int typeOfUpdate, const wxString &pWhereClause) -{ - wxString tempSqlStmt; - BuildUpdateStmt(tempSqlStmt, typeOfUpdate, pWhereClause); - wxStrcpy(pSqlStmt, tempSqlStmt); -} // BuildUpdateStmt() - - -/********** wxDbTable::BuildWhereClause() **********/ -void wxDbTable::BuildWhereClause(wxString &pWhereClause, int typeOfWhere, - const wxString &qualTableName, bool useLikeComparison) -/* - * Note: BuildWhereClause() currently ignores timestamp columns. - * They are not included as part of the where clause. - */ -{ - bool moreThanOneColumn = false; - wxString colValue; - - // Loop through the columns building a where clause as you go - int colNumber; - for (colNumber = 0; colNumber < m_numCols; colNumber++) - { - // Determine if this column should be included in the WHERE clause - if ((typeOfWhere == DB_WHERE_KEYFIELDS && colDefs[colNumber].KeyField) || - (typeOfWhere == DB_WHERE_MATCHING && (!IsColNull((UWORD)colNumber)))) - { - // Skip over timestamp columns - if (colDefs[colNumber].SqlCtype == SQL_C_TIMESTAMP) - continue; - // If there is more than 1 column, join them with the keyword "AND" - if (moreThanOneColumn) - pWhereClause += wxT(" AND "); - else - moreThanOneColumn = true; - - // Concatenate where phrase for the column - wxString tStr = colDefs[colNumber].ColName; - - if (qualTableName.length() && tStr.Find(wxT('.')) == wxNOT_FOUND) - { - pWhereClause += pDb->SQLTableName(qualTableName); - pWhereClause += wxT("."); - } - pWhereClause += pDb->SQLColumnName(colDefs[colNumber].ColName); - - if (useLikeComparison && (colDefs[colNumber].SqlCtype == SQL_C_WXCHAR)) - pWhereClause += wxT(" LIKE "); - else - pWhereClause += wxT(" = "); - - switch(colDefs[colNumber].SqlCtype) - { - case SQL_C_CHAR: -#ifdef SQL_C_WCHAR - case SQL_C_WCHAR: -#endif - //case SQL_C_WXCHAR: SQL_C_WXCHAR is covered by either SQL_C_CHAR or SQL_C_WCHAR - colValue.Printf(wxT("'%s'"), GetDb()->EscapeSqlChars((wxChar *)colDefs[colNumber].PtrDataObj).c_str()); - break; - case SQL_C_SHORT: - case SQL_C_SSHORT: - colValue.Printf(wxT("%hi"), *((SWORD *) colDefs[colNumber].PtrDataObj)); - break; - case SQL_C_USHORT: - colValue.Printf(wxT("%hu"), *((UWORD *) colDefs[colNumber].PtrDataObj)); - break; - case SQL_C_LONG: - case SQL_C_SLONG: - colValue.Printf(wxT("%li"), *((SDWORD *) colDefs[colNumber].PtrDataObj)); - break; - case SQL_C_ULONG: - colValue.Printf(wxT("%lu"), *((UDWORD *) colDefs[colNumber].PtrDataObj)); - break; - case SQL_C_FLOAT: - colValue.Printf(wxT("%.6f"), *((SFLOAT *) colDefs[colNumber].PtrDataObj)); - break; - case SQL_C_DOUBLE: - colValue.Printf(wxT("%.6f"), *((SDOUBLE *) colDefs[colNumber].PtrDataObj)); - break; - default: - { - wxString strMsg; - strMsg.Printf(wxT("wxDbTable::bindParams(): Unknown column type for colDefs %d colName %s"), - colNumber,colDefs[colNumber].ColName); - wxFAIL_MSG(strMsg.c_str()); - } - break; - } - pWhereClause += colValue; - } - } -} // wxDbTable::BuildWhereClause() - - -/***** DEPRECATED: use wxDbTable::BuildWhereClause(wxString &....) form *****/ -void wxDbTable::BuildWhereClause(wxChar *pWhereClause, int typeOfWhere, - const wxString &qualTableName, bool useLikeComparison) -{ - wxString tempSqlStmt; - BuildWhereClause(tempSqlStmt, typeOfWhere, qualTableName, useLikeComparison); - wxStrcpy(pWhereClause, tempSqlStmt); -} // wxDbTable::BuildWhereClause() - - -/********** wxDbTable::GetRowNum() **********/ -UWORD wxDbTable::GetRowNum(void) -{ - UDWORD rowNum; - - if (SQLGetStmtOption(hstmt, SQL_ROW_NUMBER, (UCHAR*) &rowNum) != SQL_SUCCESS) - { - pDb->DispAllErrors(henv, hdbc, hstmt); - return(0); - } - - // Completed successfully - return((UWORD) rowNum); - -} // wxDbTable::GetRowNum() - - -/********** wxDbTable::CloseCursor() **********/ -bool wxDbTable::CloseCursor(HSTMT cursor) -{ - if (SQLFreeStmt(cursor, SQL_CLOSE) != SQL_SUCCESS) - return(pDb->DispAllErrors(henv, hdbc, cursor)); - - // Completed successfully - return true; - -} // wxDbTable::CloseCursor() - - -/********** wxDbTable::CreateTable() **********/ -bool wxDbTable::CreateTable(bool attemptDrop) -{ - if (!pDb) - return false; - - int i, j; - wxString sqlStmt; - -#ifdef DBDEBUG_CONSOLE - cout << wxT("Creating Table ") << tableName << wxT("...") << endl; -#endif - - // Drop table first - if (attemptDrop && !DropTable()) - return false; - - // Create the table -#ifdef DBDEBUG_CONSOLE - for (i = 0; i < m_numCols; i++) - { - // Exclude derived columns since they are NOT part of the base table - if (colDefs[i].DerivedCol) - continue; - cout << i + 1 << wxT(": ") << colDefs[i].ColName << wxT("; "); - switch(colDefs[i].DbDataType) - { - case DB_DATA_TYPE_VARCHAR: - cout << pDb->GetTypeInfVarchar().TypeName << wxT("(") << (int)(colDefs[i].SzDataObj / sizeof(wxChar)) << wxT(")"); - break; - case DB_DATA_TYPE_MEMO: - cout << pDb->GetTypeInfMemo().TypeName; - break; - case DB_DATA_TYPE_INTEGER: - cout << pDb->GetTypeInfInteger().TypeName; - break; - case DB_DATA_TYPE_FLOAT: - cout << pDb->GetTypeInfFloat().TypeName; - break; - case DB_DATA_TYPE_DATE: - cout << pDb->GetTypeInfDate().TypeName; - break; - case DB_DATA_TYPE_BLOB: - cout << pDb->GetTypeInfBlob().TypeName; - break; - } - cout << endl; - } -#endif - - // Build a CREATE TABLE string from the colDefs structure. - bool needComma = false; - - sqlStmt.Printf(wxT("CREATE TABLE %s ("), - pDb->SQLTableName(tableName.c_str()).c_str()); - - for (i = 0; i < m_numCols; i++) - { - // Exclude derived columns since they are NOT part of the base table - if (colDefs[i].DerivedCol) - continue; - // Comma Delimiter - if (needComma) - sqlStmt += wxT(","); - // Column Name - sqlStmt += pDb->SQLColumnName(colDefs[i].ColName); -// sqlStmt += colDefs[i].ColName; - sqlStmt += wxT(" "); - // Column Type - switch(colDefs[i].DbDataType) - { - case DB_DATA_TYPE_VARCHAR: - sqlStmt += pDb->GetTypeInfVarchar().TypeName; - break; - case DB_DATA_TYPE_MEMO: - sqlStmt += pDb->GetTypeInfMemo().TypeName; - break; - case DB_DATA_TYPE_INTEGER: - sqlStmt += pDb->GetTypeInfInteger().TypeName; - break; - case DB_DATA_TYPE_FLOAT: - sqlStmt += pDb->GetTypeInfFloat().TypeName; - break; - case DB_DATA_TYPE_DATE: - sqlStmt += pDb->GetTypeInfDate().TypeName; - break; - case DB_DATA_TYPE_BLOB: - sqlStmt += pDb->GetTypeInfBlob().TypeName; - break; - } - // For varchars, append the size of the string - if (colDefs[i].DbDataType == DB_DATA_TYPE_VARCHAR && - (pDb->Dbms() != dbmsMY_SQL || pDb->GetTypeInfVarchar().TypeName != _T("text")))// || -// colDefs[i].DbDataType == DB_DATA_TYPE_BLOB) - { - wxString s; - s.Printf(wxT("(%d)"), (int)(colDefs[i].SzDataObj / sizeof(wxChar))); - sqlStmt += s; - } - - if (pDb->Dbms() == dbmsDB2 || - pDb->Dbms() == dbmsMY_SQL || - pDb->Dbms() == dbmsSYBASE_ASE || - pDb->Dbms() == dbmsINTERBASE || - pDb->Dbms() == dbmsFIREBIRD || - pDb->Dbms() == dbmsMS_SQL_SERVER) - { - if (colDefs[i].KeyField) - { - sqlStmt += wxT(" NOT NULL"); - } - } - - needComma = true; - } - // If there is a primary key defined, include it in the create statement - for (i = j = 0; i < m_numCols; i++) - { - if (colDefs[i].KeyField) - { - j++; - break; - } - } - if ( j && (pDb->Dbms() != dbmsDBASE) - && (pDb->Dbms() != dbmsXBASE_SEQUITER) ) // Found a keyfield - { - switch (pDb->Dbms()) - { - case dbmsACCESS: - case dbmsINFORMIX: - case dbmsSYBASE_ASA: - case dbmsSYBASE_ASE: - case dbmsMY_SQL: - case dbmsFIREBIRD: - { - // MySQL goes out on this one. We also declare the relevant key NON NULL above - sqlStmt += wxT(",PRIMARY KEY ("); - break; - } - default: - { - sqlStmt += wxT(",CONSTRAINT "); - // DB2 is limited to 18 characters for index names - if (pDb->Dbms() == dbmsDB2) - { - wxASSERT_MSG((tableName && wxStrlen(tableName) <= 13), wxT("DB2 table/index names must be no longer than 13 characters in length.\n\nTruncating table name to 13 characters.")); - sqlStmt += pDb->SQLTableName(tableName.substr(0, 13).c_str()); -// sqlStmt += tableName.substr(0, 13); - } - else - sqlStmt += pDb->SQLTableName(tableName.c_str()); -// sqlStmt += tableName; - - sqlStmt += wxT("_PIDX PRIMARY KEY ("); - break; - } - } - - // List column name(s) of column(s) comprising the primary key - for (i = j = 0; i < m_numCols; i++) - { - if (colDefs[i].KeyField) - { - if (j++) // Multi part key, comma separate names - sqlStmt += wxT(","); - sqlStmt += pDb->SQLColumnName(colDefs[i].ColName); - - if (pDb->Dbms() == dbmsMY_SQL && - colDefs[i].DbDataType == DB_DATA_TYPE_VARCHAR) - { - wxString s; - s.Printf(wxT("(%d)"), (int)(colDefs[i].SzDataObj / sizeof(wxChar))); - sqlStmt += s; - } - } - } - sqlStmt += wxT(")"); - - if (pDb->Dbms() == dbmsINFORMIX || - pDb->Dbms() == dbmsSYBASE_ASA || - pDb->Dbms() == dbmsSYBASE_ASE) - { - sqlStmt += wxT(" CONSTRAINT "); - sqlStmt += pDb->SQLTableName(tableName); -// sqlStmt += tableName; - sqlStmt += wxT("_PIDX"); - } - } - // Append the closing parentheses for the create table statement - sqlStmt += wxT(")"); - - pDb->WriteSqlLog(sqlStmt); - -#ifdef DBDEBUG_CONSOLE - cout << endl << sqlStmt.c_str() << endl; -#endif - - // Execute the CREATE TABLE statement - RETCODE retcode = SQLExecDirect(hstmt, (SQLTCHAR FAR *) sqlStmt.c_str(), SQL_NTS); - if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO) - { - pDb->DispAllErrors(henv, hdbc, hstmt); - pDb->RollbackTrans(); - CloseCursor(hstmt); - return false; - } - - // Commit the transaction and close the cursor - if (!pDb->CommitTrans()) - return false; - if (!CloseCursor(hstmt)) - return false; - - // Database table created successfully - return true; - -} // wxDbTable::CreateTable() - - -/********** wxDbTable::DropTable() **********/ -bool wxDbTable::DropTable() -{ - // NOTE: This function returns true if the Table does not exist, but - // only for identified databases. Code will need to be added - // below for any other databases when those databases are defined - // to handle this situation consistently - - wxString sqlStmt; - - sqlStmt.Printf(wxT("DROP TABLE %s"), - pDb->SQLTableName(tableName.c_str()).c_str()); - - pDb->WriteSqlLog(sqlStmt); - -#ifdef DBDEBUG_CONSOLE - cout << endl << sqlStmt.c_str() << endl; -#endif - - RETCODE retcode = SQLExecDirect(hstmt, (SQLTCHAR FAR *) sqlStmt.c_str(), SQL_NTS); - if (retcode != SQL_SUCCESS) - { - // Check for "Base table not found" error and ignore - pDb->GetNextError(henv, hdbc, hstmt); - if (wxStrcmp(pDb->sqlState, wxT("S0002")) /*&& - wxStrcmp(pDb->sqlState, wxT("S1000"))*/) // "Base table not found" - { - // Check for product specific error codes - if (!((pDb->Dbms() == dbmsSYBASE_ASA && !wxStrcmp(pDb->sqlState,wxT("42000"))) || // 5.x (and lower?) - (pDb->Dbms() == dbmsSYBASE_ASE && !wxStrcmp(pDb->sqlState,wxT("37000"))) || - (pDb->Dbms() == dbmsPERVASIVE_SQL && !wxStrcmp(pDb->sqlState,wxT("S1000"))) || // Returns an S1000 then an S0002 - (pDb->Dbms() == dbmsPOSTGRES && !wxStrcmp(pDb->sqlState,wxT("08S01"))))) - { - pDb->DispNextError(); - pDb->DispAllErrors(henv, hdbc, hstmt); - pDb->RollbackTrans(); -// CloseCursor(hstmt); - return false; - } - } - } - - // Commit the transaction and close the cursor - if (! pDb->CommitTrans()) - return false; - if (! CloseCursor(hstmt)) - return false; - - return true; -} // wxDbTable::DropTable() - - -/********** wxDbTable::CreateIndex() **********/ -bool wxDbTable::CreateIndex(const wxString &indexName, bool unique, UWORD numIndexColumns, - wxDbIdxDef *pIndexDefs, bool attemptDrop) -{ - wxString sqlStmt; - - // Drop the index first - if (attemptDrop && !DropIndex(indexName)) - return false; - - // MySQL (and possibly Sybase ASE?? - gt) require that any columns which are used as portions - // of an index have the columns defined as "NOT NULL". During initial table creation though, - // it may not be known which columns are necessarily going to be part of an index (e.g. the - // table was created, then months later you determine that an additional index while - // give better performance, so you want to add an index). - // - // The following block of code will modify the column definition to make the column be - // defined with the "NOT NULL" qualifier. - if (pDb->Dbms() == dbmsMY_SQL) - { - wxString sqlStmt; - int i; - bool ok = true; - for (i = 0; i < numIndexColumns && ok; i++) - { - int j = 0; - bool found = false; - // Find the column definition that has the ColName that matches the - // index column name. We need to do this to get the DB_DATA_TYPE of - // the index column, as MySQL's syntax for the ALTER column requires - // this information - while (!found && (j < this->m_numCols)) - { - if (wxStrcmp(colDefs[j].ColName,pIndexDefs[i].ColName) == 0) - found = true; - if (!found) - j++; - } - - if (found) - { - ok = pDb->ModifyColumn(tableName, pIndexDefs[i].ColName, - colDefs[j].DbDataType, (int)(colDefs[j].SzDataObj / sizeof(wxChar)), - wxT("NOT NULL")); - - if (!ok) - { - #if 0 - // retcode is not used - wxODBC_ERRORS retcode; - // Oracle returns a DB_ERR_GENERAL_ERROR if the column is already - // defined to be NOT NULL, but reportedly MySQL doesn't mind. - // This line is just here for debug checking of the value - retcode = (wxODBC_ERRORS)pDb->DB_STATUS; - #endif - } - } - else - ok = false; - } - if (ok) - pDb->CommitTrans(); - else - { - pDb->RollbackTrans(); - return false; - } - } - - // Build a CREATE INDEX statement - sqlStmt = wxT("CREATE "); - if (unique) - sqlStmt += wxT("UNIQUE "); - - sqlStmt += wxT("INDEX "); - sqlStmt += pDb->SQLTableName(indexName); - sqlStmt += wxT(" ON "); - - sqlStmt += pDb->SQLTableName(tableName); -// sqlStmt += tableName; - sqlStmt += wxT(" ("); - - // Append list of columns making up index - int i; - for (i = 0; i < numIndexColumns; i++) - { - sqlStmt += pDb->SQLColumnName(pIndexDefs[i].ColName); -// sqlStmt += pIndexDefs[i].ColName; - - // MySQL requires a key length on VARCHAR keys - if ( pDb->Dbms() == dbmsMY_SQL ) - { - // Find the details on this column - int j; - for ( j = 0; j < m_numCols; ++j ) - { - if ( wxStrcmp( pIndexDefs[i].ColName, colDefs[j].ColName ) == 0 ) - { - break; - } - } - if ( colDefs[j].DbDataType == DB_DATA_TYPE_VARCHAR) - { - wxString s; - s.Printf(wxT("(%d)"), (int)(colDefs[i].SzDataObj / sizeof(wxChar))); - sqlStmt += s; - } - } - - // Postgres and SQL Server 7 do not support the ASC/DESC keywords for index columns - if (!((pDb->Dbms() == dbmsMS_SQL_SERVER) && (wxStrncmp(pDb->dbInf.dbmsVer,_T("07"),2)==0)) && - !(pDb->Dbms() == dbmsFIREBIRD) && - !(pDb->Dbms() == dbmsPOSTGRES)) - { - if (pIndexDefs[i].Ascending) - sqlStmt += wxT(" ASC"); - else - sqlStmt += wxT(" DESC"); - } - else - wxASSERT_MSG(pIndexDefs[i].Ascending, _T("Datasource does not support DESCending index columns")); - - if ((i + 1) < numIndexColumns) - sqlStmt += wxT(","); - } - - // Append closing parentheses - sqlStmt += wxT(")"); - - pDb->WriteSqlLog(sqlStmt); - -#ifdef DBDEBUG_CONSOLE - cout << endl << sqlStmt.c_str() << endl << endl; -#endif - - // Execute the CREATE INDEX statement - RETCODE retcode = SQLExecDirect(hstmt, (SQLTCHAR FAR *) sqlStmt.c_str(), SQL_NTS); - if (retcode != SQL_SUCCESS) - { - pDb->DispAllErrors(henv, hdbc, hstmt); - pDb->RollbackTrans(); - CloseCursor(hstmt); - return false; - } - - // Commit the transaction and close the cursor - if (! pDb->CommitTrans()) - return false; - if (! CloseCursor(hstmt)) - return false; - - // Index Created Successfully - return true; - -} // wxDbTable::CreateIndex() - - -/********** wxDbTable::DropIndex() **********/ -bool wxDbTable::DropIndex(const wxString &indexName) -{ - // NOTE: This function returns true if the Index does not exist, but - // only for identified databases. Code will need to be added - // below for any other databases when those databases are defined - // to handle this situation consistently - - wxString sqlStmt; - - if (pDb->Dbms() == dbmsACCESS || pDb->Dbms() == dbmsMY_SQL || - pDb->Dbms() == dbmsDBASE /*|| Paradox needs this syntax too when we add support*/) - sqlStmt.Printf(wxT("DROP INDEX %s ON %s"), - pDb->SQLTableName(indexName.c_str()).c_str(), - pDb->SQLTableName(tableName.c_str()).c_str()); - else if ((pDb->Dbms() == dbmsMS_SQL_SERVER) || - (pDb->Dbms() == dbmsSYBASE_ASE) || - (pDb->Dbms() == dbmsXBASE_SEQUITER)) - sqlStmt.Printf(wxT("DROP INDEX %s.%s"), - pDb->SQLTableName(tableName.c_str()).c_str(), - pDb->SQLTableName(indexName.c_str()).c_str()); - else - sqlStmt.Printf(wxT("DROP INDEX %s"), - pDb->SQLTableName(indexName.c_str()).c_str()); - - pDb->WriteSqlLog(sqlStmt); - -#ifdef DBDEBUG_CONSOLE - cout << endl << sqlStmt.c_str() << endl; -#endif - RETCODE retcode = SQLExecDirect(hstmt, (SQLTCHAR FAR *) sqlStmt.c_str(), SQL_NTS); - if (retcode != SQL_SUCCESS) - { - // Check for "Index not found" error and ignore - pDb->GetNextError(henv, hdbc, hstmt); - if (wxStrcmp(pDb->sqlState,wxT("S0012"))) // "Index not found" - { - // Check for product specific error codes - if (!((pDb->Dbms() == dbmsSYBASE_ASA && !wxStrcmp(pDb->sqlState,wxT("42000"))) || // v5.x (and lower?) - (pDb->Dbms() == dbmsSYBASE_ASE && !wxStrcmp(pDb->sqlState,wxT("37000"))) || - (pDb->Dbms() == dbmsMS_SQL_SERVER && !wxStrcmp(pDb->sqlState,wxT("S1000"))) || - (pDb->Dbms() == dbmsINTERBASE && !wxStrcmp(pDb->sqlState,wxT("S1000"))) || - (pDb->Dbms() == dbmsMAXDB && !wxStrcmp(pDb->sqlState,wxT("S1000"))) || - (pDb->Dbms() == dbmsFIREBIRD && !wxStrcmp(pDb->sqlState,wxT("HY000"))) || - (pDb->Dbms() == dbmsSYBASE_ASE && !wxStrcmp(pDb->sqlState,wxT("S0002"))) || // Base table not found - (pDb->Dbms() == dbmsMY_SQL && !wxStrcmp(pDb->sqlState,wxT("42S12"))) || // tested by Christopher Ludwik Marino-Cebulski using v3.23.21beta - (pDb->Dbms() == dbmsPOSTGRES && !wxStrcmp(pDb->sqlState,wxT("08S01"))) - )) - { - pDb->DispNextError(); - pDb->DispAllErrors(henv, hdbc, hstmt); - pDb->RollbackTrans(); - CloseCursor(hstmt); - return false; - } - } - } - - // Commit the transaction and close the cursor - if (! pDb->CommitTrans()) - return false; - if (! CloseCursor(hstmt)) - return false; - - return true; -} // wxDbTable::DropIndex() - - -/********** wxDbTable::SetOrderByColNums() **********/ -bool wxDbTable::SetOrderByColNums(UWORD first, ... ) -{ - int colNumber = first; // using 'int' to be able to look for wxDB_NO_MORE_COLUN_NUMBERS - va_list argptr; - - bool abort = false; - wxString tempStr; - - va_start(argptr, first); /* Initialize variable arguments. */ - while (!abort && (colNumber != wxDB_NO_MORE_COLUMN_NUMBERS)) - { - // Make sure the passed in column number - // is within the valid range of columns - // - // Valid columns are 0 thru m_numCols-1 - if (colNumber >= m_numCols || colNumber < 0) - { - abort = true; - continue; - } - - if (colNumber != first) - tempStr += wxT(","); - - tempStr += colDefs[colNumber].ColName; - colNumber = va_arg (argptr, int); - } - va_end (argptr); /* Reset variable arguments. */ - - SetOrderByClause(tempStr); - - return (!abort); -} // wxDbTable::SetOrderByColNums() - - -/********** wxDbTable::Insert() **********/ -int wxDbTable::Insert(void) -{ - wxASSERT(!queryOnly); - if (queryOnly || !insertable) - return(DB_FAILURE); - - bindInsertParams(); - - // Insert the record by executing the already prepared insert statement - RETCODE retcode; - retcode = SQLExecute(hstmtInsert); - if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO && - retcode != SQL_NEED_DATA) - { - // Check to see if integrity constraint was violated - pDb->GetNextError(henv, hdbc, hstmtInsert); - if (! wxStrcmp(pDb->sqlState, wxT("23000"))) // Integrity constraint violated - return(DB_ERR_INTEGRITY_CONSTRAINT_VIOL); - else - { - pDb->DispNextError(); - pDb->DispAllErrors(henv, hdbc, hstmtInsert); - return(DB_FAILURE); - } - } - if (retcode == SQL_NEED_DATA) - { - PTR pParmID; - retcode = SQLParamData(hstmtInsert, &pParmID); - while (retcode == SQL_NEED_DATA) - { - // Find the parameter - int i; - for (i=0; i < m_numCols; i++) - { - if (colDefs[i].PtrDataObj == pParmID) - { - // We found it. Store the parameter. - retcode = SQLPutData(hstmtInsert, pParmID, colDefs[i].SzDataObj); - if (retcode != SQL_SUCCESS) - { - pDb->DispNextError(); - pDb->DispAllErrors(henv, hdbc, hstmtInsert); - return(DB_FAILURE); - } - break; - } - } - retcode = SQLParamData(hstmtInsert, &pParmID); - if (retcode != SQL_SUCCESS && - retcode != SQL_SUCCESS_WITH_INFO) - { - // record was not inserted - pDb->DispNextError(); - pDb->DispAllErrors(henv, hdbc, hstmtInsert); - return(DB_FAILURE); - } - } - } - - // Record inserted into the datasource successfully - return(DB_SUCCESS); - -} // wxDbTable::Insert() - - -/********** wxDbTable::Update() **********/ -bool wxDbTable::Update(void) -{ - wxASSERT(!queryOnly); - if (queryOnly) - return false; - - wxString sqlStmt; - - // Build the SQL UPDATE statement - BuildUpdateStmt(sqlStmt, DB_UPD_KEYFIELDS); - - pDb->WriteSqlLog(sqlStmt); - -#ifdef DBDEBUG_CONSOLE - cout << endl << sqlStmt.c_str() << endl << endl; -#endif - - // Execute the SQL UPDATE statement - return(execUpdate(sqlStmt)); - -} // wxDbTable::Update() - - -/********** wxDbTable::Update(pSqlStmt) **********/ -bool wxDbTable::Update(const wxString &pSqlStmt) -{ - wxASSERT(!queryOnly); - if (queryOnly) - return false; - - pDb->WriteSqlLog(pSqlStmt); - - return(execUpdate(pSqlStmt)); - -} // wxDbTable::Update(pSqlStmt) - - -/********** wxDbTable::UpdateWhere() **********/ -bool wxDbTable::UpdateWhere(const wxString &pWhereClause) -{ - wxASSERT(!queryOnly); - if (queryOnly) - return false; - - wxString sqlStmt; - - // Build the SQL UPDATE statement - BuildUpdateStmt(sqlStmt, DB_UPD_WHERE, pWhereClause); - - pDb->WriteSqlLog(sqlStmt); - -#ifdef DBDEBUG_CONSOLE - cout << endl << sqlStmt.c_str() << endl << endl; -#endif - - // Execute the SQL UPDATE statement - return(execUpdate(sqlStmt)); - -} // wxDbTable::UpdateWhere() - - -/********** wxDbTable::Delete() **********/ -bool wxDbTable::Delete(void) -{ - wxASSERT(!queryOnly); - if (queryOnly) - return false; - - wxString sqlStmt; - sqlStmt.Empty(); - - // Build the SQL DELETE statement - BuildDeleteStmt(sqlStmt, DB_DEL_KEYFIELDS); - - pDb->WriteSqlLog(sqlStmt); - - // Execute the SQL DELETE statement - return(execDelete(sqlStmt)); - -} // wxDbTable::Delete() - - -/********** wxDbTable::DeleteWhere() **********/ -bool wxDbTable::DeleteWhere(const wxString &pWhereClause) -{ - wxASSERT(!queryOnly); - if (queryOnly) - return false; - - wxString sqlStmt; - sqlStmt.Empty(); - - // Build the SQL DELETE statement - BuildDeleteStmt(sqlStmt, DB_DEL_WHERE, pWhereClause); - - pDb->WriteSqlLog(sqlStmt); - - // Execute the SQL DELETE statement - return(execDelete(sqlStmt)); - -} // wxDbTable::DeleteWhere() - - -/********** wxDbTable::DeleteMatching() **********/ -bool wxDbTable::DeleteMatching(void) -{ - wxASSERT(!queryOnly); - if (queryOnly) - return false; - - wxString sqlStmt; - sqlStmt.Empty(); - - // Build the SQL DELETE statement - BuildDeleteStmt(sqlStmt, DB_DEL_MATCHING); - - pDb->WriteSqlLog(sqlStmt); - - // Execute the SQL DELETE statement - return(execDelete(sqlStmt)); - -} // wxDbTable::DeleteMatching() - - -/********** wxDbTable::IsColNull() **********/ -bool wxDbTable::IsColNull(UWORD colNumber) const -{ -/* - This logic is just not right. It would indicate true - if a numeric field were set to a value of 0. - - switch(colDefs[colNumber].SqlCtype) - { - case SQL_C_CHAR: - case SQL_C_WCHAR: - //case SQL_C_WXCHAR: SQL_C_WXCHAR is covered by either SQL_C_CHAR or SQL_C_WCHAR - return(((UCHAR FAR *) colDefs[colNumber].PtrDataObj)[0] == 0); - case SQL_C_SSHORT: - return(( *((SWORD *) colDefs[colNumber].PtrDataObj)) == 0); - case SQL_C_USHORT: - return(( *((UWORD*) colDefs[colNumber].PtrDataObj)) == 0); - case SQL_C_SLONG: - return(( *((SDWORD *) colDefs[colNumber].PtrDataObj)) == 0); - case SQL_C_ULONG: - return(( *((UDWORD *) colDefs[colNumber].PtrDataObj)) == 0); - case SQL_C_FLOAT: - return(( *((SFLOAT *) colDefs[colNumber].PtrDataObj)) == 0); - case SQL_C_DOUBLE: - return((*((SDOUBLE *) colDefs[colNumber].PtrDataObj)) == 0); - case SQL_C_TIMESTAMP: - TIMESTAMP_STRUCT *pDt; - pDt = (TIMESTAMP_STRUCT *) colDefs[colNumber].PtrDataObj; - if (pDt->year == 0 && pDt->month == 0 && pDt->day == 0) - return true; - else - return false; - default: - return true; - } -*/ - return (colDefs[colNumber].Null); -} // wxDbTable::IsColNull() - - -/********** wxDbTable::CanSelectForUpdate() **********/ -bool wxDbTable::CanSelectForUpdate(void) -{ - if (queryOnly) - return false; - - if (pDb->Dbms() == dbmsMY_SQL) - return false; - - if ((pDb->Dbms() == dbmsORACLE) || - (pDb->dbInf.posStmts & SQL_PS_SELECT_FOR_UPDATE)) - return true; - else - return false; - -} // wxDbTable::CanSelectForUpdate() - - -/********** wxDbTable::CanUpdateByROWID() **********/ -bool wxDbTable::CanUpdateByROWID(void) -{ -/* - * NOTE: Returning false for now until this can be debugged, - * as the ROWID is not getting updated correctly - */ - return false; -/* - if (pDb->Dbms() == dbmsORACLE) - return true; - else - return false; -*/ -} // wxDbTable::CanUpdateByROWID() - - -/********** wxDbTable::IsCursorClosedOnCommit() **********/ -bool wxDbTable::IsCursorClosedOnCommit(void) -{ - if (pDb->dbInf.cursorCommitBehavior == SQL_CB_PRESERVE) - return false; - else - return true; - -} // wxDbTable::IsCursorClosedOnCommit() - - - -/********** wxDbTable::ClearMemberVar() **********/ -void wxDbTable::ClearMemberVar(UWORD colNumber, bool setToNull) -{ - wxASSERT(colNumber < m_numCols); - - switch(colDefs[colNumber].SqlCtype) - { - case SQL_C_CHAR: -#ifdef SQL_C_WCHAR - case SQL_C_WCHAR: -#endif - //case SQL_C_WXCHAR: SQL_C_WXCHAR is covered by either SQL_C_CHAR or SQL_C_WCHAR - ((UCHAR FAR *) colDefs[colNumber].PtrDataObj)[0] = 0; - break; - case SQL_C_SSHORT: - *((SWORD *) colDefs[colNumber].PtrDataObj) = 0; - break; - case SQL_C_USHORT: - *((UWORD*) colDefs[colNumber].PtrDataObj) = 0; - break; - case SQL_C_LONG: - case SQL_C_SLONG: - *((SDWORD *) colDefs[colNumber].PtrDataObj) = 0; - break; - case SQL_C_ULONG: - *((UDWORD *) colDefs[colNumber].PtrDataObj) = 0; - break; - case SQL_C_FLOAT: - *((SFLOAT *) colDefs[colNumber].PtrDataObj) = 0.0f; - break; - case SQL_C_DOUBLE: - *((SDOUBLE *) colDefs[colNumber].PtrDataObj) = 0.0f; - break; - case SQL_C_TIMESTAMP: - TIMESTAMP_STRUCT *pDt; - pDt = (TIMESTAMP_STRUCT *) colDefs[colNumber].PtrDataObj; - pDt->year = 0; - pDt->month = 0; - pDt->day = 0; - pDt->hour = 0; - pDt->minute = 0; - pDt->second = 0; - pDt->fraction = 0; - break; - case SQL_C_DATE: - DATE_STRUCT *pDtd; - pDtd = (DATE_STRUCT *) colDefs[colNumber].PtrDataObj; - pDtd->year = 0; - pDtd->month = 0; - pDtd->day = 0; - break; - case SQL_C_TIME: - TIME_STRUCT *pDtt; - pDtt = (TIME_STRUCT *) colDefs[colNumber].PtrDataObj; - pDtt->hour = 0; - pDtt->minute = 0; - pDtt->second = 0; - break; - } - - if (setToNull) - SetColNull(colNumber); -} // wxDbTable::ClearMemberVar() - - -/********** wxDbTable::ClearMemberVars() **********/ -void wxDbTable::ClearMemberVars(bool setToNull) -{ - int i; - - // Loop through the columns setting each member variable to zero - for (i=0; i < m_numCols; i++) - ClearMemberVar((UWORD)i,setToNull); - -} // wxDbTable::ClearMemberVars() - - -/********** wxDbTable::SetQueryTimeout() **********/ -bool wxDbTable::SetQueryTimeout(UDWORD nSeconds) -{ - if (SQLSetStmtOption(hstmtInsert, SQL_QUERY_TIMEOUT, nSeconds) != SQL_SUCCESS) - return(pDb->DispAllErrors(henv, hdbc, hstmtInsert)); - if (SQLSetStmtOption(hstmtUpdate, SQL_QUERY_TIMEOUT, nSeconds) != SQL_SUCCESS) - return(pDb->DispAllErrors(henv, hdbc, hstmtUpdate)); - if (SQLSetStmtOption(hstmtDelete, SQL_QUERY_TIMEOUT, nSeconds) != SQL_SUCCESS) - return(pDb->DispAllErrors(henv, hdbc, hstmtDelete)); - if (SQLSetStmtOption(hstmtInternal, SQL_QUERY_TIMEOUT, nSeconds) != SQL_SUCCESS) - return(pDb->DispAllErrors(henv, hdbc, hstmtInternal)); - - // Completed Successfully - return true; - -} // wxDbTable::SetQueryTimeout() - - -/********** wxDbTable::SetColDefs() **********/ -bool wxDbTable::SetColDefs(UWORD index, const wxString &fieldName, int dataType, void *pData, - SWORD cType, int size, bool keyField, bool updateable, - bool insertAllowed, bool derivedColumn) -{ - wxString tmpStr; - - if (index >= m_numCols) // Columns numbers are zero based.... - { - tmpStr.Printf(wxT("Specified column index (%d) exceeds the maximum number of columns (%d) registered for this table definition. Column definition not added."), index, m_numCols); - wxFAIL_MSG(tmpStr); - wxLogDebug(tmpStr); - return false; - } - - if (!colDefs) // May happen if the database connection fails - return false; - - if (fieldName.length() > (unsigned int) DB_MAX_COLUMN_NAME_LEN) - { - wxStrncpy(colDefs[index].ColName, fieldName, DB_MAX_COLUMN_NAME_LEN); - colDefs[index].ColName[DB_MAX_COLUMN_NAME_LEN] = 0; // Prevent buffer overrun - - tmpStr.Printf(wxT("Column name '%s' is too long. Truncated to '%s'."), - fieldName.c_str(),colDefs[index].ColName); - wxFAIL_MSG(tmpStr); - wxLogDebug(tmpStr); - } - else - wxStrcpy(colDefs[index].ColName, fieldName); - - colDefs[index].DbDataType = dataType; - colDefs[index].PtrDataObj = pData; - colDefs[index].SqlCtype = cType; - colDefs[index].SzDataObj = size; //TODO: glt ??? * sizeof(wxChar) ??? - colDefs[index].KeyField = keyField; - colDefs[index].DerivedCol = derivedColumn; - // Derived columns by definition would NOT be "Insertable" or "Updateable" - if (derivedColumn) - { - colDefs[index].Updateable = false; - colDefs[index].InsertAllowed = false; - } - else - { - colDefs[index].Updateable = updateable; - colDefs[index].InsertAllowed = insertAllowed; - } - - colDefs[index].Null = false; - - return true; - -} // wxDbTable::SetColDefs() - - -/********** wxDbTable::SetColDefs() **********/ -wxDbColDataPtr* wxDbTable::SetColDefs(wxDbColInf *pColInfs, UWORD numCols) -{ - wxASSERT(pColInfs); - wxDbColDataPtr *pColDataPtrs = NULL; - - if (pColInfs) - { - UWORD index; - - pColDataPtrs = new wxDbColDataPtr[numCols+1]; - - for (index = 0; index < numCols; index++) - { - // Process the fields - switch (pColInfs[index].dbDataType) - { - case DB_DATA_TYPE_VARCHAR: - pColDataPtrs[index].PtrDataObj = new wxChar[pColInfs[index].bufferSize+(1*sizeof(wxChar))]; - pColDataPtrs[index].SzDataObj = pColInfs[index].bufferSize+(1*sizeof(wxChar)); - pColDataPtrs[index].SqlCtype = SQL_C_WXCHAR; - break; - case DB_DATA_TYPE_MEMO: - pColDataPtrs[index].PtrDataObj = new wxChar[pColInfs[index].bufferSize+(1*sizeof(wxChar))]; - pColDataPtrs[index].SzDataObj = pColInfs[index].bufferSize+(1*sizeof(wxChar)); - pColDataPtrs[index].SqlCtype = SQL_C_WXCHAR; - break; - case DB_DATA_TYPE_INTEGER: - // Can be long or short - if (pColInfs[index].bufferSize == sizeof(long)) - { - pColDataPtrs[index].PtrDataObj = new long; - pColDataPtrs[index].SzDataObj = sizeof(long); - pColDataPtrs[index].SqlCtype = SQL_C_SLONG; - } - else - { - pColDataPtrs[index].PtrDataObj = new short; - pColDataPtrs[index].SzDataObj = sizeof(short); - pColDataPtrs[index].SqlCtype = SQL_C_SSHORT; - } - break; - case DB_DATA_TYPE_FLOAT: - // Can be float or double - if (pColInfs[index].bufferSize == sizeof(float)) - { - pColDataPtrs[index].PtrDataObj = new float; - pColDataPtrs[index].SzDataObj = sizeof(float); - pColDataPtrs[index].SqlCtype = SQL_C_FLOAT; - } - else - { - pColDataPtrs[index].PtrDataObj = new double; - pColDataPtrs[index].SzDataObj = sizeof(double); - pColDataPtrs[index].SqlCtype = SQL_C_DOUBLE; - } - break; - case DB_DATA_TYPE_DATE: - pColDataPtrs[index].PtrDataObj = new TIMESTAMP_STRUCT; - pColDataPtrs[index].SzDataObj = sizeof(TIMESTAMP_STRUCT); - pColDataPtrs[index].SqlCtype = SQL_C_TIMESTAMP; - break; - case DB_DATA_TYPE_BLOB: - wxFAIL_MSG(wxT("This form of ::SetColDefs() cannot be used with BLOB columns")); - pColDataPtrs[index].PtrDataObj = /*BLOB ADDITION NEEDED*/NULL; - pColDataPtrs[index].SzDataObj = /*BLOB ADDITION NEEDED*/sizeof(void *); - pColDataPtrs[index].SqlCtype = SQL_VARBINARY; - break; - } - if (pColDataPtrs[index].PtrDataObj != NULL) - SetColDefs (index,pColInfs[index].colName,pColInfs[index].dbDataType, pColDataPtrs[index].PtrDataObj, pColDataPtrs[index].SqlCtype, pColDataPtrs[index].SzDataObj); - else - { - // Unable to build all the column definitions, as either one of - // the calls to "new" failed above, or there was a BLOB field - // to have a column definition for. If BLOBs are to be used, - // the other form of ::SetColDefs() must be used, as it is impossible - // to know the maximum size to create the PtrDataObj to be. - delete [] pColDataPtrs; - return NULL; - } - } - } - - return (pColDataPtrs); - -} // wxDbTable::SetColDefs() - - -/********** wxDbTable::SetCursor() **********/ -void wxDbTable::SetCursor(HSTMT *hstmtActivate) -{ - if (hstmtActivate == wxDB_DEFAULT_CURSOR) - hstmt = *hstmtDefault; - else - hstmt = *hstmtActivate; - -} // wxDbTable::SetCursor() - - -/********** wxDbTable::Count(const wxString &) **********/ -ULONG wxDbTable::Count(const wxString &args) -{ - ULONG count; - wxString sqlStmt; - SQLLEN cb; - - // Build a "SELECT COUNT(*) FROM queryTableName [WHERE whereClause]" SQL Statement - sqlStmt = wxT("SELECT COUNT("); - sqlStmt += args; - sqlStmt += wxT(") FROM "); - sqlStmt += pDb->SQLTableName(queryTableName); -// sqlStmt += queryTableName; -#if wxODBC_BACKWARD_COMPATABILITY - if (from && wxStrlen(from)) -#else - if (from.length()) -#endif - sqlStmt += from; - - // Add the where clause if one is provided -#if wxODBC_BACKWARD_COMPATABILITY - if (where && wxStrlen(where)) -#else - if (where.length()) -#endif - { - sqlStmt += wxT(" WHERE "); - sqlStmt += where; - } - - pDb->WriteSqlLog(sqlStmt); - - // Initialize the Count cursor if it's not already initialized - if (!hstmtCount) - { - hstmtCount = GetNewCursor(false,false); - wxASSERT(hstmtCount); - if (!hstmtCount) - return(0); - } - - // Execute the SQL statement - if (SQLExecDirect(*hstmtCount, (SQLTCHAR FAR *) sqlStmt.c_str(), SQL_NTS) != SQL_SUCCESS) - { - pDb->DispAllErrors(henv, hdbc, *hstmtCount); - return(0); - } - - // Fetch the record - if (SQLFetch(*hstmtCount) != SQL_SUCCESS) - { - pDb->DispAllErrors(henv, hdbc, *hstmtCount); - return(0); - } - - // Obtain the result - if (SQLGetData(*hstmtCount, (UWORD)1, SQL_C_ULONG, &count, sizeof(count), &cb) != SQL_SUCCESS) - { - pDb->DispAllErrors(henv, hdbc, *hstmtCount); - return(0); - } - - // Free the cursor - if (SQLFreeStmt(*hstmtCount, SQL_CLOSE) != SQL_SUCCESS) - pDb->DispAllErrors(henv, hdbc, *hstmtCount); - - // Return the record count - return(count); - -} // wxDbTable::Count() - - -/********** wxDbTable::Refresh() **********/ -bool wxDbTable::Refresh(void) -{ - bool result = true; - - // Switch to the internal cursor so any active cursors are not corrupted - HSTMT currCursor = GetCursor(); - hstmt = hstmtInternal; -#if wxODBC_BACKWARD_COMPATABILITY - // Save the where and order by clauses - wxChar *saveWhere = where; - wxChar *saveOrderBy = orderBy; -#else - wxString saveWhere = where; - wxString saveOrderBy = orderBy; -#endif - // Build a where clause to refetch the record with. Try and use the - // ROWID if it's available, ow use the key fields. - wxString whereClause; - whereClause.Empty(); - - if (CanUpdateByROWID()) - { - SQLLEN cb; - wxChar rowid[wxDB_ROWID_LEN+1]; - - // Get the ROWID value. If not successful retreiving the ROWID, - // simply fall down through the code and build the WHERE clause - // based on the key fields. - if (SQLGetData(hstmt, (UWORD)(m_numCols+1), SQL_C_WXCHAR, (UCHAR*) rowid, sizeof(rowid), &cb) == SQL_SUCCESS) - { - whereClause += pDb->SQLTableName(queryTableName); -// whereClause += queryTableName; - whereClause += wxT(".ROWID = '"); - whereClause += rowid; - whereClause += wxT("'"); - } - } - - // If unable to use the ROWID, build a where clause from the keyfields - if (wxStrlen(whereClause) == 0) - BuildWhereClause(whereClause, DB_WHERE_KEYFIELDS, queryTableName); - - // Requery the record - where = whereClause; - orderBy.Empty(); - if (!Query()) - result = false; - - if (result && !GetNext()) - result = false; - - // Switch back to original cursor - SetCursor(&currCursor); - - // Free the internal cursor - if (SQLFreeStmt(hstmtInternal, SQL_CLOSE) != SQL_SUCCESS) - pDb->DispAllErrors(henv, hdbc, hstmtInternal); - - // Restore the original where and order by clauses - where = saveWhere; - orderBy = saveOrderBy; - - return(result); - -} // wxDbTable::Refresh() - - -/********** wxDbTable::SetColNull() **********/ -bool wxDbTable::SetColNull(UWORD colNumber, bool set) -{ - if (colNumber < m_numCols) - { - colDefs[colNumber].Null = set; - if (set) // Blank out the values in the member variable - ClearMemberVar(colNumber, false); // Must call with false here, or infinite recursion will happen - - setCbValueForColumn(colNumber); - - return true; - } - else - return false; - -} // wxDbTable::SetColNull() - - -/********** wxDbTable::SetColNull() **********/ -bool wxDbTable::SetColNull(const wxString &colName, bool set) -{ - int colNumber; - for (colNumber = 0; colNumber < m_numCols; colNumber++) - { - if (!wxStricmp(colName, colDefs[colNumber].ColName)) - break; - } - - if (colNumber < m_numCols) - { - colDefs[colNumber].Null = set; - if (set) // Blank out the values in the member variable - ClearMemberVar((UWORD)colNumber,false); // Must call with false here, or infinite recursion will happen - - setCbValueForColumn(colNumber); - - return true; - } - else - return false; - -} // wxDbTable::SetColNull() - - -/********** wxDbTable::GetNewCursor() **********/ -HSTMT *wxDbTable::GetNewCursor(bool setCursor, bool bindColumns) -{ - HSTMT *newHSTMT = new HSTMT; - wxASSERT(newHSTMT); - if (!newHSTMT) - return(0); - - if (SQLAllocStmt(hdbc, newHSTMT) != SQL_SUCCESS) - { - pDb->DispAllErrors(henv, hdbc); - delete newHSTMT; - return(0); - } - - if (SQLSetStmtOption(*newHSTMT, SQL_CURSOR_TYPE, cursorType) != SQL_SUCCESS) - { - pDb->DispAllErrors(henv, hdbc, *newHSTMT); - delete newHSTMT; - return(0); - } - - if (bindColumns) - { - if (!bindCols(*newHSTMT)) - { - delete newHSTMT; - return(0); - } - } - - if (setCursor) - SetCursor(newHSTMT); - - return(newHSTMT); - -} // wxDbTable::GetNewCursor() - - -/********** wxDbTable::DeleteCursor() **********/ -bool wxDbTable::DeleteCursor(HSTMT *hstmtDel) -{ - bool result = true; - - if (!hstmtDel) // Cursor already deleted - return(result); - -/* -ODBC 3.0 says to use this form - if (SQLFreeHandle(*hstmtDel, SQL_DROP) != SQL_SUCCESS) - -*/ - if (SQLFreeStmt(*hstmtDel, SQL_DROP) != SQL_SUCCESS) - { - pDb->DispAllErrors(henv, hdbc); - result = false; - } - - delete hstmtDel; - - return(result); - -} // wxDbTable::DeleteCursor() - -////////////////////////////////////////////////////////////// -// wxDbGrid support functions -////////////////////////////////////////////////////////////// - -void wxDbTable::SetRowMode(const rowmode_t rowmode) -{ - if (!m_hstmtGridQuery) - { - m_hstmtGridQuery = GetNewCursor(false,false); - if (!bindCols(*m_hstmtGridQuery)) - return; - } - - m_rowmode = rowmode; - switch (m_rowmode) - { - case WX_ROW_MODE_QUERY: - SetCursor(m_hstmtGridQuery); - break; - case WX_ROW_MODE_INDIVIDUAL: - SetCursor(hstmtDefault); - break; - default: - wxASSERT(0); - } -} // wxDbTable::SetRowMode() - - -wxVariant wxDbTable::GetColumn(const int colNumber) const -{ - wxVariant val; - if ((colNumber < m_numCols) && (!IsColNull((UWORD)colNumber))) - { - switch (colDefs[colNumber].SqlCtype) - { -#if wxUSE_UNICODE - #if defined(SQL_WCHAR) - case SQL_WCHAR: - #endif - #if defined(SQL_WVARCHAR) - case SQL_WVARCHAR: - #endif -#endif - case SQL_CHAR: - case SQL_VARCHAR: - val = (wxChar *)(colDefs[colNumber].PtrDataObj); - break; - case SQL_C_LONG: - case SQL_C_SLONG: - val = *(long *)(colDefs[colNumber].PtrDataObj); - break; - case SQL_C_SHORT: - case SQL_C_SSHORT: - val = (long int )(*(short *)(colDefs[colNumber].PtrDataObj)); - break; - case SQL_C_ULONG: - val = (long)(*(unsigned long *)(colDefs[colNumber].PtrDataObj)); - break; - case SQL_C_TINYINT: - val = (long)(*(wxChar *)(colDefs[colNumber].PtrDataObj)); - break; - case SQL_C_UTINYINT: - val = (long)(*(wxChar *)(colDefs[colNumber].PtrDataObj)); - break; - case SQL_C_USHORT: - val = (long)(*(UWORD *)(colDefs[colNumber].PtrDataObj)); - break; - case SQL_C_DATE: - val = (DATE_STRUCT *)(colDefs[colNumber].PtrDataObj); - break; - case SQL_C_TIME: - val = (TIME_STRUCT *)(colDefs[colNumber].PtrDataObj); - break; - case SQL_C_TIMESTAMP: - val = (TIMESTAMP_STRUCT *)(colDefs[colNumber].PtrDataObj); - break; - case SQL_C_DOUBLE: - val = *(double *)(colDefs[colNumber].PtrDataObj); - break; - default: - assert(0); - } - } - return val; -} // wxDbTable::GetCol() - - -void wxDbTable::SetColumn(const int colNumber, const wxVariant val) -{ - //FIXME: Add proper wxDateTime support to wxVariant.. - wxDateTime dateval; - - SetColNull((UWORD)colNumber, val.IsNull()); - - if (!val.IsNull()) - { - if ((colDefs[colNumber].SqlCtype == SQL_C_DATE) - || (colDefs[colNumber].SqlCtype == SQL_C_TIME) - || (colDefs[colNumber].SqlCtype == SQL_C_TIMESTAMP)) - { - //Returns null if invalid! - if (!dateval.ParseDate(val.GetString())) - SetColNull((UWORD)colNumber, true); - } - - switch (colDefs[colNumber].SqlCtype) - { -#if wxUSE_UNICODE - #if defined(SQL_WCHAR) - case SQL_WCHAR: - #endif - #if defined(SQL_WVARCHAR) - case SQL_WVARCHAR: - #endif -#endif - case SQL_CHAR: - case SQL_VARCHAR: - csstrncpyt((wxChar *)(colDefs[colNumber].PtrDataObj), - val.GetString().c_str(), - colDefs[colNumber].SzDataObj-1); //TODO: glt ??? * sizeof(wxChar) ??? - break; - case SQL_C_LONG: - case SQL_C_SLONG: - *(long *)(colDefs[colNumber].PtrDataObj) = val; - break; - case SQL_C_SHORT: - case SQL_C_SSHORT: - *(short *)(colDefs[colNumber].PtrDataObj) = (short)val.GetLong(); - break; - case SQL_C_ULONG: - *(unsigned long *)(colDefs[colNumber].PtrDataObj) = val.GetLong(); - break; - case SQL_C_TINYINT: - *(wxChar *)(colDefs[colNumber].PtrDataObj) = val.GetChar(); - break; - case SQL_C_UTINYINT: - *(wxChar *)(colDefs[colNumber].PtrDataObj) = val.GetChar(); - break; - case SQL_C_USHORT: - *(unsigned short *)(colDefs[colNumber].PtrDataObj) = (unsigned short)val.GetLong(); - break; - //FIXME: Add proper wxDateTime support to wxVariant.. - case SQL_C_DATE: - { - DATE_STRUCT *dataptr = - (DATE_STRUCT *)colDefs[colNumber].PtrDataObj; - - dataptr->year = (SWORD)dateval.GetYear(); - dataptr->month = (UWORD)(dateval.GetMonth()+1); - dataptr->day = (UWORD)dateval.GetDay(); - } - break; - case SQL_C_TIME: - { - TIME_STRUCT *dataptr = - (TIME_STRUCT *)colDefs[colNumber].PtrDataObj; - - dataptr->hour = dateval.GetHour(); - dataptr->minute = dateval.GetMinute(); - dataptr->second = dateval.GetSecond(); - } - break; - case SQL_C_TIMESTAMP: - { - TIMESTAMP_STRUCT *dataptr = - (TIMESTAMP_STRUCT *)colDefs[colNumber].PtrDataObj; - dataptr->year = (SWORD)dateval.GetYear(); - dataptr->month = (UWORD)(dateval.GetMonth()+1); - dataptr->day = (UWORD)dateval.GetDay(); - - dataptr->hour = dateval.GetHour(); - dataptr->minute = dateval.GetMinute(); - dataptr->second = dateval.GetSecond(); - } - break; - case SQL_C_DOUBLE: - *(double *)(colDefs[colNumber].PtrDataObj) = val; - break; - default: - assert(0); - } // switch - } // if (!val.IsNull()) -} // wxDbTable::SetCol() - - -GenericKey wxDbTable::GetKey() -{ - void *blk; - wxChar *blkptr; - - blk = malloc(m_keysize); - blkptr = (wxChar *) blk; - - int i; - for (i=0; i < m_numCols; i++) - { - if (colDefs[i].KeyField) - { - memcpy(blkptr,colDefs[i].PtrDataObj, colDefs[i].SzDataObj); - blkptr += colDefs[i].SzDataObj; - } - } - - GenericKey k = GenericKey(blk, m_keysize); - free(blk); - - return k; -} // wxDbTable::GetKey() - - -void wxDbTable::SetKey(const GenericKey& k) -{ - void *blk; - wxChar *blkptr; - - blk = k.GetBlk(); - blkptr = (wxChar *)blk; - - int i; - for (i=0; i < m_numCols; i++) - { - if (colDefs[i].KeyField) - { - SetColNull((UWORD)i, false); - memcpy(colDefs[i].PtrDataObj, blkptr, colDefs[i].SzDataObj); - blkptr += colDefs[i].SzDataObj; - } - } -} // wxDbTable::SetKey() - - -#endif // wxUSE_ODBC +/////////////////////////////////////////////////////////////////////////////// +// Name: src/common/dbtable.cpp +// Purpose: Implementation of the wxDbTable class. +// Author: Doug Card +// Modified by: George Tasker +// Bart Jourquin +// Mark Johnson +// Created: 9.96 +// RCS-ID: $Id: dbtable.cpp 48685 2007-09-14 19:02:28Z VZ $ +// Copyright: (c) 1996 Remstar International, Inc. +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_ODBC + +#ifndef WX_PRECOMP + #include "wx/object.h" + #include "wx/list.h" + #include "wx/string.h" + #include "wx/utils.h" + #include "wx/log.h" +#endif + +#ifdef DBDEBUG_CONSOLE +#if wxUSE_IOSTREAMH + #include +#else + #include +#endif + #include "wx/ioswrap.h" +#endif + +#include "wx/filefn.h" + +#include +#include +#include + +#include "wx/dbtable.h" + +#ifdef __UNIX__ +// The HPUX preprocessor lines below were commented out on 8/20/97 +// because macros.h currently redefines DEBUG and is unneeded. +// # ifdef HPUX +// # include +// # endif +# ifdef LINUX +# include +# endif +#endif + +ULONG lastTableID = 0; + + +#ifdef __WXDEBUG__ + #include "wx/thread.h" + + wxList TablesInUse; +#if wxUSE_THREADS + wxCriticalSection csTablesInUse; +#endif // wxUSE_THREADS +#endif + + +void csstrncpyt(wxChar *target, const wxChar *source, int n) +{ + while ( (*target++ = *source++) != '\0' && --n != 0 ) + ; + + *target = '\0'; +} + + + +/********** wxDbColDef::wxDbColDef() Constructor **********/ +wxDbColDef::wxDbColDef() +{ + Initialize(); +} // Constructor + + +bool wxDbColDef::Initialize() +{ + ColName[0] = 0; + DbDataType = DB_DATA_TYPE_INTEGER; + SqlCtype = SQL_C_LONG; + PtrDataObj = NULL; + SzDataObj = 0; + KeyField = false; + Updateable = false; + InsertAllowed = false; + DerivedCol = false; + CbValue = 0; + Null = false; + + return true; +} // wxDbColDef::Initialize() + + +/********** wxDbTable::wxDbTable() Constructor **********/ +wxDbTable::wxDbTable(wxDb *pwxDb, const wxString &tblName, const UWORD numColumns, + const wxString &qryTblName, bool qryOnly, const wxString &tblPath) +{ + if (!initialize(pwxDb, tblName, numColumns, qryTblName, qryOnly, tblPath)) + cleanup(); +} // wxDbTable::wxDbTable() + + +/***** DEPRECATED: use wxDbTable::wxDbTable() format above *****/ +#if WXWIN_COMPATIBILITY_2_4 +wxDbTable::wxDbTable(wxDb *pwxDb, const wxString &tblName, const UWORD numColumns, + const wxChar *qryTblName, bool qryOnly, const wxString &tblPath) +{ + wxString tempQryTblName; + tempQryTblName = qryTblName; + if (!initialize(pwxDb, tblName, numColumns, tempQryTblName, qryOnly, tblPath)) + cleanup(); +} // wxDbTable::wxDbTable() +#endif // WXWIN_COMPATIBILITY_2_4 + + +/********** wxDbTable::~wxDbTable() **********/ +wxDbTable::~wxDbTable() +{ + this->cleanup(); +} // wxDbTable::~wxDbTable() + + +bool wxDbTable::initialize(wxDb *pwxDb, const wxString &tblName, const UWORD numColumns, + const wxString &qryTblName, bool qryOnly, const wxString &tblPath) +{ + // Initializing member variables + pDb = pwxDb; // Pointer to the wxDb object + henv = 0; + hdbc = 0; + hstmt = 0; + m_hstmtGridQuery = 0; + hstmtDefault = 0; // Initialized below + hstmtCount = 0; // Initialized first time it is needed + hstmtInsert = 0; + hstmtDelete = 0; + hstmtUpdate = 0; + hstmtInternal = 0; + colDefs = 0; + tableID = 0; + m_numCols = numColumns; // Number of columns in the table + where.Empty(); // Where clause + orderBy.Empty(); // Order By clause + from.Empty(); // From clause + selectForUpdate = false; // SELECT ... FOR UPDATE; Indicates whether to include the FOR UPDATE phrase + queryOnly = qryOnly; + insertable = true; + tablePath.Empty(); + tableName.Empty(); + queryTableName.Empty(); + + wxASSERT(tblName.length()); + wxASSERT(pDb); + + if (!pDb) + return false; + + tableName = tblName; // Table Name + if ((pDb->Dbms() == dbmsORACLE) || + (pDb->Dbms() == dbmsFIREBIRD) || + (pDb->Dbms() == dbmsINTERBASE)) + tableName = tableName.Upper(); + + if (tblPath.length()) + tablePath = tblPath; // Table Path - used for dBase files + else + tablePath.Empty(); + + if (qryTblName.length()) // Name of the table/view to query + queryTableName = qryTblName; + else + queryTableName = tblName; + + if ((pDb->Dbms() == dbmsORACLE) || + (pDb->Dbms() == dbmsFIREBIRD) || + (pDb->Dbms() == dbmsINTERBASE)) + queryTableName = queryTableName.Upper(); + + pDb->incrementTableCount(); + + wxString s; + tableID = ++lastTableID; + s.Printf(wxT("wxDbTable constructor (%-20s) tableID:[%6lu] pDb:[%p]"), + tblName.c_str(), tableID, wx_static_cast(void*, pDb)); + +#ifdef __WXDEBUG__ + wxTablesInUse *tableInUse; + tableInUse = new wxTablesInUse(); + tableInUse->tableName = tblName; + tableInUse->tableID = tableID; + tableInUse->pDb = pDb; + { +#if wxUSE_THREADS + wxCriticalSectionLocker lock(csTablesInUse); +#endif // wxUSE_THREADS + TablesInUse.Append(tableInUse); + } +#endif + + pDb->WriteSqlLog(s); + + // Grab the HENV and HDBC from the wxDb object + henv = pDb->GetHENV(); + hdbc = pDb->GetHDBC(); + + // Allocate space for column definitions + if (m_numCols) + colDefs = new wxDbColDef[m_numCols]; // Points to the first column definition + + // Allocate statement handles for the table + if (!queryOnly) + { + // Allocate a separate statement handle for performing inserts + if (SQLAllocStmt(hdbc, &hstmtInsert) != SQL_SUCCESS) + pDb->DispAllErrors(henv, hdbc); + // Allocate a separate statement handle for performing deletes + if (SQLAllocStmt(hdbc, &hstmtDelete) != SQL_SUCCESS) + pDb->DispAllErrors(henv, hdbc); + // Allocate a separate statement handle for performing updates + if (SQLAllocStmt(hdbc, &hstmtUpdate) != SQL_SUCCESS) + pDb->DispAllErrors(henv, hdbc); + } + // Allocate a separate statement handle for internal use + if (SQLAllocStmt(hdbc, &hstmtInternal) != SQL_SUCCESS) + pDb->DispAllErrors(henv, hdbc); + + // Set the cursor type for the statement handles + cursorType = SQL_CURSOR_STATIC; + + if (SQLSetStmtOption(hstmtInternal, SQL_CURSOR_TYPE, cursorType) != SQL_SUCCESS) + { + // Check to see if cursor type is supported + pDb->GetNextError(henv, hdbc, hstmtInternal); + if (! wxStrcmp(pDb->sqlState, wxT("01S02"))) // Option Value Changed + { + // Datasource does not support static cursors. Driver + // will substitute a cursor type. Call SQLGetStmtOption() + // to determine which cursor type was selected. + if (SQLGetStmtOption(hstmtInternal, SQL_CURSOR_TYPE, &cursorType) != SQL_SUCCESS) + pDb->DispAllErrors(henv, hdbc, hstmtInternal); +#ifdef DBDEBUG_CONSOLE + cout << wxT("Static cursor changed to: "); + switch(cursorType) + { + case SQL_CURSOR_FORWARD_ONLY: + cout << wxT("Forward Only"); + break; + case SQL_CURSOR_STATIC: + cout << wxT("Static"); + break; + case SQL_CURSOR_KEYSET_DRIVEN: + cout << wxT("Keyset Driven"); + break; + case SQL_CURSOR_DYNAMIC: + cout << wxT("Dynamic"); + break; + } + cout << endl << endl; +#endif + // BJO20000425 + if (pDb->FwdOnlyCursors() && cursorType != SQL_CURSOR_FORWARD_ONLY) + { + // Force the use of a forward only cursor... + cursorType = SQL_CURSOR_FORWARD_ONLY; + if (SQLSetStmtOption(hstmtInternal, SQL_CURSOR_TYPE, cursorType) != SQL_SUCCESS) + { + // Should never happen + pDb->GetNextError(henv, hdbc, hstmtInternal); + return false; + } + } + } + else + { + pDb->DispNextError(); + pDb->DispAllErrors(henv, hdbc, hstmtInternal); + } + } +#ifdef DBDEBUG_CONSOLE + else + cout << wxT("Cursor Type set to STATIC") << endl << endl; +#endif + + if (!queryOnly) + { + // Set the cursor type for the INSERT statement handle + if (SQLSetStmtOption(hstmtInsert, SQL_CURSOR_TYPE, SQL_CURSOR_FORWARD_ONLY) != SQL_SUCCESS) + pDb->DispAllErrors(henv, hdbc, hstmtInsert); + // Set the cursor type for the DELETE statement handle + if (SQLSetStmtOption(hstmtDelete, SQL_CURSOR_TYPE, SQL_CURSOR_FORWARD_ONLY) != SQL_SUCCESS) + pDb->DispAllErrors(henv, hdbc, hstmtDelete); + // Set the cursor type for the UPDATE statement handle + if (SQLSetStmtOption(hstmtUpdate, SQL_CURSOR_TYPE, SQL_CURSOR_FORWARD_ONLY) != SQL_SUCCESS) + pDb->DispAllErrors(henv, hdbc, hstmtUpdate); + } + + // Make the default cursor the active cursor + hstmtDefault = GetNewCursor(false,false); + wxASSERT(hstmtDefault); + hstmt = *hstmtDefault; + + return true; + +} // wxDbTable::initialize() + + +void wxDbTable::cleanup() +{ + wxString s; + if (pDb) + { + s.Printf(wxT("wxDbTable destructor (%-20s) tableID:[%6lu] pDb:[%p]"), + tableName.c_str(), tableID, wx_static_cast(void*, pDb)); + pDb->WriteSqlLog(s); + } + +#ifdef __WXDEBUG__ + if (tableID) + { + bool found = false; + + wxList::compatibility_iterator pNode; + { +#if wxUSE_THREADS + wxCriticalSectionLocker lock(csTablesInUse); +#endif // wxUSE_THREADS + pNode = TablesInUse.GetFirst(); + while (!found && pNode) + { + if (((wxTablesInUse *)pNode->GetData())->tableID == tableID) + { + found = true; + delete (wxTablesInUse *)pNode->GetData(); + TablesInUse.Erase(pNode); + } + else + pNode = pNode->GetNext(); + } + } + if (!found) + { + wxString msg; + msg.Printf(wxT("Unable to find the tableID in the linked\nlist of tables in use.\n\n%s"),s.c_str()); + wxLogDebug (msg,wxT("NOTICE...")); + } + } +#endif + + // Decrement the wxDb table count + if (pDb) + pDb->decrementTableCount(); + + // Delete memory allocated for column definitions + if (colDefs) + delete [] colDefs; + + // Free statement handles + if (!queryOnly) + { + if (hstmtInsert) + { +/* +ODBC 3.0 says to use this form + if (SQLFreeHandle(*hstmtDel, SQL_DROP) != SQL_SUCCESS) +*/ + if (SQLFreeStmt(hstmtInsert, SQL_DROP) != SQL_SUCCESS) + pDb->DispAllErrors(henv, hdbc); + } + + if (hstmtDelete) + { +/* +ODBC 3.0 says to use this form + if (SQLFreeHandle(*hstmtDel, SQL_DROP) != SQL_SUCCESS) +*/ + if (SQLFreeStmt(hstmtDelete, SQL_DROP) != SQL_SUCCESS) + pDb->DispAllErrors(henv, hdbc); + } + + if (hstmtUpdate) + { +/* +ODBC 3.0 says to use this form + if (SQLFreeHandle(*hstmtDel, SQL_DROP) != SQL_SUCCESS) +*/ + if (SQLFreeStmt(hstmtUpdate, SQL_DROP) != SQL_SUCCESS) + pDb->DispAllErrors(henv, hdbc); + } + } + + if (hstmtInternal) + { + if (SQLFreeStmt(hstmtInternal, SQL_DROP) != SQL_SUCCESS) + pDb->DispAllErrors(henv, hdbc); + } + + // Delete dynamically allocated cursors + if (hstmtDefault) + DeleteCursor(hstmtDefault); + + if (hstmtCount) + DeleteCursor(hstmtCount); + + if (m_hstmtGridQuery) + DeleteCursor(m_hstmtGridQuery); + +} // wxDbTable::cleanup() + + +/***************************** PRIVATE FUNCTIONS *****************************/ + + +void wxDbTable::setCbValueForColumn(int columnIndex) +{ + switch(colDefs[columnIndex].DbDataType) + { + case DB_DATA_TYPE_VARCHAR: + case DB_DATA_TYPE_MEMO: + if (colDefs[columnIndex].Null) + colDefs[columnIndex].CbValue = SQL_NULL_DATA; + else + colDefs[columnIndex].CbValue = SQL_NTS; + break; + case DB_DATA_TYPE_INTEGER: + if (colDefs[columnIndex].Null) + colDefs[columnIndex].CbValue = SQL_NULL_DATA; + else + colDefs[columnIndex].CbValue = 0; + break; + case DB_DATA_TYPE_FLOAT: + if (colDefs[columnIndex].Null) + colDefs[columnIndex].CbValue = SQL_NULL_DATA; + else + colDefs[columnIndex].CbValue = 0; + break; + case DB_DATA_TYPE_DATE: + if (colDefs[columnIndex].Null) + colDefs[columnIndex].CbValue = SQL_NULL_DATA; + else + colDefs[columnIndex].CbValue = 0; + break; + case DB_DATA_TYPE_BLOB: + if (colDefs[columnIndex].Null) + colDefs[columnIndex].CbValue = SQL_NULL_DATA; + else + if (colDefs[columnIndex].SqlCtype == SQL_C_WXCHAR) + colDefs[columnIndex].CbValue = SQL_NTS; + else + colDefs[columnIndex].CbValue = SQL_LEN_DATA_AT_EXEC(colDefs[columnIndex].SzDataObj); + break; + } +} + +/********** wxDbTable::bindParams() **********/ +bool wxDbTable::bindParams(bool forUpdate) +{ + wxASSERT(!queryOnly); + if (queryOnly) + return false; + + SWORD fSqlType = 0; + SDWORD precision = 0; + SWORD scale = 0; + + // Bind each column of the table that should be bound + // to a parameter marker + int i; + UWORD colNumber; + + for (i=0, colNumber=1; i < m_numCols; i++) + { + if (forUpdate) + { + if (!colDefs[i].Updateable) + continue; + } + else + { + if (!colDefs[i].InsertAllowed) + continue; + } + + switch(colDefs[i].DbDataType) + { + case DB_DATA_TYPE_VARCHAR: + fSqlType = pDb->GetTypeInfVarchar().FsqlType; + precision = colDefs[i].SzDataObj; + scale = 0; + break; + case DB_DATA_TYPE_MEMO: + fSqlType = pDb->GetTypeInfMemo().FsqlType; + precision = colDefs[i].SzDataObj; + scale = 0; + break; + case DB_DATA_TYPE_INTEGER: + fSqlType = pDb->GetTypeInfInteger().FsqlType; + precision = pDb->GetTypeInfInteger().Precision; + scale = 0; + break; + case DB_DATA_TYPE_FLOAT: + fSqlType = pDb->GetTypeInfFloat().FsqlType; + precision = pDb->GetTypeInfFloat().Precision; + scale = pDb->GetTypeInfFloat().MaximumScale; + // SQL Sybase Anywhere v5.5 returned a negative number for the + // MaxScale. This caused ODBC to kick out an error on ibscale. + // I check for this here and set the scale = precision. + //if (scale < 0) + // scale = (short) precision; + break; + case DB_DATA_TYPE_DATE: + fSqlType = pDb->GetTypeInfDate().FsqlType; + precision = pDb->GetTypeInfDate().Precision; + scale = 0; + break; + case DB_DATA_TYPE_BLOB: + fSqlType = pDb->GetTypeInfBlob().FsqlType; + precision = colDefs[i].SzDataObj; + scale = 0; + break; + } + + setCbValueForColumn(i); + + if (forUpdate) + { + if (SQLBindParameter(hstmtUpdate, colNumber++, SQL_PARAM_INPUT, colDefs[i].SqlCtype, + fSqlType, precision, scale, (UCHAR*) colDefs[i].PtrDataObj, + precision+1, &colDefs[i].CbValue) != SQL_SUCCESS) + { + return(pDb->DispAllErrors(henv, hdbc, hstmtUpdate)); + } + } + else + { + if (SQLBindParameter(hstmtInsert, colNumber++, SQL_PARAM_INPUT, colDefs[i].SqlCtype, + fSqlType, precision, scale, (UCHAR*) colDefs[i].PtrDataObj, + precision+1, &colDefs[i].CbValue) != SQL_SUCCESS) + { + return(pDb->DispAllErrors(henv, hdbc, hstmtInsert)); + } + } + } + + // Completed successfully + return true; + +} // wxDbTable::bindParams() + + +/********** wxDbTable::bindInsertParams() **********/ +bool wxDbTable::bindInsertParams(void) +{ + return bindParams(false); +} // wxDbTable::bindInsertParams() + + +/********** wxDbTable::bindUpdateParams() **********/ +bool wxDbTable::bindUpdateParams(void) +{ + return bindParams(true); +} // wxDbTable::bindUpdateParams() + + +/********** wxDbTable::bindCols() **********/ +bool wxDbTable::bindCols(HSTMT cursor) +{ + // Bind each column of the table to a memory address for fetching data + UWORD i; + for (i = 0; i < m_numCols; i++) + { + if (SQLBindCol(cursor, (UWORD)(i+1), colDefs[i].SqlCtype, (UCHAR*) colDefs[i].PtrDataObj, + colDefs[i].SzDataObj, &colDefs[i].CbValue ) != SQL_SUCCESS) + return (pDb->DispAllErrors(henv, hdbc, cursor)); + } + + // Completed successfully + return true; +} // wxDbTable::bindCols() + + +/********** wxDbTable::getRec() **********/ +bool wxDbTable::getRec(UWORD fetchType) +{ + RETCODE retcode; + + if (!pDb->FwdOnlyCursors()) + { + // Fetch the NEXT, PREV, FIRST or LAST record, depending on fetchType + SQLULEN cRowsFetched; + UWORD rowStatus; + + retcode = SQLExtendedFetch(hstmt, fetchType, 0, &cRowsFetched, &rowStatus); + if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO) + { + if (retcode == SQL_NO_DATA_FOUND) + return false; + else + return(pDb->DispAllErrors(henv, hdbc, hstmt)); + } + else + { + // Set the Null member variable to indicate the Null state + // of each column just read in. + int i; + for (i = 0; i < m_numCols; i++) + colDefs[i].Null = (colDefs[i].CbValue == SQL_NULL_DATA); + } + } + else + { + // Fetch the next record from the record set + retcode = SQLFetch(hstmt); + if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO) + { + if (retcode == SQL_NO_DATA_FOUND) + return false; + else + return(pDb->DispAllErrors(henv, hdbc, hstmt)); + } + else + { + // Set the Null member variable to indicate the Null state + // of each column just read in. + int i; + for (i = 0; i < m_numCols; i++) + colDefs[i].Null = (colDefs[i].CbValue == SQL_NULL_DATA); + } + } + + // Completed successfully + return true; + +} // wxDbTable::getRec() + + +/********** wxDbTable::execDelete() **********/ +bool wxDbTable::execDelete(const wxString &pSqlStmt) +{ + RETCODE retcode; + + // Execute the DELETE statement + retcode = SQLExecDirect(hstmtDelete, (SQLTCHAR FAR *) pSqlStmt.c_str(), SQL_NTS); + + if (retcode == SQL_SUCCESS || + retcode == SQL_NO_DATA_FOUND || + retcode == SQL_SUCCESS_WITH_INFO) + { + // Record deleted successfully + return true; + } + + // Problem deleting record + return(pDb->DispAllErrors(henv, hdbc, hstmtDelete)); + +} // wxDbTable::execDelete() + + +/********** wxDbTable::execUpdate() **********/ +bool wxDbTable::execUpdate(const wxString &pSqlStmt) +{ + RETCODE retcode; + + // Execute the UPDATE statement + retcode = SQLExecDirect(hstmtUpdate, (SQLTCHAR FAR *) pSqlStmt.c_str(), SQL_NTS); + + if (retcode == SQL_SUCCESS || + retcode == SQL_NO_DATA_FOUND || + retcode == SQL_SUCCESS_WITH_INFO) + { + // Record updated successfully + return true; + } + else if (retcode == SQL_NEED_DATA) + { + PTR pParmID; + retcode = SQLParamData(hstmtUpdate, &pParmID); + while (retcode == SQL_NEED_DATA) + { + // Find the parameter + int i; + for (i=0; i < m_numCols; i++) + { + if (colDefs[i].PtrDataObj == pParmID) + { + // We found it. Store the parameter. + retcode = SQLPutData(hstmtUpdate, pParmID, colDefs[i].SzDataObj); + if (retcode != SQL_SUCCESS) + { + pDb->DispNextError(); + return pDb->DispAllErrors(henv, hdbc, hstmtUpdate); + } + break; + } + } + retcode = SQLParamData(hstmtUpdate, &pParmID); + } + if (retcode == SQL_SUCCESS || + retcode == SQL_NO_DATA_FOUND || + retcode == SQL_SUCCESS_WITH_INFO) + { + // Record updated successfully + return true; + } + } + + // Problem updating record + return(pDb->DispAllErrors(henv, hdbc, hstmtUpdate)); + +} // wxDbTable::execUpdate() + + +/********** wxDbTable::query() **********/ +bool wxDbTable::query(int queryType, bool forUpdate, bool distinct, const wxString &pSqlStmt) +{ + wxString sqlStmt; + + if (forUpdate) + // The user may wish to select for update, but the DBMS may not be capable + selectForUpdate = CanSelectForUpdate(); + else + selectForUpdate = false; + + // Set the SQL SELECT string + if (queryType != DB_SELECT_STATEMENT) // A select statement was not passed in, + { // so generate a select statement. + BuildSelectStmt(sqlStmt, queryType, distinct); + pDb->WriteSqlLog(sqlStmt); + } + + // Make sure the cursor is closed first + if (!CloseCursor(hstmt)) + return false; + + // Execute the SQL SELECT statement + int retcode; + retcode = SQLExecDirect(hstmt, (SQLTCHAR FAR *) (queryType == DB_SELECT_STATEMENT ? pSqlStmt.c_str() : sqlStmt.c_str()), SQL_NTS); + if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO) + return(pDb->DispAllErrors(henv, hdbc, hstmt)); + + // Completed successfully + return true; + +} // wxDbTable::query() + + +/***************************** PUBLIC FUNCTIONS *****************************/ + + +/********** wxDbTable::Open() **********/ +bool wxDbTable::Open(bool checkPrivileges, bool checkTableExists) +{ + if (!pDb) + return false; + + int i; + wxString sqlStmt; + wxString s; + + // Calculate the maximum size of the concatenated + // keys for use with wxDbGrid + m_keysize = 0; + for (i=0; i < m_numCols; i++) + { + if (colDefs[i].KeyField) + { + m_keysize += colDefs[i].SzDataObj; + } + } + + s.Empty(); + + bool exists = true; + if (checkTableExists) + { + if (pDb->Dbms() == dbmsPOSTGRES) + exists = pDb->TableExists(tableName, NULL, tablePath); + else + exists = pDb->TableExists(tableName, pDb->GetUsername(), tablePath); + } + + // Verify that the table exists in the database + if (!exists) + { + s = wxT("Table/view does not exist in the database"); + if ( *(pDb->dbInf.accessibleTables) == wxT('Y')) + s += wxT(", or you have no permissions.\n"); + else + s += wxT(".\n"); + } + else if (checkPrivileges) + { + // Verify the user has rights to access the table. + bool hasPrivs wxDUMMY_INITIALIZE(true); + + if (pDb->Dbms() == dbmsPOSTGRES) + hasPrivs = pDb->TablePrivileges(tableName, wxT("SELECT"), pDb->GetUsername(), NULL, tablePath); + else + hasPrivs = pDb->TablePrivileges(tableName, wxT("SELECT"), pDb->GetUsername(), pDb->GetUsername(), tablePath); + + if (!hasPrivs) + s = wxT("Connecting user does not have sufficient privileges to access this table.\n"); + } + + if (!s.empty()) + { + wxString p; + + if (!tablePath.empty()) + p.Printf(wxT("Error opening '%s/%s'.\n"),tablePath.c_str(),tableName.c_str()); + else + p.Printf(wxT("Error opening '%s'.\n"), tableName.c_str()); + + p += s; + pDb->LogError(p.GetData()); + + return false; + } + + // Bind the member variables for field exchange between + // the wxDbTable object and the ODBC record. + if (!queryOnly) + { + if (!bindInsertParams()) // Inserts + return false; + + if (!bindUpdateParams()) // Updates + return false; + } + + if (!bindCols(*hstmtDefault)) // Selects + return false; + + if (!bindCols(hstmtInternal)) // Internal use only + return false; + + /* + * Do NOT bind the hstmtCount cursor!!! + */ + + // Build an insert statement using parameter markers + if (!queryOnly && m_numCols > 0) + { + bool needComma = false; + sqlStmt.Printf(wxT("INSERT INTO %s ("), + pDb->SQLTableName(tableName.c_str()).c_str()); + for (i = 0; i < m_numCols; i++) + { + if (! colDefs[i].InsertAllowed) + continue; + if (needComma) + sqlStmt += wxT(","); + sqlStmt += pDb->SQLColumnName(colDefs[i].ColName); + needComma = true; + } + needComma = false; + sqlStmt += wxT(") VALUES ("); + + int insertableCount = 0; + + for (i = 0; i < m_numCols; i++) + { + if (! colDefs[i].InsertAllowed) + continue; + if (needComma) + sqlStmt += wxT(","); + sqlStmt += wxT("?"); + needComma = true; + insertableCount++; + } + sqlStmt += wxT(")"); + + // Prepare the insert statement for execution + if (insertableCount) + { + if (SQLPrepare(hstmtInsert, (SQLTCHAR FAR *) sqlStmt.c_str(), SQL_NTS) != SQL_SUCCESS) + return(pDb->DispAllErrors(henv, hdbc, hstmtInsert)); + } + else + insertable = false; + } + + // Completed successfully + return true; + +} // wxDbTable::Open() + + +/********** wxDbTable::Query() **********/ +bool wxDbTable::Query(bool forUpdate, bool distinct) +{ + + return(query(DB_SELECT_WHERE, forUpdate, distinct)); + +} // wxDbTable::Query() + + +/********** wxDbTable::QueryBySqlStmt() **********/ +bool wxDbTable::QueryBySqlStmt(const wxString &pSqlStmt) +{ + pDb->WriteSqlLog(pSqlStmt); + + return(query(DB_SELECT_STATEMENT, false, false, pSqlStmt)); + +} // wxDbTable::QueryBySqlStmt() + + +/********** wxDbTable::QueryMatching() **********/ +bool wxDbTable::QueryMatching(bool forUpdate, bool distinct) +{ + + return(query(DB_SELECT_MATCHING, forUpdate, distinct)); + +} // wxDbTable::QueryMatching() + + +/********** wxDbTable::QueryOnKeyFields() **********/ +bool wxDbTable::QueryOnKeyFields(bool forUpdate, bool distinct) +{ + + return(query(DB_SELECT_KEYFIELDS, forUpdate, distinct)); + +} // wxDbTable::QueryOnKeyFields() + + +/********** wxDbTable::GetPrev() **********/ +bool wxDbTable::GetPrev(void) +{ + if (pDb->FwdOnlyCursors()) + { + wxFAIL_MSG(wxT("GetPrev()::Backward scrolling cursors are not enabled for this instance of wxDbTable")); + return false; + } + else + return(getRec(SQL_FETCH_PRIOR)); + +} // wxDbTable::GetPrev() + + +/********** wxDbTable::operator-- **********/ +bool wxDbTable::operator--(int) +{ + if (pDb->FwdOnlyCursors()) + { + wxFAIL_MSG(wxT("operator--:Backward scrolling cursors are not enabled for this instance of wxDbTable")); + return false; + } + else + return(getRec(SQL_FETCH_PRIOR)); + +} // wxDbTable::operator-- + + +/********** wxDbTable::GetFirst() **********/ +bool wxDbTable::GetFirst(void) +{ + if (pDb->FwdOnlyCursors()) + { + wxFAIL_MSG(wxT("GetFirst():Backward scrolling cursors are not enabled for this instance of wxDbTable")); + return false; + } + else + return(getRec(SQL_FETCH_FIRST)); + +} // wxDbTable::GetFirst() + + +/********** wxDbTable::GetLast() **********/ +bool wxDbTable::GetLast(void) +{ + if (pDb->FwdOnlyCursors()) + { + wxFAIL_MSG(wxT("GetLast()::Backward scrolling cursors are not enabled for this instance of wxDbTable")); + return false; + } + else + return(getRec(SQL_FETCH_LAST)); + +} // wxDbTable::GetLast() + + +/********** wxDbTable::BuildDeleteStmt() **********/ +void wxDbTable::BuildDeleteStmt(wxString &pSqlStmt, int typeOfDel, const wxString &pWhereClause) +{ + wxASSERT(!queryOnly); + if (queryOnly) + return; + + wxString whereClause; + + whereClause.Empty(); + + // Handle the case of DeleteWhere() and the where clause is blank. It should + // delete all records from the database in this case. + if (typeOfDel == DB_DEL_WHERE && (pWhereClause.length() == 0)) + { + pSqlStmt.Printf(wxT("DELETE FROM %s"), + pDb->SQLTableName(tableName.c_str()).c_str()); + return; + } + + pSqlStmt.Printf(wxT("DELETE FROM %s WHERE "), + pDb->SQLTableName(tableName.c_str()).c_str()); + + // Append the WHERE clause to the SQL DELETE statement + switch(typeOfDel) + { + case DB_DEL_KEYFIELDS: + // If the datasource supports the ROWID column, build + // the where on ROWID for efficiency purposes. + // e.g. DELETE FROM PARTS WHERE ROWID = '111.222.333' + if (CanUpdateByROWID()) + { + SQLLEN cb; + wxChar rowid[wxDB_ROWID_LEN+1]; + + // Get the ROWID value. If not successful retreiving the ROWID, + // simply fall down through the code and build the WHERE clause + // based on the key fields. + if (SQLGetData(hstmt, (UWORD)(m_numCols+1), SQL_C_WXCHAR, (UCHAR*) rowid, sizeof(rowid), &cb) == SQL_SUCCESS) + { + pSqlStmt += wxT("ROWID = '"); + pSqlStmt += rowid; + pSqlStmt += wxT("'"); + break; + } + } + // Unable to delete by ROWID, so build a WHERE + // clause based on the keyfields. + BuildWhereClause(whereClause, DB_WHERE_KEYFIELDS); + pSqlStmt += whereClause; + break; + case DB_DEL_WHERE: + pSqlStmt += pWhereClause; + break; + case DB_DEL_MATCHING: + BuildWhereClause(whereClause, DB_WHERE_MATCHING); + pSqlStmt += whereClause; + break; + } + +} // BuildDeleteStmt() + + +/***** DEPRECATED: use wxDbTable::BuildDeleteStmt(wxString &....) form *****/ +void wxDbTable::BuildDeleteStmt(wxChar *pSqlStmt, int typeOfDel, const wxString &pWhereClause) +{ + wxString tempSqlStmt; + BuildDeleteStmt(tempSqlStmt, typeOfDel, pWhereClause); + wxStrcpy(pSqlStmt, tempSqlStmt); +} // wxDbTable::BuildDeleteStmt() + + +/********** wxDbTable::BuildSelectStmt() **********/ +void wxDbTable::BuildSelectStmt(wxString &pSqlStmt, int typeOfSelect, bool distinct) +{ + wxString whereClause; + whereClause.Empty(); + + // Build a select statement to query the database + pSqlStmt = wxT("SELECT "); + + // SELECT DISTINCT values only? + if (distinct) + pSqlStmt += wxT("DISTINCT "); + + // Was a FROM clause specified to join tables to the base table? + // Available for ::Query() only!!! + bool appendFromClause = false; +#if wxODBC_BACKWARD_COMPATABILITY + if (typeOfSelect == DB_SELECT_WHERE && from && wxStrlen(from)) + appendFromClause = true; +#else + if (typeOfSelect == DB_SELECT_WHERE && from.length()) + appendFromClause = true; +#endif + + // Add the column list + int i; + wxString tStr; + for (i = 0; i < m_numCols; i++) + { + tStr = colDefs[i].ColName; + // If joining tables, the base table column names must be qualified to avoid ambiguity + if ((appendFromClause || pDb->Dbms() == dbmsACCESS) && tStr.Find(wxT('.')) == wxNOT_FOUND) + { + pSqlStmt += pDb->SQLTableName(queryTableName.c_str()); + pSqlStmt += wxT("."); + } + pSqlStmt += pDb->SQLColumnName(colDefs[i].ColName); + if (i + 1 < m_numCols) + pSqlStmt += wxT(","); + } + + // If the datasource supports ROWID, get this column as well. Exception: Don't retrieve + // the ROWID if querying distinct records. The rowid will always be unique. + if (!distinct && CanUpdateByROWID()) + { + // If joining tables, the base table column names must be qualified to avoid ambiguity + if (appendFromClause || pDb->Dbms() == dbmsACCESS) + { + pSqlStmt += wxT(","); + pSqlStmt += pDb->SQLTableName(queryTableName); + pSqlStmt += wxT(".ROWID"); + } + else + pSqlStmt += wxT(",ROWID"); + } + + // Append the FROM tablename portion + pSqlStmt += wxT(" FROM "); + pSqlStmt += pDb->SQLTableName(queryTableName); +// pSqlStmt += queryTableName; + + // Sybase uses the HOLDLOCK keyword to lock a record during query. + // The HOLDLOCK keyword follows the table name in the from clause. + // Each table in the from clause must specify HOLDLOCK or + // NOHOLDLOCK (the default). Note: The "FOR UPDATE" clause + // is parsed but ignored in SYBASE Transact-SQL. + if (selectForUpdate && (pDb->Dbms() == dbmsSYBASE_ASA || pDb->Dbms() == dbmsSYBASE_ASE)) + pSqlStmt += wxT(" HOLDLOCK"); + + if (appendFromClause) + pSqlStmt += from; + + // Append the WHERE clause. Either append the where clause for the class + // or build a where clause. The typeOfSelect determines this. + switch(typeOfSelect) + { + case DB_SELECT_WHERE: +#if wxODBC_BACKWARD_COMPATABILITY + if (where && wxStrlen(where)) // May not want a where clause!!! +#else + if (where.length()) // May not want a where clause!!! +#endif + { + pSqlStmt += wxT(" WHERE "); + pSqlStmt += where; + } + break; + case DB_SELECT_KEYFIELDS: + BuildWhereClause(whereClause, DB_WHERE_KEYFIELDS); + if (whereClause.length()) + { + pSqlStmt += wxT(" WHERE "); + pSqlStmt += whereClause; + } + break; + case DB_SELECT_MATCHING: + BuildWhereClause(whereClause, DB_WHERE_MATCHING); + if (whereClause.length()) + { + pSqlStmt += wxT(" WHERE "); + pSqlStmt += whereClause; + } + break; + } + + // Append the ORDER BY clause +#if wxODBC_BACKWARD_COMPATABILITY + if (orderBy && wxStrlen(orderBy)) +#else + if (orderBy.length()) +#endif + { + pSqlStmt += wxT(" ORDER BY "); + pSqlStmt += orderBy; + } + + // SELECT FOR UPDATE if told to do so and the datasource is capable. Sybase + // parses the FOR UPDATE clause but ignores it. See the comment above on the + // HOLDLOCK for Sybase. + if (selectForUpdate && CanSelectForUpdate()) + pSqlStmt += wxT(" FOR UPDATE"); + +} // wxDbTable::BuildSelectStmt() + + +/***** DEPRECATED: use wxDbTable::BuildSelectStmt(wxString &....) form *****/ +void wxDbTable::BuildSelectStmt(wxChar *pSqlStmt, int typeOfSelect, bool distinct) +{ + wxString tempSqlStmt; + BuildSelectStmt(tempSqlStmt, typeOfSelect, distinct); + wxStrcpy(pSqlStmt, tempSqlStmt); +} // wxDbTable::BuildSelectStmt() + + +/********** wxDbTable::BuildUpdateStmt() **********/ +void wxDbTable::BuildUpdateStmt(wxString &pSqlStmt, int typeOfUpdate, const wxString &pWhereClause) +{ + wxASSERT(!queryOnly); + if (queryOnly) + return; + + wxString whereClause; + whereClause.Empty(); + + bool firstColumn = true; + + pSqlStmt.Printf(wxT("UPDATE %s SET "), + pDb->SQLTableName(tableName.c_str()).c_str()); + + // Append a list of columns to be updated + int i; + for (i = 0; i < m_numCols; i++) + { + // Only append Updateable columns + if (colDefs[i].Updateable) + { + if (!firstColumn) + pSqlStmt += wxT(","); + else + firstColumn = false; + + pSqlStmt += pDb->SQLColumnName(colDefs[i].ColName); +// pSqlStmt += colDefs[i].ColName; + pSqlStmt += wxT(" = ?"); + } + } + + // Append the WHERE clause to the SQL UPDATE statement + pSqlStmt += wxT(" WHERE "); + switch(typeOfUpdate) + { + case DB_UPD_KEYFIELDS: + // If the datasource supports the ROWID column, build + // the where on ROWID for efficiency purposes. + // e.g. UPDATE PARTS SET Col1 = ?, Col2 = ? WHERE ROWID = '111.222.333' + if (CanUpdateByROWID()) + { + SQLLEN cb; + wxChar rowid[wxDB_ROWID_LEN+1]; + + // Get the ROWID value. If not successful retreiving the ROWID, + // simply fall down through the code and build the WHERE clause + // based on the key fields. + if (SQLGetData(hstmt, (UWORD)(m_numCols+1), SQL_C_WXCHAR, (UCHAR*) rowid, sizeof(rowid), &cb) == SQL_SUCCESS) + { + pSqlStmt += wxT("ROWID = '"); + pSqlStmt += rowid; + pSqlStmt += wxT("'"); + break; + } + } + // Unable to delete by ROWID, so build a WHERE + // clause based on the keyfields. + BuildWhereClause(whereClause, DB_WHERE_KEYFIELDS); + pSqlStmt += whereClause; + break; + case DB_UPD_WHERE: + pSqlStmt += pWhereClause; + break; + } +} // BuildUpdateStmt() + + +/***** DEPRECATED: use wxDbTable::BuildUpdateStmt(wxString &....) form *****/ +void wxDbTable::BuildUpdateStmt(wxChar *pSqlStmt, int typeOfUpdate, const wxString &pWhereClause) +{ + wxString tempSqlStmt; + BuildUpdateStmt(tempSqlStmt, typeOfUpdate, pWhereClause); + wxStrcpy(pSqlStmt, tempSqlStmt); +} // BuildUpdateStmt() + + +/********** wxDbTable::BuildWhereClause() **********/ +void wxDbTable::BuildWhereClause(wxString &pWhereClause, int typeOfWhere, + const wxString &qualTableName, bool useLikeComparison) +/* + * Note: BuildWhereClause() currently ignores timestamp columns. + * They are not included as part of the where clause. + */ +{ + bool moreThanOneColumn = false; + wxString colValue; + + // Loop through the columns building a where clause as you go + int colNumber; + for (colNumber = 0; colNumber < m_numCols; colNumber++) + { + // Determine if this column should be included in the WHERE clause + if ((typeOfWhere == DB_WHERE_KEYFIELDS && colDefs[colNumber].KeyField) || + (typeOfWhere == DB_WHERE_MATCHING && (!IsColNull((UWORD)colNumber)))) + { + // Skip over timestamp columns + if (colDefs[colNumber].SqlCtype == SQL_C_TIMESTAMP) + continue; + // If there is more than 1 column, join them with the keyword "AND" + if (moreThanOneColumn) + pWhereClause += wxT(" AND "); + else + moreThanOneColumn = true; + + // Concatenate where phrase for the column + wxString tStr = colDefs[colNumber].ColName; + + if (qualTableName.length() && tStr.Find(wxT('.')) == wxNOT_FOUND) + { + pWhereClause += pDb->SQLTableName(qualTableName); + pWhereClause += wxT("."); + } + pWhereClause += pDb->SQLColumnName(colDefs[colNumber].ColName); + + if (useLikeComparison && (colDefs[colNumber].SqlCtype == SQL_C_WXCHAR)) + pWhereClause += wxT(" LIKE "); + else + pWhereClause += wxT(" = "); + + switch(colDefs[colNumber].SqlCtype) + { + case SQL_C_CHAR: +#ifdef SQL_C_WCHAR + case SQL_C_WCHAR: +#endif + //case SQL_C_WXCHAR: SQL_C_WXCHAR is covered by either SQL_C_CHAR or SQL_C_WCHAR + colValue.Printf(wxT("'%s'"), GetDb()->EscapeSqlChars((wxChar *)colDefs[colNumber].PtrDataObj).c_str()); + break; + case SQL_C_SHORT: + case SQL_C_SSHORT: + colValue.Printf(wxT("%hi"), *((SWORD *) colDefs[colNumber].PtrDataObj)); + break; + case SQL_C_USHORT: + colValue.Printf(wxT("%hu"), *((UWORD *) colDefs[colNumber].PtrDataObj)); + break; + case SQL_C_LONG: + case SQL_C_SLONG: + colValue.Printf(wxT("%li"), *((SDWORD *) colDefs[colNumber].PtrDataObj)); + break; + case SQL_C_ULONG: + colValue.Printf(wxT("%lu"), *((UDWORD *) colDefs[colNumber].PtrDataObj)); + break; + case SQL_C_FLOAT: + colValue.Printf(wxT("%.6f"), *((SFLOAT *) colDefs[colNumber].PtrDataObj)); + break; + case SQL_C_DOUBLE: + colValue.Printf(wxT("%.6f"), *((SDOUBLE *) colDefs[colNumber].PtrDataObj)); + break; + default: + { + wxString strMsg; + strMsg.Printf(wxT("wxDbTable::bindParams(): Unknown column type for colDefs %d colName %s"), + colNumber,colDefs[colNumber].ColName); + wxFAIL_MSG(strMsg.c_str()); + } + break; + } + pWhereClause += colValue; + } + } +} // wxDbTable::BuildWhereClause() + + +/***** DEPRECATED: use wxDbTable::BuildWhereClause(wxString &....) form *****/ +void wxDbTable::BuildWhereClause(wxChar *pWhereClause, int typeOfWhere, + const wxString &qualTableName, bool useLikeComparison) +{ + wxString tempSqlStmt; + BuildWhereClause(tempSqlStmt, typeOfWhere, qualTableName, useLikeComparison); + wxStrcpy(pWhereClause, tempSqlStmt); +} // wxDbTable::BuildWhereClause() + + +/********** wxDbTable::GetRowNum() **********/ +UWORD wxDbTable::GetRowNum(void) +{ + UDWORD rowNum; + + if (SQLGetStmtOption(hstmt, SQL_ROW_NUMBER, (UCHAR*) &rowNum) != SQL_SUCCESS) + { + pDb->DispAllErrors(henv, hdbc, hstmt); + return(0); + } + + // Completed successfully + return((UWORD) rowNum); + +} // wxDbTable::GetRowNum() + + +/********** wxDbTable::CloseCursor() **********/ +bool wxDbTable::CloseCursor(HSTMT cursor) +{ + if (SQLFreeStmt(cursor, SQL_CLOSE) != SQL_SUCCESS) + return(pDb->DispAllErrors(henv, hdbc, cursor)); + + // Completed successfully + return true; + +} // wxDbTable::CloseCursor() + + +/********** wxDbTable::CreateTable() **********/ +bool wxDbTable::CreateTable(bool attemptDrop) +{ + if (!pDb) + return false; + + int i, j; + wxString sqlStmt; + +#ifdef DBDEBUG_CONSOLE + cout << wxT("Creating Table ") << tableName << wxT("...") << endl; +#endif + + // Drop table first + if (attemptDrop && !DropTable()) + return false; + + // Create the table +#ifdef DBDEBUG_CONSOLE + for (i = 0; i < m_numCols; i++) + { + // Exclude derived columns since they are NOT part of the base table + if (colDefs[i].DerivedCol) + continue; + cout << i + 1 << wxT(": ") << colDefs[i].ColName << wxT("; "); + switch(colDefs[i].DbDataType) + { + case DB_DATA_TYPE_VARCHAR: + cout << pDb->GetTypeInfVarchar().TypeName << wxT("(") << (int)(colDefs[i].SzDataObj / sizeof(wxChar)) << wxT(")"); + break; + case DB_DATA_TYPE_MEMO: + cout << pDb->GetTypeInfMemo().TypeName; + break; + case DB_DATA_TYPE_INTEGER: + cout << pDb->GetTypeInfInteger().TypeName; + break; + case DB_DATA_TYPE_FLOAT: + cout << pDb->GetTypeInfFloat().TypeName; + break; + case DB_DATA_TYPE_DATE: + cout << pDb->GetTypeInfDate().TypeName; + break; + case DB_DATA_TYPE_BLOB: + cout << pDb->GetTypeInfBlob().TypeName; + break; + } + cout << endl; + } +#endif + + // Build a CREATE TABLE string from the colDefs structure. + bool needComma = false; + + sqlStmt.Printf(wxT("CREATE TABLE %s ("), + pDb->SQLTableName(tableName.c_str()).c_str()); + + for (i = 0; i < m_numCols; i++) + { + // Exclude derived columns since they are NOT part of the base table + if (colDefs[i].DerivedCol) + continue; + // Comma Delimiter + if (needComma) + sqlStmt += wxT(","); + // Column Name + sqlStmt += pDb->SQLColumnName(colDefs[i].ColName); +// sqlStmt += colDefs[i].ColName; + sqlStmt += wxT(" "); + // Column Type + switch(colDefs[i].DbDataType) + { + case DB_DATA_TYPE_VARCHAR: + sqlStmt += pDb->GetTypeInfVarchar().TypeName; + break; + case DB_DATA_TYPE_MEMO: + sqlStmt += pDb->GetTypeInfMemo().TypeName; + break; + case DB_DATA_TYPE_INTEGER: + sqlStmt += pDb->GetTypeInfInteger().TypeName; + break; + case DB_DATA_TYPE_FLOAT: + sqlStmt += pDb->GetTypeInfFloat().TypeName; + break; + case DB_DATA_TYPE_DATE: + sqlStmt += pDb->GetTypeInfDate().TypeName; + break; + case DB_DATA_TYPE_BLOB: + sqlStmt += pDb->GetTypeInfBlob().TypeName; + break; + } + // For varchars, append the size of the string + if (colDefs[i].DbDataType == DB_DATA_TYPE_VARCHAR && + (pDb->Dbms() != dbmsMY_SQL || pDb->GetTypeInfVarchar().TypeName != _T("text")))// || +// colDefs[i].DbDataType == DB_DATA_TYPE_BLOB) + { + wxString s; + s.Printf(wxT("(%d)"), (int)(colDefs[i].SzDataObj / sizeof(wxChar))); + sqlStmt += s; + } + + if (pDb->Dbms() == dbmsDB2 || + pDb->Dbms() == dbmsMY_SQL || + pDb->Dbms() == dbmsSYBASE_ASE || + pDb->Dbms() == dbmsINTERBASE || + pDb->Dbms() == dbmsFIREBIRD || + pDb->Dbms() == dbmsMS_SQL_SERVER) + { + if (colDefs[i].KeyField) + { + sqlStmt += wxT(" NOT NULL"); + } + } + + needComma = true; + } + // If there is a primary key defined, include it in the create statement + for (i = j = 0; i < m_numCols; i++) + { + if (colDefs[i].KeyField) + { + j++; + break; + } + } + if ( j && (pDb->Dbms() != dbmsDBASE) + && (pDb->Dbms() != dbmsXBASE_SEQUITER) ) // Found a keyfield + { + switch (pDb->Dbms()) + { + case dbmsACCESS: + case dbmsINFORMIX: + case dbmsSYBASE_ASA: + case dbmsSYBASE_ASE: + case dbmsMY_SQL: + case dbmsFIREBIRD: + { + // MySQL goes out on this one. We also declare the relevant key NON NULL above + sqlStmt += wxT(",PRIMARY KEY ("); + break; + } + default: + { + sqlStmt += wxT(",CONSTRAINT "); + // DB2 is limited to 18 characters for index names + if (pDb->Dbms() == dbmsDB2) + { + wxASSERT_MSG((tableName && wxStrlen(tableName) <= 13), wxT("DB2 table/index names must be no longer than 13 characters in length.\n\nTruncating table name to 13 characters.")); + sqlStmt += pDb->SQLTableName(tableName.substr(0, 13).c_str()); +// sqlStmt += tableName.substr(0, 13); + } + else + sqlStmt += pDb->SQLTableName(tableName.c_str()); +// sqlStmt += tableName; + + sqlStmt += wxT("_PIDX PRIMARY KEY ("); + break; + } + } + + // List column name(s) of column(s) comprising the primary key + for (i = j = 0; i < m_numCols; i++) + { + if (colDefs[i].KeyField) + { + if (j++) // Multi part key, comma separate names + sqlStmt += wxT(","); + sqlStmt += pDb->SQLColumnName(colDefs[i].ColName); + + if (pDb->Dbms() == dbmsMY_SQL && + colDefs[i].DbDataType == DB_DATA_TYPE_VARCHAR) + { + wxString s; + s.Printf(wxT("(%d)"), (int)(colDefs[i].SzDataObj / sizeof(wxChar))); + sqlStmt += s; + } + } + } + sqlStmt += wxT(")"); + + if (pDb->Dbms() == dbmsINFORMIX || + pDb->Dbms() == dbmsSYBASE_ASA || + pDb->Dbms() == dbmsSYBASE_ASE) + { + sqlStmt += wxT(" CONSTRAINT "); + sqlStmt += pDb->SQLTableName(tableName); +// sqlStmt += tableName; + sqlStmt += wxT("_PIDX"); + } + } + // Append the closing parentheses for the create table statement + sqlStmt += wxT(")"); + + pDb->WriteSqlLog(sqlStmt); + +#ifdef DBDEBUG_CONSOLE + cout << endl << sqlStmt.c_str() << endl; +#endif + + // Execute the CREATE TABLE statement + RETCODE retcode = SQLExecDirect(hstmt, (SQLTCHAR FAR *) sqlStmt.c_str(), SQL_NTS); + if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO) + { + pDb->DispAllErrors(henv, hdbc, hstmt); + pDb->RollbackTrans(); + CloseCursor(hstmt); + return false; + } + + // Commit the transaction and close the cursor + if (!pDb->CommitTrans()) + return false; + if (!CloseCursor(hstmt)) + return false; + + // Database table created successfully + return true; + +} // wxDbTable::CreateTable() + + +/********** wxDbTable::DropTable() **********/ +bool wxDbTable::DropTable() +{ + // NOTE: This function returns true if the Table does not exist, but + // only for identified databases. Code will need to be added + // below for any other databases when those databases are defined + // to handle this situation consistently + + wxString sqlStmt; + + sqlStmt.Printf(wxT("DROP TABLE %s"), + pDb->SQLTableName(tableName.c_str()).c_str()); + + pDb->WriteSqlLog(sqlStmt); + +#ifdef DBDEBUG_CONSOLE + cout << endl << sqlStmt.c_str() << endl; +#endif + + RETCODE retcode = SQLExecDirect(hstmt, (SQLTCHAR FAR *) sqlStmt.c_str(), SQL_NTS); + if (retcode != SQL_SUCCESS) + { + // Check for "Base table not found" error and ignore + pDb->GetNextError(henv, hdbc, hstmt); + if (wxStrcmp(pDb->sqlState, wxT("S0002")) /*&& + wxStrcmp(pDb->sqlState, wxT("S1000"))*/) // "Base table not found" + { + // Check for product specific error codes + if (!((pDb->Dbms() == dbmsSYBASE_ASA && !wxStrcmp(pDb->sqlState,wxT("42000"))) || // 5.x (and lower?) + (pDb->Dbms() == dbmsSYBASE_ASE && !wxStrcmp(pDb->sqlState,wxT("37000"))) || + (pDb->Dbms() == dbmsPERVASIVE_SQL && !wxStrcmp(pDb->sqlState,wxT("S1000"))) || // Returns an S1000 then an S0002 + (pDb->Dbms() == dbmsPOSTGRES && !wxStrcmp(pDb->sqlState,wxT("08S01"))))) + { + pDb->DispNextError(); + pDb->DispAllErrors(henv, hdbc, hstmt); + pDb->RollbackTrans(); +// CloseCursor(hstmt); + return false; + } + } + } + + // Commit the transaction and close the cursor + if (! pDb->CommitTrans()) + return false; + if (! CloseCursor(hstmt)) + return false; + + return true; +} // wxDbTable::DropTable() + + +/********** wxDbTable::CreateIndex() **********/ +bool wxDbTable::CreateIndex(const wxString &indexName, bool unique, UWORD numIndexColumns, + wxDbIdxDef *pIndexDefs, bool attemptDrop) +{ + wxString sqlStmt; + + // Drop the index first + if (attemptDrop && !DropIndex(indexName)) + return false; + + // MySQL (and possibly Sybase ASE?? - gt) require that any columns which are used as portions + // of an index have the columns defined as "NOT NULL". During initial table creation though, + // it may not be known which columns are necessarily going to be part of an index (e.g. the + // table was created, then months later you determine that an additional index while + // give better performance, so you want to add an index). + // + // The following block of code will modify the column definition to make the column be + // defined with the "NOT NULL" qualifier. + if (pDb->Dbms() == dbmsMY_SQL) + { + wxString sqlStmt; + int i; + bool ok = true; + for (i = 0; i < numIndexColumns && ok; i++) + { + int j = 0; + bool found = false; + // Find the column definition that has the ColName that matches the + // index column name. We need to do this to get the DB_DATA_TYPE of + // the index column, as MySQL's syntax for the ALTER column requires + // this information + while (!found && (j < this->m_numCols)) + { + if (wxStrcmp(colDefs[j].ColName,pIndexDefs[i].ColName) == 0) + found = true; + if (!found) + j++; + } + + if (found) + { + ok = pDb->ModifyColumn(tableName, pIndexDefs[i].ColName, + colDefs[j].DbDataType, (int)(colDefs[j].SzDataObj / sizeof(wxChar)), + wxT("NOT NULL")); + + if (!ok) + { + #if 0 + // retcode is not used + wxODBC_ERRORS retcode; + // Oracle returns a DB_ERR_GENERAL_ERROR if the column is already + // defined to be NOT NULL, but reportedly MySQL doesn't mind. + // This line is just here for debug checking of the value + retcode = (wxODBC_ERRORS)pDb->DB_STATUS; + #endif + } + } + else + ok = false; + } + if (ok) + pDb->CommitTrans(); + else + { + pDb->RollbackTrans(); + return false; + } + } + + // Build a CREATE INDEX statement + sqlStmt = wxT("CREATE "); + if (unique) + sqlStmt += wxT("UNIQUE "); + + sqlStmt += wxT("INDEX "); + sqlStmt += pDb->SQLTableName(indexName); + sqlStmt += wxT(" ON "); + + sqlStmt += pDb->SQLTableName(tableName); +// sqlStmt += tableName; + sqlStmt += wxT(" ("); + + // Append list of columns making up index + int i; + for (i = 0; i < numIndexColumns; i++) + { + sqlStmt += pDb->SQLColumnName(pIndexDefs[i].ColName); +// sqlStmt += pIndexDefs[i].ColName; + + // MySQL requires a key length on VARCHAR keys + if ( pDb->Dbms() == dbmsMY_SQL ) + { + // Find the details on this column + int j; + for ( j = 0; j < m_numCols; ++j ) + { + if ( wxStrcmp( pIndexDefs[i].ColName, colDefs[j].ColName ) == 0 ) + { + break; + } + } + if ( colDefs[j].DbDataType == DB_DATA_TYPE_VARCHAR) + { + wxString s; + s.Printf(wxT("(%d)"), (int)(colDefs[i].SzDataObj / sizeof(wxChar))); + sqlStmt += s; + } + } + + // Postgres and SQL Server 7 do not support the ASC/DESC keywords for index columns + if (!((pDb->Dbms() == dbmsMS_SQL_SERVER) && (wxStrncmp(pDb->dbInf.dbmsVer,_T("07"),2)==0)) && + !(pDb->Dbms() == dbmsFIREBIRD) && + !(pDb->Dbms() == dbmsPOSTGRES)) + { + if (pIndexDefs[i].Ascending) + sqlStmt += wxT(" ASC"); + else + sqlStmt += wxT(" DESC"); + } + else + wxASSERT_MSG(pIndexDefs[i].Ascending, _T("Datasource does not support DESCending index columns")); + + if ((i + 1) < numIndexColumns) + sqlStmt += wxT(","); + } + + // Append closing parentheses + sqlStmt += wxT(")"); + + pDb->WriteSqlLog(sqlStmt); + +#ifdef DBDEBUG_CONSOLE + cout << endl << sqlStmt.c_str() << endl << endl; +#endif + + // Execute the CREATE INDEX statement + RETCODE retcode = SQLExecDirect(hstmt, (SQLTCHAR FAR *) sqlStmt.c_str(), SQL_NTS); + if (retcode != SQL_SUCCESS) + { + pDb->DispAllErrors(henv, hdbc, hstmt); + pDb->RollbackTrans(); + CloseCursor(hstmt); + return false; + } + + // Commit the transaction and close the cursor + if (! pDb->CommitTrans()) + return false; + if (! CloseCursor(hstmt)) + return false; + + // Index Created Successfully + return true; + +} // wxDbTable::CreateIndex() + + +/********** wxDbTable::DropIndex() **********/ +bool wxDbTable::DropIndex(const wxString &indexName) +{ + // NOTE: This function returns true if the Index does not exist, but + // only for identified databases. Code will need to be added + // below for any other databases when those databases are defined + // to handle this situation consistently + + wxString sqlStmt; + + if (pDb->Dbms() == dbmsACCESS || pDb->Dbms() == dbmsMY_SQL || + pDb->Dbms() == dbmsDBASE /*|| Paradox needs this syntax too when we add support*/) + sqlStmt.Printf(wxT("DROP INDEX %s ON %s"), + pDb->SQLTableName(indexName.c_str()).c_str(), + pDb->SQLTableName(tableName.c_str()).c_str()); + else if ((pDb->Dbms() == dbmsMS_SQL_SERVER) || + (pDb->Dbms() == dbmsSYBASE_ASE) || + (pDb->Dbms() == dbmsXBASE_SEQUITER)) + sqlStmt.Printf(wxT("DROP INDEX %s.%s"), + pDb->SQLTableName(tableName.c_str()).c_str(), + pDb->SQLTableName(indexName.c_str()).c_str()); + else + sqlStmt.Printf(wxT("DROP INDEX %s"), + pDb->SQLTableName(indexName.c_str()).c_str()); + + pDb->WriteSqlLog(sqlStmt); + +#ifdef DBDEBUG_CONSOLE + cout << endl << sqlStmt.c_str() << endl; +#endif + RETCODE retcode = SQLExecDirect(hstmt, (SQLTCHAR FAR *) sqlStmt.c_str(), SQL_NTS); + if (retcode != SQL_SUCCESS) + { + // Check for "Index not found" error and ignore + pDb->GetNextError(henv, hdbc, hstmt); + if (wxStrcmp(pDb->sqlState,wxT("S0012"))) // "Index not found" + { + // Check for product specific error codes + if (!((pDb->Dbms() == dbmsSYBASE_ASA && !wxStrcmp(pDb->sqlState,wxT("42000"))) || // v5.x (and lower?) + (pDb->Dbms() == dbmsSYBASE_ASE && !wxStrcmp(pDb->sqlState,wxT("37000"))) || + (pDb->Dbms() == dbmsMS_SQL_SERVER && !wxStrcmp(pDb->sqlState,wxT("S1000"))) || + (pDb->Dbms() == dbmsINTERBASE && !wxStrcmp(pDb->sqlState,wxT("S1000"))) || + (pDb->Dbms() == dbmsMAXDB && !wxStrcmp(pDb->sqlState,wxT("S1000"))) || + (pDb->Dbms() == dbmsFIREBIRD && !wxStrcmp(pDb->sqlState,wxT("HY000"))) || + (pDb->Dbms() == dbmsSYBASE_ASE && !wxStrcmp(pDb->sqlState,wxT("S0002"))) || // Base table not found + (pDb->Dbms() == dbmsMY_SQL && !wxStrcmp(pDb->sqlState,wxT("42S12"))) || // tested by Christopher Ludwik Marino-Cebulski using v3.23.21beta + (pDb->Dbms() == dbmsPOSTGRES && !wxStrcmp(pDb->sqlState,wxT("08S01"))) + )) + { + pDb->DispNextError(); + pDb->DispAllErrors(henv, hdbc, hstmt); + pDb->RollbackTrans(); + CloseCursor(hstmt); + return false; + } + } + } + + // Commit the transaction and close the cursor + if (! pDb->CommitTrans()) + return false; + if (! CloseCursor(hstmt)) + return false; + + return true; +} // wxDbTable::DropIndex() + + +/********** wxDbTable::SetOrderByColNums() **********/ +bool wxDbTable::SetOrderByColNums(UWORD first, ... ) +{ + int colNumber = first; // using 'int' to be able to look for wxDB_NO_MORE_COLUN_NUMBERS + va_list argptr; + + bool abort = false; + wxString tempStr; + + va_start(argptr, first); /* Initialize variable arguments. */ + while (!abort && (colNumber != wxDB_NO_MORE_COLUMN_NUMBERS)) + { + // Make sure the passed in column number + // is within the valid range of columns + // + // Valid columns are 0 thru m_numCols-1 + if (colNumber >= m_numCols || colNumber < 0) + { + abort = true; + continue; + } + + if (colNumber != first) + tempStr += wxT(","); + + tempStr += colDefs[colNumber].ColName; + colNumber = va_arg (argptr, int); + } + va_end (argptr); /* Reset variable arguments. */ + + SetOrderByClause(tempStr); + + return (!abort); +} // wxDbTable::SetOrderByColNums() + + +/********** wxDbTable::Insert() **********/ +int wxDbTable::Insert(void) +{ + wxASSERT(!queryOnly); + if (queryOnly || !insertable) + return(DB_FAILURE); + + bindInsertParams(); + + // Insert the record by executing the already prepared insert statement + RETCODE retcode; + retcode = SQLExecute(hstmtInsert); + if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO && + retcode != SQL_NEED_DATA) + { + // Check to see if integrity constraint was violated + pDb->GetNextError(henv, hdbc, hstmtInsert); + if (! wxStrcmp(pDb->sqlState, wxT("23000"))) // Integrity constraint violated + return(DB_ERR_INTEGRITY_CONSTRAINT_VIOL); + else + { + pDb->DispNextError(); + pDb->DispAllErrors(henv, hdbc, hstmtInsert); + return(DB_FAILURE); + } + } + if (retcode == SQL_NEED_DATA) + { + PTR pParmID; + retcode = SQLParamData(hstmtInsert, &pParmID); + while (retcode == SQL_NEED_DATA) + { + // Find the parameter + int i; + for (i=0; i < m_numCols; i++) + { + if (colDefs[i].PtrDataObj == pParmID) + { + // We found it. Store the parameter. + retcode = SQLPutData(hstmtInsert, pParmID, colDefs[i].SzDataObj); + if (retcode != SQL_SUCCESS) + { + pDb->DispNextError(); + pDb->DispAllErrors(henv, hdbc, hstmtInsert); + return(DB_FAILURE); + } + break; + } + } + retcode = SQLParamData(hstmtInsert, &pParmID); + if (retcode != SQL_SUCCESS && + retcode != SQL_SUCCESS_WITH_INFO) + { + // record was not inserted + pDb->DispNextError(); + pDb->DispAllErrors(henv, hdbc, hstmtInsert); + return(DB_FAILURE); + } + } + } + + // Record inserted into the datasource successfully + return(DB_SUCCESS); + +} // wxDbTable::Insert() + + +/********** wxDbTable::Update() **********/ +bool wxDbTable::Update(void) +{ + wxASSERT(!queryOnly); + if (queryOnly) + return false; + + wxString sqlStmt; + + // Build the SQL UPDATE statement + BuildUpdateStmt(sqlStmt, DB_UPD_KEYFIELDS); + + pDb->WriteSqlLog(sqlStmt); + +#ifdef DBDEBUG_CONSOLE + cout << endl << sqlStmt.c_str() << endl << endl; +#endif + + // Execute the SQL UPDATE statement + return(execUpdate(sqlStmt)); + +} // wxDbTable::Update() + + +/********** wxDbTable::Update(pSqlStmt) **********/ +bool wxDbTable::Update(const wxString &pSqlStmt) +{ + wxASSERT(!queryOnly); + if (queryOnly) + return false; + + pDb->WriteSqlLog(pSqlStmt); + + return(execUpdate(pSqlStmt)); + +} // wxDbTable::Update(pSqlStmt) + + +/********** wxDbTable::UpdateWhere() **********/ +bool wxDbTable::UpdateWhere(const wxString &pWhereClause) +{ + wxASSERT(!queryOnly); + if (queryOnly) + return false; + + wxString sqlStmt; + + // Build the SQL UPDATE statement + BuildUpdateStmt(sqlStmt, DB_UPD_WHERE, pWhereClause); + + pDb->WriteSqlLog(sqlStmt); + +#ifdef DBDEBUG_CONSOLE + cout << endl << sqlStmt.c_str() << endl << endl; +#endif + + // Execute the SQL UPDATE statement + return(execUpdate(sqlStmt)); + +} // wxDbTable::UpdateWhere() + + +/********** wxDbTable::Delete() **********/ +bool wxDbTable::Delete(void) +{ + wxASSERT(!queryOnly); + if (queryOnly) + return false; + + wxString sqlStmt; + sqlStmt.Empty(); + + // Build the SQL DELETE statement + BuildDeleteStmt(sqlStmt, DB_DEL_KEYFIELDS); + + pDb->WriteSqlLog(sqlStmt); + + // Execute the SQL DELETE statement + return(execDelete(sqlStmt)); + +} // wxDbTable::Delete() + + +/********** wxDbTable::DeleteWhere() **********/ +bool wxDbTable::DeleteWhere(const wxString &pWhereClause) +{ + wxASSERT(!queryOnly); + if (queryOnly) + return false; + + wxString sqlStmt; + sqlStmt.Empty(); + + // Build the SQL DELETE statement + BuildDeleteStmt(sqlStmt, DB_DEL_WHERE, pWhereClause); + + pDb->WriteSqlLog(sqlStmt); + + // Execute the SQL DELETE statement + return(execDelete(sqlStmt)); + +} // wxDbTable::DeleteWhere() + + +/********** wxDbTable::DeleteMatching() **********/ +bool wxDbTable::DeleteMatching(void) +{ + wxASSERT(!queryOnly); + if (queryOnly) + return false; + + wxString sqlStmt; + sqlStmt.Empty(); + + // Build the SQL DELETE statement + BuildDeleteStmt(sqlStmt, DB_DEL_MATCHING); + + pDb->WriteSqlLog(sqlStmt); + + // Execute the SQL DELETE statement + return(execDelete(sqlStmt)); + +} // wxDbTable::DeleteMatching() + + +/********** wxDbTable::IsColNull() **********/ +bool wxDbTable::IsColNull(UWORD colNumber) const +{ +/* + This logic is just not right. It would indicate true + if a numeric field were set to a value of 0. + + switch(colDefs[colNumber].SqlCtype) + { + case SQL_C_CHAR: + case SQL_C_WCHAR: + //case SQL_C_WXCHAR: SQL_C_WXCHAR is covered by either SQL_C_CHAR or SQL_C_WCHAR + return(((UCHAR FAR *) colDefs[colNumber].PtrDataObj)[0] == 0); + case SQL_C_SSHORT: + return(( *((SWORD *) colDefs[colNumber].PtrDataObj)) == 0); + case SQL_C_USHORT: + return(( *((UWORD*) colDefs[colNumber].PtrDataObj)) == 0); + case SQL_C_SLONG: + return(( *((SDWORD *) colDefs[colNumber].PtrDataObj)) == 0); + case SQL_C_ULONG: + return(( *((UDWORD *) colDefs[colNumber].PtrDataObj)) == 0); + case SQL_C_FLOAT: + return(( *((SFLOAT *) colDefs[colNumber].PtrDataObj)) == 0); + case SQL_C_DOUBLE: + return((*((SDOUBLE *) colDefs[colNumber].PtrDataObj)) == 0); + case SQL_C_TIMESTAMP: + TIMESTAMP_STRUCT *pDt; + pDt = (TIMESTAMP_STRUCT *) colDefs[colNumber].PtrDataObj; + if (pDt->year == 0 && pDt->month == 0 && pDt->day == 0) + return true; + else + return false; + default: + return true; + } +*/ + return (colDefs[colNumber].Null); +} // wxDbTable::IsColNull() + + +/********** wxDbTable::CanSelectForUpdate() **********/ +bool wxDbTable::CanSelectForUpdate(void) +{ + if (queryOnly) + return false; + + if (pDb->Dbms() == dbmsMY_SQL) + return false; + + if ((pDb->Dbms() == dbmsORACLE) || + (pDb->dbInf.posStmts & SQL_PS_SELECT_FOR_UPDATE)) + return true; + else + return false; + +} // wxDbTable::CanSelectForUpdate() + + +/********** wxDbTable::CanUpdateByROWID() **********/ +bool wxDbTable::CanUpdateByROWID(void) +{ +/* + * NOTE: Returning false for now until this can be debugged, + * as the ROWID is not getting updated correctly + */ + return false; +/* + if (pDb->Dbms() == dbmsORACLE) + return true; + else + return false; +*/ +} // wxDbTable::CanUpdateByROWID() + + +/********** wxDbTable::IsCursorClosedOnCommit() **********/ +bool wxDbTable::IsCursorClosedOnCommit(void) +{ + if (pDb->dbInf.cursorCommitBehavior == SQL_CB_PRESERVE) + return false; + else + return true; + +} // wxDbTable::IsCursorClosedOnCommit() + + + +/********** wxDbTable::ClearMemberVar() **********/ +void wxDbTable::ClearMemberVar(UWORD colNumber, bool setToNull) +{ + wxASSERT(colNumber < m_numCols); + + switch(colDefs[colNumber].SqlCtype) + { + case SQL_C_CHAR: +#ifdef SQL_C_WCHAR + case SQL_C_WCHAR: +#endif + //case SQL_C_WXCHAR: SQL_C_WXCHAR is covered by either SQL_C_CHAR or SQL_C_WCHAR + ((UCHAR FAR *) colDefs[colNumber].PtrDataObj)[0] = 0; + break; + case SQL_C_SSHORT: + *((SWORD *) colDefs[colNumber].PtrDataObj) = 0; + break; + case SQL_C_USHORT: + *((UWORD*) colDefs[colNumber].PtrDataObj) = 0; + break; + case SQL_C_LONG: + case SQL_C_SLONG: + *((SDWORD *) colDefs[colNumber].PtrDataObj) = 0; + break; + case SQL_C_ULONG: + *((UDWORD *) colDefs[colNumber].PtrDataObj) = 0; + break; + case SQL_C_FLOAT: + *((SFLOAT *) colDefs[colNumber].PtrDataObj) = 0.0f; + break; + case SQL_C_DOUBLE: + *((SDOUBLE *) colDefs[colNumber].PtrDataObj) = 0.0f; + break; + case SQL_C_TIMESTAMP: + TIMESTAMP_STRUCT *pDt; + pDt = (TIMESTAMP_STRUCT *) colDefs[colNumber].PtrDataObj; + pDt->year = 0; + pDt->month = 0; + pDt->day = 0; + pDt->hour = 0; + pDt->minute = 0; + pDt->second = 0; + pDt->fraction = 0; + break; + case SQL_C_DATE: + DATE_STRUCT *pDtd; + pDtd = (DATE_STRUCT *) colDefs[colNumber].PtrDataObj; + pDtd->year = 0; + pDtd->month = 0; + pDtd->day = 0; + break; + case SQL_C_TIME: + TIME_STRUCT *pDtt; + pDtt = (TIME_STRUCT *) colDefs[colNumber].PtrDataObj; + pDtt->hour = 0; + pDtt->minute = 0; + pDtt->second = 0; + break; + } + + if (setToNull) + SetColNull(colNumber); +} // wxDbTable::ClearMemberVar() + + +/********** wxDbTable::ClearMemberVars() **********/ +void wxDbTable::ClearMemberVars(bool setToNull) +{ + int i; + + // Loop through the columns setting each member variable to zero + for (i=0; i < m_numCols; i++) + ClearMemberVar((UWORD)i,setToNull); + +} // wxDbTable::ClearMemberVars() + + +/********** wxDbTable::SetQueryTimeout() **********/ +bool wxDbTable::SetQueryTimeout(UDWORD nSeconds) +{ + if (SQLSetStmtOption(hstmtInsert, SQL_QUERY_TIMEOUT, nSeconds) != SQL_SUCCESS) + return(pDb->DispAllErrors(henv, hdbc, hstmtInsert)); + if (SQLSetStmtOption(hstmtUpdate, SQL_QUERY_TIMEOUT, nSeconds) != SQL_SUCCESS) + return(pDb->DispAllErrors(henv, hdbc, hstmtUpdate)); + if (SQLSetStmtOption(hstmtDelete, SQL_QUERY_TIMEOUT, nSeconds) != SQL_SUCCESS) + return(pDb->DispAllErrors(henv, hdbc, hstmtDelete)); + if (SQLSetStmtOption(hstmtInternal, SQL_QUERY_TIMEOUT, nSeconds) != SQL_SUCCESS) + return(pDb->DispAllErrors(henv, hdbc, hstmtInternal)); + + // Completed Successfully + return true; + +} // wxDbTable::SetQueryTimeout() + + +/********** wxDbTable::SetColDefs() **********/ +bool wxDbTable::SetColDefs(UWORD index, const wxString &fieldName, int dataType, void *pData, + SWORD cType, int size, bool keyField, bool updateable, + bool insertAllowed, bool derivedColumn) +{ + wxString tmpStr; + + if (index >= m_numCols) // Columns numbers are zero based.... + { + tmpStr.Printf(wxT("Specified column index (%d) exceeds the maximum number of columns (%d) registered for this table definition. Column definition not added."), index, m_numCols); + wxFAIL_MSG(tmpStr); + wxLogDebug(tmpStr); + return false; + } + + if (!colDefs) // May happen if the database connection fails + return false; + + if (fieldName.length() > (unsigned int) DB_MAX_COLUMN_NAME_LEN) + { + wxStrncpy(colDefs[index].ColName, fieldName, DB_MAX_COLUMN_NAME_LEN); + colDefs[index].ColName[DB_MAX_COLUMN_NAME_LEN] = 0; // Prevent buffer overrun + + tmpStr.Printf(wxT("Column name '%s' is too long. Truncated to '%s'."), + fieldName.c_str(),colDefs[index].ColName); + wxFAIL_MSG(tmpStr); + wxLogDebug(tmpStr); + } + else + wxStrcpy(colDefs[index].ColName, fieldName); + + colDefs[index].DbDataType = dataType; + colDefs[index].PtrDataObj = pData; + colDefs[index].SqlCtype = cType; + colDefs[index].SzDataObj = size; //TODO: glt ??? * sizeof(wxChar) ??? + colDefs[index].KeyField = keyField; + colDefs[index].DerivedCol = derivedColumn; + // Derived columns by definition would NOT be "Insertable" or "Updateable" + if (derivedColumn) + { + colDefs[index].Updateable = false; + colDefs[index].InsertAllowed = false; + } + else + { + colDefs[index].Updateable = updateable; + colDefs[index].InsertAllowed = insertAllowed; + } + + colDefs[index].Null = false; + + return true; + +} // wxDbTable::SetColDefs() + + +/********** wxDbTable::SetColDefs() **********/ +wxDbColDataPtr* wxDbTable::SetColDefs(wxDbColInf *pColInfs, UWORD numCols) +{ + wxASSERT(pColInfs); + wxDbColDataPtr *pColDataPtrs = NULL; + + if (pColInfs) + { + UWORD index; + + pColDataPtrs = new wxDbColDataPtr[numCols+1]; + + for (index = 0; index < numCols; index++) + { + // Process the fields + switch (pColInfs[index].dbDataType) + { + case DB_DATA_TYPE_VARCHAR: + pColDataPtrs[index].PtrDataObj = new wxChar[pColInfs[index].bufferSize+(1*sizeof(wxChar))]; + pColDataPtrs[index].SzDataObj = pColInfs[index].bufferSize+(1*sizeof(wxChar)); + pColDataPtrs[index].SqlCtype = SQL_C_WXCHAR; + break; + case DB_DATA_TYPE_MEMO: + pColDataPtrs[index].PtrDataObj = new wxChar[pColInfs[index].bufferSize+(1*sizeof(wxChar))]; + pColDataPtrs[index].SzDataObj = pColInfs[index].bufferSize+(1*sizeof(wxChar)); + pColDataPtrs[index].SqlCtype = SQL_C_WXCHAR; + break; + case DB_DATA_TYPE_INTEGER: + // Can be long or short + if (pColInfs[index].bufferSize == sizeof(long)) + { + pColDataPtrs[index].PtrDataObj = new long; + pColDataPtrs[index].SzDataObj = sizeof(long); + pColDataPtrs[index].SqlCtype = SQL_C_SLONG; + } + else + { + pColDataPtrs[index].PtrDataObj = new short; + pColDataPtrs[index].SzDataObj = sizeof(short); + pColDataPtrs[index].SqlCtype = SQL_C_SSHORT; + } + break; + case DB_DATA_TYPE_FLOAT: + // Can be float or double + if (pColInfs[index].bufferSize == sizeof(float)) + { + pColDataPtrs[index].PtrDataObj = new float; + pColDataPtrs[index].SzDataObj = sizeof(float); + pColDataPtrs[index].SqlCtype = SQL_C_FLOAT; + } + else + { + pColDataPtrs[index].PtrDataObj = new double; + pColDataPtrs[index].SzDataObj = sizeof(double); + pColDataPtrs[index].SqlCtype = SQL_C_DOUBLE; + } + break; + case DB_DATA_TYPE_DATE: + pColDataPtrs[index].PtrDataObj = new TIMESTAMP_STRUCT; + pColDataPtrs[index].SzDataObj = sizeof(TIMESTAMP_STRUCT); + pColDataPtrs[index].SqlCtype = SQL_C_TIMESTAMP; + break; + case DB_DATA_TYPE_BLOB: + wxFAIL_MSG(wxT("This form of ::SetColDefs() cannot be used with BLOB columns")); + pColDataPtrs[index].PtrDataObj = /*BLOB ADDITION NEEDED*/NULL; + pColDataPtrs[index].SzDataObj = /*BLOB ADDITION NEEDED*/sizeof(void *); + pColDataPtrs[index].SqlCtype = SQL_VARBINARY; + break; + } + if (pColDataPtrs[index].PtrDataObj != NULL) + SetColDefs (index,pColInfs[index].colName,pColInfs[index].dbDataType, pColDataPtrs[index].PtrDataObj, pColDataPtrs[index].SqlCtype, pColDataPtrs[index].SzDataObj); + else + { + // Unable to build all the column definitions, as either one of + // the calls to "new" failed above, or there was a BLOB field + // to have a column definition for. If BLOBs are to be used, + // the other form of ::SetColDefs() must be used, as it is impossible + // to know the maximum size to create the PtrDataObj to be. + delete [] pColDataPtrs; + return NULL; + } + } + } + + return (pColDataPtrs); + +} // wxDbTable::SetColDefs() + + +/********** wxDbTable::SetCursor() **********/ +void wxDbTable::SetCursor(HSTMT *hstmtActivate) +{ + if (hstmtActivate == wxDB_DEFAULT_CURSOR) + hstmt = *hstmtDefault; + else + hstmt = *hstmtActivate; + +} // wxDbTable::SetCursor() + + +/********** wxDbTable::Count(const wxString &) **********/ +ULONG wxDbTable::Count(const wxString &args) +{ + ULONG count; + wxString sqlStmt; + SQLLEN cb; + + // Build a "SELECT COUNT(*) FROM queryTableName [WHERE whereClause]" SQL Statement + sqlStmt = wxT("SELECT COUNT("); + sqlStmt += args; + sqlStmt += wxT(") FROM "); + sqlStmt += pDb->SQLTableName(queryTableName); +// sqlStmt += queryTableName; +#if wxODBC_BACKWARD_COMPATABILITY + if (from && wxStrlen(from)) +#else + if (from.length()) +#endif + sqlStmt += from; + + // Add the where clause if one is provided +#if wxODBC_BACKWARD_COMPATABILITY + if (where && wxStrlen(where)) +#else + if (where.length()) +#endif + { + sqlStmt += wxT(" WHERE "); + sqlStmt += where; + } + + pDb->WriteSqlLog(sqlStmt); + + // Initialize the Count cursor if it's not already initialized + if (!hstmtCount) + { + hstmtCount = GetNewCursor(false,false); + wxASSERT(hstmtCount); + if (!hstmtCount) + return(0); + } + + // Execute the SQL statement + if (SQLExecDirect(*hstmtCount, (SQLTCHAR FAR *) sqlStmt.c_str(), SQL_NTS) != SQL_SUCCESS) + { + pDb->DispAllErrors(henv, hdbc, *hstmtCount); + return(0); + } + + // Fetch the record + if (SQLFetch(*hstmtCount) != SQL_SUCCESS) + { + pDb->DispAllErrors(henv, hdbc, *hstmtCount); + return(0); + } + + // Obtain the result + if (SQLGetData(*hstmtCount, (UWORD)1, SQL_C_ULONG, &count, sizeof(count), &cb) != SQL_SUCCESS) + { + pDb->DispAllErrors(henv, hdbc, *hstmtCount); + return(0); + } + + // Free the cursor + if (SQLFreeStmt(*hstmtCount, SQL_CLOSE) != SQL_SUCCESS) + pDb->DispAllErrors(henv, hdbc, *hstmtCount); + + // Return the record count + return(count); + +} // wxDbTable::Count() + + +/********** wxDbTable::Refresh() **********/ +bool wxDbTable::Refresh(void) +{ + bool result = true; + + // Switch to the internal cursor so any active cursors are not corrupted + HSTMT currCursor = GetCursor(); + hstmt = hstmtInternal; +#if wxODBC_BACKWARD_COMPATABILITY + // Save the where and order by clauses + wxChar *saveWhere = where; + wxChar *saveOrderBy = orderBy; +#else + wxString saveWhere = where; + wxString saveOrderBy = orderBy; +#endif + // Build a where clause to refetch the record with. Try and use the + // ROWID if it's available, ow use the key fields. + wxString whereClause; + whereClause.Empty(); + + if (CanUpdateByROWID()) + { + SQLLEN cb; + wxChar rowid[wxDB_ROWID_LEN+1]; + + // Get the ROWID value. If not successful retreiving the ROWID, + // simply fall down through the code and build the WHERE clause + // based on the key fields. + if (SQLGetData(hstmt, (UWORD)(m_numCols+1), SQL_C_WXCHAR, (UCHAR*) rowid, sizeof(rowid), &cb) == SQL_SUCCESS) + { + whereClause += pDb->SQLTableName(queryTableName); +// whereClause += queryTableName; + whereClause += wxT(".ROWID = '"); + whereClause += rowid; + whereClause += wxT("'"); + } + } + + // If unable to use the ROWID, build a where clause from the keyfields + if (wxStrlen(whereClause) == 0) + BuildWhereClause(whereClause, DB_WHERE_KEYFIELDS, queryTableName); + + // Requery the record + where = whereClause; + orderBy.Empty(); + if (!Query()) + result = false; + + if (result && !GetNext()) + result = false; + + // Switch back to original cursor + SetCursor(&currCursor); + + // Free the internal cursor + if (SQLFreeStmt(hstmtInternal, SQL_CLOSE) != SQL_SUCCESS) + pDb->DispAllErrors(henv, hdbc, hstmtInternal); + + // Restore the original where and order by clauses + where = saveWhere; + orderBy = saveOrderBy; + + return(result); + +} // wxDbTable::Refresh() + + +/********** wxDbTable::SetColNull() **********/ +bool wxDbTable::SetColNull(UWORD colNumber, bool set) +{ + if (colNumber < m_numCols) + { + colDefs[colNumber].Null = set; + if (set) // Blank out the values in the member variable + ClearMemberVar(colNumber, false); // Must call with false here, or infinite recursion will happen + + setCbValueForColumn(colNumber); + + return true; + } + else + return false; + +} // wxDbTable::SetColNull() + + +/********** wxDbTable::SetColNull() **********/ +bool wxDbTable::SetColNull(const wxString &colName, bool set) +{ + int colNumber; + for (colNumber = 0; colNumber < m_numCols; colNumber++) + { + if (!wxStricmp(colName, colDefs[colNumber].ColName)) + break; + } + + if (colNumber < m_numCols) + { + colDefs[colNumber].Null = set; + if (set) // Blank out the values in the member variable + ClearMemberVar((UWORD)colNumber,false); // Must call with false here, or infinite recursion will happen + + setCbValueForColumn(colNumber); + + return true; + } + else + return false; + +} // wxDbTable::SetColNull() + + +/********** wxDbTable::GetNewCursor() **********/ +HSTMT *wxDbTable::GetNewCursor(bool setCursor, bool bindColumns) +{ + HSTMT *newHSTMT = new HSTMT; + wxASSERT(newHSTMT); + if (!newHSTMT) + return(0); + + if (SQLAllocStmt(hdbc, newHSTMT) != SQL_SUCCESS) + { + pDb->DispAllErrors(henv, hdbc); + delete newHSTMT; + return(0); + } + + if (SQLSetStmtOption(*newHSTMT, SQL_CURSOR_TYPE, cursorType) != SQL_SUCCESS) + { + pDb->DispAllErrors(henv, hdbc, *newHSTMT); + delete newHSTMT; + return(0); + } + + if (bindColumns) + { + if (!bindCols(*newHSTMT)) + { + delete newHSTMT; + return(0); + } + } + + if (setCursor) + SetCursor(newHSTMT); + + return(newHSTMT); + +} // wxDbTable::GetNewCursor() + + +/********** wxDbTable::DeleteCursor() **********/ +bool wxDbTable::DeleteCursor(HSTMT *hstmtDel) +{ + bool result = true; + + if (!hstmtDel) // Cursor already deleted + return(result); + +/* +ODBC 3.0 says to use this form + if (SQLFreeHandle(*hstmtDel, SQL_DROP) != SQL_SUCCESS) + +*/ + if (SQLFreeStmt(*hstmtDel, SQL_DROP) != SQL_SUCCESS) + { + pDb->DispAllErrors(henv, hdbc); + result = false; + } + + delete hstmtDel; + + return(result); + +} // wxDbTable::DeleteCursor() + +////////////////////////////////////////////////////////////// +// wxDbGrid support functions +////////////////////////////////////////////////////////////// + +void wxDbTable::SetRowMode(const rowmode_t rowmode) +{ + if (!m_hstmtGridQuery) + { + m_hstmtGridQuery = GetNewCursor(false,false); + if (!bindCols(*m_hstmtGridQuery)) + return; + } + + m_rowmode = rowmode; + switch (m_rowmode) + { + case WX_ROW_MODE_QUERY: + SetCursor(m_hstmtGridQuery); + break; + case WX_ROW_MODE_INDIVIDUAL: + SetCursor(hstmtDefault); + break; + default: + wxASSERT(0); + } +} // wxDbTable::SetRowMode() + + +wxVariant wxDbTable::GetColumn(const int colNumber) const +{ + wxVariant val; + if ((colNumber < m_numCols) && (!IsColNull((UWORD)colNumber))) + { + switch (colDefs[colNumber].SqlCtype) + { +#if wxUSE_UNICODE + #if defined(SQL_WCHAR) + case SQL_WCHAR: + #endif + #if defined(SQL_WVARCHAR) + case SQL_WVARCHAR: + #endif +#endif + case SQL_CHAR: + case SQL_VARCHAR: + val = (wxChar *)(colDefs[colNumber].PtrDataObj); + break; + case SQL_C_LONG: + case SQL_C_SLONG: + val = *(long *)(colDefs[colNumber].PtrDataObj); + break; + case SQL_C_SHORT: + case SQL_C_SSHORT: + val = (long int )(*(short *)(colDefs[colNumber].PtrDataObj)); + break; + case SQL_C_ULONG: + val = (long)(*(unsigned long *)(colDefs[colNumber].PtrDataObj)); + break; + case SQL_C_TINYINT: + val = (long)(*(wxChar *)(colDefs[colNumber].PtrDataObj)); + break; + case SQL_C_UTINYINT: + val = (long)(*(wxChar *)(colDefs[colNumber].PtrDataObj)); + break; + case SQL_C_USHORT: + val = (long)(*(UWORD *)(colDefs[colNumber].PtrDataObj)); + break; + case SQL_C_DATE: + val = (DATE_STRUCT *)(colDefs[colNumber].PtrDataObj); + break; + case SQL_C_TIME: + val = (TIME_STRUCT *)(colDefs[colNumber].PtrDataObj); + break; + case SQL_C_TIMESTAMP: + val = (TIMESTAMP_STRUCT *)(colDefs[colNumber].PtrDataObj); + break; + case SQL_C_DOUBLE: + val = *(double *)(colDefs[colNumber].PtrDataObj); + break; + default: + assert(0); + } + } + return val; +} // wxDbTable::GetCol() + + +void wxDbTable::SetColumn(const int colNumber, const wxVariant val) +{ + //FIXME: Add proper wxDateTime support to wxVariant.. + wxDateTime dateval; + + SetColNull((UWORD)colNumber, val.IsNull()); + + if (!val.IsNull()) + { + if ((colDefs[colNumber].SqlCtype == SQL_C_DATE) + || (colDefs[colNumber].SqlCtype == SQL_C_TIME) + || (colDefs[colNumber].SqlCtype == SQL_C_TIMESTAMP)) + { + //Returns null if invalid! + if (!dateval.ParseDate(val.GetString())) + SetColNull((UWORD)colNumber, true); + } + + switch (colDefs[colNumber].SqlCtype) + { +#if wxUSE_UNICODE + #if defined(SQL_WCHAR) + case SQL_WCHAR: + #endif + #if defined(SQL_WVARCHAR) + case SQL_WVARCHAR: + #endif +#endif + case SQL_CHAR: + case SQL_VARCHAR: + csstrncpyt((wxChar *)(colDefs[colNumber].PtrDataObj), + val.GetString().c_str(), + colDefs[colNumber].SzDataObj-1); //TODO: glt ??? * sizeof(wxChar) ??? + break; + case SQL_C_LONG: + case SQL_C_SLONG: + *(long *)(colDefs[colNumber].PtrDataObj) = val; + break; + case SQL_C_SHORT: + case SQL_C_SSHORT: + *(short *)(colDefs[colNumber].PtrDataObj) = (short)val.GetLong(); + break; + case SQL_C_ULONG: + *(unsigned long *)(colDefs[colNumber].PtrDataObj) = val.GetLong(); + break; + case SQL_C_TINYINT: + *(wxChar *)(colDefs[colNumber].PtrDataObj) = val.GetChar(); + break; + case SQL_C_UTINYINT: + *(wxChar *)(colDefs[colNumber].PtrDataObj) = val.GetChar(); + break; + case SQL_C_USHORT: + *(unsigned short *)(colDefs[colNumber].PtrDataObj) = (unsigned short)val.GetLong(); + break; + //FIXME: Add proper wxDateTime support to wxVariant.. + case SQL_C_DATE: + { + DATE_STRUCT *dataptr = + (DATE_STRUCT *)colDefs[colNumber].PtrDataObj; + + dataptr->year = (SWORD)dateval.GetYear(); + dataptr->month = (UWORD)(dateval.GetMonth()+1); + dataptr->day = (UWORD)dateval.GetDay(); + } + break; + case SQL_C_TIME: + { + TIME_STRUCT *dataptr = + (TIME_STRUCT *)colDefs[colNumber].PtrDataObj; + + dataptr->hour = dateval.GetHour(); + dataptr->minute = dateval.GetMinute(); + dataptr->second = dateval.GetSecond(); + } + break; + case SQL_C_TIMESTAMP: + { + TIMESTAMP_STRUCT *dataptr = + (TIMESTAMP_STRUCT *)colDefs[colNumber].PtrDataObj; + dataptr->year = (SWORD)dateval.GetYear(); + dataptr->month = (UWORD)(dateval.GetMonth()+1); + dataptr->day = (UWORD)dateval.GetDay(); + + dataptr->hour = dateval.GetHour(); + dataptr->minute = dateval.GetMinute(); + dataptr->second = dateval.GetSecond(); + } + break; + case SQL_C_DOUBLE: + *(double *)(colDefs[colNumber].PtrDataObj) = val; + break; + default: + assert(0); + } // switch + } // if (!val.IsNull()) +} // wxDbTable::SetCol() + + +GenericKey wxDbTable::GetKey() +{ + void *blk; + wxChar *blkptr; + + blk = malloc(m_keysize); + blkptr = (wxChar *) blk; + + int i; + for (i=0; i < m_numCols; i++) + { + if (colDefs[i].KeyField) + { + memcpy(blkptr,colDefs[i].PtrDataObj, colDefs[i].SzDataObj); + blkptr += colDefs[i].SzDataObj; + } + } + + GenericKey k = GenericKey(blk, m_keysize); + free(blk); + + return k; +} // wxDbTable::GetKey() + + +void wxDbTable::SetKey(const GenericKey& k) +{ + void *blk; + wxChar *blkptr; + + blk = k.GetBlk(); + blkptr = (wxChar *)blk; + + int i; + for (i=0; i < m_numCols; i++) + { + if (colDefs[i].KeyField) + { + SetColNull((UWORD)i, false); + memcpy(colDefs[i].PtrDataObj, blkptr, colDefs[i].SzDataObj); + blkptr += colDefs[i].SzDataObj; + } + } +} // wxDbTable::SetKey() + + +#endif // wxUSE_ODBC diff --git a/Externals/wxWidgets/src/common/dcbase.cpp b/Externals/wxWidgets/src/common/dcbase.cpp index 18374fa453..0d184a7c33 100644 --- a/Externals/wxWidgets/src/common/dcbase.cpp +++ b/Externals/wxWidgets/src/common/dcbase.cpp @@ -1,1159 +1,1159 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/dcbase.cpp -// Purpose: generic methods of the wxDC Class -// Author: Vadim Zeitlin -// Modified by: -// Created: 05/25/99 -// RCS-ID: $Id: dcbase.cpp 48616 2007-09-09 19:36:50Z VZ $ -// Copyright: (c) wxWidgets team -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#include "wx/dc.h" -#include "wx/dcbuffer.h" // for IMPLEMENT_DYNAMIC_CLASS - -#ifndef WX_PRECOMP - #include "wx/math.h" -#endif - -// bool wxDCBase::sm_cacheing = false; - -IMPLEMENT_ABSTRACT_CLASS(wxDCBase, wxObject) - -// ============================================================================ -// implementation -// ============================================================================ - -IMPLEMENT_DYNAMIC_CLASS(wxBufferedDC, wxMemoryDC) -IMPLEMENT_ABSTRACT_CLASS(wxBufferedPaintDC, wxBufferedDC) - -#if WXWIN_COMPATIBILITY_2_6 -void wxDCBase::BeginDrawing() -{ -} - -void wxDCBase::EndDrawing() -{ -} -#endif // WXWIN_COMPATIBILITY_2_6 - -// ---------------------------------------------------------------------------- -// special symbols -// ---------------------------------------------------------------------------- - -void wxDCBase::DoDrawCheckMark(wxCoord x1, wxCoord y1, - wxCoord width, wxCoord height) -{ - wxCHECK_RET( Ok(), wxT("invalid window dc") ); - - wxCoord x2 = x1 + width, - y2 = y1 + height; - - // the pen width is calibrated to give 3 for width == height == 10 - wxDCPenChanger pen((wxDC&)*this, - wxPen(GetTextForeground(), (width + height + 1)/7)); - - // we're drawing a scaled version of wx/generic/tick.xpm here - wxCoord x3 = x1 + (4*width) / 10, // x of the tick bottom - y3 = y1 + height / 2; // y of the left tick branch - DoDrawLine(x1, y3, x3, y2); - DoDrawLine(x3, y2, x2, y1); - - CalcBoundingBox(x1, y1); - CalcBoundingBox(x2, y2); -} - -// ---------------------------------------------------------------------------- -// line/polygons -// ---------------------------------------------------------------------------- - -void wxDCBase::DrawLines(const wxList *list, wxCoord xoffset, wxCoord yoffset) -{ - int n = list->GetCount(); - wxPoint *points = new wxPoint[n]; - - int i = 0; - for ( wxList::compatibility_iterator node = list->GetFirst(); node; node = node->GetNext(), i++ ) - { - wxPoint *point = (wxPoint *)node->GetData(); - points[i].x = point->x; - points[i].y = point->y; - } - - DoDrawLines(n, points, xoffset, yoffset); - - delete [] points; -} - - -void wxDCBase::DrawPolygon(const wxList *list, - wxCoord xoffset, wxCoord yoffset, - int fillStyle) -{ - int n = list->GetCount(); - wxPoint *points = new wxPoint[n]; - - int i = 0; - for ( wxList::compatibility_iterator node = list->GetFirst(); node; node = node->GetNext(), i++ ) - { - wxPoint *point = (wxPoint *)node->GetData(); - points[i].x = point->x; - points[i].y = point->y; - } - - DoDrawPolygon(n, points, xoffset, yoffset, fillStyle); - - delete [] points; -} - -void -wxDCBase::DoDrawPolyPolygon(int n, - int count[], - wxPoint points[], - wxCoord xoffset, wxCoord yoffset, - int fillStyle) -{ - if ( n == 1 ) - { - DoDrawPolygon(count[0], points, xoffset, yoffset, fillStyle); - return; - } - - int i, j, lastOfs; - wxPoint* pts; - wxPen pen; - - for (i = j = lastOfs = 0; i < n; i++) - { - lastOfs = j; - j += count[i]; - } - pts = new wxPoint[j+n-1]; - for (i = 0; i < j; i++) - pts[i] = points[i]; - for (i = 2; i <= n; i++) - { - lastOfs -= count[n-i]; - pts[j++] = pts[lastOfs]; - } - - pen = GetPen(); - SetPen(wxPen(*wxBLACK, 0, wxTRANSPARENT)); - DoDrawPolygon(j, pts, xoffset, yoffset, fillStyle); - SetPen(pen); - for (i = j = 0; i < n; i++) - { - DoDrawLines(count[i], pts+j, xoffset, yoffset); - j += count[i]; - } - delete[] pts; -} - -// ---------------------------------------------------------------------------- -// splines -// ---------------------------------------------------------------------------- - -#if wxUSE_SPLINES - -// TODO: this API needs fixing (wxPointList, why (!const) "wxList *"?) -void wxDCBase::DrawSpline(wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2, wxCoord x3, wxCoord y3) -{ - wxList point_list; - - wxPoint *point1 = new wxPoint; - point1->x = x1; point1->y = y1; - point_list.Append((wxObject*)point1); - - wxPoint *point2 = new wxPoint; - point2->x = x2; point2->y = y2; - point_list.Append((wxObject*)point2); - - wxPoint *point3 = new wxPoint; - point3->x = x3; point3->y = y3; - point_list.Append((wxObject*)point3); - - DrawSpline(&point_list); - - for( wxList::compatibility_iterator node = point_list.GetFirst(); node; node = node->GetNext() ) - { - wxPoint *p = (wxPoint *)node->GetData(); - delete p; - } -} - -void wxDCBase::DrawSpline(int n, wxPoint points[]) -{ - wxList list; - for (int i =0; i < n; i++) - { - list.Append((wxObject*)&points[i]); - } - - DrawSpline(&list); -} - -// ----------------------------------- spline code ---------------------------------------- - -void wx_quadratic_spline(double a1, double b1, double a2, double b2, - double a3, double b3, double a4, double b4); -void wx_clear_stack(); -int wx_spline_pop(double *x1, double *y1, double *x2, double *y2, double *x3, - double *y3, double *x4, double *y4); -void wx_spline_push(double x1, double y1, double x2, double y2, double x3, double y3, - double x4, double y4); -static bool wx_spline_add_point(double x, double y); -static void wx_spline_draw_point_array(wxDCBase *dc); - -wxList wx_spline_point_list; - -#define half(z1, z2) ((z1+z2)/2.0) -#define THRESHOLD 5 - -/* iterative version */ - -void wx_quadratic_spline(double a1, double b1, double a2, double b2, double a3, double b3, double a4, - double b4) -{ - register double xmid, ymid; - double x1, y1, x2, y2, x3, y3, x4, y4; - - wx_clear_stack(); - wx_spline_push(a1, b1, a2, b2, a3, b3, a4, b4); - - while (wx_spline_pop(&x1, &y1, &x2, &y2, &x3, &y3, &x4, &y4)) { - xmid = (double)half(x2, x3); - ymid = (double)half(y2, y3); - if (fabs(x1 - xmid) < THRESHOLD && fabs(y1 - ymid) < THRESHOLD && - fabs(xmid - x4) < THRESHOLD && fabs(ymid - y4) < THRESHOLD) { - wx_spline_add_point( x1, y1 ); - wx_spline_add_point( xmid, ymid ); - } else { - wx_spline_push(xmid, ymid, (double)half(xmid, x3), (double)half(ymid, y3), - (double)half(x3, x4), (double)half(y3, y4), x4, y4); - wx_spline_push(x1, y1, (double)half(x1, x2), (double)half(y1, y2), - (double)half(x2, xmid), (double)half(y2, ymid), xmid, ymid); - } - } -} - -/* utilities used by spline drawing routines */ - -typedef struct wx_spline_stack_struct { - double x1, y1, x2, y2, x3, y3, x4, y4; -} Stack; - -#define SPLINE_STACK_DEPTH 20 -static Stack wx_spline_stack[SPLINE_STACK_DEPTH]; -static Stack *wx_stack_top; -static int wx_stack_count; - -void wx_clear_stack() -{ - wx_stack_top = wx_spline_stack; - wx_stack_count = 0; -} - -void wx_spline_push(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4) -{ - wx_stack_top->x1 = x1; - wx_stack_top->y1 = y1; - wx_stack_top->x2 = x2; - wx_stack_top->y2 = y2; - wx_stack_top->x3 = x3; - wx_stack_top->y3 = y3; - wx_stack_top->x4 = x4; - wx_stack_top->y4 = y4; - wx_stack_top++; - wx_stack_count++; -} - -int wx_spline_pop(double *x1, double *y1, double *x2, double *y2, - double *x3, double *y3, double *x4, double *y4) -{ - if (wx_stack_count == 0) - return (0); - wx_stack_top--; - wx_stack_count--; - *x1 = wx_stack_top->x1; - *y1 = wx_stack_top->y1; - *x2 = wx_stack_top->x2; - *y2 = wx_stack_top->y2; - *x3 = wx_stack_top->x3; - *y3 = wx_stack_top->y3; - *x4 = wx_stack_top->x4; - *y4 = wx_stack_top->y4; - return (1); -} - -static bool wx_spline_add_point(double x, double y) -{ - wxPoint *point = new wxPoint ; - point->x = (int) x; - point->y = (int) y; - wx_spline_point_list.Append((wxObject*)point); - return true; -} - -static void wx_spline_draw_point_array(wxDCBase *dc) -{ - dc->DrawLines(&wx_spline_point_list, 0, 0 ); - wxList::compatibility_iterator node = wx_spline_point_list.GetFirst(); - while (node) - { - wxPoint *point = (wxPoint *)node->GetData(); - delete point; - wx_spline_point_list.Erase(node); - node = wx_spline_point_list.GetFirst(); - } -} - -void wxDCBase::DoDrawSpline( wxList *points ) -{ - wxCHECK_RET( Ok(), wxT("invalid window dc") ); - - wxPoint *p; - double cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4; - double x1, y1, x2, y2; - - wxList::compatibility_iterator node = points->GetFirst(); - if (!node) - // empty list - return; - - p = (wxPoint *)node->GetData(); - - x1 = p->x; - y1 = p->y; - - node = node->GetNext(); - p = (wxPoint *)node->GetData(); - - x2 = p->x; - y2 = p->y; - cx1 = (double)((x1 + x2) / 2); - cy1 = (double)((y1 + y2) / 2); - cx2 = (double)((cx1 + x2) / 2); - cy2 = (double)((cy1 + y2) / 2); - - wx_spline_add_point(x1, y1); - - while ((node = node->GetNext()) -#if !wxUSE_STL - != NULL -#endif // !wxUSE_STL - ) - { - p = (wxPoint *)node->GetData(); - x1 = x2; - y1 = y2; - x2 = p->x; - y2 = p->y; - cx4 = (double)(x1 + x2) / 2; - cy4 = (double)(y1 + y2) / 2; - cx3 = (double)(x1 + cx4) / 2; - cy3 = (double)(y1 + cy4) / 2; - - wx_quadratic_spline(cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4); - - cx1 = cx4; - cy1 = cy4; - cx2 = (double)(cx1 + x2) / 2; - cy2 = (double)(cy1 + y2) / 2; - } - - wx_spline_add_point( cx1, cy1 ); - wx_spline_add_point( x2, y2 ); - - wx_spline_draw_point_array( this ); -} - -#endif // wxUSE_SPLINES - -// ---------------------------------------------------------------------------- -// Partial Text Extents -// ---------------------------------------------------------------------------- - - -// Each element of the widths array will be the width of the string up to and -// including the corresponding character in text. This is the generic -// implementation, the port-specific classes should do this with native APIs -// if available and if faster. Note: pango_layout_index_to_pos is much slower -// than calling GetTextExtent!! - -#define FWC_SIZE 256 - -class FontWidthCache -{ -public: - FontWidthCache() : m_scaleX(1), m_widths(NULL) { } - ~FontWidthCache() { delete []m_widths; } - - void Reset() - { - if (!m_widths) - m_widths = new int[FWC_SIZE]; - - memset(m_widths, 0, sizeof(int)*FWC_SIZE); - } - - wxFont m_font; - double m_scaleX; - int *m_widths; -}; - -static FontWidthCache s_fontWidthCache; - -bool wxDCBase::DoGetPartialTextExtents(const wxString& text, wxArrayInt& widths) const -{ - int totalWidth = 0; - - const size_t len = text.length(); - widths.Empty(); - widths.Add(0, len); - - // reset the cache if font or horizontal scale have changed - if ( !s_fontWidthCache.m_widths || - !wxIsSameDouble(s_fontWidthCache.m_scaleX, m_scaleX) || - (s_fontWidthCache.m_font != GetFont()) ) - { - s_fontWidthCache.Reset(); - s_fontWidthCache.m_font = GetFont(); - s_fontWidthCache.m_scaleX = m_scaleX; - } - - // Calculate the position of each character based on the widths of - // the previous characters - int w, h; - for ( size_t i = 0; i < len; i++ ) - { - const wxChar c = text[i]; - unsigned int c_int = (unsigned int)c; - - if ((c_int < FWC_SIZE) && (s_fontWidthCache.m_widths[c_int] != 0)) - { - w = s_fontWidthCache.m_widths[c_int]; - } - else - { - GetTextExtent(c, &w, &h); - if (c_int < FWC_SIZE) - s_fontWidthCache.m_widths[c_int] = w; - } - - totalWidth += w; - widths[i] = totalWidth; - } - - return true; -} - - -// ---------------------------------------------------------------------------- -// enhanced text drawing -// ---------------------------------------------------------------------------- - -void wxDCBase::GetMultiLineTextExtent(const wxString& text, - wxCoord *x, - wxCoord *y, - wxCoord *h, - wxFont *font) const -{ - wxCoord widthTextMax = 0, widthLine, - heightTextTotal = 0, heightLineDefault = 0, heightLine = 0; - - wxString curLine; - for ( const wxChar *pc = text; ; pc++ ) - { - if ( *pc == _T('\n') || *pc == _T('\0') ) - { - if ( curLine.empty() ) - { - // we can't use GetTextExtent - it will return 0 for both width - // and height and an empty line should count in height - // calculation - - // assume that this line has the same height as the previous - // one - if ( !heightLineDefault ) - heightLineDefault = heightLine; - - if ( !heightLineDefault ) - { - // but we don't know it yet - choose something reasonable - GetTextExtent(_T("W"), NULL, &heightLineDefault, - NULL, NULL, font); - } - - heightTextTotal += heightLineDefault; - } - else - { - GetTextExtent(curLine, &widthLine, &heightLine, - NULL, NULL, font); - if ( widthLine > widthTextMax ) - widthTextMax = widthLine; - heightTextTotal += heightLine; - } - - if ( *pc == _T('\n') ) - { - curLine.clear(); - } - else - { - // the end of string - break; - } - } - else - { - curLine += *pc; - } - } - - if ( x ) - *x = widthTextMax; - if ( y ) - *y = heightTextTotal; - if ( h ) - *h = heightLine; -} - -void wxDCBase::DrawLabel(const wxString& text, - const wxBitmap& bitmap, - const wxRect& rect, - int alignment, - int indexAccel, - wxRect *rectBounding) -{ - // find the text position - wxCoord widthText, heightText, heightLine; - GetMultiLineTextExtent(text, &widthText, &heightText, &heightLine); - - wxCoord width, height; - if ( bitmap.Ok() ) - { - width = widthText + bitmap.GetWidth(); - height = bitmap.GetHeight(); - } - else // no bitmap - { - width = widthText; - height = heightText; - } - - wxCoord x, y; - if ( alignment & wxALIGN_RIGHT ) - { - x = rect.GetRight() - width; - } - else if ( alignment & wxALIGN_CENTRE_HORIZONTAL ) - { - x = (rect.GetLeft() + rect.GetRight() + 1 - width) / 2; - } - else // alignment & wxALIGN_LEFT - { - x = rect.GetLeft(); - } - - if ( alignment & wxALIGN_BOTTOM ) - { - y = rect.GetBottom() - height; - } - else if ( alignment & wxALIGN_CENTRE_VERTICAL ) - { - y = (rect.GetTop() + rect.GetBottom() + 1 - height) / 2; - } - else // alignment & wxALIGN_TOP - { - y = rect.GetTop(); - } - - // draw the bitmap first - wxCoord x0 = x, - y0 = y, - width0 = width; - if ( bitmap.Ok() ) - { - DrawBitmap(bitmap, x, y, true /* use mask */); - - wxCoord offset = bitmap.GetWidth() + 4; - x += offset; - width -= offset; - - y += (height - heightText) / 2; - } - - // we will draw the underscore under the accel char later - wxCoord startUnderscore = 0, - endUnderscore = 0, - yUnderscore = 0; - - // split the string into lines and draw each of them separately - wxString curLine; - for ( const wxChar *pc = text; ; pc++ ) - { - if ( *pc == _T('\n') || *pc == _T('\0') ) - { - int xRealStart = x; // init it here to avoid compielr warnings - - if ( !curLine.empty() ) - { - // NB: can't test for !(alignment & wxALIGN_LEFT) because - // wxALIGN_LEFT is 0 - if ( alignment & (wxALIGN_RIGHT | wxALIGN_CENTRE_HORIZONTAL) ) - { - wxCoord widthLine; - GetTextExtent(curLine, &widthLine, NULL); - - if ( alignment & wxALIGN_RIGHT ) - { - xRealStart += width - widthLine; - } - else // if ( alignment & wxALIGN_CENTRE_HORIZONTAL ) - { - xRealStart += (width - widthLine) / 2; - } - } - //else: left aligned, nothing to do - - DrawText(curLine, xRealStart, y); - } - - y += heightLine; - - // do we have underscore in this line? we can check yUnderscore - // because it is set below to just y + heightLine if we do - if ( y == yUnderscore ) - { - // adjust the horz positions to account for the shift - startUnderscore += xRealStart; - endUnderscore += xRealStart; - } - - if ( *pc == _T('\0') ) - break; - - curLine.clear(); - } - else // not end of line - { - if ( pc - text.c_str() == indexAccel ) - { - // remeber to draw underscore here - GetTextExtent(curLine, &startUnderscore, NULL); - curLine += *pc; - GetTextExtent(curLine, &endUnderscore, NULL); - - yUnderscore = y + heightLine; - } - else - { - curLine += *pc; - } - } - } - - // draw the underscore if found - if ( startUnderscore != endUnderscore ) - { - // it should be of the same colour as text - SetPen(wxPen(GetTextForeground(), 0, wxSOLID)); - - yUnderscore--; - - DrawLine(startUnderscore, yUnderscore, endUnderscore, yUnderscore); - } - - // return bounding rect if requested - if ( rectBounding ) - { - *rectBounding = wxRect(x, y - heightText, widthText, heightText); - } - - CalcBoundingBox(x0, y0); - CalcBoundingBox(x0 + width0, y0 + height); -} - - -void wxDCBase::DoGradientFillLinear(const wxRect& rect, - const wxColour& initialColour, - const wxColour& destColour, - wxDirection nDirection) -{ - // save old pen - wxPen oldPen = m_pen; - wxBrush oldBrush = m_brush; - - wxUint8 nR1 = initialColour.Red(); - wxUint8 nG1 = initialColour.Green(); - wxUint8 nB1 = initialColour.Blue(); - wxUint8 nR2 = destColour.Red(); - wxUint8 nG2 = destColour.Green(); - wxUint8 nB2 = destColour.Blue(); - wxUint8 nR, nG, nB; - - if ( nDirection == wxEAST || nDirection == wxWEST ) - { - wxInt32 x = rect.GetWidth(); - wxInt32 w = x; // width of area to shade - wxInt32 xDelta = w/256; // height of one shade bend - if (xDelta < 1) - xDelta = 1; - - while (x >= xDelta) - { - x -= xDelta; - if (nR1 > nR2) - nR = nR1 - (nR1-nR2)*(w-x)/w; - else - nR = nR1 + (nR2-nR1)*(w-x)/w; - - if (nG1 > nG2) - nG = nG1 - (nG1-nG2)*(w-x)/w; - else - nG = nG1 + (nG2-nG1)*(w-x)/w; - - if (nB1 > nB2) - nB = nB1 - (nB1-nB2)*(w-x)/w; - else - nB = nB1 + (nB2-nB1)*(w-x)/w; - - wxColour colour(nR,nG,nB); - SetPen(wxPen(colour, 1, wxSOLID)); - SetBrush(wxBrush(colour)); - if(nDirection == wxEAST) - DrawRectangle(rect.GetRight()-x-xDelta+1, rect.GetTop(), - xDelta, rect.GetHeight()); - else //nDirection == wxWEST - DrawRectangle(rect.GetLeft()+x, rect.GetTop(), - xDelta, rect.GetHeight()); - } - } - else // nDirection == wxNORTH || nDirection == wxSOUTH - { - wxInt32 y = rect.GetHeight(); - wxInt32 w = y; // height of area to shade - wxInt32 yDelta = w/255; // height of one shade bend - if (yDelta < 1) - yDelta = 1; - - while (y > 0) - { - y -= yDelta; - if (nR1 > nR2) - nR = nR1 - (nR1-nR2)*(w-y)/w; - else - nR = nR1 + (nR2-nR1)*(w-y)/w; - - if (nG1 > nG2) - nG = nG1 - (nG1-nG2)*(w-y)/w; - else - nG = nG1 + (nG2-nG1)*(w-y)/w; - - if (nB1 > nB2) - nB = nB1 - (nB1-nB2)*(w-y)/w; - else - nB = nB1 + (nB2-nB1)*(w-y)/w; - - wxColour colour(nR,nG,nB); - SetPen(wxPen(colour, 1, wxSOLID)); - SetBrush(wxBrush(colour)); - if(nDirection == wxNORTH) - DrawRectangle(rect.GetLeft(), rect.GetTop()+y, - rect.GetWidth(), yDelta); - else //nDirection == wxSOUTH - DrawRectangle(rect.GetLeft(), rect.GetBottom()-y-yDelta+1, - rect.GetWidth(), yDelta); - } - } - - SetPen(oldPen); - SetBrush(oldBrush); -} - -void wxDCBase::DoGradientFillConcentric(const wxRect& rect, - const wxColour& initialColour, - const wxColour& destColour, - const wxPoint& circleCenter) -{ - //save the old pen color - wxColour oldPenColour = m_pen.GetColour(); - - wxUint8 nR1 = destColour.Red(); - wxUint8 nG1 = destColour.Green(); - wxUint8 nB1 = destColour.Blue(); - wxUint8 nR2 = initialColour.Red(); - wxUint8 nG2 = initialColour.Green(); - wxUint8 nB2 = initialColour.Blue(); - wxUint8 nR, nG, nB; - - - //Radius - wxInt32 cx = rect.GetWidth() / 2; - wxInt32 cy = rect.GetHeight() / 2; - wxInt32 nRadius; - if (cx < cy) - nRadius = cx; - else - nRadius = cy; - - //Offset of circle - wxInt32 nCircleOffX = circleCenter.x - (rect.GetWidth() / 2); - wxInt32 nCircleOffY = circleCenter.y - (rect.GetHeight() / 2); - - for ( wxInt32 x = 0; x < rect.GetWidth(); x++ ) - { - for ( wxInt32 y = 0; y < rect.GetHeight(); y++ ) - { - //get color difference - wxInt32 nGradient = ((nRadius - - (wxInt32)sqrt( - pow((double)(x - cx - nCircleOffX), 2) + - pow((double)(y - cy - nCircleOffY), 2) - )) * 100) / nRadius; - - //normalize Gradient - if (nGradient < 0 ) - nGradient = 0; - - //get dest colors - nR = (wxUint8)(nR1 + ((nR2 - nR1) * nGradient / 100)); - nG = (wxUint8)(nG1 + ((nG2 - nG1) * nGradient / 100)); - nB = (wxUint8)(nB1 + ((nB2 - nB1) * nGradient / 100)); - - //set the pixel - m_pen.SetColour(wxColour(nR,nG,nB)); - DrawPoint(wxPoint(x + rect.GetLeft(), y + rect.GetTop())); - } - } - //return old pen color - m_pen.SetColour(oldPenColour); -} - -/* -Notes for wxWidgets DrawEllipticArcRot(...) - -wxDCBase::DrawEllipticArcRot(...) draws a rotated elliptic arc or an ellipse. -It uses wxDCBase::CalculateEllipticPoints(...) and wxDCBase::Rotate(...), -which are also new. - -All methods are generic, so they can be implemented in wxDCBase. -DoDrawEllipticArcRot(...) is virtual, so it can be called from deeper -methods like (WinCE) wxDC::DoDrawArc(...). - -CalculateEllipticPoints(...) fills a given list of wxPoints with some points -of an elliptic arc. The algorithm is pixel-based: In every row (in flat -parts) or every column (in steep parts) only one pixel is calculated. -Trigonometric calculation (sin, cos, tan, atan) is only done if the -starting angle is not equal to the ending angle. The calculation of the -pixels is done using simple arithmetic only and should perform not too -bad even on devices without floating point processor. I didn't test this yet. - -Rotate(...) rotates a list of point pixel-based, you will see rounding errors. -For instance: an ellipse rotated 180 degrees is drawn -slightly different from the original. - -The points are then moved to an array and used to draw a polyline and/or polygon -(with center added, the pie). -The result looks quite similar to the native ellipse, only e few pixels differ. - -The performance on a desktop system (Athlon 1800, WinXP) is about 7 times -slower as DrawEllipse(...), which calls the native API. -An rotated ellipse outside the clipping region takes nearly the same time, -while an native ellipse outside takes nearly no time to draw. - -If you draw an arc with this new method, you will see the starting and ending angles -are calculated properly. -If you use DrawEllipticArc(...), you will see they are only correct for circles -and not properly calculated for ellipses. - -Peter Lenhard -p.lenhard@t-online.de -*/ - -#ifdef __WXWINCE__ -void wxDCBase::DoDrawEllipticArcRot( wxCoord x, wxCoord y, - wxCoord w, wxCoord h, - double sa, double ea, double angle ) -{ - wxList list; - - CalculateEllipticPoints( &list, x, y, w, h, sa, ea ); - Rotate( &list, angle, wxPoint( x+w/2, y+h/2 ) ); - - // Add center (for polygon/pie) - list.Append( (wxObject*) new wxPoint( x+w/2, y+h/2 ) ); - - // copy list into array and delete list elements - int n = list.GetCount(); - wxPoint *points = new wxPoint[n]; - int i = 0; - wxNode* node = 0; - for ( node = list.GetFirst(); node; node = node->GetNext(), i++ ) - { - wxPoint *point = (wxPoint *)node->GetData(); - points[i].x = point->x; - points[i].y = point->y; - delete point; - } - - // first draw the pie without pen, if necessary - if( GetBrush() != *wxTRANSPARENT_BRUSH ) - { - wxPen tempPen( GetPen() ); - SetPen( *wxTRANSPARENT_PEN ); - DoDrawPolygon( n, points, 0, 0 ); - SetPen( tempPen ); - } - - // then draw the arc without brush, if necessary - if( GetPen() != *wxTRANSPARENT_PEN ) - { - // without center - DoDrawLines( n-1, points, 0, 0 ); - } - - delete [] points; - -} // DrawEllipticArcRot - -void wxDCBase::Rotate( wxList* points, double angle, wxPoint center ) -{ - if( angle != 0.0 ) - { - double pi(M_PI); - double dSinA = -sin(angle*2.0*pi/360.0); - double dCosA = cos(angle*2.0*pi/360.0); - for ( wxNode* node = points->GetFirst(); node; node = node->GetNext() ) - { - wxPoint* point = (wxPoint*)node->GetData(); - - // transform coordinates, if necessary - if( center.x ) point->x -= center.x; - if( center.y ) point->y -= center.y; - - // calculate rotation, rounding simply by implicit cast to integer - int xTemp = point->x * dCosA - point->y * dSinA; - point->y = point->x * dSinA + point->y * dCosA; - point->x = xTemp; - - // back transform coordinates, if necessary - if( center.x ) point->x += center.x; - if( center.y ) point->y += center.y; - } - } -} - -void wxDCBase::CalculateEllipticPoints( wxList* points, - wxCoord xStart, wxCoord yStart, - wxCoord w, wxCoord h, - double sa, double ea ) -{ - double pi = M_PI; - double sar = 0; - double ear = 0; - int xsa = 0; - int ysa = 0; - int xea = 0; - int yea = 0; - int sq = 0; - int eq = 0; - bool bUseAngles = false; - if( w<0 ) w = -w; - if( h<0 ) h = -h; - // half-axes - wxCoord a = w/2; - wxCoord b = h/2; - // decrement 1 pixel if ellipse is smaller than 2*a, 2*b - int decrX = 0; - if( 2*a == w ) decrX = 1; - int decrY = 0; - if( 2*b == h ) decrY = 1; - // center - wxCoord xCenter = xStart + a; - wxCoord yCenter = yStart + b; - // calculate data for start and end, if necessary - if( sa != ea ) - { - bUseAngles = true; - // normalisation of angles - while( sa<0 ) sa += 360; - while( ea<0 ) ea += 360; - while( sa>=360 ) sa -= 360; - while( ea>=360 ) ea -= 360; - // calculate quadrant numbers - if( sa > 270 ) sq = 3; - else if( sa > 180 ) sq = 2; - else if( sa > 90 ) sq = 1; - if( ea > 270 ) eq = 3; - else if( ea > 180 ) eq = 2; - else if( ea > 90 ) eq = 1; - sar = sa * pi / 180.0; - ear = ea * pi / 180.0; - // correct angle circle -> ellipse - sar = atan( -a/(double)b * tan( sar ) ); - if ( sq == 1 || sq == 2 ) sar += pi; - ear = atan( -a/(double)b * tan( ear ) ); - if ( eq == 1 || eq == 2 ) ear += pi; - // coordinates of points - xsa = xCenter + a * cos( sar ); - if( sq == 0 || sq == 3 ) xsa -= decrX; - ysa = yCenter + b * sin( sar ); - if( sq == 2 || sq == 3 ) ysa -= decrY; - xea = xCenter + a * cos( ear ); - if( eq == 0 || eq == 3 ) xea -= decrX; - yea = yCenter + b * sin( ear ); - if( eq == 2 || eq == 3 ) yea -= decrY; - } // if iUseAngles - // calculate c1 = b^2, c2 = b^2/a^2 with a = w/2, b = h/2 - double c1 = b * b; - double c2 = 2.0 / w; - c2 *= c2; - c2 *= c1; - wxCoord x = 0; - wxCoord y = b; - long x2 = 1; - long y2 = y*y; - long y2_old = 0; - long y_old = 0; - // Lists for quadrant 1 to 4 - wxList pointsarray[4]; - // Calculate points for first quadrant and set in all quadrants - for( x = 0; x <= a; ++x ) - { - x2 = x2+x+x-1; - y2_old = y2; - y_old = y; - bool bNewPoint = false; - while( y2 > c1 - c2 * x2 && y > 0 ) - { - bNewPoint = true; - y2 = y2-y-y+1; - --y; - } - // old y now to big: set point with old y, old x - if( bNewPoint && x>1) - { - int x1 = x - 1; - // remove points on the same line - pointsarray[0].Insert( (wxObject*) new wxPoint( xCenter + x1 - decrX, yCenter - y_old ) ); - pointsarray[1].Append( (wxObject*) new wxPoint( xCenter - x1, yCenter - y_old ) ); - pointsarray[2].Insert( (wxObject*) new wxPoint( xCenter - x1, yCenter + y_old - decrY ) ); - pointsarray[3].Append( (wxObject*) new wxPoint( xCenter + x1 - decrX, yCenter + y_old - decrY ) ); - } // set point - } // calculate point - - // Starting and/or ending points for the quadrants, first quadrant gets both. - pointsarray[0].Insert( (wxObject*) new wxPoint( xCenter + a - decrX, yCenter ) ); - pointsarray[0].Append( (wxObject*) new wxPoint( xCenter, yCenter - b ) ); - pointsarray[1].Append( (wxObject*) new wxPoint( xCenter - a, yCenter ) ); - pointsarray[2].Append( (wxObject*) new wxPoint( xCenter, yCenter + b - decrY ) ); - pointsarray[3].Append( (wxObject*) new wxPoint( xCenter + a - decrX, yCenter ) ); - - // copy quadrants in original list - if( bUseAngles ) - { - // Copy the right part of the points in the lists - // and delete the wxPoints, because they do not leave this method. - points->Append( (wxObject*) new wxPoint( xsa, ysa ) ); - int q = sq; - bool bStarted = false; - bool bReady = false; - bool bForceTurn = ( sq == eq && sa > ea ); - while( !bReady ) - { - for( wxNode *node = pointsarray[q].GetFirst(); node; node = node->GetNext() ) - { - // once: go to starting point in start quadrant - if( !bStarted && - ( - ( (wxPoint*) node->GetData() )->x < xsa+1 && q <= 1 - || - ( (wxPoint*) node->GetData() )->x > xsa-1 && q >= 2 - ) - ) - { - bStarted = true; - } - - // copy point, if not at ending point - if( bStarted ) - { - if( q != eq || bForceTurn - || - ( (wxPoint*) node->GetData() )->x > xea+1 && q <= 1 - || - ( (wxPoint*) node->GetData() )->x < xea-1 && q >= 2 - ) - { - // copy point - wxPoint* pPoint = new wxPoint( *((wxPoint*) node->GetData() ) ); - points->Append( (wxObject*) pPoint ); - } - else if( q == eq && !bForceTurn || ( (wxPoint*) node->GetData() )->x == xea) - { - bReady = true; - } - } - } // for node - ++q; - if( q > 3 ) q = 0; - bForceTurn = false; - bStarted = true; - } // while not bReady - points->Append( (wxObject*) new wxPoint( xea, yea ) ); - - // delete points - for( q = 0; q < 4; ++q ) - { - for( wxNode *node = pointsarray[q].GetFirst(); node; node = node->GetNext() ) - { - wxPoint *p = (wxPoint *)node->GetData(); - delete p; - } - } - } - else - { - wxNode* node; - // copy whole ellipse, wxPoints will be deleted outside - for( node = pointsarray[0].GetFirst(); node; node = node->GetNext() ) - { - wxObject *p = node->GetData(); - points->Append( p ); - } - for( node = pointsarray[1].GetFirst(); node; node = node->GetNext() ) - { - wxObject *p = node->GetData(); - points->Append( p ); - } - for( node = pointsarray[2].GetFirst(); node; node = node->GetNext() ) - { - wxObject *p = node->GetData(); - points->Append( p ); - } - for( node = pointsarray[3].GetFirst(); node; node = node->GetNext() ) - { - wxObject *p = node->GetData(); - points->Append( p ); - } - } // not iUseAngles -} // CalculateEllipticPoints - -#endif +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/dcbase.cpp +// Purpose: generic methods of the wxDC Class +// Author: Vadim Zeitlin +// Modified by: +// Created: 05/25/99 +// RCS-ID: $Id: dcbase.cpp 48616 2007-09-09 19:36:50Z VZ $ +// Copyright: (c) wxWidgets team +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#include "wx/dc.h" +#include "wx/dcbuffer.h" // for IMPLEMENT_DYNAMIC_CLASS + +#ifndef WX_PRECOMP + #include "wx/math.h" +#endif + +// bool wxDCBase::sm_cacheing = false; + +IMPLEMENT_ABSTRACT_CLASS(wxDCBase, wxObject) + +// ============================================================================ +// implementation +// ============================================================================ + +IMPLEMENT_DYNAMIC_CLASS(wxBufferedDC, wxMemoryDC) +IMPLEMENT_ABSTRACT_CLASS(wxBufferedPaintDC, wxBufferedDC) + +#if WXWIN_COMPATIBILITY_2_6 +void wxDCBase::BeginDrawing() +{ +} + +void wxDCBase::EndDrawing() +{ +} +#endif // WXWIN_COMPATIBILITY_2_6 + +// ---------------------------------------------------------------------------- +// special symbols +// ---------------------------------------------------------------------------- + +void wxDCBase::DoDrawCheckMark(wxCoord x1, wxCoord y1, + wxCoord width, wxCoord height) +{ + wxCHECK_RET( Ok(), wxT("invalid window dc") ); + + wxCoord x2 = x1 + width, + y2 = y1 + height; + + // the pen width is calibrated to give 3 for width == height == 10 + wxDCPenChanger pen((wxDC&)*this, + wxPen(GetTextForeground(), (width + height + 1)/7)); + + // we're drawing a scaled version of wx/generic/tick.xpm here + wxCoord x3 = x1 + (4*width) / 10, // x of the tick bottom + y3 = y1 + height / 2; // y of the left tick branch + DoDrawLine(x1, y3, x3, y2); + DoDrawLine(x3, y2, x2, y1); + + CalcBoundingBox(x1, y1); + CalcBoundingBox(x2, y2); +} + +// ---------------------------------------------------------------------------- +// line/polygons +// ---------------------------------------------------------------------------- + +void wxDCBase::DrawLines(const wxList *list, wxCoord xoffset, wxCoord yoffset) +{ + int n = list->GetCount(); + wxPoint *points = new wxPoint[n]; + + int i = 0; + for ( wxList::compatibility_iterator node = list->GetFirst(); node; node = node->GetNext(), i++ ) + { + wxPoint *point = (wxPoint *)node->GetData(); + points[i].x = point->x; + points[i].y = point->y; + } + + DoDrawLines(n, points, xoffset, yoffset); + + delete [] points; +} + + +void wxDCBase::DrawPolygon(const wxList *list, + wxCoord xoffset, wxCoord yoffset, + int fillStyle) +{ + int n = list->GetCount(); + wxPoint *points = new wxPoint[n]; + + int i = 0; + for ( wxList::compatibility_iterator node = list->GetFirst(); node; node = node->GetNext(), i++ ) + { + wxPoint *point = (wxPoint *)node->GetData(); + points[i].x = point->x; + points[i].y = point->y; + } + + DoDrawPolygon(n, points, xoffset, yoffset, fillStyle); + + delete [] points; +} + +void +wxDCBase::DoDrawPolyPolygon(int n, + int count[], + wxPoint points[], + wxCoord xoffset, wxCoord yoffset, + int fillStyle) +{ + if ( n == 1 ) + { + DoDrawPolygon(count[0], points, xoffset, yoffset, fillStyle); + return; + } + + int i, j, lastOfs; + wxPoint* pts; + wxPen pen; + + for (i = j = lastOfs = 0; i < n; i++) + { + lastOfs = j; + j += count[i]; + } + pts = new wxPoint[j+n-1]; + for (i = 0; i < j; i++) + pts[i] = points[i]; + for (i = 2; i <= n; i++) + { + lastOfs -= count[n-i]; + pts[j++] = pts[lastOfs]; + } + + pen = GetPen(); + SetPen(wxPen(*wxBLACK, 0, wxTRANSPARENT)); + DoDrawPolygon(j, pts, xoffset, yoffset, fillStyle); + SetPen(pen); + for (i = j = 0; i < n; i++) + { + DoDrawLines(count[i], pts+j, xoffset, yoffset); + j += count[i]; + } + delete[] pts; +} + +// ---------------------------------------------------------------------------- +// splines +// ---------------------------------------------------------------------------- + +#if wxUSE_SPLINES + +// TODO: this API needs fixing (wxPointList, why (!const) "wxList *"?) +void wxDCBase::DrawSpline(wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2, wxCoord x3, wxCoord y3) +{ + wxList point_list; + + wxPoint *point1 = new wxPoint; + point1->x = x1; point1->y = y1; + point_list.Append((wxObject*)point1); + + wxPoint *point2 = new wxPoint; + point2->x = x2; point2->y = y2; + point_list.Append((wxObject*)point2); + + wxPoint *point3 = new wxPoint; + point3->x = x3; point3->y = y3; + point_list.Append((wxObject*)point3); + + DrawSpline(&point_list); + + for( wxList::compatibility_iterator node = point_list.GetFirst(); node; node = node->GetNext() ) + { + wxPoint *p = (wxPoint *)node->GetData(); + delete p; + } +} + +void wxDCBase::DrawSpline(int n, wxPoint points[]) +{ + wxList list; + for (int i =0; i < n; i++) + { + list.Append((wxObject*)&points[i]); + } + + DrawSpline(&list); +} + +// ----------------------------------- spline code ---------------------------------------- + +void wx_quadratic_spline(double a1, double b1, double a2, double b2, + double a3, double b3, double a4, double b4); +void wx_clear_stack(); +int wx_spline_pop(double *x1, double *y1, double *x2, double *y2, double *x3, + double *y3, double *x4, double *y4); +void wx_spline_push(double x1, double y1, double x2, double y2, double x3, double y3, + double x4, double y4); +static bool wx_spline_add_point(double x, double y); +static void wx_spline_draw_point_array(wxDCBase *dc); + +wxList wx_spline_point_list; + +#define half(z1, z2) ((z1+z2)/2.0) +#define THRESHOLD 5 + +/* iterative version */ + +void wx_quadratic_spline(double a1, double b1, double a2, double b2, double a3, double b3, double a4, + double b4) +{ + register double xmid, ymid; + double x1, y1, x2, y2, x3, y3, x4, y4; + + wx_clear_stack(); + wx_spline_push(a1, b1, a2, b2, a3, b3, a4, b4); + + while (wx_spline_pop(&x1, &y1, &x2, &y2, &x3, &y3, &x4, &y4)) { + xmid = (double)half(x2, x3); + ymid = (double)half(y2, y3); + if (fabs(x1 - xmid) < THRESHOLD && fabs(y1 - ymid) < THRESHOLD && + fabs(xmid - x4) < THRESHOLD && fabs(ymid - y4) < THRESHOLD) { + wx_spline_add_point( x1, y1 ); + wx_spline_add_point( xmid, ymid ); + } else { + wx_spline_push(xmid, ymid, (double)half(xmid, x3), (double)half(ymid, y3), + (double)half(x3, x4), (double)half(y3, y4), x4, y4); + wx_spline_push(x1, y1, (double)half(x1, x2), (double)half(y1, y2), + (double)half(x2, xmid), (double)half(y2, ymid), xmid, ymid); + } + } +} + +/* utilities used by spline drawing routines */ + +typedef struct wx_spline_stack_struct { + double x1, y1, x2, y2, x3, y3, x4, y4; +} Stack; + +#define SPLINE_STACK_DEPTH 20 +static Stack wx_spline_stack[SPLINE_STACK_DEPTH]; +static Stack *wx_stack_top; +static int wx_stack_count; + +void wx_clear_stack() +{ + wx_stack_top = wx_spline_stack; + wx_stack_count = 0; +} + +void wx_spline_push(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4) +{ + wx_stack_top->x1 = x1; + wx_stack_top->y1 = y1; + wx_stack_top->x2 = x2; + wx_stack_top->y2 = y2; + wx_stack_top->x3 = x3; + wx_stack_top->y3 = y3; + wx_stack_top->x4 = x4; + wx_stack_top->y4 = y4; + wx_stack_top++; + wx_stack_count++; +} + +int wx_spline_pop(double *x1, double *y1, double *x2, double *y2, + double *x3, double *y3, double *x4, double *y4) +{ + if (wx_stack_count == 0) + return (0); + wx_stack_top--; + wx_stack_count--; + *x1 = wx_stack_top->x1; + *y1 = wx_stack_top->y1; + *x2 = wx_stack_top->x2; + *y2 = wx_stack_top->y2; + *x3 = wx_stack_top->x3; + *y3 = wx_stack_top->y3; + *x4 = wx_stack_top->x4; + *y4 = wx_stack_top->y4; + return (1); +} + +static bool wx_spline_add_point(double x, double y) +{ + wxPoint *point = new wxPoint ; + point->x = (int) x; + point->y = (int) y; + wx_spline_point_list.Append((wxObject*)point); + return true; +} + +static void wx_spline_draw_point_array(wxDCBase *dc) +{ + dc->DrawLines(&wx_spline_point_list, 0, 0 ); + wxList::compatibility_iterator node = wx_spline_point_list.GetFirst(); + while (node) + { + wxPoint *point = (wxPoint *)node->GetData(); + delete point; + wx_spline_point_list.Erase(node); + node = wx_spline_point_list.GetFirst(); + } +} + +void wxDCBase::DoDrawSpline( wxList *points ) +{ + wxCHECK_RET( Ok(), wxT("invalid window dc") ); + + wxPoint *p; + double cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4; + double x1, y1, x2, y2; + + wxList::compatibility_iterator node = points->GetFirst(); + if (!node) + // empty list + return; + + p = (wxPoint *)node->GetData(); + + x1 = p->x; + y1 = p->y; + + node = node->GetNext(); + p = (wxPoint *)node->GetData(); + + x2 = p->x; + y2 = p->y; + cx1 = (double)((x1 + x2) / 2); + cy1 = (double)((y1 + y2) / 2); + cx2 = (double)((cx1 + x2) / 2); + cy2 = (double)((cy1 + y2) / 2); + + wx_spline_add_point(x1, y1); + + while ((node = node->GetNext()) +#if !wxUSE_STL + != NULL +#endif // !wxUSE_STL + ) + { + p = (wxPoint *)node->GetData(); + x1 = x2; + y1 = y2; + x2 = p->x; + y2 = p->y; + cx4 = (double)(x1 + x2) / 2; + cy4 = (double)(y1 + y2) / 2; + cx3 = (double)(x1 + cx4) / 2; + cy3 = (double)(y1 + cy4) / 2; + + wx_quadratic_spline(cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4); + + cx1 = cx4; + cy1 = cy4; + cx2 = (double)(cx1 + x2) / 2; + cy2 = (double)(cy1 + y2) / 2; + } + + wx_spline_add_point( cx1, cy1 ); + wx_spline_add_point( x2, y2 ); + + wx_spline_draw_point_array( this ); +} + +#endif // wxUSE_SPLINES + +// ---------------------------------------------------------------------------- +// Partial Text Extents +// ---------------------------------------------------------------------------- + + +// Each element of the widths array will be the width of the string up to and +// including the corresponding character in text. This is the generic +// implementation, the port-specific classes should do this with native APIs +// if available and if faster. Note: pango_layout_index_to_pos is much slower +// than calling GetTextExtent!! + +#define FWC_SIZE 256 + +class FontWidthCache +{ +public: + FontWidthCache() : m_scaleX(1), m_widths(NULL) { } + ~FontWidthCache() { delete []m_widths; } + + void Reset() + { + if (!m_widths) + m_widths = new int[FWC_SIZE]; + + memset(m_widths, 0, sizeof(int)*FWC_SIZE); + } + + wxFont m_font; + double m_scaleX; + int *m_widths; +}; + +static FontWidthCache s_fontWidthCache; + +bool wxDCBase::DoGetPartialTextExtents(const wxString& text, wxArrayInt& widths) const +{ + int totalWidth = 0; + + const size_t len = text.length(); + widths.Empty(); + widths.Add(0, len); + + // reset the cache if font or horizontal scale have changed + if ( !s_fontWidthCache.m_widths || + !wxIsSameDouble(s_fontWidthCache.m_scaleX, m_scaleX) || + (s_fontWidthCache.m_font != GetFont()) ) + { + s_fontWidthCache.Reset(); + s_fontWidthCache.m_font = GetFont(); + s_fontWidthCache.m_scaleX = m_scaleX; + } + + // Calculate the position of each character based on the widths of + // the previous characters + int w, h; + for ( size_t i = 0; i < len; i++ ) + { + const wxChar c = text[i]; + unsigned int c_int = (unsigned int)c; + + if ((c_int < FWC_SIZE) && (s_fontWidthCache.m_widths[c_int] != 0)) + { + w = s_fontWidthCache.m_widths[c_int]; + } + else + { + GetTextExtent(c, &w, &h); + if (c_int < FWC_SIZE) + s_fontWidthCache.m_widths[c_int] = w; + } + + totalWidth += w; + widths[i] = totalWidth; + } + + return true; +} + + +// ---------------------------------------------------------------------------- +// enhanced text drawing +// ---------------------------------------------------------------------------- + +void wxDCBase::GetMultiLineTextExtent(const wxString& text, + wxCoord *x, + wxCoord *y, + wxCoord *h, + wxFont *font) const +{ + wxCoord widthTextMax = 0, widthLine, + heightTextTotal = 0, heightLineDefault = 0, heightLine = 0; + + wxString curLine; + for ( const wxChar *pc = text; ; pc++ ) + { + if ( *pc == _T('\n') || *pc == _T('\0') ) + { + if ( curLine.empty() ) + { + // we can't use GetTextExtent - it will return 0 for both width + // and height and an empty line should count in height + // calculation + + // assume that this line has the same height as the previous + // one + if ( !heightLineDefault ) + heightLineDefault = heightLine; + + if ( !heightLineDefault ) + { + // but we don't know it yet - choose something reasonable + GetTextExtent(_T("W"), NULL, &heightLineDefault, + NULL, NULL, font); + } + + heightTextTotal += heightLineDefault; + } + else + { + GetTextExtent(curLine, &widthLine, &heightLine, + NULL, NULL, font); + if ( widthLine > widthTextMax ) + widthTextMax = widthLine; + heightTextTotal += heightLine; + } + + if ( *pc == _T('\n') ) + { + curLine.clear(); + } + else + { + // the end of string + break; + } + } + else + { + curLine += *pc; + } + } + + if ( x ) + *x = widthTextMax; + if ( y ) + *y = heightTextTotal; + if ( h ) + *h = heightLine; +} + +void wxDCBase::DrawLabel(const wxString& text, + const wxBitmap& bitmap, + const wxRect& rect, + int alignment, + int indexAccel, + wxRect *rectBounding) +{ + // find the text position + wxCoord widthText, heightText, heightLine; + GetMultiLineTextExtent(text, &widthText, &heightText, &heightLine); + + wxCoord width, height; + if ( bitmap.Ok() ) + { + width = widthText + bitmap.GetWidth(); + height = bitmap.GetHeight(); + } + else // no bitmap + { + width = widthText; + height = heightText; + } + + wxCoord x, y; + if ( alignment & wxALIGN_RIGHT ) + { + x = rect.GetRight() - width; + } + else if ( alignment & wxALIGN_CENTRE_HORIZONTAL ) + { + x = (rect.GetLeft() + rect.GetRight() + 1 - width) / 2; + } + else // alignment & wxALIGN_LEFT + { + x = rect.GetLeft(); + } + + if ( alignment & wxALIGN_BOTTOM ) + { + y = rect.GetBottom() - height; + } + else if ( alignment & wxALIGN_CENTRE_VERTICAL ) + { + y = (rect.GetTop() + rect.GetBottom() + 1 - height) / 2; + } + else // alignment & wxALIGN_TOP + { + y = rect.GetTop(); + } + + // draw the bitmap first + wxCoord x0 = x, + y0 = y, + width0 = width; + if ( bitmap.Ok() ) + { + DrawBitmap(bitmap, x, y, true /* use mask */); + + wxCoord offset = bitmap.GetWidth() + 4; + x += offset; + width -= offset; + + y += (height - heightText) / 2; + } + + // we will draw the underscore under the accel char later + wxCoord startUnderscore = 0, + endUnderscore = 0, + yUnderscore = 0; + + // split the string into lines and draw each of them separately + wxString curLine; + for ( const wxChar *pc = text; ; pc++ ) + { + if ( *pc == _T('\n') || *pc == _T('\0') ) + { + int xRealStart = x; // init it here to avoid compielr warnings + + if ( !curLine.empty() ) + { + // NB: can't test for !(alignment & wxALIGN_LEFT) because + // wxALIGN_LEFT is 0 + if ( alignment & (wxALIGN_RIGHT | wxALIGN_CENTRE_HORIZONTAL) ) + { + wxCoord widthLine; + GetTextExtent(curLine, &widthLine, NULL); + + if ( alignment & wxALIGN_RIGHT ) + { + xRealStart += width - widthLine; + } + else // if ( alignment & wxALIGN_CENTRE_HORIZONTAL ) + { + xRealStart += (width - widthLine) / 2; + } + } + //else: left aligned, nothing to do + + DrawText(curLine, xRealStart, y); + } + + y += heightLine; + + // do we have underscore in this line? we can check yUnderscore + // because it is set below to just y + heightLine if we do + if ( y == yUnderscore ) + { + // adjust the horz positions to account for the shift + startUnderscore += xRealStart; + endUnderscore += xRealStart; + } + + if ( *pc == _T('\0') ) + break; + + curLine.clear(); + } + else // not end of line + { + if ( pc - text.c_str() == indexAccel ) + { + // remeber to draw underscore here + GetTextExtent(curLine, &startUnderscore, NULL); + curLine += *pc; + GetTextExtent(curLine, &endUnderscore, NULL); + + yUnderscore = y + heightLine; + } + else + { + curLine += *pc; + } + } + } + + // draw the underscore if found + if ( startUnderscore != endUnderscore ) + { + // it should be of the same colour as text + SetPen(wxPen(GetTextForeground(), 0, wxSOLID)); + + yUnderscore--; + + DrawLine(startUnderscore, yUnderscore, endUnderscore, yUnderscore); + } + + // return bounding rect if requested + if ( rectBounding ) + { + *rectBounding = wxRect(x, y - heightText, widthText, heightText); + } + + CalcBoundingBox(x0, y0); + CalcBoundingBox(x0 + width0, y0 + height); +} + + +void wxDCBase::DoGradientFillLinear(const wxRect& rect, + const wxColour& initialColour, + const wxColour& destColour, + wxDirection nDirection) +{ + // save old pen + wxPen oldPen = m_pen; + wxBrush oldBrush = m_brush; + + wxUint8 nR1 = initialColour.Red(); + wxUint8 nG1 = initialColour.Green(); + wxUint8 nB1 = initialColour.Blue(); + wxUint8 nR2 = destColour.Red(); + wxUint8 nG2 = destColour.Green(); + wxUint8 nB2 = destColour.Blue(); + wxUint8 nR, nG, nB; + + if ( nDirection == wxEAST || nDirection == wxWEST ) + { + wxInt32 x = rect.GetWidth(); + wxInt32 w = x; // width of area to shade + wxInt32 xDelta = w/256; // height of one shade bend + if (xDelta < 1) + xDelta = 1; + + while (x >= xDelta) + { + x -= xDelta; + if (nR1 > nR2) + nR = nR1 - (nR1-nR2)*(w-x)/w; + else + nR = nR1 + (nR2-nR1)*(w-x)/w; + + if (nG1 > nG2) + nG = nG1 - (nG1-nG2)*(w-x)/w; + else + nG = nG1 + (nG2-nG1)*(w-x)/w; + + if (nB1 > nB2) + nB = nB1 - (nB1-nB2)*(w-x)/w; + else + nB = nB1 + (nB2-nB1)*(w-x)/w; + + wxColour colour(nR,nG,nB); + SetPen(wxPen(colour, 1, wxSOLID)); + SetBrush(wxBrush(colour)); + if(nDirection == wxEAST) + DrawRectangle(rect.GetRight()-x-xDelta+1, rect.GetTop(), + xDelta, rect.GetHeight()); + else //nDirection == wxWEST + DrawRectangle(rect.GetLeft()+x, rect.GetTop(), + xDelta, rect.GetHeight()); + } + } + else // nDirection == wxNORTH || nDirection == wxSOUTH + { + wxInt32 y = rect.GetHeight(); + wxInt32 w = y; // height of area to shade + wxInt32 yDelta = w/255; // height of one shade bend + if (yDelta < 1) + yDelta = 1; + + while (y > 0) + { + y -= yDelta; + if (nR1 > nR2) + nR = nR1 - (nR1-nR2)*(w-y)/w; + else + nR = nR1 + (nR2-nR1)*(w-y)/w; + + if (nG1 > nG2) + nG = nG1 - (nG1-nG2)*(w-y)/w; + else + nG = nG1 + (nG2-nG1)*(w-y)/w; + + if (nB1 > nB2) + nB = nB1 - (nB1-nB2)*(w-y)/w; + else + nB = nB1 + (nB2-nB1)*(w-y)/w; + + wxColour colour(nR,nG,nB); + SetPen(wxPen(colour, 1, wxSOLID)); + SetBrush(wxBrush(colour)); + if(nDirection == wxNORTH) + DrawRectangle(rect.GetLeft(), rect.GetTop()+y, + rect.GetWidth(), yDelta); + else //nDirection == wxSOUTH + DrawRectangle(rect.GetLeft(), rect.GetBottom()-y-yDelta+1, + rect.GetWidth(), yDelta); + } + } + + SetPen(oldPen); + SetBrush(oldBrush); +} + +void wxDCBase::DoGradientFillConcentric(const wxRect& rect, + const wxColour& initialColour, + const wxColour& destColour, + const wxPoint& circleCenter) +{ + //save the old pen color + wxColour oldPenColour = m_pen.GetColour(); + + wxUint8 nR1 = destColour.Red(); + wxUint8 nG1 = destColour.Green(); + wxUint8 nB1 = destColour.Blue(); + wxUint8 nR2 = initialColour.Red(); + wxUint8 nG2 = initialColour.Green(); + wxUint8 nB2 = initialColour.Blue(); + wxUint8 nR, nG, nB; + + + //Radius + wxInt32 cx = rect.GetWidth() / 2; + wxInt32 cy = rect.GetHeight() / 2; + wxInt32 nRadius; + if (cx < cy) + nRadius = cx; + else + nRadius = cy; + + //Offset of circle + wxInt32 nCircleOffX = circleCenter.x - (rect.GetWidth() / 2); + wxInt32 nCircleOffY = circleCenter.y - (rect.GetHeight() / 2); + + for ( wxInt32 x = 0; x < rect.GetWidth(); x++ ) + { + for ( wxInt32 y = 0; y < rect.GetHeight(); y++ ) + { + //get color difference + wxInt32 nGradient = ((nRadius - + (wxInt32)sqrt( + pow((double)(x - cx - nCircleOffX), 2) + + pow((double)(y - cy - nCircleOffY), 2) + )) * 100) / nRadius; + + //normalize Gradient + if (nGradient < 0 ) + nGradient = 0; + + //get dest colors + nR = (wxUint8)(nR1 + ((nR2 - nR1) * nGradient / 100)); + nG = (wxUint8)(nG1 + ((nG2 - nG1) * nGradient / 100)); + nB = (wxUint8)(nB1 + ((nB2 - nB1) * nGradient / 100)); + + //set the pixel + m_pen.SetColour(wxColour(nR,nG,nB)); + DrawPoint(wxPoint(x + rect.GetLeft(), y + rect.GetTop())); + } + } + //return old pen color + m_pen.SetColour(oldPenColour); +} + +/* +Notes for wxWidgets DrawEllipticArcRot(...) + +wxDCBase::DrawEllipticArcRot(...) draws a rotated elliptic arc or an ellipse. +It uses wxDCBase::CalculateEllipticPoints(...) and wxDCBase::Rotate(...), +which are also new. + +All methods are generic, so they can be implemented in wxDCBase. +DoDrawEllipticArcRot(...) is virtual, so it can be called from deeper +methods like (WinCE) wxDC::DoDrawArc(...). + +CalculateEllipticPoints(...) fills a given list of wxPoints with some points +of an elliptic arc. The algorithm is pixel-based: In every row (in flat +parts) or every column (in steep parts) only one pixel is calculated. +Trigonometric calculation (sin, cos, tan, atan) is only done if the +starting angle is not equal to the ending angle. The calculation of the +pixels is done using simple arithmetic only and should perform not too +bad even on devices without floating point processor. I didn't test this yet. + +Rotate(...) rotates a list of point pixel-based, you will see rounding errors. +For instance: an ellipse rotated 180 degrees is drawn +slightly different from the original. + +The points are then moved to an array and used to draw a polyline and/or polygon +(with center added, the pie). +The result looks quite similar to the native ellipse, only e few pixels differ. + +The performance on a desktop system (Athlon 1800, WinXP) is about 7 times +slower as DrawEllipse(...), which calls the native API. +An rotated ellipse outside the clipping region takes nearly the same time, +while an native ellipse outside takes nearly no time to draw. + +If you draw an arc with this new method, you will see the starting and ending angles +are calculated properly. +If you use DrawEllipticArc(...), you will see they are only correct for circles +and not properly calculated for ellipses. + +Peter Lenhard +p.lenhard@t-online.de +*/ + +#ifdef __WXWINCE__ +void wxDCBase::DoDrawEllipticArcRot( wxCoord x, wxCoord y, + wxCoord w, wxCoord h, + double sa, double ea, double angle ) +{ + wxList list; + + CalculateEllipticPoints( &list, x, y, w, h, sa, ea ); + Rotate( &list, angle, wxPoint( x+w/2, y+h/2 ) ); + + // Add center (for polygon/pie) + list.Append( (wxObject*) new wxPoint( x+w/2, y+h/2 ) ); + + // copy list into array and delete list elements + int n = list.GetCount(); + wxPoint *points = new wxPoint[n]; + int i = 0; + wxNode* node = 0; + for ( node = list.GetFirst(); node; node = node->GetNext(), i++ ) + { + wxPoint *point = (wxPoint *)node->GetData(); + points[i].x = point->x; + points[i].y = point->y; + delete point; + } + + // first draw the pie without pen, if necessary + if( GetBrush() != *wxTRANSPARENT_BRUSH ) + { + wxPen tempPen( GetPen() ); + SetPen( *wxTRANSPARENT_PEN ); + DoDrawPolygon( n, points, 0, 0 ); + SetPen( tempPen ); + } + + // then draw the arc without brush, if necessary + if( GetPen() != *wxTRANSPARENT_PEN ) + { + // without center + DoDrawLines( n-1, points, 0, 0 ); + } + + delete [] points; + +} // DrawEllipticArcRot + +void wxDCBase::Rotate( wxList* points, double angle, wxPoint center ) +{ + if( angle != 0.0 ) + { + double pi(M_PI); + double dSinA = -sin(angle*2.0*pi/360.0); + double dCosA = cos(angle*2.0*pi/360.0); + for ( wxNode* node = points->GetFirst(); node; node = node->GetNext() ) + { + wxPoint* point = (wxPoint*)node->GetData(); + + // transform coordinates, if necessary + if( center.x ) point->x -= center.x; + if( center.y ) point->y -= center.y; + + // calculate rotation, rounding simply by implicit cast to integer + int xTemp = point->x * dCosA - point->y * dSinA; + point->y = point->x * dSinA + point->y * dCosA; + point->x = xTemp; + + // back transform coordinates, if necessary + if( center.x ) point->x += center.x; + if( center.y ) point->y += center.y; + } + } +} + +void wxDCBase::CalculateEllipticPoints( wxList* points, + wxCoord xStart, wxCoord yStart, + wxCoord w, wxCoord h, + double sa, double ea ) +{ + double pi = M_PI; + double sar = 0; + double ear = 0; + int xsa = 0; + int ysa = 0; + int xea = 0; + int yea = 0; + int sq = 0; + int eq = 0; + bool bUseAngles = false; + if( w<0 ) w = -w; + if( h<0 ) h = -h; + // half-axes + wxCoord a = w/2; + wxCoord b = h/2; + // decrement 1 pixel if ellipse is smaller than 2*a, 2*b + int decrX = 0; + if( 2*a == w ) decrX = 1; + int decrY = 0; + if( 2*b == h ) decrY = 1; + // center + wxCoord xCenter = xStart + a; + wxCoord yCenter = yStart + b; + // calculate data for start and end, if necessary + if( sa != ea ) + { + bUseAngles = true; + // normalisation of angles + while( sa<0 ) sa += 360; + while( ea<0 ) ea += 360; + while( sa>=360 ) sa -= 360; + while( ea>=360 ) ea -= 360; + // calculate quadrant numbers + if( sa > 270 ) sq = 3; + else if( sa > 180 ) sq = 2; + else if( sa > 90 ) sq = 1; + if( ea > 270 ) eq = 3; + else if( ea > 180 ) eq = 2; + else if( ea > 90 ) eq = 1; + sar = sa * pi / 180.0; + ear = ea * pi / 180.0; + // correct angle circle -> ellipse + sar = atan( -a/(double)b * tan( sar ) ); + if ( sq == 1 || sq == 2 ) sar += pi; + ear = atan( -a/(double)b * tan( ear ) ); + if ( eq == 1 || eq == 2 ) ear += pi; + // coordinates of points + xsa = xCenter + a * cos( sar ); + if( sq == 0 || sq == 3 ) xsa -= decrX; + ysa = yCenter + b * sin( sar ); + if( sq == 2 || sq == 3 ) ysa -= decrY; + xea = xCenter + a * cos( ear ); + if( eq == 0 || eq == 3 ) xea -= decrX; + yea = yCenter + b * sin( ear ); + if( eq == 2 || eq == 3 ) yea -= decrY; + } // if iUseAngles + // calculate c1 = b^2, c2 = b^2/a^2 with a = w/2, b = h/2 + double c1 = b * b; + double c2 = 2.0 / w; + c2 *= c2; + c2 *= c1; + wxCoord x = 0; + wxCoord y = b; + long x2 = 1; + long y2 = y*y; + long y2_old = 0; + long y_old = 0; + // Lists for quadrant 1 to 4 + wxList pointsarray[4]; + // Calculate points for first quadrant and set in all quadrants + for( x = 0; x <= a; ++x ) + { + x2 = x2+x+x-1; + y2_old = y2; + y_old = y; + bool bNewPoint = false; + while( y2 > c1 - c2 * x2 && y > 0 ) + { + bNewPoint = true; + y2 = y2-y-y+1; + --y; + } + // old y now to big: set point with old y, old x + if( bNewPoint && x>1) + { + int x1 = x - 1; + // remove points on the same line + pointsarray[0].Insert( (wxObject*) new wxPoint( xCenter + x1 - decrX, yCenter - y_old ) ); + pointsarray[1].Append( (wxObject*) new wxPoint( xCenter - x1, yCenter - y_old ) ); + pointsarray[2].Insert( (wxObject*) new wxPoint( xCenter - x1, yCenter + y_old - decrY ) ); + pointsarray[3].Append( (wxObject*) new wxPoint( xCenter + x1 - decrX, yCenter + y_old - decrY ) ); + } // set point + } // calculate point + + // Starting and/or ending points for the quadrants, first quadrant gets both. + pointsarray[0].Insert( (wxObject*) new wxPoint( xCenter + a - decrX, yCenter ) ); + pointsarray[0].Append( (wxObject*) new wxPoint( xCenter, yCenter - b ) ); + pointsarray[1].Append( (wxObject*) new wxPoint( xCenter - a, yCenter ) ); + pointsarray[2].Append( (wxObject*) new wxPoint( xCenter, yCenter + b - decrY ) ); + pointsarray[3].Append( (wxObject*) new wxPoint( xCenter + a - decrX, yCenter ) ); + + // copy quadrants in original list + if( bUseAngles ) + { + // Copy the right part of the points in the lists + // and delete the wxPoints, because they do not leave this method. + points->Append( (wxObject*) new wxPoint( xsa, ysa ) ); + int q = sq; + bool bStarted = false; + bool bReady = false; + bool bForceTurn = ( sq == eq && sa > ea ); + while( !bReady ) + { + for( wxNode *node = pointsarray[q].GetFirst(); node; node = node->GetNext() ) + { + // once: go to starting point in start quadrant + if( !bStarted && + ( + ( (wxPoint*) node->GetData() )->x < xsa+1 && q <= 1 + || + ( (wxPoint*) node->GetData() )->x > xsa-1 && q >= 2 + ) + ) + { + bStarted = true; + } + + // copy point, if not at ending point + if( bStarted ) + { + if( q != eq || bForceTurn + || + ( (wxPoint*) node->GetData() )->x > xea+1 && q <= 1 + || + ( (wxPoint*) node->GetData() )->x < xea-1 && q >= 2 + ) + { + // copy point + wxPoint* pPoint = new wxPoint( *((wxPoint*) node->GetData() ) ); + points->Append( (wxObject*) pPoint ); + } + else if( q == eq && !bForceTurn || ( (wxPoint*) node->GetData() )->x == xea) + { + bReady = true; + } + } + } // for node + ++q; + if( q > 3 ) q = 0; + bForceTurn = false; + bStarted = true; + } // while not bReady + points->Append( (wxObject*) new wxPoint( xea, yea ) ); + + // delete points + for( q = 0; q < 4; ++q ) + { + for( wxNode *node = pointsarray[q].GetFirst(); node; node = node->GetNext() ) + { + wxPoint *p = (wxPoint *)node->GetData(); + delete p; + } + } + } + else + { + wxNode* node; + // copy whole ellipse, wxPoints will be deleted outside + for( node = pointsarray[0].GetFirst(); node; node = node->GetNext() ) + { + wxObject *p = node->GetData(); + points->Append( p ); + } + for( node = pointsarray[1].GetFirst(); node; node = node->GetNext() ) + { + wxObject *p = node->GetData(); + points->Append( p ); + } + for( node = pointsarray[2].GetFirst(); node; node = node->GetNext() ) + { + wxObject *p = node->GetData(); + points->Append( p ); + } + for( node = pointsarray[3].GetFirst(); node; node = node->GetNext() ) + { + wxObject *p = node->GetData(); + points->Append( p ); + } + } // not iUseAngles +} // CalculateEllipticPoints + +#endif diff --git a/Externals/wxWidgets/src/common/dcbufcmn.cpp b/Externals/wxWidgets/src/common/dcbufcmn.cpp index 88751fe85a..3ac28eae90 100644 --- a/Externals/wxWidgets/src/common/dcbufcmn.cpp +++ b/Externals/wxWidgets/src/common/dcbufcmn.cpp @@ -1,95 +1,95 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/dcbufcmn.cpp -// Purpose: Buffered DC implementation -// Author: Ron Lee, Jaakko Salli -// Modified by: -// Created: Sep-20-2006 -// RCS-ID: $Id: dcbufcmn.cpp 52152 2008-02-27 18:03:12Z VZ $ -// Copyright: (c) wxWidgets team -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#include "wx/dcbuffer.h" - -#ifndef WX_PRECOMP - #include "wx/module.h" -#endif - -// ============================================================================ -// implementation -// ============================================================================ - -// ---------------------------------------------------------------------------- -// wxSharedDCBufferManager: helper class maintaining backing store bitmap -// ---------------------------------------------------------------------------- - -class wxSharedDCBufferManager : public wxModule -{ -public: - wxSharedDCBufferManager() { } - - virtual bool OnInit() { return true; } - virtual void OnExit() { wxDELETE(ms_buffer); } - - static wxBitmap* GetBuffer(int w, int h) - { - if ( !ms_buffer || - w > ms_buffer->GetWidth() || - h > ms_buffer->GetHeight() ) - { - delete ms_buffer; - - // we must always return a valid bitmap but creating a bitmap of - // size 0 would fail, so create a 1*1 bitmap in this case - if ( !w ) - w = 1; - if ( !h ) - h = 1; - - ms_buffer = new wxBitmap(w, h); - } - return ms_buffer; - } - -private: - static wxBitmap *ms_buffer; - - DECLARE_DYNAMIC_CLASS(wxSharedDCBufferManager) -}; - -wxBitmap* wxSharedDCBufferManager::ms_buffer = NULL; - -IMPLEMENT_DYNAMIC_CLASS(wxSharedDCBufferManager, wxModule) - -// ============================================================================ -// wxBufferedDC -// ============================================================================ - -void wxBufferedDC::UseBuffer(wxCoord w, wxCoord h) -{ - if ( !m_buffer || !m_buffer->IsOk() ) - { - if ( w == -1 || h == -1 ) - m_dc->GetSize(&w, &h); - - m_buffer = wxSharedDCBufferManager::GetBuffer(w, h); - } - - SelectObject(*m_buffer); -} - +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/dcbufcmn.cpp +// Purpose: Buffered DC implementation +// Author: Ron Lee, Jaakko Salli +// Modified by: +// Created: Sep-20-2006 +// RCS-ID: $Id: dcbufcmn.cpp 52152 2008-02-27 18:03:12Z VZ $ +// Copyright: (c) wxWidgets team +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#include "wx/dcbuffer.h" + +#ifndef WX_PRECOMP + #include "wx/module.h" +#endif + +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// wxSharedDCBufferManager: helper class maintaining backing store bitmap +// ---------------------------------------------------------------------------- + +class wxSharedDCBufferManager : public wxModule +{ +public: + wxSharedDCBufferManager() { } + + virtual bool OnInit() { return true; } + virtual void OnExit() { wxDELETE(ms_buffer); } + + static wxBitmap* GetBuffer(int w, int h) + { + if ( !ms_buffer || + w > ms_buffer->GetWidth() || + h > ms_buffer->GetHeight() ) + { + delete ms_buffer; + + // we must always return a valid bitmap but creating a bitmap of + // size 0 would fail, so create a 1*1 bitmap in this case + if ( !w ) + w = 1; + if ( !h ) + h = 1; + + ms_buffer = new wxBitmap(w, h); + } + return ms_buffer; + } + +private: + static wxBitmap *ms_buffer; + + DECLARE_DYNAMIC_CLASS(wxSharedDCBufferManager) +}; + +wxBitmap* wxSharedDCBufferManager::ms_buffer = NULL; + +IMPLEMENT_DYNAMIC_CLASS(wxSharedDCBufferManager, wxModule) + +// ============================================================================ +// wxBufferedDC +// ============================================================================ + +void wxBufferedDC::UseBuffer(wxCoord w, wxCoord h) +{ + if ( !m_buffer || !m_buffer->IsOk() ) + { + if ( w == -1 || h == -1 ) + m_dc->GetSize(&w, &h); + + m_buffer = wxSharedDCBufferManager::GetBuffer(w, h); + } + + SelectObject(*m_buffer); +} + diff --git a/Externals/wxWidgets/src/common/dcgraph.cpp b/Externals/wxWidgets/src/common/dcgraph.cpp index 0282a8c9d5..78bd6d2a47 100644 --- a/Externals/wxWidgets/src/common/dcgraph.cpp +++ b/Externals/wxWidgets/src/common/dcgraph.cpp @@ -1,1026 +1,1026 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/graphcmn.cpp -// Purpose: graphics context methods common to all platforms -// Author: Stefan Csomor -// Modified by: -// Created: -// RCS-ID: $Id: dcgraph.cpp 53772 2008-05-27 04:57:52Z SC $ -// Copyright: (c) Stefan Csomor -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#if defined(__BORLANDC__) - #pragma hdrstop -#endif - -#if wxUSE_GRAPHICS_CONTEXT - -#include "wx/graphics.h" - -#ifndef WX_PRECOMP - #include "wx/icon.h" - #include "wx/bitmap.h" - #include "wx/dcmemory.h" - #include "wx/region.h" -#endif - -#ifdef __WXMAC__ -#include "wx/mac/private.h" -#endif -//----------------------------------------------------------------------------- -// constants -//----------------------------------------------------------------------------- - -static const double RAD2DEG = 180.0 / M_PI; - -//----------------------------------------------------------------------------- -// Local functions -//----------------------------------------------------------------------------- - -static inline double DegToRad(double deg) -{ - return (deg * M_PI) / 180.0; -} - -//----------------------------------------------------------------------------- -// wxDC bridge class -//----------------------------------------------------------------------------- - -#ifdef __WXMAC__ -IMPLEMENT_DYNAMIC_CLASS(wxGCDC, wxDCBase) -#else -IMPLEMENT_DYNAMIC_CLASS(wxGCDC, wxDC) -#endif - -wxGCDC::wxGCDC() -{ - Init(); -} - -void wxGCDC::SetGraphicsContext( wxGraphicsContext* ctx ) -{ - delete m_graphicContext; - m_graphicContext = ctx; - if ( m_graphicContext ) - { - m_matrixOriginal = m_graphicContext->GetTransform(); - m_ok = true; - // apply the stored transformations to the passed in context - ComputeScaleAndOrigin(); - m_graphicContext->SetFont( m_font , m_textForegroundColour ); - m_graphicContext->SetPen( m_pen ); - m_graphicContext->SetBrush( m_brush); - } -} - -wxGCDC::wxGCDC(const wxWindowDC& dc) -{ - Init(); - SetGraphicsContext( wxGraphicsContext::Create(dc) ); -} - -#ifdef __WXMSW__ -wxGCDC::wxGCDC(const wxMemoryDC& dc) -{ - Init(); - SetGraphicsContext( wxGraphicsContext::Create(dc) ); -} -#endif - -void wxGCDC::Init() -{ - m_ok = false; - m_colour = true; - m_mm_to_pix_x = mm2pt; - m_mm_to_pix_y = mm2pt; - - m_pen = *wxBLACK_PEN; - m_font = *wxNORMAL_FONT; - m_brush = *wxWHITE_BRUSH; - - m_graphicContext = NULL; - m_logicalFunctionSupported = true; -} - - -wxGCDC::~wxGCDC() -{ - delete m_graphicContext; -} - -void wxGCDC::DoDrawBitmap( const wxBitmap &bmp, wxCoord x, wxCoord y, bool WXUNUSED(useMask) ) -{ - wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoDrawBitmap - invalid DC") ); - wxCHECK_RET( bmp.Ok(), wxT("wxGCDC(cg)::DoDrawBitmap - invalid bitmap") ); - - if ( bmp.GetDepth() == 1 ) - { - m_graphicContext->SetPen(*wxTRANSPARENT_PEN); - m_graphicContext->SetBrush( wxBrush( m_textBackgroundColour , wxSOLID ) ); - m_graphicContext->DrawRectangle( x , y , bmp.GetWidth() , bmp.GetHeight() ); - m_graphicContext->SetBrush( wxBrush( m_textForegroundColour , wxSOLID ) ); - m_graphicContext->DrawBitmap( bmp, x , y , bmp.GetWidth() , bmp.GetHeight() ); - m_graphicContext->SetBrush( m_graphicContext->CreateBrush(m_brush)); - m_graphicContext->SetPen( m_graphicContext->CreatePen(m_pen)); - } - else - m_graphicContext->DrawBitmap( bmp, x , y , bmp.GetWidth() , bmp.GetHeight() ); -} - -void wxGCDC::DoDrawIcon( const wxIcon &icon, wxCoord x, wxCoord y ) -{ - wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoDrawIcon - invalid DC") ); - wxCHECK_RET( icon.Ok(), wxT("wxGCDC(cg)::DoDrawIcon - invalid icon") ); - - wxCoord w = icon.GetWidth(); - wxCoord h = icon.GetHeight(); - - m_graphicContext->DrawIcon( icon , x, y, w, h ); -} - -bool wxGCDC::StartDoc( const wxString& WXUNUSED(message) ) -{ - return true; -} - -void wxGCDC::EndDoc() -{ -} - -void wxGCDC::StartPage() -{ -} - -void wxGCDC::EndPage() -{ -} - -void wxGCDC::Flush() -{ -#ifdef __WXMAC__ - CGContextFlush( (CGContextRef) m_graphicContext->GetNativeContext() ); -#endif -} - -void wxGCDC::DoSetClippingRegion( wxCoord x, wxCoord y, wxCoord w, wxCoord h ) -{ - wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoSetClippingRegion - invalid DC") ); - - m_graphicContext->Clip( x, y, w, h ); - if ( m_clipping ) - { - m_clipX1 = wxMax( m_clipX1, x ); - m_clipY1 = wxMax( m_clipY1, y ); - m_clipX2 = wxMin( m_clipX2, (x + w) ); - m_clipY2 = wxMin( m_clipY2, (y + h) ); - } - else - { - m_clipping = true; - - m_clipX1 = x; - m_clipY1 = y; - m_clipX2 = x + w; - m_clipY2 = y + h; - } -} - -void wxGCDC::DoSetClippingRegionAsRegion( const wxRegion ®ion ) -{ - // region is in device coordinates - wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoSetClippingRegionAsRegion - invalid DC") ); - - if (region.Empty()) - { - //DestroyClippingRegion(); - return; - } - - wxRegion logRegion( region ); - wxCoord x, y, w, h; - - logRegion.Offset( DeviceToLogicalX(0), DeviceToLogicalY(0) ); - logRegion.GetBox( x, y, w, h ); - - m_graphicContext->Clip( logRegion ); - if ( m_clipping ) - { - m_clipX1 = wxMax( m_clipX1, x ); - m_clipY1 = wxMax( m_clipY1, y ); - m_clipX2 = wxMin( m_clipX2, (x + w) ); - m_clipY2 = wxMin( m_clipY2, (y + h) ); - } - else - { - m_clipping = true; - - m_clipX1 = x; - m_clipY1 = y; - m_clipX2 = x + w; - m_clipY2 = y + h; - } -} - -void wxGCDC::DestroyClippingRegion() -{ - m_graphicContext->ResetClip(); - // currently the clip eg of a window extends to the area between the scrollbars - // so we must explicitely make sure it only covers the area we want it to draw - int width, height ; - GetSize( &width , &height ) ; - m_graphicContext->Clip( DeviceToLogicalX(0) , DeviceToLogicalY(0) , DeviceToLogicalXRel(width), DeviceToLogicalYRel(height) ); - - m_graphicContext->SetPen( m_pen ); - m_graphicContext->SetBrush( m_brush ); - - m_clipping = false; -} - -void wxGCDC::DoGetSizeMM( int* width, int* height ) const -{ - int w = 0, h = 0; - - GetSize( &w, &h ); - if (width) - *width = long( double(w) / (m_scaleX * m_mm_to_pix_x) ); - if (height) - *height = long( double(h) / (m_scaleY * m_mm_to_pix_y) ); -} - -void wxGCDC::SetTextForeground( const wxColour &col ) -{ - wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::SetTextForeground - invalid DC") ); - - if ( col != m_textForegroundColour ) - { - m_textForegroundColour = col; - m_graphicContext->SetFont( m_font, m_textForegroundColour ); - } -} - -void wxGCDC::SetTextBackground( const wxColour &col ) -{ - wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::SetTextBackground - invalid DC") ); - - m_textBackgroundColour = col; -} - -void wxGCDC::SetMapMode( int mode ) -{ - switch (mode) - { - case wxMM_TWIPS: - SetLogicalScale( twips2mm * m_mm_to_pix_x, twips2mm * m_mm_to_pix_y ); - break; - - case wxMM_POINTS: - SetLogicalScale( pt2mm * m_mm_to_pix_x, pt2mm * m_mm_to_pix_y ); - break; - - case wxMM_METRIC: - SetLogicalScale( m_mm_to_pix_x, m_mm_to_pix_y ); - break; - - case wxMM_LOMETRIC: - SetLogicalScale( m_mm_to_pix_x / 10.0, m_mm_to_pix_y / 10.0 ); - break; - - case wxMM_TEXT: - default: - SetLogicalScale( 1.0, 1.0 ); - break; - } - - ComputeScaleAndOrigin(); -} - -void wxGCDC::SetUserScale( double x, double y ) -{ - // allow negative ? -> no - - m_userScaleX = x; - m_userScaleY = y; - ComputeScaleAndOrigin(); -} - -void wxGCDC::SetLogicalScale( double x, double y ) -{ - // allow negative ? - m_logicalScaleX = x; - m_logicalScaleY = y; - ComputeScaleAndOrigin(); -} - -void wxGCDC::SetLogicalOrigin( wxCoord x, wxCoord y ) -{ - m_logicalOriginX = x * m_signX; // is this still correct ? - m_logicalOriginY = y * m_signY; - ComputeScaleAndOrigin(); -} - -void wxGCDC::SetDeviceOrigin( wxCoord x, wxCoord y ) -{ - m_deviceOriginX = x; - m_deviceOriginY = y; - ComputeScaleAndOrigin(); -} - -void wxGCDC::SetAxisOrientation( bool xLeftRight, bool yBottomUp ) -{ - m_signX = (xLeftRight ? 1 : -1); - m_signY = (yBottomUp ? -1 : 1); - ComputeScaleAndOrigin(); -} - -wxSize wxGCDC::GetPPI() const -{ - return wxSize(72, 72); -} - -int wxGCDC::GetDepth() const -{ - return 32; -} - -void wxGCDC::ComputeScaleAndOrigin() -{ - m_scaleX = m_logicalScaleX * m_userScaleX; - m_scaleY = m_logicalScaleY * m_userScaleY; - - if ( m_graphicContext ) - { - m_matrixCurrent = m_graphicContext->CreateMatrix(); - m_matrixCurrent.Translate( m_deviceOriginX, m_deviceOriginY ); - m_matrixCurrent.Scale( m_scaleX, m_scaleY ); - // the logical origin sets the origin to have new coordinates - m_matrixCurrent.Translate( -m_logicalOriginX, -m_logicalOriginY ); - - m_graphicContext->SetTransform( m_matrixOriginal ); - m_graphicContext->ConcatTransform( m_matrixCurrent ); - } -} - -void wxGCDC::SetPalette( const wxPalette& WXUNUSED(palette) ) -{ - -} - -void wxGCDC::SetBackgroundMode( int mode ) -{ - m_backgroundMode = mode; -} - -void wxGCDC::SetFont( const wxFont &font ) -{ - m_font = font; - if ( m_graphicContext ) - { - wxFont f = font; - if ( f.Ok() ) - f.SetPointSize( /*LogicalToDeviceYRel*/(font.GetPointSize())); - m_graphicContext->SetFont( f, m_textForegroundColour ); - } -} - -void wxGCDC::SetPen( const wxPen &pen ) -{ - if ( m_pen == pen ) - return; - - m_pen = pen; - if ( m_graphicContext ) - { - m_graphicContext->SetPen( m_pen ); - } -} - -void wxGCDC::SetBrush( const wxBrush &brush ) -{ - if (m_brush == brush) - return; - - m_brush = brush; - if ( m_graphicContext ) - { - m_graphicContext->SetBrush( m_brush ); - } -} - -void wxGCDC::SetBackground( const wxBrush &brush ) -{ - if (m_backgroundBrush == brush) - return; - - m_backgroundBrush = brush; - if (!m_backgroundBrush.Ok()) - return; -} - -void wxGCDC::SetLogicalFunction( int function ) -{ - if (m_logicalFunction == function) - return; - - m_logicalFunction = function; - if ( m_graphicContext->SetLogicalFunction( function ) ) - m_logicalFunctionSupported=true; - else - m_logicalFunctionSupported=false; -} - -bool wxGCDC::DoFloodFill(wxCoord WXUNUSED(x), wxCoord WXUNUSED(y), - const wxColour& WXUNUSED(col), int WXUNUSED(style)) -{ - return false; -} - -bool wxGCDC::DoGetPixel( wxCoord WXUNUSED(x), wxCoord WXUNUSED(y), wxColour *WXUNUSED(col) ) const -{ - // wxCHECK_MSG( 0 , false, wxT("wxGCDC(cg)::DoGetPixel - not implemented") ); - return false; -} - -void wxGCDC::DoDrawLine( wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2 ) -{ - wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoDrawLine - invalid DC") ); - - if ( !m_logicalFunctionSupported ) - return; - - m_graphicContext->StrokeLine(x1,y1,x2,y2); - - CalcBoundingBox(x1, y1); - CalcBoundingBox(x2, y2); -} - -void wxGCDC::DoCrossHair( wxCoord x, wxCoord y ) -{ - wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoCrossHair - invalid DC") ); - - if ( !m_logicalFunctionSupported ) - return; - - int w = 0, h = 0; - - GetSize( &w, &h ); - - m_graphicContext->StrokeLine(0,y,w,y); - m_graphicContext->StrokeLine(x,0,x,h); - - CalcBoundingBox(0, 0); - CalcBoundingBox(0+w, 0+h); -} - -void wxGCDC::DoDrawArc( wxCoord x1, wxCoord y1, - wxCoord x2, wxCoord y2, - wxCoord xc, wxCoord yc ) -{ - wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoDrawArc - invalid DC") ); - - if ( !m_logicalFunctionSupported ) - return; - - double dx = x1 - xc; - double dy = y1 - yc; - double radius = sqrt((double)(dx * dx + dy * dy)); - wxCoord rad = (wxCoord)radius; - double sa, ea; - if (x1 == x2 && y1 == y2) - { - sa = 0.0; - ea = 360.0; - } - else if (radius == 0.0) - { - sa = ea = 0.0; - } - else - { - sa = (x1 - xc == 0) ? - (y1 - yc < 0) ? 90.0 : -90.0 : - -atan2(double(y1 - yc), double(x1 - xc)) * RAD2DEG; - ea = (x2 - xc == 0) ? - (y2 - yc < 0) ? 90.0 : -90.0 : - -atan2(double(y2 - yc), double(x2 - xc)) * RAD2DEG; - } - - bool fill = m_brush.GetStyle() != wxTRANSPARENT; - - wxGraphicsPath path = m_graphicContext->CreatePath(); - if ( fill && ((x1!=x2)||(y1!=y2)) ) - path.MoveToPoint( xc, yc ); - // since these angles (ea,sa) are measured counter-clockwise, we invert them to - // get clockwise angles - path.AddArc( xc, yc , rad , DegToRad(-sa) , DegToRad(-ea), false ); - if ( fill && ((x1!=x2)||(y1!=y2)) ) - path.AddLineToPoint( xc, yc ); - m_graphicContext->DrawPath(path); -} - -void wxGCDC::DoDrawEllipticArc( wxCoord x, wxCoord y, wxCoord w, wxCoord h, - double sa, double ea ) -{ - wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoDrawEllipticArc - invalid DC") ); - - if ( !m_logicalFunctionSupported ) - return; - - m_graphicContext->PushState(); - m_graphicContext->Translate(x+w/2.0,y+h/2.0); - wxDouble factor = ((wxDouble) w) / h; - m_graphicContext->Scale( factor , 1.0); - - // since these angles (ea,sa) are measured counter-clockwise, we invert them to - // get clockwise angles - if ( m_brush.GetStyle() != wxTRANSPARENT ) - { - wxGraphicsPath path = m_graphicContext->CreatePath(); - path.MoveToPoint( 0, 0 ); - path.AddArc( 0, 0, h/2.0 , DegToRad(-sa) , DegToRad(-ea), sa > ea ); - path.AddLineToPoint( 0, 0 ); - m_graphicContext->FillPath( path ); - - path = m_graphicContext->CreatePath(); - path.AddArc( 0, 0, h/2.0 , DegToRad(-sa) , DegToRad(-ea), sa > ea ); - m_graphicContext->StrokePath( path ); - } - else - { - wxGraphicsPath path = m_graphicContext->CreatePath(); - path.AddArc( 0, 0, h/2.0 , DegToRad(-sa) , DegToRad(-ea), sa > ea ); - m_graphicContext->DrawPath( path ); - } - - m_graphicContext->PopState(); -} - -void wxGCDC::DoDrawPoint( wxCoord x, wxCoord y ) -{ - wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoDrawPoint - invalid DC") ); - - DoDrawLine( x , y , x + 1 , y + 1 ); -} - -void wxGCDC::DoDrawLines(int n, wxPoint points[], - wxCoord xoffset, wxCoord yoffset) -{ - wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoDrawLines - invalid DC") ); - - if ( !m_logicalFunctionSupported ) - return; - - wxPoint2DDouble* pointsD = new wxPoint2DDouble[n]; - for( int i = 0; i < n; ++i) - { - pointsD[i].m_x = points[i].x + xoffset; - pointsD[i].m_y = points[i].y + yoffset; - } - - m_graphicContext->StrokeLines( n , pointsD); - delete[] pointsD; -} - -#if wxUSE_SPLINES -void wxGCDC::DoDrawSpline(wxList *points) -{ - wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoDrawSpline - invalid DC") ); - - if ( !m_logicalFunctionSupported ) - return; - - wxGraphicsPath path = m_graphicContext->CreatePath(); - - wxList::compatibility_iterator node = points->GetFirst(); - if (node == wxList::compatibility_iterator()) - // empty list - return; - - wxPoint *p = (wxPoint *)node->GetData(); - - wxCoord x1 = p->x; - wxCoord y1 = p->y; - - node = node->GetNext(); - p = (wxPoint *)node->GetData(); - - wxCoord x2 = p->x; - wxCoord y2 = p->y; - wxCoord cx1 = ( x1 + x2 ) / 2; - wxCoord cy1 = ( y1 + y2 ) / 2; - - path.MoveToPoint( x1 , y1 ); - path.AddLineToPoint( cx1 , cy1 ); -#if !wxUSE_STL - - while ((node = node->GetNext()) != NULL) -#else - - while ((node = node->GetNext())) -#endif // !wxUSE_STL - - { - p = (wxPoint *)node->GetData(); - x1 = x2; - y1 = y2; - x2 = p->x; - y2 = p->y; - wxCoord cx4 = (x1 + x2) / 2; - wxCoord cy4 = (y1 + y2) / 2; - - path.AddQuadCurveToPoint(x1 , y1 ,cx4 , cy4 ); - - cx1 = cx4; - cy1 = cy4; - } - - path.AddLineToPoint( x2 , y2 ); - - m_graphicContext->StrokePath( path ); -} -#endif // wxUSE_SPLINES - -void wxGCDC::DoDrawPolygon( int n, wxPoint points[], - wxCoord xoffset, wxCoord yoffset, - int fillStyle ) -{ - wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoDrawPolygon - invalid DC") ); - - if ( n <= 0 || (m_brush.GetStyle() == wxTRANSPARENT && m_pen.GetStyle() == wxTRANSPARENT ) ) - return; - if ( !m_logicalFunctionSupported ) - return; - - bool closeIt = false; - if (points[n-1] != points[0]) - closeIt = true; - - wxPoint2DDouble* pointsD = new wxPoint2DDouble[n+(closeIt?1:0)]; - for( int i = 0; i < n; ++i) - { - pointsD[i].m_x = points[i].x + xoffset; - pointsD[i].m_y = points[i].y + yoffset; - } - if ( closeIt ) - pointsD[n] = pointsD[0]; - - m_graphicContext->DrawLines( n+(closeIt?1:0) , pointsD, fillStyle); - delete[] pointsD; -} - -void wxGCDC::DoDrawPolyPolygon(int n, - int count[], - wxPoint points[], - wxCoord xoffset, - wxCoord yoffset, - int fillStyle) -{ - wxASSERT(n > 1); - wxGraphicsPath path = m_graphicContext->CreatePath(); - - int i = 0; - for ( int j = 0; j < n; ++j) - { - wxPoint start = points[i]; - path.MoveToPoint( start.x+ xoffset, start.y+ yoffset); - ++i; - int l = count[j]; - for ( int k = 1; k < l; ++k) - { - path.AddLineToPoint( points[i].x+ xoffset, points[i].y+ yoffset); - ++i; - } - // close the polygon - if ( start != points[i-1]) - path.AddLineToPoint( start.x+ xoffset, start.y+ yoffset); - } - m_graphicContext->DrawPath( path , fillStyle); -} - -void wxGCDC::DoDrawRectangle(wxCoord x, wxCoord y, wxCoord w, wxCoord h) -{ - wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoDrawRectangle - invalid DC") ); - - if ( !m_logicalFunctionSupported ) - return; - - // CMB: draw nothing if transformed w or h is 0 - if (w == 0 || h == 0) - return; - - if ( m_graphicContext->ShouldOffset() ) - { - // if we are offsetting the entire rectangle is moved 0.5, so the - // border line gets off by 1 - w -= 1; - h -= 1; - } - m_graphicContext->DrawRectangle(x,y,w,h); -} - -void wxGCDC::DoDrawRoundedRectangle(wxCoord x, wxCoord y, - wxCoord w, wxCoord h, - double radius) -{ - wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoDrawRoundedRectangle - invalid DC") ); - - if ( !m_logicalFunctionSupported ) - return; - - if (radius < 0.0) - radius = - radius * ((w < h) ? w : h); - - // CMB: draw nothing if transformed w or h is 0 - if (w == 0 || h == 0) - return; - - if ( m_graphicContext->ShouldOffset() ) - { - // if we are offsetting the entire rectangle is moved 0.5, so the - // border line gets off by 1 - w -= 1; - h -= 1; - } - m_graphicContext->DrawRoundedRectangle( x,y,w,h,radius); -} - -void wxGCDC::DoDrawEllipse(wxCoord x, wxCoord y, wxCoord w, wxCoord h) -{ - wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoDrawEllipse - invalid DC") ); - - if ( !m_logicalFunctionSupported ) - return; - - if ( m_graphicContext->ShouldOffset() ) - { - // if we are offsetting the entire rectangle is moved 0.5, so the - // border line gets off by 1 - w -= 1; - h -= 1; - } - m_graphicContext->DrawEllipse(x,y,w,h); -} - -bool wxGCDC::CanDrawBitmap() const -{ - return true; -} - -bool wxGCDC::DoBlit( - wxCoord xdest, wxCoord ydest, wxCoord width, wxCoord height, - wxDC *source, wxCoord xsrc, wxCoord ysrc, int logical_func , bool WXUNUSED(useMask), - wxCoord xsrcMask, wxCoord ysrcMask ) -{ - wxCHECK_MSG( Ok(), false, wxT("wxGCDC(cg)::DoBlit - invalid DC") ); - wxCHECK_MSG( source->Ok(), false, wxT("wxGCDC(cg)::DoBlit - invalid source DC") ); - - if ( logical_func == wxNO_OP ) - return true; - else if ( !m_graphicContext->SetLogicalFunction( logical_func ) ) - - { - wxFAIL_MSG( wxT("Logical function is not supported by the graphics context.") ); - return false; - } - - if (xsrcMask == -1 && ysrcMask == -1) - { - xsrcMask = xsrc; - ysrcMask = ysrc; - } - - wxRect subrect(source->LogicalToDeviceX(xsrc), - source->LogicalToDeviceY(ysrc), - source->LogicalToDeviceXRel(width), - source->LogicalToDeviceYRel(height)); - - // if needed clip the subrect down to the size of the source DC - wxCoord sw, sh; - source->GetSize(&sw, &sh); - sw = source->LogicalToDeviceXRel(sw); - sh = source->LogicalToDeviceYRel(sh); - if (subrect.x + subrect.width > sw) - subrect.width = sw - subrect.x; - if (subrect.y + subrect.height > sh) - subrect.height = sh - subrect.y; - - wxBitmap blit = source->GetAsBitmap( &subrect ); - - if ( blit.Ok() ) - { - m_graphicContext->DrawBitmap( blit, xdest, ydest, - wxMin(width, blit.GetWidth()), - wxMin(height, blit.GetHeight())); - } - else - { - wxFAIL_MSG( wxT("Cannot Blit. Unable to get contents of DC as bitmap.") ); - return false; - } - - // reset logical function - m_graphicContext->SetLogicalFunction( m_logicalFunction ); - - return true; -} - -void wxGCDC::DoDrawRotatedText(const wxString& str, wxCoord x, wxCoord y, - double angle) -{ - wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoDrawRotatedText - invalid DC") ); - - if ( str.length() == 0 ) - return; - if ( !m_logicalFunctionSupported ) - return; - - if ( m_backgroundMode == wxTRANSPARENT ) - m_graphicContext->DrawText( str, x ,y , DegToRad(angle )); - else - m_graphicContext->DrawText( str, x ,y , DegToRad(angle ), m_graphicContext->CreateBrush( wxBrush(m_textBackgroundColour,wxSOLID) ) ); -} - -void wxGCDC::DoDrawText(const wxString& str, wxCoord x, wxCoord y) -{ - wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoDrawRotatedText - invalid DC") ); - - if ( str.length() == 0 ) - return; - - if ( !m_logicalFunctionSupported ) - return; - - if ( m_backgroundMode == wxTRANSPARENT ) - m_graphicContext->DrawText( str, x ,y); - else - m_graphicContext->DrawText( str, x ,y , m_graphicContext->CreateBrush( wxBrush(m_textBackgroundColour,wxSOLID) ) ); -} - -bool wxGCDC::CanGetTextExtent() const -{ - wxCHECK_MSG( Ok(), false, wxT("wxGCDC(cg)::CanGetTextExtent - invalid DC") ); - - return true; -} - -void wxGCDC::DoGetTextExtent( const wxString &str, wxCoord *width, wxCoord *height, - wxCoord *descent, wxCoord *externalLeading , - wxFont *theFont ) const -{ - wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoGetTextExtent - invalid DC") ); - - if ( theFont ) - { - m_graphicContext->SetFont( *theFont, m_textForegroundColour ); - } - - wxDouble h , d , e , w; - - m_graphicContext->GetTextExtent( str, &w, &h, &d, &e ); - - if ( height ) - *height = (wxCoord)(h+0.5); - if ( descent ) - *descent = (wxCoord)(d+0.5); - if ( externalLeading ) - *externalLeading = (wxCoord)(e+0.5); - if ( width ) - *width = (wxCoord)(w+0.5); - - if ( theFont ) - { - m_graphicContext->SetFont( m_font, m_textForegroundColour ); - } -} - -bool wxGCDC::DoGetPartialTextExtents(const wxString& text, wxArrayInt& widths) const -{ - wxCHECK_MSG( Ok(), false, wxT("wxGCDC(cg)::DoGetPartialTextExtents - invalid DC") ); - widths.Clear(); - widths.Add(0,text.Length()); - if ( text.IsEmpty() ) - return true; - - wxArrayDouble widthsD; - - m_graphicContext->GetPartialTextExtents( text, widthsD ); - for ( size_t i = 0; i < widths.GetCount(); ++i ) - widths[i] = (wxCoord)(widthsD[i] + 0.5); - - return true; -} - -wxCoord wxGCDC::GetCharWidth(void) const -{ - wxCoord width; - DoGetTextExtent( wxT("g") , &width , NULL , NULL , NULL , NULL ); - - return width; -} - -wxCoord wxGCDC::GetCharHeight(void) const -{ - wxCoord height; - DoGetTextExtent( wxT("g") , NULL , &height , NULL , NULL , NULL ); - - return height; -} - -void wxGCDC::Clear(void) -{ - wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::Clear - invalid DC") ); - // TODO better implementation / incorporate size info into wxGCDC or context - m_graphicContext->SetBrush( m_backgroundBrush ); - wxPen p = *wxTRANSPARENT_PEN; - m_graphicContext->SetPen( p ); - DoDrawRectangle( 0, 0, 32000 , 32000 ); - m_graphicContext->SetPen( m_pen ); - m_graphicContext->SetBrush( m_brush ); -} - -void wxGCDC::DoGetSize(int *width, int *height) const -{ - *width = 10000; - *height = 10000; -} - -void wxGCDC::DoGradientFillLinear(const wxRect& rect, - const wxColour& initialColour, - const wxColour& destColour, - wxDirection nDirection ) -{ - wxPoint start; - wxPoint end; - switch( nDirection) - { - case wxWEST : - start = rect.GetRightBottom(); - start.x++; - end = rect.GetLeftBottom(); - break; - case wxEAST : - start = rect.GetLeftBottom(); - end = rect.GetRightBottom(); - end.x++; - break; - case wxNORTH : - start = rect.GetLeftBottom(); - start.y++; - end = rect.GetLeftTop(); - break; - case wxSOUTH : - start = rect.GetLeftTop(); - end = rect.GetLeftBottom(); - end.y++; - break; - default : - break; - } - - if (rect.width == 0 || rect.height == 0) - return; - - m_graphicContext->SetBrush( m_graphicContext->CreateLinearGradientBrush( - start.x,start.y,end.x,end.y, initialColour, destColour)); - m_graphicContext->SetPen(*wxTRANSPARENT_PEN); - m_graphicContext->DrawRectangle(rect.x,rect.y,rect.width,rect.height); - m_graphicContext->SetPen(m_pen); -} - -void wxGCDC::DoGradientFillConcentric(const wxRect& rect, - const wxColour& initialColour, - const wxColour& destColour, - const wxPoint& circleCenter) -{ - //Radius - wxInt32 cx = rect.GetWidth() / 2; - wxInt32 cy = rect.GetHeight() / 2; - wxInt32 nRadius; - if (cx < cy) - nRadius = cx; - else - nRadius = cy; - - // make sure the background is filled (todo move into specific platform implementation ?) - m_graphicContext->SetPen(*wxTRANSPARENT_PEN); - m_graphicContext->SetBrush( wxBrush( destColour) ); - m_graphicContext->DrawRectangle(rect.x,rect.y,rect.width,rect.height); - - m_graphicContext->SetBrush( m_graphicContext->CreateRadialGradientBrush( - rect.x+circleCenter.x,rect.y+circleCenter.y, - rect.x+circleCenter.x,rect.y+circleCenter.y, - nRadius,initialColour,destColour)); - - m_graphicContext->DrawRectangle(rect.x,rect.y,rect.width,rect.height); - m_graphicContext->SetPen(m_pen); -} - -void wxGCDC::DoDrawCheckMark(wxCoord x, wxCoord y, - wxCoord width, wxCoord height) -{ - wxDCBase::DoDrawCheckMark(x,y,width,height); -} - -#endif // wxUSE_GRAPHICS_CONTEXT +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/graphcmn.cpp +// Purpose: graphics context methods common to all platforms +// Author: Stefan Csomor +// Modified by: +// Created: +// RCS-ID: $Id: dcgraph.cpp 53772 2008-05-27 04:57:52Z SC $ +// Copyright: (c) Stefan Csomor +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#if defined(__BORLANDC__) + #pragma hdrstop +#endif + +#if wxUSE_GRAPHICS_CONTEXT + +#include "wx/graphics.h" + +#ifndef WX_PRECOMP + #include "wx/icon.h" + #include "wx/bitmap.h" + #include "wx/dcmemory.h" + #include "wx/region.h" +#endif + +#ifdef __WXMAC__ +#include "wx/mac/private.h" +#endif +//----------------------------------------------------------------------------- +// constants +//----------------------------------------------------------------------------- + +static const double RAD2DEG = 180.0 / M_PI; + +//----------------------------------------------------------------------------- +// Local functions +//----------------------------------------------------------------------------- + +static inline double DegToRad(double deg) +{ + return (deg * M_PI) / 180.0; +} + +//----------------------------------------------------------------------------- +// wxDC bridge class +//----------------------------------------------------------------------------- + +#ifdef __WXMAC__ +IMPLEMENT_DYNAMIC_CLASS(wxGCDC, wxDCBase) +#else +IMPLEMENT_DYNAMIC_CLASS(wxGCDC, wxDC) +#endif + +wxGCDC::wxGCDC() +{ + Init(); +} + +void wxGCDC::SetGraphicsContext( wxGraphicsContext* ctx ) +{ + delete m_graphicContext; + m_graphicContext = ctx; + if ( m_graphicContext ) + { + m_matrixOriginal = m_graphicContext->GetTransform(); + m_ok = true; + // apply the stored transformations to the passed in context + ComputeScaleAndOrigin(); + m_graphicContext->SetFont( m_font , m_textForegroundColour ); + m_graphicContext->SetPen( m_pen ); + m_graphicContext->SetBrush( m_brush); + } +} + +wxGCDC::wxGCDC(const wxWindowDC& dc) +{ + Init(); + SetGraphicsContext( wxGraphicsContext::Create(dc) ); +} + +#ifdef __WXMSW__ +wxGCDC::wxGCDC(const wxMemoryDC& dc) +{ + Init(); + SetGraphicsContext( wxGraphicsContext::Create(dc) ); +} +#endif + +void wxGCDC::Init() +{ + m_ok = false; + m_colour = true; + m_mm_to_pix_x = mm2pt; + m_mm_to_pix_y = mm2pt; + + m_pen = *wxBLACK_PEN; + m_font = *wxNORMAL_FONT; + m_brush = *wxWHITE_BRUSH; + + m_graphicContext = NULL; + m_logicalFunctionSupported = true; +} + + +wxGCDC::~wxGCDC() +{ + delete m_graphicContext; +} + +void wxGCDC::DoDrawBitmap( const wxBitmap &bmp, wxCoord x, wxCoord y, bool WXUNUSED(useMask) ) +{ + wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoDrawBitmap - invalid DC") ); + wxCHECK_RET( bmp.Ok(), wxT("wxGCDC(cg)::DoDrawBitmap - invalid bitmap") ); + + if ( bmp.GetDepth() == 1 ) + { + m_graphicContext->SetPen(*wxTRANSPARENT_PEN); + m_graphicContext->SetBrush( wxBrush( m_textBackgroundColour , wxSOLID ) ); + m_graphicContext->DrawRectangle( x , y , bmp.GetWidth() , bmp.GetHeight() ); + m_graphicContext->SetBrush( wxBrush( m_textForegroundColour , wxSOLID ) ); + m_graphicContext->DrawBitmap( bmp, x , y , bmp.GetWidth() , bmp.GetHeight() ); + m_graphicContext->SetBrush( m_graphicContext->CreateBrush(m_brush)); + m_graphicContext->SetPen( m_graphicContext->CreatePen(m_pen)); + } + else + m_graphicContext->DrawBitmap( bmp, x , y , bmp.GetWidth() , bmp.GetHeight() ); +} + +void wxGCDC::DoDrawIcon( const wxIcon &icon, wxCoord x, wxCoord y ) +{ + wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoDrawIcon - invalid DC") ); + wxCHECK_RET( icon.Ok(), wxT("wxGCDC(cg)::DoDrawIcon - invalid icon") ); + + wxCoord w = icon.GetWidth(); + wxCoord h = icon.GetHeight(); + + m_graphicContext->DrawIcon( icon , x, y, w, h ); +} + +bool wxGCDC::StartDoc( const wxString& WXUNUSED(message) ) +{ + return true; +} + +void wxGCDC::EndDoc() +{ +} + +void wxGCDC::StartPage() +{ +} + +void wxGCDC::EndPage() +{ +} + +void wxGCDC::Flush() +{ +#ifdef __WXMAC__ + CGContextFlush( (CGContextRef) m_graphicContext->GetNativeContext() ); +#endif +} + +void wxGCDC::DoSetClippingRegion( wxCoord x, wxCoord y, wxCoord w, wxCoord h ) +{ + wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoSetClippingRegion - invalid DC") ); + + m_graphicContext->Clip( x, y, w, h ); + if ( m_clipping ) + { + m_clipX1 = wxMax( m_clipX1, x ); + m_clipY1 = wxMax( m_clipY1, y ); + m_clipX2 = wxMin( m_clipX2, (x + w) ); + m_clipY2 = wxMin( m_clipY2, (y + h) ); + } + else + { + m_clipping = true; + + m_clipX1 = x; + m_clipY1 = y; + m_clipX2 = x + w; + m_clipY2 = y + h; + } +} + +void wxGCDC::DoSetClippingRegionAsRegion( const wxRegion ®ion ) +{ + // region is in device coordinates + wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoSetClippingRegionAsRegion - invalid DC") ); + + if (region.Empty()) + { + //DestroyClippingRegion(); + return; + } + + wxRegion logRegion( region ); + wxCoord x, y, w, h; + + logRegion.Offset( DeviceToLogicalX(0), DeviceToLogicalY(0) ); + logRegion.GetBox( x, y, w, h ); + + m_graphicContext->Clip( logRegion ); + if ( m_clipping ) + { + m_clipX1 = wxMax( m_clipX1, x ); + m_clipY1 = wxMax( m_clipY1, y ); + m_clipX2 = wxMin( m_clipX2, (x + w) ); + m_clipY2 = wxMin( m_clipY2, (y + h) ); + } + else + { + m_clipping = true; + + m_clipX1 = x; + m_clipY1 = y; + m_clipX2 = x + w; + m_clipY2 = y + h; + } +} + +void wxGCDC::DestroyClippingRegion() +{ + m_graphicContext->ResetClip(); + // currently the clip eg of a window extends to the area between the scrollbars + // so we must explicitely make sure it only covers the area we want it to draw + int width, height ; + GetSize( &width , &height ) ; + m_graphicContext->Clip( DeviceToLogicalX(0) , DeviceToLogicalY(0) , DeviceToLogicalXRel(width), DeviceToLogicalYRel(height) ); + + m_graphicContext->SetPen( m_pen ); + m_graphicContext->SetBrush( m_brush ); + + m_clipping = false; +} + +void wxGCDC::DoGetSizeMM( int* width, int* height ) const +{ + int w = 0, h = 0; + + GetSize( &w, &h ); + if (width) + *width = long( double(w) / (m_scaleX * m_mm_to_pix_x) ); + if (height) + *height = long( double(h) / (m_scaleY * m_mm_to_pix_y) ); +} + +void wxGCDC::SetTextForeground( const wxColour &col ) +{ + wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::SetTextForeground - invalid DC") ); + + if ( col != m_textForegroundColour ) + { + m_textForegroundColour = col; + m_graphicContext->SetFont( m_font, m_textForegroundColour ); + } +} + +void wxGCDC::SetTextBackground( const wxColour &col ) +{ + wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::SetTextBackground - invalid DC") ); + + m_textBackgroundColour = col; +} + +void wxGCDC::SetMapMode( int mode ) +{ + switch (mode) + { + case wxMM_TWIPS: + SetLogicalScale( twips2mm * m_mm_to_pix_x, twips2mm * m_mm_to_pix_y ); + break; + + case wxMM_POINTS: + SetLogicalScale( pt2mm * m_mm_to_pix_x, pt2mm * m_mm_to_pix_y ); + break; + + case wxMM_METRIC: + SetLogicalScale( m_mm_to_pix_x, m_mm_to_pix_y ); + break; + + case wxMM_LOMETRIC: + SetLogicalScale( m_mm_to_pix_x / 10.0, m_mm_to_pix_y / 10.0 ); + break; + + case wxMM_TEXT: + default: + SetLogicalScale( 1.0, 1.0 ); + break; + } + + ComputeScaleAndOrigin(); +} + +void wxGCDC::SetUserScale( double x, double y ) +{ + // allow negative ? -> no + + m_userScaleX = x; + m_userScaleY = y; + ComputeScaleAndOrigin(); +} + +void wxGCDC::SetLogicalScale( double x, double y ) +{ + // allow negative ? + m_logicalScaleX = x; + m_logicalScaleY = y; + ComputeScaleAndOrigin(); +} + +void wxGCDC::SetLogicalOrigin( wxCoord x, wxCoord y ) +{ + m_logicalOriginX = x * m_signX; // is this still correct ? + m_logicalOriginY = y * m_signY; + ComputeScaleAndOrigin(); +} + +void wxGCDC::SetDeviceOrigin( wxCoord x, wxCoord y ) +{ + m_deviceOriginX = x; + m_deviceOriginY = y; + ComputeScaleAndOrigin(); +} + +void wxGCDC::SetAxisOrientation( bool xLeftRight, bool yBottomUp ) +{ + m_signX = (xLeftRight ? 1 : -1); + m_signY = (yBottomUp ? -1 : 1); + ComputeScaleAndOrigin(); +} + +wxSize wxGCDC::GetPPI() const +{ + return wxSize(72, 72); +} + +int wxGCDC::GetDepth() const +{ + return 32; +} + +void wxGCDC::ComputeScaleAndOrigin() +{ + m_scaleX = m_logicalScaleX * m_userScaleX; + m_scaleY = m_logicalScaleY * m_userScaleY; + + if ( m_graphicContext ) + { + m_matrixCurrent = m_graphicContext->CreateMatrix(); + m_matrixCurrent.Translate( m_deviceOriginX, m_deviceOriginY ); + m_matrixCurrent.Scale( m_scaleX, m_scaleY ); + // the logical origin sets the origin to have new coordinates + m_matrixCurrent.Translate( -m_logicalOriginX, -m_logicalOriginY ); + + m_graphicContext->SetTransform( m_matrixOriginal ); + m_graphicContext->ConcatTransform( m_matrixCurrent ); + } +} + +void wxGCDC::SetPalette( const wxPalette& WXUNUSED(palette) ) +{ + +} + +void wxGCDC::SetBackgroundMode( int mode ) +{ + m_backgroundMode = mode; +} + +void wxGCDC::SetFont( const wxFont &font ) +{ + m_font = font; + if ( m_graphicContext ) + { + wxFont f = font; + if ( f.Ok() ) + f.SetPointSize( /*LogicalToDeviceYRel*/(font.GetPointSize())); + m_graphicContext->SetFont( f, m_textForegroundColour ); + } +} + +void wxGCDC::SetPen( const wxPen &pen ) +{ + if ( m_pen == pen ) + return; + + m_pen = pen; + if ( m_graphicContext ) + { + m_graphicContext->SetPen( m_pen ); + } +} + +void wxGCDC::SetBrush( const wxBrush &brush ) +{ + if (m_brush == brush) + return; + + m_brush = brush; + if ( m_graphicContext ) + { + m_graphicContext->SetBrush( m_brush ); + } +} + +void wxGCDC::SetBackground( const wxBrush &brush ) +{ + if (m_backgroundBrush == brush) + return; + + m_backgroundBrush = brush; + if (!m_backgroundBrush.Ok()) + return; +} + +void wxGCDC::SetLogicalFunction( int function ) +{ + if (m_logicalFunction == function) + return; + + m_logicalFunction = function; + if ( m_graphicContext->SetLogicalFunction( function ) ) + m_logicalFunctionSupported=true; + else + m_logicalFunctionSupported=false; +} + +bool wxGCDC::DoFloodFill(wxCoord WXUNUSED(x), wxCoord WXUNUSED(y), + const wxColour& WXUNUSED(col), int WXUNUSED(style)) +{ + return false; +} + +bool wxGCDC::DoGetPixel( wxCoord WXUNUSED(x), wxCoord WXUNUSED(y), wxColour *WXUNUSED(col) ) const +{ + // wxCHECK_MSG( 0 , false, wxT("wxGCDC(cg)::DoGetPixel - not implemented") ); + return false; +} + +void wxGCDC::DoDrawLine( wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2 ) +{ + wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoDrawLine - invalid DC") ); + + if ( !m_logicalFunctionSupported ) + return; + + m_graphicContext->StrokeLine(x1,y1,x2,y2); + + CalcBoundingBox(x1, y1); + CalcBoundingBox(x2, y2); +} + +void wxGCDC::DoCrossHair( wxCoord x, wxCoord y ) +{ + wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoCrossHair - invalid DC") ); + + if ( !m_logicalFunctionSupported ) + return; + + int w = 0, h = 0; + + GetSize( &w, &h ); + + m_graphicContext->StrokeLine(0,y,w,y); + m_graphicContext->StrokeLine(x,0,x,h); + + CalcBoundingBox(0, 0); + CalcBoundingBox(0+w, 0+h); +} + +void wxGCDC::DoDrawArc( wxCoord x1, wxCoord y1, + wxCoord x2, wxCoord y2, + wxCoord xc, wxCoord yc ) +{ + wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoDrawArc - invalid DC") ); + + if ( !m_logicalFunctionSupported ) + return; + + double dx = x1 - xc; + double dy = y1 - yc; + double radius = sqrt((double)(dx * dx + dy * dy)); + wxCoord rad = (wxCoord)radius; + double sa, ea; + if (x1 == x2 && y1 == y2) + { + sa = 0.0; + ea = 360.0; + } + else if (radius == 0.0) + { + sa = ea = 0.0; + } + else + { + sa = (x1 - xc == 0) ? + (y1 - yc < 0) ? 90.0 : -90.0 : + -atan2(double(y1 - yc), double(x1 - xc)) * RAD2DEG; + ea = (x2 - xc == 0) ? + (y2 - yc < 0) ? 90.0 : -90.0 : + -atan2(double(y2 - yc), double(x2 - xc)) * RAD2DEG; + } + + bool fill = m_brush.GetStyle() != wxTRANSPARENT; + + wxGraphicsPath path = m_graphicContext->CreatePath(); + if ( fill && ((x1!=x2)||(y1!=y2)) ) + path.MoveToPoint( xc, yc ); + // since these angles (ea,sa) are measured counter-clockwise, we invert them to + // get clockwise angles + path.AddArc( xc, yc , rad , DegToRad(-sa) , DegToRad(-ea), false ); + if ( fill && ((x1!=x2)||(y1!=y2)) ) + path.AddLineToPoint( xc, yc ); + m_graphicContext->DrawPath(path); +} + +void wxGCDC::DoDrawEllipticArc( wxCoord x, wxCoord y, wxCoord w, wxCoord h, + double sa, double ea ) +{ + wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoDrawEllipticArc - invalid DC") ); + + if ( !m_logicalFunctionSupported ) + return; + + m_graphicContext->PushState(); + m_graphicContext->Translate(x+w/2.0,y+h/2.0); + wxDouble factor = ((wxDouble) w) / h; + m_graphicContext->Scale( factor , 1.0); + + // since these angles (ea,sa) are measured counter-clockwise, we invert them to + // get clockwise angles + if ( m_brush.GetStyle() != wxTRANSPARENT ) + { + wxGraphicsPath path = m_graphicContext->CreatePath(); + path.MoveToPoint( 0, 0 ); + path.AddArc( 0, 0, h/2.0 , DegToRad(-sa) , DegToRad(-ea), sa > ea ); + path.AddLineToPoint( 0, 0 ); + m_graphicContext->FillPath( path ); + + path = m_graphicContext->CreatePath(); + path.AddArc( 0, 0, h/2.0 , DegToRad(-sa) , DegToRad(-ea), sa > ea ); + m_graphicContext->StrokePath( path ); + } + else + { + wxGraphicsPath path = m_graphicContext->CreatePath(); + path.AddArc( 0, 0, h/2.0 , DegToRad(-sa) , DegToRad(-ea), sa > ea ); + m_graphicContext->DrawPath( path ); + } + + m_graphicContext->PopState(); +} + +void wxGCDC::DoDrawPoint( wxCoord x, wxCoord y ) +{ + wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoDrawPoint - invalid DC") ); + + DoDrawLine( x , y , x + 1 , y + 1 ); +} + +void wxGCDC::DoDrawLines(int n, wxPoint points[], + wxCoord xoffset, wxCoord yoffset) +{ + wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoDrawLines - invalid DC") ); + + if ( !m_logicalFunctionSupported ) + return; + + wxPoint2DDouble* pointsD = new wxPoint2DDouble[n]; + for( int i = 0; i < n; ++i) + { + pointsD[i].m_x = points[i].x + xoffset; + pointsD[i].m_y = points[i].y + yoffset; + } + + m_graphicContext->StrokeLines( n , pointsD); + delete[] pointsD; +} + +#if wxUSE_SPLINES +void wxGCDC::DoDrawSpline(wxList *points) +{ + wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoDrawSpline - invalid DC") ); + + if ( !m_logicalFunctionSupported ) + return; + + wxGraphicsPath path = m_graphicContext->CreatePath(); + + wxList::compatibility_iterator node = points->GetFirst(); + if (node == wxList::compatibility_iterator()) + // empty list + return; + + wxPoint *p = (wxPoint *)node->GetData(); + + wxCoord x1 = p->x; + wxCoord y1 = p->y; + + node = node->GetNext(); + p = (wxPoint *)node->GetData(); + + wxCoord x2 = p->x; + wxCoord y2 = p->y; + wxCoord cx1 = ( x1 + x2 ) / 2; + wxCoord cy1 = ( y1 + y2 ) / 2; + + path.MoveToPoint( x1 , y1 ); + path.AddLineToPoint( cx1 , cy1 ); +#if !wxUSE_STL + + while ((node = node->GetNext()) != NULL) +#else + + while ((node = node->GetNext())) +#endif // !wxUSE_STL + + { + p = (wxPoint *)node->GetData(); + x1 = x2; + y1 = y2; + x2 = p->x; + y2 = p->y; + wxCoord cx4 = (x1 + x2) / 2; + wxCoord cy4 = (y1 + y2) / 2; + + path.AddQuadCurveToPoint(x1 , y1 ,cx4 , cy4 ); + + cx1 = cx4; + cy1 = cy4; + } + + path.AddLineToPoint( x2 , y2 ); + + m_graphicContext->StrokePath( path ); +} +#endif // wxUSE_SPLINES + +void wxGCDC::DoDrawPolygon( int n, wxPoint points[], + wxCoord xoffset, wxCoord yoffset, + int fillStyle ) +{ + wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoDrawPolygon - invalid DC") ); + + if ( n <= 0 || (m_brush.GetStyle() == wxTRANSPARENT && m_pen.GetStyle() == wxTRANSPARENT ) ) + return; + if ( !m_logicalFunctionSupported ) + return; + + bool closeIt = false; + if (points[n-1] != points[0]) + closeIt = true; + + wxPoint2DDouble* pointsD = new wxPoint2DDouble[n+(closeIt?1:0)]; + for( int i = 0; i < n; ++i) + { + pointsD[i].m_x = points[i].x + xoffset; + pointsD[i].m_y = points[i].y + yoffset; + } + if ( closeIt ) + pointsD[n] = pointsD[0]; + + m_graphicContext->DrawLines( n+(closeIt?1:0) , pointsD, fillStyle); + delete[] pointsD; +} + +void wxGCDC::DoDrawPolyPolygon(int n, + int count[], + wxPoint points[], + wxCoord xoffset, + wxCoord yoffset, + int fillStyle) +{ + wxASSERT(n > 1); + wxGraphicsPath path = m_graphicContext->CreatePath(); + + int i = 0; + for ( int j = 0; j < n; ++j) + { + wxPoint start = points[i]; + path.MoveToPoint( start.x+ xoffset, start.y+ yoffset); + ++i; + int l = count[j]; + for ( int k = 1; k < l; ++k) + { + path.AddLineToPoint( points[i].x+ xoffset, points[i].y+ yoffset); + ++i; + } + // close the polygon + if ( start != points[i-1]) + path.AddLineToPoint( start.x+ xoffset, start.y+ yoffset); + } + m_graphicContext->DrawPath( path , fillStyle); +} + +void wxGCDC::DoDrawRectangle(wxCoord x, wxCoord y, wxCoord w, wxCoord h) +{ + wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoDrawRectangle - invalid DC") ); + + if ( !m_logicalFunctionSupported ) + return; + + // CMB: draw nothing if transformed w or h is 0 + if (w == 0 || h == 0) + return; + + if ( m_graphicContext->ShouldOffset() ) + { + // if we are offsetting the entire rectangle is moved 0.5, so the + // border line gets off by 1 + w -= 1; + h -= 1; + } + m_graphicContext->DrawRectangle(x,y,w,h); +} + +void wxGCDC::DoDrawRoundedRectangle(wxCoord x, wxCoord y, + wxCoord w, wxCoord h, + double radius) +{ + wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoDrawRoundedRectangle - invalid DC") ); + + if ( !m_logicalFunctionSupported ) + return; + + if (radius < 0.0) + radius = - radius * ((w < h) ? w : h); + + // CMB: draw nothing if transformed w or h is 0 + if (w == 0 || h == 0) + return; + + if ( m_graphicContext->ShouldOffset() ) + { + // if we are offsetting the entire rectangle is moved 0.5, so the + // border line gets off by 1 + w -= 1; + h -= 1; + } + m_graphicContext->DrawRoundedRectangle( x,y,w,h,radius); +} + +void wxGCDC::DoDrawEllipse(wxCoord x, wxCoord y, wxCoord w, wxCoord h) +{ + wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoDrawEllipse - invalid DC") ); + + if ( !m_logicalFunctionSupported ) + return; + + if ( m_graphicContext->ShouldOffset() ) + { + // if we are offsetting the entire rectangle is moved 0.5, so the + // border line gets off by 1 + w -= 1; + h -= 1; + } + m_graphicContext->DrawEllipse(x,y,w,h); +} + +bool wxGCDC::CanDrawBitmap() const +{ + return true; +} + +bool wxGCDC::DoBlit( + wxCoord xdest, wxCoord ydest, wxCoord width, wxCoord height, + wxDC *source, wxCoord xsrc, wxCoord ysrc, int logical_func , bool WXUNUSED(useMask), + wxCoord xsrcMask, wxCoord ysrcMask ) +{ + wxCHECK_MSG( Ok(), false, wxT("wxGCDC(cg)::DoBlit - invalid DC") ); + wxCHECK_MSG( source->Ok(), false, wxT("wxGCDC(cg)::DoBlit - invalid source DC") ); + + if ( logical_func == wxNO_OP ) + return true; + else if ( !m_graphicContext->SetLogicalFunction( logical_func ) ) + + { + wxFAIL_MSG( wxT("Logical function is not supported by the graphics context.") ); + return false; + } + + if (xsrcMask == -1 && ysrcMask == -1) + { + xsrcMask = xsrc; + ysrcMask = ysrc; + } + + wxRect subrect(source->LogicalToDeviceX(xsrc), + source->LogicalToDeviceY(ysrc), + source->LogicalToDeviceXRel(width), + source->LogicalToDeviceYRel(height)); + + // if needed clip the subrect down to the size of the source DC + wxCoord sw, sh; + source->GetSize(&sw, &sh); + sw = source->LogicalToDeviceXRel(sw); + sh = source->LogicalToDeviceYRel(sh); + if (subrect.x + subrect.width > sw) + subrect.width = sw - subrect.x; + if (subrect.y + subrect.height > sh) + subrect.height = sh - subrect.y; + + wxBitmap blit = source->GetAsBitmap( &subrect ); + + if ( blit.Ok() ) + { + m_graphicContext->DrawBitmap( blit, xdest, ydest, + wxMin(width, blit.GetWidth()), + wxMin(height, blit.GetHeight())); + } + else + { + wxFAIL_MSG( wxT("Cannot Blit. Unable to get contents of DC as bitmap.") ); + return false; + } + + // reset logical function + m_graphicContext->SetLogicalFunction( m_logicalFunction ); + + return true; +} + +void wxGCDC::DoDrawRotatedText(const wxString& str, wxCoord x, wxCoord y, + double angle) +{ + wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoDrawRotatedText - invalid DC") ); + + if ( str.length() == 0 ) + return; + if ( !m_logicalFunctionSupported ) + return; + + if ( m_backgroundMode == wxTRANSPARENT ) + m_graphicContext->DrawText( str, x ,y , DegToRad(angle )); + else + m_graphicContext->DrawText( str, x ,y , DegToRad(angle ), m_graphicContext->CreateBrush( wxBrush(m_textBackgroundColour,wxSOLID) ) ); +} + +void wxGCDC::DoDrawText(const wxString& str, wxCoord x, wxCoord y) +{ + wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoDrawRotatedText - invalid DC") ); + + if ( str.length() == 0 ) + return; + + if ( !m_logicalFunctionSupported ) + return; + + if ( m_backgroundMode == wxTRANSPARENT ) + m_graphicContext->DrawText( str, x ,y); + else + m_graphicContext->DrawText( str, x ,y , m_graphicContext->CreateBrush( wxBrush(m_textBackgroundColour,wxSOLID) ) ); +} + +bool wxGCDC::CanGetTextExtent() const +{ + wxCHECK_MSG( Ok(), false, wxT("wxGCDC(cg)::CanGetTextExtent - invalid DC") ); + + return true; +} + +void wxGCDC::DoGetTextExtent( const wxString &str, wxCoord *width, wxCoord *height, + wxCoord *descent, wxCoord *externalLeading , + wxFont *theFont ) const +{ + wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoGetTextExtent - invalid DC") ); + + if ( theFont ) + { + m_graphicContext->SetFont( *theFont, m_textForegroundColour ); + } + + wxDouble h , d , e , w; + + m_graphicContext->GetTextExtent( str, &w, &h, &d, &e ); + + if ( height ) + *height = (wxCoord)(h+0.5); + if ( descent ) + *descent = (wxCoord)(d+0.5); + if ( externalLeading ) + *externalLeading = (wxCoord)(e+0.5); + if ( width ) + *width = (wxCoord)(w+0.5); + + if ( theFont ) + { + m_graphicContext->SetFont( m_font, m_textForegroundColour ); + } +} + +bool wxGCDC::DoGetPartialTextExtents(const wxString& text, wxArrayInt& widths) const +{ + wxCHECK_MSG( Ok(), false, wxT("wxGCDC(cg)::DoGetPartialTextExtents - invalid DC") ); + widths.Clear(); + widths.Add(0,text.Length()); + if ( text.IsEmpty() ) + return true; + + wxArrayDouble widthsD; + + m_graphicContext->GetPartialTextExtents( text, widthsD ); + for ( size_t i = 0; i < widths.GetCount(); ++i ) + widths[i] = (wxCoord)(widthsD[i] + 0.5); + + return true; +} + +wxCoord wxGCDC::GetCharWidth(void) const +{ + wxCoord width; + DoGetTextExtent( wxT("g") , &width , NULL , NULL , NULL , NULL ); + + return width; +} + +wxCoord wxGCDC::GetCharHeight(void) const +{ + wxCoord height; + DoGetTextExtent( wxT("g") , NULL , &height , NULL , NULL , NULL ); + + return height; +} + +void wxGCDC::Clear(void) +{ + wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::Clear - invalid DC") ); + // TODO better implementation / incorporate size info into wxGCDC or context + m_graphicContext->SetBrush( m_backgroundBrush ); + wxPen p = *wxTRANSPARENT_PEN; + m_graphicContext->SetPen( p ); + DoDrawRectangle( 0, 0, 32000 , 32000 ); + m_graphicContext->SetPen( m_pen ); + m_graphicContext->SetBrush( m_brush ); +} + +void wxGCDC::DoGetSize(int *width, int *height) const +{ + *width = 10000; + *height = 10000; +} + +void wxGCDC::DoGradientFillLinear(const wxRect& rect, + const wxColour& initialColour, + const wxColour& destColour, + wxDirection nDirection ) +{ + wxPoint start; + wxPoint end; + switch( nDirection) + { + case wxWEST : + start = rect.GetRightBottom(); + start.x++; + end = rect.GetLeftBottom(); + break; + case wxEAST : + start = rect.GetLeftBottom(); + end = rect.GetRightBottom(); + end.x++; + break; + case wxNORTH : + start = rect.GetLeftBottom(); + start.y++; + end = rect.GetLeftTop(); + break; + case wxSOUTH : + start = rect.GetLeftTop(); + end = rect.GetLeftBottom(); + end.y++; + break; + default : + break; + } + + if (rect.width == 0 || rect.height == 0) + return; + + m_graphicContext->SetBrush( m_graphicContext->CreateLinearGradientBrush( + start.x,start.y,end.x,end.y, initialColour, destColour)); + m_graphicContext->SetPen(*wxTRANSPARENT_PEN); + m_graphicContext->DrawRectangle(rect.x,rect.y,rect.width,rect.height); + m_graphicContext->SetPen(m_pen); +} + +void wxGCDC::DoGradientFillConcentric(const wxRect& rect, + const wxColour& initialColour, + const wxColour& destColour, + const wxPoint& circleCenter) +{ + //Radius + wxInt32 cx = rect.GetWidth() / 2; + wxInt32 cy = rect.GetHeight() / 2; + wxInt32 nRadius; + if (cx < cy) + nRadius = cx; + else + nRadius = cy; + + // make sure the background is filled (todo move into specific platform implementation ?) + m_graphicContext->SetPen(*wxTRANSPARENT_PEN); + m_graphicContext->SetBrush( wxBrush( destColour) ); + m_graphicContext->DrawRectangle(rect.x,rect.y,rect.width,rect.height); + + m_graphicContext->SetBrush( m_graphicContext->CreateRadialGradientBrush( + rect.x+circleCenter.x,rect.y+circleCenter.y, + rect.x+circleCenter.x,rect.y+circleCenter.y, + nRadius,initialColour,destColour)); + + m_graphicContext->DrawRectangle(rect.x,rect.y,rect.width,rect.height); + m_graphicContext->SetPen(m_pen); +} + +void wxGCDC::DoDrawCheckMark(wxCoord x, wxCoord y, + wxCoord width, wxCoord height) +{ + wxDCBase::DoDrawCheckMark(x,y,width,height); +} + +#endif // wxUSE_GRAPHICS_CONTEXT diff --git a/Externals/wxWidgets/src/common/debugrpt.cpp b/Externals/wxWidgets/src/common/debugrpt.cpp index 5c6093c9bc..2520a2d286 100644 --- a/Externals/wxWidgets/src/common/debugrpt.cpp +++ b/Externals/wxWidgets/src/common/debugrpt.cpp @@ -1,698 +1,698 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: src/common/debugrpt.cpp -// Purpose: wxDebugReport and related classes implementation -// Author: Vadim Zeitlin -// Modified by: -// Created: 2005-01-17 -// RCS-ID: $Id: debugrpt.cpp 42650 2006-10-29 19:53:53Z VZ $ -// Copyright: (c) 2005 Vadim Zeitlin -// License: wxWindows licence -/////////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#ifndef WX_PRECOMP - #include "wx/app.h" - #include "wx/log.h" - #include "wx/intl.h" - #include "wx/utils.h" -#endif // WX_PRECOMP - -#if wxUSE_DEBUGREPORT && wxUSE_XML - -#include "wx/debugrpt.h" - -#include "wx/ffile.h" -#include "wx/filename.h" -#include "wx/dir.h" -#include "wx/dynlib.h" - -#include "wx/xml/xml.h" - -#if wxUSE_STACKWALKER - #include "wx/stackwalk.h" -#endif - -#if wxUSE_CRASHREPORT - #include "wx/msw/crashrpt.h" -#endif - -#if wxUSE_ZIPSTREAM - #include "wx/wfstream.h" - #include "wx/zipstrm.h" -#endif // wxUSE_ZIPSTREAM - -WX_CHECK_BUILD_OPTIONS("wxQA") - -// ---------------------------------------------------------------------------- -// XmlStackWalker: stack walker specialization which dumps stack in XML -// ---------------------------------------------------------------------------- - -#if wxUSE_STACKWALKER - -class XmlStackWalker : public wxStackWalker -{ -public: - XmlStackWalker(wxXmlNode *nodeStack) - { - m_isOk = false; - m_nodeStack = nodeStack; - } - - bool IsOk() const { return m_isOk; } - -protected: - virtual void OnStackFrame(const wxStackFrame& frame); - - wxXmlNode *m_nodeStack; - bool m_isOk; -}; - -// ---------------------------------------------------------------------------- -// local functions -// ---------------------------------------------------------------------------- - -static inline void -HexProperty(wxXmlNode *node, const wxChar *name, unsigned long value) -{ - node->AddProperty(name, wxString::Format(_T("%08lx"), value)); -} - -static inline void -NumProperty(wxXmlNode *node, const wxChar *name, unsigned long value) -{ - node->AddProperty(name, wxString::Format(_T("%lu"), value)); -} - -static inline void -TextElement(wxXmlNode *node, const wxChar *name, const wxString& value) -{ - wxXmlNode *nodeChild = new wxXmlNode(wxXML_ELEMENT_NODE, name); - node->AddChild(nodeChild); - nodeChild->AddChild(new wxXmlNode(wxXML_TEXT_NODE, wxEmptyString, value)); -} - -#if wxUSE_CRASHREPORT && defined(__INTEL__) - -static inline void -HexElement(wxXmlNode *node, const wxChar *name, unsigned long value) -{ - TextElement(node, name, wxString::Format(_T("%08lx"), value)); -} - -#endif // wxUSE_CRASHREPORT - -// ============================================================================ -// XmlStackWalker implementation -// ============================================================================ - -void XmlStackWalker::OnStackFrame(const wxStackFrame& frame) -{ - m_isOk = true; - - wxXmlNode *nodeFrame = new wxXmlNode(wxXML_ELEMENT_NODE, _T("frame")); - m_nodeStack->AddChild(nodeFrame); - - NumProperty(nodeFrame, _T("level"), frame.GetLevel()); - wxString func = frame.GetName(); - if ( !func.empty() ) - { - nodeFrame->AddProperty(_T("function"), func); - HexProperty(nodeFrame, _T("offset"), frame.GetOffset()); - } - - if ( frame.HasSourceLocation() ) - { - nodeFrame->AddProperty(_T("file"), frame.GetFileName()); - NumProperty(nodeFrame, _T("line"), frame.GetLine()); - } - - const size_t nParams = frame.GetParamCount(); - if ( nParams ) - { - wxXmlNode *nodeParams = new wxXmlNode(wxXML_ELEMENT_NODE, _T("parameters")); - nodeFrame->AddChild(nodeParams); - - for ( size_t n = 0; n < nParams; n++ ) - { - wxXmlNode * - nodeParam = new wxXmlNode(wxXML_ELEMENT_NODE, _T("parameter")); - nodeParams->AddChild(nodeParam); - - NumProperty(nodeParam, _T("number"), n); - - wxString type, name, value; - if ( !frame.GetParam(n, &type, &name, &value) ) - continue; - - if ( !type.empty() ) - TextElement(nodeParam, _T("type"), type); - - if ( !name.empty() ) - TextElement(nodeParam, _T("name"), name); - - if ( !value.empty() ) - TextElement(nodeParam, _T("value"), value); - } - } -} - -#endif // wxUSE_STACKWALKER - -// ============================================================================ -// wxDebugReport implementation -// ============================================================================ - -// ---------------------------------------------------------------------------- -// initialization and cleanup -// ---------------------------------------------------------------------------- - -wxDebugReport::wxDebugReport() -{ - // get a temporary directory name - wxString appname = GetReportName(); - - // we can't use CreateTempFileName() because it creates a file, not a - // directory, so do our best to create a unique name ourselves - // - // of course, this doesn't protect us against malicious users... - wxFileName fn; - fn.AssignTempFileName(appname); -#if wxUSE_DATETIME - m_dir.Printf(_T("%s%c%s_dbgrpt-%lu-%s"), - fn.GetPath().c_str(), wxFILE_SEP_PATH, appname.c_str(), - wxGetProcessId(), - wxDateTime::Now().Format(_T("%Y%m%dT%H%M%S")).c_str()); -#else - m_dir.Printf(_T("%s%c%s_dbgrpt-%lu"), - fn.GetPath().c_str(), wxFILE_SEP_PATH, appname.c_str(), - wxGetProcessId()); -#endif - - // as we are going to save the process state there use restrictive - // permissions - if ( !wxMkdir(m_dir, 0700) ) - { - wxLogSysError(_("Failed to create directory \"%s\""), m_dir.c_str()); - wxLogError(_("Debug report couldn't be created.")); - - Reset(); - } -} - -wxDebugReport::~wxDebugReport() -{ - if ( !m_dir.empty() ) - { - // remove all files in this directory - wxDir dir(m_dir); - wxString file; - for ( bool cont = dir.GetFirst(&file); cont; cont = dir.GetNext(&file) ) - { - if ( wxRemove(wxFileName(m_dir, file).GetFullPath()) != 0 ) - { - wxLogSysError(_("Failed to remove debug report file \"%s\""), - file.c_str()); - m_dir.clear(); - break; - } - } - } - - if ( !m_dir.empty() ) - { - // Temp fix: what should this be? eVC++ doesn't like wxRmDir -#ifdef __WXWINCE__ - if ( wxRmdir(m_dir.fn_str()) != 0 ) -#else - if ( wxRmDir(m_dir.fn_str()) != 0 ) -#endif - { - wxLogSysError(_("Failed to clean up debug report directory \"%s\""), - m_dir.c_str()); - } - } -} - -// ---------------------------------------------------------------------------- -// various helpers -// ---------------------------------------------------------------------------- - -wxString wxDebugReport::GetReportName() const -{ - if(wxTheApp) - return wxTheApp->GetAppName(); - - return _T("wx"); -} - -void -wxDebugReport::AddFile(const wxString& filename, const wxString& description) -{ - wxString name; - wxFileName fn(filename); - if ( fn.IsAbsolute() ) - { - // we need to copy the file to the debug report directory: give it the - // same name there - name = fn.GetFullName(); - wxCopyFile(fn.GetFullPath(), - wxFileName(GetDirectory(), name).GetFullPath()); - } - else // file relative to the report directory - { - name = filename; - - wxASSERT_MSG( wxFileName(GetDirectory(), name).FileExists(), - _T("file should exist in debug report directory") ); - } - - m_files.Add(name); - m_descriptions.Add(description); -} - -bool -wxDebugReport::AddText(const wxString& filename, - const wxString& text, - const wxString& description) -{ - wxASSERT_MSG( !wxFileName(filename).IsAbsolute(), - _T("filename should be relative to debug report directory") ); - - wxFileName fn(GetDirectory(), filename); - wxFFile file(fn.GetFullPath(), _T("w")); - if ( !file.IsOpened() || !file.Write(text) ) - return false; - - AddFile(filename, description); - - return true; -} - -void wxDebugReport::RemoveFile(const wxString& name) -{ - const int n = m_files.Index(name); - wxCHECK_RET( n != wxNOT_FOUND, _T("No such file in wxDebugReport") ); - - m_files.RemoveAt(n); - m_descriptions.RemoveAt(n); - - wxRemove(wxFileName(GetDirectory(), name).GetFullPath()); -} - -bool wxDebugReport::GetFile(size_t n, wxString *name, wxString *desc) const -{ - if ( n >= m_files.GetCount() ) - return false; - - if ( name ) - *name = m_files[n]; - if ( desc ) - *desc = m_descriptions[n]; - - return true; -} - -void wxDebugReport::AddAll(Context context) -{ -#if wxUSE_STACKWALKER - AddContext(context); -#endif // wxUSE_STACKWALKER - -#if wxUSE_CRASHREPORT - AddDump(context); -#endif // wxUSE_CRASHREPORT - -#if !wxUSE_STACKWALKER && !wxUSE_CRASHREPORT - wxUnusedVar(context); -#endif -} - -// ---------------------------------------------------------------------------- -// adding basic text information about current context -// ---------------------------------------------------------------------------- - -#if wxUSE_STACKWALKER - -bool wxDebugReport::DoAddSystemInfo(wxXmlNode *nodeSystemInfo) -{ - nodeSystemInfo->AddProperty(_T("description"), wxGetOsDescription()); - - return true; -} - -bool wxDebugReport::DoAddLoadedModules(wxXmlNode *nodeModules) -{ - wxDynamicLibraryDetailsArray modules(wxDynamicLibrary::ListLoaded()); - const size_t count = modules.GetCount(); - if ( !count ) - return false; - - for ( size_t n = 0; n < count; n++ ) - { - const wxDynamicLibraryDetails& info = modules[n]; - - wxXmlNode *nodeModule = new wxXmlNode(wxXML_ELEMENT_NODE, _T("module")); - nodeModules->AddChild(nodeModule); - - wxString path = info.GetPath(); - if ( path.empty() ) - path = info.GetName(); - if ( !path.empty() ) - nodeModule->AddProperty(_T("path"), path); - - void *addr = NULL; - size_t len = 0; - if ( info.GetAddress(&addr, &len) ) - { - HexProperty(nodeModule, _T("address"), wxPtrToUInt(addr)); - HexProperty(nodeModule, _T("size"), len); - } - - wxString ver = info.GetVersion(); - if ( !ver.empty() ) - { - nodeModule->AddProperty(_T("version"), ver); - } - } - - return true; -} - -bool wxDebugReport::DoAddExceptionInfo(wxXmlNode *nodeContext) -{ -#if wxUSE_CRASHREPORT - wxCrashContext c; - if ( !c.code ) - return false; - - wxXmlNode *nodeExc = new wxXmlNode(wxXML_ELEMENT_NODE, _T("exception")); - nodeContext->AddChild(nodeExc); - - HexProperty(nodeExc, _T("code"), c.code); - nodeExc->AddProperty(_T("name"), c.GetExceptionString()); - HexProperty(nodeExc, _T("address"), wxPtrToUInt(c.addr)); - -#ifdef __INTEL__ - wxXmlNode *nodeRegs = new wxXmlNode(wxXML_ELEMENT_NODE, _T("registers")); - nodeContext->AddChild(nodeRegs); - HexElement(nodeRegs, _T("eax"), c.regs.eax); - HexElement(nodeRegs, _T("ebx"), c.regs.ebx); - HexElement(nodeRegs, _T("ecx"), c.regs.edx); - HexElement(nodeRegs, _T("edx"), c.regs.edx); - HexElement(nodeRegs, _T("esi"), c.regs.esi); - HexElement(nodeRegs, _T("edi"), c.regs.edi); - - HexElement(nodeRegs, _T("ebp"), c.regs.ebp); - HexElement(nodeRegs, _T("esp"), c.regs.esp); - HexElement(nodeRegs, _T("eip"), c.regs.eip); - - HexElement(nodeRegs, _T("cs"), c.regs.cs); - HexElement(nodeRegs, _T("ds"), c.regs.ds); - HexElement(nodeRegs, _T("es"), c.regs.es); - HexElement(nodeRegs, _T("fs"), c.regs.fs); - HexElement(nodeRegs, _T("gs"), c.regs.gs); - HexElement(nodeRegs, _T("ss"), c.regs.ss); - - HexElement(nodeRegs, _T("flags"), c.regs.flags); -#endif // __INTEL__ - - return true; -#else // !wxUSE_CRASHREPORT - wxUnusedVar(nodeContext); - - return false; -#endif // wxUSE_CRASHREPORT/!wxUSE_CRASHREPORT -} - -bool wxDebugReport::AddContext(wxDebugReport::Context ctx) -{ - wxCHECK_MSG( IsOk(), false, _T("use IsOk() first") ); - - // create XML dump of current context - wxXmlDocument xmldoc; - wxXmlNode *nodeRoot = new wxXmlNode(wxXML_ELEMENT_NODE, _T("report")); - xmldoc.SetRoot(nodeRoot); - nodeRoot->AddProperty(_T("version"), _T("1.0")); - nodeRoot->AddProperty(_T("kind"), ctx == Context_Current ? _T("user") - : _T("exception")); - - // add system information - wxXmlNode *nodeSystemInfo = new wxXmlNode(wxXML_ELEMENT_NODE, _T("system")); - if ( DoAddSystemInfo(nodeSystemInfo) ) - nodeRoot->AddChild(nodeSystemInfo); - else - delete nodeSystemInfo; - - // add information about the loaded modules - wxXmlNode *nodeModules = new wxXmlNode(wxXML_ELEMENT_NODE, _T("modules")); - if ( DoAddLoadedModules(nodeModules) ) - nodeRoot->AddChild(nodeModules); - else - delete nodeModules; - - // add CPU context information: this only makes sense for exceptions as our - // current context is not very interesting otherwise - if ( ctx == Context_Exception ) - { - wxXmlNode *nodeContext = new wxXmlNode(wxXML_ELEMENT_NODE, _T("context")); - if ( DoAddExceptionInfo(nodeContext) ) - nodeRoot->AddChild(nodeContext); - else - delete nodeContext; - } - - // add stack traceback -#if wxUSE_STACKWALKER - wxXmlNode *nodeStack = new wxXmlNode(wxXML_ELEMENT_NODE, _T("stack")); - XmlStackWalker sw(nodeStack); - if ( ctx == Context_Exception ) - { - sw.WalkFromException(); - } - else // Context_Current - { - sw.Walk(); - } - - if ( sw.IsOk() ) - nodeRoot->AddChild(nodeStack); - else - delete nodeStack; -#endif // wxUSE_STACKWALKER - - // finally let the user add any extra information he needs - DoAddCustomContext(nodeRoot); - - - // save the entire context dump in a file - wxFileName fn(m_dir, GetReportName(), _T("xml")); - - if ( !xmldoc.Save(fn.GetFullPath()) ) - return false; - - AddFile(fn.GetFullName(), _("process context description")); - - return true; -} - -#endif // wxUSE_STACKWALKER - -// ---------------------------------------------------------------------------- -// adding core dump -// ---------------------------------------------------------------------------- - -#if wxUSE_CRASHREPORT - -bool wxDebugReport::AddDump(Context ctx) -{ - wxCHECK_MSG( IsOk(), false, _T("use IsOk() first") ); - - wxFileName fn(m_dir, GetReportName(), _T("dmp")); - wxCrashReport::SetFileName(fn.GetFullPath()); - - if ( !(ctx == Context_Exception ? wxCrashReport::Generate() - : wxCrashReport::GenerateNow()) ) - return false; - - AddFile(fn.GetFullName(), _("dump of the process state (binary)")); - - return true; -} - -#endif // wxUSE_CRASHREPORT - -// ---------------------------------------------------------------------------- -// report processing -// ---------------------------------------------------------------------------- - -bool wxDebugReport::Process() -{ - if ( !GetFilesCount() ) - { - wxLogError(_("Debug report generation has failed.")); - - return false; - } - - if ( !DoProcess() ) - { - wxLogError(_("Processing debug report has failed, leaving the files in \"%s\" directory."), - GetDirectory().c_str()); - - Reset(); - - return false; - } - - return true; -} - -bool wxDebugReport::DoProcess() -{ - wxString msg(_("A debug report has been generated. It can be found in")); - msg << _T("\n") - _T("\t") << GetDirectory() << _T("\n\n") - << _("And includes the following files:\n"); - - wxString name, desc; - const size_t count = GetFilesCount(); - for ( size_t n = 0; n < count; n++ ) - { - GetFile(n, &name, &desc); - msg += wxString::Format(_("\t%s: %s\n"), name.c_str(), desc.c_str()); - } - - msg += _("\nPlease send this report to the program maintainer, thank you!\n"); - - wxLogMessage(_T("%s"), msg.c_str()); - - // we have to do this or the report would be deleted, and we don't even - // have any way to ask the user if he wants to keep it from here - Reset(); - - return true; -} - -// ============================================================================ -// wxDebugReport-derived classes -// ============================================================================ - -#if wxUSE_ZIPSTREAM - -// ---------------------------------------------------------------------------- -// wxDebugReportCompress -// ---------------------------------------------------------------------------- - -bool wxDebugReportCompress::DoProcess() -{ - const size_t count = GetFilesCount(); - if ( !count ) - return false; - - // create the streams - wxFileName fn(GetDirectory(), GetReportName(), _T("zip")); - wxFFileOutputStream os(fn.GetFullPath(), _T("wb")); - wxZipOutputStream zos(os, 9); - - // add all files to the ZIP one - wxString name, desc; - for ( size_t n = 0; n < count; n++ ) - { - GetFile(n, &name, &desc); - - wxZipEntry *ze = new wxZipEntry(name); - ze->SetComment(desc); - - if ( !zos.PutNextEntry(ze) ) - return false; - - wxFileName filename(fn.GetPath(), name); - wxFFileInputStream is(filename.GetFullPath()); - if ( !is.IsOk() || !zos.Write(is).IsOk() ) - return false; - } - - if ( !zos.Close() ) - return false; - - m_zipfile = fn.GetFullPath(); - - return true; -} - -// ---------------------------------------------------------------------------- -// wxDebugReportUpload -// ---------------------------------------------------------------------------- - -wxDebugReportUpload::wxDebugReportUpload(const wxString& url, - const wxString& input, - const wxString& action, - const wxString& curl) - : m_uploadURL(url), - m_inputField(input), - m_curlCmd(curl) -{ - if ( m_uploadURL.Last() != _T('/') ) - m_uploadURL += _T('/'); - m_uploadURL += action; -} - -bool wxDebugReportUpload::DoProcess() -{ - if ( !wxDebugReportCompress::DoProcess() ) - return false; - - - wxArrayString output, errors; - int rc = wxExecute(wxString::Format - ( - _T("%s -F %s=@\"%s\" %s"), - m_curlCmd.c_str(), - m_inputField.c_str(), - GetCompressedFileName().c_str(), - m_uploadURL.c_str() - ), - output, - errors); - if ( rc == -1 ) - { - wxLogError(_("Failed to execute curl, please install it in PATH.")); - } - else if ( rc != 0 ) - { - const size_t count = errors.GetCount(); - if ( count ) - { - for ( size_t n = 0; n < count; n++ ) - { - wxLogWarning(_T("%s"), errors[n].c_str()); - } - } - - wxLogError(_("Failed to upload the debug report (error code %d)."), rc); - } - else // rc == 0 - { - if ( OnServerReply(output) ) - return true; - } - - return false; -} - -#endif // wxUSE_ZIPSTREAM - -#endif // wxUSE_DEBUGREPORT +/////////////////////////////////////////////////////////////////////////////// +// Name: src/common/debugrpt.cpp +// Purpose: wxDebugReport and related classes implementation +// Author: Vadim Zeitlin +// Modified by: +// Created: 2005-01-17 +// RCS-ID: $Id: debugrpt.cpp 42650 2006-10-29 19:53:53Z VZ $ +// Copyright: (c) 2005 Vadim Zeitlin +// License: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#ifndef WX_PRECOMP + #include "wx/app.h" + #include "wx/log.h" + #include "wx/intl.h" + #include "wx/utils.h" +#endif // WX_PRECOMP + +#if wxUSE_DEBUGREPORT && wxUSE_XML + +#include "wx/debugrpt.h" + +#include "wx/ffile.h" +#include "wx/filename.h" +#include "wx/dir.h" +#include "wx/dynlib.h" + +#include "wx/xml/xml.h" + +#if wxUSE_STACKWALKER + #include "wx/stackwalk.h" +#endif + +#if wxUSE_CRASHREPORT + #include "wx/msw/crashrpt.h" +#endif + +#if wxUSE_ZIPSTREAM + #include "wx/wfstream.h" + #include "wx/zipstrm.h" +#endif // wxUSE_ZIPSTREAM + +WX_CHECK_BUILD_OPTIONS("wxQA") + +// ---------------------------------------------------------------------------- +// XmlStackWalker: stack walker specialization which dumps stack in XML +// ---------------------------------------------------------------------------- + +#if wxUSE_STACKWALKER + +class XmlStackWalker : public wxStackWalker +{ +public: + XmlStackWalker(wxXmlNode *nodeStack) + { + m_isOk = false; + m_nodeStack = nodeStack; + } + + bool IsOk() const { return m_isOk; } + +protected: + virtual void OnStackFrame(const wxStackFrame& frame); + + wxXmlNode *m_nodeStack; + bool m_isOk; +}; + +// ---------------------------------------------------------------------------- +// local functions +// ---------------------------------------------------------------------------- + +static inline void +HexProperty(wxXmlNode *node, const wxChar *name, unsigned long value) +{ + node->AddProperty(name, wxString::Format(_T("%08lx"), value)); +} + +static inline void +NumProperty(wxXmlNode *node, const wxChar *name, unsigned long value) +{ + node->AddProperty(name, wxString::Format(_T("%lu"), value)); +} + +static inline void +TextElement(wxXmlNode *node, const wxChar *name, const wxString& value) +{ + wxXmlNode *nodeChild = new wxXmlNode(wxXML_ELEMENT_NODE, name); + node->AddChild(nodeChild); + nodeChild->AddChild(new wxXmlNode(wxXML_TEXT_NODE, wxEmptyString, value)); +} + +#if wxUSE_CRASHREPORT && defined(__INTEL__) + +static inline void +HexElement(wxXmlNode *node, const wxChar *name, unsigned long value) +{ + TextElement(node, name, wxString::Format(_T("%08lx"), value)); +} + +#endif // wxUSE_CRASHREPORT + +// ============================================================================ +// XmlStackWalker implementation +// ============================================================================ + +void XmlStackWalker::OnStackFrame(const wxStackFrame& frame) +{ + m_isOk = true; + + wxXmlNode *nodeFrame = new wxXmlNode(wxXML_ELEMENT_NODE, _T("frame")); + m_nodeStack->AddChild(nodeFrame); + + NumProperty(nodeFrame, _T("level"), frame.GetLevel()); + wxString func = frame.GetName(); + if ( !func.empty() ) + { + nodeFrame->AddProperty(_T("function"), func); + HexProperty(nodeFrame, _T("offset"), frame.GetOffset()); + } + + if ( frame.HasSourceLocation() ) + { + nodeFrame->AddProperty(_T("file"), frame.GetFileName()); + NumProperty(nodeFrame, _T("line"), frame.GetLine()); + } + + const size_t nParams = frame.GetParamCount(); + if ( nParams ) + { + wxXmlNode *nodeParams = new wxXmlNode(wxXML_ELEMENT_NODE, _T("parameters")); + nodeFrame->AddChild(nodeParams); + + for ( size_t n = 0; n < nParams; n++ ) + { + wxXmlNode * + nodeParam = new wxXmlNode(wxXML_ELEMENT_NODE, _T("parameter")); + nodeParams->AddChild(nodeParam); + + NumProperty(nodeParam, _T("number"), n); + + wxString type, name, value; + if ( !frame.GetParam(n, &type, &name, &value) ) + continue; + + if ( !type.empty() ) + TextElement(nodeParam, _T("type"), type); + + if ( !name.empty() ) + TextElement(nodeParam, _T("name"), name); + + if ( !value.empty() ) + TextElement(nodeParam, _T("value"), value); + } + } +} + +#endif // wxUSE_STACKWALKER + +// ============================================================================ +// wxDebugReport implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// initialization and cleanup +// ---------------------------------------------------------------------------- + +wxDebugReport::wxDebugReport() +{ + // get a temporary directory name + wxString appname = GetReportName(); + + // we can't use CreateTempFileName() because it creates a file, not a + // directory, so do our best to create a unique name ourselves + // + // of course, this doesn't protect us against malicious users... + wxFileName fn; + fn.AssignTempFileName(appname); +#if wxUSE_DATETIME + m_dir.Printf(_T("%s%c%s_dbgrpt-%lu-%s"), + fn.GetPath().c_str(), wxFILE_SEP_PATH, appname.c_str(), + wxGetProcessId(), + wxDateTime::Now().Format(_T("%Y%m%dT%H%M%S")).c_str()); +#else + m_dir.Printf(_T("%s%c%s_dbgrpt-%lu"), + fn.GetPath().c_str(), wxFILE_SEP_PATH, appname.c_str(), + wxGetProcessId()); +#endif + + // as we are going to save the process state there use restrictive + // permissions + if ( !wxMkdir(m_dir, 0700) ) + { + wxLogSysError(_("Failed to create directory \"%s\""), m_dir.c_str()); + wxLogError(_("Debug report couldn't be created.")); + + Reset(); + } +} + +wxDebugReport::~wxDebugReport() +{ + if ( !m_dir.empty() ) + { + // remove all files in this directory + wxDir dir(m_dir); + wxString file; + for ( bool cont = dir.GetFirst(&file); cont; cont = dir.GetNext(&file) ) + { + if ( wxRemove(wxFileName(m_dir, file).GetFullPath()) != 0 ) + { + wxLogSysError(_("Failed to remove debug report file \"%s\""), + file.c_str()); + m_dir.clear(); + break; + } + } + } + + if ( !m_dir.empty() ) + { + // Temp fix: what should this be? eVC++ doesn't like wxRmDir +#ifdef __WXWINCE__ + if ( wxRmdir(m_dir.fn_str()) != 0 ) +#else + if ( wxRmDir(m_dir.fn_str()) != 0 ) +#endif + { + wxLogSysError(_("Failed to clean up debug report directory \"%s\""), + m_dir.c_str()); + } + } +} + +// ---------------------------------------------------------------------------- +// various helpers +// ---------------------------------------------------------------------------- + +wxString wxDebugReport::GetReportName() const +{ + if(wxTheApp) + return wxTheApp->GetAppName(); + + return _T("wx"); +} + +void +wxDebugReport::AddFile(const wxString& filename, const wxString& description) +{ + wxString name; + wxFileName fn(filename); + if ( fn.IsAbsolute() ) + { + // we need to copy the file to the debug report directory: give it the + // same name there + name = fn.GetFullName(); + wxCopyFile(fn.GetFullPath(), + wxFileName(GetDirectory(), name).GetFullPath()); + } + else // file relative to the report directory + { + name = filename; + + wxASSERT_MSG( wxFileName(GetDirectory(), name).FileExists(), + _T("file should exist in debug report directory") ); + } + + m_files.Add(name); + m_descriptions.Add(description); +} + +bool +wxDebugReport::AddText(const wxString& filename, + const wxString& text, + const wxString& description) +{ + wxASSERT_MSG( !wxFileName(filename).IsAbsolute(), + _T("filename should be relative to debug report directory") ); + + wxFileName fn(GetDirectory(), filename); + wxFFile file(fn.GetFullPath(), _T("w")); + if ( !file.IsOpened() || !file.Write(text) ) + return false; + + AddFile(filename, description); + + return true; +} + +void wxDebugReport::RemoveFile(const wxString& name) +{ + const int n = m_files.Index(name); + wxCHECK_RET( n != wxNOT_FOUND, _T("No such file in wxDebugReport") ); + + m_files.RemoveAt(n); + m_descriptions.RemoveAt(n); + + wxRemove(wxFileName(GetDirectory(), name).GetFullPath()); +} + +bool wxDebugReport::GetFile(size_t n, wxString *name, wxString *desc) const +{ + if ( n >= m_files.GetCount() ) + return false; + + if ( name ) + *name = m_files[n]; + if ( desc ) + *desc = m_descriptions[n]; + + return true; +} + +void wxDebugReport::AddAll(Context context) +{ +#if wxUSE_STACKWALKER + AddContext(context); +#endif // wxUSE_STACKWALKER + +#if wxUSE_CRASHREPORT + AddDump(context); +#endif // wxUSE_CRASHREPORT + +#if !wxUSE_STACKWALKER && !wxUSE_CRASHREPORT + wxUnusedVar(context); +#endif +} + +// ---------------------------------------------------------------------------- +// adding basic text information about current context +// ---------------------------------------------------------------------------- + +#if wxUSE_STACKWALKER + +bool wxDebugReport::DoAddSystemInfo(wxXmlNode *nodeSystemInfo) +{ + nodeSystemInfo->AddProperty(_T("description"), wxGetOsDescription()); + + return true; +} + +bool wxDebugReport::DoAddLoadedModules(wxXmlNode *nodeModules) +{ + wxDynamicLibraryDetailsArray modules(wxDynamicLibrary::ListLoaded()); + const size_t count = modules.GetCount(); + if ( !count ) + return false; + + for ( size_t n = 0; n < count; n++ ) + { + const wxDynamicLibraryDetails& info = modules[n]; + + wxXmlNode *nodeModule = new wxXmlNode(wxXML_ELEMENT_NODE, _T("module")); + nodeModules->AddChild(nodeModule); + + wxString path = info.GetPath(); + if ( path.empty() ) + path = info.GetName(); + if ( !path.empty() ) + nodeModule->AddProperty(_T("path"), path); + + void *addr = NULL; + size_t len = 0; + if ( info.GetAddress(&addr, &len) ) + { + HexProperty(nodeModule, _T("address"), wxPtrToUInt(addr)); + HexProperty(nodeModule, _T("size"), len); + } + + wxString ver = info.GetVersion(); + if ( !ver.empty() ) + { + nodeModule->AddProperty(_T("version"), ver); + } + } + + return true; +} + +bool wxDebugReport::DoAddExceptionInfo(wxXmlNode *nodeContext) +{ +#if wxUSE_CRASHREPORT + wxCrashContext c; + if ( !c.code ) + return false; + + wxXmlNode *nodeExc = new wxXmlNode(wxXML_ELEMENT_NODE, _T("exception")); + nodeContext->AddChild(nodeExc); + + HexProperty(nodeExc, _T("code"), c.code); + nodeExc->AddProperty(_T("name"), c.GetExceptionString()); + HexProperty(nodeExc, _T("address"), wxPtrToUInt(c.addr)); + +#ifdef __INTEL__ + wxXmlNode *nodeRegs = new wxXmlNode(wxXML_ELEMENT_NODE, _T("registers")); + nodeContext->AddChild(nodeRegs); + HexElement(nodeRegs, _T("eax"), c.regs.eax); + HexElement(nodeRegs, _T("ebx"), c.regs.ebx); + HexElement(nodeRegs, _T("ecx"), c.regs.edx); + HexElement(nodeRegs, _T("edx"), c.regs.edx); + HexElement(nodeRegs, _T("esi"), c.regs.esi); + HexElement(nodeRegs, _T("edi"), c.regs.edi); + + HexElement(nodeRegs, _T("ebp"), c.regs.ebp); + HexElement(nodeRegs, _T("esp"), c.regs.esp); + HexElement(nodeRegs, _T("eip"), c.regs.eip); + + HexElement(nodeRegs, _T("cs"), c.regs.cs); + HexElement(nodeRegs, _T("ds"), c.regs.ds); + HexElement(nodeRegs, _T("es"), c.regs.es); + HexElement(nodeRegs, _T("fs"), c.regs.fs); + HexElement(nodeRegs, _T("gs"), c.regs.gs); + HexElement(nodeRegs, _T("ss"), c.regs.ss); + + HexElement(nodeRegs, _T("flags"), c.regs.flags); +#endif // __INTEL__ + + return true; +#else // !wxUSE_CRASHREPORT + wxUnusedVar(nodeContext); + + return false; +#endif // wxUSE_CRASHREPORT/!wxUSE_CRASHREPORT +} + +bool wxDebugReport::AddContext(wxDebugReport::Context ctx) +{ + wxCHECK_MSG( IsOk(), false, _T("use IsOk() first") ); + + // create XML dump of current context + wxXmlDocument xmldoc; + wxXmlNode *nodeRoot = new wxXmlNode(wxXML_ELEMENT_NODE, _T("report")); + xmldoc.SetRoot(nodeRoot); + nodeRoot->AddProperty(_T("version"), _T("1.0")); + nodeRoot->AddProperty(_T("kind"), ctx == Context_Current ? _T("user") + : _T("exception")); + + // add system information + wxXmlNode *nodeSystemInfo = new wxXmlNode(wxXML_ELEMENT_NODE, _T("system")); + if ( DoAddSystemInfo(nodeSystemInfo) ) + nodeRoot->AddChild(nodeSystemInfo); + else + delete nodeSystemInfo; + + // add information about the loaded modules + wxXmlNode *nodeModules = new wxXmlNode(wxXML_ELEMENT_NODE, _T("modules")); + if ( DoAddLoadedModules(nodeModules) ) + nodeRoot->AddChild(nodeModules); + else + delete nodeModules; + + // add CPU context information: this only makes sense for exceptions as our + // current context is not very interesting otherwise + if ( ctx == Context_Exception ) + { + wxXmlNode *nodeContext = new wxXmlNode(wxXML_ELEMENT_NODE, _T("context")); + if ( DoAddExceptionInfo(nodeContext) ) + nodeRoot->AddChild(nodeContext); + else + delete nodeContext; + } + + // add stack traceback +#if wxUSE_STACKWALKER + wxXmlNode *nodeStack = new wxXmlNode(wxXML_ELEMENT_NODE, _T("stack")); + XmlStackWalker sw(nodeStack); + if ( ctx == Context_Exception ) + { + sw.WalkFromException(); + } + else // Context_Current + { + sw.Walk(); + } + + if ( sw.IsOk() ) + nodeRoot->AddChild(nodeStack); + else + delete nodeStack; +#endif // wxUSE_STACKWALKER + + // finally let the user add any extra information he needs + DoAddCustomContext(nodeRoot); + + + // save the entire context dump in a file + wxFileName fn(m_dir, GetReportName(), _T("xml")); + + if ( !xmldoc.Save(fn.GetFullPath()) ) + return false; + + AddFile(fn.GetFullName(), _("process context description")); + + return true; +} + +#endif // wxUSE_STACKWALKER + +// ---------------------------------------------------------------------------- +// adding core dump +// ---------------------------------------------------------------------------- + +#if wxUSE_CRASHREPORT + +bool wxDebugReport::AddDump(Context ctx) +{ + wxCHECK_MSG( IsOk(), false, _T("use IsOk() first") ); + + wxFileName fn(m_dir, GetReportName(), _T("dmp")); + wxCrashReport::SetFileName(fn.GetFullPath()); + + if ( !(ctx == Context_Exception ? wxCrashReport::Generate() + : wxCrashReport::GenerateNow()) ) + return false; + + AddFile(fn.GetFullName(), _("dump of the process state (binary)")); + + return true; +} + +#endif // wxUSE_CRASHREPORT + +// ---------------------------------------------------------------------------- +// report processing +// ---------------------------------------------------------------------------- + +bool wxDebugReport::Process() +{ + if ( !GetFilesCount() ) + { + wxLogError(_("Debug report generation has failed.")); + + return false; + } + + if ( !DoProcess() ) + { + wxLogError(_("Processing debug report has failed, leaving the files in \"%s\" directory."), + GetDirectory().c_str()); + + Reset(); + + return false; + } + + return true; +} + +bool wxDebugReport::DoProcess() +{ + wxString msg(_("A debug report has been generated. It can be found in")); + msg << _T("\n") + _T("\t") << GetDirectory() << _T("\n\n") + << _("And includes the following files:\n"); + + wxString name, desc; + const size_t count = GetFilesCount(); + for ( size_t n = 0; n < count; n++ ) + { + GetFile(n, &name, &desc); + msg += wxString::Format(_("\t%s: %s\n"), name.c_str(), desc.c_str()); + } + + msg += _("\nPlease send this report to the program maintainer, thank you!\n"); + + wxLogMessage(_T("%s"), msg.c_str()); + + // we have to do this or the report would be deleted, and we don't even + // have any way to ask the user if he wants to keep it from here + Reset(); + + return true; +} + +// ============================================================================ +// wxDebugReport-derived classes +// ============================================================================ + +#if wxUSE_ZIPSTREAM + +// ---------------------------------------------------------------------------- +// wxDebugReportCompress +// ---------------------------------------------------------------------------- + +bool wxDebugReportCompress::DoProcess() +{ + const size_t count = GetFilesCount(); + if ( !count ) + return false; + + // create the streams + wxFileName fn(GetDirectory(), GetReportName(), _T("zip")); + wxFFileOutputStream os(fn.GetFullPath(), _T("wb")); + wxZipOutputStream zos(os, 9); + + // add all files to the ZIP one + wxString name, desc; + for ( size_t n = 0; n < count; n++ ) + { + GetFile(n, &name, &desc); + + wxZipEntry *ze = new wxZipEntry(name); + ze->SetComment(desc); + + if ( !zos.PutNextEntry(ze) ) + return false; + + wxFileName filename(fn.GetPath(), name); + wxFFileInputStream is(filename.GetFullPath()); + if ( !is.IsOk() || !zos.Write(is).IsOk() ) + return false; + } + + if ( !zos.Close() ) + return false; + + m_zipfile = fn.GetFullPath(); + + return true; +} + +// ---------------------------------------------------------------------------- +// wxDebugReportUpload +// ---------------------------------------------------------------------------- + +wxDebugReportUpload::wxDebugReportUpload(const wxString& url, + const wxString& input, + const wxString& action, + const wxString& curl) + : m_uploadURL(url), + m_inputField(input), + m_curlCmd(curl) +{ + if ( m_uploadURL.Last() != _T('/') ) + m_uploadURL += _T('/'); + m_uploadURL += action; +} + +bool wxDebugReportUpload::DoProcess() +{ + if ( !wxDebugReportCompress::DoProcess() ) + return false; + + + wxArrayString output, errors; + int rc = wxExecute(wxString::Format + ( + _T("%s -F %s=@\"%s\" %s"), + m_curlCmd.c_str(), + m_inputField.c_str(), + GetCompressedFileName().c_str(), + m_uploadURL.c_str() + ), + output, + errors); + if ( rc == -1 ) + { + wxLogError(_("Failed to execute curl, please install it in PATH.")); + } + else if ( rc != 0 ) + { + const size_t count = errors.GetCount(); + if ( count ) + { + for ( size_t n = 0; n < count; n++ ) + { + wxLogWarning(_T("%s"), errors[n].c_str()); + } + } + + wxLogError(_("Failed to upload the debug report (error code %d)."), rc); + } + else // rc == 0 + { + if ( OnServerReply(output) ) + return true; + } + + return false; +} + +#endif // wxUSE_ZIPSTREAM + +#endif // wxUSE_DEBUGREPORT diff --git a/Externals/wxWidgets/src/common/dircmn.cpp b/Externals/wxWidgets/src/common/dircmn.cpp index 2e2b24a34d..3e79a7a4e9 100644 --- a/Externals/wxWidgets/src/common/dircmn.cpp +++ b/Externals/wxWidgets/src/common/dircmn.cpp @@ -1,357 +1,357 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: src/common/dircmn.cpp -// Purpose: wxDir methods common to all implementations -// Author: Vadim Zeitlin -// Modified by: -// Created: 19.05.01 -// RCS-ID: $Id: dircmn.cpp 40665 2006-08-19 08:45:31Z JS $ -// Copyright: (c) 2001 Vadim Zeitlin -// License: wxWindows licence -/////////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#ifndef WX_PRECOMP - #include "wx/string.h" - #include "wx/log.h" - #include "wx/intl.h" - #include "wx/filefn.h" - #include "wx/arrstr.h" -#endif //WX_PRECOMP - -#include "wx/dir.h" -#include "wx/filename.h" - -// ============================================================================ -// implementation -// ============================================================================ - -// ---------------------------------------------------------------------------- -// wxDirTraverser -// ---------------------------------------------------------------------------- - -wxDirTraverseResult -wxDirTraverser::OnOpenError(const wxString& WXUNUSED(dirname)) -{ - return wxDIR_IGNORE; -} - -// ---------------------------------------------------------------------------- -// wxDir::HasFiles() and HasSubDirs() -// ---------------------------------------------------------------------------- - -// dumb generic implementation - -bool wxDir::HasFiles(const wxString& spec) -{ - wxString s; - return GetFirst(&s, spec, wxDIR_FILES | wxDIR_HIDDEN); -} - -// we have a (much) faster version for Unix -#if (defined(__CYGWIN__) && defined(__WINDOWS__)) || !defined(__UNIX_LIKE__) || defined(__WXMAC__) || defined(__EMX__) || defined(__WINE__) - -bool wxDir::HasSubDirs(const wxString& spec) -{ - wxString s; - return GetFirst(&s, spec, wxDIR_DIRS | wxDIR_HIDDEN); -} - -#endif // !Unix - -// ---------------------------------------------------------------------------- -// wxDir::Traverse() -// ---------------------------------------------------------------------------- - -size_t wxDir::Traverse(wxDirTraverser& sink, - const wxString& filespec, - int flags) const -{ - wxCHECK_MSG( IsOpened(), (size_t)-1, - _T("dir must be opened before traversing it") ); - - // the total number of files found - size_t nFiles = 0; - - // the name of this dir with path delimiter at the end - wxString prefix = GetName(); - prefix += wxFILE_SEP_PATH; - - // first, recurse into subdirs - if ( flags & wxDIR_DIRS ) - { - wxString dirname; - for ( bool cont = GetFirst(&dirname, wxEmptyString, wxDIR_DIRS | (flags & wxDIR_HIDDEN) ); - cont; - cont = cont && GetNext(&dirname) ) - { - const wxString fulldirname = prefix + dirname; - - switch ( sink.OnDir(fulldirname) ) - { - default: - wxFAIL_MSG(_T("unexpected OnDir() return value") ); - // fall through - - case wxDIR_STOP: - cont = false; - break; - - case wxDIR_CONTINUE: - { - wxDir subdir; - - // don't give the error messages for the directories - // which we can't open: there can be all sorts of good - // reason for this (e.g. insufficient privileges) and - // this shouldn't be treated as an error -- instead - // let the user code decide what to do - bool ok; - do - { - wxLogNull noLog; - ok = subdir.Open(fulldirname); - if ( !ok ) - { - // ask the user code what to do - bool tryagain; - switch ( sink.OnOpenError(fulldirname) ) - { - default: - wxFAIL_MSG(_T("unexpected OnOpenError() return value") ); - // fall through - - case wxDIR_STOP: - cont = false; - // fall through - - case wxDIR_IGNORE: - tryagain = false; - break; - - case wxDIR_CONTINUE: - tryagain = true; - } - - if ( !tryagain ) - break; - } - } - while ( !ok ); - - if ( ok ) - { - nFiles += subdir.Traverse(sink, filespec, flags); - } - } - break; - - case wxDIR_IGNORE: - // nothing to do - ; - } - } - } - - // now enum our own files - if ( flags & wxDIR_FILES ) - { - flags &= ~wxDIR_DIRS; - - wxString filename; - bool cont = GetFirst(&filename, filespec, flags); - while ( cont ) - { - wxDirTraverseResult res = sink.OnFile(prefix + filename); - if ( res == wxDIR_STOP ) - break; - - wxASSERT_MSG( res == wxDIR_CONTINUE, - _T("unexpected OnFile() return value") ); - - nFiles++; - - cont = GetNext(&filename); - } - } - - return nFiles; -} - -// ---------------------------------------------------------------------------- -// wxDir::GetAllFiles() -// ---------------------------------------------------------------------------- - -class wxDirTraverserSimple : public wxDirTraverser -{ -public: - wxDirTraverserSimple(wxArrayString& files) : m_files(files) { } - - virtual wxDirTraverseResult OnFile(const wxString& filename) - { - m_files.push_back(filename); - return wxDIR_CONTINUE; - } - - virtual wxDirTraverseResult OnDir(const wxString& WXUNUSED(dirname)) - { - return wxDIR_CONTINUE; - } - -private: - wxArrayString& m_files; - - DECLARE_NO_COPY_CLASS(wxDirTraverserSimple) -}; - -/* static */ -size_t wxDir::GetAllFiles(const wxString& dirname, - wxArrayString *files, - const wxString& filespec, - int flags) -{ - wxCHECK_MSG( files, (size_t)-1, _T("NULL pointer in wxDir::GetAllFiles") ); - - size_t nFiles = 0; - - wxDir dir(dirname); - if ( dir.IsOpened() ) - { - wxDirTraverserSimple traverser(*files); - - nFiles += dir.Traverse(traverser, filespec, flags); - } - - return nFiles; -} - -// ---------------------------------------------------------------------------- -// wxDir::FindFirst() -// ---------------------------------------------------------------------------- - -class wxDirTraverserFindFirst : public wxDirTraverser -{ -public: - wxDirTraverserFindFirst() { } - - virtual wxDirTraverseResult OnFile(const wxString& filename) - { - m_file = filename; - return wxDIR_STOP; - } - - virtual wxDirTraverseResult OnDir(const wxString& WXUNUSED(dirname)) - { - return wxDIR_CONTINUE; - } - - const wxString& GetFile() const - { - return m_file; - } - -private: - wxString m_file; - - DECLARE_NO_COPY_CLASS(wxDirTraverserFindFirst) -}; - -/* static */ -wxString wxDir::FindFirst(const wxString& dirname, - const wxString& filespec, - int flags) -{ - wxDir dir(dirname); - if ( dir.IsOpened() ) - { - wxDirTraverserFindFirst traverser; - - dir.Traverse(traverser, filespec, flags | wxDIR_FILES); - return traverser.GetFile(); - } - - return wxEmptyString; -} - - -// ---------------------------------------------------------------------------- -// wxDir::GetTotalSize() -// ---------------------------------------------------------------------------- - -class wxDirTraverserSumSize : public wxDirTraverser -{ -public: - wxDirTraverserSumSize() { } - - virtual wxDirTraverseResult OnFile(const wxString& filename) - { - wxULongLong sz = wxFileName::GetSize(filename); - - // wxFileName::GetSize won't use this class again as - // we're passing it a file and not a directory; - // thus we are sure to avoid an endless loop - if (sz == wxInvalidSize) - { - // if the GetSize() failed (this can happen because e.g. a - // file is locked by another process), we can proceed but - // we need to at least warn the user that the resulting - // final size could be not reliable (if e.g. the locked - // file is very big). - m_skippedFiles.Add(filename); - return wxDIR_CONTINUE; - } - - m_sz += sz; - return wxDIR_CONTINUE; - } - - virtual wxDirTraverseResult OnDir(const wxString& WXUNUSED(dirname)) - { - return wxDIR_CONTINUE; - } - - wxULongLong GetTotalSize() const - { return m_sz; } - wxArrayString &FilesSkipped() - { return m_skippedFiles; } - -protected: - wxULongLong m_sz; - wxArrayString m_skippedFiles; -}; - -wxULongLong wxDir::GetTotalSize(const wxString &dirname, wxArrayString *filesSkipped) -{ - if (!wxDirExists(dirname)) - return wxInvalidSize; - - // to get the size of this directory and its contents we need - // to recursively walk it... - wxDir dir(dirname); - if ( !dir.IsOpened() ) - return wxInvalidSize; - - wxDirTraverserSumSize traverser; - if (dir.Traverse(traverser) == (size_t)-1 || - traverser.GetTotalSize() == 0) - return wxInvalidSize; - - if (filesSkipped) - *filesSkipped = traverser.FilesSkipped(); - - return traverser.GetTotalSize(); -} - +/////////////////////////////////////////////////////////////////////////////// +// Name: src/common/dircmn.cpp +// Purpose: wxDir methods common to all implementations +// Author: Vadim Zeitlin +// Modified by: +// Created: 19.05.01 +// RCS-ID: $Id: dircmn.cpp 40665 2006-08-19 08:45:31Z JS $ +// Copyright: (c) 2001 Vadim Zeitlin +// License: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#ifndef WX_PRECOMP + #include "wx/string.h" + #include "wx/log.h" + #include "wx/intl.h" + #include "wx/filefn.h" + #include "wx/arrstr.h" +#endif //WX_PRECOMP + +#include "wx/dir.h" +#include "wx/filename.h" + +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// wxDirTraverser +// ---------------------------------------------------------------------------- + +wxDirTraverseResult +wxDirTraverser::OnOpenError(const wxString& WXUNUSED(dirname)) +{ + return wxDIR_IGNORE; +} + +// ---------------------------------------------------------------------------- +// wxDir::HasFiles() and HasSubDirs() +// ---------------------------------------------------------------------------- + +// dumb generic implementation + +bool wxDir::HasFiles(const wxString& spec) +{ + wxString s; + return GetFirst(&s, spec, wxDIR_FILES | wxDIR_HIDDEN); +} + +// we have a (much) faster version for Unix +#if (defined(__CYGWIN__) && defined(__WINDOWS__)) || !defined(__UNIX_LIKE__) || defined(__WXMAC__) || defined(__EMX__) || defined(__WINE__) + +bool wxDir::HasSubDirs(const wxString& spec) +{ + wxString s; + return GetFirst(&s, spec, wxDIR_DIRS | wxDIR_HIDDEN); +} + +#endif // !Unix + +// ---------------------------------------------------------------------------- +// wxDir::Traverse() +// ---------------------------------------------------------------------------- + +size_t wxDir::Traverse(wxDirTraverser& sink, + const wxString& filespec, + int flags) const +{ + wxCHECK_MSG( IsOpened(), (size_t)-1, + _T("dir must be opened before traversing it") ); + + // the total number of files found + size_t nFiles = 0; + + // the name of this dir with path delimiter at the end + wxString prefix = GetName(); + prefix += wxFILE_SEP_PATH; + + // first, recurse into subdirs + if ( flags & wxDIR_DIRS ) + { + wxString dirname; + for ( bool cont = GetFirst(&dirname, wxEmptyString, wxDIR_DIRS | (flags & wxDIR_HIDDEN) ); + cont; + cont = cont && GetNext(&dirname) ) + { + const wxString fulldirname = prefix + dirname; + + switch ( sink.OnDir(fulldirname) ) + { + default: + wxFAIL_MSG(_T("unexpected OnDir() return value") ); + // fall through + + case wxDIR_STOP: + cont = false; + break; + + case wxDIR_CONTINUE: + { + wxDir subdir; + + // don't give the error messages for the directories + // which we can't open: there can be all sorts of good + // reason for this (e.g. insufficient privileges) and + // this shouldn't be treated as an error -- instead + // let the user code decide what to do + bool ok; + do + { + wxLogNull noLog; + ok = subdir.Open(fulldirname); + if ( !ok ) + { + // ask the user code what to do + bool tryagain; + switch ( sink.OnOpenError(fulldirname) ) + { + default: + wxFAIL_MSG(_T("unexpected OnOpenError() return value") ); + // fall through + + case wxDIR_STOP: + cont = false; + // fall through + + case wxDIR_IGNORE: + tryagain = false; + break; + + case wxDIR_CONTINUE: + tryagain = true; + } + + if ( !tryagain ) + break; + } + } + while ( !ok ); + + if ( ok ) + { + nFiles += subdir.Traverse(sink, filespec, flags); + } + } + break; + + case wxDIR_IGNORE: + // nothing to do + ; + } + } + } + + // now enum our own files + if ( flags & wxDIR_FILES ) + { + flags &= ~wxDIR_DIRS; + + wxString filename; + bool cont = GetFirst(&filename, filespec, flags); + while ( cont ) + { + wxDirTraverseResult res = sink.OnFile(prefix + filename); + if ( res == wxDIR_STOP ) + break; + + wxASSERT_MSG( res == wxDIR_CONTINUE, + _T("unexpected OnFile() return value") ); + + nFiles++; + + cont = GetNext(&filename); + } + } + + return nFiles; +} + +// ---------------------------------------------------------------------------- +// wxDir::GetAllFiles() +// ---------------------------------------------------------------------------- + +class wxDirTraverserSimple : public wxDirTraverser +{ +public: + wxDirTraverserSimple(wxArrayString& files) : m_files(files) { } + + virtual wxDirTraverseResult OnFile(const wxString& filename) + { + m_files.push_back(filename); + return wxDIR_CONTINUE; + } + + virtual wxDirTraverseResult OnDir(const wxString& WXUNUSED(dirname)) + { + return wxDIR_CONTINUE; + } + +private: + wxArrayString& m_files; + + DECLARE_NO_COPY_CLASS(wxDirTraverserSimple) +}; + +/* static */ +size_t wxDir::GetAllFiles(const wxString& dirname, + wxArrayString *files, + const wxString& filespec, + int flags) +{ + wxCHECK_MSG( files, (size_t)-1, _T("NULL pointer in wxDir::GetAllFiles") ); + + size_t nFiles = 0; + + wxDir dir(dirname); + if ( dir.IsOpened() ) + { + wxDirTraverserSimple traverser(*files); + + nFiles += dir.Traverse(traverser, filespec, flags); + } + + return nFiles; +} + +// ---------------------------------------------------------------------------- +// wxDir::FindFirst() +// ---------------------------------------------------------------------------- + +class wxDirTraverserFindFirst : public wxDirTraverser +{ +public: + wxDirTraverserFindFirst() { } + + virtual wxDirTraverseResult OnFile(const wxString& filename) + { + m_file = filename; + return wxDIR_STOP; + } + + virtual wxDirTraverseResult OnDir(const wxString& WXUNUSED(dirname)) + { + return wxDIR_CONTINUE; + } + + const wxString& GetFile() const + { + return m_file; + } + +private: + wxString m_file; + + DECLARE_NO_COPY_CLASS(wxDirTraverserFindFirst) +}; + +/* static */ +wxString wxDir::FindFirst(const wxString& dirname, + const wxString& filespec, + int flags) +{ + wxDir dir(dirname); + if ( dir.IsOpened() ) + { + wxDirTraverserFindFirst traverser; + + dir.Traverse(traverser, filespec, flags | wxDIR_FILES); + return traverser.GetFile(); + } + + return wxEmptyString; +} + + +// ---------------------------------------------------------------------------- +// wxDir::GetTotalSize() +// ---------------------------------------------------------------------------- + +class wxDirTraverserSumSize : public wxDirTraverser +{ +public: + wxDirTraverserSumSize() { } + + virtual wxDirTraverseResult OnFile(const wxString& filename) + { + wxULongLong sz = wxFileName::GetSize(filename); + + // wxFileName::GetSize won't use this class again as + // we're passing it a file and not a directory; + // thus we are sure to avoid an endless loop + if (sz == wxInvalidSize) + { + // if the GetSize() failed (this can happen because e.g. a + // file is locked by another process), we can proceed but + // we need to at least warn the user that the resulting + // final size could be not reliable (if e.g. the locked + // file is very big). + m_skippedFiles.Add(filename); + return wxDIR_CONTINUE; + } + + m_sz += sz; + return wxDIR_CONTINUE; + } + + virtual wxDirTraverseResult OnDir(const wxString& WXUNUSED(dirname)) + { + return wxDIR_CONTINUE; + } + + wxULongLong GetTotalSize() const + { return m_sz; } + wxArrayString &FilesSkipped() + { return m_skippedFiles; } + +protected: + wxULongLong m_sz; + wxArrayString m_skippedFiles; +}; + +wxULongLong wxDir::GetTotalSize(const wxString &dirname, wxArrayString *filesSkipped) +{ + if (!wxDirExists(dirname)) + return wxInvalidSize; + + // to get the size of this directory and its contents we need + // to recursively walk it... + wxDir dir(dirname); + if ( !dir.IsOpened() ) + return wxInvalidSize; + + wxDirTraverserSumSize traverser; + if (dir.Traverse(traverser) == (size_t)-1 || + traverser.GetTotalSize() == 0) + return wxInvalidSize; + + if (filesSkipped) + *filesSkipped = traverser.FilesSkipped(); + + return traverser.GetTotalSize(); +} + diff --git a/Externals/wxWidgets/src/common/dlgcmn.cpp b/Externals/wxWidgets/src/common/dlgcmn.cpp index f119b86011..597b14e2ce 100644 --- a/Externals/wxWidgets/src/common/dlgcmn.cpp +++ b/Externals/wxWidgets/src/common/dlgcmn.cpp @@ -1,565 +1,565 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/dlgcmn.cpp -// Purpose: common (to all ports) wxDialog functions -// Author: Vadim Zeitlin -// Modified by: -// Created: 28.06.99 -// RCS-ID: $Id: dlgcmn.cpp 49747 2007-11-09 15:06:52Z JS $ -// Copyright: (c) Vadim Zeitlin -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#include "wx/dialog.h" - -#ifndef WX_PRECOMP - #include "wx/button.h" - #include "wx/dcclient.h" - #include "wx/intl.h" - #include "wx/settings.h" - #include "wx/stattext.h" - #include "wx/sizer.h" - #include "wx/containr.h" -#endif - -#include "wx/statline.h" -#include "wx/sysopt.h" - -#if wxUSE_STATTEXT - -// ---------------------------------------------------------------------------- -// wxTextWrapper -// ---------------------------------------------------------------------------- - -// this class is used to wrap the text on word boundary: wrapping is done by -// calling OnStartLine() and OnOutputLine() functions -class wxTextWrapper -{ -public: - wxTextWrapper() { m_eol = false; } - - // win is used for getting the font, text is the text to wrap, width is the - // max line width or -1 to disable wrapping - void Wrap(wxWindow *win, const wxString& text, int widthMax); - - // we don't need it, but just to avoid compiler warnings - virtual ~wxTextWrapper() { } - -protected: - // line may be empty - virtual void OnOutputLine(const wxString& line) = 0; - - // called at the start of every new line (except the very first one) - virtual void OnNewLine() { } - -private: - // call OnOutputLine() and set m_eol to true - void DoOutputLine(const wxString& line) - { - OnOutputLine(line); - - m_eol = true; - } - - // this function is a destructive inspector: when it returns true it also - // resets the flag to false so calling it again woulnd't return true any - // more - bool IsStartOfNewLine() - { - if ( !m_eol ) - return false; - - m_eol = false; - - return true; - } - - - bool m_eol; -}; - -#endif // wxUSE_STATTEXT - -// ---------------------------------------------------------------------------- -// wxDialogBase -// ---------------------------------------------------------------------------- - -BEGIN_EVENT_TABLE(wxDialogBase, wxTopLevelWindow) - EVT_BUTTON(wxID_ANY, wxDialogBase::OnButton) - - EVT_CLOSE(wxDialogBase::OnCloseWindow) - - EVT_CHAR_HOOK(wxDialogBase::OnCharHook) - - WX_EVENT_TABLE_CONTROL_CONTAINER(wxDialogBase) -END_EVENT_TABLE() - -WX_DELEGATE_TO_CONTROL_CONTAINER(wxDialogBase, wxTopLevelWindow) - -void wxDialogBase::Init() -{ - m_returnCode = 0; - m_affirmativeId = wxID_OK; - m_escapeId = wxID_ANY; - - // the dialogs have this flag on by default to prevent the events from the - // dialog controls from reaching the parent frame which is usually - // undesirable and can lead to unexpected and hard to find bugs - SetExtraStyle(GetExtraStyle() | wxWS_EX_BLOCK_EVENTS); - - m_container.SetContainerWindow(this); -} - -#if wxUSE_STATTEXT - -void wxTextWrapper::Wrap(wxWindow *win, const wxString& text, int widthMax) -{ - const wxChar *lastSpace = NULL; - wxString line; - - const wxChar *lineStart = text.c_str(); - for ( const wxChar *p = lineStart; ; p++ ) - { - if ( IsStartOfNewLine() ) - { - OnNewLine(); - - lastSpace = NULL; - line.clear(); - lineStart = p; - } - - if ( *p == _T('\n') || *p == _T('\0') ) - { - DoOutputLine(line); - - if ( *p == _T('\0') ) - break; - } - else // not EOL - { - if ( *p == _T(' ') ) - lastSpace = p; - - line += *p; - - if ( widthMax >= 0 && lastSpace ) - { - int width; - win->GetTextExtent(line, &width, NULL); - - if ( width > widthMax ) - { - // remove the last word from this line - line.erase(lastSpace - lineStart, p + 1 - lineStart); - DoOutputLine(line); - - // go back to the last word of this line which we didn't - // output yet - p = lastSpace; - } - } - //else: no wrapping at all or impossible to wrap - } - } -} - -class wxTextSizerWrapper : public wxTextWrapper -{ -public: - wxTextSizerWrapper(wxWindow *win) - { - m_win = win; - m_hLine = 0; - } - - wxSizer *CreateSizer(const wxString& text, int widthMax) - { - m_sizer = new wxBoxSizer(wxVERTICAL); - Wrap(m_win, text, widthMax); - return m_sizer; - } - -protected: - virtual void OnOutputLine(const wxString& line) - { - if ( !line.empty() ) - { - m_sizer->Add(new wxStaticText(m_win, wxID_ANY, line)); - } - else // empty line, no need to create a control for it - { - if ( !m_hLine ) - m_hLine = m_win->GetCharHeight(); - - m_sizer->Add(5, m_hLine); - } - } - -private: - wxWindow *m_win; - wxSizer *m_sizer; - int m_hLine; -}; - -wxSizer *wxDialogBase::CreateTextSizer(const wxString& message) -{ - // I admit that this is complete bogus, but it makes - // message boxes work for pda screens temporarily.. - int widthMax = -1; - const bool is_pda = wxSystemSettings::GetScreenType() <= wxSYS_SCREEN_PDA; - if (is_pda) - { - widthMax = wxSystemSettings::GetMetric( wxSYS_SCREEN_X ) - 25; - } - - // '&' is used as accel mnemonic prefix in the wxWidgets controls but in - // the static messages created by CreateTextSizer() (used by wxMessageBox, - // for example), we don't want this special meaning, so we need to quote it - wxString text(message); - text.Replace(_T("&"), _T("&&")); - - wxTextSizerWrapper wrapper(this); - - return wrapper.CreateSizer(text, widthMax); -} - -class wxLabelWrapper : public wxTextWrapper -{ -public: - void WrapLabel(wxWindow *text, int widthMax) - { - m_text.clear(); - Wrap(text, text->GetLabel(), widthMax); - text->SetLabel(m_text); - } - -protected: - virtual void OnOutputLine(const wxString& line) - { - m_text += line; - } - - virtual void OnNewLine() - { - m_text += _T('\n'); - } - -private: - wxString m_text; -}; - -// NB: don't "factor out" the scope operator, SGI MIPSpro 7.3 (but not 7.4) -// gets confused if it doesn't immediately follow the class name -void -#if defined(__WXGTK__) && !defined(__WXUNIVERSAL__) -wxStaticText:: -#else -wxStaticTextBase:: -#endif -Wrap(int width) -{ - wxLabelWrapper wrapper; - wrapper.WrapLabel(this, width); -} - -#endif // wxUSE_STATTEXT - -wxSizer *wxDialogBase::CreateButtonSizer(long flags) -{ - wxSizer *sizer = NULL; - -#ifdef __SMARTPHONE__ - wxDialog* dialog = (wxDialog*) this; - if ( flags & wxOK ) - dialog->SetLeftMenu(wxID_OK); - - if ( flags & wxCANCEL ) - dialog->SetRightMenu(wxID_CANCEL); - - if ( flags & wxYES ) - dialog->SetLeftMenu(wxID_YES); - - if ( flags & wxNO ) - dialog->SetRightMenu(wxID_NO); -#else // !__SMARTPHONE__ - -#if wxUSE_BUTTON - -#ifdef __POCKETPC__ - // PocketPC guidelines recommend for Ok/Cancel dialogs to use OK button - // located inside caption bar and implement Cancel functionality through - // Undo outside dialog. As native behaviour this will be default here but - // can be replaced with real wxButtons by setting the option below to 1 - if ( (flags & ~(wxCANCEL|wxNO_DEFAULT)) != wxOK || - wxSystemOptions::GetOptionInt(wxT("wince.dialog.real-ok-cancel")) ) -#endif // __POCKETPC__ - { - sizer = CreateStdDialogButtonSizer(flags); - } -#endif // wxUSE_BUTTON - -#endif // __SMARTPHONE__/!__SMARTPHONE__ - - return sizer; -} - -wxSizer *wxDialogBase::CreateSeparatedButtonSizer(long flags) -{ - wxSizer *sizer = CreateButtonSizer(flags); - if ( !sizer ) - return NULL; - - // Mac Human Interface Guidelines recommend not to use static lines as - // grouping elements -#if wxUSE_STATLINE && !defined(__WXMAC__) - wxBoxSizer *topsizer = new wxBoxSizer(wxVERTICAL); - topsizer->Add(new wxStaticLine(this), - wxSizerFlags().Expand().DoubleBorder(wxBOTTOM)); - topsizer->Add(sizer, wxSizerFlags().Expand()); - sizer = topsizer; -#endif // wxUSE_STATLINE - - return sizer; -} - -#if wxUSE_BUTTON - -wxStdDialogButtonSizer *wxDialogBase::CreateStdDialogButtonSizer( long flags ) -{ - wxStdDialogButtonSizer *sizer = new wxStdDialogButtonSizer(); - - wxButton *ok = NULL; - wxButton *yes = NULL; - wxButton *no = NULL; - - if (flags & wxOK) - { - ok = new wxButton(this, wxID_OK); - sizer->AddButton(ok); - } - - if (flags & wxCANCEL) - { - wxButton *cancel = new wxButton(this, wxID_CANCEL); - sizer->AddButton(cancel); - } - - if (flags & wxYES) - { - yes = new wxButton(this, wxID_YES); - sizer->AddButton(yes); - } - - if (flags & wxNO) - { - no = new wxButton(this, wxID_NO); - sizer->AddButton(no); - } - - if (flags & wxHELP) - { - wxButton *help = new wxButton(this, wxID_HELP); - sizer->AddButton(help); - } - - if (flags & wxNO_DEFAULT) - { - if (no) - { - no->SetDefault(); - no->SetFocus(); - } - } - else - { - if (ok) - { - ok->SetDefault(); - ok->SetFocus(); - } - else if (yes) - { - yes->SetDefault(); - yes->SetFocus(); - } - } - - if (flags & wxOK) - SetAffirmativeId(wxID_OK); - else if (flags & wxYES) - SetAffirmativeId(wxID_YES); - - sizer->Realize(); - - return sizer; -} - -#endif // wxUSE_BUTTON - -// ---------------------------------------------------------------------------- -// standard buttons handling -// ---------------------------------------------------------------------------- - -void wxDialogBase::EndDialog(int rc) -{ - if ( IsModal() ) - EndModal(rc); - else - Hide(); -} - -void wxDialogBase::AcceptAndClose() -{ - if ( Validate() && TransferDataFromWindow() ) - { - EndDialog(m_affirmativeId); - } -} - -void wxDialogBase::SetAffirmativeId(int affirmativeId) -{ - m_affirmativeId = affirmativeId; -} - -void wxDialogBase::SetEscapeId(int escapeId) -{ - m_escapeId = escapeId; -} - -bool wxDialogBase::EmulateButtonClickIfPresent(int id) -{ -#if wxUSE_BUTTON - wxButton *btn = wxDynamicCast(FindWindow(id), wxButton); - - if ( !btn || !btn->IsEnabled() || !btn->IsShown() ) - return false; - - wxCommandEvent event(wxEVT_COMMAND_BUTTON_CLICKED, id); - event.SetEventObject(btn); - btn->GetEventHandler()->ProcessEvent(event); - - return true; -#else // !wxUSE_BUTTON - wxUnusedVar(id); - return false; -#endif // wxUSE_BUTTON/!wxUSE_BUTTON -} - -bool wxDialogBase::IsEscapeKey(const wxKeyEvent& event) -{ - // for most platforms, Esc key is used to close the dialogs - return event.GetKeyCode() == WXK_ESCAPE && - event.GetModifiers() == wxMOD_NONE; -} - -void wxDialogBase::OnCharHook(wxKeyEvent& event) -{ - if ( event.GetKeyCode() == WXK_ESCAPE ) - { - int idCancel = GetEscapeId(); - switch ( idCancel ) - { - case wxID_NONE: - // don't handle Esc specially at all - break; - - case wxID_ANY: - // this value is special: it means translate Esc to wxID_CANCEL - // but if there is no such button, then fall back to wxID_OK - if ( EmulateButtonClickIfPresent(wxID_CANCEL) ) - return; - idCancel = GetAffirmativeId(); - // fall through - - default: - // translate Esc to button press for the button with given id - if ( EmulateButtonClickIfPresent(idCancel) ) - return; - } - } - - event.Skip(); -} - -void wxDialogBase::OnButton(wxCommandEvent& event) -{ - const int id = event.GetId(); - if ( id == GetAffirmativeId() ) - { - AcceptAndClose(); - } - else if ( id == wxID_APPLY ) - { - if ( Validate() ) - TransferDataFromWindow(); - - // TODO: disable the Apply button until things change again - } - else if ( id == GetEscapeId() || - (id == wxID_CANCEL && GetEscapeId() == wxID_ANY) ) - { - EndDialog(wxID_CANCEL); - } - else // not a standard button - { - event.Skip(); - } -} - -// ---------------------------------------------------------------------------- -// other event handlers -// ---------------------------------------------------------------------------- - -void wxDialogBase::OnCloseWindow(wxCloseEvent& WXUNUSED(event)) -{ - // We'll send a Cancel message by default, which may close the dialog. - // Check for looping if the Cancel event handler calls Close(). - - // Note that if a cancel button and handler aren't present in the dialog, - // nothing will happen when you close the dialog via the window manager, or - // via Close(). We wouldn't want to destroy the dialog by default, since - // the dialog may have been created on the stack. However, this does mean - // that calling dialog->Close() won't delete the dialog unless the handler - // for wxID_CANCEL does so. So use Destroy() if you want to be sure to - // destroy the dialog. The default OnCancel (above) simply ends a modal - // dialog, and hides a modeless dialog. - - // VZ: this is horrible and MT-unsafe. Can't we reuse some of these global - // lists here? don't dare to change it now, but should be done later! - static wxList closing; - - if ( closing.Member(this) ) - return; - - closing.Append(this); - - wxCommandEvent cancelEvent(wxEVT_COMMAND_BUTTON_CLICKED, wxID_CANCEL); - cancelEvent.SetEventObject( this ); - GetEventHandler()->ProcessEvent(cancelEvent); // This may close the dialog - - closing.DeleteObject(this); -} - -void wxDialogBase::OnSysColourChanged(wxSysColourChangedEvent& event) -{ -#ifndef __WXGTK__ - SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE)); - Refresh(); -#endif - event.Skip(); -} +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/dlgcmn.cpp +// Purpose: common (to all ports) wxDialog functions +// Author: Vadim Zeitlin +// Modified by: +// Created: 28.06.99 +// RCS-ID: $Id: dlgcmn.cpp 49747 2007-11-09 15:06:52Z JS $ +// Copyright: (c) Vadim Zeitlin +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#include "wx/dialog.h" + +#ifndef WX_PRECOMP + #include "wx/button.h" + #include "wx/dcclient.h" + #include "wx/intl.h" + #include "wx/settings.h" + #include "wx/stattext.h" + #include "wx/sizer.h" + #include "wx/containr.h" +#endif + +#include "wx/statline.h" +#include "wx/sysopt.h" + +#if wxUSE_STATTEXT + +// ---------------------------------------------------------------------------- +// wxTextWrapper +// ---------------------------------------------------------------------------- + +// this class is used to wrap the text on word boundary: wrapping is done by +// calling OnStartLine() and OnOutputLine() functions +class wxTextWrapper +{ +public: + wxTextWrapper() { m_eol = false; } + + // win is used for getting the font, text is the text to wrap, width is the + // max line width or -1 to disable wrapping + void Wrap(wxWindow *win, const wxString& text, int widthMax); + + // we don't need it, but just to avoid compiler warnings + virtual ~wxTextWrapper() { } + +protected: + // line may be empty + virtual void OnOutputLine(const wxString& line) = 0; + + // called at the start of every new line (except the very first one) + virtual void OnNewLine() { } + +private: + // call OnOutputLine() and set m_eol to true + void DoOutputLine(const wxString& line) + { + OnOutputLine(line); + + m_eol = true; + } + + // this function is a destructive inspector: when it returns true it also + // resets the flag to false so calling it again woulnd't return true any + // more + bool IsStartOfNewLine() + { + if ( !m_eol ) + return false; + + m_eol = false; + + return true; + } + + + bool m_eol; +}; + +#endif // wxUSE_STATTEXT + +// ---------------------------------------------------------------------------- +// wxDialogBase +// ---------------------------------------------------------------------------- + +BEGIN_EVENT_TABLE(wxDialogBase, wxTopLevelWindow) + EVT_BUTTON(wxID_ANY, wxDialogBase::OnButton) + + EVT_CLOSE(wxDialogBase::OnCloseWindow) + + EVT_CHAR_HOOK(wxDialogBase::OnCharHook) + + WX_EVENT_TABLE_CONTROL_CONTAINER(wxDialogBase) +END_EVENT_TABLE() + +WX_DELEGATE_TO_CONTROL_CONTAINER(wxDialogBase, wxTopLevelWindow) + +void wxDialogBase::Init() +{ + m_returnCode = 0; + m_affirmativeId = wxID_OK; + m_escapeId = wxID_ANY; + + // the dialogs have this flag on by default to prevent the events from the + // dialog controls from reaching the parent frame which is usually + // undesirable and can lead to unexpected and hard to find bugs + SetExtraStyle(GetExtraStyle() | wxWS_EX_BLOCK_EVENTS); + + m_container.SetContainerWindow(this); +} + +#if wxUSE_STATTEXT + +void wxTextWrapper::Wrap(wxWindow *win, const wxString& text, int widthMax) +{ + const wxChar *lastSpace = NULL; + wxString line; + + const wxChar *lineStart = text.c_str(); + for ( const wxChar *p = lineStart; ; p++ ) + { + if ( IsStartOfNewLine() ) + { + OnNewLine(); + + lastSpace = NULL; + line.clear(); + lineStart = p; + } + + if ( *p == _T('\n') || *p == _T('\0') ) + { + DoOutputLine(line); + + if ( *p == _T('\0') ) + break; + } + else // not EOL + { + if ( *p == _T(' ') ) + lastSpace = p; + + line += *p; + + if ( widthMax >= 0 && lastSpace ) + { + int width; + win->GetTextExtent(line, &width, NULL); + + if ( width > widthMax ) + { + // remove the last word from this line + line.erase(lastSpace - lineStart, p + 1 - lineStart); + DoOutputLine(line); + + // go back to the last word of this line which we didn't + // output yet + p = lastSpace; + } + } + //else: no wrapping at all or impossible to wrap + } + } +} + +class wxTextSizerWrapper : public wxTextWrapper +{ +public: + wxTextSizerWrapper(wxWindow *win) + { + m_win = win; + m_hLine = 0; + } + + wxSizer *CreateSizer(const wxString& text, int widthMax) + { + m_sizer = new wxBoxSizer(wxVERTICAL); + Wrap(m_win, text, widthMax); + return m_sizer; + } + +protected: + virtual void OnOutputLine(const wxString& line) + { + if ( !line.empty() ) + { + m_sizer->Add(new wxStaticText(m_win, wxID_ANY, line)); + } + else // empty line, no need to create a control for it + { + if ( !m_hLine ) + m_hLine = m_win->GetCharHeight(); + + m_sizer->Add(5, m_hLine); + } + } + +private: + wxWindow *m_win; + wxSizer *m_sizer; + int m_hLine; +}; + +wxSizer *wxDialogBase::CreateTextSizer(const wxString& message) +{ + // I admit that this is complete bogus, but it makes + // message boxes work for pda screens temporarily.. + int widthMax = -1; + const bool is_pda = wxSystemSettings::GetScreenType() <= wxSYS_SCREEN_PDA; + if (is_pda) + { + widthMax = wxSystemSettings::GetMetric( wxSYS_SCREEN_X ) - 25; + } + + // '&' is used as accel mnemonic prefix in the wxWidgets controls but in + // the static messages created by CreateTextSizer() (used by wxMessageBox, + // for example), we don't want this special meaning, so we need to quote it + wxString text(message); + text.Replace(_T("&"), _T("&&")); + + wxTextSizerWrapper wrapper(this); + + return wrapper.CreateSizer(text, widthMax); +} + +class wxLabelWrapper : public wxTextWrapper +{ +public: + void WrapLabel(wxWindow *text, int widthMax) + { + m_text.clear(); + Wrap(text, text->GetLabel(), widthMax); + text->SetLabel(m_text); + } + +protected: + virtual void OnOutputLine(const wxString& line) + { + m_text += line; + } + + virtual void OnNewLine() + { + m_text += _T('\n'); + } + +private: + wxString m_text; +}; + +// NB: don't "factor out" the scope operator, SGI MIPSpro 7.3 (but not 7.4) +// gets confused if it doesn't immediately follow the class name +void +#if defined(__WXGTK__) && !defined(__WXUNIVERSAL__) +wxStaticText:: +#else +wxStaticTextBase:: +#endif +Wrap(int width) +{ + wxLabelWrapper wrapper; + wrapper.WrapLabel(this, width); +} + +#endif // wxUSE_STATTEXT + +wxSizer *wxDialogBase::CreateButtonSizer(long flags) +{ + wxSizer *sizer = NULL; + +#ifdef __SMARTPHONE__ + wxDialog* dialog = (wxDialog*) this; + if ( flags & wxOK ) + dialog->SetLeftMenu(wxID_OK); + + if ( flags & wxCANCEL ) + dialog->SetRightMenu(wxID_CANCEL); + + if ( flags & wxYES ) + dialog->SetLeftMenu(wxID_YES); + + if ( flags & wxNO ) + dialog->SetRightMenu(wxID_NO); +#else // !__SMARTPHONE__ + +#if wxUSE_BUTTON + +#ifdef __POCKETPC__ + // PocketPC guidelines recommend for Ok/Cancel dialogs to use OK button + // located inside caption bar and implement Cancel functionality through + // Undo outside dialog. As native behaviour this will be default here but + // can be replaced with real wxButtons by setting the option below to 1 + if ( (flags & ~(wxCANCEL|wxNO_DEFAULT)) != wxOK || + wxSystemOptions::GetOptionInt(wxT("wince.dialog.real-ok-cancel")) ) +#endif // __POCKETPC__ + { + sizer = CreateStdDialogButtonSizer(flags); + } +#endif // wxUSE_BUTTON + +#endif // __SMARTPHONE__/!__SMARTPHONE__ + + return sizer; +} + +wxSizer *wxDialogBase::CreateSeparatedButtonSizer(long flags) +{ + wxSizer *sizer = CreateButtonSizer(flags); + if ( !sizer ) + return NULL; + + // Mac Human Interface Guidelines recommend not to use static lines as + // grouping elements +#if wxUSE_STATLINE && !defined(__WXMAC__) + wxBoxSizer *topsizer = new wxBoxSizer(wxVERTICAL); + topsizer->Add(new wxStaticLine(this), + wxSizerFlags().Expand().DoubleBorder(wxBOTTOM)); + topsizer->Add(sizer, wxSizerFlags().Expand()); + sizer = topsizer; +#endif // wxUSE_STATLINE + + return sizer; +} + +#if wxUSE_BUTTON + +wxStdDialogButtonSizer *wxDialogBase::CreateStdDialogButtonSizer( long flags ) +{ + wxStdDialogButtonSizer *sizer = new wxStdDialogButtonSizer(); + + wxButton *ok = NULL; + wxButton *yes = NULL; + wxButton *no = NULL; + + if (flags & wxOK) + { + ok = new wxButton(this, wxID_OK); + sizer->AddButton(ok); + } + + if (flags & wxCANCEL) + { + wxButton *cancel = new wxButton(this, wxID_CANCEL); + sizer->AddButton(cancel); + } + + if (flags & wxYES) + { + yes = new wxButton(this, wxID_YES); + sizer->AddButton(yes); + } + + if (flags & wxNO) + { + no = new wxButton(this, wxID_NO); + sizer->AddButton(no); + } + + if (flags & wxHELP) + { + wxButton *help = new wxButton(this, wxID_HELP); + sizer->AddButton(help); + } + + if (flags & wxNO_DEFAULT) + { + if (no) + { + no->SetDefault(); + no->SetFocus(); + } + } + else + { + if (ok) + { + ok->SetDefault(); + ok->SetFocus(); + } + else if (yes) + { + yes->SetDefault(); + yes->SetFocus(); + } + } + + if (flags & wxOK) + SetAffirmativeId(wxID_OK); + else if (flags & wxYES) + SetAffirmativeId(wxID_YES); + + sizer->Realize(); + + return sizer; +} + +#endif // wxUSE_BUTTON + +// ---------------------------------------------------------------------------- +// standard buttons handling +// ---------------------------------------------------------------------------- + +void wxDialogBase::EndDialog(int rc) +{ + if ( IsModal() ) + EndModal(rc); + else + Hide(); +} + +void wxDialogBase::AcceptAndClose() +{ + if ( Validate() && TransferDataFromWindow() ) + { + EndDialog(m_affirmativeId); + } +} + +void wxDialogBase::SetAffirmativeId(int affirmativeId) +{ + m_affirmativeId = affirmativeId; +} + +void wxDialogBase::SetEscapeId(int escapeId) +{ + m_escapeId = escapeId; +} + +bool wxDialogBase::EmulateButtonClickIfPresent(int id) +{ +#if wxUSE_BUTTON + wxButton *btn = wxDynamicCast(FindWindow(id), wxButton); + + if ( !btn || !btn->IsEnabled() || !btn->IsShown() ) + return false; + + wxCommandEvent event(wxEVT_COMMAND_BUTTON_CLICKED, id); + event.SetEventObject(btn); + btn->GetEventHandler()->ProcessEvent(event); + + return true; +#else // !wxUSE_BUTTON + wxUnusedVar(id); + return false; +#endif // wxUSE_BUTTON/!wxUSE_BUTTON +} + +bool wxDialogBase::IsEscapeKey(const wxKeyEvent& event) +{ + // for most platforms, Esc key is used to close the dialogs + return event.GetKeyCode() == WXK_ESCAPE && + event.GetModifiers() == wxMOD_NONE; +} + +void wxDialogBase::OnCharHook(wxKeyEvent& event) +{ + if ( event.GetKeyCode() == WXK_ESCAPE ) + { + int idCancel = GetEscapeId(); + switch ( idCancel ) + { + case wxID_NONE: + // don't handle Esc specially at all + break; + + case wxID_ANY: + // this value is special: it means translate Esc to wxID_CANCEL + // but if there is no such button, then fall back to wxID_OK + if ( EmulateButtonClickIfPresent(wxID_CANCEL) ) + return; + idCancel = GetAffirmativeId(); + // fall through + + default: + // translate Esc to button press for the button with given id + if ( EmulateButtonClickIfPresent(idCancel) ) + return; + } + } + + event.Skip(); +} + +void wxDialogBase::OnButton(wxCommandEvent& event) +{ + const int id = event.GetId(); + if ( id == GetAffirmativeId() ) + { + AcceptAndClose(); + } + else if ( id == wxID_APPLY ) + { + if ( Validate() ) + TransferDataFromWindow(); + + // TODO: disable the Apply button until things change again + } + else if ( id == GetEscapeId() || + (id == wxID_CANCEL && GetEscapeId() == wxID_ANY) ) + { + EndDialog(wxID_CANCEL); + } + else // not a standard button + { + event.Skip(); + } +} + +// ---------------------------------------------------------------------------- +// other event handlers +// ---------------------------------------------------------------------------- + +void wxDialogBase::OnCloseWindow(wxCloseEvent& WXUNUSED(event)) +{ + // We'll send a Cancel message by default, which may close the dialog. + // Check for looping if the Cancel event handler calls Close(). + + // Note that if a cancel button and handler aren't present in the dialog, + // nothing will happen when you close the dialog via the window manager, or + // via Close(). We wouldn't want to destroy the dialog by default, since + // the dialog may have been created on the stack. However, this does mean + // that calling dialog->Close() won't delete the dialog unless the handler + // for wxID_CANCEL does so. So use Destroy() if you want to be sure to + // destroy the dialog. The default OnCancel (above) simply ends a modal + // dialog, and hides a modeless dialog. + + // VZ: this is horrible and MT-unsafe. Can't we reuse some of these global + // lists here? don't dare to change it now, but should be done later! + static wxList closing; + + if ( closing.Member(this) ) + return; + + closing.Append(this); + + wxCommandEvent cancelEvent(wxEVT_COMMAND_BUTTON_CLICKED, wxID_CANCEL); + cancelEvent.SetEventObject( this ); + GetEventHandler()->ProcessEvent(cancelEvent); // This may close the dialog + + closing.DeleteObject(this); +} + +void wxDialogBase::OnSysColourChanged(wxSysColourChangedEvent& event) +{ +#ifndef __WXGTK__ + SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE)); + Refresh(); +#endif + event.Skip(); +} diff --git a/Externals/wxWidgets/src/common/dndcmn.cpp b/Externals/wxWidgets/src/common/dndcmn.cpp index 75b8a8d314..5daf3da7dd 100644 --- a/Externals/wxWidgets/src/common/dndcmn.cpp +++ b/Externals/wxWidgets/src/common/dndcmn.cpp @@ -1,31 +1,31 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: common/dndcmn.cpp -// Author: Robert Roebling -// Modified by: -// Created: 19.10.99 -// RCS-ID: $Id: dndcmn.cpp 43664 2006-11-26 21:50:51Z JS $ -// Copyright: (c) wxWidgets Team -// Licence: wxWindows licence -/////////////////////////////////////////////////////////////////////////////// - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#include "wx/dnd.h" - -#if wxUSE_DRAG_AND_DROP - -bool wxIsDragResultOk(wxDragResult res) -{ - return res == wxDragCopy || res == wxDragMove || res == wxDragLink; -} - -#endif - +/////////////////////////////////////////////////////////////////////////////// +// Name: common/dndcmn.cpp +// Author: Robert Roebling +// Modified by: +// Created: 19.10.99 +// RCS-ID: $Id: dndcmn.cpp 43664 2006-11-26 21:50:51Z JS $ +// Copyright: (c) wxWidgets Team +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#include "wx/dnd.h" + +#if wxUSE_DRAG_AND_DROP + +bool wxIsDragResultOk(wxDragResult res) +{ + return res == wxDragCopy || res == wxDragMove || res == wxDragLink; +} + +#endif + diff --git a/Externals/wxWidgets/src/common/dobjcmn.cpp b/Externals/wxWidgets/src/common/dobjcmn.cpp index f9404928e6..68b194d3ee 100644 --- a/Externals/wxWidgets/src/common/dobjcmn.cpp +++ b/Externals/wxWidgets/src/common/dobjcmn.cpp @@ -1,517 +1,517 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: src/common/dobjcmn.cpp -// Purpose: implementation of data object methods common to all platforms -// Author: Vadim Zeitlin, Robert Roebling -// Modified by: -// Created: 19.10.99 -// RCS-ID: $Id: dobjcmn.cpp 49036 2007-10-04 10:10:06Z SC $ -// Copyright: (c) wxWidgets Team -// Licence: wxWindows licence -/////////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_DATAOBJ - -#include "wx/dataobj.h" - -#ifndef WX_PRECOMP - #include "wx/app.h" -#endif - -// ---------------------------------------------------------------------------- -// lists -// ---------------------------------------------------------------------------- - -#include "wx/listimpl.cpp" - -WX_DEFINE_LIST(wxSimpleDataObjectList) - -// ---------------------------------------------------------------------------- -// globals -// ---------------------------------------------------------------------------- - -static wxDataFormat dataFormatInvalid; -WXDLLEXPORT const wxDataFormat& wxFormatInvalid = dataFormatInvalid; - -// ============================================================================ -// implementation -// ============================================================================ - -// ---------------------------------------------------------------------------- -// wxDataObjectBase -// ---------------------------------------------------------------------------- - -wxDataObjectBase::~wxDataObjectBase() -{ -} - -bool wxDataObjectBase::IsSupported(const wxDataFormat& format, - Direction dir) const -{ - size_t nFormatCount = GetFormatCount( dir ); - if ( nFormatCount == 1 ) - { - return format == GetPreferredFormat( dir ); - } - else - { - wxDataFormat *formats = new wxDataFormat[nFormatCount]; - GetAllFormats( formats, dir ); - - size_t n; - for ( n = 0; n < nFormatCount; n++ ) - { - if ( formats[n] == format ) - break; - } - - delete [] formats; - - // found? - return n < nFormatCount; - } -} - -// ---------------------------------------------------------------------------- -// wxDataObjectComposite -// ---------------------------------------------------------------------------- - -wxDataObjectComposite::wxDataObjectComposite() -{ - m_preferred = 0; - m_receivedFormat = wxFormatInvalid; -} - -wxDataObjectComposite::~wxDataObjectComposite() -{ - WX_CLEAR_LIST( wxSimpleDataObjectList, m_dataObjects ); -} - -wxDataObjectSimple * -wxDataObjectComposite::GetObject(const wxDataFormat& format) const -{ - wxSimpleDataObjectList::compatibility_iterator node = m_dataObjects.GetFirst(); - while ( node ) - { - wxDataObjectSimple *dataObj = node->GetData(); - - if ( dataObj->GetFormat() == format ) - { - return dataObj; - } - - node = node->GetNext(); - } - - return (wxDataObjectSimple *)NULL; -} - -void wxDataObjectComposite::Add(wxDataObjectSimple *dataObject, bool preferred) -{ - if ( preferred ) - m_preferred = m_dataObjects.GetCount(); - - m_dataObjects.Append( dataObject ); -} - -wxDataFormat wxDataObjectComposite::GetReceivedFormat() const -{ - return m_receivedFormat; -} - -wxDataFormat -wxDataObjectComposite::GetPreferredFormat(Direction WXUNUSED(dir)) const -{ - wxSimpleDataObjectList::compatibility_iterator node = m_dataObjects.Item( m_preferred ); - - wxCHECK_MSG( node, wxFormatInvalid, wxT("no preferred format") ); - - wxDataObjectSimple* dataObj = node->GetData(); - - return dataObj->GetFormat(); -} - -#if defined(__WXMSW__) - -size_t wxDataObjectComposite::GetBufferOffset( const wxDataFormat& format ) -{ - wxDataObjectSimple *dataObj = GetObject(format); - - wxCHECK_MSG( dataObj, 0, - wxT("unsupported format in wxDataObjectComposite")); - - return dataObj->GetBufferOffset( format ); -} - - -const void* wxDataObjectComposite::GetSizeFromBuffer( const void* buffer, - size_t* size, - const wxDataFormat& format ) -{ - wxDataObjectSimple *dataObj = GetObject(format); - - wxCHECK_MSG( dataObj, NULL, - wxT("unsupported format in wxDataObjectComposite")); - - return dataObj->GetSizeFromBuffer( buffer, size, format ); -} - - -void* wxDataObjectComposite::SetSizeInBuffer( void* buffer, size_t size, - const wxDataFormat& format ) -{ - wxDataObjectSimple *dataObj = GetObject( format ); - - wxCHECK_MSG( dataObj, NULL, - wxT("unsupported format in wxDataObjectComposite")); - - return dataObj->SetSizeInBuffer( buffer, size, format ); -} - -#endif - -size_t wxDataObjectComposite::GetFormatCount(Direction WXUNUSED(dir)) const -{ - // TODO what about the Get/Set only formats? - return m_dataObjects.GetCount(); -} - -void wxDataObjectComposite::GetAllFormats(wxDataFormat *formats, - Direction WXUNUSED(dir)) const -{ - size_t n = 0; - wxSimpleDataObjectList::compatibility_iterator node; - for ( node = m_dataObjects.GetFirst(); node; node = node->GetNext() ) - { - // TODO if ( !outputOnlyToo ) && this one counts ... - formats[n++] = node->GetData()->GetFormat(); - } -} - -size_t wxDataObjectComposite::GetDataSize(const wxDataFormat& format) const -{ - wxDataObjectSimple *dataObj = GetObject(format); - - wxCHECK_MSG( dataObj, 0, - wxT("unsupported format in wxDataObjectComposite")); - - return dataObj->GetDataSize(); -} - -bool wxDataObjectComposite::GetDataHere(const wxDataFormat& format, - void *buf) const -{ - wxDataObjectSimple *dataObj = GetObject( format ); - - wxCHECK_MSG( dataObj, false, - wxT("unsupported format in wxDataObjectComposite")); - - return dataObj->GetDataHere( buf ); -} - -bool wxDataObjectComposite::SetData(const wxDataFormat& format, - size_t len, - const void *buf) -{ - wxDataObjectSimple *dataObj = GetObject( format ); - - wxCHECK_MSG( dataObj, false, - wxT("unsupported format in wxDataObjectComposite")); - - m_receivedFormat = format; - return dataObj->SetData( len, buf ); -} - -// ---------------------------------------------------------------------------- -// wxTextDataObject -// ---------------------------------------------------------------------------- - -#if defined(__WXGTK20__) && wxUSE_UNICODE - -static inline wxMBConv& GetConv(const wxDataFormat& format) -{ - // use UTF8 for wxDF_UNICODETEXT and UCS4 for wxDF_TEXT - return format == wxDF_UNICODETEXT ? wxConvUTF8 : wxConvLibc; -} - -size_t wxTextDataObject::GetDataSize(const wxDataFormat& format) const -{ - wxCharBuffer buffer = GetConv(format).cWX2MB( GetText().c_str() ); - - return buffer ? strlen( buffer ) : 0; -} - -bool wxTextDataObject::GetDataHere(const wxDataFormat& format, void *buf) const -{ - if ( !buf ) - return false; - - wxCharBuffer buffer = GetConv(format).cWX2MB( GetText().c_str() ); - if ( !buffer ) - return false; - - memcpy( (char*) buf, buffer, GetDataSize(format) ); - // strcpy( (char*) buf, buffer ); - - return true; -} - -bool wxTextDataObject::SetData(const wxDataFormat& format, - size_t WXUNUSED(len), const void *buf) -{ - if ( buf == NULL ) - return false; - - wxWCharBuffer buffer = GetConv(format).cMB2WX( (const char*)buf ); - - SetText( buffer ); - - return true; -} - -#elif wxUSE_UNICODE && defined(__WXMAC__) - -static wxMBConvUTF16 sUTF16Converter; - -static inline wxMBConv& GetConv(const wxDataFormat& format) -{ - return - format == wxDF_UNICODETEXT - ? (wxMBConv&) sUTF16Converter - : (wxMBConv&) wxConvLocal; -} - -size_t wxTextDataObject::GetDataSize(const wxDataFormat& format) const -{ - wxCharBuffer buffer = GetConv(format).cWX2MB( GetText().c_str() ); - if ( !buffer ) - return 0; - - size_t len = GetConv(format).WC2MB( NULL, GetText().c_str(), 0 ); - return len; -} - -bool wxTextDataObject::GetDataHere(const wxDataFormat& format, void *buf) const -{ - if ( buf == NULL ) - return false; - - wxCharBuffer buffer = GetConv(format).cWX2MB( GetText().c_str() ); - if ( !buffer ) - return false; - - size_t len = GetConv(format).WC2MB( NULL, GetText().c_str(), 0 ); - memcpy( (char*)buf, (const char*)buffer, len ); - - return true; -} - -bool wxTextDataObject::SetData(const wxDataFormat& format, - size_t WXUNUSED(len), const void *buf) -{ - if ( buf == NULL ) - return false; - - wxWCharBuffer buffer = GetConv(format).cMB2WX( (const char*)buf ); - - SetText( buffer ); - - return true; -} - -#else - -size_t wxTextDataObject::GetDataSize() const -{ - return GetTextLength() * sizeof(wxChar); -} - -bool wxTextDataObject::GetDataHere(void *buf) const -{ - wxStrcpy( (wxChar*)buf, GetText().c_str() ); - - return true; -} - -bool wxTextDataObject::SetData(size_t WXUNUSED(len), const void *buf) -{ - SetText( wxString((const wxChar*)buf) ); - - return true; -} - -#endif - -// ---------------------------------------------------------------------------- -// wxFileDataObjectBase -// ---------------------------------------------------------------------------- - -// VZ: I don't need this in MSW finally, so if it is needed in wxGTK, it should -// be moved to gtk/dataobj.cpp -#if 0 - -wxString wxFileDataObjectBase::GetFilenames() const -{ - wxString str; - size_t count = m_filenames.GetCount(); - for ( size_t n = 0; n < count; n++ ) - { - str << m_filenames[n] << wxT('\0'); - } - - return str; -} - -void wxFileDataObjectBase::SetFilenames(const wxChar* filenames) -{ - m_filenames.Empty(); - - wxString current; - for ( const wxChar *pc = filenames; ; pc++ ) - { - if ( *pc ) - { - current += *pc; - } - else - { - if ( !current ) - { - // 2 consecutive NULs - this is the end of the string - break; - } - - m_filenames.Add(current); - current.Empty(); - } - } -} - -#endif - -// ---------------------------------------------------------------------------- -// wxCustomDataObject -// ---------------------------------------------------------------------------- - -wxCustomDataObject::wxCustomDataObject(const wxDataFormat& format) - : wxDataObjectSimple(format) -{ - m_data = NULL; - m_size = 0; -} - -wxCustomDataObject::~wxCustomDataObject() -{ - Free(); -} - -void wxCustomDataObject::TakeData(size_t size, void *data) -{ - Free(); - - m_size = size; - m_data = data; -} - -void *wxCustomDataObject::Alloc(size_t size) -{ - return (void *)new char[size]; -} - -void wxCustomDataObject::Free() -{ - delete [] (char*)m_data; - m_size = 0; - m_data = (void*)NULL; -} - -size_t wxCustomDataObject::GetDataSize() const -{ - return GetSize(); -} - -bool wxCustomDataObject::GetDataHere(void *buf) const -{ - if ( buf == NULL ) - return false; - - void *data = GetData(); - if ( data == NULL ) - return false; - - memcpy( buf, data, GetSize() ); - - return true; -} - -bool wxCustomDataObject::SetData(size_t size, const void *buf) -{ - Free(); - - m_data = Alloc(size); - if ( m_data == NULL ) - return false; - - m_size = size; - memcpy( m_data, buf, m_size ); - - return true; -} - -// ============================================================================ -// some common dnd related code -// ============================================================================ - -#if wxUSE_DRAG_AND_DROP - -#include "wx/dnd.h" - -// ---------------------------------------------------------------------------- -// wxTextDropTarget -// ---------------------------------------------------------------------------- - -// NB: we can't use "new" in ctor initializer lists because this provokes an -// internal compiler error with VC++ 5.0 (hey, even gcc compiles this!), -// so use SetDataObject() instead - -wxTextDropTarget::wxTextDropTarget() -{ - SetDataObject(new wxTextDataObject); -} - -wxDragResult wxTextDropTarget::OnData(wxCoord x, wxCoord y, wxDragResult def) -{ - if ( !GetData() ) - return wxDragNone; - - wxTextDataObject *dobj = (wxTextDataObject *)m_dataObject; - return OnDropText( x, y, dobj->GetText() ) ? def : wxDragNone; -} - -// ---------------------------------------------------------------------------- -// wxFileDropTarget -// ---------------------------------------------------------------------------- - -wxFileDropTarget::wxFileDropTarget() -{ - SetDataObject(new wxFileDataObject); -} - -wxDragResult wxFileDropTarget::OnData(wxCoord x, wxCoord y, wxDragResult def) -{ - if ( !GetData() ) - return wxDragNone; - - wxFileDataObject *dobj = (wxFileDataObject *)m_dataObject; - return OnDropFiles( x, y, dobj->GetFilenames() ) ? def : wxDragNone; -} - -#endif // wxUSE_DRAG_AND_DROP - -#endif // wxUSE_DATAOBJ +/////////////////////////////////////////////////////////////////////////////// +// Name: src/common/dobjcmn.cpp +// Purpose: implementation of data object methods common to all platforms +// Author: Vadim Zeitlin, Robert Roebling +// Modified by: +// Created: 19.10.99 +// RCS-ID: $Id: dobjcmn.cpp 49036 2007-10-04 10:10:06Z SC $ +// Copyright: (c) wxWidgets Team +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_DATAOBJ + +#include "wx/dataobj.h" + +#ifndef WX_PRECOMP + #include "wx/app.h" +#endif + +// ---------------------------------------------------------------------------- +// lists +// ---------------------------------------------------------------------------- + +#include "wx/listimpl.cpp" + +WX_DEFINE_LIST(wxSimpleDataObjectList) + +// ---------------------------------------------------------------------------- +// globals +// ---------------------------------------------------------------------------- + +static wxDataFormat dataFormatInvalid; +WXDLLEXPORT const wxDataFormat& wxFormatInvalid = dataFormatInvalid; + +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// wxDataObjectBase +// ---------------------------------------------------------------------------- + +wxDataObjectBase::~wxDataObjectBase() +{ +} + +bool wxDataObjectBase::IsSupported(const wxDataFormat& format, + Direction dir) const +{ + size_t nFormatCount = GetFormatCount( dir ); + if ( nFormatCount == 1 ) + { + return format == GetPreferredFormat( dir ); + } + else + { + wxDataFormat *formats = new wxDataFormat[nFormatCount]; + GetAllFormats( formats, dir ); + + size_t n; + for ( n = 0; n < nFormatCount; n++ ) + { + if ( formats[n] == format ) + break; + } + + delete [] formats; + + // found? + return n < nFormatCount; + } +} + +// ---------------------------------------------------------------------------- +// wxDataObjectComposite +// ---------------------------------------------------------------------------- + +wxDataObjectComposite::wxDataObjectComposite() +{ + m_preferred = 0; + m_receivedFormat = wxFormatInvalid; +} + +wxDataObjectComposite::~wxDataObjectComposite() +{ + WX_CLEAR_LIST( wxSimpleDataObjectList, m_dataObjects ); +} + +wxDataObjectSimple * +wxDataObjectComposite::GetObject(const wxDataFormat& format) const +{ + wxSimpleDataObjectList::compatibility_iterator node = m_dataObjects.GetFirst(); + while ( node ) + { + wxDataObjectSimple *dataObj = node->GetData(); + + if ( dataObj->GetFormat() == format ) + { + return dataObj; + } + + node = node->GetNext(); + } + + return (wxDataObjectSimple *)NULL; +} + +void wxDataObjectComposite::Add(wxDataObjectSimple *dataObject, bool preferred) +{ + if ( preferred ) + m_preferred = m_dataObjects.GetCount(); + + m_dataObjects.Append( dataObject ); +} + +wxDataFormat wxDataObjectComposite::GetReceivedFormat() const +{ + return m_receivedFormat; +} + +wxDataFormat +wxDataObjectComposite::GetPreferredFormat(Direction WXUNUSED(dir)) const +{ + wxSimpleDataObjectList::compatibility_iterator node = m_dataObjects.Item( m_preferred ); + + wxCHECK_MSG( node, wxFormatInvalid, wxT("no preferred format") ); + + wxDataObjectSimple* dataObj = node->GetData(); + + return dataObj->GetFormat(); +} + +#if defined(__WXMSW__) + +size_t wxDataObjectComposite::GetBufferOffset( const wxDataFormat& format ) +{ + wxDataObjectSimple *dataObj = GetObject(format); + + wxCHECK_MSG( dataObj, 0, + wxT("unsupported format in wxDataObjectComposite")); + + return dataObj->GetBufferOffset( format ); +} + + +const void* wxDataObjectComposite::GetSizeFromBuffer( const void* buffer, + size_t* size, + const wxDataFormat& format ) +{ + wxDataObjectSimple *dataObj = GetObject(format); + + wxCHECK_MSG( dataObj, NULL, + wxT("unsupported format in wxDataObjectComposite")); + + return dataObj->GetSizeFromBuffer( buffer, size, format ); +} + + +void* wxDataObjectComposite::SetSizeInBuffer( void* buffer, size_t size, + const wxDataFormat& format ) +{ + wxDataObjectSimple *dataObj = GetObject( format ); + + wxCHECK_MSG( dataObj, NULL, + wxT("unsupported format in wxDataObjectComposite")); + + return dataObj->SetSizeInBuffer( buffer, size, format ); +} + +#endif + +size_t wxDataObjectComposite::GetFormatCount(Direction WXUNUSED(dir)) const +{ + // TODO what about the Get/Set only formats? + return m_dataObjects.GetCount(); +} + +void wxDataObjectComposite::GetAllFormats(wxDataFormat *formats, + Direction WXUNUSED(dir)) const +{ + size_t n = 0; + wxSimpleDataObjectList::compatibility_iterator node; + for ( node = m_dataObjects.GetFirst(); node; node = node->GetNext() ) + { + // TODO if ( !outputOnlyToo ) && this one counts ... + formats[n++] = node->GetData()->GetFormat(); + } +} + +size_t wxDataObjectComposite::GetDataSize(const wxDataFormat& format) const +{ + wxDataObjectSimple *dataObj = GetObject(format); + + wxCHECK_MSG( dataObj, 0, + wxT("unsupported format in wxDataObjectComposite")); + + return dataObj->GetDataSize(); +} + +bool wxDataObjectComposite::GetDataHere(const wxDataFormat& format, + void *buf) const +{ + wxDataObjectSimple *dataObj = GetObject( format ); + + wxCHECK_MSG( dataObj, false, + wxT("unsupported format in wxDataObjectComposite")); + + return dataObj->GetDataHere( buf ); +} + +bool wxDataObjectComposite::SetData(const wxDataFormat& format, + size_t len, + const void *buf) +{ + wxDataObjectSimple *dataObj = GetObject( format ); + + wxCHECK_MSG( dataObj, false, + wxT("unsupported format in wxDataObjectComposite")); + + m_receivedFormat = format; + return dataObj->SetData( len, buf ); +} + +// ---------------------------------------------------------------------------- +// wxTextDataObject +// ---------------------------------------------------------------------------- + +#if defined(__WXGTK20__) && wxUSE_UNICODE + +static inline wxMBConv& GetConv(const wxDataFormat& format) +{ + // use UTF8 for wxDF_UNICODETEXT and UCS4 for wxDF_TEXT + return format == wxDF_UNICODETEXT ? wxConvUTF8 : wxConvLibc; +} + +size_t wxTextDataObject::GetDataSize(const wxDataFormat& format) const +{ + wxCharBuffer buffer = GetConv(format).cWX2MB( GetText().c_str() ); + + return buffer ? strlen( buffer ) : 0; +} + +bool wxTextDataObject::GetDataHere(const wxDataFormat& format, void *buf) const +{ + if ( !buf ) + return false; + + wxCharBuffer buffer = GetConv(format).cWX2MB( GetText().c_str() ); + if ( !buffer ) + return false; + + memcpy( (char*) buf, buffer, GetDataSize(format) ); + // strcpy( (char*) buf, buffer ); + + return true; +} + +bool wxTextDataObject::SetData(const wxDataFormat& format, + size_t WXUNUSED(len), const void *buf) +{ + if ( buf == NULL ) + return false; + + wxWCharBuffer buffer = GetConv(format).cMB2WX( (const char*)buf ); + + SetText( buffer ); + + return true; +} + +#elif wxUSE_UNICODE && defined(__WXMAC__) + +static wxMBConvUTF16 sUTF16Converter; + +static inline wxMBConv& GetConv(const wxDataFormat& format) +{ + return + format == wxDF_UNICODETEXT + ? (wxMBConv&) sUTF16Converter + : (wxMBConv&) wxConvLocal; +} + +size_t wxTextDataObject::GetDataSize(const wxDataFormat& format) const +{ + wxCharBuffer buffer = GetConv(format).cWX2MB( GetText().c_str() ); + if ( !buffer ) + return 0; + + size_t len = GetConv(format).WC2MB( NULL, GetText().c_str(), 0 ); + return len; +} + +bool wxTextDataObject::GetDataHere(const wxDataFormat& format, void *buf) const +{ + if ( buf == NULL ) + return false; + + wxCharBuffer buffer = GetConv(format).cWX2MB( GetText().c_str() ); + if ( !buffer ) + return false; + + size_t len = GetConv(format).WC2MB( NULL, GetText().c_str(), 0 ); + memcpy( (char*)buf, (const char*)buffer, len ); + + return true; +} + +bool wxTextDataObject::SetData(const wxDataFormat& format, + size_t WXUNUSED(len), const void *buf) +{ + if ( buf == NULL ) + return false; + + wxWCharBuffer buffer = GetConv(format).cMB2WX( (const char*)buf ); + + SetText( buffer ); + + return true; +} + +#else + +size_t wxTextDataObject::GetDataSize() const +{ + return GetTextLength() * sizeof(wxChar); +} + +bool wxTextDataObject::GetDataHere(void *buf) const +{ + wxStrcpy( (wxChar*)buf, GetText().c_str() ); + + return true; +} + +bool wxTextDataObject::SetData(size_t WXUNUSED(len), const void *buf) +{ + SetText( wxString((const wxChar*)buf) ); + + return true; +} + +#endif + +// ---------------------------------------------------------------------------- +// wxFileDataObjectBase +// ---------------------------------------------------------------------------- + +// VZ: I don't need this in MSW finally, so if it is needed in wxGTK, it should +// be moved to gtk/dataobj.cpp +#if 0 + +wxString wxFileDataObjectBase::GetFilenames() const +{ + wxString str; + size_t count = m_filenames.GetCount(); + for ( size_t n = 0; n < count; n++ ) + { + str << m_filenames[n] << wxT('\0'); + } + + return str; +} + +void wxFileDataObjectBase::SetFilenames(const wxChar* filenames) +{ + m_filenames.Empty(); + + wxString current; + for ( const wxChar *pc = filenames; ; pc++ ) + { + if ( *pc ) + { + current += *pc; + } + else + { + if ( !current ) + { + // 2 consecutive NULs - this is the end of the string + break; + } + + m_filenames.Add(current); + current.Empty(); + } + } +} + +#endif + +// ---------------------------------------------------------------------------- +// wxCustomDataObject +// ---------------------------------------------------------------------------- + +wxCustomDataObject::wxCustomDataObject(const wxDataFormat& format) + : wxDataObjectSimple(format) +{ + m_data = NULL; + m_size = 0; +} + +wxCustomDataObject::~wxCustomDataObject() +{ + Free(); +} + +void wxCustomDataObject::TakeData(size_t size, void *data) +{ + Free(); + + m_size = size; + m_data = data; +} + +void *wxCustomDataObject::Alloc(size_t size) +{ + return (void *)new char[size]; +} + +void wxCustomDataObject::Free() +{ + delete [] (char*)m_data; + m_size = 0; + m_data = (void*)NULL; +} + +size_t wxCustomDataObject::GetDataSize() const +{ + return GetSize(); +} + +bool wxCustomDataObject::GetDataHere(void *buf) const +{ + if ( buf == NULL ) + return false; + + void *data = GetData(); + if ( data == NULL ) + return false; + + memcpy( buf, data, GetSize() ); + + return true; +} + +bool wxCustomDataObject::SetData(size_t size, const void *buf) +{ + Free(); + + m_data = Alloc(size); + if ( m_data == NULL ) + return false; + + m_size = size; + memcpy( m_data, buf, m_size ); + + return true; +} + +// ============================================================================ +// some common dnd related code +// ============================================================================ + +#if wxUSE_DRAG_AND_DROP + +#include "wx/dnd.h" + +// ---------------------------------------------------------------------------- +// wxTextDropTarget +// ---------------------------------------------------------------------------- + +// NB: we can't use "new" in ctor initializer lists because this provokes an +// internal compiler error with VC++ 5.0 (hey, even gcc compiles this!), +// so use SetDataObject() instead + +wxTextDropTarget::wxTextDropTarget() +{ + SetDataObject(new wxTextDataObject); +} + +wxDragResult wxTextDropTarget::OnData(wxCoord x, wxCoord y, wxDragResult def) +{ + if ( !GetData() ) + return wxDragNone; + + wxTextDataObject *dobj = (wxTextDataObject *)m_dataObject; + return OnDropText( x, y, dobj->GetText() ) ? def : wxDragNone; +} + +// ---------------------------------------------------------------------------- +// wxFileDropTarget +// ---------------------------------------------------------------------------- + +wxFileDropTarget::wxFileDropTarget() +{ + SetDataObject(new wxFileDataObject); +} + +wxDragResult wxFileDropTarget::OnData(wxCoord x, wxCoord y, wxDragResult def) +{ + if ( !GetData() ) + return wxDragNone; + + wxFileDataObject *dobj = (wxFileDataObject *)m_dataObject; + return OnDropFiles( x, y, dobj->GetFilenames() ) ? def : wxDragNone; +} + +#endif // wxUSE_DRAG_AND_DROP + +#endif // wxUSE_DATAOBJ diff --git a/Externals/wxWidgets/src/common/docmdi.cpp b/Externals/wxWidgets/src/common/docmdi.cpp index 250add1be9..46b10afa2a 100644 --- a/Externals/wxWidgets/src/common/docmdi.cpp +++ b/Externals/wxWidgets/src/common/docmdi.cpp @@ -1,204 +1,204 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: docmdi.cpp -// Purpose: Frame classes for MDI document/view applications -// Author: Julian Smart -// Modified by: -// Created: 01/02/97 -// RCS-ID: $Id: docmdi.cpp 35650 2005-09-23 12:56:45Z MR $ -// Copyright: (c) Julian Smart -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_MDI_ARCHITECTURE - -#include "wx/docmdi.h" - -/* - * Docview MDI parent frame - */ - -IMPLEMENT_CLASS(wxDocMDIParentFrame, wxMDIParentFrame) - -BEGIN_EVENT_TABLE(wxDocMDIParentFrame, wxMDIParentFrame) - EVT_MENU(wxID_EXIT, wxDocMDIParentFrame::OnExit) - EVT_MENU_RANGE(wxID_FILE1, wxID_FILE9, wxDocMDIParentFrame::OnMRUFile) - EVT_CLOSE(wxDocMDIParentFrame::OnCloseWindow) -END_EVENT_TABLE() - -wxDocMDIParentFrame::wxDocMDIParentFrame() -{ - Init(); -} - -wxDocMDIParentFrame::wxDocMDIParentFrame(wxDocManager *manager, wxFrame *frame, wxWindowID id, const wxString& title, - const wxPoint& pos, const wxSize& size, long style, const wxString& name) -{ - Init(); - Create(manager, frame, id, title, pos, size, style, name); -} - -bool wxDocMDIParentFrame::Create(wxDocManager *manager, wxFrame *frame, wxWindowID id, const wxString& title, - const wxPoint& pos, const wxSize& size, long style, const wxString& name) -{ - m_docManager = manager; - return wxMDIParentFrame::Create(frame, id, title, pos, size, style, name); -} - -void wxDocMDIParentFrame::OnExit(wxCommandEvent& WXUNUSED(event)) -{ - Close(); -} - -void wxDocMDIParentFrame::Init() -{ - m_docManager = NULL; -} - -void wxDocMDIParentFrame::OnMRUFile(wxCommandEvent& event) -{ - wxString f(m_docManager->GetHistoryFile(event.GetId() - wxID_FILE1)); - if (!f.empty()) - (void)m_docManager->CreateDocument(f, wxDOC_SILENT); -} - -// Extend event processing to search the view's event table -bool wxDocMDIParentFrame::ProcessEvent(wxEvent& event) -{ - // Try the document manager, then do default processing - if (!m_docManager || !m_docManager->ProcessEvent(event)) - return wxEvtHandler::ProcessEvent(event); - else - return true; -} - -void wxDocMDIParentFrame::OnCloseWindow(wxCloseEvent& event) -{ - if (m_docManager->Clear(!event.CanVeto())) - { - this->Destroy(); - } - else - event.Veto(); -} - - -/* - * Default document child frame for MDI children - */ - -IMPLEMENT_CLASS(wxDocMDIChildFrame, wxMDIChildFrame) - -BEGIN_EVENT_TABLE(wxDocMDIChildFrame, wxMDIChildFrame) - EVT_ACTIVATE(wxDocMDIChildFrame::OnActivate) - EVT_CLOSE(wxDocMDIChildFrame::OnCloseWindow) -END_EVENT_TABLE() - -void wxDocMDIChildFrame::Init() -{ - m_childDocument = (wxDocument*) NULL; - m_childView = (wxView*) NULL; -} - -wxDocMDIChildFrame::wxDocMDIChildFrame() -{ - Init(); -} - -wxDocMDIChildFrame::wxDocMDIChildFrame(wxDocument *doc, wxView *view, wxMDIParentFrame *frame, wxWindowID id, - const wxString& title, const wxPoint& pos, const wxSize& size, long style, const wxString& name) -{ - Init(); - Create(doc, view, frame, id, title, pos, size, style, name); -} - -bool wxDocMDIChildFrame::Create(wxDocument *doc, wxView *view, wxMDIParentFrame *frame, wxWindowID id, - const wxString& title, const wxPoint& pos, const wxSize& size, long style, const wxString& name) -{ - m_childDocument = doc; - m_childView = view; - if (wxMDIChildFrame::Create(frame, id, title, pos, size, style, name)) - { - if (view) - view->SetFrame(this); - return true; - } - - return false; -} - -wxDocMDIChildFrame::~wxDocMDIChildFrame(void) -{ - m_childView = (wxView *) NULL; -} - -// Extend event processing to search the view's event table -bool wxDocMDIChildFrame::ProcessEvent(wxEvent& event) -{ - static wxEvent *ActiveEvent = NULL; - - // Break recursion loops - if (ActiveEvent == &event) - return false; - - ActiveEvent = &event; - - bool ret; - if ( !m_childView || ! m_childView->ProcessEvent(event) ) - { - // Only hand up to the parent if it's a menu command - if (!event.IsKindOf(CLASSINFO(wxCommandEvent)) || !GetParent() || !GetParent()->ProcessEvent(event)) - ret = wxEvtHandler::ProcessEvent(event); - else - ret = true; - } - else - ret = true; - - ActiveEvent = NULL; - return ret; -} - -void wxDocMDIChildFrame::OnActivate(wxActivateEvent& event) -{ - wxMDIChildFrame::OnActivate(event); - - if (event.GetActive() && m_childView) - m_childView->Activate(event.GetActive()); -} - -void wxDocMDIChildFrame::OnCloseWindow(wxCloseEvent& event) -{ - // Close view but don't delete the frame while doing so! - // ...since it will be deleted by wxWidgets if we return true. - if (m_childView) - { - bool ans = event.CanVeto() - ? m_childView->Close(false) // false means don't delete associated window - : true; // Must delete. - - if (ans) - { - m_childView->Activate(false); - delete m_childView; - m_childView = (wxView *) NULL; - m_childDocument = (wxDocument *) NULL; - - this->Destroy(); - } - else - event.Veto(); - } - else - event.Veto(); -} - -#endif - // wxUSE_DOC_VIEW_ARCHITECTURE - +///////////////////////////////////////////////////////////////////////////// +// Name: docmdi.cpp +// Purpose: Frame classes for MDI document/view applications +// Author: Julian Smart +// Modified by: +// Created: 01/02/97 +// RCS-ID: $Id: docmdi.cpp 35650 2005-09-23 12:56:45Z MR $ +// Copyright: (c) Julian Smart +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_MDI_ARCHITECTURE + +#include "wx/docmdi.h" + +/* + * Docview MDI parent frame + */ + +IMPLEMENT_CLASS(wxDocMDIParentFrame, wxMDIParentFrame) + +BEGIN_EVENT_TABLE(wxDocMDIParentFrame, wxMDIParentFrame) + EVT_MENU(wxID_EXIT, wxDocMDIParentFrame::OnExit) + EVT_MENU_RANGE(wxID_FILE1, wxID_FILE9, wxDocMDIParentFrame::OnMRUFile) + EVT_CLOSE(wxDocMDIParentFrame::OnCloseWindow) +END_EVENT_TABLE() + +wxDocMDIParentFrame::wxDocMDIParentFrame() +{ + Init(); +} + +wxDocMDIParentFrame::wxDocMDIParentFrame(wxDocManager *manager, wxFrame *frame, wxWindowID id, const wxString& title, + const wxPoint& pos, const wxSize& size, long style, const wxString& name) +{ + Init(); + Create(manager, frame, id, title, pos, size, style, name); +} + +bool wxDocMDIParentFrame::Create(wxDocManager *manager, wxFrame *frame, wxWindowID id, const wxString& title, + const wxPoint& pos, const wxSize& size, long style, const wxString& name) +{ + m_docManager = manager; + return wxMDIParentFrame::Create(frame, id, title, pos, size, style, name); +} + +void wxDocMDIParentFrame::OnExit(wxCommandEvent& WXUNUSED(event)) +{ + Close(); +} + +void wxDocMDIParentFrame::Init() +{ + m_docManager = NULL; +} + +void wxDocMDIParentFrame::OnMRUFile(wxCommandEvent& event) +{ + wxString f(m_docManager->GetHistoryFile(event.GetId() - wxID_FILE1)); + if (!f.empty()) + (void)m_docManager->CreateDocument(f, wxDOC_SILENT); +} + +// Extend event processing to search the view's event table +bool wxDocMDIParentFrame::ProcessEvent(wxEvent& event) +{ + // Try the document manager, then do default processing + if (!m_docManager || !m_docManager->ProcessEvent(event)) + return wxEvtHandler::ProcessEvent(event); + else + return true; +} + +void wxDocMDIParentFrame::OnCloseWindow(wxCloseEvent& event) +{ + if (m_docManager->Clear(!event.CanVeto())) + { + this->Destroy(); + } + else + event.Veto(); +} + + +/* + * Default document child frame for MDI children + */ + +IMPLEMENT_CLASS(wxDocMDIChildFrame, wxMDIChildFrame) + +BEGIN_EVENT_TABLE(wxDocMDIChildFrame, wxMDIChildFrame) + EVT_ACTIVATE(wxDocMDIChildFrame::OnActivate) + EVT_CLOSE(wxDocMDIChildFrame::OnCloseWindow) +END_EVENT_TABLE() + +void wxDocMDIChildFrame::Init() +{ + m_childDocument = (wxDocument*) NULL; + m_childView = (wxView*) NULL; +} + +wxDocMDIChildFrame::wxDocMDIChildFrame() +{ + Init(); +} + +wxDocMDIChildFrame::wxDocMDIChildFrame(wxDocument *doc, wxView *view, wxMDIParentFrame *frame, wxWindowID id, + const wxString& title, const wxPoint& pos, const wxSize& size, long style, const wxString& name) +{ + Init(); + Create(doc, view, frame, id, title, pos, size, style, name); +} + +bool wxDocMDIChildFrame::Create(wxDocument *doc, wxView *view, wxMDIParentFrame *frame, wxWindowID id, + const wxString& title, const wxPoint& pos, const wxSize& size, long style, const wxString& name) +{ + m_childDocument = doc; + m_childView = view; + if (wxMDIChildFrame::Create(frame, id, title, pos, size, style, name)) + { + if (view) + view->SetFrame(this); + return true; + } + + return false; +} + +wxDocMDIChildFrame::~wxDocMDIChildFrame(void) +{ + m_childView = (wxView *) NULL; +} + +// Extend event processing to search the view's event table +bool wxDocMDIChildFrame::ProcessEvent(wxEvent& event) +{ + static wxEvent *ActiveEvent = NULL; + + // Break recursion loops + if (ActiveEvent == &event) + return false; + + ActiveEvent = &event; + + bool ret; + if ( !m_childView || ! m_childView->ProcessEvent(event) ) + { + // Only hand up to the parent if it's a menu command + if (!event.IsKindOf(CLASSINFO(wxCommandEvent)) || !GetParent() || !GetParent()->ProcessEvent(event)) + ret = wxEvtHandler::ProcessEvent(event); + else + ret = true; + } + else + ret = true; + + ActiveEvent = NULL; + return ret; +} + +void wxDocMDIChildFrame::OnActivate(wxActivateEvent& event) +{ + wxMDIChildFrame::OnActivate(event); + + if (event.GetActive() && m_childView) + m_childView->Activate(event.GetActive()); +} + +void wxDocMDIChildFrame::OnCloseWindow(wxCloseEvent& event) +{ + // Close view but don't delete the frame while doing so! + // ...since it will be deleted by wxWidgets if we return true. + if (m_childView) + { + bool ans = event.CanVeto() + ? m_childView->Close(false) // false means don't delete associated window + : true; // Must delete. + + if (ans) + { + m_childView->Activate(false); + delete m_childView; + m_childView = (wxView *) NULL; + m_childDocument = (wxDocument *) NULL; + + this->Destroy(); + } + else + event.Veto(); + } + else + event.Veto(); +} + +#endif + // wxUSE_DOC_VIEW_ARCHITECTURE + diff --git a/Externals/wxWidgets/src/common/docview.cpp b/Externals/wxWidgets/src/common/docview.cpp index 1268ce52fd..5e24c82642 100644 --- a/Externals/wxWidgets/src/common/docview.cpp +++ b/Externals/wxWidgets/src/common/docview.cpp @@ -1,2485 +1,2485 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/docview.cpp -// Purpose: Document/view classes -// Author: Julian Smart -// Modified by: -// Created: 01/02/97 -// RCS-ID: $Id: docview.cpp 51392 2008-01-26 23:23:09Z VZ $ -// Copyright: (c) Julian Smart -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_DOC_VIEW_ARCHITECTURE - -#include "wx/docview.h" - -#ifndef WX_PRECOMP - #include "wx/list.h" - #include "wx/string.h" - #include "wx/utils.h" - #include "wx/app.h" - #include "wx/dc.h" - #include "wx/dialog.h" - #include "wx/menu.h" - #include "wx/filedlg.h" - #include "wx/intl.h" - #include "wx/log.h" - #include "wx/msgdlg.h" - #include "wx/mdi.h" - #include "wx/choicdlg.h" -#endif - -#include "wx/ffile.h" - -#ifdef __WXMAC__ - #include "wx/filename.h" -#endif - -#if wxUSE_PRINTING_ARCHITECTURE - #include "wx/prntbase.h" - #include "wx/printdlg.h" -#endif - -#include "wx/confbase.h" -#include "wx/file.h" -#include "wx/cmdproc.h" -#include "wx/tokenzr.h" - -#include -#include - -#if wxUSE_STD_IOSTREAM - #include "wx/ioswrap.h" - #if wxUSE_IOSTREAMH - #include - #else - #include - #endif -#else - #include "wx/wfstream.h" -#endif - -// ---------------------------------------------------------------------------- -// wxWidgets macros -// ---------------------------------------------------------------------------- - -IMPLEMENT_ABSTRACT_CLASS(wxDocument, wxEvtHandler) -IMPLEMENT_ABSTRACT_CLASS(wxView, wxEvtHandler) -IMPLEMENT_ABSTRACT_CLASS(wxDocTemplate, wxObject) -IMPLEMENT_DYNAMIC_CLASS(wxDocManager, wxEvtHandler) -IMPLEMENT_CLASS(wxDocChildFrame, wxFrame) -IMPLEMENT_CLASS(wxDocParentFrame, wxFrame) - -#if wxUSE_PRINTING_ARCHITECTURE - IMPLEMENT_DYNAMIC_CLASS(wxDocPrintout, wxPrintout) -#endif - -IMPLEMENT_DYNAMIC_CLASS(wxFileHistory, wxObject) - -// ---------------------------------------------------------------------------- -// function prototypes -// ---------------------------------------------------------------------------- - -static wxWindow* wxFindSuitableParent(void); - -// ---------------------------------------------------------------------------- -// local constants -// ---------------------------------------------------------------------------- - -static const wxChar *s_MRUEntryFormat = wxT("&%d %s"); - -// ============================================================================ -// implementation -// ============================================================================ - -// ---------------------------------------------------------------------------- -// local functions -// ---------------------------------------------------------------------------- - -static wxString FindExtension(const wxChar *path) -{ - wxString ext; - wxSplitPath(path, NULL, NULL, &ext); - - // VZ: extensions are considered not case sensitive - is this really a good - // idea? - return ext.MakeLower(); -} - -// ---------------------------------------------------------------------------- -// Definition of wxDocument -// ---------------------------------------------------------------------------- - -wxDocument::wxDocument(wxDocument *parent) -{ - m_documentModified = false; - m_documentParent = parent; - m_documentTemplate = (wxDocTemplate *) NULL; - m_commandProcessor = (wxCommandProcessor*) NULL; - m_savedYet = false; -} - -bool wxDocument::DeleteContents() -{ - return true; -} - -wxDocument::~wxDocument() -{ - DeleteContents(); - - if (m_commandProcessor) - delete m_commandProcessor; - - if (GetDocumentManager()) - GetDocumentManager()->RemoveDocument(this); - - // Not safe to do here, since it'll invoke virtual view functions - // expecting to see valid derived objects: and by the time we get here, - // we've called destructors higher up. - //DeleteAllViews(); -} - -bool wxDocument::Close() -{ - if (OnSaveModified()) - return OnCloseDocument(); - else - return false; -} - -bool wxDocument::OnCloseDocument() -{ - // Tell all views that we're about to close - NotifyClosing(); - DeleteContents(); - Modify(false); - return true; -} - -// Note that this implicitly deletes the document when the last view is -// deleted. -bool wxDocument::DeleteAllViews() -{ - wxDocManager* manager = GetDocumentManager(); - - // first check if all views agree to be closed - const wxList::iterator end = m_documentViews.end(); - for ( wxList::iterator i = m_documentViews.begin(); i != end; ++i ) - { - wxView *view = (wxView *)*i; - if ( !view->Close() ) - return false; - } - - // all views agreed to close, now do close them - if ( m_documentViews.empty() ) - { - // normally the document would be implicitly deleted when the last view - // is, but if don't have any views, do it here instead - if ( manager && manager->GetDocuments().Member(this) ) - delete this; - } - else // have views - { - // as we delete elements we iterate over, don't use the usual "from - // begin to end" loop - for ( ;; ) - { - wxView *view = (wxView *)*m_documentViews.begin(); - - bool isLastOne = m_documentViews.size() == 1; - - // this always deletes the node implicitly and if this is the last - // view also deletes this object itself (also implicitly, great), - // so we can't test for m_documentViews.empty() after calling this! - delete view; - - if ( isLastOne ) - break; - } - } - - return true; -} - -wxView *wxDocument::GetFirstView() const -{ - if (m_documentViews.GetCount() == 0) - return (wxView *) NULL; - return (wxView *)m_documentViews.GetFirst()->GetData(); -} - -wxDocManager *wxDocument::GetDocumentManager() const -{ - return (m_documentTemplate ? m_documentTemplate->GetDocumentManager() : (wxDocManager*) NULL); -} - -bool wxDocument::OnNewDocument() -{ - if (!OnSaveModified()) - return false; - - if (OnCloseDocument()==false) return false; - DeleteContents(); - Modify(false); - SetDocumentSaved(false); - - wxString name; - GetDocumentManager()->MakeDefaultName(name); - SetTitle(name); - SetFilename(name, true); - - return true; -} - -bool wxDocument::Save() -{ - if (!IsModified() && m_savedYet) - return true; - - if ( m_documentFile.empty() || !m_savedYet ) - return SaveAs(); - - return OnSaveDocument(m_documentFile); -} - -bool wxDocument::SaveAs() -{ - wxDocTemplate *docTemplate = GetDocumentTemplate(); - if (!docTemplate) - return false; - -#if defined(__WXMSW__) || defined(__WXGTK__) || defined(__WXMAC__) - wxString filter = docTemplate->GetDescription() + wxT(" (") + docTemplate->GetFileFilter() + wxT(")|") + docTemplate->GetFileFilter(); - - // Now see if there are some other template with identical view and document - // classes, whose filters may also be used. - - if (docTemplate->GetViewClassInfo() && docTemplate->GetDocClassInfo()) - { - wxList::compatibility_iterator node = docTemplate->GetDocumentManager()->GetTemplates().GetFirst(); - while (node) - { - wxDocTemplate *t = (wxDocTemplate*) node->GetData(); - - if (t->IsVisible() && t != docTemplate && - t->GetViewClassInfo() == docTemplate->GetViewClassInfo() && - t->GetDocClassInfo() == docTemplate->GetDocClassInfo()) - { - // add a '|' to separate this filter from the previous one - if ( !filter.empty() ) - filter << wxT('|'); - - filter << t->GetDescription() << wxT(" (") << t->GetFileFilter() << wxT(") |") - << t->GetFileFilter(); - } - - node = node->GetNext(); - } - } -#else - wxString filter = docTemplate->GetFileFilter() ; -#endif - wxString defaultDir = docTemplate->GetDirectory(); - if (defaultDir.IsEmpty()) - defaultDir = wxPathOnly(GetFilename()); - - wxString tmp = wxFileSelector(_("Save as"), - defaultDir, - wxFileNameFromPath(GetFilename()), - docTemplate->GetDefaultExtension(), - filter, - wxFD_SAVE | wxFD_OVERWRITE_PROMPT, - GetDocumentWindow()); - - if (tmp.empty()) - return false; - - wxString fileName(tmp); - wxString path, name, ext; - wxSplitPath(fileName, & path, & name, & ext); - - if (ext.empty()) - { - fileName += wxT("."); - fileName += docTemplate->GetDefaultExtension(); - } - - SetFilename(fileName); - SetTitle(wxFileNameFromPath(fileName)); - - // Notify the views that the filename has changed - wxList::compatibility_iterator node = m_documentViews.GetFirst(); - while (node) - { - wxView *view = (wxView *)node->GetData(); - view->OnChangeFilename(); - node = node->GetNext(); - } - - // Files that were not saved correctly are not added to the FileHistory. - if (!OnSaveDocument(m_documentFile)) - return false; - - // A file that doesn't use the default extension of its document template cannot be opened - // via the FileHistory, so we do not add it. - if (docTemplate->FileMatchesTemplate(fileName)) - { - GetDocumentManager()->AddFileToHistory(fileName); - } - else - { - // The user will probably not be able to open the file again, so - // we could warn about the wrong file-extension here. - } - return true; -} - -bool wxDocument::OnSaveDocument(const wxString& file) -{ - if ( !file ) - return false; - - if ( !DoSaveDocument(file) ) - return false; - - Modify(false); - SetFilename(file); - SetDocumentSaved(true); -#ifdef __WXMAC__ - wxFileName fn(file) ; - fn.MacSetDefaultTypeAndCreator() ; -#endif - return true; -} - -bool wxDocument::OnOpenDocument(const wxString& file) -{ - if (!OnSaveModified()) - return false; - - if ( !DoOpenDocument(file) ) - return false; - - SetFilename(file, true); - Modify(false); - m_savedYet = true; - - UpdateAllViews(); - - return true; -} - -#if wxUSE_STD_IOSTREAM -wxSTD istream& wxDocument::LoadObject(wxSTD istream& stream) -#else -wxInputStream& wxDocument::LoadObject(wxInputStream& stream) -#endif -{ - return stream; -} - -#if wxUSE_STD_IOSTREAM -wxSTD ostream& wxDocument::SaveObject(wxSTD ostream& stream) -#else -wxOutputStream& wxDocument::SaveObject(wxOutputStream& stream) -#endif -{ - return stream; -} - -bool wxDocument::Revert() -{ - return false; -} - - -// Get title, or filename if no title, else unnamed -bool wxDocument::GetPrintableName(wxString& buf) const -{ - if (!m_documentTitle.empty()) - { - buf = m_documentTitle; - return true; - } - else if (!m_documentFile.empty()) - { - buf = wxFileNameFromPath(m_documentFile); - return true; - } - else - { - buf = _("unnamed"); - return true; - } -} - -wxWindow *wxDocument::GetDocumentWindow() const -{ - wxView *view = GetFirstView(); - if (view) - return view->GetFrame(); - else - return wxTheApp->GetTopWindow(); -} - -wxCommandProcessor *wxDocument::OnCreateCommandProcessor() -{ - return new wxCommandProcessor; -} - -// true if safe to close -bool wxDocument::OnSaveModified() -{ - if (IsModified()) - { - wxString title; - GetPrintableName(title); - - wxString msgTitle; - if (!wxTheApp->GetAppName().empty()) - msgTitle = wxTheApp->GetAppName(); - else - msgTitle = wxString(_("Warning")); - - wxString prompt; - prompt.Printf(_("Do you want to save changes to document %s?"), - (const wxChar *)title); - int res = wxMessageBox(prompt, msgTitle, - wxYES_NO|wxCANCEL|wxICON_QUESTION, - GetDocumentWindow()); - if (res == wxNO) - { - Modify(false); - return true; - } - else if (res == wxYES) - return Save(); - else if (res == wxCANCEL) - return false; - } - return true; -} - -bool wxDocument::Draw(wxDC& WXUNUSED(context)) -{ - return true; -} - -bool wxDocument::AddView(wxView *view) -{ - if (!m_documentViews.Member(view)) - { - m_documentViews.Append(view); - OnChangedViewList(); - } - return true; -} - -bool wxDocument::RemoveView(wxView *view) -{ - (void)m_documentViews.DeleteObject(view); - OnChangedViewList(); - return true; -} - -bool wxDocument::OnCreate(const wxString& WXUNUSED(path), long flags) -{ - if (GetDocumentTemplate()->CreateView(this, flags)) - return true; - else - return false; -} - -// Called after a view is added or removed. -// The default implementation deletes the document if -// there are no more views. -void wxDocument::OnChangedViewList() -{ - if (m_documentViews.GetCount() == 0) - { - if (OnSaveModified()) - { - delete this; - } - } -} - -void wxDocument::UpdateAllViews(wxView *sender, wxObject *hint) -{ - wxList::compatibility_iterator node = m_documentViews.GetFirst(); - while (node) - { - wxView *view = (wxView *)node->GetData(); - if (view != sender) - view->OnUpdate(sender, hint); - node = node->GetNext(); - } -} - -void wxDocument::NotifyClosing() -{ - wxList::compatibility_iterator node = m_documentViews.GetFirst(); - while (node) - { - wxView *view = (wxView *)node->GetData(); - view->OnClosingDocument(); - node = node->GetNext(); - } -} - -void wxDocument::SetFilename(const wxString& filename, bool notifyViews) -{ - m_documentFile = filename; - if ( notifyViews ) - { - // Notify the views that the filename has changed - wxList::compatibility_iterator node = m_documentViews.GetFirst(); - while (node) - { - wxView *view = (wxView *)node->GetData(); - view->OnChangeFilename(); - node = node->GetNext(); - } - } -} - -bool wxDocument::DoSaveDocument(const wxString& file) -{ - wxString msgTitle; - if (!wxTheApp->GetAppName().empty()) - msgTitle = wxTheApp->GetAppName(); - else - msgTitle = wxString(_("File error")); - -#if wxUSE_STD_IOSTREAM - wxSTD ofstream store(file.mb_str(), wxSTD ios::binary); - if (store.fail() || store.bad()) -#else - wxFileOutputStream store(file); - if (store.GetLastError() != wxSTREAM_NO_ERROR) -#endif - { - (void)wxMessageBox(_("Sorry, could not open this file for saving."), msgTitle, wxOK | wxICON_EXCLAMATION, - GetDocumentWindow()); - // Saving error - return false; - } - if (!SaveObject(store)) - { - (void)wxMessageBox(_("Sorry, could not save this file."), msgTitle, wxOK | wxICON_EXCLAMATION, - GetDocumentWindow()); - // Saving error - return false; - } - - return true; -} - -bool wxDocument::DoOpenDocument(const wxString& file) -{ -#if wxUSE_STD_IOSTREAM - wxSTD ifstream store(file.mb_str(), wxSTD ios::binary); - if (!store.fail() && !store.bad()) -#else - wxFileInputStream store(file); - if (store.GetLastError() == wxSTREAM_NO_ERROR) -#endif - { -#if wxUSE_STD_IOSTREAM - LoadObject(store); - if ( !!store || store.eof() ) -#else - int res = LoadObject(store).GetLastError(); - if ( res == wxSTREAM_NO_ERROR || res == wxSTREAM_EOF ) -#endif - return true; - } - - wxLogError(_("Sorry, could not open this file.")); - return false; -} - - -// ---------------------------------------------------------------------------- -// Document view -// ---------------------------------------------------------------------------- - -wxView::wxView() -{ - m_viewDocument = (wxDocument*) NULL; - - m_viewFrame = (wxFrame *) NULL; -} - -wxView::~wxView() -{ - GetDocumentManager()->ActivateView(this, false); - m_viewDocument->RemoveView(this); -} - -// Extend event processing to search the document's event table -bool wxView::ProcessEvent(wxEvent& event) -{ - if ( !GetDocument() || !GetDocument()->ProcessEvent(event) ) - return wxEvtHandler::ProcessEvent(event); - - return true; -} - -void wxView::OnActivateView(bool WXUNUSED(activate), wxView *WXUNUSED(activeView), wxView *WXUNUSED(deactiveView)) -{ -} - -void wxView::OnPrint(wxDC *dc, wxObject *WXUNUSED(info)) -{ - OnDraw(dc); -} - -void wxView::OnUpdate(wxView *WXUNUSED(sender), wxObject *WXUNUSED(hint)) -{ -} - -void wxView::OnChangeFilename() -{ - // GetFrame can return wxWindow rather than wxTopLevelWindow due to - // generic MDI implementation so use SetLabel rather than SetTitle. - // It should cause SetTitle() for top level windows. - wxWindow *win = GetFrame(); - if (!win) return; - - wxDocument *doc = GetDocument(); - if (!doc) return; - - wxString name; - doc->GetPrintableName(name); - win->SetLabel(name); -} - -void wxView::SetDocument(wxDocument *doc) -{ - m_viewDocument = doc; - if (doc) - doc->AddView(this); -} - -bool wxView::Close(bool deleteWindow) -{ - if (OnClose(deleteWindow)) - return true; - else - return false; -} - -void wxView::Activate(bool activate) -{ - if (GetDocument() && GetDocumentManager()) - { - OnActivateView(activate, this, GetDocumentManager()->GetCurrentView()); - GetDocumentManager()->ActivateView(this, activate); - } -} - -bool wxView::OnClose(bool WXUNUSED(deleteWindow)) -{ - return GetDocument() ? GetDocument()->Close() : true; -} - -#if wxUSE_PRINTING_ARCHITECTURE -wxPrintout *wxView::OnCreatePrintout() -{ - return new wxDocPrintout(this); -} -#endif // wxUSE_PRINTING_ARCHITECTURE - -// ---------------------------------------------------------------------------- -// wxDocTemplate -// ---------------------------------------------------------------------------- - -wxDocTemplate::wxDocTemplate(wxDocManager *manager, - const wxString& descr, - const wxString& filter, - const wxString& dir, - const wxString& ext, - const wxString& docTypeName, - const wxString& viewTypeName, - wxClassInfo *docClassInfo, - wxClassInfo *viewClassInfo, - long flags) -{ - m_documentManager = manager; - m_description = descr; - m_directory = dir; - m_defaultExt = ext; - m_fileFilter = filter; - m_flags = flags; - m_docTypeName = docTypeName; - m_viewTypeName = viewTypeName; - m_documentManager->AssociateTemplate(this); - - m_docClassInfo = docClassInfo; - m_viewClassInfo = viewClassInfo; -} - -wxDocTemplate::~wxDocTemplate() -{ - m_documentManager->DisassociateTemplate(this); -} - -// Tries to dynamically construct an object of the right class. -wxDocument *wxDocTemplate::CreateDocument(const wxString& path, long flags) -{ - wxDocument *doc = DoCreateDocument(); - if ( doc == NULL ) - return (wxDocument *) NULL; - - if (InitDocument(doc, path, flags)) - { - return doc; - } - else - { - return (wxDocument *) NULL; - } -} - -bool wxDocTemplate::InitDocument(wxDocument* doc, const wxString& path, long flags) -{ - doc->SetFilename(path); - doc->SetDocumentTemplate(this); - GetDocumentManager()->AddDocument(doc); - doc->SetCommandProcessor(doc->OnCreateCommandProcessor()); - - if (doc->OnCreate(path, flags)) - return true; - else - { - if (GetDocumentManager()->GetDocuments().Member(doc)) - doc->DeleteAllViews(); - return false; - } -} - -wxView *wxDocTemplate::CreateView(wxDocument *doc, long flags) -{ - wxView *view = DoCreateView(); - if ( view == NULL ) - return (wxView *) NULL; - - view->SetDocument(doc); - if (view->OnCreate(doc, flags)) - { - return view; - } - else - { - delete view; - return (wxView *) NULL; - } -} - -// The default (very primitive) format detection: check is the extension is -// that of the template -bool wxDocTemplate::FileMatchesTemplate(const wxString& path) -{ - wxStringTokenizer parser (GetFileFilter(), wxT(";")); - wxString anything = wxT ("*"); - while (parser.HasMoreTokens()) - { - wxString filter = parser.GetNextToken(); - wxString filterExt = FindExtension (filter); - if ( filter.IsSameAs (anything) || - filterExt.IsSameAs (anything) || - filterExt.IsSameAs (FindExtension (path)) ) - return true; - } - return GetDefaultExtension().IsSameAs(FindExtension(path)); -} - -wxDocument *wxDocTemplate::DoCreateDocument() -{ - if (!m_docClassInfo) - return (wxDocument *) NULL; - - return (wxDocument *)m_docClassInfo->CreateObject(); -} - -wxView *wxDocTemplate::DoCreateView() -{ - if (!m_viewClassInfo) - return (wxView *) NULL; - - return (wxView *)m_viewClassInfo->CreateObject(); -} - -// ---------------------------------------------------------------------------- -// wxDocManager -// ---------------------------------------------------------------------------- - -BEGIN_EVENT_TABLE(wxDocManager, wxEvtHandler) - EVT_MENU(wxID_OPEN, wxDocManager::OnFileOpen) - EVT_MENU(wxID_CLOSE, wxDocManager::OnFileClose) - EVT_MENU(wxID_CLOSE_ALL, wxDocManager::OnFileCloseAll) - EVT_MENU(wxID_REVERT, wxDocManager::OnFileRevert) - EVT_MENU(wxID_NEW, wxDocManager::OnFileNew) - EVT_MENU(wxID_SAVE, wxDocManager::OnFileSave) - EVT_MENU(wxID_SAVEAS, wxDocManager::OnFileSaveAs) - EVT_MENU(wxID_UNDO, wxDocManager::OnUndo) - EVT_MENU(wxID_REDO, wxDocManager::OnRedo) - - EVT_UPDATE_UI(wxID_OPEN, wxDocManager::OnUpdateFileOpen) - EVT_UPDATE_UI(wxID_CLOSE, wxDocManager::OnUpdateFileClose) - EVT_UPDATE_UI(wxID_CLOSE_ALL, wxDocManager::OnUpdateFileClose) - EVT_UPDATE_UI(wxID_REVERT, wxDocManager::OnUpdateFileRevert) - EVT_UPDATE_UI(wxID_NEW, wxDocManager::OnUpdateFileNew) - EVT_UPDATE_UI(wxID_SAVE, wxDocManager::OnUpdateFileSave) - EVT_UPDATE_UI(wxID_SAVEAS, wxDocManager::OnUpdateFileSaveAs) - EVT_UPDATE_UI(wxID_UNDO, wxDocManager::OnUpdateUndo) - EVT_UPDATE_UI(wxID_REDO, wxDocManager::OnUpdateRedo) - -#if wxUSE_PRINTING_ARCHITECTURE - EVT_MENU(wxID_PRINT, wxDocManager::OnPrint) - EVT_MENU(wxID_PREVIEW, wxDocManager::OnPreview) - - EVT_UPDATE_UI(wxID_PRINT, wxDocManager::OnUpdatePrint) - EVT_UPDATE_UI(wxID_PREVIEW, wxDocManager::OnUpdatePreview) -#endif -END_EVENT_TABLE() - -wxDocManager* wxDocManager::sm_docManager = (wxDocManager*) NULL; - -wxDocManager::wxDocManager(long flags, bool initialize) -{ - m_defaultDocumentNameCounter = 1; - m_flags = flags; - m_currentView = (wxView *) NULL; - m_maxDocsOpen = 10000; - m_fileHistory = (wxFileHistory *) NULL; - if (initialize) - Initialize(); - sm_docManager = this; -} - -wxDocManager::~wxDocManager() -{ - Clear(); - if (m_fileHistory) - delete m_fileHistory; - sm_docManager = (wxDocManager*) NULL; -} - -// closes the specified document -bool wxDocManager::CloseDocument(wxDocument* doc, bool force) -{ - if (doc->Close() || force) - { - // Implicitly deletes the document when - // the last view is deleted - doc->DeleteAllViews(); - - // Check we're really deleted - if (m_docs.Member(doc)) - delete doc; - - return true; - } - return false; -} - -bool wxDocManager::CloseDocuments(bool force) -{ - wxList::compatibility_iterator node = m_docs.GetFirst(); - while (node) - { - wxDocument *doc = (wxDocument *)node->GetData(); - wxList::compatibility_iterator next = node->GetNext(); - - if (!CloseDocument(doc, force)) - return false; - - // This assumes that documents are not connected in - // any way, i.e. deleting one document does NOT - // delete another. - node = next; - } - return true; -} - -bool wxDocManager::Clear(bool force) -{ - if (!CloseDocuments(force)) - return false; - - m_currentView = NULL; - - wxList::compatibility_iterator node = m_templates.GetFirst(); - while (node) - { - wxDocTemplate *templ = (wxDocTemplate*) node->GetData(); - wxList::compatibility_iterator next = node->GetNext(); - delete templ; - node = next; - } - return true; -} - -bool wxDocManager::Initialize() -{ - m_fileHistory = OnCreateFileHistory(); - return true; -} - -wxFileHistory *wxDocManager::OnCreateFileHistory() -{ - return new wxFileHistory; -} - -void wxDocManager::OnFileClose(wxCommandEvent& WXUNUSED(event)) -{ - wxDocument *doc = GetCurrentDocument(); - if (!doc) - return; - if (doc->Close()) - { - doc->DeleteAllViews(); - if (m_docs.Member(doc)) - delete doc; - } -} - -void wxDocManager::OnFileCloseAll(wxCommandEvent& WXUNUSED(event)) -{ - CloseDocuments(false); -} - -void wxDocManager::OnFileNew(wxCommandEvent& WXUNUSED(event)) -{ - CreateDocument( wxEmptyString, wxDOC_NEW ); -} - -void wxDocManager::OnFileOpen(wxCommandEvent& WXUNUSED(event)) -{ - if ( !CreateDocument( wxEmptyString, 0) ) - { - OnOpenFileFailure(); - } -} - -void wxDocManager::OnFileRevert(wxCommandEvent& WXUNUSED(event)) -{ - wxDocument *doc = GetCurrentDocument(); - if (!doc) - return; - doc->Revert(); -} - -void wxDocManager::OnFileSave(wxCommandEvent& WXUNUSED(event)) -{ - wxDocument *doc = GetCurrentDocument(); - if (!doc) - return; - doc->Save(); -} - -void wxDocManager::OnFileSaveAs(wxCommandEvent& WXUNUSED(event)) -{ - wxDocument *doc = GetCurrentDocument(); - if (!doc) - return; - doc->SaveAs(); -} - -void wxDocManager::OnPrint(wxCommandEvent& WXUNUSED(event)) -{ -#if wxUSE_PRINTING_ARCHITECTURE - wxView *view = GetCurrentView(); - if (!view) - return; - - wxPrintout *printout = view->OnCreatePrintout(); - if (printout) - { - wxPrinter printer; - printer.Print(view->GetFrame(), printout, true); - - delete printout; - } -#endif // wxUSE_PRINTING_ARCHITECTURE -} - -void wxDocManager::OnPreview(wxCommandEvent& WXUNUSED(event)) -{ -#if wxUSE_PRINTING_ARCHITECTURE - wxView *view = GetCurrentView(); - if (!view) - return; - - wxPrintout *printout = view->OnCreatePrintout(); - if (printout) - { - // Pass two printout objects: for preview, and possible printing. - wxPrintPreviewBase *preview = new wxPrintPreview(printout, view->OnCreatePrintout()); - if ( !preview->Ok() ) - { - delete preview; - wxMessageBox( _("Sorry, print preview needs a printer to be installed.") ); - return; - } - - wxPreviewFrame *frame = new wxPreviewFrame(preview, (wxFrame *)wxTheApp->GetTopWindow(), _("Print Preview"), - wxPoint(100, 100), wxSize(600, 650)); - frame->Centre(wxBOTH); - frame->Initialize(); - frame->Show(true); - } -#endif // wxUSE_PRINTING_ARCHITECTURE -} - -void wxDocManager::OnUndo(wxCommandEvent& event) -{ - wxDocument *doc = GetCurrentDocument(); - if (!doc) - return; - if (doc->GetCommandProcessor()) - doc->GetCommandProcessor()->Undo(); - else - event.Skip(); -} - -void wxDocManager::OnRedo(wxCommandEvent& event) -{ - wxDocument *doc = GetCurrentDocument(); - if (!doc) - return; - if (doc->GetCommandProcessor()) - doc->GetCommandProcessor()->Redo(); - else - event.Skip(); -} - -// Handlers for UI update commands - -void wxDocManager::OnUpdateFileOpen(wxUpdateUIEvent& event) -{ - event.Enable( true ); -} - -void wxDocManager::OnUpdateFileClose(wxUpdateUIEvent& event) -{ - wxDocument *doc = GetCurrentDocument(); - event.Enable( (doc != (wxDocument*) NULL) ); -} - -void wxDocManager::OnUpdateFileRevert(wxUpdateUIEvent& event) -{ - wxDocument *doc = GetCurrentDocument(); - event.Enable( (doc != (wxDocument*) NULL) ); -} - -void wxDocManager::OnUpdateFileNew(wxUpdateUIEvent& event) -{ - event.Enable( true ); -} - -void wxDocManager::OnUpdateFileSave(wxUpdateUIEvent& event) -{ - wxDocument *doc = GetCurrentDocument(); - event.Enable( doc && doc->IsModified() ); -} - -void wxDocManager::OnUpdateFileSaveAs(wxUpdateUIEvent& event) -{ - wxDocument *doc = GetCurrentDocument(); - event.Enable( (doc != (wxDocument*) NULL) ); -} - -void wxDocManager::OnUpdateUndo(wxUpdateUIEvent& event) -{ - wxDocument *doc = GetCurrentDocument(); - if (!doc) - event.Enable(false); - else if (!doc->GetCommandProcessor()) - event.Skip(); - else - { - event.Enable( doc->GetCommandProcessor()->CanUndo() ); - doc->GetCommandProcessor()->SetMenuStrings(); - } -} - -void wxDocManager::OnUpdateRedo(wxUpdateUIEvent& event) -{ - wxDocument *doc = GetCurrentDocument(); - if (!doc) - event.Enable(false); - else if (!doc->GetCommandProcessor()) - event.Skip(); - else - { - event.Enable( doc->GetCommandProcessor()->CanRedo() ); - doc->GetCommandProcessor()->SetMenuStrings(); - } -} - -void wxDocManager::OnUpdatePrint(wxUpdateUIEvent& event) -{ - wxDocument *doc = GetCurrentDocument(); - event.Enable( (doc != (wxDocument*) NULL) ); -} - -void wxDocManager::OnUpdatePreview(wxUpdateUIEvent& event) -{ - wxDocument *doc = GetCurrentDocument(); - event.Enable( (doc != (wxDocument*) NULL) ); -} - -wxView *wxDocManager::GetCurrentView() const -{ - if (m_currentView) - return m_currentView; - if (m_docs.GetCount() == 1) - { - wxDocument* doc = (wxDocument*) m_docs.GetFirst()->GetData(); - return doc->GetFirstView(); - } - return (wxView *) NULL; -} - -// Extend event processing to search the view's event table -bool wxDocManager::ProcessEvent(wxEvent& event) -{ - wxView* view = GetCurrentView(); - if (view) - { - if (view->ProcessEvent(event)) - return true; - } - return wxEvtHandler::ProcessEvent(event); -} - -wxDocument *wxDocManager::CreateDocument(const wxString& path, long flags) -{ - wxDocTemplate **templates = new wxDocTemplate *[m_templates.GetCount()]; - int n = 0; - - for (size_t i = 0; i < m_templates.GetCount(); i++) - { - wxDocTemplate *temp = (wxDocTemplate *)(m_templates.Item(i)->GetData()); - if (temp->IsVisible()) - { - templates[n] = temp; - n ++; - } - } - if (n == 0) - { - delete[] templates; - return (wxDocument *) NULL; - } - - wxDocument* docToClose = NULL; - - // If we've reached the max number of docs, close the - // first one. - if ( (int)GetDocuments().GetCount() >= m_maxDocsOpen ) - { - wxDocument *doc = (wxDocument *)GetDocuments().GetFirst()->GetData(); - docToClose = doc; - } - - // New document: user chooses a template, unless there's only one. - if (flags & wxDOC_NEW) - { - if (n == 1) - { - if (docToClose) - { - if (!CloseDocument(docToClose, false)) - { - delete[] templates; - return NULL; - } - } - - wxDocTemplate *temp = templates[0]; - delete[] templates; - wxDocument *newDoc = temp->CreateDocument(path, flags); - - if (newDoc) - { - newDoc->SetDocumentName(temp->GetDocumentName()); - newDoc->SetDocumentTemplate(temp); - if (!newDoc->OnNewDocument() ) - { - // Document is implicitly deleted by DeleteAllViews - newDoc->DeleteAllViews(); - return NULL; - } - } - return newDoc; - } - - wxDocTemplate *temp = SelectDocumentType(templates, n); - delete[] templates; - if (temp) - { - if (docToClose) - { - if (!CloseDocument(docToClose, false)) - { - return NULL; - } - } - - wxDocument *newDoc = temp->CreateDocument(path, flags); - - if (newDoc) - { - newDoc->SetDocumentName(temp->GetDocumentName()); - newDoc->SetDocumentTemplate(temp); - if (!newDoc->OnNewDocument() ) - { - // Document is implicitly deleted by DeleteAllViews - newDoc->DeleteAllViews(); - return NULL; - } - } - return newDoc; - } - else - return (wxDocument *) NULL; - } - - // Existing document - wxDocTemplate *temp; - - wxString path2 = path; - - if (flags & wxDOC_SILENT) - { - temp = FindTemplateForPath(path2); - if (!temp) - { - // Since we do not add files with non-default extensions to the FileHistory this - // can only happen if the application changes the allowed templates in runtime. - (void)wxMessageBox(_("Sorry, the format for this file is unknown."), - _("Open File"), - wxOK | wxICON_EXCLAMATION, wxFindSuitableParent()); - } - } - else - temp = SelectDocumentPath(templates, n, path2, flags); - - delete[] templates; - - if (temp) - { - if (docToClose) - { - if (!CloseDocument(docToClose, false)) - { - return NULL; - } - } - - //see if this file is already open - for (size_t i = 0; i < GetDocuments().GetCount(); ++i) - { - wxDocument* currentDoc = (wxDocument*)(GetDocuments().Item(i)->GetData()); -#ifdef __WXMSW__ - //file paths are case-insensitive on Windows - if (path2.CmpNoCase(currentDoc->GetFilename()) == 0) -#else - if (path2.Cmp(currentDoc->GetFilename()) == 0) -#endif - { - //file already open. Just activate it and return - if (currentDoc->GetFirstView()) - { - ActivateView(currentDoc->GetFirstView(), true); - if (currentDoc->GetDocumentWindow()) - currentDoc->GetDocumentWindow()->SetFocus(); - return currentDoc; - } - } - } - - wxDocument *newDoc = temp->CreateDocument(path2, flags); - if (newDoc) - { - newDoc->SetDocumentName(temp->GetDocumentName()); - newDoc->SetDocumentTemplate(temp); - if (!newDoc->OnOpenDocument(path2)) - { - newDoc->DeleteAllViews(); - // delete newDoc; // Implicitly deleted by DeleteAllViews - return (wxDocument *) NULL; - } - // A file that doesn't use the default extension of its document - // template cannot be opened via the FileHistory, so we do not - // add it. - if (temp->FileMatchesTemplate(path2)) - AddFileToHistory(path2); - } - return newDoc; - } - - return (wxDocument *) NULL; -} - -wxView *wxDocManager::CreateView(wxDocument *doc, long flags) -{ - wxDocTemplate **templates = new wxDocTemplate *[m_templates.GetCount()]; - int n =0; - - for (size_t i = 0; i < m_templates.GetCount(); i++) - { - wxDocTemplate *temp = (wxDocTemplate *)(m_templates.Item(i)->GetData()); - if (temp->IsVisible()) - { - if (temp->GetDocumentName() == doc->GetDocumentName()) - { - templates[n] = temp; - n ++; - } - } - } - if (n == 0) - { - delete[] templates; - return (wxView *) NULL; - } - if (n == 1) - { - wxDocTemplate *temp = templates[0]; - delete[] templates; - wxView *view = temp->CreateView(doc, flags); - if (view) - view->SetViewName(temp->GetViewName()); - return view; - } - - wxDocTemplate *temp = SelectViewType(templates, n); - delete[] templates; - if (temp) - { - wxView *view = temp->CreateView(doc, flags); - if (view) - view->SetViewName(temp->GetViewName()); - return view; - } - else - return (wxView *) NULL; -} - -// Not yet implemented -void wxDocManager::DeleteTemplate(wxDocTemplate *WXUNUSED(temp), long WXUNUSED(flags)) -{ -} - -// Not yet implemented -bool wxDocManager::FlushDoc(wxDocument *WXUNUSED(doc)) -{ - return false; -} - -wxDocument *wxDocManager::GetCurrentDocument() const -{ - wxView *view = GetCurrentView(); - if (view) - return view->GetDocument(); - else - return (wxDocument *) NULL; -} - -// Make a default document name -bool wxDocManager::MakeDefaultName(wxString& name) -{ - name.Printf(_("unnamed%d"), m_defaultDocumentNameCounter); - m_defaultDocumentNameCounter++; - - return true; -} - -// Make a frame title (override this to do something different) -// If docName is empty, a document is not currently active. -wxString wxDocManager::MakeFrameTitle(wxDocument* doc) -{ - wxString appName = wxTheApp->GetAppName(); - wxString title; - if (!doc) - title = appName; - else - { - wxString docName; - doc->GetPrintableName(docName); - title = docName + wxString(_(" - ")) + appName; - } - return title; -} - - -// Not yet implemented -wxDocTemplate *wxDocManager::MatchTemplate(const wxString& WXUNUSED(path)) -{ - return (wxDocTemplate *) NULL; -} - -// File history management -void wxDocManager::AddFileToHistory(const wxString& file) -{ - if (m_fileHistory) - m_fileHistory->AddFileToHistory(file); -} - -void wxDocManager::RemoveFileFromHistory(size_t i) -{ - if (m_fileHistory) - m_fileHistory->RemoveFileFromHistory(i); -} - -wxString wxDocManager::GetHistoryFile(size_t i) const -{ - wxString histFile; - - if (m_fileHistory) - histFile = m_fileHistory->GetHistoryFile(i); - - return histFile; -} - -void wxDocManager::FileHistoryUseMenu(wxMenu *menu) -{ - if (m_fileHistory) - m_fileHistory->UseMenu(menu); -} - -void wxDocManager::FileHistoryRemoveMenu(wxMenu *menu) -{ - if (m_fileHistory) - m_fileHistory->RemoveMenu(menu); -} - -#if wxUSE_CONFIG -void wxDocManager::FileHistoryLoad(wxConfigBase& config) -{ - if (m_fileHistory) - m_fileHistory->Load(config); -} - -void wxDocManager::FileHistorySave(wxConfigBase& config) -{ - if (m_fileHistory) - m_fileHistory->Save(config); -} -#endif - -void wxDocManager::FileHistoryAddFilesToMenu(wxMenu* menu) -{ - if (m_fileHistory) - m_fileHistory->AddFilesToMenu(menu); -} - -void wxDocManager::FileHistoryAddFilesToMenu() -{ - if (m_fileHistory) - m_fileHistory->AddFilesToMenu(); -} - -size_t wxDocManager::GetHistoryFilesCount() const -{ - return m_fileHistory ? m_fileHistory->GetCount() : 0; -} - - -// Find out the document template via matching in the document file format -// against that of the template -wxDocTemplate *wxDocManager::FindTemplateForPath(const wxString& path) -{ - wxDocTemplate *theTemplate = (wxDocTemplate *) NULL; - - // Find the template which this extension corresponds to - for (size_t i = 0; i < m_templates.GetCount(); i++) - { - wxDocTemplate *temp = (wxDocTemplate *)m_templates.Item(i)->GetData(); - if ( temp->FileMatchesTemplate(path) ) - { - theTemplate = temp; - break; - } - } - return theTemplate; -} - -// Try to get a more suitable parent frame than the top window, -// for selection dialogs. Otherwise you may get an unexpected -// window being activated when a dialog is shown. -static wxWindow* wxFindSuitableParent() -{ - wxWindow* parent = wxTheApp->GetTopWindow(); - - wxWindow* focusWindow = wxWindow::FindFocus(); - if (focusWindow) - { - while (focusWindow && - !focusWindow->IsKindOf(CLASSINFO(wxDialog)) && - !focusWindow->IsKindOf(CLASSINFO(wxFrame))) - - focusWindow = focusWindow->GetParent(); - - if (focusWindow) - parent = focusWindow; - } - return parent; -} - -// Prompts user to open a file, using file specs in templates. -// Must extend the file selector dialog or implement own; OR -// match the extension to the template extension. - -wxDocTemplate *wxDocManager::SelectDocumentPath(wxDocTemplate **templates, -#if defined(__WXMSW__) || defined(__WXGTK__) || defined(__WXMAC__) - int noTemplates, -#else - int WXUNUSED(noTemplates), -#endif - wxString& path, - long WXUNUSED(flags), - bool WXUNUSED(save)) -{ - // We can only have multiple filters in Windows and GTK -#if defined(__WXMSW__) || defined(__WXGTK__) || defined(__WXMAC__) - wxString descrBuf; - - int i; - for (i = 0; i < noTemplates; i++) - { - if (templates[i]->IsVisible()) - { - // add a '|' to separate this filter from the previous one - if ( !descrBuf.empty() ) - descrBuf << wxT('|'); - - descrBuf << templates[i]->GetDescription() - << wxT(" (") << templates[i]->GetFileFilter() << wxT(") |") - << templates[i]->GetFileFilter(); - } - } -#else - wxString descrBuf = wxT("*.*"); -#endif - - int FilterIndex = -1; - - wxWindow* parent = wxFindSuitableParent(); - - wxString pathTmp = wxFileSelectorEx(_("Select a file"), - m_lastDirectory, - wxEmptyString, - &FilterIndex, - descrBuf, - 0, - parent); - - wxDocTemplate *theTemplate = (wxDocTemplate *)NULL; - if (!pathTmp.empty()) - { - if (!wxFileExists(pathTmp)) - { - wxString msgTitle; - if (!wxTheApp->GetAppName().empty()) - msgTitle = wxTheApp->GetAppName(); - else - msgTitle = wxString(_("File error")); - - (void)wxMessageBox(_("Sorry, could not open this file."), msgTitle, wxOK | wxICON_EXCLAMATION, - parent); - - path = wxEmptyString; - return (wxDocTemplate *) NULL; - } - m_lastDirectory = wxPathOnly(pathTmp); - - path = pathTmp; - - // first choose the template using the extension, if this fails (i.e. - // wxFileSelectorEx() didn't fill it), then use the path - if ( FilterIndex != -1 ) - theTemplate = templates[FilterIndex]; - if ( !theTemplate ) - theTemplate = FindTemplateForPath(path); - if ( !theTemplate ) - { - // Since we do not add files with non-default extensions to the FileHistory this - // can only happen if the application changes the allowed templates in runtime. - (void)wxMessageBox(_("Sorry, the format for this file is unknown."), - _("Open File"), - wxOK | wxICON_EXCLAMATION, wxFindSuitableParent()); - } - } - else - { - path = wxEmptyString; - } - - return theTemplate; -} - -wxDocTemplate *wxDocManager::SelectDocumentType(wxDocTemplate **templates, - int noTemplates, bool sort) -{ - wxArrayString strings; - wxDocTemplate **data = new wxDocTemplate *[noTemplates]; - int i; - int n = 0; - - for (i = 0; i < noTemplates; i++) - { - if (templates[i]->IsVisible()) - { - int j; - bool want = true; - for (j = 0; j < n; j++) - { - //filter out NOT unique documents + view combinations - if ( templates[i]->m_docTypeName == data[j]->m_docTypeName && - templates[i]->m_viewTypeName == data[j]->m_viewTypeName - ) - want = false; - } - - if ( want ) - { - strings.Add(templates[i]->m_description); - - data[n] = templates[i]; - n ++; - } - } - } // for - - if (sort) - { - strings.Sort(); // ascending sort - // Yes, this will be slow, but template lists - // are typically short. - int j; - n = strings.Count(); - for (i = 0; i < n; i++) - { - for (j = 0; j < noTemplates; j++) - { - if (strings[i] == templates[j]->m_description) - data[i] = templates[j]; - } - } - } - - wxDocTemplate *theTemplate; - - switch ( n ) - { - case 0: - // no visible templates, hence nothing to choose from - theTemplate = NULL; - break; - - case 1: - // don't propose the user to choose if he heas no choice - theTemplate = data[0]; - break; - - default: - // propose the user to choose one of several - theTemplate = (wxDocTemplate *)wxGetSingleChoiceData - ( - _("Select a document template"), - _("Templates"), - strings, - (void **)data, - wxFindSuitableParent() - ); - } - - delete[] data; - - return theTemplate; -} - -wxDocTemplate *wxDocManager::SelectViewType(wxDocTemplate **templates, - int noTemplates, bool sort) -{ - wxArrayString strings; - wxDocTemplate **data = new wxDocTemplate *[noTemplates]; - int i; - int n = 0; - - for (i = 0; i < noTemplates; i++) - { - wxDocTemplate *templ = templates[i]; - if ( templ->IsVisible() && !templ->GetViewName().empty() ) - { - int j; - bool want = true; - for (j = 0; j < n; j++) - { - //filter out NOT unique views - if ( templates[i]->m_viewTypeName == data[j]->m_viewTypeName ) - want = false; - } - - if ( want ) - { - strings.Add(templ->m_viewTypeName); - data[n] = templ; - n ++; - } - } - } - - if (sort) - { - strings.Sort(); // ascending sort - // Yes, this will be slow, but template lists - // are typically short. - int j; - n = strings.Count(); - for (i = 0; i < n; i++) - { - for (j = 0; j < noTemplates; j++) - { - if (strings[i] == templates[j]->m_viewTypeName) - data[i] = templates[j]; - } - } - } - - wxDocTemplate *theTemplate; - - // the same logic as above - switch ( n ) - { - case 0: - theTemplate = (wxDocTemplate *)NULL; - break; - - case 1: - theTemplate = data[0]; - break; - - default: - theTemplate = (wxDocTemplate *)wxGetSingleChoiceData - ( - _("Select a document view"), - _("Views"), - strings, - (void **)data, - wxFindSuitableParent() - ); - - } - - delete[] data; - return theTemplate; -} - -void wxDocManager::AssociateTemplate(wxDocTemplate *temp) -{ - if (!m_templates.Member(temp)) - m_templates.Append(temp); -} - -void wxDocManager::DisassociateTemplate(wxDocTemplate *temp) -{ - m_templates.DeleteObject(temp); -} - -// Add and remove a document from the manager's list -void wxDocManager::AddDocument(wxDocument *doc) -{ - if (!m_docs.Member(doc)) - m_docs.Append(doc); -} - -void wxDocManager::RemoveDocument(wxDocument *doc) -{ - m_docs.DeleteObject(doc); -} - -// Views or windows should inform the document manager -// when a view is going in or out of focus -void wxDocManager::ActivateView(wxView *view, bool activate) -{ - if ( activate ) - { - m_currentView = view; - } - else // deactivate - { - if ( m_currentView == view ) - { - // don't keep stale pointer - m_currentView = (wxView *) NULL; - } - } -} - -// ---------------------------------------------------------------------------- -// Default document child frame -// ---------------------------------------------------------------------------- - -BEGIN_EVENT_TABLE(wxDocChildFrame, wxFrame) - EVT_ACTIVATE(wxDocChildFrame::OnActivate) - EVT_CLOSE(wxDocChildFrame::OnCloseWindow) -END_EVENT_TABLE() - -wxDocChildFrame::wxDocChildFrame(wxDocument *doc, - wxView *view, - wxFrame *frame, - wxWindowID id, - const wxString& title, - const wxPoint& pos, - const wxSize& size, - long style, - const wxString& name) - : wxFrame(frame, id, title, pos, size, style, name) -{ - m_childDocument = doc; - m_childView = view; - if (view) - view->SetFrame(this); -} - -// Extend event processing to search the view's event table -bool wxDocChildFrame::ProcessEvent(wxEvent& event) -{ - if (m_childView) - m_childView->Activate(true); - - if ( !m_childView || ! m_childView->ProcessEvent(event) ) - { - // Only hand up to the parent if it's a menu command - if (!event.IsKindOf(CLASSINFO(wxCommandEvent)) || !GetParent() || !GetParent()->ProcessEvent(event)) - return wxEvtHandler::ProcessEvent(event); - else - return true; - } - else - return true; -} - -void wxDocChildFrame::OnActivate(wxActivateEvent& event) -{ - wxFrame::OnActivate(event); - - if (m_childView) - m_childView->Activate(event.GetActive()); -} - -void wxDocChildFrame::OnCloseWindow(wxCloseEvent& event) -{ - if (m_childView) - { - bool ans = event.CanVeto() - ? m_childView->Close(false) // false means don't delete associated window - : true; // Must delete. - - if (ans) - { - m_childView->Activate(false); - delete m_childView; - m_childView = (wxView *) NULL; - m_childDocument = (wxDocument *) NULL; - - this->Destroy(); - } - else - event.Veto(); - } - else - event.Veto(); -} - -// ---------------------------------------------------------------------------- -// Default parent frame -// ---------------------------------------------------------------------------- - -BEGIN_EVENT_TABLE(wxDocParentFrame, wxFrame) - EVT_MENU(wxID_EXIT, wxDocParentFrame::OnExit) - EVT_MENU_RANGE(wxID_FILE1, wxID_FILE9, wxDocParentFrame::OnMRUFile) - EVT_CLOSE(wxDocParentFrame::OnCloseWindow) -END_EVENT_TABLE() - -wxDocParentFrame::wxDocParentFrame() -{ - m_docManager = NULL; -} - -wxDocParentFrame::wxDocParentFrame(wxDocManager *manager, - wxFrame *frame, - wxWindowID id, - const wxString& title, - const wxPoint& pos, - const wxSize& size, - long style, - const wxString& name) - : wxFrame(frame, id, title, pos, size, style, name) -{ - m_docManager = manager; -} - -bool wxDocParentFrame::Create(wxDocManager *manager, - wxFrame *frame, - wxWindowID id, - const wxString& title, - const wxPoint& pos, - const wxSize& size, - long style, - const wxString& name) -{ - m_docManager = manager; - return base_type::Create(frame, id, title, pos, size, style, name); -} - -void wxDocParentFrame::OnExit(wxCommandEvent& WXUNUSED(event)) -{ - Close(); -} - -void wxDocParentFrame::OnMRUFile(wxCommandEvent& event) -{ - int n = event.GetId() - wxID_FILE1; // the index in MRU list - wxString filename(m_docManager->GetHistoryFile(n)); - if ( !filename.empty() ) - { - // verify that the file exists before doing anything else - if ( wxFile::Exists(filename) ) - { - // try to open it - if (!m_docManager->CreateDocument(filename, wxDOC_SILENT)) - { - // remove the file from the MRU list. The user should already be notified. - m_docManager->RemoveFileFromHistory(n); - - wxLogError(_("The file '%s' couldn't be opened.\nIt has been removed from the most recently used files list."), - filename.c_str()); - } - } - else - { - // remove the bogus filename from the MRU list and notify the user - // about it - m_docManager->RemoveFileFromHistory(n); - - wxLogError(_("The file '%s' doesn't exist and couldn't be opened.\nIt has been removed from the most recently used files list."), - filename.c_str()); - } - } -} - -// Extend event processing to search the view's event table -bool wxDocParentFrame::ProcessEvent(wxEvent& event) -{ - // Try the document manager, then do default processing - if (!m_docManager || !m_docManager->ProcessEvent(event)) - return wxEvtHandler::ProcessEvent(event); - else - return true; -} - -// Define the behaviour for the frame closing -// - must delete all frames except for the main one. -void wxDocParentFrame::OnCloseWindow(wxCloseEvent& event) -{ - if (m_docManager->Clear(!event.CanVeto())) - { - this->Destroy(); - } - else - event.Veto(); -} - -#if wxUSE_PRINTING_ARCHITECTURE - -wxDocPrintout::wxDocPrintout(wxView *view, const wxString& title) - : wxPrintout(title) -{ - m_printoutView = view; -} - -bool wxDocPrintout::OnPrintPage(int WXUNUSED(page)) -{ - wxDC *dc = GetDC(); - - // Get the logical pixels per inch of screen and printer - int ppiScreenX, ppiScreenY; - GetPPIScreen(&ppiScreenX, &ppiScreenY); - wxUnusedVar(ppiScreenY); - int ppiPrinterX, ppiPrinterY; - GetPPIPrinter(&ppiPrinterX, &ppiPrinterY); - wxUnusedVar(ppiPrinterY); - - // This scales the DC so that the printout roughly represents the - // the screen scaling. The text point size _should_ be the right size - // but in fact is too small for some reason. This is a detail that will - // need to be addressed at some point but can be fudged for the - // moment. - float scale = (float)((float)ppiPrinterX/(float)ppiScreenX); - - // Now we have to check in case our real page size is reduced - // (e.g. because we're drawing to a print preview memory DC) - int pageWidth, pageHeight; - int w, h; - dc->GetSize(&w, &h); - GetPageSizePixels(&pageWidth, &pageHeight); - wxUnusedVar(pageHeight); - - // If printer pageWidth == current DC width, then this doesn't - // change. But w might be the preview bitmap width, so scale down. - float overallScale = scale * (float)(w/(float)pageWidth); - dc->SetUserScale(overallScale, overallScale); - - if (m_printoutView) - { - m_printoutView->OnDraw(dc); - } - return true; -} - -bool wxDocPrintout::HasPage(int pageNum) -{ - return (pageNum == 1); -} - -bool wxDocPrintout::OnBeginDocument(int startPage, int endPage) -{ - if (!wxPrintout::OnBeginDocument(startPage, endPage)) - return false; - - return true; -} - -void wxDocPrintout::GetPageInfo(int *minPage, int *maxPage, int *selPageFrom, int *selPageTo) -{ - *minPage = 1; - *maxPage = 1; - *selPageFrom = 1; - *selPageTo = 1; -} - -#endif // wxUSE_PRINTING_ARCHITECTURE - -// ---------------------------------------------------------------------------- -// File history processor -// ---------------------------------------------------------------------------- - -static inline wxChar* MYcopystring(const wxString& s) -{ - wxChar* copy = new wxChar[s.length() + 1]; - return wxStrcpy(copy, s.c_str()); -} - -static inline wxChar* MYcopystring(const wxChar* s) -{ - wxChar* copy = new wxChar[wxStrlen(s) + 1]; - return wxStrcpy(copy, s); -} - -wxFileHistory::wxFileHistory(size_t maxFiles, wxWindowID idBase) -{ - m_fileMaxFiles = maxFiles; - m_idBase = idBase; - m_fileHistoryN = 0; - m_fileHistory = new wxChar *[m_fileMaxFiles]; -} - -wxFileHistory::~wxFileHistory() -{ - size_t i; - for (i = 0; i < m_fileHistoryN; i++) - delete[] m_fileHistory[i]; - delete[] m_fileHistory; -} - -// File history management -void wxFileHistory::AddFileToHistory(const wxString& file) -{ - size_t i; - - // Check we don't already have this file - for (i = 0; i < m_fileHistoryN; i++) - { -#if defined( __WXMSW__ ) // Add any other OSes with case insensitive file names - wxString testString; - if ( m_fileHistory[i] ) - testString = m_fileHistory[i]; - if ( m_fileHistory[i] && ( file.Lower() == testString.Lower() ) ) -#else - if ( m_fileHistory[i] && ( file == m_fileHistory[i] ) ) -#endif - { - // we do have it, move it to the top of the history - RemoveFileFromHistory (i); - AddFileToHistory (file); - return; - } - } - - // if we already have a full history, delete the one at the end - if ( m_fileMaxFiles == m_fileHistoryN ) - { - RemoveFileFromHistory (m_fileHistoryN - 1); - AddFileToHistory (file); - return; - } - - // Add to the project file history: - // Move existing files (if any) down so we can insert file at beginning. - if (m_fileHistoryN < m_fileMaxFiles) - { - wxList::compatibility_iterator node = m_fileMenus.GetFirst(); - while (node) - { - wxMenu* menu = (wxMenu*) node->GetData(); - if ( m_fileHistoryN == 0 && menu->GetMenuItemCount() ) - { - menu->AppendSeparator(); - } - menu->Append(m_idBase+m_fileHistoryN, _("[EMPTY]")); - node = node->GetNext(); - } - m_fileHistoryN ++; - } - // Shuffle filenames down - for (i = (m_fileHistoryN-1); i > 0; i--) - { - m_fileHistory[i] = m_fileHistory[i-1]; - } - m_fileHistory[0] = MYcopystring(file); - - // this is the directory of the last opened file - wxString pathCurrent; - wxSplitPath( m_fileHistory[0], &pathCurrent, NULL, NULL ); - for (i = 0; i < m_fileHistoryN; i++) - { - if ( m_fileHistory[i] ) - { - // if in same directory just show the filename; otherwise the full - // path - wxString pathInMenu, path, filename, ext; - wxSplitPath( m_fileHistory[i], &path, &filename, &ext ); - if ( path == pathCurrent ) - { - pathInMenu = filename; - if ( !ext.empty() ) - pathInMenu = pathInMenu + wxFILE_SEP_EXT + ext; - } - else - { - // absolute path; could also set relative path - pathInMenu = m_fileHistory[i]; - } - - // we need to quote '&' characters which are used for mnemonics - pathInMenu.Replace(_T("&"), _T("&&")); - wxString buf; - buf.Printf(s_MRUEntryFormat, i + 1, pathInMenu.c_str()); - wxList::compatibility_iterator node = m_fileMenus.GetFirst(); - while (node) - { - wxMenu* menu = (wxMenu*) node->GetData(); - menu->SetLabel(m_idBase + i, buf); - node = node->GetNext(); - } - } - } -} - -void wxFileHistory::RemoveFileFromHistory(size_t i) -{ - wxCHECK_RET( i < m_fileHistoryN, - wxT("invalid index in wxFileHistory::RemoveFileFromHistory") ); - - // delete the element from the array (could use memmove() too...) - delete [] m_fileHistory[i]; - - size_t j; - for ( j = i; j < m_fileHistoryN - 1; j++ ) - { - m_fileHistory[j] = m_fileHistory[j + 1]; - } - - wxList::compatibility_iterator node = m_fileMenus.GetFirst(); - while ( node ) - { - wxMenu* menu = (wxMenu*) node->GetData(); - - // shuffle filenames up - wxString buf; - for ( j = i; j < m_fileHistoryN - 1; j++ ) - { - buf.Printf(s_MRUEntryFormat, j + 1, m_fileHistory[j]); - menu->SetLabel(m_idBase + j, buf); - } - - node = node->GetNext(); - - // delete the last menu item which is unused now - wxWindowID lastItemId = m_idBase + wx_truncate_cast(wxWindowID, m_fileHistoryN) - 1; - if (menu->FindItem(lastItemId)) - { - menu->Delete(lastItemId); - } - - // delete the last separator too if no more files are left - if ( m_fileHistoryN == 1 ) - { - wxMenuItemList::compatibility_iterator nodeLast = menu->GetMenuItems().GetLast(); - if ( nodeLast ) - { - wxMenuItem *menuItem = nodeLast->GetData(); - if ( menuItem->IsSeparator() ) - { - menu->Delete(menuItem); - } - //else: should we search backwards for the last separator? - } - //else: menu is empty somehow - } - } - - m_fileHistoryN--; -} - -wxString wxFileHistory::GetHistoryFile(size_t i) const -{ - wxString s; - if ( i < m_fileHistoryN ) - { - s = m_fileHistory[i]; - } - else - { - wxFAIL_MSG( wxT("bad index in wxFileHistory::GetHistoryFile") ); - } - - return s; -} - -void wxFileHistory::UseMenu(wxMenu *menu) -{ - if (!m_fileMenus.Member(menu)) - m_fileMenus.Append(menu); -} - -void wxFileHistory::RemoveMenu(wxMenu *menu) -{ - m_fileMenus.DeleteObject(menu); -} - -#if wxUSE_CONFIG -void wxFileHistory::Load(wxConfigBase& config) -{ - m_fileHistoryN = 0; - wxString buf; - buf.Printf(wxT("file%d"), (int)m_fileHistoryN+1); - wxString historyFile; - while ((m_fileHistoryN < m_fileMaxFiles) && config.Read(buf, &historyFile) && (!historyFile.empty())) - { - m_fileHistory[m_fileHistoryN] = MYcopystring((const wxChar*) historyFile); - m_fileHistoryN ++; - buf.Printf(wxT("file%d"), (int)m_fileHistoryN+1); - historyFile = wxEmptyString; - } - AddFilesToMenu(); -} - -void wxFileHistory::Save(wxConfigBase& config) -{ - size_t i; - for (i = 0; i < m_fileMaxFiles; i++) - { - wxString buf; - buf.Printf(wxT("file%d"), (int)i+1); - if (i < m_fileHistoryN) - config.Write(buf, wxString(m_fileHistory[i])); - else - config.Write(buf, wxEmptyString); - } -} -#endif // wxUSE_CONFIG - -void wxFileHistory::AddFilesToMenu() -{ - if (m_fileHistoryN > 0) - { - wxList::compatibility_iterator node = m_fileMenus.GetFirst(); - while (node) - { - wxMenu* menu = (wxMenu*) node->GetData(); - if (menu->GetMenuItemCount()) - { - menu->AppendSeparator(); - } - - size_t i; - for (i = 0; i < m_fileHistoryN; i++) - { - if (m_fileHistory[i]) - { - wxString buf; - buf.Printf(s_MRUEntryFormat, i+1, m_fileHistory[i]); - menu->Append(m_idBase+i, buf); - } - } - node = node->GetNext(); - } - } -} - -void wxFileHistory::AddFilesToMenu(wxMenu* menu) -{ - if (m_fileHistoryN > 0) - { - if (menu->GetMenuItemCount()) - { - menu->AppendSeparator(); - } - - size_t i; - for (i = 0; i < m_fileHistoryN; i++) - { - if (m_fileHistory[i]) - { - wxString buf; - buf.Printf(s_MRUEntryFormat, i+1, m_fileHistory[i]); - menu->Append(m_idBase+i, buf); - } - } - } -} - -// ---------------------------------------------------------------------------- -// Permits compatibility with existing file formats and functions that -// manipulate files directly -// ---------------------------------------------------------------------------- - -#if wxUSE_STD_IOSTREAM - -bool wxTransferFileToStream(const wxString& filename, wxSTD ostream& stream) -{ - wxFFile file(filename, _T("rb")); - if ( !file.IsOpened() ) - return false; - - char buf[4096]; - - size_t nRead; - do - { - nRead = file.Read(buf, WXSIZEOF(buf)); - if ( file.Error() ) - return false; - - stream.write(buf, nRead); - if ( !stream ) - return false; - } - while ( !file.Eof() ); - - return true; -} - -bool wxTransferStreamToFile(wxSTD istream& stream, const wxString& filename) -{ - wxFFile file(filename, _T("wb")); - if ( !file.IsOpened() ) - return false; - - char buf[4096]; - do - { - stream.read(buf, WXSIZEOF(buf)); - if ( !stream.bad() ) // fail may be set on EOF, don't use operator!() - { - if ( !file.Write(buf, stream.gcount()) ) - return false; - } - } - while ( !stream.eof() ); - - return true; -} - -#else // !wxUSE_STD_IOSTREAM - -bool wxTransferFileToStream(const wxString& filename, wxOutputStream& stream) -{ - wxFFile file(filename, _T("rb")); - if ( !file.IsOpened() ) - return false; - - char buf[4096]; - - size_t nRead; - do - { - nRead = file.Read(buf, WXSIZEOF(buf)); - if ( file.Error() ) - return false; - - stream.Write(buf, nRead); - if ( !stream ) - return false; - } - while ( !file.Eof() ); - - return true; -} - -bool wxTransferStreamToFile(wxInputStream& stream, const wxString& filename) -{ - wxFFile file(filename, _T("wb")); - if ( !file.IsOpened() ) - return false; - - char buf[4096]; - for ( ;; ) - { - stream.Read(buf, WXSIZEOF(buf)); - - const size_t nRead = stream.LastRead(); - if ( !nRead ) - { - if ( stream.Eof() ) - break; - - return false; - } - - if ( !file.Write(buf, nRead) ) - return false; - } - - return true; -} - -#endif // wxUSE_STD_IOSTREAM/!wxUSE_STD_IOSTREAM - -#endif // wxUSE_DOC_VIEW_ARCHITECTURE +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/docview.cpp +// Purpose: Document/view classes +// Author: Julian Smart +// Modified by: +// Created: 01/02/97 +// RCS-ID: $Id: docview.cpp 51392 2008-01-26 23:23:09Z VZ $ +// Copyright: (c) Julian Smart +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_DOC_VIEW_ARCHITECTURE + +#include "wx/docview.h" + +#ifndef WX_PRECOMP + #include "wx/list.h" + #include "wx/string.h" + #include "wx/utils.h" + #include "wx/app.h" + #include "wx/dc.h" + #include "wx/dialog.h" + #include "wx/menu.h" + #include "wx/filedlg.h" + #include "wx/intl.h" + #include "wx/log.h" + #include "wx/msgdlg.h" + #include "wx/mdi.h" + #include "wx/choicdlg.h" +#endif + +#include "wx/ffile.h" + +#ifdef __WXMAC__ + #include "wx/filename.h" +#endif + +#if wxUSE_PRINTING_ARCHITECTURE + #include "wx/prntbase.h" + #include "wx/printdlg.h" +#endif + +#include "wx/confbase.h" +#include "wx/file.h" +#include "wx/cmdproc.h" +#include "wx/tokenzr.h" + +#include +#include + +#if wxUSE_STD_IOSTREAM + #include "wx/ioswrap.h" + #if wxUSE_IOSTREAMH + #include + #else + #include + #endif +#else + #include "wx/wfstream.h" +#endif + +// ---------------------------------------------------------------------------- +// wxWidgets macros +// ---------------------------------------------------------------------------- + +IMPLEMENT_ABSTRACT_CLASS(wxDocument, wxEvtHandler) +IMPLEMENT_ABSTRACT_CLASS(wxView, wxEvtHandler) +IMPLEMENT_ABSTRACT_CLASS(wxDocTemplate, wxObject) +IMPLEMENT_DYNAMIC_CLASS(wxDocManager, wxEvtHandler) +IMPLEMENT_CLASS(wxDocChildFrame, wxFrame) +IMPLEMENT_CLASS(wxDocParentFrame, wxFrame) + +#if wxUSE_PRINTING_ARCHITECTURE + IMPLEMENT_DYNAMIC_CLASS(wxDocPrintout, wxPrintout) +#endif + +IMPLEMENT_DYNAMIC_CLASS(wxFileHistory, wxObject) + +// ---------------------------------------------------------------------------- +// function prototypes +// ---------------------------------------------------------------------------- + +static wxWindow* wxFindSuitableParent(void); + +// ---------------------------------------------------------------------------- +// local constants +// ---------------------------------------------------------------------------- + +static const wxChar *s_MRUEntryFormat = wxT("&%d %s"); + +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// local functions +// ---------------------------------------------------------------------------- + +static wxString FindExtension(const wxChar *path) +{ + wxString ext; + wxSplitPath(path, NULL, NULL, &ext); + + // VZ: extensions are considered not case sensitive - is this really a good + // idea? + return ext.MakeLower(); +} + +// ---------------------------------------------------------------------------- +// Definition of wxDocument +// ---------------------------------------------------------------------------- + +wxDocument::wxDocument(wxDocument *parent) +{ + m_documentModified = false; + m_documentParent = parent; + m_documentTemplate = (wxDocTemplate *) NULL; + m_commandProcessor = (wxCommandProcessor*) NULL; + m_savedYet = false; +} + +bool wxDocument::DeleteContents() +{ + return true; +} + +wxDocument::~wxDocument() +{ + DeleteContents(); + + if (m_commandProcessor) + delete m_commandProcessor; + + if (GetDocumentManager()) + GetDocumentManager()->RemoveDocument(this); + + // Not safe to do here, since it'll invoke virtual view functions + // expecting to see valid derived objects: and by the time we get here, + // we've called destructors higher up. + //DeleteAllViews(); +} + +bool wxDocument::Close() +{ + if (OnSaveModified()) + return OnCloseDocument(); + else + return false; +} + +bool wxDocument::OnCloseDocument() +{ + // Tell all views that we're about to close + NotifyClosing(); + DeleteContents(); + Modify(false); + return true; +} + +// Note that this implicitly deletes the document when the last view is +// deleted. +bool wxDocument::DeleteAllViews() +{ + wxDocManager* manager = GetDocumentManager(); + + // first check if all views agree to be closed + const wxList::iterator end = m_documentViews.end(); + for ( wxList::iterator i = m_documentViews.begin(); i != end; ++i ) + { + wxView *view = (wxView *)*i; + if ( !view->Close() ) + return false; + } + + // all views agreed to close, now do close them + if ( m_documentViews.empty() ) + { + // normally the document would be implicitly deleted when the last view + // is, but if don't have any views, do it here instead + if ( manager && manager->GetDocuments().Member(this) ) + delete this; + } + else // have views + { + // as we delete elements we iterate over, don't use the usual "from + // begin to end" loop + for ( ;; ) + { + wxView *view = (wxView *)*m_documentViews.begin(); + + bool isLastOne = m_documentViews.size() == 1; + + // this always deletes the node implicitly and if this is the last + // view also deletes this object itself (also implicitly, great), + // so we can't test for m_documentViews.empty() after calling this! + delete view; + + if ( isLastOne ) + break; + } + } + + return true; +} + +wxView *wxDocument::GetFirstView() const +{ + if (m_documentViews.GetCount() == 0) + return (wxView *) NULL; + return (wxView *)m_documentViews.GetFirst()->GetData(); +} + +wxDocManager *wxDocument::GetDocumentManager() const +{ + return (m_documentTemplate ? m_documentTemplate->GetDocumentManager() : (wxDocManager*) NULL); +} + +bool wxDocument::OnNewDocument() +{ + if (!OnSaveModified()) + return false; + + if (OnCloseDocument()==false) return false; + DeleteContents(); + Modify(false); + SetDocumentSaved(false); + + wxString name; + GetDocumentManager()->MakeDefaultName(name); + SetTitle(name); + SetFilename(name, true); + + return true; +} + +bool wxDocument::Save() +{ + if (!IsModified() && m_savedYet) + return true; + + if ( m_documentFile.empty() || !m_savedYet ) + return SaveAs(); + + return OnSaveDocument(m_documentFile); +} + +bool wxDocument::SaveAs() +{ + wxDocTemplate *docTemplate = GetDocumentTemplate(); + if (!docTemplate) + return false; + +#if defined(__WXMSW__) || defined(__WXGTK__) || defined(__WXMAC__) + wxString filter = docTemplate->GetDescription() + wxT(" (") + docTemplate->GetFileFilter() + wxT(")|") + docTemplate->GetFileFilter(); + + // Now see if there are some other template with identical view and document + // classes, whose filters may also be used. + + if (docTemplate->GetViewClassInfo() && docTemplate->GetDocClassInfo()) + { + wxList::compatibility_iterator node = docTemplate->GetDocumentManager()->GetTemplates().GetFirst(); + while (node) + { + wxDocTemplate *t = (wxDocTemplate*) node->GetData(); + + if (t->IsVisible() && t != docTemplate && + t->GetViewClassInfo() == docTemplate->GetViewClassInfo() && + t->GetDocClassInfo() == docTemplate->GetDocClassInfo()) + { + // add a '|' to separate this filter from the previous one + if ( !filter.empty() ) + filter << wxT('|'); + + filter << t->GetDescription() << wxT(" (") << t->GetFileFilter() << wxT(") |") + << t->GetFileFilter(); + } + + node = node->GetNext(); + } + } +#else + wxString filter = docTemplate->GetFileFilter() ; +#endif + wxString defaultDir = docTemplate->GetDirectory(); + if (defaultDir.IsEmpty()) + defaultDir = wxPathOnly(GetFilename()); + + wxString tmp = wxFileSelector(_("Save as"), + defaultDir, + wxFileNameFromPath(GetFilename()), + docTemplate->GetDefaultExtension(), + filter, + wxFD_SAVE | wxFD_OVERWRITE_PROMPT, + GetDocumentWindow()); + + if (tmp.empty()) + return false; + + wxString fileName(tmp); + wxString path, name, ext; + wxSplitPath(fileName, & path, & name, & ext); + + if (ext.empty()) + { + fileName += wxT("."); + fileName += docTemplate->GetDefaultExtension(); + } + + SetFilename(fileName); + SetTitle(wxFileNameFromPath(fileName)); + + // Notify the views that the filename has changed + wxList::compatibility_iterator node = m_documentViews.GetFirst(); + while (node) + { + wxView *view = (wxView *)node->GetData(); + view->OnChangeFilename(); + node = node->GetNext(); + } + + // Files that were not saved correctly are not added to the FileHistory. + if (!OnSaveDocument(m_documentFile)) + return false; + + // A file that doesn't use the default extension of its document template cannot be opened + // via the FileHistory, so we do not add it. + if (docTemplate->FileMatchesTemplate(fileName)) + { + GetDocumentManager()->AddFileToHistory(fileName); + } + else + { + // The user will probably not be able to open the file again, so + // we could warn about the wrong file-extension here. + } + return true; +} + +bool wxDocument::OnSaveDocument(const wxString& file) +{ + if ( !file ) + return false; + + if ( !DoSaveDocument(file) ) + return false; + + Modify(false); + SetFilename(file); + SetDocumentSaved(true); +#ifdef __WXMAC__ + wxFileName fn(file) ; + fn.MacSetDefaultTypeAndCreator() ; +#endif + return true; +} + +bool wxDocument::OnOpenDocument(const wxString& file) +{ + if (!OnSaveModified()) + return false; + + if ( !DoOpenDocument(file) ) + return false; + + SetFilename(file, true); + Modify(false); + m_savedYet = true; + + UpdateAllViews(); + + return true; +} + +#if wxUSE_STD_IOSTREAM +wxSTD istream& wxDocument::LoadObject(wxSTD istream& stream) +#else +wxInputStream& wxDocument::LoadObject(wxInputStream& stream) +#endif +{ + return stream; +} + +#if wxUSE_STD_IOSTREAM +wxSTD ostream& wxDocument::SaveObject(wxSTD ostream& stream) +#else +wxOutputStream& wxDocument::SaveObject(wxOutputStream& stream) +#endif +{ + return stream; +} + +bool wxDocument::Revert() +{ + return false; +} + + +// Get title, or filename if no title, else unnamed +bool wxDocument::GetPrintableName(wxString& buf) const +{ + if (!m_documentTitle.empty()) + { + buf = m_documentTitle; + return true; + } + else if (!m_documentFile.empty()) + { + buf = wxFileNameFromPath(m_documentFile); + return true; + } + else + { + buf = _("unnamed"); + return true; + } +} + +wxWindow *wxDocument::GetDocumentWindow() const +{ + wxView *view = GetFirstView(); + if (view) + return view->GetFrame(); + else + return wxTheApp->GetTopWindow(); +} + +wxCommandProcessor *wxDocument::OnCreateCommandProcessor() +{ + return new wxCommandProcessor; +} + +// true if safe to close +bool wxDocument::OnSaveModified() +{ + if (IsModified()) + { + wxString title; + GetPrintableName(title); + + wxString msgTitle; + if (!wxTheApp->GetAppName().empty()) + msgTitle = wxTheApp->GetAppName(); + else + msgTitle = wxString(_("Warning")); + + wxString prompt; + prompt.Printf(_("Do you want to save changes to document %s?"), + (const wxChar *)title); + int res = wxMessageBox(prompt, msgTitle, + wxYES_NO|wxCANCEL|wxICON_QUESTION, + GetDocumentWindow()); + if (res == wxNO) + { + Modify(false); + return true; + } + else if (res == wxYES) + return Save(); + else if (res == wxCANCEL) + return false; + } + return true; +} + +bool wxDocument::Draw(wxDC& WXUNUSED(context)) +{ + return true; +} + +bool wxDocument::AddView(wxView *view) +{ + if (!m_documentViews.Member(view)) + { + m_documentViews.Append(view); + OnChangedViewList(); + } + return true; +} + +bool wxDocument::RemoveView(wxView *view) +{ + (void)m_documentViews.DeleteObject(view); + OnChangedViewList(); + return true; +} + +bool wxDocument::OnCreate(const wxString& WXUNUSED(path), long flags) +{ + if (GetDocumentTemplate()->CreateView(this, flags)) + return true; + else + return false; +} + +// Called after a view is added or removed. +// The default implementation deletes the document if +// there are no more views. +void wxDocument::OnChangedViewList() +{ + if (m_documentViews.GetCount() == 0) + { + if (OnSaveModified()) + { + delete this; + } + } +} + +void wxDocument::UpdateAllViews(wxView *sender, wxObject *hint) +{ + wxList::compatibility_iterator node = m_documentViews.GetFirst(); + while (node) + { + wxView *view = (wxView *)node->GetData(); + if (view != sender) + view->OnUpdate(sender, hint); + node = node->GetNext(); + } +} + +void wxDocument::NotifyClosing() +{ + wxList::compatibility_iterator node = m_documentViews.GetFirst(); + while (node) + { + wxView *view = (wxView *)node->GetData(); + view->OnClosingDocument(); + node = node->GetNext(); + } +} + +void wxDocument::SetFilename(const wxString& filename, bool notifyViews) +{ + m_documentFile = filename; + if ( notifyViews ) + { + // Notify the views that the filename has changed + wxList::compatibility_iterator node = m_documentViews.GetFirst(); + while (node) + { + wxView *view = (wxView *)node->GetData(); + view->OnChangeFilename(); + node = node->GetNext(); + } + } +} + +bool wxDocument::DoSaveDocument(const wxString& file) +{ + wxString msgTitle; + if (!wxTheApp->GetAppName().empty()) + msgTitle = wxTheApp->GetAppName(); + else + msgTitle = wxString(_("File error")); + +#if wxUSE_STD_IOSTREAM + wxSTD ofstream store(file.mb_str(), wxSTD ios::binary); + if (store.fail() || store.bad()) +#else + wxFileOutputStream store(file); + if (store.GetLastError() != wxSTREAM_NO_ERROR) +#endif + { + (void)wxMessageBox(_("Sorry, could not open this file for saving."), msgTitle, wxOK | wxICON_EXCLAMATION, + GetDocumentWindow()); + // Saving error + return false; + } + if (!SaveObject(store)) + { + (void)wxMessageBox(_("Sorry, could not save this file."), msgTitle, wxOK | wxICON_EXCLAMATION, + GetDocumentWindow()); + // Saving error + return false; + } + + return true; +} + +bool wxDocument::DoOpenDocument(const wxString& file) +{ +#if wxUSE_STD_IOSTREAM + wxSTD ifstream store(file.mb_str(), wxSTD ios::binary); + if (!store.fail() && !store.bad()) +#else + wxFileInputStream store(file); + if (store.GetLastError() == wxSTREAM_NO_ERROR) +#endif + { +#if wxUSE_STD_IOSTREAM + LoadObject(store); + if ( !!store || store.eof() ) +#else + int res = LoadObject(store).GetLastError(); + if ( res == wxSTREAM_NO_ERROR || res == wxSTREAM_EOF ) +#endif + return true; + } + + wxLogError(_("Sorry, could not open this file.")); + return false; +} + + +// ---------------------------------------------------------------------------- +// Document view +// ---------------------------------------------------------------------------- + +wxView::wxView() +{ + m_viewDocument = (wxDocument*) NULL; + + m_viewFrame = (wxFrame *) NULL; +} + +wxView::~wxView() +{ + GetDocumentManager()->ActivateView(this, false); + m_viewDocument->RemoveView(this); +} + +// Extend event processing to search the document's event table +bool wxView::ProcessEvent(wxEvent& event) +{ + if ( !GetDocument() || !GetDocument()->ProcessEvent(event) ) + return wxEvtHandler::ProcessEvent(event); + + return true; +} + +void wxView::OnActivateView(bool WXUNUSED(activate), wxView *WXUNUSED(activeView), wxView *WXUNUSED(deactiveView)) +{ +} + +void wxView::OnPrint(wxDC *dc, wxObject *WXUNUSED(info)) +{ + OnDraw(dc); +} + +void wxView::OnUpdate(wxView *WXUNUSED(sender), wxObject *WXUNUSED(hint)) +{ +} + +void wxView::OnChangeFilename() +{ + // GetFrame can return wxWindow rather than wxTopLevelWindow due to + // generic MDI implementation so use SetLabel rather than SetTitle. + // It should cause SetTitle() for top level windows. + wxWindow *win = GetFrame(); + if (!win) return; + + wxDocument *doc = GetDocument(); + if (!doc) return; + + wxString name; + doc->GetPrintableName(name); + win->SetLabel(name); +} + +void wxView::SetDocument(wxDocument *doc) +{ + m_viewDocument = doc; + if (doc) + doc->AddView(this); +} + +bool wxView::Close(bool deleteWindow) +{ + if (OnClose(deleteWindow)) + return true; + else + return false; +} + +void wxView::Activate(bool activate) +{ + if (GetDocument() && GetDocumentManager()) + { + OnActivateView(activate, this, GetDocumentManager()->GetCurrentView()); + GetDocumentManager()->ActivateView(this, activate); + } +} + +bool wxView::OnClose(bool WXUNUSED(deleteWindow)) +{ + return GetDocument() ? GetDocument()->Close() : true; +} + +#if wxUSE_PRINTING_ARCHITECTURE +wxPrintout *wxView::OnCreatePrintout() +{ + return new wxDocPrintout(this); +} +#endif // wxUSE_PRINTING_ARCHITECTURE + +// ---------------------------------------------------------------------------- +// wxDocTemplate +// ---------------------------------------------------------------------------- + +wxDocTemplate::wxDocTemplate(wxDocManager *manager, + const wxString& descr, + const wxString& filter, + const wxString& dir, + const wxString& ext, + const wxString& docTypeName, + const wxString& viewTypeName, + wxClassInfo *docClassInfo, + wxClassInfo *viewClassInfo, + long flags) +{ + m_documentManager = manager; + m_description = descr; + m_directory = dir; + m_defaultExt = ext; + m_fileFilter = filter; + m_flags = flags; + m_docTypeName = docTypeName; + m_viewTypeName = viewTypeName; + m_documentManager->AssociateTemplate(this); + + m_docClassInfo = docClassInfo; + m_viewClassInfo = viewClassInfo; +} + +wxDocTemplate::~wxDocTemplate() +{ + m_documentManager->DisassociateTemplate(this); +} + +// Tries to dynamically construct an object of the right class. +wxDocument *wxDocTemplate::CreateDocument(const wxString& path, long flags) +{ + wxDocument *doc = DoCreateDocument(); + if ( doc == NULL ) + return (wxDocument *) NULL; + + if (InitDocument(doc, path, flags)) + { + return doc; + } + else + { + return (wxDocument *) NULL; + } +} + +bool wxDocTemplate::InitDocument(wxDocument* doc, const wxString& path, long flags) +{ + doc->SetFilename(path); + doc->SetDocumentTemplate(this); + GetDocumentManager()->AddDocument(doc); + doc->SetCommandProcessor(doc->OnCreateCommandProcessor()); + + if (doc->OnCreate(path, flags)) + return true; + else + { + if (GetDocumentManager()->GetDocuments().Member(doc)) + doc->DeleteAllViews(); + return false; + } +} + +wxView *wxDocTemplate::CreateView(wxDocument *doc, long flags) +{ + wxView *view = DoCreateView(); + if ( view == NULL ) + return (wxView *) NULL; + + view->SetDocument(doc); + if (view->OnCreate(doc, flags)) + { + return view; + } + else + { + delete view; + return (wxView *) NULL; + } +} + +// The default (very primitive) format detection: check is the extension is +// that of the template +bool wxDocTemplate::FileMatchesTemplate(const wxString& path) +{ + wxStringTokenizer parser (GetFileFilter(), wxT(";")); + wxString anything = wxT ("*"); + while (parser.HasMoreTokens()) + { + wxString filter = parser.GetNextToken(); + wxString filterExt = FindExtension (filter); + if ( filter.IsSameAs (anything) || + filterExt.IsSameAs (anything) || + filterExt.IsSameAs (FindExtension (path)) ) + return true; + } + return GetDefaultExtension().IsSameAs(FindExtension(path)); +} + +wxDocument *wxDocTemplate::DoCreateDocument() +{ + if (!m_docClassInfo) + return (wxDocument *) NULL; + + return (wxDocument *)m_docClassInfo->CreateObject(); +} + +wxView *wxDocTemplate::DoCreateView() +{ + if (!m_viewClassInfo) + return (wxView *) NULL; + + return (wxView *)m_viewClassInfo->CreateObject(); +} + +// ---------------------------------------------------------------------------- +// wxDocManager +// ---------------------------------------------------------------------------- + +BEGIN_EVENT_TABLE(wxDocManager, wxEvtHandler) + EVT_MENU(wxID_OPEN, wxDocManager::OnFileOpen) + EVT_MENU(wxID_CLOSE, wxDocManager::OnFileClose) + EVT_MENU(wxID_CLOSE_ALL, wxDocManager::OnFileCloseAll) + EVT_MENU(wxID_REVERT, wxDocManager::OnFileRevert) + EVT_MENU(wxID_NEW, wxDocManager::OnFileNew) + EVT_MENU(wxID_SAVE, wxDocManager::OnFileSave) + EVT_MENU(wxID_SAVEAS, wxDocManager::OnFileSaveAs) + EVT_MENU(wxID_UNDO, wxDocManager::OnUndo) + EVT_MENU(wxID_REDO, wxDocManager::OnRedo) + + EVT_UPDATE_UI(wxID_OPEN, wxDocManager::OnUpdateFileOpen) + EVT_UPDATE_UI(wxID_CLOSE, wxDocManager::OnUpdateFileClose) + EVT_UPDATE_UI(wxID_CLOSE_ALL, wxDocManager::OnUpdateFileClose) + EVT_UPDATE_UI(wxID_REVERT, wxDocManager::OnUpdateFileRevert) + EVT_UPDATE_UI(wxID_NEW, wxDocManager::OnUpdateFileNew) + EVT_UPDATE_UI(wxID_SAVE, wxDocManager::OnUpdateFileSave) + EVT_UPDATE_UI(wxID_SAVEAS, wxDocManager::OnUpdateFileSaveAs) + EVT_UPDATE_UI(wxID_UNDO, wxDocManager::OnUpdateUndo) + EVT_UPDATE_UI(wxID_REDO, wxDocManager::OnUpdateRedo) + +#if wxUSE_PRINTING_ARCHITECTURE + EVT_MENU(wxID_PRINT, wxDocManager::OnPrint) + EVT_MENU(wxID_PREVIEW, wxDocManager::OnPreview) + + EVT_UPDATE_UI(wxID_PRINT, wxDocManager::OnUpdatePrint) + EVT_UPDATE_UI(wxID_PREVIEW, wxDocManager::OnUpdatePreview) +#endif +END_EVENT_TABLE() + +wxDocManager* wxDocManager::sm_docManager = (wxDocManager*) NULL; + +wxDocManager::wxDocManager(long flags, bool initialize) +{ + m_defaultDocumentNameCounter = 1; + m_flags = flags; + m_currentView = (wxView *) NULL; + m_maxDocsOpen = 10000; + m_fileHistory = (wxFileHistory *) NULL; + if (initialize) + Initialize(); + sm_docManager = this; +} + +wxDocManager::~wxDocManager() +{ + Clear(); + if (m_fileHistory) + delete m_fileHistory; + sm_docManager = (wxDocManager*) NULL; +} + +// closes the specified document +bool wxDocManager::CloseDocument(wxDocument* doc, bool force) +{ + if (doc->Close() || force) + { + // Implicitly deletes the document when + // the last view is deleted + doc->DeleteAllViews(); + + // Check we're really deleted + if (m_docs.Member(doc)) + delete doc; + + return true; + } + return false; +} + +bool wxDocManager::CloseDocuments(bool force) +{ + wxList::compatibility_iterator node = m_docs.GetFirst(); + while (node) + { + wxDocument *doc = (wxDocument *)node->GetData(); + wxList::compatibility_iterator next = node->GetNext(); + + if (!CloseDocument(doc, force)) + return false; + + // This assumes that documents are not connected in + // any way, i.e. deleting one document does NOT + // delete another. + node = next; + } + return true; +} + +bool wxDocManager::Clear(bool force) +{ + if (!CloseDocuments(force)) + return false; + + m_currentView = NULL; + + wxList::compatibility_iterator node = m_templates.GetFirst(); + while (node) + { + wxDocTemplate *templ = (wxDocTemplate*) node->GetData(); + wxList::compatibility_iterator next = node->GetNext(); + delete templ; + node = next; + } + return true; +} + +bool wxDocManager::Initialize() +{ + m_fileHistory = OnCreateFileHistory(); + return true; +} + +wxFileHistory *wxDocManager::OnCreateFileHistory() +{ + return new wxFileHistory; +} + +void wxDocManager::OnFileClose(wxCommandEvent& WXUNUSED(event)) +{ + wxDocument *doc = GetCurrentDocument(); + if (!doc) + return; + if (doc->Close()) + { + doc->DeleteAllViews(); + if (m_docs.Member(doc)) + delete doc; + } +} + +void wxDocManager::OnFileCloseAll(wxCommandEvent& WXUNUSED(event)) +{ + CloseDocuments(false); +} + +void wxDocManager::OnFileNew(wxCommandEvent& WXUNUSED(event)) +{ + CreateDocument( wxEmptyString, wxDOC_NEW ); +} + +void wxDocManager::OnFileOpen(wxCommandEvent& WXUNUSED(event)) +{ + if ( !CreateDocument( wxEmptyString, 0) ) + { + OnOpenFileFailure(); + } +} + +void wxDocManager::OnFileRevert(wxCommandEvent& WXUNUSED(event)) +{ + wxDocument *doc = GetCurrentDocument(); + if (!doc) + return; + doc->Revert(); +} + +void wxDocManager::OnFileSave(wxCommandEvent& WXUNUSED(event)) +{ + wxDocument *doc = GetCurrentDocument(); + if (!doc) + return; + doc->Save(); +} + +void wxDocManager::OnFileSaveAs(wxCommandEvent& WXUNUSED(event)) +{ + wxDocument *doc = GetCurrentDocument(); + if (!doc) + return; + doc->SaveAs(); +} + +void wxDocManager::OnPrint(wxCommandEvent& WXUNUSED(event)) +{ +#if wxUSE_PRINTING_ARCHITECTURE + wxView *view = GetCurrentView(); + if (!view) + return; + + wxPrintout *printout = view->OnCreatePrintout(); + if (printout) + { + wxPrinter printer; + printer.Print(view->GetFrame(), printout, true); + + delete printout; + } +#endif // wxUSE_PRINTING_ARCHITECTURE +} + +void wxDocManager::OnPreview(wxCommandEvent& WXUNUSED(event)) +{ +#if wxUSE_PRINTING_ARCHITECTURE + wxView *view = GetCurrentView(); + if (!view) + return; + + wxPrintout *printout = view->OnCreatePrintout(); + if (printout) + { + // Pass two printout objects: for preview, and possible printing. + wxPrintPreviewBase *preview = new wxPrintPreview(printout, view->OnCreatePrintout()); + if ( !preview->Ok() ) + { + delete preview; + wxMessageBox( _("Sorry, print preview needs a printer to be installed.") ); + return; + } + + wxPreviewFrame *frame = new wxPreviewFrame(preview, (wxFrame *)wxTheApp->GetTopWindow(), _("Print Preview"), + wxPoint(100, 100), wxSize(600, 650)); + frame->Centre(wxBOTH); + frame->Initialize(); + frame->Show(true); + } +#endif // wxUSE_PRINTING_ARCHITECTURE +} + +void wxDocManager::OnUndo(wxCommandEvent& event) +{ + wxDocument *doc = GetCurrentDocument(); + if (!doc) + return; + if (doc->GetCommandProcessor()) + doc->GetCommandProcessor()->Undo(); + else + event.Skip(); +} + +void wxDocManager::OnRedo(wxCommandEvent& event) +{ + wxDocument *doc = GetCurrentDocument(); + if (!doc) + return; + if (doc->GetCommandProcessor()) + doc->GetCommandProcessor()->Redo(); + else + event.Skip(); +} + +// Handlers for UI update commands + +void wxDocManager::OnUpdateFileOpen(wxUpdateUIEvent& event) +{ + event.Enable( true ); +} + +void wxDocManager::OnUpdateFileClose(wxUpdateUIEvent& event) +{ + wxDocument *doc = GetCurrentDocument(); + event.Enable( (doc != (wxDocument*) NULL) ); +} + +void wxDocManager::OnUpdateFileRevert(wxUpdateUIEvent& event) +{ + wxDocument *doc = GetCurrentDocument(); + event.Enable( (doc != (wxDocument*) NULL) ); +} + +void wxDocManager::OnUpdateFileNew(wxUpdateUIEvent& event) +{ + event.Enable( true ); +} + +void wxDocManager::OnUpdateFileSave(wxUpdateUIEvent& event) +{ + wxDocument *doc = GetCurrentDocument(); + event.Enable( doc && doc->IsModified() ); +} + +void wxDocManager::OnUpdateFileSaveAs(wxUpdateUIEvent& event) +{ + wxDocument *doc = GetCurrentDocument(); + event.Enable( (doc != (wxDocument*) NULL) ); +} + +void wxDocManager::OnUpdateUndo(wxUpdateUIEvent& event) +{ + wxDocument *doc = GetCurrentDocument(); + if (!doc) + event.Enable(false); + else if (!doc->GetCommandProcessor()) + event.Skip(); + else + { + event.Enable( doc->GetCommandProcessor()->CanUndo() ); + doc->GetCommandProcessor()->SetMenuStrings(); + } +} + +void wxDocManager::OnUpdateRedo(wxUpdateUIEvent& event) +{ + wxDocument *doc = GetCurrentDocument(); + if (!doc) + event.Enable(false); + else if (!doc->GetCommandProcessor()) + event.Skip(); + else + { + event.Enable( doc->GetCommandProcessor()->CanRedo() ); + doc->GetCommandProcessor()->SetMenuStrings(); + } +} + +void wxDocManager::OnUpdatePrint(wxUpdateUIEvent& event) +{ + wxDocument *doc = GetCurrentDocument(); + event.Enable( (doc != (wxDocument*) NULL) ); +} + +void wxDocManager::OnUpdatePreview(wxUpdateUIEvent& event) +{ + wxDocument *doc = GetCurrentDocument(); + event.Enable( (doc != (wxDocument*) NULL) ); +} + +wxView *wxDocManager::GetCurrentView() const +{ + if (m_currentView) + return m_currentView; + if (m_docs.GetCount() == 1) + { + wxDocument* doc = (wxDocument*) m_docs.GetFirst()->GetData(); + return doc->GetFirstView(); + } + return (wxView *) NULL; +} + +// Extend event processing to search the view's event table +bool wxDocManager::ProcessEvent(wxEvent& event) +{ + wxView* view = GetCurrentView(); + if (view) + { + if (view->ProcessEvent(event)) + return true; + } + return wxEvtHandler::ProcessEvent(event); +} + +wxDocument *wxDocManager::CreateDocument(const wxString& path, long flags) +{ + wxDocTemplate **templates = new wxDocTemplate *[m_templates.GetCount()]; + int n = 0; + + for (size_t i = 0; i < m_templates.GetCount(); i++) + { + wxDocTemplate *temp = (wxDocTemplate *)(m_templates.Item(i)->GetData()); + if (temp->IsVisible()) + { + templates[n] = temp; + n ++; + } + } + if (n == 0) + { + delete[] templates; + return (wxDocument *) NULL; + } + + wxDocument* docToClose = NULL; + + // If we've reached the max number of docs, close the + // first one. + if ( (int)GetDocuments().GetCount() >= m_maxDocsOpen ) + { + wxDocument *doc = (wxDocument *)GetDocuments().GetFirst()->GetData(); + docToClose = doc; + } + + // New document: user chooses a template, unless there's only one. + if (flags & wxDOC_NEW) + { + if (n == 1) + { + if (docToClose) + { + if (!CloseDocument(docToClose, false)) + { + delete[] templates; + return NULL; + } + } + + wxDocTemplate *temp = templates[0]; + delete[] templates; + wxDocument *newDoc = temp->CreateDocument(path, flags); + + if (newDoc) + { + newDoc->SetDocumentName(temp->GetDocumentName()); + newDoc->SetDocumentTemplate(temp); + if (!newDoc->OnNewDocument() ) + { + // Document is implicitly deleted by DeleteAllViews + newDoc->DeleteAllViews(); + return NULL; + } + } + return newDoc; + } + + wxDocTemplate *temp = SelectDocumentType(templates, n); + delete[] templates; + if (temp) + { + if (docToClose) + { + if (!CloseDocument(docToClose, false)) + { + return NULL; + } + } + + wxDocument *newDoc = temp->CreateDocument(path, flags); + + if (newDoc) + { + newDoc->SetDocumentName(temp->GetDocumentName()); + newDoc->SetDocumentTemplate(temp); + if (!newDoc->OnNewDocument() ) + { + // Document is implicitly deleted by DeleteAllViews + newDoc->DeleteAllViews(); + return NULL; + } + } + return newDoc; + } + else + return (wxDocument *) NULL; + } + + // Existing document + wxDocTemplate *temp; + + wxString path2 = path; + + if (flags & wxDOC_SILENT) + { + temp = FindTemplateForPath(path2); + if (!temp) + { + // Since we do not add files with non-default extensions to the FileHistory this + // can only happen if the application changes the allowed templates in runtime. + (void)wxMessageBox(_("Sorry, the format for this file is unknown."), + _("Open File"), + wxOK | wxICON_EXCLAMATION, wxFindSuitableParent()); + } + } + else + temp = SelectDocumentPath(templates, n, path2, flags); + + delete[] templates; + + if (temp) + { + if (docToClose) + { + if (!CloseDocument(docToClose, false)) + { + return NULL; + } + } + + //see if this file is already open + for (size_t i = 0; i < GetDocuments().GetCount(); ++i) + { + wxDocument* currentDoc = (wxDocument*)(GetDocuments().Item(i)->GetData()); +#ifdef __WXMSW__ + //file paths are case-insensitive on Windows + if (path2.CmpNoCase(currentDoc->GetFilename()) == 0) +#else + if (path2.Cmp(currentDoc->GetFilename()) == 0) +#endif + { + //file already open. Just activate it and return + if (currentDoc->GetFirstView()) + { + ActivateView(currentDoc->GetFirstView(), true); + if (currentDoc->GetDocumentWindow()) + currentDoc->GetDocumentWindow()->SetFocus(); + return currentDoc; + } + } + } + + wxDocument *newDoc = temp->CreateDocument(path2, flags); + if (newDoc) + { + newDoc->SetDocumentName(temp->GetDocumentName()); + newDoc->SetDocumentTemplate(temp); + if (!newDoc->OnOpenDocument(path2)) + { + newDoc->DeleteAllViews(); + // delete newDoc; // Implicitly deleted by DeleteAllViews + return (wxDocument *) NULL; + } + // A file that doesn't use the default extension of its document + // template cannot be opened via the FileHistory, so we do not + // add it. + if (temp->FileMatchesTemplate(path2)) + AddFileToHistory(path2); + } + return newDoc; + } + + return (wxDocument *) NULL; +} + +wxView *wxDocManager::CreateView(wxDocument *doc, long flags) +{ + wxDocTemplate **templates = new wxDocTemplate *[m_templates.GetCount()]; + int n =0; + + for (size_t i = 0; i < m_templates.GetCount(); i++) + { + wxDocTemplate *temp = (wxDocTemplate *)(m_templates.Item(i)->GetData()); + if (temp->IsVisible()) + { + if (temp->GetDocumentName() == doc->GetDocumentName()) + { + templates[n] = temp; + n ++; + } + } + } + if (n == 0) + { + delete[] templates; + return (wxView *) NULL; + } + if (n == 1) + { + wxDocTemplate *temp = templates[0]; + delete[] templates; + wxView *view = temp->CreateView(doc, flags); + if (view) + view->SetViewName(temp->GetViewName()); + return view; + } + + wxDocTemplate *temp = SelectViewType(templates, n); + delete[] templates; + if (temp) + { + wxView *view = temp->CreateView(doc, flags); + if (view) + view->SetViewName(temp->GetViewName()); + return view; + } + else + return (wxView *) NULL; +} + +// Not yet implemented +void wxDocManager::DeleteTemplate(wxDocTemplate *WXUNUSED(temp), long WXUNUSED(flags)) +{ +} + +// Not yet implemented +bool wxDocManager::FlushDoc(wxDocument *WXUNUSED(doc)) +{ + return false; +} + +wxDocument *wxDocManager::GetCurrentDocument() const +{ + wxView *view = GetCurrentView(); + if (view) + return view->GetDocument(); + else + return (wxDocument *) NULL; +} + +// Make a default document name +bool wxDocManager::MakeDefaultName(wxString& name) +{ + name.Printf(_("unnamed%d"), m_defaultDocumentNameCounter); + m_defaultDocumentNameCounter++; + + return true; +} + +// Make a frame title (override this to do something different) +// If docName is empty, a document is not currently active. +wxString wxDocManager::MakeFrameTitle(wxDocument* doc) +{ + wxString appName = wxTheApp->GetAppName(); + wxString title; + if (!doc) + title = appName; + else + { + wxString docName; + doc->GetPrintableName(docName); + title = docName + wxString(_(" - ")) + appName; + } + return title; +} + + +// Not yet implemented +wxDocTemplate *wxDocManager::MatchTemplate(const wxString& WXUNUSED(path)) +{ + return (wxDocTemplate *) NULL; +} + +// File history management +void wxDocManager::AddFileToHistory(const wxString& file) +{ + if (m_fileHistory) + m_fileHistory->AddFileToHistory(file); +} + +void wxDocManager::RemoveFileFromHistory(size_t i) +{ + if (m_fileHistory) + m_fileHistory->RemoveFileFromHistory(i); +} + +wxString wxDocManager::GetHistoryFile(size_t i) const +{ + wxString histFile; + + if (m_fileHistory) + histFile = m_fileHistory->GetHistoryFile(i); + + return histFile; +} + +void wxDocManager::FileHistoryUseMenu(wxMenu *menu) +{ + if (m_fileHistory) + m_fileHistory->UseMenu(menu); +} + +void wxDocManager::FileHistoryRemoveMenu(wxMenu *menu) +{ + if (m_fileHistory) + m_fileHistory->RemoveMenu(menu); +} + +#if wxUSE_CONFIG +void wxDocManager::FileHistoryLoad(wxConfigBase& config) +{ + if (m_fileHistory) + m_fileHistory->Load(config); +} + +void wxDocManager::FileHistorySave(wxConfigBase& config) +{ + if (m_fileHistory) + m_fileHistory->Save(config); +} +#endif + +void wxDocManager::FileHistoryAddFilesToMenu(wxMenu* menu) +{ + if (m_fileHistory) + m_fileHistory->AddFilesToMenu(menu); +} + +void wxDocManager::FileHistoryAddFilesToMenu() +{ + if (m_fileHistory) + m_fileHistory->AddFilesToMenu(); +} + +size_t wxDocManager::GetHistoryFilesCount() const +{ + return m_fileHistory ? m_fileHistory->GetCount() : 0; +} + + +// Find out the document template via matching in the document file format +// against that of the template +wxDocTemplate *wxDocManager::FindTemplateForPath(const wxString& path) +{ + wxDocTemplate *theTemplate = (wxDocTemplate *) NULL; + + // Find the template which this extension corresponds to + for (size_t i = 0; i < m_templates.GetCount(); i++) + { + wxDocTemplate *temp = (wxDocTemplate *)m_templates.Item(i)->GetData(); + if ( temp->FileMatchesTemplate(path) ) + { + theTemplate = temp; + break; + } + } + return theTemplate; +} + +// Try to get a more suitable parent frame than the top window, +// for selection dialogs. Otherwise you may get an unexpected +// window being activated when a dialog is shown. +static wxWindow* wxFindSuitableParent() +{ + wxWindow* parent = wxTheApp->GetTopWindow(); + + wxWindow* focusWindow = wxWindow::FindFocus(); + if (focusWindow) + { + while (focusWindow && + !focusWindow->IsKindOf(CLASSINFO(wxDialog)) && + !focusWindow->IsKindOf(CLASSINFO(wxFrame))) + + focusWindow = focusWindow->GetParent(); + + if (focusWindow) + parent = focusWindow; + } + return parent; +} + +// Prompts user to open a file, using file specs in templates. +// Must extend the file selector dialog or implement own; OR +// match the extension to the template extension. + +wxDocTemplate *wxDocManager::SelectDocumentPath(wxDocTemplate **templates, +#if defined(__WXMSW__) || defined(__WXGTK__) || defined(__WXMAC__) + int noTemplates, +#else + int WXUNUSED(noTemplates), +#endif + wxString& path, + long WXUNUSED(flags), + bool WXUNUSED(save)) +{ + // We can only have multiple filters in Windows and GTK +#if defined(__WXMSW__) || defined(__WXGTK__) || defined(__WXMAC__) + wxString descrBuf; + + int i; + for (i = 0; i < noTemplates; i++) + { + if (templates[i]->IsVisible()) + { + // add a '|' to separate this filter from the previous one + if ( !descrBuf.empty() ) + descrBuf << wxT('|'); + + descrBuf << templates[i]->GetDescription() + << wxT(" (") << templates[i]->GetFileFilter() << wxT(") |") + << templates[i]->GetFileFilter(); + } + } +#else + wxString descrBuf = wxT("*.*"); +#endif + + int FilterIndex = -1; + + wxWindow* parent = wxFindSuitableParent(); + + wxString pathTmp = wxFileSelectorEx(_("Select a file"), + m_lastDirectory, + wxEmptyString, + &FilterIndex, + descrBuf, + 0, + parent); + + wxDocTemplate *theTemplate = (wxDocTemplate *)NULL; + if (!pathTmp.empty()) + { + if (!wxFileExists(pathTmp)) + { + wxString msgTitle; + if (!wxTheApp->GetAppName().empty()) + msgTitle = wxTheApp->GetAppName(); + else + msgTitle = wxString(_("File error")); + + (void)wxMessageBox(_("Sorry, could not open this file."), msgTitle, wxOK | wxICON_EXCLAMATION, + parent); + + path = wxEmptyString; + return (wxDocTemplate *) NULL; + } + m_lastDirectory = wxPathOnly(pathTmp); + + path = pathTmp; + + // first choose the template using the extension, if this fails (i.e. + // wxFileSelectorEx() didn't fill it), then use the path + if ( FilterIndex != -1 ) + theTemplate = templates[FilterIndex]; + if ( !theTemplate ) + theTemplate = FindTemplateForPath(path); + if ( !theTemplate ) + { + // Since we do not add files with non-default extensions to the FileHistory this + // can only happen if the application changes the allowed templates in runtime. + (void)wxMessageBox(_("Sorry, the format for this file is unknown."), + _("Open File"), + wxOK | wxICON_EXCLAMATION, wxFindSuitableParent()); + } + } + else + { + path = wxEmptyString; + } + + return theTemplate; +} + +wxDocTemplate *wxDocManager::SelectDocumentType(wxDocTemplate **templates, + int noTemplates, bool sort) +{ + wxArrayString strings; + wxDocTemplate **data = new wxDocTemplate *[noTemplates]; + int i; + int n = 0; + + for (i = 0; i < noTemplates; i++) + { + if (templates[i]->IsVisible()) + { + int j; + bool want = true; + for (j = 0; j < n; j++) + { + //filter out NOT unique documents + view combinations + if ( templates[i]->m_docTypeName == data[j]->m_docTypeName && + templates[i]->m_viewTypeName == data[j]->m_viewTypeName + ) + want = false; + } + + if ( want ) + { + strings.Add(templates[i]->m_description); + + data[n] = templates[i]; + n ++; + } + } + } // for + + if (sort) + { + strings.Sort(); // ascending sort + // Yes, this will be slow, but template lists + // are typically short. + int j; + n = strings.Count(); + for (i = 0; i < n; i++) + { + for (j = 0; j < noTemplates; j++) + { + if (strings[i] == templates[j]->m_description) + data[i] = templates[j]; + } + } + } + + wxDocTemplate *theTemplate; + + switch ( n ) + { + case 0: + // no visible templates, hence nothing to choose from + theTemplate = NULL; + break; + + case 1: + // don't propose the user to choose if he heas no choice + theTemplate = data[0]; + break; + + default: + // propose the user to choose one of several + theTemplate = (wxDocTemplate *)wxGetSingleChoiceData + ( + _("Select a document template"), + _("Templates"), + strings, + (void **)data, + wxFindSuitableParent() + ); + } + + delete[] data; + + return theTemplate; +} + +wxDocTemplate *wxDocManager::SelectViewType(wxDocTemplate **templates, + int noTemplates, bool sort) +{ + wxArrayString strings; + wxDocTemplate **data = new wxDocTemplate *[noTemplates]; + int i; + int n = 0; + + for (i = 0; i < noTemplates; i++) + { + wxDocTemplate *templ = templates[i]; + if ( templ->IsVisible() && !templ->GetViewName().empty() ) + { + int j; + bool want = true; + for (j = 0; j < n; j++) + { + //filter out NOT unique views + if ( templates[i]->m_viewTypeName == data[j]->m_viewTypeName ) + want = false; + } + + if ( want ) + { + strings.Add(templ->m_viewTypeName); + data[n] = templ; + n ++; + } + } + } + + if (sort) + { + strings.Sort(); // ascending sort + // Yes, this will be slow, but template lists + // are typically short. + int j; + n = strings.Count(); + for (i = 0; i < n; i++) + { + for (j = 0; j < noTemplates; j++) + { + if (strings[i] == templates[j]->m_viewTypeName) + data[i] = templates[j]; + } + } + } + + wxDocTemplate *theTemplate; + + // the same logic as above + switch ( n ) + { + case 0: + theTemplate = (wxDocTemplate *)NULL; + break; + + case 1: + theTemplate = data[0]; + break; + + default: + theTemplate = (wxDocTemplate *)wxGetSingleChoiceData + ( + _("Select a document view"), + _("Views"), + strings, + (void **)data, + wxFindSuitableParent() + ); + + } + + delete[] data; + return theTemplate; +} + +void wxDocManager::AssociateTemplate(wxDocTemplate *temp) +{ + if (!m_templates.Member(temp)) + m_templates.Append(temp); +} + +void wxDocManager::DisassociateTemplate(wxDocTemplate *temp) +{ + m_templates.DeleteObject(temp); +} + +// Add and remove a document from the manager's list +void wxDocManager::AddDocument(wxDocument *doc) +{ + if (!m_docs.Member(doc)) + m_docs.Append(doc); +} + +void wxDocManager::RemoveDocument(wxDocument *doc) +{ + m_docs.DeleteObject(doc); +} + +// Views or windows should inform the document manager +// when a view is going in or out of focus +void wxDocManager::ActivateView(wxView *view, bool activate) +{ + if ( activate ) + { + m_currentView = view; + } + else // deactivate + { + if ( m_currentView == view ) + { + // don't keep stale pointer + m_currentView = (wxView *) NULL; + } + } +} + +// ---------------------------------------------------------------------------- +// Default document child frame +// ---------------------------------------------------------------------------- + +BEGIN_EVENT_TABLE(wxDocChildFrame, wxFrame) + EVT_ACTIVATE(wxDocChildFrame::OnActivate) + EVT_CLOSE(wxDocChildFrame::OnCloseWindow) +END_EVENT_TABLE() + +wxDocChildFrame::wxDocChildFrame(wxDocument *doc, + wxView *view, + wxFrame *frame, + wxWindowID id, + const wxString& title, + const wxPoint& pos, + const wxSize& size, + long style, + const wxString& name) + : wxFrame(frame, id, title, pos, size, style, name) +{ + m_childDocument = doc; + m_childView = view; + if (view) + view->SetFrame(this); +} + +// Extend event processing to search the view's event table +bool wxDocChildFrame::ProcessEvent(wxEvent& event) +{ + if (m_childView) + m_childView->Activate(true); + + if ( !m_childView || ! m_childView->ProcessEvent(event) ) + { + // Only hand up to the parent if it's a menu command + if (!event.IsKindOf(CLASSINFO(wxCommandEvent)) || !GetParent() || !GetParent()->ProcessEvent(event)) + return wxEvtHandler::ProcessEvent(event); + else + return true; + } + else + return true; +} + +void wxDocChildFrame::OnActivate(wxActivateEvent& event) +{ + wxFrame::OnActivate(event); + + if (m_childView) + m_childView->Activate(event.GetActive()); +} + +void wxDocChildFrame::OnCloseWindow(wxCloseEvent& event) +{ + if (m_childView) + { + bool ans = event.CanVeto() + ? m_childView->Close(false) // false means don't delete associated window + : true; // Must delete. + + if (ans) + { + m_childView->Activate(false); + delete m_childView; + m_childView = (wxView *) NULL; + m_childDocument = (wxDocument *) NULL; + + this->Destroy(); + } + else + event.Veto(); + } + else + event.Veto(); +} + +// ---------------------------------------------------------------------------- +// Default parent frame +// ---------------------------------------------------------------------------- + +BEGIN_EVENT_TABLE(wxDocParentFrame, wxFrame) + EVT_MENU(wxID_EXIT, wxDocParentFrame::OnExit) + EVT_MENU_RANGE(wxID_FILE1, wxID_FILE9, wxDocParentFrame::OnMRUFile) + EVT_CLOSE(wxDocParentFrame::OnCloseWindow) +END_EVENT_TABLE() + +wxDocParentFrame::wxDocParentFrame() +{ + m_docManager = NULL; +} + +wxDocParentFrame::wxDocParentFrame(wxDocManager *manager, + wxFrame *frame, + wxWindowID id, + const wxString& title, + const wxPoint& pos, + const wxSize& size, + long style, + const wxString& name) + : wxFrame(frame, id, title, pos, size, style, name) +{ + m_docManager = manager; +} + +bool wxDocParentFrame::Create(wxDocManager *manager, + wxFrame *frame, + wxWindowID id, + const wxString& title, + const wxPoint& pos, + const wxSize& size, + long style, + const wxString& name) +{ + m_docManager = manager; + return base_type::Create(frame, id, title, pos, size, style, name); +} + +void wxDocParentFrame::OnExit(wxCommandEvent& WXUNUSED(event)) +{ + Close(); +} + +void wxDocParentFrame::OnMRUFile(wxCommandEvent& event) +{ + int n = event.GetId() - wxID_FILE1; // the index in MRU list + wxString filename(m_docManager->GetHistoryFile(n)); + if ( !filename.empty() ) + { + // verify that the file exists before doing anything else + if ( wxFile::Exists(filename) ) + { + // try to open it + if (!m_docManager->CreateDocument(filename, wxDOC_SILENT)) + { + // remove the file from the MRU list. The user should already be notified. + m_docManager->RemoveFileFromHistory(n); + + wxLogError(_("The file '%s' couldn't be opened.\nIt has been removed from the most recently used files list."), + filename.c_str()); + } + } + else + { + // remove the bogus filename from the MRU list and notify the user + // about it + m_docManager->RemoveFileFromHistory(n); + + wxLogError(_("The file '%s' doesn't exist and couldn't be opened.\nIt has been removed from the most recently used files list."), + filename.c_str()); + } + } +} + +// Extend event processing to search the view's event table +bool wxDocParentFrame::ProcessEvent(wxEvent& event) +{ + // Try the document manager, then do default processing + if (!m_docManager || !m_docManager->ProcessEvent(event)) + return wxEvtHandler::ProcessEvent(event); + else + return true; +} + +// Define the behaviour for the frame closing +// - must delete all frames except for the main one. +void wxDocParentFrame::OnCloseWindow(wxCloseEvent& event) +{ + if (m_docManager->Clear(!event.CanVeto())) + { + this->Destroy(); + } + else + event.Veto(); +} + +#if wxUSE_PRINTING_ARCHITECTURE + +wxDocPrintout::wxDocPrintout(wxView *view, const wxString& title) + : wxPrintout(title) +{ + m_printoutView = view; +} + +bool wxDocPrintout::OnPrintPage(int WXUNUSED(page)) +{ + wxDC *dc = GetDC(); + + // Get the logical pixels per inch of screen and printer + int ppiScreenX, ppiScreenY; + GetPPIScreen(&ppiScreenX, &ppiScreenY); + wxUnusedVar(ppiScreenY); + int ppiPrinterX, ppiPrinterY; + GetPPIPrinter(&ppiPrinterX, &ppiPrinterY); + wxUnusedVar(ppiPrinterY); + + // This scales the DC so that the printout roughly represents the + // the screen scaling. The text point size _should_ be the right size + // but in fact is too small for some reason. This is a detail that will + // need to be addressed at some point but can be fudged for the + // moment. + float scale = (float)((float)ppiPrinterX/(float)ppiScreenX); + + // Now we have to check in case our real page size is reduced + // (e.g. because we're drawing to a print preview memory DC) + int pageWidth, pageHeight; + int w, h; + dc->GetSize(&w, &h); + GetPageSizePixels(&pageWidth, &pageHeight); + wxUnusedVar(pageHeight); + + // If printer pageWidth == current DC width, then this doesn't + // change. But w might be the preview bitmap width, so scale down. + float overallScale = scale * (float)(w/(float)pageWidth); + dc->SetUserScale(overallScale, overallScale); + + if (m_printoutView) + { + m_printoutView->OnDraw(dc); + } + return true; +} + +bool wxDocPrintout::HasPage(int pageNum) +{ + return (pageNum == 1); +} + +bool wxDocPrintout::OnBeginDocument(int startPage, int endPage) +{ + if (!wxPrintout::OnBeginDocument(startPage, endPage)) + return false; + + return true; +} + +void wxDocPrintout::GetPageInfo(int *minPage, int *maxPage, int *selPageFrom, int *selPageTo) +{ + *minPage = 1; + *maxPage = 1; + *selPageFrom = 1; + *selPageTo = 1; +} + +#endif // wxUSE_PRINTING_ARCHITECTURE + +// ---------------------------------------------------------------------------- +// File history processor +// ---------------------------------------------------------------------------- + +static inline wxChar* MYcopystring(const wxString& s) +{ + wxChar* copy = new wxChar[s.length() + 1]; + return wxStrcpy(copy, s.c_str()); +} + +static inline wxChar* MYcopystring(const wxChar* s) +{ + wxChar* copy = new wxChar[wxStrlen(s) + 1]; + return wxStrcpy(copy, s); +} + +wxFileHistory::wxFileHistory(size_t maxFiles, wxWindowID idBase) +{ + m_fileMaxFiles = maxFiles; + m_idBase = idBase; + m_fileHistoryN = 0; + m_fileHistory = new wxChar *[m_fileMaxFiles]; +} + +wxFileHistory::~wxFileHistory() +{ + size_t i; + for (i = 0; i < m_fileHistoryN; i++) + delete[] m_fileHistory[i]; + delete[] m_fileHistory; +} + +// File history management +void wxFileHistory::AddFileToHistory(const wxString& file) +{ + size_t i; + + // Check we don't already have this file + for (i = 0; i < m_fileHistoryN; i++) + { +#if defined( __WXMSW__ ) // Add any other OSes with case insensitive file names + wxString testString; + if ( m_fileHistory[i] ) + testString = m_fileHistory[i]; + if ( m_fileHistory[i] && ( file.Lower() == testString.Lower() ) ) +#else + if ( m_fileHistory[i] && ( file == m_fileHistory[i] ) ) +#endif + { + // we do have it, move it to the top of the history + RemoveFileFromHistory (i); + AddFileToHistory (file); + return; + } + } + + // if we already have a full history, delete the one at the end + if ( m_fileMaxFiles == m_fileHistoryN ) + { + RemoveFileFromHistory (m_fileHistoryN - 1); + AddFileToHistory (file); + return; + } + + // Add to the project file history: + // Move existing files (if any) down so we can insert file at beginning. + if (m_fileHistoryN < m_fileMaxFiles) + { + wxList::compatibility_iterator node = m_fileMenus.GetFirst(); + while (node) + { + wxMenu* menu = (wxMenu*) node->GetData(); + if ( m_fileHistoryN == 0 && menu->GetMenuItemCount() ) + { + menu->AppendSeparator(); + } + menu->Append(m_idBase+m_fileHistoryN, _("[EMPTY]")); + node = node->GetNext(); + } + m_fileHistoryN ++; + } + // Shuffle filenames down + for (i = (m_fileHistoryN-1); i > 0; i--) + { + m_fileHistory[i] = m_fileHistory[i-1]; + } + m_fileHistory[0] = MYcopystring(file); + + // this is the directory of the last opened file + wxString pathCurrent; + wxSplitPath( m_fileHistory[0], &pathCurrent, NULL, NULL ); + for (i = 0; i < m_fileHistoryN; i++) + { + if ( m_fileHistory[i] ) + { + // if in same directory just show the filename; otherwise the full + // path + wxString pathInMenu, path, filename, ext; + wxSplitPath( m_fileHistory[i], &path, &filename, &ext ); + if ( path == pathCurrent ) + { + pathInMenu = filename; + if ( !ext.empty() ) + pathInMenu = pathInMenu + wxFILE_SEP_EXT + ext; + } + else + { + // absolute path; could also set relative path + pathInMenu = m_fileHistory[i]; + } + + // we need to quote '&' characters which are used for mnemonics + pathInMenu.Replace(_T("&"), _T("&&")); + wxString buf; + buf.Printf(s_MRUEntryFormat, i + 1, pathInMenu.c_str()); + wxList::compatibility_iterator node = m_fileMenus.GetFirst(); + while (node) + { + wxMenu* menu = (wxMenu*) node->GetData(); + menu->SetLabel(m_idBase + i, buf); + node = node->GetNext(); + } + } + } +} + +void wxFileHistory::RemoveFileFromHistory(size_t i) +{ + wxCHECK_RET( i < m_fileHistoryN, + wxT("invalid index in wxFileHistory::RemoveFileFromHistory") ); + + // delete the element from the array (could use memmove() too...) + delete [] m_fileHistory[i]; + + size_t j; + for ( j = i; j < m_fileHistoryN - 1; j++ ) + { + m_fileHistory[j] = m_fileHistory[j + 1]; + } + + wxList::compatibility_iterator node = m_fileMenus.GetFirst(); + while ( node ) + { + wxMenu* menu = (wxMenu*) node->GetData(); + + // shuffle filenames up + wxString buf; + for ( j = i; j < m_fileHistoryN - 1; j++ ) + { + buf.Printf(s_MRUEntryFormat, j + 1, m_fileHistory[j]); + menu->SetLabel(m_idBase + j, buf); + } + + node = node->GetNext(); + + // delete the last menu item which is unused now + wxWindowID lastItemId = m_idBase + wx_truncate_cast(wxWindowID, m_fileHistoryN) - 1; + if (menu->FindItem(lastItemId)) + { + menu->Delete(lastItemId); + } + + // delete the last separator too if no more files are left + if ( m_fileHistoryN == 1 ) + { + wxMenuItemList::compatibility_iterator nodeLast = menu->GetMenuItems().GetLast(); + if ( nodeLast ) + { + wxMenuItem *menuItem = nodeLast->GetData(); + if ( menuItem->IsSeparator() ) + { + menu->Delete(menuItem); + } + //else: should we search backwards for the last separator? + } + //else: menu is empty somehow + } + } + + m_fileHistoryN--; +} + +wxString wxFileHistory::GetHistoryFile(size_t i) const +{ + wxString s; + if ( i < m_fileHistoryN ) + { + s = m_fileHistory[i]; + } + else + { + wxFAIL_MSG( wxT("bad index in wxFileHistory::GetHistoryFile") ); + } + + return s; +} + +void wxFileHistory::UseMenu(wxMenu *menu) +{ + if (!m_fileMenus.Member(menu)) + m_fileMenus.Append(menu); +} + +void wxFileHistory::RemoveMenu(wxMenu *menu) +{ + m_fileMenus.DeleteObject(menu); +} + +#if wxUSE_CONFIG +void wxFileHistory::Load(wxConfigBase& config) +{ + m_fileHistoryN = 0; + wxString buf; + buf.Printf(wxT("file%d"), (int)m_fileHistoryN+1); + wxString historyFile; + while ((m_fileHistoryN < m_fileMaxFiles) && config.Read(buf, &historyFile) && (!historyFile.empty())) + { + m_fileHistory[m_fileHistoryN] = MYcopystring((const wxChar*) historyFile); + m_fileHistoryN ++; + buf.Printf(wxT("file%d"), (int)m_fileHistoryN+1); + historyFile = wxEmptyString; + } + AddFilesToMenu(); +} + +void wxFileHistory::Save(wxConfigBase& config) +{ + size_t i; + for (i = 0; i < m_fileMaxFiles; i++) + { + wxString buf; + buf.Printf(wxT("file%d"), (int)i+1); + if (i < m_fileHistoryN) + config.Write(buf, wxString(m_fileHistory[i])); + else + config.Write(buf, wxEmptyString); + } +} +#endif // wxUSE_CONFIG + +void wxFileHistory::AddFilesToMenu() +{ + if (m_fileHistoryN > 0) + { + wxList::compatibility_iterator node = m_fileMenus.GetFirst(); + while (node) + { + wxMenu* menu = (wxMenu*) node->GetData(); + if (menu->GetMenuItemCount()) + { + menu->AppendSeparator(); + } + + size_t i; + for (i = 0; i < m_fileHistoryN; i++) + { + if (m_fileHistory[i]) + { + wxString buf; + buf.Printf(s_MRUEntryFormat, i+1, m_fileHistory[i]); + menu->Append(m_idBase+i, buf); + } + } + node = node->GetNext(); + } + } +} + +void wxFileHistory::AddFilesToMenu(wxMenu* menu) +{ + if (m_fileHistoryN > 0) + { + if (menu->GetMenuItemCount()) + { + menu->AppendSeparator(); + } + + size_t i; + for (i = 0; i < m_fileHistoryN; i++) + { + if (m_fileHistory[i]) + { + wxString buf; + buf.Printf(s_MRUEntryFormat, i+1, m_fileHistory[i]); + menu->Append(m_idBase+i, buf); + } + } + } +} + +// ---------------------------------------------------------------------------- +// Permits compatibility with existing file formats and functions that +// manipulate files directly +// ---------------------------------------------------------------------------- + +#if wxUSE_STD_IOSTREAM + +bool wxTransferFileToStream(const wxString& filename, wxSTD ostream& stream) +{ + wxFFile file(filename, _T("rb")); + if ( !file.IsOpened() ) + return false; + + char buf[4096]; + + size_t nRead; + do + { + nRead = file.Read(buf, WXSIZEOF(buf)); + if ( file.Error() ) + return false; + + stream.write(buf, nRead); + if ( !stream ) + return false; + } + while ( !file.Eof() ); + + return true; +} + +bool wxTransferStreamToFile(wxSTD istream& stream, const wxString& filename) +{ + wxFFile file(filename, _T("wb")); + if ( !file.IsOpened() ) + return false; + + char buf[4096]; + do + { + stream.read(buf, WXSIZEOF(buf)); + if ( !stream.bad() ) // fail may be set on EOF, don't use operator!() + { + if ( !file.Write(buf, stream.gcount()) ) + return false; + } + } + while ( !stream.eof() ); + + return true; +} + +#else // !wxUSE_STD_IOSTREAM + +bool wxTransferFileToStream(const wxString& filename, wxOutputStream& stream) +{ + wxFFile file(filename, _T("rb")); + if ( !file.IsOpened() ) + return false; + + char buf[4096]; + + size_t nRead; + do + { + nRead = file.Read(buf, WXSIZEOF(buf)); + if ( file.Error() ) + return false; + + stream.Write(buf, nRead); + if ( !stream ) + return false; + } + while ( !file.Eof() ); + + return true; +} + +bool wxTransferStreamToFile(wxInputStream& stream, const wxString& filename) +{ + wxFFile file(filename, _T("wb")); + if ( !file.IsOpened() ) + return false; + + char buf[4096]; + for ( ;; ) + { + stream.Read(buf, WXSIZEOF(buf)); + + const size_t nRead = stream.LastRead(); + if ( !nRead ) + { + if ( stream.Eof() ) + break; + + return false; + } + + if ( !file.Write(buf, nRead) ) + return false; + } + + return true; +} + +#endif // wxUSE_STD_IOSTREAM/!wxUSE_STD_IOSTREAM + +#endif // wxUSE_DOC_VIEW_ARCHITECTURE diff --git a/Externals/wxWidgets/src/common/dpycmn.cpp b/Externals/wxWidgets/src/common/dpycmn.cpp index 5d8d3e7067..4cc0e44352 100644 --- a/Externals/wxWidgets/src/common/dpycmn.cpp +++ b/Externals/wxWidgets/src/common/dpycmn.cpp @@ -1,269 +1,269 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: src/common/dpycmn.cpp -// Purpose: wxDisplay and wxDisplayImplSingle implementation -// Author: Vadim Zeitlin -// Modified by: -// Created: 01.03.03 -// RCS-ID: $Id: dpycmn.cpp 41548 2006-10-02 05:38:05Z PC $ -// Copyright: (c) 2003-2006 Vadim Zeitlin -// License: wxWindows licence -/////////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#ifndef WX_PRECOMP - #include "wx/gdicmn.h" - #include "wx/window.h" - #include "wx/module.h" -#endif //WX_PRECOMP - -#include "wx/display.h" -#include "wx/display_impl.h" - -#if wxUSE_DISPLAY - -#include "wx/arrimpl.cpp" -WX_DEFINE_OBJARRAY(wxArrayVideoModes) - -const wxVideoMode wxDefaultVideoMode; - -#endif // wxUSE_DISPLAY - -// ---------------------------------------------------------------------------- -// globals -// ---------------------------------------------------------------------------- - -// the factory object used by wxDisplay -// -// created on demand and destroyed by wxDisplayModule -static wxDisplayFactory *gs_factory = NULL; - -// ---------------------------------------------------------------------------- -// wxDisplayImplSingle: trivial implementation working for main display only -// ---------------------------------------------------------------------------- - -class WXDLLEXPORT wxDisplayImplSingle : public wxDisplayImpl -{ -public: - wxDisplayImplSingle() : wxDisplayImpl(0) { } - - virtual wxRect GetGeometry() const - { - wxRect r; - wxDisplaySize(&r.width, &r.height); - return r; - } - - virtual wxRect GetClientArea() const { return wxGetClientDisplayRect(); } - - virtual wxString GetName() const { return wxString(); } - -#if wxUSE_DISPLAY - // no video modes support for us, provide just the stubs - - virtual wxArrayVideoModes GetModes(const wxVideoMode& WXUNUSED(mode)) const - { - return wxArrayVideoModes(); - } - - virtual wxVideoMode GetCurrentMode() const { return wxVideoMode(); } - - virtual bool ChangeMode(const wxVideoMode& WXUNUSED(mode)) { return false; } -#endif // wxUSE_DISPLAY - - - DECLARE_NO_COPY_CLASS(wxDisplayImplSingle) -}; - -// ---------------------------------------------------------------------------- -// wxDisplayModule is used to cleanup gs_factory -// ---------------------------------------------------------------------------- - -class wxDisplayModule : public wxModule -{ -public: - virtual bool OnInit() { return true; } - virtual void OnExit() - { - if ( gs_factory ) - { - delete gs_factory; - gs_factory = NULL; - } - } - - DECLARE_DYNAMIC_CLASS(wxDisplayModule) -}; - -IMPLEMENT_DYNAMIC_CLASS(wxDisplayModule, wxModule) - -// ============================================================================ -// wxDisplay implementation -// ============================================================================ - -// ---------------------------------------------------------------------------- -// ctor/dtor -// ---------------------------------------------------------------------------- - -wxDisplay::wxDisplay(unsigned n) -{ - wxASSERT_MSG( n < GetCount(), - wxT("An invalid index was passed to wxDisplay") ); - - m_impl = Factory().CreateDisplay(n); -} - -wxDisplay::~wxDisplay() -{ - delete m_impl; -} - -// ---------------------------------------------------------------------------- -// static functions forwarded to wxDisplayFactory -// ---------------------------------------------------------------------------- - -/* static */ unsigned wxDisplay::GetCount() -{ - return Factory().GetCount(); -} - -/* static */ int wxDisplay::GetFromPoint(const wxPoint& pt) -{ - return Factory().GetFromPoint(pt); -} - -/* static */ int wxDisplay::GetFromWindow(wxWindow *window) -{ - wxCHECK_MSG( window, wxNOT_FOUND, _T("invalid window") ); - - return Factory().GetFromWindow(window); -} - -// ---------------------------------------------------------------------------- -// functions forwarded to wxDisplayImpl -// ---------------------------------------------------------------------------- - -wxRect wxDisplay::GetGeometry() const -{ - wxCHECK_MSG( IsOk(), wxRect(), _T("invalid wxDisplay object") ); - - return m_impl->GetGeometry(); -} - -wxRect wxDisplay::GetClientArea() const -{ - wxCHECK_MSG( IsOk(), wxRect(), _T("invalid wxDisplay object") ); - - return m_impl->GetClientArea(); -} - -wxString wxDisplay::GetName() const -{ - wxCHECK_MSG( IsOk(), wxString(), _T("invalid wxDisplay object") ); - - return m_impl->GetName(); -} - -bool wxDisplay::IsPrimary() const -{ - return m_impl && m_impl->GetIndex() == 0; -} - -#if wxUSE_DISPLAY - -wxArrayVideoModes wxDisplay::GetModes(const wxVideoMode& mode) const -{ - wxCHECK_MSG( IsOk(), wxArrayVideoModes(), _T("invalid wxDisplay object") ); - - return m_impl->GetModes(mode); -} - -wxVideoMode wxDisplay::GetCurrentMode() const -{ - wxCHECK_MSG( IsOk(), wxVideoMode(), _T("invalid wxDisplay object") ); - - return m_impl->GetCurrentMode(); -} - -bool wxDisplay::ChangeMode(const wxVideoMode& mode) -{ - wxCHECK_MSG( IsOk(), false, _T("invalid wxDisplay object") ); - - return m_impl->ChangeMode(mode); -} - -#endif // wxUSE_DIRECTDRAW - -// ---------------------------------------------------------------------------- -// static functions implementation -// ---------------------------------------------------------------------------- - -// if wxUSE_DISPLAY == 1 this is implemented in port-specific code -#if !wxUSE_DISPLAY - -/* static */ wxDisplayFactory *wxDisplay::CreateFactory() -{ - return new wxDisplayFactorySingle; -} - -#endif // !wxUSE_DISPLAY - -/* static */ wxDisplayFactory& wxDisplay::Factory() -{ - if ( !gs_factory ) - { - gs_factory = CreateFactory(); - } - - return *gs_factory; -} - -// ============================================================================ -// wxDisplayFactory implementation -// ============================================================================ - -int wxDisplayFactory::GetFromWindow(wxWindow *window) -{ - // consider that the window belongs to the display containing its centre - const wxRect r(window->GetRect()); - return GetFromPoint(wxPoint(r.x + r.width/2, r.y + r.height/2)); -} - -// ============================================================================ -// wxDisplayFactorySingle implementation -// ============================================================================ - -/* static */ -wxDisplayImpl *wxDisplayFactorySingle::CreateDisplay(unsigned n) -{ - // we recognize the main display only - return n != 0 ? NULL : new wxDisplayImplSingle; -} - -int wxDisplayFactorySingle::GetFromPoint(const wxPoint& pt) -{ - if ( pt.x >= 0 && pt.y >= 0 ) - { - int w, h; - wxDisplaySize(&w, &h); - - if ( pt.x < w && pt.y < h ) - return 0; - } - - // the point is outside of the screen - return wxNOT_FOUND; -} +/////////////////////////////////////////////////////////////////////////////// +// Name: src/common/dpycmn.cpp +// Purpose: wxDisplay and wxDisplayImplSingle implementation +// Author: Vadim Zeitlin +// Modified by: +// Created: 01.03.03 +// RCS-ID: $Id: dpycmn.cpp 41548 2006-10-02 05:38:05Z PC $ +// Copyright: (c) 2003-2006 Vadim Zeitlin +// License: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#ifndef WX_PRECOMP + #include "wx/gdicmn.h" + #include "wx/window.h" + #include "wx/module.h" +#endif //WX_PRECOMP + +#include "wx/display.h" +#include "wx/display_impl.h" + +#if wxUSE_DISPLAY + +#include "wx/arrimpl.cpp" +WX_DEFINE_OBJARRAY(wxArrayVideoModes) + +const wxVideoMode wxDefaultVideoMode; + +#endif // wxUSE_DISPLAY + +// ---------------------------------------------------------------------------- +// globals +// ---------------------------------------------------------------------------- + +// the factory object used by wxDisplay +// +// created on demand and destroyed by wxDisplayModule +static wxDisplayFactory *gs_factory = NULL; + +// ---------------------------------------------------------------------------- +// wxDisplayImplSingle: trivial implementation working for main display only +// ---------------------------------------------------------------------------- + +class WXDLLEXPORT wxDisplayImplSingle : public wxDisplayImpl +{ +public: + wxDisplayImplSingle() : wxDisplayImpl(0) { } + + virtual wxRect GetGeometry() const + { + wxRect r; + wxDisplaySize(&r.width, &r.height); + return r; + } + + virtual wxRect GetClientArea() const { return wxGetClientDisplayRect(); } + + virtual wxString GetName() const { return wxString(); } + +#if wxUSE_DISPLAY + // no video modes support for us, provide just the stubs + + virtual wxArrayVideoModes GetModes(const wxVideoMode& WXUNUSED(mode)) const + { + return wxArrayVideoModes(); + } + + virtual wxVideoMode GetCurrentMode() const { return wxVideoMode(); } + + virtual bool ChangeMode(const wxVideoMode& WXUNUSED(mode)) { return false; } +#endif // wxUSE_DISPLAY + + + DECLARE_NO_COPY_CLASS(wxDisplayImplSingle) +}; + +// ---------------------------------------------------------------------------- +// wxDisplayModule is used to cleanup gs_factory +// ---------------------------------------------------------------------------- + +class wxDisplayModule : public wxModule +{ +public: + virtual bool OnInit() { return true; } + virtual void OnExit() + { + if ( gs_factory ) + { + delete gs_factory; + gs_factory = NULL; + } + } + + DECLARE_DYNAMIC_CLASS(wxDisplayModule) +}; + +IMPLEMENT_DYNAMIC_CLASS(wxDisplayModule, wxModule) + +// ============================================================================ +// wxDisplay implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// ctor/dtor +// ---------------------------------------------------------------------------- + +wxDisplay::wxDisplay(unsigned n) +{ + wxASSERT_MSG( n < GetCount(), + wxT("An invalid index was passed to wxDisplay") ); + + m_impl = Factory().CreateDisplay(n); +} + +wxDisplay::~wxDisplay() +{ + delete m_impl; +} + +// ---------------------------------------------------------------------------- +// static functions forwarded to wxDisplayFactory +// ---------------------------------------------------------------------------- + +/* static */ unsigned wxDisplay::GetCount() +{ + return Factory().GetCount(); +} + +/* static */ int wxDisplay::GetFromPoint(const wxPoint& pt) +{ + return Factory().GetFromPoint(pt); +} + +/* static */ int wxDisplay::GetFromWindow(wxWindow *window) +{ + wxCHECK_MSG( window, wxNOT_FOUND, _T("invalid window") ); + + return Factory().GetFromWindow(window); +} + +// ---------------------------------------------------------------------------- +// functions forwarded to wxDisplayImpl +// ---------------------------------------------------------------------------- + +wxRect wxDisplay::GetGeometry() const +{ + wxCHECK_MSG( IsOk(), wxRect(), _T("invalid wxDisplay object") ); + + return m_impl->GetGeometry(); +} + +wxRect wxDisplay::GetClientArea() const +{ + wxCHECK_MSG( IsOk(), wxRect(), _T("invalid wxDisplay object") ); + + return m_impl->GetClientArea(); +} + +wxString wxDisplay::GetName() const +{ + wxCHECK_MSG( IsOk(), wxString(), _T("invalid wxDisplay object") ); + + return m_impl->GetName(); +} + +bool wxDisplay::IsPrimary() const +{ + return m_impl && m_impl->GetIndex() == 0; +} + +#if wxUSE_DISPLAY + +wxArrayVideoModes wxDisplay::GetModes(const wxVideoMode& mode) const +{ + wxCHECK_MSG( IsOk(), wxArrayVideoModes(), _T("invalid wxDisplay object") ); + + return m_impl->GetModes(mode); +} + +wxVideoMode wxDisplay::GetCurrentMode() const +{ + wxCHECK_MSG( IsOk(), wxVideoMode(), _T("invalid wxDisplay object") ); + + return m_impl->GetCurrentMode(); +} + +bool wxDisplay::ChangeMode(const wxVideoMode& mode) +{ + wxCHECK_MSG( IsOk(), false, _T("invalid wxDisplay object") ); + + return m_impl->ChangeMode(mode); +} + +#endif // wxUSE_DIRECTDRAW + +// ---------------------------------------------------------------------------- +// static functions implementation +// ---------------------------------------------------------------------------- + +// if wxUSE_DISPLAY == 1 this is implemented in port-specific code +#if !wxUSE_DISPLAY + +/* static */ wxDisplayFactory *wxDisplay::CreateFactory() +{ + return new wxDisplayFactorySingle; +} + +#endif // !wxUSE_DISPLAY + +/* static */ wxDisplayFactory& wxDisplay::Factory() +{ + if ( !gs_factory ) + { + gs_factory = CreateFactory(); + } + + return *gs_factory; +} + +// ============================================================================ +// wxDisplayFactory implementation +// ============================================================================ + +int wxDisplayFactory::GetFromWindow(wxWindow *window) +{ + // consider that the window belongs to the display containing its centre + const wxRect r(window->GetRect()); + return GetFromPoint(wxPoint(r.x + r.width/2, r.y + r.height/2)); +} + +// ============================================================================ +// wxDisplayFactorySingle implementation +// ============================================================================ + +/* static */ +wxDisplayImpl *wxDisplayFactorySingle::CreateDisplay(unsigned n) +{ + // we recognize the main display only + return n != 0 ? NULL : new wxDisplayImplSingle; +} + +int wxDisplayFactorySingle::GetFromPoint(const wxPoint& pt) +{ + if ( pt.x >= 0 && pt.y >= 0 ) + { + int w, h; + wxDisplaySize(&w, &h); + + if ( pt.x < w && pt.y < h ) + return 0; + } + + // the point is outside of the screen + return wxNOT_FOUND; +} diff --git a/Externals/wxWidgets/src/common/dseldlg.cpp b/Externals/wxWidgets/src/common/dseldlg.cpp index 060dcf326a..04944fc65e 100644 --- a/Externals/wxWidgets/src/common/dseldlg.cpp +++ b/Externals/wxWidgets/src/common/dseldlg.cpp @@ -1,55 +1,55 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: src/common/dseldlg.cpp -// Purpose: implementation of ::wxDirSelector() -// Author: Paul Thiessen -// Modified by: -// Created: 20.02.01 -// RCS-ID: $Id: dseldlg.cpp 39613 2006-06-07 11:44:19Z ABX $ -// Copyright: (c) 2001 wxWidgets team -// License: wxWindows licence -/////////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_DIRDLG - -#include "wx/dirdlg.h" - -#ifndef WX_PRECOMP -#endif //WX_PRECOMP - -// ============================================================================ -// implementation -// ============================================================================ - -wxString wxDirSelector(const wxString& message, - const wxString& defaultPath, - long style, - const wxPoint& pos, - wxWindow *parent) -{ - wxString path; - - wxDirDialog dirDialog(parent, message, defaultPath, style, pos); - if ( dirDialog.ShowModal() == wxID_OK ) - { - path = dirDialog.GetPath(); - } - - return path; -} - -#endif // wxUSE_DIRDLG +/////////////////////////////////////////////////////////////////////////////// +// Name: src/common/dseldlg.cpp +// Purpose: implementation of ::wxDirSelector() +// Author: Paul Thiessen +// Modified by: +// Created: 20.02.01 +// RCS-ID: $Id: dseldlg.cpp 39613 2006-06-07 11:44:19Z ABX $ +// Copyright: (c) 2001 wxWidgets team +// License: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_DIRDLG + +#include "wx/dirdlg.h" + +#ifndef WX_PRECOMP +#endif //WX_PRECOMP + +// ============================================================================ +// implementation +// ============================================================================ + +wxString wxDirSelector(const wxString& message, + const wxString& defaultPath, + long style, + const wxPoint& pos, + wxWindow *parent) +{ + wxString path; + + wxDirDialog dirDialog(parent, message, defaultPath, style, pos); + if ( dirDialog.ShowModal() == wxID_OK ) + { + path = dirDialog.GetPath(); + } + + return path; +} + +#endif // wxUSE_DIRDLG diff --git a/Externals/wxWidgets/src/common/dummy.cpp b/Externals/wxWidgets/src/common/dummy.cpp index 34719e6741..db74ef7c68 100644 --- a/Externals/wxWidgets/src/common/dummy.cpp +++ b/Externals/wxWidgets/src/common/dummy.cpp @@ -1,32 +1,32 @@ -/* - * File: src/common/dummy.cpp - * Purpose: See below - * Author: Julian Smart - * Created: 1993 - * Updated: - * Copyright: (c) 1993, AIAI, University of Edinburgh - */ - -/* A dummy file to include wx.h. If precompiling wx.h, - * always start by compiling this and producing the PCH file. - * Then subsequent source files use the PCH file. - * - * If precompiling wx.h for wxWidgets and derived apps, - * link dummy.obj with your program. - * - * This will produce a big PCH file. - */ - -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#ifdef __WXMSW__ - #include "wx/msw/msvcrt.h" -#endif - -#ifdef __VISAGECPP__ - char wxDummyChar = 0; -#endif +/* + * File: src/common/dummy.cpp + * Purpose: See below + * Author: Julian Smart + * Created: 1993 + * Updated: + * Copyright: (c) 1993, AIAI, University of Edinburgh + */ + +/* A dummy file to include wx.h. If precompiling wx.h, + * always start by compiling this and producing the PCH file. + * Then subsequent source files use the PCH file. + * + * If precompiling wx.h for wxWidgets and derived apps, + * link dummy.obj with your program. + * + * This will produce a big PCH file. + */ + +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#ifdef __WXMSW__ + #include "wx/msw/msvcrt.h" +#endif + +#ifdef __VISAGECPP__ + char wxDummyChar = 0; +#endif diff --git a/Externals/wxWidgets/src/common/dynarray.cpp b/Externals/wxWidgets/src/common/dynarray.cpp index bdde0eafea..b5f2b4bc7d 100644 --- a/Externals/wxWidgets/src/common/dynarray.cpp +++ b/Externals/wxWidgets/src/common/dynarray.cpp @@ -1,527 +1,527 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: src/common/dynarray.cpp -// Purpose: implementation of wxBaseArray class -// Author: Vadim Zeitlin -// Modified by: -// Created: 12.09.97 -// RCS-ID: $Id: dynarray.cpp 43030 2006-11-04 12:51:01Z VZ $ -// Copyright: (c) 1998 Vadim Zeitlin -// Licence: wxWindows licence -/////////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// headers -// ============================================================================ - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#ifndef WX_PRECOMP - #include "wx/dynarray.h" - #include "wx/intl.h" -#endif //WX_PRECOMP - -#include -#include // for memmove - -// we cast the value to long from which we cast it to void * in IndexForInsert: -// this can't work if the pointers are not big enough -wxCOMPILE_TIME_ASSERT( sizeof(wxUIntPtr) <= sizeof(void *), - wxArraySizeOfPtrLessSizeOfLong ); // < 32 symbols - -// ============================================================================ -// constants -// ============================================================================ - -// size increment = max(50% of current size, ARRAY_MAXSIZE_INCREMENT) -#define ARRAY_MAXSIZE_INCREMENT 4096 - -// ============================================================================ -// implementation -// ============================================================================ - -// ---------------------------------------------------------------------------- -// wxBaseArray - dynamic array of 'T's -// ---------------------------------------------------------------------------- - -#define _WX_DEFINE_BASEARRAY_COMMON(T, name) \ -/* searches the array for an item (forward or backwards) */ \ -int name::Index(T lItem, bool bFromEnd) const \ -{ \ - if ( bFromEnd ) { \ - if ( size() > 0 ) { \ - size_t n = size(); \ - do { \ - if ( (*this)[--n] == lItem ) \ - return n; \ - } \ - while ( n != 0 ); \ - } \ - } \ - else { \ - for( size_t n = 0; n < size(); n++ ) { \ - if( (*this)[n] == lItem ) \ - return n; \ - } \ - } \ - \ - return wxNOT_FOUND; \ -} \ - \ -/* add item assuming the array is sorted with fnCompare function */ \ -size_t name::Add(T lItem, CMPFUNC fnCompare) \ -{ \ - size_t idx = IndexForInsert(lItem, fnCompare); \ - Insert(lItem, idx); \ - return idx; \ -} - -#if wxUSE_STL - -#define _WX_DEFINE_BASEARRAY_NOCOMMON(T, name) \ -size_t name::IndexForInsert(T lItem, CMPFUNC fnCompare) const \ -{ \ - Predicate p((SCMPFUNC)fnCompare); \ - const_iterator it = std::lower_bound(begin(), end(), lItem, p); \ - return it - begin(); \ -} \ - \ -int name::Index(T lItem, CMPFUNC fnCompare) const \ -{ \ - Predicate p((SCMPFUNC)fnCompare); \ - const_iterator it = std::lower_bound(begin(), end(), lItem, p); \ - return (it != end() && !p(lItem, *it)) ? \ - (int)(it - begin()) : wxNOT_FOUND; \ -} \ - \ -void name::Shrink() \ -{ \ - name tmp(*this); \ - swap(tmp); \ -} - -#else // if !wxUSE_STL - -#define _WX_DEFINE_BASEARRAY_NOCOMMON(T, name) \ -/* ctor */ \ -name::name() \ -{ \ - m_nSize = \ - m_nCount = 0; \ - m_pItems = (T *)NULL; \ -} \ - \ -/* copy ctor */ \ -name::name(const name& src) \ -{ \ - m_nSize = /* not src.m_nSize to save memory */ \ - m_nCount = src.m_nCount; \ - \ - if ( m_nSize != 0 ) { \ - m_pItems = new T[m_nSize]; \ - /* only copy if allocation succeeded */ \ - if ( m_pItems ) { \ - memcpy(m_pItems, src.m_pItems, m_nCount*sizeof(T)); \ - } \ - else { \ - m_nSize = 0; \ - } \ - } \ - else \ - m_pItems = (T *) NULL; \ -} \ - \ -/* assignment operator */ \ -name& name::operator=(const name& src) \ -{ \ - wxDELETEA(m_pItems); \ - \ - m_nSize = /* not src.m_nSize to save memory */ \ - m_nCount = src.m_nCount; \ - \ - if ( m_nSize != 0 ){ \ - m_pItems = new T[m_nSize]; \ - /* only copy if allocation succeeded */ \ - if ( m_pItems ) { \ - memcpy(m_pItems, src.m_pItems, m_nCount*sizeof(T)); \ - } \ - else { \ - m_nSize = 0; \ - } \ - } \ - else \ - m_pItems = (T *) NULL; \ - \ - return *this; \ -} \ - \ -/* allocate new buffer of the given size and move our data to it */ \ -bool name::Realloc(size_t nSize) \ -{ \ - T *pNew = new T[nSize]; \ - /* only grow if allocation succeeded */ \ - if ( !pNew ) \ - return false; \ - \ - m_nSize = nSize; \ - /* copy data to new location */ \ - memcpy(pNew, m_pItems, m_nCount*sizeof(T)); \ - delete [] m_pItems; \ - m_pItems = pNew; \ - \ - return true; \ -} \ - \ -/* grow the array */ \ -void name::Grow(size_t nIncrement) \ -{ \ - /* only do it if no more place */ \ - if( (m_nCount == m_nSize) || ((m_nSize - m_nCount) < nIncrement) ) { \ - if( m_nSize == 0 ) { \ - /* was empty, determine initial size */ \ - size_t size = WX_ARRAY_DEFAULT_INITIAL_SIZE; \ - if (size < nIncrement) size = nIncrement; \ - /* allocate some memory */ \ - m_pItems = new T[size]; \ - /* only grow if allocation succeeded */ \ - if ( m_pItems ) { \ - m_nSize = size; \ - } \ - } \ - else \ - { \ - /* add at least 50% but not too much */ \ - size_t ndefIncrement = m_nSize < WX_ARRAY_DEFAULT_INITIAL_SIZE \ - ? WX_ARRAY_DEFAULT_INITIAL_SIZE : m_nSize >> 1; \ - if ( ndefIncrement > ARRAY_MAXSIZE_INCREMENT ) \ - ndefIncrement = ARRAY_MAXSIZE_INCREMENT; \ - if ( nIncrement < ndefIncrement ) \ - nIncrement = ndefIncrement; \ - Realloc(m_nSize + nIncrement); \ - } \ - } \ -} \ - \ -/* make sure that the array has at least count elements */ \ -void name::SetCount(size_t count, T defval) \ -{ \ - if ( m_nSize < count ) \ - { \ - /* need to realloc memory: don't overallocate it here as if */ \ - /* SetCount() is called, it probably means that the caller */ \ - /* knows in advance how many elements there will be in the */ \ - /* array and so it won't be necessary to realloc it later */ \ - if ( !Realloc(count) ) \ - { \ - /* out of memory -- what can we do? */ \ - return; \ - } \ - } \ - \ - /* add new elements if we extend the array */ \ - while ( m_nCount < count ) \ - { \ - m_pItems[m_nCount++] = defval; \ - } \ -} \ - \ -/* dtor */ \ -name::~name() \ -{ \ - wxDELETEA(m_pItems); \ -} \ - \ -/* clears the list */ \ -void name::Clear() \ -{ \ - m_nSize = \ - m_nCount = 0; \ - \ - wxDELETEA(m_pItems); \ -} \ - \ -/* minimizes the memory usage by freeing unused memory */ \ -void name::Shrink() \ -{ \ - /* only do it if we have some memory to free */ \ - if( m_nCount < m_nSize ) { \ - /* allocates exactly as much memory as we need */ \ - T *pNew = new T[m_nCount]; \ - /* only shrink if allocation succeeded */ \ - if ( pNew ) { \ - /* copy data to new location */ \ - memcpy(pNew, m_pItems, m_nCount*sizeof(T)); \ - delete [] m_pItems; \ - m_pItems = pNew; \ - \ - /* update the size of the new block */ \ - m_nSize = m_nCount; \ - } \ - /* else: don't do anything, better keep old memory block! */ \ - } \ -} \ - \ -/* add item at the end */ \ -void name::Add(T lItem, size_t nInsert) \ -{ \ - if (nInsert == 0) \ - return; \ - Grow(nInsert); \ - for (size_t i = 0; i < nInsert; i++) \ - m_pItems[m_nCount++] = lItem; \ -} \ - \ -/* add item at the given position */ \ -void name::Insert(T lItem, size_t nIndex, size_t nInsert) \ -{ \ - wxCHECK_RET( nIndex <= m_nCount, wxT("bad index in wxArray::Insert") ); \ - wxCHECK_RET( m_nCount <= m_nCount + nInsert, \ - wxT("array size overflow in wxArray::Insert") ); \ - \ - if (nInsert == 0) \ - return; \ - Grow(nInsert); \ - \ - memmove(&m_pItems[nIndex + nInsert], &m_pItems[nIndex], \ - (m_nCount - nIndex)*sizeof(T)); \ - for (size_t i = 0; i < nInsert; i++) \ - m_pItems[nIndex + i] = lItem; \ - m_nCount += nInsert; \ -} \ - \ -/* search for a place to insert item into sorted array (binary search) */ \ -size_t name::IndexForInsert(T lItem, CMPFUNC fnCompare) const \ -{ \ - size_t i, \ - lo = 0, \ - hi = m_nCount; \ - int res; \ - \ - while ( lo < hi ) { \ - i = (lo + hi)/2; \ - \ - res = (*fnCompare)((const void *)(wxUIntPtr)lItem, \ - (const void *)(wxUIntPtr)(m_pItems[i])); \ - if ( res < 0 ) \ - hi = i; \ - else if ( res > 0 ) \ - lo = i + 1; \ - else { \ - lo = i; \ - break; \ - } \ - } \ - \ - return lo; \ -} \ - \ -/* search for an item in a sorted array (binary search) */ \ -int name::Index(T lItem, CMPFUNC fnCompare) const \ -{ \ - size_t n = IndexForInsert(lItem, fnCompare); \ - \ - return (n >= m_nCount || \ - (*fnCompare)((const void *)(wxUIntPtr)lItem, \ - ((const void *)(wxUIntPtr)m_pItems[n]))) \ - ? wxNOT_FOUND \ - : (int)n; \ -} \ - \ -/* removes item from array (by index) */ \ -void name::RemoveAt(size_t nIndex, size_t nRemove) \ -{ \ - wxCHECK_RET( nIndex < m_nCount, wxT("bad index in wxArray::RemoveAt") ); \ - wxCHECK_RET( nIndex + nRemove <= m_nCount, \ - wxT("removing too many elements in wxArray::RemoveAt") ); \ - \ - memmove(&m_pItems[nIndex], &m_pItems[nIndex + nRemove], \ - (m_nCount - nIndex - nRemove)*sizeof(T)); \ - m_nCount -= nRemove; \ -} \ - \ -/* removes item from array (by value) */ \ -void name::Remove(T lItem) \ -{ \ - int iIndex = Index(lItem); \ - \ - wxCHECK_RET( iIndex != wxNOT_FOUND, \ - wxT("removing inexistent item in wxArray::Remove") ); \ - \ - RemoveAt((size_t)iIndex); \ -} \ - \ -/* sort array elements using passed comparaison function */ \ -void name::Sort(CMPFUNC fCmp) \ -{ \ - qsort(m_pItems, m_nCount, sizeof(T), fCmp); \ -} \ - \ -void name::assign(const_iterator first, const_iterator last) \ -{ \ - clear(); \ - reserve(last - first); \ - for(; first != last; ++first) \ - push_back(*first); \ -} \ - \ -void name::assign(size_type n, const_reference v) \ -{ \ - clear(); \ - reserve(n); \ - for( size_type i = 0; i < n; ++i ) \ - push_back(v); \ -} \ - \ -void name::insert(iterator it, const_iterator first, const_iterator last) \ -{ \ - size_t nInsert = last - first, nIndex = it - begin(); \ - if (nInsert == 0) \ - return; \ - Grow(nInsert); \ - \ - memmove(&m_pItems[nIndex + nInsert], &m_pItems[nIndex], \ - (m_nCount - nIndex)*sizeof(T)); \ - for (size_t i = 0; i < nInsert; ++i, ++it, ++first) \ - *it = *first; \ - m_nCount += nInsert; \ -} - -#endif - -#define _WX_DEFINE_BASEARRAY(T, name) \ - _WX_DEFINE_BASEARRAY_COMMON(T, name) \ - _WX_DEFINE_BASEARRAY_NOCOMMON(T, name) - -#ifdef __INTELC__ - #pragma warning(push) - #pragma warning(disable: 1684) - #pragma warning(disable: 1572) -#endif - -_WX_DEFINE_BASEARRAY(const void *, wxBaseArrayPtrVoid) -_WX_DEFINE_BASEARRAY(char, wxBaseArrayChar) -_WX_DEFINE_BASEARRAY(short, wxBaseArrayShort) -_WX_DEFINE_BASEARRAY(int, wxBaseArrayInt) -_WX_DEFINE_BASEARRAY(long, wxBaseArrayLong) -_WX_DEFINE_BASEARRAY(size_t, wxBaseArraySizeT) -_WX_DEFINE_BASEARRAY(double, wxBaseArrayDouble) - -#ifdef __INTELC__ - #pragma warning(pop) -#endif - -#if wxUSE_STL -#include "wx/arrstr.h" - -#include "wx/beforestd.h" -#include -#include "wx/afterstd.h" - -_WX_DEFINE_BASEARRAY(wxString, wxBaseArrayStringBase) - -// some compilers (Sun CC being the only known example) distinguish between -// extern "C" functions and the functions with C++ linkage and ptr_fun and -// wxStringCompareLess can't take wxStrcmp/wxStricmp directly as arguments in -// this case, we need the wrappers below to make this work -inline int wxStrcmpCppWrapper(const wxChar *p, const wxChar *q) -{ - return wxStrcmp(p, q); -} - -inline int wxStricmpCppWrapper(const wxChar *p, const wxChar *q) -{ - return wxStricmp(p, q); -} - -int wxArrayString::Index(const wxChar* sz, bool bCase, bool WXUNUSED(bFromEnd)) const -{ - wxArrayString::const_iterator it; - - if (bCase) - { - it = std::find_if(begin(), end(), - std::not1( - std::bind2nd( - std::ptr_fun(wxStrcmpCppWrapper), sz))); - } - else // !bCase - { - it = std::find_if(begin(), end(), - std::not1( - std::bind2nd( - std::ptr_fun(wxStricmpCppWrapper), sz))); - } - - return it == end() ? wxNOT_FOUND : it - begin(); -} - -template -class wxStringCompareLess -{ -public: - wxStringCompareLess(F f) : m_f(f) { } - bool operator()(const wxChar* s1, const wxChar* s2) - { return m_f(s1, s2) < 0; } - bool operator()(const wxString& s1, const wxString& s2) - { return m_f(s1, s2) < 0; } -private: - F m_f; -}; - -template -wxStringCompareLess wxStringCompare(F f) -{ - return wxStringCompareLess(f); -} - -void wxArrayString::Sort(CompareFunction function) -{ - std::sort(begin(), end(), wxStringCompare(function)); -} - -void wxArrayString::Sort(bool reverseOrder) -{ - if (reverseOrder) - { - std::sort(begin(), end(), std::greater()); - } - else - { - std::sort(begin(), end()); - } -} - -int wxSortedArrayString::Index(const wxChar* sz, bool bCase, bool WXUNUSED(bFromEnd)) const -{ - wxSortedArrayString::const_iterator it; - wxString s(sz); - - if (bCase) - it = std::lower_bound(begin(), end(), s, - wxStringCompare(wxStrcmpCppWrapper)); - else - it = std::lower_bound(begin(), end(), s, - wxStringCompare(wxStricmpCppWrapper)); - - if (it == end()) - return wxNOT_FOUND; - - if (bCase) - { - if (wxStrcmp(it->c_str(), sz) != 0) - return wxNOT_FOUND; - } - else - { - if (wxStricmp(it->c_str(), sz) != 0) - return wxNOT_FOUND; - } - - return it - begin(); -} - -#endif +/////////////////////////////////////////////////////////////////////////////// +// Name: src/common/dynarray.cpp +// Purpose: implementation of wxBaseArray class +// Author: Vadim Zeitlin +// Modified by: +// Created: 12.09.97 +// RCS-ID: $Id: dynarray.cpp 43030 2006-11-04 12:51:01Z VZ $ +// Copyright: (c) 1998 Vadim Zeitlin +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// headers +// ============================================================================ + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#ifndef WX_PRECOMP + #include "wx/dynarray.h" + #include "wx/intl.h" +#endif //WX_PRECOMP + +#include +#include // for memmove + +// we cast the value to long from which we cast it to void * in IndexForInsert: +// this can't work if the pointers are not big enough +wxCOMPILE_TIME_ASSERT( sizeof(wxUIntPtr) <= sizeof(void *), + wxArraySizeOfPtrLessSizeOfLong ); // < 32 symbols + +// ============================================================================ +// constants +// ============================================================================ + +// size increment = max(50% of current size, ARRAY_MAXSIZE_INCREMENT) +#define ARRAY_MAXSIZE_INCREMENT 4096 + +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// wxBaseArray - dynamic array of 'T's +// ---------------------------------------------------------------------------- + +#define _WX_DEFINE_BASEARRAY_COMMON(T, name) \ +/* searches the array for an item (forward or backwards) */ \ +int name::Index(T lItem, bool bFromEnd) const \ +{ \ + if ( bFromEnd ) { \ + if ( size() > 0 ) { \ + size_t n = size(); \ + do { \ + if ( (*this)[--n] == lItem ) \ + return n; \ + } \ + while ( n != 0 ); \ + } \ + } \ + else { \ + for( size_t n = 0; n < size(); n++ ) { \ + if( (*this)[n] == lItem ) \ + return n; \ + } \ + } \ + \ + return wxNOT_FOUND; \ +} \ + \ +/* add item assuming the array is sorted with fnCompare function */ \ +size_t name::Add(T lItem, CMPFUNC fnCompare) \ +{ \ + size_t idx = IndexForInsert(lItem, fnCompare); \ + Insert(lItem, idx); \ + return idx; \ +} + +#if wxUSE_STL + +#define _WX_DEFINE_BASEARRAY_NOCOMMON(T, name) \ +size_t name::IndexForInsert(T lItem, CMPFUNC fnCompare) const \ +{ \ + Predicate p((SCMPFUNC)fnCompare); \ + const_iterator it = std::lower_bound(begin(), end(), lItem, p); \ + return it - begin(); \ +} \ + \ +int name::Index(T lItem, CMPFUNC fnCompare) const \ +{ \ + Predicate p((SCMPFUNC)fnCompare); \ + const_iterator it = std::lower_bound(begin(), end(), lItem, p); \ + return (it != end() && !p(lItem, *it)) ? \ + (int)(it - begin()) : wxNOT_FOUND; \ +} \ + \ +void name::Shrink() \ +{ \ + name tmp(*this); \ + swap(tmp); \ +} + +#else // if !wxUSE_STL + +#define _WX_DEFINE_BASEARRAY_NOCOMMON(T, name) \ +/* ctor */ \ +name::name() \ +{ \ + m_nSize = \ + m_nCount = 0; \ + m_pItems = (T *)NULL; \ +} \ + \ +/* copy ctor */ \ +name::name(const name& src) \ +{ \ + m_nSize = /* not src.m_nSize to save memory */ \ + m_nCount = src.m_nCount; \ + \ + if ( m_nSize != 0 ) { \ + m_pItems = new T[m_nSize]; \ + /* only copy if allocation succeeded */ \ + if ( m_pItems ) { \ + memcpy(m_pItems, src.m_pItems, m_nCount*sizeof(T)); \ + } \ + else { \ + m_nSize = 0; \ + } \ + } \ + else \ + m_pItems = (T *) NULL; \ +} \ + \ +/* assignment operator */ \ +name& name::operator=(const name& src) \ +{ \ + wxDELETEA(m_pItems); \ + \ + m_nSize = /* not src.m_nSize to save memory */ \ + m_nCount = src.m_nCount; \ + \ + if ( m_nSize != 0 ){ \ + m_pItems = new T[m_nSize]; \ + /* only copy if allocation succeeded */ \ + if ( m_pItems ) { \ + memcpy(m_pItems, src.m_pItems, m_nCount*sizeof(T)); \ + } \ + else { \ + m_nSize = 0; \ + } \ + } \ + else \ + m_pItems = (T *) NULL; \ + \ + return *this; \ +} \ + \ +/* allocate new buffer of the given size and move our data to it */ \ +bool name::Realloc(size_t nSize) \ +{ \ + T *pNew = new T[nSize]; \ + /* only grow if allocation succeeded */ \ + if ( !pNew ) \ + return false; \ + \ + m_nSize = nSize; \ + /* copy data to new location */ \ + memcpy(pNew, m_pItems, m_nCount*sizeof(T)); \ + delete [] m_pItems; \ + m_pItems = pNew; \ + \ + return true; \ +} \ + \ +/* grow the array */ \ +void name::Grow(size_t nIncrement) \ +{ \ + /* only do it if no more place */ \ + if( (m_nCount == m_nSize) || ((m_nSize - m_nCount) < nIncrement) ) { \ + if( m_nSize == 0 ) { \ + /* was empty, determine initial size */ \ + size_t size = WX_ARRAY_DEFAULT_INITIAL_SIZE; \ + if (size < nIncrement) size = nIncrement; \ + /* allocate some memory */ \ + m_pItems = new T[size]; \ + /* only grow if allocation succeeded */ \ + if ( m_pItems ) { \ + m_nSize = size; \ + } \ + } \ + else \ + { \ + /* add at least 50% but not too much */ \ + size_t ndefIncrement = m_nSize < WX_ARRAY_DEFAULT_INITIAL_SIZE \ + ? WX_ARRAY_DEFAULT_INITIAL_SIZE : m_nSize >> 1; \ + if ( ndefIncrement > ARRAY_MAXSIZE_INCREMENT ) \ + ndefIncrement = ARRAY_MAXSIZE_INCREMENT; \ + if ( nIncrement < ndefIncrement ) \ + nIncrement = ndefIncrement; \ + Realloc(m_nSize + nIncrement); \ + } \ + } \ +} \ + \ +/* make sure that the array has at least count elements */ \ +void name::SetCount(size_t count, T defval) \ +{ \ + if ( m_nSize < count ) \ + { \ + /* need to realloc memory: don't overallocate it here as if */ \ + /* SetCount() is called, it probably means that the caller */ \ + /* knows in advance how many elements there will be in the */ \ + /* array and so it won't be necessary to realloc it later */ \ + if ( !Realloc(count) ) \ + { \ + /* out of memory -- what can we do? */ \ + return; \ + } \ + } \ + \ + /* add new elements if we extend the array */ \ + while ( m_nCount < count ) \ + { \ + m_pItems[m_nCount++] = defval; \ + } \ +} \ + \ +/* dtor */ \ +name::~name() \ +{ \ + wxDELETEA(m_pItems); \ +} \ + \ +/* clears the list */ \ +void name::Clear() \ +{ \ + m_nSize = \ + m_nCount = 0; \ + \ + wxDELETEA(m_pItems); \ +} \ + \ +/* minimizes the memory usage by freeing unused memory */ \ +void name::Shrink() \ +{ \ + /* only do it if we have some memory to free */ \ + if( m_nCount < m_nSize ) { \ + /* allocates exactly as much memory as we need */ \ + T *pNew = new T[m_nCount]; \ + /* only shrink if allocation succeeded */ \ + if ( pNew ) { \ + /* copy data to new location */ \ + memcpy(pNew, m_pItems, m_nCount*sizeof(T)); \ + delete [] m_pItems; \ + m_pItems = pNew; \ + \ + /* update the size of the new block */ \ + m_nSize = m_nCount; \ + } \ + /* else: don't do anything, better keep old memory block! */ \ + } \ +} \ + \ +/* add item at the end */ \ +void name::Add(T lItem, size_t nInsert) \ +{ \ + if (nInsert == 0) \ + return; \ + Grow(nInsert); \ + for (size_t i = 0; i < nInsert; i++) \ + m_pItems[m_nCount++] = lItem; \ +} \ + \ +/* add item at the given position */ \ +void name::Insert(T lItem, size_t nIndex, size_t nInsert) \ +{ \ + wxCHECK_RET( nIndex <= m_nCount, wxT("bad index in wxArray::Insert") ); \ + wxCHECK_RET( m_nCount <= m_nCount + nInsert, \ + wxT("array size overflow in wxArray::Insert") ); \ + \ + if (nInsert == 0) \ + return; \ + Grow(nInsert); \ + \ + memmove(&m_pItems[nIndex + nInsert], &m_pItems[nIndex], \ + (m_nCount - nIndex)*sizeof(T)); \ + for (size_t i = 0; i < nInsert; i++) \ + m_pItems[nIndex + i] = lItem; \ + m_nCount += nInsert; \ +} \ + \ +/* search for a place to insert item into sorted array (binary search) */ \ +size_t name::IndexForInsert(T lItem, CMPFUNC fnCompare) const \ +{ \ + size_t i, \ + lo = 0, \ + hi = m_nCount; \ + int res; \ + \ + while ( lo < hi ) { \ + i = (lo + hi)/2; \ + \ + res = (*fnCompare)((const void *)(wxUIntPtr)lItem, \ + (const void *)(wxUIntPtr)(m_pItems[i])); \ + if ( res < 0 ) \ + hi = i; \ + else if ( res > 0 ) \ + lo = i + 1; \ + else { \ + lo = i; \ + break; \ + } \ + } \ + \ + return lo; \ +} \ + \ +/* search for an item in a sorted array (binary search) */ \ +int name::Index(T lItem, CMPFUNC fnCompare) const \ +{ \ + size_t n = IndexForInsert(lItem, fnCompare); \ + \ + return (n >= m_nCount || \ + (*fnCompare)((const void *)(wxUIntPtr)lItem, \ + ((const void *)(wxUIntPtr)m_pItems[n]))) \ + ? wxNOT_FOUND \ + : (int)n; \ +} \ + \ +/* removes item from array (by index) */ \ +void name::RemoveAt(size_t nIndex, size_t nRemove) \ +{ \ + wxCHECK_RET( nIndex < m_nCount, wxT("bad index in wxArray::RemoveAt") ); \ + wxCHECK_RET( nIndex + nRemove <= m_nCount, \ + wxT("removing too many elements in wxArray::RemoveAt") ); \ + \ + memmove(&m_pItems[nIndex], &m_pItems[nIndex + nRemove], \ + (m_nCount - nIndex - nRemove)*sizeof(T)); \ + m_nCount -= nRemove; \ +} \ + \ +/* removes item from array (by value) */ \ +void name::Remove(T lItem) \ +{ \ + int iIndex = Index(lItem); \ + \ + wxCHECK_RET( iIndex != wxNOT_FOUND, \ + wxT("removing inexistent item in wxArray::Remove") ); \ + \ + RemoveAt((size_t)iIndex); \ +} \ + \ +/* sort array elements using passed comparaison function */ \ +void name::Sort(CMPFUNC fCmp) \ +{ \ + qsort(m_pItems, m_nCount, sizeof(T), fCmp); \ +} \ + \ +void name::assign(const_iterator first, const_iterator last) \ +{ \ + clear(); \ + reserve(last - first); \ + for(; first != last; ++first) \ + push_back(*first); \ +} \ + \ +void name::assign(size_type n, const_reference v) \ +{ \ + clear(); \ + reserve(n); \ + for( size_type i = 0; i < n; ++i ) \ + push_back(v); \ +} \ + \ +void name::insert(iterator it, const_iterator first, const_iterator last) \ +{ \ + size_t nInsert = last - first, nIndex = it - begin(); \ + if (nInsert == 0) \ + return; \ + Grow(nInsert); \ + \ + memmove(&m_pItems[nIndex + nInsert], &m_pItems[nIndex], \ + (m_nCount - nIndex)*sizeof(T)); \ + for (size_t i = 0; i < nInsert; ++i, ++it, ++first) \ + *it = *first; \ + m_nCount += nInsert; \ +} + +#endif + +#define _WX_DEFINE_BASEARRAY(T, name) \ + _WX_DEFINE_BASEARRAY_COMMON(T, name) \ + _WX_DEFINE_BASEARRAY_NOCOMMON(T, name) + +#ifdef __INTELC__ + #pragma warning(push) + #pragma warning(disable: 1684) + #pragma warning(disable: 1572) +#endif + +_WX_DEFINE_BASEARRAY(const void *, wxBaseArrayPtrVoid) +_WX_DEFINE_BASEARRAY(char, wxBaseArrayChar) +_WX_DEFINE_BASEARRAY(short, wxBaseArrayShort) +_WX_DEFINE_BASEARRAY(int, wxBaseArrayInt) +_WX_DEFINE_BASEARRAY(long, wxBaseArrayLong) +_WX_DEFINE_BASEARRAY(size_t, wxBaseArraySizeT) +_WX_DEFINE_BASEARRAY(double, wxBaseArrayDouble) + +#ifdef __INTELC__ + #pragma warning(pop) +#endif + +#if wxUSE_STL +#include "wx/arrstr.h" + +#include "wx/beforestd.h" +#include +#include "wx/afterstd.h" + +_WX_DEFINE_BASEARRAY(wxString, wxBaseArrayStringBase) + +// some compilers (Sun CC being the only known example) distinguish between +// extern "C" functions and the functions with C++ linkage and ptr_fun and +// wxStringCompareLess can't take wxStrcmp/wxStricmp directly as arguments in +// this case, we need the wrappers below to make this work +inline int wxStrcmpCppWrapper(const wxChar *p, const wxChar *q) +{ + return wxStrcmp(p, q); +} + +inline int wxStricmpCppWrapper(const wxChar *p, const wxChar *q) +{ + return wxStricmp(p, q); +} + +int wxArrayString::Index(const wxChar* sz, bool bCase, bool WXUNUSED(bFromEnd)) const +{ + wxArrayString::const_iterator it; + + if (bCase) + { + it = std::find_if(begin(), end(), + std::not1( + std::bind2nd( + std::ptr_fun(wxStrcmpCppWrapper), sz))); + } + else // !bCase + { + it = std::find_if(begin(), end(), + std::not1( + std::bind2nd( + std::ptr_fun(wxStricmpCppWrapper), sz))); + } + + return it == end() ? wxNOT_FOUND : it - begin(); +} + +template +class wxStringCompareLess +{ +public: + wxStringCompareLess(F f) : m_f(f) { } + bool operator()(const wxChar* s1, const wxChar* s2) + { return m_f(s1, s2) < 0; } + bool operator()(const wxString& s1, const wxString& s2) + { return m_f(s1, s2) < 0; } +private: + F m_f; +}; + +template +wxStringCompareLess wxStringCompare(F f) +{ + return wxStringCompareLess(f); +} + +void wxArrayString::Sort(CompareFunction function) +{ + std::sort(begin(), end(), wxStringCompare(function)); +} + +void wxArrayString::Sort(bool reverseOrder) +{ + if (reverseOrder) + { + std::sort(begin(), end(), std::greater()); + } + else + { + std::sort(begin(), end()); + } +} + +int wxSortedArrayString::Index(const wxChar* sz, bool bCase, bool WXUNUSED(bFromEnd)) const +{ + wxSortedArrayString::const_iterator it; + wxString s(sz); + + if (bCase) + it = std::lower_bound(begin(), end(), s, + wxStringCompare(wxStrcmpCppWrapper)); + else + it = std::lower_bound(begin(), end(), s, + wxStringCompare(wxStricmpCppWrapper)); + + if (it == end()) + return wxNOT_FOUND; + + if (bCase) + { + if (wxStrcmp(it->c_str(), sz) != 0) + return wxNOT_FOUND; + } + else + { + if (wxStricmp(it->c_str(), sz) != 0) + return wxNOT_FOUND; + } + + return it - begin(); +} + +#endif diff --git a/Externals/wxWidgets/src/common/dynlib.cpp b/Externals/wxWidgets/src/common/dynlib.cpp index f4e75259cd..a2db5e3bab 100644 --- a/Externals/wxWidgets/src/common/dynlib.cpp +++ b/Externals/wxWidgets/src/common/dynlib.cpp @@ -1,323 +1,323 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/dynlib.cpp -// Purpose: Dynamic library management -// Author: Guilhem Lavaux -// Modified by: -// Created: 20/07/98 -// RCS-ID: $Id: dynlib.cpp 41807 2006-10-09 15:58:56Z VZ $ -// Copyright: (c) 1998 Guilhem Lavaux -// 2000-2005 Vadim Zeitlin -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -//FIXME: This class isn't really common at all, it should be moved into -// platform dependent files (already done for Windows and Unix) - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_DYNLIB_CLASS - -#include "wx/dynlib.h" - -#ifndef WX_PRECOMP - #include "wx/intl.h" - #include "wx/log.h" - #include "wx/app.h" - #include "wx/utils.h" -#endif //WX_PRECOMP - -#include "wx/filefn.h" -#include "wx/filename.h" // for SplitPath() -#include "wx/platinfo.h" - -#include "wx/arrimpl.cpp" - -#if defined(__WXMAC__) - #include "wx/mac/private.h" -#endif - -WX_DEFINE_USER_EXPORTED_OBJARRAY(wxDynamicLibraryDetailsArray) - -// ============================================================================ -// implementation -// ============================================================================ - -// --------------------------------------------------------------------------- -// wxDynamicLibrary -// --------------------------------------------------------------------------- - -#if defined(__WXPM__) || defined(__EMX__) - const wxChar *wxDynamicLibrary::ms_dllext = _T(".dll"); -#elif defined(__WXMAC__) && !defined(__DARWIN__) - const wxChar *wxDynamicLibrary::ms_dllext = wxEmptyString; -#endif - -// for MSW/Unix it is defined in platform-specific file -#if !(defined(__WXMSW__) || defined(__UNIX__)) || defined(__EMX__) - -wxDllType wxDynamicLibrary::GetProgramHandle() -{ - wxFAIL_MSG( wxT("GetProgramHandle() is not implemented under this platform")); - return 0; -} - -#endif // __WXMSW__ || __UNIX__ - - -bool wxDynamicLibrary::Load(const wxString& libnameOrig, int flags) -{ - wxASSERT_MSG(m_handle == 0, _T("Library already loaded.")); - - // add the proper extension for the DLL ourselves unless told not to - wxString libname = libnameOrig; - if ( !(flags & wxDL_VERBATIM) ) - { - // and also check that the libname doesn't already have it - wxString ext; - wxFileName::SplitPath(libname, NULL, NULL, &ext); - if ( ext.empty() ) - { - libname += GetDllExt(); - } - } - - // different ways to load a shared library - // - // FIXME: should go to the platform-specific files! -#if defined(__WXMAC__) && !defined(__DARWIN__) - FSSpec myFSSpec; - Ptr myMainAddr; - Str255 myErrName; - - wxMacFilename2FSSpec( libname , &myFSSpec ); - - if( GetDiskFragment( &myFSSpec, - 0, - kCFragGoesToEOF, - "\p", - kPrivateCFragCopy, - &m_handle, - &myMainAddr, - myErrName ) != noErr ) - { - wxLogSysError( _("Failed to load shared library '%s' Error '%s'"), - libname.c_str(), - wxMacMakeStringFromPascal( myErrName ).c_str() ); - m_handle = 0; - } - -#elif defined(__WXPM__) || defined(__EMX__) - char err[256] = ""; - DosLoadModule(err, sizeof(err), (PSZ)libname.c_str(), &m_handle); -#else // this should be the only remaining branch eventually - m_handle = RawLoad(libname, flags); -#endif - - if ( m_handle == 0 ) - { -#ifdef wxHAVE_DYNLIB_ERROR - Error(); -#else - wxLogSysError(_("Failed to load shared library '%s'"), libname.c_str()); -#endif - } - - return IsLoaded(); -} - -// for MSW and Unix this is implemented in the platform-specific file -// -// TODO: move the rest to os2/dlpm.cpp and mac/dlmac.cpp! -#if (!defined(__WXMSW__) && !defined(__UNIX__)) || defined(__EMX__) - -/* static */ -void wxDynamicLibrary::Unload(wxDllType handle) -{ -#if defined(__OS2__) || defined(__EMX__) - DosFreeModule( handle ); -#elif defined(__WXMAC__) && !defined(__DARWIN__) - CloseConnection( (CFragConnectionID*) &handle ); -#else - #error "runtime shared lib support not implemented" -#endif -} - -#endif // !(__WXMSW__ || __UNIX__) - -void *wxDynamicLibrary::DoGetSymbol(const wxString &name, bool *success) const -{ - wxCHECK_MSG( IsLoaded(), NULL, - _T("Can't load symbol from unloaded library") ); - - void *symbol = 0; - - wxUnusedVar(symbol); -#if defined(__WXMAC__) && !defined(__DARWIN__) - Ptr symAddress; - CFragSymbolClass symClass; - Str255 symName; -#if TARGET_CARBON - c2pstrcpy( (StringPtr) symName, name.fn_str() ); -#else - strcpy( (char *)symName, name.fn_str() ); - c2pstr( (char *)symName ); -#endif - if( FindSymbol( m_handle, symName, &symAddress, &symClass ) == noErr ) - symbol = (void *)symAddress; -#elif defined(__WXPM__) || defined(__EMX__) - DosQueryProcAddr( m_handle, 1L, (PSZ)name.c_str(), (PFN*)symbol ); -#else - symbol = RawGetSymbol(m_handle, name); -#endif - - if ( success ) - *success = symbol != NULL; - - return symbol; -} - -void *wxDynamicLibrary::GetSymbol(const wxString& name, bool *success) const -{ - void *symbol = DoGetSymbol(name, success); - if ( !symbol ) - { -#ifdef wxHAVE_DYNLIB_ERROR - Error(); -#else - wxLogSysError(_("Couldn't find symbol '%s' in a dynamic library"), - name.c_str()); -#endif - } - - return symbol; -} - -// ---------------------------------------------------------------------------- -// informational methods -// ---------------------------------------------------------------------------- - -/*static*/ -wxString -wxDynamicLibrary::CanonicalizeName(const wxString& name, - wxDynamicLibraryCategory cat) -{ - wxString nameCanonic; - - // under Unix the library names usually start with "lib" prefix, add it -#if defined(__UNIX__) && !defined(__EMX__) - switch ( cat ) - { - default: - wxFAIL_MSG( _T("unknown wxDynamicLibraryCategory value") ); - // fall through - - case wxDL_MODULE: - // don't do anything for modules, their names are arbitrary - break; - - case wxDL_LIBRARY: - // library names should start with "lib" under Unix - nameCanonic = _T("lib"); - break; - } -#else // !__UNIX__ - wxUnusedVar(cat); -#endif // __UNIX__/!__UNIX__ - - nameCanonic << name << GetDllExt(); - return nameCanonic; -} - -/*static*/ -wxString wxDynamicLibrary::CanonicalizePluginName(const wxString& name, - wxPluginCategory cat) -{ - wxString suffix; - if ( cat == wxDL_PLUGIN_GUI ) - { - suffix = wxPlatformInfo::Get().GetPortIdShortName(); - } -#if wxUSE_UNICODE - suffix << _T('u'); -#endif -#ifdef __WXDEBUG__ - suffix << _T('d'); -#endif - - if ( !suffix.empty() ) - suffix = wxString(_T("_")) + suffix; - -#define WXSTRINGIZE(x) #x -#if defined(__UNIX__) && !defined(__EMX__) - #if (wxMINOR_VERSION % 2) == 0 - #define wxDLLVER(x,y,z) "-" WXSTRINGIZE(x) "." WXSTRINGIZE(y) - #else - #define wxDLLVER(x,y,z) "-" WXSTRINGIZE(x) "." WXSTRINGIZE(y) "." WXSTRINGIZE(z) - #endif -#else - #if (wxMINOR_VERSION % 2) == 0 - #define wxDLLVER(x,y,z) WXSTRINGIZE(x) WXSTRINGIZE(y) - #else - #define wxDLLVER(x,y,z) WXSTRINGIZE(x) WXSTRINGIZE(y) WXSTRINGIZE(z) - #endif -#endif - - suffix << wxString::FromAscii(wxDLLVER(wxMAJOR_VERSION, wxMINOR_VERSION, - wxRELEASE_NUMBER)); -#undef wxDLLVER -#undef WXSTRINGIZE - -#ifdef __WINDOWS__ - // Add compiler identification: - #if defined(__GNUG__) - suffix << _T("_gcc"); - #elif defined(__VISUALC__) - suffix << _T("_vc"); - #elif defined(__WATCOMC__) - suffix << _T("_wat"); - #elif defined(__BORLANDC__) - suffix << _T("_bcc"); - #endif -#endif - - return CanonicalizeName(name + suffix, wxDL_MODULE); -} - -/*static*/ -wxString wxDynamicLibrary::GetPluginsDirectory() -{ -#ifdef __UNIX__ - wxString format = wxGetInstallPrefix(); - wxString dir; - format << wxFILE_SEP_PATH - << wxT("lib") << wxFILE_SEP_PATH - << wxT("wx") << wxFILE_SEP_PATH -#if (wxMINOR_VERSION % 2) == 0 - << wxT("%i.%i"); - dir.Printf(format.c_str(), wxMAJOR_VERSION, wxMINOR_VERSION); -#else - << wxT("%i.%i.%i"); - dir.Printf(format.c_str(), - wxMAJOR_VERSION, wxMINOR_VERSION, wxRELEASE_NUMBER); -#endif - return dir; - -#else // ! __UNIX__ - return wxEmptyString; -#endif -} - - -#endif // wxUSE_DYNLIB_CLASS +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/dynlib.cpp +// Purpose: Dynamic library management +// Author: Guilhem Lavaux +// Modified by: +// Created: 20/07/98 +// RCS-ID: $Id: dynlib.cpp 41807 2006-10-09 15:58:56Z VZ $ +// Copyright: (c) 1998 Guilhem Lavaux +// 2000-2005 Vadim Zeitlin +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +//FIXME: This class isn't really common at all, it should be moved into +// platform dependent files (already done for Windows and Unix) + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_DYNLIB_CLASS + +#include "wx/dynlib.h" + +#ifndef WX_PRECOMP + #include "wx/intl.h" + #include "wx/log.h" + #include "wx/app.h" + #include "wx/utils.h" +#endif //WX_PRECOMP + +#include "wx/filefn.h" +#include "wx/filename.h" // for SplitPath() +#include "wx/platinfo.h" + +#include "wx/arrimpl.cpp" + +#if defined(__WXMAC__) + #include "wx/mac/private.h" +#endif + +WX_DEFINE_USER_EXPORTED_OBJARRAY(wxDynamicLibraryDetailsArray) + +// ============================================================================ +// implementation +// ============================================================================ + +// --------------------------------------------------------------------------- +// wxDynamicLibrary +// --------------------------------------------------------------------------- + +#if defined(__WXPM__) || defined(__EMX__) + const wxChar *wxDynamicLibrary::ms_dllext = _T(".dll"); +#elif defined(__WXMAC__) && !defined(__DARWIN__) + const wxChar *wxDynamicLibrary::ms_dllext = wxEmptyString; +#endif + +// for MSW/Unix it is defined in platform-specific file +#if !(defined(__WXMSW__) || defined(__UNIX__)) || defined(__EMX__) + +wxDllType wxDynamicLibrary::GetProgramHandle() +{ + wxFAIL_MSG( wxT("GetProgramHandle() is not implemented under this platform")); + return 0; +} + +#endif // __WXMSW__ || __UNIX__ + + +bool wxDynamicLibrary::Load(const wxString& libnameOrig, int flags) +{ + wxASSERT_MSG(m_handle == 0, _T("Library already loaded.")); + + // add the proper extension for the DLL ourselves unless told not to + wxString libname = libnameOrig; + if ( !(flags & wxDL_VERBATIM) ) + { + // and also check that the libname doesn't already have it + wxString ext; + wxFileName::SplitPath(libname, NULL, NULL, &ext); + if ( ext.empty() ) + { + libname += GetDllExt(); + } + } + + // different ways to load a shared library + // + // FIXME: should go to the platform-specific files! +#if defined(__WXMAC__) && !defined(__DARWIN__) + FSSpec myFSSpec; + Ptr myMainAddr; + Str255 myErrName; + + wxMacFilename2FSSpec( libname , &myFSSpec ); + + if( GetDiskFragment( &myFSSpec, + 0, + kCFragGoesToEOF, + "\p", + kPrivateCFragCopy, + &m_handle, + &myMainAddr, + myErrName ) != noErr ) + { + wxLogSysError( _("Failed to load shared library '%s' Error '%s'"), + libname.c_str(), + wxMacMakeStringFromPascal( myErrName ).c_str() ); + m_handle = 0; + } + +#elif defined(__WXPM__) || defined(__EMX__) + char err[256] = ""; + DosLoadModule(err, sizeof(err), (PSZ)libname.c_str(), &m_handle); +#else // this should be the only remaining branch eventually + m_handle = RawLoad(libname, flags); +#endif + + if ( m_handle == 0 ) + { +#ifdef wxHAVE_DYNLIB_ERROR + Error(); +#else + wxLogSysError(_("Failed to load shared library '%s'"), libname.c_str()); +#endif + } + + return IsLoaded(); +} + +// for MSW and Unix this is implemented in the platform-specific file +// +// TODO: move the rest to os2/dlpm.cpp and mac/dlmac.cpp! +#if (!defined(__WXMSW__) && !defined(__UNIX__)) || defined(__EMX__) + +/* static */ +void wxDynamicLibrary::Unload(wxDllType handle) +{ +#if defined(__OS2__) || defined(__EMX__) + DosFreeModule( handle ); +#elif defined(__WXMAC__) && !defined(__DARWIN__) + CloseConnection( (CFragConnectionID*) &handle ); +#else + #error "runtime shared lib support not implemented" +#endif +} + +#endif // !(__WXMSW__ || __UNIX__) + +void *wxDynamicLibrary::DoGetSymbol(const wxString &name, bool *success) const +{ + wxCHECK_MSG( IsLoaded(), NULL, + _T("Can't load symbol from unloaded library") ); + + void *symbol = 0; + + wxUnusedVar(symbol); +#if defined(__WXMAC__) && !defined(__DARWIN__) + Ptr symAddress; + CFragSymbolClass symClass; + Str255 symName; +#if TARGET_CARBON + c2pstrcpy( (StringPtr) symName, name.fn_str() ); +#else + strcpy( (char *)symName, name.fn_str() ); + c2pstr( (char *)symName ); +#endif + if( FindSymbol( m_handle, symName, &symAddress, &symClass ) == noErr ) + symbol = (void *)symAddress; +#elif defined(__WXPM__) || defined(__EMX__) + DosQueryProcAddr( m_handle, 1L, (PSZ)name.c_str(), (PFN*)symbol ); +#else + symbol = RawGetSymbol(m_handle, name); +#endif + + if ( success ) + *success = symbol != NULL; + + return symbol; +} + +void *wxDynamicLibrary::GetSymbol(const wxString& name, bool *success) const +{ + void *symbol = DoGetSymbol(name, success); + if ( !symbol ) + { +#ifdef wxHAVE_DYNLIB_ERROR + Error(); +#else + wxLogSysError(_("Couldn't find symbol '%s' in a dynamic library"), + name.c_str()); +#endif + } + + return symbol; +} + +// ---------------------------------------------------------------------------- +// informational methods +// ---------------------------------------------------------------------------- + +/*static*/ +wxString +wxDynamicLibrary::CanonicalizeName(const wxString& name, + wxDynamicLibraryCategory cat) +{ + wxString nameCanonic; + + // under Unix the library names usually start with "lib" prefix, add it +#if defined(__UNIX__) && !defined(__EMX__) + switch ( cat ) + { + default: + wxFAIL_MSG( _T("unknown wxDynamicLibraryCategory value") ); + // fall through + + case wxDL_MODULE: + // don't do anything for modules, their names are arbitrary + break; + + case wxDL_LIBRARY: + // library names should start with "lib" under Unix + nameCanonic = _T("lib"); + break; + } +#else // !__UNIX__ + wxUnusedVar(cat); +#endif // __UNIX__/!__UNIX__ + + nameCanonic << name << GetDllExt(); + return nameCanonic; +} + +/*static*/ +wxString wxDynamicLibrary::CanonicalizePluginName(const wxString& name, + wxPluginCategory cat) +{ + wxString suffix; + if ( cat == wxDL_PLUGIN_GUI ) + { + suffix = wxPlatformInfo::Get().GetPortIdShortName(); + } +#if wxUSE_UNICODE + suffix << _T('u'); +#endif +#ifdef __WXDEBUG__ + suffix << _T('d'); +#endif + + if ( !suffix.empty() ) + suffix = wxString(_T("_")) + suffix; + +#define WXSTRINGIZE(x) #x +#if defined(__UNIX__) && !defined(__EMX__) + #if (wxMINOR_VERSION % 2) == 0 + #define wxDLLVER(x,y,z) "-" WXSTRINGIZE(x) "." WXSTRINGIZE(y) + #else + #define wxDLLVER(x,y,z) "-" WXSTRINGIZE(x) "." WXSTRINGIZE(y) "." WXSTRINGIZE(z) + #endif +#else + #if (wxMINOR_VERSION % 2) == 0 + #define wxDLLVER(x,y,z) WXSTRINGIZE(x) WXSTRINGIZE(y) + #else + #define wxDLLVER(x,y,z) WXSTRINGIZE(x) WXSTRINGIZE(y) WXSTRINGIZE(z) + #endif +#endif + + suffix << wxString::FromAscii(wxDLLVER(wxMAJOR_VERSION, wxMINOR_VERSION, + wxRELEASE_NUMBER)); +#undef wxDLLVER +#undef WXSTRINGIZE + +#ifdef __WINDOWS__ + // Add compiler identification: + #if defined(__GNUG__) + suffix << _T("_gcc"); + #elif defined(__VISUALC__) + suffix << _T("_vc"); + #elif defined(__WATCOMC__) + suffix << _T("_wat"); + #elif defined(__BORLANDC__) + suffix << _T("_bcc"); + #endif +#endif + + return CanonicalizeName(name + suffix, wxDL_MODULE); +} + +/*static*/ +wxString wxDynamicLibrary::GetPluginsDirectory() +{ +#ifdef __UNIX__ + wxString format = wxGetInstallPrefix(); + wxString dir; + format << wxFILE_SEP_PATH + << wxT("lib") << wxFILE_SEP_PATH + << wxT("wx") << wxFILE_SEP_PATH +#if (wxMINOR_VERSION % 2) == 0 + << wxT("%i.%i"); + dir.Printf(format.c_str(), wxMAJOR_VERSION, wxMINOR_VERSION); +#else + << wxT("%i.%i.%i"); + dir.Printf(format.c_str(), + wxMAJOR_VERSION, wxMINOR_VERSION, wxRELEASE_NUMBER); +#endif + return dir; + +#else // ! __UNIX__ + return wxEmptyString; +#endif +} + + +#endif // wxUSE_DYNLIB_CLASS diff --git a/Externals/wxWidgets/src/common/dynload.cpp b/Externals/wxWidgets/src/common/dynload.cpp index 1a0aac9b32..a28b9e5289 100644 --- a/Externals/wxWidgets/src/common/dynload.cpp +++ b/Externals/wxWidgets/src/common/dynload.cpp @@ -1,362 +1,362 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/dynload.cpp -// Purpose: Dynamic loading framework -// Author: Ron Lee, David Falkinder, Vadim Zeitlin and a cast of 1000's -// (derived in part from dynlib.cpp (c) 1998 Guilhem Lavaux) -// Modified by: -// Created: 03/12/01 -// RCS-ID: $Id: dynload.cpp 40943 2006-08-31 19:31:43Z ABX $ -// Copyright: (c) 2001 Ron Lee -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_DYNAMIC_LOADER - -#ifdef __WINDOWS__ - #include "wx/msw/private.h" -#endif - -#ifndef WX_PRECOMP - #include "wx/log.h" - #include "wx/intl.h" - #include "wx/hash.h" - #include "wx/utils.h" - #include "wx/module.h" -#endif - -#include "wx/strconv.h" - -#include "wx/dynload.h" - - -// --------------------------------------------------------------------------- -// wxPluginLibrary -// --------------------------------------------------------------------------- - - -wxDLImports* wxPluginLibrary::ms_classes = NULL; - -class wxPluginLibraryModule : public wxModule -{ -public: - wxPluginLibraryModule() { } - - // TODO: create ms_classes on demand, why always preallocate it? - virtual bool OnInit() - { - wxPluginLibrary::ms_classes = new wxDLImports; - wxPluginManager::CreateManifest(); - return true; - } - - virtual void OnExit() - { - delete wxPluginLibrary::ms_classes; - wxPluginLibrary::ms_classes = NULL; - wxPluginManager::ClearManifest(); - } - -private: - DECLARE_DYNAMIC_CLASS(wxPluginLibraryModule ) -}; - -IMPLEMENT_DYNAMIC_CLASS(wxPluginLibraryModule, wxModule) - - -wxPluginLibrary::wxPluginLibrary(const wxString &libname, int flags) - : m_linkcount(1) - , m_objcount(0) -{ - m_before = wxClassInfo::sm_first; - Load( libname, flags ); - m_after = wxClassInfo::sm_first; - - if( m_handle != 0 ) - { - UpdateClasses(); - RegisterModules(); - } - else - { - // Flag us for deletion - --m_linkcount; - } -} - -wxPluginLibrary::~wxPluginLibrary() -{ - if( m_handle != 0 ) - { - UnregisterModules(); - RestoreClasses(); - } -} - -wxPluginLibrary *wxPluginLibrary::RefLib() -{ - wxCHECK_MSG( m_linkcount > 0, NULL, - _T("Library had been already deleted!") ); - - ++m_linkcount; - return this; -} - -bool wxPluginLibrary::UnrefLib() -{ - wxASSERT_MSG( m_objcount == 0, - _T("Library unloaded before all objects were destroyed") ); - - if ( m_linkcount == 0 || --m_linkcount == 0 ) - { - delete this; - return true; - } - - return false; -} - -// ------------------------ -// Private methods -// ------------------------ - -void wxPluginLibrary::UpdateClasses() -{ - for (wxClassInfo *info = m_after; info != m_before; info = info->m_next) - { - if( info->GetClassName() ) - { - // Hash all the class names into a local table too so - // we can quickly find the entry they correspond to. - (*ms_classes)[info->GetClassName()] = this; - } - } -} - -void wxPluginLibrary::RestoreClasses() -{ - // Check if there is a need to restore classes. - if (!ms_classes) - return; - - for(wxClassInfo *info = m_after; info != m_before; info = info->m_next) - { - ms_classes->erase(ms_classes->find(info->GetClassName())); - } -} - -void wxPluginLibrary::RegisterModules() -{ - // Plugin libraries might have wxModules, Register and initialise them if - // they do. - // - // Note that these classes are NOT included in the reference counting since - // it's implicit that they will be unloaded if and when the last handle to - // the library is. We do have to keep a copy of the module's pointer - // though, as there is currently no way to Unregister it without it. - - wxASSERT_MSG( m_linkcount == 1, - _T("RegisterModules should only be called for the first load") ); - - for ( wxClassInfo *info = m_after; info != m_before; info = info->m_next) - { - if( info->IsKindOf(CLASSINFO(wxModule)) ) - { - wxModule *m = wxDynamicCast(info->CreateObject(), wxModule); - - wxASSERT_MSG( m, _T("wxDynamicCast of wxModule failed") ); - - m_wxmodules.push_back(m); - wxModule::RegisterModule(m); - } - } - - // FIXME: Likewise this is (well was) very similar to InitializeModules() - - for ( wxModuleList::iterator it = m_wxmodules.begin(); - it != m_wxmodules.end(); - ++it) - { - if( !(*it)->Init() ) - { - wxLogDebug(_T("wxModule::Init() failed for wxPluginLibrary")); - - // XXX: Watch this, a different hash implementation might break it, - // a good hash implementation would let us fix it though. - - // The name of the game is to remove any uninitialised modules and - // let the dtor Exit the rest on shutdown, (which we'll initiate - // shortly). - - wxModuleList::iterator oldNode = m_wxmodules.end(); - do { - ++it; - if( oldNode != m_wxmodules.end() ) - m_wxmodules.erase(oldNode); - wxModule::UnregisterModule( *it ); - oldNode = it; - } while( it != m_wxmodules.end() ); - - --m_linkcount; // Flag us for deletion - break; - } - } -} - -void wxPluginLibrary::UnregisterModules() -{ - wxModuleList::iterator it; - - for ( it = m_wxmodules.begin(); it != m_wxmodules.end(); ++it ) - (*it)->Exit(); - - for ( it = m_wxmodules.begin(); it != m_wxmodules.end(); ++it ) - wxModule::UnregisterModule( *it ); - - // NB: content of the list was deleted by UnregisterModule calls above: - m_wxmodules.clear(); -} - - -// --------------------------------------------------------------------------- -// wxPluginManager -// --------------------------------------------------------------------------- - -wxDLManifest* wxPluginManager::ms_manifest = NULL; - -// ------------------------ -// Static accessors -// ------------------------ - -wxPluginLibrary * -wxPluginManager::LoadLibrary(const wxString &libname, int flags) -{ - wxString realname(libname); - - if( !(flags & wxDL_VERBATIM) ) - realname += wxDynamicLibrary::GetDllExt(); - - wxPluginLibrary *entry; - - if ( flags & wxDL_NOSHARE ) - { - entry = NULL; - } - else - { - entry = FindByName(realname); - } - - if ( entry ) - { - wxLogTrace(_T("dll"), - _T("LoadLibrary(%s): already loaded."), realname.c_str()); - - entry->RefLib(); - } - else - { - entry = new wxPluginLibrary( libname, flags ); - - if ( entry->IsLoaded() ) - { - (*ms_manifest)[realname] = entry; - - wxLogTrace(_T("dll"), - _T("LoadLibrary(%s): loaded ok."), realname.c_str()); - - } - else - { - wxLogTrace(_T("dll"), - _T("LoadLibrary(%s): failed to load."), realname.c_str()); - - // we have created entry just above - if ( !entry->UnrefLib() ) - { - // ... so UnrefLib() is supposed to delete it - wxFAIL_MSG( _T("Currently linked library is not loaded?") ); - } - - entry = NULL; - } - } - - return entry; -} - -bool wxPluginManager::UnloadLibrary(const wxString& libname) -{ - wxString realname = libname; - - wxPluginLibrary *entry = FindByName(realname); - - if ( !entry ) - { - realname += wxDynamicLibrary::GetDllExt(); - - entry = FindByName(realname); - } - - if ( !entry ) - { - wxLogDebug(_T("Attempt to unload library '%s' which is not loaded."), - libname.c_str()); - - return false; - } - - wxLogTrace(_T("dll"), _T("UnloadLibrary(%s)"), realname.c_str()); - - if ( !entry->UnrefLib() ) - { - // not really unloaded yet - return false; - } - - ms_manifest->erase(ms_manifest->find(realname)); - - return true; -} - -// ------------------------ -// Class implementation -// ------------------------ - -bool wxPluginManager::Load(const wxString &libname, int flags) -{ - m_entry = wxPluginManager::LoadLibrary(libname, flags); - - return IsLoaded(); -} - -void wxPluginManager::Unload() -{ - wxCHECK_RET( m_entry, _T("unloading an invalid wxPluginManager?") ); - - for ( wxDLManifest::iterator i = ms_manifest->begin(); - i != ms_manifest->end(); - ++i ) - { - if ( i->second == m_entry ) - { - ms_manifest->erase(i); - break; - } - } - - m_entry->UnrefLib(); - - m_entry = NULL; -} - -#endif // wxUSE_DYNAMIC_LOADER +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/dynload.cpp +// Purpose: Dynamic loading framework +// Author: Ron Lee, David Falkinder, Vadim Zeitlin and a cast of 1000's +// (derived in part from dynlib.cpp (c) 1998 Guilhem Lavaux) +// Modified by: +// Created: 03/12/01 +// RCS-ID: $Id: dynload.cpp 40943 2006-08-31 19:31:43Z ABX $ +// Copyright: (c) 2001 Ron Lee +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_DYNAMIC_LOADER + +#ifdef __WINDOWS__ + #include "wx/msw/private.h" +#endif + +#ifndef WX_PRECOMP + #include "wx/log.h" + #include "wx/intl.h" + #include "wx/hash.h" + #include "wx/utils.h" + #include "wx/module.h" +#endif + +#include "wx/strconv.h" + +#include "wx/dynload.h" + + +// --------------------------------------------------------------------------- +// wxPluginLibrary +// --------------------------------------------------------------------------- + + +wxDLImports* wxPluginLibrary::ms_classes = NULL; + +class wxPluginLibraryModule : public wxModule +{ +public: + wxPluginLibraryModule() { } + + // TODO: create ms_classes on demand, why always preallocate it? + virtual bool OnInit() + { + wxPluginLibrary::ms_classes = new wxDLImports; + wxPluginManager::CreateManifest(); + return true; + } + + virtual void OnExit() + { + delete wxPluginLibrary::ms_classes; + wxPluginLibrary::ms_classes = NULL; + wxPluginManager::ClearManifest(); + } + +private: + DECLARE_DYNAMIC_CLASS(wxPluginLibraryModule ) +}; + +IMPLEMENT_DYNAMIC_CLASS(wxPluginLibraryModule, wxModule) + + +wxPluginLibrary::wxPluginLibrary(const wxString &libname, int flags) + : m_linkcount(1) + , m_objcount(0) +{ + m_before = wxClassInfo::sm_first; + Load( libname, flags ); + m_after = wxClassInfo::sm_first; + + if( m_handle != 0 ) + { + UpdateClasses(); + RegisterModules(); + } + else + { + // Flag us for deletion + --m_linkcount; + } +} + +wxPluginLibrary::~wxPluginLibrary() +{ + if( m_handle != 0 ) + { + UnregisterModules(); + RestoreClasses(); + } +} + +wxPluginLibrary *wxPluginLibrary::RefLib() +{ + wxCHECK_MSG( m_linkcount > 0, NULL, + _T("Library had been already deleted!") ); + + ++m_linkcount; + return this; +} + +bool wxPluginLibrary::UnrefLib() +{ + wxASSERT_MSG( m_objcount == 0, + _T("Library unloaded before all objects were destroyed") ); + + if ( m_linkcount == 0 || --m_linkcount == 0 ) + { + delete this; + return true; + } + + return false; +} + +// ------------------------ +// Private methods +// ------------------------ + +void wxPluginLibrary::UpdateClasses() +{ + for (wxClassInfo *info = m_after; info != m_before; info = info->m_next) + { + if( info->GetClassName() ) + { + // Hash all the class names into a local table too so + // we can quickly find the entry they correspond to. + (*ms_classes)[info->GetClassName()] = this; + } + } +} + +void wxPluginLibrary::RestoreClasses() +{ + // Check if there is a need to restore classes. + if (!ms_classes) + return; + + for(wxClassInfo *info = m_after; info != m_before; info = info->m_next) + { + ms_classes->erase(ms_classes->find(info->GetClassName())); + } +} + +void wxPluginLibrary::RegisterModules() +{ + // Plugin libraries might have wxModules, Register and initialise them if + // they do. + // + // Note that these classes are NOT included in the reference counting since + // it's implicit that they will be unloaded if and when the last handle to + // the library is. We do have to keep a copy of the module's pointer + // though, as there is currently no way to Unregister it without it. + + wxASSERT_MSG( m_linkcount == 1, + _T("RegisterModules should only be called for the first load") ); + + for ( wxClassInfo *info = m_after; info != m_before; info = info->m_next) + { + if( info->IsKindOf(CLASSINFO(wxModule)) ) + { + wxModule *m = wxDynamicCast(info->CreateObject(), wxModule); + + wxASSERT_MSG( m, _T("wxDynamicCast of wxModule failed") ); + + m_wxmodules.push_back(m); + wxModule::RegisterModule(m); + } + } + + // FIXME: Likewise this is (well was) very similar to InitializeModules() + + for ( wxModuleList::iterator it = m_wxmodules.begin(); + it != m_wxmodules.end(); + ++it) + { + if( !(*it)->Init() ) + { + wxLogDebug(_T("wxModule::Init() failed for wxPluginLibrary")); + + // XXX: Watch this, a different hash implementation might break it, + // a good hash implementation would let us fix it though. + + // The name of the game is to remove any uninitialised modules and + // let the dtor Exit the rest on shutdown, (which we'll initiate + // shortly). + + wxModuleList::iterator oldNode = m_wxmodules.end(); + do { + ++it; + if( oldNode != m_wxmodules.end() ) + m_wxmodules.erase(oldNode); + wxModule::UnregisterModule( *it ); + oldNode = it; + } while( it != m_wxmodules.end() ); + + --m_linkcount; // Flag us for deletion + break; + } + } +} + +void wxPluginLibrary::UnregisterModules() +{ + wxModuleList::iterator it; + + for ( it = m_wxmodules.begin(); it != m_wxmodules.end(); ++it ) + (*it)->Exit(); + + for ( it = m_wxmodules.begin(); it != m_wxmodules.end(); ++it ) + wxModule::UnregisterModule( *it ); + + // NB: content of the list was deleted by UnregisterModule calls above: + m_wxmodules.clear(); +} + + +// --------------------------------------------------------------------------- +// wxPluginManager +// --------------------------------------------------------------------------- + +wxDLManifest* wxPluginManager::ms_manifest = NULL; + +// ------------------------ +// Static accessors +// ------------------------ + +wxPluginLibrary * +wxPluginManager::LoadLibrary(const wxString &libname, int flags) +{ + wxString realname(libname); + + if( !(flags & wxDL_VERBATIM) ) + realname += wxDynamicLibrary::GetDllExt(); + + wxPluginLibrary *entry; + + if ( flags & wxDL_NOSHARE ) + { + entry = NULL; + } + else + { + entry = FindByName(realname); + } + + if ( entry ) + { + wxLogTrace(_T("dll"), + _T("LoadLibrary(%s): already loaded."), realname.c_str()); + + entry->RefLib(); + } + else + { + entry = new wxPluginLibrary( libname, flags ); + + if ( entry->IsLoaded() ) + { + (*ms_manifest)[realname] = entry; + + wxLogTrace(_T("dll"), + _T("LoadLibrary(%s): loaded ok."), realname.c_str()); + + } + else + { + wxLogTrace(_T("dll"), + _T("LoadLibrary(%s): failed to load."), realname.c_str()); + + // we have created entry just above + if ( !entry->UnrefLib() ) + { + // ... so UnrefLib() is supposed to delete it + wxFAIL_MSG( _T("Currently linked library is not loaded?") ); + } + + entry = NULL; + } + } + + return entry; +} + +bool wxPluginManager::UnloadLibrary(const wxString& libname) +{ + wxString realname = libname; + + wxPluginLibrary *entry = FindByName(realname); + + if ( !entry ) + { + realname += wxDynamicLibrary::GetDllExt(); + + entry = FindByName(realname); + } + + if ( !entry ) + { + wxLogDebug(_T("Attempt to unload library '%s' which is not loaded."), + libname.c_str()); + + return false; + } + + wxLogTrace(_T("dll"), _T("UnloadLibrary(%s)"), realname.c_str()); + + if ( !entry->UnrefLib() ) + { + // not really unloaded yet + return false; + } + + ms_manifest->erase(ms_manifest->find(realname)); + + return true; +} + +// ------------------------ +// Class implementation +// ------------------------ + +bool wxPluginManager::Load(const wxString &libname, int flags) +{ + m_entry = wxPluginManager::LoadLibrary(libname, flags); + + return IsLoaded(); +} + +void wxPluginManager::Unload() +{ + wxCHECK_RET( m_entry, _T("unloading an invalid wxPluginManager?") ); + + for ( wxDLManifest::iterator i = ms_manifest->begin(); + i != ms_manifest->end(); + ++i ) + { + if ( i->second == m_entry ) + { + ms_manifest->erase(i); + break; + } + } + + m_entry->UnrefLib(); + + m_entry = NULL; +} + +#endif // wxUSE_DYNAMIC_LOADER diff --git a/Externals/wxWidgets/src/common/effects.cpp b/Externals/wxWidgets/src/common/effects.cpp index 444595b5f6..dc1ab01e5c 100644 --- a/Externals/wxWidgets/src/common/effects.cpp +++ b/Externals/wxWidgets/src/common/effects.cpp @@ -1,124 +1,124 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/effects.cpp -// Purpose: wxEffects implementation -// Author: Julian Smart -// Modified by: -// Created: 25/4/2000 -// RCS-ID: $Id: effects.cpp 42755 2006-10-30 19:41:46Z VZ $ -// Copyright: (c) Julian Smart -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#include "wx/effects.h" - -#ifndef WX_PRECOMP - #include "wx/dcmemory.h" - #include "wx/pen.h" - #include "wx/settings.h" - #include "wx/gdicmn.h" -#endif //WX_PRECOMP - -/* - * wxEffects: various 3D effects - */ - -IMPLEMENT_CLASS(wxEffects, wxObject) - -// Assume system colours -wxEffects::wxEffects() -{ - m_highlightColour = wxSystemSettings::GetColour(wxSYS_COLOUR_3DHILIGHT) ; - m_lightShadow = wxSystemSettings::GetColour(wxSYS_COLOUR_3DLIGHT) ; - m_faceColour = wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE) ; - m_mediumShadow = wxSystemSettings::GetColour(wxSYS_COLOUR_3DSHADOW) ; - m_darkShadow = wxSystemSettings::GetColour(wxSYS_COLOUR_3DDKSHADOW) ; -} - -// Going from lightest to darkest -wxEffects::wxEffects(const wxColour& highlightColour, const wxColour& lightShadow, - const wxColour& faceColour, const wxColour& mediumShadow, const wxColour& darkShadow) -{ - m_highlightColour = highlightColour; - m_lightShadow = lightShadow; - m_faceColour = faceColour; - m_mediumShadow = mediumShadow; - m_darkShadow = darkShadow; -} - -// Draw a sunken edge -void wxEffects::DrawSunkenEdge(wxDC& dc, const wxRect& rect, int WXUNUSED(borderSize)) -{ - wxPen highlightPen(m_highlightColour, 1, wxSOLID); - wxPen lightShadowPen(m_lightShadow, 1, wxSOLID); - wxPen facePen(m_faceColour, 1, wxSOLID); - wxPen mediumShadowPen(m_mediumShadow, 1, wxSOLID); - wxPen darkShadowPen(m_darkShadow, 1, wxSOLID); - - //// LEFT AND TOP - // Draw a medium shadow pen on left and top, followed by dark shadow line to - // right and below of these lines - - dc.SetPen(mediumShadowPen); - dc.DrawLine(rect.x, rect.y, rect.x+rect.width-1, rect.y); // Top - dc.DrawLine(rect.x, rect.y, rect.x, rect.y+rect.height-1); // Left - - dc.SetPen(darkShadowPen); - dc.DrawLine(rect.x+1, rect.y+1, rect.x+rect.width-2, rect.y+1); // Top - dc.DrawLine(rect.x+1, rect.y+1, rect.x+1, rect.y+rect.height-1); // Left - - //// RIGHT AND BOTTOM - - dc.SetPen(highlightPen); - dc.DrawLine(rect.x+rect.width-1, rect.y, rect.x+rect.width-1, rect.y+rect.height-1); // Right - dc.DrawLine(rect.x, rect.y+rect.height-1, rect.x+rect.width, rect.y+rect.height-1); // Bottom - - dc.SetPen(lightShadowPen); - dc.DrawLine(rect.x+rect.width-2, rect.y+1, rect.x+rect.width-2, rect.y+rect.height-2); // Right - dc.DrawLine(rect.x+1, rect.y+rect.height-2, rect.x+rect.width-1, rect.y+rect.height-2); // Bottom - - dc.SetPen(wxNullPen); -} - -bool wxEffects::TileBitmap(const wxRect& rect, wxDC& dc, const wxBitmap& bitmap) -{ - int w = bitmap.GetWidth(); - int h = bitmap.GetHeight(); - - wxMemoryDC dcMem; - -#if wxUSE_PALETTE - static bool hiColour = (wxDisplayDepth() >= 16) ; - if (bitmap.GetPalette() && !hiColour) - { - dc.SetPalette(* bitmap.GetPalette()); - dcMem.SetPalette(* bitmap.GetPalette()); - } -#endif // wxUSE_PALETTE - - dcMem.SelectObjectAsSource(bitmap); - - int i, j; - for (i = rect.x; i < rect.x + rect.width; i += w) - { - for (j = rect.y; j < rect.y + rect.height; j+= h) - dc.Blit(i, j, bitmap.GetWidth(), bitmap.GetHeight(), & dcMem, 0, 0); - } - dcMem.SelectObject(wxNullBitmap); - -#if wxUSE_PALETTE - if (bitmap.GetPalette() && !hiColour) - { - dc.SetPalette(wxNullPalette); - dcMem.SetPalette(wxNullPalette); - } -#endif // wxUSE_PALETTE - - return true; -} +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/effects.cpp +// Purpose: wxEffects implementation +// Author: Julian Smart +// Modified by: +// Created: 25/4/2000 +// RCS-ID: $Id: effects.cpp 42755 2006-10-30 19:41:46Z VZ $ +// Copyright: (c) Julian Smart +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#include "wx/effects.h" + +#ifndef WX_PRECOMP + #include "wx/dcmemory.h" + #include "wx/pen.h" + #include "wx/settings.h" + #include "wx/gdicmn.h" +#endif //WX_PRECOMP + +/* + * wxEffects: various 3D effects + */ + +IMPLEMENT_CLASS(wxEffects, wxObject) + +// Assume system colours +wxEffects::wxEffects() +{ + m_highlightColour = wxSystemSettings::GetColour(wxSYS_COLOUR_3DHILIGHT) ; + m_lightShadow = wxSystemSettings::GetColour(wxSYS_COLOUR_3DLIGHT) ; + m_faceColour = wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE) ; + m_mediumShadow = wxSystemSettings::GetColour(wxSYS_COLOUR_3DSHADOW) ; + m_darkShadow = wxSystemSettings::GetColour(wxSYS_COLOUR_3DDKSHADOW) ; +} + +// Going from lightest to darkest +wxEffects::wxEffects(const wxColour& highlightColour, const wxColour& lightShadow, + const wxColour& faceColour, const wxColour& mediumShadow, const wxColour& darkShadow) +{ + m_highlightColour = highlightColour; + m_lightShadow = lightShadow; + m_faceColour = faceColour; + m_mediumShadow = mediumShadow; + m_darkShadow = darkShadow; +} + +// Draw a sunken edge +void wxEffects::DrawSunkenEdge(wxDC& dc, const wxRect& rect, int WXUNUSED(borderSize)) +{ + wxPen highlightPen(m_highlightColour, 1, wxSOLID); + wxPen lightShadowPen(m_lightShadow, 1, wxSOLID); + wxPen facePen(m_faceColour, 1, wxSOLID); + wxPen mediumShadowPen(m_mediumShadow, 1, wxSOLID); + wxPen darkShadowPen(m_darkShadow, 1, wxSOLID); + + //// LEFT AND TOP + // Draw a medium shadow pen on left and top, followed by dark shadow line to + // right and below of these lines + + dc.SetPen(mediumShadowPen); + dc.DrawLine(rect.x, rect.y, rect.x+rect.width-1, rect.y); // Top + dc.DrawLine(rect.x, rect.y, rect.x, rect.y+rect.height-1); // Left + + dc.SetPen(darkShadowPen); + dc.DrawLine(rect.x+1, rect.y+1, rect.x+rect.width-2, rect.y+1); // Top + dc.DrawLine(rect.x+1, rect.y+1, rect.x+1, rect.y+rect.height-1); // Left + + //// RIGHT AND BOTTOM + + dc.SetPen(highlightPen); + dc.DrawLine(rect.x+rect.width-1, rect.y, rect.x+rect.width-1, rect.y+rect.height-1); // Right + dc.DrawLine(rect.x, rect.y+rect.height-1, rect.x+rect.width, rect.y+rect.height-1); // Bottom + + dc.SetPen(lightShadowPen); + dc.DrawLine(rect.x+rect.width-2, rect.y+1, rect.x+rect.width-2, rect.y+rect.height-2); // Right + dc.DrawLine(rect.x+1, rect.y+rect.height-2, rect.x+rect.width-1, rect.y+rect.height-2); // Bottom + + dc.SetPen(wxNullPen); +} + +bool wxEffects::TileBitmap(const wxRect& rect, wxDC& dc, const wxBitmap& bitmap) +{ + int w = bitmap.GetWidth(); + int h = bitmap.GetHeight(); + + wxMemoryDC dcMem; + +#if wxUSE_PALETTE + static bool hiColour = (wxDisplayDepth() >= 16) ; + if (bitmap.GetPalette() && !hiColour) + { + dc.SetPalette(* bitmap.GetPalette()); + dcMem.SetPalette(* bitmap.GetPalette()); + } +#endif // wxUSE_PALETTE + + dcMem.SelectObjectAsSource(bitmap); + + int i, j; + for (i = rect.x; i < rect.x + rect.width; i += w) + { + for (j = rect.y; j < rect.y + rect.height; j+= h) + dc.Blit(i, j, bitmap.GetWidth(), bitmap.GetHeight(), & dcMem, 0, 0); + } + dcMem.SelectObject(wxNullBitmap); + +#if wxUSE_PALETTE + if (bitmap.GetPalette() && !hiColour) + { + dc.SetPalette(wxNullPalette); + dcMem.SetPalette(wxNullPalette); + } +#endif // wxUSE_PALETTE + + return true; +} diff --git a/Externals/wxWidgets/src/common/emptydmy.cpp b/Externals/wxWidgets/src/common/emptydmy.cpp index 9e79b3b00a..4c2b115372 100644 --- a/Externals/wxWidgets/src/common/emptydmy.cpp +++ b/Externals/wxWidgets/src/common/emptydmy.cpp @@ -1,3 +1,3 @@ -// This file exists so that it can be compiled into an object so the linker -// will have something to chew on so that builds don't break when a platform -// lacks any objects in a particular multilib. +// This file exists so that it can be compiled into an object so the linker +// will have something to chew on so that builds don't break when a platform +// lacks any objects in a particular multilib. diff --git a/Externals/wxWidgets/src/common/encconv.cpp b/Externals/wxWidgets/src/common/encconv.cpp index 15f884fb9d..15509c9cbc 100644 --- a/Externals/wxWidgets/src/common/encconv.cpp +++ b/Externals/wxWidgets/src/common/encconv.cpp @@ -1,531 +1,531 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: encconv.cpp -// Purpose: wxEncodingConverter class for converting between different -// font encodings -// Author: Vaclav Slavik -// Copyright: (c) 1999 Vaclav Slavik -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#include "wx/encconv.h" - -#include - -// conversion tables, generated by scripts in $(WXWIN)/misc/unictabl: -#if defined( __BORLANDC__ ) || defined(__DARWIN__) - #include "../common/unictabl.inc" -#else - #include "unictabl.inc" -#endif - -#if wxUSE_WCHAR_T - typedef wchar_t tchar; -#else - typedef char tchar; -#endif - -#ifdef __WXMAC__ -#ifdef __DARWIN__ -#include -#else -#include -#include -#include -#endif - #include "wx/fontutil.h" - #include "wx/mac/private.h" // includes mac headers - - wxUint16 gMacEncodings[wxFONTENCODING_MACMAX-wxFONTENCODING_MACMIN+1][128] ; - bool gMacEncodingsInited[wxFONTENCODING_MACMAX-wxFONTENCODING_MACMIN+1] ; -#endif - -#ifdef __WXWINCE__ - #include "wx/msw/wince/missing.h" // for bsearch() -#endif - -static const wxUint16* GetEncTable(wxFontEncoding enc) -{ -#ifdef __WXMAC__ - if( enc >= wxFONTENCODING_MACMIN && enc <= wxFONTENCODING_MACMAX ) - { - int i = enc-wxFONTENCODING_MACMIN ; - if ( gMacEncodingsInited[i] == false ) - { - TECObjectRef converter ; - TextEncodingBase code = wxMacGetSystemEncFromFontEnc( enc ) ; - TextEncodingBase unicode = CreateTextEncoding(kTextEncodingUnicodeDefault,0,kUnicode16BitFormat) ; - OSStatus status = TECCreateConverter(&converter,code,unicode); - char s[2] ; - s[1] = 0 ; - ByteCount byteInLen, byteOutLen ; - for( unsigned char c = 255 ; c >= 128 ; --c ) - { - s[0] = c ; - status = TECConvertText(converter, (ConstTextPtr) &s , 1, &byteInLen, - (TextPtr) &gMacEncodings[i][c-128] , 2, &byteOutLen); - } - status = TECDisposeConverter(converter); - gMacEncodingsInited[i]=true; - } - return gMacEncodings[i] ; - } -#endif - - for (int i = 0; encodings_list[i].table != NULL; i++) - { - if (encodings_list[i].encoding == enc) - return encodings_list[i].table; - } - return NULL; -} - -typedef struct { - wxUint16 u; - wxUint8 c; -} CharsetItem; - -extern "C" int wxCMPFUNC_CONV -CompareCharsetItems(const void *i1, const void *i2) -{ - return ( ((CharsetItem*)i1) -> u - ((CharsetItem*)i2) -> u ); -} - - -static CharsetItem* BuildReverseTable(const wxUint16 *tbl) -{ - CharsetItem *rev = new CharsetItem[128]; - - for (int i = 0; i < 128; i++) - rev[i].c = wxUint8(128 + i), rev[i].u = tbl[i]; - - qsort(rev, 128, sizeof(CharsetItem), CompareCharsetItems); - - return rev; -} - - - -wxEncodingConverter::wxEncodingConverter() -{ - m_Table = NULL; - m_UnicodeInput = m_UnicodeOutput = false; - m_JustCopy = false; -} - - - -bool wxEncodingConverter::Init(wxFontEncoding input_enc, wxFontEncoding output_enc, int method) -{ - unsigned i; - const wxUint16 *in_tbl; - const wxUint16 *out_tbl = NULL; - - if (m_Table) {delete[] m_Table; m_Table = NULL;} - -#if !wxUSE_WCHAR_T - if (input_enc == wxFONTENCODING_UNICODE || output_enc == wxFONTENCODING_UNICODE) return false; -#endif - - if (input_enc == output_enc) {m_JustCopy = true; return true;} - - m_UnicodeOutput = (output_enc == wxFONTENCODING_UNICODE); - m_JustCopy = false; - - if (input_enc == wxFONTENCODING_UNICODE) - { - if ((out_tbl = GetEncTable(output_enc)) == NULL) return false; - - m_Table = new tchar[65536]; - for (i = 0; i < 128; i++) m_Table[i] = (tchar)i; // 7bit ASCII - for (i = 128; i < 65536; i++) m_Table[i] = (tchar)0; - - if (method == wxCONVERT_SUBSTITUTE) - { - for (i = 0; i < encoding_unicode_fallback_count; i++) - m_Table[encoding_unicode_fallback[i].c] = (tchar) encoding_unicode_fallback[i].s; - } - - for (i = 0; i < 128; i++) - m_Table[out_tbl[i]] = (tchar)(128 + i); - - m_UnicodeInput = true; - } - else // input !Unicode - { - if ((in_tbl = GetEncTable(input_enc)) == NULL) return false; - if (output_enc != wxFONTENCODING_UNICODE) - if ((out_tbl = GetEncTable(output_enc)) == NULL) return false; - - m_UnicodeInput = false; - - m_Table = new tchar[256]; - for (i = 0; i < 128; i++) m_Table[i] = (tchar)i; // 7bit ASCII - - if (output_enc == wxFONTENCODING_UNICODE) - { - for (i = 0; i < 128; i++) m_Table[128 + i] = (tchar)in_tbl[i]; - return true; - } - else // output !Unicode - { - CharsetItem *rev = BuildReverseTable(out_tbl); - CharsetItem *item; - CharsetItem key; - - for (i = 0; i < 128; i++) - { - key.u = in_tbl[i]; - item = (CharsetItem*) bsearch(&key, rev, 128, sizeof(CharsetItem), CompareCharsetItems); - if (item == NULL && method == wxCONVERT_SUBSTITUTE) - item = (CharsetItem*) bsearch(&key, encoding_unicode_fallback, - encoding_unicode_fallback_count, sizeof(CharsetItem), CompareCharsetItems); - if (item) - m_Table[128 + i] = (tchar)item -> c; - else -#if wxUSE_WCHAR_T - m_Table[128 + i] = (wchar_t)(128 + i); -#else - m_Table[128 + i] = (char)(128 + i); -#endif - } - - delete[] rev; - } - } - - return true; -} - - -#define REPLACEMENT_CHAR ((tchar)'?') - -inline tchar GetTableValue(const tchar *table, tchar value, bool& repl) -{ - tchar r = table[value]; - if (r == 0 && value != 0) - { - r = REPLACEMENT_CHAR; - repl = true; - } - return r; -} - - -bool wxEncodingConverter::Convert(const char* input, char* output) const -{ - wxASSERT_MSG(!m_UnicodeOutput, wxT("You cannot convert to unicode if output is const char*!")); - wxASSERT_MSG(!m_UnicodeInput, wxT("You cannot convert from unicode if input is const char*!")); - - const char *i; - char *o; - - if (m_JustCopy) - { - strcpy(output, input); - return true; - } - - wxCHECK_MSG(m_Table != NULL, false, - wxT("You must call wxEncodingConverter::Init() before actually converting!")); - - bool replaced = false; - - for (i = input, o = output; *i != 0;) - *(o++) = (char)(GetTableValue(m_Table, (wxUint8)*(i++), replaced)); - *o = 0; - - return !replaced; -} - - -#if wxUSE_WCHAR_T - -bool wxEncodingConverter::Convert(const char* input, wchar_t* output) const -{ - wxASSERT_MSG(m_UnicodeOutput, wxT("You cannot convert to 8-bit if output is const wchar_t*!")); - wxASSERT_MSG(!m_UnicodeInput, wxT("You cannot convert from unicode if input is const char*!")); - - const char *i; - wchar_t *o; - - if (m_JustCopy) - { - for (i = input, o = output; *i != 0;) - *(o++) = (wchar_t)(*(i++)); - *o = 0; - return true; - } - - wxCHECK_MSG(m_Table != NULL, false, - wxT("You must call wxEncodingConverter::Init() before actually converting!")); - - bool replaced = false; - - for (i = input, o = output; *i != 0;) - *(o++) = (wchar_t)(GetTableValue(m_Table, (wxUint8)*(i++), replaced)); - *o = 0; - - return !replaced; -} - - - -bool wxEncodingConverter::Convert(const wchar_t* input, char* output) const -{ - wxASSERT_MSG(!m_UnicodeOutput, wxT("You cannot convert to unicode if output is const char*!")); - wxASSERT_MSG(m_UnicodeInput, wxT("You cannot convert from 8-bit if input is const wchar_t*!")); - - const wchar_t *i; - char *o; - - if (m_JustCopy) - { - for (i = input, o = output; *i != 0;) - *(o++) = (char)(*(i++)); - *o = 0; - return true; - } - - wxCHECK_MSG(m_Table != NULL, false, - wxT("You must call wxEncodingConverter::Init() before actually converting!")); - - bool replaced = false; - - for (i = input, o = output; *i != 0;) - *(o++) = (char)(GetTableValue(m_Table, (wxUint16)*(i++), replaced)); - *o = 0; - - return !replaced; -} - - - -bool wxEncodingConverter::Convert(const wchar_t* input, wchar_t* output) const -{ - wxASSERT_MSG(m_UnicodeOutput, wxT("You cannot convert to 8-bit if output is const wchar_t*!")); - wxASSERT_MSG(m_UnicodeInput, wxT("You cannot convert from 8-bit if input is const wchar_t*!")); - - const wchar_t *i; - wchar_t *o; - - if (m_JustCopy) - { - // wcscpy() is not guaranteed to exist - for (i = input, o = output; *i != 0;) - *(o++) = (*(i++)); - *o = 0; - return true; - } - - wxCHECK_MSG(m_Table != NULL, false, - wxT("You must call wxEncodingConverter::Init() before actually converting!")); - - bool replaced = false; - - for (i = input, o = output; *i != 0;) - *(o++) = (wchar_t)(GetTableValue(m_Table, (wxUint8)*(i++), replaced)); - *o = 0; - - return !replaced; -} - -#endif // wxUSE_WCHAR_T - - -wxString wxEncodingConverter::Convert(const wxString& input) const -{ - if (m_JustCopy) return input; - - wxString s; - const wxChar *i; - - wxCHECK_MSG(m_Table != NULL, s, - wxT("You must call wxEncodingConverter::Init() before actually converting!")); - - if (m_UnicodeInput) - { - for (i = input.c_str(); *i != 0; i++) - s << (wxChar)(m_Table[(wxUint16)*i]); - } - else - { - for (i = input.c_str(); *i != 0; i++) - s << (wxChar)(m_Table[(wxUint8)*i]); - } - - return s; -} - - - - - - - -// Following tables describe classes of encoding equivalence. -// - -#define STOP wxFONTENCODING_SYSTEM - -#define NUM_OF_PLATFORMS 4 /*must conform to enum wxPLATFORM_XXXX !!!*/ -#define ENC_PER_PLATFORM 3 - // max no. of encodings for one language used on one platform. - // Using maximum of everything at the current moment to not make the - // library larger than necessary. Make larger only if necessary - MR - -static const wxFontEncoding - EquivalentEncodings[][NUM_OF_PLATFORMS][ENC_PER_PLATFORM+1] = { - - // *** Please put more common encodings as first! *** - - // Western European - { - /* unix */ {wxFONTENCODING_ISO8859_1, wxFONTENCODING_ISO8859_15, STOP}, - /* windows */ {wxFONTENCODING_CP1252, STOP}, - /* os2 */ {STOP}, - /* mac */ {wxFONTENCODING_MACROMAN, STOP} - }, - - // Central European - { - /* unix */ {wxFONTENCODING_ISO8859_2, STOP}, - /* windows */ {wxFONTENCODING_CP1250, STOP}, - /* os2 */ {STOP}, - /* mac */ {wxFONTENCODING_MACCENTRALEUR, STOP} - }, - - // Baltic - { - /* unix */ {wxFONTENCODING_ISO8859_13, wxFONTENCODING_ISO8859_4, STOP}, - /* windows */ {wxFONTENCODING_CP1257, STOP}, - /* os2 */ {STOP}, - /* mac */ {STOP} - }, - - // Hebrew - { - /* unix */ {wxFONTENCODING_ISO8859_8, STOP}, - /* windows */ {wxFONTENCODING_CP1255, STOP}, - /* os2 */ {STOP}, - /* mac */ {wxFONTENCODING_MACHEBREW, STOP} - }, - - // Greek - { - /* unix */ {wxFONTENCODING_ISO8859_7, STOP}, - /* windows */ {wxFONTENCODING_CP1253, STOP}, - /* os2 */ {STOP}, - /* mac */ {wxFONTENCODING_MACGREEK, STOP} - }, - - // Arabic - { - /* unix */ {wxFONTENCODING_ISO8859_6, STOP}, - /* windows */ {wxFONTENCODING_CP1256, STOP}, - /* os2 */ {STOP}, - /* mac */ {wxFONTENCODING_MACARABIC, STOP} - }, - - // Turkish - { - /* unix */ {wxFONTENCODING_ISO8859_9, STOP}, - /* windows */ {wxFONTENCODING_CP1254, STOP}, - /* os2 */ {STOP}, - /* mac */ {wxFONTENCODING_MACTURKISH, STOP} - }, - - // Cyrillic - { - /* unix */ {wxFONTENCODING_KOI8, wxFONTENCODING_KOI8_U, wxFONTENCODING_ISO8859_5, STOP}, - /* windows */ {wxFONTENCODING_CP1251, STOP}, - /* os2 */ {STOP}, - /* mac */ {wxFONTENCODING_MACCYRILLIC, STOP} - }, - - {{STOP},{STOP},{STOP},{STOP}} /* Terminator */ - /* no, _not_ Arnold! */ -}; - - -static bool FindEncoding(const wxFontEncodingArray& arr, wxFontEncoding f) -{ - for (wxFontEncodingArray::const_iterator it = arr.begin(), en = arr.end(); - it != en; ++it) - if (*it == f) - return true; - return false; -} - -wxFontEncodingArray wxEncodingConverter::GetPlatformEquivalents(wxFontEncoding enc, int platform) -{ - if (platform == wxPLATFORM_CURRENT) - { -#if defined(__WXMSW__) - platform = wxPLATFORM_WINDOWS; -#elif defined(__WXGTK__) || defined(__WXMOTIF__) - platform = wxPLATFORM_UNIX; -#elif defined(__WXPM__) - platform = wxPLATFORM_OS2; -#elif defined(__WXMAC__) - platform = wxPLATFORM_MAC; -#endif - } - - int i, clas, e ; - const wxFontEncoding *f; - wxFontEncodingArray arr; - - clas = 0; - while (EquivalentEncodings[clas][0][0] != STOP) - { - for (i = 0; i < NUM_OF_PLATFORMS; i++) - for (e = 0; EquivalentEncodings[clas][i][e] != STOP; e++) - if (EquivalentEncodings[clas][i][e] == enc) - { - for (f = EquivalentEncodings[clas][platform]; *f != STOP; f++) - if (*f == enc) arr.push_back(enc); - for (f = EquivalentEncodings[clas][platform]; *f != STOP; f++) - if (!FindEncoding(arr, *f)) arr.push_back(*f); - i = NUM_OF_PLATFORMS/*hack*/; break; - } - clas++; - } - - return arr; -} - - - -wxFontEncodingArray wxEncodingConverter::GetAllEquivalents(wxFontEncoding enc) -{ - int i, clas, e, j ; - const wxFontEncoding *f; - wxFontEncodingArray arr; - - arr = GetPlatformEquivalents(enc); // we want them to be first items in array - - clas = 0; - while (EquivalentEncodings[clas][0][0] != STOP) - { - for (i = 0; i < NUM_OF_PLATFORMS; i++) - for (e = 0; EquivalentEncodings[clas][i][e] != STOP; e++) - if (EquivalentEncodings[clas][i][e] == enc) - { - for (j = 0; j < NUM_OF_PLATFORMS; j++) - for (f = EquivalentEncodings[clas][j]; *f != STOP; f++) - if (!FindEncoding(arr, *f)) arr.push_back(*f); - i = NUM_OF_PLATFORMS/*hack*/; break; - } - clas++; - } - - return arr; -} - +///////////////////////////////////////////////////////////////////////////// +// Name: encconv.cpp +// Purpose: wxEncodingConverter class for converting between different +// font encodings +// Author: Vaclav Slavik +// Copyright: (c) 1999 Vaclav Slavik +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#include "wx/encconv.h" + +#include + +// conversion tables, generated by scripts in $(WXWIN)/misc/unictabl: +#if defined( __BORLANDC__ ) || defined(__DARWIN__) + #include "../common/unictabl.inc" +#else + #include "unictabl.inc" +#endif + +#if wxUSE_WCHAR_T + typedef wchar_t tchar; +#else + typedef char tchar; +#endif + +#ifdef __WXMAC__ +#ifdef __DARWIN__ +#include +#else +#include +#include +#include +#endif + #include "wx/fontutil.h" + #include "wx/mac/private.h" // includes mac headers + + wxUint16 gMacEncodings[wxFONTENCODING_MACMAX-wxFONTENCODING_MACMIN+1][128] ; + bool gMacEncodingsInited[wxFONTENCODING_MACMAX-wxFONTENCODING_MACMIN+1] ; +#endif + +#ifdef __WXWINCE__ + #include "wx/msw/wince/missing.h" // for bsearch() +#endif + +static const wxUint16* GetEncTable(wxFontEncoding enc) +{ +#ifdef __WXMAC__ + if( enc >= wxFONTENCODING_MACMIN && enc <= wxFONTENCODING_MACMAX ) + { + int i = enc-wxFONTENCODING_MACMIN ; + if ( gMacEncodingsInited[i] == false ) + { + TECObjectRef converter ; + TextEncodingBase code = wxMacGetSystemEncFromFontEnc( enc ) ; + TextEncodingBase unicode = CreateTextEncoding(kTextEncodingUnicodeDefault,0,kUnicode16BitFormat) ; + OSStatus status = TECCreateConverter(&converter,code,unicode); + char s[2] ; + s[1] = 0 ; + ByteCount byteInLen, byteOutLen ; + for( unsigned char c = 255 ; c >= 128 ; --c ) + { + s[0] = c ; + status = TECConvertText(converter, (ConstTextPtr) &s , 1, &byteInLen, + (TextPtr) &gMacEncodings[i][c-128] , 2, &byteOutLen); + } + status = TECDisposeConverter(converter); + gMacEncodingsInited[i]=true; + } + return gMacEncodings[i] ; + } +#endif + + for (int i = 0; encodings_list[i].table != NULL; i++) + { + if (encodings_list[i].encoding == enc) + return encodings_list[i].table; + } + return NULL; +} + +typedef struct { + wxUint16 u; + wxUint8 c; +} CharsetItem; + +extern "C" int wxCMPFUNC_CONV +CompareCharsetItems(const void *i1, const void *i2) +{ + return ( ((CharsetItem*)i1) -> u - ((CharsetItem*)i2) -> u ); +} + + +static CharsetItem* BuildReverseTable(const wxUint16 *tbl) +{ + CharsetItem *rev = new CharsetItem[128]; + + for (int i = 0; i < 128; i++) + rev[i].c = wxUint8(128 + i), rev[i].u = tbl[i]; + + qsort(rev, 128, sizeof(CharsetItem), CompareCharsetItems); + + return rev; +} + + + +wxEncodingConverter::wxEncodingConverter() +{ + m_Table = NULL; + m_UnicodeInput = m_UnicodeOutput = false; + m_JustCopy = false; +} + + + +bool wxEncodingConverter::Init(wxFontEncoding input_enc, wxFontEncoding output_enc, int method) +{ + unsigned i; + const wxUint16 *in_tbl; + const wxUint16 *out_tbl = NULL; + + if (m_Table) {delete[] m_Table; m_Table = NULL;} + +#if !wxUSE_WCHAR_T + if (input_enc == wxFONTENCODING_UNICODE || output_enc == wxFONTENCODING_UNICODE) return false; +#endif + + if (input_enc == output_enc) {m_JustCopy = true; return true;} + + m_UnicodeOutput = (output_enc == wxFONTENCODING_UNICODE); + m_JustCopy = false; + + if (input_enc == wxFONTENCODING_UNICODE) + { + if ((out_tbl = GetEncTable(output_enc)) == NULL) return false; + + m_Table = new tchar[65536]; + for (i = 0; i < 128; i++) m_Table[i] = (tchar)i; // 7bit ASCII + for (i = 128; i < 65536; i++) m_Table[i] = (tchar)0; + + if (method == wxCONVERT_SUBSTITUTE) + { + for (i = 0; i < encoding_unicode_fallback_count; i++) + m_Table[encoding_unicode_fallback[i].c] = (tchar) encoding_unicode_fallback[i].s; + } + + for (i = 0; i < 128; i++) + m_Table[out_tbl[i]] = (tchar)(128 + i); + + m_UnicodeInput = true; + } + else // input !Unicode + { + if ((in_tbl = GetEncTable(input_enc)) == NULL) return false; + if (output_enc != wxFONTENCODING_UNICODE) + if ((out_tbl = GetEncTable(output_enc)) == NULL) return false; + + m_UnicodeInput = false; + + m_Table = new tchar[256]; + for (i = 0; i < 128; i++) m_Table[i] = (tchar)i; // 7bit ASCII + + if (output_enc == wxFONTENCODING_UNICODE) + { + for (i = 0; i < 128; i++) m_Table[128 + i] = (tchar)in_tbl[i]; + return true; + } + else // output !Unicode + { + CharsetItem *rev = BuildReverseTable(out_tbl); + CharsetItem *item; + CharsetItem key; + + for (i = 0; i < 128; i++) + { + key.u = in_tbl[i]; + item = (CharsetItem*) bsearch(&key, rev, 128, sizeof(CharsetItem), CompareCharsetItems); + if (item == NULL && method == wxCONVERT_SUBSTITUTE) + item = (CharsetItem*) bsearch(&key, encoding_unicode_fallback, + encoding_unicode_fallback_count, sizeof(CharsetItem), CompareCharsetItems); + if (item) + m_Table[128 + i] = (tchar)item -> c; + else +#if wxUSE_WCHAR_T + m_Table[128 + i] = (wchar_t)(128 + i); +#else + m_Table[128 + i] = (char)(128 + i); +#endif + } + + delete[] rev; + } + } + + return true; +} + + +#define REPLACEMENT_CHAR ((tchar)'?') + +inline tchar GetTableValue(const tchar *table, tchar value, bool& repl) +{ + tchar r = table[value]; + if (r == 0 && value != 0) + { + r = REPLACEMENT_CHAR; + repl = true; + } + return r; +} + + +bool wxEncodingConverter::Convert(const char* input, char* output) const +{ + wxASSERT_MSG(!m_UnicodeOutput, wxT("You cannot convert to unicode if output is const char*!")); + wxASSERT_MSG(!m_UnicodeInput, wxT("You cannot convert from unicode if input is const char*!")); + + const char *i; + char *o; + + if (m_JustCopy) + { + strcpy(output, input); + return true; + } + + wxCHECK_MSG(m_Table != NULL, false, + wxT("You must call wxEncodingConverter::Init() before actually converting!")); + + bool replaced = false; + + for (i = input, o = output; *i != 0;) + *(o++) = (char)(GetTableValue(m_Table, (wxUint8)*(i++), replaced)); + *o = 0; + + return !replaced; +} + + +#if wxUSE_WCHAR_T + +bool wxEncodingConverter::Convert(const char* input, wchar_t* output) const +{ + wxASSERT_MSG(m_UnicodeOutput, wxT("You cannot convert to 8-bit if output is const wchar_t*!")); + wxASSERT_MSG(!m_UnicodeInput, wxT("You cannot convert from unicode if input is const char*!")); + + const char *i; + wchar_t *o; + + if (m_JustCopy) + { + for (i = input, o = output; *i != 0;) + *(o++) = (wchar_t)(*(i++)); + *o = 0; + return true; + } + + wxCHECK_MSG(m_Table != NULL, false, + wxT("You must call wxEncodingConverter::Init() before actually converting!")); + + bool replaced = false; + + for (i = input, o = output; *i != 0;) + *(o++) = (wchar_t)(GetTableValue(m_Table, (wxUint8)*(i++), replaced)); + *o = 0; + + return !replaced; +} + + + +bool wxEncodingConverter::Convert(const wchar_t* input, char* output) const +{ + wxASSERT_MSG(!m_UnicodeOutput, wxT("You cannot convert to unicode if output is const char*!")); + wxASSERT_MSG(m_UnicodeInput, wxT("You cannot convert from 8-bit if input is const wchar_t*!")); + + const wchar_t *i; + char *o; + + if (m_JustCopy) + { + for (i = input, o = output; *i != 0;) + *(o++) = (char)(*(i++)); + *o = 0; + return true; + } + + wxCHECK_MSG(m_Table != NULL, false, + wxT("You must call wxEncodingConverter::Init() before actually converting!")); + + bool replaced = false; + + for (i = input, o = output; *i != 0;) + *(o++) = (char)(GetTableValue(m_Table, (wxUint16)*(i++), replaced)); + *o = 0; + + return !replaced; +} + + + +bool wxEncodingConverter::Convert(const wchar_t* input, wchar_t* output) const +{ + wxASSERT_MSG(m_UnicodeOutput, wxT("You cannot convert to 8-bit if output is const wchar_t*!")); + wxASSERT_MSG(m_UnicodeInput, wxT("You cannot convert from 8-bit if input is const wchar_t*!")); + + const wchar_t *i; + wchar_t *o; + + if (m_JustCopy) + { + // wcscpy() is not guaranteed to exist + for (i = input, o = output; *i != 0;) + *(o++) = (*(i++)); + *o = 0; + return true; + } + + wxCHECK_MSG(m_Table != NULL, false, + wxT("You must call wxEncodingConverter::Init() before actually converting!")); + + bool replaced = false; + + for (i = input, o = output; *i != 0;) + *(o++) = (wchar_t)(GetTableValue(m_Table, (wxUint8)*(i++), replaced)); + *o = 0; + + return !replaced; +} + +#endif // wxUSE_WCHAR_T + + +wxString wxEncodingConverter::Convert(const wxString& input) const +{ + if (m_JustCopy) return input; + + wxString s; + const wxChar *i; + + wxCHECK_MSG(m_Table != NULL, s, + wxT("You must call wxEncodingConverter::Init() before actually converting!")); + + if (m_UnicodeInput) + { + for (i = input.c_str(); *i != 0; i++) + s << (wxChar)(m_Table[(wxUint16)*i]); + } + else + { + for (i = input.c_str(); *i != 0; i++) + s << (wxChar)(m_Table[(wxUint8)*i]); + } + + return s; +} + + + + + + + +// Following tables describe classes of encoding equivalence. +// + +#define STOP wxFONTENCODING_SYSTEM + +#define NUM_OF_PLATFORMS 4 /*must conform to enum wxPLATFORM_XXXX !!!*/ +#define ENC_PER_PLATFORM 3 + // max no. of encodings for one language used on one platform. + // Using maximum of everything at the current moment to not make the + // library larger than necessary. Make larger only if necessary - MR + +static const wxFontEncoding + EquivalentEncodings[][NUM_OF_PLATFORMS][ENC_PER_PLATFORM+1] = { + + // *** Please put more common encodings as first! *** + + // Western European + { + /* unix */ {wxFONTENCODING_ISO8859_1, wxFONTENCODING_ISO8859_15, STOP}, + /* windows */ {wxFONTENCODING_CP1252, STOP}, + /* os2 */ {STOP}, + /* mac */ {wxFONTENCODING_MACROMAN, STOP} + }, + + // Central European + { + /* unix */ {wxFONTENCODING_ISO8859_2, STOP}, + /* windows */ {wxFONTENCODING_CP1250, STOP}, + /* os2 */ {STOP}, + /* mac */ {wxFONTENCODING_MACCENTRALEUR, STOP} + }, + + // Baltic + { + /* unix */ {wxFONTENCODING_ISO8859_13, wxFONTENCODING_ISO8859_4, STOP}, + /* windows */ {wxFONTENCODING_CP1257, STOP}, + /* os2 */ {STOP}, + /* mac */ {STOP} + }, + + // Hebrew + { + /* unix */ {wxFONTENCODING_ISO8859_8, STOP}, + /* windows */ {wxFONTENCODING_CP1255, STOP}, + /* os2 */ {STOP}, + /* mac */ {wxFONTENCODING_MACHEBREW, STOP} + }, + + // Greek + { + /* unix */ {wxFONTENCODING_ISO8859_7, STOP}, + /* windows */ {wxFONTENCODING_CP1253, STOP}, + /* os2 */ {STOP}, + /* mac */ {wxFONTENCODING_MACGREEK, STOP} + }, + + // Arabic + { + /* unix */ {wxFONTENCODING_ISO8859_6, STOP}, + /* windows */ {wxFONTENCODING_CP1256, STOP}, + /* os2 */ {STOP}, + /* mac */ {wxFONTENCODING_MACARABIC, STOP} + }, + + // Turkish + { + /* unix */ {wxFONTENCODING_ISO8859_9, STOP}, + /* windows */ {wxFONTENCODING_CP1254, STOP}, + /* os2 */ {STOP}, + /* mac */ {wxFONTENCODING_MACTURKISH, STOP} + }, + + // Cyrillic + { + /* unix */ {wxFONTENCODING_KOI8, wxFONTENCODING_KOI8_U, wxFONTENCODING_ISO8859_5, STOP}, + /* windows */ {wxFONTENCODING_CP1251, STOP}, + /* os2 */ {STOP}, + /* mac */ {wxFONTENCODING_MACCYRILLIC, STOP} + }, + + {{STOP},{STOP},{STOP},{STOP}} /* Terminator */ + /* no, _not_ Arnold! */ +}; + + +static bool FindEncoding(const wxFontEncodingArray& arr, wxFontEncoding f) +{ + for (wxFontEncodingArray::const_iterator it = arr.begin(), en = arr.end(); + it != en; ++it) + if (*it == f) + return true; + return false; +} + +wxFontEncodingArray wxEncodingConverter::GetPlatformEquivalents(wxFontEncoding enc, int platform) +{ + if (platform == wxPLATFORM_CURRENT) + { +#if defined(__WXMSW__) + platform = wxPLATFORM_WINDOWS; +#elif defined(__WXGTK__) || defined(__WXMOTIF__) + platform = wxPLATFORM_UNIX; +#elif defined(__WXPM__) + platform = wxPLATFORM_OS2; +#elif defined(__WXMAC__) + platform = wxPLATFORM_MAC; +#endif + } + + int i, clas, e ; + const wxFontEncoding *f; + wxFontEncodingArray arr; + + clas = 0; + while (EquivalentEncodings[clas][0][0] != STOP) + { + for (i = 0; i < NUM_OF_PLATFORMS; i++) + for (e = 0; EquivalentEncodings[clas][i][e] != STOP; e++) + if (EquivalentEncodings[clas][i][e] == enc) + { + for (f = EquivalentEncodings[clas][platform]; *f != STOP; f++) + if (*f == enc) arr.push_back(enc); + for (f = EquivalentEncodings[clas][platform]; *f != STOP; f++) + if (!FindEncoding(arr, *f)) arr.push_back(*f); + i = NUM_OF_PLATFORMS/*hack*/; break; + } + clas++; + } + + return arr; +} + + + +wxFontEncodingArray wxEncodingConverter::GetAllEquivalents(wxFontEncoding enc) +{ + int i, clas, e, j ; + const wxFontEncoding *f; + wxFontEncodingArray arr; + + arr = GetPlatformEquivalents(enc); // we want them to be first items in array + + clas = 0; + while (EquivalentEncodings[clas][0][0] != STOP) + { + for (i = 0; i < NUM_OF_PLATFORMS; i++) + for (e = 0; EquivalentEncodings[clas][i][e] != STOP; e++) + if (EquivalentEncodings[clas][i][e] == enc) + { + for (j = 0; j < NUM_OF_PLATFORMS; j++) + for (f = EquivalentEncodings[clas][j]; *f != STOP; f++) + if (!FindEncoding(arr, *f)) arr.push_back(*f); + i = NUM_OF_PLATFORMS/*hack*/; break; + } + clas++; + } + + return arr; +} + diff --git a/Externals/wxWidgets/src/common/event.cpp b/Externals/wxWidgets/src/common/event.cpp index a12e131f8a..e006c58588 100644 --- a/Externals/wxWidgets/src/common/event.cpp +++ b/Externals/wxWidgets/src/common/event.cpp @@ -1,1490 +1,1490 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/event.cpp -// Purpose: Event classes -// Author: Julian Smart -// Modified by: -// Created: 01/02/97 -// RCS-ID: $Id: event.cpp 51404 2008-01-27 12:57:04Z VZ $ -// Copyright: (c) Julian Smart -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#include "wx/event.h" - -#ifndef WX_PRECOMP - #include "wx/list.h" - #include "wx/app.h" - #include "wx/utils.h" - #include "wx/stopwatch.h" - #include "wx/module.h" - - #if wxUSE_GUI - #include "wx/control.h" - #include "wx/dc.h" - #include "wx/textctrl.h" - #include "wx/validate.h" - #endif // wxUSE_GUI -#endif - -#if wxUSE_BASE - #include "wx/ptr_scpd.h" - - wxDECLARE_SCOPED_PTR(wxEvent, wxEventPtr) - wxDEFINE_SCOPED_PTR(wxEvent, wxEventPtr) -#endif // wxUSE_BASE - -// ---------------------------------------------------------------------------- -// wxWin macros -// ---------------------------------------------------------------------------- - -#if wxUSE_BASE - IMPLEMENT_DYNAMIC_CLASS(wxEvtHandler, wxObject) - IMPLEMENT_ABSTRACT_CLASS(wxEvent, wxObject) -#endif // wxUSE_BASE - -#if wxUSE_GUI - IMPLEMENT_DYNAMIC_CLASS(wxIdleEvent, wxEvent) - IMPLEMENT_DYNAMIC_CLASS(wxCommandEvent, wxEvent) - IMPLEMENT_DYNAMIC_CLASS(wxNotifyEvent, wxCommandEvent) - IMPLEMENT_DYNAMIC_CLASS(wxScrollEvent, wxCommandEvent) - IMPLEMENT_DYNAMIC_CLASS(wxScrollWinEvent, wxEvent) - IMPLEMENT_DYNAMIC_CLASS(wxMouseEvent, wxEvent) - IMPLEMENT_DYNAMIC_CLASS(wxKeyEvent, wxEvent) - IMPLEMENT_DYNAMIC_CLASS(wxSizeEvent, wxEvent) - IMPLEMENT_DYNAMIC_CLASS(wxPaintEvent, wxEvent) - IMPLEMENT_DYNAMIC_CLASS(wxNcPaintEvent, wxEvent) - IMPLEMENT_DYNAMIC_CLASS(wxEraseEvent, wxEvent) - IMPLEMENT_DYNAMIC_CLASS(wxMoveEvent, wxEvent) - IMPLEMENT_DYNAMIC_CLASS(wxFocusEvent, wxEvent) - IMPLEMENT_DYNAMIC_CLASS(wxChildFocusEvent, wxCommandEvent) - IMPLEMENT_DYNAMIC_CLASS(wxCloseEvent, wxEvent) - IMPLEMENT_DYNAMIC_CLASS(wxShowEvent, wxEvent) - IMPLEMENT_DYNAMIC_CLASS(wxMaximizeEvent, wxEvent) - IMPLEMENT_DYNAMIC_CLASS(wxIconizeEvent, wxEvent) - IMPLEMENT_DYNAMIC_CLASS(wxMenuEvent, wxEvent) - IMPLEMENT_DYNAMIC_CLASS(wxJoystickEvent, wxEvent) - IMPLEMENT_DYNAMIC_CLASS(wxDropFilesEvent, wxEvent) - IMPLEMENT_DYNAMIC_CLASS(wxActivateEvent, wxEvent) - IMPLEMENT_DYNAMIC_CLASS(wxInitDialogEvent, wxEvent) - IMPLEMENT_DYNAMIC_CLASS(wxSetCursorEvent, wxEvent) - IMPLEMENT_DYNAMIC_CLASS(wxSysColourChangedEvent, wxEvent) - IMPLEMENT_DYNAMIC_CLASS(wxDisplayChangedEvent, wxEvent) - IMPLEMENT_DYNAMIC_CLASS(wxUpdateUIEvent, wxCommandEvent) - IMPLEMENT_DYNAMIC_CLASS(wxNavigationKeyEvent, wxEvent) - IMPLEMENT_DYNAMIC_CLASS(wxPaletteChangedEvent, wxEvent) - IMPLEMENT_DYNAMIC_CLASS(wxQueryNewPaletteEvent, wxEvent) - IMPLEMENT_DYNAMIC_CLASS(wxWindowCreateEvent, wxEvent) - IMPLEMENT_DYNAMIC_CLASS(wxWindowDestroyEvent, wxEvent) - IMPLEMENT_DYNAMIC_CLASS(wxHelpEvent, wxCommandEvent) - IMPLEMENT_DYNAMIC_CLASS(wxContextMenuEvent, wxCommandEvent) - IMPLEMENT_DYNAMIC_CLASS(wxMouseCaptureChangedEvent, wxEvent) - IMPLEMENT_DYNAMIC_CLASS(wxMouseCaptureLostEvent, wxEvent) - IMPLEMENT_DYNAMIC_CLASS(wxClipboardTextEvent, wxCommandEvent) -#endif // wxUSE_GUI - -#if wxUSE_BASE - -const wxEventTable *wxEvtHandler::GetEventTable() const - { return &wxEvtHandler::sm_eventTable; } - -const wxEventTable wxEvtHandler::sm_eventTable = - { (const wxEventTable *)NULL, &wxEvtHandler::sm_eventTableEntries[0] }; - -wxEventHashTable &wxEvtHandler::GetEventHashTable() const - { return wxEvtHandler::sm_eventHashTable; } - -wxEventHashTable wxEvtHandler::sm_eventHashTable(wxEvtHandler::sm_eventTable); - -const wxEventTableEntry wxEvtHandler::sm_eventTableEntries[] = - { DECLARE_EVENT_TABLE_ENTRY(wxEVT_NULL, 0, 0, (wxObjectEventFunction)NULL, NULL) }; - - -#ifdef __WXDEBUG__ -// Clear up event hash table contents or we can get problems -// when C++ is cleaning up the static object -class wxEventTableEntryModule: public wxModule -{ -DECLARE_DYNAMIC_CLASS(wxEventTableEntryModule) -public: - wxEventTableEntryModule() {} - bool OnInit() - { - wxEventHashTable::ReconstructAll(); - return true; - } - void OnExit() - { - wxEventHashTable::ClearAll(); - } -}; -IMPLEMENT_DYNAMIC_CLASS(wxEventTableEntryModule, wxModule) -#endif - -// ---------------------------------------------------------------------------- -// global variables -// ---------------------------------------------------------------------------- - -// To put pending event handlers -wxList *wxPendingEvents = (wxList *)NULL; - -#if wxUSE_THREADS - // protects wxPendingEvents list - wxCriticalSection *wxPendingEventsLocker = (wxCriticalSection *)NULL; -#endif - -#if !WXWIN_COMPATIBILITY_EVENT_TYPES - -// common event types are defined here, other event types are defined by the -// components which use them - -const wxEventType wxEVT_FIRST = 10000; -const wxEventType wxEVT_USER_FIRST = wxEVT_FIRST + 2000; - -DEFINE_EVENT_TYPE(wxEVT_NULL) -DEFINE_EVENT_TYPE(wxEVT_IDLE) -DEFINE_EVENT_TYPE(wxEVT_SOCKET) - -#endif // !WXWIN_COMPATIBILITY_EVENT_TYPES - -#endif // wxUSE_BASE - -#if wxUSE_GUI - -#if !WXWIN_COMPATIBILITY_EVENT_TYPES - -DEFINE_EVENT_TYPE(wxEVT_COMMAND_BUTTON_CLICKED) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_CHECKBOX_CLICKED) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_CHOICE_SELECTED) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_LISTBOX_SELECTED) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_LISTBOX_DOUBLECLICKED) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_CHECKLISTBOX_TOGGLED) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_MENU_SELECTED) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_SLIDER_UPDATED) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_RADIOBOX_SELECTED) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_RADIOBUTTON_SELECTED) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_SCROLLBAR_UPDATED) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_VLBOX_SELECTED) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_COMBOBOX_SELECTED) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_TOOL_RCLICKED) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_TOOL_ENTER) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_SPINCTRL_UPDATED) - -// Sockets and timers send events, too -DEFINE_EVENT_TYPE(wxEVT_TIMER) - -// Mouse event types -DEFINE_EVENT_TYPE(wxEVT_LEFT_DOWN) -DEFINE_EVENT_TYPE(wxEVT_LEFT_UP) -DEFINE_EVENT_TYPE(wxEVT_MIDDLE_DOWN) -DEFINE_EVENT_TYPE(wxEVT_MIDDLE_UP) -DEFINE_EVENT_TYPE(wxEVT_RIGHT_DOWN) -DEFINE_EVENT_TYPE(wxEVT_RIGHT_UP) -DEFINE_EVENT_TYPE(wxEVT_MOTION) -DEFINE_EVENT_TYPE(wxEVT_ENTER_WINDOW) -DEFINE_EVENT_TYPE(wxEVT_LEAVE_WINDOW) -DEFINE_EVENT_TYPE(wxEVT_LEFT_DCLICK) -DEFINE_EVENT_TYPE(wxEVT_MIDDLE_DCLICK) -DEFINE_EVENT_TYPE(wxEVT_RIGHT_DCLICK) -DEFINE_EVENT_TYPE(wxEVT_SET_FOCUS) -DEFINE_EVENT_TYPE(wxEVT_KILL_FOCUS) -DEFINE_EVENT_TYPE(wxEVT_CHILD_FOCUS) -DEFINE_EVENT_TYPE(wxEVT_MOUSEWHEEL) - -// Non-client mouse events -DEFINE_EVENT_TYPE(wxEVT_NC_LEFT_DOWN) -DEFINE_EVENT_TYPE(wxEVT_NC_LEFT_UP) -DEFINE_EVENT_TYPE(wxEVT_NC_MIDDLE_DOWN) -DEFINE_EVENT_TYPE(wxEVT_NC_MIDDLE_UP) -DEFINE_EVENT_TYPE(wxEVT_NC_RIGHT_DOWN) -DEFINE_EVENT_TYPE(wxEVT_NC_RIGHT_UP) -DEFINE_EVENT_TYPE(wxEVT_NC_MOTION) -DEFINE_EVENT_TYPE(wxEVT_NC_ENTER_WINDOW) -DEFINE_EVENT_TYPE(wxEVT_NC_LEAVE_WINDOW) -DEFINE_EVENT_TYPE(wxEVT_NC_LEFT_DCLICK) -DEFINE_EVENT_TYPE(wxEVT_NC_MIDDLE_DCLICK) -DEFINE_EVENT_TYPE(wxEVT_NC_RIGHT_DCLICK) - -// Character input event type -DEFINE_EVENT_TYPE(wxEVT_CHAR) -DEFINE_EVENT_TYPE(wxEVT_CHAR_HOOK) -DEFINE_EVENT_TYPE(wxEVT_NAVIGATION_KEY) -DEFINE_EVENT_TYPE(wxEVT_KEY_DOWN) -DEFINE_EVENT_TYPE(wxEVT_KEY_UP) -#if wxUSE_HOTKEY -DEFINE_EVENT_TYPE(wxEVT_HOTKEY) -#endif - -// Set cursor event -DEFINE_EVENT_TYPE(wxEVT_SET_CURSOR) - -// wxScrollbar and wxSlider event identifiers -DEFINE_EVENT_TYPE(wxEVT_SCROLL_TOP) -DEFINE_EVENT_TYPE(wxEVT_SCROLL_BOTTOM) -DEFINE_EVENT_TYPE(wxEVT_SCROLL_LINEUP) -DEFINE_EVENT_TYPE(wxEVT_SCROLL_LINEDOWN) -DEFINE_EVENT_TYPE(wxEVT_SCROLL_PAGEUP) -DEFINE_EVENT_TYPE(wxEVT_SCROLL_PAGEDOWN) -DEFINE_EVENT_TYPE(wxEVT_SCROLL_THUMBTRACK) -DEFINE_EVENT_TYPE(wxEVT_SCROLL_THUMBRELEASE) -DEFINE_EVENT_TYPE(wxEVT_SCROLL_CHANGED) - -// Scroll events from wxWindow -DEFINE_EVENT_TYPE(wxEVT_SCROLLWIN_TOP) -DEFINE_EVENT_TYPE(wxEVT_SCROLLWIN_BOTTOM) -DEFINE_EVENT_TYPE(wxEVT_SCROLLWIN_LINEUP) -DEFINE_EVENT_TYPE(wxEVT_SCROLLWIN_LINEDOWN) -DEFINE_EVENT_TYPE(wxEVT_SCROLLWIN_PAGEUP) -DEFINE_EVENT_TYPE(wxEVT_SCROLLWIN_PAGEDOWN) -DEFINE_EVENT_TYPE(wxEVT_SCROLLWIN_THUMBTRACK) -DEFINE_EVENT_TYPE(wxEVT_SCROLLWIN_THUMBRELEASE) - -// System events -DEFINE_EVENT_TYPE(wxEVT_SIZE) -DEFINE_EVENT_TYPE(wxEVT_SIZING) -DEFINE_EVENT_TYPE(wxEVT_MOVE) -DEFINE_EVENT_TYPE(wxEVT_MOVING) -DEFINE_EVENT_TYPE(wxEVT_CLOSE_WINDOW) -DEFINE_EVENT_TYPE(wxEVT_END_SESSION) -DEFINE_EVENT_TYPE(wxEVT_QUERY_END_SESSION) -DEFINE_EVENT_TYPE(wxEVT_HIBERNATE) -DEFINE_EVENT_TYPE(wxEVT_ACTIVATE_APP) -DEFINE_EVENT_TYPE(wxEVT_POWER) -DEFINE_EVENT_TYPE(wxEVT_ACTIVATE) -DEFINE_EVENT_TYPE(wxEVT_CREATE) -DEFINE_EVENT_TYPE(wxEVT_DESTROY) -DEFINE_EVENT_TYPE(wxEVT_SHOW) -DEFINE_EVENT_TYPE(wxEVT_ICONIZE) -DEFINE_EVENT_TYPE(wxEVT_MAXIMIZE) -DEFINE_EVENT_TYPE(wxEVT_MOUSE_CAPTURE_CHANGED) -DEFINE_EVENT_TYPE(wxEVT_MOUSE_CAPTURE_LOST) -DEFINE_EVENT_TYPE(wxEVT_PAINT) -DEFINE_EVENT_TYPE(wxEVT_ERASE_BACKGROUND) -DEFINE_EVENT_TYPE(wxEVT_NC_PAINT) -DEFINE_EVENT_TYPE(wxEVT_PAINT_ICON) -DEFINE_EVENT_TYPE(wxEVT_MENU_OPEN) -DEFINE_EVENT_TYPE(wxEVT_MENU_CLOSE) -DEFINE_EVENT_TYPE(wxEVT_MENU_HIGHLIGHT) -DEFINE_EVENT_TYPE(wxEVT_CONTEXT_MENU) -DEFINE_EVENT_TYPE(wxEVT_SYS_COLOUR_CHANGED) -DEFINE_EVENT_TYPE(wxEVT_DISPLAY_CHANGED) -DEFINE_EVENT_TYPE(wxEVT_SETTING_CHANGED) -DEFINE_EVENT_TYPE(wxEVT_QUERY_NEW_PALETTE) -DEFINE_EVENT_TYPE(wxEVT_PALETTE_CHANGED) -DEFINE_EVENT_TYPE(wxEVT_JOY_BUTTON_DOWN) -DEFINE_EVENT_TYPE(wxEVT_JOY_BUTTON_UP) -DEFINE_EVENT_TYPE(wxEVT_JOY_MOVE) -DEFINE_EVENT_TYPE(wxEVT_JOY_ZMOVE) -DEFINE_EVENT_TYPE(wxEVT_DROP_FILES) -DEFINE_EVENT_TYPE(wxEVT_DRAW_ITEM) -DEFINE_EVENT_TYPE(wxEVT_MEASURE_ITEM) -DEFINE_EVENT_TYPE(wxEVT_COMPARE_ITEM) -DEFINE_EVENT_TYPE(wxEVT_INIT_DIALOG) -DEFINE_EVENT_TYPE(wxEVT_UPDATE_UI) - -// Clipboard events -DEFINE_EVENT_TYPE(wxEVT_COMMAND_TEXT_COPY) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_TEXT_CUT) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_TEXT_PASTE) - -// Generic command events -// Note: a click is a higher-level event than button down/up -DEFINE_EVENT_TYPE(wxEVT_COMMAND_LEFT_CLICK) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_LEFT_DCLICK) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_RIGHT_CLICK) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_RIGHT_DCLICK) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_SET_FOCUS) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_KILL_FOCUS) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_ENTER) - -// Help events -DEFINE_EVENT_TYPE(wxEVT_HELP) -DEFINE_EVENT_TYPE(wxEVT_DETAILED_HELP) - -#endif // !WXWIN_COMPATIBILITY_EVENT_TYPES - -#endif // wxUSE_GUI - -#if wxUSE_BASE - -// ============================================================================ -// implementation -// ============================================================================ - -// ---------------------------------------------------------------------------- -// event initialization -// ---------------------------------------------------------------------------- - -int wxNewEventType() -{ - // MT-FIXME - static int s_lastUsedEventType = wxEVT_FIRST; - - return s_lastUsedEventType++; -} - -// ---------------------------------------------------------------------------- -// wxEvent -// ---------------------------------------------------------------------------- - -/* - * General wxWidgets events, covering - * all interesting things that might happen (button clicking, resizing, - * setting text in widgets, etc.). - * - * For each completely new event type, derive a new event class. - * - */ - -wxEvent::wxEvent(int theId, wxEventType commandType ) -{ - m_eventType = commandType; - m_eventObject = (wxObject *) NULL; - m_timeStamp = 0; - m_id = theId; - m_skipped = false; - m_callbackUserData = (wxObject *) NULL; - m_isCommandEvent = false; - m_propagationLevel = wxEVENT_PROPAGATE_NONE; -} - -wxEvent::wxEvent(const wxEvent &src) - : wxObject(src) - , m_eventObject(src.m_eventObject) - , m_eventType(src.m_eventType) - , m_timeStamp(src.m_timeStamp) - , m_id(src.m_id) - , m_callbackUserData(src.m_callbackUserData) - , m_propagationLevel(src.m_propagationLevel) - , m_skipped(src.m_skipped) - , m_isCommandEvent(src.m_isCommandEvent) -{ -} - -#endif // wxUSE_BASE - -#if wxUSE_GUI - -/* - * Command events - * - */ - -#ifdef __VISUALC__ - // 'this' : used in base member initializer list (for m_commandString) - #pragma warning(disable:4355) -#endif - -wxCommandEvent::wxCommandEvent(wxEventType commandType, int theId) - : wxEvent(theId, commandType) -#if WXWIN_COMPATIBILITY_2_4 - , m_commandString(this) -#endif -{ - m_clientData = (char *) NULL; - m_clientObject = (wxClientData *) NULL; - m_extraLong = 0; - m_commandInt = 0; - m_isCommandEvent = true; - - // the command events are propagated upwards by default - m_propagationLevel = wxEVENT_PROPAGATE_MAX; -} - -#ifdef __VISUALC__ - #pragma warning(default:4355) -#endif - -wxString wxCommandEvent::GetString() const -{ - if(m_eventType != wxEVT_COMMAND_TEXT_UPDATED || !m_eventObject) - return m_cmdString; - else - { -#if wxUSE_TEXTCTRL - wxTextCtrl *txt = wxDynamicCast(m_eventObject, wxTextCtrl); - if(txt) - return txt->GetValue(); - else -#endif // wxUSE_TEXTCTRL - return m_cmdString; - } -} - -/* - * UI update events - */ - -#if wxUSE_LONGLONG -wxLongLong wxUpdateUIEvent::sm_lastUpdate = 0; -#endif - -long wxUpdateUIEvent::sm_updateInterval = 0; - -wxUpdateUIMode wxUpdateUIEvent::sm_updateMode = wxUPDATE_UI_PROCESS_ALL; - -// Can we update? -bool wxUpdateUIEvent::CanUpdate(wxWindowBase *win) -{ - // Don't update if we've switched global updating off - // and this window doesn't support updates. - if (win && - (GetMode() == wxUPDATE_UI_PROCESS_SPECIFIED && - ((win->GetExtraStyle() & wxWS_EX_PROCESS_UI_UPDATES) == 0))) - return false; - - if (sm_updateInterval == -1) - return false; - - if (sm_updateInterval == 0) - return true; - -#if wxUSE_STOPWATCH && wxUSE_LONGLONG - wxLongLong now = wxGetLocalTimeMillis(); - if (now > (sm_lastUpdate + sm_updateInterval)) - { - return true; - } - - return false; -#else - // If we don't have wxStopWatch or wxLongLong, we - // should err on the safe side and update now anyway. - return true; -#endif -} - -// Reset the update time to provide a delay until the next -// time we should update -void wxUpdateUIEvent::ResetUpdateTime() -{ -#if wxUSE_STOPWATCH && wxUSE_LONGLONG - if (sm_updateInterval > 0) - { - wxLongLong now = wxGetLocalTimeMillis(); - if (now > (sm_lastUpdate + sm_updateInterval)) - { - sm_lastUpdate = now; - } - } -#endif -} - -/* - * Idle events - */ - -wxIdleMode wxIdleEvent::sm_idleMode = wxIDLE_PROCESS_ALL; - -// Can we send an idle event? -bool wxIdleEvent::CanSend(wxWindow* win) -{ - // Don't update if we've switched global updating off - // and this window doesn't support updates. - if (win && - (GetMode() == wxIDLE_PROCESS_SPECIFIED && - ((win->GetExtraStyle() & wxWS_EX_PROCESS_IDLE) == 0))) - return false; - - return true; -} - -/* - * Scroll events - */ - -wxScrollEvent::wxScrollEvent(wxEventType commandType, - int id, - int pos, - int orient) - : wxCommandEvent(commandType, id) -{ - m_extraLong = orient; - m_commandInt = pos; -} - -/* - * ScrollWin events - */ - -wxScrollWinEvent::wxScrollWinEvent(wxEventType commandType, - int pos, - int orient) -{ - m_eventType = commandType; - m_extraLong = orient; - m_commandInt = pos; -} - -/* - * Mouse events - * - */ - -wxMouseEvent::wxMouseEvent(wxEventType commandType) -{ - m_eventType = commandType; - m_metaDown = false; - m_altDown = false; - m_controlDown = false; - m_shiftDown = false; - m_leftDown = false; - m_rightDown = false; - m_middleDown = false; - m_x = 0; - m_y = 0; - m_wheelRotation = 0; - m_wheelDelta = 0; - m_linesPerAction = 0; -} - -void wxMouseEvent::Assign(const wxMouseEvent& event) -{ - m_eventType = event.m_eventType; - - m_x = event.m_x; - m_y = event.m_y; - - m_leftDown = event.m_leftDown; - m_middleDown = event.m_middleDown; - m_rightDown = event.m_rightDown; - - m_controlDown = event.m_controlDown; - m_shiftDown = event.m_shiftDown; - m_altDown = event.m_altDown; - m_metaDown = event.m_metaDown; - - m_wheelRotation = event.m_wheelRotation; - m_wheelDelta = event.m_wheelDelta; - m_linesPerAction = event.m_linesPerAction; -} - -// return true if was a button dclick event -bool wxMouseEvent::ButtonDClick(int but) const -{ - switch (but) - { - default: - wxFAIL_MSG(wxT("invalid parameter in wxMouseEvent::ButtonDClick")); - // fall through - - case wxMOUSE_BTN_ANY: - return (LeftDClick() || MiddleDClick() || RightDClick()); - - case wxMOUSE_BTN_LEFT: - return LeftDClick(); - - case wxMOUSE_BTN_MIDDLE: - return MiddleDClick(); - - case wxMOUSE_BTN_RIGHT: - return RightDClick(); - } -} - -// return true if was a button down event -bool wxMouseEvent::ButtonDown(int but) const -{ - switch (but) - { - default: - wxFAIL_MSG(wxT("invalid parameter in wxMouseEvent::ButtonDown")); - // fall through - - case wxMOUSE_BTN_ANY: - return (LeftDown() || MiddleDown() || RightDown()); - - case wxMOUSE_BTN_LEFT: - return LeftDown(); - - case wxMOUSE_BTN_MIDDLE: - return MiddleDown(); - - case wxMOUSE_BTN_RIGHT: - return RightDown(); - } -} - -// return true if was a button up event -bool wxMouseEvent::ButtonUp(int but) const -{ - switch (but) - { - default: - wxFAIL_MSG(wxT("invalid parameter in wxMouseEvent::ButtonUp")); - // fall through - - case wxMOUSE_BTN_ANY: - return (LeftUp() || MiddleUp() || RightUp()); - - case wxMOUSE_BTN_LEFT: - return LeftUp(); - - case wxMOUSE_BTN_MIDDLE: - return MiddleUp(); - - case wxMOUSE_BTN_RIGHT: - return RightUp(); - } -} - -// return true if the given button is currently changing state -bool wxMouseEvent::Button(int but) const -{ - switch (but) - { - default: - wxFAIL_MSG(wxT("invalid parameter in wxMouseEvent::Button")); - // fall through - - case wxMOUSE_BTN_ANY: - return ButtonUp(wxMOUSE_BTN_ANY) || - ButtonDown(wxMOUSE_BTN_ANY) || - ButtonDClick(wxMOUSE_BTN_ANY); - - case wxMOUSE_BTN_LEFT: - return LeftDown() || LeftUp() || LeftDClick(); - - case wxMOUSE_BTN_MIDDLE: - return MiddleDown() || MiddleUp() || MiddleDClick(); - - case wxMOUSE_BTN_RIGHT: - return RightDown() || RightUp() || RightDClick(); - } -} - -bool wxMouseEvent::ButtonIsDown(int but) const -{ - switch (but) - { - default: - wxFAIL_MSG(wxT("invalid parameter in wxMouseEvent::ButtonIsDown")); - // fall through - - case wxMOUSE_BTN_ANY: - return LeftIsDown() || MiddleIsDown() || RightIsDown(); - - case wxMOUSE_BTN_LEFT: - return LeftIsDown(); - - case wxMOUSE_BTN_MIDDLE: - return MiddleIsDown(); - - case wxMOUSE_BTN_RIGHT: - return RightIsDown(); - } -} - -int wxMouseEvent::GetButton() const -{ - for ( int i = 1; i <= 3; i++ ) - { - if ( Button(i) ) - { - return i; - } - } - - return wxMOUSE_BTN_NONE; -} - -// Find the logical position of the event given the DC -wxPoint wxMouseEvent::GetLogicalPosition(const wxDC& dc) const -{ - wxPoint pt(dc.DeviceToLogicalX(m_x), dc.DeviceToLogicalY(m_y)); - return pt; -} - - -/* - * Keyboard event - * - */ - -wxKeyEvent::wxKeyEvent(wxEventType type) -{ - m_eventType = type; - m_shiftDown = false; - m_controlDown = false; - m_metaDown = false; - m_altDown = false; - m_keyCode = 0; - m_scanCode = 0; -#if wxUSE_UNICODE - m_uniChar = 0; -#endif -} - -wxKeyEvent::wxKeyEvent(const wxKeyEvent& evt) - : wxEvent(evt) -{ - m_x = evt.m_x; - m_y = evt.m_y; - - m_keyCode = evt.m_keyCode; - - m_controlDown = evt.m_controlDown; - m_shiftDown = evt.m_shiftDown; - m_altDown = evt.m_altDown; - m_metaDown = evt.m_metaDown; - m_scanCode = evt.m_scanCode; - m_rawCode = evt.m_rawCode; - m_rawFlags = evt.m_rawFlags; - -#if wxUSE_UNICODE - m_uniChar = evt.m_uniChar; -#endif -} - -#if WXWIN_COMPATIBILITY_2_6 -long wxKeyEvent::KeyCode() const -{ - return m_keyCode; -} -#endif // WXWIN_COMPATIBILITY_2_6 - -wxWindowCreateEvent::wxWindowCreateEvent(wxWindow *win) -{ - SetEventType(wxEVT_CREATE); - SetEventObject(win); -} - -wxWindowDestroyEvent::wxWindowDestroyEvent(wxWindow *win) -{ - SetEventType(wxEVT_DESTROY); - SetEventObject(win); -} - -wxChildFocusEvent::wxChildFocusEvent(wxWindow *win) - : wxCommandEvent(wxEVT_CHILD_FOCUS) -{ - SetEventObject(win); -} - -// ---------------------------------------------------------------------------- -// wxHelpEvent -// ---------------------------------------------------------------------------- - -/* static */ -wxHelpEvent::Origin wxHelpEvent::GuessOrigin(Origin origin) -{ - if ( origin == Origin_Unknown ) - { - // assume that the event comes from the help button if it's not from - // keyboard and that pressing F1 always results in the help event - origin = wxGetKeyState(WXK_F1) ? Origin_Keyboard : Origin_HelpButton; - } - - return origin; -} - -#endif // wxUSE_GUI - - -#if wxUSE_BASE - -// ---------------------------------------------------------------------------- -// wxEventHashTable -// ---------------------------------------------------------------------------- - -static const int EVENT_TYPE_TABLE_INIT_SIZE = 31; // Not too big not too small... - -wxEventHashTable* wxEventHashTable::sm_first = NULL; - -wxEventHashTable::wxEventHashTable(const wxEventTable &table) - : m_table(table), - m_rebuildHash(true) -{ - AllocEventTypeTable(EVENT_TYPE_TABLE_INIT_SIZE); - - m_next = sm_first; - if (m_next) - m_next->m_previous = this; - sm_first = this; -} - -wxEventHashTable::~wxEventHashTable() -{ - if (m_next) - m_next->m_previous = m_previous; - if (m_previous) - m_previous->m_next = m_next; - if (sm_first == this) - sm_first = m_next; - - Clear(); -} - -void wxEventHashTable::Clear() -{ - size_t i; - for(i = 0; i < m_size; i++) - { - EventTypeTablePointer eTTnode = m_eventTypeTable[i]; - if (eTTnode) - { - delete eTTnode; - } - } - - // Necessary in order to not invoke the - // overloaded delete operator when statics are cleaned up - if (m_eventTypeTable) - delete[] m_eventTypeTable; - - m_eventTypeTable = NULL; - m_size = 0; -} - -// Clear all tables -void wxEventHashTable::ClearAll() -{ - wxEventHashTable* table = sm_first; - while (table) - { - table->Clear(); - table = table->m_next; - } -} - -// Rebuild all tables if they were cleared by ClearAll -void wxEventHashTable::ReconstructAll() -{ - wxEventHashTable* table = sm_first; - while (table) - { - // This will only be true if the event table was cleared. - // What we do here is basically what the constructor does. - if(table->m_eventTypeTable == NULL) - { - table->AllocEventTypeTable(EVENT_TYPE_TABLE_INIT_SIZE); - table->m_rebuildHash = true; - } - table = table->m_next; - } -} - -bool wxEventHashTable::HandleEvent(wxEvent &event, wxEvtHandler *self) -{ - if (m_rebuildHash) - { - InitHashTable(); - m_rebuildHash = false; - } - - if (!m_eventTypeTable) - return false; - - // Find all entries for the given event type. - wxEventType eventType = event.GetEventType(); - const EventTypeTablePointer eTTnode = m_eventTypeTable[eventType % m_size]; - if (eTTnode && eTTnode->eventType == eventType) - { - // Now start the search for an event handler - // that can handle an event with the given ID. - const wxEventTableEntryPointerArray& - eventEntryTable = eTTnode->eventEntryTable; - - const size_t count = eventEntryTable.GetCount(); - for (size_t n = 0; n < count; n++) - { - if ( wxEvtHandler:: - ProcessEventIfMatches(*eventEntryTable[n], self, event) ) - { - return true; - } - } - } - - return false; -} - -void wxEventHashTable::InitHashTable() -{ - // Loop over the event tables and all its base tables. - const wxEventTable *table = &m_table; - while (table) - { - // Retrieve all valid event handler entries - const wxEventTableEntry *entry = table->entries; - while (entry->m_fn != 0) - { - // Add the event entry in the Hash. - AddEntry(*entry); - - entry++; - } - - table = table->baseTable; - } - - // Lets free some memory. - size_t i; - for(i = 0; i < m_size; i++) - { - EventTypeTablePointer eTTnode = m_eventTypeTable[i]; - if (eTTnode) - { - eTTnode->eventEntryTable.Shrink(); - } - } -} - -void wxEventHashTable::AddEntry(const wxEventTableEntry &entry) -{ - // This might happen 'accidentally' as the app is exiting - if (!m_eventTypeTable) - return; - - EventTypeTablePointer *peTTnode = &m_eventTypeTable[entry.m_eventType % m_size]; - EventTypeTablePointer eTTnode = *peTTnode; - - if (eTTnode) - { - if (eTTnode->eventType != entry.m_eventType) - { - // Resize the table! - GrowEventTypeTable(); - // Try again to add it. - AddEntry(entry); - return; - } - } - else - { - eTTnode = new EventTypeTable; - eTTnode->eventType = entry.m_eventType; - *peTTnode = eTTnode; - } - - // Fill all hash entries between entry.m_id and entry.m_lastId... - eTTnode->eventEntryTable.Add(&entry); -} - -void wxEventHashTable::AllocEventTypeTable(size_t size) -{ - m_eventTypeTable = new EventTypeTablePointer[size]; - memset((void *)m_eventTypeTable, 0, sizeof(EventTypeTablePointer)*size); - m_size = size; -} - -void wxEventHashTable::GrowEventTypeTable() -{ - size_t oldSize = m_size; - EventTypeTablePointer *oldEventTypeTable = m_eventTypeTable; - - // TODO: Search the most optimal grow sequence - AllocEventTypeTable(/* GetNextPrime(oldSize) */oldSize*2+1); - - for ( size_t i = 0; i < oldSize; /* */ ) - { - EventTypeTablePointer eTToldNode = oldEventTypeTable[i]; - if (eTToldNode) - { - EventTypeTablePointer *peTTnode = &m_eventTypeTable[eTToldNode->eventType % m_size]; - EventTypeTablePointer eTTnode = *peTTnode; - - // Check for collision, we don't want any. - if (eTTnode) - { - GrowEventTypeTable(); - continue; // Don't increment the counter, - // as we still need to add this element. - } - else - { - // Get the old value and put it in the new table. - *peTTnode = oldEventTypeTable[i]; - } - } - - i++; - } - - delete[] oldEventTypeTable; -} - - -// ---------------------------------------------------------------------------- -// wxEvtHandler -// ---------------------------------------------------------------------------- - -/* - * Event handler - */ - -wxEvtHandler::wxEvtHandler() -{ - m_nextHandler = (wxEvtHandler *) NULL; - m_previousHandler = (wxEvtHandler *) NULL; - m_enabled = true; - m_dynamicEvents = (wxList *) NULL; - m_pendingEvents = (wxList *) NULL; -#if wxUSE_THREADS -# if !defined(__VISAGECPP__) - m_eventsLocker = new wxCriticalSection; -# endif -#endif - - // no client data (yet) - m_clientData = NULL; - m_clientDataType = wxClientData_None; -} - -wxEvtHandler::~wxEvtHandler() -{ - // Takes itself out of the list of handlers - if (m_previousHandler) - m_previousHandler->m_nextHandler = m_nextHandler; - - if (m_nextHandler) - m_nextHandler->m_previousHandler = m_previousHandler; - - if (m_dynamicEvents) - { - for ( wxList::iterator it = m_dynamicEvents->begin(), - end = m_dynamicEvents->end(); - it != end; - ++it ) - { -#if WXWIN_COMPATIBILITY_EVENT_TYPES - wxEventTableEntry *entry = (wxEventTableEntry*)*it; -#else // !WXWIN_COMPATIBILITY_EVENT_TYPES - wxDynamicEventTableEntry *entry = (wxDynamicEventTableEntry*)*it; -#endif // WXWIN_COMPATIBILITY_EVENT_TYPES/!WXWIN_COMPATIBILITY_EVENT_TYPES - - if (entry->m_callbackUserData) - delete entry->m_callbackUserData; - delete entry; - } - delete m_dynamicEvents; - }; - - if (m_pendingEvents) - m_pendingEvents->DeleteContents(true); - delete m_pendingEvents; - -#if wxUSE_THREADS -# if !defined(__VISAGECPP__) - delete m_eventsLocker; -# endif - - // Remove us from wxPendingEvents if necessary. - if(wxPendingEventsLocker) - wxENTER_CRIT_SECT(*wxPendingEventsLocker); - if ( wxPendingEvents ) - { - // Delete all occurences of this from the list of pending events - while (wxPendingEvents->DeleteObject(this)) { } // Do nothing - } - if(wxPendingEventsLocker) - wxLEAVE_CRIT_SECT(*wxPendingEventsLocker); -#endif - - // we only delete object data, not untyped - if ( m_clientDataType == wxClientData_Object ) - delete m_clientObject; -} - -#if wxUSE_THREADS - -bool wxEvtHandler::ProcessThreadEvent(wxEvent& event) -{ - // check that we are really in a child thread - wxASSERT_MSG( !wxThread::IsMain(), - wxT("use ProcessEvent() in main thread") ); - - AddPendingEvent(event); - - return true; -} - -void wxEvtHandler::ClearEventLocker() -{ -#if !defined(__VISAGECPP__) - delete m_eventsLocker; - m_eventsLocker = NULL; -#endif -} - -#endif // wxUSE_THREADS - -void wxEvtHandler::AddPendingEvent(wxEvent& event) -{ - // 1) Add event to list of pending events of this event handler - - wxEvent *eventCopy = event.Clone(); - - // we must be able to copy the events here so the event class must - // implement Clone() properly instead of just providing a NULL stab for it - wxCHECK_RET( eventCopy, - _T("events of this type aren't supposed to be posted") ); - - wxENTER_CRIT_SECT( Lock() ); - - if ( !m_pendingEvents ) - m_pendingEvents = new wxList; - - m_pendingEvents->Append(eventCopy); - - wxLEAVE_CRIT_SECT( Lock() ); - - // 2) Add this event handler to list of event handlers that - // have pending events. - - wxENTER_CRIT_SECT(*wxPendingEventsLocker); - - if ( !wxPendingEvents ) - wxPendingEvents = new wxList; - wxPendingEvents->Append(this); - - wxLEAVE_CRIT_SECT(*wxPendingEventsLocker); - - // 3) Inform the system that new pending events are somewhere, - // and that these should be processed in idle time. - wxWakeUpIdle(); -} - -void wxEvtHandler::ProcessPendingEvents() -{ - // this method is only called by wxApp if this handler does have - // pending events - wxCHECK_RET( m_pendingEvents, - wxT("Please call wxApp::ProcessPendingEvents() instead") ); - - wxENTER_CRIT_SECT( Lock() ); - - // we leave the loop once we have processed all events that were present at - // the start of ProcessPendingEvents because otherwise we could get into - // infinite loop if the pending event handler execution resulted in another - // event being posted - size_t n = m_pendingEvents->size(); - for ( wxList::compatibility_iterator node = m_pendingEvents->GetFirst(); - node; - node = m_pendingEvents->GetFirst() ) - { - wxEventPtr event(wx_static_cast(wxEvent *, node->GetData())); - - // It's important we remove event from list before processing it. - // Else a nested event loop, for example from a modal dialog, might - // process the same event again. - - m_pendingEvents->Erase(node); - - wxLEAVE_CRIT_SECT( Lock() ); - - ProcessEvent(*event); - - wxENTER_CRIT_SECT( Lock() ); - - if ( --n == 0 ) - break; - } - - wxLEAVE_CRIT_SECT( Lock() ); -} - -/* - * Event table stuff - */ -/* static */ bool -wxEvtHandler::ProcessEventIfMatches(const wxEventTableEntryBase& entry, - wxEvtHandler *handler, - wxEvent& event) -{ - int tableId1 = entry.m_id, - tableId2 = entry.m_lastId; - - // match only if the event type is the same and the id is either -1 in - // the event table (meaning "any") or the event id matches the id - // specified in the event table either exactly or by falling into - // range between first and last - if ((tableId1 == wxID_ANY) || - (tableId2 == wxID_ANY && tableId1 == event.GetId()) || - (tableId2 != wxID_ANY && - (event.GetId() >= tableId1 && event.GetId() <= tableId2))) - { - event.Skip(false); - event.m_callbackUserData = entry.m_callbackUserData; - -#if wxUSE_EXCEPTIONS - if ( wxTheApp ) - { - // call the handler via wxApp method which allows the user to catch - // any exceptions which may be thrown by any handler in the program - // in one place - wxTheApp->HandleEvent(handler, (wxEventFunction)entry.m_fn, event); - } - else -#endif // wxUSE_EXCEPTIONS - { - // no need for an extra virtual function call - (handler->*((wxEventFunction) (entry.m_fn)))(event); - } - - if (!event.GetSkipped()) - return true; - } - - return false; -} - -bool wxEvtHandler::TryParent(wxEvent& event) -{ - if ( wxTheApp && (this != wxTheApp) ) - { - // Special case: don't pass wxEVT_IDLE to wxApp, since it'll always - // swallow it. wxEVT_IDLE is sent explicitly to wxApp so it will be - // processed appropriately via SearchEventTable. - if ( event.GetEventType() != wxEVT_IDLE ) - { - if ( wxTheApp->ProcessEvent(event) ) - return true; - } - } - - return false; -} - -bool wxEvtHandler::ProcessEvent(wxEvent& event) -{ - // allow the application to hook into event processing - if ( wxTheApp ) - { - int rc = wxTheApp->FilterEvent(event); - if ( rc != -1 ) - { - wxASSERT_MSG( rc == 1 || rc == 0, - _T("unexpected wxApp::FilterEvent return value") ); - - return rc != 0; - } - //else: proceed normally - } - - // An event handler can be enabled or disabled - if ( GetEvtHandlerEnabled() ) - { - // if we have a validator, it has higher priority than our own event - // table - if ( TryValidator(event) ) - return true; - - // Handle per-instance dynamic event tables first - if ( m_dynamicEvents && SearchDynamicEventTable(event) ) - return true; - - // Then static per-class event tables - if ( GetEventHashTable().HandleEvent(event, this) ) - return true; - } - - // Try going down the event handler chain - if ( GetNextHandler() ) - { - if ( GetNextHandler()->ProcessEvent(event) ) - return true; - } - - // Finally propagate the event upwards the window chain and/or to the - // application object as necessary - return TryParent(event); -} - - -bool wxEvtHandler::SearchEventTable(wxEventTable& table, wxEvent& event) -{ - const wxEventType eventType = event.GetEventType(); - for ( int i = 0; table.entries[i].m_fn != 0; i++ ) - { - const wxEventTableEntry& entry = table.entries[i]; - if ( eventType == entry.m_eventType ) - { - if ( ProcessEventIfMatches(entry, this, event) ) - return true; - } - } - - return false; -} - -void wxEvtHandler::Connect( int id, int lastId, - int eventType, - wxObjectEventFunction func, - wxObject *userData, - wxEvtHandler* eventSink ) -{ -#if WXWIN_COMPATIBILITY_EVENT_TYPES - wxEventTableEntry *entry = new wxEventTableEntry; - entry->m_eventType = eventType; - entry->m_id = id; - entry->m_lastId = lastId; - entry->m_fn = func; - entry->m_callbackUserData = userData; -#else // !WXWIN_COMPATIBILITY_EVENT_TYPES - wxDynamicEventTableEntry *entry = - new wxDynamicEventTableEntry(eventType, id, lastId, func, userData, eventSink); -#endif // WXWIN_COMPATIBILITY_EVENT_TYPES/!WXWIN_COMPATIBILITY_EVENT_TYPES - - if (!m_dynamicEvents) - m_dynamicEvents = new wxList; - - // Insert at the front of the list so most recent additions are found first - m_dynamicEvents->Insert( (wxObject*) entry ); -} - -bool wxEvtHandler::Disconnect( int id, int lastId, wxEventType eventType, - wxObjectEventFunction func, - wxObject *userData, - wxEvtHandler* eventSink ) -{ - if (!m_dynamicEvents) - return false; - - wxList::compatibility_iterator node = m_dynamicEvents->GetFirst(); - while (node) - { -#if WXWIN_COMPATIBILITY_EVENT_TYPES - wxEventTableEntry *entry = (wxEventTableEntry*)node->GetData(); -#else // !WXWIN_COMPATIBILITY_EVENT_TYPES - wxDynamicEventTableEntry *entry = (wxDynamicEventTableEntry*)node->GetData(); -#endif // WXWIN_COMPATIBILITY_EVENT_TYPES/!WXWIN_COMPATIBILITY_EVENT_TYPES - - if ((entry->m_id == id) && - ((entry->m_lastId == lastId) || (lastId == wxID_ANY)) && - ((entry->m_eventType == eventType) || (eventType == wxEVT_NULL)) && - ((entry->m_fn == func) || (func == (wxObjectEventFunction)NULL)) && - ((entry->m_eventSink == eventSink) || (eventSink == (wxEvtHandler*)NULL)) && - ((entry->m_callbackUserData == userData) || (userData == (wxObject*)NULL))) - { - if (entry->m_callbackUserData) - delete entry->m_callbackUserData; - m_dynamicEvents->Erase( node ); - delete entry; - return true; - } - node = node->GetNext(); - } - return false; -} - -bool wxEvtHandler::SearchDynamicEventTable( wxEvent& event ) -{ - wxCHECK_MSG( m_dynamicEvents, false, - wxT("caller should check that we have dynamic events") ); - - wxList::compatibility_iterator node = m_dynamicEvents->GetFirst(); - while (node) - { -#if WXWIN_COMPATIBILITY_EVENT_TYPES - wxEventTableEntry *entry = (wxEventTableEntry*)node->GetData(); -#else // !WXWIN_COMPATIBILITY_EVENT_TYPES - wxDynamicEventTableEntry *entry = (wxDynamicEventTableEntry*)node->GetData(); -#endif // WXWIN_COMPATIBILITY_EVENT_TYPES/!WXWIN_COMPATIBILITY_EVENT_TYPES - - // get next node before (maybe) calling the event handler as it could - // call Disconnect() invalidating the current node - node = node->GetNext(); - - if ((event.GetEventType() == entry->m_eventType) && (entry->m_fn != 0)) - { - wxEvtHandler *handler = -#if !WXWIN_COMPATIBILITY_EVENT_TYPES - entry->m_eventSink ? entry->m_eventSink - : -#endif - this; - - if ( ProcessEventIfMatches(*entry, handler, event) ) - { - return true; - } - } - } - - return false; -} - -void wxEvtHandler::DoSetClientObject( wxClientData *data ) -{ - wxASSERT_MSG( m_clientDataType != wxClientData_Void, - wxT("can't have both object and void client data") ); - - if ( m_clientObject ) - delete m_clientObject; - - m_clientObject = data; - m_clientDataType = wxClientData_Object; -} - -wxClientData *wxEvtHandler::DoGetClientObject() const -{ - // it's not an error to call GetClientObject() on a window which doesn't - // have client data at all - NULL will be returned - wxASSERT_MSG( m_clientDataType != wxClientData_Void, - wxT("this window doesn't have object client data") ); - - return m_clientObject; -} - -void wxEvtHandler::DoSetClientData( void *data ) -{ - wxASSERT_MSG( m_clientDataType != wxClientData_Object, - wxT("can't have both object and void client data") ); - - m_clientData = data; - m_clientDataType = wxClientData_Void; -} - -void *wxEvtHandler::DoGetClientData() const -{ - // it's not an error to call GetClientData() on a window which doesn't have - // client data at all - NULL will be returned - wxASSERT_MSG( m_clientDataType != wxClientData_Object, - wxT("this window doesn't have void client data") ); - - return m_clientData; -} - -#endif // wxUSE_BASE - -#if wxUSE_GUI - -// Find a window with the focus, that is also a descendant of the given window. -// This is used to determine the window to initially send commands to. -wxWindow* wxFindFocusDescendant(wxWindow* ancestor) -{ - // Process events starting with the window with the focus, if any. - wxWindow* focusWin = wxWindow::FindFocus(); - wxWindow* win = focusWin; - - // Check if this is a descendant of this frame. - // If not, win will be set to NULL. - while (win) - { - if (win == ancestor) - break; - else - win = win->GetParent(); - } - if (win == (wxWindow*) NULL) - focusWin = (wxWindow*) NULL; - - return focusWin; -} - -#endif // wxUSE_GUI +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/event.cpp +// Purpose: Event classes +// Author: Julian Smart +// Modified by: +// Created: 01/02/97 +// RCS-ID: $Id: event.cpp 51404 2008-01-27 12:57:04Z VZ $ +// Copyright: (c) Julian Smart +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#include "wx/event.h" + +#ifndef WX_PRECOMP + #include "wx/list.h" + #include "wx/app.h" + #include "wx/utils.h" + #include "wx/stopwatch.h" + #include "wx/module.h" + + #if wxUSE_GUI + #include "wx/control.h" + #include "wx/dc.h" + #include "wx/textctrl.h" + #include "wx/validate.h" + #endif // wxUSE_GUI +#endif + +#if wxUSE_BASE + #include "wx/ptr_scpd.h" + + wxDECLARE_SCOPED_PTR(wxEvent, wxEventPtr) + wxDEFINE_SCOPED_PTR(wxEvent, wxEventPtr) +#endif // wxUSE_BASE + +// ---------------------------------------------------------------------------- +// wxWin macros +// ---------------------------------------------------------------------------- + +#if wxUSE_BASE + IMPLEMENT_DYNAMIC_CLASS(wxEvtHandler, wxObject) + IMPLEMENT_ABSTRACT_CLASS(wxEvent, wxObject) +#endif // wxUSE_BASE + +#if wxUSE_GUI + IMPLEMENT_DYNAMIC_CLASS(wxIdleEvent, wxEvent) + IMPLEMENT_DYNAMIC_CLASS(wxCommandEvent, wxEvent) + IMPLEMENT_DYNAMIC_CLASS(wxNotifyEvent, wxCommandEvent) + IMPLEMENT_DYNAMIC_CLASS(wxScrollEvent, wxCommandEvent) + IMPLEMENT_DYNAMIC_CLASS(wxScrollWinEvent, wxEvent) + IMPLEMENT_DYNAMIC_CLASS(wxMouseEvent, wxEvent) + IMPLEMENT_DYNAMIC_CLASS(wxKeyEvent, wxEvent) + IMPLEMENT_DYNAMIC_CLASS(wxSizeEvent, wxEvent) + IMPLEMENT_DYNAMIC_CLASS(wxPaintEvent, wxEvent) + IMPLEMENT_DYNAMIC_CLASS(wxNcPaintEvent, wxEvent) + IMPLEMENT_DYNAMIC_CLASS(wxEraseEvent, wxEvent) + IMPLEMENT_DYNAMIC_CLASS(wxMoveEvent, wxEvent) + IMPLEMENT_DYNAMIC_CLASS(wxFocusEvent, wxEvent) + IMPLEMENT_DYNAMIC_CLASS(wxChildFocusEvent, wxCommandEvent) + IMPLEMENT_DYNAMIC_CLASS(wxCloseEvent, wxEvent) + IMPLEMENT_DYNAMIC_CLASS(wxShowEvent, wxEvent) + IMPLEMENT_DYNAMIC_CLASS(wxMaximizeEvent, wxEvent) + IMPLEMENT_DYNAMIC_CLASS(wxIconizeEvent, wxEvent) + IMPLEMENT_DYNAMIC_CLASS(wxMenuEvent, wxEvent) + IMPLEMENT_DYNAMIC_CLASS(wxJoystickEvent, wxEvent) + IMPLEMENT_DYNAMIC_CLASS(wxDropFilesEvent, wxEvent) + IMPLEMENT_DYNAMIC_CLASS(wxActivateEvent, wxEvent) + IMPLEMENT_DYNAMIC_CLASS(wxInitDialogEvent, wxEvent) + IMPLEMENT_DYNAMIC_CLASS(wxSetCursorEvent, wxEvent) + IMPLEMENT_DYNAMIC_CLASS(wxSysColourChangedEvent, wxEvent) + IMPLEMENT_DYNAMIC_CLASS(wxDisplayChangedEvent, wxEvent) + IMPLEMENT_DYNAMIC_CLASS(wxUpdateUIEvent, wxCommandEvent) + IMPLEMENT_DYNAMIC_CLASS(wxNavigationKeyEvent, wxEvent) + IMPLEMENT_DYNAMIC_CLASS(wxPaletteChangedEvent, wxEvent) + IMPLEMENT_DYNAMIC_CLASS(wxQueryNewPaletteEvent, wxEvent) + IMPLEMENT_DYNAMIC_CLASS(wxWindowCreateEvent, wxEvent) + IMPLEMENT_DYNAMIC_CLASS(wxWindowDestroyEvent, wxEvent) + IMPLEMENT_DYNAMIC_CLASS(wxHelpEvent, wxCommandEvent) + IMPLEMENT_DYNAMIC_CLASS(wxContextMenuEvent, wxCommandEvent) + IMPLEMENT_DYNAMIC_CLASS(wxMouseCaptureChangedEvent, wxEvent) + IMPLEMENT_DYNAMIC_CLASS(wxMouseCaptureLostEvent, wxEvent) + IMPLEMENT_DYNAMIC_CLASS(wxClipboardTextEvent, wxCommandEvent) +#endif // wxUSE_GUI + +#if wxUSE_BASE + +const wxEventTable *wxEvtHandler::GetEventTable() const + { return &wxEvtHandler::sm_eventTable; } + +const wxEventTable wxEvtHandler::sm_eventTable = + { (const wxEventTable *)NULL, &wxEvtHandler::sm_eventTableEntries[0] }; + +wxEventHashTable &wxEvtHandler::GetEventHashTable() const + { return wxEvtHandler::sm_eventHashTable; } + +wxEventHashTable wxEvtHandler::sm_eventHashTable(wxEvtHandler::sm_eventTable); + +const wxEventTableEntry wxEvtHandler::sm_eventTableEntries[] = + { DECLARE_EVENT_TABLE_ENTRY(wxEVT_NULL, 0, 0, (wxObjectEventFunction)NULL, NULL) }; + + +#ifdef __WXDEBUG__ +// Clear up event hash table contents or we can get problems +// when C++ is cleaning up the static object +class wxEventTableEntryModule: public wxModule +{ +DECLARE_DYNAMIC_CLASS(wxEventTableEntryModule) +public: + wxEventTableEntryModule() {} + bool OnInit() + { + wxEventHashTable::ReconstructAll(); + return true; + } + void OnExit() + { + wxEventHashTable::ClearAll(); + } +}; +IMPLEMENT_DYNAMIC_CLASS(wxEventTableEntryModule, wxModule) +#endif + +// ---------------------------------------------------------------------------- +// global variables +// ---------------------------------------------------------------------------- + +// To put pending event handlers +wxList *wxPendingEvents = (wxList *)NULL; + +#if wxUSE_THREADS + // protects wxPendingEvents list + wxCriticalSection *wxPendingEventsLocker = (wxCriticalSection *)NULL; +#endif + +#if !WXWIN_COMPATIBILITY_EVENT_TYPES + +// common event types are defined here, other event types are defined by the +// components which use them + +const wxEventType wxEVT_FIRST = 10000; +const wxEventType wxEVT_USER_FIRST = wxEVT_FIRST + 2000; + +DEFINE_EVENT_TYPE(wxEVT_NULL) +DEFINE_EVENT_TYPE(wxEVT_IDLE) +DEFINE_EVENT_TYPE(wxEVT_SOCKET) + +#endif // !WXWIN_COMPATIBILITY_EVENT_TYPES + +#endif // wxUSE_BASE + +#if wxUSE_GUI + +#if !WXWIN_COMPATIBILITY_EVENT_TYPES + +DEFINE_EVENT_TYPE(wxEVT_COMMAND_BUTTON_CLICKED) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_CHECKBOX_CLICKED) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_CHOICE_SELECTED) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_LISTBOX_SELECTED) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_LISTBOX_DOUBLECLICKED) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_CHECKLISTBOX_TOGGLED) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_MENU_SELECTED) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_SLIDER_UPDATED) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_RADIOBOX_SELECTED) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_RADIOBUTTON_SELECTED) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_SCROLLBAR_UPDATED) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_VLBOX_SELECTED) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_COMBOBOX_SELECTED) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_TOOL_RCLICKED) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_TOOL_ENTER) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_SPINCTRL_UPDATED) + +// Sockets and timers send events, too +DEFINE_EVENT_TYPE(wxEVT_TIMER) + +// Mouse event types +DEFINE_EVENT_TYPE(wxEVT_LEFT_DOWN) +DEFINE_EVENT_TYPE(wxEVT_LEFT_UP) +DEFINE_EVENT_TYPE(wxEVT_MIDDLE_DOWN) +DEFINE_EVENT_TYPE(wxEVT_MIDDLE_UP) +DEFINE_EVENT_TYPE(wxEVT_RIGHT_DOWN) +DEFINE_EVENT_TYPE(wxEVT_RIGHT_UP) +DEFINE_EVENT_TYPE(wxEVT_MOTION) +DEFINE_EVENT_TYPE(wxEVT_ENTER_WINDOW) +DEFINE_EVENT_TYPE(wxEVT_LEAVE_WINDOW) +DEFINE_EVENT_TYPE(wxEVT_LEFT_DCLICK) +DEFINE_EVENT_TYPE(wxEVT_MIDDLE_DCLICK) +DEFINE_EVENT_TYPE(wxEVT_RIGHT_DCLICK) +DEFINE_EVENT_TYPE(wxEVT_SET_FOCUS) +DEFINE_EVENT_TYPE(wxEVT_KILL_FOCUS) +DEFINE_EVENT_TYPE(wxEVT_CHILD_FOCUS) +DEFINE_EVENT_TYPE(wxEVT_MOUSEWHEEL) + +// Non-client mouse events +DEFINE_EVENT_TYPE(wxEVT_NC_LEFT_DOWN) +DEFINE_EVENT_TYPE(wxEVT_NC_LEFT_UP) +DEFINE_EVENT_TYPE(wxEVT_NC_MIDDLE_DOWN) +DEFINE_EVENT_TYPE(wxEVT_NC_MIDDLE_UP) +DEFINE_EVENT_TYPE(wxEVT_NC_RIGHT_DOWN) +DEFINE_EVENT_TYPE(wxEVT_NC_RIGHT_UP) +DEFINE_EVENT_TYPE(wxEVT_NC_MOTION) +DEFINE_EVENT_TYPE(wxEVT_NC_ENTER_WINDOW) +DEFINE_EVENT_TYPE(wxEVT_NC_LEAVE_WINDOW) +DEFINE_EVENT_TYPE(wxEVT_NC_LEFT_DCLICK) +DEFINE_EVENT_TYPE(wxEVT_NC_MIDDLE_DCLICK) +DEFINE_EVENT_TYPE(wxEVT_NC_RIGHT_DCLICK) + +// Character input event type +DEFINE_EVENT_TYPE(wxEVT_CHAR) +DEFINE_EVENT_TYPE(wxEVT_CHAR_HOOK) +DEFINE_EVENT_TYPE(wxEVT_NAVIGATION_KEY) +DEFINE_EVENT_TYPE(wxEVT_KEY_DOWN) +DEFINE_EVENT_TYPE(wxEVT_KEY_UP) +#if wxUSE_HOTKEY +DEFINE_EVENT_TYPE(wxEVT_HOTKEY) +#endif + +// Set cursor event +DEFINE_EVENT_TYPE(wxEVT_SET_CURSOR) + +// wxScrollbar and wxSlider event identifiers +DEFINE_EVENT_TYPE(wxEVT_SCROLL_TOP) +DEFINE_EVENT_TYPE(wxEVT_SCROLL_BOTTOM) +DEFINE_EVENT_TYPE(wxEVT_SCROLL_LINEUP) +DEFINE_EVENT_TYPE(wxEVT_SCROLL_LINEDOWN) +DEFINE_EVENT_TYPE(wxEVT_SCROLL_PAGEUP) +DEFINE_EVENT_TYPE(wxEVT_SCROLL_PAGEDOWN) +DEFINE_EVENT_TYPE(wxEVT_SCROLL_THUMBTRACK) +DEFINE_EVENT_TYPE(wxEVT_SCROLL_THUMBRELEASE) +DEFINE_EVENT_TYPE(wxEVT_SCROLL_CHANGED) + +// Scroll events from wxWindow +DEFINE_EVENT_TYPE(wxEVT_SCROLLWIN_TOP) +DEFINE_EVENT_TYPE(wxEVT_SCROLLWIN_BOTTOM) +DEFINE_EVENT_TYPE(wxEVT_SCROLLWIN_LINEUP) +DEFINE_EVENT_TYPE(wxEVT_SCROLLWIN_LINEDOWN) +DEFINE_EVENT_TYPE(wxEVT_SCROLLWIN_PAGEUP) +DEFINE_EVENT_TYPE(wxEVT_SCROLLWIN_PAGEDOWN) +DEFINE_EVENT_TYPE(wxEVT_SCROLLWIN_THUMBTRACK) +DEFINE_EVENT_TYPE(wxEVT_SCROLLWIN_THUMBRELEASE) + +// System events +DEFINE_EVENT_TYPE(wxEVT_SIZE) +DEFINE_EVENT_TYPE(wxEVT_SIZING) +DEFINE_EVENT_TYPE(wxEVT_MOVE) +DEFINE_EVENT_TYPE(wxEVT_MOVING) +DEFINE_EVENT_TYPE(wxEVT_CLOSE_WINDOW) +DEFINE_EVENT_TYPE(wxEVT_END_SESSION) +DEFINE_EVENT_TYPE(wxEVT_QUERY_END_SESSION) +DEFINE_EVENT_TYPE(wxEVT_HIBERNATE) +DEFINE_EVENT_TYPE(wxEVT_ACTIVATE_APP) +DEFINE_EVENT_TYPE(wxEVT_POWER) +DEFINE_EVENT_TYPE(wxEVT_ACTIVATE) +DEFINE_EVENT_TYPE(wxEVT_CREATE) +DEFINE_EVENT_TYPE(wxEVT_DESTROY) +DEFINE_EVENT_TYPE(wxEVT_SHOW) +DEFINE_EVENT_TYPE(wxEVT_ICONIZE) +DEFINE_EVENT_TYPE(wxEVT_MAXIMIZE) +DEFINE_EVENT_TYPE(wxEVT_MOUSE_CAPTURE_CHANGED) +DEFINE_EVENT_TYPE(wxEVT_MOUSE_CAPTURE_LOST) +DEFINE_EVENT_TYPE(wxEVT_PAINT) +DEFINE_EVENT_TYPE(wxEVT_ERASE_BACKGROUND) +DEFINE_EVENT_TYPE(wxEVT_NC_PAINT) +DEFINE_EVENT_TYPE(wxEVT_PAINT_ICON) +DEFINE_EVENT_TYPE(wxEVT_MENU_OPEN) +DEFINE_EVENT_TYPE(wxEVT_MENU_CLOSE) +DEFINE_EVENT_TYPE(wxEVT_MENU_HIGHLIGHT) +DEFINE_EVENT_TYPE(wxEVT_CONTEXT_MENU) +DEFINE_EVENT_TYPE(wxEVT_SYS_COLOUR_CHANGED) +DEFINE_EVENT_TYPE(wxEVT_DISPLAY_CHANGED) +DEFINE_EVENT_TYPE(wxEVT_SETTING_CHANGED) +DEFINE_EVENT_TYPE(wxEVT_QUERY_NEW_PALETTE) +DEFINE_EVENT_TYPE(wxEVT_PALETTE_CHANGED) +DEFINE_EVENT_TYPE(wxEVT_JOY_BUTTON_DOWN) +DEFINE_EVENT_TYPE(wxEVT_JOY_BUTTON_UP) +DEFINE_EVENT_TYPE(wxEVT_JOY_MOVE) +DEFINE_EVENT_TYPE(wxEVT_JOY_ZMOVE) +DEFINE_EVENT_TYPE(wxEVT_DROP_FILES) +DEFINE_EVENT_TYPE(wxEVT_DRAW_ITEM) +DEFINE_EVENT_TYPE(wxEVT_MEASURE_ITEM) +DEFINE_EVENT_TYPE(wxEVT_COMPARE_ITEM) +DEFINE_EVENT_TYPE(wxEVT_INIT_DIALOG) +DEFINE_EVENT_TYPE(wxEVT_UPDATE_UI) + +// Clipboard events +DEFINE_EVENT_TYPE(wxEVT_COMMAND_TEXT_COPY) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_TEXT_CUT) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_TEXT_PASTE) + +// Generic command events +// Note: a click is a higher-level event than button down/up +DEFINE_EVENT_TYPE(wxEVT_COMMAND_LEFT_CLICK) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_LEFT_DCLICK) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_RIGHT_CLICK) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_RIGHT_DCLICK) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_SET_FOCUS) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_KILL_FOCUS) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_ENTER) + +// Help events +DEFINE_EVENT_TYPE(wxEVT_HELP) +DEFINE_EVENT_TYPE(wxEVT_DETAILED_HELP) + +#endif // !WXWIN_COMPATIBILITY_EVENT_TYPES + +#endif // wxUSE_GUI + +#if wxUSE_BASE + +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// event initialization +// ---------------------------------------------------------------------------- + +int wxNewEventType() +{ + // MT-FIXME + static int s_lastUsedEventType = wxEVT_FIRST; + + return s_lastUsedEventType++; +} + +// ---------------------------------------------------------------------------- +// wxEvent +// ---------------------------------------------------------------------------- + +/* + * General wxWidgets events, covering + * all interesting things that might happen (button clicking, resizing, + * setting text in widgets, etc.). + * + * For each completely new event type, derive a new event class. + * + */ + +wxEvent::wxEvent(int theId, wxEventType commandType ) +{ + m_eventType = commandType; + m_eventObject = (wxObject *) NULL; + m_timeStamp = 0; + m_id = theId; + m_skipped = false; + m_callbackUserData = (wxObject *) NULL; + m_isCommandEvent = false; + m_propagationLevel = wxEVENT_PROPAGATE_NONE; +} + +wxEvent::wxEvent(const wxEvent &src) + : wxObject(src) + , m_eventObject(src.m_eventObject) + , m_eventType(src.m_eventType) + , m_timeStamp(src.m_timeStamp) + , m_id(src.m_id) + , m_callbackUserData(src.m_callbackUserData) + , m_propagationLevel(src.m_propagationLevel) + , m_skipped(src.m_skipped) + , m_isCommandEvent(src.m_isCommandEvent) +{ +} + +#endif // wxUSE_BASE + +#if wxUSE_GUI + +/* + * Command events + * + */ + +#ifdef __VISUALC__ + // 'this' : used in base member initializer list (for m_commandString) + #pragma warning(disable:4355) +#endif + +wxCommandEvent::wxCommandEvent(wxEventType commandType, int theId) + : wxEvent(theId, commandType) +#if WXWIN_COMPATIBILITY_2_4 + , m_commandString(this) +#endif +{ + m_clientData = (char *) NULL; + m_clientObject = (wxClientData *) NULL; + m_extraLong = 0; + m_commandInt = 0; + m_isCommandEvent = true; + + // the command events are propagated upwards by default + m_propagationLevel = wxEVENT_PROPAGATE_MAX; +} + +#ifdef __VISUALC__ + #pragma warning(default:4355) +#endif + +wxString wxCommandEvent::GetString() const +{ + if(m_eventType != wxEVT_COMMAND_TEXT_UPDATED || !m_eventObject) + return m_cmdString; + else + { +#if wxUSE_TEXTCTRL + wxTextCtrl *txt = wxDynamicCast(m_eventObject, wxTextCtrl); + if(txt) + return txt->GetValue(); + else +#endif // wxUSE_TEXTCTRL + return m_cmdString; + } +} + +/* + * UI update events + */ + +#if wxUSE_LONGLONG +wxLongLong wxUpdateUIEvent::sm_lastUpdate = 0; +#endif + +long wxUpdateUIEvent::sm_updateInterval = 0; + +wxUpdateUIMode wxUpdateUIEvent::sm_updateMode = wxUPDATE_UI_PROCESS_ALL; + +// Can we update? +bool wxUpdateUIEvent::CanUpdate(wxWindowBase *win) +{ + // Don't update if we've switched global updating off + // and this window doesn't support updates. + if (win && + (GetMode() == wxUPDATE_UI_PROCESS_SPECIFIED && + ((win->GetExtraStyle() & wxWS_EX_PROCESS_UI_UPDATES) == 0))) + return false; + + if (sm_updateInterval == -1) + return false; + + if (sm_updateInterval == 0) + return true; + +#if wxUSE_STOPWATCH && wxUSE_LONGLONG + wxLongLong now = wxGetLocalTimeMillis(); + if (now > (sm_lastUpdate + sm_updateInterval)) + { + return true; + } + + return false; +#else + // If we don't have wxStopWatch or wxLongLong, we + // should err on the safe side and update now anyway. + return true; +#endif +} + +// Reset the update time to provide a delay until the next +// time we should update +void wxUpdateUIEvent::ResetUpdateTime() +{ +#if wxUSE_STOPWATCH && wxUSE_LONGLONG + if (sm_updateInterval > 0) + { + wxLongLong now = wxGetLocalTimeMillis(); + if (now > (sm_lastUpdate + sm_updateInterval)) + { + sm_lastUpdate = now; + } + } +#endif +} + +/* + * Idle events + */ + +wxIdleMode wxIdleEvent::sm_idleMode = wxIDLE_PROCESS_ALL; + +// Can we send an idle event? +bool wxIdleEvent::CanSend(wxWindow* win) +{ + // Don't update if we've switched global updating off + // and this window doesn't support updates. + if (win && + (GetMode() == wxIDLE_PROCESS_SPECIFIED && + ((win->GetExtraStyle() & wxWS_EX_PROCESS_IDLE) == 0))) + return false; + + return true; +} + +/* + * Scroll events + */ + +wxScrollEvent::wxScrollEvent(wxEventType commandType, + int id, + int pos, + int orient) + : wxCommandEvent(commandType, id) +{ + m_extraLong = orient; + m_commandInt = pos; +} + +/* + * ScrollWin events + */ + +wxScrollWinEvent::wxScrollWinEvent(wxEventType commandType, + int pos, + int orient) +{ + m_eventType = commandType; + m_extraLong = orient; + m_commandInt = pos; +} + +/* + * Mouse events + * + */ + +wxMouseEvent::wxMouseEvent(wxEventType commandType) +{ + m_eventType = commandType; + m_metaDown = false; + m_altDown = false; + m_controlDown = false; + m_shiftDown = false; + m_leftDown = false; + m_rightDown = false; + m_middleDown = false; + m_x = 0; + m_y = 0; + m_wheelRotation = 0; + m_wheelDelta = 0; + m_linesPerAction = 0; +} + +void wxMouseEvent::Assign(const wxMouseEvent& event) +{ + m_eventType = event.m_eventType; + + m_x = event.m_x; + m_y = event.m_y; + + m_leftDown = event.m_leftDown; + m_middleDown = event.m_middleDown; + m_rightDown = event.m_rightDown; + + m_controlDown = event.m_controlDown; + m_shiftDown = event.m_shiftDown; + m_altDown = event.m_altDown; + m_metaDown = event.m_metaDown; + + m_wheelRotation = event.m_wheelRotation; + m_wheelDelta = event.m_wheelDelta; + m_linesPerAction = event.m_linesPerAction; +} + +// return true if was a button dclick event +bool wxMouseEvent::ButtonDClick(int but) const +{ + switch (but) + { + default: + wxFAIL_MSG(wxT("invalid parameter in wxMouseEvent::ButtonDClick")); + // fall through + + case wxMOUSE_BTN_ANY: + return (LeftDClick() || MiddleDClick() || RightDClick()); + + case wxMOUSE_BTN_LEFT: + return LeftDClick(); + + case wxMOUSE_BTN_MIDDLE: + return MiddleDClick(); + + case wxMOUSE_BTN_RIGHT: + return RightDClick(); + } +} + +// return true if was a button down event +bool wxMouseEvent::ButtonDown(int but) const +{ + switch (but) + { + default: + wxFAIL_MSG(wxT("invalid parameter in wxMouseEvent::ButtonDown")); + // fall through + + case wxMOUSE_BTN_ANY: + return (LeftDown() || MiddleDown() || RightDown()); + + case wxMOUSE_BTN_LEFT: + return LeftDown(); + + case wxMOUSE_BTN_MIDDLE: + return MiddleDown(); + + case wxMOUSE_BTN_RIGHT: + return RightDown(); + } +} + +// return true if was a button up event +bool wxMouseEvent::ButtonUp(int but) const +{ + switch (but) + { + default: + wxFAIL_MSG(wxT("invalid parameter in wxMouseEvent::ButtonUp")); + // fall through + + case wxMOUSE_BTN_ANY: + return (LeftUp() || MiddleUp() || RightUp()); + + case wxMOUSE_BTN_LEFT: + return LeftUp(); + + case wxMOUSE_BTN_MIDDLE: + return MiddleUp(); + + case wxMOUSE_BTN_RIGHT: + return RightUp(); + } +} + +// return true if the given button is currently changing state +bool wxMouseEvent::Button(int but) const +{ + switch (but) + { + default: + wxFAIL_MSG(wxT("invalid parameter in wxMouseEvent::Button")); + // fall through + + case wxMOUSE_BTN_ANY: + return ButtonUp(wxMOUSE_BTN_ANY) || + ButtonDown(wxMOUSE_BTN_ANY) || + ButtonDClick(wxMOUSE_BTN_ANY); + + case wxMOUSE_BTN_LEFT: + return LeftDown() || LeftUp() || LeftDClick(); + + case wxMOUSE_BTN_MIDDLE: + return MiddleDown() || MiddleUp() || MiddleDClick(); + + case wxMOUSE_BTN_RIGHT: + return RightDown() || RightUp() || RightDClick(); + } +} + +bool wxMouseEvent::ButtonIsDown(int but) const +{ + switch (but) + { + default: + wxFAIL_MSG(wxT("invalid parameter in wxMouseEvent::ButtonIsDown")); + // fall through + + case wxMOUSE_BTN_ANY: + return LeftIsDown() || MiddleIsDown() || RightIsDown(); + + case wxMOUSE_BTN_LEFT: + return LeftIsDown(); + + case wxMOUSE_BTN_MIDDLE: + return MiddleIsDown(); + + case wxMOUSE_BTN_RIGHT: + return RightIsDown(); + } +} + +int wxMouseEvent::GetButton() const +{ + for ( int i = 1; i <= 3; i++ ) + { + if ( Button(i) ) + { + return i; + } + } + + return wxMOUSE_BTN_NONE; +} + +// Find the logical position of the event given the DC +wxPoint wxMouseEvent::GetLogicalPosition(const wxDC& dc) const +{ + wxPoint pt(dc.DeviceToLogicalX(m_x), dc.DeviceToLogicalY(m_y)); + return pt; +} + + +/* + * Keyboard event + * + */ + +wxKeyEvent::wxKeyEvent(wxEventType type) +{ + m_eventType = type; + m_shiftDown = false; + m_controlDown = false; + m_metaDown = false; + m_altDown = false; + m_keyCode = 0; + m_scanCode = 0; +#if wxUSE_UNICODE + m_uniChar = 0; +#endif +} + +wxKeyEvent::wxKeyEvent(const wxKeyEvent& evt) + : wxEvent(evt) +{ + m_x = evt.m_x; + m_y = evt.m_y; + + m_keyCode = evt.m_keyCode; + + m_controlDown = evt.m_controlDown; + m_shiftDown = evt.m_shiftDown; + m_altDown = evt.m_altDown; + m_metaDown = evt.m_metaDown; + m_scanCode = evt.m_scanCode; + m_rawCode = evt.m_rawCode; + m_rawFlags = evt.m_rawFlags; + +#if wxUSE_UNICODE + m_uniChar = evt.m_uniChar; +#endif +} + +#if WXWIN_COMPATIBILITY_2_6 +long wxKeyEvent::KeyCode() const +{ + return m_keyCode; +} +#endif // WXWIN_COMPATIBILITY_2_6 + +wxWindowCreateEvent::wxWindowCreateEvent(wxWindow *win) +{ + SetEventType(wxEVT_CREATE); + SetEventObject(win); +} + +wxWindowDestroyEvent::wxWindowDestroyEvent(wxWindow *win) +{ + SetEventType(wxEVT_DESTROY); + SetEventObject(win); +} + +wxChildFocusEvent::wxChildFocusEvent(wxWindow *win) + : wxCommandEvent(wxEVT_CHILD_FOCUS) +{ + SetEventObject(win); +} + +// ---------------------------------------------------------------------------- +// wxHelpEvent +// ---------------------------------------------------------------------------- + +/* static */ +wxHelpEvent::Origin wxHelpEvent::GuessOrigin(Origin origin) +{ + if ( origin == Origin_Unknown ) + { + // assume that the event comes from the help button if it's not from + // keyboard and that pressing F1 always results in the help event + origin = wxGetKeyState(WXK_F1) ? Origin_Keyboard : Origin_HelpButton; + } + + return origin; +} + +#endif // wxUSE_GUI + + +#if wxUSE_BASE + +// ---------------------------------------------------------------------------- +// wxEventHashTable +// ---------------------------------------------------------------------------- + +static const int EVENT_TYPE_TABLE_INIT_SIZE = 31; // Not too big not too small... + +wxEventHashTable* wxEventHashTable::sm_first = NULL; + +wxEventHashTable::wxEventHashTable(const wxEventTable &table) + : m_table(table), + m_rebuildHash(true) +{ + AllocEventTypeTable(EVENT_TYPE_TABLE_INIT_SIZE); + + m_next = sm_first; + if (m_next) + m_next->m_previous = this; + sm_first = this; +} + +wxEventHashTable::~wxEventHashTable() +{ + if (m_next) + m_next->m_previous = m_previous; + if (m_previous) + m_previous->m_next = m_next; + if (sm_first == this) + sm_first = m_next; + + Clear(); +} + +void wxEventHashTable::Clear() +{ + size_t i; + for(i = 0; i < m_size; i++) + { + EventTypeTablePointer eTTnode = m_eventTypeTable[i]; + if (eTTnode) + { + delete eTTnode; + } + } + + // Necessary in order to not invoke the + // overloaded delete operator when statics are cleaned up + if (m_eventTypeTable) + delete[] m_eventTypeTable; + + m_eventTypeTable = NULL; + m_size = 0; +} + +// Clear all tables +void wxEventHashTable::ClearAll() +{ + wxEventHashTable* table = sm_first; + while (table) + { + table->Clear(); + table = table->m_next; + } +} + +// Rebuild all tables if they were cleared by ClearAll +void wxEventHashTable::ReconstructAll() +{ + wxEventHashTable* table = sm_first; + while (table) + { + // This will only be true if the event table was cleared. + // What we do here is basically what the constructor does. + if(table->m_eventTypeTable == NULL) + { + table->AllocEventTypeTable(EVENT_TYPE_TABLE_INIT_SIZE); + table->m_rebuildHash = true; + } + table = table->m_next; + } +} + +bool wxEventHashTable::HandleEvent(wxEvent &event, wxEvtHandler *self) +{ + if (m_rebuildHash) + { + InitHashTable(); + m_rebuildHash = false; + } + + if (!m_eventTypeTable) + return false; + + // Find all entries for the given event type. + wxEventType eventType = event.GetEventType(); + const EventTypeTablePointer eTTnode = m_eventTypeTable[eventType % m_size]; + if (eTTnode && eTTnode->eventType == eventType) + { + // Now start the search for an event handler + // that can handle an event with the given ID. + const wxEventTableEntryPointerArray& + eventEntryTable = eTTnode->eventEntryTable; + + const size_t count = eventEntryTable.GetCount(); + for (size_t n = 0; n < count; n++) + { + if ( wxEvtHandler:: + ProcessEventIfMatches(*eventEntryTable[n], self, event) ) + { + return true; + } + } + } + + return false; +} + +void wxEventHashTable::InitHashTable() +{ + // Loop over the event tables and all its base tables. + const wxEventTable *table = &m_table; + while (table) + { + // Retrieve all valid event handler entries + const wxEventTableEntry *entry = table->entries; + while (entry->m_fn != 0) + { + // Add the event entry in the Hash. + AddEntry(*entry); + + entry++; + } + + table = table->baseTable; + } + + // Lets free some memory. + size_t i; + for(i = 0; i < m_size; i++) + { + EventTypeTablePointer eTTnode = m_eventTypeTable[i]; + if (eTTnode) + { + eTTnode->eventEntryTable.Shrink(); + } + } +} + +void wxEventHashTable::AddEntry(const wxEventTableEntry &entry) +{ + // This might happen 'accidentally' as the app is exiting + if (!m_eventTypeTable) + return; + + EventTypeTablePointer *peTTnode = &m_eventTypeTable[entry.m_eventType % m_size]; + EventTypeTablePointer eTTnode = *peTTnode; + + if (eTTnode) + { + if (eTTnode->eventType != entry.m_eventType) + { + // Resize the table! + GrowEventTypeTable(); + // Try again to add it. + AddEntry(entry); + return; + } + } + else + { + eTTnode = new EventTypeTable; + eTTnode->eventType = entry.m_eventType; + *peTTnode = eTTnode; + } + + // Fill all hash entries between entry.m_id and entry.m_lastId... + eTTnode->eventEntryTable.Add(&entry); +} + +void wxEventHashTable::AllocEventTypeTable(size_t size) +{ + m_eventTypeTable = new EventTypeTablePointer[size]; + memset((void *)m_eventTypeTable, 0, sizeof(EventTypeTablePointer)*size); + m_size = size; +} + +void wxEventHashTable::GrowEventTypeTable() +{ + size_t oldSize = m_size; + EventTypeTablePointer *oldEventTypeTable = m_eventTypeTable; + + // TODO: Search the most optimal grow sequence + AllocEventTypeTable(/* GetNextPrime(oldSize) */oldSize*2+1); + + for ( size_t i = 0; i < oldSize; /* */ ) + { + EventTypeTablePointer eTToldNode = oldEventTypeTable[i]; + if (eTToldNode) + { + EventTypeTablePointer *peTTnode = &m_eventTypeTable[eTToldNode->eventType % m_size]; + EventTypeTablePointer eTTnode = *peTTnode; + + // Check for collision, we don't want any. + if (eTTnode) + { + GrowEventTypeTable(); + continue; // Don't increment the counter, + // as we still need to add this element. + } + else + { + // Get the old value and put it in the new table. + *peTTnode = oldEventTypeTable[i]; + } + } + + i++; + } + + delete[] oldEventTypeTable; +} + + +// ---------------------------------------------------------------------------- +// wxEvtHandler +// ---------------------------------------------------------------------------- + +/* + * Event handler + */ + +wxEvtHandler::wxEvtHandler() +{ + m_nextHandler = (wxEvtHandler *) NULL; + m_previousHandler = (wxEvtHandler *) NULL; + m_enabled = true; + m_dynamicEvents = (wxList *) NULL; + m_pendingEvents = (wxList *) NULL; +#if wxUSE_THREADS +# if !defined(__VISAGECPP__) + m_eventsLocker = new wxCriticalSection; +# endif +#endif + + // no client data (yet) + m_clientData = NULL; + m_clientDataType = wxClientData_None; +} + +wxEvtHandler::~wxEvtHandler() +{ + // Takes itself out of the list of handlers + if (m_previousHandler) + m_previousHandler->m_nextHandler = m_nextHandler; + + if (m_nextHandler) + m_nextHandler->m_previousHandler = m_previousHandler; + + if (m_dynamicEvents) + { + for ( wxList::iterator it = m_dynamicEvents->begin(), + end = m_dynamicEvents->end(); + it != end; + ++it ) + { +#if WXWIN_COMPATIBILITY_EVENT_TYPES + wxEventTableEntry *entry = (wxEventTableEntry*)*it; +#else // !WXWIN_COMPATIBILITY_EVENT_TYPES + wxDynamicEventTableEntry *entry = (wxDynamicEventTableEntry*)*it; +#endif // WXWIN_COMPATIBILITY_EVENT_TYPES/!WXWIN_COMPATIBILITY_EVENT_TYPES + + if (entry->m_callbackUserData) + delete entry->m_callbackUserData; + delete entry; + } + delete m_dynamicEvents; + }; + + if (m_pendingEvents) + m_pendingEvents->DeleteContents(true); + delete m_pendingEvents; + +#if wxUSE_THREADS +# if !defined(__VISAGECPP__) + delete m_eventsLocker; +# endif + + // Remove us from wxPendingEvents if necessary. + if(wxPendingEventsLocker) + wxENTER_CRIT_SECT(*wxPendingEventsLocker); + if ( wxPendingEvents ) + { + // Delete all occurences of this from the list of pending events + while (wxPendingEvents->DeleteObject(this)) { } // Do nothing + } + if(wxPendingEventsLocker) + wxLEAVE_CRIT_SECT(*wxPendingEventsLocker); +#endif + + // we only delete object data, not untyped + if ( m_clientDataType == wxClientData_Object ) + delete m_clientObject; +} + +#if wxUSE_THREADS + +bool wxEvtHandler::ProcessThreadEvent(wxEvent& event) +{ + // check that we are really in a child thread + wxASSERT_MSG( !wxThread::IsMain(), + wxT("use ProcessEvent() in main thread") ); + + AddPendingEvent(event); + + return true; +} + +void wxEvtHandler::ClearEventLocker() +{ +#if !defined(__VISAGECPP__) + delete m_eventsLocker; + m_eventsLocker = NULL; +#endif +} + +#endif // wxUSE_THREADS + +void wxEvtHandler::AddPendingEvent(wxEvent& event) +{ + // 1) Add event to list of pending events of this event handler + + wxEvent *eventCopy = event.Clone(); + + // we must be able to copy the events here so the event class must + // implement Clone() properly instead of just providing a NULL stab for it + wxCHECK_RET( eventCopy, + _T("events of this type aren't supposed to be posted") ); + + wxENTER_CRIT_SECT( Lock() ); + + if ( !m_pendingEvents ) + m_pendingEvents = new wxList; + + m_pendingEvents->Append(eventCopy); + + wxLEAVE_CRIT_SECT( Lock() ); + + // 2) Add this event handler to list of event handlers that + // have pending events. + + wxENTER_CRIT_SECT(*wxPendingEventsLocker); + + if ( !wxPendingEvents ) + wxPendingEvents = new wxList; + wxPendingEvents->Append(this); + + wxLEAVE_CRIT_SECT(*wxPendingEventsLocker); + + // 3) Inform the system that new pending events are somewhere, + // and that these should be processed in idle time. + wxWakeUpIdle(); +} + +void wxEvtHandler::ProcessPendingEvents() +{ + // this method is only called by wxApp if this handler does have + // pending events + wxCHECK_RET( m_pendingEvents, + wxT("Please call wxApp::ProcessPendingEvents() instead") ); + + wxENTER_CRIT_SECT( Lock() ); + + // we leave the loop once we have processed all events that were present at + // the start of ProcessPendingEvents because otherwise we could get into + // infinite loop if the pending event handler execution resulted in another + // event being posted + size_t n = m_pendingEvents->size(); + for ( wxList::compatibility_iterator node = m_pendingEvents->GetFirst(); + node; + node = m_pendingEvents->GetFirst() ) + { + wxEventPtr event(wx_static_cast(wxEvent *, node->GetData())); + + // It's important we remove event from list before processing it. + // Else a nested event loop, for example from a modal dialog, might + // process the same event again. + + m_pendingEvents->Erase(node); + + wxLEAVE_CRIT_SECT( Lock() ); + + ProcessEvent(*event); + + wxENTER_CRIT_SECT( Lock() ); + + if ( --n == 0 ) + break; + } + + wxLEAVE_CRIT_SECT( Lock() ); +} + +/* + * Event table stuff + */ +/* static */ bool +wxEvtHandler::ProcessEventIfMatches(const wxEventTableEntryBase& entry, + wxEvtHandler *handler, + wxEvent& event) +{ + int tableId1 = entry.m_id, + tableId2 = entry.m_lastId; + + // match only if the event type is the same and the id is either -1 in + // the event table (meaning "any") or the event id matches the id + // specified in the event table either exactly or by falling into + // range between first and last + if ((tableId1 == wxID_ANY) || + (tableId2 == wxID_ANY && tableId1 == event.GetId()) || + (tableId2 != wxID_ANY && + (event.GetId() >= tableId1 && event.GetId() <= tableId2))) + { + event.Skip(false); + event.m_callbackUserData = entry.m_callbackUserData; + +#if wxUSE_EXCEPTIONS + if ( wxTheApp ) + { + // call the handler via wxApp method which allows the user to catch + // any exceptions which may be thrown by any handler in the program + // in one place + wxTheApp->HandleEvent(handler, (wxEventFunction)entry.m_fn, event); + } + else +#endif // wxUSE_EXCEPTIONS + { + // no need for an extra virtual function call + (handler->*((wxEventFunction) (entry.m_fn)))(event); + } + + if (!event.GetSkipped()) + return true; + } + + return false; +} + +bool wxEvtHandler::TryParent(wxEvent& event) +{ + if ( wxTheApp && (this != wxTheApp) ) + { + // Special case: don't pass wxEVT_IDLE to wxApp, since it'll always + // swallow it. wxEVT_IDLE is sent explicitly to wxApp so it will be + // processed appropriately via SearchEventTable. + if ( event.GetEventType() != wxEVT_IDLE ) + { + if ( wxTheApp->ProcessEvent(event) ) + return true; + } + } + + return false; +} + +bool wxEvtHandler::ProcessEvent(wxEvent& event) +{ + // allow the application to hook into event processing + if ( wxTheApp ) + { + int rc = wxTheApp->FilterEvent(event); + if ( rc != -1 ) + { + wxASSERT_MSG( rc == 1 || rc == 0, + _T("unexpected wxApp::FilterEvent return value") ); + + return rc != 0; + } + //else: proceed normally + } + + // An event handler can be enabled or disabled + if ( GetEvtHandlerEnabled() ) + { + // if we have a validator, it has higher priority than our own event + // table + if ( TryValidator(event) ) + return true; + + // Handle per-instance dynamic event tables first + if ( m_dynamicEvents && SearchDynamicEventTable(event) ) + return true; + + // Then static per-class event tables + if ( GetEventHashTable().HandleEvent(event, this) ) + return true; + } + + // Try going down the event handler chain + if ( GetNextHandler() ) + { + if ( GetNextHandler()->ProcessEvent(event) ) + return true; + } + + // Finally propagate the event upwards the window chain and/or to the + // application object as necessary + return TryParent(event); +} + + +bool wxEvtHandler::SearchEventTable(wxEventTable& table, wxEvent& event) +{ + const wxEventType eventType = event.GetEventType(); + for ( int i = 0; table.entries[i].m_fn != 0; i++ ) + { + const wxEventTableEntry& entry = table.entries[i]; + if ( eventType == entry.m_eventType ) + { + if ( ProcessEventIfMatches(entry, this, event) ) + return true; + } + } + + return false; +} + +void wxEvtHandler::Connect( int id, int lastId, + int eventType, + wxObjectEventFunction func, + wxObject *userData, + wxEvtHandler* eventSink ) +{ +#if WXWIN_COMPATIBILITY_EVENT_TYPES + wxEventTableEntry *entry = new wxEventTableEntry; + entry->m_eventType = eventType; + entry->m_id = id; + entry->m_lastId = lastId; + entry->m_fn = func; + entry->m_callbackUserData = userData; +#else // !WXWIN_COMPATIBILITY_EVENT_TYPES + wxDynamicEventTableEntry *entry = + new wxDynamicEventTableEntry(eventType, id, lastId, func, userData, eventSink); +#endif // WXWIN_COMPATIBILITY_EVENT_TYPES/!WXWIN_COMPATIBILITY_EVENT_TYPES + + if (!m_dynamicEvents) + m_dynamicEvents = new wxList; + + // Insert at the front of the list so most recent additions are found first + m_dynamicEvents->Insert( (wxObject*) entry ); +} + +bool wxEvtHandler::Disconnect( int id, int lastId, wxEventType eventType, + wxObjectEventFunction func, + wxObject *userData, + wxEvtHandler* eventSink ) +{ + if (!m_dynamicEvents) + return false; + + wxList::compatibility_iterator node = m_dynamicEvents->GetFirst(); + while (node) + { +#if WXWIN_COMPATIBILITY_EVENT_TYPES + wxEventTableEntry *entry = (wxEventTableEntry*)node->GetData(); +#else // !WXWIN_COMPATIBILITY_EVENT_TYPES + wxDynamicEventTableEntry *entry = (wxDynamicEventTableEntry*)node->GetData(); +#endif // WXWIN_COMPATIBILITY_EVENT_TYPES/!WXWIN_COMPATIBILITY_EVENT_TYPES + + if ((entry->m_id == id) && + ((entry->m_lastId == lastId) || (lastId == wxID_ANY)) && + ((entry->m_eventType == eventType) || (eventType == wxEVT_NULL)) && + ((entry->m_fn == func) || (func == (wxObjectEventFunction)NULL)) && + ((entry->m_eventSink == eventSink) || (eventSink == (wxEvtHandler*)NULL)) && + ((entry->m_callbackUserData == userData) || (userData == (wxObject*)NULL))) + { + if (entry->m_callbackUserData) + delete entry->m_callbackUserData; + m_dynamicEvents->Erase( node ); + delete entry; + return true; + } + node = node->GetNext(); + } + return false; +} + +bool wxEvtHandler::SearchDynamicEventTable( wxEvent& event ) +{ + wxCHECK_MSG( m_dynamicEvents, false, + wxT("caller should check that we have dynamic events") ); + + wxList::compatibility_iterator node = m_dynamicEvents->GetFirst(); + while (node) + { +#if WXWIN_COMPATIBILITY_EVENT_TYPES + wxEventTableEntry *entry = (wxEventTableEntry*)node->GetData(); +#else // !WXWIN_COMPATIBILITY_EVENT_TYPES + wxDynamicEventTableEntry *entry = (wxDynamicEventTableEntry*)node->GetData(); +#endif // WXWIN_COMPATIBILITY_EVENT_TYPES/!WXWIN_COMPATIBILITY_EVENT_TYPES + + // get next node before (maybe) calling the event handler as it could + // call Disconnect() invalidating the current node + node = node->GetNext(); + + if ((event.GetEventType() == entry->m_eventType) && (entry->m_fn != 0)) + { + wxEvtHandler *handler = +#if !WXWIN_COMPATIBILITY_EVENT_TYPES + entry->m_eventSink ? entry->m_eventSink + : +#endif + this; + + if ( ProcessEventIfMatches(*entry, handler, event) ) + { + return true; + } + } + } + + return false; +} + +void wxEvtHandler::DoSetClientObject( wxClientData *data ) +{ + wxASSERT_MSG( m_clientDataType != wxClientData_Void, + wxT("can't have both object and void client data") ); + + if ( m_clientObject ) + delete m_clientObject; + + m_clientObject = data; + m_clientDataType = wxClientData_Object; +} + +wxClientData *wxEvtHandler::DoGetClientObject() const +{ + // it's not an error to call GetClientObject() on a window which doesn't + // have client data at all - NULL will be returned + wxASSERT_MSG( m_clientDataType != wxClientData_Void, + wxT("this window doesn't have object client data") ); + + return m_clientObject; +} + +void wxEvtHandler::DoSetClientData( void *data ) +{ + wxASSERT_MSG( m_clientDataType != wxClientData_Object, + wxT("can't have both object and void client data") ); + + m_clientData = data; + m_clientDataType = wxClientData_Void; +} + +void *wxEvtHandler::DoGetClientData() const +{ + // it's not an error to call GetClientData() on a window which doesn't have + // client data at all - NULL will be returned + wxASSERT_MSG( m_clientDataType != wxClientData_Object, + wxT("this window doesn't have void client data") ); + + return m_clientData; +} + +#endif // wxUSE_BASE + +#if wxUSE_GUI + +// Find a window with the focus, that is also a descendant of the given window. +// This is used to determine the window to initially send commands to. +wxWindow* wxFindFocusDescendant(wxWindow* ancestor) +{ + // Process events starting with the window with the focus, if any. + wxWindow* focusWin = wxWindow::FindFocus(); + wxWindow* win = focusWin; + + // Check if this is a descendant of this frame. + // If not, win will be set to NULL. + while (win) + { + if (win == ancestor) + break; + else + win = win->GetParent(); + } + if (win == (wxWindow*) NULL) + focusWin = (wxWindow*) NULL; + + return focusWin; +} + +#endif // wxUSE_GUI diff --git a/Externals/wxWidgets/src/common/evtloopcmn.cpp b/Externals/wxWidgets/src/common/evtloopcmn.cpp index 75f88ca12f..00bc1001bb 100644 --- a/Externals/wxWidgets/src/common/evtloopcmn.cpp +++ b/Externals/wxWidgets/src/common/evtloopcmn.cpp @@ -1,172 +1,172 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: src/common/evtloopcmn.cpp -// Purpose: common wxEventLoop-related stuff -// Author: Vadim Zeitlin -// Modified by: -// Created: 2006-01-12 -// RCS-ID: $Id: evtloopcmn.cpp 45938 2007-05-10 02:07:41Z VZ $ -// Copyright: (c) 2006 Vadim Zeitlin -// Licence: wxWindows licence -/////////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// for compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#include "wx/evtloop.h" - -#ifndef WX_PRECOMP - #include "wx/app.h" -#endif //WX_PRECOMP - -// see the comment near the declaration of wxRunningEventLoopCount in -// src/msw/thread.cpp for the explanation of this hack -#if defined(__WXMSW__) && wxUSE_THREADS - -extern WXDLLIMPEXP_DATA_BASE(int) wxRunningEventLoopCount; -struct wxRunningEventLoopCounter -{ - wxRunningEventLoopCounter() { wxRunningEventLoopCount++; } - ~wxRunningEventLoopCounter() { wxRunningEventLoopCount--; } -}; - -#endif // __WXMSW__ - -// ---------------------------------------------------------------------------- -// globals -// ---------------------------------------------------------------------------- - -wxEventLoop *wxEventLoopBase::ms_activeLoop = NULL; - -// wxEventLoopManual is unused in the other ports -#if defined(__WXMSW__) || defined(__WXMAC__) || defined(__WXDFB__) - -// ============================================================================ -// wxEventLoopManual implementation -// ============================================================================ - -wxEventLoopManual::wxEventLoopManual() -{ - m_exitcode = 0; - m_shouldExit = false; -} - -int wxEventLoopManual::Run() -{ - // event loops are not recursive, you need to create another loop! - wxCHECK_MSG( !IsRunning(), -1, _T("can't reenter a message loop") ); - - // ProcessIdle() and Dispatch() below may throw so the code here should - // be exception-safe, hence we must use local objects for all actions we - // should undo - wxEventLoopActivator activate(wx_static_cast(wxEventLoop *, this)); - -#if defined(__WXMSW__) && wxUSE_THREADS - wxRunningEventLoopCounter evtLoopCounter; -#endif // __WXMSW__ - - // we must ensure that OnExit() is called even if an exception is thrown - // from inside Dispatch() but we must call it from Exit() in normal - // situations because it is supposed to be called synchronously, - // wxModalEventLoop depends on this (so we can't just use ON_BLOCK_EXIT or - // something similar here) -#if wxUSE_EXCEPTIONS - for ( ;; ) - { - try - { -#endif // wxUSE_EXCEPTIONS - - // this is the event loop itself - for ( ;; ) - { - // give them the possibility to do whatever they want - OnNextIteration(); - - // generate and process idle events for as long as we don't - // have anything else to do - while ( !Pending() && (wxTheApp && wxTheApp->ProcessIdle()) ) - ; - - // if the "should exit" flag is set, the loop should terminate - // but not before processing any remaining messages so while - // Pending() returns true, do process them - if ( m_shouldExit ) - { - while ( Pending() ) - Dispatch(); - - break; - } - - // a message came or no more idle processing to do, sit in - // Dispatch() waiting for the next message - if ( !Dispatch() ) - { - // we got WM_QUIT - break; - } - } - -#if wxUSE_EXCEPTIONS - // exit the outer loop as well - break; - } - catch ( ... ) - { - try - { - if ( !wxTheApp || !wxTheApp->OnExceptionInMainLoop() ) - { - OnExit(); - break; - } - //else: continue running the event loop - } - catch ( ... ) - { - // OnException() throwed, possibly rethrowing the same - // exception again: very good, but we still need OnExit() to - // be called - OnExit(); - throw; - } - } - } -#endif // wxUSE_EXCEPTIONS - - return m_exitcode; -} - -void wxEventLoopManual::Exit(int rc) -{ - wxCHECK_RET( IsRunning(), _T("can't call Exit() if not running") ); - - m_exitcode = rc; - m_shouldExit = true; - - OnExit(); - - // all we have to do to exit from the loop is to (maybe) wake it up so that - // it can notice that Exit() had been called - // - // in particular, do *not* use here calls such as PostQuitMessage() (under - // MSW) which terminate the current event loop here because we're not sure - // that it is going to be processed by the correct event loop: it would be - // possible that another one is started and terminated by mistake if we do - // this - WakeUp(); -} - -#endif // __WXMSW__ || __WXMAC__ || __WXDFB__ +/////////////////////////////////////////////////////////////////////////////// +// Name: src/common/evtloopcmn.cpp +// Purpose: common wxEventLoop-related stuff +// Author: Vadim Zeitlin +// Modified by: +// Created: 2006-01-12 +// RCS-ID: $Id: evtloopcmn.cpp 45938 2007-05-10 02:07:41Z VZ $ +// Copyright: (c) 2006 Vadim Zeitlin +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// for compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#include "wx/evtloop.h" + +#ifndef WX_PRECOMP + #include "wx/app.h" +#endif //WX_PRECOMP + +// see the comment near the declaration of wxRunningEventLoopCount in +// src/msw/thread.cpp for the explanation of this hack +#if defined(__WXMSW__) && wxUSE_THREADS + +extern WXDLLIMPEXP_DATA_BASE(int) wxRunningEventLoopCount; +struct wxRunningEventLoopCounter +{ + wxRunningEventLoopCounter() { wxRunningEventLoopCount++; } + ~wxRunningEventLoopCounter() { wxRunningEventLoopCount--; } +}; + +#endif // __WXMSW__ + +// ---------------------------------------------------------------------------- +// globals +// ---------------------------------------------------------------------------- + +wxEventLoop *wxEventLoopBase::ms_activeLoop = NULL; + +// wxEventLoopManual is unused in the other ports +#if defined(__WXMSW__) || defined(__WXMAC__) || defined(__WXDFB__) + +// ============================================================================ +// wxEventLoopManual implementation +// ============================================================================ + +wxEventLoopManual::wxEventLoopManual() +{ + m_exitcode = 0; + m_shouldExit = false; +} + +int wxEventLoopManual::Run() +{ + // event loops are not recursive, you need to create another loop! + wxCHECK_MSG( !IsRunning(), -1, _T("can't reenter a message loop") ); + + // ProcessIdle() and Dispatch() below may throw so the code here should + // be exception-safe, hence we must use local objects for all actions we + // should undo + wxEventLoopActivator activate(wx_static_cast(wxEventLoop *, this)); + +#if defined(__WXMSW__) && wxUSE_THREADS + wxRunningEventLoopCounter evtLoopCounter; +#endif // __WXMSW__ + + // we must ensure that OnExit() is called even if an exception is thrown + // from inside Dispatch() but we must call it from Exit() in normal + // situations because it is supposed to be called synchronously, + // wxModalEventLoop depends on this (so we can't just use ON_BLOCK_EXIT or + // something similar here) +#if wxUSE_EXCEPTIONS + for ( ;; ) + { + try + { +#endif // wxUSE_EXCEPTIONS + + // this is the event loop itself + for ( ;; ) + { + // give them the possibility to do whatever they want + OnNextIteration(); + + // generate and process idle events for as long as we don't + // have anything else to do + while ( !Pending() && (wxTheApp && wxTheApp->ProcessIdle()) ) + ; + + // if the "should exit" flag is set, the loop should terminate + // but not before processing any remaining messages so while + // Pending() returns true, do process them + if ( m_shouldExit ) + { + while ( Pending() ) + Dispatch(); + + break; + } + + // a message came or no more idle processing to do, sit in + // Dispatch() waiting for the next message + if ( !Dispatch() ) + { + // we got WM_QUIT + break; + } + } + +#if wxUSE_EXCEPTIONS + // exit the outer loop as well + break; + } + catch ( ... ) + { + try + { + if ( !wxTheApp || !wxTheApp->OnExceptionInMainLoop() ) + { + OnExit(); + break; + } + //else: continue running the event loop + } + catch ( ... ) + { + // OnException() throwed, possibly rethrowing the same + // exception again: very good, but we still need OnExit() to + // be called + OnExit(); + throw; + } + } + } +#endif // wxUSE_EXCEPTIONS + + return m_exitcode; +} + +void wxEventLoopManual::Exit(int rc) +{ + wxCHECK_RET( IsRunning(), _T("can't call Exit() if not running") ); + + m_exitcode = rc; + m_shouldExit = true; + + OnExit(); + + // all we have to do to exit from the loop is to (maybe) wake it up so that + // it can notice that Exit() had been called + // + // in particular, do *not* use here calls such as PostQuitMessage() (under + // MSW) which terminate the current event loop here because we're not sure + // that it is going to be processed by the correct event loop: it would be + // possible that another one is started and terminated by mistake if we do + // this + WakeUp(); +} + +#endif // __WXMSW__ || __WXMAC__ || __WXDFB__ diff --git a/Externals/wxWidgets/src/common/execcmn.cpp b/Externals/wxWidgets/src/common/execcmn.cpp index 60af65d0e8..2b2025270f 100644 --- a/Externals/wxWidgets/src/common/execcmn.cpp +++ b/Externals/wxWidgets/src/common/execcmn.cpp @@ -1,122 +1,122 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: common/wxexec.cpp -// Purpose: defines wxStreamTempInputBuffer which is used by Unix and MSW -// implementations of wxExecute; this file is only used by the -// library and never by the user code -// Author: Vadim Zeitlin -// Modified by: -// Created: 20.08.02 -// RCS-ID: $Id: execcmn.cpp 35289 2005-08-23 23:12:48Z VZ $ -// Copyright: (c) 2002 Vadim Zeitlin -// Licence: wxWindows licence -/////////////////////////////////////////////////////////////////////////////// - -#ifndef _WX_WXEXEC_CPP_ -#define _WX_WXEXEC_CPP_ - -// this file should never be compiled directly, just included by other code -#ifndef _WX_USED_BY_WXEXECUTE_ - #error "You should never directly build this file!" -#endif - -// ---------------------------------------------------------------------------- -// wxStreamTempInputBuffer -// ---------------------------------------------------------------------------- - -/* - wxStreamTempInputBuffer is a hack which we need to solve the problem of - executing a child process synchronously with IO redirecting: when we do - this, the child writes to a pipe we open to it but when the pipe buffer - (which has finite capacity, e.g. commonly just 4Kb) becomes full we have to - read data from it because the child blocks in its write() until then and if - it blocks we are never going to return from wxExecute() so we dead lock. - - So here is the fix: we now read the output as soon as it appears into a temp - buffer (wxStreamTempInputBuffer object) and later just stuff it back into - the stream when the process terminates. See supporting code in wxExecute() - itself as well. - - Note that this is horribly inefficient for large amounts of output (count - the number of times we copy the data around) and so a better API is badly - needed! However it's not easy to devise a way to do this keeping backwards - compatibility with the existing wxExecute(wxEXEC_SYNC)... -*/ - -class wxStreamTempInputBuffer -{ -public: - wxStreamTempInputBuffer(); - - // call to associate a stream with this buffer, otherwise nothing happens - // at all - void Init(wxPipeInputStream *stream); - - // check for input on our stream and cache it in our buffer if any - void Update(); - - ~wxStreamTempInputBuffer(); - -private: - // the stream we're buffering, if NULL we don't do anything at all - wxPipeInputStream *m_stream; - - // the buffer of size m_size (NULL if m_size == 0) - void *m_buffer; - - // the size of the buffer - size_t m_size; - - DECLARE_NO_COPY_CLASS(wxStreamTempInputBuffer) -}; - -inline wxStreamTempInputBuffer::wxStreamTempInputBuffer() -{ - m_stream = NULL; - m_buffer = NULL; - m_size = 0; -} - -inline void wxStreamTempInputBuffer::Init(wxPipeInputStream *stream) -{ - m_stream = stream; -} - -inline -void wxStreamTempInputBuffer::Update() -{ - if ( m_stream && m_stream->CanRead() ) - { - // realloc in blocks of 4Kb: this is the default (and minimal) buffer - // size of the Unix pipes so it should be the optimal step - // - // NB: don't use "static int" in this inline function, some compilers - // (e.g. IBM xlC) don't like it - enum { incSize = 4096 }; - - void *buf = realloc(m_buffer, m_size + incSize); - if ( !buf ) - { - // don't read any more, we don't have enough memory to do it - m_stream = NULL; - } - else // got memory for the buffer - { - m_buffer = buf; - m_stream->Read((char *)m_buffer + m_size, incSize); - m_size += m_stream->LastRead(); - } - } -} - -inline -wxStreamTempInputBuffer::~wxStreamTempInputBuffer() -{ - if ( m_buffer ) - { - m_stream->Ungetch(m_buffer, m_size); - free(m_buffer); - } -} - -#endif // _WX_WXEXEC_CPP_ - +/////////////////////////////////////////////////////////////////////////////// +// Name: common/wxexec.cpp +// Purpose: defines wxStreamTempInputBuffer which is used by Unix and MSW +// implementations of wxExecute; this file is only used by the +// library and never by the user code +// Author: Vadim Zeitlin +// Modified by: +// Created: 20.08.02 +// RCS-ID: $Id: execcmn.cpp 35289 2005-08-23 23:12:48Z VZ $ +// Copyright: (c) 2002 Vadim Zeitlin +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +#ifndef _WX_WXEXEC_CPP_ +#define _WX_WXEXEC_CPP_ + +// this file should never be compiled directly, just included by other code +#ifndef _WX_USED_BY_WXEXECUTE_ + #error "You should never directly build this file!" +#endif + +// ---------------------------------------------------------------------------- +// wxStreamTempInputBuffer +// ---------------------------------------------------------------------------- + +/* + wxStreamTempInputBuffer is a hack which we need to solve the problem of + executing a child process synchronously with IO redirecting: when we do + this, the child writes to a pipe we open to it but when the pipe buffer + (which has finite capacity, e.g. commonly just 4Kb) becomes full we have to + read data from it because the child blocks in its write() until then and if + it blocks we are never going to return from wxExecute() so we dead lock. + + So here is the fix: we now read the output as soon as it appears into a temp + buffer (wxStreamTempInputBuffer object) and later just stuff it back into + the stream when the process terminates. See supporting code in wxExecute() + itself as well. + + Note that this is horribly inefficient for large amounts of output (count + the number of times we copy the data around) and so a better API is badly + needed! However it's not easy to devise a way to do this keeping backwards + compatibility with the existing wxExecute(wxEXEC_SYNC)... +*/ + +class wxStreamTempInputBuffer +{ +public: + wxStreamTempInputBuffer(); + + // call to associate a stream with this buffer, otherwise nothing happens + // at all + void Init(wxPipeInputStream *stream); + + // check for input on our stream and cache it in our buffer if any + void Update(); + + ~wxStreamTempInputBuffer(); + +private: + // the stream we're buffering, if NULL we don't do anything at all + wxPipeInputStream *m_stream; + + // the buffer of size m_size (NULL if m_size == 0) + void *m_buffer; + + // the size of the buffer + size_t m_size; + + DECLARE_NO_COPY_CLASS(wxStreamTempInputBuffer) +}; + +inline wxStreamTempInputBuffer::wxStreamTempInputBuffer() +{ + m_stream = NULL; + m_buffer = NULL; + m_size = 0; +} + +inline void wxStreamTempInputBuffer::Init(wxPipeInputStream *stream) +{ + m_stream = stream; +} + +inline +void wxStreamTempInputBuffer::Update() +{ + if ( m_stream && m_stream->CanRead() ) + { + // realloc in blocks of 4Kb: this is the default (and minimal) buffer + // size of the Unix pipes so it should be the optimal step + // + // NB: don't use "static int" in this inline function, some compilers + // (e.g. IBM xlC) don't like it + enum { incSize = 4096 }; + + void *buf = realloc(m_buffer, m_size + incSize); + if ( !buf ) + { + // don't read any more, we don't have enough memory to do it + m_stream = NULL; + } + else // got memory for the buffer + { + m_buffer = buf; + m_stream->Read((char *)m_buffer + m_size, incSize); + m_size += m_stream->LastRead(); + } + } +} + +inline +wxStreamTempInputBuffer::~wxStreamTempInputBuffer() +{ + if ( m_buffer ) + { + m_stream->Ungetch(m_buffer, m_size); + free(m_buffer); + } +} + +#endif // _WX_WXEXEC_CPP_ + diff --git a/Externals/wxWidgets/src/common/fddlgcmn.cpp b/Externals/wxWidgets/src/common/fddlgcmn.cpp index 11585c03cb..64d9f91ccd 100644 --- a/Externals/wxWidgets/src/common/fddlgcmn.cpp +++ b/Externals/wxWidgets/src/common/fddlgcmn.cpp @@ -1,102 +1,102 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/fdrepdlg.cpp -// Purpose: common parts of wxFindReplaceDialog implementations -// Author: Vadim Zeitlin -// Modified by: -// Created: 01.08.01 -// RCS-ID: -// Copyright: (c) 2001 Vadim Zeitlin -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_FINDREPLDLG - -#ifndef WX_PRECOMP -#endif - -#include "wx/fdrepdlg.h" - -// ---------------------------------------------------------------------------- -// wxWin macros -// ---------------------------------------------------------------------------- - -IMPLEMENT_DYNAMIC_CLASS(wxFindDialogEvent, wxCommandEvent) - -DEFINE_EVENT_TYPE(wxEVT_COMMAND_FIND) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_FIND_NEXT) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_FIND_REPLACE) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_FIND_REPLACE_ALL) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_FIND_CLOSE) - -// ============================================================================ -// implementations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// wxFindReplaceData -// ---------------------------------------------------------------------------- - -void wxFindReplaceData::Init() -{ - m_Flags = 0; -} - -// ---------------------------------------------------------------------------- -// wxFindReplaceDialogBase -// ---------------------------------------------------------------------------- - -wxFindReplaceDialogBase::~wxFindReplaceDialogBase() -{ -} - -void wxFindReplaceDialogBase::Send(wxFindDialogEvent& event) -{ - // we copy the data to dialog->GetData() as well - - m_FindReplaceData->m_Flags = event.GetFlags(); - m_FindReplaceData->m_FindWhat = event.GetFindString(); - if ( HasFlag(wxFR_REPLACEDIALOG) && - (event.GetEventType() == wxEVT_COMMAND_FIND_REPLACE || - event.GetEventType() == wxEVT_COMMAND_FIND_REPLACE_ALL) ) - { - m_FindReplaceData->m_ReplaceWith = event.GetReplaceString(); - } - - // translate wxEVT_COMMAND_FIND_NEXT to wxEVT_COMMAND_FIND if needed - if ( event.GetEventType() == wxEVT_COMMAND_FIND_NEXT ) - { - if ( m_FindReplaceData->m_FindWhat != m_lastSearch ) - { - event.SetEventType(wxEVT_COMMAND_FIND); - - m_lastSearch = m_FindReplaceData->m_FindWhat; - } - } - - if ( !GetEventHandler()->ProcessEvent(event) ) - { - // the event is not propagated upwards to the parent automatically - // because the dialog is a top level window, so do it manually as - // in 9 cases of 10 the message must be processed by the dialog - // owner and not the dialog itself - (void)GetParent()->GetEventHandler()->ProcessEvent(event); - } -} - -#endif // wxUSE_FINDREPLDLG - +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/fdrepdlg.cpp +// Purpose: common parts of wxFindReplaceDialog implementations +// Author: Vadim Zeitlin +// Modified by: +// Created: 01.08.01 +// RCS-ID: +// Copyright: (c) 2001 Vadim Zeitlin +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_FINDREPLDLG + +#ifndef WX_PRECOMP +#endif + +#include "wx/fdrepdlg.h" + +// ---------------------------------------------------------------------------- +// wxWin macros +// ---------------------------------------------------------------------------- + +IMPLEMENT_DYNAMIC_CLASS(wxFindDialogEvent, wxCommandEvent) + +DEFINE_EVENT_TYPE(wxEVT_COMMAND_FIND) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_FIND_NEXT) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_FIND_REPLACE) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_FIND_REPLACE_ALL) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_FIND_CLOSE) + +// ============================================================================ +// implementations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// wxFindReplaceData +// ---------------------------------------------------------------------------- + +void wxFindReplaceData::Init() +{ + m_Flags = 0; +} + +// ---------------------------------------------------------------------------- +// wxFindReplaceDialogBase +// ---------------------------------------------------------------------------- + +wxFindReplaceDialogBase::~wxFindReplaceDialogBase() +{ +} + +void wxFindReplaceDialogBase::Send(wxFindDialogEvent& event) +{ + // we copy the data to dialog->GetData() as well + + m_FindReplaceData->m_Flags = event.GetFlags(); + m_FindReplaceData->m_FindWhat = event.GetFindString(); + if ( HasFlag(wxFR_REPLACEDIALOG) && + (event.GetEventType() == wxEVT_COMMAND_FIND_REPLACE || + event.GetEventType() == wxEVT_COMMAND_FIND_REPLACE_ALL) ) + { + m_FindReplaceData->m_ReplaceWith = event.GetReplaceString(); + } + + // translate wxEVT_COMMAND_FIND_NEXT to wxEVT_COMMAND_FIND if needed + if ( event.GetEventType() == wxEVT_COMMAND_FIND_NEXT ) + { + if ( m_FindReplaceData->m_FindWhat != m_lastSearch ) + { + event.SetEventType(wxEVT_COMMAND_FIND); + + m_lastSearch = m_FindReplaceData->m_FindWhat; + } + } + + if ( !GetEventHandler()->ProcessEvent(event) ) + { + // the event is not propagated upwards to the parent automatically + // because the dialog is a top level window, so do it manually as + // in 9 cases of 10 the message must be processed by the dialog + // owner and not the dialog itself + (void)GetParent()->GetEventHandler()->ProcessEvent(event); + } +} + +#endif // wxUSE_FINDREPLDLG + diff --git a/Externals/wxWidgets/src/common/ffile.cpp b/Externals/wxWidgets/src/common/ffile.cpp index 12dfeb0832..c4b6b06426 100644 --- a/Externals/wxWidgets/src/common/ffile.cpp +++ b/Externals/wxWidgets/src/common/ffile.cpp @@ -1,268 +1,268 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: ffile.cpp -// Purpose: wxFFile encapsulates "FILE *" IO stream -// Author: Vadim Zeitlin -// Modified by: -// Created: 14.07.99 -// RCS-ID: $Id: ffile.cpp 38570 2006-04-05 14:37:47Z VZ $ -// Copyright: (c) 1998 Vadim Zeitlin -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_FFILE - -#ifndef WX_PRECOMP - #include "wx/intl.h" - #include "wx/log.h" -#endif - -#ifdef __WINDOWS__ -#include "wx/msw/mslu.h" -#endif - -#include "wx/ffile.h" - -// ============================================================================ -// implementation -// ============================================================================ - -// ---------------------------------------------------------------------------- -// seek and tell with large file support if available -// ---------------------------------------------------------------------------- - -#ifdef HAVE_FSEEKO -# define wxFseek fseeko -# define wxFtell ftello -#else -# define wxFseek fseek -# define wxFtell ftell -#endif - -// ---------------------------------------------------------------------------- -// opening the file -// ---------------------------------------------------------------------------- - -wxFFile::wxFFile(const wxChar *filename, const wxChar *mode) -{ - Detach(); - - (void)Open(filename, mode); -} - -bool wxFFile::Open(const wxChar *filename, const wxChar *mode) -{ - wxASSERT_MSG( !m_fp, wxT("should close or detach the old file first") ); - - m_fp = wxFopen(filename, mode); - - if ( !m_fp ) - { - wxLogSysError(_("can't open file '%s'"), filename); - - return false; - } - - m_name = filename; - - return true; -} - -bool wxFFile::Close() -{ - if ( IsOpened() ) - { - if ( fclose(m_fp) != 0 ) - { - wxLogSysError(_("can't close file '%s'"), m_name.c_str()); - - return false; - } - - Detach(); - } - - return true; -} - -// ---------------------------------------------------------------------------- -// read/write -// ---------------------------------------------------------------------------- - -bool wxFFile::ReadAll(wxString *str, const wxMBConv& conv) -{ - wxCHECK_MSG( str, false, wxT("invalid parameter") ); - wxCHECK_MSG( IsOpened(), false, wxT("can't read from closed file") ); - wxCHECK_MSG( Length() >= 0, false, wxT("invalid length") ); - size_t length = wx_truncate_cast(size_t, Length()); - wxCHECK_MSG( (wxFileOffset)length == Length(), false, wxT("huge file not supported") ); - - clearerr(m_fp); - - wxCharBuffer buf(length + 1); - - // note that real length may be less than file length for text files with DOS EOLs - // ('\r's get dropped by CRT when reading which means that we have - // realLen = fileLen - numOfLinesInTheFile) - length = fread(buf.data(), sizeof(char), length, m_fp); - - if ( Error() ) - { - wxLogSysError(_("Read error on file '%s'"), m_name.c_str()); - - return false; - } - - buf.data()[length] = 0; - *str = wxString(buf, conv); - - return true; -} - -size_t wxFFile::Read(void *pBuf, size_t nCount) -{ - wxCHECK_MSG( pBuf, 0, wxT("invalid parameter") ); - wxCHECK_MSG( IsOpened(), 0, wxT("can't read from closed file") ); - - size_t nRead = fread(pBuf, 1, nCount, m_fp); - if ( (nRead < nCount) && Error() ) - { - wxLogSysError(_("Read error on file '%s'"), m_name.c_str()); - } - - return nRead; -} - -size_t wxFFile::Write(const void *pBuf, size_t nCount) -{ - wxCHECK_MSG( pBuf, 0, wxT("invalid parameter") ); - wxCHECK_MSG( IsOpened(), 0, wxT("can't write to closed file") ); - - size_t nWritten = fwrite(pBuf, 1, nCount, m_fp); - if ( nWritten < nCount ) - { - wxLogSysError(_("Write error on file '%s'"), m_name.c_str()); - } - - return nWritten; -} - -bool wxFFile::Flush() -{ - if ( IsOpened() ) - { - // fflush returns non-zero on error - // - if ( fflush(m_fp) ) - { - wxLogSysError(_("failed to flush the file '%s'"), m_name.c_str()); - - return false; - } - } - - return true; -} - -// ---------------------------------------------------------------------------- -// seeking -// ---------------------------------------------------------------------------- - -bool wxFFile::Seek(wxFileOffset ofs, wxSeekMode mode) -{ - wxCHECK_MSG( IsOpened(), false, wxT("can't seek on closed file") ); - - int origin; - switch ( mode ) - { - default: - wxFAIL_MSG(wxT("unknown seek mode")); - // still fall through - - case wxFromStart: - origin = SEEK_SET; - break; - - case wxFromCurrent: - origin = SEEK_CUR; - break; - - case wxFromEnd: - origin = SEEK_END; - break; - } - -#ifndef HAVE_FSEEKO - if ((long)ofs != ofs) - { - wxLogError(_("Seek error on file '%s' (large files not supported by stdio)"), m_name.c_str()); - - return false; - } - - if ( wxFseek(m_fp, (long)ofs, origin) != 0 ) -#else - if ( wxFseek(m_fp, ofs, origin) != 0 ) -#endif - { - wxLogSysError(_("Seek error on file '%s'"), m_name.c_str()); - - return false; - } - - return true; -} - -wxFileOffset wxFFile::Tell() const -{ - wxCHECK_MSG( IsOpened(), wxInvalidOffset, - _T("wxFFile::Tell(): file is closed!") ); - - wxFileOffset rc = wxFtell(m_fp); - if ( rc == wxInvalidOffset ) - { - wxLogSysError(_("Can't find current position in file '%s'"), - m_name.c_str()); - } - - return rc; -} - -wxFileOffset wxFFile::Length() const -{ - wxCHECK_MSG( IsOpened(), wxInvalidOffset, - _T("wxFFile::Length(): file is closed!") ); - - wxFFile& self = *(wxFFile *)this; // const_cast - - wxFileOffset posOld = Tell(); - if ( posOld != wxInvalidOffset ) - { - if ( self.SeekEnd() ) - { - wxFileOffset len = Tell(); - - (void)self.Seek(posOld); - - return len; - } - } - - return wxInvalidOffset; -} - -#endif // wxUSE_FFILE +///////////////////////////////////////////////////////////////////////////// +// Name: ffile.cpp +// Purpose: wxFFile encapsulates "FILE *" IO stream +// Author: Vadim Zeitlin +// Modified by: +// Created: 14.07.99 +// RCS-ID: $Id: ffile.cpp 38570 2006-04-05 14:37:47Z VZ $ +// Copyright: (c) 1998 Vadim Zeitlin +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_FFILE + +#ifndef WX_PRECOMP + #include "wx/intl.h" + #include "wx/log.h" +#endif + +#ifdef __WINDOWS__ +#include "wx/msw/mslu.h" +#endif + +#include "wx/ffile.h" + +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// seek and tell with large file support if available +// ---------------------------------------------------------------------------- + +#ifdef HAVE_FSEEKO +# define wxFseek fseeko +# define wxFtell ftello +#else +# define wxFseek fseek +# define wxFtell ftell +#endif + +// ---------------------------------------------------------------------------- +// opening the file +// ---------------------------------------------------------------------------- + +wxFFile::wxFFile(const wxChar *filename, const wxChar *mode) +{ + Detach(); + + (void)Open(filename, mode); +} + +bool wxFFile::Open(const wxChar *filename, const wxChar *mode) +{ + wxASSERT_MSG( !m_fp, wxT("should close or detach the old file first") ); + + m_fp = wxFopen(filename, mode); + + if ( !m_fp ) + { + wxLogSysError(_("can't open file '%s'"), filename); + + return false; + } + + m_name = filename; + + return true; +} + +bool wxFFile::Close() +{ + if ( IsOpened() ) + { + if ( fclose(m_fp) != 0 ) + { + wxLogSysError(_("can't close file '%s'"), m_name.c_str()); + + return false; + } + + Detach(); + } + + return true; +} + +// ---------------------------------------------------------------------------- +// read/write +// ---------------------------------------------------------------------------- + +bool wxFFile::ReadAll(wxString *str, const wxMBConv& conv) +{ + wxCHECK_MSG( str, false, wxT("invalid parameter") ); + wxCHECK_MSG( IsOpened(), false, wxT("can't read from closed file") ); + wxCHECK_MSG( Length() >= 0, false, wxT("invalid length") ); + size_t length = wx_truncate_cast(size_t, Length()); + wxCHECK_MSG( (wxFileOffset)length == Length(), false, wxT("huge file not supported") ); + + clearerr(m_fp); + + wxCharBuffer buf(length + 1); + + // note that real length may be less than file length for text files with DOS EOLs + // ('\r's get dropped by CRT when reading which means that we have + // realLen = fileLen - numOfLinesInTheFile) + length = fread(buf.data(), sizeof(char), length, m_fp); + + if ( Error() ) + { + wxLogSysError(_("Read error on file '%s'"), m_name.c_str()); + + return false; + } + + buf.data()[length] = 0; + *str = wxString(buf, conv); + + return true; +} + +size_t wxFFile::Read(void *pBuf, size_t nCount) +{ + wxCHECK_MSG( pBuf, 0, wxT("invalid parameter") ); + wxCHECK_MSG( IsOpened(), 0, wxT("can't read from closed file") ); + + size_t nRead = fread(pBuf, 1, nCount, m_fp); + if ( (nRead < nCount) && Error() ) + { + wxLogSysError(_("Read error on file '%s'"), m_name.c_str()); + } + + return nRead; +} + +size_t wxFFile::Write(const void *pBuf, size_t nCount) +{ + wxCHECK_MSG( pBuf, 0, wxT("invalid parameter") ); + wxCHECK_MSG( IsOpened(), 0, wxT("can't write to closed file") ); + + size_t nWritten = fwrite(pBuf, 1, nCount, m_fp); + if ( nWritten < nCount ) + { + wxLogSysError(_("Write error on file '%s'"), m_name.c_str()); + } + + return nWritten; +} + +bool wxFFile::Flush() +{ + if ( IsOpened() ) + { + // fflush returns non-zero on error + // + if ( fflush(m_fp) ) + { + wxLogSysError(_("failed to flush the file '%s'"), m_name.c_str()); + + return false; + } + } + + return true; +} + +// ---------------------------------------------------------------------------- +// seeking +// ---------------------------------------------------------------------------- + +bool wxFFile::Seek(wxFileOffset ofs, wxSeekMode mode) +{ + wxCHECK_MSG( IsOpened(), false, wxT("can't seek on closed file") ); + + int origin; + switch ( mode ) + { + default: + wxFAIL_MSG(wxT("unknown seek mode")); + // still fall through + + case wxFromStart: + origin = SEEK_SET; + break; + + case wxFromCurrent: + origin = SEEK_CUR; + break; + + case wxFromEnd: + origin = SEEK_END; + break; + } + +#ifndef HAVE_FSEEKO + if ((long)ofs != ofs) + { + wxLogError(_("Seek error on file '%s' (large files not supported by stdio)"), m_name.c_str()); + + return false; + } + + if ( wxFseek(m_fp, (long)ofs, origin) != 0 ) +#else + if ( wxFseek(m_fp, ofs, origin) != 0 ) +#endif + { + wxLogSysError(_("Seek error on file '%s'"), m_name.c_str()); + + return false; + } + + return true; +} + +wxFileOffset wxFFile::Tell() const +{ + wxCHECK_MSG( IsOpened(), wxInvalidOffset, + _T("wxFFile::Tell(): file is closed!") ); + + wxFileOffset rc = wxFtell(m_fp); + if ( rc == wxInvalidOffset ) + { + wxLogSysError(_("Can't find current position in file '%s'"), + m_name.c_str()); + } + + return rc; +} + +wxFileOffset wxFFile::Length() const +{ + wxCHECK_MSG( IsOpened(), wxInvalidOffset, + _T("wxFFile::Length(): file is closed!") ); + + wxFFile& self = *(wxFFile *)this; // const_cast + + wxFileOffset posOld = Tell(); + if ( posOld != wxInvalidOffset ) + { + if ( self.SeekEnd() ) + { + wxFileOffset len = Tell(); + + (void)self.Seek(posOld); + + return len; + } + } + + return wxInvalidOffset; +} + +#endif // wxUSE_FFILE diff --git a/Externals/wxWidgets/src/common/file.cpp b/Externals/wxWidgets/src/common/file.cpp index 7b5427460f..26f0ce80de 100644 --- a/Externals/wxWidgets/src/common/file.cpp +++ b/Externals/wxWidgets/src/common/file.cpp @@ -1,559 +1,559 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: file.cpp -// Purpose: wxFile - encapsulates low-level "file descriptor" -// wxTempFile -// Author: Vadim Zeitlin -// Modified by: -// Created: 29/01/98 -// RCS-ID: $Id: file.cpp 42876 2006-10-31 23:29:02Z SN $ -// Copyright: (c) 1998 Vadim Zeitlin -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_FILE - -// standard -#if defined(__WXMSW__) && !defined(__GNUWIN32__) && !defined(__WXMICROWIN__) && !defined(__WXWINCE__) - -#ifndef __SALFORDC__ - #define WIN32_LEAN_AND_MEAN - #define NOSERVICE - #define NOIME - #define NOATOM - #define NOGDI - #define NOGDICAPMASKS - #define NOMETAFILE - #define NOMINMAX - #define NOMSG - #define NOOPENFILE - #define NORASTEROPS - #define NOSCROLL - #define NOSOUND - #define NOSYSMETRICS - #define NOTEXTMETRIC - #define NOWH - #define NOCOMM - #define NOKANJI - #define NOCRYPT - #define NOMCX -#endif - -#elif defined(__WXMSW__) && defined(__WXWINCE__) - #include "wx/msw/missing.h" -#elif (defined(__OS2__)) - #include -#elif (defined(__UNIX__) || defined(__GNUWIN32__)) - #include - #include - #include - #ifdef __GNUWIN32__ - #include "wx/msw/wrapwin.h" - #endif -#elif defined(__DOS__) - #if defined(__WATCOMC__) - #include - #elif defined(__DJGPP__) - #include - #include - #include - #else - #error "Please specify the header with file functions declarations." - #endif -#elif (defined(__WXSTUBS__)) - // Have to ifdef this for different environments - #include -#elif (defined(__WXMAC__)) -#if __MSL__ < 0x6000 - int access( const char *path, int mode ) { return 0 ; } -#else - int _access( const char *path, int mode ) { return 0 ; } -#endif - char* mktemp( char * path ) { return path ;} - #include - #include -#else - #error "Please specify the header with file functions declarations." -#endif //Win/UNIX - -#include // SEEK_xxx constants - -// Windows compilers don't have these constants -#ifndef W_OK - enum - { - F_OK = 0, // test for existence - X_OK = 1, // execute permission - W_OK = 2, // write - R_OK = 4 // read - }; -#endif // W_OK - -#ifdef __SALFORDC__ - #include -#endif - -// some broken compilers don't have 3rd argument in open() and creat() -#ifdef __SALFORDC__ - #define ACCESS(access) - #define stat _stat -#else // normal compiler - #define ACCESS(access) , (access) -#endif // Salford C - -// wxWidgets -#ifndef WX_PRECOMP - #include "wx/string.h" - #include "wx/intl.h" - #include "wx/log.h" -#endif // !WX_PRECOMP - -#include "wx/filename.h" -#include "wx/file.h" -#include "wx/filefn.h" - -// there is no distinction between text and binary files under Unix, so define -// O_BINARY as 0 if the system headers don't do it already -#if defined(__UNIX__) && !defined(O_BINARY) - #define O_BINARY (0) -#endif //__UNIX__ - -#ifdef __WXMSW__ - #include "wx/msw/mslu.h" -#endif - -#ifdef __WXWINCE__ - #include "wx/msw/private.h" -#endif - -#ifndef MAX_PATH - #define MAX_PATH 512 -#endif - -// ============================================================================ -// implementation of wxFile -// ============================================================================ - -// ---------------------------------------------------------------------------- -// static functions -// ---------------------------------------------------------------------------- - -bool wxFile::Exists(const wxChar *name) -{ - return wxFileExists(name); -} - -bool wxFile::Access(const wxChar *name, OpenMode mode) -{ - int how; - - switch ( mode ) - { - default: - wxFAIL_MSG(wxT("bad wxFile::Access mode parameter.")); - // fall through - - case read: - how = R_OK; - break; - - case write: - how = W_OK; - break; - - case read_write: - how = R_OK | W_OK; - break; - } - - return wxAccess(name, how) == 0; -} - -// ---------------------------------------------------------------------------- -// opening/closing -// ---------------------------------------------------------------------------- - -// ctors -wxFile::wxFile(const wxChar *szFileName, OpenMode mode) -{ - m_fd = fd_invalid; - m_error = false; - - Open(szFileName, mode); -} - -// create the file, fail if it already exists and bOverwrite -bool wxFile::Create(const wxChar *szFileName, bool bOverwrite, int accessMode) -{ - // if bOverwrite we create a new file or truncate the existing one, - // otherwise we only create the new file and fail if it already exists -#if defined(__WXMAC__) && !defined(__UNIX__) && !wxUSE_UNICODE - // Dominic Mazzoni [dmazzoni+@cs.cmu.edu] reports that open is still broken on the mac, so we replace - // int fd = open( szFileName , O_CREAT | (bOverwrite ? O_TRUNC : O_EXCL), access); - int fd = creat( szFileName , accessMode); -#else - int fd = wxOpen( szFileName, - O_BINARY | O_WRONLY | O_CREAT | - (bOverwrite ? O_TRUNC : O_EXCL) - ACCESS(accessMode) ); -#endif - if ( fd == -1 ) - { - wxLogSysError(_("can't create file '%s'"), szFileName); - return false; - } - - Attach(fd); - return true; -} - -// open the file -bool wxFile::Open(const wxChar *szFileName, OpenMode mode, int accessMode) -{ - int flags = O_BINARY; - - switch ( mode ) - { - case read: - flags |= O_RDONLY; - break; - - case write_append: - if ( wxFile::Exists(szFileName) ) - { - flags |= O_WRONLY | O_APPEND; - break; - } - //else: fall through as write_append is the same as write if the - // file doesn't exist - - case write: - flags |= O_WRONLY | O_CREAT | O_TRUNC; - break; - - case write_excl: - flags |= O_WRONLY | O_CREAT | O_EXCL; - break; - - case read_write: - flags |= O_RDWR; - break; - } - -#ifdef __WINDOWS__ - // only read/write bits for "all" are supported by this function under - // Windows, and VC++ 8 returns EINVAL if any other bits are used in - // accessMode, so clear them as they have at best no effect anyhow - accessMode &= wxS_IRUSR | wxS_IWUSR; -#endif // __WINDOWS__ - - int fd = wxOpen( szFileName, flags ACCESS(accessMode)); - - if ( fd == -1 ) - { - wxLogSysError(_("can't open file '%s'"), szFileName); - return false; - } - - Attach(fd); - return true; -} - -// close -bool wxFile::Close() -{ - if ( IsOpened() ) { - if (wxClose(m_fd) == -1) - { - wxLogSysError(_("can't close file descriptor %d"), m_fd); - m_fd = fd_invalid; - return false; - } - else - m_fd = fd_invalid; - } - - return true; -} - -// ---------------------------------------------------------------------------- -// read/write -// ---------------------------------------------------------------------------- - -// read -ssize_t wxFile::Read(void *pBuf, size_t nCount) -{ - wxCHECK( (pBuf != NULL) && IsOpened(), 0 ); - - ssize_t iRc = wxRead(m_fd, pBuf, nCount); - - if ( iRc == -1 ) - { - wxLogSysError(_("can't read from file descriptor %d"), m_fd); - return wxInvalidOffset; - } - - return iRc; -} - -// write -size_t wxFile::Write(const void *pBuf, size_t nCount) -{ - wxCHECK( (pBuf != NULL) && IsOpened(), 0 ); - - ssize_t iRc = wxWrite(m_fd, pBuf, nCount); - - if ( iRc == -1 ) - { - wxLogSysError(_("can't write to file descriptor %d"), m_fd); - m_error = true; - iRc = 0; - } - - return iRc; -} - -// flush -bool wxFile::Flush() -{ -#ifdef HAVE_FSYNC - // fsync() only works on disk files and returns errors for pipes, don't - // call it then - if ( IsOpened() && GetKind() == wxFILE_KIND_DISK ) - { - if ( wxFsync(m_fd) == -1 ) - { - wxLogSysError(_("can't flush file descriptor %d"), m_fd); - return false; - } - } -#endif // HAVE_FSYNC - - return true; -} - -// ---------------------------------------------------------------------------- -// seek -// ---------------------------------------------------------------------------- - -// seek -wxFileOffset wxFile::Seek(wxFileOffset ofs, wxSeekMode mode) -{ - wxASSERT_MSG( IsOpened(), _T("can't seek on closed file") ); - wxCHECK_MSG( ofs != wxInvalidOffset || mode != wxFromStart, - wxInvalidOffset, - _T("invalid absolute file offset") ); - - int origin; - switch ( mode ) { - default: - wxFAIL_MSG(_("unknown seek origin")); - - case wxFromStart: - origin = SEEK_SET; - break; - - case wxFromCurrent: - origin = SEEK_CUR; - break; - - case wxFromEnd: - origin = SEEK_END; - break; - } - - wxFileOffset iRc = wxSeek(m_fd, ofs, origin); - if ( iRc == wxInvalidOffset ) - { - wxLogSysError(_("can't seek on file descriptor %d"), m_fd); - } - - return iRc; -} - -// get current file offset -wxFileOffset wxFile::Tell() const -{ - wxASSERT( IsOpened() ); - - wxFileOffset iRc = wxTell(m_fd); - if ( iRc == wxInvalidOffset ) - { - wxLogSysError(_("can't get seek position on file descriptor %d"), m_fd); - } - - return iRc; -} - -// get current file length -wxFileOffset wxFile::Length() const -{ - wxASSERT( IsOpened() ); - - wxFileOffset iRc = Tell(); - if ( iRc != wxInvalidOffset ) { - // have to use const_cast :-( - wxFileOffset iLen = ((wxFile *)this)->SeekEnd(); - if ( iLen != wxInvalidOffset ) { - // restore old position - if ( ((wxFile *)this)->Seek(iRc) == wxInvalidOffset ) { - // error - iLen = wxInvalidOffset; - } - } - - iRc = iLen; - } - - if ( iRc == wxInvalidOffset ) - { - wxLogSysError(_("can't find length of file on file descriptor %d"), m_fd); - } - - return iRc; -} - -// is end of file reached? -bool wxFile::Eof() const -{ - wxASSERT( IsOpened() ); - - wxFileOffset iRc; - -#if defined(__DOS__) || defined(__UNIX__) || defined(__GNUWIN32__) || defined( __MWERKS__ ) || defined(__SALFORDC__) - // @@ this doesn't work, of course, on unseekable file descriptors - wxFileOffset ofsCur = Tell(), - ofsMax = Length(); - if ( ofsCur == wxInvalidOffset || ofsMax == wxInvalidOffset ) - iRc = wxInvalidOffset; - else - iRc = ofsCur == ofsMax; -#else // Windows and "native" compiler - iRc = wxEof(m_fd); -#endif // Windows/Unix - - if ( iRc == 1) - {} - else if ( iRc == 0 ) - return false; - else if ( iRc == wxInvalidOffset ) - wxLogSysError(_("can't determine if the end of file is reached on descriptor %d"), m_fd); - else - wxFAIL_MSG(_("invalid eof() return value.")); - - return true; -} - -// ============================================================================ -// implementation of wxTempFile -// ============================================================================ - -// ---------------------------------------------------------------------------- -// construction -// ---------------------------------------------------------------------------- - -wxTempFile::wxTempFile(const wxString& strName) -{ - Open(strName); -} - -bool wxTempFile::Open(const wxString& strName) -{ - // we must have an absolute filename because otherwise CreateTempFileName() - // would create the temp file in $TMP (i.e. the system standard location - // for the temp files) which might be on another volume/drive/mount and - // wxRename()ing it later to m_strName from Commit() would then fail - // - // with the absolute filename, the temp file is created in the same - // directory as this one which ensures that wxRename() may work later - wxFileName fn(strName); - if ( !fn.IsAbsolute() ) - { - fn.Normalize(wxPATH_NORM_ABSOLUTE); - } - - m_strName = fn.GetFullPath(); - - m_strTemp = wxFileName::CreateTempFileName(m_strName, &m_file); - - if ( m_strTemp.empty() ) - { - // CreateTempFileName() failed - return false; - } - -#ifdef __UNIX__ - // the temp file should have the same permissions as the original one - mode_t mode; - - wxStructStat st; - if ( stat( (const char*) m_strName.fn_str(), &st) == 0 ) - { - mode = st.st_mode; - } - else - { - // file probably didn't exist, just give it the default mode _using_ - // user's umask (new files creation should respect umask) - mode_t mask = umask(0777); - mode = 0666 & ~mask; - umask(mask); - } - - if ( chmod( (const char*) m_strTemp.fn_str(), mode) == -1 ) - { -#ifndef __OS2__ - wxLogSysError(_("Failed to set temporary file permissions")); -#endif - } -#endif // Unix - - return true; -} - -// ---------------------------------------------------------------------------- -// destruction -// ---------------------------------------------------------------------------- - -wxTempFile::~wxTempFile() -{ - if ( IsOpened() ) - Discard(); -} - -bool wxTempFile::Commit() -{ - m_file.Close(); - - if ( wxFile::Exists(m_strName) && wxRemove(m_strName) != 0 ) { - wxLogSysError(_("can't remove file '%s'"), m_strName.c_str()); - return false; - } - - if ( !wxRenameFile(m_strTemp, m_strName) ) { - wxLogSysError(_("can't commit changes to file '%s'"), m_strName.c_str()); - return false; - } - - return true; -} - -void wxTempFile::Discard() -{ - m_file.Close(); - if ( wxRemove(m_strTemp) != 0 ) - wxLogSysError(_("can't remove temporary file '%s'"), m_strTemp.c_str()); -} - -#endif // wxUSE_FILE - +///////////////////////////////////////////////////////////////////////////// +// Name: file.cpp +// Purpose: wxFile - encapsulates low-level "file descriptor" +// wxTempFile +// Author: Vadim Zeitlin +// Modified by: +// Created: 29/01/98 +// RCS-ID: $Id: file.cpp 42876 2006-10-31 23:29:02Z SN $ +// Copyright: (c) 1998 Vadim Zeitlin +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_FILE + +// standard +#if defined(__WXMSW__) && !defined(__GNUWIN32__) && !defined(__WXMICROWIN__) && !defined(__WXWINCE__) + +#ifndef __SALFORDC__ + #define WIN32_LEAN_AND_MEAN + #define NOSERVICE + #define NOIME + #define NOATOM + #define NOGDI + #define NOGDICAPMASKS + #define NOMETAFILE + #define NOMINMAX + #define NOMSG + #define NOOPENFILE + #define NORASTEROPS + #define NOSCROLL + #define NOSOUND + #define NOSYSMETRICS + #define NOTEXTMETRIC + #define NOWH + #define NOCOMM + #define NOKANJI + #define NOCRYPT + #define NOMCX +#endif + +#elif defined(__WXMSW__) && defined(__WXWINCE__) + #include "wx/msw/missing.h" +#elif (defined(__OS2__)) + #include +#elif (defined(__UNIX__) || defined(__GNUWIN32__)) + #include + #include + #include + #ifdef __GNUWIN32__ + #include "wx/msw/wrapwin.h" + #endif +#elif defined(__DOS__) + #if defined(__WATCOMC__) + #include + #elif defined(__DJGPP__) + #include + #include + #include + #else + #error "Please specify the header with file functions declarations." + #endif +#elif (defined(__WXSTUBS__)) + // Have to ifdef this for different environments + #include +#elif (defined(__WXMAC__)) +#if __MSL__ < 0x6000 + int access( const char *path, int mode ) { return 0 ; } +#else + int _access( const char *path, int mode ) { return 0 ; } +#endif + char* mktemp( char * path ) { return path ;} + #include + #include +#else + #error "Please specify the header with file functions declarations." +#endif //Win/UNIX + +#include // SEEK_xxx constants + +// Windows compilers don't have these constants +#ifndef W_OK + enum + { + F_OK = 0, // test for existence + X_OK = 1, // execute permission + W_OK = 2, // write + R_OK = 4 // read + }; +#endif // W_OK + +#ifdef __SALFORDC__ + #include +#endif + +// some broken compilers don't have 3rd argument in open() and creat() +#ifdef __SALFORDC__ + #define ACCESS(access) + #define stat _stat +#else // normal compiler + #define ACCESS(access) , (access) +#endif // Salford C + +// wxWidgets +#ifndef WX_PRECOMP + #include "wx/string.h" + #include "wx/intl.h" + #include "wx/log.h" +#endif // !WX_PRECOMP + +#include "wx/filename.h" +#include "wx/file.h" +#include "wx/filefn.h" + +// there is no distinction between text and binary files under Unix, so define +// O_BINARY as 0 if the system headers don't do it already +#if defined(__UNIX__) && !defined(O_BINARY) + #define O_BINARY (0) +#endif //__UNIX__ + +#ifdef __WXMSW__ + #include "wx/msw/mslu.h" +#endif + +#ifdef __WXWINCE__ + #include "wx/msw/private.h" +#endif + +#ifndef MAX_PATH + #define MAX_PATH 512 +#endif + +// ============================================================================ +// implementation of wxFile +// ============================================================================ + +// ---------------------------------------------------------------------------- +// static functions +// ---------------------------------------------------------------------------- + +bool wxFile::Exists(const wxChar *name) +{ + return wxFileExists(name); +} + +bool wxFile::Access(const wxChar *name, OpenMode mode) +{ + int how; + + switch ( mode ) + { + default: + wxFAIL_MSG(wxT("bad wxFile::Access mode parameter.")); + // fall through + + case read: + how = R_OK; + break; + + case write: + how = W_OK; + break; + + case read_write: + how = R_OK | W_OK; + break; + } + + return wxAccess(name, how) == 0; +} + +// ---------------------------------------------------------------------------- +// opening/closing +// ---------------------------------------------------------------------------- + +// ctors +wxFile::wxFile(const wxChar *szFileName, OpenMode mode) +{ + m_fd = fd_invalid; + m_error = false; + + Open(szFileName, mode); +} + +// create the file, fail if it already exists and bOverwrite +bool wxFile::Create(const wxChar *szFileName, bool bOverwrite, int accessMode) +{ + // if bOverwrite we create a new file or truncate the existing one, + // otherwise we only create the new file and fail if it already exists +#if defined(__WXMAC__) && !defined(__UNIX__) && !wxUSE_UNICODE + // Dominic Mazzoni [dmazzoni+@cs.cmu.edu] reports that open is still broken on the mac, so we replace + // int fd = open( szFileName , O_CREAT | (bOverwrite ? O_TRUNC : O_EXCL), access); + int fd = creat( szFileName , accessMode); +#else + int fd = wxOpen( szFileName, + O_BINARY | O_WRONLY | O_CREAT | + (bOverwrite ? O_TRUNC : O_EXCL) + ACCESS(accessMode) ); +#endif + if ( fd == -1 ) + { + wxLogSysError(_("can't create file '%s'"), szFileName); + return false; + } + + Attach(fd); + return true; +} + +// open the file +bool wxFile::Open(const wxChar *szFileName, OpenMode mode, int accessMode) +{ + int flags = O_BINARY; + + switch ( mode ) + { + case read: + flags |= O_RDONLY; + break; + + case write_append: + if ( wxFile::Exists(szFileName) ) + { + flags |= O_WRONLY | O_APPEND; + break; + } + //else: fall through as write_append is the same as write if the + // file doesn't exist + + case write: + flags |= O_WRONLY | O_CREAT | O_TRUNC; + break; + + case write_excl: + flags |= O_WRONLY | O_CREAT | O_EXCL; + break; + + case read_write: + flags |= O_RDWR; + break; + } + +#ifdef __WINDOWS__ + // only read/write bits for "all" are supported by this function under + // Windows, and VC++ 8 returns EINVAL if any other bits are used in + // accessMode, so clear them as they have at best no effect anyhow + accessMode &= wxS_IRUSR | wxS_IWUSR; +#endif // __WINDOWS__ + + int fd = wxOpen( szFileName, flags ACCESS(accessMode)); + + if ( fd == -1 ) + { + wxLogSysError(_("can't open file '%s'"), szFileName); + return false; + } + + Attach(fd); + return true; +} + +// close +bool wxFile::Close() +{ + if ( IsOpened() ) { + if (wxClose(m_fd) == -1) + { + wxLogSysError(_("can't close file descriptor %d"), m_fd); + m_fd = fd_invalid; + return false; + } + else + m_fd = fd_invalid; + } + + return true; +} + +// ---------------------------------------------------------------------------- +// read/write +// ---------------------------------------------------------------------------- + +// read +ssize_t wxFile::Read(void *pBuf, size_t nCount) +{ + wxCHECK( (pBuf != NULL) && IsOpened(), 0 ); + + ssize_t iRc = wxRead(m_fd, pBuf, nCount); + + if ( iRc == -1 ) + { + wxLogSysError(_("can't read from file descriptor %d"), m_fd); + return wxInvalidOffset; + } + + return iRc; +} + +// write +size_t wxFile::Write(const void *pBuf, size_t nCount) +{ + wxCHECK( (pBuf != NULL) && IsOpened(), 0 ); + + ssize_t iRc = wxWrite(m_fd, pBuf, nCount); + + if ( iRc == -1 ) + { + wxLogSysError(_("can't write to file descriptor %d"), m_fd); + m_error = true; + iRc = 0; + } + + return iRc; +} + +// flush +bool wxFile::Flush() +{ +#ifdef HAVE_FSYNC + // fsync() only works on disk files and returns errors for pipes, don't + // call it then + if ( IsOpened() && GetKind() == wxFILE_KIND_DISK ) + { + if ( wxFsync(m_fd) == -1 ) + { + wxLogSysError(_("can't flush file descriptor %d"), m_fd); + return false; + } + } +#endif // HAVE_FSYNC + + return true; +} + +// ---------------------------------------------------------------------------- +// seek +// ---------------------------------------------------------------------------- + +// seek +wxFileOffset wxFile::Seek(wxFileOffset ofs, wxSeekMode mode) +{ + wxASSERT_MSG( IsOpened(), _T("can't seek on closed file") ); + wxCHECK_MSG( ofs != wxInvalidOffset || mode != wxFromStart, + wxInvalidOffset, + _T("invalid absolute file offset") ); + + int origin; + switch ( mode ) { + default: + wxFAIL_MSG(_("unknown seek origin")); + + case wxFromStart: + origin = SEEK_SET; + break; + + case wxFromCurrent: + origin = SEEK_CUR; + break; + + case wxFromEnd: + origin = SEEK_END; + break; + } + + wxFileOffset iRc = wxSeek(m_fd, ofs, origin); + if ( iRc == wxInvalidOffset ) + { + wxLogSysError(_("can't seek on file descriptor %d"), m_fd); + } + + return iRc; +} + +// get current file offset +wxFileOffset wxFile::Tell() const +{ + wxASSERT( IsOpened() ); + + wxFileOffset iRc = wxTell(m_fd); + if ( iRc == wxInvalidOffset ) + { + wxLogSysError(_("can't get seek position on file descriptor %d"), m_fd); + } + + return iRc; +} + +// get current file length +wxFileOffset wxFile::Length() const +{ + wxASSERT( IsOpened() ); + + wxFileOffset iRc = Tell(); + if ( iRc != wxInvalidOffset ) { + // have to use const_cast :-( + wxFileOffset iLen = ((wxFile *)this)->SeekEnd(); + if ( iLen != wxInvalidOffset ) { + // restore old position + if ( ((wxFile *)this)->Seek(iRc) == wxInvalidOffset ) { + // error + iLen = wxInvalidOffset; + } + } + + iRc = iLen; + } + + if ( iRc == wxInvalidOffset ) + { + wxLogSysError(_("can't find length of file on file descriptor %d"), m_fd); + } + + return iRc; +} + +// is end of file reached? +bool wxFile::Eof() const +{ + wxASSERT( IsOpened() ); + + wxFileOffset iRc; + +#if defined(__DOS__) || defined(__UNIX__) || defined(__GNUWIN32__) || defined( __MWERKS__ ) || defined(__SALFORDC__) + // @@ this doesn't work, of course, on unseekable file descriptors + wxFileOffset ofsCur = Tell(), + ofsMax = Length(); + if ( ofsCur == wxInvalidOffset || ofsMax == wxInvalidOffset ) + iRc = wxInvalidOffset; + else + iRc = ofsCur == ofsMax; +#else // Windows and "native" compiler + iRc = wxEof(m_fd); +#endif // Windows/Unix + + if ( iRc == 1) + {} + else if ( iRc == 0 ) + return false; + else if ( iRc == wxInvalidOffset ) + wxLogSysError(_("can't determine if the end of file is reached on descriptor %d"), m_fd); + else + wxFAIL_MSG(_("invalid eof() return value.")); + + return true; +} + +// ============================================================================ +// implementation of wxTempFile +// ============================================================================ + +// ---------------------------------------------------------------------------- +// construction +// ---------------------------------------------------------------------------- + +wxTempFile::wxTempFile(const wxString& strName) +{ + Open(strName); +} + +bool wxTempFile::Open(const wxString& strName) +{ + // we must have an absolute filename because otherwise CreateTempFileName() + // would create the temp file in $TMP (i.e. the system standard location + // for the temp files) which might be on another volume/drive/mount and + // wxRename()ing it later to m_strName from Commit() would then fail + // + // with the absolute filename, the temp file is created in the same + // directory as this one which ensures that wxRename() may work later + wxFileName fn(strName); + if ( !fn.IsAbsolute() ) + { + fn.Normalize(wxPATH_NORM_ABSOLUTE); + } + + m_strName = fn.GetFullPath(); + + m_strTemp = wxFileName::CreateTempFileName(m_strName, &m_file); + + if ( m_strTemp.empty() ) + { + // CreateTempFileName() failed + return false; + } + +#ifdef __UNIX__ + // the temp file should have the same permissions as the original one + mode_t mode; + + wxStructStat st; + if ( stat( (const char*) m_strName.fn_str(), &st) == 0 ) + { + mode = st.st_mode; + } + else + { + // file probably didn't exist, just give it the default mode _using_ + // user's umask (new files creation should respect umask) + mode_t mask = umask(0777); + mode = 0666 & ~mask; + umask(mask); + } + + if ( chmod( (const char*) m_strTemp.fn_str(), mode) == -1 ) + { +#ifndef __OS2__ + wxLogSysError(_("Failed to set temporary file permissions")); +#endif + } +#endif // Unix + + return true; +} + +// ---------------------------------------------------------------------------- +// destruction +// ---------------------------------------------------------------------------- + +wxTempFile::~wxTempFile() +{ + if ( IsOpened() ) + Discard(); +} + +bool wxTempFile::Commit() +{ + m_file.Close(); + + if ( wxFile::Exists(m_strName) && wxRemove(m_strName) != 0 ) { + wxLogSysError(_("can't remove file '%s'"), m_strName.c_str()); + return false; + } + + if ( !wxRenameFile(m_strTemp, m_strName) ) { + wxLogSysError(_("can't commit changes to file '%s'"), m_strName.c_str()); + return false; + } + + return true; +} + +void wxTempFile::Discard() +{ + m_file.Close(); + if ( wxRemove(m_strTemp) != 0 ) + wxLogSysError(_("can't remove temporary file '%s'"), m_strTemp.c_str()); +} + +#endif // wxUSE_FILE + diff --git a/Externals/wxWidgets/src/common/fileback.cpp b/Externals/wxWidgets/src/common/fileback.cpp index 58fba90c02..ccce957bfb 100644 --- a/Externals/wxWidgets/src/common/fileback.cpp +++ b/Externals/wxWidgets/src/common/fileback.cpp @@ -1,338 +1,338 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/fileback.cpp -// Purpose: Back an input stream with memory or a file -// Author: Mike Wetherell -// RCS-ID: $Id: fileback.cpp 42651 2006-10-29 20:06:45Z MW $ -// Copyright: (c) 2006 Mike Wetherell -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_FILESYSTEM - -#include "wx/private/fileback.h" - -#ifndef WX_PRECOMP - #include "wx/utils.h" - #include "wx/log.h" -#endif - -#include "wx/private/filename.h" - -// Prefer wxFFile unless wxFile has large file support but wxFFile does not. -// -#if wxUSE_FFILE && (defined wxHAS_LARGE_FFILES || !defined wxHAS_LARGE_FILES) -typedef wxFFile wxBFFile; -static const bool wxBadSeek = false; -#else -typedef wxFile wxBFFile; -static const wxFileOffset wxBadSeek = wxInvalidOffset; -#endif - -///////////////////////////////////////////////////////////////////////////// -// Backing file implementation - -class wxBackingFileImpl -{ -public: - wxBackingFileImpl(wxInputStream *stream, - size_t bufsize, - const wxString& prefix); - ~wxBackingFileImpl(); - - void Release() { if (--m_refcount == 0) delete this; } - wxBackingFileImpl *AddRef() { m_refcount++; return this; } - - wxStreamError ReadAt(wxFileOffset pos, void *buffer, size_t *size); - wxFileOffset GetLength() const; - -private: - int m_refcount; - - wxInputStream *m_stream; - wxStreamError m_parenterror; - - char *m_buf; - size_t m_bufsize; - size_t m_buflen; - - wxString m_prefix; - wxString m_filename; - wxBFFile m_file; - wxFileOffset m_filelen; -}; - -wxBackingFileImpl::wxBackingFileImpl(wxInputStream *stream, - size_t bufsize, - const wxString& prefix) - : m_refcount(1), - m_stream(stream), - m_parenterror(wxSTREAM_NO_ERROR), - m_buf(NULL), - m_bufsize(bufsize), - m_buflen(0), - m_prefix(prefix), - m_filelen(0) -{ - wxFileOffset len = m_stream->GetLength(); - - if (len >= 0 && len + size_t(1) < m_bufsize) - m_bufsize = size_t(len + 1); - - if (m_bufsize) - m_buf = new char[m_bufsize]; -} - -wxBackingFileImpl::~wxBackingFileImpl() -{ - delete m_stream; - delete [] m_buf; - - if (!m_filename.empty()) - wxRemoveFile(m_filename); -} - -wxStreamError wxBackingFileImpl::ReadAt(wxFileOffset pos, - void *buffer, - size_t *size) -{ - size_t reqestedSize = *size; - *size = 0; - - // size1 is the number of bytes it will read directly from the backing - // file. size2 is any remaining bytes not yet backed, these are returned - // from the buffer or read from the parent stream. - size_t size1, size2; - - if (pos + reqestedSize <= m_filelen + size_t(0)) { - size1 = reqestedSize; - size2 = 0; - } else if (pos < m_filelen) { - size1 = size_t(m_filelen - pos); - size2 = reqestedSize - size1; - } else { - size1 = 0; - size2 = reqestedSize; - } - - if (pos < 0) - return wxSTREAM_READ_ERROR; - - // read the backing file - if (size1) { - if (m_file.Seek(pos) == wxBadSeek) - return wxSTREAM_READ_ERROR; - - ssize_t n = m_file.Read(buffer, size1); - if (n > 0) { - *size = n; - pos += n; - } - - if (*size < size1) - return wxSTREAM_READ_ERROR; - } - - // read from the buffer or parent stream - if (size2) - { - while (*size < reqestedSize) - { - // if pos is further ahead than the parent has been read so far, - // then read forward in the parent stream - while (pos - m_filelen + size_t(0) >= m_buflen) - { - // if the parent is small enough, don't use a backing file - // just the buffer memory - if (!m_stream && m_filelen == 0) - return m_parenterror; - - // before refilling the buffer write out the current buffer - // to the backing file if there is anything in it - if (m_buflen) - { - if (!m_file.IsOpened()) - if (!wxCreateTempFile(m_prefix, &m_file, &m_filename)) - return wxSTREAM_READ_ERROR; - - if (m_file.Seek(m_filelen) == wxBadSeek) - return wxSTREAM_READ_ERROR; - - size_t count = m_file.Write(m_buf, m_buflen); - m_filelen += count; - - if (count < m_buflen) { - delete m_stream; - m_stream = NULL; - if (count > 0) { - delete[] m_buf; - m_buf = NULL; - m_buflen = 0; - } - m_parenterror = wxSTREAM_READ_ERROR; - return m_parenterror; - } - - m_buflen = 0; - - if (!m_stream) { - delete[] m_buf; - m_buf = NULL; - } - } - - if (!m_stream) - return m_parenterror; - - // refill buffer - m_buflen = m_stream->Read(m_buf, m_bufsize).LastRead(); - - if (m_buflen < m_bufsize) { - m_parenterror = m_stream->GetLastError(); - if (m_parenterror == wxSTREAM_NO_ERROR) - m_parenterror = wxSTREAM_EOF; - delete m_stream; - m_stream = NULL; - } - } - - // copy to the user's buffer - size_t start = size_t(pos - m_filelen); - size_t len = wxMin(m_buflen - start, reqestedSize - *size); - - memcpy((char*)buffer + *size, m_buf + start, len); - *size += len; - pos += len; - } - } - - return wxSTREAM_NO_ERROR; -} - -wxFileOffset wxBackingFileImpl::GetLength() const -{ - if (m_parenterror != wxSTREAM_EOF) { - wxLogNull nolog; - return m_stream->GetLength(); - } - return m_filelen + m_buflen; -} - - -///////////////////////////////////////////////////////////////////////////// -// Backing File, the handle part - -wxBackingFile::wxBackingFile(wxInputStream *stream, - size_t bufsize, - const wxString& prefix) - : m_impl(new wxBackingFileImpl(stream, bufsize, prefix)) -{ -} - -wxBackingFile::wxBackingFile(const wxBackingFile& backer) - : m_impl(backer.m_impl ? backer.m_impl->AddRef() : NULL) -{ -} - -wxBackingFile& wxBackingFile::operator=(const wxBackingFile& backer) -{ - if (backer.m_impl != m_impl) { - if (m_impl) - m_impl->Release(); - - m_impl = backer.m_impl; - - if (m_impl) - m_impl->AddRef(); - } - - return *this; -} - -wxBackingFile::~wxBackingFile() -{ - if (m_impl) - m_impl->Release(); -} - - -///////////////////////////////////////////////////////////////////////////// -// Input stream - -wxBackedInputStream::wxBackedInputStream(const wxBackingFile& backer) - : m_backer(backer), - m_pos(0) -{ -} - -wxFileOffset wxBackedInputStream::GetLength() const -{ - return m_backer.m_impl->GetLength(); -} - -wxFileOffset wxBackedInputStream::FindLength() const -{ - wxFileOffset len = GetLength(); - - if (len == wxInvalidOffset && IsOk()) { - // read a byte at 7ff...ffe - wxFileOffset pos = 1; - pos <<= sizeof(pos) * 8 - 1; - pos = ~pos - 1; - char ch; - size_t size = 1; - m_backer.m_impl->ReadAt(pos, &ch, &size); - len = GetLength(); - } - - return len; -} - -size_t wxBackedInputStream::OnSysRead(void *buffer, size_t size) -{ - if (!IsOk()) - return 0; - - m_lasterror = m_backer.m_impl->ReadAt(m_pos, buffer, &size); - m_pos += size; - return size; -} - -wxFileOffset wxBackedInputStream::OnSysSeek(wxFileOffset pos, wxSeekMode mode) -{ - switch (mode) { - case wxFromCurrent: - { - m_pos += pos; - break; - } - case wxFromEnd: - { - wxFileOffset len = GetLength(); - if (len == wxInvalidOffset) - return wxInvalidOffset; - m_pos = len + pos; - break; - } - default: - { - m_pos = pos; - break; - } - } - - return m_pos; -} - -wxFileOffset wxBackedInputStream::OnSysTell() const -{ - return m_pos; -} - -#endif // wxUSE_FILESYSTEM +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/fileback.cpp +// Purpose: Back an input stream with memory or a file +// Author: Mike Wetherell +// RCS-ID: $Id: fileback.cpp 42651 2006-10-29 20:06:45Z MW $ +// Copyright: (c) 2006 Mike Wetherell +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_FILESYSTEM + +#include "wx/private/fileback.h" + +#ifndef WX_PRECOMP + #include "wx/utils.h" + #include "wx/log.h" +#endif + +#include "wx/private/filename.h" + +// Prefer wxFFile unless wxFile has large file support but wxFFile does not. +// +#if wxUSE_FFILE && (defined wxHAS_LARGE_FFILES || !defined wxHAS_LARGE_FILES) +typedef wxFFile wxBFFile; +static const bool wxBadSeek = false; +#else +typedef wxFile wxBFFile; +static const wxFileOffset wxBadSeek = wxInvalidOffset; +#endif + +///////////////////////////////////////////////////////////////////////////// +// Backing file implementation + +class wxBackingFileImpl +{ +public: + wxBackingFileImpl(wxInputStream *stream, + size_t bufsize, + const wxString& prefix); + ~wxBackingFileImpl(); + + void Release() { if (--m_refcount == 0) delete this; } + wxBackingFileImpl *AddRef() { m_refcount++; return this; } + + wxStreamError ReadAt(wxFileOffset pos, void *buffer, size_t *size); + wxFileOffset GetLength() const; + +private: + int m_refcount; + + wxInputStream *m_stream; + wxStreamError m_parenterror; + + char *m_buf; + size_t m_bufsize; + size_t m_buflen; + + wxString m_prefix; + wxString m_filename; + wxBFFile m_file; + wxFileOffset m_filelen; +}; + +wxBackingFileImpl::wxBackingFileImpl(wxInputStream *stream, + size_t bufsize, + const wxString& prefix) + : m_refcount(1), + m_stream(stream), + m_parenterror(wxSTREAM_NO_ERROR), + m_buf(NULL), + m_bufsize(bufsize), + m_buflen(0), + m_prefix(prefix), + m_filelen(0) +{ + wxFileOffset len = m_stream->GetLength(); + + if (len >= 0 && len + size_t(1) < m_bufsize) + m_bufsize = size_t(len + 1); + + if (m_bufsize) + m_buf = new char[m_bufsize]; +} + +wxBackingFileImpl::~wxBackingFileImpl() +{ + delete m_stream; + delete [] m_buf; + + if (!m_filename.empty()) + wxRemoveFile(m_filename); +} + +wxStreamError wxBackingFileImpl::ReadAt(wxFileOffset pos, + void *buffer, + size_t *size) +{ + size_t reqestedSize = *size; + *size = 0; + + // size1 is the number of bytes it will read directly from the backing + // file. size2 is any remaining bytes not yet backed, these are returned + // from the buffer or read from the parent stream. + size_t size1, size2; + + if (pos + reqestedSize <= m_filelen + size_t(0)) { + size1 = reqestedSize; + size2 = 0; + } else if (pos < m_filelen) { + size1 = size_t(m_filelen - pos); + size2 = reqestedSize - size1; + } else { + size1 = 0; + size2 = reqestedSize; + } + + if (pos < 0) + return wxSTREAM_READ_ERROR; + + // read the backing file + if (size1) { + if (m_file.Seek(pos) == wxBadSeek) + return wxSTREAM_READ_ERROR; + + ssize_t n = m_file.Read(buffer, size1); + if (n > 0) { + *size = n; + pos += n; + } + + if (*size < size1) + return wxSTREAM_READ_ERROR; + } + + // read from the buffer or parent stream + if (size2) + { + while (*size < reqestedSize) + { + // if pos is further ahead than the parent has been read so far, + // then read forward in the parent stream + while (pos - m_filelen + size_t(0) >= m_buflen) + { + // if the parent is small enough, don't use a backing file + // just the buffer memory + if (!m_stream && m_filelen == 0) + return m_parenterror; + + // before refilling the buffer write out the current buffer + // to the backing file if there is anything in it + if (m_buflen) + { + if (!m_file.IsOpened()) + if (!wxCreateTempFile(m_prefix, &m_file, &m_filename)) + return wxSTREAM_READ_ERROR; + + if (m_file.Seek(m_filelen) == wxBadSeek) + return wxSTREAM_READ_ERROR; + + size_t count = m_file.Write(m_buf, m_buflen); + m_filelen += count; + + if (count < m_buflen) { + delete m_stream; + m_stream = NULL; + if (count > 0) { + delete[] m_buf; + m_buf = NULL; + m_buflen = 0; + } + m_parenterror = wxSTREAM_READ_ERROR; + return m_parenterror; + } + + m_buflen = 0; + + if (!m_stream) { + delete[] m_buf; + m_buf = NULL; + } + } + + if (!m_stream) + return m_parenterror; + + // refill buffer + m_buflen = m_stream->Read(m_buf, m_bufsize).LastRead(); + + if (m_buflen < m_bufsize) { + m_parenterror = m_stream->GetLastError(); + if (m_parenterror == wxSTREAM_NO_ERROR) + m_parenterror = wxSTREAM_EOF; + delete m_stream; + m_stream = NULL; + } + } + + // copy to the user's buffer + size_t start = size_t(pos - m_filelen); + size_t len = wxMin(m_buflen - start, reqestedSize - *size); + + memcpy((char*)buffer + *size, m_buf + start, len); + *size += len; + pos += len; + } + } + + return wxSTREAM_NO_ERROR; +} + +wxFileOffset wxBackingFileImpl::GetLength() const +{ + if (m_parenterror != wxSTREAM_EOF) { + wxLogNull nolog; + return m_stream->GetLength(); + } + return m_filelen + m_buflen; +} + + +///////////////////////////////////////////////////////////////////////////// +// Backing File, the handle part + +wxBackingFile::wxBackingFile(wxInputStream *stream, + size_t bufsize, + const wxString& prefix) + : m_impl(new wxBackingFileImpl(stream, bufsize, prefix)) +{ +} + +wxBackingFile::wxBackingFile(const wxBackingFile& backer) + : m_impl(backer.m_impl ? backer.m_impl->AddRef() : NULL) +{ +} + +wxBackingFile& wxBackingFile::operator=(const wxBackingFile& backer) +{ + if (backer.m_impl != m_impl) { + if (m_impl) + m_impl->Release(); + + m_impl = backer.m_impl; + + if (m_impl) + m_impl->AddRef(); + } + + return *this; +} + +wxBackingFile::~wxBackingFile() +{ + if (m_impl) + m_impl->Release(); +} + + +///////////////////////////////////////////////////////////////////////////// +// Input stream + +wxBackedInputStream::wxBackedInputStream(const wxBackingFile& backer) + : m_backer(backer), + m_pos(0) +{ +} + +wxFileOffset wxBackedInputStream::GetLength() const +{ + return m_backer.m_impl->GetLength(); +} + +wxFileOffset wxBackedInputStream::FindLength() const +{ + wxFileOffset len = GetLength(); + + if (len == wxInvalidOffset && IsOk()) { + // read a byte at 7ff...ffe + wxFileOffset pos = 1; + pos <<= sizeof(pos) * 8 - 1; + pos = ~pos - 1; + char ch; + size_t size = 1; + m_backer.m_impl->ReadAt(pos, &ch, &size); + len = GetLength(); + } + + return len; +} + +size_t wxBackedInputStream::OnSysRead(void *buffer, size_t size) +{ + if (!IsOk()) + return 0; + + m_lasterror = m_backer.m_impl->ReadAt(m_pos, buffer, &size); + m_pos += size; + return size; +} + +wxFileOffset wxBackedInputStream::OnSysSeek(wxFileOffset pos, wxSeekMode mode) +{ + switch (mode) { + case wxFromCurrent: + { + m_pos += pos; + break; + } + case wxFromEnd: + { + wxFileOffset len = GetLength(); + if (len == wxInvalidOffset) + return wxInvalidOffset; + m_pos = len + pos; + break; + } + default: + { + m_pos = pos; + break; + } + } + + return m_pos; +} + +wxFileOffset wxBackedInputStream::OnSysTell() const +{ + return m_pos; +} + +#endif // wxUSE_FILESYSTEM diff --git a/Externals/wxWidgets/src/common/fileconf.cpp b/Externals/wxWidgets/src/common/fileconf.cpp index d89f8a96f2..c85ebe894f 100644 --- a/Externals/wxWidgets/src/common/fileconf.cpp +++ b/Externals/wxWidgets/src/common/fileconf.cpp @@ -1,2131 +1,2131 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: src/common/fileconf.cpp -// Purpose: implementation of wxFileConfig derivation of wxConfig -// Author: Vadim Zeitlin -// Modified by: -// Created: 07.04.98 (adapted from appconf.cpp) -// RCS-ID: $Id: fileconf.cpp 50711 2007-12-15 02:57:58Z VZ $ -// Copyright: (c) 1997 Karsten Ballueder & Vadim Zeitlin -// Ballueder@usa.net -// Licence: wxWindows licence -/////////////////////////////////////////////////////////////////////////////// - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif //__BORLANDC__ - -#if wxUSE_CONFIG && wxUSE_FILECONFIG - -#ifndef WX_PRECOMP - #include "wx/dynarray.h" - #include "wx/string.h" - #include "wx/intl.h" - #include "wx/log.h" - #include "wx/app.h" - #include "wx/utils.h" // for wxGetHomeDir - #if wxUSE_STREAMS - #include "wx/stream.h" - #endif // wxUSE_STREAMS -#endif //WX_PRECOMP - -#include "wx/file.h" -#include "wx/textfile.h" -#include "wx/memtext.h" -#include "wx/config.h" -#include "wx/fileconf.h" -#include "wx/filefn.h" - -#if defined(__WXMAC__) - #include "wx/mac/private.h" // includes mac headers - #include "wx/filename.h" // for MacSetTypeAndCreator -#endif - -#if defined(__WXMSW__) - #include "wx/msw/private.h" -#endif //windows.h -#if defined(__WXPM__) - #define INCL_DOS - #include -#endif - -#include -#include - -// ---------------------------------------------------------------------------- -// macros -// ---------------------------------------------------------------------------- -#define CONST_CAST ((wxFileConfig *)this)-> - -// ---------------------------------------------------------------------------- -// constants -// ---------------------------------------------------------------------------- - -#ifndef MAX_PATH - #define MAX_PATH 512 -#endif - -#define FILECONF_TRACE_MASK _T("fileconf") - -// ---------------------------------------------------------------------------- -// global functions declarations -// ---------------------------------------------------------------------------- - -// compare functions for sorting the arrays -static int LINKAGEMODE CompareEntries(wxFileConfigEntry *p1, wxFileConfigEntry *p2); -static int LINKAGEMODE CompareGroups(wxFileConfigGroup *p1, wxFileConfigGroup *p2); - -// filter strings -static wxString FilterInValue(const wxString& str); -static wxString FilterOutValue(const wxString& str); - -static wxString FilterInEntryName(const wxString& str); -static wxString FilterOutEntryName(const wxString& str); - -// get the name to use in wxFileConfig ctor -static wxString GetAppName(const wxString& appname); - -// ============================================================================ -// private classes -// ============================================================================ - -// ---------------------------------------------------------------------------- -// "template" array types -// ---------------------------------------------------------------------------- - -#ifdef WXMAKINGDLL_BASE - WX_DEFINE_SORTED_USER_EXPORTED_ARRAY(wxFileConfigEntry *, ArrayEntries, - WXDLLIMPEXP_BASE); - WX_DEFINE_SORTED_USER_EXPORTED_ARRAY(wxFileConfigGroup *, ArrayGroups, - WXDLLIMPEXP_BASE); -#else - WX_DEFINE_SORTED_ARRAY(wxFileConfigEntry *, ArrayEntries); - WX_DEFINE_SORTED_ARRAY(wxFileConfigGroup *, ArrayGroups); -#endif - -// ---------------------------------------------------------------------------- -// wxFileConfigLineList -// ---------------------------------------------------------------------------- - -// we store all lines of the local config file as a linked list in memory -class wxFileConfigLineList -{ -public: - void SetNext(wxFileConfigLineList *pNext) { m_pNext = pNext; } - void SetPrev(wxFileConfigLineList *pPrev) { m_pPrev = pPrev; } - - // ctor - wxFileConfigLineList(const wxString& str, - wxFileConfigLineList *pNext = NULL) : m_strLine(str) - { SetNext(pNext); SetPrev(NULL); } - - // next/prev nodes in the linked list - wxFileConfigLineList *Next() const { return m_pNext; } - wxFileConfigLineList *Prev() const { return m_pPrev; } - - // get/change lines text - void SetText(const wxString& str) { m_strLine = str; } - const wxString& Text() const { return m_strLine; } - -private: - wxString m_strLine; // line contents - wxFileConfigLineList *m_pNext, // next node - *m_pPrev; // previous one - - DECLARE_NO_COPY_CLASS(wxFileConfigLineList) -}; - -// ---------------------------------------------------------------------------- -// wxFileConfigEntry: a name/value pair -// ---------------------------------------------------------------------------- - -class wxFileConfigEntry -{ -private: - wxFileConfigGroup *m_pParent; // group that contains us - - wxString m_strName, // entry name - m_strValue; // value - bool m_bImmutable:1, // can be overriden locally? - m_bHasValue:1; // set after first call to SetValue() - - int m_nLine; // used if m_pLine == NULL only - - // pointer to our line in the linked list or NULL if it was found in global - // file (which we don't modify) - wxFileConfigLineList *m_pLine; - -public: - wxFileConfigEntry(wxFileConfigGroup *pParent, - const wxString& strName, int nLine); - - // simple accessors - const wxString& Name() const { return m_strName; } - const wxString& Value() const { return m_strValue; } - wxFileConfigGroup *Group() const { return m_pParent; } - bool IsImmutable() const { return m_bImmutable; } - bool IsLocal() const { return m_pLine != 0; } - int Line() const { return m_nLine; } - wxFileConfigLineList * - GetLine() const { return m_pLine; } - - // modify entry attributes - void SetValue(const wxString& strValue, bool bUser = true); - void SetLine(wxFileConfigLineList *pLine); - - DECLARE_NO_COPY_CLASS(wxFileConfigEntry) -}; - -// ---------------------------------------------------------------------------- -// wxFileConfigGroup: container of entries and other groups -// ---------------------------------------------------------------------------- - -class wxFileConfigGroup -{ -private: - wxFileConfig *m_pConfig; // config object we belong to - wxFileConfigGroup *m_pParent; // parent group (NULL for root group) - ArrayEntries m_aEntries; // entries in this group - ArrayGroups m_aSubgroups; // subgroups - wxString m_strName; // group's name - wxFileConfigLineList *m_pLine; // pointer to our line in the linked list - wxFileConfigEntry *m_pLastEntry; // last entry/subgroup of this group in the - wxFileConfigGroup *m_pLastGroup; // local file (we insert new ones after it) - - // DeleteSubgroupByName helper - bool DeleteSubgroup(wxFileConfigGroup *pGroup); - - // used by Rename() - void UpdateGroupAndSubgroupsLines(); - -public: - // ctor - wxFileConfigGroup(wxFileConfigGroup *pParent, const wxString& strName, wxFileConfig *); - - // dtor deletes all entries and subgroups also - ~wxFileConfigGroup(); - - // simple accessors - const wxString& Name() const { return m_strName; } - wxFileConfigGroup *Parent() const { return m_pParent; } - wxFileConfig *Config() const { return m_pConfig; } - - const ArrayEntries& Entries() const { return m_aEntries; } - const ArrayGroups& Groups() const { return m_aSubgroups; } - bool IsEmpty() const { return Entries().IsEmpty() && Groups().IsEmpty(); } - - // find entry/subgroup (NULL if not found) - wxFileConfigGroup *FindSubgroup(const wxChar *szName) const; - wxFileConfigEntry *FindEntry (const wxChar *szName) const; - - // delete entry/subgroup, return false if doesn't exist - bool DeleteSubgroupByName(const wxChar *szName); - bool DeleteEntry(const wxChar *szName); - - // create new entry/subgroup returning pointer to newly created element - wxFileConfigGroup *AddSubgroup(const wxString& strName); - wxFileConfigEntry *AddEntry (const wxString& strName, int nLine = wxNOT_FOUND); - - void SetLine(wxFileConfigLineList *pLine); - - // rename: no checks are done to ensure that the name is unique! - void Rename(const wxString& newName); - - // - wxString GetFullName() const; - - // get the last line belonging to an entry/subgroup of this group - wxFileConfigLineList *GetGroupLine(); // line which contains [group] - // may be NULL for "/" only - wxFileConfigLineList *GetLastEntryLine(); // after which our subgroups start - wxFileConfigLineList *GetLastGroupLine(); // after which the next group starts - - // called by entries/subgroups when they're created/deleted - void SetLastEntry(wxFileConfigEntry *pEntry); - void SetLastGroup(wxFileConfigGroup *pGroup) - { m_pLastGroup = pGroup; } - - DECLARE_NO_COPY_CLASS(wxFileConfigGroup) -}; - -// ============================================================================ -// implementation -// ============================================================================ - -// ---------------------------------------------------------------------------- -// static functions -// ---------------------------------------------------------------------------- -wxString wxFileConfig::GetGlobalDir() -{ - wxString strDir; - -#ifdef __VMS__ // Note if __VMS is defined __UNIX is also defined - strDir = wxT("sys$manager:"); -#elif defined(__WXMAC__) - strDir = wxMacFindFolder( (short) kOnSystemDisk, kPreferencesFolderType, kDontCreateFolder ) ; -#elif defined( __UNIX__ ) - strDir = wxT("/etc/"); -#elif defined(__OS2__) - ULONG aulSysInfo[QSV_MAX] = {0}; - UINT drive; - APIRET rc; - - rc = DosQuerySysInfo( 1L, QSV_MAX, (PVOID)aulSysInfo, sizeof(ULONG)*QSV_MAX); - if (rc == 0) - { - drive = aulSysInfo[QSV_BOOT_DRIVE - 1]; - strDir.Printf(wxT("%c:\\OS2\\"), 'A'+drive-1); - } -#elif defined(__WXSTUBS__) - wxFAIL_MSG( wxT("TODO") ); -#elif defined(__DOS__) - // There's no such thing as global cfg dir in MS-DOS, let's return - // current directory (FIXME_MGL?) - strDir = wxT(".\\"); -#elif defined(__WXWINCE__) - strDir = wxT("\\Windows\\"); -#else // Windows - - wxChar szWinDir[MAX_PATH]; - ::GetWindowsDirectory(szWinDir, MAX_PATH); - - strDir = szWinDir; - strDir << wxT('\\'); -#endif // Unix/Windows - - return strDir; -} - -wxString wxFileConfig::GetLocalDir() -{ - wxString strDir; - -#if defined(__WXMAC__) || defined(__DOS__) - // no local dir concept on Mac OS 9 or MS-DOS - strDir << GetGlobalDir() ; -#else - wxGetHomeDir(&strDir); - - #ifdef __UNIX__ - if ( - (strDir.Last() != wxT('/')) - #ifdef __VMS - && (strDir.Last() != wxT(']')) - #endif - ) - strDir << wxT('/'); - #else - if (strDir.Last() != wxT('\\')) - strDir << wxT('\\'); - #endif -#endif - - return strDir; -} - -wxString wxFileConfig::GetGlobalFileName(const wxChar *szFile) -{ - wxString str = GetGlobalDir(); - str << szFile; - - if ( wxStrchr(szFile, wxT('.')) == NULL ) -#if defined( __WXMAC__ ) - str << wxT(" Preferences") ; -#elif defined( __UNIX__ ) - str << wxT(".conf"); -#else // Windows - str << wxT(".ini"); -#endif // UNIX/Win - - return str; -} - -wxString wxFileConfig::GetLocalFileName(const wxChar *szFile) -{ -#ifdef __VMS__ - // On VMS I saw the problem that the home directory was appended - // twice for the configuration file. Does that also happen for - // other platforms? - wxString str = wxT( '.' ); -#else - wxString str = GetLocalDir(); -#endif - -#if defined( __UNIX__ ) && !defined( __VMS ) && !defined( __WXMAC__ ) - str << wxT('.'); -#endif - - str << szFile; - -#if defined(__WINDOWS__) || defined(__DOS__) - if ( wxStrchr(szFile, wxT('.')) == NULL ) - str << wxT(".ini"); -#endif - -#ifdef __WXMAC__ - str << wxT(" Preferences") ; -#endif - - return str; -} - -// ---------------------------------------------------------------------------- -// ctor -// ---------------------------------------------------------------------------- - -void wxFileConfig::Init() -{ - m_pCurrentGroup = - m_pRootGroup = new wxFileConfigGroup(NULL, wxEmptyString, this); - - m_linesHead = - m_linesTail = NULL; - - // It's not an error if (one of the) file(s) doesn't exist. - - // parse the global file - if ( !m_strGlobalFile.empty() && wxFile::Exists(m_strGlobalFile) ) - { - wxTextFile fileGlobal(m_strGlobalFile); - - if ( fileGlobal.Open(*m_conv/*ignored in ANSI build*/) ) - { - Parse(fileGlobal, false /* global */); - SetRootPath(); - } - else - { - wxLogWarning(_("can't open global configuration file '%s'."), m_strGlobalFile.c_str()); - } - } - - // parse the local file - if ( !m_strLocalFile.empty() && wxFile::Exists(m_strLocalFile) ) - { - wxTextFile fileLocal(m_strLocalFile); - if ( fileLocal.Open(*m_conv/*ignored in ANSI build*/) ) - { - Parse(fileLocal, true /* local */); - SetRootPath(); - } - else - { - wxLogWarning(_("can't open user configuration file '%s'."), m_strLocalFile.c_str() ); - } - } - - m_isDirty = false; -} - -// constructor supports creation of wxFileConfig objects of any type -wxFileConfig::wxFileConfig(const wxString& appName, const wxString& vendorName, - const wxString& strLocal, const wxString& strGlobal, - long style, - const wxMBConv& conv) - : wxConfigBase(::GetAppName(appName), vendorName, - strLocal, strGlobal, - style), - m_strLocalFile(strLocal), m_strGlobalFile(strGlobal), - m_conv(conv.Clone()) -{ - // Make up names for files if empty - if ( m_strLocalFile.empty() && (style & wxCONFIG_USE_LOCAL_FILE) ) - { - m_strLocalFile = GetLocalFileName(GetAppName()); -#if defined(__UNIX__) && !defined(__VMS) - if ( style & wxCONFIG_USE_SUBDIR ) - m_strLocalFile << wxFILE_SEP_PATH << GetAppName() << _T(".conf"); -#endif - } - - if ( m_strGlobalFile.empty() && (style & wxCONFIG_USE_GLOBAL_FILE) ) - m_strGlobalFile = GetGlobalFileName(GetAppName()); - - // Check if styles are not supplied, but filenames are, in which case - // add the correct styles. - if ( !m_strLocalFile.empty() ) - SetStyle(GetStyle() | wxCONFIG_USE_LOCAL_FILE); - - if ( !m_strGlobalFile.empty() ) - SetStyle(GetStyle() | wxCONFIG_USE_GLOBAL_FILE); - - // if the path is not absolute, prepend the standard directory to it - // UNLESS wxCONFIG_USE_RELATIVE_PATH style is set - if ( !(style & wxCONFIG_USE_RELATIVE_PATH) ) - { - if ( !m_strLocalFile.empty() && !wxIsAbsolutePath(m_strLocalFile) ) - { - const wxString strLocalOrig = m_strLocalFile; - m_strLocalFile = GetLocalDir(); - m_strLocalFile << strLocalOrig; - } - - if ( !m_strGlobalFile.empty() && !wxIsAbsolutePath(m_strGlobalFile) ) - { - const wxString strGlobalOrig = m_strGlobalFile; - m_strGlobalFile = GetGlobalDir(); - m_strGlobalFile << strGlobalOrig; - } - } - - SetUmask(-1); - - Init(); -} - -#if wxUSE_STREAMS - -wxFileConfig::wxFileConfig(wxInputStream &inStream, const wxMBConv& conv) - : m_conv(conv.Clone()) -{ - // always local_file when this constructor is called (?) - SetStyle(GetStyle() | wxCONFIG_USE_LOCAL_FILE); - - m_pCurrentGroup = - m_pRootGroup = new wxFileConfigGroup(NULL, wxEmptyString, this); - - m_linesHead = - m_linesTail = NULL; - - // read the entire stream contents in memory - wxString str; - { - static const size_t chunkLen = 1024; - - wxMemoryBuffer buf(chunkLen); - do - { - inStream.Read(buf.GetAppendBuf(chunkLen), chunkLen); - buf.UngetAppendBuf(inStream.LastRead()); - - const wxStreamError err = inStream.GetLastError(); - - if ( err != wxSTREAM_NO_ERROR && err != wxSTREAM_EOF ) - { - wxLogError(_("Error reading config options.")); - break; - } - } - while ( !inStream.Eof() ); - -#if wxUSE_UNICODE - size_t len; - str = conv.cMB2WC((char *)buf.GetData(), buf.GetDataLen(), &len); - if ( !len && buf.GetDataLen() ) - { - wxLogError(_("Failed to read config options.")); - } -#else // !wxUSE_UNICODE - // no need for conversion - str.assign((char *)buf.GetData(), buf.GetDataLen()); -#endif // wxUSE_UNICODE/!wxUSE_UNICODE - } - - - // translate everything to the current (platform-dependent) line - // termination character - str = wxTextBuffer::Translate(str); - - wxMemoryText memText; - - // Now we can add the text to the memory text. To do this we extract line - // by line from the translated string, until we've reached the end. - // - // VZ: all this is horribly inefficient, we should do the translation on - // the fly in one pass saving both memory and time (TODO) - - const wxChar *pEOL = wxTextBuffer::GetEOL(wxTextBuffer::typeDefault); - const size_t EOLLen = wxStrlen(pEOL); - - int posLineStart = str.Find(pEOL); - while ( posLineStart != -1 ) - { - wxString line(str.Left(posLineStart)); - - memText.AddLine(line); - - str = str.Mid(posLineStart + EOLLen); - - posLineStart = str.Find(pEOL); - } - - // also add whatever we have left in the translated string. - if ( !str.empty() ) - memText.AddLine(str); - - // Finally we can parse it all. - Parse(memText, true /* local */); - - SetRootPath(); - ResetDirty(); -} - -#endif // wxUSE_STREAMS - -void wxFileConfig::CleanUp() -{ - delete m_pRootGroup; - - wxFileConfigLineList *pCur = m_linesHead; - while ( pCur != NULL ) { - wxFileConfigLineList *pNext = pCur->Next(); - delete pCur; - pCur = pNext; - } -} - -wxFileConfig::~wxFileConfig() -{ - Flush(); - - CleanUp(); - - delete m_conv; -} - -// ---------------------------------------------------------------------------- -// parse a config file -// ---------------------------------------------------------------------------- - -void wxFileConfig::Parse(const wxTextBuffer& buffer, bool bLocal) -{ - const wxChar *pStart; - const wxChar *pEnd; - wxString strLine; - - size_t nLineCount = buffer.GetLineCount(); - - for ( size_t n = 0; n < nLineCount; n++ ) - { - strLine = buffer[n]; - - // add the line to linked list - if ( bLocal ) - LineListAppend(strLine); - - - // skip leading spaces - for ( pStart = strLine; wxIsspace(*pStart); pStart++ ) - ; - - // skip blank/comment lines - if ( *pStart == wxT('\0')|| *pStart == wxT(';') || *pStart == wxT('#') ) - continue; - - if ( *pStart == wxT('[') ) { // a new group - pEnd = pStart; - - while ( *++pEnd != wxT(']') ) { - if ( *pEnd == wxT('\\') ) { - // the next char is escaped, so skip it even if it is ']' - pEnd++; - } - - if ( *pEnd == wxT('\n') || *pEnd == wxT('\0') ) { - // we reached the end of line, break out of the loop - break; - } - } - - if ( *pEnd != wxT(']') ) { - wxLogError(_("file '%s': unexpected character %c at line %d."), - buffer.GetName(), *pEnd, n + 1); - continue; // skip this line - } - - // group name here is always considered as abs path - wxString strGroup; - pStart++; - strGroup << wxCONFIG_PATH_SEPARATOR - << FilterInEntryName(wxString(pStart, pEnd - pStart)); - - // will create it if doesn't yet exist - SetPath(strGroup); - - if ( bLocal ) - { - if ( m_pCurrentGroup->Parent() ) - m_pCurrentGroup->Parent()->SetLastGroup(m_pCurrentGroup); - m_pCurrentGroup->SetLine(m_linesTail); - } - - // check that there is nothing except comments left on this line - bool bCont = true; - while ( *++pEnd != wxT('\0') && bCont ) { - switch ( *pEnd ) { - case wxT('#'): - case wxT(';'): - bCont = false; - break; - - case wxT(' '): - case wxT('\t'): - // ignore whitespace ('\n' impossible here) - break; - - default: - wxLogWarning(_("file '%s', line %d: '%s' ignored after group header."), - buffer.GetName(), n + 1, pEnd); - bCont = false; - } - } - } - else { // a key - pEnd = pStart; - while ( *pEnd && *pEnd != wxT('=') /* && !wxIsspace(*pEnd)*/ ) { - if ( *pEnd == wxT('\\') ) { - // next character may be space or not - still take it because it's - // quoted (unless there is nothing) - pEnd++; - if ( !*pEnd ) { - // the error message will be given below anyhow - break; - } - } - - pEnd++; - } - - wxString strKey(FilterInEntryName(wxString(pStart, pEnd).Trim())); - - // skip whitespace - while ( wxIsspace(*pEnd) ) - pEnd++; - - if ( *pEnd++ != wxT('=') ) { - wxLogError(_("file '%s', line %d: '=' expected."), - buffer.GetName(), n + 1); - } - else { - wxFileConfigEntry *pEntry = m_pCurrentGroup->FindEntry(strKey); - - if ( pEntry == NULL ) { - // new entry - pEntry = m_pCurrentGroup->AddEntry(strKey, n); - } - else { - if ( bLocal && pEntry->IsImmutable() ) { - // immutable keys can't be changed by user - wxLogWarning(_("file '%s', line %d: value for immutable key '%s' ignored."), - buffer.GetName(), n + 1, strKey.c_str()); - continue; - } - // the condition below catches the cases (a) and (b) but not (c): - // (a) global key found second time in global file - // (b) key found second (or more) time in local file - // (c) key from global file now found in local one - // which is exactly what we want. - else if ( !bLocal || pEntry->IsLocal() ) { - wxLogWarning(_("file '%s', line %d: key '%s' was first found at line %d."), - buffer.GetName(), n + 1, strKey.c_str(), pEntry->Line()); - - } - } - - if ( bLocal ) - pEntry->SetLine(m_linesTail); - - // skip whitespace - while ( wxIsspace(*pEnd) ) - pEnd++; - - wxString value = pEnd; - if ( !(GetStyle() & wxCONFIG_USE_NO_ESCAPE_CHARACTERS) ) - value = FilterInValue(value); - - pEntry->SetValue(value, false); - } - } - } -} - -// ---------------------------------------------------------------------------- -// set/retrieve path -// ---------------------------------------------------------------------------- - -void wxFileConfig::SetRootPath() -{ - m_strPath.Empty(); - m_pCurrentGroup = m_pRootGroup; -} - -bool -wxFileConfig::DoSetPath(const wxString& strPath, bool createMissingComponents) -{ - wxArrayString aParts; - - if ( strPath.empty() ) { - SetRootPath(); - return true; - } - - if ( strPath[0] == wxCONFIG_PATH_SEPARATOR ) { - // absolute path - wxSplitPath(aParts, strPath); - } - else { - // relative path, combine with current one - wxString strFullPath = m_strPath; - strFullPath << wxCONFIG_PATH_SEPARATOR << strPath; - wxSplitPath(aParts, strFullPath); - } - - // change current group - size_t n; - m_pCurrentGroup = m_pRootGroup; - for ( n = 0; n < aParts.Count(); n++ ) { - wxFileConfigGroup *pNextGroup = m_pCurrentGroup->FindSubgroup(aParts[n]); - if ( pNextGroup == NULL ) - { - if ( !createMissingComponents ) - return false; - - pNextGroup = m_pCurrentGroup->AddSubgroup(aParts[n]); - } - - m_pCurrentGroup = pNextGroup; - } - - // recombine path parts in one variable - m_strPath.Empty(); - for ( n = 0; n < aParts.Count(); n++ ) { - m_strPath << wxCONFIG_PATH_SEPARATOR << aParts[n]; - } - - return true; -} - -void wxFileConfig::SetPath(const wxString& strPath) -{ - DoSetPath(strPath, true /* create missing path components */); -} - -// ---------------------------------------------------------------------------- -// enumeration -// ---------------------------------------------------------------------------- - -bool wxFileConfig::GetFirstGroup(wxString& str, long& lIndex) const -{ - lIndex = 0; - return GetNextGroup(str, lIndex); -} - -bool wxFileConfig::GetNextGroup (wxString& str, long& lIndex) const -{ - if ( size_t(lIndex) < m_pCurrentGroup->Groups().Count() ) { - str = m_pCurrentGroup->Groups()[(size_t)lIndex++]->Name(); - return true; - } - else - return false; -} - -bool wxFileConfig::GetFirstEntry(wxString& str, long& lIndex) const -{ - lIndex = 0; - return GetNextEntry(str, lIndex); -} - -bool wxFileConfig::GetNextEntry (wxString& str, long& lIndex) const -{ - if ( size_t(lIndex) < m_pCurrentGroup->Entries().Count() ) { - str = m_pCurrentGroup->Entries()[(size_t)lIndex++]->Name(); - return true; - } - else - return false; -} - -size_t wxFileConfig::GetNumberOfEntries(bool bRecursive) const -{ - size_t n = m_pCurrentGroup->Entries().Count(); - if ( bRecursive ) { - wxFileConfigGroup *pOldCurrentGroup = m_pCurrentGroup; - size_t nSubgroups = m_pCurrentGroup->Groups().Count(); - for ( size_t nGroup = 0; nGroup < nSubgroups; nGroup++ ) { - CONST_CAST m_pCurrentGroup = m_pCurrentGroup->Groups()[nGroup]; - n += GetNumberOfEntries(true); - CONST_CAST m_pCurrentGroup = pOldCurrentGroup; - } - } - - return n; -} - -size_t wxFileConfig::GetNumberOfGroups(bool bRecursive) const -{ - size_t n = m_pCurrentGroup->Groups().Count(); - if ( bRecursive ) { - wxFileConfigGroup *pOldCurrentGroup = m_pCurrentGroup; - size_t nSubgroups = m_pCurrentGroup->Groups().Count(); - for ( size_t nGroup = 0; nGroup < nSubgroups; nGroup++ ) { - CONST_CAST m_pCurrentGroup = m_pCurrentGroup->Groups()[nGroup]; - n += GetNumberOfGroups(true); - CONST_CAST m_pCurrentGroup = pOldCurrentGroup; - } - } - - return n; -} - -// ---------------------------------------------------------------------------- -// tests for existence -// ---------------------------------------------------------------------------- - -bool wxFileConfig::HasGroup(const wxString& strName) const -{ - // special case: DoSetPath("") does work as it's equivalent to DoSetPath("/") - // but there is no group with empty name so treat this separately - if ( strName.empty() ) - return false; - - const wxString pathOld = GetPath(); - - wxFileConfig *self = wx_const_cast(wxFileConfig *, this); - const bool - rc = self->DoSetPath(strName, false /* don't create missing components */); - - self->SetPath(pathOld); - - return rc; -} - -bool wxFileConfig::HasEntry(const wxString& entry) const -{ - // path is the part before the last "/" - wxString path = entry.BeforeLast(wxCONFIG_PATH_SEPARATOR); - - // except in the special case of "/keyname" when there is nothing before "/" - if ( path.empty() && *entry.c_str() == wxCONFIG_PATH_SEPARATOR ) - { - path = wxCONFIG_PATH_SEPARATOR; - } - - // change to the path of the entry if necessary and remember the old path - // to restore it later - wxString pathOld; - wxFileConfig * const self = wx_const_cast(wxFileConfig *, this); - if ( !path.empty() ) - { - pathOld = GetPath(); - if ( pathOld.empty() ) - pathOld = wxCONFIG_PATH_SEPARATOR; - - if ( !self->DoSetPath(path, false /* don't create if doesn't exist */) ) - { - return false; - } - } - - // check if the entry exists in this group - const bool exists = m_pCurrentGroup->FindEntry( - entry.AfterLast(wxCONFIG_PATH_SEPARATOR)) != NULL; - - // restore the old path if we changed it above - if ( !pathOld.empty() ) - { - self->SetPath(pathOld); - } - - return exists; -} - -// ---------------------------------------------------------------------------- -// read/write values -// ---------------------------------------------------------------------------- - -bool wxFileConfig::DoReadString(const wxString& key, wxString* pStr) const -{ - wxConfigPathChanger path(this, key); - - wxFileConfigEntry *pEntry = m_pCurrentGroup->FindEntry(path.Name()); - if (pEntry == NULL) { - return false; - } - - *pStr = pEntry->Value(); - - return true; -} - -bool wxFileConfig::DoReadLong(const wxString& key, long *pl) const -{ - wxString str; - if ( !Read(key, &str) ) - return false; - - // extra spaces shouldn't prevent us from reading numeric values - str.Trim(); - - return str.ToLong(pl); -} - -bool wxFileConfig::DoWriteString(const wxString& key, const wxString& szValue) -{ - wxConfigPathChanger path(this, key); - wxString strName = path.Name(); - - wxLogTrace( FILECONF_TRACE_MASK, - _T(" Writing String '%s' = '%s' to Group '%s'"), - strName.c_str(), - szValue.c_str(), - GetPath().c_str() ); - - if ( strName.empty() ) - { - // setting the value of a group is an error - - wxASSERT_MSG( szValue.empty(), wxT("can't set value of a group!") ); - - // ... except if it's empty in which case it's a way to force it's creation - - wxLogTrace( FILECONF_TRACE_MASK, - _T(" Creating group %s"), - m_pCurrentGroup->Name().c_str() ); - - SetDirty(); - - // this will add a line for this group if it didn't have it before (or - // do nothing for the root but it's ok as it always exists anyhow) - (void)m_pCurrentGroup->GetGroupLine(); - } - else - { - // writing an entry check that the name is reasonable - if ( strName[0u] == wxCONFIG_IMMUTABLE_PREFIX ) - { - wxLogError( _("Config entry name cannot start with '%c'."), - wxCONFIG_IMMUTABLE_PREFIX); - return false; - } - - wxFileConfigEntry *pEntry = m_pCurrentGroup->FindEntry(strName); - - if ( pEntry == 0 ) - { - wxLogTrace( FILECONF_TRACE_MASK, - _T(" Adding Entry %s"), - strName.c_str() ); - pEntry = m_pCurrentGroup->AddEntry(strName); - } - - wxLogTrace( FILECONF_TRACE_MASK, - _T(" Setting value %s"), - szValue.c_str() ); - pEntry->SetValue(szValue); - - SetDirty(); - } - - return true; -} - -bool wxFileConfig::DoWriteLong(const wxString& key, long lValue) -{ - return Write(key, wxString::Format(_T("%ld"), lValue)); -} - -bool wxFileConfig::Flush(bool /* bCurrentOnly */) -{ - if ( !IsDirty() || !m_strLocalFile ) - return true; - - // set the umask if needed - wxCHANGE_UMASK(m_umask); - - wxTempFile file(m_strLocalFile); - - if ( !file.IsOpened() ) - { - wxLogError(_("can't open user configuration file.")); - return false; - } - - // write all strings to file - wxString filetext; - filetext.reserve(4096); - for ( wxFileConfigLineList *p = m_linesHead; p != NULL; p = p->Next() ) - { - filetext << p->Text() << wxTextFile::GetEOL(); - } - - if ( !file.Write(filetext, *m_conv) ) - { - wxLogError(_("can't write user configuration file.")); - return false; - } - - if ( !file.Commit() ) - { - wxLogError(_("Failed to update user configuration file.")); - - return false; - } - - ResetDirty(); - -#if defined(__WXMAC__) - wxFileName(m_strLocalFile).MacSetTypeAndCreator('TEXT', 'ttxt'); -#endif // __WXMAC__ - - return true; -} - -#if wxUSE_STREAMS - -bool wxFileConfig::Save(wxOutputStream& os, const wxMBConv& conv) -{ - // save unconditionally, even if not dirty - for ( wxFileConfigLineList *p = m_linesHead; p != NULL; p = p->Next() ) - { - wxString line = p->Text(); - line += wxTextFile::GetEOL(); - - wxCharBuffer buf(line.mb_str(conv)); - if ( !os.Write(buf, strlen(buf)) ) - { - wxLogError(_("Error saving user configuration data.")); - - return false; - } - } - - ResetDirty(); - - return true; -} - -#endif // wxUSE_STREAMS - -// ---------------------------------------------------------------------------- -// renaming groups/entries -// ---------------------------------------------------------------------------- - -bool wxFileConfig::RenameEntry(const wxString& oldName, - const wxString& newName) -{ - wxASSERT_MSG( !wxStrchr(oldName, wxCONFIG_PATH_SEPARATOR), - _T("RenameEntry(): paths are not supported") ); - - // check that the entry exists - wxFileConfigEntry *oldEntry = m_pCurrentGroup->FindEntry(oldName); - if ( !oldEntry ) - return false; - - // check that the new entry doesn't already exist - if ( m_pCurrentGroup->FindEntry(newName) ) - return false; - - // delete the old entry, create the new one - wxString value = oldEntry->Value(); - if ( !m_pCurrentGroup->DeleteEntry(oldName) ) - return false; - - SetDirty(); - - wxFileConfigEntry *newEntry = m_pCurrentGroup->AddEntry(newName); - newEntry->SetValue(value); - - return true; -} - -bool wxFileConfig::RenameGroup(const wxString& oldName, - const wxString& newName) -{ - // check that the group exists - wxFileConfigGroup *group = m_pCurrentGroup->FindSubgroup(oldName); - if ( !group ) - return false; - - // check that the new group doesn't already exist - if ( m_pCurrentGroup->FindSubgroup(newName) ) - return false; - - group->Rename(newName); - - SetDirty(); - - return true; -} - -// ---------------------------------------------------------------------------- -// delete groups/entries -// ---------------------------------------------------------------------------- - -bool wxFileConfig::DeleteEntry(const wxString& key, bool bGroupIfEmptyAlso) -{ - wxConfigPathChanger path(this, key); - - if ( !m_pCurrentGroup->DeleteEntry(path.Name()) ) - return false; - - SetDirty(); - - if ( bGroupIfEmptyAlso && m_pCurrentGroup->IsEmpty() ) { - if ( m_pCurrentGroup != m_pRootGroup ) { - wxFileConfigGroup *pGroup = m_pCurrentGroup; - SetPath(wxT("..")); // changes m_pCurrentGroup! - m_pCurrentGroup->DeleteSubgroupByName(pGroup->Name()); - } - //else: never delete the root group - } - - return true; -} - -bool wxFileConfig::DeleteGroup(const wxString& key) -{ - wxConfigPathChanger path(this, RemoveTrailingSeparator(key)); - - if ( !m_pCurrentGroup->DeleteSubgroupByName(path.Name()) ) - return false; - - path.UpdateIfDeleted(); - - SetDirty(); - - return true; -} - -bool wxFileConfig::DeleteAll() -{ - CleanUp(); - - if ( !m_strLocalFile.empty() ) - { - if ( wxFile::Exists(m_strLocalFile) && wxRemove(m_strLocalFile) == -1 ) - { - wxLogSysError(_("can't delete user configuration file '%s'"), - m_strLocalFile.c_str()); - return false; - } - } - - Init(); - - return true; -} - -// ---------------------------------------------------------------------------- -// linked list functions -// ---------------------------------------------------------------------------- - - // append a new line to the end of the list - -wxFileConfigLineList *wxFileConfig::LineListAppend(const wxString& str) -{ - wxLogTrace( FILECONF_TRACE_MASK, - _T(" ** Adding Line '%s'"), - str.c_str() ); - wxLogTrace( FILECONF_TRACE_MASK, - _T(" head: %s"), - ((m_linesHead) ? m_linesHead->Text().c_str() : wxEmptyString) ); - wxLogTrace( FILECONF_TRACE_MASK, - _T(" tail: %s"), - ((m_linesTail) ? m_linesTail->Text().c_str() : wxEmptyString) ); - - wxFileConfigLineList *pLine = new wxFileConfigLineList(str); - - if ( m_linesTail == NULL ) - { - // list is empty - m_linesHead = pLine; - } - else - { - // adjust pointers - m_linesTail->SetNext(pLine); - pLine->SetPrev(m_linesTail); - } - - m_linesTail = pLine; - - wxLogTrace( FILECONF_TRACE_MASK, - _T(" head: %s"), - ((m_linesHead) ? m_linesHead->Text().c_str() : wxEmptyString) ); - wxLogTrace( FILECONF_TRACE_MASK, - _T(" tail: %s"), - ((m_linesTail) ? m_linesTail->Text().c_str() : wxEmptyString) ); - - return m_linesTail; -} - -// insert a new line after the given one or in the very beginning if !pLine -wxFileConfigLineList *wxFileConfig::LineListInsert(const wxString& str, - wxFileConfigLineList *pLine) -{ - wxLogTrace( FILECONF_TRACE_MASK, - _T(" ** Inserting Line '%s' after '%s'"), - str.c_str(), - ((pLine) ? pLine->Text().c_str() : wxEmptyString) ); - wxLogTrace( FILECONF_TRACE_MASK, - _T(" head: %s"), - ((m_linesHead) ? m_linesHead->Text().c_str() : wxEmptyString) ); - wxLogTrace( FILECONF_TRACE_MASK, - _T(" tail: %s"), - ((m_linesTail) ? m_linesTail->Text().c_str() : wxEmptyString) ); - - if ( pLine == m_linesTail ) - return LineListAppend(str); - - wxFileConfigLineList *pNewLine = new wxFileConfigLineList(str); - if ( pLine == NULL ) - { - // prepend to the list - pNewLine->SetNext(m_linesHead); - m_linesHead->SetPrev(pNewLine); - m_linesHead = pNewLine; - } - else - { - // insert before pLine - wxFileConfigLineList *pNext = pLine->Next(); - pNewLine->SetNext(pNext); - pNewLine->SetPrev(pLine); - pNext->SetPrev(pNewLine); - pLine->SetNext(pNewLine); - } - - wxLogTrace( FILECONF_TRACE_MASK, - _T(" head: %s"), - ((m_linesHead) ? m_linesHead->Text().c_str() : wxEmptyString) ); - wxLogTrace( FILECONF_TRACE_MASK, - _T(" tail: %s"), - ((m_linesTail) ? m_linesTail->Text().c_str() : wxEmptyString) ); - - return pNewLine; -} - -void wxFileConfig::LineListRemove(wxFileConfigLineList *pLine) -{ - wxLogTrace( FILECONF_TRACE_MASK, - _T(" ** Removing Line '%s'"), - pLine->Text().c_str() ); - wxLogTrace( FILECONF_TRACE_MASK, - _T(" head: %s"), - ((m_linesHead) ? m_linesHead->Text().c_str() : wxEmptyString) ); - wxLogTrace( FILECONF_TRACE_MASK, - _T(" tail: %s"), - ((m_linesTail) ? m_linesTail->Text().c_str() : wxEmptyString) ); - - wxFileConfigLineList *pPrev = pLine->Prev(), - *pNext = pLine->Next(); - - // first entry? - - if ( pPrev == NULL ) - m_linesHead = pNext; - else - pPrev->SetNext(pNext); - - // last entry? - - if ( pNext == NULL ) - m_linesTail = pPrev; - else - pNext->SetPrev(pPrev); - - if ( m_pRootGroup->GetGroupLine() == pLine ) - m_pRootGroup->SetLine(m_linesHead); - - wxLogTrace( FILECONF_TRACE_MASK, - _T(" head: %s"), - ((m_linesHead) ? m_linesHead->Text().c_str() : wxEmptyString) ); - wxLogTrace( FILECONF_TRACE_MASK, - _T(" tail: %s"), - ((m_linesTail) ? m_linesTail->Text().c_str() : wxEmptyString) ); - - delete pLine; -} - -bool wxFileConfig::LineListIsEmpty() -{ - return m_linesHead == NULL; -} - -// ============================================================================ -// wxFileConfig::wxFileConfigGroup -// ============================================================================ - -// ---------------------------------------------------------------------------- -// ctor/dtor -// ---------------------------------------------------------------------------- - -// ctor -wxFileConfigGroup::wxFileConfigGroup(wxFileConfigGroup *pParent, - const wxString& strName, - wxFileConfig *pConfig) - : m_aEntries(CompareEntries), - m_aSubgroups(CompareGroups), - m_strName(strName) -{ - m_pConfig = pConfig; - m_pParent = pParent; - m_pLine = NULL; - - m_pLastEntry = NULL; - m_pLastGroup = NULL; -} - -// dtor deletes all children -wxFileConfigGroup::~wxFileConfigGroup() -{ - // entries - size_t n, nCount = m_aEntries.Count(); - for ( n = 0; n < nCount; n++ ) - delete m_aEntries[n]; - - // subgroups - nCount = m_aSubgroups.Count(); - for ( n = 0; n < nCount; n++ ) - delete m_aSubgroups[n]; -} - -// ---------------------------------------------------------------------------- -// line -// ---------------------------------------------------------------------------- - -void wxFileConfigGroup::SetLine(wxFileConfigLineList *pLine) -{ - // for a normal (i.e. not root) group this method shouldn't be called twice - // unless we are resetting the line - wxASSERT_MSG( !m_pParent || !m_pLine || !pLine, - _T("changing line for a non-root group?") ); - - m_pLine = pLine; -} - -/* - This is a bit complicated, so let me explain it in details. All lines that - were read from the local file (the only one we will ever modify) are stored - in a (doubly) linked list. Our problem is to know at which position in this - list should we insert the new entries/subgroups. To solve it we keep three - variables for each group: m_pLine, m_pLastEntry and m_pLastGroup. - - m_pLine points to the line containing "[group_name]" - m_pLastEntry points to the last entry of this group in the local file. - m_pLastGroup subgroup - - Initially, they're NULL all three. When the group (an entry/subgroup) is read - from the local file, the corresponding variable is set. However, if the group - was read from the global file and then modified or created by the application - these variables are still NULL and we need to create the corresponding lines. - See the following functions (and comments preceding them) for the details of - how we do it. - - Also, when our last entry/group are deleted we need to find the new last - element - the code in DeleteEntry/Subgroup does this by backtracking the list - of lines until it either founds an entry/subgroup (and this is the new last - element) or the m_pLine of the group, in which case there are no more entries - (or subgroups) left and m_pLast becomes NULL. - - NB: This last problem could be avoided for entries if we added new entries - immediately after m_pLine, but in this case the entries would appear - backwards in the config file (OTOH, it's not that important) and as we - would still need to do it for the subgroups the code wouldn't have been - significantly less complicated. -*/ - -// Return the line which contains "[our name]". If we're still not in the list, -// add our line to it immediately after the last line of our parent group if we -// have it or in the very beginning if we're the root group. -wxFileConfigLineList *wxFileConfigGroup::GetGroupLine() -{ - wxLogTrace( FILECONF_TRACE_MASK, - _T(" GetGroupLine() for Group '%s'"), - Name().c_str() ); - - if ( !m_pLine ) - { - wxLogTrace( FILECONF_TRACE_MASK, - _T(" Getting Line item pointer") ); - - wxFileConfigGroup *pParent = Parent(); - - // this group wasn't present in local config file, add it now - if ( pParent ) - { - wxLogTrace( FILECONF_TRACE_MASK, - _T(" checking parent '%s'"), - pParent->Name().c_str() ); - - wxString strFullName; - - // add 1 to the name because we don't want to start with '/' - strFullName << wxT("[") - << FilterOutEntryName(GetFullName().c_str() + 1) - << wxT("]"); - m_pLine = m_pConfig->LineListInsert(strFullName, - pParent->GetLastGroupLine()); - pParent->SetLastGroup(this); // we're surely after all the others - } - //else: this is the root group and so we return NULL because we don't - // have any group line - } - - return m_pLine; -} - -// Return the last line belonging to the subgroups of this group (after which -// we can add a new subgroup), if we don't have any subgroups or entries our -// last line is the group line (m_pLine) itself. -wxFileConfigLineList *wxFileConfigGroup::GetLastGroupLine() -{ - // if we have any subgroups, our last line is the last line of the last - // subgroup - if ( m_pLastGroup ) - { - wxFileConfigLineList *pLine = m_pLastGroup->GetLastGroupLine(); - - wxASSERT_MSG( pLine, _T("last group must have !NULL associated line") ); - - return pLine; - } - - // no subgroups, so the last line is the line of thelast entry (if any) - return GetLastEntryLine(); -} - -// return the last line belonging to the entries of this group (after which -// we can add a new entry), if we don't have any entries we will add the new -// one immediately after the group line itself. -wxFileConfigLineList *wxFileConfigGroup::GetLastEntryLine() -{ - wxLogTrace( FILECONF_TRACE_MASK, - _T(" GetLastEntryLine() for Group '%s'"), - Name().c_str() ); - - if ( m_pLastEntry ) - { - wxFileConfigLineList *pLine = m_pLastEntry->GetLine(); - - wxASSERT_MSG( pLine, _T("last entry must have !NULL associated line") ); - - return pLine; - } - - // no entries: insert after the group header, if any - return GetGroupLine(); -} - -void wxFileConfigGroup::SetLastEntry(wxFileConfigEntry *pEntry) -{ - m_pLastEntry = pEntry; - - if ( !m_pLine ) - { - // the only situation in which a group without its own line can have - // an entry is when the first entry is added to the initially empty - // root pseudo-group - wxASSERT_MSG( !m_pParent, _T("unexpected for non root group") ); - - // let the group know that it does have a line in the file now - m_pLine = pEntry->GetLine(); - } -} - -// ---------------------------------------------------------------------------- -// group name -// ---------------------------------------------------------------------------- - -void wxFileConfigGroup::UpdateGroupAndSubgroupsLines() -{ - // update the line of this group - wxFileConfigLineList *line = GetGroupLine(); - wxCHECK_RET( line, _T("a non root group must have a corresponding line!") ); - - // +1: skip the leading '/' - line->SetText(wxString::Format(_T("[%s]"), GetFullName().c_str() + 1)); - - - // also update all subgroups as they have this groups name in their lines - const size_t nCount = m_aSubgroups.Count(); - for ( size_t n = 0; n < nCount; n++ ) - { - m_aSubgroups[n]->UpdateGroupAndSubgroupsLines(); - } -} - -void wxFileConfigGroup::Rename(const wxString& newName) -{ - wxCHECK_RET( m_pParent, _T("the root group can't be renamed") ); - - if ( newName == m_strName ) - return; - - // we need to remove the group from the parent and it back under the new - // name to keep the parents array of subgroups alphabetically sorted - m_pParent->m_aSubgroups.Remove(this); - - m_strName = newName; - - m_pParent->m_aSubgroups.Add(this); - - // update the group lines recursively - UpdateGroupAndSubgroupsLines(); -} - -wxString wxFileConfigGroup::GetFullName() const -{ - wxString fullname; - if ( Parent() ) - fullname = Parent()->GetFullName() + wxCONFIG_PATH_SEPARATOR + Name(); - - return fullname; -} - -// ---------------------------------------------------------------------------- -// find an item -// ---------------------------------------------------------------------------- - -// use binary search because the array is sorted -wxFileConfigEntry * -wxFileConfigGroup::FindEntry(const wxChar *szName) const -{ - size_t i, - lo = 0, - hi = m_aEntries.Count(); - int res; - wxFileConfigEntry *pEntry; - - while ( lo < hi ) { - i = (lo + hi)/2; - pEntry = m_aEntries[i]; - - #if wxCONFIG_CASE_SENSITIVE - res = wxStrcmp(pEntry->Name(), szName); - #else - res = wxStricmp(pEntry->Name(), szName); - #endif - - if ( res > 0 ) - hi = i; - else if ( res < 0 ) - lo = i + 1; - else - return pEntry; - } - - return NULL; -} - -wxFileConfigGroup * -wxFileConfigGroup::FindSubgroup(const wxChar *szName) const -{ - size_t i, - lo = 0, - hi = m_aSubgroups.Count(); - int res; - wxFileConfigGroup *pGroup; - - while ( lo < hi ) { - i = (lo + hi)/2; - pGroup = m_aSubgroups[i]; - - #if wxCONFIG_CASE_SENSITIVE - res = wxStrcmp(pGroup->Name(), szName); - #else - res = wxStricmp(pGroup->Name(), szName); - #endif - - if ( res > 0 ) - hi = i; - else if ( res < 0 ) - lo = i + 1; - else - return pGroup; - } - - return NULL; -} - -// ---------------------------------------------------------------------------- -// create a new item -// ---------------------------------------------------------------------------- - -// create a new entry and add it to the current group -wxFileConfigEntry *wxFileConfigGroup::AddEntry(const wxString& strName, int nLine) -{ - wxASSERT( FindEntry(strName) == 0 ); - - wxFileConfigEntry *pEntry = new wxFileConfigEntry(this, strName, nLine); - - m_aEntries.Add(pEntry); - return pEntry; -} - -// create a new group and add it to the current group -wxFileConfigGroup *wxFileConfigGroup::AddSubgroup(const wxString& strName) -{ - wxASSERT( FindSubgroup(strName) == 0 ); - - wxFileConfigGroup *pGroup = new wxFileConfigGroup(this, strName, m_pConfig); - - m_aSubgroups.Add(pGroup); - return pGroup; -} - -// ---------------------------------------------------------------------------- -// delete an item -// ---------------------------------------------------------------------------- - -/* - The delete operations are _very_ slow if we delete the last item of this - group (see comments before GetXXXLineXXX functions for more details), - so it's much better to start with the first entry/group if we want to - delete several of them. - */ - -bool wxFileConfigGroup::DeleteSubgroupByName(const wxChar *szName) -{ - wxFileConfigGroup * const pGroup = FindSubgroup(szName); - - return pGroup ? DeleteSubgroup(pGroup) : false; -} - -// Delete the subgroup and remove all references to it from -// other data structures. -bool wxFileConfigGroup::DeleteSubgroup(wxFileConfigGroup *pGroup) -{ - wxCHECK_MSG( pGroup, false, _T("deleting non existing group?") ); - - wxLogTrace( FILECONF_TRACE_MASK, - _T("Deleting group '%s' from '%s'"), - pGroup->Name().c_str(), - Name().c_str() ); - - wxLogTrace( FILECONF_TRACE_MASK, - _T(" (m_pLine) = prev: %p, this %p, next %p"), - m_pLine ? wx_static_cast(void*, m_pLine->Prev()) : 0, - wx_static_cast(void*, m_pLine), - m_pLine ? wx_static_cast(void*, m_pLine->Next()) : 0 ); - wxLogTrace( FILECONF_TRACE_MASK, - _T(" text: '%s'"), - m_pLine ? m_pLine->Text().c_str() : wxEmptyString ); - - // delete all entries... - size_t nCount = pGroup->m_aEntries.Count(); - - wxLogTrace(FILECONF_TRACE_MASK, - _T("Removing %lu entries"), (unsigned long)nCount ); - - for ( size_t nEntry = 0; nEntry < nCount; nEntry++ ) - { - wxFileConfigLineList *pLine = pGroup->m_aEntries[nEntry]->GetLine(); - - if ( pLine ) - { - wxLogTrace( FILECONF_TRACE_MASK, - _T(" '%s'"), - pLine->Text().c_str() ); - m_pConfig->LineListRemove(pLine); - } - } - - // ...and subgroups of this subgroup - nCount = pGroup->m_aSubgroups.Count(); - - wxLogTrace( FILECONF_TRACE_MASK, - _T("Removing %lu subgroups"), (unsigned long)nCount ); - - for ( size_t nGroup = 0; nGroup < nCount; nGroup++ ) - { - pGroup->DeleteSubgroup(pGroup->m_aSubgroups[0]); - } - - // and then finally the group itself - wxFileConfigLineList *pLine = pGroup->m_pLine; - if ( pLine ) - { - wxLogTrace( FILECONF_TRACE_MASK, - _T(" Removing line for group '%s' : '%s'"), - pGroup->Name().c_str(), - pLine->Text().c_str() ); - wxLogTrace( FILECONF_TRACE_MASK, - _T(" Removing from group '%s' : '%s'"), - Name().c_str(), - ((m_pLine) ? m_pLine->Text().c_str() : wxEmptyString) ); - - // notice that we may do this test inside the previous "if" - // because the last entry's line is surely !NULL - if ( pGroup == m_pLastGroup ) - { - wxLogTrace( FILECONF_TRACE_MASK, - _T(" Removing last group") ); - - // our last entry is being deleted, so find the last one which - // stays by going back until we find a subgroup or reach the - // group line - const size_t nSubgroups = m_aSubgroups.Count(); - - m_pLastGroup = NULL; - for ( wxFileConfigLineList *pl = pLine->Prev(); - pl && !m_pLastGroup; - pl = pl->Prev() ) - { - // does this line belong to our subgroup? - for ( size_t n = 0; n < nSubgroups; n++ ) - { - // do _not_ call GetGroupLine! we don't want to add it to - // the local file if it's not already there - if ( m_aSubgroups[n]->m_pLine == pl ) - { - m_pLastGroup = m_aSubgroups[n]; - break; - } - } - - if ( pl == m_pLine ) - break; - } - } - - m_pConfig->LineListRemove(pLine); - } - else - { - wxLogTrace( FILECONF_TRACE_MASK, - _T(" No line entry for Group '%s'?"), - pGroup->Name().c_str() ); - } - - m_aSubgroups.Remove(pGroup); - delete pGroup; - - return true; -} - -bool wxFileConfigGroup::DeleteEntry(const wxChar *szName) -{ - wxFileConfigEntry *pEntry = FindEntry(szName); - if ( !pEntry ) - { - // entry doesn't exist, nothing to do - return false; - } - - wxFileConfigLineList *pLine = pEntry->GetLine(); - if ( pLine != NULL ) { - // notice that we may do this test inside the previous "if" because the - // last entry's line is surely !NULL - if ( pEntry == m_pLastEntry ) { - // our last entry is being deleted - find the last one which stays - wxASSERT( m_pLine != NULL ); // if we have an entry with !NULL pLine... - - // find the previous entry (if any) - wxFileConfigEntry *pNewLast = NULL; - const wxFileConfigLineList * const - pNewLastLine = m_pLastEntry->GetLine()->Prev(); - const size_t nEntries = m_aEntries.GetCount(); - for ( size_t n = 0; n < nEntries; n++ ) { - if ( m_aEntries[n]->GetLine() == pNewLastLine ) { - pNewLast = m_aEntries[n]; - break; - } - } - - // pNewLast can be NULL here -- it's ok and can happen if we have no - // entries left - m_pLastEntry = pNewLast; - } - - m_pConfig->LineListRemove(pLine); - } - - m_aEntries.Remove(pEntry); - delete pEntry; - - return true; -} - -// ============================================================================ -// wxFileConfig::wxFileConfigEntry -// ============================================================================ - -// ---------------------------------------------------------------------------- -// ctor -// ---------------------------------------------------------------------------- -wxFileConfigEntry::wxFileConfigEntry(wxFileConfigGroup *pParent, - const wxString& strName, - int nLine) - : m_strName(strName) -{ - wxASSERT( !strName.empty() ); - - m_pParent = pParent; - m_nLine = nLine; - m_pLine = NULL; - - m_bHasValue = false; - - m_bImmutable = strName[0] == wxCONFIG_IMMUTABLE_PREFIX; - if ( m_bImmutable ) - m_strName.erase(0, 1); // remove first character -} - -// ---------------------------------------------------------------------------- -// set value -// ---------------------------------------------------------------------------- - -void wxFileConfigEntry::SetLine(wxFileConfigLineList *pLine) -{ - if ( m_pLine != NULL ) { - wxLogWarning(_("entry '%s' appears more than once in group '%s'"), - Name().c_str(), m_pParent->GetFullName().c_str()); - } - - m_pLine = pLine; - Group()->SetLastEntry(this); -} - -// second parameter is false if we read the value from file and prevents the -// entry from being marked as 'dirty' -void wxFileConfigEntry::SetValue(const wxString& strValue, bool bUser) -{ - if ( bUser && IsImmutable() ) - { - wxLogWarning( _("attempt to change immutable key '%s' ignored."), - Name().c_str()); - return; - } - - // do nothing if it's the same value: but don't test for it if m_bHasValue - // hadn't been set yet or we'd never write empty values to the file - if ( m_bHasValue && strValue == m_strValue ) - return; - - m_bHasValue = true; - m_strValue = strValue; - - if ( bUser ) - { - wxString strValFiltered; - - if ( Group()->Config()->GetStyle() & wxCONFIG_USE_NO_ESCAPE_CHARACTERS ) - { - strValFiltered = strValue; - } - else { - strValFiltered = FilterOutValue(strValue); - } - - wxString strLine; - strLine << FilterOutEntryName(m_strName) << wxT('=') << strValFiltered; - - if ( m_pLine ) - { - // entry was read from the local config file, just modify the line - m_pLine->SetText(strLine); - } - else // this entry didn't exist in the local file - { - // add a new line to the file: note that line returned by - // GetLastEntryLine() may be NULL if we're in the root group and it - // doesn't have any entries yet, but this is ok as passing NULL - // line to LineListInsert() means to prepend new line to the list - wxFileConfigLineList *line = Group()->GetLastEntryLine(); - m_pLine = Group()->Config()->LineListInsert(strLine, line); - - Group()->SetLastEntry(this); - } - } -} - -// ============================================================================ -// global functions -// ============================================================================ - -// ---------------------------------------------------------------------------- -// compare functions for array sorting -// ---------------------------------------------------------------------------- - -int CompareEntries(wxFileConfigEntry *p1, wxFileConfigEntry *p2) -{ -#if wxCONFIG_CASE_SENSITIVE - return wxStrcmp(p1->Name(), p2->Name()); -#else - return wxStricmp(p1->Name(), p2->Name()); -#endif -} - -int CompareGroups(wxFileConfigGroup *p1, wxFileConfigGroup *p2) -{ -#if wxCONFIG_CASE_SENSITIVE - return wxStrcmp(p1->Name(), p2->Name()); -#else - return wxStricmp(p1->Name(), p2->Name()); -#endif -} - -// ---------------------------------------------------------------------------- -// filter functions -// ---------------------------------------------------------------------------- - -// undo FilterOutValue -static wxString FilterInValue(const wxString& str) -{ - wxString strResult; - strResult.Alloc(str.Len()); - - bool bQuoted = !str.empty() && str[0] == '"'; - - for ( size_t n = bQuoted ? 1 : 0; n < str.Len(); n++ ) { - if ( str[n] == wxT('\\') ) { - switch ( str[++n] ) { - case wxT('n'): - strResult += wxT('\n'); - break; - - case wxT('r'): - strResult += wxT('\r'); - break; - - case wxT('t'): - strResult += wxT('\t'); - break; - - case wxT('\\'): - strResult += wxT('\\'); - break; - - case wxT('"'): - strResult += wxT('"'); - break; - } - } - else { - if ( str[n] != wxT('"') || !bQuoted ) - strResult += str[n]; - else if ( n != str.Len() - 1 ) { - wxLogWarning(_("unexpected \" at position %d in '%s'."), - n, str.c_str()); - } - //else: it's the last quote of a quoted string, ok - } - } - - return strResult; -} - -// quote the string before writing it to file -static wxString FilterOutValue(const wxString& str) -{ - if ( !str ) - return str; - - wxString strResult; - strResult.Alloc(str.Len()); - - // quoting is necessary to preserve spaces in the beginning of the string - bool bQuote = wxIsspace(str[0]) || str[0] == wxT('"'); - - if ( bQuote ) - strResult += wxT('"'); - - wxChar c; - for ( size_t n = 0; n < str.Len(); n++ ) { - switch ( str[n] ) { - case wxT('\n'): - c = wxT('n'); - break; - - case wxT('\r'): - c = wxT('r'); - break; - - case wxT('\t'): - c = wxT('t'); - break; - - case wxT('\\'): - c = wxT('\\'); - break; - - case wxT('"'): - if ( bQuote ) { - c = wxT('"'); - break; - } - //else: fall through - - default: - strResult += str[n]; - continue; // nothing special to do - } - - // we get here only for special characters - strResult << wxT('\\') << c; - } - - if ( bQuote ) - strResult += wxT('"'); - - return strResult; -} - -// undo FilterOutEntryName -static wxString FilterInEntryName(const wxString& str) -{ - wxString strResult; - strResult.Alloc(str.Len()); - - for ( const wxChar *pc = str.c_str(); *pc != '\0'; pc++ ) { - if ( *pc == wxT('\\') ) { - // we need to test it here or we'd skip past the NUL in the loop line - if ( *++pc == _T('\0') ) - break; - } - - strResult += *pc; - } - - return strResult; -} - -// sanitize entry or group name: insert '\\' before any special characters -static wxString FilterOutEntryName(const wxString& str) -{ - wxString strResult; - strResult.Alloc(str.Len()); - - for ( const wxChar *pc = str.c_str(); *pc != wxT('\0'); pc++ ) { - const wxChar c = *pc; - - // we explicitly allow some of "safe" chars and 8bit ASCII characters - // which will probably never have special meaning and with which we can't - // use isalnum() anyhow (in ASCII built, in Unicode it's just fine) - // - // NB: note that wxCONFIG_IMMUTABLE_PREFIX and wxCONFIG_PATH_SEPARATOR - // should *not* be quoted - if ( -#if !wxUSE_UNICODE - ((unsigned char)c < 127) && -#endif // ANSI - !wxIsalnum(c) && !wxStrchr(wxT("@_/-!.*%"), c) ) - { - strResult += wxT('\\'); - } - - strResult += c; - } - - return strResult; -} - -// we can't put ?: in the ctor initializer list because it confuses some -// broken compilers (Borland C++) -static wxString GetAppName(const wxString& appName) -{ - if ( !appName && wxTheApp ) - return wxTheApp->GetAppName(); - else - return appName; -} - -#endif // wxUSE_CONFIG +/////////////////////////////////////////////////////////////////////////////// +// Name: src/common/fileconf.cpp +// Purpose: implementation of wxFileConfig derivation of wxConfig +// Author: Vadim Zeitlin +// Modified by: +// Created: 07.04.98 (adapted from appconf.cpp) +// RCS-ID: $Id: fileconf.cpp 50711 2007-12-15 02:57:58Z VZ $ +// Copyright: (c) 1997 Karsten Ballueder & Vadim Zeitlin +// Ballueder@usa.net +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif //__BORLANDC__ + +#if wxUSE_CONFIG && wxUSE_FILECONFIG + +#ifndef WX_PRECOMP + #include "wx/dynarray.h" + #include "wx/string.h" + #include "wx/intl.h" + #include "wx/log.h" + #include "wx/app.h" + #include "wx/utils.h" // for wxGetHomeDir + #if wxUSE_STREAMS + #include "wx/stream.h" + #endif // wxUSE_STREAMS +#endif //WX_PRECOMP + +#include "wx/file.h" +#include "wx/textfile.h" +#include "wx/memtext.h" +#include "wx/config.h" +#include "wx/fileconf.h" +#include "wx/filefn.h" + +#if defined(__WXMAC__) + #include "wx/mac/private.h" // includes mac headers + #include "wx/filename.h" // for MacSetTypeAndCreator +#endif + +#if defined(__WXMSW__) + #include "wx/msw/private.h" +#endif //windows.h +#if defined(__WXPM__) + #define INCL_DOS + #include +#endif + +#include +#include + +// ---------------------------------------------------------------------------- +// macros +// ---------------------------------------------------------------------------- +#define CONST_CAST ((wxFileConfig *)this)-> + +// ---------------------------------------------------------------------------- +// constants +// ---------------------------------------------------------------------------- + +#ifndef MAX_PATH + #define MAX_PATH 512 +#endif + +#define FILECONF_TRACE_MASK _T("fileconf") + +// ---------------------------------------------------------------------------- +// global functions declarations +// ---------------------------------------------------------------------------- + +// compare functions for sorting the arrays +static int LINKAGEMODE CompareEntries(wxFileConfigEntry *p1, wxFileConfigEntry *p2); +static int LINKAGEMODE CompareGroups(wxFileConfigGroup *p1, wxFileConfigGroup *p2); + +// filter strings +static wxString FilterInValue(const wxString& str); +static wxString FilterOutValue(const wxString& str); + +static wxString FilterInEntryName(const wxString& str); +static wxString FilterOutEntryName(const wxString& str); + +// get the name to use in wxFileConfig ctor +static wxString GetAppName(const wxString& appname); + +// ============================================================================ +// private classes +// ============================================================================ + +// ---------------------------------------------------------------------------- +// "template" array types +// ---------------------------------------------------------------------------- + +#ifdef WXMAKINGDLL_BASE + WX_DEFINE_SORTED_USER_EXPORTED_ARRAY(wxFileConfigEntry *, ArrayEntries, + WXDLLIMPEXP_BASE); + WX_DEFINE_SORTED_USER_EXPORTED_ARRAY(wxFileConfigGroup *, ArrayGroups, + WXDLLIMPEXP_BASE); +#else + WX_DEFINE_SORTED_ARRAY(wxFileConfigEntry *, ArrayEntries); + WX_DEFINE_SORTED_ARRAY(wxFileConfigGroup *, ArrayGroups); +#endif + +// ---------------------------------------------------------------------------- +// wxFileConfigLineList +// ---------------------------------------------------------------------------- + +// we store all lines of the local config file as a linked list in memory +class wxFileConfigLineList +{ +public: + void SetNext(wxFileConfigLineList *pNext) { m_pNext = pNext; } + void SetPrev(wxFileConfigLineList *pPrev) { m_pPrev = pPrev; } + + // ctor + wxFileConfigLineList(const wxString& str, + wxFileConfigLineList *pNext = NULL) : m_strLine(str) + { SetNext(pNext); SetPrev(NULL); } + + // next/prev nodes in the linked list + wxFileConfigLineList *Next() const { return m_pNext; } + wxFileConfigLineList *Prev() const { return m_pPrev; } + + // get/change lines text + void SetText(const wxString& str) { m_strLine = str; } + const wxString& Text() const { return m_strLine; } + +private: + wxString m_strLine; // line contents + wxFileConfigLineList *m_pNext, // next node + *m_pPrev; // previous one + + DECLARE_NO_COPY_CLASS(wxFileConfigLineList) +}; + +// ---------------------------------------------------------------------------- +// wxFileConfigEntry: a name/value pair +// ---------------------------------------------------------------------------- + +class wxFileConfigEntry +{ +private: + wxFileConfigGroup *m_pParent; // group that contains us + + wxString m_strName, // entry name + m_strValue; // value + bool m_bImmutable:1, // can be overriden locally? + m_bHasValue:1; // set after first call to SetValue() + + int m_nLine; // used if m_pLine == NULL only + + // pointer to our line in the linked list or NULL if it was found in global + // file (which we don't modify) + wxFileConfigLineList *m_pLine; + +public: + wxFileConfigEntry(wxFileConfigGroup *pParent, + const wxString& strName, int nLine); + + // simple accessors + const wxString& Name() const { return m_strName; } + const wxString& Value() const { return m_strValue; } + wxFileConfigGroup *Group() const { return m_pParent; } + bool IsImmutable() const { return m_bImmutable; } + bool IsLocal() const { return m_pLine != 0; } + int Line() const { return m_nLine; } + wxFileConfigLineList * + GetLine() const { return m_pLine; } + + // modify entry attributes + void SetValue(const wxString& strValue, bool bUser = true); + void SetLine(wxFileConfigLineList *pLine); + + DECLARE_NO_COPY_CLASS(wxFileConfigEntry) +}; + +// ---------------------------------------------------------------------------- +// wxFileConfigGroup: container of entries and other groups +// ---------------------------------------------------------------------------- + +class wxFileConfigGroup +{ +private: + wxFileConfig *m_pConfig; // config object we belong to + wxFileConfigGroup *m_pParent; // parent group (NULL for root group) + ArrayEntries m_aEntries; // entries in this group + ArrayGroups m_aSubgroups; // subgroups + wxString m_strName; // group's name + wxFileConfigLineList *m_pLine; // pointer to our line in the linked list + wxFileConfigEntry *m_pLastEntry; // last entry/subgroup of this group in the + wxFileConfigGroup *m_pLastGroup; // local file (we insert new ones after it) + + // DeleteSubgroupByName helper + bool DeleteSubgroup(wxFileConfigGroup *pGroup); + + // used by Rename() + void UpdateGroupAndSubgroupsLines(); + +public: + // ctor + wxFileConfigGroup(wxFileConfigGroup *pParent, const wxString& strName, wxFileConfig *); + + // dtor deletes all entries and subgroups also + ~wxFileConfigGroup(); + + // simple accessors + const wxString& Name() const { return m_strName; } + wxFileConfigGroup *Parent() const { return m_pParent; } + wxFileConfig *Config() const { return m_pConfig; } + + const ArrayEntries& Entries() const { return m_aEntries; } + const ArrayGroups& Groups() const { return m_aSubgroups; } + bool IsEmpty() const { return Entries().IsEmpty() && Groups().IsEmpty(); } + + // find entry/subgroup (NULL if not found) + wxFileConfigGroup *FindSubgroup(const wxChar *szName) const; + wxFileConfigEntry *FindEntry (const wxChar *szName) const; + + // delete entry/subgroup, return false if doesn't exist + bool DeleteSubgroupByName(const wxChar *szName); + bool DeleteEntry(const wxChar *szName); + + // create new entry/subgroup returning pointer to newly created element + wxFileConfigGroup *AddSubgroup(const wxString& strName); + wxFileConfigEntry *AddEntry (const wxString& strName, int nLine = wxNOT_FOUND); + + void SetLine(wxFileConfigLineList *pLine); + + // rename: no checks are done to ensure that the name is unique! + void Rename(const wxString& newName); + + // + wxString GetFullName() const; + + // get the last line belonging to an entry/subgroup of this group + wxFileConfigLineList *GetGroupLine(); // line which contains [group] + // may be NULL for "/" only + wxFileConfigLineList *GetLastEntryLine(); // after which our subgroups start + wxFileConfigLineList *GetLastGroupLine(); // after which the next group starts + + // called by entries/subgroups when they're created/deleted + void SetLastEntry(wxFileConfigEntry *pEntry); + void SetLastGroup(wxFileConfigGroup *pGroup) + { m_pLastGroup = pGroup; } + + DECLARE_NO_COPY_CLASS(wxFileConfigGroup) +}; + +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// static functions +// ---------------------------------------------------------------------------- +wxString wxFileConfig::GetGlobalDir() +{ + wxString strDir; + +#ifdef __VMS__ // Note if __VMS is defined __UNIX is also defined + strDir = wxT("sys$manager:"); +#elif defined(__WXMAC__) + strDir = wxMacFindFolder( (short) kOnSystemDisk, kPreferencesFolderType, kDontCreateFolder ) ; +#elif defined( __UNIX__ ) + strDir = wxT("/etc/"); +#elif defined(__OS2__) + ULONG aulSysInfo[QSV_MAX] = {0}; + UINT drive; + APIRET rc; + + rc = DosQuerySysInfo( 1L, QSV_MAX, (PVOID)aulSysInfo, sizeof(ULONG)*QSV_MAX); + if (rc == 0) + { + drive = aulSysInfo[QSV_BOOT_DRIVE - 1]; + strDir.Printf(wxT("%c:\\OS2\\"), 'A'+drive-1); + } +#elif defined(__WXSTUBS__) + wxFAIL_MSG( wxT("TODO") ); +#elif defined(__DOS__) + // There's no such thing as global cfg dir in MS-DOS, let's return + // current directory (FIXME_MGL?) + strDir = wxT(".\\"); +#elif defined(__WXWINCE__) + strDir = wxT("\\Windows\\"); +#else // Windows + + wxChar szWinDir[MAX_PATH]; + ::GetWindowsDirectory(szWinDir, MAX_PATH); + + strDir = szWinDir; + strDir << wxT('\\'); +#endif // Unix/Windows + + return strDir; +} + +wxString wxFileConfig::GetLocalDir() +{ + wxString strDir; + +#if defined(__WXMAC__) || defined(__DOS__) + // no local dir concept on Mac OS 9 or MS-DOS + strDir << GetGlobalDir() ; +#else + wxGetHomeDir(&strDir); + + #ifdef __UNIX__ + if ( + (strDir.Last() != wxT('/')) + #ifdef __VMS + && (strDir.Last() != wxT(']')) + #endif + ) + strDir << wxT('/'); + #else + if (strDir.Last() != wxT('\\')) + strDir << wxT('\\'); + #endif +#endif + + return strDir; +} + +wxString wxFileConfig::GetGlobalFileName(const wxChar *szFile) +{ + wxString str = GetGlobalDir(); + str << szFile; + + if ( wxStrchr(szFile, wxT('.')) == NULL ) +#if defined( __WXMAC__ ) + str << wxT(" Preferences") ; +#elif defined( __UNIX__ ) + str << wxT(".conf"); +#else // Windows + str << wxT(".ini"); +#endif // UNIX/Win + + return str; +} + +wxString wxFileConfig::GetLocalFileName(const wxChar *szFile) +{ +#ifdef __VMS__ + // On VMS I saw the problem that the home directory was appended + // twice for the configuration file. Does that also happen for + // other platforms? + wxString str = wxT( '.' ); +#else + wxString str = GetLocalDir(); +#endif + +#if defined( __UNIX__ ) && !defined( __VMS ) && !defined( __WXMAC__ ) + str << wxT('.'); +#endif + + str << szFile; + +#if defined(__WINDOWS__) || defined(__DOS__) + if ( wxStrchr(szFile, wxT('.')) == NULL ) + str << wxT(".ini"); +#endif + +#ifdef __WXMAC__ + str << wxT(" Preferences") ; +#endif + + return str; +} + +// ---------------------------------------------------------------------------- +// ctor +// ---------------------------------------------------------------------------- + +void wxFileConfig::Init() +{ + m_pCurrentGroup = + m_pRootGroup = new wxFileConfigGroup(NULL, wxEmptyString, this); + + m_linesHead = + m_linesTail = NULL; + + // It's not an error if (one of the) file(s) doesn't exist. + + // parse the global file + if ( !m_strGlobalFile.empty() && wxFile::Exists(m_strGlobalFile) ) + { + wxTextFile fileGlobal(m_strGlobalFile); + + if ( fileGlobal.Open(*m_conv/*ignored in ANSI build*/) ) + { + Parse(fileGlobal, false /* global */); + SetRootPath(); + } + else + { + wxLogWarning(_("can't open global configuration file '%s'."), m_strGlobalFile.c_str()); + } + } + + // parse the local file + if ( !m_strLocalFile.empty() && wxFile::Exists(m_strLocalFile) ) + { + wxTextFile fileLocal(m_strLocalFile); + if ( fileLocal.Open(*m_conv/*ignored in ANSI build*/) ) + { + Parse(fileLocal, true /* local */); + SetRootPath(); + } + else + { + wxLogWarning(_("can't open user configuration file '%s'."), m_strLocalFile.c_str() ); + } + } + + m_isDirty = false; +} + +// constructor supports creation of wxFileConfig objects of any type +wxFileConfig::wxFileConfig(const wxString& appName, const wxString& vendorName, + const wxString& strLocal, const wxString& strGlobal, + long style, + const wxMBConv& conv) + : wxConfigBase(::GetAppName(appName), vendorName, + strLocal, strGlobal, + style), + m_strLocalFile(strLocal), m_strGlobalFile(strGlobal), + m_conv(conv.Clone()) +{ + // Make up names for files if empty + if ( m_strLocalFile.empty() && (style & wxCONFIG_USE_LOCAL_FILE) ) + { + m_strLocalFile = GetLocalFileName(GetAppName()); +#if defined(__UNIX__) && !defined(__VMS) + if ( style & wxCONFIG_USE_SUBDIR ) + m_strLocalFile << wxFILE_SEP_PATH << GetAppName() << _T(".conf"); +#endif + } + + if ( m_strGlobalFile.empty() && (style & wxCONFIG_USE_GLOBAL_FILE) ) + m_strGlobalFile = GetGlobalFileName(GetAppName()); + + // Check if styles are not supplied, but filenames are, in which case + // add the correct styles. + if ( !m_strLocalFile.empty() ) + SetStyle(GetStyle() | wxCONFIG_USE_LOCAL_FILE); + + if ( !m_strGlobalFile.empty() ) + SetStyle(GetStyle() | wxCONFIG_USE_GLOBAL_FILE); + + // if the path is not absolute, prepend the standard directory to it + // UNLESS wxCONFIG_USE_RELATIVE_PATH style is set + if ( !(style & wxCONFIG_USE_RELATIVE_PATH) ) + { + if ( !m_strLocalFile.empty() && !wxIsAbsolutePath(m_strLocalFile) ) + { + const wxString strLocalOrig = m_strLocalFile; + m_strLocalFile = GetLocalDir(); + m_strLocalFile << strLocalOrig; + } + + if ( !m_strGlobalFile.empty() && !wxIsAbsolutePath(m_strGlobalFile) ) + { + const wxString strGlobalOrig = m_strGlobalFile; + m_strGlobalFile = GetGlobalDir(); + m_strGlobalFile << strGlobalOrig; + } + } + + SetUmask(-1); + + Init(); +} + +#if wxUSE_STREAMS + +wxFileConfig::wxFileConfig(wxInputStream &inStream, const wxMBConv& conv) + : m_conv(conv.Clone()) +{ + // always local_file when this constructor is called (?) + SetStyle(GetStyle() | wxCONFIG_USE_LOCAL_FILE); + + m_pCurrentGroup = + m_pRootGroup = new wxFileConfigGroup(NULL, wxEmptyString, this); + + m_linesHead = + m_linesTail = NULL; + + // read the entire stream contents in memory + wxString str; + { + static const size_t chunkLen = 1024; + + wxMemoryBuffer buf(chunkLen); + do + { + inStream.Read(buf.GetAppendBuf(chunkLen), chunkLen); + buf.UngetAppendBuf(inStream.LastRead()); + + const wxStreamError err = inStream.GetLastError(); + + if ( err != wxSTREAM_NO_ERROR && err != wxSTREAM_EOF ) + { + wxLogError(_("Error reading config options.")); + break; + } + } + while ( !inStream.Eof() ); + +#if wxUSE_UNICODE + size_t len; + str = conv.cMB2WC((char *)buf.GetData(), buf.GetDataLen(), &len); + if ( !len && buf.GetDataLen() ) + { + wxLogError(_("Failed to read config options.")); + } +#else // !wxUSE_UNICODE + // no need for conversion + str.assign((char *)buf.GetData(), buf.GetDataLen()); +#endif // wxUSE_UNICODE/!wxUSE_UNICODE + } + + + // translate everything to the current (platform-dependent) line + // termination character + str = wxTextBuffer::Translate(str); + + wxMemoryText memText; + + // Now we can add the text to the memory text. To do this we extract line + // by line from the translated string, until we've reached the end. + // + // VZ: all this is horribly inefficient, we should do the translation on + // the fly in one pass saving both memory and time (TODO) + + const wxChar *pEOL = wxTextBuffer::GetEOL(wxTextBuffer::typeDefault); + const size_t EOLLen = wxStrlen(pEOL); + + int posLineStart = str.Find(pEOL); + while ( posLineStart != -1 ) + { + wxString line(str.Left(posLineStart)); + + memText.AddLine(line); + + str = str.Mid(posLineStart + EOLLen); + + posLineStart = str.Find(pEOL); + } + + // also add whatever we have left in the translated string. + if ( !str.empty() ) + memText.AddLine(str); + + // Finally we can parse it all. + Parse(memText, true /* local */); + + SetRootPath(); + ResetDirty(); +} + +#endif // wxUSE_STREAMS + +void wxFileConfig::CleanUp() +{ + delete m_pRootGroup; + + wxFileConfigLineList *pCur = m_linesHead; + while ( pCur != NULL ) { + wxFileConfigLineList *pNext = pCur->Next(); + delete pCur; + pCur = pNext; + } +} + +wxFileConfig::~wxFileConfig() +{ + Flush(); + + CleanUp(); + + delete m_conv; +} + +// ---------------------------------------------------------------------------- +// parse a config file +// ---------------------------------------------------------------------------- + +void wxFileConfig::Parse(const wxTextBuffer& buffer, bool bLocal) +{ + const wxChar *pStart; + const wxChar *pEnd; + wxString strLine; + + size_t nLineCount = buffer.GetLineCount(); + + for ( size_t n = 0; n < nLineCount; n++ ) + { + strLine = buffer[n]; + + // add the line to linked list + if ( bLocal ) + LineListAppend(strLine); + + + // skip leading spaces + for ( pStart = strLine; wxIsspace(*pStart); pStart++ ) + ; + + // skip blank/comment lines + if ( *pStart == wxT('\0')|| *pStart == wxT(';') || *pStart == wxT('#') ) + continue; + + if ( *pStart == wxT('[') ) { // a new group + pEnd = pStart; + + while ( *++pEnd != wxT(']') ) { + if ( *pEnd == wxT('\\') ) { + // the next char is escaped, so skip it even if it is ']' + pEnd++; + } + + if ( *pEnd == wxT('\n') || *pEnd == wxT('\0') ) { + // we reached the end of line, break out of the loop + break; + } + } + + if ( *pEnd != wxT(']') ) { + wxLogError(_("file '%s': unexpected character %c at line %d."), + buffer.GetName(), *pEnd, n + 1); + continue; // skip this line + } + + // group name here is always considered as abs path + wxString strGroup; + pStart++; + strGroup << wxCONFIG_PATH_SEPARATOR + << FilterInEntryName(wxString(pStart, pEnd - pStart)); + + // will create it if doesn't yet exist + SetPath(strGroup); + + if ( bLocal ) + { + if ( m_pCurrentGroup->Parent() ) + m_pCurrentGroup->Parent()->SetLastGroup(m_pCurrentGroup); + m_pCurrentGroup->SetLine(m_linesTail); + } + + // check that there is nothing except comments left on this line + bool bCont = true; + while ( *++pEnd != wxT('\0') && bCont ) { + switch ( *pEnd ) { + case wxT('#'): + case wxT(';'): + bCont = false; + break; + + case wxT(' '): + case wxT('\t'): + // ignore whitespace ('\n' impossible here) + break; + + default: + wxLogWarning(_("file '%s', line %d: '%s' ignored after group header."), + buffer.GetName(), n + 1, pEnd); + bCont = false; + } + } + } + else { // a key + pEnd = pStart; + while ( *pEnd && *pEnd != wxT('=') /* && !wxIsspace(*pEnd)*/ ) { + if ( *pEnd == wxT('\\') ) { + // next character may be space or not - still take it because it's + // quoted (unless there is nothing) + pEnd++; + if ( !*pEnd ) { + // the error message will be given below anyhow + break; + } + } + + pEnd++; + } + + wxString strKey(FilterInEntryName(wxString(pStart, pEnd).Trim())); + + // skip whitespace + while ( wxIsspace(*pEnd) ) + pEnd++; + + if ( *pEnd++ != wxT('=') ) { + wxLogError(_("file '%s', line %d: '=' expected."), + buffer.GetName(), n + 1); + } + else { + wxFileConfigEntry *pEntry = m_pCurrentGroup->FindEntry(strKey); + + if ( pEntry == NULL ) { + // new entry + pEntry = m_pCurrentGroup->AddEntry(strKey, n); + } + else { + if ( bLocal && pEntry->IsImmutable() ) { + // immutable keys can't be changed by user + wxLogWarning(_("file '%s', line %d: value for immutable key '%s' ignored."), + buffer.GetName(), n + 1, strKey.c_str()); + continue; + } + // the condition below catches the cases (a) and (b) but not (c): + // (a) global key found second time in global file + // (b) key found second (or more) time in local file + // (c) key from global file now found in local one + // which is exactly what we want. + else if ( !bLocal || pEntry->IsLocal() ) { + wxLogWarning(_("file '%s', line %d: key '%s' was first found at line %d."), + buffer.GetName(), n + 1, strKey.c_str(), pEntry->Line()); + + } + } + + if ( bLocal ) + pEntry->SetLine(m_linesTail); + + // skip whitespace + while ( wxIsspace(*pEnd) ) + pEnd++; + + wxString value = pEnd; + if ( !(GetStyle() & wxCONFIG_USE_NO_ESCAPE_CHARACTERS) ) + value = FilterInValue(value); + + pEntry->SetValue(value, false); + } + } + } +} + +// ---------------------------------------------------------------------------- +// set/retrieve path +// ---------------------------------------------------------------------------- + +void wxFileConfig::SetRootPath() +{ + m_strPath.Empty(); + m_pCurrentGroup = m_pRootGroup; +} + +bool +wxFileConfig::DoSetPath(const wxString& strPath, bool createMissingComponents) +{ + wxArrayString aParts; + + if ( strPath.empty() ) { + SetRootPath(); + return true; + } + + if ( strPath[0] == wxCONFIG_PATH_SEPARATOR ) { + // absolute path + wxSplitPath(aParts, strPath); + } + else { + // relative path, combine with current one + wxString strFullPath = m_strPath; + strFullPath << wxCONFIG_PATH_SEPARATOR << strPath; + wxSplitPath(aParts, strFullPath); + } + + // change current group + size_t n; + m_pCurrentGroup = m_pRootGroup; + for ( n = 0; n < aParts.Count(); n++ ) { + wxFileConfigGroup *pNextGroup = m_pCurrentGroup->FindSubgroup(aParts[n]); + if ( pNextGroup == NULL ) + { + if ( !createMissingComponents ) + return false; + + pNextGroup = m_pCurrentGroup->AddSubgroup(aParts[n]); + } + + m_pCurrentGroup = pNextGroup; + } + + // recombine path parts in one variable + m_strPath.Empty(); + for ( n = 0; n < aParts.Count(); n++ ) { + m_strPath << wxCONFIG_PATH_SEPARATOR << aParts[n]; + } + + return true; +} + +void wxFileConfig::SetPath(const wxString& strPath) +{ + DoSetPath(strPath, true /* create missing path components */); +} + +// ---------------------------------------------------------------------------- +// enumeration +// ---------------------------------------------------------------------------- + +bool wxFileConfig::GetFirstGroup(wxString& str, long& lIndex) const +{ + lIndex = 0; + return GetNextGroup(str, lIndex); +} + +bool wxFileConfig::GetNextGroup (wxString& str, long& lIndex) const +{ + if ( size_t(lIndex) < m_pCurrentGroup->Groups().Count() ) { + str = m_pCurrentGroup->Groups()[(size_t)lIndex++]->Name(); + return true; + } + else + return false; +} + +bool wxFileConfig::GetFirstEntry(wxString& str, long& lIndex) const +{ + lIndex = 0; + return GetNextEntry(str, lIndex); +} + +bool wxFileConfig::GetNextEntry (wxString& str, long& lIndex) const +{ + if ( size_t(lIndex) < m_pCurrentGroup->Entries().Count() ) { + str = m_pCurrentGroup->Entries()[(size_t)lIndex++]->Name(); + return true; + } + else + return false; +} + +size_t wxFileConfig::GetNumberOfEntries(bool bRecursive) const +{ + size_t n = m_pCurrentGroup->Entries().Count(); + if ( bRecursive ) { + wxFileConfigGroup *pOldCurrentGroup = m_pCurrentGroup; + size_t nSubgroups = m_pCurrentGroup->Groups().Count(); + for ( size_t nGroup = 0; nGroup < nSubgroups; nGroup++ ) { + CONST_CAST m_pCurrentGroup = m_pCurrentGroup->Groups()[nGroup]; + n += GetNumberOfEntries(true); + CONST_CAST m_pCurrentGroup = pOldCurrentGroup; + } + } + + return n; +} + +size_t wxFileConfig::GetNumberOfGroups(bool bRecursive) const +{ + size_t n = m_pCurrentGroup->Groups().Count(); + if ( bRecursive ) { + wxFileConfigGroup *pOldCurrentGroup = m_pCurrentGroup; + size_t nSubgroups = m_pCurrentGroup->Groups().Count(); + for ( size_t nGroup = 0; nGroup < nSubgroups; nGroup++ ) { + CONST_CAST m_pCurrentGroup = m_pCurrentGroup->Groups()[nGroup]; + n += GetNumberOfGroups(true); + CONST_CAST m_pCurrentGroup = pOldCurrentGroup; + } + } + + return n; +} + +// ---------------------------------------------------------------------------- +// tests for existence +// ---------------------------------------------------------------------------- + +bool wxFileConfig::HasGroup(const wxString& strName) const +{ + // special case: DoSetPath("") does work as it's equivalent to DoSetPath("/") + // but there is no group with empty name so treat this separately + if ( strName.empty() ) + return false; + + const wxString pathOld = GetPath(); + + wxFileConfig *self = wx_const_cast(wxFileConfig *, this); + const bool + rc = self->DoSetPath(strName, false /* don't create missing components */); + + self->SetPath(pathOld); + + return rc; +} + +bool wxFileConfig::HasEntry(const wxString& entry) const +{ + // path is the part before the last "/" + wxString path = entry.BeforeLast(wxCONFIG_PATH_SEPARATOR); + + // except in the special case of "/keyname" when there is nothing before "/" + if ( path.empty() && *entry.c_str() == wxCONFIG_PATH_SEPARATOR ) + { + path = wxCONFIG_PATH_SEPARATOR; + } + + // change to the path of the entry if necessary and remember the old path + // to restore it later + wxString pathOld; + wxFileConfig * const self = wx_const_cast(wxFileConfig *, this); + if ( !path.empty() ) + { + pathOld = GetPath(); + if ( pathOld.empty() ) + pathOld = wxCONFIG_PATH_SEPARATOR; + + if ( !self->DoSetPath(path, false /* don't create if doesn't exist */) ) + { + return false; + } + } + + // check if the entry exists in this group + const bool exists = m_pCurrentGroup->FindEntry( + entry.AfterLast(wxCONFIG_PATH_SEPARATOR)) != NULL; + + // restore the old path if we changed it above + if ( !pathOld.empty() ) + { + self->SetPath(pathOld); + } + + return exists; +} + +// ---------------------------------------------------------------------------- +// read/write values +// ---------------------------------------------------------------------------- + +bool wxFileConfig::DoReadString(const wxString& key, wxString* pStr) const +{ + wxConfigPathChanger path(this, key); + + wxFileConfigEntry *pEntry = m_pCurrentGroup->FindEntry(path.Name()); + if (pEntry == NULL) { + return false; + } + + *pStr = pEntry->Value(); + + return true; +} + +bool wxFileConfig::DoReadLong(const wxString& key, long *pl) const +{ + wxString str; + if ( !Read(key, &str) ) + return false; + + // extra spaces shouldn't prevent us from reading numeric values + str.Trim(); + + return str.ToLong(pl); +} + +bool wxFileConfig::DoWriteString(const wxString& key, const wxString& szValue) +{ + wxConfigPathChanger path(this, key); + wxString strName = path.Name(); + + wxLogTrace( FILECONF_TRACE_MASK, + _T(" Writing String '%s' = '%s' to Group '%s'"), + strName.c_str(), + szValue.c_str(), + GetPath().c_str() ); + + if ( strName.empty() ) + { + // setting the value of a group is an error + + wxASSERT_MSG( szValue.empty(), wxT("can't set value of a group!") ); + + // ... except if it's empty in which case it's a way to force it's creation + + wxLogTrace( FILECONF_TRACE_MASK, + _T(" Creating group %s"), + m_pCurrentGroup->Name().c_str() ); + + SetDirty(); + + // this will add a line for this group if it didn't have it before (or + // do nothing for the root but it's ok as it always exists anyhow) + (void)m_pCurrentGroup->GetGroupLine(); + } + else + { + // writing an entry check that the name is reasonable + if ( strName[0u] == wxCONFIG_IMMUTABLE_PREFIX ) + { + wxLogError( _("Config entry name cannot start with '%c'."), + wxCONFIG_IMMUTABLE_PREFIX); + return false; + } + + wxFileConfigEntry *pEntry = m_pCurrentGroup->FindEntry(strName); + + if ( pEntry == 0 ) + { + wxLogTrace( FILECONF_TRACE_MASK, + _T(" Adding Entry %s"), + strName.c_str() ); + pEntry = m_pCurrentGroup->AddEntry(strName); + } + + wxLogTrace( FILECONF_TRACE_MASK, + _T(" Setting value %s"), + szValue.c_str() ); + pEntry->SetValue(szValue); + + SetDirty(); + } + + return true; +} + +bool wxFileConfig::DoWriteLong(const wxString& key, long lValue) +{ + return Write(key, wxString::Format(_T("%ld"), lValue)); +} + +bool wxFileConfig::Flush(bool /* bCurrentOnly */) +{ + if ( !IsDirty() || !m_strLocalFile ) + return true; + + // set the umask if needed + wxCHANGE_UMASK(m_umask); + + wxTempFile file(m_strLocalFile); + + if ( !file.IsOpened() ) + { + wxLogError(_("can't open user configuration file.")); + return false; + } + + // write all strings to file + wxString filetext; + filetext.reserve(4096); + for ( wxFileConfigLineList *p = m_linesHead; p != NULL; p = p->Next() ) + { + filetext << p->Text() << wxTextFile::GetEOL(); + } + + if ( !file.Write(filetext, *m_conv) ) + { + wxLogError(_("can't write user configuration file.")); + return false; + } + + if ( !file.Commit() ) + { + wxLogError(_("Failed to update user configuration file.")); + + return false; + } + + ResetDirty(); + +#if defined(__WXMAC__) + wxFileName(m_strLocalFile).MacSetTypeAndCreator('TEXT', 'ttxt'); +#endif // __WXMAC__ + + return true; +} + +#if wxUSE_STREAMS + +bool wxFileConfig::Save(wxOutputStream& os, const wxMBConv& conv) +{ + // save unconditionally, even if not dirty + for ( wxFileConfigLineList *p = m_linesHead; p != NULL; p = p->Next() ) + { + wxString line = p->Text(); + line += wxTextFile::GetEOL(); + + wxCharBuffer buf(line.mb_str(conv)); + if ( !os.Write(buf, strlen(buf)) ) + { + wxLogError(_("Error saving user configuration data.")); + + return false; + } + } + + ResetDirty(); + + return true; +} + +#endif // wxUSE_STREAMS + +// ---------------------------------------------------------------------------- +// renaming groups/entries +// ---------------------------------------------------------------------------- + +bool wxFileConfig::RenameEntry(const wxString& oldName, + const wxString& newName) +{ + wxASSERT_MSG( !wxStrchr(oldName, wxCONFIG_PATH_SEPARATOR), + _T("RenameEntry(): paths are not supported") ); + + // check that the entry exists + wxFileConfigEntry *oldEntry = m_pCurrentGroup->FindEntry(oldName); + if ( !oldEntry ) + return false; + + // check that the new entry doesn't already exist + if ( m_pCurrentGroup->FindEntry(newName) ) + return false; + + // delete the old entry, create the new one + wxString value = oldEntry->Value(); + if ( !m_pCurrentGroup->DeleteEntry(oldName) ) + return false; + + SetDirty(); + + wxFileConfigEntry *newEntry = m_pCurrentGroup->AddEntry(newName); + newEntry->SetValue(value); + + return true; +} + +bool wxFileConfig::RenameGroup(const wxString& oldName, + const wxString& newName) +{ + // check that the group exists + wxFileConfigGroup *group = m_pCurrentGroup->FindSubgroup(oldName); + if ( !group ) + return false; + + // check that the new group doesn't already exist + if ( m_pCurrentGroup->FindSubgroup(newName) ) + return false; + + group->Rename(newName); + + SetDirty(); + + return true; +} + +// ---------------------------------------------------------------------------- +// delete groups/entries +// ---------------------------------------------------------------------------- + +bool wxFileConfig::DeleteEntry(const wxString& key, bool bGroupIfEmptyAlso) +{ + wxConfigPathChanger path(this, key); + + if ( !m_pCurrentGroup->DeleteEntry(path.Name()) ) + return false; + + SetDirty(); + + if ( bGroupIfEmptyAlso && m_pCurrentGroup->IsEmpty() ) { + if ( m_pCurrentGroup != m_pRootGroup ) { + wxFileConfigGroup *pGroup = m_pCurrentGroup; + SetPath(wxT("..")); // changes m_pCurrentGroup! + m_pCurrentGroup->DeleteSubgroupByName(pGroup->Name()); + } + //else: never delete the root group + } + + return true; +} + +bool wxFileConfig::DeleteGroup(const wxString& key) +{ + wxConfigPathChanger path(this, RemoveTrailingSeparator(key)); + + if ( !m_pCurrentGroup->DeleteSubgroupByName(path.Name()) ) + return false; + + path.UpdateIfDeleted(); + + SetDirty(); + + return true; +} + +bool wxFileConfig::DeleteAll() +{ + CleanUp(); + + if ( !m_strLocalFile.empty() ) + { + if ( wxFile::Exists(m_strLocalFile) && wxRemove(m_strLocalFile) == -1 ) + { + wxLogSysError(_("can't delete user configuration file '%s'"), + m_strLocalFile.c_str()); + return false; + } + } + + Init(); + + return true; +} + +// ---------------------------------------------------------------------------- +// linked list functions +// ---------------------------------------------------------------------------- + + // append a new line to the end of the list + +wxFileConfigLineList *wxFileConfig::LineListAppend(const wxString& str) +{ + wxLogTrace( FILECONF_TRACE_MASK, + _T(" ** Adding Line '%s'"), + str.c_str() ); + wxLogTrace( FILECONF_TRACE_MASK, + _T(" head: %s"), + ((m_linesHead) ? m_linesHead->Text().c_str() : wxEmptyString) ); + wxLogTrace( FILECONF_TRACE_MASK, + _T(" tail: %s"), + ((m_linesTail) ? m_linesTail->Text().c_str() : wxEmptyString) ); + + wxFileConfigLineList *pLine = new wxFileConfigLineList(str); + + if ( m_linesTail == NULL ) + { + // list is empty + m_linesHead = pLine; + } + else + { + // adjust pointers + m_linesTail->SetNext(pLine); + pLine->SetPrev(m_linesTail); + } + + m_linesTail = pLine; + + wxLogTrace( FILECONF_TRACE_MASK, + _T(" head: %s"), + ((m_linesHead) ? m_linesHead->Text().c_str() : wxEmptyString) ); + wxLogTrace( FILECONF_TRACE_MASK, + _T(" tail: %s"), + ((m_linesTail) ? m_linesTail->Text().c_str() : wxEmptyString) ); + + return m_linesTail; +} + +// insert a new line after the given one or in the very beginning if !pLine +wxFileConfigLineList *wxFileConfig::LineListInsert(const wxString& str, + wxFileConfigLineList *pLine) +{ + wxLogTrace( FILECONF_TRACE_MASK, + _T(" ** Inserting Line '%s' after '%s'"), + str.c_str(), + ((pLine) ? pLine->Text().c_str() : wxEmptyString) ); + wxLogTrace( FILECONF_TRACE_MASK, + _T(" head: %s"), + ((m_linesHead) ? m_linesHead->Text().c_str() : wxEmptyString) ); + wxLogTrace( FILECONF_TRACE_MASK, + _T(" tail: %s"), + ((m_linesTail) ? m_linesTail->Text().c_str() : wxEmptyString) ); + + if ( pLine == m_linesTail ) + return LineListAppend(str); + + wxFileConfigLineList *pNewLine = new wxFileConfigLineList(str); + if ( pLine == NULL ) + { + // prepend to the list + pNewLine->SetNext(m_linesHead); + m_linesHead->SetPrev(pNewLine); + m_linesHead = pNewLine; + } + else + { + // insert before pLine + wxFileConfigLineList *pNext = pLine->Next(); + pNewLine->SetNext(pNext); + pNewLine->SetPrev(pLine); + pNext->SetPrev(pNewLine); + pLine->SetNext(pNewLine); + } + + wxLogTrace( FILECONF_TRACE_MASK, + _T(" head: %s"), + ((m_linesHead) ? m_linesHead->Text().c_str() : wxEmptyString) ); + wxLogTrace( FILECONF_TRACE_MASK, + _T(" tail: %s"), + ((m_linesTail) ? m_linesTail->Text().c_str() : wxEmptyString) ); + + return pNewLine; +} + +void wxFileConfig::LineListRemove(wxFileConfigLineList *pLine) +{ + wxLogTrace( FILECONF_TRACE_MASK, + _T(" ** Removing Line '%s'"), + pLine->Text().c_str() ); + wxLogTrace( FILECONF_TRACE_MASK, + _T(" head: %s"), + ((m_linesHead) ? m_linesHead->Text().c_str() : wxEmptyString) ); + wxLogTrace( FILECONF_TRACE_MASK, + _T(" tail: %s"), + ((m_linesTail) ? m_linesTail->Text().c_str() : wxEmptyString) ); + + wxFileConfigLineList *pPrev = pLine->Prev(), + *pNext = pLine->Next(); + + // first entry? + + if ( pPrev == NULL ) + m_linesHead = pNext; + else + pPrev->SetNext(pNext); + + // last entry? + + if ( pNext == NULL ) + m_linesTail = pPrev; + else + pNext->SetPrev(pPrev); + + if ( m_pRootGroup->GetGroupLine() == pLine ) + m_pRootGroup->SetLine(m_linesHead); + + wxLogTrace( FILECONF_TRACE_MASK, + _T(" head: %s"), + ((m_linesHead) ? m_linesHead->Text().c_str() : wxEmptyString) ); + wxLogTrace( FILECONF_TRACE_MASK, + _T(" tail: %s"), + ((m_linesTail) ? m_linesTail->Text().c_str() : wxEmptyString) ); + + delete pLine; +} + +bool wxFileConfig::LineListIsEmpty() +{ + return m_linesHead == NULL; +} + +// ============================================================================ +// wxFileConfig::wxFileConfigGroup +// ============================================================================ + +// ---------------------------------------------------------------------------- +// ctor/dtor +// ---------------------------------------------------------------------------- + +// ctor +wxFileConfigGroup::wxFileConfigGroup(wxFileConfigGroup *pParent, + const wxString& strName, + wxFileConfig *pConfig) + : m_aEntries(CompareEntries), + m_aSubgroups(CompareGroups), + m_strName(strName) +{ + m_pConfig = pConfig; + m_pParent = pParent; + m_pLine = NULL; + + m_pLastEntry = NULL; + m_pLastGroup = NULL; +} + +// dtor deletes all children +wxFileConfigGroup::~wxFileConfigGroup() +{ + // entries + size_t n, nCount = m_aEntries.Count(); + for ( n = 0; n < nCount; n++ ) + delete m_aEntries[n]; + + // subgroups + nCount = m_aSubgroups.Count(); + for ( n = 0; n < nCount; n++ ) + delete m_aSubgroups[n]; +} + +// ---------------------------------------------------------------------------- +// line +// ---------------------------------------------------------------------------- + +void wxFileConfigGroup::SetLine(wxFileConfigLineList *pLine) +{ + // for a normal (i.e. not root) group this method shouldn't be called twice + // unless we are resetting the line + wxASSERT_MSG( !m_pParent || !m_pLine || !pLine, + _T("changing line for a non-root group?") ); + + m_pLine = pLine; +} + +/* + This is a bit complicated, so let me explain it in details. All lines that + were read from the local file (the only one we will ever modify) are stored + in a (doubly) linked list. Our problem is to know at which position in this + list should we insert the new entries/subgroups. To solve it we keep three + variables for each group: m_pLine, m_pLastEntry and m_pLastGroup. + + m_pLine points to the line containing "[group_name]" + m_pLastEntry points to the last entry of this group in the local file. + m_pLastGroup subgroup + + Initially, they're NULL all three. When the group (an entry/subgroup) is read + from the local file, the corresponding variable is set. However, if the group + was read from the global file and then modified or created by the application + these variables are still NULL and we need to create the corresponding lines. + See the following functions (and comments preceding them) for the details of + how we do it. + + Also, when our last entry/group are deleted we need to find the new last + element - the code in DeleteEntry/Subgroup does this by backtracking the list + of lines until it either founds an entry/subgroup (and this is the new last + element) or the m_pLine of the group, in which case there are no more entries + (or subgroups) left and m_pLast becomes NULL. + + NB: This last problem could be avoided for entries if we added new entries + immediately after m_pLine, but in this case the entries would appear + backwards in the config file (OTOH, it's not that important) and as we + would still need to do it for the subgroups the code wouldn't have been + significantly less complicated. +*/ + +// Return the line which contains "[our name]". If we're still not in the list, +// add our line to it immediately after the last line of our parent group if we +// have it or in the very beginning if we're the root group. +wxFileConfigLineList *wxFileConfigGroup::GetGroupLine() +{ + wxLogTrace( FILECONF_TRACE_MASK, + _T(" GetGroupLine() for Group '%s'"), + Name().c_str() ); + + if ( !m_pLine ) + { + wxLogTrace( FILECONF_TRACE_MASK, + _T(" Getting Line item pointer") ); + + wxFileConfigGroup *pParent = Parent(); + + // this group wasn't present in local config file, add it now + if ( pParent ) + { + wxLogTrace( FILECONF_TRACE_MASK, + _T(" checking parent '%s'"), + pParent->Name().c_str() ); + + wxString strFullName; + + // add 1 to the name because we don't want to start with '/' + strFullName << wxT("[") + << FilterOutEntryName(GetFullName().c_str() + 1) + << wxT("]"); + m_pLine = m_pConfig->LineListInsert(strFullName, + pParent->GetLastGroupLine()); + pParent->SetLastGroup(this); // we're surely after all the others + } + //else: this is the root group and so we return NULL because we don't + // have any group line + } + + return m_pLine; +} + +// Return the last line belonging to the subgroups of this group (after which +// we can add a new subgroup), if we don't have any subgroups or entries our +// last line is the group line (m_pLine) itself. +wxFileConfigLineList *wxFileConfigGroup::GetLastGroupLine() +{ + // if we have any subgroups, our last line is the last line of the last + // subgroup + if ( m_pLastGroup ) + { + wxFileConfigLineList *pLine = m_pLastGroup->GetLastGroupLine(); + + wxASSERT_MSG( pLine, _T("last group must have !NULL associated line") ); + + return pLine; + } + + // no subgroups, so the last line is the line of thelast entry (if any) + return GetLastEntryLine(); +} + +// return the last line belonging to the entries of this group (after which +// we can add a new entry), if we don't have any entries we will add the new +// one immediately after the group line itself. +wxFileConfigLineList *wxFileConfigGroup::GetLastEntryLine() +{ + wxLogTrace( FILECONF_TRACE_MASK, + _T(" GetLastEntryLine() for Group '%s'"), + Name().c_str() ); + + if ( m_pLastEntry ) + { + wxFileConfigLineList *pLine = m_pLastEntry->GetLine(); + + wxASSERT_MSG( pLine, _T("last entry must have !NULL associated line") ); + + return pLine; + } + + // no entries: insert after the group header, if any + return GetGroupLine(); +} + +void wxFileConfigGroup::SetLastEntry(wxFileConfigEntry *pEntry) +{ + m_pLastEntry = pEntry; + + if ( !m_pLine ) + { + // the only situation in which a group without its own line can have + // an entry is when the first entry is added to the initially empty + // root pseudo-group + wxASSERT_MSG( !m_pParent, _T("unexpected for non root group") ); + + // let the group know that it does have a line in the file now + m_pLine = pEntry->GetLine(); + } +} + +// ---------------------------------------------------------------------------- +// group name +// ---------------------------------------------------------------------------- + +void wxFileConfigGroup::UpdateGroupAndSubgroupsLines() +{ + // update the line of this group + wxFileConfigLineList *line = GetGroupLine(); + wxCHECK_RET( line, _T("a non root group must have a corresponding line!") ); + + // +1: skip the leading '/' + line->SetText(wxString::Format(_T("[%s]"), GetFullName().c_str() + 1)); + + + // also update all subgroups as they have this groups name in their lines + const size_t nCount = m_aSubgroups.Count(); + for ( size_t n = 0; n < nCount; n++ ) + { + m_aSubgroups[n]->UpdateGroupAndSubgroupsLines(); + } +} + +void wxFileConfigGroup::Rename(const wxString& newName) +{ + wxCHECK_RET( m_pParent, _T("the root group can't be renamed") ); + + if ( newName == m_strName ) + return; + + // we need to remove the group from the parent and it back under the new + // name to keep the parents array of subgroups alphabetically sorted + m_pParent->m_aSubgroups.Remove(this); + + m_strName = newName; + + m_pParent->m_aSubgroups.Add(this); + + // update the group lines recursively + UpdateGroupAndSubgroupsLines(); +} + +wxString wxFileConfigGroup::GetFullName() const +{ + wxString fullname; + if ( Parent() ) + fullname = Parent()->GetFullName() + wxCONFIG_PATH_SEPARATOR + Name(); + + return fullname; +} + +// ---------------------------------------------------------------------------- +// find an item +// ---------------------------------------------------------------------------- + +// use binary search because the array is sorted +wxFileConfigEntry * +wxFileConfigGroup::FindEntry(const wxChar *szName) const +{ + size_t i, + lo = 0, + hi = m_aEntries.Count(); + int res; + wxFileConfigEntry *pEntry; + + while ( lo < hi ) { + i = (lo + hi)/2; + pEntry = m_aEntries[i]; + + #if wxCONFIG_CASE_SENSITIVE + res = wxStrcmp(pEntry->Name(), szName); + #else + res = wxStricmp(pEntry->Name(), szName); + #endif + + if ( res > 0 ) + hi = i; + else if ( res < 0 ) + lo = i + 1; + else + return pEntry; + } + + return NULL; +} + +wxFileConfigGroup * +wxFileConfigGroup::FindSubgroup(const wxChar *szName) const +{ + size_t i, + lo = 0, + hi = m_aSubgroups.Count(); + int res; + wxFileConfigGroup *pGroup; + + while ( lo < hi ) { + i = (lo + hi)/2; + pGroup = m_aSubgroups[i]; + + #if wxCONFIG_CASE_SENSITIVE + res = wxStrcmp(pGroup->Name(), szName); + #else + res = wxStricmp(pGroup->Name(), szName); + #endif + + if ( res > 0 ) + hi = i; + else if ( res < 0 ) + lo = i + 1; + else + return pGroup; + } + + return NULL; +} + +// ---------------------------------------------------------------------------- +// create a new item +// ---------------------------------------------------------------------------- + +// create a new entry and add it to the current group +wxFileConfigEntry *wxFileConfigGroup::AddEntry(const wxString& strName, int nLine) +{ + wxASSERT( FindEntry(strName) == 0 ); + + wxFileConfigEntry *pEntry = new wxFileConfigEntry(this, strName, nLine); + + m_aEntries.Add(pEntry); + return pEntry; +} + +// create a new group and add it to the current group +wxFileConfigGroup *wxFileConfigGroup::AddSubgroup(const wxString& strName) +{ + wxASSERT( FindSubgroup(strName) == 0 ); + + wxFileConfigGroup *pGroup = new wxFileConfigGroup(this, strName, m_pConfig); + + m_aSubgroups.Add(pGroup); + return pGroup; +} + +// ---------------------------------------------------------------------------- +// delete an item +// ---------------------------------------------------------------------------- + +/* + The delete operations are _very_ slow if we delete the last item of this + group (see comments before GetXXXLineXXX functions for more details), + so it's much better to start with the first entry/group if we want to + delete several of them. + */ + +bool wxFileConfigGroup::DeleteSubgroupByName(const wxChar *szName) +{ + wxFileConfigGroup * const pGroup = FindSubgroup(szName); + + return pGroup ? DeleteSubgroup(pGroup) : false; +} + +// Delete the subgroup and remove all references to it from +// other data structures. +bool wxFileConfigGroup::DeleteSubgroup(wxFileConfigGroup *pGroup) +{ + wxCHECK_MSG( pGroup, false, _T("deleting non existing group?") ); + + wxLogTrace( FILECONF_TRACE_MASK, + _T("Deleting group '%s' from '%s'"), + pGroup->Name().c_str(), + Name().c_str() ); + + wxLogTrace( FILECONF_TRACE_MASK, + _T(" (m_pLine) = prev: %p, this %p, next %p"), + m_pLine ? wx_static_cast(void*, m_pLine->Prev()) : 0, + wx_static_cast(void*, m_pLine), + m_pLine ? wx_static_cast(void*, m_pLine->Next()) : 0 ); + wxLogTrace( FILECONF_TRACE_MASK, + _T(" text: '%s'"), + m_pLine ? m_pLine->Text().c_str() : wxEmptyString ); + + // delete all entries... + size_t nCount = pGroup->m_aEntries.Count(); + + wxLogTrace(FILECONF_TRACE_MASK, + _T("Removing %lu entries"), (unsigned long)nCount ); + + for ( size_t nEntry = 0; nEntry < nCount; nEntry++ ) + { + wxFileConfigLineList *pLine = pGroup->m_aEntries[nEntry]->GetLine(); + + if ( pLine ) + { + wxLogTrace( FILECONF_TRACE_MASK, + _T(" '%s'"), + pLine->Text().c_str() ); + m_pConfig->LineListRemove(pLine); + } + } + + // ...and subgroups of this subgroup + nCount = pGroup->m_aSubgroups.Count(); + + wxLogTrace( FILECONF_TRACE_MASK, + _T("Removing %lu subgroups"), (unsigned long)nCount ); + + for ( size_t nGroup = 0; nGroup < nCount; nGroup++ ) + { + pGroup->DeleteSubgroup(pGroup->m_aSubgroups[0]); + } + + // and then finally the group itself + wxFileConfigLineList *pLine = pGroup->m_pLine; + if ( pLine ) + { + wxLogTrace( FILECONF_TRACE_MASK, + _T(" Removing line for group '%s' : '%s'"), + pGroup->Name().c_str(), + pLine->Text().c_str() ); + wxLogTrace( FILECONF_TRACE_MASK, + _T(" Removing from group '%s' : '%s'"), + Name().c_str(), + ((m_pLine) ? m_pLine->Text().c_str() : wxEmptyString) ); + + // notice that we may do this test inside the previous "if" + // because the last entry's line is surely !NULL + if ( pGroup == m_pLastGroup ) + { + wxLogTrace( FILECONF_TRACE_MASK, + _T(" Removing last group") ); + + // our last entry is being deleted, so find the last one which + // stays by going back until we find a subgroup or reach the + // group line + const size_t nSubgroups = m_aSubgroups.Count(); + + m_pLastGroup = NULL; + for ( wxFileConfigLineList *pl = pLine->Prev(); + pl && !m_pLastGroup; + pl = pl->Prev() ) + { + // does this line belong to our subgroup? + for ( size_t n = 0; n < nSubgroups; n++ ) + { + // do _not_ call GetGroupLine! we don't want to add it to + // the local file if it's not already there + if ( m_aSubgroups[n]->m_pLine == pl ) + { + m_pLastGroup = m_aSubgroups[n]; + break; + } + } + + if ( pl == m_pLine ) + break; + } + } + + m_pConfig->LineListRemove(pLine); + } + else + { + wxLogTrace( FILECONF_TRACE_MASK, + _T(" No line entry for Group '%s'?"), + pGroup->Name().c_str() ); + } + + m_aSubgroups.Remove(pGroup); + delete pGroup; + + return true; +} + +bool wxFileConfigGroup::DeleteEntry(const wxChar *szName) +{ + wxFileConfigEntry *pEntry = FindEntry(szName); + if ( !pEntry ) + { + // entry doesn't exist, nothing to do + return false; + } + + wxFileConfigLineList *pLine = pEntry->GetLine(); + if ( pLine != NULL ) { + // notice that we may do this test inside the previous "if" because the + // last entry's line is surely !NULL + if ( pEntry == m_pLastEntry ) { + // our last entry is being deleted - find the last one which stays + wxASSERT( m_pLine != NULL ); // if we have an entry with !NULL pLine... + + // find the previous entry (if any) + wxFileConfigEntry *pNewLast = NULL; + const wxFileConfigLineList * const + pNewLastLine = m_pLastEntry->GetLine()->Prev(); + const size_t nEntries = m_aEntries.GetCount(); + for ( size_t n = 0; n < nEntries; n++ ) { + if ( m_aEntries[n]->GetLine() == pNewLastLine ) { + pNewLast = m_aEntries[n]; + break; + } + } + + // pNewLast can be NULL here -- it's ok and can happen if we have no + // entries left + m_pLastEntry = pNewLast; + } + + m_pConfig->LineListRemove(pLine); + } + + m_aEntries.Remove(pEntry); + delete pEntry; + + return true; +} + +// ============================================================================ +// wxFileConfig::wxFileConfigEntry +// ============================================================================ + +// ---------------------------------------------------------------------------- +// ctor +// ---------------------------------------------------------------------------- +wxFileConfigEntry::wxFileConfigEntry(wxFileConfigGroup *pParent, + const wxString& strName, + int nLine) + : m_strName(strName) +{ + wxASSERT( !strName.empty() ); + + m_pParent = pParent; + m_nLine = nLine; + m_pLine = NULL; + + m_bHasValue = false; + + m_bImmutable = strName[0] == wxCONFIG_IMMUTABLE_PREFIX; + if ( m_bImmutable ) + m_strName.erase(0, 1); // remove first character +} + +// ---------------------------------------------------------------------------- +// set value +// ---------------------------------------------------------------------------- + +void wxFileConfigEntry::SetLine(wxFileConfigLineList *pLine) +{ + if ( m_pLine != NULL ) { + wxLogWarning(_("entry '%s' appears more than once in group '%s'"), + Name().c_str(), m_pParent->GetFullName().c_str()); + } + + m_pLine = pLine; + Group()->SetLastEntry(this); +} + +// second parameter is false if we read the value from file and prevents the +// entry from being marked as 'dirty' +void wxFileConfigEntry::SetValue(const wxString& strValue, bool bUser) +{ + if ( bUser && IsImmutable() ) + { + wxLogWarning( _("attempt to change immutable key '%s' ignored."), + Name().c_str()); + return; + } + + // do nothing if it's the same value: but don't test for it if m_bHasValue + // hadn't been set yet or we'd never write empty values to the file + if ( m_bHasValue && strValue == m_strValue ) + return; + + m_bHasValue = true; + m_strValue = strValue; + + if ( bUser ) + { + wxString strValFiltered; + + if ( Group()->Config()->GetStyle() & wxCONFIG_USE_NO_ESCAPE_CHARACTERS ) + { + strValFiltered = strValue; + } + else { + strValFiltered = FilterOutValue(strValue); + } + + wxString strLine; + strLine << FilterOutEntryName(m_strName) << wxT('=') << strValFiltered; + + if ( m_pLine ) + { + // entry was read from the local config file, just modify the line + m_pLine->SetText(strLine); + } + else // this entry didn't exist in the local file + { + // add a new line to the file: note that line returned by + // GetLastEntryLine() may be NULL if we're in the root group and it + // doesn't have any entries yet, but this is ok as passing NULL + // line to LineListInsert() means to prepend new line to the list + wxFileConfigLineList *line = Group()->GetLastEntryLine(); + m_pLine = Group()->Config()->LineListInsert(strLine, line); + + Group()->SetLastEntry(this); + } + } +} + +// ============================================================================ +// global functions +// ============================================================================ + +// ---------------------------------------------------------------------------- +// compare functions for array sorting +// ---------------------------------------------------------------------------- + +int CompareEntries(wxFileConfigEntry *p1, wxFileConfigEntry *p2) +{ +#if wxCONFIG_CASE_SENSITIVE + return wxStrcmp(p1->Name(), p2->Name()); +#else + return wxStricmp(p1->Name(), p2->Name()); +#endif +} + +int CompareGroups(wxFileConfigGroup *p1, wxFileConfigGroup *p2) +{ +#if wxCONFIG_CASE_SENSITIVE + return wxStrcmp(p1->Name(), p2->Name()); +#else + return wxStricmp(p1->Name(), p2->Name()); +#endif +} + +// ---------------------------------------------------------------------------- +// filter functions +// ---------------------------------------------------------------------------- + +// undo FilterOutValue +static wxString FilterInValue(const wxString& str) +{ + wxString strResult; + strResult.Alloc(str.Len()); + + bool bQuoted = !str.empty() && str[0] == '"'; + + for ( size_t n = bQuoted ? 1 : 0; n < str.Len(); n++ ) { + if ( str[n] == wxT('\\') ) { + switch ( str[++n] ) { + case wxT('n'): + strResult += wxT('\n'); + break; + + case wxT('r'): + strResult += wxT('\r'); + break; + + case wxT('t'): + strResult += wxT('\t'); + break; + + case wxT('\\'): + strResult += wxT('\\'); + break; + + case wxT('"'): + strResult += wxT('"'); + break; + } + } + else { + if ( str[n] != wxT('"') || !bQuoted ) + strResult += str[n]; + else if ( n != str.Len() - 1 ) { + wxLogWarning(_("unexpected \" at position %d in '%s'."), + n, str.c_str()); + } + //else: it's the last quote of a quoted string, ok + } + } + + return strResult; +} + +// quote the string before writing it to file +static wxString FilterOutValue(const wxString& str) +{ + if ( !str ) + return str; + + wxString strResult; + strResult.Alloc(str.Len()); + + // quoting is necessary to preserve spaces in the beginning of the string + bool bQuote = wxIsspace(str[0]) || str[0] == wxT('"'); + + if ( bQuote ) + strResult += wxT('"'); + + wxChar c; + for ( size_t n = 0; n < str.Len(); n++ ) { + switch ( str[n] ) { + case wxT('\n'): + c = wxT('n'); + break; + + case wxT('\r'): + c = wxT('r'); + break; + + case wxT('\t'): + c = wxT('t'); + break; + + case wxT('\\'): + c = wxT('\\'); + break; + + case wxT('"'): + if ( bQuote ) { + c = wxT('"'); + break; + } + //else: fall through + + default: + strResult += str[n]; + continue; // nothing special to do + } + + // we get here only for special characters + strResult << wxT('\\') << c; + } + + if ( bQuote ) + strResult += wxT('"'); + + return strResult; +} + +// undo FilterOutEntryName +static wxString FilterInEntryName(const wxString& str) +{ + wxString strResult; + strResult.Alloc(str.Len()); + + for ( const wxChar *pc = str.c_str(); *pc != '\0'; pc++ ) { + if ( *pc == wxT('\\') ) { + // we need to test it here or we'd skip past the NUL in the loop line + if ( *++pc == _T('\0') ) + break; + } + + strResult += *pc; + } + + return strResult; +} + +// sanitize entry or group name: insert '\\' before any special characters +static wxString FilterOutEntryName(const wxString& str) +{ + wxString strResult; + strResult.Alloc(str.Len()); + + for ( const wxChar *pc = str.c_str(); *pc != wxT('\0'); pc++ ) { + const wxChar c = *pc; + + // we explicitly allow some of "safe" chars and 8bit ASCII characters + // which will probably never have special meaning and with which we can't + // use isalnum() anyhow (in ASCII built, in Unicode it's just fine) + // + // NB: note that wxCONFIG_IMMUTABLE_PREFIX and wxCONFIG_PATH_SEPARATOR + // should *not* be quoted + if ( +#if !wxUSE_UNICODE + ((unsigned char)c < 127) && +#endif // ANSI + !wxIsalnum(c) && !wxStrchr(wxT("@_/-!.*%"), c) ) + { + strResult += wxT('\\'); + } + + strResult += c; + } + + return strResult; +} + +// we can't put ?: in the ctor initializer list because it confuses some +// broken compilers (Borland C++) +static wxString GetAppName(const wxString& appName) +{ + if ( !appName && wxTheApp ) + return wxTheApp->GetAppName(); + else + return appName; +} + +#endif // wxUSE_CONFIG diff --git a/Externals/wxWidgets/src/common/filefn.cpp b/Externals/wxWidgets/src/common/filefn.cpp index a825cb2a32..4a64c2fab8 100644 --- a/Externals/wxWidgets/src/common/filefn.cpp +++ b/Externals/wxWidgets/src/common/filefn.cpp @@ -1,2108 +1,2108 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/filefn.cpp -// Purpose: File- and directory-related functions -// Author: Julian Smart -// Modified by: -// Created: 29/01/98 -// RCS-ID: $Id: filefn.cpp 51858 2008-02-17 09:16:11Z SC $ -// Copyright: (c) 1998 Julian Smart -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#include "wx/filefn.h" - -#ifndef WX_PRECOMP - #include "wx/intl.h" - #include "wx/log.h" - #include "wx/utils.h" -#endif - -#include "wx/file.h" -#include "wx/filename.h" -#include "wx/dir.h" - -#include "wx/tokenzr.h" - -// there are just too many of those... -#ifdef __VISUALC__ - #pragma warning(disable:4706) // assignment within conditional expression -#endif // VC++ - -#include -#include -#include -#include -#if !wxONLY_WATCOM_EARLIER_THAN(1,4) - #if !(defined(_MSC_VER) && (_MSC_VER > 800)) - #include - #endif -#endif - -#if defined(__WXMAC__) - #include "wx/mac/private.h" // includes mac headers -#endif - -#ifdef __WINDOWS__ - #include "wx/msw/private.h" - #include "wx/msw/mslu.h" - - // sys/cygwin.h is needed for cygwin_conv_to_full_win32_path() - // - // note that it must be included after - #ifdef __GNUWIN32__ - #ifdef __CYGWIN__ - #include - #endif - #endif // __GNUWIN32__ - - // io.h is needed for _get_osfhandle() - // Already included by filefn.h for many Windows compilers - #if defined __MWERKS__ || defined __CYGWIN__ - #include - #endif -#endif // __WINDOWS__ - -#if defined(__VMS__) - #include -#endif - -// TODO: Borland probably has _wgetcwd as well? -#ifdef _MSC_VER - #define HAVE_WGETCWD -#endif - -// ---------------------------------------------------------------------------- -// constants -// ---------------------------------------------------------------------------- - -#ifndef _MAXPATHLEN - #define _MAXPATHLEN 1024 -#endif - -#ifdef __WXMAC__ -# include "MoreFilesX.h" -#endif - -// ---------------------------------------------------------------------------- -// private globals -// ---------------------------------------------------------------------------- - -// MT-FIXME: get rid of this horror and all code using it -static wxChar wxFileFunctionsBuffer[4*_MAXPATHLEN]; - -#if defined(__VISAGECPP__) && __IBMCPP__ >= 400 -// -// VisualAge C++ V4.0 cannot have any external linkage const decs -// in headers included by more than one primary source -// -const int wxInvalidOffset = -1; -#endif - -// ---------------------------------------------------------------------------- -// macros -// ---------------------------------------------------------------------------- - -// translate the filenames before passing them to OS functions -#define OS_FILENAME(s) (s.fn_str()) - -// ============================================================================ -// implementation -// ============================================================================ - -// ---------------------------------------------------------------------------- -// wrappers around standard POSIX functions -// ---------------------------------------------------------------------------- - -#ifdef wxNEED_WX_UNISTD_H - -WXDLLEXPORT int wxStat( const wxChar *file_name, wxStructStat *buf ) -{ - return stat( wxConvFile.cWX2MB( file_name ), buf ); -} - -WXDLLEXPORT int wxLstat( const wxChar *file_name, wxStructStat *buf ) -{ - return lstat( wxConvFile.cWX2MB( file_name ), buf ); -} - -WXDLLEXPORT int wxAccess( const wxChar *pathname, int mode ) -{ - return access( wxConvFile.cWX2MB( pathname ), mode ); -} - -WXDLLEXPORT int wxOpen( const wxChar *pathname, int flags, mode_t mode ) -{ - return open( wxConvFile.cWX2MB( pathname ), flags, mode ); -} - -#endif // wxNEED_WX_UNISTD_H - -#if wxUSE_UNICODE && defined __BORLANDC__ \ - && __BORLANDC__ >= 0x550 && __BORLANDC__ <= 0x551 - -// BCC 5.5 and 5.5.1 have a bug in _wopen where files are created read only -// regardless of the mode parameter. This hack works around the problem by -// setting the mode with _wchmod. -// -int wxOpen(const wchar_t *pathname, int flags, mode_t mode) -{ - int moreflags = 0; - - // we only want to fix the mode when the file is actually created, so - // when creating first try doing it O_EXCL so we can tell if the file - // was already there. - if ((flags & O_CREAT) && !(flags & O_EXCL) && (mode & wxS_IWUSR) != 0) - moreflags = O_EXCL; - - int fd = _wopen(pathname, flags | moreflags, mode); - - // the file was actually created and needs fixing - if (fd != -1 && (flags & O_CREAT) != 0 && (mode & wxS_IWUSR) != 0) - { - close(fd); - _wchmod(pathname, mode); - fd = _wopen(pathname, flags & ~(O_EXCL | O_CREAT)); - } - // the open failed, but it may have been because the added O_EXCL stopped - // the opening of an existing file, so try again without. - else if (fd == -1 && moreflags != 0) - { - fd = _wopen(pathname, flags & ~O_CREAT); - } - - return fd; -} - -#endif - -// ---------------------------------------------------------------------------- -// wxPathList -// ---------------------------------------------------------------------------- - -bool wxPathList::Add(const wxString& path) -{ - // add a path separator to force wxFileName to interpret it always as a directory - // (i.e. if we are called with '/home/user' we want to consider it a folder and - // not, as wxFileName would consider, a filename). - wxFileName fn(path + wxFileName::GetPathSeparator()); - - // add only normalized relative/absolute paths - // NB: we won't do wxPATH_NORM_DOTS in order to avoid problems when trying to - // normalize paths which starts with ".." (which can be normalized only if - // we use also wxPATH_NORM_ABSOLUTE - which we don't want to use). - if (!fn.Normalize(wxPATH_NORM_TILDE|wxPATH_NORM_LONG|wxPATH_NORM_ENV_VARS)) - return false; - - wxString toadd = fn.GetPath(); - if (Index(toadd) == wxNOT_FOUND) - wxArrayString::Add(toadd); // do not add duplicates - - return true; -} - -void wxPathList::Add(const wxArrayString &arr) -{ - for (size_t j=0; j < arr.GetCount(); j++) - Add(arr[j]); -} - -// Add paths e.g. from the PATH environment variable -void wxPathList::AddEnvList (const wxString& WXUNUSED_IN_WINCE(envVariable)) -{ - // No environment variables on WinCE -#ifndef __WXWINCE__ - - // The space has been removed from the tokenizers, otherwise a - // path such as "C:\Program Files" would be split into 2 paths: - // "C:\Program" and "Files"; this is true for both Windows and Unix. - - static const wxChar PATH_TOKS[] = -#if defined(__WINDOWS__) || defined(__OS2__) - wxT(";"); // Don't separate with colon in DOS (used for drive) -#else - wxT(":;"); -#endif - - wxString val; - if ( wxGetEnv(envVariable, &val) ) - { - // split into an array of string the value of the env var - wxArrayString arr = wxStringTokenize(val, PATH_TOKS); - WX_APPEND_ARRAY(*this, arr); - } -#endif // !__WXWINCE__ -} - -// Given a full filename (with path), ensure that that file can -// be accessed again USING FILENAME ONLY by adding the path -// to the list if not already there. -bool wxPathList::EnsureFileAccessible (const wxString& path) -{ - return Add(wxPathOnly(path)); -} - -#if WXWIN_COMPATIBILITY_2_6 -bool wxPathList::Member (const wxString& path) const -{ - return Index(path) != wxNOT_FOUND; -} -#endif - -wxString wxPathList::FindValidPath (const wxString& file) const -{ - // normalize the given string as it could be a path + a filename - // and not only a filename - wxFileName fn(file); - wxString strend; - - // NB: normalize without making absolute otherwise calling this function with - // e.g. "b/c.txt" would result in removing the directory 'b' and the for loop - // below would only add to the paths of this list the 'c.txt' part when doing - // the existence checks... - // NB: we don't use wxPATH_NORM_DOTS here, too (see wxPathList::Add for more info) - if (!fn.Normalize(wxPATH_NORM_TILDE|wxPATH_NORM_LONG|wxPATH_NORM_ENV_VARS)) - return wxEmptyString; - - wxASSERT_MSG(!fn.IsDir(), wxT("Cannot search for directories; only for files")); - if (fn.IsAbsolute()) - strend = fn.GetFullName(); // search for the file name and ignore the path part - else - strend = fn.GetFullPath(); - - for (size_t i=0; i 0) - { - if (buffer[i] == wxT('.')) - { - buffer[i] = 0; - break; - } - i --; - } -} - -void wxStripExtension(wxString& buffer) -{ - //RN: Be careful about the handling the case where - //buffer.length() == 0 - for(size_t i = buffer.length() - 1; i != wxString::npos; --i) - { - if (buffer.GetChar(i) == wxT('.')) - { - buffer = buffer.Left(i); - break; - } - } -} - -// Destructive removal of /./ and /../ stuff -wxChar *wxRealPath (wxChar *path) -{ -#ifdef __WXMSW__ - static const wxChar SEP = wxT('\\'); - wxUnix2DosFilename(path); -#else - static const wxChar SEP = wxT('/'); -#endif - if (path[0] && path[1]) { - /* MATTHEW: special case "/./x" */ - wxChar *p; - if (path[2] == SEP && path[1] == wxT('.')) - p = &path[0]; - else - p = &path[2]; - for (; *p; p++) - { - if (*p == SEP) - { - if (p[1] == wxT('.') && p[2] == wxT('.') && (p[3] == SEP || p[3] == wxT('\0'))) - { - wxChar *q; - for (q = p - 1; q >= path && *q != SEP; q--) - { - // Empty - } - - if (q[0] == SEP && (q[1] != wxT('.') || q[2] != wxT('.') || q[3] != SEP) - && (q - 1 <= path || q[-1] != SEP)) - { - wxStrcpy (q, p + 3); - if (path[0] == wxT('\0')) - { - path[0] = SEP; - path[1] = wxT('\0'); - } -#if defined(__WXMSW__) || defined(__OS2__) - /* Check that path[2] is NULL! */ - else if (path[1] == wxT(':') && !path[2]) - { - path[2] = SEP; - path[3] = wxT('\0'); - } -#endif - p = q - 1; - } - } - else if (p[1] == wxT('.') && (p[2] == SEP || p[2] == wxT('\0'))) - wxStrcpy (p, p + 2); - } - } - } - return path; -} - -wxString wxRealPath(const wxString& path) -{ - wxChar *buf1=MYcopystring(path); - wxChar *buf2=wxRealPath(buf1); - wxString buf(buf2); - delete [] buf1; - return buf; -} - - -// Must be destroyed -wxChar *wxCopyAbsolutePath(const wxString& filename) -{ - if (filename.empty()) - return (wxChar *) NULL; - - if (! wxIsAbsolutePath(wxExpandPath(wxFileFunctionsBuffer, filename))) - { - wxString buf = ::wxGetCwd(); - wxChar ch = buf.Last(); -#ifdef __WXMSW__ - if (ch != wxT('\\') && ch != wxT('/')) - buf << wxT("\\"); -#else - if (ch != wxT('/')) - buf << wxT("/"); -#endif - buf << wxFileFunctionsBuffer; - buf = wxRealPath( buf ); - return MYcopystring( buf ); - } - return MYcopystring( wxFileFunctionsBuffer ); -} - -/*- - Handles: - ~/ => home dir - ~user/ => user's home dir - If the environment variable a = "foo" and b = "bar" then: - Unix: - $a => foo - $a$b => foobar - $a.c => foo.c - xxx$a => xxxfoo - ${a}! => foo! - $(b)! => bar! - \$a => \$a - MSDOS: - $a ==> $a - $(a) ==> foo - $(a)$b ==> foo$b - $(a)$(b)==> foobar - test.$$ ==> test.$$ - */ - -/* input name in name, pathname output to buf. */ - -wxChar *wxExpandPath(wxChar *buf, const wxChar *name) -{ - register wxChar *d, *s, *nm; - wxChar lnm[_MAXPATHLEN]; - int q; - - // Some compilers don't like this line. -// const wxChar trimchars[] = wxT("\n \t"); - - wxChar trimchars[4]; - trimchars[0] = wxT('\n'); - trimchars[1] = wxT(' '); - trimchars[2] = wxT('\t'); - trimchars[3] = 0; - -#ifdef __WXMSW__ - const wxChar SEP = wxT('\\'); -#else - const wxChar SEP = wxT('/'); -#endif - buf[0] = wxT('\0'); - if (name == NULL || *name == wxT('\0')) - return buf; - nm = MYcopystring(name); // Make a scratch copy - wxChar *nm_tmp = nm; - - /* Skip leading whitespace and cr */ - while (wxStrchr((wxChar *)trimchars, *nm) != NULL) - nm++; - /* And strip off trailing whitespace and cr */ - s = nm + (q = wxStrlen(nm)) - 1; - while (q-- && wxStrchr((wxChar *)trimchars, *s) != NULL) - *s = wxT('\0'); - - s = nm; - d = lnm; -#ifdef __WXMSW__ - q = FALSE; -#else - q = nm[0] == wxT('\\') && nm[1] == wxT('~'); -#endif - - /* Expand inline environment variables */ -#ifdef __VISAGECPP__ - while (*d) - { - *d++ = *s; - if(*s == wxT('\\')) - { - *(d - 1) = *++s; - if (*d) - { - s++; - continue; - } - else - break; - } - else -#else - while ((*d++ = *s) != 0) { -# ifndef __WXMSW__ - if (*s == wxT('\\')) { - if ((*(d - 1) = *++s)!=0) { - s++; - continue; - } else - break; - } else -# endif -#endif - // No env variables on WinCE -#ifndef __WXWINCE__ -#ifdef __WXMSW__ - if (*s++ == wxT('$') && (*s == wxT('{') || *s == wxT(')'))) -#else - if (*s++ == wxT('$')) -#endif - { - register wxChar *start = d; - register int braces = (*s == wxT('{') || *s == wxT('(')); - register wxChar *value; - while ((*d++ = *s) != 0) - if (braces ? (*s == wxT('}') || *s == wxT(')')) : !(wxIsalnum(*s) || *s == wxT('_')) ) - break; - else - s++; - *--d = 0; - value = wxGetenv(braces ? start + 1 : start); - if (value) { - for ((d = start - 1); (*d++ = *value++) != 0;) - { - // Empty - } - - d--; - if (braces && *s) - s++; - } - } -#endif - // __WXWINCE__ - } - - /* Expand ~ and ~user */ - nm = lnm; - if (nm[0] == wxT('~') && !q) - { - /* prefix ~ */ - if (nm[1] == SEP || nm[1] == 0) - { /* ~/filename */ - // FIXME: wxGetUserHome could return temporary storage in Unicode mode - if ((s = WXSTRINGCAST wxGetUserHome(wxEmptyString)) != NULL) { - if (*++nm) - nm++; - } - } else - { /* ~user/filename */ - register wxChar *nnm; - register wxChar *home; - for (s = nm; *s && *s != SEP; s++) - { - // Empty - } - int was_sep; /* MATTHEW: Was there a separator, or NULL? */ - was_sep = (*s == SEP); - nnm = *s ? s + 1 : s; - *s = 0; - // FIXME: wxGetUserHome could return temporary storage in Unicode mode - if ((home = WXSTRINGCAST wxGetUserHome(wxString(nm + 1))) == NULL) - { - if (was_sep) /* replace only if it was there: */ - *s = SEP; - s = NULL; - } - else - { - nm = nnm; - s = home; - } - } - } - - d = buf; - if (s && *s) { /* MATTHEW: s could be NULL if user '~' didn't exist */ - /* Copy home dir */ - while (wxT('\0') != (*d++ = *s++)) - /* loop */; - // Handle root home - if (d - 1 > buf && *(d - 2) != SEP) - *(d - 1) = SEP; - } - s = nm; - while ((*d++ = *s++) != 0) - { - // Empty - } - delete[] nm_tmp; // clean up alloc - /* Now clean up the buffer */ - return wxRealPath(buf); -} - -/* Contract Paths to be build upon an environment variable - component: - - example: "/usr/openwin/lib", OPENWINHOME --> ${OPENWINHOME}/lib - - The call wxExpandPath can convert these back! - */ -wxChar * -wxContractPath (const wxString& filename, - const wxString& WXUNUSED_IN_WINCE(envname), - const wxString& user) -{ - static wxChar dest[_MAXPATHLEN]; - - if (filename.empty()) - return (wxChar *) NULL; - - wxStrcpy (dest, WXSTRINGCAST filename); -#ifdef __WXMSW__ - wxUnix2DosFilename(dest); -#endif - - // Handle environment - const wxChar *val; -#ifndef __WXWINCE__ - wxChar *tcp; - if (!envname.empty() && (val = wxGetenv (WXSTRINGCAST envname)) != NULL && - (tcp = wxStrstr (dest, val)) != NULL) - { - wxStrcpy (wxFileFunctionsBuffer, tcp + wxStrlen (val)); - *tcp++ = wxT('$'); - *tcp++ = wxT('{'); - wxStrcpy (tcp, WXSTRINGCAST envname); - wxStrcat (tcp, wxT("}")); - wxStrcat (tcp, wxFileFunctionsBuffer); - } -#endif - - // Handle User's home (ignore root homes!) - val = wxGetUserHome (user); - if (!val) - return dest; - - const size_t len = wxStrlen(val); - if (len <= 2) - return dest; - - if (wxStrncmp(dest, val, len) == 0) - { - wxStrcpy(wxFileFunctionsBuffer, wxT("~")); - if (!user.empty()) - wxStrcat(wxFileFunctionsBuffer, (const wxChar*) user); - wxStrcat(wxFileFunctionsBuffer, dest + len); - wxStrcpy (dest, wxFileFunctionsBuffer); - } - - return dest; -} - -// Return just the filename, not the path (basename) -wxChar *wxFileNameFromPath (wxChar *path) -{ - wxString p = path; - wxString n = wxFileNameFromPath(p); - - return path + p.length() - n.length(); -} - -wxString wxFileNameFromPath (const wxString& path) -{ - wxString name, ext; - wxFileName::SplitPath(path, NULL, &name, &ext); - - wxString fullname = name; - if ( !ext.empty() ) - { - fullname << wxFILE_SEP_EXT << ext; - } - - return fullname; -} - -// Return just the directory, or NULL if no directory -wxChar * -wxPathOnly (wxChar *path) -{ - if (path && *path) - { - static wxChar buf[_MAXPATHLEN]; - - // Local copy - wxStrcpy (buf, path); - - int l = wxStrlen(path); - int i = l - 1; - - // Search backward for a backward or forward slash - while (i > -1) - { -#if defined(__WXMAC__) && !defined(__DARWIN__) - // Classic or Carbon CodeWarrior like - // Carbon with Apple DevTools is Unix like - if (path[i] == wxT(':') ) - { - buf[i] = 0; - return buf; - } -#else - // Unix like or Windows - if (path[i] == wxT('/') || path[i] == wxT('\\')) - { - buf[i] = 0; - return buf; - } -#endif -#ifdef __VMS__ - if (path[i] == wxT(']')) - { - buf[i+1] = 0; - return buf; - } -#endif - i --; - } - -#if defined(__WXMSW__) || defined(__OS2__) - // Try Drive specifier - if (wxIsalpha (buf[0]) && buf[1] == wxT(':')) - { - // A:junk --> A:. (since A:.\junk Not A:\junk) - buf[2] = wxT('.'); - buf[3] = wxT('\0'); - return buf; - } -#endif - } - return (wxChar *) NULL; -} - -// Return just the directory, or NULL if no directory -wxString wxPathOnly (const wxString& path) -{ - if (!path.empty()) - { - wxChar buf[_MAXPATHLEN]; - - // Local copy - wxStrcpy (buf, WXSTRINGCAST path); - - int l = path.length(); - int i = l - 1; - - // Search backward for a backward or forward slash - while (i > -1) - { -#if defined(__WXMAC__) && !defined(__DARWIN__) - // Classic or Carbon CodeWarrior like - // Carbon with Apple DevTools is Unix like - if (path[i] == wxT(':') ) - { - buf[i] = 0; - return wxString(buf); - } -#else - // Unix like or Windows - if (path[i] == wxT('/') || path[i] == wxT('\\')) - { - // Don't return an empty string - if (i == 0) - i ++; - buf[i] = 0; - return wxString(buf); - } -#endif -#ifdef __VMS__ - if (path[i] == wxT(']')) - { - buf[i+1] = 0; - return wxString(buf); - } -#endif - i --; - } - -#if defined(__WXMSW__) || defined(__OS2__) - // Try Drive specifier - if (wxIsalpha (buf[0]) && buf[1] == wxT(':')) - { - // A:junk --> A:. (since A:.\junk Not A:\junk) - buf[2] = wxT('.'); - buf[3] = wxT('\0'); - return wxString(buf); - } -#endif - } - return wxEmptyString; -} - -// Utility for converting delimiters in DOS filenames to UNIX style -// and back again - or we get nasty problems with delimiters. -// Also, convert to lower case, since case is significant in UNIX. - -#if defined(__WXMAC__) - -#if TARGET_API_MAC_OSX -#define kDefaultPathStyle kCFURLPOSIXPathStyle -#else -#define kDefaultPathStyle kCFURLHFSPathStyle -#endif - -wxString wxMacFSRefToPath( const FSRef *fsRef , CFStringRef additionalPathComponent ) -{ - CFURLRef fullURLRef; - fullURLRef = CFURLCreateFromFSRef(NULL, fsRef); - if ( additionalPathComponent ) - { - CFURLRef parentURLRef = fullURLRef ; - fullURLRef = CFURLCreateCopyAppendingPathComponent(NULL, parentURLRef, - additionalPathComponent,false); - CFRelease( parentURLRef ) ; - } - CFStringRef cfString = CFURLCopyFileSystemPath(fullURLRef, kDefaultPathStyle); - CFRelease( fullURLRef ) ; - CFMutableStringRef cfMutableString = CFStringCreateMutableCopy(NULL, 0, cfString); - CFRelease( cfString ); - CFStringNormalize(cfMutableString,kCFStringNormalizationFormC); - return wxMacCFStringHolder(cfMutableString).AsString(); -} - -OSStatus wxMacPathToFSRef( const wxString&path , FSRef *fsRef ) -{ - OSStatus err = noErr ; - CFMutableStringRef cfMutableString = CFStringCreateMutableCopy(NULL, 0, wxMacCFStringHolder(path)); - CFStringNormalize(cfMutableString,kCFStringNormalizationFormD); - CFURLRef url = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, cfMutableString , kDefaultPathStyle, false); - CFRelease( cfMutableString ); - if ( NULL != url ) - { - if ( CFURLGetFSRef(url, fsRef) == false ) - err = fnfErr ; - CFRelease( url ) ; - } - else - { - err = fnfErr ; - } - return err ; -} - -wxString wxMacHFSUniStrToString( ConstHFSUniStr255Param uniname ) -{ - CFStringRef cfname = CFStringCreateWithCharacters( kCFAllocatorDefault, - uniname->unicode, - uniname->length ); - CFMutableStringRef cfMutableString = CFStringCreateMutableCopy(NULL, 0, cfname); - CFRelease( cfname ); - CFStringNormalize(cfMutableString,kCFStringNormalizationFormC); - return wxMacCFStringHolder(cfMutableString).AsString() ; -} - -#ifndef __LP64__ - -wxString wxMacFSSpec2MacFilename( const FSSpec *spec ) -{ - FSRef fsRef ; - if ( FSpMakeFSRef( spec , &fsRef) == noErr ) - { - return wxMacFSRefToPath( &fsRef ) ; - } - return wxEmptyString ; -} - -void wxMacFilename2FSSpec( const wxString& path , FSSpec *spec ) -{ - OSStatus err = noErr ; - FSRef fsRef ; - wxMacPathToFSRef( path , &fsRef ) ; - err = FSRefMakeFSSpec( &fsRef , spec ) ; -} -#endif - -#endif // __WXMAC__ - -void -wxDos2UnixFilename (wxChar *s) -{ - if (s) - while (*s) - { - if (*s == _T('\\')) - *s = _T('/'); -#ifdef __WXMSW__ - else - *s = (wxChar)wxTolower (*s); // Case INDEPENDENT -#endif - s++; - } -} - -void -#if defined(__WXMSW__) || defined(__OS2__) -wxUnix2DosFilename (wxChar *s) -#else -wxUnix2DosFilename (wxChar *WXUNUSED(s) ) -#endif -{ -// Yes, I really mean this to happen under DOS only! JACS -#if defined(__WXMSW__) || defined(__OS2__) - if (s) - while (*s) - { - if (*s == wxT('/')) - *s = wxT('\\'); - s++; - } -#endif -} - -// Concatenate two files to form third -bool -wxConcatFiles (const wxString& file1, const wxString& file2, const wxString& file3) -{ -#if wxUSE_FILE - - wxFile in1(file1), in2(file2); - wxTempFile out(file3); - - if ( !in1.IsOpened() || !in2.IsOpened() || !out.IsOpened() ) - return false; - - ssize_t ofs; - unsigned char buf[1024]; - - for( int i=0; i<2; i++) - { - wxFile *in = i==0 ? &in1 : &in2; - do{ - if ( (ofs = in->Read(buf,WXSIZEOF(buf))) == wxInvalidOffset ) return false; - if ( ofs > 0 ) - if ( !out.Write(buf,ofs) ) - return false; - } while ( ofs == (ssize_t)WXSIZEOF(buf) ); - } - - return out.Commit(); - -#else - - wxUnusedVar(file1); - wxUnusedVar(file2); - wxUnusedVar(file3); - return false; - -#endif -} - -// Copy files -bool -wxCopyFile (const wxString& file1, const wxString& file2, bool overwrite) -{ -#if defined(__WIN32__) && !defined(__WXMICROWIN__) - // CopyFile() copies file attributes and modification time too, so use it - // instead of our code if available - // - // NB: 3rd parameter is bFailIfExists i.e. the inverse of overwrite - if ( !::CopyFile(file1, file2, !overwrite) ) - { - wxLogSysError(_("Failed to copy the file '%s' to '%s'"), - file1.c_str(), file2.c_str()); - - return false; - } -#elif defined(__OS2__) - if ( ::DosCopy((PSZ)file1.c_str(), (PSZ)file2.c_str(), overwrite ? DCPY_EXISTING : 0) != 0 ) - return false; -#elif defined(__PALMOS__) - // TODO with http://www.palmos.com/dev/support/docs/protein_books/Memory_Databases_Files/ - return false; -#elif wxUSE_FILE // !Win32 - - wxStructStat fbuf; - // get permissions of file1 - if ( wxStat( file1.c_str(), &fbuf) != 0 ) - { - // the file probably doesn't exist or we haven't the rights to read - // from it anyhow - wxLogSysError(_("Impossible to get permissions for file '%s'"), - file1.c_str()); - return false; - } - - // open file1 for reading - wxFile fileIn(file1, wxFile::read); - if ( !fileIn.IsOpened() ) - return false; - - // remove file2, if it exists. This is needed for creating - // file2 with the correct permissions in the next step - if ( wxFileExists(file2) && (!overwrite || !wxRemoveFile(file2))) - { - wxLogSysError(_("Impossible to overwrite the file '%s'"), - file2.c_str()); - return false; - } - - // reset the umask as we want to create the file with exactly the same - // permissions as the original one - wxCHANGE_UMASK(0); - - // create file2 with the same permissions than file1 and open it for - // writing - - wxFile fileOut; - if ( !fileOut.Create(file2, overwrite, fbuf.st_mode & 0777) ) - return false; - - // copy contents of file1 to file2 - char buf[4096]; - size_t count; - for ( ;; ) - { - count = fileIn.Read(buf, WXSIZEOF(buf)); - if ( fileIn.Error() ) - return false; - - // end of file? - if ( !count ) - break; - - if ( fileOut.Write(buf, count) < count ) - return false; - } - - // we can expect fileIn to be closed successfully, but we should ensure - // that fileOut was closed as some write errors (disk full) might not be - // detected before doing this - if ( !fileIn.Close() || !fileOut.Close() ) - return false; - -#if !defined(__VISAGECPP__) && !defined(__WXMAC__) || defined(__UNIX__) - // no chmod in VA. Should be some permission API for HPFS386 partitions - // however - if ( chmod(OS_FILENAME(file2), fbuf.st_mode) != 0 ) - { - wxLogSysError(_("Impossible to set permissions for the file '%s'"), - file2.c_str()); - return false; - } -#endif // OS/2 || Mac - -#else // !Win32 && ! wxUSE_FILE - - // impossible to simulate with wxWidgets API - wxUnusedVar(file1); - wxUnusedVar(file2); - wxUnusedVar(overwrite); - return false; - -#endif // __WXMSW__ && __WIN32__ - - return true; -} - -bool -wxRenameFile(const wxString& file1, const wxString& file2, bool overwrite) -{ - if ( !overwrite && wxFileExists(file2) ) - { - wxLogSysError - ( - _("Failed to rename the file '%s' to '%s' because the destination file already exists."), - file1.c_str(), file2.c_str() - ); - - return false; - } - -#if !defined(__WXWINCE__) && !defined(__WXPALMOS__) - // Normal system call - if ( wxRename (file1, file2) == 0 ) - return true; -#endif - - // Try to copy - if (wxCopyFile(file1, file2, overwrite)) { - wxRemoveFile(file1); - return true; - } - // Give up - return false; -} - -bool wxRemoveFile(const wxString& file) -{ -#if defined(__VISUALC__) \ - || defined(__BORLANDC__) \ - || defined(__WATCOMC__) \ - || defined(__DMC__) \ - || defined(__GNUWIN32__) \ - || (defined(__MWERKS__) && defined(__MSL__)) - int res = wxRemove(file); -#elif defined(__WXMAC__) - int res = unlink(wxFNCONV(file)); -#elif defined(__WXPALMOS__) - int res = 1; - // TODO with VFSFileDelete() -#else - int res = unlink(OS_FILENAME(file)); -#endif - - return res == 0; -} - -bool wxMkdir(const wxString& dir, int perm) -{ -#if defined(__WXPALMOS__) - return false; -#elif defined(__WXMAC__) && !defined(__UNIX__) - return (mkdir( wxFNCONV(dir) , 0 ) == 0); -#else // !Mac - const wxChar *dirname = dir.c_str(); - - // assume mkdir() has 2 args on non Windows-OS/2 platforms and on Windows too - // for the GNU compiler -#if (!(defined(__WXMSW__) || defined(__OS2__) || defined(__DOS__))) || (defined(__GNUWIN32__) && !defined(__MINGW32__)) || defined(__WINE__) || defined(__WXMICROWIN__) - #if defined(MSVCRT) - wxUnusedVar(perm); - if ( mkdir(wxFNCONV(dirname)) != 0 ) - #else - if ( mkdir(wxFNCONV(dirname), perm) != 0 ) - #endif -#elif defined(__OS2__) - wxUnusedVar(perm); - if (::DosCreateDir((PSZ)dirname, NULL) != 0) // enhance for EAB's?? -#elif defined(__DOS__) - #if defined(__WATCOMC__) - (void)perm; - if ( wxMkDir(wxFNSTRINGCAST wxFNCONV(dirname)) != 0 ) - #elif defined(__DJGPP__) - if ( mkdir(wxFNCONV(dirname), perm) != 0 ) - #else - #error "Unsupported DOS compiler!" - #endif -#else // !MSW, !DOS and !OS/2 VAC++ - wxUnusedVar(perm); -#ifdef __WXWINCE__ - if ( !CreateDirectory(dirname, NULL) ) -#else - if ( wxMkDir(dir.fn_str()) != 0 ) -#endif -#endif // !MSW/MSW - { - wxLogSysError(_("Directory '%s' couldn't be created"), dirname); - - return false; - } - - return true; -#endif // Mac/!Mac -} - -bool wxRmdir(const wxString& dir, int WXUNUSED(flags)) -{ -#if defined(__VMS__) - return false; //to be changed since rmdir exists in VMS7.x -#elif defined(__OS2__) - return (::DosDeleteDir((PSZ)dir.c_str()) == 0); -#elif defined(__WXWINCE__) - return (RemoveDirectory(dir) != 0); -#elif defined(__WXPALMOS__) - // TODO with VFSFileRename() - return false; -#else - return (wxRmDir(OS_FILENAME(dir)) == 0); -#endif -} - -// does the path exists? (may have or not '/' or '\\' at the end) -bool wxDirExists(const wxChar *pszPathName) -{ - wxString strPath(pszPathName); - -#if defined(__WINDOWS__) || defined(__OS2__) - // Windows fails to find directory named "c:\dir\" even if "c:\dir" exists, - // so remove all trailing backslashes from the path - but don't do this for - // the paths "d:\" (which are different from "d:") nor for just "\" - while ( wxEndsWithPathSeparator(strPath) ) - { - size_t len = strPath.length(); - if ( len == 1 || (len == 3 && strPath[len - 2] == _T(':')) ) - break; - - strPath.Truncate(len - 1); - } -#endif // __WINDOWS__ - -#ifdef __OS2__ - // OS/2 can't handle "d:", it wants either "d:\" or "d:." - if (strPath.length() == 2 && strPath[1u] == _T(':')) - strPath << _T('.'); -#endif - -#if defined(__WXPALMOS__) - return false; -#elif defined(__WIN32__) && !defined(__WXMICROWIN__) - // stat() can't cope with network paths - DWORD ret = ::GetFileAttributes(strPath); - - return (ret != (DWORD)-1) && (ret & FILE_ATTRIBUTE_DIRECTORY); -#elif defined(__OS2__) - FILESTATUS3 Info = {{0}}; - APIRET rc = ::DosQueryPathInfo((PSZ)(WXSTRINGCAST strPath), FIL_STANDARD, - (void*) &Info, sizeof(FILESTATUS3)); - - return ((rc == NO_ERROR) && (Info.attrFile & FILE_DIRECTORY)) || - (rc == ERROR_SHARING_VIOLATION); - // If we got a sharing violation, there must be something with this name. -#else // !__WIN32__ - - wxStructStat st; -#ifndef __VISAGECPP__ - return wxStat(strPath.c_str(), &st) == 0 && ((st.st_mode & S_IFMT) == S_IFDIR); -#else - // S_IFMT not supported in VA compilers.. st_mode is a 2byte value only - return wxStat(pszPathName, &st) == 0 && (st.st_mode == S_IFDIR); -#endif - -#endif // __WIN32__/!__WIN32__ -} - -// Get a temporary filename, opening and closing the file. -wxChar *wxGetTempFileName(const wxString& prefix, wxChar *buf) -{ - wxString filename; - if ( !wxGetTempFileName(prefix, filename) ) - return NULL; - - if ( buf ) - wxStrcpy(buf, filename); - else - buf = MYcopystring(filename); - - return buf; -} - -bool wxGetTempFileName(const wxString& prefix, wxString& buf) -{ -#if wxUSE_FILE - buf = wxFileName::CreateTempFileName(prefix); - - return !buf.empty(); -#else // !wxUSE_FILE - wxUnusedVar(prefix); - wxUnusedVar(buf); - - return false; -#endif // wxUSE_FILE/!wxUSE_FILE -} - -// Get first file name matching given wild card. - -static wxDir *gs_dir = NULL; -static wxString gs_dirPath; - -wxString wxFindFirstFile(const wxChar *spec, int flags) -{ - wxSplitPath(spec, &gs_dirPath, NULL, NULL); - if ( gs_dirPath.empty() ) - gs_dirPath = wxT("."); - if ( !wxEndsWithPathSeparator(gs_dirPath ) ) - gs_dirPath << wxFILE_SEP_PATH; - - if (gs_dir) - delete gs_dir; - gs_dir = new wxDir(gs_dirPath); - - if ( !gs_dir->IsOpened() ) - { - wxLogSysError(_("Can not enumerate files '%s'"), spec); - return wxEmptyString; - } - - int dirFlags; - switch (flags) - { - case wxDIR: dirFlags = wxDIR_DIRS; break; - case wxFILE: dirFlags = wxDIR_FILES; break; - default: dirFlags = wxDIR_DIRS | wxDIR_FILES; break; - } - - wxString result; - gs_dir->GetFirst(&result, wxFileNameFromPath(wxString(spec)), dirFlags); - if ( result.empty() ) - { - wxDELETE(gs_dir); - return result; - } - - return gs_dirPath + result; -} - -wxString wxFindNextFile() -{ - wxASSERT_MSG( gs_dir, wxT("You must call wxFindFirstFile before!") ); - - wxString result; - gs_dir->GetNext(&result); - - if ( result.empty() ) - { - wxDELETE(gs_dir); - return result; - } - - return gs_dirPath + result; -} - - -// Get current working directory. -// If buf is NULL, allocates space using new, else copies into buf. -// wxGetWorkingDirectory() is obsolete, use wxGetCwd() -// wxDoGetCwd() is their common core to be moved -// to wxGetCwd() once wxGetWorkingDirectory() will be removed. -// Do not expose wxDoGetCwd in headers! - -wxChar *wxDoGetCwd(wxChar *buf, int sz) -{ -#if defined(__WXPALMOS__) - // TODO - if(buf && sz>0) buf[0] = _T('\0'); - return buf; -#elif defined(__WXWINCE__) - // TODO - if(buf && sz>0) buf[0] = _T('\0'); - return buf; -#else - if ( !buf ) - { - buf = new wxChar[sz + 1]; - } - - bool ok wxDUMMY_INITIALIZE(false); - - // for the compilers which have Unicode version of _getcwd(), call it - // directly, for the others call the ANSI version and do the translation -#if !wxUSE_UNICODE - #define cbuf buf -#else // wxUSE_UNICODE - bool needsANSI = true; - - #if !defined(HAVE_WGETCWD) || wxUSE_UNICODE_MSLU - char cbuf[_MAXPATHLEN]; - #endif - - #ifdef HAVE_WGETCWD - #if wxUSE_UNICODE_MSLU - if ( wxGetOsVersion() != wxOS_WINDOWS_9X ) - #else - char *cbuf = NULL; // never really used because needsANSI will always be false - #endif - { - ok = _wgetcwd(buf, sz) != NULL; - needsANSI = false; - } - #endif - - if ( needsANSI ) -#endif // wxUSE_UNICODE - { - #if defined(_MSC_VER) || defined(__MINGW32__) - ok = _getcwd(cbuf, sz) != NULL; - #elif defined(__WXMAC__) && !defined(__DARWIN__) - char lbuf[1024] ; - if ( getcwd( lbuf , sizeof( lbuf ) ) ) - { - wxString res( lbuf , *wxConvCurrent ) ; - wxStrcpy( buf , res ) ; - ok = true; - } - else - ok = false ; - #elif defined(__OS2__) - APIRET rc; - ULONG ulDriveNum = 0; - ULONG ulDriveMap = 0; - rc = ::DosQueryCurrentDisk(&ulDriveNum, &ulDriveMap); - ok = rc == 0; - if (ok) - { - sz -= 3; - rc = ::DosQueryCurrentDir( 0 // current drive - ,cbuf + 3 - ,(PULONG)&sz - ); - cbuf[0] = char('A' + (ulDriveNum - 1)); - cbuf[1] = ':'; - cbuf[2] = '\\'; - ok = rc == 0; - } - #else // !Win32/VC++ !Mac !OS2 - ok = getcwd(cbuf, sz) != NULL; - #endif // platform - - #if wxUSE_UNICODE && !(defined(__WXMAC__) && !defined(__DARWIN__)) - // finally convert the result to Unicode if needed - wxConvFile.MB2WC(buf, cbuf, sz); - #endif // wxUSE_UNICODE - } - - if ( !ok ) - { - wxLogSysError(_("Failed to get the working directory")); - - // VZ: the old code used to return "." on error which didn't make any - // sense at all to me - empty string is a better error indicator - // (NULL might be even better but I'm afraid this could lead to - // problems with the old code assuming the return is never NULL) - buf[0] = _T('\0'); - } - else // ok, but we might need to massage the path into the right format - { -#ifdef __DJGPP__ - // VS: DJGPP is a strange mix of DOS and UNIX API and returns paths - // with / deliminers. We don't like that. - for (wxChar *ch = buf; *ch; ch++) - { - if (*ch == wxT('/')) - *ch = wxT('\\'); - } -#endif // __DJGPP__ - -// MBN: we hope that in the case the user is compiling a GTK+/Motif app, -// he needs Unix as opposed to Win32 pathnames -#if defined( __CYGWIN__ ) && defined( __WINDOWS__ ) - // another example of DOS/Unix mix (Cygwin) - wxString pathUnix = buf; -#if wxUSE_UNICODE - char bufA[_MAXPATHLEN]; - cygwin_conv_to_full_win32_path(pathUnix.mb_str(wxConvFile), bufA); - wxConvFile.MB2WC(buf, bufA, sz); -#else - cygwin_conv_to_full_win32_path(pathUnix, buf); -#endif // wxUSE_UNICODE -#endif // __CYGWIN__ - } - - return buf; - -#if !wxUSE_UNICODE - #undef cbuf -#endif - -#endif - // __WXWINCE__ -} - -#if WXWIN_COMPATIBILITY_2_6 -wxChar *wxGetWorkingDirectory(wxChar *buf, int sz) -{ - return wxDoGetCwd(buf,sz); -} -#endif // WXWIN_COMPATIBILITY_2_6 - -wxString wxGetCwd() -{ - wxString str; - wxDoGetCwd(wxStringBuffer(str, _MAXPATHLEN), _MAXPATHLEN); - return str; -} - -bool wxSetWorkingDirectory(const wxString& d) -{ -#if defined(__OS2__) - if (d[1] == ':') - { - ::DosSetDefaultDisk(1 + wxToupper(d[0]) - _T('A')); - // do not call DosSetCurrentDir when just changing drive, - // since it requires e.g. "d:." instead of "d:"! - if (d.length() == 2) - return true; - } - return (::DosSetCurrentDir((PSZ)d.c_str()) == 0); -#elif defined(__UNIX__) || defined(__WXMAC__) || defined(__DOS__) - return (chdir(wxFNSTRINGCAST d.fn_str()) == 0); -#elif defined(__WINDOWS__) - -#ifdef __WIN32__ -#ifdef __WXWINCE__ - // No equivalent in WinCE - wxUnusedVar(d); - return false; -#else - return (bool)(SetCurrentDirectory(d) != 0); -#endif -#else - // Must change drive, too. - bool isDriveSpec = ((strlen(d) > 1) && (d[1] == ':')); - if (isDriveSpec) - { - wxChar firstChar = d[0]; - - // To upper case - if (firstChar > 90) - firstChar = firstChar - 32; - - // To a drive number - unsigned int driveNo = firstChar - 64; - if (driveNo > 0) - { - unsigned int noDrives; - _dos_setdrive(driveNo, &noDrives); - } - } - bool success = (chdir(WXSTRINGCAST d) == 0); - - return success; -#endif - -#endif -} - -// Get the OS directory if appropriate (such as the Windows directory). -// On non-Windows platform, probably just return the empty string. -wxString wxGetOSDirectory() -{ -#ifdef __WXWINCE__ - return wxString(wxT("\\Windows")); -#elif defined(__WINDOWS__) && !defined(__WXMICROWIN__) - wxChar buf[256]; - GetWindowsDirectory(buf, 256); - return wxString(buf); -#elif defined(__WXMAC__) - return wxMacFindFolder(kOnSystemDisk, 'macs', false); -#else - return wxEmptyString; -#endif -} - -bool wxEndsWithPathSeparator(const wxChar *pszFileName) -{ - size_t len = wxStrlen(pszFileName); - - return len && wxIsPathSeparator(pszFileName[len - 1]); -} - -// find a file in a list of directories, returns false if not found -bool wxFindFileInPath(wxString *pStr, const wxChar *pszPath, const wxChar *pszFile) -{ - // we assume that it's not empty - wxCHECK_MSG( !wxIsEmpty(pszFile), false, - _T("empty file name in wxFindFileInPath")); - - // skip path separator in the beginning of the file name if present - if ( wxIsPathSeparator(*pszFile) ) - pszFile++; - - // copy the path (strtok will modify it) - wxChar *szPath = new wxChar[wxStrlen(pszPath) + 1]; - wxStrcpy(szPath, pszPath); - - wxString strFile; - wxChar *pc, *save_ptr; - for ( pc = wxStrtok(szPath, wxPATH_SEP, &save_ptr); - pc != NULL; - pc = wxStrtok((wxChar *) NULL, wxPATH_SEP, &save_ptr) ) - { - // search for the file in this directory - strFile = pc; - if ( !wxEndsWithPathSeparator(pc) ) - strFile += wxFILE_SEP_PATH; - strFile += pszFile; - - if ( wxFileExists(strFile) ) { - *pStr = strFile; - break; - } - } - - // suppress warning about unused variable save_ptr when wxStrtok() is a - // macro which throws away its third argument - save_ptr = pc; - - delete [] szPath; - - return pc != NULL; // if true => we breaked from the loop -} - -void WXDLLEXPORT wxSplitPath(const wxChar *pszFileName, - wxString *pstrPath, - wxString *pstrName, - wxString *pstrExt) -{ - // it can be empty, but it shouldn't be NULL - wxCHECK_RET( pszFileName, wxT("NULL file name in wxSplitPath") ); - - wxFileName::SplitPath(pszFileName, pstrPath, pstrName, pstrExt); -} - -#if wxUSE_DATETIME - -time_t WXDLLEXPORT wxFileModificationTime(const wxString& filename) -{ - wxDateTime mtime; - if ( !wxFileName(filename).GetTimes(NULL, &mtime, NULL) ) - return (time_t)-1; - - return mtime.GetTicks(); -} - -#endif // wxUSE_DATETIME - - -// Parses the filterStr, returning the number of filters. -// Returns 0 if none or if there's a problem. -// filterStr is in the form: "All files (*.*)|*.*|JPEG Files (*.jpeg)|*.jpeg" - -int WXDLLEXPORT wxParseCommonDialogsFilter(const wxString& filterStr, - wxArrayString& descriptions, - wxArrayString& filters) -{ - descriptions.Clear(); - filters.Clear(); - - wxString str(filterStr); - - wxString description, filter; - int pos = 0; - while( pos != wxNOT_FOUND ) - { - pos = str.Find(wxT('|')); - if ( pos == wxNOT_FOUND ) - { - // if there are no '|'s at all in the string just take the entire - // string as filter and make description empty for later autocompletion - if ( filters.IsEmpty() ) - { - descriptions.Add(wxEmptyString); - filters.Add(filterStr); - } - else - { - wxFAIL_MSG( _T("missing '|' in the wildcard string!") ); - } - - break; - } - - description = str.Left(pos); - str = str.Mid(pos + 1); - pos = str.Find(wxT('|')); - if ( pos == wxNOT_FOUND ) - { - filter = str; - } - else - { - filter = str.Left(pos); - str = str.Mid(pos + 1); - } - - descriptions.Add(description); - filters.Add(filter); - } - -#if defined(__WXMOTIF__) - // split it so there is one wildcard per entry - for( size_t i = 0 ; i < descriptions.GetCount() ; i++ ) - { - pos = filters[i].Find(wxT(';')); - if (pos != wxNOT_FOUND) - { - // first split only filters - descriptions.Insert(descriptions[i],i+1); - filters.Insert(filters[i].Mid(pos+1),i+1); - filters[i]=filters[i].Left(pos); - - // autoreplace new filter in description with pattern: - // C/C++ Files(*.cpp;*.c;*.h)|*.cpp;*.c;*.h - // cause split into: - // C/C++ Files(*.cpp)|*.cpp - // C/C++ Files(*.c;*.h)|*.c;*.h - // and next iteration cause another split into: - // C/C++ Files(*.cpp)|*.cpp - // C/C++ Files(*.c)|*.c - // C/C++ Files(*.h)|*.h - for ( size_t k=i;kbefore.Find(_T(')'),true)) - { - before = before.Left(pos+1); - before << filters[k]; - pos = after.Find(_T(')')); - int pos1 = after.Find(_T('(')); - if (pos != wxNOT_FOUND && (pos -* -* The match procedure is public domain code (from ircII's reg.c) -* but modified to suit our tastes (RN: No "%" syntax I guess) -*/ - -bool wxMatchWild( const wxString& pat, const wxString& text, bool dot_special ) -{ - if (text.empty()) - { - /* Match if both are empty. */ - return pat.empty(); - } - - const wxChar *m = pat.c_str(), - *n = text.c_str(), - *ma = NULL, - *na = NULL; - int just = 0, - acount = 0, - count = 0; - - if (dot_special && (*n == wxT('.'))) - { - /* Never match so that hidden Unix files - * are never found. */ - return false; - } - - for (;;) - { - if (*m == wxT('*')) - { - ma = ++m; - na = n; - just = 1; - acount = count; - } - else if (*m == wxT('?')) - { - m++; - if (!*n++) - return false; - } - else - { - if (*m == wxT('\\')) - { - m++; - /* Quoting "nothing" is a bad thing */ - if (!*m) - return false; - } - if (!*m) - { - /* - * If we are out of both strings or we just - * saw a wildcard, then we can say we have a - * match - */ - if (!*n) - return true; - if (just) - return true; - just = 0; - goto not_matched; - } - /* - * We could check for *n == NULL at this point, but - * since it's more common to have a character there, - * check to see if they match first (m and n) and - * then if they don't match, THEN we can check for - * the NULL of n - */ - just = 0; - if (*m == *n) - { - m++; - count++; - n++; - } - else - { - - not_matched: - - /* - * If there are no more characters in the - * string, but we still need to find another - * character (*m != NULL), then it will be - * impossible to match it - */ - if (!*n) - return false; - - if (ma) - { - m = ma; - n = ++na; - count = acount; - } - else - return false; - } - } - } -} - -#ifdef __VISUALC__ - #pragma warning(default:4706) // assignment within conditional expression -#endif // VC++ +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/filefn.cpp +// Purpose: File- and directory-related functions +// Author: Julian Smart +// Modified by: +// Created: 29/01/98 +// RCS-ID: $Id: filefn.cpp 51858 2008-02-17 09:16:11Z SC $ +// Copyright: (c) 1998 Julian Smart +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#include "wx/filefn.h" + +#ifndef WX_PRECOMP + #include "wx/intl.h" + #include "wx/log.h" + #include "wx/utils.h" +#endif + +#include "wx/file.h" +#include "wx/filename.h" +#include "wx/dir.h" + +#include "wx/tokenzr.h" + +// there are just too many of those... +#ifdef __VISUALC__ + #pragma warning(disable:4706) // assignment within conditional expression +#endif // VC++ + +#include +#include +#include +#include +#if !wxONLY_WATCOM_EARLIER_THAN(1,4) + #if !(defined(_MSC_VER) && (_MSC_VER > 800)) + #include + #endif +#endif + +#if defined(__WXMAC__) + #include "wx/mac/private.h" // includes mac headers +#endif + +#ifdef __WINDOWS__ + #include "wx/msw/private.h" + #include "wx/msw/mslu.h" + + // sys/cygwin.h is needed for cygwin_conv_to_full_win32_path() + // + // note that it must be included after + #ifdef __GNUWIN32__ + #ifdef __CYGWIN__ + #include + #endif + #endif // __GNUWIN32__ + + // io.h is needed for _get_osfhandle() + // Already included by filefn.h for many Windows compilers + #if defined __MWERKS__ || defined __CYGWIN__ + #include + #endif +#endif // __WINDOWS__ + +#if defined(__VMS__) + #include +#endif + +// TODO: Borland probably has _wgetcwd as well? +#ifdef _MSC_VER + #define HAVE_WGETCWD +#endif + +// ---------------------------------------------------------------------------- +// constants +// ---------------------------------------------------------------------------- + +#ifndef _MAXPATHLEN + #define _MAXPATHLEN 1024 +#endif + +#ifdef __WXMAC__ +# include "MoreFilesX.h" +#endif + +// ---------------------------------------------------------------------------- +// private globals +// ---------------------------------------------------------------------------- + +// MT-FIXME: get rid of this horror and all code using it +static wxChar wxFileFunctionsBuffer[4*_MAXPATHLEN]; + +#if defined(__VISAGECPP__) && __IBMCPP__ >= 400 +// +// VisualAge C++ V4.0 cannot have any external linkage const decs +// in headers included by more than one primary source +// +const int wxInvalidOffset = -1; +#endif + +// ---------------------------------------------------------------------------- +// macros +// ---------------------------------------------------------------------------- + +// translate the filenames before passing them to OS functions +#define OS_FILENAME(s) (s.fn_str()) + +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// wrappers around standard POSIX functions +// ---------------------------------------------------------------------------- + +#ifdef wxNEED_WX_UNISTD_H + +WXDLLEXPORT int wxStat( const wxChar *file_name, wxStructStat *buf ) +{ + return stat( wxConvFile.cWX2MB( file_name ), buf ); +} + +WXDLLEXPORT int wxLstat( const wxChar *file_name, wxStructStat *buf ) +{ + return lstat( wxConvFile.cWX2MB( file_name ), buf ); +} + +WXDLLEXPORT int wxAccess( const wxChar *pathname, int mode ) +{ + return access( wxConvFile.cWX2MB( pathname ), mode ); +} + +WXDLLEXPORT int wxOpen( const wxChar *pathname, int flags, mode_t mode ) +{ + return open( wxConvFile.cWX2MB( pathname ), flags, mode ); +} + +#endif // wxNEED_WX_UNISTD_H + +#if wxUSE_UNICODE && defined __BORLANDC__ \ + && __BORLANDC__ >= 0x550 && __BORLANDC__ <= 0x551 + +// BCC 5.5 and 5.5.1 have a bug in _wopen where files are created read only +// regardless of the mode parameter. This hack works around the problem by +// setting the mode with _wchmod. +// +int wxOpen(const wchar_t *pathname, int flags, mode_t mode) +{ + int moreflags = 0; + + // we only want to fix the mode when the file is actually created, so + // when creating first try doing it O_EXCL so we can tell if the file + // was already there. + if ((flags & O_CREAT) && !(flags & O_EXCL) && (mode & wxS_IWUSR) != 0) + moreflags = O_EXCL; + + int fd = _wopen(pathname, flags | moreflags, mode); + + // the file was actually created and needs fixing + if (fd != -1 && (flags & O_CREAT) != 0 && (mode & wxS_IWUSR) != 0) + { + close(fd); + _wchmod(pathname, mode); + fd = _wopen(pathname, flags & ~(O_EXCL | O_CREAT)); + } + // the open failed, but it may have been because the added O_EXCL stopped + // the opening of an existing file, so try again without. + else if (fd == -1 && moreflags != 0) + { + fd = _wopen(pathname, flags & ~O_CREAT); + } + + return fd; +} + +#endif + +// ---------------------------------------------------------------------------- +// wxPathList +// ---------------------------------------------------------------------------- + +bool wxPathList::Add(const wxString& path) +{ + // add a path separator to force wxFileName to interpret it always as a directory + // (i.e. if we are called with '/home/user' we want to consider it a folder and + // not, as wxFileName would consider, a filename). + wxFileName fn(path + wxFileName::GetPathSeparator()); + + // add only normalized relative/absolute paths + // NB: we won't do wxPATH_NORM_DOTS in order to avoid problems when trying to + // normalize paths which starts with ".." (which can be normalized only if + // we use also wxPATH_NORM_ABSOLUTE - which we don't want to use). + if (!fn.Normalize(wxPATH_NORM_TILDE|wxPATH_NORM_LONG|wxPATH_NORM_ENV_VARS)) + return false; + + wxString toadd = fn.GetPath(); + if (Index(toadd) == wxNOT_FOUND) + wxArrayString::Add(toadd); // do not add duplicates + + return true; +} + +void wxPathList::Add(const wxArrayString &arr) +{ + for (size_t j=0; j < arr.GetCount(); j++) + Add(arr[j]); +} + +// Add paths e.g. from the PATH environment variable +void wxPathList::AddEnvList (const wxString& WXUNUSED_IN_WINCE(envVariable)) +{ + // No environment variables on WinCE +#ifndef __WXWINCE__ + + // The space has been removed from the tokenizers, otherwise a + // path such as "C:\Program Files" would be split into 2 paths: + // "C:\Program" and "Files"; this is true for both Windows and Unix. + + static const wxChar PATH_TOKS[] = +#if defined(__WINDOWS__) || defined(__OS2__) + wxT(";"); // Don't separate with colon in DOS (used for drive) +#else + wxT(":;"); +#endif + + wxString val; + if ( wxGetEnv(envVariable, &val) ) + { + // split into an array of string the value of the env var + wxArrayString arr = wxStringTokenize(val, PATH_TOKS); + WX_APPEND_ARRAY(*this, arr); + } +#endif // !__WXWINCE__ +} + +// Given a full filename (with path), ensure that that file can +// be accessed again USING FILENAME ONLY by adding the path +// to the list if not already there. +bool wxPathList::EnsureFileAccessible (const wxString& path) +{ + return Add(wxPathOnly(path)); +} + +#if WXWIN_COMPATIBILITY_2_6 +bool wxPathList::Member (const wxString& path) const +{ + return Index(path) != wxNOT_FOUND; +} +#endif + +wxString wxPathList::FindValidPath (const wxString& file) const +{ + // normalize the given string as it could be a path + a filename + // and not only a filename + wxFileName fn(file); + wxString strend; + + // NB: normalize without making absolute otherwise calling this function with + // e.g. "b/c.txt" would result in removing the directory 'b' and the for loop + // below would only add to the paths of this list the 'c.txt' part when doing + // the existence checks... + // NB: we don't use wxPATH_NORM_DOTS here, too (see wxPathList::Add for more info) + if (!fn.Normalize(wxPATH_NORM_TILDE|wxPATH_NORM_LONG|wxPATH_NORM_ENV_VARS)) + return wxEmptyString; + + wxASSERT_MSG(!fn.IsDir(), wxT("Cannot search for directories; only for files")); + if (fn.IsAbsolute()) + strend = fn.GetFullName(); // search for the file name and ignore the path part + else + strend = fn.GetFullPath(); + + for (size_t i=0; i 0) + { + if (buffer[i] == wxT('.')) + { + buffer[i] = 0; + break; + } + i --; + } +} + +void wxStripExtension(wxString& buffer) +{ + //RN: Be careful about the handling the case where + //buffer.length() == 0 + for(size_t i = buffer.length() - 1; i != wxString::npos; --i) + { + if (buffer.GetChar(i) == wxT('.')) + { + buffer = buffer.Left(i); + break; + } + } +} + +// Destructive removal of /./ and /../ stuff +wxChar *wxRealPath (wxChar *path) +{ +#ifdef __WXMSW__ + static const wxChar SEP = wxT('\\'); + wxUnix2DosFilename(path); +#else + static const wxChar SEP = wxT('/'); +#endif + if (path[0] && path[1]) { + /* MATTHEW: special case "/./x" */ + wxChar *p; + if (path[2] == SEP && path[1] == wxT('.')) + p = &path[0]; + else + p = &path[2]; + for (; *p; p++) + { + if (*p == SEP) + { + if (p[1] == wxT('.') && p[2] == wxT('.') && (p[3] == SEP || p[3] == wxT('\0'))) + { + wxChar *q; + for (q = p - 1; q >= path && *q != SEP; q--) + { + // Empty + } + + if (q[0] == SEP && (q[1] != wxT('.') || q[2] != wxT('.') || q[3] != SEP) + && (q - 1 <= path || q[-1] != SEP)) + { + wxStrcpy (q, p + 3); + if (path[0] == wxT('\0')) + { + path[0] = SEP; + path[1] = wxT('\0'); + } +#if defined(__WXMSW__) || defined(__OS2__) + /* Check that path[2] is NULL! */ + else if (path[1] == wxT(':') && !path[2]) + { + path[2] = SEP; + path[3] = wxT('\0'); + } +#endif + p = q - 1; + } + } + else if (p[1] == wxT('.') && (p[2] == SEP || p[2] == wxT('\0'))) + wxStrcpy (p, p + 2); + } + } + } + return path; +} + +wxString wxRealPath(const wxString& path) +{ + wxChar *buf1=MYcopystring(path); + wxChar *buf2=wxRealPath(buf1); + wxString buf(buf2); + delete [] buf1; + return buf; +} + + +// Must be destroyed +wxChar *wxCopyAbsolutePath(const wxString& filename) +{ + if (filename.empty()) + return (wxChar *) NULL; + + if (! wxIsAbsolutePath(wxExpandPath(wxFileFunctionsBuffer, filename))) + { + wxString buf = ::wxGetCwd(); + wxChar ch = buf.Last(); +#ifdef __WXMSW__ + if (ch != wxT('\\') && ch != wxT('/')) + buf << wxT("\\"); +#else + if (ch != wxT('/')) + buf << wxT("/"); +#endif + buf << wxFileFunctionsBuffer; + buf = wxRealPath( buf ); + return MYcopystring( buf ); + } + return MYcopystring( wxFileFunctionsBuffer ); +} + +/*- + Handles: + ~/ => home dir + ~user/ => user's home dir + If the environment variable a = "foo" and b = "bar" then: + Unix: + $a => foo + $a$b => foobar + $a.c => foo.c + xxx$a => xxxfoo + ${a}! => foo! + $(b)! => bar! + \$a => \$a + MSDOS: + $a ==> $a + $(a) ==> foo + $(a)$b ==> foo$b + $(a)$(b)==> foobar + test.$$ ==> test.$$ + */ + +/* input name in name, pathname output to buf. */ + +wxChar *wxExpandPath(wxChar *buf, const wxChar *name) +{ + register wxChar *d, *s, *nm; + wxChar lnm[_MAXPATHLEN]; + int q; + + // Some compilers don't like this line. +// const wxChar trimchars[] = wxT("\n \t"); + + wxChar trimchars[4]; + trimchars[0] = wxT('\n'); + trimchars[1] = wxT(' '); + trimchars[2] = wxT('\t'); + trimchars[3] = 0; + +#ifdef __WXMSW__ + const wxChar SEP = wxT('\\'); +#else + const wxChar SEP = wxT('/'); +#endif + buf[0] = wxT('\0'); + if (name == NULL || *name == wxT('\0')) + return buf; + nm = MYcopystring(name); // Make a scratch copy + wxChar *nm_tmp = nm; + + /* Skip leading whitespace and cr */ + while (wxStrchr((wxChar *)trimchars, *nm) != NULL) + nm++; + /* And strip off trailing whitespace and cr */ + s = nm + (q = wxStrlen(nm)) - 1; + while (q-- && wxStrchr((wxChar *)trimchars, *s) != NULL) + *s = wxT('\0'); + + s = nm; + d = lnm; +#ifdef __WXMSW__ + q = FALSE; +#else + q = nm[0] == wxT('\\') && nm[1] == wxT('~'); +#endif + + /* Expand inline environment variables */ +#ifdef __VISAGECPP__ + while (*d) + { + *d++ = *s; + if(*s == wxT('\\')) + { + *(d - 1) = *++s; + if (*d) + { + s++; + continue; + } + else + break; + } + else +#else + while ((*d++ = *s) != 0) { +# ifndef __WXMSW__ + if (*s == wxT('\\')) { + if ((*(d - 1) = *++s)!=0) { + s++; + continue; + } else + break; + } else +# endif +#endif + // No env variables on WinCE +#ifndef __WXWINCE__ +#ifdef __WXMSW__ + if (*s++ == wxT('$') && (*s == wxT('{') || *s == wxT(')'))) +#else + if (*s++ == wxT('$')) +#endif + { + register wxChar *start = d; + register int braces = (*s == wxT('{') || *s == wxT('(')); + register wxChar *value; + while ((*d++ = *s) != 0) + if (braces ? (*s == wxT('}') || *s == wxT(')')) : !(wxIsalnum(*s) || *s == wxT('_')) ) + break; + else + s++; + *--d = 0; + value = wxGetenv(braces ? start + 1 : start); + if (value) { + for ((d = start - 1); (*d++ = *value++) != 0;) + { + // Empty + } + + d--; + if (braces && *s) + s++; + } + } +#endif + // __WXWINCE__ + } + + /* Expand ~ and ~user */ + nm = lnm; + if (nm[0] == wxT('~') && !q) + { + /* prefix ~ */ + if (nm[1] == SEP || nm[1] == 0) + { /* ~/filename */ + // FIXME: wxGetUserHome could return temporary storage in Unicode mode + if ((s = WXSTRINGCAST wxGetUserHome(wxEmptyString)) != NULL) { + if (*++nm) + nm++; + } + } else + { /* ~user/filename */ + register wxChar *nnm; + register wxChar *home; + for (s = nm; *s && *s != SEP; s++) + { + // Empty + } + int was_sep; /* MATTHEW: Was there a separator, or NULL? */ + was_sep = (*s == SEP); + nnm = *s ? s + 1 : s; + *s = 0; + // FIXME: wxGetUserHome could return temporary storage in Unicode mode + if ((home = WXSTRINGCAST wxGetUserHome(wxString(nm + 1))) == NULL) + { + if (was_sep) /* replace only if it was there: */ + *s = SEP; + s = NULL; + } + else + { + nm = nnm; + s = home; + } + } + } + + d = buf; + if (s && *s) { /* MATTHEW: s could be NULL if user '~' didn't exist */ + /* Copy home dir */ + while (wxT('\0') != (*d++ = *s++)) + /* loop */; + // Handle root home + if (d - 1 > buf && *(d - 2) != SEP) + *(d - 1) = SEP; + } + s = nm; + while ((*d++ = *s++) != 0) + { + // Empty + } + delete[] nm_tmp; // clean up alloc + /* Now clean up the buffer */ + return wxRealPath(buf); +} + +/* Contract Paths to be build upon an environment variable + component: + + example: "/usr/openwin/lib", OPENWINHOME --> ${OPENWINHOME}/lib + + The call wxExpandPath can convert these back! + */ +wxChar * +wxContractPath (const wxString& filename, + const wxString& WXUNUSED_IN_WINCE(envname), + const wxString& user) +{ + static wxChar dest[_MAXPATHLEN]; + + if (filename.empty()) + return (wxChar *) NULL; + + wxStrcpy (dest, WXSTRINGCAST filename); +#ifdef __WXMSW__ + wxUnix2DosFilename(dest); +#endif + + // Handle environment + const wxChar *val; +#ifndef __WXWINCE__ + wxChar *tcp; + if (!envname.empty() && (val = wxGetenv (WXSTRINGCAST envname)) != NULL && + (tcp = wxStrstr (dest, val)) != NULL) + { + wxStrcpy (wxFileFunctionsBuffer, tcp + wxStrlen (val)); + *tcp++ = wxT('$'); + *tcp++ = wxT('{'); + wxStrcpy (tcp, WXSTRINGCAST envname); + wxStrcat (tcp, wxT("}")); + wxStrcat (tcp, wxFileFunctionsBuffer); + } +#endif + + // Handle User's home (ignore root homes!) + val = wxGetUserHome (user); + if (!val) + return dest; + + const size_t len = wxStrlen(val); + if (len <= 2) + return dest; + + if (wxStrncmp(dest, val, len) == 0) + { + wxStrcpy(wxFileFunctionsBuffer, wxT("~")); + if (!user.empty()) + wxStrcat(wxFileFunctionsBuffer, (const wxChar*) user); + wxStrcat(wxFileFunctionsBuffer, dest + len); + wxStrcpy (dest, wxFileFunctionsBuffer); + } + + return dest; +} + +// Return just the filename, not the path (basename) +wxChar *wxFileNameFromPath (wxChar *path) +{ + wxString p = path; + wxString n = wxFileNameFromPath(p); + + return path + p.length() - n.length(); +} + +wxString wxFileNameFromPath (const wxString& path) +{ + wxString name, ext; + wxFileName::SplitPath(path, NULL, &name, &ext); + + wxString fullname = name; + if ( !ext.empty() ) + { + fullname << wxFILE_SEP_EXT << ext; + } + + return fullname; +} + +// Return just the directory, or NULL if no directory +wxChar * +wxPathOnly (wxChar *path) +{ + if (path && *path) + { + static wxChar buf[_MAXPATHLEN]; + + // Local copy + wxStrcpy (buf, path); + + int l = wxStrlen(path); + int i = l - 1; + + // Search backward for a backward or forward slash + while (i > -1) + { +#if defined(__WXMAC__) && !defined(__DARWIN__) + // Classic or Carbon CodeWarrior like + // Carbon with Apple DevTools is Unix like + if (path[i] == wxT(':') ) + { + buf[i] = 0; + return buf; + } +#else + // Unix like or Windows + if (path[i] == wxT('/') || path[i] == wxT('\\')) + { + buf[i] = 0; + return buf; + } +#endif +#ifdef __VMS__ + if (path[i] == wxT(']')) + { + buf[i+1] = 0; + return buf; + } +#endif + i --; + } + +#if defined(__WXMSW__) || defined(__OS2__) + // Try Drive specifier + if (wxIsalpha (buf[0]) && buf[1] == wxT(':')) + { + // A:junk --> A:. (since A:.\junk Not A:\junk) + buf[2] = wxT('.'); + buf[3] = wxT('\0'); + return buf; + } +#endif + } + return (wxChar *) NULL; +} + +// Return just the directory, or NULL if no directory +wxString wxPathOnly (const wxString& path) +{ + if (!path.empty()) + { + wxChar buf[_MAXPATHLEN]; + + // Local copy + wxStrcpy (buf, WXSTRINGCAST path); + + int l = path.length(); + int i = l - 1; + + // Search backward for a backward or forward slash + while (i > -1) + { +#if defined(__WXMAC__) && !defined(__DARWIN__) + // Classic or Carbon CodeWarrior like + // Carbon with Apple DevTools is Unix like + if (path[i] == wxT(':') ) + { + buf[i] = 0; + return wxString(buf); + } +#else + // Unix like or Windows + if (path[i] == wxT('/') || path[i] == wxT('\\')) + { + // Don't return an empty string + if (i == 0) + i ++; + buf[i] = 0; + return wxString(buf); + } +#endif +#ifdef __VMS__ + if (path[i] == wxT(']')) + { + buf[i+1] = 0; + return wxString(buf); + } +#endif + i --; + } + +#if defined(__WXMSW__) || defined(__OS2__) + // Try Drive specifier + if (wxIsalpha (buf[0]) && buf[1] == wxT(':')) + { + // A:junk --> A:. (since A:.\junk Not A:\junk) + buf[2] = wxT('.'); + buf[3] = wxT('\0'); + return wxString(buf); + } +#endif + } + return wxEmptyString; +} + +// Utility for converting delimiters in DOS filenames to UNIX style +// and back again - or we get nasty problems with delimiters. +// Also, convert to lower case, since case is significant in UNIX. + +#if defined(__WXMAC__) + +#if TARGET_API_MAC_OSX +#define kDefaultPathStyle kCFURLPOSIXPathStyle +#else +#define kDefaultPathStyle kCFURLHFSPathStyle +#endif + +wxString wxMacFSRefToPath( const FSRef *fsRef , CFStringRef additionalPathComponent ) +{ + CFURLRef fullURLRef; + fullURLRef = CFURLCreateFromFSRef(NULL, fsRef); + if ( additionalPathComponent ) + { + CFURLRef parentURLRef = fullURLRef ; + fullURLRef = CFURLCreateCopyAppendingPathComponent(NULL, parentURLRef, + additionalPathComponent,false); + CFRelease( parentURLRef ) ; + } + CFStringRef cfString = CFURLCopyFileSystemPath(fullURLRef, kDefaultPathStyle); + CFRelease( fullURLRef ) ; + CFMutableStringRef cfMutableString = CFStringCreateMutableCopy(NULL, 0, cfString); + CFRelease( cfString ); + CFStringNormalize(cfMutableString,kCFStringNormalizationFormC); + return wxMacCFStringHolder(cfMutableString).AsString(); +} + +OSStatus wxMacPathToFSRef( const wxString&path , FSRef *fsRef ) +{ + OSStatus err = noErr ; + CFMutableStringRef cfMutableString = CFStringCreateMutableCopy(NULL, 0, wxMacCFStringHolder(path)); + CFStringNormalize(cfMutableString,kCFStringNormalizationFormD); + CFURLRef url = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, cfMutableString , kDefaultPathStyle, false); + CFRelease( cfMutableString ); + if ( NULL != url ) + { + if ( CFURLGetFSRef(url, fsRef) == false ) + err = fnfErr ; + CFRelease( url ) ; + } + else + { + err = fnfErr ; + } + return err ; +} + +wxString wxMacHFSUniStrToString( ConstHFSUniStr255Param uniname ) +{ + CFStringRef cfname = CFStringCreateWithCharacters( kCFAllocatorDefault, + uniname->unicode, + uniname->length ); + CFMutableStringRef cfMutableString = CFStringCreateMutableCopy(NULL, 0, cfname); + CFRelease( cfname ); + CFStringNormalize(cfMutableString,kCFStringNormalizationFormC); + return wxMacCFStringHolder(cfMutableString).AsString() ; +} + +#ifndef __LP64__ + +wxString wxMacFSSpec2MacFilename( const FSSpec *spec ) +{ + FSRef fsRef ; + if ( FSpMakeFSRef( spec , &fsRef) == noErr ) + { + return wxMacFSRefToPath( &fsRef ) ; + } + return wxEmptyString ; +} + +void wxMacFilename2FSSpec( const wxString& path , FSSpec *spec ) +{ + OSStatus err = noErr ; + FSRef fsRef ; + wxMacPathToFSRef( path , &fsRef ) ; + err = FSRefMakeFSSpec( &fsRef , spec ) ; +} +#endif + +#endif // __WXMAC__ + +void +wxDos2UnixFilename (wxChar *s) +{ + if (s) + while (*s) + { + if (*s == _T('\\')) + *s = _T('/'); +#ifdef __WXMSW__ + else + *s = (wxChar)wxTolower (*s); // Case INDEPENDENT +#endif + s++; + } +} + +void +#if defined(__WXMSW__) || defined(__OS2__) +wxUnix2DosFilename (wxChar *s) +#else +wxUnix2DosFilename (wxChar *WXUNUSED(s) ) +#endif +{ +// Yes, I really mean this to happen under DOS only! JACS +#if defined(__WXMSW__) || defined(__OS2__) + if (s) + while (*s) + { + if (*s == wxT('/')) + *s = wxT('\\'); + s++; + } +#endif +} + +// Concatenate two files to form third +bool +wxConcatFiles (const wxString& file1, const wxString& file2, const wxString& file3) +{ +#if wxUSE_FILE + + wxFile in1(file1), in2(file2); + wxTempFile out(file3); + + if ( !in1.IsOpened() || !in2.IsOpened() || !out.IsOpened() ) + return false; + + ssize_t ofs; + unsigned char buf[1024]; + + for( int i=0; i<2; i++) + { + wxFile *in = i==0 ? &in1 : &in2; + do{ + if ( (ofs = in->Read(buf,WXSIZEOF(buf))) == wxInvalidOffset ) return false; + if ( ofs > 0 ) + if ( !out.Write(buf,ofs) ) + return false; + } while ( ofs == (ssize_t)WXSIZEOF(buf) ); + } + + return out.Commit(); + +#else + + wxUnusedVar(file1); + wxUnusedVar(file2); + wxUnusedVar(file3); + return false; + +#endif +} + +// Copy files +bool +wxCopyFile (const wxString& file1, const wxString& file2, bool overwrite) +{ +#if defined(__WIN32__) && !defined(__WXMICROWIN__) + // CopyFile() copies file attributes and modification time too, so use it + // instead of our code if available + // + // NB: 3rd parameter is bFailIfExists i.e. the inverse of overwrite + if ( !::CopyFile(file1, file2, !overwrite) ) + { + wxLogSysError(_("Failed to copy the file '%s' to '%s'"), + file1.c_str(), file2.c_str()); + + return false; + } +#elif defined(__OS2__) + if ( ::DosCopy((PSZ)file1.c_str(), (PSZ)file2.c_str(), overwrite ? DCPY_EXISTING : 0) != 0 ) + return false; +#elif defined(__PALMOS__) + // TODO with http://www.palmos.com/dev/support/docs/protein_books/Memory_Databases_Files/ + return false; +#elif wxUSE_FILE // !Win32 + + wxStructStat fbuf; + // get permissions of file1 + if ( wxStat( file1.c_str(), &fbuf) != 0 ) + { + // the file probably doesn't exist or we haven't the rights to read + // from it anyhow + wxLogSysError(_("Impossible to get permissions for file '%s'"), + file1.c_str()); + return false; + } + + // open file1 for reading + wxFile fileIn(file1, wxFile::read); + if ( !fileIn.IsOpened() ) + return false; + + // remove file2, if it exists. This is needed for creating + // file2 with the correct permissions in the next step + if ( wxFileExists(file2) && (!overwrite || !wxRemoveFile(file2))) + { + wxLogSysError(_("Impossible to overwrite the file '%s'"), + file2.c_str()); + return false; + } + + // reset the umask as we want to create the file with exactly the same + // permissions as the original one + wxCHANGE_UMASK(0); + + // create file2 with the same permissions than file1 and open it for + // writing + + wxFile fileOut; + if ( !fileOut.Create(file2, overwrite, fbuf.st_mode & 0777) ) + return false; + + // copy contents of file1 to file2 + char buf[4096]; + size_t count; + for ( ;; ) + { + count = fileIn.Read(buf, WXSIZEOF(buf)); + if ( fileIn.Error() ) + return false; + + // end of file? + if ( !count ) + break; + + if ( fileOut.Write(buf, count) < count ) + return false; + } + + // we can expect fileIn to be closed successfully, but we should ensure + // that fileOut was closed as some write errors (disk full) might not be + // detected before doing this + if ( !fileIn.Close() || !fileOut.Close() ) + return false; + +#if !defined(__VISAGECPP__) && !defined(__WXMAC__) || defined(__UNIX__) + // no chmod in VA. Should be some permission API for HPFS386 partitions + // however + if ( chmod(OS_FILENAME(file2), fbuf.st_mode) != 0 ) + { + wxLogSysError(_("Impossible to set permissions for the file '%s'"), + file2.c_str()); + return false; + } +#endif // OS/2 || Mac + +#else // !Win32 && ! wxUSE_FILE + + // impossible to simulate with wxWidgets API + wxUnusedVar(file1); + wxUnusedVar(file2); + wxUnusedVar(overwrite); + return false; + +#endif // __WXMSW__ && __WIN32__ + + return true; +} + +bool +wxRenameFile(const wxString& file1, const wxString& file2, bool overwrite) +{ + if ( !overwrite && wxFileExists(file2) ) + { + wxLogSysError + ( + _("Failed to rename the file '%s' to '%s' because the destination file already exists."), + file1.c_str(), file2.c_str() + ); + + return false; + } + +#if !defined(__WXWINCE__) && !defined(__WXPALMOS__) + // Normal system call + if ( wxRename (file1, file2) == 0 ) + return true; +#endif + + // Try to copy + if (wxCopyFile(file1, file2, overwrite)) { + wxRemoveFile(file1); + return true; + } + // Give up + return false; +} + +bool wxRemoveFile(const wxString& file) +{ +#if defined(__VISUALC__) \ + || defined(__BORLANDC__) \ + || defined(__WATCOMC__) \ + || defined(__DMC__) \ + || defined(__GNUWIN32__) \ + || (defined(__MWERKS__) && defined(__MSL__)) + int res = wxRemove(file); +#elif defined(__WXMAC__) + int res = unlink(wxFNCONV(file)); +#elif defined(__WXPALMOS__) + int res = 1; + // TODO with VFSFileDelete() +#else + int res = unlink(OS_FILENAME(file)); +#endif + + return res == 0; +} + +bool wxMkdir(const wxString& dir, int perm) +{ +#if defined(__WXPALMOS__) + return false; +#elif defined(__WXMAC__) && !defined(__UNIX__) + return (mkdir( wxFNCONV(dir) , 0 ) == 0); +#else // !Mac + const wxChar *dirname = dir.c_str(); + + // assume mkdir() has 2 args on non Windows-OS/2 platforms and on Windows too + // for the GNU compiler +#if (!(defined(__WXMSW__) || defined(__OS2__) || defined(__DOS__))) || (defined(__GNUWIN32__) && !defined(__MINGW32__)) || defined(__WINE__) || defined(__WXMICROWIN__) + #if defined(MSVCRT) + wxUnusedVar(perm); + if ( mkdir(wxFNCONV(dirname)) != 0 ) + #else + if ( mkdir(wxFNCONV(dirname), perm) != 0 ) + #endif +#elif defined(__OS2__) + wxUnusedVar(perm); + if (::DosCreateDir((PSZ)dirname, NULL) != 0) // enhance for EAB's?? +#elif defined(__DOS__) + #if defined(__WATCOMC__) + (void)perm; + if ( wxMkDir(wxFNSTRINGCAST wxFNCONV(dirname)) != 0 ) + #elif defined(__DJGPP__) + if ( mkdir(wxFNCONV(dirname), perm) != 0 ) + #else + #error "Unsupported DOS compiler!" + #endif +#else // !MSW, !DOS and !OS/2 VAC++ + wxUnusedVar(perm); +#ifdef __WXWINCE__ + if ( !CreateDirectory(dirname, NULL) ) +#else + if ( wxMkDir(dir.fn_str()) != 0 ) +#endif +#endif // !MSW/MSW + { + wxLogSysError(_("Directory '%s' couldn't be created"), dirname); + + return false; + } + + return true; +#endif // Mac/!Mac +} + +bool wxRmdir(const wxString& dir, int WXUNUSED(flags)) +{ +#if defined(__VMS__) + return false; //to be changed since rmdir exists in VMS7.x +#elif defined(__OS2__) + return (::DosDeleteDir((PSZ)dir.c_str()) == 0); +#elif defined(__WXWINCE__) + return (RemoveDirectory(dir) != 0); +#elif defined(__WXPALMOS__) + // TODO with VFSFileRename() + return false; +#else + return (wxRmDir(OS_FILENAME(dir)) == 0); +#endif +} + +// does the path exists? (may have or not '/' or '\\' at the end) +bool wxDirExists(const wxChar *pszPathName) +{ + wxString strPath(pszPathName); + +#if defined(__WINDOWS__) || defined(__OS2__) + // Windows fails to find directory named "c:\dir\" even if "c:\dir" exists, + // so remove all trailing backslashes from the path - but don't do this for + // the paths "d:\" (which are different from "d:") nor for just "\" + while ( wxEndsWithPathSeparator(strPath) ) + { + size_t len = strPath.length(); + if ( len == 1 || (len == 3 && strPath[len - 2] == _T(':')) ) + break; + + strPath.Truncate(len - 1); + } +#endif // __WINDOWS__ + +#ifdef __OS2__ + // OS/2 can't handle "d:", it wants either "d:\" or "d:." + if (strPath.length() == 2 && strPath[1u] == _T(':')) + strPath << _T('.'); +#endif + +#if defined(__WXPALMOS__) + return false; +#elif defined(__WIN32__) && !defined(__WXMICROWIN__) + // stat() can't cope with network paths + DWORD ret = ::GetFileAttributes(strPath); + + return (ret != (DWORD)-1) && (ret & FILE_ATTRIBUTE_DIRECTORY); +#elif defined(__OS2__) + FILESTATUS3 Info = {{0}}; + APIRET rc = ::DosQueryPathInfo((PSZ)(WXSTRINGCAST strPath), FIL_STANDARD, + (void*) &Info, sizeof(FILESTATUS3)); + + return ((rc == NO_ERROR) && (Info.attrFile & FILE_DIRECTORY)) || + (rc == ERROR_SHARING_VIOLATION); + // If we got a sharing violation, there must be something with this name. +#else // !__WIN32__ + + wxStructStat st; +#ifndef __VISAGECPP__ + return wxStat(strPath.c_str(), &st) == 0 && ((st.st_mode & S_IFMT) == S_IFDIR); +#else + // S_IFMT not supported in VA compilers.. st_mode is a 2byte value only + return wxStat(pszPathName, &st) == 0 && (st.st_mode == S_IFDIR); +#endif + +#endif // __WIN32__/!__WIN32__ +} + +// Get a temporary filename, opening and closing the file. +wxChar *wxGetTempFileName(const wxString& prefix, wxChar *buf) +{ + wxString filename; + if ( !wxGetTempFileName(prefix, filename) ) + return NULL; + + if ( buf ) + wxStrcpy(buf, filename); + else + buf = MYcopystring(filename); + + return buf; +} + +bool wxGetTempFileName(const wxString& prefix, wxString& buf) +{ +#if wxUSE_FILE + buf = wxFileName::CreateTempFileName(prefix); + + return !buf.empty(); +#else // !wxUSE_FILE + wxUnusedVar(prefix); + wxUnusedVar(buf); + + return false; +#endif // wxUSE_FILE/!wxUSE_FILE +} + +// Get first file name matching given wild card. + +static wxDir *gs_dir = NULL; +static wxString gs_dirPath; + +wxString wxFindFirstFile(const wxChar *spec, int flags) +{ + wxSplitPath(spec, &gs_dirPath, NULL, NULL); + if ( gs_dirPath.empty() ) + gs_dirPath = wxT("."); + if ( !wxEndsWithPathSeparator(gs_dirPath ) ) + gs_dirPath << wxFILE_SEP_PATH; + + if (gs_dir) + delete gs_dir; + gs_dir = new wxDir(gs_dirPath); + + if ( !gs_dir->IsOpened() ) + { + wxLogSysError(_("Can not enumerate files '%s'"), spec); + return wxEmptyString; + } + + int dirFlags; + switch (flags) + { + case wxDIR: dirFlags = wxDIR_DIRS; break; + case wxFILE: dirFlags = wxDIR_FILES; break; + default: dirFlags = wxDIR_DIRS | wxDIR_FILES; break; + } + + wxString result; + gs_dir->GetFirst(&result, wxFileNameFromPath(wxString(spec)), dirFlags); + if ( result.empty() ) + { + wxDELETE(gs_dir); + return result; + } + + return gs_dirPath + result; +} + +wxString wxFindNextFile() +{ + wxASSERT_MSG( gs_dir, wxT("You must call wxFindFirstFile before!") ); + + wxString result; + gs_dir->GetNext(&result); + + if ( result.empty() ) + { + wxDELETE(gs_dir); + return result; + } + + return gs_dirPath + result; +} + + +// Get current working directory. +// If buf is NULL, allocates space using new, else copies into buf. +// wxGetWorkingDirectory() is obsolete, use wxGetCwd() +// wxDoGetCwd() is their common core to be moved +// to wxGetCwd() once wxGetWorkingDirectory() will be removed. +// Do not expose wxDoGetCwd in headers! + +wxChar *wxDoGetCwd(wxChar *buf, int sz) +{ +#if defined(__WXPALMOS__) + // TODO + if(buf && sz>0) buf[0] = _T('\0'); + return buf; +#elif defined(__WXWINCE__) + // TODO + if(buf && sz>0) buf[0] = _T('\0'); + return buf; +#else + if ( !buf ) + { + buf = new wxChar[sz + 1]; + } + + bool ok wxDUMMY_INITIALIZE(false); + + // for the compilers which have Unicode version of _getcwd(), call it + // directly, for the others call the ANSI version and do the translation +#if !wxUSE_UNICODE + #define cbuf buf +#else // wxUSE_UNICODE + bool needsANSI = true; + + #if !defined(HAVE_WGETCWD) || wxUSE_UNICODE_MSLU + char cbuf[_MAXPATHLEN]; + #endif + + #ifdef HAVE_WGETCWD + #if wxUSE_UNICODE_MSLU + if ( wxGetOsVersion() != wxOS_WINDOWS_9X ) + #else + char *cbuf = NULL; // never really used because needsANSI will always be false + #endif + { + ok = _wgetcwd(buf, sz) != NULL; + needsANSI = false; + } + #endif + + if ( needsANSI ) +#endif // wxUSE_UNICODE + { + #if defined(_MSC_VER) || defined(__MINGW32__) + ok = _getcwd(cbuf, sz) != NULL; + #elif defined(__WXMAC__) && !defined(__DARWIN__) + char lbuf[1024] ; + if ( getcwd( lbuf , sizeof( lbuf ) ) ) + { + wxString res( lbuf , *wxConvCurrent ) ; + wxStrcpy( buf , res ) ; + ok = true; + } + else + ok = false ; + #elif defined(__OS2__) + APIRET rc; + ULONG ulDriveNum = 0; + ULONG ulDriveMap = 0; + rc = ::DosQueryCurrentDisk(&ulDriveNum, &ulDriveMap); + ok = rc == 0; + if (ok) + { + sz -= 3; + rc = ::DosQueryCurrentDir( 0 // current drive + ,cbuf + 3 + ,(PULONG)&sz + ); + cbuf[0] = char('A' + (ulDriveNum - 1)); + cbuf[1] = ':'; + cbuf[2] = '\\'; + ok = rc == 0; + } + #else // !Win32/VC++ !Mac !OS2 + ok = getcwd(cbuf, sz) != NULL; + #endif // platform + + #if wxUSE_UNICODE && !(defined(__WXMAC__) && !defined(__DARWIN__)) + // finally convert the result to Unicode if needed + wxConvFile.MB2WC(buf, cbuf, sz); + #endif // wxUSE_UNICODE + } + + if ( !ok ) + { + wxLogSysError(_("Failed to get the working directory")); + + // VZ: the old code used to return "." on error which didn't make any + // sense at all to me - empty string is a better error indicator + // (NULL might be even better but I'm afraid this could lead to + // problems with the old code assuming the return is never NULL) + buf[0] = _T('\0'); + } + else // ok, but we might need to massage the path into the right format + { +#ifdef __DJGPP__ + // VS: DJGPP is a strange mix of DOS and UNIX API and returns paths + // with / deliminers. We don't like that. + for (wxChar *ch = buf; *ch; ch++) + { + if (*ch == wxT('/')) + *ch = wxT('\\'); + } +#endif // __DJGPP__ + +// MBN: we hope that in the case the user is compiling a GTK+/Motif app, +// he needs Unix as opposed to Win32 pathnames +#if defined( __CYGWIN__ ) && defined( __WINDOWS__ ) + // another example of DOS/Unix mix (Cygwin) + wxString pathUnix = buf; +#if wxUSE_UNICODE + char bufA[_MAXPATHLEN]; + cygwin_conv_to_full_win32_path(pathUnix.mb_str(wxConvFile), bufA); + wxConvFile.MB2WC(buf, bufA, sz); +#else + cygwin_conv_to_full_win32_path(pathUnix, buf); +#endif // wxUSE_UNICODE +#endif // __CYGWIN__ + } + + return buf; + +#if !wxUSE_UNICODE + #undef cbuf +#endif + +#endif + // __WXWINCE__ +} + +#if WXWIN_COMPATIBILITY_2_6 +wxChar *wxGetWorkingDirectory(wxChar *buf, int sz) +{ + return wxDoGetCwd(buf,sz); +} +#endif // WXWIN_COMPATIBILITY_2_6 + +wxString wxGetCwd() +{ + wxString str; + wxDoGetCwd(wxStringBuffer(str, _MAXPATHLEN), _MAXPATHLEN); + return str; +} + +bool wxSetWorkingDirectory(const wxString& d) +{ +#if defined(__OS2__) + if (d[1] == ':') + { + ::DosSetDefaultDisk(1 + wxToupper(d[0]) - _T('A')); + // do not call DosSetCurrentDir when just changing drive, + // since it requires e.g. "d:." instead of "d:"! + if (d.length() == 2) + return true; + } + return (::DosSetCurrentDir((PSZ)d.c_str()) == 0); +#elif defined(__UNIX__) || defined(__WXMAC__) || defined(__DOS__) + return (chdir(wxFNSTRINGCAST d.fn_str()) == 0); +#elif defined(__WINDOWS__) + +#ifdef __WIN32__ +#ifdef __WXWINCE__ + // No equivalent in WinCE + wxUnusedVar(d); + return false; +#else + return (bool)(SetCurrentDirectory(d) != 0); +#endif +#else + // Must change drive, too. + bool isDriveSpec = ((strlen(d) > 1) && (d[1] == ':')); + if (isDriveSpec) + { + wxChar firstChar = d[0]; + + // To upper case + if (firstChar > 90) + firstChar = firstChar - 32; + + // To a drive number + unsigned int driveNo = firstChar - 64; + if (driveNo > 0) + { + unsigned int noDrives; + _dos_setdrive(driveNo, &noDrives); + } + } + bool success = (chdir(WXSTRINGCAST d) == 0); + + return success; +#endif + +#endif +} + +// Get the OS directory if appropriate (such as the Windows directory). +// On non-Windows platform, probably just return the empty string. +wxString wxGetOSDirectory() +{ +#ifdef __WXWINCE__ + return wxString(wxT("\\Windows")); +#elif defined(__WINDOWS__) && !defined(__WXMICROWIN__) + wxChar buf[256]; + GetWindowsDirectory(buf, 256); + return wxString(buf); +#elif defined(__WXMAC__) + return wxMacFindFolder(kOnSystemDisk, 'macs', false); +#else + return wxEmptyString; +#endif +} + +bool wxEndsWithPathSeparator(const wxChar *pszFileName) +{ + size_t len = wxStrlen(pszFileName); + + return len && wxIsPathSeparator(pszFileName[len - 1]); +} + +// find a file in a list of directories, returns false if not found +bool wxFindFileInPath(wxString *pStr, const wxChar *pszPath, const wxChar *pszFile) +{ + // we assume that it's not empty + wxCHECK_MSG( !wxIsEmpty(pszFile), false, + _T("empty file name in wxFindFileInPath")); + + // skip path separator in the beginning of the file name if present + if ( wxIsPathSeparator(*pszFile) ) + pszFile++; + + // copy the path (strtok will modify it) + wxChar *szPath = new wxChar[wxStrlen(pszPath) + 1]; + wxStrcpy(szPath, pszPath); + + wxString strFile; + wxChar *pc, *save_ptr; + for ( pc = wxStrtok(szPath, wxPATH_SEP, &save_ptr); + pc != NULL; + pc = wxStrtok((wxChar *) NULL, wxPATH_SEP, &save_ptr) ) + { + // search for the file in this directory + strFile = pc; + if ( !wxEndsWithPathSeparator(pc) ) + strFile += wxFILE_SEP_PATH; + strFile += pszFile; + + if ( wxFileExists(strFile) ) { + *pStr = strFile; + break; + } + } + + // suppress warning about unused variable save_ptr when wxStrtok() is a + // macro which throws away its third argument + save_ptr = pc; + + delete [] szPath; + + return pc != NULL; // if true => we breaked from the loop +} + +void WXDLLEXPORT wxSplitPath(const wxChar *pszFileName, + wxString *pstrPath, + wxString *pstrName, + wxString *pstrExt) +{ + // it can be empty, but it shouldn't be NULL + wxCHECK_RET( pszFileName, wxT("NULL file name in wxSplitPath") ); + + wxFileName::SplitPath(pszFileName, pstrPath, pstrName, pstrExt); +} + +#if wxUSE_DATETIME + +time_t WXDLLEXPORT wxFileModificationTime(const wxString& filename) +{ + wxDateTime mtime; + if ( !wxFileName(filename).GetTimes(NULL, &mtime, NULL) ) + return (time_t)-1; + + return mtime.GetTicks(); +} + +#endif // wxUSE_DATETIME + + +// Parses the filterStr, returning the number of filters. +// Returns 0 if none or if there's a problem. +// filterStr is in the form: "All files (*.*)|*.*|JPEG Files (*.jpeg)|*.jpeg" + +int WXDLLEXPORT wxParseCommonDialogsFilter(const wxString& filterStr, + wxArrayString& descriptions, + wxArrayString& filters) +{ + descriptions.Clear(); + filters.Clear(); + + wxString str(filterStr); + + wxString description, filter; + int pos = 0; + while( pos != wxNOT_FOUND ) + { + pos = str.Find(wxT('|')); + if ( pos == wxNOT_FOUND ) + { + // if there are no '|'s at all in the string just take the entire + // string as filter and make description empty for later autocompletion + if ( filters.IsEmpty() ) + { + descriptions.Add(wxEmptyString); + filters.Add(filterStr); + } + else + { + wxFAIL_MSG( _T("missing '|' in the wildcard string!") ); + } + + break; + } + + description = str.Left(pos); + str = str.Mid(pos + 1); + pos = str.Find(wxT('|')); + if ( pos == wxNOT_FOUND ) + { + filter = str; + } + else + { + filter = str.Left(pos); + str = str.Mid(pos + 1); + } + + descriptions.Add(description); + filters.Add(filter); + } + +#if defined(__WXMOTIF__) + // split it so there is one wildcard per entry + for( size_t i = 0 ; i < descriptions.GetCount() ; i++ ) + { + pos = filters[i].Find(wxT(';')); + if (pos != wxNOT_FOUND) + { + // first split only filters + descriptions.Insert(descriptions[i],i+1); + filters.Insert(filters[i].Mid(pos+1),i+1); + filters[i]=filters[i].Left(pos); + + // autoreplace new filter in description with pattern: + // C/C++ Files(*.cpp;*.c;*.h)|*.cpp;*.c;*.h + // cause split into: + // C/C++ Files(*.cpp)|*.cpp + // C/C++ Files(*.c;*.h)|*.c;*.h + // and next iteration cause another split into: + // C/C++ Files(*.cpp)|*.cpp + // C/C++ Files(*.c)|*.c + // C/C++ Files(*.h)|*.h + for ( size_t k=i;kbefore.Find(_T(')'),true)) + { + before = before.Left(pos+1); + before << filters[k]; + pos = after.Find(_T(')')); + int pos1 = after.Find(_T('(')); + if (pos != wxNOT_FOUND && (pos +* +* The match procedure is public domain code (from ircII's reg.c) +* but modified to suit our tastes (RN: No "%" syntax I guess) +*/ + +bool wxMatchWild( const wxString& pat, const wxString& text, bool dot_special ) +{ + if (text.empty()) + { + /* Match if both are empty. */ + return pat.empty(); + } + + const wxChar *m = pat.c_str(), + *n = text.c_str(), + *ma = NULL, + *na = NULL; + int just = 0, + acount = 0, + count = 0; + + if (dot_special && (*n == wxT('.'))) + { + /* Never match so that hidden Unix files + * are never found. */ + return false; + } + + for (;;) + { + if (*m == wxT('*')) + { + ma = ++m; + na = n; + just = 1; + acount = count; + } + else if (*m == wxT('?')) + { + m++; + if (!*n++) + return false; + } + else + { + if (*m == wxT('\\')) + { + m++; + /* Quoting "nothing" is a bad thing */ + if (!*m) + return false; + } + if (!*m) + { + /* + * If we are out of both strings or we just + * saw a wildcard, then we can say we have a + * match + */ + if (!*n) + return true; + if (just) + return true; + just = 0; + goto not_matched; + } + /* + * We could check for *n == NULL at this point, but + * since it's more common to have a character there, + * check to see if they match first (m and n) and + * then if they don't match, THEN we can check for + * the NULL of n + */ + just = 0; + if (*m == *n) + { + m++; + count++; + n++; + } + else + { + + not_matched: + + /* + * If there are no more characters in the + * string, but we still need to find another + * character (*m != NULL), then it will be + * impossible to match it + */ + if (!*n) + return false; + + if (ma) + { + m = ma; + n = ++na; + count = acount; + } + else + return false; + } + } + } +} + +#ifdef __VISUALC__ + #pragma warning(default:4706) // assignment within conditional expression +#endif // VC++ diff --git a/Externals/wxWidgets/src/common/filename.cpp b/Externals/wxWidgets/src/common/filename.cpp index 9326ae2e6e..431fa2e90d 100644 --- a/Externals/wxWidgets/src/common/filename.cpp +++ b/Externals/wxWidgets/src/common/filename.cpp @@ -1,2537 +1,2537 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/filename.cpp -// Purpose: wxFileName - encapsulates a file path -// Author: Robert Roebling, Vadim Zeitlin -// Modified by: -// Created: 28.12.2000 -// RCS-ID: $Id: filename.cpp 52996 2008-04-03 12:47:16Z VZ $ -// Copyright: (c) 2000 Robert Roebling -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -/* - Here are brief descriptions of the filename formats supported by this class: - - wxPATH_UNIX: standard Unix format, used under Darwin as well, absolute file - names have the form: - /dir1/dir2/.../dirN/filename, "." and ".." stand for the - current and parent directory respectively, "~" is parsed as the - user HOME and "~username" as the HOME of that user - - wxPATH_DOS: DOS/Windows format, absolute file names have the form: - drive:\dir1\dir2\...\dirN\filename.ext where drive is a single - letter. "." and ".." as for Unix but no "~". - - There are also UNC names of the form \\share\fullpath - - wxPATH_MAC: Mac OS 8/9 and Mac OS X under CodeWarrior 7 format, absolute file - names have the form - volume:dir1:...:dirN:filename - and the relative file names are either - :dir1:...:dirN:filename - or just - filename - (although :filename works as well). - Since the volume is just part of the file path, it is not - treated like a separate entity as it is done under DOS and - VMS, it is just treated as another dir. - - wxPATH_VMS: VMS native format, absolute file names have the form - :[dir1.dir2.dir3]file.txt - or - :[000000.dir1.dir2.dir3]file.txt - - the is the physical device (i.e. disk). 000000 is the - root directory on the device which can be omitted. - - Note that VMS uses different separators unlike Unix: - : always after the device. If the path does not contain : than - the default (the device of the current directory) is assumed. - [ start of directory specification - . separator between directory and subdirectory - ] between directory and file - */ - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ -#pragma hdrstop -#endif - -#ifndef WX_PRECOMP - #ifdef __WXMSW__ - #include "wx/msw/wrapwin.h" // For GetShort/LongPathName - #endif - #include "wx/dynarray.h" - #include "wx/intl.h" - #include "wx/log.h" - #include "wx/utils.h" -#endif - -#include "wx/filename.h" -#include "wx/private/filename.h" -#include "wx/tokenzr.h" -#include "wx/config.h" // for wxExpandEnvVars -#include "wx/dynlib.h" - -#if defined(__WIN32__) && defined(__MINGW32__) - #include "wx/msw/gccpriv.h" -#endif - -#ifdef __WXWINCE__ -#include "wx/msw/private.h" -#endif - -#if defined(__WXMAC__) - #include "wx/mac/private.h" // includes mac headers -#endif - -// utime() is POSIX so should normally be available on all Unices -#ifdef __UNIX_LIKE__ -#include -#include -#include -#include -#endif - -#ifdef __DJGPP__ -#include -#endif - -#ifdef __MWERKS__ -#ifdef __MACH__ -#include -#include -#include -#include -#else -#include -#include -#include -#endif -#endif - -#ifdef __WATCOMC__ -#include -#include -#include -#endif - -#ifdef __VISAGECPP__ -#ifndef MAX_PATH -#define MAX_PATH 256 -#endif -#endif - -#ifdef __EMX__ -#include -#define MAX_PATH _MAX_PATH -#endif - - -wxULongLong wxInvalidSize = (unsigned)-1; - - -// ---------------------------------------------------------------------------- -// private classes -// ---------------------------------------------------------------------------- - -// small helper class which opens and closes the file - we use it just to get -// a file handle for the given file name to pass it to some Win32 API function -#if defined(__WIN32__) && !defined(__WXMICROWIN__) - -class wxFileHandle -{ -public: - enum OpenMode - { - Read, - Write - }; - - wxFileHandle(const wxString& filename, OpenMode mode) - { - m_hFile = ::CreateFile - ( - filename, // name - mode == Read ? GENERIC_READ // access mask - : GENERIC_WRITE, - FILE_SHARE_READ | // sharing mode - FILE_SHARE_WRITE, // (allow everything) - NULL, // no secutity attr - OPEN_EXISTING, // creation disposition - 0, // no flags - NULL // no template file - ); - - if ( m_hFile == INVALID_HANDLE_VALUE ) - { - wxLogSysError(_("Failed to open '%s' for %s"), - filename.c_str(), - mode == Read ? _("reading") : _("writing")); - } - } - - ~wxFileHandle() - { - if ( m_hFile != INVALID_HANDLE_VALUE ) - { - if ( !::CloseHandle(m_hFile) ) - { - wxLogSysError(_("Failed to close file handle")); - } - } - } - - // return true only if the file could be opened successfully - bool IsOk() const { return m_hFile != INVALID_HANDLE_VALUE; } - - // get the handle - operator HANDLE() const { return m_hFile; } - -private: - HANDLE m_hFile; -}; - -#endif // __WIN32__ - -// ---------------------------------------------------------------------------- -// private functions -// ---------------------------------------------------------------------------- - -#if wxUSE_DATETIME && defined(__WIN32__) && !defined(__WXMICROWIN__) - -// convert between wxDateTime and FILETIME which is a 64-bit value representing -// the number of 100-nanosecond intervals since January 1, 1601. - -static void ConvertFileTimeToWx(wxDateTime *dt, const FILETIME &ft) -{ - FILETIME ftcopy = ft; - FILETIME ftLocal; - if ( !::FileTimeToLocalFileTime(&ftcopy, &ftLocal) ) - { - wxLogLastError(_T("FileTimeToLocalFileTime")); - } - - SYSTEMTIME st; - if ( !::FileTimeToSystemTime(&ftLocal, &st) ) - { - wxLogLastError(_T("FileTimeToSystemTime")); - } - - dt->Set(st.wDay, wxDateTime::Month(st.wMonth - 1), st.wYear, - st.wHour, st.wMinute, st.wSecond, st.wMilliseconds); -} - -static void ConvertWxToFileTime(FILETIME *ft, const wxDateTime& dt) -{ - SYSTEMTIME st; - st.wDay = dt.GetDay(); - st.wMonth = (WORD)(dt.GetMonth() + 1); - st.wYear = (WORD)dt.GetYear(); - st.wHour = dt.GetHour(); - st.wMinute = dt.GetMinute(); - st.wSecond = dt.GetSecond(); - st.wMilliseconds = dt.GetMillisecond(); - - FILETIME ftLocal; - if ( !::SystemTimeToFileTime(&st, &ftLocal) ) - { - wxLogLastError(_T("SystemTimeToFileTime")); - } - - if ( !::LocalFileTimeToFileTime(&ftLocal, ft) ) - { - wxLogLastError(_T("LocalFileTimeToFileTime")); - } -} - -#endif // wxUSE_DATETIME && __WIN32__ - -// return a string with the volume par -static wxString wxGetVolumeString(const wxString& volume, wxPathFormat format) -{ - wxString path; - - if ( !volume.empty() ) - { - format = wxFileName::GetFormat(format); - - // Special Windows UNC paths hack, part 2: undo what we did in - // SplitPath() and make an UNC path if we have a drive which is not a - // single letter (hopefully the network shares can't be one letter only - // although I didn't find any authoritative docs on this) - if ( format == wxPATH_DOS && volume.length() > 1 ) - { - path << wxFILE_SEP_PATH_DOS << wxFILE_SEP_PATH_DOS << volume; - } - else if ( format == wxPATH_DOS || format == wxPATH_VMS ) - { - path << volume << wxFileName::GetVolumeSeparator(format); - } - // else ignore - } - - return path; -} - -// return true if the format used is the DOS/Windows one and the string looks -// like a UNC path -static bool IsUNCPath(const wxString& path, wxPathFormat format) -{ - return format == wxPATH_DOS && - path.length() >= 4 && // "\\a" can't be a UNC path - path[0u] == wxFILE_SEP_PATH_DOS && - path[1u] == wxFILE_SEP_PATH_DOS && - path[2u] != wxFILE_SEP_PATH_DOS; -} - -// ============================================================================ -// implementation -// ============================================================================ - -// ---------------------------------------------------------------------------- -// wxFileName construction -// ---------------------------------------------------------------------------- - -void wxFileName::Assign( const wxFileName &filepath ) -{ - m_volume = filepath.GetVolume(); - m_dirs = filepath.GetDirs(); - m_name = filepath.GetName(); - m_ext = filepath.GetExt(); - m_relative = filepath.m_relative; - m_hasExt = filepath.m_hasExt; -} - -void wxFileName::Assign(const wxString& volume, - const wxString& path, - const wxString& name, - const wxString& ext, - bool hasExt, - wxPathFormat format) -{ - // we should ignore paths which look like UNC shares because we already - // have the volume here and the UNC notation (\\server\path) is only valid - // for paths which don't start with a volume, so prevent SetPath() from - // recognizing "\\foo\bar" in "c:\\foo\bar" as an UNC path - // - // note also that this is a rather ugly way to do what we want (passing - // some kind of flag telling to ignore UNC paths to SetPath() would be - // better) but this is the safest thing to do to avoid breaking backwards - // compatibility in 2.8 - if ( IsUNCPath(path, format) ) - { - // remove one of the 2 leading backslashes to ensure that it's not - // recognized as an UNC path by SetPath() - wxString pathNonUNC(path, 1, wxString::npos); - SetPath(pathNonUNC, format); - } - else // no UNC complications - { - SetPath(path, format); - } - - m_volume = volume; - m_ext = ext; - m_name = name; - - m_hasExt = hasExt; -} - -void wxFileName::SetPath( const wxString& pathOrig, wxPathFormat format ) -{ - m_dirs.Clear(); - - if ( pathOrig.empty() ) - { - // no path at all - m_relative = true; - - return; - } - - format = GetFormat( format ); - - // 0) deal with possible volume part first - wxString volume, - path; - SplitVolume(pathOrig, &volume, &path, format); - if ( !volume.empty() ) - { - m_relative = false; - - SetVolume(volume); - } - - // 1) Determine if the path is relative or absolute. - wxChar leadingChar = path[0u]; - - switch (format) - { - case wxPATH_MAC: - m_relative = leadingChar == wxT(':'); - - // We then remove a leading ":". The reason is in our - // storage form for relative paths: - // ":dir:file.txt" actually means "./dir/file.txt" in - // DOS notation and should get stored as - // (relative) (dir) (file.txt) - // "::dir:file.txt" actually means "../dir/file.txt" - // stored as (relative) (..) (dir) (file.txt) - // This is important only for the Mac as an empty dir - // actually means , whereas under DOS, double - // slashes can be ignored: "\\\\" is the same as "\\". - if (m_relative) - path.erase( 0, 1 ); - break; - - case wxPATH_VMS: - // TODO: what is the relative path format here? - m_relative = false; - break; - - default: - wxFAIL_MSG( _T("Unknown path format") ); - // !! Fall through !! - - case wxPATH_UNIX: - // the paths of the form "~" or "~username" are absolute - m_relative = leadingChar != wxT('/') && leadingChar != _T('~'); - break; - - case wxPATH_DOS: - m_relative = !IsPathSeparator(leadingChar, format); - break; - - } - - // 2) Break up the path into its members. If the original path - // was just "/" or "\\", m_dirs will be empty. We know from - // the m_relative field, if this means "nothing" or "root dir". - - wxStringTokenizer tn( path, GetPathSeparators(format) ); - - while ( tn.HasMoreTokens() ) - { - wxString token = tn.GetNextToken(); - - // Remove empty token under DOS and Unix, interpret them - // as .. under Mac. - if (token.empty()) - { - if (format == wxPATH_MAC) - m_dirs.Add( wxT("..") ); - // else ignore - } - else - { - m_dirs.Add( token ); - } - } -} - -void wxFileName::Assign(const wxString& fullpath, - wxPathFormat format) -{ - wxString volume, path, name, ext; - bool hasExt; - SplitPath(fullpath, &volume, &path, &name, &ext, &hasExt, format); - - Assign(volume, path, name, ext, hasExt, format); -} - -void wxFileName::Assign(const wxString& fullpathOrig, - const wxString& fullname, - wxPathFormat format) -{ - // always recognize fullpath as directory, even if it doesn't end with a - // slash - wxString fullpath = fullpathOrig; - if ( !fullpath.empty() && !wxEndsWithPathSeparator(fullpath) ) - { - fullpath += GetPathSeparator(format); - } - - wxString volume, path, name, ext; - bool hasExt; - - // do some consistency checks in debug mode: the name should be really just - // the filename and the path should be really just a path -#ifdef __WXDEBUG__ - wxString volDummy, pathDummy, nameDummy, extDummy; - - SplitPath(fullname, &volDummy, &pathDummy, &name, &ext, &hasExt, format); - - wxASSERT_MSG( volDummy.empty() && pathDummy.empty(), - _T("the file name shouldn't contain the path") ); - - SplitPath(fullpath, &volume, &path, &nameDummy, &extDummy, format); - - wxASSERT_MSG( nameDummy.empty() && extDummy.empty(), - _T("the path shouldn't contain file name nor extension") ); - -#else // !__WXDEBUG__ - SplitPath(fullname, NULL /* no volume */, NULL /* no path */, - &name, &ext, &hasExt, format); - SplitPath(fullpath, &volume, &path, NULL, NULL, format); -#endif // __WXDEBUG__/!__WXDEBUG__ - - Assign(volume, path, name, ext, hasExt, format); -} - -void wxFileName::Assign(const wxString& pathOrig, - const wxString& name, - const wxString& ext, - wxPathFormat format) -{ - wxString volume, - path; - SplitVolume(pathOrig, &volume, &path, format); - - Assign(volume, path, name, ext, format); -} - -void wxFileName::AssignDir(const wxString& dir, wxPathFormat format) -{ - Assign(dir, wxEmptyString, format); -} - -void wxFileName::Clear() -{ - m_dirs.Clear(); - - m_volume = - m_name = - m_ext = wxEmptyString; - - // we don't have any absolute path for now - m_relative = true; - - // nor any extension - m_hasExt = false; -} - -/* static */ -wxFileName wxFileName::FileName(const wxString& file, wxPathFormat format) -{ - return wxFileName(file, format); -} - -/* static */ -wxFileName wxFileName::DirName(const wxString& dir, wxPathFormat format) -{ - wxFileName fn; - fn.AssignDir(dir, format); - return fn; -} - -// ---------------------------------------------------------------------------- -// existence tests -// ---------------------------------------------------------------------------- - -bool wxFileName::FileExists() const -{ - return wxFileName::FileExists( GetFullPath() ); -} - -bool wxFileName::FileExists( const wxString &file ) -{ - return ::wxFileExists( file ); -} - -bool wxFileName::DirExists() const -{ - return wxFileName::DirExists( GetPath() ); -} - -bool wxFileName::DirExists( const wxString &dir ) -{ - return ::wxDirExists( dir ); -} - -// ---------------------------------------------------------------------------- -// CWD and HOME stuff -// ---------------------------------------------------------------------------- - -void wxFileName::AssignCwd(const wxString& volume) -{ - AssignDir(wxFileName::GetCwd(volume)); -} - -/* static */ -wxString wxFileName::GetCwd(const wxString& volume) -{ - // if we have the volume, we must get the current directory on this drive - // and to do this we have to chdir to this volume - at least under Windows, - // I don't know how to get the current drive on another volume elsewhere - // (TODO) - wxString cwdOld; - if ( !volume.empty() ) - { - cwdOld = wxGetCwd(); - SetCwd(volume + GetVolumeSeparator()); - } - - wxString cwd = ::wxGetCwd(); - - if ( !volume.empty() ) - { - SetCwd(cwdOld); - } - - return cwd; -} - -bool wxFileName::SetCwd() -{ - return wxFileName::SetCwd( GetPath() ); -} - -bool wxFileName::SetCwd( const wxString &cwd ) -{ - return ::wxSetWorkingDirectory( cwd ); -} - -void wxFileName::AssignHomeDir() -{ - AssignDir(wxFileName::GetHomeDir()); -} - -wxString wxFileName::GetHomeDir() -{ - return ::wxGetHomeDir(); -} - - -// ---------------------------------------------------------------------------- -// CreateTempFileName -// ---------------------------------------------------------------------------- - -#if wxUSE_FILE || wxUSE_FFILE - - -#if !defined wx_fdopen && defined HAVE_FDOPEN - #define wx_fdopen fdopen -#endif - -// NB: GetTempFileName() under Windows creates the file, so using -// O_EXCL there would fail -#ifdef __WINDOWS__ - #define wxOPEN_EXCL 0 -#else - #define wxOPEN_EXCL O_EXCL -#endif - - -#ifdef wxOpenOSFHandle -#define WX_HAVE_DELETE_ON_CLOSE -// On Windows create a file with the FILE_FLAGS_DELETE_ON_CLOSE flags. -// -static int wxOpenWithDeleteOnClose(const wxString& filename) -{ - DWORD access = GENERIC_READ | GENERIC_WRITE; - - DWORD disposition = OPEN_ALWAYS; - - DWORD attributes = FILE_ATTRIBUTE_TEMPORARY | - FILE_FLAG_DELETE_ON_CLOSE; - - HANDLE h = ::CreateFile(filename, access, 0, NULL, - disposition, attributes, NULL); - - return wxOpenOSFHandle(h, wxO_BINARY); -} -#endif // wxOpenOSFHandle - - -// Helper to open the file -// -static int wxTempOpen(const wxString& path, bool *deleteOnClose) -{ -#ifdef WX_HAVE_DELETE_ON_CLOSE - if (*deleteOnClose) - return wxOpenWithDeleteOnClose(path); -#endif - - *deleteOnClose = false; - - return wxOpen(path, wxO_BINARY | O_RDWR | O_CREAT | wxOPEN_EXCL, 0600); -} - - -#if wxUSE_FFILE -// Helper to open the file and attach it to the wxFFile -// -static bool wxTempOpen(wxFFile *file, const wxString& path, bool *deleteOnClose) -{ -#ifndef wx_fdopen - *deleteOnClose = false; - return file->Open(path, _T("w+b")); -#else // wx_fdopen - int fd = wxTempOpen(path, deleteOnClose); - if (fd == -1) - return false; - file->Attach(wx_fdopen(fd, "w+b")); - return file->IsOpened(); -#endif // wx_fdopen -} -#endif // wxUSE_FFILE - - -#if !wxUSE_FILE - #define WXFILEARGS(x, y) y -#elif !wxUSE_FFILE - #define WXFILEARGS(x, y) x -#else - #define WXFILEARGS(x, y) x, y -#endif - - -// Implementation of wxFileName::CreateTempFileName(). -// -static wxString wxCreateTempImpl( - const wxString& prefix, - WXFILEARGS(wxFile *fileTemp, wxFFile *ffileTemp), - bool *deleteOnClose = NULL) -{ - static int pid = -1; -#if wxUSE_FILE && wxUSE_FFILE - wxASSERT(fileTemp == NULL || ffileTemp == NULL); -#endif - wxString path, dir, name; - bool wantDeleteOnClose = false; - - if (deleteOnClose) - { - // set the result to false initially - wantDeleteOnClose = *deleteOnClose; - *deleteOnClose = false; - } - else - { - // easier if it alwasys points to something - deleteOnClose = &wantDeleteOnClose; - } - - // use the directory specified by the prefix - wxFileName::SplitPath(prefix, &dir, &name, NULL /* extension */); - - if (dir.empty()) - { - dir = wxFileName::GetTempDir(); - } - -#if defined(__WXWINCE__) - path = dir + wxT("\\") + name; - int i = 1; - while (wxFileName::FileExists(path)) - { - path = dir + wxT("\\") + name ; - path << i; - i ++; - } - -#elif defined(__WINDOWS__) && !defined(__WXMICROWIN__) - if ( !::GetTempFileName(dir, name, 0, wxStringBuffer(path, MAX_PATH + 1)) ) - { - wxLogLastError(_T("GetTempFileName")); - - path.clear(); - } - -#else // !Windows - path = dir; - - if ( !wxEndsWithPathSeparator(dir) && - (name.empty() || !wxIsPathSeparator(name[0u])) ) - { - path += wxFILE_SEP_PATH; - } - - path += name; - -#if defined(HAVE_MKSTEMP) - // scratch space for mkstemp() - path += _T("XXXXXX"); - - // we need to copy the path to the buffer in which mkstemp() can modify it - wxCharBuffer buf( wxConvFile.cWX2MB( path ) ); - - // cast is safe because the string length doesn't change - int fdTemp = mkstemp( (char*)(const char*) buf ); - if ( fdTemp == -1 ) - { - // this might be not necessary as mkstemp() on most systems should have - // already done it but it doesn't hurt neither... - path.clear(); - } - else // mkstemp() succeeded - { - path = wxConvFile.cMB2WX( (const char*) buf ); - - #if wxUSE_FILE - // avoid leaking the fd - if ( fileTemp ) - { - fileTemp->Attach(fdTemp); - } - else - #endif - - #if wxUSE_FFILE - if ( ffileTemp ) - { - #ifdef wx_fdopen - ffileTemp->Attach(wx_fdopen(fdTemp, "r+b")); - #else - ffileTemp->Open(path, _T("r+b")); - close(fdTemp); - #endif - } - else - #endif - - { - close(fdTemp); - } - } -#else // !HAVE_MKSTEMP - -#ifdef HAVE_MKTEMP - // same as above - path += _T("XXXXXX"); - - wxCharBuffer buf = wxConvFile.cWX2MB( path ); - if ( !mktemp( (char*)(const char*) buf ) ) - { - path.clear(); - } - else - { - path = wxConvFile.cMB2WX( (const char*) buf ); - } -#else // !HAVE_MKTEMP (includes __DOS__) - // generate the unique file name ourselves - #if !defined(__DOS__) && !defined(__PALMOS__) && (!defined(__MWERKS__) || defined(__DARWIN__) ) - - if(pid < 0) - pid = getpid(); - - path << (unsigned int)pid; - #endif - - wxString pathTry; - - static const size_t numTries = 1000; - for ( size_t n = 0; n < numTries; n++ ) - { - // 3 hex digits is enough for numTries == 1000 < 4096 - pathTry = path + wxString::Format(_T("%.03x"), (unsigned int) n); - if ( !wxFileName::FileExists(pathTry) ) - { - break; - } - - pathTry.clear(); - } - - path = pathTry; -#endif // HAVE_MKTEMP/!HAVE_MKTEMP - -#endif // HAVE_MKSTEMP/!HAVE_MKSTEMP - -#endif // Windows/!Windows - - if ( path.empty() ) - { - wxLogSysError(_("Failed to create a temporary file name")); - } - else - { - bool ok = true; - - // open the file - of course, there is a race condition here, this is - // why we always prefer using mkstemp()... - #if wxUSE_FILE - if ( fileTemp && !fileTemp->IsOpened() ) - { - *deleteOnClose = wantDeleteOnClose; - int fd = wxTempOpen(path, deleteOnClose); - if (fd != -1) - fileTemp->Attach(fd); - else - ok = false; - } - #endif - - #if wxUSE_FFILE - if ( ffileTemp && !ffileTemp->IsOpened() ) - { - *deleteOnClose = wantDeleteOnClose; - ok = wxTempOpen(ffileTemp, path, deleteOnClose); - } - #endif - - if ( !ok ) - { - // FIXME: If !ok here should we loop and try again with another - // file name? That is the standard recourse if open(O_EXCL) - // fails, though of course it should be protected against - // possible infinite looping too. - - wxLogError(_("Failed to open temporary file.")); - - path.clear(); - } - } - - return path; -} - - -static bool wxCreateTempImpl( - const wxString& prefix, - WXFILEARGS(wxFile *fileTemp, wxFFile *ffileTemp), - wxString *name) -{ - bool deleteOnClose = true; - - *name = wxCreateTempImpl(prefix, - WXFILEARGS(fileTemp, ffileTemp), - &deleteOnClose); - - bool ok = !name->empty(); - - if (deleteOnClose) - name->clear(); -#ifdef __UNIX__ - else if (ok && wxRemoveFile(*name)) - name->clear(); -#endif - - return ok; -} - - -static void wxAssignTempImpl( - wxFileName *fn, - const wxString& prefix, - WXFILEARGS(wxFile *fileTemp, wxFFile *ffileTemp)) -{ - wxString tempname; - tempname = wxCreateTempImpl(prefix, WXFILEARGS(fileTemp, ffileTemp)); - - if ( tempname.empty() ) - { - // error, failed to get temp file name - fn->Clear(); - } - else // ok - { - fn->Assign(tempname); - } -} - - -void wxFileName::AssignTempFileName(const wxString& prefix) -{ - wxAssignTempImpl(this, prefix, WXFILEARGS(NULL, NULL)); -} - -/* static */ -wxString wxFileName::CreateTempFileName(const wxString& prefix) -{ - return wxCreateTempImpl(prefix, WXFILEARGS(NULL, NULL)); -} - -#endif // wxUSE_FILE || wxUSE_FFILE - - -#if wxUSE_FILE - -wxString wxCreateTempFileName(const wxString& prefix, - wxFile *fileTemp, - bool *deleteOnClose) -{ - return wxCreateTempImpl(prefix, WXFILEARGS(fileTemp, NULL), deleteOnClose); -} - -bool wxCreateTempFile(const wxString& prefix, - wxFile *fileTemp, - wxString *name) -{ - return wxCreateTempImpl(prefix, WXFILEARGS(fileTemp, NULL), name); -} - -void wxFileName::AssignTempFileName(const wxString& prefix, wxFile *fileTemp) -{ - wxAssignTempImpl(this, prefix, WXFILEARGS(fileTemp, NULL)); -} - -/* static */ -wxString -wxFileName::CreateTempFileName(const wxString& prefix, wxFile *fileTemp) -{ - return wxCreateTempFileName(prefix, fileTemp); -} - -#endif // wxUSE_FILE - - -#if wxUSE_FFILE - -wxString wxCreateTempFileName(const wxString& prefix, - wxFFile *fileTemp, - bool *deleteOnClose) -{ - return wxCreateTempImpl(prefix, WXFILEARGS(NULL, fileTemp), deleteOnClose); -} - -bool wxCreateTempFile(const wxString& prefix, - wxFFile *fileTemp, - wxString *name) -{ - return wxCreateTempImpl(prefix, WXFILEARGS(NULL, fileTemp), name); - -} - -void wxFileName::AssignTempFileName(const wxString& prefix, wxFFile *fileTemp) -{ - wxAssignTempImpl(this, prefix, WXFILEARGS(NULL, fileTemp)); -} - -/* static */ -wxString -wxFileName::CreateTempFileName(const wxString& prefix, wxFFile *fileTemp) -{ - return wxCreateTempFileName(prefix, fileTemp); -} - -#endif // wxUSE_FFILE - - -// ---------------------------------------------------------------------------- -// directory operations -// ---------------------------------------------------------------------------- - -wxString wxFileName::GetTempDir() -{ - wxString dir; - dir = wxGetenv(_T("TMPDIR")); - if (dir.empty()) - { - dir = wxGetenv(_T("TMP")); - if (dir.empty()) - { - dir = wxGetenv(_T("TEMP")); - } - } - -#if defined(__WXWINCE__) - if (dir.empty()) - { - // FIXME. Create \temp dir? - if (DirExists(wxT("\\temp"))) - dir = wxT("\\temp"); - } -#elif defined(__WINDOWS__) && !defined(__WXMICROWIN__) - - if ( dir.empty() ) - { - if ( !::GetTempPath(MAX_PATH, wxStringBuffer(dir, MAX_PATH + 1)) ) - { - wxLogLastError(_T("GetTempPath")); - } - - if ( dir.empty() ) - { - // GetTempFileName() fails if we pass it an empty string - dir = _T('.'); - } - } -#else // !Windows - - if ( dir.empty() ) - { - // default -#if defined(__DOS__) || defined(__OS2__) - dir = _T("."); -#elif defined(__WXMAC__) - dir = wxMacFindFolder(short(kOnSystemDisk), kTemporaryFolderType, kCreateFolder); -#else - dir = _T("/tmp"); -#endif - } -#endif - - return dir; -} - -bool wxFileName::Mkdir( int perm, int flags ) -{ - return wxFileName::Mkdir(GetPath(), perm, flags); -} - -bool wxFileName::Mkdir( const wxString& dir, int perm, int flags ) -{ - if ( flags & wxPATH_MKDIR_FULL ) - { - // split the path in components - wxFileName filename; - filename.AssignDir(dir); - - wxString currPath; - if ( filename.HasVolume()) - { - currPath << wxGetVolumeString(filename.GetVolume(), wxPATH_NATIVE); - } - - wxArrayString dirs = filename.GetDirs(); - size_t count = dirs.GetCount(); - for ( size_t i = 0; i < count; i++ ) - { - if ( i > 0 || -#if defined(__WXMAC__) && !defined(__DARWIN__) - // relative pathnames are exactely the other way round under mac... - !filename.IsAbsolute() -#else - filename.IsAbsolute() -#endif - ) - currPath += wxFILE_SEP_PATH; - currPath += dirs[i]; - - if (!DirExists(currPath)) - { - if (!wxMkdir(currPath, perm)) - { - // no need to try creating further directories - return false; - } - } - } - - return true; - - } - - return ::wxMkdir( dir, perm ); -} - -bool wxFileName::Rmdir() -{ - return wxFileName::Rmdir( GetPath() ); -} - -bool wxFileName::Rmdir( const wxString &dir ) -{ - return ::wxRmdir( dir ); -} - -// ---------------------------------------------------------------------------- -// path normalization -// ---------------------------------------------------------------------------- - -bool wxFileName::Normalize(int flags, - const wxString& cwd, - wxPathFormat format) -{ - // deal with env vars renaming first as this may seriously change the path - if ( flags & wxPATH_NORM_ENV_VARS ) - { - wxString pathOrig = GetFullPath(format); - wxString path = wxExpandEnvVars(pathOrig); - if ( path != pathOrig ) - { - Assign(path); - } - } - - - // the existing path components - wxArrayString dirs = GetDirs(); - - // the path to prepend in front to make the path absolute - wxFileName curDir; - - format = GetFormat(format); - - // set up the directory to use for making the path absolute later - if ( (flags & wxPATH_NORM_ABSOLUTE) && !IsAbsolute(format) ) - { - if ( cwd.empty() ) - { - curDir.AssignCwd(GetVolume()); - } - else // cwd provided - { - curDir.AssignDir(cwd); - } - } - - // handle ~ stuff under Unix only - if ( (format == wxPATH_UNIX) && (flags & wxPATH_NORM_TILDE) ) - { - if ( !dirs.IsEmpty() ) - { - wxString dir = dirs[0u]; - if ( !dir.empty() && dir[0u] == _T('~') ) - { - // to make the path absolute use the home directory - curDir.AssignDir(wxGetUserHome(dir.c_str() + 1)); - - // if we are expanding the tilde, then this path - // *should* be already relative (since we checked for - // the tilde only in the first char of the first dir); - // if m_relative==false, it's because it was initialized - // from a string which started with /~; in that case - // we reach this point but then need m_relative=true - // for relative->absolute expansion later - m_relative = true; - - dirs.RemoveAt(0u); - } - } - } - - // transform relative path into abs one - if ( curDir.IsOk() ) - { - // this path may be relative because it doesn't have the volume name - // and still have m_relative=true; in this case we shouldn't modify - // our directory components but just set the current volume - if ( !HasVolume() && curDir.HasVolume() ) - { - SetVolume(curDir.GetVolume()); - - if ( !m_relative ) - { - // yes, it was the case - we don't need curDir then - curDir.Clear(); - } - } - - // finally, prepend curDir to the dirs array - wxArrayString dirsNew = curDir.GetDirs(); - WX_PREPEND_ARRAY(dirs, dirsNew); - - // if we used e.g. tilde expansion previously and wxGetUserHome didn't - // return for some reason an absolute path, then curDir maybe not be absolute! - if ( curDir.IsAbsolute(format) ) - { - // we have prepended an absolute path and thus we are now an absolute - // file name too - m_relative = false; - } - // else if (flags & wxPATH_NORM_ABSOLUTE): - // should we warn the user that we didn't manage to make the path absolute? - } - - // now deal with ".", ".." and the rest - m_dirs.Empty(); - size_t count = dirs.GetCount(); - for ( size_t n = 0; n < count; n++ ) - { - wxString dir = dirs[n]; - - if ( flags & wxPATH_NORM_DOTS ) - { - if ( dir == wxT(".") ) - { - // just ignore - continue; - } - - if ( dir == wxT("..") ) - { - if ( m_dirs.IsEmpty() ) - { - wxLogError(_("The path '%s' contains too many \"..\"!"), - GetFullPath().c_str()); - return false; - } - - m_dirs.RemoveAt(m_dirs.GetCount() - 1); - continue; - } - } - - if ( (flags & wxPATH_NORM_CASE) && !IsCaseSensitive(format) ) - { - dir.MakeLower(); - } - - m_dirs.Add(dir); - } - -#if defined(__WIN32__) && !defined(__WXWINCE__) && wxUSE_OLE - if ( (flags & wxPATH_NORM_SHORTCUT) ) - { - wxString filename; - if (GetShortcutTarget(GetFullPath(format), filename)) - { - // Repeat this since we may now have a new path - if ( (flags & wxPATH_NORM_CASE) && !IsCaseSensitive(format) ) - { - filename.MakeLower(); - } - m_relative = false; - Assign(filename); - } - } -#endif - - if ( (flags & wxPATH_NORM_CASE) && !IsCaseSensitive(format) ) - { - // VZ: expand env vars here too? - - m_volume.MakeLower(); - m_name.MakeLower(); - m_ext.MakeLower(); - } - -#if defined(__WIN32__) - if ( (flags & wxPATH_NORM_LONG) && (format == wxPATH_DOS) ) - { - Assign(GetLongPath()); - } -#endif // Win32 - - return true; -} - -// ---------------------------------------------------------------------------- -// get the shortcut target -// ---------------------------------------------------------------------------- - -// WinCE (3) doesn't have CLSID_ShellLink, IID_IShellLink definitions. -// The .lnk file is a plain text file so it should be easy to -// make it work. Hint from Google Groups: -// "If you open up a lnk file, you'll see a -// number, followed by a pound sign (#), followed by more text. The -// number is the number of characters that follows the pound sign. The -// characters after the pound sign are the command line (which _can_ -// include arguments) to be executed. Any path (e.g. \windows\program -// files\myapp.exe) that includes spaces needs to be enclosed in -// quotation marks." - -#if defined(__WIN32__) && !defined(__WXWINCE__) && wxUSE_OLE -// The following lines are necessary under WinCE -// #include "wx/msw/private.h" -// #include -#include -#if defined(__WXWINCE__) -#include -#endif - -bool wxFileName::GetShortcutTarget(const wxString& shortcutPath, - wxString& targetFilename, - wxString* arguments) -{ - wxString path, file, ext; - wxSplitPath(shortcutPath, & path, & file, & ext); - - HRESULT hres; - IShellLink* psl; - bool success = false; - - // Assume it's not a shortcut if it doesn't end with lnk - if (ext.CmpNoCase(wxT("lnk"))!=0) - return false; - - // create a ShellLink object - hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, - IID_IShellLink, (LPVOID*) &psl); - - if (SUCCEEDED(hres)) - { - IPersistFile* ppf; - hres = psl->QueryInterface( IID_IPersistFile, (LPVOID *) &ppf); - if (SUCCEEDED(hres)) - { - WCHAR wsz[MAX_PATH]; - - MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, shortcutPath.mb_str(), -1, wsz, - MAX_PATH); - - hres = ppf->Load(wsz, 0); - ppf->Release(); - - if (SUCCEEDED(hres)) - { - wxChar buf[2048]; - // Wrong prototype in early versions -#if defined(__MINGW32__) && !wxCHECK_W32API_VERSION(2, 2) - psl->GetPath((CHAR*) buf, 2048, NULL, SLGP_UNCPRIORITY); -#else - psl->GetPath(buf, 2048, NULL, SLGP_UNCPRIORITY); -#endif - targetFilename = wxString(buf); - success = (shortcutPath != targetFilename); - - psl->GetArguments(buf, 2048); - wxString args(buf); - if (!args.empty() && arguments) - { - *arguments = args; - } - } - } - - psl->Release(); - } - return success; -} - -#endif // __WIN32__ && !__WXWINCE__ - - -// ---------------------------------------------------------------------------- -// absolute/relative paths -// ---------------------------------------------------------------------------- - -bool wxFileName::IsAbsolute(wxPathFormat format) const -{ - // if our path doesn't start with a path separator, it's not an absolute - // path - if ( m_relative ) - return false; - - if ( !GetVolumeSeparator(format).empty() ) - { - // this format has volumes and an absolute path must have one, it's not - // enough to have the full path to bean absolute file under Windows - if ( GetVolume().empty() ) - return false; - } - - return true; -} - -bool wxFileName::MakeRelativeTo(const wxString& pathBase, wxPathFormat format) -{ - wxFileName fnBase = wxFileName::DirName(pathBase, format); - - // get cwd only once - small time saving - wxString cwd = wxGetCwd(); - Normalize(wxPATH_NORM_ALL & ~wxPATH_NORM_CASE, cwd, format); - fnBase.Normalize(wxPATH_NORM_ALL & ~wxPATH_NORM_CASE, cwd, format); - - bool withCase = IsCaseSensitive(format); - - // we can't do anything if the files live on different volumes - if ( !GetVolume().IsSameAs(fnBase.GetVolume(), withCase) ) - { - // nothing done - return false; - } - - // same drive, so we don't need our volume - m_volume.clear(); - - // remove common directories starting at the top - while ( !m_dirs.IsEmpty() && !fnBase.m_dirs.IsEmpty() && - m_dirs[0u].IsSameAs(fnBase.m_dirs[0u], withCase) ) - { - m_dirs.RemoveAt(0); - fnBase.m_dirs.RemoveAt(0); - } - - // add as many ".." as needed - size_t count = fnBase.m_dirs.GetCount(); - for ( size_t i = 0; i < count; i++ ) - { - m_dirs.Insert(wxT(".."), 0u); - } - - if ( format == wxPATH_UNIX || format == wxPATH_DOS ) - { - // a directory made relative with respect to itself is '.' under Unix - // and DOS, by definition (but we don't have to insert "./" for the - // files) - if ( m_dirs.IsEmpty() && IsDir() ) - { - m_dirs.Add(_T('.')); - } - } - - m_relative = true; - - // we were modified - return true; -} - -// ---------------------------------------------------------------------------- -// filename kind tests -// ---------------------------------------------------------------------------- - -bool wxFileName::SameAs(const wxFileName& filepath, wxPathFormat format) const -{ - wxFileName fn1 = *this, - fn2 = filepath; - - // get cwd only once - small time saving - wxString cwd = wxGetCwd(); - fn1.Normalize(wxPATH_NORM_ALL | wxPATH_NORM_CASE, cwd, format); - fn2.Normalize(wxPATH_NORM_ALL | wxPATH_NORM_CASE, cwd, format); - - if ( fn1.GetFullPath() == fn2.GetFullPath() ) - return true; - - // TODO: compare inodes for Unix, this works even when filenames are - // different but files are the same (symlinks) (VZ) - - return false; -} - -/* static */ -bool wxFileName::IsCaseSensitive( wxPathFormat format ) -{ - // only Unix filenames are truely case-sensitive - return GetFormat(format) == wxPATH_UNIX; -} - -/* static */ -wxString wxFileName::GetForbiddenChars(wxPathFormat format) -{ - // Inits to forbidden characters that are common to (almost) all platforms. - wxString strForbiddenChars = wxT("*?"); - - // If asserts, wxPathFormat has been changed. In case of a new path format - // addition, the following code might have to be updated. - wxCOMPILE_TIME_ASSERT(wxPATH_MAX == 5, wxPathFormatChanged); - switch ( GetFormat(format) ) - { - default : - wxFAIL_MSG( wxT("Unknown path format") ); - // !! Fall through !! - - case wxPATH_UNIX: - break; - - case wxPATH_MAC: - // On a Mac even names with * and ? are allowed (Tested with OS - // 9.2.1 and OS X 10.2.5) - strForbiddenChars = wxEmptyString; - break; - - case wxPATH_DOS: - strForbiddenChars += wxT("\\/:\"<>|"); - break; - - case wxPATH_VMS: - break; - } - - return strForbiddenChars; -} - -/* static */ -wxString wxFileName::GetVolumeSeparator(wxPathFormat WXUNUSED_IN_WINCE(format)) -{ -#ifdef __WXWINCE__ - return wxEmptyString; -#else - wxString sepVol; - - if ( (GetFormat(format) == wxPATH_DOS) || - (GetFormat(format) == wxPATH_VMS) ) - { - sepVol = wxFILE_SEP_DSK; - } - //else: leave empty - - return sepVol; -#endif -} - -/* static */ -wxString wxFileName::GetPathSeparators(wxPathFormat format) -{ - wxString seps; - switch ( GetFormat(format) ) - { - case wxPATH_DOS: - // accept both as native APIs do but put the native one first as - // this is the one we use in GetFullPath() - seps << wxFILE_SEP_PATH_DOS << wxFILE_SEP_PATH_UNIX; - break; - - default: - wxFAIL_MSG( _T("Unknown wxPATH_XXX style") ); - // fall through - - case wxPATH_UNIX: - seps = wxFILE_SEP_PATH_UNIX; - break; - - case wxPATH_MAC: - seps = wxFILE_SEP_PATH_MAC; - break; - - case wxPATH_VMS: - seps = wxFILE_SEP_PATH_VMS; - break; - } - - return seps; -} - -/* static */ -wxString wxFileName::GetPathTerminators(wxPathFormat format) -{ - format = GetFormat(format); - - // under VMS the end of the path is ']', not the path separator used to - // separate the components - return format == wxPATH_VMS ? wxString(_T(']')) : GetPathSeparators(format); -} - -/* static */ -bool wxFileName::IsPathSeparator(wxChar ch, wxPathFormat format) -{ - // wxString::Find() doesn't work as expected with NUL - it will always find - // it, so test for it separately - return ch != _T('\0') && GetPathSeparators(format).Find(ch) != wxNOT_FOUND; -} - -// ---------------------------------------------------------------------------- -// path components manipulation -// ---------------------------------------------------------------------------- - -/* static */ bool wxFileName::IsValidDirComponent(const wxString& dir) -{ - if ( dir.empty() ) - { - wxFAIL_MSG( _T("empty directory passed to wxFileName::InsertDir()") ); - - return false; - } - - const size_t len = dir.length(); - for ( size_t n = 0; n < len; n++ ) - { - if ( dir[n] == GetVolumeSeparator() || IsPathSeparator(dir[n]) ) - { - wxFAIL_MSG( _T("invalid directory component in wxFileName") ); - - return false; - } - } - - return true; -} - -void wxFileName::AppendDir( const wxString& dir ) -{ - if ( IsValidDirComponent(dir) ) - m_dirs.Add( dir ); -} - -void wxFileName::PrependDir( const wxString& dir ) -{ - InsertDir(0, dir); -} - -void wxFileName::InsertDir(size_t before, const wxString& dir) -{ - if ( IsValidDirComponent(dir) ) - m_dirs.Insert(dir, before); -} - -void wxFileName::RemoveDir(size_t pos) -{ - m_dirs.RemoveAt(pos); -} - -// ---------------------------------------------------------------------------- -// accessors -// ---------------------------------------------------------------------------- - -void wxFileName::SetFullName(const wxString& fullname) -{ - SplitPath(fullname, NULL /* no volume */, NULL /* no path */, - &m_name, &m_ext, &m_hasExt); -} - -wxString wxFileName::GetFullName() const -{ - wxString fullname = m_name; - if ( m_hasExt ) - { - fullname << wxFILE_SEP_EXT << m_ext; - } - - return fullname; -} - -wxString wxFileName::GetPath( int flags, wxPathFormat format ) const -{ - format = GetFormat( format ); - - wxString fullpath; - - // return the volume with the path as well if requested - if ( flags & wxPATH_GET_VOLUME ) - { - fullpath += wxGetVolumeString(GetVolume(), format); - } - - // the leading character - switch ( format ) - { - case wxPATH_MAC: - if ( m_relative ) - fullpath += wxFILE_SEP_PATH_MAC; - break; - - case wxPATH_DOS: - if ( !m_relative ) - fullpath += wxFILE_SEP_PATH_DOS; - break; - - default: - wxFAIL_MSG( wxT("Unknown path format") ); - // fall through - - case wxPATH_UNIX: - if ( !m_relative ) - { - // normally the absolute file names start with a slash - // with one exception: the ones like "~/foo.bar" don't - // have it - if ( m_dirs.IsEmpty() || m_dirs[0u] != _T('~') ) - { - fullpath += wxFILE_SEP_PATH_UNIX; - } - } - break; - - case wxPATH_VMS: - // no leading character here but use this place to unset - // wxPATH_GET_SEPARATOR flag: under VMS it doesn't make sense - // as, if I understand correctly, there should never be a dot - // before the closing bracket - flags &= ~wxPATH_GET_SEPARATOR; - } - - if ( m_dirs.empty() ) - { - // there is nothing more - return fullpath; - } - - // then concatenate all the path components using the path separator - if ( format == wxPATH_VMS ) - { - fullpath += wxT('['); - } - - const size_t dirCount = m_dirs.GetCount(); - for ( size_t i = 0; i < dirCount; i++ ) - { - switch (format) - { - case wxPATH_MAC: - if ( m_dirs[i] == wxT(".") ) - { - // skip appending ':', this shouldn't be done in this - // case as "::" is interpreted as ".." under Unix - continue; - } - - // convert back from ".." to nothing - if ( !m_dirs[i].IsSameAs(wxT("..")) ) - fullpath += m_dirs[i]; - break; - - default: - wxFAIL_MSG( wxT("Unexpected path format") ); - // still fall through - - case wxPATH_DOS: - case wxPATH_UNIX: - fullpath += m_dirs[i]; - break; - - case wxPATH_VMS: - // TODO: What to do with ".." under VMS - - // convert back from ".." to nothing - if ( !m_dirs[i].IsSameAs(wxT("..")) ) - fullpath += m_dirs[i]; - break; - } - - if ( (flags & wxPATH_GET_SEPARATOR) || (i != dirCount - 1) ) - fullpath += GetPathSeparator(format); - } - - if ( format == wxPATH_VMS ) - { - fullpath += wxT(']'); - } - - return fullpath; -} - -wxString wxFileName::GetFullPath( wxPathFormat format ) const -{ - // we already have a function to get the path - wxString fullpath = GetPath(wxPATH_GET_VOLUME | wxPATH_GET_SEPARATOR, - format); - - // now just add the file name and extension to it - fullpath += GetFullName(); - - return fullpath; -} - -// Return the short form of the path (returns identity on non-Windows platforms) -wxString wxFileName::GetShortPath() const -{ - wxString path(GetFullPath()); - -#if defined(__WXMSW__) && defined(__WIN32__) && !defined(__WXMICROWIN__) && !defined(__WXWINCE__) - DWORD sz = ::GetShortPathName(path, NULL, 0); - if ( sz != 0 ) - { - wxString pathOut; - if ( ::GetShortPathName - ( - path, - wxStringBuffer(pathOut, sz), - sz - ) != 0 ) - { - return pathOut; - } - } -#endif // Windows - - return path; -} - -// Return the long form of the path (returns identity on non-Windows platforms) -wxString wxFileName::GetLongPath() const -{ - wxString pathOut, - path = GetFullPath(); - -#if defined(__WIN32__) && !defined(__WXWINCE__) && !defined(__WXMICROWIN__) - -#if wxUSE_DYNLIB_CLASS - typedef DWORD (WINAPI *GET_LONG_PATH_NAME)(const wxChar *, wxChar *, DWORD); - - // this is MT-safe as in the worst case we're going to resolve the function - // twice -- but as the result is the same in both threads, it's ok - static GET_LONG_PATH_NAME s_pfnGetLongPathName = NULL; - if ( !s_pfnGetLongPathName ) - { - static bool s_triedToLoad = false; - - if ( !s_triedToLoad ) - { - s_triedToLoad = true; - - wxDynamicLibrary dllKernel(_T("kernel32")); - - const wxChar* GetLongPathName = _T("GetLongPathName") -#if wxUSE_UNICODE - _T("W"); -#else // ANSI - _T("A"); -#endif // Unicode/ANSI - - if ( dllKernel.HasSymbol(GetLongPathName) ) - { - s_pfnGetLongPathName = (GET_LONG_PATH_NAME) - dllKernel.GetSymbol(GetLongPathName); - } - - // note that kernel32.dll can be unloaded, it stays in memory - // anyhow as all Win32 programs link to it and so it's safe to call - // GetLongPathName() even after unloading it - } - } - - if ( s_pfnGetLongPathName ) - { - DWORD dwSize = (*s_pfnGetLongPathName)(path, NULL, 0); - if ( dwSize > 0 ) - { - if ( (*s_pfnGetLongPathName) - ( - path, - wxStringBuffer(pathOut, dwSize), - dwSize - ) != 0 ) - { - return pathOut; - } - } - } -#endif // wxUSE_DYNLIB_CLASS - - // The OS didn't support GetLongPathName, or some other error. - // We need to call FindFirstFile on each component in turn. - - WIN32_FIND_DATA findFileData; - HANDLE hFind; - - if ( HasVolume() ) - pathOut = GetVolume() + - GetVolumeSeparator(wxPATH_DOS) + - GetPathSeparator(wxPATH_DOS); - else - pathOut = wxEmptyString; - - wxArrayString dirs = GetDirs(); - dirs.Add(GetFullName()); - - wxString tmpPath; - - size_t count = dirs.GetCount(); - for ( size_t i = 0; i < count; i++ ) - { - // We're using pathOut to collect the long-name path, but using a - // temporary for appending the last path component which may be - // short-name - tmpPath = pathOut + dirs[i]; - - if ( tmpPath.empty() ) - continue; - - // can't see this being necessary? MF - if ( tmpPath.Last() == GetVolumeSeparator(wxPATH_DOS) ) - { - // Can't pass a drive and root dir to FindFirstFile, - // so continue to next dir - tmpPath += wxFILE_SEP_PATH; - pathOut = tmpPath; - continue; - } - - hFind = ::FindFirstFile(tmpPath, &findFileData); - if (hFind == INVALID_HANDLE_VALUE) - { - // Error: most likely reason is that path doesn't exist, so - // append any unprocessed parts and return - for ( i += 1; i < count; i++ ) - tmpPath += wxFILE_SEP_PATH + dirs[i]; - - return tmpPath; - } - - pathOut += findFileData.cFileName; - if ( (i < (count-1)) ) - pathOut += wxFILE_SEP_PATH; - - ::FindClose(hFind); - } -#else // !Win32 - pathOut = path; -#endif // Win32/!Win32 - - return pathOut; -} - -wxPathFormat wxFileName::GetFormat( wxPathFormat format ) -{ - if (format == wxPATH_NATIVE) - { -#if defined(__WXMSW__) || defined(__OS2__) || defined(__DOS__) - format = wxPATH_DOS; -#elif defined(__WXMAC__) && !defined(__DARWIN__) - format = wxPATH_MAC; -#elif defined(__VMS) - format = wxPATH_VMS; -#else - format = wxPATH_UNIX; -#endif - } - return format; -} - -// ---------------------------------------------------------------------------- -// path splitting function -// ---------------------------------------------------------------------------- - -/* static */ -void -wxFileName::SplitVolume(const wxString& fullpathWithVolume, - wxString *pstrVolume, - wxString *pstrPath, - wxPathFormat format) -{ - format = GetFormat(format); - - wxString fullpath = fullpathWithVolume; - - // special Windows UNC paths hack: transform \\share\path into share:path - if ( IsUNCPath(fullpath, format) ) - { - fullpath.erase(0, 2); - - size_t posFirstSlash = - fullpath.find_first_of(GetPathTerminators(format)); - if ( posFirstSlash != wxString::npos ) - { - fullpath[posFirstSlash] = wxFILE_SEP_DSK; - - // UNC paths are always absolute, right? (FIXME) - fullpath.insert(posFirstSlash + 1, 1, wxFILE_SEP_PATH_DOS); - } - } - - // We separate the volume here - if ( format == wxPATH_DOS || format == wxPATH_VMS ) - { - wxString sepVol = GetVolumeSeparator(format); - - size_t posFirstColon = fullpath.find_first_of(sepVol); - if ( posFirstColon != wxString::npos ) - { - if ( pstrVolume ) - { - *pstrVolume = fullpath.Left(posFirstColon); - } - - // remove the volume name and the separator from the full path - fullpath.erase(0, posFirstColon + sepVol.length()); - } - } - - if ( pstrPath ) - *pstrPath = fullpath; -} - -/* static */ -void wxFileName::SplitPath(const wxString& fullpathWithVolume, - wxString *pstrVolume, - wxString *pstrPath, - wxString *pstrName, - wxString *pstrExt, - bool *hasExt, - wxPathFormat format) -{ - format = GetFormat(format); - - wxString fullpath; - SplitVolume(fullpathWithVolume, pstrVolume, &fullpath, format); - - // find the positions of the last dot and last path separator in the path - size_t posLastDot = fullpath.find_last_of(wxFILE_SEP_EXT); - size_t posLastSlash = fullpath.find_last_of(GetPathTerminators(format)); - - // check whether this dot occurs at the very beginning of a path component - if ( (posLastDot != wxString::npos) && - (posLastDot == 0 || - IsPathSeparator(fullpath[posLastDot - 1]) || - (format == wxPATH_VMS && fullpath[posLastDot - 1] == _T(']'))) ) - { - // dot may be (and commonly -- at least under Unix -- is) the first - // character of the filename, don't treat the entire filename as - // extension in this case - posLastDot = wxString::npos; - } - - // if we do have a dot and a slash, check that the dot is in the name part - if ( (posLastDot != wxString::npos) && - (posLastSlash != wxString::npos) && - (posLastDot < posLastSlash) ) - { - // the dot is part of the path, not the start of the extension - posLastDot = wxString::npos; - } - - // now fill in the variables provided by user - if ( pstrPath ) - { - if ( posLastSlash == wxString::npos ) - { - // no path at all - pstrPath->Empty(); - } - else - { - // take everything up to the path separator but take care to make - // the path equal to something like '/', not empty, for the files - // immediately under root directory - size_t len = posLastSlash; - - // this rule does not apply to mac since we do not start with colons (sep) - // except for relative paths - if ( !len && format != wxPATH_MAC) - len++; - - *pstrPath = fullpath.Left(len); - - // special VMS hack: remove the initial bracket - if ( format == wxPATH_VMS ) - { - if ( (*pstrPath)[0u] == _T('[') ) - pstrPath->erase(0, 1); - } - } - } - - if ( pstrName ) - { - // take all characters starting from the one after the last slash and - // up to, but excluding, the last dot - size_t nStart = posLastSlash == wxString::npos ? 0 : posLastSlash + 1; - size_t count; - if ( posLastDot == wxString::npos ) - { - // take all until the end - count = wxString::npos; - } - else if ( posLastSlash == wxString::npos ) - { - count = posLastDot; - } - else // have both dot and slash - { - count = posLastDot - posLastSlash - 1; - } - - *pstrName = fullpath.Mid(nStart, count); - } - - // finally deal with the extension here: we have an added complication that - // extension may be empty (but present) as in "foo." where trailing dot - // indicates the empty extension at the end -- and hence we must remember - // that we have it independently of pstrExt - if ( posLastDot == wxString::npos ) - { - // no extension - if ( pstrExt ) - pstrExt->clear(); - if ( hasExt ) - *hasExt = false; - } - else - { - // take everything after the dot - if ( pstrExt ) - *pstrExt = fullpath.Mid(posLastDot + 1); - if ( hasExt ) - *hasExt = true; - } -} - -/* static */ -void wxFileName::SplitPath(const wxString& fullpath, - wxString *path, - wxString *name, - wxString *ext, - wxPathFormat format) -{ - wxString volume; - SplitPath(fullpath, &volume, path, name, ext, format); - - if ( path ) - { - path->Prepend(wxGetVolumeString(volume, format)); - } -} - -// ---------------------------------------------------------------------------- -// time functions -// ---------------------------------------------------------------------------- - -#if wxUSE_DATETIME - -bool wxFileName::SetTimes(const wxDateTime *dtAccess, - const wxDateTime *dtMod, - const wxDateTime *dtCreate) -{ -#if defined(__WIN32__) - if ( IsDir() ) - { - // VZ: please let me know how to do this if you can - wxFAIL_MSG( _T("SetTimes() not implemented for the directories") ); - } - else // file - { - wxFileHandle fh(GetFullPath(), wxFileHandle::Write); - if ( fh.IsOk() ) - { - FILETIME ftAccess, ftCreate, ftWrite; - - if ( dtCreate ) - ConvertWxToFileTime(&ftCreate, *dtCreate); - if ( dtAccess ) - ConvertWxToFileTime(&ftAccess, *dtAccess); - if ( dtMod ) - ConvertWxToFileTime(&ftWrite, *dtMod); - - if ( ::SetFileTime(fh, - dtCreate ? &ftCreate : NULL, - dtAccess ? &ftAccess : NULL, - dtMod ? &ftWrite : NULL) ) - { - return true; - } - } - } -#elif defined(__UNIX_LIKE__) || (defined(__DOS__) && defined(__WATCOMC__)) - wxUnusedVar(dtCreate); - - if ( !dtAccess && !dtMod ) - { - // can't modify the creation time anyhow, don't try - return true; - } - - // if dtAccess or dtMod is not specified, use the other one (which must be - // non NULL because of the test above) for both times - utimbuf utm; - utm.actime = dtAccess ? dtAccess->GetTicks() : dtMod->GetTicks(); - utm.modtime = dtMod ? dtMod->GetTicks() : dtAccess->GetTicks(); - if ( utime(GetFullPath().fn_str(), &utm) == 0 ) - { - return true; - } -#else // other platform - wxUnusedVar(dtAccess); - wxUnusedVar(dtMod); - wxUnusedVar(dtCreate); -#endif // platforms - - wxLogSysError(_("Failed to modify file times for '%s'"), - GetFullPath().c_str()); - - return false; -} - -bool wxFileName::Touch() -{ -#if defined(__UNIX_LIKE__) - // under Unix touching file is simple: just pass NULL to utime() - if ( utime(GetFullPath().fn_str(), NULL) == 0 ) - { - return true; - } - - wxLogSysError(_("Failed to touch the file '%s'"), GetFullPath().c_str()); - - return false; -#else // other platform - wxDateTime dtNow = wxDateTime::Now(); - - return SetTimes(&dtNow, &dtNow, NULL /* don't change create time */); -#endif // platforms -} - -#ifdef wxNEED_WX_UNISTD_H - -static int wxStat( const char *file_name, wxStructStat *buf ) -{ - return stat( file_name , buf ); -} - -#endif - -bool wxFileName::GetTimes(wxDateTime *dtAccess, - wxDateTime *dtMod, - wxDateTime *dtCreate) const -{ -#if defined(__WIN32__) - // we must use different methods for the files and directories under - // Windows as CreateFile(GENERIC_READ) doesn't work for the directories and - // CreateFile(FILE_FLAG_BACKUP_SEMANTICS) works -- but only under NT and - // not 9x - bool ok; - FILETIME ftAccess, ftCreate, ftWrite; - if ( IsDir() ) - { - // implemented in msw/dir.cpp - extern bool wxGetDirectoryTimes(const wxString& dirname, - FILETIME *, FILETIME *, FILETIME *); - - // we should pass the path without the trailing separator to - // wxGetDirectoryTimes() - ok = wxGetDirectoryTimes(GetPath(wxPATH_GET_VOLUME), - &ftAccess, &ftCreate, &ftWrite); - } - else // file - { - wxFileHandle fh(GetFullPath(), wxFileHandle::Read); - if ( fh.IsOk() ) - { - ok = ::GetFileTime(fh, - dtCreate ? &ftCreate : NULL, - dtAccess ? &ftAccess : NULL, - dtMod ? &ftWrite : NULL) != 0; - } - else - { - ok = false; - } - } - - if ( ok ) - { - if ( dtCreate ) - ConvertFileTimeToWx(dtCreate, ftCreate); - if ( dtAccess ) - ConvertFileTimeToWx(dtAccess, ftAccess); - if ( dtMod ) - ConvertFileTimeToWx(dtMod, ftWrite); - - return true; - } -#elif defined(__UNIX_LIKE__) || defined(__WXMAC__) || defined(__OS2__) || (defined(__DOS__) && defined(__WATCOMC__)) - // no need to test for IsDir() here - wxStructStat stBuf; - if ( wxStat( GetFullPath().fn_str(), &stBuf) == 0 ) - { - if ( dtAccess ) - dtAccess->Set(stBuf.st_atime); - if ( dtMod ) - dtMod->Set(stBuf.st_mtime); - if ( dtCreate ) - dtCreate->Set(stBuf.st_ctime); - - return true; - } -#else // other platform - wxUnusedVar(dtAccess); - wxUnusedVar(dtMod); - wxUnusedVar(dtCreate); -#endif // platforms - - wxLogSysError(_("Failed to retrieve file times for '%s'"), - GetFullPath().c_str()); - - return false; -} - -#endif // wxUSE_DATETIME - - -// ---------------------------------------------------------------------------- -// file size functions -// ---------------------------------------------------------------------------- - -/* static */ -wxULongLong wxFileName::GetSize(const wxString &filename) -{ - if (!wxFileExists(filename)) - return wxInvalidSize; - -#if defined(__WXPALMOS__) - // TODO - return wxInvalidSize; -#elif defined(__WIN32__) - wxFileHandle f(filename, wxFileHandle::Read); - if (!f.IsOk()) - return wxInvalidSize; - - DWORD lpFileSizeHigh; - DWORD ret = GetFileSize(f, &lpFileSizeHigh); - if ( ret == INVALID_FILE_SIZE && ::GetLastError() != NO_ERROR ) - return wxInvalidSize; - - return wxULongLong(lpFileSizeHigh, ret); -#else // ! __WIN32__ - wxStructStat st; -#ifndef wxNEED_WX_UNISTD_H - if (wxStat( filename.fn_str() , &st) != 0) -#else - if (wxStat( filename, &st) != 0) -#endif - return wxInvalidSize; - return wxULongLong(st.st_size); -#endif -} - -/* static */ -wxString wxFileName::GetHumanReadableSize(const wxULongLong &bs, - const wxString &nullsize, - int precision) -{ - static const double KILOBYTESIZE = 1024.0; - static const double MEGABYTESIZE = 1024.0*KILOBYTESIZE; - static const double GIGABYTESIZE = 1024.0*MEGABYTESIZE; - static const double TERABYTESIZE = 1024.0*GIGABYTESIZE; - - if (bs == 0 || bs == wxInvalidSize) - return nullsize; - - double bytesize = bs.ToDouble(); - if (bytesize < KILOBYTESIZE) - return wxString::Format(_("%s B"), bs.ToString().c_str()); - if (bytesize < MEGABYTESIZE) - return wxString::Format(_("%.*f kB"), precision, bytesize/KILOBYTESIZE); - if (bytesize < GIGABYTESIZE) - return wxString::Format(_("%.*f MB"), precision, bytesize/MEGABYTESIZE); - if (bytesize < TERABYTESIZE) - return wxString::Format(_("%.*f GB"), precision, bytesize/GIGABYTESIZE); - - return wxString::Format(_("%.*f TB"), precision, bytesize/TERABYTESIZE); -} - -wxULongLong wxFileName::GetSize() const -{ - return GetSize(GetFullPath()); -} - -wxString wxFileName::GetHumanReadableSize(const wxString &failmsg, int precision) const -{ - return GetHumanReadableSize(GetSize(), failmsg, precision); -} - - -// ---------------------------------------------------------------------------- -// Mac-specific functions -// ---------------------------------------------------------------------------- - -#ifdef __WXMAC__ - -const short kMacExtensionMaxLength = 16 ; -class MacDefaultExtensionRecord -{ -public : - MacDefaultExtensionRecord() - { - m_ext[0] = 0 ; - m_type = m_creator = 0 ; - } - MacDefaultExtensionRecord( const MacDefaultExtensionRecord& from ) - { - wxStrcpy( m_ext , from.m_ext ) ; - m_type = from.m_type ; - m_creator = from.m_creator ; - } - MacDefaultExtensionRecord( const wxChar * extension , OSType type , OSType creator ) - { - wxStrncpy( m_ext , extension , kMacExtensionMaxLength ) ; - m_ext[kMacExtensionMaxLength] = 0 ; - m_type = type ; - m_creator = creator ; - } - wxChar m_ext[kMacExtensionMaxLength] ; - OSType m_type ; - OSType m_creator ; -} ; - -WX_DECLARE_OBJARRAY(MacDefaultExtensionRecord, MacDefaultExtensionArray) ; - -bool gMacDefaultExtensionsInited = false ; - -#include "wx/arrimpl.cpp" - -WX_DEFINE_EXPORTED_OBJARRAY(MacDefaultExtensionArray) ; - -MacDefaultExtensionArray gMacDefaultExtensions ; - -// load the default extensions -MacDefaultExtensionRecord gDefaults[] = -{ - MacDefaultExtensionRecord( wxT("txt") , 'TEXT' , 'ttxt' ) , - MacDefaultExtensionRecord( wxT("tif") , 'TIFF' , '****' ) , - MacDefaultExtensionRecord( wxT("jpg") , 'JPEG' , '****' ) , -} ; - -static void MacEnsureDefaultExtensionsLoaded() -{ - if ( !gMacDefaultExtensionsInited ) - { - // we could load the pc exchange prefs here too - for ( size_t i = 0 ; i < WXSIZEOF( gDefaults ) ; ++i ) - { - gMacDefaultExtensions.Add( gDefaults[i] ) ; - } - gMacDefaultExtensionsInited = true ; - } -} - -bool wxFileName::MacSetTypeAndCreator( wxUint32 type , wxUint32 creator ) -{ - FSRef fsRef ; - FSCatalogInfo catInfo; - FileInfo *finfo ; - - if ( wxMacPathToFSRef( GetFullPath() , &fsRef ) == noErr ) - { - if ( FSGetCatalogInfo (&fsRef, kFSCatInfoFinderInfo, &catInfo, NULL, NULL, NULL) == noErr ) - { - finfo = (FileInfo*)&catInfo.finderInfo; - finfo->fileType = type ; - finfo->fileCreator = creator ; - FSSetCatalogInfo( &fsRef, kFSCatInfoFinderInfo, &catInfo ) ; - return true ; - } - } - return false ; -} - -bool wxFileName::MacGetTypeAndCreator( wxUint32 *type , wxUint32 *creator ) -{ - FSRef fsRef ; - FSCatalogInfo catInfo; - FileInfo *finfo ; - - if ( wxMacPathToFSRef( GetFullPath() , &fsRef ) == noErr ) - { - if ( FSGetCatalogInfo (&fsRef, kFSCatInfoFinderInfo, &catInfo, NULL, NULL, NULL) == noErr ) - { - finfo = (FileInfo*)&catInfo.finderInfo; - *type = finfo->fileType ; - *creator = finfo->fileCreator ; - return true ; - } - } - return false ; -} - -bool wxFileName::MacSetDefaultTypeAndCreator() -{ - wxUint32 type , creator ; - if ( wxFileName::MacFindDefaultTypeAndCreator(GetExt() , &type , - &creator ) ) - { - return MacSetTypeAndCreator( type , creator ) ; - } - return false; -} - -bool wxFileName::MacFindDefaultTypeAndCreator( const wxString& ext , wxUint32 *type , wxUint32 *creator ) -{ - MacEnsureDefaultExtensionsLoaded() ; - wxString extl = ext.Lower() ; - for( int i = gMacDefaultExtensions.Count() - 1 ; i >= 0 ; --i ) - { - if ( gMacDefaultExtensions.Item(i).m_ext == extl ) - { - *type = gMacDefaultExtensions.Item(i).m_type ; - *creator = gMacDefaultExtensions.Item(i).m_creator ; - return true ; - } - } - return false ; -} - -void wxFileName::MacRegisterDefaultTypeAndCreator( const wxString& ext , wxUint32 type , wxUint32 creator ) -{ - MacEnsureDefaultExtensionsLoaded() ; - MacDefaultExtensionRecord rec ; - rec.m_type = type ; - rec.m_creator = creator ; - wxStrncpy( rec.m_ext , ext.Lower().c_str() , kMacExtensionMaxLength ) ; - gMacDefaultExtensions.Add( rec ) ; -} -#endif +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/filename.cpp +// Purpose: wxFileName - encapsulates a file path +// Author: Robert Roebling, Vadim Zeitlin +// Modified by: +// Created: 28.12.2000 +// RCS-ID: $Id: filename.cpp 52996 2008-04-03 12:47:16Z VZ $ +// Copyright: (c) 2000 Robert Roebling +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +/* + Here are brief descriptions of the filename formats supported by this class: + + wxPATH_UNIX: standard Unix format, used under Darwin as well, absolute file + names have the form: + /dir1/dir2/.../dirN/filename, "." and ".." stand for the + current and parent directory respectively, "~" is parsed as the + user HOME and "~username" as the HOME of that user + + wxPATH_DOS: DOS/Windows format, absolute file names have the form: + drive:\dir1\dir2\...\dirN\filename.ext where drive is a single + letter. "." and ".." as for Unix but no "~". + + There are also UNC names of the form \\share\fullpath + + wxPATH_MAC: Mac OS 8/9 and Mac OS X under CodeWarrior 7 format, absolute file + names have the form + volume:dir1:...:dirN:filename + and the relative file names are either + :dir1:...:dirN:filename + or just + filename + (although :filename works as well). + Since the volume is just part of the file path, it is not + treated like a separate entity as it is done under DOS and + VMS, it is just treated as another dir. + + wxPATH_VMS: VMS native format, absolute file names have the form + :[dir1.dir2.dir3]file.txt + or + :[000000.dir1.dir2.dir3]file.txt + + the is the physical device (i.e. disk). 000000 is the + root directory on the device which can be omitted. + + Note that VMS uses different separators unlike Unix: + : always after the device. If the path does not contain : than + the default (the device of the current directory) is assumed. + [ start of directory specification + . separator between directory and subdirectory + ] between directory and file + */ + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ +#pragma hdrstop +#endif + +#ifndef WX_PRECOMP + #ifdef __WXMSW__ + #include "wx/msw/wrapwin.h" // For GetShort/LongPathName + #endif + #include "wx/dynarray.h" + #include "wx/intl.h" + #include "wx/log.h" + #include "wx/utils.h" +#endif + +#include "wx/filename.h" +#include "wx/private/filename.h" +#include "wx/tokenzr.h" +#include "wx/config.h" // for wxExpandEnvVars +#include "wx/dynlib.h" + +#if defined(__WIN32__) && defined(__MINGW32__) + #include "wx/msw/gccpriv.h" +#endif + +#ifdef __WXWINCE__ +#include "wx/msw/private.h" +#endif + +#if defined(__WXMAC__) + #include "wx/mac/private.h" // includes mac headers +#endif + +// utime() is POSIX so should normally be available on all Unices +#ifdef __UNIX_LIKE__ +#include +#include +#include +#include +#endif + +#ifdef __DJGPP__ +#include +#endif + +#ifdef __MWERKS__ +#ifdef __MACH__ +#include +#include +#include +#include +#else +#include +#include +#include +#endif +#endif + +#ifdef __WATCOMC__ +#include +#include +#include +#endif + +#ifdef __VISAGECPP__ +#ifndef MAX_PATH +#define MAX_PATH 256 +#endif +#endif + +#ifdef __EMX__ +#include +#define MAX_PATH _MAX_PATH +#endif + + +wxULongLong wxInvalidSize = (unsigned)-1; + + +// ---------------------------------------------------------------------------- +// private classes +// ---------------------------------------------------------------------------- + +// small helper class which opens and closes the file - we use it just to get +// a file handle for the given file name to pass it to some Win32 API function +#if defined(__WIN32__) && !defined(__WXMICROWIN__) + +class wxFileHandle +{ +public: + enum OpenMode + { + Read, + Write + }; + + wxFileHandle(const wxString& filename, OpenMode mode) + { + m_hFile = ::CreateFile + ( + filename, // name + mode == Read ? GENERIC_READ // access mask + : GENERIC_WRITE, + FILE_SHARE_READ | // sharing mode + FILE_SHARE_WRITE, // (allow everything) + NULL, // no secutity attr + OPEN_EXISTING, // creation disposition + 0, // no flags + NULL // no template file + ); + + if ( m_hFile == INVALID_HANDLE_VALUE ) + { + wxLogSysError(_("Failed to open '%s' for %s"), + filename.c_str(), + mode == Read ? _("reading") : _("writing")); + } + } + + ~wxFileHandle() + { + if ( m_hFile != INVALID_HANDLE_VALUE ) + { + if ( !::CloseHandle(m_hFile) ) + { + wxLogSysError(_("Failed to close file handle")); + } + } + } + + // return true only if the file could be opened successfully + bool IsOk() const { return m_hFile != INVALID_HANDLE_VALUE; } + + // get the handle + operator HANDLE() const { return m_hFile; } + +private: + HANDLE m_hFile; +}; + +#endif // __WIN32__ + +// ---------------------------------------------------------------------------- +// private functions +// ---------------------------------------------------------------------------- + +#if wxUSE_DATETIME && defined(__WIN32__) && !defined(__WXMICROWIN__) + +// convert between wxDateTime and FILETIME which is a 64-bit value representing +// the number of 100-nanosecond intervals since January 1, 1601. + +static void ConvertFileTimeToWx(wxDateTime *dt, const FILETIME &ft) +{ + FILETIME ftcopy = ft; + FILETIME ftLocal; + if ( !::FileTimeToLocalFileTime(&ftcopy, &ftLocal) ) + { + wxLogLastError(_T("FileTimeToLocalFileTime")); + } + + SYSTEMTIME st; + if ( !::FileTimeToSystemTime(&ftLocal, &st) ) + { + wxLogLastError(_T("FileTimeToSystemTime")); + } + + dt->Set(st.wDay, wxDateTime::Month(st.wMonth - 1), st.wYear, + st.wHour, st.wMinute, st.wSecond, st.wMilliseconds); +} + +static void ConvertWxToFileTime(FILETIME *ft, const wxDateTime& dt) +{ + SYSTEMTIME st; + st.wDay = dt.GetDay(); + st.wMonth = (WORD)(dt.GetMonth() + 1); + st.wYear = (WORD)dt.GetYear(); + st.wHour = dt.GetHour(); + st.wMinute = dt.GetMinute(); + st.wSecond = dt.GetSecond(); + st.wMilliseconds = dt.GetMillisecond(); + + FILETIME ftLocal; + if ( !::SystemTimeToFileTime(&st, &ftLocal) ) + { + wxLogLastError(_T("SystemTimeToFileTime")); + } + + if ( !::LocalFileTimeToFileTime(&ftLocal, ft) ) + { + wxLogLastError(_T("LocalFileTimeToFileTime")); + } +} + +#endif // wxUSE_DATETIME && __WIN32__ + +// return a string with the volume par +static wxString wxGetVolumeString(const wxString& volume, wxPathFormat format) +{ + wxString path; + + if ( !volume.empty() ) + { + format = wxFileName::GetFormat(format); + + // Special Windows UNC paths hack, part 2: undo what we did in + // SplitPath() and make an UNC path if we have a drive which is not a + // single letter (hopefully the network shares can't be one letter only + // although I didn't find any authoritative docs on this) + if ( format == wxPATH_DOS && volume.length() > 1 ) + { + path << wxFILE_SEP_PATH_DOS << wxFILE_SEP_PATH_DOS << volume; + } + else if ( format == wxPATH_DOS || format == wxPATH_VMS ) + { + path << volume << wxFileName::GetVolumeSeparator(format); + } + // else ignore + } + + return path; +} + +// return true if the format used is the DOS/Windows one and the string looks +// like a UNC path +static bool IsUNCPath(const wxString& path, wxPathFormat format) +{ + return format == wxPATH_DOS && + path.length() >= 4 && // "\\a" can't be a UNC path + path[0u] == wxFILE_SEP_PATH_DOS && + path[1u] == wxFILE_SEP_PATH_DOS && + path[2u] != wxFILE_SEP_PATH_DOS; +} + +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// wxFileName construction +// ---------------------------------------------------------------------------- + +void wxFileName::Assign( const wxFileName &filepath ) +{ + m_volume = filepath.GetVolume(); + m_dirs = filepath.GetDirs(); + m_name = filepath.GetName(); + m_ext = filepath.GetExt(); + m_relative = filepath.m_relative; + m_hasExt = filepath.m_hasExt; +} + +void wxFileName::Assign(const wxString& volume, + const wxString& path, + const wxString& name, + const wxString& ext, + bool hasExt, + wxPathFormat format) +{ + // we should ignore paths which look like UNC shares because we already + // have the volume here and the UNC notation (\\server\path) is only valid + // for paths which don't start with a volume, so prevent SetPath() from + // recognizing "\\foo\bar" in "c:\\foo\bar" as an UNC path + // + // note also that this is a rather ugly way to do what we want (passing + // some kind of flag telling to ignore UNC paths to SetPath() would be + // better) but this is the safest thing to do to avoid breaking backwards + // compatibility in 2.8 + if ( IsUNCPath(path, format) ) + { + // remove one of the 2 leading backslashes to ensure that it's not + // recognized as an UNC path by SetPath() + wxString pathNonUNC(path, 1, wxString::npos); + SetPath(pathNonUNC, format); + } + else // no UNC complications + { + SetPath(path, format); + } + + m_volume = volume; + m_ext = ext; + m_name = name; + + m_hasExt = hasExt; +} + +void wxFileName::SetPath( const wxString& pathOrig, wxPathFormat format ) +{ + m_dirs.Clear(); + + if ( pathOrig.empty() ) + { + // no path at all + m_relative = true; + + return; + } + + format = GetFormat( format ); + + // 0) deal with possible volume part first + wxString volume, + path; + SplitVolume(pathOrig, &volume, &path, format); + if ( !volume.empty() ) + { + m_relative = false; + + SetVolume(volume); + } + + // 1) Determine if the path is relative or absolute. + wxChar leadingChar = path[0u]; + + switch (format) + { + case wxPATH_MAC: + m_relative = leadingChar == wxT(':'); + + // We then remove a leading ":". The reason is in our + // storage form for relative paths: + // ":dir:file.txt" actually means "./dir/file.txt" in + // DOS notation and should get stored as + // (relative) (dir) (file.txt) + // "::dir:file.txt" actually means "../dir/file.txt" + // stored as (relative) (..) (dir) (file.txt) + // This is important only for the Mac as an empty dir + // actually means , whereas under DOS, double + // slashes can be ignored: "\\\\" is the same as "\\". + if (m_relative) + path.erase( 0, 1 ); + break; + + case wxPATH_VMS: + // TODO: what is the relative path format here? + m_relative = false; + break; + + default: + wxFAIL_MSG( _T("Unknown path format") ); + // !! Fall through !! + + case wxPATH_UNIX: + // the paths of the form "~" or "~username" are absolute + m_relative = leadingChar != wxT('/') && leadingChar != _T('~'); + break; + + case wxPATH_DOS: + m_relative = !IsPathSeparator(leadingChar, format); + break; + + } + + // 2) Break up the path into its members. If the original path + // was just "/" or "\\", m_dirs will be empty. We know from + // the m_relative field, if this means "nothing" or "root dir". + + wxStringTokenizer tn( path, GetPathSeparators(format) ); + + while ( tn.HasMoreTokens() ) + { + wxString token = tn.GetNextToken(); + + // Remove empty token under DOS and Unix, interpret them + // as .. under Mac. + if (token.empty()) + { + if (format == wxPATH_MAC) + m_dirs.Add( wxT("..") ); + // else ignore + } + else + { + m_dirs.Add( token ); + } + } +} + +void wxFileName::Assign(const wxString& fullpath, + wxPathFormat format) +{ + wxString volume, path, name, ext; + bool hasExt; + SplitPath(fullpath, &volume, &path, &name, &ext, &hasExt, format); + + Assign(volume, path, name, ext, hasExt, format); +} + +void wxFileName::Assign(const wxString& fullpathOrig, + const wxString& fullname, + wxPathFormat format) +{ + // always recognize fullpath as directory, even if it doesn't end with a + // slash + wxString fullpath = fullpathOrig; + if ( !fullpath.empty() && !wxEndsWithPathSeparator(fullpath) ) + { + fullpath += GetPathSeparator(format); + } + + wxString volume, path, name, ext; + bool hasExt; + + // do some consistency checks in debug mode: the name should be really just + // the filename and the path should be really just a path +#ifdef __WXDEBUG__ + wxString volDummy, pathDummy, nameDummy, extDummy; + + SplitPath(fullname, &volDummy, &pathDummy, &name, &ext, &hasExt, format); + + wxASSERT_MSG( volDummy.empty() && pathDummy.empty(), + _T("the file name shouldn't contain the path") ); + + SplitPath(fullpath, &volume, &path, &nameDummy, &extDummy, format); + + wxASSERT_MSG( nameDummy.empty() && extDummy.empty(), + _T("the path shouldn't contain file name nor extension") ); + +#else // !__WXDEBUG__ + SplitPath(fullname, NULL /* no volume */, NULL /* no path */, + &name, &ext, &hasExt, format); + SplitPath(fullpath, &volume, &path, NULL, NULL, format); +#endif // __WXDEBUG__/!__WXDEBUG__ + + Assign(volume, path, name, ext, hasExt, format); +} + +void wxFileName::Assign(const wxString& pathOrig, + const wxString& name, + const wxString& ext, + wxPathFormat format) +{ + wxString volume, + path; + SplitVolume(pathOrig, &volume, &path, format); + + Assign(volume, path, name, ext, format); +} + +void wxFileName::AssignDir(const wxString& dir, wxPathFormat format) +{ + Assign(dir, wxEmptyString, format); +} + +void wxFileName::Clear() +{ + m_dirs.Clear(); + + m_volume = + m_name = + m_ext = wxEmptyString; + + // we don't have any absolute path for now + m_relative = true; + + // nor any extension + m_hasExt = false; +} + +/* static */ +wxFileName wxFileName::FileName(const wxString& file, wxPathFormat format) +{ + return wxFileName(file, format); +} + +/* static */ +wxFileName wxFileName::DirName(const wxString& dir, wxPathFormat format) +{ + wxFileName fn; + fn.AssignDir(dir, format); + return fn; +} + +// ---------------------------------------------------------------------------- +// existence tests +// ---------------------------------------------------------------------------- + +bool wxFileName::FileExists() const +{ + return wxFileName::FileExists( GetFullPath() ); +} + +bool wxFileName::FileExists( const wxString &file ) +{ + return ::wxFileExists( file ); +} + +bool wxFileName::DirExists() const +{ + return wxFileName::DirExists( GetPath() ); +} + +bool wxFileName::DirExists( const wxString &dir ) +{ + return ::wxDirExists( dir ); +} + +// ---------------------------------------------------------------------------- +// CWD and HOME stuff +// ---------------------------------------------------------------------------- + +void wxFileName::AssignCwd(const wxString& volume) +{ + AssignDir(wxFileName::GetCwd(volume)); +} + +/* static */ +wxString wxFileName::GetCwd(const wxString& volume) +{ + // if we have the volume, we must get the current directory on this drive + // and to do this we have to chdir to this volume - at least under Windows, + // I don't know how to get the current drive on another volume elsewhere + // (TODO) + wxString cwdOld; + if ( !volume.empty() ) + { + cwdOld = wxGetCwd(); + SetCwd(volume + GetVolumeSeparator()); + } + + wxString cwd = ::wxGetCwd(); + + if ( !volume.empty() ) + { + SetCwd(cwdOld); + } + + return cwd; +} + +bool wxFileName::SetCwd() +{ + return wxFileName::SetCwd( GetPath() ); +} + +bool wxFileName::SetCwd( const wxString &cwd ) +{ + return ::wxSetWorkingDirectory( cwd ); +} + +void wxFileName::AssignHomeDir() +{ + AssignDir(wxFileName::GetHomeDir()); +} + +wxString wxFileName::GetHomeDir() +{ + return ::wxGetHomeDir(); +} + + +// ---------------------------------------------------------------------------- +// CreateTempFileName +// ---------------------------------------------------------------------------- + +#if wxUSE_FILE || wxUSE_FFILE + + +#if !defined wx_fdopen && defined HAVE_FDOPEN + #define wx_fdopen fdopen +#endif + +// NB: GetTempFileName() under Windows creates the file, so using +// O_EXCL there would fail +#ifdef __WINDOWS__ + #define wxOPEN_EXCL 0 +#else + #define wxOPEN_EXCL O_EXCL +#endif + + +#ifdef wxOpenOSFHandle +#define WX_HAVE_DELETE_ON_CLOSE +// On Windows create a file with the FILE_FLAGS_DELETE_ON_CLOSE flags. +// +static int wxOpenWithDeleteOnClose(const wxString& filename) +{ + DWORD access = GENERIC_READ | GENERIC_WRITE; + + DWORD disposition = OPEN_ALWAYS; + + DWORD attributes = FILE_ATTRIBUTE_TEMPORARY | + FILE_FLAG_DELETE_ON_CLOSE; + + HANDLE h = ::CreateFile(filename, access, 0, NULL, + disposition, attributes, NULL); + + return wxOpenOSFHandle(h, wxO_BINARY); +} +#endif // wxOpenOSFHandle + + +// Helper to open the file +// +static int wxTempOpen(const wxString& path, bool *deleteOnClose) +{ +#ifdef WX_HAVE_DELETE_ON_CLOSE + if (*deleteOnClose) + return wxOpenWithDeleteOnClose(path); +#endif + + *deleteOnClose = false; + + return wxOpen(path, wxO_BINARY | O_RDWR | O_CREAT | wxOPEN_EXCL, 0600); +} + + +#if wxUSE_FFILE +// Helper to open the file and attach it to the wxFFile +// +static bool wxTempOpen(wxFFile *file, const wxString& path, bool *deleteOnClose) +{ +#ifndef wx_fdopen + *deleteOnClose = false; + return file->Open(path, _T("w+b")); +#else // wx_fdopen + int fd = wxTempOpen(path, deleteOnClose); + if (fd == -1) + return false; + file->Attach(wx_fdopen(fd, "w+b")); + return file->IsOpened(); +#endif // wx_fdopen +} +#endif // wxUSE_FFILE + + +#if !wxUSE_FILE + #define WXFILEARGS(x, y) y +#elif !wxUSE_FFILE + #define WXFILEARGS(x, y) x +#else + #define WXFILEARGS(x, y) x, y +#endif + + +// Implementation of wxFileName::CreateTempFileName(). +// +static wxString wxCreateTempImpl( + const wxString& prefix, + WXFILEARGS(wxFile *fileTemp, wxFFile *ffileTemp), + bool *deleteOnClose = NULL) +{ + static int pid = -1; +#if wxUSE_FILE && wxUSE_FFILE + wxASSERT(fileTemp == NULL || ffileTemp == NULL); +#endif + wxString path, dir, name; + bool wantDeleteOnClose = false; + + if (deleteOnClose) + { + // set the result to false initially + wantDeleteOnClose = *deleteOnClose; + *deleteOnClose = false; + } + else + { + // easier if it alwasys points to something + deleteOnClose = &wantDeleteOnClose; + } + + // use the directory specified by the prefix + wxFileName::SplitPath(prefix, &dir, &name, NULL /* extension */); + + if (dir.empty()) + { + dir = wxFileName::GetTempDir(); + } + +#if defined(__WXWINCE__) + path = dir + wxT("\\") + name; + int i = 1; + while (wxFileName::FileExists(path)) + { + path = dir + wxT("\\") + name ; + path << i; + i ++; + } + +#elif defined(__WINDOWS__) && !defined(__WXMICROWIN__) + if ( !::GetTempFileName(dir, name, 0, wxStringBuffer(path, MAX_PATH + 1)) ) + { + wxLogLastError(_T("GetTempFileName")); + + path.clear(); + } + +#else // !Windows + path = dir; + + if ( !wxEndsWithPathSeparator(dir) && + (name.empty() || !wxIsPathSeparator(name[0u])) ) + { + path += wxFILE_SEP_PATH; + } + + path += name; + +#if defined(HAVE_MKSTEMP) + // scratch space for mkstemp() + path += _T("XXXXXX"); + + // we need to copy the path to the buffer in which mkstemp() can modify it + wxCharBuffer buf( wxConvFile.cWX2MB( path ) ); + + // cast is safe because the string length doesn't change + int fdTemp = mkstemp( (char*)(const char*) buf ); + if ( fdTemp == -1 ) + { + // this might be not necessary as mkstemp() on most systems should have + // already done it but it doesn't hurt neither... + path.clear(); + } + else // mkstemp() succeeded + { + path = wxConvFile.cMB2WX( (const char*) buf ); + + #if wxUSE_FILE + // avoid leaking the fd + if ( fileTemp ) + { + fileTemp->Attach(fdTemp); + } + else + #endif + + #if wxUSE_FFILE + if ( ffileTemp ) + { + #ifdef wx_fdopen + ffileTemp->Attach(wx_fdopen(fdTemp, "r+b")); + #else + ffileTemp->Open(path, _T("r+b")); + close(fdTemp); + #endif + } + else + #endif + + { + close(fdTemp); + } + } +#else // !HAVE_MKSTEMP + +#ifdef HAVE_MKTEMP + // same as above + path += _T("XXXXXX"); + + wxCharBuffer buf = wxConvFile.cWX2MB( path ); + if ( !mktemp( (char*)(const char*) buf ) ) + { + path.clear(); + } + else + { + path = wxConvFile.cMB2WX( (const char*) buf ); + } +#else // !HAVE_MKTEMP (includes __DOS__) + // generate the unique file name ourselves + #if !defined(__DOS__) && !defined(__PALMOS__) && (!defined(__MWERKS__) || defined(__DARWIN__) ) + + if(pid < 0) + pid = getpid(); + + path << (unsigned int)pid; + #endif + + wxString pathTry; + + static const size_t numTries = 1000; + for ( size_t n = 0; n < numTries; n++ ) + { + // 3 hex digits is enough for numTries == 1000 < 4096 + pathTry = path + wxString::Format(_T("%.03x"), (unsigned int) n); + if ( !wxFileName::FileExists(pathTry) ) + { + break; + } + + pathTry.clear(); + } + + path = pathTry; +#endif // HAVE_MKTEMP/!HAVE_MKTEMP + +#endif // HAVE_MKSTEMP/!HAVE_MKSTEMP + +#endif // Windows/!Windows + + if ( path.empty() ) + { + wxLogSysError(_("Failed to create a temporary file name")); + } + else + { + bool ok = true; + + // open the file - of course, there is a race condition here, this is + // why we always prefer using mkstemp()... + #if wxUSE_FILE + if ( fileTemp && !fileTemp->IsOpened() ) + { + *deleteOnClose = wantDeleteOnClose; + int fd = wxTempOpen(path, deleteOnClose); + if (fd != -1) + fileTemp->Attach(fd); + else + ok = false; + } + #endif + + #if wxUSE_FFILE + if ( ffileTemp && !ffileTemp->IsOpened() ) + { + *deleteOnClose = wantDeleteOnClose; + ok = wxTempOpen(ffileTemp, path, deleteOnClose); + } + #endif + + if ( !ok ) + { + // FIXME: If !ok here should we loop and try again with another + // file name? That is the standard recourse if open(O_EXCL) + // fails, though of course it should be protected against + // possible infinite looping too. + + wxLogError(_("Failed to open temporary file.")); + + path.clear(); + } + } + + return path; +} + + +static bool wxCreateTempImpl( + const wxString& prefix, + WXFILEARGS(wxFile *fileTemp, wxFFile *ffileTemp), + wxString *name) +{ + bool deleteOnClose = true; + + *name = wxCreateTempImpl(prefix, + WXFILEARGS(fileTemp, ffileTemp), + &deleteOnClose); + + bool ok = !name->empty(); + + if (deleteOnClose) + name->clear(); +#ifdef __UNIX__ + else if (ok && wxRemoveFile(*name)) + name->clear(); +#endif + + return ok; +} + + +static void wxAssignTempImpl( + wxFileName *fn, + const wxString& prefix, + WXFILEARGS(wxFile *fileTemp, wxFFile *ffileTemp)) +{ + wxString tempname; + tempname = wxCreateTempImpl(prefix, WXFILEARGS(fileTemp, ffileTemp)); + + if ( tempname.empty() ) + { + // error, failed to get temp file name + fn->Clear(); + } + else // ok + { + fn->Assign(tempname); + } +} + + +void wxFileName::AssignTempFileName(const wxString& prefix) +{ + wxAssignTempImpl(this, prefix, WXFILEARGS(NULL, NULL)); +} + +/* static */ +wxString wxFileName::CreateTempFileName(const wxString& prefix) +{ + return wxCreateTempImpl(prefix, WXFILEARGS(NULL, NULL)); +} + +#endif // wxUSE_FILE || wxUSE_FFILE + + +#if wxUSE_FILE + +wxString wxCreateTempFileName(const wxString& prefix, + wxFile *fileTemp, + bool *deleteOnClose) +{ + return wxCreateTempImpl(prefix, WXFILEARGS(fileTemp, NULL), deleteOnClose); +} + +bool wxCreateTempFile(const wxString& prefix, + wxFile *fileTemp, + wxString *name) +{ + return wxCreateTempImpl(prefix, WXFILEARGS(fileTemp, NULL), name); +} + +void wxFileName::AssignTempFileName(const wxString& prefix, wxFile *fileTemp) +{ + wxAssignTempImpl(this, prefix, WXFILEARGS(fileTemp, NULL)); +} + +/* static */ +wxString +wxFileName::CreateTempFileName(const wxString& prefix, wxFile *fileTemp) +{ + return wxCreateTempFileName(prefix, fileTemp); +} + +#endif // wxUSE_FILE + + +#if wxUSE_FFILE + +wxString wxCreateTempFileName(const wxString& prefix, + wxFFile *fileTemp, + bool *deleteOnClose) +{ + return wxCreateTempImpl(prefix, WXFILEARGS(NULL, fileTemp), deleteOnClose); +} + +bool wxCreateTempFile(const wxString& prefix, + wxFFile *fileTemp, + wxString *name) +{ + return wxCreateTempImpl(prefix, WXFILEARGS(NULL, fileTemp), name); + +} + +void wxFileName::AssignTempFileName(const wxString& prefix, wxFFile *fileTemp) +{ + wxAssignTempImpl(this, prefix, WXFILEARGS(NULL, fileTemp)); +} + +/* static */ +wxString +wxFileName::CreateTempFileName(const wxString& prefix, wxFFile *fileTemp) +{ + return wxCreateTempFileName(prefix, fileTemp); +} + +#endif // wxUSE_FFILE + + +// ---------------------------------------------------------------------------- +// directory operations +// ---------------------------------------------------------------------------- + +wxString wxFileName::GetTempDir() +{ + wxString dir; + dir = wxGetenv(_T("TMPDIR")); + if (dir.empty()) + { + dir = wxGetenv(_T("TMP")); + if (dir.empty()) + { + dir = wxGetenv(_T("TEMP")); + } + } + +#if defined(__WXWINCE__) + if (dir.empty()) + { + // FIXME. Create \temp dir? + if (DirExists(wxT("\\temp"))) + dir = wxT("\\temp"); + } +#elif defined(__WINDOWS__) && !defined(__WXMICROWIN__) + + if ( dir.empty() ) + { + if ( !::GetTempPath(MAX_PATH, wxStringBuffer(dir, MAX_PATH + 1)) ) + { + wxLogLastError(_T("GetTempPath")); + } + + if ( dir.empty() ) + { + // GetTempFileName() fails if we pass it an empty string + dir = _T('.'); + } + } +#else // !Windows + + if ( dir.empty() ) + { + // default +#if defined(__DOS__) || defined(__OS2__) + dir = _T("."); +#elif defined(__WXMAC__) + dir = wxMacFindFolder(short(kOnSystemDisk), kTemporaryFolderType, kCreateFolder); +#else + dir = _T("/tmp"); +#endif + } +#endif + + return dir; +} + +bool wxFileName::Mkdir( int perm, int flags ) +{ + return wxFileName::Mkdir(GetPath(), perm, flags); +} + +bool wxFileName::Mkdir( const wxString& dir, int perm, int flags ) +{ + if ( flags & wxPATH_MKDIR_FULL ) + { + // split the path in components + wxFileName filename; + filename.AssignDir(dir); + + wxString currPath; + if ( filename.HasVolume()) + { + currPath << wxGetVolumeString(filename.GetVolume(), wxPATH_NATIVE); + } + + wxArrayString dirs = filename.GetDirs(); + size_t count = dirs.GetCount(); + for ( size_t i = 0; i < count; i++ ) + { + if ( i > 0 || +#if defined(__WXMAC__) && !defined(__DARWIN__) + // relative pathnames are exactely the other way round under mac... + !filename.IsAbsolute() +#else + filename.IsAbsolute() +#endif + ) + currPath += wxFILE_SEP_PATH; + currPath += dirs[i]; + + if (!DirExists(currPath)) + { + if (!wxMkdir(currPath, perm)) + { + // no need to try creating further directories + return false; + } + } + } + + return true; + + } + + return ::wxMkdir( dir, perm ); +} + +bool wxFileName::Rmdir() +{ + return wxFileName::Rmdir( GetPath() ); +} + +bool wxFileName::Rmdir( const wxString &dir ) +{ + return ::wxRmdir( dir ); +} + +// ---------------------------------------------------------------------------- +// path normalization +// ---------------------------------------------------------------------------- + +bool wxFileName::Normalize(int flags, + const wxString& cwd, + wxPathFormat format) +{ + // deal with env vars renaming first as this may seriously change the path + if ( flags & wxPATH_NORM_ENV_VARS ) + { + wxString pathOrig = GetFullPath(format); + wxString path = wxExpandEnvVars(pathOrig); + if ( path != pathOrig ) + { + Assign(path); + } + } + + + // the existing path components + wxArrayString dirs = GetDirs(); + + // the path to prepend in front to make the path absolute + wxFileName curDir; + + format = GetFormat(format); + + // set up the directory to use for making the path absolute later + if ( (flags & wxPATH_NORM_ABSOLUTE) && !IsAbsolute(format) ) + { + if ( cwd.empty() ) + { + curDir.AssignCwd(GetVolume()); + } + else // cwd provided + { + curDir.AssignDir(cwd); + } + } + + // handle ~ stuff under Unix only + if ( (format == wxPATH_UNIX) && (flags & wxPATH_NORM_TILDE) ) + { + if ( !dirs.IsEmpty() ) + { + wxString dir = dirs[0u]; + if ( !dir.empty() && dir[0u] == _T('~') ) + { + // to make the path absolute use the home directory + curDir.AssignDir(wxGetUserHome(dir.c_str() + 1)); + + // if we are expanding the tilde, then this path + // *should* be already relative (since we checked for + // the tilde only in the first char of the first dir); + // if m_relative==false, it's because it was initialized + // from a string which started with /~; in that case + // we reach this point but then need m_relative=true + // for relative->absolute expansion later + m_relative = true; + + dirs.RemoveAt(0u); + } + } + } + + // transform relative path into abs one + if ( curDir.IsOk() ) + { + // this path may be relative because it doesn't have the volume name + // and still have m_relative=true; in this case we shouldn't modify + // our directory components but just set the current volume + if ( !HasVolume() && curDir.HasVolume() ) + { + SetVolume(curDir.GetVolume()); + + if ( !m_relative ) + { + // yes, it was the case - we don't need curDir then + curDir.Clear(); + } + } + + // finally, prepend curDir to the dirs array + wxArrayString dirsNew = curDir.GetDirs(); + WX_PREPEND_ARRAY(dirs, dirsNew); + + // if we used e.g. tilde expansion previously and wxGetUserHome didn't + // return for some reason an absolute path, then curDir maybe not be absolute! + if ( curDir.IsAbsolute(format) ) + { + // we have prepended an absolute path and thus we are now an absolute + // file name too + m_relative = false; + } + // else if (flags & wxPATH_NORM_ABSOLUTE): + // should we warn the user that we didn't manage to make the path absolute? + } + + // now deal with ".", ".." and the rest + m_dirs.Empty(); + size_t count = dirs.GetCount(); + for ( size_t n = 0; n < count; n++ ) + { + wxString dir = dirs[n]; + + if ( flags & wxPATH_NORM_DOTS ) + { + if ( dir == wxT(".") ) + { + // just ignore + continue; + } + + if ( dir == wxT("..") ) + { + if ( m_dirs.IsEmpty() ) + { + wxLogError(_("The path '%s' contains too many \"..\"!"), + GetFullPath().c_str()); + return false; + } + + m_dirs.RemoveAt(m_dirs.GetCount() - 1); + continue; + } + } + + if ( (flags & wxPATH_NORM_CASE) && !IsCaseSensitive(format) ) + { + dir.MakeLower(); + } + + m_dirs.Add(dir); + } + +#if defined(__WIN32__) && !defined(__WXWINCE__) && wxUSE_OLE + if ( (flags & wxPATH_NORM_SHORTCUT) ) + { + wxString filename; + if (GetShortcutTarget(GetFullPath(format), filename)) + { + // Repeat this since we may now have a new path + if ( (flags & wxPATH_NORM_CASE) && !IsCaseSensitive(format) ) + { + filename.MakeLower(); + } + m_relative = false; + Assign(filename); + } + } +#endif + + if ( (flags & wxPATH_NORM_CASE) && !IsCaseSensitive(format) ) + { + // VZ: expand env vars here too? + + m_volume.MakeLower(); + m_name.MakeLower(); + m_ext.MakeLower(); + } + +#if defined(__WIN32__) + if ( (flags & wxPATH_NORM_LONG) && (format == wxPATH_DOS) ) + { + Assign(GetLongPath()); + } +#endif // Win32 + + return true; +} + +// ---------------------------------------------------------------------------- +// get the shortcut target +// ---------------------------------------------------------------------------- + +// WinCE (3) doesn't have CLSID_ShellLink, IID_IShellLink definitions. +// The .lnk file is a plain text file so it should be easy to +// make it work. Hint from Google Groups: +// "If you open up a lnk file, you'll see a +// number, followed by a pound sign (#), followed by more text. The +// number is the number of characters that follows the pound sign. The +// characters after the pound sign are the command line (which _can_ +// include arguments) to be executed. Any path (e.g. \windows\program +// files\myapp.exe) that includes spaces needs to be enclosed in +// quotation marks." + +#if defined(__WIN32__) && !defined(__WXWINCE__) && wxUSE_OLE +// The following lines are necessary under WinCE +// #include "wx/msw/private.h" +// #include +#include +#if defined(__WXWINCE__) +#include +#endif + +bool wxFileName::GetShortcutTarget(const wxString& shortcutPath, + wxString& targetFilename, + wxString* arguments) +{ + wxString path, file, ext; + wxSplitPath(shortcutPath, & path, & file, & ext); + + HRESULT hres; + IShellLink* psl; + bool success = false; + + // Assume it's not a shortcut if it doesn't end with lnk + if (ext.CmpNoCase(wxT("lnk"))!=0) + return false; + + // create a ShellLink object + hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, + IID_IShellLink, (LPVOID*) &psl); + + if (SUCCEEDED(hres)) + { + IPersistFile* ppf; + hres = psl->QueryInterface( IID_IPersistFile, (LPVOID *) &ppf); + if (SUCCEEDED(hres)) + { + WCHAR wsz[MAX_PATH]; + + MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, shortcutPath.mb_str(), -1, wsz, + MAX_PATH); + + hres = ppf->Load(wsz, 0); + ppf->Release(); + + if (SUCCEEDED(hres)) + { + wxChar buf[2048]; + // Wrong prototype in early versions +#if defined(__MINGW32__) && !wxCHECK_W32API_VERSION(2, 2) + psl->GetPath((CHAR*) buf, 2048, NULL, SLGP_UNCPRIORITY); +#else + psl->GetPath(buf, 2048, NULL, SLGP_UNCPRIORITY); +#endif + targetFilename = wxString(buf); + success = (shortcutPath != targetFilename); + + psl->GetArguments(buf, 2048); + wxString args(buf); + if (!args.empty() && arguments) + { + *arguments = args; + } + } + } + + psl->Release(); + } + return success; +} + +#endif // __WIN32__ && !__WXWINCE__ + + +// ---------------------------------------------------------------------------- +// absolute/relative paths +// ---------------------------------------------------------------------------- + +bool wxFileName::IsAbsolute(wxPathFormat format) const +{ + // if our path doesn't start with a path separator, it's not an absolute + // path + if ( m_relative ) + return false; + + if ( !GetVolumeSeparator(format).empty() ) + { + // this format has volumes and an absolute path must have one, it's not + // enough to have the full path to bean absolute file under Windows + if ( GetVolume().empty() ) + return false; + } + + return true; +} + +bool wxFileName::MakeRelativeTo(const wxString& pathBase, wxPathFormat format) +{ + wxFileName fnBase = wxFileName::DirName(pathBase, format); + + // get cwd only once - small time saving + wxString cwd = wxGetCwd(); + Normalize(wxPATH_NORM_ALL & ~wxPATH_NORM_CASE, cwd, format); + fnBase.Normalize(wxPATH_NORM_ALL & ~wxPATH_NORM_CASE, cwd, format); + + bool withCase = IsCaseSensitive(format); + + // we can't do anything if the files live on different volumes + if ( !GetVolume().IsSameAs(fnBase.GetVolume(), withCase) ) + { + // nothing done + return false; + } + + // same drive, so we don't need our volume + m_volume.clear(); + + // remove common directories starting at the top + while ( !m_dirs.IsEmpty() && !fnBase.m_dirs.IsEmpty() && + m_dirs[0u].IsSameAs(fnBase.m_dirs[0u], withCase) ) + { + m_dirs.RemoveAt(0); + fnBase.m_dirs.RemoveAt(0); + } + + // add as many ".." as needed + size_t count = fnBase.m_dirs.GetCount(); + for ( size_t i = 0; i < count; i++ ) + { + m_dirs.Insert(wxT(".."), 0u); + } + + if ( format == wxPATH_UNIX || format == wxPATH_DOS ) + { + // a directory made relative with respect to itself is '.' under Unix + // and DOS, by definition (but we don't have to insert "./" for the + // files) + if ( m_dirs.IsEmpty() && IsDir() ) + { + m_dirs.Add(_T('.')); + } + } + + m_relative = true; + + // we were modified + return true; +} + +// ---------------------------------------------------------------------------- +// filename kind tests +// ---------------------------------------------------------------------------- + +bool wxFileName::SameAs(const wxFileName& filepath, wxPathFormat format) const +{ + wxFileName fn1 = *this, + fn2 = filepath; + + // get cwd only once - small time saving + wxString cwd = wxGetCwd(); + fn1.Normalize(wxPATH_NORM_ALL | wxPATH_NORM_CASE, cwd, format); + fn2.Normalize(wxPATH_NORM_ALL | wxPATH_NORM_CASE, cwd, format); + + if ( fn1.GetFullPath() == fn2.GetFullPath() ) + return true; + + // TODO: compare inodes for Unix, this works even when filenames are + // different but files are the same (symlinks) (VZ) + + return false; +} + +/* static */ +bool wxFileName::IsCaseSensitive( wxPathFormat format ) +{ + // only Unix filenames are truely case-sensitive + return GetFormat(format) == wxPATH_UNIX; +} + +/* static */ +wxString wxFileName::GetForbiddenChars(wxPathFormat format) +{ + // Inits to forbidden characters that are common to (almost) all platforms. + wxString strForbiddenChars = wxT("*?"); + + // If asserts, wxPathFormat has been changed. In case of a new path format + // addition, the following code might have to be updated. + wxCOMPILE_TIME_ASSERT(wxPATH_MAX == 5, wxPathFormatChanged); + switch ( GetFormat(format) ) + { + default : + wxFAIL_MSG( wxT("Unknown path format") ); + // !! Fall through !! + + case wxPATH_UNIX: + break; + + case wxPATH_MAC: + // On a Mac even names with * and ? are allowed (Tested with OS + // 9.2.1 and OS X 10.2.5) + strForbiddenChars = wxEmptyString; + break; + + case wxPATH_DOS: + strForbiddenChars += wxT("\\/:\"<>|"); + break; + + case wxPATH_VMS: + break; + } + + return strForbiddenChars; +} + +/* static */ +wxString wxFileName::GetVolumeSeparator(wxPathFormat WXUNUSED_IN_WINCE(format)) +{ +#ifdef __WXWINCE__ + return wxEmptyString; +#else + wxString sepVol; + + if ( (GetFormat(format) == wxPATH_DOS) || + (GetFormat(format) == wxPATH_VMS) ) + { + sepVol = wxFILE_SEP_DSK; + } + //else: leave empty + + return sepVol; +#endif +} + +/* static */ +wxString wxFileName::GetPathSeparators(wxPathFormat format) +{ + wxString seps; + switch ( GetFormat(format) ) + { + case wxPATH_DOS: + // accept both as native APIs do but put the native one first as + // this is the one we use in GetFullPath() + seps << wxFILE_SEP_PATH_DOS << wxFILE_SEP_PATH_UNIX; + break; + + default: + wxFAIL_MSG( _T("Unknown wxPATH_XXX style") ); + // fall through + + case wxPATH_UNIX: + seps = wxFILE_SEP_PATH_UNIX; + break; + + case wxPATH_MAC: + seps = wxFILE_SEP_PATH_MAC; + break; + + case wxPATH_VMS: + seps = wxFILE_SEP_PATH_VMS; + break; + } + + return seps; +} + +/* static */ +wxString wxFileName::GetPathTerminators(wxPathFormat format) +{ + format = GetFormat(format); + + // under VMS the end of the path is ']', not the path separator used to + // separate the components + return format == wxPATH_VMS ? wxString(_T(']')) : GetPathSeparators(format); +} + +/* static */ +bool wxFileName::IsPathSeparator(wxChar ch, wxPathFormat format) +{ + // wxString::Find() doesn't work as expected with NUL - it will always find + // it, so test for it separately + return ch != _T('\0') && GetPathSeparators(format).Find(ch) != wxNOT_FOUND; +} + +// ---------------------------------------------------------------------------- +// path components manipulation +// ---------------------------------------------------------------------------- + +/* static */ bool wxFileName::IsValidDirComponent(const wxString& dir) +{ + if ( dir.empty() ) + { + wxFAIL_MSG( _T("empty directory passed to wxFileName::InsertDir()") ); + + return false; + } + + const size_t len = dir.length(); + for ( size_t n = 0; n < len; n++ ) + { + if ( dir[n] == GetVolumeSeparator() || IsPathSeparator(dir[n]) ) + { + wxFAIL_MSG( _T("invalid directory component in wxFileName") ); + + return false; + } + } + + return true; +} + +void wxFileName::AppendDir( const wxString& dir ) +{ + if ( IsValidDirComponent(dir) ) + m_dirs.Add( dir ); +} + +void wxFileName::PrependDir( const wxString& dir ) +{ + InsertDir(0, dir); +} + +void wxFileName::InsertDir(size_t before, const wxString& dir) +{ + if ( IsValidDirComponent(dir) ) + m_dirs.Insert(dir, before); +} + +void wxFileName::RemoveDir(size_t pos) +{ + m_dirs.RemoveAt(pos); +} + +// ---------------------------------------------------------------------------- +// accessors +// ---------------------------------------------------------------------------- + +void wxFileName::SetFullName(const wxString& fullname) +{ + SplitPath(fullname, NULL /* no volume */, NULL /* no path */, + &m_name, &m_ext, &m_hasExt); +} + +wxString wxFileName::GetFullName() const +{ + wxString fullname = m_name; + if ( m_hasExt ) + { + fullname << wxFILE_SEP_EXT << m_ext; + } + + return fullname; +} + +wxString wxFileName::GetPath( int flags, wxPathFormat format ) const +{ + format = GetFormat( format ); + + wxString fullpath; + + // return the volume with the path as well if requested + if ( flags & wxPATH_GET_VOLUME ) + { + fullpath += wxGetVolumeString(GetVolume(), format); + } + + // the leading character + switch ( format ) + { + case wxPATH_MAC: + if ( m_relative ) + fullpath += wxFILE_SEP_PATH_MAC; + break; + + case wxPATH_DOS: + if ( !m_relative ) + fullpath += wxFILE_SEP_PATH_DOS; + break; + + default: + wxFAIL_MSG( wxT("Unknown path format") ); + // fall through + + case wxPATH_UNIX: + if ( !m_relative ) + { + // normally the absolute file names start with a slash + // with one exception: the ones like "~/foo.bar" don't + // have it + if ( m_dirs.IsEmpty() || m_dirs[0u] != _T('~') ) + { + fullpath += wxFILE_SEP_PATH_UNIX; + } + } + break; + + case wxPATH_VMS: + // no leading character here but use this place to unset + // wxPATH_GET_SEPARATOR flag: under VMS it doesn't make sense + // as, if I understand correctly, there should never be a dot + // before the closing bracket + flags &= ~wxPATH_GET_SEPARATOR; + } + + if ( m_dirs.empty() ) + { + // there is nothing more + return fullpath; + } + + // then concatenate all the path components using the path separator + if ( format == wxPATH_VMS ) + { + fullpath += wxT('['); + } + + const size_t dirCount = m_dirs.GetCount(); + for ( size_t i = 0; i < dirCount; i++ ) + { + switch (format) + { + case wxPATH_MAC: + if ( m_dirs[i] == wxT(".") ) + { + // skip appending ':', this shouldn't be done in this + // case as "::" is interpreted as ".." under Unix + continue; + } + + // convert back from ".." to nothing + if ( !m_dirs[i].IsSameAs(wxT("..")) ) + fullpath += m_dirs[i]; + break; + + default: + wxFAIL_MSG( wxT("Unexpected path format") ); + // still fall through + + case wxPATH_DOS: + case wxPATH_UNIX: + fullpath += m_dirs[i]; + break; + + case wxPATH_VMS: + // TODO: What to do with ".." under VMS + + // convert back from ".." to nothing + if ( !m_dirs[i].IsSameAs(wxT("..")) ) + fullpath += m_dirs[i]; + break; + } + + if ( (flags & wxPATH_GET_SEPARATOR) || (i != dirCount - 1) ) + fullpath += GetPathSeparator(format); + } + + if ( format == wxPATH_VMS ) + { + fullpath += wxT(']'); + } + + return fullpath; +} + +wxString wxFileName::GetFullPath( wxPathFormat format ) const +{ + // we already have a function to get the path + wxString fullpath = GetPath(wxPATH_GET_VOLUME | wxPATH_GET_SEPARATOR, + format); + + // now just add the file name and extension to it + fullpath += GetFullName(); + + return fullpath; +} + +// Return the short form of the path (returns identity on non-Windows platforms) +wxString wxFileName::GetShortPath() const +{ + wxString path(GetFullPath()); + +#if defined(__WXMSW__) && defined(__WIN32__) && !defined(__WXMICROWIN__) && !defined(__WXWINCE__) + DWORD sz = ::GetShortPathName(path, NULL, 0); + if ( sz != 0 ) + { + wxString pathOut; + if ( ::GetShortPathName + ( + path, + wxStringBuffer(pathOut, sz), + sz + ) != 0 ) + { + return pathOut; + } + } +#endif // Windows + + return path; +} + +// Return the long form of the path (returns identity on non-Windows platforms) +wxString wxFileName::GetLongPath() const +{ + wxString pathOut, + path = GetFullPath(); + +#if defined(__WIN32__) && !defined(__WXWINCE__) && !defined(__WXMICROWIN__) + +#if wxUSE_DYNLIB_CLASS + typedef DWORD (WINAPI *GET_LONG_PATH_NAME)(const wxChar *, wxChar *, DWORD); + + // this is MT-safe as in the worst case we're going to resolve the function + // twice -- but as the result is the same in both threads, it's ok + static GET_LONG_PATH_NAME s_pfnGetLongPathName = NULL; + if ( !s_pfnGetLongPathName ) + { + static bool s_triedToLoad = false; + + if ( !s_triedToLoad ) + { + s_triedToLoad = true; + + wxDynamicLibrary dllKernel(_T("kernel32")); + + const wxChar* GetLongPathName = _T("GetLongPathName") +#if wxUSE_UNICODE + _T("W"); +#else // ANSI + _T("A"); +#endif // Unicode/ANSI + + if ( dllKernel.HasSymbol(GetLongPathName) ) + { + s_pfnGetLongPathName = (GET_LONG_PATH_NAME) + dllKernel.GetSymbol(GetLongPathName); + } + + // note that kernel32.dll can be unloaded, it stays in memory + // anyhow as all Win32 programs link to it and so it's safe to call + // GetLongPathName() even after unloading it + } + } + + if ( s_pfnGetLongPathName ) + { + DWORD dwSize = (*s_pfnGetLongPathName)(path, NULL, 0); + if ( dwSize > 0 ) + { + if ( (*s_pfnGetLongPathName) + ( + path, + wxStringBuffer(pathOut, dwSize), + dwSize + ) != 0 ) + { + return pathOut; + } + } + } +#endif // wxUSE_DYNLIB_CLASS + + // The OS didn't support GetLongPathName, or some other error. + // We need to call FindFirstFile on each component in turn. + + WIN32_FIND_DATA findFileData; + HANDLE hFind; + + if ( HasVolume() ) + pathOut = GetVolume() + + GetVolumeSeparator(wxPATH_DOS) + + GetPathSeparator(wxPATH_DOS); + else + pathOut = wxEmptyString; + + wxArrayString dirs = GetDirs(); + dirs.Add(GetFullName()); + + wxString tmpPath; + + size_t count = dirs.GetCount(); + for ( size_t i = 0; i < count; i++ ) + { + // We're using pathOut to collect the long-name path, but using a + // temporary for appending the last path component which may be + // short-name + tmpPath = pathOut + dirs[i]; + + if ( tmpPath.empty() ) + continue; + + // can't see this being necessary? MF + if ( tmpPath.Last() == GetVolumeSeparator(wxPATH_DOS) ) + { + // Can't pass a drive and root dir to FindFirstFile, + // so continue to next dir + tmpPath += wxFILE_SEP_PATH; + pathOut = tmpPath; + continue; + } + + hFind = ::FindFirstFile(tmpPath, &findFileData); + if (hFind == INVALID_HANDLE_VALUE) + { + // Error: most likely reason is that path doesn't exist, so + // append any unprocessed parts and return + for ( i += 1; i < count; i++ ) + tmpPath += wxFILE_SEP_PATH + dirs[i]; + + return tmpPath; + } + + pathOut += findFileData.cFileName; + if ( (i < (count-1)) ) + pathOut += wxFILE_SEP_PATH; + + ::FindClose(hFind); + } +#else // !Win32 + pathOut = path; +#endif // Win32/!Win32 + + return pathOut; +} + +wxPathFormat wxFileName::GetFormat( wxPathFormat format ) +{ + if (format == wxPATH_NATIVE) + { +#if defined(__WXMSW__) || defined(__OS2__) || defined(__DOS__) + format = wxPATH_DOS; +#elif defined(__WXMAC__) && !defined(__DARWIN__) + format = wxPATH_MAC; +#elif defined(__VMS) + format = wxPATH_VMS; +#else + format = wxPATH_UNIX; +#endif + } + return format; +} + +// ---------------------------------------------------------------------------- +// path splitting function +// ---------------------------------------------------------------------------- + +/* static */ +void +wxFileName::SplitVolume(const wxString& fullpathWithVolume, + wxString *pstrVolume, + wxString *pstrPath, + wxPathFormat format) +{ + format = GetFormat(format); + + wxString fullpath = fullpathWithVolume; + + // special Windows UNC paths hack: transform \\share\path into share:path + if ( IsUNCPath(fullpath, format) ) + { + fullpath.erase(0, 2); + + size_t posFirstSlash = + fullpath.find_first_of(GetPathTerminators(format)); + if ( posFirstSlash != wxString::npos ) + { + fullpath[posFirstSlash] = wxFILE_SEP_DSK; + + // UNC paths are always absolute, right? (FIXME) + fullpath.insert(posFirstSlash + 1, 1, wxFILE_SEP_PATH_DOS); + } + } + + // We separate the volume here + if ( format == wxPATH_DOS || format == wxPATH_VMS ) + { + wxString sepVol = GetVolumeSeparator(format); + + size_t posFirstColon = fullpath.find_first_of(sepVol); + if ( posFirstColon != wxString::npos ) + { + if ( pstrVolume ) + { + *pstrVolume = fullpath.Left(posFirstColon); + } + + // remove the volume name and the separator from the full path + fullpath.erase(0, posFirstColon + sepVol.length()); + } + } + + if ( pstrPath ) + *pstrPath = fullpath; +} + +/* static */ +void wxFileName::SplitPath(const wxString& fullpathWithVolume, + wxString *pstrVolume, + wxString *pstrPath, + wxString *pstrName, + wxString *pstrExt, + bool *hasExt, + wxPathFormat format) +{ + format = GetFormat(format); + + wxString fullpath; + SplitVolume(fullpathWithVolume, pstrVolume, &fullpath, format); + + // find the positions of the last dot and last path separator in the path + size_t posLastDot = fullpath.find_last_of(wxFILE_SEP_EXT); + size_t posLastSlash = fullpath.find_last_of(GetPathTerminators(format)); + + // check whether this dot occurs at the very beginning of a path component + if ( (posLastDot != wxString::npos) && + (posLastDot == 0 || + IsPathSeparator(fullpath[posLastDot - 1]) || + (format == wxPATH_VMS && fullpath[posLastDot - 1] == _T(']'))) ) + { + // dot may be (and commonly -- at least under Unix -- is) the first + // character of the filename, don't treat the entire filename as + // extension in this case + posLastDot = wxString::npos; + } + + // if we do have a dot and a slash, check that the dot is in the name part + if ( (posLastDot != wxString::npos) && + (posLastSlash != wxString::npos) && + (posLastDot < posLastSlash) ) + { + // the dot is part of the path, not the start of the extension + posLastDot = wxString::npos; + } + + // now fill in the variables provided by user + if ( pstrPath ) + { + if ( posLastSlash == wxString::npos ) + { + // no path at all + pstrPath->Empty(); + } + else + { + // take everything up to the path separator but take care to make + // the path equal to something like '/', not empty, for the files + // immediately under root directory + size_t len = posLastSlash; + + // this rule does not apply to mac since we do not start with colons (sep) + // except for relative paths + if ( !len && format != wxPATH_MAC) + len++; + + *pstrPath = fullpath.Left(len); + + // special VMS hack: remove the initial bracket + if ( format == wxPATH_VMS ) + { + if ( (*pstrPath)[0u] == _T('[') ) + pstrPath->erase(0, 1); + } + } + } + + if ( pstrName ) + { + // take all characters starting from the one after the last slash and + // up to, but excluding, the last dot + size_t nStart = posLastSlash == wxString::npos ? 0 : posLastSlash + 1; + size_t count; + if ( posLastDot == wxString::npos ) + { + // take all until the end + count = wxString::npos; + } + else if ( posLastSlash == wxString::npos ) + { + count = posLastDot; + } + else // have both dot and slash + { + count = posLastDot - posLastSlash - 1; + } + + *pstrName = fullpath.Mid(nStart, count); + } + + // finally deal with the extension here: we have an added complication that + // extension may be empty (but present) as in "foo." where trailing dot + // indicates the empty extension at the end -- and hence we must remember + // that we have it independently of pstrExt + if ( posLastDot == wxString::npos ) + { + // no extension + if ( pstrExt ) + pstrExt->clear(); + if ( hasExt ) + *hasExt = false; + } + else + { + // take everything after the dot + if ( pstrExt ) + *pstrExt = fullpath.Mid(posLastDot + 1); + if ( hasExt ) + *hasExt = true; + } +} + +/* static */ +void wxFileName::SplitPath(const wxString& fullpath, + wxString *path, + wxString *name, + wxString *ext, + wxPathFormat format) +{ + wxString volume; + SplitPath(fullpath, &volume, path, name, ext, format); + + if ( path ) + { + path->Prepend(wxGetVolumeString(volume, format)); + } +} + +// ---------------------------------------------------------------------------- +// time functions +// ---------------------------------------------------------------------------- + +#if wxUSE_DATETIME + +bool wxFileName::SetTimes(const wxDateTime *dtAccess, + const wxDateTime *dtMod, + const wxDateTime *dtCreate) +{ +#if defined(__WIN32__) + if ( IsDir() ) + { + // VZ: please let me know how to do this if you can + wxFAIL_MSG( _T("SetTimes() not implemented for the directories") ); + } + else // file + { + wxFileHandle fh(GetFullPath(), wxFileHandle::Write); + if ( fh.IsOk() ) + { + FILETIME ftAccess, ftCreate, ftWrite; + + if ( dtCreate ) + ConvertWxToFileTime(&ftCreate, *dtCreate); + if ( dtAccess ) + ConvertWxToFileTime(&ftAccess, *dtAccess); + if ( dtMod ) + ConvertWxToFileTime(&ftWrite, *dtMod); + + if ( ::SetFileTime(fh, + dtCreate ? &ftCreate : NULL, + dtAccess ? &ftAccess : NULL, + dtMod ? &ftWrite : NULL) ) + { + return true; + } + } + } +#elif defined(__UNIX_LIKE__) || (defined(__DOS__) && defined(__WATCOMC__)) + wxUnusedVar(dtCreate); + + if ( !dtAccess && !dtMod ) + { + // can't modify the creation time anyhow, don't try + return true; + } + + // if dtAccess or dtMod is not specified, use the other one (which must be + // non NULL because of the test above) for both times + utimbuf utm; + utm.actime = dtAccess ? dtAccess->GetTicks() : dtMod->GetTicks(); + utm.modtime = dtMod ? dtMod->GetTicks() : dtAccess->GetTicks(); + if ( utime(GetFullPath().fn_str(), &utm) == 0 ) + { + return true; + } +#else // other platform + wxUnusedVar(dtAccess); + wxUnusedVar(dtMod); + wxUnusedVar(dtCreate); +#endif // platforms + + wxLogSysError(_("Failed to modify file times for '%s'"), + GetFullPath().c_str()); + + return false; +} + +bool wxFileName::Touch() +{ +#if defined(__UNIX_LIKE__) + // under Unix touching file is simple: just pass NULL to utime() + if ( utime(GetFullPath().fn_str(), NULL) == 0 ) + { + return true; + } + + wxLogSysError(_("Failed to touch the file '%s'"), GetFullPath().c_str()); + + return false; +#else // other platform + wxDateTime dtNow = wxDateTime::Now(); + + return SetTimes(&dtNow, &dtNow, NULL /* don't change create time */); +#endif // platforms +} + +#ifdef wxNEED_WX_UNISTD_H + +static int wxStat( const char *file_name, wxStructStat *buf ) +{ + return stat( file_name , buf ); +} + +#endif + +bool wxFileName::GetTimes(wxDateTime *dtAccess, + wxDateTime *dtMod, + wxDateTime *dtCreate) const +{ +#if defined(__WIN32__) + // we must use different methods for the files and directories under + // Windows as CreateFile(GENERIC_READ) doesn't work for the directories and + // CreateFile(FILE_FLAG_BACKUP_SEMANTICS) works -- but only under NT and + // not 9x + bool ok; + FILETIME ftAccess, ftCreate, ftWrite; + if ( IsDir() ) + { + // implemented in msw/dir.cpp + extern bool wxGetDirectoryTimes(const wxString& dirname, + FILETIME *, FILETIME *, FILETIME *); + + // we should pass the path without the trailing separator to + // wxGetDirectoryTimes() + ok = wxGetDirectoryTimes(GetPath(wxPATH_GET_VOLUME), + &ftAccess, &ftCreate, &ftWrite); + } + else // file + { + wxFileHandle fh(GetFullPath(), wxFileHandle::Read); + if ( fh.IsOk() ) + { + ok = ::GetFileTime(fh, + dtCreate ? &ftCreate : NULL, + dtAccess ? &ftAccess : NULL, + dtMod ? &ftWrite : NULL) != 0; + } + else + { + ok = false; + } + } + + if ( ok ) + { + if ( dtCreate ) + ConvertFileTimeToWx(dtCreate, ftCreate); + if ( dtAccess ) + ConvertFileTimeToWx(dtAccess, ftAccess); + if ( dtMod ) + ConvertFileTimeToWx(dtMod, ftWrite); + + return true; + } +#elif defined(__UNIX_LIKE__) || defined(__WXMAC__) || defined(__OS2__) || (defined(__DOS__) && defined(__WATCOMC__)) + // no need to test for IsDir() here + wxStructStat stBuf; + if ( wxStat( GetFullPath().fn_str(), &stBuf) == 0 ) + { + if ( dtAccess ) + dtAccess->Set(stBuf.st_atime); + if ( dtMod ) + dtMod->Set(stBuf.st_mtime); + if ( dtCreate ) + dtCreate->Set(stBuf.st_ctime); + + return true; + } +#else // other platform + wxUnusedVar(dtAccess); + wxUnusedVar(dtMod); + wxUnusedVar(dtCreate); +#endif // platforms + + wxLogSysError(_("Failed to retrieve file times for '%s'"), + GetFullPath().c_str()); + + return false; +} + +#endif // wxUSE_DATETIME + + +// ---------------------------------------------------------------------------- +// file size functions +// ---------------------------------------------------------------------------- + +/* static */ +wxULongLong wxFileName::GetSize(const wxString &filename) +{ + if (!wxFileExists(filename)) + return wxInvalidSize; + +#if defined(__WXPALMOS__) + // TODO + return wxInvalidSize; +#elif defined(__WIN32__) + wxFileHandle f(filename, wxFileHandle::Read); + if (!f.IsOk()) + return wxInvalidSize; + + DWORD lpFileSizeHigh; + DWORD ret = GetFileSize(f, &lpFileSizeHigh); + if ( ret == INVALID_FILE_SIZE && ::GetLastError() != NO_ERROR ) + return wxInvalidSize; + + return wxULongLong(lpFileSizeHigh, ret); +#else // ! __WIN32__ + wxStructStat st; +#ifndef wxNEED_WX_UNISTD_H + if (wxStat( filename.fn_str() , &st) != 0) +#else + if (wxStat( filename, &st) != 0) +#endif + return wxInvalidSize; + return wxULongLong(st.st_size); +#endif +} + +/* static */ +wxString wxFileName::GetHumanReadableSize(const wxULongLong &bs, + const wxString &nullsize, + int precision) +{ + static const double KILOBYTESIZE = 1024.0; + static const double MEGABYTESIZE = 1024.0*KILOBYTESIZE; + static const double GIGABYTESIZE = 1024.0*MEGABYTESIZE; + static const double TERABYTESIZE = 1024.0*GIGABYTESIZE; + + if (bs == 0 || bs == wxInvalidSize) + return nullsize; + + double bytesize = bs.ToDouble(); + if (bytesize < KILOBYTESIZE) + return wxString::Format(_("%s B"), bs.ToString().c_str()); + if (bytesize < MEGABYTESIZE) + return wxString::Format(_("%.*f kB"), precision, bytesize/KILOBYTESIZE); + if (bytesize < GIGABYTESIZE) + return wxString::Format(_("%.*f MB"), precision, bytesize/MEGABYTESIZE); + if (bytesize < TERABYTESIZE) + return wxString::Format(_("%.*f GB"), precision, bytesize/GIGABYTESIZE); + + return wxString::Format(_("%.*f TB"), precision, bytesize/TERABYTESIZE); +} + +wxULongLong wxFileName::GetSize() const +{ + return GetSize(GetFullPath()); +} + +wxString wxFileName::GetHumanReadableSize(const wxString &failmsg, int precision) const +{ + return GetHumanReadableSize(GetSize(), failmsg, precision); +} + + +// ---------------------------------------------------------------------------- +// Mac-specific functions +// ---------------------------------------------------------------------------- + +#ifdef __WXMAC__ + +const short kMacExtensionMaxLength = 16 ; +class MacDefaultExtensionRecord +{ +public : + MacDefaultExtensionRecord() + { + m_ext[0] = 0 ; + m_type = m_creator = 0 ; + } + MacDefaultExtensionRecord( const MacDefaultExtensionRecord& from ) + { + wxStrcpy( m_ext , from.m_ext ) ; + m_type = from.m_type ; + m_creator = from.m_creator ; + } + MacDefaultExtensionRecord( const wxChar * extension , OSType type , OSType creator ) + { + wxStrncpy( m_ext , extension , kMacExtensionMaxLength ) ; + m_ext[kMacExtensionMaxLength] = 0 ; + m_type = type ; + m_creator = creator ; + } + wxChar m_ext[kMacExtensionMaxLength] ; + OSType m_type ; + OSType m_creator ; +} ; + +WX_DECLARE_OBJARRAY(MacDefaultExtensionRecord, MacDefaultExtensionArray) ; + +bool gMacDefaultExtensionsInited = false ; + +#include "wx/arrimpl.cpp" + +WX_DEFINE_EXPORTED_OBJARRAY(MacDefaultExtensionArray) ; + +MacDefaultExtensionArray gMacDefaultExtensions ; + +// load the default extensions +MacDefaultExtensionRecord gDefaults[] = +{ + MacDefaultExtensionRecord( wxT("txt") , 'TEXT' , 'ttxt' ) , + MacDefaultExtensionRecord( wxT("tif") , 'TIFF' , '****' ) , + MacDefaultExtensionRecord( wxT("jpg") , 'JPEG' , '****' ) , +} ; + +static void MacEnsureDefaultExtensionsLoaded() +{ + if ( !gMacDefaultExtensionsInited ) + { + // we could load the pc exchange prefs here too + for ( size_t i = 0 ; i < WXSIZEOF( gDefaults ) ; ++i ) + { + gMacDefaultExtensions.Add( gDefaults[i] ) ; + } + gMacDefaultExtensionsInited = true ; + } +} + +bool wxFileName::MacSetTypeAndCreator( wxUint32 type , wxUint32 creator ) +{ + FSRef fsRef ; + FSCatalogInfo catInfo; + FileInfo *finfo ; + + if ( wxMacPathToFSRef( GetFullPath() , &fsRef ) == noErr ) + { + if ( FSGetCatalogInfo (&fsRef, kFSCatInfoFinderInfo, &catInfo, NULL, NULL, NULL) == noErr ) + { + finfo = (FileInfo*)&catInfo.finderInfo; + finfo->fileType = type ; + finfo->fileCreator = creator ; + FSSetCatalogInfo( &fsRef, kFSCatInfoFinderInfo, &catInfo ) ; + return true ; + } + } + return false ; +} + +bool wxFileName::MacGetTypeAndCreator( wxUint32 *type , wxUint32 *creator ) +{ + FSRef fsRef ; + FSCatalogInfo catInfo; + FileInfo *finfo ; + + if ( wxMacPathToFSRef( GetFullPath() , &fsRef ) == noErr ) + { + if ( FSGetCatalogInfo (&fsRef, kFSCatInfoFinderInfo, &catInfo, NULL, NULL, NULL) == noErr ) + { + finfo = (FileInfo*)&catInfo.finderInfo; + *type = finfo->fileType ; + *creator = finfo->fileCreator ; + return true ; + } + } + return false ; +} + +bool wxFileName::MacSetDefaultTypeAndCreator() +{ + wxUint32 type , creator ; + if ( wxFileName::MacFindDefaultTypeAndCreator(GetExt() , &type , + &creator ) ) + { + return MacSetTypeAndCreator( type , creator ) ; + } + return false; +} + +bool wxFileName::MacFindDefaultTypeAndCreator( const wxString& ext , wxUint32 *type , wxUint32 *creator ) +{ + MacEnsureDefaultExtensionsLoaded() ; + wxString extl = ext.Lower() ; + for( int i = gMacDefaultExtensions.Count() - 1 ; i >= 0 ; --i ) + { + if ( gMacDefaultExtensions.Item(i).m_ext == extl ) + { + *type = gMacDefaultExtensions.Item(i).m_type ; + *creator = gMacDefaultExtensions.Item(i).m_creator ; + return true ; + } + } + return false ; +} + +void wxFileName::MacRegisterDefaultTypeAndCreator( const wxString& ext , wxUint32 type , wxUint32 creator ) +{ + MacEnsureDefaultExtensionsLoaded() ; + MacDefaultExtensionRecord rec ; + rec.m_type = type ; + rec.m_creator = creator ; + wxStrncpy( rec.m_ext , ext.Lower().c_str() , kMacExtensionMaxLength ) ; + gMacDefaultExtensions.Add( rec ) ; +} +#endif diff --git a/Externals/wxWidgets/src/common/filepickercmn.cpp b/Externals/wxWidgets/src/common/filepickercmn.cpp index 87def3dfc7..7b805dc8fe 100644 --- a/Externals/wxWidgets/src/common/filepickercmn.cpp +++ b/Externals/wxWidgets/src/common/filepickercmn.cpp @@ -1,224 +1,224 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: src/common/filepickercmn.cpp -// Purpose: wxFilePickerCtrl class implementation -// Author: Francesco Montorsi (readapted code written by Vadim Zeitlin) -// Modified by: -// Created: 15/04/2006 -// RCS-ID: $Id: filepickercmn.cpp 42219 2006-10-21 19:53:05Z PC $ -// Copyright: (c) Vadim Zeitlin, Francesco Montorsi -// Licence: wxWindows licence -/////////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_FILEPICKERCTRL || wxUSE_DIRPICKERCTRL - -#include "wx/filepicker.h" -#include "wx/filename.h" - -#ifndef WX_PRECOMP - #include "wx/textctrl.h" -#endif - -// ============================================================================ -// implementation -// ============================================================================ - -const wxChar wxFilePickerCtrlNameStr[] = wxT("filepicker"); -const wxChar wxFilePickerWidgetNameStr[] = wxT("filepickerwidget"); -const wxChar wxDirPickerCtrlNameStr[] = wxT("dirpicker"); -const wxChar wxDirPickerWidgetNameStr[] = wxT("dirpickerwidget"); -const wxChar wxFilePickerWidgetLabel[] = wxT("Browse"); -const wxChar wxDirPickerWidgetLabel[] = wxT("Browse"); - -DEFINE_EVENT_TYPE(wxEVT_COMMAND_FILEPICKER_CHANGED) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_DIRPICKER_CHANGED) -IMPLEMENT_DYNAMIC_CLASS(wxFileDirPickerEvent, wxCommandEvent) - -// ---------------------------------------------------------------------------- -// wxFileDirPickerCtrlBase -// ---------------------------------------------------------------------------- - -bool wxFileDirPickerCtrlBase::CreateBase(wxWindow *parent, - wxWindowID id, - const wxString &path, - const wxString &message, - const wxString &wildcard, - const wxPoint &pos, - const wxSize &size, - long style, - const wxValidator& validator, - const wxString &name ) -{ - wxASSERT_MSG(path.empty() || CheckPath(path), wxT("Invalid initial path!")); - - if (!wxPickerBase::CreateBase(parent, id, path, pos, size, - style, validator, name)) - return false; - - if (!HasFlag(wxFLP_OPEN) && !HasFlag(wxFLP_SAVE)) - m_windowStyle |= wxFLP_OPEN; // wxFD_OPEN is the default - - // check that the styles are not contradictory - wxASSERT_MSG( !(HasFlag(wxFLP_SAVE) && HasFlag(wxFLP_OPEN)), - _T("can't specify both wxFLP_SAVE and wxFLP_OPEN at once") ); - - wxASSERT_MSG( !HasFlag(wxFLP_SAVE) || !HasFlag(wxFLP_FILE_MUST_EXIST), - _T("wxFLP_FILE_MUST_EXIST can't be used with wxFLP_SAVE" ) ); - - wxASSERT_MSG( !HasFlag(wxFLP_OPEN) || !HasFlag(wxFLP_OVERWRITE_PROMPT), - _T("wxFLP_OVERWRITE_PROMPT can't be used with wxFLP_OPEN") ); - - // create a wxFilePickerWidget or a wxDirPickerWidget... - m_pickerIface = CreatePicker(this, path, message, wildcard); - if ( !m_pickerIface ) - return false; - m_picker = m_pickerIface->AsControl(); - - // complete sizer creation - wxPickerBase::PostCreation(); - - m_picker->Connect(GetEventType(), - wxFileDirPickerEventHandler(wxFileDirPickerCtrlBase::OnFileDirChange), - NULL, this); - - // default's wxPickerBase textctrl limit is too small for this control: - // make it bigger - if (m_text) m_text->SetMaxLength(512); - - return true; -} - -wxString wxFileDirPickerCtrlBase::GetPath() const -{ - return m_pickerIface->GetPath(); -} - -void wxFileDirPickerCtrlBase::SetPath(const wxString &path) -{ - m_pickerIface->SetPath(path); - UpdateTextCtrlFromPicker(); -} - -void wxFileDirPickerCtrlBase::UpdatePickerFromTextCtrl() -{ - wxASSERT(m_text); - - if (m_bIgnoreNextTextCtrlUpdate) - { - // ignore this update - m_bIgnoreNextTextCtrlUpdate = false; - return; - } - - // remove the eventually present path-separator from the end of the textctrl - // string otherwise we would generate a wxFileDirPickerEvent when changing - // from e.g. /home/user to /home/user/ and we want to avoid it ! - wxString newpath(GetTextCtrlValue()); - if (!CheckPath(newpath)) - return; // invalid user input - - if (m_pickerIface->GetPath() != newpath) - { - m_pickerIface->SetPath(newpath); - - // update current working directory, if necessary - // NOTE: the path separator is required because if newpath is "C:" - // then no change would happen - if (IsCwdToUpdate()) - wxSetWorkingDirectory(newpath); - - // fire an event - wxFileDirPickerEvent event(GetEventType(), this, GetId(), newpath); - GetEventHandler()->ProcessEvent(event); - } -} - -void wxFileDirPickerCtrlBase::UpdateTextCtrlFromPicker() -{ - if (!m_text) - return; // no textctrl to update - - // NOTE: this SetValue() will generate an unwanted wxEVT_COMMAND_TEXT_UPDATED - // which will trigger a unneeded UpdateFromTextCtrl(); thus before using - // SetValue() we set the m_bIgnoreNextTextCtrlUpdate flag... - m_bIgnoreNextTextCtrlUpdate = true; - m_text->SetValue(m_pickerIface->GetPath()); -} - - - -// ---------------------------------------------------------------------------- -// wxFileDirPickerCtrlBase - event handlers -// ---------------------------------------------------------------------------- - -void wxFileDirPickerCtrlBase::OnFileDirChange(wxFileDirPickerEvent &ev) -{ - UpdateTextCtrlFromPicker(); - - // the wxFilePickerWidget sent us a colour-change notification. - // forward this event to our parent - wxFileDirPickerEvent event(GetEventType(), this, GetId(), ev.GetPath()); - GetEventHandler()->ProcessEvent(event); -} - -#endif // wxUSE_FILEPICKERCTRL || wxUSE_DIRPICKERCTRL - -// ---------------------------------------------------------------------------- -// wxFileDirPickerCtrl -// ---------------------------------------------------------------------------- - -#if wxUSE_FILEPICKERCTRL - -IMPLEMENT_DYNAMIC_CLASS(wxFilePickerCtrl, wxPickerBase) - -bool wxFilePickerCtrl::CheckPath(const wxString& path) const -{ - // if wxFLP_SAVE was given or wxFLP_FILE_MUST_EXIST has NOT been given we - // must accept any path - return HasFlag(wxFLP_SAVE) || - !HasFlag(wxFLP_FILE_MUST_EXIST) || - wxFileName::FileExists(path); -} - -wxString wxFilePickerCtrl::GetTextCtrlValue() const -{ - // filter it through wxFileName to remove any spurious path separator - return wxFileName(m_text->GetValue()).GetFullPath(); -} - -#endif // wxUSE_FILEPICKERCTRL - -// ---------------------------------------------------------------------------- -// wxDirPickerCtrl -// ---------------------------------------------------------------------------- - -#if wxUSE_DIRPICKERCTRL -IMPLEMENT_DYNAMIC_CLASS(wxDirPickerCtrl, wxPickerBase) - -bool wxDirPickerCtrl::CheckPath(const wxString& path) const -{ - // if wxDIRP_DIR_MUST_EXIST has NOT been given we must accept any path - return !HasFlag(wxDIRP_DIR_MUST_EXIST) || wxFileName::DirExists(path); -} - -wxString wxDirPickerCtrl::GetTextCtrlValue() const -{ - // filter it through wxFileName to remove any spurious path separator - return wxFileName::DirName(m_text->GetValue()).GetPath(); -} - -#endif // wxUSE_DIRPICKERCTRL +/////////////////////////////////////////////////////////////////////////////// +// Name: src/common/filepickercmn.cpp +// Purpose: wxFilePickerCtrl class implementation +// Author: Francesco Montorsi (readapted code written by Vadim Zeitlin) +// Modified by: +// Created: 15/04/2006 +// RCS-ID: $Id: filepickercmn.cpp 42219 2006-10-21 19:53:05Z PC $ +// Copyright: (c) Vadim Zeitlin, Francesco Montorsi +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_FILEPICKERCTRL || wxUSE_DIRPICKERCTRL + +#include "wx/filepicker.h" +#include "wx/filename.h" + +#ifndef WX_PRECOMP + #include "wx/textctrl.h" +#endif + +// ============================================================================ +// implementation +// ============================================================================ + +const wxChar wxFilePickerCtrlNameStr[] = wxT("filepicker"); +const wxChar wxFilePickerWidgetNameStr[] = wxT("filepickerwidget"); +const wxChar wxDirPickerCtrlNameStr[] = wxT("dirpicker"); +const wxChar wxDirPickerWidgetNameStr[] = wxT("dirpickerwidget"); +const wxChar wxFilePickerWidgetLabel[] = wxT("Browse"); +const wxChar wxDirPickerWidgetLabel[] = wxT("Browse"); + +DEFINE_EVENT_TYPE(wxEVT_COMMAND_FILEPICKER_CHANGED) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_DIRPICKER_CHANGED) +IMPLEMENT_DYNAMIC_CLASS(wxFileDirPickerEvent, wxCommandEvent) + +// ---------------------------------------------------------------------------- +// wxFileDirPickerCtrlBase +// ---------------------------------------------------------------------------- + +bool wxFileDirPickerCtrlBase::CreateBase(wxWindow *parent, + wxWindowID id, + const wxString &path, + const wxString &message, + const wxString &wildcard, + const wxPoint &pos, + const wxSize &size, + long style, + const wxValidator& validator, + const wxString &name ) +{ + wxASSERT_MSG(path.empty() || CheckPath(path), wxT("Invalid initial path!")); + + if (!wxPickerBase::CreateBase(parent, id, path, pos, size, + style, validator, name)) + return false; + + if (!HasFlag(wxFLP_OPEN) && !HasFlag(wxFLP_SAVE)) + m_windowStyle |= wxFLP_OPEN; // wxFD_OPEN is the default + + // check that the styles are not contradictory + wxASSERT_MSG( !(HasFlag(wxFLP_SAVE) && HasFlag(wxFLP_OPEN)), + _T("can't specify both wxFLP_SAVE and wxFLP_OPEN at once") ); + + wxASSERT_MSG( !HasFlag(wxFLP_SAVE) || !HasFlag(wxFLP_FILE_MUST_EXIST), + _T("wxFLP_FILE_MUST_EXIST can't be used with wxFLP_SAVE" ) ); + + wxASSERT_MSG( !HasFlag(wxFLP_OPEN) || !HasFlag(wxFLP_OVERWRITE_PROMPT), + _T("wxFLP_OVERWRITE_PROMPT can't be used with wxFLP_OPEN") ); + + // create a wxFilePickerWidget or a wxDirPickerWidget... + m_pickerIface = CreatePicker(this, path, message, wildcard); + if ( !m_pickerIface ) + return false; + m_picker = m_pickerIface->AsControl(); + + // complete sizer creation + wxPickerBase::PostCreation(); + + m_picker->Connect(GetEventType(), + wxFileDirPickerEventHandler(wxFileDirPickerCtrlBase::OnFileDirChange), + NULL, this); + + // default's wxPickerBase textctrl limit is too small for this control: + // make it bigger + if (m_text) m_text->SetMaxLength(512); + + return true; +} + +wxString wxFileDirPickerCtrlBase::GetPath() const +{ + return m_pickerIface->GetPath(); +} + +void wxFileDirPickerCtrlBase::SetPath(const wxString &path) +{ + m_pickerIface->SetPath(path); + UpdateTextCtrlFromPicker(); +} + +void wxFileDirPickerCtrlBase::UpdatePickerFromTextCtrl() +{ + wxASSERT(m_text); + + if (m_bIgnoreNextTextCtrlUpdate) + { + // ignore this update + m_bIgnoreNextTextCtrlUpdate = false; + return; + } + + // remove the eventually present path-separator from the end of the textctrl + // string otherwise we would generate a wxFileDirPickerEvent when changing + // from e.g. /home/user to /home/user/ and we want to avoid it ! + wxString newpath(GetTextCtrlValue()); + if (!CheckPath(newpath)) + return; // invalid user input + + if (m_pickerIface->GetPath() != newpath) + { + m_pickerIface->SetPath(newpath); + + // update current working directory, if necessary + // NOTE: the path separator is required because if newpath is "C:" + // then no change would happen + if (IsCwdToUpdate()) + wxSetWorkingDirectory(newpath); + + // fire an event + wxFileDirPickerEvent event(GetEventType(), this, GetId(), newpath); + GetEventHandler()->ProcessEvent(event); + } +} + +void wxFileDirPickerCtrlBase::UpdateTextCtrlFromPicker() +{ + if (!m_text) + return; // no textctrl to update + + // NOTE: this SetValue() will generate an unwanted wxEVT_COMMAND_TEXT_UPDATED + // which will trigger a unneeded UpdateFromTextCtrl(); thus before using + // SetValue() we set the m_bIgnoreNextTextCtrlUpdate flag... + m_bIgnoreNextTextCtrlUpdate = true; + m_text->SetValue(m_pickerIface->GetPath()); +} + + + +// ---------------------------------------------------------------------------- +// wxFileDirPickerCtrlBase - event handlers +// ---------------------------------------------------------------------------- + +void wxFileDirPickerCtrlBase::OnFileDirChange(wxFileDirPickerEvent &ev) +{ + UpdateTextCtrlFromPicker(); + + // the wxFilePickerWidget sent us a colour-change notification. + // forward this event to our parent + wxFileDirPickerEvent event(GetEventType(), this, GetId(), ev.GetPath()); + GetEventHandler()->ProcessEvent(event); +} + +#endif // wxUSE_FILEPICKERCTRL || wxUSE_DIRPICKERCTRL + +// ---------------------------------------------------------------------------- +// wxFileDirPickerCtrl +// ---------------------------------------------------------------------------- + +#if wxUSE_FILEPICKERCTRL + +IMPLEMENT_DYNAMIC_CLASS(wxFilePickerCtrl, wxPickerBase) + +bool wxFilePickerCtrl::CheckPath(const wxString& path) const +{ + // if wxFLP_SAVE was given or wxFLP_FILE_MUST_EXIST has NOT been given we + // must accept any path + return HasFlag(wxFLP_SAVE) || + !HasFlag(wxFLP_FILE_MUST_EXIST) || + wxFileName::FileExists(path); +} + +wxString wxFilePickerCtrl::GetTextCtrlValue() const +{ + // filter it through wxFileName to remove any spurious path separator + return wxFileName(m_text->GetValue()).GetFullPath(); +} + +#endif // wxUSE_FILEPICKERCTRL + +// ---------------------------------------------------------------------------- +// wxDirPickerCtrl +// ---------------------------------------------------------------------------- + +#if wxUSE_DIRPICKERCTRL +IMPLEMENT_DYNAMIC_CLASS(wxDirPickerCtrl, wxPickerBase) + +bool wxDirPickerCtrl::CheckPath(const wxString& path) const +{ + // if wxDIRP_DIR_MUST_EXIST has NOT been given we must accept any path + return !HasFlag(wxDIRP_DIR_MUST_EXIST) || wxFileName::DirExists(path); +} + +wxString wxDirPickerCtrl::GetTextCtrlValue() const +{ + // filter it through wxFileName to remove any spurious path separator + return wxFileName::DirName(m_text->GetValue()).GetPath(); +} + +#endif // wxUSE_DIRPICKERCTRL diff --git a/Externals/wxWidgets/src/common/filesys.cpp b/Externals/wxWidgets/src/common/filesys.cpp index 7892ce719e..d39242b14f 100644 --- a/Externals/wxWidgets/src/common/filesys.cpp +++ b/Externals/wxWidgets/src/common/filesys.cpp @@ -1,684 +1,684 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/filesys.cpp -// Purpose: wxFileSystem class - interface for opening files -// Author: Vaclav Slavik -// Copyright: (c) 1999 Vaclav Slavik -// CVS-ID: $Id: filesys.cpp 51940 2008-02-20 16:33:55Z VZ $ -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - - -#if wxUSE_FILESYSTEM - -#include "wx/filesys.h" - -#ifndef WX_PRECOMP - #include "wx/log.h" - #include "wx/module.h" -#endif - -#include "wx/wfstream.h" -#include "wx/mimetype.h" -#include "wx/filename.h" -#include "wx/tokenzr.h" -#include "wx/uri.h" -#include "wx/private/fileback.h" - - -//-------------------------------------------------------------------------------- -// wxFileSystemHandler -//-------------------------------------------------------------------------------- - -IMPLEMENT_ABSTRACT_CLASS(wxFileSystemHandler, wxObject) - - -wxString wxFileSystemHandler::GetMimeTypeFromExt(const wxString& location) -{ - wxString ext, mime; - wxString loc = GetRightLocation(location); - wxChar c; - int l = loc.length(), l2; - - l2 = l; - for (int i = l-1; i >= 0; i--) - { - c = loc[(unsigned int) i]; - if ( c == wxT('#') ) - l2 = i + 1; - if ( c == wxT('.') ) - { - ext = loc.Right(l2-i-1); - break; - } - if ( (c == wxT('/')) || (c == wxT('\\')) || (c == wxT(':')) ) - return wxEmptyString; - } - -#if wxUSE_MIMETYPE - static bool s_MinimalMimeEnsured = false; - if (!s_MinimalMimeEnsured) - { - static const wxFileTypeInfo fallbacks[] = - { - wxFileTypeInfo(_T("image/jpeg"), - wxEmptyString, - wxEmptyString, - _T("JPEG image (from fallback)"), - _T("jpg"), _T("jpeg"), _T("JPG"), _T("JPEG"), NULL), - wxFileTypeInfo(_T("image/gif"), - wxEmptyString, - wxEmptyString, - _T("GIF image (from fallback)"), - _T("gif"), _T("GIF"), NULL), - wxFileTypeInfo(_T("image/png"), - wxEmptyString, - wxEmptyString, - _T("PNG image (from fallback)"), - _T("png"), _T("PNG"), NULL), - wxFileTypeInfo(_T("image/bmp"), - wxEmptyString, - wxEmptyString, - _T("windows bitmap image (from fallback)"), - _T("bmp"), _T("BMP"), NULL), - wxFileTypeInfo(_T("text/html"), - wxEmptyString, - wxEmptyString, - _T("HTML document (from fallback)"), - _T("htm"), _T("html"), _T("HTM"), _T("HTML"), NULL), - // must terminate the table with this! - wxFileTypeInfo() - }; - wxTheMimeTypesManager->AddFallbacks(fallbacks); - s_MinimalMimeEnsured = true; - } - - wxFileType *ft = wxTheMimeTypesManager->GetFileTypeFromExtension(ext); - if ( !ft || !ft -> GetMimeType(&mime) ) - { - mime = wxEmptyString; - } - - delete ft; - - return mime; -#else - if ( ext.IsSameAs(wxT("htm"), false) || ext.IsSameAs(_T("html"), false) ) - return wxT("text/html"); - if ( ext.IsSameAs(wxT("jpg"), false) || ext.IsSameAs(_T("jpeg"), false) ) - return wxT("image/jpeg"); - if ( ext.IsSameAs(wxT("gif"), false) ) - return wxT("image/gif"); - if ( ext.IsSameAs(wxT("png"), false) ) - return wxT("image/png"); - if ( ext.IsSameAs(wxT("bmp"), false) ) - return wxT("image/bmp"); - return wxEmptyString; -#endif -} - - - -wxString wxFileSystemHandler::GetProtocol(const wxString& location) const -{ - wxString s = wxEmptyString; - int i, l = location.length(); - bool fnd = false; - - for (i = l-1; (i >= 0) && ((location[i] != wxT('#')) || (!fnd)); i--) { - if ((location[i] == wxT(':')) && (i != 1 /*win: C:\path*/)) fnd = true; - } - if (!fnd) return wxT("file"); - for (++i; (i < l) && (location[i] != wxT(':')); i++) s << location[i]; - return s; -} - - -wxString wxFileSystemHandler::GetLeftLocation(const wxString& location) const -{ - int i; - bool fnd = false; - - for (i = location.length()-1; i >= 0; i--) { - if ((location[i] == wxT(':')) && (i != 1 /*win: C:\path*/)) fnd = true; - else if (fnd && (location[i] == wxT('#'))) return location.Left(i); - } - return wxEmptyString; -} - -wxString wxFileSystemHandler::GetRightLocation(const wxString& location) const -{ - int i, l = location.length(); - int l2 = l + 1; - - for (i = l-1; - (i >= 0) && - ((location[i] != wxT(':')) || (i == 1) || (location[i-2] == wxT(':'))); - i--) - { - if (location[i] == wxT('#')) l2 = i + 1; - } - if (i == 0) return wxEmptyString; - else return location.Mid(i + 1, l2 - i - 2); -} - -wxString wxFileSystemHandler::GetAnchor(const wxString& location) const -{ - wxChar c; - int l = location.length(); - - for (int i = l-1; i >= 0; i--) { - c = location[i]; - if (c == wxT('#')) return location.Right(l-i-1); - else if ((c == wxT('.')) || (c == wxT('/')) || (c == wxT('\\')) || (c == wxT(':'))) return wxEmptyString; - } - return wxEmptyString; -} - - -wxString wxFileSystemHandler::FindFirst(const wxString& WXUNUSED(spec), - int WXUNUSED(flags)) -{ - return wxEmptyString; -} - -wxString wxFileSystemHandler::FindNext() -{ - return wxEmptyString; -} - -//-------------------------------------------------------------------------------- -// wxLocalFSHandler -//-------------------------------------------------------------------------------- - - -wxString wxLocalFSHandler::ms_root; - -bool wxLocalFSHandler::CanOpen(const wxString& location) -{ - return GetProtocol(location) == wxT("file"); -} - -wxFSFile* wxLocalFSHandler::OpenFile(wxFileSystem& WXUNUSED(fs), const wxString& location) -{ - // location has Unix path separators - wxString right = GetRightLocation(location); - wxFileName fn = wxFileSystem::URLToFileName(right); - wxString fullpath = ms_root + fn.GetFullPath(); - - if (!wxFileExists(fullpath)) - return (wxFSFile*) NULL; - - // we need to check whether we can really read from this file, otherwise - // wxFSFile is not going to work -#if wxUSE_FFILE - wxFFileInputStream *is = new wxFFileInputStream(fullpath); -#elif wxUSE_FILE - wxFileInputStream *is = new wxFileInputStream(fullpath); -#else -#error One of wxUSE_FILE or wxUSE_FFILE must be set to 1 for wxFSHandler to work -#endif - if ( !is->Ok() ) - { - delete is; - return (wxFSFile*) NULL; - } - - return new wxFSFile(is, - right, - GetMimeTypeFromExt(location), - GetAnchor(location) -#if wxUSE_DATETIME - ,wxDateTime(wxFileModificationTime(fullpath)) -#endif // wxUSE_DATETIME - ); -} - -wxString wxLocalFSHandler::FindFirst(const wxString& spec, int flags) -{ - wxFileName fn = wxFileSystem::URLToFileName(GetRightLocation(spec)); - return wxFindFirstFile(ms_root + fn.GetFullPath(), flags); -} - -wxString wxLocalFSHandler::FindNext() -{ - return wxFindNextFile(); -} - - - -//----------------------------------------------------------------------------- -// wxFileSystem -//----------------------------------------------------------------------------- - -IMPLEMENT_DYNAMIC_CLASS(wxFileSystem, wxObject) -IMPLEMENT_ABSTRACT_CLASS(wxFSFile, wxObject) - - -wxList wxFileSystem::m_Handlers; - - -wxFileSystem::~wxFileSystem() -{ - WX_CLEAR_HASH_MAP(wxFSHandlerHash, m_LocalHandlers) -} - - -static wxString MakeCorrectPath(const wxString& path) -{ - wxString p(path); - wxString r; - int i, j, cnt; - - cnt = p.length(); - for (i = 0; i < cnt; i++) - if (p.GetChar(i) == wxT('\\')) p.GetWritableChar(i) = wxT('/'); // Want to be windows-safe - - if (p.Left(2) == wxT("./")) { p = p.Mid(2); cnt -= 2; } - - if (cnt < 3) return p; - - r << p.GetChar(0) << p.GetChar(1); - - // skip trailing ../.., if any - for (i = 2; i < cnt && (p.GetChar(i) == wxT('/') || p.GetChar(i) == wxT('.')); i++) r << p.GetChar(i); - - // remove back references: translate dir1/../dir2 to dir2 - for (; i < cnt; i++) - { - r << p.GetChar(i); - if (p.GetChar(i) == wxT('/') && p.GetChar(i-1) == wxT('.') && p.GetChar(i-2) == wxT('.')) - { - for (j = r.length() - 2; j >= 0 && r.GetChar(j) != wxT('/') && r.GetChar(j) != wxT(':'); j--) {} - if (j >= 0 && r.GetChar(j) != wxT(':')) - { - for (j = j - 1; j >= 0 && r.GetChar(j) != wxT('/') && r.GetChar(j) != wxT(':'); j--) {} - r.Remove(j + 1); - } - } - } - - for (; i < cnt; i++) r << p.GetChar(i); - - return r; -} - - -void wxFileSystem::ChangePathTo(const wxString& location, bool is_dir) -{ - int i, pathpos = -1; - - m_Path = MakeCorrectPath(location); - - if (is_dir) - { - if (m_Path.length() > 0 && m_Path.Last() != wxT('/') && m_Path.Last() != wxT(':')) - m_Path << wxT('/'); - } - - else - { - for (i = m_Path.length()-1; i >= 0; i--) - { - if (m_Path[(unsigned int) i] == wxT('/')) - { - if ((i > 1) && (m_Path[(unsigned int) (i-1)] == wxT('/')) && (m_Path[(unsigned int) (i-2)] == wxT(':'))) - { - i -= 2; - continue; - } - else - { - pathpos = i; - break; - } - } - else if (m_Path[(unsigned int) i] == wxT(':')) { - pathpos = i; - break; - } - } - if (pathpos == -1) - { - for (i = 0; i < (int) m_Path.length(); i++) - { - if (m_Path[(unsigned int) i] == wxT(':')) - { - m_Path.Remove(i+1); - break; - } - } - if (i == (int) m_Path.length()) - m_Path = wxEmptyString; - } - else - { - m_Path.Remove(pathpos+1); - } - } -} - - - -wxFileSystemHandler *wxFileSystem::MakeLocal(wxFileSystemHandler *h) -{ - wxClassInfo *classinfo = h->GetClassInfo(); - - if (classinfo->IsDynamic()) - { - wxFileSystemHandler*& local = m_LocalHandlers[classinfo]; - if (!local) - local = (wxFileSystemHandler*)classinfo->CreateObject(); - return local; - } - else - { - return h; - } -} - - - -wxFSFile* wxFileSystem::OpenFile(const wxString& location, int flags) -{ - if ((flags & wxFS_READ) == 0) - return NULL; - - wxString loc = MakeCorrectPath(location); - unsigned i, ln; - wxChar meta; - wxFSFile *s = NULL; - wxList::compatibility_iterator node; - - ln = loc.length(); - meta = 0; - for (i = 0; i < ln; i++) - { - switch (loc[i]) - { - case wxT('/') : case wxT(':') : case wxT('#') : - meta = loc[i]; - break; - } - if (meta != 0) break; - } - m_LastName = wxEmptyString; - - // try relative paths first : - if (meta != wxT(':')) - { - node = m_Handlers.GetFirst(); - while (node) - { - wxFileSystemHandler *h = (wxFileSystemHandler*) node -> GetData(); - if (h->CanOpen(m_Path + loc)) - { - s = MakeLocal(h)->OpenFile(*this, m_Path + loc); - if (s) { m_LastName = m_Path + loc; break; } - } - node = node->GetNext(); - } - } - - // if failed, try absolute paths : - if (s == NULL) - { - node = m_Handlers.GetFirst(); - while (node) - { - wxFileSystemHandler *h = (wxFileSystemHandler*) node->GetData(); - if (h->CanOpen(loc)) - { - s = MakeLocal(h)->OpenFile(*this, loc); - if (s) { m_LastName = loc; break; } - } - node = node->GetNext(); - } - } - - if (s && (flags & wxFS_SEEKABLE) != 0 && !s->GetStream()->IsSeekable()) - { - wxBackedInputStream *stream; - stream = new wxBackedInputStream(s->DetachStream()); - stream->FindLength(); - s->SetStream(stream); - } - - return (s); -} - - - -wxString wxFileSystem::FindFirst(const wxString& spec, int flags) -{ - wxList::compatibility_iterator node; - wxString spec2(spec); - - m_FindFileHandler = NULL; - - for (int i = spec2.length()-1; i >= 0; i--) - if (spec2[(unsigned int) i] == wxT('\\')) spec2.GetWritableChar(i) = wxT('/'); // Want to be windows-safe - - node = m_Handlers.GetFirst(); - while (node) - { - wxFileSystemHandler *h = (wxFileSystemHandler*) node -> GetData(); - if (h -> CanOpen(m_Path + spec2)) - { - m_FindFileHandler = MakeLocal(h); - return m_FindFileHandler -> FindFirst(m_Path + spec2, flags); - } - node = node->GetNext(); - } - - node = m_Handlers.GetFirst(); - while (node) - { - wxFileSystemHandler *h = (wxFileSystemHandler*) node -> GetData(); - if (h -> CanOpen(spec2)) - { - m_FindFileHandler = MakeLocal(h); - return m_FindFileHandler -> FindFirst(spec2, flags); - } - node = node->GetNext(); - } - - return wxEmptyString; -} - - - -wxString wxFileSystem::FindNext() -{ - if (m_FindFileHandler == NULL) return wxEmptyString; - else return m_FindFileHandler -> FindNext(); -} - -bool wxFileSystem::FindFileInPath(wxString *pStr, - const wxChar *path, - const wxChar *basename) -{ - // we assume that it's not empty - wxCHECK_MSG( !wxIsEmpty(basename), false, - _T("empty file name in wxFileSystem::FindFileInPath")); - - // skip path separator in the beginning of the file name if present - if ( wxIsPathSeparator(*basename) ) - basename++; - - wxStringTokenizer tokenizer(path, wxPATH_SEP); - while ( tokenizer.HasMoreTokens() ) - { - wxString strFile = tokenizer.GetNextToken(); - if ( !wxEndsWithPathSeparator(strFile) ) - strFile += wxFILE_SEP_PATH; - strFile += basename; - - wxFSFile *file = OpenFile(strFile); - if ( file ) - { - delete file; - *pStr = strFile; - return true; - } - } - - return false; -} - -void wxFileSystem::AddHandler(wxFileSystemHandler *handler) -{ - // prepend the handler to the beginning of the list because handlers added - // last should have the highest priority to allow overriding them - m_Handlers.Insert((size_t)0, handler); -} - -wxFileSystemHandler* wxFileSystem::RemoveHandler(wxFileSystemHandler *handler) -{ - // if handler has already been removed (or deleted) - // we return NULL. This is by design in case - // CleanUpHandlers() is called before RemoveHandler - // is called, as we cannot control the order - // which modules are unloaded - if (!m_Handlers.DeleteObject(handler)) - return NULL; - - return handler; -} - - -bool wxFileSystem::HasHandlerForPath(const wxString &location) -{ - for ( wxList::compatibility_iterator node = m_Handlers.GetFirst(); - node; node = node->GetNext() ) - { - wxFileSystemHandler *h = (wxFileSystemHandler*) node->GetData(); - if (h->CanOpen(location)) - return true; - } - - return false; -} - -void wxFileSystem::CleanUpHandlers() -{ - WX_CLEAR_LIST(wxList, m_Handlers); -} - -static const wxString g_unixPathString(wxT("/")); -static const wxString g_nativePathString(wxFILE_SEP_PATH); - -// Returns the native path for a file URL -wxFileName wxFileSystem::URLToFileName(const wxString& url) -{ - wxString path = url; - - if ( path.Find(wxT("file://")) == 0 ) - { - path = path.Mid(7); - } - else if ( path.Find(wxT("file:")) == 0 ) - { - path = path.Mid(5); - } - // Remove preceding double slash on Mac Classic -#if defined(__WXMAC__) && !defined(__UNIX__) - else if ( path.Find(wxT("//")) == 0 ) - path = path.Mid(2); -#endif - - path = wxURI::Unescape(path); - -#ifdef __WXMSW__ - // file urls either start with a forward slash (local harddisk), - // otherwise they have a servername/sharename notation, - // which only exists on msw and corresponds to a unc - if ( path[0u] == wxT('/') && path [1u] != wxT('/')) - { - path = path.Mid(1); - } - else if ( (url.Find(wxT("file://")) == 0) && - (path.Find(wxT('/')) != wxNOT_FOUND) && - (path.length() > 1) && (path[1u] != wxT(':')) ) - { - path = wxT("//") + path; - } -#endif - - path.Replace(g_unixPathString, g_nativePathString); - - return wxFileName(path, wxPATH_NATIVE); -} - -// Returns the file URL for a native path -wxString wxFileSystem::FileNameToURL(const wxFileName& filename) -{ - wxFileName fn = filename; - fn.Normalize(wxPATH_NORM_DOTS | wxPATH_NORM_TILDE | wxPATH_NORM_ABSOLUTE); - wxString url = fn.GetFullPath(wxPATH_NATIVE); - -#ifndef __UNIX__ - // unc notation, wxMSW - if ( url.Find(wxT("\\\\")) == 0 ) - { - url = wxT("//") + url.Mid(2); - } - else - { - url = wxT("/") + url; -#ifdef __WXMAC__ - url = wxT("/") + url; -#endif - - } -#endif - - url.Replace(g_nativePathString, g_unixPathString); - url.Replace(wxT("%"), wxT("%25")); // '%'s must be replaced first! - url.Replace(wxT("#"), wxT("%23")); - url.Replace(wxT(":"), wxT("%3A")); - url = wxT("file:") + url; - return url; -} - - -///// Module: - -class wxFileSystemModule : public wxModule -{ - DECLARE_DYNAMIC_CLASS(wxFileSystemModule) - - public: - wxFileSystemModule() : - wxModule(), - m_handler(NULL) - { - } - - virtual bool OnInit() - { - m_handler = new wxLocalFSHandler; - wxFileSystem::AddHandler(m_handler); - return true; - } - virtual void OnExit() - { - delete wxFileSystem::RemoveHandler(m_handler); - - wxFileSystem::CleanUpHandlers(); - } - - private: - wxFileSystemHandler* m_handler; - -}; - -IMPLEMENT_DYNAMIC_CLASS(wxFileSystemModule, wxModule) - -#endif - // wxUSE_FILESYSTEM +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/filesys.cpp +// Purpose: wxFileSystem class - interface for opening files +// Author: Vaclav Slavik +// Copyright: (c) 1999 Vaclav Slavik +// CVS-ID: $Id: filesys.cpp 51940 2008-02-20 16:33:55Z VZ $ +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + + +#if wxUSE_FILESYSTEM + +#include "wx/filesys.h" + +#ifndef WX_PRECOMP + #include "wx/log.h" + #include "wx/module.h" +#endif + +#include "wx/wfstream.h" +#include "wx/mimetype.h" +#include "wx/filename.h" +#include "wx/tokenzr.h" +#include "wx/uri.h" +#include "wx/private/fileback.h" + + +//-------------------------------------------------------------------------------- +// wxFileSystemHandler +//-------------------------------------------------------------------------------- + +IMPLEMENT_ABSTRACT_CLASS(wxFileSystemHandler, wxObject) + + +wxString wxFileSystemHandler::GetMimeTypeFromExt(const wxString& location) +{ + wxString ext, mime; + wxString loc = GetRightLocation(location); + wxChar c; + int l = loc.length(), l2; + + l2 = l; + for (int i = l-1; i >= 0; i--) + { + c = loc[(unsigned int) i]; + if ( c == wxT('#') ) + l2 = i + 1; + if ( c == wxT('.') ) + { + ext = loc.Right(l2-i-1); + break; + } + if ( (c == wxT('/')) || (c == wxT('\\')) || (c == wxT(':')) ) + return wxEmptyString; + } + +#if wxUSE_MIMETYPE + static bool s_MinimalMimeEnsured = false; + if (!s_MinimalMimeEnsured) + { + static const wxFileTypeInfo fallbacks[] = + { + wxFileTypeInfo(_T("image/jpeg"), + wxEmptyString, + wxEmptyString, + _T("JPEG image (from fallback)"), + _T("jpg"), _T("jpeg"), _T("JPG"), _T("JPEG"), NULL), + wxFileTypeInfo(_T("image/gif"), + wxEmptyString, + wxEmptyString, + _T("GIF image (from fallback)"), + _T("gif"), _T("GIF"), NULL), + wxFileTypeInfo(_T("image/png"), + wxEmptyString, + wxEmptyString, + _T("PNG image (from fallback)"), + _T("png"), _T("PNG"), NULL), + wxFileTypeInfo(_T("image/bmp"), + wxEmptyString, + wxEmptyString, + _T("windows bitmap image (from fallback)"), + _T("bmp"), _T("BMP"), NULL), + wxFileTypeInfo(_T("text/html"), + wxEmptyString, + wxEmptyString, + _T("HTML document (from fallback)"), + _T("htm"), _T("html"), _T("HTM"), _T("HTML"), NULL), + // must terminate the table with this! + wxFileTypeInfo() + }; + wxTheMimeTypesManager->AddFallbacks(fallbacks); + s_MinimalMimeEnsured = true; + } + + wxFileType *ft = wxTheMimeTypesManager->GetFileTypeFromExtension(ext); + if ( !ft || !ft -> GetMimeType(&mime) ) + { + mime = wxEmptyString; + } + + delete ft; + + return mime; +#else + if ( ext.IsSameAs(wxT("htm"), false) || ext.IsSameAs(_T("html"), false) ) + return wxT("text/html"); + if ( ext.IsSameAs(wxT("jpg"), false) || ext.IsSameAs(_T("jpeg"), false) ) + return wxT("image/jpeg"); + if ( ext.IsSameAs(wxT("gif"), false) ) + return wxT("image/gif"); + if ( ext.IsSameAs(wxT("png"), false) ) + return wxT("image/png"); + if ( ext.IsSameAs(wxT("bmp"), false) ) + return wxT("image/bmp"); + return wxEmptyString; +#endif +} + + + +wxString wxFileSystemHandler::GetProtocol(const wxString& location) const +{ + wxString s = wxEmptyString; + int i, l = location.length(); + bool fnd = false; + + for (i = l-1; (i >= 0) && ((location[i] != wxT('#')) || (!fnd)); i--) { + if ((location[i] == wxT(':')) && (i != 1 /*win: C:\path*/)) fnd = true; + } + if (!fnd) return wxT("file"); + for (++i; (i < l) && (location[i] != wxT(':')); i++) s << location[i]; + return s; +} + + +wxString wxFileSystemHandler::GetLeftLocation(const wxString& location) const +{ + int i; + bool fnd = false; + + for (i = location.length()-1; i >= 0; i--) { + if ((location[i] == wxT(':')) && (i != 1 /*win: C:\path*/)) fnd = true; + else if (fnd && (location[i] == wxT('#'))) return location.Left(i); + } + return wxEmptyString; +} + +wxString wxFileSystemHandler::GetRightLocation(const wxString& location) const +{ + int i, l = location.length(); + int l2 = l + 1; + + for (i = l-1; + (i >= 0) && + ((location[i] != wxT(':')) || (i == 1) || (location[i-2] == wxT(':'))); + i--) + { + if (location[i] == wxT('#')) l2 = i + 1; + } + if (i == 0) return wxEmptyString; + else return location.Mid(i + 1, l2 - i - 2); +} + +wxString wxFileSystemHandler::GetAnchor(const wxString& location) const +{ + wxChar c; + int l = location.length(); + + for (int i = l-1; i >= 0; i--) { + c = location[i]; + if (c == wxT('#')) return location.Right(l-i-1); + else if ((c == wxT('.')) || (c == wxT('/')) || (c == wxT('\\')) || (c == wxT(':'))) return wxEmptyString; + } + return wxEmptyString; +} + + +wxString wxFileSystemHandler::FindFirst(const wxString& WXUNUSED(spec), + int WXUNUSED(flags)) +{ + return wxEmptyString; +} + +wxString wxFileSystemHandler::FindNext() +{ + return wxEmptyString; +} + +//-------------------------------------------------------------------------------- +// wxLocalFSHandler +//-------------------------------------------------------------------------------- + + +wxString wxLocalFSHandler::ms_root; + +bool wxLocalFSHandler::CanOpen(const wxString& location) +{ + return GetProtocol(location) == wxT("file"); +} + +wxFSFile* wxLocalFSHandler::OpenFile(wxFileSystem& WXUNUSED(fs), const wxString& location) +{ + // location has Unix path separators + wxString right = GetRightLocation(location); + wxFileName fn = wxFileSystem::URLToFileName(right); + wxString fullpath = ms_root + fn.GetFullPath(); + + if (!wxFileExists(fullpath)) + return (wxFSFile*) NULL; + + // we need to check whether we can really read from this file, otherwise + // wxFSFile is not going to work +#if wxUSE_FFILE + wxFFileInputStream *is = new wxFFileInputStream(fullpath); +#elif wxUSE_FILE + wxFileInputStream *is = new wxFileInputStream(fullpath); +#else +#error One of wxUSE_FILE or wxUSE_FFILE must be set to 1 for wxFSHandler to work +#endif + if ( !is->Ok() ) + { + delete is; + return (wxFSFile*) NULL; + } + + return new wxFSFile(is, + right, + GetMimeTypeFromExt(location), + GetAnchor(location) +#if wxUSE_DATETIME + ,wxDateTime(wxFileModificationTime(fullpath)) +#endif // wxUSE_DATETIME + ); +} + +wxString wxLocalFSHandler::FindFirst(const wxString& spec, int flags) +{ + wxFileName fn = wxFileSystem::URLToFileName(GetRightLocation(spec)); + return wxFindFirstFile(ms_root + fn.GetFullPath(), flags); +} + +wxString wxLocalFSHandler::FindNext() +{ + return wxFindNextFile(); +} + + + +//----------------------------------------------------------------------------- +// wxFileSystem +//----------------------------------------------------------------------------- + +IMPLEMENT_DYNAMIC_CLASS(wxFileSystem, wxObject) +IMPLEMENT_ABSTRACT_CLASS(wxFSFile, wxObject) + + +wxList wxFileSystem::m_Handlers; + + +wxFileSystem::~wxFileSystem() +{ + WX_CLEAR_HASH_MAP(wxFSHandlerHash, m_LocalHandlers) +} + + +static wxString MakeCorrectPath(const wxString& path) +{ + wxString p(path); + wxString r; + int i, j, cnt; + + cnt = p.length(); + for (i = 0; i < cnt; i++) + if (p.GetChar(i) == wxT('\\')) p.GetWritableChar(i) = wxT('/'); // Want to be windows-safe + + if (p.Left(2) == wxT("./")) { p = p.Mid(2); cnt -= 2; } + + if (cnt < 3) return p; + + r << p.GetChar(0) << p.GetChar(1); + + // skip trailing ../.., if any + for (i = 2; i < cnt && (p.GetChar(i) == wxT('/') || p.GetChar(i) == wxT('.')); i++) r << p.GetChar(i); + + // remove back references: translate dir1/../dir2 to dir2 + for (; i < cnt; i++) + { + r << p.GetChar(i); + if (p.GetChar(i) == wxT('/') && p.GetChar(i-1) == wxT('.') && p.GetChar(i-2) == wxT('.')) + { + for (j = r.length() - 2; j >= 0 && r.GetChar(j) != wxT('/') && r.GetChar(j) != wxT(':'); j--) {} + if (j >= 0 && r.GetChar(j) != wxT(':')) + { + for (j = j - 1; j >= 0 && r.GetChar(j) != wxT('/') && r.GetChar(j) != wxT(':'); j--) {} + r.Remove(j + 1); + } + } + } + + for (; i < cnt; i++) r << p.GetChar(i); + + return r; +} + + +void wxFileSystem::ChangePathTo(const wxString& location, bool is_dir) +{ + int i, pathpos = -1; + + m_Path = MakeCorrectPath(location); + + if (is_dir) + { + if (m_Path.length() > 0 && m_Path.Last() != wxT('/') && m_Path.Last() != wxT(':')) + m_Path << wxT('/'); + } + + else + { + for (i = m_Path.length()-1; i >= 0; i--) + { + if (m_Path[(unsigned int) i] == wxT('/')) + { + if ((i > 1) && (m_Path[(unsigned int) (i-1)] == wxT('/')) && (m_Path[(unsigned int) (i-2)] == wxT(':'))) + { + i -= 2; + continue; + } + else + { + pathpos = i; + break; + } + } + else if (m_Path[(unsigned int) i] == wxT(':')) { + pathpos = i; + break; + } + } + if (pathpos == -1) + { + for (i = 0; i < (int) m_Path.length(); i++) + { + if (m_Path[(unsigned int) i] == wxT(':')) + { + m_Path.Remove(i+1); + break; + } + } + if (i == (int) m_Path.length()) + m_Path = wxEmptyString; + } + else + { + m_Path.Remove(pathpos+1); + } + } +} + + + +wxFileSystemHandler *wxFileSystem::MakeLocal(wxFileSystemHandler *h) +{ + wxClassInfo *classinfo = h->GetClassInfo(); + + if (classinfo->IsDynamic()) + { + wxFileSystemHandler*& local = m_LocalHandlers[classinfo]; + if (!local) + local = (wxFileSystemHandler*)classinfo->CreateObject(); + return local; + } + else + { + return h; + } +} + + + +wxFSFile* wxFileSystem::OpenFile(const wxString& location, int flags) +{ + if ((flags & wxFS_READ) == 0) + return NULL; + + wxString loc = MakeCorrectPath(location); + unsigned i, ln; + wxChar meta; + wxFSFile *s = NULL; + wxList::compatibility_iterator node; + + ln = loc.length(); + meta = 0; + for (i = 0; i < ln; i++) + { + switch (loc[i]) + { + case wxT('/') : case wxT(':') : case wxT('#') : + meta = loc[i]; + break; + } + if (meta != 0) break; + } + m_LastName = wxEmptyString; + + // try relative paths first : + if (meta != wxT(':')) + { + node = m_Handlers.GetFirst(); + while (node) + { + wxFileSystemHandler *h = (wxFileSystemHandler*) node -> GetData(); + if (h->CanOpen(m_Path + loc)) + { + s = MakeLocal(h)->OpenFile(*this, m_Path + loc); + if (s) { m_LastName = m_Path + loc; break; } + } + node = node->GetNext(); + } + } + + // if failed, try absolute paths : + if (s == NULL) + { + node = m_Handlers.GetFirst(); + while (node) + { + wxFileSystemHandler *h = (wxFileSystemHandler*) node->GetData(); + if (h->CanOpen(loc)) + { + s = MakeLocal(h)->OpenFile(*this, loc); + if (s) { m_LastName = loc; break; } + } + node = node->GetNext(); + } + } + + if (s && (flags & wxFS_SEEKABLE) != 0 && !s->GetStream()->IsSeekable()) + { + wxBackedInputStream *stream; + stream = new wxBackedInputStream(s->DetachStream()); + stream->FindLength(); + s->SetStream(stream); + } + + return (s); +} + + + +wxString wxFileSystem::FindFirst(const wxString& spec, int flags) +{ + wxList::compatibility_iterator node; + wxString spec2(spec); + + m_FindFileHandler = NULL; + + for (int i = spec2.length()-1; i >= 0; i--) + if (spec2[(unsigned int) i] == wxT('\\')) spec2.GetWritableChar(i) = wxT('/'); // Want to be windows-safe + + node = m_Handlers.GetFirst(); + while (node) + { + wxFileSystemHandler *h = (wxFileSystemHandler*) node -> GetData(); + if (h -> CanOpen(m_Path + spec2)) + { + m_FindFileHandler = MakeLocal(h); + return m_FindFileHandler -> FindFirst(m_Path + spec2, flags); + } + node = node->GetNext(); + } + + node = m_Handlers.GetFirst(); + while (node) + { + wxFileSystemHandler *h = (wxFileSystemHandler*) node -> GetData(); + if (h -> CanOpen(spec2)) + { + m_FindFileHandler = MakeLocal(h); + return m_FindFileHandler -> FindFirst(spec2, flags); + } + node = node->GetNext(); + } + + return wxEmptyString; +} + + + +wxString wxFileSystem::FindNext() +{ + if (m_FindFileHandler == NULL) return wxEmptyString; + else return m_FindFileHandler -> FindNext(); +} + +bool wxFileSystem::FindFileInPath(wxString *pStr, + const wxChar *path, + const wxChar *basename) +{ + // we assume that it's not empty + wxCHECK_MSG( !wxIsEmpty(basename), false, + _T("empty file name in wxFileSystem::FindFileInPath")); + + // skip path separator in the beginning of the file name if present + if ( wxIsPathSeparator(*basename) ) + basename++; + + wxStringTokenizer tokenizer(path, wxPATH_SEP); + while ( tokenizer.HasMoreTokens() ) + { + wxString strFile = tokenizer.GetNextToken(); + if ( !wxEndsWithPathSeparator(strFile) ) + strFile += wxFILE_SEP_PATH; + strFile += basename; + + wxFSFile *file = OpenFile(strFile); + if ( file ) + { + delete file; + *pStr = strFile; + return true; + } + } + + return false; +} + +void wxFileSystem::AddHandler(wxFileSystemHandler *handler) +{ + // prepend the handler to the beginning of the list because handlers added + // last should have the highest priority to allow overriding them + m_Handlers.Insert((size_t)0, handler); +} + +wxFileSystemHandler* wxFileSystem::RemoveHandler(wxFileSystemHandler *handler) +{ + // if handler has already been removed (or deleted) + // we return NULL. This is by design in case + // CleanUpHandlers() is called before RemoveHandler + // is called, as we cannot control the order + // which modules are unloaded + if (!m_Handlers.DeleteObject(handler)) + return NULL; + + return handler; +} + + +bool wxFileSystem::HasHandlerForPath(const wxString &location) +{ + for ( wxList::compatibility_iterator node = m_Handlers.GetFirst(); + node; node = node->GetNext() ) + { + wxFileSystemHandler *h = (wxFileSystemHandler*) node->GetData(); + if (h->CanOpen(location)) + return true; + } + + return false; +} + +void wxFileSystem::CleanUpHandlers() +{ + WX_CLEAR_LIST(wxList, m_Handlers); +} + +static const wxString g_unixPathString(wxT("/")); +static const wxString g_nativePathString(wxFILE_SEP_PATH); + +// Returns the native path for a file URL +wxFileName wxFileSystem::URLToFileName(const wxString& url) +{ + wxString path = url; + + if ( path.Find(wxT("file://")) == 0 ) + { + path = path.Mid(7); + } + else if ( path.Find(wxT("file:")) == 0 ) + { + path = path.Mid(5); + } + // Remove preceding double slash on Mac Classic +#if defined(__WXMAC__) && !defined(__UNIX__) + else if ( path.Find(wxT("//")) == 0 ) + path = path.Mid(2); +#endif + + path = wxURI::Unescape(path); + +#ifdef __WXMSW__ + // file urls either start with a forward slash (local harddisk), + // otherwise they have a servername/sharename notation, + // which only exists on msw and corresponds to a unc + if ( path[0u] == wxT('/') && path [1u] != wxT('/')) + { + path = path.Mid(1); + } + else if ( (url.Find(wxT("file://")) == 0) && + (path.Find(wxT('/')) != wxNOT_FOUND) && + (path.length() > 1) && (path[1u] != wxT(':')) ) + { + path = wxT("//") + path; + } +#endif + + path.Replace(g_unixPathString, g_nativePathString); + + return wxFileName(path, wxPATH_NATIVE); +} + +// Returns the file URL for a native path +wxString wxFileSystem::FileNameToURL(const wxFileName& filename) +{ + wxFileName fn = filename; + fn.Normalize(wxPATH_NORM_DOTS | wxPATH_NORM_TILDE | wxPATH_NORM_ABSOLUTE); + wxString url = fn.GetFullPath(wxPATH_NATIVE); + +#ifndef __UNIX__ + // unc notation, wxMSW + if ( url.Find(wxT("\\\\")) == 0 ) + { + url = wxT("//") + url.Mid(2); + } + else + { + url = wxT("/") + url; +#ifdef __WXMAC__ + url = wxT("/") + url; +#endif + + } +#endif + + url.Replace(g_nativePathString, g_unixPathString); + url.Replace(wxT("%"), wxT("%25")); // '%'s must be replaced first! + url.Replace(wxT("#"), wxT("%23")); + url.Replace(wxT(":"), wxT("%3A")); + url = wxT("file:") + url; + return url; +} + + +///// Module: + +class wxFileSystemModule : public wxModule +{ + DECLARE_DYNAMIC_CLASS(wxFileSystemModule) + + public: + wxFileSystemModule() : + wxModule(), + m_handler(NULL) + { + } + + virtual bool OnInit() + { + m_handler = new wxLocalFSHandler; + wxFileSystem::AddHandler(m_handler); + return true; + } + virtual void OnExit() + { + delete wxFileSystem::RemoveHandler(m_handler); + + wxFileSystem::CleanUpHandlers(); + } + + private: + wxFileSystemHandler* m_handler; + +}; + +IMPLEMENT_DYNAMIC_CLASS(wxFileSystemModule, wxModule) + +#endif + // wxUSE_FILESYSTEM diff --git a/Externals/wxWidgets/src/common/filtall.cpp b/Externals/wxWidgets/src/common/filtall.cpp index 69f595e450..952730f82b 100644 --- a/Externals/wxWidgets/src/common/filtall.cpp +++ b/Externals/wxWidgets/src/common/filtall.cpp @@ -1,36 +1,36 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/filtall.cpp -// Purpose: Link all filter streams -// Author: Mike Wetherell -// RCS-ID: $Id: filtall.cpp 42412 2006-10-25 20:41:12Z MW $ -// Copyright: (c) 2006 Mike Wetherell -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_STREAMS - -#if wxUSE_ZLIB -#include "wx/zstream.h" -#endif - -// Reference filter classes to ensure they are linked into a statically -// linked program that uses Find or GetFirst to look for an filter handler. -// It is in its own file so that the user can override this behaviour by -// providing their own implementation. - -void wxUseFilterClasses() -{ -#if wxUSE_ZLIB - wxZlibClassFactory(); - wxGzipClassFactory(); -#endif -} - -#endif // wxUSE_STREAMS +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/filtall.cpp +// Purpose: Link all filter streams +// Author: Mike Wetherell +// RCS-ID: $Id: filtall.cpp 42412 2006-10-25 20:41:12Z MW $ +// Copyright: (c) 2006 Mike Wetherell +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_STREAMS + +#if wxUSE_ZLIB +#include "wx/zstream.h" +#endif + +// Reference filter classes to ensure they are linked into a statically +// linked program that uses Find or GetFirst to look for an filter handler. +// It is in its own file so that the user can override this behaviour by +// providing their own implementation. + +void wxUseFilterClasses() +{ +#if wxUSE_ZLIB + wxZlibClassFactory(); + wxGzipClassFactory(); +#endif +} + +#endif // wxUSE_STREAMS diff --git a/Externals/wxWidgets/src/common/filtfind.cpp b/Externals/wxWidgets/src/common/filtfind.cpp index 7da889a768..16cb227f3b 100644 --- a/Externals/wxWidgets/src/common/filtfind.cpp +++ b/Externals/wxWidgets/src/common/filtfind.cpp @@ -1,43 +1,43 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/filtfind.cpp -// Purpose: Streams for filter formats -// Author: Mike Wetherell -// RCS-ID: $Id: filtfind.cpp 42412 2006-10-25 20:41:12Z MW $ -// Copyright: (c) Mike Wetherell -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_STREAMS - -#include "wx/stream.h" - -// These functions are in a separate file so that statically linked apps -// that do not call them to search for filter handlers will only link in -// the filter classes they use. - -const wxFilterClassFactory * -wxFilterClassFactory::Find(const wxChar *protocol, wxStreamProtocolType type) -{ - for (const wxFilterClassFactory *f = GetFirst(); f; f = f->GetNext()) - if (f->CanHandle(protocol, type)) - return f; - - return NULL; -} - -// static -const wxFilterClassFactory *wxFilterClassFactory::GetFirst() -{ - if (!sm_first) - wxUseFilterClasses(); - return sm_first; -} - -#endif // wxUSE_STREAMS +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/filtfind.cpp +// Purpose: Streams for filter formats +// Author: Mike Wetherell +// RCS-ID: $Id: filtfind.cpp 42412 2006-10-25 20:41:12Z MW $ +// Copyright: (c) Mike Wetherell +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_STREAMS + +#include "wx/stream.h" + +// These functions are in a separate file so that statically linked apps +// that do not call them to search for filter handlers will only link in +// the filter classes they use. + +const wxFilterClassFactory * +wxFilterClassFactory::Find(const wxChar *protocol, wxStreamProtocolType type) +{ + for (const wxFilterClassFactory *f = GetFirst(); f; f = f->GetNext()) + if (f->CanHandle(protocol, type)) + return f; + + return NULL; +} + +// static +const wxFilterClassFactory *wxFilterClassFactory::GetFirst() +{ + if (!sm_first) + wxUseFilterClasses(); + return sm_first; +} + +#endif // wxUSE_STREAMS diff --git a/Externals/wxWidgets/src/common/fldlgcmn.cpp b/Externals/wxWidgets/src/common/fldlgcmn.cpp index e949d68fe8..d8ee0e40e9 100644 --- a/Externals/wxWidgets/src/common/fldlgcmn.cpp +++ b/Externals/wxWidgets/src/common/fldlgcmn.cpp @@ -1,348 +1,348 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/fldlgcmn.cpp -// Purpose: wxFileDialog common functions -// Author: John Labenski -// Modified by: -// Created: 14.06.03 (extracted from src/*/filedlg.cpp) -// RCS-ID: $Id: fldlgcmn.cpp 47482 2007-07-15 14:12:08Z VS $ -// Copyright: (c) Robert Roebling -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -#ifdef __BORLANDC__ -#pragma hdrstop -#endif - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#if wxUSE_FILEDLG - -#include "wx/filedlg.h" -#include "wx/dirdlg.h" - -#ifndef WX_PRECOMP - #include "wx/string.h" - #include "wx/intl.h" - #include "wx/window.h" -#endif // WX_PRECOMP - -//---------------------------------------------------------------------------- -// wxFileDialogBase -//---------------------------------------------------------------------------- - -IMPLEMENT_DYNAMIC_CLASS(wxFileDialogBase, wxDialog) - -void wxFileDialogBase::Init() -{ - m_filterIndex = - m_windowStyle = 0; -} - -bool wxFileDialogBase::Create(wxWindow *parent, - const wxString& message, - const wxString& defaultDir, - const wxString& defaultFile, - const wxString& wildCard, - long style, - const wxPoint& WXUNUSED(pos), - const wxSize& WXUNUSED(sz), - const wxString& WXUNUSED(name)) -{ - m_message = message; - m_dir = defaultDir; - m_fileName = defaultFile; - m_wildCard = wildCard; - - m_parent = parent; - m_windowStyle = style; - m_filterIndex = 0; - - if (!HasFdFlag(wxFD_OPEN) && !HasFdFlag(wxFD_SAVE)) - m_windowStyle |= wxFD_OPEN; // wxFD_OPEN is the default - - // check that the styles are not contradictory - wxASSERT_MSG( !(HasFdFlag(wxFD_SAVE) && HasFdFlag(wxFD_OPEN)), - _T("can't specify both wxFD_SAVE and wxFD_OPEN at once") ); - - wxASSERT_MSG( !HasFdFlag(wxFD_SAVE) || - (!HasFdFlag(wxFD_MULTIPLE) && !HasFdFlag(wxFD_FILE_MUST_EXIST)), - _T("wxFD_MULTIPLE or wxFD_FILE_MUST_EXIST can't be used with wxFD_SAVE" ) ); - - wxASSERT_MSG( !HasFdFlag(wxFD_OPEN) || !HasFdFlag(wxFD_OVERWRITE_PROMPT), - _T("wxFD_OVERWRITE_PROMPT can't be used with wxFD_OPEN") ); - - if ( wildCard.empty() || wildCard == wxFileSelectorDefaultWildcardStr ) - { - m_wildCard = wxString::Format(_("All files (%s)|%s"), - wxFileSelectorDefaultWildcardStr, - wxFileSelectorDefaultWildcardStr); - } - else // have wild card - { - // convert m_wildCard from "*.bar" to "bar files (*.bar)|*.bar" - if ( m_wildCard.Find(wxT('|')) == wxNOT_FOUND ) - { - wxString::size_type nDot = m_wildCard.find(_T("*.")); - if ( nDot != wxString::npos ) - nDot++; - else - nDot = 0; - - m_wildCard = wxString::Format - ( - _("%s files (%s)|%s"), - wildCard.c_str() + nDot, - wildCard.c_str(), - wildCard.c_str() - ); - } - } - - return true; -} - -#if WXWIN_COMPATIBILITY_2_4 -// Parses the filterStr, returning the number of filters. -// Returns 0 if none or if there's a problem. -// filterStr is in the form: "All files (*.*)|*.*|JPEG Files (*.jpeg)|*.jpg" -int wxFileDialogBase::ParseWildcard(const wxString& filterStr, - wxArrayString& descriptions, - wxArrayString& filters) -{ - return ::wxParseCommonDialogsFilter(filterStr, descriptions, filters); -} -#endif // WXWIN_COMPATIBILITY_2_4 - -#if WXWIN_COMPATIBILITY_2_6 -long wxFileDialogBase::GetStyle() const -{ - return GetWindowStyle(); -} - -void wxFileDialogBase::SetStyle(long style) -{ - SetWindowStyle(style); -} -#endif // WXWIN_COMPATIBILITY_2_6 - - -wxString wxFileDialogBase::AppendExtension(const wxString &filePath, - const wxString &extensionList) -{ - // strip off path, to avoid problems with "path.bar/foo" - wxString fileName = filePath.AfterLast(wxFILE_SEP_PATH); - - // if fileName is of form "foo.bar" it's ok, return it - int idx_dot = fileName.Find(wxT('.'), true); - if ((idx_dot != wxNOT_FOUND) && (idx_dot < (int)fileName.length() - 1)) - return filePath; - - // get the first extension from extensionList, or all of it - wxString ext = extensionList.BeforeFirst(wxT(';')); - - // if ext == "foo" or "foo." there's no extension - int idx_ext_dot = ext.Find(wxT('.'), true); - if ((idx_ext_dot == wxNOT_FOUND) || (idx_ext_dot == (int)ext.length() - 1)) - return filePath; - else - ext = ext.AfterLast(wxT('.')); - - // if ext == "*" or "bar*" or "b?r" or " " then its not valid - if ((ext.Find(wxT('*')) != wxNOT_FOUND) || - (ext.Find(wxT('?')) != wxNOT_FOUND) || - (ext.Strip(wxString::both).empty())) - return filePath; - - // if fileName doesn't have a '.' then add one - if (filePath.Last() != wxT('.')) - ext = wxT(".") + ext; - - return filePath + ext; -} - -//---------------------------------------------------------------------------- -// wxFileDialog convenience functions -//---------------------------------------------------------------------------- - -wxString wxFileSelector(const wxChar *title, - const wxChar *defaultDir, - const wxChar *defaultFileName, - const wxChar *defaultExtension, - const wxChar *filter, - int flags, - wxWindow *parent, - int x, int y) -{ - // The defaultExtension, if non-NULL, is - // appended to the filename if the user fails to type an extension. The new - // implementation (taken from wxFileSelectorEx) appends the extension - // automatically, by looking at the filter specification. In fact this - // should be better than the native Microsoft implementation because - // Windows only allows *one* default extension, whereas here we do the - // right thing depending on the filter the user has chosen. - - // If there's a default extension specified but no filter, we create a - // suitable filter. - - wxString filter2; - if ( !wxIsEmpty(defaultExtension) && wxIsEmpty(filter) ) - filter2 = wxString(wxT("*.")) + defaultExtension; - else if ( !wxIsEmpty(filter) ) - filter2 = filter; - - wxString defaultDirString; - if (!wxIsEmpty(defaultDir)) - defaultDirString = defaultDir; - - wxString defaultFilenameString; - if (!wxIsEmpty(defaultFileName)) - defaultFilenameString = defaultFileName; - - wxFileDialog fileDialog(parent, title, defaultDirString, - defaultFilenameString, filter2, - flags, wxPoint(x, y)); - - // if filter is of form "All files (*)|*|..." set correct filter index - if((wxStrlen(defaultExtension) != 0) && (filter2.Find(wxT('|')) != wxNOT_FOUND)) - { - int filterIndex = 0; - - wxArrayString descriptions, filters; - // don't care about errors, handled already by wxFileDialog - (void)wxParseCommonDialogsFilter(filter2, descriptions, filters); - for (size_t n=0; n 0) - fileDialog.SetFilterIndex(filterIndex); - } - - wxString filename; - if ( fileDialog.ShowModal() == wxID_OK ) - { - filename = fileDialog.GetPath(); - } - - return filename; -} - -//---------------------------------------------------------------------------- -// wxFileSelectorEx -//---------------------------------------------------------------------------- - -wxString wxFileSelectorEx(const wxChar *title, - const wxChar *defaultDir, - const wxChar *defaultFileName, - int* defaultFilterIndex, - const wxChar *filter, - int flags, - wxWindow* parent, - int x, - int y) - -{ - wxFileDialog fileDialog(parent, - !wxIsEmpty(title) ? title : wxEmptyString, - !wxIsEmpty(defaultDir) ? defaultDir : wxEmptyString, - !wxIsEmpty(defaultFileName) ? defaultFileName : wxEmptyString, - !wxIsEmpty(filter) ? filter : wxEmptyString, - flags, wxPoint(x, y)); - - wxString filename; - if ( fileDialog.ShowModal() == wxID_OK ) - { - if ( defaultFilterIndex ) - *defaultFilterIndex = fileDialog.GetFilterIndex(); - - filename = fileDialog.GetPath(); - } - - return filename; -} - -//---------------------------------------------------------------------------- -// wxDefaultFileSelector - Generic load/save dialog (for internal use only) -//---------------------------------------------------------------------------- - -static wxString wxDefaultFileSelector(bool load, - const wxChar *what, - const wxChar *extension, - const wxChar *default_name, - wxWindow *parent) -{ - wxString prompt; - wxString str; - if (load) - str = _("Load %s file"); - else - str = _("Save %s file"); - prompt.Printf(str, what); - - wxString wild; - const wxChar *ext = extension; - if ( !wxIsEmpty(ext) ) - { - if ( *ext == wxT('.') ) - ext++; - - wild.Printf(wxT("*.%s"), ext); - } - else // no extension specified - { - wild = wxFileSelectorDefaultWildcardStr; - } - - return wxFileSelector(prompt, NULL, default_name, ext, wild, - load ? wxFD_OPEN : wxFD_SAVE, parent); -} - -//---------------------------------------------------------------------------- -// wxLoadFileSelector -//---------------------------------------------------------------------------- - -WXDLLEXPORT wxString wxLoadFileSelector(const wxChar *what, - const wxChar *extension, - const wxChar *default_name, - wxWindow *parent) -{ - return wxDefaultFileSelector(true, what, extension, default_name, parent); -} - -//---------------------------------------------------------------------------- -// wxSaveFileSelector -//---------------------------------------------------------------------------- - -WXDLLEXPORT wxString wxSaveFileSelector(const wxChar *what, - const wxChar *extension, - const wxChar *default_name, - wxWindow *parent) -{ - return wxDefaultFileSelector(false, what, extension, default_name, parent); -} - - -//---------------------------------------------------------------------------- -// wxDirDialogBase -//---------------------------------------------------------------------------- - -#if WXWIN_COMPATIBILITY_2_6 -long wxDirDialogBase::GetStyle() const -{ - return GetWindowStyle(); -} - -void wxDirDialogBase::SetStyle(long style) -{ - SetWindowStyle(style); -} -#endif // WXWIN_COMPATIBILITY_2_6 - - -#endif // wxUSE_FILEDLG +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/fldlgcmn.cpp +// Purpose: wxFileDialog common functions +// Author: John Labenski +// Modified by: +// Created: 14.06.03 (extracted from src/*/filedlg.cpp) +// RCS-ID: $Id: fldlgcmn.cpp 47482 2007-07-15 14:12:08Z VS $ +// Copyright: (c) Robert Roebling +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifdef __BORLANDC__ +#pragma hdrstop +#endif + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#if wxUSE_FILEDLG + +#include "wx/filedlg.h" +#include "wx/dirdlg.h" + +#ifndef WX_PRECOMP + #include "wx/string.h" + #include "wx/intl.h" + #include "wx/window.h" +#endif // WX_PRECOMP + +//---------------------------------------------------------------------------- +// wxFileDialogBase +//---------------------------------------------------------------------------- + +IMPLEMENT_DYNAMIC_CLASS(wxFileDialogBase, wxDialog) + +void wxFileDialogBase::Init() +{ + m_filterIndex = + m_windowStyle = 0; +} + +bool wxFileDialogBase::Create(wxWindow *parent, + const wxString& message, + const wxString& defaultDir, + const wxString& defaultFile, + const wxString& wildCard, + long style, + const wxPoint& WXUNUSED(pos), + const wxSize& WXUNUSED(sz), + const wxString& WXUNUSED(name)) +{ + m_message = message; + m_dir = defaultDir; + m_fileName = defaultFile; + m_wildCard = wildCard; + + m_parent = parent; + m_windowStyle = style; + m_filterIndex = 0; + + if (!HasFdFlag(wxFD_OPEN) && !HasFdFlag(wxFD_SAVE)) + m_windowStyle |= wxFD_OPEN; // wxFD_OPEN is the default + + // check that the styles are not contradictory + wxASSERT_MSG( !(HasFdFlag(wxFD_SAVE) && HasFdFlag(wxFD_OPEN)), + _T("can't specify both wxFD_SAVE and wxFD_OPEN at once") ); + + wxASSERT_MSG( !HasFdFlag(wxFD_SAVE) || + (!HasFdFlag(wxFD_MULTIPLE) && !HasFdFlag(wxFD_FILE_MUST_EXIST)), + _T("wxFD_MULTIPLE or wxFD_FILE_MUST_EXIST can't be used with wxFD_SAVE" ) ); + + wxASSERT_MSG( !HasFdFlag(wxFD_OPEN) || !HasFdFlag(wxFD_OVERWRITE_PROMPT), + _T("wxFD_OVERWRITE_PROMPT can't be used with wxFD_OPEN") ); + + if ( wildCard.empty() || wildCard == wxFileSelectorDefaultWildcardStr ) + { + m_wildCard = wxString::Format(_("All files (%s)|%s"), + wxFileSelectorDefaultWildcardStr, + wxFileSelectorDefaultWildcardStr); + } + else // have wild card + { + // convert m_wildCard from "*.bar" to "bar files (*.bar)|*.bar" + if ( m_wildCard.Find(wxT('|')) == wxNOT_FOUND ) + { + wxString::size_type nDot = m_wildCard.find(_T("*.")); + if ( nDot != wxString::npos ) + nDot++; + else + nDot = 0; + + m_wildCard = wxString::Format + ( + _("%s files (%s)|%s"), + wildCard.c_str() + nDot, + wildCard.c_str(), + wildCard.c_str() + ); + } + } + + return true; +} + +#if WXWIN_COMPATIBILITY_2_4 +// Parses the filterStr, returning the number of filters. +// Returns 0 if none or if there's a problem. +// filterStr is in the form: "All files (*.*)|*.*|JPEG Files (*.jpeg)|*.jpg" +int wxFileDialogBase::ParseWildcard(const wxString& filterStr, + wxArrayString& descriptions, + wxArrayString& filters) +{ + return ::wxParseCommonDialogsFilter(filterStr, descriptions, filters); +} +#endif // WXWIN_COMPATIBILITY_2_4 + +#if WXWIN_COMPATIBILITY_2_6 +long wxFileDialogBase::GetStyle() const +{ + return GetWindowStyle(); +} + +void wxFileDialogBase::SetStyle(long style) +{ + SetWindowStyle(style); +} +#endif // WXWIN_COMPATIBILITY_2_6 + + +wxString wxFileDialogBase::AppendExtension(const wxString &filePath, + const wxString &extensionList) +{ + // strip off path, to avoid problems with "path.bar/foo" + wxString fileName = filePath.AfterLast(wxFILE_SEP_PATH); + + // if fileName is of form "foo.bar" it's ok, return it + int idx_dot = fileName.Find(wxT('.'), true); + if ((idx_dot != wxNOT_FOUND) && (idx_dot < (int)fileName.length() - 1)) + return filePath; + + // get the first extension from extensionList, or all of it + wxString ext = extensionList.BeforeFirst(wxT(';')); + + // if ext == "foo" or "foo." there's no extension + int idx_ext_dot = ext.Find(wxT('.'), true); + if ((idx_ext_dot == wxNOT_FOUND) || (idx_ext_dot == (int)ext.length() - 1)) + return filePath; + else + ext = ext.AfterLast(wxT('.')); + + // if ext == "*" or "bar*" or "b?r" or " " then its not valid + if ((ext.Find(wxT('*')) != wxNOT_FOUND) || + (ext.Find(wxT('?')) != wxNOT_FOUND) || + (ext.Strip(wxString::both).empty())) + return filePath; + + // if fileName doesn't have a '.' then add one + if (filePath.Last() != wxT('.')) + ext = wxT(".") + ext; + + return filePath + ext; +} + +//---------------------------------------------------------------------------- +// wxFileDialog convenience functions +//---------------------------------------------------------------------------- + +wxString wxFileSelector(const wxChar *title, + const wxChar *defaultDir, + const wxChar *defaultFileName, + const wxChar *defaultExtension, + const wxChar *filter, + int flags, + wxWindow *parent, + int x, int y) +{ + // The defaultExtension, if non-NULL, is + // appended to the filename if the user fails to type an extension. The new + // implementation (taken from wxFileSelectorEx) appends the extension + // automatically, by looking at the filter specification. In fact this + // should be better than the native Microsoft implementation because + // Windows only allows *one* default extension, whereas here we do the + // right thing depending on the filter the user has chosen. + + // If there's a default extension specified but no filter, we create a + // suitable filter. + + wxString filter2; + if ( !wxIsEmpty(defaultExtension) && wxIsEmpty(filter) ) + filter2 = wxString(wxT("*.")) + defaultExtension; + else if ( !wxIsEmpty(filter) ) + filter2 = filter; + + wxString defaultDirString; + if (!wxIsEmpty(defaultDir)) + defaultDirString = defaultDir; + + wxString defaultFilenameString; + if (!wxIsEmpty(defaultFileName)) + defaultFilenameString = defaultFileName; + + wxFileDialog fileDialog(parent, title, defaultDirString, + defaultFilenameString, filter2, + flags, wxPoint(x, y)); + + // if filter is of form "All files (*)|*|..." set correct filter index + if((wxStrlen(defaultExtension) != 0) && (filter2.Find(wxT('|')) != wxNOT_FOUND)) + { + int filterIndex = 0; + + wxArrayString descriptions, filters; + // don't care about errors, handled already by wxFileDialog + (void)wxParseCommonDialogsFilter(filter2, descriptions, filters); + for (size_t n=0; n 0) + fileDialog.SetFilterIndex(filterIndex); + } + + wxString filename; + if ( fileDialog.ShowModal() == wxID_OK ) + { + filename = fileDialog.GetPath(); + } + + return filename; +} + +//---------------------------------------------------------------------------- +// wxFileSelectorEx +//---------------------------------------------------------------------------- + +wxString wxFileSelectorEx(const wxChar *title, + const wxChar *defaultDir, + const wxChar *defaultFileName, + int* defaultFilterIndex, + const wxChar *filter, + int flags, + wxWindow* parent, + int x, + int y) + +{ + wxFileDialog fileDialog(parent, + !wxIsEmpty(title) ? title : wxEmptyString, + !wxIsEmpty(defaultDir) ? defaultDir : wxEmptyString, + !wxIsEmpty(defaultFileName) ? defaultFileName : wxEmptyString, + !wxIsEmpty(filter) ? filter : wxEmptyString, + flags, wxPoint(x, y)); + + wxString filename; + if ( fileDialog.ShowModal() == wxID_OK ) + { + if ( defaultFilterIndex ) + *defaultFilterIndex = fileDialog.GetFilterIndex(); + + filename = fileDialog.GetPath(); + } + + return filename; +} + +//---------------------------------------------------------------------------- +// wxDefaultFileSelector - Generic load/save dialog (for internal use only) +//---------------------------------------------------------------------------- + +static wxString wxDefaultFileSelector(bool load, + const wxChar *what, + const wxChar *extension, + const wxChar *default_name, + wxWindow *parent) +{ + wxString prompt; + wxString str; + if (load) + str = _("Load %s file"); + else + str = _("Save %s file"); + prompt.Printf(str, what); + + wxString wild; + const wxChar *ext = extension; + if ( !wxIsEmpty(ext) ) + { + if ( *ext == wxT('.') ) + ext++; + + wild.Printf(wxT("*.%s"), ext); + } + else // no extension specified + { + wild = wxFileSelectorDefaultWildcardStr; + } + + return wxFileSelector(prompt, NULL, default_name, ext, wild, + load ? wxFD_OPEN : wxFD_SAVE, parent); +} + +//---------------------------------------------------------------------------- +// wxLoadFileSelector +//---------------------------------------------------------------------------- + +WXDLLEXPORT wxString wxLoadFileSelector(const wxChar *what, + const wxChar *extension, + const wxChar *default_name, + wxWindow *parent) +{ + return wxDefaultFileSelector(true, what, extension, default_name, parent); +} + +//---------------------------------------------------------------------------- +// wxSaveFileSelector +//---------------------------------------------------------------------------- + +WXDLLEXPORT wxString wxSaveFileSelector(const wxChar *what, + const wxChar *extension, + const wxChar *default_name, + wxWindow *parent) +{ + return wxDefaultFileSelector(false, what, extension, default_name, parent); +} + + +//---------------------------------------------------------------------------- +// wxDirDialogBase +//---------------------------------------------------------------------------- + +#if WXWIN_COMPATIBILITY_2_6 +long wxDirDialogBase::GetStyle() const +{ + return GetWindowStyle(); +} + +void wxDirDialogBase::SetStyle(long style) +{ + SetWindowStyle(style); +} +#endif // WXWIN_COMPATIBILITY_2_6 + + +#endif // wxUSE_FILEDLG diff --git a/Externals/wxWidgets/src/common/fmapbase.cpp b/Externals/wxWidgets/src/common/fmapbase.cpp index 1650132780..d273922c1b 100644 --- a/Externals/wxWidgets/src/common/fmapbase.cpp +++ b/Externals/wxWidgets/src/common/fmapbase.cpp @@ -1,737 +1,737 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: src/common/fmapbase.cpp -// Purpose: wxFontMapperBase class implementation -// Author: Vadim Zeitlin -// Modified by: -// Created: 21.06.2003 (extracted from common/fontmap.cpp) -// RCS-ID: $Id: fmapbase.cpp 43063 2006-11-04 20:48:04Z VZ $ -// Copyright: (c) 1999-2003 Vadim Zeitlin -// License: wxWindows license -/////////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// for compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_FONTMAP - -#ifndef WX_PRECOMP - #include "wx/app.h" - #include "wx/log.h" - #include "wx/intl.h" - #include "wx/module.h" -#endif //WX_PRECOMP - -#if defined(__WXMSW__) - #include "wx/msw/private.h" // includes windows.h for LOGFONT - #include "wx/msw/winundef.h" -#endif - -#include "wx/fontmap.h" -#include "wx/fmappriv.h" - -#include "wx/apptrait.h" - -// wxMemoryConfig uses wxFileConfig -#if wxUSE_CONFIG && wxUSE_FILECONFIG - #include "wx/config.h" - #include "wx/memconf.h" -#endif - -// ---------------------------------------------------------------------------- -// constants -// ---------------------------------------------------------------------------- - -// encodings supported by GetEncodingDescription -static wxFontEncoding gs_encodings[] = -{ - wxFONTENCODING_ISO8859_1, - wxFONTENCODING_ISO8859_2, - wxFONTENCODING_ISO8859_3, - wxFONTENCODING_ISO8859_4, - wxFONTENCODING_ISO8859_5, - wxFONTENCODING_ISO8859_6, - wxFONTENCODING_ISO8859_7, - wxFONTENCODING_ISO8859_8, - wxFONTENCODING_ISO8859_9, - wxFONTENCODING_ISO8859_10, - wxFONTENCODING_ISO8859_11, - wxFONTENCODING_ISO8859_12, - wxFONTENCODING_ISO8859_13, - wxFONTENCODING_ISO8859_14, - wxFONTENCODING_ISO8859_15, - wxFONTENCODING_KOI8, - wxFONTENCODING_KOI8_U, - wxFONTENCODING_CP874, - wxFONTENCODING_CP932, - wxFONTENCODING_CP936, - wxFONTENCODING_CP949, - wxFONTENCODING_CP950, - wxFONTENCODING_CP1250, - wxFONTENCODING_CP1251, - wxFONTENCODING_CP1252, - wxFONTENCODING_CP1253, - wxFONTENCODING_CP1254, - wxFONTENCODING_CP1255, - wxFONTENCODING_CP1256, - wxFONTENCODING_CP1257, - wxFONTENCODING_CP437, - wxFONTENCODING_UTF7, - wxFONTENCODING_UTF8, - wxFONTENCODING_UTF16BE, - wxFONTENCODING_UTF16LE, - wxFONTENCODING_UTF32BE, - wxFONTENCODING_UTF32LE, - wxFONTENCODING_EUC_JP, - wxFONTENCODING_DEFAULT, - wxFONTENCODING_BIG5, - wxFONTENCODING_SHIFT_JIS, - wxFONTENCODING_GB2312, -}; - -// the descriptions for them -static const wxChar* gs_encodingDescs[] = -{ - wxTRANSLATE( "Western European (ISO-8859-1)" ), - wxTRANSLATE( "Central European (ISO-8859-2)" ), - wxTRANSLATE( "Esperanto (ISO-8859-3)" ), - wxTRANSLATE( "Baltic (old) (ISO-8859-4)" ), - wxTRANSLATE( "Cyrillic (ISO-8859-5)" ), - wxTRANSLATE( "Arabic (ISO-8859-6)" ), - wxTRANSLATE( "Greek (ISO-8859-7)" ), - wxTRANSLATE( "Hebrew (ISO-8859-8)" ), - wxTRANSLATE( "Turkish (ISO-8859-9)" ), - wxTRANSLATE( "Nordic (ISO-8859-10)" ), - wxTRANSLATE( "Thai (ISO-8859-11)" ), - wxTRANSLATE( "Indian (ISO-8859-12)" ), - wxTRANSLATE( "Baltic (ISO-8859-13)" ), - wxTRANSLATE( "Celtic (ISO-8859-14)" ), - wxTRANSLATE( "Western European with Euro (ISO-8859-15)" ), - wxTRANSLATE( "KOI8-R" ), - wxTRANSLATE( "KOI8-U" ), - wxTRANSLATE( "Windows Thai (CP 874)" ), - wxTRANSLATE( "Windows Japanese (CP 932)" ), - wxTRANSLATE( "Windows Chinese Simplified (CP 936)" ), - wxTRANSLATE( "Windows Korean (CP 949)" ), - wxTRANSLATE( "Windows Chinese Traditional (CP 950)" ), - wxTRANSLATE( "Windows Central European (CP 1250)" ), - wxTRANSLATE( "Windows Cyrillic (CP 1251)" ), - wxTRANSLATE( "Windows Western European (CP 1252)" ), - wxTRANSLATE( "Windows Greek (CP 1253)" ), - wxTRANSLATE( "Windows Turkish (CP 1254)" ), - wxTRANSLATE( "Windows Hebrew (CP 1255)" ), - wxTRANSLATE( "Windows Arabic (CP 1256)" ), - wxTRANSLATE( "Windows Baltic (CP 1257)" ), - wxTRANSLATE( "Windows/DOS OEM (CP 437)" ), - wxTRANSLATE( "Unicode 7 bit (UTF-7)" ), - wxTRANSLATE( "Unicode 8 bit (UTF-8)" ), -#ifdef WORDS_BIGENDIAN - wxTRANSLATE( "Unicode 16 bit (UTF-16)" ), - wxTRANSLATE( "Unicode 16 bit Little Endian (UTF-16LE)" ), - wxTRANSLATE( "Unicode 32 bit (UTF-32)" ), - wxTRANSLATE( "Unicode 32 bit Little Endian (UTF-32LE)" ), -#else // WORDS_BIGENDIAN - wxTRANSLATE( "Unicode 16 bit Big Endian (UTF-16BE)" ), - wxTRANSLATE( "Unicode 16 bit (UTF-16)" ), - wxTRANSLATE( "Unicode 32 bit Big Endian (UTF-32BE)" ), - wxTRANSLATE( "Unicode 32 bit (UTF-32)" ), -#endif // WORDS_BIGENDIAN - wxTRANSLATE( "Extended Unix Codepage for Japanese (EUC-JP)" ), - wxTRANSLATE( "US-ASCII" ), - wxTRANSLATE( "BIG5" ), - wxTRANSLATE( "SHIFT-JIS" ), - wxTRANSLATE( "GB-2312" ), -}; - -// and the internal names (these are not translated on purpose!) -static const wxChar* gs_encodingNames[WXSIZEOF(gs_encodingDescs)][9] = -{ - // names from the columns correspond to these OS: - // Linux Solaris and IRIX HP-UX AIX - { _T("ISO-8859-1"), _T("ISO8859-1"), _T("iso88591"), _T("8859-1"), wxT("iso_8859_1"), NULL }, - { _T("ISO-8859-2"), _T("ISO8859-2"), _T("iso88592"), _T("8859-2"), NULL }, - { _T("ISO-8859-3"), _T("ISO8859-3"), _T("iso88593"), _T("8859-3"), NULL }, - { _T("ISO-8859-4"), _T("ISO8859-4"), _T("iso88594"), _T("8859-4"), NULL }, - { _T("ISO-8859-5"), _T("ISO8859-5"), _T("iso88595"), _T("8859-5"), NULL }, - { _T("ISO-8859-6"), _T("ISO8859-6"), _T("iso88596"), _T("8859-6"), NULL }, - { _T("ISO-8859-7"), _T("ISO8859-7"), _T("iso88597"), _T("8859-7"), NULL }, - { _T("ISO-8859-8"), _T("ISO8859-8"), _T("iso88598"), _T("8859-8"), NULL }, - { _T("ISO-8859-9"), _T("ISO8859-9"), _T("iso88599"), _T("8859-9"), NULL }, - { _T("ISO-8859-10"), _T("ISO8859-10"), _T("iso885910"), _T("8859-10"), NULL }, - { _T("ISO-8859-11"), _T("ISO8859-11"), _T("iso885911"), _T("8859-11"), NULL }, - { _T("ISO-8859-12"), _T("ISO8859-12"), _T("iso885912"), _T("8859-12"), NULL }, - { _T("ISO-8859-13"), _T("ISO8859-13"), _T("iso885913"), _T("8859-13"), NULL }, - { _T("ISO-8859-14"), _T("ISO8859-14"), _T("iso885914"), _T("8859-14"), NULL }, - { _T("ISO-8859-15"), _T("ISO8859-15"), _T("iso885915"), _T("8859-15"), NULL }, - - // although koi8-ru is not strictly speaking the same as koi8-r, - // they are similar enough to make mapping it to koi8 better than - // not recognizing it at all - { wxT( "KOI8-R" ), wxT( "KOI8-RU" ), NULL }, - { wxT( "KOI8-U" ), NULL }, - - { wxT( "WINDOWS-874" ), wxT( "CP-874" ), NULL }, - { wxT( "WINDOWS-932" ), wxT( "CP-932" ), NULL }, - { wxT( "WINDOWS-936" ), wxT( "CP-936" ), NULL }, - { wxT( "WINDOWS-949" ), wxT( "CP-949" ), wxT( "EUC-KR" ), wxT( "eucKR" ), wxT( "euc_kr" ), NULL }, - { wxT( "WINDOWS-950" ), wxT( "CP-950" ), NULL }, - { wxT( "WINDOWS-1250" ),wxT( "CP-1250" ), NULL }, - { wxT( "WINDOWS-1251" ),wxT( "CP-1251" ), NULL }, - { wxT( "WINDOWS-1252" ),wxT( "CP-1252" ), wxT("IBM-1252"), NULL }, - { wxT( "WINDOWS-1253" ),wxT( "CP-1253" ), NULL }, - { wxT( "WINDOWS-1254" ),wxT( "CP-1254" ), NULL }, - { wxT( "WINDOWS-1255" ),wxT( "CP-1255" ), NULL }, - { wxT( "WINDOWS-1256" ),wxT( "CP-1256" ), NULL }, - { wxT( "WINDOWS-1257" ),wxT( "CP-1257" ), NULL }, - { wxT( "WINDOWS-437" ), wxT( "CP-437" ), NULL }, - - { wxT( "UTF-7" ), wxT("utf7"), NULL }, - { wxT( "UTF-8" ), wxT("utf8"), NULL }, -#ifdef WORDS_BIGENDIAN - { wxT( "UTF-16BE" ), wxT("UCS-2BE"), wxT( "UTF-16" ), wxT("UCS-2"), wxT("UCS2"), NULL }, - { wxT( "UTF-16LE" ), wxT("UCS-2LE"), NULL }, - { wxT( "UTF-32BE" ), wxT( "UCS-4BE" ), wxT( "UTF-32" ), wxT( "UCS-4" ), wxT("UCS4"), NULL }, - { wxT( "UTF-32LE" ), wxT( "UCS-4LE" ), NULL }, -#else // WORDS_BIGENDIAN - { wxT( "UTF-16BE" ), wxT("UCS-2BE"), NULL }, - { wxT( "UTF-16LE" ), wxT("UCS-2LE"), wxT( "UTF-16" ), wxT("UCS-2"), wxT("UCS2"), NULL }, - { wxT( "UTF-32BE" ), wxT( "UCS-4BE" ), NULL }, - { wxT( "UTF-32LE" ), wxT( "UCS-4LE" ), wxT( "UTF-32" ), wxT( "UCS-4" ), wxT("UCS4"), NULL }, -#endif // WORDS_BIGENDIAN - - { wxT( "EUC-JP" ), wxT( "eucJP" ), wxT( "euc_jp" ), wxT( "IBM-eucJP" ), NULL }, - - // 646 is for Solaris, roman8 -- for HP-UX - { wxT( "US-ASCII" ), wxT( "ASCII" ), wxT("C"), wxT("POSIX"), wxT("ANSI_X3.4-1968"), - wxT("646"), wxT("roman8"), wxT( "" ), NULL }, - - { wxT( "BIG5" ), wxT("big5"), NULL }, - { wxT( "SJIS" ), wxT( "SHIFT-JIS" ), wxT( "SHIFT_JIS" ), NULL }, - { wxT( "GB2312" ), NULL }, -}; - -wxCOMPILE_TIME_ASSERT( WXSIZEOF(gs_encodingDescs) == WXSIZEOF(gs_encodings), EncodingsArraysNotInSync ); -wxCOMPILE_TIME_ASSERT( WXSIZEOF(gs_encodingNames) == WXSIZEOF(gs_encodings), EncodingsArraysNotInSync ); - -// ---------------------------------------------------------------------------- -// private classes -// ---------------------------------------------------------------------------- - -// clean up the font mapper object -class wxFontMapperModule : public wxModule -{ -public: - wxFontMapperModule() : wxModule() { } - - virtual bool OnInit() - { - // a dummy wxFontMapperBase object could have been created during the - // program startup before wxApp was created, we have to delete it to - // allow creating the real font mapper next time it is needed now that - // we can create it (when the modules are initialized, wxApp object - // already exists) - wxFontMapperBase *fm = wxFontMapperBase::Get(); - if ( fm && fm->IsDummy() ) - wxFontMapperBase::Reset(); - - return true; - } - - virtual void OnExit() - { - wxFontMapperBase::Reset(); - } - - DECLARE_DYNAMIC_CLASS(wxFontMapperModule) -}; - -IMPLEMENT_DYNAMIC_CLASS(wxFontMapperModule, wxModule) - - -// ============================================================================ -// wxFontMapperBase implementation -// ============================================================================ - -wxFontMapper *wxFontMapperBase::sm_instance = NULL; - -// ---------------------------------------------------------------------------- -// ctor and dtor -// ---------------------------------------------------------------------------- - -wxFontMapperBase::wxFontMapperBase() -{ -#if wxUSE_CONFIG && wxUSE_FILECONFIG - m_configDummy = NULL; -#endif // wxUSE_CONFIG -} - -wxFontMapperBase::~wxFontMapperBase() -{ -#if wxUSE_CONFIG && wxUSE_FILECONFIG - if ( m_configDummy ) - delete m_configDummy; -#endif // wxUSE_CONFIG -} - -/* static */ -wxFontMapperBase *wxFontMapperBase::Get() -{ - if ( !sm_instance ) - { - wxAppTraits *traits = wxTheApp ? wxTheApp->GetTraits() : NULL; - if ( traits ) - { - sm_instance = traits->CreateFontMapper(); - - wxASSERT_MSG( sm_instance, - _T("wxAppTraits::CreateFontMapper() failed") ); - } - - if ( !sm_instance ) - { - // last resort: we must create something because the existing code - // relies on always having a valid font mapper object - sm_instance = (wxFontMapper *)new wxFontMapperBase; - } - } - - return (wxFontMapperBase*)sm_instance; -} - -/* static */ -wxFontMapper *wxFontMapperBase::Set(wxFontMapper *mapper) -{ - wxFontMapper *old = sm_instance; - sm_instance = mapper; - return old; -} - -/* static */ -void wxFontMapperBase::Reset() -{ - if ( sm_instance ) - { - // we need a cast as wxFontMapper is not fully declared here and so the - // compiler can't know that it derives from wxFontMapperBase (but - // run-time behaviour will be correct because the dtor is virtual) - delete (wxFontMapperBase *)sm_instance; - sm_instance = NULL; - } -} - -#if wxUSE_CONFIG && wxUSE_FILECONFIG - -// ---------------------------------------------------------------------------- -// config usage customisation -// ---------------------------------------------------------------------------- - -/* static */ -const wxChar *wxFontMapperBase::GetDefaultConfigPath() -{ - return FONTMAPPER_ROOT_PATH; -} - -void wxFontMapperBase::SetConfigPath(const wxString& prefix) -{ - wxCHECK_RET( !prefix.empty() && prefix[0] == wxCONFIG_PATH_SEPARATOR, - wxT("an absolute path should be given to wxFontMapper::SetConfigPath()") ); - - m_configRootPath = prefix; -} - -// ---------------------------------------------------------------------------- -// get config object and path for it -// ---------------------------------------------------------------------------- - -wxConfigBase *wxFontMapperBase::GetConfig() -{ - wxConfigBase *config = wxConfig::Get(false); - - // If there is no global configuration, use an internal memory configuration - if ( !config ) - { - if ( !m_configDummy ) - m_configDummy = new wxMemoryConfig; - config = m_configDummy; - - // FIXME: ideally, we should add keys from dummy config to a real one later, - // but it is a low-priority task because typical wxWin application - // either doesn't use wxConfig at all or creates wxConfig object in - // wxApp::OnInit(), before any real interaction with the user takes - // place... - } - - return config; -} - -const wxString& wxFontMapperBase::GetConfigPath() -{ - if ( !m_configRootPath ) - { - // use the default - m_configRootPath = GetDefaultConfigPath(); - } - - return m_configRootPath; -} - -// ---------------------------------------------------------------------------- -// config helpers -// ---------------------------------------------------------------------------- - -bool wxFontMapperBase::ChangePath(const wxString& pathNew, wxString *pathOld) -{ - wxConfigBase *config = GetConfig(); - if ( !config ) - return false; - - *pathOld = config->GetPath(); - - wxString path = GetConfigPath(); - if ( path.empty() || path.Last() != wxCONFIG_PATH_SEPARATOR ) - { - path += wxCONFIG_PATH_SEPARATOR; - } - - wxASSERT_MSG( !pathNew || (pathNew[0] != wxCONFIG_PATH_SEPARATOR), - wxT("should be a relative path") ); - - path += pathNew; - - config->SetPath(path); - - return true; -} - -void wxFontMapperBase::RestorePath(const wxString& pathOld) -{ - GetConfig()->SetPath(pathOld); -} - -#endif - -// ---------------------------------------------------------------------------- -// charset/encoding correspondence -// ---------------------------------------------------------------------------- - -wxFontEncoding -wxFontMapperBase::CharsetToEncoding(const wxString& charset, - bool WXUNUSED(interactive)) -{ - int enc = NonInteractiveCharsetToEncoding(charset); - if ( enc == wxFONTENCODING_UNKNOWN ) - { - // we should return wxFONTENCODING_SYSTEM from here for unknown - // encodings - enc = wxFONTENCODING_SYSTEM; - } - - return (wxFontEncoding)enc; -} - -int -wxFontMapperBase::NonInteractiveCharsetToEncoding(const wxString& charset) -{ - wxFontEncoding encoding = wxFONTENCODING_SYSTEM; - - // we're going to modify it, make a copy - wxString cs = charset; - -#if wxUSE_CONFIG && wxUSE_FILECONFIG - // first try the user-defined settings - wxFontMapperPathChanger path(this, FONTMAPPER_CHARSET_PATH); - if ( path.IsOk() ) - { - wxConfigBase *config = GetConfig(); - - // do we have an encoding for this charset? - long value = config->Read(charset, -1l); - if ( value != -1 ) - { - if ( value == wxFONTENCODING_UNKNOWN ) - { - // don't try to find it, in particular don't ask the user - return value; - } - - if ( value >= 0 && value <= wxFONTENCODING_MAX ) - { - encoding = (wxFontEncoding)value; - } - else - { - wxLogDebug(wxT("corrupted config data: invalid encoding %ld for charset '%s' ignored"), - value, charset.c_str()); - } - } - - if ( encoding == wxFONTENCODING_SYSTEM ) - { - // may be we have an alias? - config->SetPath(FONTMAPPER_CHARSET_ALIAS_PATH); - - wxString alias = config->Read(charset); - if ( !alias.empty() ) - { - // yes, we do - use it instead - cs = alias; - } - } - } -#endif // wxUSE_CONFIG - - // if didn't find it there, try to recognize it ourselves - if ( encoding == wxFONTENCODING_SYSTEM ) - { - // trim any spaces - cs.Trim(true); - cs.Trim(false); - - // discard the optional quotes - if ( !cs.empty() ) - { - if ( cs[0u] == _T('"') && cs.Last() == _T('"') ) - { - cs = wxString(cs.c_str(), cs.length() - 1); - } - } - - for ( size_t i = 0; i < WXSIZEOF(gs_encodingNames); ++i ) - { - for ( const wxChar** encName = gs_encodingNames[i]; *encName; ++encName ) - { - if ( cs.CmpNoCase(*encName) == 0 ) - return gs_encodings[i]; - } - } - - cs.MakeUpper(); - - if ( cs.Left(3) == wxT("ISO") ) - { - // the dash is optional (or, to be exact, it is not, but - // several brokenmails "forget" it) - const wxChar *p = cs.c_str() + 3; - if ( *p == wxT('-') ) - p++; - - // printf( "iso %s\n", (const char*) cs.ToAscii() ); - - unsigned int value; - if ( wxSscanf(p, wxT("8859-%u"), &value) == 1 ) - { - // printf( "value %d\n", (int)value ); - - // make it 0 based and check that it is strictly positive in - // the process (no such thing as iso8859-0 encoding) - if ( (value-- > 0) && - (value < wxFONTENCODING_ISO8859_MAX - - wxFONTENCODING_ISO8859_1) ) - { - // it's a valid ISO8859 encoding - value += wxFONTENCODING_ISO8859_1; - encoding = (wxFontEncoding)value; - } - } - } - else if ( cs.Left(4) == wxT("8859") ) - { - const wxChar *p = cs.c_str(); - - unsigned int value; - if ( wxSscanf(p, wxT("8859-%u"), &value) == 1 ) - { - // printf( "value %d\n", (int)value ); - - // make it 0 based and check that it is strictly positive in - // the process (no such thing as iso8859-0 encoding) - if ( (value-- > 0) && - (value < wxFONTENCODING_ISO8859_MAX - - wxFONTENCODING_ISO8859_1) ) - { - // it's a valid ISO8859 encoding - value += wxFONTENCODING_ISO8859_1; - encoding = (wxFontEncoding)value; - } - } - } - else // check for Windows charsets - { - size_t len; - if ( cs.Left(7) == wxT("WINDOWS") ) - { - len = 7; - } - else if ( cs.Left(2) == wxT("CP") ) - { - len = 2; - } - else // not a Windows encoding - { - len = 0; - } - - if ( len ) - { - const wxChar *p = cs.c_str() + len; - if ( *p == wxT('-') ) - p++; - - unsigned int value; - if ( wxSscanf(p, wxT("%u"), &value) == 1 ) - { - if ( value >= 1250 ) - { - value -= 1250; - if ( value < wxFONTENCODING_CP12_MAX - - wxFONTENCODING_CP1250 ) - { - // a valid Windows code page - value += wxFONTENCODING_CP1250; - encoding = (wxFontEncoding)value; - } - } - - switch ( value ) - { - case 866: - encoding = wxFONTENCODING_CP866; - break; - - case 874: - encoding = wxFONTENCODING_CP874; - break; - - case 932: - encoding = wxFONTENCODING_CP932; - break; - - case 936: - encoding = wxFONTENCODING_CP936; - break; - - case 949: - encoding = wxFONTENCODING_CP949; - break; - - case 950: - encoding = wxFONTENCODING_CP950; - break; - } - } - } - } - //else: unknown - } - - return encoding; -} - -/* static */ -size_t wxFontMapperBase::GetSupportedEncodingsCount() -{ - return WXSIZEOF(gs_encodings); -} - -/* static */ -wxFontEncoding wxFontMapperBase::GetEncoding(size_t n) -{ - wxCHECK_MSG( n < WXSIZEOF(gs_encodings), wxFONTENCODING_SYSTEM, - _T("wxFontMapper::GetEncoding(): invalid index") ); - - return gs_encodings[n]; -} - -/* static */ -wxString wxFontMapperBase::GetEncodingDescription(wxFontEncoding encoding) -{ - if ( encoding == wxFONTENCODING_DEFAULT ) - { - return _("Default encoding"); - } - - const size_t count = WXSIZEOF(gs_encodingDescs); - - for ( size_t i = 0; i < count; i++ ) - { - if ( gs_encodings[i] == encoding ) - { - return wxGetTranslation(gs_encodingDescs[i]); - } - } - - wxString str; - str.Printf(_("Unknown encoding (%d)"), encoding); - - return str; -} - -/* static */ -wxString wxFontMapperBase::GetEncodingName(wxFontEncoding encoding) -{ - if ( encoding == wxFONTENCODING_DEFAULT ) - { - return _("default"); - } - - const size_t count = WXSIZEOF(gs_encodingNames); - - for ( size_t i = 0; i < count; i++ ) - { - if ( gs_encodings[i] == encoding ) - { - return gs_encodingNames[i][0]; - } - } - - wxString str; - str.Printf(_("unknown-%d"), encoding); - - return str; -} - -/* static */ -const wxChar** wxFontMapperBase::GetAllEncodingNames(wxFontEncoding encoding) -{ - static const wxChar* dummy[] = { NULL }; - - for ( size_t i = 0; i < WXSIZEOF(gs_encodingNames); i++ ) - { - if ( gs_encodings[i] == encoding ) - { - return gs_encodingNames[i]; - } - } - - return dummy; -} - -/* static */ -wxFontEncoding wxFontMapperBase::GetEncodingFromName(const wxString& name) -{ - const size_t count = WXSIZEOF(gs_encodingNames); - - for ( size_t i = 0; i < count; i++ ) - { - for ( const wxChar** encName = gs_encodingNames[i]; *encName; ++encName ) - { - if ( name.CmpNoCase(*encName) == 0 ) - return gs_encodings[i]; - } - } - - return wxFONTENCODING_MAX; -} - -#endif // wxUSE_FONTMAP +/////////////////////////////////////////////////////////////////////////////// +// Name: src/common/fmapbase.cpp +// Purpose: wxFontMapperBase class implementation +// Author: Vadim Zeitlin +// Modified by: +// Created: 21.06.2003 (extracted from common/fontmap.cpp) +// RCS-ID: $Id: fmapbase.cpp 43063 2006-11-04 20:48:04Z VZ $ +// Copyright: (c) 1999-2003 Vadim Zeitlin +// License: wxWindows license +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// for compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_FONTMAP + +#ifndef WX_PRECOMP + #include "wx/app.h" + #include "wx/log.h" + #include "wx/intl.h" + #include "wx/module.h" +#endif //WX_PRECOMP + +#if defined(__WXMSW__) + #include "wx/msw/private.h" // includes windows.h for LOGFONT + #include "wx/msw/winundef.h" +#endif + +#include "wx/fontmap.h" +#include "wx/fmappriv.h" + +#include "wx/apptrait.h" + +// wxMemoryConfig uses wxFileConfig +#if wxUSE_CONFIG && wxUSE_FILECONFIG + #include "wx/config.h" + #include "wx/memconf.h" +#endif + +// ---------------------------------------------------------------------------- +// constants +// ---------------------------------------------------------------------------- + +// encodings supported by GetEncodingDescription +static wxFontEncoding gs_encodings[] = +{ + wxFONTENCODING_ISO8859_1, + wxFONTENCODING_ISO8859_2, + wxFONTENCODING_ISO8859_3, + wxFONTENCODING_ISO8859_4, + wxFONTENCODING_ISO8859_5, + wxFONTENCODING_ISO8859_6, + wxFONTENCODING_ISO8859_7, + wxFONTENCODING_ISO8859_8, + wxFONTENCODING_ISO8859_9, + wxFONTENCODING_ISO8859_10, + wxFONTENCODING_ISO8859_11, + wxFONTENCODING_ISO8859_12, + wxFONTENCODING_ISO8859_13, + wxFONTENCODING_ISO8859_14, + wxFONTENCODING_ISO8859_15, + wxFONTENCODING_KOI8, + wxFONTENCODING_KOI8_U, + wxFONTENCODING_CP874, + wxFONTENCODING_CP932, + wxFONTENCODING_CP936, + wxFONTENCODING_CP949, + wxFONTENCODING_CP950, + wxFONTENCODING_CP1250, + wxFONTENCODING_CP1251, + wxFONTENCODING_CP1252, + wxFONTENCODING_CP1253, + wxFONTENCODING_CP1254, + wxFONTENCODING_CP1255, + wxFONTENCODING_CP1256, + wxFONTENCODING_CP1257, + wxFONTENCODING_CP437, + wxFONTENCODING_UTF7, + wxFONTENCODING_UTF8, + wxFONTENCODING_UTF16BE, + wxFONTENCODING_UTF16LE, + wxFONTENCODING_UTF32BE, + wxFONTENCODING_UTF32LE, + wxFONTENCODING_EUC_JP, + wxFONTENCODING_DEFAULT, + wxFONTENCODING_BIG5, + wxFONTENCODING_SHIFT_JIS, + wxFONTENCODING_GB2312, +}; + +// the descriptions for them +static const wxChar* gs_encodingDescs[] = +{ + wxTRANSLATE( "Western European (ISO-8859-1)" ), + wxTRANSLATE( "Central European (ISO-8859-2)" ), + wxTRANSLATE( "Esperanto (ISO-8859-3)" ), + wxTRANSLATE( "Baltic (old) (ISO-8859-4)" ), + wxTRANSLATE( "Cyrillic (ISO-8859-5)" ), + wxTRANSLATE( "Arabic (ISO-8859-6)" ), + wxTRANSLATE( "Greek (ISO-8859-7)" ), + wxTRANSLATE( "Hebrew (ISO-8859-8)" ), + wxTRANSLATE( "Turkish (ISO-8859-9)" ), + wxTRANSLATE( "Nordic (ISO-8859-10)" ), + wxTRANSLATE( "Thai (ISO-8859-11)" ), + wxTRANSLATE( "Indian (ISO-8859-12)" ), + wxTRANSLATE( "Baltic (ISO-8859-13)" ), + wxTRANSLATE( "Celtic (ISO-8859-14)" ), + wxTRANSLATE( "Western European with Euro (ISO-8859-15)" ), + wxTRANSLATE( "KOI8-R" ), + wxTRANSLATE( "KOI8-U" ), + wxTRANSLATE( "Windows Thai (CP 874)" ), + wxTRANSLATE( "Windows Japanese (CP 932)" ), + wxTRANSLATE( "Windows Chinese Simplified (CP 936)" ), + wxTRANSLATE( "Windows Korean (CP 949)" ), + wxTRANSLATE( "Windows Chinese Traditional (CP 950)" ), + wxTRANSLATE( "Windows Central European (CP 1250)" ), + wxTRANSLATE( "Windows Cyrillic (CP 1251)" ), + wxTRANSLATE( "Windows Western European (CP 1252)" ), + wxTRANSLATE( "Windows Greek (CP 1253)" ), + wxTRANSLATE( "Windows Turkish (CP 1254)" ), + wxTRANSLATE( "Windows Hebrew (CP 1255)" ), + wxTRANSLATE( "Windows Arabic (CP 1256)" ), + wxTRANSLATE( "Windows Baltic (CP 1257)" ), + wxTRANSLATE( "Windows/DOS OEM (CP 437)" ), + wxTRANSLATE( "Unicode 7 bit (UTF-7)" ), + wxTRANSLATE( "Unicode 8 bit (UTF-8)" ), +#ifdef WORDS_BIGENDIAN + wxTRANSLATE( "Unicode 16 bit (UTF-16)" ), + wxTRANSLATE( "Unicode 16 bit Little Endian (UTF-16LE)" ), + wxTRANSLATE( "Unicode 32 bit (UTF-32)" ), + wxTRANSLATE( "Unicode 32 bit Little Endian (UTF-32LE)" ), +#else // WORDS_BIGENDIAN + wxTRANSLATE( "Unicode 16 bit Big Endian (UTF-16BE)" ), + wxTRANSLATE( "Unicode 16 bit (UTF-16)" ), + wxTRANSLATE( "Unicode 32 bit Big Endian (UTF-32BE)" ), + wxTRANSLATE( "Unicode 32 bit (UTF-32)" ), +#endif // WORDS_BIGENDIAN + wxTRANSLATE( "Extended Unix Codepage for Japanese (EUC-JP)" ), + wxTRANSLATE( "US-ASCII" ), + wxTRANSLATE( "BIG5" ), + wxTRANSLATE( "SHIFT-JIS" ), + wxTRANSLATE( "GB-2312" ), +}; + +// and the internal names (these are not translated on purpose!) +static const wxChar* gs_encodingNames[WXSIZEOF(gs_encodingDescs)][9] = +{ + // names from the columns correspond to these OS: + // Linux Solaris and IRIX HP-UX AIX + { _T("ISO-8859-1"), _T("ISO8859-1"), _T("iso88591"), _T("8859-1"), wxT("iso_8859_1"), NULL }, + { _T("ISO-8859-2"), _T("ISO8859-2"), _T("iso88592"), _T("8859-2"), NULL }, + { _T("ISO-8859-3"), _T("ISO8859-3"), _T("iso88593"), _T("8859-3"), NULL }, + { _T("ISO-8859-4"), _T("ISO8859-4"), _T("iso88594"), _T("8859-4"), NULL }, + { _T("ISO-8859-5"), _T("ISO8859-5"), _T("iso88595"), _T("8859-5"), NULL }, + { _T("ISO-8859-6"), _T("ISO8859-6"), _T("iso88596"), _T("8859-6"), NULL }, + { _T("ISO-8859-7"), _T("ISO8859-7"), _T("iso88597"), _T("8859-7"), NULL }, + { _T("ISO-8859-8"), _T("ISO8859-8"), _T("iso88598"), _T("8859-8"), NULL }, + { _T("ISO-8859-9"), _T("ISO8859-9"), _T("iso88599"), _T("8859-9"), NULL }, + { _T("ISO-8859-10"), _T("ISO8859-10"), _T("iso885910"), _T("8859-10"), NULL }, + { _T("ISO-8859-11"), _T("ISO8859-11"), _T("iso885911"), _T("8859-11"), NULL }, + { _T("ISO-8859-12"), _T("ISO8859-12"), _T("iso885912"), _T("8859-12"), NULL }, + { _T("ISO-8859-13"), _T("ISO8859-13"), _T("iso885913"), _T("8859-13"), NULL }, + { _T("ISO-8859-14"), _T("ISO8859-14"), _T("iso885914"), _T("8859-14"), NULL }, + { _T("ISO-8859-15"), _T("ISO8859-15"), _T("iso885915"), _T("8859-15"), NULL }, + + // although koi8-ru is not strictly speaking the same as koi8-r, + // they are similar enough to make mapping it to koi8 better than + // not recognizing it at all + { wxT( "KOI8-R" ), wxT( "KOI8-RU" ), NULL }, + { wxT( "KOI8-U" ), NULL }, + + { wxT( "WINDOWS-874" ), wxT( "CP-874" ), NULL }, + { wxT( "WINDOWS-932" ), wxT( "CP-932" ), NULL }, + { wxT( "WINDOWS-936" ), wxT( "CP-936" ), NULL }, + { wxT( "WINDOWS-949" ), wxT( "CP-949" ), wxT( "EUC-KR" ), wxT( "eucKR" ), wxT( "euc_kr" ), NULL }, + { wxT( "WINDOWS-950" ), wxT( "CP-950" ), NULL }, + { wxT( "WINDOWS-1250" ),wxT( "CP-1250" ), NULL }, + { wxT( "WINDOWS-1251" ),wxT( "CP-1251" ), NULL }, + { wxT( "WINDOWS-1252" ),wxT( "CP-1252" ), wxT("IBM-1252"), NULL }, + { wxT( "WINDOWS-1253" ),wxT( "CP-1253" ), NULL }, + { wxT( "WINDOWS-1254" ),wxT( "CP-1254" ), NULL }, + { wxT( "WINDOWS-1255" ),wxT( "CP-1255" ), NULL }, + { wxT( "WINDOWS-1256" ),wxT( "CP-1256" ), NULL }, + { wxT( "WINDOWS-1257" ),wxT( "CP-1257" ), NULL }, + { wxT( "WINDOWS-437" ), wxT( "CP-437" ), NULL }, + + { wxT( "UTF-7" ), wxT("utf7"), NULL }, + { wxT( "UTF-8" ), wxT("utf8"), NULL }, +#ifdef WORDS_BIGENDIAN + { wxT( "UTF-16BE" ), wxT("UCS-2BE"), wxT( "UTF-16" ), wxT("UCS-2"), wxT("UCS2"), NULL }, + { wxT( "UTF-16LE" ), wxT("UCS-2LE"), NULL }, + { wxT( "UTF-32BE" ), wxT( "UCS-4BE" ), wxT( "UTF-32" ), wxT( "UCS-4" ), wxT("UCS4"), NULL }, + { wxT( "UTF-32LE" ), wxT( "UCS-4LE" ), NULL }, +#else // WORDS_BIGENDIAN + { wxT( "UTF-16BE" ), wxT("UCS-2BE"), NULL }, + { wxT( "UTF-16LE" ), wxT("UCS-2LE"), wxT( "UTF-16" ), wxT("UCS-2"), wxT("UCS2"), NULL }, + { wxT( "UTF-32BE" ), wxT( "UCS-4BE" ), NULL }, + { wxT( "UTF-32LE" ), wxT( "UCS-4LE" ), wxT( "UTF-32" ), wxT( "UCS-4" ), wxT("UCS4"), NULL }, +#endif // WORDS_BIGENDIAN + + { wxT( "EUC-JP" ), wxT( "eucJP" ), wxT( "euc_jp" ), wxT( "IBM-eucJP" ), NULL }, + + // 646 is for Solaris, roman8 -- for HP-UX + { wxT( "US-ASCII" ), wxT( "ASCII" ), wxT("C"), wxT("POSIX"), wxT("ANSI_X3.4-1968"), + wxT("646"), wxT("roman8"), wxT( "" ), NULL }, + + { wxT( "BIG5" ), wxT("big5"), NULL }, + { wxT( "SJIS" ), wxT( "SHIFT-JIS" ), wxT( "SHIFT_JIS" ), NULL }, + { wxT( "GB2312" ), NULL }, +}; + +wxCOMPILE_TIME_ASSERT( WXSIZEOF(gs_encodingDescs) == WXSIZEOF(gs_encodings), EncodingsArraysNotInSync ); +wxCOMPILE_TIME_ASSERT( WXSIZEOF(gs_encodingNames) == WXSIZEOF(gs_encodings), EncodingsArraysNotInSync ); + +// ---------------------------------------------------------------------------- +// private classes +// ---------------------------------------------------------------------------- + +// clean up the font mapper object +class wxFontMapperModule : public wxModule +{ +public: + wxFontMapperModule() : wxModule() { } + + virtual bool OnInit() + { + // a dummy wxFontMapperBase object could have been created during the + // program startup before wxApp was created, we have to delete it to + // allow creating the real font mapper next time it is needed now that + // we can create it (when the modules are initialized, wxApp object + // already exists) + wxFontMapperBase *fm = wxFontMapperBase::Get(); + if ( fm && fm->IsDummy() ) + wxFontMapperBase::Reset(); + + return true; + } + + virtual void OnExit() + { + wxFontMapperBase::Reset(); + } + + DECLARE_DYNAMIC_CLASS(wxFontMapperModule) +}; + +IMPLEMENT_DYNAMIC_CLASS(wxFontMapperModule, wxModule) + + +// ============================================================================ +// wxFontMapperBase implementation +// ============================================================================ + +wxFontMapper *wxFontMapperBase::sm_instance = NULL; + +// ---------------------------------------------------------------------------- +// ctor and dtor +// ---------------------------------------------------------------------------- + +wxFontMapperBase::wxFontMapperBase() +{ +#if wxUSE_CONFIG && wxUSE_FILECONFIG + m_configDummy = NULL; +#endif // wxUSE_CONFIG +} + +wxFontMapperBase::~wxFontMapperBase() +{ +#if wxUSE_CONFIG && wxUSE_FILECONFIG + if ( m_configDummy ) + delete m_configDummy; +#endif // wxUSE_CONFIG +} + +/* static */ +wxFontMapperBase *wxFontMapperBase::Get() +{ + if ( !sm_instance ) + { + wxAppTraits *traits = wxTheApp ? wxTheApp->GetTraits() : NULL; + if ( traits ) + { + sm_instance = traits->CreateFontMapper(); + + wxASSERT_MSG( sm_instance, + _T("wxAppTraits::CreateFontMapper() failed") ); + } + + if ( !sm_instance ) + { + // last resort: we must create something because the existing code + // relies on always having a valid font mapper object + sm_instance = (wxFontMapper *)new wxFontMapperBase; + } + } + + return (wxFontMapperBase*)sm_instance; +} + +/* static */ +wxFontMapper *wxFontMapperBase::Set(wxFontMapper *mapper) +{ + wxFontMapper *old = sm_instance; + sm_instance = mapper; + return old; +} + +/* static */ +void wxFontMapperBase::Reset() +{ + if ( sm_instance ) + { + // we need a cast as wxFontMapper is not fully declared here and so the + // compiler can't know that it derives from wxFontMapperBase (but + // run-time behaviour will be correct because the dtor is virtual) + delete (wxFontMapperBase *)sm_instance; + sm_instance = NULL; + } +} + +#if wxUSE_CONFIG && wxUSE_FILECONFIG + +// ---------------------------------------------------------------------------- +// config usage customisation +// ---------------------------------------------------------------------------- + +/* static */ +const wxChar *wxFontMapperBase::GetDefaultConfigPath() +{ + return FONTMAPPER_ROOT_PATH; +} + +void wxFontMapperBase::SetConfigPath(const wxString& prefix) +{ + wxCHECK_RET( !prefix.empty() && prefix[0] == wxCONFIG_PATH_SEPARATOR, + wxT("an absolute path should be given to wxFontMapper::SetConfigPath()") ); + + m_configRootPath = prefix; +} + +// ---------------------------------------------------------------------------- +// get config object and path for it +// ---------------------------------------------------------------------------- + +wxConfigBase *wxFontMapperBase::GetConfig() +{ + wxConfigBase *config = wxConfig::Get(false); + + // If there is no global configuration, use an internal memory configuration + if ( !config ) + { + if ( !m_configDummy ) + m_configDummy = new wxMemoryConfig; + config = m_configDummy; + + // FIXME: ideally, we should add keys from dummy config to a real one later, + // but it is a low-priority task because typical wxWin application + // either doesn't use wxConfig at all or creates wxConfig object in + // wxApp::OnInit(), before any real interaction with the user takes + // place... + } + + return config; +} + +const wxString& wxFontMapperBase::GetConfigPath() +{ + if ( !m_configRootPath ) + { + // use the default + m_configRootPath = GetDefaultConfigPath(); + } + + return m_configRootPath; +} + +// ---------------------------------------------------------------------------- +// config helpers +// ---------------------------------------------------------------------------- + +bool wxFontMapperBase::ChangePath(const wxString& pathNew, wxString *pathOld) +{ + wxConfigBase *config = GetConfig(); + if ( !config ) + return false; + + *pathOld = config->GetPath(); + + wxString path = GetConfigPath(); + if ( path.empty() || path.Last() != wxCONFIG_PATH_SEPARATOR ) + { + path += wxCONFIG_PATH_SEPARATOR; + } + + wxASSERT_MSG( !pathNew || (pathNew[0] != wxCONFIG_PATH_SEPARATOR), + wxT("should be a relative path") ); + + path += pathNew; + + config->SetPath(path); + + return true; +} + +void wxFontMapperBase::RestorePath(const wxString& pathOld) +{ + GetConfig()->SetPath(pathOld); +} + +#endif + +// ---------------------------------------------------------------------------- +// charset/encoding correspondence +// ---------------------------------------------------------------------------- + +wxFontEncoding +wxFontMapperBase::CharsetToEncoding(const wxString& charset, + bool WXUNUSED(interactive)) +{ + int enc = NonInteractiveCharsetToEncoding(charset); + if ( enc == wxFONTENCODING_UNKNOWN ) + { + // we should return wxFONTENCODING_SYSTEM from here for unknown + // encodings + enc = wxFONTENCODING_SYSTEM; + } + + return (wxFontEncoding)enc; +} + +int +wxFontMapperBase::NonInteractiveCharsetToEncoding(const wxString& charset) +{ + wxFontEncoding encoding = wxFONTENCODING_SYSTEM; + + // we're going to modify it, make a copy + wxString cs = charset; + +#if wxUSE_CONFIG && wxUSE_FILECONFIG + // first try the user-defined settings + wxFontMapperPathChanger path(this, FONTMAPPER_CHARSET_PATH); + if ( path.IsOk() ) + { + wxConfigBase *config = GetConfig(); + + // do we have an encoding for this charset? + long value = config->Read(charset, -1l); + if ( value != -1 ) + { + if ( value == wxFONTENCODING_UNKNOWN ) + { + // don't try to find it, in particular don't ask the user + return value; + } + + if ( value >= 0 && value <= wxFONTENCODING_MAX ) + { + encoding = (wxFontEncoding)value; + } + else + { + wxLogDebug(wxT("corrupted config data: invalid encoding %ld for charset '%s' ignored"), + value, charset.c_str()); + } + } + + if ( encoding == wxFONTENCODING_SYSTEM ) + { + // may be we have an alias? + config->SetPath(FONTMAPPER_CHARSET_ALIAS_PATH); + + wxString alias = config->Read(charset); + if ( !alias.empty() ) + { + // yes, we do - use it instead + cs = alias; + } + } + } +#endif // wxUSE_CONFIG + + // if didn't find it there, try to recognize it ourselves + if ( encoding == wxFONTENCODING_SYSTEM ) + { + // trim any spaces + cs.Trim(true); + cs.Trim(false); + + // discard the optional quotes + if ( !cs.empty() ) + { + if ( cs[0u] == _T('"') && cs.Last() == _T('"') ) + { + cs = wxString(cs.c_str(), cs.length() - 1); + } + } + + for ( size_t i = 0; i < WXSIZEOF(gs_encodingNames); ++i ) + { + for ( const wxChar** encName = gs_encodingNames[i]; *encName; ++encName ) + { + if ( cs.CmpNoCase(*encName) == 0 ) + return gs_encodings[i]; + } + } + + cs.MakeUpper(); + + if ( cs.Left(3) == wxT("ISO") ) + { + // the dash is optional (or, to be exact, it is not, but + // several brokenmails "forget" it) + const wxChar *p = cs.c_str() + 3; + if ( *p == wxT('-') ) + p++; + + // printf( "iso %s\n", (const char*) cs.ToAscii() ); + + unsigned int value; + if ( wxSscanf(p, wxT("8859-%u"), &value) == 1 ) + { + // printf( "value %d\n", (int)value ); + + // make it 0 based and check that it is strictly positive in + // the process (no such thing as iso8859-0 encoding) + if ( (value-- > 0) && + (value < wxFONTENCODING_ISO8859_MAX - + wxFONTENCODING_ISO8859_1) ) + { + // it's a valid ISO8859 encoding + value += wxFONTENCODING_ISO8859_1; + encoding = (wxFontEncoding)value; + } + } + } + else if ( cs.Left(4) == wxT("8859") ) + { + const wxChar *p = cs.c_str(); + + unsigned int value; + if ( wxSscanf(p, wxT("8859-%u"), &value) == 1 ) + { + // printf( "value %d\n", (int)value ); + + // make it 0 based and check that it is strictly positive in + // the process (no such thing as iso8859-0 encoding) + if ( (value-- > 0) && + (value < wxFONTENCODING_ISO8859_MAX - + wxFONTENCODING_ISO8859_1) ) + { + // it's a valid ISO8859 encoding + value += wxFONTENCODING_ISO8859_1; + encoding = (wxFontEncoding)value; + } + } + } + else // check for Windows charsets + { + size_t len; + if ( cs.Left(7) == wxT("WINDOWS") ) + { + len = 7; + } + else if ( cs.Left(2) == wxT("CP") ) + { + len = 2; + } + else // not a Windows encoding + { + len = 0; + } + + if ( len ) + { + const wxChar *p = cs.c_str() + len; + if ( *p == wxT('-') ) + p++; + + unsigned int value; + if ( wxSscanf(p, wxT("%u"), &value) == 1 ) + { + if ( value >= 1250 ) + { + value -= 1250; + if ( value < wxFONTENCODING_CP12_MAX - + wxFONTENCODING_CP1250 ) + { + // a valid Windows code page + value += wxFONTENCODING_CP1250; + encoding = (wxFontEncoding)value; + } + } + + switch ( value ) + { + case 866: + encoding = wxFONTENCODING_CP866; + break; + + case 874: + encoding = wxFONTENCODING_CP874; + break; + + case 932: + encoding = wxFONTENCODING_CP932; + break; + + case 936: + encoding = wxFONTENCODING_CP936; + break; + + case 949: + encoding = wxFONTENCODING_CP949; + break; + + case 950: + encoding = wxFONTENCODING_CP950; + break; + } + } + } + } + //else: unknown + } + + return encoding; +} + +/* static */ +size_t wxFontMapperBase::GetSupportedEncodingsCount() +{ + return WXSIZEOF(gs_encodings); +} + +/* static */ +wxFontEncoding wxFontMapperBase::GetEncoding(size_t n) +{ + wxCHECK_MSG( n < WXSIZEOF(gs_encodings), wxFONTENCODING_SYSTEM, + _T("wxFontMapper::GetEncoding(): invalid index") ); + + return gs_encodings[n]; +} + +/* static */ +wxString wxFontMapperBase::GetEncodingDescription(wxFontEncoding encoding) +{ + if ( encoding == wxFONTENCODING_DEFAULT ) + { + return _("Default encoding"); + } + + const size_t count = WXSIZEOF(gs_encodingDescs); + + for ( size_t i = 0; i < count; i++ ) + { + if ( gs_encodings[i] == encoding ) + { + return wxGetTranslation(gs_encodingDescs[i]); + } + } + + wxString str; + str.Printf(_("Unknown encoding (%d)"), encoding); + + return str; +} + +/* static */ +wxString wxFontMapperBase::GetEncodingName(wxFontEncoding encoding) +{ + if ( encoding == wxFONTENCODING_DEFAULT ) + { + return _("default"); + } + + const size_t count = WXSIZEOF(gs_encodingNames); + + for ( size_t i = 0; i < count; i++ ) + { + if ( gs_encodings[i] == encoding ) + { + return gs_encodingNames[i][0]; + } + } + + wxString str; + str.Printf(_("unknown-%d"), encoding); + + return str; +} + +/* static */ +const wxChar** wxFontMapperBase::GetAllEncodingNames(wxFontEncoding encoding) +{ + static const wxChar* dummy[] = { NULL }; + + for ( size_t i = 0; i < WXSIZEOF(gs_encodingNames); i++ ) + { + if ( gs_encodings[i] == encoding ) + { + return gs_encodingNames[i]; + } + } + + return dummy; +} + +/* static */ +wxFontEncoding wxFontMapperBase::GetEncodingFromName(const wxString& name) +{ + const size_t count = WXSIZEOF(gs_encodingNames); + + for ( size_t i = 0; i < count; i++ ) + { + for ( const wxChar** encName = gs_encodingNames[i]; *encName; ++encName ) + { + if ( name.CmpNoCase(*encName) == 0 ) + return gs_encodings[i]; + } + } + + return wxFONTENCODING_MAX; +} + +#endif // wxUSE_FONTMAP diff --git a/Externals/wxWidgets/src/common/fontcmn.cpp b/Externals/wxWidgets/src/common/fontcmn.cpp index fe34d8a521..f88b54dcb9 100644 --- a/Externals/wxWidgets/src/common/fontcmn.cpp +++ b/Externals/wxWidgets/src/common/fontcmn.cpp @@ -1,784 +1,784 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/fontcmn.cpp -// Purpose: implementation of wxFontBase methods -// Author: Vadim Zeitlin -// Modified by: -// Created: 20.09.99 -// RCS-ID: $Id: fontcmn.cpp 43661 2006-11-26 20:18:53Z VZ $ -// Copyright: (c) wxWidgets team -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#include "wx/font.h" - -#ifndef WX_PRECOMP - #include "wx/dc.h" - #include "wx/intl.h" - #include "wx/dcscreen.h" - #include "wx/log.h" - #include "wx/gdicmn.h" -#endif // WX_PRECOMP - -#if defined(__WXMSW__) - #include "wx/msw/private.h" // includes windows.h for LOGFONT - #include "wx/msw/winundef.h" -#endif - -#include "wx/fontutil.h" // for wxNativeFontInfo -#include "wx/fontmap.h" -#include "wx/fontenum.h" - -#include "wx/tokenzr.h" - -// ============================================================================ -// implementation -// ============================================================================ - -// ---------------------------------------------------------------------------- -// helper functions -// ---------------------------------------------------------------------------- - -static void AdjustFontSize(wxFont& font, wxDC& dc, const wxSize& pixelSize) -{ - int currentSize = 0; - int largestGood = 0; - int smallestBad = 0; - - bool initialGoodFound = false; - bool initialBadFound = false; - - // NB: this assignment was separated from the variable definition - // in order to fix a gcc v3.3.3 compiler crash - currentSize = font.GetPointSize(); - while (currentSize > 0) - { - dc.SetFont(font); - - // if currentSize (in points) results in a font that is smaller - // than required by pixelSize it is considered a good size - if (dc.GetCharHeight() <= pixelSize.GetHeight() && - (!pixelSize.GetWidth() || - dc.GetCharWidth() <= pixelSize.GetWidth())) - { - largestGood = currentSize; - initialGoodFound = true; - } - else - { - smallestBad = currentSize; - initialBadFound = true; - } - if (!initialGoodFound) - { - currentSize /= 2; - } - else if (!initialBadFound) - { - currentSize *= 2; - } - else - { - int distance = smallestBad - largestGood; - if (distance == 1) - break; - - currentSize = largestGood + distance / 2; - } - - font.SetPointSize(currentSize); - } - - if (currentSize != largestGood) - font.SetPointSize(largestGood); -} - -// ---------------------------------------------------------------------------- -// wxFontBase -// ---------------------------------------------------------------------------- - -wxFontEncoding wxFontBase::ms_encodingDefault = wxFONTENCODING_SYSTEM; - -/* static */ -void wxFontBase::SetDefaultEncoding(wxFontEncoding encoding) -{ - // GetDefaultEncoding() should return something != wxFONTENCODING_DEFAULT - // and, besides, using this value here doesn't make any sense - wxCHECK_RET( encoding != wxFONTENCODING_DEFAULT, - _T("can't set default encoding to wxFONTENCODING_DEFAULT") ); - - ms_encodingDefault = encoding; -} - -wxFontBase::~wxFontBase() -{ - // this destructor is required for Darwin -} - -/* static */ -wxFont *wxFontBase::New(int size, - int family, - int style, - int weight, - bool underlined, - const wxString& face, - wxFontEncoding encoding) -{ - return new wxFont(size, family, style, weight, underlined, face, encoding); -} - -static inline int flags2Style(int flags) -{ - return flags & wxFONTFLAG_ITALIC - ? wxFONTSTYLE_ITALIC - : flags & wxFONTFLAG_SLANT - ? wxFONTSTYLE_SLANT - : wxFONTSTYLE_NORMAL; -} - -static inline int flags2Weight(int flags) -{ - return flags & wxFONTFLAG_LIGHT - ? wxFONTWEIGHT_LIGHT - : flags & wxFONTFLAG_BOLD - ? wxFONTWEIGHT_BOLD - : wxFONTWEIGHT_NORMAL; -} - -static inline bool flags2Underlined(int flags) -{ - return (flags & wxFONTFLAG_UNDERLINED) != 0; -} - -/* static */ -wxFont *wxFontBase::New(int pointSize, - wxFontFamily family, - int flags, - const wxString& face, - wxFontEncoding encoding) -{ - return New(pointSize, family, flags2Style(flags), flags2Weight(flags), - flags2Underlined(flags), face, encoding); -} - -/* static */ -wxFont *wxFontBase::New(const wxSize& pixelSize, - int family, - int style, - int weight, - bool underlined, - const wxString& face, - wxFontEncoding encoding) -{ -#if defined(__WXMSW__) - return new wxFont(pixelSize, family, style, weight, underlined, - face, encoding); -#else - wxFont *self = New(10, family, style, weight, underlined, face, encoding); - wxScreenDC dc; - AdjustFontSize(*(wxFont *)self, dc, pixelSize); - return self; -#endif -} - -/* static */ -wxFont *wxFontBase::New(const wxSize& pixelSize, - wxFontFamily family, - int flags, - const wxString& face, - wxFontEncoding encoding) -{ - return New(pixelSize, family, flags2Style(flags), flags2Weight(flags), - flags2Underlined(flags), face, encoding); -} - -wxSize wxFontBase::GetPixelSize() const -{ - wxScreenDC dc; - dc.SetFont(*(wxFont *)this); - return wxSize(dc.GetCharWidth(), dc.GetCharHeight()); -} - -bool wxFontBase::IsUsingSizeInPixels() const -{ - return false; -} - -void wxFontBase::SetPixelSize( const wxSize& pixelSize ) -{ - wxScreenDC dc; - AdjustFontSize(*(wxFont *)this, dc, pixelSize); -} - -/* static */ -wxFont *wxFontBase::New(const wxNativeFontInfo& info) -{ - return new wxFont(info); -} - -/* static */ -wxFont *wxFontBase::New(const wxString& strNativeFontDesc) -{ - wxNativeFontInfo fontInfo; - if ( !fontInfo.FromString(strNativeFontDesc) ) - return new wxFont(*wxNORMAL_FONT); - - return New(fontInfo); -} - -bool wxFontBase::IsFixedWidth() const -{ - return GetFamily() == wxFONTFAMILY_TELETYPE; -} - -void wxFontBase::DoSetNativeFontInfo(const wxNativeFontInfo& info) -{ -#ifdef wxNO_NATIVE_FONTINFO - SetPointSize(info.pointSize); - SetFamily(info.family); - SetStyle(info.style); - SetWeight(info.weight); - SetUnderlined(info.underlined); - SetFaceName(info.faceName); - SetEncoding(info.encoding); -#else - (void)info; -#endif -} - -wxString wxFontBase::GetNativeFontInfoDesc() const -{ - wxString fontDesc; - const wxNativeFontInfo *fontInfo = GetNativeFontInfo(); - if ( fontInfo ) - { - fontDesc = fontInfo->ToString(); - wxASSERT_MSG(!fontDesc.empty(), wxT("This should be a non-empty string!")); - } - else - { - wxFAIL_MSG(wxT("Derived class should have created the wxNativeFontInfo!")); - } - - return fontDesc; -} - -wxString wxFontBase::GetNativeFontInfoUserDesc() const -{ - wxString fontDesc; - const wxNativeFontInfo *fontInfo = GetNativeFontInfo(); - if ( fontInfo ) - { - fontDesc = fontInfo->ToUserString(); - wxASSERT_MSG(!fontDesc.empty(), wxT("This should be a non-empty string!")); - } - else - { - wxFAIL_MSG(wxT("Derived class should have created the wxNativeFontInfo!")); - } - - return fontDesc; -} - -bool wxFontBase::SetNativeFontInfo(const wxString& info) -{ - wxNativeFontInfo fontInfo; - if ( !info.empty() && fontInfo.FromString(info) ) - { - SetNativeFontInfo(fontInfo); - return true; - } - - UnRef(); - return false; -} - -bool wxFontBase::SetNativeFontInfoUserDesc(const wxString& info) -{ - wxNativeFontInfo fontInfo; - if ( !info.empty() && fontInfo.FromUserString(info) ) - { - SetNativeFontInfo(fontInfo); - return true; - } - - UnRef(); - return false; -} - -bool wxFontBase::operator==(const wxFont& font) const -{ - // either it is the same font, i.e. they share the same common data or they - // have different ref datas but still describe the same font - return IsSameAs(font) || - ( - Ok() == font.Ok() && - GetPointSize() == font.GetPointSize() && - // in wxGTK1 GetPixelSize() calls GetInternalFont() which uses - // operator==() resulting in infinite recursion so we can't use it - // in that port -#if !defined(__WXGTK__) || defined(__WXGTK20__) - GetPixelSize() == font.GetPixelSize() && -#endif - GetFamily() == font.GetFamily() && - GetStyle() == font.GetStyle() && - GetWeight() == font.GetWeight() && - GetUnderlined() == font.GetUnderlined() && - GetFaceName().IsSameAs(font.GetFaceName(), false) && - GetEncoding() == font.GetEncoding() - ); -} - -bool wxFontBase::operator!=(const wxFont& font) const -{ - return !(*this == font); -} - -wxString wxFontBase::GetFamilyString() const -{ - wxCHECK_MSG( Ok(), wxT("wxDEFAULT"), wxT("invalid font") ); - - switch ( GetFamily() ) - { - case wxDECORATIVE: return wxT("wxDECORATIVE"); - case wxROMAN: return wxT("wxROMAN"); - case wxSCRIPT: return wxT("wxSCRIPT"); - case wxSWISS: return wxT("wxSWISS"); - case wxMODERN: return wxT("wxMODERN"); - case wxTELETYPE: return wxT("wxTELETYPE"); - default: return wxT("wxDEFAULT"); - } -} - -wxString wxFontBase::GetStyleString() const -{ - wxCHECK_MSG( Ok(), wxT("wxDEFAULT"), wxT("invalid font") ); - - switch ( GetStyle() ) - { - case wxNORMAL: return wxT("wxNORMAL"); - case wxSLANT: return wxT("wxSLANT"); - case wxITALIC: return wxT("wxITALIC"); - default: return wxT("wxDEFAULT"); - } -} - -wxString wxFontBase::GetWeightString() const -{ - wxCHECK_MSG( Ok(), wxT("wxDEFAULT"), wxT("invalid font") ); - - switch ( GetWeight() ) - { - case wxNORMAL: return wxT("wxNORMAL"); - case wxBOLD: return wxT("wxBOLD"); - case wxLIGHT: return wxT("wxLIGHT"); - default: return wxT("wxDEFAULT"); - } -} - -bool wxFontBase::SetFaceName(const wxString &facename) -{ - if (!wxFontEnumerator::IsValidFacename(facename)) - { - UnRef(); // make Ok() return false - return false; - } - - return true; -} - - -// ---------------------------------------------------------------------------- -// wxNativeFontInfo -// ---------------------------------------------------------------------------- - -// Up to now, there are no native implementations of this function: -void wxNativeFontInfo::SetFaceName(const wxArrayString &facenames) -{ - for (size_t i=0; i < facenames.GetCount(); i++) - { - if (wxFontEnumerator::IsValidFacename(facenames[i])) - { - SetFaceName(facenames[i]); - return; - } - } - - // set the first valid facename we can find on this system - wxString validfacename = wxFontEnumerator::GetFacenames().Item(0); - wxLogTrace(wxT("font"), wxT("Falling back to '%s'"), validfacename.c_str()); - SetFaceName(validfacename); -} - - -#ifdef wxNO_NATIVE_FONTINFO - -// These are the generic forms of FromString()/ToString. -// -// convert to/from the string representation: format is -// version;pointsize;family;style;weight;underlined;facename;encoding - -bool wxNativeFontInfo::FromString(const wxString& s) -{ - long l; - - wxStringTokenizer tokenizer(s, _T(";")); - - wxString token = tokenizer.GetNextToken(); - // - // Ignore the version for now - // - - token = tokenizer.GetNextToken(); - if ( !token.ToLong(&l) ) - return false; - pointSize = (int)l; - - token = tokenizer.GetNextToken(); - if ( !token.ToLong(&l) ) - return false; - family = (wxFontFamily)l; - - token = tokenizer.GetNextToken(); - if ( !token.ToLong(&l) ) - return false; - style = (wxFontStyle)l; - - token = tokenizer.GetNextToken(); - if ( !token.ToLong(&l) ) - return false; - weight = (wxFontWeight)l; - - token = tokenizer.GetNextToken(); - if ( !token.ToLong(&l) ) - return false; - underlined = l != 0; - - faceName = tokenizer.GetNextToken(); - -#ifndef __WXMAC__ - if( !faceName ) - return false; -#endif - - token = tokenizer.GetNextToken(); - if ( !token.ToLong(&l) ) - return false; - encoding = (wxFontEncoding)l; - - return true; -} - -wxString wxNativeFontInfo::ToString() const -{ - wxString s; - - s.Printf(_T("%d;%d;%d;%d;%d;%d;%s;%d"), - 0, // version - pointSize, - family, - (int)style, - (int)weight, - underlined, - faceName.GetData(), - (int)encoding); - - return s; -} - -void wxNativeFontInfo::Init() -{ - pointSize = 0; - family = wxFONTFAMILY_DEFAULT; - style = wxFONTSTYLE_NORMAL; - weight = wxFONTWEIGHT_NORMAL; - underlined = false; - faceName.clear(); - encoding = wxFONTENCODING_DEFAULT; -} - -int wxNativeFontInfo::GetPointSize() const -{ - return pointSize; -} - -wxFontStyle wxNativeFontInfo::GetStyle() const -{ - return style; -} - -wxFontWeight wxNativeFontInfo::GetWeight() const -{ - return weight; -} - -bool wxNativeFontInfo::GetUnderlined() const -{ - return underlined; -} - -wxString wxNativeFontInfo::GetFaceName() const -{ - return faceName; -} - -wxFontFamily wxNativeFontInfo::GetFamily() const -{ - return family; -} - -wxFontEncoding wxNativeFontInfo::GetEncoding() const -{ - return encoding; -} - -void wxNativeFontInfo::SetPointSize(int pointsize) -{ - pointSize = pointsize; -} - -void wxNativeFontInfo::SetStyle(wxFontStyle style_) -{ - style = style_; -} - -void wxNativeFontInfo::SetWeight(wxFontWeight weight_) -{ - weight = weight_; -} - -void wxNativeFontInfo::SetUnderlined(bool underlined_) -{ - underlined = underlined_; -} - -bool wxNativeFontInfo::SetFaceName(const wxString& facename_) -{ - faceName = facename_; - return true; -} - -void wxNativeFontInfo::SetFamily(wxFontFamily family_) -{ - family = family_; -} - -void wxNativeFontInfo::SetEncoding(wxFontEncoding encoding_) -{ - encoding = encoding_; -} - -#endif // generic wxNativeFontInfo implementation - -// conversion to/from user-readable string: this is used in the generic -// versions and under MSW as well because there is no standard font description -// format there anyhow (but there is a well-defined standard for X11 fonts used -// by wxGTK and wxMotif) - -#if defined(wxNO_NATIVE_FONTINFO) || defined(__WXMSW__) || defined (__WXPM__) - -wxString wxNativeFontInfo::ToUserString() const -{ - wxString desc; - - // first put the adjectives, if any - this is English-centric, of course, - // but what else can we do? - if ( GetUnderlined() ) - { - desc << _("underlined"); - } - - switch ( GetWeight() ) - { - default: - wxFAIL_MSG( _T("unknown font weight") ); - // fall through - - case wxFONTWEIGHT_NORMAL: - break; - - case wxFONTWEIGHT_LIGHT: - desc << _(" light"); - break; - - case wxFONTWEIGHT_BOLD: - desc << _(" bold"); - break; - } - - switch ( GetStyle() ) - { - default: - wxFAIL_MSG( _T("unknown font style") ); - // fall through - - case wxFONTSTYLE_NORMAL: - break; - - // we don't distinguish between the two for now anyhow... - case wxFONTSTYLE_ITALIC: - case wxFONTSTYLE_SLANT: - desc << _(" italic"); - break; - } - - wxString face = GetFaceName(); - if ( !face.empty() ) - { - desc << _T(' ') << face; - } - - int size = GetPointSize(); - if ( size != wxNORMAL_FONT->GetPointSize() ) - { - desc << _T(' ') << size; - } - -#if wxUSE_FONTMAP - wxFontEncoding enc = GetEncoding(); - if ( enc != wxFONTENCODING_DEFAULT && enc != wxFONTENCODING_SYSTEM ) - { - desc << _T(' ') << wxFontMapper::GetEncodingName(enc); - } -#endif // wxUSE_FONTMAP - - return desc.Strip(wxString::both).MakeLower(); -} - -bool wxNativeFontInfo::FromUserString(const wxString& s) -{ - // reset to the default state - Init(); - - // parse a more or less free form string - // - // TODO: we should handle at least the quoted facenames - wxStringTokenizer tokenizer(s, _T(";, "), wxTOKEN_STRTOK); - - wxString face; - unsigned long size; - bool weightfound = false, pointsizefound = false; -#if wxUSE_FONTMAP - bool encodingfound = false; -#endif - - while ( tokenizer.HasMoreTokens() ) - { - wxString token = tokenizer.GetNextToken(); - - // normalize it - token.Trim(true).Trim(false).MakeLower(); - - // look for the known tokens - if ( token == _T("underlined") || token == _("underlined") ) - { - SetUnderlined(true); - } - else if ( token == _T("light") || token == _("light") ) - { - SetWeight(wxFONTWEIGHT_LIGHT); - weightfound = true; - } - else if ( token == _T("bold") || token == _("bold") ) - { - SetWeight(wxFONTWEIGHT_BOLD); - weightfound = true; - } - else if ( token == _T("italic") || token == _("italic") ) - { - SetStyle(wxFONTSTYLE_ITALIC); - } - else if ( token.ToULong(&size) ) - { - SetPointSize(size); - pointsizefound = true; - } - else - { -#if wxUSE_FONTMAP - // try to interpret this as an encoding - wxFontEncoding encoding = wxFontMapper::Get()->CharsetToEncoding(token, false); - if ( encoding != wxFONTENCODING_DEFAULT && - encoding != wxFONTENCODING_SYSTEM ) // returned when the recognition failed - { - SetEncoding(encoding); - encodingfound = true; - } - else - { -#endif // wxUSE_FONTMAP - - // assume it is the face name - if ( !face.empty() ) - { - face += _T(' '); - } - - face += token; - - // skip the code which resets face below - continue; - -#if wxUSE_FONTMAP - } -#endif // wxUSE_FONTMAP - } - - // if we had had the facename, we shouldn't continue appending tokens - // to it (i.e. "foo bold bar" shouldn't result in the facename "foo - // bar") - if ( !face.empty() ) - { - // NB: the check on the facename is implemented in wxFontBase::SetFaceName - // and not in wxNativeFontInfo::SetFaceName thus we need to explicitely - // call here wxFontEnumerator::IsValidFacename - if (!wxFontEnumerator::IsValidFacename(face) || - !SetFaceName(face)) - SetFaceName(wxNORMAL_FONT->GetFaceName()); - face.clear(); - } - } - - // we might not have flushed it inside the loop - if ( !face.empty() ) - { - // NB: the check on the facename is implemented in wxFontBase::SetFaceName - // and not in wxNativeFontInfo::SetFaceName thus we need to explicitely - // call here wxFontEnumerator::IsValidFacename - if (!wxFontEnumerator::IsValidFacename(face) || - !SetFaceName(face)) - SetFaceName(wxNORMAL_FONT->GetFaceName()); - } - - // set point size to default value if size was not given - if ( !pointsizefound ) - SetPointSize(wxNORMAL_FONT->GetPointSize()); - - // set font weight to default value if weight was not given - if ( !weightfound ) - SetWeight(wxFONTWEIGHT_NORMAL); - -#if wxUSE_FONTMAP - // set font encoding to default value if encoding was not given - if ( !encodingfound ) - SetEncoding(wxFONTENCODING_SYSTEM); -#endif // wxUSE_FONTMAP - - return true; -} - -#endif // generic or wxMSW or wxOS2 +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/fontcmn.cpp +// Purpose: implementation of wxFontBase methods +// Author: Vadim Zeitlin +// Modified by: +// Created: 20.09.99 +// RCS-ID: $Id: fontcmn.cpp 43661 2006-11-26 20:18:53Z VZ $ +// Copyright: (c) wxWidgets team +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#include "wx/font.h" + +#ifndef WX_PRECOMP + #include "wx/dc.h" + #include "wx/intl.h" + #include "wx/dcscreen.h" + #include "wx/log.h" + #include "wx/gdicmn.h" +#endif // WX_PRECOMP + +#if defined(__WXMSW__) + #include "wx/msw/private.h" // includes windows.h for LOGFONT + #include "wx/msw/winundef.h" +#endif + +#include "wx/fontutil.h" // for wxNativeFontInfo +#include "wx/fontmap.h" +#include "wx/fontenum.h" + +#include "wx/tokenzr.h" + +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// helper functions +// ---------------------------------------------------------------------------- + +static void AdjustFontSize(wxFont& font, wxDC& dc, const wxSize& pixelSize) +{ + int currentSize = 0; + int largestGood = 0; + int smallestBad = 0; + + bool initialGoodFound = false; + bool initialBadFound = false; + + // NB: this assignment was separated from the variable definition + // in order to fix a gcc v3.3.3 compiler crash + currentSize = font.GetPointSize(); + while (currentSize > 0) + { + dc.SetFont(font); + + // if currentSize (in points) results in a font that is smaller + // than required by pixelSize it is considered a good size + if (dc.GetCharHeight() <= pixelSize.GetHeight() && + (!pixelSize.GetWidth() || + dc.GetCharWidth() <= pixelSize.GetWidth())) + { + largestGood = currentSize; + initialGoodFound = true; + } + else + { + smallestBad = currentSize; + initialBadFound = true; + } + if (!initialGoodFound) + { + currentSize /= 2; + } + else if (!initialBadFound) + { + currentSize *= 2; + } + else + { + int distance = smallestBad - largestGood; + if (distance == 1) + break; + + currentSize = largestGood + distance / 2; + } + + font.SetPointSize(currentSize); + } + + if (currentSize != largestGood) + font.SetPointSize(largestGood); +} + +// ---------------------------------------------------------------------------- +// wxFontBase +// ---------------------------------------------------------------------------- + +wxFontEncoding wxFontBase::ms_encodingDefault = wxFONTENCODING_SYSTEM; + +/* static */ +void wxFontBase::SetDefaultEncoding(wxFontEncoding encoding) +{ + // GetDefaultEncoding() should return something != wxFONTENCODING_DEFAULT + // and, besides, using this value here doesn't make any sense + wxCHECK_RET( encoding != wxFONTENCODING_DEFAULT, + _T("can't set default encoding to wxFONTENCODING_DEFAULT") ); + + ms_encodingDefault = encoding; +} + +wxFontBase::~wxFontBase() +{ + // this destructor is required for Darwin +} + +/* static */ +wxFont *wxFontBase::New(int size, + int family, + int style, + int weight, + bool underlined, + const wxString& face, + wxFontEncoding encoding) +{ + return new wxFont(size, family, style, weight, underlined, face, encoding); +} + +static inline int flags2Style(int flags) +{ + return flags & wxFONTFLAG_ITALIC + ? wxFONTSTYLE_ITALIC + : flags & wxFONTFLAG_SLANT + ? wxFONTSTYLE_SLANT + : wxFONTSTYLE_NORMAL; +} + +static inline int flags2Weight(int flags) +{ + return flags & wxFONTFLAG_LIGHT + ? wxFONTWEIGHT_LIGHT + : flags & wxFONTFLAG_BOLD + ? wxFONTWEIGHT_BOLD + : wxFONTWEIGHT_NORMAL; +} + +static inline bool flags2Underlined(int flags) +{ + return (flags & wxFONTFLAG_UNDERLINED) != 0; +} + +/* static */ +wxFont *wxFontBase::New(int pointSize, + wxFontFamily family, + int flags, + const wxString& face, + wxFontEncoding encoding) +{ + return New(pointSize, family, flags2Style(flags), flags2Weight(flags), + flags2Underlined(flags), face, encoding); +} + +/* static */ +wxFont *wxFontBase::New(const wxSize& pixelSize, + int family, + int style, + int weight, + bool underlined, + const wxString& face, + wxFontEncoding encoding) +{ +#if defined(__WXMSW__) + return new wxFont(pixelSize, family, style, weight, underlined, + face, encoding); +#else + wxFont *self = New(10, family, style, weight, underlined, face, encoding); + wxScreenDC dc; + AdjustFontSize(*(wxFont *)self, dc, pixelSize); + return self; +#endif +} + +/* static */ +wxFont *wxFontBase::New(const wxSize& pixelSize, + wxFontFamily family, + int flags, + const wxString& face, + wxFontEncoding encoding) +{ + return New(pixelSize, family, flags2Style(flags), flags2Weight(flags), + flags2Underlined(flags), face, encoding); +} + +wxSize wxFontBase::GetPixelSize() const +{ + wxScreenDC dc; + dc.SetFont(*(wxFont *)this); + return wxSize(dc.GetCharWidth(), dc.GetCharHeight()); +} + +bool wxFontBase::IsUsingSizeInPixels() const +{ + return false; +} + +void wxFontBase::SetPixelSize( const wxSize& pixelSize ) +{ + wxScreenDC dc; + AdjustFontSize(*(wxFont *)this, dc, pixelSize); +} + +/* static */ +wxFont *wxFontBase::New(const wxNativeFontInfo& info) +{ + return new wxFont(info); +} + +/* static */ +wxFont *wxFontBase::New(const wxString& strNativeFontDesc) +{ + wxNativeFontInfo fontInfo; + if ( !fontInfo.FromString(strNativeFontDesc) ) + return new wxFont(*wxNORMAL_FONT); + + return New(fontInfo); +} + +bool wxFontBase::IsFixedWidth() const +{ + return GetFamily() == wxFONTFAMILY_TELETYPE; +} + +void wxFontBase::DoSetNativeFontInfo(const wxNativeFontInfo& info) +{ +#ifdef wxNO_NATIVE_FONTINFO + SetPointSize(info.pointSize); + SetFamily(info.family); + SetStyle(info.style); + SetWeight(info.weight); + SetUnderlined(info.underlined); + SetFaceName(info.faceName); + SetEncoding(info.encoding); +#else + (void)info; +#endif +} + +wxString wxFontBase::GetNativeFontInfoDesc() const +{ + wxString fontDesc; + const wxNativeFontInfo *fontInfo = GetNativeFontInfo(); + if ( fontInfo ) + { + fontDesc = fontInfo->ToString(); + wxASSERT_MSG(!fontDesc.empty(), wxT("This should be a non-empty string!")); + } + else + { + wxFAIL_MSG(wxT("Derived class should have created the wxNativeFontInfo!")); + } + + return fontDesc; +} + +wxString wxFontBase::GetNativeFontInfoUserDesc() const +{ + wxString fontDesc; + const wxNativeFontInfo *fontInfo = GetNativeFontInfo(); + if ( fontInfo ) + { + fontDesc = fontInfo->ToUserString(); + wxASSERT_MSG(!fontDesc.empty(), wxT("This should be a non-empty string!")); + } + else + { + wxFAIL_MSG(wxT("Derived class should have created the wxNativeFontInfo!")); + } + + return fontDesc; +} + +bool wxFontBase::SetNativeFontInfo(const wxString& info) +{ + wxNativeFontInfo fontInfo; + if ( !info.empty() && fontInfo.FromString(info) ) + { + SetNativeFontInfo(fontInfo); + return true; + } + + UnRef(); + return false; +} + +bool wxFontBase::SetNativeFontInfoUserDesc(const wxString& info) +{ + wxNativeFontInfo fontInfo; + if ( !info.empty() && fontInfo.FromUserString(info) ) + { + SetNativeFontInfo(fontInfo); + return true; + } + + UnRef(); + return false; +} + +bool wxFontBase::operator==(const wxFont& font) const +{ + // either it is the same font, i.e. they share the same common data or they + // have different ref datas but still describe the same font + return IsSameAs(font) || + ( + Ok() == font.Ok() && + GetPointSize() == font.GetPointSize() && + // in wxGTK1 GetPixelSize() calls GetInternalFont() which uses + // operator==() resulting in infinite recursion so we can't use it + // in that port +#if !defined(__WXGTK__) || defined(__WXGTK20__) + GetPixelSize() == font.GetPixelSize() && +#endif + GetFamily() == font.GetFamily() && + GetStyle() == font.GetStyle() && + GetWeight() == font.GetWeight() && + GetUnderlined() == font.GetUnderlined() && + GetFaceName().IsSameAs(font.GetFaceName(), false) && + GetEncoding() == font.GetEncoding() + ); +} + +bool wxFontBase::operator!=(const wxFont& font) const +{ + return !(*this == font); +} + +wxString wxFontBase::GetFamilyString() const +{ + wxCHECK_MSG( Ok(), wxT("wxDEFAULT"), wxT("invalid font") ); + + switch ( GetFamily() ) + { + case wxDECORATIVE: return wxT("wxDECORATIVE"); + case wxROMAN: return wxT("wxROMAN"); + case wxSCRIPT: return wxT("wxSCRIPT"); + case wxSWISS: return wxT("wxSWISS"); + case wxMODERN: return wxT("wxMODERN"); + case wxTELETYPE: return wxT("wxTELETYPE"); + default: return wxT("wxDEFAULT"); + } +} + +wxString wxFontBase::GetStyleString() const +{ + wxCHECK_MSG( Ok(), wxT("wxDEFAULT"), wxT("invalid font") ); + + switch ( GetStyle() ) + { + case wxNORMAL: return wxT("wxNORMAL"); + case wxSLANT: return wxT("wxSLANT"); + case wxITALIC: return wxT("wxITALIC"); + default: return wxT("wxDEFAULT"); + } +} + +wxString wxFontBase::GetWeightString() const +{ + wxCHECK_MSG( Ok(), wxT("wxDEFAULT"), wxT("invalid font") ); + + switch ( GetWeight() ) + { + case wxNORMAL: return wxT("wxNORMAL"); + case wxBOLD: return wxT("wxBOLD"); + case wxLIGHT: return wxT("wxLIGHT"); + default: return wxT("wxDEFAULT"); + } +} + +bool wxFontBase::SetFaceName(const wxString &facename) +{ + if (!wxFontEnumerator::IsValidFacename(facename)) + { + UnRef(); // make Ok() return false + return false; + } + + return true; +} + + +// ---------------------------------------------------------------------------- +// wxNativeFontInfo +// ---------------------------------------------------------------------------- + +// Up to now, there are no native implementations of this function: +void wxNativeFontInfo::SetFaceName(const wxArrayString &facenames) +{ + for (size_t i=0; i < facenames.GetCount(); i++) + { + if (wxFontEnumerator::IsValidFacename(facenames[i])) + { + SetFaceName(facenames[i]); + return; + } + } + + // set the first valid facename we can find on this system + wxString validfacename = wxFontEnumerator::GetFacenames().Item(0); + wxLogTrace(wxT("font"), wxT("Falling back to '%s'"), validfacename.c_str()); + SetFaceName(validfacename); +} + + +#ifdef wxNO_NATIVE_FONTINFO + +// These are the generic forms of FromString()/ToString. +// +// convert to/from the string representation: format is +// version;pointsize;family;style;weight;underlined;facename;encoding + +bool wxNativeFontInfo::FromString(const wxString& s) +{ + long l; + + wxStringTokenizer tokenizer(s, _T(";")); + + wxString token = tokenizer.GetNextToken(); + // + // Ignore the version for now + // + + token = tokenizer.GetNextToken(); + if ( !token.ToLong(&l) ) + return false; + pointSize = (int)l; + + token = tokenizer.GetNextToken(); + if ( !token.ToLong(&l) ) + return false; + family = (wxFontFamily)l; + + token = tokenizer.GetNextToken(); + if ( !token.ToLong(&l) ) + return false; + style = (wxFontStyle)l; + + token = tokenizer.GetNextToken(); + if ( !token.ToLong(&l) ) + return false; + weight = (wxFontWeight)l; + + token = tokenizer.GetNextToken(); + if ( !token.ToLong(&l) ) + return false; + underlined = l != 0; + + faceName = tokenizer.GetNextToken(); + +#ifndef __WXMAC__ + if( !faceName ) + return false; +#endif + + token = tokenizer.GetNextToken(); + if ( !token.ToLong(&l) ) + return false; + encoding = (wxFontEncoding)l; + + return true; +} + +wxString wxNativeFontInfo::ToString() const +{ + wxString s; + + s.Printf(_T("%d;%d;%d;%d;%d;%d;%s;%d"), + 0, // version + pointSize, + family, + (int)style, + (int)weight, + underlined, + faceName.GetData(), + (int)encoding); + + return s; +} + +void wxNativeFontInfo::Init() +{ + pointSize = 0; + family = wxFONTFAMILY_DEFAULT; + style = wxFONTSTYLE_NORMAL; + weight = wxFONTWEIGHT_NORMAL; + underlined = false; + faceName.clear(); + encoding = wxFONTENCODING_DEFAULT; +} + +int wxNativeFontInfo::GetPointSize() const +{ + return pointSize; +} + +wxFontStyle wxNativeFontInfo::GetStyle() const +{ + return style; +} + +wxFontWeight wxNativeFontInfo::GetWeight() const +{ + return weight; +} + +bool wxNativeFontInfo::GetUnderlined() const +{ + return underlined; +} + +wxString wxNativeFontInfo::GetFaceName() const +{ + return faceName; +} + +wxFontFamily wxNativeFontInfo::GetFamily() const +{ + return family; +} + +wxFontEncoding wxNativeFontInfo::GetEncoding() const +{ + return encoding; +} + +void wxNativeFontInfo::SetPointSize(int pointsize) +{ + pointSize = pointsize; +} + +void wxNativeFontInfo::SetStyle(wxFontStyle style_) +{ + style = style_; +} + +void wxNativeFontInfo::SetWeight(wxFontWeight weight_) +{ + weight = weight_; +} + +void wxNativeFontInfo::SetUnderlined(bool underlined_) +{ + underlined = underlined_; +} + +bool wxNativeFontInfo::SetFaceName(const wxString& facename_) +{ + faceName = facename_; + return true; +} + +void wxNativeFontInfo::SetFamily(wxFontFamily family_) +{ + family = family_; +} + +void wxNativeFontInfo::SetEncoding(wxFontEncoding encoding_) +{ + encoding = encoding_; +} + +#endif // generic wxNativeFontInfo implementation + +// conversion to/from user-readable string: this is used in the generic +// versions and under MSW as well because there is no standard font description +// format there anyhow (but there is a well-defined standard for X11 fonts used +// by wxGTK and wxMotif) + +#if defined(wxNO_NATIVE_FONTINFO) || defined(__WXMSW__) || defined (__WXPM__) + +wxString wxNativeFontInfo::ToUserString() const +{ + wxString desc; + + // first put the adjectives, if any - this is English-centric, of course, + // but what else can we do? + if ( GetUnderlined() ) + { + desc << _("underlined"); + } + + switch ( GetWeight() ) + { + default: + wxFAIL_MSG( _T("unknown font weight") ); + // fall through + + case wxFONTWEIGHT_NORMAL: + break; + + case wxFONTWEIGHT_LIGHT: + desc << _(" light"); + break; + + case wxFONTWEIGHT_BOLD: + desc << _(" bold"); + break; + } + + switch ( GetStyle() ) + { + default: + wxFAIL_MSG( _T("unknown font style") ); + // fall through + + case wxFONTSTYLE_NORMAL: + break; + + // we don't distinguish between the two for now anyhow... + case wxFONTSTYLE_ITALIC: + case wxFONTSTYLE_SLANT: + desc << _(" italic"); + break; + } + + wxString face = GetFaceName(); + if ( !face.empty() ) + { + desc << _T(' ') << face; + } + + int size = GetPointSize(); + if ( size != wxNORMAL_FONT->GetPointSize() ) + { + desc << _T(' ') << size; + } + +#if wxUSE_FONTMAP + wxFontEncoding enc = GetEncoding(); + if ( enc != wxFONTENCODING_DEFAULT && enc != wxFONTENCODING_SYSTEM ) + { + desc << _T(' ') << wxFontMapper::GetEncodingName(enc); + } +#endif // wxUSE_FONTMAP + + return desc.Strip(wxString::both).MakeLower(); +} + +bool wxNativeFontInfo::FromUserString(const wxString& s) +{ + // reset to the default state + Init(); + + // parse a more or less free form string + // + // TODO: we should handle at least the quoted facenames + wxStringTokenizer tokenizer(s, _T(";, "), wxTOKEN_STRTOK); + + wxString face; + unsigned long size; + bool weightfound = false, pointsizefound = false; +#if wxUSE_FONTMAP + bool encodingfound = false; +#endif + + while ( tokenizer.HasMoreTokens() ) + { + wxString token = tokenizer.GetNextToken(); + + // normalize it + token.Trim(true).Trim(false).MakeLower(); + + // look for the known tokens + if ( token == _T("underlined") || token == _("underlined") ) + { + SetUnderlined(true); + } + else if ( token == _T("light") || token == _("light") ) + { + SetWeight(wxFONTWEIGHT_LIGHT); + weightfound = true; + } + else if ( token == _T("bold") || token == _("bold") ) + { + SetWeight(wxFONTWEIGHT_BOLD); + weightfound = true; + } + else if ( token == _T("italic") || token == _("italic") ) + { + SetStyle(wxFONTSTYLE_ITALIC); + } + else if ( token.ToULong(&size) ) + { + SetPointSize(size); + pointsizefound = true; + } + else + { +#if wxUSE_FONTMAP + // try to interpret this as an encoding + wxFontEncoding encoding = wxFontMapper::Get()->CharsetToEncoding(token, false); + if ( encoding != wxFONTENCODING_DEFAULT && + encoding != wxFONTENCODING_SYSTEM ) // returned when the recognition failed + { + SetEncoding(encoding); + encodingfound = true; + } + else + { +#endif // wxUSE_FONTMAP + + // assume it is the face name + if ( !face.empty() ) + { + face += _T(' '); + } + + face += token; + + // skip the code which resets face below + continue; + +#if wxUSE_FONTMAP + } +#endif // wxUSE_FONTMAP + } + + // if we had had the facename, we shouldn't continue appending tokens + // to it (i.e. "foo bold bar" shouldn't result in the facename "foo + // bar") + if ( !face.empty() ) + { + // NB: the check on the facename is implemented in wxFontBase::SetFaceName + // and not in wxNativeFontInfo::SetFaceName thus we need to explicitely + // call here wxFontEnumerator::IsValidFacename + if (!wxFontEnumerator::IsValidFacename(face) || + !SetFaceName(face)) + SetFaceName(wxNORMAL_FONT->GetFaceName()); + face.clear(); + } + } + + // we might not have flushed it inside the loop + if ( !face.empty() ) + { + // NB: the check on the facename is implemented in wxFontBase::SetFaceName + // and not in wxNativeFontInfo::SetFaceName thus we need to explicitely + // call here wxFontEnumerator::IsValidFacename + if (!wxFontEnumerator::IsValidFacename(face) || + !SetFaceName(face)) + SetFaceName(wxNORMAL_FONT->GetFaceName()); + } + + // set point size to default value if size was not given + if ( !pointsizefound ) + SetPointSize(wxNORMAL_FONT->GetPointSize()); + + // set font weight to default value if weight was not given + if ( !weightfound ) + SetWeight(wxFONTWEIGHT_NORMAL); + +#if wxUSE_FONTMAP + // set font encoding to default value if encoding was not given + if ( !encodingfound ) + SetEncoding(wxFONTENCODING_SYSTEM); +#endif // wxUSE_FONTMAP + + return true; +} + +#endif // generic or wxMSW or wxOS2 diff --git a/Externals/wxWidgets/src/common/fontenumcmn.cpp b/Externals/wxWidgets/src/common/fontenumcmn.cpp index 0b64d0f4db..6ea8a30cb1 100644 --- a/Externals/wxWidgets/src/common/fontenumcmn.cpp +++ b/Externals/wxWidgets/src/common/fontenumcmn.cpp @@ -1,131 +1,131 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/fontenumcmn.cpp -// Purpose: wxFontEnumerator class -// Author: Vadim Zeitlin -// Modified by: -// Created: 7/5/2006 -// RCS-ID: $Id: fontenumcmn.cpp 43727 2006-12-01 10:14:28Z VS $ -// Copyright: (c) 1999-2003 Vadim Zeitlin -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#include "wx/fontenum.h" - -// ============================================================================ -// implementation -// ============================================================================ - -// A simple wxFontEnumerator which doesn't perform any filtering and -// just returns all facenames and encodings found in the system -class WXDLLEXPORT wxSimpleFontEnumerator : public wxFontEnumerator -{ -public: - wxSimpleFontEnumerator() { } - - // called by EnumerateFacenames - virtual bool OnFacename(const wxString& facename) - { - m_arrFacenames.Add(facename); - return true; - } - - // called by EnumerateEncodings - virtual bool OnFontEncoding(const wxString& WXUNUSED(facename), - const wxString& encoding) - { - m_arrEncodings.Add(encoding); - return true; - } - -public: - wxArrayString m_arrFacenames, m_arrEncodings; -}; - - -/* static */ -wxArrayString wxFontEnumerator::GetFacenames(wxFontEncoding encoding, bool fixedWidthOnly) -{ - wxSimpleFontEnumerator temp; - temp.EnumerateFacenames(encoding, fixedWidthOnly); - return temp.m_arrFacenames; -} - -/* static */ -wxArrayString wxFontEnumerator::GetEncodings(const wxString& facename) -{ - wxSimpleFontEnumerator temp; - temp.EnumerateEncodings(facename); - return temp.m_arrEncodings; -} - -/* static */ -bool wxFontEnumerator::IsValidFacename(const wxString &facename) -{ - // we cache the result of wxFontEnumerator::GetFacenames supposing that - // the array of face names won't change in the session of this program - static wxArrayString s_arr = wxFontEnumerator::GetFacenames(); - -#ifdef __WXMSW__ - // Quoting the MSDN: - // "MS Shell Dlg is a mapping mechanism that enables - // U.S. English Microsoft Windows NT, and Microsoft Windows 2000 to - // support locales that have characters that are not contained in code - // page 1252. It is not a font but a face name for a nonexistent font." - // Thus we need to consider "Ms Shell Dlg" and "Ms Shell Dlg 2" as valid - // font face names even if they are enumerated by wxFontEnumerator - if (facename.IsSameAs(wxT("Ms Shell Dlg"), false) || - facename.IsSameAs(wxT("Ms Shell Dlg 2"), false)) - return true; -#endif - - // is given font face name a valid one ? - if (s_arr.Index(facename, false) == wxNOT_FOUND) - return false; - - return true; -} - -#ifdef wxHAS_UTF8_FONTS -bool wxFontEnumerator::EnumerateEncodingsUTF8(const wxString& facename) -{ - // name of UTF-8 encoding: no need to use wxFontMapper for it as it's - // unlikely to change - const wxString utf8(_T("UTF-8")); - - // all fonts are in UTF-8 only if this code is used - if ( !facename.empty() ) - { - OnFontEncoding(facename, utf8); - return true; - } - - // so enumerating all facenames supporting this encoding is the same as - // enumerating all facenames - const wxArrayString facenames(GetFacenames(wxFONTENCODING_UTF8)); - const size_t count = facenames.size(); - if ( !count ) - return false; - - for ( size_t n = 0; n < count; n++ ) - { - OnFontEncoding(facenames[n], utf8); - } - - return true; -} -#endif // wxHAS_UTF8_FONTS +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/fontenumcmn.cpp +// Purpose: wxFontEnumerator class +// Author: Vadim Zeitlin +// Modified by: +// Created: 7/5/2006 +// RCS-ID: $Id: fontenumcmn.cpp 43727 2006-12-01 10:14:28Z VS $ +// Copyright: (c) 1999-2003 Vadim Zeitlin +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#include "wx/fontenum.h" + +// ============================================================================ +// implementation +// ============================================================================ + +// A simple wxFontEnumerator which doesn't perform any filtering and +// just returns all facenames and encodings found in the system +class WXDLLEXPORT wxSimpleFontEnumerator : public wxFontEnumerator +{ +public: + wxSimpleFontEnumerator() { } + + // called by EnumerateFacenames + virtual bool OnFacename(const wxString& facename) + { + m_arrFacenames.Add(facename); + return true; + } + + // called by EnumerateEncodings + virtual bool OnFontEncoding(const wxString& WXUNUSED(facename), + const wxString& encoding) + { + m_arrEncodings.Add(encoding); + return true; + } + +public: + wxArrayString m_arrFacenames, m_arrEncodings; +}; + + +/* static */ +wxArrayString wxFontEnumerator::GetFacenames(wxFontEncoding encoding, bool fixedWidthOnly) +{ + wxSimpleFontEnumerator temp; + temp.EnumerateFacenames(encoding, fixedWidthOnly); + return temp.m_arrFacenames; +} + +/* static */ +wxArrayString wxFontEnumerator::GetEncodings(const wxString& facename) +{ + wxSimpleFontEnumerator temp; + temp.EnumerateEncodings(facename); + return temp.m_arrEncodings; +} + +/* static */ +bool wxFontEnumerator::IsValidFacename(const wxString &facename) +{ + // we cache the result of wxFontEnumerator::GetFacenames supposing that + // the array of face names won't change in the session of this program + static wxArrayString s_arr = wxFontEnumerator::GetFacenames(); + +#ifdef __WXMSW__ + // Quoting the MSDN: + // "MS Shell Dlg is a mapping mechanism that enables + // U.S. English Microsoft Windows NT, and Microsoft Windows 2000 to + // support locales that have characters that are not contained in code + // page 1252. It is not a font but a face name for a nonexistent font." + // Thus we need to consider "Ms Shell Dlg" and "Ms Shell Dlg 2" as valid + // font face names even if they are enumerated by wxFontEnumerator + if (facename.IsSameAs(wxT("Ms Shell Dlg"), false) || + facename.IsSameAs(wxT("Ms Shell Dlg 2"), false)) + return true; +#endif + + // is given font face name a valid one ? + if (s_arr.Index(facename, false) == wxNOT_FOUND) + return false; + + return true; +} + +#ifdef wxHAS_UTF8_FONTS +bool wxFontEnumerator::EnumerateEncodingsUTF8(const wxString& facename) +{ + // name of UTF-8 encoding: no need to use wxFontMapper for it as it's + // unlikely to change + const wxString utf8(_T("UTF-8")); + + // all fonts are in UTF-8 only if this code is used + if ( !facename.empty() ) + { + OnFontEncoding(facename, utf8); + return true; + } + + // so enumerating all facenames supporting this encoding is the same as + // enumerating all facenames + const wxArrayString facenames(GetFacenames(wxFONTENCODING_UTF8)); + const size_t count = facenames.size(); + if ( !count ) + return false; + + for ( size_t n = 0; n < count; n++ ) + { + OnFontEncoding(facenames[n], utf8); + } + + return true; +} +#endif // wxHAS_UTF8_FONTS diff --git a/Externals/wxWidgets/src/common/fontmap.cpp b/Externals/wxWidgets/src/common/fontmap.cpp index cf53fd914e..3d38007660 100644 --- a/Externals/wxWidgets/src/common/fontmap.cpp +++ b/Externals/wxWidgets/src/common/fontmap.cpp @@ -1,519 +1,519 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/fontmap.cpp -// Purpose: wxFontMapper class -// Author: Vadim Zeitlin -// Modified by: -// Created: 04.11.99 -// RCS-ID: $Id: fontmap.cpp 39651 2006-06-09 17:50:46Z ABX $ -// Copyright: (c) 1999-2003 Vadim Zeitlin -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_FONTMAP - -#include "wx/fontmap.h" - -#ifndef WX_PRECOMP - #include "wx/app.h" - #include "wx/log.h" - #include "wx/intl.h" - #include "wx/msgdlg.h" - #include "wx/choicdlg.h" -#endif // PCH - -#if wxUSE_CONFIG - #include "wx/config.h" -#endif // wxUSE_CONFIG - -#if defined(__WXMSW__) - #include "wx/msw/private.h" // includes windows.h for LOGFONT - #include "wx/msw/winundef.h" -#endif - -#include "wx/fmappriv.h" -#include "wx/fontutil.h" -#include "wx/fontdlg.h" -#include "wx/encinfo.h" - -#include "wx/encconv.h" - -#if wxUSE_EXTENDED_RTTI - -wxBEGIN_ENUM( wxFontEncoding ) - wxENUM_MEMBER( wxFONTENCODING_SYSTEM ) - wxENUM_MEMBER( wxFONTENCODING_DEFAULT ) - - wxENUM_MEMBER( wxFONTENCODING_ISO8859_1 ) - wxENUM_MEMBER( wxFONTENCODING_ISO8859_2 ) - wxENUM_MEMBER( wxFONTENCODING_ISO8859_3 ) - wxENUM_MEMBER( wxFONTENCODING_ISO8859_4 ) - wxENUM_MEMBER( wxFONTENCODING_ISO8859_5 ) - wxENUM_MEMBER( wxFONTENCODING_ISO8859_6 ) - wxENUM_MEMBER( wxFONTENCODING_ISO8859_7 ) - wxENUM_MEMBER( wxFONTENCODING_ISO8859_8 ) - wxENUM_MEMBER( wxFONTENCODING_ISO8859_9 ) - wxENUM_MEMBER( wxFONTENCODING_ISO8859_10 ) - wxENUM_MEMBER( wxFONTENCODING_ISO8859_11 ) - wxENUM_MEMBER( wxFONTENCODING_ISO8859_12 ) - wxENUM_MEMBER( wxFONTENCODING_ISO8859_13 ) - wxENUM_MEMBER( wxFONTENCODING_ISO8859_14 ) - wxENUM_MEMBER( wxFONTENCODING_ISO8859_15 ) - wxENUM_MEMBER( wxFONTENCODING_ISO8859_MAX ) - wxENUM_MEMBER( wxFONTENCODING_KOI8 ) - wxENUM_MEMBER( wxFONTENCODING_KOI8_U ) - wxENUM_MEMBER( wxFONTENCODING_ALTERNATIVE ) - wxENUM_MEMBER( wxFONTENCODING_BULGARIAN ) - wxENUM_MEMBER( wxFONTENCODING_CP437 ) - wxENUM_MEMBER( wxFONTENCODING_CP850 ) - wxENUM_MEMBER( wxFONTENCODING_CP852 ) - wxENUM_MEMBER( wxFONTENCODING_CP855 ) - wxENUM_MEMBER( wxFONTENCODING_CP866 ) - - wxENUM_MEMBER( wxFONTENCODING_CP874 ) - wxENUM_MEMBER( wxFONTENCODING_CP932 ) - wxENUM_MEMBER( wxFONTENCODING_CP936 ) - wxENUM_MEMBER( wxFONTENCODING_CP949 ) - wxENUM_MEMBER( wxFONTENCODING_CP950 ) - wxENUM_MEMBER( wxFONTENCODING_CP1250 ) - wxENUM_MEMBER( wxFONTENCODING_CP1251 ) - wxENUM_MEMBER( wxFONTENCODING_CP1252 ) - wxENUM_MEMBER( wxFONTENCODING_CP1253 ) - wxENUM_MEMBER( wxFONTENCODING_CP1254 ) - wxENUM_MEMBER( wxFONTENCODING_CP1255 ) - wxENUM_MEMBER( wxFONTENCODING_CP1256 ) - wxENUM_MEMBER( wxFONTENCODING_CP1257 ) - wxENUM_MEMBER( wxFONTENCODING_CP12_MAX ) - wxENUM_MEMBER( wxFONTENCODING_UTF7 ) - wxENUM_MEMBER( wxFONTENCODING_UTF8 ) - wxENUM_MEMBER( wxFONTENCODING_GB2312 ) - wxENUM_MEMBER( wxFONTENCODING_BIG5 ) - wxENUM_MEMBER( wxFONTENCODING_SHIFT_JIS ) - wxENUM_MEMBER( wxFONTENCODING_EUC_JP ) - wxENUM_MEMBER( wxFONTENCODING_UNICODE ) -wxEND_ENUM( wxFontEncoding ) -#endif - -// ---------------------------------------------------------------------------- -// constants -// ---------------------------------------------------------------------------- - -// the config paths we use -#if wxUSE_CONFIG - -static const wxChar* FONTMAPPER_FONT_FROM_ENCODING_PATH = wxT("Encodings"); -static const wxChar* FONTMAPPER_FONT_DONT_ASK = wxT("none"); - -#endif // wxUSE_CONFIG - -// ---------------------------------------------------------------------------- -// private classes -// ---------------------------------------------------------------------------- - -// it may happen that while we're showing a dialog asking the user about -// something, another request for an encoding mapping arrives: in this case it -// is best to not do anything because otherwise we risk to enter an infinite -// loop so we create an object of this class on stack to test for this in all -// interactive functions -class ReentrancyBlocker -{ -public: - ReentrancyBlocker(bool& flag) : m_flagOld(flag), m_flag(flag) - { m_flag = true; } - ~ReentrancyBlocker() { m_flag = m_flagOld; } - -private: - bool m_flagOld; - bool& m_flag; - - DECLARE_NO_COPY_CLASS(ReentrancyBlocker) -}; - -// ============================================================================ -// implementation -// ============================================================================ - -// ---------------------------------------------------------------------------- -// ctor and dtor -// ---------------------------------------------------------------------------- - -wxFontMapper::wxFontMapper() -{ - m_windowParent = NULL; -} - -wxFontMapper::~wxFontMapper() -{ -} - -/* static */ -wxFontMapper *wxFontMapper::Get() -{ - wxFontMapperBase *fontmapper = wxFontMapperBase::Get(); - wxASSERT_MSG( !fontmapper->IsDummy(), - wxT("GUI code requested a wxFontMapper but we only have a wxFontMapperBase.") ); - - // Now return it anyway because there's a chance the GUI code might just - // only want to call wxFontMapperBase functions and it's better than - // crashing by returning NULL - return (wxFontMapper *)fontmapper; -} - -wxFontEncoding -wxFontMapper::CharsetToEncoding(const wxString& charset, bool interactive) -{ - // try the ways not needing the users intervention first - int encoding = wxFontMapperBase::NonInteractiveCharsetToEncoding(charset); - - // if we failed to find the encoding, ask the user -- unless disabled - if ( encoding == wxFONTENCODING_UNKNOWN ) - { - // this is the special value which disables asking the user (he had - // chosen to suppress this the last time) - encoding = wxFONTENCODING_SYSTEM; - } -#if wxUSE_CHOICEDLG - else if ( (encoding == wxFONTENCODING_SYSTEM) && interactive ) - { - // prepare the dialog data - - // the dialog title - wxString title(m_titleDialog); - if ( !title ) - title << wxTheApp->GetAppName() << _(": unknown charset"); - - // the message - wxString msg; - msg.Printf(_("The charset '%s' is unknown. You may select\nanother charset to replace it with or choose\n[Cancel] if it cannot be replaced"), charset.c_str()); - - // the list of choices - const size_t count = GetSupportedEncodingsCount(); - - wxString *encodingNamesTranslated = new wxString[count]; - - for ( size_t i = 0; i < count; i++ ) - { - encodingNamesTranslated[i] = GetEncodingDescription(GetEncoding(i)); - } - - // the parent window - wxWindow *parent = m_windowParent; - if ( !parent ) - parent = wxTheApp->GetTopWindow(); - - // do ask the user and get back the index in encodings table - int n = wxGetSingleChoiceIndex(msg, title, - count, - encodingNamesTranslated, - parent); - - delete [] encodingNamesTranslated; - - if ( n != -1 ) - { - encoding = GetEncoding(n); - } - -#if wxUSE_CONFIG && wxUSE_FILECONFIG - // save the result in the config now - wxFontMapperPathChanger path(this, FONTMAPPER_CHARSET_PATH); - if ( path.IsOk() ) - { - wxConfigBase *config = GetConfig(); - - // remember the alt encoding for this charset -- or remember that - // we don't know it - long value = n == -1 ? (long)wxFONTENCODING_UNKNOWN : (long)encoding; - if ( !config->Write(charset, value) ) - { - wxLogError(_("Failed to remember the encoding for the charset '%s'."), charset.c_str()); - } - } -#endif // wxUSE_CONFIG - } -#else - wxUnusedVar(interactive); -#endif // wxUSE_CHOICEDLG - - return (wxFontEncoding)encoding; -} - -// ---------------------------------------------------------------------------- -// support for unknown encodings: we maintain a map between the -// (platform-specific) strings identifying them and our wxFontEncodings they -// correspond to which is used by GetFontForEncoding() function -// ---------------------------------------------------------------------------- - -bool wxFontMapper::TestAltEncoding(const wxString& configEntry, - wxFontEncoding encReplacement, - wxNativeEncodingInfo *info) -{ - if ( wxGetNativeFontEncoding(encReplacement, info) && - wxTestFontEncoding(*info) ) - { -#if wxUSE_CONFIG && wxUSE_FILECONFIG - // remember the mapping in the config - wxFontMapperPathChanger path(this, FONTMAPPER_FONT_FROM_ENCODING_PATH); - - if ( path.IsOk() ) - { - GetConfig()->Write(configEntry, info->ToString()); - } -#else - wxUnusedVar(configEntry); -#endif // wxUSE_CONFIG - return true; - } - - return false; -} - -bool wxFontMapper::GetAltForEncoding(wxFontEncoding encoding, - wxNativeEncodingInfo *info, - const wxString& facename, - bool interactive) -{ -#if wxUSE_GUI - // we need a flag to prevent infinite recursion which happens, for - // example, when GetAltForEncoding() is called from an OnPaint() handler: - // in this case, wxYield() which is called from wxMessageBox() we use here - // will lead to another call of OnPaint() and hence to another call of - // GetAltForEncoding() -- and it is impossible to catch this from the user - // code because we are called from wxFont ctor implicitly. - - // assume we're always called from the main thread, so that it is safe to - // use a static var - static bool s_inGetAltForEncoding = false; - - if ( interactive && s_inGetAltForEncoding ) - return false; - - ReentrancyBlocker blocker(s_inGetAltForEncoding); -#endif // wxUSE_GUI - - wxCHECK_MSG( info, false, wxT("bad pointer in GetAltForEncoding") ); - - info->facename = facename; - - if ( encoding == wxFONTENCODING_DEFAULT ) - { - encoding = wxFont::GetDefaultEncoding(); - } - - // if we failed to load the system default encoding, something is really - // wrong and we'd better stop now -- otherwise we will go into endless - // recursion trying to create the font in the msg box with the error - // message - if ( encoding == wxFONTENCODING_SYSTEM ) - { - wxLogFatalError(_("can't load any font, aborting")); - - // wxLogFatalError doesn't return - } - - wxString configEntry, - encName = GetEncodingName(encoding); - if ( !facename.empty() ) - { - configEntry = facename + _T("_"); - } - configEntry += encName; - -#if wxUSE_CONFIG && wxUSE_FILECONFIG - // do we have a font spec for this encoding? - wxString fontinfo; - wxFontMapperPathChanger path(this, FONTMAPPER_FONT_FROM_ENCODING_PATH); - if ( path.IsOk() ) - { - fontinfo = GetConfig()->Read(configEntry); - } - - // this special value means that we don't know of fonts for this - // encoding but, moreover, have already asked the user as well and he - // didn't specify any font neither - if ( fontinfo == FONTMAPPER_FONT_DONT_ASK ) - { - interactive = false; - } - else // use the info entered the last time - { - if ( !fontinfo.empty() && !facename.empty() ) - { - // we tried to find a match with facename -- now try without it - fontinfo = GetConfig()->Read(encName); - } - - if ( !fontinfo.empty() ) - { - if ( info->FromString(fontinfo) ) - { - if ( wxTestFontEncoding(*info) ) - { - // ok, got something - return true; - } - //else: no such fonts, look for something else - // (should we erase the outdated value?) - } - else - { - wxLogDebug(wxT("corrupted config data: string '%s' is not a valid font encoding info"), - fontinfo.c_str()); - } - } - //else: there is no information in config about this encoding - } -#endif // wxUSE_CONFIG - - // now try to map this encoding to a compatible one which we have on this - // system - wxFontEncodingArray equiv = wxEncodingConverter::GetAllEquivalents(encoding); - size_t count = equiv.GetCount(); - bool foundEquivEncoding = false; - wxFontEncoding equivEncoding = wxFONTENCODING_SYSTEM; - if ( count ) - { - for ( size_t i = 0; i < count && !foundEquivEncoding; i++ ) - { - // don't test for encoding itself, we already know we don't have it - if ( equiv[i] == encoding ) - continue; - - if ( TestAltEncoding(configEntry, equiv[i], info) ) - { - equivEncoding = equiv[i]; - - foundEquivEncoding = true; - } - } - } - - // ask the user -#if wxUSE_FONTDLG - if ( interactive ) - { - wxString title(m_titleDialog); - if ( !title ) - title << wxTheApp->GetAppName() << _(": unknown encoding"); - - // built the message - wxString encDesc = GetEncodingDescription(encoding), - msg; - if ( foundEquivEncoding ) - { - // ask the user if he wants to override found alternative encoding - msg.Printf(_("No font for displaying text in encoding '%s' found,\nbut an alternative encoding '%s' is available.\nDo you want to use this encoding (otherwise you will have to choose another one)?"), - encDesc.c_str(), GetEncodingDescription(equivEncoding).c_str()); - } - else - { - msg.Printf(_("No font for displaying text in encoding '%s' found.\nWould you like to select a font to be used for this encoding\n(otherwise the text in this encoding will not be shown correctly)?"), - encDesc.c_str()); - } - - // the question is different in 2 cases so the answer has to be - // interpreted differently as well - int answer = foundEquivEncoding ? wxNO : wxYES; - - if ( wxMessageBox(msg, title, - wxICON_QUESTION | wxYES_NO, - m_windowParent) == answer ) - { - wxFontData data; - data.SetEncoding(encoding); - data.EncodingInfo() = *info; - wxFontDialog dialog(m_windowParent, data); - if ( dialog.ShowModal() == wxID_OK ) - { - wxFontData retData = dialog.GetFontData(); - - *info = retData.EncodingInfo(); - info->encoding = retData.GetEncoding(); - -#if wxUSE_CONFIG && wxUSE_FILECONFIG - // remember this in the config - wxFontMapperPathChanger path2(this, - FONTMAPPER_FONT_FROM_ENCODING_PATH); - if ( path2.IsOk() ) - { - GetConfig()->Write(configEntry, info->ToString()); - } -#endif // wxUSE_CONFIG - - return true; - } - //else: the user canceled the font selection dialog - } - else - { - // the user doesn't want to select a font for this encoding - // or selected to use equivalent encoding - // - // remember it to avoid asking the same question again later -#if wxUSE_CONFIG && wxUSE_FILECONFIG - wxFontMapperPathChanger path2(this, - FONTMAPPER_FONT_FROM_ENCODING_PATH); - if ( path2.IsOk() ) - { - GetConfig()->Write - ( - configEntry, - foundEquivEncoding ? info->ToString().c_str() - : FONTMAPPER_FONT_DONT_ASK - ); - } -#endif // wxUSE_CONFIG - } - } - //else: we're in non-interactive mode -#else - wxUnusedVar(equivEncoding); -#endif // wxUSE_FONTDLG - - return foundEquivEncoding; -} - -bool wxFontMapper::GetAltForEncoding(wxFontEncoding encoding, - wxFontEncoding *encodingAlt, - const wxString& facename, - bool interactive) -{ - wxCHECK_MSG( encodingAlt, false, - _T("wxFontEncoding::GetAltForEncoding(): NULL pointer") ); - - wxNativeEncodingInfo info; - if ( !GetAltForEncoding(encoding, &info, facename, interactive) ) - return false; - - *encodingAlt = info.encoding; - - return true; -} - -bool wxFontMapper::IsEncodingAvailable(wxFontEncoding encoding, - const wxString& facename) -{ - wxNativeEncodingInfo info; - - if ( !wxGetNativeFontEncoding(encoding, &info) ) - return false; - - info.facename = facename; - return wxTestFontEncoding(info); -} - -#endif // wxUSE_FONTMAP +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/fontmap.cpp +// Purpose: wxFontMapper class +// Author: Vadim Zeitlin +// Modified by: +// Created: 04.11.99 +// RCS-ID: $Id: fontmap.cpp 39651 2006-06-09 17:50:46Z ABX $ +// Copyright: (c) 1999-2003 Vadim Zeitlin +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_FONTMAP + +#include "wx/fontmap.h" + +#ifndef WX_PRECOMP + #include "wx/app.h" + #include "wx/log.h" + #include "wx/intl.h" + #include "wx/msgdlg.h" + #include "wx/choicdlg.h" +#endif // PCH + +#if wxUSE_CONFIG + #include "wx/config.h" +#endif // wxUSE_CONFIG + +#if defined(__WXMSW__) + #include "wx/msw/private.h" // includes windows.h for LOGFONT + #include "wx/msw/winundef.h" +#endif + +#include "wx/fmappriv.h" +#include "wx/fontutil.h" +#include "wx/fontdlg.h" +#include "wx/encinfo.h" + +#include "wx/encconv.h" + +#if wxUSE_EXTENDED_RTTI + +wxBEGIN_ENUM( wxFontEncoding ) + wxENUM_MEMBER( wxFONTENCODING_SYSTEM ) + wxENUM_MEMBER( wxFONTENCODING_DEFAULT ) + + wxENUM_MEMBER( wxFONTENCODING_ISO8859_1 ) + wxENUM_MEMBER( wxFONTENCODING_ISO8859_2 ) + wxENUM_MEMBER( wxFONTENCODING_ISO8859_3 ) + wxENUM_MEMBER( wxFONTENCODING_ISO8859_4 ) + wxENUM_MEMBER( wxFONTENCODING_ISO8859_5 ) + wxENUM_MEMBER( wxFONTENCODING_ISO8859_6 ) + wxENUM_MEMBER( wxFONTENCODING_ISO8859_7 ) + wxENUM_MEMBER( wxFONTENCODING_ISO8859_8 ) + wxENUM_MEMBER( wxFONTENCODING_ISO8859_9 ) + wxENUM_MEMBER( wxFONTENCODING_ISO8859_10 ) + wxENUM_MEMBER( wxFONTENCODING_ISO8859_11 ) + wxENUM_MEMBER( wxFONTENCODING_ISO8859_12 ) + wxENUM_MEMBER( wxFONTENCODING_ISO8859_13 ) + wxENUM_MEMBER( wxFONTENCODING_ISO8859_14 ) + wxENUM_MEMBER( wxFONTENCODING_ISO8859_15 ) + wxENUM_MEMBER( wxFONTENCODING_ISO8859_MAX ) + wxENUM_MEMBER( wxFONTENCODING_KOI8 ) + wxENUM_MEMBER( wxFONTENCODING_KOI8_U ) + wxENUM_MEMBER( wxFONTENCODING_ALTERNATIVE ) + wxENUM_MEMBER( wxFONTENCODING_BULGARIAN ) + wxENUM_MEMBER( wxFONTENCODING_CP437 ) + wxENUM_MEMBER( wxFONTENCODING_CP850 ) + wxENUM_MEMBER( wxFONTENCODING_CP852 ) + wxENUM_MEMBER( wxFONTENCODING_CP855 ) + wxENUM_MEMBER( wxFONTENCODING_CP866 ) + + wxENUM_MEMBER( wxFONTENCODING_CP874 ) + wxENUM_MEMBER( wxFONTENCODING_CP932 ) + wxENUM_MEMBER( wxFONTENCODING_CP936 ) + wxENUM_MEMBER( wxFONTENCODING_CP949 ) + wxENUM_MEMBER( wxFONTENCODING_CP950 ) + wxENUM_MEMBER( wxFONTENCODING_CP1250 ) + wxENUM_MEMBER( wxFONTENCODING_CP1251 ) + wxENUM_MEMBER( wxFONTENCODING_CP1252 ) + wxENUM_MEMBER( wxFONTENCODING_CP1253 ) + wxENUM_MEMBER( wxFONTENCODING_CP1254 ) + wxENUM_MEMBER( wxFONTENCODING_CP1255 ) + wxENUM_MEMBER( wxFONTENCODING_CP1256 ) + wxENUM_MEMBER( wxFONTENCODING_CP1257 ) + wxENUM_MEMBER( wxFONTENCODING_CP12_MAX ) + wxENUM_MEMBER( wxFONTENCODING_UTF7 ) + wxENUM_MEMBER( wxFONTENCODING_UTF8 ) + wxENUM_MEMBER( wxFONTENCODING_GB2312 ) + wxENUM_MEMBER( wxFONTENCODING_BIG5 ) + wxENUM_MEMBER( wxFONTENCODING_SHIFT_JIS ) + wxENUM_MEMBER( wxFONTENCODING_EUC_JP ) + wxENUM_MEMBER( wxFONTENCODING_UNICODE ) +wxEND_ENUM( wxFontEncoding ) +#endif + +// ---------------------------------------------------------------------------- +// constants +// ---------------------------------------------------------------------------- + +// the config paths we use +#if wxUSE_CONFIG + +static const wxChar* FONTMAPPER_FONT_FROM_ENCODING_PATH = wxT("Encodings"); +static const wxChar* FONTMAPPER_FONT_DONT_ASK = wxT("none"); + +#endif // wxUSE_CONFIG + +// ---------------------------------------------------------------------------- +// private classes +// ---------------------------------------------------------------------------- + +// it may happen that while we're showing a dialog asking the user about +// something, another request for an encoding mapping arrives: in this case it +// is best to not do anything because otherwise we risk to enter an infinite +// loop so we create an object of this class on stack to test for this in all +// interactive functions +class ReentrancyBlocker +{ +public: + ReentrancyBlocker(bool& flag) : m_flagOld(flag), m_flag(flag) + { m_flag = true; } + ~ReentrancyBlocker() { m_flag = m_flagOld; } + +private: + bool m_flagOld; + bool& m_flag; + + DECLARE_NO_COPY_CLASS(ReentrancyBlocker) +}; + +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// ctor and dtor +// ---------------------------------------------------------------------------- + +wxFontMapper::wxFontMapper() +{ + m_windowParent = NULL; +} + +wxFontMapper::~wxFontMapper() +{ +} + +/* static */ +wxFontMapper *wxFontMapper::Get() +{ + wxFontMapperBase *fontmapper = wxFontMapperBase::Get(); + wxASSERT_MSG( !fontmapper->IsDummy(), + wxT("GUI code requested a wxFontMapper but we only have a wxFontMapperBase.") ); + + // Now return it anyway because there's a chance the GUI code might just + // only want to call wxFontMapperBase functions and it's better than + // crashing by returning NULL + return (wxFontMapper *)fontmapper; +} + +wxFontEncoding +wxFontMapper::CharsetToEncoding(const wxString& charset, bool interactive) +{ + // try the ways not needing the users intervention first + int encoding = wxFontMapperBase::NonInteractiveCharsetToEncoding(charset); + + // if we failed to find the encoding, ask the user -- unless disabled + if ( encoding == wxFONTENCODING_UNKNOWN ) + { + // this is the special value which disables asking the user (he had + // chosen to suppress this the last time) + encoding = wxFONTENCODING_SYSTEM; + } +#if wxUSE_CHOICEDLG + else if ( (encoding == wxFONTENCODING_SYSTEM) && interactive ) + { + // prepare the dialog data + + // the dialog title + wxString title(m_titleDialog); + if ( !title ) + title << wxTheApp->GetAppName() << _(": unknown charset"); + + // the message + wxString msg; + msg.Printf(_("The charset '%s' is unknown. You may select\nanother charset to replace it with or choose\n[Cancel] if it cannot be replaced"), charset.c_str()); + + // the list of choices + const size_t count = GetSupportedEncodingsCount(); + + wxString *encodingNamesTranslated = new wxString[count]; + + for ( size_t i = 0; i < count; i++ ) + { + encodingNamesTranslated[i] = GetEncodingDescription(GetEncoding(i)); + } + + // the parent window + wxWindow *parent = m_windowParent; + if ( !parent ) + parent = wxTheApp->GetTopWindow(); + + // do ask the user and get back the index in encodings table + int n = wxGetSingleChoiceIndex(msg, title, + count, + encodingNamesTranslated, + parent); + + delete [] encodingNamesTranslated; + + if ( n != -1 ) + { + encoding = GetEncoding(n); + } + +#if wxUSE_CONFIG && wxUSE_FILECONFIG + // save the result in the config now + wxFontMapperPathChanger path(this, FONTMAPPER_CHARSET_PATH); + if ( path.IsOk() ) + { + wxConfigBase *config = GetConfig(); + + // remember the alt encoding for this charset -- or remember that + // we don't know it + long value = n == -1 ? (long)wxFONTENCODING_UNKNOWN : (long)encoding; + if ( !config->Write(charset, value) ) + { + wxLogError(_("Failed to remember the encoding for the charset '%s'."), charset.c_str()); + } + } +#endif // wxUSE_CONFIG + } +#else + wxUnusedVar(interactive); +#endif // wxUSE_CHOICEDLG + + return (wxFontEncoding)encoding; +} + +// ---------------------------------------------------------------------------- +// support for unknown encodings: we maintain a map between the +// (platform-specific) strings identifying them and our wxFontEncodings they +// correspond to which is used by GetFontForEncoding() function +// ---------------------------------------------------------------------------- + +bool wxFontMapper::TestAltEncoding(const wxString& configEntry, + wxFontEncoding encReplacement, + wxNativeEncodingInfo *info) +{ + if ( wxGetNativeFontEncoding(encReplacement, info) && + wxTestFontEncoding(*info) ) + { +#if wxUSE_CONFIG && wxUSE_FILECONFIG + // remember the mapping in the config + wxFontMapperPathChanger path(this, FONTMAPPER_FONT_FROM_ENCODING_PATH); + + if ( path.IsOk() ) + { + GetConfig()->Write(configEntry, info->ToString()); + } +#else + wxUnusedVar(configEntry); +#endif // wxUSE_CONFIG + return true; + } + + return false; +} + +bool wxFontMapper::GetAltForEncoding(wxFontEncoding encoding, + wxNativeEncodingInfo *info, + const wxString& facename, + bool interactive) +{ +#if wxUSE_GUI + // we need a flag to prevent infinite recursion which happens, for + // example, when GetAltForEncoding() is called from an OnPaint() handler: + // in this case, wxYield() which is called from wxMessageBox() we use here + // will lead to another call of OnPaint() and hence to another call of + // GetAltForEncoding() -- and it is impossible to catch this from the user + // code because we are called from wxFont ctor implicitly. + + // assume we're always called from the main thread, so that it is safe to + // use a static var + static bool s_inGetAltForEncoding = false; + + if ( interactive && s_inGetAltForEncoding ) + return false; + + ReentrancyBlocker blocker(s_inGetAltForEncoding); +#endif // wxUSE_GUI + + wxCHECK_MSG( info, false, wxT("bad pointer in GetAltForEncoding") ); + + info->facename = facename; + + if ( encoding == wxFONTENCODING_DEFAULT ) + { + encoding = wxFont::GetDefaultEncoding(); + } + + // if we failed to load the system default encoding, something is really + // wrong and we'd better stop now -- otherwise we will go into endless + // recursion trying to create the font in the msg box with the error + // message + if ( encoding == wxFONTENCODING_SYSTEM ) + { + wxLogFatalError(_("can't load any font, aborting")); + + // wxLogFatalError doesn't return + } + + wxString configEntry, + encName = GetEncodingName(encoding); + if ( !facename.empty() ) + { + configEntry = facename + _T("_"); + } + configEntry += encName; + +#if wxUSE_CONFIG && wxUSE_FILECONFIG + // do we have a font spec for this encoding? + wxString fontinfo; + wxFontMapperPathChanger path(this, FONTMAPPER_FONT_FROM_ENCODING_PATH); + if ( path.IsOk() ) + { + fontinfo = GetConfig()->Read(configEntry); + } + + // this special value means that we don't know of fonts for this + // encoding but, moreover, have already asked the user as well and he + // didn't specify any font neither + if ( fontinfo == FONTMAPPER_FONT_DONT_ASK ) + { + interactive = false; + } + else // use the info entered the last time + { + if ( !fontinfo.empty() && !facename.empty() ) + { + // we tried to find a match with facename -- now try without it + fontinfo = GetConfig()->Read(encName); + } + + if ( !fontinfo.empty() ) + { + if ( info->FromString(fontinfo) ) + { + if ( wxTestFontEncoding(*info) ) + { + // ok, got something + return true; + } + //else: no such fonts, look for something else + // (should we erase the outdated value?) + } + else + { + wxLogDebug(wxT("corrupted config data: string '%s' is not a valid font encoding info"), + fontinfo.c_str()); + } + } + //else: there is no information in config about this encoding + } +#endif // wxUSE_CONFIG + + // now try to map this encoding to a compatible one which we have on this + // system + wxFontEncodingArray equiv = wxEncodingConverter::GetAllEquivalents(encoding); + size_t count = equiv.GetCount(); + bool foundEquivEncoding = false; + wxFontEncoding equivEncoding = wxFONTENCODING_SYSTEM; + if ( count ) + { + for ( size_t i = 0; i < count && !foundEquivEncoding; i++ ) + { + // don't test for encoding itself, we already know we don't have it + if ( equiv[i] == encoding ) + continue; + + if ( TestAltEncoding(configEntry, equiv[i], info) ) + { + equivEncoding = equiv[i]; + + foundEquivEncoding = true; + } + } + } + + // ask the user +#if wxUSE_FONTDLG + if ( interactive ) + { + wxString title(m_titleDialog); + if ( !title ) + title << wxTheApp->GetAppName() << _(": unknown encoding"); + + // built the message + wxString encDesc = GetEncodingDescription(encoding), + msg; + if ( foundEquivEncoding ) + { + // ask the user if he wants to override found alternative encoding + msg.Printf(_("No font for displaying text in encoding '%s' found,\nbut an alternative encoding '%s' is available.\nDo you want to use this encoding (otherwise you will have to choose another one)?"), + encDesc.c_str(), GetEncodingDescription(equivEncoding).c_str()); + } + else + { + msg.Printf(_("No font for displaying text in encoding '%s' found.\nWould you like to select a font to be used for this encoding\n(otherwise the text in this encoding will not be shown correctly)?"), + encDesc.c_str()); + } + + // the question is different in 2 cases so the answer has to be + // interpreted differently as well + int answer = foundEquivEncoding ? wxNO : wxYES; + + if ( wxMessageBox(msg, title, + wxICON_QUESTION | wxYES_NO, + m_windowParent) == answer ) + { + wxFontData data; + data.SetEncoding(encoding); + data.EncodingInfo() = *info; + wxFontDialog dialog(m_windowParent, data); + if ( dialog.ShowModal() == wxID_OK ) + { + wxFontData retData = dialog.GetFontData(); + + *info = retData.EncodingInfo(); + info->encoding = retData.GetEncoding(); + +#if wxUSE_CONFIG && wxUSE_FILECONFIG + // remember this in the config + wxFontMapperPathChanger path2(this, + FONTMAPPER_FONT_FROM_ENCODING_PATH); + if ( path2.IsOk() ) + { + GetConfig()->Write(configEntry, info->ToString()); + } +#endif // wxUSE_CONFIG + + return true; + } + //else: the user canceled the font selection dialog + } + else + { + // the user doesn't want to select a font for this encoding + // or selected to use equivalent encoding + // + // remember it to avoid asking the same question again later +#if wxUSE_CONFIG && wxUSE_FILECONFIG + wxFontMapperPathChanger path2(this, + FONTMAPPER_FONT_FROM_ENCODING_PATH); + if ( path2.IsOk() ) + { + GetConfig()->Write + ( + configEntry, + foundEquivEncoding ? info->ToString().c_str() + : FONTMAPPER_FONT_DONT_ASK + ); + } +#endif // wxUSE_CONFIG + } + } + //else: we're in non-interactive mode +#else + wxUnusedVar(equivEncoding); +#endif // wxUSE_FONTDLG + + return foundEquivEncoding; +} + +bool wxFontMapper::GetAltForEncoding(wxFontEncoding encoding, + wxFontEncoding *encodingAlt, + const wxString& facename, + bool interactive) +{ + wxCHECK_MSG( encodingAlt, false, + _T("wxFontEncoding::GetAltForEncoding(): NULL pointer") ); + + wxNativeEncodingInfo info; + if ( !GetAltForEncoding(encoding, &info, facename, interactive) ) + return false; + + *encodingAlt = info.encoding; + + return true; +} + +bool wxFontMapper::IsEncodingAvailable(wxFontEncoding encoding, + const wxString& facename) +{ + wxNativeEncodingInfo info; + + if ( !wxGetNativeFontEncoding(encoding, &info) ) + return false; + + info.facename = facename; + return wxTestFontEncoding(info); +} + +#endif // wxUSE_FONTMAP diff --git a/Externals/wxWidgets/src/common/fontmgrcmn.cpp b/Externals/wxWidgets/src/common/fontmgrcmn.cpp index 0ade79e254..eb1e6b7cbc 100644 --- a/Externals/wxWidgets/src/common/fontmgrcmn.cpp +++ b/Externals/wxWidgets/src/common/fontmgrcmn.cpp @@ -1,345 +1,345 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/fontmgrcmn.cpp -// Purpose: font management for ports that don't have their own -// Author: Vaclav Slavik -// Created: 2006-11-18 -// RCS-ID: $Id: fontmgrcmn.cpp 43550 2006-11-20 20:45:57Z VS $ -// Copyright: (c) 2001-2002 SciTech Software, Inc. (www.scitechsoft.com) -// (c) 2006 REA Elektronik GmbH -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#include "wx/private/fontmgr.h" - -#include "wx/listimpl.cpp" -#include "wx/hashmap.h" - -WX_DECLARE_LIST(wxFontInstance, wxFontInstanceList); -WX_DEFINE_LIST(wxFontInstanceList) -WX_DEFINE_LIST(wxFontBundleList) -WX_DECLARE_HASH_MAP(wxString, wxFontBundle*, - wxStringHash, wxStringEqual, - wxFontBundleHash); - -// ============================================================================ -// implementation -// ============================================================================ - -// ---------------------------------------------------------------------------- -// wxFontFaceBase -// ---------------------------------------------------------------------------- - -wxFontFaceBase::wxFontFaceBase() - : m_refCnt(0) -{ - m_instances = new wxFontInstanceList; - m_instances->DeleteContents(true); -} - -wxFontFaceBase::~wxFontFaceBase() -{ - delete m_instances; -} - -void wxFontFaceBase::Acquire() -{ - m_refCnt++; -} - -void wxFontFaceBase::Release() -{ - if ( --m_refCnt == 0 ) - { - m_instances->Clear(); - } -} - -wxFontInstance *wxFontFaceBase::GetFontInstance(float ptSize, bool aa) -{ - wxASSERT_MSG( m_refCnt > 0, _T("font library not loaded!") ); - - wxFontInstance *i; - wxFontInstanceList::Node *node; - - for ( node = m_instances->GetFirst(); node; node = node->GetNext() ) - { - i = node->GetData(); - if ( i->GetPointSize() == ptSize && i->IsAntiAliased() == aa ) - return i; - } - - i = CreateFontInstance(ptSize, aa); - m_instances->Append(i); - return i; -} - -// ---------------------------------------------------------------------------- -// wxFontBundleBase -// ---------------------------------------------------------------------------- - -wxFontBundleBase::wxFontBundleBase() -{ - for (int i = 0; i < FaceType_Max; i++) - m_faces[i] = NULL; -} - -wxFontBundleBase::~wxFontBundleBase() -{ - for (int i = 0; i < FaceType_Max; i++) - delete m_faces[i]; -} - -wxFontFace *wxFontBundleBase::GetFace(FaceType type) const -{ - wxFontFace *f = m_faces[type]; - - wxCHECK_MSG( f, NULL, _T("no such face in font bundle") ); - - f->Acquire(); - - return f; -} - -wxFontFace * -wxFontBundleBase::GetFaceForFont(const wxFontMgrFontRefData& font) const -{ - wxASSERT_MSG( font.GetFaceName().empty() || font.GetFaceName() == GetName(), - _T("calling GetFaceForFont for incompatible font") ); - - int type = FaceType_Regular; - - if ( font.GetWeight() == wxBOLD ) - type |= FaceType_Bold; - - // FIXME -- this should read "if ( font->GetStyle() == wxITALIC )", - // but since MGL neither DFB supports slant, we try to display it with - // italic face (better than nothing...) - if ( font.GetStyle() == wxITALIC || font.GetStyle() == wxSLANT ) - { - if ( HasFace((FaceType)(type | FaceType_Italic)) ) - type |= FaceType_Italic; - } - - if ( !HasFace((FaceType)type) ) - { - for (int i = 0; i < FaceType_Max; i++) - { - if ( HasFace((FaceType)i) ) - return GetFace((FaceType)i); - } - - wxFAIL_MSG( _T("no face") ); - return NULL; - } - - return GetFace((FaceType)type); -} - -// ---------------------------------------------------------------------------- -// wxFontsManagerBase -// ---------------------------------------------------------------------------- - -wxFontsManager *wxFontsManagerBase::ms_instance = NULL; - -wxFontsManagerBase::wxFontsManagerBase() -{ - m_hash = new wxFontBundleHash(); - m_list = new wxFontBundleList; - m_list->DeleteContents(true); -} - -wxFontsManagerBase::~wxFontsManagerBase() -{ - delete m_hash; - delete m_list; -} - -/* static */ -wxFontsManager *wxFontsManagerBase::Get() -{ - if ( !ms_instance ) - ms_instance = new wxFontsManager(); - return ms_instance; -} - -/* static */ -void wxFontsManagerBase::CleanUp() -{ - wxDELETE(ms_instance); -} - -wxFontBundle *wxFontsManagerBase::GetBundle(const wxString& name) const -{ - return (*m_hash)[name.Lower()]; -} - -wxFontBundle * -wxFontsManagerBase::GetBundleForFont(const wxFontMgrFontRefData& font) const -{ - wxFontBundle *bundle = NULL; - - wxString facename = font.GetFaceName(); - if ( !facename.empty() ) - bundle = GetBundle(facename); - - if ( !bundle ) - { - facename = GetDefaultFacename((wxFontFamily)font.GetFamily()); - if ( !facename.empty() ) - bundle = GetBundle(facename); - } - - if ( !bundle ) - { - if ( m_list->GetFirst() ) - bundle = m_list->GetFirst()->GetData(); - else - wxFAIL_MSG(wxT("Fatal error, no fonts available!")); - } - - return bundle; -} - -void wxFontsManagerBase::AddBundle(wxFontBundle *bundle) -{ - (*m_hash)[bundle->GetName().Lower()] = bundle; - m_list->Append(bundle); -} - - -// ---------------------------------------------------------------------------- -// wxFontMgrFontRefData -// ---------------------------------------------------------------------------- - -wxFontMgrFontRefData::wxFontMgrFontRefData(int size, - int family, - int style, - int weight, - bool underlined, - const wxString& faceName, - wxFontEncoding encoding) -{ - if ( family == wxDEFAULT ) - family = wxSWISS; - if ( style == wxDEFAULT ) - style = wxNORMAL; - if ( weight == wxDEFAULT ) - weight = wxNORMAL; - if ( size == wxDEFAULT ) - size = 12; - - m_info.family = (wxFontFamily)family; - m_info.faceName = faceName; - m_info.style = (wxFontStyle)style; - m_info.weight = (wxFontWeight)weight; - m_info.pointSize = size; - m_info.underlined = underlined; - m_info.encoding = encoding; - - m_noAA = false; - - m_fontFace = NULL; - m_fontBundle = NULL; - m_fontValid = false; -} - -wxFontMgrFontRefData::wxFontMgrFontRefData(const wxFontMgrFontRefData& data) -{ - m_info = data.m_info; - m_noAA = data.m_noAA; - - m_fontFace = data.m_fontFace; - m_fontBundle = data.m_fontBundle; - m_fontValid = data.m_fontValid; - if ( m_fontFace ) - m_fontFace->Acquire(); -} - -wxFontMgrFontRefData::~wxFontMgrFontRefData() -{ - if ( m_fontFace ) - m_fontFace->Release(); -} - -wxFontBundle *wxFontMgrFontRefData::GetFontBundle() const -{ - wxConstCast(this, wxFontMgrFontRefData)->EnsureValidFont(); - return m_fontBundle; -} - -wxFontInstance * -wxFontMgrFontRefData::GetFontInstance(float scale, bool antialiased) const -{ - wxConstCast(this, wxFontMgrFontRefData)->EnsureValidFont(); - return m_fontFace->GetFontInstance(m_info.pointSize * scale, - antialiased && !m_noAA); -} - -void wxFontMgrFontRefData::SetPointSize(int pointSize) -{ - m_info.pointSize = pointSize; - m_fontValid = false; -} - -void wxFontMgrFontRefData::SetFamily(int family) -{ - m_info.family = (wxFontFamily)family; - m_fontValid = false; -} - -void wxFontMgrFontRefData::SetStyle(int style) -{ - m_info.style = (wxFontStyle)style; - m_fontValid = false; -} - -void wxFontMgrFontRefData::SetWeight(int weight) -{ - m_info.weight = (wxFontWeight)weight; - m_fontValid = false; -} - -void wxFontMgrFontRefData::SetFaceName(const wxString& faceName) -{ - m_info.faceName = faceName; - m_fontValid = false; -} - -void wxFontMgrFontRefData::SetUnderlined(bool underlined) -{ - m_info.underlined = underlined; - m_fontValid = false; -} - -void wxFontMgrFontRefData::SetEncoding(wxFontEncoding encoding) -{ - m_info.encoding = encoding; - m_fontValid = false; -} - -void wxFontMgrFontRefData::SetNoAntiAliasing(bool no) -{ - m_noAA = no; -} - - -void wxFontMgrFontRefData::EnsureValidFont() -{ - if ( !m_fontValid ) - { - wxFontFace *old = m_fontFace; - - m_fontBundle = wxFontsManager::Get()->GetBundleForFont(*this); - m_fontFace = m_fontBundle->GetFaceForFont(*this); - - if ( old ) - old->Release(); - } -} +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/fontmgrcmn.cpp +// Purpose: font management for ports that don't have their own +// Author: Vaclav Slavik +// Created: 2006-11-18 +// RCS-ID: $Id: fontmgrcmn.cpp 43550 2006-11-20 20:45:57Z VS $ +// Copyright: (c) 2001-2002 SciTech Software, Inc. (www.scitechsoft.com) +// (c) 2006 REA Elektronik GmbH +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#include "wx/private/fontmgr.h" + +#include "wx/listimpl.cpp" +#include "wx/hashmap.h" + +WX_DECLARE_LIST(wxFontInstance, wxFontInstanceList); +WX_DEFINE_LIST(wxFontInstanceList) +WX_DEFINE_LIST(wxFontBundleList) +WX_DECLARE_HASH_MAP(wxString, wxFontBundle*, + wxStringHash, wxStringEqual, + wxFontBundleHash); + +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// wxFontFaceBase +// ---------------------------------------------------------------------------- + +wxFontFaceBase::wxFontFaceBase() + : m_refCnt(0) +{ + m_instances = new wxFontInstanceList; + m_instances->DeleteContents(true); +} + +wxFontFaceBase::~wxFontFaceBase() +{ + delete m_instances; +} + +void wxFontFaceBase::Acquire() +{ + m_refCnt++; +} + +void wxFontFaceBase::Release() +{ + if ( --m_refCnt == 0 ) + { + m_instances->Clear(); + } +} + +wxFontInstance *wxFontFaceBase::GetFontInstance(float ptSize, bool aa) +{ + wxASSERT_MSG( m_refCnt > 0, _T("font library not loaded!") ); + + wxFontInstance *i; + wxFontInstanceList::Node *node; + + for ( node = m_instances->GetFirst(); node; node = node->GetNext() ) + { + i = node->GetData(); + if ( i->GetPointSize() == ptSize && i->IsAntiAliased() == aa ) + return i; + } + + i = CreateFontInstance(ptSize, aa); + m_instances->Append(i); + return i; +} + +// ---------------------------------------------------------------------------- +// wxFontBundleBase +// ---------------------------------------------------------------------------- + +wxFontBundleBase::wxFontBundleBase() +{ + for (int i = 0; i < FaceType_Max; i++) + m_faces[i] = NULL; +} + +wxFontBundleBase::~wxFontBundleBase() +{ + for (int i = 0; i < FaceType_Max; i++) + delete m_faces[i]; +} + +wxFontFace *wxFontBundleBase::GetFace(FaceType type) const +{ + wxFontFace *f = m_faces[type]; + + wxCHECK_MSG( f, NULL, _T("no such face in font bundle") ); + + f->Acquire(); + + return f; +} + +wxFontFace * +wxFontBundleBase::GetFaceForFont(const wxFontMgrFontRefData& font) const +{ + wxASSERT_MSG( font.GetFaceName().empty() || font.GetFaceName() == GetName(), + _T("calling GetFaceForFont for incompatible font") ); + + int type = FaceType_Regular; + + if ( font.GetWeight() == wxBOLD ) + type |= FaceType_Bold; + + // FIXME -- this should read "if ( font->GetStyle() == wxITALIC )", + // but since MGL neither DFB supports slant, we try to display it with + // italic face (better than nothing...) + if ( font.GetStyle() == wxITALIC || font.GetStyle() == wxSLANT ) + { + if ( HasFace((FaceType)(type | FaceType_Italic)) ) + type |= FaceType_Italic; + } + + if ( !HasFace((FaceType)type) ) + { + for (int i = 0; i < FaceType_Max; i++) + { + if ( HasFace((FaceType)i) ) + return GetFace((FaceType)i); + } + + wxFAIL_MSG( _T("no face") ); + return NULL; + } + + return GetFace((FaceType)type); +} + +// ---------------------------------------------------------------------------- +// wxFontsManagerBase +// ---------------------------------------------------------------------------- + +wxFontsManager *wxFontsManagerBase::ms_instance = NULL; + +wxFontsManagerBase::wxFontsManagerBase() +{ + m_hash = new wxFontBundleHash(); + m_list = new wxFontBundleList; + m_list->DeleteContents(true); +} + +wxFontsManagerBase::~wxFontsManagerBase() +{ + delete m_hash; + delete m_list; +} + +/* static */ +wxFontsManager *wxFontsManagerBase::Get() +{ + if ( !ms_instance ) + ms_instance = new wxFontsManager(); + return ms_instance; +} + +/* static */ +void wxFontsManagerBase::CleanUp() +{ + wxDELETE(ms_instance); +} + +wxFontBundle *wxFontsManagerBase::GetBundle(const wxString& name) const +{ + return (*m_hash)[name.Lower()]; +} + +wxFontBundle * +wxFontsManagerBase::GetBundleForFont(const wxFontMgrFontRefData& font) const +{ + wxFontBundle *bundle = NULL; + + wxString facename = font.GetFaceName(); + if ( !facename.empty() ) + bundle = GetBundle(facename); + + if ( !bundle ) + { + facename = GetDefaultFacename((wxFontFamily)font.GetFamily()); + if ( !facename.empty() ) + bundle = GetBundle(facename); + } + + if ( !bundle ) + { + if ( m_list->GetFirst() ) + bundle = m_list->GetFirst()->GetData(); + else + wxFAIL_MSG(wxT("Fatal error, no fonts available!")); + } + + return bundle; +} + +void wxFontsManagerBase::AddBundle(wxFontBundle *bundle) +{ + (*m_hash)[bundle->GetName().Lower()] = bundle; + m_list->Append(bundle); +} + + +// ---------------------------------------------------------------------------- +// wxFontMgrFontRefData +// ---------------------------------------------------------------------------- + +wxFontMgrFontRefData::wxFontMgrFontRefData(int size, + int family, + int style, + int weight, + bool underlined, + const wxString& faceName, + wxFontEncoding encoding) +{ + if ( family == wxDEFAULT ) + family = wxSWISS; + if ( style == wxDEFAULT ) + style = wxNORMAL; + if ( weight == wxDEFAULT ) + weight = wxNORMAL; + if ( size == wxDEFAULT ) + size = 12; + + m_info.family = (wxFontFamily)family; + m_info.faceName = faceName; + m_info.style = (wxFontStyle)style; + m_info.weight = (wxFontWeight)weight; + m_info.pointSize = size; + m_info.underlined = underlined; + m_info.encoding = encoding; + + m_noAA = false; + + m_fontFace = NULL; + m_fontBundle = NULL; + m_fontValid = false; +} + +wxFontMgrFontRefData::wxFontMgrFontRefData(const wxFontMgrFontRefData& data) +{ + m_info = data.m_info; + m_noAA = data.m_noAA; + + m_fontFace = data.m_fontFace; + m_fontBundle = data.m_fontBundle; + m_fontValid = data.m_fontValid; + if ( m_fontFace ) + m_fontFace->Acquire(); +} + +wxFontMgrFontRefData::~wxFontMgrFontRefData() +{ + if ( m_fontFace ) + m_fontFace->Release(); +} + +wxFontBundle *wxFontMgrFontRefData::GetFontBundle() const +{ + wxConstCast(this, wxFontMgrFontRefData)->EnsureValidFont(); + return m_fontBundle; +} + +wxFontInstance * +wxFontMgrFontRefData::GetFontInstance(float scale, bool antialiased) const +{ + wxConstCast(this, wxFontMgrFontRefData)->EnsureValidFont(); + return m_fontFace->GetFontInstance(m_info.pointSize * scale, + antialiased && !m_noAA); +} + +void wxFontMgrFontRefData::SetPointSize(int pointSize) +{ + m_info.pointSize = pointSize; + m_fontValid = false; +} + +void wxFontMgrFontRefData::SetFamily(int family) +{ + m_info.family = (wxFontFamily)family; + m_fontValid = false; +} + +void wxFontMgrFontRefData::SetStyle(int style) +{ + m_info.style = (wxFontStyle)style; + m_fontValid = false; +} + +void wxFontMgrFontRefData::SetWeight(int weight) +{ + m_info.weight = (wxFontWeight)weight; + m_fontValid = false; +} + +void wxFontMgrFontRefData::SetFaceName(const wxString& faceName) +{ + m_info.faceName = faceName; + m_fontValid = false; +} + +void wxFontMgrFontRefData::SetUnderlined(bool underlined) +{ + m_info.underlined = underlined; + m_fontValid = false; +} + +void wxFontMgrFontRefData::SetEncoding(wxFontEncoding encoding) +{ + m_info.encoding = encoding; + m_fontValid = false; +} + +void wxFontMgrFontRefData::SetNoAntiAliasing(bool no) +{ + m_noAA = no; +} + + +void wxFontMgrFontRefData::EnsureValidFont() +{ + if ( !m_fontValid ) + { + wxFontFace *old = m_fontFace; + + m_fontBundle = wxFontsManager::Get()->GetBundleForFont(*this); + m_fontFace = m_fontBundle->GetFaceForFont(*this); + + if ( old ) + old->Release(); + } +} diff --git a/Externals/wxWidgets/src/common/fontpickercmn.cpp b/Externals/wxWidgets/src/common/fontpickercmn.cpp index 08808e996c..c4af53f25c 100644 --- a/Externals/wxWidgets/src/common/fontpickercmn.cpp +++ b/Externals/wxWidgets/src/common/fontpickercmn.cpp @@ -1,181 +1,181 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: src/common/fontpickercmn.cpp -// Purpose: wxFontPickerCtrl class implementation -// Author: Francesco Montorsi -// Modified by: -// Created: 15/04/2006 -// RCS-ID: $Id: fontpickercmn.cpp 42999 2006-11-03 21:54:13Z VZ $ -// Copyright: (c) Francesco Montorsi -// Licence: wxWindows licence -/////////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_FONTPICKERCTRL - -#include "wx/fontpicker.h" - -#ifndef WX_PRECOMP - #include "wx/textctrl.h" -#endif - -#include "wx/fontenum.h" -#include "wx/tokenzr.h" - -// ============================================================================ -// implementation -// ============================================================================ - -const wxChar wxFontPickerCtrlNameStr[] = wxT("fontpicker"); -const wxChar wxFontPickerWidgetNameStr[] = wxT("fontpickerwidget"); - -DEFINE_EVENT_TYPE(wxEVT_COMMAND_FONTPICKER_CHANGED) -IMPLEMENT_DYNAMIC_CLASS(wxFontPickerCtrl, wxPickerBase) -IMPLEMENT_DYNAMIC_CLASS(wxFontPickerEvent, wxCommandEvent) - -// ---------------------------------------------------------------------------- -// wxFontPickerCtrl -// ---------------------------------------------------------------------------- - -#define M_PICKER ((wxFontPickerWidget*)m_picker) - -bool wxFontPickerCtrl::Create( wxWindow *parent, wxWindowID id, - const wxFont &initial, - const wxPoint &pos, const wxSize &size, - long style, const wxValidator& validator, - const wxString &name ) -{ - if (!wxPickerBase::CreateBase(parent, id, - Font2String(initial.IsOk() ? initial - : *wxNORMAL_FONT), - pos, size, style, validator, name)) - return false; - - // the picker of a wxFontPickerCtrl is a wxFontPickerWidget - m_picker = new wxFontPickerWidget(this, wxID_ANY, initial, - wxDefaultPosition, wxDefaultSize, - GetPickerStyle(style)); - // complete sizer creation - wxPickerBase::PostCreation(); - - m_picker->Connect(wxEVT_COMMAND_FONTPICKER_CHANGED, - wxFontPickerEventHandler(wxFontPickerCtrl::OnFontChange), - NULL, this); - - return true; -} - -wxString wxFontPickerCtrl::Font2String(const wxFont &f) -{ - wxString ret = f.GetNativeFontInfoUserDesc(); -#ifdef __WXMSW__ - // on wxMSW the encoding of the font is appended at the end of the string; - // since encoding is not very user-friendly we remove it. - wxFontEncoding enc = f.GetEncoding(); - if ( enc != wxFONTENCODING_DEFAULT && enc != wxFONTENCODING_SYSTEM ) - ret = ret.BeforeLast(wxT(' ')); -#endif - return ret; -} - -wxFont wxFontPickerCtrl::String2Font(const wxString &s) -{ - wxString str(s); - wxFont ret; - double n; - - // put a limit on the maximum point size which the user can enter - // NOTE: we suppose the last word of given string is the pointsize - wxString size = str.AfterLast(wxT(' ')); - if (size.ToDouble(&n)) - { - if (n < 1) - str = str.Left(str.length() - size.length()) + wxT("1"); - else if (n >= m_nMaxPointSize) - str = str.Left(str.length() - size.length()) + - wxString::Format(wxT("%d"), m_nMaxPointSize); - } - - if (!ret.SetNativeFontInfoUserDesc(str)) - return wxNullFont; - - return ret; -} - -void wxFontPickerCtrl::SetSelectedFont(const wxFont &f) -{ - M_PICKER->SetSelectedFont(f); - UpdateTextCtrlFromPicker(); -} - -void wxFontPickerCtrl::UpdatePickerFromTextCtrl() -{ - wxASSERT(m_text); - - if (m_bIgnoreNextTextCtrlUpdate) - { - // ignore this update - m_bIgnoreNextTextCtrlUpdate = false; - return; - } - - // NB: we don't use the wxFont::wxFont(const wxString &) constructor - // since that constructor expects the native font description - // string returned by wxFont::GetNativeFontInfoDesc() and not - // the user-friendly one returned by wxFont::GetNativeFontInfoUserDesc() - wxFont f = String2Font(m_text->GetValue()); - if (!f.Ok()) - return; // invalid user input - - if (M_PICKER->GetSelectedFont() != f) - { - M_PICKER->SetSelectedFont(f); - - // fire an event - wxFontPickerEvent event(this, GetId(), f); - GetEventHandler()->ProcessEvent(event); - } -} - -void wxFontPickerCtrl::UpdateTextCtrlFromPicker() -{ - if (!m_text) - return; // no textctrl to update - - // NOTE: this SetValue() will generate an unwanted wxEVT_COMMAND_TEXT_UPDATED - // which will trigger a unneeded UpdateFromTextCtrl(); thus before using - // SetValue() we set the m_bIgnoreNextTextCtrlUpdate flag... - m_bIgnoreNextTextCtrlUpdate = true; - m_text->SetValue(Font2String(M_PICKER->GetSelectedFont())); -} - - - -// ---------------------------------------------------------------------------- -// wxFontPickerCtrl - event handlers -// ---------------------------------------------------------------------------- - -void wxFontPickerCtrl::OnFontChange(wxFontPickerEvent &ev) -{ - UpdateTextCtrlFromPicker(); - - // the wxFontPickerWidget sent us a colour-change notification. - // forward this event to our parent - wxFontPickerEvent event(this, GetId(), ev.GetFont()); - GetEventHandler()->ProcessEvent(event); -} - -#endif // wxUSE_FONTPICKERCTRL +/////////////////////////////////////////////////////////////////////////////// +// Name: src/common/fontpickercmn.cpp +// Purpose: wxFontPickerCtrl class implementation +// Author: Francesco Montorsi +// Modified by: +// Created: 15/04/2006 +// RCS-ID: $Id: fontpickercmn.cpp 42999 2006-11-03 21:54:13Z VZ $ +// Copyright: (c) Francesco Montorsi +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_FONTPICKERCTRL + +#include "wx/fontpicker.h" + +#ifndef WX_PRECOMP + #include "wx/textctrl.h" +#endif + +#include "wx/fontenum.h" +#include "wx/tokenzr.h" + +// ============================================================================ +// implementation +// ============================================================================ + +const wxChar wxFontPickerCtrlNameStr[] = wxT("fontpicker"); +const wxChar wxFontPickerWidgetNameStr[] = wxT("fontpickerwidget"); + +DEFINE_EVENT_TYPE(wxEVT_COMMAND_FONTPICKER_CHANGED) +IMPLEMENT_DYNAMIC_CLASS(wxFontPickerCtrl, wxPickerBase) +IMPLEMENT_DYNAMIC_CLASS(wxFontPickerEvent, wxCommandEvent) + +// ---------------------------------------------------------------------------- +// wxFontPickerCtrl +// ---------------------------------------------------------------------------- + +#define M_PICKER ((wxFontPickerWidget*)m_picker) + +bool wxFontPickerCtrl::Create( wxWindow *parent, wxWindowID id, + const wxFont &initial, + const wxPoint &pos, const wxSize &size, + long style, const wxValidator& validator, + const wxString &name ) +{ + if (!wxPickerBase::CreateBase(parent, id, + Font2String(initial.IsOk() ? initial + : *wxNORMAL_FONT), + pos, size, style, validator, name)) + return false; + + // the picker of a wxFontPickerCtrl is a wxFontPickerWidget + m_picker = new wxFontPickerWidget(this, wxID_ANY, initial, + wxDefaultPosition, wxDefaultSize, + GetPickerStyle(style)); + // complete sizer creation + wxPickerBase::PostCreation(); + + m_picker->Connect(wxEVT_COMMAND_FONTPICKER_CHANGED, + wxFontPickerEventHandler(wxFontPickerCtrl::OnFontChange), + NULL, this); + + return true; +} + +wxString wxFontPickerCtrl::Font2String(const wxFont &f) +{ + wxString ret = f.GetNativeFontInfoUserDesc(); +#ifdef __WXMSW__ + // on wxMSW the encoding of the font is appended at the end of the string; + // since encoding is not very user-friendly we remove it. + wxFontEncoding enc = f.GetEncoding(); + if ( enc != wxFONTENCODING_DEFAULT && enc != wxFONTENCODING_SYSTEM ) + ret = ret.BeforeLast(wxT(' ')); +#endif + return ret; +} + +wxFont wxFontPickerCtrl::String2Font(const wxString &s) +{ + wxString str(s); + wxFont ret; + double n; + + // put a limit on the maximum point size which the user can enter + // NOTE: we suppose the last word of given string is the pointsize + wxString size = str.AfterLast(wxT(' ')); + if (size.ToDouble(&n)) + { + if (n < 1) + str = str.Left(str.length() - size.length()) + wxT("1"); + else if (n >= m_nMaxPointSize) + str = str.Left(str.length() - size.length()) + + wxString::Format(wxT("%d"), m_nMaxPointSize); + } + + if (!ret.SetNativeFontInfoUserDesc(str)) + return wxNullFont; + + return ret; +} + +void wxFontPickerCtrl::SetSelectedFont(const wxFont &f) +{ + M_PICKER->SetSelectedFont(f); + UpdateTextCtrlFromPicker(); +} + +void wxFontPickerCtrl::UpdatePickerFromTextCtrl() +{ + wxASSERT(m_text); + + if (m_bIgnoreNextTextCtrlUpdate) + { + // ignore this update + m_bIgnoreNextTextCtrlUpdate = false; + return; + } + + // NB: we don't use the wxFont::wxFont(const wxString &) constructor + // since that constructor expects the native font description + // string returned by wxFont::GetNativeFontInfoDesc() and not + // the user-friendly one returned by wxFont::GetNativeFontInfoUserDesc() + wxFont f = String2Font(m_text->GetValue()); + if (!f.Ok()) + return; // invalid user input + + if (M_PICKER->GetSelectedFont() != f) + { + M_PICKER->SetSelectedFont(f); + + // fire an event + wxFontPickerEvent event(this, GetId(), f); + GetEventHandler()->ProcessEvent(event); + } +} + +void wxFontPickerCtrl::UpdateTextCtrlFromPicker() +{ + if (!m_text) + return; // no textctrl to update + + // NOTE: this SetValue() will generate an unwanted wxEVT_COMMAND_TEXT_UPDATED + // which will trigger a unneeded UpdateFromTextCtrl(); thus before using + // SetValue() we set the m_bIgnoreNextTextCtrlUpdate flag... + m_bIgnoreNextTextCtrlUpdate = true; + m_text->SetValue(Font2String(M_PICKER->GetSelectedFont())); +} + + + +// ---------------------------------------------------------------------------- +// wxFontPickerCtrl - event handlers +// ---------------------------------------------------------------------------- + +void wxFontPickerCtrl::OnFontChange(wxFontPickerEvent &ev) +{ + UpdateTextCtrlFromPicker(); + + // the wxFontPickerWidget sent us a colour-change notification. + // forward this event to our parent + wxFontPickerEvent event(this, GetId(), ev.GetFont()); + GetEventHandler()->ProcessEvent(event); +} + +#endif // wxUSE_FONTPICKERCTRL diff --git a/Externals/wxWidgets/src/common/framecmn.cpp b/Externals/wxWidgets/src/common/framecmn.cpp index 4b7e3bc175..65c3c48ac8 100644 --- a/Externals/wxWidgets/src/common/framecmn.cpp +++ b/Externals/wxWidgets/src/common/framecmn.cpp @@ -1,590 +1,590 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/framecmn.cpp -// Purpose: common (for all platforms) wxFrame functions -// Author: Julian Smart, Vadim Zeitlin -// Created: 01/02/97 -// Id: $Id: framecmn.cpp 51463 2008-01-30 21:31:03Z VZ $ -// Copyright: (c) 1998 Robert Roebling and Julian Smart -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#include "wx/frame.h" - -#ifndef WX_PRECOMP - #include "wx/menu.h" - #include "wx/menuitem.h" - #include "wx/dcclient.h" - #include "wx/toolbar.h" - #include "wx/statusbr.h" -#endif // WX_PRECOMP - -// ---------------------------------------------------------------------------- -// event table -// ---------------------------------------------------------------------------- - -#if wxUSE_MENUS && wxUSE_STATUSBAR - -BEGIN_EVENT_TABLE(wxFrameBase, wxTopLevelWindow) - EVT_MENU_OPEN(wxFrameBase::OnMenuOpen) - EVT_MENU_CLOSE(wxFrameBase::OnMenuClose) - - EVT_MENU_HIGHLIGHT_ALL(wxFrameBase::OnMenuHighlight) -END_EVENT_TABLE() - -#endif // wxUSE_MENUS && wxUSE_STATUSBAR - -// ============================================================================ -// implementation -// ============================================================================ - -// ---------------------------------------------------------------------------- -// construction/destruction -// ---------------------------------------------------------------------------- - -wxFrameBase::wxFrameBase() -{ -#if wxUSE_MENUS - m_frameMenuBar = NULL; -#endif // wxUSE_MENUS - -#if wxUSE_TOOLBAR - m_frameToolBar = NULL; -#endif // wxUSE_TOOLBAR - -#if wxUSE_STATUSBAR - m_frameStatusBar = NULL; -#endif // wxUSE_STATUSBAR - - m_statusBarPane = 0; -} - -wxFrameBase::~wxFrameBase() -{ - // this destructor is required for Darwin -} - -wxFrame *wxFrameBase::New(wxWindow *parent, - wxWindowID id, - const wxString& title, - const wxPoint& pos, - const wxSize& size, - long style, - const wxString& name) -{ - return new wxFrame(parent, id, title, pos, size, style, name); -} - -void wxFrameBase::DeleteAllBars() -{ -#if wxUSE_MENUS - if ( m_frameMenuBar ) - { - delete m_frameMenuBar; - m_frameMenuBar = (wxMenuBar *) NULL; - } -#endif // wxUSE_MENUS - -#if wxUSE_STATUSBAR - if ( m_frameStatusBar ) - { - delete m_frameStatusBar; - m_frameStatusBar = (wxStatusBar *) NULL; - } -#endif // wxUSE_STATUSBAR - -#if wxUSE_TOOLBAR - if ( m_frameToolBar ) - { - delete m_frameToolBar; - m_frameToolBar = (wxToolBar *) NULL; - } -#endif // wxUSE_TOOLBAR -} - -bool wxFrameBase::IsOneOfBars(const wxWindow *win) const -{ -#if wxUSE_MENUS - if ( win == GetMenuBar() ) - return true; -#endif // wxUSE_MENUS - -#if wxUSE_STATUSBAR - if ( win == GetStatusBar() ) - return true; -#endif // wxUSE_STATUSBAR - -#if wxUSE_TOOLBAR - if ( win == GetToolBar() ) - return true; -#endif // wxUSE_TOOLBAR - - return false; -} - -// ---------------------------------------------------------------------------- -// wxFrame size management: we exclude the areas taken by menu/status/toolbars -// from the client area, so the client area is what's really available for the -// frame contents -// ---------------------------------------------------------------------------- - -// get the origin of the client area in the client coordinates -wxPoint wxFrameBase::GetClientAreaOrigin() const -{ - wxPoint pt = wxTopLevelWindow::GetClientAreaOrigin(); - -#if wxUSE_TOOLBAR && !defined(__WXUNIVERSAL__) - wxToolBar *toolbar = GetToolBar(); - if ( toolbar && toolbar->IsShown() ) - { - int w, h; - toolbar->GetSize(&w, &h); - - if ( toolbar->GetWindowStyleFlag() & wxTB_VERTICAL ) - { - pt.x += w; - } - else - { - pt.y += h; - } - } -#endif // wxUSE_TOOLBAR - - return pt; -} - - -void wxFrameBase::SendSizeEvent() -{ - const wxSize size = GetSize(); - wxSizeEvent event( size, GetId() ); - event.SetEventObject( this ); - GetEventHandler()->AddPendingEvent( event ); - -#ifdef __WXGTK__ - // SendSizeEvent is typically called when a toolbar is shown - // or hidden, but sending the size event alone is not enough - // to trigger a full layout. - ((wxFrame*)this)->GtkOnSize( -#ifndef __WXGTK20__ - 0, 0, size.x, size.y -#endif // __WXGTK20__ - ); -#endif // __WXGTK__ -} - - -// ---------------------------------------------------------------------------- -// misc -// ---------------------------------------------------------------------------- - -bool wxFrameBase::ProcessCommand(int id) -{ -#if wxUSE_MENUS - wxMenuBar *bar = GetMenuBar(); - if ( !bar ) - return false; - - wxCommandEvent commandEvent(wxEVT_COMMAND_MENU_SELECTED, id); - commandEvent.SetEventObject(this); - - wxMenuItem *item = bar->FindItem(id); - if (item) - { - if (!item->IsEnabled()) - return true; - - if ((item->GetKind() == wxITEM_RADIO) && item->IsChecked() ) - return true; - - if (item->IsCheckable()) - { - item->Toggle(); - - // use the new value - commandEvent.SetInt(item->IsChecked()); - } - } - - return GetEventHandler()->ProcessEvent(commandEvent); -#else // !wxUSE_MENUS - return false; -#endif // wxUSE_MENUS/!wxUSE_MENUS -} - -// Do the UI update processing for this window. This is -// provided for the application to call if it wants to -// force a UI update, particularly for the menus and toolbar. -void wxFrameBase::UpdateWindowUI(long flags) -{ - wxWindowBase::UpdateWindowUI(flags); - -#if wxUSE_TOOLBAR - if (GetToolBar()) - GetToolBar()->UpdateWindowUI(flags); -#endif - -#if wxUSE_MENUS - if (GetMenuBar()) - { - if ((flags & wxUPDATE_UI_FROMIDLE) && !wxUSE_IDLEMENUUPDATES) - { - // If coming from an idle event, we only - // want to update the menus if we're - // in the wxUSE_IDLEMENUUPDATES configuration: - // so if we're not, do nothing - } - else - DoMenuUpdates(); - } -#endif // wxUSE_MENUS -} - -// ---------------------------------------------------------------------------- -// event handlers for status bar updates from menus -// ---------------------------------------------------------------------------- - -#if wxUSE_MENUS && wxUSE_STATUSBAR - -void wxFrameBase::OnMenuHighlight(wxMenuEvent& event) -{ -#if wxUSE_STATUSBAR - (void)ShowMenuHelp(GetStatusBar(), event.GetMenuId()); -#endif // wxUSE_STATUSBAR -} - -#if !wxUSE_IDLEMENUUPDATES -void wxFrameBase::OnMenuOpen(wxMenuEvent& event) -#else -void wxFrameBase::OnMenuOpen(wxMenuEvent& WXUNUSED(event)) -#endif -{ -#if !wxUSE_IDLEMENUUPDATES - DoMenuUpdates(event.GetMenu()); -#endif // !wxUSE_IDLEMENUUPDATES -} - -void wxFrameBase::OnMenuClose(wxMenuEvent& WXUNUSED(event)) -{ - // do we have real status text to restore? - if ( !m_oldStatusText.empty() ) - { - if ( m_statusBarPane >= 0 ) - { - wxStatusBar *statbar = GetStatusBar(); - if ( statbar ) - statbar->SetStatusText(m_oldStatusText, m_statusBarPane); - } - - m_oldStatusText.clear(); - } -} - -#endif // wxUSE_MENUS && wxUSE_STATUSBAR - -// Implement internal behaviour (menu updating on some platforms) -void wxFrameBase::OnInternalIdle() -{ - wxTopLevelWindow::OnInternalIdle(); - -#if wxUSE_MENUS && wxUSE_IDLEMENUUPDATES - if (wxUpdateUIEvent::CanUpdate(this)) - DoMenuUpdates(); -#endif -} - -// ---------------------------------------------------------------------------- -// status bar stuff -// ---------------------------------------------------------------------------- - -#if wxUSE_STATUSBAR - -wxStatusBar* wxFrameBase::CreateStatusBar(int number, - long style, - wxWindowID id, - const wxString& name) -{ - // the main status bar can only be created once (or else it should be - // deleted before calling CreateStatusBar() again) - wxCHECK_MSG( !m_frameStatusBar, (wxStatusBar *)NULL, - wxT("recreating status bar in wxFrame") ); - - SetStatusBar(OnCreateStatusBar(number, style, id, name)); - - return m_frameStatusBar; -} - -wxStatusBar *wxFrameBase::OnCreateStatusBar(int number, - long style, - wxWindowID id, - const wxString& name) -{ - wxStatusBar *statusBar = new wxStatusBar(this, id, style, name); - - statusBar->SetFieldsCount(number); - - return statusBar; -} - -void wxFrameBase::SetStatusText(const wxString& text, int number) -{ - wxCHECK_RET( m_frameStatusBar != NULL, wxT("no statusbar to set text for") ); - - m_frameStatusBar->SetStatusText(text, number); -} - -void wxFrameBase::SetStatusWidths(int n, const int widths_field[] ) -{ - wxCHECK_RET( m_frameStatusBar != NULL, wxT("no statusbar to set widths for") ); - - m_frameStatusBar->SetStatusWidths(n, widths_field); - - PositionStatusBar(); -} - -void wxFrameBase::PushStatusText(const wxString& text, int number) -{ - wxCHECK_RET( m_frameStatusBar != NULL, wxT("no statusbar to set text for") ); - - m_frameStatusBar->PushStatusText(text, number); -} - -void wxFrameBase::PopStatusText(int number) -{ - wxCHECK_RET( m_frameStatusBar != NULL, wxT("no statusbar to set text for") ); - - m_frameStatusBar->PopStatusText(number); -} - -bool wxFrameBase::ShowMenuHelp(wxStatusBar *WXUNUSED(statbar), int menuId) -{ -#if wxUSE_MENUS - // if no help string found, we will clear the status bar text - wxString helpString; - bool show = menuId != wxID_SEPARATOR && menuId != -2 /* wxID_TITLE */; - - if ( show ) - { - wxMenuBar *menuBar = GetMenuBar(); - if ( menuBar ) - { - // it's ok if we don't find the item because it might belong - // to the popup menu - wxMenuItem *item = menuBar->FindItem(menuId); - if ( item ) - helpString = item->GetHelp(); - } - } - - DoGiveHelp(helpString, show); - - return !helpString.empty(); -#else // !wxUSE_MENUS - return false; -#endif // wxUSE_MENUS/!wxUSE_MENUS -} - -void wxFrameBase::SetStatusBar(wxStatusBar *statBar) -{ - bool hadBar = m_frameStatusBar != NULL; - m_frameStatusBar = statBar; - - if ( (m_frameStatusBar != NULL) != hadBar ) - { - PositionStatusBar(); - - DoLayout(); - } -} - -#endif // wxUSE_STATUSBAR - -#if wxUSE_MENUS || wxUSE_TOOLBAR -void wxFrameBase::DoGiveHelp(const wxString& text, bool show) -{ -#if wxUSE_STATUSBAR - if ( m_statusBarPane < 0 ) - { - // status bar messages disabled - return; - } - - wxStatusBar *statbar = GetStatusBar(); - if ( !statbar ) - return; - - wxString help; - if ( show ) - { - help = text; - - // remember the old status bar text if this is the first time we're - // called since the menu has been opened as we're going to overwrite it - // in our DoGiveHelp() and we want to restore it when the menu is - // closed - // - // note that it would be logical to do this in OnMenuOpen() but under - // MSW we get an EVT_MENU_HIGHLIGHT before EVT_MENU_OPEN, strangely - // enough, and so this doesn't work and instead we use the ugly trick - // with using special m_oldStatusText value as "menu opened" (but it is - // arguably better than adding yet another member variable to wxFrame - // on all platforms) - if ( m_oldStatusText.empty() ) - { - m_oldStatusText = statbar->GetStatusText(m_statusBarPane); - if ( m_oldStatusText.empty() ) - { - // use special value to prevent us from doing this the next time - m_oldStatusText += _T('\0'); - } - } - } - else // hide the status bar text - { - // i.e. restore the old one - help = m_oldStatusText; - - // make sure we get the up to date text when showing it the next time - m_oldStatusText.clear(); - } - - statbar->SetStatusText(help, m_statusBarPane); -#else - wxUnusedVar(text); - wxUnusedVar(show); -#endif // wxUSE_STATUSBAR -} -#endif // wxUSE_MENUS || wxUSE_TOOLBAR - - -// ---------------------------------------------------------------------------- -// toolbar stuff -// ---------------------------------------------------------------------------- - -#if wxUSE_TOOLBAR - -wxToolBar* wxFrameBase::CreateToolBar(long style, - wxWindowID id, - const wxString& name) -{ - // the main toolbar can't be recreated (unless it was explicitly deleted - // before) - wxCHECK_MSG( !m_frameToolBar, (wxToolBar *)NULL, - wxT("recreating toolbar in wxFrame") ); - - if ( style == -1 ) - { - // use default style - // - // NB: we don't specify the default value in the method declaration - // because - // a) this allows us to have different defaults for different - // platforms (even if we don't have them right now) - // b) we don't need to include wx/toolbar.h in the header then - style = wxBORDER_NONE | wxTB_HORIZONTAL | wxTB_FLAT; - } - - SetToolBar(OnCreateToolBar(style, id, name)); - - return m_frameToolBar; -} - -wxToolBar* wxFrameBase::OnCreateToolBar(long style, - wxWindowID id, - const wxString& name) -{ -#if defined(__WXWINCE__) && defined(__POCKETPC__) - return new wxToolMenuBar(this, id, - wxDefaultPosition, wxDefaultSize, - style, name); -#else - return new wxToolBar(this, id, - wxDefaultPosition, wxDefaultSize, - style, name); -#endif -} - -void wxFrameBase::SetToolBar(wxToolBar *toolbar) -{ - bool hadBar = m_frameToolBar != NULL; - m_frameToolBar = toolbar; - - if ( (m_frameToolBar != NULL) != hadBar ) - { - PositionToolBar(); - - DoLayout(); - } -} - -#endif // wxUSE_TOOLBAR - -// ---------------------------------------------------------------------------- -// menus -// ---------------------------------------------------------------------------- - -#if wxUSE_MENUS - -// update all menus -void wxFrameBase::DoMenuUpdates(wxMenu* menu) -{ - if (menu) - { - wxEvtHandler* source = GetEventHandler(); - menu->UpdateUI(source); - } - else - { - wxMenuBar* bar = GetMenuBar(); - if (bar != NULL) - bar->UpdateMenus(); - } -} - -void wxFrameBase::DetachMenuBar() -{ - if ( m_frameMenuBar ) - { - m_frameMenuBar->Detach(); - m_frameMenuBar = NULL; - } -} - -void wxFrameBase::AttachMenuBar(wxMenuBar *menubar) -{ - if ( menubar ) - { - menubar->Attach((wxFrame *)this); - m_frameMenuBar = menubar; - } -} - -void wxFrameBase::SetMenuBar(wxMenuBar *menubar) -{ - if ( menubar == GetMenuBar() ) - { - // nothing to do - return; - } - - DetachMenuBar(); - - this->AttachMenuBar(menubar); -} - -#endif // wxUSE_MENUS +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/framecmn.cpp +// Purpose: common (for all platforms) wxFrame functions +// Author: Julian Smart, Vadim Zeitlin +// Created: 01/02/97 +// Id: $Id: framecmn.cpp 51463 2008-01-30 21:31:03Z VZ $ +// Copyright: (c) 1998 Robert Roebling and Julian Smart +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#include "wx/frame.h" + +#ifndef WX_PRECOMP + #include "wx/menu.h" + #include "wx/menuitem.h" + #include "wx/dcclient.h" + #include "wx/toolbar.h" + #include "wx/statusbr.h" +#endif // WX_PRECOMP + +// ---------------------------------------------------------------------------- +// event table +// ---------------------------------------------------------------------------- + +#if wxUSE_MENUS && wxUSE_STATUSBAR + +BEGIN_EVENT_TABLE(wxFrameBase, wxTopLevelWindow) + EVT_MENU_OPEN(wxFrameBase::OnMenuOpen) + EVT_MENU_CLOSE(wxFrameBase::OnMenuClose) + + EVT_MENU_HIGHLIGHT_ALL(wxFrameBase::OnMenuHighlight) +END_EVENT_TABLE() + +#endif // wxUSE_MENUS && wxUSE_STATUSBAR + +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// construction/destruction +// ---------------------------------------------------------------------------- + +wxFrameBase::wxFrameBase() +{ +#if wxUSE_MENUS + m_frameMenuBar = NULL; +#endif // wxUSE_MENUS + +#if wxUSE_TOOLBAR + m_frameToolBar = NULL; +#endif // wxUSE_TOOLBAR + +#if wxUSE_STATUSBAR + m_frameStatusBar = NULL; +#endif // wxUSE_STATUSBAR + + m_statusBarPane = 0; +} + +wxFrameBase::~wxFrameBase() +{ + // this destructor is required for Darwin +} + +wxFrame *wxFrameBase::New(wxWindow *parent, + wxWindowID id, + const wxString& title, + const wxPoint& pos, + const wxSize& size, + long style, + const wxString& name) +{ + return new wxFrame(parent, id, title, pos, size, style, name); +} + +void wxFrameBase::DeleteAllBars() +{ +#if wxUSE_MENUS + if ( m_frameMenuBar ) + { + delete m_frameMenuBar; + m_frameMenuBar = (wxMenuBar *) NULL; + } +#endif // wxUSE_MENUS + +#if wxUSE_STATUSBAR + if ( m_frameStatusBar ) + { + delete m_frameStatusBar; + m_frameStatusBar = (wxStatusBar *) NULL; + } +#endif // wxUSE_STATUSBAR + +#if wxUSE_TOOLBAR + if ( m_frameToolBar ) + { + delete m_frameToolBar; + m_frameToolBar = (wxToolBar *) NULL; + } +#endif // wxUSE_TOOLBAR +} + +bool wxFrameBase::IsOneOfBars(const wxWindow *win) const +{ +#if wxUSE_MENUS + if ( win == GetMenuBar() ) + return true; +#endif // wxUSE_MENUS + +#if wxUSE_STATUSBAR + if ( win == GetStatusBar() ) + return true; +#endif // wxUSE_STATUSBAR + +#if wxUSE_TOOLBAR + if ( win == GetToolBar() ) + return true; +#endif // wxUSE_TOOLBAR + + return false; +} + +// ---------------------------------------------------------------------------- +// wxFrame size management: we exclude the areas taken by menu/status/toolbars +// from the client area, so the client area is what's really available for the +// frame contents +// ---------------------------------------------------------------------------- + +// get the origin of the client area in the client coordinates +wxPoint wxFrameBase::GetClientAreaOrigin() const +{ + wxPoint pt = wxTopLevelWindow::GetClientAreaOrigin(); + +#if wxUSE_TOOLBAR && !defined(__WXUNIVERSAL__) + wxToolBar *toolbar = GetToolBar(); + if ( toolbar && toolbar->IsShown() ) + { + int w, h; + toolbar->GetSize(&w, &h); + + if ( toolbar->GetWindowStyleFlag() & wxTB_VERTICAL ) + { + pt.x += w; + } + else + { + pt.y += h; + } + } +#endif // wxUSE_TOOLBAR + + return pt; +} + + +void wxFrameBase::SendSizeEvent() +{ + const wxSize size = GetSize(); + wxSizeEvent event( size, GetId() ); + event.SetEventObject( this ); + GetEventHandler()->AddPendingEvent( event ); + +#ifdef __WXGTK__ + // SendSizeEvent is typically called when a toolbar is shown + // or hidden, but sending the size event alone is not enough + // to trigger a full layout. + ((wxFrame*)this)->GtkOnSize( +#ifndef __WXGTK20__ + 0, 0, size.x, size.y +#endif // __WXGTK20__ + ); +#endif // __WXGTK__ +} + + +// ---------------------------------------------------------------------------- +// misc +// ---------------------------------------------------------------------------- + +bool wxFrameBase::ProcessCommand(int id) +{ +#if wxUSE_MENUS + wxMenuBar *bar = GetMenuBar(); + if ( !bar ) + return false; + + wxCommandEvent commandEvent(wxEVT_COMMAND_MENU_SELECTED, id); + commandEvent.SetEventObject(this); + + wxMenuItem *item = bar->FindItem(id); + if (item) + { + if (!item->IsEnabled()) + return true; + + if ((item->GetKind() == wxITEM_RADIO) && item->IsChecked() ) + return true; + + if (item->IsCheckable()) + { + item->Toggle(); + + // use the new value + commandEvent.SetInt(item->IsChecked()); + } + } + + return GetEventHandler()->ProcessEvent(commandEvent); +#else // !wxUSE_MENUS + return false; +#endif // wxUSE_MENUS/!wxUSE_MENUS +} + +// Do the UI update processing for this window. This is +// provided for the application to call if it wants to +// force a UI update, particularly for the menus and toolbar. +void wxFrameBase::UpdateWindowUI(long flags) +{ + wxWindowBase::UpdateWindowUI(flags); + +#if wxUSE_TOOLBAR + if (GetToolBar()) + GetToolBar()->UpdateWindowUI(flags); +#endif + +#if wxUSE_MENUS + if (GetMenuBar()) + { + if ((flags & wxUPDATE_UI_FROMIDLE) && !wxUSE_IDLEMENUUPDATES) + { + // If coming from an idle event, we only + // want to update the menus if we're + // in the wxUSE_IDLEMENUUPDATES configuration: + // so if we're not, do nothing + } + else + DoMenuUpdates(); + } +#endif // wxUSE_MENUS +} + +// ---------------------------------------------------------------------------- +// event handlers for status bar updates from menus +// ---------------------------------------------------------------------------- + +#if wxUSE_MENUS && wxUSE_STATUSBAR + +void wxFrameBase::OnMenuHighlight(wxMenuEvent& event) +{ +#if wxUSE_STATUSBAR + (void)ShowMenuHelp(GetStatusBar(), event.GetMenuId()); +#endif // wxUSE_STATUSBAR +} + +#if !wxUSE_IDLEMENUUPDATES +void wxFrameBase::OnMenuOpen(wxMenuEvent& event) +#else +void wxFrameBase::OnMenuOpen(wxMenuEvent& WXUNUSED(event)) +#endif +{ +#if !wxUSE_IDLEMENUUPDATES + DoMenuUpdates(event.GetMenu()); +#endif // !wxUSE_IDLEMENUUPDATES +} + +void wxFrameBase::OnMenuClose(wxMenuEvent& WXUNUSED(event)) +{ + // do we have real status text to restore? + if ( !m_oldStatusText.empty() ) + { + if ( m_statusBarPane >= 0 ) + { + wxStatusBar *statbar = GetStatusBar(); + if ( statbar ) + statbar->SetStatusText(m_oldStatusText, m_statusBarPane); + } + + m_oldStatusText.clear(); + } +} + +#endif // wxUSE_MENUS && wxUSE_STATUSBAR + +// Implement internal behaviour (menu updating on some platforms) +void wxFrameBase::OnInternalIdle() +{ + wxTopLevelWindow::OnInternalIdle(); + +#if wxUSE_MENUS && wxUSE_IDLEMENUUPDATES + if (wxUpdateUIEvent::CanUpdate(this)) + DoMenuUpdates(); +#endif +} + +// ---------------------------------------------------------------------------- +// status bar stuff +// ---------------------------------------------------------------------------- + +#if wxUSE_STATUSBAR + +wxStatusBar* wxFrameBase::CreateStatusBar(int number, + long style, + wxWindowID id, + const wxString& name) +{ + // the main status bar can only be created once (or else it should be + // deleted before calling CreateStatusBar() again) + wxCHECK_MSG( !m_frameStatusBar, (wxStatusBar *)NULL, + wxT("recreating status bar in wxFrame") ); + + SetStatusBar(OnCreateStatusBar(number, style, id, name)); + + return m_frameStatusBar; +} + +wxStatusBar *wxFrameBase::OnCreateStatusBar(int number, + long style, + wxWindowID id, + const wxString& name) +{ + wxStatusBar *statusBar = new wxStatusBar(this, id, style, name); + + statusBar->SetFieldsCount(number); + + return statusBar; +} + +void wxFrameBase::SetStatusText(const wxString& text, int number) +{ + wxCHECK_RET( m_frameStatusBar != NULL, wxT("no statusbar to set text for") ); + + m_frameStatusBar->SetStatusText(text, number); +} + +void wxFrameBase::SetStatusWidths(int n, const int widths_field[] ) +{ + wxCHECK_RET( m_frameStatusBar != NULL, wxT("no statusbar to set widths for") ); + + m_frameStatusBar->SetStatusWidths(n, widths_field); + + PositionStatusBar(); +} + +void wxFrameBase::PushStatusText(const wxString& text, int number) +{ + wxCHECK_RET( m_frameStatusBar != NULL, wxT("no statusbar to set text for") ); + + m_frameStatusBar->PushStatusText(text, number); +} + +void wxFrameBase::PopStatusText(int number) +{ + wxCHECK_RET( m_frameStatusBar != NULL, wxT("no statusbar to set text for") ); + + m_frameStatusBar->PopStatusText(number); +} + +bool wxFrameBase::ShowMenuHelp(wxStatusBar *WXUNUSED(statbar), int menuId) +{ +#if wxUSE_MENUS + // if no help string found, we will clear the status bar text + wxString helpString; + bool show = menuId != wxID_SEPARATOR && menuId != -2 /* wxID_TITLE */; + + if ( show ) + { + wxMenuBar *menuBar = GetMenuBar(); + if ( menuBar ) + { + // it's ok if we don't find the item because it might belong + // to the popup menu + wxMenuItem *item = menuBar->FindItem(menuId); + if ( item ) + helpString = item->GetHelp(); + } + } + + DoGiveHelp(helpString, show); + + return !helpString.empty(); +#else // !wxUSE_MENUS + return false; +#endif // wxUSE_MENUS/!wxUSE_MENUS +} + +void wxFrameBase::SetStatusBar(wxStatusBar *statBar) +{ + bool hadBar = m_frameStatusBar != NULL; + m_frameStatusBar = statBar; + + if ( (m_frameStatusBar != NULL) != hadBar ) + { + PositionStatusBar(); + + DoLayout(); + } +} + +#endif // wxUSE_STATUSBAR + +#if wxUSE_MENUS || wxUSE_TOOLBAR +void wxFrameBase::DoGiveHelp(const wxString& text, bool show) +{ +#if wxUSE_STATUSBAR + if ( m_statusBarPane < 0 ) + { + // status bar messages disabled + return; + } + + wxStatusBar *statbar = GetStatusBar(); + if ( !statbar ) + return; + + wxString help; + if ( show ) + { + help = text; + + // remember the old status bar text if this is the first time we're + // called since the menu has been opened as we're going to overwrite it + // in our DoGiveHelp() and we want to restore it when the menu is + // closed + // + // note that it would be logical to do this in OnMenuOpen() but under + // MSW we get an EVT_MENU_HIGHLIGHT before EVT_MENU_OPEN, strangely + // enough, and so this doesn't work and instead we use the ugly trick + // with using special m_oldStatusText value as "menu opened" (but it is + // arguably better than adding yet another member variable to wxFrame + // on all platforms) + if ( m_oldStatusText.empty() ) + { + m_oldStatusText = statbar->GetStatusText(m_statusBarPane); + if ( m_oldStatusText.empty() ) + { + // use special value to prevent us from doing this the next time + m_oldStatusText += _T('\0'); + } + } + } + else // hide the status bar text + { + // i.e. restore the old one + help = m_oldStatusText; + + // make sure we get the up to date text when showing it the next time + m_oldStatusText.clear(); + } + + statbar->SetStatusText(help, m_statusBarPane); +#else + wxUnusedVar(text); + wxUnusedVar(show); +#endif // wxUSE_STATUSBAR +} +#endif // wxUSE_MENUS || wxUSE_TOOLBAR + + +// ---------------------------------------------------------------------------- +// toolbar stuff +// ---------------------------------------------------------------------------- + +#if wxUSE_TOOLBAR + +wxToolBar* wxFrameBase::CreateToolBar(long style, + wxWindowID id, + const wxString& name) +{ + // the main toolbar can't be recreated (unless it was explicitly deleted + // before) + wxCHECK_MSG( !m_frameToolBar, (wxToolBar *)NULL, + wxT("recreating toolbar in wxFrame") ); + + if ( style == -1 ) + { + // use default style + // + // NB: we don't specify the default value in the method declaration + // because + // a) this allows us to have different defaults for different + // platforms (even if we don't have them right now) + // b) we don't need to include wx/toolbar.h in the header then + style = wxBORDER_NONE | wxTB_HORIZONTAL | wxTB_FLAT; + } + + SetToolBar(OnCreateToolBar(style, id, name)); + + return m_frameToolBar; +} + +wxToolBar* wxFrameBase::OnCreateToolBar(long style, + wxWindowID id, + const wxString& name) +{ +#if defined(__WXWINCE__) && defined(__POCKETPC__) + return new wxToolMenuBar(this, id, + wxDefaultPosition, wxDefaultSize, + style, name); +#else + return new wxToolBar(this, id, + wxDefaultPosition, wxDefaultSize, + style, name); +#endif +} + +void wxFrameBase::SetToolBar(wxToolBar *toolbar) +{ + bool hadBar = m_frameToolBar != NULL; + m_frameToolBar = toolbar; + + if ( (m_frameToolBar != NULL) != hadBar ) + { + PositionToolBar(); + + DoLayout(); + } +} + +#endif // wxUSE_TOOLBAR + +// ---------------------------------------------------------------------------- +// menus +// ---------------------------------------------------------------------------- + +#if wxUSE_MENUS + +// update all menus +void wxFrameBase::DoMenuUpdates(wxMenu* menu) +{ + if (menu) + { + wxEvtHandler* source = GetEventHandler(); + menu->UpdateUI(source); + } + else + { + wxMenuBar* bar = GetMenuBar(); + if (bar != NULL) + bar->UpdateMenus(); + } +} + +void wxFrameBase::DetachMenuBar() +{ + if ( m_frameMenuBar ) + { + m_frameMenuBar->Detach(); + m_frameMenuBar = NULL; + } +} + +void wxFrameBase::AttachMenuBar(wxMenuBar *menubar) +{ + if ( menubar ) + { + menubar->Attach((wxFrame *)this); + m_frameMenuBar = menubar; + } +} + +void wxFrameBase::SetMenuBar(wxMenuBar *menubar) +{ + if ( menubar == GetMenuBar() ) + { + // nothing to do + return; + } + + DetachMenuBar(); + + this->AttachMenuBar(menubar); +} + +#endif // wxUSE_MENUS diff --git a/Externals/wxWidgets/src/common/fs_arc.cpp b/Externals/wxWidgets/src/common/fs_arc.cpp index dae1910a12..ee1220cfc2 100644 --- a/Externals/wxWidgets/src/common/fs_arc.cpp +++ b/Externals/wxWidgets/src/common/fs_arc.cpp @@ -1,533 +1,533 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: fs_arc.cpp -// Purpose: wxArchive file system -// Author: Vaclav Slavik, Mike Wetherell -// Copyright: (c) 1999 Vaclav Slavik, (c) 2006 Mike Wetherell -// CVS-ID: $Id: fs_arc.cpp 51495 2008-02-01 16:44:56Z MW $ -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ -#pragma hdrstop -#endif - -#if wxUSE_FS_ARCHIVE - -#include "wx/fs_arc.h" - -#ifndef WXPRECOMP - #include "wx/intl.h" - #include "wx/log.h" -#endif - -#if WXWIN_COMPATIBILITY_2_6 && wxUSE_ZIPSTREAM - #include "wx/zipstrm.h" -#else - #include "wx/archive.h" -#endif - -#include "wx/private/fileback.h" - -//--------------------------------------------------------------------------- -// wxArchiveFSCacheDataImpl -// -// Holds the catalog of an archive file, and if it is being read from a -// non-seekable stream, a copy of its backing file. -// -// This class is actually the reference counted implementation for the -// wxArchiveFSCacheData class below. It was done that way to allow sharing -// between instances of wxFileSystem, though that's a feature not used in this -// version. -//--------------------------------------------------------------------------- - -WX_DECLARE_STRING_HASH_MAP(wxArchiveEntry*, wxArchiveFSEntryHash); - -struct wxArchiveFSEntry -{ - wxArchiveEntry *entry; - wxArchiveFSEntry *next; -}; - -class wxArchiveFSCacheDataImpl -{ -public: - wxArchiveFSCacheDataImpl(const wxArchiveClassFactory& factory, - const wxBackingFile& backer); - wxArchiveFSCacheDataImpl(const wxArchiveClassFactory& factory, - wxInputStream *stream); - - ~wxArchiveFSCacheDataImpl(); - - void Release() { if (--m_refcount == 0) delete this; } - wxArchiveFSCacheDataImpl *AddRef() { m_refcount++; return this; } - - wxArchiveEntry *Get(const wxString& name); - wxInputStream *NewStream() const; - - wxArchiveFSEntry *GetNext(wxArchiveFSEntry *fse); - -private: - wxArchiveFSEntry *AddToCache(wxArchiveEntry *entry); - void CloseStreams(); - - int m_refcount; - - wxArchiveFSEntryHash m_hash; - wxArchiveFSEntry *m_begin; - wxArchiveFSEntry **m_endptr; - - wxBackingFile m_backer; - wxInputStream *m_stream; - wxArchiveInputStream *m_archive; -}; - -wxArchiveFSCacheDataImpl::wxArchiveFSCacheDataImpl( - const wxArchiveClassFactory& factory, - const wxBackingFile& backer) - : m_refcount(1), - m_begin(NULL), - m_endptr(&m_begin), - m_backer(backer), - m_stream(new wxBackedInputStream(backer)), - m_archive(factory.NewStream(*m_stream)) -{ -} - -wxArchiveFSCacheDataImpl::wxArchiveFSCacheDataImpl( - const wxArchiveClassFactory& factory, - wxInputStream *stream) - : m_refcount(1), - m_begin(NULL), - m_endptr(&m_begin), - m_stream(stream), - m_archive(factory.NewStream(*m_stream)) -{ -} - -wxArchiveFSCacheDataImpl::~wxArchiveFSCacheDataImpl() -{ - WX_CLEAR_HASH_MAP(wxArchiveFSEntryHash, m_hash); - - wxArchiveFSEntry *entry = m_begin; - - while (entry) - { - wxArchiveFSEntry *next = entry->next; - delete entry; - entry = next; - } - - CloseStreams(); -} - -wxArchiveFSEntry *wxArchiveFSCacheDataImpl::AddToCache(wxArchiveEntry *entry) -{ - m_hash[entry->GetName(wxPATH_UNIX)] = entry; - wxArchiveFSEntry *fse = new wxArchiveFSEntry; - *m_endptr = fse; - (*m_endptr)->entry = entry; - (*m_endptr)->next = NULL; - m_endptr = &(*m_endptr)->next; - return fse; -} - -void wxArchiveFSCacheDataImpl::CloseStreams() -{ - delete m_archive; - m_archive = NULL; - delete m_stream; - m_stream = NULL; -} - -wxArchiveEntry *wxArchiveFSCacheDataImpl::Get(const wxString& name) -{ - wxArchiveFSEntryHash::iterator it = m_hash.find(name); - - if (it != m_hash.end()) - return it->second; - - if (!m_archive) - return NULL; - - wxArchiveEntry *entry; - - while ((entry = m_archive->GetNextEntry()) != NULL) - { - AddToCache(entry); - - if (entry->GetName(wxPATH_UNIX) == name) - return entry; - } - - CloseStreams(); - - return NULL; -} - -wxInputStream* wxArchiveFSCacheDataImpl::NewStream() const -{ - if (m_backer) - return new wxBackedInputStream(m_backer); - else - return NULL; -} - -wxArchiveFSEntry *wxArchiveFSCacheDataImpl::GetNext(wxArchiveFSEntry *fse) -{ - wxArchiveFSEntry *next = fse ? fse->next : m_begin; - - if (!next && m_archive) - { - wxArchiveEntry *entry = m_archive->GetNextEntry(); - - if (entry) - next = AddToCache(entry); - else - CloseStreams(); - } - - return next; -} - -//--------------------------------------------------------------------------- -// wxArchiveFSCacheData -// -// This is the inteface for wxArchiveFSCacheDataImpl above. Holds the catalog -// of an archive file, and if it is being read from a non-seekable stream, a -// copy of its backing file. -//--------------------------------------------------------------------------- - -class wxArchiveFSCacheData -{ -public: - wxArchiveFSCacheData() : m_impl(NULL) { } - wxArchiveFSCacheData(const wxArchiveClassFactory& factory, - const wxBackingFile& backer); - wxArchiveFSCacheData(const wxArchiveClassFactory& factory, - wxInputStream *stream); - - wxArchiveFSCacheData(const wxArchiveFSCacheData& data); - wxArchiveFSCacheData& operator=(const wxArchiveFSCacheData& data); - - ~wxArchiveFSCacheData() { if (m_impl) m_impl->Release(); } - - wxArchiveEntry *Get(const wxString& name) { return m_impl->Get(name); } - wxInputStream *NewStream() const { return m_impl->NewStream(); } - wxArchiveFSEntry *GetNext(wxArchiveFSEntry *fse) - { return m_impl->GetNext(fse); } - -private: - wxArchiveFSCacheDataImpl *m_impl; -}; - -wxArchiveFSCacheData::wxArchiveFSCacheData( - const wxArchiveClassFactory& factory, - const wxBackingFile& backer) - : m_impl(new wxArchiveFSCacheDataImpl(factory, backer)) -{ -} - -wxArchiveFSCacheData::wxArchiveFSCacheData( - const wxArchiveClassFactory& factory, - wxInputStream *stream) - : m_impl(new wxArchiveFSCacheDataImpl(factory, stream)) -{ -} - -wxArchiveFSCacheData::wxArchiveFSCacheData(const wxArchiveFSCacheData& data) - : m_impl(data.m_impl ? data.m_impl->AddRef() : NULL) -{ -} - -wxArchiveFSCacheData& wxArchiveFSCacheData::operator=( - const wxArchiveFSCacheData& data) -{ - if (data.m_impl != m_impl) - { - if (m_impl) - m_impl->Release(); - - m_impl = data.m_impl; - - if (m_impl) - m_impl->AddRef(); - } - - return *this; -} - -//--------------------------------------------------------------------------- -// wxArchiveFSCache -// -// wxArchiveFSCacheData caches a single archive, and this class holds a -// collection of them to cache all the archives accessed by this instance -// of wxFileSystem. -//--------------------------------------------------------------------------- - -WX_DECLARE_STRING_HASH_MAP(wxArchiveFSCacheData, wxArchiveFSCacheDataHash); - -class wxArchiveFSCache -{ -public: - wxArchiveFSCache() { } - ~wxArchiveFSCache() { } - - wxArchiveFSCacheData* Add(const wxString& name, - const wxArchiveClassFactory& factory, - wxInputStream *stream); - - wxArchiveFSCacheData *Get(const wxString& name); - -private: - wxArchiveFSCacheDataHash m_hash; -}; - -wxArchiveFSCacheData* wxArchiveFSCache::Add( - const wxString& name, - const wxArchiveClassFactory& factory, - wxInputStream *stream) -{ - wxArchiveFSCacheData& data = m_hash[name]; - - if (stream->IsSeekable()) - data = wxArchiveFSCacheData(factory, stream); - else - data = wxArchiveFSCacheData(factory, wxBackingFile(stream)); - - return &data; -} - -wxArchiveFSCacheData *wxArchiveFSCache::Get(const wxString& name) -{ - wxArchiveFSCacheDataHash::iterator it; - - if ((it = m_hash.find(name)) != m_hash.end()) - return &it->second; - - return NULL; -} - -//---------------------------------------------------------------------------- -// wxArchiveFSHandler -//---------------------------------------------------------------------------- - -IMPLEMENT_DYNAMIC_CLASS(wxArchiveFSHandler, wxFileSystemHandler) - -wxArchiveFSHandler::wxArchiveFSHandler() - : wxFileSystemHandler() -{ - m_Archive = NULL; - m_FindEntry = NULL; - m_ZipFile = m_Pattern = m_BaseDir = wxEmptyString; - m_AllowDirs = m_AllowFiles = true; - m_DirsFound = NULL; - m_cache = NULL; -} - -wxArchiveFSHandler::~wxArchiveFSHandler() -{ - Cleanup(); - delete m_cache; -} - -void wxArchiveFSHandler::Cleanup() -{ - wxDELETE(m_DirsFound); -} - -bool wxArchiveFSHandler::CanOpen(const wxString& location) -{ - wxString p = GetProtocol(location); - return wxArchiveClassFactory::Find(p) != NULL; -} - -wxFSFile* wxArchiveFSHandler::OpenFile( - wxFileSystem& WXUNUSED(fs), - const wxString& location) -{ - wxString right = GetRightLocation(location); - wxString left = GetLeftLocation(location); - wxString protocol = GetProtocol(location); - wxString key = left + wxT("#") + protocol + wxT(":"); - - if (right.Contains(wxT("./"))) - { - if (right.GetChar(0) != wxT('/')) right = wxT('/') + right; - wxFileName rightPart(right, wxPATH_UNIX); - rightPart.Normalize(wxPATH_NORM_DOTS, wxT("/"), wxPATH_UNIX); - right = rightPart.GetFullPath(wxPATH_UNIX); - } - - if (right.GetChar(0) == wxT('/')) right = right.Mid(1); - - if (!m_cache) - m_cache = new wxArchiveFSCache; - - const wxArchiveClassFactory *factory; - factory = wxArchiveClassFactory::Find(protocol); - if (!factory) - return NULL; - - wxArchiveFSCacheData *cached = m_cache->Get(key); - if (!cached) - { - wxFSFile *leftFile = m_fs.OpenFile(left); - if (!leftFile) - return NULL; - cached = m_cache->Add(key, *factory, leftFile->DetachStream()); - delete leftFile; - } - - wxArchiveEntry *entry = cached->Get(right); - if (!entry) - return NULL; - - wxInputStream *leftStream = cached->NewStream(); - if (!leftStream) - { - wxFSFile *leftFile = m_fs.OpenFile(left); - if (!leftFile) - return NULL; - leftStream = leftFile->DetachStream(); - delete leftFile; - } - - wxArchiveInputStream *s = factory->NewStream(leftStream); - s->OpenEntry(*entry); - - if (s && s->IsOk()) - { -#if WXWIN_COMPATIBILITY_2_6 && wxUSE_ZIPSTREAM - if (factory->IsKindOf(CLASSINFO(wxZipClassFactory))) - ((wxZipInputStream*)s)->m_allowSeeking = true; -#endif // WXWIN_COMPATIBILITY_2_6 - - return new wxFSFile(s, - key + right, - GetMimeTypeFromExt(location), - GetAnchor(location) -#if wxUSE_DATETIME - , entry->GetDateTime() -#endif // wxUSE_DATETIME - ); - } - - delete s; - return NULL; -} - -wxString wxArchiveFSHandler::FindFirst(const wxString& spec, int flags) -{ - wxString right = GetRightLocation(spec); - wxString left = GetLeftLocation(spec); - wxString protocol = GetProtocol(spec); - wxString key = left + wxT("#") + protocol + wxT(":"); - - if (!right.empty() && right.Last() == wxT('/')) right.RemoveLast(); - - if (!m_cache) - m_cache = new wxArchiveFSCache; - - const wxArchiveClassFactory *factory; - factory = wxArchiveClassFactory::Find(protocol); - if (!factory) - return wxEmptyString; - - m_Archive = m_cache->Get(key); - if (!m_Archive) - { - wxFSFile *leftFile = m_fs.OpenFile(left); - if (!leftFile) - return wxEmptyString; - m_Archive = m_cache->Add(key, *factory, leftFile->DetachStream()); - delete leftFile; - } - - m_FindEntry = NULL; - - switch (flags) - { - case wxFILE: - m_AllowDirs = false, m_AllowFiles = true; break; - case wxDIR: - m_AllowDirs = true, m_AllowFiles = false; break; - default: - m_AllowDirs = m_AllowFiles = true; break; - } - - m_ZipFile = key; - - m_Pattern = right.AfterLast(wxT('/')); - m_BaseDir = right.BeforeLast(wxT('/')); - if (m_BaseDir.StartsWith(wxT("/"))) - m_BaseDir = m_BaseDir.Mid(1); - - if (m_Archive) - { - if (m_AllowDirs) - { - delete m_DirsFound; - m_DirsFound = new wxArchiveFilenameHashMap(); - if (right.empty()) // allow "/" to match the archive root - return spec; - } - return DoFind(); - } - return wxEmptyString; -} - -wxString wxArchiveFSHandler::FindNext() -{ - if (!m_Archive) return wxEmptyString; - return DoFind(); -} - -wxString wxArchiveFSHandler::DoFind() -{ - wxString namestr, dir, filename; - wxString match = wxEmptyString; - - while (match == wxEmptyString) - { - m_FindEntry = m_Archive->GetNext(m_FindEntry); - - if (!m_FindEntry) - { - m_Archive = NULL; - m_FindEntry = NULL; - break; - } - namestr = m_FindEntry->entry->GetName(wxPATH_UNIX); - - if (m_AllowDirs) - { - dir = namestr.BeforeLast(wxT('/')); - while (!dir.empty()) - { - if( m_DirsFound->find(dir) == m_DirsFound->end() ) - { - (*m_DirsFound)[dir] = 1; - filename = dir.AfterLast(wxT('/')); - dir = dir.BeforeLast(wxT('/')); - if (!filename.empty() && m_BaseDir == dir && - wxMatchWild(m_Pattern, filename, false)) - match = m_ZipFile + dir + wxT("/") + filename; - } - else - break; // already tranversed - } - } - - filename = namestr.AfterLast(wxT('/')); - dir = namestr.BeforeLast(wxT('/')); - if (m_AllowFiles && !filename.empty() && m_BaseDir == dir && - wxMatchWild(m_Pattern, filename, false)) - match = m_ZipFile + namestr; - } - - return match; -} - -#endif // wxUSE_FS_ARCHIVE +///////////////////////////////////////////////////////////////////////////// +// Name: fs_arc.cpp +// Purpose: wxArchive file system +// Author: Vaclav Slavik, Mike Wetherell +// Copyright: (c) 1999 Vaclav Slavik, (c) 2006 Mike Wetherell +// CVS-ID: $Id: fs_arc.cpp 51495 2008-02-01 16:44:56Z MW $ +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ +#pragma hdrstop +#endif + +#if wxUSE_FS_ARCHIVE + +#include "wx/fs_arc.h" + +#ifndef WXPRECOMP + #include "wx/intl.h" + #include "wx/log.h" +#endif + +#if WXWIN_COMPATIBILITY_2_6 && wxUSE_ZIPSTREAM + #include "wx/zipstrm.h" +#else + #include "wx/archive.h" +#endif + +#include "wx/private/fileback.h" + +//--------------------------------------------------------------------------- +// wxArchiveFSCacheDataImpl +// +// Holds the catalog of an archive file, and if it is being read from a +// non-seekable stream, a copy of its backing file. +// +// This class is actually the reference counted implementation for the +// wxArchiveFSCacheData class below. It was done that way to allow sharing +// between instances of wxFileSystem, though that's a feature not used in this +// version. +//--------------------------------------------------------------------------- + +WX_DECLARE_STRING_HASH_MAP(wxArchiveEntry*, wxArchiveFSEntryHash); + +struct wxArchiveFSEntry +{ + wxArchiveEntry *entry; + wxArchiveFSEntry *next; +}; + +class wxArchiveFSCacheDataImpl +{ +public: + wxArchiveFSCacheDataImpl(const wxArchiveClassFactory& factory, + const wxBackingFile& backer); + wxArchiveFSCacheDataImpl(const wxArchiveClassFactory& factory, + wxInputStream *stream); + + ~wxArchiveFSCacheDataImpl(); + + void Release() { if (--m_refcount == 0) delete this; } + wxArchiveFSCacheDataImpl *AddRef() { m_refcount++; return this; } + + wxArchiveEntry *Get(const wxString& name); + wxInputStream *NewStream() const; + + wxArchiveFSEntry *GetNext(wxArchiveFSEntry *fse); + +private: + wxArchiveFSEntry *AddToCache(wxArchiveEntry *entry); + void CloseStreams(); + + int m_refcount; + + wxArchiveFSEntryHash m_hash; + wxArchiveFSEntry *m_begin; + wxArchiveFSEntry **m_endptr; + + wxBackingFile m_backer; + wxInputStream *m_stream; + wxArchiveInputStream *m_archive; +}; + +wxArchiveFSCacheDataImpl::wxArchiveFSCacheDataImpl( + const wxArchiveClassFactory& factory, + const wxBackingFile& backer) + : m_refcount(1), + m_begin(NULL), + m_endptr(&m_begin), + m_backer(backer), + m_stream(new wxBackedInputStream(backer)), + m_archive(factory.NewStream(*m_stream)) +{ +} + +wxArchiveFSCacheDataImpl::wxArchiveFSCacheDataImpl( + const wxArchiveClassFactory& factory, + wxInputStream *stream) + : m_refcount(1), + m_begin(NULL), + m_endptr(&m_begin), + m_stream(stream), + m_archive(factory.NewStream(*m_stream)) +{ +} + +wxArchiveFSCacheDataImpl::~wxArchiveFSCacheDataImpl() +{ + WX_CLEAR_HASH_MAP(wxArchiveFSEntryHash, m_hash); + + wxArchiveFSEntry *entry = m_begin; + + while (entry) + { + wxArchiveFSEntry *next = entry->next; + delete entry; + entry = next; + } + + CloseStreams(); +} + +wxArchiveFSEntry *wxArchiveFSCacheDataImpl::AddToCache(wxArchiveEntry *entry) +{ + m_hash[entry->GetName(wxPATH_UNIX)] = entry; + wxArchiveFSEntry *fse = new wxArchiveFSEntry; + *m_endptr = fse; + (*m_endptr)->entry = entry; + (*m_endptr)->next = NULL; + m_endptr = &(*m_endptr)->next; + return fse; +} + +void wxArchiveFSCacheDataImpl::CloseStreams() +{ + delete m_archive; + m_archive = NULL; + delete m_stream; + m_stream = NULL; +} + +wxArchiveEntry *wxArchiveFSCacheDataImpl::Get(const wxString& name) +{ + wxArchiveFSEntryHash::iterator it = m_hash.find(name); + + if (it != m_hash.end()) + return it->second; + + if (!m_archive) + return NULL; + + wxArchiveEntry *entry; + + while ((entry = m_archive->GetNextEntry()) != NULL) + { + AddToCache(entry); + + if (entry->GetName(wxPATH_UNIX) == name) + return entry; + } + + CloseStreams(); + + return NULL; +} + +wxInputStream* wxArchiveFSCacheDataImpl::NewStream() const +{ + if (m_backer) + return new wxBackedInputStream(m_backer); + else + return NULL; +} + +wxArchiveFSEntry *wxArchiveFSCacheDataImpl::GetNext(wxArchiveFSEntry *fse) +{ + wxArchiveFSEntry *next = fse ? fse->next : m_begin; + + if (!next && m_archive) + { + wxArchiveEntry *entry = m_archive->GetNextEntry(); + + if (entry) + next = AddToCache(entry); + else + CloseStreams(); + } + + return next; +} + +//--------------------------------------------------------------------------- +// wxArchiveFSCacheData +// +// This is the inteface for wxArchiveFSCacheDataImpl above. Holds the catalog +// of an archive file, and if it is being read from a non-seekable stream, a +// copy of its backing file. +//--------------------------------------------------------------------------- + +class wxArchiveFSCacheData +{ +public: + wxArchiveFSCacheData() : m_impl(NULL) { } + wxArchiveFSCacheData(const wxArchiveClassFactory& factory, + const wxBackingFile& backer); + wxArchiveFSCacheData(const wxArchiveClassFactory& factory, + wxInputStream *stream); + + wxArchiveFSCacheData(const wxArchiveFSCacheData& data); + wxArchiveFSCacheData& operator=(const wxArchiveFSCacheData& data); + + ~wxArchiveFSCacheData() { if (m_impl) m_impl->Release(); } + + wxArchiveEntry *Get(const wxString& name) { return m_impl->Get(name); } + wxInputStream *NewStream() const { return m_impl->NewStream(); } + wxArchiveFSEntry *GetNext(wxArchiveFSEntry *fse) + { return m_impl->GetNext(fse); } + +private: + wxArchiveFSCacheDataImpl *m_impl; +}; + +wxArchiveFSCacheData::wxArchiveFSCacheData( + const wxArchiveClassFactory& factory, + const wxBackingFile& backer) + : m_impl(new wxArchiveFSCacheDataImpl(factory, backer)) +{ +} + +wxArchiveFSCacheData::wxArchiveFSCacheData( + const wxArchiveClassFactory& factory, + wxInputStream *stream) + : m_impl(new wxArchiveFSCacheDataImpl(factory, stream)) +{ +} + +wxArchiveFSCacheData::wxArchiveFSCacheData(const wxArchiveFSCacheData& data) + : m_impl(data.m_impl ? data.m_impl->AddRef() : NULL) +{ +} + +wxArchiveFSCacheData& wxArchiveFSCacheData::operator=( + const wxArchiveFSCacheData& data) +{ + if (data.m_impl != m_impl) + { + if (m_impl) + m_impl->Release(); + + m_impl = data.m_impl; + + if (m_impl) + m_impl->AddRef(); + } + + return *this; +} + +//--------------------------------------------------------------------------- +// wxArchiveFSCache +// +// wxArchiveFSCacheData caches a single archive, and this class holds a +// collection of them to cache all the archives accessed by this instance +// of wxFileSystem. +//--------------------------------------------------------------------------- + +WX_DECLARE_STRING_HASH_MAP(wxArchiveFSCacheData, wxArchiveFSCacheDataHash); + +class wxArchiveFSCache +{ +public: + wxArchiveFSCache() { } + ~wxArchiveFSCache() { } + + wxArchiveFSCacheData* Add(const wxString& name, + const wxArchiveClassFactory& factory, + wxInputStream *stream); + + wxArchiveFSCacheData *Get(const wxString& name); + +private: + wxArchiveFSCacheDataHash m_hash; +}; + +wxArchiveFSCacheData* wxArchiveFSCache::Add( + const wxString& name, + const wxArchiveClassFactory& factory, + wxInputStream *stream) +{ + wxArchiveFSCacheData& data = m_hash[name]; + + if (stream->IsSeekable()) + data = wxArchiveFSCacheData(factory, stream); + else + data = wxArchiveFSCacheData(factory, wxBackingFile(stream)); + + return &data; +} + +wxArchiveFSCacheData *wxArchiveFSCache::Get(const wxString& name) +{ + wxArchiveFSCacheDataHash::iterator it; + + if ((it = m_hash.find(name)) != m_hash.end()) + return &it->second; + + return NULL; +} + +//---------------------------------------------------------------------------- +// wxArchiveFSHandler +//---------------------------------------------------------------------------- + +IMPLEMENT_DYNAMIC_CLASS(wxArchiveFSHandler, wxFileSystemHandler) + +wxArchiveFSHandler::wxArchiveFSHandler() + : wxFileSystemHandler() +{ + m_Archive = NULL; + m_FindEntry = NULL; + m_ZipFile = m_Pattern = m_BaseDir = wxEmptyString; + m_AllowDirs = m_AllowFiles = true; + m_DirsFound = NULL; + m_cache = NULL; +} + +wxArchiveFSHandler::~wxArchiveFSHandler() +{ + Cleanup(); + delete m_cache; +} + +void wxArchiveFSHandler::Cleanup() +{ + wxDELETE(m_DirsFound); +} + +bool wxArchiveFSHandler::CanOpen(const wxString& location) +{ + wxString p = GetProtocol(location); + return wxArchiveClassFactory::Find(p) != NULL; +} + +wxFSFile* wxArchiveFSHandler::OpenFile( + wxFileSystem& WXUNUSED(fs), + const wxString& location) +{ + wxString right = GetRightLocation(location); + wxString left = GetLeftLocation(location); + wxString protocol = GetProtocol(location); + wxString key = left + wxT("#") + protocol + wxT(":"); + + if (right.Contains(wxT("./"))) + { + if (right.GetChar(0) != wxT('/')) right = wxT('/') + right; + wxFileName rightPart(right, wxPATH_UNIX); + rightPart.Normalize(wxPATH_NORM_DOTS, wxT("/"), wxPATH_UNIX); + right = rightPart.GetFullPath(wxPATH_UNIX); + } + + if (right.GetChar(0) == wxT('/')) right = right.Mid(1); + + if (!m_cache) + m_cache = new wxArchiveFSCache; + + const wxArchiveClassFactory *factory; + factory = wxArchiveClassFactory::Find(protocol); + if (!factory) + return NULL; + + wxArchiveFSCacheData *cached = m_cache->Get(key); + if (!cached) + { + wxFSFile *leftFile = m_fs.OpenFile(left); + if (!leftFile) + return NULL; + cached = m_cache->Add(key, *factory, leftFile->DetachStream()); + delete leftFile; + } + + wxArchiveEntry *entry = cached->Get(right); + if (!entry) + return NULL; + + wxInputStream *leftStream = cached->NewStream(); + if (!leftStream) + { + wxFSFile *leftFile = m_fs.OpenFile(left); + if (!leftFile) + return NULL; + leftStream = leftFile->DetachStream(); + delete leftFile; + } + + wxArchiveInputStream *s = factory->NewStream(leftStream); + s->OpenEntry(*entry); + + if (s && s->IsOk()) + { +#if WXWIN_COMPATIBILITY_2_6 && wxUSE_ZIPSTREAM + if (factory->IsKindOf(CLASSINFO(wxZipClassFactory))) + ((wxZipInputStream*)s)->m_allowSeeking = true; +#endif // WXWIN_COMPATIBILITY_2_6 + + return new wxFSFile(s, + key + right, + GetMimeTypeFromExt(location), + GetAnchor(location) +#if wxUSE_DATETIME + , entry->GetDateTime() +#endif // wxUSE_DATETIME + ); + } + + delete s; + return NULL; +} + +wxString wxArchiveFSHandler::FindFirst(const wxString& spec, int flags) +{ + wxString right = GetRightLocation(spec); + wxString left = GetLeftLocation(spec); + wxString protocol = GetProtocol(spec); + wxString key = left + wxT("#") + protocol + wxT(":"); + + if (!right.empty() && right.Last() == wxT('/')) right.RemoveLast(); + + if (!m_cache) + m_cache = new wxArchiveFSCache; + + const wxArchiveClassFactory *factory; + factory = wxArchiveClassFactory::Find(protocol); + if (!factory) + return wxEmptyString; + + m_Archive = m_cache->Get(key); + if (!m_Archive) + { + wxFSFile *leftFile = m_fs.OpenFile(left); + if (!leftFile) + return wxEmptyString; + m_Archive = m_cache->Add(key, *factory, leftFile->DetachStream()); + delete leftFile; + } + + m_FindEntry = NULL; + + switch (flags) + { + case wxFILE: + m_AllowDirs = false, m_AllowFiles = true; break; + case wxDIR: + m_AllowDirs = true, m_AllowFiles = false; break; + default: + m_AllowDirs = m_AllowFiles = true; break; + } + + m_ZipFile = key; + + m_Pattern = right.AfterLast(wxT('/')); + m_BaseDir = right.BeforeLast(wxT('/')); + if (m_BaseDir.StartsWith(wxT("/"))) + m_BaseDir = m_BaseDir.Mid(1); + + if (m_Archive) + { + if (m_AllowDirs) + { + delete m_DirsFound; + m_DirsFound = new wxArchiveFilenameHashMap(); + if (right.empty()) // allow "/" to match the archive root + return spec; + } + return DoFind(); + } + return wxEmptyString; +} + +wxString wxArchiveFSHandler::FindNext() +{ + if (!m_Archive) return wxEmptyString; + return DoFind(); +} + +wxString wxArchiveFSHandler::DoFind() +{ + wxString namestr, dir, filename; + wxString match = wxEmptyString; + + while (match == wxEmptyString) + { + m_FindEntry = m_Archive->GetNext(m_FindEntry); + + if (!m_FindEntry) + { + m_Archive = NULL; + m_FindEntry = NULL; + break; + } + namestr = m_FindEntry->entry->GetName(wxPATH_UNIX); + + if (m_AllowDirs) + { + dir = namestr.BeforeLast(wxT('/')); + while (!dir.empty()) + { + if( m_DirsFound->find(dir) == m_DirsFound->end() ) + { + (*m_DirsFound)[dir] = 1; + filename = dir.AfterLast(wxT('/')); + dir = dir.BeforeLast(wxT('/')); + if (!filename.empty() && m_BaseDir == dir && + wxMatchWild(m_Pattern, filename, false)) + match = m_ZipFile + dir + wxT("/") + filename; + } + else + break; // already tranversed + } + } + + filename = namestr.AfterLast(wxT('/')); + dir = namestr.BeforeLast(wxT('/')); + if (m_AllowFiles && !filename.empty() && m_BaseDir == dir && + wxMatchWild(m_Pattern, filename, false)) + match = m_ZipFile + namestr; + } + + return match; +} + +#endif // wxUSE_FS_ARCHIVE diff --git a/Externals/wxWidgets/src/common/fs_filter.cpp b/Externals/wxWidgets/src/common/fs_filter.cpp index adaf0cba11..d0fae32ba4 100644 --- a/Externals/wxWidgets/src/common/fs_filter.cpp +++ b/Externals/wxWidgets/src/common/fs_filter.cpp @@ -1,92 +1,92 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/fs_filter.cpp -// Purpose: wxFilter file system handler -// Author: Mike Wetherell -// Copyright: (c) 2006 Mike Wetherell -// CVS-ID: $Id: fs_filter.cpp 42514 2006-10-27 10:47:13Z MW $ -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_FILESYSTEM - -#include "wx/fs_filter.h" - -#ifndef WXPRECOMP -#endif - -#include "wx/ptr_scpd.h" - -wxDEFINE_SCOPED_PTR_TYPE(wxFSFile) -wxDEFINE_SCOPED_PTR_TYPE(wxInputStream) - -//---------------------------------------------------------------------------- -// wxFilterFSHandler -//---------------------------------------------------------------------------- - -bool wxFilterFSHandler::CanOpen(const wxString& location) -{ - return wxFilterClassFactory::Find(GetProtocol(location)) != NULL; -} - -wxFSFile* wxFilterFSHandler::OpenFile( - wxFileSystem& fs, - const wxString& location) -{ - wxString right = GetRightLocation(location); - if (!right.empty()) - return NULL; - - wxString protocol = GetProtocol(location); - const wxFilterClassFactory *factory = wxFilterClassFactory::Find(protocol); - if (!factory) - return NULL; - - wxString left = GetLeftLocation(location); - wxFSFilePtr leftFile(fs.OpenFile(left)); - if (!leftFile.get()) - return NULL; - - wxInputStreamPtr leftStream(leftFile->DetachStream()); - if (!leftStream.get() || !leftStream->IsOk()) - return NULL; - - wxInputStreamPtr stream(factory->NewStream(leftStream.release())); - - // The way compressed streams are supposed to be served is e.g.: - // Content-type: application/postscript - // Content-encoding: gzip - // So the mime type should be just the mime type of the lhs. However check - // whether the mime type is that of this compression format (e.g. - // application/gzip). If so pop any extension and try GetMimeTypeFromExt, - // e.g. if it were '.ps.gz' pop the '.gz' and try looking up '.ps' - wxString mime = leftFile->GetMimeType(); - if (factory->CanHandle(mime, wxSTREAM_MIMETYPE)) - mime = GetMimeTypeFromExt(factory->PopExtension(left)); - - return new wxFSFile(stream.release(), - left + wxT("#") + protocol + wxT(":") + right, - mime, - GetAnchor(location) -#if wxUSE_DATETIME - , leftFile->GetModificationTime() -#endif // wxUSE_DATETIME - ); -} - -wxString wxFilterFSHandler::FindFirst(const wxString& WXUNUSED(spec), int WXUNUSED(flags)) -{ - return wxEmptyString; -} - -wxString wxFilterFSHandler::FindNext() -{ - return wxEmptyString; -} - -#endif //wxUSE_FILESYSTEM +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/fs_filter.cpp +// Purpose: wxFilter file system handler +// Author: Mike Wetherell +// Copyright: (c) 2006 Mike Wetherell +// CVS-ID: $Id: fs_filter.cpp 42514 2006-10-27 10:47:13Z MW $ +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_FILESYSTEM + +#include "wx/fs_filter.h" + +#ifndef WXPRECOMP +#endif + +#include "wx/ptr_scpd.h" + +wxDEFINE_SCOPED_PTR_TYPE(wxFSFile) +wxDEFINE_SCOPED_PTR_TYPE(wxInputStream) + +//---------------------------------------------------------------------------- +// wxFilterFSHandler +//---------------------------------------------------------------------------- + +bool wxFilterFSHandler::CanOpen(const wxString& location) +{ + return wxFilterClassFactory::Find(GetProtocol(location)) != NULL; +} + +wxFSFile* wxFilterFSHandler::OpenFile( + wxFileSystem& fs, + const wxString& location) +{ + wxString right = GetRightLocation(location); + if (!right.empty()) + return NULL; + + wxString protocol = GetProtocol(location); + const wxFilterClassFactory *factory = wxFilterClassFactory::Find(protocol); + if (!factory) + return NULL; + + wxString left = GetLeftLocation(location); + wxFSFilePtr leftFile(fs.OpenFile(left)); + if (!leftFile.get()) + return NULL; + + wxInputStreamPtr leftStream(leftFile->DetachStream()); + if (!leftStream.get() || !leftStream->IsOk()) + return NULL; + + wxInputStreamPtr stream(factory->NewStream(leftStream.release())); + + // The way compressed streams are supposed to be served is e.g.: + // Content-type: application/postscript + // Content-encoding: gzip + // So the mime type should be just the mime type of the lhs. However check + // whether the mime type is that of this compression format (e.g. + // application/gzip). If so pop any extension and try GetMimeTypeFromExt, + // e.g. if it were '.ps.gz' pop the '.gz' and try looking up '.ps' + wxString mime = leftFile->GetMimeType(); + if (factory->CanHandle(mime, wxSTREAM_MIMETYPE)) + mime = GetMimeTypeFromExt(factory->PopExtension(left)); + + return new wxFSFile(stream.release(), + left + wxT("#") + protocol + wxT(":") + right, + mime, + GetAnchor(location) +#if wxUSE_DATETIME + , leftFile->GetModificationTime() +#endif // wxUSE_DATETIME + ); +} + +wxString wxFilterFSHandler::FindFirst(const wxString& WXUNUSED(spec), int WXUNUSED(flags)) +{ + return wxEmptyString; +} + +wxString wxFilterFSHandler::FindNext() +{ + return wxEmptyString; +} + +#endif //wxUSE_FILESYSTEM diff --git a/Externals/wxWidgets/src/common/fs_inet.cpp b/Externals/wxWidgets/src/common/fs_inet.cpp index 81bf6a9591..6bcb1cf4b7 100644 --- a/Externals/wxWidgets/src/common/fs_inet.cpp +++ b/Externals/wxWidgets/src/common/fs_inet.cpp @@ -1,167 +1,167 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/fs_inet.cpp -// Purpose: HTTP and FTP file system -// Author: Vaclav Slavik -// Copyright: (c) 1999 Vaclav Slavik -// RCS-ID: $Id: fs_inet.cpp 41033 2006-09-06 13:49:42Z RR $ -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if !wxUSE_SOCKETS - #undef wxUSE_FS_INET - #define wxUSE_FS_INET 0 -#endif - -#if wxUSE_FILESYSTEM && wxUSE_FS_INET - -#ifndef WXPRECOMP - #include "wx/module.h" -#endif - -#include "wx/wfstream.h" -#include "wx/url.h" -#include "wx/filesys.h" -#include "wx/fs_inet.h" - -// ---------------------------------------------------------------------------- -// Helper classes -// ---------------------------------------------------------------------------- - -// This stream deletes the file when destroyed -class wxTemporaryFileInputStream : public wxFileInputStream -{ -public: - wxTemporaryFileInputStream(const wxString& filename) : - wxFileInputStream(filename), m_filename(filename) {} - - virtual ~wxTemporaryFileInputStream() - { - // NB: copied from wxFileInputStream dtor, we need to do it before - // wxRemoveFile - if (m_file_destroy) - { - delete m_file; - m_file_destroy = false; - } - wxRemoveFile(m_filename); - } - -protected: - wxString m_filename; -}; - - -// ---------------------------------------------------------------------------- -// wxInternetFSHandler -// ---------------------------------------------------------------------------- - -static wxString StripProtocolAnchor(const wxString& location) -{ - wxString myloc(location.BeforeLast(wxT('#'))); - if (myloc.empty()) myloc = location.AfterFirst(wxT(':')); - else myloc = myloc.AfterFirst(wxT(':')); - - // fix malformed url: - if (!myloc.Left(2).IsSameAs(wxT("//"))) - { - if (myloc.GetChar(0) != wxT('/')) myloc = wxT("//") + myloc; - else myloc = wxT("/") + myloc; - } - if (myloc.Mid(2).Find(wxT('/')) == wxNOT_FOUND) myloc << wxT('/'); - - return myloc; -} - - -bool wxInternetFSHandler::CanOpen(const wxString& location) -{ -#if wxUSE_URL - wxString p = GetProtocol(location); - if ((p == wxT("http")) || (p == wxT("ftp"))) - { - wxURL url(p + wxT(":") + StripProtocolAnchor(location)); - return (url.GetError() == wxURL_NOERR); - } -#endif - return false; -} - - -wxFSFile* wxInternetFSHandler::OpenFile(wxFileSystem& WXUNUSED(fs), - const wxString& location) -{ -#if !wxUSE_URL - return NULL; -#else - wxString right = - GetProtocol(location) + wxT(":") + StripProtocolAnchor(location); - - wxURL url(right); - if (url.GetError() == wxURL_NOERR) - { - wxInputStream *s = url.GetInputStream(); - wxString content = url.GetProtocol().GetContentType(); - if (content == wxEmptyString) content = GetMimeTypeFromExt(location); - if (s) - { - wxString tmpfile = - wxFileName::CreateTempFileName(wxT("wxhtml")); - - { // now copy streams content to temporary file: - wxFileOutputStream sout(tmpfile); - s->Read(sout); - } - delete s; - - return new wxFSFile(new wxTemporaryFileInputStream(tmpfile), - right, - content, - GetAnchor(location) -#if wxUSE_DATETIME - , wxDateTime::Now() -#endif // wxUSE_DATETIME - ); - } - } - - return (wxFSFile*) NULL; // incorrect URL -#endif -} - - -class wxFileSystemInternetModule : public wxModule -{ - DECLARE_DYNAMIC_CLASS(wxFileSystemInternetModule) - - public: - wxFileSystemInternetModule() : - wxModule(), - m_handler(NULL) - { - } - - virtual bool OnInit() - { - m_handler = new wxInternetFSHandler; - wxFileSystem::AddHandler(m_handler); - return true; - } - - virtual void OnExit() - { - delete wxFileSystem::RemoveHandler(m_handler); - } - - private: - wxFileSystemHandler* m_handler; -}; - -IMPLEMENT_DYNAMIC_CLASS(wxFileSystemInternetModule, wxModule) - -#endif // wxUSE_FILESYSTEM && wxUSE_FS_INET +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/fs_inet.cpp +// Purpose: HTTP and FTP file system +// Author: Vaclav Slavik +// Copyright: (c) 1999 Vaclav Slavik +// RCS-ID: $Id: fs_inet.cpp 41033 2006-09-06 13:49:42Z RR $ +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if !wxUSE_SOCKETS + #undef wxUSE_FS_INET + #define wxUSE_FS_INET 0 +#endif + +#if wxUSE_FILESYSTEM && wxUSE_FS_INET + +#ifndef WXPRECOMP + #include "wx/module.h" +#endif + +#include "wx/wfstream.h" +#include "wx/url.h" +#include "wx/filesys.h" +#include "wx/fs_inet.h" + +// ---------------------------------------------------------------------------- +// Helper classes +// ---------------------------------------------------------------------------- + +// This stream deletes the file when destroyed +class wxTemporaryFileInputStream : public wxFileInputStream +{ +public: + wxTemporaryFileInputStream(const wxString& filename) : + wxFileInputStream(filename), m_filename(filename) {} + + virtual ~wxTemporaryFileInputStream() + { + // NB: copied from wxFileInputStream dtor, we need to do it before + // wxRemoveFile + if (m_file_destroy) + { + delete m_file; + m_file_destroy = false; + } + wxRemoveFile(m_filename); + } + +protected: + wxString m_filename; +}; + + +// ---------------------------------------------------------------------------- +// wxInternetFSHandler +// ---------------------------------------------------------------------------- + +static wxString StripProtocolAnchor(const wxString& location) +{ + wxString myloc(location.BeforeLast(wxT('#'))); + if (myloc.empty()) myloc = location.AfterFirst(wxT(':')); + else myloc = myloc.AfterFirst(wxT(':')); + + // fix malformed url: + if (!myloc.Left(2).IsSameAs(wxT("//"))) + { + if (myloc.GetChar(0) != wxT('/')) myloc = wxT("//") + myloc; + else myloc = wxT("/") + myloc; + } + if (myloc.Mid(2).Find(wxT('/')) == wxNOT_FOUND) myloc << wxT('/'); + + return myloc; +} + + +bool wxInternetFSHandler::CanOpen(const wxString& location) +{ +#if wxUSE_URL + wxString p = GetProtocol(location); + if ((p == wxT("http")) || (p == wxT("ftp"))) + { + wxURL url(p + wxT(":") + StripProtocolAnchor(location)); + return (url.GetError() == wxURL_NOERR); + } +#endif + return false; +} + + +wxFSFile* wxInternetFSHandler::OpenFile(wxFileSystem& WXUNUSED(fs), + const wxString& location) +{ +#if !wxUSE_URL + return NULL; +#else + wxString right = + GetProtocol(location) + wxT(":") + StripProtocolAnchor(location); + + wxURL url(right); + if (url.GetError() == wxURL_NOERR) + { + wxInputStream *s = url.GetInputStream(); + wxString content = url.GetProtocol().GetContentType(); + if (content == wxEmptyString) content = GetMimeTypeFromExt(location); + if (s) + { + wxString tmpfile = + wxFileName::CreateTempFileName(wxT("wxhtml")); + + { // now copy streams content to temporary file: + wxFileOutputStream sout(tmpfile); + s->Read(sout); + } + delete s; + + return new wxFSFile(new wxTemporaryFileInputStream(tmpfile), + right, + content, + GetAnchor(location) +#if wxUSE_DATETIME + , wxDateTime::Now() +#endif // wxUSE_DATETIME + ); + } + } + + return (wxFSFile*) NULL; // incorrect URL +#endif +} + + +class wxFileSystemInternetModule : public wxModule +{ + DECLARE_DYNAMIC_CLASS(wxFileSystemInternetModule) + + public: + wxFileSystemInternetModule() : + wxModule(), + m_handler(NULL) + { + } + + virtual bool OnInit() + { + m_handler = new wxInternetFSHandler; + wxFileSystem::AddHandler(m_handler); + return true; + } + + virtual void OnExit() + { + delete wxFileSystem::RemoveHandler(m_handler); + } + + private: + wxFileSystemHandler* m_handler; +}; + +IMPLEMENT_DYNAMIC_CLASS(wxFileSystemInternetModule, wxModule) + +#endif // wxUSE_FILESYSTEM && wxUSE_FS_INET diff --git a/Externals/wxWidgets/src/common/fs_mem.cpp b/Externals/wxWidgets/src/common/fs_mem.cpp index 9967b881b2..3bf24969e3 100644 --- a/Externals/wxWidgets/src/common/fs_mem.cpp +++ b/Externals/wxWidgets/src/common/fs_mem.cpp @@ -1,288 +1,288 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/fs_mem.cpp -// Purpose: in-memory file system -// Author: Vaclav Slavik -// RCS-ID: $Id: fs_mem.cpp 46522 2007-06-18 18:37:40Z VS $ -// Copyright: (c) 2000 Vaclav Slavik -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_FILESYSTEM && wxUSE_STREAMS - -#include "wx/fs_mem.h" - -#ifndef WXPRECOMP - #include "wx/intl.h" - #include "wx/log.h" - #include "wx/hash.h" - #if wxUSE_GUI - #include "wx/bitmap.h" - #include "wx/image.h" - #endif // wxUSE_GUI -#endif - -#include "wx/mstream.h" - -class MemFSHashObj : public wxObject -{ - public: - - MemFSHashObj(const void *data, size_t len, const wxString& mime) - { - m_Data = new char[len]; - memcpy(m_Data, data, len); - m_Len = len; - m_MimeType = mime; - InitTime(); - } - - MemFSHashObj(const wxMemoryOutputStream& stream, const wxString& mime) - { - m_Len = stream.GetSize(); - m_Data = new char[m_Len]; - stream.CopyTo(m_Data, m_Len); - m_MimeType = mime; - InitTime(); - } - - virtual ~MemFSHashObj() - { - delete[] m_Data; - } - - char *m_Data; - size_t m_Len; - wxString m_MimeType; -#if wxUSE_DATETIME - wxDateTime m_Time; -#endif // wxUSE_DATETIME - - DECLARE_NO_COPY_CLASS(MemFSHashObj) - - private: - void InitTime() - { -#if wxUSE_DATETIME - m_Time = wxDateTime::Now(); -#endif // wxUSE_DATETIME - } -}; - -#if wxUSE_BASE - - -//-------------------------------------------------------------------------------- -// wxMemoryFSHandler -//-------------------------------------------------------------------------------- - - -wxHashTable *wxMemoryFSHandlerBase::m_Hash = NULL; - - -wxMemoryFSHandlerBase::wxMemoryFSHandlerBase() : wxFileSystemHandler() -{ -} - - - -wxMemoryFSHandlerBase::~wxMemoryFSHandlerBase() -{ - // as only one copy of FS handler is supposed to exist, we may silently - // delete static data here. (There is no way how to remove FS handler from - // wxFileSystem other than releasing _all_ handlers.) - - if (m_Hash) - { - WX_CLEAR_HASH_TABLE(*m_Hash); - delete m_Hash; - m_Hash = NULL; - } -} - - - -bool wxMemoryFSHandlerBase::CanOpen(const wxString& location) -{ - wxString p = GetProtocol(location); - return (p == wxT("memory")); -} - - - - -wxFSFile* wxMemoryFSHandlerBase::OpenFile(wxFileSystem& WXUNUSED(fs), const wxString& location) -{ - if (m_Hash) - { - MemFSHashObj *obj = (MemFSHashObj*) m_Hash -> Get(GetRightLocation(location)); - if (obj == NULL) - { - return NULL; - } - else - { - wxString mime = obj->m_MimeType; - if ( mime.empty() ) - mime = GetMimeTypeFromExt(location); - return new wxFSFile - ( - new wxMemoryInputStream(obj -> m_Data, obj -> m_Len), - location, - mime, - GetAnchor(location) -#if wxUSE_DATETIME - , obj -> m_Time -#endif // wxUSE_DATETIME - ); - } - } - else return NULL; -} - - - -wxString wxMemoryFSHandlerBase::FindFirst(const wxString& WXUNUSED(spec), - int WXUNUSED(flags)) -{ - wxFAIL_MSG(wxT("wxMemoryFSHandlerBase::FindFirst not implemented")); - - return wxEmptyString; -} - - - -wxString wxMemoryFSHandlerBase::FindNext() -{ - wxFAIL_MSG(wxT("wxMemoryFSHandlerBase::FindNext not implemented")); - - return wxEmptyString; -} - - -bool wxMemoryFSHandlerBase::CheckHash(const wxString& filename) -{ - if (m_Hash == NULL) - { - m_Hash = new wxHashTable(wxKEY_STRING); - } - - if (m_Hash -> Get(filename) != NULL) - { - wxString s; - s.Printf(_("Memory VFS already contains file '%s'!"), filename.c_str()); - wxLogError(s); - return false; - } - else - return true; -} - - -/*static*/ -void wxMemoryFSHandlerBase::AddFileWithMimeType(const wxString& filename, - const wxString& textdata, - const wxString& mimetype) -{ - AddFileWithMimeType(filename, - (const void*) textdata.mb_str(), textdata.length(), - mimetype); -} - - -/*static*/ -void wxMemoryFSHandlerBase::AddFileWithMimeType(const wxString& filename, - const void *binarydata, size_t size, - const wxString& mimetype) -{ - if (!CheckHash(filename)) return; - m_Hash -> Put(filename, new MemFSHashObj(binarydata, size, mimetype)); -} - -/*static*/ -void wxMemoryFSHandlerBase::AddFile(const wxString& filename, - const wxString& textdata) -{ - AddFileWithMimeType(filename, textdata, wxEmptyString); -} - - -/*static*/ -void wxMemoryFSHandlerBase::AddFile(const wxString& filename, - const void *binarydata, size_t size) -{ - AddFileWithMimeType(filename, binarydata, size, wxEmptyString); -} - - - -/*static*/ void wxMemoryFSHandlerBase::RemoveFile(const wxString& filename) -{ - if (m_Hash == NULL || - m_Hash -> Get(filename) == NULL) - { - wxString s; - s.Printf(_("Trying to remove file '%s' from memory VFS, but it is not loaded!"), filename.c_str()); - wxLogError(s); - } - - else - delete m_Hash -> Delete(filename); -} - -#endif // wxUSE_BASE - -#if wxUSE_GUI - -#if wxUSE_IMAGE -/*static*/ void -wxMemoryFSHandler::AddFile(const wxString& filename, - const wxImage& image, - long type) -{ - if (!CheckHash(filename)) return; - - wxMemoryOutputStream mems; - if (image.Ok() && image.SaveFile(mems, (int)type)) - { - m_Hash->Put - ( - filename, - new MemFSHashObj - ( - mems, - wxImage::FindHandler(type)->GetMimeType() - ) - ); - } - else - { - wxString s; - s.Printf(_("Failed to store image '%s' to memory VFS!"), filename.c_str()); - wxPrintf(wxT("'%s'\n"), s.c_str()); - wxLogError(s); - } -} - -/*static*/ void -wxMemoryFSHandler::AddFile(const wxString& filename, - const wxBitmap& bitmap, - long type) -{ -#if !defined(__WXMSW__) || wxUSE_WXDIB - wxImage img = bitmap.ConvertToImage(); - AddFile(filename, img, type); -#endif -} - -#endif // wxUSE_IMAGE - -#endif // wxUSE_GUI - - -#endif // wxUSE_FILESYSTEM && wxUSE_FS_ZIP +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/fs_mem.cpp +// Purpose: in-memory file system +// Author: Vaclav Slavik +// RCS-ID: $Id: fs_mem.cpp 46522 2007-06-18 18:37:40Z VS $ +// Copyright: (c) 2000 Vaclav Slavik +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_FILESYSTEM && wxUSE_STREAMS + +#include "wx/fs_mem.h" + +#ifndef WXPRECOMP + #include "wx/intl.h" + #include "wx/log.h" + #include "wx/hash.h" + #if wxUSE_GUI + #include "wx/bitmap.h" + #include "wx/image.h" + #endif // wxUSE_GUI +#endif + +#include "wx/mstream.h" + +class MemFSHashObj : public wxObject +{ + public: + + MemFSHashObj(const void *data, size_t len, const wxString& mime) + { + m_Data = new char[len]; + memcpy(m_Data, data, len); + m_Len = len; + m_MimeType = mime; + InitTime(); + } + + MemFSHashObj(const wxMemoryOutputStream& stream, const wxString& mime) + { + m_Len = stream.GetSize(); + m_Data = new char[m_Len]; + stream.CopyTo(m_Data, m_Len); + m_MimeType = mime; + InitTime(); + } + + virtual ~MemFSHashObj() + { + delete[] m_Data; + } + + char *m_Data; + size_t m_Len; + wxString m_MimeType; +#if wxUSE_DATETIME + wxDateTime m_Time; +#endif // wxUSE_DATETIME + + DECLARE_NO_COPY_CLASS(MemFSHashObj) + + private: + void InitTime() + { +#if wxUSE_DATETIME + m_Time = wxDateTime::Now(); +#endif // wxUSE_DATETIME + } +}; + +#if wxUSE_BASE + + +//-------------------------------------------------------------------------------- +// wxMemoryFSHandler +//-------------------------------------------------------------------------------- + + +wxHashTable *wxMemoryFSHandlerBase::m_Hash = NULL; + + +wxMemoryFSHandlerBase::wxMemoryFSHandlerBase() : wxFileSystemHandler() +{ +} + + + +wxMemoryFSHandlerBase::~wxMemoryFSHandlerBase() +{ + // as only one copy of FS handler is supposed to exist, we may silently + // delete static data here. (There is no way how to remove FS handler from + // wxFileSystem other than releasing _all_ handlers.) + + if (m_Hash) + { + WX_CLEAR_HASH_TABLE(*m_Hash); + delete m_Hash; + m_Hash = NULL; + } +} + + + +bool wxMemoryFSHandlerBase::CanOpen(const wxString& location) +{ + wxString p = GetProtocol(location); + return (p == wxT("memory")); +} + + + + +wxFSFile* wxMemoryFSHandlerBase::OpenFile(wxFileSystem& WXUNUSED(fs), const wxString& location) +{ + if (m_Hash) + { + MemFSHashObj *obj = (MemFSHashObj*) m_Hash -> Get(GetRightLocation(location)); + if (obj == NULL) + { + return NULL; + } + else + { + wxString mime = obj->m_MimeType; + if ( mime.empty() ) + mime = GetMimeTypeFromExt(location); + return new wxFSFile + ( + new wxMemoryInputStream(obj -> m_Data, obj -> m_Len), + location, + mime, + GetAnchor(location) +#if wxUSE_DATETIME + , obj -> m_Time +#endif // wxUSE_DATETIME + ); + } + } + else return NULL; +} + + + +wxString wxMemoryFSHandlerBase::FindFirst(const wxString& WXUNUSED(spec), + int WXUNUSED(flags)) +{ + wxFAIL_MSG(wxT("wxMemoryFSHandlerBase::FindFirst not implemented")); + + return wxEmptyString; +} + + + +wxString wxMemoryFSHandlerBase::FindNext() +{ + wxFAIL_MSG(wxT("wxMemoryFSHandlerBase::FindNext not implemented")); + + return wxEmptyString; +} + + +bool wxMemoryFSHandlerBase::CheckHash(const wxString& filename) +{ + if (m_Hash == NULL) + { + m_Hash = new wxHashTable(wxKEY_STRING); + } + + if (m_Hash -> Get(filename) != NULL) + { + wxString s; + s.Printf(_("Memory VFS already contains file '%s'!"), filename.c_str()); + wxLogError(s); + return false; + } + else + return true; +} + + +/*static*/ +void wxMemoryFSHandlerBase::AddFileWithMimeType(const wxString& filename, + const wxString& textdata, + const wxString& mimetype) +{ + AddFileWithMimeType(filename, + (const void*) textdata.mb_str(), textdata.length(), + mimetype); +} + + +/*static*/ +void wxMemoryFSHandlerBase::AddFileWithMimeType(const wxString& filename, + const void *binarydata, size_t size, + const wxString& mimetype) +{ + if (!CheckHash(filename)) return; + m_Hash -> Put(filename, new MemFSHashObj(binarydata, size, mimetype)); +} + +/*static*/ +void wxMemoryFSHandlerBase::AddFile(const wxString& filename, + const wxString& textdata) +{ + AddFileWithMimeType(filename, textdata, wxEmptyString); +} + + +/*static*/ +void wxMemoryFSHandlerBase::AddFile(const wxString& filename, + const void *binarydata, size_t size) +{ + AddFileWithMimeType(filename, binarydata, size, wxEmptyString); +} + + + +/*static*/ void wxMemoryFSHandlerBase::RemoveFile(const wxString& filename) +{ + if (m_Hash == NULL || + m_Hash -> Get(filename) == NULL) + { + wxString s; + s.Printf(_("Trying to remove file '%s' from memory VFS, but it is not loaded!"), filename.c_str()); + wxLogError(s); + } + + else + delete m_Hash -> Delete(filename); +} + +#endif // wxUSE_BASE + +#if wxUSE_GUI + +#if wxUSE_IMAGE +/*static*/ void +wxMemoryFSHandler::AddFile(const wxString& filename, + const wxImage& image, + long type) +{ + if (!CheckHash(filename)) return; + + wxMemoryOutputStream mems; + if (image.Ok() && image.SaveFile(mems, (int)type)) + { + m_Hash->Put + ( + filename, + new MemFSHashObj + ( + mems, + wxImage::FindHandler(type)->GetMimeType() + ) + ); + } + else + { + wxString s; + s.Printf(_("Failed to store image '%s' to memory VFS!"), filename.c_str()); + wxPrintf(wxT("'%s'\n"), s.c_str()); + wxLogError(s); + } +} + +/*static*/ void +wxMemoryFSHandler::AddFile(const wxString& filename, + const wxBitmap& bitmap, + long type) +{ +#if !defined(__WXMSW__) || wxUSE_WXDIB + wxImage img = bitmap.ConvertToImage(); + AddFile(filename, img, type); +#endif +} + +#endif // wxUSE_IMAGE + +#endif // wxUSE_GUI + + +#endif // wxUSE_FILESYSTEM && wxUSE_FS_ZIP diff --git a/Externals/wxWidgets/src/common/ftp.cpp b/Externals/wxWidgets/src/common/ftp.cpp index a490f81993..0878f90d0e 100644 --- a/Externals/wxWidgets/src/common/ftp.cpp +++ b/Externals/wxWidgets/src/common/ftp.cpp @@ -1,1008 +1,1008 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: common/ftp.cpp -// Purpose: FTP protocol -// Author: Guilhem Lavaux -// Modified by: Mark Johnson, wxWindows@mj10777.de -// 20000917 : RmDir, GetLastResult, GetList -// Vadim Zeitlin (numerous fixes and rewrites to all part of the -// code, support ASCII/Binary modes, better error reporting, more -// robust Abort(), support for arbitrary FTP commands, ...) -// Randall Fox (support for active mode) -// Created: 07/07/1997 -// RCS-ID: $Id: ftp.cpp 47969 2007-08-08 23:34:14Z VZ $ -// Copyright: (c) 1997, 1998 Guilhem Lavaux -// (c) 1998-2004 wxWidgets team -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_PROTOCOL_FTP - -#ifndef WX_PRECOMP - #include - #include "wx/string.h" - #include "wx/utils.h" - #include "wx/log.h" - #include "wx/intl.h" -#endif // WX_PRECOMP - -#include "wx/sckaddr.h" -#include "wx/socket.h" -#include "wx/url.h" -#include "wx/sckstrm.h" -#include "wx/protocol/protocol.h" -#include "wx/protocol/ftp.h" - -#if defined(__WXMAC__) - #include "wx/mac/macsock.h" -#endif - -#ifndef __MWERKS__ - #include -#endif - -// ---------------------------------------------------------------------------- -// constants -// ---------------------------------------------------------------------------- - -// the length of FTP status code (3 digits) -static const size_t LEN_CODE = 3; - -// ---------------------------------------------------------------------------- -// macros -// ---------------------------------------------------------------------------- - -IMPLEMENT_DYNAMIC_CLASS(wxFTP, wxProtocol) -IMPLEMENT_PROTOCOL(wxFTP, wxT("ftp"), wxT("ftp"), true) - -// ============================================================================ -// implementation -// ============================================================================ - -// ---------------------------------------------------------------------------- -// wxFTP constructor and destructor -// ---------------------------------------------------------------------------- - -wxFTP::wxFTP() -{ - m_lastError = wxPROTO_NOERR; - m_streaming = false; - m_currentTransfermode = NONE; - - m_user = wxT("anonymous"); - m_passwd << wxGetUserId() << wxT('@') << wxGetFullHostName(); - - SetNotify(0); - SetFlags(wxSOCKET_NOWAIT); - m_bPassive = true; - SetDefaultTimeout(60); // Default is Sixty Seconds - m_bEncounteredError = false; -} - -wxFTP::~wxFTP() -{ - if ( m_streaming ) - { - // if we are streaming, this will issue - // an FTP ABORT command, to tell the server we are aborting - (void)Abort(); - } - - // now this issues a "QUIT" command to tell the server we are - Close(); -} - -// ---------------------------------------------------------------------------- -// wxFTP connect and login methods -// ---------------------------------------------------------------------------- - -bool wxFTP::Connect(wxSockAddress& addr, bool WXUNUSED(wait)) -{ - if ( !wxProtocol::Connect(addr) ) - { - m_lastError = wxPROTO_NETERR; - return false; - } - - if ( !m_user ) - { - m_lastError = wxPROTO_CONNERR; - return false; - } - - // we should have 220 welcome message - if ( !CheckResult('2') ) - { - Close(); - return false; - } - - wxString command; - command.Printf(wxT("USER %s"), m_user.c_str()); - char rc = SendCommand(command); - if ( rc == '2' ) - { - // 230 return: user accepted without password - return true; - } - - if ( rc != '3' ) - { - Close(); - return false; - } - - command.Printf(wxT("PASS %s"), m_passwd.c_str()); - if ( !CheckCommand(command, '2') ) - { - Close(); - return false; - } - - return true; -} - -bool wxFTP::Connect(const wxString& host) -{ - wxIPV4address addr; - addr.Hostname(host); - addr.Service(wxT("ftp")); - - return Connect(addr); -} - -bool wxFTP::Close() -{ - if ( m_streaming ) - { - m_lastError = wxPROTO_STREAMING; - return false; - } - - if ( IsConnected() ) - { - if ( !CheckCommand(wxT("QUIT"), '2') ) - { - wxLogDebug(_T("Failed to close connection gracefully.")); - } - } - - return wxSocketClient::Close(); -} - -// ============================================================================ -// low level methods -// ============================================================================ - -// ---------------------------------------------------------------------------- -// Send command to FTP server -// ---------------------------------------------------------------------------- - -char wxFTP::SendCommand(const wxString& command) -{ - if ( m_streaming ) - { - m_lastError = wxPROTO_STREAMING; - return 0; - } - - wxString tmp_str = command + wxT("\r\n"); - const wxWX2MBbuf tmp_buf = tmp_str.mb_str(); - if ( Write(wxMBSTRINGCAST tmp_buf, strlen(tmp_buf)).Error()) - { - m_lastError = wxPROTO_NETERR; - return 0; - } - -#ifdef __WXDEBUG__ - // don't show the passwords in the logs (even in debug ones) - wxString cmd, password; - if ( command.Upper().StartsWith(_T("PASS "), &password) ) - { - cmd << _T("PASS ") << wxString(_T('*'), password.length()); - } - else - { - cmd = command; - } - - wxLogTrace(FTP_TRACE_MASK, _T("==> %s"), cmd.c_str()); -#endif // __WXDEBUG__ - - return GetResult(); -} - -// ---------------------------------------------------------------------------- -// Recieve servers reply -// ---------------------------------------------------------------------------- - -char wxFTP::GetResult() -{ - // if we've already had a read or write timeout error, the connection is - // probably toast, so don't bother, it just wastes the users time - if ( m_bEncounteredError ) - return 0; - - wxString code; - - // m_lastResult will contain the entire server response, possibly on - // multiple lines - m_lastResult.clear(); - - // we handle multiline replies here according to RFC 959: it says that a - // reply may either be on 1 line of the form "xyz ..." or on several lines - // in whuch case it looks like - // xyz-... - // ... - // xyz ... - // and the intermeidate lines may start with xyz or not - bool badReply = false; - bool firstLine = true; - bool endOfReply = false; - while ( !endOfReply && !badReply ) - { - wxString line; - m_lastError = ReadLine(this,line); - if ( m_lastError ) - { - m_bEncounteredError = true; - return 0; - } - - if ( !m_lastResult.empty() ) - { - // separate from last line - m_lastResult += _T('\n'); - } - - m_lastResult += line; - - // unless this is an intermediate line of a multiline reply, it must - // contain the code in the beginning and '-' or ' ' following it - if ( line.Len() < LEN_CODE + 1 ) - { - if ( firstLine ) - { - badReply = true; - } - else - { - wxLogTrace(FTP_TRACE_MASK, _T("<== %s %s"), - code.c_str(), line.c_str()); - } - } - else // line has at least 4 chars - { - // this is the char which tells us what we're dealing with - wxChar chMarker = line.GetChar(LEN_CODE); - - if ( firstLine ) - { - code = wxString(line, LEN_CODE); - wxLogTrace(FTP_TRACE_MASK, _T("<== %s %s"), - code.c_str(), line.c_str() + LEN_CODE + 1); - - switch ( chMarker ) - { - case _T(' '): - endOfReply = true; - break; - - case _T('-'): - firstLine = false; - break; - - default: - // unexpected - badReply = true; - } - } - else // subsequent line of multiline reply - { - if ( wxStrncmp(line, code, LEN_CODE) == 0 ) - { - if ( chMarker == _T(' ') ) - { - endOfReply = true; - } - - wxLogTrace(FTP_TRACE_MASK, _T("<== %s %s"), - code.c_str(), line.c_str() + LEN_CODE + 1); - } - else - { - // just part of reply - wxLogTrace(FTP_TRACE_MASK, _T("<== %s %s"), - code.c_str(), line.c_str()); - } - } - } - } - - if ( badReply ) - { - wxLogDebug(_T("Broken FTP server: '%s' is not a valid reply."), - m_lastResult.c_str()); - - m_lastError = wxPROTO_PROTERR; - - return 0; - } - - // if we got here we must have a non empty code string - return (char)code[0u]; -} - -// ---------------------------------------------------------------------------- -// wxFTP simple commands -// ---------------------------------------------------------------------------- - -bool wxFTP::SetTransferMode(TransferMode transferMode) -{ - if ( transferMode == m_currentTransfermode ) - { - // nothing to do - return true; - } - - wxString mode; - switch ( transferMode ) - { - default: - wxFAIL_MSG(_T("unknown FTP transfer mode")); - // fall through - - case BINARY: - mode = _T('I'); - break; - - case ASCII: - mode = _T('A'); - break; - } - - if ( !DoSimpleCommand(_T("TYPE"), mode) ) - { - wxLogError(_("Failed to set FTP transfer mode to %s."), (const wxChar*) - (transferMode == ASCII ? _("ASCII") : _("binary"))); - - return false; - } - - // If we get here the operation has been successfully completed - // Set the status-member - m_currentTransfermode = transferMode; - - return true; -} - -bool wxFTP::DoSimpleCommand(const wxChar *command, const wxString& arg) -{ - wxString fullcmd = command; - if ( !arg.empty() ) - { - fullcmd << _T(' ') << arg; - } - - if ( !CheckCommand(fullcmd, '2') ) - { - wxLogDebug(_T("FTP command '%s' failed."), fullcmd.c_str()); - - return false; - } - - return true; -} - -bool wxFTP::ChDir(const wxString& dir) -{ - // some servers might not understand ".." if they use different directory - // tree conventions, but they always understand CDUP - should we use it if - // dir == ".."? OTOH, do such servers (still) exist? - - return DoSimpleCommand(_T("CWD"), dir); -} - -bool wxFTP::MkDir(const wxString& dir) -{ - return DoSimpleCommand(_T("MKD"), dir); -} - -bool wxFTP::RmDir(const wxString& dir) -{ - return DoSimpleCommand(_T("RMD"), dir); -} - -wxString wxFTP::Pwd() -{ - wxString path; - - if ( CheckCommand(wxT("PWD"), '2') ) - { - // the result is at least that long if CheckCommand() succeeded - const wxChar *p = m_lastResult.c_str() + LEN_CODE + 1; - if ( *p != _T('"') ) - { - wxLogDebug(_T("Missing starting quote in reply for PWD: %s"), p); - } - else - { - for ( p++; *p; p++ ) - { - if ( *p == _T('"') ) - { - // check if the quote is doubled - p++; - if ( !*p || *p != _T('"') ) - { - // no, this is the end - break; - } - //else: yes, it is: this is an embedded quote in the - // filename, treat as normal char - } - - path += *p; - } - - if ( !*p ) - { - wxLogDebug(_T("Missing ending quote in reply for PWD: %s"), - m_lastResult.c_str() + LEN_CODE + 1); - } - } - } - else - { - wxLogDebug(_T("FTP PWD command failed.")); - } - - return path; -} - -bool wxFTP::Rename(const wxString& src, const wxString& dst) -{ - wxString str; - - str = wxT("RNFR ") + src; - if ( !CheckCommand(str, '3') ) - return false; - - str = wxT("RNTO ") + dst; - - return CheckCommand(str, '2'); -} - -bool wxFTP::RmFile(const wxString& path) -{ - wxString str; - str = wxT("DELE ") + path; - - return CheckCommand(str, '2'); -} - -// ---------------------------------------------------------------------------- -// wxFTP download and upload -// ---------------------------------------------------------------------------- - -class wxInputFTPStream : public wxSocketInputStream -{ -public: - wxInputFTPStream(wxFTP *ftp, wxSocketBase *sock) - : wxSocketInputStream(*sock) - { - m_ftp = ftp; - // socket timeout automatically set in GetPort function - } - - virtual ~wxInputFTPStream() - { - delete m_i_socket; // keep at top - - // when checking the result, the stream will - // almost always show an error, even if the file was - // properly transfered, thus, lets just grab the result - - // we are looking for "226 transfer completed" - char code = m_ftp->GetResult(); - if ('2' == code) - { - // it was a good transfer. - // we're done! - m_ftp->m_streaming = false; - return; - } - // did we timeout? - if (0 == code) - { - // the connection is probably toast. issue an abort, and - // then a close. there won't be any more waiting - // for this connection - m_ftp->Abort(); - m_ftp->Close(); - return; - } - // There was a problem with the transfer and the server - // has acknowledged it. If we issue an "ABORT" now, the user - // would get the "226" for the abort and think the xfer was - // complete, thus, don't do anything here, just return - } - - wxFTP *m_ftp; - - DECLARE_NO_COPY_CLASS(wxInputFTPStream) -}; - -class wxOutputFTPStream : public wxSocketOutputStream -{ -public: - wxOutputFTPStream(wxFTP *ftp_clt, wxSocketBase *sock) - : wxSocketOutputStream(*sock), m_ftp(ftp_clt) - { - } - - virtual ~wxOutputFTPStream(void) - { - if ( IsOk() ) - { - // close data connection first, this will generate "transfer - // completed" reply - delete m_o_socket; - - // read this reply - m_ftp->GetResult(); // save result so user can get to it - - m_ftp->m_streaming = false; - } - else - { - // abort data connection first - m_ftp->Abort(); - - // and close it after - delete m_o_socket; - } - } - - wxFTP *m_ftp; - - DECLARE_NO_COPY_CLASS(wxOutputFTPStream) -}; - -void wxFTP::SetDefaultTimeout(wxUint32 Value) -{ - m_uiDefaultTimeout = Value; - SetTimeout(Value); // sets it for this socket -} - - -wxSocketBase *wxFTP::GetPort() -{ - /* - PASSIVE: Client sends a "PASV" to the server. The server responds with - an address and port number which it will be listening on. Then - the client connects to the server at the specified address and - port. - - ACTIVE: Client sends the server a PORT command which includes an - address and port number which the client will be listening on. - The server then connects to the client at that address and - port. - */ - - wxSocketBase *socket = m_bPassive ? GetPassivePort() : GetActivePort(); - if ( !socket ) - { - m_bEncounteredError = true; - return NULL; - } - - // Now set the time for the new socket to the default or user selected - // timeout period - socket->SetTimeout(m_uiDefaultTimeout); - - return socket; -} - -wxSocketBase *wxFTP::AcceptIfActive(wxSocketBase *sock) -{ - if ( m_bPassive ) - return sock; - - // now wait for a connection from server - wxSocketServer *sockSrv = (wxSocketServer *)sock; - if ( !sockSrv->WaitForAccept() ) - { - m_lastError = wxPROTO_CONNERR; - wxLogError(_("Timeout while waiting for FTP server to connect, try passive mode.")); - delete sock; - sock = NULL; - } - else - { - sock = sockSrv->Accept(true); - delete sockSrv; - } - - return sock; -} - -wxString wxFTP::GetPortCmdArgument(const wxIPV4address& addrLocal, - const wxIPV4address& addrNew) -{ - // Just fills in the return value with the local IP - // address of the current socket. Also it fill in the - // PORT which the client will be listening on - - wxString addrIP = addrLocal.IPAddress(); - int portNew = addrNew.Service(); - - // We need to break the PORT number in bytes - addrIP.Replace(_T("."), _T(",")); - addrIP << _T(',') - << wxString::Format(_T("%d"), portNew >> 8) << _T(',') - << wxString::Format(_T("%d"), portNew & 0xff); - - // Now we have a value like "10,0,0,1,5,23" - return addrIP; -} - -wxSocketBase *wxFTP::GetActivePort() -{ - // we need an address to listen on - wxIPV4address addrNew, addrLocal; - GetLocal(addrLocal); - addrNew.AnyAddress(); - addrNew.Service(0); // pick an open port number. - - wxSocketServer *sockSrv = new wxSocketServer(addrNew); - if (!sockSrv->Ok()) - { - // We use Ok() here to see if everything is ok - m_lastError = wxPROTO_PROTERR; - delete sockSrv; - return NULL; - } - - //gets the new address, actually it is just the port number - sockSrv->GetLocal(addrNew); - - // Now we create the argument of the PORT command, we send in both - // addresses because the addrNew has an IP of "0.0.0.0", so we need the - // value in addrLocal - wxString port = GetPortCmdArgument(addrLocal, addrNew); - if ( !DoSimpleCommand(_T("PORT"), port) ) - { - m_lastError = wxPROTO_PROTERR; - delete sockSrv; - wxLogError(_("The FTP server doesn't support the PORT command.")); - return NULL; - } - - sockSrv->Notify(false); // Don't send any events - return sockSrv; -} - -wxSocketBase *wxFTP::GetPassivePort() -{ - if ( !DoSimpleCommand(_T("PASV")) ) - { - wxLogError(_("The FTP server doesn't support passive mode.")); - return NULL; - } - - const wxChar *addrStart = wxStrchr(m_lastResult, _T('(')); - const wxChar *addrEnd = addrStart ? wxStrchr(addrStart, _T(')')) : NULL; - if ( !addrEnd ) - { - m_lastError = wxPROTO_PROTERR; - - return NULL; - } - - // get the port number and address - int a[6]; - wxString straddr(addrStart + 1, addrEnd); - wxSscanf(straddr, wxT("%d,%d,%d,%d,%d,%d"), - &a[2],&a[3],&a[4],&a[5],&a[0],&a[1]); - - wxUint32 hostaddr = (wxUint16)a[2] << 24 | - (wxUint16)a[3] << 16 | - (wxUint16)a[4] << 8 | - a[5]; - wxUint16 port = (wxUint16)(a[0] << 8 | a[1]); - - wxIPV4address addr; - addr.Hostname(hostaddr); - addr.Service(port); - - wxSocketClient *client = new wxSocketClient(); - if ( !client->Connect(addr) ) - { - delete client; - return NULL; - } - - client->Notify(false); - - return client; -} - -bool wxFTP::Abort() -{ - if ( !m_streaming ) - return true; - - m_streaming = false; - if ( !CheckCommand(wxT("ABOR"), '4') ) - return false; - - return CheckResult('2'); -} - -wxInputStream *wxFTP::GetInputStream(const wxString& path) -{ - if ( ( m_currentTransfermode == NONE ) && !SetTransferMode(BINARY) ) - return NULL; - - wxSocketBase *sock = GetPort(); - - if ( !sock ) - { - m_lastError = wxPROTO_NETERR; - return NULL; - } - - wxString tmp_str = wxT("RETR ") + wxURI::Unescape(path); - if ( !CheckCommand(tmp_str, '1') ) - return NULL; - - sock = AcceptIfActive(sock); - if ( !sock ) - return NULL; - - sock->SetFlags(wxSOCKET_WAITALL); - - m_streaming = true; - - wxInputFTPStream *in_stream = new wxInputFTPStream(this, sock); - - return in_stream; -} - -wxOutputStream *wxFTP::GetOutputStream(const wxString& path) -{ - if ( ( m_currentTransfermode == NONE ) && !SetTransferMode(BINARY) ) - return NULL; - - wxSocketBase *sock = GetPort(); - - wxString tmp_str = wxT("STOR ") + path; - if ( !CheckCommand(tmp_str, '1') ) - return NULL; - - sock = AcceptIfActive(sock); - - m_streaming = true; - - return new wxOutputFTPStream(this, sock); -} - -// ---------------------------------------------------------------------------- -// FTP directory listing -// ---------------------------------------------------------------------------- - -bool wxFTP::GetList(wxArrayString& files, - const wxString& wildcard, - bool details) -{ - wxSocketBase *sock = GetPort(); - if (!sock) - return false; - - // NLST : List of Filenames (including Directory's !) - // LIST : depending on BS of FTP-Server - // - Unix : result like "ls" command - // - Windows : like "dir" command - // - others : ? - wxString line(details ? _T("LIST") : _T("NLST")); - if ( !wildcard.empty() ) - { - line << _T(' ') << wildcard; - } - - if ( !CheckCommand(line, '1') ) - { - m_lastError = wxPROTO_PROTERR; - wxLogDebug(_T("FTP 'LIST' command returned unexpected result from server")); - delete sock; - return false; - } - - sock = AcceptIfActive(sock); - if ( !sock ) - return false; - - files.Empty(); - while (ReadLine(sock, line) == wxPROTO_NOERR ) - { - files.Add(line); - } - - delete sock; - - // the file list should be terminated by "226 Transfer complete"" - return CheckResult('2'); -} - -bool wxFTP::FileExists(const wxString& fileName) -{ - // This function checks if the file specified in fileName exists in the - // current dir. It does so by simply doing an NLST (via GetList). - // If this succeeds (and the list is not empty) the file exists. - - bool retval = false; - wxArrayString fileList; - - if ( GetList(fileList, fileName, false) ) - { - // Some ftp-servers (Ipswitch WS_FTP Server 1.0.5 does this) - // displays this behaviour when queried on a nonexistent file: - // NLST this_file_does_not_exist - // 150 Opening ASCII data connection for directory listing - // (no data transferred) - // 226 Transfer complete - // Here wxFTP::GetList(...) will succeed but it will return an empty - // list. - retval = !fileList.IsEmpty(); - } - - return retval; -} - -// ---------------------------------------------------------------------------- -// FTP GetSize -// ---------------------------------------------------------------------------- - -int wxFTP::GetFileSize(const wxString& fileName) -{ - // return the filesize of the given file if possible - // return -1 otherwise (predominantly if file doesn't exist - // in current dir) - - int filesize = -1; - - // Check for existance of file via wxFTP::FileExists(...) - if ( FileExists(fileName) ) - { - wxString command; - - // First try "SIZE" command using BINARY(IMAGE) transfermode - // Especially UNIX ftp-servers distinguish between the different - // transfermodes and reports different filesizes accordingly. - // The BINARY size is the interesting one: How much memory - // will we need to hold this file? - TransferMode oldTransfermode = m_currentTransfermode; - SetTransferMode(BINARY); - command << _T("SIZE ") << fileName; - - bool ok = CheckCommand(command, '2'); - - if ( ok ) - { - // The answer should be one line: "213 \n" - // 213 is File Status (STD9) - // "SIZE" is not described anywhere..? It works on most servers - int statuscode; - if ( wxSscanf(GetLastResult().c_str(), _T("%i %i"), - &statuscode, &filesize) == 2 ) - { - // We've gotten a good reply. - ok = true; - } - else - { - // Something bad happened.. A "2yz" reply with no size - // Fallback - ok = false; - } - } - - // Set transfermode back to the original. Only the "SIZE"-command - // is dependant on transfermode - if ( oldTransfermode != NONE ) - { - SetTransferMode(oldTransfermode); - } - - // this is not a direct else clause.. The size command might return an - // invalid "2yz" reply - if ( !ok ) - { - // The server didn't understand the "SIZE"-command or it - // returned an invalid reply. - // We now try to get details for the file with a "LIST"-command - // and then parse the output from there.. - wxArrayString fileList; - if ( GetList(fileList, fileName, true) ) - { - if ( !fileList.IsEmpty() ) - { - // We _should_ only get one line in return, but just to be - // safe we run through the line(s) returned and look for a - // substring containing the name we are looking for. We - // stop the iteration at the first occurrence of the - // filename. The search is not case-sensitive. - bool foundIt = false; - - size_t i; - for ( i = 0; !foundIt && i < fileList.Count(); i++ ) - { - foundIt = fileList[i].Upper().Contains(fileName.Upper()); - } - - if ( foundIt ) - { - // The index i points to the first occurrence of - // fileName in the array Now we have to find out what - // format the LIST has returned. There are two - // "schools": Unix-like - // - // '-rw-rw-rw- owner group size month day time filename' - // - // or Windows-like - // - // 'date size filename' - - // check if the first character is '-'. This would - // indicate Unix-style (this also limits this function - // to searching for files, not directories) - if ( fileList[i].Mid(0, 1) == _T("-") ) - { - - if ( wxSscanf(fileList[i].c_str(), - _T("%*s %*s %*s %*s %i %*s %*s %*s %*s"), - &filesize) != 9 ) - { - // Hmm... Invalid response - wxLogTrace(FTP_TRACE_MASK, - _T("Invalid LIST response")); - } - } - else // Windows-style response (?) - { - if ( wxSscanf(fileList[i].c_str(), - _T("%*s %*s %i %*s"), - &filesize) != 4 ) - { - // something bad happened..? - wxLogTrace(FTP_TRACE_MASK, - _T("Invalid or unknown LIST response")); - } - } - } - } - } - } - } - - // filesize might still be -1 when exiting - return filesize; -} - -#endif // wxUSE_PROTOCOL_FTP - +///////////////////////////////////////////////////////////////////////////// +// Name: common/ftp.cpp +// Purpose: FTP protocol +// Author: Guilhem Lavaux +// Modified by: Mark Johnson, wxWindows@mj10777.de +// 20000917 : RmDir, GetLastResult, GetList +// Vadim Zeitlin (numerous fixes and rewrites to all part of the +// code, support ASCII/Binary modes, better error reporting, more +// robust Abort(), support for arbitrary FTP commands, ...) +// Randall Fox (support for active mode) +// Created: 07/07/1997 +// RCS-ID: $Id: ftp.cpp 47969 2007-08-08 23:34:14Z VZ $ +// Copyright: (c) 1997, 1998 Guilhem Lavaux +// (c) 1998-2004 wxWidgets team +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_PROTOCOL_FTP + +#ifndef WX_PRECOMP + #include + #include "wx/string.h" + #include "wx/utils.h" + #include "wx/log.h" + #include "wx/intl.h" +#endif // WX_PRECOMP + +#include "wx/sckaddr.h" +#include "wx/socket.h" +#include "wx/url.h" +#include "wx/sckstrm.h" +#include "wx/protocol/protocol.h" +#include "wx/protocol/ftp.h" + +#if defined(__WXMAC__) + #include "wx/mac/macsock.h" +#endif + +#ifndef __MWERKS__ + #include +#endif + +// ---------------------------------------------------------------------------- +// constants +// ---------------------------------------------------------------------------- + +// the length of FTP status code (3 digits) +static const size_t LEN_CODE = 3; + +// ---------------------------------------------------------------------------- +// macros +// ---------------------------------------------------------------------------- + +IMPLEMENT_DYNAMIC_CLASS(wxFTP, wxProtocol) +IMPLEMENT_PROTOCOL(wxFTP, wxT("ftp"), wxT("ftp"), true) + +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// wxFTP constructor and destructor +// ---------------------------------------------------------------------------- + +wxFTP::wxFTP() +{ + m_lastError = wxPROTO_NOERR; + m_streaming = false; + m_currentTransfermode = NONE; + + m_user = wxT("anonymous"); + m_passwd << wxGetUserId() << wxT('@') << wxGetFullHostName(); + + SetNotify(0); + SetFlags(wxSOCKET_NOWAIT); + m_bPassive = true; + SetDefaultTimeout(60); // Default is Sixty Seconds + m_bEncounteredError = false; +} + +wxFTP::~wxFTP() +{ + if ( m_streaming ) + { + // if we are streaming, this will issue + // an FTP ABORT command, to tell the server we are aborting + (void)Abort(); + } + + // now this issues a "QUIT" command to tell the server we are + Close(); +} + +// ---------------------------------------------------------------------------- +// wxFTP connect and login methods +// ---------------------------------------------------------------------------- + +bool wxFTP::Connect(wxSockAddress& addr, bool WXUNUSED(wait)) +{ + if ( !wxProtocol::Connect(addr) ) + { + m_lastError = wxPROTO_NETERR; + return false; + } + + if ( !m_user ) + { + m_lastError = wxPROTO_CONNERR; + return false; + } + + // we should have 220 welcome message + if ( !CheckResult('2') ) + { + Close(); + return false; + } + + wxString command; + command.Printf(wxT("USER %s"), m_user.c_str()); + char rc = SendCommand(command); + if ( rc == '2' ) + { + // 230 return: user accepted without password + return true; + } + + if ( rc != '3' ) + { + Close(); + return false; + } + + command.Printf(wxT("PASS %s"), m_passwd.c_str()); + if ( !CheckCommand(command, '2') ) + { + Close(); + return false; + } + + return true; +} + +bool wxFTP::Connect(const wxString& host) +{ + wxIPV4address addr; + addr.Hostname(host); + addr.Service(wxT("ftp")); + + return Connect(addr); +} + +bool wxFTP::Close() +{ + if ( m_streaming ) + { + m_lastError = wxPROTO_STREAMING; + return false; + } + + if ( IsConnected() ) + { + if ( !CheckCommand(wxT("QUIT"), '2') ) + { + wxLogDebug(_T("Failed to close connection gracefully.")); + } + } + + return wxSocketClient::Close(); +} + +// ============================================================================ +// low level methods +// ============================================================================ + +// ---------------------------------------------------------------------------- +// Send command to FTP server +// ---------------------------------------------------------------------------- + +char wxFTP::SendCommand(const wxString& command) +{ + if ( m_streaming ) + { + m_lastError = wxPROTO_STREAMING; + return 0; + } + + wxString tmp_str = command + wxT("\r\n"); + const wxWX2MBbuf tmp_buf = tmp_str.mb_str(); + if ( Write(wxMBSTRINGCAST tmp_buf, strlen(tmp_buf)).Error()) + { + m_lastError = wxPROTO_NETERR; + return 0; + } + +#ifdef __WXDEBUG__ + // don't show the passwords in the logs (even in debug ones) + wxString cmd, password; + if ( command.Upper().StartsWith(_T("PASS "), &password) ) + { + cmd << _T("PASS ") << wxString(_T('*'), password.length()); + } + else + { + cmd = command; + } + + wxLogTrace(FTP_TRACE_MASK, _T("==> %s"), cmd.c_str()); +#endif // __WXDEBUG__ + + return GetResult(); +} + +// ---------------------------------------------------------------------------- +// Recieve servers reply +// ---------------------------------------------------------------------------- + +char wxFTP::GetResult() +{ + // if we've already had a read or write timeout error, the connection is + // probably toast, so don't bother, it just wastes the users time + if ( m_bEncounteredError ) + return 0; + + wxString code; + + // m_lastResult will contain the entire server response, possibly on + // multiple lines + m_lastResult.clear(); + + // we handle multiline replies here according to RFC 959: it says that a + // reply may either be on 1 line of the form "xyz ..." or on several lines + // in whuch case it looks like + // xyz-... + // ... + // xyz ... + // and the intermeidate lines may start with xyz or not + bool badReply = false; + bool firstLine = true; + bool endOfReply = false; + while ( !endOfReply && !badReply ) + { + wxString line; + m_lastError = ReadLine(this,line); + if ( m_lastError ) + { + m_bEncounteredError = true; + return 0; + } + + if ( !m_lastResult.empty() ) + { + // separate from last line + m_lastResult += _T('\n'); + } + + m_lastResult += line; + + // unless this is an intermediate line of a multiline reply, it must + // contain the code in the beginning and '-' or ' ' following it + if ( line.Len() < LEN_CODE + 1 ) + { + if ( firstLine ) + { + badReply = true; + } + else + { + wxLogTrace(FTP_TRACE_MASK, _T("<== %s %s"), + code.c_str(), line.c_str()); + } + } + else // line has at least 4 chars + { + // this is the char which tells us what we're dealing with + wxChar chMarker = line.GetChar(LEN_CODE); + + if ( firstLine ) + { + code = wxString(line, LEN_CODE); + wxLogTrace(FTP_TRACE_MASK, _T("<== %s %s"), + code.c_str(), line.c_str() + LEN_CODE + 1); + + switch ( chMarker ) + { + case _T(' '): + endOfReply = true; + break; + + case _T('-'): + firstLine = false; + break; + + default: + // unexpected + badReply = true; + } + } + else // subsequent line of multiline reply + { + if ( wxStrncmp(line, code, LEN_CODE) == 0 ) + { + if ( chMarker == _T(' ') ) + { + endOfReply = true; + } + + wxLogTrace(FTP_TRACE_MASK, _T("<== %s %s"), + code.c_str(), line.c_str() + LEN_CODE + 1); + } + else + { + // just part of reply + wxLogTrace(FTP_TRACE_MASK, _T("<== %s %s"), + code.c_str(), line.c_str()); + } + } + } + } + + if ( badReply ) + { + wxLogDebug(_T("Broken FTP server: '%s' is not a valid reply."), + m_lastResult.c_str()); + + m_lastError = wxPROTO_PROTERR; + + return 0; + } + + // if we got here we must have a non empty code string + return (char)code[0u]; +} + +// ---------------------------------------------------------------------------- +// wxFTP simple commands +// ---------------------------------------------------------------------------- + +bool wxFTP::SetTransferMode(TransferMode transferMode) +{ + if ( transferMode == m_currentTransfermode ) + { + // nothing to do + return true; + } + + wxString mode; + switch ( transferMode ) + { + default: + wxFAIL_MSG(_T("unknown FTP transfer mode")); + // fall through + + case BINARY: + mode = _T('I'); + break; + + case ASCII: + mode = _T('A'); + break; + } + + if ( !DoSimpleCommand(_T("TYPE"), mode) ) + { + wxLogError(_("Failed to set FTP transfer mode to %s."), (const wxChar*) + (transferMode == ASCII ? _("ASCII") : _("binary"))); + + return false; + } + + // If we get here the operation has been successfully completed + // Set the status-member + m_currentTransfermode = transferMode; + + return true; +} + +bool wxFTP::DoSimpleCommand(const wxChar *command, const wxString& arg) +{ + wxString fullcmd = command; + if ( !arg.empty() ) + { + fullcmd << _T(' ') << arg; + } + + if ( !CheckCommand(fullcmd, '2') ) + { + wxLogDebug(_T("FTP command '%s' failed."), fullcmd.c_str()); + + return false; + } + + return true; +} + +bool wxFTP::ChDir(const wxString& dir) +{ + // some servers might not understand ".." if they use different directory + // tree conventions, but they always understand CDUP - should we use it if + // dir == ".."? OTOH, do such servers (still) exist? + + return DoSimpleCommand(_T("CWD"), dir); +} + +bool wxFTP::MkDir(const wxString& dir) +{ + return DoSimpleCommand(_T("MKD"), dir); +} + +bool wxFTP::RmDir(const wxString& dir) +{ + return DoSimpleCommand(_T("RMD"), dir); +} + +wxString wxFTP::Pwd() +{ + wxString path; + + if ( CheckCommand(wxT("PWD"), '2') ) + { + // the result is at least that long if CheckCommand() succeeded + const wxChar *p = m_lastResult.c_str() + LEN_CODE + 1; + if ( *p != _T('"') ) + { + wxLogDebug(_T("Missing starting quote in reply for PWD: %s"), p); + } + else + { + for ( p++; *p; p++ ) + { + if ( *p == _T('"') ) + { + // check if the quote is doubled + p++; + if ( !*p || *p != _T('"') ) + { + // no, this is the end + break; + } + //else: yes, it is: this is an embedded quote in the + // filename, treat as normal char + } + + path += *p; + } + + if ( !*p ) + { + wxLogDebug(_T("Missing ending quote in reply for PWD: %s"), + m_lastResult.c_str() + LEN_CODE + 1); + } + } + } + else + { + wxLogDebug(_T("FTP PWD command failed.")); + } + + return path; +} + +bool wxFTP::Rename(const wxString& src, const wxString& dst) +{ + wxString str; + + str = wxT("RNFR ") + src; + if ( !CheckCommand(str, '3') ) + return false; + + str = wxT("RNTO ") + dst; + + return CheckCommand(str, '2'); +} + +bool wxFTP::RmFile(const wxString& path) +{ + wxString str; + str = wxT("DELE ") + path; + + return CheckCommand(str, '2'); +} + +// ---------------------------------------------------------------------------- +// wxFTP download and upload +// ---------------------------------------------------------------------------- + +class wxInputFTPStream : public wxSocketInputStream +{ +public: + wxInputFTPStream(wxFTP *ftp, wxSocketBase *sock) + : wxSocketInputStream(*sock) + { + m_ftp = ftp; + // socket timeout automatically set in GetPort function + } + + virtual ~wxInputFTPStream() + { + delete m_i_socket; // keep at top + + // when checking the result, the stream will + // almost always show an error, even if the file was + // properly transfered, thus, lets just grab the result + + // we are looking for "226 transfer completed" + char code = m_ftp->GetResult(); + if ('2' == code) + { + // it was a good transfer. + // we're done! + m_ftp->m_streaming = false; + return; + } + // did we timeout? + if (0 == code) + { + // the connection is probably toast. issue an abort, and + // then a close. there won't be any more waiting + // for this connection + m_ftp->Abort(); + m_ftp->Close(); + return; + } + // There was a problem with the transfer and the server + // has acknowledged it. If we issue an "ABORT" now, the user + // would get the "226" for the abort and think the xfer was + // complete, thus, don't do anything here, just return + } + + wxFTP *m_ftp; + + DECLARE_NO_COPY_CLASS(wxInputFTPStream) +}; + +class wxOutputFTPStream : public wxSocketOutputStream +{ +public: + wxOutputFTPStream(wxFTP *ftp_clt, wxSocketBase *sock) + : wxSocketOutputStream(*sock), m_ftp(ftp_clt) + { + } + + virtual ~wxOutputFTPStream(void) + { + if ( IsOk() ) + { + // close data connection first, this will generate "transfer + // completed" reply + delete m_o_socket; + + // read this reply + m_ftp->GetResult(); // save result so user can get to it + + m_ftp->m_streaming = false; + } + else + { + // abort data connection first + m_ftp->Abort(); + + // and close it after + delete m_o_socket; + } + } + + wxFTP *m_ftp; + + DECLARE_NO_COPY_CLASS(wxOutputFTPStream) +}; + +void wxFTP::SetDefaultTimeout(wxUint32 Value) +{ + m_uiDefaultTimeout = Value; + SetTimeout(Value); // sets it for this socket +} + + +wxSocketBase *wxFTP::GetPort() +{ + /* + PASSIVE: Client sends a "PASV" to the server. The server responds with + an address and port number which it will be listening on. Then + the client connects to the server at the specified address and + port. + + ACTIVE: Client sends the server a PORT command which includes an + address and port number which the client will be listening on. + The server then connects to the client at that address and + port. + */ + + wxSocketBase *socket = m_bPassive ? GetPassivePort() : GetActivePort(); + if ( !socket ) + { + m_bEncounteredError = true; + return NULL; + } + + // Now set the time for the new socket to the default or user selected + // timeout period + socket->SetTimeout(m_uiDefaultTimeout); + + return socket; +} + +wxSocketBase *wxFTP::AcceptIfActive(wxSocketBase *sock) +{ + if ( m_bPassive ) + return sock; + + // now wait for a connection from server + wxSocketServer *sockSrv = (wxSocketServer *)sock; + if ( !sockSrv->WaitForAccept() ) + { + m_lastError = wxPROTO_CONNERR; + wxLogError(_("Timeout while waiting for FTP server to connect, try passive mode.")); + delete sock; + sock = NULL; + } + else + { + sock = sockSrv->Accept(true); + delete sockSrv; + } + + return sock; +} + +wxString wxFTP::GetPortCmdArgument(const wxIPV4address& addrLocal, + const wxIPV4address& addrNew) +{ + // Just fills in the return value with the local IP + // address of the current socket. Also it fill in the + // PORT which the client will be listening on + + wxString addrIP = addrLocal.IPAddress(); + int portNew = addrNew.Service(); + + // We need to break the PORT number in bytes + addrIP.Replace(_T("."), _T(",")); + addrIP << _T(',') + << wxString::Format(_T("%d"), portNew >> 8) << _T(',') + << wxString::Format(_T("%d"), portNew & 0xff); + + // Now we have a value like "10,0,0,1,5,23" + return addrIP; +} + +wxSocketBase *wxFTP::GetActivePort() +{ + // we need an address to listen on + wxIPV4address addrNew, addrLocal; + GetLocal(addrLocal); + addrNew.AnyAddress(); + addrNew.Service(0); // pick an open port number. + + wxSocketServer *sockSrv = new wxSocketServer(addrNew); + if (!sockSrv->Ok()) + { + // We use Ok() here to see if everything is ok + m_lastError = wxPROTO_PROTERR; + delete sockSrv; + return NULL; + } + + //gets the new address, actually it is just the port number + sockSrv->GetLocal(addrNew); + + // Now we create the argument of the PORT command, we send in both + // addresses because the addrNew has an IP of "0.0.0.0", so we need the + // value in addrLocal + wxString port = GetPortCmdArgument(addrLocal, addrNew); + if ( !DoSimpleCommand(_T("PORT"), port) ) + { + m_lastError = wxPROTO_PROTERR; + delete sockSrv; + wxLogError(_("The FTP server doesn't support the PORT command.")); + return NULL; + } + + sockSrv->Notify(false); // Don't send any events + return sockSrv; +} + +wxSocketBase *wxFTP::GetPassivePort() +{ + if ( !DoSimpleCommand(_T("PASV")) ) + { + wxLogError(_("The FTP server doesn't support passive mode.")); + return NULL; + } + + const wxChar *addrStart = wxStrchr(m_lastResult, _T('(')); + const wxChar *addrEnd = addrStart ? wxStrchr(addrStart, _T(')')) : NULL; + if ( !addrEnd ) + { + m_lastError = wxPROTO_PROTERR; + + return NULL; + } + + // get the port number and address + int a[6]; + wxString straddr(addrStart + 1, addrEnd); + wxSscanf(straddr, wxT("%d,%d,%d,%d,%d,%d"), + &a[2],&a[3],&a[4],&a[5],&a[0],&a[1]); + + wxUint32 hostaddr = (wxUint16)a[2] << 24 | + (wxUint16)a[3] << 16 | + (wxUint16)a[4] << 8 | + a[5]; + wxUint16 port = (wxUint16)(a[0] << 8 | a[1]); + + wxIPV4address addr; + addr.Hostname(hostaddr); + addr.Service(port); + + wxSocketClient *client = new wxSocketClient(); + if ( !client->Connect(addr) ) + { + delete client; + return NULL; + } + + client->Notify(false); + + return client; +} + +bool wxFTP::Abort() +{ + if ( !m_streaming ) + return true; + + m_streaming = false; + if ( !CheckCommand(wxT("ABOR"), '4') ) + return false; + + return CheckResult('2'); +} + +wxInputStream *wxFTP::GetInputStream(const wxString& path) +{ + if ( ( m_currentTransfermode == NONE ) && !SetTransferMode(BINARY) ) + return NULL; + + wxSocketBase *sock = GetPort(); + + if ( !sock ) + { + m_lastError = wxPROTO_NETERR; + return NULL; + } + + wxString tmp_str = wxT("RETR ") + wxURI::Unescape(path); + if ( !CheckCommand(tmp_str, '1') ) + return NULL; + + sock = AcceptIfActive(sock); + if ( !sock ) + return NULL; + + sock->SetFlags(wxSOCKET_WAITALL); + + m_streaming = true; + + wxInputFTPStream *in_stream = new wxInputFTPStream(this, sock); + + return in_stream; +} + +wxOutputStream *wxFTP::GetOutputStream(const wxString& path) +{ + if ( ( m_currentTransfermode == NONE ) && !SetTransferMode(BINARY) ) + return NULL; + + wxSocketBase *sock = GetPort(); + + wxString tmp_str = wxT("STOR ") + path; + if ( !CheckCommand(tmp_str, '1') ) + return NULL; + + sock = AcceptIfActive(sock); + + m_streaming = true; + + return new wxOutputFTPStream(this, sock); +} + +// ---------------------------------------------------------------------------- +// FTP directory listing +// ---------------------------------------------------------------------------- + +bool wxFTP::GetList(wxArrayString& files, + const wxString& wildcard, + bool details) +{ + wxSocketBase *sock = GetPort(); + if (!sock) + return false; + + // NLST : List of Filenames (including Directory's !) + // LIST : depending on BS of FTP-Server + // - Unix : result like "ls" command + // - Windows : like "dir" command + // - others : ? + wxString line(details ? _T("LIST") : _T("NLST")); + if ( !wildcard.empty() ) + { + line << _T(' ') << wildcard; + } + + if ( !CheckCommand(line, '1') ) + { + m_lastError = wxPROTO_PROTERR; + wxLogDebug(_T("FTP 'LIST' command returned unexpected result from server")); + delete sock; + return false; + } + + sock = AcceptIfActive(sock); + if ( !sock ) + return false; + + files.Empty(); + while (ReadLine(sock, line) == wxPROTO_NOERR ) + { + files.Add(line); + } + + delete sock; + + // the file list should be terminated by "226 Transfer complete"" + return CheckResult('2'); +} + +bool wxFTP::FileExists(const wxString& fileName) +{ + // This function checks if the file specified in fileName exists in the + // current dir. It does so by simply doing an NLST (via GetList). + // If this succeeds (and the list is not empty) the file exists. + + bool retval = false; + wxArrayString fileList; + + if ( GetList(fileList, fileName, false) ) + { + // Some ftp-servers (Ipswitch WS_FTP Server 1.0.5 does this) + // displays this behaviour when queried on a nonexistent file: + // NLST this_file_does_not_exist + // 150 Opening ASCII data connection for directory listing + // (no data transferred) + // 226 Transfer complete + // Here wxFTP::GetList(...) will succeed but it will return an empty + // list. + retval = !fileList.IsEmpty(); + } + + return retval; +} + +// ---------------------------------------------------------------------------- +// FTP GetSize +// ---------------------------------------------------------------------------- + +int wxFTP::GetFileSize(const wxString& fileName) +{ + // return the filesize of the given file if possible + // return -1 otherwise (predominantly if file doesn't exist + // in current dir) + + int filesize = -1; + + // Check for existance of file via wxFTP::FileExists(...) + if ( FileExists(fileName) ) + { + wxString command; + + // First try "SIZE" command using BINARY(IMAGE) transfermode + // Especially UNIX ftp-servers distinguish between the different + // transfermodes and reports different filesizes accordingly. + // The BINARY size is the interesting one: How much memory + // will we need to hold this file? + TransferMode oldTransfermode = m_currentTransfermode; + SetTransferMode(BINARY); + command << _T("SIZE ") << fileName; + + bool ok = CheckCommand(command, '2'); + + if ( ok ) + { + // The answer should be one line: "213 \n" + // 213 is File Status (STD9) + // "SIZE" is not described anywhere..? It works on most servers + int statuscode; + if ( wxSscanf(GetLastResult().c_str(), _T("%i %i"), + &statuscode, &filesize) == 2 ) + { + // We've gotten a good reply. + ok = true; + } + else + { + // Something bad happened.. A "2yz" reply with no size + // Fallback + ok = false; + } + } + + // Set transfermode back to the original. Only the "SIZE"-command + // is dependant on transfermode + if ( oldTransfermode != NONE ) + { + SetTransferMode(oldTransfermode); + } + + // this is not a direct else clause.. The size command might return an + // invalid "2yz" reply + if ( !ok ) + { + // The server didn't understand the "SIZE"-command or it + // returned an invalid reply. + // We now try to get details for the file with a "LIST"-command + // and then parse the output from there.. + wxArrayString fileList; + if ( GetList(fileList, fileName, true) ) + { + if ( !fileList.IsEmpty() ) + { + // We _should_ only get one line in return, but just to be + // safe we run through the line(s) returned and look for a + // substring containing the name we are looking for. We + // stop the iteration at the first occurrence of the + // filename. The search is not case-sensitive. + bool foundIt = false; + + size_t i; + for ( i = 0; !foundIt && i < fileList.Count(); i++ ) + { + foundIt = fileList[i].Upper().Contains(fileName.Upper()); + } + + if ( foundIt ) + { + // The index i points to the first occurrence of + // fileName in the array Now we have to find out what + // format the LIST has returned. There are two + // "schools": Unix-like + // + // '-rw-rw-rw- owner group size month day time filename' + // + // or Windows-like + // + // 'date size filename' + + // check if the first character is '-'. This would + // indicate Unix-style (this also limits this function + // to searching for files, not directories) + if ( fileList[i].Mid(0, 1) == _T("-") ) + { + + if ( wxSscanf(fileList[i].c_str(), + _T("%*s %*s %*s %*s %i %*s %*s %*s %*s"), + &filesize) != 9 ) + { + // Hmm... Invalid response + wxLogTrace(FTP_TRACE_MASK, + _T("Invalid LIST response")); + } + } + else // Windows-style response (?) + { + if ( wxSscanf(fileList[i].c_str(), + _T("%*s %*s %i %*s"), + &filesize) != 4 ) + { + // something bad happened..? + wxLogTrace(FTP_TRACE_MASK, + _T("Invalid or unknown LIST response")); + } + } + } + } + } + } + } + + // filesize might still be -1 when exiting + return filesize; +} + +#endif // wxUSE_PROTOCOL_FTP + diff --git a/Externals/wxWidgets/src/common/gaugecmn.cpp b/Externals/wxWidgets/src/common/gaugecmn.cpp index f672bb6a3d..d8ab642e69 100644 --- a/Externals/wxWidgets/src/common/gaugecmn.cpp +++ b/Externals/wxWidgets/src/common/gaugecmn.cpp @@ -1,156 +1,156 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: src/common/gaugecmn.cpp -// Purpose: wxGaugeBase: common to all ports methods of wxGauge -// Author: Vadim Zeitlin -// Modified by: -// Created: 20.02.01 -// RCS-ID: $Id: gaugecmn.cpp 41089 2006-09-09 13:36:54Z RR $ -// Copyright: (c) 2001 Vadim Zeitlin -// License: wxWindows licence -/////////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#ifndef WX_PRECOMP -#endif //WX_PRECOMP - -#if wxUSE_GAUGE - -#include "wx/gauge.h" - -const wxChar wxGaugeNameStr[] = wxT("gauge"); - -// ============================================================================ -// implementation -// ============================================================================ - -wxGaugeBase::~wxGaugeBase() -{ - // this destructor is required for Darwin -} - -// ---------------------------------------------------------------------------- -// wxGauge creation -// ---------------------------------------------------------------------------- - -bool wxGaugeBase::Create(wxWindow *parent, - wxWindowID id, - int range, - const wxPoint& pos, - const wxSize& size, - long style, - const wxValidator& validator, - const wxString& name) -{ - if ( !wxControl::Create(parent, id, pos, size, style, validator, name) ) - return false; - - SetName(name); - -#if wxUSE_VALIDATORS - SetValidator(validator); -#endif // wxUSE_VALIDATORS - - SetRange(range); - SetValue(0); -#if wxGAUGE_EMULATE_INDETERMINATE_MODE - m_nDirection = wxRIGHT; -#endif - - return true; -} - -// ---------------------------------------------------------------------------- -// wxGauge determinate mode range/position -// ---------------------------------------------------------------------------- - -void wxGaugeBase::SetRange(int range) -{ - m_rangeMax = range; -} - -int wxGaugeBase::GetRange() const -{ - return m_rangeMax; -} - -void wxGaugeBase::SetValue(int pos) -{ - m_gaugePos = pos; -} - -int wxGaugeBase::GetValue() const -{ - return m_gaugePos; -} - -// ---------------------------------------------------------------------------- -// wxGauge indeterminate mode -// ---------------------------------------------------------------------------- - -void wxGaugeBase::Pulse() -{ -#if wxGAUGE_EMULATE_INDETERMINATE_MODE - // simulate indeterminate mode - int curr = GetValue(), max = GetRange(); - - if (m_nDirection == wxRIGHT) - { - if (curr < max) - SetValue(curr + 1); - else - { - SetValue(max - 1); - m_nDirection = wxLEFT; - } - } - else - { - if (curr > 0) - SetValue(curr - 1); - else - { - SetValue(1); - m_nDirection = wxRIGHT; - } - } -#endif -} - -// ---------------------------------------------------------------------------- -// wxGauge appearance params -// ---------------------------------------------------------------------------- - -void wxGaugeBase::SetShadowWidth(int WXUNUSED(w)) -{ -} - -int wxGaugeBase::GetShadowWidth() const -{ - return 0; -} - - -void wxGaugeBase::SetBezelFace(int WXUNUSED(w)) -{ -} - -int wxGaugeBase::GetBezelFace() const -{ - return 0; -} - -#endif // wxUSE_GAUGE +/////////////////////////////////////////////////////////////////////////////// +// Name: src/common/gaugecmn.cpp +// Purpose: wxGaugeBase: common to all ports methods of wxGauge +// Author: Vadim Zeitlin +// Modified by: +// Created: 20.02.01 +// RCS-ID: $Id: gaugecmn.cpp 41089 2006-09-09 13:36:54Z RR $ +// Copyright: (c) 2001 Vadim Zeitlin +// License: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#ifndef WX_PRECOMP +#endif //WX_PRECOMP + +#if wxUSE_GAUGE + +#include "wx/gauge.h" + +const wxChar wxGaugeNameStr[] = wxT("gauge"); + +// ============================================================================ +// implementation +// ============================================================================ + +wxGaugeBase::~wxGaugeBase() +{ + // this destructor is required for Darwin +} + +// ---------------------------------------------------------------------------- +// wxGauge creation +// ---------------------------------------------------------------------------- + +bool wxGaugeBase::Create(wxWindow *parent, + wxWindowID id, + int range, + const wxPoint& pos, + const wxSize& size, + long style, + const wxValidator& validator, + const wxString& name) +{ + if ( !wxControl::Create(parent, id, pos, size, style, validator, name) ) + return false; + + SetName(name); + +#if wxUSE_VALIDATORS + SetValidator(validator); +#endif // wxUSE_VALIDATORS + + SetRange(range); + SetValue(0); +#if wxGAUGE_EMULATE_INDETERMINATE_MODE + m_nDirection = wxRIGHT; +#endif + + return true; +} + +// ---------------------------------------------------------------------------- +// wxGauge determinate mode range/position +// ---------------------------------------------------------------------------- + +void wxGaugeBase::SetRange(int range) +{ + m_rangeMax = range; +} + +int wxGaugeBase::GetRange() const +{ + return m_rangeMax; +} + +void wxGaugeBase::SetValue(int pos) +{ + m_gaugePos = pos; +} + +int wxGaugeBase::GetValue() const +{ + return m_gaugePos; +} + +// ---------------------------------------------------------------------------- +// wxGauge indeterminate mode +// ---------------------------------------------------------------------------- + +void wxGaugeBase::Pulse() +{ +#if wxGAUGE_EMULATE_INDETERMINATE_MODE + // simulate indeterminate mode + int curr = GetValue(), max = GetRange(); + + if (m_nDirection == wxRIGHT) + { + if (curr < max) + SetValue(curr + 1); + else + { + SetValue(max - 1); + m_nDirection = wxLEFT; + } + } + else + { + if (curr > 0) + SetValue(curr - 1); + else + { + SetValue(1); + m_nDirection = wxRIGHT; + } + } +#endif +} + +// ---------------------------------------------------------------------------- +// wxGauge appearance params +// ---------------------------------------------------------------------------- + +void wxGaugeBase::SetShadowWidth(int WXUNUSED(w)) +{ +} + +int wxGaugeBase::GetShadowWidth() const +{ + return 0; +} + + +void wxGaugeBase::SetBezelFace(int WXUNUSED(w)) +{ +} + +int wxGaugeBase::GetBezelFace() const +{ + return 0; +} + +#endif // wxUSE_GAUGE diff --git a/Externals/wxWidgets/src/common/gbsizer.cpp b/Externals/wxWidgets/src/common/gbsizer.cpp index bfed38ea46..68402aad1c 100644 --- a/Externals/wxWidgets/src/common/gbsizer.cpp +++ b/Externals/wxWidgets/src/common/gbsizer.cpp @@ -1,784 +1,784 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: gbsizer.cpp -// Purpose: wxGridBagSizer: A sizer that can lay out items in a grid, -// with items at specified cells, and with the option of row -// and/or column spanning -// -// Author: Robin Dunn -// Created: 03-Nov-2003 -// RCS-ID: $Id: gbsizer.cpp 53000 2008-04-03 23:28:16Z RD $ -// Copyright: (c) Robin Dunn -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#include "wx/gbsizer.h" - -//--------------------------------------------------------------------------- - -IMPLEMENT_DYNAMIC_CLASS(wxGBSizerItem, wxSizerItem) -IMPLEMENT_CLASS(wxGridBagSizer, wxFlexGridSizer) - -const wxGBSpan wxDefaultSpan; - -//--------------------------------------------------------------------------- -// wxGBSizerItem -//--------------------------------------------------------------------------- - -wxGBSizerItem::wxGBSizerItem( int width, - int height, - const wxGBPosition& pos, - const wxGBSpan& span, - int flag, - int border, - wxObject* userData) - : wxSizerItem(width, height, 0, flag, border, userData), - m_pos(pos), - m_span(span), - m_gbsizer(NULL) -{ -} - - -wxGBSizerItem::wxGBSizerItem( wxWindow *window, - const wxGBPosition& pos, - const wxGBSpan& span, - int flag, - int border, - wxObject* userData ) - : wxSizerItem(window, 0, flag, border, userData), - m_pos(pos), - m_span(span), - m_gbsizer(NULL) -{ -} - - -wxGBSizerItem::wxGBSizerItem( wxSizer *sizer, - const wxGBPosition& pos, - const wxGBSpan& span, - int flag, - int border, - wxObject* userData ) - : wxSizerItem(sizer, 0, flag, border, userData), - m_pos(pos), - m_span(span), - m_gbsizer(NULL) -{ -} - -wxGBSizerItem::wxGBSizerItem() - : wxSizerItem(), - m_pos(-1,-1), - m_span(-1,-1), - m_gbsizer(NULL) -{ -} - -//--------------------------------------------------------------------------- - - -void wxGBSizerItem::GetPos(int& row, int& col) const -{ - row = m_pos.GetRow(); - col = m_pos.GetCol(); -} - -void wxGBSizerItem::GetSpan(int& rowspan, int& colspan) const -{ - rowspan = m_span.GetRowspan(); - colspan = m_span.GetColspan(); -} - - -bool wxGBSizerItem::SetPos( const wxGBPosition& pos ) -{ - if (m_gbsizer) - { - wxCHECK_MSG( !m_gbsizer->CheckForIntersection(pos, m_span, this), false, - wxT("An item is already at that position") ); - } - m_pos = pos; - return true; -} - -bool wxGBSizerItem::SetSpan( const wxGBSpan& span ) -{ - if (m_gbsizer) - { - wxCHECK_MSG( !m_gbsizer->CheckForIntersection(m_pos, span, this), false, - wxT("An item is already at that position") ); - } - m_span = span; - return true; -} - - -inline bool InRange(int val, int min, int max) -{ - return (val >= min && val <= max); -} - -bool wxGBSizerItem::Intersects(const wxGBSizerItem& other) -{ - return Intersects(other.GetPos(), other.GetSpan()); -} - -bool wxGBSizerItem::Intersects(const wxGBPosition& pos, const wxGBSpan& span) -{ - - int row, col, endrow, endcol; - int otherrow, othercol, otherendrow, otherendcol; - - GetPos(row, col); - GetEndPos(endrow, endcol); - - otherrow = pos.GetRow(); - othercol = pos.GetCol(); - otherendrow = otherrow + span.GetRowspan() - 1; - otherendcol = othercol + span.GetColspan() - 1; - - // is the other item's start or end in the range of this one? - if (( InRange(otherrow, row, endrow) && InRange(othercol, col, endcol) ) || - ( InRange(otherendrow, row, endrow) && InRange(otherendcol, col, endcol) )) - return true; - - // is this item's start or end in the range of the other one? - if (( InRange(row, otherrow, otherendrow) && InRange(col, othercol, otherendcol) ) || - ( InRange(endrow, otherrow, otherendrow) && InRange(endcol, othercol, otherendcol) )) - return true; - - return false; -} - - -void wxGBSizerItem::GetEndPos(int& row, int& col) -{ - row = m_pos.GetRow() + m_span.GetRowspan() - 1; - col = m_pos.GetCol() + m_span.GetColspan() - 1; -} - - -//--------------------------------------------------------------------------- -// wxGridBagSizer -//--------------------------------------------------------------------------- - -wxGridBagSizer::wxGridBagSizer(int vgap, int hgap ) - : wxFlexGridSizer(1, vgap, hgap), - m_emptyCellSize(10,20) - -{ -} - - -wxSizerItem* wxGridBagSizer::Add( wxWindow *window, - const wxGBPosition& pos, const wxGBSpan& span, - int flag, int border, wxObject* userData ) -{ - wxGBSizerItem* item = new wxGBSizerItem(window, pos, span, flag, border, userData); - if ( Add(item) ) - return item; - else - { - delete item; - return (wxSizerItem*)NULL; - } -} - -wxSizerItem* wxGridBagSizer::Add( wxSizer *sizer, - const wxGBPosition& pos, const wxGBSpan& span, - int flag, int border, wxObject* userData ) -{ - wxGBSizerItem* item = new wxGBSizerItem(sizer, pos, span, flag, border, userData); - if ( Add(item) ) - return item; - else - { - delete item; - return (wxSizerItem*)NULL; - } -} - -wxSizerItem* wxGridBagSizer::Add( int width, int height, - const wxGBPosition& pos, const wxGBSpan& span, - int flag, int border, wxObject* userData ) -{ - wxGBSizerItem* item = new wxGBSizerItem(width, height, pos, span, flag, border, userData); - if ( Add(item) ) - return item; - else - { - delete item; - return (wxSizerItem*)NULL; - } -} - -wxSizerItem* wxGridBagSizer::Add( wxGBSizerItem *item ) -{ - wxCHECK_MSG( !CheckForIntersection(item), NULL, - wxT("An item is already at that position") ); - m_children.Append(item); - item->SetGBSizer(this); - if ( item->GetWindow() ) - item->GetWindow()->SetContainingSizer( this ); - - return item; -} - - - -//--------------------------------------------------------------------------- - -wxSize wxGridBagSizer::GetCellSize(int row, int col) const -{ - wxCHECK_MSG( (row < m_rows) && (col < m_cols), - wxDefaultSize, - wxT("Invalid cell.")); - return wxSize( m_colWidths[col], m_rowHeights[row] ); -} - - -wxGBPosition wxGridBagSizer::GetItemPosition(wxWindow *window) -{ - wxGBPosition badpos(-1,-1); - wxGBSizerItem* item = FindItem(window); - wxCHECK_MSG(item, badpos, wxT("Failed to find item.")); - return item->GetPos(); -} - - -wxGBPosition wxGridBagSizer::GetItemPosition(wxSizer *sizer) -{ - wxGBPosition badpos(-1,-1); - wxGBSizerItem* item = FindItem(sizer); - wxCHECK_MSG(item, badpos, wxT("Failed to find item.")); - return item->GetPos(); -} - - -wxGBPosition wxGridBagSizer::GetItemPosition(size_t index) -{ - wxGBPosition badpos(-1,-1); - wxSizerItemList::compatibility_iterator node = m_children.Item( index ); - wxCHECK_MSG( node, badpos, _T("Failed to find item.") ); - wxGBSizerItem* item = (wxGBSizerItem*)node->GetData(); - return item->GetPos(); -} - - - -bool wxGridBagSizer::SetItemPosition(wxWindow *window, const wxGBPosition& pos) -{ - wxGBSizerItem* item = FindItem(window); - wxCHECK_MSG(item, false, wxT("Failed to find item.")); - return item->SetPos(pos); -} - - -bool wxGridBagSizer::SetItemPosition(wxSizer *sizer, const wxGBPosition& pos) -{ - wxGBSizerItem* item = FindItem(sizer); - wxCHECK_MSG(item, false, wxT("Failed to find item.")); - return item->SetPos(pos); -} - - -bool wxGridBagSizer::SetItemPosition(size_t index, const wxGBPosition& pos) -{ - wxSizerItemList::compatibility_iterator node = m_children.Item( index ); - wxCHECK_MSG( node, false, _T("Failed to find item.") ); - wxGBSizerItem* item = (wxGBSizerItem*)node->GetData(); - return item->SetPos(pos); -} - - - -wxGBSpan wxGridBagSizer::GetItemSpan(wxWindow *window) -{ - wxGBSpan badspan(-1,-1); - wxGBSizerItem* item = FindItem(window); - wxCHECK_MSG( item, badspan, _T("Failed to find item.") ); - return item->GetSpan(); -} - - -wxGBSpan wxGridBagSizer::GetItemSpan(wxSizer *sizer) -{ - wxGBSpan badspan(-1,-1); - wxGBSizerItem* item = FindItem(sizer); - wxCHECK_MSG( item, badspan, _T("Failed to find item.") ); - return item->GetSpan(); -} - - -wxGBSpan wxGridBagSizer::GetItemSpan(size_t index) -{ - wxGBSpan badspan(-1,-1); - wxSizerItemList::compatibility_iterator node = m_children.Item( index ); - wxCHECK_MSG( node, badspan, _T("Failed to find item.") ); - wxGBSizerItem* item = (wxGBSizerItem*)node->GetData(); - return item->GetSpan(); -} - - - -bool wxGridBagSizer::SetItemSpan(wxWindow *window, const wxGBSpan& span) -{ - wxGBSizerItem* item = FindItem(window); - wxCHECK_MSG(item, false, wxT("Failed to find item.")); - return item->SetSpan(span); -} - - -bool wxGridBagSizer::SetItemSpan(wxSizer *sizer, const wxGBSpan& span) -{ - wxGBSizerItem* item = FindItem(sizer); - wxCHECK_MSG(item, false, wxT("Failed to find item.")); - return item->SetSpan(span); -} - - -bool wxGridBagSizer::SetItemSpan(size_t index, const wxGBSpan& span) -{ - wxSizerItemList::compatibility_iterator node = m_children.Item( index ); - wxCHECK_MSG( node, false, _T("Failed to find item.") ); - wxGBSizerItem* item = (wxGBSizerItem*)node->GetData(); - return item->SetSpan(span); -} - - - - -wxGBSizerItem* wxGridBagSizer::FindItem(wxWindow* window) -{ - wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); - while (node) - { - wxGBSizerItem* item = (wxGBSizerItem*)node->GetData(); - if ( item->GetWindow() == window ) - return item; - node = node->GetNext(); - } - return NULL; -} - - -wxGBSizerItem* wxGridBagSizer::FindItem(wxSizer* sizer) -{ - wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); - while (node) - { - wxGBSizerItem* item = (wxGBSizerItem*)node->GetData(); - if ( item->GetSizer() == sizer ) - return item; - node = node->GetNext(); - } - return NULL; -} - - - - -wxGBSizerItem* wxGridBagSizer::FindItemAtPosition(const wxGBPosition& pos) -{ - wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); - while (node) - { - wxGBSizerItem* item = (wxGBSizerItem*)node->GetData(); - if ( item->Intersects(pos, wxDefaultSpan) ) - return item; - node = node->GetNext(); - } - return NULL; -} - - - - -wxGBSizerItem* wxGridBagSizer::FindItemAtPoint(const wxPoint& pt) -{ - wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); - while (node) - { - wxGBSizerItem* item = (wxGBSizerItem*)node->GetData(); - wxRect rect(item->GetPosition(), item->GetSize()); - rect.Inflate(m_hgap, m_vgap); - if ( rect.Contains(pt) ) - return item; - node = node->GetNext(); - } - return NULL; -} - - - - -wxGBSizerItem* wxGridBagSizer::FindItemWithData(const wxObject* userData) -{ - wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); - while (node) - { - wxGBSizerItem* item = (wxGBSizerItem*)node->GetData(); - if ( item->GetUserData() == userData ) - return item; - node = node->GetNext(); - } - return NULL; -} - - - - -//--------------------------------------------------------------------------- - -// Figure out what all the min row heights and col widths are, and calculate -// min size from that. -wxSize wxGridBagSizer::CalcMin() -{ - int idx; - - if (m_children.GetCount() == 0) - return m_emptyCellSize; - - m_rowHeights.Empty(); - m_colWidths.Empty(); - - wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); - while (node) - { - wxGBSizerItem* item = (wxGBSizerItem*)node->GetData(); - if ( item->ShouldAccountFor() ) - { - int row, col, endrow, endcol; - - item->GetPos(row, col); - item->GetEndPos(endrow, endcol); - - // fill heights and widths upto this item if needed - while ( m_rowHeights.GetCount() <= (size_t)endrow ) - m_rowHeights.Add(m_emptyCellSize.GetHeight()); - while ( m_colWidths.GetCount() <= (size_t)endcol ) - m_colWidths.Add(m_emptyCellSize.GetWidth()); - - // See if this item increases the size of its row(s) or col(s) - wxSize size(item->CalcMin()); - for (idx=row; idx <= endrow; idx++) - m_rowHeights[idx] = wxMax(m_rowHeights[idx], size.GetHeight() / (endrow-row+1)); - for (idx=col; idx <= endcol; idx++) - m_colWidths[idx] = wxMax(m_colWidths[idx], size.GetWidth() / (endcol-col+1)); - } - node = node->GetNext(); - } - - AdjustForOverflow(); - AdjustForFlexDirection(); - - // Now traverse the heights and widths arrays calcing the totals, including gaps - int width = 0; - m_cols = m_colWidths.GetCount(); - for (idx=0; idx < m_cols; idx++) - width += m_colWidths[idx] + ( idx == m_cols-1 ? 0 : m_hgap ); - - int height = 0; - m_rows = m_rowHeights.GetCount(); - for (idx=0; idx < m_rows; idx++) - height += m_rowHeights[idx] + ( idx == m_rows-1 ? 0 : m_vgap ); - - m_calculatedMinSize = wxSize(width, height); - return m_calculatedMinSize; -} - - - -void wxGridBagSizer::RecalcSizes() -{ - if (m_children.GetCount() == 0) - return; - - wxPoint pt( GetPosition() ); - wxSize sz( GetSize() ); - - m_rows = m_rowHeights.GetCount(); - m_cols = m_colWidths.GetCount(); - int idx, width, height; - - AdjustForGrowables(sz, m_calculatedMinSize, m_rows, m_cols); - - // Find the start positions on the window of the rows and columns - wxArrayInt rowpos; - rowpos.Add(0, m_rows); - int y = pt.y; - for (idx=0; idx < m_rows; idx++) - { - height = m_rowHeights[idx] + m_vgap; - rowpos[idx] = y; - y += height; - } - - wxArrayInt colpos; - colpos.Add(0, m_cols); - int x = pt.x; - for (idx=0; idx < m_cols; idx++) - { - width = m_colWidths[idx] + m_hgap; - colpos[idx] = x; - x += width; - } - - - // Now iterate the children, setting each child's dimensions - wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); - while (node) - { - int row, col, endrow, endcol; - wxGBSizerItem* item = (wxGBSizerItem*)node->GetData(); - - if ( item->ShouldAccountFor() ) - { - item->GetPos(row, col); - item->GetEndPos(endrow, endcol); - - height = 0; - for(idx=row; idx <= endrow; idx++) - height += m_rowHeights[idx]; - height += (endrow - row) * m_vgap; // add a vgap for every row spanned - - width = 0; - for (idx=col; idx <= endcol; idx++) - width += m_colWidths[idx]; - width += (endcol - col) * m_hgap; // add a hgap for every col spanned - - SetItemBounds(item, colpos[col], rowpos[row], width, height); - } - - node = node->GetNext(); - } -} - - -// Sometimes CalcMin can result in some rows or cols having too much space in -// them because as it traverses the items it makes some assumptions when -// items span to other cells. But those assumptions can become invalid later -// on when other items are fitted into the same rows or columns that the -// spanning item occupies. This method tries to find those situations and -// fixes them. -void wxGridBagSizer::AdjustForOverflow() -{ - int row, col; - - for (row=0; row<(int)m_rowHeights.GetCount(); row++) - { - int rowExtra=INT_MAX; - int rowHeight = m_rowHeights[row]; - for (col=0; col<(int)m_colWidths.GetCount(); col++) - { - wxGBPosition pos(row,col); - wxGBSizerItem* item = FindItemAtPosition(pos); - if ( !item ) - continue; - - int endrow, endcol; - item->GetEndPos(endrow, endcol); - - // If the item starts in this position and doesn't span rows, then - // just look at the whole item height - if ( item->GetPos() == pos && endrow == row ) - { - int itemHeight = item->CalcMin().GetHeight(); - rowExtra = wxMin(rowExtra, rowHeight - itemHeight); - continue; - } - - // Otherwise, only look at spanning items if they end on this row - if ( endrow == row ) - { - // first deduct the portions of the item that are on prior rows - int itemHeight = item->CalcMin().GetHeight(); - for (int r=item->GetPos().GetRow(); rGetEndPos(endrow, endcol); - - if ( item->GetPos() == pos && endcol == col ) - { - int itemWidth = item->CalcMin().GetWidth(); - colExtra = wxMin(colExtra, colWidth - itemWidth); - continue; - } - - if ( endcol == col ) - { - int itemWidth = item->CalcMin().GetWidth(); - for (int c=item->GetPos().GetCol(); cGetPos(), item->GetSpan(), excludeItem); -} - -bool wxGridBagSizer::CheckForIntersection(const wxGBPosition& pos, const wxGBSpan& span, wxGBSizerItem* excludeItem) -{ - wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); - while (node) - { - wxGBSizerItem* item = (wxGBSizerItem*)node->GetData(); - node = node->GetNext(); - - if ( excludeItem && item == excludeItem ) - continue; - - if ( item->Intersects(pos, span) ) - return true; - - } - return false; -} - - -// Assumes a 10x10 grid, and returns the first empty cell found. This is -// really stupid but it is only used by the Add methods that match the base -// class virtuals, which should normally not be used anyway... -wxGBPosition wxGridBagSizer::FindEmptyCell() -{ - int row, col; - - for (row=0; row<10; row++) - for (col=0; col<10; col++) - { - wxGBPosition pos(row, col); - if ( !CheckForIntersection(pos, wxDefaultSpan) ) - return pos; - } - return wxGBPosition(-1, -1); -} - - -//--------------------------------------------------------------------------- - -// The Add base class virtuals should not be used with this class, but -// we'll try to make them automatically select a location for the item -// anyway. - -wxSizerItem* wxGridBagSizer::Add( wxWindow *window, int, int flag, int border, wxObject* userData ) -{ - return Add(window, FindEmptyCell(), wxDefaultSpan, flag, border, userData); -} - -wxSizerItem* wxGridBagSizer::Add( wxSizer *sizer, int, int flag, int border, wxObject* userData ) -{ - return Add(sizer, FindEmptyCell(), wxDefaultSpan, flag, border, userData); -} - -wxSizerItem* wxGridBagSizer::Add( int width, int height, int, int flag, int border, wxObject* userData ) -{ - return Add(width, height, FindEmptyCell(), wxDefaultSpan, flag, border, userData); -} - - - -// The Insert nad Prepend base class virtuals that are not appropriate for -// this class and should not be used. Their implementation in this class -// simply fails. - -wxSizerItem* wxGridBagSizer::Add( wxSizerItem * ) -{ - wxFAIL_MSG(wxT("Invalid Add form called.")); - return (wxSizerItem*)NULL; -} - -wxSizerItem* wxGridBagSizer::Prepend( wxWindow *, int, int, int, wxObject* ) -{ - wxFAIL_MSG(wxT("Prepend should not be used with wxGridBagSizer.")); - return (wxSizerItem*)NULL; -} - -wxSizerItem* wxGridBagSizer::Prepend( wxSizer *, int, int, int, wxObject* ) -{ - wxFAIL_MSG(wxT("Prepend should not be used with wxGridBagSizer.")); - return (wxSizerItem*)NULL; -} - -wxSizerItem* wxGridBagSizer::Prepend( int, int, int, int, int, wxObject* ) -{ - wxFAIL_MSG(wxT("Prepend should not be used with wxGridBagSizer.")); - return (wxSizerItem*)NULL; -} - -wxSizerItem* wxGridBagSizer::Prepend( wxSizerItem * ) -{ - wxFAIL_MSG(wxT("Prepend should not be used with wxGridBagSizer.")); - return (wxSizerItem*)NULL; -} - - -wxSizerItem* wxGridBagSizer::Insert( size_t, wxWindow *, int, int, int, wxObject* ) -{ - wxFAIL_MSG(wxT("Insert should not be used with wxGridBagSizer.")); - return (wxSizerItem*)NULL; -} - -wxSizerItem* wxGridBagSizer::Insert( size_t, wxSizer *, int, int, int, wxObject* ) -{ - wxFAIL_MSG(wxT("Insert should not be used with wxGridBagSizer.")); - return (wxSizerItem*)NULL; -} - -wxSizerItem* wxGridBagSizer::Insert( size_t, int, int, int, int, int, wxObject* ) -{ - wxFAIL_MSG(wxT("Insert should not be used with wxGridBagSizer.")); - return (wxSizerItem*)NULL; -} - -wxSizerItem* wxGridBagSizer::Insert( size_t, wxSizerItem * ) -{ - wxFAIL_MSG(wxT("Insert should not be used with wxGridBagSizer.")); - return (wxSizerItem*)NULL; -} - - -//--------------------------------------------------------------------------- -//--------------------------------------------------------------------------- +///////////////////////////////////////////////////////////////////////////// +// Name: gbsizer.cpp +// Purpose: wxGridBagSizer: A sizer that can lay out items in a grid, +// with items at specified cells, and with the option of row +// and/or column spanning +// +// Author: Robin Dunn +// Created: 03-Nov-2003 +// RCS-ID: $Id: gbsizer.cpp 53000 2008-04-03 23:28:16Z RD $ +// Copyright: (c) Robin Dunn +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#include "wx/gbsizer.h" + +//--------------------------------------------------------------------------- + +IMPLEMENT_DYNAMIC_CLASS(wxGBSizerItem, wxSizerItem) +IMPLEMENT_CLASS(wxGridBagSizer, wxFlexGridSizer) + +const wxGBSpan wxDefaultSpan; + +//--------------------------------------------------------------------------- +// wxGBSizerItem +//--------------------------------------------------------------------------- + +wxGBSizerItem::wxGBSizerItem( int width, + int height, + const wxGBPosition& pos, + const wxGBSpan& span, + int flag, + int border, + wxObject* userData) + : wxSizerItem(width, height, 0, flag, border, userData), + m_pos(pos), + m_span(span), + m_gbsizer(NULL) +{ +} + + +wxGBSizerItem::wxGBSizerItem( wxWindow *window, + const wxGBPosition& pos, + const wxGBSpan& span, + int flag, + int border, + wxObject* userData ) + : wxSizerItem(window, 0, flag, border, userData), + m_pos(pos), + m_span(span), + m_gbsizer(NULL) +{ +} + + +wxGBSizerItem::wxGBSizerItem( wxSizer *sizer, + const wxGBPosition& pos, + const wxGBSpan& span, + int flag, + int border, + wxObject* userData ) + : wxSizerItem(sizer, 0, flag, border, userData), + m_pos(pos), + m_span(span), + m_gbsizer(NULL) +{ +} + +wxGBSizerItem::wxGBSizerItem() + : wxSizerItem(), + m_pos(-1,-1), + m_span(-1,-1), + m_gbsizer(NULL) +{ +} + +//--------------------------------------------------------------------------- + + +void wxGBSizerItem::GetPos(int& row, int& col) const +{ + row = m_pos.GetRow(); + col = m_pos.GetCol(); +} + +void wxGBSizerItem::GetSpan(int& rowspan, int& colspan) const +{ + rowspan = m_span.GetRowspan(); + colspan = m_span.GetColspan(); +} + + +bool wxGBSizerItem::SetPos( const wxGBPosition& pos ) +{ + if (m_gbsizer) + { + wxCHECK_MSG( !m_gbsizer->CheckForIntersection(pos, m_span, this), false, + wxT("An item is already at that position") ); + } + m_pos = pos; + return true; +} + +bool wxGBSizerItem::SetSpan( const wxGBSpan& span ) +{ + if (m_gbsizer) + { + wxCHECK_MSG( !m_gbsizer->CheckForIntersection(m_pos, span, this), false, + wxT("An item is already at that position") ); + } + m_span = span; + return true; +} + + +inline bool InRange(int val, int min, int max) +{ + return (val >= min && val <= max); +} + +bool wxGBSizerItem::Intersects(const wxGBSizerItem& other) +{ + return Intersects(other.GetPos(), other.GetSpan()); +} + +bool wxGBSizerItem::Intersects(const wxGBPosition& pos, const wxGBSpan& span) +{ + + int row, col, endrow, endcol; + int otherrow, othercol, otherendrow, otherendcol; + + GetPos(row, col); + GetEndPos(endrow, endcol); + + otherrow = pos.GetRow(); + othercol = pos.GetCol(); + otherendrow = otherrow + span.GetRowspan() - 1; + otherendcol = othercol + span.GetColspan() - 1; + + // is the other item's start or end in the range of this one? + if (( InRange(otherrow, row, endrow) && InRange(othercol, col, endcol) ) || + ( InRange(otherendrow, row, endrow) && InRange(otherendcol, col, endcol) )) + return true; + + // is this item's start or end in the range of the other one? + if (( InRange(row, otherrow, otherendrow) && InRange(col, othercol, otherendcol) ) || + ( InRange(endrow, otherrow, otherendrow) && InRange(endcol, othercol, otherendcol) )) + return true; + + return false; +} + + +void wxGBSizerItem::GetEndPos(int& row, int& col) +{ + row = m_pos.GetRow() + m_span.GetRowspan() - 1; + col = m_pos.GetCol() + m_span.GetColspan() - 1; +} + + +//--------------------------------------------------------------------------- +// wxGridBagSizer +//--------------------------------------------------------------------------- + +wxGridBagSizer::wxGridBagSizer(int vgap, int hgap ) + : wxFlexGridSizer(1, vgap, hgap), + m_emptyCellSize(10,20) + +{ +} + + +wxSizerItem* wxGridBagSizer::Add( wxWindow *window, + const wxGBPosition& pos, const wxGBSpan& span, + int flag, int border, wxObject* userData ) +{ + wxGBSizerItem* item = new wxGBSizerItem(window, pos, span, flag, border, userData); + if ( Add(item) ) + return item; + else + { + delete item; + return (wxSizerItem*)NULL; + } +} + +wxSizerItem* wxGridBagSizer::Add( wxSizer *sizer, + const wxGBPosition& pos, const wxGBSpan& span, + int flag, int border, wxObject* userData ) +{ + wxGBSizerItem* item = new wxGBSizerItem(sizer, pos, span, flag, border, userData); + if ( Add(item) ) + return item; + else + { + delete item; + return (wxSizerItem*)NULL; + } +} + +wxSizerItem* wxGridBagSizer::Add( int width, int height, + const wxGBPosition& pos, const wxGBSpan& span, + int flag, int border, wxObject* userData ) +{ + wxGBSizerItem* item = new wxGBSizerItem(width, height, pos, span, flag, border, userData); + if ( Add(item) ) + return item; + else + { + delete item; + return (wxSizerItem*)NULL; + } +} + +wxSizerItem* wxGridBagSizer::Add( wxGBSizerItem *item ) +{ + wxCHECK_MSG( !CheckForIntersection(item), NULL, + wxT("An item is already at that position") ); + m_children.Append(item); + item->SetGBSizer(this); + if ( item->GetWindow() ) + item->GetWindow()->SetContainingSizer( this ); + + return item; +} + + + +//--------------------------------------------------------------------------- + +wxSize wxGridBagSizer::GetCellSize(int row, int col) const +{ + wxCHECK_MSG( (row < m_rows) && (col < m_cols), + wxDefaultSize, + wxT("Invalid cell.")); + return wxSize( m_colWidths[col], m_rowHeights[row] ); +} + + +wxGBPosition wxGridBagSizer::GetItemPosition(wxWindow *window) +{ + wxGBPosition badpos(-1,-1); + wxGBSizerItem* item = FindItem(window); + wxCHECK_MSG(item, badpos, wxT("Failed to find item.")); + return item->GetPos(); +} + + +wxGBPosition wxGridBagSizer::GetItemPosition(wxSizer *sizer) +{ + wxGBPosition badpos(-1,-1); + wxGBSizerItem* item = FindItem(sizer); + wxCHECK_MSG(item, badpos, wxT("Failed to find item.")); + return item->GetPos(); +} + + +wxGBPosition wxGridBagSizer::GetItemPosition(size_t index) +{ + wxGBPosition badpos(-1,-1); + wxSizerItemList::compatibility_iterator node = m_children.Item( index ); + wxCHECK_MSG( node, badpos, _T("Failed to find item.") ); + wxGBSizerItem* item = (wxGBSizerItem*)node->GetData(); + return item->GetPos(); +} + + + +bool wxGridBagSizer::SetItemPosition(wxWindow *window, const wxGBPosition& pos) +{ + wxGBSizerItem* item = FindItem(window); + wxCHECK_MSG(item, false, wxT("Failed to find item.")); + return item->SetPos(pos); +} + + +bool wxGridBagSizer::SetItemPosition(wxSizer *sizer, const wxGBPosition& pos) +{ + wxGBSizerItem* item = FindItem(sizer); + wxCHECK_MSG(item, false, wxT("Failed to find item.")); + return item->SetPos(pos); +} + + +bool wxGridBagSizer::SetItemPosition(size_t index, const wxGBPosition& pos) +{ + wxSizerItemList::compatibility_iterator node = m_children.Item( index ); + wxCHECK_MSG( node, false, _T("Failed to find item.") ); + wxGBSizerItem* item = (wxGBSizerItem*)node->GetData(); + return item->SetPos(pos); +} + + + +wxGBSpan wxGridBagSizer::GetItemSpan(wxWindow *window) +{ + wxGBSpan badspan(-1,-1); + wxGBSizerItem* item = FindItem(window); + wxCHECK_MSG( item, badspan, _T("Failed to find item.") ); + return item->GetSpan(); +} + + +wxGBSpan wxGridBagSizer::GetItemSpan(wxSizer *sizer) +{ + wxGBSpan badspan(-1,-1); + wxGBSizerItem* item = FindItem(sizer); + wxCHECK_MSG( item, badspan, _T("Failed to find item.") ); + return item->GetSpan(); +} + + +wxGBSpan wxGridBagSizer::GetItemSpan(size_t index) +{ + wxGBSpan badspan(-1,-1); + wxSizerItemList::compatibility_iterator node = m_children.Item( index ); + wxCHECK_MSG( node, badspan, _T("Failed to find item.") ); + wxGBSizerItem* item = (wxGBSizerItem*)node->GetData(); + return item->GetSpan(); +} + + + +bool wxGridBagSizer::SetItemSpan(wxWindow *window, const wxGBSpan& span) +{ + wxGBSizerItem* item = FindItem(window); + wxCHECK_MSG(item, false, wxT("Failed to find item.")); + return item->SetSpan(span); +} + + +bool wxGridBagSizer::SetItemSpan(wxSizer *sizer, const wxGBSpan& span) +{ + wxGBSizerItem* item = FindItem(sizer); + wxCHECK_MSG(item, false, wxT("Failed to find item.")); + return item->SetSpan(span); +} + + +bool wxGridBagSizer::SetItemSpan(size_t index, const wxGBSpan& span) +{ + wxSizerItemList::compatibility_iterator node = m_children.Item( index ); + wxCHECK_MSG( node, false, _T("Failed to find item.") ); + wxGBSizerItem* item = (wxGBSizerItem*)node->GetData(); + return item->SetSpan(span); +} + + + + +wxGBSizerItem* wxGridBagSizer::FindItem(wxWindow* window) +{ + wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); + while (node) + { + wxGBSizerItem* item = (wxGBSizerItem*)node->GetData(); + if ( item->GetWindow() == window ) + return item; + node = node->GetNext(); + } + return NULL; +} + + +wxGBSizerItem* wxGridBagSizer::FindItem(wxSizer* sizer) +{ + wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); + while (node) + { + wxGBSizerItem* item = (wxGBSizerItem*)node->GetData(); + if ( item->GetSizer() == sizer ) + return item; + node = node->GetNext(); + } + return NULL; +} + + + + +wxGBSizerItem* wxGridBagSizer::FindItemAtPosition(const wxGBPosition& pos) +{ + wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); + while (node) + { + wxGBSizerItem* item = (wxGBSizerItem*)node->GetData(); + if ( item->Intersects(pos, wxDefaultSpan) ) + return item; + node = node->GetNext(); + } + return NULL; +} + + + + +wxGBSizerItem* wxGridBagSizer::FindItemAtPoint(const wxPoint& pt) +{ + wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); + while (node) + { + wxGBSizerItem* item = (wxGBSizerItem*)node->GetData(); + wxRect rect(item->GetPosition(), item->GetSize()); + rect.Inflate(m_hgap, m_vgap); + if ( rect.Contains(pt) ) + return item; + node = node->GetNext(); + } + return NULL; +} + + + + +wxGBSizerItem* wxGridBagSizer::FindItemWithData(const wxObject* userData) +{ + wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); + while (node) + { + wxGBSizerItem* item = (wxGBSizerItem*)node->GetData(); + if ( item->GetUserData() == userData ) + return item; + node = node->GetNext(); + } + return NULL; +} + + + + +//--------------------------------------------------------------------------- + +// Figure out what all the min row heights and col widths are, and calculate +// min size from that. +wxSize wxGridBagSizer::CalcMin() +{ + int idx; + + if (m_children.GetCount() == 0) + return m_emptyCellSize; + + m_rowHeights.Empty(); + m_colWidths.Empty(); + + wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); + while (node) + { + wxGBSizerItem* item = (wxGBSizerItem*)node->GetData(); + if ( item->ShouldAccountFor() ) + { + int row, col, endrow, endcol; + + item->GetPos(row, col); + item->GetEndPos(endrow, endcol); + + // fill heights and widths upto this item if needed + while ( m_rowHeights.GetCount() <= (size_t)endrow ) + m_rowHeights.Add(m_emptyCellSize.GetHeight()); + while ( m_colWidths.GetCount() <= (size_t)endcol ) + m_colWidths.Add(m_emptyCellSize.GetWidth()); + + // See if this item increases the size of its row(s) or col(s) + wxSize size(item->CalcMin()); + for (idx=row; idx <= endrow; idx++) + m_rowHeights[idx] = wxMax(m_rowHeights[idx], size.GetHeight() / (endrow-row+1)); + for (idx=col; idx <= endcol; idx++) + m_colWidths[idx] = wxMax(m_colWidths[idx], size.GetWidth() / (endcol-col+1)); + } + node = node->GetNext(); + } + + AdjustForOverflow(); + AdjustForFlexDirection(); + + // Now traverse the heights and widths arrays calcing the totals, including gaps + int width = 0; + m_cols = m_colWidths.GetCount(); + for (idx=0; idx < m_cols; idx++) + width += m_colWidths[idx] + ( idx == m_cols-1 ? 0 : m_hgap ); + + int height = 0; + m_rows = m_rowHeights.GetCount(); + for (idx=0; idx < m_rows; idx++) + height += m_rowHeights[idx] + ( idx == m_rows-1 ? 0 : m_vgap ); + + m_calculatedMinSize = wxSize(width, height); + return m_calculatedMinSize; +} + + + +void wxGridBagSizer::RecalcSizes() +{ + if (m_children.GetCount() == 0) + return; + + wxPoint pt( GetPosition() ); + wxSize sz( GetSize() ); + + m_rows = m_rowHeights.GetCount(); + m_cols = m_colWidths.GetCount(); + int idx, width, height; + + AdjustForGrowables(sz, m_calculatedMinSize, m_rows, m_cols); + + // Find the start positions on the window of the rows and columns + wxArrayInt rowpos; + rowpos.Add(0, m_rows); + int y = pt.y; + for (idx=0; idx < m_rows; idx++) + { + height = m_rowHeights[idx] + m_vgap; + rowpos[idx] = y; + y += height; + } + + wxArrayInt colpos; + colpos.Add(0, m_cols); + int x = pt.x; + for (idx=0; idx < m_cols; idx++) + { + width = m_colWidths[idx] + m_hgap; + colpos[idx] = x; + x += width; + } + + + // Now iterate the children, setting each child's dimensions + wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); + while (node) + { + int row, col, endrow, endcol; + wxGBSizerItem* item = (wxGBSizerItem*)node->GetData(); + + if ( item->ShouldAccountFor() ) + { + item->GetPos(row, col); + item->GetEndPos(endrow, endcol); + + height = 0; + for(idx=row; idx <= endrow; idx++) + height += m_rowHeights[idx]; + height += (endrow - row) * m_vgap; // add a vgap for every row spanned + + width = 0; + for (idx=col; idx <= endcol; idx++) + width += m_colWidths[idx]; + width += (endcol - col) * m_hgap; // add a hgap for every col spanned + + SetItemBounds(item, colpos[col], rowpos[row], width, height); + } + + node = node->GetNext(); + } +} + + +// Sometimes CalcMin can result in some rows or cols having too much space in +// them because as it traverses the items it makes some assumptions when +// items span to other cells. But those assumptions can become invalid later +// on when other items are fitted into the same rows or columns that the +// spanning item occupies. This method tries to find those situations and +// fixes them. +void wxGridBagSizer::AdjustForOverflow() +{ + int row, col; + + for (row=0; row<(int)m_rowHeights.GetCount(); row++) + { + int rowExtra=INT_MAX; + int rowHeight = m_rowHeights[row]; + for (col=0; col<(int)m_colWidths.GetCount(); col++) + { + wxGBPosition pos(row,col); + wxGBSizerItem* item = FindItemAtPosition(pos); + if ( !item ) + continue; + + int endrow, endcol; + item->GetEndPos(endrow, endcol); + + // If the item starts in this position and doesn't span rows, then + // just look at the whole item height + if ( item->GetPos() == pos && endrow == row ) + { + int itemHeight = item->CalcMin().GetHeight(); + rowExtra = wxMin(rowExtra, rowHeight - itemHeight); + continue; + } + + // Otherwise, only look at spanning items if they end on this row + if ( endrow == row ) + { + // first deduct the portions of the item that are on prior rows + int itemHeight = item->CalcMin().GetHeight(); + for (int r=item->GetPos().GetRow(); rGetEndPos(endrow, endcol); + + if ( item->GetPos() == pos && endcol == col ) + { + int itemWidth = item->CalcMin().GetWidth(); + colExtra = wxMin(colExtra, colWidth - itemWidth); + continue; + } + + if ( endcol == col ) + { + int itemWidth = item->CalcMin().GetWidth(); + for (int c=item->GetPos().GetCol(); cGetPos(), item->GetSpan(), excludeItem); +} + +bool wxGridBagSizer::CheckForIntersection(const wxGBPosition& pos, const wxGBSpan& span, wxGBSizerItem* excludeItem) +{ + wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); + while (node) + { + wxGBSizerItem* item = (wxGBSizerItem*)node->GetData(); + node = node->GetNext(); + + if ( excludeItem && item == excludeItem ) + continue; + + if ( item->Intersects(pos, span) ) + return true; + + } + return false; +} + + +// Assumes a 10x10 grid, and returns the first empty cell found. This is +// really stupid but it is only used by the Add methods that match the base +// class virtuals, which should normally not be used anyway... +wxGBPosition wxGridBagSizer::FindEmptyCell() +{ + int row, col; + + for (row=0; row<10; row++) + for (col=0; col<10; col++) + { + wxGBPosition pos(row, col); + if ( !CheckForIntersection(pos, wxDefaultSpan) ) + return pos; + } + return wxGBPosition(-1, -1); +} + + +//--------------------------------------------------------------------------- + +// The Add base class virtuals should not be used with this class, but +// we'll try to make them automatically select a location for the item +// anyway. + +wxSizerItem* wxGridBagSizer::Add( wxWindow *window, int, int flag, int border, wxObject* userData ) +{ + return Add(window, FindEmptyCell(), wxDefaultSpan, flag, border, userData); +} + +wxSizerItem* wxGridBagSizer::Add( wxSizer *sizer, int, int flag, int border, wxObject* userData ) +{ + return Add(sizer, FindEmptyCell(), wxDefaultSpan, flag, border, userData); +} + +wxSizerItem* wxGridBagSizer::Add( int width, int height, int, int flag, int border, wxObject* userData ) +{ + return Add(width, height, FindEmptyCell(), wxDefaultSpan, flag, border, userData); +} + + + +// The Insert nad Prepend base class virtuals that are not appropriate for +// this class and should not be used. Their implementation in this class +// simply fails. + +wxSizerItem* wxGridBagSizer::Add( wxSizerItem * ) +{ + wxFAIL_MSG(wxT("Invalid Add form called.")); + return (wxSizerItem*)NULL; +} + +wxSizerItem* wxGridBagSizer::Prepend( wxWindow *, int, int, int, wxObject* ) +{ + wxFAIL_MSG(wxT("Prepend should not be used with wxGridBagSizer.")); + return (wxSizerItem*)NULL; +} + +wxSizerItem* wxGridBagSizer::Prepend( wxSizer *, int, int, int, wxObject* ) +{ + wxFAIL_MSG(wxT("Prepend should not be used with wxGridBagSizer.")); + return (wxSizerItem*)NULL; +} + +wxSizerItem* wxGridBagSizer::Prepend( int, int, int, int, int, wxObject* ) +{ + wxFAIL_MSG(wxT("Prepend should not be used with wxGridBagSizer.")); + return (wxSizerItem*)NULL; +} + +wxSizerItem* wxGridBagSizer::Prepend( wxSizerItem * ) +{ + wxFAIL_MSG(wxT("Prepend should not be used with wxGridBagSizer.")); + return (wxSizerItem*)NULL; +} + + +wxSizerItem* wxGridBagSizer::Insert( size_t, wxWindow *, int, int, int, wxObject* ) +{ + wxFAIL_MSG(wxT("Insert should not be used with wxGridBagSizer.")); + return (wxSizerItem*)NULL; +} + +wxSizerItem* wxGridBagSizer::Insert( size_t, wxSizer *, int, int, int, wxObject* ) +{ + wxFAIL_MSG(wxT("Insert should not be used with wxGridBagSizer.")); + return (wxSizerItem*)NULL; +} + +wxSizerItem* wxGridBagSizer::Insert( size_t, int, int, int, int, int, wxObject* ) +{ + wxFAIL_MSG(wxT("Insert should not be used with wxGridBagSizer.")); + return (wxSizerItem*)NULL; +} + +wxSizerItem* wxGridBagSizer::Insert( size_t, wxSizerItem * ) +{ + wxFAIL_MSG(wxT("Insert should not be used with wxGridBagSizer.")); + return (wxSizerItem*)NULL; +} + + +//--------------------------------------------------------------------------- +//--------------------------------------------------------------------------- diff --git a/Externals/wxWidgets/src/common/gdicmn.cpp b/Externals/wxWidgets/src/common/gdicmn.cpp index 86411416fd..2322388537 100644 --- a/Externals/wxWidgets/src/common/gdicmn.cpp +++ b/Externals/wxWidgets/src/common/gdicmn.cpp @@ -1,871 +1,871 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/gdicmn.cpp -// Purpose: Common GDI classes -// Author: Julian Smart -// Modified by: -// Created: 01/02/97 -// RCS-ID: $Id: gdicmn.cpp 50022 2007-11-17 14:24:18Z VZ $ -// Copyright: (c) Julian Smart -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#include "wx/gdicmn.h" -#include "wx/gdiobj.h" - -#ifndef WX_PRECOMP - #include "wx/log.h" - #include "wx/pen.h" - #include "wx/brush.h" - #include "wx/palette.h" - #include "wx/icon.h" - #include "wx/cursor.h" - #include "wx/settings.h" - #include "wx/bitmap.h" - #include "wx/colour.h" - #include "wx/font.h" -#endif - - -IMPLEMENT_DYNAMIC_CLASS(wxGDIObject, wxObject) - - -WXDLLIMPEXP_DATA_CORE(wxBrushList*) wxTheBrushList; -WXDLLIMPEXP_DATA_CORE(wxFontList*) wxTheFontList; -WXDLLIMPEXP_DATA_CORE(wxPenList*) wxThePenList; - -WXDLLIMPEXP_DATA_CORE(wxColourDatabase*) wxTheColourDatabase; - -WXDLLIMPEXP_DATA_CORE(wxBitmap) wxNullBitmap; -WXDLLIMPEXP_DATA_CORE(wxBrush) wxNullBrush; -WXDLLIMPEXP_DATA_CORE(wxColour) wxNullColour; -WXDLLIMPEXP_DATA_CORE(wxCursor) wxNullCursor; -WXDLLIMPEXP_DATA_CORE(wxFont) wxNullFont; -WXDLLIMPEXP_DATA_CORE(wxIcon) wxNullIcon; -WXDLLIMPEXP_DATA_CORE(wxPen) wxNullPen; -#if wxUSE_PALETTE -WXDLLIMPEXP_DATA_CORE(wxPalette) wxNullPalette; -#endif - -const wxSize wxDefaultSize(wxDefaultCoord, wxDefaultCoord); -const wxPoint wxDefaultPosition(wxDefaultCoord, wxDefaultCoord); - -#if wxUSE_EXTENDED_RTTI - -// wxPoint - -template<> void wxStringReadValue(const wxString &s , wxPoint &data ) -{ - wxSscanf(s, wxT("%d,%d"), &data.x , &data.y ) ; -} - -template<> void wxStringWriteValue(wxString &s , const wxPoint &data ) -{ - s = wxString::Format(wxT("%d,%d"), data.x , data.y ) ; -} - -wxCUSTOM_TYPE_INFO(wxPoint, wxToStringConverter , wxFromStringConverter) - -template<> void wxStringReadValue(const wxString &s , wxSize &data ) -{ - wxSscanf(s, wxT("%d,%d"), &data.x , &data.y ) ; -} - -template<> void wxStringWriteValue(wxString &s , const wxSize &data ) -{ - s = wxString::Format(wxT("%d,%d"), data.x , data.y ) ; -} - -wxCUSTOM_TYPE_INFO(wxSize, wxToStringConverter , wxFromStringConverter) - -#endif - -wxRect::wxRect(const wxPoint& point1, const wxPoint& point2) -{ - x = point1.x; - y = point1.y; - width = point2.x - point1.x; - height = point2.y - point1.y; - - if (width < 0) - { - width = -width; - x = point2.x; - } - width++; - - if (height < 0) - { - height = -height; - y = point2.y; - } - height++; -} - -bool wxRect::operator==(const wxRect& rect) const -{ - return ((x == rect.x) && - (y == rect.y) && - (width == rect.width) && - (height == rect.height)); -} - -wxRect wxRect::operator+(const wxRect& rect) const -{ - int x1 = wxMin(this->x, rect.x); - int y1 = wxMin(this->y, rect.y); - int y2 = wxMax(y+height, rect.height+rect.y); - int x2 = wxMax(x+width, rect.width+rect.x); - return wxRect(x1, y1, x2-x1, y2-y1); -} - -wxRect& wxRect::Union(const wxRect& rect) -{ - // ignore empty rectangles: union with an empty rectangle shouldn't extend - // this one to (0, 0) - if ( !width || !height ) - { - *this = rect; - } - else if ( rect.width && rect.height ) - { - int x1 = wxMin(x, rect.x); - int y1 = wxMin(y, rect.y); - int y2 = wxMax(y + height, rect.height + rect.y); - int x2 = wxMax(x + width, rect.width + rect.x); - - x = x1; - y = y1; - width = x2 - x1; - height = y2 - y1; - } - //else: we're not empty and rect is empty - - return *this; -} - -wxRect& wxRect::Inflate(wxCoord dx, wxCoord dy) -{ - if (-2*dx>width) - { - // Don't allow deflate to eat more width than we have, - // a well-defined rectangle cannot have negative width. - x+=width/2; - width=0; - } - else - { - // The inflate is valid. - x-=dx; - width+=2*dx; - } - - if (-2*dy>height) - { - // Don't allow deflate to eat more height than we have, - // a well-defined rectangle cannot have negative height. - y+=height/2; - height=0; - } - else - { - // The inflate is valid. - y-=dy; - height+=2*dy; - } - - return *this; -} - -bool wxRect::Contains(int cx, int cy) const -{ - return ( (cx >= x) && (cy >= y) - && ((cy - y) < height) - && ((cx - x) < width) - ); -} - -bool wxRect::Contains(const wxRect& rect) const -{ - return Contains(rect.GetTopLeft()) && Contains(rect.GetBottomRight()); -} - -wxRect& wxRect::Intersect(const wxRect& rect) -{ - int x2 = GetRight(), - y2 = GetBottom(); - - if ( x < rect.x ) - x = rect.x; - if ( y < rect.y ) - y = rect.y; - if ( x2 > rect.GetRight() ) - x2 = rect.GetRight(); - if ( y2 > rect.GetBottom() ) - y2 = rect.GetBottom(); - - width = x2 - x + 1; - height = y2 - y + 1; - - if ( width <= 0 || height <= 0 ) - { - width = - height = 0; - } - - return *this; -} - -bool wxRect::Intersects(const wxRect& rect) const -{ - wxRect r = Intersect(rect); - - // if there is no intersection, both width and height are 0 - return r.width != 0; -} - -// ============================================================================ -// wxColourDatabase -// ============================================================================ - -// ---------------------------------------------------------------------------- -// wxColourDatabase ctor/dtor -// ---------------------------------------------------------------------------- - -wxColourDatabase::wxColourDatabase () -{ - // will be created on demand in Initialize() - m_map = NULL; -} - -wxColourDatabase::~wxColourDatabase () -{ - if ( m_map ) - { - WX_CLEAR_HASH_MAP(wxStringToColourHashMap, *m_map); - - delete m_map; - } - -#ifdef __WXPM__ - delete [] m_palTable; -#endif -} - -// Colour database stuff -void wxColourDatabase::Initialize() -{ - if ( m_map ) - { - // already initialized - return; - } - - m_map = new wxStringToColourHashMap; - - static const struct wxColourDesc - { - const wxChar *name; - unsigned char r,g,b; - } - wxColourTable[] = - { - {wxT("AQUAMARINE"),112, 219, 147}, - {wxT("BLACK"),0, 0, 0}, - {wxT("BLUE"), 0, 0, 255}, - {wxT("BLUE VIOLET"), 159, 95, 159}, - {wxT("BROWN"), 165, 42, 42}, - {wxT("CADET BLUE"), 95, 159, 159}, - {wxT("CORAL"), 255, 127, 0}, - {wxT("CORNFLOWER BLUE"), 66, 66, 111}, - {wxT("CYAN"), 0, 255, 255}, - {wxT("DARK GREY"), 47, 47, 47}, // ? - - {wxT("DARK GREEN"), 47, 79, 47}, - {wxT("DARK OLIVE GREEN"), 79, 79, 47}, - {wxT("DARK ORCHID"), 153, 50, 204}, - {wxT("DARK SLATE BLUE"), 107, 35, 142}, - {wxT("DARK SLATE GREY"), 47, 79, 79}, - {wxT("DARK TURQUOISE"), 112, 147, 219}, - {wxT("DIM GREY"), 84, 84, 84}, - {wxT("FIREBRICK"), 142, 35, 35}, - {wxT("FOREST GREEN"), 35, 142, 35}, - {wxT("GOLD"), 204, 127, 50}, - {wxT("GOLDENROD"), 219, 219, 112}, - {wxT("GREY"), 128, 128, 128}, - {wxT("GREEN"), 0, 255, 0}, - {wxT("GREEN YELLOW"), 147, 219, 112}, - {wxT("INDIAN RED"), 79, 47, 47}, - {wxT("KHAKI"), 159, 159, 95}, - {wxT("LIGHT BLUE"), 191, 216, 216}, - {wxT("LIGHT GREY"), 192, 192, 192}, - {wxT("LIGHT STEEL BLUE"), 143, 143, 188}, - {wxT("LIME GREEN"), 50, 204, 50}, - {wxT("LIGHT MAGENTA"), 255, 0, 255}, - {wxT("MAGENTA"), 255, 0, 255}, - {wxT("MAROON"), 142, 35, 107}, - {wxT("MEDIUM AQUAMARINE"), 50, 204, 153}, - {wxT("MEDIUM GREY"), 100, 100, 100}, - {wxT("MEDIUM BLUE"), 50, 50, 204}, - {wxT("MEDIUM FOREST GREEN"), 107, 142, 35}, - {wxT("MEDIUM GOLDENROD"), 234, 234, 173}, - {wxT("MEDIUM ORCHID"), 147, 112, 219}, - {wxT("MEDIUM SEA GREEN"), 66, 111, 66}, - {wxT("MEDIUM SLATE BLUE"), 127, 0, 255}, - {wxT("MEDIUM SPRING GREEN"), 127, 255, 0}, - {wxT("MEDIUM TURQUOISE"), 112, 219, 219}, - {wxT("MEDIUM VIOLET RED"), 219, 112, 147}, - {wxT("MIDNIGHT BLUE"), 47, 47, 79}, - {wxT("NAVY"), 35, 35, 142}, - {wxT("ORANGE"), 204, 50, 50}, - {wxT("ORANGE RED"), 255, 0, 127}, - {wxT("ORCHID"), 219, 112, 219}, - {wxT("PALE GREEN"), 143, 188, 143}, - {wxT("PINK"), 255, 192, 203}, - {wxT("PLUM"), 234, 173, 234}, - {wxT("PURPLE"), 176, 0, 255}, - {wxT("RED"), 255, 0, 0}, - {wxT("SALMON"), 111, 66, 66}, - {wxT("SEA GREEN"), 35, 142, 107}, - {wxT("SIENNA"), 142, 107, 35}, - {wxT("SKY BLUE"), 50, 153, 204}, - {wxT("SLATE BLUE"), 0, 127, 255}, - {wxT("SPRING GREEN"), 0, 255, 127}, - {wxT("STEEL BLUE"), 35, 107, 142}, - {wxT("TAN"), 219, 147, 112}, - {wxT("THISTLE"), 216, 191, 216}, - {wxT("TURQUOISE"), 173, 234, 234}, - {wxT("VIOLET"), 79, 47, 79}, - {wxT("VIOLET RED"), 204, 50, 153}, - {wxT("WHEAT"), 216, 216, 191}, - {wxT("WHITE"), 255, 255, 255}, - {wxT("YELLOW"), 255, 255, 0}, - {wxT("YELLOW GREEN"), 153, 204, 50} - }; - - size_t n; - - for ( n = 0; n < WXSIZEOF(wxColourTable); n++ ) - { - const wxColourDesc& cc = wxColourTable[n]; - (*m_map)[cc.name] = new wxColour(cc.r, cc.g, cc.b); - } - -#ifdef __WXPM__ - m_palTable = new long[n]; - for ( n = 0; n < WXSIZEOF(wxColourTable); n++ ) - { - const wxColourDesc& cc = wxColourTable[n]; - m_palTable[n] = OS2RGB(cc.r,cc.g,cc.b); - } - m_nSize = n; -#endif -} - -// ---------------------------------------------------------------------------- -// wxColourDatabase operations -// ---------------------------------------------------------------------------- - -void wxColourDatabase::AddColour(const wxString& name, const wxColour& colour) -{ - Initialize(); - - // canonicalize the colour names before using them as keys: they should be - // in upper case - wxString colName = name; - colName.MakeUpper(); - - // ... and we also allow both grey/gray - wxString colNameAlt = colName; - if ( !colNameAlt.Replace(_T("GRAY"), _T("GREY")) ) - { - // but in this case it is not necessary so avoid extra search below - colNameAlt.clear(); - } - - wxStringToColourHashMap::iterator it = m_map->find(colName); - if ( it == m_map->end() && !colNameAlt.empty() ) - it = m_map->find(colNameAlt); - if ( it != m_map->end() ) - { - *(it->second) = colour; - } - else // new colour - { - (*m_map)[colName] = new wxColour(colour); - } -} - -wxColour wxColourDatabase::Find(const wxString& colour) const -{ - wxColourDatabase * const self = wxConstCast(this, wxColourDatabase); - self->Initialize(); - - // make the comparaison case insensitive and also match both grey and gray - wxString colName = colour; - colName.MakeUpper(); - wxString colNameAlt = colName; - if ( !colNameAlt.Replace(_T("GRAY"), _T("GREY")) ) - colNameAlt.clear(); - - wxStringToColourHashMap::iterator it = m_map->find(colName); - if ( it == m_map->end() && !colNameAlt.empty() ) - it = m_map->find(colNameAlt); - if ( it != m_map->end() ) - return *(it->second); - - // we did not find any result in existing colours: - // we won't use wxString -> wxColour conversion because the - // wxColour::Set(const wxString &) function which does that conversion - // internally uses this function (wxColourDatabase::Find) and we want - // to avoid infinite recursion ! - return wxNullColour; -} - -wxString wxColourDatabase::FindName(const wxColour& colour) const -{ - wxColourDatabase * const self = wxConstCast(this, wxColourDatabase); - self->Initialize(); - - typedef wxStringToColourHashMap::iterator iterator; - - for ( iterator it = m_map->begin(), en = m_map->end(); it != en; ++it ) - { - if ( *(it->second) == colour ) - return it->first; - } - - return wxEmptyString; -} - -// ---------------------------------------------------------------------------- -// deprecated wxColourDatabase methods -// ---------------------------------------------------------------------------- - -#if WXWIN_COMPATIBILITY_2_6 -wxColour *wxColourDatabase::FindColour(const wxString& name) -{ - // This function is deprecated, use Find() instead. - // Formerly this function sometimes would return a deletable pointer and - // sometimes a non-deletable one (when returning a colour from the database). - // Trying to delete the latter anyway results in problems, so probably - // nobody ever freed the pointers. Currently it always returns a new - // instance, which means there will be memory leaks. - wxLogDebug(wxT("wxColourDataBase::FindColour():") - wxT(" Please use wxColourDataBase::Find() instead")); - - // using a static variable here is not the most elegant solution but unless - // we want to make wxStringToColourHashMap public (i.e. move it to the - // header) so that we could have a member function returning - // wxStringToColourHashMap::iterator, there is really no good way to do it - // otherwise - // - // and knowing that this function is going to disappear in the next release - // anyhow I don't want to waste time on this - - static wxColour s_col; - - s_col = Find(name); - if ( !s_col.Ok() ) - return NULL; - - return new wxColour(s_col); -} -#endif // WXWIN_COMPATIBILITY_2_6 - -// ============================================================================ -// stock objects -// ============================================================================ - -static wxStockGDI gs_wxStockGDI_instance; -wxStockGDI* wxStockGDI::ms_instance = &gs_wxStockGDI_instance; -wxObject* wxStockGDI::ms_stockObject[ITEMCOUNT]; - -wxStockGDI::wxStockGDI() -{ -} - -wxStockGDI::~wxStockGDI() -{ -} - -void wxStockGDI::DeleteAll() -{ - for (unsigned i = 0; i < ITEMCOUNT; i++) - { - delete ms_stockObject[i]; - ms_stockObject[i] = NULL; - } -} - -const wxBrush* wxStockGDI::GetBrush(Item item) -{ - wxBrush* brush = wx_static_cast(wxBrush*, ms_stockObject[item]); - if (brush == NULL) - { - switch (item) - { - case BRUSH_BLACK: - brush = new wxBrush(*GetColour(COLOUR_BLACK), wxSOLID); - break; - case BRUSH_BLUE: - brush = new wxBrush(*GetColour(COLOUR_BLUE), wxSOLID); - break; - case BRUSH_CYAN: - brush = new wxBrush(*GetColour(COLOUR_CYAN), wxSOLID); - break; - case BRUSH_GREEN: - brush = new wxBrush(*GetColour(COLOUR_GREEN), wxSOLID); - break; - case BRUSH_GREY: - brush = new wxBrush(wxColour(wxT("GREY")), wxSOLID); - break; - case BRUSH_LIGHTGREY: - brush = new wxBrush(*GetColour(COLOUR_LIGHTGREY), wxSOLID); - break; - case BRUSH_MEDIUMGREY: - brush = new wxBrush(wxColour(wxT("MEDIUM GREY")), wxSOLID); - break; - case BRUSH_RED: - brush = new wxBrush(*GetColour(COLOUR_RED), wxSOLID); - break; - case BRUSH_TRANSPARENT: - brush = new wxBrush(*GetColour(COLOUR_BLACK), wxTRANSPARENT); - break; - case BRUSH_WHITE: - brush = new wxBrush(*GetColour(COLOUR_WHITE), wxSOLID); - break; - default: - wxFAIL; - } - ms_stockObject[item] = brush; - } - return brush; -} - -const wxColour* wxStockGDI::GetColour(Item item) -{ - wxColour* colour = wx_static_cast(wxColour*, ms_stockObject[item]); - if (colour == NULL) - { - switch (item) - { - case COLOUR_BLACK: - colour = new wxColour(0, 0, 0); - break; - case COLOUR_BLUE: - colour = new wxColour(0, 0, 255); - break; - case COLOUR_CYAN: - colour = new wxColour(wxT("CYAN")); - break; - case COLOUR_GREEN: - colour = new wxColour(0, 255, 0); - break; - case COLOUR_LIGHTGREY: - colour = new wxColour(wxT("LIGHT GREY")); - break; - case COLOUR_RED: - colour = new wxColour(255, 0, 0); - break; - case COLOUR_WHITE: - colour = new wxColour(255, 255, 255); - break; - default: - wxFAIL; - } - ms_stockObject[item] = colour; - } - return colour; -} - -const wxCursor* wxStockGDI::GetCursor(Item item) -{ - wxCursor* cursor = wx_static_cast(wxCursor*, ms_stockObject[item]); - if (cursor == NULL) - { - switch (item) - { - case CURSOR_CROSS: - cursor = new wxCursor(wxCURSOR_CROSS); - break; - case CURSOR_HOURGLASS: - cursor = new wxCursor(wxCURSOR_WAIT); - break; - case CURSOR_STANDARD: - cursor = new wxCursor(wxCURSOR_ARROW); - break; - default: - wxFAIL; - } - ms_stockObject[item] = cursor; - } - return cursor; -} - -const wxFont* wxStockGDI::GetFont(Item item) -{ - wxFont* font = wx_static_cast(wxFont*, ms_stockObject[item]); - if (font == NULL) - { - switch (item) - { - case FONT_ITALIC: - font = new wxFont(GetFont(FONT_NORMAL)->GetPointSize(), wxROMAN, wxITALIC, wxNORMAL); - break; - case FONT_NORMAL: - font = new wxFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT)); - break; - case FONT_SMALL: - font = new wxFont(GetFont(FONT_NORMAL)->GetPointSize() - 2, wxSWISS, wxNORMAL, wxNORMAL); - break; - case FONT_SWISS: - font = new wxFont(GetFont(FONT_NORMAL)->GetPointSize(), wxSWISS, wxNORMAL, wxNORMAL); - break; - default: - wxFAIL; - } - ms_stockObject[item] = font; - } - return font; -} - -const wxPen* wxStockGDI::GetPen(Item item) -{ - wxPen* pen = wx_static_cast(wxPen*, ms_stockObject[item]); - if (pen == NULL) - { - switch (item) - { - case PEN_BLACK: - pen = new wxPen(*GetColour(COLOUR_BLACK), 1, wxSOLID); - break; - case PEN_BLACKDASHED: - pen = new wxPen(*GetColour(COLOUR_BLACK), 1, wxSHORT_DASH); - break; - case PEN_CYAN: - pen = new wxPen(*GetColour(COLOUR_CYAN), 1, wxSOLID); - break; - case PEN_GREEN: - pen = new wxPen(*GetColour(COLOUR_GREEN), 1, wxSOLID); - break; - case PEN_GREY: - pen = new wxPen(wxColour(wxT("GREY")), 1, wxSOLID); - break; - case PEN_LIGHTGREY: - pen = new wxPen(*GetColour(COLOUR_LIGHTGREY), 1, wxSOLID); - break; - case PEN_MEDIUMGREY: - pen = new wxPen(wxColour(wxT("MEDIUM GREY")), 1, wxSOLID); - break; - case PEN_RED: - pen = new wxPen(*GetColour(COLOUR_RED), 1, wxSOLID); - break; - case PEN_TRANSPARENT: - pen = new wxPen(*GetColour(COLOUR_BLACK), 1, wxTRANSPARENT); - break; - case PEN_WHITE: - pen = new wxPen(*GetColour(COLOUR_WHITE), 1, wxSOLID); - break; - default: - wxFAIL; - } - ms_stockObject[item] = pen; - } - return pen; -} - -void wxInitializeStockLists() -{ - wxTheColourDatabase = new wxColourDatabase; - - wxTheBrushList = new wxBrushList; - wxThePenList = new wxPenList; - wxTheFontList = new wxFontList; -} - -void wxDeleteStockLists() -{ - wxDELETE(wxTheBrushList); - wxDELETE(wxThePenList); - wxDELETE(wxTheFontList); -} - -// ============================================================================ -// wxTheXXXList stuff (semi-obsolete) -// ============================================================================ - -wxGDIObjListBase::wxGDIObjListBase() -{ -} - -wxGDIObjListBase::~wxGDIObjListBase() -{ - for (wxList::compatibility_iterator node = list.GetFirst(); node; node = node->GetNext()) - { - delete wx_static_cast(wxObject*, node->GetData()); - } -} - -wxPen *wxPenList::FindOrCreatePen (const wxColour& colour, int width, int style) -{ - for ( wxList::compatibility_iterator node = list.GetFirst(); - node; - node = node->GetNext() ) - { - wxPen * const pen = (wxPen *) node->GetData(); - if ( pen->GetWidth () == width && - pen->GetStyle () == style && - pen->GetColour() == colour ) - return pen; - } - - wxPen* pen = NULL; - wxPen penTmp(colour, width, style); - if (penTmp.Ok()) - { - pen = new wxPen(penTmp); - list.Append(pen); - } - - return pen; -} - -wxBrush *wxBrushList::FindOrCreateBrush (const wxColour& colour, int style) -{ - for ( wxList::compatibility_iterator node = list.GetFirst(); - node; - node = node->GetNext() ) - { - wxBrush * const brush = (wxBrush *) node->GetData (); - if ( brush->GetStyle () == style && brush->GetColour() == colour ) - return brush; - } - - wxBrush* brush = NULL; - wxBrush brushTmp(colour, style); - if (brushTmp.Ok()) - { - brush = new wxBrush(brushTmp); - list.Append(brush); - } - - return brush; -} - -wxFont *wxFontList::FindOrCreateFont(int pointSize, - int family, - int style, - int weight, - bool underline, - const wxString& facename, - wxFontEncoding encoding) -{ - wxFont *font; - wxList::compatibility_iterator node; - for (node = list.GetFirst(); node; node = node->GetNext()) - { - font = (wxFont *)node->GetData(); - if ( - font->GetPointSize () == pointSize && - font->GetStyle () == style && - font->GetWeight () == weight && - font->GetUnderlined () == underline ) - { - int fontFamily = font->GetFamily(); - -#if defined(__WXGTK__) - // under GTK the default family is wxSWISS, so looking for a font - // with wxDEFAULT family should return a wxSWISS one instead of - // creating a new one - bool same = (fontFamily == family) || - (fontFamily == wxSWISS && family == wxDEFAULT); -#else // !GTK - // VZ: but why elsewhere do we require an exact match? mystery... - bool same = fontFamily == family; -#endif // GTK/!GTK - - // empty facename matches anything at all: this is bad because - // depending on which fonts are already created, we might get back - // a different font if we create it with empty facename, but it is - // still better than never matching anything in the cache at all - // in this case - if ( same && !facename.empty() ) - { - const wxString& fontFace = font->GetFaceName(); - - // empty facename matches everything - same = !fontFace || fontFace == facename; - } - - if ( same && (encoding != wxFONTENCODING_DEFAULT) ) - { - // have to match the encoding too - same = font->GetEncoding() == encoding; - } - - if ( same ) - { - return font; - } - } - } - - // font not found, create the new one - font = NULL; - wxFont fontTmp(pointSize, family, style, weight, underline, facename, encoding); - if (fontTmp.Ok()) - { - font = new wxFont(fontTmp); - list.Append(font); - } - - return font; -} - -#if WXWIN_COMPATIBILITY_2_6 -void wxBrushList::AddBrush(wxBrush*) { } -void wxBrushList::RemoveBrush(wxBrush*) { } -void wxFontList::AddFont(wxFont*) { } -void wxFontList::RemoveFont(wxFont*) { } -void wxPenList::AddPen(wxPen*) { } -void wxPenList::RemovePen(wxPen*) { } -#endif - -wxSize wxGetDisplaySize() -{ - int x, y; - wxDisplaySize(& x, & y); - return wxSize(x, y); -} - -wxRect wxGetClientDisplayRect() -{ - int x, y, width, height; - wxClientDisplayRect(&x, &y, &width, &height); // call plat-specific version - return wxRect(x, y, width, height); -} - -wxSize wxGetDisplaySizeMM() -{ - int x, y; - wxDisplaySizeMM(& x, & y); - return wxSize(x, y); -} - -wxResourceCache::~wxResourceCache () -{ - wxList::compatibility_iterator node = GetFirst (); - while (node) { - wxObject *item = (wxObject *)node->GetData(); - delete item; - - node = node->GetNext (); - } -} +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/gdicmn.cpp +// Purpose: Common GDI classes +// Author: Julian Smart +// Modified by: +// Created: 01/02/97 +// RCS-ID: $Id: gdicmn.cpp 50022 2007-11-17 14:24:18Z VZ $ +// Copyright: (c) Julian Smart +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#include "wx/gdicmn.h" +#include "wx/gdiobj.h" + +#ifndef WX_PRECOMP + #include "wx/log.h" + #include "wx/pen.h" + #include "wx/brush.h" + #include "wx/palette.h" + #include "wx/icon.h" + #include "wx/cursor.h" + #include "wx/settings.h" + #include "wx/bitmap.h" + #include "wx/colour.h" + #include "wx/font.h" +#endif + + +IMPLEMENT_DYNAMIC_CLASS(wxGDIObject, wxObject) + + +WXDLLIMPEXP_DATA_CORE(wxBrushList*) wxTheBrushList; +WXDLLIMPEXP_DATA_CORE(wxFontList*) wxTheFontList; +WXDLLIMPEXP_DATA_CORE(wxPenList*) wxThePenList; + +WXDLLIMPEXP_DATA_CORE(wxColourDatabase*) wxTheColourDatabase; + +WXDLLIMPEXP_DATA_CORE(wxBitmap) wxNullBitmap; +WXDLLIMPEXP_DATA_CORE(wxBrush) wxNullBrush; +WXDLLIMPEXP_DATA_CORE(wxColour) wxNullColour; +WXDLLIMPEXP_DATA_CORE(wxCursor) wxNullCursor; +WXDLLIMPEXP_DATA_CORE(wxFont) wxNullFont; +WXDLLIMPEXP_DATA_CORE(wxIcon) wxNullIcon; +WXDLLIMPEXP_DATA_CORE(wxPen) wxNullPen; +#if wxUSE_PALETTE +WXDLLIMPEXP_DATA_CORE(wxPalette) wxNullPalette; +#endif + +const wxSize wxDefaultSize(wxDefaultCoord, wxDefaultCoord); +const wxPoint wxDefaultPosition(wxDefaultCoord, wxDefaultCoord); + +#if wxUSE_EXTENDED_RTTI + +// wxPoint + +template<> void wxStringReadValue(const wxString &s , wxPoint &data ) +{ + wxSscanf(s, wxT("%d,%d"), &data.x , &data.y ) ; +} + +template<> void wxStringWriteValue(wxString &s , const wxPoint &data ) +{ + s = wxString::Format(wxT("%d,%d"), data.x , data.y ) ; +} + +wxCUSTOM_TYPE_INFO(wxPoint, wxToStringConverter , wxFromStringConverter) + +template<> void wxStringReadValue(const wxString &s , wxSize &data ) +{ + wxSscanf(s, wxT("%d,%d"), &data.x , &data.y ) ; +} + +template<> void wxStringWriteValue(wxString &s , const wxSize &data ) +{ + s = wxString::Format(wxT("%d,%d"), data.x , data.y ) ; +} + +wxCUSTOM_TYPE_INFO(wxSize, wxToStringConverter , wxFromStringConverter) + +#endif + +wxRect::wxRect(const wxPoint& point1, const wxPoint& point2) +{ + x = point1.x; + y = point1.y; + width = point2.x - point1.x; + height = point2.y - point1.y; + + if (width < 0) + { + width = -width; + x = point2.x; + } + width++; + + if (height < 0) + { + height = -height; + y = point2.y; + } + height++; +} + +bool wxRect::operator==(const wxRect& rect) const +{ + return ((x == rect.x) && + (y == rect.y) && + (width == rect.width) && + (height == rect.height)); +} + +wxRect wxRect::operator+(const wxRect& rect) const +{ + int x1 = wxMin(this->x, rect.x); + int y1 = wxMin(this->y, rect.y); + int y2 = wxMax(y+height, rect.height+rect.y); + int x2 = wxMax(x+width, rect.width+rect.x); + return wxRect(x1, y1, x2-x1, y2-y1); +} + +wxRect& wxRect::Union(const wxRect& rect) +{ + // ignore empty rectangles: union with an empty rectangle shouldn't extend + // this one to (0, 0) + if ( !width || !height ) + { + *this = rect; + } + else if ( rect.width && rect.height ) + { + int x1 = wxMin(x, rect.x); + int y1 = wxMin(y, rect.y); + int y2 = wxMax(y + height, rect.height + rect.y); + int x2 = wxMax(x + width, rect.width + rect.x); + + x = x1; + y = y1; + width = x2 - x1; + height = y2 - y1; + } + //else: we're not empty and rect is empty + + return *this; +} + +wxRect& wxRect::Inflate(wxCoord dx, wxCoord dy) +{ + if (-2*dx>width) + { + // Don't allow deflate to eat more width than we have, + // a well-defined rectangle cannot have negative width. + x+=width/2; + width=0; + } + else + { + // The inflate is valid. + x-=dx; + width+=2*dx; + } + + if (-2*dy>height) + { + // Don't allow deflate to eat more height than we have, + // a well-defined rectangle cannot have negative height. + y+=height/2; + height=0; + } + else + { + // The inflate is valid. + y-=dy; + height+=2*dy; + } + + return *this; +} + +bool wxRect::Contains(int cx, int cy) const +{ + return ( (cx >= x) && (cy >= y) + && ((cy - y) < height) + && ((cx - x) < width) + ); +} + +bool wxRect::Contains(const wxRect& rect) const +{ + return Contains(rect.GetTopLeft()) && Contains(rect.GetBottomRight()); +} + +wxRect& wxRect::Intersect(const wxRect& rect) +{ + int x2 = GetRight(), + y2 = GetBottom(); + + if ( x < rect.x ) + x = rect.x; + if ( y < rect.y ) + y = rect.y; + if ( x2 > rect.GetRight() ) + x2 = rect.GetRight(); + if ( y2 > rect.GetBottom() ) + y2 = rect.GetBottom(); + + width = x2 - x + 1; + height = y2 - y + 1; + + if ( width <= 0 || height <= 0 ) + { + width = + height = 0; + } + + return *this; +} + +bool wxRect::Intersects(const wxRect& rect) const +{ + wxRect r = Intersect(rect); + + // if there is no intersection, both width and height are 0 + return r.width != 0; +} + +// ============================================================================ +// wxColourDatabase +// ============================================================================ + +// ---------------------------------------------------------------------------- +// wxColourDatabase ctor/dtor +// ---------------------------------------------------------------------------- + +wxColourDatabase::wxColourDatabase () +{ + // will be created on demand in Initialize() + m_map = NULL; +} + +wxColourDatabase::~wxColourDatabase () +{ + if ( m_map ) + { + WX_CLEAR_HASH_MAP(wxStringToColourHashMap, *m_map); + + delete m_map; + } + +#ifdef __WXPM__ + delete [] m_palTable; +#endif +} + +// Colour database stuff +void wxColourDatabase::Initialize() +{ + if ( m_map ) + { + // already initialized + return; + } + + m_map = new wxStringToColourHashMap; + + static const struct wxColourDesc + { + const wxChar *name; + unsigned char r,g,b; + } + wxColourTable[] = + { + {wxT("AQUAMARINE"),112, 219, 147}, + {wxT("BLACK"),0, 0, 0}, + {wxT("BLUE"), 0, 0, 255}, + {wxT("BLUE VIOLET"), 159, 95, 159}, + {wxT("BROWN"), 165, 42, 42}, + {wxT("CADET BLUE"), 95, 159, 159}, + {wxT("CORAL"), 255, 127, 0}, + {wxT("CORNFLOWER BLUE"), 66, 66, 111}, + {wxT("CYAN"), 0, 255, 255}, + {wxT("DARK GREY"), 47, 47, 47}, // ? + + {wxT("DARK GREEN"), 47, 79, 47}, + {wxT("DARK OLIVE GREEN"), 79, 79, 47}, + {wxT("DARK ORCHID"), 153, 50, 204}, + {wxT("DARK SLATE BLUE"), 107, 35, 142}, + {wxT("DARK SLATE GREY"), 47, 79, 79}, + {wxT("DARK TURQUOISE"), 112, 147, 219}, + {wxT("DIM GREY"), 84, 84, 84}, + {wxT("FIREBRICK"), 142, 35, 35}, + {wxT("FOREST GREEN"), 35, 142, 35}, + {wxT("GOLD"), 204, 127, 50}, + {wxT("GOLDENROD"), 219, 219, 112}, + {wxT("GREY"), 128, 128, 128}, + {wxT("GREEN"), 0, 255, 0}, + {wxT("GREEN YELLOW"), 147, 219, 112}, + {wxT("INDIAN RED"), 79, 47, 47}, + {wxT("KHAKI"), 159, 159, 95}, + {wxT("LIGHT BLUE"), 191, 216, 216}, + {wxT("LIGHT GREY"), 192, 192, 192}, + {wxT("LIGHT STEEL BLUE"), 143, 143, 188}, + {wxT("LIME GREEN"), 50, 204, 50}, + {wxT("LIGHT MAGENTA"), 255, 0, 255}, + {wxT("MAGENTA"), 255, 0, 255}, + {wxT("MAROON"), 142, 35, 107}, + {wxT("MEDIUM AQUAMARINE"), 50, 204, 153}, + {wxT("MEDIUM GREY"), 100, 100, 100}, + {wxT("MEDIUM BLUE"), 50, 50, 204}, + {wxT("MEDIUM FOREST GREEN"), 107, 142, 35}, + {wxT("MEDIUM GOLDENROD"), 234, 234, 173}, + {wxT("MEDIUM ORCHID"), 147, 112, 219}, + {wxT("MEDIUM SEA GREEN"), 66, 111, 66}, + {wxT("MEDIUM SLATE BLUE"), 127, 0, 255}, + {wxT("MEDIUM SPRING GREEN"), 127, 255, 0}, + {wxT("MEDIUM TURQUOISE"), 112, 219, 219}, + {wxT("MEDIUM VIOLET RED"), 219, 112, 147}, + {wxT("MIDNIGHT BLUE"), 47, 47, 79}, + {wxT("NAVY"), 35, 35, 142}, + {wxT("ORANGE"), 204, 50, 50}, + {wxT("ORANGE RED"), 255, 0, 127}, + {wxT("ORCHID"), 219, 112, 219}, + {wxT("PALE GREEN"), 143, 188, 143}, + {wxT("PINK"), 255, 192, 203}, + {wxT("PLUM"), 234, 173, 234}, + {wxT("PURPLE"), 176, 0, 255}, + {wxT("RED"), 255, 0, 0}, + {wxT("SALMON"), 111, 66, 66}, + {wxT("SEA GREEN"), 35, 142, 107}, + {wxT("SIENNA"), 142, 107, 35}, + {wxT("SKY BLUE"), 50, 153, 204}, + {wxT("SLATE BLUE"), 0, 127, 255}, + {wxT("SPRING GREEN"), 0, 255, 127}, + {wxT("STEEL BLUE"), 35, 107, 142}, + {wxT("TAN"), 219, 147, 112}, + {wxT("THISTLE"), 216, 191, 216}, + {wxT("TURQUOISE"), 173, 234, 234}, + {wxT("VIOLET"), 79, 47, 79}, + {wxT("VIOLET RED"), 204, 50, 153}, + {wxT("WHEAT"), 216, 216, 191}, + {wxT("WHITE"), 255, 255, 255}, + {wxT("YELLOW"), 255, 255, 0}, + {wxT("YELLOW GREEN"), 153, 204, 50} + }; + + size_t n; + + for ( n = 0; n < WXSIZEOF(wxColourTable); n++ ) + { + const wxColourDesc& cc = wxColourTable[n]; + (*m_map)[cc.name] = new wxColour(cc.r, cc.g, cc.b); + } + +#ifdef __WXPM__ + m_palTable = new long[n]; + for ( n = 0; n < WXSIZEOF(wxColourTable); n++ ) + { + const wxColourDesc& cc = wxColourTable[n]; + m_palTable[n] = OS2RGB(cc.r,cc.g,cc.b); + } + m_nSize = n; +#endif +} + +// ---------------------------------------------------------------------------- +// wxColourDatabase operations +// ---------------------------------------------------------------------------- + +void wxColourDatabase::AddColour(const wxString& name, const wxColour& colour) +{ + Initialize(); + + // canonicalize the colour names before using them as keys: they should be + // in upper case + wxString colName = name; + colName.MakeUpper(); + + // ... and we also allow both grey/gray + wxString colNameAlt = colName; + if ( !colNameAlt.Replace(_T("GRAY"), _T("GREY")) ) + { + // but in this case it is not necessary so avoid extra search below + colNameAlt.clear(); + } + + wxStringToColourHashMap::iterator it = m_map->find(colName); + if ( it == m_map->end() && !colNameAlt.empty() ) + it = m_map->find(colNameAlt); + if ( it != m_map->end() ) + { + *(it->second) = colour; + } + else // new colour + { + (*m_map)[colName] = new wxColour(colour); + } +} + +wxColour wxColourDatabase::Find(const wxString& colour) const +{ + wxColourDatabase * const self = wxConstCast(this, wxColourDatabase); + self->Initialize(); + + // make the comparaison case insensitive and also match both grey and gray + wxString colName = colour; + colName.MakeUpper(); + wxString colNameAlt = colName; + if ( !colNameAlt.Replace(_T("GRAY"), _T("GREY")) ) + colNameAlt.clear(); + + wxStringToColourHashMap::iterator it = m_map->find(colName); + if ( it == m_map->end() && !colNameAlt.empty() ) + it = m_map->find(colNameAlt); + if ( it != m_map->end() ) + return *(it->second); + + // we did not find any result in existing colours: + // we won't use wxString -> wxColour conversion because the + // wxColour::Set(const wxString &) function which does that conversion + // internally uses this function (wxColourDatabase::Find) and we want + // to avoid infinite recursion ! + return wxNullColour; +} + +wxString wxColourDatabase::FindName(const wxColour& colour) const +{ + wxColourDatabase * const self = wxConstCast(this, wxColourDatabase); + self->Initialize(); + + typedef wxStringToColourHashMap::iterator iterator; + + for ( iterator it = m_map->begin(), en = m_map->end(); it != en; ++it ) + { + if ( *(it->second) == colour ) + return it->first; + } + + return wxEmptyString; +} + +// ---------------------------------------------------------------------------- +// deprecated wxColourDatabase methods +// ---------------------------------------------------------------------------- + +#if WXWIN_COMPATIBILITY_2_6 +wxColour *wxColourDatabase::FindColour(const wxString& name) +{ + // This function is deprecated, use Find() instead. + // Formerly this function sometimes would return a deletable pointer and + // sometimes a non-deletable one (when returning a colour from the database). + // Trying to delete the latter anyway results in problems, so probably + // nobody ever freed the pointers. Currently it always returns a new + // instance, which means there will be memory leaks. + wxLogDebug(wxT("wxColourDataBase::FindColour():") + wxT(" Please use wxColourDataBase::Find() instead")); + + // using a static variable here is not the most elegant solution but unless + // we want to make wxStringToColourHashMap public (i.e. move it to the + // header) so that we could have a member function returning + // wxStringToColourHashMap::iterator, there is really no good way to do it + // otherwise + // + // and knowing that this function is going to disappear in the next release + // anyhow I don't want to waste time on this + + static wxColour s_col; + + s_col = Find(name); + if ( !s_col.Ok() ) + return NULL; + + return new wxColour(s_col); +} +#endif // WXWIN_COMPATIBILITY_2_6 + +// ============================================================================ +// stock objects +// ============================================================================ + +static wxStockGDI gs_wxStockGDI_instance; +wxStockGDI* wxStockGDI::ms_instance = &gs_wxStockGDI_instance; +wxObject* wxStockGDI::ms_stockObject[ITEMCOUNT]; + +wxStockGDI::wxStockGDI() +{ +} + +wxStockGDI::~wxStockGDI() +{ +} + +void wxStockGDI::DeleteAll() +{ + for (unsigned i = 0; i < ITEMCOUNT; i++) + { + delete ms_stockObject[i]; + ms_stockObject[i] = NULL; + } +} + +const wxBrush* wxStockGDI::GetBrush(Item item) +{ + wxBrush* brush = wx_static_cast(wxBrush*, ms_stockObject[item]); + if (brush == NULL) + { + switch (item) + { + case BRUSH_BLACK: + brush = new wxBrush(*GetColour(COLOUR_BLACK), wxSOLID); + break; + case BRUSH_BLUE: + brush = new wxBrush(*GetColour(COLOUR_BLUE), wxSOLID); + break; + case BRUSH_CYAN: + brush = new wxBrush(*GetColour(COLOUR_CYAN), wxSOLID); + break; + case BRUSH_GREEN: + brush = new wxBrush(*GetColour(COLOUR_GREEN), wxSOLID); + break; + case BRUSH_GREY: + brush = new wxBrush(wxColour(wxT("GREY")), wxSOLID); + break; + case BRUSH_LIGHTGREY: + brush = new wxBrush(*GetColour(COLOUR_LIGHTGREY), wxSOLID); + break; + case BRUSH_MEDIUMGREY: + brush = new wxBrush(wxColour(wxT("MEDIUM GREY")), wxSOLID); + break; + case BRUSH_RED: + brush = new wxBrush(*GetColour(COLOUR_RED), wxSOLID); + break; + case BRUSH_TRANSPARENT: + brush = new wxBrush(*GetColour(COLOUR_BLACK), wxTRANSPARENT); + break; + case BRUSH_WHITE: + brush = new wxBrush(*GetColour(COLOUR_WHITE), wxSOLID); + break; + default: + wxFAIL; + } + ms_stockObject[item] = brush; + } + return brush; +} + +const wxColour* wxStockGDI::GetColour(Item item) +{ + wxColour* colour = wx_static_cast(wxColour*, ms_stockObject[item]); + if (colour == NULL) + { + switch (item) + { + case COLOUR_BLACK: + colour = new wxColour(0, 0, 0); + break; + case COLOUR_BLUE: + colour = new wxColour(0, 0, 255); + break; + case COLOUR_CYAN: + colour = new wxColour(wxT("CYAN")); + break; + case COLOUR_GREEN: + colour = new wxColour(0, 255, 0); + break; + case COLOUR_LIGHTGREY: + colour = new wxColour(wxT("LIGHT GREY")); + break; + case COLOUR_RED: + colour = new wxColour(255, 0, 0); + break; + case COLOUR_WHITE: + colour = new wxColour(255, 255, 255); + break; + default: + wxFAIL; + } + ms_stockObject[item] = colour; + } + return colour; +} + +const wxCursor* wxStockGDI::GetCursor(Item item) +{ + wxCursor* cursor = wx_static_cast(wxCursor*, ms_stockObject[item]); + if (cursor == NULL) + { + switch (item) + { + case CURSOR_CROSS: + cursor = new wxCursor(wxCURSOR_CROSS); + break; + case CURSOR_HOURGLASS: + cursor = new wxCursor(wxCURSOR_WAIT); + break; + case CURSOR_STANDARD: + cursor = new wxCursor(wxCURSOR_ARROW); + break; + default: + wxFAIL; + } + ms_stockObject[item] = cursor; + } + return cursor; +} + +const wxFont* wxStockGDI::GetFont(Item item) +{ + wxFont* font = wx_static_cast(wxFont*, ms_stockObject[item]); + if (font == NULL) + { + switch (item) + { + case FONT_ITALIC: + font = new wxFont(GetFont(FONT_NORMAL)->GetPointSize(), wxROMAN, wxITALIC, wxNORMAL); + break; + case FONT_NORMAL: + font = new wxFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT)); + break; + case FONT_SMALL: + font = new wxFont(GetFont(FONT_NORMAL)->GetPointSize() - 2, wxSWISS, wxNORMAL, wxNORMAL); + break; + case FONT_SWISS: + font = new wxFont(GetFont(FONT_NORMAL)->GetPointSize(), wxSWISS, wxNORMAL, wxNORMAL); + break; + default: + wxFAIL; + } + ms_stockObject[item] = font; + } + return font; +} + +const wxPen* wxStockGDI::GetPen(Item item) +{ + wxPen* pen = wx_static_cast(wxPen*, ms_stockObject[item]); + if (pen == NULL) + { + switch (item) + { + case PEN_BLACK: + pen = new wxPen(*GetColour(COLOUR_BLACK), 1, wxSOLID); + break; + case PEN_BLACKDASHED: + pen = new wxPen(*GetColour(COLOUR_BLACK), 1, wxSHORT_DASH); + break; + case PEN_CYAN: + pen = new wxPen(*GetColour(COLOUR_CYAN), 1, wxSOLID); + break; + case PEN_GREEN: + pen = new wxPen(*GetColour(COLOUR_GREEN), 1, wxSOLID); + break; + case PEN_GREY: + pen = new wxPen(wxColour(wxT("GREY")), 1, wxSOLID); + break; + case PEN_LIGHTGREY: + pen = new wxPen(*GetColour(COLOUR_LIGHTGREY), 1, wxSOLID); + break; + case PEN_MEDIUMGREY: + pen = new wxPen(wxColour(wxT("MEDIUM GREY")), 1, wxSOLID); + break; + case PEN_RED: + pen = new wxPen(*GetColour(COLOUR_RED), 1, wxSOLID); + break; + case PEN_TRANSPARENT: + pen = new wxPen(*GetColour(COLOUR_BLACK), 1, wxTRANSPARENT); + break; + case PEN_WHITE: + pen = new wxPen(*GetColour(COLOUR_WHITE), 1, wxSOLID); + break; + default: + wxFAIL; + } + ms_stockObject[item] = pen; + } + return pen; +} + +void wxInitializeStockLists() +{ + wxTheColourDatabase = new wxColourDatabase; + + wxTheBrushList = new wxBrushList; + wxThePenList = new wxPenList; + wxTheFontList = new wxFontList; +} + +void wxDeleteStockLists() +{ + wxDELETE(wxTheBrushList); + wxDELETE(wxThePenList); + wxDELETE(wxTheFontList); +} + +// ============================================================================ +// wxTheXXXList stuff (semi-obsolete) +// ============================================================================ + +wxGDIObjListBase::wxGDIObjListBase() +{ +} + +wxGDIObjListBase::~wxGDIObjListBase() +{ + for (wxList::compatibility_iterator node = list.GetFirst(); node; node = node->GetNext()) + { + delete wx_static_cast(wxObject*, node->GetData()); + } +} + +wxPen *wxPenList::FindOrCreatePen (const wxColour& colour, int width, int style) +{ + for ( wxList::compatibility_iterator node = list.GetFirst(); + node; + node = node->GetNext() ) + { + wxPen * const pen = (wxPen *) node->GetData(); + if ( pen->GetWidth () == width && + pen->GetStyle () == style && + pen->GetColour() == colour ) + return pen; + } + + wxPen* pen = NULL; + wxPen penTmp(colour, width, style); + if (penTmp.Ok()) + { + pen = new wxPen(penTmp); + list.Append(pen); + } + + return pen; +} + +wxBrush *wxBrushList::FindOrCreateBrush (const wxColour& colour, int style) +{ + for ( wxList::compatibility_iterator node = list.GetFirst(); + node; + node = node->GetNext() ) + { + wxBrush * const brush = (wxBrush *) node->GetData (); + if ( brush->GetStyle () == style && brush->GetColour() == colour ) + return brush; + } + + wxBrush* brush = NULL; + wxBrush brushTmp(colour, style); + if (brushTmp.Ok()) + { + brush = new wxBrush(brushTmp); + list.Append(brush); + } + + return brush; +} + +wxFont *wxFontList::FindOrCreateFont(int pointSize, + int family, + int style, + int weight, + bool underline, + const wxString& facename, + wxFontEncoding encoding) +{ + wxFont *font; + wxList::compatibility_iterator node; + for (node = list.GetFirst(); node; node = node->GetNext()) + { + font = (wxFont *)node->GetData(); + if ( + font->GetPointSize () == pointSize && + font->GetStyle () == style && + font->GetWeight () == weight && + font->GetUnderlined () == underline ) + { + int fontFamily = font->GetFamily(); + +#if defined(__WXGTK__) + // under GTK the default family is wxSWISS, so looking for a font + // with wxDEFAULT family should return a wxSWISS one instead of + // creating a new one + bool same = (fontFamily == family) || + (fontFamily == wxSWISS && family == wxDEFAULT); +#else // !GTK + // VZ: but why elsewhere do we require an exact match? mystery... + bool same = fontFamily == family; +#endif // GTK/!GTK + + // empty facename matches anything at all: this is bad because + // depending on which fonts are already created, we might get back + // a different font if we create it with empty facename, but it is + // still better than never matching anything in the cache at all + // in this case + if ( same && !facename.empty() ) + { + const wxString& fontFace = font->GetFaceName(); + + // empty facename matches everything + same = !fontFace || fontFace == facename; + } + + if ( same && (encoding != wxFONTENCODING_DEFAULT) ) + { + // have to match the encoding too + same = font->GetEncoding() == encoding; + } + + if ( same ) + { + return font; + } + } + } + + // font not found, create the new one + font = NULL; + wxFont fontTmp(pointSize, family, style, weight, underline, facename, encoding); + if (fontTmp.Ok()) + { + font = new wxFont(fontTmp); + list.Append(font); + } + + return font; +} + +#if WXWIN_COMPATIBILITY_2_6 +void wxBrushList::AddBrush(wxBrush*) { } +void wxBrushList::RemoveBrush(wxBrush*) { } +void wxFontList::AddFont(wxFont*) { } +void wxFontList::RemoveFont(wxFont*) { } +void wxPenList::AddPen(wxPen*) { } +void wxPenList::RemovePen(wxPen*) { } +#endif + +wxSize wxGetDisplaySize() +{ + int x, y; + wxDisplaySize(& x, & y); + return wxSize(x, y); +} + +wxRect wxGetClientDisplayRect() +{ + int x, y, width, height; + wxClientDisplayRect(&x, &y, &width, &height); // call plat-specific version + return wxRect(x, y, width, height); +} + +wxSize wxGetDisplaySizeMM() +{ + int x, y; + wxDisplaySizeMM(& x, & y); + return wxSize(x, y); +} + +wxResourceCache::~wxResourceCache () +{ + wxList::compatibility_iterator node = GetFirst (); + while (node) { + wxObject *item = (wxObject *)node->GetData(); + delete item; + + node = node->GetNext (); + } +} diff --git a/Externals/wxWidgets/src/common/geometry.cpp b/Externals/wxWidgets/src/common/geometry.cpp index 66726d13eb..362b1aee50 100644 --- a/Externals/wxWidgets/src/common/geometry.cpp +++ b/Externals/wxWidgets/src/common/geometry.cpp @@ -1,364 +1,364 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/geometry.cpp -// Purpose: Common Geometry Classes -// Author: Stefan Csomor -// Modified by: -// Created: 08/05/99 -// RCS-ID: -// Copyright: (c) 1999 Stefan Csomor -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_GEOMETRY - -#include "wx/geometry.h" - -#ifndef WX_PRECOMP - #include "wx/log.h" -#endif - -#include - -#include "wx/datstrm.h" - -// -// wxPoint2D -// - -// -// wxRect2D -// - -// wxDouble version - -// for the following calculations always remember -// that the right and bottom edges are not part of a rect - -bool wxRect2DDouble::Intersects( const wxRect2DDouble &rect ) const -{ - wxDouble left,right,bottom,top; - left = wxMax ( m_x , rect.m_x ); - right = wxMin ( m_x+m_width, rect.m_x + rect.m_width ); - top = wxMax ( m_y , rect.m_y ); - bottom = wxMin ( m_y+m_height, rect.m_y + rect.m_height ); - - if ( left < right && top < bottom ) - { - return true; - } - return false; -} - -void wxRect2DDouble::Intersect( const wxRect2DDouble &src1 , const wxRect2DDouble &src2 , wxRect2DDouble *dest ) -{ - wxDouble left,right,bottom,top; - left = wxMax ( src1.m_x , src2.m_x ); - right = wxMin ( src1.m_x+src1.m_width, src2.m_x + src2.m_width ); - top = wxMax ( src1.m_y , src2.m_y ); - bottom = wxMin ( src1.m_y+src1.m_height, src2.m_y + src2.m_height ); - - if ( left < right && top < bottom ) - { - dest->m_x = left; - dest->m_y = top; - dest->m_width = right - left; - dest->m_height = bottom - top; - } - else - { - dest->m_width = dest->m_height = 0; - } -} - -void wxRect2DDouble::Union( const wxRect2DDouble &src1 , const wxRect2DDouble &src2 , wxRect2DDouble *dest ) -{ - wxDouble left,right,bottom,top; - - left = wxMin ( src1.m_x , src2.m_x ); - right = wxMax ( src1.m_x+src1.m_width, src2.m_x + src2.m_width ); - top = wxMin ( src1.m_y , src2.m_y ); - bottom = wxMax ( src1.m_y+src1.m_height, src2.m_y + src2.m_height ); - - dest->m_x = left; - dest->m_y = top; - dest->m_width = right - left; - dest->m_height = bottom - top; -} - -void wxRect2DDouble::Union( const wxPoint2DDouble &pt ) -{ - wxDouble x = pt.m_x; - wxDouble y = pt.m_y; - - if ( x < m_x ) - { - SetLeft( x ); - } - else if ( x < m_x + m_width ) - { - // contained - } - else - { - SetRight( x ); - } - - if ( y < m_y ) - { - SetTop( y ); - } - else if ( y < m_y + m_height ) - { - // contained - } - else - { - SetBottom( y ); - } -} - -void wxRect2DDouble::ConstrainTo( const wxRect2DDouble &rect ) -{ - if ( GetLeft() < rect.GetLeft() ) - SetLeft( rect.GetLeft() ); - - if ( GetRight() > rect.GetRight() ) - SetRight( rect.GetRight() ); - - if ( GetBottom() > rect.GetBottom() ) - SetBottom( rect.GetBottom() ); - - if ( GetTop() < rect.GetTop() ) - SetTop( rect.GetTop() ); -} - -wxRect2DDouble& wxRect2DDouble::operator=( const wxRect2DDouble &r ) -{ - m_x = r.m_x; - m_y = r.m_y; - m_width = r.m_width; - m_height = r.m_height; - return *this; -} - -// integer version - -// for the following calculations always remember -// that the right and bottom edges are not part of a rect - -// wxPoint2D - -#if wxUSE_STREAMS -void wxPoint2DInt::WriteTo( wxDataOutputStream &stream ) const -{ - stream.Write32( m_x ); - stream.Write32( m_y ); -} - -void wxPoint2DInt::ReadFrom( wxDataInputStream &stream ) -{ - m_x = stream.Read32(); - m_y = stream.Read32(); -} -#endif // wxUSE_STREAMS - -wxDouble wxPoint2DInt::GetVectorAngle() const -{ - if ( m_x == 0 ) - { - if ( m_y >= 0 ) - return 90; - else - return 270; - } - if ( m_y == 0 ) - { - if ( m_x >= 0 ) - return 0; - else - return 180; - } - - // casts needed for MIPSpro compiler under SGI - wxDouble deg = atan2( (double)m_y , (double)m_x ) * 180 / M_PI; - if ( deg < 0 ) - { - deg += 360; - } - return deg; -} - - -void wxPoint2DInt::SetVectorAngle( wxDouble degrees ) -{ - wxDouble length = GetVectorLength(); - m_x = (int)(length * cos( degrees / 180 * M_PI )); - m_y = (int)(length * sin( degrees / 180 * M_PI )); -} - -wxDouble wxPoint2DDouble::GetVectorAngle() const -{ - if ( wxIsNullDouble(m_x) ) - { - if ( m_y >= 0 ) - return 90; - else - return 270; - } - if ( wxIsNullDouble(m_y) ) - { - if ( m_x >= 0 ) - return 0; - else - return 180; - } - wxDouble deg = atan2( m_y , m_x ) * 180 / M_PI; - if ( deg < 0 ) - { - deg += 360; - } - return deg; -} - -void wxPoint2DDouble::SetVectorAngle( wxDouble degrees ) -{ - wxDouble length = GetVectorLength(); - m_x = length * cos( degrees / 180 * M_PI ); - m_y = length * sin( degrees / 180 * M_PI ); -} - -// wxRect2D - -bool wxRect2DInt::Intersects( const wxRect2DInt &rect ) const -{ - wxInt32 left,right,bottom,top; - left = wxMax ( m_x , rect.m_x ); - right = wxMin ( m_x+m_width, rect.m_x + rect.m_width ); - top = wxMax ( m_y , rect.m_y ); - bottom = wxMin ( m_y+m_height, rect.m_y + rect.m_height ); - - if ( left < right && top < bottom ) - { - return true; - } - return false; -} - -void wxRect2DInt::Intersect( const wxRect2DInt &src1 , const wxRect2DInt &src2 , wxRect2DInt *dest ) -{ - wxInt32 left,right,bottom,top; - left = wxMax ( src1.m_x , src2.m_x ); - right = wxMin ( src1.m_x+src1.m_width, src2.m_x + src2.m_width ); - top = wxMax ( src1.m_y , src2.m_y ); - bottom = wxMin ( src1.m_y+src1.m_height, src2.m_y + src2.m_height ); - - if ( left < right && top < bottom ) - { - dest->m_x = left; - dest->m_y = top; - dest->m_width = right - left; - dest->m_height = bottom - top; - } - else - { - dest->m_width = dest->m_height = 0; - } -} - -void wxRect2DInt::Union( const wxRect2DInt &src1 , const wxRect2DInt &src2 , wxRect2DInt *dest ) -{ - wxInt32 left,right,bottom,top; - - left = wxMin ( src1.m_x , src2.m_x ); - right = wxMax ( src1.m_x+src1.m_width, src2.m_x + src2.m_width ); - top = wxMin ( src1.m_y , src2.m_y ); - bottom = wxMax ( src1.m_y+src1.m_height, src2.m_y + src2.m_height ); - - dest->m_x = left; - dest->m_y = top; - dest->m_width = right - left; - dest->m_height = bottom - top; -} - -void wxRect2DInt::Union( const wxPoint2DInt &pt ) -{ - wxInt32 x = pt.m_x; - wxInt32 y = pt.m_y; - - if ( x < m_x ) - { - SetLeft( x ); - } - else if ( x < m_x + m_width ) - { - // contained - } - else - { - SetRight( x ); - } - - if ( y < m_y ) - { - SetTop( y ); - } - else if ( y < m_y + m_height ) - { - // contained - } - else - { - SetBottom( y ); - } -} - -void wxRect2DInt::ConstrainTo( const wxRect2DInt &rect ) -{ - if ( GetLeft() < rect.GetLeft() ) - SetLeft( rect.GetLeft() ); - - if ( GetRight() > rect.GetRight() ) - SetRight( rect.GetRight() ); - - if ( GetBottom() > rect.GetBottom() ) - SetBottom( rect.GetBottom() ); - - if ( GetTop() < rect.GetTop() ) - SetTop( rect.GetTop() ); -} - -wxRect2DInt& wxRect2DInt::operator=( const wxRect2DInt &r ) -{ - m_x = r.m_x; - m_y = r.m_y; - m_width = r.m_width; - m_height = r.m_height; - return *this; -} - -#if wxUSE_STREAMS -void wxRect2DInt::WriteTo( wxDataOutputStream &stream ) const -{ - stream.Write32( m_x ); - stream.Write32( m_y ); - stream.Write32( m_width ); - stream.Write32( m_height ); -} - -void wxRect2DInt::ReadFrom( wxDataInputStream &stream ) -{ - m_x = stream.Read32(); - m_y = stream.Read32(); - m_width = stream.Read32(); - m_height = stream.Read32(); -} -#endif // wxUSE_STREAMS - -#endif // wxUSE_GEOMETRY +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/geometry.cpp +// Purpose: Common Geometry Classes +// Author: Stefan Csomor +// Modified by: +// Created: 08/05/99 +// RCS-ID: +// Copyright: (c) 1999 Stefan Csomor +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_GEOMETRY + +#include "wx/geometry.h" + +#ifndef WX_PRECOMP + #include "wx/log.h" +#endif + +#include + +#include "wx/datstrm.h" + +// +// wxPoint2D +// + +// +// wxRect2D +// + +// wxDouble version + +// for the following calculations always remember +// that the right and bottom edges are not part of a rect + +bool wxRect2DDouble::Intersects( const wxRect2DDouble &rect ) const +{ + wxDouble left,right,bottom,top; + left = wxMax ( m_x , rect.m_x ); + right = wxMin ( m_x+m_width, rect.m_x + rect.m_width ); + top = wxMax ( m_y , rect.m_y ); + bottom = wxMin ( m_y+m_height, rect.m_y + rect.m_height ); + + if ( left < right && top < bottom ) + { + return true; + } + return false; +} + +void wxRect2DDouble::Intersect( const wxRect2DDouble &src1 , const wxRect2DDouble &src2 , wxRect2DDouble *dest ) +{ + wxDouble left,right,bottom,top; + left = wxMax ( src1.m_x , src2.m_x ); + right = wxMin ( src1.m_x+src1.m_width, src2.m_x + src2.m_width ); + top = wxMax ( src1.m_y , src2.m_y ); + bottom = wxMin ( src1.m_y+src1.m_height, src2.m_y + src2.m_height ); + + if ( left < right && top < bottom ) + { + dest->m_x = left; + dest->m_y = top; + dest->m_width = right - left; + dest->m_height = bottom - top; + } + else + { + dest->m_width = dest->m_height = 0; + } +} + +void wxRect2DDouble::Union( const wxRect2DDouble &src1 , const wxRect2DDouble &src2 , wxRect2DDouble *dest ) +{ + wxDouble left,right,bottom,top; + + left = wxMin ( src1.m_x , src2.m_x ); + right = wxMax ( src1.m_x+src1.m_width, src2.m_x + src2.m_width ); + top = wxMin ( src1.m_y , src2.m_y ); + bottom = wxMax ( src1.m_y+src1.m_height, src2.m_y + src2.m_height ); + + dest->m_x = left; + dest->m_y = top; + dest->m_width = right - left; + dest->m_height = bottom - top; +} + +void wxRect2DDouble::Union( const wxPoint2DDouble &pt ) +{ + wxDouble x = pt.m_x; + wxDouble y = pt.m_y; + + if ( x < m_x ) + { + SetLeft( x ); + } + else if ( x < m_x + m_width ) + { + // contained + } + else + { + SetRight( x ); + } + + if ( y < m_y ) + { + SetTop( y ); + } + else if ( y < m_y + m_height ) + { + // contained + } + else + { + SetBottom( y ); + } +} + +void wxRect2DDouble::ConstrainTo( const wxRect2DDouble &rect ) +{ + if ( GetLeft() < rect.GetLeft() ) + SetLeft( rect.GetLeft() ); + + if ( GetRight() > rect.GetRight() ) + SetRight( rect.GetRight() ); + + if ( GetBottom() > rect.GetBottom() ) + SetBottom( rect.GetBottom() ); + + if ( GetTop() < rect.GetTop() ) + SetTop( rect.GetTop() ); +} + +wxRect2DDouble& wxRect2DDouble::operator=( const wxRect2DDouble &r ) +{ + m_x = r.m_x; + m_y = r.m_y; + m_width = r.m_width; + m_height = r.m_height; + return *this; +} + +// integer version + +// for the following calculations always remember +// that the right and bottom edges are not part of a rect + +// wxPoint2D + +#if wxUSE_STREAMS +void wxPoint2DInt::WriteTo( wxDataOutputStream &stream ) const +{ + stream.Write32( m_x ); + stream.Write32( m_y ); +} + +void wxPoint2DInt::ReadFrom( wxDataInputStream &stream ) +{ + m_x = stream.Read32(); + m_y = stream.Read32(); +} +#endif // wxUSE_STREAMS + +wxDouble wxPoint2DInt::GetVectorAngle() const +{ + if ( m_x == 0 ) + { + if ( m_y >= 0 ) + return 90; + else + return 270; + } + if ( m_y == 0 ) + { + if ( m_x >= 0 ) + return 0; + else + return 180; + } + + // casts needed for MIPSpro compiler under SGI + wxDouble deg = atan2( (double)m_y , (double)m_x ) * 180 / M_PI; + if ( deg < 0 ) + { + deg += 360; + } + return deg; +} + + +void wxPoint2DInt::SetVectorAngle( wxDouble degrees ) +{ + wxDouble length = GetVectorLength(); + m_x = (int)(length * cos( degrees / 180 * M_PI )); + m_y = (int)(length * sin( degrees / 180 * M_PI )); +} + +wxDouble wxPoint2DDouble::GetVectorAngle() const +{ + if ( wxIsNullDouble(m_x) ) + { + if ( m_y >= 0 ) + return 90; + else + return 270; + } + if ( wxIsNullDouble(m_y) ) + { + if ( m_x >= 0 ) + return 0; + else + return 180; + } + wxDouble deg = atan2( m_y , m_x ) * 180 / M_PI; + if ( deg < 0 ) + { + deg += 360; + } + return deg; +} + +void wxPoint2DDouble::SetVectorAngle( wxDouble degrees ) +{ + wxDouble length = GetVectorLength(); + m_x = length * cos( degrees / 180 * M_PI ); + m_y = length * sin( degrees / 180 * M_PI ); +} + +// wxRect2D + +bool wxRect2DInt::Intersects( const wxRect2DInt &rect ) const +{ + wxInt32 left,right,bottom,top; + left = wxMax ( m_x , rect.m_x ); + right = wxMin ( m_x+m_width, rect.m_x + rect.m_width ); + top = wxMax ( m_y , rect.m_y ); + bottom = wxMin ( m_y+m_height, rect.m_y + rect.m_height ); + + if ( left < right && top < bottom ) + { + return true; + } + return false; +} + +void wxRect2DInt::Intersect( const wxRect2DInt &src1 , const wxRect2DInt &src2 , wxRect2DInt *dest ) +{ + wxInt32 left,right,bottom,top; + left = wxMax ( src1.m_x , src2.m_x ); + right = wxMin ( src1.m_x+src1.m_width, src2.m_x + src2.m_width ); + top = wxMax ( src1.m_y , src2.m_y ); + bottom = wxMin ( src1.m_y+src1.m_height, src2.m_y + src2.m_height ); + + if ( left < right && top < bottom ) + { + dest->m_x = left; + dest->m_y = top; + dest->m_width = right - left; + dest->m_height = bottom - top; + } + else + { + dest->m_width = dest->m_height = 0; + } +} + +void wxRect2DInt::Union( const wxRect2DInt &src1 , const wxRect2DInt &src2 , wxRect2DInt *dest ) +{ + wxInt32 left,right,bottom,top; + + left = wxMin ( src1.m_x , src2.m_x ); + right = wxMax ( src1.m_x+src1.m_width, src2.m_x + src2.m_width ); + top = wxMin ( src1.m_y , src2.m_y ); + bottom = wxMax ( src1.m_y+src1.m_height, src2.m_y + src2.m_height ); + + dest->m_x = left; + dest->m_y = top; + dest->m_width = right - left; + dest->m_height = bottom - top; +} + +void wxRect2DInt::Union( const wxPoint2DInt &pt ) +{ + wxInt32 x = pt.m_x; + wxInt32 y = pt.m_y; + + if ( x < m_x ) + { + SetLeft( x ); + } + else if ( x < m_x + m_width ) + { + // contained + } + else + { + SetRight( x ); + } + + if ( y < m_y ) + { + SetTop( y ); + } + else if ( y < m_y + m_height ) + { + // contained + } + else + { + SetBottom( y ); + } +} + +void wxRect2DInt::ConstrainTo( const wxRect2DInt &rect ) +{ + if ( GetLeft() < rect.GetLeft() ) + SetLeft( rect.GetLeft() ); + + if ( GetRight() > rect.GetRight() ) + SetRight( rect.GetRight() ); + + if ( GetBottom() > rect.GetBottom() ) + SetBottom( rect.GetBottom() ); + + if ( GetTop() < rect.GetTop() ) + SetTop( rect.GetTop() ); +} + +wxRect2DInt& wxRect2DInt::operator=( const wxRect2DInt &r ) +{ + m_x = r.m_x; + m_y = r.m_y; + m_width = r.m_width; + m_height = r.m_height; + return *this; +} + +#if wxUSE_STREAMS +void wxRect2DInt::WriteTo( wxDataOutputStream &stream ) const +{ + stream.Write32( m_x ); + stream.Write32( m_y ); + stream.Write32( m_width ); + stream.Write32( m_height ); +} + +void wxRect2DInt::ReadFrom( wxDataInputStream &stream ) +{ + m_x = stream.Read32(); + m_y = stream.Read32(); + m_width = stream.Read32(); + m_height = stream.Read32(); +} +#endif // wxUSE_STREAMS + +#endif // wxUSE_GEOMETRY diff --git a/Externals/wxWidgets/src/common/gifdecod.cpp b/Externals/wxWidgets/src/common/gifdecod.cpp index f158185f02..c4555ce0b0 100644 --- a/Externals/wxWidgets/src/common/gifdecod.cpp +++ b/Externals/wxWidgets/src/common/gifdecod.cpp @@ -1,906 +1,906 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/gifdecod.cpp -// Purpose: wxGIFDecoder, GIF reader for wxImage and wxAnimation -// Author: Guillermo Rodriguez Garcia -// Version: 3.04 -// RCS-ID: $Id: gifdecod.cpp 43898 2006-12-10 14:18:37Z VZ $ -// Copyright: (c) Guillermo Rodriguez Garcia -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_STREAMS && wxUSE_GIF - -#ifndef WX_PRECOMP - #include "wx/palette.h" -#endif - -#include -#include -#include "wx/gifdecod.h" - - - -//--------------------------------------------------------------------------- -// GIFImage -//--------------------------------------------------------------------------- - -// internal class for storing GIF image data -class GIFImage -{ -public: - // def ctor - GIFImage(); - - unsigned int w; // width - unsigned int h; // height - unsigned int left; // x coord (in logical screen) - unsigned int top; // y coord (in logical screen) - int transparent; // transparent color index (-1 = none) - wxAnimationDisposal disposal; // disposal method - long delay; // delay in ms (-1 = unused) - unsigned char *p; // bitmap - unsigned char *pal; // palette - unsigned int ncolours; // number of colours - - DECLARE_NO_COPY_CLASS(GIFImage) -}; - - - -//--------------------------------------------------------------------------- -// GIFImage constructor -//--------------------------------------------------------------------------- -GIFImage::GIFImage() -{ - w = 0; - h = 0; - left = 0; - top = 0; - transparent = 0; - disposal = wxANIM_DONOTREMOVE; - delay = -1; - p = (unsigned char *) NULL; - pal = (unsigned char *) NULL; - ncolours = 0; -} - -//--------------------------------------------------------------------------- -// wxGIFDecoder constructor and destructor -//--------------------------------------------------------------------------- - -wxGIFDecoder::wxGIFDecoder() -{ -} - -wxGIFDecoder::~wxGIFDecoder() -{ - Destroy(); -} - -void wxGIFDecoder::Destroy() -{ - wxASSERT(m_nFrames==m_frames.GetCount()); - for (unsigned int i=0; ip); - free(f->pal); - delete f; - } - - m_frames.Clear(); - m_nFrames = 0; -} - - -//--------------------------------------------------------------------------- -// Convert this image to a wxImage object -//--------------------------------------------------------------------------- - -// This function was designed by Vaclav Slavik - -bool wxGIFDecoder::ConvertToImage(unsigned int frame, wxImage *image) const -{ - unsigned char *src, *dst, *pal; - unsigned long i; - int transparent; - - // just in case... - image->Destroy(); - - // create the image - wxSize sz = GetFrameSize(frame); - image->Create(sz.GetWidth(), sz.GetHeight()); - - if (!image->Ok()) - return false; - - pal = GetPalette(frame); - src = GetData(frame); - dst = image->GetData(); - transparent = GetTransparentColourIndex(frame); - - // set transparent colour mask - if (transparent != -1) - { - for (i = 0; i < GetNcolours(frame); i++) - { - if ((pal[3 * i + 0] == 255) && - (pal[3 * i + 1] == 0) && - (pal[3 * i + 2] == 255)) - { - pal[3 * i + 2] = 254; - } - } - - pal[3 * transparent + 0] = 255, - pal[3 * transparent + 1] = 0, - pal[3 * transparent + 2] = 255; - - image->SetMaskColour(255, 0, 255); - } - else - image->SetMask(false); - -#if wxUSE_PALETTE - unsigned char r[256]; - unsigned char g[256]; - unsigned char b[256]; - - for (i = 0; i < 256; i++) - { - r[i] = pal[3*i + 0]; - g[i] = pal[3*i + 1]; - b[i] = pal[3*i + 2]; - } - - image->SetPalette(wxPalette(GetNcolours(frame), r, g, b)); -#endif // wxUSE_PALETTE - - // copy image data - unsigned long npixel = sz.GetWidth() * sz.GetHeight(); - for (i = 0; i < npixel; i++, src++) - { - *(dst++) = pal[3 * (*src) + 0]; - *(dst++) = pal[3 * (*src) + 1]; - *(dst++) = pal[3 * (*src) + 2]; - } - - return true; -} - - -//--------------------------------------------------------------------------- -// Data accessors -//--------------------------------------------------------------------------- - -#define GetFrame(n) ((GIFImage*)m_frames[n]) - - -// Get data for current frame - -wxSize wxGIFDecoder::GetFrameSize(unsigned int frame) const -{ - return wxSize(GetFrame(frame)->w, GetFrame(frame)->h); -} - -wxPoint wxGIFDecoder::GetFramePosition(unsigned int frame) const -{ - return wxPoint(GetFrame(frame)->left, GetFrame(frame)->top); -} - -wxAnimationDisposal wxGIFDecoder::GetDisposalMethod(unsigned int frame) const -{ - return GetFrame(frame)->disposal; -} - -long wxGIFDecoder::GetDelay(unsigned int frame) const -{ - return GetFrame(frame)->delay; -} - -wxColour wxGIFDecoder::GetTransparentColour(unsigned int frame) const -{ - unsigned char *pal = GetFrame(frame)->pal; - int n = GetFrame(frame)->transparent; - if (n == -1) - return wxNullColour; - - return wxColour(pal[n*3 + 0], - pal[n*3 + 1], - pal[n*3 + 2]); -} - -unsigned char* wxGIFDecoder::GetData(unsigned int frame) const { return (GetFrame(frame)->p); } -unsigned char* wxGIFDecoder::GetPalette(unsigned int frame) const { return (GetFrame(frame)->pal); } -unsigned int wxGIFDecoder::GetNcolours(unsigned int frame) const { return (GetFrame(frame)->ncolours); } -int wxGIFDecoder::GetTransparentColourIndex(unsigned int frame) const { return (GetFrame(frame)->transparent); } - - - -//--------------------------------------------------------------------------- -// GIF reading and decoding -//--------------------------------------------------------------------------- - -// getcode: -// Reads the next code from the file stream, with size 'bits' -// -int wxGIFDecoder::getcode(wxInputStream& stream, int bits, int ab_fin) -{ - unsigned int mask; // bit mask - unsigned int code; // code (result) - - // get remaining bits from last byte read - mask = (1 << bits) - 1; - code = (m_lastbyte >> (8 - m_restbits)) & mask; - - // keep reading new bytes while needed - while (bits > m_restbits) - { - // if no bytes left in this block, read the next block - if (m_restbyte == 0) - { - m_restbyte = (unsigned char)stream.GetC(); - - /* Some encoders are a bit broken: instead of issuing - * an end-of-image symbol (ab_fin) they come up with - * a zero-length subblock!! We catch this here so - * that the decoder sees an ab_fin code. - */ - if (m_restbyte == 0) - { - code = ab_fin; - break; - } - - // prefetch data - stream.Read((void *) m_buffer, m_restbyte); - if (stream.LastRead() != m_restbyte) - { - code = ab_fin; - return code; - } - m_bufp = m_buffer; - } - - // read next byte and isolate the bits we need - m_lastbyte = (unsigned char) (*m_bufp++); - mask = (1 << (bits - m_restbits)) - 1; - code = code + ((m_lastbyte & mask) << m_restbits); - m_restbyte--; - - // adjust total number of bits extracted from the buffer - m_restbits = m_restbits + 8; - } - - // find number of bits remaining for next code - m_restbits = (m_restbits - bits); - - return code; -} - - -// dgif: -// GIF decoding function. The initial code size (aka root size) -// is 'bits'. Supports interlaced images (interl == 1). -// Returns wxGIF_OK (== 0) on success, or an error code if something -// fails (see header file for details) -wxGIFErrorCode -wxGIFDecoder::dgif(wxInputStream& stream, GIFImage *img, int interl, int bits) -{ - static const int allocSize = 4096 + 1; - int *ab_prefix = new int[allocSize]; // alphabet (prefixes) - if (ab_prefix == NULL) - { - return wxGIF_MEMERR; - } - - int *ab_tail = new int[allocSize]; // alphabet (tails) - if (ab_tail == NULL) - { - delete[] ab_prefix; - return wxGIF_MEMERR; - } - - int *stack = new int[allocSize]; // decompression stack - if (stack == NULL) - { - delete[] ab_prefix; - delete[] ab_tail; - return wxGIF_MEMERR; - } - - int ab_clr; // clear code - int ab_fin; // end of info code - int ab_bits; // actual symbol width, in bits - int ab_free; // first free position in alphabet - int ab_max; // last possible character in alphabet - int pass; // pass number in interlaced images - int pos; // index into decompresion stack - unsigned int x, y; // position in image buffer - - int code, readcode, lastcode, abcabca; - - // these won't change - ab_clr = (1 << bits); - ab_fin = (1 << bits) + 1; - - // these will change through the decompression proccess - ab_bits = bits + 1; - ab_free = (1 << bits) + 2; - ab_max = (1 << ab_bits) - 1; - lastcode = -1; - abcabca = -1; - pass = 1; - pos = x = y = 0; - - // reset decoder vars - m_restbits = 0; - m_restbyte = 0; - m_lastbyte = 0; - - do - { - // get next code - readcode = code = getcode(stream, ab_bits, ab_fin); - - // end of image? - if (code == ab_fin) break; - - // reset alphabet? - if (code == ab_clr) - { - // reset main variables - ab_bits = bits + 1; - ab_free = (1 << bits) + 2; - ab_max = (1 << ab_bits) - 1; - lastcode = -1; - abcabca = -1; - - // skip to next code - continue; - } - - // unknown code: special case (like in ABCABCA) - if (code >= ab_free) - { - code = lastcode; // take last string - stack[pos++] = abcabca; // add first character - } - - // build the string for this code in the stack - while (code > ab_clr) - { - stack[pos++] = ab_tail[code]; - code = ab_prefix[code]; - - // Don't overflow. This shouldn't happen with normal - // GIF files, the allocSize of 4096+1 is enough. This - // will only happen with badly formed GIFs. - if (pos >= allocSize) - { - delete[] ab_prefix; - delete[] ab_tail; - delete[] stack; - return wxGIF_INVFORMAT; - } - } - - if (pos >= allocSize) - { - delete[] ab_prefix; - delete[] ab_tail; - delete[] stack; - return wxGIF_INVFORMAT; - } - - stack[pos] = code; // push last code into the stack - abcabca = code; // save for special case - - // make new entry in alphabet (only if NOT just cleared) - if (lastcode != -1) - { - // Normally, after the alphabet is full and can't grow any - // further (ab_free == 4096), encoder should (must?) emit CLEAR - // to reset it. This checks whether we really got it, otherwise - // the GIF is damaged. - if (ab_free > ab_max) - { - delete[] ab_prefix; - delete[] ab_tail; - delete[] stack; - return wxGIF_INVFORMAT; - } - - // This assert seems unnecessary since the condition above - // eliminates the only case in which it went false. But I really - // don't like being forced to ask "Who in .text could have - // written there?!" And I wouldn't have been forced to ask if - // this line had already been here. - wxASSERT(ab_free < allocSize); - - ab_prefix[ab_free] = lastcode; - ab_tail[ab_free] = code; - ab_free++; - - if ((ab_free > ab_max) && (ab_bits < 12)) - { - ab_bits++; - ab_max = (1 << ab_bits) - 1; - } - } - - // dump stack data to the image buffer - while (pos >= 0) - { - (img->p)[x + (y * (img->w))] = (char) stack[pos]; - pos--; - - if (++x >= (img->w)) - { - x = 0; - - if (interl) - { - // support for interlaced images - switch (pass) - { - case 1: y += 8; break; - case 2: y += 8; break; - case 3: y += 4; break; - case 4: y += 2; break; - } - - /* loop until a valid y coordinate has been - found, Or if the maximum number of passes has - been reached, exit the loop, and stop image - decoding (At this point the image is successfully - decoded). - If we don't loop, but merely set y to some other - value, that new value might still be invalid depending - on the height of the image. This would cause out of - bounds writing. - */ - while (y >= (img->h)) - { - switch (++pass) - { - case 2: y = 4; break; - case 3: y = 2; break; - case 4: y = 1; break; - - default: - /* - It's possible we arrive here. For example this - happens when the image is interlaced, and the - height is 1. Looking at the above cases, the - lowest possible y is 1. While the only valid - one would be 0 for an image of height 1. So - 'eventually' the loop will arrive here. - This case makes sure this while loop is - exited, as well as the 2 other ones. - */ - - // Set y to a valid coordinate so the local - // while loop will be exited. (y = 0 always - // is >= img->h since if img->h == 0 the - // image is never decoded) - y = 0; - - // This will exit the other outer while loop - pos = -1; - - // This will halt image decoding. - code = ab_fin; - - break; - } - } - } - else - { - // non-interlaced - y++; -/* -Normally image decoding is finished when an End of Information code is -encountered (code == ab_fin) however some broken encoders write wrong -"block byte counts" (The first byte value after the "code size" byte), -being one value too high. It might very well be possible other variants -of this problem occur as well. The only sensible solution seems to -be to check for clipping. -Example of wrong encoding: -(1 * 1 B/W image, raster data stream follows in hex bytes) - -02 << B/W images have a code size of 2 -02 << Block byte count -44 << LZW packed -00 << Zero byte count (terminates data stream) - -Because the block byte count is 2, the zero byte count is used in the -decoding process, and decoding is continued after this byte. (While it -should signal an end of image) - -It should be: -02 -02 -44 -01 << When decoded this correctly includes the End of Information code -00 - -Or (Worse solution): -02 -01 -44 -00 -(The 44 doesn't include an End of Information code, but at least the -decoder correctly skips to 00 now after decoding, and signals this -as an End of Information itself) -*/ - if (y >= img->h) - { - code = ab_fin; - break; - } - } - } - } - - pos = 0; - lastcode = readcode; - } - while (code != ab_fin); - - delete [] ab_prefix ; - delete [] ab_tail ; - delete [] stack ; - - return wxGIF_OK; -} - - -// CanRead: -// Returns true if the file looks like a valid GIF, false otherwise. -// -bool wxGIFDecoder::CanRead(wxInputStream &stream) const -{ - unsigned char buf[3]; - - if ( !stream.Read(buf, WXSIZEOF(buf)) ) - return false; - - stream.SeekI(-(wxFileOffset)WXSIZEOF(buf), wxFromCurrent); - - return memcmp(buf, "GIF", WXSIZEOF(buf)) == 0; -} - - -// LoadGIF: -// Reads and decodes one or more GIF images, depending on whether -// animated GIF support is enabled. Can read GIFs with any bit -// size (color depth), but the output images are always expanded -// to 8 bits per pixel. Also, the image palettes always contain -// 256 colors, although some of them may be unused. Returns wxGIF_OK -// (== 0) on success, or an error code if something fails (see -// header file for details) -// -wxGIFErrorCode wxGIFDecoder::LoadGIF(wxInputStream& stream) -{ - unsigned int global_ncolors = 0; - int bits, interl, transparent, i; - wxAnimationDisposal disposal; - long size; - long delay; - unsigned char type = 0; - unsigned char pal[768]; - unsigned char buf[16]; - bool anim = true; - - // check GIF signature - if (!CanRead(stream)) - return wxGIF_INVFORMAT; - - // check for animated GIF support (ver. >= 89a) - - static const unsigned int headerSize = (3 + 3); - stream.Read(buf, headerSize); - if (stream.LastRead() != headerSize) - { - return wxGIF_INVFORMAT; - } - - if (memcmp(buf + 3, "89a", 3) < 0) - { - anim = false; - } - - // read logical screen descriptor block (LSDB) - static const unsigned int lsdbSize = (2 + 2 + 1 + 1 + 1); - stream.Read(buf, lsdbSize); - if (stream.LastRead() != lsdbSize) - { - return wxGIF_INVFORMAT; - } - - m_szAnimation.SetWidth( buf[0] + 256 * buf[1] ); - m_szAnimation.SetHeight( buf[2] + 256 * buf[3] ); - - if (anim && ((m_szAnimation.GetWidth() == 0) || (m_szAnimation.GetHeight() == 0))) - { - return wxGIF_INVFORMAT; - } - - // load global color map if available - if ((buf[4] & 0x80) == 0x80) - { - int backgroundColIndex = buf[5]; - - global_ncolors = 2 << (buf[4] & 0x07); - unsigned int numBytes = 3 * global_ncolors; - stream.Read(pal, numBytes); - if (stream.LastRead() != numBytes) - { - return wxGIF_INVFORMAT; - } - - m_background.Set(pal[backgroundColIndex*3 + 0], - pal[backgroundColIndex*3 + 1], - pal[backgroundColIndex*3 + 2]); - } - - // transparent colour, disposal method and delay default to unused - transparent = -1; - disposal = wxANIM_UNSPECIFIED; - delay = -1; - - bool done = false; - while (!done) - { - type = (unsigned char)stream.GetC(); - - /* - If the end of file has been reached (or an error) and a ";" - (0x3B) hasn't been encountered yet, exit the loop. (Without this - check the while loop would loop endlessly.) Later on, in the next while - loop, the file will be treated as being truncated (But still - be decoded as far as possible). returning wxGIF_TRUNCATED is not - possible here since some init code is done after this loop. - */ - if (stream.Eof())// || !stream.IsOk()) - { - /* - type is set to some bogus value, so there's no - need to continue evaluating it. - */ - break; // Alternative : "return wxGIF_INVFORMAT;" - } - - // end of data? - if (type == 0x3B) - { - done = true; - } - else - // extension block? - if (type == 0x21) - { - if (((unsigned char)stream.GetC()) == 0xF9) - // graphics control extension, parse it - { - static const unsigned int gceSize = 6; - stream.Read(buf, gceSize); - if (stream.LastRead() != gceSize) - { - Destroy(); - return wxGIF_INVFORMAT; - } - - // read delay and convert from 1/100 of a second to ms - delay = 10 * (buf[2] + 256 * buf[3]); - - // read transparent colour index, if used - if (buf[1] & 0x01) - transparent = buf[4]; - - // read disposal method - disposal = (wxAnimationDisposal)(((buf[1] & 0x1C) >> 2) - 1); - } - else - // other extension, skip - { - while ((i = (unsigned char)stream.GetC()) != 0) - { - if (stream.Eof() || (stream.LastRead() == 0)) - { - done = true; - break; - } - stream.SeekI(i, wxFromCurrent); - } - } - } - else - // image descriptor block? - if (type == 0x2C) - { - // allocate memory for IMAGEN struct - GIFImage *pimg = new GIFImage(); - - if (pimg == NULL) - { - Destroy(); - return wxGIF_MEMERR; - } - - // fill in the data - static const unsigned int idbSize = (2 + 2 + 2 + 2 + 1); - stream.Read(buf, idbSize); - if (stream.LastRead() != idbSize) - { - Destroy(); - return wxGIF_INVFORMAT; - } - - pimg->left = buf[0] + 256 * buf[1]; - pimg->top = buf[2] + 256 * buf[3]; -/* - pimg->left = buf[4] + 256 * buf[5]; - pimg->top = buf[4] + 256 * buf[5]; -*/ - pimg->w = buf[4] + 256 * buf[5]; - pimg->h = buf[6] + 256 * buf[7]; - - if (anim && ((pimg->w == 0) || (pimg->w > (unsigned int)m_szAnimation.GetWidth()) || - (pimg->h == 0) || (pimg->h > (unsigned int)m_szAnimation.GetHeight()))) - { - Destroy(); - return wxGIF_INVFORMAT; - } - - interl = ((buf[8] & 0x40)? 1 : 0); - size = pimg->w * pimg->h; - - pimg->transparent = transparent; - pimg->disposal = disposal; - pimg->delay = delay; - - // allocate memory for image and palette - pimg->p = (unsigned char *) malloc((unsigned int)size); - pimg->pal = (unsigned char *) malloc(768); - - if ((!pimg->p) || (!pimg->pal)) - { - Destroy(); - return wxGIF_MEMERR; - } - - // load local color map if available, else use global map - if ((buf[8] & 0x80) == 0x80) - { - unsigned int local_ncolors = 2 << (buf[8] & 0x07); - unsigned int numBytes = 3 * local_ncolors; - stream.Read(pimg->pal, numBytes); - pimg->ncolours = local_ncolors; - if (stream.LastRead() != numBytes) - { - Destroy(); - return wxGIF_INVFORMAT; - } - } - else - { - memcpy(pimg->pal, pal, 768); - pimg->ncolours = global_ncolors; - } - - // get initial code size from first byte in raster data - bits = (unsigned char)stream.GetC(); - if (bits == 0) - { - Destroy(); - return wxGIF_INVFORMAT; - } - - // decode image - wxGIFErrorCode result = dgif(stream, pimg, interl, bits); - if (result != wxGIF_OK) - { - Destroy(); - return result; - } - - // add the image to our frame array - m_frames.Add((void*)pimg); - m_nFrames++; - - // if this is not an animated GIF, exit after first image - if (!anim) - done = true; - } - } - - if (m_nFrames <= 0) - { - Destroy(); - return wxGIF_INVFORMAT; - } - - // try to read to the end of the stream - while (type != 0x3B) - { - if (!stream.IsOk()) - return wxGIF_TRUNCATED; - - type = (unsigned char)stream.GetC(); - - if (type == 0x21) - { - // extension type - (void) stream.GetC(); - - // skip all data - while ((i = (unsigned char)stream.GetC()) != 0) - { - if (stream.Eof() || (stream.LastRead() == 0)) - { - Destroy(); - return wxGIF_INVFORMAT; - } - stream.SeekI(i, wxFromCurrent); - } - } - else if (type == 0x2C) - { - // image descriptor block - static const unsigned int idbSize = (2 + 2 + 2 + 2 + 1); - stream.Read(buf, idbSize); - if (stream.LastRead() != idbSize) - { - Destroy(); - return wxGIF_INVFORMAT; - } - - // local color map - if ((buf[8] & 0x80) == 0x80) - { - unsigned int local_ncolors = 2 << (buf[8] & 0x07); - wxFileOffset numBytes = 3 * local_ncolors; - stream.SeekI(numBytes, wxFromCurrent); - } - - // initial code size - (void) stream.GetC(); - if (stream.Eof() || (stream.LastRead() == 0)) - { - Destroy(); - return wxGIF_INVFORMAT; - } - - // skip all data - while ((i = (unsigned char)stream.GetC()) != 0) - { - if (stream.Eof() || (stream.LastRead() == 0)) - { - Destroy(); - return wxGIF_INVFORMAT; - } - stream.SeekI(i, wxFromCurrent); - } - } - else if ((type != 0x3B) && (type != 00)) // testing - { - // images are OK, but couldn't read to the end of the stream - return wxGIF_TRUNCATED; - } - } - - return wxGIF_OK; -} - -#endif // wxUSE_STREAMS && wxUSE_GIF +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/gifdecod.cpp +// Purpose: wxGIFDecoder, GIF reader for wxImage and wxAnimation +// Author: Guillermo Rodriguez Garcia +// Version: 3.04 +// RCS-ID: $Id: gifdecod.cpp 43898 2006-12-10 14:18:37Z VZ $ +// Copyright: (c) Guillermo Rodriguez Garcia +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_STREAMS && wxUSE_GIF + +#ifndef WX_PRECOMP + #include "wx/palette.h" +#endif + +#include +#include +#include "wx/gifdecod.h" + + + +//--------------------------------------------------------------------------- +// GIFImage +//--------------------------------------------------------------------------- + +// internal class for storing GIF image data +class GIFImage +{ +public: + // def ctor + GIFImage(); + + unsigned int w; // width + unsigned int h; // height + unsigned int left; // x coord (in logical screen) + unsigned int top; // y coord (in logical screen) + int transparent; // transparent color index (-1 = none) + wxAnimationDisposal disposal; // disposal method + long delay; // delay in ms (-1 = unused) + unsigned char *p; // bitmap + unsigned char *pal; // palette + unsigned int ncolours; // number of colours + + DECLARE_NO_COPY_CLASS(GIFImage) +}; + + + +//--------------------------------------------------------------------------- +// GIFImage constructor +//--------------------------------------------------------------------------- +GIFImage::GIFImage() +{ + w = 0; + h = 0; + left = 0; + top = 0; + transparent = 0; + disposal = wxANIM_DONOTREMOVE; + delay = -1; + p = (unsigned char *) NULL; + pal = (unsigned char *) NULL; + ncolours = 0; +} + +//--------------------------------------------------------------------------- +// wxGIFDecoder constructor and destructor +//--------------------------------------------------------------------------- + +wxGIFDecoder::wxGIFDecoder() +{ +} + +wxGIFDecoder::~wxGIFDecoder() +{ + Destroy(); +} + +void wxGIFDecoder::Destroy() +{ + wxASSERT(m_nFrames==m_frames.GetCount()); + for (unsigned int i=0; ip); + free(f->pal); + delete f; + } + + m_frames.Clear(); + m_nFrames = 0; +} + + +//--------------------------------------------------------------------------- +// Convert this image to a wxImage object +//--------------------------------------------------------------------------- + +// This function was designed by Vaclav Slavik + +bool wxGIFDecoder::ConvertToImage(unsigned int frame, wxImage *image) const +{ + unsigned char *src, *dst, *pal; + unsigned long i; + int transparent; + + // just in case... + image->Destroy(); + + // create the image + wxSize sz = GetFrameSize(frame); + image->Create(sz.GetWidth(), sz.GetHeight()); + + if (!image->Ok()) + return false; + + pal = GetPalette(frame); + src = GetData(frame); + dst = image->GetData(); + transparent = GetTransparentColourIndex(frame); + + // set transparent colour mask + if (transparent != -1) + { + for (i = 0; i < GetNcolours(frame); i++) + { + if ((pal[3 * i + 0] == 255) && + (pal[3 * i + 1] == 0) && + (pal[3 * i + 2] == 255)) + { + pal[3 * i + 2] = 254; + } + } + + pal[3 * transparent + 0] = 255, + pal[3 * transparent + 1] = 0, + pal[3 * transparent + 2] = 255; + + image->SetMaskColour(255, 0, 255); + } + else + image->SetMask(false); + +#if wxUSE_PALETTE + unsigned char r[256]; + unsigned char g[256]; + unsigned char b[256]; + + for (i = 0; i < 256; i++) + { + r[i] = pal[3*i + 0]; + g[i] = pal[3*i + 1]; + b[i] = pal[3*i + 2]; + } + + image->SetPalette(wxPalette(GetNcolours(frame), r, g, b)); +#endif // wxUSE_PALETTE + + // copy image data + unsigned long npixel = sz.GetWidth() * sz.GetHeight(); + for (i = 0; i < npixel; i++, src++) + { + *(dst++) = pal[3 * (*src) + 0]; + *(dst++) = pal[3 * (*src) + 1]; + *(dst++) = pal[3 * (*src) + 2]; + } + + return true; +} + + +//--------------------------------------------------------------------------- +// Data accessors +//--------------------------------------------------------------------------- + +#define GetFrame(n) ((GIFImage*)m_frames[n]) + + +// Get data for current frame + +wxSize wxGIFDecoder::GetFrameSize(unsigned int frame) const +{ + return wxSize(GetFrame(frame)->w, GetFrame(frame)->h); +} + +wxPoint wxGIFDecoder::GetFramePosition(unsigned int frame) const +{ + return wxPoint(GetFrame(frame)->left, GetFrame(frame)->top); +} + +wxAnimationDisposal wxGIFDecoder::GetDisposalMethod(unsigned int frame) const +{ + return GetFrame(frame)->disposal; +} + +long wxGIFDecoder::GetDelay(unsigned int frame) const +{ + return GetFrame(frame)->delay; +} + +wxColour wxGIFDecoder::GetTransparentColour(unsigned int frame) const +{ + unsigned char *pal = GetFrame(frame)->pal; + int n = GetFrame(frame)->transparent; + if (n == -1) + return wxNullColour; + + return wxColour(pal[n*3 + 0], + pal[n*3 + 1], + pal[n*3 + 2]); +} + +unsigned char* wxGIFDecoder::GetData(unsigned int frame) const { return (GetFrame(frame)->p); } +unsigned char* wxGIFDecoder::GetPalette(unsigned int frame) const { return (GetFrame(frame)->pal); } +unsigned int wxGIFDecoder::GetNcolours(unsigned int frame) const { return (GetFrame(frame)->ncolours); } +int wxGIFDecoder::GetTransparentColourIndex(unsigned int frame) const { return (GetFrame(frame)->transparent); } + + + +//--------------------------------------------------------------------------- +// GIF reading and decoding +//--------------------------------------------------------------------------- + +// getcode: +// Reads the next code from the file stream, with size 'bits' +// +int wxGIFDecoder::getcode(wxInputStream& stream, int bits, int ab_fin) +{ + unsigned int mask; // bit mask + unsigned int code; // code (result) + + // get remaining bits from last byte read + mask = (1 << bits) - 1; + code = (m_lastbyte >> (8 - m_restbits)) & mask; + + // keep reading new bytes while needed + while (bits > m_restbits) + { + // if no bytes left in this block, read the next block + if (m_restbyte == 0) + { + m_restbyte = (unsigned char)stream.GetC(); + + /* Some encoders are a bit broken: instead of issuing + * an end-of-image symbol (ab_fin) they come up with + * a zero-length subblock!! We catch this here so + * that the decoder sees an ab_fin code. + */ + if (m_restbyte == 0) + { + code = ab_fin; + break; + } + + // prefetch data + stream.Read((void *) m_buffer, m_restbyte); + if (stream.LastRead() != m_restbyte) + { + code = ab_fin; + return code; + } + m_bufp = m_buffer; + } + + // read next byte and isolate the bits we need + m_lastbyte = (unsigned char) (*m_bufp++); + mask = (1 << (bits - m_restbits)) - 1; + code = code + ((m_lastbyte & mask) << m_restbits); + m_restbyte--; + + // adjust total number of bits extracted from the buffer + m_restbits = m_restbits + 8; + } + + // find number of bits remaining for next code + m_restbits = (m_restbits - bits); + + return code; +} + + +// dgif: +// GIF decoding function. The initial code size (aka root size) +// is 'bits'. Supports interlaced images (interl == 1). +// Returns wxGIF_OK (== 0) on success, or an error code if something +// fails (see header file for details) +wxGIFErrorCode +wxGIFDecoder::dgif(wxInputStream& stream, GIFImage *img, int interl, int bits) +{ + static const int allocSize = 4096 + 1; + int *ab_prefix = new int[allocSize]; // alphabet (prefixes) + if (ab_prefix == NULL) + { + return wxGIF_MEMERR; + } + + int *ab_tail = new int[allocSize]; // alphabet (tails) + if (ab_tail == NULL) + { + delete[] ab_prefix; + return wxGIF_MEMERR; + } + + int *stack = new int[allocSize]; // decompression stack + if (stack == NULL) + { + delete[] ab_prefix; + delete[] ab_tail; + return wxGIF_MEMERR; + } + + int ab_clr; // clear code + int ab_fin; // end of info code + int ab_bits; // actual symbol width, in bits + int ab_free; // first free position in alphabet + int ab_max; // last possible character in alphabet + int pass; // pass number in interlaced images + int pos; // index into decompresion stack + unsigned int x, y; // position in image buffer + + int code, readcode, lastcode, abcabca; + + // these won't change + ab_clr = (1 << bits); + ab_fin = (1 << bits) + 1; + + // these will change through the decompression proccess + ab_bits = bits + 1; + ab_free = (1 << bits) + 2; + ab_max = (1 << ab_bits) - 1; + lastcode = -1; + abcabca = -1; + pass = 1; + pos = x = y = 0; + + // reset decoder vars + m_restbits = 0; + m_restbyte = 0; + m_lastbyte = 0; + + do + { + // get next code + readcode = code = getcode(stream, ab_bits, ab_fin); + + // end of image? + if (code == ab_fin) break; + + // reset alphabet? + if (code == ab_clr) + { + // reset main variables + ab_bits = bits + 1; + ab_free = (1 << bits) + 2; + ab_max = (1 << ab_bits) - 1; + lastcode = -1; + abcabca = -1; + + // skip to next code + continue; + } + + // unknown code: special case (like in ABCABCA) + if (code >= ab_free) + { + code = lastcode; // take last string + stack[pos++] = abcabca; // add first character + } + + // build the string for this code in the stack + while (code > ab_clr) + { + stack[pos++] = ab_tail[code]; + code = ab_prefix[code]; + + // Don't overflow. This shouldn't happen with normal + // GIF files, the allocSize of 4096+1 is enough. This + // will only happen with badly formed GIFs. + if (pos >= allocSize) + { + delete[] ab_prefix; + delete[] ab_tail; + delete[] stack; + return wxGIF_INVFORMAT; + } + } + + if (pos >= allocSize) + { + delete[] ab_prefix; + delete[] ab_tail; + delete[] stack; + return wxGIF_INVFORMAT; + } + + stack[pos] = code; // push last code into the stack + abcabca = code; // save for special case + + // make new entry in alphabet (only if NOT just cleared) + if (lastcode != -1) + { + // Normally, after the alphabet is full and can't grow any + // further (ab_free == 4096), encoder should (must?) emit CLEAR + // to reset it. This checks whether we really got it, otherwise + // the GIF is damaged. + if (ab_free > ab_max) + { + delete[] ab_prefix; + delete[] ab_tail; + delete[] stack; + return wxGIF_INVFORMAT; + } + + // This assert seems unnecessary since the condition above + // eliminates the only case in which it went false. But I really + // don't like being forced to ask "Who in .text could have + // written there?!" And I wouldn't have been forced to ask if + // this line had already been here. + wxASSERT(ab_free < allocSize); + + ab_prefix[ab_free] = lastcode; + ab_tail[ab_free] = code; + ab_free++; + + if ((ab_free > ab_max) && (ab_bits < 12)) + { + ab_bits++; + ab_max = (1 << ab_bits) - 1; + } + } + + // dump stack data to the image buffer + while (pos >= 0) + { + (img->p)[x + (y * (img->w))] = (char) stack[pos]; + pos--; + + if (++x >= (img->w)) + { + x = 0; + + if (interl) + { + // support for interlaced images + switch (pass) + { + case 1: y += 8; break; + case 2: y += 8; break; + case 3: y += 4; break; + case 4: y += 2; break; + } + + /* loop until a valid y coordinate has been + found, Or if the maximum number of passes has + been reached, exit the loop, and stop image + decoding (At this point the image is successfully + decoded). + If we don't loop, but merely set y to some other + value, that new value might still be invalid depending + on the height of the image. This would cause out of + bounds writing. + */ + while (y >= (img->h)) + { + switch (++pass) + { + case 2: y = 4; break; + case 3: y = 2; break; + case 4: y = 1; break; + + default: + /* + It's possible we arrive here. For example this + happens when the image is interlaced, and the + height is 1. Looking at the above cases, the + lowest possible y is 1. While the only valid + one would be 0 for an image of height 1. So + 'eventually' the loop will arrive here. + This case makes sure this while loop is + exited, as well as the 2 other ones. + */ + + // Set y to a valid coordinate so the local + // while loop will be exited. (y = 0 always + // is >= img->h since if img->h == 0 the + // image is never decoded) + y = 0; + + // This will exit the other outer while loop + pos = -1; + + // This will halt image decoding. + code = ab_fin; + + break; + } + } + } + else + { + // non-interlaced + y++; +/* +Normally image decoding is finished when an End of Information code is +encountered (code == ab_fin) however some broken encoders write wrong +"block byte counts" (The first byte value after the "code size" byte), +being one value too high. It might very well be possible other variants +of this problem occur as well. The only sensible solution seems to +be to check for clipping. +Example of wrong encoding: +(1 * 1 B/W image, raster data stream follows in hex bytes) + +02 << B/W images have a code size of 2 +02 << Block byte count +44 << LZW packed +00 << Zero byte count (terminates data stream) + +Because the block byte count is 2, the zero byte count is used in the +decoding process, and decoding is continued after this byte. (While it +should signal an end of image) + +It should be: +02 +02 +44 +01 << When decoded this correctly includes the End of Information code +00 + +Or (Worse solution): +02 +01 +44 +00 +(The 44 doesn't include an End of Information code, but at least the +decoder correctly skips to 00 now after decoding, and signals this +as an End of Information itself) +*/ + if (y >= img->h) + { + code = ab_fin; + break; + } + } + } + } + + pos = 0; + lastcode = readcode; + } + while (code != ab_fin); + + delete [] ab_prefix ; + delete [] ab_tail ; + delete [] stack ; + + return wxGIF_OK; +} + + +// CanRead: +// Returns true if the file looks like a valid GIF, false otherwise. +// +bool wxGIFDecoder::CanRead(wxInputStream &stream) const +{ + unsigned char buf[3]; + + if ( !stream.Read(buf, WXSIZEOF(buf)) ) + return false; + + stream.SeekI(-(wxFileOffset)WXSIZEOF(buf), wxFromCurrent); + + return memcmp(buf, "GIF", WXSIZEOF(buf)) == 0; +} + + +// LoadGIF: +// Reads and decodes one or more GIF images, depending on whether +// animated GIF support is enabled. Can read GIFs with any bit +// size (color depth), but the output images are always expanded +// to 8 bits per pixel. Also, the image palettes always contain +// 256 colors, although some of them may be unused. Returns wxGIF_OK +// (== 0) on success, or an error code if something fails (see +// header file for details) +// +wxGIFErrorCode wxGIFDecoder::LoadGIF(wxInputStream& stream) +{ + unsigned int global_ncolors = 0; + int bits, interl, transparent, i; + wxAnimationDisposal disposal; + long size; + long delay; + unsigned char type = 0; + unsigned char pal[768]; + unsigned char buf[16]; + bool anim = true; + + // check GIF signature + if (!CanRead(stream)) + return wxGIF_INVFORMAT; + + // check for animated GIF support (ver. >= 89a) + + static const unsigned int headerSize = (3 + 3); + stream.Read(buf, headerSize); + if (stream.LastRead() != headerSize) + { + return wxGIF_INVFORMAT; + } + + if (memcmp(buf + 3, "89a", 3) < 0) + { + anim = false; + } + + // read logical screen descriptor block (LSDB) + static const unsigned int lsdbSize = (2 + 2 + 1 + 1 + 1); + stream.Read(buf, lsdbSize); + if (stream.LastRead() != lsdbSize) + { + return wxGIF_INVFORMAT; + } + + m_szAnimation.SetWidth( buf[0] + 256 * buf[1] ); + m_szAnimation.SetHeight( buf[2] + 256 * buf[3] ); + + if (anim && ((m_szAnimation.GetWidth() == 0) || (m_szAnimation.GetHeight() == 0))) + { + return wxGIF_INVFORMAT; + } + + // load global color map if available + if ((buf[4] & 0x80) == 0x80) + { + int backgroundColIndex = buf[5]; + + global_ncolors = 2 << (buf[4] & 0x07); + unsigned int numBytes = 3 * global_ncolors; + stream.Read(pal, numBytes); + if (stream.LastRead() != numBytes) + { + return wxGIF_INVFORMAT; + } + + m_background.Set(pal[backgroundColIndex*3 + 0], + pal[backgroundColIndex*3 + 1], + pal[backgroundColIndex*3 + 2]); + } + + // transparent colour, disposal method and delay default to unused + transparent = -1; + disposal = wxANIM_UNSPECIFIED; + delay = -1; + + bool done = false; + while (!done) + { + type = (unsigned char)stream.GetC(); + + /* + If the end of file has been reached (or an error) and a ";" + (0x3B) hasn't been encountered yet, exit the loop. (Without this + check the while loop would loop endlessly.) Later on, in the next while + loop, the file will be treated as being truncated (But still + be decoded as far as possible). returning wxGIF_TRUNCATED is not + possible here since some init code is done after this loop. + */ + if (stream.Eof())// || !stream.IsOk()) + { + /* + type is set to some bogus value, so there's no + need to continue evaluating it. + */ + break; // Alternative : "return wxGIF_INVFORMAT;" + } + + // end of data? + if (type == 0x3B) + { + done = true; + } + else + // extension block? + if (type == 0x21) + { + if (((unsigned char)stream.GetC()) == 0xF9) + // graphics control extension, parse it + { + static const unsigned int gceSize = 6; + stream.Read(buf, gceSize); + if (stream.LastRead() != gceSize) + { + Destroy(); + return wxGIF_INVFORMAT; + } + + // read delay and convert from 1/100 of a second to ms + delay = 10 * (buf[2] + 256 * buf[3]); + + // read transparent colour index, if used + if (buf[1] & 0x01) + transparent = buf[4]; + + // read disposal method + disposal = (wxAnimationDisposal)(((buf[1] & 0x1C) >> 2) - 1); + } + else + // other extension, skip + { + while ((i = (unsigned char)stream.GetC()) != 0) + { + if (stream.Eof() || (stream.LastRead() == 0)) + { + done = true; + break; + } + stream.SeekI(i, wxFromCurrent); + } + } + } + else + // image descriptor block? + if (type == 0x2C) + { + // allocate memory for IMAGEN struct + GIFImage *pimg = new GIFImage(); + + if (pimg == NULL) + { + Destroy(); + return wxGIF_MEMERR; + } + + // fill in the data + static const unsigned int idbSize = (2 + 2 + 2 + 2 + 1); + stream.Read(buf, idbSize); + if (stream.LastRead() != idbSize) + { + Destroy(); + return wxGIF_INVFORMAT; + } + + pimg->left = buf[0] + 256 * buf[1]; + pimg->top = buf[2] + 256 * buf[3]; +/* + pimg->left = buf[4] + 256 * buf[5]; + pimg->top = buf[4] + 256 * buf[5]; +*/ + pimg->w = buf[4] + 256 * buf[5]; + pimg->h = buf[6] + 256 * buf[7]; + + if (anim && ((pimg->w == 0) || (pimg->w > (unsigned int)m_szAnimation.GetWidth()) || + (pimg->h == 0) || (pimg->h > (unsigned int)m_szAnimation.GetHeight()))) + { + Destroy(); + return wxGIF_INVFORMAT; + } + + interl = ((buf[8] & 0x40)? 1 : 0); + size = pimg->w * pimg->h; + + pimg->transparent = transparent; + pimg->disposal = disposal; + pimg->delay = delay; + + // allocate memory for image and palette + pimg->p = (unsigned char *) malloc((unsigned int)size); + pimg->pal = (unsigned char *) malloc(768); + + if ((!pimg->p) || (!pimg->pal)) + { + Destroy(); + return wxGIF_MEMERR; + } + + // load local color map if available, else use global map + if ((buf[8] & 0x80) == 0x80) + { + unsigned int local_ncolors = 2 << (buf[8] & 0x07); + unsigned int numBytes = 3 * local_ncolors; + stream.Read(pimg->pal, numBytes); + pimg->ncolours = local_ncolors; + if (stream.LastRead() != numBytes) + { + Destroy(); + return wxGIF_INVFORMAT; + } + } + else + { + memcpy(pimg->pal, pal, 768); + pimg->ncolours = global_ncolors; + } + + // get initial code size from first byte in raster data + bits = (unsigned char)stream.GetC(); + if (bits == 0) + { + Destroy(); + return wxGIF_INVFORMAT; + } + + // decode image + wxGIFErrorCode result = dgif(stream, pimg, interl, bits); + if (result != wxGIF_OK) + { + Destroy(); + return result; + } + + // add the image to our frame array + m_frames.Add((void*)pimg); + m_nFrames++; + + // if this is not an animated GIF, exit after first image + if (!anim) + done = true; + } + } + + if (m_nFrames <= 0) + { + Destroy(); + return wxGIF_INVFORMAT; + } + + // try to read to the end of the stream + while (type != 0x3B) + { + if (!stream.IsOk()) + return wxGIF_TRUNCATED; + + type = (unsigned char)stream.GetC(); + + if (type == 0x21) + { + // extension type + (void) stream.GetC(); + + // skip all data + while ((i = (unsigned char)stream.GetC()) != 0) + { + if (stream.Eof() || (stream.LastRead() == 0)) + { + Destroy(); + return wxGIF_INVFORMAT; + } + stream.SeekI(i, wxFromCurrent); + } + } + else if (type == 0x2C) + { + // image descriptor block + static const unsigned int idbSize = (2 + 2 + 2 + 2 + 1); + stream.Read(buf, idbSize); + if (stream.LastRead() != idbSize) + { + Destroy(); + return wxGIF_INVFORMAT; + } + + // local color map + if ((buf[8] & 0x80) == 0x80) + { + unsigned int local_ncolors = 2 << (buf[8] & 0x07); + wxFileOffset numBytes = 3 * local_ncolors; + stream.SeekI(numBytes, wxFromCurrent); + } + + // initial code size + (void) stream.GetC(); + if (stream.Eof() || (stream.LastRead() == 0)) + { + Destroy(); + return wxGIF_INVFORMAT; + } + + // skip all data + while ((i = (unsigned char)stream.GetC()) != 0) + { + if (stream.Eof() || (stream.LastRead() == 0)) + { + Destroy(); + return wxGIF_INVFORMAT; + } + stream.SeekI(i, wxFromCurrent); + } + } + else if ((type != 0x3B) && (type != 00)) // testing + { + // images are OK, but couldn't read to the end of the stream + return wxGIF_TRUNCATED; + } + } + + return wxGIF_OK; +} + +#endif // wxUSE_STREAMS && wxUSE_GIF diff --git a/Externals/wxWidgets/src/common/graphcmn.cpp b/Externals/wxWidgets/src/common/graphcmn.cpp index 368026025d..d0b4c10760 100644 --- a/Externals/wxWidgets/src/common/graphcmn.cpp +++ b/Externals/wxWidgets/src/common/graphcmn.cpp @@ -1,769 +1,769 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/graphcmn.cpp -// Purpose: graphics context methods common to all platforms -// Author: Stefan Csomor -// Modified by: -// Created: -// RCS-ID: $Id: graphcmn.cpp 49287 2007-10-21 11:52:54Z SC $ -// Copyright: (c) Stefan Csomor -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#if defined(__BORLANDC__) - #pragma hdrstop -#endif - -#if wxUSE_GRAPHICS_CONTEXT - -#include "wx/graphics.h" - -#ifndef WX_PRECOMP - #include "wx/icon.h" - #include "wx/bitmap.h" - #include "wx/dcmemory.h" - #include "wx/region.h" - #include "wx/log.h" -#endif - -#if !defined(wxMAC_USE_CORE_GRAPHICS_BLEND_MODES) -#define wxMAC_USE_CORE_GRAPHICS_BLEND_MODES 0 -#endif - -//----------------------------------------------------------------------------- -// constants -//----------------------------------------------------------------------------- - -static const double RAD2DEG = 180.0 / M_PI; - -//----------------------------------------------------------------------------- -// Local functions -//----------------------------------------------------------------------------- - -static inline double DegToRad(double deg) -{ - return (deg * M_PI) / 180.0; -} - -//----------------------------------------------------------------------------- - -//----------------------------------------------------------------------------- -// wxGraphicsObject -//----------------------------------------------------------------------------- - -IMPLEMENT_DYNAMIC_CLASS(wxGraphicsObject, wxObject) - -wxGraphicsObjectRefData::wxGraphicsObjectRefData( wxGraphicsRenderer* renderer ) -{ - m_renderer = renderer; -} -wxGraphicsObjectRefData::wxGraphicsObjectRefData( const wxGraphicsObjectRefData* data ) -{ - m_renderer = data->m_renderer; -} -wxGraphicsRenderer* wxGraphicsObjectRefData::GetRenderer() const -{ - return m_renderer ; -} - -wxGraphicsObjectRefData* wxGraphicsObjectRefData::Clone() const -{ - return new wxGraphicsObjectRefData(this); -} - -wxGraphicsObject::wxGraphicsObject() -{ -} - -wxGraphicsObject::wxGraphicsObject( wxGraphicsRenderer* renderer ) -{ - SetRefData( new wxGraphicsObjectRefData(renderer)); -} - -wxGraphicsObject::~wxGraphicsObject() -{ -} - -bool wxGraphicsObject::IsNull() const -{ - return m_refData == NULL; -} - -wxGraphicsRenderer* wxGraphicsObject::GetRenderer() const -{ - return ( IsNull() ? NULL : GetGraphicsData()->GetRenderer() ); -} - -wxGraphicsObjectRefData* wxGraphicsObject::GetGraphicsData() const -{ - return (wxGraphicsObjectRefData*) m_refData; -} - -wxObjectRefData* wxGraphicsObject::CreateRefData() const -{ - wxLogDebug(wxT("A Null Object cannot be changed")); - return NULL; -} - -wxObjectRefData* wxGraphicsObject::CloneRefData(const wxObjectRefData* data) const -{ - const wxGraphicsObjectRefData* ptr = (const wxGraphicsObjectRefData*) data; - return ptr->Clone(); -} - -//----------------------------------------------------------------------------- -// pens etc. -//----------------------------------------------------------------------------- - -IMPLEMENT_DYNAMIC_CLASS(wxGraphicsPen, wxGraphicsObject) -IMPLEMENT_DYNAMIC_CLASS(wxGraphicsBrush, wxGraphicsObject) -IMPLEMENT_DYNAMIC_CLASS(wxGraphicsFont, wxGraphicsObject) - -WXDLLIMPEXP_DATA_CORE(wxGraphicsPen) wxNullGraphicsPen; -WXDLLIMPEXP_DATA_CORE(wxGraphicsBrush) wxNullGraphicsBrush; -WXDLLIMPEXP_DATA_CORE(wxGraphicsFont) wxNullGraphicsFont; - -//----------------------------------------------------------------------------- -// matrix -//----------------------------------------------------------------------------- - -IMPLEMENT_DYNAMIC_CLASS(wxGraphicsMatrix, wxGraphicsObject) -WXDLLIMPEXP_DATA_CORE(wxGraphicsMatrix) wxNullGraphicsMatrix; - -// concatenates the matrix -void wxGraphicsMatrix::Concat( const wxGraphicsMatrix *t ) -{ - AllocExclusive(); - GetMatrixData()->Concat(t->GetMatrixData()); -} - -// sets the matrix to the respective values -void wxGraphicsMatrix::Set(wxDouble a, wxDouble b, wxDouble c, wxDouble d, - wxDouble tx, wxDouble ty) -{ - AllocExclusive(); - GetMatrixData()->Set(a,b,c,d,tx,ty); -} - -// gets the component valuess of the matrix -void wxGraphicsMatrix::Get(wxDouble* a, wxDouble* b, wxDouble* c, - wxDouble* d, wxDouble* tx, wxDouble* ty) const -{ - GetMatrixData()->Get(a, b, c, d, tx, ty); -} - -// makes this the inverse matrix -void wxGraphicsMatrix::Invert() -{ - AllocExclusive(); - GetMatrixData()->Invert(); -} - -// returns true if the elements of the transformation matrix are equal ? -bool wxGraphicsMatrix::IsEqual( const wxGraphicsMatrix* t) const -{ - return GetMatrixData()->IsEqual(t->GetMatrixData()); -} - -// return true if this is the identity matrix -bool wxGraphicsMatrix::IsIdentity() const -{ - return GetMatrixData()->IsIdentity(); -} - -// add the translation to this matrix -void wxGraphicsMatrix::Translate( wxDouble dx , wxDouble dy ) -{ - AllocExclusive(); - GetMatrixData()->Translate(dx,dy); -} - -// add the scale to this matrix -void wxGraphicsMatrix::Scale( wxDouble xScale , wxDouble yScale ) -{ - AllocExclusive(); - GetMatrixData()->Scale(xScale,yScale); -} - -// add the rotation to this matrix (radians) -void wxGraphicsMatrix::Rotate( wxDouble angle ) -{ - AllocExclusive(); - GetMatrixData()->Rotate(angle); -} - -// -// apply the transforms -// - -// applies that matrix to the point -void wxGraphicsMatrix::TransformPoint( wxDouble *x, wxDouble *y ) const -{ - GetMatrixData()->TransformPoint(x,y); -} - -// applies the matrix except for translations -void wxGraphicsMatrix::TransformDistance( wxDouble *dx, wxDouble *dy ) const -{ - GetMatrixData()->TransformDistance(dx,dy); -} - -// returns the native representation -void * wxGraphicsMatrix::GetNativeMatrix() const -{ - return GetMatrixData()->GetNativeMatrix(); -} - -//----------------------------------------------------------------------------- -// path -//----------------------------------------------------------------------------- - -IMPLEMENT_DYNAMIC_CLASS(wxGraphicsPath, wxGraphicsObject) -WXDLLIMPEXP_DATA_CORE(wxGraphicsPath) wxNullGraphicsPath; - -// convenience functions, for using wxPoint2DDouble etc - -wxPoint2DDouble wxGraphicsPath::GetCurrentPoint() const -{ - wxDouble x,y; - GetCurrentPoint(&x,&y); - return wxPoint2DDouble(x,y); -} - -void wxGraphicsPath::MoveToPoint( const wxPoint2DDouble& p) -{ - MoveToPoint( p.m_x , p.m_y); -} - -void wxGraphicsPath::AddLineToPoint( const wxPoint2DDouble& p) -{ - AddLineToPoint( p.m_x , p.m_y); -} - -void wxGraphicsPath::AddCurveToPoint( const wxPoint2DDouble& c1, const wxPoint2DDouble& c2, const wxPoint2DDouble& e) -{ - AddCurveToPoint(c1.m_x, c1.m_y, c2.m_x, c2.m_y, e.m_x, e.m_y); -} - -void wxGraphicsPath::AddArc( const wxPoint2DDouble& c, wxDouble r, wxDouble startAngle, wxDouble endAngle, bool clockwise) -{ - AddArc(c.m_x, c.m_y, r, startAngle, endAngle, clockwise); -} - -wxRect2DDouble wxGraphicsPath::GetBox() const -{ - wxDouble x,y,w,h; - GetBox(&x,&y,&w,&h); - return wxRect2DDouble( x,y,w,h ); -} - -bool wxGraphicsPath::Contains( const wxPoint2DDouble& c, int fillStyle ) const -{ - return Contains( c.m_x, c.m_y, fillStyle); -} - -// true redirections - -// begins a new subpath at (x,y) -void wxGraphicsPath::MoveToPoint( wxDouble x, wxDouble y ) -{ - AllocExclusive(); - GetPathData()->MoveToPoint(x,y); -} - -// adds a straight line from the current point to (x,y) -void wxGraphicsPath::AddLineToPoint( wxDouble x, wxDouble y ) -{ - AllocExclusive(); - GetPathData()->AddLineToPoint(x,y); -} - -// adds a cubic Bezier curve from the current point, using two control points and an end point -void wxGraphicsPath::AddCurveToPoint( wxDouble cx1, wxDouble cy1, wxDouble cx2, wxDouble cy2, wxDouble x, wxDouble y ) -{ - AllocExclusive(); - GetPathData()->AddCurveToPoint(cx1,cy1,cx2,cy2,x,y); -} - -// adds another path -void wxGraphicsPath::AddPath( const wxGraphicsPath& path ) -{ - AllocExclusive(); - GetPathData()->AddPath(path.GetPathData()); -} - -// closes the current sub-path -void wxGraphicsPath::CloseSubpath() -{ - AllocExclusive(); - GetPathData()->CloseSubpath(); -} - -// gets the last point of the current path, (0,0) if not yet set -void wxGraphicsPath::GetCurrentPoint( wxDouble* x, wxDouble* y) const -{ - GetPathData()->GetCurrentPoint(x,y); -} - -// adds an arc of a circle centering at (x,y) with radius (r) from startAngle to endAngle -void wxGraphicsPath::AddArc( wxDouble x, wxDouble y, wxDouble r, wxDouble startAngle, wxDouble endAngle, bool clockwise ) -{ - AllocExclusive(); - GetPathData()->AddArc(x,y,r,startAngle,endAngle,clockwise); -} - -// -// These are convenience functions which - if not available natively will be assembled -// using the primitives from above -// - -// adds a quadratic Bezier curve from the current point, using a control point and an end point -void wxGraphicsPath::AddQuadCurveToPoint( wxDouble cx, wxDouble cy, wxDouble x, wxDouble y ) -{ - AllocExclusive(); - GetPathData()->AddQuadCurveToPoint(cx,cy,x,y); -} - -// appends a rectangle as a new closed subpath -void wxGraphicsPath::AddRectangle( wxDouble x, wxDouble y, wxDouble w, wxDouble h ) -{ - AllocExclusive(); - GetPathData()->AddRectangle(x,y,w,h); -} - -// appends an ellipsis as a new closed subpath fitting the passed rectangle -void wxGraphicsPath::AddCircle( wxDouble x, wxDouble y, wxDouble r ) -{ - AllocExclusive(); - GetPathData()->AddCircle(x,y,r); -} - -// appends a an arc to two tangents connecting (current) to (x1,y1) and (x1,y1) to (x2,y2), also a straight line from (current) to (x1,y1) -void wxGraphicsPath::AddArcToPoint( wxDouble x1, wxDouble y1 , wxDouble x2, wxDouble y2, wxDouble r ) -{ - GetPathData()->AddArcToPoint(x1,y1,x2,y2,r); -} - -// appends an ellipse -void wxGraphicsPath::AddEllipse( wxDouble x, wxDouble y, wxDouble w, wxDouble h) -{ - AllocExclusive(); - GetPathData()->AddEllipse(x,y,w,h); -} - -// appends a rounded rectangle -void wxGraphicsPath::AddRoundedRectangle( wxDouble x, wxDouble y, wxDouble w, wxDouble h, wxDouble radius) -{ - AllocExclusive(); - GetPathData()->AddRoundedRectangle(x,y,w,h,radius); -} - -// returns the native path -void * wxGraphicsPath::GetNativePath() const -{ - return GetPathData()->GetNativePath(); -} - -// give the native path returned by GetNativePath() back (there might be some deallocations necessary) -void wxGraphicsPath::UnGetNativePath(void *p)const -{ - GetPathData()->UnGetNativePath(p); -} - -// transforms each point of this path by the matrix -void wxGraphicsPath::Transform( const wxGraphicsMatrix& matrix ) -{ - AllocExclusive(); - GetPathData()->Transform(matrix.GetMatrixData()); -} - -// gets the bounding box enclosing all points (possibly including control points) -void wxGraphicsPath::GetBox(wxDouble *x, wxDouble *y, wxDouble *w, wxDouble *h) const -{ - GetPathData()->GetBox(x,y,w,h); -} - -bool wxGraphicsPath::Contains( wxDouble x, wxDouble y, int fillStyle ) const -{ - return GetPathData()->Contains(x,y,fillStyle); -} - -// -// Emulations, these mus be implemented in the ...Data classes in order to allow for proper overrides -// - -void wxGraphicsPathData::AddQuadCurveToPoint( wxDouble cx, wxDouble cy, wxDouble x, wxDouble y ) -{ - // calculate using degree elevation to a cubic bezier - wxPoint2DDouble c1; - wxPoint2DDouble c2; - - wxPoint2DDouble start; - GetCurrentPoint(&start.m_x,&start.m_y); - wxPoint2DDouble end(x,y); - wxPoint2DDouble c(cx,cy); - c1 = wxDouble(1/3.0) * start + wxDouble(2/3.0) * c; - c2 = wxDouble(2/3.0) * c + wxDouble(1/3.0) * end; - AddCurveToPoint(c1.m_x,c1.m_y,c2.m_x,c2.m_y,x,y); -} - -void wxGraphicsPathData::AddRectangle( wxDouble x, wxDouble y, wxDouble w, wxDouble h ) -{ - MoveToPoint(x,y); - AddLineToPoint(x,y+h); - AddLineToPoint(x+w,y+h); - AddLineToPoint(x+w,y); - CloseSubpath(); -} - -void wxGraphicsPathData::AddCircle( wxDouble x, wxDouble y, wxDouble r ) -{ - MoveToPoint(x+r,y); - AddArc( x,y,r,0,2*M_PI,false); - CloseSubpath(); -} - -void wxGraphicsPathData::AddEllipse( wxDouble x, wxDouble y, wxDouble w, wxDouble h) -{ - wxDouble rw = w/2; - wxDouble rh = h/2; - wxDouble xc = x + rw; - wxDouble yc = y + rh; - wxGraphicsMatrix m = GetRenderer()->CreateMatrix(); - m.Translate(xc,yc); - m.Scale(rw/rh,1.0); - wxGraphicsPath p = GetRenderer()->CreatePath(); - p.AddCircle(0,0,rh); - p.Transform(m); - AddPath(p.GetPathData()); -} - -void wxGraphicsPathData::AddRoundedRectangle( wxDouble x, wxDouble y, wxDouble w, wxDouble h, wxDouble radius) -{ - if ( radius == 0 ) - AddRectangle(x,y,w,h); - else - { - MoveToPoint( x + w, y + h / 2); - AddArcToPoint(x + w, y + h, x + w / 2, y + h, radius); - AddArcToPoint(x, y + h, x, y + h / 2, radius); - AddArcToPoint(x, y , x + w / 2, y, radius); - AddArcToPoint(x + w, y, x + w, y + h / 2, radius); - CloseSubpath(); - } -} - -// draws a an arc to two tangents connecting (current) to (x1,y1) and (x1,y1) to (x2,y2), also a straight line from (current) to (x1,y1) -void wxGraphicsPathData::AddArcToPoint( wxDouble x1, wxDouble y1 , wxDouble x2, wxDouble y2, wxDouble r ) -{ - wxPoint2DDouble current; - GetCurrentPoint(¤t.m_x,¤t.m_y); - wxPoint2DDouble p1(x1,y1); - wxPoint2DDouble p2(x2,y2); - - wxPoint2DDouble v1 = current - p1; - v1.Normalize(); - wxPoint2DDouble v2 = p2 - p1; - v2.Normalize(); - - wxDouble alpha = v1.GetVectorAngle() - v2.GetVectorAngle(); - - if ( alpha < 0 ) - alpha = 360 + alpha; - // TODO obtuse angles - - alpha = DegToRad(alpha); - - wxDouble dist = r / sin(alpha/2) * cos(alpha/2); - // calculate tangential points - wxPoint2DDouble t1 = dist*v1 + p1; - wxPoint2DDouble t2 = dist*v2 + p1; - - wxPoint2DDouble nv1 = v1; - nv1.SetVectorAngle(v1.GetVectorAngle()-90); - wxPoint2DDouble c = t1 + r*nv1; - - wxDouble a1 = v1.GetVectorAngle()+90; - wxDouble a2 = v2.GetVectorAngle()-90; - - AddLineToPoint(t1.m_x,t1.m_y); - AddArc(c.m_x,c.m_y,r,DegToRad(a1),DegToRad(a2),true); - AddLineToPoint(p2.m_x,p2.m_y); -} - -//----------------------------------------------------------------------------- -// wxGraphicsContext Convenience Methods -//----------------------------------------------------------------------------- - -IMPLEMENT_ABSTRACT_CLASS(wxGraphicsContext, wxObject) - - -wxGraphicsContext::wxGraphicsContext(wxGraphicsRenderer* renderer) : wxGraphicsObject(renderer) -{ - m_logicalFunction = wxCOPY; -} - -wxGraphicsContext::~wxGraphicsContext() -{ -} - -// sets the pen -void wxGraphicsContext::SetPen( const wxGraphicsPen& pen ) -{ - m_pen = pen; -} - -void wxGraphicsContext::SetPen( const wxPen& pen ) -{ - if ( !pen.Ok() || pen.GetStyle() == wxTRANSPARENT ) - SetPen( wxNullGraphicsPen ); - else - SetPen( CreatePen( pen ) ); -} - -// sets the brush for filling -void wxGraphicsContext::SetBrush( const wxGraphicsBrush& brush ) -{ - m_brush = brush; -} - -void wxGraphicsContext::SetBrush( const wxBrush& brush ) -{ - if ( !brush.Ok() || brush.GetStyle() == wxTRANSPARENT ) - SetBrush( wxNullGraphicsBrush ); - else - SetBrush( CreateBrush( brush ) ); -} - -// sets the brush for filling -void wxGraphicsContext::SetFont( const wxGraphicsFont& font ) -{ - m_font = font; -} - -bool wxGraphicsContext::SetLogicalFunction( int function ) -{ - if ( function == wxCOPY ) - { - m_logicalFunction = function; - return true; - } - return false; -} - -void wxGraphicsContext::SetFont( const wxFont& font, const wxColour& colour ) -{ - if ( font.Ok() ) - SetFont( CreateFont( font, colour ) ); - else - SetFont( wxNullGraphicsFont ); -} - -void wxGraphicsContext::DrawPath( const wxGraphicsPath& path, int fillStyle ) -{ - FillPath( path , fillStyle ); - StrokePath( path ); -} - -void wxGraphicsContext::DrawText( const wxString &str, wxDouble x, wxDouble y, wxDouble angle ) -{ - Translate(x,y); - Rotate( -angle ); - DrawText( str , 0, 0 ); - Rotate( angle ); - Translate(-x,-y); -} - -void wxGraphicsContext::DrawText( const wxString &str, wxDouble x, wxDouble y, const wxGraphicsBrush& backgroundBrush ) -{ - wxGraphicsBrush formerBrush = m_brush; - wxGraphicsPen formerPen = m_pen; - wxDouble width; - wxDouble height; - wxDouble descent; - wxDouble externalLeading; - GetTextExtent( str , &width, &height, &descent, &externalLeading ); - SetBrush( backgroundBrush ); - // to make sure our 'OffsetToPixelBoundaries' doesn't move the fill shape - SetPen( wxNullGraphicsPen ); - - wxGraphicsPath path = CreatePath(); - path.AddRectangle( x , y, width, height ); - FillPath( path ); - - DrawText( str, x ,y); - SetBrush( formerBrush ); - SetPen( formerPen ); -} - -void wxGraphicsContext::DrawText( const wxString &str, wxDouble x, wxDouble y, wxDouble angle, const wxGraphicsBrush& backgroundBrush ) -{ - wxGraphicsBrush formerBrush = m_brush; - wxGraphicsPen formerPen = m_pen; - - wxDouble width; - wxDouble height; - wxDouble descent; - wxDouble externalLeading; - GetTextExtent( str , &width, &height, &descent, &externalLeading ); - SetBrush( backgroundBrush ); - // to make sure our 'OffsetToPixelBoundaries' doesn't move the fill shape - SetPen( wxNullGraphicsPen ); - - wxGraphicsPath path = CreatePath(); - path.MoveToPoint( x , y ); - path.AddLineToPoint( (int) (x + sin(angle) * height) , (int) (y + cos(angle) * height) ); - path.AddLineToPoint( - (int) (x + sin(angle) * height + cos(angle) * width) , - (int) (y + cos(angle) * height - sin(angle) * width)); - path.AddLineToPoint((int) (x + cos(angle) * width) , (int) (y - sin(angle) * width) ); - FillPath( path ); - DrawText( str, x ,y, angle); - SetBrush( formerBrush ); - SetPen( formerPen ); -} - -void wxGraphicsContext::StrokeLine( wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2) -{ - wxGraphicsPath path = CreatePath(); - path.MoveToPoint(x1, y1); - path.AddLineToPoint( x2, y2 ); - StrokePath( path ); -} - -void wxGraphicsContext::DrawRectangle( wxDouble x, wxDouble y, wxDouble w, wxDouble h) -{ - wxGraphicsPath path = CreatePath(); - path.AddRectangle( x , y , w , h ); - DrawPath( path ); -} - -void wxGraphicsContext::DrawEllipse( wxDouble x, wxDouble y, wxDouble w, wxDouble h) -{ - wxGraphicsPath path = CreatePath(); - path.AddEllipse(x,y,w,h); - DrawPath(path); -} - -void wxGraphicsContext::DrawRoundedRectangle( wxDouble x, wxDouble y, wxDouble w, wxDouble h, wxDouble radius) -{ - wxGraphicsPath path = CreatePath(); - path.AddRoundedRectangle(x,y,w,h,radius); - DrawPath(path); -} - -void wxGraphicsContext::StrokeLines( size_t n, const wxPoint2DDouble *points) -{ - wxASSERT(n > 1); - wxGraphicsPath path = CreatePath(); - path.MoveToPoint(points[0].m_x, points[0].m_y); - for ( size_t i = 1; i < n; ++i) - path.AddLineToPoint( points[i].m_x, points[i].m_y ); - StrokePath( path ); -} - -void wxGraphicsContext::DrawLines( size_t n, const wxPoint2DDouble *points, int fillStyle) -{ - wxASSERT(n > 1); - wxGraphicsPath path = CreatePath(); - path.MoveToPoint(points[0].m_x, points[0].m_y); - for ( size_t i = 1; i < n; ++i) - path.AddLineToPoint( points[i].m_x, points[i].m_y ); - DrawPath( path , fillStyle); -} - -void wxGraphicsContext::StrokeLines( size_t n, const wxPoint2DDouble *beginPoints, const wxPoint2DDouble *endPoints) -{ - wxASSERT(n > 0); - wxGraphicsPath path = CreatePath(); - for ( size_t i = 0; i < n; ++i) - { - path.MoveToPoint(beginPoints[i].m_x, beginPoints[i].m_y); - path.AddLineToPoint( endPoints[i].m_x, endPoints[i].m_y ); - } - StrokePath( path ); -} - -// create a 'native' matrix corresponding to these values -wxGraphicsMatrix wxGraphicsContext::CreateMatrix( wxDouble a, wxDouble b, wxDouble c, wxDouble d, - wxDouble tx, wxDouble ty) const -{ - return GetRenderer()->CreateMatrix(a,b,c,d,tx,ty); -} - -wxGraphicsPath wxGraphicsContext::CreatePath() const -{ - return GetRenderer()->CreatePath(); -} - -wxGraphicsPen wxGraphicsContext::CreatePen(const wxPen& pen) const -{ - return GetRenderer()->CreatePen(pen); -} - -wxGraphicsBrush wxGraphicsContext::CreateBrush(const wxBrush& brush ) const -{ - return GetRenderer()->CreateBrush(brush); -} - -// sets the brush to a linear gradient, starting at (x1,y1) with color c1 to (x2,y2) with color c2 -wxGraphicsBrush wxGraphicsContext::CreateLinearGradientBrush( wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2, - const wxColour&c1, const wxColour&c2) const -{ - return GetRenderer()->CreateLinearGradientBrush(x1,y1,x2,y2,c1,c2); -} - -// sets the brush to a radial gradient originating at (xo,yc) with color oColor and ends on a circle around (xc,yc) -// with radius r and color cColor -wxGraphicsBrush wxGraphicsContext::CreateRadialGradientBrush( wxDouble xo, wxDouble yo, wxDouble xc, wxDouble yc, wxDouble radius, - const wxColour &oColor, const wxColour &cColor) const -{ - return GetRenderer()->CreateRadialGradientBrush(xo,yo,xc,yc,radius,oColor,cColor); -} - -// sets the font -wxGraphicsFont wxGraphicsContext::CreateFont( const wxFont &font , const wxColour &col ) const -{ - return GetRenderer()->CreateFont(font,col); -} - -wxGraphicsContext* wxGraphicsContext::Create( const wxWindowDC& dc) -{ - return wxGraphicsRenderer::GetDefaultRenderer()->CreateContext(dc); -} -#ifdef __WXMSW__ -wxGraphicsContext* wxGraphicsContext::Create( const wxMemoryDC& dc) -{ - return wxGraphicsRenderer::GetDefaultRenderer()->CreateContext(dc); -} -#endif - -wxGraphicsContext* wxGraphicsContext::CreateFromNative( void * context ) -{ - return wxGraphicsRenderer::GetDefaultRenderer()->CreateContextFromNativeContext(context); -} - -wxGraphicsContext* wxGraphicsContext::CreateFromNativeWindow( void * window ) -{ - return wxGraphicsRenderer::GetDefaultRenderer()->CreateContextFromNativeWindow(window); -} - -wxGraphicsContext* wxGraphicsContext::Create( wxWindow* window ) -{ - return wxGraphicsRenderer::GetDefaultRenderer()->CreateContext(window); -} - -wxGraphicsContext* wxGraphicsContext::Create() -{ - return wxGraphicsRenderer::GetDefaultRenderer()->CreateMeasuringContext(); -} - -//----------------------------------------------------------------------------- -// wxGraphicsRenderer -//----------------------------------------------------------------------------- - -IMPLEMENT_ABSTRACT_CLASS(wxGraphicsRenderer, wxObject) - -#endif // wxUSE_GRAPHICS_CONTEXT +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/graphcmn.cpp +// Purpose: graphics context methods common to all platforms +// Author: Stefan Csomor +// Modified by: +// Created: +// RCS-ID: $Id: graphcmn.cpp 49287 2007-10-21 11:52:54Z SC $ +// Copyright: (c) Stefan Csomor +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#if defined(__BORLANDC__) + #pragma hdrstop +#endif + +#if wxUSE_GRAPHICS_CONTEXT + +#include "wx/graphics.h" + +#ifndef WX_PRECOMP + #include "wx/icon.h" + #include "wx/bitmap.h" + #include "wx/dcmemory.h" + #include "wx/region.h" + #include "wx/log.h" +#endif + +#if !defined(wxMAC_USE_CORE_GRAPHICS_BLEND_MODES) +#define wxMAC_USE_CORE_GRAPHICS_BLEND_MODES 0 +#endif + +//----------------------------------------------------------------------------- +// constants +//----------------------------------------------------------------------------- + +static const double RAD2DEG = 180.0 / M_PI; + +//----------------------------------------------------------------------------- +// Local functions +//----------------------------------------------------------------------------- + +static inline double DegToRad(double deg) +{ + return (deg * M_PI) / 180.0; +} + +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// wxGraphicsObject +//----------------------------------------------------------------------------- + +IMPLEMENT_DYNAMIC_CLASS(wxGraphicsObject, wxObject) + +wxGraphicsObjectRefData::wxGraphicsObjectRefData( wxGraphicsRenderer* renderer ) +{ + m_renderer = renderer; +} +wxGraphicsObjectRefData::wxGraphicsObjectRefData( const wxGraphicsObjectRefData* data ) +{ + m_renderer = data->m_renderer; +} +wxGraphicsRenderer* wxGraphicsObjectRefData::GetRenderer() const +{ + return m_renderer ; +} + +wxGraphicsObjectRefData* wxGraphicsObjectRefData::Clone() const +{ + return new wxGraphicsObjectRefData(this); +} + +wxGraphicsObject::wxGraphicsObject() +{ +} + +wxGraphicsObject::wxGraphicsObject( wxGraphicsRenderer* renderer ) +{ + SetRefData( new wxGraphicsObjectRefData(renderer)); +} + +wxGraphicsObject::~wxGraphicsObject() +{ +} + +bool wxGraphicsObject::IsNull() const +{ + return m_refData == NULL; +} + +wxGraphicsRenderer* wxGraphicsObject::GetRenderer() const +{ + return ( IsNull() ? NULL : GetGraphicsData()->GetRenderer() ); +} + +wxGraphicsObjectRefData* wxGraphicsObject::GetGraphicsData() const +{ + return (wxGraphicsObjectRefData*) m_refData; +} + +wxObjectRefData* wxGraphicsObject::CreateRefData() const +{ + wxLogDebug(wxT("A Null Object cannot be changed")); + return NULL; +} + +wxObjectRefData* wxGraphicsObject::CloneRefData(const wxObjectRefData* data) const +{ + const wxGraphicsObjectRefData* ptr = (const wxGraphicsObjectRefData*) data; + return ptr->Clone(); +} + +//----------------------------------------------------------------------------- +// pens etc. +//----------------------------------------------------------------------------- + +IMPLEMENT_DYNAMIC_CLASS(wxGraphicsPen, wxGraphicsObject) +IMPLEMENT_DYNAMIC_CLASS(wxGraphicsBrush, wxGraphicsObject) +IMPLEMENT_DYNAMIC_CLASS(wxGraphicsFont, wxGraphicsObject) + +WXDLLIMPEXP_DATA_CORE(wxGraphicsPen) wxNullGraphicsPen; +WXDLLIMPEXP_DATA_CORE(wxGraphicsBrush) wxNullGraphicsBrush; +WXDLLIMPEXP_DATA_CORE(wxGraphicsFont) wxNullGraphicsFont; + +//----------------------------------------------------------------------------- +// matrix +//----------------------------------------------------------------------------- + +IMPLEMENT_DYNAMIC_CLASS(wxGraphicsMatrix, wxGraphicsObject) +WXDLLIMPEXP_DATA_CORE(wxGraphicsMatrix) wxNullGraphicsMatrix; + +// concatenates the matrix +void wxGraphicsMatrix::Concat( const wxGraphicsMatrix *t ) +{ + AllocExclusive(); + GetMatrixData()->Concat(t->GetMatrixData()); +} + +// sets the matrix to the respective values +void wxGraphicsMatrix::Set(wxDouble a, wxDouble b, wxDouble c, wxDouble d, + wxDouble tx, wxDouble ty) +{ + AllocExclusive(); + GetMatrixData()->Set(a,b,c,d,tx,ty); +} + +// gets the component valuess of the matrix +void wxGraphicsMatrix::Get(wxDouble* a, wxDouble* b, wxDouble* c, + wxDouble* d, wxDouble* tx, wxDouble* ty) const +{ + GetMatrixData()->Get(a, b, c, d, tx, ty); +} + +// makes this the inverse matrix +void wxGraphicsMatrix::Invert() +{ + AllocExclusive(); + GetMatrixData()->Invert(); +} + +// returns true if the elements of the transformation matrix are equal ? +bool wxGraphicsMatrix::IsEqual( const wxGraphicsMatrix* t) const +{ + return GetMatrixData()->IsEqual(t->GetMatrixData()); +} + +// return true if this is the identity matrix +bool wxGraphicsMatrix::IsIdentity() const +{ + return GetMatrixData()->IsIdentity(); +} + +// add the translation to this matrix +void wxGraphicsMatrix::Translate( wxDouble dx , wxDouble dy ) +{ + AllocExclusive(); + GetMatrixData()->Translate(dx,dy); +} + +// add the scale to this matrix +void wxGraphicsMatrix::Scale( wxDouble xScale , wxDouble yScale ) +{ + AllocExclusive(); + GetMatrixData()->Scale(xScale,yScale); +} + +// add the rotation to this matrix (radians) +void wxGraphicsMatrix::Rotate( wxDouble angle ) +{ + AllocExclusive(); + GetMatrixData()->Rotate(angle); +} + +// +// apply the transforms +// + +// applies that matrix to the point +void wxGraphicsMatrix::TransformPoint( wxDouble *x, wxDouble *y ) const +{ + GetMatrixData()->TransformPoint(x,y); +} + +// applies the matrix except for translations +void wxGraphicsMatrix::TransformDistance( wxDouble *dx, wxDouble *dy ) const +{ + GetMatrixData()->TransformDistance(dx,dy); +} + +// returns the native representation +void * wxGraphicsMatrix::GetNativeMatrix() const +{ + return GetMatrixData()->GetNativeMatrix(); +} + +//----------------------------------------------------------------------------- +// path +//----------------------------------------------------------------------------- + +IMPLEMENT_DYNAMIC_CLASS(wxGraphicsPath, wxGraphicsObject) +WXDLLIMPEXP_DATA_CORE(wxGraphicsPath) wxNullGraphicsPath; + +// convenience functions, for using wxPoint2DDouble etc + +wxPoint2DDouble wxGraphicsPath::GetCurrentPoint() const +{ + wxDouble x,y; + GetCurrentPoint(&x,&y); + return wxPoint2DDouble(x,y); +} + +void wxGraphicsPath::MoveToPoint( const wxPoint2DDouble& p) +{ + MoveToPoint( p.m_x , p.m_y); +} + +void wxGraphicsPath::AddLineToPoint( const wxPoint2DDouble& p) +{ + AddLineToPoint( p.m_x , p.m_y); +} + +void wxGraphicsPath::AddCurveToPoint( const wxPoint2DDouble& c1, const wxPoint2DDouble& c2, const wxPoint2DDouble& e) +{ + AddCurveToPoint(c1.m_x, c1.m_y, c2.m_x, c2.m_y, e.m_x, e.m_y); +} + +void wxGraphicsPath::AddArc( const wxPoint2DDouble& c, wxDouble r, wxDouble startAngle, wxDouble endAngle, bool clockwise) +{ + AddArc(c.m_x, c.m_y, r, startAngle, endAngle, clockwise); +} + +wxRect2DDouble wxGraphicsPath::GetBox() const +{ + wxDouble x,y,w,h; + GetBox(&x,&y,&w,&h); + return wxRect2DDouble( x,y,w,h ); +} + +bool wxGraphicsPath::Contains( const wxPoint2DDouble& c, int fillStyle ) const +{ + return Contains( c.m_x, c.m_y, fillStyle); +} + +// true redirections + +// begins a new subpath at (x,y) +void wxGraphicsPath::MoveToPoint( wxDouble x, wxDouble y ) +{ + AllocExclusive(); + GetPathData()->MoveToPoint(x,y); +} + +// adds a straight line from the current point to (x,y) +void wxGraphicsPath::AddLineToPoint( wxDouble x, wxDouble y ) +{ + AllocExclusive(); + GetPathData()->AddLineToPoint(x,y); +} + +// adds a cubic Bezier curve from the current point, using two control points and an end point +void wxGraphicsPath::AddCurveToPoint( wxDouble cx1, wxDouble cy1, wxDouble cx2, wxDouble cy2, wxDouble x, wxDouble y ) +{ + AllocExclusive(); + GetPathData()->AddCurveToPoint(cx1,cy1,cx2,cy2,x,y); +} + +// adds another path +void wxGraphicsPath::AddPath( const wxGraphicsPath& path ) +{ + AllocExclusive(); + GetPathData()->AddPath(path.GetPathData()); +} + +// closes the current sub-path +void wxGraphicsPath::CloseSubpath() +{ + AllocExclusive(); + GetPathData()->CloseSubpath(); +} + +// gets the last point of the current path, (0,0) if not yet set +void wxGraphicsPath::GetCurrentPoint( wxDouble* x, wxDouble* y) const +{ + GetPathData()->GetCurrentPoint(x,y); +} + +// adds an arc of a circle centering at (x,y) with radius (r) from startAngle to endAngle +void wxGraphicsPath::AddArc( wxDouble x, wxDouble y, wxDouble r, wxDouble startAngle, wxDouble endAngle, bool clockwise ) +{ + AllocExclusive(); + GetPathData()->AddArc(x,y,r,startAngle,endAngle,clockwise); +} + +// +// These are convenience functions which - if not available natively will be assembled +// using the primitives from above +// + +// adds a quadratic Bezier curve from the current point, using a control point and an end point +void wxGraphicsPath::AddQuadCurveToPoint( wxDouble cx, wxDouble cy, wxDouble x, wxDouble y ) +{ + AllocExclusive(); + GetPathData()->AddQuadCurveToPoint(cx,cy,x,y); +} + +// appends a rectangle as a new closed subpath +void wxGraphicsPath::AddRectangle( wxDouble x, wxDouble y, wxDouble w, wxDouble h ) +{ + AllocExclusive(); + GetPathData()->AddRectangle(x,y,w,h); +} + +// appends an ellipsis as a new closed subpath fitting the passed rectangle +void wxGraphicsPath::AddCircle( wxDouble x, wxDouble y, wxDouble r ) +{ + AllocExclusive(); + GetPathData()->AddCircle(x,y,r); +} + +// appends a an arc to two tangents connecting (current) to (x1,y1) and (x1,y1) to (x2,y2), also a straight line from (current) to (x1,y1) +void wxGraphicsPath::AddArcToPoint( wxDouble x1, wxDouble y1 , wxDouble x2, wxDouble y2, wxDouble r ) +{ + GetPathData()->AddArcToPoint(x1,y1,x2,y2,r); +} + +// appends an ellipse +void wxGraphicsPath::AddEllipse( wxDouble x, wxDouble y, wxDouble w, wxDouble h) +{ + AllocExclusive(); + GetPathData()->AddEllipse(x,y,w,h); +} + +// appends a rounded rectangle +void wxGraphicsPath::AddRoundedRectangle( wxDouble x, wxDouble y, wxDouble w, wxDouble h, wxDouble radius) +{ + AllocExclusive(); + GetPathData()->AddRoundedRectangle(x,y,w,h,radius); +} + +// returns the native path +void * wxGraphicsPath::GetNativePath() const +{ + return GetPathData()->GetNativePath(); +} + +// give the native path returned by GetNativePath() back (there might be some deallocations necessary) +void wxGraphicsPath::UnGetNativePath(void *p)const +{ + GetPathData()->UnGetNativePath(p); +} + +// transforms each point of this path by the matrix +void wxGraphicsPath::Transform( const wxGraphicsMatrix& matrix ) +{ + AllocExclusive(); + GetPathData()->Transform(matrix.GetMatrixData()); +} + +// gets the bounding box enclosing all points (possibly including control points) +void wxGraphicsPath::GetBox(wxDouble *x, wxDouble *y, wxDouble *w, wxDouble *h) const +{ + GetPathData()->GetBox(x,y,w,h); +} + +bool wxGraphicsPath::Contains( wxDouble x, wxDouble y, int fillStyle ) const +{ + return GetPathData()->Contains(x,y,fillStyle); +} + +// +// Emulations, these mus be implemented in the ...Data classes in order to allow for proper overrides +// + +void wxGraphicsPathData::AddQuadCurveToPoint( wxDouble cx, wxDouble cy, wxDouble x, wxDouble y ) +{ + // calculate using degree elevation to a cubic bezier + wxPoint2DDouble c1; + wxPoint2DDouble c2; + + wxPoint2DDouble start; + GetCurrentPoint(&start.m_x,&start.m_y); + wxPoint2DDouble end(x,y); + wxPoint2DDouble c(cx,cy); + c1 = wxDouble(1/3.0) * start + wxDouble(2/3.0) * c; + c2 = wxDouble(2/3.0) * c + wxDouble(1/3.0) * end; + AddCurveToPoint(c1.m_x,c1.m_y,c2.m_x,c2.m_y,x,y); +} + +void wxGraphicsPathData::AddRectangle( wxDouble x, wxDouble y, wxDouble w, wxDouble h ) +{ + MoveToPoint(x,y); + AddLineToPoint(x,y+h); + AddLineToPoint(x+w,y+h); + AddLineToPoint(x+w,y); + CloseSubpath(); +} + +void wxGraphicsPathData::AddCircle( wxDouble x, wxDouble y, wxDouble r ) +{ + MoveToPoint(x+r,y); + AddArc( x,y,r,0,2*M_PI,false); + CloseSubpath(); +} + +void wxGraphicsPathData::AddEllipse( wxDouble x, wxDouble y, wxDouble w, wxDouble h) +{ + wxDouble rw = w/2; + wxDouble rh = h/2; + wxDouble xc = x + rw; + wxDouble yc = y + rh; + wxGraphicsMatrix m = GetRenderer()->CreateMatrix(); + m.Translate(xc,yc); + m.Scale(rw/rh,1.0); + wxGraphicsPath p = GetRenderer()->CreatePath(); + p.AddCircle(0,0,rh); + p.Transform(m); + AddPath(p.GetPathData()); +} + +void wxGraphicsPathData::AddRoundedRectangle( wxDouble x, wxDouble y, wxDouble w, wxDouble h, wxDouble radius) +{ + if ( radius == 0 ) + AddRectangle(x,y,w,h); + else + { + MoveToPoint( x + w, y + h / 2); + AddArcToPoint(x + w, y + h, x + w / 2, y + h, radius); + AddArcToPoint(x, y + h, x, y + h / 2, radius); + AddArcToPoint(x, y , x + w / 2, y, radius); + AddArcToPoint(x + w, y, x + w, y + h / 2, radius); + CloseSubpath(); + } +} + +// draws a an arc to two tangents connecting (current) to (x1,y1) and (x1,y1) to (x2,y2), also a straight line from (current) to (x1,y1) +void wxGraphicsPathData::AddArcToPoint( wxDouble x1, wxDouble y1 , wxDouble x2, wxDouble y2, wxDouble r ) +{ + wxPoint2DDouble current; + GetCurrentPoint(¤t.m_x,¤t.m_y); + wxPoint2DDouble p1(x1,y1); + wxPoint2DDouble p2(x2,y2); + + wxPoint2DDouble v1 = current - p1; + v1.Normalize(); + wxPoint2DDouble v2 = p2 - p1; + v2.Normalize(); + + wxDouble alpha = v1.GetVectorAngle() - v2.GetVectorAngle(); + + if ( alpha < 0 ) + alpha = 360 + alpha; + // TODO obtuse angles + + alpha = DegToRad(alpha); + + wxDouble dist = r / sin(alpha/2) * cos(alpha/2); + // calculate tangential points + wxPoint2DDouble t1 = dist*v1 + p1; + wxPoint2DDouble t2 = dist*v2 + p1; + + wxPoint2DDouble nv1 = v1; + nv1.SetVectorAngle(v1.GetVectorAngle()-90); + wxPoint2DDouble c = t1 + r*nv1; + + wxDouble a1 = v1.GetVectorAngle()+90; + wxDouble a2 = v2.GetVectorAngle()-90; + + AddLineToPoint(t1.m_x,t1.m_y); + AddArc(c.m_x,c.m_y,r,DegToRad(a1),DegToRad(a2),true); + AddLineToPoint(p2.m_x,p2.m_y); +} + +//----------------------------------------------------------------------------- +// wxGraphicsContext Convenience Methods +//----------------------------------------------------------------------------- + +IMPLEMENT_ABSTRACT_CLASS(wxGraphicsContext, wxObject) + + +wxGraphicsContext::wxGraphicsContext(wxGraphicsRenderer* renderer) : wxGraphicsObject(renderer) +{ + m_logicalFunction = wxCOPY; +} + +wxGraphicsContext::~wxGraphicsContext() +{ +} + +// sets the pen +void wxGraphicsContext::SetPen( const wxGraphicsPen& pen ) +{ + m_pen = pen; +} + +void wxGraphicsContext::SetPen( const wxPen& pen ) +{ + if ( !pen.Ok() || pen.GetStyle() == wxTRANSPARENT ) + SetPen( wxNullGraphicsPen ); + else + SetPen( CreatePen( pen ) ); +} + +// sets the brush for filling +void wxGraphicsContext::SetBrush( const wxGraphicsBrush& brush ) +{ + m_brush = brush; +} + +void wxGraphicsContext::SetBrush( const wxBrush& brush ) +{ + if ( !brush.Ok() || brush.GetStyle() == wxTRANSPARENT ) + SetBrush( wxNullGraphicsBrush ); + else + SetBrush( CreateBrush( brush ) ); +} + +// sets the brush for filling +void wxGraphicsContext::SetFont( const wxGraphicsFont& font ) +{ + m_font = font; +} + +bool wxGraphicsContext::SetLogicalFunction( int function ) +{ + if ( function == wxCOPY ) + { + m_logicalFunction = function; + return true; + } + return false; +} + +void wxGraphicsContext::SetFont( const wxFont& font, const wxColour& colour ) +{ + if ( font.Ok() ) + SetFont( CreateFont( font, colour ) ); + else + SetFont( wxNullGraphicsFont ); +} + +void wxGraphicsContext::DrawPath( const wxGraphicsPath& path, int fillStyle ) +{ + FillPath( path , fillStyle ); + StrokePath( path ); +} + +void wxGraphicsContext::DrawText( const wxString &str, wxDouble x, wxDouble y, wxDouble angle ) +{ + Translate(x,y); + Rotate( -angle ); + DrawText( str , 0, 0 ); + Rotate( angle ); + Translate(-x,-y); +} + +void wxGraphicsContext::DrawText( const wxString &str, wxDouble x, wxDouble y, const wxGraphicsBrush& backgroundBrush ) +{ + wxGraphicsBrush formerBrush = m_brush; + wxGraphicsPen formerPen = m_pen; + wxDouble width; + wxDouble height; + wxDouble descent; + wxDouble externalLeading; + GetTextExtent( str , &width, &height, &descent, &externalLeading ); + SetBrush( backgroundBrush ); + // to make sure our 'OffsetToPixelBoundaries' doesn't move the fill shape + SetPen( wxNullGraphicsPen ); + + wxGraphicsPath path = CreatePath(); + path.AddRectangle( x , y, width, height ); + FillPath( path ); + + DrawText( str, x ,y); + SetBrush( formerBrush ); + SetPen( formerPen ); +} + +void wxGraphicsContext::DrawText( const wxString &str, wxDouble x, wxDouble y, wxDouble angle, const wxGraphicsBrush& backgroundBrush ) +{ + wxGraphicsBrush formerBrush = m_brush; + wxGraphicsPen formerPen = m_pen; + + wxDouble width; + wxDouble height; + wxDouble descent; + wxDouble externalLeading; + GetTextExtent( str , &width, &height, &descent, &externalLeading ); + SetBrush( backgroundBrush ); + // to make sure our 'OffsetToPixelBoundaries' doesn't move the fill shape + SetPen( wxNullGraphicsPen ); + + wxGraphicsPath path = CreatePath(); + path.MoveToPoint( x , y ); + path.AddLineToPoint( (int) (x + sin(angle) * height) , (int) (y + cos(angle) * height) ); + path.AddLineToPoint( + (int) (x + sin(angle) * height + cos(angle) * width) , + (int) (y + cos(angle) * height - sin(angle) * width)); + path.AddLineToPoint((int) (x + cos(angle) * width) , (int) (y - sin(angle) * width) ); + FillPath( path ); + DrawText( str, x ,y, angle); + SetBrush( formerBrush ); + SetPen( formerPen ); +} + +void wxGraphicsContext::StrokeLine( wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2) +{ + wxGraphicsPath path = CreatePath(); + path.MoveToPoint(x1, y1); + path.AddLineToPoint( x2, y2 ); + StrokePath( path ); +} + +void wxGraphicsContext::DrawRectangle( wxDouble x, wxDouble y, wxDouble w, wxDouble h) +{ + wxGraphicsPath path = CreatePath(); + path.AddRectangle( x , y , w , h ); + DrawPath( path ); +} + +void wxGraphicsContext::DrawEllipse( wxDouble x, wxDouble y, wxDouble w, wxDouble h) +{ + wxGraphicsPath path = CreatePath(); + path.AddEllipse(x,y,w,h); + DrawPath(path); +} + +void wxGraphicsContext::DrawRoundedRectangle( wxDouble x, wxDouble y, wxDouble w, wxDouble h, wxDouble radius) +{ + wxGraphicsPath path = CreatePath(); + path.AddRoundedRectangle(x,y,w,h,radius); + DrawPath(path); +} + +void wxGraphicsContext::StrokeLines( size_t n, const wxPoint2DDouble *points) +{ + wxASSERT(n > 1); + wxGraphicsPath path = CreatePath(); + path.MoveToPoint(points[0].m_x, points[0].m_y); + for ( size_t i = 1; i < n; ++i) + path.AddLineToPoint( points[i].m_x, points[i].m_y ); + StrokePath( path ); +} + +void wxGraphicsContext::DrawLines( size_t n, const wxPoint2DDouble *points, int fillStyle) +{ + wxASSERT(n > 1); + wxGraphicsPath path = CreatePath(); + path.MoveToPoint(points[0].m_x, points[0].m_y); + for ( size_t i = 1; i < n; ++i) + path.AddLineToPoint( points[i].m_x, points[i].m_y ); + DrawPath( path , fillStyle); +} + +void wxGraphicsContext::StrokeLines( size_t n, const wxPoint2DDouble *beginPoints, const wxPoint2DDouble *endPoints) +{ + wxASSERT(n > 0); + wxGraphicsPath path = CreatePath(); + for ( size_t i = 0; i < n; ++i) + { + path.MoveToPoint(beginPoints[i].m_x, beginPoints[i].m_y); + path.AddLineToPoint( endPoints[i].m_x, endPoints[i].m_y ); + } + StrokePath( path ); +} + +// create a 'native' matrix corresponding to these values +wxGraphicsMatrix wxGraphicsContext::CreateMatrix( wxDouble a, wxDouble b, wxDouble c, wxDouble d, + wxDouble tx, wxDouble ty) const +{ + return GetRenderer()->CreateMatrix(a,b,c,d,tx,ty); +} + +wxGraphicsPath wxGraphicsContext::CreatePath() const +{ + return GetRenderer()->CreatePath(); +} + +wxGraphicsPen wxGraphicsContext::CreatePen(const wxPen& pen) const +{ + return GetRenderer()->CreatePen(pen); +} + +wxGraphicsBrush wxGraphicsContext::CreateBrush(const wxBrush& brush ) const +{ + return GetRenderer()->CreateBrush(brush); +} + +// sets the brush to a linear gradient, starting at (x1,y1) with color c1 to (x2,y2) with color c2 +wxGraphicsBrush wxGraphicsContext::CreateLinearGradientBrush( wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2, + const wxColour&c1, const wxColour&c2) const +{ + return GetRenderer()->CreateLinearGradientBrush(x1,y1,x2,y2,c1,c2); +} + +// sets the brush to a radial gradient originating at (xo,yc) with color oColor and ends on a circle around (xc,yc) +// with radius r and color cColor +wxGraphicsBrush wxGraphicsContext::CreateRadialGradientBrush( wxDouble xo, wxDouble yo, wxDouble xc, wxDouble yc, wxDouble radius, + const wxColour &oColor, const wxColour &cColor) const +{ + return GetRenderer()->CreateRadialGradientBrush(xo,yo,xc,yc,radius,oColor,cColor); +} + +// sets the font +wxGraphicsFont wxGraphicsContext::CreateFont( const wxFont &font , const wxColour &col ) const +{ + return GetRenderer()->CreateFont(font,col); +} + +wxGraphicsContext* wxGraphicsContext::Create( const wxWindowDC& dc) +{ + return wxGraphicsRenderer::GetDefaultRenderer()->CreateContext(dc); +} +#ifdef __WXMSW__ +wxGraphicsContext* wxGraphicsContext::Create( const wxMemoryDC& dc) +{ + return wxGraphicsRenderer::GetDefaultRenderer()->CreateContext(dc); +} +#endif + +wxGraphicsContext* wxGraphicsContext::CreateFromNative( void * context ) +{ + return wxGraphicsRenderer::GetDefaultRenderer()->CreateContextFromNativeContext(context); +} + +wxGraphicsContext* wxGraphicsContext::CreateFromNativeWindow( void * window ) +{ + return wxGraphicsRenderer::GetDefaultRenderer()->CreateContextFromNativeWindow(window); +} + +wxGraphicsContext* wxGraphicsContext::Create( wxWindow* window ) +{ + return wxGraphicsRenderer::GetDefaultRenderer()->CreateContext(window); +} + +wxGraphicsContext* wxGraphicsContext::Create() +{ + return wxGraphicsRenderer::GetDefaultRenderer()->CreateMeasuringContext(); +} + +//----------------------------------------------------------------------------- +// wxGraphicsRenderer +//----------------------------------------------------------------------------- + +IMPLEMENT_ABSTRACT_CLASS(wxGraphicsRenderer, wxObject) + +#endif // wxUSE_GRAPHICS_CONTEXT diff --git a/Externals/wxWidgets/src/common/hash.cpp b/Externals/wxWidgets/src/common/hash.cpp index 4fb13b4380..9969bb1884 100644 --- a/Externals/wxWidgets/src/common/hash.cpp +++ b/Externals/wxWidgets/src/common/hash.cpp @@ -1,1077 +1,1077 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/hash.cpp -// Purpose: wxHashTable implementation -// Author: Julian Smart -// Modified by: VZ at 25.02.00: type safe hashes with WX_DECLARE_HASH() -// Created: 01/02/97 -// RCS-ID: $Id: hash.cpp 49529 2007-10-30 00:32:18Z VZ $ -// Copyright: (c) Julian Smart -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#ifndef WX_PRECOMP - #include "wx/list.h" - #include "wx/hash.h" -#endif - -#if wxUSE_OLD_HASH_TABLE - -#include -#include - -// ---------------------------------------------------------------------------- -// wxWin macros -// ---------------------------------------------------------------------------- - -IMPLEMENT_DYNAMIC_CLASS(wxHashTable, wxObject) - -// ============================================================================ -// implementation -// ============================================================================ - -// ---------------------------------------------------------------------------- -// wxHashTablleBase for working with "void *" data -// ---------------------------------------------------------------------------- - -wxHashTableBase::wxHashTableBase() -{ - m_deleteContents = false; - m_hashTable = (wxListBase **)NULL; - m_hashSize = 0; - m_count = 0; - m_keyType = wxKEY_NONE; -} - -void wxHashTableBase::Create(wxKeyType keyType, size_t size) -{ - Destroy(); - - m_hashSize = size; - m_keyType = keyType; - m_hashTable = new wxListBase *[size]; - for ( size_t n = 0; n < m_hashSize; n++ ) - { - m_hashTable[n] = (wxListBase *) NULL; - } -} - -void wxHashTableBase::Destroy() -{ - if ( m_hashTable ) - { - for ( size_t n = 0; n < m_hashSize; n++ ) - { - delete m_hashTable[n]; - } - - delete [] m_hashTable; - - m_hashTable = (wxListBase **)NULL; - - m_count = 0; - } -} - -void wxHashTableBase::DeleteContents(bool flag) -{ - m_deleteContents = flag; - for ( size_t n = 0; n < m_hashSize; n++ ) - { - if ( m_hashTable[n] ) - { - m_hashTable[n]->DeleteContents(flag); - } - } -} - -wxNodeBase *wxHashTableBase::GetNode(long key, long value) const -{ - size_t slot = (size_t)abs((int)(key % (long)m_hashSize)); - - wxNodeBase *node; - if ( m_hashTable[slot] ) - { - node = m_hashTable[slot]->Find(wxListKey(value)); - } - else - { - node = (wxNodeBase *)NULL; - } - - return node; -} - -#if WXWIN_COMPATIBILITY_2_4 - -// ---------------------------------------------------------------------------- -// wxHashTableLong -// ---------------------------------------------------------------------------- - -wxHashTableLong::~wxHashTableLong() -{ - Destroy(); -} - -void wxHashTableLong::Init(size_t size) -{ - m_hashSize = size; - m_values = new wxArrayLong *[size]; - m_keys = new wxArrayLong *[size]; - - for ( size_t n = 0; n < m_hashSize; n++ ) - { - m_values[n] = - m_keys[n] = (wxArrayLong *)NULL; - } - - m_count = 0; -} - -void wxHashTableLong::Create(size_t size) -{ - Init(size); -} - -void wxHashTableLong::Destroy() -{ - for ( size_t n = 0; n < m_hashSize; n++ ) - { - delete m_values[n]; - delete m_keys[n]; - } - - delete [] m_values; - delete [] m_keys; - m_hashSize = 0; - m_count = 0; -} - -void wxHashTableLong::Put(long key, long value) -{ - wxCHECK_RET( m_hashSize, _T("must call Create() first") ); - - size_t slot = (size_t)abs((int)(key % (long)m_hashSize)); - - if ( !m_keys[slot] ) - { - m_keys[slot] = new wxArrayLong; - m_values[slot] = new wxArrayLong; - } - - m_keys[slot]->Add(key); - m_values[slot]->Add(value); - - m_count++; -} - -long wxHashTableLong::Get(long key) const -{ - wxCHECK_MSG( m_hashSize, wxNOT_FOUND, _T("must call Create() first") ); - - size_t slot = (size_t)abs((int)(key % (long)m_hashSize)); - - wxArrayLong *keys = m_keys[slot]; - if ( keys ) - { - size_t count = keys->GetCount(); - for ( size_t n = 0; n < count; n++ ) - { - if ( keys->Item(n) == key ) - { - return m_values[slot]->Item(n); - } - } - } - - return wxNOT_FOUND; -} - -long wxHashTableLong::Delete(long key) -{ - wxCHECK_MSG( m_hashSize, wxNOT_FOUND, _T("must call Create() first") ); - - size_t slot = (size_t)abs((int)(key % (long)m_hashSize)); - - wxArrayLong *keys = m_keys[slot]; - if ( keys ) - { - size_t count = keys->GetCount(); - for ( size_t n = 0; n < count; n++ ) - { - if ( keys->Item(n) == key ) - { - long val = m_values[slot]->Item(n); - - keys->RemoveAt(n); - m_values[slot]->RemoveAt(n); - - m_count--; - - return val; - } - } - } - - return wxNOT_FOUND; -} - -// ---------------------------------------------------------------------------- -// wxStringHashTable: more efficient than storing strings in a list -// ---------------------------------------------------------------------------- - -wxStringHashTable::wxStringHashTable(size_t sizeTable) -{ - m_keys = new wxArrayLong *[sizeTable]; - m_values = new wxArrayString *[sizeTable]; - - m_hashSize = sizeTable; - for ( size_t n = 0; n < m_hashSize; n++ ) - { - m_values[n] = (wxArrayString *)NULL; - m_keys[n] = (wxArrayLong *)NULL; - } -} - -wxStringHashTable::~wxStringHashTable() -{ - Destroy(); -} - -void wxStringHashTable::Destroy() -{ - for ( size_t n = 0; n < m_hashSize; n++ ) - { - delete m_values[n]; - delete m_keys[n]; - } - - delete [] m_values; - delete [] m_keys; - m_hashSize = 0; -} - -void wxStringHashTable::Put(long key, const wxString& value) -{ - wxCHECK_RET( m_hashSize, _T("must call Create() first") ); - - size_t slot = (size_t)abs((int)(key % (long)m_hashSize)); - - if ( !m_keys[slot] ) - { - m_keys[slot] = new wxArrayLong; - m_values[slot] = new wxArrayString; - } - - m_keys[slot]->Add(key); - m_values[slot]->Add(value); -} - -wxString wxStringHashTable::Get(long key, bool *wasFound) const -{ - wxCHECK_MSG( m_hashSize, wxEmptyString, _T("must call Create() first") ); - - size_t slot = (size_t)abs((int)(key % (long)m_hashSize)); - - wxArrayLong *keys = m_keys[slot]; - if ( keys ) - { - size_t count = keys->GetCount(); - for ( size_t n = 0; n < count; n++ ) - { - if ( keys->Item(n) == key ) - { - if ( wasFound ) - *wasFound = true; - - return m_values[slot]->Item(n); - } - } - } - - if ( wasFound ) - *wasFound = false; - - return wxEmptyString; -} - -bool wxStringHashTable::Delete(long key) const -{ - wxCHECK_MSG( m_hashSize, false, _T("must call Create() first") ); - - size_t slot = (size_t)abs((int)(key % (long)m_hashSize)); - - wxArrayLong *keys = m_keys[slot]; - if ( keys ) - { - size_t count = keys->GetCount(); - for ( size_t n = 0; n < count; n++ ) - { - if ( keys->Item(n) == key ) - { - keys->RemoveAt(n); - m_values[slot]->RemoveAt(n); - return true; - } - } - } - - return false; -} - -#endif // WXWIN_COMPATIBILITY_2_4 - -// ---------------------------------------------------------------------------- -// old not type safe wxHashTable -// ---------------------------------------------------------------------------- - -wxHashTable::wxHashTable (int the_key_type, int size) -{ - n = 0; - hash_table = (wxList**) NULL; - Create(the_key_type, size); - m_count = 0; - m_deleteContents = false; -/* - n = size; - current_position = -1; - current_node = (wxNode *) NULL; - - key_type = the_key_type; - hash_table = new wxList *[size]; - int i; - for (i = 0; i < size; i++) - hash_table[i] = (wxList *) NULL; -*/ -} - -wxHashTable::~wxHashTable () -{ - Destroy(); -} - -void wxHashTable::Destroy() -{ - if (!hash_table) return; - int i; - for (i = 0; i < n; i++) - if (hash_table[i]) - delete hash_table[i]; - delete[] hash_table; - hash_table = NULL; -} - -bool wxHashTable::Create(int the_key_type, int size) -{ - Destroy(); - - n = size; - current_position = -1; - current_node = (wxNode *) NULL; - - key_type = the_key_type; - hash_table = new wxList *[size]; - int i; - for (i = 0; i < size; i++) - hash_table[i] = (wxList *) NULL; - return true; -} - - -void wxHashTable::DoCopy(const wxHashTable& table) -{ - n = table.n; - m_count = table.m_count; - current_position = table.current_position; - current_node = NULL; // doesn't matter - Next() will reconstruct it - key_type = table.key_type; - - hash_table = new wxList *[n]; - for (int i = 0; i < n; i++) { - if (table.hash_table[i] == NULL) - hash_table[i] = NULL; - else { - hash_table[i] = new wxList(key_type); - *hash_table[i] = *(table.hash_table[i]); - } - } -} - -void wxHashTable::Put (long key, long value, wxObject * object) -{ - // Should NEVER be - long k = (long) key; - - int position = (int) (k % n); - if (position < 0) position = -position; - - if (!hash_table[position]) - { - hash_table[position] = new wxList (wxKEY_INTEGER); - if (m_deleteContents) hash_table[position]->DeleteContents(true); - } - - hash_table[position]->Append (value, object); - m_count++; -} - -void wxHashTable::Put (long key, const wxChar *value, wxObject * object) -{ - // Should NEVER be - long k = (long) key; - - int position = (int) (k % n); - if (position < 0) position = -position; - - if (!hash_table[position]) - { - hash_table[position] = new wxList (wxKEY_STRING); - if (m_deleteContents) hash_table[position]->DeleteContents(true); - } - - hash_table[position]->Append (value, object); - m_count++; -} - -void wxHashTable::Put (long key, wxObject * object) -{ - // Should NEVER be - long k = (long) key; - - int position = (int) (k % n); - if (position < 0) position = -position; - - if (!hash_table[position]) - { - hash_table[position] = new wxList (wxKEY_INTEGER); - if (m_deleteContents) hash_table[position]->DeleteContents(true); - } - - hash_table[position]->Append (k, object); - m_count++; -} - -void wxHashTable::Put (const wxChar *key, wxObject * object) -{ - int position = (int) (MakeKey (key) % n); - if (position < 0) position = -position; - - if (!hash_table[position]) - { - hash_table[position] = new wxList (wxKEY_STRING); - if (m_deleteContents) hash_table[position]->DeleteContents(true); - } - - hash_table[position]->Append (key, object); - m_count++; -} - -wxObject *wxHashTable::Get (long key, long value) const -{ - // Should NEVER be - long k = (long) key; - - int position = (int) (k % n); - if (position < 0) position = -position; - - if (!hash_table[position]) - return (wxObject *) NULL; - else - { - wxNode *node = hash_table[position]->Find (value); - if (node) - return node->GetData (); - else - return (wxObject *) NULL; - } -} - -wxObject *wxHashTable::Get (long key, const wxChar *value) const -{ - // Should NEVER be - long k = (long) key; - - int position = (int) (k % n); - if (position < 0) position = -position; - - if (!hash_table[position]) - return (wxObject *) NULL; - else - { - wxNode *node = hash_table[position]->Find (value); - if (node) - return node->GetData (); - else - return (wxObject *) NULL; - } -} - -wxObject *wxHashTable::Get (long key) const -{ - // Should NEVER be - long k = (long) key; - - int position = (int) (k % n); - if (position < 0) position = -position; - - if (!hash_table[position]) - return (wxObject *) NULL; - else - { - wxNode *node = hash_table[position]->Find (k); - return node ? node->GetData () : (wxObject*)NULL; - } -} - -wxObject *wxHashTable::Get (const wxChar *key) const -{ - int position = (int) (MakeKey (key) % n); - if (position < 0) position = -position; - - if (!hash_table[position]) - return (wxObject *) NULL; - else - { - wxNode *node = hash_table[position]->Find (key); - return node ? node->GetData () : (wxObject*)NULL; - } -} - -wxObject *wxHashTable::Delete (long key) -{ - // Should NEVER be - long k = (long) key; - - int position = (int) (k % n); - if (position < 0) position = -position; - - if (!hash_table[position]) - return (wxObject *) NULL; - else - { - wxNode *node = hash_table[position]->Find (k); - if (node) - { - wxObject *data = node->GetData (); - delete node; - m_count--; - return data; - } - else - return (wxObject *) NULL; - } -} - -wxObject *wxHashTable::Delete (const wxChar *key) -{ - int position = (int) (MakeKey (key) % n); - if (position < 0) position = -position; - - if (!hash_table[position]) - return (wxObject *) NULL; - else - { - wxNode *node = hash_table[position]->Find (key); - if (node) - { - wxObject *data = node->GetData (); - delete node; - m_count--; - return data; - } - else - return (wxObject *) NULL; - } -} - -wxObject *wxHashTable::Delete (long key, int value) -{ - // Should NEVER be - long k = (long) key; - - int position = (int) (k % n); - if (position < 0) position = -position; - - if (!hash_table[position]) - return (wxObject *) NULL; - else - { - wxNode *node = hash_table[position]->Find (value); - if (node) - { - wxObject *data = node->GetData (); - delete node; - m_count--; - return data; - } - else - return (wxObject *) NULL; - } -} - -wxObject *wxHashTable::Delete (long key, const wxChar *value) -{ - int position = (int) (key % n); - if (position < 0) position = -position; - - if (!hash_table[position]) - return (wxObject *) NULL; - else - { - wxNode *node = hash_table[position]->Find (value); - if (node) - { - wxObject *data = node->GetData (); - delete node; - m_count--; - return data; - } - else - return (wxObject *) NULL; - } -} - -long wxHashTable::MakeKey (const wxChar *string) const -{ - long int_key = 0; - - while (*string) - int_key += (wxUChar) *string++; - - return int_key; -} - -void wxHashTable::BeginFind () -{ - current_position = -1; - current_node = (wxNode *) NULL; -} - -wxHashTable::Node* wxHashTable::Next () -{ - wxNode *found = (wxNode *) NULL; - bool end = false; - while (!end && !found) - { - if (!current_node) - { - current_position++; - if (current_position >= n) - { - current_position = -1; - current_node = (wxNode *) NULL; - end = true; - } - else - { - if (hash_table[current_position]) - { - current_node = hash_table[current_position]->GetFirst (); - found = current_node; - } - } - } - else - { - current_node = current_node->GetNext (); - found = current_node; - } - } - return found; -} - -void wxHashTable::DeleteContents (bool flag) -{ - int i; - m_deleteContents = flag; - for (i = 0; i < n; i++) - { - if (hash_table[i]) - hash_table[i]->DeleteContents (flag); - } -} - -void wxHashTable::Clear () -{ - int i; - if (hash_table) - { - for (i = 0; i < n; i++) - { - if (hash_table[i]) - hash_table[i]->Clear (); - } - } - m_count = 0; -} - -#else // if !wxUSE_OLD_HASH_TABLE - -wxHashTableBase_Node::wxHashTableBase_Node( long key, void* value, - wxHashTableBase* table ) - : m_value( value ), m_hashPtr( table ) -{ - m_key.integer = key; -} - -wxHashTableBase_Node::wxHashTableBase_Node( const wxChar* key, void* value, - wxHashTableBase* table ) - : m_value( value ), m_hashPtr( table ) -{ - m_key.string = wxStrcpy( new wxChar[wxStrlen( key ) + 1], key ); -} - -wxHashTableBase_Node::~wxHashTableBase_Node() -{ - if( m_hashPtr ) m_hashPtr->DoRemoveNode( this ); -} - -// - -wxHashTableBase::wxHashTableBase() - : m_size( 0 ), m_count( 0 ), m_table( NULL ), m_keyType( wxKEY_NONE ), - m_deleteContents( false ) -{ -} - -void wxHashTableBase::Create( wxKeyType keyType, size_t size ) -{ - m_keyType = keyType; - m_size = size; - m_table = new wxHashTableBase_Node*[ m_size ]; - - for( size_t i = 0; i < m_size; ++i ) - m_table[i] = NULL; -} - -void wxHashTableBase::Clear() -{ - for( size_t i = 0; i < m_size; ++i ) - { - Node* end = m_table[i]; - - if( end == NULL ) - continue; - - Node *curr, *next = end->GetNext(); - - do - { - curr = next; - next = curr->GetNext(); - - DoDestroyNode( curr ); - - delete curr; - } - while( curr != end ); - - m_table[i] = NULL; - } - - m_count = 0; -} - -void wxHashTableBase::DoRemoveNode( wxHashTableBase_Node* node ) -{ - size_t bucket = ( m_keyType == wxKEY_INTEGER ? - node->m_key.integer : - MakeKey( node->m_key.string ) ) % m_size; - - if( node->GetNext() == node ) - { - // single-node chain (common case) - m_table[bucket] = NULL; - } - else - { - Node *start = m_table[bucket], *curr; - Node* prev = start; - - for( curr = prev->GetNext(); curr != node; - prev = curr, curr = curr->GetNext() ) ; - - DoUnlinkNode( bucket, node, prev ); - } - - DoDestroyNode( node ); -} - -void wxHashTableBase::DoDestroyNode( wxHashTableBase_Node* node ) -{ - // if it is called from DoRemoveNode, node has already been - // removed, from other places it does not matter - node->m_hashPtr = NULL; - - if( m_keyType == wxKEY_STRING ) - delete[] node->m_key.string; - if( m_deleteContents ) - DoDeleteContents( node ); -} - -void wxHashTableBase::Destroy() -{ - Clear(); - - delete[] m_table; - - m_table = NULL; - m_size = 0; -} - -void wxHashTableBase::DoInsertNode( size_t bucket, wxHashTableBase_Node* node ) -{ - if( m_table[bucket] == NULL ) - { - m_table[bucket] = node->m_next = node; - } - else - { - Node *prev = m_table[bucket]; - Node *next = prev->m_next; - - prev->m_next = node; - node->m_next = next; - m_table[bucket] = node; - } - - ++m_count; -} - -void wxHashTableBase::DoPut( long key, long hash, void* data ) -{ - wxASSERT( m_keyType == wxKEY_INTEGER ); - - size_t bucket = size_t(hash) % m_size; - Node* node = new wxHashTableBase_Node( key, data, this ); - - DoInsertNode( bucket, node ); -} - -void wxHashTableBase::DoPut( const wxChar* key, long hash, void* data ) -{ - wxASSERT( m_keyType == wxKEY_STRING ); - - size_t bucket = size_t(hash) % m_size; - Node* node = new wxHashTableBase_Node( key, data, this ); - - DoInsertNode( bucket, node ); -} - -void* wxHashTableBase::DoGet( long key, long hash ) const -{ - wxASSERT( m_keyType == wxKEY_INTEGER ); - - size_t bucket = size_t(hash) % m_size; - - if( m_table[bucket] == NULL ) - return NULL; - - Node *first = m_table[bucket]->GetNext(), - *curr = first; - - do - { - if( curr->m_key.integer == key ) - return curr->m_value; - - curr = curr->GetNext(); - } - while( curr != first ); - - return NULL; -} - -void* wxHashTableBase::DoGet( const wxChar* key, long hash ) const -{ - wxASSERT( m_keyType == wxKEY_STRING ); - - size_t bucket = size_t(hash) % m_size; - - if( m_table[bucket] == NULL ) - return NULL; - - Node *first = m_table[bucket]->GetNext(), - *curr = first; - - do - { - if( wxStrcmp( curr->m_key.string, key ) == 0 ) - return curr->m_value; - - curr = curr->GetNext(); - } - while( curr != first ); - - return NULL; -} - -void wxHashTableBase::DoUnlinkNode( size_t bucket, wxHashTableBase_Node* node, - wxHashTableBase_Node* prev ) -{ - if( node == m_table[bucket] ) - m_table[bucket] = prev; - - if( prev == node && prev == node->GetNext() ) - m_table[bucket] = NULL; - else - prev->m_next = node->m_next; - - DoDestroyNode( node ); - --m_count; -} - -void* wxHashTableBase::DoDelete( long key, long hash ) -{ - wxASSERT( m_keyType == wxKEY_INTEGER ); - - size_t bucket = size_t(hash) % m_size; - - if( m_table[bucket] == NULL ) - return NULL; - - Node *first = m_table[bucket]->GetNext(), - *curr = first, - *prev = m_table[bucket]; - - do - { - if( curr->m_key.integer == key ) - { - void* retval = curr->m_value; - curr->m_value = NULL; - - DoUnlinkNode( bucket, curr, prev ); - delete curr; - - return retval; - } - - prev = curr; - curr = curr->GetNext(); - } - while( curr != first ); - - return NULL; -} - -void* wxHashTableBase::DoDelete( const wxChar* key, long hash ) -{ - wxASSERT( m_keyType == wxKEY_STRING ); - - size_t bucket = size_t(hash) % m_size; - - if( m_table[bucket] == NULL ) - return NULL; - - Node *first = m_table[bucket]->GetNext(), - *curr = first, - *prev = m_table[bucket]; - - do - { - if( wxStrcmp( curr->m_key.string, key ) == 0 ) - { - void* retval = curr->m_value; - curr->m_value = NULL; - - DoUnlinkNode( bucket, curr, prev ); - delete curr; - - return retval; - } - - prev = curr; - curr = curr->GetNext(); - } - while( curr != first ); - - return NULL; -} - -long wxHashTableBase::MakeKey( const wxChar *str ) -{ - long int_key = 0; - - while( *str ) - int_key += (wxUChar)*str++; - - return int_key; -} - -// ---------------------------------------------------------------------------- -// wxHashTable -// ---------------------------------------------------------------------------- - -wxHashTable::wxHashTable( const wxHashTable& table ) - : wxHashTableBase() -{ - DoCopy( table ); -} - -const wxHashTable& wxHashTable::operator=( const wxHashTable& table ) -{ - Destroy(); - DoCopy( table ); - - return *this; -} - -void wxHashTable::DoCopy( const wxHashTable& WXUNUSED(table) ) -{ - Create( m_keyType, m_size ); - - wxFAIL; -} - -void wxHashTable::DoDeleteContents( wxHashTableBase_Node* node ) -{ - delete ((wxHashTable_Node*)node)->GetData(); -} - -void wxHashTable::GetNextNode( size_t bucketStart ) -{ - for( size_t i = bucketStart; i < m_size; ++i ) - { - if( m_table[i] != NULL ) - { - m_curr = ((Node*)m_table[i])->GetNext(); - m_currBucket = i; - return; - } - } - - m_curr = NULL; - m_currBucket = 0; -} - -wxHashTable::Node* wxHashTable::Next() -{ - if( m_curr == NULL ) - GetNextNode( 0 ); - else - { - m_curr = m_curr->GetNext(); - - if( m_curr == ( (Node*)m_table[m_currBucket] )->GetNext() ) - GetNextNode( m_currBucket + 1 ); - } - - return m_curr; -} - -#endif // !wxUSE_OLD_HASH_TABLE +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/hash.cpp +// Purpose: wxHashTable implementation +// Author: Julian Smart +// Modified by: VZ at 25.02.00: type safe hashes with WX_DECLARE_HASH() +// Created: 01/02/97 +// RCS-ID: $Id: hash.cpp 49529 2007-10-30 00:32:18Z VZ $ +// Copyright: (c) Julian Smart +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#ifndef WX_PRECOMP + #include "wx/list.h" + #include "wx/hash.h" +#endif + +#if wxUSE_OLD_HASH_TABLE + +#include +#include + +// ---------------------------------------------------------------------------- +// wxWin macros +// ---------------------------------------------------------------------------- + +IMPLEMENT_DYNAMIC_CLASS(wxHashTable, wxObject) + +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// wxHashTablleBase for working with "void *" data +// ---------------------------------------------------------------------------- + +wxHashTableBase::wxHashTableBase() +{ + m_deleteContents = false; + m_hashTable = (wxListBase **)NULL; + m_hashSize = 0; + m_count = 0; + m_keyType = wxKEY_NONE; +} + +void wxHashTableBase::Create(wxKeyType keyType, size_t size) +{ + Destroy(); + + m_hashSize = size; + m_keyType = keyType; + m_hashTable = new wxListBase *[size]; + for ( size_t n = 0; n < m_hashSize; n++ ) + { + m_hashTable[n] = (wxListBase *) NULL; + } +} + +void wxHashTableBase::Destroy() +{ + if ( m_hashTable ) + { + for ( size_t n = 0; n < m_hashSize; n++ ) + { + delete m_hashTable[n]; + } + + delete [] m_hashTable; + + m_hashTable = (wxListBase **)NULL; + + m_count = 0; + } +} + +void wxHashTableBase::DeleteContents(bool flag) +{ + m_deleteContents = flag; + for ( size_t n = 0; n < m_hashSize; n++ ) + { + if ( m_hashTable[n] ) + { + m_hashTable[n]->DeleteContents(flag); + } + } +} + +wxNodeBase *wxHashTableBase::GetNode(long key, long value) const +{ + size_t slot = (size_t)abs((int)(key % (long)m_hashSize)); + + wxNodeBase *node; + if ( m_hashTable[slot] ) + { + node = m_hashTable[slot]->Find(wxListKey(value)); + } + else + { + node = (wxNodeBase *)NULL; + } + + return node; +} + +#if WXWIN_COMPATIBILITY_2_4 + +// ---------------------------------------------------------------------------- +// wxHashTableLong +// ---------------------------------------------------------------------------- + +wxHashTableLong::~wxHashTableLong() +{ + Destroy(); +} + +void wxHashTableLong::Init(size_t size) +{ + m_hashSize = size; + m_values = new wxArrayLong *[size]; + m_keys = new wxArrayLong *[size]; + + for ( size_t n = 0; n < m_hashSize; n++ ) + { + m_values[n] = + m_keys[n] = (wxArrayLong *)NULL; + } + + m_count = 0; +} + +void wxHashTableLong::Create(size_t size) +{ + Init(size); +} + +void wxHashTableLong::Destroy() +{ + for ( size_t n = 0; n < m_hashSize; n++ ) + { + delete m_values[n]; + delete m_keys[n]; + } + + delete [] m_values; + delete [] m_keys; + m_hashSize = 0; + m_count = 0; +} + +void wxHashTableLong::Put(long key, long value) +{ + wxCHECK_RET( m_hashSize, _T("must call Create() first") ); + + size_t slot = (size_t)abs((int)(key % (long)m_hashSize)); + + if ( !m_keys[slot] ) + { + m_keys[slot] = new wxArrayLong; + m_values[slot] = new wxArrayLong; + } + + m_keys[slot]->Add(key); + m_values[slot]->Add(value); + + m_count++; +} + +long wxHashTableLong::Get(long key) const +{ + wxCHECK_MSG( m_hashSize, wxNOT_FOUND, _T("must call Create() first") ); + + size_t slot = (size_t)abs((int)(key % (long)m_hashSize)); + + wxArrayLong *keys = m_keys[slot]; + if ( keys ) + { + size_t count = keys->GetCount(); + for ( size_t n = 0; n < count; n++ ) + { + if ( keys->Item(n) == key ) + { + return m_values[slot]->Item(n); + } + } + } + + return wxNOT_FOUND; +} + +long wxHashTableLong::Delete(long key) +{ + wxCHECK_MSG( m_hashSize, wxNOT_FOUND, _T("must call Create() first") ); + + size_t slot = (size_t)abs((int)(key % (long)m_hashSize)); + + wxArrayLong *keys = m_keys[slot]; + if ( keys ) + { + size_t count = keys->GetCount(); + for ( size_t n = 0; n < count; n++ ) + { + if ( keys->Item(n) == key ) + { + long val = m_values[slot]->Item(n); + + keys->RemoveAt(n); + m_values[slot]->RemoveAt(n); + + m_count--; + + return val; + } + } + } + + return wxNOT_FOUND; +} + +// ---------------------------------------------------------------------------- +// wxStringHashTable: more efficient than storing strings in a list +// ---------------------------------------------------------------------------- + +wxStringHashTable::wxStringHashTable(size_t sizeTable) +{ + m_keys = new wxArrayLong *[sizeTable]; + m_values = new wxArrayString *[sizeTable]; + + m_hashSize = sizeTable; + for ( size_t n = 0; n < m_hashSize; n++ ) + { + m_values[n] = (wxArrayString *)NULL; + m_keys[n] = (wxArrayLong *)NULL; + } +} + +wxStringHashTable::~wxStringHashTable() +{ + Destroy(); +} + +void wxStringHashTable::Destroy() +{ + for ( size_t n = 0; n < m_hashSize; n++ ) + { + delete m_values[n]; + delete m_keys[n]; + } + + delete [] m_values; + delete [] m_keys; + m_hashSize = 0; +} + +void wxStringHashTable::Put(long key, const wxString& value) +{ + wxCHECK_RET( m_hashSize, _T("must call Create() first") ); + + size_t slot = (size_t)abs((int)(key % (long)m_hashSize)); + + if ( !m_keys[slot] ) + { + m_keys[slot] = new wxArrayLong; + m_values[slot] = new wxArrayString; + } + + m_keys[slot]->Add(key); + m_values[slot]->Add(value); +} + +wxString wxStringHashTable::Get(long key, bool *wasFound) const +{ + wxCHECK_MSG( m_hashSize, wxEmptyString, _T("must call Create() first") ); + + size_t slot = (size_t)abs((int)(key % (long)m_hashSize)); + + wxArrayLong *keys = m_keys[slot]; + if ( keys ) + { + size_t count = keys->GetCount(); + for ( size_t n = 0; n < count; n++ ) + { + if ( keys->Item(n) == key ) + { + if ( wasFound ) + *wasFound = true; + + return m_values[slot]->Item(n); + } + } + } + + if ( wasFound ) + *wasFound = false; + + return wxEmptyString; +} + +bool wxStringHashTable::Delete(long key) const +{ + wxCHECK_MSG( m_hashSize, false, _T("must call Create() first") ); + + size_t slot = (size_t)abs((int)(key % (long)m_hashSize)); + + wxArrayLong *keys = m_keys[slot]; + if ( keys ) + { + size_t count = keys->GetCount(); + for ( size_t n = 0; n < count; n++ ) + { + if ( keys->Item(n) == key ) + { + keys->RemoveAt(n); + m_values[slot]->RemoveAt(n); + return true; + } + } + } + + return false; +} + +#endif // WXWIN_COMPATIBILITY_2_4 + +// ---------------------------------------------------------------------------- +// old not type safe wxHashTable +// ---------------------------------------------------------------------------- + +wxHashTable::wxHashTable (int the_key_type, int size) +{ + n = 0; + hash_table = (wxList**) NULL; + Create(the_key_type, size); + m_count = 0; + m_deleteContents = false; +/* + n = size; + current_position = -1; + current_node = (wxNode *) NULL; + + key_type = the_key_type; + hash_table = new wxList *[size]; + int i; + for (i = 0; i < size; i++) + hash_table[i] = (wxList *) NULL; +*/ +} + +wxHashTable::~wxHashTable () +{ + Destroy(); +} + +void wxHashTable::Destroy() +{ + if (!hash_table) return; + int i; + for (i = 0; i < n; i++) + if (hash_table[i]) + delete hash_table[i]; + delete[] hash_table; + hash_table = NULL; +} + +bool wxHashTable::Create(int the_key_type, int size) +{ + Destroy(); + + n = size; + current_position = -1; + current_node = (wxNode *) NULL; + + key_type = the_key_type; + hash_table = new wxList *[size]; + int i; + for (i = 0; i < size; i++) + hash_table[i] = (wxList *) NULL; + return true; +} + + +void wxHashTable::DoCopy(const wxHashTable& table) +{ + n = table.n; + m_count = table.m_count; + current_position = table.current_position; + current_node = NULL; // doesn't matter - Next() will reconstruct it + key_type = table.key_type; + + hash_table = new wxList *[n]; + for (int i = 0; i < n; i++) { + if (table.hash_table[i] == NULL) + hash_table[i] = NULL; + else { + hash_table[i] = new wxList(key_type); + *hash_table[i] = *(table.hash_table[i]); + } + } +} + +void wxHashTable::Put (long key, long value, wxObject * object) +{ + // Should NEVER be + long k = (long) key; + + int position = (int) (k % n); + if (position < 0) position = -position; + + if (!hash_table[position]) + { + hash_table[position] = new wxList (wxKEY_INTEGER); + if (m_deleteContents) hash_table[position]->DeleteContents(true); + } + + hash_table[position]->Append (value, object); + m_count++; +} + +void wxHashTable::Put (long key, const wxChar *value, wxObject * object) +{ + // Should NEVER be + long k = (long) key; + + int position = (int) (k % n); + if (position < 0) position = -position; + + if (!hash_table[position]) + { + hash_table[position] = new wxList (wxKEY_STRING); + if (m_deleteContents) hash_table[position]->DeleteContents(true); + } + + hash_table[position]->Append (value, object); + m_count++; +} + +void wxHashTable::Put (long key, wxObject * object) +{ + // Should NEVER be + long k = (long) key; + + int position = (int) (k % n); + if (position < 0) position = -position; + + if (!hash_table[position]) + { + hash_table[position] = new wxList (wxKEY_INTEGER); + if (m_deleteContents) hash_table[position]->DeleteContents(true); + } + + hash_table[position]->Append (k, object); + m_count++; +} + +void wxHashTable::Put (const wxChar *key, wxObject * object) +{ + int position = (int) (MakeKey (key) % n); + if (position < 0) position = -position; + + if (!hash_table[position]) + { + hash_table[position] = new wxList (wxKEY_STRING); + if (m_deleteContents) hash_table[position]->DeleteContents(true); + } + + hash_table[position]->Append (key, object); + m_count++; +} + +wxObject *wxHashTable::Get (long key, long value) const +{ + // Should NEVER be + long k = (long) key; + + int position = (int) (k % n); + if (position < 0) position = -position; + + if (!hash_table[position]) + return (wxObject *) NULL; + else + { + wxNode *node = hash_table[position]->Find (value); + if (node) + return node->GetData (); + else + return (wxObject *) NULL; + } +} + +wxObject *wxHashTable::Get (long key, const wxChar *value) const +{ + // Should NEVER be + long k = (long) key; + + int position = (int) (k % n); + if (position < 0) position = -position; + + if (!hash_table[position]) + return (wxObject *) NULL; + else + { + wxNode *node = hash_table[position]->Find (value); + if (node) + return node->GetData (); + else + return (wxObject *) NULL; + } +} + +wxObject *wxHashTable::Get (long key) const +{ + // Should NEVER be + long k = (long) key; + + int position = (int) (k % n); + if (position < 0) position = -position; + + if (!hash_table[position]) + return (wxObject *) NULL; + else + { + wxNode *node = hash_table[position]->Find (k); + return node ? node->GetData () : (wxObject*)NULL; + } +} + +wxObject *wxHashTable::Get (const wxChar *key) const +{ + int position = (int) (MakeKey (key) % n); + if (position < 0) position = -position; + + if (!hash_table[position]) + return (wxObject *) NULL; + else + { + wxNode *node = hash_table[position]->Find (key); + return node ? node->GetData () : (wxObject*)NULL; + } +} + +wxObject *wxHashTable::Delete (long key) +{ + // Should NEVER be + long k = (long) key; + + int position = (int) (k % n); + if (position < 0) position = -position; + + if (!hash_table[position]) + return (wxObject *) NULL; + else + { + wxNode *node = hash_table[position]->Find (k); + if (node) + { + wxObject *data = node->GetData (); + delete node; + m_count--; + return data; + } + else + return (wxObject *) NULL; + } +} + +wxObject *wxHashTable::Delete (const wxChar *key) +{ + int position = (int) (MakeKey (key) % n); + if (position < 0) position = -position; + + if (!hash_table[position]) + return (wxObject *) NULL; + else + { + wxNode *node = hash_table[position]->Find (key); + if (node) + { + wxObject *data = node->GetData (); + delete node; + m_count--; + return data; + } + else + return (wxObject *) NULL; + } +} + +wxObject *wxHashTable::Delete (long key, int value) +{ + // Should NEVER be + long k = (long) key; + + int position = (int) (k % n); + if (position < 0) position = -position; + + if (!hash_table[position]) + return (wxObject *) NULL; + else + { + wxNode *node = hash_table[position]->Find (value); + if (node) + { + wxObject *data = node->GetData (); + delete node; + m_count--; + return data; + } + else + return (wxObject *) NULL; + } +} + +wxObject *wxHashTable::Delete (long key, const wxChar *value) +{ + int position = (int) (key % n); + if (position < 0) position = -position; + + if (!hash_table[position]) + return (wxObject *) NULL; + else + { + wxNode *node = hash_table[position]->Find (value); + if (node) + { + wxObject *data = node->GetData (); + delete node; + m_count--; + return data; + } + else + return (wxObject *) NULL; + } +} + +long wxHashTable::MakeKey (const wxChar *string) const +{ + long int_key = 0; + + while (*string) + int_key += (wxUChar) *string++; + + return int_key; +} + +void wxHashTable::BeginFind () +{ + current_position = -1; + current_node = (wxNode *) NULL; +} + +wxHashTable::Node* wxHashTable::Next () +{ + wxNode *found = (wxNode *) NULL; + bool end = false; + while (!end && !found) + { + if (!current_node) + { + current_position++; + if (current_position >= n) + { + current_position = -1; + current_node = (wxNode *) NULL; + end = true; + } + else + { + if (hash_table[current_position]) + { + current_node = hash_table[current_position]->GetFirst (); + found = current_node; + } + } + } + else + { + current_node = current_node->GetNext (); + found = current_node; + } + } + return found; +} + +void wxHashTable::DeleteContents (bool flag) +{ + int i; + m_deleteContents = flag; + for (i = 0; i < n; i++) + { + if (hash_table[i]) + hash_table[i]->DeleteContents (flag); + } +} + +void wxHashTable::Clear () +{ + int i; + if (hash_table) + { + for (i = 0; i < n; i++) + { + if (hash_table[i]) + hash_table[i]->Clear (); + } + } + m_count = 0; +} + +#else // if !wxUSE_OLD_HASH_TABLE + +wxHashTableBase_Node::wxHashTableBase_Node( long key, void* value, + wxHashTableBase* table ) + : m_value( value ), m_hashPtr( table ) +{ + m_key.integer = key; +} + +wxHashTableBase_Node::wxHashTableBase_Node( const wxChar* key, void* value, + wxHashTableBase* table ) + : m_value( value ), m_hashPtr( table ) +{ + m_key.string = wxStrcpy( new wxChar[wxStrlen( key ) + 1], key ); +} + +wxHashTableBase_Node::~wxHashTableBase_Node() +{ + if( m_hashPtr ) m_hashPtr->DoRemoveNode( this ); +} + +// + +wxHashTableBase::wxHashTableBase() + : m_size( 0 ), m_count( 0 ), m_table( NULL ), m_keyType( wxKEY_NONE ), + m_deleteContents( false ) +{ +} + +void wxHashTableBase::Create( wxKeyType keyType, size_t size ) +{ + m_keyType = keyType; + m_size = size; + m_table = new wxHashTableBase_Node*[ m_size ]; + + for( size_t i = 0; i < m_size; ++i ) + m_table[i] = NULL; +} + +void wxHashTableBase::Clear() +{ + for( size_t i = 0; i < m_size; ++i ) + { + Node* end = m_table[i]; + + if( end == NULL ) + continue; + + Node *curr, *next = end->GetNext(); + + do + { + curr = next; + next = curr->GetNext(); + + DoDestroyNode( curr ); + + delete curr; + } + while( curr != end ); + + m_table[i] = NULL; + } + + m_count = 0; +} + +void wxHashTableBase::DoRemoveNode( wxHashTableBase_Node* node ) +{ + size_t bucket = ( m_keyType == wxKEY_INTEGER ? + node->m_key.integer : + MakeKey( node->m_key.string ) ) % m_size; + + if( node->GetNext() == node ) + { + // single-node chain (common case) + m_table[bucket] = NULL; + } + else + { + Node *start = m_table[bucket], *curr; + Node* prev = start; + + for( curr = prev->GetNext(); curr != node; + prev = curr, curr = curr->GetNext() ) ; + + DoUnlinkNode( bucket, node, prev ); + } + + DoDestroyNode( node ); +} + +void wxHashTableBase::DoDestroyNode( wxHashTableBase_Node* node ) +{ + // if it is called from DoRemoveNode, node has already been + // removed, from other places it does not matter + node->m_hashPtr = NULL; + + if( m_keyType == wxKEY_STRING ) + delete[] node->m_key.string; + if( m_deleteContents ) + DoDeleteContents( node ); +} + +void wxHashTableBase::Destroy() +{ + Clear(); + + delete[] m_table; + + m_table = NULL; + m_size = 0; +} + +void wxHashTableBase::DoInsertNode( size_t bucket, wxHashTableBase_Node* node ) +{ + if( m_table[bucket] == NULL ) + { + m_table[bucket] = node->m_next = node; + } + else + { + Node *prev = m_table[bucket]; + Node *next = prev->m_next; + + prev->m_next = node; + node->m_next = next; + m_table[bucket] = node; + } + + ++m_count; +} + +void wxHashTableBase::DoPut( long key, long hash, void* data ) +{ + wxASSERT( m_keyType == wxKEY_INTEGER ); + + size_t bucket = size_t(hash) % m_size; + Node* node = new wxHashTableBase_Node( key, data, this ); + + DoInsertNode( bucket, node ); +} + +void wxHashTableBase::DoPut( const wxChar* key, long hash, void* data ) +{ + wxASSERT( m_keyType == wxKEY_STRING ); + + size_t bucket = size_t(hash) % m_size; + Node* node = new wxHashTableBase_Node( key, data, this ); + + DoInsertNode( bucket, node ); +} + +void* wxHashTableBase::DoGet( long key, long hash ) const +{ + wxASSERT( m_keyType == wxKEY_INTEGER ); + + size_t bucket = size_t(hash) % m_size; + + if( m_table[bucket] == NULL ) + return NULL; + + Node *first = m_table[bucket]->GetNext(), + *curr = first; + + do + { + if( curr->m_key.integer == key ) + return curr->m_value; + + curr = curr->GetNext(); + } + while( curr != first ); + + return NULL; +} + +void* wxHashTableBase::DoGet( const wxChar* key, long hash ) const +{ + wxASSERT( m_keyType == wxKEY_STRING ); + + size_t bucket = size_t(hash) % m_size; + + if( m_table[bucket] == NULL ) + return NULL; + + Node *first = m_table[bucket]->GetNext(), + *curr = first; + + do + { + if( wxStrcmp( curr->m_key.string, key ) == 0 ) + return curr->m_value; + + curr = curr->GetNext(); + } + while( curr != first ); + + return NULL; +} + +void wxHashTableBase::DoUnlinkNode( size_t bucket, wxHashTableBase_Node* node, + wxHashTableBase_Node* prev ) +{ + if( node == m_table[bucket] ) + m_table[bucket] = prev; + + if( prev == node && prev == node->GetNext() ) + m_table[bucket] = NULL; + else + prev->m_next = node->m_next; + + DoDestroyNode( node ); + --m_count; +} + +void* wxHashTableBase::DoDelete( long key, long hash ) +{ + wxASSERT( m_keyType == wxKEY_INTEGER ); + + size_t bucket = size_t(hash) % m_size; + + if( m_table[bucket] == NULL ) + return NULL; + + Node *first = m_table[bucket]->GetNext(), + *curr = first, + *prev = m_table[bucket]; + + do + { + if( curr->m_key.integer == key ) + { + void* retval = curr->m_value; + curr->m_value = NULL; + + DoUnlinkNode( bucket, curr, prev ); + delete curr; + + return retval; + } + + prev = curr; + curr = curr->GetNext(); + } + while( curr != first ); + + return NULL; +} + +void* wxHashTableBase::DoDelete( const wxChar* key, long hash ) +{ + wxASSERT( m_keyType == wxKEY_STRING ); + + size_t bucket = size_t(hash) % m_size; + + if( m_table[bucket] == NULL ) + return NULL; + + Node *first = m_table[bucket]->GetNext(), + *curr = first, + *prev = m_table[bucket]; + + do + { + if( wxStrcmp( curr->m_key.string, key ) == 0 ) + { + void* retval = curr->m_value; + curr->m_value = NULL; + + DoUnlinkNode( bucket, curr, prev ); + delete curr; + + return retval; + } + + prev = curr; + curr = curr->GetNext(); + } + while( curr != first ); + + return NULL; +} + +long wxHashTableBase::MakeKey( const wxChar *str ) +{ + long int_key = 0; + + while( *str ) + int_key += (wxUChar)*str++; + + return int_key; +} + +// ---------------------------------------------------------------------------- +// wxHashTable +// ---------------------------------------------------------------------------- + +wxHashTable::wxHashTable( const wxHashTable& table ) + : wxHashTableBase() +{ + DoCopy( table ); +} + +const wxHashTable& wxHashTable::operator=( const wxHashTable& table ) +{ + Destroy(); + DoCopy( table ); + + return *this; +} + +void wxHashTable::DoCopy( const wxHashTable& WXUNUSED(table) ) +{ + Create( m_keyType, m_size ); + + wxFAIL; +} + +void wxHashTable::DoDeleteContents( wxHashTableBase_Node* node ) +{ + delete ((wxHashTable_Node*)node)->GetData(); +} + +void wxHashTable::GetNextNode( size_t bucketStart ) +{ + for( size_t i = bucketStart; i < m_size; ++i ) + { + if( m_table[i] != NULL ) + { + m_curr = ((Node*)m_table[i])->GetNext(); + m_currBucket = i; + return; + } + } + + m_curr = NULL; + m_currBucket = 0; +} + +wxHashTable::Node* wxHashTable::Next() +{ + if( m_curr == NULL ) + GetNextNode( 0 ); + else + { + m_curr = m_curr->GetNext(); + + if( m_curr == ( (Node*)m_table[m_currBucket] )->GetNext() ) + GetNextNode( m_currBucket + 1 ); + } + + return m_curr; +} + +#endif // !wxUSE_OLD_HASH_TABLE diff --git a/Externals/wxWidgets/src/common/hashmap.cpp b/Externals/wxWidgets/src/common/hashmap.cpp index c3fba8dfc2..215396f8e0 100644 --- a/Externals/wxWidgets/src/common/hashmap.cpp +++ b/Externals/wxWidgets/src/common/hashmap.cpp @@ -1,152 +1,152 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/hashmap.cpp -// Purpose: wxHashMap implementation -// Author: Mattia Barbon -// Modified by: -// Created: 29/01/2002 -// RCS-ID: $Id: hashmap.cpp 39802 2006-06-20 10:24:07Z ABX $ -// Copyright: (c) Mattia Barbon -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#include "wx/hashmap.h" - -/* FYI: This is the "One-at-a-Time" algorithm by Bob Jenkins */ -/* from requirements by Colin Plumb. */ -/* (http://burtleburtle.net/bob/hash/doobs.html) */ -/* adapted from Perl sources ( hv.h ) */ -unsigned long wxStringHash::wxCharStringHash( const wxChar* k ) -{ - unsigned long hash = 0; - - while( *k ) - { - hash += *k++; - hash += (hash << 10); - hash ^= (hash >> 6); - } - hash += (hash << 3); - hash ^= (hash >> 11); - - return hash + (hash << 15); -} - -#if wxUSE_UNICODE -unsigned long wxStringHash::charStringHash( const char* k ) -{ - unsigned long hash = 0; - - while( *k ) - { - hash += *k++; - hash += (hash << 10); - hash ^= (hash >> 6); - } - hash += (hash << 3); - hash ^= (hash >> 11); - - return hash + (hash << 15); -} -#endif - -#if !wxUSE_STL || !defined(HAVE_STL_HASH_MAP) - -/* from SGI STL */ -const unsigned long _wxHashTableBase2::ms_primes[prime_count] = -{ - 7ul, 13ul, 29ul, - 53ul, 97ul, 193ul, 389ul, 769ul, - 1543ul, 3079ul, 6151ul, 12289ul, 24593ul, - 49157ul, 98317ul, 196613ul, 393241ul, 786433ul, - 1572869ul, 3145739ul, 6291469ul, 12582917ul, 25165843ul, - 50331653ul, 100663319ul, 201326611ul, 402653189ul, 805306457ul, - 1610612741ul, 3221225473ul, 4294967291ul -}; - -unsigned long _wxHashTableBase2::GetNextPrime( unsigned long n ) -{ - const unsigned long* ptr = &ms_primes[0]; - for( size_t i = 0; i < prime_count; ++i, ++ptr ) - { - if( n < *ptr ) - return *ptr; - } - - /* someone might try to alloc a 2^32-element hash table */ - wxFAIL_MSG( _T("hash table too big?") ); - - /* quiet warning */ - return 0; -} - -unsigned long _wxHashTableBase2::GetPreviousPrime( unsigned long n ) -{ - const unsigned long* ptr = &ms_primes[prime_count - 1]; - - for( size_t i = 0; i < prime_count; ++i, --ptr ) - { - if( n > *ptr ) - return *ptr; - } - - /* quiet warning */ - return 1; -} - -void _wxHashTableBase2::DeleteNodes( size_t buckets, - _wxHashTable_NodeBase** table, - NodeDtor dtor ) -{ - size_t i; - - for( i = 0; i < buckets; ++i ) - { - _wxHashTable_NodeBase* node = table[i]; - _wxHashTable_NodeBase* tmp; - - while( node ) - { - tmp = node->m_nxt; - dtor( node ); - node = tmp; - } - } - - memset( table, 0, buckets * sizeof(void*) ); -} - -void _wxHashTableBase2::CopyHashTable( _wxHashTable_NodeBase** srcTable, - size_t srcBuckets, - _wxHashTableBase2* dst, - _wxHashTable_NodeBase** dstTable, - BucketFromNode func, ProcessNode proc ) -{ - for( size_t i = 0; i < srcBuckets; ++i ) - { - _wxHashTable_NodeBase* nextnode; - - for( _wxHashTable_NodeBase* node = srcTable[i]; node; node = nextnode ) - { - size_t bucket = func( dst, node ); - - nextnode = node->m_nxt; - _wxHashTable_NodeBase* newnode = proc( node ); - newnode->m_nxt = dstTable[bucket]; - dstTable[bucket] = newnode; - } - } -} - -_wxHashTable_NodeBase* _wxHashTableBase2::DummyProcessNode(_wxHashTable_NodeBase* node) -{ - return node; -} - -#endif // !wxUSE_STL || !defined(HAVE_STL_HASH_MAP) +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/hashmap.cpp +// Purpose: wxHashMap implementation +// Author: Mattia Barbon +// Modified by: +// Created: 29/01/2002 +// RCS-ID: $Id: hashmap.cpp 39802 2006-06-20 10:24:07Z ABX $ +// Copyright: (c) Mattia Barbon +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#include "wx/hashmap.h" + +/* FYI: This is the "One-at-a-Time" algorithm by Bob Jenkins */ +/* from requirements by Colin Plumb. */ +/* (http://burtleburtle.net/bob/hash/doobs.html) */ +/* adapted from Perl sources ( hv.h ) */ +unsigned long wxStringHash::wxCharStringHash( const wxChar* k ) +{ + unsigned long hash = 0; + + while( *k ) + { + hash += *k++; + hash += (hash << 10); + hash ^= (hash >> 6); + } + hash += (hash << 3); + hash ^= (hash >> 11); + + return hash + (hash << 15); +} + +#if wxUSE_UNICODE +unsigned long wxStringHash::charStringHash( const char* k ) +{ + unsigned long hash = 0; + + while( *k ) + { + hash += *k++; + hash += (hash << 10); + hash ^= (hash >> 6); + } + hash += (hash << 3); + hash ^= (hash >> 11); + + return hash + (hash << 15); +} +#endif + +#if !wxUSE_STL || !defined(HAVE_STL_HASH_MAP) + +/* from SGI STL */ +const unsigned long _wxHashTableBase2::ms_primes[prime_count] = +{ + 7ul, 13ul, 29ul, + 53ul, 97ul, 193ul, 389ul, 769ul, + 1543ul, 3079ul, 6151ul, 12289ul, 24593ul, + 49157ul, 98317ul, 196613ul, 393241ul, 786433ul, + 1572869ul, 3145739ul, 6291469ul, 12582917ul, 25165843ul, + 50331653ul, 100663319ul, 201326611ul, 402653189ul, 805306457ul, + 1610612741ul, 3221225473ul, 4294967291ul +}; + +unsigned long _wxHashTableBase2::GetNextPrime( unsigned long n ) +{ + const unsigned long* ptr = &ms_primes[0]; + for( size_t i = 0; i < prime_count; ++i, ++ptr ) + { + if( n < *ptr ) + return *ptr; + } + + /* someone might try to alloc a 2^32-element hash table */ + wxFAIL_MSG( _T("hash table too big?") ); + + /* quiet warning */ + return 0; +} + +unsigned long _wxHashTableBase2::GetPreviousPrime( unsigned long n ) +{ + const unsigned long* ptr = &ms_primes[prime_count - 1]; + + for( size_t i = 0; i < prime_count; ++i, --ptr ) + { + if( n > *ptr ) + return *ptr; + } + + /* quiet warning */ + return 1; +} + +void _wxHashTableBase2::DeleteNodes( size_t buckets, + _wxHashTable_NodeBase** table, + NodeDtor dtor ) +{ + size_t i; + + for( i = 0; i < buckets; ++i ) + { + _wxHashTable_NodeBase* node = table[i]; + _wxHashTable_NodeBase* tmp; + + while( node ) + { + tmp = node->m_nxt; + dtor( node ); + node = tmp; + } + } + + memset( table, 0, buckets * sizeof(void*) ); +} + +void _wxHashTableBase2::CopyHashTable( _wxHashTable_NodeBase** srcTable, + size_t srcBuckets, + _wxHashTableBase2* dst, + _wxHashTable_NodeBase** dstTable, + BucketFromNode func, ProcessNode proc ) +{ + for( size_t i = 0; i < srcBuckets; ++i ) + { + _wxHashTable_NodeBase* nextnode; + + for( _wxHashTable_NodeBase* node = srcTable[i]; node; node = nextnode ) + { + size_t bucket = func( dst, node ); + + nextnode = node->m_nxt; + _wxHashTable_NodeBase* newnode = proc( node ); + newnode->m_nxt = dstTable[bucket]; + dstTable[bucket] = newnode; + } + } +} + +_wxHashTable_NodeBase* _wxHashTableBase2::DummyProcessNode(_wxHashTable_NodeBase* node) +{ + return node; +} + +#endif // !wxUSE_STL || !defined(HAVE_STL_HASH_MAP) diff --git a/Externals/wxWidgets/src/common/helpbase.cpp b/Externals/wxWidgets/src/common/helpbase.cpp index b1f95e2def..83ede72d74 100644 --- a/Externals/wxWidgets/src/common/helpbase.cpp +++ b/Externals/wxWidgets/src/common/helpbase.cpp @@ -1,28 +1,28 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/helpbase.cpp -// Purpose: Help system base classes -// Author: Julian Smart -// Modified by: -// Created: 04/01/98 -// RCS-ID: $Id: helpbase.cpp 38787 2006-04-18 07:24:35Z ABX $ -// Copyright: (c) Julian Smart -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_HELP - -#ifndef WX_PRECOMP -#endif - -#include "wx/helpbase.h" - -IMPLEMENT_CLASS(wxHelpControllerBase, wxObject) - -#endif // wxUSE_HELP +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/helpbase.cpp +// Purpose: Help system base classes +// Author: Julian Smart +// Modified by: +// Created: 04/01/98 +// RCS-ID: $Id: helpbase.cpp 38787 2006-04-18 07:24:35Z ABX $ +// Copyright: (c) Julian Smart +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_HELP + +#ifndef WX_PRECOMP +#endif + +#include "wx/helpbase.h" + +IMPLEMENT_CLASS(wxHelpControllerBase, wxObject) + +#endif // wxUSE_HELP diff --git a/Externals/wxWidgets/src/common/http.cpp b/Externals/wxWidgets/src/common/http.cpp index f5bceedde8..cf21f6a34d 100644 --- a/Externals/wxWidgets/src/common/http.cpp +++ b/Externals/wxWidgets/src/common/http.cpp @@ -1,422 +1,422 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/http.cpp -// Purpose: HTTP protocol -// Author: Guilhem Lavaux -// Modified by: Simo Virokannas (authentication, Dec 2005) -// Created: August 1997 -// RCS-ID: $Id: http.cpp 44660 2007-03-07 23:07:17Z VZ $ -// Copyright: (c) 1997, 1998 Guilhem Lavaux -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_PROTOCOL_HTTP - -#include -#include - -#ifndef WX_PRECOMP - #include "wx/string.h" - #include "wx/app.h" -#endif - -#include "wx/tokenzr.h" -#include "wx/socket.h" -#include "wx/protocol/protocol.h" -#include "wx/url.h" -#include "wx/protocol/http.h" -#include "wx/sckstrm.h" - -IMPLEMENT_DYNAMIC_CLASS(wxHTTP, wxProtocol) -IMPLEMENT_PROTOCOL(wxHTTP, wxT("http"), wxT("80"), true) - -wxHTTP::wxHTTP() - : wxProtocol() -{ - m_addr = NULL; - m_read = false; - m_proxy_mode = false; - m_post_buf = wxEmptyString; - m_http_response = 0; - - SetNotify(wxSOCKET_LOST_FLAG); -} - -wxHTTP::~wxHTTP() -{ - ClearHeaders(); - - delete m_addr; -} - -void wxHTTP::ClearHeaders() -{ - m_headers.clear(); -} - -wxString wxHTTP::GetContentType() -{ - return GetHeader(wxT("Content-Type")); -} - -void wxHTTP::SetProxyMode(bool on) -{ - m_proxy_mode = on; -} - -wxHTTP::wxHeaderIterator wxHTTP::FindHeader(const wxString& header) -{ - wxHeaderIterator it = m_headers.begin(); - for ( wxHeaderIterator en = m_headers.end(); it != en; ++it ) - { - if ( wxStricmp(it->first, header) == 0 ) - break; - } - - return it; -} - -wxHTTP::wxHeaderConstIterator wxHTTP::FindHeader(const wxString& header) const -{ - wxHeaderConstIterator it = m_headers.begin(); - for ( wxHeaderConstIterator en = m_headers.end(); it != en; ++it ) - { - if ( wxStricmp(it->first, header) == 0 ) - break; - } - - return it; -} - -void wxHTTP::SetHeader(const wxString& header, const wxString& h_data) -{ - if (m_read) { - ClearHeaders(); - m_read = false; - } - - wxHeaderIterator it = FindHeader(header); - if (it != m_headers.end()) - it->second = h_data; - else - m_headers[header] = h_data; -} - -wxString wxHTTP::GetHeader(const wxString& header) const -{ - wxHeaderConstIterator it = FindHeader(header); - - return it == m_headers.end() ? wxGetEmptyString() : it->second; -} - -wxString wxHTTP::GenerateAuthString(const wxString& user, const wxString& pass) const -{ - static const char *base64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - - wxString buf; - wxString toencode; - - buf.Printf(wxT("Basic ")); - - toencode.Printf(wxT("%s:%s"),user.c_str(),pass.c_str()); - - size_t len = toencode.length(); - const wxChar *from = toencode.c_str(); - while (len >= 3) { // encode full blocks first - buf << wxString::Format(wxT("%c%c"), base64[(from[0] >> 2) & 0x3f], base64[((from[0] << 4) & 0x30) | ((from[1] >> 4) & 0xf)]); - buf << wxString::Format(wxT("%c%c"), base64[((from[1] << 2) & 0x3c) | ((from[2] >> 6) & 0x3)], base64[from[2] & 0x3f]); - from += 3; - len -= 3; - } - if (len > 0) { // pad the remaining characters - buf << wxString::Format(wxT("%c"), base64[(from[0] >> 2) & 0x3f]); - if (len == 1) { - buf << wxString::Format(wxT("%c="), base64[(from[0] << 4) & 0x30]); - } else { - buf << wxString::Format(wxT("%c%c"), base64[((from[0] << 4) & 0x30) | ((from[1] >> 4) & 0xf)], base64[(from[1] << 2) & 0x3c]); - } - buf << wxString::Format(wxT("=")); - } - - return buf; -} - -void wxHTTP::SetPostBuffer(const wxString& post_buf) -{ - m_post_buf = post_buf; -} - -void wxHTTP::SendHeaders() -{ - typedef wxStringToStringHashMap::iterator iterator; - wxString buf; - - for (iterator it = m_headers.begin(), en = m_headers.end(); it != en; ++it ) - { - buf.Printf(wxT("%s: %s\r\n"), it->first.c_str(), it->second.c_str()); - - const wxWX2MBbuf cbuf = buf.mb_str(); - Write(cbuf, strlen(cbuf)); - } -} - -bool wxHTTP::ParseHeaders() -{ - wxString line; - wxStringTokenizer tokenzr; - - ClearHeaders(); - m_read = true; - - for ( ;; ) - { - m_perr = ReadLine(this, line); - if (m_perr != wxPROTO_NOERR) - return false; - - if (line.length() == 0) - break; - - wxString left_str = line.BeforeFirst(':'); - m_headers[left_str] = line.AfterFirst(':').Strip(wxString::both); - } - return true; -} - -bool wxHTTP::Connect(const wxString& host, unsigned short port) -{ - wxIPV4address *addr; - - if (m_addr) { - delete m_addr; - m_addr = NULL; - Close(); - } - - m_addr = addr = new wxIPV4address(); - - if (!addr->Hostname(host)) { - delete m_addr; - m_addr = NULL; - m_perr = wxPROTO_NETERR; - return false; - } - - if ( port ) - addr->Service(port); - else if (!addr->Service(wxT("http"))) - addr->Service(80); - - SetHeader(wxT("Host"), host); - - return true; -} - -bool wxHTTP::Connect(wxSockAddress& addr, bool WXUNUSED(wait)) -{ - if (m_addr) { - delete m_addr; - Close(); - } - - m_addr = addr.Clone(); - - wxIPV4address *ipv4addr = wxDynamicCast(&addr, wxIPV4address); - if (ipv4addr) - SetHeader(wxT("Host"), ipv4addr->OrigHostname()); - - return true; -} - -bool wxHTTP::BuildRequest(const wxString& path, wxHTTP_Req req) -{ - const wxChar *request; - - switch (req) - { - case wxHTTP_GET: - request = wxT("GET"); - break; - - case wxHTTP_POST: - request = wxT("POST"); - if ( GetHeader( wxT("Content-Length") ).IsNull() ) - SetHeader( wxT("Content-Length"), wxString::Format( wxT("%lu"), (unsigned long)m_post_buf.Len() ) ); - break; - - default: - return false; - } - - m_http_response = 0; - - // If there is no User-Agent defined, define it. - if (GetHeader(wxT("User-Agent")).IsNull()) - SetHeader(wxT("User-Agent"), wxT("wxWidgets 2.x")); - - // Send authentication information - if (!m_username.empty() || !m_password.empty()) { - SetHeader(wxT("Authorization"), GenerateAuthString(m_username, m_password)); - } - - SaveState(); - - // we may use non blocking sockets only if we can dispatch events from them - SetFlags( wxIsMainThread() && wxApp::IsMainLoopRunning() ? wxSOCKET_NONE - : wxSOCKET_BLOCK ); - Notify(false); - - wxString buf; - buf.Printf(wxT("%s %s HTTP/1.0\r\n"), request, path.c_str()); - const wxWX2MBbuf pathbuf = wxConvLocal.cWX2MB(buf); - Write(pathbuf, strlen(wxMBSTRINGCAST pathbuf)); - SendHeaders(); - Write("\r\n", 2); - - if ( req == wxHTTP_POST ) { - Write(m_post_buf.mbc_str(), m_post_buf.Len()); - m_post_buf = wxEmptyString; - } - - wxString tmp_str; - m_perr = ReadLine(this, tmp_str); - if (m_perr != wxPROTO_NOERR) { - RestoreState(); - return false; - } - - if (!tmp_str.Contains(wxT("HTTP/"))) { - // TODO: support HTTP v0.9 which can have no header. - // FIXME: tmp_str is not put back in the in-queue of the socket. - SetHeader(wxT("Content-Length"), wxT("-1")); - SetHeader(wxT("Content-Type"), wxT("none/none")); - RestoreState(); - return true; - } - - wxStringTokenizer token(tmp_str,wxT(' ')); - wxString tmp_str2; - bool ret_value; - - token.NextToken(); - tmp_str2 = token.NextToken(); - - m_http_response = wxAtoi(tmp_str2); - - switch (tmp_str2[0u]) - { - case wxT('1'): - /* INFORMATION / SUCCESS */ - break; - - case wxT('2'): - /* SUCCESS */ - break; - - case wxT('3'): - /* REDIRECTION */ - break; - - default: - m_perr = wxPROTO_NOFILE; - RestoreState(); - return false; - } - - ret_value = ParseHeaders(); - RestoreState(); - return ret_value; -} - -class wxHTTPStream : public wxSocketInputStream -{ -public: - wxHTTP *m_http; - size_t m_httpsize; - unsigned long m_read_bytes; - - wxHTTPStream(wxHTTP *http) : wxSocketInputStream(*http), m_http(http) {} - size_t GetSize() const { return m_httpsize; } - virtual ~wxHTTPStream(void) { m_http->Abort(); } - -protected: - size_t OnSysRead(void *buffer, size_t bufsize); - - DECLARE_NO_COPY_CLASS(wxHTTPStream) -}; - -size_t wxHTTPStream::OnSysRead(void *buffer, size_t bufsize) -{ - if (m_httpsize > 0 && m_read_bytes >= m_httpsize) - { - m_lasterror = wxSTREAM_EOF; - return 0; - } - - size_t ret = wxSocketInputStream::OnSysRead(buffer, bufsize); - m_read_bytes += ret; - - if (m_httpsize==(size_t)-1 && m_lasterror == wxSTREAM_READ_ERROR ) - { - // if m_httpsize is (size_t) -1 this means read until connection closed - // which is equivalent to getting a READ_ERROR, for clients however this - // must be translated into EOF, as it is the expected way of signalling - // end end of the content - m_lasterror = wxSTREAM_EOF ; - } - - return ret; -} - -bool wxHTTP::Abort(void) -{ - return wxSocketClient::Close(); -} - -wxInputStream *wxHTTP::GetInputStream(const wxString& path) -{ - wxHTTPStream *inp_stream; - - wxString new_path; - - m_perr = wxPROTO_CONNERR; - if (!m_addr) - return NULL; - - // We set m_connected back to false so wxSocketBase will know what to do. -#ifdef __WXMAC__ - wxSocketClient::Connect(*m_addr , false ); - wxSocketClient::WaitOnConnect(10); - - if (!wxSocketClient::IsConnected()) - return NULL; -#else - if (!wxProtocol::Connect(*m_addr)) - return NULL; -#endif - - if (!BuildRequest(path, m_post_buf.empty() ? wxHTTP_GET : wxHTTP_POST)) - return NULL; - - inp_stream = new wxHTTPStream(this); - - if (!GetHeader(wxT("Content-Length")).empty()) - inp_stream->m_httpsize = wxAtoi(WXSTRINGCAST GetHeader(wxT("Content-Length"))); - else - inp_stream->m_httpsize = (size_t)-1; - - inp_stream->m_read_bytes = 0; - - Notify(false); - SetFlags(wxSOCKET_BLOCK | wxSOCKET_WAITALL); - - return inp_stream; -} - -#endif // wxUSE_PROTOCOL_HTTP +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/http.cpp +// Purpose: HTTP protocol +// Author: Guilhem Lavaux +// Modified by: Simo Virokannas (authentication, Dec 2005) +// Created: August 1997 +// RCS-ID: $Id: http.cpp 44660 2007-03-07 23:07:17Z VZ $ +// Copyright: (c) 1997, 1998 Guilhem Lavaux +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_PROTOCOL_HTTP + +#include +#include + +#ifndef WX_PRECOMP + #include "wx/string.h" + #include "wx/app.h" +#endif + +#include "wx/tokenzr.h" +#include "wx/socket.h" +#include "wx/protocol/protocol.h" +#include "wx/url.h" +#include "wx/protocol/http.h" +#include "wx/sckstrm.h" + +IMPLEMENT_DYNAMIC_CLASS(wxHTTP, wxProtocol) +IMPLEMENT_PROTOCOL(wxHTTP, wxT("http"), wxT("80"), true) + +wxHTTP::wxHTTP() + : wxProtocol() +{ + m_addr = NULL; + m_read = false; + m_proxy_mode = false; + m_post_buf = wxEmptyString; + m_http_response = 0; + + SetNotify(wxSOCKET_LOST_FLAG); +} + +wxHTTP::~wxHTTP() +{ + ClearHeaders(); + + delete m_addr; +} + +void wxHTTP::ClearHeaders() +{ + m_headers.clear(); +} + +wxString wxHTTP::GetContentType() +{ + return GetHeader(wxT("Content-Type")); +} + +void wxHTTP::SetProxyMode(bool on) +{ + m_proxy_mode = on; +} + +wxHTTP::wxHeaderIterator wxHTTP::FindHeader(const wxString& header) +{ + wxHeaderIterator it = m_headers.begin(); + for ( wxHeaderIterator en = m_headers.end(); it != en; ++it ) + { + if ( wxStricmp(it->first, header) == 0 ) + break; + } + + return it; +} + +wxHTTP::wxHeaderConstIterator wxHTTP::FindHeader(const wxString& header) const +{ + wxHeaderConstIterator it = m_headers.begin(); + for ( wxHeaderConstIterator en = m_headers.end(); it != en; ++it ) + { + if ( wxStricmp(it->first, header) == 0 ) + break; + } + + return it; +} + +void wxHTTP::SetHeader(const wxString& header, const wxString& h_data) +{ + if (m_read) { + ClearHeaders(); + m_read = false; + } + + wxHeaderIterator it = FindHeader(header); + if (it != m_headers.end()) + it->second = h_data; + else + m_headers[header] = h_data; +} + +wxString wxHTTP::GetHeader(const wxString& header) const +{ + wxHeaderConstIterator it = FindHeader(header); + + return it == m_headers.end() ? wxGetEmptyString() : it->second; +} + +wxString wxHTTP::GenerateAuthString(const wxString& user, const wxString& pass) const +{ + static const char *base64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + + wxString buf; + wxString toencode; + + buf.Printf(wxT("Basic ")); + + toencode.Printf(wxT("%s:%s"),user.c_str(),pass.c_str()); + + size_t len = toencode.length(); + const wxChar *from = toencode.c_str(); + while (len >= 3) { // encode full blocks first + buf << wxString::Format(wxT("%c%c"), base64[(from[0] >> 2) & 0x3f], base64[((from[0] << 4) & 0x30) | ((from[1] >> 4) & 0xf)]); + buf << wxString::Format(wxT("%c%c"), base64[((from[1] << 2) & 0x3c) | ((from[2] >> 6) & 0x3)], base64[from[2] & 0x3f]); + from += 3; + len -= 3; + } + if (len > 0) { // pad the remaining characters + buf << wxString::Format(wxT("%c"), base64[(from[0] >> 2) & 0x3f]); + if (len == 1) { + buf << wxString::Format(wxT("%c="), base64[(from[0] << 4) & 0x30]); + } else { + buf << wxString::Format(wxT("%c%c"), base64[((from[0] << 4) & 0x30) | ((from[1] >> 4) & 0xf)], base64[(from[1] << 2) & 0x3c]); + } + buf << wxString::Format(wxT("=")); + } + + return buf; +} + +void wxHTTP::SetPostBuffer(const wxString& post_buf) +{ + m_post_buf = post_buf; +} + +void wxHTTP::SendHeaders() +{ + typedef wxStringToStringHashMap::iterator iterator; + wxString buf; + + for (iterator it = m_headers.begin(), en = m_headers.end(); it != en; ++it ) + { + buf.Printf(wxT("%s: %s\r\n"), it->first.c_str(), it->second.c_str()); + + const wxWX2MBbuf cbuf = buf.mb_str(); + Write(cbuf, strlen(cbuf)); + } +} + +bool wxHTTP::ParseHeaders() +{ + wxString line; + wxStringTokenizer tokenzr; + + ClearHeaders(); + m_read = true; + + for ( ;; ) + { + m_perr = ReadLine(this, line); + if (m_perr != wxPROTO_NOERR) + return false; + + if (line.length() == 0) + break; + + wxString left_str = line.BeforeFirst(':'); + m_headers[left_str] = line.AfterFirst(':').Strip(wxString::both); + } + return true; +} + +bool wxHTTP::Connect(const wxString& host, unsigned short port) +{ + wxIPV4address *addr; + + if (m_addr) { + delete m_addr; + m_addr = NULL; + Close(); + } + + m_addr = addr = new wxIPV4address(); + + if (!addr->Hostname(host)) { + delete m_addr; + m_addr = NULL; + m_perr = wxPROTO_NETERR; + return false; + } + + if ( port ) + addr->Service(port); + else if (!addr->Service(wxT("http"))) + addr->Service(80); + + SetHeader(wxT("Host"), host); + + return true; +} + +bool wxHTTP::Connect(wxSockAddress& addr, bool WXUNUSED(wait)) +{ + if (m_addr) { + delete m_addr; + Close(); + } + + m_addr = addr.Clone(); + + wxIPV4address *ipv4addr = wxDynamicCast(&addr, wxIPV4address); + if (ipv4addr) + SetHeader(wxT("Host"), ipv4addr->OrigHostname()); + + return true; +} + +bool wxHTTP::BuildRequest(const wxString& path, wxHTTP_Req req) +{ + const wxChar *request; + + switch (req) + { + case wxHTTP_GET: + request = wxT("GET"); + break; + + case wxHTTP_POST: + request = wxT("POST"); + if ( GetHeader( wxT("Content-Length") ).IsNull() ) + SetHeader( wxT("Content-Length"), wxString::Format( wxT("%lu"), (unsigned long)m_post_buf.Len() ) ); + break; + + default: + return false; + } + + m_http_response = 0; + + // If there is no User-Agent defined, define it. + if (GetHeader(wxT("User-Agent")).IsNull()) + SetHeader(wxT("User-Agent"), wxT("wxWidgets 2.x")); + + // Send authentication information + if (!m_username.empty() || !m_password.empty()) { + SetHeader(wxT("Authorization"), GenerateAuthString(m_username, m_password)); + } + + SaveState(); + + // we may use non blocking sockets only if we can dispatch events from them + SetFlags( wxIsMainThread() && wxApp::IsMainLoopRunning() ? wxSOCKET_NONE + : wxSOCKET_BLOCK ); + Notify(false); + + wxString buf; + buf.Printf(wxT("%s %s HTTP/1.0\r\n"), request, path.c_str()); + const wxWX2MBbuf pathbuf = wxConvLocal.cWX2MB(buf); + Write(pathbuf, strlen(wxMBSTRINGCAST pathbuf)); + SendHeaders(); + Write("\r\n", 2); + + if ( req == wxHTTP_POST ) { + Write(m_post_buf.mbc_str(), m_post_buf.Len()); + m_post_buf = wxEmptyString; + } + + wxString tmp_str; + m_perr = ReadLine(this, tmp_str); + if (m_perr != wxPROTO_NOERR) { + RestoreState(); + return false; + } + + if (!tmp_str.Contains(wxT("HTTP/"))) { + // TODO: support HTTP v0.9 which can have no header. + // FIXME: tmp_str is not put back in the in-queue of the socket. + SetHeader(wxT("Content-Length"), wxT("-1")); + SetHeader(wxT("Content-Type"), wxT("none/none")); + RestoreState(); + return true; + } + + wxStringTokenizer token(tmp_str,wxT(' ')); + wxString tmp_str2; + bool ret_value; + + token.NextToken(); + tmp_str2 = token.NextToken(); + + m_http_response = wxAtoi(tmp_str2); + + switch (tmp_str2[0u]) + { + case wxT('1'): + /* INFORMATION / SUCCESS */ + break; + + case wxT('2'): + /* SUCCESS */ + break; + + case wxT('3'): + /* REDIRECTION */ + break; + + default: + m_perr = wxPROTO_NOFILE; + RestoreState(); + return false; + } + + ret_value = ParseHeaders(); + RestoreState(); + return ret_value; +} + +class wxHTTPStream : public wxSocketInputStream +{ +public: + wxHTTP *m_http; + size_t m_httpsize; + unsigned long m_read_bytes; + + wxHTTPStream(wxHTTP *http) : wxSocketInputStream(*http), m_http(http) {} + size_t GetSize() const { return m_httpsize; } + virtual ~wxHTTPStream(void) { m_http->Abort(); } + +protected: + size_t OnSysRead(void *buffer, size_t bufsize); + + DECLARE_NO_COPY_CLASS(wxHTTPStream) +}; + +size_t wxHTTPStream::OnSysRead(void *buffer, size_t bufsize) +{ + if (m_httpsize > 0 && m_read_bytes >= m_httpsize) + { + m_lasterror = wxSTREAM_EOF; + return 0; + } + + size_t ret = wxSocketInputStream::OnSysRead(buffer, bufsize); + m_read_bytes += ret; + + if (m_httpsize==(size_t)-1 && m_lasterror == wxSTREAM_READ_ERROR ) + { + // if m_httpsize is (size_t) -1 this means read until connection closed + // which is equivalent to getting a READ_ERROR, for clients however this + // must be translated into EOF, as it is the expected way of signalling + // end end of the content + m_lasterror = wxSTREAM_EOF ; + } + + return ret; +} + +bool wxHTTP::Abort(void) +{ + return wxSocketClient::Close(); +} + +wxInputStream *wxHTTP::GetInputStream(const wxString& path) +{ + wxHTTPStream *inp_stream; + + wxString new_path; + + m_perr = wxPROTO_CONNERR; + if (!m_addr) + return NULL; + + // We set m_connected back to false so wxSocketBase will know what to do. +#ifdef __WXMAC__ + wxSocketClient::Connect(*m_addr , false ); + wxSocketClient::WaitOnConnect(10); + + if (!wxSocketClient::IsConnected()) + return NULL; +#else + if (!wxProtocol::Connect(*m_addr)) + return NULL; +#endif + + if (!BuildRequest(path, m_post_buf.empty() ? wxHTTP_GET : wxHTTP_POST)) + return NULL; + + inp_stream = new wxHTTPStream(this); + + if (!GetHeader(wxT("Content-Length")).empty()) + inp_stream->m_httpsize = wxAtoi(WXSTRINGCAST GetHeader(wxT("Content-Length"))); + else + inp_stream->m_httpsize = (size_t)-1; + + inp_stream->m_read_bytes = 0; + + Notify(false); + SetFlags(wxSOCKET_BLOCK | wxSOCKET_WAITALL); + + return inp_stream; +} + +#endif // wxUSE_PROTOCOL_HTTP diff --git a/Externals/wxWidgets/src/common/iconbndl.cpp b/Externals/wxWidgets/src/common/iconbndl.cpp index 56ccc004b8..98805d7e8a 100644 --- a/Externals/wxWidgets/src/common/iconbndl.cpp +++ b/Externals/wxWidgets/src/common/iconbndl.cpp @@ -1,142 +1,142 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/iconbndl.cpp -// Purpose: wxIconBundle -// Author: Mattia Barbon -// Created: 23.03.2002 -// RCS-ID: $Id: iconbndl.cpp 40654 2006-08-17 16:08:13Z VS $ -// Copyright: (c) Mattia barbon -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#include "wx/iconbndl.h" - -#ifndef WX_PRECOMP - #include "wx/settings.h" - #include "wx/icon.h" - #include "wx/log.h" - #include "wx/intl.h" - #include "wx/bitmap.h" - #include "wx/image.h" -#endif - -#include "wx/arrimpl.cpp" - -WX_DEFINE_OBJARRAY(wxIconArray) - -const wxIconBundle& wxIconBundle::operator =( const wxIconBundle& ic ) -{ - if( this == &ic ) return *this; - - size_t i, max = ic.m_icons.GetCount(); - - DeleteIcons(); - for( i = 0; i < max; ++i ) - m_icons.Add( ic.m_icons[i] ); - - return *this; -} - -void wxIconBundle::DeleteIcons() -{ - m_icons.Empty(); -} - -#if wxUSE_IMAGE -void wxIconBundle::AddIcon( const wxString& file, long type ) -#else -void wxIconBundle::AddIcon( const wxString& WXUNUSED(file), long WXUNUSED(type) ) -#endif -{ -#if wxUSE_IMAGE && (!defined(__WXMSW__) || wxUSE_WXDIB) - size_t count = wxImage::GetImageCount( file, type ); - size_t i; - wxImage image; - - for( i = 0; i < count; ++i ) - { - if( !image.LoadFile( file, type, i ) ) - { - wxLogError( _("Failed to load image %d from file '%s'."), - i, file.c_str() ); - continue; - } - - wxIcon* tmp = new wxIcon(); - tmp->CopyFromBitmap( wxBitmap( image ) ); - AddIcon( *tmp ); - delete tmp; - } -#endif -} - -const wxIcon& wxIconBundle::GetIcon( const wxSize& size ) const -{ - // temp. variable needed to fix Borland C++ 5.5.1 problem - // with passing a return value through two functions - wxIcon *tmp; - - size_t max = m_icons.GetCount(); - - // if we have one or no icon, we can return now without doing more work: - if ( max <= 1 ) - { - if ( max == 1 ) // fix for broken BCC - tmp = &m_icons[0]; - else // max == 0 - tmp = &wxNullIcon; - return *tmp; - } - - // there are more icons, find the best match: - wxCoord sysX = wxSystemSettings::GetMetric( wxSYS_ICON_X ), - sysY = wxSystemSettings::GetMetric( wxSYS_ICON_Y ); - - wxIcon *sysIcon = 0; - - for( size_t i = 0; i < max; i++ ) - { - if( !m_icons[i].Ok() ) - continue; - wxCoord sx = m_icons[i].GetWidth(), sy = m_icons[i].GetHeight(); - // requested size - if( sx == size.x && sy == size.y ) - { - tmp = &m_icons[i]; // fix for broken BCC - return *tmp; - } - // keep track if there is a system-size icon - if( sx == sysX && sy == sysY ) - sysIcon = &m_icons[i]; - } - - // return the system-sized icon if we've got one - if( sysIcon ) return *sysIcon; - // we certainly have at least one icon thanks to the <=1 check above - tmp = &m_icons[0]; - return *tmp; -} - -void wxIconBundle::AddIcon( const wxIcon& icon ) -{ - size_t i, max = m_icons.GetCount(); - - for( i = 0; i < max; ++i ) - { - wxIcon& tmp = m_icons[i]; - if( tmp.Ok() && tmp.GetWidth() == icon.GetWidth() && - tmp.GetHeight() == icon.GetHeight() ) - { - tmp = icon; - return; - } - } - - m_icons.Add( icon ); -} +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/iconbndl.cpp +// Purpose: wxIconBundle +// Author: Mattia Barbon +// Created: 23.03.2002 +// RCS-ID: $Id: iconbndl.cpp 40654 2006-08-17 16:08:13Z VS $ +// Copyright: (c) Mattia barbon +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#include "wx/iconbndl.h" + +#ifndef WX_PRECOMP + #include "wx/settings.h" + #include "wx/icon.h" + #include "wx/log.h" + #include "wx/intl.h" + #include "wx/bitmap.h" + #include "wx/image.h" +#endif + +#include "wx/arrimpl.cpp" + +WX_DEFINE_OBJARRAY(wxIconArray) + +const wxIconBundle& wxIconBundle::operator =( const wxIconBundle& ic ) +{ + if( this == &ic ) return *this; + + size_t i, max = ic.m_icons.GetCount(); + + DeleteIcons(); + for( i = 0; i < max; ++i ) + m_icons.Add( ic.m_icons[i] ); + + return *this; +} + +void wxIconBundle::DeleteIcons() +{ + m_icons.Empty(); +} + +#if wxUSE_IMAGE +void wxIconBundle::AddIcon( const wxString& file, long type ) +#else +void wxIconBundle::AddIcon( const wxString& WXUNUSED(file), long WXUNUSED(type) ) +#endif +{ +#if wxUSE_IMAGE && (!defined(__WXMSW__) || wxUSE_WXDIB) + size_t count = wxImage::GetImageCount( file, type ); + size_t i; + wxImage image; + + for( i = 0; i < count; ++i ) + { + if( !image.LoadFile( file, type, i ) ) + { + wxLogError( _("Failed to load image %d from file '%s'."), + i, file.c_str() ); + continue; + } + + wxIcon* tmp = new wxIcon(); + tmp->CopyFromBitmap( wxBitmap( image ) ); + AddIcon( *tmp ); + delete tmp; + } +#endif +} + +const wxIcon& wxIconBundle::GetIcon( const wxSize& size ) const +{ + // temp. variable needed to fix Borland C++ 5.5.1 problem + // with passing a return value through two functions + wxIcon *tmp; + + size_t max = m_icons.GetCount(); + + // if we have one or no icon, we can return now without doing more work: + if ( max <= 1 ) + { + if ( max == 1 ) // fix for broken BCC + tmp = &m_icons[0]; + else // max == 0 + tmp = &wxNullIcon; + return *tmp; + } + + // there are more icons, find the best match: + wxCoord sysX = wxSystemSettings::GetMetric( wxSYS_ICON_X ), + sysY = wxSystemSettings::GetMetric( wxSYS_ICON_Y ); + + wxIcon *sysIcon = 0; + + for( size_t i = 0; i < max; i++ ) + { + if( !m_icons[i].Ok() ) + continue; + wxCoord sx = m_icons[i].GetWidth(), sy = m_icons[i].GetHeight(); + // requested size + if( sx == size.x && sy == size.y ) + { + tmp = &m_icons[i]; // fix for broken BCC + return *tmp; + } + // keep track if there is a system-size icon + if( sx == sysX && sy == sysY ) + sysIcon = &m_icons[i]; + } + + // return the system-sized icon if we've got one + if( sysIcon ) return *sysIcon; + // we certainly have at least one icon thanks to the <=1 check above + tmp = &m_icons[0]; + return *tmp; +} + +void wxIconBundle::AddIcon( const wxIcon& icon ) +{ + size_t i, max = m_icons.GetCount(); + + for( i = 0; i < max; ++i ) + { + wxIcon& tmp = m_icons[i]; + if( tmp.Ok() && tmp.GetWidth() == icon.GetWidth() && + tmp.GetHeight() == icon.GetHeight() ) + { + tmp = icon; + return; + } + } + + m_icons.Add( icon ); +} diff --git a/Externals/wxWidgets/src/common/imagall.cpp b/Externals/wxWidgets/src/common/imagall.cpp index 311c567e55..90e66ac95f 100644 --- a/Externals/wxWidgets/src/common/imagall.cpp +++ b/Externals/wxWidgets/src/common/imagall.cpp @@ -1,64 +1,64 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/imagall.cpp -// Purpose: wxImage access all handler -// Author: Sylvain Bougnoux -// RCS-ID: $Id: imagall.cpp 42644 2006-10-29 18:58:25Z VZ $ -// Copyright: (c) Sylvain Bougnoux -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_IMAGE - -#ifndef WX_PRECOMP - #include "wx/image.h" -#endif - -//----------------------------------------------------------------------------- -// This function allows dynamic access to all image handlers compile within -// the library. This function should be in a separate file as some compilers -// link against the whole object file as long as just one of is function is called! - -void wxInitAllImageHandlers() -{ -#if wxUSE_LIBPNG - wxImage::AddHandler( new wxPNGHandler ); -#endif -#if wxUSE_LIBJPEG - wxImage::AddHandler( new wxJPEGHandler ); -#endif -#if wxUSE_LIBTIFF - wxImage::AddHandler( new wxTIFFHandler ); -#endif -#if wxUSE_GIF - wxImage::AddHandler( new wxGIFHandler ); -#endif -#if wxUSE_PNM - wxImage::AddHandler( new wxPNMHandler ); -#endif -#if wxUSE_PCX - wxImage::AddHandler( new wxPCXHandler ); -#endif -#if wxUSE_IFF - wxImage::AddHandler( new wxIFFHandler ); -#endif -#if wxUSE_ICO_CUR - wxImage::AddHandler( new wxICOHandler ); - wxImage::AddHandler( new wxCURHandler ); - wxImage::AddHandler( new wxANIHandler ); -#endif -#if wxUSE_TGA - wxImage::AddHandler( new wxTGAHandler ); -#endif -#if wxUSE_XPM - wxImage::AddHandler( new wxXPMHandler ); -#endif -} - -#endif // wxUSE_IMAGE +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/imagall.cpp +// Purpose: wxImage access all handler +// Author: Sylvain Bougnoux +// RCS-ID: $Id: imagall.cpp 42644 2006-10-29 18:58:25Z VZ $ +// Copyright: (c) Sylvain Bougnoux +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_IMAGE + +#ifndef WX_PRECOMP + #include "wx/image.h" +#endif + +//----------------------------------------------------------------------------- +// This function allows dynamic access to all image handlers compile within +// the library. This function should be in a separate file as some compilers +// link against the whole object file as long as just one of is function is called! + +void wxInitAllImageHandlers() +{ +#if wxUSE_LIBPNG + wxImage::AddHandler( new wxPNGHandler ); +#endif +#if wxUSE_LIBJPEG + wxImage::AddHandler( new wxJPEGHandler ); +#endif +#if wxUSE_LIBTIFF + wxImage::AddHandler( new wxTIFFHandler ); +#endif +#if wxUSE_GIF + wxImage::AddHandler( new wxGIFHandler ); +#endif +#if wxUSE_PNM + wxImage::AddHandler( new wxPNMHandler ); +#endif +#if wxUSE_PCX + wxImage::AddHandler( new wxPCXHandler ); +#endif +#if wxUSE_IFF + wxImage::AddHandler( new wxIFFHandler ); +#endif +#if wxUSE_ICO_CUR + wxImage::AddHandler( new wxICOHandler ); + wxImage::AddHandler( new wxCURHandler ); + wxImage::AddHandler( new wxANIHandler ); +#endif +#if wxUSE_TGA + wxImage::AddHandler( new wxTGAHandler ); +#endif +#if wxUSE_XPM + wxImage::AddHandler( new wxXPMHandler ); +#endif +} + +#endif // wxUSE_IMAGE diff --git a/Externals/wxWidgets/src/common/imagbmp.cpp b/Externals/wxWidgets/src/common/imagbmp.cpp index 6d6dbbc6e6..0d48451bb8 100644 --- a/Externals/wxWidgets/src/common/imagbmp.cpp +++ b/Externals/wxWidgets/src/common/imagbmp.cpp @@ -1,1356 +1,1356 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/imagbmp.cpp -// Purpose: wxImage BMP,ICO and CUR handlers -// Author: Robert Roebling, Chris Elliott -// RCS-ID: $Id: imagbmp.cpp 41819 2006-10-09 17:51:07Z VZ $ -// Copyright: (c) Robert Roebling, Chris Elliott -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_IMAGE - -#include "wx/imagbmp.h" - -#ifndef WX_PRECOMP - #ifdef __WXMSW__ - #include "wx/msw/wrapwin.h" - #endif - #include "wx/log.h" - #include "wx/app.h" - #include "wx/bitmap.h" - #include "wx/palette.h" - #include "wx/intl.h" -#endif - -#include "wx/filefn.h" -#include "wx/wfstream.h" -#include "wx/quantize.h" -#include "wx/anidecod.h" - -// For memcpy -#include - -#ifdef __SALFORDC__ -#ifdef FAR -#undef FAR -#endif -#endif - -//----------------------------------------------------------------------------- -// wxBMPHandler -//----------------------------------------------------------------------------- - -IMPLEMENT_DYNAMIC_CLASS(wxBMPHandler,wxImageHandler) - -#if wxUSE_STREAMS - -#ifndef BI_RGB - #define BI_RGB 0 -#endif - -#ifndef BI_RLE8 -#define BI_RLE8 1 -#endif - -#ifndef BI_RLE4 -#define BI_RLE4 2 -#endif - -#ifndef BI_BITFIELDS -#define BI_BITFIELDS 3 -#endif - -#define poffset (line * width * 3 + column * 3) - -bool wxBMPHandler::SaveFile(wxImage *image, - wxOutputStream& stream, - bool verbose) -{ - return SaveDib(image, stream, verbose, true/*IsBmp*/, false/*IsMask*/); -} - -bool wxBMPHandler::SaveDib(wxImage *image, - wxOutputStream& stream, - bool verbose, - bool IsBmp, - bool IsMask) - -{ - wxCHECK_MSG( image, false, _T("invalid pointer in wxBMPHandler::SaveFile") ); - - if ( !image->Ok() ) - { - if ( verbose ) - wxLogError(_("BMP: Couldn't save invalid image.")); - return false; - } - - // get the format of the BMP file to save, else use 24bpp - unsigned format = wxBMP_24BPP; - if ( image->HasOption(wxIMAGE_OPTION_BMP_FORMAT) ) - format = image->GetOptionInt(wxIMAGE_OPTION_BMP_FORMAT); - - wxUint16 bpp; // # of bits per pixel - int palette_size; // # of color map entries, ie. 2^bpp colors - - // set the bpp and appropriate palette_size, and do additional checks - if ( (format == wxBMP_1BPP) || (format == wxBMP_1BPP_BW) ) - { - bpp = 1; - palette_size = 2; - } - else if ( format == wxBMP_4BPP ) - { - bpp = 4; - palette_size = 16; - } - else if ( (format == wxBMP_8BPP) || (format == wxBMP_8BPP_GREY) || - (format == wxBMP_8BPP_RED) || (format == wxBMP_8BPP_PALETTE) ) - { - // need to set a wxPalette to use this, HOW TO CHECK IF VALID, SIZE? - if ((format == wxBMP_8BPP_PALETTE) -#if wxUSE_PALETTE - && !image->HasPalette() -#endif // wxUSE_PALETTE - ) - { - if ( verbose ) - wxLogError(_("BMP: wxImage doesn't have own wxPalette.")); - return false; - } - bpp = 8; - palette_size = 256; - } - else // you get 24bpp - { - format = wxBMP_24BPP; - bpp = 24; - palette_size = 0; - } - - unsigned width = image->GetWidth(); - unsigned row_padding = (4 - int(width*bpp/8.0) % 4) % 4; // # bytes to pad to dword - unsigned row_width = int(width * bpp/8.0) + row_padding; // # of bytes per row - - struct - { - // BitmapHeader: - wxUint16 magic; // format magic, always 'BM' - wxUint32 filesize; // total file size, inc. headers - wxUint32 reserved; // for future use - wxUint32 data_offset; // image data offset in the file - - // BitmapInfoHeader: - wxUint32 bih_size; // 2nd part's size - wxUint32 width, height; // bitmap's dimensions - wxUint16 planes; // num of planes - wxUint16 bpp; // bits per pixel - wxUint32 compression; // compression method - wxUint32 size_of_bmp; // size of the bitmap - wxUint32 h_res, v_res; // image resolution in dpi - wxUint32 num_clrs; // number of colors used - wxUint32 num_signif_clrs;// number of significant colors - } hdr; - - wxUint32 hdr_size = 14/*BitmapHeader*/ + 40/*BitmapInfoHeader*/; - - hdr.magic = wxUINT16_SWAP_ON_BE(0x4D42/*'BM'*/); - hdr.filesize = wxUINT32_SWAP_ON_BE( hdr_size + palette_size*4 + - row_width * image->GetHeight() ); - hdr.reserved = 0; - hdr.data_offset = wxUINT32_SWAP_ON_BE(hdr_size + palette_size*4); - - hdr.bih_size = wxUINT32_SWAP_ON_BE(hdr_size - 14); - hdr.width = wxUINT32_SWAP_ON_BE(image->GetWidth()); - if ( IsBmp ) - { - hdr.height = wxUINT32_SWAP_ON_BE(image->GetHeight()); - } - else - { - hdr.height = wxUINT32_SWAP_ON_BE(2 * image->GetHeight()); - } - hdr.planes = wxUINT16_SWAP_ON_BE(1); // always 1 plane - hdr.bpp = wxUINT16_SWAP_ON_BE(bpp); - hdr.compression = 0; // RGB uncompressed - hdr.size_of_bmp = wxUINT32_SWAP_ON_BE(row_width * image->GetHeight()); - hdr.h_res = hdr.v_res = wxUINT32_SWAP_ON_BE(72); // 72dpi is standard - hdr.num_clrs = wxUINT32_SWAP_ON_BE(palette_size); // # colors in colormap - hdr.num_signif_clrs = 0; // all colors are significant - - if ( IsBmp ) - { - if (// VS: looks ugly but compilers tend to do ugly things with structs, - // like aligning hdr.filesize's ofset to dword :( - // VZ: we should add padding then... - !stream.Write(&hdr.magic, 2) || - !stream.Write(&hdr.filesize, 4) || - !stream.Write(&hdr.reserved, 4) || - !stream.Write(&hdr.data_offset, 4) - ) - { - if (verbose) - wxLogError(_("BMP: Couldn't write the file (Bitmap) header.")); - return false; - } - } - if ( !IsMask ) - { - if ( - !stream.Write(&hdr.bih_size, 4) || - !stream.Write(&hdr.width, 4) || - !stream.Write(&hdr.height, 4) || - !stream.Write(&hdr.planes, 2) || - !stream.Write(&hdr.bpp, 2) || - !stream.Write(&hdr.compression, 4) || - !stream.Write(&hdr.size_of_bmp, 4) || - !stream.Write(&hdr.h_res, 4) || - !stream.Write(&hdr.v_res, 4) || - !stream.Write(&hdr.num_clrs, 4) || - !stream.Write(&hdr.num_signif_clrs, 4) - ) - { - if (verbose) - wxLogError(_("BMP: Couldn't write the file (BitmapInfo) header.")); - return false; - } - } - - wxPalette *palette = NULL; // entries for quantized images - wxUint8 *rgbquad = NULL; // for the RGBQUAD bytes for the colormap - wxImage *q_image = NULL; // destination for quantized image - - // if <24bpp use quantization to reduce colors for *some* of the formats - if ( (format == wxBMP_1BPP) || (format == wxBMP_4BPP) || - (format == wxBMP_8BPP) || (format == wxBMP_8BPP_PALETTE) ) - { - // make a new palette and quantize the image - if (format != wxBMP_8BPP_PALETTE) - { - q_image = new wxImage(); - - // I get a delete error using Quantize when desired colors > 236 - int quantize = ((palette_size > 236) ? 236 : palette_size); - // fill the destination too, it gives much nicer 4bpp images - wxQuantize::Quantize( *image, *q_image, &palette, quantize, 0, - wxQUANTIZE_FILL_DESTINATION_IMAGE ); - } - else - { -#if wxUSE_PALETTE - palette = new wxPalette(image->GetPalette()); -#endif // wxUSE_PALETTE - } - - int i; - unsigned char r, g, b; - rgbquad = new wxUint8 [palette_size*4]; - - for (i = 0; i < palette_size; i++) - { -#if wxUSE_PALETTE - if ( !palette->GetRGB(i, &r, &g, &b) ) -#endif // wxUSE_PALETTE - r = g = b = 0; - - rgbquad[i*4] = b; - rgbquad[i*4+1] = g; - rgbquad[i*4+2] = r; - rgbquad[i*4+3] = 0; - } - } - // make a 256 entry greyscale colormap or 2 entry black & white - else if ( (format == wxBMP_8BPP_GREY) || (format == wxBMP_8BPP_RED) || - (format == wxBMP_1BPP_BW) ) - { - rgbquad = new wxUint8 [palette_size*4]; - - for ( int i = 0; i < palette_size; i++ ) - { - // if 1BPP_BW then the value should be either 0 or 255 - wxUint8 c = (wxUint8)((i > 0) && (format == wxBMP_1BPP_BW) ? 255 : i); - - rgbquad[i*4] = - rgbquad[i*4+1] = - rgbquad[i*4+2] = c; - rgbquad[i*4+3] = 0; - } - } - - // if the colormap was made, then it needs to be written - if (rgbquad) - { - if ( !IsMask ) - { - if ( !stream.Write(rgbquad, palette_size*4) ) - { - if (verbose) - wxLogError(_("BMP: Couldn't write RGB color map.")); - delete[] rgbquad; -#if wxUSE_PALETTE - delete palette; -#endif // wxUSE_PALETTE - delete q_image; - return false; - } - } - delete []rgbquad; - } - - // pointer to the image data, use quantized if available - wxUint8 *data = (wxUint8*) image->GetData(); - if (q_image) if (q_image->Ok()) data = (wxUint8*) q_image->GetData(); - - wxUint8 *buffer = new wxUint8[row_width]; - memset(buffer, 0, row_width); - int y; unsigned x; - long int pixel; - - for (y = image->GetHeight() -1; y >= 0; y--) - { - if ( format == wxBMP_24BPP ) // 3 bytes per pixel red,green,blue - { - for ( x = 0; x < width; x++ ) - { - pixel = 3*(y*width + x); - - buffer[3*x ] = data[pixel+2]; - buffer[3*x + 1] = data[pixel+1]; - buffer[3*x + 2] = data[pixel]; - } - } - else if ((format == wxBMP_8BPP) || // 1 byte per pixel in color - (format == wxBMP_8BPP_PALETTE)) - { - for (x = 0; x < width; x++) - { - pixel = 3*(y*width + x); -#if wxUSE_PALETTE - buffer[x] = (wxUint8)palette->GetPixel( data[pixel], - data[pixel+1], - data[pixel+2] ); -#else - // FIXME: what should this be? use some std palette maybe? - buffer[x] = 0; -#endif // wxUSE_PALETTE - } - } - else if ( format == wxBMP_8BPP_GREY ) // 1 byte per pix, rgb ave to grey - { - for (x = 0; x < width; x++) - { - pixel = 3*(y*width + x); - buffer[x] = (wxUint8)(.299*data[pixel] + - .587*data[pixel+1] + - .114*data[pixel+2]); - } - } - else if ( format == wxBMP_8BPP_RED ) // 1 byte per pixel, red as greys - { - for (x = 0; x < width; x++) - { - buffer[x] = (wxUint8)data[3*(y*width + x)]; - } - } - else if ( format == wxBMP_4BPP ) // 4 bpp in color - { - for (x = 0; x < width; x+=2) - { - pixel = 3*(y*width + x); - - // fill buffer, ignore if > width -#if wxUSE_PALETTE - buffer[x/2] = (wxUint8)( - ((wxUint8)palette->GetPixel(data[pixel], - data[pixel+1], - data[pixel+2]) << 4) | - (((x+1) > width) - ? 0 - : ((wxUint8)palette->GetPixel(data[pixel+3], - data[pixel+4], - data[pixel+5]) )) ); -#else - // FIXME: what should this be? use some std palette maybe? - buffer[x/2] = 0; -#endif // wxUSE_PALETTE - } - } - else if ( format == wxBMP_1BPP ) // 1 bpp in "color" - { - for (x = 0; x < width; x+=8) - { - pixel = 3*(y*width + x); - -#if wxUSE_PALETTE - buffer[x/8] = (wxUint8)( - ((wxUint8)palette->GetPixel(data[pixel], data[pixel+1], data[pixel+2]) << 7) | - (((x+1) > width) ? 0 : ((wxUint8)palette->GetPixel(data[pixel+3], data[pixel+4], data[pixel+5]) << 6)) | - (((x+2) > width) ? 0 : ((wxUint8)palette->GetPixel(data[pixel+6], data[pixel+7], data[pixel+8]) << 5)) | - (((x+3) > width) ? 0 : ((wxUint8)palette->GetPixel(data[pixel+9], data[pixel+10], data[pixel+11]) << 4)) | - (((x+4) > width) ? 0 : ((wxUint8)palette->GetPixel(data[pixel+12], data[pixel+13], data[pixel+14]) << 3)) | - (((x+5) > width) ? 0 : ((wxUint8)palette->GetPixel(data[pixel+15], data[pixel+16], data[pixel+17]) << 2)) | - (((x+6) > width) ? 0 : ((wxUint8)palette->GetPixel(data[pixel+18], data[pixel+19], data[pixel+20]) << 1)) | - (((x+7) > width) ? 0 : ((wxUint8)palette->GetPixel(data[pixel+21], data[pixel+22], data[pixel+23]) )) ); -#else - // FIXME: what should this be? use some std palette maybe? - buffer[x/8] = 0; -#endif // wxUSE_PALETTE - } - } - else if ( format == wxBMP_1BPP_BW ) // 1 bpp B&W colormap from red color ONLY - { - for (x = 0; x < width; x+=8) - { - pixel = 3*(y*width + x); - - buffer[x/8] = (wxUint8)( - (((wxUint8)(data[pixel] /128.)) << 7) | - (((x+1) > width) ? 0 : (((wxUint8)(data[pixel+3] /128.)) << 6)) | - (((x+2) > width) ? 0 : (((wxUint8)(data[pixel+6] /128.)) << 5)) | - (((x+3) > width) ? 0 : (((wxUint8)(data[pixel+9] /128.)) << 4)) | - (((x+4) > width) ? 0 : (((wxUint8)(data[pixel+12]/128.)) << 3)) | - (((x+5) > width) ? 0 : (((wxUint8)(data[pixel+15]/128.)) << 2)) | - (((x+6) > width) ? 0 : (((wxUint8)(data[pixel+18]/128.)) << 1)) | - (((x+7) > width) ? 0 : (((wxUint8)(data[pixel+21]/128.)) )) ); - } - } - - if ( !stream.Write(buffer, row_width) ) - { - if (verbose) - wxLogError(_("BMP: Couldn't write data.")); - delete[] buffer; -#if wxUSE_PALETTE - delete palette; -#endif // wxUSE_PALETTE - delete q_image; - return false; - } - } - delete[] buffer; -#if wxUSE_PALETTE - delete palette; -#endif // wxUSE_PALETTE - delete q_image; - - return true; -} - - -typedef struct -{ - unsigned char r, g, b; -} _cmap; - -bool wxBMPHandler::DoLoadDib(wxImage * image, int width, int height, - int bpp, int ncolors, int comp, - wxFileOffset bmpOffset, wxInputStream& stream, - bool verbose, bool IsBmp, bool hasPalette) -{ - wxInt32 aDword, rmask = 0, gmask = 0, bmask = 0; - int rshift = 0, gshift = 0, bshift = 0; - int rbits = 0, gbits = 0, bbits = 0; - wxInt32 dbuf[4]; - wxInt8 bbuf[4]; - wxUint8 aByte; - wxUint16 aWord; - - // allocate space for palette if needed: - _cmap *cmap; - - if ( bpp < 16 ) - { - cmap = new _cmap[ncolors]; - if ( !cmap ) - { - if (verbose) - wxLogError(_("BMP: Couldn't allocate memory.")); - return false; - } - } - else - cmap = NULL; - - // destroy existing here instead of: - image->Destroy(); - image->Create(width, height); - - unsigned char *ptr = image->GetData(); - - if ( !ptr ) - { - if ( verbose ) - wxLogError( _("BMP: Couldn't allocate memory.") ); - if ( cmap ) - delete[] cmap; - return false; - } - - // Reading the palette, if it exists: - if ( bpp < 16 && ncolors != 0 ) - { - unsigned char* r = new unsigned char[ncolors]; - unsigned char* g = new unsigned char[ncolors]; - unsigned char* b = new unsigned char[ncolors]; - for (int j = 0; j < ncolors; j++) - { - if (hasPalette) - { - stream.Read(bbuf, 4); - cmap[j].b = bbuf[0]; - cmap[j].g = bbuf[1]; - cmap[j].r = bbuf[2]; - - r[j] = cmap[j].r; - g[j] = cmap[j].g; - b[j] = cmap[j].b; - } - else - { - //used in reading .ico file mask - r[j] = cmap[j].r = - g[j] = cmap[j].g = - b[j] = cmap[j].b = ( j ? 255 : 0 ); - } - } - -#if wxUSE_PALETTE - // Set the palette for the wxImage - image->SetPalette(wxPalette(ncolors, r, g, b)); -#endif // wxUSE_PALETTE - - delete[] r; - delete[] g; - delete[] b; - } - else if ( bpp == 16 || bpp == 32 ) - { - if ( comp == BI_BITFIELDS ) - { - int bit = 0; - stream.Read(dbuf, 4 * 3); - rmask = wxINT32_SWAP_ON_BE(dbuf[0]); - gmask = wxINT32_SWAP_ON_BE(dbuf[1]); - bmask = wxINT32_SWAP_ON_BE(dbuf[2]); - // find shift amount (Least significant bit of mask) - for (bit = bpp-1; bit>=0; bit--) - { - if (bmask & (1 << bit)) - bshift = bit; - if (gmask & (1 << bit)) - gshift = bit; - if (rmask & (1 << bit)) - rshift = bit; - } - // Find number of bits in mask (MSB-LSB+1) - for (bit = 0; bit < bpp; bit++) - { - if (bmask & (1 << bit)) - bbits = bit-bshift+1; - if (gmask & (1 << bit)) - gbits = bit-gshift+1; - if (rmask & (1 << bit)) - rbits = bit-rshift+1; - } - } - else if ( bpp == 16 ) - { - rmask = 0x7C00; - gmask = 0x03E0; - bmask = 0x001F; - rshift = 10; - gshift = 5; - bshift = 0; - rbits = 5; - gbits = 5; - bbits = 5; - } - else if ( bpp == 32 ) - { - rmask = 0x00FF0000; - gmask = 0x0000FF00; - bmask = 0x000000FF; - rshift = 16; - gshift = 8; - bshift = 0; - rbits = 8; - gbits = 8; - bbits = 8; - } - } - - /* - * Reading the image data - */ - if ( IsBmp ) - stream.SeekI(bmpOffset); // else icon, just carry on - - unsigned char *data = ptr; - - /* set the whole image to the background color */ - if ( bpp < 16 && (comp == BI_RLE4 || comp == BI_RLE8) ) - { - for (int i = 0; i < width * height; i++) - { - *ptr++ = cmap[0].r; - *ptr++ = cmap[0].g; - *ptr++ = cmap[0].b; - } - ptr = data; - } - - int linesize = ((width * bpp + 31) / 32) * 4; - - /* BMPs are stored upside down */ - for ( int line = (height - 1); line >= 0; line-- ) - { - int linepos = 0; - for ( int column = 0; column < width ; ) - { - if ( bpp < 16 ) - { - linepos++; - aByte = stream.GetC(); - if ( bpp == 1 ) - { - for (int bit = 0; bit < 8 && column < width; bit++) - { - int index = ((aByte & (0x80 >> bit)) ? 1 : 0); - ptr[poffset] = cmap[index].r; - ptr[poffset + 1] = cmap[index].g; - ptr[poffset + 2] = cmap[index].b; - column++; - } - } - else if ( bpp == 4 ) - { - if ( comp == BI_RLE4 ) - { - wxUint8 first; - first = aByte; - aByte = stream.GetC(); - if ( first == 0 ) - { - if ( aByte == 0 ) - { - if ( column > 0 ) - column = width; - } - else if ( aByte == 1 ) - { - column = width; - line = -1; - } - else if ( aByte == 2 ) - { - aByte = stream.GetC(); - column += aByte; - linepos = column * bpp / 4; - aByte = stream.GetC(); - line -= aByte; // upside down - } - else - { - int absolute = aByte; - wxUint8 nibble[2] ; - int readBytes = 0 ; - for (int k = 0; k < absolute; k++) - { - if ( !(k % 2 ) ) - { - ++readBytes ; - aByte = stream.GetC(); - nibble[0] = (wxUint8)( (aByte & 0xF0) >> 4 ) ; - nibble[1] = (wxUint8)( aByte & 0x0F ) ; - } - ptr[poffset ] = cmap[nibble[k%2]].r; - ptr[poffset + 1] = cmap[nibble[k%2]].g; - ptr[poffset + 2] = cmap[nibble[k%2]].b; - column++; - if ( k % 2 ) - linepos++; - } - if ( readBytes & 0x01 ) - aByte = stream.GetC(); - } - } - else - { - wxUint8 nibble[2] ; - nibble[0] = (wxUint8)( (aByte & 0xF0) >> 4 ) ; - nibble[1] = (wxUint8)( aByte & 0x0F ) ; - - for ( int l = 0; l < first && column < width; l++ ) - { - ptr[poffset ] = cmap[nibble[l%2]].r; - ptr[poffset + 1] = cmap[nibble[l%2]].g; - ptr[poffset + 2] = cmap[nibble[l%2]].b; - column++; - if ( l % 2 ) - linepos++; - } - } - } - else - { - for (int nibble = 0; nibble < 2 && column < width; nibble++) - { - int index = ((aByte & (0xF0 >> nibble * 4)) >> (!nibble * 4)); - if ( index >= 16 ) - index = 15; - ptr[poffset] = cmap[index].r; - ptr[poffset + 1] = cmap[index].g; - ptr[poffset + 2] = cmap[index].b; - column++; - } - } - } - else if ( bpp == 8 ) - { - if ( comp == BI_RLE8 ) - { - unsigned char first; - first = aByte; - aByte = stream.GetC(); - if ( first == 0 ) - { - if ( aByte == 0 ) - { - /* column = width; */ - } - else if ( aByte == 1 ) - { - column = width; - line = -1; - } - else if ( aByte == 2 ) - { - aByte = stream.GetC(); - column += aByte; - linepos = column * bpp / 8; - aByte = stream.GetC(); - line += aByte; - } - else - { - int absolute = aByte; - for (int k = 0; k < absolute; k++) - { - linepos++; - aByte = stream.GetC(); - ptr[poffset ] = cmap[aByte].r; - ptr[poffset + 1] = cmap[aByte].g; - ptr[poffset + 2] = cmap[aByte].b; - column++; - } - if ( absolute & 0x01 ) - aByte = stream.GetC(); - } - } - else - { - for ( int l = 0; l < first && column < width; l++ ) - { - ptr[poffset ] = cmap[aByte].r; - ptr[poffset + 1] = cmap[aByte].g; - ptr[poffset + 2] = cmap[aByte].b; - column++; - linepos++; - } - } - } - else - { - ptr[poffset ] = cmap[aByte].r; - ptr[poffset + 1] = cmap[aByte].g; - ptr[poffset + 2] = cmap[aByte].b; - column++; - // linepos += size; seems to be wrong, RR - } - } - } - else if ( bpp == 24 ) - { - stream.Read(bbuf, 3); - linepos += 3; - ptr[poffset ] = (unsigned char)bbuf[2]; - ptr[poffset + 1] = (unsigned char)bbuf[1]; - ptr[poffset + 2] = (unsigned char)bbuf[0]; - column++; - } - else if ( bpp == 16 ) - { - unsigned char temp; - stream.Read(&aWord, 2); - aWord = wxUINT16_SWAP_ON_BE(aWord); - linepos += 2; - /* use the masks and calculated amonut of shift - to retrieve the color data out of the word. Then - shift it left by (8 - number of bits) such that - the image has the proper dynamic range */ - temp = (unsigned char)((aWord & rmask) >> rshift << (8-rbits)); - ptr[poffset] = temp; - temp = (unsigned char)((aWord & gmask) >> gshift << (8-gbits)); - ptr[poffset + 1] = temp; - temp = (unsigned char)((aWord & bmask) >> bshift << (8-bbits)); - ptr[poffset + 2] = temp; - column++; - } - else - { - unsigned char temp; - stream.Read(&aDword, 4); - aDword = wxINT32_SWAP_ON_BE(aDword); - linepos += 4; - temp = (unsigned char)((aDword & rmask) >> rshift); - ptr[poffset] = temp; - temp = (unsigned char)((aDword & gmask) >> gshift); - ptr[poffset + 1] = temp; - temp = (unsigned char)((aDword & bmask) >> bshift); - ptr[poffset + 2] = temp; - column++; - } - } - while ( (linepos < linesize) && (comp != 1) && (comp != 2) ) - { - stream.Read(&aByte, 1); - linepos += 1; - if ( !stream ) - break; - } - } - - delete[] cmap; - - image->SetMask(false); - - const wxStreamError err = stream.GetLastError(); - return err == wxSTREAM_NO_ERROR || err == wxSTREAM_EOF; -} - -bool wxBMPHandler::LoadDib(wxImage *image, wxInputStream& stream, - bool verbose, bool IsBmp) -{ - wxUint16 aWord; - wxInt32 dbuf[4]; - wxInt8 bbuf[4]; - - wxFileOffset offset = 0; // keep gcc quiet - if ( IsBmp ) - { - // read the header off the .BMP format file - - offset = stream.TellI(); - if (offset == wxInvalidOffset) - offset = 0; - - stream.Read(bbuf, 2); - stream.Read(dbuf, 16); - } - else - { - stream.Read(dbuf, 4); - } - #if 0 // unused - wxInt32 size = wxINT32_SWAP_ON_BE(dbuf[0]); - #endif - offset = offset + wxINT32_SWAP_ON_BE(dbuf[2]); - - stream.Read(dbuf, 4 * 2); - int width = wxINT32_SWAP_ON_BE((int)dbuf[0]); - int height = wxINT32_SWAP_ON_BE((int)dbuf[1]); - if ( !IsBmp)height = height / 2; // for icons divide by 2 - - if ( width > 32767 ) - { - if (verbose) - wxLogError( _("DIB Header: Image width > 32767 pixels for file.") ); - return false; - } - if ( height > 32767 ) - { - if (verbose) - wxLogError( _("DIB Header: Image height > 32767 pixels for file.") ); - return false; - } - - stream.Read(&aWord, 2); - /* - TODO - int planes = (int)wxUINT16_SWAP_ON_BE( aWord ); - */ - stream.Read(&aWord, 2); - int bpp = wxUINT16_SWAP_ON_BE((int)aWord); - if ( bpp != 1 && bpp != 4 && bpp != 8 && bpp != 16 && bpp != 24 && bpp != 32 ) - { - if (verbose) - wxLogError( _("DIB Header: Unknown bitdepth in file.") ); - return false; - } - - stream.Read(dbuf, 4 * 4); - int comp = wxINT32_SWAP_ON_BE((int)dbuf[0]); - if ( comp != BI_RGB && comp != BI_RLE4 && comp != BI_RLE8 && - comp != BI_BITFIELDS ) - { - if (verbose) - wxLogError( _("DIB Header: Unknown encoding in file.") ); - return false; - } - - stream.Read(dbuf, 4 * 2); - int ncolors = wxINT32_SWAP_ON_BE( (int)dbuf[0] ); - if (ncolors == 0) - ncolors = 1 << bpp; - /* some more sanity checks */ - if (((comp == BI_RLE4) && (bpp != 4)) || - ((comp == BI_RLE8) && (bpp != 8)) || - ((comp == BI_BITFIELDS) && (bpp != 16 && bpp != 32))) - { - if (verbose) - wxLogError( _("DIB Header: Encoding doesn't match bitdepth.") ); - return false; - } - - //read DIB; this is the BMP image or the XOR part of an icon image - if ( !DoLoadDib(image, width, height, bpp, ncolors, comp, offset, stream, - verbose, IsBmp, true) ) - { - if (verbose) - wxLogError( _("Error in reading image DIB.") ); - return false; - } - - if ( !IsBmp ) - { - //read Icon mask which is monochrome - //there is no palette, so we will create one - wxImage mask; - if ( !DoLoadDib(&mask, width, height, 1, 2, BI_RGB, offset, stream, - verbose, IsBmp, false) ) - { - if (verbose) - wxLogError( _("ICO: Error in reading mask DIB.") ); - return false; - } - image->SetMaskFromImage(mask, 255, 255, 255); - - } - - return true; -} - -bool wxBMPHandler::LoadFile(wxImage *image, wxInputStream& stream, - bool verbose, int WXUNUSED(index)) -{ - // Read a single DIB fom the file: - return LoadDib(image, stream, verbose, true/*isBmp*/); -} - -bool wxBMPHandler::DoCanRead(wxInputStream& stream) -{ - unsigned char hdr[2]; - - if ( !stream.Read(hdr, WXSIZEOF(hdr)) ) - return false; - - // do we have the BMP file signature? - return hdr[0] == 'B' && hdr[1] == 'M'; -} - -#endif // wxUSE_STREAMS - - -#if wxUSE_ICO_CUR -//----------------------------------------------------------------------------- -// wxICOHandler -//----------------------------------------------------------------------------- - -IMPLEMENT_DYNAMIC_CLASS(wxICOHandler, wxBMPHandler) - -#if wxUSE_STREAMS - -struct ICONDIRENTRY -{ - wxUint8 bWidth; // Width of the image - wxUint8 bHeight; // Height of the image (times 2) - wxUint8 bColorCount; // Number of colors in image (0 if >=8bpp) - wxUint8 bReserved; // Reserved - - // these two are different in icons and cursors: - // icon or cursor - wxUint16 wPlanes; // Color Planes or XHotSpot - wxUint16 wBitCount; // Bits per pixel or YHotSpot - - wxUint32 dwBytesInRes; // how many bytes in this resource? - wxUint32 dwImageOffset; // where in the file is this image -}; - -struct ICONDIR -{ - wxUint16 idReserved; // Reserved - wxUint16 idType; // resource type (1 for icons, 2 for cursors) - wxUint16 idCount; // how many images? -}; - - -bool wxICOHandler::SaveFile(wxImage *image, - wxOutputStream& stream, - bool verbose) - -{ - //sanity check; icon must be less than 127 pixels high and 255 wide - if ( image->GetHeight () > 127 ) - { - if ( verbose ) - wxLogError(_("ICO: Image too tall for an icon.")); - return false; - } - if ( image->GetWidth () > 255 ) - { - if ( verbose ) - wxLogError(_("ICO: Image too wide for an icon.")); - return false; - } - - const int images = 1; // only generate one image - - // VS: This is a hack of sort - since ICO and CUR files are almost - // identical, we have all the meat in wxICOHandler and check for - // the actual (handler) type when the code has to distinguish between - // the two formats - int type = (this->GetType() == wxBITMAP_TYPE_CUR) ? 2 : 1; - - // write a header, (ICONDIR) - // Calculate the header size - wxUint32 offset = 3 * sizeof(wxUint16); - - ICONDIR IconDir; - IconDir.idReserved = 0; - IconDir.idType = wxUINT16_SWAP_ON_BE((wxUint16)type); - IconDir.idCount = wxUINT16_SWAP_ON_BE((wxUint16)images); - stream.Write(&IconDir.idReserved, sizeof(IconDir.idReserved)); - stream.Write(&IconDir.idType, sizeof(IconDir.idType)); - stream.Write(&IconDir.idCount, sizeof(IconDir.idCount)); - if ( !stream.IsOk() ) - { - if ( verbose ) - wxLogError(_("ICO: Error writing the image file!")); - return false; - } - - // for each iamage write a description ICONDIRENTRY: - ICONDIRENTRY icondirentry; - for (int img = 0; img < images; img++) - { - wxImage mask; - - if ( image->HasMask() ) - { - // make another image with black/white: - mask = image->ConvertToMono (image->GetMaskRed(), image->GetMaskGreen(), image->GetMaskBlue() ); - - // now we need to change the masked regions to black: - unsigned char r = image->GetMaskRed(); - unsigned char g = image->GetMaskGreen(); - unsigned char b = image->GetMaskBlue(); - if ( (r != 0) || (g != 0) || (b != 0) ) - { - // Go round and apply black to the masked bits: - int i, j; - for (i = 0; i < mask.GetWidth(); i++) - { - for (j = 0; j < mask.GetHeight(); j++) - { - if ((r == mask.GetRed(i, j)) && - (g == mask.GetGreen(i, j))&& - (b == mask.GetBlue(i, j)) ) - image->SetRGB(i, j, 0, 0, 0 ); - } - } - } - } - else - { - // just make a black mask all over: - mask = image->Copy(); - int i, j; - for (i = 0; i < mask.GetWidth(); i++) - for (j = 0; j < mask.GetHeight(); j++) - mask.SetRGB(i, j, 0, 0, 0 ); - } - // Set the formats for image and mask - // (Windows never saves with more than 8 colors): - image->SetOption(wxIMAGE_OPTION_BMP_FORMAT, wxBMP_8BPP); - - // monochome bitmap: - mask.SetOption(wxIMAGE_OPTION_BMP_FORMAT, wxBMP_1BPP_BW); - bool IsBmp = false; - bool IsMask = false; - - //calculate size and offset of image and mask - wxCountingOutputStream cStream; - bool bResult = SaveDib(image, cStream, verbose, IsBmp, IsMask); - if ( !bResult ) - { - if ( verbose ) - wxLogError(_("ICO: Error writing the image file!")); - return false; - } - IsMask = true; - - bResult = SaveDib(&mask, cStream, verbose, IsBmp, IsMask); - if ( !bResult ) - { - if ( verbose ) - wxLogError(_("ICO: Error writing the image file!")); - return false; - } - wxUint32 Size = cStream.GetSize(); - - // wxCountingOutputStream::IsOk() always returns true for now and this - // "if" provokes VC++ warnings in optimized build -#if 0 - if ( !cStream.Ok() ) - { - if ( verbose ) - wxLogError(_("ICO: Error writing the image file!")); - return false; - } -#endif // 0 - - offset = offset + sizeof(ICONDIRENTRY); - - icondirentry.bWidth = (wxUint8)image->GetWidth(); - icondirentry.bHeight = (wxUint8)(2 * image->GetHeight()); - icondirentry.bColorCount = 0; - icondirentry.bReserved = 0; - icondirentry.wPlanes = wxUINT16_SWAP_ON_BE(1); - icondirentry.wBitCount = wxUINT16_SWAP_ON_BE(wxBMP_8BPP); - if ( type == 2 /*CUR*/) - { - int hx = image->HasOption(wxIMAGE_OPTION_CUR_HOTSPOT_X) ? - image->GetOptionInt(wxIMAGE_OPTION_CUR_HOTSPOT_X) : - image->GetWidth() / 2; - int hy = image->HasOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y) ? - image->GetOptionInt(wxIMAGE_OPTION_CUR_HOTSPOT_Y) : - image->GetHeight() / 2; - - // actually write the values of the hot spot here: - icondirentry.wPlanes = wxUINT16_SWAP_ON_BE((wxUint16)hx); - icondirentry.wBitCount = wxUINT16_SWAP_ON_BE((wxUint16)hy); - } - icondirentry.dwBytesInRes = wxUINT32_SWAP_ON_BE(Size); - icondirentry.dwImageOffset = wxUINT32_SWAP_ON_BE(offset); - - // increase size to allow for the data written: - offset += Size; - - // write to stream: - stream.Write(&icondirentry.bWidth, sizeof(icondirentry.bWidth)); - stream.Write(&icondirentry.bHeight, sizeof(icondirentry.bHeight)); - stream.Write(&icondirentry.bColorCount, sizeof(icondirentry.bColorCount)); - stream.Write(&icondirentry.bReserved, sizeof(icondirentry.bReserved)); - stream.Write(&icondirentry.wPlanes, sizeof(icondirentry.wPlanes)); - stream.Write(&icondirentry.wBitCount, sizeof(icondirentry.wBitCount)); - stream.Write(&icondirentry.dwBytesInRes, sizeof(icondirentry.dwBytesInRes)); - stream.Write(&icondirentry.dwImageOffset, sizeof(icondirentry.dwImageOffset)); - if ( !stream.IsOk() ) - { - if ( verbose ) - wxLogError(_("ICO: Error writing the image file!")); - return false; - } - - // actually save it: - IsMask = false; - bResult = SaveDib(image, stream, verbose, IsBmp, IsMask); - if ( !bResult ) - { - if ( verbose ) - wxLogError(_("ICO: Error writing the image file!")); - return false; - } - IsMask = true; - - bResult = SaveDib(&mask, stream, verbose, IsBmp, IsMask); - if ( !bResult ) - { - if ( verbose ) - wxLogError(_("ICO: Error writing the image file!")); - return false; - } - - } // end of for loop - - return true; -} - -bool wxICOHandler::LoadFile(wxImage *image, wxInputStream& stream, - bool verbose, int index) -{ - stream.SeekI(0); - return DoLoadFile(image, stream, verbose, index); -} - -bool wxICOHandler::DoLoadFile(wxImage *image, wxInputStream& stream, - bool WXUNUSED(verbose), int index) -{ - bool bResult wxDUMMY_INITIALIZE(false); - bool IsBmp = false; - - ICONDIR IconDir; - - wxFileOffset iPos = stream.TellI(); - stream.Read(&IconDir, sizeof(IconDir)); - wxUint16 nIcons = wxUINT16_SWAP_ON_BE(IconDir.idCount); - // nType is 1 for Icons, 2 for Cursors: - wxUint16 nType = wxUINT16_SWAP_ON_BE(IconDir.idType); - - // loop round the icons and choose the best one: - ICONDIRENTRY *pIconDirEntry = new ICONDIRENTRY[nIcons]; - ICONDIRENTRY *pCurrentEntry = pIconDirEntry; - int wMax = 0; - int colmax = 0; - int iSel = wxNOT_FOUND; - - for (int i = 0; i < nIcons; i++ ) - { - stream.Read(pCurrentEntry, sizeof(ICONDIRENTRY)); - // bHeight and bColorCount are wxUint8 - if ( pCurrentEntry->bWidth >= wMax ) - { - // see if we have more colors, ==0 indicates > 8bpp: - if ( pCurrentEntry->bColorCount == 0 ) - pCurrentEntry->bColorCount = 255; - if ( pCurrentEntry->bColorCount >= colmax ) - { - iSel = i; - wMax = pCurrentEntry->bWidth; - colmax = pCurrentEntry->bColorCount; - } - } - pCurrentEntry++; - } - - if ( index != -1 ) - { - // VS: Note that we *have* to run the loop above even if index != -1, because - // it reads ICONDIRENTRies. - iSel = index; - } - - if ( iSel == wxNOT_FOUND || iSel < 0 || iSel >= nIcons ) - { - wxLogError(_("ICO: Invalid icon index.")); - bResult = false; - } - else - { - // seek to selected icon: - pCurrentEntry = pIconDirEntry + iSel; - stream.SeekI(iPos + wxUINT32_SWAP_ON_BE(pCurrentEntry->dwImageOffset), wxFromStart); - bResult = LoadDib(image, stream, true, IsBmp); - bool bIsCursorType = (this->GetType() == wxBITMAP_TYPE_CUR) || (this->GetType() == wxBITMAP_TYPE_ANI); - if ( bResult && bIsCursorType && nType == 2 ) - { - // it is a cursor, so let's set the hotspot: - image->SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, wxUINT16_SWAP_ON_BE(pCurrentEntry->wPlanes)); - image->SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, wxUINT16_SWAP_ON_BE(pCurrentEntry->wBitCount)); - } - } - delete[] pIconDirEntry; - return bResult; -} - -int wxICOHandler::GetImageCount(wxInputStream& stream) -{ - ICONDIR IconDir; - wxFileOffset iPos = stream.TellI(); - stream.SeekI(0); - stream.Read(&IconDir, sizeof(IconDir)); - wxUint16 nIcons = wxUINT16_SWAP_ON_BE(IconDir.idCount); - stream.SeekI(iPos); - return (int)nIcons; -} - -bool wxICOHandler::DoCanRead(wxInputStream& stream) -{ - stream.SeekI(0); - unsigned char hdr[4]; - if ( !stream.Read(hdr, WXSIZEOF(hdr)) ) - return false; - - // hdr[2] is one for an icon and two for a cursor - return hdr[0] == '\0' && hdr[1] == '\0' && hdr[2] == '\1' && hdr[3] == '\0'; -} - -#endif // wxUSE_STREAMS - - -//----------------------------------------------------------------------------- -// wxCURHandler -//----------------------------------------------------------------------------- - -IMPLEMENT_DYNAMIC_CLASS(wxCURHandler, wxICOHandler) - -#if wxUSE_STREAMS - -bool wxCURHandler::DoCanRead(wxInputStream& stream) -{ - stream.SeekI(0); - unsigned char hdr[4]; - if ( !stream.Read(hdr, WXSIZEOF(hdr)) ) - return false; - - // hdr[2] is one for an icon and two for a cursor - return hdr[0] == '\0' && hdr[1] == '\0' && hdr[2] == '\2' && hdr[3] == '\0'; -} - -#endif // wxUSE_STREAMS - -//----------------------------------------------------------------------------- -// wxANIHandler -//----------------------------------------------------------------------------- - -IMPLEMENT_DYNAMIC_CLASS(wxANIHandler, wxCURHandler) - -#if wxUSE_STREAMS - -bool wxANIHandler::LoadFile(wxImage *image, wxInputStream& stream, - bool WXUNUSED(verbose), int index) -{ - wxANIDecoder decoder; - if (!decoder.Load(stream)) - return false; - - return decoder.ConvertToImage(index != -1 ? (size_t)index : 0, image); -} - -bool wxANIHandler::DoCanRead(wxInputStream& stream) -{ - wxANIDecoder decod; - return decod.CanRead(stream); -} - -int wxANIHandler::GetImageCount(wxInputStream& stream) -{ - wxANIDecoder decoder; - if (!decoder.Load(stream)) - return wxNOT_FOUND; - - return decoder.GetFrameCount(); -} - -#endif // wxUSE_STREAMS - -#endif // wxUSE_ICO_CUR - -#endif // wxUSE_IMAGE +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/imagbmp.cpp +// Purpose: wxImage BMP,ICO and CUR handlers +// Author: Robert Roebling, Chris Elliott +// RCS-ID: $Id: imagbmp.cpp 41819 2006-10-09 17:51:07Z VZ $ +// Copyright: (c) Robert Roebling, Chris Elliott +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_IMAGE + +#include "wx/imagbmp.h" + +#ifndef WX_PRECOMP + #ifdef __WXMSW__ + #include "wx/msw/wrapwin.h" + #endif + #include "wx/log.h" + #include "wx/app.h" + #include "wx/bitmap.h" + #include "wx/palette.h" + #include "wx/intl.h" +#endif + +#include "wx/filefn.h" +#include "wx/wfstream.h" +#include "wx/quantize.h" +#include "wx/anidecod.h" + +// For memcpy +#include + +#ifdef __SALFORDC__ +#ifdef FAR +#undef FAR +#endif +#endif + +//----------------------------------------------------------------------------- +// wxBMPHandler +//----------------------------------------------------------------------------- + +IMPLEMENT_DYNAMIC_CLASS(wxBMPHandler,wxImageHandler) + +#if wxUSE_STREAMS + +#ifndef BI_RGB + #define BI_RGB 0 +#endif + +#ifndef BI_RLE8 +#define BI_RLE8 1 +#endif + +#ifndef BI_RLE4 +#define BI_RLE4 2 +#endif + +#ifndef BI_BITFIELDS +#define BI_BITFIELDS 3 +#endif + +#define poffset (line * width * 3 + column * 3) + +bool wxBMPHandler::SaveFile(wxImage *image, + wxOutputStream& stream, + bool verbose) +{ + return SaveDib(image, stream, verbose, true/*IsBmp*/, false/*IsMask*/); +} + +bool wxBMPHandler::SaveDib(wxImage *image, + wxOutputStream& stream, + bool verbose, + bool IsBmp, + bool IsMask) + +{ + wxCHECK_MSG( image, false, _T("invalid pointer in wxBMPHandler::SaveFile") ); + + if ( !image->Ok() ) + { + if ( verbose ) + wxLogError(_("BMP: Couldn't save invalid image.")); + return false; + } + + // get the format of the BMP file to save, else use 24bpp + unsigned format = wxBMP_24BPP; + if ( image->HasOption(wxIMAGE_OPTION_BMP_FORMAT) ) + format = image->GetOptionInt(wxIMAGE_OPTION_BMP_FORMAT); + + wxUint16 bpp; // # of bits per pixel + int palette_size; // # of color map entries, ie. 2^bpp colors + + // set the bpp and appropriate palette_size, and do additional checks + if ( (format == wxBMP_1BPP) || (format == wxBMP_1BPP_BW) ) + { + bpp = 1; + palette_size = 2; + } + else if ( format == wxBMP_4BPP ) + { + bpp = 4; + palette_size = 16; + } + else if ( (format == wxBMP_8BPP) || (format == wxBMP_8BPP_GREY) || + (format == wxBMP_8BPP_RED) || (format == wxBMP_8BPP_PALETTE) ) + { + // need to set a wxPalette to use this, HOW TO CHECK IF VALID, SIZE? + if ((format == wxBMP_8BPP_PALETTE) +#if wxUSE_PALETTE + && !image->HasPalette() +#endif // wxUSE_PALETTE + ) + { + if ( verbose ) + wxLogError(_("BMP: wxImage doesn't have own wxPalette.")); + return false; + } + bpp = 8; + palette_size = 256; + } + else // you get 24bpp + { + format = wxBMP_24BPP; + bpp = 24; + palette_size = 0; + } + + unsigned width = image->GetWidth(); + unsigned row_padding = (4 - int(width*bpp/8.0) % 4) % 4; // # bytes to pad to dword + unsigned row_width = int(width * bpp/8.0) + row_padding; // # of bytes per row + + struct + { + // BitmapHeader: + wxUint16 magic; // format magic, always 'BM' + wxUint32 filesize; // total file size, inc. headers + wxUint32 reserved; // for future use + wxUint32 data_offset; // image data offset in the file + + // BitmapInfoHeader: + wxUint32 bih_size; // 2nd part's size + wxUint32 width, height; // bitmap's dimensions + wxUint16 planes; // num of planes + wxUint16 bpp; // bits per pixel + wxUint32 compression; // compression method + wxUint32 size_of_bmp; // size of the bitmap + wxUint32 h_res, v_res; // image resolution in dpi + wxUint32 num_clrs; // number of colors used + wxUint32 num_signif_clrs;// number of significant colors + } hdr; + + wxUint32 hdr_size = 14/*BitmapHeader*/ + 40/*BitmapInfoHeader*/; + + hdr.magic = wxUINT16_SWAP_ON_BE(0x4D42/*'BM'*/); + hdr.filesize = wxUINT32_SWAP_ON_BE( hdr_size + palette_size*4 + + row_width * image->GetHeight() ); + hdr.reserved = 0; + hdr.data_offset = wxUINT32_SWAP_ON_BE(hdr_size + palette_size*4); + + hdr.bih_size = wxUINT32_SWAP_ON_BE(hdr_size - 14); + hdr.width = wxUINT32_SWAP_ON_BE(image->GetWidth()); + if ( IsBmp ) + { + hdr.height = wxUINT32_SWAP_ON_BE(image->GetHeight()); + } + else + { + hdr.height = wxUINT32_SWAP_ON_BE(2 * image->GetHeight()); + } + hdr.planes = wxUINT16_SWAP_ON_BE(1); // always 1 plane + hdr.bpp = wxUINT16_SWAP_ON_BE(bpp); + hdr.compression = 0; // RGB uncompressed + hdr.size_of_bmp = wxUINT32_SWAP_ON_BE(row_width * image->GetHeight()); + hdr.h_res = hdr.v_res = wxUINT32_SWAP_ON_BE(72); // 72dpi is standard + hdr.num_clrs = wxUINT32_SWAP_ON_BE(palette_size); // # colors in colormap + hdr.num_signif_clrs = 0; // all colors are significant + + if ( IsBmp ) + { + if (// VS: looks ugly but compilers tend to do ugly things with structs, + // like aligning hdr.filesize's ofset to dword :( + // VZ: we should add padding then... + !stream.Write(&hdr.magic, 2) || + !stream.Write(&hdr.filesize, 4) || + !stream.Write(&hdr.reserved, 4) || + !stream.Write(&hdr.data_offset, 4) + ) + { + if (verbose) + wxLogError(_("BMP: Couldn't write the file (Bitmap) header.")); + return false; + } + } + if ( !IsMask ) + { + if ( + !stream.Write(&hdr.bih_size, 4) || + !stream.Write(&hdr.width, 4) || + !stream.Write(&hdr.height, 4) || + !stream.Write(&hdr.planes, 2) || + !stream.Write(&hdr.bpp, 2) || + !stream.Write(&hdr.compression, 4) || + !stream.Write(&hdr.size_of_bmp, 4) || + !stream.Write(&hdr.h_res, 4) || + !stream.Write(&hdr.v_res, 4) || + !stream.Write(&hdr.num_clrs, 4) || + !stream.Write(&hdr.num_signif_clrs, 4) + ) + { + if (verbose) + wxLogError(_("BMP: Couldn't write the file (BitmapInfo) header.")); + return false; + } + } + + wxPalette *palette = NULL; // entries for quantized images + wxUint8 *rgbquad = NULL; // for the RGBQUAD bytes for the colormap + wxImage *q_image = NULL; // destination for quantized image + + // if <24bpp use quantization to reduce colors for *some* of the formats + if ( (format == wxBMP_1BPP) || (format == wxBMP_4BPP) || + (format == wxBMP_8BPP) || (format == wxBMP_8BPP_PALETTE) ) + { + // make a new palette and quantize the image + if (format != wxBMP_8BPP_PALETTE) + { + q_image = new wxImage(); + + // I get a delete error using Quantize when desired colors > 236 + int quantize = ((palette_size > 236) ? 236 : palette_size); + // fill the destination too, it gives much nicer 4bpp images + wxQuantize::Quantize( *image, *q_image, &palette, quantize, 0, + wxQUANTIZE_FILL_DESTINATION_IMAGE ); + } + else + { +#if wxUSE_PALETTE + palette = new wxPalette(image->GetPalette()); +#endif // wxUSE_PALETTE + } + + int i; + unsigned char r, g, b; + rgbquad = new wxUint8 [palette_size*4]; + + for (i = 0; i < palette_size; i++) + { +#if wxUSE_PALETTE + if ( !palette->GetRGB(i, &r, &g, &b) ) +#endif // wxUSE_PALETTE + r = g = b = 0; + + rgbquad[i*4] = b; + rgbquad[i*4+1] = g; + rgbquad[i*4+2] = r; + rgbquad[i*4+3] = 0; + } + } + // make a 256 entry greyscale colormap or 2 entry black & white + else if ( (format == wxBMP_8BPP_GREY) || (format == wxBMP_8BPP_RED) || + (format == wxBMP_1BPP_BW) ) + { + rgbquad = new wxUint8 [palette_size*4]; + + for ( int i = 0; i < palette_size; i++ ) + { + // if 1BPP_BW then the value should be either 0 or 255 + wxUint8 c = (wxUint8)((i > 0) && (format == wxBMP_1BPP_BW) ? 255 : i); + + rgbquad[i*4] = + rgbquad[i*4+1] = + rgbquad[i*4+2] = c; + rgbquad[i*4+3] = 0; + } + } + + // if the colormap was made, then it needs to be written + if (rgbquad) + { + if ( !IsMask ) + { + if ( !stream.Write(rgbquad, palette_size*4) ) + { + if (verbose) + wxLogError(_("BMP: Couldn't write RGB color map.")); + delete[] rgbquad; +#if wxUSE_PALETTE + delete palette; +#endif // wxUSE_PALETTE + delete q_image; + return false; + } + } + delete []rgbquad; + } + + // pointer to the image data, use quantized if available + wxUint8 *data = (wxUint8*) image->GetData(); + if (q_image) if (q_image->Ok()) data = (wxUint8*) q_image->GetData(); + + wxUint8 *buffer = new wxUint8[row_width]; + memset(buffer, 0, row_width); + int y; unsigned x; + long int pixel; + + for (y = image->GetHeight() -1; y >= 0; y--) + { + if ( format == wxBMP_24BPP ) // 3 bytes per pixel red,green,blue + { + for ( x = 0; x < width; x++ ) + { + pixel = 3*(y*width + x); + + buffer[3*x ] = data[pixel+2]; + buffer[3*x + 1] = data[pixel+1]; + buffer[3*x + 2] = data[pixel]; + } + } + else if ((format == wxBMP_8BPP) || // 1 byte per pixel in color + (format == wxBMP_8BPP_PALETTE)) + { + for (x = 0; x < width; x++) + { + pixel = 3*(y*width + x); +#if wxUSE_PALETTE + buffer[x] = (wxUint8)palette->GetPixel( data[pixel], + data[pixel+1], + data[pixel+2] ); +#else + // FIXME: what should this be? use some std palette maybe? + buffer[x] = 0; +#endif // wxUSE_PALETTE + } + } + else if ( format == wxBMP_8BPP_GREY ) // 1 byte per pix, rgb ave to grey + { + for (x = 0; x < width; x++) + { + pixel = 3*(y*width + x); + buffer[x] = (wxUint8)(.299*data[pixel] + + .587*data[pixel+1] + + .114*data[pixel+2]); + } + } + else if ( format == wxBMP_8BPP_RED ) // 1 byte per pixel, red as greys + { + for (x = 0; x < width; x++) + { + buffer[x] = (wxUint8)data[3*(y*width + x)]; + } + } + else if ( format == wxBMP_4BPP ) // 4 bpp in color + { + for (x = 0; x < width; x+=2) + { + pixel = 3*(y*width + x); + + // fill buffer, ignore if > width +#if wxUSE_PALETTE + buffer[x/2] = (wxUint8)( + ((wxUint8)palette->GetPixel(data[pixel], + data[pixel+1], + data[pixel+2]) << 4) | + (((x+1) > width) + ? 0 + : ((wxUint8)palette->GetPixel(data[pixel+3], + data[pixel+4], + data[pixel+5]) )) ); +#else + // FIXME: what should this be? use some std palette maybe? + buffer[x/2] = 0; +#endif // wxUSE_PALETTE + } + } + else if ( format == wxBMP_1BPP ) // 1 bpp in "color" + { + for (x = 0; x < width; x+=8) + { + pixel = 3*(y*width + x); + +#if wxUSE_PALETTE + buffer[x/8] = (wxUint8)( + ((wxUint8)palette->GetPixel(data[pixel], data[pixel+1], data[pixel+2]) << 7) | + (((x+1) > width) ? 0 : ((wxUint8)palette->GetPixel(data[pixel+3], data[pixel+4], data[pixel+5]) << 6)) | + (((x+2) > width) ? 0 : ((wxUint8)palette->GetPixel(data[pixel+6], data[pixel+7], data[pixel+8]) << 5)) | + (((x+3) > width) ? 0 : ((wxUint8)palette->GetPixel(data[pixel+9], data[pixel+10], data[pixel+11]) << 4)) | + (((x+4) > width) ? 0 : ((wxUint8)palette->GetPixel(data[pixel+12], data[pixel+13], data[pixel+14]) << 3)) | + (((x+5) > width) ? 0 : ((wxUint8)palette->GetPixel(data[pixel+15], data[pixel+16], data[pixel+17]) << 2)) | + (((x+6) > width) ? 0 : ((wxUint8)palette->GetPixel(data[pixel+18], data[pixel+19], data[pixel+20]) << 1)) | + (((x+7) > width) ? 0 : ((wxUint8)palette->GetPixel(data[pixel+21], data[pixel+22], data[pixel+23]) )) ); +#else + // FIXME: what should this be? use some std palette maybe? + buffer[x/8] = 0; +#endif // wxUSE_PALETTE + } + } + else if ( format == wxBMP_1BPP_BW ) // 1 bpp B&W colormap from red color ONLY + { + for (x = 0; x < width; x+=8) + { + pixel = 3*(y*width + x); + + buffer[x/8] = (wxUint8)( + (((wxUint8)(data[pixel] /128.)) << 7) | + (((x+1) > width) ? 0 : (((wxUint8)(data[pixel+3] /128.)) << 6)) | + (((x+2) > width) ? 0 : (((wxUint8)(data[pixel+6] /128.)) << 5)) | + (((x+3) > width) ? 0 : (((wxUint8)(data[pixel+9] /128.)) << 4)) | + (((x+4) > width) ? 0 : (((wxUint8)(data[pixel+12]/128.)) << 3)) | + (((x+5) > width) ? 0 : (((wxUint8)(data[pixel+15]/128.)) << 2)) | + (((x+6) > width) ? 0 : (((wxUint8)(data[pixel+18]/128.)) << 1)) | + (((x+7) > width) ? 0 : (((wxUint8)(data[pixel+21]/128.)) )) ); + } + } + + if ( !stream.Write(buffer, row_width) ) + { + if (verbose) + wxLogError(_("BMP: Couldn't write data.")); + delete[] buffer; +#if wxUSE_PALETTE + delete palette; +#endif // wxUSE_PALETTE + delete q_image; + return false; + } + } + delete[] buffer; +#if wxUSE_PALETTE + delete palette; +#endif // wxUSE_PALETTE + delete q_image; + + return true; +} + + +typedef struct +{ + unsigned char r, g, b; +} _cmap; + +bool wxBMPHandler::DoLoadDib(wxImage * image, int width, int height, + int bpp, int ncolors, int comp, + wxFileOffset bmpOffset, wxInputStream& stream, + bool verbose, bool IsBmp, bool hasPalette) +{ + wxInt32 aDword, rmask = 0, gmask = 0, bmask = 0; + int rshift = 0, gshift = 0, bshift = 0; + int rbits = 0, gbits = 0, bbits = 0; + wxInt32 dbuf[4]; + wxInt8 bbuf[4]; + wxUint8 aByte; + wxUint16 aWord; + + // allocate space for palette if needed: + _cmap *cmap; + + if ( bpp < 16 ) + { + cmap = new _cmap[ncolors]; + if ( !cmap ) + { + if (verbose) + wxLogError(_("BMP: Couldn't allocate memory.")); + return false; + } + } + else + cmap = NULL; + + // destroy existing here instead of: + image->Destroy(); + image->Create(width, height); + + unsigned char *ptr = image->GetData(); + + if ( !ptr ) + { + if ( verbose ) + wxLogError( _("BMP: Couldn't allocate memory.") ); + if ( cmap ) + delete[] cmap; + return false; + } + + // Reading the palette, if it exists: + if ( bpp < 16 && ncolors != 0 ) + { + unsigned char* r = new unsigned char[ncolors]; + unsigned char* g = new unsigned char[ncolors]; + unsigned char* b = new unsigned char[ncolors]; + for (int j = 0; j < ncolors; j++) + { + if (hasPalette) + { + stream.Read(bbuf, 4); + cmap[j].b = bbuf[0]; + cmap[j].g = bbuf[1]; + cmap[j].r = bbuf[2]; + + r[j] = cmap[j].r; + g[j] = cmap[j].g; + b[j] = cmap[j].b; + } + else + { + //used in reading .ico file mask + r[j] = cmap[j].r = + g[j] = cmap[j].g = + b[j] = cmap[j].b = ( j ? 255 : 0 ); + } + } + +#if wxUSE_PALETTE + // Set the palette for the wxImage + image->SetPalette(wxPalette(ncolors, r, g, b)); +#endif // wxUSE_PALETTE + + delete[] r; + delete[] g; + delete[] b; + } + else if ( bpp == 16 || bpp == 32 ) + { + if ( comp == BI_BITFIELDS ) + { + int bit = 0; + stream.Read(dbuf, 4 * 3); + rmask = wxINT32_SWAP_ON_BE(dbuf[0]); + gmask = wxINT32_SWAP_ON_BE(dbuf[1]); + bmask = wxINT32_SWAP_ON_BE(dbuf[2]); + // find shift amount (Least significant bit of mask) + for (bit = bpp-1; bit>=0; bit--) + { + if (bmask & (1 << bit)) + bshift = bit; + if (gmask & (1 << bit)) + gshift = bit; + if (rmask & (1 << bit)) + rshift = bit; + } + // Find number of bits in mask (MSB-LSB+1) + for (bit = 0; bit < bpp; bit++) + { + if (bmask & (1 << bit)) + bbits = bit-bshift+1; + if (gmask & (1 << bit)) + gbits = bit-gshift+1; + if (rmask & (1 << bit)) + rbits = bit-rshift+1; + } + } + else if ( bpp == 16 ) + { + rmask = 0x7C00; + gmask = 0x03E0; + bmask = 0x001F; + rshift = 10; + gshift = 5; + bshift = 0; + rbits = 5; + gbits = 5; + bbits = 5; + } + else if ( bpp == 32 ) + { + rmask = 0x00FF0000; + gmask = 0x0000FF00; + bmask = 0x000000FF; + rshift = 16; + gshift = 8; + bshift = 0; + rbits = 8; + gbits = 8; + bbits = 8; + } + } + + /* + * Reading the image data + */ + if ( IsBmp ) + stream.SeekI(bmpOffset); // else icon, just carry on + + unsigned char *data = ptr; + + /* set the whole image to the background color */ + if ( bpp < 16 && (comp == BI_RLE4 || comp == BI_RLE8) ) + { + for (int i = 0; i < width * height; i++) + { + *ptr++ = cmap[0].r; + *ptr++ = cmap[0].g; + *ptr++ = cmap[0].b; + } + ptr = data; + } + + int linesize = ((width * bpp + 31) / 32) * 4; + + /* BMPs are stored upside down */ + for ( int line = (height - 1); line >= 0; line-- ) + { + int linepos = 0; + for ( int column = 0; column < width ; ) + { + if ( bpp < 16 ) + { + linepos++; + aByte = stream.GetC(); + if ( bpp == 1 ) + { + for (int bit = 0; bit < 8 && column < width; bit++) + { + int index = ((aByte & (0x80 >> bit)) ? 1 : 0); + ptr[poffset] = cmap[index].r; + ptr[poffset + 1] = cmap[index].g; + ptr[poffset + 2] = cmap[index].b; + column++; + } + } + else if ( bpp == 4 ) + { + if ( comp == BI_RLE4 ) + { + wxUint8 first; + first = aByte; + aByte = stream.GetC(); + if ( first == 0 ) + { + if ( aByte == 0 ) + { + if ( column > 0 ) + column = width; + } + else if ( aByte == 1 ) + { + column = width; + line = -1; + } + else if ( aByte == 2 ) + { + aByte = stream.GetC(); + column += aByte; + linepos = column * bpp / 4; + aByte = stream.GetC(); + line -= aByte; // upside down + } + else + { + int absolute = aByte; + wxUint8 nibble[2] ; + int readBytes = 0 ; + for (int k = 0; k < absolute; k++) + { + if ( !(k % 2 ) ) + { + ++readBytes ; + aByte = stream.GetC(); + nibble[0] = (wxUint8)( (aByte & 0xF0) >> 4 ) ; + nibble[1] = (wxUint8)( aByte & 0x0F ) ; + } + ptr[poffset ] = cmap[nibble[k%2]].r; + ptr[poffset + 1] = cmap[nibble[k%2]].g; + ptr[poffset + 2] = cmap[nibble[k%2]].b; + column++; + if ( k % 2 ) + linepos++; + } + if ( readBytes & 0x01 ) + aByte = stream.GetC(); + } + } + else + { + wxUint8 nibble[2] ; + nibble[0] = (wxUint8)( (aByte & 0xF0) >> 4 ) ; + nibble[1] = (wxUint8)( aByte & 0x0F ) ; + + for ( int l = 0; l < first && column < width; l++ ) + { + ptr[poffset ] = cmap[nibble[l%2]].r; + ptr[poffset + 1] = cmap[nibble[l%2]].g; + ptr[poffset + 2] = cmap[nibble[l%2]].b; + column++; + if ( l % 2 ) + linepos++; + } + } + } + else + { + for (int nibble = 0; nibble < 2 && column < width; nibble++) + { + int index = ((aByte & (0xF0 >> nibble * 4)) >> (!nibble * 4)); + if ( index >= 16 ) + index = 15; + ptr[poffset] = cmap[index].r; + ptr[poffset + 1] = cmap[index].g; + ptr[poffset + 2] = cmap[index].b; + column++; + } + } + } + else if ( bpp == 8 ) + { + if ( comp == BI_RLE8 ) + { + unsigned char first; + first = aByte; + aByte = stream.GetC(); + if ( first == 0 ) + { + if ( aByte == 0 ) + { + /* column = width; */ + } + else if ( aByte == 1 ) + { + column = width; + line = -1; + } + else if ( aByte == 2 ) + { + aByte = stream.GetC(); + column += aByte; + linepos = column * bpp / 8; + aByte = stream.GetC(); + line += aByte; + } + else + { + int absolute = aByte; + for (int k = 0; k < absolute; k++) + { + linepos++; + aByte = stream.GetC(); + ptr[poffset ] = cmap[aByte].r; + ptr[poffset + 1] = cmap[aByte].g; + ptr[poffset + 2] = cmap[aByte].b; + column++; + } + if ( absolute & 0x01 ) + aByte = stream.GetC(); + } + } + else + { + for ( int l = 0; l < first && column < width; l++ ) + { + ptr[poffset ] = cmap[aByte].r; + ptr[poffset + 1] = cmap[aByte].g; + ptr[poffset + 2] = cmap[aByte].b; + column++; + linepos++; + } + } + } + else + { + ptr[poffset ] = cmap[aByte].r; + ptr[poffset + 1] = cmap[aByte].g; + ptr[poffset + 2] = cmap[aByte].b; + column++; + // linepos += size; seems to be wrong, RR + } + } + } + else if ( bpp == 24 ) + { + stream.Read(bbuf, 3); + linepos += 3; + ptr[poffset ] = (unsigned char)bbuf[2]; + ptr[poffset + 1] = (unsigned char)bbuf[1]; + ptr[poffset + 2] = (unsigned char)bbuf[0]; + column++; + } + else if ( bpp == 16 ) + { + unsigned char temp; + stream.Read(&aWord, 2); + aWord = wxUINT16_SWAP_ON_BE(aWord); + linepos += 2; + /* use the masks and calculated amonut of shift + to retrieve the color data out of the word. Then + shift it left by (8 - number of bits) such that + the image has the proper dynamic range */ + temp = (unsigned char)((aWord & rmask) >> rshift << (8-rbits)); + ptr[poffset] = temp; + temp = (unsigned char)((aWord & gmask) >> gshift << (8-gbits)); + ptr[poffset + 1] = temp; + temp = (unsigned char)((aWord & bmask) >> bshift << (8-bbits)); + ptr[poffset + 2] = temp; + column++; + } + else + { + unsigned char temp; + stream.Read(&aDword, 4); + aDword = wxINT32_SWAP_ON_BE(aDword); + linepos += 4; + temp = (unsigned char)((aDword & rmask) >> rshift); + ptr[poffset] = temp; + temp = (unsigned char)((aDword & gmask) >> gshift); + ptr[poffset + 1] = temp; + temp = (unsigned char)((aDword & bmask) >> bshift); + ptr[poffset + 2] = temp; + column++; + } + } + while ( (linepos < linesize) && (comp != 1) && (comp != 2) ) + { + stream.Read(&aByte, 1); + linepos += 1; + if ( !stream ) + break; + } + } + + delete[] cmap; + + image->SetMask(false); + + const wxStreamError err = stream.GetLastError(); + return err == wxSTREAM_NO_ERROR || err == wxSTREAM_EOF; +} + +bool wxBMPHandler::LoadDib(wxImage *image, wxInputStream& stream, + bool verbose, bool IsBmp) +{ + wxUint16 aWord; + wxInt32 dbuf[4]; + wxInt8 bbuf[4]; + + wxFileOffset offset = 0; // keep gcc quiet + if ( IsBmp ) + { + // read the header off the .BMP format file + + offset = stream.TellI(); + if (offset == wxInvalidOffset) + offset = 0; + + stream.Read(bbuf, 2); + stream.Read(dbuf, 16); + } + else + { + stream.Read(dbuf, 4); + } + #if 0 // unused + wxInt32 size = wxINT32_SWAP_ON_BE(dbuf[0]); + #endif + offset = offset + wxINT32_SWAP_ON_BE(dbuf[2]); + + stream.Read(dbuf, 4 * 2); + int width = wxINT32_SWAP_ON_BE((int)dbuf[0]); + int height = wxINT32_SWAP_ON_BE((int)dbuf[1]); + if ( !IsBmp)height = height / 2; // for icons divide by 2 + + if ( width > 32767 ) + { + if (verbose) + wxLogError( _("DIB Header: Image width > 32767 pixels for file.") ); + return false; + } + if ( height > 32767 ) + { + if (verbose) + wxLogError( _("DIB Header: Image height > 32767 pixels for file.") ); + return false; + } + + stream.Read(&aWord, 2); + /* + TODO + int planes = (int)wxUINT16_SWAP_ON_BE( aWord ); + */ + stream.Read(&aWord, 2); + int bpp = wxUINT16_SWAP_ON_BE((int)aWord); + if ( bpp != 1 && bpp != 4 && bpp != 8 && bpp != 16 && bpp != 24 && bpp != 32 ) + { + if (verbose) + wxLogError( _("DIB Header: Unknown bitdepth in file.") ); + return false; + } + + stream.Read(dbuf, 4 * 4); + int comp = wxINT32_SWAP_ON_BE((int)dbuf[0]); + if ( comp != BI_RGB && comp != BI_RLE4 && comp != BI_RLE8 && + comp != BI_BITFIELDS ) + { + if (verbose) + wxLogError( _("DIB Header: Unknown encoding in file.") ); + return false; + } + + stream.Read(dbuf, 4 * 2); + int ncolors = wxINT32_SWAP_ON_BE( (int)dbuf[0] ); + if (ncolors == 0) + ncolors = 1 << bpp; + /* some more sanity checks */ + if (((comp == BI_RLE4) && (bpp != 4)) || + ((comp == BI_RLE8) && (bpp != 8)) || + ((comp == BI_BITFIELDS) && (bpp != 16 && bpp != 32))) + { + if (verbose) + wxLogError( _("DIB Header: Encoding doesn't match bitdepth.") ); + return false; + } + + //read DIB; this is the BMP image or the XOR part of an icon image + if ( !DoLoadDib(image, width, height, bpp, ncolors, comp, offset, stream, + verbose, IsBmp, true) ) + { + if (verbose) + wxLogError( _("Error in reading image DIB.") ); + return false; + } + + if ( !IsBmp ) + { + //read Icon mask which is monochrome + //there is no palette, so we will create one + wxImage mask; + if ( !DoLoadDib(&mask, width, height, 1, 2, BI_RGB, offset, stream, + verbose, IsBmp, false) ) + { + if (verbose) + wxLogError( _("ICO: Error in reading mask DIB.") ); + return false; + } + image->SetMaskFromImage(mask, 255, 255, 255); + + } + + return true; +} + +bool wxBMPHandler::LoadFile(wxImage *image, wxInputStream& stream, + bool verbose, int WXUNUSED(index)) +{ + // Read a single DIB fom the file: + return LoadDib(image, stream, verbose, true/*isBmp*/); +} + +bool wxBMPHandler::DoCanRead(wxInputStream& stream) +{ + unsigned char hdr[2]; + + if ( !stream.Read(hdr, WXSIZEOF(hdr)) ) + return false; + + // do we have the BMP file signature? + return hdr[0] == 'B' && hdr[1] == 'M'; +} + +#endif // wxUSE_STREAMS + + +#if wxUSE_ICO_CUR +//----------------------------------------------------------------------------- +// wxICOHandler +//----------------------------------------------------------------------------- + +IMPLEMENT_DYNAMIC_CLASS(wxICOHandler, wxBMPHandler) + +#if wxUSE_STREAMS + +struct ICONDIRENTRY +{ + wxUint8 bWidth; // Width of the image + wxUint8 bHeight; // Height of the image (times 2) + wxUint8 bColorCount; // Number of colors in image (0 if >=8bpp) + wxUint8 bReserved; // Reserved + + // these two are different in icons and cursors: + // icon or cursor + wxUint16 wPlanes; // Color Planes or XHotSpot + wxUint16 wBitCount; // Bits per pixel or YHotSpot + + wxUint32 dwBytesInRes; // how many bytes in this resource? + wxUint32 dwImageOffset; // where in the file is this image +}; + +struct ICONDIR +{ + wxUint16 idReserved; // Reserved + wxUint16 idType; // resource type (1 for icons, 2 for cursors) + wxUint16 idCount; // how many images? +}; + + +bool wxICOHandler::SaveFile(wxImage *image, + wxOutputStream& stream, + bool verbose) + +{ + //sanity check; icon must be less than 127 pixels high and 255 wide + if ( image->GetHeight () > 127 ) + { + if ( verbose ) + wxLogError(_("ICO: Image too tall for an icon.")); + return false; + } + if ( image->GetWidth () > 255 ) + { + if ( verbose ) + wxLogError(_("ICO: Image too wide for an icon.")); + return false; + } + + const int images = 1; // only generate one image + + // VS: This is a hack of sort - since ICO and CUR files are almost + // identical, we have all the meat in wxICOHandler and check for + // the actual (handler) type when the code has to distinguish between + // the two formats + int type = (this->GetType() == wxBITMAP_TYPE_CUR) ? 2 : 1; + + // write a header, (ICONDIR) + // Calculate the header size + wxUint32 offset = 3 * sizeof(wxUint16); + + ICONDIR IconDir; + IconDir.idReserved = 0; + IconDir.idType = wxUINT16_SWAP_ON_BE((wxUint16)type); + IconDir.idCount = wxUINT16_SWAP_ON_BE((wxUint16)images); + stream.Write(&IconDir.idReserved, sizeof(IconDir.idReserved)); + stream.Write(&IconDir.idType, sizeof(IconDir.idType)); + stream.Write(&IconDir.idCount, sizeof(IconDir.idCount)); + if ( !stream.IsOk() ) + { + if ( verbose ) + wxLogError(_("ICO: Error writing the image file!")); + return false; + } + + // for each iamage write a description ICONDIRENTRY: + ICONDIRENTRY icondirentry; + for (int img = 0; img < images; img++) + { + wxImage mask; + + if ( image->HasMask() ) + { + // make another image with black/white: + mask = image->ConvertToMono (image->GetMaskRed(), image->GetMaskGreen(), image->GetMaskBlue() ); + + // now we need to change the masked regions to black: + unsigned char r = image->GetMaskRed(); + unsigned char g = image->GetMaskGreen(); + unsigned char b = image->GetMaskBlue(); + if ( (r != 0) || (g != 0) || (b != 0) ) + { + // Go round and apply black to the masked bits: + int i, j; + for (i = 0; i < mask.GetWidth(); i++) + { + for (j = 0; j < mask.GetHeight(); j++) + { + if ((r == mask.GetRed(i, j)) && + (g == mask.GetGreen(i, j))&& + (b == mask.GetBlue(i, j)) ) + image->SetRGB(i, j, 0, 0, 0 ); + } + } + } + } + else + { + // just make a black mask all over: + mask = image->Copy(); + int i, j; + for (i = 0; i < mask.GetWidth(); i++) + for (j = 0; j < mask.GetHeight(); j++) + mask.SetRGB(i, j, 0, 0, 0 ); + } + // Set the formats for image and mask + // (Windows never saves with more than 8 colors): + image->SetOption(wxIMAGE_OPTION_BMP_FORMAT, wxBMP_8BPP); + + // monochome bitmap: + mask.SetOption(wxIMAGE_OPTION_BMP_FORMAT, wxBMP_1BPP_BW); + bool IsBmp = false; + bool IsMask = false; + + //calculate size and offset of image and mask + wxCountingOutputStream cStream; + bool bResult = SaveDib(image, cStream, verbose, IsBmp, IsMask); + if ( !bResult ) + { + if ( verbose ) + wxLogError(_("ICO: Error writing the image file!")); + return false; + } + IsMask = true; + + bResult = SaveDib(&mask, cStream, verbose, IsBmp, IsMask); + if ( !bResult ) + { + if ( verbose ) + wxLogError(_("ICO: Error writing the image file!")); + return false; + } + wxUint32 Size = cStream.GetSize(); + + // wxCountingOutputStream::IsOk() always returns true for now and this + // "if" provokes VC++ warnings in optimized build +#if 0 + if ( !cStream.Ok() ) + { + if ( verbose ) + wxLogError(_("ICO: Error writing the image file!")); + return false; + } +#endif // 0 + + offset = offset + sizeof(ICONDIRENTRY); + + icondirentry.bWidth = (wxUint8)image->GetWidth(); + icondirentry.bHeight = (wxUint8)(2 * image->GetHeight()); + icondirentry.bColorCount = 0; + icondirentry.bReserved = 0; + icondirentry.wPlanes = wxUINT16_SWAP_ON_BE(1); + icondirentry.wBitCount = wxUINT16_SWAP_ON_BE(wxBMP_8BPP); + if ( type == 2 /*CUR*/) + { + int hx = image->HasOption(wxIMAGE_OPTION_CUR_HOTSPOT_X) ? + image->GetOptionInt(wxIMAGE_OPTION_CUR_HOTSPOT_X) : + image->GetWidth() / 2; + int hy = image->HasOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y) ? + image->GetOptionInt(wxIMAGE_OPTION_CUR_HOTSPOT_Y) : + image->GetHeight() / 2; + + // actually write the values of the hot spot here: + icondirentry.wPlanes = wxUINT16_SWAP_ON_BE((wxUint16)hx); + icondirentry.wBitCount = wxUINT16_SWAP_ON_BE((wxUint16)hy); + } + icondirentry.dwBytesInRes = wxUINT32_SWAP_ON_BE(Size); + icondirentry.dwImageOffset = wxUINT32_SWAP_ON_BE(offset); + + // increase size to allow for the data written: + offset += Size; + + // write to stream: + stream.Write(&icondirentry.bWidth, sizeof(icondirentry.bWidth)); + stream.Write(&icondirentry.bHeight, sizeof(icondirentry.bHeight)); + stream.Write(&icondirentry.bColorCount, sizeof(icondirentry.bColorCount)); + stream.Write(&icondirentry.bReserved, sizeof(icondirentry.bReserved)); + stream.Write(&icondirentry.wPlanes, sizeof(icondirentry.wPlanes)); + stream.Write(&icondirentry.wBitCount, sizeof(icondirentry.wBitCount)); + stream.Write(&icondirentry.dwBytesInRes, sizeof(icondirentry.dwBytesInRes)); + stream.Write(&icondirentry.dwImageOffset, sizeof(icondirentry.dwImageOffset)); + if ( !stream.IsOk() ) + { + if ( verbose ) + wxLogError(_("ICO: Error writing the image file!")); + return false; + } + + // actually save it: + IsMask = false; + bResult = SaveDib(image, stream, verbose, IsBmp, IsMask); + if ( !bResult ) + { + if ( verbose ) + wxLogError(_("ICO: Error writing the image file!")); + return false; + } + IsMask = true; + + bResult = SaveDib(&mask, stream, verbose, IsBmp, IsMask); + if ( !bResult ) + { + if ( verbose ) + wxLogError(_("ICO: Error writing the image file!")); + return false; + } + + } // end of for loop + + return true; +} + +bool wxICOHandler::LoadFile(wxImage *image, wxInputStream& stream, + bool verbose, int index) +{ + stream.SeekI(0); + return DoLoadFile(image, stream, verbose, index); +} + +bool wxICOHandler::DoLoadFile(wxImage *image, wxInputStream& stream, + bool WXUNUSED(verbose), int index) +{ + bool bResult wxDUMMY_INITIALIZE(false); + bool IsBmp = false; + + ICONDIR IconDir; + + wxFileOffset iPos = stream.TellI(); + stream.Read(&IconDir, sizeof(IconDir)); + wxUint16 nIcons = wxUINT16_SWAP_ON_BE(IconDir.idCount); + // nType is 1 for Icons, 2 for Cursors: + wxUint16 nType = wxUINT16_SWAP_ON_BE(IconDir.idType); + + // loop round the icons and choose the best one: + ICONDIRENTRY *pIconDirEntry = new ICONDIRENTRY[nIcons]; + ICONDIRENTRY *pCurrentEntry = pIconDirEntry; + int wMax = 0; + int colmax = 0; + int iSel = wxNOT_FOUND; + + for (int i = 0; i < nIcons; i++ ) + { + stream.Read(pCurrentEntry, sizeof(ICONDIRENTRY)); + // bHeight and bColorCount are wxUint8 + if ( pCurrentEntry->bWidth >= wMax ) + { + // see if we have more colors, ==0 indicates > 8bpp: + if ( pCurrentEntry->bColorCount == 0 ) + pCurrentEntry->bColorCount = 255; + if ( pCurrentEntry->bColorCount >= colmax ) + { + iSel = i; + wMax = pCurrentEntry->bWidth; + colmax = pCurrentEntry->bColorCount; + } + } + pCurrentEntry++; + } + + if ( index != -1 ) + { + // VS: Note that we *have* to run the loop above even if index != -1, because + // it reads ICONDIRENTRies. + iSel = index; + } + + if ( iSel == wxNOT_FOUND || iSel < 0 || iSel >= nIcons ) + { + wxLogError(_("ICO: Invalid icon index.")); + bResult = false; + } + else + { + // seek to selected icon: + pCurrentEntry = pIconDirEntry + iSel; + stream.SeekI(iPos + wxUINT32_SWAP_ON_BE(pCurrentEntry->dwImageOffset), wxFromStart); + bResult = LoadDib(image, stream, true, IsBmp); + bool bIsCursorType = (this->GetType() == wxBITMAP_TYPE_CUR) || (this->GetType() == wxBITMAP_TYPE_ANI); + if ( bResult && bIsCursorType && nType == 2 ) + { + // it is a cursor, so let's set the hotspot: + image->SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, wxUINT16_SWAP_ON_BE(pCurrentEntry->wPlanes)); + image->SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, wxUINT16_SWAP_ON_BE(pCurrentEntry->wBitCount)); + } + } + delete[] pIconDirEntry; + return bResult; +} + +int wxICOHandler::GetImageCount(wxInputStream& stream) +{ + ICONDIR IconDir; + wxFileOffset iPos = stream.TellI(); + stream.SeekI(0); + stream.Read(&IconDir, sizeof(IconDir)); + wxUint16 nIcons = wxUINT16_SWAP_ON_BE(IconDir.idCount); + stream.SeekI(iPos); + return (int)nIcons; +} + +bool wxICOHandler::DoCanRead(wxInputStream& stream) +{ + stream.SeekI(0); + unsigned char hdr[4]; + if ( !stream.Read(hdr, WXSIZEOF(hdr)) ) + return false; + + // hdr[2] is one for an icon and two for a cursor + return hdr[0] == '\0' && hdr[1] == '\0' && hdr[2] == '\1' && hdr[3] == '\0'; +} + +#endif // wxUSE_STREAMS + + +//----------------------------------------------------------------------------- +// wxCURHandler +//----------------------------------------------------------------------------- + +IMPLEMENT_DYNAMIC_CLASS(wxCURHandler, wxICOHandler) + +#if wxUSE_STREAMS + +bool wxCURHandler::DoCanRead(wxInputStream& stream) +{ + stream.SeekI(0); + unsigned char hdr[4]; + if ( !stream.Read(hdr, WXSIZEOF(hdr)) ) + return false; + + // hdr[2] is one for an icon and two for a cursor + return hdr[0] == '\0' && hdr[1] == '\0' && hdr[2] == '\2' && hdr[3] == '\0'; +} + +#endif // wxUSE_STREAMS + +//----------------------------------------------------------------------------- +// wxANIHandler +//----------------------------------------------------------------------------- + +IMPLEMENT_DYNAMIC_CLASS(wxANIHandler, wxCURHandler) + +#if wxUSE_STREAMS + +bool wxANIHandler::LoadFile(wxImage *image, wxInputStream& stream, + bool WXUNUSED(verbose), int index) +{ + wxANIDecoder decoder; + if (!decoder.Load(stream)) + return false; + + return decoder.ConvertToImage(index != -1 ? (size_t)index : 0, image); +} + +bool wxANIHandler::DoCanRead(wxInputStream& stream) +{ + wxANIDecoder decod; + return decod.CanRead(stream); +} + +int wxANIHandler::GetImageCount(wxInputStream& stream) +{ + wxANIDecoder decoder; + if (!decoder.Load(stream)) + return wxNOT_FOUND; + + return decoder.GetFrameCount(); +} + +#endif // wxUSE_STREAMS + +#endif // wxUSE_ICO_CUR + +#endif // wxUSE_IMAGE diff --git a/Externals/wxWidgets/src/common/image.cpp b/Externals/wxWidgets/src/common/image.cpp index 3a8e2236f0..d63f8fe29c 100644 --- a/Externals/wxWidgets/src/common/image.cpp +++ b/Externals/wxWidgets/src/common/image.cpp @@ -1,3128 +1,3128 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/image.cpp -// Purpose: wxImage -// Author: Robert Roebling -// RCS-ID: $Id: image.cpp 53245 2008-04-17 15:10:20Z RR $ -// Copyright: (c) Robert Roebling -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_IMAGE - -#include "wx/image.h" - -#ifndef WX_PRECOMP - #include "wx/log.h" - #include "wx/hash.h" - #include "wx/utils.h" - #include "wx/math.h" - #include "wx/module.h" - #include "wx/palette.h" - #include "wx/intl.h" -#endif - -#include "wx/filefn.h" -#include "wx/wfstream.h" -#include "wx/xpmdecod.h" - -// For memcpy -#include - -// make the code compile with either wxFile*Stream or wxFFile*Stream: -#define HAS_FILE_STREAMS (wxUSE_STREAMS && (wxUSE_FILE || wxUSE_FFILE)) - -#if HAS_FILE_STREAMS - #if wxUSE_FFILE - typedef wxFFileInputStream wxImageFileInputStream; - typedef wxFFileOutputStream wxImageFileOutputStream; - #elif wxUSE_FILE - typedef wxFileInputStream wxImageFileInputStream; - typedef wxFileOutputStream wxImageFileOutputStream; - #endif // wxUSE_FILE/wxUSE_FFILE -#endif // HAS_FILE_STREAMS - -#if wxUSE_VARIANT -IMPLEMENT_VARIANT_OBJECT_EXPORTED_SHALLOWCMP(wxImage,WXDLLEXPORT) -#endif - -//----------------------------------------------------------------------------- -// wxImage -//----------------------------------------------------------------------------- - -class wxImageRefData: public wxObjectRefData -{ -public: - wxImageRefData(); - virtual ~wxImageRefData(); - - int m_width; - int m_height; - unsigned char *m_data; - - bool m_hasMask; - unsigned char m_maskRed,m_maskGreen,m_maskBlue; - - // alpha channel data, may be NULL for the formats without alpha support - unsigned char *m_alpha; - - bool m_ok; - - // if true, m_data is pointer to static data and shouldn't be freed - bool m_static; - - // same as m_static but for m_alpha - bool m_staticAlpha; - -#if wxUSE_PALETTE - wxPalette m_palette; -#endif // wxUSE_PALETTE - - wxArrayString m_optionNames; - wxArrayString m_optionValues; - - DECLARE_NO_COPY_CLASS(wxImageRefData) -}; - -wxImageRefData::wxImageRefData() -{ - m_width = 0; - m_height = 0; - m_data = - m_alpha = (unsigned char *) NULL; - - m_maskRed = 0; - m_maskGreen = 0; - m_maskBlue = 0; - m_hasMask = false; - - m_ok = false; - m_static = - m_staticAlpha = false; -} - -wxImageRefData::~wxImageRefData() -{ - if ( !m_static ) - free( m_data ); - if ( !m_staticAlpha ) - free( m_alpha ); -} - -wxList wxImage::sm_handlers; - -wxImage wxNullImage; - -//----------------------------------------------------------------------------- - -#define M_IMGDATA wx_static_cast(wxImageRefData*, m_refData) - -IMPLEMENT_DYNAMIC_CLASS(wxImage, wxObject) - -wxImage::wxImage( int width, int height, bool clear ) -{ - Create( width, height, clear ); -} - -wxImage::wxImage( int width, int height, unsigned char* data, bool static_data ) -{ - Create( width, height, data, static_data ); -} - -wxImage::wxImage( int width, int height, unsigned char* data, unsigned char* alpha, bool static_data ) -{ - Create( width, height, data, alpha, static_data ); -} - -wxImage::wxImage( const wxString& name, long type, int index ) -{ - LoadFile( name, type, index ); -} - -wxImage::wxImage( const wxString& name, const wxString& mimetype, int index ) -{ - LoadFile( name, mimetype, index ); -} - -#if wxUSE_STREAMS -wxImage::wxImage( wxInputStream& stream, long type, int index ) -{ - LoadFile( stream, type, index ); -} - -wxImage::wxImage( wxInputStream& stream, const wxString& mimetype, int index ) -{ - LoadFile( stream, mimetype, index ); -} -#endif // wxUSE_STREAMS - -wxImage::wxImage(const char* const* xpmData) -{ - Create(xpmData); -} - -bool wxImage::Create(const char* const* xpmData) -{ -#if wxUSE_XPM - UnRef(); - - wxXPMDecoder decoder; - (*this) = decoder.ReadData(xpmData); - return Ok(); -#else - return false; -#endif -} - -bool wxImage::Create( int width, int height, bool clear ) -{ - UnRef(); - - m_refData = new wxImageRefData(); - - M_IMGDATA->m_data = (unsigned char *) malloc( width*height*3 ); - if (!M_IMGDATA->m_data) - { - UnRef(); - return false; - } - - if (clear) - memset(M_IMGDATA->m_data, 0, width*height*3); - - M_IMGDATA->m_width = width; - M_IMGDATA->m_height = height; - M_IMGDATA->m_ok = true; - - return true; -} - -bool wxImage::Create( int width, int height, unsigned char* data, bool static_data ) -{ - UnRef(); - - wxCHECK_MSG( data, false, _T("NULL data in wxImage::Create") ); - - m_refData = new wxImageRefData(); - - M_IMGDATA->m_data = data; - M_IMGDATA->m_width = width; - M_IMGDATA->m_height = height; - M_IMGDATA->m_ok = true; - M_IMGDATA->m_static = static_data; - - return true; -} - -bool wxImage::Create( int width, int height, unsigned char* data, unsigned char* alpha, bool static_data ) -{ - UnRef(); - - wxCHECK_MSG( data, false, _T("NULL data in wxImage::Create") ); - - m_refData = new wxImageRefData(); - - M_IMGDATA->m_data = data; - M_IMGDATA->m_alpha = alpha; - M_IMGDATA->m_width = width; - M_IMGDATA->m_height = height; - M_IMGDATA->m_ok = true; - M_IMGDATA->m_static = static_data; - - return true; -} - -void wxImage::Destroy() -{ - UnRef(); -} - -wxObjectRefData* wxImage::CreateRefData() const -{ - return new wxImageRefData; -} - -wxObjectRefData* wxImage::CloneRefData(const wxObjectRefData* that) const -{ - const wxImageRefData* refData = wx_static_cast(const wxImageRefData*, that); - wxCHECK_MSG(refData->m_ok, NULL, wxT("invalid image") ); - - wxImageRefData* refData_new = new wxImageRefData; - refData_new->m_width = refData->m_width; - refData_new->m_height = refData->m_height; - refData_new->m_maskRed = refData->m_maskRed; - refData_new->m_maskGreen = refData->m_maskGreen; - refData_new->m_maskBlue = refData->m_maskBlue; - refData_new->m_hasMask = refData->m_hasMask; - refData_new->m_ok = true; - unsigned size = unsigned(refData->m_width) * unsigned(refData->m_height); - if (refData->m_alpha != NULL) - { - refData_new->m_alpha = (unsigned char*)malloc(size); - memcpy(refData_new->m_alpha, refData->m_alpha, size); - } - size *= 3; - refData_new->m_data = (unsigned char*)malloc(size); - memcpy(refData_new->m_data, refData->m_data, size); -#if wxUSE_PALETTE - refData_new->m_palette = refData->m_palette; -#endif - refData_new->m_optionNames = refData->m_optionNames; - refData_new->m_optionValues = refData->m_optionValues; - return refData_new; -} - -wxImage wxImage::Copy() const -{ - wxImage image; - - wxCHECK_MSG( Ok(), image, wxT("invalid image") ); - - image.m_refData = CloneRefData(m_refData); - - return image; -} - -wxImage wxImage::ShrinkBy( int xFactor , int yFactor ) const -{ - if( xFactor == 1 && yFactor == 1 ) - return *this; - - wxImage image; - - wxCHECK_MSG( Ok(), image, wxT("invalid image") ); - - // can't scale to/from 0 size - wxCHECK_MSG( (xFactor > 0) && (yFactor > 0), image, - wxT("invalid new image size") ); - - long old_height = M_IMGDATA->m_height, - old_width = M_IMGDATA->m_width; - - wxCHECK_MSG( (old_height > 0) && (old_width > 0), image, - wxT("invalid old image size") ); - - long width = old_width / xFactor ; - long height = old_height / yFactor ; - - image.Create( width, height, false ); - - char unsigned *data = image.GetData(); - - wxCHECK_MSG( data, image, wxT("unable to create image") ); - - bool hasMask = false ; - unsigned char maskRed = 0; - unsigned char maskGreen = 0; - unsigned char maskBlue =0 ; - - unsigned char *source_data = M_IMGDATA->m_data; - unsigned char *target_data = data; - unsigned char *source_alpha = 0 ; - unsigned char *target_alpha = 0 ; - if (M_IMGDATA->m_hasMask) - { - hasMask = true ; - maskRed = M_IMGDATA->m_maskRed; - maskGreen = M_IMGDATA->m_maskGreen; - maskBlue =M_IMGDATA->m_maskBlue ; - - image.SetMaskColour( M_IMGDATA->m_maskRed, - M_IMGDATA->m_maskGreen, - M_IMGDATA->m_maskBlue ); - } - else - { - source_alpha = M_IMGDATA->m_alpha ; - if ( source_alpha ) - { - image.SetAlpha() ; - target_alpha = image.GetAlpha() ; - } - } - - for (long y = 0; y < height; y++) - { - for (long x = 0; x < width; x++) - { - unsigned long avgRed = 0 ; - unsigned long avgGreen = 0; - unsigned long avgBlue = 0; - unsigned long avgAlpha = 0 ; - unsigned long counter = 0 ; - // determine average - for ( int y1 = 0 ; y1 < yFactor ; ++y1 ) - { - long y_offset = (y * yFactor + y1) * old_width; - for ( int x1 = 0 ; x1 < xFactor ; ++x1 ) - { - unsigned char *pixel = source_data + 3 * ( y_offset + x * xFactor + x1 ) ; - unsigned char red = pixel[0] ; - unsigned char green = pixel[1] ; - unsigned char blue = pixel[2] ; - unsigned char alpha = 255 ; - if ( source_alpha ) - alpha = *(source_alpha + y_offset + x * xFactor + x1) ; - if ( !hasMask || red != maskRed || green != maskGreen || blue != maskBlue ) - { - if ( alpha > 0 ) - { - avgRed += red ; - avgGreen += green ; - avgBlue += blue ; - } - avgAlpha += alpha ; - counter++ ; - } - } - } - if ( counter == 0 ) - { - *(target_data++) = M_IMGDATA->m_maskRed ; - *(target_data++) = M_IMGDATA->m_maskGreen ; - *(target_data++) = M_IMGDATA->m_maskBlue ; - } - else - { - if ( source_alpha ) - *(target_alpha++) = (unsigned char)(avgAlpha / counter ) ; - *(target_data++) = (unsigned char)(avgRed / counter); - *(target_data++) = (unsigned char)(avgGreen / counter); - *(target_data++) = (unsigned char)(avgBlue / counter); - } - } - } - - // In case this is a cursor, make sure the hotspot is scaled accordingly: - if ( HasOption(wxIMAGE_OPTION_CUR_HOTSPOT_X) ) - image.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, - (GetOptionInt(wxIMAGE_OPTION_CUR_HOTSPOT_X))/xFactor); - if ( HasOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y) ) - image.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, - (GetOptionInt(wxIMAGE_OPTION_CUR_HOTSPOT_Y))/yFactor); - - return image; -} - -wxImage wxImage::Scale( int width, int height, int quality ) const -{ - wxImage image; - - wxCHECK_MSG( Ok(), image, wxT("invalid image") ); - - // can't scale to/from 0 size - wxCHECK_MSG( (width > 0) && (height > 0), image, - wxT("invalid new image size") ); - - long old_height = M_IMGDATA->m_height, - old_width = M_IMGDATA->m_width; - wxCHECK_MSG( (old_height > 0) && (old_width > 0), image, - wxT("invalid old image size") ); - - // If the image's new width and height are the same as the original, no - // need to waste time or CPU cycles - if ( old_width == width && old_height == height ) - return *this; - - // Scale the image (...or more appropriately, resample the image) using - // either the high-quality or normal method as specified - if ( quality == wxIMAGE_QUALITY_HIGH ) - { - // We need to check whether we are downsampling or upsampling the image - if ( width < old_width && height < old_height ) - { - // Downsample the image using the box averaging method for best results - image = ResampleBox(width, height); - } - else - { - // For upsampling or other random/wierd image dimensions we'll use - // a bicubic b-spline scaling method - image = ResampleBicubic(width, height); - } - } - else // Default scaling method == simple pixel replication - { - if ( old_width % width == 0 && old_width >= width && - old_height % height == 0 && old_height >= height ) - { - return ShrinkBy( old_width / width , old_height / height ) ; - } - image.Create( width, height, false ); - - unsigned char *data = image.GetData(); - - wxCHECK_MSG( data, image, wxT("unable to create image") ); - - unsigned char *source_data = M_IMGDATA->m_data; - unsigned char *target_data = data; - unsigned char *source_alpha = 0 ; - unsigned char *target_alpha = 0 ; - - if ( !M_IMGDATA->m_hasMask ) - { - source_alpha = M_IMGDATA->m_alpha ; - if ( source_alpha ) - { - image.SetAlpha() ; - target_alpha = image.GetAlpha() ; - } - } - - long x_delta = (old_width<<16) / width; - long y_delta = (old_height<<16) / height; - - unsigned char* dest_pixel = target_data; - - long y = 0; - for ( long j = 0; j < height; j++ ) - { - unsigned char* src_line = &source_data[(y>>16)*old_width*3]; - unsigned char* src_alpha_line = source_alpha ? &source_alpha[(y>>16)*old_width] : 0 ; - - long x = 0; - for ( long i = 0; i < width; i++ ) - { - unsigned char* src_pixel = &src_line[(x>>16)*3]; - unsigned char* src_alpha_pixel = source_alpha ? &src_alpha_line[(x>>16)] : 0 ; - dest_pixel[0] = src_pixel[0]; - dest_pixel[1] = src_pixel[1]; - dest_pixel[2] = src_pixel[2]; - dest_pixel += 3; - if ( source_alpha ) - *(target_alpha++) = *src_alpha_pixel ; - x += x_delta; - } - - y += y_delta; - } - } - - // If the original image has a mask, apply the mask to the new image - if (M_IMGDATA->m_hasMask) - { - image.SetMaskColour( M_IMGDATA->m_maskRed, - M_IMGDATA->m_maskGreen, - M_IMGDATA->m_maskBlue ); - } - - // In case this is a cursor, make sure the hotspot is scaled accordingly: - if ( HasOption(wxIMAGE_OPTION_CUR_HOTSPOT_X) ) - image.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, - (GetOptionInt(wxIMAGE_OPTION_CUR_HOTSPOT_X)*width)/old_width); - if ( HasOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y) ) - image.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, - (GetOptionInt(wxIMAGE_OPTION_CUR_HOTSPOT_Y)*height)/old_height); - - return image; -} - -wxImage wxImage::ResampleBox(int width, int height) const -{ - // This function implements a simple pre-blur/box averaging method for - // downsampling that gives reasonably smooth results To scale the image - // down we will need to gather a grid of pixels of the size of the scale - // factor in each direction and then do an averaging of the pixels. - - wxImage ret_image(width, height, false); - - const double scale_factor_x = double(M_IMGDATA->m_width) / width; - const double scale_factor_y = double(M_IMGDATA->m_height) / height; - - const int scale_factor_x_2 = (int)(scale_factor_x / 2); - const int scale_factor_y_2 = (int)(scale_factor_y / 2); - - unsigned char* src_data = M_IMGDATA->m_data; - unsigned char* src_alpha = M_IMGDATA->m_alpha; - unsigned char* dst_data = ret_image.GetData(); - unsigned char* dst_alpha = NULL; - - if ( src_alpha ) - { - ret_image.SetAlpha(); - dst_alpha = ret_image.GetAlpha(); - } - - int averaged_pixels, src_pixel_index; - double sum_r, sum_g, sum_b, sum_a; - - for ( int y = 0; y < height; y++ ) // Destination image - Y direction - { - // Source pixel in the Y direction - int src_y = (int)(y * scale_factor_y); - - for ( int x = 0; x < width; x++ ) // Destination image - X direction - { - // Source pixel in the X direction - int src_x = (int)(x * scale_factor_x); - - // Box of pixels to average - averaged_pixels = 0; - sum_r = sum_g = sum_b = sum_a = 0.0; - - for ( int j = int(src_y - scale_factor_y/2.0 + 1); - j <= int(src_y + scale_factor_y_2); - j++ ) - { - // We don't care to average pixels that don't exist (edges) - if ( j < 0 || j > M_IMGDATA->m_height - 1 ) - continue; - - for ( int i = int(src_x - scale_factor_x/2.0 + 1); - i <= src_x + scale_factor_x_2; - i++ ) - { - // Don't average edge pixels - if ( i < 0 || i > M_IMGDATA->m_width - 1 ) - continue; - - // Calculate the actual index in our source pixels - src_pixel_index = j * M_IMGDATA->m_width + i; - - sum_r += src_data[src_pixel_index * 3 + 0]; - sum_g += src_data[src_pixel_index * 3 + 1]; - sum_b += src_data[src_pixel_index * 3 + 2]; - if ( src_alpha ) - sum_a += src_alpha[src_pixel_index]; - - averaged_pixels++; - } - } - - // Calculate the average from the sum and number of averaged pixels - dst_data[0] = (unsigned char)(sum_r / averaged_pixels); - dst_data[1] = (unsigned char)(sum_g / averaged_pixels); - dst_data[2] = (unsigned char)(sum_b / averaged_pixels); - dst_data += 3; - if ( src_alpha ) - *dst_alpha++ = (unsigned char)(sum_a / averaged_pixels); - } - } - - return ret_image; -} - -// The following two local functions are for the B-spline weighting of the -// bicubic sampling algorithm -static inline double spline_cube(double value) -{ - return value <= 0.0 ? 0.0 : value * value * value; -} - -static inline double spline_weight(double value) -{ - return (spline_cube(value + 2) - - 4 * spline_cube(value + 1) + - 6 * spline_cube(value) - - 4 * spline_cube(value - 1)) / 6; -} - -// This is the bicubic resampling algorithm -wxImage wxImage::ResampleBicubic(int width, int height) const -{ - // This function implements a Bicubic B-Spline algorithm for resampling. - // This method is certainly a little slower than wxImage's default pixel - // replication method, however for most reasonably sized images not being - // upsampled too much on a fairly average CPU this difference is hardly - // noticeable and the results are far more pleasing to look at. - // - // This particular bicubic algorithm does pixel weighting according to a - // B-Spline that basically implements a Gaussian bell-like weighting - // kernel. Because of this method the results may appear a bit blurry when - // upsampling by large factors. This is basically because a slight - // gaussian blur is being performed to get the smooth look of the upsampled - // image. - - // Edge pixels: 3-4 possible solutions - // - (Wrap/tile) Wrap the image, take the color value from the opposite - // side of the image. - // - (Mirror) Duplicate edge pixels, so that pixel at coordinate (2, n), - // where n is nonpositive, will have the value of (2, 1). - // - (Ignore) Simply ignore the edge pixels and apply the kernel only to - // pixels which do have all neighbours. - // - (Clamp) Choose the nearest pixel along the border. This takes the - // border pixels and extends them out to infinity. - // - // NOTE: below the y_offset and x_offset variables are being set for edge - // pixels using the "Mirror" method mentioned above - - wxImage ret_image; - - ret_image.Create(width, height, false); - - unsigned char* src_data = M_IMGDATA->m_data; - unsigned char* src_alpha = M_IMGDATA->m_alpha; - unsigned char* dst_data = ret_image.GetData(); - unsigned char* dst_alpha = NULL; - - if ( src_alpha ) - { - ret_image.SetAlpha(); - dst_alpha = ret_image.GetAlpha(); - } - - for ( int dsty = 0; dsty < height; dsty++ ) - { - // We need to calculate the source pixel to interpolate from - Y-axis - double srcpixy = double(dsty * M_IMGDATA->m_height) / height; - double dy = srcpixy - (int)srcpixy; - - for ( int dstx = 0; dstx < width; dstx++ ) - { - // X-axis of pixel to interpolate from - double srcpixx = double(dstx * M_IMGDATA->m_width) / width; - double dx = srcpixx - (int)srcpixx; - - // Sums for each color channel - double sum_r = 0, sum_g = 0, sum_b = 0, sum_a = 0; - - // Here we actually determine the RGBA values for the destination pixel - for ( int k = -1; k <= 2; k++ ) - { - // Y offset - int y_offset = srcpixy + k < 0.0 - ? 0 - : srcpixy + k >= M_IMGDATA->m_height - ? M_IMGDATA->m_height - 1 - : (int)(srcpixy + k); - - // Loop across the X axis - for ( int i = -1; i <= 2; i++ ) - { - // X offset - int x_offset = srcpixx + i < 0.0 - ? 0 - : srcpixx + i >= M_IMGDATA->m_width - ? M_IMGDATA->m_width - 1 - : (int)(srcpixx + i); - - // Calculate the exact position where the source data - // should be pulled from based on the x_offset and y_offset - int src_pixel_index = y_offset*M_IMGDATA->m_width + x_offset; - - // Calculate the weight for the specified pixel according - // to the bicubic b-spline kernel we're using for - // interpolation - double - pixel_weight = spline_weight(i - dx)*spline_weight(k - dy); - - // Create a sum of all velues for each color channel - // adjusted for the pixel's calculated weight - sum_r += src_data[src_pixel_index * 3 + 0] * pixel_weight; - sum_g += src_data[src_pixel_index * 3 + 1] * pixel_weight; - sum_b += src_data[src_pixel_index * 3 + 2] * pixel_weight; - if ( src_alpha ) - sum_a += src_alpha[src_pixel_index] * pixel_weight; - } - } - - // Put the data into the destination image. The summed values are - // of double data type and are rounded here for accuracy - dst_data[0] = (unsigned char)(sum_r + 0.5); - dst_data[1] = (unsigned char)(sum_g + 0.5); - dst_data[2] = (unsigned char)(sum_b + 0.5); - dst_data += 3; - - if ( src_alpha ) - *dst_alpha++ = (unsigned char)sum_a; - } - } - - return ret_image; -} - -// Blur in the horizontal direction -wxImage wxImage::BlurHorizontal(int blurRadius) -{ - wxImage ret_image; - ret_image.Create(M_IMGDATA->m_width, M_IMGDATA->m_height, false); - - unsigned char* src_data = M_IMGDATA->m_data; - unsigned char* dst_data = ret_image.GetData(); - unsigned char* src_alpha = M_IMGDATA->m_alpha; - unsigned char* dst_alpha = NULL; - - // Check for a mask or alpha - if ( M_IMGDATA->m_hasMask ) - { - ret_image.SetMaskColour(M_IMGDATA->m_maskRed, - M_IMGDATA->m_maskGreen, - M_IMGDATA->m_maskBlue); - } - else - { - if ( src_alpha ) - { - ret_image.SetAlpha(); - dst_alpha = ret_image.GetAlpha(); - } - } - - // number of pixels we average over - const int blurArea = blurRadius*2 + 1; - - // Horizontal blurring algorithm - average all pixels in the specified blur - // radius in the X or horizontal direction - for ( int y = 0; y < M_IMGDATA->m_height; y++ ) - { - // Variables used in the blurring algorithm - long sum_r = 0, - sum_g = 0, - sum_b = 0, - sum_a = 0; - - long pixel_idx; - const unsigned char *src; - unsigned char *dst; - - // Calculate the average of all pixels in the blur radius for the first - // pixel of the row - for ( int kernel_x = -blurRadius; kernel_x <= blurRadius; kernel_x++ ) - { - // To deal with the pixels at the start of a row so it's not - // grabbing GOK values from memory at negative indices of the - // image's data or grabbing from the previous row - if ( kernel_x < 0 ) - pixel_idx = y * M_IMGDATA->m_width; - else - pixel_idx = kernel_x + y * M_IMGDATA->m_width; - - src = src_data + pixel_idx*3; - sum_r += src[0]; - sum_g += src[1]; - sum_b += src[2]; - if ( src_alpha ) - sum_a += src_alpha[pixel_idx]; - } - - dst = dst_data + y * M_IMGDATA->m_width*3; - dst[0] = (unsigned char)(sum_r / blurArea); - dst[1] = (unsigned char)(sum_g / blurArea); - dst[2] = (unsigned char)(sum_b / blurArea); - if ( src_alpha ) - dst_alpha[y * M_IMGDATA->m_width] = (unsigned char)(sum_a / blurArea); - - // Now average the values of the rest of the pixels by just moving the - // blur radius box along the row - for ( int x = 1; x < M_IMGDATA->m_width; x++ ) - { - // Take care of edge pixels on the left edge by essentially - // duplicating the edge pixel - if ( x - blurRadius - 1 < 0 ) - pixel_idx = y * M_IMGDATA->m_width; - else - pixel_idx = (x - blurRadius - 1) + y * M_IMGDATA->m_width; - - // Subtract the value of the pixel at the left side of the blur - // radius box - src = src_data + pixel_idx*3; - sum_r -= src[0]; - sum_g -= src[1]; - sum_b -= src[2]; - if ( src_alpha ) - sum_a -= src_alpha[pixel_idx]; - - // Take care of edge pixels on the right edge - if ( x + blurRadius > M_IMGDATA->m_width - 1 ) - pixel_idx = M_IMGDATA->m_width - 1 + y * M_IMGDATA->m_width; - else - pixel_idx = x + blurRadius + y * M_IMGDATA->m_width; - - // Add the value of the pixel being added to the end of our box - src = src_data + pixel_idx*3; - sum_r += src[0]; - sum_g += src[1]; - sum_b += src[2]; - if ( src_alpha ) - sum_a += src_alpha[pixel_idx]; - - // Save off the averaged data - dst = dst_data + x*3 + y*M_IMGDATA->m_width*3; - dst[0] = (unsigned char)(sum_r / blurArea); - dst[1] = (unsigned char)(sum_g / blurArea); - dst[2] = (unsigned char)(sum_b / blurArea); - if ( src_alpha ) - dst_alpha[x + y * M_IMGDATA->m_width] = (unsigned char)(sum_a / blurArea); - } - } - - return ret_image; -} - -// Blur in the vertical direction -wxImage wxImage::BlurVertical(int blurRadius) -{ - wxImage ret_image; - ret_image.Create(M_IMGDATA->m_width, M_IMGDATA->m_height, false); - - unsigned char* src_data = M_IMGDATA->m_data; - unsigned char* dst_data = ret_image.GetData(); - unsigned char* src_alpha = M_IMGDATA->m_alpha; - unsigned char* dst_alpha = NULL; - - // Check for a mask or alpha - if ( M_IMGDATA->m_hasMask ) - { - ret_image.SetMaskColour(M_IMGDATA->m_maskRed, - M_IMGDATA->m_maskGreen, - M_IMGDATA->m_maskBlue); - } - else - { - if ( src_alpha ) - { - ret_image.SetAlpha(); - dst_alpha = ret_image.GetAlpha(); - } - } - - // number of pixels we average over - const int blurArea = blurRadius*2 + 1; - - // Vertical blurring algorithm - same as horizontal but switched the - // opposite direction - for ( int x = 0; x < M_IMGDATA->m_width; x++ ) - { - // Variables used in the blurring algorithm - long sum_r = 0, - sum_g = 0, - sum_b = 0, - sum_a = 0; - - long pixel_idx; - const unsigned char *src; - unsigned char *dst; - - // Calculate the average of all pixels in our blur radius box for the - // first pixel of the column - for ( int kernel_y = -blurRadius; kernel_y <= blurRadius; kernel_y++ ) - { - // To deal with the pixels at the start of a column so it's not - // grabbing GOK values from memory at negative indices of the - // image's data or grabbing from the previous column - if ( kernel_y < 0 ) - pixel_idx = x; - else - pixel_idx = x + kernel_y * M_IMGDATA->m_width; - - src = src_data + pixel_idx*3; - sum_r += src[0]; - sum_g += src[1]; - sum_b += src[2]; - if ( src_alpha ) - sum_a += src_alpha[pixel_idx]; - } - - dst = dst_data + x*3; - dst[0] = (unsigned char)(sum_r / blurArea); - dst[1] = (unsigned char)(sum_g / blurArea); - dst[2] = (unsigned char)(sum_b / blurArea); - if ( src_alpha ) - dst_alpha[x] = (unsigned char)(sum_a / blurArea); - - // Now average the values of the rest of the pixels by just moving the - // box along the column from top to bottom - for ( int y = 1; y < M_IMGDATA->m_height; y++ ) - { - // Take care of pixels that would be beyond the top edge by - // duplicating the top edge pixel for the column - if ( y - blurRadius - 1 < 0 ) - pixel_idx = x; - else - pixel_idx = x + (y - blurRadius - 1) * M_IMGDATA->m_width; - - // Subtract the value of the pixel at the top of our blur radius box - src = src_data + pixel_idx*3; - sum_r -= src[0]; - sum_g -= src[1]; - sum_b -= src[2]; - if ( src_alpha ) - sum_a -= src_alpha[pixel_idx]; - - // Take care of the pixels that would be beyond the bottom edge of - // the image similar to the top edge - if ( y + blurRadius > M_IMGDATA->m_height - 1 ) - pixel_idx = x + (M_IMGDATA->m_height - 1) * M_IMGDATA->m_width; - else - pixel_idx = x + (blurRadius + y) * M_IMGDATA->m_width; - - // Add the value of the pixel being added to the end of our box - src = src_data + pixel_idx*3; - sum_r += src[0]; - sum_g += src[1]; - sum_b += src[2]; - if ( src_alpha ) - sum_a += src_alpha[pixel_idx]; - - // Save off the averaged data - dst = dst_data + (x + y * M_IMGDATA->m_width) * 3; - dst[0] = (unsigned char)(sum_r / blurArea); - dst[1] = (unsigned char)(sum_g / blurArea); - dst[2] = (unsigned char)(sum_b / blurArea); - if ( src_alpha ) - dst_alpha[x + y * M_IMGDATA->m_width] = (unsigned char)(sum_a / blurArea); - } - } - - return ret_image; -} - -// The new blur function -wxImage wxImage::Blur(int blurRadius) -{ - wxImage ret_image; - ret_image.Create(M_IMGDATA->m_width, M_IMGDATA->m_height, false); - - // Blur the image in each direction - ret_image = BlurHorizontal(blurRadius); - ret_image = ret_image.BlurVertical(blurRadius); - - return ret_image; -} - -wxImage wxImage::Rotate90( bool clockwise ) const -{ - wxImage image; - - wxCHECK_MSG( Ok(), image, wxT("invalid image") ); - - image.Create( M_IMGDATA->m_height, M_IMGDATA->m_width, false ); - - unsigned char *data = image.GetData(); - - wxCHECK_MSG( data, image, wxT("unable to create image") ); - - unsigned char *source_data = M_IMGDATA->m_data; - unsigned char *target_data; - unsigned char *alpha_data = 0 ; - unsigned char *source_alpha = 0 ; - unsigned char *target_alpha = 0 ; - - if (M_IMGDATA->m_hasMask) - { - image.SetMaskColour( M_IMGDATA->m_maskRed, M_IMGDATA->m_maskGreen, M_IMGDATA->m_maskBlue ); - } - else - { - source_alpha = M_IMGDATA->m_alpha ; - if ( source_alpha ) - { - image.SetAlpha() ; - alpha_data = image.GetAlpha() ; - } - } - - long height = M_IMGDATA->m_height; - long width = M_IMGDATA->m_width; - - for (long j = 0; j < height; j++) - { - for (long i = 0; i < width; i++) - { - if (clockwise) - { - target_data = data + (((i+1)*height) - j - 1)*3; - if(source_alpha) - target_alpha = alpha_data + (((i+1)*height) - j - 1); - } - else - { - target_data = data + ((height*(width-1)) + j - (i*height))*3; - if(source_alpha) - target_alpha = alpha_data + ((height*(width-1)) + j - (i*height)); - } - memcpy( target_data, source_data, 3 ); - source_data += 3; - - if(source_alpha) - { - memcpy( target_alpha, source_alpha, 1 ); - source_alpha += 1; - } - } - } - - return image; -} - -wxImage wxImage::Mirror( bool horizontally ) const -{ - wxImage image; - - wxCHECK_MSG( Ok(), image, wxT("invalid image") ); - - image.Create( M_IMGDATA->m_width, M_IMGDATA->m_height, false ); - - unsigned char *data = image.GetData(); - unsigned char *alpha = NULL; - - wxCHECK_MSG( data, image, wxT("unable to create image") ); - - if (M_IMGDATA->m_alpha != NULL) { - image.SetAlpha(); - alpha = image.GetAlpha(); - wxCHECK_MSG( alpha, image, wxT("unable to create alpha channel") ); - } - - if (M_IMGDATA->m_hasMask) - image.SetMaskColour( M_IMGDATA->m_maskRed, M_IMGDATA->m_maskGreen, M_IMGDATA->m_maskBlue ); - - long height = M_IMGDATA->m_height; - long width = M_IMGDATA->m_width; - - unsigned char *source_data = M_IMGDATA->m_data; - unsigned char *target_data; - - if (horizontally) - { - for (long j = 0; j < height; j++) - { - data += width*3; - target_data = data-3; - for (long i = 0; i < width; i++) - { - memcpy( target_data, source_data, 3 ); - source_data += 3; - target_data -= 3; - } - } - - if (alpha != NULL) - { - // src_alpha starts at the first pixel and increases by 1 after each step - // (a step here is the copy of the alpha value of one pixel) - const unsigned char *src_alpha = M_IMGDATA->m_alpha; - // dest_alpha starts just beyond the first line, decreases before each step, - // and after each line is finished, increases by 2 widths (skipping the line - // just copied and the line that will be copied next) - unsigned char *dest_alpha = alpha + width; - - for (long jj = 0; jj < height; ++jj) - { - for (long i = 0; i < width; ++i) { - *(--dest_alpha) = *(src_alpha++); // copy one pixel - } - dest_alpha += 2 * width; // advance beyond the end of the next line - } - } - } - else - { - for (long i = 0; i < height; i++) - { - target_data = data + 3*width*(height-1-i); - memcpy( target_data, source_data, (size_t)3*width ); - source_data += 3*width; - } - - if (alpha != NULL) - { - // src_alpha starts at the first pixel and increases by 1 width after each step - // (a step here is the copy of the alpha channel of an entire line) - const unsigned char *src_alpha = M_IMGDATA->m_alpha; - // dest_alpha starts just beyond the last line (beyond the whole image) - // and decreases by 1 width before each step - unsigned char *dest_alpha = alpha + width * height; - - for (long jj = 0; jj < height; ++jj) - { - dest_alpha -= width; - memcpy( dest_alpha, src_alpha, (size_t)width ); - src_alpha += width; - } - } - } - - return image; -} - -wxImage wxImage::GetSubImage( const wxRect &rect ) const -{ - wxImage image; - - wxCHECK_MSG( Ok(), image, wxT("invalid image") ); - - wxCHECK_MSG( (rect.GetLeft()>=0) && (rect.GetTop()>=0) && - (rect.GetRight()<=GetWidth()) && (rect.GetBottom()<=GetHeight()), - image, wxT("invalid subimage size") ); - - const int subwidth = rect.GetWidth(); - const int subheight = rect.GetHeight(); - - image.Create( subwidth, subheight, false ); - - const unsigned char *src_data = GetData(); - const unsigned char *src_alpha = M_IMGDATA->m_alpha; - unsigned char *subdata = image.GetData(); - unsigned char *subalpha = NULL; - - wxCHECK_MSG( subdata, image, wxT("unable to create image") ); - - if (src_alpha != NULL) { - image.SetAlpha(); - subalpha = image.GetAlpha(); - wxCHECK_MSG( subalpha, image, wxT("unable to create alpha channel")); - } - - if (M_IMGDATA->m_hasMask) - image.SetMaskColour( M_IMGDATA->m_maskRed, M_IMGDATA->m_maskGreen, M_IMGDATA->m_maskBlue ); - - const int width = GetWidth(); - const int pixsoff = rect.GetLeft() + width * rect.GetTop(); - - src_data += 3 * pixsoff; - src_alpha += pixsoff; // won't be used if was NULL, so this is ok - - for (long j = 0; j < subheight; ++j) - { - memcpy( subdata, src_data, 3 * subwidth ); - subdata += 3 * subwidth; - src_data += 3 * width; - if (subalpha != NULL) { - memcpy( subalpha, src_alpha, subwidth ); - subalpha += subwidth; - src_alpha += width; - } - } - - return image; -} - -wxImage wxImage::Size( const wxSize& size, const wxPoint& pos, - int r_, int g_, int b_ ) const -{ - wxImage image; - - wxCHECK_MSG( Ok(), image, wxT("invalid image") ); - wxCHECK_MSG( (size.GetWidth() > 0) && (size.GetHeight() > 0), image, wxT("invalid size") ); - - int width = GetWidth(), height = GetHeight(); - image.Create(size.GetWidth(), size.GetHeight(), false); - - unsigned char r = (unsigned char)r_; - unsigned char g = (unsigned char)g_; - unsigned char b = (unsigned char)b_; - if ((r_ == -1) && (g_ == -1) && (b_ == -1)) - { - GetOrFindMaskColour( &r, &g, &b ); - image.SetMaskColour(r, g, b); - } - - image.SetRGB(wxRect(), r, g, b); - - wxRect subRect(pos.x, pos.y, width, height); - wxRect finalRect(0, 0, size.GetWidth(), size.GetHeight()); - if (pos.x < 0) - finalRect.width -= pos.x; - if (pos.y < 0) - finalRect.height -= pos.y; - - subRect.Intersect(finalRect); - - if (!subRect.IsEmpty()) - { - if ((subRect.GetWidth() == width) && (subRect.GetHeight() == height)) - image.Paste(*this, pos.x, pos.y); - else - image.Paste(GetSubImage(subRect), pos.x, pos.y); - } - - return image; -} - -void wxImage::Paste( const wxImage &image, int x, int y ) -{ - wxCHECK_RET( Ok(), wxT("invalid image") ); - wxCHECK_RET( image.Ok(), wxT("invalid image") ); - - AllocExclusive(); - - int xx = 0; - int yy = 0; - int width = image.GetWidth(); - int height = image.GetHeight(); - - if (x < 0) - { - xx = -x; - width += x; - } - if (y < 0) - { - yy = -y; - height += y; - } - - if ((x+xx)+width > M_IMGDATA->m_width) - width = M_IMGDATA->m_width - (x+xx); - if ((y+yy)+height > M_IMGDATA->m_height) - height = M_IMGDATA->m_height - (y+yy); - - if (width < 1) return; - if (height < 1) return; - - if ((!HasMask() && !image.HasMask()) || - (HasMask() && !image.HasMask()) || - ((HasMask() && image.HasMask() && - (GetMaskRed()==image.GetMaskRed()) && - (GetMaskGreen()==image.GetMaskGreen()) && - (GetMaskBlue()==image.GetMaskBlue())))) - { - width *= 3; - unsigned char* source_data = image.GetData() + xx*3 + yy*3*image.GetWidth(); - int source_step = image.GetWidth()*3; - - unsigned char* target_data = GetData() + (x+xx)*3 + (y+yy)*3*M_IMGDATA->m_width; - int target_step = M_IMGDATA->m_width*3; - for (int j = 0; j < height; j++) - { - memcpy( target_data, source_data, width ); - source_data += source_step; - target_data += target_step; - } - return; - } - - // Copy over the alpha channel from the original image - if ( image.HasAlpha() ) - { - if ( !HasAlpha() ) - InitAlpha(); - - unsigned char* source_data = image.GetAlpha() + xx + yy*image.GetWidth(); - int source_step = image.GetWidth(); - - unsigned char* target_data = GetAlpha() + (x+xx) + (y+yy)*M_IMGDATA->m_width; - int target_step = M_IMGDATA->m_width; - - for (int j = 0; j < height; j++, - source_data += source_step, - target_data += target_step) - { - memcpy( target_data, source_data, width ); - } - } - - if (!HasMask() && image.HasMask()) - { - unsigned char r = image.GetMaskRed(); - unsigned char g = image.GetMaskGreen(); - unsigned char b = image.GetMaskBlue(); - - width *= 3; - unsigned char* source_data = image.GetData() + xx*3 + yy*3*image.GetWidth(); - int source_step = image.GetWidth()*3; - - unsigned char* target_data = GetData() + (x+xx)*3 + (y+yy)*3*M_IMGDATA->m_width; - int target_step = M_IMGDATA->m_width*3; - - for (int j = 0; j < height; j++) - { - for (int i = 0; i < width; i+=3) - { - if ((source_data[i] != r) || - (source_data[i+1] != g) || - (source_data[i+2] != b)) - { - memcpy( target_data+i, source_data+i, 3 ); - } - } - source_data += source_step; - target_data += target_step; - } - } -} - -void wxImage::Replace( unsigned char r1, unsigned char g1, unsigned char b1, - unsigned char r2, unsigned char g2, unsigned char b2 ) -{ - wxCHECK_RET( Ok(), wxT("invalid image") ); - - AllocExclusive(); - - unsigned char *data = GetData(); - - const int w = GetWidth(); - const int h = GetHeight(); - - for (int j = 0; j < h; j++) - for (int i = 0; i < w; i++) - { - if ((data[0] == r1) && (data[1] == g1) && (data[2] == b1)) - { - data[0] = r2; - data[1] = g2; - data[2] = b2; - } - data += 3; - } -} - -wxImage wxImage::ConvertToGreyscale( double lr, double lg, double lb ) const -{ - wxImage image; - - wxCHECK_MSG( Ok(), image, wxT("invalid image") ); - - image.Create(M_IMGDATA->m_width, M_IMGDATA->m_height, false); - - unsigned char *dest = image.GetData(); - - wxCHECK_MSG( dest, image, wxT("unable to create image") ); - - unsigned char *src = M_IMGDATA->m_data; - bool hasMask = M_IMGDATA->m_hasMask; - unsigned char maskRed = M_IMGDATA->m_maskRed; - unsigned char maskGreen = M_IMGDATA->m_maskGreen; - unsigned char maskBlue = M_IMGDATA->m_maskBlue; - - if ( hasMask ) - image.SetMaskColour(maskRed, maskGreen, maskBlue); - - const long size = M_IMGDATA->m_width * M_IMGDATA->m_height; - for ( long i = 0; i < size; i++, src += 3, dest += 3 ) - { - // don't modify the mask - if ( hasMask && src[0] == maskRed && src[1] == maskGreen && src[2] == maskBlue ) - { - memcpy(dest, src, 3); - } - else - { - // calculate the luma - double luma = (src[0] * lr + src[1] * lg + src[2] * lb) + 0.5; - dest[0] = dest[1] = dest[2] = wx_static_cast(unsigned char, luma); - } - } - - // copy the alpha channel, if any - if (HasAlpha()) - { - const size_t alphaSize = GetWidth() * GetHeight(); - unsigned char *alpha = (unsigned char*)malloc(alphaSize); - memcpy(alpha, GetAlpha(), alphaSize); - image.InitAlpha(); - image.SetAlpha(alpha); - } - - return image; -} - -wxImage wxImage::ConvertToMono( unsigned char r, unsigned char g, unsigned char b ) const -{ - wxImage image; - - wxCHECK_MSG( Ok(), image, wxT("invalid image") ); - - image.Create( M_IMGDATA->m_width, M_IMGDATA->m_height, false ); - - unsigned char *data = image.GetData(); - - wxCHECK_MSG( data, image, wxT("unable to create image") ); - - if (M_IMGDATA->m_hasMask) - { - if (M_IMGDATA->m_maskRed == r && M_IMGDATA->m_maskGreen == g && - M_IMGDATA->m_maskBlue == b) - image.SetMaskColour( 255, 255, 255 ); - else - image.SetMaskColour( 0, 0, 0 ); - } - - long size = M_IMGDATA->m_height * M_IMGDATA->m_width; - - unsigned char *srcd = M_IMGDATA->m_data; - unsigned char *tard = image.GetData(); - - for ( long i = 0; i < size; i++, srcd += 3, tard += 3 ) - { - if (srcd[0] == r && srcd[1] == g && srcd[2] == b) - tard[0] = tard[1] = tard[2] = 255; - else - tard[0] = tard[1] = tard[2] = 0; - } - - return image; -} - -int wxImage::GetWidth() const -{ - wxCHECK_MSG( Ok(), 0, wxT("invalid image") ); - - return M_IMGDATA->m_width; -} - -int wxImage::GetHeight() const -{ - wxCHECK_MSG( Ok(), 0, wxT("invalid image") ); - - return M_IMGDATA->m_height; -} - -long wxImage::XYToIndex(int x, int y) const -{ - if ( Ok() && - x >= 0 && y >= 0 && - x < M_IMGDATA->m_width && y < M_IMGDATA->m_height ) - { - return y*M_IMGDATA->m_width + x; - } - - return -1; -} - -void wxImage::SetRGB( int x, int y, unsigned char r, unsigned char g, unsigned char b ) -{ - long pos = XYToIndex(x, y); - wxCHECK_RET( pos != -1, wxT("invalid image coordinates") ); - - AllocExclusive(); - - pos *= 3; - - M_IMGDATA->m_data[ pos ] = r; - M_IMGDATA->m_data[ pos+1 ] = g; - M_IMGDATA->m_data[ pos+2 ] = b; -} - -void wxImage::SetRGB( const wxRect& rect_, unsigned char r, unsigned char g, unsigned char b ) -{ - wxCHECK_RET( Ok(), wxT("invalid image") ); - - AllocExclusive(); - - wxRect rect(rect_); - wxRect imageRect(0, 0, GetWidth(), GetHeight()); - if ( rect == wxRect() ) - { - rect = imageRect; - } - else - { - wxCHECK_RET( imageRect.Contains(rect.GetTopLeft()) && - imageRect.Contains(rect.GetBottomRight()), - wxT("invalid bounding rectangle") ); - } - - int x1 = rect.GetLeft(), - y1 = rect.GetTop(), - x2 = rect.GetRight() + 1, - y2 = rect.GetBottom() + 1; - - unsigned char *data wxDUMMY_INITIALIZE(NULL); - int x, y, width = GetWidth(); - for (y = y1; y < y2; y++) - { - data = M_IMGDATA->m_data + (y*width + x1)*3; - for (x = x1; x < x2; x++) - { - *data++ = r; - *data++ = g; - *data++ = b; - } - } -} - -unsigned char wxImage::GetRed( int x, int y ) const -{ - long pos = XYToIndex(x, y); - wxCHECK_MSG( pos != -1, 0, wxT("invalid image coordinates") ); - - pos *= 3; - - return M_IMGDATA->m_data[pos]; -} - -unsigned char wxImage::GetGreen( int x, int y ) const -{ - long pos = XYToIndex(x, y); - wxCHECK_MSG( pos != -1, 0, wxT("invalid image coordinates") ); - - pos *= 3; - - return M_IMGDATA->m_data[pos+1]; -} - -unsigned char wxImage::GetBlue( int x, int y ) const -{ - long pos = XYToIndex(x, y); - wxCHECK_MSG( pos != -1, 0, wxT("invalid image coordinates") ); - - pos *= 3; - - return M_IMGDATA->m_data[pos+2]; -} - -bool wxImage::IsOk() const -{ - // image of 0 width or height can't be considered ok - at least because it - // causes crashes in ConvertToBitmap() if we don't catch it in time - wxImageRefData *data = M_IMGDATA; - return data && data->m_ok && data->m_width && data->m_height; -} - -unsigned char *wxImage::GetData() const -{ - wxCHECK_MSG( Ok(), (unsigned char *)NULL, wxT("invalid image") ); - - return M_IMGDATA->m_data; -} - -void wxImage::SetData( unsigned char *data, bool static_data ) -{ - wxCHECK_RET( Ok(), wxT("invalid image") ); - - wxImageRefData *newRefData = new wxImageRefData(); - - newRefData->m_width = M_IMGDATA->m_width; - newRefData->m_height = M_IMGDATA->m_height; - newRefData->m_data = data; - newRefData->m_ok = true; - newRefData->m_maskRed = M_IMGDATA->m_maskRed; - newRefData->m_maskGreen = M_IMGDATA->m_maskGreen; - newRefData->m_maskBlue = M_IMGDATA->m_maskBlue; - newRefData->m_hasMask = M_IMGDATA->m_hasMask; - newRefData->m_static = static_data; - - UnRef(); - - m_refData = newRefData; -} - -void wxImage::SetData( unsigned char *data, int new_width, int new_height, bool static_data ) -{ - wxImageRefData *newRefData = new wxImageRefData(); - - if (m_refData) - { - newRefData->m_width = new_width; - newRefData->m_height = new_height; - newRefData->m_data = data; - newRefData->m_ok = true; - newRefData->m_maskRed = M_IMGDATA->m_maskRed; - newRefData->m_maskGreen = M_IMGDATA->m_maskGreen; - newRefData->m_maskBlue = M_IMGDATA->m_maskBlue; - newRefData->m_hasMask = M_IMGDATA->m_hasMask; - } - else - { - newRefData->m_width = new_width; - newRefData->m_height = new_height; - newRefData->m_data = data; - newRefData->m_ok = true; - } - newRefData->m_static = static_data; - - UnRef(); - - m_refData = newRefData; -} - -// ---------------------------------------------------------------------------- -// alpha channel support -// ---------------------------------------------------------------------------- - -void wxImage::SetAlpha(int x, int y, unsigned char alpha) -{ - wxCHECK_RET( HasAlpha(), wxT("no alpha channel") ); - - long pos = XYToIndex(x, y); - wxCHECK_RET( pos != -1, wxT("invalid image coordinates") ); - - AllocExclusive(); - - M_IMGDATA->m_alpha[pos] = alpha; -} - -unsigned char wxImage::GetAlpha(int x, int y) const -{ - wxCHECK_MSG( HasAlpha(), 0, wxT("no alpha channel") ); - - long pos = XYToIndex(x, y); - wxCHECK_MSG( pos != -1, 0, wxT("invalid image coordinates") ); - - return M_IMGDATA->m_alpha[pos]; -} - -bool -wxImage::ConvertColourToAlpha(unsigned char r, unsigned char g, unsigned char b) -{ - SetAlpha(NULL); - - const int w = M_IMGDATA->m_width; - const int h = M_IMGDATA->m_height; - - unsigned char *alpha = GetAlpha(); - unsigned char *data = GetData(); - - for ( int y = 0; y < h; y++ ) - { - for ( int x = 0; x < w; x++ ) - { - *alpha++ = *data; - *data++ = r; - *data++ = g; - *data++ = b; - } - } - - return true; -} - -void wxImage::SetAlpha( unsigned char *alpha, bool static_data ) -{ - wxCHECK_RET( Ok(), wxT("invalid image") ); - - AllocExclusive(); - - if ( !alpha ) - { - alpha = (unsigned char *)malloc(M_IMGDATA->m_width*M_IMGDATA->m_height); - } - - if( !M_IMGDATA->m_staticAlpha ) - free(M_IMGDATA->m_alpha); - - M_IMGDATA->m_alpha = alpha; - M_IMGDATA->m_staticAlpha = static_data; -} - -unsigned char *wxImage::GetAlpha() const -{ - wxCHECK_MSG( Ok(), (unsigned char *)NULL, wxT("invalid image") ); - - return M_IMGDATA->m_alpha; -} - -void wxImage::InitAlpha() -{ - wxCHECK_RET( !HasAlpha(), wxT("image already has an alpha channel") ); - - // initialize memory for alpha channel - SetAlpha(); - - unsigned char *alpha = M_IMGDATA->m_alpha; - const size_t lenAlpha = M_IMGDATA->m_width * M_IMGDATA->m_height; - - if ( HasMask() ) - { - // use the mask to initialize the alpha channel. - const unsigned char * const alphaEnd = alpha + lenAlpha; - - const unsigned char mr = M_IMGDATA->m_maskRed; - const unsigned char mg = M_IMGDATA->m_maskGreen; - const unsigned char mb = M_IMGDATA->m_maskBlue; - for ( unsigned char *src = M_IMGDATA->m_data; - alpha < alphaEnd; - src += 3, alpha++ ) - { - *alpha = (src[0] == mr && src[1] == mg && src[2] == mb) - ? wxIMAGE_ALPHA_TRANSPARENT - : wxIMAGE_ALPHA_OPAQUE; - } - - M_IMGDATA->m_hasMask = false; - } - else // no mask - { - // make the image fully opaque - memset(alpha, wxIMAGE_ALPHA_OPAQUE, lenAlpha); - } -} - -// ---------------------------------------------------------------------------- -// mask support -// ---------------------------------------------------------------------------- - -void wxImage::SetMaskColour( unsigned char r, unsigned char g, unsigned char b ) -{ - wxCHECK_RET( Ok(), wxT("invalid image") ); - - AllocExclusive(); - - M_IMGDATA->m_maskRed = r; - M_IMGDATA->m_maskGreen = g; - M_IMGDATA->m_maskBlue = b; - M_IMGDATA->m_hasMask = true; -} - -bool wxImage::GetOrFindMaskColour( unsigned char *r, unsigned char *g, unsigned char *b ) const -{ - wxCHECK_MSG( Ok(), false, wxT("invalid image") ); - - if (M_IMGDATA->m_hasMask) - { - if (r) *r = M_IMGDATA->m_maskRed; - if (g) *g = M_IMGDATA->m_maskGreen; - if (b) *b = M_IMGDATA->m_maskBlue; - return true; - } - else - { - FindFirstUnusedColour(r, g, b); - return false; - } -} - -unsigned char wxImage::GetMaskRed() const -{ - wxCHECK_MSG( Ok(), 0, wxT("invalid image") ); - - return M_IMGDATA->m_maskRed; -} - -unsigned char wxImage::GetMaskGreen() const -{ - wxCHECK_MSG( Ok(), 0, wxT("invalid image") ); - - return M_IMGDATA->m_maskGreen; -} - -unsigned char wxImage::GetMaskBlue() const -{ - wxCHECK_MSG( Ok(), 0, wxT("invalid image") ); - - return M_IMGDATA->m_maskBlue; -} - -void wxImage::SetMask( bool mask ) -{ - wxCHECK_RET( Ok(), wxT("invalid image") ); - - AllocExclusive(); - - M_IMGDATA->m_hasMask = mask; -} - -bool wxImage::HasMask() const -{ - wxCHECK_MSG( Ok(), false, wxT("invalid image") ); - - return M_IMGDATA->m_hasMask; -} - -bool wxImage::IsTransparent(int x, int y, unsigned char threshold) const -{ - long pos = XYToIndex(x, y); - wxCHECK_MSG( pos != -1, false, wxT("invalid image coordinates") ); - - // check mask - if ( M_IMGDATA->m_hasMask ) - { - const unsigned char *p = M_IMGDATA->m_data + 3*pos; - if ( p[0] == M_IMGDATA->m_maskRed && - p[1] == M_IMGDATA->m_maskGreen && - p[2] == M_IMGDATA->m_maskBlue ) - { - return true; - } - } - - // then check alpha - if ( M_IMGDATA->m_alpha ) - { - if ( M_IMGDATA->m_alpha[pos] < threshold ) - { - // transparent enough - return true; - } - } - - // not transparent - return false; -} - -bool wxImage::SetMaskFromImage(const wxImage& mask, - unsigned char mr, unsigned char mg, unsigned char mb) -{ - // check that the images are the same size - if ( (M_IMGDATA->m_height != mask.GetHeight() ) || (M_IMGDATA->m_width != mask.GetWidth () ) ) - { - wxLogError( _("Image and mask have different sizes.") ); - return false; - } - - // find unused colour - unsigned char r,g,b ; - if (!FindFirstUnusedColour(&r, &g, &b)) - { - wxLogError( _("No unused colour in image being masked.") ); - return false ; - } - - AllocExclusive(); - - unsigned char *imgdata = GetData(); - unsigned char *maskdata = mask.GetData(); - - const int w = GetWidth(); - const int h = GetHeight(); - - for (int j = 0; j < h; j++) - { - for (int i = 0; i < w; i++) - { - if ((maskdata[0] == mr) && (maskdata[1] == mg) && (maskdata[2] == mb)) - { - imgdata[0] = r; - imgdata[1] = g; - imgdata[2] = b; - } - imgdata += 3; - maskdata += 3; - } - } - - SetMaskColour(r, g, b); - SetMask(true); - - return true; -} - -bool wxImage::ConvertAlphaToMask(unsigned char threshold) -{ - if (!HasAlpha()) - return true; - - unsigned char mr, mg, mb; - if (!FindFirstUnusedColour(&mr, &mg, &mb)) - { - wxLogError( _("No unused colour in image being masked.") ); - return false; - } - - AllocExclusive(); - - SetMask(true); - SetMaskColour(mr, mg, mb); - - unsigned char *imgdata = GetData(); - unsigned char *alphadata = GetAlpha(); - - int w = GetWidth(); - int h = GetHeight(); - - for (int y = 0; y < h; y++) - { - for (int x = 0; x < w; x++, imgdata += 3, alphadata++) - { - if (*alphadata < threshold) - { - imgdata[0] = mr; - imgdata[1] = mg; - imgdata[2] = mb; - } - } - } - - if( !M_IMGDATA->m_staticAlpha ) - free(M_IMGDATA->m_alpha); - - M_IMGDATA->m_alpha = NULL; - M_IMGDATA->m_staticAlpha = false; - - return true; -} - -// ---------------------------------------------------------------------------- -// Palette functions -// ---------------------------------------------------------------------------- - -#if wxUSE_PALETTE - -bool wxImage::HasPalette() const -{ - if (!Ok()) - return false; - - return M_IMGDATA->m_palette.Ok(); -} - -const wxPalette& wxImage::GetPalette() const -{ - wxCHECK_MSG( Ok(), wxNullPalette, wxT("invalid image") ); - - return M_IMGDATA->m_palette; -} - -void wxImage::SetPalette(const wxPalette& palette) -{ - wxCHECK_RET( Ok(), wxT("invalid image") ); - - AllocExclusive(); - - M_IMGDATA->m_palette = palette; -} - -#endif // wxUSE_PALETTE - -// ---------------------------------------------------------------------------- -// Option functions (arbitrary name/value mapping) -// ---------------------------------------------------------------------------- - -void wxImage::SetOption(const wxString& name, const wxString& value) -{ - wxCHECK_RET( Ok(), wxT("invalid image") ); - - AllocExclusive(); - - int idx = M_IMGDATA->m_optionNames.Index(name, false); - if (idx == wxNOT_FOUND) - { - M_IMGDATA->m_optionNames.Add(name); - M_IMGDATA->m_optionValues.Add(value); - } - else - { - M_IMGDATA->m_optionNames[idx] = name; - M_IMGDATA->m_optionValues[idx] = value; - } -} - -void wxImage::SetOption(const wxString& name, int value) -{ - wxString valStr; - valStr.Printf(wxT("%d"), value); - SetOption(name, valStr); -} - -wxString wxImage::GetOption(const wxString& name) const -{ - wxCHECK_MSG( Ok(), wxEmptyString, wxT("invalid image") ); - - int idx = M_IMGDATA->m_optionNames.Index(name, false); - if (idx == wxNOT_FOUND) - return wxEmptyString; - else - return M_IMGDATA->m_optionValues[idx]; -} - -int wxImage::GetOptionInt(const wxString& name) const -{ - return wxAtoi(GetOption(name)); -} - -bool wxImage::HasOption(const wxString& name) const -{ - wxCHECK_MSG( Ok(), false, wxT("invalid image") ); - - return (M_IMGDATA->m_optionNames.Index(name, false) != wxNOT_FOUND); -} - -// ---------------------------------------------------------------------------- -// image I/O -// ---------------------------------------------------------------------------- - -bool wxImage::LoadFile( const wxString& WXUNUSED_UNLESS_STREAMS(filename), - long WXUNUSED_UNLESS_STREAMS(type), - int WXUNUSED_UNLESS_STREAMS(index) ) -{ -#if HAS_FILE_STREAMS - if (wxFileExists(filename)) - { - wxImageFileInputStream stream(filename); - wxBufferedInputStream bstream( stream ); - return LoadFile(bstream, type, index); - } - else - { - wxLogError( _("Can't load image from file '%s': file does not exist."), filename.c_str() ); - - return false; - } -#else // !HAS_FILE_STREAMS - return false; -#endif // HAS_FILE_STREAMS -} - -bool wxImage::LoadFile( const wxString& WXUNUSED_UNLESS_STREAMS(filename), - const wxString& WXUNUSED_UNLESS_STREAMS(mimetype), - int WXUNUSED_UNLESS_STREAMS(index) ) -{ -#if HAS_FILE_STREAMS - if (wxFileExists(filename)) - { - wxImageFileInputStream stream(filename); - wxBufferedInputStream bstream( stream ); - return LoadFile(bstream, mimetype, index); - } - else - { - wxLogError( _("Can't load image from file '%s': file does not exist."), filename.c_str() ); - - return false; - } -#else // !HAS_FILE_STREAMS - return false; -#endif // HAS_FILE_STREAMS -} - - - -bool wxImage::SaveFile( const wxString& filename ) const -{ - wxString ext = filename.AfterLast('.').Lower(); - - wxImageHandler * pHandler = FindHandler(ext, -1); - if (pHandler) - { - return SaveFile(filename, pHandler->GetType()); - } - - wxLogError(_("Can't save image to file '%s': unknown extension."), filename.c_str()); - - return false; -} - -bool wxImage::SaveFile( const wxString& WXUNUSED_UNLESS_STREAMS(filename), - int WXUNUSED_UNLESS_STREAMS(type) ) const -{ -#if HAS_FILE_STREAMS - wxCHECK_MSG( Ok(), false, wxT("invalid image") ); - - ((wxImage*)this)->SetOption(wxIMAGE_OPTION_FILENAME, filename); - - wxImageFileOutputStream stream(filename); - - if ( stream.IsOk() ) - { - wxBufferedOutputStream bstream( stream ); - return SaveFile(bstream, type); - } -#endif // HAS_FILE_STREAMS - - return false; -} - -bool wxImage::SaveFile( const wxString& WXUNUSED_UNLESS_STREAMS(filename), - const wxString& WXUNUSED_UNLESS_STREAMS(mimetype) ) const -{ -#if HAS_FILE_STREAMS - wxCHECK_MSG( Ok(), false, wxT("invalid image") ); - - ((wxImage*)this)->SetOption(wxIMAGE_OPTION_FILENAME, filename); - - wxImageFileOutputStream stream(filename); - - if ( stream.IsOk() ) - { - wxBufferedOutputStream bstream( stream ); - return SaveFile(bstream, mimetype); - } -#endif // HAS_FILE_STREAMS - - return false; -} - -bool wxImage::CanRead( const wxString& WXUNUSED_UNLESS_STREAMS(name) ) -{ -#if HAS_FILE_STREAMS - wxImageFileInputStream stream(name); - return CanRead(stream); -#else - return false; -#endif -} - -int wxImage::GetImageCount( const wxString& WXUNUSED_UNLESS_STREAMS(name), - long WXUNUSED_UNLESS_STREAMS(type) ) -{ -#if HAS_FILE_STREAMS - wxImageFileInputStream stream(name); - if (stream.Ok()) - return GetImageCount(stream, type); -#endif - - return 0; -} - -#if wxUSE_STREAMS - -bool wxImage::CanRead( wxInputStream &stream ) -{ - const wxList& list = GetHandlers(); - - for ( wxList::compatibility_iterator node = list.GetFirst(); node; node = node->GetNext() ) - { - wxImageHandler *handler=(wxImageHandler*)node->GetData(); - if (handler->CanRead( stream )) - return true; - } - - return false; -} - -int wxImage::GetImageCount( wxInputStream &stream, long type ) -{ - wxImageHandler *handler; - - if ( type == wxBITMAP_TYPE_ANY ) - { - wxList &list=GetHandlers(); - - for (wxList::compatibility_iterator node = list.GetFirst(); node; node = node->GetNext()) - { - handler=(wxImageHandler*)node->GetData(); - if ( handler->CanRead(stream) ) - return handler->GetImageCount(stream); - - } - - wxLogWarning(_("No handler found for image type.")); - return 0; - } - - handler = FindHandler(type); - - if ( !handler ) - { - wxLogWarning(_("No image handler for type %ld defined."), type); - return false; - } - - if ( handler->CanRead(stream) ) - { - return handler->GetImageCount(stream); - } - else - { - wxLogError(_("Image file is not of type %ld."), type); - return 0; - } -} - -bool wxImage::LoadFile( wxInputStream& stream, long type, int index ) -{ - UnRef(); - - m_refData = new wxImageRefData; - - wxImageHandler *handler; - - if ( type == wxBITMAP_TYPE_ANY ) - { - wxList &list=GetHandlers(); - - for ( wxList::compatibility_iterator node = list.GetFirst(); node; node = node->GetNext() ) - { - handler=(wxImageHandler*)node->GetData(); - if ( handler->CanRead(stream) ) - return handler->LoadFile(this, stream, true/*verbose*/, index); - - } - - wxLogWarning( _("No handler found for image type.") ); - return false; - } - - handler = FindHandler(type); - - if (handler == 0) - { - wxLogWarning( _("No image handler for type %ld defined."), type ); - - return false; - } - - if (stream.IsSeekable() && !handler->CanRead(stream)) - { - wxLogError(_("Image file is not of type %ld."), type); - return false; - } - else - return handler->LoadFile(this, stream, true/*verbose*/, index); -} - -bool wxImage::LoadFile( wxInputStream& stream, const wxString& mimetype, int index ) -{ - UnRef(); - - m_refData = new wxImageRefData; - - wxImageHandler *handler = FindHandlerMime(mimetype); - - if (handler == 0) - { - wxLogWarning( _("No image handler for type %s defined."), mimetype.GetData() ); - - return false; - } - - if (stream.IsSeekable() && !handler->CanRead(stream)) - { - wxLogError(_("Image file is not of type %s."), (const wxChar*) mimetype); - return false; - } - else - return handler->LoadFile( this, stream, true/*verbose*/, index ); -} - -bool wxImage::SaveFile( wxOutputStream& stream, int type ) const -{ - wxCHECK_MSG( Ok(), false, wxT("invalid image") ); - - wxImageHandler *handler = FindHandler(type); - if ( !handler ) - { - wxLogWarning( _("No image handler for type %d defined."), type ); - - return false; - } - - return handler->SaveFile( (wxImage*)this, stream ); -} - -bool wxImage::SaveFile( wxOutputStream& stream, const wxString& mimetype ) const -{ - wxCHECK_MSG( Ok(), false, wxT("invalid image") ); - - wxImageHandler *handler = FindHandlerMime(mimetype); - if ( !handler ) - { - wxLogWarning( _("No image handler for type %s defined."), mimetype.GetData() ); - - return false; - } - - return handler->SaveFile( (wxImage*)this, stream ); -} -#endif // wxUSE_STREAMS - -// ---------------------------------------------------------------------------- -// image I/O handlers -// ---------------------------------------------------------------------------- - -void wxImage::AddHandler( wxImageHandler *handler ) -{ - // Check for an existing handler of the type being added. - if (FindHandler( handler->GetType() ) == 0) - { - sm_handlers.Append( handler ); - } - else - { - // This is not documented behaviour, merely the simplest 'fix' - // for preventing duplicate additions. If someone ever has - // a good reason to add and remove duplicate handlers (and they - // may) we should probably refcount the duplicates. - // also an issue in InsertHandler below. - - wxLogDebug( _T("Adding duplicate image handler for '%s'"), - handler->GetName().c_str() ); - delete handler; - } -} - -void wxImage::InsertHandler( wxImageHandler *handler ) -{ - // Check for an existing handler of the type being added. - if (FindHandler( handler->GetType() ) == 0) - { - sm_handlers.Insert( handler ); - } - else - { - // see AddHandler for additional comments. - wxLogDebug( _T("Inserting duplicate image handler for '%s'"), - handler->GetName().c_str() ); - delete handler; - } -} - -bool wxImage::RemoveHandler( const wxString& name ) -{ - wxImageHandler *handler = FindHandler(name); - if (handler) - { - sm_handlers.DeleteObject(handler); - delete handler; - return true; - } - else - return false; -} - -wxImageHandler *wxImage::FindHandler( const wxString& name ) -{ - wxList::compatibility_iterator node = sm_handlers.GetFirst(); - while (node) - { - wxImageHandler *handler = (wxImageHandler*)node->GetData(); - if (handler->GetName().Cmp(name) == 0) return handler; - - node = node->GetNext(); - } - return 0; -} - -wxImageHandler *wxImage::FindHandler( const wxString& extension, long bitmapType ) -{ - wxList::compatibility_iterator node = sm_handlers.GetFirst(); - while (node) - { - wxImageHandler *handler = (wxImageHandler*)node->GetData(); - if ( (handler->GetExtension().Cmp(extension) == 0) && - (bitmapType == -1 || handler->GetType() == bitmapType) ) - return handler; - node = node->GetNext(); - } - return 0; -} - -wxImageHandler *wxImage::FindHandler( long bitmapType ) -{ - wxList::compatibility_iterator node = sm_handlers.GetFirst(); - while (node) - { - wxImageHandler *handler = (wxImageHandler *)node->GetData(); - if (handler->GetType() == bitmapType) return handler; - node = node->GetNext(); - } - return 0; -} - -wxImageHandler *wxImage::FindHandlerMime( const wxString& mimetype ) -{ - wxList::compatibility_iterator node = sm_handlers.GetFirst(); - while (node) - { - wxImageHandler *handler = (wxImageHandler *)node->GetData(); - if (handler->GetMimeType().IsSameAs(mimetype, false)) return handler; - node = node->GetNext(); - } - return 0; -} - -void wxImage::InitStandardHandlers() -{ -#if wxUSE_STREAMS - AddHandler(new wxBMPHandler); -#endif // wxUSE_STREAMS -} - -void wxImage::CleanUpHandlers() -{ - wxList::compatibility_iterator node = sm_handlers.GetFirst(); - while (node) - { - wxImageHandler *handler = (wxImageHandler *)node->GetData(); - wxList::compatibility_iterator next = node->GetNext(); - delete handler; - node = next; - } - - sm_handlers.Clear(); -} - -wxString wxImage::GetImageExtWildcard() -{ - wxString fmts; - - wxList& Handlers = wxImage::GetHandlers(); - wxList::compatibility_iterator Node = Handlers.GetFirst(); - while ( Node ) - { - wxImageHandler* Handler = (wxImageHandler*)Node->GetData(); - fmts += wxT("*.") + Handler->GetExtension(); - Node = Node->GetNext(); - if ( Node ) fmts += wxT(";"); - } - - return wxT("(") + fmts + wxT(")|") + fmts; -} - -wxImage::HSVValue wxImage::RGBtoHSV(const RGBValue& rgb) -{ - const double red = rgb.red / 255.0, - green = rgb.green / 255.0, - blue = rgb.blue / 255.0; - - // find the min and max intensity (and remember which one was it for the - // latter) - double minimumRGB = red; - if ( green < minimumRGB ) - minimumRGB = green; - if ( blue < minimumRGB ) - minimumRGB = blue; - - enum { RED, GREEN, BLUE } chMax = RED; - double maximumRGB = red; - if ( green > maximumRGB ) - { - chMax = GREEN; - maximumRGB = green; - } - if ( blue > maximumRGB ) - { - chMax = BLUE; - maximumRGB = blue; - } - - const double value = maximumRGB; - - double hue = 0.0, saturation; - const double deltaRGB = maximumRGB - minimumRGB; - if ( wxIsNullDouble(deltaRGB) ) - { - // Gray has no color - hue = 0.0; - saturation = 0.0; - } - else - { - switch ( chMax ) - { - case RED: - hue = (green - blue) / deltaRGB; - break; - - case GREEN: - hue = 2.0 + (blue - red) / deltaRGB; - break; - - case BLUE: - hue = 4.0 + (red - green) / deltaRGB; - break; - - default: - wxFAIL_MSG(wxT("hue not specified")); - break; - } - - hue /= 6.0; - - if ( hue < 0.0 ) - hue += 1.0; - - saturation = deltaRGB / maximumRGB; - } - - return HSVValue(hue, saturation, value); -} - -wxImage::RGBValue wxImage::HSVtoRGB(const HSVValue& hsv) -{ - double red, green, blue; - - if ( wxIsNullDouble(hsv.saturation) ) - { - // Grey - red = hsv.value; - green = hsv.value; - blue = hsv.value; - } - else // not grey - { - double hue = hsv.hue * 6.0; // sector 0 to 5 - int i = (int)floor(hue); - double f = hue - i; // fractional part of h - double p = hsv.value * (1.0 - hsv.saturation); - - switch (i) - { - case 0: - red = hsv.value; - green = hsv.value * (1.0 - hsv.saturation * (1.0 - f)); - blue = p; - break; - - case 1: - red = hsv.value * (1.0 - hsv.saturation * f); - green = hsv.value; - blue = p; - break; - - case 2: - red = p; - green = hsv.value; - blue = hsv.value * (1.0 - hsv.saturation * (1.0 - f)); - break; - - case 3: - red = p; - green = hsv.value * (1.0 - hsv.saturation * f); - blue = hsv.value; - break; - - case 4: - red = hsv.value * (1.0 - hsv.saturation * (1.0 - f)); - green = p; - blue = hsv.value; - break; - - default: // case 5: - red = hsv.value; - green = p; - blue = hsv.value * (1.0 - hsv.saturation * f); - break; - } - } - - return RGBValue((unsigned char)(red * 255.0), - (unsigned char)(green * 255.0), - (unsigned char)(blue * 255.0)); -} - -/* - * Rotates the hue of each pixel of the image. angle is a double in the range - * -1.0..1.0 where -1.0 is -360 degrees and 1.0 is 360 degrees - */ -void wxImage::RotateHue(double angle) -{ - AllocExclusive(); - - unsigned char *srcBytePtr; - unsigned char *dstBytePtr; - unsigned long count; - wxImage::HSVValue hsv; - wxImage::RGBValue rgb; - - wxASSERT (angle >= -1.0 && angle <= 1.0); - count = M_IMGDATA->m_width * M_IMGDATA->m_height; - if ( count > 0 && !wxIsNullDouble(angle) ) - { - srcBytePtr = M_IMGDATA->m_data; - dstBytePtr = srcBytePtr; - do - { - rgb.red = *srcBytePtr++; - rgb.green = *srcBytePtr++; - rgb.blue = *srcBytePtr++; - hsv = RGBtoHSV(rgb); - - hsv.hue = hsv.hue + angle; - if (hsv.hue > 1.0) - hsv.hue = hsv.hue - 1.0; - else if (hsv.hue < 0.0) - hsv.hue = hsv.hue + 1.0; - - rgb = HSVtoRGB(hsv); - *dstBytePtr++ = rgb.red; - *dstBytePtr++ = rgb.green; - *dstBytePtr++ = rgb.blue; - } while (--count != 0); - } -} - -//----------------------------------------------------------------------------- -// wxImageHandler -//----------------------------------------------------------------------------- - -IMPLEMENT_ABSTRACT_CLASS(wxImageHandler,wxObject) - -#if wxUSE_STREAMS -bool wxImageHandler::LoadFile( wxImage *WXUNUSED(image), wxInputStream& WXUNUSED(stream), bool WXUNUSED(verbose), int WXUNUSED(index) ) -{ - return false; -} - -bool wxImageHandler::SaveFile( wxImage *WXUNUSED(image), wxOutputStream& WXUNUSED(stream), bool WXUNUSED(verbose) ) -{ - return false; -} - -int wxImageHandler::GetImageCount( wxInputStream& WXUNUSED(stream) ) -{ - return 1; -} - -bool wxImageHandler::CanRead( const wxString& name ) -{ - if (wxFileExists(name)) - { - wxImageFileInputStream stream(name); - return CanRead(stream); - } - - wxLogError( _("Can't check image format of file '%s': file does not exist."), name.c_str() ); - - return false; -} - -bool wxImageHandler::CallDoCanRead(wxInputStream& stream) -{ - wxFileOffset posOld = stream.TellI(); - if ( posOld == wxInvalidOffset ) - { - // can't test unseekable stream - return false; - } - - bool ok = DoCanRead(stream); - - // restore the old position to be able to test other formats and so on - if ( stream.SeekI(posOld) == wxInvalidOffset ) - { - wxLogDebug(_T("Failed to rewind the stream in wxImageHandler!")); - - // reading would fail anyhow as we're not at the right position - return false; - } - - return ok; -} - -#endif // wxUSE_STREAMS - -// ---------------------------------------------------------------------------- -// image histogram stuff -// ---------------------------------------------------------------------------- - -bool -wxImageHistogram::FindFirstUnusedColour(unsigned char *r, - unsigned char *g, - unsigned char *b, - unsigned char r2, - unsigned char b2, - unsigned char g2) const -{ - unsigned long key = MakeKey(r2, g2, b2); - - while ( find(key) != end() ) - { - // color already used - r2++; - if ( r2 >= 255 ) - { - r2 = 0; - g2++; - if ( g2 >= 255 ) - { - g2 = 0; - b2++; - if ( b2 >= 255 ) - { - wxLogError(_("No unused colour in image.") ); - return false; - } - } - } - - key = MakeKey(r2, g2, b2); - } - - if ( r ) - *r = r2; - if ( g ) - *g = g2; - if ( b ) - *b = b2; - - return true; -} - -bool -wxImage::FindFirstUnusedColour(unsigned char *r, - unsigned char *g, - unsigned char *b, - unsigned char r2, - unsigned char b2, - unsigned char g2) const -{ - wxImageHistogram histogram; - - ComputeHistogram(histogram); - - return histogram.FindFirstUnusedColour(r, g, b, r2, g2, b2); -} - - - -// GRG, Dic/99 -// Counts and returns the number of different colours. Optionally stops -// when it exceeds 'stopafter' different colours. This is useful, for -// example, to see if the image can be saved as 8-bit (256 colour or -// less, in this case it would be invoked as CountColours(256)). Default -// value for stopafter is -1 (don't care). -// -unsigned long wxImage::CountColours( unsigned long stopafter ) const -{ - wxHashTable h; - wxObject dummy; - unsigned char r, g, b; - unsigned char *p; - unsigned long size, nentries, key; - - p = GetData(); - size = GetWidth() * GetHeight(); - nentries = 0; - - for (unsigned long j = 0; (j < size) && (nentries <= stopafter) ; j++) - { - r = *(p++); - g = *(p++); - b = *(p++); - key = wxImageHistogram::MakeKey(r, g, b); - - if (h.Get(key) == NULL) - { - h.Put(key, &dummy); - nentries++; - } - } - - return nentries; -} - - -unsigned long wxImage::ComputeHistogram( wxImageHistogram &h ) const -{ - unsigned char *p = GetData(); - unsigned long nentries = 0; - - h.clear(); - - const unsigned long size = GetWidth() * GetHeight(); - - unsigned char r, g, b; - for ( unsigned long n = 0; n < size; n++ ) - { - r = *p++; - g = *p++; - b = *p++; - - wxImageHistogramEntry& entry = h[wxImageHistogram::MakeKey(r, g, b)]; - - if ( entry.value++ == 0 ) - entry.index = nentries++; - } - - return nentries; -} - -/* - * Rotation code by Carlos Moreno - */ - -static const double wxROTATE_EPSILON = 1e-10; - -// Auxiliary function to rotate a point (x,y) with respect to point p0 -// make it inline and use a straight return to facilitate optimization -// also, the function receives the sine and cosine of the angle to avoid -// repeating the time-consuming calls to these functions -- sin/cos can -// be computed and stored in the calling function. - -static inline wxRealPoint -wxRotatePoint(const wxRealPoint& p, double cos_angle, double sin_angle, - const wxRealPoint& p0) -{ - return wxRealPoint(p0.x + (p.x - p0.x) * cos_angle - (p.y - p0.y) * sin_angle, - p0.y + (p.y - p0.y) * cos_angle + (p.x - p0.x) * sin_angle); -} - -static inline wxRealPoint -wxRotatePoint(double x, double y, double cos_angle, double sin_angle, - const wxRealPoint & p0) -{ - return wxRotatePoint (wxRealPoint(x,y), cos_angle, sin_angle, p0); -} - -wxImage wxImage::Rotate(double angle, const wxPoint & centre_of_rotation, bool interpolating, wxPoint * offset_after_rotation) const -{ - int i; - angle = -angle; // screen coordinates are a mirror image of "real" coordinates - - bool has_alpha = HasAlpha(); - - const int w = GetWidth(), - h = GetHeight(); - - // Create pointer-based array to accelerate access to wxImage's data - unsigned char ** data = new unsigned char * [h]; - data[0] = GetData(); - for (i = 1; i < h; i++) - data[i] = data[i - 1] + (3 * w); - - // Same for alpha channel - unsigned char ** alpha = NULL; - if (has_alpha) - { - alpha = new unsigned char * [h]; - alpha[0] = GetAlpha(); - for (i = 1; i < h; i++) - alpha[i] = alpha[i - 1] + w; - } - - // precompute coefficients for rotation formula - // (sine and cosine of the angle) - const double cos_angle = cos(angle); - const double sin_angle = sin(angle); - - // Create new Image to store the result - // First, find rectangle that covers the rotated image; to do that, - // rotate the four corners - - const wxRealPoint p0(centre_of_rotation.x, centre_of_rotation.y); - - wxRealPoint p1 = wxRotatePoint (0, 0, cos_angle, sin_angle, p0); - wxRealPoint p2 = wxRotatePoint (0, h, cos_angle, sin_angle, p0); - wxRealPoint p3 = wxRotatePoint (w, 0, cos_angle, sin_angle, p0); - wxRealPoint p4 = wxRotatePoint (w, h, cos_angle, sin_angle, p0); - - int x1a = (int) floor (wxMin (wxMin(p1.x, p2.x), wxMin(p3.x, p4.x))); - int y1a = (int) floor (wxMin (wxMin(p1.y, p2.y), wxMin(p3.y, p4.y))); - int x2a = (int) ceil (wxMax (wxMax(p1.x, p2.x), wxMax(p3.x, p4.x))); - int y2a = (int) ceil (wxMax (wxMax(p1.y, p2.y), wxMax(p3.y, p4.y))); - - // Create rotated image - wxImage rotated (x2a - x1a + 1, y2a - y1a + 1, false); - // With alpha channel - if (has_alpha) - rotated.SetAlpha(); - - if (offset_after_rotation != NULL) - { - *offset_after_rotation = wxPoint (x1a, y1a); - } - - // GRG: The rotated (destination) image is always accessed - // sequentially, so there is no need for a pointer-based - // array here (and in fact it would be slower). - // - unsigned char * dst = rotated.GetData(); - - unsigned char * alpha_dst = NULL; - if (has_alpha) - alpha_dst = rotated.GetAlpha(); - - // GRG: if the original image has a mask, use its RGB values - // as the blank pixel, else, fall back to default (black). - // - unsigned char blank_r = 0; - unsigned char blank_g = 0; - unsigned char blank_b = 0; - - if (HasMask()) - { - blank_r = GetMaskRed(); - blank_g = GetMaskGreen(); - blank_b = GetMaskBlue(); - rotated.SetMaskColour( blank_r, blank_g, blank_b ); - } - - // Now, for each point of the rotated image, find where it came from, by - // performing an inverse rotation (a rotation of -angle) and getting the - // pixel at those coordinates - - const int rH = rotated.GetHeight(); - const int rW = rotated.GetWidth(); - - // GRG: I've taken the (interpolating) test out of the loops, so that - // it is done only once, instead of repeating it for each pixel. - - if (interpolating) - { - for (int y = 0; y < rH; y++) - { - for (int x = 0; x < rW; x++) - { - wxRealPoint src = wxRotatePoint (x + x1a, y + y1a, cos_angle, -sin_angle, p0); - - if (-0.25 < src.x && src.x < w - 0.75 && - -0.25 < src.y && src.y < h - 0.75) - { - // interpolate using the 4 enclosing grid-points. Those - // points can be obtained using floor and ceiling of the - // exact coordinates of the point - int x1, y1, x2, y2; - - if (0 < src.x && src.x < w - 1) - { - x1 = wxRound(floor(src.x)); - x2 = wxRound(ceil(src.x)); - } - else // else means that x is near one of the borders (0 or width-1) - { - x1 = x2 = wxRound (src.x); - } - - if (0 < src.y && src.y < h - 1) - { - y1 = wxRound(floor(src.y)); - y2 = wxRound(ceil(src.y)); - } - else - { - y1 = y2 = wxRound (src.y); - } - - // get four points and the distances (square of the distance, - // for efficiency reasons) for the interpolation formula - - // GRG: Do not calculate the points until they are - // really needed -- this way we can calculate - // just one, instead of four, if d1, d2, d3 - // or d4 are < wxROTATE_EPSILON - - const double d1 = (src.x - x1) * (src.x - x1) + (src.y - y1) * (src.y - y1); - const double d2 = (src.x - x2) * (src.x - x2) + (src.y - y1) * (src.y - y1); - const double d3 = (src.x - x2) * (src.x - x2) + (src.y - y2) * (src.y - y2); - const double d4 = (src.x - x1) * (src.x - x1) + (src.y - y2) * (src.y - y2); - - // Now interpolate as a weighted average of the four surrounding - // points, where the weights are the distances to each of those points - - // If the point is exactly at one point of the grid of the source - // image, then don't interpolate -- just assign the pixel - - // d1,d2,d3,d4 are positive -- no need for abs() - if (d1 < wxROTATE_EPSILON) - { - unsigned char *p = data[y1] + (3 * x1); - *(dst++) = *(p++); - *(dst++) = *(p++); - *(dst++) = *p; - - if (has_alpha) - *(alpha_dst++) = *(alpha[y1] + x1); - } - else if (d2 < wxROTATE_EPSILON) - { - unsigned char *p = data[y1] + (3 * x2); - *(dst++) = *(p++); - *(dst++) = *(p++); - *(dst++) = *p; - - if (has_alpha) - *(alpha_dst++) = *(alpha[y1] + x2); - } - else if (d3 < wxROTATE_EPSILON) - { - unsigned char *p = data[y2] + (3 * x2); - *(dst++) = *(p++); - *(dst++) = *(p++); - *(dst++) = *p; - - if (has_alpha) - *(alpha_dst++) = *(alpha[y2] + x2); - } - else if (d4 < wxROTATE_EPSILON) - { - unsigned char *p = data[y2] + (3 * x1); - *(dst++) = *(p++); - *(dst++) = *(p++); - *(dst++) = *p; - - if (has_alpha) - *(alpha_dst++) = *(alpha[y2] + x1); - } - else - { - // weights for the weighted average are proportional to the inverse of the distance - unsigned char *v1 = data[y1] + (3 * x1); - unsigned char *v2 = data[y1] + (3 * x2); - unsigned char *v3 = data[y2] + (3 * x2); - unsigned char *v4 = data[y2] + (3 * x1); - - const double w1 = 1/d1, w2 = 1/d2, w3 = 1/d3, w4 = 1/d4; - - // GRG: Unrolled. - - *(dst++) = (unsigned char) - ( (w1 * *(v1++) + w2 * *(v2++) + - w3 * *(v3++) + w4 * *(v4++)) / - (w1 + w2 + w3 + w4) ); - *(dst++) = (unsigned char) - ( (w1 * *(v1++) + w2 * *(v2++) + - w3 * *(v3++) + w4 * *(v4++)) / - (w1 + w2 + w3 + w4) ); - *(dst++) = (unsigned char) - ( (w1 * *v1 + w2 * *v2 + - w3 * *v3 + w4 * *v4) / - (w1 + w2 + w3 + w4) ); - - if (has_alpha) - { - v1 = alpha[y1] + (x1); - v2 = alpha[y1] + (x2); - v3 = alpha[y2] + (x2); - v4 = alpha[y2] + (x1); - - *(alpha_dst++) = (unsigned char) - ( (w1 * *v1 + w2 * *v2 + - w3 * *v3 + w4 * *v4) / - (w1 + w2 + w3 + w4) ); - } - } - } - else - { - *(dst++) = blank_r; - *(dst++) = blank_g; - *(dst++) = blank_b; - - if (has_alpha) - *(alpha_dst++) = 0; - } - } - } - } - else // not interpolating - { - for (int y = 0; y < rH; y++) - { - for (int x = 0; x < rW; x++) - { - wxRealPoint src = wxRotatePoint (x + x1a, y + y1a, cos_angle, -sin_angle, p0); - - const int xs = wxRound (src.x); // wxRound rounds to the - const int ys = wxRound (src.y); // closest integer - - if (0 <= xs && xs < w && 0 <= ys && ys < h) - { - unsigned char *p = data[ys] + (3 * xs); - *(dst++) = *(p++); - *(dst++) = *(p++); - *(dst++) = *p; - - if (has_alpha) - *(alpha_dst++) = *(alpha[ys] + (xs)); - } - else - { - *(dst++) = blank_r; - *(dst++) = blank_g; - *(dst++) = blank_b; - - if (has_alpha) - *(alpha_dst++) = 255; - } - } - } - } - - delete [] data; - - if (has_alpha) - delete [] alpha; - - return rotated; -} - - - - - -// A module to allow wxImage initialization/cleanup -// without calling these functions from app.cpp or from -// the user's application. - -class wxImageModule: public wxModule -{ -DECLARE_DYNAMIC_CLASS(wxImageModule) -public: - wxImageModule() {} - bool OnInit() { wxImage::InitStandardHandlers(); return true; } - void OnExit() { wxImage::CleanUpHandlers(); } -}; - -IMPLEMENT_DYNAMIC_CLASS(wxImageModule, wxModule) - - -#endif // wxUSE_IMAGE +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/image.cpp +// Purpose: wxImage +// Author: Robert Roebling +// RCS-ID: $Id: image.cpp 53245 2008-04-17 15:10:20Z RR $ +// Copyright: (c) Robert Roebling +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_IMAGE + +#include "wx/image.h" + +#ifndef WX_PRECOMP + #include "wx/log.h" + #include "wx/hash.h" + #include "wx/utils.h" + #include "wx/math.h" + #include "wx/module.h" + #include "wx/palette.h" + #include "wx/intl.h" +#endif + +#include "wx/filefn.h" +#include "wx/wfstream.h" +#include "wx/xpmdecod.h" + +// For memcpy +#include + +// make the code compile with either wxFile*Stream or wxFFile*Stream: +#define HAS_FILE_STREAMS (wxUSE_STREAMS && (wxUSE_FILE || wxUSE_FFILE)) + +#if HAS_FILE_STREAMS + #if wxUSE_FFILE + typedef wxFFileInputStream wxImageFileInputStream; + typedef wxFFileOutputStream wxImageFileOutputStream; + #elif wxUSE_FILE + typedef wxFileInputStream wxImageFileInputStream; + typedef wxFileOutputStream wxImageFileOutputStream; + #endif // wxUSE_FILE/wxUSE_FFILE +#endif // HAS_FILE_STREAMS + +#if wxUSE_VARIANT +IMPLEMENT_VARIANT_OBJECT_EXPORTED_SHALLOWCMP(wxImage,WXDLLEXPORT) +#endif + +//----------------------------------------------------------------------------- +// wxImage +//----------------------------------------------------------------------------- + +class wxImageRefData: public wxObjectRefData +{ +public: + wxImageRefData(); + virtual ~wxImageRefData(); + + int m_width; + int m_height; + unsigned char *m_data; + + bool m_hasMask; + unsigned char m_maskRed,m_maskGreen,m_maskBlue; + + // alpha channel data, may be NULL for the formats without alpha support + unsigned char *m_alpha; + + bool m_ok; + + // if true, m_data is pointer to static data and shouldn't be freed + bool m_static; + + // same as m_static but for m_alpha + bool m_staticAlpha; + +#if wxUSE_PALETTE + wxPalette m_palette; +#endif // wxUSE_PALETTE + + wxArrayString m_optionNames; + wxArrayString m_optionValues; + + DECLARE_NO_COPY_CLASS(wxImageRefData) +}; + +wxImageRefData::wxImageRefData() +{ + m_width = 0; + m_height = 0; + m_data = + m_alpha = (unsigned char *) NULL; + + m_maskRed = 0; + m_maskGreen = 0; + m_maskBlue = 0; + m_hasMask = false; + + m_ok = false; + m_static = + m_staticAlpha = false; +} + +wxImageRefData::~wxImageRefData() +{ + if ( !m_static ) + free( m_data ); + if ( !m_staticAlpha ) + free( m_alpha ); +} + +wxList wxImage::sm_handlers; + +wxImage wxNullImage; + +//----------------------------------------------------------------------------- + +#define M_IMGDATA wx_static_cast(wxImageRefData*, m_refData) + +IMPLEMENT_DYNAMIC_CLASS(wxImage, wxObject) + +wxImage::wxImage( int width, int height, bool clear ) +{ + Create( width, height, clear ); +} + +wxImage::wxImage( int width, int height, unsigned char* data, bool static_data ) +{ + Create( width, height, data, static_data ); +} + +wxImage::wxImage( int width, int height, unsigned char* data, unsigned char* alpha, bool static_data ) +{ + Create( width, height, data, alpha, static_data ); +} + +wxImage::wxImage( const wxString& name, long type, int index ) +{ + LoadFile( name, type, index ); +} + +wxImage::wxImage( const wxString& name, const wxString& mimetype, int index ) +{ + LoadFile( name, mimetype, index ); +} + +#if wxUSE_STREAMS +wxImage::wxImage( wxInputStream& stream, long type, int index ) +{ + LoadFile( stream, type, index ); +} + +wxImage::wxImage( wxInputStream& stream, const wxString& mimetype, int index ) +{ + LoadFile( stream, mimetype, index ); +} +#endif // wxUSE_STREAMS + +wxImage::wxImage(const char* const* xpmData) +{ + Create(xpmData); +} + +bool wxImage::Create(const char* const* xpmData) +{ +#if wxUSE_XPM + UnRef(); + + wxXPMDecoder decoder; + (*this) = decoder.ReadData(xpmData); + return Ok(); +#else + return false; +#endif +} + +bool wxImage::Create( int width, int height, bool clear ) +{ + UnRef(); + + m_refData = new wxImageRefData(); + + M_IMGDATA->m_data = (unsigned char *) malloc( width*height*3 ); + if (!M_IMGDATA->m_data) + { + UnRef(); + return false; + } + + if (clear) + memset(M_IMGDATA->m_data, 0, width*height*3); + + M_IMGDATA->m_width = width; + M_IMGDATA->m_height = height; + M_IMGDATA->m_ok = true; + + return true; +} + +bool wxImage::Create( int width, int height, unsigned char* data, bool static_data ) +{ + UnRef(); + + wxCHECK_MSG( data, false, _T("NULL data in wxImage::Create") ); + + m_refData = new wxImageRefData(); + + M_IMGDATA->m_data = data; + M_IMGDATA->m_width = width; + M_IMGDATA->m_height = height; + M_IMGDATA->m_ok = true; + M_IMGDATA->m_static = static_data; + + return true; +} + +bool wxImage::Create( int width, int height, unsigned char* data, unsigned char* alpha, bool static_data ) +{ + UnRef(); + + wxCHECK_MSG( data, false, _T("NULL data in wxImage::Create") ); + + m_refData = new wxImageRefData(); + + M_IMGDATA->m_data = data; + M_IMGDATA->m_alpha = alpha; + M_IMGDATA->m_width = width; + M_IMGDATA->m_height = height; + M_IMGDATA->m_ok = true; + M_IMGDATA->m_static = static_data; + + return true; +} + +void wxImage::Destroy() +{ + UnRef(); +} + +wxObjectRefData* wxImage::CreateRefData() const +{ + return new wxImageRefData; +} + +wxObjectRefData* wxImage::CloneRefData(const wxObjectRefData* that) const +{ + const wxImageRefData* refData = wx_static_cast(const wxImageRefData*, that); + wxCHECK_MSG(refData->m_ok, NULL, wxT("invalid image") ); + + wxImageRefData* refData_new = new wxImageRefData; + refData_new->m_width = refData->m_width; + refData_new->m_height = refData->m_height; + refData_new->m_maskRed = refData->m_maskRed; + refData_new->m_maskGreen = refData->m_maskGreen; + refData_new->m_maskBlue = refData->m_maskBlue; + refData_new->m_hasMask = refData->m_hasMask; + refData_new->m_ok = true; + unsigned size = unsigned(refData->m_width) * unsigned(refData->m_height); + if (refData->m_alpha != NULL) + { + refData_new->m_alpha = (unsigned char*)malloc(size); + memcpy(refData_new->m_alpha, refData->m_alpha, size); + } + size *= 3; + refData_new->m_data = (unsigned char*)malloc(size); + memcpy(refData_new->m_data, refData->m_data, size); +#if wxUSE_PALETTE + refData_new->m_palette = refData->m_palette; +#endif + refData_new->m_optionNames = refData->m_optionNames; + refData_new->m_optionValues = refData->m_optionValues; + return refData_new; +} + +wxImage wxImage::Copy() const +{ + wxImage image; + + wxCHECK_MSG( Ok(), image, wxT("invalid image") ); + + image.m_refData = CloneRefData(m_refData); + + return image; +} + +wxImage wxImage::ShrinkBy( int xFactor , int yFactor ) const +{ + if( xFactor == 1 && yFactor == 1 ) + return *this; + + wxImage image; + + wxCHECK_MSG( Ok(), image, wxT("invalid image") ); + + // can't scale to/from 0 size + wxCHECK_MSG( (xFactor > 0) && (yFactor > 0), image, + wxT("invalid new image size") ); + + long old_height = M_IMGDATA->m_height, + old_width = M_IMGDATA->m_width; + + wxCHECK_MSG( (old_height > 0) && (old_width > 0), image, + wxT("invalid old image size") ); + + long width = old_width / xFactor ; + long height = old_height / yFactor ; + + image.Create( width, height, false ); + + char unsigned *data = image.GetData(); + + wxCHECK_MSG( data, image, wxT("unable to create image") ); + + bool hasMask = false ; + unsigned char maskRed = 0; + unsigned char maskGreen = 0; + unsigned char maskBlue =0 ; + + unsigned char *source_data = M_IMGDATA->m_data; + unsigned char *target_data = data; + unsigned char *source_alpha = 0 ; + unsigned char *target_alpha = 0 ; + if (M_IMGDATA->m_hasMask) + { + hasMask = true ; + maskRed = M_IMGDATA->m_maskRed; + maskGreen = M_IMGDATA->m_maskGreen; + maskBlue =M_IMGDATA->m_maskBlue ; + + image.SetMaskColour( M_IMGDATA->m_maskRed, + M_IMGDATA->m_maskGreen, + M_IMGDATA->m_maskBlue ); + } + else + { + source_alpha = M_IMGDATA->m_alpha ; + if ( source_alpha ) + { + image.SetAlpha() ; + target_alpha = image.GetAlpha() ; + } + } + + for (long y = 0; y < height; y++) + { + for (long x = 0; x < width; x++) + { + unsigned long avgRed = 0 ; + unsigned long avgGreen = 0; + unsigned long avgBlue = 0; + unsigned long avgAlpha = 0 ; + unsigned long counter = 0 ; + // determine average + for ( int y1 = 0 ; y1 < yFactor ; ++y1 ) + { + long y_offset = (y * yFactor + y1) * old_width; + for ( int x1 = 0 ; x1 < xFactor ; ++x1 ) + { + unsigned char *pixel = source_data + 3 * ( y_offset + x * xFactor + x1 ) ; + unsigned char red = pixel[0] ; + unsigned char green = pixel[1] ; + unsigned char blue = pixel[2] ; + unsigned char alpha = 255 ; + if ( source_alpha ) + alpha = *(source_alpha + y_offset + x * xFactor + x1) ; + if ( !hasMask || red != maskRed || green != maskGreen || blue != maskBlue ) + { + if ( alpha > 0 ) + { + avgRed += red ; + avgGreen += green ; + avgBlue += blue ; + } + avgAlpha += alpha ; + counter++ ; + } + } + } + if ( counter == 0 ) + { + *(target_data++) = M_IMGDATA->m_maskRed ; + *(target_data++) = M_IMGDATA->m_maskGreen ; + *(target_data++) = M_IMGDATA->m_maskBlue ; + } + else + { + if ( source_alpha ) + *(target_alpha++) = (unsigned char)(avgAlpha / counter ) ; + *(target_data++) = (unsigned char)(avgRed / counter); + *(target_data++) = (unsigned char)(avgGreen / counter); + *(target_data++) = (unsigned char)(avgBlue / counter); + } + } + } + + // In case this is a cursor, make sure the hotspot is scaled accordingly: + if ( HasOption(wxIMAGE_OPTION_CUR_HOTSPOT_X) ) + image.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, + (GetOptionInt(wxIMAGE_OPTION_CUR_HOTSPOT_X))/xFactor); + if ( HasOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y) ) + image.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, + (GetOptionInt(wxIMAGE_OPTION_CUR_HOTSPOT_Y))/yFactor); + + return image; +} + +wxImage wxImage::Scale( int width, int height, int quality ) const +{ + wxImage image; + + wxCHECK_MSG( Ok(), image, wxT("invalid image") ); + + // can't scale to/from 0 size + wxCHECK_MSG( (width > 0) && (height > 0), image, + wxT("invalid new image size") ); + + long old_height = M_IMGDATA->m_height, + old_width = M_IMGDATA->m_width; + wxCHECK_MSG( (old_height > 0) && (old_width > 0), image, + wxT("invalid old image size") ); + + // If the image's new width and height are the same as the original, no + // need to waste time or CPU cycles + if ( old_width == width && old_height == height ) + return *this; + + // Scale the image (...or more appropriately, resample the image) using + // either the high-quality or normal method as specified + if ( quality == wxIMAGE_QUALITY_HIGH ) + { + // We need to check whether we are downsampling or upsampling the image + if ( width < old_width && height < old_height ) + { + // Downsample the image using the box averaging method for best results + image = ResampleBox(width, height); + } + else + { + // For upsampling or other random/wierd image dimensions we'll use + // a bicubic b-spline scaling method + image = ResampleBicubic(width, height); + } + } + else // Default scaling method == simple pixel replication + { + if ( old_width % width == 0 && old_width >= width && + old_height % height == 0 && old_height >= height ) + { + return ShrinkBy( old_width / width , old_height / height ) ; + } + image.Create( width, height, false ); + + unsigned char *data = image.GetData(); + + wxCHECK_MSG( data, image, wxT("unable to create image") ); + + unsigned char *source_data = M_IMGDATA->m_data; + unsigned char *target_data = data; + unsigned char *source_alpha = 0 ; + unsigned char *target_alpha = 0 ; + + if ( !M_IMGDATA->m_hasMask ) + { + source_alpha = M_IMGDATA->m_alpha ; + if ( source_alpha ) + { + image.SetAlpha() ; + target_alpha = image.GetAlpha() ; + } + } + + long x_delta = (old_width<<16) / width; + long y_delta = (old_height<<16) / height; + + unsigned char* dest_pixel = target_data; + + long y = 0; + for ( long j = 0; j < height; j++ ) + { + unsigned char* src_line = &source_data[(y>>16)*old_width*3]; + unsigned char* src_alpha_line = source_alpha ? &source_alpha[(y>>16)*old_width] : 0 ; + + long x = 0; + for ( long i = 0; i < width; i++ ) + { + unsigned char* src_pixel = &src_line[(x>>16)*3]; + unsigned char* src_alpha_pixel = source_alpha ? &src_alpha_line[(x>>16)] : 0 ; + dest_pixel[0] = src_pixel[0]; + dest_pixel[1] = src_pixel[1]; + dest_pixel[2] = src_pixel[2]; + dest_pixel += 3; + if ( source_alpha ) + *(target_alpha++) = *src_alpha_pixel ; + x += x_delta; + } + + y += y_delta; + } + } + + // If the original image has a mask, apply the mask to the new image + if (M_IMGDATA->m_hasMask) + { + image.SetMaskColour( M_IMGDATA->m_maskRed, + M_IMGDATA->m_maskGreen, + M_IMGDATA->m_maskBlue ); + } + + // In case this is a cursor, make sure the hotspot is scaled accordingly: + if ( HasOption(wxIMAGE_OPTION_CUR_HOTSPOT_X) ) + image.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, + (GetOptionInt(wxIMAGE_OPTION_CUR_HOTSPOT_X)*width)/old_width); + if ( HasOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y) ) + image.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, + (GetOptionInt(wxIMAGE_OPTION_CUR_HOTSPOT_Y)*height)/old_height); + + return image; +} + +wxImage wxImage::ResampleBox(int width, int height) const +{ + // This function implements a simple pre-blur/box averaging method for + // downsampling that gives reasonably smooth results To scale the image + // down we will need to gather a grid of pixels of the size of the scale + // factor in each direction and then do an averaging of the pixels. + + wxImage ret_image(width, height, false); + + const double scale_factor_x = double(M_IMGDATA->m_width) / width; + const double scale_factor_y = double(M_IMGDATA->m_height) / height; + + const int scale_factor_x_2 = (int)(scale_factor_x / 2); + const int scale_factor_y_2 = (int)(scale_factor_y / 2); + + unsigned char* src_data = M_IMGDATA->m_data; + unsigned char* src_alpha = M_IMGDATA->m_alpha; + unsigned char* dst_data = ret_image.GetData(); + unsigned char* dst_alpha = NULL; + + if ( src_alpha ) + { + ret_image.SetAlpha(); + dst_alpha = ret_image.GetAlpha(); + } + + int averaged_pixels, src_pixel_index; + double sum_r, sum_g, sum_b, sum_a; + + for ( int y = 0; y < height; y++ ) // Destination image - Y direction + { + // Source pixel in the Y direction + int src_y = (int)(y * scale_factor_y); + + for ( int x = 0; x < width; x++ ) // Destination image - X direction + { + // Source pixel in the X direction + int src_x = (int)(x * scale_factor_x); + + // Box of pixels to average + averaged_pixels = 0; + sum_r = sum_g = sum_b = sum_a = 0.0; + + for ( int j = int(src_y - scale_factor_y/2.0 + 1); + j <= int(src_y + scale_factor_y_2); + j++ ) + { + // We don't care to average pixels that don't exist (edges) + if ( j < 0 || j > M_IMGDATA->m_height - 1 ) + continue; + + for ( int i = int(src_x - scale_factor_x/2.0 + 1); + i <= src_x + scale_factor_x_2; + i++ ) + { + // Don't average edge pixels + if ( i < 0 || i > M_IMGDATA->m_width - 1 ) + continue; + + // Calculate the actual index in our source pixels + src_pixel_index = j * M_IMGDATA->m_width + i; + + sum_r += src_data[src_pixel_index * 3 + 0]; + sum_g += src_data[src_pixel_index * 3 + 1]; + sum_b += src_data[src_pixel_index * 3 + 2]; + if ( src_alpha ) + sum_a += src_alpha[src_pixel_index]; + + averaged_pixels++; + } + } + + // Calculate the average from the sum and number of averaged pixels + dst_data[0] = (unsigned char)(sum_r / averaged_pixels); + dst_data[1] = (unsigned char)(sum_g / averaged_pixels); + dst_data[2] = (unsigned char)(sum_b / averaged_pixels); + dst_data += 3; + if ( src_alpha ) + *dst_alpha++ = (unsigned char)(sum_a / averaged_pixels); + } + } + + return ret_image; +} + +// The following two local functions are for the B-spline weighting of the +// bicubic sampling algorithm +static inline double spline_cube(double value) +{ + return value <= 0.0 ? 0.0 : value * value * value; +} + +static inline double spline_weight(double value) +{ + return (spline_cube(value + 2) - + 4 * spline_cube(value + 1) + + 6 * spline_cube(value) - + 4 * spline_cube(value - 1)) / 6; +} + +// This is the bicubic resampling algorithm +wxImage wxImage::ResampleBicubic(int width, int height) const +{ + // This function implements a Bicubic B-Spline algorithm for resampling. + // This method is certainly a little slower than wxImage's default pixel + // replication method, however for most reasonably sized images not being + // upsampled too much on a fairly average CPU this difference is hardly + // noticeable and the results are far more pleasing to look at. + // + // This particular bicubic algorithm does pixel weighting according to a + // B-Spline that basically implements a Gaussian bell-like weighting + // kernel. Because of this method the results may appear a bit blurry when + // upsampling by large factors. This is basically because a slight + // gaussian blur is being performed to get the smooth look of the upsampled + // image. + + // Edge pixels: 3-4 possible solutions + // - (Wrap/tile) Wrap the image, take the color value from the opposite + // side of the image. + // - (Mirror) Duplicate edge pixels, so that pixel at coordinate (2, n), + // where n is nonpositive, will have the value of (2, 1). + // - (Ignore) Simply ignore the edge pixels and apply the kernel only to + // pixels which do have all neighbours. + // - (Clamp) Choose the nearest pixel along the border. This takes the + // border pixels and extends them out to infinity. + // + // NOTE: below the y_offset and x_offset variables are being set for edge + // pixels using the "Mirror" method mentioned above + + wxImage ret_image; + + ret_image.Create(width, height, false); + + unsigned char* src_data = M_IMGDATA->m_data; + unsigned char* src_alpha = M_IMGDATA->m_alpha; + unsigned char* dst_data = ret_image.GetData(); + unsigned char* dst_alpha = NULL; + + if ( src_alpha ) + { + ret_image.SetAlpha(); + dst_alpha = ret_image.GetAlpha(); + } + + for ( int dsty = 0; dsty < height; dsty++ ) + { + // We need to calculate the source pixel to interpolate from - Y-axis + double srcpixy = double(dsty * M_IMGDATA->m_height) / height; + double dy = srcpixy - (int)srcpixy; + + for ( int dstx = 0; dstx < width; dstx++ ) + { + // X-axis of pixel to interpolate from + double srcpixx = double(dstx * M_IMGDATA->m_width) / width; + double dx = srcpixx - (int)srcpixx; + + // Sums for each color channel + double sum_r = 0, sum_g = 0, sum_b = 0, sum_a = 0; + + // Here we actually determine the RGBA values for the destination pixel + for ( int k = -1; k <= 2; k++ ) + { + // Y offset + int y_offset = srcpixy + k < 0.0 + ? 0 + : srcpixy + k >= M_IMGDATA->m_height + ? M_IMGDATA->m_height - 1 + : (int)(srcpixy + k); + + // Loop across the X axis + for ( int i = -1; i <= 2; i++ ) + { + // X offset + int x_offset = srcpixx + i < 0.0 + ? 0 + : srcpixx + i >= M_IMGDATA->m_width + ? M_IMGDATA->m_width - 1 + : (int)(srcpixx + i); + + // Calculate the exact position where the source data + // should be pulled from based on the x_offset and y_offset + int src_pixel_index = y_offset*M_IMGDATA->m_width + x_offset; + + // Calculate the weight for the specified pixel according + // to the bicubic b-spline kernel we're using for + // interpolation + double + pixel_weight = spline_weight(i - dx)*spline_weight(k - dy); + + // Create a sum of all velues for each color channel + // adjusted for the pixel's calculated weight + sum_r += src_data[src_pixel_index * 3 + 0] * pixel_weight; + sum_g += src_data[src_pixel_index * 3 + 1] * pixel_weight; + sum_b += src_data[src_pixel_index * 3 + 2] * pixel_weight; + if ( src_alpha ) + sum_a += src_alpha[src_pixel_index] * pixel_weight; + } + } + + // Put the data into the destination image. The summed values are + // of double data type and are rounded here for accuracy + dst_data[0] = (unsigned char)(sum_r + 0.5); + dst_data[1] = (unsigned char)(sum_g + 0.5); + dst_data[2] = (unsigned char)(sum_b + 0.5); + dst_data += 3; + + if ( src_alpha ) + *dst_alpha++ = (unsigned char)sum_a; + } + } + + return ret_image; +} + +// Blur in the horizontal direction +wxImage wxImage::BlurHorizontal(int blurRadius) +{ + wxImage ret_image; + ret_image.Create(M_IMGDATA->m_width, M_IMGDATA->m_height, false); + + unsigned char* src_data = M_IMGDATA->m_data; + unsigned char* dst_data = ret_image.GetData(); + unsigned char* src_alpha = M_IMGDATA->m_alpha; + unsigned char* dst_alpha = NULL; + + // Check for a mask or alpha + if ( M_IMGDATA->m_hasMask ) + { + ret_image.SetMaskColour(M_IMGDATA->m_maskRed, + M_IMGDATA->m_maskGreen, + M_IMGDATA->m_maskBlue); + } + else + { + if ( src_alpha ) + { + ret_image.SetAlpha(); + dst_alpha = ret_image.GetAlpha(); + } + } + + // number of pixels we average over + const int blurArea = blurRadius*2 + 1; + + // Horizontal blurring algorithm - average all pixels in the specified blur + // radius in the X or horizontal direction + for ( int y = 0; y < M_IMGDATA->m_height; y++ ) + { + // Variables used in the blurring algorithm + long sum_r = 0, + sum_g = 0, + sum_b = 0, + sum_a = 0; + + long pixel_idx; + const unsigned char *src; + unsigned char *dst; + + // Calculate the average of all pixels in the blur radius for the first + // pixel of the row + for ( int kernel_x = -blurRadius; kernel_x <= blurRadius; kernel_x++ ) + { + // To deal with the pixels at the start of a row so it's not + // grabbing GOK values from memory at negative indices of the + // image's data or grabbing from the previous row + if ( kernel_x < 0 ) + pixel_idx = y * M_IMGDATA->m_width; + else + pixel_idx = kernel_x + y * M_IMGDATA->m_width; + + src = src_data + pixel_idx*3; + sum_r += src[0]; + sum_g += src[1]; + sum_b += src[2]; + if ( src_alpha ) + sum_a += src_alpha[pixel_idx]; + } + + dst = dst_data + y * M_IMGDATA->m_width*3; + dst[0] = (unsigned char)(sum_r / blurArea); + dst[1] = (unsigned char)(sum_g / blurArea); + dst[2] = (unsigned char)(sum_b / blurArea); + if ( src_alpha ) + dst_alpha[y * M_IMGDATA->m_width] = (unsigned char)(sum_a / blurArea); + + // Now average the values of the rest of the pixels by just moving the + // blur radius box along the row + for ( int x = 1; x < M_IMGDATA->m_width; x++ ) + { + // Take care of edge pixels on the left edge by essentially + // duplicating the edge pixel + if ( x - blurRadius - 1 < 0 ) + pixel_idx = y * M_IMGDATA->m_width; + else + pixel_idx = (x - blurRadius - 1) + y * M_IMGDATA->m_width; + + // Subtract the value of the pixel at the left side of the blur + // radius box + src = src_data + pixel_idx*3; + sum_r -= src[0]; + sum_g -= src[1]; + sum_b -= src[2]; + if ( src_alpha ) + sum_a -= src_alpha[pixel_idx]; + + // Take care of edge pixels on the right edge + if ( x + blurRadius > M_IMGDATA->m_width - 1 ) + pixel_idx = M_IMGDATA->m_width - 1 + y * M_IMGDATA->m_width; + else + pixel_idx = x + blurRadius + y * M_IMGDATA->m_width; + + // Add the value of the pixel being added to the end of our box + src = src_data + pixel_idx*3; + sum_r += src[0]; + sum_g += src[1]; + sum_b += src[2]; + if ( src_alpha ) + sum_a += src_alpha[pixel_idx]; + + // Save off the averaged data + dst = dst_data + x*3 + y*M_IMGDATA->m_width*3; + dst[0] = (unsigned char)(sum_r / blurArea); + dst[1] = (unsigned char)(sum_g / blurArea); + dst[2] = (unsigned char)(sum_b / blurArea); + if ( src_alpha ) + dst_alpha[x + y * M_IMGDATA->m_width] = (unsigned char)(sum_a / blurArea); + } + } + + return ret_image; +} + +// Blur in the vertical direction +wxImage wxImage::BlurVertical(int blurRadius) +{ + wxImage ret_image; + ret_image.Create(M_IMGDATA->m_width, M_IMGDATA->m_height, false); + + unsigned char* src_data = M_IMGDATA->m_data; + unsigned char* dst_data = ret_image.GetData(); + unsigned char* src_alpha = M_IMGDATA->m_alpha; + unsigned char* dst_alpha = NULL; + + // Check for a mask or alpha + if ( M_IMGDATA->m_hasMask ) + { + ret_image.SetMaskColour(M_IMGDATA->m_maskRed, + M_IMGDATA->m_maskGreen, + M_IMGDATA->m_maskBlue); + } + else + { + if ( src_alpha ) + { + ret_image.SetAlpha(); + dst_alpha = ret_image.GetAlpha(); + } + } + + // number of pixels we average over + const int blurArea = blurRadius*2 + 1; + + // Vertical blurring algorithm - same as horizontal but switched the + // opposite direction + for ( int x = 0; x < M_IMGDATA->m_width; x++ ) + { + // Variables used in the blurring algorithm + long sum_r = 0, + sum_g = 0, + sum_b = 0, + sum_a = 0; + + long pixel_idx; + const unsigned char *src; + unsigned char *dst; + + // Calculate the average of all pixels in our blur radius box for the + // first pixel of the column + for ( int kernel_y = -blurRadius; kernel_y <= blurRadius; kernel_y++ ) + { + // To deal with the pixels at the start of a column so it's not + // grabbing GOK values from memory at negative indices of the + // image's data or grabbing from the previous column + if ( kernel_y < 0 ) + pixel_idx = x; + else + pixel_idx = x + kernel_y * M_IMGDATA->m_width; + + src = src_data + pixel_idx*3; + sum_r += src[0]; + sum_g += src[1]; + sum_b += src[2]; + if ( src_alpha ) + sum_a += src_alpha[pixel_idx]; + } + + dst = dst_data + x*3; + dst[0] = (unsigned char)(sum_r / blurArea); + dst[1] = (unsigned char)(sum_g / blurArea); + dst[2] = (unsigned char)(sum_b / blurArea); + if ( src_alpha ) + dst_alpha[x] = (unsigned char)(sum_a / blurArea); + + // Now average the values of the rest of the pixels by just moving the + // box along the column from top to bottom + for ( int y = 1; y < M_IMGDATA->m_height; y++ ) + { + // Take care of pixels that would be beyond the top edge by + // duplicating the top edge pixel for the column + if ( y - blurRadius - 1 < 0 ) + pixel_idx = x; + else + pixel_idx = x + (y - blurRadius - 1) * M_IMGDATA->m_width; + + // Subtract the value of the pixel at the top of our blur radius box + src = src_data + pixel_idx*3; + sum_r -= src[0]; + sum_g -= src[1]; + sum_b -= src[2]; + if ( src_alpha ) + sum_a -= src_alpha[pixel_idx]; + + // Take care of the pixels that would be beyond the bottom edge of + // the image similar to the top edge + if ( y + blurRadius > M_IMGDATA->m_height - 1 ) + pixel_idx = x + (M_IMGDATA->m_height - 1) * M_IMGDATA->m_width; + else + pixel_idx = x + (blurRadius + y) * M_IMGDATA->m_width; + + // Add the value of the pixel being added to the end of our box + src = src_data + pixel_idx*3; + sum_r += src[0]; + sum_g += src[1]; + sum_b += src[2]; + if ( src_alpha ) + sum_a += src_alpha[pixel_idx]; + + // Save off the averaged data + dst = dst_data + (x + y * M_IMGDATA->m_width) * 3; + dst[0] = (unsigned char)(sum_r / blurArea); + dst[1] = (unsigned char)(sum_g / blurArea); + dst[2] = (unsigned char)(sum_b / blurArea); + if ( src_alpha ) + dst_alpha[x + y * M_IMGDATA->m_width] = (unsigned char)(sum_a / blurArea); + } + } + + return ret_image; +} + +// The new blur function +wxImage wxImage::Blur(int blurRadius) +{ + wxImage ret_image; + ret_image.Create(M_IMGDATA->m_width, M_IMGDATA->m_height, false); + + // Blur the image in each direction + ret_image = BlurHorizontal(blurRadius); + ret_image = ret_image.BlurVertical(blurRadius); + + return ret_image; +} + +wxImage wxImage::Rotate90( bool clockwise ) const +{ + wxImage image; + + wxCHECK_MSG( Ok(), image, wxT("invalid image") ); + + image.Create( M_IMGDATA->m_height, M_IMGDATA->m_width, false ); + + unsigned char *data = image.GetData(); + + wxCHECK_MSG( data, image, wxT("unable to create image") ); + + unsigned char *source_data = M_IMGDATA->m_data; + unsigned char *target_data; + unsigned char *alpha_data = 0 ; + unsigned char *source_alpha = 0 ; + unsigned char *target_alpha = 0 ; + + if (M_IMGDATA->m_hasMask) + { + image.SetMaskColour( M_IMGDATA->m_maskRed, M_IMGDATA->m_maskGreen, M_IMGDATA->m_maskBlue ); + } + else + { + source_alpha = M_IMGDATA->m_alpha ; + if ( source_alpha ) + { + image.SetAlpha() ; + alpha_data = image.GetAlpha() ; + } + } + + long height = M_IMGDATA->m_height; + long width = M_IMGDATA->m_width; + + for (long j = 0; j < height; j++) + { + for (long i = 0; i < width; i++) + { + if (clockwise) + { + target_data = data + (((i+1)*height) - j - 1)*3; + if(source_alpha) + target_alpha = alpha_data + (((i+1)*height) - j - 1); + } + else + { + target_data = data + ((height*(width-1)) + j - (i*height))*3; + if(source_alpha) + target_alpha = alpha_data + ((height*(width-1)) + j - (i*height)); + } + memcpy( target_data, source_data, 3 ); + source_data += 3; + + if(source_alpha) + { + memcpy( target_alpha, source_alpha, 1 ); + source_alpha += 1; + } + } + } + + return image; +} + +wxImage wxImage::Mirror( bool horizontally ) const +{ + wxImage image; + + wxCHECK_MSG( Ok(), image, wxT("invalid image") ); + + image.Create( M_IMGDATA->m_width, M_IMGDATA->m_height, false ); + + unsigned char *data = image.GetData(); + unsigned char *alpha = NULL; + + wxCHECK_MSG( data, image, wxT("unable to create image") ); + + if (M_IMGDATA->m_alpha != NULL) { + image.SetAlpha(); + alpha = image.GetAlpha(); + wxCHECK_MSG( alpha, image, wxT("unable to create alpha channel") ); + } + + if (M_IMGDATA->m_hasMask) + image.SetMaskColour( M_IMGDATA->m_maskRed, M_IMGDATA->m_maskGreen, M_IMGDATA->m_maskBlue ); + + long height = M_IMGDATA->m_height; + long width = M_IMGDATA->m_width; + + unsigned char *source_data = M_IMGDATA->m_data; + unsigned char *target_data; + + if (horizontally) + { + for (long j = 0; j < height; j++) + { + data += width*3; + target_data = data-3; + for (long i = 0; i < width; i++) + { + memcpy( target_data, source_data, 3 ); + source_data += 3; + target_data -= 3; + } + } + + if (alpha != NULL) + { + // src_alpha starts at the first pixel and increases by 1 after each step + // (a step here is the copy of the alpha value of one pixel) + const unsigned char *src_alpha = M_IMGDATA->m_alpha; + // dest_alpha starts just beyond the first line, decreases before each step, + // and after each line is finished, increases by 2 widths (skipping the line + // just copied and the line that will be copied next) + unsigned char *dest_alpha = alpha + width; + + for (long jj = 0; jj < height; ++jj) + { + for (long i = 0; i < width; ++i) { + *(--dest_alpha) = *(src_alpha++); // copy one pixel + } + dest_alpha += 2 * width; // advance beyond the end of the next line + } + } + } + else + { + for (long i = 0; i < height; i++) + { + target_data = data + 3*width*(height-1-i); + memcpy( target_data, source_data, (size_t)3*width ); + source_data += 3*width; + } + + if (alpha != NULL) + { + // src_alpha starts at the first pixel and increases by 1 width after each step + // (a step here is the copy of the alpha channel of an entire line) + const unsigned char *src_alpha = M_IMGDATA->m_alpha; + // dest_alpha starts just beyond the last line (beyond the whole image) + // and decreases by 1 width before each step + unsigned char *dest_alpha = alpha + width * height; + + for (long jj = 0; jj < height; ++jj) + { + dest_alpha -= width; + memcpy( dest_alpha, src_alpha, (size_t)width ); + src_alpha += width; + } + } + } + + return image; +} + +wxImage wxImage::GetSubImage( const wxRect &rect ) const +{ + wxImage image; + + wxCHECK_MSG( Ok(), image, wxT("invalid image") ); + + wxCHECK_MSG( (rect.GetLeft()>=0) && (rect.GetTop()>=0) && + (rect.GetRight()<=GetWidth()) && (rect.GetBottom()<=GetHeight()), + image, wxT("invalid subimage size") ); + + const int subwidth = rect.GetWidth(); + const int subheight = rect.GetHeight(); + + image.Create( subwidth, subheight, false ); + + const unsigned char *src_data = GetData(); + const unsigned char *src_alpha = M_IMGDATA->m_alpha; + unsigned char *subdata = image.GetData(); + unsigned char *subalpha = NULL; + + wxCHECK_MSG( subdata, image, wxT("unable to create image") ); + + if (src_alpha != NULL) { + image.SetAlpha(); + subalpha = image.GetAlpha(); + wxCHECK_MSG( subalpha, image, wxT("unable to create alpha channel")); + } + + if (M_IMGDATA->m_hasMask) + image.SetMaskColour( M_IMGDATA->m_maskRed, M_IMGDATA->m_maskGreen, M_IMGDATA->m_maskBlue ); + + const int width = GetWidth(); + const int pixsoff = rect.GetLeft() + width * rect.GetTop(); + + src_data += 3 * pixsoff; + src_alpha += pixsoff; // won't be used if was NULL, so this is ok + + for (long j = 0; j < subheight; ++j) + { + memcpy( subdata, src_data, 3 * subwidth ); + subdata += 3 * subwidth; + src_data += 3 * width; + if (subalpha != NULL) { + memcpy( subalpha, src_alpha, subwidth ); + subalpha += subwidth; + src_alpha += width; + } + } + + return image; +} + +wxImage wxImage::Size( const wxSize& size, const wxPoint& pos, + int r_, int g_, int b_ ) const +{ + wxImage image; + + wxCHECK_MSG( Ok(), image, wxT("invalid image") ); + wxCHECK_MSG( (size.GetWidth() > 0) && (size.GetHeight() > 0), image, wxT("invalid size") ); + + int width = GetWidth(), height = GetHeight(); + image.Create(size.GetWidth(), size.GetHeight(), false); + + unsigned char r = (unsigned char)r_; + unsigned char g = (unsigned char)g_; + unsigned char b = (unsigned char)b_; + if ((r_ == -1) && (g_ == -1) && (b_ == -1)) + { + GetOrFindMaskColour( &r, &g, &b ); + image.SetMaskColour(r, g, b); + } + + image.SetRGB(wxRect(), r, g, b); + + wxRect subRect(pos.x, pos.y, width, height); + wxRect finalRect(0, 0, size.GetWidth(), size.GetHeight()); + if (pos.x < 0) + finalRect.width -= pos.x; + if (pos.y < 0) + finalRect.height -= pos.y; + + subRect.Intersect(finalRect); + + if (!subRect.IsEmpty()) + { + if ((subRect.GetWidth() == width) && (subRect.GetHeight() == height)) + image.Paste(*this, pos.x, pos.y); + else + image.Paste(GetSubImage(subRect), pos.x, pos.y); + } + + return image; +} + +void wxImage::Paste( const wxImage &image, int x, int y ) +{ + wxCHECK_RET( Ok(), wxT("invalid image") ); + wxCHECK_RET( image.Ok(), wxT("invalid image") ); + + AllocExclusive(); + + int xx = 0; + int yy = 0; + int width = image.GetWidth(); + int height = image.GetHeight(); + + if (x < 0) + { + xx = -x; + width += x; + } + if (y < 0) + { + yy = -y; + height += y; + } + + if ((x+xx)+width > M_IMGDATA->m_width) + width = M_IMGDATA->m_width - (x+xx); + if ((y+yy)+height > M_IMGDATA->m_height) + height = M_IMGDATA->m_height - (y+yy); + + if (width < 1) return; + if (height < 1) return; + + if ((!HasMask() && !image.HasMask()) || + (HasMask() && !image.HasMask()) || + ((HasMask() && image.HasMask() && + (GetMaskRed()==image.GetMaskRed()) && + (GetMaskGreen()==image.GetMaskGreen()) && + (GetMaskBlue()==image.GetMaskBlue())))) + { + width *= 3; + unsigned char* source_data = image.GetData() + xx*3 + yy*3*image.GetWidth(); + int source_step = image.GetWidth()*3; + + unsigned char* target_data = GetData() + (x+xx)*3 + (y+yy)*3*M_IMGDATA->m_width; + int target_step = M_IMGDATA->m_width*3; + for (int j = 0; j < height; j++) + { + memcpy( target_data, source_data, width ); + source_data += source_step; + target_data += target_step; + } + return; + } + + // Copy over the alpha channel from the original image + if ( image.HasAlpha() ) + { + if ( !HasAlpha() ) + InitAlpha(); + + unsigned char* source_data = image.GetAlpha() + xx + yy*image.GetWidth(); + int source_step = image.GetWidth(); + + unsigned char* target_data = GetAlpha() + (x+xx) + (y+yy)*M_IMGDATA->m_width; + int target_step = M_IMGDATA->m_width; + + for (int j = 0; j < height; j++, + source_data += source_step, + target_data += target_step) + { + memcpy( target_data, source_data, width ); + } + } + + if (!HasMask() && image.HasMask()) + { + unsigned char r = image.GetMaskRed(); + unsigned char g = image.GetMaskGreen(); + unsigned char b = image.GetMaskBlue(); + + width *= 3; + unsigned char* source_data = image.GetData() + xx*3 + yy*3*image.GetWidth(); + int source_step = image.GetWidth()*3; + + unsigned char* target_data = GetData() + (x+xx)*3 + (y+yy)*3*M_IMGDATA->m_width; + int target_step = M_IMGDATA->m_width*3; + + for (int j = 0; j < height; j++) + { + for (int i = 0; i < width; i+=3) + { + if ((source_data[i] != r) || + (source_data[i+1] != g) || + (source_data[i+2] != b)) + { + memcpy( target_data+i, source_data+i, 3 ); + } + } + source_data += source_step; + target_data += target_step; + } + } +} + +void wxImage::Replace( unsigned char r1, unsigned char g1, unsigned char b1, + unsigned char r2, unsigned char g2, unsigned char b2 ) +{ + wxCHECK_RET( Ok(), wxT("invalid image") ); + + AllocExclusive(); + + unsigned char *data = GetData(); + + const int w = GetWidth(); + const int h = GetHeight(); + + for (int j = 0; j < h; j++) + for (int i = 0; i < w; i++) + { + if ((data[0] == r1) && (data[1] == g1) && (data[2] == b1)) + { + data[0] = r2; + data[1] = g2; + data[2] = b2; + } + data += 3; + } +} + +wxImage wxImage::ConvertToGreyscale( double lr, double lg, double lb ) const +{ + wxImage image; + + wxCHECK_MSG( Ok(), image, wxT("invalid image") ); + + image.Create(M_IMGDATA->m_width, M_IMGDATA->m_height, false); + + unsigned char *dest = image.GetData(); + + wxCHECK_MSG( dest, image, wxT("unable to create image") ); + + unsigned char *src = M_IMGDATA->m_data; + bool hasMask = M_IMGDATA->m_hasMask; + unsigned char maskRed = M_IMGDATA->m_maskRed; + unsigned char maskGreen = M_IMGDATA->m_maskGreen; + unsigned char maskBlue = M_IMGDATA->m_maskBlue; + + if ( hasMask ) + image.SetMaskColour(maskRed, maskGreen, maskBlue); + + const long size = M_IMGDATA->m_width * M_IMGDATA->m_height; + for ( long i = 0; i < size; i++, src += 3, dest += 3 ) + { + // don't modify the mask + if ( hasMask && src[0] == maskRed && src[1] == maskGreen && src[2] == maskBlue ) + { + memcpy(dest, src, 3); + } + else + { + // calculate the luma + double luma = (src[0] * lr + src[1] * lg + src[2] * lb) + 0.5; + dest[0] = dest[1] = dest[2] = wx_static_cast(unsigned char, luma); + } + } + + // copy the alpha channel, if any + if (HasAlpha()) + { + const size_t alphaSize = GetWidth() * GetHeight(); + unsigned char *alpha = (unsigned char*)malloc(alphaSize); + memcpy(alpha, GetAlpha(), alphaSize); + image.InitAlpha(); + image.SetAlpha(alpha); + } + + return image; +} + +wxImage wxImage::ConvertToMono( unsigned char r, unsigned char g, unsigned char b ) const +{ + wxImage image; + + wxCHECK_MSG( Ok(), image, wxT("invalid image") ); + + image.Create( M_IMGDATA->m_width, M_IMGDATA->m_height, false ); + + unsigned char *data = image.GetData(); + + wxCHECK_MSG( data, image, wxT("unable to create image") ); + + if (M_IMGDATA->m_hasMask) + { + if (M_IMGDATA->m_maskRed == r && M_IMGDATA->m_maskGreen == g && + M_IMGDATA->m_maskBlue == b) + image.SetMaskColour( 255, 255, 255 ); + else + image.SetMaskColour( 0, 0, 0 ); + } + + long size = M_IMGDATA->m_height * M_IMGDATA->m_width; + + unsigned char *srcd = M_IMGDATA->m_data; + unsigned char *tard = image.GetData(); + + for ( long i = 0; i < size; i++, srcd += 3, tard += 3 ) + { + if (srcd[0] == r && srcd[1] == g && srcd[2] == b) + tard[0] = tard[1] = tard[2] = 255; + else + tard[0] = tard[1] = tard[2] = 0; + } + + return image; +} + +int wxImage::GetWidth() const +{ + wxCHECK_MSG( Ok(), 0, wxT("invalid image") ); + + return M_IMGDATA->m_width; +} + +int wxImage::GetHeight() const +{ + wxCHECK_MSG( Ok(), 0, wxT("invalid image") ); + + return M_IMGDATA->m_height; +} + +long wxImage::XYToIndex(int x, int y) const +{ + if ( Ok() && + x >= 0 && y >= 0 && + x < M_IMGDATA->m_width && y < M_IMGDATA->m_height ) + { + return y*M_IMGDATA->m_width + x; + } + + return -1; +} + +void wxImage::SetRGB( int x, int y, unsigned char r, unsigned char g, unsigned char b ) +{ + long pos = XYToIndex(x, y); + wxCHECK_RET( pos != -1, wxT("invalid image coordinates") ); + + AllocExclusive(); + + pos *= 3; + + M_IMGDATA->m_data[ pos ] = r; + M_IMGDATA->m_data[ pos+1 ] = g; + M_IMGDATA->m_data[ pos+2 ] = b; +} + +void wxImage::SetRGB( const wxRect& rect_, unsigned char r, unsigned char g, unsigned char b ) +{ + wxCHECK_RET( Ok(), wxT("invalid image") ); + + AllocExclusive(); + + wxRect rect(rect_); + wxRect imageRect(0, 0, GetWidth(), GetHeight()); + if ( rect == wxRect() ) + { + rect = imageRect; + } + else + { + wxCHECK_RET( imageRect.Contains(rect.GetTopLeft()) && + imageRect.Contains(rect.GetBottomRight()), + wxT("invalid bounding rectangle") ); + } + + int x1 = rect.GetLeft(), + y1 = rect.GetTop(), + x2 = rect.GetRight() + 1, + y2 = rect.GetBottom() + 1; + + unsigned char *data wxDUMMY_INITIALIZE(NULL); + int x, y, width = GetWidth(); + for (y = y1; y < y2; y++) + { + data = M_IMGDATA->m_data + (y*width + x1)*3; + for (x = x1; x < x2; x++) + { + *data++ = r; + *data++ = g; + *data++ = b; + } + } +} + +unsigned char wxImage::GetRed( int x, int y ) const +{ + long pos = XYToIndex(x, y); + wxCHECK_MSG( pos != -1, 0, wxT("invalid image coordinates") ); + + pos *= 3; + + return M_IMGDATA->m_data[pos]; +} + +unsigned char wxImage::GetGreen( int x, int y ) const +{ + long pos = XYToIndex(x, y); + wxCHECK_MSG( pos != -1, 0, wxT("invalid image coordinates") ); + + pos *= 3; + + return M_IMGDATA->m_data[pos+1]; +} + +unsigned char wxImage::GetBlue( int x, int y ) const +{ + long pos = XYToIndex(x, y); + wxCHECK_MSG( pos != -1, 0, wxT("invalid image coordinates") ); + + pos *= 3; + + return M_IMGDATA->m_data[pos+2]; +} + +bool wxImage::IsOk() const +{ + // image of 0 width or height can't be considered ok - at least because it + // causes crashes in ConvertToBitmap() if we don't catch it in time + wxImageRefData *data = M_IMGDATA; + return data && data->m_ok && data->m_width && data->m_height; +} + +unsigned char *wxImage::GetData() const +{ + wxCHECK_MSG( Ok(), (unsigned char *)NULL, wxT("invalid image") ); + + return M_IMGDATA->m_data; +} + +void wxImage::SetData( unsigned char *data, bool static_data ) +{ + wxCHECK_RET( Ok(), wxT("invalid image") ); + + wxImageRefData *newRefData = new wxImageRefData(); + + newRefData->m_width = M_IMGDATA->m_width; + newRefData->m_height = M_IMGDATA->m_height; + newRefData->m_data = data; + newRefData->m_ok = true; + newRefData->m_maskRed = M_IMGDATA->m_maskRed; + newRefData->m_maskGreen = M_IMGDATA->m_maskGreen; + newRefData->m_maskBlue = M_IMGDATA->m_maskBlue; + newRefData->m_hasMask = M_IMGDATA->m_hasMask; + newRefData->m_static = static_data; + + UnRef(); + + m_refData = newRefData; +} + +void wxImage::SetData( unsigned char *data, int new_width, int new_height, bool static_data ) +{ + wxImageRefData *newRefData = new wxImageRefData(); + + if (m_refData) + { + newRefData->m_width = new_width; + newRefData->m_height = new_height; + newRefData->m_data = data; + newRefData->m_ok = true; + newRefData->m_maskRed = M_IMGDATA->m_maskRed; + newRefData->m_maskGreen = M_IMGDATA->m_maskGreen; + newRefData->m_maskBlue = M_IMGDATA->m_maskBlue; + newRefData->m_hasMask = M_IMGDATA->m_hasMask; + } + else + { + newRefData->m_width = new_width; + newRefData->m_height = new_height; + newRefData->m_data = data; + newRefData->m_ok = true; + } + newRefData->m_static = static_data; + + UnRef(); + + m_refData = newRefData; +} + +// ---------------------------------------------------------------------------- +// alpha channel support +// ---------------------------------------------------------------------------- + +void wxImage::SetAlpha(int x, int y, unsigned char alpha) +{ + wxCHECK_RET( HasAlpha(), wxT("no alpha channel") ); + + long pos = XYToIndex(x, y); + wxCHECK_RET( pos != -1, wxT("invalid image coordinates") ); + + AllocExclusive(); + + M_IMGDATA->m_alpha[pos] = alpha; +} + +unsigned char wxImage::GetAlpha(int x, int y) const +{ + wxCHECK_MSG( HasAlpha(), 0, wxT("no alpha channel") ); + + long pos = XYToIndex(x, y); + wxCHECK_MSG( pos != -1, 0, wxT("invalid image coordinates") ); + + return M_IMGDATA->m_alpha[pos]; +} + +bool +wxImage::ConvertColourToAlpha(unsigned char r, unsigned char g, unsigned char b) +{ + SetAlpha(NULL); + + const int w = M_IMGDATA->m_width; + const int h = M_IMGDATA->m_height; + + unsigned char *alpha = GetAlpha(); + unsigned char *data = GetData(); + + for ( int y = 0; y < h; y++ ) + { + for ( int x = 0; x < w; x++ ) + { + *alpha++ = *data; + *data++ = r; + *data++ = g; + *data++ = b; + } + } + + return true; +} + +void wxImage::SetAlpha( unsigned char *alpha, bool static_data ) +{ + wxCHECK_RET( Ok(), wxT("invalid image") ); + + AllocExclusive(); + + if ( !alpha ) + { + alpha = (unsigned char *)malloc(M_IMGDATA->m_width*M_IMGDATA->m_height); + } + + if( !M_IMGDATA->m_staticAlpha ) + free(M_IMGDATA->m_alpha); + + M_IMGDATA->m_alpha = alpha; + M_IMGDATA->m_staticAlpha = static_data; +} + +unsigned char *wxImage::GetAlpha() const +{ + wxCHECK_MSG( Ok(), (unsigned char *)NULL, wxT("invalid image") ); + + return M_IMGDATA->m_alpha; +} + +void wxImage::InitAlpha() +{ + wxCHECK_RET( !HasAlpha(), wxT("image already has an alpha channel") ); + + // initialize memory for alpha channel + SetAlpha(); + + unsigned char *alpha = M_IMGDATA->m_alpha; + const size_t lenAlpha = M_IMGDATA->m_width * M_IMGDATA->m_height; + + if ( HasMask() ) + { + // use the mask to initialize the alpha channel. + const unsigned char * const alphaEnd = alpha + lenAlpha; + + const unsigned char mr = M_IMGDATA->m_maskRed; + const unsigned char mg = M_IMGDATA->m_maskGreen; + const unsigned char mb = M_IMGDATA->m_maskBlue; + for ( unsigned char *src = M_IMGDATA->m_data; + alpha < alphaEnd; + src += 3, alpha++ ) + { + *alpha = (src[0] == mr && src[1] == mg && src[2] == mb) + ? wxIMAGE_ALPHA_TRANSPARENT + : wxIMAGE_ALPHA_OPAQUE; + } + + M_IMGDATA->m_hasMask = false; + } + else // no mask + { + // make the image fully opaque + memset(alpha, wxIMAGE_ALPHA_OPAQUE, lenAlpha); + } +} + +// ---------------------------------------------------------------------------- +// mask support +// ---------------------------------------------------------------------------- + +void wxImage::SetMaskColour( unsigned char r, unsigned char g, unsigned char b ) +{ + wxCHECK_RET( Ok(), wxT("invalid image") ); + + AllocExclusive(); + + M_IMGDATA->m_maskRed = r; + M_IMGDATA->m_maskGreen = g; + M_IMGDATA->m_maskBlue = b; + M_IMGDATA->m_hasMask = true; +} + +bool wxImage::GetOrFindMaskColour( unsigned char *r, unsigned char *g, unsigned char *b ) const +{ + wxCHECK_MSG( Ok(), false, wxT("invalid image") ); + + if (M_IMGDATA->m_hasMask) + { + if (r) *r = M_IMGDATA->m_maskRed; + if (g) *g = M_IMGDATA->m_maskGreen; + if (b) *b = M_IMGDATA->m_maskBlue; + return true; + } + else + { + FindFirstUnusedColour(r, g, b); + return false; + } +} + +unsigned char wxImage::GetMaskRed() const +{ + wxCHECK_MSG( Ok(), 0, wxT("invalid image") ); + + return M_IMGDATA->m_maskRed; +} + +unsigned char wxImage::GetMaskGreen() const +{ + wxCHECK_MSG( Ok(), 0, wxT("invalid image") ); + + return M_IMGDATA->m_maskGreen; +} + +unsigned char wxImage::GetMaskBlue() const +{ + wxCHECK_MSG( Ok(), 0, wxT("invalid image") ); + + return M_IMGDATA->m_maskBlue; +} + +void wxImage::SetMask( bool mask ) +{ + wxCHECK_RET( Ok(), wxT("invalid image") ); + + AllocExclusive(); + + M_IMGDATA->m_hasMask = mask; +} + +bool wxImage::HasMask() const +{ + wxCHECK_MSG( Ok(), false, wxT("invalid image") ); + + return M_IMGDATA->m_hasMask; +} + +bool wxImage::IsTransparent(int x, int y, unsigned char threshold) const +{ + long pos = XYToIndex(x, y); + wxCHECK_MSG( pos != -1, false, wxT("invalid image coordinates") ); + + // check mask + if ( M_IMGDATA->m_hasMask ) + { + const unsigned char *p = M_IMGDATA->m_data + 3*pos; + if ( p[0] == M_IMGDATA->m_maskRed && + p[1] == M_IMGDATA->m_maskGreen && + p[2] == M_IMGDATA->m_maskBlue ) + { + return true; + } + } + + // then check alpha + if ( M_IMGDATA->m_alpha ) + { + if ( M_IMGDATA->m_alpha[pos] < threshold ) + { + // transparent enough + return true; + } + } + + // not transparent + return false; +} + +bool wxImage::SetMaskFromImage(const wxImage& mask, + unsigned char mr, unsigned char mg, unsigned char mb) +{ + // check that the images are the same size + if ( (M_IMGDATA->m_height != mask.GetHeight() ) || (M_IMGDATA->m_width != mask.GetWidth () ) ) + { + wxLogError( _("Image and mask have different sizes.") ); + return false; + } + + // find unused colour + unsigned char r,g,b ; + if (!FindFirstUnusedColour(&r, &g, &b)) + { + wxLogError( _("No unused colour in image being masked.") ); + return false ; + } + + AllocExclusive(); + + unsigned char *imgdata = GetData(); + unsigned char *maskdata = mask.GetData(); + + const int w = GetWidth(); + const int h = GetHeight(); + + for (int j = 0; j < h; j++) + { + for (int i = 0; i < w; i++) + { + if ((maskdata[0] == mr) && (maskdata[1] == mg) && (maskdata[2] == mb)) + { + imgdata[0] = r; + imgdata[1] = g; + imgdata[2] = b; + } + imgdata += 3; + maskdata += 3; + } + } + + SetMaskColour(r, g, b); + SetMask(true); + + return true; +} + +bool wxImage::ConvertAlphaToMask(unsigned char threshold) +{ + if (!HasAlpha()) + return true; + + unsigned char mr, mg, mb; + if (!FindFirstUnusedColour(&mr, &mg, &mb)) + { + wxLogError( _("No unused colour in image being masked.") ); + return false; + } + + AllocExclusive(); + + SetMask(true); + SetMaskColour(mr, mg, mb); + + unsigned char *imgdata = GetData(); + unsigned char *alphadata = GetAlpha(); + + int w = GetWidth(); + int h = GetHeight(); + + for (int y = 0; y < h; y++) + { + for (int x = 0; x < w; x++, imgdata += 3, alphadata++) + { + if (*alphadata < threshold) + { + imgdata[0] = mr; + imgdata[1] = mg; + imgdata[2] = mb; + } + } + } + + if( !M_IMGDATA->m_staticAlpha ) + free(M_IMGDATA->m_alpha); + + M_IMGDATA->m_alpha = NULL; + M_IMGDATA->m_staticAlpha = false; + + return true; +} + +// ---------------------------------------------------------------------------- +// Palette functions +// ---------------------------------------------------------------------------- + +#if wxUSE_PALETTE + +bool wxImage::HasPalette() const +{ + if (!Ok()) + return false; + + return M_IMGDATA->m_palette.Ok(); +} + +const wxPalette& wxImage::GetPalette() const +{ + wxCHECK_MSG( Ok(), wxNullPalette, wxT("invalid image") ); + + return M_IMGDATA->m_palette; +} + +void wxImage::SetPalette(const wxPalette& palette) +{ + wxCHECK_RET( Ok(), wxT("invalid image") ); + + AllocExclusive(); + + M_IMGDATA->m_palette = palette; +} + +#endif // wxUSE_PALETTE + +// ---------------------------------------------------------------------------- +// Option functions (arbitrary name/value mapping) +// ---------------------------------------------------------------------------- + +void wxImage::SetOption(const wxString& name, const wxString& value) +{ + wxCHECK_RET( Ok(), wxT("invalid image") ); + + AllocExclusive(); + + int idx = M_IMGDATA->m_optionNames.Index(name, false); + if (idx == wxNOT_FOUND) + { + M_IMGDATA->m_optionNames.Add(name); + M_IMGDATA->m_optionValues.Add(value); + } + else + { + M_IMGDATA->m_optionNames[idx] = name; + M_IMGDATA->m_optionValues[idx] = value; + } +} + +void wxImage::SetOption(const wxString& name, int value) +{ + wxString valStr; + valStr.Printf(wxT("%d"), value); + SetOption(name, valStr); +} + +wxString wxImage::GetOption(const wxString& name) const +{ + wxCHECK_MSG( Ok(), wxEmptyString, wxT("invalid image") ); + + int idx = M_IMGDATA->m_optionNames.Index(name, false); + if (idx == wxNOT_FOUND) + return wxEmptyString; + else + return M_IMGDATA->m_optionValues[idx]; +} + +int wxImage::GetOptionInt(const wxString& name) const +{ + return wxAtoi(GetOption(name)); +} + +bool wxImage::HasOption(const wxString& name) const +{ + wxCHECK_MSG( Ok(), false, wxT("invalid image") ); + + return (M_IMGDATA->m_optionNames.Index(name, false) != wxNOT_FOUND); +} + +// ---------------------------------------------------------------------------- +// image I/O +// ---------------------------------------------------------------------------- + +bool wxImage::LoadFile( const wxString& WXUNUSED_UNLESS_STREAMS(filename), + long WXUNUSED_UNLESS_STREAMS(type), + int WXUNUSED_UNLESS_STREAMS(index) ) +{ +#if HAS_FILE_STREAMS + if (wxFileExists(filename)) + { + wxImageFileInputStream stream(filename); + wxBufferedInputStream bstream( stream ); + return LoadFile(bstream, type, index); + } + else + { + wxLogError( _("Can't load image from file '%s': file does not exist."), filename.c_str() ); + + return false; + } +#else // !HAS_FILE_STREAMS + return false; +#endif // HAS_FILE_STREAMS +} + +bool wxImage::LoadFile( const wxString& WXUNUSED_UNLESS_STREAMS(filename), + const wxString& WXUNUSED_UNLESS_STREAMS(mimetype), + int WXUNUSED_UNLESS_STREAMS(index) ) +{ +#if HAS_FILE_STREAMS + if (wxFileExists(filename)) + { + wxImageFileInputStream stream(filename); + wxBufferedInputStream bstream( stream ); + return LoadFile(bstream, mimetype, index); + } + else + { + wxLogError( _("Can't load image from file '%s': file does not exist."), filename.c_str() ); + + return false; + } +#else // !HAS_FILE_STREAMS + return false; +#endif // HAS_FILE_STREAMS +} + + + +bool wxImage::SaveFile( const wxString& filename ) const +{ + wxString ext = filename.AfterLast('.').Lower(); + + wxImageHandler * pHandler = FindHandler(ext, -1); + if (pHandler) + { + return SaveFile(filename, pHandler->GetType()); + } + + wxLogError(_("Can't save image to file '%s': unknown extension."), filename.c_str()); + + return false; +} + +bool wxImage::SaveFile( const wxString& WXUNUSED_UNLESS_STREAMS(filename), + int WXUNUSED_UNLESS_STREAMS(type) ) const +{ +#if HAS_FILE_STREAMS + wxCHECK_MSG( Ok(), false, wxT("invalid image") ); + + ((wxImage*)this)->SetOption(wxIMAGE_OPTION_FILENAME, filename); + + wxImageFileOutputStream stream(filename); + + if ( stream.IsOk() ) + { + wxBufferedOutputStream bstream( stream ); + return SaveFile(bstream, type); + } +#endif // HAS_FILE_STREAMS + + return false; +} + +bool wxImage::SaveFile( const wxString& WXUNUSED_UNLESS_STREAMS(filename), + const wxString& WXUNUSED_UNLESS_STREAMS(mimetype) ) const +{ +#if HAS_FILE_STREAMS + wxCHECK_MSG( Ok(), false, wxT("invalid image") ); + + ((wxImage*)this)->SetOption(wxIMAGE_OPTION_FILENAME, filename); + + wxImageFileOutputStream stream(filename); + + if ( stream.IsOk() ) + { + wxBufferedOutputStream bstream( stream ); + return SaveFile(bstream, mimetype); + } +#endif // HAS_FILE_STREAMS + + return false; +} + +bool wxImage::CanRead( const wxString& WXUNUSED_UNLESS_STREAMS(name) ) +{ +#if HAS_FILE_STREAMS + wxImageFileInputStream stream(name); + return CanRead(stream); +#else + return false; +#endif +} + +int wxImage::GetImageCount( const wxString& WXUNUSED_UNLESS_STREAMS(name), + long WXUNUSED_UNLESS_STREAMS(type) ) +{ +#if HAS_FILE_STREAMS + wxImageFileInputStream stream(name); + if (stream.Ok()) + return GetImageCount(stream, type); +#endif + + return 0; +} + +#if wxUSE_STREAMS + +bool wxImage::CanRead( wxInputStream &stream ) +{ + const wxList& list = GetHandlers(); + + for ( wxList::compatibility_iterator node = list.GetFirst(); node; node = node->GetNext() ) + { + wxImageHandler *handler=(wxImageHandler*)node->GetData(); + if (handler->CanRead( stream )) + return true; + } + + return false; +} + +int wxImage::GetImageCount( wxInputStream &stream, long type ) +{ + wxImageHandler *handler; + + if ( type == wxBITMAP_TYPE_ANY ) + { + wxList &list=GetHandlers(); + + for (wxList::compatibility_iterator node = list.GetFirst(); node; node = node->GetNext()) + { + handler=(wxImageHandler*)node->GetData(); + if ( handler->CanRead(stream) ) + return handler->GetImageCount(stream); + + } + + wxLogWarning(_("No handler found for image type.")); + return 0; + } + + handler = FindHandler(type); + + if ( !handler ) + { + wxLogWarning(_("No image handler for type %ld defined."), type); + return false; + } + + if ( handler->CanRead(stream) ) + { + return handler->GetImageCount(stream); + } + else + { + wxLogError(_("Image file is not of type %ld."), type); + return 0; + } +} + +bool wxImage::LoadFile( wxInputStream& stream, long type, int index ) +{ + UnRef(); + + m_refData = new wxImageRefData; + + wxImageHandler *handler; + + if ( type == wxBITMAP_TYPE_ANY ) + { + wxList &list=GetHandlers(); + + for ( wxList::compatibility_iterator node = list.GetFirst(); node; node = node->GetNext() ) + { + handler=(wxImageHandler*)node->GetData(); + if ( handler->CanRead(stream) ) + return handler->LoadFile(this, stream, true/*verbose*/, index); + + } + + wxLogWarning( _("No handler found for image type.") ); + return false; + } + + handler = FindHandler(type); + + if (handler == 0) + { + wxLogWarning( _("No image handler for type %ld defined."), type ); + + return false; + } + + if (stream.IsSeekable() && !handler->CanRead(stream)) + { + wxLogError(_("Image file is not of type %ld."), type); + return false; + } + else + return handler->LoadFile(this, stream, true/*verbose*/, index); +} + +bool wxImage::LoadFile( wxInputStream& stream, const wxString& mimetype, int index ) +{ + UnRef(); + + m_refData = new wxImageRefData; + + wxImageHandler *handler = FindHandlerMime(mimetype); + + if (handler == 0) + { + wxLogWarning( _("No image handler for type %s defined."), mimetype.GetData() ); + + return false; + } + + if (stream.IsSeekable() && !handler->CanRead(stream)) + { + wxLogError(_("Image file is not of type %s."), (const wxChar*) mimetype); + return false; + } + else + return handler->LoadFile( this, stream, true/*verbose*/, index ); +} + +bool wxImage::SaveFile( wxOutputStream& stream, int type ) const +{ + wxCHECK_MSG( Ok(), false, wxT("invalid image") ); + + wxImageHandler *handler = FindHandler(type); + if ( !handler ) + { + wxLogWarning( _("No image handler for type %d defined."), type ); + + return false; + } + + return handler->SaveFile( (wxImage*)this, stream ); +} + +bool wxImage::SaveFile( wxOutputStream& stream, const wxString& mimetype ) const +{ + wxCHECK_MSG( Ok(), false, wxT("invalid image") ); + + wxImageHandler *handler = FindHandlerMime(mimetype); + if ( !handler ) + { + wxLogWarning( _("No image handler for type %s defined."), mimetype.GetData() ); + + return false; + } + + return handler->SaveFile( (wxImage*)this, stream ); +} +#endif // wxUSE_STREAMS + +// ---------------------------------------------------------------------------- +// image I/O handlers +// ---------------------------------------------------------------------------- + +void wxImage::AddHandler( wxImageHandler *handler ) +{ + // Check for an existing handler of the type being added. + if (FindHandler( handler->GetType() ) == 0) + { + sm_handlers.Append( handler ); + } + else + { + // This is not documented behaviour, merely the simplest 'fix' + // for preventing duplicate additions. If someone ever has + // a good reason to add and remove duplicate handlers (and they + // may) we should probably refcount the duplicates. + // also an issue in InsertHandler below. + + wxLogDebug( _T("Adding duplicate image handler for '%s'"), + handler->GetName().c_str() ); + delete handler; + } +} + +void wxImage::InsertHandler( wxImageHandler *handler ) +{ + // Check for an existing handler of the type being added. + if (FindHandler( handler->GetType() ) == 0) + { + sm_handlers.Insert( handler ); + } + else + { + // see AddHandler for additional comments. + wxLogDebug( _T("Inserting duplicate image handler for '%s'"), + handler->GetName().c_str() ); + delete handler; + } +} + +bool wxImage::RemoveHandler( const wxString& name ) +{ + wxImageHandler *handler = FindHandler(name); + if (handler) + { + sm_handlers.DeleteObject(handler); + delete handler; + return true; + } + else + return false; +} + +wxImageHandler *wxImage::FindHandler( const wxString& name ) +{ + wxList::compatibility_iterator node = sm_handlers.GetFirst(); + while (node) + { + wxImageHandler *handler = (wxImageHandler*)node->GetData(); + if (handler->GetName().Cmp(name) == 0) return handler; + + node = node->GetNext(); + } + return 0; +} + +wxImageHandler *wxImage::FindHandler( const wxString& extension, long bitmapType ) +{ + wxList::compatibility_iterator node = sm_handlers.GetFirst(); + while (node) + { + wxImageHandler *handler = (wxImageHandler*)node->GetData(); + if ( (handler->GetExtension().Cmp(extension) == 0) && + (bitmapType == -1 || handler->GetType() == bitmapType) ) + return handler; + node = node->GetNext(); + } + return 0; +} + +wxImageHandler *wxImage::FindHandler( long bitmapType ) +{ + wxList::compatibility_iterator node = sm_handlers.GetFirst(); + while (node) + { + wxImageHandler *handler = (wxImageHandler *)node->GetData(); + if (handler->GetType() == bitmapType) return handler; + node = node->GetNext(); + } + return 0; +} + +wxImageHandler *wxImage::FindHandlerMime( const wxString& mimetype ) +{ + wxList::compatibility_iterator node = sm_handlers.GetFirst(); + while (node) + { + wxImageHandler *handler = (wxImageHandler *)node->GetData(); + if (handler->GetMimeType().IsSameAs(mimetype, false)) return handler; + node = node->GetNext(); + } + return 0; +} + +void wxImage::InitStandardHandlers() +{ +#if wxUSE_STREAMS + AddHandler(new wxBMPHandler); +#endif // wxUSE_STREAMS +} + +void wxImage::CleanUpHandlers() +{ + wxList::compatibility_iterator node = sm_handlers.GetFirst(); + while (node) + { + wxImageHandler *handler = (wxImageHandler *)node->GetData(); + wxList::compatibility_iterator next = node->GetNext(); + delete handler; + node = next; + } + + sm_handlers.Clear(); +} + +wxString wxImage::GetImageExtWildcard() +{ + wxString fmts; + + wxList& Handlers = wxImage::GetHandlers(); + wxList::compatibility_iterator Node = Handlers.GetFirst(); + while ( Node ) + { + wxImageHandler* Handler = (wxImageHandler*)Node->GetData(); + fmts += wxT("*.") + Handler->GetExtension(); + Node = Node->GetNext(); + if ( Node ) fmts += wxT(";"); + } + + return wxT("(") + fmts + wxT(")|") + fmts; +} + +wxImage::HSVValue wxImage::RGBtoHSV(const RGBValue& rgb) +{ + const double red = rgb.red / 255.0, + green = rgb.green / 255.0, + blue = rgb.blue / 255.0; + + // find the min and max intensity (and remember which one was it for the + // latter) + double minimumRGB = red; + if ( green < minimumRGB ) + minimumRGB = green; + if ( blue < minimumRGB ) + minimumRGB = blue; + + enum { RED, GREEN, BLUE } chMax = RED; + double maximumRGB = red; + if ( green > maximumRGB ) + { + chMax = GREEN; + maximumRGB = green; + } + if ( blue > maximumRGB ) + { + chMax = BLUE; + maximumRGB = blue; + } + + const double value = maximumRGB; + + double hue = 0.0, saturation; + const double deltaRGB = maximumRGB - minimumRGB; + if ( wxIsNullDouble(deltaRGB) ) + { + // Gray has no color + hue = 0.0; + saturation = 0.0; + } + else + { + switch ( chMax ) + { + case RED: + hue = (green - blue) / deltaRGB; + break; + + case GREEN: + hue = 2.0 + (blue - red) / deltaRGB; + break; + + case BLUE: + hue = 4.0 + (red - green) / deltaRGB; + break; + + default: + wxFAIL_MSG(wxT("hue not specified")); + break; + } + + hue /= 6.0; + + if ( hue < 0.0 ) + hue += 1.0; + + saturation = deltaRGB / maximumRGB; + } + + return HSVValue(hue, saturation, value); +} + +wxImage::RGBValue wxImage::HSVtoRGB(const HSVValue& hsv) +{ + double red, green, blue; + + if ( wxIsNullDouble(hsv.saturation) ) + { + // Grey + red = hsv.value; + green = hsv.value; + blue = hsv.value; + } + else // not grey + { + double hue = hsv.hue * 6.0; // sector 0 to 5 + int i = (int)floor(hue); + double f = hue - i; // fractional part of h + double p = hsv.value * (1.0 - hsv.saturation); + + switch (i) + { + case 0: + red = hsv.value; + green = hsv.value * (1.0 - hsv.saturation * (1.0 - f)); + blue = p; + break; + + case 1: + red = hsv.value * (1.0 - hsv.saturation * f); + green = hsv.value; + blue = p; + break; + + case 2: + red = p; + green = hsv.value; + blue = hsv.value * (1.0 - hsv.saturation * (1.0 - f)); + break; + + case 3: + red = p; + green = hsv.value * (1.0 - hsv.saturation * f); + blue = hsv.value; + break; + + case 4: + red = hsv.value * (1.0 - hsv.saturation * (1.0 - f)); + green = p; + blue = hsv.value; + break; + + default: // case 5: + red = hsv.value; + green = p; + blue = hsv.value * (1.0 - hsv.saturation * f); + break; + } + } + + return RGBValue((unsigned char)(red * 255.0), + (unsigned char)(green * 255.0), + (unsigned char)(blue * 255.0)); +} + +/* + * Rotates the hue of each pixel of the image. angle is a double in the range + * -1.0..1.0 where -1.0 is -360 degrees and 1.0 is 360 degrees + */ +void wxImage::RotateHue(double angle) +{ + AllocExclusive(); + + unsigned char *srcBytePtr; + unsigned char *dstBytePtr; + unsigned long count; + wxImage::HSVValue hsv; + wxImage::RGBValue rgb; + + wxASSERT (angle >= -1.0 && angle <= 1.0); + count = M_IMGDATA->m_width * M_IMGDATA->m_height; + if ( count > 0 && !wxIsNullDouble(angle) ) + { + srcBytePtr = M_IMGDATA->m_data; + dstBytePtr = srcBytePtr; + do + { + rgb.red = *srcBytePtr++; + rgb.green = *srcBytePtr++; + rgb.blue = *srcBytePtr++; + hsv = RGBtoHSV(rgb); + + hsv.hue = hsv.hue + angle; + if (hsv.hue > 1.0) + hsv.hue = hsv.hue - 1.0; + else if (hsv.hue < 0.0) + hsv.hue = hsv.hue + 1.0; + + rgb = HSVtoRGB(hsv); + *dstBytePtr++ = rgb.red; + *dstBytePtr++ = rgb.green; + *dstBytePtr++ = rgb.blue; + } while (--count != 0); + } +} + +//----------------------------------------------------------------------------- +// wxImageHandler +//----------------------------------------------------------------------------- + +IMPLEMENT_ABSTRACT_CLASS(wxImageHandler,wxObject) + +#if wxUSE_STREAMS +bool wxImageHandler::LoadFile( wxImage *WXUNUSED(image), wxInputStream& WXUNUSED(stream), bool WXUNUSED(verbose), int WXUNUSED(index) ) +{ + return false; +} + +bool wxImageHandler::SaveFile( wxImage *WXUNUSED(image), wxOutputStream& WXUNUSED(stream), bool WXUNUSED(verbose) ) +{ + return false; +} + +int wxImageHandler::GetImageCount( wxInputStream& WXUNUSED(stream) ) +{ + return 1; +} + +bool wxImageHandler::CanRead( const wxString& name ) +{ + if (wxFileExists(name)) + { + wxImageFileInputStream stream(name); + return CanRead(stream); + } + + wxLogError( _("Can't check image format of file '%s': file does not exist."), name.c_str() ); + + return false; +} + +bool wxImageHandler::CallDoCanRead(wxInputStream& stream) +{ + wxFileOffset posOld = stream.TellI(); + if ( posOld == wxInvalidOffset ) + { + // can't test unseekable stream + return false; + } + + bool ok = DoCanRead(stream); + + // restore the old position to be able to test other formats and so on + if ( stream.SeekI(posOld) == wxInvalidOffset ) + { + wxLogDebug(_T("Failed to rewind the stream in wxImageHandler!")); + + // reading would fail anyhow as we're not at the right position + return false; + } + + return ok; +} + +#endif // wxUSE_STREAMS + +// ---------------------------------------------------------------------------- +// image histogram stuff +// ---------------------------------------------------------------------------- + +bool +wxImageHistogram::FindFirstUnusedColour(unsigned char *r, + unsigned char *g, + unsigned char *b, + unsigned char r2, + unsigned char b2, + unsigned char g2) const +{ + unsigned long key = MakeKey(r2, g2, b2); + + while ( find(key) != end() ) + { + // color already used + r2++; + if ( r2 >= 255 ) + { + r2 = 0; + g2++; + if ( g2 >= 255 ) + { + g2 = 0; + b2++; + if ( b2 >= 255 ) + { + wxLogError(_("No unused colour in image.") ); + return false; + } + } + } + + key = MakeKey(r2, g2, b2); + } + + if ( r ) + *r = r2; + if ( g ) + *g = g2; + if ( b ) + *b = b2; + + return true; +} + +bool +wxImage::FindFirstUnusedColour(unsigned char *r, + unsigned char *g, + unsigned char *b, + unsigned char r2, + unsigned char b2, + unsigned char g2) const +{ + wxImageHistogram histogram; + + ComputeHistogram(histogram); + + return histogram.FindFirstUnusedColour(r, g, b, r2, g2, b2); +} + + + +// GRG, Dic/99 +// Counts and returns the number of different colours. Optionally stops +// when it exceeds 'stopafter' different colours. This is useful, for +// example, to see if the image can be saved as 8-bit (256 colour or +// less, in this case it would be invoked as CountColours(256)). Default +// value for stopafter is -1 (don't care). +// +unsigned long wxImage::CountColours( unsigned long stopafter ) const +{ + wxHashTable h; + wxObject dummy; + unsigned char r, g, b; + unsigned char *p; + unsigned long size, nentries, key; + + p = GetData(); + size = GetWidth() * GetHeight(); + nentries = 0; + + for (unsigned long j = 0; (j < size) && (nentries <= stopafter) ; j++) + { + r = *(p++); + g = *(p++); + b = *(p++); + key = wxImageHistogram::MakeKey(r, g, b); + + if (h.Get(key) == NULL) + { + h.Put(key, &dummy); + nentries++; + } + } + + return nentries; +} + + +unsigned long wxImage::ComputeHistogram( wxImageHistogram &h ) const +{ + unsigned char *p = GetData(); + unsigned long nentries = 0; + + h.clear(); + + const unsigned long size = GetWidth() * GetHeight(); + + unsigned char r, g, b; + for ( unsigned long n = 0; n < size; n++ ) + { + r = *p++; + g = *p++; + b = *p++; + + wxImageHistogramEntry& entry = h[wxImageHistogram::MakeKey(r, g, b)]; + + if ( entry.value++ == 0 ) + entry.index = nentries++; + } + + return nentries; +} + +/* + * Rotation code by Carlos Moreno + */ + +static const double wxROTATE_EPSILON = 1e-10; + +// Auxiliary function to rotate a point (x,y) with respect to point p0 +// make it inline and use a straight return to facilitate optimization +// also, the function receives the sine and cosine of the angle to avoid +// repeating the time-consuming calls to these functions -- sin/cos can +// be computed and stored in the calling function. + +static inline wxRealPoint +wxRotatePoint(const wxRealPoint& p, double cos_angle, double sin_angle, + const wxRealPoint& p0) +{ + return wxRealPoint(p0.x + (p.x - p0.x) * cos_angle - (p.y - p0.y) * sin_angle, + p0.y + (p.y - p0.y) * cos_angle + (p.x - p0.x) * sin_angle); +} + +static inline wxRealPoint +wxRotatePoint(double x, double y, double cos_angle, double sin_angle, + const wxRealPoint & p0) +{ + return wxRotatePoint (wxRealPoint(x,y), cos_angle, sin_angle, p0); +} + +wxImage wxImage::Rotate(double angle, const wxPoint & centre_of_rotation, bool interpolating, wxPoint * offset_after_rotation) const +{ + int i; + angle = -angle; // screen coordinates are a mirror image of "real" coordinates + + bool has_alpha = HasAlpha(); + + const int w = GetWidth(), + h = GetHeight(); + + // Create pointer-based array to accelerate access to wxImage's data + unsigned char ** data = new unsigned char * [h]; + data[0] = GetData(); + for (i = 1; i < h; i++) + data[i] = data[i - 1] + (3 * w); + + // Same for alpha channel + unsigned char ** alpha = NULL; + if (has_alpha) + { + alpha = new unsigned char * [h]; + alpha[0] = GetAlpha(); + for (i = 1; i < h; i++) + alpha[i] = alpha[i - 1] + w; + } + + // precompute coefficients for rotation formula + // (sine and cosine of the angle) + const double cos_angle = cos(angle); + const double sin_angle = sin(angle); + + // Create new Image to store the result + // First, find rectangle that covers the rotated image; to do that, + // rotate the four corners + + const wxRealPoint p0(centre_of_rotation.x, centre_of_rotation.y); + + wxRealPoint p1 = wxRotatePoint (0, 0, cos_angle, sin_angle, p0); + wxRealPoint p2 = wxRotatePoint (0, h, cos_angle, sin_angle, p0); + wxRealPoint p3 = wxRotatePoint (w, 0, cos_angle, sin_angle, p0); + wxRealPoint p4 = wxRotatePoint (w, h, cos_angle, sin_angle, p0); + + int x1a = (int) floor (wxMin (wxMin(p1.x, p2.x), wxMin(p3.x, p4.x))); + int y1a = (int) floor (wxMin (wxMin(p1.y, p2.y), wxMin(p3.y, p4.y))); + int x2a = (int) ceil (wxMax (wxMax(p1.x, p2.x), wxMax(p3.x, p4.x))); + int y2a = (int) ceil (wxMax (wxMax(p1.y, p2.y), wxMax(p3.y, p4.y))); + + // Create rotated image + wxImage rotated (x2a - x1a + 1, y2a - y1a + 1, false); + // With alpha channel + if (has_alpha) + rotated.SetAlpha(); + + if (offset_after_rotation != NULL) + { + *offset_after_rotation = wxPoint (x1a, y1a); + } + + // GRG: The rotated (destination) image is always accessed + // sequentially, so there is no need for a pointer-based + // array here (and in fact it would be slower). + // + unsigned char * dst = rotated.GetData(); + + unsigned char * alpha_dst = NULL; + if (has_alpha) + alpha_dst = rotated.GetAlpha(); + + // GRG: if the original image has a mask, use its RGB values + // as the blank pixel, else, fall back to default (black). + // + unsigned char blank_r = 0; + unsigned char blank_g = 0; + unsigned char blank_b = 0; + + if (HasMask()) + { + blank_r = GetMaskRed(); + blank_g = GetMaskGreen(); + blank_b = GetMaskBlue(); + rotated.SetMaskColour( blank_r, blank_g, blank_b ); + } + + // Now, for each point of the rotated image, find where it came from, by + // performing an inverse rotation (a rotation of -angle) and getting the + // pixel at those coordinates + + const int rH = rotated.GetHeight(); + const int rW = rotated.GetWidth(); + + // GRG: I've taken the (interpolating) test out of the loops, so that + // it is done only once, instead of repeating it for each pixel. + + if (interpolating) + { + for (int y = 0; y < rH; y++) + { + for (int x = 0; x < rW; x++) + { + wxRealPoint src = wxRotatePoint (x + x1a, y + y1a, cos_angle, -sin_angle, p0); + + if (-0.25 < src.x && src.x < w - 0.75 && + -0.25 < src.y && src.y < h - 0.75) + { + // interpolate using the 4 enclosing grid-points. Those + // points can be obtained using floor and ceiling of the + // exact coordinates of the point + int x1, y1, x2, y2; + + if (0 < src.x && src.x < w - 1) + { + x1 = wxRound(floor(src.x)); + x2 = wxRound(ceil(src.x)); + } + else // else means that x is near one of the borders (0 or width-1) + { + x1 = x2 = wxRound (src.x); + } + + if (0 < src.y && src.y < h - 1) + { + y1 = wxRound(floor(src.y)); + y2 = wxRound(ceil(src.y)); + } + else + { + y1 = y2 = wxRound (src.y); + } + + // get four points and the distances (square of the distance, + // for efficiency reasons) for the interpolation formula + + // GRG: Do not calculate the points until they are + // really needed -- this way we can calculate + // just one, instead of four, if d1, d2, d3 + // or d4 are < wxROTATE_EPSILON + + const double d1 = (src.x - x1) * (src.x - x1) + (src.y - y1) * (src.y - y1); + const double d2 = (src.x - x2) * (src.x - x2) + (src.y - y1) * (src.y - y1); + const double d3 = (src.x - x2) * (src.x - x2) + (src.y - y2) * (src.y - y2); + const double d4 = (src.x - x1) * (src.x - x1) + (src.y - y2) * (src.y - y2); + + // Now interpolate as a weighted average of the four surrounding + // points, where the weights are the distances to each of those points + + // If the point is exactly at one point of the grid of the source + // image, then don't interpolate -- just assign the pixel + + // d1,d2,d3,d4 are positive -- no need for abs() + if (d1 < wxROTATE_EPSILON) + { + unsigned char *p = data[y1] + (3 * x1); + *(dst++) = *(p++); + *(dst++) = *(p++); + *(dst++) = *p; + + if (has_alpha) + *(alpha_dst++) = *(alpha[y1] + x1); + } + else if (d2 < wxROTATE_EPSILON) + { + unsigned char *p = data[y1] + (3 * x2); + *(dst++) = *(p++); + *(dst++) = *(p++); + *(dst++) = *p; + + if (has_alpha) + *(alpha_dst++) = *(alpha[y1] + x2); + } + else if (d3 < wxROTATE_EPSILON) + { + unsigned char *p = data[y2] + (3 * x2); + *(dst++) = *(p++); + *(dst++) = *(p++); + *(dst++) = *p; + + if (has_alpha) + *(alpha_dst++) = *(alpha[y2] + x2); + } + else if (d4 < wxROTATE_EPSILON) + { + unsigned char *p = data[y2] + (3 * x1); + *(dst++) = *(p++); + *(dst++) = *(p++); + *(dst++) = *p; + + if (has_alpha) + *(alpha_dst++) = *(alpha[y2] + x1); + } + else + { + // weights for the weighted average are proportional to the inverse of the distance + unsigned char *v1 = data[y1] + (3 * x1); + unsigned char *v2 = data[y1] + (3 * x2); + unsigned char *v3 = data[y2] + (3 * x2); + unsigned char *v4 = data[y2] + (3 * x1); + + const double w1 = 1/d1, w2 = 1/d2, w3 = 1/d3, w4 = 1/d4; + + // GRG: Unrolled. + + *(dst++) = (unsigned char) + ( (w1 * *(v1++) + w2 * *(v2++) + + w3 * *(v3++) + w4 * *(v4++)) / + (w1 + w2 + w3 + w4) ); + *(dst++) = (unsigned char) + ( (w1 * *(v1++) + w2 * *(v2++) + + w3 * *(v3++) + w4 * *(v4++)) / + (w1 + w2 + w3 + w4) ); + *(dst++) = (unsigned char) + ( (w1 * *v1 + w2 * *v2 + + w3 * *v3 + w4 * *v4) / + (w1 + w2 + w3 + w4) ); + + if (has_alpha) + { + v1 = alpha[y1] + (x1); + v2 = alpha[y1] + (x2); + v3 = alpha[y2] + (x2); + v4 = alpha[y2] + (x1); + + *(alpha_dst++) = (unsigned char) + ( (w1 * *v1 + w2 * *v2 + + w3 * *v3 + w4 * *v4) / + (w1 + w2 + w3 + w4) ); + } + } + } + else + { + *(dst++) = blank_r; + *(dst++) = blank_g; + *(dst++) = blank_b; + + if (has_alpha) + *(alpha_dst++) = 0; + } + } + } + } + else // not interpolating + { + for (int y = 0; y < rH; y++) + { + for (int x = 0; x < rW; x++) + { + wxRealPoint src = wxRotatePoint (x + x1a, y + y1a, cos_angle, -sin_angle, p0); + + const int xs = wxRound (src.x); // wxRound rounds to the + const int ys = wxRound (src.y); // closest integer + + if (0 <= xs && xs < w && 0 <= ys && ys < h) + { + unsigned char *p = data[ys] + (3 * xs); + *(dst++) = *(p++); + *(dst++) = *(p++); + *(dst++) = *p; + + if (has_alpha) + *(alpha_dst++) = *(alpha[ys] + (xs)); + } + else + { + *(dst++) = blank_r; + *(dst++) = blank_g; + *(dst++) = blank_b; + + if (has_alpha) + *(alpha_dst++) = 255; + } + } + } + } + + delete [] data; + + if (has_alpha) + delete [] alpha; + + return rotated; +} + + + + + +// A module to allow wxImage initialization/cleanup +// without calling these functions from app.cpp or from +// the user's application. + +class wxImageModule: public wxModule +{ +DECLARE_DYNAMIC_CLASS(wxImageModule) +public: + wxImageModule() {} + bool OnInit() { wxImage::InitStandardHandlers(); return true; } + void OnExit() { wxImage::CleanUpHandlers(); } +}; + +IMPLEMENT_DYNAMIC_CLASS(wxImageModule, wxModule) + + +#endif // wxUSE_IMAGE diff --git a/Externals/wxWidgets/src/common/imagfill.cpp b/Externals/wxWidgets/src/common/imagfill.cpp index 5d016de76d..8c4e03b967 100644 --- a/Externals/wxWidgets/src/common/imagfill.cpp +++ b/Externals/wxWidgets/src/common/imagfill.cpp @@ -1,308 +1,308 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/imagfill.cpp -// Purpose: FloodFill for wxImage -// Author: Julian Smart -// RCS-ID: $Id: imagfill.cpp 39957 2006-07-03 19:02:54Z ABX $ -// Copyright: (c) Julian Smart -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_IMAGE && !defined(__WXMSW__) -// we have no use for this code in wxMSW... - -#ifndef WX_PRECOMP - #include "wx/brush.h" - #include "wx/dc.h" - #include "wx/dcmemory.h" - #include "wx/image.h" -#endif - -// DoFloodFill -// Fills with the colour extracted from fillBrush, starting at x,y until either -// a color different from the start pixel is reached (wxFLOOD_SURFACE) -// or fill color is reached (wxFLOOD_BORDER) - -static bool LINKAGEMODE MatchPixel(wxImage *img, int x, int y, int w, int h, const wxColour& c) -{ - if ((x<0)||(x>=w)||(y<0)||(y>=h)) return false; - - unsigned char r = img->GetRed(x,y); - unsigned char g = img->GetGreen(x,y); - unsigned char b = img->GetBlue(x,y); - return c.Red() == r && c.Green() == g && c.Blue() == b ; -} - -static bool LINKAGEMODE MatchBoundaryPixel(wxImage *img, int x, int y, int w, int h, const wxColour & fill, const wxColour& bound) -{ - if ((x<0)||(x>=w)||(y<0)||(y>=h)) return true; - - unsigned char r = img->GetRed(x,y); - unsigned char g = img->GetGreen(x,y); - unsigned char b = img->GetBlue(x,y); - if ( fill.Red() == r && fill.Green() == g && fill.Blue() == b ) - return true; - if ( bound.Red() == r && bound.Green() == g && bound.Blue() == b ) - return true; - return false; -} - - -static void LINKAGEMODE -wxImageFloodFill(wxImage *image, - wxCoord x, wxCoord y, const wxBrush & fillBrush, - const wxColour& testColour, int style, - int WXUNUSED(LogicalFunction)) -{ - /* A diamond flood-fill using a circular queue system. - Each pixel surrounding the current pixel is added to - the queue if it meets the criteria, then is retrieved in - its turn. Code originally based on http://www.drawit.co.nz/Developers.htm, - with explicit permission to use this for wxWidgets granted by Andrew Empson - (no copyright claimed) - */ - - int width = image->GetWidth(); - int height = image->GetHeight(); - - //Draw using a pen made from the current brush colour - //Potentially allows us to use patterned flood fills in future code - wxColour fillColour = fillBrush.GetColour(); - unsigned char r = fillColour.Red(); - unsigned char g = fillColour.Green(); - unsigned char b = fillColour.Blue(); - - //initial test : - if (style == wxFLOOD_SURFACE) - { - //if wxFLOOD_SURFACE, if fill colour is same as required, we don't do anything - if ( image->GetRed(x,y) != r - || image->GetGreen(x,y) != g - || image->GetBlue (x,y) != b ) - { - //prepare memory for queue - //queue save, start, read - size_t *qs, *qst, *qr; - - //queue size (physical) - long qSz= height * width * 2; - qst = new size_t [qSz]; - - //temporary x and y locations - int xt, yt; - - for (int i=0; i < qSz; i++) - qst[i] = 0; - - // start queue - qs=qr=qst; - *qs=xt=x; - qs++; - *qs=yt=y; - qs++; - - image->SetRGB(xt,yt,r,g,b); - - //Main queue loop - while(qr!=qs) - { - //Add new members to queue - //Above current pixel - if(MatchPixel(image,xt,yt-1,width,height,testColour)) - { - *qs=xt; - qs++; - *qs=yt-1; - qs++; - image->SetRGB(xt,yt-1,r,g,b); - - //Loop back to beginning of queue - if(qs>=(qst+qSz)) qs=qst; - } - - //Below current pixel - if(MatchPixel(image,xt,yt+1,width,height,testColour)) - { - *qs=xt; - qs++; - *qs=yt+1; - qs++; - image->SetRGB(xt,yt+1,r,g,b); - if(qs>=(qst+qSz)) qs=qst; - } - - //Left of current pixel - if(MatchPixel(image,xt-1,yt,width,height,testColour)) - { - *qs=xt-1; - qs++; - *qs=yt; - qs++; - image->SetRGB(xt-1,yt,r,g,b); - if(qs>=(qst+qSz)) qs=qst; - } - - //Right of current pixel - if(MatchPixel(image,xt+1,yt,width,height,testColour)) - { - *qs=xt+1; - qs++; - *qs=yt; - qs++; - image->SetRGB(xt+1,yt,r,g,b); - if(qs>=(qst+qSz)) qs=qst; - } - - //Retrieve current queue member - qr+=2; - - //Loop back to the beginning - if(qr>=(qst+qSz)) qr=qst; - xt=*qr; - yt=*(qr+1); - - //Go Back to beginning of loop - } - - delete[] qst; - } - } - else - { - //style is wxFLOOD_BORDER - // fill up to testColor border - if already testColour don't do anything - if ( image->GetRed(x,y) != testColour.Red() - || image->GetGreen(x,y) != testColour.Green() - || image->GetBlue(x,y) != testColour.Blue() ) - { - //prepare memory for queue - //queue save, start, read - size_t *qs, *qst, *qr; - - //queue size (physical) - long qSz= height * width * 2; - qst = new size_t [qSz]; - - //temporary x and y locations - int xt, yt; - - for (int i=0; i < qSz; i++) - qst[i] = 0; - - // start queue - qs=qr=qst; - *qs=xt=x; - qs++; - *qs=yt=y; - qs++; - - image->SetRGB(xt,yt,r,g,b); - - //Main queue loop - while (qr!=qs) - { - //Add new members to queue - //Above current pixel - if(!MatchBoundaryPixel(image,xt,yt-1,width,height,fillColour,testColour)) - { - *qs=xt; - qs++; - *qs=yt-1; - qs++; - image->SetRGB(xt,yt-1,r,g,b); - - //Loop back to beginning of queue - if(qs>=(qst+qSz)) qs=qst; - } - - //Below current pixel - if(!MatchBoundaryPixel(image,xt,yt+1,width,height,fillColour,testColour)) - { - *qs=xt; - qs++; - *qs=yt+1; - qs++; - image->SetRGB(xt,yt+1,r,g,b); - if(qs>=(qst+qSz)) qs=qst; - } - - //Left of current pixel - if(!MatchBoundaryPixel(image,xt-1,yt,width,height,fillColour,testColour)) - { - *qs=xt-1; - qs++; - *qs=yt; - qs++; - image->SetRGB(xt-1,yt,r,g,b); - if(qs>=(qst+qSz)) qs=qst; - } - - //Right of current pixel - if(!MatchBoundaryPixel(image,xt+1,yt,width,height,fillColour,testColour)) - { - *qs=xt+1; - qs++; - *qs=yt; - qs++; - image->SetRGB(xt+1,yt,r,g,b); - if(qs>=(qst+qSz)) qs=qst; - } - - //Retrieve current queue member - qr+=2; - - //Loop back to the beginning - if(qr>=(qst+qSz)) qr=qst; - xt=*qr; - yt=*(qr+1); - - //Go Back to beginning of loop - } - - delete[] qst; - } - } - //all done, -} - - -bool wxDoFloodFill(wxDC *dc, wxCoord x, wxCoord y, - const wxColour& col, int style) -{ - if (dc->GetBrush().GetStyle() == wxTRANSPARENT) - return true; - - int height = 0; - int width = 0; - dc->GetSize(&width, &height); - - //it would be nice to fail if we don't get a sensible size... - wxCHECK_MSG(width >= 1 && height >= 1, false, - wxT("In FloodFill, dc.GetSize routine failed, method not supported by this DC")); - - //this is much faster than doing the individual pixels - wxMemoryDC memdc; - wxBitmap bitmap(width, height); - memdc.SelectObject(bitmap); - memdc.Blit(0, 0, width, height, dc, 0, 0); - memdc.SelectObject(wxNullBitmap); - - wxImage image = bitmap.ConvertToImage(); - wxImageFloodFill(&image, x,y, dc->GetBrush(), col, style, - dc->GetLogicalFunction()); - bitmap = wxBitmap(image); - memdc.SelectObject(bitmap); - dc->Blit(0, 0, width, height, &memdc, 0, 0); - memdc.SelectObject(wxNullBitmap); - - return true; -} - -#endif // wxUSE_IMAGE +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/imagfill.cpp +// Purpose: FloodFill for wxImage +// Author: Julian Smart +// RCS-ID: $Id: imagfill.cpp 39957 2006-07-03 19:02:54Z ABX $ +// Copyright: (c) Julian Smart +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_IMAGE && !defined(__WXMSW__) +// we have no use for this code in wxMSW... + +#ifndef WX_PRECOMP + #include "wx/brush.h" + #include "wx/dc.h" + #include "wx/dcmemory.h" + #include "wx/image.h" +#endif + +// DoFloodFill +// Fills with the colour extracted from fillBrush, starting at x,y until either +// a color different from the start pixel is reached (wxFLOOD_SURFACE) +// or fill color is reached (wxFLOOD_BORDER) + +static bool LINKAGEMODE MatchPixel(wxImage *img, int x, int y, int w, int h, const wxColour& c) +{ + if ((x<0)||(x>=w)||(y<0)||(y>=h)) return false; + + unsigned char r = img->GetRed(x,y); + unsigned char g = img->GetGreen(x,y); + unsigned char b = img->GetBlue(x,y); + return c.Red() == r && c.Green() == g && c.Blue() == b ; +} + +static bool LINKAGEMODE MatchBoundaryPixel(wxImage *img, int x, int y, int w, int h, const wxColour & fill, const wxColour& bound) +{ + if ((x<0)||(x>=w)||(y<0)||(y>=h)) return true; + + unsigned char r = img->GetRed(x,y); + unsigned char g = img->GetGreen(x,y); + unsigned char b = img->GetBlue(x,y); + if ( fill.Red() == r && fill.Green() == g && fill.Blue() == b ) + return true; + if ( bound.Red() == r && bound.Green() == g && bound.Blue() == b ) + return true; + return false; +} + + +static void LINKAGEMODE +wxImageFloodFill(wxImage *image, + wxCoord x, wxCoord y, const wxBrush & fillBrush, + const wxColour& testColour, int style, + int WXUNUSED(LogicalFunction)) +{ + /* A diamond flood-fill using a circular queue system. + Each pixel surrounding the current pixel is added to + the queue if it meets the criteria, then is retrieved in + its turn. Code originally based on http://www.drawit.co.nz/Developers.htm, + with explicit permission to use this for wxWidgets granted by Andrew Empson + (no copyright claimed) + */ + + int width = image->GetWidth(); + int height = image->GetHeight(); + + //Draw using a pen made from the current brush colour + //Potentially allows us to use patterned flood fills in future code + wxColour fillColour = fillBrush.GetColour(); + unsigned char r = fillColour.Red(); + unsigned char g = fillColour.Green(); + unsigned char b = fillColour.Blue(); + + //initial test : + if (style == wxFLOOD_SURFACE) + { + //if wxFLOOD_SURFACE, if fill colour is same as required, we don't do anything + if ( image->GetRed(x,y) != r + || image->GetGreen(x,y) != g + || image->GetBlue (x,y) != b ) + { + //prepare memory for queue + //queue save, start, read + size_t *qs, *qst, *qr; + + //queue size (physical) + long qSz= height * width * 2; + qst = new size_t [qSz]; + + //temporary x and y locations + int xt, yt; + + for (int i=0; i < qSz; i++) + qst[i] = 0; + + // start queue + qs=qr=qst; + *qs=xt=x; + qs++; + *qs=yt=y; + qs++; + + image->SetRGB(xt,yt,r,g,b); + + //Main queue loop + while(qr!=qs) + { + //Add new members to queue + //Above current pixel + if(MatchPixel(image,xt,yt-1,width,height,testColour)) + { + *qs=xt; + qs++; + *qs=yt-1; + qs++; + image->SetRGB(xt,yt-1,r,g,b); + + //Loop back to beginning of queue + if(qs>=(qst+qSz)) qs=qst; + } + + //Below current pixel + if(MatchPixel(image,xt,yt+1,width,height,testColour)) + { + *qs=xt; + qs++; + *qs=yt+1; + qs++; + image->SetRGB(xt,yt+1,r,g,b); + if(qs>=(qst+qSz)) qs=qst; + } + + //Left of current pixel + if(MatchPixel(image,xt-1,yt,width,height,testColour)) + { + *qs=xt-1; + qs++; + *qs=yt; + qs++; + image->SetRGB(xt-1,yt,r,g,b); + if(qs>=(qst+qSz)) qs=qst; + } + + //Right of current pixel + if(MatchPixel(image,xt+1,yt,width,height,testColour)) + { + *qs=xt+1; + qs++; + *qs=yt; + qs++; + image->SetRGB(xt+1,yt,r,g,b); + if(qs>=(qst+qSz)) qs=qst; + } + + //Retrieve current queue member + qr+=2; + + //Loop back to the beginning + if(qr>=(qst+qSz)) qr=qst; + xt=*qr; + yt=*(qr+1); + + //Go Back to beginning of loop + } + + delete[] qst; + } + } + else + { + //style is wxFLOOD_BORDER + // fill up to testColor border - if already testColour don't do anything + if ( image->GetRed(x,y) != testColour.Red() + || image->GetGreen(x,y) != testColour.Green() + || image->GetBlue(x,y) != testColour.Blue() ) + { + //prepare memory for queue + //queue save, start, read + size_t *qs, *qst, *qr; + + //queue size (physical) + long qSz= height * width * 2; + qst = new size_t [qSz]; + + //temporary x and y locations + int xt, yt; + + for (int i=0; i < qSz; i++) + qst[i] = 0; + + // start queue + qs=qr=qst; + *qs=xt=x; + qs++; + *qs=yt=y; + qs++; + + image->SetRGB(xt,yt,r,g,b); + + //Main queue loop + while (qr!=qs) + { + //Add new members to queue + //Above current pixel + if(!MatchBoundaryPixel(image,xt,yt-1,width,height,fillColour,testColour)) + { + *qs=xt; + qs++; + *qs=yt-1; + qs++; + image->SetRGB(xt,yt-1,r,g,b); + + //Loop back to beginning of queue + if(qs>=(qst+qSz)) qs=qst; + } + + //Below current pixel + if(!MatchBoundaryPixel(image,xt,yt+1,width,height,fillColour,testColour)) + { + *qs=xt; + qs++; + *qs=yt+1; + qs++; + image->SetRGB(xt,yt+1,r,g,b); + if(qs>=(qst+qSz)) qs=qst; + } + + //Left of current pixel + if(!MatchBoundaryPixel(image,xt-1,yt,width,height,fillColour,testColour)) + { + *qs=xt-1; + qs++; + *qs=yt; + qs++; + image->SetRGB(xt-1,yt,r,g,b); + if(qs>=(qst+qSz)) qs=qst; + } + + //Right of current pixel + if(!MatchBoundaryPixel(image,xt+1,yt,width,height,fillColour,testColour)) + { + *qs=xt+1; + qs++; + *qs=yt; + qs++; + image->SetRGB(xt+1,yt,r,g,b); + if(qs>=(qst+qSz)) qs=qst; + } + + //Retrieve current queue member + qr+=2; + + //Loop back to the beginning + if(qr>=(qst+qSz)) qr=qst; + xt=*qr; + yt=*(qr+1); + + //Go Back to beginning of loop + } + + delete[] qst; + } + } + //all done, +} + + +bool wxDoFloodFill(wxDC *dc, wxCoord x, wxCoord y, + const wxColour& col, int style) +{ + if (dc->GetBrush().GetStyle() == wxTRANSPARENT) + return true; + + int height = 0; + int width = 0; + dc->GetSize(&width, &height); + + //it would be nice to fail if we don't get a sensible size... + wxCHECK_MSG(width >= 1 && height >= 1, false, + wxT("In FloodFill, dc.GetSize routine failed, method not supported by this DC")); + + //this is much faster than doing the individual pixels + wxMemoryDC memdc; + wxBitmap bitmap(width, height); + memdc.SelectObject(bitmap); + memdc.Blit(0, 0, width, height, dc, 0, 0); + memdc.SelectObject(wxNullBitmap); + + wxImage image = bitmap.ConvertToImage(); + wxImageFloodFill(&image, x,y, dc->GetBrush(), col, style, + dc->GetLogicalFunction()); + bitmap = wxBitmap(image); + memdc.SelectObject(bitmap); + dc->Blit(0, 0, width, height, &memdc, 0, 0); + memdc.SelectObject(wxNullBitmap); + + return true; +} + +#endif // wxUSE_IMAGE diff --git a/Externals/wxWidgets/src/common/imaggif.cpp b/Externals/wxWidgets/src/common/imaggif.cpp index befa52af3c..bb49847cf1 100644 --- a/Externals/wxWidgets/src/common/imaggif.cpp +++ b/Externals/wxWidgets/src/common/imaggif.cpp @@ -1,105 +1,105 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/imaggif.cpp -// Purpose: wxGIFHandler -// Author: Vaclav Slavik & Guillermo Rodriguez Garcia -// RCS-ID: $Id: imaggif.cpp 41819 2006-10-09 17:51:07Z VZ $ -// Copyright: (c) 1999 Vaclav Slavik & Guillermo Rodriguez Garcia -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_IMAGE && wxUSE_GIF - -#ifndef WX_PRECOMP - #include "wx/intl.h" - #include "wx/log.h" -#endif - -#include "wx/imaggif.h" -#include "wx/gifdecod.h" -#include "wx/wfstream.h" - -IMPLEMENT_DYNAMIC_CLASS(wxGIFHandler,wxImageHandler) - -//----------------------------------------------------------------------------- -// wxGIFHandler -//----------------------------------------------------------------------------- - -#if wxUSE_STREAMS - -bool wxGIFHandler::LoadFile(wxImage *image, wxInputStream& stream, - bool verbose, int index) -{ - wxGIFDecoder *decod; - wxGIFErrorCode error; - bool ok = true; - -// image->Destroy(); - decod = new wxGIFDecoder(); - error = decod->LoadGIF(stream); - - if ((error != wxGIF_OK) && (error != wxGIF_TRUNCATED)) - { - if (verbose) - { - switch (error) - { - case wxGIF_INVFORMAT: - wxLogError(_("GIF: error in GIF image format.")); - break; - case wxGIF_MEMERR: - wxLogError(_("GIF: not enough memory.")); - break; - default: - wxLogError(_("GIF: unknown error!!!")); - break; - } - } - delete decod; - return false; - } - - if ((error == wxGIF_TRUNCATED) && verbose) - { - wxLogError(_("GIF: data stream seems to be truncated.")); - /* go on; image data is OK */ - } - - if (ok) - { - ok = decod->ConvertToImage(index != -1 ? (size_t)index : 0, image); - } - else - { - wxLogError(_("GIF: Invalid gif index.")); - } - - delete decod; - - return ok; -} - -bool wxGIFHandler::SaveFile( wxImage * WXUNUSED(image), - wxOutputStream& WXUNUSED(stream), bool verbose ) -{ - if (verbose) - wxLogDebug(wxT("GIF: the handler is read-only!!")); - - return false; -} - -bool wxGIFHandler::DoCanRead( wxInputStream& stream ) -{ - wxGIFDecoder decod; - return decod.CanRead(stream); -} - -#endif // wxUSE_STREAMS - -#endif // wxUSE_GIF +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/imaggif.cpp +// Purpose: wxGIFHandler +// Author: Vaclav Slavik & Guillermo Rodriguez Garcia +// RCS-ID: $Id: imaggif.cpp 41819 2006-10-09 17:51:07Z VZ $ +// Copyright: (c) 1999 Vaclav Slavik & Guillermo Rodriguez Garcia +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_IMAGE && wxUSE_GIF + +#ifndef WX_PRECOMP + #include "wx/intl.h" + #include "wx/log.h" +#endif + +#include "wx/imaggif.h" +#include "wx/gifdecod.h" +#include "wx/wfstream.h" + +IMPLEMENT_DYNAMIC_CLASS(wxGIFHandler,wxImageHandler) + +//----------------------------------------------------------------------------- +// wxGIFHandler +//----------------------------------------------------------------------------- + +#if wxUSE_STREAMS + +bool wxGIFHandler::LoadFile(wxImage *image, wxInputStream& stream, + bool verbose, int index) +{ + wxGIFDecoder *decod; + wxGIFErrorCode error; + bool ok = true; + +// image->Destroy(); + decod = new wxGIFDecoder(); + error = decod->LoadGIF(stream); + + if ((error != wxGIF_OK) && (error != wxGIF_TRUNCATED)) + { + if (verbose) + { + switch (error) + { + case wxGIF_INVFORMAT: + wxLogError(_("GIF: error in GIF image format.")); + break; + case wxGIF_MEMERR: + wxLogError(_("GIF: not enough memory.")); + break; + default: + wxLogError(_("GIF: unknown error!!!")); + break; + } + } + delete decod; + return false; + } + + if ((error == wxGIF_TRUNCATED) && verbose) + { + wxLogError(_("GIF: data stream seems to be truncated.")); + /* go on; image data is OK */ + } + + if (ok) + { + ok = decod->ConvertToImage(index != -1 ? (size_t)index : 0, image); + } + else + { + wxLogError(_("GIF: Invalid gif index.")); + } + + delete decod; + + return ok; +} + +bool wxGIFHandler::SaveFile( wxImage * WXUNUSED(image), + wxOutputStream& WXUNUSED(stream), bool verbose ) +{ + if (verbose) + wxLogDebug(wxT("GIF: the handler is read-only!!")); + + return false; +} + +bool wxGIFHandler::DoCanRead( wxInputStream& stream ) +{ + wxGIFDecoder decod; + return decod.CanRead(stream); +} + +#endif // wxUSE_STREAMS + +#endif // wxUSE_GIF diff --git a/Externals/wxWidgets/src/common/imagiff.cpp b/Externals/wxWidgets/src/common/imagiff.cpp index 1f00efae82..87ef214455 100644 --- a/Externals/wxWidgets/src/common/imagiff.cpp +++ b/Externals/wxWidgets/src/common/imagiff.cpp @@ -1,794 +1,794 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/imagiff.h -// Purpose: wxImage handler for Amiga IFF images -// Author: Steffen Gutmann, Thomas Meyer -// RCS-ID: $Id: imagiff.cpp 38787 2006-04-18 07:24:35Z ABX $ -// Copyright: (c) Steffen Gutmann, 2002 -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// Parts of this source are based on the iff loading algorithm found -// in xviff.c. Permission by the original author, Thomas Meyer, and -// by the author of xv, John Bradley for using the iff loading part -// in wxWidgets has been gratefully given. - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_IMAGE && wxUSE_IFF - -#ifndef WX_PRECOMP - #include "wx/log.h" - #include "wx/intl.h" -#endif - -#include "wx/imagiff.h" -#include "wx/wfstream.h" - -#if wxUSE_PALETTE - #include "wx/palette.h" -#endif // wxUSE_PALETTE - -#include -#include - - -// -------------------------------------------------------------------------- -// Constants -// -------------------------------------------------------------------------- - -// Error codes: -// Note that the error code wxIFF_TRUNCATED means that the image itself -// is most probably OK, but the decoder didn't reach the end of the data -// stream; this means that if it was not reading directly from file, -// the stream will not be correctly positioned. -// - -enum -{ - wxIFF_OK = 0, /* everything was OK */ - wxIFF_INVFORMAT, /* error in iff header */ - wxIFF_MEMERR, /* error allocating memory */ - wxIFF_TRUNCATED /* file appears to be truncated */ -}; - -// -------------------------------------------------------------------------- -// wxIFFDecoder class -// -------------------------------------------------------------------------- - -// internal class for storing IFF image data -class IFFImage -{ -public: - unsigned int w; /* width */ - unsigned int h; /* height */ - int transparent; /* transparent color (-1 = none) */ - int colors; /* number of colors */ - unsigned char *p; /* bitmap */ - unsigned char *pal; /* palette */ - - IFFImage() : w(0), h(0), colors(0), p(0), pal(0) {} - ~IFFImage() { delete [] p; delete [] pal; } -}; - -class WXDLLEXPORT wxIFFDecoder -{ -private: - IFFImage *m_image; // image data - wxInputStream *m_f; // input stream - unsigned char *databuf; - unsigned char *picptr; - unsigned char *decomp_mem; - - void Destroy(); - -public: - // get data of current frame - unsigned char* GetData() const; - unsigned char* GetPalette() const; - int GetNumColors() const; - unsigned int GetWidth() const; - unsigned int GetHeight() const; - int GetTransparentColour() const; - - // constructor, destructor, etc. - wxIFFDecoder(wxInputStream *s); - ~wxIFFDecoder() { Destroy(); } - bool CanRead(); - int ReadIFF(); - bool ConvertToImage(wxImage *image) const; -}; - - -//--------------------------------------------------------------------------- -// wxIFFDecoder constructor and destructor -//--------------------------------------------------------------------------- - -wxIFFDecoder::wxIFFDecoder(wxInputStream *s) -{ - m_f = s; - m_image = 0; - databuf = 0; - decomp_mem = 0; -} - -void wxIFFDecoder::Destroy() -{ - delete m_image; - m_image = 0; - delete [] databuf; - databuf = 0; - delete [] decomp_mem; - decomp_mem = 0; -} - -//--------------------------------------------------------------------------- -// Convert this image to a wxImage object -//--------------------------------------------------------------------------- - -// This function was designed by Vaclav Slavik - -bool wxIFFDecoder::ConvertToImage(wxImage *image) const -{ - // just in case... - image->Destroy(); - - // create the image - image->Create(GetWidth(), GetHeight()); - - if (!image->Ok()) - return false; - - unsigned char *pal = GetPalette(); - unsigned char *src = GetData(); - unsigned char *dst = image->GetData(); - int colors = GetNumColors(); - int transparent = GetTransparentColour(); - long i; - - // set transparent colour mask - if (transparent != -1) - { - for (i = 0; i < colors; i++) - { - if ((pal[3 * i + 0] == 255) && - (pal[3 * i + 1] == 0) && - (pal[3 * i + 2] == 255)) - { - pal[3 * i + 2] = 254; - } - } - - pal[3 * transparent + 0] = 255, - pal[3 * transparent + 1] = 0, - pal[3 * transparent + 2] = 255; - - image->SetMaskColour(255, 0, 255); - } - else - image->SetMask(false); - -#if wxUSE_PALETTE - if (pal && colors > 0) - { - unsigned char* r = new unsigned char[colors]; - unsigned char* g = new unsigned char[colors]; - unsigned char* b = new unsigned char[colors]; - - for (i = 0; i < colors; i++) - { - r[i] = pal[3*i + 0]; - g[i] = pal[3*i + 1]; - b[i] = pal[3*i + 2]; - } - - image->SetPalette(wxPalette(colors, r, g, b)); - - delete [] r; - delete [] g; - delete [] b; - } -#endif // wxUSE_PALETTE - - // copy image data - for (i = 0; i < (long)(GetWidth() * GetHeight()); i++, src += 3, dst += 3) - { - dst[0] = src[0]; - dst[1] = src[1]; - dst[2] = src[2]; - } - - return true; -} - - -//--------------------------------------------------------------------------- -// Data accessors -//--------------------------------------------------------------------------- - -// Get data for current frame - -unsigned char* wxIFFDecoder::GetData() const { return (m_image->p); } -unsigned char* wxIFFDecoder::GetPalette() const { return (m_image->pal); } -int wxIFFDecoder::GetNumColors() const { return m_image->colors; } -unsigned int wxIFFDecoder::GetWidth() const { return (m_image->w); } -unsigned int wxIFFDecoder::GetHeight() const { return (m_image->h); } -int wxIFFDecoder::GetTransparentColour() const { return m_image->transparent; } - -//--------------------------------------------------------------------------- -// IFF reading and decoding -//--------------------------------------------------------------------------- - -// -// CanRead: -// Returns true if the file looks like a valid IFF, false otherwise. -// -bool wxIFFDecoder::CanRead() -{ - unsigned char buf[12]; - - if ( !m_f->Read(buf, WXSIZEOF(buf)) ) - return false; - - m_f->SeekI(-(wxFileOffset)WXSIZEOF(buf), wxFromCurrent); - - return (memcmp(buf, "FORM", 4) == 0) && (memcmp(buf+8, "ILBM", 4) == 0); -} - - -// ReadIFF: -// Based on xv source code by Thomas Meyer -// Permission for use in wxWidgets has been gratefully given. - -typedef unsigned char byte; -#define IFFDEBUG 0 - -/************************************************************************* - void decomprle(source, destination, source length, buffer size) - - Decompress run-length encoded data from source to destination. Terminates - when source is decoded completely or destination buffer is full. - - The decruncher is as optimized as I could make it, without risking - safety in case of corrupt BODY chunks. -**************************************************************************/ - -static void decomprle(const byte *sptr, byte *dptr, long slen, long dlen) -{ - byte codeByte, dataByte; - - while ((slen > 0) && (dlen > 0)) { - // read control byte - codeByte = *sptr++; - - if (codeByte < 0x80) { - codeByte++; - if ((slen > (long) codeByte) && (dlen >= (long) codeByte)) { - slen -= codeByte + 1; - dlen -= codeByte; - while (codeByte > 0) { - *dptr++ = *sptr++; - codeByte--; - } - } - else slen = 0; - } - - else if (codeByte > 0x80) { - codeByte = 0x81 - (codeByte & 0x7f); - if ((slen > (long) 0) && (dlen >= (long) codeByte)) { - dataByte = *sptr++; - slen -= 2; - dlen -= codeByte; - while (codeByte > 0) { - *dptr++ = dataByte; - codeByte--; - } - } - else slen = 0; - } - } -} - -/******************************************/ -static unsigned int iff_getword(const byte *ptr) -{ - unsigned int v; - - v = *ptr++; - v = (v << 8) + *ptr; - return v; -} - -/******************************************/ -static unsigned long iff_getlong(const byte *ptr) -{ - unsigned long l; - - l = *ptr++; - l = (l << 8) + *ptr++; - l = (l << 8) + *ptr++; - l = (l << 8) + *ptr; - return l; -} - -// Define internal ILBM types -#define ILBM_NORMAL 0 -#define ILBM_EHB 1 -#define ILBM_HAM 2 -#define ILBM_HAM8 3 -#define ILBM_24BIT 4 - -int wxIFFDecoder::ReadIFF() -{ - Destroy(); - - m_image = new IFFImage(); - if (m_image == 0) { - Destroy(); - return wxIFF_MEMERR; - } - - // compute file length - wxFileOffset currentPos = m_f->TellI(); - m_f->SeekI(0, wxFromEnd); - long filesize = m_f->TellI(); - m_f->SeekI(currentPos, wxFromStart); - - // allocate memory for complete file - if ((databuf = new byte[filesize]) == 0) { - Destroy(); - return wxIFF_MEMERR; - } - - m_f->Read(databuf, filesize); - const byte *dataend = databuf + filesize; - - // initialize work pointer. used to trace the buffer for IFF chunks - const byte *dataptr = databuf; - - // check for minmal size - if (dataptr + 12 > dataend) { - Destroy(); - return wxIFF_INVFORMAT; - } - - // check if we really got an IFF file - if (strncmp((char *)dataptr, "FORM", 4) != 0) { - Destroy(); - return wxIFF_INVFORMAT; - } - - dataptr = dataptr + 8; // skip ID and length of FORM - - // check if the IFF file is an ILBM (picture) file - if (strncmp((char *) dataptr, "ILBM", 4) != 0) { - Destroy(); - return wxIFF_INVFORMAT; - } - - wxLogTrace(_T("iff"), _T("IFF ILBM file recognized")); - - dataptr = dataptr + 4; // skip ID - - // - // main decoding loop. searches IFF chunks and handles them. - // terminates when BODY chunk was found or dataptr ran over end of file - // - bool BMHDok = false, CMAPok = false, CAMGok = false; - int bmhd_width = 0, bmhd_height = 0, bmhd_bitplanes = 0, bmhd_transcol = -1; - byte bmhd_masking = 0, bmhd_compression = 0; - long camg_viewmode = 0; - int colors = 0; - while (dataptr + 8 <= dataend) { - // get chunk length and make even - size_t chunkLen = (iff_getlong(dataptr + 4) + 1) & 0xfffffffe; -#ifdef __VMS - // Silence compiler warning - int chunkLen_; - chunkLen_ = chunkLen; - if (chunkLen_ < 0) { // format error? -#else - if (chunkLen < 0) { // format error? -#endif - break; - } - bool truncated = (dataptr + 8 + chunkLen > dataend); - - if (strncmp((char *)dataptr, "BMHD", 4) == 0) { // BMHD chunk? - if (chunkLen < 12 + 2 || truncated) { - break; - } - bmhd_width = iff_getword(dataptr + 8); // width of picture - bmhd_height= iff_getword(dataptr + 8 + 2); // height of picture - bmhd_bitplanes = *(dataptr + 8 + 8); // # of bitplanes - bmhd_masking = *(dataptr + 8 + 9); - bmhd_compression = *(dataptr + 8 + 10); // get compression - bmhd_transcol = iff_getword(dataptr + 8 + 12); - BMHDok = true; // got BMHD - dataptr += 8 + chunkLen; // to next chunk - } - else if (strncmp((char *)dataptr, "CMAP", 4) == 0) { // CMAP ? - if (truncated) { - break; - } - const byte *cmapptr = dataptr + 8; - colors = chunkLen / 3; // calc no of colors - - delete m_image->pal; - m_image->pal = 0; - m_image->colors = colors; - if (colors > 0) { - m_image->pal = new byte[3*colors]; - if (!m_image->pal) { - Destroy(); - return wxIFF_MEMERR; - } - - // copy colors to color map - for (int i=0; i < colors; i++) { - m_image->pal[3*i + 0] = *cmapptr++; - m_image->pal[3*i + 1] = *cmapptr++; - m_image->pal[3*i + 2] = *cmapptr++; - } - } - - wxLogTrace(_T("iff"), _T("Read %d colors from IFF file."), - colors); - - CMAPok = true; // got CMAP - dataptr += 8 + chunkLen; // to next chunk - } else if (strncmp((char *)dataptr, "CAMG", 4) == 0) { // CAMG ? - if (chunkLen < 4 || truncated) { - break; - } - camg_viewmode = iff_getlong(dataptr + 8); // get viewmodes - CAMGok = true; // got CAMG - dataptr += 8 + chunkLen; // to next chunk - } - else if (strncmp((char *)dataptr, "BODY", 4) == 0) { // BODY ? - if (!BMHDok) { // BMHD found? - break; - } - const byte *bodyptr = dataptr + 8; // -> BODY data - - if (truncated) { - chunkLen = dataend - dataptr; - } - - // - // if BODY is compressed, allocate buffer for decrunched BODY - // and decompress it (run length encoding) - // - if (bmhd_compression == 1) { - // calc size of decrunch buffer - (size of the actual pic. - // decompressed in interleaved Amiga bitplane format) - - size_t decomp_bufsize = (((bmhd_width + 15) >> 4) << 1) - * bmhd_height * bmhd_bitplanes; - - if ((decomp_mem = new byte[decomp_bufsize]) == 0) { - Destroy(); - return wxIFF_MEMERR; - } - - decomprle(bodyptr, decomp_mem, chunkLen, decomp_bufsize); - bodyptr = decomp_mem; // -> uncompressed BODY - chunkLen = decomp_bufsize; - delete [] databuf; - databuf = 0; - } - - // the following determines the type of the ILBM file. - // it's either NORMAL, EHB, HAM, HAM8 or 24BIT - - int fmt = ILBM_NORMAL; // assume normal ILBM - if (bmhd_bitplanes == 24) { - fmt = ILBM_24BIT; - } else if (bmhd_bitplanes == 8) { - if (CAMGok && (camg_viewmode & 0x800)) { - fmt = ILBM_HAM8; - } - } else if ((bmhd_bitplanes > 5) && CAMGok) { - if (camg_viewmode & 0x80) { - fmt = ILBM_EHB; - } else if (camg_viewmode & 0x800) { - fmt = ILBM_HAM; - } - } - - wxLogTrace(_T("iff"), - _T("LoadIFF: %s %dx%d, planes=%d (%d cols), comp=%d"), - (fmt==ILBM_NORMAL) ? "Normal ILBM" : - (fmt==ILBM_HAM) ? "HAM ILBM" : - (fmt==ILBM_HAM8) ? "HAM8 ILBM" : - (fmt==ILBM_EHB) ? "EHB ILBM" : - (fmt==ILBM_24BIT) ? "24BIT ILBM" : "unknown ILBM", - bmhd_width, bmhd_height, bmhd_bitplanes, - 1< m_image->colors) { - byte *pal = new byte[colors*3]; - if (!pal) { - Destroy(); - return wxIFF_MEMERR; - } - int i; - for (i = 0; i < m_image->colors; i++) { - pal[3*i + 0] = m_image->pal[3*i + 0]; - pal[3*i + 1] = m_image->pal[3*i + 1]; - pal[3*i + 2] = m_image->pal[3*i + 2]; - } - for (; i < colors; i++) { - pal[3*i + 0] = 0; - pal[3*i + 1] = 0; - pal[3*i + 2] = 0; - } - delete m_image->pal; - m_image->pal = pal; - m_image->colors = colors; - } - - for (int i=0; i < colors; i++) { - m_image->pal[3*i + 0] = (m_image->pal[3*i + 0] >> 4) * 17; - m_image->pal[3*i + 1] = (m_image->pal[3*i + 1] >> 4) * 17; - m_image->pal[3*i + 2] = (m_image->pal[3*i + 2] >> 4) * 17; - } - } - - m_image->p = new byte[bmhd_width * bmhd_height * 3]; - byte *picptr = m_image->p; - if (!picptr) { - Destroy(); - return wxIFF_MEMERR; - } - - byte *pal = m_image->pal; - int lineskip = ((bmhd_width + 15) >> 4) << 1; - int height = chunkLen / (lineskip * bmhd_bitplanes); - - if (bmhd_height < height) { - height = bmhd_height; - } - - if (fmt == ILBM_HAM || fmt == ILBM_HAM8 || fmt == ILBM_24BIT) { - byte *pic = picptr; - const byte *workptr = bodyptr; - - for (int i=0; i < height; i++) { - byte bitmsk = 0x80; - const byte *workptr2 = workptr; - - // at start of each line, init RGB values to background - byte rval = pal[0]; - byte gval = pal[1]; - byte bval = pal[2]; - - for (int j=0; j < bmhd_width; j++) { - long col = 0; - long colbit = 1; - const byte *workptr3 = workptr2; - for (int k=0; k < bmhd_bitplanes; k++) { - if (*workptr3 & bitmsk) { - col += colbit; - } - workptr3 += lineskip; - colbit <<= 1; - } - - if (fmt==ILBM_HAM) { - int c = (col & 0x0f); - switch (col & 0x30) { - case 0x00: if (c >= 0 && c < colors) { - rval = pal[3*c + 0]; - gval = pal[3*c + 1]; - bval = pal[3*c + 2]; - } - break; - - case 0x10: bval = c * 17; - break; - - case 0x20: rval = c * 17; - break; - - case 0x30: gval = c * 17; - break; - } - } else if (fmt == ILBM_HAM8) { - int c = (col & 0x3f); - switch(col & 0xc0) { - case 0x00: if (c >= 0 && c < colors) { - rval = pal[3*c + 0]; - gval = pal[3*c + 1]; - bval = pal[3*c + 2]; - } - break; - - case 0x40: bval = (bval & 3) | (c << 2); - break; - - case 0x80: rval = (rval & 3) | (c << 2); - break; - - case 0xc0: gval = (rval & 3) | (c << 2); - } - } else { - rval = col & 0xff; - gval = (col >> 8) & 0xff; - bval = (col >> 16) & 0xff; - } - - *pic++ = rval; - *pic++ = gval; - *pic++ = bval; - - bitmsk = bitmsk >> 1; - if (bitmsk == 0) { - bitmsk = 0x80; - workptr2++; - } - } - workptr += lineskip * bmhd_bitplanes; - } - } else if ((fmt == ILBM_NORMAL) || (fmt == ILBM_EHB)) { - if (fmt == ILBM_EHB) { - wxLogTrace(_T("iff"), _T("Doubling CMAP for EHB mode")); - - for (int i=0; i<32; i++) { - pal[3*(i + 32) + 0] = pal[3*i + 0] >> 1; - pal[3*(i + 32) + 1] = pal[3*i + 1] >> 1; - pal[3*(i + 32) + 2] = pal[3*i + 2] >> 1; - } - } - - byte *pic = picptr; // ptr to buffer - const byte *workptr = bodyptr; // ptr to pic, planar format - - if (bmhd_height < height) { - height = bmhd_height; - } - - for (int i=0; i < height; i++) { - byte bitmsk = 0x80; // left most bit (mask) - const byte *workptr2 = workptr; // work ptr to source - for (int j=0; j < bmhd_width; j++) { - long col = 0; - long colbit = 1; - const byte *workptr3 = workptr2; // 1st byte in 1st pln - - for (int k=0; k < bmhd_bitplanes; k++) { - if (*workptr3 & bitmsk) { // if bit set in this pln - col = col + colbit; // add bit to chunky byte - } - workptr3 += lineskip; // go to next line - colbit <<= 1; // shift color bit - } - - if (col >= 0 && col < colors) { - pic[0] = pal[3*col + 0]; - pic[1] = pal[3*col + 1]; - pic[2] = pal[3*col + 2]; - } else { - pic[0] = pic[1] = pic[2] = 0; - } - pic += 3; - bitmsk = bitmsk >> 1; // shift mask to next bit - if (bitmsk == 0) { // if mask is zero - bitmsk = 0x80; // reset mask - workptr2++; // mv ptr to next byte - } - } - - workptr += lineskip * bmhd_bitplanes; // to next line - } - } else { - break; // unknown format - } - - m_image->w = bmhd_width; - m_image->h = height; - m_image->transparent = bmhd_transcol; - - wxLogTrace(_T("iff"), _T("Loaded IFF picture %s"), - truncated? "truncated" : "completely"); - - return (truncated? wxIFF_TRUNCATED : wxIFF_OK); - } else { - wxLogTrace(_T("iff"), _T("Skipping unknown chunk '%c%c%c%c'"), - *dataptr, *(dataptr+1), *(dataptr+2), *(dataptr+3)); - - dataptr = dataptr + 8 + chunkLen; // skip unknown chunk - } - } - - Destroy(); - return wxIFF_INVFORMAT; -} - - - -//----------------------------------------------------------------------------- -// wxIFFHandler -//----------------------------------------------------------------------------- - -IMPLEMENT_DYNAMIC_CLASS(wxIFFHandler, wxImageHandler) - -#if wxUSE_STREAMS - -bool wxIFFHandler::LoadFile(wxImage *image, wxInputStream& stream, - bool verbose, int WXUNUSED(index)) -{ - wxIFFDecoder *decod; - int error; - bool ok; - - decod = new wxIFFDecoder(&stream); - error = decod->ReadIFF(); - - if ((error != wxIFF_OK) && (error != wxIFF_TRUNCATED)) - { - if (verbose) - { - switch (error) - { - case wxIFF_INVFORMAT: - wxLogError(_("IFF: error in IFF image format.")); - break; - case wxIFF_MEMERR: - wxLogError(_("IFF: not enough memory.")); - break; - default: - wxLogError(_("IFF: unknown error!!!")); - break; - } - } - delete decod; - return false; - } - - if ((error == wxIFF_TRUNCATED) && verbose) - { - wxLogError(_("IFF: data stream seems to be truncated.")); - /* go on; image data is OK */ - } - - ok = decod->ConvertToImage(image); - delete decod; - - return ok; -} - -bool wxIFFHandler::SaveFile(wxImage * WXUNUSED(image), - wxOutputStream& WXUNUSED(stream), bool verbose) -{ - if (verbose) - wxLogDebug(wxT("IFF: the handler is read-only!!")); - - return false; -} - -bool wxIFFHandler::DoCanRead(wxInputStream& stream) -{ - wxIFFDecoder decod(&stream); - - return decod.CanRead(); -} - -#endif // wxUSE_STREAMS - -#endif // wxUSE_IFF +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/imagiff.h +// Purpose: wxImage handler for Amiga IFF images +// Author: Steffen Gutmann, Thomas Meyer +// RCS-ID: $Id: imagiff.cpp 38787 2006-04-18 07:24:35Z ABX $ +// Copyright: (c) Steffen Gutmann, 2002 +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// Parts of this source are based on the iff loading algorithm found +// in xviff.c. Permission by the original author, Thomas Meyer, and +// by the author of xv, John Bradley for using the iff loading part +// in wxWidgets has been gratefully given. + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_IMAGE && wxUSE_IFF + +#ifndef WX_PRECOMP + #include "wx/log.h" + #include "wx/intl.h" +#endif + +#include "wx/imagiff.h" +#include "wx/wfstream.h" + +#if wxUSE_PALETTE + #include "wx/palette.h" +#endif // wxUSE_PALETTE + +#include +#include + + +// -------------------------------------------------------------------------- +// Constants +// -------------------------------------------------------------------------- + +// Error codes: +// Note that the error code wxIFF_TRUNCATED means that the image itself +// is most probably OK, but the decoder didn't reach the end of the data +// stream; this means that if it was not reading directly from file, +// the stream will not be correctly positioned. +// + +enum +{ + wxIFF_OK = 0, /* everything was OK */ + wxIFF_INVFORMAT, /* error in iff header */ + wxIFF_MEMERR, /* error allocating memory */ + wxIFF_TRUNCATED /* file appears to be truncated */ +}; + +// -------------------------------------------------------------------------- +// wxIFFDecoder class +// -------------------------------------------------------------------------- + +// internal class for storing IFF image data +class IFFImage +{ +public: + unsigned int w; /* width */ + unsigned int h; /* height */ + int transparent; /* transparent color (-1 = none) */ + int colors; /* number of colors */ + unsigned char *p; /* bitmap */ + unsigned char *pal; /* palette */ + + IFFImage() : w(0), h(0), colors(0), p(0), pal(0) {} + ~IFFImage() { delete [] p; delete [] pal; } +}; + +class WXDLLEXPORT wxIFFDecoder +{ +private: + IFFImage *m_image; // image data + wxInputStream *m_f; // input stream + unsigned char *databuf; + unsigned char *picptr; + unsigned char *decomp_mem; + + void Destroy(); + +public: + // get data of current frame + unsigned char* GetData() const; + unsigned char* GetPalette() const; + int GetNumColors() const; + unsigned int GetWidth() const; + unsigned int GetHeight() const; + int GetTransparentColour() const; + + // constructor, destructor, etc. + wxIFFDecoder(wxInputStream *s); + ~wxIFFDecoder() { Destroy(); } + bool CanRead(); + int ReadIFF(); + bool ConvertToImage(wxImage *image) const; +}; + + +//--------------------------------------------------------------------------- +// wxIFFDecoder constructor and destructor +//--------------------------------------------------------------------------- + +wxIFFDecoder::wxIFFDecoder(wxInputStream *s) +{ + m_f = s; + m_image = 0; + databuf = 0; + decomp_mem = 0; +} + +void wxIFFDecoder::Destroy() +{ + delete m_image; + m_image = 0; + delete [] databuf; + databuf = 0; + delete [] decomp_mem; + decomp_mem = 0; +} + +//--------------------------------------------------------------------------- +// Convert this image to a wxImage object +//--------------------------------------------------------------------------- + +// This function was designed by Vaclav Slavik + +bool wxIFFDecoder::ConvertToImage(wxImage *image) const +{ + // just in case... + image->Destroy(); + + // create the image + image->Create(GetWidth(), GetHeight()); + + if (!image->Ok()) + return false; + + unsigned char *pal = GetPalette(); + unsigned char *src = GetData(); + unsigned char *dst = image->GetData(); + int colors = GetNumColors(); + int transparent = GetTransparentColour(); + long i; + + // set transparent colour mask + if (transparent != -1) + { + for (i = 0; i < colors; i++) + { + if ((pal[3 * i + 0] == 255) && + (pal[3 * i + 1] == 0) && + (pal[3 * i + 2] == 255)) + { + pal[3 * i + 2] = 254; + } + } + + pal[3 * transparent + 0] = 255, + pal[3 * transparent + 1] = 0, + pal[3 * transparent + 2] = 255; + + image->SetMaskColour(255, 0, 255); + } + else + image->SetMask(false); + +#if wxUSE_PALETTE + if (pal && colors > 0) + { + unsigned char* r = new unsigned char[colors]; + unsigned char* g = new unsigned char[colors]; + unsigned char* b = new unsigned char[colors]; + + for (i = 0; i < colors; i++) + { + r[i] = pal[3*i + 0]; + g[i] = pal[3*i + 1]; + b[i] = pal[3*i + 2]; + } + + image->SetPalette(wxPalette(colors, r, g, b)); + + delete [] r; + delete [] g; + delete [] b; + } +#endif // wxUSE_PALETTE + + // copy image data + for (i = 0; i < (long)(GetWidth() * GetHeight()); i++, src += 3, dst += 3) + { + dst[0] = src[0]; + dst[1] = src[1]; + dst[2] = src[2]; + } + + return true; +} + + +//--------------------------------------------------------------------------- +// Data accessors +//--------------------------------------------------------------------------- + +// Get data for current frame + +unsigned char* wxIFFDecoder::GetData() const { return (m_image->p); } +unsigned char* wxIFFDecoder::GetPalette() const { return (m_image->pal); } +int wxIFFDecoder::GetNumColors() const { return m_image->colors; } +unsigned int wxIFFDecoder::GetWidth() const { return (m_image->w); } +unsigned int wxIFFDecoder::GetHeight() const { return (m_image->h); } +int wxIFFDecoder::GetTransparentColour() const { return m_image->transparent; } + +//--------------------------------------------------------------------------- +// IFF reading and decoding +//--------------------------------------------------------------------------- + +// +// CanRead: +// Returns true if the file looks like a valid IFF, false otherwise. +// +bool wxIFFDecoder::CanRead() +{ + unsigned char buf[12]; + + if ( !m_f->Read(buf, WXSIZEOF(buf)) ) + return false; + + m_f->SeekI(-(wxFileOffset)WXSIZEOF(buf), wxFromCurrent); + + return (memcmp(buf, "FORM", 4) == 0) && (memcmp(buf+8, "ILBM", 4) == 0); +} + + +// ReadIFF: +// Based on xv source code by Thomas Meyer +// Permission for use in wxWidgets has been gratefully given. + +typedef unsigned char byte; +#define IFFDEBUG 0 + +/************************************************************************* + void decomprle(source, destination, source length, buffer size) + + Decompress run-length encoded data from source to destination. Terminates + when source is decoded completely or destination buffer is full. + + The decruncher is as optimized as I could make it, without risking + safety in case of corrupt BODY chunks. +**************************************************************************/ + +static void decomprle(const byte *sptr, byte *dptr, long slen, long dlen) +{ + byte codeByte, dataByte; + + while ((slen > 0) && (dlen > 0)) { + // read control byte + codeByte = *sptr++; + + if (codeByte < 0x80) { + codeByte++; + if ((slen > (long) codeByte) && (dlen >= (long) codeByte)) { + slen -= codeByte + 1; + dlen -= codeByte; + while (codeByte > 0) { + *dptr++ = *sptr++; + codeByte--; + } + } + else slen = 0; + } + + else if (codeByte > 0x80) { + codeByte = 0x81 - (codeByte & 0x7f); + if ((slen > (long) 0) && (dlen >= (long) codeByte)) { + dataByte = *sptr++; + slen -= 2; + dlen -= codeByte; + while (codeByte > 0) { + *dptr++ = dataByte; + codeByte--; + } + } + else slen = 0; + } + } +} + +/******************************************/ +static unsigned int iff_getword(const byte *ptr) +{ + unsigned int v; + + v = *ptr++; + v = (v << 8) + *ptr; + return v; +} + +/******************************************/ +static unsigned long iff_getlong(const byte *ptr) +{ + unsigned long l; + + l = *ptr++; + l = (l << 8) + *ptr++; + l = (l << 8) + *ptr++; + l = (l << 8) + *ptr; + return l; +} + +// Define internal ILBM types +#define ILBM_NORMAL 0 +#define ILBM_EHB 1 +#define ILBM_HAM 2 +#define ILBM_HAM8 3 +#define ILBM_24BIT 4 + +int wxIFFDecoder::ReadIFF() +{ + Destroy(); + + m_image = new IFFImage(); + if (m_image == 0) { + Destroy(); + return wxIFF_MEMERR; + } + + // compute file length + wxFileOffset currentPos = m_f->TellI(); + m_f->SeekI(0, wxFromEnd); + long filesize = m_f->TellI(); + m_f->SeekI(currentPos, wxFromStart); + + // allocate memory for complete file + if ((databuf = new byte[filesize]) == 0) { + Destroy(); + return wxIFF_MEMERR; + } + + m_f->Read(databuf, filesize); + const byte *dataend = databuf + filesize; + + // initialize work pointer. used to trace the buffer for IFF chunks + const byte *dataptr = databuf; + + // check for minmal size + if (dataptr + 12 > dataend) { + Destroy(); + return wxIFF_INVFORMAT; + } + + // check if we really got an IFF file + if (strncmp((char *)dataptr, "FORM", 4) != 0) { + Destroy(); + return wxIFF_INVFORMAT; + } + + dataptr = dataptr + 8; // skip ID and length of FORM + + // check if the IFF file is an ILBM (picture) file + if (strncmp((char *) dataptr, "ILBM", 4) != 0) { + Destroy(); + return wxIFF_INVFORMAT; + } + + wxLogTrace(_T("iff"), _T("IFF ILBM file recognized")); + + dataptr = dataptr + 4; // skip ID + + // + // main decoding loop. searches IFF chunks and handles them. + // terminates when BODY chunk was found or dataptr ran over end of file + // + bool BMHDok = false, CMAPok = false, CAMGok = false; + int bmhd_width = 0, bmhd_height = 0, bmhd_bitplanes = 0, bmhd_transcol = -1; + byte bmhd_masking = 0, bmhd_compression = 0; + long camg_viewmode = 0; + int colors = 0; + while (dataptr + 8 <= dataend) { + // get chunk length and make even + size_t chunkLen = (iff_getlong(dataptr + 4) + 1) & 0xfffffffe; +#ifdef __VMS + // Silence compiler warning + int chunkLen_; + chunkLen_ = chunkLen; + if (chunkLen_ < 0) { // format error? +#else + if (chunkLen < 0) { // format error? +#endif + break; + } + bool truncated = (dataptr + 8 + chunkLen > dataend); + + if (strncmp((char *)dataptr, "BMHD", 4) == 0) { // BMHD chunk? + if (chunkLen < 12 + 2 || truncated) { + break; + } + bmhd_width = iff_getword(dataptr + 8); // width of picture + bmhd_height= iff_getword(dataptr + 8 + 2); // height of picture + bmhd_bitplanes = *(dataptr + 8 + 8); // # of bitplanes + bmhd_masking = *(dataptr + 8 + 9); + bmhd_compression = *(dataptr + 8 + 10); // get compression + bmhd_transcol = iff_getword(dataptr + 8 + 12); + BMHDok = true; // got BMHD + dataptr += 8 + chunkLen; // to next chunk + } + else if (strncmp((char *)dataptr, "CMAP", 4) == 0) { // CMAP ? + if (truncated) { + break; + } + const byte *cmapptr = dataptr + 8; + colors = chunkLen / 3; // calc no of colors + + delete m_image->pal; + m_image->pal = 0; + m_image->colors = colors; + if (colors > 0) { + m_image->pal = new byte[3*colors]; + if (!m_image->pal) { + Destroy(); + return wxIFF_MEMERR; + } + + // copy colors to color map + for (int i=0; i < colors; i++) { + m_image->pal[3*i + 0] = *cmapptr++; + m_image->pal[3*i + 1] = *cmapptr++; + m_image->pal[3*i + 2] = *cmapptr++; + } + } + + wxLogTrace(_T("iff"), _T("Read %d colors from IFF file."), + colors); + + CMAPok = true; // got CMAP + dataptr += 8 + chunkLen; // to next chunk + } else if (strncmp((char *)dataptr, "CAMG", 4) == 0) { // CAMG ? + if (chunkLen < 4 || truncated) { + break; + } + camg_viewmode = iff_getlong(dataptr + 8); // get viewmodes + CAMGok = true; // got CAMG + dataptr += 8 + chunkLen; // to next chunk + } + else if (strncmp((char *)dataptr, "BODY", 4) == 0) { // BODY ? + if (!BMHDok) { // BMHD found? + break; + } + const byte *bodyptr = dataptr + 8; // -> BODY data + + if (truncated) { + chunkLen = dataend - dataptr; + } + + // + // if BODY is compressed, allocate buffer for decrunched BODY + // and decompress it (run length encoding) + // + if (bmhd_compression == 1) { + // calc size of decrunch buffer - (size of the actual pic. + // decompressed in interleaved Amiga bitplane format) + + size_t decomp_bufsize = (((bmhd_width + 15) >> 4) << 1) + * bmhd_height * bmhd_bitplanes; + + if ((decomp_mem = new byte[decomp_bufsize]) == 0) { + Destroy(); + return wxIFF_MEMERR; + } + + decomprle(bodyptr, decomp_mem, chunkLen, decomp_bufsize); + bodyptr = decomp_mem; // -> uncompressed BODY + chunkLen = decomp_bufsize; + delete [] databuf; + databuf = 0; + } + + // the following determines the type of the ILBM file. + // it's either NORMAL, EHB, HAM, HAM8 or 24BIT + + int fmt = ILBM_NORMAL; // assume normal ILBM + if (bmhd_bitplanes == 24) { + fmt = ILBM_24BIT; + } else if (bmhd_bitplanes == 8) { + if (CAMGok && (camg_viewmode & 0x800)) { + fmt = ILBM_HAM8; + } + } else if ((bmhd_bitplanes > 5) && CAMGok) { + if (camg_viewmode & 0x80) { + fmt = ILBM_EHB; + } else if (camg_viewmode & 0x800) { + fmt = ILBM_HAM; + } + } + + wxLogTrace(_T("iff"), + _T("LoadIFF: %s %dx%d, planes=%d (%d cols), comp=%d"), + (fmt==ILBM_NORMAL) ? "Normal ILBM" : + (fmt==ILBM_HAM) ? "HAM ILBM" : + (fmt==ILBM_HAM8) ? "HAM8 ILBM" : + (fmt==ILBM_EHB) ? "EHB ILBM" : + (fmt==ILBM_24BIT) ? "24BIT ILBM" : "unknown ILBM", + bmhd_width, bmhd_height, bmhd_bitplanes, + 1< m_image->colors) { + byte *pal = new byte[colors*3]; + if (!pal) { + Destroy(); + return wxIFF_MEMERR; + } + int i; + for (i = 0; i < m_image->colors; i++) { + pal[3*i + 0] = m_image->pal[3*i + 0]; + pal[3*i + 1] = m_image->pal[3*i + 1]; + pal[3*i + 2] = m_image->pal[3*i + 2]; + } + for (; i < colors; i++) { + pal[3*i + 0] = 0; + pal[3*i + 1] = 0; + pal[3*i + 2] = 0; + } + delete m_image->pal; + m_image->pal = pal; + m_image->colors = colors; + } + + for (int i=0; i < colors; i++) { + m_image->pal[3*i + 0] = (m_image->pal[3*i + 0] >> 4) * 17; + m_image->pal[3*i + 1] = (m_image->pal[3*i + 1] >> 4) * 17; + m_image->pal[3*i + 2] = (m_image->pal[3*i + 2] >> 4) * 17; + } + } + + m_image->p = new byte[bmhd_width * bmhd_height * 3]; + byte *picptr = m_image->p; + if (!picptr) { + Destroy(); + return wxIFF_MEMERR; + } + + byte *pal = m_image->pal; + int lineskip = ((bmhd_width + 15) >> 4) << 1; + int height = chunkLen / (lineskip * bmhd_bitplanes); + + if (bmhd_height < height) { + height = bmhd_height; + } + + if (fmt == ILBM_HAM || fmt == ILBM_HAM8 || fmt == ILBM_24BIT) { + byte *pic = picptr; + const byte *workptr = bodyptr; + + for (int i=0; i < height; i++) { + byte bitmsk = 0x80; + const byte *workptr2 = workptr; + + // at start of each line, init RGB values to background + byte rval = pal[0]; + byte gval = pal[1]; + byte bval = pal[2]; + + for (int j=0; j < bmhd_width; j++) { + long col = 0; + long colbit = 1; + const byte *workptr3 = workptr2; + for (int k=0; k < bmhd_bitplanes; k++) { + if (*workptr3 & bitmsk) { + col += colbit; + } + workptr3 += lineskip; + colbit <<= 1; + } + + if (fmt==ILBM_HAM) { + int c = (col & 0x0f); + switch (col & 0x30) { + case 0x00: if (c >= 0 && c < colors) { + rval = pal[3*c + 0]; + gval = pal[3*c + 1]; + bval = pal[3*c + 2]; + } + break; + + case 0x10: bval = c * 17; + break; + + case 0x20: rval = c * 17; + break; + + case 0x30: gval = c * 17; + break; + } + } else if (fmt == ILBM_HAM8) { + int c = (col & 0x3f); + switch(col & 0xc0) { + case 0x00: if (c >= 0 && c < colors) { + rval = pal[3*c + 0]; + gval = pal[3*c + 1]; + bval = pal[3*c + 2]; + } + break; + + case 0x40: bval = (bval & 3) | (c << 2); + break; + + case 0x80: rval = (rval & 3) | (c << 2); + break; + + case 0xc0: gval = (rval & 3) | (c << 2); + } + } else { + rval = col & 0xff; + gval = (col >> 8) & 0xff; + bval = (col >> 16) & 0xff; + } + + *pic++ = rval; + *pic++ = gval; + *pic++ = bval; + + bitmsk = bitmsk >> 1; + if (bitmsk == 0) { + bitmsk = 0x80; + workptr2++; + } + } + workptr += lineskip * bmhd_bitplanes; + } + } else if ((fmt == ILBM_NORMAL) || (fmt == ILBM_EHB)) { + if (fmt == ILBM_EHB) { + wxLogTrace(_T("iff"), _T("Doubling CMAP for EHB mode")); + + for (int i=0; i<32; i++) { + pal[3*(i + 32) + 0] = pal[3*i + 0] >> 1; + pal[3*(i + 32) + 1] = pal[3*i + 1] >> 1; + pal[3*(i + 32) + 2] = pal[3*i + 2] >> 1; + } + } + + byte *pic = picptr; // ptr to buffer + const byte *workptr = bodyptr; // ptr to pic, planar format + + if (bmhd_height < height) { + height = bmhd_height; + } + + for (int i=0; i < height; i++) { + byte bitmsk = 0x80; // left most bit (mask) + const byte *workptr2 = workptr; // work ptr to source + for (int j=0; j < bmhd_width; j++) { + long col = 0; + long colbit = 1; + const byte *workptr3 = workptr2; // 1st byte in 1st pln + + for (int k=0; k < bmhd_bitplanes; k++) { + if (*workptr3 & bitmsk) { // if bit set in this pln + col = col + colbit; // add bit to chunky byte + } + workptr3 += lineskip; // go to next line + colbit <<= 1; // shift color bit + } + + if (col >= 0 && col < colors) { + pic[0] = pal[3*col + 0]; + pic[1] = pal[3*col + 1]; + pic[2] = pal[3*col + 2]; + } else { + pic[0] = pic[1] = pic[2] = 0; + } + pic += 3; + bitmsk = bitmsk >> 1; // shift mask to next bit + if (bitmsk == 0) { // if mask is zero + bitmsk = 0x80; // reset mask + workptr2++; // mv ptr to next byte + } + } + + workptr += lineskip * bmhd_bitplanes; // to next line + } + } else { + break; // unknown format + } + + m_image->w = bmhd_width; + m_image->h = height; + m_image->transparent = bmhd_transcol; + + wxLogTrace(_T("iff"), _T("Loaded IFF picture %s"), + truncated? "truncated" : "completely"); + + return (truncated? wxIFF_TRUNCATED : wxIFF_OK); + } else { + wxLogTrace(_T("iff"), _T("Skipping unknown chunk '%c%c%c%c'"), + *dataptr, *(dataptr+1), *(dataptr+2), *(dataptr+3)); + + dataptr = dataptr + 8 + chunkLen; // skip unknown chunk + } + } + + Destroy(); + return wxIFF_INVFORMAT; +} + + + +//----------------------------------------------------------------------------- +// wxIFFHandler +//----------------------------------------------------------------------------- + +IMPLEMENT_DYNAMIC_CLASS(wxIFFHandler, wxImageHandler) + +#if wxUSE_STREAMS + +bool wxIFFHandler::LoadFile(wxImage *image, wxInputStream& stream, + bool verbose, int WXUNUSED(index)) +{ + wxIFFDecoder *decod; + int error; + bool ok; + + decod = new wxIFFDecoder(&stream); + error = decod->ReadIFF(); + + if ((error != wxIFF_OK) && (error != wxIFF_TRUNCATED)) + { + if (verbose) + { + switch (error) + { + case wxIFF_INVFORMAT: + wxLogError(_("IFF: error in IFF image format.")); + break; + case wxIFF_MEMERR: + wxLogError(_("IFF: not enough memory.")); + break; + default: + wxLogError(_("IFF: unknown error!!!")); + break; + } + } + delete decod; + return false; + } + + if ((error == wxIFF_TRUNCATED) && verbose) + { + wxLogError(_("IFF: data stream seems to be truncated.")); + /* go on; image data is OK */ + } + + ok = decod->ConvertToImage(image); + delete decod; + + return ok; +} + +bool wxIFFHandler::SaveFile(wxImage * WXUNUSED(image), + wxOutputStream& WXUNUSED(stream), bool verbose) +{ + if (verbose) + wxLogDebug(wxT("IFF: the handler is read-only!!")); + + return false; +} + +bool wxIFFHandler::DoCanRead(wxInputStream& stream) +{ + wxIFFDecoder decod(&stream); + + return decod.CanRead(); +} + +#endif // wxUSE_STREAMS + +#endif // wxUSE_IFF diff --git a/Externals/wxWidgets/src/common/imagjpeg.cpp b/Externals/wxWidgets/src/common/imagjpeg.cpp index a247d70915..9fb2d4e699 100644 --- a/Externals/wxWidgets/src/common/imagjpeg.cpp +++ b/Externals/wxWidgets/src/common/imagjpeg.cpp @@ -1,480 +1,480 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/imagjpeg.cpp -// Purpose: wxImage JPEG handler -// Author: Vaclav Slavik -// RCS-ID: $Id: imagjpeg.cpp 43781 2006-12-03 21:59:47Z MW $ -// Copyright: (c) Vaclav Slavik -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_IMAGE && wxUSE_LIBJPEG - -#include "wx/imagjpeg.h" - -#ifndef WX_PRECOMP - #include "wx/log.h" - #include "wx/app.h" - #include "wx/intl.h" - #include "wx/bitmap.h" - #include "wx/module.h" -#endif - -// A hack based on one from tif_jpeg.c to overcome the problem on Windows -// of rpcndr.h defining boolean with a different type to the jpeg headers. -// -// This hack is only necessary for an external jpeg library, the builtin one -// usually used on Windows doesn't use the type boolean, so always works. -// -#ifdef wxHACK_BOOLEAN - #define HAVE_BOOLEAN - #define boolean wxHACK_BOOLEAN -#endif - -extern "C" -{ - #if defined(__WXMSW__) - #define XMD_H - #endif - #include "jpeglib.h" -} - -#ifndef HAVE_WXJPEG_BOOLEAN -typedef boolean wxjpeg_boolean; -#endif - -#include "wx/filefn.h" -#include "wx/wfstream.h" - -// For memcpy -#include -// For JPEG library error handling -#include - -#ifdef __SALFORDC__ -#undef FAR -#endif - -// ---------------------------------------------------------------------------- -// types -// ---------------------------------------------------------------------------- - -// the standard definition of METHODDEF(type) from jmorecfg.h is "static type" -// which means that we can't declare the method functions as extern "C" - the -// compiler (rightfully) complains about the multiple storage classes in -// declaration -// -// so we only add extern "C" when using our own, modified, jmorecfg.h - and use -// whatever we have in the system headers if this is what we use hoping that it -// should be ok (can't do anything else) -#ifdef JPEG_METHOD_LINKAGE - #define CPP_METHODDEF(type) extern "C" METHODDEF(type) -#else // not using our jmorecfg.h header - #define CPP_METHODDEF(type) METHODDEF(type) -#endif - -//----------------------------------------------------------------------------- -// wxJPEGHandler -//----------------------------------------------------------------------------- - -IMPLEMENT_DYNAMIC_CLASS(wxJPEGHandler,wxImageHandler) - -#if wxUSE_STREAMS - -//------------- JPEG Data Source Manager - -#define JPEG_IO_BUFFER_SIZE 2048 - -typedef struct { - struct jpeg_source_mgr pub; /* public fields */ - - JOCTET* buffer; /* start of buffer */ - wxInputStream *stream; -} wx_source_mgr; - -typedef wx_source_mgr * wx_src_ptr; - -CPP_METHODDEF(void) wx_init_source ( j_decompress_ptr WXUNUSED(cinfo) ) -{ -} - -CPP_METHODDEF(wxjpeg_boolean) wx_fill_input_buffer ( j_decompress_ptr cinfo ) -{ - wx_src_ptr src = (wx_src_ptr) cinfo->src; - - src->pub.next_input_byte = src->buffer; - src->pub.bytes_in_buffer = src->stream->Read(src->buffer, JPEG_IO_BUFFER_SIZE).LastRead(); - - if (src->pub.bytes_in_buffer == 0) // check for end-of-stream - { - // Insert a fake EOI marker - src->buffer[0] = 0xFF; - src->buffer[1] = JPEG_EOI; - src->pub.bytes_in_buffer = 2; - } - return TRUE; -} - -CPP_METHODDEF(void) wx_skip_input_data ( j_decompress_ptr cinfo, long num_bytes ) -{ - if (num_bytes > 0) - { - wx_src_ptr src = (wx_src_ptr) cinfo->src; - - while (num_bytes > (long)src->pub.bytes_in_buffer) - { - num_bytes -= (long) src->pub.bytes_in_buffer; - src->pub.fill_input_buffer(cinfo); - } - src->pub.next_input_byte += (size_t) num_bytes; - src->pub.bytes_in_buffer -= (size_t) num_bytes; - } -} - -CPP_METHODDEF(void) wx_term_source ( j_decompress_ptr cinfo ) -{ - wx_src_ptr src = (wx_src_ptr) cinfo->src; - - if (src->pub.bytes_in_buffer > 0) - src->stream->SeekI(-(long)src->pub.bytes_in_buffer, wxFromCurrent); - delete[] src->buffer; -} - - -// JPEG error manager: - -struct wx_error_mgr { - struct jpeg_error_mgr pub; /* "public" fields */ - - jmp_buf setjmp_buffer; /* for return to caller */ -}; - -typedef struct wx_error_mgr * wx_error_ptr; - -/* - * Here's the routine that will replace the standard error_exit method: - */ - -CPP_METHODDEF(void) wx_error_exit (j_common_ptr cinfo) -{ - /* cinfo->err really points to a wx_error_mgr struct, so coerce pointer */ - wx_error_ptr myerr = (wx_error_ptr) cinfo->err; - - /* Always display the message. */ - /* We could postpone this until after returning, if we chose. */ - (*cinfo->err->output_message) (cinfo); - - /* Return control to the setjmp point */ - longjmp(myerr->setjmp_buffer, 1); -} - -/* - * This will replace the standard output_message method when the user - * wants us to be silent (verbose==false). We must have such method instead of - * simply using NULL for cinfo->err->output_message because it's called - * unconditionally from within libjpeg when there's "garbage input". - */ -CPP_METHODDEF(void) wx_ignore_message (j_common_ptr WXUNUSED(cinfo)) -{ -} - -void wx_jpeg_io_src( j_decompress_ptr cinfo, wxInputStream& infile ) -{ - wx_src_ptr src; - - if (cinfo->src == NULL) { /* first time for this JPEG object? */ - cinfo->src = (struct jpeg_source_mgr *) - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, - sizeof(wx_source_mgr)); - } - src = (wx_src_ptr) cinfo->src; - src->pub.bytes_in_buffer = 0; /* forces fill_input_buffer on first read */ - src->buffer = new JOCTET[JPEG_IO_BUFFER_SIZE]; - src->pub.next_input_byte = NULL; /* until buffer loaded */ - src->stream = &infile; - - src->pub.init_source = wx_init_source; - src->pub.fill_input_buffer = wx_fill_input_buffer; - src->pub.skip_input_data = wx_skip_input_data; - src->pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */ - src->pub.term_source = wx_term_source; -} - -static inline void wx_cmyk_to_rgb(unsigned char* rgb, const unsigned char* cmyk) -{ - register int k = 255 - cmyk[3]; - register int k2 = cmyk[3]; - register int c; - - c = k + k2 * (255 - cmyk[0]) / 255; - rgb[0] = (unsigned char)((c > 255) ? 0 : (255 - c)); - - c = k + k2 * (255 - cmyk[1]) / 255; - rgb[1] = (unsigned char)((c > 255) ? 0 : (255 - c)); - - c = k + k2 * (255 - cmyk[2]) / 255; - rgb[2] = (unsigned char)((c > 255) ? 0 : (255 - c)); -} - -// temporarily disable the warning C4611 (interaction between '_setjmp' and -// C++ object destruction is non-portable) - I don't see any dtors here -#ifdef __VISUALC__ - #pragma warning(disable:4611) -#endif /* VC++ */ - -bool wxJPEGHandler::LoadFile( wxImage *image, wxInputStream& stream, bool verbose, int WXUNUSED(index) ) -{ - struct jpeg_decompress_struct cinfo; - struct wx_error_mgr jerr; - unsigned char *ptr; - - image->Destroy(); - cinfo.err = jpeg_std_error( &jerr.pub ); - jerr.pub.error_exit = wx_error_exit; - - if (!verbose) - cinfo.err->output_message = wx_ignore_message; - - /* Establish the setjmp return context for wx_error_exit to use. */ - if (setjmp(jerr.setjmp_buffer)) { - /* If we get here, the JPEG code has signaled an error. - * We need to clean up the JPEG object, close the input file, and return. - */ - if (verbose) - wxLogError(_("JPEG: Couldn't load - file is probably corrupted.")); - (cinfo.src->term_source)(&cinfo); - jpeg_destroy_decompress(&cinfo); - if (image->Ok()) image->Destroy(); - return false; - } - - jpeg_create_decompress( &cinfo ); - wx_jpeg_io_src( &cinfo, stream ); - jpeg_read_header( &cinfo, TRUE ); - - int bytesPerPixel; - if ((cinfo.out_color_space == JCS_CMYK) || (cinfo.out_color_space == JCS_YCCK)) - { - cinfo.out_color_space = JCS_CMYK; - bytesPerPixel = 4; - } - else // all the rest is treated as RGB - { - cinfo.out_color_space = JCS_RGB; - bytesPerPixel = 3; - } - - jpeg_start_decompress( &cinfo ); - - image->Create( cinfo.image_width, cinfo.image_height ); - if (!image->Ok()) { - jpeg_finish_decompress( &cinfo ); - jpeg_destroy_decompress( &cinfo ); - return false; - } - image->SetMask( false ); - ptr = image->GetData(); - - unsigned stride = cinfo.output_width * bytesPerPixel; - JSAMPARRAY tempbuf = (*cinfo.mem->alloc_sarray) - ((j_common_ptr) &cinfo, JPOOL_IMAGE, stride, 1 ); - - while ( cinfo.output_scanline < cinfo.output_height ) - { - jpeg_read_scanlines( &cinfo, tempbuf, 1 ); - if (cinfo.out_color_space == JCS_RGB) - { - memcpy( ptr, tempbuf[0], stride ); - ptr += stride; - } - else // CMYK - { - const unsigned char* inptr = (const unsigned char*) tempbuf[0]; - for (size_t i = 0; i < cinfo.output_width; i++) - { - wx_cmyk_to_rgb(ptr, inptr); - ptr += 3; - inptr += 4; - } - } - } - - jpeg_finish_decompress( &cinfo ); - jpeg_destroy_decompress( &cinfo ); - return true; -} - -typedef struct { - struct jpeg_destination_mgr pub; - - wxOutputStream *stream; - JOCTET * buffer; -} wx_destination_mgr; - -typedef wx_destination_mgr * wx_dest_ptr; - -#define OUTPUT_BUF_SIZE 4096 /* choose an efficiently fwrite'able size */ - -CPP_METHODDEF(void) wx_init_destination (j_compress_ptr cinfo) -{ - wx_dest_ptr dest = (wx_dest_ptr) cinfo->dest; - - /* Allocate the output buffer --- it will be released when done with image */ - dest->buffer = (JOCTET *) - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, - OUTPUT_BUF_SIZE * sizeof(JOCTET)); - dest->pub.next_output_byte = dest->buffer; - dest->pub.free_in_buffer = OUTPUT_BUF_SIZE; -} - -CPP_METHODDEF(wxjpeg_boolean) wx_empty_output_buffer (j_compress_ptr cinfo) -{ - wx_dest_ptr dest = (wx_dest_ptr) cinfo->dest; - - dest->stream->Write(dest->buffer, OUTPUT_BUF_SIZE); - dest->pub.next_output_byte = dest->buffer; - dest->pub.free_in_buffer = OUTPUT_BUF_SIZE; - return TRUE; -} - -CPP_METHODDEF(void) wx_term_destination (j_compress_ptr cinfo) -{ - wx_dest_ptr dest = (wx_dest_ptr) cinfo->dest; - size_t datacount = OUTPUT_BUF_SIZE - dest->pub.free_in_buffer; - /* Write any data remaining in the buffer */ - if (datacount > 0) - dest->stream->Write(dest->buffer, datacount); -} - -GLOBAL(void) wx_jpeg_io_dest (j_compress_ptr cinfo, wxOutputStream& outfile) -{ - wx_dest_ptr dest; - - if (cinfo->dest == NULL) { /* first time for this JPEG object? */ - cinfo->dest = (struct jpeg_destination_mgr *) - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, - sizeof(wx_destination_mgr)); - } - - dest = (wx_dest_ptr) cinfo->dest; - dest->pub.init_destination = wx_init_destination; - dest->pub.empty_output_buffer = wx_empty_output_buffer; - dest->pub.term_destination = wx_term_destination; - dest->stream = &outfile; -} - -bool wxJPEGHandler::SaveFile( wxImage *image, wxOutputStream& stream, bool verbose ) -{ - struct jpeg_compress_struct cinfo; - struct wx_error_mgr jerr; - JSAMPROW row_pointer[1]; /* pointer to JSAMPLE row[s] */ - JSAMPLE *image_buffer; - int stride; /* physical row width in image buffer */ - - cinfo.err = jpeg_std_error(&jerr.pub); - jerr.pub.error_exit = wx_error_exit; - - if (!verbose) - cinfo.err->output_message = wx_ignore_message; - - /* Establish the setjmp return context for wx_error_exit to use. */ - if (setjmp(jerr.setjmp_buffer)) - { - /* If we get here, the JPEG code has signaled an error. - * We need to clean up the JPEG object, close the input file, and return. - */ - if (verbose) - wxLogError(_("JPEG: Couldn't save image.")); - jpeg_destroy_compress(&cinfo); - return false; - } - - jpeg_create_compress(&cinfo); - wx_jpeg_io_dest(&cinfo, stream); - - cinfo.image_width = image->GetWidth(); - cinfo.image_height = image->GetHeight(); - cinfo.input_components = 3; - cinfo.in_color_space = JCS_RGB; - jpeg_set_defaults(&cinfo); - - // TODO: 3rd parameter is force_baseline, what value should this be? - // Code says: "If force_baseline is TRUE, the computed quantization table entries - // are limited to 1..255 for JPEG baseline compatibility." - // 'Quality' is a number between 0 (terrible) and 100 (very good). - // The default (in jcparam.c, jpeg_set_defaults) is 75, - // and force_baseline is TRUE. - if (image->HasOption(wxIMAGE_OPTION_QUALITY)) - jpeg_set_quality(&cinfo, image->GetOptionInt(wxIMAGE_OPTION_QUALITY), TRUE); - - // set the resolution fields in the output file - UINT16 resX, - resY; - if ( image->HasOption(wxIMAGE_OPTION_RESOLUTIONX) && - image->HasOption(wxIMAGE_OPTION_RESOLUTIONY) ) - { - resX = (UINT16)image->GetOptionInt(wxIMAGE_OPTION_RESOLUTIONX); - resY = (UINT16)image->GetOptionInt(wxIMAGE_OPTION_RESOLUTIONY); - } - else if ( image->HasOption(wxIMAGE_OPTION_RESOLUTION) ) - { - resX = - resY = (UINT16)image->GetOptionInt(wxIMAGE_OPTION_RESOLUTION); - } - else - { - resX = - resY = 0; - } - - if ( resX && resY ) - { - cinfo.X_density = resX; - cinfo.Y_density = resY; - } - - // sets the resolution unit field in the output file - // wxIMAGE_RESOLUTION_INCHES for inches - // wxIMAGE_RESOLUTION_CM for centimeters - if ( image->HasOption(wxIMAGE_OPTION_RESOLUTIONUNIT) ) - { - cinfo.density_unit = (UINT8)image->GetOptionInt(wxIMAGE_OPTION_RESOLUTIONUNIT); - } - - jpeg_start_compress(&cinfo, TRUE); - - stride = cinfo.image_width * 3; /* JSAMPLEs per row in image_buffer */ - image_buffer = image->GetData(); - while (cinfo.next_scanline < cinfo.image_height) { - row_pointer[0] = &image_buffer[cinfo.next_scanline * stride]; - jpeg_write_scanlines( &cinfo, row_pointer, 1 ); - } - jpeg_finish_compress(&cinfo); - jpeg_destroy_compress(&cinfo); - - return true; -} - -#ifdef __VISUALC__ - #pragma warning(default:4611) -#endif /* VC++ */ - -bool wxJPEGHandler::DoCanRead( wxInputStream& stream ) -{ - unsigned char hdr[2]; - - if ( !stream.Read(hdr, WXSIZEOF(hdr)) ) - return false; - - return hdr[0] == 0xFF && hdr[1] == 0xD8; -} - -#endif // wxUSE_STREAMS - -#endif // wxUSE_LIBJPEG +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/imagjpeg.cpp +// Purpose: wxImage JPEG handler +// Author: Vaclav Slavik +// RCS-ID: $Id: imagjpeg.cpp 43781 2006-12-03 21:59:47Z MW $ +// Copyright: (c) Vaclav Slavik +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_IMAGE && wxUSE_LIBJPEG + +#include "wx/imagjpeg.h" + +#ifndef WX_PRECOMP + #include "wx/log.h" + #include "wx/app.h" + #include "wx/intl.h" + #include "wx/bitmap.h" + #include "wx/module.h" +#endif + +// A hack based on one from tif_jpeg.c to overcome the problem on Windows +// of rpcndr.h defining boolean with a different type to the jpeg headers. +// +// This hack is only necessary for an external jpeg library, the builtin one +// usually used on Windows doesn't use the type boolean, so always works. +// +#ifdef wxHACK_BOOLEAN + #define HAVE_BOOLEAN + #define boolean wxHACK_BOOLEAN +#endif + +extern "C" +{ + #if defined(__WXMSW__) + #define XMD_H + #endif + #include "jpeglib.h" +} + +#ifndef HAVE_WXJPEG_BOOLEAN +typedef boolean wxjpeg_boolean; +#endif + +#include "wx/filefn.h" +#include "wx/wfstream.h" + +// For memcpy +#include +// For JPEG library error handling +#include + +#ifdef __SALFORDC__ +#undef FAR +#endif + +// ---------------------------------------------------------------------------- +// types +// ---------------------------------------------------------------------------- + +// the standard definition of METHODDEF(type) from jmorecfg.h is "static type" +// which means that we can't declare the method functions as extern "C" - the +// compiler (rightfully) complains about the multiple storage classes in +// declaration +// +// so we only add extern "C" when using our own, modified, jmorecfg.h - and use +// whatever we have in the system headers if this is what we use hoping that it +// should be ok (can't do anything else) +#ifdef JPEG_METHOD_LINKAGE + #define CPP_METHODDEF(type) extern "C" METHODDEF(type) +#else // not using our jmorecfg.h header + #define CPP_METHODDEF(type) METHODDEF(type) +#endif + +//----------------------------------------------------------------------------- +// wxJPEGHandler +//----------------------------------------------------------------------------- + +IMPLEMENT_DYNAMIC_CLASS(wxJPEGHandler,wxImageHandler) + +#if wxUSE_STREAMS + +//------------- JPEG Data Source Manager + +#define JPEG_IO_BUFFER_SIZE 2048 + +typedef struct { + struct jpeg_source_mgr pub; /* public fields */ + + JOCTET* buffer; /* start of buffer */ + wxInputStream *stream; +} wx_source_mgr; + +typedef wx_source_mgr * wx_src_ptr; + +CPP_METHODDEF(void) wx_init_source ( j_decompress_ptr WXUNUSED(cinfo) ) +{ +} + +CPP_METHODDEF(wxjpeg_boolean) wx_fill_input_buffer ( j_decompress_ptr cinfo ) +{ + wx_src_ptr src = (wx_src_ptr) cinfo->src; + + src->pub.next_input_byte = src->buffer; + src->pub.bytes_in_buffer = src->stream->Read(src->buffer, JPEG_IO_BUFFER_SIZE).LastRead(); + + if (src->pub.bytes_in_buffer == 0) // check for end-of-stream + { + // Insert a fake EOI marker + src->buffer[0] = 0xFF; + src->buffer[1] = JPEG_EOI; + src->pub.bytes_in_buffer = 2; + } + return TRUE; +} + +CPP_METHODDEF(void) wx_skip_input_data ( j_decompress_ptr cinfo, long num_bytes ) +{ + if (num_bytes > 0) + { + wx_src_ptr src = (wx_src_ptr) cinfo->src; + + while (num_bytes > (long)src->pub.bytes_in_buffer) + { + num_bytes -= (long) src->pub.bytes_in_buffer; + src->pub.fill_input_buffer(cinfo); + } + src->pub.next_input_byte += (size_t) num_bytes; + src->pub.bytes_in_buffer -= (size_t) num_bytes; + } +} + +CPP_METHODDEF(void) wx_term_source ( j_decompress_ptr cinfo ) +{ + wx_src_ptr src = (wx_src_ptr) cinfo->src; + + if (src->pub.bytes_in_buffer > 0) + src->stream->SeekI(-(long)src->pub.bytes_in_buffer, wxFromCurrent); + delete[] src->buffer; +} + + +// JPEG error manager: + +struct wx_error_mgr { + struct jpeg_error_mgr pub; /* "public" fields */ + + jmp_buf setjmp_buffer; /* for return to caller */ +}; + +typedef struct wx_error_mgr * wx_error_ptr; + +/* + * Here's the routine that will replace the standard error_exit method: + */ + +CPP_METHODDEF(void) wx_error_exit (j_common_ptr cinfo) +{ + /* cinfo->err really points to a wx_error_mgr struct, so coerce pointer */ + wx_error_ptr myerr = (wx_error_ptr) cinfo->err; + + /* Always display the message. */ + /* We could postpone this until after returning, if we chose. */ + (*cinfo->err->output_message) (cinfo); + + /* Return control to the setjmp point */ + longjmp(myerr->setjmp_buffer, 1); +} + +/* + * This will replace the standard output_message method when the user + * wants us to be silent (verbose==false). We must have such method instead of + * simply using NULL for cinfo->err->output_message because it's called + * unconditionally from within libjpeg when there's "garbage input". + */ +CPP_METHODDEF(void) wx_ignore_message (j_common_ptr WXUNUSED(cinfo)) +{ +} + +void wx_jpeg_io_src( j_decompress_ptr cinfo, wxInputStream& infile ) +{ + wx_src_ptr src; + + if (cinfo->src == NULL) { /* first time for this JPEG object? */ + cinfo->src = (struct jpeg_source_mgr *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, + sizeof(wx_source_mgr)); + } + src = (wx_src_ptr) cinfo->src; + src->pub.bytes_in_buffer = 0; /* forces fill_input_buffer on first read */ + src->buffer = new JOCTET[JPEG_IO_BUFFER_SIZE]; + src->pub.next_input_byte = NULL; /* until buffer loaded */ + src->stream = &infile; + + src->pub.init_source = wx_init_source; + src->pub.fill_input_buffer = wx_fill_input_buffer; + src->pub.skip_input_data = wx_skip_input_data; + src->pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */ + src->pub.term_source = wx_term_source; +} + +static inline void wx_cmyk_to_rgb(unsigned char* rgb, const unsigned char* cmyk) +{ + register int k = 255 - cmyk[3]; + register int k2 = cmyk[3]; + register int c; + + c = k + k2 * (255 - cmyk[0]) / 255; + rgb[0] = (unsigned char)((c > 255) ? 0 : (255 - c)); + + c = k + k2 * (255 - cmyk[1]) / 255; + rgb[1] = (unsigned char)((c > 255) ? 0 : (255 - c)); + + c = k + k2 * (255 - cmyk[2]) / 255; + rgb[2] = (unsigned char)((c > 255) ? 0 : (255 - c)); +} + +// temporarily disable the warning C4611 (interaction between '_setjmp' and +// C++ object destruction is non-portable) - I don't see any dtors here +#ifdef __VISUALC__ + #pragma warning(disable:4611) +#endif /* VC++ */ + +bool wxJPEGHandler::LoadFile( wxImage *image, wxInputStream& stream, bool verbose, int WXUNUSED(index) ) +{ + struct jpeg_decompress_struct cinfo; + struct wx_error_mgr jerr; + unsigned char *ptr; + + image->Destroy(); + cinfo.err = jpeg_std_error( &jerr.pub ); + jerr.pub.error_exit = wx_error_exit; + + if (!verbose) + cinfo.err->output_message = wx_ignore_message; + + /* Establish the setjmp return context for wx_error_exit to use. */ + if (setjmp(jerr.setjmp_buffer)) { + /* If we get here, the JPEG code has signaled an error. + * We need to clean up the JPEG object, close the input file, and return. + */ + if (verbose) + wxLogError(_("JPEG: Couldn't load - file is probably corrupted.")); + (cinfo.src->term_source)(&cinfo); + jpeg_destroy_decompress(&cinfo); + if (image->Ok()) image->Destroy(); + return false; + } + + jpeg_create_decompress( &cinfo ); + wx_jpeg_io_src( &cinfo, stream ); + jpeg_read_header( &cinfo, TRUE ); + + int bytesPerPixel; + if ((cinfo.out_color_space == JCS_CMYK) || (cinfo.out_color_space == JCS_YCCK)) + { + cinfo.out_color_space = JCS_CMYK; + bytesPerPixel = 4; + } + else // all the rest is treated as RGB + { + cinfo.out_color_space = JCS_RGB; + bytesPerPixel = 3; + } + + jpeg_start_decompress( &cinfo ); + + image->Create( cinfo.image_width, cinfo.image_height ); + if (!image->Ok()) { + jpeg_finish_decompress( &cinfo ); + jpeg_destroy_decompress( &cinfo ); + return false; + } + image->SetMask( false ); + ptr = image->GetData(); + + unsigned stride = cinfo.output_width * bytesPerPixel; + JSAMPARRAY tempbuf = (*cinfo.mem->alloc_sarray) + ((j_common_ptr) &cinfo, JPOOL_IMAGE, stride, 1 ); + + while ( cinfo.output_scanline < cinfo.output_height ) + { + jpeg_read_scanlines( &cinfo, tempbuf, 1 ); + if (cinfo.out_color_space == JCS_RGB) + { + memcpy( ptr, tempbuf[0], stride ); + ptr += stride; + } + else // CMYK + { + const unsigned char* inptr = (const unsigned char*) tempbuf[0]; + for (size_t i = 0; i < cinfo.output_width; i++) + { + wx_cmyk_to_rgb(ptr, inptr); + ptr += 3; + inptr += 4; + } + } + } + + jpeg_finish_decompress( &cinfo ); + jpeg_destroy_decompress( &cinfo ); + return true; +} + +typedef struct { + struct jpeg_destination_mgr pub; + + wxOutputStream *stream; + JOCTET * buffer; +} wx_destination_mgr; + +typedef wx_destination_mgr * wx_dest_ptr; + +#define OUTPUT_BUF_SIZE 4096 /* choose an efficiently fwrite'able size */ + +CPP_METHODDEF(void) wx_init_destination (j_compress_ptr cinfo) +{ + wx_dest_ptr dest = (wx_dest_ptr) cinfo->dest; + + /* Allocate the output buffer --- it will be released when done with image */ + dest->buffer = (JOCTET *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + OUTPUT_BUF_SIZE * sizeof(JOCTET)); + dest->pub.next_output_byte = dest->buffer; + dest->pub.free_in_buffer = OUTPUT_BUF_SIZE; +} + +CPP_METHODDEF(wxjpeg_boolean) wx_empty_output_buffer (j_compress_ptr cinfo) +{ + wx_dest_ptr dest = (wx_dest_ptr) cinfo->dest; + + dest->stream->Write(dest->buffer, OUTPUT_BUF_SIZE); + dest->pub.next_output_byte = dest->buffer; + dest->pub.free_in_buffer = OUTPUT_BUF_SIZE; + return TRUE; +} + +CPP_METHODDEF(void) wx_term_destination (j_compress_ptr cinfo) +{ + wx_dest_ptr dest = (wx_dest_ptr) cinfo->dest; + size_t datacount = OUTPUT_BUF_SIZE - dest->pub.free_in_buffer; + /* Write any data remaining in the buffer */ + if (datacount > 0) + dest->stream->Write(dest->buffer, datacount); +} + +GLOBAL(void) wx_jpeg_io_dest (j_compress_ptr cinfo, wxOutputStream& outfile) +{ + wx_dest_ptr dest; + + if (cinfo->dest == NULL) { /* first time for this JPEG object? */ + cinfo->dest = (struct jpeg_destination_mgr *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, + sizeof(wx_destination_mgr)); + } + + dest = (wx_dest_ptr) cinfo->dest; + dest->pub.init_destination = wx_init_destination; + dest->pub.empty_output_buffer = wx_empty_output_buffer; + dest->pub.term_destination = wx_term_destination; + dest->stream = &outfile; +} + +bool wxJPEGHandler::SaveFile( wxImage *image, wxOutputStream& stream, bool verbose ) +{ + struct jpeg_compress_struct cinfo; + struct wx_error_mgr jerr; + JSAMPROW row_pointer[1]; /* pointer to JSAMPLE row[s] */ + JSAMPLE *image_buffer; + int stride; /* physical row width in image buffer */ + + cinfo.err = jpeg_std_error(&jerr.pub); + jerr.pub.error_exit = wx_error_exit; + + if (!verbose) + cinfo.err->output_message = wx_ignore_message; + + /* Establish the setjmp return context for wx_error_exit to use. */ + if (setjmp(jerr.setjmp_buffer)) + { + /* If we get here, the JPEG code has signaled an error. + * We need to clean up the JPEG object, close the input file, and return. + */ + if (verbose) + wxLogError(_("JPEG: Couldn't save image.")); + jpeg_destroy_compress(&cinfo); + return false; + } + + jpeg_create_compress(&cinfo); + wx_jpeg_io_dest(&cinfo, stream); + + cinfo.image_width = image->GetWidth(); + cinfo.image_height = image->GetHeight(); + cinfo.input_components = 3; + cinfo.in_color_space = JCS_RGB; + jpeg_set_defaults(&cinfo); + + // TODO: 3rd parameter is force_baseline, what value should this be? + // Code says: "If force_baseline is TRUE, the computed quantization table entries + // are limited to 1..255 for JPEG baseline compatibility." + // 'Quality' is a number between 0 (terrible) and 100 (very good). + // The default (in jcparam.c, jpeg_set_defaults) is 75, + // and force_baseline is TRUE. + if (image->HasOption(wxIMAGE_OPTION_QUALITY)) + jpeg_set_quality(&cinfo, image->GetOptionInt(wxIMAGE_OPTION_QUALITY), TRUE); + + // set the resolution fields in the output file + UINT16 resX, + resY; + if ( image->HasOption(wxIMAGE_OPTION_RESOLUTIONX) && + image->HasOption(wxIMAGE_OPTION_RESOLUTIONY) ) + { + resX = (UINT16)image->GetOptionInt(wxIMAGE_OPTION_RESOLUTIONX); + resY = (UINT16)image->GetOptionInt(wxIMAGE_OPTION_RESOLUTIONY); + } + else if ( image->HasOption(wxIMAGE_OPTION_RESOLUTION) ) + { + resX = + resY = (UINT16)image->GetOptionInt(wxIMAGE_OPTION_RESOLUTION); + } + else + { + resX = + resY = 0; + } + + if ( resX && resY ) + { + cinfo.X_density = resX; + cinfo.Y_density = resY; + } + + // sets the resolution unit field in the output file + // wxIMAGE_RESOLUTION_INCHES for inches + // wxIMAGE_RESOLUTION_CM for centimeters + if ( image->HasOption(wxIMAGE_OPTION_RESOLUTIONUNIT) ) + { + cinfo.density_unit = (UINT8)image->GetOptionInt(wxIMAGE_OPTION_RESOLUTIONUNIT); + } + + jpeg_start_compress(&cinfo, TRUE); + + stride = cinfo.image_width * 3; /* JSAMPLEs per row in image_buffer */ + image_buffer = image->GetData(); + while (cinfo.next_scanline < cinfo.image_height) { + row_pointer[0] = &image_buffer[cinfo.next_scanline * stride]; + jpeg_write_scanlines( &cinfo, row_pointer, 1 ); + } + jpeg_finish_compress(&cinfo); + jpeg_destroy_compress(&cinfo); + + return true; +} + +#ifdef __VISUALC__ + #pragma warning(default:4611) +#endif /* VC++ */ + +bool wxJPEGHandler::DoCanRead( wxInputStream& stream ) +{ + unsigned char hdr[2]; + + if ( !stream.Read(hdr, WXSIZEOF(hdr)) ) + return false; + + return hdr[0] == 0xFF && hdr[1] == 0xD8; +} + +#endif // wxUSE_STREAMS + +#endif // wxUSE_LIBJPEG diff --git a/Externals/wxWidgets/src/common/imagpcx.cpp b/Externals/wxWidgets/src/common/imagpcx.cpp index 96694be690..55740685ee 100644 --- a/Externals/wxWidgets/src/common/imagpcx.cpp +++ b/Externals/wxWidgets/src/common/imagpcx.cpp @@ -1,500 +1,500 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/imagpcx.cpp -// Purpose: wxImage PCX handler -// Author: Guillermo Rodriguez Garcia -// Version: 1.1 -// CVS-ID: $Id: imagpcx.cpp 40943 2006-08-31 19:31:43Z ABX $ -// Copyright: (c) 1999 Guillermo Rodriguez Garcia -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_IMAGE && wxUSE_PCX - -#ifndef WX_PRECOMP - #include "wx/object.h" - #include "wx/list.h" - #include "wx/log.h" - #include "wx/intl.h" - #include "wx/palette.h" - #include "wx/hash.h" - #include "wx/module.h" -#endif - -#include "wx/imagpcx.h" -#include "wx/wfstream.h" - -//----------------------------------------------------------------------------- -// wxPCXHandler -//----------------------------------------------------------------------------- - -IMPLEMENT_DYNAMIC_CLASS(wxPCXHandler,wxImageHandler) - -#if wxUSE_STREAMS - -//----------------------------------------------------------------------------- -// RLE encoding and decoding -//----------------------------------------------------------------------------- - -void RLEencode(unsigned char *p, unsigned int size, wxOutputStream& s) -{ - unsigned int data, last, cont; - - // Write 'size' bytes. The PCX official specs say there will be - // a decoding break at the end of each scanline, so in order to - // force this decoding break use this function to write, at most, - // _one_ complete scanline at a time. - - last = (unsigned char) *(p++); - cont = 1; - size--; - - while (size-- > 0) - { - data = (unsigned char) *(p++); - - // Up to 63 bytes with the same value can be stored using - // a single { cont, value } pair. - // - if ((data == last) && (cont < 63)) - { - cont++; - } - else - { - // need to write a 'counter' byte? - if ((cont > 1) || ((last & 0xC0) == 0xC0)) - s.PutC((char) (cont | 0xC0)); - - s.PutC((char) last); - last = data; - cont = 1; - } - } - - // write the last one and return; - if ((cont > 1) || ((last & 0xC0) == 0xC0)) - s.PutC((char) (cont | 0xC0)); - - s.PutC((char) last); -} - -void RLEdecode(unsigned char *p, unsigned int size, wxInputStream& s) -{ - unsigned int i, data, cont; - - // Read 'size' bytes. The PCX official specs say there will be - // a decoding break at the end of each scanline (but not at the - // end of each plane inside a scanline). Only use this function - // to read one or more _complete_ scanlines. Else, more than - // 'size' bytes might be read and the buffer might overflow. - - while (size > 0) - { - data = (unsigned char)s.GetC(); - - // If ((data & 0xC0) != 0xC0), then the value read is a data - // byte. Else, it is a counter (cont = val & 0x3F) and the - // next byte is the data byte. - - if ((data & 0xC0) != 0xC0) - { - *(p++) = (unsigned char)data; - size--; - } - else - { - cont = data & 0x3F; - data = (unsigned char)s.GetC(); - for (i = 1; i <= cont; i++) - *(p++) = (unsigned char)data; - size -= cont; - } - } -} - - -//----------------------------------------------------------------------------- -// PCX reading and saving -//----------------------------------------------------------------------------- - -// PCX header -#define HDR_MANUFACTURER 0 -#define HDR_VERSION 1 -#define HDR_ENCODING 2 -#define HDR_BITSPERPIXEL 3 -#define HDR_XMIN 4 -#define HDR_YMIN 6 -#define HDR_XMAX 8 -#define HDR_YMAX 10 -#define HDR_NPLANES 65 -#define HDR_BYTESPERLINE 66 -#define HDR_PALETTEINFO 68 - -// image formats -enum { - wxPCX_8BIT, // 8 bpp, 1 plane (8 bit) - wxPCX_24BIT // 8 bpp, 3 planes (24 bit) -}; - -// error codes -enum { - wxPCX_OK = 0, // everything was OK - wxPCX_INVFORMAT = 1, // error in pcx file format - wxPCX_MEMERR = 2, // error allocating memory - wxPCX_VERERR = 3 // error in pcx version number -}; - - -// ReadPCX: -// Loads a PCX file into the wxImage object pointed by image. -// Returns wxPCX_OK on success, or an error code otherwise -// (see above for error codes) -// -int ReadPCX(wxImage *image, wxInputStream& stream) -{ - unsigned char hdr[128]; // PCX header - unsigned char pal[768]; // palette for 8 bit images - unsigned char *p; // space to store one scanline - unsigned char *dst; // pointer into wxImage data - unsigned int width, height; // size of the image - unsigned int bytesperline; // bytes per line (each plane) - int bitsperpixel; // bits per pixel (each plane) - int nplanes; // number of planes - int encoding; // is the image RLE encoded? - int format; // image format (8 bit, 24 bit) - unsigned int i, j; - - // Read PCX header and check the version number (it must - // be at least 5 or higher for 8 bit and 24 bit images). - - stream.Read(hdr, 128); - - if (hdr[HDR_VERSION] < 5) return wxPCX_VERERR; - - // Extract all image info from the PCX header. - - encoding = hdr[HDR_ENCODING]; - nplanes = hdr[HDR_NPLANES]; - bitsperpixel = hdr[HDR_BITSPERPIXEL]; - bytesperline = hdr[HDR_BYTESPERLINE] + 256 * hdr[HDR_BYTESPERLINE + 1]; - width = (hdr[HDR_XMAX] + 256 * hdr[HDR_XMAX + 1]) - - (hdr[HDR_XMIN] + 256 * hdr[HDR_XMIN + 1]) + 1; - height = (hdr[HDR_YMAX] + 256 * hdr[HDR_YMAX + 1]) - - (hdr[HDR_YMIN] + 256 * hdr[HDR_YMIN + 1]) + 1; - - // Check image format. Currently supported formats are - // 8 bits (8 bpp, 1 plane) and 24 bits (8 bpp, 3 planes). - - if ((nplanes == 3) && (bitsperpixel == 8)) - format = wxPCX_24BIT; - else if ((nplanes == 1) && (bitsperpixel == 8)) - format = wxPCX_8BIT; - else - return wxPCX_INVFORMAT; - - // If the image is of type wxPCX_8BIT, then there is - // a palette at the end of the image data. If we were - // working with a file, we could seek at the end to the - // end (SeekI(-769, wxFromEnd) and read the palette - // before proceeding. Unfortunately, this would prevent - // loading several PCXs in a single stream, so we can't - // do it. Thus, 8-bit images will have to be decoded in - // two passes: one to read and decode the image data, - // and another to replace 'colour indexes' with RGB - // values. - - // Resize the image and allocate memory for a scanline. - - image->Create(width, height); - - if (!image->Ok()) - return wxPCX_MEMERR; - - if ((p = (unsigned char *) malloc(bytesperline * nplanes)) == NULL) - return wxPCX_MEMERR; - - // Now start reading the file, line by line, and store - // the data in the format required by wxImage. - - dst = image->GetData(); - - for (j = height; j; j--) - { - if (encoding) - RLEdecode(p, bytesperline * nplanes, stream); - else - stream.Read(p, bytesperline * nplanes); - - switch (format) - { - case wxPCX_8BIT: - { - for (i = 0; i < width; i++) - { - // first pass, just store the colour index - *dst = p[i]; - dst += 3; - } - break; - } - case wxPCX_24BIT: - { - for (i = 0; i < width; i++) - { - *(dst++) = p[i]; - *(dst++) = p[i + bytesperline]; - *(dst++) = p[i + 2 * bytesperline]; - } - break; - } - } - } - - free(p); - - // For 8 bit images, we read the palette, and then do a second - // pass replacing indexes with their RGB values; - - if (format == wxPCX_8BIT) - { - unsigned char index; - - if (stream.GetC() != 12) - return wxPCX_INVFORMAT; - - stream.Read(pal, 768); - - p = image->GetData(); - for (unsigned long k = height * width; k; k--) - { - index = *p; - *(p++) = pal[3 * index]; - *(p++) = pal[3 * index + 1]; - *(p++) = pal[3 * index + 2]; - } - -#if wxUSE_PALETTE - unsigned char r[256]; - unsigned char g[256]; - unsigned char b[256]; - for (i = 0; i < 256; i++) - { - r[i] = pal[3*i + 0]; - g[i] = pal[3*i + 1]; - b[i] = pal[3*i + 2]; - } - image->SetPalette(wxPalette(256, r, g, b)); -#endif // wxUSE_PALETTE - } - - return wxPCX_OK; -} - -// SavePCX: -// Saves a PCX file into the wxImage object pointed by image. -// Returns wxPCX_OK on success, or an error code otherwise -// (see above for error codes). Will try to save as 8-bit -// PCX if possible, and then fall back to 24-bit if there -// are more than 256 different colours. -// -int SavePCX(wxImage *image, wxOutputStream& stream) -{ - unsigned char hdr[128]; // PCX header - unsigned char pal[768]; // palette for 8 bit images - unsigned char *p; // space to store one scanline - unsigned char *src; // pointer into wxImage data - unsigned int width, height; // size of the image - unsigned int bytesperline; // bytes per line (each plane) - unsigned char nplanes = 3; // number of planes - int format = wxPCX_24BIT; // image format (8 bit, 24 bit) - wxImageHistogram histogram; // image histogram - unsigned long key; // key in the hashtable - unsigned int i; - - // See if we can save as 8 bit. - - if (image->CountColours(256) <= 256) - { - image->ComputeHistogram(histogram); - format = wxPCX_8BIT; - nplanes = 1; - } - - // Get image dimensions, calculate bytesperline (must be even, - // according to PCX specs) and allocate space for one complete - // scanline. - - if (!image->Ok()) - return wxPCX_INVFORMAT; - - width = image->GetWidth(); - height = image->GetHeight(); - bytesperline = width; - if (bytesperline % 2) - bytesperline++; - - if ((p = (unsigned char *) malloc(bytesperline * nplanes)) == NULL) - return wxPCX_MEMERR; - - // Build header data and write it to the stream. Initially, - // set all bytes to zero (most values default to zero). - - memset(hdr, 0, sizeof(hdr)); - - hdr[HDR_MANUFACTURER] = 10; - hdr[HDR_VERSION] = 5; - hdr[HDR_ENCODING] = 1; - hdr[HDR_NPLANES] = nplanes; - hdr[HDR_BITSPERPIXEL] = 8; - hdr[HDR_BYTESPERLINE] = (unsigned char)(bytesperline % 256); - hdr[HDR_BYTESPERLINE + 1] = (unsigned char)(bytesperline / 256); - hdr[HDR_XMAX] = (unsigned char)((width - 1) % 256); - hdr[HDR_XMAX + 1] = (unsigned char)((width - 1) / 256); - hdr[HDR_YMAX] = (unsigned char)((height - 1) % 256); - hdr[HDR_YMAX + 1] = (unsigned char)((height - 1) / 256); - hdr[HDR_PALETTEINFO] = 1; - - stream.Write(hdr, 128); - - // Encode image data line by line and write it to the stream - - src = image->GetData(); - - for (; height; height--) - { - switch (format) - { - case wxPCX_8BIT: - { - unsigned char r, g, b; - - for (i = 0; i < width; i++) - { - r = *(src++); - g = *(src++); - b = *(src++); - key = (r << 16) | (g << 8) | b; - - p[i] = (unsigned char)histogram[key].index; - } - break; - } - case wxPCX_24BIT: - { - for (i = 0; i < width; i++) - { - p[i] = *(src++); - p[i + bytesperline] = *(src++); - p[i + 2 * bytesperline] = *(src++); - } - break; - } - } - - RLEencode(p, bytesperline * nplanes, stream); - } - - free(p); - - // For 8 bit images, build the palette and write it to the stream: - if (format == wxPCX_8BIT) - { - // zero unused colours - memset(pal, 0, sizeof(pal)); - - unsigned long index; - - for (wxImageHistogram::iterator entry = histogram.begin(); - entry != histogram.end(); ++entry ) - { - key = entry->first; - index = entry->second.index; - pal[3 * index] = (unsigned char)(key >> 16); - pal[3 * index + 1] = (unsigned char)(key >> 8); - pal[3 * index + 2] = (unsigned char)(key); - } - - stream.PutC(12); - stream.Write(pal, 768); - } - - return wxPCX_OK; -} - -//----------------------------------------------------------------------------- -// wxPCXHandler -//----------------------------------------------------------------------------- - -bool wxPCXHandler::LoadFile( wxImage *image, wxInputStream& stream, bool verbose, int WXUNUSED(index) ) -{ - int error; - - if (!CanRead(stream)) - { - if (verbose) - wxLogError(_("PCX: this is not a PCX file.")); - - return false; - } - - image->Destroy(); - - if ((error = ReadPCX(image, stream)) != wxPCX_OK) - { - if (verbose) - { - switch (error) - { - case wxPCX_INVFORMAT: wxLogError(_("PCX: image format unsupported")); break; - case wxPCX_MEMERR: wxLogError(_("PCX: couldn't allocate memory")); break; - case wxPCX_VERERR: wxLogError(_("PCX: version number too low")); break; - default: wxLogError(_("PCX: unknown error !!!")); - } - } - image->Destroy(); - return false; - } - - return true; -} - -bool wxPCXHandler::SaveFile( wxImage *image, wxOutputStream& stream, bool verbose ) -{ - int error; - - if ((error = SavePCX(image, stream)) != wxPCX_OK) - { - if (verbose) - { - switch (error) - { - case wxPCX_INVFORMAT: wxLogError(_("PCX: invalid image")); break; - case wxPCX_MEMERR: wxLogError(_("PCX: couldn't allocate memory")); break; - default: wxLogError(_("PCX: unknown error !!!")); - } - } - } - - return (error == wxPCX_OK); -} - -bool wxPCXHandler::DoCanRead( wxInputStream& stream ) -{ - unsigned char c = stream.GetC(); - if ( !stream ) - return false; - - // not very safe, but this is all we can get from PCX header :-( - return c == 10; -} - -#endif // wxUSE_STREAMS - -#endif // wxUSE_IMAGE && wxUSE_PCX +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/imagpcx.cpp +// Purpose: wxImage PCX handler +// Author: Guillermo Rodriguez Garcia +// Version: 1.1 +// CVS-ID: $Id: imagpcx.cpp 40943 2006-08-31 19:31:43Z ABX $ +// Copyright: (c) 1999 Guillermo Rodriguez Garcia +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_IMAGE && wxUSE_PCX + +#ifndef WX_PRECOMP + #include "wx/object.h" + #include "wx/list.h" + #include "wx/log.h" + #include "wx/intl.h" + #include "wx/palette.h" + #include "wx/hash.h" + #include "wx/module.h" +#endif + +#include "wx/imagpcx.h" +#include "wx/wfstream.h" + +//----------------------------------------------------------------------------- +// wxPCXHandler +//----------------------------------------------------------------------------- + +IMPLEMENT_DYNAMIC_CLASS(wxPCXHandler,wxImageHandler) + +#if wxUSE_STREAMS + +//----------------------------------------------------------------------------- +// RLE encoding and decoding +//----------------------------------------------------------------------------- + +void RLEencode(unsigned char *p, unsigned int size, wxOutputStream& s) +{ + unsigned int data, last, cont; + + // Write 'size' bytes. The PCX official specs say there will be + // a decoding break at the end of each scanline, so in order to + // force this decoding break use this function to write, at most, + // _one_ complete scanline at a time. + + last = (unsigned char) *(p++); + cont = 1; + size--; + + while (size-- > 0) + { + data = (unsigned char) *(p++); + + // Up to 63 bytes with the same value can be stored using + // a single { cont, value } pair. + // + if ((data == last) && (cont < 63)) + { + cont++; + } + else + { + // need to write a 'counter' byte? + if ((cont > 1) || ((last & 0xC0) == 0xC0)) + s.PutC((char) (cont | 0xC0)); + + s.PutC((char) last); + last = data; + cont = 1; + } + } + + // write the last one and return; + if ((cont > 1) || ((last & 0xC0) == 0xC0)) + s.PutC((char) (cont | 0xC0)); + + s.PutC((char) last); +} + +void RLEdecode(unsigned char *p, unsigned int size, wxInputStream& s) +{ + unsigned int i, data, cont; + + // Read 'size' bytes. The PCX official specs say there will be + // a decoding break at the end of each scanline (but not at the + // end of each plane inside a scanline). Only use this function + // to read one or more _complete_ scanlines. Else, more than + // 'size' bytes might be read and the buffer might overflow. + + while (size > 0) + { + data = (unsigned char)s.GetC(); + + // If ((data & 0xC0) != 0xC0), then the value read is a data + // byte. Else, it is a counter (cont = val & 0x3F) and the + // next byte is the data byte. + + if ((data & 0xC0) != 0xC0) + { + *(p++) = (unsigned char)data; + size--; + } + else + { + cont = data & 0x3F; + data = (unsigned char)s.GetC(); + for (i = 1; i <= cont; i++) + *(p++) = (unsigned char)data; + size -= cont; + } + } +} + + +//----------------------------------------------------------------------------- +// PCX reading and saving +//----------------------------------------------------------------------------- + +// PCX header +#define HDR_MANUFACTURER 0 +#define HDR_VERSION 1 +#define HDR_ENCODING 2 +#define HDR_BITSPERPIXEL 3 +#define HDR_XMIN 4 +#define HDR_YMIN 6 +#define HDR_XMAX 8 +#define HDR_YMAX 10 +#define HDR_NPLANES 65 +#define HDR_BYTESPERLINE 66 +#define HDR_PALETTEINFO 68 + +// image formats +enum { + wxPCX_8BIT, // 8 bpp, 1 plane (8 bit) + wxPCX_24BIT // 8 bpp, 3 planes (24 bit) +}; + +// error codes +enum { + wxPCX_OK = 0, // everything was OK + wxPCX_INVFORMAT = 1, // error in pcx file format + wxPCX_MEMERR = 2, // error allocating memory + wxPCX_VERERR = 3 // error in pcx version number +}; + + +// ReadPCX: +// Loads a PCX file into the wxImage object pointed by image. +// Returns wxPCX_OK on success, or an error code otherwise +// (see above for error codes) +// +int ReadPCX(wxImage *image, wxInputStream& stream) +{ + unsigned char hdr[128]; // PCX header + unsigned char pal[768]; // palette for 8 bit images + unsigned char *p; // space to store one scanline + unsigned char *dst; // pointer into wxImage data + unsigned int width, height; // size of the image + unsigned int bytesperline; // bytes per line (each plane) + int bitsperpixel; // bits per pixel (each plane) + int nplanes; // number of planes + int encoding; // is the image RLE encoded? + int format; // image format (8 bit, 24 bit) + unsigned int i, j; + + // Read PCX header and check the version number (it must + // be at least 5 or higher for 8 bit and 24 bit images). + + stream.Read(hdr, 128); + + if (hdr[HDR_VERSION] < 5) return wxPCX_VERERR; + + // Extract all image info from the PCX header. + + encoding = hdr[HDR_ENCODING]; + nplanes = hdr[HDR_NPLANES]; + bitsperpixel = hdr[HDR_BITSPERPIXEL]; + bytesperline = hdr[HDR_BYTESPERLINE] + 256 * hdr[HDR_BYTESPERLINE + 1]; + width = (hdr[HDR_XMAX] + 256 * hdr[HDR_XMAX + 1]) - + (hdr[HDR_XMIN] + 256 * hdr[HDR_XMIN + 1]) + 1; + height = (hdr[HDR_YMAX] + 256 * hdr[HDR_YMAX + 1]) - + (hdr[HDR_YMIN] + 256 * hdr[HDR_YMIN + 1]) + 1; + + // Check image format. Currently supported formats are + // 8 bits (8 bpp, 1 plane) and 24 bits (8 bpp, 3 planes). + + if ((nplanes == 3) && (bitsperpixel == 8)) + format = wxPCX_24BIT; + else if ((nplanes == 1) && (bitsperpixel == 8)) + format = wxPCX_8BIT; + else + return wxPCX_INVFORMAT; + + // If the image is of type wxPCX_8BIT, then there is + // a palette at the end of the image data. If we were + // working with a file, we could seek at the end to the + // end (SeekI(-769, wxFromEnd) and read the palette + // before proceeding. Unfortunately, this would prevent + // loading several PCXs in a single stream, so we can't + // do it. Thus, 8-bit images will have to be decoded in + // two passes: one to read and decode the image data, + // and another to replace 'colour indexes' with RGB + // values. + + // Resize the image and allocate memory for a scanline. + + image->Create(width, height); + + if (!image->Ok()) + return wxPCX_MEMERR; + + if ((p = (unsigned char *) malloc(bytesperline * nplanes)) == NULL) + return wxPCX_MEMERR; + + // Now start reading the file, line by line, and store + // the data in the format required by wxImage. + + dst = image->GetData(); + + for (j = height; j; j--) + { + if (encoding) + RLEdecode(p, bytesperline * nplanes, stream); + else + stream.Read(p, bytesperline * nplanes); + + switch (format) + { + case wxPCX_8BIT: + { + for (i = 0; i < width; i++) + { + // first pass, just store the colour index + *dst = p[i]; + dst += 3; + } + break; + } + case wxPCX_24BIT: + { + for (i = 0; i < width; i++) + { + *(dst++) = p[i]; + *(dst++) = p[i + bytesperline]; + *(dst++) = p[i + 2 * bytesperline]; + } + break; + } + } + } + + free(p); + + // For 8 bit images, we read the palette, and then do a second + // pass replacing indexes with their RGB values; + + if (format == wxPCX_8BIT) + { + unsigned char index; + + if (stream.GetC() != 12) + return wxPCX_INVFORMAT; + + stream.Read(pal, 768); + + p = image->GetData(); + for (unsigned long k = height * width; k; k--) + { + index = *p; + *(p++) = pal[3 * index]; + *(p++) = pal[3 * index + 1]; + *(p++) = pal[3 * index + 2]; + } + +#if wxUSE_PALETTE + unsigned char r[256]; + unsigned char g[256]; + unsigned char b[256]; + for (i = 0; i < 256; i++) + { + r[i] = pal[3*i + 0]; + g[i] = pal[3*i + 1]; + b[i] = pal[3*i + 2]; + } + image->SetPalette(wxPalette(256, r, g, b)); +#endif // wxUSE_PALETTE + } + + return wxPCX_OK; +} + +// SavePCX: +// Saves a PCX file into the wxImage object pointed by image. +// Returns wxPCX_OK on success, or an error code otherwise +// (see above for error codes). Will try to save as 8-bit +// PCX if possible, and then fall back to 24-bit if there +// are more than 256 different colours. +// +int SavePCX(wxImage *image, wxOutputStream& stream) +{ + unsigned char hdr[128]; // PCX header + unsigned char pal[768]; // palette for 8 bit images + unsigned char *p; // space to store one scanline + unsigned char *src; // pointer into wxImage data + unsigned int width, height; // size of the image + unsigned int bytesperline; // bytes per line (each plane) + unsigned char nplanes = 3; // number of planes + int format = wxPCX_24BIT; // image format (8 bit, 24 bit) + wxImageHistogram histogram; // image histogram + unsigned long key; // key in the hashtable + unsigned int i; + + // See if we can save as 8 bit. + + if (image->CountColours(256) <= 256) + { + image->ComputeHistogram(histogram); + format = wxPCX_8BIT; + nplanes = 1; + } + + // Get image dimensions, calculate bytesperline (must be even, + // according to PCX specs) and allocate space for one complete + // scanline. + + if (!image->Ok()) + return wxPCX_INVFORMAT; + + width = image->GetWidth(); + height = image->GetHeight(); + bytesperline = width; + if (bytesperline % 2) + bytesperline++; + + if ((p = (unsigned char *) malloc(bytesperline * nplanes)) == NULL) + return wxPCX_MEMERR; + + // Build header data and write it to the stream. Initially, + // set all bytes to zero (most values default to zero). + + memset(hdr, 0, sizeof(hdr)); + + hdr[HDR_MANUFACTURER] = 10; + hdr[HDR_VERSION] = 5; + hdr[HDR_ENCODING] = 1; + hdr[HDR_NPLANES] = nplanes; + hdr[HDR_BITSPERPIXEL] = 8; + hdr[HDR_BYTESPERLINE] = (unsigned char)(bytesperline % 256); + hdr[HDR_BYTESPERLINE + 1] = (unsigned char)(bytesperline / 256); + hdr[HDR_XMAX] = (unsigned char)((width - 1) % 256); + hdr[HDR_XMAX + 1] = (unsigned char)((width - 1) / 256); + hdr[HDR_YMAX] = (unsigned char)((height - 1) % 256); + hdr[HDR_YMAX + 1] = (unsigned char)((height - 1) / 256); + hdr[HDR_PALETTEINFO] = 1; + + stream.Write(hdr, 128); + + // Encode image data line by line and write it to the stream + + src = image->GetData(); + + for (; height; height--) + { + switch (format) + { + case wxPCX_8BIT: + { + unsigned char r, g, b; + + for (i = 0; i < width; i++) + { + r = *(src++); + g = *(src++); + b = *(src++); + key = (r << 16) | (g << 8) | b; + + p[i] = (unsigned char)histogram[key].index; + } + break; + } + case wxPCX_24BIT: + { + for (i = 0; i < width; i++) + { + p[i] = *(src++); + p[i + bytesperline] = *(src++); + p[i + 2 * bytesperline] = *(src++); + } + break; + } + } + + RLEencode(p, bytesperline * nplanes, stream); + } + + free(p); + + // For 8 bit images, build the palette and write it to the stream: + if (format == wxPCX_8BIT) + { + // zero unused colours + memset(pal, 0, sizeof(pal)); + + unsigned long index; + + for (wxImageHistogram::iterator entry = histogram.begin(); + entry != histogram.end(); ++entry ) + { + key = entry->first; + index = entry->second.index; + pal[3 * index] = (unsigned char)(key >> 16); + pal[3 * index + 1] = (unsigned char)(key >> 8); + pal[3 * index + 2] = (unsigned char)(key); + } + + stream.PutC(12); + stream.Write(pal, 768); + } + + return wxPCX_OK; +} + +//----------------------------------------------------------------------------- +// wxPCXHandler +//----------------------------------------------------------------------------- + +bool wxPCXHandler::LoadFile( wxImage *image, wxInputStream& stream, bool verbose, int WXUNUSED(index) ) +{ + int error; + + if (!CanRead(stream)) + { + if (verbose) + wxLogError(_("PCX: this is not a PCX file.")); + + return false; + } + + image->Destroy(); + + if ((error = ReadPCX(image, stream)) != wxPCX_OK) + { + if (verbose) + { + switch (error) + { + case wxPCX_INVFORMAT: wxLogError(_("PCX: image format unsupported")); break; + case wxPCX_MEMERR: wxLogError(_("PCX: couldn't allocate memory")); break; + case wxPCX_VERERR: wxLogError(_("PCX: version number too low")); break; + default: wxLogError(_("PCX: unknown error !!!")); + } + } + image->Destroy(); + return false; + } + + return true; +} + +bool wxPCXHandler::SaveFile( wxImage *image, wxOutputStream& stream, bool verbose ) +{ + int error; + + if ((error = SavePCX(image, stream)) != wxPCX_OK) + { + if (verbose) + { + switch (error) + { + case wxPCX_INVFORMAT: wxLogError(_("PCX: invalid image")); break; + case wxPCX_MEMERR: wxLogError(_("PCX: couldn't allocate memory")); break; + default: wxLogError(_("PCX: unknown error !!!")); + } + } + } + + return (error == wxPCX_OK); +} + +bool wxPCXHandler::DoCanRead( wxInputStream& stream ) +{ + unsigned char c = stream.GetC(); + if ( !stream ) + return false; + + // not very safe, but this is all we can get from PCX header :-( + return c == 10; +} + +#endif // wxUSE_STREAMS + +#endif // wxUSE_IMAGE && wxUSE_PCX diff --git a/Externals/wxWidgets/src/common/imagpng.cpp b/Externals/wxWidgets/src/common/imagpng.cpp index f8277721b1..14217bb6dd 100644 --- a/Externals/wxWidgets/src/common/imagpng.cpp +++ b/Externals/wxWidgets/src/common/imagpng.cpp @@ -1,868 +1,868 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/imagepng.cpp -// Purpose: wxImage PNG handler -// Author: Robert Roebling -// RCS-ID: $Id: imagpng.cpp 53479 2008-05-07 16:23:55Z PC $ -// Copyright: (c) Robert Roebling -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_IMAGE && wxUSE_LIBPNG - -#include "wx/imagpng.h" - -#ifndef WX_PRECOMP - #include "wx/log.h" - #include "wx/app.h" - #include "wx/bitmap.h" - #include "wx/module.h" -#endif - -#include "png.h" -#include "wx/filefn.h" -#include "wx/wfstream.h" -#include "wx/intl.h" -#include "wx/palette.h" - -// For memcpy -#include - -#ifdef __SALFORDC__ -#ifdef FAR -#undef FAR -#endif -#endif - -// ---------------------------------------------------------------------------- -// constants -// ---------------------------------------------------------------------------- - -// image can not have any transparent pixels at all, have only 100% opaque -// and/or 100% transparent pixels in which case a simple mask is enough to -// store this information in wxImage or have a real alpha channel in which case -// we need to have it in wxImage as well -enum Transparency -{ - Transparency_None, - Transparency_Mask, - Transparency_Alpha -}; - -// ---------------------------------------------------------------------------- -// local functions -// ---------------------------------------------------------------------------- - -// return the kind of transparency needed for this image assuming that it does -// have transparent pixels, i.e. either Transparency_Alpha or Transparency_Mask -static Transparency -CheckTransparency(unsigned char **lines, - png_uint_32 x, png_uint_32 y, png_uint_32 w, png_uint_32 h, - size_t numColBytes); - -// init the alpha channel for the image and fill it with 1s up to (x, y) -static unsigned char *InitAlpha(wxImage *image, png_uint_32 x, png_uint_32 y); - -// find a free colour for the mask in the PNG data array -static void -FindMaskColour(unsigned char **lines, png_uint_32 width, png_uint_32 height, - unsigned char& rMask, unsigned char& gMask, unsigned char& bMask); - -// is the pixel with this value of alpha a fully opaque one? -static inline -bool IsOpaque(unsigned char a) -{ - return a == 0xff; -} - -// is the pixel with this value of alpha a fully transparent one? -static inline -bool IsTransparent(unsigned char a) -{ - return !a; -} - -// ============================================================================ -// wxPNGHandler implementation -// ============================================================================ - -IMPLEMENT_DYNAMIC_CLASS(wxPNGHandler,wxImageHandler) - -#if wxUSE_STREAMS - -#ifndef PNGLINKAGEMODE - #ifdef PNGAPI - #define PNGLINKAGEMODE PNGAPI - #elif defined(__WATCOMC__) - // we need an explicit cdecl for Watcom, at least according to - // - // http://sf.net/tracker/index.php?func=detail&aid=651492&group_id=9863&atid=109863 - // - // more testing is needed for this however, please remove this comment - // if you can confirm that my fix works with Watcom 11 - #define PNGLINKAGEMODE cdecl - #else - #define PNGLINKAGEMODE LINKAGEMODE - #endif -#endif - - -// VS: wxPNGInfoStruct declared below is a hack that needs some explanation. -// First, let me describe what's the problem: libpng uses jmp_buf in -// its png_struct structure. Unfortunately, this structure is -// compiler-specific and may vary in size, so if you use libpng compiled -// as DLL with another compiler than the main executable, it may not work -// (this is for example the case with wxMGL port and SciTech MGL library -// that provides custom runtime-loadable libpng implementation with jmpbuf -// disabled altogether). Luckily, it is still possible to use setjmp() & -// longjmp() as long as the structure is not part of png_struct. -// -// Sadly, there's no clean way to attach user-defined data to png_struct. -// There is only one customizable place, png_struct.io_ptr, which is meant -// only for I/O routines and is set with png_set_read_fn or -// png_set_write_fn. The hacky part is that we use io_ptr to store -// a pointer to wxPNGInfoStruct that holds I/O structures _and_ jmp_buf. - -struct wxPNGInfoStruct -{ - jmp_buf jmpbuf; - bool verbose; - - union - { - wxInputStream *in; - wxOutputStream *out; - } stream; -}; - -#define WX_PNG_INFO(png_ptr) ((wxPNGInfoStruct*)png_get_io_ptr(png_ptr)) - -// ---------------------------------------------------------------------------- -// helper functions -// ---------------------------------------------------------------------------- - -extern "C" -{ - -void PNGLINKAGEMODE wx_PNG_stream_reader( png_structp png_ptr, png_bytep data, - png_size_t length ) -{ - WX_PNG_INFO(png_ptr)->stream.in->Read(data, length); -} - -void PNGLINKAGEMODE wx_PNG_stream_writer( png_structp png_ptr, png_bytep data, - png_size_t length ) -{ - WX_PNG_INFO(png_ptr)->stream.out->Write(data, length); -} - -void -PNGLINKAGEMODE wx_png_warning(png_structp png_ptr, png_const_charp message) -{ - wxPNGInfoStruct *info = png_ptr ? WX_PNG_INFO(png_ptr) : NULL; - if ( !info || info->verbose ) - wxLogWarning( wxString::FromAscii(message) ); -} - -// from pngerror.c -// so that the libpng doesn't send anything on stderr -void -PNGLINKAGEMODE wx_png_error(png_structp png_ptr, png_const_charp message) -{ - wx_png_warning(NULL, message); - - // we're not using libpng built-in jump buffer (see comment before - // wxPNGInfoStruct above) so we have to return ourselves, otherwise libpng - // would just abort - longjmp(WX_PNG_INFO(png_ptr)->jmpbuf, 1); -} - -} // extern "C" - -// ---------------------------------------------------------------------------- -// LoadFile() helpers -// ---------------------------------------------------------------------------- - -// determine the kind of transparency we need for this image: if the only alpha -// values it has are 0 (transparent) and 0xff (opaque) then we can simply -// create a mask for it, we should be ok with a simple mask but otherwise we -// need a full blown alpha channel in wxImage -// -// parameters: -// lines raw PNG data -// x, y starting position -// w, h size of the image -// numColBytes number of colour bytes (1 for grey scale, 3 for RGB) -// (NB: alpha always follows the colour bytes) -Transparency -CheckTransparency(unsigned char **lines, - png_uint_32 x, png_uint_32 y, png_uint_32 w, png_uint_32 h, - size_t numColBytes) -{ - // suppose that a mask will suffice and check all the remaining alpha - // values to see if it does - for ( ; y < h; y++ ) - { - // each pixel is numColBytes+1 bytes, offset into the current line by - // the current x position - unsigned const char *ptr = lines[y] + (x * (numColBytes + 1)); - - for ( png_uint_32 x2 = x; x2 < w; x2++ ) - { - // skip the grey or colour byte(s) - ptr += numColBytes; - - unsigned char a2 = *ptr++; - - if ( !IsTransparent(a2) && !IsOpaque(a2) ) - { - // not fully opaque nor fully transparent, hence need alpha - return Transparency_Alpha; - } - } - - // during the next loop iteration check all the pixels in the row - x = 0; - } - - // mask will be enough - return Transparency_Mask; -} - -unsigned char *InitAlpha(wxImage *image, png_uint_32 x, png_uint_32 y) -{ - // create alpha channel - image->SetAlpha(); - - unsigned char *alpha = image->GetAlpha(); - - // set alpha for the pixels we had so far - png_uint_32 end = y * image->GetWidth() + x; - for ( png_uint_32 i = 0; i < end; i++ ) - { - // all the previous pixels were opaque - *alpha++ = 0xff; - } - - return alpha; -} - -void -FindMaskColour(unsigned char **lines, png_uint_32 width, png_uint_32 height, - unsigned char& rMask, unsigned char& gMask, unsigned char& bMask) -{ - // choosing the colour for the mask is more - // difficult: we need to iterate over the entire - // image for this in order to choose an unused - // colour (this is not very efficient but what else - // can we do?) - wxImageHistogram h; - unsigned nentries = 0; - unsigned char r2, g2, b2; - for ( png_uint_32 y2 = 0; y2 < height; y2++ ) - { - const unsigned char *p = lines[y2]; - for ( png_uint_32 x2 = 0; x2 < width; x2++ ) - { - r2 = *p++; - g2 = *p++; - b2 = *p++; - ++p; // jump over alpha - - wxImageHistogramEntry& - entry = h[wxImageHistogram:: MakeKey(r2, g2, b2)]; - - if ( entry.value++ == 0 ) - entry.index = nentries++; - } - } - - if ( !h.FindFirstUnusedColour(&rMask, &gMask, &bMask) ) - { - wxLogWarning(_("Too many colours in PNG, the image may be slightly blurred.")); - - // use a fixed mask colour and we'll fudge - // the real pixels with this colour (see - // below) - rMask = 0xfe; - gMask = 0; - bMask = 0xff; - } -} - -// ---------------------------------------------------------------------------- -// reading PNGs -// ---------------------------------------------------------------------------- - -bool wxPNGHandler::DoCanRead( wxInputStream& stream ) -{ - unsigned char hdr[4]; - - if ( !stream.Read(hdr, WXSIZEOF(hdr)) ) - return false; - - return memcmp(hdr, "\211PNG", WXSIZEOF(hdr)) == 0; -} - -// convert data from RGB to wxImage format -static -void CopyDataFromPNG(wxImage *image, - unsigned char **lines, - png_uint_32 width, - png_uint_32 height, - int color_type) -{ - Transparency transparency = Transparency_None; - - // only non NULL if transparency == Transparency_Alpha - unsigned char *alpha = NULL; - - // RGB of the mask colour if transparency == Transparency_Mask - // (but init them anyhow to avoid compiler warnings) - unsigned char rMask = 0, - gMask = 0, - bMask = 0; - - unsigned char *ptrDst = image->GetData(); - if ( !(color_type & PNG_COLOR_MASK_COLOR) ) - { - // grey image: GAGAGA... where G == grey component and A == alpha - for ( png_uint_32 y = 0; y < height; y++ ) - { - const unsigned char *ptrSrc = lines[y]; - for ( png_uint_32 x = 0; x < width; x++ ) - { - unsigned char g = *ptrSrc++; - unsigned char a = *ptrSrc++; - - // the first time we encounter a transparent pixel we must - // decide about what to do about them - if ( !IsOpaque(a) && transparency == Transparency_None ) - { - // we'll need at least the mask for this image and - // maybe even full alpha channel info: the former is - // only enough if we have alpha values of 0 and 0xff - // only, otherwisewe need the latter - transparency = CheckTransparency - ( - lines, - x, y, - width, height, - 1 - ); - - if ( transparency == Transparency_Mask ) - { - // let's choose this colour for the mask: this is - // not a problem here as all the other pixels are - // grey, i.e. R == G == B which is not the case for - // this one so no confusion is possible - rMask = 0xff; - gMask = 0; - bMask = 0xff; - } - else // transparency == Transparency_Alpha - { - alpha = InitAlpha(image, x, y); - } - } - - switch ( transparency ) - { - case Transparency_Mask: - if ( IsTransparent(a) ) - { - *ptrDst++ = rMask; - *ptrDst++ = gMask; - *ptrDst++ = bMask; - break; - } - // else: !transparent - - // must be opaque then as otherwise we shouldn't be - // using the mask at all - wxASSERT_MSG( IsOpaque(a), _T("logic error") ); - - // fall through - - case Transparency_Alpha: - if ( alpha ) - *alpha++ = a; - // fall through - - case Transparency_None: - *ptrDst++ = g; - *ptrDst++ = g; - *ptrDst++ = g; - break; - } - } - } - } - else // colour image: RGBRGB... - { - for ( png_uint_32 y = 0; y < height; y++ ) - { - const unsigned char *ptrSrc = lines[y]; - for ( png_uint_32 x = 0; x < width; x++ ) - { - unsigned char r = *ptrSrc++; - unsigned char g = *ptrSrc++; - unsigned char b = *ptrSrc++; - unsigned char a = *ptrSrc++; - - // the logic here is the same as for the grey case except - // where noted - if ( !IsOpaque(a) && transparency == Transparency_None ) - { - transparency = CheckTransparency - ( - lines, - x, y, - width, height, - 3 - ); - - if ( transparency == Transparency_Mask ) - { - FindMaskColour(lines, width, height, - rMask, gMask, bMask); - } - else // transparency == Transparency_Alpha - { - alpha = InitAlpha(image, x, y); - } - - } - - switch ( transparency ) - { - case Transparency_Mask: - if ( IsTransparent(a) ) - { - *ptrDst++ = rMask; - *ptrDst++ = gMask; - *ptrDst++ = bMask; - break; - } - else // !transparent - { - // must be opaque then as otherwise we shouldn't be - // using the mask at all - wxASSERT_MSG( IsOpaque(a), _T("logic error") ); - - // if we couldn't find a unique colour for the - // mask, we can have real pixels with the same - // value as the mask and it's better to slightly - // change their colour than to make them - // transparent - if ( r == rMask && g == gMask && b == bMask ) - { - r++; - } - } - - // fall through - - case Transparency_Alpha: - if ( alpha ) - *alpha++ = a; - // fall through - - case Transparency_None: - *ptrDst++ = r; - *ptrDst++ = g; - *ptrDst++ = b; - break; - } - } - } - } - - if ( transparency == Transparency_Mask ) - { - image->SetMaskColour(rMask, gMask, bMask); - } -} - -// temporarily disable the warning C4611 (interaction between '_setjmp' and -// C++ object destruction is non-portable) - I don't see any dtors here -#ifdef __VISUALC__ - #pragma warning(disable:4611) -#endif /* VC++ */ - -bool -wxPNGHandler::LoadFile(wxImage *image, - wxInputStream& stream, - bool verbose, - int WXUNUSED(index)) -{ - // VZ: as this function uses setjmp() the only fool-proof error handling - // method is to use goto (setjmp is not really C++ dtors friendly...) - - unsigned char **lines = NULL; - png_infop info_ptr = (png_infop) NULL; - wxPNGInfoStruct wxinfo; - - png_uint_32 i, width, height = 0; - int bit_depth, color_type, interlace_type; - - wxinfo.verbose = verbose; - wxinfo.stream.in = &stream; - - image->Destroy(); - - png_structp png_ptr = png_create_read_struct - ( - PNG_LIBPNG_VER_STRING, - (voidp) NULL, - wx_png_error, - wx_png_warning - ); - if (!png_ptr) - goto error; - - // NB: please see the comment near wxPNGInfoStruct declaration for - // explanation why this line is mandatory - png_set_read_fn( png_ptr, &wxinfo, wx_PNG_stream_reader); - - info_ptr = png_create_info_struct( png_ptr ); - if (!info_ptr) - goto error; - - if (setjmp(wxinfo.jmpbuf)) - goto error; - - png_read_info( png_ptr, info_ptr ); - png_get_IHDR( png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, (int*) NULL, (int*) NULL ); - - if (color_type == PNG_COLOR_TYPE_PALETTE) - png_set_expand( png_ptr ); - - // Fix for Bug [ 439207 ] Monochrome PNG images come up black - if (bit_depth < 8) - png_set_expand( png_ptr ); - - png_set_strip_16( png_ptr ); - png_set_packing( png_ptr ); - if (png_get_valid( png_ptr, info_ptr, PNG_INFO_tRNS)) - png_set_expand( png_ptr ); - png_set_filler( png_ptr, 0xff, PNG_FILLER_AFTER ); - - image->Create((int)width, (int)height, (bool) false /* no need to init pixels */); - - if (!image->Ok()) - goto error; - - lines = (unsigned char **)malloc( (size_t)(height * sizeof(unsigned char *)) ); - if ( !lines ) - goto error; - - for (i = 0; i < height; i++) - { - if ((lines[i] = (unsigned char *)malloc( (size_t)(width * (sizeof(unsigned char) * 4)))) == NULL) - { - for ( unsigned int n = 0; n < i; n++ ) - free( lines[n] ); - goto error; - } - } - - png_read_image( png_ptr, lines ); - png_read_end( png_ptr, info_ptr ); - -#if wxUSE_PALETTE - if (color_type == PNG_COLOR_TYPE_PALETTE) - { - const size_t ncolors = info_ptr->num_palette; - unsigned char* r = new unsigned char[ncolors]; - unsigned char* g = new unsigned char[ncolors]; - unsigned char* b = new unsigned char[ncolors]; - - for (size_t j = 0; j < ncolors; j++) - { - r[j] = info_ptr->palette[j].red; - g[j] = info_ptr->palette[j].green; - b[j] = info_ptr->palette[j].blue; - } - - image->SetPalette(wxPalette(ncolors, r, g, b)); - delete[] r; - delete[] g; - delete[] b; - } -#endif // wxUSE_PALETTE - - png_destroy_read_struct( &png_ptr, &info_ptr, (png_infopp) NULL ); - - // loaded successfully, now init wxImage with this data - CopyDataFromPNG(image, lines, width, height, color_type); - - for ( i = 0; i < height; i++ ) - free( lines[i] ); - free( lines ); - - return true; - -error: - if (verbose) - wxLogError(_("Couldn't load a PNG image - file is corrupted or not enough memory.")); - - if ( image->Ok() ) - { - image->Destroy(); - } - - if ( lines ) - { - for ( unsigned int n = 0; n < height; n++ ) - free( lines[n] ); - - free( lines ); - } - - if ( png_ptr ) - { - if ( info_ptr ) - { - png_destroy_read_struct( &png_ptr, &info_ptr, (png_infopp) NULL ); - free(info_ptr); - } - else - png_destroy_read_struct( &png_ptr, (png_infopp) NULL, (png_infopp) NULL ); - } - return false; -} - -// ---------------------------------------------------------------------------- -// writing PNGs -// ---------------------------------------------------------------------------- - -bool wxPNGHandler::SaveFile( wxImage *image, wxOutputStream& stream, bool verbose ) -{ - wxPNGInfoStruct wxinfo; - - wxinfo.verbose = verbose; - wxinfo.stream.out = &stream; - - png_structp png_ptr = png_create_write_struct - ( - PNG_LIBPNG_VER_STRING, - NULL, - wx_png_error, - wx_png_warning - ); - if (!png_ptr) - { - if (verbose) - wxLogError(_("Couldn't save PNG image.")); - return false; - } - - png_infop info_ptr = png_create_info_struct(png_ptr); - if (info_ptr == NULL) - { - png_destroy_write_struct( &png_ptr, (png_infopp)NULL ); - if (verbose) - wxLogError(_("Couldn't save PNG image.")); - return false; - } - - if (setjmp(wxinfo.jmpbuf)) - { - png_destroy_write_struct( &png_ptr, (png_infopp)NULL ); - if (verbose) - wxLogError(_("Couldn't save PNG image.")); - return false; - } - - // NB: please see the comment near wxPNGInfoStruct declaration for - // explanation why this line is mandatory - png_set_write_fn( png_ptr, &wxinfo, wx_PNG_stream_writer, NULL); - - const int iColorType = image->HasOption(wxIMAGE_OPTION_PNG_FORMAT) - ? image->GetOptionInt(wxIMAGE_OPTION_PNG_FORMAT) - : wxPNG_TYPE_COLOUR; - const int iBitDepth = image->HasOption(wxIMAGE_OPTION_PNG_BITDEPTH) - ? image->GetOptionInt(wxIMAGE_OPTION_PNG_BITDEPTH) - : 8; - - wxASSERT_MSG( iBitDepth == 8 || iBitDepth == 16, - _T("PNG bit depth must be 8 or 16") ); - - bool bHasAlpha = image->HasAlpha(); - bool bHasMask = image->HasMask(); - bool bUseAlpha = bHasAlpha || bHasMask; - - int iPngColorType; - if ( iColorType==wxPNG_TYPE_COLOUR ) - { - iPngColorType = bUseAlpha ? PNG_COLOR_TYPE_RGB_ALPHA - : PNG_COLOR_TYPE_RGB; - } - else - { - iPngColorType = bUseAlpha ? PNG_COLOR_TYPE_GRAY_ALPHA - : PNG_COLOR_TYPE_GRAY; - } - - png_set_IHDR( png_ptr, info_ptr, image->GetWidth(), image->GetHeight(), - iBitDepth, iPngColorType, - PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, - PNG_FILTER_TYPE_BASE); - - int iElements; - png_color_8 sig_bit; - - if ( iPngColorType & PNG_COLOR_MASK_COLOR ) - { - sig_bit.red = - sig_bit.green = - sig_bit.blue = (png_byte)iBitDepth; - iElements = 3; - } - else // grey - { - sig_bit.gray = (png_byte)iBitDepth; - iElements = 1; - } - - if ( iPngColorType & PNG_COLOR_MASK_ALPHA ) - { - sig_bit.alpha = (png_byte)iBitDepth; - iElements++; - } - - if ( iBitDepth == 16 ) - iElements *= 2; - - png_set_sBIT( png_ptr, info_ptr, &sig_bit ); - png_write_info( png_ptr, info_ptr ); - png_set_shift( png_ptr, &sig_bit ); - png_set_packing( png_ptr ); - - unsigned char * - data = (unsigned char *)malloc( image->GetWidth() * iElements ); - if ( !data ) - { - png_destroy_write_struct( &png_ptr, (png_infopp)NULL ); - return false; - } - - unsigned char * - pAlpha = (unsigned char *)(bHasAlpha ? image->GetAlpha() : NULL); - int iHeight = image->GetHeight(); - int iWidth = image->GetWidth(); - - unsigned char uchMaskRed = 0, uchMaskGreen = 0, uchMaskBlue = 0; - - if ( bHasMask ) - { - uchMaskRed = image->GetMaskRed(); - uchMaskGreen = image->GetMaskGreen(); - uchMaskBlue = image->GetMaskBlue(); - } - - unsigned char *pColors = image->GetData(); - - for (int y = 0; y != iHeight; ++y) - { - unsigned char *pData = data; - for (int x = 0; x != iWidth; x++) - { - unsigned char uchRed = *pColors++; - unsigned char uchGreen = *pColors++; - unsigned char uchBlue = *pColors++; - - switch ( iColorType ) - { - default: - wxFAIL_MSG( _T("unknown wxPNG_TYPE_XXX") ); - // fall through - - case wxPNG_TYPE_COLOUR: - *pData++ = uchRed; - if ( iBitDepth == 16 ) - *pData++ = 0; - *pData++ = uchGreen; - if ( iBitDepth == 16 ) - *pData++ = 0; - *pData++ = uchBlue; - if ( iBitDepth == 16 ) - *pData++ = 0; - break; - - case wxPNG_TYPE_GREY: - { - // where do these coefficients come from? maybe we - // should have image options for them as well? - unsigned uiColor = - (unsigned) (76.544*(unsigned)uchRed + - 150.272*(unsigned)uchGreen + - 36.864*(unsigned)uchBlue); - - *pData++ = (unsigned char)((uiColor >> 8) & 0xFF); - if ( iBitDepth == 16 ) - *pData++ = (unsigned char)(uiColor & 0xFF); - } - break; - - case wxPNG_TYPE_GREY_RED: - *pData++ = uchRed; - if ( iBitDepth == 16 ) - *pData++ = 0; - break; - } - - if ( bUseAlpha ) - { - unsigned char uchAlpha = 255; - if ( bHasAlpha ) - uchAlpha = *pAlpha++; - - if ( bHasMask ) - { - if ( (uchRed == uchMaskRed) - && (uchGreen == uchMaskGreen) - && (uchBlue == uchMaskBlue) ) - uchAlpha = 0; - } - - *pData++ = uchAlpha; - if ( iBitDepth == 16 ) - *pData++ = 0; - } - } - - png_bytep row_ptr = data; - png_write_rows( png_ptr, &row_ptr, 1 ); - } - - free(data); - png_write_end( png_ptr, info_ptr ); - png_destroy_write_struct( &png_ptr, (png_infopp)&info_ptr ); - - return true; -} - -#ifdef __VISUALC__ - #pragma warning(default:4611) -#endif /* VC++ */ - -#endif // wxUSE_STREAMS - -#endif // wxUSE_LIBPNG +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/imagepng.cpp +// Purpose: wxImage PNG handler +// Author: Robert Roebling +// RCS-ID: $Id: imagpng.cpp 53479 2008-05-07 16:23:55Z PC $ +// Copyright: (c) Robert Roebling +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_IMAGE && wxUSE_LIBPNG + +#include "wx/imagpng.h" + +#ifndef WX_PRECOMP + #include "wx/log.h" + #include "wx/app.h" + #include "wx/bitmap.h" + #include "wx/module.h" +#endif + +#include "png.h" +#include "wx/filefn.h" +#include "wx/wfstream.h" +#include "wx/intl.h" +#include "wx/palette.h" + +// For memcpy +#include + +#ifdef __SALFORDC__ +#ifdef FAR +#undef FAR +#endif +#endif + +// ---------------------------------------------------------------------------- +// constants +// ---------------------------------------------------------------------------- + +// image can not have any transparent pixels at all, have only 100% opaque +// and/or 100% transparent pixels in which case a simple mask is enough to +// store this information in wxImage or have a real alpha channel in which case +// we need to have it in wxImage as well +enum Transparency +{ + Transparency_None, + Transparency_Mask, + Transparency_Alpha +}; + +// ---------------------------------------------------------------------------- +// local functions +// ---------------------------------------------------------------------------- + +// return the kind of transparency needed for this image assuming that it does +// have transparent pixels, i.e. either Transparency_Alpha or Transparency_Mask +static Transparency +CheckTransparency(unsigned char **lines, + png_uint_32 x, png_uint_32 y, png_uint_32 w, png_uint_32 h, + size_t numColBytes); + +// init the alpha channel for the image and fill it with 1s up to (x, y) +static unsigned char *InitAlpha(wxImage *image, png_uint_32 x, png_uint_32 y); + +// find a free colour for the mask in the PNG data array +static void +FindMaskColour(unsigned char **lines, png_uint_32 width, png_uint_32 height, + unsigned char& rMask, unsigned char& gMask, unsigned char& bMask); + +// is the pixel with this value of alpha a fully opaque one? +static inline +bool IsOpaque(unsigned char a) +{ + return a == 0xff; +} + +// is the pixel with this value of alpha a fully transparent one? +static inline +bool IsTransparent(unsigned char a) +{ + return !a; +} + +// ============================================================================ +// wxPNGHandler implementation +// ============================================================================ + +IMPLEMENT_DYNAMIC_CLASS(wxPNGHandler,wxImageHandler) + +#if wxUSE_STREAMS + +#ifndef PNGLINKAGEMODE + #ifdef PNGAPI + #define PNGLINKAGEMODE PNGAPI + #elif defined(__WATCOMC__) + // we need an explicit cdecl for Watcom, at least according to + // + // http://sf.net/tracker/index.php?func=detail&aid=651492&group_id=9863&atid=109863 + // + // more testing is needed for this however, please remove this comment + // if you can confirm that my fix works with Watcom 11 + #define PNGLINKAGEMODE cdecl + #else + #define PNGLINKAGEMODE LINKAGEMODE + #endif +#endif + + +// VS: wxPNGInfoStruct declared below is a hack that needs some explanation. +// First, let me describe what's the problem: libpng uses jmp_buf in +// its png_struct structure. Unfortunately, this structure is +// compiler-specific and may vary in size, so if you use libpng compiled +// as DLL with another compiler than the main executable, it may not work +// (this is for example the case with wxMGL port and SciTech MGL library +// that provides custom runtime-loadable libpng implementation with jmpbuf +// disabled altogether). Luckily, it is still possible to use setjmp() & +// longjmp() as long as the structure is not part of png_struct. +// +// Sadly, there's no clean way to attach user-defined data to png_struct. +// There is only one customizable place, png_struct.io_ptr, which is meant +// only for I/O routines and is set with png_set_read_fn or +// png_set_write_fn. The hacky part is that we use io_ptr to store +// a pointer to wxPNGInfoStruct that holds I/O structures _and_ jmp_buf. + +struct wxPNGInfoStruct +{ + jmp_buf jmpbuf; + bool verbose; + + union + { + wxInputStream *in; + wxOutputStream *out; + } stream; +}; + +#define WX_PNG_INFO(png_ptr) ((wxPNGInfoStruct*)png_get_io_ptr(png_ptr)) + +// ---------------------------------------------------------------------------- +// helper functions +// ---------------------------------------------------------------------------- + +extern "C" +{ + +void PNGLINKAGEMODE wx_PNG_stream_reader( png_structp png_ptr, png_bytep data, + png_size_t length ) +{ + WX_PNG_INFO(png_ptr)->stream.in->Read(data, length); +} + +void PNGLINKAGEMODE wx_PNG_stream_writer( png_structp png_ptr, png_bytep data, + png_size_t length ) +{ + WX_PNG_INFO(png_ptr)->stream.out->Write(data, length); +} + +void +PNGLINKAGEMODE wx_png_warning(png_structp png_ptr, png_const_charp message) +{ + wxPNGInfoStruct *info = png_ptr ? WX_PNG_INFO(png_ptr) : NULL; + if ( !info || info->verbose ) + wxLogWarning( wxString::FromAscii(message) ); +} + +// from pngerror.c +// so that the libpng doesn't send anything on stderr +void +PNGLINKAGEMODE wx_png_error(png_structp png_ptr, png_const_charp message) +{ + wx_png_warning(NULL, message); + + // we're not using libpng built-in jump buffer (see comment before + // wxPNGInfoStruct above) so we have to return ourselves, otherwise libpng + // would just abort + longjmp(WX_PNG_INFO(png_ptr)->jmpbuf, 1); +} + +} // extern "C" + +// ---------------------------------------------------------------------------- +// LoadFile() helpers +// ---------------------------------------------------------------------------- + +// determine the kind of transparency we need for this image: if the only alpha +// values it has are 0 (transparent) and 0xff (opaque) then we can simply +// create a mask for it, we should be ok with a simple mask but otherwise we +// need a full blown alpha channel in wxImage +// +// parameters: +// lines raw PNG data +// x, y starting position +// w, h size of the image +// numColBytes number of colour bytes (1 for grey scale, 3 for RGB) +// (NB: alpha always follows the colour bytes) +Transparency +CheckTransparency(unsigned char **lines, + png_uint_32 x, png_uint_32 y, png_uint_32 w, png_uint_32 h, + size_t numColBytes) +{ + // suppose that a mask will suffice and check all the remaining alpha + // values to see if it does + for ( ; y < h; y++ ) + { + // each pixel is numColBytes+1 bytes, offset into the current line by + // the current x position + unsigned const char *ptr = lines[y] + (x * (numColBytes + 1)); + + for ( png_uint_32 x2 = x; x2 < w; x2++ ) + { + // skip the grey or colour byte(s) + ptr += numColBytes; + + unsigned char a2 = *ptr++; + + if ( !IsTransparent(a2) && !IsOpaque(a2) ) + { + // not fully opaque nor fully transparent, hence need alpha + return Transparency_Alpha; + } + } + + // during the next loop iteration check all the pixels in the row + x = 0; + } + + // mask will be enough + return Transparency_Mask; +} + +unsigned char *InitAlpha(wxImage *image, png_uint_32 x, png_uint_32 y) +{ + // create alpha channel + image->SetAlpha(); + + unsigned char *alpha = image->GetAlpha(); + + // set alpha for the pixels we had so far + png_uint_32 end = y * image->GetWidth() + x; + for ( png_uint_32 i = 0; i < end; i++ ) + { + // all the previous pixels were opaque + *alpha++ = 0xff; + } + + return alpha; +} + +void +FindMaskColour(unsigned char **lines, png_uint_32 width, png_uint_32 height, + unsigned char& rMask, unsigned char& gMask, unsigned char& bMask) +{ + // choosing the colour for the mask is more + // difficult: we need to iterate over the entire + // image for this in order to choose an unused + // colour (this is not very efficient but what else + // can we do?) + wxImageHistogram h; + unsigned nentries = 0; + unsigned char r2, g2, b2; + for ( png_uint_32 y2 = 0; y2 < height; y2++ ) + { + const unsigned char *p = lines[y2]; + for ( png_uint_32 x2 = 0; x2 < width; x2++ ) + { + r2 = *p++; + g2 = *p++; + b2 = *p++; + ++p; // jump over alpha + + wxImageHistogramEntry& + entry = h[wxImageHistogram:: MakeKey(r2, g2, b2)]; + + if ( entry.value++ == 0 ) + entry.index = nentries++; + } + } + + if ( !h.FindFirstUnusedColour(&rMask, &gMask, &bMask) ) + { + wxLogWarning(_("Too many colours in PNG, the image may be slightly blurred.")); + + // use a fixed mask colour and we'll fudge + // the real pixels with this colour (see + // below) + rMask = 0xfe; + gMask = 0; + bMask = 0xff; + } +} + +// ---------------------------------------------------------------------------- +// reading PNGs +// ---------------------------------------------------------------------------- + +bool wxPNGHandler::DoCanRead( wxInputStream& stream ) +{ + unsigned char hdr[4]; + + if ( !stream.Read(hdr, WXSIZEOF(hdr)) ) + return false; + + return memcmp(hdr, "\211PNG", WXSIZEOF(hdr)) == 0; +} + +// convert data from RGB to wxImage format +static +void CopyDataFromPNG(wxImage *image, + unsigned char **lines, + png_uint_32 width, + png_uint_32 height, + int color_type) +{ + Transparency transparency = Transparency_None; + + // only non NULL if transparency == Transparency_Alpha + unsigned char *alpha = NULL; + + // RGB of the mask colour if transparency == Transparency_Mask + // (but init them anyhow to avoid compiler warnings) + unsigned char rMask = 0, + gMask = 0, + bMask = 0; + + unsigned char *ptrDst = image->GetData(); + if ( !(color_type & PNG_COLOR_MASK_COLOR) ) + { + // grey image: GAGAGA... where G == grey component and A == alpha + for ( png_uint_32 y = 0; y < height; y++ ) + { + const unsigned char *ptrSrc = lines[y]; + for ( png_uint_32 x = 0; x < width; x++ ) + { + unsigned char g = *ptrSrc++; + unsigned char a = *ptrSrc++; + + // the first time we encounter a transparent pixel we must + // decide about what to do about them + if ( !IsOpaque(a) && transparency == Transparency_None ) + { + // we'll need at least the mask for this image and + // maybe even full alpha channel info: the former is + // only enough if we have alpha values of 0 and 0xff + // only, otherwisewe need the latter + transparency = CheckTransparency + ( + lines, + x, y, + width, height, + 1 + ); + + if ( transparency == Transparency_Mask ) + { + // let's choose this colour for the mask: this is + // not a problem here as all the other pixels are + // grey, i.e. R == G == B which is not the case for + // this one so no confusion is possible + rMask = 0xff; + gMask = 0; + bMask = 0xff; + } + else // transparency == Transparency_Alpha + { + alpha = InitAlpha(image, x, y); + } + } + + switch ( transparency ) + { + case Transparency_Mask: + if ( IsTransparent(a) ) + { + *ptrDst++ = rMask; + *ptrDst++ = gMask; + *ptrDst++ = bMask; + break; + } + // else: !transparent + + // must be opaque then as otherwise we shouldn't be + // using the mask at all + wxASSERT_MSG( IsOpaque(a), _T("logic error") ); + + // fall through + + case Transparency_Alpha: + if ( alpha ) + *alpha++ = a; + // fall through + + case Transparency_None: + *ptrDst++ = g; + *ptrDst++ = g; + *ptrDst++ = g; + break; + } + } + } + } + else // colour image: RGBRGB... + { + for ( png_uint_32 y = 0; y < height; y++ ) + { + const unsigned char *ptrSrc = lines[y]; + for ( png_uint_32 x = 0; x < width; x++ ) + { + unsigned char r = *ptrSrc++; + unsigned char g = *ptrSrc++; + unsigned char b = *ptrSrc++; + unsigned char a = *ptrSrc++; + + // the logic here is the same as for the grey case except + // where noted + if ( !IsOpaque(a) && transparency == Transparency_None ) + { + transparency = CheckTransparency + ( + lines, + x, y, + width, height, + 3 + ); + + if ( transparency == Transparency_Mask ) + { + FindMaskColour(lines, width, height, + rMask, gMask, bMask); + } + else // transparency == Transparency_Alpha + { + alpha = InitAlpha(image, x, y); + } + + } + + switch ( transparency ) + { + case Transparency_Mask: + if ( IsTransparent(a) ) + { + *ptrDst++ = rMask; + *ptrDst++ = gMask; + *ptrDst++ = bMask; + break; + } + else // !transparent + { + // must be opaque then as otherwise we shouldn't be + // using the mask at all + wxASSERT_MSG( IsOpaque(a), _T("logic error") ); + + // if we couldn't find a unique colour for the + // mask, we can have real pixels with the same + // value as the mask and it's better to slightly + // change their colour than to make them + // transparent + if ( r == rMask && g == gMask && b == bMask ) + { + r++; + } + } + + // fall through + + case Transparency_Alpha: + if ( alpha ) + *alpha++ = a; + // fall through + + case Transparency_None: + *ptrDst++ = r; + *ptrDst++ = g; + *ptrDst++ = b; + break; + } + } + } + } + + if ( transparency == Transparency_Mask ) + { + image->SetMaskColour(rMask, gMask, bMask); + } +} + +// temporarily disable the warning C4611 (interaction between '_setjmp' and +// C++ object destruction is non-portable) - I don't see any dtors here +#ifdef __VISUALC__ + #pragma warning(disable:4611) +#endif /* VC++ */ + +bool +wxPNGHandler::LoadFile(wxImage *image, + wxInputStream& stream, + bool verbose, + int WXUNUSED(index)) +{ + // VZ: as this function uses setjmp() the only fool-proof error handling + // method is to use goto (setjmp is not really C++ dtors friendly...) + + unsigned char **lines = NULL; + png_infop info_ptr = (png_infop) NULL; + wxPNGInfoStruct wxinfo; + + png_uint_32 i, width, height = 0; + int bit_depth, color_type, interlace_type; + + wxinfo.verbose = verbose; + wxinfo.stream.in = &stream; + + image->Destroy(); + + png_structp png_ptr = png_create_read_struct + ( + PNG_LIBPNG_VER_STRING, + (voidp) NULL, + wx_png_error, + wx_png_warning + ); + if (!png_ptr) + goto error; + + // NB: please see the comment near wxPNGInfoStruct declaration for + // explanation why this line is mandatory + png_set_read_fn( png_ptr, &wxinfo, wx_PNG_stream_reader); + + info_ptr = png_create_info_struct( png_ptr ); + if (!info_ptr) + goto error; + + if (setjmp(wxinfo.jmpbuf)) + goto error; + + png_read_info( png_ptr, info_ptr ); + png_get_IHDR( png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, (int*) NULL, (int*) NULL ); + + if (color_type == PNG_COLOR_TYPE_PALETTE) + png_set_expand( png_ptr ); + + // Fix for Bug [ 439207 ] Monochrome PNG images come up black + if (bit_depth < 8) + png_set_expand( png_ptr ); + + png_set_strip_16( png_ptr ); + png_set_packing( png_ptr ); + if (png_get_valid( png_ptr, info_ptr, PNG_INFO_tRNS)) + png_set_expand( png_ptr ); + png_set_filler( png_ptr, 0xff, PNG_FILLER_AFTER ); + + image->Create((int)width, (int)height, (bool) false /* no need to init pixels */); + + if (!image->Ok()) + goto error; + + lines = (unsigned char **)malloc( (size_t)(height * sizeof(unsigned char *)) ); + if ( !lines ) + goto error; + + for (i = 0; i < height; i++) + { + if ((lines[i] = (unsigned char *)malloc( (size_t)(width * (sizeof(unsigned char) * 4)))) == NULL) + { + for ( unsigned int n = 0; n < i; n++ ) + free( lines[n] ); + goto error; + } + } + + png_read_image( png_ptr, lines ); + png_read_end( png_ptr, info_ptr ); + +#if wxUSE_PALETTE + if (color_type == PNG_COLOR_TYPE_PALETTE) + { + const size_t ncolors = info_ptr->num_palette; + unsigned char* r = new unsigned char[ncolors]; + unsigned char* g = new unsigned char[ncolors]; + unsigned char* b = new unsigned char[ncolors]; + + for (size_t j = 0; j < ncolors; j++) + { + r[j] = info_ptr->palette[j].red; + g[j] = info_ptr->palette[j].green; + b[j] = info_ptr->palette[j].blue; + } + + image->SetPalette(wxPalette(ncolors, r, g, b)); + delete[] r; + delete[] g; + delete[] b; + } +#endif // wxUSE_PALETTE + + png_destroy_read_struct( &png_ptr, &info_ptr, (png_infopp) NULL ); + + // loaded successfully, now init wxImage with this data + CopyDataFromPNG(image, lines, width, height, color_type); + + for ( i = 0; i < height; i++ ) + free( lines[i] ); + free( lines ); + + return true; + +error: + if (verbose) + wxLogError(_("Couldn't load a PNG image - file is corrupted or not enough memory.")); + + if ( image->Ok() ) + { + image->Destroy(); + } + + if ( lines ) + { + for ( unsigned int n = 0; n < height; n++ ) + free( lines[n] ); + + free( lines ); + } + + if ( png_ptr ) + { + if ( info_ptr ) + { + png_destroy_read_struct( &png_ptr, &info_ptr, (png_infopp) NULL ); + free(info_ptr); + } + else + png_destroy_read_struct( &png_ptr, (png_infopp) NULL, (png_infopp) NULL ); + } + return false; +} + +// ---------------------------------------------------------------------------- +// writing PNGs +// ---------------------------------------------------------------------------- + +bool wxPNGHandler::SaveFile( wxImage *image, wxOutputStream& stream, bool verbose ) +{ + wxPNGInfoStruct wxinfo; + + wxinfo.verbose = verbose; + wxinfo.stream.out = &stream; + + png_structp png_ptr = png_create_write_struct + ( + PNG_LIBPNG_VER_STRING, + NULL, + wx_png_error, + wx_png_warning + ); + if (!png_ptr) + { + if (verbose) + wxLogError(_("Couldn't save PNG image.")); + return false; + } + + png_infop info_ptr = png_create_info_struct(png_ptr); + if (info_ptr == NULL) + { + png_destroy_write_struct( &png_ptr, (png_infopp)NULL ); + if (verbose) + wxLogError(_("Couldn't save PNG image.")); + return false; + } + + if (setjmp(wxinfo.jmpbuf)) + { + png_destroy_write_struct( &png_ptr, (png_infopp)NULL ); + if (verbose) + wxLogError(_("Couldn't save PNG image.")); + return false; + } + + // NB: please see the comment near wxPNGInfoStruct declaration for + // explanation why this line is mandatory + png_set_write_fn( png_ptr, &wxinfo, wx_PNG_stream_writer, NULL); + + const int iColorType = image->HasOption(wxIMAGE_OPTION_PNG_FORMAT) + ? image->GetOptionInt(wxIMAGE_OPTION_PNG_FORMAT) + : wxPNG_TYPE_COLOUR; + const int iBitDepth = image->HasOption(wxIMAGE_OPTION_PNG_BITDEPTH) + ? image->GetOptionInt(wxIMAGE_OPTION_PNG_BITDEPTH) + : 8; + + wxASSERT_MSG( iBitDepth == 8 || iBitDepth == 16, + _T("PNG bit depth must be 8 or 16") ); + + bool bHasAlpha = image->HasAlpha(); + bool bHasMask = image->HasMask(); + bool bUseAlpha = bHasAlpha || bHasMask; + + int iPngColorType; + if ( iColorType==wxPNG_TYPE_COLOUR ) + { + iPngColorType = bUseAlpha ? PNG_COLOR_TYPE_RGB_ALPHA + : PNG_COLOR_TYPE_RGB; + } + else + { + iPngColorType = bUseAlpha ? PNG_COLOR_TYPE_GRAY_ALPHA + : PNG_COLOR_TYPE_GRAY; + } + + png_set_IHDR( png_ptr, info_ptr, image->GetWidth(), image->GetHeight(), + iBitDepth, iPngColorType, + PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, + PNG_FILTER_TYPE_BASE); + + int iElements; + png_color_8 sig_bit; + + if ( iPngColorType & PNG_COLOR_MASK_COLOR ) + { + sig_bit.red = + sig_bit.green = + sig_bit.blue = (png_byte)iBitDepth; + iElements = 3; + } + else // grey + { + sig_bit.gray = (png_byte)iBitDepth; + iElements = 1; + } + + if ( iPngColorType & PNG_COLOR_MASK_ALPHA ) + { + sig_bit.alpha = (png_byte)iBitDepth; + iElements++; + } + + if ( iBitDepth == 16 ) + iElements *= 2; + + png_set_sBIT( png_ptr, info_ptr, &sig_bit ); + png_write_info( png_ptr, info_ptr ); + png_set_shift( png_ptr, &sig_bit ); + png_set_packing( png_ptr ); + + unsigned char * + data = (unsigned char *)malloc( image->GetWidth() * iElements ); + if ( !data ) + { + png_destroy_write_struct( &png_ptr, (png_infopp)NULL ); + return false; + } + + unsigned char * + pAlpha = (unsigned char *)(bHasAlpha ? image->GetAlpha() : NULL); + int iHeight = image->GetHeight(); + int iWidth = image->GetWidth(); + + unsigned char uchMaskRed = 0, uchMaskGreen = 0, uchMaskBlue = 0; + + if ( bHasMask ) + { + uchMaskRed = image->GetMaskRed(); + uchMaskGreen = image->GetMaskGreen(); + uchMaskBlue = image->GetMaskBlue(); + } + + unsigned char *pColors = image->GetData(); + + for (int y = 0; y != iHeight; ++y) + { + unsigned char *pData = data; + for (int x = 0; x != iWidth; x++) + { + unsigned char uchRed = *pColors++; + unsigned char uchGreen = *pColors++; + unsigned char uchBlue = *pColors++; + + switch ( iColorType ) + { + default: + wxFAIL_MSG( _T("unknown wxPNG_TYPE_XXX") ); + // fall through + + case wxPNG_TYPE_COLOUR: + *pData++ = uchRed; + if ( iBitDepth == 16 ) + *pData++ = 0; + *pData++ = uchGreen; + if ( iBitDepth == 16 ) + *pData++ = 0; + *pData++ = uchBlue; + if ( iBitDepth == 16 ) + *pData++ = 0; + break; + + case wxPNG_TYPE_GREY: + { + // where do these coefficients come from? maybe we + // should have image options for them as well? + unsigned uiColor = + (unsigned) (76.544*(unsigned)uchRed + + 150.272*(unsigned)uchGreen + + 36.864*(unsigned)uchBlue); + + *pData++ = (unsigned char)((uiColor >> 8) & 0xFF); + if ( iBitDepth == 16 ) + *pData++ = (unsigned char)(uiColor & 0xFF); + } + break; + + case wxPNG_TYPE_GREY_RED: + *pData++ = uchRed; + if ( iBitDepth == 16 ) + *pData++ = 0; + break; + } + + if ( bUseAlpha ) + { + unsigned char uchAlpha = 255; + if ( bHasAlpha ) + uchAlpha = *pAlpha++; + + if ( bHasMask ) + { + if ( (uchRed == uchMaskRed) + && (uchGreen == uchMaskGreen) + && (uchBlue == uchMaskBlue) ) + uchAlpha = 0; + } + + *pData++ = uchAlpha; + if ( iBitDepth == 16 ) + *pData++ = 0; + } + } + + png_bytep row_ptr = data; + png_write_rows( png_ptr, &row_ptr, 1 ); + } + + free(data); + png_write_end( png_ptr, info_ptr ); + png_destroy_write_struct( &png_ptr, (png_infopp)&info_ptr ); + + return true; +} + +#ifdef __VISUALC__ + #pragma warning(default:4611) +#endif /* VC++ */ + +#endif // wxUSE_STREAMS + +#endif // wxUSE_LIBPNG diff --git a/Externals/wxWidgets/src/common/imagpnm.cpp b/Externals/wxWidgets/src/common/imagpnm.cpp index ba9c5c8bf6..3fcc959169 100644 --- a/Externals/wxWidgets/src/common/imagpnm.cpp +++ b/Externals/wxWidgets/src/common/imagpnm.cpp @@ -1,201 +1,201 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/imagpnm.cpp -// Purpose: wxImage PNM handler -// Author: Sylvain Bougnoux -// RCS-ID: $Id: imagpnm.cpp 46311 2007-06-03 22:14:32Z VZ $ -// Copyright: (c) Sylvain Bougnoux -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_IMAGE && wxUSE_PNM - -#include "wx/imagpnm.h" - -#ifndef WX_PRECOMP - #include "wx/intl.h" - #include "wx/log.h" -#endif - -#include "wx/txtstrm.h" - -//----------------------------------------------------------------------------- -// wxBMPHandler -//----------------------------------------------------------------------------- - -IMPLEMENT_DYNAMIC_CLASS(wxPNMHandler,wxImageHandler) - -#if wxUSE_STREAMS - -void Skip_Comment(wxInputStream &stream) -{ - wxTextInputStream text_stream(stream); - - if (stream.Peek()==wxT('#')) - { - text_stream.ReadLine(); - Skip_Comment(stream); - } -} - -bool wxPNMHandler::LoadFile( wxImage *image, wxInputStream& stream, bool verbose, int WXUNUSED(index) ) -{ - wxUint32 width, height; - wxUint16 maxval; - char c(0); - - image->Destroy(); - - /* - * Read the PNM header - */ - - wxBufferedInputStream buf_stream(stream); - wxTextInputStream text_stream(buf_stream); - - Skip_Comment(buf_stream); - if (buf_stream.GetC()==wxT('P')) c=buf_stream.GetC(); - - switch (c) - { - case wxT('2'): // ASCII Grey - case wxT('3'): // ASCII RGB - case wxT('5'): // RAW Grey - case wxT('6'): break; - default: - if (verbose) wxLogError(_("PNM: File format is not recognized.")); - return false; - } - - text_stream.ReadLine(); // for the \n - Skip_Comment(buf_stream); - text_stream >> width >> height ; - Skip_Comment(buf_stream); - text_stream >> maxval; - - //cout << line << " " << width << " " << height << " " << maxval << endl; - image->Create( width, height ); - unsigned char *ptr = image->GetData(); - if (!ptr) - { - if (verbose) - wxLogError( _("PNM: Couldn't allocate memory.") ); - return false; - } - - - if (c=='2') // Ascii GREY - { - wxUint32 value, size=width*height; - for (wxUint32 i=0; iSetMask( false ); - - const wxStreamError err = buf_stream.GetLastError(); - return err == wxSTREAM_NO_ERROR || err == wxSTREAM_EOF; -} - -bool wxPNMHandler::SaveFile( wxImage *image, wxOutputStream& stream, bool WXUNUSED(verbose) ) -{ - wxTextOutputStream text_stream(stream); - - //text_stream << "P6" << endl - //<< image->GetWidth() << " " << image->GetHeight() << endl - //<< "255" << endl; - text_stream << wxT("P6\n") << image->GetWidth() << wxT(" ") << image->GetHeight() << wxT("\n255\n"); - stream.Write(image->GetData(),3*image->GetWidth()*image->GetHeight()); - - return stream.IsOk(); -} - -bool wxPNMHandler::DoCanRead( wxInputStream& stream ) -{ - Skip_Comment(stream); - - if ( stream.GetC() == 'P' ) - { - switch ( stream.GetC() ) - { - case '2': // ASCII Grey - case '3': // ASCII RGB - case '5': // RAW Grey - case '6': // RAW RGB - return true; - } - } - - return false; -} - - -#endif // wxUSE_STREAMS - -#endif // wxUSE_IMAGE && wxUSE_PNM +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/imagpnm.cpp +// Purpose: wxImage PNM handler +// Author: Sylvain Bougnoux +// RCS-ID: $Id: imagpnm.cpp 46311 2007-06-03 22:14:32Z VZ $ +// Copyright: (c) Sylvain Bougnoux +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_IMAGE && wxUSE_PNM + +#include "wx/imagpnm.h" + +#ifndef WX_PRECOMP + #include "wx/intl.h" + #include "wx/log.h" +#endif + +#include "wx/txtstrm.h" + +//----------------------------------------------------------------------------- +// wxBMPHandler +//----------------------------------------------------------------------------- + +IMPLEMENT_DYNAMIC_CLASS(wxPNMHandler,wxImageHandler) + +#if wxUSE_STREAMS + +void Skip_Comment(wxInputStream &stream) +{ + wxTextInputStream text_stream(stream); + + if (stream.Peek()==wxT('#')) + { + text_stream.ReadLine(); + Skip_Comment(stream); + } +} + +bool wxPNMHandler::LoadFile( wxImage *image, wxInputStream& stream, bool verbose, int WXUNUSED(index) ) +{ + wxUint32 width, height; + wxUint16 maxval; + char c(0); + + image->Destroy(); + + /* + * Read the PNM header + */ + + wxBufferedInputStream buf_stream(stream); + wxTextInputStream text_stream(buf_stream); + + Skip_Comment(buf_stream); + if (buf_stream.GetC()==wxT('P')) c=buf_stream.GetC(); + + switch (c) + { + case wxT('2'): // ASCII Grey + case wxT('3'): // ASCII RGB + case wxT('5'): // RAW Grey + case wxT('6'): break; + default: + if (verbose) wxLogError(_("PNM: File format is not recognized.")); + return false; + } + + text_stream.ReadLine(); // for the \n + Skip_Comment(buf_stream); + text_stream >> width >> height ; + Skip_Comment(buf_stream); + text_stream >> maxval; + + //cout << line << " " << width << " " << height << " " << maxval << endl; + image->Create( width, height ); + unsigned char *ptr = image->GetData(); + if (!ptr) + { + if (verbose) + wxLogError( _("PNM: Couldn't allocate memory.") ); + return false; + } + + + if (c=='2') // Ascii GREY + { + wxUint32 value, size=width*height; + for (wxUint32 i=0; iSetMask( false ); + + const wxStreamError err = buf_stream.GetLastError(); + return err == wxSTREAM_NO_ERROR || err == wxSTREAM_EOF; +} + +bool wxPNMHandler::SaveFile( wxImage *image, wxOutputStream& stream, bool WXUNUSED(verbose) ) +{ + wxTextOutputStream text_stream(stream); + + //text_stream << "P6" << endl + //<< image->GetWidth() << " " << image->GetHeight() << endl + //<< "255" << endl; + text_stream << wxT("P6\n") << image->GetWidth() << wxT(" ") << image->GetHeight() << wxT("\n255\n"); + stream.Write(image->GetData(),3*image->GetWidth()*image->GetHeight()); + + return stream.IsOk(); +} + +bool wxPNMHandler::DoCanRead( wxInputStream& stream ) +{ + Skip_Comment(stream); + + if ( stream.GetC() == 'P' ) + { + switch ( stream.GetC() ) + { + case '2': // ASCII Grey + case '3': // ASCII RGB + case '5': // RAW Grey + case '6': // RAW RGB + return true; + } + } + + return false; +} + + +#endif // wxUSE_STREAMS + +#endif // wxUSE_IMAGE && wxUSE_PNM diff --git a/Externals/wxWidgets/src/common/imagtga.cpp b/Externals/wxWidgets/src/common/imagtga.cpp index 458bc27c76..c9b39dce7d 100644 --- a/Externals/wxWidgets/src/common/imagtga.cpp +++ b/Externals/wxWidgets/src/common/imagtga.cpp @@ -1,750 +1,750 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: imagtga.cpp -// Purpose: wxImage TGA handler -// Author: Seth Jackson -// CVS-ID: $Id: imagtga.cpp 43681 2006-11-27 15:01:58Z VZ $ -// Copyright: (c) 2005 Seth Jackson -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_IMAGE && wxUSE_TGA - -#ifndef WX_PRECOMP - #include "wx/palette.h" -#endif - -#include "wx/imagtga.h" -#include "wx/log.h" -#include "wx/scopeguard.h" - -// ---------------------------------------------------------------------------- -// constants -// ---------------------------------------------------------------------------- - -// TGA error codes. -enum -{ - wxTGA_OK = 0, - wxTGA_INVFORMAT = 1, - wxTGA_MEMERR = 2 -}; - -// TGA header bytes. -enum -{ - HDR_OFFSET = 0, - HDR_COLORTYPE = 1, - HDR_IMAGETYPE = 2, - HDR_PALETTESTART = 3, - HDR_PALETTELENGTH = 5, - HDR_PALETTEBITS = 7, - HDR_XORIGIN = 8, - HDR_YORIGIN = 10, - HDR_WIDTH = 12, - HDR_HEIGHT = 14, - HDR_BPP = 16, - HDR_ORIENTATION = 17, - HDR_SIZE -}; - -// TGA color types. -enum -{ - wxTGA_UNMAPPED = 0, - wxTGA_MAPPED = 1 -}; - -// ============================================================================ -// implementation -// ============================================================================ - -IMPLEMENT_DYNAMIC_CLASS(wxTGAHandler, wxImageHandler) - -#if wxUSE_STREAMS - -// ---------------------------------------------------------------------------- -// worker functions -// ---------------------------------------------------------------------------- - -static -void FlipTGA(unsigned char* imageData, int width, int height, short pixelSize) -{ - int lineLength = width * pixelSize; - unsigned char *line1 = imageData; - unsigned char *line2 = &imageData[lineLength * (height - 1)]; - - unsigned char temp; - for ( ; line1 < line2; line2 -= (lineLength * 2)) - { - for (int index = 0; index < lineLength; line1++, line2++, index++) - { - temp = *line1; - *line1 = *line2; - *line2 = temp; - } - } -} - -static -void DecodeRLE(unsigned char* imageData, unsigned long imageSize, - short pixelSize, wxInputStream& stream) -{ - unsigned long index = 0; - unsigned char current; - unsigned int length; - unsigned char buf[4]; - - while (index < imageSize) - { - current = stream.GetC(); - - // RLE packet. - if ( current & 0x80 ) - { - // Get the run length of the packet. - current &= 0x7f; - - current++; - - length = current; - - index += current * pixelSize; - - // Repeat the pixel length times. - stream.Read(buf, pixelSize); - - for (unsigned int i = 0; i < length; i++) - { - memcpy(imageData, buf, pixelSize); - - imageData += pixelSize; - } - } - else // Raw packet. - { - // Get the run length of the packet. - current++; - - length = current * pixelSize; - - index += length; - - // Write the next length pixels directly to the image data. - stream.Read(imageData, length); - - imageData += length; - } - } -} - -static -int ReadTGA(wxImage* image, wxInputStream& stream) -{ - // Read in the TGA header - unsigned char hdr[HDR_SIZE]; - stream.Read(hdr, HDR_SIZE); - - short offset = hdr[HDR_OFFSET] + HDR_SIZE; - short colorType = hdr[HDR_COLORTYPE]; - short imageType = hdr[HDR_IMAGETYPE]; - int paletteLength = hdr[HDR_PALETTELENGTH] + 256 * hdr[HDR_PALETTELENGTH + 1]; - int width = (hdr[HDR_WIDTH] + 256 * hdr[HDR_WIDTH + 1]) - - (hdr[HDR_XORIGIN] + 256 * hdr[HDR_XORIGIN + 1]); - int height = (hdr[HDR_HEIGHT] + 256 * hdr[HDR_HEIGHT + 1]) - - (hdr[HDR_YORIGIN] + 256 * hdr[HDR_YORIGIN + 1]); - short bpp = hdr[HDR_BPP]; - short orientation = hdr[HDR_ORIENTATION] & 0x20; - - image->Create(width, height); - - if (!image->Ok()) - { - return wxTGA_MEMERR; - } - - const short pixelSize = bpp / 8; - - const unsigned long imageSize = width * height * pixelSize; - - unsigned char *imageData = (unsigned char* )malloc(imageSize); - - if (!imageData) - { - return wxTGA_MEMERR; - } - - wxON_BLOCK_EXIT1(free, imageData); - - unsigned char *dst = image->GetData(); - - unsigned char* alpha = NULL; - if (bpp == 16 || bpp == 32) - { - image->SetAlpha(); - - alpha = image->GetAlpha(); - } - - // Seek from the offset we got from the TGA header. - stream.SeekI(offset, wxFromStart); - - // Load a palette if we have one. - if (colorType == wxTGA_MAPPED) - { - unsigned char buf[3]; - - unsigned char* r = new unsigned char[paletteLength]; - unsigned char* g = new unsigned char[paletteLength]; - unsigned char* b = new unsigned char[paletteLength]; - - for (int i = 0; i < paletteLength; i++) - { - stream.Read(buf, 3); - - r[i] = buf[2]; - g[i] = buf[1]; - b[i] = buf[0]; - } - -#if wxUSE_PALETTE - // Set the palette of the image. - image->SetPalette(wxPalette(paletteLength, r, g, b)); -#endif // wxUSE_PALETTE - - delete[] r; - delete[] g; - delete[] b; - } - - // Handle the various TGA formats we support. - - switch (imageType) - { -#if wxUSE_PALETTE - // Raw indexed. - - case 1: - { - const wxPalette& palette = image->GetPalette(); - unsigned char r; - unsigned char g; - unsigned char b; - - // No compression read the data directly to imageData. - - stream.Read(imageData, imageSize); - - // If orientation == 0, then the image is stored upside down. - // We need to store it right side up. - - if (orientation == 0) - { - FlipTGA(imageData, width, height, pixelSize); - } - - // Handle the different pixel depths. - - switch (bpp) - { - // 8 bpp. - - case 8: - { - for (unsigned long index = 0; index < imageSize; index += pixelSize) - { - palette.GetRGB(imageData[index], &r, &g, &b); - - *(dst++) = r; - *(dst++) = g; - *(dst++) = b; - } - } - break; - - // 16 bpp. - - case 16: - { - for (unsigned long index = 0; index < imageSize; index += pixelSize) - { - palette.GetRGB(imageData[index], &r, &g, &b); - - *(dst++) = r; - *(dst++) = g; - *(dst++) = b; - *(alpha++) = (imageData[index + 1] & 0x80) ? 0 : 255; - } - } - break; - - default: - return wxTGA_INVFORMAT; - } - } - break; -#endif // wxUSE_PALETTE - - // Raw RGB. - - case 2: - { - // No compression read the data directly to imageData. - - stream.Read(imageData, imageSize); - - // If orientation == 0, then the image is stored upside down. - // We need to store it right side up. - - if (orientation == 0) - { - FlipTGA(imageData, width, height, pixelSize); - } - - // Handle the different pixel depths. - - switch (bpp) - { - //16 bpp. - - case 16: - { - unsigned char temp; - - for (unsigned long index = 0; index < imageSize; index += pixelSize) - { - temp = (imageData[index + 1] & 0x7c) << 1; - temp |= temp >> 5; - *(dst++) = temp; - - temp = ((imageData[index + 1] & 0x03) << 6) | ((imageData[index] & 0xe0) >> 2); - temp |= temp >> 5; - *(dst++) = temp; - - temp = (imageData[index] & 0x1f) << 3; - temp |= temp >> 5; - *(dst++) = temp; - - *(alpha++) = (imageData[index + 1] & 0x80) ? 0 : 255; - } - } - break; - - // 24 bpp. - - case 24: - { - for (unsigned long index = 0; index < imageSize; index += pixelSize) - { - *(dst++) = imageData[index + 2]; - *(dst++) = imageData[index + 1]; - *(dst++) = imageData[index]; - } - } - break; - - // 32 bpp. - - case 32: - { - for (unsigned long index = 0; index < imageSize; index += pixelSize) - { - *(dst++) = imageData[index + 2]; - *(dst++) = imageData[index + 1]; - *(dst++) = imageData[index]; - *(alpha++) = imageData[index + 3]; - } - } - break; - - default: - return wxTGA_INVFORMAT; - } - } - break; - - // Raw grayscale. - - case 3: - { - // No compression read the data directly to imageData. - - stream.Read(imageData, imageSize); - - // If orientation == 0, then the image is stored upside down. - // We need to store it right side up. - - if (orientation == 0) - { - FlipTGA(imageData, width, height, pixelSize); - } - - // Handle the different pixel depths. - - switch (bpp) - { - // 8 bpp. - - case 8: - { - for (unsigned long index = 0; index < imageSize; index += pixelSize) - { - *(dst++) = imageData[index]; - *(dst++) = imageData[index]; - *(dst++) = imageData[index]; - } - } - break; - - // 16 bpp. - - case 16: - { - for (unsigned long index = 0; index < imageSize; index += pixelSize) - { - *(dst++) = imageData[index]; - *(dst++) = imageData[index]; - *(dst++) = imageData[index]; - *(alpha++) = imageData[index + 1]; - } - } - break; - - default: - return wxTGA_INVFORMAT; - } - } - break; - -#if wxUSE_PALETTE - // RLE indexed. - - case 9: - { - const wxPalette& palette = image->GetPalette(); - unsigned char r; - unsigned char g; - unsigned char b; - - // Decode the RLE data. - - DecodeRLE(imageData, imageSize, pixelSize, stream); - - // If orientation == 0, then the image is stored upside down. - // We need to store it right side up. - - if (orientation == 0) - { - FlipTGA(imageData, width, height, pixelSize); - } - - // Handle the different pixel depths. - - switch (bpp) - { - // 8 bpp. - - case 8: - { - for (unsigned long index = 0; index < imageSize; index += pixelSize) - { - palette.GetRGB(imageData[index], &r, &g, &b); - - *(dst++) = r; - *(dst++) = g; - *(dst++) = b; - } - } - break; - - // 16 bpp. - - case 16: - { - for (unsigned long index = 0; index < imageSize; index += pixelSize) - { - palette.GetRGB(imageData[index], &r, &g, &b); - - *(dst++) = r; - *(dst++) = g; - *(dst++) = b; - *(alpha++) = (imageData[index + 1] & 0x80) ? 0 : 255; - } - } - break; - - default: - return wxTGA_INVFORMAT; - } - } - break; -#endif // wxUSE_PALETTE - - // RLE RGB. - - case 10: - { - // Decode the RLE data. - - DecodeRLE(imageData, imageSize, pixelSize, stream); - - // If orientation == 0, then the image is stored upside down. - // We need to store it right side up. - - if (orientation == 0) - { - FlipTGA(imageData, width, height, pixelSize); - } - - // Handle the different pixel depths. - - switch (bpp) - { - //16 bpp. - - case 16: - { - unsigned char temp; - - for (unsigned long index = 0; index < imageSize; index += pixelSize) - { - temp = (imageData[index + 1] & 0x7c) << 1; - temp |= temp >> 5; - *(dst++) = temp; - - temp = ((imageData[index + 1] & 0x03) << 6) | ((imageData[index] & 0xe0) >> 2); - temp |= temp >> 5; - *(dst++) = temp; - - temp = (imageData[index] & 0x1f) << 3; - temp |= temp >> 5; - *(dst++) = temp; - - *(alpha++) = (imageData[index + 1] & 0x80) ? 0 : 255; - } - } - break; - - // 24 bpp. - - case 24: - { - for (unsigned long index = 0; index < imageSize; index += pixelSize) - { - *(dst++) = imageData[index + 2]; - *(dst++) = imageData[index + 1]; - *(dst++) = imageData[index]; - } - } - break; - - // 32 bpp. - - case 32: - { - for (unsigned long index = 0; index < imageSize; index += pixelSize) - { - *(dst++) = imageData[index + 2]; - *(dst++) = imageData[index + 1]; - *(dst++) = imageData[index]; - *(alpha++) = imageData[index + 3]; - } - } - break; - - default: - return wxTGA_INVFORMAT; - } - } - break; - - // RLE grayscale. - - case 11: - { - // Decode the RLE data. - - DecodeRLE(imageData, imageSize, pixelSize, stream); - - // If orientation == 0, then the image is stored upside down. - // We need to store it right side up. - - if (orientation == 0) - { - FlipTGA(imageData, width, height, pixelSize); - } - - // Handle the different pixel depths. - - switch (bpp) - { - // 8 bpp. - - case 8: - { - for (unsigned long index = 0; index < imageSize; index += pixelSize) - { - *(dst++) = imageData[index]; - *(dst++) = imageData[index]; - *(dst++) = imageData[index]; - } - } - break; - - // 16 bpp. - - case 16: - { - for (unsigned long index = 0; index < imageSize; index += pixelSize) - { - *(dst++) = imageData[index]; - *(dst++) = imageData[index]; - *(dst++) = imageData[index]; - *(alpha++) = imageData[index + 1]; - } - } - break; - - default: - return wxTGA_INVFORMAT; - } - } - break; - - default: - return wxTGA_INVFORMAT; - } - - return wxTGA_OK; -} - -static -int SaveTGA(wxImage* WXUNUSED(image), wxOutputStream& WXUNUSED(stream)) -{ - wxLogError(wxT("Saving in TGA format is not implemented.")); - - return wxTGA_OK; -} - -// ---------------------------------------------------------------------------- -// wxTGAHandler -// ---------------------------------------------------------------------------- - -bool wxTGAHandler::LoadFile(wxImage* image, - wxInputStream& stream, - bool verbose, - int WXUNUSED(index)) -{ - if ( !CanRead(stream) ) - { - if ( verbose ) - wxLogError(wxT("TGA: this is not a TGA file.")); - - return false; - } - - image->Destroy(); - - int error = ReadTGA(image, stream); - if ( error != wxTGA_OK ) - { - if ( verbose ) - { - switch ( error ) - { - case wxTGA_INVFORMAT: - wxLogError(wxT("TGA: image format unsupported.")); - break; - - case wxTGA_MEMERR: - wxLogError(wxT("TGA: couldn't allocate memory.")); - break; - - default: - wxLogError(wxT("TGA: unknown error!")); - } - } - - image->Destroy(); - - return false; - } - - return true; -} - -bool wxTGAHandler::SaveFile(wxImage* image, wxOutputStream& stream, bool verbose) -{ - int error = SaveTGA(image, stream); - - if ( error != wxTGA_OK ) - { - if ( verbose ) - { - switch ( error ) - { - case wxTGA_INVFORMAT: - wxLogError(wxT("TGA: invalid image.")); - break; - - case wxTGA_MEMERR: - wxLogError(wxT("TGA: couldn't allocate memory.")); - break; - - default: - wxLogError(wxT("TGA: unknown error!")); - } - } - - return false; - } - - return true; -} - -bool wxTGAHandler::DoCanRead(wxInputStream& stream) -{ - // read the fixed-size TGA headers - unsigned char hdr[HDR_SIZE]; - stream.Read(hdr, HDR_SIZE); - - // Check wether we can read the file or not. - - short colorType = hdr[HDR_COLORTYPE]; - if ( colorType != wxTGA_UNMAPPED && colorType != wxTGA_MAPPED ) - { - return false; - } - - short imageType = hdr[HDR_IMAGETYPE]; - if ( imageType == 0 || imageType == 32 || imageType == 33 ) - { - return false; - } - - short bpp = hdr[HDR_BPP]; - if ( bpp != 8 && bpp != 16 && bpp != 24 && bpp != 32 ) - { - return false; - } - - return true; -} - -#endif // wxUSE_STREAMS - -#endif // wxUSE_IMAGE && wxUSE_TGA +///////////////////////////////////////////////////////////////////////////// +// Name: imagtga.cpp +// Purpose: wxImage TGA handler +// Author: Seth Jackson +// CVS-ID: $Id: imagtga.cpp 43681 2006-11-27 15:01:58Z VZ $ +// Copyright: (c) 2005 Seth Jackson +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_IMAGE && wxUSE_TGA + +#ifndef WX_PRECOMP + #include "wx/palette.h" +#endif + +#include "wx/imagtga.h" +#include "wx/log.h" +#include "wx/scopeguard.h" + +// ---------------------------------------------------------------------------- +// constants +// ---------------------------------------------------------------------------- + +// TGA error codes. +enum +{ + wxTGA_OK = 0, + wxTGA_INVFORMAT = 1, + wxTGA_MEMERR = 2 +}; + +// TGA header bytes. +enum +{ + HDR_OFFSET = 0, + HDR_COLORTYPE = 1, + HDR_IMAGETYPE = 2, + HDR_PALETTESTART = 3, + HDR_PALETTELENGTH = 5, + HDR_PALETTEBITS = 7, + HDR_XORIGIN = 8, + HDR_YORIGIN = 10, + HDR_WIDTH = 12, + HDR_HEIGHT = 14, + HDR_BPP = 16, + HDR_ORIENTATION = 17, + HDR_SIZE +}; + +// TGA color types. +enum +{ + wxTGA_UNMAPPED = 0, + wxTGA_MAPPED = 1 +}; + +// ============================================================================ +// implementation +// ============================================================================ + +IMPLEMENT_DYNAMIC_CLASS(wxTGAHandler, wxImageHandler) + +#if wxUSE_STREAMS + +// ---------------------------------------------------------------------------- +// worker functions +// ---------------------------------------------------------------------------- + +static +void FlipTGA(unsigned char* imageData, int width, int height, short pixelSize) +{ + int lineLength = width * pixelSize; + unsigned char *line1 = imageData; + unsigned char *line2 = &imageData[lineLength * (height - 1)]; + + unsigned char temp; + for ( ; line1 < line2; line2 -= (lineLength * 2)) + { + for (int index = 0; index < lineLength; line1++, line2++, index++) + { + temp = *line1; + *line1 = *line2; + *line2 = temp; + } + } +} + +static +void DecodeRLE(unsigned char* imageData, unsigned long imageSize, + short pixelSize, wxInputStream& stream) +{ + unsigned long index = 0; + unsigned char current; + unsigned int length; + unsigned char buf[4]; + + while (index < imageSize) + { + current = stream.GetC(); + + // RLE packet. + if ( current & 0x80 ) + { + // Get the run length of the packet. + current &= 0x7f; + + current++; + + length = current; + + index += current * pixelSize; + + // Repeat the pixel length times. + stream.Read(buf, pixelSize); + + for (unsigned int i = 0; i < length; i++) + { + memcpy(imageData, buf, pixelSize); + + imageData += pixelSize; + } + } + else // Raw packet. + { + // Get the run length of the packet. + current++; + + length = current * pixelSize; + + index += length; + + // Write the next length pixels directly to the image data. + stream.Read(imageData, length); + + imageData += length; + } + } +} + +static +int ReadTGA(wxImage* image, wxInputStream& stream) +{ + // Read in the TGA header + unsigned char hdr[HDR_SIZE]; + stream.Read(hdr, HDR_SIZE); + + short offset = hdr[HDR_OFFSET] + HDR_SIZE; + short colorType = hdr[HDR_COLORTYPE]; + short imageType = hdr[HDR_IMAGETYPE]; + int paletteLength = hdr[HDR_PALETTELENGTH] + 256 * hdr[HDR_PALETTELENGTH + 1]; + int width = (hdr[HDR_WIDTH] + 256 * hdr[HDR_WIDTH + 1]) - + (hdr[HDR_XORIGIN] + 256 * hdr[HDR_XORIGIN + 1]); + int height = (hdr[HDR_HEIGHT] + 256 * hdr[HDR_HEIGHT + 1]) - + (hdr[HDR_YORIGIN] + 256 * hdr[HDR_YORIGIN + 1]); + short bpp = hdr[HDR_BPP]; + short orientation = hdr[HDR_ORIENTATION] & 0x20; + + image->Create(width, height); + + if (!image->Ok()) + { + return wxTGA_MEMERR; + } + + const short pixelSize = bpp / 8; + + const unsigned long imageSize = width * height * pixelSize; + + unsigned char *imageData = (unsigned char* )malloc(imageSize); + + if (!imageData) + { + return wxTGA_MEMERR; + } + + wxON_BLOCK_EXIT1(free, imageData); + + unsigned char *dst = image->GetData(); + + unsigned char* alpha = NULL; + if (bpp == 16 || bpp == 32) + { + image->SetAlpha(); + + alpha = image->GetAlpha(); + } + + // Seek from the offset we got from the TGA header. + stream.SeekI(offset, wxFromStart); + + // Load a palette if we have one. + if (colorType == wxTGA_MAPPED) + { + unsigned char buf[3]; + + unsigned char* r = new unsigned char[paletteLength]; + unsigned char* g = new unsigned char[paletteLength]; + unsigned char* b = new unsigned char[paletteLength]; + + for (int i = 0; i < paletteLength; i++) + { + stream.Read(buf, 3); + + r[i] = buf[2]; + g[i] = buf[1]; + b[i] = buf[0]; + } + +#if wxUSE_PALETTE + // Set the palette of the image. + image->SetPalette(wxPalette(paletteLength, r, g, b)); +#endif // wxUSE_PALETTE + + delete[] r; + delete[] g; + delete[] b; + } + + // Handle the various TGA formats we support. + + switch (imageType) + { +#if wxUSE_PALETTE + // Raw indexed. + + case 1: + { + const wxPalette& palette = image->GetPalette(); + unsigned char r; + unsigned char g; + unsigned char b; + + // No compression read the data directly to imageData. + + stream.Read(imageData, imageSize); + + // If orientation == 0, then the image is stored upside down. + // We need to store it right side up. + + if (orientation == 0) + { + FlipTGA(imageData, width, height, pixelSize); + } + + // Handle the different pixel depths. + + switch (bpp) + { + // 8 bpp. + + case 8: + { + for (unsigned long index = 0; index < imageSize; index += pixelSize) + { + palette.GetRGB(imageData[index], &r, &g, &b); + + *(dst++) = r; + *(dst++) = g; + *(dst++) = b; + } + } + break; + + // 16 bpp. + + case 16: + { + for (unsigned long index = 0; index < imageSize; index += pixelSize) + { + palette.GetRGB(imageData[index], &r, &g, &b); + + *(dst++) = r; + *(dst++) = g; + *(dst++) = b; + *(alpha++) = (imageData[index + 1] & 0x80) ? 0 : 255; + } + } + break; + + default: + return wxTGA_INVFORMAT; + } + } + break; +#endif // wxUSE_PALETTE + + // Raw RGB. + + case 2: + { + // No compression read the data directly to imageData. + + stream.Read(imageData, imageSize); + + // If orientation == 0, then the image is stored upside down. + // We need to store it right side up. + + if (orientation == 0) + { + FlipTGA(imageData, width, height, pixelSize); + } + + // Handle the different pixel depths. + + switch (bpp) + { + //16 bpp. + + case 16: + { + unsigned char temp; + + for (unsigned long index = 0; index < imageSize; index += pixelSize) + { + temp = (imageData[index + 1] & 0x7c) << 1; + temp |= temp >> 5; + *(dst++) = temp; + + temp = ((imageData[index + 1] & 0x03) << 6) | ((imageData[index] & 0xe0) >> 2); + temp |= temp >> 5; + *(dst++) = temp; + + temp = (imageData[index] & 0x1f) << 3; + temp |= temp >> 5; + *(dst++) = temp; + + *(alpha++) = (imageData[index + 1] & 0x80) ? 0 : 255; + } + } + break; + + // 24 bpp. + + case 24: + { + for (unsigned long index = 0; index < imageSize; index += pixelSize) + { + *(dst++) = imageData[index + 2]; + *(dst++) = imageData[index + 1]; + *(dst++) = imageData[index]; + } + } + break; + + // 32 bpp. + + case 32: + { + for (unsigned long index = 0; index < imageSize; index += pixelSize) + { + *(dst++) = imageData[index + 2]; + *(dst++) = imageData[index + 1]; + *(dst++) = imageData[index]; + *(alpha++) = imageData[index + 3]; + } + } + break; + + default: + return wxTGA_INVFORMAT; + } + } + break; + + // Raw grayscale. + + case 3: + { + // No compression read the data directly to imageData. + + stream.Read(imageData, imageSize); + + // If orientation == 0, then the image is stored upside down. + // We need to store it right side up. + + if (orientation == 0) + { + FlipTGA(imageData, width, height, pixelSize); + } + + // Handle the different pixel depths. + + switch (bpp) + { + // 8 bpp. + + case 8: + { + for (unsigned long index = 0; index < imageSize; index += pixelSize) + { + *(dst++) = imageData[index]; + *(dst++) = imageData[index]; + *(dst++) = imageData[index]; + } + } + break; + + // 16 bpp. + + case 16: + { + for (unsigned long index = 0; index < imageSize; index += pixelSize) + { + *(dst++) = imageData[index]; + *(dst++) = imageData[index]; + *(dst++) = imageData[index]; + *(alpha++) = imageData[index + 1]; + } + } + break; + + default: + return wxTGA_INVFORMAT; + } + } + break; + +#if wxUSE_PALETTE + // RLE indexed. + + case 9: + { + const wxPalette& palette = image->GetPalette(); + unsigned char r; + unsigned char g; + unsigned char b; + + // Decode the RLE data. + + DecodeRLE(imageData, imageSize, pixelSize, stream); + + // If orientation == 0, then the image is stored upside down. + // We need to store it right side up. + + if (orientation == 0) + { + FlipTGA(imageData, width, height, pixelSize); + } + + // Handle the different pixel depths. + + switch (bpp) + { + // 8 bpp. + + case 8: + { + for (unsigned long index = 0; index < imageSize; index += pixelSize) + { + palette.GetRGB(imageData[index], &r, &g, &b); + + *(dst++) = r; + *(dst++) = g; + *(dst++) = b; + } + } + break; + + // 16 bpp. + + case 16: + { + for (unsigned long index = 0; index < imageSize; index += pixelSize) + { + palette.GetRGB(imageData[index], &r, &g, &b); + + *(dst++) = r; + *(dst++) = g; + *(dst++) = b; + *(alpha++) = (imageData[index + 1] & 0x80) ? 0 : 255; + } + } + break; + + default: + return wxTGA_INVFORMAT; + } + } + break; +#endif // wxUSE_PALETTE + + // RLE RGB. + + case 10: + { + // Decode the RLE data. + + DecodeRLE(imageData, imageSize, pixelSize, stream); + + // If orientation == 0, then the image is stored upside down. + // We need to store it right side up. + + if (orientation == 0) + { + FlipTGA(imageData, width, height, pixelSize); + } + + // Handle the different pixel depths. + + switch (bpp) + { + //16 bpp. + + case 16: + { + unsigned char temp; + + for (unsigned long index = 0; index < imageSize; index += pixelSize) + { + temp = (imageData[index + 1] & 0x7c) << 1; + temp |= temp >> 5; + *(dst++) = temp; + + temp = ((imageData[index + 1] & 0x03) << 6) | ((imageData[index] & 0xe0) >> 2); + temp |= temp >> 5; + *(dst++) = temp; + + temp = (imageData[index] & 0x1f) << 3; + temp |= temp >> 5; + *(dst++) = temp; + + *(alpha++) = (imageData[index + 1] & 0x80) ? 0 : 255; + } + } + break; + + // 24 bpp. + + case 24: + { + for (unsigned long index = 0; index < imageSize; index += pixelSize) + { + *(dst++) = imageData[index + 2]; + *(dst++) = imageData[index + 1]; + *(dst++) = imageData[index]; + } + } + break; + + // 32 bpp. + + case 32: + { + for (unsigned long index = 0; index < imageSize; index += pixelSize) + { + *(dst++) = imageData[index + 2]; + *(dst++) = imageData[index + 1]; + *(dst++) = imageData[index]; + *(alpha++) = imageData[index + 3]; + } + } + break; + + default: + return wxTGA_INVFORMAT; + } + } + break; + + // RLE grayscale. + + case 11: + { + // Decode the RLE data. + + DecodeRLE(imageData, imageSize, pixelSize, stream); + + // If orientation == 0, then the image is stored upside down. + // We need to store it right side up. + + if (orientation == 0) + { + FlipTGA(imageData, width, height, pixelSize); + } + + // Handle the different pixel depths. + + switch (bpp) + { + // 8 bpp. + + case 8: + { + for (unsigned long index = 0; index < imageSize; index += pixelSize) + { + *(dst++) = imageData[index]; + *(dst++) = imageData[index]; + *(dst++) = imageData[index]; + } + } + break; + + // 16 bpp. + + case 16: + { + for (unsigned long index = 0; index < imageSize; index += pixelSize) + { + *(dst++) = imageData[index]; + *(dst++) = imageData[index]; + *(dst++) = imageData[index]; + *(alpha++) = imageData[index + 1]; + } + } + break; + + default: + return wxTGA_INVFORMAT; + } + } + break; + + default: + return wxTGA_INVFORMAT; + } + + return wxTGA_OK; +} + +static +int SaveTGA(wxImage* WXUNUSED(image), wxOutputStream& WXUNUSED(stream)) +{ + wxLogError(wxT("Saving in TGA format is not implemented.")); + + return wxTGA_OK; +} + +// ---------------------------------------------------------------------------- +// wxTGAHandler +// ---------------------------------------------------------------------------- + +bool wxTGAHandler::LoadFile(wxImage* image, + wxInputStream& stream, + bool verbose, + int WXUNUSED(index)) +{ + if ( !CanRead(stream) ) + { + if ( verbose ) + wxLogError(wxT("TGA: this is not a TGA file.")); + + return false; + } + + image->Destroy(); + + int error = ReadTGA(image, stream); + if ( error != wxTGA_OK ) + { + if ( verbose ) + { + switch ( error ) + { + case wxTGA_INVFORMAT: + wxLogError(wxT("TGA: image format unsupported.")); + break; + + case wxTGA_MEMERR: + wxLogError(wxT("TGA: couldn't allocate memory.")); + break; + + default: + wxLogError(wxT("TGA: unknown error!")); + } + } + + image->Destroy(); + + return false; + } + + return true; +} + +bool wxTGAHandler::SaveFile(wxImage* image, wxOutputStream& stream, bool verbose) +{ + int error = SaveTGA(image, stream); + + if ( error != wxTGA_OK ) + { + if ( verbose ) + { + switch ( error ) + { + case wxTGA_INVFORMAT: + wxLogError(wxT("TGA: invalid image.")); + break; + + case wxTGA_MEMERR: + wxLogError(wxT("TGA: couldn't allocate memory.")); + break; + + default: + wxLogError(wxT("TGA: unknown error!")); + } + } + + return false; + } + + return true; +} + +bool wxTGAHandler::DoCanRead(wxInputStream& stream) +{ + // read the fixed-size TGA headers + unsigned char hdr[HDR_SIZE]; + stream.Read(hdr, HDR_SIZE); + + // Check wether we can read the file or not. + + short colorType = hdr[HDR_COLORTYPE]; + if ( colorType != wxTGA_UNMAPPED && colorType != wxTGA_MAPPED ) + { + return false; + } + + short imageType = hdr[HDR_IMAGETYPE]; + if ( imageType == 0 || imageType == 32 || imageType == 33 ) + { + return false; + } + + short bpp = hdr[HDR_BPP]; + if ( bpp != 8 && bpp != 16 && bpp != 24 && bpp != 32 ) + { + return false; + } + + return true; +} + +#endif // wxUSE_STREAMS + +#endif // wxUSE_IMAGE && wxUSE_TGA diff --git a/Externals/wxWidgets/src/common/imagtiff.cpp b/Externals/wxWidgets/src/common/imagtiff.cpp index c44415d744..45800c1aa2 100644 --- a/Externals/wxWidgets/src/common/imagtiff.cpp +++ b/Externals/wxWidgets/src/common/imagtiff.cpp @@ -1,515 +1,515 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/imagtiff.cpp -// Purpose: wxImage TIFF handler -// Author: Robert Roebling -// RCS-ID: $Id: imagtiff.cpp 48694 2007-09-14 23:21:29Z VZ $ -// Copyright: (c) Robert Roebling -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_IMAGE && wxUSE_LIBTIFF - -#include "wx/imagtiff.h" - -#ifndef WX_PRECOMP - #include "wx/log.h" - #include "wx/app.h" - #include "wx/intl.h" - #include "wx/bitmap.h" - #include "wx/module.h" -#endif - -extern "C" -{ - #include "tiff.h" - #include "tiffio.h" -} -#include "wx/filefn.h" -#include "wx/wfstream.h" - -#ifndef TIFFLINKAGEMODE - #if defined(__WATCOMC__) && defined(__WXMGL__) - #define TIFFLINKAGEMODE cdecl - #else - #define TIFFLINKAGEMODE LINKAGEMODE - #endif -#endif - -//----------------------------------------------------------------------------- -// wxTIFFHandler -//----------------------------------------------------------------------------- - -IMPLEMENT_DYNAMIC_CLASS(wxTIFFHandler,wxImageHandler) - -#if wxUSE_STREAMS - -// helper to translate our, possibly 64 bit, wxFileOffset to TIFF, always 32 -// bit, toff_t -static toff_t wxFileOffsetToTIFF(wxFileOffset ofs) -{ - if ( ofs == wxInvalidOffset ) - return (toff_t)-1; - - toff_t tofs = wx_truncate_cast(toff_t, ofs); - wxCHECK_MSG( (wxFileOffset)tofs == ofs, (toff_t)-1, - _T("TIFF library doesn't support large files") ); - - return tofs; -} - -// another helper to convert standard seek mode to our -static wxSeekMode wxSeekModeFromTIFF(int whence) -{ - switch ( whence ) - { - case SEEK_SET: - return wxFromStart; - - case SEEK_CUR: - return wxFromCurrent; - - case SEEK_END: - return wxFromEnd; - - default: - return wxFromCurrent; - } -} - -extern "C" -{ - -tsize_t TIFFLINKAGEMODE -wxTIFFNullProc(thandle_t WXUNUSED(handle), - tdata_t WXUNUSED(buf), - tsize_t WXUNUSED(size)) -{ - return (tsize_t) -1; -} - -tsize_t TIFFLINKAGEMODE -wxTIFFReadProc(thandle_t handle, tdata_t buf, tsize_t size) -{ - wxInputStream *stream = (wxInputStream*) handle; - stream->Read( (void*) buf, (size_t) size ); - return wx_truncate_cast(tsize_t, stream->LastRead()); -} - -tsize_t TIFFLINKAGEMODE -wxTIFFWriteProc(thandle_t handle, tdata_t buf, tsize_t size) -{ - wxOutputStream *stream = (wxOutputStream*) handle; - stream->Write( (void*) buf, (size_t) size ); - return wx_truncate_cast(tsize_t, stream->LastWrite()); -} - -toff_t TIFFLINKAGEMODE -wxTIFFSeekIProc(thandle_t handle, toff_t off, int whence) -{ - wxInputStream *stream = (wxInputStream*) handle; - - return wxFileOffsetToTIFF(stream->SeekI((wxFileOffset)off, - wxSeekModeFromTIFF(whence))); -} - -toff_t TIFFLINKAGEMODE -wxTIFFSeekOProc(thandle_t handle, toff_t off, int whence) -{ - wxOutputStream *stream = (wxOutputStream*) handle; - - return wxFileOffsetToTIFF(stream->SeekO((wxFileOffset)off, - wxSeekModeFromTIFF(whence))); -} - -int TIFFLINKAGEMODE -wxTIFFCloseIProc(thandle_t WXUNUSED(handle)) -{ - // there is no need to close the input stream - return 0; -} - -int TIFFLINKAGEMODE -wxTIFFCloseOProc(thandle_t handle) -{ - wxOutputStream *stream = (wxOutputStream*) handle; - - return stream->Close() ? 0 : -1; -} - -toff_t TIFFLINKAGEMODE -wxTIFFSizeProc(thandle_t handle) -{ - wxStreamBase *stream = (wxStreamBase*) handle; - return (toff_t) stream->GetSize(); -} - -int TIFFLINKAGEMODE -wxTIFFMapProc(thandle_t WXUNUSED(handle), - tdata_t* WXUNUSED(pbase), - toff_t* WXUNUSED(psize)) -{ - return 0; -} - -void TIFFLINKAGEMODE -wxTIFFUnmapProc(thandle_t WXUNUSED(handle), - tdata_t WXUNUSED(base), - toff_t WXUNUSED(size)) -{ -} - -static void -TIFFwxWarningHandler(const char* module, - const char* WXUNUSED_IN_UNICODE(fmt), - va_list WXUNUSED_IN_UNICODE(ap)) -{ - if (module != NULL) - wxLogWarning(_("tiff module: %s"), wxString::FromAscii(module).c_str()); - - // FIXME: this is not terrible informative but better than crashing! -#if wxUSE_UNICODE - wxLogWarning(_("TIFF library warning.")); -#else - wxVLogWarning(fmt, ap); -#endif -} - -static void -TIFFwxErrorHandler(const char* module, - const char* WXUNUSED_IN_UNICODE(fmt), - va_list WXUNUSED_IN_UNICODE(ap)) -{ - if (module != NULL) - wxLogError(_("tiff module: %s"), wxString::FromAscii(module).c_str()); - - // FIXME: as above -#if wxUSE_UNICODE - wxLogError(_("TIFF library error.")); -#else - wxVLogError(fmt, ap); -#endif -} - -} // extern "C" - -TIFF* -TIFFwxOpen(wxInputStream &stream, const char* name, const char* mode) -{ - TIFF* tif = TIFFClientOpen(name, mode, - (thandle_t) &stream, - wxTIFFReadProc, wxTIFFNullProc, - wxTIFFSeekIProc, wxTIFFCloseIProc, wxTIFFSizeProc, - wxTIFFMapProc, wxTIFFUnmapProc); - - return tif; -} - -TIFF* -TIFFwxOpen(wxOutputStream &stream, const char* name, const char* mode) -{ - TIFF* tif = TIFFClientOpen(name, mode, - (thandle_t) &stream, - wxTIFFNullProc, wxTIFFWriteProc, - wxTIFFSeekOProc, wxTIFFCloseOProc, wxTIFFSizeProc, - wxTIFFMapProc, wxTIFFUnmapProc); - - return tif; -} - -wxTIFFHandler::wxTIFFHandler() -{ - m_name = wxT("TIFF file"); - m_extension = wxT("tif"); - m_type = wxBITMAP_TYPE_TIF; - m_mime = wxT("image/tiff"); - TIFFSetWarningHandler((TIFFErrorHandler) TIFFwxWarningHandler); - TIFFSetErrorHandler((TIFFErrorHandler) TIFFwxErrorHandler); -} - -bool wxTIFFHandler::LoadFile( wxImage *image, wxInputStream& stream, bool verbose, int index ) -{ - if (index == -1) - index = 0; - - image->Destroy(); - - TIFF *tif = TIFFwxOpen( stream, "image", "r" ); - - if (!tif) - { - if (verbose) - wxLogError( _("TIFF: Error loading image.") ); - - return false; - } - - if (!TIFFSetDirectory( tif, (tdir_t)index )) - { - if (verbose) - wxLogError( _("Invalid TIFF image index.") ); - - TIFFClose( tif ); - - return false; - } - - uint32 w, h; - uint32 npixels; - uint32 *raster; - - TIFFGetField( tif, TIFFTAG_IMAGEWIDTH, &w ); - TIFFGetField( tif, TIFFTAG_IMAGELENGTH, &h ); - - uint16 extraSamples; - uint16* samplesInfo; - TIFFGetFieldDefaulted(tif, TIFFTAG_EXTRASAMPLES, - &extraSamples, &samplesInfo); - const bool hasAlpha = (extraSamples == 1 && - (samplesInfo[0] == EXTRASAMPLE_ASSOCALPHA || - samplesInfo[0] == EXTRASAMPLE_UNASSALPHA)); - - npixels = w * h; - - raster = (uint32*) _TIFFmalloc( npixels * sizeof(uint32) ); - - if (!raster) - { - if (verbose) - wxLogError( _("TIFF: Couldn't allocate memory.") ); - - TIFFClose( tif ); - - return false; - } - - image->Create( (int)w, (int)h ); - if (!image->Ok()) - { - if (verbose) - wxLogError( _("TIFF: Couldn't allocate memory.") ); - - _TIFFfree( raster ); - TIFFClose( tif ); - - return false; - } - - if ( hasAlpha ) - image->SetAlpha(); - - if (!TIFFReadRGBAImage( tif, w, h, raster, 0 )) - { - if (verbose) - wxLogError( _("TIFF: Error reading image.") ); - - _TIFFfree( raster ); - image->Destroy(); - TIFFClose( tif ); - - return false; - } - - unsigned char *ptr = image->GetData(); - ptr += w*3*(h-1); - - unsigned char *alpha = hasAlpha ? image->GetAlpha() : NULL; - if ( hasAlpha ) - alpha += w*(h-1); - - uint32 pos = 0; - - for (uint32 i = 0; i < h; i++) - { - for (uint32 j = 0; j < w; j++) - { - *(ptr++) = (unsigned char)TIFFGetR(raster[pos]); - *(ptr++) = (unsigned char)TIFFGetG(raster[pos]); - *(ptr++) = (unsigned char)TIFFGetB(raster[pos]); - if ( hasAlpha ) - *(alpha++) = (unsigned char)TIFFGetA(raster[pos]); - - pos++; - } - - // subtract line we just added plus one line: - ptr -= 2*w*3; - if ( hasAlpha ) - alpha -= 2*w; - } - - _TIFFfree( raster ); - - TIFFClose( tif ); - - return true; -} - -int wxTIFFHandler::GetImageCount( wxInputStream& stream ) -{ - TIFF *tif = TIFFwxOpen( stream, "image", "r" ); - - if (!tif) - return 0; - - int dircount = 0; // according to the libtiff docs, dircount should be set to 1 here??? - do { - dircount++; - } while (TIFFReadDirectory(tif)); - - TIFFClose( tif ); - - return dircount; -} - -bool wxTIFFHandler::SaveFile( wxImage *image, wxOutputStream& stream, bool verbose ) -{ - TIFF *tif = TIFFwxOpen( stream, "image", "w" ); - - if (!tif) - { - if (verbose) - wxLogError( _("TIFF: Error saving image.") ); - - return false; - } - - TIFFSetField(tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT); - TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, (uint32)image->GetWidth()); - TIFFSetField(tif, TIFFTAG_IMAGELENGTH, (uint32)image->GetHeight()); - TIFFSetField(tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT); - TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); - - if ( image->HasOption(wxIMAGE_OPTION_RESOLUTIONX) && - image->HasOption(wxIMAGE_OPTION_RESOLUTIONY) ) - { - TIFFSetField(tif, TIFFTAG_XRESOLUTION, - (float)image->GetOptionInt(wxIMAGE_OPTION_RESOLUTIONX)); - TIFFSetField(tif, TIFFTAG_YRESOLUTION, - (float)image->GetOptionInt(wxIMAGE_OPTION_RESOLUTIONY)); - } - - int spp = image->GetOptionInt(wxIMAGE_OPTION_SAMPLESPERPIXEL); - if ( !spp ) - spp = 3; - - int bpp = image->GetOptionInt(wxIMAGE_OPTION_BITSPERSAMPLE); - if ( !bpp ) - bpp=8; - - int compression = image->GetOptionInt(wxIMAGE_OPTION_COMPRESSION); - if ( !compression ) - { - // we can't use COMPRESSION_LZW because current version of libtiff - // doesn't implement it ("no longer implemented due to Unisys patent - // enforcement") and other compression methods are lossy so we - // shouldn't use them by default -- and the only remaining one is none - compression = COMPRESSION_NONE; - } - - TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, spp); - TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, bpp); - TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, spp*bpp == 1 ? PHOTOMETRIC_MINISBLACK - : PHOTOMETRIC_RGB); - TIFFSetField(tif, TIFFTAG_COMPRESSION, compression); - - // scanlinesize if determined by spp and bpp - tsize_t linebytes = (tsize_t)image->GetWidth() * spp * bpp / 8; - - if ( (image->GetWidth() % 8 > 0) && (spp * bpp < 8) ) - linebytes+=1; - - unsigned char *buf; - - if (TIFFScanlineSize(tif) > linebytes || (spp * bpp < 24)) - { - buf = (unsigned char *)_TIFFmalloc(TIFFScanlineSize(tif)); - if (!buf) - { - if (verbose) - wxLogError( _("TIFF: Couldn't allocate memory.") ); - - TIFFClose( tif ); - - return false; - } - } - else - { - buf = NULL; - } - - TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP,TIFFDefaultStripSize(tif, (uint32) -1)); - - unsigned char *ptr = image->GetData(); - for ( int row = 0; row < image->GetHeight(); row++ ) - { - if ( buf ) - { - if ( spp * bpp > 1 ) - { - // color image - memcpy(buf, ptr, image->GetWidth()); - } - else // black and white image - { - for ( int column = 0; column < linebytes; column++ ) - { - uint8 reverse = 0; - for ( int bp = 0; bp < 8; bp++ ) - { - if ( ptr[column*24 + bp*3] > 0 ) - { - // check only red as this is sufficient - reverse = (uint8)(reverse | 128 >> bp); - } - } - - buf[column] = reverse; - } - } - } - - if ( TIFFWriteScanline(tif, buf ? buf : ptr, (uint32)row, 0) < 0 ) - { - if (verbose) - wxLogError( _("TIFF: Error writing image.") ); - - TIFFClose( tif ); - if (buf) - _TIFFfree(buf); - - return false; - } - - ptr += image->GetWidth()*3; - } - - (void) TIFFClose(tif); - - if (buf) - _TIFFfree(buf); - - return true; -} - -bool wxTIFFHandler::DoCanRead( wxInputStream& stream ) -{ - unsigned char hdr[2]; - - if ( !stream.Read(&hdr[0], WXSIZEOF(hdr)) ) - return false; - - return (hdr[0] == 'I' && hdr[1] == 'I') || - (hdr[0] == 'M' && hdr[1] == 'M'); -} - -#endif // wxUSE_STREAMS - -#endif // wxUSE_LIBTIFF +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/imagtiff.cpp +// Purpose: wxImage TIFF handler +// Author: Robert Roebling +// RCS-ID: $Id: imagtiff.cpp 48694 2007-09-14 23:21:29Z VZ $ +// Copyright: (c) Robert Roebling +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_IMAGE && wxUSE_LIBTIFF + +#include "wx/imagtiff.h" + +#ifndef WX_PRECOMP + #include "wx/log.h" + #include "wx/app.h" + #include "wx/intl.h" + #include "wx/bitmap.h" + #include "wx/module.h" +#endif + +extern "C" +{ + #include "tiff.h" + #include "tiffio.h" +} +#include "wx/filefn.h" +#include "wx/wfstream.h" + +#ifndef TIFFLINKAGEMODE + #if defined(__WATCOMC__) && defined(__WXMGL__) + #define TIFFLINKAGEMODE cdecl + #else + #define TIFFLINKAGEMODE LINKAGEMODE + #endif +#endif + +//----------------------------------------------------------------------------- +// wxTIFFHandler +//----------------------------------------------------------------------------- + +IMPLEMENT_DYNAMIC_CLASS(wxTIFFHandler,wxImageHandler) + +#if wxUSE_STREAMS + +// helper to translate our, possibly 64 bit, wxFileOffset to TIFF, always 32 +// bit, toff_t +static toff_t wxFileOffsetToTIFF(wxFileOffset ofs) +{ + if ( ofs == wxInvalidOffset ) + return (toff_t)-1; + + toff_t tofs = wx_truncate_cast(toff_t, ofs); + wxCHECK_MSG( (wxFileOffset)tofs == ofs, (toff_t)-1, + _T("TIFF library doesn't support large files") ); + + return tofs; +} + +// another helper to convert standard seek mode to our +static wxSeekMode wxSeekModeFromTIFF(int whence) +{ + switch ( whence ) + { + case SEEK_SET: + return wxFromStart; + + case SEEK_CUR: + return wxFromCurrent; + + case SEEK_END: + return wxFromEnd; + + default: + return wxFromCurrent; + } +} + +extern "C" +{ + +tsize_t TIFFLINKAGEMODE +wxTIFFNullProc(thandle_t WXUNUSED(handle), + tdata_t WXUNUSED(buf), + tsize_t WXUNUSED(size)) +{ + return (tsize_t) -1; +} + +tsize_t TIFFLINKAGEMODE +wxTIFFReadProc(thandle_t handle, tdata_t buf, tsize_t size) +{ + wxInputStream *stream = (wxInputStream*) handle; + stream->Read( (void*) buf, (size_t) size ); + return wx_truncate_cast(tsize_t, stream->LastRead()); +} + +tsize_t TIFFLINKAGEMODE +wxTIFFWriteProc(thandle_t handle, tdata_t buf, tsize_t size) +{ + wxOutputStream *stream = (wxOutputStream*) handle; + stream->Write( (void*) buf, (size_t) size ); + return wx_truncate_cast(tsize_t, stream->LastWrite()); +} + +toff_t TIFFLINKAGEMODE +wxTIFFSeekIProc(thandle_t handle, toff_t off, int whence) +{ + wxInputStream *stream = (wxInputStream*) handle; + + return wxFileOffsetToTIFF(stream->SeekI((wxFileOffset)off, + wxSeekModeFromTIFF(whence))); +} + +toff_t TIFFLINKAGEMODE +wxTIFFSeekOProc(thandle_t handle, toff_t off, int whence) +{ + wxOutputStream *stream = (wxOutputStream*) handle; + + return wxFileOffsetToTIFF(stream->SeekO((wxFileOffset)off, + wxSeekModeFromTIFF(whence))); +} + +int TIFFLINKAGEMODE +wxTIFFCloseIProc(thandle_t WXUNUSED(handle)) +{ + // there is no need to close the input stream + return 0; +} + +int TIFFLINKAGEMODE +wxTIFFCloseOProc(thandle_t handle) +{ + wxOutputStream *stream = (wxOutputStream*) handle; + + return stream->Close() ? 0 : -1; +} + +toff_t TIFFLINKAGEMODE +wxTIFFSizeProc(thandle_t handle) +{ + wxStreamBase *stream = (wxStreamBase*) handle; + return (toff_t) stream->GetSize(); +} + +int TIFFLINKAGEMODE +wxTIFFMapProc(thandle_t WXUNUSED(handle), + tdata_t* WXUNUSED(pbase), + toff_t* WXUNUSED(psize)) +{ + return 0; +} + +void TIFFLINKAGEMODE +wxTIFFUnmapProc(thandle_t WXUNUSED(handle), + tdata_t WXUNUSED(base), + toff_t WXUNUSED(size)) +{ +} + +static void +TIFFwxWarningHandler(const char* module, + const char* WXUNUSED_IN_UNICODE(fmt), + va_list WXUNUSED_IN_UNICODE(ap)) +{ + if (module != NULL) + wxLogWarning(_("tiff module: %s"), wxString::FromAscii(module).c_str()); + + // FIXME: this is not terrible informative but better than crashing! +#if wxUSE_UNICODE + wxLogWarning(_("TIFF library warning.")); +#else + wxVLogWarning(fmt, ap); +#endif +} + +static void +TIFFwxErrorHandler(const char* module, + const char* WXUNUSED_IN_UNICODE(fmt), + va_list WXUNUSED_IN_UNICODE(ap)) +{ + if (module != NULL) + wxLogError(_("tiff module: %s"), wxString::FromAscii(module).c_str()); + + // FIXME: as above +#if wxUSE_UNICODE + wxLogError(_("TIFF library error.")); +#else + wxVLogError(fmt, ap); +#endif +} + +} // extern "C" + +TIFF* +TIFFwxOpen(wxInputStream &stream, const char* name, const char* mode) +{ + TIFF* tif = TIFFClientOpen(name, mode, + (thandle_t) &stream, + wxTIFFReadProc, wxTIFFNullProc, + wxTIFFSeekIProc, wxTIFFCloseIProc, wxTIFFSizeProc, + wxTIFFMapProc, wxTIFFUnmapProc); + + return tif; +} + +TIFF* +TIFFwxOpen(wxOutputStream &stream, const char* name, const char* mode) +{ + TIFF* tif = TIFFClientOpen(name, mode, + (thandle_t) &stream, + wxTIFFNullProc, wxTIFFWriteProc, + wxTIFFSeekOProc, wxTIFFCloseOProc, wxTIFFSizeProc, + wxTIFFMapProc, wxTIFFUnmapProc); + + return tif; +} + +wxTIFFHandler::wxTIFFHandler() +{ + m_name = wxT("TIFF file"); + m_extension = wxT("tif"); + m_type = wxBITMAP_TYPE_TIF; + m_mime = wxT("image/tiff"); + TIFFSetWarningHandler((TIFFErrorHandler) TIFFwxWarningHandler); + TIFFSetErrorHandler((TIFFErrorHandler) TIFFwxErrorHandler); +} + +bool wxTIFFHandler::LoadFile( wxImage *image, wxInputStream& stream, bool verbose, int index ) +{ + if (index == -1) + index = 0; + + image->Destroy(); + + TIFF *tif = TIFFwxOpen( stream, "image", "r" ); + + if (!tif) + { + if (verbose) + wxLogError( _("TIFF: Error loading image.") ); + + return false; + } + + if (!TIFFSetDirectory( tif, (tdir_t)index )) + { + if (verbose) + wxLogError( _("Invalid TIFF image index.") ); + + TIFFClose( tif ); + + return false; + } + + uint32 w, h; + uint32 npixels; + uint32 *raster; + + TIFFGetField( tif, TIFFTAG_IMAGEWIDTH, &w ); + TIFFGetField( tif, TIFFTAG_IMAGELENGTH, &h ); + + uint16 extraSamples; + uint16* samplesInfo; + TIFFGetFieldDefaulted(tif, TIFFTAG_EXTRASAMPLES, + &extraSamples, &samplesInfo); + const bool hasAlpha = (extraSamples == 1 && + (samplesInfo[0] == EXTRASAMPLE_ASSOCALPHA || + samplesInfo[0] == EXTRASAMPLE_UNASSALPHA)); + + npixels = w * h; + + raster = (uint32*) _TIFFmalloc( npixels * sizeof(uint32) ); + + if (!raster) + { + if (verbose) + wxLogError( _("TIFF: Couldn't allocate memory.") ); + + TIFFClose( tif ); + + return false; + } + + image->Create( (int)w, (int)h ); + if (!image->Ok()) + { + if (verbose) + wxLogError( _("TIFF: Couldn't allocate memory.") ); + + _TIFFfree( raster ); + TIFFClose( tif ); + + return false; + } + + if ( hasAlpha ) + image->SetAlpha(); + + if (!TIFFReadRGBAImage( tif, w, h, raster, 0 )) + { + if (verbose) + wxLogError( _("TIFF: Error reading image.") ); + + _TIFFfree( raster ); + image->Destroy(); + TIFFClose( tif ); + + return false; + } + + unsigned char *ptr = image->GetData(); + ptr += w*3*(h-1); + + unsigned char *alpha = hasAlpha ? image->GetAlpha() : NULL; + if ( hasAlpha ) + alpha += w*(h-1); + + uint32 pos = 0; + + for (uint32 i = 0; i < h; i++) + { + for (uint32 j = 0; j < w; j++) + { + *(ptr++) = (unsigned char)TIFFGetR(raster[pos]); + *(ptr++) = (unsigned char)TIFFGetG(raster[pos]); + *(ptr++) = (unsigned char)TIFFGetB(raster[pos]); + if ( hasAlpha ) + *(alpha++) = (unsigned char)TIFFGetA(raster[pos]); + + pos++; + } + + // subtract line we just added plus one line: + ptr -= 2*w*3; + if ( hasAlpha ) + alpha -= 2*w; + } + + _TIFFfree( raster ); + + TIFFClose( tif ); + + return true; +} + +int wxTIFFHandler::GetImageCount( wxInputStream& stream ) +{ + TIFF *tif = TIFFwxOpen( stream, "image", "r" ); + + if (!tif) + return 0; + + int dircount = 0; // according to the libtiff docs, dircount should be set to 1 here??? + do { + dircount++; + } while (TIFFReadDirectory(tif)); + + TIFFClose( tif ); + + return dircount; +} + +bool wxTIFFHandler::SaveFile( wxImage *image, wxOutputStream& stream, bool verbose ) +{ + TIFF *tif = TIFFwxOpen( stream, "image", "w" ); + + if (!tif) + { + if (verbose) + wxLogError( _("TIFF: Error saving image.") ); + + return false; + } + + TIFFSetField(tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT); + TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, (uint32)image->GetWidth()); + TIFFSetField(tif, TIFFTAG_IMAGELENGTH, (uint32)image->GetHeight()); + TIFFSetField(tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT); + TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); + + if ( image->HasOption(wxIMAGE_OPTION_RESOLUTIONX) && + image->HasOption(wxIMAGE_OPTION_RESOLUTIONY) ) + { + TIFFSetField(tif, TIFFTAG_XRESOLUTION, + (float)image->GetOptionInt(wxIMAGE_OPTION_RESOLUTIONX)); + TIFFSetField(tif, TIFFTAG_YRESOLUTION, + (float)image->GetOptionInt(wxIMAGE_OPTION_RESOLUTIONY)); + } + + int spp = image->GetOptionInt(wxIMAGE_OPTION_SAMPLESPERPIXEL); + if ( !spp ) + spp = 3; + + int bpp = image->GetOptionInt(wxIMAGE_OPTION_BITSPERSAMPLE); + if ( !bpp ) + bpp=8; + + int compression = image->GetOptionInt(wxIMAGE_OPTION_COMPRESSION); + if ( !compression ) + { + // we can't use COMPRESSION_LZW because current version of libtiff + // doesn't implement it ("no longer implemented due to Unisys patent + // enforcement") and other compression methods are lossy so we + // shouldn't use them by default -- and the only remaining one is none + compression = COMPRESSION_NONE; + } + + TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, spp); + TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, bpp); + TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, spp*bpp == 1 ? PHOTOMETRIC_MINISBLACK + : PHOTOMETRIC_RGB); + TIFFSetField(tif, TIFFTAG_COMPRESSION, compression); + + // scanlinesize if determined by spp and bpp + tsize_t linebytes = (tsize_t)image->GetWidth() * spp * bpp / 8; + + if ( (image->GetWidth() % 8 > 0) && (spp * bpp < 8) ) + linebytes+=1; + + unsigned char *buf; + + if (TIFFScanlineSize(tif) > linebytes || (spp * bpp < 24)) + { + buf = (unsigned char *)_TIFFmalloc(TIFFScanlineSize(tif)); + if (!buf) + { + if (verbose) + wxLogError( _("TIFF: Couldn't allocate memory.") ); + + TIFFClose( tif ); + + return false; + } + } + else + { + buf = NULL; + } + + TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP,TIFFDefaultStripSize(tif, (uint32) -1)); + + unsigned char *ptr = image->GetData(); + for ( int row = 0; row < image->GetHeight(); row++ ) + { + if ( buf ) + { + if ( spp * bpp > 1 ) + { + // color image + memcpy(buf, ptr, image->GetWidth()); + } + else // black and white image + { + for ( int column = 0; column < linebytes; column++ ) + { + uint8 reverse = 0; + for ( int bp = 0; bp < 8; bp++ ) + { + if ( ptr[column*24 + bp*3] > 0 ) + { + // check only red as this is sufficient + reverse = (uint8)(reverse | 128 >> bp); + } + } + + buf[column] = reverse; + } + } + } + + if ( TIFFWriteScanline(tif, buf ? buf : ptr, (uint32)row, 0) < 0 ) + { + if (verbose) + wxLogError( _("TIFF: Error writing image.") ); + + TIFFClose( tif ); + if (buf) + _TIFFfree(buf); + + return false; + } + + ptr += image->GetWidth()*3; + } + + (void) TIFFClose(tif); + + if (buf) + _TIFFfree(buf); + + return true; +} + +bool wxTIFFHandler::DoCanRead( wxInputStream& stream ) +{ + unsigned char hdr[2]; + + if ( !stream.Read(&hdr[0], WXSIZEOF(hdr)) ) + return false; + + return (hdr[0] == 'I' && hdr[1] == 'I') || + (hdr[0] == 'M' && hdr[1] == 'M'); +} + +#endif // wxUSE_STREAMS + +#endif // wxUSE_LIBTIFF diff --git a/Externals/wxWidgets/src/common/imagxpm.cpp b/Externals/wxWidgets/src/common/imagxpm.cpp index cca244c1a6..8ef328cf2f 100644 --- a/Externals/wxWidgets/src/common/imagxpm.cpp +++ b/Externals/wxWidgets/src/common/imagxpm.cpp @@ -1,224 +1,224 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/imagxpm.cpp -// Purpose: wxXPMHandler -// Author: Vaclav Slavik, Robert Roebling -// RCS-ID: $Id: imagxpm.cpp 53477 2008-05-07 07:28:57Z JS $ -// Copyright: (c) 2001 Vaclav Slavik -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -/* - -This file is partially based on source code of ImageMagick by John Cristy. Its -license is as follows: - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% % -% % -% % -% X X PPPP M M % -% X X P P MM MM % -% X PPPP M M M % -% X X P M M % -% X X P M M % -% % -% % -% Read/Write ImageMagick Image Format. % -% % -% % -% Software Design % -% John Cristy % -% July 1992 % -% % -% % -% Copyright (C) 2001 ImageMagick Studio, a non-profit organization dedicated % -% to making software imaging solutions freely available. % -% % -% Permission is hereby granted, free of charge, to any person obtaining a % -% copy of this software and associated documentation files ("ImageMagick"), % -% to deal in ImageMagick without restriction, including without limitation % -% the rights to use, copy, modify, merge, publish, distribute, sublicense, % -% and/or sell copies of ImageMagick, and to permit persons to whom the % -% ImageMagick is furnished to do so, subject to the following conditions: % -% % -% The above copyright notice and this permission notice shall be included in % -% all copies or substantial portions of ImageMagick. % -% % -% The software is provided "as is", without warranty of any kind, express or % -% implied, including but not limited to the warranties of merchantability, % -% fitness for a particular purpose and noninfringement. In no event shall % -% ImageMagick Studio be liable for any claim, damages or other liability, % -% whether in an action of contract, tort or otherwise, arising from, out of % -% or in connection with ImageMagick or the use or other dealings in % -% ImageMagick. % -% % -% Except as contained in this notice, the name of the ImageMagick Studio % -% shall not be used in advertising or otherwise to promote the sale, use or % -% other dealings in ImageMagick without prior written authorization from the % -% ImageMagick Studio. % -% % -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% -% -*/ - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_XPM - -#ifndef WX_PRECOMP - #include "wx/log.h" - #include "wx/intl.h" - #include "wx/utils.h" -#endif - -#include "wx/imagxpm.h" -#include "wx/wfstream.h" -#include "wx/xpmdecod.h" - -IMPLEMENT_DYNAMIC_CLASS(wxXPMHandler,wxImageHandler) - -//----------------------------------------------------------------------------- -// wxXPMHandler -//----------------------------------------------------------------------------- - -#if wxUSE_STREAMS - -bool wxXPMHandler::LoadFile(wxImage *image, - wxInputStream& stream, - bool WXUNUSED(verbose), int WXUNUSED(index)) -{ - wxXPMDecoder decoder; - - wxImage img = decoder.ReadFile(stream); - if ( !img.Ok() ) - return false; - *image = img; - return true; -} - -bool wxXPMHandler::SaveFile(wxImage * image, - wxOutputStream& stream, bool WXUNUSED(verbose)) -{ - // 1. count colours: - #define MaxCixels 92 - static const char Cixel[MaxCixels+1] = - " .XoO+@#$%&*=-;:>,<1234567890qwertyuipasdfghjk" - "lzxcvbnmMNBVCZASDFGHJKLPIUYTREWQ!~^/()_`'][{}|"; - int i, j, k; - - wxImageHistogram histogram; - int cols = int(image->ComputeHistogram(histogram)); - - int chars_per_pixel = 1; - for ( k = MaxCixels; cols > k; k *= MaxCixels) - chars_per_pixel++; - - // 2. write the header: - wxString sName; - if ( image->HasOption(wxIMAGE_OPTION_FILENAME) ) - { - wxSplitPath(image->GetOption(wxIMAGE_OPTION_FILENAME), - NULL, &sName, NULL); - sName << wxT("_xpm"); - } - - if ( !sName.empty() ) - sName = wxString(wxT("/* XPM */\nstatic const char *")) + sName; - else - sName = wxT("/* XPM */\nstatic const char *xpm_data"); - stream.Write( (const char*) sName.ToAscii(), sName.Len() ); - - char tmpbuf[200]; - // VS: 200b is safe upper bound for anything produced by sprintf below - // (<101 bytes the string, neither %i can expand into more than 10 chars) - sprintf(tmpbuf, - "[] = {\n" - "/* columns rows colors chars-per-pixel */\n" - "\"%i %i %i %i\",\n", - image->GetWidth(), image->GetHeight(), cols, chars_per_pixel); - stream.Write(tmpbuf, strlen(tmpbuf)); - - // 3. create color symbols table: - char *symbols_data = new char[cols * (chars_per_pixel+1)]; - char **symbols = new char*[cols]; - - // 2a. find mask colour: - unsigned long mask_key = 0x1000000 /*invalid RGB value*/; - if (image->HasMask()) - mask_key = (image->GetMaskRed() << 16) | - (image->GetMaskGreen() << 8) | image->GetMaskBlue(); - - // 2b. generate colour table: - for (wxImageHistogram::iterator entry = histogram.begin(); - entry != histogram.end(); ++entry ) - { - unsigned long index = entry->second.index; - symbols[index] = symbols_data + index * (chars_per_pixel+1); - char *sym = symbols[index]; - - for (j = 0; j < chars_per_pixel; j++) - { - sym[j] = Cixel[index % MaxCixels]; - index /= MaxCixels; - } - sym[j] = '\0'; - - unsigned long key = entry->first; - - if (key == 0) - sprintf( tmpbuf, "\"%s c Black\",\n", sym); - else if (key == mask_key) - sprintf( tmpbuf, "\"%s c None\",\n", sym); - else - { - wxByte r = wxByte(key >> 16); - wxByte g = wxByte(key >> 8); - wxByte b = wxByte(key); - sprintf(tmpbuf, "\"%s c #%02X%02X%02X\",\n", sym, r, g, b); - } - stream.Write( tmpbuf, strlen(tmpbuf) ); - } - - stream.Write("/* pixels */\n", 13); - - unsigned char *data = image->GetData(); - for (j = 0; j < image->GetHeight(); j++) - { - char tmp_c; - tmp_c = '\"'; stream.Write(&tmp_c, 1); - for (i = 0; i < image->GetWidth(); i++, data += 3) - { - unsigned long key = (data[0] << 16) | (data[1] << 8) | (data[2]); - stream.Write(symbols[histogram[key].index], chars_per_pixel); - } - tmp_c = '\"'; stream.Write(&tmp_c, 1); - if ( j + 1 < image->GetHeight() ) - { - tmp_c = ','; stream.Write(&tmp_c, 1); - } - tmp_c = '\n'; stream.Write(&tmp_c, 1); - } - stream.Write("};\n", 3 ); - - // Clean up: - delete[] symbols; - delete[] symbols_data; - - return true; -} - -bool wxXPMHandler::DoCanRead(wxInputStream& stream) -{ - wxXPMDecoder decoder; - return decoder.CanRead(stream); -} - -#endif // wxUSE_STREAMS - -#endif // wxUSE_XPM +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/imagxpm.cpp +// Purpose: wxXPMHandler +// Author: Vaclav Slavik, Robert Roebling +// RCS-ID: $Id: imagxpm.cpp 53477 2008-05-07 07:28:57Z JS $ +// Copyright: (c) 2001 Vaclav Slavik +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +/* + +This file is partially based on source code of ImageMagick by John Cristy. Its +license is as follows: + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% % +% % +% % +% X X PPPP M M % +% X X P P MM MM % +% X PPPP M M M % +% X X P M M % +% X X P M M % +% % +% % +% Read/Write ImageMagick Image Format. % +% % +% % +% Software Design % +% John Cristy % +% July 1992 % +% % +% % +% Copyright (C) 2001 ImageMagick Studio, a non-profit organization dedicated % +% to making software imaging solutions freely available. % +% % +% Permission is hereby granted, free of charge, to any person obtaining a % +% copy of this software and associated documentation files ("ImageMagick"), % +% to deal in ImageMagick without restriction, including without limitation % +% the rights to use, copy, modify, merge, publish, distribute, sublicense, % +% and/or sell copies of ImageMagick, and to permit persons to whom the % +% ImageMagick is furnished to do so, subject to the following conditions: % +% % +% The above copyright notice and this permission notice shall be included in % +% all copies or substantial portions of ImageMagick. % +% % +% The software is provided "as is", without warranty of any kind, express or % +% implied, including but not limited to the warranties of merchantability, % +% fitness for a particular purpose and noninfringement. In no event shall % +% ImageMagick Studio be liable for any claim, damages or other liability, % +% whether in an action of contract, tort or otherwise, arising from, out of % +% or in connection with ImageMagick or the use or other dealings in % +% ImageMagick. % +% % +% Except as contained in this notice, the name of the ImageMagick Studio % +% shall not be used in advertising or otherwise to promote the sale, use or % +% other dealings in ImageMagick without prior written authorization from the % +% ImageMagick Studio. % +% % +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% +*/ + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_XPM + +#ifndef WX_PRECOMP + #include "wx/log.h" + #include "wx/intl.h" + #include "wx/utils.h" +#endif + +#include "wx/imagxpm.h" +#include "wx/wfstream.h" +#include "wx/xpmdecod.h" + +IMPLEMENT_DYNAMIC_CLASS(wxXPMHandler,wxImageHandler) + +//----------------------------------------------------------------------------- +// wxXPMHandler +//----------------------------------------------------------------------------- + +#if wxUSE_STREAMS + +bool wxXPMHandler::LoadFile(wxImage *image, + wxInputStream& stream, + bool WXUNUSED(verbose), int WXUNUSED(index)) +{ + wxXPMDecoder decoder; + + wxImage img = decoder.ReadFile(stream); + if ( !img.Ok() ) + return false; + *image = img; + return true; +} + +bool wxXPMHandler::SaveFile(wxImage * image, + wxOutputStream& stream, bool WXUNUSED(verbose)) +{ + // 1. count colours: + #define MaxCixels 92 + static const char Cixel[MaxCixels+1] = + " .XoO+@#$%&*=-;:>,<1234567890qwertyuipasdfghjk" + "lzxcvbnmMNBVCZASDFGHJKLPIUYTREWQ!~^/()_`'][{}|"; + int i, j, k; + + wxImageHistogram histogram; + int cols = int(image->ComputeHistogram(histogram)); + + int chars_per_pixel = 1; + for ( k = MaxCixels; cols > k; k *= MaxCixels) + chars_per_pixel++; + + // 2. write the header: + wxString sName; + if ( image->HasOption(wxIMAGE_OPTION_FILENAME) ) + { + wxSplitPath(image->GetOption(wxIMAGE_OPTION_FILENAME), + NULL, &sName, NULL); + sName << wxT("_xpm"); + } + + if ( !sName.empty() ) + sName = wxString(wxT("/* XPM */\nstatic const char *")) + sName; + else + sName = wxT("/* XPM */\nstatic const char *xpm_data"); + stream.Write( (const char*) sName.ToAscii(), sName.Len() ); + + char tmpbuf[200]; + // VS: 200b is safe upper bound for anything produced by sprintf below + // (<101 bytes the string, neither %i can expand into more than 10 chars) + sprintf(tmpbuf, + "[] = {\n" + "/* columns rows colors chars-per-pixel */\n" + "\"%i %i %i %i\",\n", + image->GetWidth(), image->GetHeight(), cols, chars_per_pixel); + stream.Write(tmpbuf, strlen(tmpbuf)); + + // 3. create color symbols table: + char *symbols_data = new char[cols * (chars_per_pixel+1)]; + char **symbols = new char*[cols]; + + // 2a. find mask colour: + unsigned long mask_key = 0x1000000 /*invalid RGB value*/; + if (image->HasMask()) + mask_key = (image->GetMaskRed() << 16) | + (image->GetMaskGreen() << 8) | image->GetMaskBlue(); + + // 2b. generate colour table: + for (wxImageHistogram::iterator entry = histogram.begin(); + entry != histogram.end(); ++entry ) + { + unsigned long index = entry->second.index; + symbols[index] = symbols_data + index * (chars_per_pixel+1); + char *sym = symbols[index]; + + for (j = 0; j < chars_per_pixel; j++) + { + sym[j] = Cixel[index % MaxCixels]; + index /= MaxCixels; + } + sym[j] = '\0'; + + unsigned long key = entry->first; + + if (key == 0) + sprintf( tmpbuf, "\"%s c Black\",\n", sym); + else if (key == mask_key) + sprintf( tmpbuf, "\"%s c None\",\n", sym); + else + { + wxByte r = wxByte(key >> 16); + wxByte g = wxByte(key >> 8); + wxByte b = wxByte(key); + sprintf(tmpbuf, "\"%s c #%02X%02X%02X\",\n", sym, r, g, b); + } + stream.Write( tmpbuf, strlen(tmpbuf) ); + } + + stream.Write("/* pixels */\n", 13); + + unsigned char *data = image->GetData(); + for (j = 0; j < image->GetHeight(); j++) + { + char tmp_c; + tmp_c = '\"'; stream.Write(&tmp_c, 1); + for (i = 0; i < image->GetWidth(); i++, data += 3) + { + unsigned long key = (data[0] << 16) | (data[1] << 8) | (data[2]); + stream.Write(symbols[histogram[key].index], chars_per_pixel); + } + tmp_c = '\"'; stream.Write(&tmp_c, 1); + if ( j + 1 < image->GetHeight() ) + { + tmp_c = ','; stream.Write(&tmp_c, 1); + } + tmp_c = '\n'; stream.Write(&tmp_c, 1); + } + stream.Write("};\n", 3 ); + + // Clean up: + delete[] symbols; + delete[] symbols_data; + + return true; +} + +bool wxXPMHandler::DoCanRead(wxInputStream& stream) +{ + wxXPMDecoder decoder; + return decoder.CanRead(stream); +} + +#endif // wxUSE_STREAMS + +#endif // wxUSE_XPM diff --git a/Externals/wxWidgets/src/common/init.cpp b/Externals/wxWidgets/src/common/init.cpp index c9b760ac22..b440e54b21 100644 --- a/Externals/wxWidgets/src/common/init.cpp +++ b/Externals/wxWidgets/src/common/init.cpp @@ -1,502 +1,502 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/init.cpp -// Purpose: initialisation for the library -// Author: Vadim Zeitlin -// Modified by: -// Created: 04.10.99 -// RCS-ID: $Id: init.cpp 51336 2008-01-22 13:59:45Z SC $ -// Copyright: (c) Vadim Zeitlin -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif //__BORLANDC__ - -#ifndef WX_PRECOMP - #include "wx/app.h" - #include "wx/filefn.h" - #include "wx/log.h" - #include "wx/thread.h" - #include "wx/intl.h" - #include "wx/module.h" -#endif - -#include "wx/init.h" - -#include "wx/ptr_scpd.h" -#include "wx/except.h" - -#if defined(__WXMSW__) && defined(__WXDEBUG__) - #include "wx/msw/msvcrt.h" - - static struct EnableMemLeakChecking - { - EnableMemLeakChecking() - { - // do check for memory leaks on program exit (another useful flag - // is _CRTDBG_DELAY_FREE_MEM_DF which doesn't free deallocated - // memory which may be used to simulate low-memory condition) - wxCrtSetDbgFlag(_CRTDBG_LEAK_CHECK_DF); - } - } gs_enableLeakChecks; -#endif // __WXMSW__ && __WXDEBUG__ - -// ---------------------------------------------------------------------------- -// private classes -// ---------------------------------------------------------------------------- - -// we need a dummy app object if the user doesn't want to create a real one -class wxDummyConsoleApp : public wxAppConsole -{ -public: - wxDummyConsoleApp() { } - - virtual int OnRun() { wxFAIL_MSG( _T("unreachable code") ); return 0; } - - DECLARE_NO_COPY_CLASS(wxDummyConsoleApp) -}; - -// we need a special kind of auto pointer to wxApp which not only deletes the -// pointer it holds in its dtor but also resets the global application pointer -wxDECLARE_SCOPED_PTR(wxAppConsole, wxAppPtrBase) -wxDEFINE_SCOPED_PTR(wxAppConsole, wxAppPtrBase) - -class wxAppPtr : public wxAppPtrBase -{ -public: - wxEXPLICIT wxAppPtr(wxAppConsole *ptr = NULL) : wxAppPtrBase(ptr) { } - ~wxAppPtr() - { - if ( get() ) - { - // the pointer is going to be deleted in the base class dtor, don't - // leave the dangling pointer! - wxApp::SetInstance(NULL); - } - } - - void Set(wxAppConsole *ptr) - { - reset(ptr); - - wxApp::SetInstance(ptr); - } - - DECLARE_NO_COPY_CLASS(wxAppPtr) -}; - -// class to ensure that wxAppBase::CleanUp() is called if our Initialize() -// fails -class wxCallAppCleanup -{ -public: - wxCallAppCleanup(wxAppConsole *app) : m_app(app) { } - ~wxCallAppCleanup() { if ( m_app ) m_app->CleanUp(); } - - void Dismiss() { m_app = NULL; } - -private: - wxAppConsole *m_app; -}; - -// another tiny class which simply exists to ensure that wxEntryCleanup is -// always called -class wxCleanupOnExit -{ -public: - ~wxCleanupOnExit() { wxEntryCleanup(); } -}; - -// ---------------------------------------------------------------------------- -// private functions -// ---------------------------------------------------------------------------- - -// suppress warnings about unused variables -static inline void Use(void *) { } - -#define WX_SUPPRESS_UNUSED_WARN(x) Use(&x) - -// ---------------------------------------------------------------------------- -// initialization data -// ---------------------------------------------------------------------------- - -static struct InitData -{ - InitData() - { - nInitCount = 0; - -#if wxUSE_UNICODE - argc = 0; - // argv = NULL; -- not even really needed -#endif // wxUSE_UNICODE - } - - // critical section protecting this struct - wxCRIT_SECT_DECLARE_MEMBER(csInit); - - // number of times wxInitialize() was called minus the number of times - // wxUninitialize() was - size_t nInitCount; - -#if wxUSE_UNICODE - int argc; - - // if we receive the command line arguments as ASCII and have to convert - // them to Unicode ourselves (this is the case under Unix but not Windows, - // for example), we remember the converted argv here because we'll have to - // free it when doing cleanup to avoid memory leaks - wchar_t **argv; -#endif // wxUSE_UNICODE - - DECLARE_NO_COPY_CLASS(InitData) -} gs_initData; - -// ============================================================================ -// implementation -// ============================================================================ - -// ---------------------------------------------------------------------------- -// command line arguments ANSI -> Unicode conversion -// ---------------------------------------------------------------------------- - -#if wxUSE_UNICODE - -static void ConvertArgsToUnicode(int argc, char **argv) -{ - gs_initData.argv = new wchar_t *[argc + 1]; - int wargc = 0; - for ( int i = 0; i < argc; i++ ) - { -#ifdef __DARWIN__ - wxWCharBuffer buf(wxConvFileName->cMB2WX(argv[i])); -#else - wxWCharBuffer buf(wxConvLocal.cMB2WX(argv[i])); -#endif - if ( !buf ) - { - wxLogWarning(_("Command line argument %d couldn't be converted to Unicode and will be ignored."), - i); - } - else // converted ok - { - gs_initData.argv[wargc++] = wxStrdup(buf); - } - } - - gs_initData.argc = wargc; - gs_initData.argv[wargc] = NULL; -} - -static void FreeConvertedArgs() -{ - if ( gs_initData.argv ) - { - for ( int i = 0; i < gs_initData.argc; i++ ) - { - free(gs_initData.argv[i]); - } - - delete [] gs_initData.argv; - gs_initData.argv = NULL; - gs_initData.argc = 0; - } -} - -#endif // wxUSE_UNICODE - -// ---------------------------------------------------------------------------- -// start up -// ---------------------------------------------------------------------------- - -// initialization which is always done (not customizable) before wxApp creation -static bool DoCommonPreInit() -{ -#if wxUSE_LOG - // Reset logging in case we were cleaned up and are being reinitialized. - wxLog::DoCreateOnDemand(); - - // install temporary log sink: we can't use wxLogGui before wxApp is - // constructed and if we use wxLogStderr, all messages during - // initialization simply disappear under Windows - // - // note that we will delete this log target below - delete wxLog::SetActiveTarget(new wxLogBuffer); -#endif // wxUSE_LOG - - return true; -} - -// non customizable initialization done after wxApp creation and initialization -static bool DoCommonPostInit() -{ - wxModule::RegisterModules(); - - if ( !wxModule::InitializeModules() ) - { - wxLogError(_("Initialization failed in post init, aborting.")); - return false; - } - - return true; -} - -bool wxEntryStart(int& argc, wxChar **argv) -{ - // do minimal, always necessary, initialization - // -------------------------------------------- - - // initialize wxRTTI - if ( !DoCommonPreInit() ) - { - return false; - } - - - // first of all, we need an application object - // ------------------------------------------- - - // the user might have already created it himself somehow - wxAppPtr app(wxTheApp); - if ( !app.get() ) - { - // if not, he might have used IMPLEMENT_APP() to give us a function to - // create it - wxAppInitializerFunction fnCreate = wxApp::GetInitializerFunction(); - - if ( fnCreate ) - { - // he did, try to create the custom wxApp object - app.Set((*fnCreate)()); - } - } - - if ( !app.get() ) - { - // either IMPLEMENT_APP() was not used at all or it failed -- in any - // case we still need something - app.Set(new wxDummyConsoleApp); - } - - - // wxApp initialization: this can be customized - // -------------------------------------------- - - if ( !app->Initialize(argc, argv) ) - { - return false; - } - - wxCallAppCleanup callAppCleanup(app.get()); - - // for compatibility call the old initialization function too - if ( !app->OnInitGui() ) - return false; - - - // common initialization after wxTheApp creation - // --------------------------------------------- - - if ( !DoCommonPostInit() ) - return false; - - - // prevent the smart pointer from destroying its contents - app.release(); - - // and the cleanup object from doing cleanup - callAppCleanup.Dismiss(); - -#if wxUSE_LOG - // now that we have a valid wxApp (wxLogGui would have crashed if we used - // it before now), we can delete the temporary sink we had created for the - // initialization messages -- the next time logging function is called, the - // sink will be recreated but this time wxAppTraits will be used - delete wxLog::SetActiveTarget(NULL); -#endif // wxUSE_LOG - - return true; -} - -#if wxUSE_UNICODE - -// we provide a wxEntryStart() wrapper taking "char *" pointer too -bool wxEntryStart(int& argc, char **argv) -{ - ConvertArgsToUnicode(argc, argv); - - if ( !wxEntryStart(gs_initData.argc, gs_initData.argv) ) - { - FreeConvertedArgs(); - - return false; - } - - return true; -} - -#endif // wxUSE_UNICODE - -// ---------------------------------------------------------------------------- -// clean up -// ---------------------------------------------------------------------------- - -// cleanup done before destroying wxTheApp -static void DoCommonPreCleanup() -{ -#if wxUSE_LOG - // flush the logged messages if any and install a 'safer' log target: the - // default one (wxLogGui) can't be used after the resources are freed just - // below and the user supplied one might be even more unsafe (using any - // wxWidgets GUI function is unsafe starting from now) - wxLog::DontCreateOnDemand(); - - // this will flush the old messages if any - delete wxLog::SetActiveTarget(new wxLogStderr); -#endif // wxUSE_LOG -} - -// cleanup done after destroying wxTheApp -static void DoCommonPostCleanup() -{ - wxModule::CleanUpModules(); - - // we can't do this in wxApp itself because it doesn't know if argv had - // been allocated -#if wxUSE_UNICODE - FreeConvertedArgs(); -#endif // wxUSE_UNICODE - - // use Set(NULL) and not Get() to avoid creating a message output object on - // demand when we just want to delete it - delete wxMessageOutput::Set(NULL); - -#if wxUSE_LOG - // and now delete the last logger as well - delete wxLog::SetActiveTarget(NULL); -#endif // wxUSE_LOG -} - -void wxEntryCleanup() -{ - DoCommonPreCleanup(); - - - // delete the application object - if ( wxTheApp ) - { - wxTheApp->CleanUp(); - - // reset the global pointer to it to NULL before destroying it as in - // some circumstances this can result in executing the code using - // wxTheApp and using half-destroyed object is no good - wxAppConsole * const app = wxApp::GetInstance(); - wxApp::SetInstance(NULL); - delete app; - } - - - DoCommonPostCleanup(); -} - -// ---------------------------------------------------------------------------- -// wxEntry -// ---------------------------------------------------------------------------- - -// for MSW the real wxEntry is defined in msw/main.cpp -#ifndef __WXMSW__ - #define wxEntryReal wxEntry -#endif // !__WXMSW__ - -int wxEntryReal(int& argc, wxChar **argv) -{ - // library initialization - if ( !wxEntryStart(argc, argv) ) - { -#if wxUSE_LOG - // flush any log messages explaining why we failed - delete wxLog::SetActiveTarget(NULL); -#endif - return -1; - } - - // if wxEntryStart succeeded, we must call wxEntryCleanup even if the code - // below returns or throws - wxCleanupOnExit cleanupOnExit; - - WX_SUPPRESS_UNUSED_WARN(cleanupOnExit); - - wxTRY - { - - // app initialization - if ( !wxTheApp->CallOnInit() ) - { - // don't call OnExit() if OnInit() failed - return -1; - } - - // ensure that OnExit() is called if OnInit() had succeeded - class CallOnExit - { - public: - ~CallOnExit() { wxTheApp->OnExit(); } - } callOnExit; - - WX_SUPPRESS_UNUSED_WARN(callOnExit); - - // app execution - return wxTheApp->OnRun(); - } - wxCATCH_ALL( wxTheApp->OnUnhandledException(); return -1; ) -} - -#if wxUSE_UNICODE - -// as with wxEntryStart, we provide an ANSI wrapper -int wxEntry(int& argc, char **argv) -{ - ConvertArgsToUnicode(argc, argv); - - return wxEntry(gs_initData.argc, gs_initData.argv); -} - -#endif // wxUSE_UNICODE - -// ---------------------------------------------------------------------------- -// wxInitialize/wxUninitialize -// ---------------------------------------------------------------------------- - -bool wxInitialize(int argc, wxChar **argv) -{ - wxCRIT_SECT_LOCKER(lockInit, gs_initData.csInit); - - if ( gs_initData.nInitCount++ ) - { - // already initialized - return true; - } - - return wxEntryStart(argc, argv); -} - -void wxUninitialize() -{ - wxCRIT_SECT_LOCKER(lockInit, gs_initData.csInit); - - if ( --gs_initData.nInitCount == 0 ) - { - wxEntryCleanup(); - } -} +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/init.cpp +// Purpose: initialisation for the library +// Author: Vadim Zeitlin +// Modified by: +// Created: 04.10.99 +// RCS-ID: $Id: init.cpp 51336 2008-01-22 13:59:45Z SC $ +// Copyright: (c) Vadim Zeitlin +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif //__BORLANDC__ + +#ifndef WX_PRECOMP + #include "wx/app.h" + #include "wx/filefn.h" + #include "wx/log.h" + #include "wx/thread.h" + #include "wx/intl.h" + #include "wx/module.h" +#endif + +#include "wx/init.h" + +#include "wx/ptr_scpd.h" +#include "wx/except.h" + +#if defined(__WXMSW__) && defined(__WXDEBUG__) + #include "wx/msw/msvcrt.h" + + static struct EnableMemLeakChecking + { + EnableMemLeakChecking() + { + // do check for memory leaks on program exit (another useful flag + // is _CRTDBG_DELAY_FREE_MEM_DF which doesn't free deallocated + // memory which may be used to simulate low-memory condition) + wxCrtSetDbgFlag(_CRTDBG_LEAK_CHECK_DF); + } + } gs_enableLeakChecks; +#endif // __WXMSW__ && __WXDEBUG__ + +// ---------------------------------------------------------------------------- +// private classes +// ---------------------------------------------------------------------------- + +// we need a dummy app object if the user doesn't want to create a real one +class wxDummyConsoleApp : public wxAppConsole +{ +public: + wxDummyConsoleApp() { } + + virtual int OnRun() { wxFAIL_MSG( _T("unreachable code") ); return 0; } + + DECLARE_NO_COPY_CLASS(wxDummyConsoleApp) +}; + +// we need a special kind of auto pointer to wxApp which not only deletes the +// pointer it holds in its dtor but also resets the global application pointer +wxDECLARE_SCOPED_PTR(wxAppConsole, wxAppPtrBase) +wxDEFINE_SCOPED_PTR(wxAppConsole, wxAppPtrBase) + +class wxAppPtr : public wxAppPtrBase +{ +public: + wxEXPLICIT wxAppPtr(wxAppConsole *ptr = NULL) : wxAppPtrBase(ptr) { } + ~wxAppPtr() + { + if ( get() ) + { + // the pointer is going to be deleted in the base class dtor, don't + // leave the dangling pointer! + wxApp::SetInstance(NULL); + } + } + + void Set(wxAppConsole *ptr) + { + reset(ptr); + + wxApp::SetInstance(ptr); + } + + DECLARE_NO_COPY_CLASS(wxAppPtr) +}; + +// class to ensure that wxAppBase::CleanUp() is called if our Initialize() +// fails +class wxCallAppCleanup +{ +public: + wxCallAppCleanup(wxAppConsole *app) : m_app(app) { } + ~wxCallAppCleanup() { if ( m_app ) m_app->CleanUp(); } + + void Dismiss() { m_app = NULL; } + +private: + wxAppConsole *m_app; +}; + +// another tiny class which simply exists to ensure that wxEntryCleanup is +// always called +class wxCleanupOnExit +{ +public: + ~wxCleanupOnExit() { wxEntryCleanup(); } +}; + +// ---------------------------------------------------------------------------- +// private functions +// ---------------------------------------------------------------------------- + +// suppress warnings about unused variables +static inline void Use(void *) { } + +#define WX_SUPPRESS_UNUSED_WARN(x) Use(&x) + +// ---------------------------------------------------------------------------- +// initialization data +// ---------------------------------------------------------------------------- + +static struct InitData +{ + InitData() + { + nInitCount = 0; + +#if wxUSE_UNICODE + argc = 0; + // argv = NULL; -- not even really needed +#endif // wxUSE_UNICODE + } + + // critical section protecting this struct + wxCRIT_SECT_DECLARE_MEMBER(csInit); + + // number of times wxInitialize() was called minus the number of times + // wxUninitialize() was + size_t nInitCount; + +#if wxUSE_UNICODE + int argc; + + // if we receive the command line arguments as ASCII and have to convert + // them to Unicode ourselves (this is the case under Unix but not Windows, + // for example), we remember the converted argv here because we'll have to + // free it when doing cleanup to avoid memory leaks + wchar_t **argv; +#endif // wxUSE_UNICODE + + DECLARE_NO_COPY_CLASS(InitData) +} gs_initData; + +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// command line arguments ANSI -> Unicode conversion +// ---------------------------------------------------------------------------- + +#if wxUSE_UNICODE + +static void ConvertArgsToUnicode(int argc, char **argv) +{ + gs_initData.argv = new wchar_t *[argc + 1]; + int wargc = 0; + for ( int i = 0; i < argc; i++ ) + { +#ifdef __DARWIN__ + wxWCharBuffer buf(wxConvFileName->cMB2WX(argv[i])); +#else + wxWCharBuffer buf(wxConvLocal.cMB2WX(argv[i])); +#endif + if ( !buf ) + { + wxLogWarning(_("Command line argument %d couldn't be converted to Unicode and will be ignored."), + i); + } + else // converted ok + { + gs_initData.argv[wargc++] = wxStrdup(buf); + } + } + + gs_initData.argc = wargc; + gs_initData.argv[wargc] = NULL; +} + +static void FreeConvertedArgs() +{ + if ( gs_initData.argv ) + { + for ( int i = 0; i < gs_initData.argc; i++ ) + { + free(gs_initData.argv[i]); + } + + delete [] gs_initData.argv; + gs_initData.argv = NULL; + gs_initData.argc = 0; + } +} + +#endif // wxUSE_UNICODE + +// ---------------------------------------------------------------------------- +// start up +// ---------------------------------------------------------------------------- + +// initialization which is always done (not customizable) before wxApp creation +static bool DoCommonPreInit() +{ +#if wxUSE_LOG + // Reset logging in case we were cleaned up and are being reinitialized. + wxLog::DoCreateOnDemand(); + + // install temporary log sink: we can't use wxLogGui before wxApp is + // constructed and if we use wxLogStderr, all messages during + // initialization simply disappear under Windows + // + // note that we will delete this log target below + delete wxLog::SetActiveTarget(new wxLogBuffer); +#endif // wxUSE_LOG + + return true; +} + +// non customizable initialization done after wxApp creation and initialization +static bool DoCommonPostInit() +{ + wxModule::RegisterModules(); + + if ( !wxModule::InitializeModules() ) + { + wxLogError(_("Initialization failed in post init, aborting.")); + return false; + } + + return true; +} + +bool wxEntryStart(int& argc, wxChar **argv) +{ + // do minimal, always necessary, initialization + // -------------------------------------------- + + // initialize wxRTTI + if ( !DoCommonPreInit() ) + { + return false; + } + + + // first of all, we need an application object + // ------------------------------------------- + + // the user might have already created it himself somehow + wxAppPtr app(wxTheApp); + if ( !app.get() ) + { + // if not, he might have used IMPLEMENT_APP() to give us a function to + // create it + wxAppInitializerFunction fnCreate = wxApp::GetInitializerFunction(); + + if ( fnCreate ) + { + // he did, try to create the custom wxApp object + app.Set((*fnCreate)()); + } + } + + if ( !app.get() ) + { + // either IMPLEMENT_APP() was not used at all or it failed -- in any + // case we still need something + app.Set(new wxDummyConsoleApp); + } + + + // wxApp initialization: this can be customized + // -------------------------------------------- + + if ( !app->Initialize(argc, argv) ) + { + return false; + } + + wxCallAppCleanup callAppCleanup(app.get()); + + // for compatibility call the old initialization function too + if ( !app->OnInitGui() ) + return false; + + + // common initialization after wxTheApp creation + // --------------------------------------------- + + if ( !DoCommonPostInit() ) + return false; + + + // prevent the smart pointer from destroying its contents + app.release(); + + // and the cleanup object from doing cleanup + callAppCleanup.Dismiss(); + +#if wxUSE_LOG + // now that we have a valid wxApp (wxLogGui would have crashed if we used + // it before now), we can delete the temporary sink we had created for the + // initialization messages -- the next time logging function is called, the + // sink will be recreated but this time wxAppTraits will be used + delete wxLog::SetActiveTarget(NULL); +#endif // wxUSE_LOG + + return true; +} + +#if wxUSE_UNICODE + +// we provide a wxEntryStart() wrapper taking "char *" pointer too +bool wxEntryStart(int& argc, char **argv) +{ + ConvertArgsToUnicode(argc, argv); + + if ( !wxEntryStart(gs_initData.argc, gs_initData.argv) ) + { + FreeConvertedArgs(); + + return false; + } + + return true; +} + +#endif // wxUSE_UNICODE + +// ---------------------------------------------------------------------------- +// clean up +// ---------------------------------------------------------------------------- + +// cleanup done before destroying wxTheApp +static void DoCommonPreCleanup() +{ +#if wxUSE_LOG + // flush the logged messages if any and install a 'safer' log target: the + // default one (wxLogGui) can't be used after the resources are freed just + // below and the user supplied one might be even more unsafe (using any + // wxWidgets GUI function is unsafe starting from now) + wxLog::DontCreateOnDemand(); + + // this will flush the old messages if any + delete wxLog::SetActiveTarget(new wxLogStderr); +#endif // wxUSE_LOG +} + +// cleanup done after destroying wxTheApp +static void DoCommonPostCleanup() +{ + wxModule::CleanUpModules(); + + // we can't do this in wxApp itself because it doesn't know if argv had + // been allocated +#if wxUSE_UNICODE + FreeConvertedArgs(); +#endif // wxUSE_UNICODE + + // use Set(NULL) and not Get() to avoid creating a message output object on + // demand when we just want to delete it + delete wxMessageOutput::Set(NULL); + +#if wxUSE_LOG + // and now delete the last logger as well + delete wxLog::SetActiveTarget(NULL); +#endif // wxUSE_LOG +} + +void wxEntryCleanup() +{ + DoCommonPreCleanup(); + + + // delete the application object + if ( wxTheApp ) + { + wxTheApp->CleanUp(); + + // reset the global pointer to it to NULL before destroying it as in + // some circumstances this can result in executing the code using + // wxTheApp and using half-destroyed object is no good + wxAppConsole * const app = wxApp::GetInstance(); + wxApp::SetInstance(NULL); + delete app; + } + + + DoCommonPostCleanup(); +} + +// ---------------------------------------------------------------------------- +// wxEntry +// ---------------------------------------------------------------------------- + +// for MSW the real wxEntry is defined in msw/main.cpp +#ifndef __WXMSW__ + #define wxEntryReal wxEntry +#endif // !__WXMSW__ + +int wxEntryReal(int& argc, wxChar **argv) +{ + // library initialization + if ( !wxEntryStart(argc, argv) ) + { +#if wxUSE_LOG + // flush any log messages explaining why we failed + delete wxLog::SetActiveTarget(NULL); +#endif + return -1; + } + + // if wxEntryStart succeeded, we must call wxEntryCleanup even if the code + // below returns or throws + wxCleanupOnExit cleanupOnExit; + + WX_SUPPRESS_UNUSED_WARN(cleanupOnExit); + + wxTRY + { + + // app initialization + if ( !wxTheApp->CallOnInit() ) + { + // don't call OnExit() if OnInit() failed + return -1; + } + + // ensure that OnExit() is called if OnInit() had succeeded + class CallOnExit + { + public: + ~CallOnExit() { wxTheApp->OnExit(); } + } callOnExit; + + WX_SUPPRESS_UNUSED_WARN(callOnExit); + + // app execution + return wxTheApp->OnRun(); + } + wxCATCH_ALL( wxTheApp->OnUnhandledException(); return -1; ) +} + +#if wxUSE_UNICODE + +// as with wxEntryStart, we provide an ANSI wrapper +int wxEntry(int& argc, char **argv) +{ + ConvertArgsToUnicode(argc, argv); + + return wxEntry(gs_initData.argc, gs_initData.argv); +} + +#endif // wxUSE_UNICODE + +// ---------------------------------------------------------------------------- +// wxInitialize/wxUninitialize +// ---------------------------------------------------------------------------- + +bool wxInitialize(int argc, wxChar **argv) +{ + wxCRIT_SECT_LOCKER(lockInit, gs_initData.csInit); + + if ( gs_initData.nInitCount++ ) + { + // already initialized + return true; + } + + return wxEntryStart(argc, argv); +} + +void wxUninitialize() +{ + wxCRIT_SECT_LOCKER(lockInit, gs_initData.csInit); + + if ( --gs_initData.nInitCount == 0 ) + { + wxEntryCleanup(); + } +} diff --git a/Externals/wxWidgets/src/common/intl.cpp b/Externals/wxWidgets/src/common/intl.cpp index 4b36349880..4d4f9afc3b 100644 --- a/Externals/wxWidgets/src/common/intl.cpp +++ b/Externals/wxWidgets/src/common/intl.cpp @@ -1,3778 +1,3778 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/intl.cpp -// Purpose: Internationalization and localisation for wxWidgets -// Author: Vadim Zeitlin -// Modified by: Michael N. Filippov -// (2003/09/30 - PluralForms support) -// Created: 29/01/98 -// RCS-ID: $Id: intl.cpp 53628 2008-05-17 22:49:30Z VZ $ -// Copyright: (c) 1998 Vadim Zeitlin -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declaration -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#ifdef __EMX__ -// The following define is needed by Innotek's libc to -// make the definition of struct localeconv available. -#define __INTERNAL_DEFS -#endif - -#if wxUSE_INTL - -#ifndef WX_PRECOMP - #include "wx/dynarray.h" - #include "wx/string.h" - #include "wx/intl.h" - #include "wx/log.h" - #include "wx/utils.h" - #include "wx/app.h" - #include "wx/hashmap.h" - #include "wx/module.h" -#endif // WX_PRECOMP - -#ifndef __WXWINCE__ - #include -#endif - -// standard headers -#include -#include -#ifdef HAVE_LANGINFO_H - #include -#endif - -#ifdef __WIN32__ - #include "wx/msw/private.h" -#elif defined(__UNIX_LIKE__) - #include "wx/fontmap.h" // for CharsetToEncoding() -#endif - -#include "wx/file.h" -#include "wx/filename.h" -#include "wx/tokenzr.h" -#include "wx/fontmap.h" -#include "wx/encconv.h" -#include "wx/ptr_scpd.h" -#include "wx/apptrait.h" -#include "wx/stdpaths.h" - -#if defined(__WXMAC__) - #include "wx/mac/private.h" // includes mac headers -#endif - -#if defined(__DARWIN__) - #include "wx/mac/corefoundation/cfref.h" - #include - #include "wx/mac/corefoundation/cfstring.h" -#endif - -// ---------------------------------------------------------------------------- -// simple types -// ---------------------------------------------------------------------------- - -// this should *not* be wxChar, this type must have exactly 8 bits! -typedef wxUint8 size_t8; -typedef wxUint32 size_t32; - -// ---------------------------------------------------------------------------- -// constants -// ---------------------------------------------------------------------------- - -// magic number identifying the .mo format file -const size_t32 MSGCATALOG_MAGIC = 0x950412de; -const size_t32 MSGCATALOG_MAGIC_SW = 0xde120495; - -// the constants describing the format of lang_LANG locale string -static const size_t LEN_LANG = 2; -static const size_t LEN_SUBLANG = 2; -static const size_t LEN_FULL = LEN_LANG + 1 + LEN_SUBLANG; // 1 for '_' - -#define TRACE_I18N _T("i18n") - -// ---------------------------------------------------------------------------- -// global functions -// ---------------------------------------------------------------------------- - -#ifdef __WXDEBUG__ - -// small class to suppress the translation erros until exit from current scope -class NoTransErr -{ -public: - NoTransErr() { ms_suppressCount++; } - ~NoTransErr() { ms_suppressCount--; } - - static bool Suppress() { return ms_suppressCount > 0; } - -private: - static size_t ms_suppressCount; -}; - -size_t NoTransErr::ms_suppressCount = 0; - -#else // !Debug - -class NoTransErr -{ -public: - NoTransErr() { } - ~NoTransErr() { } -}; - -#endif // Debug/!Debug - -static wxLocale *wxSetLocale(wxLocale *pLocale); - -// helper functions of GetSystemLanguage() -#ifdef __UNIX__ - -// get just the language part -static inline wxString ExtractLang(const wxString& langFull) -{ - return langFull.Left(LEN_LANG); -} - -// get everything else (including the leading '_') -static inline wxString ExtractNotLang(const wxString& langFull) -{ - return langFull.Mid(LEN_LANG); -} - -#endif // __UNIX__ - - -// ---------------------------------------------------------------------------- -// Plural forms parser -// ---------------------------------------------------------------------------- - -/* - Simplified Grammar - -Expression: - LogicalOrExpression '?' Expression ':' Expression - LogicalOrExpression - -LogicalOrExpression: - LogicalAndExpression "||" LogicalOrExpression // to (a || b) || c - LogicalAndExpression - -LogicalAndExpression: - EqualityExpression "&&" LogicalAndExpression // to (a && b) && c - EqualityExpression - -EqualityExpression: - RelationalExpression "==" RelationalExperession - RelationalExpression "!=" RelationalExperession - RelationalExpression - -RelationalExpression: - MultiplicativeExpression '>' MultiplicativeExpression - MultiplicativeExpression '<' MultiplicativeExpression - MultiplicativeExpression ">=" MultiplicativeExpression - MultiplicativeExpression "<=" MultiplicativeExpression - MultiplicativeExpression - -MultiplicativeExpression: - PmExpression '%' PmExpression - PmExpression - -PmExpression: - N - Number - '(' Expression ')' -*/ - -class wxPluralFormsToken -{ -public: - enum Type - { - T_ERROR, T_EOF, T_NUMBER, T_N, T_PLURAL, T_NPLURALS, T_EQUAL, T_ASSIGN, - T_GREATER, T_GREATER_OR_EQUAL, T_LESS, T_LESS_OR_EQUAL, - T_REMINDER, T_NOT_EQUAL, - T_LOGICAL_AND, T_LOGICAL_OR, T_QUESTION, T_COLON, T_SEMICOLON, - T_LEFT_BRACKET, T_RIGHT_BRACKET - }; - Type type() const { return m_type; } - void setType(Type type) { m_type = type; } - // for T_NUMBER only - typedef int Number; - Number number() const { return m_number; } - void setNumber(Number num) { m_number = num; } -private: - Type m_type; - Number m_number; -}; - - -class wxPluralFormsScanner -{ -public: - wxPluralFormsScanner(const char* s); - const wxPluralFormsToken& token() const { return m_token; } - bool nextToken(); // returns false if error -private: - const char* m_s; - wxPluralFormsToken m_token; -}; - -wxPluralFormsScanner::wxPluralFormsScanner(const char* s) : m_s(s) -{ - nextToken(); -} - -bool wxPluralFormsScanner::nextToken() -{ - wxPluralFormsToken::Type type = wxPluralFormsToken::T_ERROR; - while (isspace((unsigned char) *m_s)) - { - ++m_s; - } - if (*m_s == 0) - { - type = wxPluralFormsToken::T_EOF; - } - else if (isdigit((unsigned char) *m_s)) - { - wxPluralFormsToken::Number number = *m_s++ - '0'; - while (isdigit((unsigned char) *m_s)) - { - number = number * 10 + (*m_s++ - '0'); - } - m_token.setNumber(number); - type = wxPluralFormsToken::T_NUMBER; - } - else if (isalpha((unsigned char) *m_s)) - { - const char* begin = m_s++; - while (isalnum((unsigned char) *m_s)) - { - ++m_s; - } - size_t size = m_s - begin; - if (size == 1 && memcmp(begin, "n", size) == 0) - { - type = wxPluralFormsToken::T_N; - } - else if (size == 6 && memcmp(begin, "plural", size) == 0) - { - type = wxPluralFormsToken::T_PLURAL; - } - else if (size == 8 && memcmp(begin, "nplurals", size) == 0) - { - type = wxPluralFormsToken::T_NPLURALS; - } - } - else if (*m_s == '=') - { - ++m_s; - if (*m_s == '=') - { - ++m_s; - type = wxPluralFormsToken::T_EQUAL; - } - else - { - type = wxPluralFormsToken::T_ASSIGN; - } - } - else if (*m_s == '>') - { - ++m_s; - if (*m_s == '=') - { - ++m_s; - type = wxPluralFormsToken::T_GREATER_OR_EQUAL; - } - else - { - type = wxPluralFormsToken::T_GREATER; - } - } - else if (*m_s == '<') - { - ++m_s; - if (*m_s == '=') - { - ++m_s; - type = wxPluralFormsToken::T_LESS_OR_EQUAL; - } - else - { - type = wxPluralFormsToken::T_LESS; - } - } - else if (*m_s == '%') - { - ++m_s; - type = wxPluralFormsToken::T_REMINDER; - } - else if (*m_s == '!' && m_s[1] == '=') - { - m_s += 2; - type = wxPluralFormsToken::T_NOT_EQUAL; - } - else if (*m_s == '&' && m_s[1] == '&') - { - m_s += 2; - type = wxPluralFormsToken::T_LOGICAL_AND; - } - else if (*m_s == '|' && m_s[1] == '|') - { - m_s += 2; - type = wxPluralFormsToken::T_LOGICAL_OR; - } - else if (*m_s == '?') - { - ++m_s; - type = wxPluralFormsToken::T_QUESTION; - } - else if (*m_s == ':') - { - ++m_s; - type = wxPluralFormsToken::T_COLON; - } else if (*m_s == ';') { - ++m_s; - type = wxPluralFormsToken::T_SEMICOLON; - } - else if (*m_s == '(') - { - ++m_s; - type = wxPluralFormsToken::T_LEFT_BRACKET; - } - else if (*m_s == ')') - { - ++m_s; - type = wxPluralFormsToken::T_RIGHT_BRACKET; - } - m_token.setType(type); - return type != wxPluralFormsToken::T_ERROR; -} - -class wxPluralFormsNode; - -// NB: Can't use wxDEFINE_SCOPED_PTR_TYPE because wxPluralFormsNode is not -// fully defined yet: -class wxPluralFormsNodePtr -{ -public: - wxPluralFormsNodePtr(wxPluralFormsNode *p = NULL) : m_p(p) {} - ~wxPluralFormsNodePtr(); - wxPluralFormsNode& operator*() const { return *m_p; } - wxPluralFormsNode* operator->() const { return m_p; } - wxPluralFormsNode* get() const { return m_p; } - wxPluralFormsNode* release(); - void reset(wxPluralFormsNode *p); - -private: - wxPluralFormsNode *m_p; -}; - -class wxPluralFormsNode -{ -public: - wxPluralFormsNode(const wxPluralFormsToken& token) : m_token(token) {} - const wxPluralFormsToken& token() const { return m_token; } - const wxPluralFormsNode* node(size_t i) const - { return m_nodes[i].get(); } - void setNode(size_t i, wxPluralFormsNode* n); - wxPluralFormsNode* releaseNode(size_t i); - wxPluralFormsToken::Number evaluate(wxPluralFormsToken::Number n) const; - -private: - wxPluralFormsToken m_token; - wxPluralFormsNodePtr m_nodes[3]; -}; - -wxPluralFormsNodePtr::~wxPluralFormsNodePtr() -{ - delete m_p; -} -wxPluralFormsNode* wxPluralFormsNodePtr::release() -{ - wxPluralFormsNode *p = m_p; - m_p = NULL; - return p; -} -void wxPluralFormsNodePtr::reset(wxPluralFormsNode *p) -{ - if (p != m_p) - { - delete m_p; - m_p = p; - } -} - - -void wxPluralFormsNode::setNode(size_t i, wxPluralFormsNode* n) -{ - m_nodes[i].reset(n); -} - -wxPluralFormsNode* wxPluralFormsNode::releaseNode(size_t i) -{ - return m_nodes[i].release(); -} - -wxPluralFormsToken::Number -wxPluralFormsNode::evaluate(wxPluralFormsToken::Number n) const -{ - switch (token().type()) - { - // leaf - case wxPluralFormsToken::T_NUMBER: - return token().number(); - case wxPluralFormsToken::T_N: - return n; - // 2 args - case wxPluralFormsToken::T_EQUAL: - return node(0)->evaluate(n) == node(1)->evaluate(n); - case wxPluralFormsToken::T_NOT_EQUAL: - return node(0)->evaluate(n) != node(1)->evaluate(n); - case wxPluralFormsToken::T_GREATER: - return node(0)->evaluate(n) > node(1)->evaluate(n); - case wxPluralFormsToken::T_GREATER_OR_EQUAL: - return node(0)->evaluate(n) >= node(1)->evaluate(n); - case wxPluralFormsToken::T_LESS: - return node(0)->evaluate(n) < node(1)->evaluate(n); - case wxPluralFormsToken::T_LESS_OR_EQUAL: - return node(0)->evaluate(n) <= node(1)->evaluate(n); - case wxPluralFormsToken::T_REMINDER: - { - wxPluralFormsToken::Number number = node(1)->evaluate(n); - if (number != 0) - { - return node(0)->evaluate(n) % number; - } - else - { - return 0; - } - } - case wxPluralFormsToken::T_LOGICAL_AND: - return node(0)->evaluate(n) && node(1)->evaluate(n); - case wxPluralFormsToken::T_LOGICAL_OR: - return node(0)->evaluate(n) || node(1)->evaluate(n); - // 3 args - case wxPluralFormsToken::T_QUESTION: - return node(0)->evaluate(n) - ? node(1)->evaluate(n) - : node(2)->evaluate(n); - default: - return 0; - } -} - - -class wxPluralFormsCalculator -{ -public: - wxPluralFormsCalculator() : m_nplurals(0), m_plural(0) {} - - // input: number, returns msgstr index - int evaluate(int n) const; - - // input: text after "Plural-Forms:" (e.g. "nplurals=2; plural=(n != 1);"), - // if s == 0, creates default handler - // returns 0 if error - static wxPluralFormsCalculator* make(const char* s = 0); - - ~wxPluralFormsCalculator() {} - - void init(wxPluralFormsToken::Number nplurals, wxPluralFormsNode* plural); - -private: - wxPluralFormsToken::Number m_nplurals; - wxPluralFormsNodePtr m_plural; -}; - -wxDEFINE_SCOPED_PTR_TYPE(wxPluralFormsCalculator) - -void wxPluralFormsCalculator::init(wxPluralFormsToken::Number nplurals, - wxPluralFormsNode* plural) -{ - m_nplurals = nplurals; - m_plural.reset(plural); -} - -int wxPluralFormsCalculator::evaluate(int n) const -{ - if (m_plural.get() == 0) - { - return 0; - } - wxPluralFormsToken::Number number = m_plural->evaluate(n); - if (number < 0 || number > m_nplurals) - { - return 0; - } - return number; -} - - -class wxPluralFormsParser -{ -public: - wxPluralFormsParser(wxPluralFormsScanner& scanner) : m_scanner(scanner) {} - bool parse(wxPluralFormsCalculator& rCalculator); - -private: - wxPluralFormsNode* parsePlural(); - // stops at T_SEMICOLON, returns 0 if error - wxPluralFormsScanner& m_scanner; - const wxPluralFormsToken& token() const; - bool nextToken(); - - wxPluralFormsNode* expression(); - wxPluralFormsNode* logicalOrExpression(); - wxPluralFormsNode* logicalAndExpression(); - wxPluralFormsNode* equalityExpression(); - wxPluralFormsNode* multiplicativeExpression(); - wxPluralFormsNode* relationalExpression(); - wxPluralFormsNode* pmExpression(); -}; - -bool wxPluralFormsParser::parse(wxPluralFormsCalculator& rCalculator) -{ - if (token().type() != wxPluralFormsToken::T_NPLURALS) - return false; - if (!nextToken()) - return false; - if (token().type() != wxPluralFormsToken::T_ASSIGN) - return false; - if (!nextToken()) - return false; - if (token().type() != wxPluralFormsToken::T_NUMBER) - return false; - wxPluralFormsToken::Number nplurals = token().number(); - if (!nextToken()) - return false; - if (token().type() != wxPluralFormsToken::T_SEMICOLON) - return false; - if (!nextToken()) - return false; - if (token().type() != wxPluralFormsToken::T_PLURAL) - return false; - if (!nextToken()) - return false; - if (token().type() != wxPluralFormsToken::T_ASSIGN) - return false; - if (!nextToken()) - return false; - wxPluralFormsNode* plural = parsePlural(); - if (plural == 0) - return false; - if (token().type() != wxPluralFormsToken::T_SEMICOLON) - return false; - if (!nextToken()) - return false; - if (token().type() != wxPluralFormsToken::T_EOF) - return false; - rCalculator.init(nplurals, plural); - return true; -} - -wxPluralFormsNode* wxPluralFormsParser::parsePlural() -{ - wxPluralFormsNode* p = expression(); - if (p == NULL) - { - return NULL; - } - wxPluralFormsNodePtr n(p); - if (token().type() != wxPluralFormsToken::T_SEMICOLON) - { - return NULL; - } - return n.release(); -} - -const wxPluralFormsToken& wxPluralFormsParser::token() const -{ - return m_scanner.token(); -} - -bool wxPluralFormsParser::nextToken() -{ - if (!m_scanner.nextToken()) - return false; - return true; -} - -wxPluralFormsNode* wxPluralFormsParser::expression() -{ - wxPluralFormsNode* p = logicalOrExpression(); - if (p == NULL) - return NULL; - wxPluralFormsNodePtr n(p); - if (token().type() == wxPluralFormsToken::T_QUESTION) - { - wxPluralFormsNodePtr qn(new wxPluralFormsNode(token())); - if (!nextToken()) - { - return 0; - } - p = expression(); - if (p == 0) - { - return 0; - } - qn->setNode(1, p); - if (token().type() != wxPluralFormsToken::T_COLON) - { - return 0; - } - if (!nextToken()) - { - return 0; - } - p = expression(); - if (p == 0) - { - return 0; - } - qn->setNode(2, p); - qn->setNode(0, n.release()); - return qn.release(); - } - return n.release(); -} - -wxPluralFormsNode*wxPluralFormsParser::logicalOrExpression() -{ - wxPluralFormsNode* p = logicalAndExpression(); - if (p == NULL) - return NULL; - wxPluralFormsNodePtr ln(p); - if (token().type() == wxPluralFormsToken::T_LOGICAL_OR) - { - wxPluralFormsNodePtr un(new wxPluralFormsNode(token())); - if (!nextToken()) - { - return 0; - } - p = logicalOrExpression(); - if (p == 0) - { - return 0; - } - wxPluralFormsNodePtr rn(p); // right - if (rn->token().type() == wxPluralFormsToken::T_LOGICAL_OR) - { - // see logicalAndExpression comment - un->setNode(0, ln.release()); - un->setNode(1, rn->releaseNode(0)); - rn->setNode(0, un.release()); - return rn.release(); - } - - - un->setNode(0, ln.release()); - un->setNode(1, rn.release()); - return un.release(); - } - return ln.release(); -} - -wxPluralFormsNode* wxPluralFormsParser::logicalAndExpression() -{ - wxPluralFormsNode* p = equalityExpression(); - if (p == NULL) - return NULL; - wxPluralFormsNodePtr ln(p); // left - if (token().type() == wxPluralFormsToken::T_LOGICAL_AND) - { - wxPluralFormsNodePtr un(new wxPluralFormsNode(token())); // up - if (!nextToken()) - { - return NULL; - } - p = logicalAndExpression(); - if (p == 0) - { - return NULL; - } - wxPluralFormsNodePtr rn(p); // right - if (rn->token().type() == wxPluralFormsToken::T_LOGICAL_AND) - { -// transform 1 && (2 && 3) -> (1 && 2) && 3 -// u r -// l r -> u 3 -// 2 3 l 2 - un->setNode(0, ln.release()); - un->setNode(1, rn->releaseNode(0)); - rn->setNode(0, un.release()); - return rn.release(); - } - - un->setNode(0, ln.release()); - un->setNode(1, rn.release()); - return un.release(); - } - return ln.release(); -} - -wxPluralFormsNode* wxPluralFormsParser::equalityExpression() -{ - wxPluralFormsNode* p = relationalExpression(); - if (p == NULL) - return NULL; - wxPluralFormsNodePtr n(p); - if (token().type() == wxPluralFormsToken::T_EQUAL - || token().type() == wxPluralFormsToken::T_NOT_EQUAL) - { - wxPluralFormsNodePtr qn(new wxPluralFormsNode(token())); - if (!nextToken()) - { - return NULL; - } - p = relationalExpression(); - if (p == NULL) - { - return NULL; - } - qn->setNode(1, p); - qn->setNode(0, n.release()); - return qn.release(); - } - return n.release(); -} - -wxPluralFormsNode* wxPluralFormsParser::relationalExpression() -{ - wxPluralFormsNode* p = multiplicativeExpression(); - if (p == NULL) - return NULL; - wxPluralFormsNodePtr n(p); - if (token().type() == wxPluralFormsToken::T_GREATER - || token().type() == wxPluralFormsToken::T_LESS - || token().type() == wxPluralFormsToken::T_GREATER_OR_EQUAL - || token().type() == wxPluralFormsToken::T_LESS_OR_EQUAL) - { - wxPluralFormsNodePtr qn(new wxPluralFormsNode(token())); - if (!nextToken()) - { - return NULL; - } - p = multiplicativeExpression(); - if (p == NULL) - { - return NULL; - } - qn->setNode(1, p); - qn->setNode(0, n.release()); - return qn.release(); - } - return n.release(); -} - -wxPluralFormsNode* wxPluralFormsParser::multiplicativeExpression() -{ - wxPluralFormsNode* p = pmExpression(); - if (p == NULL) - return NULL; - wxPluralFormsNodePtr n(p); - if (token().type() == wxPluralFormsToken::T_REMINDER) - { - wxPluralFormsNodePtr qn(new wxPluralFormsNode(token())); - if (!nextToken()) - { - return NULL; - } - p = pmExpression(); - if (p == NULL) - { - return NULL; - } - qn->setNode(1, p); - qn->setNode(0, n.release()); - return qn.release(); - } - return n.release(); -} - -wxPluralFormsNode* wxPluralFormsParser::pmExpression() -{ - wxPluralFormsNodePtr n; - if (token().type() == wxPluralFormsToken::T_N - || token().type() == wxPluralFormsToken::T_NUMBER) - { - n.reset(new wxPluralFormsNode(token())); - if (!nextToken()) - { - return NULL; - } - } - else if (token().type() == wxPluralFormsToken::T_LEFT_BRACKET) { - if (!nextToken()) - { - return NULL; - } - wxPluralFormsNode* p = expression(); - if (p == NULL) - { - return NULL; - } - n.reset(p); - if (token().type() != wxPluralFormsToken::T_RIGHT_BRACKET) - { - return NULL; - } - if (!nextToken()) - { - return NULL; - } - } - else - { - return NULL; - } - return n.release(); -} - -wxPluralFormsCalculator* wxPluralFormsCalculator::make(const char* s) -{ - wxPluralFormsCalculatorPtr calculator(new wxPluralFormsCalculator); - if (s != NULL) - { - wxPluralFormsScanner scanner(s); - wxPluralFormsParser p(scanner); - if (!p.parse(*calculator)) - { - return NULL; - } - } - return calculator.release(); -} - - - - -// ---------------------------------------------------------------------------- -// wxMsgCatalogFile corresponds to one disk-file message catalog. -// -// This is a "low-level" class and is used only by wxMsgCatalog -// ---------------------------------------------------------------------------- - -WX_DECLARE_EXPORTED_STRING_HASH_MAP(wxString, wxMessagesHash); - -class wxMsgCatalogFile -{ -public: - // ctor & dtor - wxMsgCatalogFile(); - ~wxMsgCatalogFile(); - - // load the catalog from disk (szDirPrefix corresponds to language) - bool Load(const wxChar *szDirPrefix, const wxChar *szName, - wxPluralFormsCalculatorPtr& rPluralFormsCalculator); - - // fills the hash with string-translation pairs - void FillHash(wxMessagesHash& hash, - const wxString& msgIdCharset, - bool convertEncoding) const; - - // return the charset of the strings in this catalog or empty string if - // none/unknown - wxString GetCharset() const { return m_charset; } - -private: - // this implementation is binary compatible with GNU gettext() version 0.10 - - // an entry in the string table - struct wxMsgTableEntry - { - size_t32 nLen; // length of the string - size_t32 ofsString; // pointer to the string - }; - - // header of a .mo file - struct wxMsgCatalogHeader - { - size_t32 magic, // offset +00: magic id - revision, // +04: revision - numStrings; // +08: number of strings in the file - size_t32 ofsOrigTable, // +0C: start of original string table - ofsTransTable; // +10: start of translated string table - size_t32 nHashSize, // +14: hash table size - ofsHashTable; // +18: offset of hash table start - }; - - // all data is stored here, NULL if no data loaded - size_t8 *m_pData; - - // amount of memory pointed to by m_pData. - size_t32 m_nSize; - - // data description - size_t32 m_numStrings; // number of strings in this domain - wxMsgTableEntry *m_pOrigTable, // pointer to original strings - *m_pTransTable; // translated - - wxString m_charset; // from the message catalog header - - - // swap the 2 halves of 32 bit integer if needed - size_t32 Swap(size_t32 ui) const - { - return m_bSwapped ? (ui << 24) | ((ui & 0xff00) << 8) | - ((ui >> 8) & 0xff00) | (ui >> 24) - : ui; - } - - const char *StringAtOfs(wxMsgTableEntry *pTable, size_t32 n) const - { - const wxMsgTableEntry * const ent = pTable + n; - - // this check could fail for a corrupt message catalog - size_t32 ofsString = Swap(ent->ofsString); - if ( ofsString + Swap(ent->nLen) > m_nSize) - { - return NULL; - } - - return (const char *)(m_pData + ofsString); - } - - bool m_bSwapped; // wrong endianness? - - DECLARE_NO_COPY_CLASS(wxMsgCatalogFile) -}; - - -// ---------------------------------------------------------------------------- -// wxMsgCatalog corresponds to one loaded message catalog. -// -// This is a "low-level" class and is used only by wxLocale (that's why -// it's designed to be stored in a linked list) -// ---------------------------------------------------------------------------- - -class wxMsgCatalog -{ -public: -#if !wxUSE_UNICODE - wxMsgCatalog() { m_conv = NULL; } - ~wxMsgCatalog(); -#endif - - // load the catalog from disk (szDirPrefix corresponds to language) - bool Load(const wxChar *szDirPrefix, const wxChar *szName, - const wxChar *msgIdCharset = NULL, bool bConvertEncoding = false); - - // get name of the catalog - wxString GetName() const { return m_name; } - - // get the translated string: returns NULL if not found - const wxChar *GetString(const wxChar *sz, size_t n = size_t(-1)) const; - - // public variable pointing to the next element in a linked list (or NULL) - wxMsgCatalog *m_pNext; - -private: - wxMessagesHash m_messages; // all messages in the catalog - wxString m_name; // name of the domain - -#if !wxUSE_UNICODE - // the conversion corresponding to this catalog charset if we installed it - // as the global one - wxCSConv *m_conv; -#endif - - wxPluralFormsCalculatorPtr m_pluralFormsCalculator; -}; - -// ---------------------------------------------------------------------------- -// global variables -// ---------------------------------------------------------------------------- - -// the list of the directories to search for message catalog files -static wxArrayString gs_searchPrefixes; - -// ============================================================================ -// implementation -// ============================================================================ - -// ---------------------------------------------------------------------------- -// wxMsgCatalogFile class -// ---------------------------------------------------------------------------- - -wxMsgCatalogFile::wxMsgCatalogFile() -{ - m_pData = NULL; - m_nSize = 0; -} - -wxMsgCatalogFile::~wxMsgCatalogFile() -{ - delete [] m_pData; -} - -// return the directories to search for message catalogs under the given -// prefix, separated by wxPATH_SEP -static -wxString GetMsgCatalogSubdirs(const wxChar *prefix, const wxChar *lang) -{ - // Search first in Unix-standard prefix/lang/LC_MESSAGES, then in - // prefix/lang and finally in just prefix. - // - // Note that we use LC_MESSAGES on all platforms and not just Unix, because - // it doesn't cost much to look into one more directory and doing it this - // way has two important benefits: - // a) we don't break compatibility with wx-2.6 and older by stopping to - // look in a directory where the catalogs used to be and thus silently - // breaking apps after they are recompiled against the latest wx - // b) it makes it possible to package app's support files in the same - // way on all target platforms - wxString pathPrefix; - pathPrefix << prefix << wxFILE_SEP_PATH << lang; - - wxString searchPath; - searchPath.reserve(4*pathPrefix.length()); - searchPath << pathPrefix << wxFILE_SEP_PATH << wxT("LC_MESSAGES") << wxPATH_SEP - << prefix << wxFILE_SEP_PATH << wxPATH_SEP - << pathPrefix; - - return searchPath; -} - -// construct the search path for the given language -static wxString GetFullSearchPath(const wxChar *lang) -{ - // first take the entries explicitly added by the program - wxArrayString paths; - paths.reserve(gs_searchPrefixes.size() + 1); - size_t n, - count = gs_searchPrefixes.size(); - for ( n = 0; n < count; n++ ) - { - paths.Add(GetMsgCatalogSubdirs(gs_searchPrefixes[n], lang)); - } - - -#if wxUSE_STDPATHS - // then look in the standard location - const wxString stdp = wxStandardPaths::Get(). - GetLocalizedResourcesDir(lang, wxStandardPaths::ResourceCat_Messages); - - if ( paths.Index(stdp) == wxNOT_FOUND ) - paths.Add(stdp); -#endif // wxUSE_STDPATHS - - // last look in default locations -#ifdef __UNIX__ - // LC_PATH is a standard env var containing the search path for the .mo - // files - const wxChar *pszLcPath = wxGetenv(wxT("LC_PATH")); - if ( pszLcPath ) - { - const wxString lcp = GetMsgCatalogSubdirs(pszLcPath, lang); - if ( paths.Index(lcp) == wxNOT_FOUND ) - paths.Add(lcp); - } - - // also add the one from where wxWin was installed: - wxString wxp = wxGetInstallPrefix(); - if ( !wxp.empty() ) - { - wxp = GetMsgCatalogSubdirs(wxp + _T("/share/locale"), lang); - if ( paths.Index(wxp) == wxNOT_FOUND ) - paths.Add(wxp); - } -#endif // __UNIX__ - - - // finally construct the full search path - wxString searchPath; - searchPath.reserve(500); - count = paths.size(); - for ( n = 0; n < count; n++ ) - { - searchPath += paths[n]; - if ( n != count - 1 ) - searchPath += wxPATH_SEP; - } - - return searchPath; -} - -// open disk file and read in it's contents -bool wxMsgCatalogFile::Load(const wxChar *szDirPrefix, const wxChar *szName, - wxPluralFormsCalculatorPtr& rPluralFormsCalculator) -{ - wxString searchPath; - -#if wxUSE_FONTMAP - // first look for the catalog for this language and the current locale: - // notice that we don't use the system name for the locale as this would - // force us to install catalogs in different locations depending on the - // system but always use the canonical name - wxFontEncoding encSys = wxLocale::GetSystemEncoding(); - if ( encSys != wxFONTENCODING_SYSTEM ) - { - wxString fullname(szDirPrefix); - fullname << _T('.') << wxFontMapperBase::GetEncodingName(encSys); - searchPath << GetFullSearchPath(fullname) << wxPATH_SEP; - } -#endif // wxUSE_FONTMAP - - - searchPath += GetFullSearchPath(szDirPrefix); - const wxChar *sublocale = wxStrchr(szDirPrefix, wxT('_')); - if ( sublocale ) - { - // also add just base locale name: for things like "fr_BE" (belgium - // french) we should use "fr" if no belgium specific message catalogs - // exist - searchPath << wxPATH_SEP - << GetFullSearchPath(wxString(szDirPrefix). - Left((size_t)(sublocale - szDirPrefix))); - } - - // don't give translation errors here because the wxstd catalog might - // not yet be loaded (and it's normal) - // - // (we're using an object because we have several return paths) - - NoTransErr noTransErr; - wxLogVerbose(_("looking for catalog '%s' in path '%s'."), - szName, searchPath.c_str()); - wxLogTrace(TRACE_I18N, _T("Looking for \"%s.mo\" in \"%s\""), - szName, searchPath.c_str()); - - wxFileName fn(szName); - fn.SetExt(_T("mo")); - wxString strFullName; - if ( !wxFindFileInPath(&strFullName, searchPath, fn.GetFullPath()) ) { - wxLogVerbose(_("catalog file for domain '%s' not found."), szName); - wxLogTrace(TRACE_I18N, _T("Catalog \"%s.mo\" not found"), szName); - return false; - } - - // open file - wxLogVerbose(_("using catalog '%s' from '%s'."), szName, strFullName.c_str()); - wxLogTrace(TRACE_I18N, _T("Using catalog \"%s\"."), strFullName.c_str()); - - wxFile fileMsg(strFullName); - if ( !fileMsg.IsOpened() ) - return false; - - // get the file size (assume it is less than 4Gb...) - wxFileOffset lenFile = fileMsg.Length(); - if ( lenFile == wxInvalidOffset ) - return false; - - size_t nSize = wx_truncate_cast(size_t, lenFile); - wxASSERT_MSG( nSize == lenFile + size_t(0), _T("message catalog bigger than 4GB?") ); - - // read the whole file in memory - m_pData = new size_t8[nSize]; - if ( fileMsg.Read(m_pData, nSize) != lenFile ) { - wxDELETEA(m_pData); - return false; - } - - // examine header - bool bValid = nSize + (size_t)0 > sizeof(wxMsgCatalogHeader); - - wxMsgCatalogHeader *pHeader = (wxMsgCatalogHeader *)m_pData; - if ( bValid ) { - // we'll have to swap all the integers if it's true - m_bSwapped = pHeader->magic == MSGCATALOG_MAGIC_SW; - - // check the magic number - bValid = m_bSwapped || pHeader->magic == MSGCATALOG_MAGIC; - } - - if ( !bValid ) { - // it's either too short or has incorrect magic number - wxLogWarning(_("'%s' is not a valid message catalog."), strFullName.c_str()); - - wxDELETEA(m_pData); - return false; - } - - // initialize - m_numStrings = Swap(pHeader->numStrings); - m_pOrigTable = (wxMsgTableEntry *)(m_pData + - Swap(pHeader->ofsOrigTable)); - m_pTransTable = (wxMsgTableEntry *)(m_pData + - Swap(pHeader->ofsTransTable)); - m_nSize = (size_t32)nSize; - - // now parse catalog's header and try to extract catalog charset and - // plural forms formula from it: - - const char* headerData = StringAtOfs(m_pOrigTable, 0); - if (headerData && headerData[0] == 0) - { - // Extract the charset: - wxString header = wxString::FromAscii(StringAtOfs(m_pTransTable, 0)); - int begin = header.Find(wxT("Content-Type: text/plain; charset=")); - if (begin != wxNOT_FOUND) - { - begin += 34; //strlen("Content-Type: text/plain; charset=") - size_t end = header.find('\n', begin); - if (end != size_t(-1)) - { - m_charset.assign(header, begin, end - begin); - if (m_charset == wxT("CHARSET")) - { - // "CHARSET" is not valid charset, but lazy translator - m_charset.Clear(); - } - } - } - // else: incorrectly filled Content-Type header - - // Extract plural forms: - begin = header.Find(wxT("Plural-Forms:")); - if (begin != wxNOT_FOUND) - { - begin += 13; - size_t end = header.find('\n', begin); - if (end != size_t(-1)) - { - wxString pfs(header, begin, end - begin); - wxPluralFormsCalculator* pCalculator = wxPluralFormsCalculator - ::make(pfs.ToAscii()); - if (pCalculator != 0) - { - rPluralFormsCalculator.reset(pCalculator); - } - else - { - wxLogVerbose(_("Cannot parse Plural-Forms:'%s'"), pfs.c_str()); - } - } - } - if (rPluralFormsCalculator.get() == NULL) - { - rPluralFormsCalculator.reset(wxPluralFormsCalculator::make()); - } - } - - // everything is fine - return true; -} - -void wxMsgCatalogFile::FillHash(wxMessagesHash& hash, - const wxString& msgIdCharset, - bool convertEncoding) const -{ -#if wxUSE_UNICODE - // this parameter doesn't make sense, we always must convert encoding in - // Unicode build - convertEncoding = true; -#elif wxUSE_FONTMAP - if ( convertEncoding ) - { - // determine if we need any conversion at all - wxFontEncoding encCat = wxFontMapperBase::GetEncodingFromName(m_charset); - if ( encCat == wxLocale::GetSystemEncoding() ) - { - // no need to convert - convertEncoding = false; - } - } -#endif // wxUSE_UNICODE/wxUSE_FONTMAP - -#if wxUSE_WCHAR_T - // conversion to use to convert catalog strings to the GUI encoding - wxMBConv *inputConv, - *inputConvPtr = NULL; // same as inputConv but safely deleteable - if ( convertEncoding && !m_charset.empty() ) - { - inputConvPtr = - inputConv = new wxCSConv(m_charset); - } - else // no need or not possible to convert the encoding - { -#if wxUSE_UNICODE - // we must somehow convert the narrow strings in the message catalog to - // wide strings, so use the default conversion if we have no charset - inputConv = wxConvCurrent; -#else // !wxUSE_UNICODE - inputConv = NULL; -#endif // wxUSE_UNICODE/!wxUSE_UNICODE - } - - // conversion to apply to msgid strings before looking them up: we only - // need it if the msgids are neither in 7 bit ASCII nor in the same - // encoding as the catalog - wxCSConv *sourceConv = msgIdCharset.empty() || (msgIdCharset == m_charset) - ? NULL - : new wxCSConv(msgIdCharset); - -#elif wxUSE_FONTMAP - wxASSERT_MSG( msgIdCharset.empty(), - _T("non-ASCII msgid languages only supported if wxUSE_WCHAR_T=1") ); - - wxEncodingConverter converter; - if ( convertEncoding ) - { - wxFontEncoding targetEnc = wxFONTENCODING_SYSTEM; - wxFontEncoding enc = wxFontMapperBase::Get()->CharsetToEncoding(m_charset, false); - if ( enc == wxFONTENCODING_SYSTEM ) - { - convertEncoding = false; // unknown encoding - } - else - { - targetEnc = wxLocale::GetSystemEncoding(); - if (targetEnc == wxFONTENCODING_SYSTEM) - { - wxFontEncodingArray a = wxEncodingConverter::GetPlatformEquivalents(enc); - if (a[0] == enc) - // no conversion needed, locale uses native encoding - convertEncoding = false; - if (a.GetCount() == 0) - // we don't know common equiv. under this platform - convertEncoding = false; - targetEnc = a[0]; - } - } - - if ( convertEncoding ) - { - converter.Init(enc, targetEnc); - } - } -#endif // wxUSE_WCHAR_T/!wxUSE_WCHAR_T - (void)convertEncoding; // get rid of warnings about unused parameter - - for (size_t32 i = 0; i < m_numStrings; i++) - { - const char *data = StringAtOfs(m_pOrigTable, i); - - wxString msgid; -#if wxUSE_UNICODE - msgid = wxString(data, *inputConv); -#else // ASCII - #if wxUSE_WCHAR_T - if ( inputConv && sourceConv ) - msgid = wxString(inputConv->cMB2WC(data), *sourceConv); - else - #endif - msgid = data; -#endif // wxUSE_UNICODE - - data = StringAtOfs(m_pTransTable, i); - size_t length = Swap(m_pTransTable[i].nLen); - size_t offset = 0; - size_t index = 0; - while (offset < length) - { - const char * const str = data + offset; - - wxString msgstr; -#if wxUSE_UNICODE - msgstr = wxString(str, *inputConv); -#elif wxUSE_WCHAR_T - if ( inputConv ) - msgstr = wxString(inputConv->cMB2WC(str), *wxConvUI); - else - msgstr = str; -#else // !wxUSE_WCHAR_T - #if wxUSE_FONTMAP - if ( convertEncoding ) - msgstr = wxString(converter.Convert(str)); - else - #endif - msgstr = str; -#endif // wxUSE_WCHAR_T/!wxUSE_WCHAR_T - - if ( !msgstr.empty() ) - { - hash[index == 0 ? msgid : msgid + wxChar(index)] = msgstr; - } - - // skip this string - offset += strlen(str) + 1; - ++index; - } - } - -#if wxUSE_WCHAR_T - delete sourceConv; - delete inputConvPtr; -#endif // wxUSE_WCHAR_T -} - - -// ---------------------------------------------------------------------------- -// wxMsgCatalog class -// ---------------------------------------------------------------------------- - -#if !wxUSE_UNICODE -wxMsgCatalog::~wxMsgCatalog() -{ - if ( m_conv ) - { - if ( wxConvUI == m_conv ) - { - // we only change wxConvUI if it points to wxConvLocal so we reset - // it back to it too - wxConvUI = &wxConvLocal; - } - - delete m_conv; - } -} -#endif // !wxUSE_UNICODE - -bool wxMsgCatalog::Load(const wxChar *szDirPrefix, const wxChar *szName, - const wxChar *msgIdCharset, bool bConvertEncoding) -{ - wxMsgCatalogFile file; - - m_name = szName; - - if ( !file.Load(szDirPrefix, szName, m_pluralFormsCalculator) ) - return false; - - file.FillHash(m_messages, msgIdCharset, bConvertEncoding); - -#if !wxUSE_UNICODE && wxUSE_WCHAR_T - // we should use a conversion compatible with the message catalog encoding - // in the GUI if we don't convert the strings to the current conversion but - // as the encoding is global, only change it once, otherwise we could get - // into trouble if we use several message catalogs with different encodings - // - // this is, of course, a hack but it at least allows the program to use - // message catalogs in any encodings without asking the user to change his - // locale - if ( !bConvertEncoding && - !file.GetCharset().empty() && - wxConvUI == &wxConvLocal ) - { - wxConvUI = - m_conv = new wxCSConv(file.GetCharset()); - } -#endif // !wxUSE_UNICODE && wxUSE_WCHAR_T - - return true; -} - -const wxChar *wxMsgCatalog::GetString(const wxChar *sz, size_t n) const -{ - int index = 0; - if (n != size_t(-1)) - { - index = m_pluralFormsCalculator->evaluate(n); - } - wxMessagesHash::const_iterator i; - if (index != 0) - { - i = m_messages.find(wxString(sz) + wxChar(index)); // plural - } - else - { - i = m_messages.find(sz); - } - - if ( i != m_messages.end() ) - { - return i->second.c_str(); - } - else - return NULL; -} - -// ---------------------------------------------------------------------------- -// wxLocale -// ---------------------------------------------------------------------------- - -#include "wx/arrimpl.cpp" -WX_DECLARE_EXPORTED_OBJARRAY(wxLanguageInfo, wxLanguageInfoArray); -WX_DEFINE_OBJARRAY(wxLanguageInfoArray) - -wxLanguageInfoArray *wxLocale::ms_languagesDB = NULL; - -/*static*/ void wxLocale::CreateLanguagesDB() -{ - if (ms_languagesDB == NULL) - { - ms_languagesDB = new wxLanguageInfoArray; - InitLanguagesDB(); - } -} - -/*static*/ void wxLocale::DestroyLanguagesDB() -{ - delete ms_languagesDB; - ms_languagesDB = NULL; -} - - -void wxLocale::DoCommonInit() -{ - m_pszOldLocale = NULL; - - m_pOldLocale = wxSetLocale(this); - - m_pMsgCat = NULL; - m_language = wxLANGUAGE_UNKNOWN; - m_initialized = false; -} - -// NB: this function has (desired) side effect of changing current locale -bool wxLocale::Init(const wxChar *szName, - const wxChar *szShort, - const wxChar *szLocale, - bool bLoadDefault, - bool bConvertEncoding) -{ - wxASSERT_MSG( !m_initialized, - _T("you can't call wxLocale::Init more than once") ); - - m_initialized = true; - m_strLocale = szName; - m_strShort = szShort; - m_bConvertEncoding = bConvertEncoding; - m_language = wxLANGUAGE_UNKNOWN; - - // change current locale (default: same as long name) - if ( szLocale == NULL ) - { - // the argument to setlocale() - szLocale = szShort; - - wxCHECK_MSG( szLocale, false, _T("no locale to set in wxLocale::Init()") ); - } - -#ifdef __WXWINCE__ - // FIXME: I'm guessing here - wxChar localeName[256]; - int ret = GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SLANGUAGE, localeName, - 256); - if (ret != 0) - { - m_pszOldLocale = wxStrdup(localeName); - } - else - m_pszOldLocale = NULL; - - // TODO: how to find languageId - // SetLocaleInfo(languageId, SORT_DEFAULT, localeName); -#else - wxMB2WXbuf oldLocale = wxSetlocale(LC_ALL, szLocale); - if ( oldLocale ) - m_pszOldLocale = wxStrdup(oldLocale); - else - m_pszOldLocale = NULL; -#endif - - if ( m_pszOldLocale == NULL ) - wxLogError(_("locale '%s' can not be set."), szLocale); - - // the short name will be used to look for catalog files as well, - // so we need something here - if ( m_strShort.empty() ) { - // FIXME I don't know how these 2 letter abbreviations are formed, - // this wild guess is surely wrong - if ( szLocale && szLocale[0] ) - { - m_strShort += (wxChar)wxTolower(szLocale[0]); - if ( szLocale[1] ) - m_strShort += (wxChar)wxTolower(szLocale[1]); - } - } - - // load the default catalog with wxWidgets standard messages - m_pMsgCat = NULL; - bool bOk = true; - if ( bLoadDefault ) - { - bOk = AddCatalog(wxT("wxstd")); - - // there may be a catalog with toolkit specific overrides, it is not - // an error if this does not exist - if ( bOk ) - { - wxString port(wxPlatformInfo::Get().GetPortIdName()); - if ( !port.empty() ) - { - AddCatalog(port.BeforeFirst(wxT('/')).MakeLower()); - } - } - } - - return bOk; -} - - -#if defined(__UNIX__) && wxUSE_UNICODE && !defined(__WXMAC__) -static wxWCharBuffer wxSetlocaleTryUTF(int c, const wxChar *lc) -{ - wxMB2WXbuf l = wxSetlocale(c, lc); - if ( !l && lc && lc[0] != 0 ) - { - wxString buf(lc); - wxString buf2; - buf2 = buf + wxT(".UTF-8"); - l = wxSetlocale(c, buf2.c_str()); - if ( !l ) - { - buf2 = buf + wxT(".utf-8"); - l = wxSetlocale(c, buf2.c_str()); - } - if ( !l ) - { - buf2 = buf + wxT(".UTF8"); - l = wxSetlocale(c, buf2.c_str()); - } - if ( !l ) - { - buf2 = buf + wxT(".utf8"); - l = wxSetlocale(c, buf2.c_str()); - } - } - return l; -} -#else -#define wxSetlocaleTryUTF(c, lc) wxSetlocale(c, lc) -#endif - -bool wxLocale::Init(int language, int flags) -{ - int lang = language; - if (lang == wxLANGUAGE_DEFAULT) - { - // auto detect the language - lang = GetSystemLanguage(); - } - - // We failed to detect system language, so we will use English: - if (lang == wxLANGUAGE_UNKNOWN) - { - return false; - } - - const wxLanguageInfo *info = GetLanguageInfo(lang); - - // Unknown language: - if (info == NULL) - { - wxLogError(wxT("Unknown language %i."), lang); - return false; - } - - wxString name = info->Description; - wxString canonical = info->CanonicalName; - wxString locale; - - // Set the locale: -#if defined(__OS2__) - wxMB2WXbuf retloc = wxSetlocale(LC_ALL , wxEmptyString); -#elif defined(__UNIX__) && !defined(__WXMAC__) - if (language != wxLANGUAGE_DEFAULT) - locale = info->CanonicalName; - - wxMB2WXbuf retloc = wxSetlocaleTryUTF(LC_ALL, locale); - - const wxString langOnly = locale.Left(2); - if ( !retloc ) - { - // Some C libraries don't like xx_YY form and require xx only - retloc = wxSetlocaleTryUTF(LC_ALL, langOnly); - } - -#if wxUSE_FONTMAP - // some systems (e.g. FreeBSD and HP-UX) don't have xx_YY aliases but - // require the full xx_YY.encoding form, so try using UTF-8 because this is - // the only thing we can do generically - // - // TODO: add encodings applicable to each language to the lang DB and try - // them all in turn here - if ( !retloc ) - { - const wxChar **names = - wxFontMapperBase::GetAllEncodingNames(wxFONTENCODING_UTF8); - while ( *names ) - { - retloc = wxSetlocale(LC_ALL, locale + _T('.') + *names++); - if ( retloc ) - break; - } - } -#endif // wxUSE_FONTMAP - - if ( !retloc ) - { - // Some C libraries (namely glibc) still use old ISO 639, - // so will translate the abbrev for them - wxString localeAlt; - if ( langOnly == wxT("he") ) - localeAlt = wxT("iw") + locale.Mid(3); - else if ( langOnly == wxT("id") ) - localeAlt = wxT("in") + locale.Mid(3); - else if ( langOnly == wxT("yi") ) - localeAlt = wxT("ji") + locale.Mid(3); - else if ( langOnly == wxT("nb") ) - localeAlt = wxT("no_NO"); - else if ( langOnly == wxT("nn") ) - localeAlt = wxT("no_NY"); - - if ( !localeAlt.empty() ) - { - retloc = wxSetlocaleTryUTF(LC_ALL, localeAlt); - if ( !retloc ) - retloc = wxSetlocaleTryUTF(LC_ALL, localeAlt.Left(2)); - } - } - - if ( !retloc ) - { - wxLogError(wxT("Cannot set locale to '%s'."), locale.c_str()); - return false; - } - -#ifdef __AIX__ - // at least in AIX 5.2 libc is buggy and the string returned from setlocale(LC_ALL) - // can't be passed back to it because it returns 6 strings (one for each locale - // category), i.e. for C locale we get back "C C C C C C" - // - // this contradicts IBM own docs but this is not of much help, so just work around - // it in the crudest possible manner - wxChar *p = wxStrchr((wxChar *)retloc, _T(' ')); - if ( p ) - *p = _T('\0'); -#endif // __AIX__ - -#elif defined(__WIN32__) - - #if wxUSE_UNICODE && (defined(__VISUALC__) || defined(__MINGW32__)) - // NB: setlocale() from msvcrt.dll (used by VC++ and Mingw) - // can't set locale to language that can only be written using - // Unicode. Therefore wxSetlocale call failed, but we don't want - // to report it as an error -- so that at least message catalogs - // can be used. Watch for code marked with - // #ifdef SETLOCALE_FAILS_ON_UNICODE_LANGS bellow. - #define SETLOCALE_FAILS_ON_UNICODE_LANGS - #endif - -#if !wxUSE_UNICODE - const -#endif - wxMB2WXbuf retloc = wxT("C"); - if (language != wxLANGUAGE_DEFAULT) - { - if (info->WinLang == 0) - { - wxLogWarning(wxT("Locale '%s' not supported by OS."), name.c_str()); - // retloc already set to "C" - } - else - { - int codepage - #ifdef SETLOCALE_FAILS_ON_UNICODE_LANGS - = -1 - #endif - ; - wxUint32 lcid = MAKELCID(MAKELANGID(info->WinLang, info->WinSublang), - SORT_DEFAULT); - // FIXME -#ifndef __WXWINCE__ - SetThreadLocale(lcid); -#endif - // NB: we must translate LCID to CRT's setlocale string ourselves, - // because SetThreadLocale does not modify change the - // interpretation of setlocale(LC_ALL, "") call: - wxChar buffer[256]; - buffer[0] = wxT('\0'); - GetLocaleInfo(lcid, LOCALE_SENGLANGUAGE, buffer, 256); - locale << buffer; - if (GetLocaleInfo(lcid, LOCALE_SENGCOUNTRY, buffer, 256) > 0) - locale << wxT("_") << buffer; - if (GetLocaleInfo(lcid, LOCALE_IDEFAULTANSICODEPAGE, buffer, 256) > 0) - { - codepage = wxAtoi(buffer); - if (codepage != 0) - locale << wxT(".") << buffer; - } - if (locale.empty()) - { - wxLogLastError(wxT("SetThreadLocale")); - wxLogError(wxT("Cannot set locale to language %s."), name.c_str()); - return false; - } - else - { - // FIXME -#ifndef __WXWINCE__ - retloc = wxSetlocale(LC_ALL, locale); -#endif -#ifdef SETLOCALE_FAILS_ON_UNICODE_LANGS - if (codepage == 0 && (const wxChar*)retloc == NULL) - { - retloc = wxT("C"); - } -#endif - } - } - } - else - { - // FIXME -#ifndef __WXWINCE__ - retloc = wxSetlocale(LC_ALL, wxEmptyString); -#else - retloc = NULL; -#endif -#ifdef SETLOCALE_FAILS_ON_UNICODE_LANGS - if ((const wxChar*)retloc == NULL) - { - wxChar buffer[16]; - if (GetLocaleInfo(LOCALE_USER_DEFAULT, - LOCALE_IDEFAULTANSICODEPAGE, buffer, 16) > 0 && - wxStrcmp(buffer, wxT("0")) == 0) - { - retloc = wxT("C"); - } - } -#endif - } - - if ( !retloc ) - { - wxLogError(wxT("Cannot set locale to language %s."), name.c_str()); - return false; - } -#elif defined(__WXMAC__) - if (lang == wxLANGUAGE_DEFAULT) - locale = wxEmptyString; - else - locale = info->CanonicalName; - - wxMB2WXbuf retloc = wxSetlocale(LC_ALL, locale); - - if ( !retloc ) - { - // Some C libraries don't like xx_YY form and require xx only - retloc = wxSetlocale(LC_ALL, locale.Mid(0,2)); - } - if ( !retloc ) - { - wxLogError(wxT("Cannot set locale to '%s'."), locale.c_str()); - return false; - } -#else - wxUnusedVar(flags); - return false; - #define WX_NO_LOCALE_SUPPORT -#endif - -#ifndef WX_NO_LOCALE_SUPPORT - wxChar *szLocale = retloc ? wxStrdup(retloc) : NULL; - bool ret = Init(name, canonical, szLocale, - (flags & wxLOCALE_LOAD_DEFAULT) != 0, - (flags & wxLOCALE_CONV_ENCODING) != 0); - free(szLocale); - - if (IsOk()) // setlocale() succeeded - m_language = lang; - - return ret; -#endif // !WX_NO_LOCALE_SUPPORT -} - - - -void wxLocale::AddCatalogLookupPathPrefix(const wxString& prefix) -{ - if ( gs_searchPrefixes.Index(prefix) == wxNOT_FOUND ) - { - gs_searchPrefixes.Add(prefix); - } - //else: already have it -} - -/*static*/ int wxLocale::GetSystemLanguage() -{ - CreateLanguagesDB(); - - // init i to avoid compiler warning - size_t i = 0, - count = ms_languagesDB->GetCount(); - -#if defined(__UNIX__) && !defined(__WXMAC__) - // first get the string identifying the language from the environment - wxString langFull; - if (!wxGetEnv(wxT("LC_ALL"), &langFull) && - !wxGetEnv(wxT("LC_MESSAGES"), &langFull) && - !wxGetEnv(wxT("LANG"), &langFull)) - { - // no language specified, treat it as English - return wxLANGUAGE_ENGLISH_US; - } - - if ( langFull == _T("C") || langFull == _T("POSIX") ) - { - // default C locale is English too - return wxLANGUAGE_ENGLISH_US; - } - - // the language string has the following form - // - // lang[_LANG][.encoding][@modifier] - // - // (see environ(5) in the Open Unix specification) - // - // where lang is the primary language, LANG is a sublang/territory, - // encoding is the charset to use and modifier "allows the user to select - // a specific instance of localization data within a single category" - // - // for example, the following strings are valid: - // fr - // fr_FR - // de_DE.iso88591 - // de_DE@euro - // de_DE.iso88591@euro - - // for now we don't use the encoding, although we probably should (doing - // translations of the msg catalogs on the fly as required) (TODO) - // - // we need the modified for languages like Valencian: ca_ES@valencia - // though, remember it - wxString modifier; - size_t posModifier = langFull.find_first_of(_T("@")); - if ( posModifier != wxString::npos ) - modifier = langFull.Mid(posModifier); - - size_t posEndLang = langFull.find_first_of(_T("@.")); - if ( posEndLang != wxString::npos ) - { - langFull.Truncate(posEndLang); - } - - // in addition to the format above, we also can have full language names - // in LANG env var - for example, SuSE is known to use LANG="german" - so - // check for this - - // do we have just the language (or sublang too)? - bool justLang = langFull.length() == LEN_LANG; - if ( justLang || - (langFull.length() == LEN_FULL && langFull[LEN_LANG] == wxT('_')) ) - { - // 0. Make sure the lang is according to latest ISO 639 - // (this is necessary because glibc uses iw and in instead - // of he and id respectively). - - // the language itself (second part is the dialect/sublang) - wxString langOrig = ExtractLang(langFull); - - wxString lang; - if ( langOrig == wxT("iw")) - lang = _T("he"); - else if (langOrig == wxT("in")) - lang = wxT("id"); - else if (langOrig == wxT("ji")) - lang = wxT("yi"); - else if (langOrig == wxT("no_NO")) - lang = wxT("nb_NO"); - else if (langOrig == wxT("no_NY")) - lang = wxT("nn_NO"); - else if (langOrig == wxT("no")) - lang = wxT("nb_NO"); - else - lang = langOrig; - - // did we change it? - if ( lang != langOrig ) - { - langFull = lang + ExtractNotLang(langFull); - } - - // 1. Try to find the language either as is: - // a) With modifier if set - if ( !modifier.empty() ) - { - wxString langFullWithModifier = langFull + modifier; - for ( i = 0; i < count; i++ ) - { - if ( ms_languagesDB->Item(i).CanonicalName == langFullWithModifier ) - break; - } - } - - // b) Without modifier - if ( modifier.empty() || i == count ) - { - for ( i = 0; i < count; i++ ) - { - if ( ms_languagesDB->Item(i).CanonicalName == langFull ) - break; - } - } - - // 2. If langFull is of the form xx_YY, try to find xx: - if ( i == count && !justLang ) - { - for ( i = 0; i < count; i++ ) - { - if ( ms_languagesDB->Item(i).CanonicalName == lang ) - { - break; - } - } - } - - // 3. If langFull is of the form xx, try to find any xx_YY record: - if ( i == count && justLang ) - { - for ( i = 0; i < count; i++ ) - { - if ( ExtractLang(ms_languagesDB->Item(i).CanonicalName) - == langFull ) - { - break; - } - } - } - } - else // not standard format - { - // try to find the name in verbose description - for ( i = 0; i < count; i++ ) - { - if (ms_languagesDB->Item(i).Description.CmpNoCase(langFull) == 0) - { - break; - } - } - } -#elif defined(__WXMAC__) - const wxChar * lc = NULL ; - long lang = GetScriptVariable( smSystemScript, smScriptLang) ; - switch( GetScriptManagerVariable( smRegionCode ) ) { - case verUS : - lc = wxT("en_US") ; - break ; - case verFrance : - lc = wxT("fr_FR") ; - break ; - case verBritain : - lc = wxT("en_GB") ; - break ; - case verGermany : - lc = wxT("de_DE") ; - break ; - case verItaly : - lc = wxT("it_IT") ; - break ; - case verNetherlands : - lc = wxT("nl_NL") ; - break ; - case verFlemish : - lc = wxT("nl_BE") ; - break ; - case verSweden : - lc = wxT("sv_SE" ); - break ; - case verSpain : - lc = wxT("es_ES" ); - break ; - case verDenmark : - lc = wxT("da_DK") ; - break ; - case verPortugal : - lc = wxT("pt_PT") ; - break ; - case verFrCanada: - lc = wxT("fr_CA") ; - break ; - case verNorway: - lc = wxT("nb_NO") ; - break ; - case verIsrael: - lc = wxT("iw_IL") ; - break ; - case verJapan: - lc = wxT("ja_JP") ; - break ; - case verAustralia: - lc = wxT("en_AU") ; - break ; - case verArabic: - lc = wxT("ar") ; - break ; - case verFinland: - lc = wxT("fi_FI") ; - break ; - case verFrSwiss: - lc = wxT("fr_CH") ; - break ; - case verGrSwiss: - lc = wxT("de_CH") ; - break ; - case verGreece: - lc = wxT("el_GR") ; - break ; - case verIceland: - lc = wxT("is_IS") ; - break ; - case verMalta: - lc = wxT("mt_MT") ; - break ; - case verCyprus: - // _CY is not part of wx, so we have to translate according to the system language - if ( lang == langGreek ) { - lc = wxT("el_GR") ; - } - else if ( lang == langTurkish ) { - lc = wxT("tr_TR") ; - } - break ; - case verTurkey: - lc = wxT("tr_TR") ; - break ; - case verYugoCroatian: - lc = wxT("hr_HR") ; - break ; - case verIndiaHindi: - lc = wxT("hi_IN") ; - break ; - case verPakistanUrdu: - lc = wxT("ur_PK") ; - break ; - case verTurkishModified: - lc = wxT("tr_TR") ; - break ; - case verItalianSwiss: - lc = wxT("it_CH") ; - break ; - case verInternational: - lc = wxT("en") ; - break ; - case verRomania: - lc = wxT("ro_RO") ; - break ; - case verGreecePoly: - lc = wxT("el_GR") ; - break ; - case verLithuania: - lc = wxT("lt_LT") ; - break ; - case verPoland: - lc = wxT("pl_PL") ; - break ; - case verMagyar : - case verHungary: - lc = wxT("hu_HU") ; - break ; - case verEstonia: - lc = wxT("et_EE") ; - break ; - case verLatvia: - lc = wxT("lv_LV") ; - break ; - case verSami: - lc = wxT("se_NO") ; - break ; - case verFaroeIsl: - lc = wxT("fo_FO") ; - break ; - case verIran: - lc = wxT("fa_IR") ; - break ; - case verRussia: - lc = wxT("ru_RU") ; - break ; - case verIreland: - lc = wxT("ga_IE") ; - break ; - case verKorea: - lc = wxT("ko_KR") ; - break ; - case verChina: - lc = wxT("zh_CN") ; - break ; - case verTaiwan: - lc = wxT("zh_TW") ; - break ; - case verThailand: - lc = wxT("th_TH") ; - break ; - case verCzech: - lc = wxT("cs_CZ") ; - break ; - case verSlovak: - lc = wxT("sk_SK") ; - break ; - case verBengali: - lc = wxT("bn") ; - break ; - case verByeloRussian: - lc = wxT("be_BY") ; - break ; - case verUkraine: - lc = wxT("uk_UA") ; - break ; - case verGreeceAlt: - lc = wxT("el_GR") ; - break ; - case verSerbian: - lc = wxT("sr_YU") ; - break ; - case verSlovenian: - lc = wxT("sl_SI") ; - break ; - case verMacedonian: - lc = wxT("mk_MK") ; - break ; - case verCroatia: - lc = wxT("hr_HR") ; - break ; - case verBrazil: - lc = wxT("pt_BR ") ; - break ; - case verBulgaria: - lc = wxT("bg_BG") ; - break ; - case verCatalonia: - lc = wxT("ca_ES") ; - break ; - case verScottishGaelic: - lc = wxT("gd") ; - break ; - case verManxGaelic: - lc = wxT("gv") ; - break ; - case verBreton: - lc = wxT("br") ; - break ; - case verNunavut: - lc = wxT("iu_CA") ; - break ; - case verWelsh: - lc = wxT("cy") ; - break ; - case verIrishGaelicScript: - lc = wxT("ga_IE") ; - break ; - case verEngCanada: - lc = wxT("en_CA") ; - break ; - case verBhutan: - lc = wxT("dz_BT") ; - break ; - case verArmenian: - lc = wxT("hy_AM") ; - break ; - case verGeorgian: - lc = wxT("ka_GE") ; - break ; - case verSpLatinAmerica: - lc = wxT("es_AR") ; - break ; - case verTonga: - lc = wxT("to_TO" ); - break ; - case verFrenchUniversal: - lc = wxT("fr_FR") ; - break ; - case verAustria: - lc = wxT("de_AT") ; - break ; - case verGujarati: - lc = wxT("gu_IN") ; - break ; - case verPunjabi: - lc = wxT("pa") ; - break ; - case verIndiaUrdu: - lc = wxT("ur_IN") ; - break ; - case verVietnam: - lc = wxT("vi_VN") ; - break ; - case verFrBelgium: - lc = wxT("fr_BE") ; - break ; - case verUzbek: - lc = wxT("uz_UZ") ; - break ; - case verSingapore: - lc = wxT("zh_SG") ; - break ; - case verNynorsk: - lc = wxT("nn_NO") ; - break ; - case verAfrikaans: - lc = wxT("af_ZA") ; - break ; - case verEsperanto: - lc = wxT("eo") ; - break ; - case verMarathi: - lc = wxT("mr_IN") ; - break ; - case verTibetan: - lc = wxT("bo") ; - break ; - case verNepal: - lc = wxT("ne_NP") ; - break ; - case verGreenland: - lc = wxT("kl_GL") ; - break ; - default : - break ; - } - if ( !lc ) - return wxLANGUAGE_UNKNOWN; - for ( i = 0; i < count; i++ ) - { - if ( ms_languagesDB->Item(i).CanonicalName == lc ) - { - break; - } - } - -#elif defined(__WIN32__) - LCID lcid = GetUserDefaultLCID(); - if ( lcid != 0 ) - { - wxUint32 lang = PRIMARYLANGID(LANGIDFROMLCID(lcid)); - wxUint32 sublang = SUBLANGID(LANGIDFROMLCID(lcid)); - - for ( i = 0; i < count; i++ ) - { - if (ms_languagesDB->Item(i).WinLang == lang && - ms_languagesDB->Item(i).WinSublang == sublang) - { - break; - } - } - } - //else: leave wxlang == wxLANGUAGE_UNKNOWN -#endif // Unix/Win32 - - if ( i < count ) - { - // we did find a matching entry, use it - return ms_languagesDB->Item(i).Language; - } - - // no info about this language in the database - return wxLANGUAGE_UNKNOWN; -} - -// ---------------------------------------------------------------------------- -// encoding stuff -// ---------------------------------------------------------------------------- - -// this is a bit strange as under Windows we get the encoding name using its -// numeric value and under Unix we do it the other way round, but this just -// reflects the way different systems provide the encoding info - -/* static */ -wxString wxLocale::GetSystemEncodingName() -{ - wxString encname; - -#if defined(__WIN32__) && !defined(__WXMICROWIN__) - // FIXME: what is the error return value for GetACP()? - UINT codepage = ::GetACP(); - encname.Printf(_T("windows-%u"), codepage); -#elif defined(__WXMAC__) - // default is just empty string, this resolves to the default system - // encoding later -#elif defined(__UNIX_LIKE__) - -#if defined(HAVE_LANGINFO_H) && defined(CODESET) - // GNU libc provides current character set this way (this conforms - // to Unix98) - char *oldLocale = strdup(setlocale(LC_CTYPE, NULL)); - setlocale(LC_CTYPE, ""); - const char *alang = nl_langinfo(CODESET); - setlocale(LC_CTYPE, oldLocale); - free(oldLocale); - - if ( alang ) - { - encname = wxString::FromAscii( alang ); - } - else // nl_langinfo() failed -#endif // HAVE_LANGINFO_H - { - // if we can't get at the character set directly, try to see if it's in - // the environment variables (in most cases this won't work, but I was - // out of ideas) - char *lang = getenv( "LC_ALL"); - char *dot = lang ? strchr(lang, '.') : (char *)NULL; - if (!dot) - { - lang = getenv( "LC_CTYPE" ); - if ( lang ) - dot = strchr(lang, '.' ); - } - if (!dot) - { - lang = getenv( "LANG"); - if ( lang ) - dot = strchr(lang, '.'); - } - - if ( dot ) - { - encname = wxString::FromAscii( dot+1 ); - } - } -#endif // Win32/Unix - - return encname; -} - -/* static */ -wxFontEncoding wxLocale::GetSystemEncoding() -{ -#if defined(__WIN32__) && !defined(__WXMICROWIN__) - UINT codepage = ::GetACP(); - - // wxWidgets only knows about CP1250-1257, 874, 932, 936, 949, 950 - if ( codepage >= 1250 && codepage <= 1257 ) - { - return (wxFontEncoding)(wxFONTENCODING_CP1250 + codepage - 1250); - } - - if ( codepage == 874 ) - { - return wxFONTENCODING_CP874; - } - - if ( codepage == 932 ) - { - return wxFONTENCODING_CP932; - } - - if ( codepage == 936 ) - { - return wxFONTENCODING_CP936; - } - - if ( codepage == 949 ) - { - return wxFONTENCODING_CP949; - } - - if ( codepage == 950 ) - { - return wxFONTENCODING_CP950; - } -#elif defined(__WXMAC__) - TextEncoding encoding = 0 ; -#if TARGET_CARBON - encoding = CFStringGetSystemEncoding() ; -#else - UpgradeScriptInfoToTextEncoding ( smSystemScript , kTextLanguageDontCare , kTextRegionDontCare , NULL , &encoding ) ; -#endif - return wxMacGetFontEncFromSystemEnc( encoding ) ; -#elif defined(__UNIX_LIKE__) && wxUSE_FONTMAP - const wxString encname = GetSystemEncodingName(); - if ( !encname.empty() ) - { - wxFontEncoding enc = wxFontMapperBase::GetEncodingFromName(encname); - - // on some modern Linux systems (RedHat 8) the default system locale - // is UTF8 -- but it isn't supported by wxGTK1 in ANSI build at all so - // don't even try to use it in this case -#if !wxUSE_UNICODE && \ - ((defined(__WXGTK__) && !defined(__WXGTK20__)) || defined(__WXMOTIF__)) - if ( enc == wxFONTENCODING_UTF8 ) - { - // the most similar supported encoding... - enc = wxFONTENCODING_ISO8859_1; - } -#endif // !wxUSE_UNICODE - - // GetEncodingFromName() returns wxFONTENCODING_DEFAULT for C locale - // (a.k.a. US-ASCII) which is arguably a bug but keep it like this for - // backwards compatibility and just take care to not return - // wxFONTENCODING_DEFAULT from here as this surely doesn't make sense - if ( enc != wxFONTENCODING_MAX && enc != wxFONTENCODING_DEFAULT ) - { - return enc; - } - //else: return wxFONTENCODING_SYSTEM below - } -#endif // Win32/Unix - - return wxFONTENCODING_SYSTEM; -} - -/* static */ -void wxLocale::AddLanguage(const wxLanguageInfo& info) -{ - CreateLanguagesDB(); - ms_languagesDB->Add(info); -} - -/* static */ -const wxLanguageInfo *wxLocale::GetLanguageInfo(int lang) -{ - CreateLanguagesDB(); - - // calling GetLanguageInfo(wxLANGUAGE_DEFAULT) is a natural thing to do, so - // make it work - if ( lang == wxLANGUAGE_DEFAULT ) - lang = GetSystemLanguage(); - - const size_t count = ms_languagesDB->GetCount(); - for ( size_t i = 0; i < count; i++ ) - { - if ( ms_languagesDB->Item(i).Language == lang ) - { - // We need to create a temporary here in order to make this work with BCC in final build mode - wxLanguageInfo *ptr = &ms_languagesDB->Item(i); - return ptr; - } - } - - return NULL; -} - -/* static */ -wxString wxLocale::GetLanguageName(int lang) -{ - const wxLanguageInfo *info = GetLanguageInfo(lang); - if ( !info ) - return wxEmptyString; - else - return info->Description; -} - -/* static */ -const wxLanguageInfo *wxLocale::FindLanguageInfo(const wxString& locale) -{ - CreateLanguagesDB(); - - const wxLanguageInfo *infoRet = NULL; - - const size_t count = ms_languagesDB->GetCount(); - for ( size_t i = 0; i < count; i++ ) - { - const wxLanguageInfo *info = &ms_languagesDB->Item(i); - - if ( wxStricmp(locale, info->CanonicalName) == 0 || - wxStricmp(locale, info->Description) == 0 ) - { - // exact match, stop searching - infoRet = info; - break; - } - - if ( wxStricmp(locale, info->CanonicalName.BeforeFirst(_T('_'))) == 0 ) - { - // a match -- but maybe we'll find an exact one later, so continue - // looking - // - // OTOH, maybe we had already found a language match and in this - // case don't overwrite it becauce the entry for the default - // country always appears first in ms_languagesDB - if ( !infoRet ) - infoRet = info; - } - } - - return infoRet; -} - -wxString wxLocale::GetSysName() const -{ - // FIXME -#ifndef __WXWINCE__ - return wxSetlocale(LC_ALL, NULL); -#else - return wxEmptyString; -#endif -} - -// clean up -wxLocale::~wxLocale() -{ - // free memory - wxMsgCatalog *pTmpCat; - while ( m_pMsgCat != NULL ) { - pTmpCat = m_pMsgCat; - m_pMsgCat = m_pMsgCat->m_pNext; - delete pTmpCat; - } - - // restore old locale pointer - wxSetLocale(m_pOldLocale); - - // FIXME -#ifndef __WXWINCE__ - wxSetlocale(LC_ALL, m_pszOldLocale); -#endif - free((wxChar *)m_pszOldLocale); // const_cast -} - -// get the translation of given string in current locale -const wxChar *wxLocale::GetString(const wxChar *szOrigString, - const wxChar *szDomain) const -{ - return GetString(szOrigString, szOrigString, size_t(-1), szDomain); -} - -const wxChar *wxLocale::GetString(const wxChar *szOrigString, - const wxChar *szOrigString2, - size_t n, - const wxChar *szDomain) const -{ - if ( wxIsEmpty(szOrigString) ) - return wxEmptyString; - - const wxChar *pszTrans = NULL; - wxMsgCatalog *pMsgCat; - - if ( szDomain != NULL && szDomain[0] ) - { - pMsgCat = FindCatalog(szDomain); - - // does the catalog exist? - if ( pMsgCat != NULL ) - pszTrans = pMsgCat->GetString(szOrigString, n); - } - else - { - // search in all domains - for ( pMsgCat = m_pMsgCat; pMsgCat != NULL; pMsgCat = pMsgCat->m_pNext ) - { - pszTrans = pMsgCat->GetString(szOrigString, n); - if ( pszTrans != NULL ) // take the first found - break; - } - } - - if ( pszTrans == NULL ) - { -#ifdef __WXDEBUG__ - if ( !NoTransErr::Suppress() ) - { - NoTransErr noTransErr; - - wxLogTrace(TRACE_I18N, - _T("string \"%s\"[%ld] not found in %slocale '%s'."), - szOrigString, (long)n, - szDomain ? wxString::Format(_T("domain '%s' "), szDomain).c_str() - : _T(""), - m_strLocale.c_str()); - } -#endif // __WXDEBUG__ - - if (n == size_t(-1)) - return szOrigString; - else - return n == 1 ? szOrigString : szOrigString2; - } - - return pszTrans; -} - -wxString wxLocale::GetHeaderValue( const wxChar* szHeader, - const wxChar* szDomain ) const -{ - if ( wxIsEmpty(szHeader) ) - return wxEmptyString; - - wxChar const * pszTrans = NULL; - wxMsgCatalog *pMsgCat; - - if ( szDomain != NULL ) - { - pMsgCat = FindCatalog(szDomain); - - // does the catalog exist? - if ( pMsgCat == NULL ) - return wxEmptyString; - - pszTrans = pMsgCat->GetString(wxEmptyString, (size_t)-1); - } - else - { - // search in all domains - for ( pMsgCat = m_pMsgCat; pMsgCat != NULL; pMsgCat = pMsgCat->m_pNext ) - { - pszTrans = pMsgCat->GetString(wxEmptyString, (size_t)-1); - if ( pszTrans != NULL ) // take the first found - break; - } - } - - if ( wxIsEmpty(pszTrans) ) - return wxEmptyString; - - wxChar const * pszFound = wxStrstr(pszTrans, szHeader); - if ( pszFound == NULL ) - return wxEmptyString; - - pszFound += wxStrlen(szHeader) + 2 /* ': ' */; - - // Every header is separated by \n - - wxChar const * pszEndLine = wxStrchr(pszFound, wxT('\n')); - if ( pszEndLine == NULL ) pszEndLine = pszFound + wxStrlen(pszFound); - - - // wxString( wxChar*, length); - wxString retVal( pszFound, pszEndLine - pszFound ); - - return retVal; -} - - -// find catalog by name in a linked list, return NULL if !found -wxMsgCatalog *wxLocale::FindCatalog(const wxChar *szDomain) const -{ - // linear search in the linked list - wxMsgCatalog *pMsgCat; - for ( pMsgCat = m_pMsgCat; pMsgCat != NULL; pMsgCat = pMsgCat->m_pNext ) - { - if ( wxStricmp(pMsgCat->GetName(), szDomain) == 0 ) - return pMsgCat; - } - - return NULL; -} - -// check if the given locale is provided by OS and C run time -/* static */ -bool wxLocale::IsAvailable(int lang) -{ - const wxLanguageInfo *info = wxLocale::GetLanguageInfo(lang); - wxCHECK_MSG( info, false, _T("invalid language") ); - -#if defined(__WIN32__) - if ( !info->WinLang ) - return false; - - if ( !::IsValidLocale - ( - MAKELCID(MAKELANGID(info->WinLang, info->WinSublang), - SORT_DEFAULT), - LCID_INSTALLED - ) ) - return false; - -#elif defined(__UNIX__) - - // Test if setting the locale works, then set it back. - wxMB2WXbuf oldLocale = wxSetlocale(LC_ALL, wxEmptyString); - wxMB2WXbuf tmp = wxSetlocaleTryUTF(LC_ALL, info->CanonicalName); - if ( !tmp ) - { - // Some C libraries don't like xx_YY form and require xx only - tmp = wxSetlocaleTryUTF(LC_ALL, info->CanonicalName.Left(2)); - if ( !tmp ) - return false; - } - // restore the original locale - wxSetlocale(LC_ALL, oldLocale); -#endif - - return true; -} - -// check if the given catalog is loaded -bool wxLocale::IsLoaded(const wxChar *szDomain) const -{ - return FindCatalog(szDomain) != NULL; -} - -// add a catalog to our linked list -bool wxLocale::AddCatalog(const wxChar *szDomain) -{ - return AddCatalog(szDomain, wxLANGUAGE_ENGLISH_US, NULL); -} - -// add a catalog to our linked list -bool wxLocale::AddCatalog(const wxChar *szDomain, - wxLanguage msgIdLanguage, - const wxChar *msgIdCharset) - -{ - wxMsgCatalog *pMsgCat = new wxMsgCatalog; - - if ( pMsgCat->Load(m_strShort, szDomain, msgIdCharset, m_bConvertEncoding) ) { - // add it to the head of the list so that in GetString it will - // be searched before the catalogs added earlier - pMsgCat->m_pNext = m_pMsgCat; - m_pMsgCat = pMsgCat; - - return true; - } - else { - // don't add it because it couldn't be loaded anyway - delete pMsgCat; - - // It is OK to not load catalog if the msgid language and m_language match, - // in which case we can directly display the texts embedded in program's - // source code: - if (m_language == msgIdLanguage) - return true; - - // If there's no exact match, we may still get partial match where the - // (basic) language is same, but the country differs. For example, it's - // permitted to use en_US strings from sources even if m_language is en_GB: - const wxLanguageInfo *msgIdLangInfo = GetLanguageInfo(msgIdLanguage); - if ( msgIdLangInfo && - msgIdLangInfo->CanonicalName.Mid(0, 2) == m_strShort.Mid(0, 2) ) - { - return true; - } - - return false; - } -} - -// ---------------------------------------------------------------------------- -// accessors for locale-dependent data -// ---------------------------------------------------------------------------- - -#ifdef __WXMSW__ - -/* static */ -wxString wxLocale::GetInfo(wxLocaleInfo index, wxLocaleCategory WXUNUSED(cat)) -{ - wxUint32 lcid = LOCALE_USER_DEFAULT; - - if (wxGetLocale()) - { - const wxLanguageInfo *info = GetLanguageInfo(wxGetLocale()->GetLanguage()); - if (info) - { ; - lcid = MAKELCID(MAKELANGID(info->WinLang, info->WinSublang), - SORT_DEFAULT); - } - } - - wxString str; - wxChar buffer[256]; - size_t count; - buffer[0] = wxT('\0'); - switch (index) - { - case wxLOCALE_DECIMAL_POINT: - count = ::GetLocaleInfo(lcid, LOCALE_SDECIMAL, buffer, 256); - if (!count) - str << wxT("."); - else - str << buffer; - break; -#if 0 - case wxSYS_LIST_SEPARATOR: - count = ::GetLocaleInfo(lcid, LOCALE_SLIST, buffer, 256); - if (!count) - str << wxT(","); - else - str << buffer; - break; - case wxSYS_LEADING_ZERO: // 0 means no leading zero, 1 means leading zero - count = ::GetLocaleInfo(lcid, LOCALE_ILZERO, buffer, 256); - if (!count) - str << wxT("0"); - else - str << buffer; - break; -#endif - default: - wxFAIL_MSG(wxT("Unknown System String !")); - } - return str; -} - -#elif defined(__DARWIN__) - -/* static */ -wxString wxLocale::GetInfo(wxLocaleInfo index, wxLocaleCategory WXUNUSED(cat)) -{ - CFLocaleRef userLocaleRefRaw; - if ( wxGetLocale() ) - { - userLocaleRefRaw = CFLocaleCreate - ( - kCFAllocatorDefault, - wxMacCFStringHolder(wxGetLocale()->GetCanonicalName()) - ); - } - else // no current locale, use the default one - { - userLocaleRefRaw = CFLocaleCopyCurrent(); - } - - wxCFRef userLocaleRef(userLocaleRefRaw); - - CFTypeRef cfstr; - switch ( index ) - { - case wxLOCALE_THOUSANDS_SEP: - cfstr = CFLocaleGetValue(userLocaleRef, kCFLocaleGroupingSeparator); - break; - - case wxLOCALE_DECIMAL_POINT: - cfstr = CFLocaleGetValue(userLocaleRef, kCFLocaleDecimalSeparator); - break; - - default: - wxFAIL_MSG( _T("Unknown locale info") ); - } - - wxMacCFStringHolder - str(CFStringCreateCopy(NULL, static_cast(cfstr))); - return str.AsString(); -} - -#else // !__WXMSW__ && !__DARWIN__ - -/* static */ -wxString wxLocale::GetInfo(wxLocaleInfo index, wxLocaleCategory cat) -{ - struct lconv *locale_info = localeconv(); - switch (cat) - { - case wxLOCALE_CAT_NUMBER: - switch (index) - { - case wxLOCALE_THOUSANDS_SEP: - return wxString(locale_info->thousands_sep, - *wxConvCurrent); - case wxLOCALE_DECIMAL_POINT: - return wxString(locale_info->decimal_point, - *wxConvCurrent); - default: - return wxEmptyString; - } - case wxLOCALE_CAT_MONEY: - switch (index) - { - case wxLOCALE_THOUSANDS_SEP: - return wxString(locale_info->mon_thousands_sep, - *wxConvCurrent); - case wxLOCALE_DECIMAL_POINT: - return wxString(locale_info->mon_decimal_point, - *wxConvCurrent); - default: - return wxEmptyString; - } - default: - return wxEmptyString; - } -} - -#endif // __WXMSW__/!__WXMSW__ - -// ---------------------------------------------------------------------------- -// global functions and variables -// ---------------------------------------------------------------------------- - -// retrieve/change current locale -// ------------------------------ - -// the current locale object -static wxLocale *g_pLocale = NULL; - -wxLocale *wxGetLocale() -{ - return g_pLocale; -} - -wxLocale *wxSetLocale(wxLocale *pLocale) -{ - wxLocale *pOld = g_pLocale; - g_pLocale = pLocale; - return pOld; -} - - - -// ---------------------------------------------------------------------------- -// wxLocale module (for lazy destruction of languagesDB) -// ---------------------------------------------------------------------------- - -class wxLocaleModule: public wxModule -{ - DECLARE_DYNAMIC_CLASS(wxLocaleModule) - public: - wxLocaleModule() {} - bool OnInit() { return true; } - void OnExit() { wxLocale::DestroyLanguagesDB(); } -}; - -IMPLEMENT_DYNAMIC_CLASS(wxLocaleModule, wxModule) - - - -// ---------------------------------------------------------------------------- -// default languages table & initialization -// ---------------------------------------------------------------------------- - - - -// --- --- --- generated code begins here --- --- --- - -// This table is generated by misc/languages/genlang.py -// When making changes, please put them into misc/languages/langtabl.txt - -#if !defined(__WIN32__) || defined(__WXMICROWIN__) - -#define SETWINLANG(info,lang,sublang) - -#else - -#define SETWINLANG(info,lang,sublang) \ - info.WinLang = lang, info.WinSublang = sublang; - -#ifndef LANG_AFRIKAANS -#define LANG_AFRIKAANS (0) -#endif -#ifndef LANG_ALBANIAN -#define LANG_ALBANIAN (0) -#endif -#ifndef LANG_ARABIC -#define LANG_ARABIC (0) -#endif -#ifndef LANG_ARMENIAN -#define LANG_ARMENIAN (0) -#endif -#ifndef LANG_ASSAMESE -#define LANG_ASSAMESE (0) -#endif -#ifndef LANG_AZERI -#define LANG_AZERI (0) -#endif -#ifndef LANG_BASQUE -#define LANG_BASQUE (0) -#endif -#ifndef LANG_BELARUSIAN -#define LANG_BELARUSIAN (0) -#endif -#ifndef LANG_BENGALI -#define LANG_BENGALI (0) -#endif -#ifndef LANG_BULGARIAN -#define LANG_BULGARIAN (0) -#endif -#ifndef LANG_CATALAN -#define LANG_CATALAN (0) -#endif -#ifndef LANG_CHINESE -#define LANG_CHINESE (0) -#endif -#ifndef LANG_CROATIAN -#define LANG_CROATIAN (0) -#endif -#ifndef LANG_CZECH -#define LANG_CZECH (0) -#endif -#ifndef LANG_DANISH -#define LANG_DANISH (0) -#endif -#ifndef LANG_DUTCH -#define LANG_DUTCH (0) -#endif -#ifndef LANG_ENGLISH -#define LANG_ENGLISH (0) -#endif -#ifndef LANG_ESTONIAN -#define LANG_ESTONIAN (0) -#endif -#ifndef LANG_FAEROESE -#define LANG_FAEROESE (0) -#endif -#ifndef LANG_FARSI -#define LANG_FARSI (0) -#endif -#ifndef LANG_FINNISH -#define LANG_FINNISH (0) -#endif -#ifndef LANG_FRENCH -#define LANG_FRENCH (0) -#endif -#ifndef LANG_GEORGIAN -#define LANG_GEORGIAN (0) -#endif -#ifndef LANG_GERMAN -#define LANG_GERMAN (0) -#endif -#ifndef LANG_GREEK -#define LANG_GREEK (0) -#endif -#ifndef LANG_GUJARATI -#define LANG_GUJARATI (0) -#endif -#ifndef LANG_HEBREW -#define LANG_HEBREW (0) -#endif -#ifndef LANG_HINDI -#define LANG_HINDI (0) -#endif -#ifndef LANG_HUNGARIAN -#define LANG_HUNGARIAN (0) -#endif -#ifndef LANG_ICELANDIC -#define LANG_ICELANDIC (0) -#endif -#ifndef LANG_INDONESIAN -#define LANG_INDONESIAN (0) -#endif -#ifndef LANG_ITALIAN -#define LANG_ITALIAN (0) -#endif -#ifndef LANG_JAPANESE -#define LANG_JAPANESE (0) -#endif -#ifndef LANG_KANNADA -#define LANG_KANNADA (0) -#endif -#ifndef LANG_KASHMIRI -#define LANG_KASHMIRI (0) -#endif -#ifndef LANG_KAZAK -#define LANG_KAZAK (0) -#endif -#ifndef LANG_KONKANI -#define LANG_KONKANI (0) -#endif -#ifndef LANG_KOREAN -#define LANG_KOREAN (0) -#endif -#ifndef LANG_LATVIAN -#define LANG_LATVIAN (0) -#endif -#ifndef LANG_LITHUANIAN -#define LANG_LITHUANIAN (0) -#endif -#ifndef LANG_MACEDONIAN -#define LANG_MACEDONIAN (0) -#endif -#ifndef LANG_MALAY -#define LANG_MALAY (0) -#endif -#ifndef LANG_MALAYALAM -#define LANG_MALAYALAM (0) -#endif -#ifndef LANG_MANIPURI -#define LANG_MANIPURI (0) -#endif -#ifndef LANG_MARATHI -#define LANG_MARATHI (0) -#endif -#ifndef LANG_NEPALI -#define LANG_NEPALI (0) -#endif -#ifndef LANG_NORWEGIAN -#define LANG_NORWEGIAN (0) -#endif -#ifndef LANG_ORIYA -#define LANG_ORIYA (0) -#endif -#ifndef LANG_POLISH -#define LANG_POLISH (0) -#endif -#ifndef LANG_PORTUGUESE -#define LANG_PORTUGUESE (0) -#endif -#ifndef LANG_PUNJABI -#define LANG_PUNJABI (0) -#endif -#ifndef LANG_ROMANIAN -#define LANG_ROMANIAN (0) -#endif -#ifndef LANG_RUSSIAN -#define LANG_RUSSIAN (0) -#endif -#ifndef LANG_SAMI -#define LANG_SAMI (0) -#endif -#ifndef LANG_SANSKRIT -#define LANG_SANSKRIT (0) -#endif -#ifndef LANG_SERBIAN -#define LANG_SERBIAN (0) -#endif -#ifndef LANG_SINDHI -#define LANG_SINDHI (0) -#endif -#ifndef LANG_SLOVAK -#define LANG_SLOVAK (0) -#endif -#ifndef LANG_SLOVENIAN -#define LANG_SLOVENIAN (0) -#endif -#ifndef LANG_SPANISH -#define LANG_SPANISH (0) -#endif -#ifndef LANG_SWAHILI -#define LANG_SWAHILI (0) -#endif -#ifndef LANG_SWEDISH -#define LANG_SWEDISH (0) -#endif -#ifndef LANG_TAMIL -#define LANG_TAMIL (0) -#endif -#ifndef LANG_TATAR -#define LANG_TATAR (0) -#endif -#ifndef LANG_TELUGU -#define LANG_TELUGU (0) -#endif -#ifndef LANG_THAI -#define LANG_THAI (0) -#endif -#ifndef LANG_TURKISH -#define LANG_TURKISH (0) -#endif -#ifndef LANG_UKRAINIAN -#define LANG_UKRAINIAN (0) -#endif -#ifndef LANG_URDU -#define LANG_URDU (0) -#endif -#ifndef LANG_UZBEK -#define LANG_UZBEK (0) -#endif -#ifndef LANG_VALENCIAN -#define LANG_VALENCIAN (0) -#endif -#ifndef LANG_VIETNAMESE -#define LANG_VIETNAMESE (0) -#endif -#ifndef SUBLANG_ARABIC_ALGERIA -#define SUBLANG_ARABIC_ALGERIA SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_ARABIC_BAHRAIN -#define SUBLANG_ARABIC_BAHRAIN SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_ARABIC_EGYPT -#define SUBLANG_ARABIC_EGYPT SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_ARABIC_IRAQ -#define SUBLANG_ARABIC_IRAQ SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_ARABIC_JORDAN -#define SUBLANG_ARABIC_JORDAN SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_ARABIC_KUWAIT -#define SUBLANG_ARABIC_KUWAIT SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_ARABIC_LEBANON -#define SUBLANG_ARABIC_LEBANON SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_ARABIC_LIBYA -#define SUBLANG_ARABIC_LIBYA SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_ARABIC_MOROCCO -#define SUBLANG_ARABIC_MOROCCO SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_ARABIC_OMAN -#define SUBLANG_ARABIC_OMAN SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_ARABIC_QATAR -#define SUBLANG_ARABIC_QATAR SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_ARABIC_SAUDI_ARABIA -#define SUBLANG_ARABIC_SAUDI_ARABIA SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_ARABIC_SYRIA -#define SUBLANG_ARABIC_SYRIA SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_ARABIC_TUNISIA -#define SUBLANG_ARABIC_TUNISIA SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_ARABIC_UAE -#define SUBLANG_ARABIC_UAE SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_ARABIC_YEMEN -#define SUBLANG_ARABIC_YEMEN SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_AZERI_CYRILLIC -#define SUBLANG_AZERI_CYRILLIC SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_AZERI_LATIN -#define SUBLANG_AZERI_LATIN SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_CHINESE_SIMPLIFIED -#define SUBLANG_CHINESE_SIMPLIFIED SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_CHINESE_TRADITIONAL -#define SUBLANG_CHINESE_TRADITIONAL SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_CHINESE_HONGKONG -#define SUBLANG_CHINESE_HONGKONG SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_CHINESE_MACAU -#define SUBLANG_CHINESE_MACAU SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_CHINESE_SINGAPORE -#define SUBLANG_CHINESE_SINGAPORE SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_DUTCH -#define SUBLANG_DUTCH SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_DUTCH_BELGIAN -#define SUBLANG_DUTCH_BELGIAN SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_ENGLISH_UK -#define SUBLANG_ENGLISH_UK SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_ENGLISH_US -#define SUBLANG_ENGLISH_US SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_ENGLISH_AUS -#define SUBLANG_ENGLISH_AUS SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_ENGLISH_BELIZE -#define SUBLANG_ENGLISH_BELIZE SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_ENGLISH_CAN -#define SUBLANG_ENGLISH_CAN SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_ENGLISH_CARIBBEAN -#define SUBLANG_ENGLISH_CARIBBEAN SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_ENGLISH_EIRE -#define SUBLANG_ENGLISH_EIRE SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_ENGLISH_JAMAICA -#define SUBLANG_ENGLISH_JAMAICA SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_ENGLISH_NZ -#define SUBLANG_ENGLISH_NZ SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_ENGLISH_PHILIPPINES -#define SUBLANG_ENGLISH_PHILIPPINES SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_ENGLISH_SOUTH_AFRICA -#define SUBLANG_ENGLISH_SOUTH_AFRICA SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_ENGLISH_TRINIDAD -#define SUBLANG_ENGLISH_TRINIDAD SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_ENGLISH_ZIMBABWE -#define SUBLANG_ENGLISH_ZIMBABWE SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_FRENCH -#define SUBLANG_FRENCH SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_FRENCH_BELGIAN -#define SUBLANG_FRENCH_BELGIAN SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_FRENCH_CANADIAN -#define SUBLANG_FRENCH_CANADIAN SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_FRENCH_LUXEMBOURG -#define SUBLANG_FRENCH_LUXEMBOURG SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_FRENCH_MONACO -#define SUBLANG_FRENCH_MONACO SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_FRENCH_SWISS -#define SUBLANG_FRENCH_SWISS SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_GERMAN -#define SUBLANG_GERMAN SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_GERMAN_AUSTRIAN -#define SUBLANG_GERMAN_AUSTRIAN SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_GERMAN_LIECHTENSTEIN -#define SUBLANG_GERMAN_LIECHTENSTEIN SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_GERMAN_LUXEMBOURG -#define SUBLANG_GERMAN_LUXEMBOURG SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_GERMAN_SWISS -#define SUBLANG_GERMAN_SWISS SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_ITALIAN -#define SUBLANG_ITALIAN SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_ITALIAN_SWISS -#define SUBLANG_ITALIAN_SWISS SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_KASHMIRI_INDIA -#define SUBLANG_KASHMIRI_INDIA SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_KOREAN -#define SUBLANG_KOREAN SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_LITHUANIAN -#define SUBLANG_LITHUANIAN SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_MALAY_BRUNEI_DARUSSALAM -#define SUBLANG_MALAY_BRUNEI_DARUSSALAM SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_MALAY_MALAYSIA -#define SUBLANG_MALAY_MALAYSIA SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_NEPALI_INDIA -#define SUBLANG_NEPALI_INDIA SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_NORWEGIAN_BOKMAL -#define SUBLANG_NORWEGIAN_BOKMAL SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_NORWEGIAN_NYNORSK -#define SUBLANG_NORWEGIAN_NYNORSK SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_PORTUGUESE -#define SUBLANG_PORTUGUESE SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_PORTUGUESE_BRAZILIAN -#define SUBLANG_PORTUGUESE_BRAZILIAN SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_SERBIAN_CYRILLIC -#define SUBLANG_SERBIAN_CYRILLIC SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_SERBIAN_LATIN -#define SUBLANG_SERBIAN_LATIN SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_SPANISH -#define SUBLANG_SPANISH SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_SPANISH_ARGENTINA -#define SUBLANG_SPANISH_ARGENTINA SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_SPANISH_BOLIVIA -#define SUBLANG_SPANISH_BOLIVIA SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_SPANISH_CHILE -#define SUBLANG_SPANISH_CHILE SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_SPANISH_COLOMBIA -#define SUBLANG_SPANISH_COLOMBIA SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_SPANISH_COSTA_RICA -#define SUBLANG_SPANISH_COSTA_RICA SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_SPANISH_DOMINICAN_REPUBLIC -#define SUBLANG_SPANISH_DOMINICAN_REPUBLIC SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_SPANISH_ECUADOR -#define SUBLANG_SPANISH_ECUADOR SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_SPANISH_EL_SALVADOR -#define SUBLANG_SPANISH_EL_SALVADOR SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_SPANISH_GUATEMALA -#define SUBLANG_SPANISH_GUATEMALA SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_SPANISH_HONDURAS -#define SUBLANG_SPANISH_HONDURAS SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_SPANISH_MEXICAN -#define SUBLANG_SPANISH_MEXICAN SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_SPANISH_MODERN -#define SUBLANG_SPANISH_MODERN SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_SPANISH_NICARAGUA -#define SUBLANG_SPANISH_NICARAGUA SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_SPANISH_PANAMA -#define SUBLANG_SPANISH_PANAMA SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_SPANISH_PARAGUAY -#define SUBLANG_SPANISH_PARAGUAY SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_SPANISH_PERU -#define SUBLANG_SPANISH_PERU SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_SPANISH_PUERTO_RICO -#define SUBLANG_SPANISH_PUERTO_RICO SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_SPANISH_URUGUAY -#define SUBLANG_SPANISH_URUGUAY SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_SPANISH_VENEZUELA -#define SUBLANG_SPANISH_VENEZUELA SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_SWEDISH -#define SUBLANG_SWEDISH SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_SWEDISH_FINLAND -#define SUBLANG_SWEDISH_FINLAND SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_URDU_INDIA -#define SUBLANG_URDU_INDIA SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_URDU_PAKISTAN -#define SUBLANG_URDU_PAKISTAN SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_UZBEK_CYRILLIC -#define SUBLANG_UZBEK_CYRILLIC SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_UZBEK_LATIN -#define SUBLANG_UZBEK_LATIN SUBLANG_DEFAULT -#endif - - -#endif // __WIN32__ - -#define LNG(wxlang, canonical, winlang, winsublang, layout, desc) \ - info.Language = wxlang; \ - info.CanonicalName = wxT(canonical); \ - info.LayoutDirection = layout; \ - info.Description = wxT(desc); \ - SETWINLANG(info, winlang, winsublang) \ - AddLanguage(info); - -void wxLocale::InitLanguagesDB() -{ - wxLanguageInfo info; - wxStringTokenizer tkn; - - LNG(wxLANGUAGE_ABKHAZIAN, "ab" , 0 , 0 , wxLayout_LeftToRight, "Abkhazian") - LNG(wxLANGUAGE_AFAR, "aa" , 0 , 0 , wxLayout_LeftToRight, "Afar") - LNG(wxLANGUAGE_AFRIKAANS, "af_ZA", LANG_AFRIKAANS , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Afrikaans") - LNG(wxLANGUAGE_ALBANIAN, "sq_AL", LANG_ALBANIAN , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Albanian") - LNG(wxLANGUAGE_AMHARIC, "am" , 0 , 0 , wxLayout_LeftToRight, "Amharic") - LNG(wxLANGUAGE_ARABIC, "ar" , LANG_ARABIC , SUBLANG_DEFAULT , wxLayout_RightToLeft, "Arabic") - LNG(wxLANGUAGE_ARABIC_ALGERIA, "ar_DZ", LANG_ARABIC , SUBLANG_ARABIC_ALGERIA , wxLayout_RightToLeft, "Arabic (Algeria)") - LNG(wxLANGUAGE_ARABIC_BAHRAIN, "ar_BH", LANG_ARABIC , SUBLANG_ARABIC_BAHRAIN , wxLayout_RightToLeft, "Arabic (Bahrain)") - LNG(wxLANGUAGE_ARABIC_EGYPT, "ar_EG", LANG_ARABIC , SUBLANG_ARABIC_EGYPT , wxLayout_RightToLeft, "Arabic (Egypt)") - LNG(wxLANGUAGE_ARABIC_IRAQ, "ar_IQ", LANG_ARABIC , SUBLANG_ARABIC_IRAQ , wxLayout_RightToLeft, "Arabic (Iraq)") - LNG(wxLANGUAGE_ARABIC_JORDAN, "ar_JO", LANG_ARABIC , SUBLANG_ARABIC_JORDAN , wxLayout_RightToLeft, "Arabic (Jordan)") - LNG(wxLANGUAGE_ARABIC_KUWAIT, "ar_KW", LANG_ARABIC , SUBLANG_ARABIC_KUWAIT , wxLayout_RightToLeft, "Arabic (Kuwait)") - LNG(wxLANGUAGE_ARABIC_LEBANON, "ar_LB", LANG_ARABIC , SUBLANG_ARABIC_LEBANON , wxLayout_RightToLeft, "Arabic (Lebanon)") - LNG(wxLANGUAGE_ARABIC_LIBYA, "ar_LY", LANG_ARABIC , SUBLANG_ARABIC_LIBYA , wxLayout_RightToLeft, "Arabic (Libya)") - LNG(wxLANGUAGE_ARABIC_MOROCCO, "ar_MA", LANG_ARABIC , SUBLANG_ARABIC_MOROCCO , wxLayout_RightToLeft, "Arabic (Morocco)") - LNG(wxLANGUAGE_ARABIC_OMAN, "ar_OM", LANG_ARABIC , SUBLANG_ARABIC_OMAN , wxLayout_RightToLeft, "Arabic (Oman)") - LNG(wxLANGUAGE_ARABIC_QATAR, "ar_QA", LANG_ARABIC , SUBLANG_ARABIC_QATAR , wxLayout_RightToLeft, "Arabic (Qatar)") - LNG(wxLANGUAGE_ARABIC_SAUDI_ARABIA, "ar_SA", LANG_ARABIC , SUBLANG_ARABIC_SAUDI_ARABIA , wxLayout_RightToLeft, "Arabic (Saudi Arabia)") - LNG(wxLANGUAGE_ARABIC_SUDAN, "ar_SD", 0 , 0 , wxLayout_RightToLeft, "Arabic (Sudan)") - LNG(wxLANGUAGE_ARABIC_SYRIA, "ar_SY", LANG_ARABIC , SUBLANG_ARABIC_SYRIA , wxLayout_RightToLeft, "Arabic (Syria)") - LNG(wxLANGUAGE_ARABIC_TUNISIA, "ar_TN", LANG_ARABIC , SUBLANG_ARABIC_TUNISIA , wxLayout_RightToLeft, "Arabic (Tunisia)") - LNG(wxLANGUAGE_ARABIC_UAE, "ar_AE", LANG_ARABIC , SUBLANG_ARABIC_UAE , wxLayout_RightToLeft, "Arabic (Uae)") - LNG(wxLANGUAGE_ARABIC_YEMEN, "ar_YE", LANG_ARABIC , SUBLANG_ARABIC_YEMEN , wxLayout_RightToLeft, "Arabic (Yemen)") - LNG(wxLANGUAGE_ARMENIAN, "hy" , LANG_ARMENIAN , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Armenian") - LNG(wxLANGUAGE_ASSAMESE, "as" , LANG_ASSAMESE , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Assamese") - LNG(wxLANGUAGE_AYMARA, "ay" , 0 , 0 , wxLayout_LeftToRight, "Aymara") - LNG(wxLANGUAGE_AZERI, "az" , LANG_AZERI , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Azeri") - LNG(wxLANGUAGE_AZERI_CYRILLIC, "az" , LANG_AZERI , SUBLANG_AZERI_CYRILLIC , wxLayout_LeftToRight, "Azeri (Cyrillic)") - LNG(wxLANGUAGE_AZERI_LATIN, "az" , LANG_AZERI , SUBLANG_AZERI_LATIN , wxLayout_LeftToRight, "Azeri (Latin)") - LNG(wxLANGUAGE_BASHKIR, "ba" , 0 , 0 , wxLayout_LeftToRight, "Bashkir") - LNG(wxLANGUAGE_BASQUE, "eu_ES", LANG_BASQUE , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Basque") - LNG(wxLANGUAGE_BELARUSIAN, "be_BY", LANG_BELARUSIAN, SUBLANG_DEFAULT , wxLayout_LeftToRight, "Belarusian") - LNG(wxLANGUAGE_BENGALI, "bn" , LANG_BENGALI , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Bengali") - LNG(wxLANGUAGE_BHUTANI, "dz" , 0 , 0 , wxLayout_LeftToRight, "Bhutani") - LNG(wxLANGUAGE_BIHARI, "bh" , 0 , 0 , wxLayout_LeftToRight, "Bihari") - LNG(wxLANGUAGE_BISLAMA, "bi" , 0 , 0 , wxLayout_LeftToRight, "Bislama") - LNG(wxLANGUAGE_BRETON, "br" , 0 , 0 , wxLayout_LeftToRight, "Breton") - LNG(wxLANGUAGE_BULGARIAN, "bg_BG", LANG_BULGARIAN , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Bulgarian") - LNG(wxLANGUAGE_BURMESE, "my" , 0 , 0 , wxLayout_LeftToRight, "Burmese") - LNG(wxLANGUAGE_CAMBODIAN, "km" , 0 , 0 , wxLayout_LeftToRight, "Cambodian") - LNG(wxLANGUAGE_CATALAN, "ca_ES", LANG_CATALAN , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Catalan") - LNG(wxLANGUAGE_CHINESE, "zh_TW", LANG_CHINESE , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Chinese") - LNG(wxLANGUAGE_CHINESE_SIMPLIFIED, "zh_CN", LANG_CHINESE , SUBLANG_CHINESE_SIMPLIFIED , wxLayout_LeftToRight, "Chinese (Simplified)") - LNG(wxLANGUAGE_CHINESE_TRADITIONAL, "zh_TW", LANG_CHINESE , SUBLANG_CHINESE_TRADITIONAL , wxLayout_LeftToRight, "Chinese (Traditional)") - LNG(wxLANGUAGE_CHINESE_HONGKONG, "zh_HK", LANG_CHINESE , SUBLANG_CHINESE_HONGKONG , wxLayout_LeftToRight, "Chinese (Hongkong)") - LNG(wxLANGUAGE_CHINESE_MACAU, "zh_MO", LANG_CHINESE , SUBLANG_CHINESE_MACAU , wxLayout_LeftToRight, "Chinese (Macau)") - LNG(wxLANGUAGE_CHINESE_SINGAPORE, "zh_SG", LANG_CHINESE , SUBLANG_CHINESE_SINGAPORE , wxLayout_LeftToRight, "Chinese (Singapore)") - LNG(wxLANGUAGE_CHINESE_TAIWAN, "zh_TW", LANG_CHINESE , SUBLANG_CHINESE_TRADITIONAL , wxLayout_LeftToRight, "Chinese (Taiwan)") - LNG(wxLANGUAGE_CORSICAN, "co" , 0 , 0 , wxLayout_LeftToRight, "Corsican") - LNG(wxLANGUAGE_CROATIAN, "hr_HR", LANG_CROATIAN , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Croatian") - LNG(wxLANGUAGE_CZECH, "cs_CZ", LANG_CZECH , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Czech") - LNG(wxLANGUAGE_DANISH, "da_DK", LANG_DANISH , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Danish") - LNG(wxLANGUAGE_DUTCH, "nl_NL", LANG_DUTCH , SUBLANG_DUTCH , wxLayout_LeftToRight, "Dutch") - LNG(wxLANGUAGE_DUTCH_BELGIAN, "nl_BE", LANG_DUTCH , SUBLANG_DUTCH_BELGIAN , wxLayout_LeftToRight, "Dutch (Belgian)") - LNG(wxLANGUAGE_ENGLISH, "en_GB", LANG_ENGLISH , SUBLANG_ENGLISH_UK , wxLayout_LeftToRight, "English") - LNG(wxLANGUAGE_ENGLISH_UK, "en_GB", LANG_ENGLISH , SUBLANG_ENGLISH_UK , wxLayout_LeftToRight, "English (U.K.)") - LNG(wxLANGUAGE_ENGLISH_US, "en_US", LANG_ENGLISH , SUBLANG_ENGLISH_US , wxLayout_LeftToRight, "English (U.S.)") - LNG(wxLANGUAGE_ENGLISH_AUSTRALIA, "en_AU", LANG_ENGLISH , SUBLANG_ENGLISH_AUS , wxLayout_LeftToRight, "English (Australia)") - LNG(wxLANGUAGE_ENGLISH_BELIZE, "en_BZ", LANG_ENGLISH , SUBLANG_ENGLISH_BELIZE , wxLayout_LeftToRight, "English (Belize)") - LNG(wxLANGUAGE_ENGLISH_BOTSWANA, "en_BW", 0 , 0 , wxLayout_LeftToRight, "English (Botswana)") - LNG(wxLANGUAGE_ENGLISH_CANADA, "en_CA", LANG_ENGLISH , SUBLANG_ENGLISH_CAN , wxLayout_LeftToRight, "English (Canada)") - LNG(wxLANGUAGE_ENGLISH_CARIBBEAN, "en_CB", LANG_ENGLISH , SUBLANG_ENGLISH_CARIBBEAN , wxLayout_LeftToRight, "English (Caribbean)") - LNG(wxLANGUAGE_ENGLISH_DENMARK, "en_DK", 0 , 0 , wxLayout_LeftToRight, "English (Denmark)") - LNG(wxLANGUAGE_ENGLISH_EIRE, "en_IE", LANG_ENGLISH , SUBLANG_ENGLISH_EIRE , wxLayout_LeftToRight, "English (Eire)") - LNG(wxLANGUAGE_ENGLISH_JAMAICA, "en_JM", LANG_ENGLISH , SUBLANG_ENGLISH_JAMAICA , wxLayout_LeftToRight, "English (Jamaica)") - LNG(wxLANGUAGE_ENGLISH_NEW_ZEALAND, "en_NZ", LANG_ENGLISH , SUBLANG_ENGLISH_NZ , wxLayout_LeftToRight, "English (New Zealand)") - LNG(wxLANGUAGE_ENGLISH_PHILIPPINES, "en_PH", LANG_ENGLISH , SUBLANG_ENGLISH_PHILIPPINES , wxLayout_LeftToRight, "English (Philippines)") - LNG(wxLANGUAGE_ENGLISH_SOUTH_AFRICA, "en_ZA", LANG_ENGLISH , SUBLANG_ENGLISH_SOUTH_AFRICA , wxLayout_LeftToRight, "English (South Africa)") - LNG(wxLANGUAGE_ENGLISH_TRINIDAD, "en_TT", LANG_ENGLISH , SUBLANG_ENGLISH_TRINIDAD , wxLayout_LeftToRight, "English (Trinidad)") - LNG(wxLANGUAGE_ENGLISH_ZIMBABWE, "en_ZW", LANG_ENGLISH , SUBLANG_ENGLISH_ZIMBABWE , wxLayout_LeftToRight, "English (Zimbabwe)") - LNG(wxLANGUAGE_ESPERANTO, "eo" , 0 , 0 , wxLayout_LeftToRight, "Esperanto") - LNG(wxLANGUAGE_ESTONIAN, "et_EE", LANG_ESTONIAN , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Estonian") - LNG(wxLANGUAGE_FAEROESE, "fo_FO", LANG_FAEROESE , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Faeroese") - LNG(wxLANGUAGE_FARSI, "fa_IR", LANG_FARSI , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Farsi") - LNG(wxLANGUAGE_FIJI, "fj" , 0 , 0 , wxLayout_LeftToRight, "Fiji") - LNG(wxLANGUAGE_FINNISH, "fi_FI", LANG_FINNISH , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Finnish") - LNG(wxLANGUAGE_FRENCH, "fr_FR", LANG_FRENCH , SUBLANG_FRENCH , wxLayout_LeftToRight, "French") - LNG(wxLANGUAGE_FRENCH_BELGIAN, "fr_BE", LANG_FRENCH , SUBLANG_FRENCH_BELGIAN , wxLayout_LeftToRight, "French (Belgian)") - LNG(wxLANGUAGE_FRENCH_CANADIAN, "fr_CA", LANG_FRENCH , SUBLANG_FRENCH_CANADIAN , wxLayout_LeftToRight, "French (Canadian)") - LNG(wxLANGUAGE_FRENCH_LUXEMBOURG, "fr_LU", LANG_FRENCH , SUBLANG_FRENCH_LUXEMBOURG , wxLayout_LeftToRight, "French (Luxembourg)") - LNG(wxLANGUAGE_FRENCH_MONACO, "fr_MC", LANG_FRENCH , SUBLANG_FRENCH_MONACO , wxLayout_LeftToRight, "French (Monaco)") - LNG(wxLANGUAGE_FRENCH_SWISS, "fr_CH", LANG_FRENCH , SUBLANG_FRENCH_SWISS , wxLayout_LeftToRight, "French (Swiss)") - LNG(wxLANGUAGE_FRISIAN, "fy" , 0 , 0 , wxLayout_LeftToRight, "Frisian") - LNG(wxLANGUAGE_GALICIAN, "gl_ES", 0 , 0 , wxLayout_LeftToRight, "Galician") - LNG(wxLANGUAGE_GEORGIAN, "ka_GE", LANG_GEORGIAN , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Georgian") - LNG(wxLANGUAGE_GERMAN, "de_DE", LANG_GERMAN , SUBLANG_GERMAN , wxLayout_LeftToRight, "German") - LNG(wxLANGUAGE_GERMAN_AUSTRIAN, "de_AT", LANG_GERMAN , SUBLANG_GERMAN_AUSTRIAN , wxLayout_LeftToRight, "German (Austrian)") - LNG(wxLANGUAGE_GERMAN_BELGIUM, "de_BE", 0 , 0 , wxLayout_LeftToRight, "German (Belgium)") - LNG(wxLANGUAGE_GERMAN_LIECHTENSTEIN, "de_LI", LANG_GERMAN , SUBLANG_GERMAN_LIECHTENSTEIN , wxLayout_LeftToRight, "German (Liechtenstein)") - LNG(wxLANGUAGE_GERMAN_LUXEMBOURG, "de_LU", LANG_GERMAN , SUBLANG_GERMAN_LUXEMBOURG , wxLayout_LeftToRight, "German (Luxembourg)") - LNG(wxLANGUAGE_GERMAN_SWISS, "de_CH", LANG_GERMAN , SUBLANG_GERMAN_SWISS , wxLayout_LeftToRight, "German (Swiss)") - LNG(wxLANGUAGE_GREEK, "el_GR", LANG_GREEK , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Greek") - LNG(wxLANGUAGE_GREENLANDIC, "kl_GL", 0 , 0 , wxLayout_LeftToRight, "Greenlandic") - LNG(wxLANGUAGE_GUARANI, "gn" , 0 , 0 , wxLayout_LeftToRight, "Guarani") - LNG(wxLANGUAGE_GUJARATI, "gu" , LANG_GUJARATI , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Gujarati") - LNG(wxLANGUAGE_HAUSA, "ha" , 0 , 0 , wxLayout_LeftToRight, "Hausa") - LNG(wxLANGUAGE_HEBREW, "he_IL", LANG_HEBREW , SUBLANG_DEFAULT , wxLayout_RightToLeft, "Hebrew") - LNG(wxLANGUAGE_HINDI, "hi_IN", LANG_HINDI , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Hindi") - LNG(wxLANGUAGE_HUNGARIAN, "hu_HU", LANG_HUNGARIAN , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Hungarian") - LNG(wxLANGUAGE_ICELANDIC, "is_IS", LANG_ICELANDIC , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Icelandic") - LNG(wxLANGUAGE_INDONESIAN, "id_ID", LANG_INDONESIAN, SUBLANG_DEFAULT , wxLayout_LeftToRight, "Indonesian") - LNG(wxLANGUAGE_INTERLINGUA, "ia" , 0 , 0 , wxLayout_LeftToRight, "Interlingua") - LNG(wxLANGUAGE_INTERLINGUE, "ie" , 0 , 0 , wxLayout_LeftToRight, "Interlingue") - LNG(wxLANGUAGE_INUKTITUT, "iu" , 0 , 0 , wxLayout_LeftToRight, "Inuktitut") - LNG(wxLANGUAGE_INUPIAK, "ik" , 0 , 0 , wxLayout_LeftToRight, "Inupiak") - LNG(wxLANGUAGE_IRISH, "ga_IE", 0 , 0 , wxLayout_LeftToRight, "Irish") - LNG(wxLANGUAGE_ITALIAN, "it_IT", LANG_ITALIAN , SUBLANG_ITALIAN , wxLayout_LeftToRight, "Italian") - LNG(wxLANGUAGE_ITALIAN_SWISS, "it_CH", LANG_ITALIAN , SUBLANG_ITALIAN_SWISS , wxLayout_LeftToRight, "Italian (Swiss)") - LNG(wxLANGUAGE_JAPANESE, "ja_JP", LANG_JAPANESE , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Japanese") - LNG(wxLANGUAGE_JAVANESE, "jw" , 0 , 0 , wxLayout_LeftToRight, "Javanese") - LNG(wxLANGUAGE_KANNADA, "kn" , LANG_KANNADA , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Kannada") - LNG(wxLANGUAGE_KASHMIRI, "ks" , LANG_KASHMIRI , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Kashmiri") - LNG(wxLANGUAGE_KASHMIRI_INDIA, "ks_IN", LANG_KASHMIRI , SUBLANG_KASHMIRI_INDIA , wxLayout_LeftToRight, "Kashmiri (India)") - LNG(wxLANGUAGE_KAZAKH, "kk" , LANG_KAZAK , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Kazakh") - LNG(wxLANGUAGE_KERNEWEK, "kw_GB", 0 , 0 , wxLayout_LeftToRight, "Kernewek") - LNG(wxLANGUAGE_KINYARWANDA, "rw" , 0 , 0 , wxLayout_LeftToRight, "Kinyarwanda") - LNG(wxLANGUAGE_KIRGHIZ, "ky" , 0 , 0 , wxLayout_LeftToRight, "Kirghiz") - LNG(wxLANGUAGE_KIRUNDI, "rn" , 0 , 0 , wxLayout_LeftToRight, "Kirundi") - LNG(wxLANGUAGE_KONKANI, "" , LANG_KONKANI , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Konkani") - LNG(wxLANGUAGE_KOREAN, "ko_KR", LANG_KOREAN , SUBLANG_KOREAN , wxLayout_LeftToRight, "Korean") - LNG(wxLANGUAGE_KURDISH, "ku_TR", 0 , 0 , wxLayout_LeftToRight, "Kurdish") - LNG(wxLANGUAGE_LAOTHIAN, "lo" , 0 , 0 , wxLayout_LeftToRight, "Laothian") - LNG(wxLANGUAGE_LATIN, "la" , 0 , 0 , wxLayout_LeftToRight, "Latin") - LNG(wxLANGUAGE_LATVIAN, "lv_LV", LANG_LATVIAN , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Latvian") - LNG(wxLANGUAGE_LINGALA, "ln" , 0 , 0 , wxLayout_LeftToRight, "Lingala") - LNG(wxLANGUAGE_LITHUANIAN, "lt_LT", LANG_LITHUANIAN, SUBLANG_LITHUANIAN , wxLayout_LeftToRight, "Lithuanian") - LNG(wxLANGUAGE_MACEDONIAN, "mk_MK", LANG_MACEDONIAN, SUBLANG_DEFAULT , wxLayout_LeftToRight, "Macedonian") - LNG(wxLANGUAGE_MALAGASY, "mg" , 0 , 0 , wxLayout_LeftToRight, "Malagasy") - LNG(wxLANGUAGE_MALAY, "ms_MY", LANG_MALAY , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Malay") - LNG(wxLANGUAGE_MALAYALAM, "ml" , LANG_MALAYALAM , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Malayalam") - LNG(wxLANGUAGE_MALAY_BRUNEI_DARUSSALAM, "ms_BN", LANG_MALAY , SUBLANG_MALAY_BRUNEI_DARUSSALAM , wxLayout_LeftToRight, "Malay (Brunei Darussalam)") - LNG(wxLANGUAGE_MALAY_MALAYSIA, "ms_MY", LANG_MALAY , SUBLANG_MALAY_MALAYSIA , wxLayout_LeftToRight, "Malay (Malaysia)") - LNG(wxLANGUAGE_MALTESE, "mt_MT", 0 , 0 , wxLayout_LeftToRight, "Maltese") - LNG(wxLANGUAGE_MANIPURI, "" , LANG_MANIPURI , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Manipuri") - LNG(wxLANGUAGE_MAORI, "mi" , 0 , 0 , wxLayout_LeftToRight, "Maori") - LNG(wxLANGUAGE_MARATHI, "mr_IN", LANG_MARATHI , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Marathi") - LNG(wxLANGUAGE_MOLDAVIAN, "mo" , 0 , 0 , wxLayout_LeftToRight, "Moldavian") - LNG(wxLANGUAGE_MONGOLIAN, "mn" , 0 , 0 , wxLayout_LeftToRight, "Mongolian") - LNG(wxLANGUAGE_NAURU, "na" , 0 , 0 , wxLayout_LeftToRight, "Nauru") - LNG(wxLANGUAGE_NEPALI, "ne_NP", LANG_NEPALI , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Nepali") - LNG(wxLANGUAGE_NEPALI_INDIA, "ne_IN", LANG_NEPALI , SUBLANG_NEPALI_INDIA , wxLayout_LeftToRight, "Nepali (India)") - LNG(wxLANGUAGE_NORWEGIAN_BOKMAL, "nb_NO", LANG_NORWEGIAN , SUBLANG_NORWEGIAN_BOKMAL , wxLayout_LeftToRight, "Norwegian (Bokmal)") - LNG(wxLANGUAGE_NORWEGIAN_NYNORSK, "nn_NO", LANG_NORWEGIAN , SUBLANG_NORWEGIAN_NYNORSK , wxLayout_LeftToRight, "Norwegian (Nynorsk)") - LNG(wxLANGUAGE_OCCITAN, "oc" , 0 , 0 , wxLayout_LeftToRight, "Occitan") - LNG(wxLANGUAGE_ORIYA, "or" , LANG_ORIYA , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Oriya") - LNG(wxLANGUAGE_OROMO, "om" , 0 , 0 , wxLayout_LeftToRight, "(Afan) Oromo") - LNG(wxLANGUAGE_PASHTO, "ps" , 0 , 0 , wxLayout_LeftToRight, "Pashto, Pushto") - LNG(wxLANGUAGE_POLISH, "pl_PL", LANG_POLISH , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Polish") - LNG(wxLANGUAGE_PORTUGUESE, "pt_PT", LANG_PORTUGUESE, SUBLANG_PORTUGUESE , wxLayout_LeftToRight, "Portuguese") - LNG(wxLANGUAGE_PORTUGUESE_BRAZILIAN, "pt_BR", LANG_PORTUGUESE, SUBLANG_PORTUGUESE_BRAZILIAN , wxLayout_LeftToRight, "Portuguese (Brazilian)") - LNG(wxLANGUAGE_PUNJABI, "pa" , LANG_PUNJABI , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Punjabi") - LNG(wxLANGUAGE_QUECHUA, "qu" , 0 , 0 , wxLayout_LeftToRight, "Quechua") - LNG(wxLANGUAGE_RHAETO_ROMANCE, "rm" , 0 , 0 , wxLayout_LeftToRight, "Rhaeto-Romance") - LNG(wxLANGUAGE_ROMANIAN, "ro_RO", LANG_ROMANIAN , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Romanian") - LNG(wxLANGUAGE_RUSSIAN, "ru_RU", LANG_RUSSIAN , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Russian") - LNG(wxLANGUAGE_RUSSIAN_UKRAINE, "ru_UA", 0 , 0 , wxLayout_LeftToRight, "Russian (Ukraine)") - LNG(wxLANGUAGE_SAMOAN, "sm" , 0 , 0 , wxLayout_LeftToRight, "Samoan") - LNG(wxLANGUAGE_SANGHO, "sg" , 0 , 0 , wxLayout_LeftToRight, "Sangho") - LNG(wxLANGUAGE_SANSKRIT, "sa" , LANG_SANSKRIT , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Sanskrit") - LNG(wxLANGUAGE_SCOTS_GAELIC, "gd" , 0 , 0 , wxLayout_LeftToRight, "Scots Gaelic") - LNG(wxLANGUAGE_SAMI, "se_NO", LANG_SAMI , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Northern Sami") - LNG(wxLANGUAGE_SERBIAN, "sr_SR", LANG_SERBIAN , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Serbian") - LNG(wxLANGUAGE_SERBIAN_CYRILLIC, "sr_SR", LANG_SERBIAN , SUBLANG_SERBIAN_CYRILLIC , wxLayout_LeftToRight, "Serbian (Cyrillic)") - LNG(wxLANGUAGE_SERBIAN_LATIN, "sr_SR@latin", LANG_SERBIAN , SUBLANG_SERBIAN_LATIN , wxLayout_LeftToRight, "Serbian (Latin)") - LNG(wxLANGUAGE_SERBIAN_CYRILLIC, "sr_YU", LANG_SERBIAN , SUBLANG_SERBIAN_CYRILLIC , wxLayout_LeftToRight, "Serbian (Cyrillic)") - LNG(wxLANGUAGE_SERBIAN_LATIN, "sr_YU@latin", LANG_SERBIAN , SUBLANG_SERBIAN_LATIN , wxLayout_LeftToRight, "Serbian (Latin)") - LNG(wxLANGUAGE_SERBO_CROATIAN, "sh" , 0 , 0 , wxLayout_LeftToRight, "Serbo-Croatian") - LNG(wxLANGUAGE_SESOTHO, "st" , 0 , 0 , wxLayout_LeftToRight, "Sesotho") - LNG(wxLANGUAGE_SETSWANA, "tn" , 0 , 0 , wxLayout_LeftToRight, "Setswana") - LNG(wxLANGUAGE_SHONA, "sn" , 0 , 0 , wxLayout_LeftToRight, "Shona") - LNG(wxLANGUAGE_SINDHI, "sd" , LANG_SINDHI , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Sindhi") - LNG(wxLANGUAGE_SINHALESE, "si" , 0 , 0 , wxLayout_LeftToRight, "Sinhalese") - LNG(wxLANGUAGE_SISWATI, "ss" , 0 , 0 , wxLayout_LeftToRight, "Siswati") - LNG(wxLANGUAGE_SLOVAK, "sk_SK", LANG_SLOVAK , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Slovak") - LNG(wxLANGUAGE_SLOVENIAN, "sl_SI", LANG_SLOVENIAN , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Slovenian") - LNG(wxLANGUAGE_SOMALI, "so" , 0 , 0 , wxLayout_LeftToRight, "Somali") - LNG(wxLANGUAGE_SPANISH, "es_ES", LANG_SPANISH , SUBLANG_SPANISH , wxLayout_LeftToRight, "Spanish") - LNG(wxLANGUAGE_SPANISH_ARGENTINA, "es_AR", LANG_SPANISH , SUBLANG_SPANISH_ARGENTINA , wxLayout_LeftToRight, "Spanish (Argentina)") - LNG(wxLANGUAGE_SPANISH_BOLIVIA, "es_BO", LANG_SPANISH , SUBLANG_SPANISH_BOLIVIA , wxLayout_LeftToRight, "Spanish (Bolivia)") - LNG(wxLANGUAGE_SPANISH_CHILE, "es_CL", LANG_SPANISH , SUBLANG_SPANISH_CHILE , wxLayout_LeftToRight, "Spanish (Chile)") - LNG(wxLANGUAGE_SPANISH_COLOMBIA, "es_CO", LANG_SPANISH , SUBLANG_SPANISH_COLOMBIA , wxLayout_LeftToRight, "Spanish (Colombia)") - LNG(wxLANGUAGE_SPANISH_COSTA_RICA, "es_CR", LANG_SPANISH , SUBLANG_SPANISH_COSTA_RICA , wxLayout_LeftToRight, "Spanish (Costa Rica)") - LNG(wxLANGUAGE_SPANISH_DOMINICAN_REPUBLIC, "es_DO", LANG_SPANISH , SUBLANG_SPANISH_DOMINICAN_REPUBLIC, wxLayout_LeftToRight, "Spanish (Dominican republic)") - LNG(wxLANGUAGE_SPANISH_ECUADOR, "es_EC", LANG_SPANISH , SUBLANG_SPANISH_ECUADOR , wxLayout_LeftToRight, "Spanish (Ecuador)") - LNG(wxLANGUAGE_SPANISH_EL_SALVADOR, "es_SV", LANG_SPANISH , SUBLANG_SPANISH_EL_SALVADOR , wxLayout_LeftToRight, "Spanish (El Salvador)") - LNG(wxLANGUAGE_SPANISH_GUATEMALA, "es_GT", LANG_SPANISH , SUBLANG_SPANISH_GUATEMALA , wxLayout_LeftToRight, "Spanish (Guatemala)") - LNG(wxLANGUAGE_SPANISH_HONDURAS, "es_HN", LANG_SPANISH , SUBLANG_SPANISH_HONDURAS , wxLayout_LeftToRight, "Spanish (Honduras)") - LNG(wxLANGUAGE_SPANISH_MEXICAN, "es_MX", LANG_SPANISH , SUBLANG_SPANISH_MEXICAN , wxLayout_LeftToRight, "Spanish (Mexican)") - LNG(wxLANGUAGE_SPANISH_MODERN, "es_ES", LANG_SPANISH , SUBLANG_SPANISH_MODERN , wxLayout_LeftToRight, "Spanish (Modern)") - LNG(wxLANGUAGE_SPANISH_NICARAGUA, "es_NI", LANG_SPANISH , SUBLANG_SPANISH_NICARAGUA , wxLayout_LeftToRight, "Spanish (Nicaragua)") - LNG(wxLANGUAGE_SPANISH_PANAMA, "es_PA", LANG_SPANISH , SUBLANG_SPANISH_PANAMA , wxLayout_LeftToRight, "Spanish (Panama)") - LNG(wxLANGUAGE_SPANISH_PARAGUAY, "es_PY", LANG_SPANISH , SUBLANG_SPANISH_PARAGUAY , wxLayout_LeftToRight, "Spanish (Paraguay)") - LNG(wxLANGUAGE_SPANISH_PERU, "es_PE", LANG_SPANISH , SUBLANG_SPANISH_PERU , wxLayout_LeftToRight, "Spanish (Peru)") - LNG(wxLANGUAGE_SPANISH_PUERTO_RICO, "es_PR", LANG_SPANISH , SUBLANG_SPANISH_PUERTO_RICO , wxLayout_LeftToRight, "Spanish (Puerto Rico)") - LNG(wxLANGUAGE_SPANISH_URUGUAY, "es_UY", LANG_SPANISH , SUBLANG_SPANISH_URUGUAY , wxLayout_LeftToRight, "Spanish (Uruguay)") - LNG(wxLANGUAGE_SPANISH_US, "es_US", 0 , 0 , wxLayout_LeftToRight, "Spanish (U.S.)") - LNG(wxLANGUAGE_SPANISH_VENEZUELA, "es_VE", LANG_SPANISH , SUBLANG_SPANISH_VENEZUELA , wxLayout_LeftToRight, "Spanish (Venezuela)") - LNG(wxLANGUAGE_SUNDANESE, "su" , 0 , 0 , wxLayout_LeftToRight, "Sundanese") - LNG(wxLANGUAGE_SWAHILI, "sw_KE", LANG_SWAHILI , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Swahili") - LNG(wxLANGUAGE_SWEDISH, "sv_SE", LANG_SWEDISH , SUBLANG_SWEDISH , wxLayout_LeftToRight, "Swedish") - LNG(wxLANGUAGE_SWEDISH_FINLAND, "sv_FI", LANG_SWEDISH , SUBLANG_SWEDISH_FINLAND , wxLayout_LeftToRight, "Swedish (Finland)") - LNG(wxLANGUAGE_TAGALOG, "tl_PH", 0 , 0 , wxLayout_LeftToRight, "Tagalog") - LNG(wxLANGUAGE_TAJIK, "tg" , 0 , 0 , wxLayout_LeftToRight, "Tajik") - LNG(wxLANGUAGE_TAMIL, "ta" , LANG_TAMIL , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Tamil") - LNG(wxLANGUAGE_TATAR, "tt" , LANG_TATAR , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Tatar") - LNG(wxLANGUAGE_TELUGU, "te" , LANG_TELUGU , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Telugu") - LNG(wxLANGUAGE_THAI, "th_TH", LANG_THAI , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Thai") - LNG(wxLANGUAGE_TIBETAN, "bo" , 0 , 0 , wxLayout_LeftToRight, "Tibetan") - LNG(wxLANGUAGE_TIGRINYA, "ti" , 0 , 0 , wxLayout_LeftToRight, "Tigrinya") - LNG(wxLANGUAGE_TONGA, "to" , 0 , 0 , wxLayout_LeftToRight, "Tonga") - LNG(wxLANGUAGE_TSONGA, "ts" , 0 , 0 , wxLayout_LeftToRight, "Tsonga") - LNG(wxLANGUAGE_TURKISH, "tr_TR", LANG_TURKISH , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Turkish") - LNG(wxLANGUAGE_TURKMEN, "tk" , 0 , 0 , wxLayout_LeftToRight, "Turkmen") - LNG(wxLANGUAGE_TWI, "tw" , 0 , 0 , wxLayout_LeftToRight, "Twi") - LNG(wxLANGUAGE_UIGHUR, "ug" , 0 , 0 , wxLayout_LeftToRight, "Uighur") - LNG(wxLANGUAGE_UKRAINIAN, "uk_UA", LANG_UKRAINIAN , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Ukrainian") - LNG(wxLANGUAGE_URDU, "ur" , LANG_URDU , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Urdu") - LNG(wxLANGUAGE_URDU_INDIA, "ur_IN", LANG_URDU , SUBLANG_URDU_INDIA , wxLayout_LeftToRight, "Urdu (India)") - LNG(wxLANGUAGE_URDU_PAKISTAN, "ur_PK", LANG_URDU , SUBLANG_URDU_PAKISTAN , wxLayout_LeftToRight, "Urdu (Pakistan)") - LNG(wxLANGUAGE_UZBEK, "uz" , LANG_UZBEK , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Uzbek") - LNG(wxLANGUAGE_UZBEK_CYRILLIC, "uz" , LANG_UZBEK , SUBLANG_UZBEK_CYRILLIC , wxLayout_LeftToRight, "Uzbek (Cyrillic)") - LNG(wxLANGUAGE_UZBEK_LATIN, "uz" , LANG_UZBEK , SUBLANG_UZBEK_LATIN , wxLayout_LeftToRight, "Uzbek (Latin)") - LNG(wxLANGUAGE_VALENCIAN, "ca_ES@valencia", LANG_VALENCIAN , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Valencian") - LNG(wxLANGUAGE_VIETNAMESE, "vi_VN", LANG_VIETNAMESE, SUBLANG_DEFAULT , wxLayout_LeftToRight, "Vietnamese") - LNG(wxLANGUAGE_VOLAPUK, "vo" , 0 , 0 , wxLayout_LeftToRight, "Volapuk") - LNG(wxLANGUAGE_WELSH, "cy" , 0 , 0 , wxLayout_LeftToRight, "Welsh") - LNG(wxLANGUAGE_WOLOF, "wo" , 0 , 0 , wxLayout_LeftToRight, "Wolof") - LNG(wxLANGUAGE_XHOSA, "xh" , 0 , 0 , wxLayout_LeftToRight, "Xhosa") - LNG(wxLANGUAGE_YIDDISH, "yi" , 0 , 0 , wxLayout_LeftToRight, "Yiddish") - LNG(wxLANGUAGE_YORUBA, "yo" , 0 , 0 , wxLayout_LeftToRight, "Yoruba") - LNG(wxLANGUAGE_ZHUANG, "za" , 0 , 0 , wxLayout_LeftToRight, "Zhuang") - LNG(wxLANGUAGE_ZULU, "zu" , 0 , 0 , wxLayout_LeftToRight, "Zulu") -} -#undef LNG - -// --- --- --- generated code ends here --- --- --- - -#endif // wxUSE_INTL +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/intl.cpp +// Purpose: Internationalization and localisation for wxWidgets +// Author: Vadim Zeitlin +// Modified by: Michael N. Filippov +// (2003/09/30 - PluralForms support) +// Created: 29/01/98 +// RCS-ID: $Id: intl.cpp 53628 2008-05-17 22:49:30Z VZ $ +// Copyright: (c) 1998 Vadim Zeitlin +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declaration +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#ifdef __EMX__ +// The following define is needed by Innotek's libc to +// make the definition of struct localeconv available. +#define __INTERNAL_DEFS +#endif + +#if wxUSE_INTL + +#ifndef WX_PRECOMP + #include "wx/dynarray.h" + #include "wx/string.h" + #include "wx/intl.h" + #include "wx/log.h" + #include "wx/utils.h" + #include "wx/app.h" + #include "wx/hashmap.h" + #include "wx/module.h" +#endif // WX_PRECOMP + +#ifndef __WXWINCE__ + #include +#endif + +// standard headers +#include +#include +#ifdef HAVE_LANGINFO_H + #include +#endif + +#ifdef __WIN32__ + #include "wx/msw/private.h" +#elif defined(__UNIX_LIKE__) + #include "wx/fontmap.h" // for CharsetToEncoding() +#endif + +#include "wx/file.h" +#include "wx/filename.h" +#include "wx/tokenzr.h" +#include "wx/fontmap.h" +#include "wx/encconv.h" +#include "wx/ptr_scpd.h" +#include "wx/apptrait.h" +#include "wx/stdpaths.h" + +#if defined(__WXMAC__) + #include "wx/mac/private.h" // includes mac headers +#endif + +#if defined(__DARWIN__) + #include "wx/mac/corefoundation/cfref.h" + #include + #include "wx/mac/corefoundation/cfstring.h" +#endif + +// ---------------------------------------------------------------------------- +// simple types +// ---------------------------------------------------------------------------- + +// this should *not* be wxChar, this type must have exactly 8 bits! +typedef wxUint8 size_t8; +typedef wxUint32 size_t32; + +// ---------------------------------------------------------------------------- +// constants +// ---------------------------------------------------------------------------- + +// magic number identifying the .mo format file +const size_t32 MSGCATALOG_MAGIC = 0x950412de; +const size_t32 MSGCATALOG_MAGIC_SW = 0xde120495; + +// the constants describing the format of lang_LANG locale string +static const size_t LEN_LANG = 2; +static const size_t LEN_SUBLANG = 2; +static const size_t LEN_FULL = LEN_LANG + 1 + LEN_SUBLANG; // 1 for '_' + +#define TRACE_I18N _T("i18n") + +// ---------------------------------------------------------------------------- +// global functions +// ---------------------------------------------------------------------------- + +#ifdef __WXDEBUG__ + +// small class to suppress the translation erros until exit from current scope +class NoTransErr +{ +public: + NoTransErr() { ms_suppressCount++; } + ~NoTransErr() { ms_suppressCount--; } + + static bool Suppress() { return ms_suppressCount > 0; } + +private: + static size_t ms_suppressCount; +}; + +size_t NoTransErr::ms_suppressCount = 0; + +#else // !Debug + +class NoTransErr +{ +public: + NoTransErr() { } + ~NoTransErr() { } +}; + +#endif // Debug/!Debug + +static wxLocale *wxSetLocale(wxLocale *pLocale); + +// helper functions of GetSystemLanguage() +#ifdef __UNIX__ + +// get just the language part +static inline wxString ExtractLang(const wxString& langFull) +{ + return langFull.Left(LEN_LANG); +} + +// get everything else (including the leading '_') +static inline wxString ExtractNotLang(const wxString& langFull) +{ + return langFull.Mid(LEN_LANG); +} + +#endif // __UNIX__ + + +// ---------------------------------------------------------------------------- +// Plural forms parser +// ---------------------------------------------------------------------------- + +/* + Simplified Grammar + +Expression: + LogicalOrExpression '?' Expression ':' Expression + LogicalOrExpression + +LogicalOrExpression: + LogicalAndExpression "||" LogicalOrExpression // to (a || b) || c + LogicalAndExpression + +LogicalAndExpression: + EqualityExpression "&&" LogicalAndExpression // to (a && b) && c + EqualityExpression + +EqualityExpression: + RelationalExpression "==" RelationalExperession + RelationalExpression "!=" RelationalExperession + RelationalExpression + +RelationalExpression: + MultiplicativeExpression '>' MultiplicativeExpression + MultiplicativeExpression '<' MultiplicativeExpression + MultiplicativeExpression ">=" MultiplicativeExpression + MultiplicativeExpression "<=" MultiplicativeExpression + MultiplicativeExpression + +MultiplicativeExpression: + PmExpression '%' PmExpression + PmExpression + +PmExpression: + N + Number + '(' Expression ')' +*/ + +class wxPluralFormsToken +{ +public: + enum Type + { + T_ERROR, T_EOF, T_NUMBER, T_N, T_PLURAL, T_NPLURALS, T_EQUAL, T_ASSIGN, + T_GREATER, T_GREATER_OR_EQUAL, T_LESS, T_LESS_OR_EQUAL, + T_REMINDER, T_NOT_EQUAL, + T_LOGICAL_AND, T_LOGICAL_OR, T_QUESTION, T_COLON, T_SEMICOLON, + T_LEFT_BRACKET, T_RIGHT_BRACKET + }; + Type type() const { return m_type; } + void setType(Type type) { m_type = type; } + // for T_NUMBER only + typedef int Number; + Number number() const { return m_number; } + void setNumber(Number num) { m_number = num; } +private: + Type m_type; + Number m_number; +}; + + +class wxPluralFormsScanner +{ +public: + wxPluralFormsScanner(const char* s); + const wxPluralFormsToken& token() const { return m_token; } + bool nextToken(); // returns false if error +private: + const char* m_s; + wxPluralFormsToken m_token; +}; + +wxPluralFormsScanner::wxPluralFormsScanner(const char* s) : m_s(s) +{ + nextToken(); +} + +bool wxPluralFormsScanner::nextToken() +{ + wxPluralFormsToken::Type type = wxPluralFormsToken::T_ERROR; + while (isspace((unsigned char) *m_s)) + { + ++m_s; + } + if (*m_s == 0) + { + type = wxPluralFormsToken::T_EOF; + } + else if (isdigit((unsigned char) *m_s)) + { + wxPluralFormsToken::Number number = *m_s++ - '0'; + while (isdigit((unsigned char) *m_s)) + { + number = number * 10 + (*m_s++ - '0'); + } + m_token.setNumber(number); + type = wxPluralFormsToken::T_NUMBER; + } + else if (isalpha((unsigned char) *m_s)) + { + const char* begin = m_s++; + while (isalnum((unsigned char) *m_s)) + { + ++m_s; + } + size_t size = m_s - begin; + if (size == 1 && memcmp(begin, "n", size) == 0) + { + type = wxPluralFormsToken::T_N; + } + else if (size == 6 && memcmp(begin, "plural", size) == 0) + { + type = wxPluralFormsToken::T_PLURAL; + } + else if (size == 8 && memcmp(begin, "nplurals", size) == 0) + { + type = wxPluralFormsToken::T_NPLURALS; + } + } + else if (*m_s == '=') + { + ++m_s; + if (*m_s == '=') + { + ++m_s; + type = wxPluralFormsToken::T_EQUAL; + } + else + { + type = wxPluralFormsToken::T_ASSIGN; + } + } + else if (*m_s == '>') + { + ++m_s; + if (*m_s == '=') + { + ++m_s; + type = wxPluralFormsToken::T_GREATER_OR_EQUAL; + } + else + { + type = wxPluralFormsToken::T_GREATER; + } + } + else if (*m_s == '<') + { + ++m_s; + if (*m_s == '=') + { + ++m_s; + type = wxPluralFormsToken::T_LESS_OR_EQUAL; + } + else + { + type = wxPluralFormsToken::T_LESS; + } + } + else if (*m_s == '%') + { + ++m_s; + type = wxPluralFormsToken::T_REMINDER; + } + else if (*m_s == '!' && m_s[1] == '=') + { + m_s += 2; + type = wxPluralFormsToken::T_NOT_EQUAL; + } + else if (*m_s == '&' && m_s[1] == '&') + { + m_s += 2; + type = wxPluralFormsToken::T_LOGICAL_AND; + } + else if (*m_s == '|' && m_s[1] == '|') + { + m_s += 2; + type = wxPluralFormsToken::T_LOGICAL_OR; + } + else if (*m_s == '?') + { + ++m_s; + type = wxPluralFormsToken::T_QUESTION; + } + else if (*m_s == ':') + { + ++m_s; + type = wxPluralFormsToken::T_COLON; + } else if (*m_s == ';') { + ++m_s; + type = wxPluralFormsToken::T_SEMICOLON; + } + else if (*m_s == '(') + { + ++m_s; + type = wxPluralFormsToken::T_LEFT_BRACKET; + } + else if (*m_s == ')') + { + ++m_s; + type = wxPluralFormsToken::T_RIGHT_BRACKET; + } + m_token.setType(type); + return type != wxPluralFormsToken::T_ERROR; +} + +class wxPluralFormsNode; + +// NB: Can't use wxDEFINE_SCOPED_PTR_TYPE because wxPluralFormsNode is not +// fully defined yet: +class wxPluralFormsNodePtr +{ +public: + wxPluralFormsNodePtr(wxPluralFormsNode *p = NULL) : m_p(p) {} + ~wxPluralFormsNodePtr(); + wxPluralFormsNode& operator*() const { return *m_p; } + wxPluralFormsNode* operator->() const { return m_p; } + wxPluralFormsNode* get() const { return m_p; } + wxPluralFormsNode* release(); + void reset(wxPluralFormsNode *p); + +private: + wxPluralFormsNode *m_p; +}; + +class wxPluralFormsNode +{ +public: + wxPluralFormsNode(const wxPluralFormsToken& token) : m_token(token) {} + const wxPluralFormsToken& token() const { return m_token; } + const wxPluralFormsNode* node(size_t i) const + { return m_nodes[i].get(); } + void setNode(size_t i, wxPluralFormsNode* n); + wxPluralFormsNode* releaseNode(size_t i); + wxPluralFormsToken::Number evaluate(wxPluralFormsToken::Number n) const; + +private: + wxPluralFormsToken m_token; + wxPluralFormsNodePtr m_nodes[3]; +}; + +wxPluralFormsNodePtr::~wxPluralFormsNodePtr() +{ + delete m_p; +} +wxPluralFormsNode* wxPluralFormsNodePtr::release() +{ + wxPluralFormsNode *p = m_p; + m_p = NULL; + return p; +} +void wxPluralFormsNodePtr::reset(wxPluralFormsNode *p) +{ + if (p != m_p) + { + delete m_p; + m_p = p; + } +} + + +void wxPluralFormsNode::setNode(size_t i, wxPluralFormsNode* n) +{ + m_nodes[i].reset(n); +} + +wxPluralFormsNode* wxPluralFormsNode::releaseNode(size_t i) +{ + return m_nodes[i].release(); +} + +wxPluralFormsToken::Number +wxPluralFormsNode::evaluate(wxPluralFormsToken::Number n) const +{ + switch (token().type()) + { + // leaf + case wxPluralFormsToken::T_NUMBER: + return token().number(); + case wxPluralFormsToken::T_N: + return n; + // 2 args + case wxPluralFormsToken::T_EQUAL: + return node(0)->evaluate(n) == node(1)->evaluate(n); + case wxPluralFormsToken::T_NOT_EQUAL: + return node(0)->evaluate(n) != node(1)->evaluate(n); + case wxPluralFormsToken::T_GREATER: + return node(0)->evaluate(n) > node(1)->evaluate(n); + case wxPluralFormsToken::T_GREATER_OR_EQUAL: + return node(0)->evaluate(n) >= node(1)->evaluate(n); + case wxPluralFormsToken::T_LESS: + return node(0)->evaluate(n) < node(1)->evaluate(n); + case wxPluralFormsToken::T_LESS_OR_EQUAL: + return node(0)->evaluate(n) <= node(1)->evaluate(n); + case wxPluralFormsToken::T_REMINDER: + { + wxPluralFormsToken::Number number = node(1)->evaluate(n); + if (number != 0) + { + return node(0)->evaluate(n) % number; + } + else + { + return 0; + } + } + case wxPluralFormsToken::T_LOGICAL_AND: + return node(0)->evaluate(n) && node(1)->evaluate(n); + case wxPluralFormsToken::T_LOGICAL_OR: + return node(0)->evaluate(n) || node(1)->evaluate(n); + // 3 args + case wxPluralFormsToken::T_QUESTION: + return node(0)->evaluate(n) + ? node(1)->evaluate(n) + : node(2)->evaluate(n); + default: + return 0; + } +} + + +class wxPluralFormsCalculator +{ +public: + wxPluralFormsCalculator() : m_nplurals(0), m_plural(0) {} + + // input: number, returns msgstr index + int evaluate(int n) const; + + // input: text after "Plural-Forms:" (e.g. "nplurals=2; plural=(n != 1);"), + // if s == 0, creates default handler + // returns 0 if error + static wxPluralFormsCalculator* make(const char* s = 0); + + ~wxPluralFormsCalculator() {} + + void init(wxPluralFormsToken::Number nplurals, wxPluralFormsNode* plural); + +private: + wxPluralFormsToken::Number m_nplurals; + wxPluralFormsNodePtr m_plural; +}; + +wxDEFINE_SCOPED_PTR_TYPE(wxPluralFormsCalculator) + +void wxPluralFormsCalculator::init(wxPluralFormsToken::Number nplurals, + wxPluralFormsNode* plural) +{ + m_nplurals = nplurals; + m_plural.reset(plural); +} + +int wxPluralFormsCalculator::evaluate(int n) const +{ + if (m_plural.get() == 0) + { + return 0; + } + wxPluralFormsToken::Number number = m_plural->evaluate(n); + if (number < 0 || number > m_nplurals) + { + return 0; + } + return number; +} + + +class wxPluralFormsParser +{ +public: + wxPluralFormsParser(wxPluralFormsScanner& scanner) : m_scanner(scanner) {} + bool parse(wxPluralFormsCalculator& rCalculator); + +private: + wxPluralFormsNode* parsePlural(); + // stops at T_SEMICOLON, returns 0 if error + wxPluralFormsScanner& m_scanner; + const wxPluralFormsToken& token() const; + bool nextToken(); + + wxPluralFormsNode* expression(); + wxPluralFormsNode* logicalOrExpression(); + wxPluralFormsNode* logicalAndExpression(); + wxPluralFormsNode* equalityExpression(); + wxPluralFormsNode* multiplicativeExpression(); + wxPluralFormsNode* relationalExpression(); + wxPluralFormsNode* pmExpression(); +}; + +bool wxPluralFormsParser::parse(wxPluralFormsCalculator& rCalculator) +{ + if (token().type() != wxPluralFormsToken::T_NPLURALS) + return false; + if (!nextToken()) + return false; + if (token().type() != wxPluralFormsToken::T_ASSIGN) + return false; + if (!nextToken()) + return false; + if (token().type() != wxPluralFormsToken::T_NUMBER) + return false; + wxPluralFormsToken::Number nplurals = token().number(); + if (!nextToken()) + return false; + if (token().type() != wxPluralFormsToken::T_SEMICOLON) + return false; + if (!nextToken()) + return false; + if (token().type() != wxPluralFormsToken::T_PLURAL) + return false; + if (!nextToken()) + return false; + if (token().type() != wxPluralFormsToken::T_ASSIGN) + return false; + if (!nextToken()) + return false; + wxPluralFormsNode* plural = parsePlural(); + if (plural == 0) + return false; + if (token().type() != wxPluralFormsToken::T_SEMICOLON) + return false; + if (!nextToken()) + return false; + if (token().type() != wxPluralFormsToken::T_EOF) + return false; + rCalculator.init(nplurals, plural); + return true; +} + +wxPluralFormsNode* wxPluralFormsParser::parsePlural() +{ + wxPluralFormsNode* p = expression(); + if (p == NULL) + { + return NULL; + } + wxPluralFormsNodePtr n(p); + if (token().type() != wxPluralFormsToken::T_SEMICOLON) + { + return NULL; + } + return n.release(); +} + +const wxPluralFormsToken& wxPluralFormsParser::token() const +{ + return m_scanner.token(); +} + +bool wxPluralFormsParser::nextToken() +{ + if (!m_scanner.nextToken()) + return false; + return true; +} + +wxPluralFormsNode* wxPluralFormsParser::expression() +{ + wxPluralFormsNode* p = logicalOrExpression(); + if (p == NULL) + return NULL; + wxPluralFormsNodePtr n(p); + if (token().type() == wxPluralFormsToken::T_QUESTION) + { + wxPluralFormsNodePtr qn(new wxPluralFormsNode(token())); + if (!nextToken()) + { + return 0; + } + p = expression(); + if (p == 0) + { + return 0; + } + qn->setNode(1, p); + if (token().type() != wxPluralFormsToken::T_COLON) + { + return 0; + } + if (!nextToken()) + { + return 0; + } + p = expression(); + if (p == 0) + { + return 0; + } + qn->setNode(2, p); + qn->setNode(0, n.release()); + return qn.release(); + } + return n.release(); +} + +wxPluralFormsNode*wxPluralFormsParser::logicalOrExpression() +{ + wxPluralFormsNode* p = logicalAndExpression(); + if (p == NULL) + return NULL; + wxPluralFormsNodePtr ln(p); + if (token().type() == wxPluralFormsToken::T_LOGICAL_OR) + { + wxPluralFormsNodePtr un(new wxPluralFormsNode(token())); + if (!nextToken()) + { + return 0; + } + p = logicalOrExpression(); + if (p == 0) + { + return 0; + } + wxPluralFormsNodePtr rn(p); // right + if (rn->token().type() == wxPluralFormsToken::T_LOGICAL_OR) + { + // see logicalAndExpression comment + un->setNode(0, ln.release()); + un->setNode(1, rn->releaseNode(0)); + rn->setNode(0, un.release()); + return rn.release(); + } + + + un->setNode(0, ln.release()); + un->setNode(1, rn.release()); + return un.release(); + } + return ln.release(); +} + +wxPluralFormsNode* wxPluralFormsParser::logicalAndExpression() +{ + wxPluralFormsNode* p = equalityExpression(); + if (p == NULL) + return NULL; + wxPluralFormsNodePtr ln(p); // left + if (token().type() == wxPluralFormsToken::T_LOGICAL_AND) + { + wxPluralFormsNodePtr un(new wxPluralFormsNode(token())); // up + if (!nextToken()) + { + return NULL; + } + p = logicalAndExpression(); + if (p == 0) + { + return NULL; + } + wxPluralFormsNodePtr rn(p); // right + if (rn->token().type() == wxPluralFormsToken::T_LOGICAL_AND) + { +// transform 1 && (2 && 3) -> (1 && 2) && 3 +// u r +// l r -> u 3 +// 2 3 l 2 + un->setNode(0, ln.release()); + un->setNode(1, rn->releaseNode(0)); + rn->setNode(0, un.release()); + return rn.release(); + } + + un->setNode(0, ln.release()); + un->setNode(1, rn.release()); + return un.release(); + } + return ln.release(); +} + +wxPluralFormsNode* wxPluralFormsParser::equalityExpression() +{ + wxPluralFormsNode* p = relationalExpression(); + if (p == NULL) + return NULL; + wxPluralFormsNodePtr n(p); + if (token().type() == wxPluralFormsToken::T_EQUAL + || token().type() == wxPluralFormsToken::T_NOT_EQUAL) + { + wxPluralFormsNodePtr qn(new wxPluralFormsNode(token())); + if (!nextToken()) + { + return NULL; + } + p = relationalExpression(); + if (p == NULL) + { + return NULL; + } + qn->setNode(1, p); + qn->setNode(0, n.release()); + return qn.release(); + } + return n.release(); +} + +wxPluralFormsNode* wxPluralFormsParser::relationalExpression() +{ + wxPluralFormsNode* p = multiplicativeExpression(); + if (p == NULL) + return NULL; + wxPluralFormsNodePtr n(p); + if (token().type() == wxPluralFormsToken::T_GREATER + || token().type() == wxPluralFormsToken::T_LESS + || token().type() == wxPluralFormsToken::T_GREATER_OR_EQUAL + || token().type() == wxPluralFormsToken::T_LESS_OR_EQUAL) + { + wxPluralFormsNodePtr qn(new wxPluralFormsNode(token())); + if (!nextToken()) + { + return NULL; + } + p = multiplicativeExpression(); + if (p == NULL) + { + return NULL; + } + qn->setNode(1, p); + qn->setNode(0, n.release()); + return qn.release(); + } + return n.release(); +} + +wxPluralFormsNode* wxPluralFormsParser::multiplicativeExpression() +{ + wxPluralFormsNode* p = pmExpression(); + if (p == NULL) + return NULL; + wxPluralFormsNodePtr n(p); + if (token().type() == wxPluralFormsToken::T_REMINDER) + { + wxPluralFormsNodePtr qn(new wxPluralFormsNode(token())); + if (!nextToken()) + { + return NULL; + } + p = pmExpression(); + if (p == NULL) + { + return NULL; + } + qn->setNode(1, p); + qn->setNode(0, n.release()); + return qn.release(); + } + return n.release(); +} + +wxPluralFormsNode* wxPluralFormsParser::pmExpression() +{ + wxPluralFormsNodePtr n; + if (token().type() == wxPluralFormsToken::T_N + || token().type() == wxPluralFormsToken::T_NUMBER) + { + n.reset(new wxPluralFormsNode(token())); + if (!nextToken()) + { + return NULL; + } + } + else if (token().type() == wxPluralFormsToken::T_LEFT_BRACKET) { + if (!nextToken()) + { + return NULL; + } + wxPluralFormsNode* p = expression(); + if (p == NULL) + { + return NULL; + } + n.reset(p); + if (token().type() != wxPluralFormsToken::T_RIGHT_BRACKET) + { + return NULL; + } + if (!nextToken()) + { + return NULL; + } + } + else + { + return NULL; + } + return n.release(); +} + +wxPluralFormsCalculator* wxPluralFormsCalculator::make(const char* s) +{ + wxPluralFormsCalculatorPtr calculator(new wxPluralFormsCalculator); + if (s != NULL) + { + wxPluralFormsScanner scanner(s); + wxPluralFormsParser p(scanner); + if (!p.parse(*calculator)) + { + return NULL; + } + } + return calculator.release(); +} + + + + +// ---------------------------------------------------------------------------- +// wxMsgCatalogFile corresponds to one disk-file message catalog. +// +// This is a "low-level" class and is used only by wxMsgCatalog +// ---------------------------------------------------------------------------- + +WX_DECLARE_EXPORTED_STRING_HASH_MAP(wxString, wxMessagesHash); + +class wxMsgCatalogFile +{ +public: + // ctor & dtor + wxMsgCatalogFile(); + ~wxMsgCatalogFile(); + + // load the catalog from disk (szDirPrefix corresponds to language) + bool Load(const wxChar *szDirPrefix, const wxChar *szName, + wxPluralFormsCalculatorPtr& rPluralFormsCalculator); + + // fills the hash with string-translation pairs + void FillHash(wxMessagesHash& hash, + const wxString& msgIdCharset, + bool convertEncoding) const; + + // return the charset of the strings in this catalog or empty string if + // none/unknown + wxString GetCharset() const { return m_charset; } + +private: + // this implementation is binary compatible with GNU gettext() version 0.10 + + // an entry in the string table + struct wxMsgTableEntry + { + size_t32 nLen; // length of the string + size_t32 ofsString; // pointer to the string + }; + + // header of a .mo file + struct wxMsgCatalogHeader + { + size_t32 magic, // offset +00: magic id + revision, // +04: revision + numStrings; // +08: number of strings in the file + size_t32 ofsOrigTable, // +0C: start of original string table + ofsTransTable; // +10: start of translated string table + size_t32 nHashSize, // +14: hash table size + ofsHashTable; // +18: offset of hash table start + }; + + // all data is stored here, NULL if no data loaded + size_t8 *m_pData; + + // amount of memory pointed to by m_pData. + size_t32 m_nSize; + + // data description + size_t32 m_numStrings; // number of strings in this domain + wxMsgTableEntry *m_pOrigTable, // pointer to original strings + *m_pTransTable; // translated + + wxString m_charset; // from the message catalog header + + + // swap the 2 halves of 32 bit integer if needed + size_t32 Swap(size_t32 ui) const + { + return m_bSwapped ? (ui << 24) | ((ui & 0xff00) << 8) | + ((ui >> 8) & 0xff00) | (ui >> 24) + : ui; + } + + const char *StringAtOfs(wxMsgTableEntry *pTable, size_t32 n) const + { + const wxMsgTableEntry * const ent = pTable + n; + + // this check could fail for a corrupt message catalog + size_t32 ofsString = Swap(ent->ofsString); + if ( ofsString + Swap(ent->nLen) > m_nSize) + { + return NULL; + } + + return (const char *)(m_pData + ofsString); + } + + bool m_bSwapped; // wrong endianness? + + DECLARE_NO_COPY_CLASS(wxMsgCatalogFile) +}; + + +// ---------------------------------------------------------------------------- +// wxMsgCatalog corresponds to one loaded message catalog. +// +// This is a "low-level" class and is used only by wxLocale (that's why +// it's designed to be stored in a linked list) +// ---------------------------------------------------------------------------- + +class wxMsgCatalog +{ +public: +#if !wxUSE_UNICODE + wxMsgCatalog() { m_conv = NULL; } + ~wxMsgCatalog(); +#endif + + // load the catalog from disk (szDirPrefix corresponds to language) + bool Load(const wxChar *szDirPrefix, const wxChar *szName, + const wxChar *msgIdCharset = NULL, bool bConvertEncoding = false); + + // get name of the catalog + wxString GetName() const { return m_name; } + + // get the translated string: returns NULL if not found + const wxChar *GetString(const wxChar *sz, size_t n = size_t(-1)) const; + + // public variable pointing to the next element in a linked list (or NULL) + wxMsgCatalog *m_pNext; + +private: + wxMessagesHash m_messages; // all messages in the catalog + wxString m_name; // name of the domain + +#if !wxUSE_UNICODE + // the conversion corresponding to this catalog charset if we installed it + // as the global one + wxCSConv *m_conv; +#endif + + wxPluralFormsCalculatorPtr m_pluralFormsCalculator; +}; + +// ---------------------------------------------------------------------------- +// global variables +// ---------------------------------------------------------------------------- + +// the list of the directories to search for message catalog files +static wxArrayString gs_searchPrefixes; + +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// wxMsgCatalogFile class +// ---------------------------------------------------------------------------- + +wxMsgCatalogFile::wxMsgCatalogFile() +{ + m_pData = NULL; + m_nSize = 0; +} + +wxMsgCatalogFile::~wxMsgCatalogFile() +{ + delete [] m_pData; +} + +// return the directories to search for message catalogs under the given +// prefix, separated by wxPATH_SEP +static +wxString GetMsgCatalogSubdirs(const wxChar *prefix, const wxChar *lang) +{ + // Search first in Unix-standard prefix/lang/LC_MESSAGES, then in + // prefix/lang and finally in just prefix. + // + // Note that we use LC_MESSAGES on all platforms and not just Unix, because + // it doesn't cost much to look into one more directory and doing it this + // way has two important benefits: + // a) we don't break compatibility with wx-2.6 and older by stopping to + // look in a directory where the catalogs used to be and thus silently + // breaking apps after they are recompiled against the latest wx + // b) it makes it possible to package app's support files in the same + // way on all target platforms + wxString pathPrefix; + pathPrefix << prefix << wxFILE_SEP_PATH << lang; + + wxString searchPath; + searchPath.reserve(4*pathPrefix.length()); + searchPath << pathPrefix << wxFILE_SEP_PATH << wxT("LC_MESSAGES") << wxPATH_SEP + << prefix << wxFILE_SEP_PATH << wxPATH_SEP + << pathPrefix; + + return searchPath; +} + +// construct the search path for the given language +static wxString GetFullSearchPath(const wxChar *lang) +{ + // first take the entries explicitly added by the program + wxArrayString paths; + paths.reserve(gs_searchPrefixes.size() + 1); + size_t n, + count = gs_searchPrefixes.size(); + for ( n = 0; n < count; n++ ) + { + paths.Add(GetMsgCatalogSubdirs(gs_searchPrefixes[n], lang)); + } + + +#if wxUSE_STDPATHS + // then look in the standard location + const wxString stdp = wxStandardPaths::Get(). + GetLocalizedResourcesDir(lang, wxStandardPaths::ResourceCat_Messages); + + if ( paths.Index(stdp) == wxNOT_FOUND ) + paths.Add(stdp); +#endif // wxUSE_STDPATHS + + // last look in default locations +#ifdef __UNIX__ + // LC_PATH is a standard env var containing the search path for the .mo + // files + const wxChar *pszLcPath = wxGetenv(wxT("LC_PATH")); + if ( pszLcPath ) + { + const wxString lcp = GetMsgCatalogSubdirs(pszLcPath, lang); + if ( paths.Index(lcp) == wxNOT_FOUND ) + paths.Add(lcp); + } + + // also add the one from where wxWin was installed: + wxString wxp = wxGetInstallPrefix(); + if ( !wxp.empty() ) + { + wxp = GetMsgCatalogSubdirs(wxp + _T("/share/locale"), lang); + if ( paths.Index(wxp) == wxNOT_FOUND ) + paths.Add(wxp); + } +#endif // __UNIX__ + + + // finally construct the full search path + wxString searchPath; + searchPath.reserve(500); + count = paths.size(); + for ( n = 0; n < count; n++ ) + { + searchPath += paths[n]; + if ( n != count - 1 ) + searchPath += wxPATH_SEP; + } + + return searchPath; +} + +// open disk file and read in it's contents +bool wxMsgCatalogFile::Load(const wxChar *szDirPrefix, const wxChar *szName, + wxPluralFormsCalculatorPtr& rPluralFormsCalculator) +{ + wxString searchPath; + +#if wxUSE_FONTMAP + // first look for the catalog for this language and the current locale: + // notice that we don't use the system name for the locale as this would + // force us to install catalogs in different locations depending on the + // system but always use the canonical name + wxFontEncoding encSys = wxLocale::GetSystemEncoding(); + if ( encSys != wxFONTENCODING_SYSTEM ) + { + wxString fullname(szDirPrefix); + fullname << _T('.') << wxFontMapperBase::GetEncodingName(encSys); + searchPath << GetFullSearchPath(fullname) << wxPATH_SEP; + } +#endif // wxUSE_FONTMAP + + + searchPath += GetFullSearchPath(szDirPrefix); + const wxChar *sublocale = wxStrchr(szDirPrefix, wxT('_')); + if ( sublocale ) + { + // also add just base locale name: for things like "fr_BE" (belgium + // french) we should use "fr" if no belgium specific message catalogs + // exist + searchPath << wxPATH_SEP + << GetFullSearchPath(wxString(szDirPrefix). + Left((size_t)(sublocale - szDirPrefix))); + } + + // don't give translation errors here because the wxstd catalog might + // not yet be loaded (and it's normal) + // + // (we're using an object because we have several return paths) + + NoTransErr noTransErr; + wxLogVerbose(_("looking for catalog '%s' in path '%s'."), + szName, searchPath.c_str()); + wxLogTrace(TRACE_I18N, _T("Looking for \"%s.mo\" in \"%s\""), + szName, searchPath.c_str()); + + wxFileName fn(szName); + fn.SetExt(_T("mo")); + wxString strFullName; + if ( !wxFindFileInPath(&strFullName, searchPath, fn.GetFullPath()) ) { + wxLogVerbose(_("catalog file for domain '%s' not found."), szName); + wxLogTrace(TRACE_I18N, _T("Catalog \"%s.mo\" not found"), szName); + return false; + } + + // open file + wxLogVerbose(_("using catalog '%s' from '%s'."), szName, strFullName.c_str()); + wxLogTrace(TRACE_I18N, _T("Using catalog \"%s\"."), strFullName.c_str()); + + wxFile fileMsg(strFullName); + if ( !fileMsg.IsOpened() ) + return false; + + // get the file size (assume it is less than 4Gb...) + wxFileOffset lenFile = fileMsg.Length(); + if ( lenFile == wxInvalidOffset ) + return false; + + size_t nSize = wx_truncate_cast(size_t, lenFile); + wxASSERT_MSG( nSize == lenFile + size_t(0), _T("message catalog bigger than 4GB?") ); + + // read the whole file in memory + m_pData = new size_t8[nSize]; + if ( fileMsg.Read(m_pData, nSize) != lenFile ) { + wxDELETEA(m_pData); + return false; + } + + // examine header + bool bValid = nSize + (size_t)0 > sizeof(wxMsgCatalogHeader); + + wxMsgCatalogHeader *pHeader = (wxMsgCatalogHeader *)m_pData; + if ( bValid ) { + // we'll have to swap all the integers if it's true + m_bSwapped = pHeader->magic == MSGCATALOG_MAGIC_SW; + + // check the magic number + bValid = m_bSwapped || pHeader->magic == MSGCATALOG_MAGIC; + } + + if ( !bValid ) { + // it's either too short or has incorrect magic number + wxLogWarning(_("'%s' is not a valid message catalog."), strFullName.c_str()); + + wxDELETEA(m_pData); + return false; + } + + // initialize + m_numStrings = Swap(pHeader->numStrings); + m_pOrigTable = (wxMsgTableEntry *)(m_pData + + Swap(pHeader->ofsOrigTable)); + m_pTransTable = (wxMsgTableEntry *)(m_pData + + Swap(pHeader->ofsTransTable)); + m_nSize = (size_t32)nSize; + + // now parse catalog's header and try to extract catalog charset and + // plural forms formula from it: + + const char* headerData = StringAtOfs(m_pOrigTable, 0); + if (headerData && headerData[0] == 0) + { + // Extract the charset: + wxString header = wxString::FromAscii(StringAtOfs(m_pTransTable, 0)); + int begin = header.Find(wxT("Content-Type: text/plain; charset=")); + if (begin != wxNOT_FOUND) + { + begin += 34; //strlen("Content-Type: text/plain; charset=") + size_t end = header.find('\n', begin); + if (end != size_t(-1)) + { + m_charset.assign(header, begin, end - begin); + if (m_charset == wxT("CHARSET")) + { + // "CHARSET" is not valid charset, but lazy translator + m_charset.Clear(); + } + } + } + // else: incorrectly filled Content-Type header + + // Extract plural forms: + begin = header.Find(wxT("Plural-Forms:")); + if (begin != wxNOT_FOUND) + { + begin += 13; + size_t end = header.find('\n', begin); + if (end != size_t(-1)) + { + wxString pfs(header, begin, end - begin); + wxPluralFormsCalculator* pCalculator = wxPluralFormsCalculator + ::make(pfs.ToAscii()); + if (pCalculator != 0) + { + rPluralFormsCalculator.reset(pCalculator); + } + else + { + wxLogVerbose(_("Cannot parse Plural-Forms:'%s'"), pfs.c_str()); + } + } + } + if (rPluralFormsCalculator.get() == NULL) + { + rPluralFormsCalculator.reset(wxPluralFormsCalculator::make()); + } + } + + // everything is fine + return true; +} + +void wxMsgCatalogFile::FillHash(wxMessagesHash& hash, + const wxString& msgIdCharset, + bool convertEncoding) const +{ +#if wxUSE_UNICODE + // this parameter doesn't make sense, we always must convert encoding in + // Unicode build + convertEncoding = true; +#elif wxUSE_FONTMAP + if ( convertEncoding ) + { + // determine if we need any conversion at all + wxFontEncoding encCat = wxFontMapperBase::GetEncodingFromName(m_charset); + if ( encCat == wxLocale::GetSystemEncoding() ) + { + // no need to convert + convertEncoding = false; + } + } +#endif // wxUSE_UNICODE/wxUSE_FONTMAP + +#if wxUSE_WCHAR_T + // conversion to use to convert catalog strings to the GUI encoding + wxMBConv *inputConv, + *inputConvPtr = NULL; // same as inputConv but safely deleteable + if ( convertEncoding && !m_charset.empty() ) + { + inputConvPtr = + inputConv = new wxCSConv(m_charset); + } + else // no need or not possible to convert the encoding + { +#if wxUSE_UNICODE + // we must somehow convert the narrow strings in the message catalog to + // wide strings, so use the default conversion if we have no charset + inputConv = wxConvCurrent; +#else // !wxUSE_UNICODE + inputConv = NULL; +#endif // wxUSE_UNICODE/!wxUSE_UNICODE + } + + // conversion to apply to msgid strings before looking them up: we only + // need it if the msgids are neither in 7 bit ASCII nor in the same + // encoding as the catalog + wxCSConv *sourceConv = msgIdCharset.empty() || (msgIdCharset == m_charset) + ? NULL + : new wxCSConv(msgIdCharset); + +#elif wxUSE_FONTMAP + wxASSERT_MSG( msgIdCharset.empty(), + _T("non-ASCII msgid languages only supported if wxUSE_WCHAR_T=1") ); + + wxEncodingConverter converter; + if ( convertEncoding ) + { + wxFontEncoding targetEnc = wxFONTENCODING_SYSTEM; + wxFontEncoding enc = wxFontMapperBase::Get()->CharsetToEncoding(m_charset, false); + if ( enc == wxFONTENCODING_SYSTEM ) + { + convertEncoding = false; // unknown encoding + } + else + { + targetEnc = wxLocale::GetSystemEncoding(); + if (targetEnc == wxFONTENCODING_SYSTEM) + { + wxFontEncodingArray a = wxEncodingConverter::GetPlatformEquivalents(enc); + if (a[0] == enc) + // no conversion needed, locale uses native encoding + convertEncoding = false; + if (a.GetCount() == 0) + // we don't know common equiv. under this platform + convertEncoding = false; + targetEnc = a[0]; + } + } + + if ( convertEncoding ) + { + converter.Init(enc, targetEnc); + } + } +#endif // wxUSE_WCHAR_T/!wxUSE_WCHAR_T + (void)convertEncoding; // get rid of warnings about unused parameter + + for (size_t32 i = 0; i < m_numStrings; i++) + { + const char *data = StringAtOfs(m_pOrigTable, i); + + wxString msgid; +#if wxUSE_UNICODE + msgid = wxString(data, *inputConv); +#else // ASCII + #if wxUSE_WCHAR_T + if ( inputConv && sourceConv ) + msgid = wxString(inputConv->cMB2WC(data), *sourceConv); + else + #endif + msgid = data; +#endif // wxUSE_UNICODE + + data = StringAtOfs(m_pTransTable, i); + size_t length = Swap(m_pTransTable[i].nLen); + size_t offset = 0; + size_t index = 0; + while (offset < length) + { + const char * const str = data + offset; + + wxString msgstr; +#if wxUSE_UNICODE + msgstr = wxString(str, *inputConv); +#elif wxUSE_WCHAR_T + if ( inputConv ) + msgstr = wxString(inputConv->cMB2WC(str), *wxConvUI); + else + msgstr = str; +#else // !wxUSE_WCHAR_T + #if wxUSE_FONTMAP + if ( convertEncoding ) + msgstr = wxString(converter.Convert(str)); + else + #endif + msgstr = str; +#endif // wxUSE_WCHAR_T/!wxUSE_WCHAR_T + + if ( !msgstr.empty() ) + { + hash[index == 0 ? msgid : msgid + wxChar(index)] = msgstr; + } + + // skip this string + offset += strlen(str) + 1; + ++index; + } + } + +#if wxUSE_WCHAR_T + delete sourceConv; + delete inputConvPtr; +#endif // wxUSE_WCHAR_T +} + + +// ---------------------------------------------------------------------------- +// wxMsgCatalog class +// ---------------------------------------------------------------------------- + +#if !wxUSE_UNICODE +wxMsgCatalog::~wxMsgCatalog() +{ + if ( m_conv ) + { + if ( wxConvUI == m_conv ) + { + // we only change wxConvUI if it points to wxConvLocal so we reset + // it back to it too + wxConvUI = &wxConvLocal; + } + + delete m_conv; + } +} +#endif // !wxUSE_UNICODE + +bool wxMsgCatalog::Load(const wxChar *szDirPrefix, const wxChar *szName, + const wxChar *msgIdCharset, bool bConvertEncoding) +{ + wxMsgCatalogFile file; + + m_name = szName; + + if ( !file.Load(szDirPrefix, szName, m_pluralFormsCalculator) ) + return false; + + file.FillHash(m_messages, msgIdCharset, bConvertEncoding); + +#if !wxUSE_UNICODE && wxUSE_WCHAR_T + // we should use a conversion compatible with the message catalog encoding + // in the GUI if we don't convert the strings to the current conversion but + // as the encoding is global, only change it once, otherwise we could get + // into trouble if we use several message catalogs with different encodings + // + // this is, of course, a hack but it at least allows the program to use + // message catalogs in any encodings without asking the user to change his + // locale + if ( !bConvertEncoding && + !file.GetCharset().empty() && + wxConvUI == &wxConvLocal ) + { + wxConvUI = + m_conv = new wxCSConv(file.GetCharset()); + } +#endif // !wxUSE_UNICODE && wxUSE_WCHAR_T + + return true; +} + +const wxChar *wxMsgCatalog::GetString(const wxChar *sz, size_t n) const +{ + int index = 0; + if (n != size_t(-1)) + { + index = m_pluralFormsCalculator->evaluate(n); + } + wxMessagesHash::const_iterator i; + if (index != 0) + { + i = m_messages.find(wxString(sz) + wxChar(index)); // plural + } + else + { + i = m_messages.find(sz); + } + + if ( i != m_messages.end() ) + { + return i->second.c_str(); + } + else + return NULL; +} + +// ---------------------------------------------------------------------------- +// wxLocale +// ---------------------------------------------------------------------------- + +#include "wx/arrimpl.cpp" +WX_DECLARE_EXPORTED_OBJARRAY(wxLanguageInfo, wxLanguageInfoArray); +WX_DEFINE_OBJARRAY(wxLanguageInfoArray) + +wxLanguageInfoArray *wxLocale::ms_languagesDB = NULL; + +/*static*/ void wxLocale::CreateLanguagesDB() +{ + if (ms_languagesDB == NULL) + { + ms_languagesDB = new wxLanguageInfoArray; + InitLanguagesDB(); + } +} + +/*static*/ void wxLocale::DestroyLanguagesDB() +{ + delete ms_languagesDB; + ms_languagesDB = NULL; +} + + +void wxLocale::DoCommonInit() +{ + m_pszOldLocale = NULL; + + m_pOldLocale = wxSetLocale(this); + + m_pMsgCat = NULL; + m_language = wxLANGUAGE_UNKNOWN; + m_initialized = false; +} + +// NB: this function has (desired) side effect of changing current locale +bool wxLocale::Init(const wxChar *szName, + const wxChar *szShort, + const wxChar *szLocale, + bool bLoadDefault, + bool bConvertEncoding) +{ + wxASSERT_MSG( !m_initialized, + _T("you can't call wxLocale::Init more than once") ); + + m_initialized = true; + m_strLocale = szName; + m_strShort = szShort; + m_bConvertEncoding = bConvertEncoding; + m_language = wxLANGUAGE_UNKNOWN; + + // change current locale (default: same as long name) + if ( szLocale == NULL ) + { + // the argument to setlocale() + szLocale = szShort; + + wxCHECK_MSG( szLocale, false, _T("no locale to set in wxLocale::Init()") ); + } + +#ifdef __WXWINCE__ + // FIXME: I'm guessing here + wxChar localeName[256]; + int ret = GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SLANGUAGE, localeName, + 256); + if (ret != 0) + { + m_pszOldLocale = wxStrdup(localeName); + } + else + m_pszOldLocale = NULL; + + // TODO: how to find languageId + // SetLocaleInfo(languageId, SORT_DEFAULT, localeName); +#else + wxMB2WXbuf oldLocale = wxSetlocale(LC_ALL, szLocale); + if ( oldLocale ) + m_pszOldLocale = wxStrdup(oldLocale); + else + m_pszOldLocale = NULL; +#endif + + if ( m_pszOldLocale == NULL ) + wxLogError(_("locale '%s' can not be set."), szLocale); + + // the short name will be used to look for catalog files as well, + // so we need something here + if ( m_strShort.empty() ) { + // FIXME I don't know how these 2 letter abbreviations are formed, + // this wild guess is surely wrong + if ( szLocale && szLocale[0] ) + { + m_strShort += (wxChar)wxTolower(szLocale[0]); + if ( szLocale[1] ) + m_strShort += (wxChar)wxTolower(szLocale[1]); + } + } + + // load the default catalog with wxWidgets standard messages + m_pMsgCat = NULL; + bool bOk = true; + if ( bLoadDefault ) + { + bOk = AddCatalog(wxT("wxstd")); + + // there may be a catalog with toolkit specific overrides, it is not + // an error if this does not exist + if ( bOk ) + { + wxString port(wxPlatformInfo::Get().GetPortIdName()); + if ( !port.empty() ) + { + AddCatalog(port.BeforeFirst(wxT('/')).MakeLower()); + } + } + } + + return bOk; +} + + +#if defined(__UNIX__) && wxUSE_UNICODE && !defined(__WXMAC__) +static wxWCharBuffer wxSetlocaleTryUTF(int c, const wxChar *lc) +{ + wxMB2WXbuf l = wxSetlocale(c, lc); + if ( !l && lc && lc[0] != 0 ) + { + wxString buf(lc); + wxString buf2; + buf2 = buf + wxT(".UTF-8"); + l = wxSetlocale(c, buf2.c_str()); + if ( !l ) + { + buf2 = buf + wxT(".utf-8"); + l = wxSetlocale(c, buf2.c_str()); + } + if ( !l ) + { + buf2 = buf + wxT(".UTF8"); + l = wxSetlocale(c, buf2.c_str()); + } + if ( !l ) + { + buf2 = buf + wxT(".utf8"); + l = wxSetlocale(c, buf2.c_str()); + } + } + return l; +} +#else +#define wxSetlocaleTryUTF(c, lc) wxSetlocale(c, lc) +#endif + +bool wxLocale::Init(int language, int flags) +{ + int lang = language; + if (lang == wxLANGUAGE_DEFAULT) + { + // auto detect the language + lang = GetSystemLanguage(); + } + + // We failed to detect system language, so we will use English: + if (lang == wxLANGUAGE_UNKNOWN) + { + return false; + } + + const wxLanguageInfo *info = GetLanguageInfo(lang); + + // Unknown language: + if (info == NULL) + { + wxLogError(wxT("Unknown language %i."), lang); + return false; + } + + wxString name = info->Description; + wxString canonical = info->CanonicalName; + wxString locale; + + // Set the locale: +#if defined(__OS2__) + wxMB2WXbuf retloc = wxSetlocale(LC_ALL , wxEmptyString); +#elif defined(__UNIX__) && !defined(__WXMAC__) + if (language != wxLANGUAGE_DEFAULT) + locale = info->CanonicalName; + + wxMB2WXbuf retloc = wxSetlocaleTryUTF(LC_ALL, locale); + + const wxString langOnly = locale.Left(2); + if ( !retloc ) + { + // Some C libraries don't like xx_YY form and require xx only + retloc = wxSetlocaleTryUTF(LC_ALL, langOnly); + } + +#if wxUSE_FONTMAP + // some systems (e.g. FreeBSD and HP-UX) don't have xx_YY aliases but + // require the full xx_YY.encoding form, so try using UTF-8 because this is + // the only thing we can do generically + // + // TODO: add encodings applicable to each language to the lang DB and try + // them all in turn here + if ( !retloc ) + { + const wxChar **names = + wxFontMapperBase::GetAllEncodingNames(wxFONTENCODING_UTF8); + while ( *names ) + { + retloc = wxSetlocale(LC_ALL, locale + _T('.') + *names++); + if ( retloc ) + break; + } + } +#endif // wxUSE_FONTMAP + + if ( !retloc ) + { + // Some C libraries (namely glibc) still use old ISO 639, + // so will translate the abbrev for them + wxString localeAlt; + if ( langOnly == wxT("he") ) + localeAlt = wxT("iw") + locale.Mid(3); + else if ( langOnly == wxT("id") ) + localeAlt = wxT("in") + locale.Mid(3); + else if ( langOnly == wxT("yi") ) + localeAlt = wxT("ji") + locale.Mid(3); + else if ( langOnly == wxT("nb") ) + localeAlt = wxT("no_NO"); + else if ( langOnly == wxT("nn") ) + localeAlt = wxT("no_NY"); + + if ( !localeAlt.empty() ) + { + retloc = wxSetlocaleTryUTF(LC_ALL, localeAlt); + if ( !retloc ) + retloc = wxSetlocaleTryUTF(LC_ALL, localeAlt.Left(2)); + } + } + + if ( !retloc ) + { + wxLogError(wxT("Cannot set locale to '%s'."), locale.c_str()); + return false; + } + +#ifdef __AIX__ + // at least in AIX 5.2 libc is buggy and the string returned from setlocale(LC_ALL) + // can't be passed back to it because it returns 6 strings (one for each locale + // category), i.e. for C locale we get back "C C C C C C" + // + // this contradicts IBM own docs but this is not of much help, so just work around + // it in the crudest possible manner + wxChar *p = wxStrchr((wxChar *)retloc, _T(' ')); + if ( p ) + *p = _T('\0'); +#endif // __AIX__ + +#elif defined(__WIN32__) + + #if wxUSE_UNICODE && (defined(__VISUALC__) || defined(__MINGW32__)) + // NB: setlocale() from msvcrt.dll (used by VC++ and Mingw) + // can't set locale to language that can only be written using + // Unicode. Therefore wxSetlocale call failed, but we don't want + // to report it as an error -- so that at least message catalogs + // can be used. Watch for code marked with + // #ifdef SETLOCALE_FAILS_ON_UNICODE_LANGS bellow. + #define SETLOCALE_FAILS_ON_UNICODE_LANGS + #endif + +#if !wxUSE_UNICODE + const +#endif + wxMB2WXbuf retloc = wxT("C"); + if (language != wxLANGUAGE_DEFAULT) + { + if (info->WinLang == 0) + { + wxLogWarning(wxT("Locale '%s' not supported by OS."), name.c_str()); + // retloc already set to "C" + } + else + { + int codepage + #ifdef SETLOCALE_FAILS_ON_UNICODE_LANGS + = -1 + #endif + ; + wxUint32 lcid = MAKELCID(MAKELANGID(info->WinLang, info->WinSublang), + SORT_DEFAULT); + // FIXME +#ifndef __WXWINCE__ + SetThreadLocale(lcid); +#endif + // NB: we must translate LCID to CRT's setlocale string ourselves, + // because SetThreadLocale does not modify change the + // interpretation of setlocale(LC_ALL, "") call: + wxChar buffer[256]; + buffer[0] = wxT('\0'); + GetLocaleInfo(lcid, LOCALE_SENGLANGUAGE, buffer, 256); + locale << buffer; + if (GetLocaleInfo(lcid, LOCALE_SENGCOUNTRY, buffer, 256) > 0) + locale << wxT("_") << buffer; + if (GetLocaleInfo(lcid, LOCALE_IDEFAULTANSICODEPAGE, buffer, 256) > 0) + { + codepage = wxAtoi(buffer); + if (codepage != 0) + locale << wxT(".") << buffer; + } + if (locale.empty()) + { + wxLogLastError(wxT("SetThreadLocale")); + wxLogError(wxT("Cannot set locale to language %s."), name.c_str()); + return false; + } + else + { + // FIXME +#ifndef __WXWINCE__ + retloc = wxSetlocale(LC_ALL, locale); +#endif +#ifdef SETLOCALE_FAILS_ON_UNICODE_LANGS + if (codepage == 0 && (const wxChar*)retloc == NULL) + { + retloc = wxT("C"); + } +#endif + } + } + } + else + { + // FIXME +#ifndef __WXWINCE__ + retloc = wxSetlocale(LC_ALL, wxEmptyString); +#else + retloc = NULL; +#endif +#ifdef SETLOCALE_FAILS_ON_UNICODE_LANGS + if ((const wxChar*)retloc == NULL) + { + wxChar buffer[16]; + if (GetLocaleInfo(LOCALE_USER_DEFAULT, + LOCALE_IDEFAULTANSICODEPAGE, buffer, 16) > 0 && + wxStrcmp(buffer, wxT("0")) == 0) + { + retloc = wxT("C"); + } + } +#endif + } + + if ( !retloc ) + { + wxLogError(wxT("Cannot set locale to language %s."), name.c_str()); + return false; + } +#elif defined(__WXMAC__) + if (lang == wxLANGUAGE_DEFAULT) + locale = wxEmptyString; + else + locale = info->CanonicalName; + + wxMB2WXbuf retloc = wxSetlocale(LC_ALL, locale); + + if ( !retloc ) + { + // Some C libraries don't like xx_YY form and require xx only + retloc = wxSetlocale(LC_ALL, locale.Mid(0,2)); + } + if ( !retloc ) + { + wxLogError(wxT("Cannot set locale to '%s'."), locale.c_str()); + return false; + } +#else + wxUnusedVar(flags); + return false; + #define WX_NO_LOCALE_SUPPORT +#endif + +#ifndef WX_NO_LOCALE_SUPPORT + wxChar *szLocale = retloc ? wxStrdup(retloc) : NULL; + bool ret = Init(name, canonical, szLocale, + (flags & wxLOCALE_LOAD_DEFAULT) != 0, + (flags & wxLOCALE_CONV_ENCODING) != 0); + free(szLocale); + + if (IsOk()) // setlocale() succeeded + m_language = lang; + + return ret; +#endif // !WX_NO_LOCALE_SUPPORT +} + + + +void wxLocale::AddCatalogLookupPathPrefix(const wxString& prefix) +{ + if ( gs_searchPrefixes.Index(prefix) == wxNOT_FOUND ) + { + gs_searchPrefixes.Add(prefix); + } + //else: already have it +} + +/*static*/ int wxLocale::GetSystemLanguage() +{ + CreateLanguagesDB(); + + // init i to avoid compiler warning + size_t i = 0, + count = ms_languagesDB->GetCount(); + +#if defined(__UNIX__) && !defined(__WXMAC__) + // first get the string identifying the language from the environment + wxString langFull; + if (!wxGetEnv(wxT("LC_ALL"), &langFull) && + !wxGetEnv(wxT("LC_MESSAGES"), &langFull) && + !wxGetEnv(wxT("LANG"), &langFull)) + { + // no language specified, treat it as English + return wxLANGUAGE_ENGLISH_US; + } + + if ( langFull == _T("C") || langFull == _T("POSIX") ) + { + // default C locale is English too + return wxLANGUAGE_ENGLISH_US; + } + + // the language string has the following form + // + // lang[_LANG][.encoding][@modifier] + // + // (see environ(5) in the Open Unix specification) + // + // where lang is the primary language, LANG is a sublang/territory, + // encoding is the charset to use and modifier "allows the user to select + // a specific instance of localization data within a single category" + // + // for example, the following strings are valid: + // fr + // fr_FR + // de_DE.iso88591 + // de_DE@euro + // de_DE.iso88591@euro + + // for now we don't use the encoding, although we probably should (doing + // translations of the msg catalogs on the fly as required) (TODO) + // + // we need the modified for languages like Valencian: ca_ES@valencia + // though, remember it + wxString modifier; + size_t posModifier = langFull.find_first_of(_T("@")); + if ( posModifier != wxString::npos ) + modifier = langFull.Mid(posModifier); + + size_t posEndLang = langFull.find_first_of(_T("@.")); + if ( posEndLang != wxString::npos ) + { + langFull.Truncate(posEndLang); + } + + // in addition to the format above, we also can have full language names + // in LANG env var - for example, SuSE is known to use LANG="german" - so + // check for this + + // do we have just the language (or sublang too)? + bool justLang = langFull.length() == LEN_LANG; + if ( justLang || + (langFull.length() == LEN_FULL && langFull[LEN_LANG] == wxT('_')) ) + { + // 0. Make sure the lang is according to latest ISO 639 + // (this is necessary because glibc uses iw and in instead + // of he and id respectively). + + // the language itself (second part is the dialect/sublang) + wxString langOrig = ExtractLang(langFull); + + wxString lang; + if ( langOrig == wxT("iw")) + lang = _T("he"); + else if (langOrig == wxT("in")) + lang = wxT("id"); + else if (langOrig == wxT("ji")) + lang = wxT("yi"); + else if (langOrig == wxT("no_NO")) + lang = wxT("nb_NO"); + else if (langOrig == wxT("no_NY")) + lang = wxT("nn_NO"); + else if (langOrig == wxT("no")) + lang = wxT("nb_NO"); + else + lang = langOrig; + + // did we change it? + if ( lang != langOrig ) + { + langFull = lang + ExtractNotLang(langFull); + } + + // 1. Try to find the language either as is: + // a) With modifier if set + if ( !modifier.empty() ) + { + wxString langFullWithModifier = langFull + modifier; + for ( i = 0; i < count; i++ ) + { + if ( ms_languagesDB->Item(i).CanonicalName == langFullWithModifier ) + break; + } + } + + // b) Without modifier + if ( modifier.empty() || i == count ) + { + for ( i = 0; i < count; i++ ) + { + if ( ms_languagesDB->Item(i).CanonicalName == langFull ) + break; + } + } + + // 2. If langFull is of the form xx_YY, try to find xx: + if ( i == count && !justLang ) + { + for ( i = 0; i < count; i++ ) + { + if ( ms_languagesDB->Item(i).CanonicalName == lang ) + { + break; + } + } + } + + // 3. If langFull is of the form xx, try to find any xx_YY record: + if ( i == count && justLang ) + { + for ( i = 0; i < count; i++ ) + { + if ( ExtractLang(ms_languagesDB->Item(i).CanonicalName) + == langFull ) + { + break; + } + } + } + } + else // not standard format + { + // try to find the name in verbose description + for ( i = 0; i < count; i++ ) + { + if (ms_languagesDB->Item(i).Description.CmpNoCase(langFull) == 0) + { + break; + } + } + } +#elif defined(__WXMAC__) + const wxChar * lc = NULL ; + long lang = GetScriptVariable( smSystemScript, smScriptLang) ; + switch( GetScriptManagerVariable( smRegionCode ) ) { + case verUS : + lc = wxT("en_US") ; + break ; + case verFrance : + lc = wxT("fr_FR") ; + break ; + case verBritain : + lc = wxT("en_GB") ; + break ; + case verGermany : + lc = wxT("de_DE") ; + break ; + case verItaly : + lc = wxT("it_IT") ; + break ; + case verNetherlands : + lc = wxT("nl_NL") ; + break ; + case verFlemish : + lc = wxT("nl_BE") ; + break ; + case verSweden : + lc = wxT("sv_SE" ); + break ; + case verSpain : + lc = wxT("es_ES" ); + break ; + case verDenmark : + lc = wxT("da_DK") ; + break ; + case verPortugal : + lc = wxT("pt_PT") ; + break ; + case verFrCanada: + lc = wxT("fr_CA") ; + break ; + case verNorway: + lc = wxT("nb_NO") ; + break ; + case verIsrael: + lc = wxT("iw_IL") ; + break ; + case verJapan: + lc = wxT("ja_JP") ; + break ; + case verAustralia: + lc = wxT("en_AU") ; + break ; + case verArabic: + lc = wxT("ar") ; + break ; + case verFinland: + lc = wxT("fi_FI") ; + break ; + case verFrSwiss: + lc = wxT("fr_CH") ; + break ; + case verGrSwiss: + lc = wxT("de_CH") ; + break ; + case verGreece: + lc = wxT("el_GR") ; + break ; + case verIceland: + lc = wxT("is_IS") ; + break ; + case verMalta: + lc = wxT("mt_MT") ; + break ; + case verCyprus: + // _CY is not part of wx, so we have to translate according to the system language + if ( lang == langGreek ) { + lc = wxT("el_GR") ; + } + else if ( lang == langTurkish ) { + lc = wxT("tr_TR") ; + } + break ; + case verTurkey: + lc = wxT("tr_TR") ; + break ; + case verYugoCroatian: + lc = wxT("hr_HR") ; + break ; + case verIndiaHindi: + lc = wxT("hi_IN") ; + break ; + case verPakistanUrdu: + lc = wxT("ur_PK") ; + break ; + case verTurkishModified: + lc = wxT("tr_TR") ; + break ; + case verItalianSwiss: + lc = wxT("it_CH") ; + break ; + case verInternational: + lc = wxT("en") ; + break ; + case verRomania: + lc = wxT("ro_RO") ; + break ; + case verGreecePoly: + lc = wxT("el_GR") ; + break ; + case verLithuania: + lc = wxT("lt_LT") ; + break ; + case verPoland: + lc = wxT("pl_PL") ; + break ; + case verMagyar : + case verHungary: + lc = wxT("hu_HU") ; + break ; + case verEstonia: + lc = wxT("et_EE") ; + break ; + case verLatvia: + lc = wxT("lv_LV") ; + break ; + case verSami: + lc = wxT("se_NO") ; + break ; + case verFaroeIsl: + lc = wxT("fo_FO") ; + break ; + case verIran: + lc = wxT("fa_IR") ; + break ; + case verRussia: + lc = wxT("ru_RU") ; + break ; + case verIreland: + lc = wxT("ga_IE") ; + break ; + case verKorea: + lc = wxT("ko_KR") ; + break ; + case verChina: + lc = wxT("zh_CN") ; + break ; + case verTaiwan: + lc = wxT("zh_TW") ; + break ; + case verThailand: + lc = wxT("th_TH") ; + break ; + case verCzech: + lc = wxT("cs_CZ") ; + break ; + case verSlovak: + lc = wxT("sk_SK") ; + break ; + case verBengali: + lc = wxT("bn") ; + break ; + case verByeloRussian: + lc = wxT("be_BY") ; + break ; + case verUkraine: + lc = wxT("uk_UA") ; + break ; + case verGreeceAlt: + lc = wxT("el_GR") ; + break ; + case verSerbian: + lc = wxT("sr_YU") ; + break ; + case verSlovenian: + lc = wxT("sl_SI") ; + break ; + case verMacedonian: + lc = wxT("mk_MK") ; + break ; + case verCroatia: + lc = wxT("hr_HR") ; + break ; + case verBrazil: + lc = wxT("pt_BR ") ; + break ; + case verBulgaria: + lc = wxT("bg_BG") ; + break ; + case verCatalonia: + lc = wxT("ca_ES") ; + break ; + case verScottishGaelic: + lc = wxT("gd") ; + break ; + case verManxGaelic: + lc = wxT("gv") ; + break ; + case verBreton: + lc = wxT("br") ; + break ; + case verNunavut: + lc = wxT("iu_CA") ; + break ; + case verWelsh: + lc = wxT("cy") ; + break ; + case verIrishGaelicScript: + lc = wxT("ga_IE") ; + break ; + case verEngCanada: + lc = wxT("en_CA") ; + break ; + case verBhutan: + lc = wxT("dz_BT") ; + break ; + case verArmenian: + lc = wxT("hy_AM") ; + break ; + case verGeorgian: + lc = wxT("ka_GE") ; + break ; + case verSpLatinAmerica: + lc = wxT("es_AR") ; + break ; + case verTonga: + lc = wxT("to_TO" ); + break ; + case verFrenchUniversal: + lc = wxT("fr_FR") ; + break ; + case verAustria: + lc = wxT("de_AT") ; + break ; + case verGujarati: + lc = wxT("gu_IN") ; + break ; + case verPunjabi: + lc = wxT("pa") ; + break ; + case verIndiaUrdu: + lc = wxT("ur_IN") ; + break ; + case verVietnam: + lc = wxT("vi_VN") ; + break ; + case verFrBelgium: + lc = wxT("fr_BE") ; + break ; + case verUzbek: + lc = wxT("uz_UZ") ; + break ; + case verSingapore: + lc = wxT("zh_SG") ; + break ; + case verNynorsk: + lc = wxT("nn_NO") ; + break ; + case verAfrikaans: + lc = wxT("af_ZA") ; + break ; + case verEsperanto: + lc = wxT("eo") ; + break ; + case verMarathi: + lc = wxT("mr_IN") ; + break ; + case verTibetan: + lc = wxT("bo") ; + break ; + case verNepal: + lc = wxT("ne_NP") ; + break ; + case verGreenland: + lc = wxT("kl_GL") ; + break ; + default : + break ; + } + if ( !lc ) + return wxLANGUAGE_UNKNOWN; + for ( i = 0; i < count; i++ ) + { + if ( ms_languagesDB->Item(i).CanonicalName == lc ) + { + break; + } + } + +#elif defined(__WIN32__) + LCID lcid = GetUserDefaultLCID(); + if ( lcid != 0 ) + { + wxUint32 lang = PRIMARYLANGID(LANGIDFROMLCID(lcid)); + wxUint32 sublang = SUBLANGID(LANGIDFROMLCID(lcid)); + + for ( i = 0; i < count; i++ ) + { + if (ms_languagesDB->Item(i).WinLang == lang && + ms_languagesDB->Item(i).WinSublang == sublang) + { + break; + } + } + } + //else: leave wxlang == wxLANGUAGE_UNKNOWN +#endif // Unix/Win32 + + if ( i < count ) + { + // we did find a matching entry, use it + return ms_languagesDB->Item(i).Language; + } + + // no info about this language in the database + return wxLANGUAGE_UNKNOWN; +} + +// ---------------------------------------------------------------------------- +// encoding stuff +// ---------------------------------------------------------------------------- + +// this is a bit strange as under Windows we get the encoding name using its +// numeric value and under Unix we do it the other way round, but this just +// reflects the way different systems provide the encoding info + +/* static */ +wxString wxLocale::GetSystemEncodingName() +{ + wxString encname; + +#if defined(__WIN32__) && !defined(__WXMICROWIN__) + // FIXME: what is the error return value for GetACP()? + UINT codepage = ::GetACP(); + encname.Printf(_T("windows-%u"), codepage); +#elif defined(__WXMAC__) + // default is just empty string, this resolves to the default system + // encoding later +#elif defined(__UNIX_LIKE__) + +#if defined(HAVE_LANGINFO_H) && defined(CODESET) + // GNU libc provides current character set this way (this conforms + // to Unix98) + char *oldLocale = strdup(setlocale(LC_CTYPE, NULL)); + setlocale(LC_CTYPE, ""); + const char *alang = nl_langinfo(CODESET); + setlocale(LC_CTYPE, oldLocale); + free(oldLocale); + + if ( alang ) + { + encname = wxString::FromAscii( alang ); + } + else // nl_langinfo() failed +#endif // HAVE_LANGINFO_H + { + // if we can't get at the character set directly, try to see if it's in + // the environment variables (in most cases this won't work, but I was + // out of ideas) + char *lang = getenv( "LC_ALL"); + char *dot = lang ? strchr(lang, '.') : (char *)NULL; + if (!dot) + { + lang = getenv( "LC_CTYPE" ); + if ( lang ) + dot = strchr(lang, '.' ); + } + if (!dot) + { + lang = getenv( "LANG"); + if ( lang ) + dot = strchr(lang, '.'); + } + + if ( dot ) + { + encname = wxString::FromAscii( dot+1 ); + } + } +#endif // Win32/Unix + + return encname; +} + +/* static */ +wxFontEncoding wxLocale::GetSystemEncoding() +{ +#if defined(__WIN32__) && !defined(__WXMICROWIN__) + UINT codepage = ::GetACP(); + + // wxWidgets only knows about CP1250-1257, 874, 932, 936, 949, 950 + if ( codepage >= 1250 && codepage <= 1257 ) + { + return (wxFontEncoding)(wxFONTENCODING_CP1250 + codepage - 1250); + } + + if ( codepage == 874 ) + { + return wxFONTENCODING_CP874; + } + + if ( codepage == 932 ) + { + return wxFONTENCODING_CP932; + } + + if ( codepage == 936 ) + { + return wxFONTENCODING_CP936; + } + + if ( codepage == 949 ) + { + return wxFONTENCODING_CP949; + } + + if ( codepage == 950 ) + { + return wxFONTENCODING_CP950; + } +#elif defined(__WXMAC__) + TextEncoding encoding = 0 ; +#if TARGET_CARBON + encoding = CFStringGetSystemEncoding() ; +#else + UpgradeScriptInfoToTextEncoding ( smSystemScript , kTextLanguageDontCare , kTextRegionDontCare , NULL , &encoding ) ; +#endif + return wxMacGetFontEncFromSystemEnc( encoding ) ; +#elif defined(__UNIX_LIKE__) && wxUSE_FONTMAP + const wxString encname = GetSystemEncodingName(); + if ( !encname.empty() ) + { + wxFontEncoding enc = wxFontMapperBase::GetEncodingFromName(encname); + + // on some modern Linux systems (RedHat 8) the default system locale + // is UTF8 -- but it isn't supported by wxGTK1 in ANSI build at all so + // don't even try to use it in this case +#if !wxUSE_UNICODE && \ + ((defined(__WXGTK__) && !defined(__WXGTK20__)) || defined(__WXMOTIF__)) + if ( enc == wxFONTENCODING_UTF8 ) + { + // the most similar supported encoding... + enc = wxFONTENCODING_ISO8859_1; + } +#endif // !wxUSE_UNICODE + + // GetEncodingFromName() returns wxFONTENCODING_DEFAULT for C locale + // (a.k.a. US-ASCII) which is arguably a bug but keep it like this for + // backwards compatibility and just take care to not return + // wxFONTENCODING_DEFAULT from here as this surely doesn't make sense + if ( enc != wxFONTENCODING_MAX && enc != wxFONTENCODING_DEFAULT ) + { + return enc; + } + //else: return wxFONTENCODING_SYSTEM below + } +#endif // Win32/Unix + + return wxFONTENCODING_SYSTEM; +} + +/* static */ +void wxLocale::AddLanguage(const wxLanguageInfo& info) +{ + CreateLanguagesDB(); + ms_languagesDB->Add(info); +} + +/* static */ +const wxLanguageInfo *wxLocale::GetLanguageInfo(int lang) +{ + CreateLanguagesDB(); + + // calling GetLanguageInfo(wxLANGUAGE_DEFAULT) is a natural thing to do, so + // make it work + if ( lang == wxLANGUAGE_DEFAULT ) + lang = GetSystemLanguage(); + + const size_t count = ms_languagesDB->GetCount(); + for ( size_t i = 0; i < count; i++ ) + { + if ( ms_languagesDB->Item(i).Language == lang ) + { + // We need to create a temporary here in order to make this work with BCC in final build mode + wxLanguageInfo *ptr = &ms_languagesDB->Item(i); + return ptr; + } + } + + return NULL; +} + +/* static */ +wxString wxLocale::GetLanguageName(int lang) +{ + const wxLanguageInfo *info = GetLanguageInfo(lang); + if ( !info ) + return wxEmptyString; + else + return info->Description; +} + +/* static */ +const wxLanguageInfo *wxLocale::FindLanguageInfo(const wxString& locale) +{ + CreateLanguagesDB(); + + const wxLanguageInfo *infoRet = NULL; + + const size_t count = ms_languagesDB->GetCount(); + for ( size_t i = 0; i < count; i++ ) + { + const wxLanguageInfo *info = &ms_languagesDB->Item(i); + + if ( wxStricmp(locale, info->CanonicalName) == 0 || + wxStricmp(locale, info->Description) == 0 ) + { + // exact match, stop searching + infoRet = info; + break; + } + + if ( wxStricmp(locale, info->CanonicalName.BeforeFirst(_T('_'))) == 0 ) + { + // a match -- but maybe we'll find an exact one later, so continue + // looking + // + // OTOH, maybe we had already found a language match and in this + // case don't overwrite it becauce the entry for the default + // country always appears first in ms_languagesDB + if ( !infoRet ) + infoRet = info; + } + } + + return infoRet; +} + +wxString wxLocale::GetSysName() const +{ + // FIXME +#ifndef __WXWINCE__ + return wxSetlocale(LC_ALL, NULL); +#else + return wxEmptyString; +#endif +} + +// clean up +wxLocale::~wxLocale() +{ + // free memory + wxMsgCatalog *pTmpCat; + while ( m_pMsgCat != NULL ) { + pTmpCat = m_pMsgCat; + m_pMsgCat = m_pMsgCat->m_pNext; + delete pTmpCat; + } + + // restore old locale pointer + wxSetLocale(m_pOldLocale); + + // FIXME +#ifndef __WXWINCE__ + wxSetlocale(LC_ALL, m_pszOldLocale); +#endif + free((wxChar *)m_pszOldLocale); // const_cast +} + +// get the translation of given string in current locale +const wxChar *wxLocale::GetString(const wxChar *szOrigString, + const wxChar *szDomain) const +{ + return GetString(szOrigString, szOrigString, size_t(-1), szDomain); +} + +const wxChar *wxLocale::GetString(const wxChar *szOrigString, + const wxChar *szOrigString2, + size_t n, + const wxChar *szDomain) const +{ + if ( wxIsEmpty(szOrigString) ) + return wxEmptyString; + + const wxChar *pszTrans = NULL; + wxMsgCatalog *pMsgCat; + + if ( szDomain != NULL && szDomain[0] ) + { + pMsgCat = FindCatalog(szDomain); + + // does the catalog exist? + if ( pMsgCat != NULL ) + pszTrans = pMsgCat->GetString(szOrigString, n); + } + else + { + // search in all domains + for ( pMsgCat = m_pMsgCat; pMsgCat != NULL; pMsgCat = pMsgCat->m_pNext ) + { + pszTrans = pMsgCat->GetString(szOrigString, n); + if ( pszTrans != NULL ) // take the first found + break; + } + } + + if ( pszTrans == NULL ) + { +#ifdef __WXDEBUG__ + if ( !NoTransErr::Suppress() ) + { + NoTransErr noTransErr; + + wxLogTrace(TRACE_I18N, + _T("string \"%s\"[%ld] not found in %slocale '%s'."), + szOrigString, (long)n, + szDomain ? wxString::Format(_T("domain '%s' "), szDomain).c_str() + : _T(""), + m_strLocale.c_str()); + } +#endif // __WXDEBUG__ + + if (n == size_t(-1)) + return szOrigString; + else + return n == 1 ? szOrigString : szOrigString2; + } + + return pszTrans; +} + +wxString wxLocale::GetHeaderValue( const wxChar* szHeader, + const wxChar* szDomain ) const +{ + if ( wxIsEmpty(szHeader) ) + return wxEmptyString; + + wxChar const * pszTrans = NULL; + wxMsgCatalog *pMsgCat; + + if ( szDomain != NULL ) + { + pMsgCat = FindCatalog(szDomain); + + // does the catalog exist? + if ( pMsgCat == NULL ) + return wxEmptyString; + + pszTrans = pMsgCat->GetString(wxEmptyString, (size_t)-1); + } + else + { + // search in all domains + for ( pMsgCat = m_pMsgCat; pMsgCat != NULL; pMsgCat = pMsgCat->m_pNext ) + { + pszTrans = pMsgCat->GetString(wxEmptyString, (size_t)-1); + if ( pszTrans != NULL ) // take the first found + break; + } + } + + if ( wxIsEmpty(pszTrans) ) + return wxEmptyString; + + wxChar const * pszFound = wxStrstr(pszTrans, szHeader); + if ( pszFound == NULL ) + return wxEmptyString; + + pszFound += wxStrlen(szHeader) + 2 /* ': ' */; + + // Every header is separated by \n + + wxChar const * pszEndLine = wxStrchr(pszFound, wxT('\n')); + if ( pszEndLine == NULL ) pszEndLine = pszFound + wxStrlen(pszFound); + + + // wxString( wxChar*, length); + wxString retVal( pszFound, pszEndLine - pszFound ); + + return retVal; +} + + +// find catalog by name in a linked list, return NULL if !found +wxMsgCatalog *wxLocale::FindCatalog(const wxChar *szDomain) const +{ + // linear search in the linked list + wxMsgCatalog *pMsgCat; + for ( pMsgCat = m_pMsgCat; pMsgCat != NULL; pMsgCat = pMsgCat->m_pNext ) + { + if ( wxStricmp(pMsgCat->GetName(), szDomain) == 0 ) + return pMsgCat; + } + + return NULL; +} + +// check if the given locale is provided by OS and C run time +/* static */ +bool wxLocale::IsAvailable(int lang) +{ + const wxLanguageInfo *info = wxLocale::GetLanguageInfo(lang); + wxCHECK_MSG( info, false, _T("invalid language") ); + +#if defined(__WIN32__) + if ( !info->WinLang ) + return false; + + if ( !::IsValidLocale + ( + MAKELCID(MAKELANGID(info->WinLang, info->WinSublang), + SORT_DEFAULT), + LCID_INSTALLED + ) ) + return false; + +#elif defined(__UNIX__) + + // Test if setting the locale works, then set it back. + wxMB2WXbuf oldLocale = wxSetlocale(LC_ALL, wxEmptyString); + wxMB2WXbuf tmp = wxSetlocaleTryUTF(LC_ALL, info->CanonicalName); + if ( !tmp ) + { + // Some C libraries don't like xx_YY form and require xx only + tmp = wxSetlocaleTryUTF(LC_ALL, info->CanonicalName.Left(2)); + if ( !tmp ) + return false; + } + // restore the original locale + wxSetlocale(LC_ALL, oldLocale); +#endif + + return true; +} + +// check if the given catalog is loaded +bool wxLocale::IsLoaded(const wxChar *szDomain) const +{ + return FindCatalog(szDomain) != NULL; +} + +// add a catalog to our linked list +bool wxLocale::AddCatalog(const wxChar *szDomain) +{ + return AddCatalog(szDomain, wxLANGUAGE_ENGLISH_US, NULL); +} + +// add a catalog to our linked list +bool wxLocale::AddCatalog(const wxChar *szDomain, + wxLanguage msgIdLanguage, + const wxChar *msgIdCharset) + +{ + wxMsgCatalog *pMsgCat = new wxMsgCatalog; + + if ( pMsgCat->Load(m_strShort, szDomain, msgIdCharset, m_bConvertEncoding) ) { + // add it to the head of the list so that in GetString it will + // be searched before the catalogs added earlier + pMsgCat->m_pNext = m_pMsgCat; + m_pMsgCat = pMsgCat; + + return true; + } + else { + // don't add it because it couldn't be loaded anyway + delete pMsgCat; + + // It is OK to not load catalog if the msgid language and m_language match, + // in which case we can directly display the texts embedded in program's + // source code: + if (m_language == msgIdLanguage) + return true; + + // If there's no exact match, we may still get partial match where the + // (basic) language is same, but the country differs. For example, it's + // permitted to use en_US strings from sources even if m_language is en_GB: + const wxLanguageInfo *msgIdLangInfo = GetLanguageInfo(msgIdLanguage); + if ( msgIdLangInfo && + msgIdLangInfo->CanonicalName.Mid(0, 2) == m_strShort.Mid(0, 2) ) + { + return true; + } + + return false; + } +} + +// ---------------------------------------------------------------------------- +// accessors for locale-dependent data +// ---------------------------------------------------------------------------- + +#ifdef __WXMSW__ + +/* static */ +wxString wxLocale::GetInfo(wxLocaleInfo index, wxLocaleCategory WXUNUSED(cat)) +{ + wxUint32 lcid = LOCALE_USER_DEFAULT; + + if (wxGetLocale()) + { + const wxLanguageInfo *info = GetLanguageInfo(wxGetLocale()->GetLanguage()); + if (info) + { ; + lcid = MAKELCID(MAKELANGID(info->WinLang, info->WinSublang), + SORT_DEFAULT); + } + } + + wxString str; + wxChar buffer[256]; + size_t count; + buffer[0] = wxT('\0'); + switch (index) + { + case wxLOCALE_DECIMAL_POINT: + count = ::GetLocaleInfo(lcid, LOCALE_SDECIMAL, buffer, 256); + if (!count) + str << wxT("."); + else + str << buffer; + break; +#if 0 + case wxSYS_LIST_SEPARATOR: + count = ::GetLocaleInfo(lcid, LOCALE_SLIST, buffer, 256); + if (!count) + str << wxT(","); + else + str << buffer; + break; + case wxSYS_LEADING_ZERO: // 0 means no leading zero, 1 means leading zero + count = ::GetLocaleInfo(lcid, LOCALE_ILZERO, buffer, 256); + if (!count) + str << wxT("0"); + else + str << buffer; + break; +#endif + default: + wxFAIL_MSG(wxT("Unknown System String !")); + } + return str; +} + +#elif defined(__DARWIN__) + +/* static */ +wxString wxLocale::GetInfo(wxLocaleInfo index, wxLocaleCategory WXUNUSED(cat)) +{ + CFLocaleRef userLocaleRefRaw; + if ( wxGetLocale() ) + { + userLocaleRefRaw = CFLocaleCreate + ( + kCFAllocatorDefault, + wxMacCFStringHolder(wxGetLocale()->GetCanonicalName()) + ); + } + else // no current locale, use the default one + { + userLocaleRefRaw = CFLocaleCopyCurrent(); + } + + wxCFRef userLocaleRef(userLocaleRefRaw); + + CFTypeRef cfstr; + switch ( index ) + { + case wxLOCALE_THOUSANDS_SEP: + cfstr = CFLocaleGetValue(userLocaleRef, kCFLocaleGroupingSeparator); + break; + + case wxLOCALE_DECIMAL_POINT: + cfstr = CFLocaleGetValue(userLocaleRef, kCFLocaleDecimalSeparator); + break; + + default: + wxFAIL_MSG( _T("Unknown locale info") ); + } + + wxMacCFStringHolder + str(CFStringCreateCopy(NULL, static_cast(cfstr))); + return str.AsString(); +} + +#else // !__WXMSW__ && !__DARWIN__ + +/* static */ +wxString wxLocale::GetInfo(wxLocaleInfo index, wxLocaleCategory cat) +{ + struct lconv *locale_info = localeconv(); + switch (cat) + { + case wxLOCALE_CAT_NUMBER: + switch (index) + { + case wxLOCALE_THOUSANDS_SEP: + return wxString(locale_info->thousands_sep, + *wxConvCurrent); + case wxLOCALE_DECIMAL_POINT: + return wxString(locale_info->decimal_point, + *wxConvCurrent); + default: + return wxEmptyString; + } + case wxLOCALE_CAT_MONEY: + switch (index) + { + case wxLOCALE_THOUSANDS_SEP: + return wxString(locale_info->mon_thousands_sep, + *wxConvCurrent); + case wxLOCALE_DECIMAL_POINT: + return wxString(locale_info->mon_decimal_point, + *wxConvCurrent); + default: + return wxEmptyString; + } + default: + return wxEmptyString; + } +} + +#endif // __WXMSW__/!__WXMSW__ + +// ---------------------------------------------------------------------------- +// global functions and variables +// ---------------------------------------------------------------------------- + +// retrieve/change current locale +// ------------------------------ + +// the current locale object +static wxLocale *g_pLocale = NULL; + +wxLocale *wxGetLocale() +{ + return g_pLocale; +} + +wxLocale *wxSetLocale(wxLocale *pLocale) +{ + wxLocale *pOld = g_pLocale; + g_pLocale = pLocale; + return pOld; +} + + + +// ---------------------------------------------------------------------------- +// wxLocale module (for lazy destruction of languagesDB) +// ---------------------------------------------------------------------------- + +class wxLocaleModule: public wxModule +{ + DECLARE_DYNAMIC_CLASS(wxLocaleModule) + public: + wxLocaleModule() {} + bool OnInit() { return true; } + void OnExit() { wxLocale::DestroyLanguagesDB(); } +}; + +IMPLEMENT_DYNAMIC_CLASS(wxLocaleModule, wxModule) + + + +// ---------------------------------------------------------------------------- +// default languages table & initialization +// ---------------------------------------------------------------------------- + + + +// --- --- --- generated code begins here --- --- --- + +// This table is generated by misc/languages/genlang.py +// When making changes, please put them into misc/languages/langtabl.txt + +#if !defined(__WIN32__) || defined(__WXMICROWIN__) + +#define SETWINLANG(info,lang,sublang) + +#else + +#define SETWINLANG(info,lang,sublang) \ + info.WinLang = lang, info.WinSublang = sublang; + +#ifndef LANG_AFRIKAANS +#define LANG_AFRIKAANS (0) +#endif +#ifndef LANG_ALBANIAN +#define LANG_ALBANIAN (0) +#endif +#ifndef LANG_ARABIC +#define LANG_ARABIC (0) +#endif +#ifndef LANG_ARMENIAN +#define LANG_ARMENIAN (0) +#endif +#ifndef LANG_ASSAMESE +#define LANG_ASSAMESE (0) +#endif +#ifndef LANG_AZERI +#define LANG_AZERI (0) +#endif +#ifndef LANG_BASQUE +#define LANG_BASQUE (0) +#endif +#ifndef LANG_BELARUSIAN +#define LANG_BELARUSIAN (0) +#endif +#ifndef LANG_BENGALI +#define LANG_BENGALI (0) +#endif +#ifndef LANG_BULGARIAN +#define LANG_BULGARIAN (0) +#endif +#ifndef LANG_CATALAN +#define LANG_CATALAN (0) +#endif +#ifndef LANG_CHINESE +#define LANG_CHINESE (0) +#endif +#ifndef LANG_CROATIAN +#define LANG_CROATIAN (0) +#endif +#ifndef LANG_CZECH +#define LANG_CZECH (0) +#endif +#ifndef LANG_DANISH +#define LANG_DANISH (0) +#endif +#ifndef LANG_DUTCH +#define LANG_DUTCH (0) +#endif +#ifndef LANG_ENGLISH +#define LANG_ENGLISH (0) +#endif +#ifndef LANG_ESTONIAN +#define LANG_ESTONIAN (0) +#endif +#ifndef LANG_FAEROESE +#define LANG_FAEROESE (0) +#endif +#ifndef LANG_FARSI +#define LANG_FARSI (0) +#endif +#ifndef LANG_FINNISH +#define LANG_FINNISH (0) +#endif +#ifndef LANG_FRENCH +#define LANG_FRENCH (0) +#endif +#ifndef LANG_GEORGIAN +#define LANG_GEORGIAN (0) +#endif +#ifndef LANG_GERMAN +#define LANG_GERMAN (0) +#endif +#ifndef LANG_GREEK +#define LANG_GREEK (0) +#endif +#ifndef LANG_GUJARATI +#define LANG_GUJARATI (0) +#endif +#ifndef LANG_HEBREW +#define LANG_HEBREW (0) +#endif +#ifndef LANG_HINDI +#define LANG_HINDI (0) +#endif +#ifndef LANG_HUNGARIAN +#define LANG_HUNGARIAN (0) +#endif +#ifndef LANG_ICELANDIC +#define LANG_ICELANDIC (0) +#endif +#ifndef LANG_INDONESIAN +#define LANG_INDONESIAN (0) +#endif +#ifndef LANG_ITALIAN +#define LANG_ITALIAN (0) +#endif +#ifndef LANG_JAPANESE +#define LANG_JAPANESE (0) +#endif +#ifndef LANG_KANNADA +#define LANG_KANNADA (0) +#endif +#ifndef LANG_KASHMIRI +#define LANG_KASHMIRI (0) +#endif +#ifndef LANG_KAZAK +#define LANG_KAZAK (0) +#endif +#ifndef LANG_KONKANI +#define LANG_KONKANI (0) +#endif +#ifndef LANG_KOREAN +#define LANG_KOREAN (0) +#endif +#ifndef LANG_LATVIAN +#define LANG_LATVIAN (0) +#endif +#ifndef LANG_LITHUANIAN +#define LANG_LITHUANIAN (0) +#endif +#ifndef LANG_MACEDONIAN +#define LANG_MACEDONIAN (0) +#endif +#ifndef LANG_MALAY +#define LANG_MALAY (0) +#endif +#ifndef LANG_MALAYALAM +#define LANG_MALAYALAM (0) +#endif +#ifndef LANG_MANIPURI +#define LANG_MANIPURI (0) +#endif +#ifndef LANG_MARATHI +#define LANG_MARATHI (0) +#endif +#ifndef LANG_NEPALI +#define LANG_NEPALI (0) +#endif +#ifndef LANG_NORWEGIAN +#define LANG_NORWEGIAN (0) +#endif +#ifndef LANG_ORIYA +#define LANG_ORIYA (0) +#endif +#ifndef LANG_POLISH +#define LANG_POLISH (0) +#endif +#ifndef LANG_PORTUGUESE +#define LANG_PORTUGUESE (0) +#endif +#ifndef LANG_PUNJABI +#define LANG_PUNJABI (0) +#endif +#ifndef LANG_ROMANIAN +#define LANG_ROMANIAN (0) +#endif +#ifndef LANG_RUSSIAN +#define LANG_RUSSIAN (0) +#endif +#ifndef LANG_SAMI +#define LANG_SAMI (0) +#endif +#ifndef LANG_SANSKRIT +#define LANG_SANSKRIT (0) +#endif +#ifndef LANG_SERBIAN +#define LANG_SERBIAN (0) +#endif +#ifndef LANG_SINDHI +#define LANG_SINDHI (0) +#endif +#ifndef LANG_SLOVAK +#define LANG_SLOVAK (0) +#endif +#ifndef LANG_SLOVENIAN +#define LANG_SLOVENIAN (0) +#endif +#ifndef LANG_SPANISH +#define LANG_SPANISH (0) +#endif +#ifndef LANG_SWAHILI +#define LANG_SWAHILI (0) +#endif +#ifndef LANG_SWEDISH +#define LANG_SWEDISH (0) +#endif +#ifndef LANG_TAMIL +#define LANG_TAMIL (0) +#endif +#ifndef LANG_TATAR +#define LANG_TATAR (0) +#endif +#ifndef LANG_TELUGU +#define LANG_TELUGU (0) +#endif +#ifndef LANG_THAI +#define LANG_THAI (0) +#endif +#ifndef LANG_TURKISH +#define LANG_TURKISH (0) +#endif +#ifndef LANG_UKRAINIAN +#define LANG_UKRAINIAN (0) +#endif +#ifndef LANG_URDU +#define LANG_URDU (0) +#endif +#ifndef LANG_UZBEK +#define LANG_UZBEK (0) +#endif +#ifndef LANG_VALENCIAN +#define LANG_VALENCIAN (0) +#endif +#ifndef LANG_VIETNAMESE +#define LANG_VIETNAMESE (0) +#endif +#ifndef SUBLANG_ARABIC_ALGERIA +#define SUBLANG_ARABIC_ALGERIA SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_ARABIC_BAHRAIN +#define SUBLANG_ARABIC_BAHRAIN SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_ARABIC_EGYPT +#define SUBLANG_ARABIC_EGYPT SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_ARABIC_IRAQ +#define SUBLANG_ARABIC_IRAQ SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_ARABIC_JORDAN +#define SUBLANG_ARABIC_JORDAN SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_ARABIC_KUWAIT +#define SUBLANG_ARABIC_KUWAIT SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_ARABIC_LEBANON +#define SUBLANG_ARABIC_LEBANON SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_ARABIC_LIBYA +#define SUBLANG_ARABIC_LIBYA SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_ARABIC_MOROCCO +#define SUBLANG_ARABIC_MOROCCO SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_ARABIC_OMAN +#define SUBLANG_ARABIC_OMAN SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_ARABIC_QATAR +#define SUBLANG_ARABIC_QATAR SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_ARABIC_SAUDI_ARABIA +#define SUBLANG_ARABIC_SAUDI_ARABIA SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_ARABIC_SYRIA +#define SUBLANG_ARABIC_SYRIA SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_ARABIC_TUNISIA +#define SUBLANG_ARABIC_TUNISIA SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_ARABIC_UAE +#define SUBLANG_ARABIC_UAE SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_ARABIC_YEMEN +#define SUBLANG_ARABIC_YEMEN SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_AZERI_CYRILLIC +#define SUBLANG_AZERI_CYRILLIC SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_AZERI_LATIN +#define SUBLANG_AZERI_LATIN SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_CHINESE_SIMPLIFIED +#define SUBLANG_CHINESE_SIMPLIFIED SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_CHINESE_TRADITIONAL +#define SUBLANG_CHINESE_TRADITIONAL SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_CHINESE_HONGKONG +#define SUBLANG_CHINESE_HONGKONG SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_CHINESE_MACAU +#define SUBLANG_CHINESE_MACAU SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_CHINESE_SINGAPORE +#define SUBLANG_CHINESE_SINGAPORE SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_DUTCH +#define SUBLANG_DUTCH SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_DUTCH_BELGIAN +#define SUBLANG_DUTCH_BELGIAN SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_ENGLISH_UK +#define SUBLANG_ENGLISH_UK SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_ENGLISH_US +#define SUBLANG_ENGLISH_US SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_ENGLISH_AUS +#define SUBLANG_ENGLISH_AUS SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_ENGLISH_BELIZE +#define SUBLANG_ENGLISH_BELIZE SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_ENGLISH_CAN +#define SUBLANG_ENGLISH_CAN SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_ENGLISH_CARIBBEAN +#define SUBLANG_ENGLISH_CARIBBEAN SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_ENGLISH_EIRE +#define SUBLANG_ENGLISH_EIRE SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_ENGLISH_JAMAICA +#define SUBLANG_ENGLISH_JAMAICA SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_ENGLISH_NZ +#define SUBLANG_ENGLISH_NZ SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_ENGLISH_PHILIPPINES +#define SUBLANG_ENGLISH_PHILIPPINES SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_ENGLISH_SOUTH_AFRICA +#define SUBLANG_ENGLISH_SOUTH_AFRICA SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_ENGLISH_TRINIDAD +#define SUBLANG_ENGLISH_TRINIDAD SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_ENGLISH_ZIMBABWE +#define SUBLANG_ENGLISH_ZIMBABWE SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_FRENCH +#define SUBLANG_FRENCH SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_FRENCH_BELGIAN +#define SUBLANG_FRENCH_BELGIAN SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_FRENCH_CANADIAN +#define SUBLANG_FRENCH_CANADIAN SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_FRENCH_LUXEMBOURG +#define SUBLANG_FRENCH_LUXEMBOURG SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_FRENCH_MONACO +#define SUBLANG_FRENCH_MONACO SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_FRENCH_SWISS +#define SUBLANG_FRENCH_SWISS SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_GERMAN +#define SUBLANG_GERMAN SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_GERMAN_AUSTRIAN +#define SUBLANG_GERMAN_AUSTRIAN SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_GERMAN_LIECHTENSTEIN +#define SUBLANG_GERMAN_LIECHTENSTEIN SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_GERMAN_LUXEMBOURG +#define SUBLANG_GERMAN_LUXEMBOURG SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_GERMAN_SWISS +#define SUBLANG_GERMAN_SWISS SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_ITALIAN +#define SUBLANG_ITALIAN SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_ITALIAN_SWISS +#define SUBLANG_ITALIAN_SWISS SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_KASHMIRI_INDIA +#define SUBLANG_KASHMIRI_INDIA SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_KOREAN +#define SUBLANG_KOREAN SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_LITHUANIAN +#define SUBLANG_LITHUANIAN SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_MALAY_BRUNEI_DARUSSALAM +#define SUBLANG_MALAY_BRUNEI_DARUSSALAM SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_MALAY_MALAYSIA +#define SUBLANG_MALAY_MALAYSIA SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_NEPALI_INDIA +#define SUBLANG_NEPALI_INDIA SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_NORWEGIAN_BOKMAL +#define SUBLANG_NORWEGIAN_BOKMAL SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_NORWEGIAN_NYNORSK +#define SUBLANG_NORWEGIAN_NYNORSK SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_PORTUGUESE +#define SUBLANG_PORTUGUESE SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_PORTUGUESE_BRAZILIAN +#define SUBLANG_PORTUGUESE_BRAZILIAN SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_SERBIAN_CYRILLIC +#define SUBLANG_SERBIAN_CYRILLIC SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_SERBIAN_LATIN +#define SUBLANG_SERBIAN_LATIN SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_SPANISH +#define SUBLANG_SPANISH SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_SPANISH_ARGENTINA +#define SUBLANG_SPANISH_ARGENTINA SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_SPANISH_BOLIVIA +#define SUBLANG_SPANISH_BOLIVIA SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_SPANISH_CHILE +#define SUBLANG_SPANISH_CHILE SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_SPANISH_COLOMBIA +#define SUBLANG_SPANISH_COLOMBIA SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_SPANISH_COSTA_RICA +#define SUBLANG_SPANISH_COSTA_RICA SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_SPANISH_DOMINICAN_REPUBLIC +#define SUBLANG_SPANISH_DOMINICAN_REPUBLIC SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_SPANISH_ECUADOR +#define SUBLANG_SPANISH_ECUADOR SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_SPANISH_EL_SALVADOR +#define SUBLANG_SPANISH_EL_SALVADOR SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_SPANISH_GUATEMALA +#define SUBLANG_SPANISH_GUATEMALA SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_SPANISH_HONDURAS +#define SUBLANG_SPANISH_HONDURAS SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_SPANISH_MEXICAN +#define SUBLANG_SPANISH_MEXICAN SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_SPANISH_MODERN +#define SUBLANG_SPANISH_MODERN SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_SPANISH_NICARAGUA +#define SUBLANG_SPANISH_NICARAGUA SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_SPANISH_PANAMA +#define SUBLANG_SPANISH_PANAMA SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_SPANISH_PARAGUAY +#define SUBLANG_SPANISH_PARAGUAY SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_SPANISH_PERU +#define SUBLANG_SPANISH_PERU SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_SPANISH_PUERTO_RICO +#define SUBLANG_SPANISH_PUERTO_RICO SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_SPANISH_URUGUAY +#define SUBLANG_SPANISH_URUGUAY SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_SPANISH_VENEZUELA +#define SUBLANG_SPANISH_VENEZUELA SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_SWEDISH +#define SUBLANG_SWEDISH SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_SWEDISH_FINLAND +#define SUBLANG_SWEDISH_FINLAND SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_URDU_INDIA +#define SUBLANG_URDU_INDIA SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_URDU_PAKISTAN +#define SUBLANG_URDU_PAKISTAN SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_UZBEK_CYRILLIC +#define SUBLANG_UZBEK_CYRILLIC SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_UZBEK_LATIN +#define SUBLANG_UZBEK_LATIN SUBLANG_DEFAULT +#endif + + +#endif // __WIN32__ + +#define LNG(wxlang, canonical, winlang, winsublang, layout, desc) \ + info.Language = wxlang; \ + info.CanonicalName = wxT(canonical); \ + info.LayoutDirection = layout; \ + info.Description = wxT(desc); \ + SETWINLANG(info, winlang, winsublang) \ + AddLanguage(info); + +void wxLocale::InitLanguagesDB() +{ + wxLanguageInfo info; + wxStringTokenizer tkn; + + LNG(wxLANGUAGE_ABKHAZIAN, "ab" , 0 , 0 , wxLayout_LeftToRight, "Abkhazian") + LNG(wxLANGUAGE_AFAR, "aa" , 0 , 0 , wxLayout_LeftToRight, "Afar") + LNG(wxLANGUAGE_AFRIKAANS, "af_ZA", LANG_AFRIKAANS , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Afrikaans") + LNG(wxLANGUAGE_ALBANIAN, "sq_AL", LANG_ALBANIAN , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Albanian") + LNG(wxLANGUAGE_AMHARIC, "am" , 0 , 0 , wxLayout_LeftToRight, "Amharic") + LNG(wxLANGUAGE_ARABIC, "ar" , LANG_ARABIC , SUBLANG_DEFAULT , wxLayout_RightToLeft, "Arabic") + LNG(wxLANGUAGE_ARABIC_ALGERIA, "ar_DZ", LANG_ARABIC , SUBLANG_ARABIC_ALGERIA , wxLayout_RightToLeft, "Arabic (Algeria)") + LNG(wxLANGUAGE_ARABIC_BAHRAIN, "ar_BH", LANG_ARABIC , SUBLANG_ARABIC_BAHRAIN , wxLayout_RightToLeft, "Arabic (Bahrain)") + LNG(wxLANGUAGE_ARABIC_EGYPT, "ar_EG", LANG_ARABIC , SUBLANG_ARABIC_EGYPT , wxLayout_RightToLeft, "Arabic (Egypt)") + LNG(wxLANGUAGE_ARABIC_IRAQ, "ar_IQ", LANG_ARABIC , SUBLANG_ARABIC_IRAQ , wxLayout_RightToLeft, "Arabic (Iraq)") + LNG(wxLANGUAGE_ARABIC_JORDAN, "ar_JO", LANG_ARABIC , SUBLANG_ARABIC_JORDAN , wxLayout_RightToLeft, "Arabic (Jordan)") + LNG(wxLANGUAGE_ARABIC_KUWAIT, "ar_KW", LANG_ARABIC , SUBLANG_ARABIC_KUWAIT , wxLayout_RightToLeft, "Arabic (Kuwait)") + LNG(wxLANGUAGE_ARABIC_LEBANON, "ar_LB", LANG_ARABIC , SUBLANG_ARABIC_LEBANON , wxLayout_RightToLeft, "Arabic (Lebanon)") + LNG(wxLANGUAGE_ARABIC_LIBYA, "ar_LY", LANG_ARABIC , SUBLANG_ARABIC_LIBYA , wxLayout_RightToLeft, "Arabic (Libya)") + LNG(wxLANGUAGE_ARABIC_MOROCCO, "ar_MA", LANG_ARABIC , SUBLANG_ARABIC_MOROCCO , wxLayout_RightToLeft, "Arabic (Morocco)") + LNG(wxLANGUAGE_ARABIC_OMAN, "ar_OM", LANG_ARABIC , SUBLANG_ARABIC_OMAN , wxLayout_RightToLeft, "Arabic (Oman)") + LNG(wxLANGUAGE_ARABIC_QATAR, "ar_QA", LANG_ARABIC , SUBLANG_ARABIC_QATAR , wxLayout_RightToLeft, "Arabic (Qatar)") + LNG(wxLANGUAGE_ARABIC_SAUDI_ARABIA, "ar_SA", LANG_ARABIC , SUBLANG_ARABIC_SAUDI_ARABIA , wxLayout_RightToLeft, "Arabic (Saudi Arabia)") + LNG(wxLANGUAGE_ARABIC_SUDAN, "ar_SD", 0 , 0 , wxLayout_RightToLeft, "Arabic (Sudan)") + LNG(wxLANGUAGE_ARABIC_SYRIA, "ar_SY", LANG_ARABIC , SUBLANG_ARABIC_SYRIA , wxLayout_RightToLeft, "Arabic (Syria)") + LNG(wxLANGUAGE_ARABIC_TUNISIA, "ar_TN", LANG_ARABIC , SUBLANG_ARABIC_TUNISIA , wxLayout_RightToLeft, "Arabic (Tunisia)") + LNG(wxLANGUAGE_ARABIC_UAE, "ar_AE", LANG_ARABIC , SUBLANG_ARABIC_UAE , wxLayout_RightToLeft, "Arabic (Uae)") + LNG(wxLANGUAGE_ARABIC_YEMEN, "ar_YE", LANG_ARABIC , SUBLANG_ARABIC_YEMEN , wxLayout_RightToLeft, "Arabic (Yemen)") + LNG(wxLANGUAGE_ARMENIAN, "hy" , LANG_ARMENIAN , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Armenian") + LNG(wxLANGUAGE_ASSAMESE, "as" , LANG_ASSAMESE , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Assamese") + LNG(wxLANGUAGE_AYMARA, "ay" , 0 , 0 , wxLayout_LeftToRight, "Aymara") + LNG(wxLANGUAGE_AZERI, "az" , LANG_AZERI , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Azeri") + LNG(wxLANGUAGE_AZERI_CYRILLIC, "az" , LANG_AZERI , SUBLANG_AZERI_CYRILLIC , wxLayout_LeftToRight, "Azeri (Cyrillic)") + LNG(wxLANGUAGE_AZERI_LATIN, "az" , LANG_AZERI , SUBLANG_AZERI_LATIN , wxLayout_LeftToRight, "Azeri (Latin)") + LNG(wxLANGUAGE_BASHKIR, "ba" , 0 , 0 , wxLayout_LeftToRight, "Bashkir") + LNG(wxLANGUAGE_BASQUE, "eu_ES", LANG_BASQUE , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Basque") + LNG(wxLANGUAGE_BELARUSIAN, "be_BY", LANG_BELARUSIAN, SUBLANG_DEFAULT , wxLayout_LeftToRight, "Belarusian") + LNG(wxLANGUAGE_BENGALI, "bn" , LANG_BENGALI , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Bengali") + LNG(wxLANGUAGE_BHUTANI, "dz" , 0 , 0 , wxLayout_LeftToRight, "Bhutani") + LNG(wxLANGUAGE_BIHARI, "bh" , 0 , 0 , wxLayout_LeftToRight, "Bihari") + LNG(wxLANGUAGE_BISLAMA, "bi" , 0 , 0 , wxLayout_LeftToRight, "Bislama") + LNG(wxLANGUAGE_BRETON, "br" , 0 , 0 , wxLayout_LeftToRight, "Breton") + LNG(wxLANGUAGE_BULGARIAN, "bg_BG", LANG_BULGARIAN , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Bulgarian") + LNG(wxLANGUAGE_BURMESE, "my" , 0 , 0 , wxLayout_LeftToRight, "Burmese") + LNG(wxLANGUAGE_CAMBODIAN, "km" , 0 , 0 , wxLayout_LeftToRight, "Cambodian") + LNG(wxLANGUAGE_CATALAN, "ca_ES", LANG_CATALAN , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Catalan") + LNG(wxLANGUAGE_CHINESE, "zh_TW", LANG_CHINESE , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Chinese") + LNG(wxLANGUAGE_CHINESE_SIMPLIFIED, "zh_CN", LANG_CHINESE , SUBLANG_CHINESE_SIMPLIFIED , wxLayout_LeftToRight, "Chinese (Simplified)") + LNG(wxLANGUAGE_CHINESE_TRADITIONAL, "zh_TW", LANG_CHINESE , SUBLANG_CHINESE_TRADITIONAL , wxLayout_LeftToRight, "Chinese (Traditional)") + LNG(wxLANGUAGE_CHINESE_HONGKONG, "zh_HK", LANG_CHINESE , SUBLANG_CHINESE_HONGKONG , wxLayout_LeftToRight, "Chinese (Hongkong)") + LNG(wxLANGUAGE_CHINESE_MACAU, "zh_MO", LANG_CHINESE , SUBLANG_CHINESE_MACAU , wxLayout_LeftToRight, "Chinese (Macau)") + LNG(wxLANGUAGE_CHINESE_SINGAPORE, "zh_SG", LANG_CHINESE , SUBLANG_CHINESE_SINGAPORE , wxLayout_LeftToRight, "Chinese (Singapore)") + LNG(wxLANGUAGE_CHINESE_TAIWAN, "zh_TW", LANG_CHINESE , SUBLANG_CHINESE_TRADITIONAL , wxLayout_LeftToRight, "Chinese (Taiwan)") + LNG(wxLANGUAGE_CORSICAN, "co" , 0 , 0 , wxLayout_LeftToRight, "Corsican") + LNG(wxLANGUAGE_CROATIAN, "hr_HR", LANG_CROATIAN , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Croatian") + LNG(wxLANGUAGE_CZECH, "cs_CZ", LANG_CZECH , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Czech") + LNG(wxLANGUAGE_DANISH, "da_DK", LANG_DANISH , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Danish") + LNG(wxLANGUAGE_DUTCH, "nl_NL", LANG_DUTCH , SUBLANG_DUTCH , wxLayout_LeftToRight, "Dutch") + LNG(wxLANGUAGE_DUTCH_BELGIAN, "nl_BE", LANG_DUTCH , SUBLANG_DUTCH_BELGIAN , wxLayout_LeftToRight, "Dutch (Belgian)") + LNG(wxLANGUAGE_ENGLISH, "en_GB", LANG_ENGLISH , SUBLANG_ENGLISH_UK , wxLayout_LeftToRight, "English") + LNG(wxLANGUAGE_ENGLISH_UK, "en_GB", LANG_ENGLISH , SUBLANG_ENGLISH_UK , wxLayout_LeftToRight, "English (U.K.)") + LNG(wxLANGUAGE_ENGLISH_US, "en_US", LANG_ENGLISH , SUBLANG_ENGLISH_US , wxLayout_LeftToRight, "English (U.S.)") + LNG(wxLANGUAGE_ENGLISH_AUSTRALIA, "en_AU", LANG_ENGLISH , SUBLANG_ENGLISH_AUS , wxLayout_LeftToRight, "English (Australia)") + LNG(wxLANGUAGE_ENGLISH_BELIZE, "en_BZ", LANG_ENGLISH , SUBLANG_ENGLISH_BELIZE , wxLayout_LeftToRight, "English (Belize)") + LNG(wxLANGUAGE_ENGLISH_BOTSWANA, "en_BW", 0 , 0 , wxLayout_LeftToRight, "English (Botswana)") + LNG(wxLANGUAGE_ENGLISH_CANADA, "en_CA", LANG_ENGLISH , SUBLANG_ENGLISH_CAN , wxLayout_LeftToRight, "English (Canada)") + LNG(wxLANGUAGE_ENGLISH_CARIBBEAN, "en_CB", LANG_ENGLISH , SUBLANG_ENGLISH_CARIBBEAN , wxLayout_LeftToRight, "English (Caribbean)") + LNG(wxLANGUAGE_ENGLISH_DENMARK, "en_DK", 0 , 0 , wxLayout_LeftToRight, "English (Denmark)") + LNG(wxLANGUAGE_ENGLISH_EIRE, "en_IE", LANG_ENGLISH , SUBLANG_ENGLISH_EIRE , wxLayout_LeftToRight, "English (Eire)") + LNG(wxLANGUAGE_ENGLISH_JAMAICA, "en_JM", LANG_ENGLISH , SUBLANG_ENGLISH_JAMAICA , wxLayout_LeftToRight, "English (Jamaica)") + LNG(wxLANGUAGE_ENGLISH_NEW_ZEALAND, "en_NZ", LANG_ENGLISH , SUBLANG_ENGLISH_NZ , wxLayout_LeftToRight, "English (New Zealand)") + LNG(wxLANGUAGE_ENGLISH_PHILIPPINES, "en_PH", LANG_ENGLISH , SUBLANG_ENGLISH_PHILIPPINES , wxLayout_LeftToRight, "English (Philippines)") + LNG(wxLANGUAGE_ENGLISH_SOUTH_AFRICA, "en_ZA", LANG_ENGLISH , SUBLANG_ENGLISH_SOUTH_AFRICA , wxLayout_LeftToRight, "English (South Africa)") + LNG(wxLANGUAGE_ENGLISH_TRINIDAD, "en_TT", LANG_ENGLISH , SUBLANG_ENGLISH_TRINIDAD , wxLayout_LeftToRight, "English (Trinidad)") + LNG(wxLANGUAGE_ENGLISH_ZIMBABWE, "en_ZW", LANG_ENGLISH , SUBLANG_ENGLISH_ZIMBABWE , wxLayout_LeftToRight, "English (Zimbabwe)") + LNG(wxLANGUAGE_ESPERANTO, "eo" , 0 , 0 , wxLayout_LeftToRight, "Esperanto") + LNG(wxLANGUAGE_ESTONIAN, "et_EE", LANG_ESTONIAN , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Estonian") + LNG(wxLANGUAGE_FAEROESE, "fo_FO", LANG_FAEROESE , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Faeroese") + LNG(wxLANGUAGE_FARSI, "fa_IR", LANG_FARSI , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Farsi") + LNG(wxLANGUAGE_FIJI, "fj" , 0 , 0 , wxLayout_LeftToRight, "Fiji") + LNG(wxLANGUAGE_FINNISH, "fi_FI", LANG_FINNISH , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Finnish") + LNG(wxLANGUAGE_FRENCH, "fr_FR", LANG_FRENCH , SUBLANG_FRENCH , wxLayout_LeftToRight, "French") + LNG(wxLANGUAGE_FRENCH_BELGIAN, "fr_BE", LANG_FRENCH , SUBLANG_FRENCH_BELGIAN , wxLayout_LeftToRight, "French (Belgian)") + LNG(wxLANGUAGE_FRENCH_CANADIAN, "fr_CA", LANG_FRENCH , SUBLANG_FRENCH_CANADIAN , wxLayout_LeftToRight, "French (Canadian)") + LNG(wxLANGUAGE_FRENCH_LUXEMBOURG, "fr_LU", LANG_FRENCH , SUBLANG_FRENCH_LUXEMBOURG , wxLayout_LeftToRight, "French (Luxembourg)") + LNG(wxLANGUAGE_FRENCH_MONACO, "fr_MC", LANG_FRENCH , SUBLANG_FRENCH_MONACO , wxLayout_LeftToRight, "French (Monaco)") + LNG(wxLANGUAGE_FRENCH_SWISS, "fr_CH", LANG_FRENCH , SUBLANG_FRENCH_SWISS , wxLayout_LeftToRight, "French (Swiss)") + LNG(wxLANGUAGE_FRISIAN, "fy" , 0 , 0 , wxLayout_LeftToRight, "Frisian") + LNG(wxLANGUAGE_GALICIAN, "gl_ES", 0 , 0 , wxLayout_LeftToRight, "Galician") + LNG(wxLANGUAGE_GEORGIAN, "ka_GE", LANG_GEORGIAN , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Georgian") + LNG(wxLANGUAGE_GERMAN, "de_DE", LANG_GERMAN , SUBLANG_GERMAN , wxLayout_LeftToRight, "German") + LNG(wxLANGUAGE_GERMAN_AUSTRIAN, "de_AT", LANG_GERMAN , SUBLANG_GERMAN_AUSTRIAN , wxLayout_LeftToRight, "German (Austrian)") + LNG(wxLANGUAGE_GERMAN_BELGIUM, "de_BE", 0 , 0 , wxLayout_LeftToRight, "German (Belgium)") + LNG(wxLANGUAGE_GERMAN_LIECHTENSTEIN, "de_LI", LANG_GERMAN , SUBLANG_GERMAN_LIECHTENSTEIN , wxLayout_LeftToRight, "German (Liechtenstein)") + LNG(wxLANGUAGE_GERMAN_LUXEMBOURG, "de_LU", LANG_GERMAN , SUBLANG_GERMAN_LUXEMBOURG , wxLayout_LeftToRight, "German (Luxembourg)") + LNG(wxLANGUAGE_GERMAN_SWISS, "de_CH", LANG_GERMAN , SUBLANG_GERMAN_SWISS , wxLayout_LeftToRight, "German (Swiss)") + LNG(wxLANGUAGE_GREEK, "el_GR", LANG_GREEK , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Greek") + LNG(wxLANGUAGE_GREENLANDIC, "kl_GL", 0 , 0 , wxLayout_LeftToRight, "Greenlandic") + LNG(wxLANGUAGE_GUARANI, "gn" , 0 , 0 , wxLayout_LeftToRight, "Guarani") + LNG(wxLANGUAGE_GUJARATI, "gu" , LANG_GUJARATI , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Gujarati") + LNG(wxLANGUAGE_HAUSA, "ha" , 0 , 0 , wxLayout_LeftToRight, "Hausa") + LNG(wxLANGUAGE_HEBREW, "he_IL", LANG_HEBREW , SUBLANG_DEFAULT , wxLayout_RightToLeft, "Hebrew") + LNG(wxLANGUAGE_HINDI, "hi_IN", LANG_HINDI , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Hindi") + LNG(wxLANGUAGE_HUNGARIAN, "hu_HU", LANG_HUNGARIAN , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Hungarian") + LNG(wxLANGUAGE_ICELANDIC, "is_IS", LANG_ICELANDIC , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Icelandic") + LNG(wxLANGUAGE_INDONESIAN, "id_ID", LANG_INDONESIAN, SUBLANG_DEFAULT , wxLayout_LeftToRight, "Indonesian") + LNG(wxLANGUAGE_INTERLINGUA, "ia" , 0 , 0 , wxLayout_LeftToRight, "Interlingua") + LNG(wxLANGUAGE_INTERLINGUE, "ie" , 0 , 0 , wxLayout_LeftToRight, "Interlingue") + LNG(wxLANGUAGE_INUKTITUT, "iu" , 0 , 0 , wxLayout_LeftToRight, "Inuktitut") + LNG(wxLANGUAGE_INUPIAK, "ik" , 0 , 0 , wxLayout_LeftToRight, "Inupiak") + LNG(wxLANGUAGE_IRISH, "ga_IE", 0 , 0 , wxLayout_LeftToRight, "Irish") + LNG(wxLANGUAGE_ITALIAN, "it_IT", LANG_ITALIAN , SUBLANG_ITALIAN , wxLayout_LeftToRight, "Italian") + LNG(wxLANGUAGE_ITALIAN_SWISS, "it_CH", LANG_ITALIAN , SUBLANG_ITALIAN_SWISS , wxLayout_LeftToRight, "Italian (Swiss)") + LNG(wxLANGUAGE_JAPANESE, "ja_JP", LANG_JAPANESE , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Japanese") + LNG(wxLANGUAGE_JAVANESE, "jw" , 0 , 0 , wxLayout_LeftToRight, "Javanese") + LNG(wxLANGUAGE_KANNADA, "kn" , LANG_KANNADA , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Kannada") + LNG(wxLANGUAGE_KASHMIRI, "ks" , LANG_KASHMIRI , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Kashmiri") + LNG(wxLANGUAGE_KASHMIRI_INDIA, "ks_IN", LANG_KASHMIRI , SUBLANG_KASHMIRI_INDIA , wxLayout_LeftToRight, "Kashmiri (India)") + LNG(wxLANGUAGE_KAZAKH, "kk" , LANG_KAZAK , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Kazakh") + LNG(wxLANGUAGE_KERNEWEK, "kw_GB", 0 , 0 , wxLayout_LeftToRight, "Kernewek") + LNG(wxLANGUAGE_KINYARWANDA, "rw" , 0 , 0 , wxLayout_LeftToRight, "Kinyarwanda") + LNG(wxLANGUAGE_KIRGHIZ, "ky" , 0 , 0 , wxLayout_LeftToRight, "Kirghiz") + LNG(wxLANGUAGE_KIRUNDI, "rn" , 0 , 0 , wxLayout_LeftToRight, "Kirundi") + LNG(wxLANGUAGE_KONKANI, "" , LANG_KONKANI , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Konkani") + LNG(wxLANGUAGE_KOREAN, "ko_KR", LANG_KOREAN , SUBLANG_KOREAN , wxLayout_LeftToRight, "Korean") + LNG(wxLANGUAGE_KURDISH, "ku_TR", 0 , 0 , wxLayout_LeftToRight, "Kurdish") + LNG(wxLANGUAGE_LAOTHIAN, "lo" , 0 , 0 , wxLayout_LeftToRight, "Laothian") + LNG(wxLANGUAGE_LATIN, "la" , 0 , 0 , wxLayout_LeftToRight, "Latin") + LNG(wxLANGUAGE_LATVIAN, "lv_LV", LANG_LATVIAN , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Latvian") + LNG(wxLANGUAGE_LINGALA, "ln" , 0 , 0 , wxLayout_LeftToRight, "Lingala") + LNG(wxLANGUAGE_LITHUANIAN, "lt_LT", LANG_LITHUANIAN, SUBLANG_LITHUANIAN , wxLayout_LeftToRight, "Lithuanian") + LNG(wxLANGUAGE_MACEDONIAN, "mk_MK", LANG_MACEDONIAN, SUBLANG_DEFAULT , wxLayout_LeftToRight, "Macedonian") + LNG(wxLANGUAGE_MALAGASY, "mg" , 0 , 0 , wxLayout_LeftToRight, "Malagasy") + LNG(wxLANGUAGE_MALAY, "ms_MY", LANG_MALAY , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Malay") + LNG(wxLANGUAGE_MALAYALAM, "ml" , LANG_MALAYALAM , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Malayalam") + LNG(wxLANGUAGE_MALAY_BRUNEI_DARUSSALAM, "ms_BN", LANG_MALAY , SUBLANG_MALAY_BRUNEI_DARUSSALAM , wxLayout_LeftToRight, "Malay (Brunei Darussalam)") + LNG(wxLANGUAGE_MALAY_MALAYSIA, "ms_MY", LANG_MALAY , SUBLANG_MALAY_MALAYSIA , wxLayout_LeftToRight, "Malay (Malaysia)") + LNG(wxLANGUAGE_MALTESE, "mt_MT", 0 , 0 , wxLayout_LeftToRight, "Maltese") + LNG(wxLANGUAGE_MANIPURI, "" , LANG_MANIPURI , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Manipuri") + LNG(wxLANGUAGE_MAORI, "mi" , 0 , 0 , wxLayout_LeftToRight, "Maori") + LNG(wxLANGUAGE_MARATHI, "mr_IN", LANG_MARATHI , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Marathi") + LNG(wxLANGUAGE_MOLDAVIAN, "mo" , 0 , 0 , wxLayout_LeftToRight, "Moldavian") + LNG(wxLANGUAGE_MONGOLIAN, "mn" , 0 , 0 , wxLayout_LeftToRight, "Mongolian") + LNG(wxLANGUAGE_NAURU, "na" , 0 , 0 , wxLayout_LeftToRight, "Nauru") + LNG(wxLANGUAGE_NEPALI, "ne_NP", LANG_NEPALI , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Nepali") + LNG(wxLANGUAGE_NEPALI_INDIA, "ne_IN", LANG_NEPALI , SUBLANG_NEPALI_INDIA , wxLayout_LeftToRight, "Nepali (India)") + LNG(wxLANGUAGE_NORWEGIAN_BOKMAL, "nb_NO", LANG_NORWEGIAN , SUBLANG_NORWEGIAN_BOKMAL , wxLayout_LeftToRight, "Norwegian (Bokmal)") + LNG(wxLANGUAGE_NORWEGIAN_NYNORSK, "nn_NO", LANG_NORWEGIAN , SUBLANG_NORWEGIAN_NYNORSK , wxLayout_LeftToRight, "Norwegian (Nynorsk)") + LNG(wxLANGUAGE_OCCITAN, "oc" , 0 , 0 , wxLayout_LeftToRight, "Occitan") + LNG(wxLANGUAGE_ORIYA, "or" , LANG_ORIYA , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Oriya") + LNG(wxLANGUAGE_OROMO, "om" , 0 , 0 , wxLayout_LeftToRight, "(Afan) Oromo") + LNG(wxLANGUAGE_PASHTO, "ps" , 0 , 0 , wxLayout_LeftToRight, "Pashto, Pushto") + LNG(wxLANGUAGE_POLISH, "pl_PL", LANG_POLISH , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Polish") + LNG(wxLANGUAGE_PORTUGUESE, "pt_PT", LANG_PORTUGUESE, SUBLANG_PORTUGUESE , wxLayout_LeftToRight, "Portuguese") + LNG(wxLANGUAGE_PORTUGUESE_BRAZILIAN, "pt_BR", LANG_PORTUGUESE, SUBLANG_PORTUGUESE_BRAZILIAN , wxLayout_LeftToRight, "Portuguese (Brazilian)") + LNG(wxLANGUAGE_PUNJABI, "pa" , LANG_PUNJABI , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Punjabi") + LNG(wxLANGUAGE_QUECHUA, "qu" , 0 , 0 , wxLayout_LeftToRight, "Quechua") + LNG(wxLANGUAGE_RHAETO_ROMANCE, "rm" , 0 , 0 , wxLayout_LeftToRight, "Rhaeto-Romance") + LNG(wxLANGUAGE_ROMANIAN, "ro_RO", LANG_ROMANIAN , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Romanian") + LNG(wxLANGUAGE_RUSSIAN, "ru_RU", LANG_RUSSIAN , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Russian") + LNG(wxLANGUAGE_RUSSIAN_UKRAINE, "ru_UA", 0 , 0 , wxLayout_LeftToRight, "Russian (Ukraine)") + LNG(wxLANGUAGE_SAMOAN, "sm" , 0 , 0 , wxLayout_LeftToRight, "Samoan") + LNG(wxLANGUAGE_SANGHO, "sg" , 0 , 0 , wxLayout_LeftToRight, "Sangho") + LNG(wxLANGUAGE_SANSKRIT, "sa" , LANG_SANSKRIT , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Sanskrit") + LNG(wxLANGUAGE_SCOTS_GAELIC, "gd" , 0 , 0 , wxLayout_LeftToRight, "Scots Gaelic") + LNG(wxLANGUAGE_SAMI, "se_NO", LANG_SAMI , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Northern Sami") + LNG(wxLANGUAGE_SERBIAN, "sr_SR", LANG_SERBIAN , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Serbian") + LNG(wxLANGUAGE_SERBIAN_CYRILLIC, "sr_SR", LANG_SERBIAN , SUBLANG_SERBIAN_CYRILLIC , wxLayout_LeftToRight, "Serbian (Cyrillic)") + LNG(wxLANGUAGE_SERBIAN_LATIN, "sr_SR@latin", LANG_SERBIAN , SUBLANG_SERBIAN_LATIN , wxLayout_LeftToRight, "Serbian (Latin)") + LNG(wxLANGUAGE_SERBIAN_CYRILLIC, "sr_YU", LANG_SERBIAN , SUBLANG_SERBIAN_CYRILLIC , wxLayout_LeftToRight, "Serbian (Cyrillic)") + LNG(wxLANGUAGE_SERBIAN_LATIN, "sr_YU@latin", LANG_SERBIAN , SUBLANG_SERBIAN_LATIN , wxLayout_LeftToRight, "Serbian (Latin)") + LNG(wxLANGUAGE_SERBO_CROATIAN, "sh" , 0 , 0 , wxLayout_LeftToRight, "Serbo-Croatian") + LNG(wxLANGUAGE_SESOTHO, "st" , 0 , 0 , wxLayout_LeftToRight, "Sesotho") + LNG(wxLANGUAGE_SETSWANA, "tn" , 0 , 0 , wxLayout_LeftToRight, "Setswana") + LNG(wxLANGUAGE_SHONA, "sn" , 0 , 0 , wxLayout_LeftToRight, "Shona") + LNG(wxLANGUAGE_SINDHI, "sd" , LANG_SINDHI , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Sindhi") + LNG(wxLANGUAGE_SINHALESE, "si" , 0 , 0 , wxLayout_LeftToRight, "Sinhalese") + LNG(wxLANGUAGE_SISWATI, "ss" , 0 , 0 , wxLayout_LeftToRight, "Siswati") + LNG(wxLANGUAGE_SLOVAK, "sk_SK", LANG_SLOVAK , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Slovak") + LNG(wxLANGUAGE_SLOVENIAN, "sl_SI", LANG_SLOVENIAN , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Slovenian") + LNG(wxLANGUAGE_SOMALI, "so" , 0 , 0 , wxLayout_LeftToRight, "Somali") + LNG(wxLANGUAGE_SPANISH, "es_ES", LANG_SPANISH , SUBLANG_SPANISH , wxLayout_LeftToRight, "Spanish") + LNG(wxLANGUAGE_SPANISH_ARGENTINA, "es_AR", LANG_SPANISH , SUBLANG_SPANISH_ARGENTINA , wxLayout_LeftToRight, "Spanish (Argentina)") + LNG(wxLANGUAGE_SPANISH_BOLIVIA, "es_BO", LANG_SPANISH , SUBLANG_SPANISH_BOLIVIA , wxLayout_LeftToRight, "Spanish (Bolivia)") + LNG(wxLANGUAGE_SPANISH_CHILE, "es_CL", LANG_SPANISH , SUBLANG_SPANISH_CHILE , wxLayout_LeftToRight, "Spanish (Chile)") + LNG(wxLANGUAGE_SPANISH_COLOMBIA, "es_CO", LANG_SPANISH , SUBLANG_SPANISH_COLOMBIA , wxLayout_LeftToRight, "Spanish (Colombia)") + LNG(wxLANGUAGE_SPANISH_COSTA_RICA, "es_CR", LANG_SPANISH , SUBLANG_SPANISH_COSTA_RICA , wxLayout_LeftToRight, "Spanish (Costa Rica)") + LNG(wxLANGUAGE_SPANISH_DOMINICAN_REPUBLIC, "es_DO", LANG_SPANISH , SUBLANG_SPANISH_DOMINICAN_REPUBLIC, wxLayout_LeftToRight, "Spanish (Dominican republic)") + LNG(wxLANGUAGE_SPANISH_ECUADOR, "es_EC", LANG_SPANISH , SUBLANG_SPANISH_ECUADOR , wxLayout_LeftToRight, "Spanish (Ecuador)") + LNG(wxLANGUAGE_SPANISH_EL_SALVADOR, "es_SV", LANG_SPANISH , SUBLANG_SPANISH_EL_SALVADOR , wxLayout_LeftToRight, "Spanish (El Salvador)") + LNG(wxLANGUAGE_SPANISH_GUATEMALA, "es_GT", LANG_SPANISH , SUBLANG_SPANISH_GUATEMALA , wxLayout_LeftToRight, "Spanish (Guatemala)") + LNG(wxLANGUAGE_SPANISH_HONDURAS, "es_HN", LANG_SPANISH , SUBLANG_SPANISH_HONDURAS , wxLayout_LeftToRight, "Spanish (Honduras)") + LNG(wxLANGUAGE_SPANISH_MEXICAN, "es_MX", LANG_SPANISH , SUBLANG_SPANISH_MEXICAN , wxLayout_LeftToRight, "Spanish (Mexican)") + LNG(wxLANGUAGE_SPANISH_MODERN, "es_ES", LANG_SPANISH , SUBLANG_SPANISH_MODERN , wxLayout_LeftToRight, "Spanish (Modern)") + LNG(wxLANGUAGE_SPANISH_NICARAGUA, "es_NI", LANG_SPANISH , SUBLANG_SPANISH_NICARAGUA , wxLayout_LeftToRight, "Spanish (Nicaragua)") + LNG(wxLANGUAGE_SPANISH_PANAMA, "es_PA", LANG_SPANISH , SUBLANG_SPANISH_PANAMA , wxLayout_LeftToRight, "Spanish (Panama)") + LNG(wxLANGUAGE_SPANISH_PARAGUAY, "es_PY", LANG_SPANISH , SUBLANG_SPANISH_PARAGUAY , wxLayout_LeftToRight, "Spanish (Paraguay)") + LNG(wxLANGUAGE_SPANISH_PERU, "es_PE", LANG_SPANISH , SUBLANG_SPANISH_PERU , wxLayout_LeftToRight, "Spanish (Peru)") + LNG(wxLANGUAGE_SPANISH_PUERTO_RICO, "es_PR", LANG_SPANISH , SUBLANG_SPANISH_PUERTO_RICO , wxLayout_LeftToRight, "Spanish (Puerto Rico)") + LNG(wxLANGUAGE_SPANISH_URUGUAY, "es_UY", LANG_SPANISH , SUBLANG_SPANISH_URUGUAY , wxLayout_LeftToRight, "Spanish (Uruguay)") + LNG(wxLANGUAGE_SPANISH_US, "es_US", 0 , 0 , wxLayout_LeftToRight, "Spanish (U.S.)") + LNG(wxLANGUAGE_SPANISH_VENEZUELA, "es_VE", LANG_SPANISH , SUBLANG_SPANISH_VENEZUELA , wxLayout_LeftToRight, "Spanish (Venezuela)") + LNG(wxLANGUAGE_SUNDANESE, "su" , 0 , 0 , wxLayout_LeftToRight, "Sundanese") + LNG(wxLANGUAGE_SWAHILI, "sw_KE", LANG_SWAHILI , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Swahili") + LNG(wxLANGUAGE_SWEDISH, "sv_SE", LANG_SWEDISH , SUBLANG_SWEDISH , wxLayout_LeftToRight, "Swedish") + LNG(wxLANGUAGE_SWEDISH_FINLAND, "sv_FI", LANG_SWEDISH , SUBLANG_SWEDISH_FINLAND , wxLayout_LeftToRight, "Swedish (Finland)") + LNG(wxLANGUAGE_TAGALOG, "tl_PH", 0 , 0 , wxLayout_LeftToRight, "Tagalog") + LNG(wxLANGUAGE_TAJIK, "tg" , 0 , 0 , wxLayout_LeftToRight, "Tajik") + LNG(wxLANGUAGE_TAMIL, "ta" , LANG_TAMIL , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Tamil") + LNG(wxLANGUAGE_TATAR, "tt" , LANG_TATAR , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Tatar") + LNG(wxLANGUAGE_TELUGU, "te" , LANG_TELUGU , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Telugu") + LNG(wxLANGUAGE_THAI, "th_TH", LANG_THAI , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Thai") + LNG(wxLANGUAGE_TIBETAN, "bo" , 0 , 0 , wxLayout_LeftToRight, "Tibetan") + LNG(wxLANGUAGE_TIGRINYA, "ti" , 0 , 0 , wxLayout_LeftToRight, "Tigrinya") + LNG(wxLANGUAGE_TONGA, "to" , 0 , 0 , wxLayout_LeftToRight, "Tonga") + LNG(wxLANGUAGE_TSONGA, "ts" , 0 , 0 , wxLayout_LeftToRight, "Tsonga") + LNG(wxLANGUAGE_TURKISH, "tr_TR", LANG_TURKISH , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Turkish") + LNG(wxLANGUAGE_TURKMEN, "tk" , 0 , 0 , wxLayout_LeftToRight, "Turkmen") + LNG(wxLANGUAGE_TWI, "tw" , 0 , 0 , wxLayout_LeftToRight, "Twi") + LNG(wxLANGUAGE_UIGHUR, "ug" , 0 , 0 , wxLayout_LeftToRight, "Uighur") + LNG(wxLANGUAGE_UKRAINIAN, "uk_UA", LANG_UKRAINIAN , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Ukrainian") + LNG(wxLANGUAGE_URDU, "ur" , LANG_URDU , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Urdu") + LNG(wxLANGUAGE_URDU_INDIA, "ur_IN", LANG_URDU , SUBLANG_URDU_INDIA , wxLayout_LeftToRight, "Urdu (India)") + LNG(wxLANGUAGE_URDU_PAKISTAN, "ur_PK", LANG_URDU , SUBLANG_URDU_PAKISTAN , wxLayout_LeftToRight, "Urdu (Pakistan)") + LNG(wxLANGUAGE_UZBEK, "uz" , LANG_UZBEK , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Uzbek") + LNG(wxLANGUAGE_UZBEK_CYRILLIC, "uz" , LANG_UZBEK , SUBLANG_UZBEK_CYRILLIC , wxLayout_LeftToRight, "Uzbek (Cyrillic)") + LNG(wxLANGUAGE_UZBEK_LATIN, "uz" , LANG_UZBEK , SUBLANG_UZBEK_LATIN , wxLayout_LeftToRight, "Uzbek (Latin)") + LNG(wxLANGUAGE_VALENCIAN, "ca_ES@valencia", LANG_VALENCIAN , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Valencian") + LNG(wxLANGUAGE_VIETNAMESE, "vi_VN", LANG_VIETNAMESE, SUBLANG_DEFAULT , wxLayout_LeftToRight, "Vietnamese") + LNG(wxLANGUAGE_VOLAPUK, "vo" , 0 , 0 , wxLayout_LeftToRight, "Volapuk") + LNG(wxLANGUAGE_WELSH, "cy" , 0 , 0 , wxLayout_LeftToRight, "Welsh") + LNG(wxLANGUAGE_WOLOF, "wo" , 0 , 0 , wxLayout_LeftToRight, "Wolof") + LNG(wxLANGUAGE_XHOSA, "xh" , 0 , 0 , wxLayout_LeftToRight, "Xhosa") + LNG(wxLANGUAGE_YIDDISH, "yi" , 0 , 0 , wxLayout_LeftToRight, "Yiddish") + LNG(wxLANGUAGE_YORUBA, "yo" , 0 , 0 , wxLayout_LeftToRight, "Yoruba") + LNG(wxLANGUAGE_ZHUANG, "za" , 0 , 0 , wxLayout_LeftToRight, "Zhuang") + LNG(wxLANGUAGE_ZULU, "zu" , 0 , 0 , wxLayout_LeftToRight, "Zulu") +} +#undef LNG + +// --- --- --- generated code ends here --- --- --- + +#endif // wxUSE_INTL diff --git a/Externals/wxWidgets/src/common/ipcbase.cpp b/Externals/wxWidgets/src/common/ipcbase.cpp index 212ed50945..da6cfa249b 100644 --- a/Externals/wxWidgets/src/common/ipcbase.cpp +++ b/Externals/wxWidgets/src/common/ipcbase.cpp @@ -1,88 +1,88 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/ipcbase.cpp -// Purpose: IPC base classes -// Author: Julian Smart -// Modified by: -// Created: 04/01/98 -// RCS-ID: $Id: ipcbase.cpp 38787 2006-04-18 07:24:35Z ABX $ -// Copyright: (c) Julian Smart -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#ifndef WX_PRECOMP -#endif - -#include "wx/ipcbase.h" - -IMPLEMENT_CLASS(wxServerBase, wxObject) -IMPLEMENT_CLASS(wxClientBase, wxObject) -IMPLEMENT_CLASS(wxConnectionBase, wxObject) - -wxConnectionBase::wxConnectionBase(wxChar *buffer, int bytes) - : m_connected(true), - m_buffer(buffer), - m_buffersize(bytes), - m_deletebufferwhendone(false) -{ - if ( buffer == (wxChar *)NULL ) - { // behave like next constructor - m_buffersize = 0; - m_deletebufferwhendone = true; - } -} - -wxConnectionBase::wxConnectionBase() - : m_connected(true), - m_buffer(NULL), - m_buffersize(0), - m_deletebufferwhendone(true) -{ -} - -wxConnectionBase::wxConnectionBase(const wxConnectionBase& copy) - : wxObject(), - m_connected(copy.m_connected), - m_buffer(copy.m_buffer), - m_buffersize(copy.m_buffersize), - m_deletebufferwhendone(false) - -{ - // copy constructor would require ref-counted pointer to buffer - wxFAIL_MSG( _T("Copy constructor of wxConnectionBase not implemented") ); -} - - -wxConnectionBase::~wxConnectionBase(void) -{ - if ( m_deletebufferwhendone && m_buffer ) - delete m_buffer; -} - -wxChar *wxConnectionBase::GetBufferAtLeast( size_t bytes ) -{ - if ( m_buffersize >= bytes ) - return m_buffer; - else - { // need to resize buffer - if ( m_deletebufferwhendone ) - { // we're in charge of buffer, increase it - if ( m_buffer ) - delete m_buffer; - // the argument specifies **byte size**, but m_buffer is of type - // wxChar. Under unicode: sizeof(wxChar) > 1, so the buffer size is - // bytes / sizeof(wxChar) rounded upwards. - m_buffer = new wxChar[(bytes + sizeof(wxChar) - 1) / sizeof(wxChar)]; - m_buffersize = bytes; - return m_buffer; - } // user-supplied buffer, fail - else - return NULL; - } -} +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/ipcbase.cpp +// Purpose: IPC base classes +// Author: Julian Smart +// Modified by: +// Created: 04/01/98 +// RCS-ID: $Id: ipcbase.cpp 38787 2006-04-18 07:24:35Z ABX $ +// Copyright: (c) Julian Smart +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#ifndef WX_PRECOMP +#endif + +#include "wx/ipcbase.h" + +IMPLEMENT_CLASS(wxServerBase, wxObject) +IMPLEMENT_CLASS(wxClientBase, wxObject) +IMPLEMENT_CLASS(wxConnectionBase, wxObject) + +wxConnectionBase::wxConnectionBase(wxChar *buffer, int bytes) + : m_connected(true), + m_buffer(buffer), + m_buffersize(bytes), + m_deletebufferwhendone(false) +{ + if ( buffer == (wxChar *)NULL ) + { // behave like next constructor + m_buffersize = 0; + m_deletebufferwhendone = true; + } +} + +wxConnectionBase::wxConnectionBase() + : m_connected(true), + m_buffer(NULL), + m_buffersize(0), + m_deletebufferwhendone(true) +{ +} + +wxConnectionBase::wxConnectionBase(const wxConnectionBase& copy) + : wxObject(), + m_connected(copy.m_connected), + m_buffer(copy.m_buffer), + m_buffersize(copy.m_buffersize), + m_deletebufferwhendone(false) + +{ + // copy constructor would require ref-counted pointer to buffer + wxFAIL_MSG( _T("Copy constructor of wxConnectionBase not implemented") ); +} + + +wxConnectionBase::~wxConnectionBase(void) +{ + if ( m_deletebufferwhendone && m_buffer ) + delete m_buffer; +} + +wxChar *wxConnectionBase::GetBufferAtLeast( size_t bytes ) +{ + if ( m_buffersize >= bytes ) + return m_buffer; + else + { // need to resize buffer + if ( m_deletebufferwhendone ) + { // we're in charge of buffer, increase it + if ( m_buffer ) + delete m_buffer; + // the argument specifies **byte size**, but m_buffer is of type + // wxChar. Under unicode: sizeof(wxChar) > 1, so the buffer size is + // bytes / sizeof(wxChar) rounded upwards. + m_buffer = new wxChar[(bytes + sizeof(wxChar) - 1) / sizeof(wxChar)]; + m_buffersize = bytes; + return m_buffer; + } // user-supplied buffer, fail + else + return NULL; + } +} diff --git a/Externals/wxWidgets/src/common/layout.cpp b/Externals/wxWidgets/src/common/layout.cpp index 9df71dce75..d796eee1f7 100644 --- a/Externals/wxWidgets/src/common/layout.cpp +++ b/Externals/wxWidgets/src/common/layout.cpp @@ -1,1026 +1,1026 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/layout.cpp -// Purpose: Constraint layout system classes -// Author: Julian Smart -// Modified by: -// Created: 04/01/98 -// RCS-ID: $Id: layout.cpp 39627 2006-06-08 06:57:39Z ABX $ -// Copyright: (c) Julian Smart -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// ============================================================================= -// declarations -// ============================================================================= - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_CONSTRAINTS - -#include "wx/layout.h" - -#ifndef WX_PRECOMP - #include "wx/window.h" - #include "wx/utils.h" - #include "wx/dialog.h" - #include "wx/msgdlg.h" - #include "wx/intl.h" -#endif - - -IMPLEMENT_DYNAMIC_CLASS(wxIndividualLayoutConstraint, wxObject) -IMPLEMENT_DYNAMIC_CLASS(wxLayoutConstraints, wxObject) - - -inline void wxGetAsIs(wxWindowBase* win, int* w, int* h) -{ -#if 1 - // The old way. Works for me. - win->GetSize(w, h); -#endif - -#if 0 - // Vadim's change. Breaks wxPython's LayoutAnchors - win->GetBestSize(w, h); -#endif - -#if 0 - // Proposed compromise. Doesn't work. - int sw, sh, bw, bh; - win->GetSize(&sw, &sh); - win->GetBestSize(&bw, &bh); - if (w) - *w = wxMax(sw, bw); - if (h) - *h = wxMax(sh, bh); -#endif -} - - -wxIndividualLayoutConstraint::wxIndividualLayoutConstraint() -{ - myEdge = wxTop; - relationship = wxUnconstrained; - margin = 0; - value = 0; - percent = 0; - otherEdge = wxTop; - done = false; - otherWin = (wxWindowBase *) NULL; -} - -void wxIndividualLayoutConstraint::Set(wxRelationship rel, wxWindowBase *otherW, wxEdge otherE, int val, int marg) -{ - if (rel == wxSameAs) - { - // If Set is called by the user with wxSameAs then call SameAs to do - // it since it will actually use wxPercent instead. - SameAs(otherW, otherE, marg); - return; - } - - relationship = rel; - otherWin = otherW; - otherEdge = otherE; - - if ( rel == wxPercentOf ) - { - percent = val; - } - else - { - value = val; - } - - margin = marg; -} - -void wxIndividualLayoutConstraint::LeftOf(wxWindowBase *sibling, int marg) -{ - Set(wxLeftOf, sibling, wxLeft, 0, marg); -} - -void wxIndividualLayoutConstraint::RightOf(wxWindowBase *sibling, int marg) -{ - Set(wxRightOf, sibling, wxRight, 0, marg); -} - -void wxIndividualLayoutConstraint::Above(wxWindowBase *sibling, int marg) -{ - Set(wxAbove, sibling, wxTop, 0, marg); -} - -void wxIndividualLayoutConstraint::Below(wxWindowBase *sibling, int marg) -{ - Set(wxBelow, sibling, wxBottom, 0, marg); -} - -// -// 'Same edge' alignment -// -void wxIndividualLayoutConstraint::SameAs(wxWindowBase *otherW, wxEdge edge, int marg) -{ - Set(wxPercentOf, otherW, edge, 100, marg); -} - -// The edge is a percentage of the other window's edge -void wxIndividualLayoutConstraint::PercentOf(wxWindowBase *otherW, wxEdge wh, int per) -{ - Set(wxPercentOf, otherW, wh, per); -} - -// -// Edge has absolute value -// -void wxIndividualLayoutConstraint::Absolute(int val) -{ - value = val; - relationship = wxAbsolute; -} - -// Reset constraint if it mentions otherWin -bool wxIndividualLayoutConstraint::ResetIfWin(wxWindowBase *otherW) -{ - if (otherW == otherWin) - { - myEdge = wxTop; - relationship = wxAsIs; - margin = 0; - value = 0; - percent = 0; - otherEdge = wxTop; - otherWin = (wxWindowBase *) NULL; - return true; - } - - return false; -} - -// Try to satisfy constraint -bool wxIndividualLayoutConstraint::SatisfyConstraint(wxLayoutConstraints *constraints, wxWindowBase *win) -{ - if (relationship == wxAbsolute) - { - done = true; - return true; - } - - switch (myEdge) - { - case wxLeft: - { - switch (relationship) - { - case wxLeftOf: - { - // We can know this edge if: otherWin is win's - // parent, or otherWin has a satisfied constraint, - // or otherWin has no constraint. - int edgePos = GetEdge(otherEdge, win, otherWin); - if (edgePos != -1) - { - value = edgePos - margin; - done = true; - return true; - } - else - return false; - } - case wxRightOf: - { - int edgePos = GetEdge(otherEdge, win, otherWin); - if (edgePos != -1) - { - value = edgePos + margin; - done = true; - return true; - } - else - return false; - } - case wxPercentOf: - { - int edgePos = GetEdge(otherEdge, win, otherWin); - if (edgePos != -1) - { - value = (int)(edgePos*(((float)percent)*0.01) + margin); - done = true; - return true; - } - else - return false; - } - case wxUnconstrained: - { - // We know the left-hand edge position if we know - // the right-hand edge and we know the width; OR if - // we know the centre and the width. - if (constraints->right.GetDone() && constraints->width.GetDone()) - { - value = (constraints->right.GetValue() - constraints->width.GetValue() + margin); - done = true; - return true; - } - else if (constraints->centreX.GetDone() && constraints->width.GetDone()) - { - value = (int)(constraints->centreX.GetValue() - (constraints->width.GetValue()/2) + margin); - done = true; - return true; - } - else - return false; - } - case wxAsIs: - { - int y; - win->GetPosition(&value, &y); - done = true; - return true; - } - default: - break; - } - break; - } - case wxRight: - { - switch (relationship) - { - case wxLeftOf: - { - // We can know this edge if: otherWin is win's - // parent, or otherWin has a satisfied constraint, - // or otherWin has no constraint. - int edgePos = GetEdge(otherEdge, win, otherWin); - if (edgePos != -1) - { - value = edgePos - margin; - done = true; - return true; - } - else - return false; - } - case wxRightOf: - { - int edgePos = GetEdge(otherEdge, win, otherWin); - if (edgePos != -1) - { - value = edgePos + margin; - done = true; - return true; - } - else - return false; - } - case wxPercentOf: - { - int edgePos = GetEdge(otherEdge, win, otherWin); - if (edgePos != -1) - { - value = (int)(edgePos*(((float)percent)*0.01) - margin); - done = true; - return true; - } - else - return false; - } - case wxUnconstrained: - { - // We know the right-hand edge position if we know the - // left-hand edge and we know the width, OR if we know the - // centre edge and the width. - if (constraints->left.GetDone() && constraints->width.GetDone()) - { - value = (constraints->left.GetValue() + constraints->width.GetValue() - margin); - done = true; - return true; - } - else if (constraints->centreX.GetDone() && constraints->width.GetDone()) - { - value = (int)(constraints->centreX.GetValue() + (constraints->width.GetValue()/2) - margin); - done = true; - return true; - } - else - return false; - } - case wxAsIs: - { - int x, y; - int w, h; - wxGetAsIs(win, &w, &h); - win->GetPosition(&x, &y); - value = x + w; - done = true; - return true; - } - default: - break; - } - break; - } - case wxTop: - { - switch (relationship) - { - case wxAbove: - { - // We can know this edge if: otherWin is win's - // parent, or otherWin has a satisfied constraint, - // or otherWin has no constraint. - int edgePos = GetEdge(otherEdge, win, otherWin); - if (edgePos != -1) - { - value = edgePos - margin; - done = true; - return true; - } - else - return false; - } - case wxBelow: - { - int edgePos = GetEdge(otherEdge, win, otherWin); - if (edgePos != -1) - { - value = edgePos + margin; - done = true; - return true; - } - else - return false; - } - case wxPercentOf: - { - int edgePos = GetEdge(otherEdge, win, otherWin); - if (edgePos != -1) - { - value = (int)(edgePos*(((float)percent)*0.01) + margin); - done = true; - return true; - } - else - return false; - } - case wxUnconstrained: - { - // We know the top edge position if we know the bottom edge - // and we know the height; OR if we know the centre edge and - // the height. - if (constraints->bottom.GetDone() && constraints->height.GetDone()) - { - value = (constraints->bottom.GetValue() - constraints->height.GetValue() + margin); - done = true; - return true; - } - else if (constraints->centreY.GetDone() && constraints->height.GetDone()) - { - value = (constraints->centreY.GetValue() - (constraints->height.GetValue()/2) + margin); - done = true; - return true; - } - else - return false; - } - case wxAsIs: - { - int x; - win->GetPosition(&x, &value); - done = true; - return true; - } - default: - break; - } - break; - } - case wxBottom: - { - switch (relationship) - { - case wxAbove: - { - // We can know this edge if: otherWin is win's parent, - // or otherWin has a satisfied constraint, or - // otherWin has no constraint. - int edgePos = GetEdge(otherEdge, win, otherWin); - if (edgePos != -1) - { - value = edgePos + margin; - done = true; - return true; - } - else - return false; - } - case wxBelow: - { - int edgePos = GetEdge(otherEdge, win, otherWin); - if (edgePos != -1) - { - value = edgePos - margin; - done = true; - return true; - } - else - return false; - } - case wxPercentOf: - { - int edgePos = GetEdge(otherEdge, win, otherWin); - if (edgePos != -1) - { - value = (int)(edgePos*(((float)percent)*0.01) - margin); - done = true; - return true; - } - else - return false; - } - case wxUnconstrained: - { - // We know the bottom edge position if we know the top edge - // and we know the height; OR if we know the centre edge and - // the height. - if (constraints->top.GetDone() && constraints->height.GetDone()) - { - value = (constraints->top.GetValue() + constraints->height.GetValue() - margin); - done = true; - return true; - } - else if (constraints->centreY.GetDone() && constraints->height.GetDone()) - { - value = (constraints->centreY.GetValue() + (constraints->height.GetValue()/2) - margin); - done = true; - return true; - } - else - return false; - } - case wxAsIs: - { - int x, y; - int w, h; - wxGetAsIs(win, &w, &h); - win->GetPosition(&x, &y); - value = h + y; - done = true; - return true; - } - default: - break; - } - break; - } - case wxCentreX: - { - switch (relationship) - { - case wxLeftOf: - { - // We can know this edge if: otherWin is win's parent, or - // otherWin has a satisfied constraint, or otherWin has no - // constraint. - int edgePos = GetEdge(otherEdge, win, otherWin); - if (edgePos != -1) - { - value = edgePos - margin; - done = true; - return true; - } - else - return false; - } - case wxRightOf: - { - int edgePos = GetEdge(otherEdge, win, otherWin); - if (edgePos != -1) - { - value = edgePos + margin; - done = true; - return true; - } - else - return false; - } - case wxPercentOf: - { - int edgePos = GetEdge(otherEdge, win, otherWin); - if (edgePos != -1) - { - value = (int)(edgePos*(((float)percent)*0.01) + margin); - done = true; - return true; - } - else - return false; - } - case wxUnconstrained: - { - // We know the centre position if we know - // the left-hand edge and we know the width, OR - // the right-hand edge and the width - if (constraints->left.GetDone() && constraints->width.GetDone()) - { - value = (int)(constraints->left.GetValue() + (constraints->width.GetValue()/2) + margin); - done = true; - return true; - } - else if (constraints->right.GetDone() && constraints->width.GetDone()) - { - value = (int)(constraints->left.GetValue() - (constraints->width.GetValue()/2) + margin); - done = true; - return true; - } - else - return false; - } - default: - break; - } - break; - } - case wxCentreY: - { - switch (relationship) - { - case wxAbove: - { - // We can know this edge if: otherWin is win's parent, - // or otherWin has a satisfied constraint, or otherWin - // has no constraint. - int edgePos = GetEdge(otherEdge, win, otherWin); - if (edgePos != -1) - { - value = edgePos - margin; - done = true; - return true; - } - else - return false; - } - case wxBelow: - { - int edgePos = GetEdge(otherEdge, win, otherWin); - if (edgePos != -1) - { - value = edgePos + margin; - done = true; - return true; - } - else - return false; - } - case wxPercentOf: - { - int edgePos = GetEdge(otherEdge, win, otherWin); - if (edgePos != -1) - { - value = (int)(edgePos*(((float)percent)*0.01) + margin); - done = true; - return true; - } - else - return false; - } - case wxUnconstrained: - { - // We know the centre position if we know - // the top edge and we know the height, OR - // the bottom edge and the height. - if (constraints->bottom.GetDone() && constraints->height.GetDone()) - { - value = (int)(constraints->bottom.GetValue() - (constraints->height.GetValue()/2) + margin); - done = true; - return true; - } - else if (constraints->top.GetDone() && constraints->height.GetDone()) - { - value = (int)(constraints->top.GetValue() + (constraints->height.GetValue()/2) + margin); - done = true; - return true; - } - else - return false; - } - default: - break; - } - break; - } - case wxWidth: - { - switch (relationship) - { - case wxPercentOf: - { - int edgePos = GetEdge(otherEdge, win, otherWin); - if (edgePos != -1) - { - value = (int)(edgePos*(((float)percent)*0.01)); - done = true; - return true; - } - else - return false; - } - case wxAsIs: - { - if (win) - { - int h; - wxGetAsIs(win, &value, &h); - done = true; - return true; - } - else return false; - } - case wxUnconstrained: - { - // We know the width if we know the left edge and the right edge, OR - // if we know the left edge and the centre, OR - // if we know the right edge and the centre - if (constraints->left.GetDone() && constraints->right.GetDone()) - { - value = constraints->right.GetValue() - constraints->left.GetValue(); - done = true; - return true; - } - else if (constraints->centreX.GetDone() && constraints->left.GetDone()) - { - value = (int)(2*(constraints->centreX.GetValue() - constraints->left.GetValue())); - done = true; - return true; - } - else if (constraints->centreX.GetDone() && constraints->right.GetDone()) - { - value = (int)(2*(constraints->right.GetValue() - constraints->centreX.GetValue())); - done = true; - return true; - } - else - return false; - } - default: - break; - } - break; - } - case wxHeight: - { - switch (relationship) - { - case wxPercentOf: - { - int edgePos = GetEdge(otherEdge, win, otherWin); - if (edgePos != -1) - { - value = (int)(edgePos*(((float)percent)*0.01)); - done = true; - return true; - } - else - return false; - } - case wxAsIs: - { - if (win) - { - int w; - wxGetAsIs(win, &w, &value); - done = true; - return true; - } - else return false; - } - case wxUnconstrained: - { - // We know the height if we know the top edge and the bottom edge, OR - // if we know the top edge and the centre, OR - // if we know the bottom edge and the centre - if (constraints->top.GetDone() && constraints->bottom.GetDone()) - { - value = constraints->bottom.GetValue() - constraints->top.GetValue(); - done = true; - return true; - } - else if (constraints->top.GetDone() && constraints->centreY.GetDone()) - { - value = (int)(2*(constraints->centreY.GetValue() - constraints->top.GetValue())); - done = true; - return true; - } - else if (constraints->bottom.GetDone() && constraints->centreY.GetDone()) - { - value = (int)(2*(constraints->bottom.GetValue() - constraints->centreY.GetValue())); - done = true; - return true; - } - else - return false; - } - default: - break; - } - break; - } - default: - break; - } - return false; -} - -// Get the value of this edge or dimension, or if this is not determinable, -1. -int wxIndividualLayoutConstraint::GetEdge(wxEdge which, - wxWindowBase *thisWin, - wxWindowBase *other) const -{ - // If the edge or dimension belongs to the parent, then we know the - // dimension is obtainable immediately. E.g. a wxExpandSizer may contain a - // button (but the button's true parent is a panel, not the sizer) - if (other->GetChildren().Find((wxWindow*)thisWin)) - { - switch (which) - { - case wxLeft: - { - return 0; - } - case wxTop: - { - return 0; - } - case wxRight: - { - int w, h; - other->GetClientSizeConstraint(&w, &h); - return w; - } - case wxBottom: - { - int w, h; - other->GetClientSizeConstraint(&w, &h); - return h; - } - case wxWidth: - { - int w, h; - other->GetClientSizeConstraint(&w, &h); - return w; - } - case wxHeight: - { - int w, h; - other->GetClientSizeConstraint(&w, &h); - return h; - } - case wxCentreX: - case wxCentreY: - { - int w, h; - other->GetClientSizeConstraint(&w, &h); - if (which == wxCentreX) - return (int)(w/2); - else - return (int)(h/2); - } - default: - return -1; - } - } - switch (which) - { - case wxLeft: - { - wxLayoutConstraints *constr = other->GetConstraints(); - // If no constraints, it means the window is not dependent - // on anything, and therefore we know its value immediately - if (constr) - { - if (constr->left.GetDone()) - return constr->left.GetValue(); - else - return -1; - } - else - { - int x, y; - other->GetPosition(&x, &y); - return x; - } - } - case wxTop: - { - wxLayoutConstraints *constr = other->GetConstraints(); - // If no constraints, it means the window is not dependent - // on anything, and therefore we know its value immediately - if (constr) - { - if (constr->top.GetDone()) - return constr->top.GetValue(); - else - return -1; - } - else - { - int x, y; - other->GetPosition(&x, &y); - return y; - } - } - case wxRight: - { - wxLayoutConstraints *constr = other->GetConstraints(); - // If no constraints, it means the window is not dependent - // on anything, and therefore we know its value immediately - if (constr) - { - if (constr->right.GetDone()) - return constr->right.GetValue(); - else - return -1; - } - else - { - int x, y, w, h; - other->GetPosition(&x, &y); - other->GetSize(&w, &h); - return (int)(x + w); - } - } - case wxBottom: - { - wxLayoutConstraints *constr = other->GetConstraints(); - // If no constraints, it means the window is not dependent - // on anything, and therefore we know its value immediately - if (constr) - { - if (constr->bottom.GetDone()) - return constr->bottom.GetValue(); - else - return -1; - } - else - { - int x, y, w, h; - other->GetPosition(&x, &y); - other->GetSize(&w, &h); - return (int)(y + h); - } - } - case wxWidth: - { - wxLayoutConstraints *constr = other->GetConstraints(); - // If no constraints, it means the window is not dependent - // on anything, and therefore we know its value immediately - if (constr) - { - if (constr->width.GetDone()) - return constr->width.GetValue(); - else - return -1; - } - else - { - int w, h; - other->GetSize(&w, &h); - return w; - } - } - case wxHeight: - { - wxLayoutConstraints *constr = other->GetConstraints(); - // If no constraints, it means the window is not dependent - // on anything, and therefore we know its value immediately - if (constr) - { - if (constr->height.GetDone()) - return constr->height.GetValue(); - else - return -1; - } - else - { - int w, h; - other->GetSize(&w, &h); - return h; - } - } - case wxCentreX: - { - wxLayoutConstraints *constr = other->GetConstraints(); - // If no constraints, it means the window is not dependent - // on anything, and therefore we know its value immediately - if (constr) - { - if (constr->centreX.GetDone()) - return constr->centreX.GetValue(); - else - return -1; - } - else - { - int x, y, w, h; - other->GetPosition(&x, &y); - other->GetSize(&w, &h); - return (int)(x + (w/2)); - } - } - case wxCentreY: - { - wxLayoutConstraints *constr = other->GetConstraints(); - // If no constraints, it means the window is not dependent - // on anything, and therefore we know its value immediately - if (constr) - { - if (constr->centreY.GetDone()) - return constr->centreY.GetValue(); - else - return -1; - } - else - { - int x, y, w, h; - other->GetPosition(&x, &y); - other->GetSize(&w, &h); - return (int)(y + (h/2)); - } - } - default: - break; - } - return -1; -} - -wxLayoutConstraints::wxLayoutConstraints() -{ - left.SetEdge(wxLeft); - top.SetEdge(wxTop); - right.SetEdge(wxRight); - bottom.SetEdge(wxBottom); - centreX.SetEdge(wxCentreX); - centreY.SetEdge(wxCentreY); - width.SetEdge(wxWidth); - height.SetEdge(wxHeight); -} - -bool wxLayoutConstraints::SatisfyConstraints(wxWindowBase *win, int *nChanges) -{ - int noChanges = 0; - - bool done = width.GetDone(); - bool newDone = (done ? true : width.SatisfyConstraint(this, win)); - if (newDone != done) - noChanges ++; - - done = height.GetDone(); - newDone = (done ? true : height.SatisfyConstraint(this, win)); - if (newDone != done) - noChanges ++; - - done = left.GetDone(); - newDone = (done ? true : left.SatisfyConstraint(this, win)); - if (newDone != done) - noChanges ++; - - done = top.GetDone(); - newDone = (done ? true : top.SatisfyConstraint(this, win)); - if (newDone != done) - noChanges ++; - - done = right.GetDone(); - newDone = (done ? true : right.SatisfyConstraint(this, win)); - if (newDone != done) - noChanges ++; - - done = bottom.GetDone(); - newDone = (done ? true : bottom.SatisfyConstraint(this, win)); - if (newDone != done) - noChanges ++; - - done = centreX.GetDone(); - newDone = (done ? true : centreX.SatisfyConstraint(this, win)); - if (newDone != done) - noChanges ++; - - done = centreY.GetDone(); - newDone = (done ? true : centreY.SatisfyConstraint(this, win)); - if (newDone != done) - noChanges ++; - - *nChanges = noChanges; - - return AreSatisfied(); -} - -#endif // wxUSE_CONSTRAINTS +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/layout.cpp +// Purpose: Constraint layout system classes +// Author: Julian Smart +// Modified by: +// Created: 04/01/98 +// RCS-ID: $Id: layout.cpp 39627 2006-06-08 06:57:39Z ABX $ +// Copyright: (c) Julian Smart +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================= +// declarations +// ============================================================================= + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_CONSTRAINTS + +#include "wx/layout.h" + +#ifndef WX_PRECOMP + #include "wx/window.h" + #include "wx/utils.h" + #include "wx/dialog.h" + #include "wx/msgdlg.h" + #include "wx/intl.h" +#endif + + +IMPLEMENT_DYNAMIC_CLASS(wxIndividualLayoutConstraint, wxObject) +IMPLEMENT_DYNAMIC_CLASS(wxLayoutConstraints, wxObject) + + +inline void wxGetAsIs(wxWindowBase* win, int* w, int* h) +{ +#if 1 + // The old way. Works for me. + win->GetSize(w, h); +#endif + +#if 0 + // Vadim's change. Breaks wxPython's LayoutAnchors + win->GetBestSize(w, h); +#endif + +#if 0 + // Proposed compromise. Doesn't work. + int sw, sh, bw, bh; + win->GetSize(&sw, &sh); + win->GetBestSize(&bw, &bh); + if (w) + *w = wxMax(sw, bw); + if (h) + *h = wxMax(sh, bh); +#endif +} + + +wxIndividualLayoutConstraint::wxIndividualLayoutConstraint() +{ + myEdge = wxTop; + relationship = wxUnconstrained; + margin = 0; + value = 0; + percent = 0; + otherEdge = wxTop; + done = false; + otherWin = (wxWindowBase *) NULL; +} + +void wxIndividualLayoutConstraint::Set(wxRelationship rel, wxWindowBase *otherW, wxEdge otherE, int val, int marg) +{ + if (rel == wxSameAs) + { + // If Set is called by the user with wxSameAs then call SameAs to do + // it since it will actually use wxPercent instead. + SameAs(otherW, otherE, marg); + return; + } + + relationship = rel; + otherWin = otherW; + otherEdge = otherE; + + if ( rel == wxPercentOf ) + { + percent = val; + } + else + { + value = val; + } + + margin = marg; +} + +void wxIndividualLayoutConstraint::LeftOf(wxWindowBase *sibling, int marg) +{ + Set(wxLeftOf, sibling, wxLeft, 0, marg); +} + +void wxIndividualLayoutConstraint::RightOf(wxWindowBase *sibling, int marg) +{ + Set(wxRightOf, sibling, wxRight, 0, marg); +} + +void wxIndividualLayoutConstraint::Above(wxWindowBase *sibling, int marg) +{ + Set(wxAbove, sibling, wxTop, 0, marg); +} + +void wxIndividualLayoutConstraint::Below(wxWindowBase *sibling, int marg) +{ + Set(wxBelow, sibling, wxBottom, 0, marg); +} + +// +// 'Same edge' alignment +// +void wxIndividualLayoutConstraint::SameAs(wxWindowBase *otherW, wxEdge edge, int marg) +{ + Set(wxPercentOf, otherW, edge, 100, marg); +} + +// The edge is a percentage of the other window's edge +void wxIndividualLayoutConstraint::PercentOf(wxWindowBase *otherW, wxEdge wh, int per) +{ + Set(wxPercentOf, otherW, wh, per); +} + +// +// Edge has absolute value +// +void wxIndividualLayoutConstraint::Absolute(int val) +{ + value = val; + relationship = wxAbsolute; +} + +// Reset constraint if it mentions otherWin +bool wxIndividualLayoutConstraint::ResetIfWin(wxWindowBase *otherW) +{ + if (otherW == otherWin) + { + myEdge = wxTop; + relationship = wxAsIs; + margin = 0; + value = 0; + percent = 0; + otherEdge = wxTop; + otherWin = (wxWindowBase *) NULL; + return true; + } + + return false; +} + +// Try to satisfy constraint +bool wxIndividualLayoutConstraint::SatisfyConstraint(wxLayoutConstraints *constraints, wxWindowBase *win) +{ + if (relationship == wxAbsolute) + { + done = true; + return true; + } + + switch (myEdge) + { + case wxLeft: + { + switch (relationship) + { + case wxLeftOf: + { + // We can know this edge if: otherWin is win's + // parent, or otherWin has a satisfied constraint, + // or otherWin has no constraint. + int edgePos = GetEdge(otherEdge, win, otherWin); + if (edgePos != -1) + { + value = edgePos - margin; + done = true; + return true; + } + else + return false; + } + case wxRightOf: + { + int edgePos = GetEdge(otherEdge, win, otherWin); + if (edgePos != -1) + { + value = edgePos + margin; + done = true; + return true; + } + else + return false; + } + case wxPercentOf: + { + int edgePos = GetEdge(otherEdge, win, otherWin); + if (edgePos != -1) + { + value = (int)(edgePos*(((float)percent)*0.01) + margin); + done = true; + return true; + } + else + return false; + } + case wxUnconstrained: + { + // We know the left-hand edge position if we know + // the right-hand edge and we know the width; OR if + // we know the centre and the width. + if (constraints->right.GetDone() && constraints->width.GetDone()) + { + value = (constraints->right.GetValue() - constraints->width.GetValue() + margin); + done = true; + return true; + } + else if (constraints->centreX.GetDone() && constraints->width.GetDone()) + { + value = (int)(constraints->centreX.GetValue() - (constraints->width.GetValue()/2) + margin); + done = true; + return true; + } + else + return false; + } + case wxAsIs: + { + int y; + win->GetPosition(&value, &y); + done = true; + return true; + } + default: + break; + } + break; + } + case wxRight: + { + switch (relationship) + { + case wxLeftOf: + { + // We can know this edge if: otherWin is win's + // parent, or otherWin has a satisfied constraint, + // or otherWin has no constraint. + int edgePos = GetEdge(otherEdge, win, otherWin); + if (edgePos != -1) + { + value = edgePos - margin; + done = true; + return true; + } + else + return false; + } + case wxRightOf: + { + int edgePos = GetEdge(otherEdge, win, otherWin); + if (edgePos != -1) + { + value = edgePos + margin; + done = true; + return true; + } + else + return false; + } + case wxPercentOf: + { + int edgePos = GetEdge(otherEdge, win, otherWin); + if (edgePos != -1) + { + value = (int)(edgePos*(((float)percent)*0.01) - margin); + done = true; + return true; + } + else + return false; + } + case wxUnconstrained: + { + // We know the right-hand edge position if we know the + // left-hand edge and we know the width, OR if we know the + // centre edge and the width. + if (constraints->left.GetDone() && constraints->width.GetDone()) + { + value = (constraints->left.GetValue() + constraints->width.GetValue() - margin); + done = true; + return true; + } + else if (constraints->centreX.GetDone() && constraints->width.GetDone()) + { + value = (int)(constraints->centreX.GetValue() + (constraints->width.GetValue()/2) - margin); + done = true; + return true; + } + else + return false; + } + case wxAsIs: + { + int x, y; + int w, h; + wxGetAsIs(win, &w, &h); + win->GetPosition(&x, &y); + value = x + w; + done = true; + return true; + } + default: + break; + } + break; + } + case wxTop: + { + switch (relationship) + { + case wxAbove: + { + // We can know this edge if: otherWin is win's + // parent, or otherWin has a satisfied constraint, + // or otherWin has no constraint. + int edgePos = GetEdge(otherEdge, win, otherWin); + if (edgePos != -1) + { + value = edgePos - margin; + done = true; + return true; + } + else + return false; + } + case wxBelow: + { + int edgePos = GetEdge(otherEdge, win, otherWin); + if (edgePos != -1) + { + value = edgePos + margin; + done = true; + return true; + } + else + return false; + } + case wxPercentOf: + { + int edgePos = GetEdge(otherEdge, win, otherWin); + if (edgePos != -1) + { + value = (int)(edgePos*(((float)percent)*0.01) + margin); + done = true; + return true; + } + else + return false; + } + case wxUnconstrained: + { + // We know the top edge position if we know the bottom edge + // and we know the height; OR if we know the centre edge and + // the height. + if (constraints->bottom.GetDone() && constraints->height.GetDone()) + { + value = (constraints->bottom.GetValue() - constraints->height.GetValue() + margin); + done = true; + return true; + } + else if (constraints->centreY.GetDone() && constraints->height.GetDone()) + { + value = (constraints->centreY.GetValue() - (constraints->height.GetValue()/2) + margin); + done = true; + return true; + } + else + return false; + } + case wxAsIs: + { + int x; + win->GetPosition(&x, &value); + done = true; + return true; + } + default: + break; + } + break; + } + case wxBottom: + { + switch (relationship) + { + case wxAbove: + { + // We can know this edge if: otherWin is win's parent, + // or otherWin has a satisfied constraint, or + // otherWin has no constraint. + int edgePos = GetEdge(otherEdge, win, otherWin); + if (edgePos != -1) + { + value = edgePos + margin; + done = true; + return true; + } + else + return false; + } + case wxBelow: + { + int edgePos = GetEdge(otherEdge, win, otherWin); + if (edgePos != -1) + { + value = edgePos - margin; + done = true; + return true; + } + else + return false; + } + case wxPercentOf: + { + int edgePos = GetEdge(otherEdge, win, otherWin); + if (edgePos != -1) + { + value = (int)(edgePos*(((float)percent)*0.01) - margin); + done = true; + return true; + } + else + return false; + } + case wxUnconstrained: + { + // We know the bottom edge position if we know the top edge + // and we know the height; OR if we know the centre edge and + // the height. + if (constraints->top.GetDone() && constraints->height.GetDone()) + { + value = (constraints->top.GetValue() + constraints->height.GetValue() - margin); + done = true; + return true; + } + else if (constraints->centreY.GetDone() && constraints->height.GetDone()) + { + value = (constraints->centreY.GetValue() + (constraints->height.GetValue()/2) - margin); + done = true; + return true; + } + else + return false; + } + case wxAsIs: + { + int x, y; + int w, h; + wxGetAsIs(win, &w, &h); + win->GetPosition(&x, &y); + value = h + y; + done = true; + return true; + } + default: + break; + } + break; + } + case wxCentreX: + { + switch (relationship) + { + case wxLeftOf: + { + // We can know this edge if: otherWin is win's parent, or + // otherWin has a satisfied constraint, or otherWin has no + // constraint. + int edgePos = GetEdge(otherEdge, win, otherWin); + if (edgePos != -1) + { + value = edgePos - margin; + done = true; + return true; + } + else + return false; + } + case wxRightOf: + { + int edgePos = GetEdge(otherEdge, win, otherWin); + if (edgePos != -1) + { + value = edgePos + margin; + done = true; + return true; + } + else + return false; + } + case wxPercentOf: + { + int edgePos = GetEdge(otherEdge, win, otherWin); + if (edgePos != -1) + { + value = (int)(edgePos*(((float)percent)*0.01) + margin); + done = true; + return true; + } + else + return false; + } + case wxUnconstrained: + { + // We know the centre position if we know + // the left-hand edge and we know the width, OR + // the right-hand edge and the width + if (constraints->left.GetDone() && constraints->width.GetDone()) + { + value = (int)(constraints->left.GetValue() + (constraints->width.GetValue()/2) + margin); + done = true; + return true; + } + else if (constraints->right.GetDone() && constraints->width.GetDone()) + { + value = (int)(constraints->left.GetValue() - (constraints->width.GetValue()/2) + margin); + done = true; + return true; + } + else + return false; + } + default: + break; + } + break; + } + case wxCentreY: + { + switch (relationship) + { + case wxAbove: + { + // We can know this edge if: otherWin is win's parent, + // or otherWin has a satisfied constraint, or otherWin + // has no constraint. + int edgePos = GetEdge(otherEdge, win, otherWin); + if (edgePos != -1) + { + value = edgePos - margin; + done = true; + return true; + } + else + return false; + } + case wxBelow: + { + int edgePos = GetEdge(otherEdge, win, otherWin); + if (edgePos != -1) + { + value = edgePos + margin; + done = true; + return true; + } + else + return false; + } + case wxPercentOf: + { + int edgePos = GetEdge(otherEdge, win, otherWin); + if (edgePos != -1) + { + value = (int)(edgePos*(((float)percent)*0.01) + margin); + done = true; + return true; + } + else + return false; + } + case wxUnconstrained: + { + // We know the centre position if we know + // the top edge and we know the height, OR + // the bottom edge and the height. + if (constraints->bottom.GetDone() && constraints->height.GetDone()) + { + value = (int)(constraints->bottom.GetValue() - (constraints->height.GetValue()/2) + margin); + done = true; + return true; + } + else if (constraints->top.GetDone() && constraints->height.GetDone()) + { + value = (int)(constraints->top.GetValue() + (constraints->height.GetValue()/2) + margin); + done = true; + return true; + } + else + return false; + } + default: + break; + } + break; + } + case wxWidth: + { + switch (relationship) + { + case wxPercentOf: + { + int edgePos = GetEdge(otherEdge, win, otherWin); + if (edgePos != -1) + { + value = (int)(edgePos*(((float)percent)*0.01)); + done = true; + return true; + } + else + return false; + } + case wxAsIs: + { + if (win) + { + int h; + wxGetAsIs(win, &value, &h); + done = true; + return true; + } + else return false; + } + case wxUnconstrained: + { + // We know the width if we know the left edge and the right edge, OR + // if we know the left edge and the centre, OR + // if we know the right edge and the centre + if (constraints->left.GetDone() && constraints->right.GetDone()) + { + value = constraints->right.GetValue() - constraints->left.GetValue(); + done = true; + return true; + } + else if (constraints->centreX.GetDone() && constraints->left.GetDone()) + { + value = (int)(2*(constraints->centreX.GetValue() - constraints->left.GetValue())); + done = true; + return true; + } + else if (constraints->centreX.GetDone() && constraints->right.GetDone()) + { + value = (int)(2*(constraints->right.GetValue() - constraints->centreX.GetValue())); + done = true; + return true; + } + else + return false; + } + default: + break; + } + break; + } + case wxHeight: + { + switch (relationship) + { + case wxPercentOf: + { + int edgePos = GetEdge(otherEdge, win, otherWin); + if (edgePos != -1) + { + value = (int)(edgePos*(((float)percent)*0.01)); + done = true; + return true; + } + else + return false; + } + case wxAsIs: + { + if (win) + { + int w; + wxGetAsIs(win, &w, &value); + done = true; + return true; + } + else return false; + } + case wxUnconstrained: + { + // We know the height if we know the top edge and the bottom edge, OR + // if we know the top edge and the centre, OR + // if we know the bottom edge and the centre + if (constraints->top.GetDone() && constraints->bottom.GetDone()) + { + value = constraints->bottom.GetValue() - constraints->top.GetValue(); + done = true; + return true; + } + else if (constraints->top.GetDone() && constraints->centreY.GetDone()) + { + value = (int)(2*(constraints->centreY.GetValue() - constraints->top.GetValue())); + done = true; + return true; + } + else if (constraints->bottom.GetDone() && constraints->centreY.GetDone()) + { + value = (int)(2*(constraints->bottom.GetValue() - constraints->centreY.GetValue())); + done = true; + return true; + } + else + return false; + } + default: + break; + } + break; + } + default: + break; + } + return false; +} + +// Get the value of this edge or dimension, or if this is not determinable, -1. +int wxIndividualLayoutConstraint::GetEdge(wxEdge which, + wxWindowBase *thisWin, + wxWindowBase *other) const +{ + // If the edge or dimension belongs to the parent, then we know the + // dimension is obtainable immediately. E.g. a wxExpandSizer may contain a + // button (but the button's true parent is a panel, not the sizer) + if (other->GetChildren().Find((wxWindow*)thisWin)) + { + switch (which) + { + case wxLeft: + { + return 0; + } + case wxTop: + { + return 0; + } + case wxRight: + { + int w, h; + other->GetClientSizeConstraint(&w, &h); + return w; + } + case wxBottom: + { + int w, h; + other->GetClientSizeConstraint(&w, &h); + return h; + } + case wxWidth: + { + int w, h; + other->GetClientSizeConstraint(&w, &h); + return w; + } + case wxHeight: + { + int w, h; + other->GetClientSizeConstraint(&w, &h); + return h; + } + case wxCentreX: + case wxCentreY: + { + int w, h; + other->GetClientSizeConstraint(&w, &h); + if (which == wxCentreX) + return (int)(w/2); + else + return (int)(h/2); + } + default: + return -1; + } + } + switch (which) + { + case wxLeft: + { + wxLayoutConstraints *constr = other->GetConstraints(); + // If no constraints, it means the window is not dependent + // on anything, and therefore we know its value immediately + if (constr) + { + if (constr->left.GetDone()) + return constr->left.GetValue(); + else + return -1; + } + else + { + int x, y; + other->GetPosition(&x, &y); + return x; + } + } + case wxTop: + { + wxLayoutConstraints *constr = other->GetConstraints(); + // If no constraints, it means the window is not dependent + // on anything, and therefore we know its value immediately + if (constr) + { + if (constr->top.GetDone()) + return constr->top.GetValue(); + else + return -1; + } + else + { + int x, y; + other->GetPosition(&x, &y); + return y; + } + } + case wxRight: + { + wxLayoutConstraints *constr = other->GetConstraints(); + // If no constraints, it means the window is not dependent + // on anything, and therefore we know its value immediately + if (constr) + { + if (constr->right.GetDone()) + return constr->right.GetValue(); + else + return -1; + } + else + { + int x, y, w, h; + other->GetPosition(&x, &y); + other->GetSize(&w, &h); + return (int)(x + w); + } + } + case wxBottom: + { + wxLayoutConstraints *constr = other->GetConstraints(); + // If no constraints, it means the window is not dependent + // on anything, and therefore we know its value immediately + if (constr) + { + if (constr->bottom.GetDone()) + return constr->bottom.GetValue(); + else + return -1; + } + else + { + int x, y, w, h; + other->GetPosition(&x, &y); + other->GetSize(&w, &h); + return (int)(y + h); + } + } + case wxWidth: + { + wxLayoutConstraints *constr = other->GetConstraints(); + // If no constraints, it means the window is not dependent + // on anything, and therefore we know its value immediately + if (constr) + { + if (constr->width.GetDone()) + return constr->width.GetValue(); + else + return -1; + } + else + { + int w, h; + other->GetSize(&w, &h); + return w; + } + } + case wxHeight: + { + wxLayoutConstraints *constr = other->GetConstraints(); + // If no constraints, it means the window is not dependent + // on anything, and therefore we know its value immediately + if (constr) + { + if (constr->height.GetDone()) + return constr->height.GetValue(); + else + return -1; + } + else + { + int w, h; + other->GetSize(&w, &h); + return h; + } + } + case wxCentreX: + { + wxLayoutConstraints *constr = other->GetConstraints(); + // If no constraints, it means the window is not dependent + // on anything, and therefore we know its value immediately + if (constr) + { + if (constr->centreX.GetDone()) + return constr->centreX.GetValue(); + else + return -1; + } + else + { + int x, y, w, h; + other->GetPosition(&x, &y); + other->GetSize(&w, &h); + return (int)(x + (w/2)); + } + } + case wxCentreY: + { + wxLayoutConstraints *constr = other->GetConstraints(); + // If no constraints, it means the window is not dependent + // on anything, and therefore we know its value immediately + if (constr) + { + if (constr->centreY.GetDone()) + return constr->centreY.GetValue(); + else + return -1; + } + else + { + int x, y, w, h; + other->GetPosition(&x, &y); + other->GetSize(&w, &h); + return (int)(y + (h/2)); + } + } + default: + break; + } + return -1; +} + +wxLayoutConstraints::wxLayoutConstraints() +{ + left.SetEdge(wxLeft); + top.SetEdge(wxTop); + right.SetEdge(wxRight); + bottom.SetEdge(wxBottom); + centreX.SetEdge(wxCentreX); + centreY.SetEdge(wxCentreY); + width.SetEdge(wxWidth); + height.SetEdge(wxHeight); +} + +bool wxLayoutConstraints::SatisfyConstraints(wxWindowBase *win, int *nChanges) +{ + int noChanges = 0; + + bool done = width.GetDone(); + bool newDone = (done ? true : width.SatisfyConstraint(this, win)); + if (newDone != done) + noChanges ++; + + done = height.GetDone(); + newDone = (done ? true : height.SatisfyConstraint(this, win)); + if (newDone != done) + noChanges ++; + + done = left.GetDone(); + newDone = (done ? true : left.SatisfyConstraint(this, win)); + if (newDone != done) + noChanges ++; + + done = top.GetDone(); + newDone = (done ? true : top.SatisfyConstraint(this, win)); + if (newDone != done) + noChanges ++; + + done = right.GetDone(); + newDone = (done ? true : right.SatisfyConstraint(this, win)); + if (newDone != done) + noChanges ++; + + done = bottom.GetDone(); + newDone = (done ? true : bottom.SatisfyConstraint(this, win)); + if (newDone != done) + noChanges ++; + + done = centreX.GetDone(); + newDone = (done ? true : centreX.SatisfyConstraint(this, win)); + if (newDone != done) + noChanges ++; + + done = centreY.GetDone(); + newDone = (done ? true : centreY.SatisfyConstraint(this, win)); + if (newDone != done) + noChanges ++; + + *nChanges = noChanges; + + return AreSatisfied(); +} + +#endif // wxUSE_CONSTRAINTS diff --git a/Externals/wxWidgets/src/common/lboxcmn.cpp b/Externals/wxWidgets/src/common/lboxcmn.cpp index f1787982a5..883e4858c5 100644 --- a/Externals/wxWidgets/src/common/lboxcmn.cpp +++ b/Externals/wxWidgets/src/common/lboxcmn.cpp @@ -1,147 +1,147 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: src/common/lboxcmn.cpp -// Purpose: wxListBox class methods common to all platforms -// Author: Vadim Zeitlin -// Modified by: -// Created: 22.10.99 -// RCS-ID: $Id: lboxcmn.cpp 39964 2006-07-04 00:31:52Z VZ $ -// Copyright: (c) wxWidgets team -// Licence: wxWindows licence -/////////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_LISTBOX - -#include "wx/listbox.h" - -#ifndef WX_PRECOMP - #include "wx/dynarray.h" - #include "wx/arrstr.h" -#endif - -// ============================================================================ -// implementation -// ============================================================================ - -wxListBoxBase::~wxListBoxBase() -{ - // this destructor is required for Darwin -} - -// ---------------------------------------------------------------------------- -// adding items -// ---------------------------------------------------------------------------- - -void wxListBoxBase::InsertItems(unsigned int nItems, const wxString *items, unsigned int pos) -{ - wxArrayString aItems; - for ( unsigned int n = 0; n < nItems; n++ ) - { - aItems.Add(items[n]); - } - - DoInsertItems(aItems, pos); -} - - -void wxListBoxBase::Set(int nItems, const wxString* items, void **clientData) -{ - wxArrayString aItems; - for ( int n = 0; n < nItems; n++ ) - { - aItems.Add(items[n]); - } - - DoSetItems(aItems, clientData); -} - -// ---------------------------------------------------------------------------- -// selection -// ---------------------------------------------------------------------------- - -bool wxListBoxBase::SetStringSelection(const wxString& s, bool select) -{ - const int sel = FindString(s); - if ( sel == wxNOT_FOUND ) - return false; - - SetSelection(sel, select); - - return true; -} - -void wxListBoxBase::DeselectAll(int itemToLeaveSelected) -{ - if ( HasMultipleSelection() ) - { - wxArrayInt selections; - GetSelections(selections); - - size_t count = selections.GetCount(); - for ( size_t n = 0; n < count; n++ ) - { - int item = selections[n]; - if ( item != itemToLeaveSelected ) - Deselect(item); - } - } - else // single selection - { - int sel = GetSelection(); - if ( sel != wxNOT_FOUND && sel != itemToLeaveSelected ) - { - Deselect(sel); - } - } -} - -// ---------------------------------------------------------------------------- -// misc -// ---------------------------------------------------------------------------- - -void wxListBoxBase::Command(wxCommandEvent& event) -{ - SetSelection(event.GetInt(), event.GetExtraLong() != 0); - (void)ProcessEvent(event); -} - -// ---------------------------------------------------------------------------- -// SetFirstItem() and such -// ---------------------------------------------------------------------------- - -void wxListBoxBase::SetFirstItem(const wxString& s) -{ - int n = FindString(s); - - wxCHECK_RET( n != wxNOT_FOUND, wxT("invalid string in wxListBox::SetFirstItem") ); - - DoSetFirstItem(n); -} - -void wxListBoxBase::AppendAndEnsureVisible(const wxString& s) -{ - Append(s); - EnsureVisible(GetCount() - 1); -} - -void wxListBoxBase::EnsureVisible(int WXUNUSED(n)) -{ - // the base class version does nothing (the only alternative would be to - // call SetFirstItem() but this is probably even more stupid) -} - -#endif // wxUSE_LISTBOX +/////////////////////////////////////////////////////////////////////////////// +// Name: src/common/lboxcmn.cpp +// Purpose: wxListBox class methods common to all platforms +// Author: Vadim Zeitlin +// Modified by: +// Created: 22.10.99 +// RCS-ID: $Id: lboxcmn.cpp 39964 2006-07-04 00:31:52Z VZ $ +// Copyright: (c) wxWidgets team +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_LISTBOX + +#include "wx/listbox.h" + +#ifndef WX_PRECOMP + #include "wx/dynarray.h" + #include "wx/arrstr.h" +#endif + +// ============================================================================ +// implementation +// ============================================================================ + +wxListBoxBase::~wxListBoxBase() +{ + // this destructor is required for Darwin +} + +// ---------------------------------------------------------------------------- +// adding items +// ---------------------------------------------------------------------------- + +void wxListBoxBase::InsertItems(unsigned int nItems, const wxString *items, unsigned int pos) +{ + wxArrayString aItems; + for ( unsigned int n = 0; n < nItems; n++ ) + { + aItems.Add(items[n]); + } + + DoInsertItems(aItems, pos); +} + + +void wxListBoxBase::Set(int nItems, const wxString* items, void **clientData) +{ + wxArrayString aItems; + for ( int n = 0; n < nItems; n++ ) + { + aItems.Add(items[n]); + } + + DoSetItems(aItems, clientData); +} + +// ---------------------------------------------------------------------------- +// selection +// ---------------------------------------------------------------------------- + +bool wxListBoxBase::SetStringSelection(const wxString& s, bool select) +{ + const int sel = FindString(s); + if ( sel == wxNOT_FOUND ) + return false; + + SetSelection(sel, select); + + return true; +} + +void wxListBoxBase::DeselectAll(int itemToLeaveSelected) +{ + if ( HasMultipleSelection() ) + { + wxArrayInt selections; + GetSelections(selections); + + size_t count = selections.GetCount(); + for ( size_t n = 0; n < count; n++ ) + { + int item = selections[n]; + if ( item != itemToLeaveSelected ) + Deselect(item); + } + } + else // single selection + { + int sel = GetSelection(); + if ( sel != wxNOT_FOUND && sel != itemToLeaveSelected ) + { + Deselect(sel); + } + } +} + +// ---------------------------------------------------------------------------- +// misc +// ---------------------------------------------------------------------------- + +void wxListBoxBase::Command(wxCommandEvent& event) +{ + SetSelection(event.GetInt(), event.GetExtraLong() != 0); + (void)ProcessEvent(event); +} + +// ---------------------------------------------------------------------------- +// SetFirstItem() and such +// ---------------------------------------------------------------------------- + +void wxListBoxBase::SetFirstItem(const wxString& s) +{ + int n = FindString(s); + + wxCHECK_RET( n != wxNOT_FOUND, wxT("invalid string in wxListBox::SetFirstItem") ); + + DoSetFirstItem(n); +} + +void wxListBoxBase::AppendAndEnsureVisible(const wxString& s) +{ + Append(s); + EnsureVisible(GetCount() - 1); +} + +void wxListBoxBase::EnsureVisible(int WXUNUSED(n)) +{ + // the base class version does nothing (the only alternative would be to + // call SetFirstItem() but this is probably even more stupid) +} + +#endif // wxUSE_LISTBOX diff --git a/Externals/wxWidgets/src/common/list.cpp b/Externals/wxWidgets/src/common/list.cpp index 1a9f46a3aa..6074a8fddb 100644 --- a/Externals/wxWidgets/src/common/list.cpp +++ b/Externals/wxWidgets/src/common/list.cpp @@ -1,768 +1,768 @@ -//////////////////////////////////////////////////////////////////////////////// -// Name: src/common/list.cpp -// Purpose: wxList implementation -// Author: Julian Smart -// Modified by: VZ at 16/11/98: WX_DECLARE_LIST() and typesafe lists added -// Created: 04/01/98 -// RCS-ID: $Id: list.cpp 43048 2006-11-04 18:14:50Z VZ $ -// Copyright: (c) Julian Smart -// Licence: wxWindows licence -//////////////////////////////////////////////////////////////////////////////// - -// ============================================================================= -// declarations -// ============================================================================= - -// ----------------------------------------------------------------------------- -// headers -// ----------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#include -#include -#include - -#ifndef WX_PRECOMP - #include "wx/list.h" -#endif - -#if !wxUSE_STL - -// ============================================================================= -// implementation -// ============================================================================= - -// ----------------------------------------------------------------------------- -// wxListKey -// ----------------------------------------------------------------------------- -wxListKey wxDefaultListKey; - -bool wxListKey::operator==(wxListKeyValue value) const -{ - switch ( m_keyType ) - { - default: - wxFAIL_MSG(wxT("bad key type.")); - // let compiler optimize the line above away in release build - // by not putting return here... - - case wxKEY_STRING: - return wxStrcmp(m_key.string, value.string) == 0; - - case wxKEY_INTEGER: - return m_key.integer == value.integer; - } -} - -// ----------------------------------------------------------------------------- -// wxNodeBase -// ----------------------------------------------------------------------------- - -wxNodeBase::wxNodeBase(wxListBase *list, - wxNodeBase *previous, wxNodeBase *next, - void *data, const wxListKey& key) -{ - m_list = list; - m_data = data; - m_previous = previous; - m_next = next; - - switch ( key.GetKeyType() ) - { - case wxKEY_NONE: - break; - - case wxKEY_INTEGER: - m_key.integer = key.GetNumber(); - break; - - case wxKEY_STRING: - // to be free()d later - m_key.string = wxStrdup(key.GetString()); - break; - - default: - wxFAIL_MSG(wxT("invalid key type")); - } - - if ( previous ) - previous->m_next = this; - - if ( next ) - next->m_previous = this; -} - -wxNodeBase::~wxNodeBase() -{ - // handle the case when we're being deleted from the list by the user (i.e. - // not by the list itself from DeleteNode) - we must do it for - // compatibility with old code - if ( m_list != NULL ) - { - if ( m_list->m_keyType == wxKEY_STRING ) - { - free(m_key.string); - } - - m_list->DetachNode(this); - } -} - -int wxNodeBase::IndexOf() const -{ - wxCHECK_MSG( m_list, wxNOT_FOUND, wxT("node doesn't belong to a list in IndexOf")); - - // It would be more efficient to implement IndexOf() completely inside - // wxListBase (only traverse the list once), but this is probably a more - // reusable way of doing it. Can always be optimized at a later date (since - // IndexOf() resides in wxListBase as well) if efficiency is a problem. - int i; - wxNodeBase *prev = m_previous; - - for( i = 0; prev; i++ ) - { - prev = prev->m_previous; - } - - return i; -} - -// ----------------------------------------------------------------------------- -// wxListBase -// ----------------------------------------------------------------------------- - -void wxListBase::Init(wxKeyType keyType) -{ - m_nodeFirst = - m_nodeLast = (wxNodeBase *) NULL; - m_count = 0; - m_destroy = false; - m_keyType = keyType; -} - -wxListBase::wxListBase(size_t count, void *elements[]) -{ - Init(); - - for ( size_t n = 0; n < count; n++ ) - { - Append(elements[n]); - } -} - -void wxListBase::DoCopy(const wxListBase& list) -{ - wxASSERT_MSG( !list.m_destroy, - wxT("copying list which owns it's elements is a bad idea") ); - - m_destroy = list.m_destroy; - m_keyType = list.m_keyType; - m_nodeFirst = - m_nodeLast = (wxNodeBase *) NULL; - - switch (m_keyType) - { - case wxKEY_INTEGER: - { - long key; - for ( wxNodeBase *node = list.GetFirst(); node; node = node->GetNext() ) - { - key = node->GetKeyInteger(); - Append(key, node->GetData()); - } - break; - } - - case wxKEY_STRING: - { - const wxChar *key; - for ( wxNodeBase *node = list.GetFirst(); node; node = node->GetNext() ) - { - key = node->GetKeyString(); - Append(key, node->GetData()); - } - break; - } - - default: - { - for ( wxNodeBase *node = list.GetFirst(); node; node = node->GetNext() ) - { - Append(node->GetData()); - } - break; - } - } - - wxASSERT_MSG( m_count == list.m_count, _T("logic error in wxList::DoCopy") ); -} - -wxListBase::~wxListBase() -{ - wxNodeBase *each = m_nodeFirst; - while ( each != NULL ) - { - wxNodeBase *next = each->GetNext(); - DoDeleteNode(each); - each = next; - } -} - -wxNodeBase *wxListBase::AppendCommon(wxNodeBase *node) -{ - if ( !m_nodeFirst ) - { - m_nodeFirst = node; - m_nodeLast = m_nodeFirst; - } - else - { - m_nodeLast->m_next = node; - m_nodeLast = node; - } - - m_count++; - - return node; -} - -wxNodeBase *wxListBase::Append(void *object) -{ - // all objects in a keyed list should have a key - wxCHECK_MSG( m_keyType == wxKEY_NONE, (wxNodeBase *)NULL, - wxT("need a key for the object to append") ); - - // we use wxDefaultListKey even though it is the default parameter value - // because gcc under Mac OS X seems to miscompile this call otherwise - wxNodeBase *node = CreateNode(m_nodeLast, (wxNodeBase *)NULL, object, - wxDefaultListKey); - - return AppendCommon(node); -} - -wxNodeBase *wxListBase::Append(long key, void *object) -{ - wxCHECK_MSG( (m_keyType == wxKEY_INTEGER) || - (m_keyType == wxKEY_NONE && m_count == 0), - (wxNodeBase *)NULL, - wxT("can't append object with numeric key to this list") ); - - wxNodeBase *node = CreateNode(m_nodeLast, (wxNodeBase *)NULL, object, key); - return AppendCommon(node); -} - -wxNodeBase *wxListBase::Append (const wxChar *key, void *object) -{ - wxCHECK_MSG( (m_keyType == wxKEY_STRING) || - (m_keyType == wxKEY_NONE && m_count == 0), - (wxNodeBase *)NULL, - wxT("can't append object with string key to this list") ); - - wxNodeBase *node = CreateNode(m_nodeLast, (wxNodeBase *)NULL, object, key); - return AppendCommon(node); -} - -wxNodeBase *wxListBase::Insert(wxNodeBase *position, void *object) -{ - // all objects in a keyed list should have a key - wxCHECK_MSG( m_keyType == wxKEY_NONE, (wxNodeBase *)NULL, - wxT("need a key for the object to insert") ); - - wxCHECK_MSG( !position || position->m_list == this, (wxNodeBase *)NULL, - wxT("can't insert before a node from another list") ); - - // previous and next node for the node being inserted - wxNodeBase *prev, *next; - if ( position ) - { - prev = position->GetPrevious(); - next = position; - } - else - { - // inserting in the beginning of the list - prev = (wxNodeBase *)NULL; - next = m_nodeFirst; - } - - // wxDefaultListKey: see comment in Append() above - wxNodeBase *node = CreateNode(prev, next, object, wxDefaultListKey); - if ( !m_nodeFirst ) - { - m_nodeLast = node; - } - - if ( prev == NULL ) - { - m_nodeFirst = node; - } - - m_count++; - - return node; -} - -wxNodeBase *wxListBase::Item(size_t n) const -{ - for ( wxNodeBase *current = GetFirst(); current; current = current->GetNext() ) - { - if ( n-- == 0 ) - { - return current; - } - } - - wxFAIL_MSG( wxT("invalid index in wxListBase::Item") ); - - return (wxNodeBase *)NULL; -} - -wxNodeBase *wxListBase::Find(const wxListKey& key) const -{ - wxASSERT_MSG( m_keyType == key.GetKeyType(), - wxT("this list is not keyed on the type of this key") ); - - for ( wxNodeBase *current = GetFirst(); current; current = current->GetNext() ) - { - if ( key == current->m_key ) - { - return current; - } - } - - // not found - return (wxNodeBase *)NULL; -} - -wxNodeBase *wxListBase::Find(const void *object) const -{ - for ( wxNodeBase *current = GetFirst(); current; current = current->GetNext() ) - { - if ( current->GetData() == object ) - return current; - } - - // not found - return (wxNodeBase *)NULL; -} - -int wxListBase::IndexOf(void *object) const -{ - wxNodeBase *node = Find( object ); - - return node ? node->IndexOf() : wxNOT_FOUND; -} - -void wxListBase::DoDeleteNode(wxNodeBase *node) -{ - // free node's data - if ( m_keyType == wxKEY_STRING ) - { - free(node->m_key.string); - } - - if ( m_destroy ) - { - node->DeleteData(); - } - - // so that the node knows that it's being deleted by the list - node->m_list = NULL; - delete node; -} - -wxNodeBase *wxListBase::DetachNode(wxNodeBase *node) -{ - wxCHECK_MSG( node, NULL, wxT("detaching NULL wxNodeBase") ); - wxCHECK_MSG( node->m_list == this, NULL, - wxT("detaching node which is not from this list") ); - - // update the list - wxNodeBase **prevNext = node->GetPrevious() ? &node->GetPrevious()->m_next - : &m_nodeFirst; - wxNodeBase **nextPrev = node->GetNext() ? &node->GetNext()->m_previous - : &m_nodeLast; - - *prevNext = node->GetNext(); - *nextPrev = node->GetPrevious(); - - m_count--; - - // mark the node as not belonging to this list any more - node->m_list = NULL; - - return node; -} - -bool wxListBase::DeleteNode(wxNodeBase *node) -{ - if ( !DetachNode(node) ) - return false; - - DoDeleteNode(node); - - return true; -} - -bool wxListBase::DeleteObject(void *object) -{ - for ( wxNodeBase *current = GetFirst(); current; current = current->GetNext() ) - { - if ( current->GetData() == object ) - { - DeleteNode(current); - return true; - } - } - - // not found - return false; -} - -void wxListBase::Clear() -{ - wxNodeBase *current = m_nodeFirst; - while ( current ) - { - wxNodeBase *next = current->GetNext(); - DoDeleteNode(current); - current = next; - } - - m_nodeFirst = - m_nodeLast = (wxNodeBase *)NULL; - - m_count = 0; -} - -void wxListBase::ForEach(wxListIterateFunction F) -{ - for ( wxNodeBase *current = GetFirst(); current; current = current->GetNext() ) - { - (*F)(current->GetData()); - } -} - -void *wxListBase::FirstThat(wxListIterateFunction F) -{ - for ( wxNodeBase *current = GetFirst(); current; current = current->GetNext() ) - { - if ( (*F)(current->GetData()) ) - return current->GetData(); - } - - return (wxNodeBase *)NULL; -} - -void *wxListBase::LastThat(wxListIterateFunction F) -{ - for ( wxNodeBase *current = GetLast(); current; current = current->GetPrevious() ) - { - if ( (*F)(current->GetData()) ) - return current->GetData(); - } - - return (wxNodeBase *)NULL; -} - -// (stefan.hammes@urz.uni-heidelberg.de) -// -// function for sorting lists. the concept is borrowed from 'qsort'. -// by giving a sort function, arbitrary lists can be sorted. -// method: -// - put wxObject pointers into an array -// - sort the array with qsort -// - put back the sorted wxObject pointers into the list -// -// CAVE: the sort function receives pointers to wxObject pointers (wxObject **), -// so dereference right! -// EXAMPLE: -// int listcompare(const void *arg1, const void *arg2) -// { -// return(compare(**(wxString **)arg1, -// **(wxString **)arg2)); -// } -// -// void main() -// { -// wxListBase list; -// -// list.Append(new wxString("DEF")); -// list.Append(new wxString("GHI")); -// list.Append(new wxString("ABC")); -// list.Sort(listcompare); -// } - -void wxListBase::Sort(const wxSortCompareFunction compfunc) -{ - // allocate an array for the wxObject pointers of the list - const size_t num = GetCount(); - void **objArray = new void *[num]; - void **objPtr = objArray; - - // go through the list and put the pointers into the array - wxNodeBase *node; - for ( node = GetFirst(); node; node = node->GetNext() ) - { - *objPtr++ = node->GetData(); - } - - // sort the array - qsort((void *)objArray,num,sizeof(wxObject *), -#ifdef __WXWINCE__ - (int (__cdecl *)(const void *,const void *)) -#endif - compfunc); - - // put the sorted pointers back into the list - objPtr = objArray; - for ( node = GetFirst(); node; node = node->GetNext() ) - { - node->SetData(*objPtr++); - } - - // free the array - delete[] objArray; -} - -void wxListBase::Reverse() -{ - wxNodeBase* node = m_nodeFirst; - wxNodeBase* tmp; - - while (node) - { - // swap prev and next pointers - tmp = node->m_next; - node->m_next = node->m_previous; - node->m_previous = tmp; - - // this is the node that was next before swapping - node = tmp; - } - - // swap first and last node - tmp = m_nodeFirst; m_nodeFirst = m_nodeLast; m_nodeLast = tmp; -} - -void wxListBase::DeleteNodes(wxNodeBase* first, wxNodeBase* last) -{ - wxNodeBase* node = first; - - while (node != last) - { - wxNodeBase* next = node->GetNext(); - DeleteNode(node); - node = next; - } -} - -// ============================================================================ -// compatibility section from now on -// ============================================================================ - -#ifdef wxLIST_COMPATIBILITY - -// ----------------------------------------------------------------------------- -// wxList (a.k.a. wxObjectList) -// ----------------------------------------------------------------------------- - -IMPLEMENT_DYNAMIC_CLASS(wxList, wxObject) - -wxList::wxList( int key_type ) - : wxObjectList( (wxKeyType)key_type ) -{ -} - -void wxObjectListNode::DeleteData() -{ - delete (wxObject *)GetData(); -} - -// ---------------------------------------------------------------------------- -// wxStringList -// ---------------------------------------------------------------------------- - -static inline wxChar* MYcopystring(const wxChar* s) -{ - wxChar* copy = new wxChar[wxStrlen(s) + 1]; - return wxStrcpy(copy, s); -} - -IMPLEMENT_DYNAMIC_CLASS(wxStringList, wxObject) - -// instead of WX_DEFINE_LIST(wxStringListBase) we define this function -// ourselves -void wxStringListNode::DeleteData() -{ - delete [] (char *)GetData(); -} - -bool wxStringList::Delete(const wxChar *s) -{ - wxStringListNode *current; - - for ( current = GetFirst(); current; current = current->GetNext() ) - { - if ( wxStrcmp(current->GetData(), s) == 0 ) - { - DeleteNode(current); - return true; - } - } - - // not found - return false; -} - -void wxStringList::DoCopy(const wxStringList& other) -{ - wxASSERT( GetCount() == 0 ); // this list must be empty before copying! - - size_t count = other.GetCount(); - for ( size_t n = 0; n < count; n++ ) - { - Add(other.Item(n)->GetData()); - } -} - -wxStringList::wxStringList() -{ - DeleteContents(true); -} - -// Variable argument list, terminated by a zero -// Makes new storage for the strings -wxStringList::wxStringList (const wxChar *first, ...) -{ - DeleteContents(true); - if ( !first ) - return; - - va_list ap; - va_start(ap, first); - - const wxChar *s = first; - for (;;) - { - Add(s); - - // icc gives this warning in its own va_arg() macro, argh -#ifdef __INTELC__ - #pragma warning(push) - #pragma warning(disable: 1684) -#endif - - s = va_arg(ap, const wxChar *); - -#ifdef __INTELC__ - #pragma warning(pop) -#endif - - if ( !s ) - break; - } - - va_end(ap); -} - -// Only makes new strings if arg is true -wxChar **wxStringList::ListToArray(bool new_copies) const -{ - wxChar **string_array = new wxChar *[GetCount()]; - wxStringListNode *node = GetFirst(); - for (size_t i = 0; i < GetCount(); i++) - { - wxChar *s = node->GetData(); - if ( new_copies ) - string_array[i] = MYcopystring(s); - else - string_array[i] = s; - node = node->GetNext(); - } - - return string_array; -} - -// Checks whether s is a member of the list -bool wxStringList::Member(const wxChar *s) const -{ - for ( wxStringListNode *node = GetFirst(); node; node = node->GetNext() ) - { - const wxChar *s1 = node->GetData(); - if (s == s1 || wxStrcmp (s, s1) == 0) - return true; - } - - return false; -} - -#ifdef __WXWINCE__ -extern "C" int __cdecl -#else -extern "C" int LINKAGEMODE -#endif - -wx_comparestrings(const void *arg1, const void *arg2) -{ - wxChar **s1 = (wxChar **) arg1; - wxChar **s2 = (wxChar **) arg2; - - return wxStrcmp (*s1, *s2); -} - -// Sort a list of strings - deallocates old nodes, allocates new -void wxStringList::Sort() -{ - size_t N = GetCount(); - wxChar **array = new wxChar *[N]; - wxStringListNode *node; - - size_t i = 0; - for ( node = GetFirst(); node; node = node->GetNext() ) - { - array[i++] = node->GetData(); - } - - qsort (array, N, sizeof (wxChar *), wx_comparestrings); - - i = 0; - for ( node = GetFirst(); node; node = node->GetNext() ) - node->SetData( array[i++] ); - - delete [] array; -} - -wxNode *wxStringList::Add(const wxChar *s) -{ - return (wxNode *)(wxStringListBase::Node *) - wxStringListBase::Append(MYcopystring(s)); -} - -wxNode *wxStringList::Prepend(const wxChar *s) -{ - return (wxNode *)(wxStringListBase::Node *) - wxStringListBase::Insert(MYcopystring(s)); -} - -#endif // wxLIST_COMPATIBILITY - -#else // wxUSE_STL = 1 - - #include "wx/listimpl.cpp" - WX_DEFINE_LIST(wxObjectList) - -// with wxUSE_STL wxStringList contains wxString objects, not pointers -void _WX_LIST_HELPER_wxStringListBase::DeleteFunction( wxString WXUNUSED(X) ) -{ -} - -wxStringListBase::BaseListType wxStringListBase::EmptyList; - -#endif // !wxUSE_STL +//////////////////////////////////////////////////////////////////////////////// +// Name: src/common/list.cpp +// Purpose: wxList implementation +// Author: Julian Smart +// Modified by: VZ at 16/11/98: WX_DECLARE_LIST() and typesafe lists added +// Created: 04/01/98 +// RCS-ID: $Id: list.cpp 43048 2006-11-04 18:14:50Z VZ $ +// Copyright: (c) Julian Smart +// Licence: wxWindows licence +//////////////////////////////////////////////////////////////////////////////// + +// ============================================================================= +// declarations +// ============================================================================= + +// ----------------------------------------------------------------------------- +// headers +// ----------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#include +#include +#include + +#ifndef WX_PRECOMP + #include "wx/list.h" +#endif + +#if !wxUSE_STL + +// ============================================================================= +// implementation +// ============================================================================= + +// ----------------------------------------------------------------------------- +// wxListKey +// ----------------------------------------------------------------------------- +wxListKey wxDefaultListKey; + +bool wxListKey::operator==(wxListKeyValue value) const +{ + switch ( m_keyType ) + { + default: + wxFAIL_MSG(wxT("bad key type.")); + // let compiler optimize the line above away in release build + // by not putting return here... + + case wxKEY_STRING: + return wxStrcmp(m_key.string, value.string) == 0; + + case wxKEY_INTEGER: + return m_key.integer == value.integer; + } +} + +// ----------------------------------------------------------------------------- +// wxNodeBase +// ----------------------------------------------------------------------------- + +wxNodeBase::wxNodeBase(wxListBase *list, + wxNodeBase *previous, wxNodeBase *next, + void *data, const wxListKey& key) +{ + m_list = list; + m_data = data; + m_previous = previous; + m_next = next; + + switch ( key.GetKeyType() ) + { + case wxKEY_NONE: + break; + + case wxKEY_INTEGER: + m_key.integer = key.GetNumber(); + break; + + case wxKEY_STRING: + // to be free()d later + m_key.string = wxStrdup(key.GetString()); + break; + + default: + wxFAIL_MSG(wxT("invalid key type")); + } + + if ( previous ) + previous->m_next = this; + + if ( next ) + next->m_previous = this; +} + +wxNodeBase::~wxNodeBase() +{ + // handle the case when we're being deleted from the list by the user (i.e. + // not by the list itself from DeleteNode) - we must do it for + // compatibility with old code + if ( m_list != NULL ) + { + if ( m_list->m_keyType == wxKEY_STRING ) + { + free(m_key.string); + } + + m_list->DetachNode(this); + } +} + +int wxNodeBase::IndexOf() const +{ + wxCHECK_MSG( m_list, wxNOT_FOUND, wxT("node doesn't belong to a list in IndexOf")); + + // It would be more efficient to implement IndexOf() completely inside + // wxListBase (only traverse the list once), but this is probably a more + // reusable way of doing it. Can always be optimized at a later date (since + // IndexOf() resides in wxListBase as well) if efficiency is a problem. + int i; + wxNodeBase *prev = m_previous; + + for( i = 0; prev; i++ ) + { + prev = prev->m_previous; + } + + return i; +} + +// ----------------------------------------------------------------------------- +// wxListBase +// ----------------------------------------------------------------------------- + +void wxListBase::Init(wxKeyType keyType) +{ + m_nodeFirst = + m_nodeLast = (wxNodeBase *) NULL; + m_count = 0; + m_destroy = false; + m_keyType = keyType; +} + +wxListBase::wxListBase(size_t count, void *elements[]) +{ + Init(); + + for ( size_t n = 0; n < count; n++ ) + { + Append(elements[n]); + } +} + +void wxListBase::DoCopy(const wxListBase& list) +{ + wxASSERT_MSG( !list.m_destroy, + wxT("copying list which owns it's elements is a bad idea") ); + + m_destroy = list.m_destroy; + m_keyType = list.m_keyType; + m_nodeFirst = + m_nodeLast = (wxNodeBase *) NULL; + + switch (m_keyType) + { + case wxKEY_INTEGER: + { + long key; + for ( wxNodeBase *node = list.GetFirst(); node; node = node->GetNext() ) + { + key = node->GetKeyInteger(); + Append(key, node->GetData()); + } + break; + } + + case wxKEY_STRING: + { + const wxChar *key; + for ( wxNodeBase *node = list.GetFirst(); node; node = node->GetNext() ) + { + key = node->GetKeyString(); + Append(key, node->GetData()); + } + break; + } + + default: + { + for ( wxNodeBase *node = list.GetFirst(); node; node = node->GetNext() ) + { + Append(node->GetData()); + } + break; + } + } + + wxASSERT_MSG( m_count == list.m_count, _T("logic error in wxList::DoCopy") ); +} + +wxListBase::~wxListBase() +{ + wxNodeBase *each = m_nodeFirst; + while ( each != NULL ) + { + wxNodeBase *next = each->GetNext(); + DoDeleteNode(each); + each = next; + } +} + +wxNodeBase *wxListBase::AppendCommon(wxNodeBase *node) +{ + if ( !m_nodeFirst ) + { + m_nodeFirst = node; + m_nodeLast = m_nodeFirst; + } + else + { + m_nodeLast->m_next = node; + m_nodeLast = node; + } + + m_count++; + + return node; +} + +wxNodeBase *wxListBase::Append(void *object) +{ + // all objects in a keyed list should have a key + wxCHECK_MSG( m_keyType == wxKEY_NONE, (wxNodeBase *)NULL, + wxT("need a key for the object to append") ); + + // we use wxDefaultListKey even though it is the default parameter value + // because gcc under Mac OS X seems to miscompile this call otherwise + wxNodeBase *node = CreateNode(m_nodeLast, (wxNodeBase *)NULL, object, + wxDefaultListKey); + + return AppendCommon(node); +} + +wxNodeBase *wxListBase::Append(long key, void *object) +{ + wxCHECK_MSG( (m_keyType == wxKEY_INTEGER) || + (m_keyType == wxKEY_NONE && m_count == 0), + (wxNodeBase *)NULL, + wxT("can't append object with numeric key to this list") ); + + wxNodeBase *node = CreateNode(m_nodeLast, (wxNodeBase *)NULL, object, key); + return AppendCommon(node); +} + +wxNodeBase *wxListBase::Append (const wxChar *key, void *object) +{ + wxCHECK_MSG( (m_keyType == wxKEY_STRING) || + (m_keyType == wxKEY_NONE && m_count == 0), + (wxNodeBase *)NULL, + wxT("can't append object with string key to this list") ); + + wxNodeBase *node = CreateNode(m_nodeLast, (wxNodeBase *)NULL, object, key); + return AppendCommon(node); +} + +wxNodeBase *wxListBase::Insert(wxNodeBase *position, void *object) +{ + // all objects in a keyed list should have a key + wxCHECK_MSG( m_keyType == wxKEY_NONE, (wxNodeBase *)NULL, + wxT("need a key for the object to insert") ); + + wxCHECK_MSG( !position || position->m_list == this, (wxNodeBase *)NULL, + wxT("can't insert before a node from another list") ); + + // previous and next node for the node being inserted + wxNodeBase *prev, *next; + if ( position ) + { + prev = position->GetPrevious(); + next = position; + } + else + { + // inserting in the beginning of the list + prev = (wxNodeBase *)NULL; + next = m_nodeFirst; + } + + // wxDefaultListKey: see comment in Append() above + wxNodeBase *node = CreateNode(prev, next, object, wxDefaultListKey); + if ( !m_nodeFirst ) + { + m_nodeLast = node; + } + + if ( prev == NULL ) + { + m_nodeFirst = node; + } + + m_count++; + + return node; +} + +wxNodeBase *wxListBase::Item(size_t n) const +{ + for ( wxNodeBase *current = GetFirst(); current; current = current->GetNext() ) + { + if ( n-- == 0 ) + { + return current; + } + } + + wxFAIL_MSG( wxT("invalid index in wxListBase::Item") ); + + return (wxNodeBase *)NULL; +} + +wxNodeBase *wxListBase::Find(const wxListKey& key) const +{ + wxASSERT_MSG( m_keyType == key.GetKeyType(), + wxT("this list is not keyed on the type of this key") ); + + for ( wxNodeBase *current = GetFirst(); current; current = current->GetNext() ) + { + if ( key == current->m_key ) + { + return current; + } + } + + // not found + return (wxNodeBase *)NULL; +} + +wxNodeBase *wxListBase::Find(const void *object) const +{ + for ( wxNodeBase *current = GetFirst(); current; current = current->GetNext() ) + { + if ( current->GetData() == object ) + return current; + } + + // not found + return (wxNodeBase *)NULL; +} + +int wxListBase::IndexOf(void *object) const +{ + wxNodeBase *node = Find( object ); + + return node ? node->IndexOf() : wxNOT_FOUND; +} + +void wxListBase::DoDeleteNode(wxNodeBase *node) +{ + // free node's data + if ( m_keyType == wxKEY_STRING ) + { + free(node->m_key.string); + } + + if ( m_destroy ) + { + node->DeleteData(); + } + + // so that the node knows that it's being deleted by the list + node->m_list = NULL; + delete node; +} + +wxNodeBase *wxListBase::DetachNode(wxNodeBase *node) +{ + wxCHECK_MSG( node, NULL, wxT("detaching NULL wxNodeBase") ); + wxCHECK_MSG( node->m_list == this, NULL, + wxT("detaching node which is not from this list") ); + + // update the list + wxNodeBase **prevNext = node->GetPrevious() ? &node->GetPrevious()->m_next + : &m_nodeFirst; + wxNodeBase **nextPrev = node->GetNext() ? &node->GetNext()->m_previous + : &m_nodeLast; + + *prevNext = node->GetNext(); + *nextPrev = node->GetPrevious(); + + m_count--; + + // mark the node as not belonging to this list any more + node->m_list = NULL; + + return node; +} + +bool wxListBase::DeleteNode(wxNodeBase *node) +{ + if ( !DetachNode(node) ) + return false; + + DoDeleteNode(node); + + return true; +} + +bool wxListBase::DeleteObject(void *object) +{ + for ( wxNodeBase *current = GetFirst(); current; current = current->GetNext() ) + { + if ( current->GetData() == object ) + { + DeleteNode(current); + return true; + } + } + + // not found + return false; +} + +void wxListBase::Clear() +{ + wxNodeBase *current = m_nodeFirst; + while ( current ) + { + wxNodeBase *next = current->GetNext(); + DoDeleteNode(current); + current = next; + } + + m_nodeFirst = + m_nodeLast = (wxNodeBase *)NULL; + + m_count = 0; +} + +void wxListBase::ForEach(wxListIterateFunction F) +{ + for ( wxNodeBase *current = GetFirst(); current; current = current->GetNext() ) + { + (*F)(current->GetData()); + } +} + +void *wxListBase::FirstThat(wxListIterateFunction F) +{ + for ( wxNodeBase *current = GetFirst(); current; current = current->GetNext() ) + { + if ( (*F)(current->GetData()) ) + return current->GetData(); + } + + return (wxNodeBase *)NULL; +} + +void *wxListBase::LastThat(wxListIterateFunction F) +{ + for ( wxNodeBase *current = GetLast(); current; current = current->GetPrevious() ) + { + if ( (*F)(current->GetData()) ) + return current->GetData(); + } + + return (wxNodeBase *)NULL; +} + +// (stefan.hammes@urz.uni-heidelberg.de) +// +// function for sorting lists. the concept is borrowed from 'qsort'. +// by giving a sort function, arbitrary lists can be sorted. +// method: +// - put wxObject pointers into an array +// - sort the array with qsort +// - put back the sorted wxObject pointers into the list +// +// CAVE: the sort function receives pointers to wxObject pointers (wxObject **), +// so dereference right! +// EXAMPLE: +// int listcompare(const void *arg1, const void *arg2) +// { +// return(compare(**(wxString **)arg1, +// **(wxString **)arg2)); +// } +// +// void main() +// { +// wxListBase list; +// +// list.Append(new wxString("DEF")); +// list.Append(new wxString("GHI")); +// list.Append(new wxString("ABC")); +// list.Sort(listcompare); +// } + +void wxListBase::Sort(const wxSortCompareFunction compfunc) +{ + // allocate an array for the wxObject pointers of the list + const size_t num = GetCount(); + void **objArray = new void *[num]; + void **objPtr = objArray; + + // go through the list and put the pointers into the array + wxNodeBase *node; + for ( node = GetFirst(); node; node = node->GetNext() ) + { + *objPtr++ = node->GetData(); + } + + // sort the array + qsort((void *)objArray,num,sizeof(wxObject *), +#ifdef __WXWINCE__ + (int (__cdecl *)(const void *,const void *)) +#endif + compfunc); + + // put the sorted pointers back into the list + objPtr = objArray; + for ( node = GetFirst(); node; node = node->GetNext() ) + { + node->SetData(*objPtr++); + } + + // free the array + delete[] objArray; +} + +void wxListBase::Reverse() +{ + wxNodeBase* node = m_nodeFirst; + wxNodeBase* tmp; + + while (node) + { + // swap prev and next pointers + tmp = node->m_next; + node->m_next = node->m_previous; + node->m_previous = tmp; + + // this is the node that was next before swapping + node = tmp; + } + + // swap first and last node + tmp = m_nodeFirst; m_nodeFirst = m_nodeLast; m_nodeLast = tmp; +} + +void wxListBase::DeleteNodes(wxNodeBase* first, wxNodeBase* last) +{ + wxNodeBase* node = first; + + while (node != last) + { + wxNodeBase* next = node->GetNext(); + DeleteNode(node); + node = next; + } +} + +// ============================================================================ +// compatibility section from now on +// ============================================================================ + +#ifdef wxLIST_COMPATIBILITY + +// ----------------------------------------------------------------------------- +// wxList (a.k.a. wxObjectList) +// ----------------------------------------------------------------------------- + +IMPLEMENT_DYNAMIC_CLASS(wxList, wxObject) + +wxList::wxList( int key_type ) + : wxObjectList( (wxKeyType)key_type ) +{ +} + +void wxObjectListNode::DeleteData() +{ + delete (wxObject *)GetData(); +} + +// ---------------------------------------------------------------------------- +// wxStringList +// ---------------------------------------------------------------------------- + +static inline wxChar* MYcopystring(const wxChar* s) +{ + wxChar* copy = new wxChar[wxStrlen(s) + 1]; + return wxStrcpy(copy, s); +} + +IMPLEMENT_DYNAMIC_CLASS(wxStringList, wxObject) + +// instead of WX_DEFINE_LIST(wxStringListBase) we define this function +// ourselves +void wxStringListNode::DeleteData() +{ + delete [] (char *)GetData(); +} + +bool wxStringList::Delete(const wxChar *s) +{ + wxStringListNode *current; + + for ( current = GetFirst(); current; current = current->GetNext() ) + { + if ( wxStrcmp(current->GetData(), s) == 0 ) + { + DeleteNode(current); + return true; + } + } + + // not found + return false; +} + +void wxStringList::DoCopy(const wxStringList& other) +{ + wxASSERT( GetCount() == 0 ); // this list must be empty before copying! + + size_t count = other.GetCount(); + for ( size_t n = 0; n < count; n++ ) + { + Add(other.Item(n)->GetData()); + } +} + +wxStringList::wxStringList() +{ + DeleteContents(true); +} + +// Variable argument list, terminated by a zero +// Makes new storage for the strings +wxStringList::wxStringList (const wxChar *first, ...) +{ + DeleteContents(true); + if ( !first ) + return; + + va_list ap; + va_start(ap, first); + + const wxChar *s = first; + for (;;) + { + Add(s); + + // icc gives this warning in its own va_arg() macro, argh +#ifdef __INTELC__ + #pragma warning(push) + #pragma warning(disable: 1684) +#endif + + s = va_arg(ap, const wxChar *); + +#ifdef __INTELC__ + #pragma warning(pop) +#endif + + if ( !s ) + break; + } + + va_end(ap); +} + +// Only makes new strings if arg is true +wxChar **wxStringList::ListToArray(bool new_copies) const +{ + wxChar **string_array = new wxChar *[GetCount()]; + wxStringListNode *node = GetFirst(); + for (size_t i = 0; i < GetCount(); i++) + { + wxChar *s = node->GetData(); + if ( new_copies ) + string_array[i] = MYcopystring(s); + else + string_array[i] = s; + node = node->GetNext(); + } + + return string_array; +} + +// Checks whether s is a member of the list +bool wxStringList::Member(const wxChar *s) const +{ + for ( wxStringListNode *node = GetFirst(); node; node = node->GetNext() ) + { + const wxChar *s1 = node->GetData(); + if (s == s1 || wxStrcmp (s, s1) == 0) + return true; + } + + return false; +} + +#ifdef __WXWINCE__ +extern "C" int __cdecl +#else +extern "C" int LINKAGEMODE +#endif + +wx_comparestrings(const void *arg1, const void *arg2) +{ + wxChar **s1 = (wxChar **) arg1; + wxChar **s2 = (wxChar **) arg2; + + return wxStrcmp (*s1, *s2); +} + +// Sort a list of strings - deallocates old nodes, allocates new +void wxStringList::Sort() +{ + size_t N = GetCount(); + wxChar **array = new wxChar *[N]; + wxStringListNode *node; + + size_t i = 0; + for ( node = GetFirst(); node; node = node->GetNext() ) + { + array[i++] = node->GetData(); + } + + qsort (array, N, sizeof (wxChar *), wx_comparestrings); + + i = 0; + for ( node = GetFirst(); node; node = node->GetNext() ) + node->SetData( array[i++] ); + + delete [] array; +} + +wxNode *wxStringList::Add(const wxChar *s) +{ + return (wxNode *)(wxStringListBase::Node *) + wxStringListBase::Append(MYcopystring(s)); +} + +wxNode *wxStringList::Prepend(const wxChar *s) +{ + return (wxNode *)(wxStringListBase::Node *) + wxStringListBase::Insert(MYcopystring(s)); +} + +#endif // wxLIST_COMPATIBILITY + +#else // wxUSE_STL = 1 + + #include "wx/listimpl.cpp" + WX_DEFINE_LIST(wxObjectList) + +// with wxUSE_STL wxStringList contains wxString objects, not pointers +void _WX_LIST_HELPER_wxStringListBase::DeleteFunction( wxString WXUNUSED(X) ) +{ +} + +wxStringListBase::BaseListType wxStringListBase::EmptyList; + +#endif // !wxUSE_STL diff --git a/Externals/wxWidgets/src/common/listctrlcmn.cpp b/Externals/wxWidgets/src/common/listctrlcmn.cpp index f0703f39e4..c5366a1aac 100644 --- a/Externals/wxWidgets/src/common/listctrlcmn.cpp +++ b/Externals/wxWidgets/src/common/listctrlcmn.cpp @@ -1,54 +1,54 @@ -//////////////////////////////////////////////////////////////////////////////// -// Name: src/common/listctrlcmn.cpp -// Purpose: Common defines for wxListCtrl and wxListCtrl-based classes. -// Author: Kevin Ollivier -// Created: 09/15/06 -// RCS-ID: $Id: listctrlcmn.cpp 41568 2006-10-02 17:38:30Z PC $ -// Copyright: (c) Kevin Ollivier -// Licence: wxWindows licence -//////////////////////////////////////////////////////////////////////////////// - -// ============================================================================= -// declarations -// ============================================================================= - -// ----------------------------------------------------------------------------- -// headers -// ----------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#if wxUSE_LISTCTRL - -#include "wx/listctrl.h" - -const wxChar wxListCtrlNameStr[] = wxT("listCtrl"); - -// ListCtrl events -DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_BEGIN_DRAG) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_BEGIN_RDRAG) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_BEGIN_LABEL_EDIT) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_END_LABEL_EDIT) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_DELETE_ITEM) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_DELETE_ALL_ITEMS) -#if WXWIN_COMPATIBILITY_2_4 -DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_GET_INFO) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_SET_INFO) -#endif -DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_SELECTED) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_DESELECTED) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_KEY_DOWN) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_INSERT_ITEM) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_COL_CLICK) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_COL_RIGHT_CLICK) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_COL_BEGIN_DRAG) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_COL_DRAGGING) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_COL_END_DRAG) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_RIGHT_CLICK) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_MIDDLE_CLICK) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_ACTIVATED) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_FOCUSED) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_CACHE_HINT) - -#endif // wxUSE_LISTCTRL +//////////////////////////////////////////////////////////////////////////////// +// Name: src/common/listctrlcmn.cpp +// Purpose: Common defines for wxListCtrl and wxListCtrl-based classes. +// Author: Kevin Ollivier +// Created: 09/15/06 +// RCS-ID: $Id: listctrlcmn.cpp 41568 2006-10-02 17:38:30Z PC $ +// Copyright: (c) Kevin Ollivier +// Licence: wxWindows licence +//////////////////////////////////////////////////////////////////////////////// + +// ============================================================================= +// declarations +// ============================================================================= + +// ----------------------------------------------------------------------------- +// headers +// ----------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#if wxUSE_LISTCTRL + +#include "wx/listctrl.h" + +const wxChar wxListCtrlNameStr[] = wxT("listCtrl"); + +// ListCtrl events +DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_BEGIN_DRAG) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_BEGIN_RDRAG) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_BEGIN_LABEL_EDIT) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_END_LABEL_EDIT) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_DELETE_ITEM) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_DELETE_ALL_ITEMS) +#if WXWIN_COMPATIBILITY_2_4 +DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_GET_INFO) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_SET_INFO) +#endif +DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_SELECTED) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_DESELECTED) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_KEY_DOWN) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_INSERT_ITEM) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_COL_CLICK) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_COL_RIGHT_CLICK) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_COL_BEGIN_DRAG) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_COL_DRAGGING) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_COL_END_DRAG) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_RIGHT_CLICK) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_MIDDLE_CLICK) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_ACTIVATED) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_FOCUSED) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_CACHE_HINT) + +#endif // wxUSE_LISTCTRL diff --git a/Externals/wxWidgets/src/common/log.cpp b/Externals/wxWidgets/src/common/log.cpp index 9c56c4719e..19eb3b9856 100644 --- a/Externals/wxWidgets/src/common/log.cpp +++ b/Externals/wxWidgets/src/common/log.cpp @@ -1,838 +1,838 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/log.cpp -// Purpose: Assorted wxLogXXX functions, and wxLog (sink for logs) -// Author: Vadim Zeitlin -// Modified by: -// Created: 29/01/98 -// RCS-ID: $Id: log.cpp 50994 2008-01-02 21:27:31Z VZ $ -// Copyright: (c) 1998 Vadim Zeitlin -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_LOG - -// wxWidgets -#ifndef WX_PRECOMP - #include "wx/log.h" - #include "wx/app.h" - #include "wx/arrstr.h" - #include "wx/intl.h" - #include "wx/string.h" - #include "wx/utils.h" -#endif //WX_PRECOMP - -#include "wx/apptrait.h" -#include "wx/datetime.h" -#include "wx/file.h" -#include "wx/msgout.h" -#include "wx/textfile.h" -#include "wx/thread.h" -#include "wx/wxchar.h" - -// other standard headers -#ifndef __WXWINCE__ -#include -#endif - -#include - -#ifndef __WXWINCE__ -#include -#else -#include "wx/msw/wince/time.h" -#endif - -#if defined(__WINDOWS__) - #include "wx/msw/private.h" // includes windows.h -#endif - -// ---------------------------------------------------------------------------- -// non member functions -// ---------------------------------------------------------------------------- - -// define this to enable wrapping of log messages -//#define LOG_PRETTY_WRAP - -#ifdef LOG_PRETTY_WRAP - static void wxLogWrap(FILE *f, const char *pszPrefix, const char *psz); -#endif - -// ============================================================================ -// implementation -// ============================================================================ - -// ---------------------------------------------------------------------------- -// implementation of Log functions -// -// NB: unfortunately we need all these distinct functions, we can't make them -// macros and not all compilers inline vararg functions. -// ---------------------------------------------------------------------------- - -// generic log function -void wxVLogGeneric(wxLogLevel level, const wxChar *szFormat, va_list argptr) -{ - if ( wxLog::IsEnabled() ) { - wxLog::OnLog(level, wxString::FormatV(szFormat, argptr), time(NULL)); - } -} - -void wxLogGeneric(wxLogLevel level, const wxChar *szFormat, ...) -{ - va_list argptr; - va_start(argptr, szFormat); - wxVLogGeneric(level, szFormat, argptr); - va_end(argptr); -} - -#define IMPLEMENT_LOG_FUNCTION(level) \ - void wxVLog##level(const wxChar *szFormat, va_list argptr) \ - { \ - if ( wxLog::IsEnabled() ) { \ - wxLog::OnLog(wxLOG_##level, \ - wxString::FormatV(szFormat, argptr), time(NULL));\ - } \ - } \ - \ - void wxLog##level(const wxChar *szFormat, ...) \ - { \ - va_list argptr; \ - va_start(argptr, szFormat); \ - wxVLog##level(szFormat, argptr); \ - va_end(argptr); \ - } - -IMPLEMENT_LOG_FUNCTION(Error) -IMPLEMENT_LOG_FUNCTION(Warning) -IMPLEMENT_LOG_FUNCTION(Message) -IMPLEMENT_LOG_FUNCTION(Info) -IMPLEMENT_LOG_FUNCTION(Status) - -void wxSafeShowMessage(const wxString& title, const wxString& text) -{ -#ifdef __WINDOWS__ - ::MessageBox(NULL, text, title, MB_OK | MB_ICONSTOP); -#else - wxFprintf(stderr, _T("%s: %s\n"), title.c_str(), text.c_str()); - fflush(stderr); -#endif -} - -// fatal errors can't be suppressed nor handled by the custom log target and -// always terminate the program -void wxVLogFatalError(const wxChar *szFormat, va_list argptr) -{ - wxSafeShowMessage(_T("Fatal Error"), wxString::FormatV(szFormat, argptr)); - -#ifdef __WXWINCE__ - ExitThread(3); -#else - abort(); -#endif -} - -void wxLogFatalError(const wxChar *szFormat, ...) -{ - va_list argptr; - va_start(argptr, szFormat); - wxVLogFatalError(szFormat, argptr); - - // some compilers warn about unreachable code and it shouldn't matter - // for the others anyhow... - //va_end(argptr); -} - -// same as info, but only if 'verbose' mode is on -void wxVLogVerbose(const wxChar *szFormat, va_list argptr) -{ - if ( wxLog::IsEnabled() ) { - if ( wxLog::GetActiveTarget() != NULL && wxLog::GetVerbose() ) { - wxLog::OnLog(wxLOG_Info, - wxString::FormatV(szFormat, argptr), time(NULL)); - } - } -} - -void wxLogVerbose(const wxChar *szFormat, ...) -{ - va_list argptr; - va_start(argptr, szFormat); - wxVLogVerbose(szFormat, argptr); - va_end(argptr); -} - -// debug functions -#ifdef __WXDEBUG__ -#define IMPLEMENT_LOG_DEBUG_FUNCTION(level) \ - void wxVLog##level(const wxChar *szFormat, va_list argptr) \ - { \ - if ( wxLog::IsEnabled() ) { \ - wxLog::OnLog(wxLOG_##level, \ - wxString::FormatV(szFormat, argptr), time(NULL));\ - } \ - } \ - \ - void wxLog##level(const wxChar *szFormat, ...) \ - { \ - va_list argptr; \ - va_start(argptr, szFormat); \ - wxVLog##level(szFormat, argptr); \ - va_end(argptr); \ - } - - void wxVLogTrace(const wxChar *mask, const wxChar *szFormat, va_list argptr) - { - if ( wxLog::IsEnabled() && wxLog::IsAllowedTraceMask(mask) ) { - wxString msg; - msg << _T("(") << mask << _T(") ") << wxString::FormatV(szFormat, argptr); - - wxLog::OnLog(wxLOG_Trace, msg, time(NULL)); - } - } - - void wxLogTrace(const wxChar *mask, const wxChar *szFormat, ...) - { - va_list argptr; - va_start(argptr, szFormat); - wxVLogTrace(mask, szFormat, argptr); - va_end(argptr); - } - - void wxVLogTrace(wxTraceMask mask, const wxChar *szFormat, va_list argptr) - { - // we check that all of mask bits are set in the current mask, so - // that wxLogTrace(wxTraceRefCount | wxTraceOle) will only do something - // if both bits are set. - if ( wxLog::IsEnabled() && ((wxLog::GetTraceMask() & mask) == mask) ) { - wxLog::OnLog(wxLOG_Trace, wxString::FormatV(szFormat, argptr), time(NULL)); - } - } - - void wxLogTrace(wxTraceMask mask, const wxChar *szFormat, ...) - { - va_list argptr; - va_start(argptr, szFormat); - wxVLogTrace(mask, szFormat, argptr); - va_end(argptr); - } - -#else // release - #define IMPLEMENT_LOG_DEBUG_FUNCTION(level) -#endif - -IMPLEMENT_LOG_DEBUG_FUNCTION(Debug) -IMPLEMENT_LOG_DEBUG_FUNCTION(Trace) - -// wxLogSysError: one uses the last error code, for other you must give it -// explicitly - -// return the system error message description -static inline wxString wxLogSysErrorHelper(long err) -{ - return wxString::Format(_(" (error %ld: %s)"), err, wxSysErrorMsg(err)); -} - -void WXDLLEXPORT wxVLogSysError(const wxChar *szFormat, va_list argptr) -{ - wxVLogSysError(wxSysErrorCode(), szFormat, argptr); -} - -void WXDLLEXPORT wxLogSysError(const wxChar *szFormat, ...) -{ - va_list argptr; - va_start(argptr, szFormat); - wxVLogSysError(szFormat, argptr); - va_end(argptr); -} - -void WXDLLEXPORT wxVLogSysError(long err, const wxChar *fmt, va_list argptr) -{ - if ( wxLog::IsEnabled() ) { - wxLog::OnLog(wxLOG_Error, - wxString::FormatV(fmt, argptr) + wxLogSysErrorHelper(err), - time(NULL)); - } -} - -void WXDLLEXPORT wxLogSysError(long lErrCode, const wxChar *szFormat, ...) -{ - va_list argptr; - va_start(argptr, szFormat); - wxVLogSysError(lErrCode, szFormat, argptr); - va_end(argptr); -} - -// ---------------------------------------------------------------------------- -// wxLog class implementation -// ---------------------------------------------------------------------------- - -// define a critical section gs_prevCS protecting access to wxLog::ms_prevXXX -wxCRIT_SECT_DECLARE(gs_prevCS); - -/* static */ -unsigned wxLog::DoLogNumberOfRepeats() -{ - wxLog * const pLogger = GetActiveTarget(); - return pLogger ? pLogger->LogLastRepeatIfNeeded() : 0u; -} - -unsigned wxLog::LogLastRepeatIfNeeded() -{ - wxCRIT_SECT_LOCKER(lock, gs_prevCS); - - return LogLastRepeatIfNeededUnlocked(); -} - -unsigned wxLog::LogLastRepeatIfNeededUnlocked() -{ - long retval = ms_prevCounter; - if ( ms_prevCounter > 0 ) - { - wxString msg; -#if wxUSE_INTL - msg.Printf(wxPLURAL("The previous message repeated once.", - "The previous message repeated %lu times.", - ms_prevCounter), - ms_prevCounter); -#else - msg.Printf(wxT("The previous message was repeated.")); -#endif - ms_prevCounter = 0; - ms_prevString.clear(); - DoLog(ms_prevLevel, msg.c_str(), ms_prevTimeStamp); - } - return retval; -} - -wxLog::~wxLog() -{ -} - -/* static */ -void wxLog::OnLog(wxLogLevel level, const wxChar *szString, time_t t) -{ - if ( IsEnabled() && ms_logLevel >= level ) - { - wxLog *pLogger = GetActiveTarget(); - if ( pLogger ) - { - if ( GetRepetitionCounting() ) - { - wxCRIT_SECT_LOCKER(lock, gs_prevCS); - - if ( szString == ms_prevString ) - { - ms_prevCounter++; - - // nothing else to do, in particular, don't log the - // repeated message - return; - } - - pLogger->LogLastRepeatIfNeededUnlocked(); - - // reset repetition counter for a new message - ms_prevString = szString; - ms_prevLevel = level; - ms_prevTimeStamp = t; - } - - pLogger->DoLog(level, szString, t); - } - } -} - -// deprecated function -#if WXWIN_COMPATIBILITY_2_6 - -wxChar *wxLog::SetLogBuffer(wxChar * WXUNUSED(buf), size_t WXUNUSED(size)) -{ - return NULL; -} - -#endif // WXWIN_COMPATIBILITY_2_6 - -wxLog *wxLog::GetActiveTarget() -{ - if ( ms_bAutoCreate && ms_pLogger == NULL ) { - // prevent infinite recursion if someone calls wxLogXXX() from - // wxApp::CreateLogTarget() - static bool s_bInGetActiveTarget = false; - if ( !s_bInGetActiveTarget ) { - s_bInGetActiveTarget = true; - - // ask the application to create a log target for us - if ( wxTheApp != NULL ) - ms_pLogger = wxTheApp->GetTraits()->CreateLogTarget(); - else - ms_pLogger = new wxLogStderr; - - s_bInGetActiveTarget = false; - - // do nothing if it fails - what can we do? - } - } - - return ms_pLogger; -} - -wxLog *wxLog::SetActiveTarget(wxLog *pLogger) -{ - if ( ms_pLogger != NULL ) { - // flush the old messages before changing because otherwise they might - // get lost later if this target is not restored - ms_pLogger->Flush(); - } - - wxLog *pOldLogger = ms_pLogger; - ms_pLogger = pLogger; - - return pOldLogger; -} - -void wxLog::DontCreateOnDemand() -{ - ms_bAutoCreate = false; - - // this is usually called at the end of the program and we assume that it - // is *always* called at the end - so we free memory here to avoid false - // memory leak reports from wxWin memory tracking code - ClearTraceMasks(); -} - -void wxLog::DoCreateOnDemand() -{ - ms_bAutoCreate = true; -} - -void wxLog::RemoveTraceMask(const wxString& str) -{ - int index = ms_aTraceMasks.Index(str); - if ( index != wxNOT_FOUND ) - ms_aTraceMasks.RemoveAt((size_t)index); -} - -void wxLog::ClearTraceMasks() -{ - ms_aTraceMasks.Clear(); -} - -void wxLog::TimeStamp(wxString *str) -{ -#if wxUSE_DATETIME - if ( ms_timestamp ) - { - wxChar buf[256]; - time_t timeNow; - (void)time(&timeNow); - - struct tm tm; - wxStrftime(buf, WXSIZEOF(buf), - ms_timestamp, wxLocaltime_r(&timeNow, &tm)); - - str->Empty(); - *str << buf << wxT(": "); - } -#endif // wxUSE_DATETIME -} - -void wxLog::DoLog(wxLogLevel level, const wxChar *szString, time_t t) -{ - switch ( level ) { - case wxLOG_FatalError: - DoLogString(wxString(_("Fatal error: ")) + szString, t); - DoLogString(_("Program aborted."), t); - Flush(); -#ifdef __WXWINCE__ - ExitThread(3); -#else - abort(); -#endif - break; - - case wxLOG_Error: - DoLogString(wxString(_("Error: ")) + szString, t); - break; - - case wxLOG_Warning: - DoLogString(wxString(_("Warning: ")) + szString, t); - break; - - case wxLOG_Info: - if ( GetVerbose() ) - case wxLOG_Message: - case wxLOG_Status: - default: // log unknown log levels too - DoLogString(szString, t); - break; - - case wxLOG_Trace: - case wxLOG_Debug: -#ifdef __WXDEBUG__ - { - wxString msg = level == wxLOG_Trace ? wxT("Trace: ") - : wxT("Debug: "); - msg << szString; - DoLogString(msg, t); - } -#endif // Debug - break; - } -} - -void wxLog::DoLogString(const wxChar *WXUNUSED(szString), time_t WXUNUSED(t)) -{ - wxFAIL_MSG(wxT("DoLogString must be overriden if it's called.")); -} - -void wxLog::Flush() -{ - LogLastRepeatIfNeeded(); -} - -/*static*/ bool wxLog::IsAllowedTraceMask(const wxChar *mask) -{ - for ( wxArrayString::iterator it = ms_aTraceMasks.begin(), - en = ms_aTraceMasks.end(); - it != en; ++it ) - if ( *it == mask) - return true; - return false; -} - -// ---------------------------------------------------------------------------- -// wxLogBuffer implementation -// ---------------------------------------------------------------------------- - -void wxLogBuffer::Flush() -{ - if ( !m_str.empty() ) - { - wxMessageOutputBest out; - out.Printf(_T("%s"), m_str.c_str()); - m_str.clear(); - } -} - -void wxLogBuffer::DoLog(wxLogLevel level, const wxChar *szString, time_t t) -{ - switch ( level ) - { - case wxLOG_Trace: - case wxLOG_Debug: -#ifdef __WXDEBUG__ - // don't put debug messages in the buffer, we don't want to show - // them to the user in a msg box, log them immediately - { - wxString str; - TimeStamp(&str); - str += szString; - - wxMessageOutputDebug dbgout; - dbgout.Printf(_T("%s\n"), str.c_str()); - } -#endif // __WXDEBUG__ - break; - - default: - wxLog::DoLog(level, szString, t); - } -} - -void wxLogBuffer::DoLogString(const wxChar *szString, time_t WXUNUSED(t)) -{ - m_str << szString << _T("\n"); -} - -// ---------------------------------------------------------------------------- -// wxLogStderr class implementation -// ---------------------------------------------------------------------------- - -wxLogStderr::wxLogStderr(FILE *fp) -{ - if ( fp == NULL ) - m_fp = stderr; - else - m_fp = fp; -} - -void wxLogStderr::DoLogString(const wxChar *szString, time_t WXUNUSED(t)) -{ - wxString str; - TimeStamp(&str); - str << szString; - - wxFputs(str, m_fp); - wxFputc(_T('\n'), m_fp); - fflush(m_fp); - - // under GUI systems such as Windows or Mac, programs usually don't have - // stderr at all, so show the messages also somewhere else, typically in - // the debugger window so that they go at least somewhere instead of being - // simply lost - if ( m_fp == stderr ) - { - wxAppTraits *traits = wxTheApp ? wxTheApp->GetTraits() : NULL; - if ( traits && !traits->HasStderr() ) - { - wxMessageOutputDebug dbgout; - dbgout.Printf(_T("%s\n"), str.c_str()); - } - } -} - -// ---------------------------------------------------------------------------- -// wxLogStream implementation -// ---------------------------------------------------------------------------- - -#if wxUSE_STD_IOSTREAM -#include "wx/ioswrap.h" -wxLogStream::wxLogStream(wxSTD ostream *ostr) -{ - if ( ostr == NULL ) - m_ostr = &wxSTD cerr; - else - m_ostr = ostr; -} - -void wxLogStream::DoLogString(const wxChar *szString, time_t WXUNUSED(t)) -{ - wxString str; - TimeStamp(&str); - (*m_ostr) << wxSafeConvertWX2MB(str) << wxSafeConvertWX2MB(szString) << wxSTD endl; -} -#endif // wxUSE_STD_IOSTREAM - -// ---------------------------------------------------------------------------- -// wxLogChain -// ---------------------------------------------------------------------------- - -wxLogChain::wxLogChain(wxLog *logger) -{ - m_bPassMessages = true; - - m_logNew = logger; - m_logOld = wxLog::SetActiveTarget(this); -} - -wxLogChain::~wxLogChain() -{ - delete m_logOld; - - if ( m_logNew != this ) - delete m_logNew; -} - -void wxLogChain::SetLog(wxLog *logger) -{ - if ( m_logNew != this ) - delete m_logNew; - - m_logNew = logger; -} - -void wxLogChain::Flush() -{ - if ( m_logOld ) - m_logOld->Flush(); - - // be careful to avoid infinite recursion - if ( m_logNew && m_logNew != this ) - m_logNew->Flush(); -} - -void wxLogChain::DoLog(wxLogLevel level, const wxChar *szString, time_t t) -{ - // let the previous logger show it - if ( m_logOld && IsPassingMessages() ) - { - // bogus cast just to access protected DoLog - ((wxLogChain *)m_logOld)->DoLog(level, szString, t); - } - - if ( m_logNew && m_logNew != this ) - { - // as above... - ((wxLogChain *)m_logNew)->DoLog(level, szString, t); - } -} - -// ---------------------------------------------------------------------------- -// wxLogPassThrough -// ---------------------------------------------------------------------------- - -#ifdef __VISUALC__ - // "'this' : used in base member initializer list" - so what? - #pragma warning(disable:4355) -#endif // VC++ - -wxLogPassThrough::wxLogPassThrough() - : wxLogChain(this) -{ -} - -#ifdef __VISUALC__ - #pragma warning(default:4355) -#endif // VC++ - -// ============================================================================ -// Global functions/variables -// ============================================================================ - -// ---------------------------------------------------------------------------- -// static variables -// ---------------------------------------------------------------------------- - -bool wxLog::ms_bRepetCounting = false; -wxString wxLog::ms_prevString; -unsigned int wxLog::ms_prevCounter = 0; -time_t wxLog::ms_prevTimeStamp= 0; -wxLogLevel wxLog::ms_prevLevel; - -wxLog *wxLog::ms_pLogger = (wxLog *)NULL; -bool wxLog::ms_doLog = true; -bool wxLog::ms_bAutoCreate = true; -bool wxLog::ms_bVerbose = false; - -wxLogLevel wxLog::ms_logLevel = wxLOG_Max; // log everything by default - -size_t wxLog::ms_suspendCount = 0; - -const wxChar *wxLog::ms_timestamp = wxT("%X"); // time only, no date - -wxTraceMask wxLog::ms_ulTraceMask = (wxTraceMask)0; -wxArrayString wxLog::ms_aTraceMasks; - -// ---------------------------------------------------------------------------- -// stdout error logging helper -// ---------------------------------------------------------------------------- - -// helper function: wraps the message and justifies it under given position -// (looks more pretty on the terminal). Also adds newline at the end. -// -// TODO this is now disabled until I find a portable way of determining the -// terminal window size (ok, I found it but does anybody really cares?) -#ifdef LOG_PRETTY_WRAP -static void wxLogWrap(FILE *f, const char *pszPrefix, const char *psz) -{ - size_t nMax = 80; // FIXME - size_t nStart = strlen(pszPrefix); - fputs(pszPrefix, f); - - size_t n; - while ( *psz != '\0' ) { - for ( n = nStart; (n < nMax) && (*psz != '\0'); n++ ) - putc(*psz++, f); - - // wrapped? - if ( *psz != '\0' ) { - /*putc('\n', f);*/ - for ( n = 0; n < nStart; n++ ) - putc(' ', f); - - // as we wrapped, squeeze all white space - while ( isspace(*psz) ) - psz++; - } - } - - putc('\n', f); -} -#endif //LOG_PRETTY_WRAP - -// ---------------------------------------------------------------------------- -// error code/error message retrieval functions -// ---------------------------------------------------------------------------- - -// get error code from syste -unsigned long wxSysErrorCode() -{ -#if defined(__WXMSW__) && !defined(__WXMICROWIN__) - return ::GetLastError(); -#else //Unix - return errno; -#endif //Win/Unix -} - -// get error message from system -const wxChar *wxSysErrorMsg(unsigned long nErrCode) -{ - if ( nErrCode == 0 ) - nErrCode = wxSysErrorCode(); - -#if defined(__WXMSW__) && !defined(__WXMICROWIN__) - static wxChar s_szBuf[1024]; - - // get error message from system - LPVOID lpMsgBuf; - if ( ::FormatMessage - ( - FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, - NULL, - nErrCode, - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - (LPTSTR)&lpMsgBuf, - 0, - NULL - ) == 0 ) - { - // if this happens, something is seriously wrong, so don't use _() here - // for safety - wxSprintf(s_szBuf, _T("unknown error %lx"), nErrCode); - return s_szBuf; - } - - - // copy it to our buffer and free memory - // Crashes on SmartPhone (FIXME) -#if !defined(__SMARTPHONE__) /* of WinCE */ - if( lpMsgBuf != 0 ) - { - wxStrncpy(s_szBuf, (const wxChar *)lpMsgBuf, WXSIZEOF(s_szBuf) - 1); - s_szBuf[WXSIZEOF(s_szBuf) - 1] = wxT('\0'); - - LocalFree(lpMsgBuf); - - // returned string is capitalized and ended with '\r\n' - bad - s_szBuf[0] = (wxChar)wxTolower(s_szBuf[0]); - size_t len = wxStrlen(s_szBuf); - if ( len > 0 ) { - // truncate string - if ( s_szBuf[len - 2] == wxT('\r') ) - s_szBuf[len - 2] = wxT('\0'); - } - } - else -#endif // !__SMARTPHONE__ - { - s_szBuf[0] = wxT('\0'); - } - - return s_szBuf; -#else // !__WXMSW__ - #if wxUSE_UNICODE - static wchar_t s_wzBuf[1024]; - wxConvCurrent->MB2WC(s_wzBuf, strerror((int)nErrCode), - WXSIZEOF(s_wzBuf) - 1); - return s_wzBuf; - #else - return strerror((int)nErrCode); - #endif -#endif // __WXMSW__/!__WXMSW__ -} - -#endif // wxUSE_LOG +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/log.cpp +// Purpose: Assorted wxLogXXX functions, and wxLog (sink for logs) +// Author: Vadim Zeitlin +// Modified by: +// Created: 29/01/98 +// RCS-ID: $Id: log.cpp 50994 2008-01-02 21:27:31Z VZ $ +// Copyright: (c) 1998 Vadim Zeitlin +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_LOG + +// wxWidgets +#ifndef WX_PRECOMP + #include "wx/log.h" + #include "wx/app.h" + #include "wx/arrstr.h" + #include "wx/intl.h" + #include "wx/string.h" + #include "wx/utils.h" +#endif //WX_PRECOMP + +#include "wx/apptrait.h" +#include "wx/datetime.h" +#include "wx/file.h" +#include "wx/msgout.h" +#include "wx/textfile.h" +#include "wx/thread.h" +#include "wx/wxchar.h" + +// other standard headers +#ifndef __WXWINCE__ +#include +#endif + +#include + +#ifndef __WXWINCE__ +#include +#else +#include "wx/msw/wince/time.h" +#endif + +#if defined(__WINDOWS__) + #include "wx/msw/private.h" // includes windows.h +#endif + +// ---------------------------------------------------------------------------- +// non member functions +// ---------------------------------------------------------------------------- + +// define this to enable wrapping of log messages +//#define LOG_PRETTY_WRAP + +#ifdef LOG_PRETTY_WRAP + static void wxLogWrap(FILE *f, const char *pszPrefix, const char *psz); +#endif + +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// implementation of Log functions +// +// NB: unfortunately we need all these distinct functions, we can't make them +// macros and not all compilers inline vararg functions. +// ---------------------------------------------------------------------------- + +// generic log function +void wxVLogGeneric(wxLogLevel level, const wxChar *szFormat, va_list argptr) +{ + if ( wxLog::IsEnabled() ) { + wxLog::OnLog(level, wxString::FormatV(szFormat, argptr), time(NULL)); + } +} + +void wxLogGeneric(wxLogLevel level, const wxChar *szFormat, ...) +{ + va_list argptr; + va_start(argptr, szFormat); + wxVLogGeneric(level, szFormat, argptr); + va_end(argptr); +} + +#define IMPLEMENT_LOG_FUNCTION(level) \ + void wxVLog##level(const wxChar *szFormat, va_list argptr) \ + { \ + if ( wxLog::IsEnabled() ) { \ + wxLog::OnLog(wxLOG_##level, \ + wxString::FormatV(szFormat, argptr), time(NULL));\ + } \ + } \ + \ + void wxLog##level(const wxChar *szFormat, ...) \ + { \ + va_list argptr; \ + va_start(argptr, szFormat); \ + wxVLog##level(szFormat, argptr); \ + va_end(argptr); \ + } + +IMPLEMENT_LOG_FUNCTION(Error) +IMPLEMENT_LOG_FUNCTION(Warning) +IMPLEMENT_LOG_FUNCTION(Message) +IMPLEMENT_LOG_FUNCTION(Info) +IMPLEMENT_LOG_FUNCTION(Status) + +void wxSafeShowMessage(const wxString& title, const wxString& text) +{ +#ifdef __WINDOWS__ + ::MessageBox(NULL, text, title, MB_OK | MB_ICONSTOP); +#else + wxFprintf(stderr, _T("%s: %s\n"), title.c_str(), text.c_str()); + fflush(stderr); +#endif +} + +// fatal errors can't be suppressed nor handled by the custom log target and +// always terminate the program +void wxVLogFatalError(const wxChar *szFormat, va_list argptr) +{ + wxSafeShowMessage(_T("Fatal Error"), wxString::FormatV(szFormat, argptr)); + +#ifdef __WXWINCE__ + ExitThread(3); +#else + abort(); +#endif +} + +void wxLogFatalError(const wxChar *szFormat, ...) +{ + va_list argptr; + va_start(argptr, szFormat); + wxVLogFatalError(szFormat, argptr); + + // some compilers warn about unreachable code and it shouldn't matter + // for the others anyhow... + //va_end(argptr); +} + +// same as info, but only if 'verbose' mode is on +void wxVLogVerbose(const wxChar *szFormat, va_list argptr) +{ + if ( wxLog::IsEnabled() ) { + if ( wxLog::GetActiveTarget() != NULL && wxLog::GetVerbose() ) { + wxLog::OnLog(wxLOG_Info, + wxString::FormatV(szFormat, argptr), time(NULL)); + } + } +} + +void wxLogVerbose(const wxChar *szFormat, ...) +{ + va_list argptr; + va_start(argptr, szFormat); + wxVLogVerbose(szFormat, argptr); + va_end(argptr); +} + +// debug functions +#ifdef __WXDEBUG__ +#define IMPLEMENT_LOG_DEBUG_FUNCTION(level) \ + void wxVLog##level(const wxChar *szFormat, va_list argptr) \ + { \ + if ( wxLog::IsEnabled() ) { \ + wxLog::OnLog(wxLOG_##level, \ + wxString::FormatV(szFormat, argptr), time(NULL));\ + } \ + } \ + \ + void wxLog##level(const wxChar *szFormat, ...) \ + { \ + va_list argptr; \ + va_start(argptr, szFormat); \ + wxVLog##level(szFormat, argptr); \ + va_end(argptr); \ + } + + void wxVLogTrace(const wxChar *mask, const wxChar *szFormat, va_list argptr) + { + if ( wxLog::IsEnabled() && wxLog::IsAllowedTraceMask(mask) ) { + wxString msg; + msg << _T("(") << mask << _T(") ") << wxString::FormatV(szFormat, argptr); + + wxLog::OnLog(wxLOG_Trace, msg, time(NULL)); + } + } + + void wxLogTrace(const wxChar *mask, const wxChar *szFormat, ...) + { + va_list argptr; + va_start(argptr, szFormat); + wxVLogTrace(mask, szFormat, argptr); + va_end(argptr); + } + + void wxVLogTrace(wxTraceMask mask, const wxChar *szFormat, va_list argptr) + { + // we check that all of mask bits are set in the current mask, so + // that wxLogTrace(wxTraceRefCount | wxTraceOle) will only do something + // if both bits are set. + if ( wxLog::IsEnabled() && ((wxLog::GetTraceMask() & mask) == mask) ) { + wxLog::OnLog(wxLOG_Trace, wxString::FormatV(szFormat, argptr), time(NULL)); + } + } + + void wxLogTrace(wxTraceMask mask, const wxChar *szFormat, ...) + { + va_list argptr; + va_start(argptr, szFormat); + wxVLogTrace(mask, szFormat, argptr); + va_end(argptr); + } + +#else // release + #define IMPLEMENT_LOG_DEBUG_FUNCTION(level) +#endif + +IMPLEMENT_LOG_DEBUG_FUNCTION(Debug) +IMPLEMENT_LOG_DEBUG_FUNCTION(Trace) + +// wxLogSysError: one uses the last error code, for other you must give it +// explicitly + +// return the system error message description +static inline wxString wxLogSysErrorHelper(long err) +{ + return wxString::Format(_(" (error %ld: %s)"), err, wxSysErrorMsg(err)); +} + +void WXDLLEXPORT wxVLogSysError(const wxChar *szFormat, va_list argptr) +{ + wxVLogSysError(wxSysErrorCode(), szFormat, argptr); +} + +void WXDLLEXPORT wxLogSysError(const wxChar *szFormat, ...) +{ + va_list argptr; + va_start(argptr, szFormat); + wxVLogSysError(szFormat, argptr); + va_end(argptr); +} + +void WXDLLEXPORT wxVLogSysError(long err, const wxChar *fmt, va_list argptr) +{ + if ( wxLog::IsEnabled() ) { + wxLog::OnLog(wxLOG_Error, + wxString::FormatV(fmt, argptr) + wxLogSysErrorHelper(err), + time(NULL)); + } +} + +void WXDLLEXPORT wxLogSysError(long lErrCode, const wxChar *szFormat, ...) +{ + va_list argptr; + va_start(argptr, szFormat); + wxVLogSysError(lErrCode, szFormat, argptr); + va_end(argptr); +} + +// ---------------------------------------------------------------------------- +// wxLog class implementation +// ---------------------------------------------------------------------------- + +// define a critical section gs_prevCS protecting access to wxLog::ms_prevXXX +wxCRIT_SECT_DECLARE(gs_prevCS); + +/* static */ +unsigned wxLog::DoLogNumberOfRepeats() +{ + wxLog * const pLogger = GetActiveTarget(); + return pLogger ? pLogger->LogLastRepeatIfNeeded() : 0u; +} + +unsigned wxLog::LogLastRepeatIfNeeded() +{ + wxCRIT_SECT_LOCKER(lock, gs_prevCS); + + return LogLastRepeatIfNeededUnlocked(); +} + +unsigned wxLog::LogLastRepeatIfNeededUnlocked() +{ + long retval = ms_prevCounter; + if ( ms_prevCounter > 0 ) + { + wxString msg; +#if wxUSE_INTL + msg.Printf(wxPLURAL("The previous message repeated once.", + "The previous message repeated %lu times.", + ms_prevCounter), + ms_prevCounter); +#else + msg.Printf(wxT("The previous message was repeated.")); +#endif + ms_prevCounter = 0; + ms_prevString.clear(); + DoLog(ms_prevLevel, msg.c_str(), ms_prevTimeStamp); + } + return retval; +} + +wxLog::~wxLog() +{ +} + +/* static */ +void wxLog::OnLog(wxLogLevel level, const wxChar *szString, time_t t) +{ + if ( IsEnabled() && ms_logLevel >= level ) + { + wxLog *pLogger = GetActiveTarget(); + if ( pLogger ) + { + if ( GetRepetitionCounting() ) + { + wxCRIT_SECT_LOCKER(lock, gs_prevCS); + + if ( szString == ms_prevString ) + { + ms_prevCounter++; + + // nothing else to do, in particular, don't log the + // repeated message + return; + } + + pLogger->LogLastRepeatIfNeededUnlocked(); + + // reset repetition counter for a new message + ms_prevString = szString; + ms_prevLevel = level; + ms_prevTimeStamp = t; + } + + pLogger->DoLog(level, szString, t); + } + } +} + +// deprecated function +#if WXWIN_COMPATIBILITY_2_6 + +wxChar *wxLog::SetLogBuffer(wxChar * WXUNUSED(buf), size_t WXUNUSED(size)) +{ + return NULL; +} + +#endif // WXWIN_COMPATIBILITY_2_6 + +wxLog *wxLog::GetActiveTarget() +{ + if ( ms_bAutoCreate && ms_pLogger == NULL ) { + // prevent infinite recursion if someone calls wxLogXXX() from + // wxApp::CreateLogTarget() + static bool s_bInGetActiveTarget = false; + if ( !s_bInGetActiveTarget ) { + s_bInGetActiveTarget = true; + + // ask the application to create a log target for us + if ( wxTheApp != NULL ) + ms_pLogger = wxTheApp->GetTraits()->CreateLogTarget(); + else + ms_pLogger = new wxLogStderr; + + s_bInGetActiveTarget = false; + + // do nothing if it fails - what can we do? + } + } + + return ms_pLogger; +} + +wxLog *wxLog::SetActiveTarget(wxLog *pLogger) +{ + if ( ms_pLogger != NULL ) { + // flush the old messages before changing because otherwise they might + // get lost later if this target is not restored + ms_pLogger->Flush(); + } + + wxLog *pOldLogger = ms_pLogger; + ms_pLogger = pLogger; + + return pOldLogger; +} + +void wxLog::DontCreateOnDemand() +{ + ms_bAutoCreate = false; + + // this is usually called at the end of the program and we assume that it + // is *always* called at the end - so we free memory here to avoid false + // memory leak reports from wxWin memory tracking code + ClearTraceMasks(); +} + +void wxLog::DoCreateOnDemand() +{ + ms_bAutoCreate = true; +} + +void wxLog::RemoveTraceMask(const wxString& str) +{ + int index = ms_aTraceMasks.Index(str); + if ( index != wxNOT_FOUND ) + ms_aTraceMasks.RemoveAt((size_t)index); +} + +void wxLog::ClearTraceMasks() +{ + ms_aTraceMasks.Clear(); +} + +void wxLog::TimeStamp(wxString *str) +{ +#if wxUSE_DATETIME + if ( ms_timestamp ) + { + wxChar buf[256]; + time_t timeNow; + (void)time(&timeNow); + + struct tm tm; + wxStrftime(buf, WXSIZEOF(buf), + ms_timestamp, wxLocaltime_r(&timeNow, &tm)); + + str->Empty(); + *str << buf << wxT(": "); + } +#endif // wxUSE_DATETIME +} + +void wxLog::DoLog(wxLogLevel level, const wxChar *szString, time_t t) +{ + switch ( level ) { + case wxLOG_FatalError: + DoLogString(wxString(_("Fatal error: ")) + szString, t); + DoLogString(_("Program aborted."), t); + Flush(); +#ifdef __WXWINCE__ + ExitThread(3); +#else + abort(); +#endif + break; + + case wxLOG_Error: + DoLogString(wxString(_("Error: ")) + szString, t); + break; + + case wxLOG_Warning: + DoLogString(wxString(_("Warning: ")) + szString, t); + break; + + case wxLOG_Info: + if ( GetVerbose() ) + case wxLOG_Message: + case wxLOG_Status: + default: // log unknown log levels too + DoLogString(szString, t); + break; + + case wxLOG_Trace: + case wxLOG_Debug: +#ifdef __WXDEBUG__ + { + wxString msg = level == wxLOG_Trace ? wxT("Trace: ") + : wxT("Debug: "); + msg << szString; + DoLogString(msg, t); + } +#endif // Debug + break; + } +} + +void wxLog::DoLogString(const wxChar *WXUNUSED(szString), time_t WXUNUSED(t)) +{ + wxFAIL_MSG(wxT("DoLogString must be overriden if it's called.")); +} + +void wxLog::Flush() +{ + LogLastRepeatIfNeeded(); +} + +/*static*/ bool wxLog::IsAllowedTraceMask(const wxChar *mask) +{ + for ( wxArrayString::iterator it = ms_aTraceMasks.begin(), + en = ms_aTraceMasks.end(); + it != en; ++it ) + if ( *it == mask) + return true; + return false; +} + +// ---------------------------------------------------------------------------- +// wxLogBuffer implementation +// ---------------------------------------------------------------------------- + +void wxLogBuffer::Flush() +{ + if ( !m_str.empty() ) + { + wxMessageOutputBest out; + out.Printf(_T("%s"), m_str.c_str()); + m_str.clear(); + } +} + +void wxLogBuffer::DoLog(wxLogLevel level, const wxChar *szString, time_t t) +{ + switch ( level ) + { + case wxLOG_Trace: + case wxLOG_Debug: +#ifdef __WXDEBUG__ + // don't put debug messages in the buffer, we don't want to show + // them to the user in a msg box, log them immediately + { + wxString str; + TimeStamp(&str); + str += szString; + + wxMessageOutputDebug dbgout; + dbgout.Printf(_T("%s\n"), str.c_str()); + } +#endif // __WXDEBUG__ + break; + + default: + wxLog::DoLog(level, szString, t); + } +} + +void wxLogBuffer::DoLogString(const wxChar *szString, time_t WXUNUSED(t)) +{ + m_str << szString << _T("\n"); +} + +// ---------------------------------------------------------------------------- +// wxLogStderr class implementation +// ---------------------------------------------------------------------------- + +wxLogStderr::wxLogStderr(FILE *fp) +{ + if ( fp == NULL ) + m_fp = stderr; + else + m_fp = fp; +} + +void wxLogStderr::DoLogString(const wxChar *szString, time_t WXUNUSED(t)) +{ + wxString str; + TimeStamp(&str); + str << szString; + + wxFputs(str, m_fp); + wxFputc(_T('\n'), m_fp); + fflush(m_fp); + + // under GUI systems such as Windows or Mac, programs usually don't have + // stderr at all, so show the messages also somewhere else, typically in + // the debugger window so that they go at least somewhere instead of being + // simply lost + if ( m_fp == stderr ) + { + wxAppTraits *traits = wxTheApp ? wxTheApp->GetTraits() : NULL; + if ( traits && !traits->HasStderr() ) + { + wxMessageOutputDebug dbgout; + dbgout.Printf(_T("%s\n"), str.c_str()); + } + } +} + +// ---------------------------------------------------------------------------- +// wxLogStream implementation +// ---------------------------------------------------------------------------- + +#if wxUSE_STD_IOSTREAM +#include "wx/ioswrap.h" +wxLogStream::wxLogStream(wxSTD ostream *ostr) +{ + if ( ostr == NULL ) + m_ostr = &wxSTD cerr; + else + m_ostr = ostr; +} + +void wxLogStream::DoLogString(const wxChar *szString, time_t WXUNUSED(t)) +{ + wxString str; + TimeStamp(&str); + (*m_ostr) << wxSafeConvertWX2MB(str) << wxSafeConvertWX2MB(szString) << wxSTD endl; +} +#endif // wxUSE_STD_IOSTREAM + +// ---------------------------------------------------------------------------- +// wxLogChain +// ---------------------------------------------------------------------------- + +wxLogChain::wxLogChain(wxLog *logger) +{ + m_bPassMessages = true; + + m_logNew = logger; + m_logOld = wxLog::SetActiveTarget(this); +} + +wxLogChain::~wxLogChain() +{ + delete m_logOld; + + if ( m_logNew != this ) + delete m_logNew; +} + +void wxLogChain::SetLog(wxLog *logger) +{ + if ( m_logNew != this ) + delete m_logNew; + + m_logNew = logger; +} + +void wxLogChain::Flush() +{ + if ( m_logOld ) + m_logOld->Flush(); + + // be careful to avoid infinite recursion + if ( m_logNew && m_logNew != this ) + m_logNew->Flush(); +} + +void wxLogChain::DoLog(wxLogLevel level, const wxChar *szString, time_t t) +{ + // let the previous logger show it + if ( m_logOld && IsPassingMessages() ) + { + // bogus cast just to access protected DoLog + ((wxLogChain *)m_logOld)->DoLog(level, szString, t); + } + + if ( m_logNew && m_logNew != this ) + { + // as above... + ((wxLogChain *)m_logNew)->DoLog(level, szString, t); + } +} + +// ---------------------------------------------------------------------------- +// wxLogPassThrough +// ---------------------------------------------------------------------------- + +#ifdef __VISUALC__ + // "'this' : used in base member initializer list" - so what? + #pragma warning(disable:4355) +#endif // VC++ + +wxLogPassThrough::wxLogPassThrough() + : wxLogChain(this) +{ +} + +#ifdef __VISUALC__ + #pragma warning(default:4355) +#endif // VC++ + +// ============================================================================ +// Global functions/variables +// ============================================================================ + +// ---------------------------------------------------------------------------- +// static variables +// ---------------------------------------------------------------------------- + +bool wxLog::ms_bRepetCounting = false; +wxString wxLog::ms_prevString; +unsigned int wxLog::ms_prevCounter = 0; +time_t wxLog::ms_prevTimeStamp= 0; +wxLogLevel wxLog::ms_prevLevel; + +wxLog *wxLog::ms_pLogger = (wxLog *)NULL; +bool wxLog::ms_doLog = true; +bool wxLog::ms_bAutoCreate = true; +bool wxLog::ms_bVerbose = false; + +wxLogLevel wxLog::ms_logLevel = wxLOG_Max; // log everything by default + +size_t wxLog::ms_suspendCount = 0; + +const wxChar *wxLog::ms_timestamp = wxT("%X"); // time only, no date + +wxTraceMask wxLog::ms_ulTraceMask = (wxTraceMask)0; +wxArrayString wxLog::ms_aTraceMasks; + +// ---------------------------------------------------------------------------- +// stdout error logging helper +// ---------------------------------------------------------------------------- + +// helper function: wraps the message and justifies it under given position +// (looks more pretty on the terminal). Also adds newline at the end. +// +// TODO this is now disabled until I find a portable way of determining the +// terminal window size (ok, I found it but does anybody really cares?) +#ifdef LOG_PRETTY_WRAP +static void wxLogWrap(FILE *f, const char *pszPrefix, const char *psz) +{ + size_t nMax = 80; // FIXME + size_t nStart = strlen(pszPrefix); + fputs(pszPrefix, f); + + size_t n; + while ( *psz != '\0' ) { + for ( n = nStart; (n < nMax) && (*psz != '\0'); n++ ) + putc(*psz++, f); + + // wrapped? + if ( *psz != '\0' ) { + /*putc('\n', f);*/ + for ( n = 0; n < nStart; n++ ) + putc(' ', f); + + // as we wrapped, squeeze all white space + while ( isspace(*psz) ) + psz++; + } + } + + putc('\n', f); +} +#endif //LOG_PRETTY_WRAP + +// ---------------------------------------------------------------------------- +// error code/error message retrieval functions +// ---------------------------------------------------------------------------- + +// get error code from syste +unsigned long wxSysErrorCode() +{ +#if defined(__WXMSW__) && !defined(__WXMICROWIN__) + return ::GetLastError(); +#else //Unix + return errno; +#endif //Win/Unix +} + +// get error message from system +const wxChar *wxSysErrorMsg(unsigned long nErrCode) +{ + if ( nErrCode == 0 ) + nErrCode = wxSysErrorCode(); + +#if defined(__WXMSW__) && !defined(__WXMICROWIN__) + static wxChar s_szBuf[1024]; + + // get error message from system + LPVOID lpMsgBuf; + if ( ::FormatMessage + ( + FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, + NULL, + nErrCode, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPTSTR)&lpMsgBuf, + 0, + NULL + ) == 0 ) + { + // if this happens, something is seriously wrong, so don't use _() here + // for safety + wxSprintf(s_szBuf, _T("unknown error %lx"), nErrCode); + return s_szBuf; + } + + + // copy it to our buffer and free memory + // Crashes on SmartPhone (FIXME) +#if !defined(__SMARTPHONE__) /* of WinCE */ + if( lpMsgBuf != 0 ) + { + wxStrncpy(s_szBuf, (const wxChar *)lpMsgBuf, WXSIZEOF(s_szBuf) - 1); + s_szBuf[WXSIZEOF(s_szBuf) - 1] = wxT('\0'); + + LocalFree(lpMsgBuf); + + // returned string is capitalized and ended with '\r\n' - bad + s_szBuf[0] = (wxChar)wxTolower(s_szBuf[0]); + size_t len = wxStrlen(s_szBuf); + if ( len > 0 ) { + // truncate string + if ( s_szBuf[len - 2] == wxT('\r') ) + s_szBuf[len - 2] = wxT('\0'); + } + } + else +#endif // !__SMARTPHONE__ + { + s_szBuf[0] = wxT('\0'); + } + + return s_szBuf; +#else // !__WXMSW__ + #if wxUSE_UNICODE + static wchar_t s_wzBuf[1024]; + wxConvCurrent->MB2WC(s_wzBuf, strerror((int)nErrCode), + WXSIZEOF(s_wzBuf) - 1); + return s_wzBuf; + #else + return strerror((int)nErrCode); + #endif +#endif // __WXMSW__/!__WXMSW__ +} + +#endif // wxUSE_LOG diff --git a/Externals/wxWidgets/src/common/longlong.cpp b/Externals/wxWidgets/src/common/longlong.cpp index af121be815..78a47ce25d 100644 --- a/Externals/wxWidgets/src/common/longlong.cpp +++ b/Externals/wxWidgets/src/common/longlong.cpp @@ -1,1363 +1,1363 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/longlong.cpp -// Purpose: implementation of wxLongLongNative -// Author: Jeffrey C. Ollie , Vadim Zeitlin -// Remarks: this class is not public in wxWidgets 2.0! It is intentionally -// not documented and is for private use only. -// Modified by: -// Created: 10.02.99 -// RCS-ID: $Id: longlong.cpp 40750 2006-08-22 19:04:45Z MW $ -// Copyright: (c) 1998 Vadim Zeitlin -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// headers -// ============================================================================ - -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_LONGLONG - -#include "wx/longlong.h" - -#ifndef WX_PRECOMP - #include "wx/math.h" // for fabs() -#endif - -#if wxUSE_STREAMS - #include "wx/txtstrm.h" -#endif - -#include // for memset() - -#include "wx/ioswrap.h" - -// ============================================================================ -// implementation -// ============================================================================ - -#if wxUSE_LONGLONG_NATIVE - -// ---------------------------------------------------------------------------- -// misc -// ---------------------------------------------------------------------------- - -void *wxLongLongNative::asArray() const -{ - static unsigned char temp[8]; - - temp[0] = wx_truncate_cast(unsigned char, ((m_ll >> 56) & 0xFF)); - temp[1] = wx_truncate_cast(unsigned char, ((m_ll >> 48) & 0xFF)); - temp[2] = wx_truncate_cast(unsigned char, ((m_ll >> 40) & 0xFF)); - temp[3] = wx_truncate_cast(unsigned char, ((m_ll >> 32) & 0xFF)); - temp[4] = wx_truncate_cast(unsigned char, ((m_ll >> 24) & 0xFF)); - temp[5] = wx_truncate_cast(unsigned char, ((m_ll >> 16) & 0xFF)); - temp[6] = wx_truncate_cast(unsigned char, ((m_ll >> 8) & 0xFF)); - temp[7] = wx_truncate_cast(unsigned char, ((m_ll >> 0) & 0xFF)); - - return temp; -} - -void *wxULongLongNative::asArray() const -{ - static unsigned char temp[8]; - - temp[0] = wx_truncate_cast(unsigned char, ((m_ll >> 56) & 0xFF)); - temp[1] = wx_truncate_cast(unsigned char, ((m_ll >> 48) & 0xFF)); - temp[2] = wx_truncate_cast(unsigned char, ((m_ll >> 40) & 0xFF)); - temp[3] = wx_truncate_cast(unsigned char, ((m_ll >> 32) & 0xFF)); - temp[4] = wx_truncate_cast(unsigned char, ((m_ll >> 24) & 0xFF)); - temp[5] = wx_truncate_cast(unsigned char, ((m_ll >> 16) & 0xFF)); - temp[6] = wx_truncate_cast(unsigned char, ((m_ll >> 8) & 0xFF)); - temp[7] = wx_truncate_cast(unsigned char, ((m_ll >> 0) & 0xFF)); - - return temp; -} - -#if wxUSE_LONGLONG_WX -wxLongLongNative::wxLongLongNative(wxLongLongWx ll) -{ - // assign first to avoid precision loss! - m_ll = ll.GetHi(); - m_ll <<= 32; - m_ll |= ll.GetLo(); -} - -wxLongLongNative& wxLongLongNative::operator=(wxLongLongWx ll) -{ - // assign first to avoid precision loss! - m_ll = ll.GetHi(); - m_ll <<= 32; - m_ll |= ll.GetLo(); - return *this; -} - -wxLongLongNative& wxLongLongNative::operator=(const class wxULongLongWx &ll) -{ - // assign first to avoid precision loss! - m_ll = ll.GetHi(); - m_ll <<= 32; - m_ll |= ll.GetLo(); - return *this; -} - -wxULongLongNative::wxULongLongNative(const class wxULongLongWx &ll) -{ - // assign first to avoid precision loss! - m_ll = ll.GetHi(); - m_ll <<= 32; - m_ll |= ((unsigned long) ll.GetLo()); -} - -wxULongLongNative& wxULongLongNative::operator=(wxLongLongWx ll) -{ - // assign first to avoid precision loss! - m_ll = ll.GetHi(); - m_ll <<= 32; - m_ll |= ((unsigned long) ll.GetLo()); - return *this; -} - -wxULongLongNative& wxULongLongNative::operator=(const class wxULongLongWx &ll) -{ - // assign first to avoid precision loss! - m_ll = ll.GetHi(); - m_ll <<= 32; - m_ll |= ((unsigned long) ll.GetLo()); - return *this; -} -#endif - -#endif // wxUSE_LONGLONG_NATIVE - -// ============================================================================ -// wxLongLongWx: emulation of 'long long' using 2 longs -// ============================================================================ - -#if wxUSE_LONGLONG_WX - -// Set value from unsigned wxULongLongWx -wxLongLongWx &wxLongLongWx::operator=(const class wxULongLongWx &ll) -{ - m_hi = (unsigned long) ll.GetHi(); - m_lo = ll.GetLo(); - return *this; -} - -// assignment -wxLongLongWx& wxLongLongWx::Assign(double d) -{ - bool positive = d >= 0; - d = fabs(d); - if ( d <= ULONG_MAX ) - { - m_hi = 0; - m_lo = (long)d; - } - else - { - m_hi = (unsigned long)(d / (1.0 + (double)ULONG_MAX)); - m_lo = (unsigned long)(d - ((double)m_hi * (1.0 + (double)ULONG_MAX))); - } - -#ifdef wxLONGLONG_TEST_MODE - m_ll = (wxLongLong_t)d; - - Check(); -#endif // wxLONGLONG_TEST_MODE - - if ( !positive ) - Negate(); - - return *this; -} - -double wxLongLongWx::ToDouble() const -{ - double d = m_hi; - d *= 1.0 + (double)ULONG_MAX; - d += m_lo; - -#ifdef wxLONGLONG_TEST_MODE - wxASSERT( d == m_ll ); -#endif // wxLONGLONG_TEST_MODE - - return d; -} - -double wxULongLongWx::ToDouble() const -{ - unsigned double d = m_hi; - d *= 1.0 + (double)ULONG_MAX; - d += m_lo; - -#ifdef wxLONGLONG_TEST_MODE - wxASSERT( d == m_ll ); -#endif // wxLONGLONG_TEST_MODE - - return d; -} - -wxLongLongWx wxLongLongWx::operator<<(int shift) const -{ - wxLongLongWx ll(*this); - ll <<= shift; - - return ll; -} - -wxULongLongWx wxULongLongWx::operator<<(int shift) const -{ - wxULongLongWx ll(*this); - ll <<= shift; - - return ll; -} - -wxLongLongWx& wxLongLongWx::operator<<=(int shift) -{ - if (shift != 0) - { - if (shift < 32) - { - m_hi <<= shift; - m_hi |= m_lo >> (32 - shift); - m_lo <<= shift; - } - else - { - m_hi = m_lo << (shift - 32); - m_lo = 0; - } - } - -#ifdef wxLONGLONG_TEST_MODE - m_ll <<= shift; - - Check(); -#endif // wxLONGLONG_TEST_MODE - - return *this; -} - -wxULongLongWx& wxULongLongWx::operator<<=(int shift) -{ - if (shift != 0) - { - if (shift < 32) - { - m_hi <<= shift; - m_hi |= m_lo >> (32 - shift); - m_lo <<= shift; - } - else - { - m_hi = m_lo << (shift - 32); - m_lo = 0; - } - } - -#ifdef wxLONGLONG_TEST_MODE - m_ll <<= shift; - - Check(); -#endif // wxLONGLONG_TEST_MODE - - return *this; -} - -wxLongLongWx wxLongLongWx::operator>>(int shift) const -{ - wxLongLongWx ll(*this); - ll >>= shift; - - return ll; -} - -wxULongLongWx wxULongLongWx::operator>>(int shift) const -{ - wxULongLongWx ll(*this); - ll >>= shift; - - return ll; -} - -wxLongLongWx& wxLongLongWx::operator>>=(int shift) -{ - if (shift != 0) - { - if (shift < 32) - { - m_lo >>= shift; - m_lo |= m_hi << (32 - shift); - m_hi >>= shift; - } - else - { - m_lo = m_hi >> (shift - 32); - m_hi = (m_hi < 0 ? -1L : 0); - } - } - -#ifdef wxLONGLONG_TEST_MODE - m_ll >>= shift; - - Check(); -#endif // wxLONGLONG_TEST_MODE - - return *this; -} - -wxULongLongWx& wxULongLongWx::operator>>=(int shift) -{ - if (shift != 0) - { - if (shift < 32) - { - m_lo >>= shift; - m_lo |= m_hi << (32 - shift); - m_hi >>= shift; - } - else - { - m_lo = m_hi >> (shift - 32); - m_hi = 0; - } - } - -#ifdef wxLONGLONG_TEST_MODE - m_ll >>= shift; - - Check(); -#endif // wxLONGLONG_TEST_MODE - - return *this; -} - -wxLongLongWx wxLongLongWx::operator+(const wxLongLongWx& ll) const -{ - wxLongLongWx res(*this); - res += ll; - - return res; -} - -wxULongLongWx wxULongLongWx::operator+(const wxULongLongWx& ll) const -{ - wxULongLongWx res(*this); - res += ll; - - return res; -} - -wxLongLongWx wxLongLongWx::operator+(long l) const -{ - wxLongLongWx res(*this); - res += l; - - return res; -} - -wxULongLongWx wxULongLongWx::operator+(unsigned long l) const -{ - wxULongLongWx res(*this); - res += l; - - return res; -} - -wxLongLongWx& wxLongLongWx::operator+=(const wxLongLongWx& ll) -{ - unsigned long previous = m_lo; - - m_lo += ll.m_lo; - m_hi += ll.m_hi; - - if ((m_lo < previous) || (m_lo < ll.m_lo)) - m_hi++; - -#ifdef wxLONGLONG_TEST_MODE - m_ll += ll.m_ll; - - Check(); -#endif // wxLONGLONG_TEST_MODE - - return *this; -} - -wxULongLongWx& wxULongLongWx::operator+=(const wxULongLongWx& ll) -{ - unsigned long previous = m_lo; - - m_lo += ll.m_lo; - m_hi += ll.m_hi; - - if ((m_lo < previous) || (m_lo < ll.m_lo)) - m_hi++; - -#ifdef wxLONGLONG_TEST_MODE - m_ll += ll.m_ll; - - Check(); -#endif // wxLONGLONG_TEST_MODE - - return *this; -} - -wxLongLongWx& wxLongLongWx::operator+=(long l) -{ - unsigned long previous = m_lo; - - m_lo += l; - if (l < 0) - m_hi += -1l; - - if ((m_lo < previous) || (m_lo < (unsigned long)l)) - m_hi++; - -#ifdef wxLONGLONG_TEST_MODE - m_ll += l; - - Check(); -#endif // wxLONGLONG_TEST_MODE - - return *this; -} - -wxULongLongWx& wxULongLongWx::operator+=(unsigned long l) -{ - unsigned long previous = m_lo; - - m_lo += l; - - if ((m_lo < previous) || (m_lo < l)) - m_hi++; - -#ifdef wxLONGLONG_TEST_MODE - m_ll += l; - - Check(); -#endif // wxLONGLONG_TEST_MODE - - return *this; -} - -// pre increment -wxLongLongWx& wxLongLongWx::operator++() -{ - m_lo++; - if (m_lo == 0) - m_hi++; - -#ifdef wxLONGLONG_TEST_MODE - m_ll++; - - Check(); -#endif // wxLONGLONG_TEST_MODE - - return *this; -} - -wxULongLongWx& wxULongLongWx::operator++() -{ - m_lo++; - if (m_lo == 0) - m_hi++; - -#ifdef wxLONGLONG_TEST_MODE - m_ll++; - - Check(); -#endif // wxLONGLONG_TEST_MODE - - return *this; -} - -// negation -wxLongLongWx wxLongLongWx::operator-() const -{ - wxLongLongWx res(*this); - res.Negate(); - - return res; -} - -wxLongLongWx& wxLongLongWx::Negate() -{ - m_hi = ~m_hi; - m_lo = ~m_lo; - - m_lo++; - if ( m_lo == 0 ) - m_hi++; - -#ifdef wxLONGLONG_TEST_MODE - m_ll = -m_ll; - - Check(); -#endif // wxLONGLONG_TEST_MODE - - return *this; -} - -// subtraction - -wxLongLongWx wxLongLongWx::operator-(const wxLongLongWx& ll) const -{ - wxLongLongWx res(*this); - res -= ll; - - return res; -} - -wxLongLongWx wxULongLongWx::operator-(const wxULongLongWx& ll) const -{ - wxASSERT(m_hi <= LONG_MAX ); - wxASSERT(ll.m_hi <= LONG_MAX ); - - wxLongLongWx res( (long)m_hi , m_lo ); - wxLongLongWx op( (long)ll.m_hi , ll.m_lo ); - res -= op; - - return res; -} - -wxLongLongWx& wxLongLongWx::operator-=(const wxLongLongWx& ll) -{ - unsigned long previous = m_lo; - - m_lo -= ll.m_lo; - m_hi -= ll.m_hi; - - if (previous < ll.m_lo) - m_hi--; - -#ifdef wxLONGLONG_TEST_MODE - m_ll -= ll.m_ll; - - Check(); -#endif // wxLONGLONG_TEST_MODE - - return *this; -} - -wxULongLongWx& wxULongLongWx::operator-=(const wxULongLongWx& ll) -{ - unsigned long previous = m_lo; - - m_lo -= ll.m_lo; - m_hi -= ll.m_hi; - - if (previous < ll.m_lo) - m_hi--; - -#ifdef wxLONGLONG_TEST_MODE - m_ll -= ll.m_ll; - - Check(); -#endif // wxLONGLONG_TEST_MODE - - return *this; -} - -// pre decrement -wxLongLongWx& wxLongLongWx::operator--() -{ - m_lo--; - if (m_lo == 0xFFFFFFFF) - m_hi--; - -#ifdef wxLONGLONG_TEST_MODE - m_ll--; - - Check(); -#endif // wxLONGLONG_TEST_MODE - - return *this; -} - -wxULongLongWx& wxULongLongWx::operator--() -{ - m_lo--; - if (m_lo == 0xFFFFFFFF) - m_hi--; - -#ifdef wxLONGLONG_TEST_MODE - m_ll--; - - Check(); -#endif // wxLONGLONG_TEST_MODE - - return *this; -} - -// comparison operators - -bool wxLongLongWx::operator<(const wxLongLongWx& ll) const -{ - if ( m_hi < ll.m_hi ) - return true; - else if ( m_hi == ll.m_hi ) - return m_lo < ll.m_lo; - else - return false; -} - -bool wxULongLongWx::operator<(const wxULongLongWx& ll) const -{ - if ( m_hi < ll.m_hi ) - return true; - else if ( m_hi == ll.m_hi ) - return m_lo < ll.m_lo; - else - return false; -} - -bool wxLongLongWx::operator>(const wxLongLongWx& ll) const -{ - if ( m_hi > ll.m_hi ) - return true; - else if ( m_hi == ll.m_hi ) - return m_lo > ll.m_lo; - else - return false; -} - -bool wxULongLongWx::operator>(const wxULongLongWx& ll) const -{ - if ( m_hi > ll.m_hi ) - return true; - else if ( m_hi == ll.m_hi ) - return m_lo > ll.m_lo; - else - return false; -} - -// bitwise operators - -wxLongLongWx wxLongLongWx::operator&(const wxLongLongWx& ll) const -{ - return wxLongLongWx(m_hi & ll.m_hi, m_lo & ll.m_lo); -} - -wxULongLongWx wxULongLongWx::operator&(const wxULongLongWx& ll) const -{ - return wxULongLongWx(m_hi & ll.m_hi, m_lo & ll.m_lo); -} - -wxLongLongWx wxLongLongWx::operator|(const wxLongLongWx& ll) const -{ - return wxLongLongWx(m_hi | ll.m_hi, m_lo | ll.m_lo); -} - -wxULongLongWx wxULongLongWx::operator|(const wxULongLongWx& ll) const -{ - return wxULongLongWx(m_hi | ll.m_hi, m_lo | ll.m_lo); -} - -wxLongLongWx wxLongLongWx::operator^(const wxLongLongWx& ll) const -{ - return wxLongLongWx(m_hi ^ ll.m_hi, m_lo ^ ll.m_lo); -} - -wxULongLongWx wxULongLongWx::operator^(const wxULongLongWx& ll) const -{ - return wxULongLongWx(m_hi ^ ll.m_hi, m_lo ^ ll.m_lo); -} - -wxLongLongWx& wxLongLongWx::operator&=(const wxLongLongWx& ll) -{ - m_lo &= ll.m_lo; - m_hi &= ll.m_hi; - -#ifdef wxLONGLONG_TEST_MODE - m_ll &= ll.m_ll; - - Check(); -#endif // wxLONGLONG_TEST_MODE - - return *this; -} - -wxULongLongWx& wxULongLongWx::operator&=(const wxULongLongWx& ll) -{ - m_lo &= ll.m_lo; - m_hi &= ll.m_hi; - -#ifdef wxLONGLONG_TEST_MODE - m_ll &= ll.m_ll; - - Check(); -#endif // wxLONGLONG_TEST_MODE - - return *this; -} - -wxLongLongWx& wxLongLongWx::operator|=(const wxLongLongWx& ll) -{ - m_lo |= ll.m_lo; - m_hi |= ll.m_hi; - -#ifdef wxLONGLONG_TEST_MODE - m_ll |= ll.m_ll; - - Check(); -#endif // wxLONGLONG_TEST_MODE - - return *this; -} - -wxULongLongWx& wxULongLongWx::operator|=(const wxULongLongWx& ll) -{ - m_lo |= ll.m_lo; - m_hi |= ll.m_hi; - -#ifdef wxLONGLONG_TEST_MODE - m_ll |= ll.m_ll; - - Check(); -#endif // wxLONGLONG_TEST_MODE - - return *this; -} - -wxLongLongWx& wxLongLongWx::operator^=(const wxLongLongWx& ll) -{ - m_lo ^= ll.m_lo; - m_hi ^= ll.m_hi; - -#ifdef wxLONGLONG_TEST_MODE - m_ll ^= ll.m_ll; - - Check(); -#endif // wxLONGLONG_TEST_MODE - - return *this; -} - -wxULongLongWx& wxULongLongWx::operator^=(const wxULongLongWx& ll) -{ - m_lo ^= ll.m_lo; - m_hi ^= ll.m_hi; - -#ifdef wxLONGLONG_TEST_MODE - m_ll ^= ll.m_ll; - - Check(); -#endif // wxLONGLONG_TEST_MODE - - return *this; -} - -wxLongLongWx wxLongLongWx::operator~() const -{ - return wxLongLongWx(~m_hi, ~m_lo); -} - -wxULongLongWx wxULongLongWx::operator~() const -{ - return wxULongLongWx(~m_hi, ~m_lo); -} - -// multiplication - -wxLongLongWx wxLongLongWx::operator*(const wxLongLongWx& ll) const -{ - wxLongLongWx res(*this); - res *= ll; - - return res; -} - -wxULongLongWx wxULongLongWx::operator*(const wxULongLongWx& ll) const -{ - wxULongLongWx res(*this); - res *= ll; - - return res; -} - -wxLongLongWx& wxLongLongWx::operator*=(const wxLongLongWx& ll) -{ - wxLongLongWx t(m_hi, m_lo); - wxLongLongWx q(ll.m_hi, ll.m_lo); - - m_hi = m_lo = 0; - -#ifdef wxLONGLONG_TEST_MODE - wxLongLong_t llOld = m_ll; - m_ll = 0; -#endif // wxLONGLONG_TEST_MODE - - int counter = 0; - do - { - if ((q.m_lo & 1) != 0) - *this += t; - q >>= 1; - t <<= 1; - counter++; - } - while ((counter < 64) && ((q.m_hi != 0) || (q.m_lo != 0))); - -#ifdef wxLONGLONG_TEST_MODE - m_ll = llOld * ll.m_ll; - - Check(); -#endif // wxLONGLONG_TEST_MODE - - return *this; -} - -wxULongLongWx& wxULongLongWx::operator*=(const wxULongLongWx& ll) -{ - wxULongLongWx t(m_hi, m_lo); - wxULongLongWx q(ll.m_hi, ll.m_lo); - - m_hi = m_lo = 0; - -#ifdef wxLONGLONG_TEST_MODE - wxULongLong_t llOld = m_ll; - m_ll = 0; -#endif // wxLONGLONG_TEST_MODE - - int counter = 0; - do - { - if ((q.m_lo & 1) != 0) - *this += t; - q >>= 1; - t <<= 1; - counter++; - } - while ((counter < 64) && ((q.m_hi != 0) || (q.m_lo != 0))); - -#ifdef wxLONGLONG_TEST_MODE - m_ll = llOld * ll.m_ll; - - Check(); -#endif // wxLONGLONG_TEST_MODE - - return *this; -} - -// division - -#define IS_MSB_SET(ll) ((ll.GetHi()) & (1 << (8*sizeof(long) - 1))) - -void wxLongLongWx::Divide(const wxLongLongWx& divisorIn, - wxLongLongWx& quotient, - wxLongLongWx& remainderIO) const -{ - if ((divisorIn.m_lo == 0) && (divisorIn.m_hi == 0)) - { - // provoke division by zero error and silence the compilers warnings - // about an expression without effect and unused variable - long dummy = divisorIn.m_lo/divisorIn.m_hi; - dummy += 0; - } - - // VZ: I'm writing this in a hurry and it's surely not the fastest way to - // do this - any improvements are more than welcome - // - // code inspired by the snippet at - // http://www.bearcave.com/software/divide.htm - // - // Copyright notice: - // - // Use of this program, for any purpose, is granted the author, Ian - // Kaplan, as long as this copyright notice is included in the source - // code or any source code derived from this program. The user assumes - // all responsibility for using this code. - - // init everything - wxULongLongWx dividend, divisor, remainder; - - quotient = 0l; - remainder = 0l; - - // always do unsigned division and adjust the signs later: in C integer - // division, the sign of the remainder is the same as the sign of the - // dividend, while the sign of the quotient is the product of the signs of - // the dividend and divisor. Of course, we also always have - // - // dividend = quotient*divisor + remainder - // - // with 0 <= abs(remainder) < abs(divisor) - bool negRemainder = GetHi() < 0; - bool negQuotient = false; // assume positive - if ( GetHi() < 0 ) - { - negQuotient = !negQuotient; - dividend = -*this; - } else { - dividend = *this; - } - if ( divisorIn.GetHi() < 0 ) - { - negQuotient = !negQuotient; - divisor = -divisorIn; - } else { - divisor = divisorIn; - } - - // check for some particular cases - if ( divisor > dividend ) - { - remainder = dividend; - } - else if ( divisor == dividend ) - { - quotient = 1l; - } - else - { - // here: dividend > divisor and both are positive: do unsigned division - size_t nBits = 64u; - wxLongLongWx d; - - while ( remainder < divisor ) - { - remainder <<= 1; - if ( IS_MSB_SET(dividend) ) - { - remainder |= 1; - } - - d = dividend; - dividend <<= 1; - - nBits--; - } - - // undo the last loop iteration - dividend = d; - remainder >>= 1; - nBits++; - - for ( size_t i = 0; i < nBits; i++ ) - { - remainder <<= 1; - if ( IS_MSB_SET(dividend) ) - { - remainder |= 1; - } - - wxLongLongWx t = remainder - divisor; - dividend <<= 1; - quotient <<= 1; - if ( !IS_MSB_SET(t) ) - { - quotient |= 1; - - remainder = t; - } - } - } - - remainderIO = remainder; - - // adjust signs - if ( negRemainder ) - { - remainderIO = -remainderIO; - } - - if ( negQuotient ) - { - quotient = -quotient; - } -} - -void wxULongLongWx::Divide(const wxULongLongWx& divisorIn, - wxULongLongWx& quotient, - wxULongLongWx& remainder) const -{ - if ((divisorIn.m_lo == 0) && (divisorIn.m_hi == 0)) - { - // provoke division by zero error and silence the compilers warnings - // about an expression without effect and unused variable - unsigned long dummy = divisorIn.m_lo/divisorIn.m_hi; - dummy += 0; - } - - // VZ: I'm writing this in a hurry and it's surely not the fastest way to - // do this - any improvements are more than welcome - // - // code inspired by the snippet at - // http://www.bearcave.com/software/divide.htm - // - // Copyright notice: - // - // Use of this program, for any purpose, is granted the author, Ian - // Kaplan, as long as this copyright notice is included in the source - // code or any source code derived from this program. The user assumes - // all responsibility for using this code. - - // init everything - wxULongLongWx dividend = *this, - divisor = divisorIn; - - quotient = 0l; - remainder = 0l; - - // check for some particular cases - if ( divisor > dividend ) - { - remainder = dividend; - } - else if ( divisor == dividend ) - { - quotient = 1l; - } - else - { - // here: dividend > divisor - size_t nBits = 64u; - wxULongLongWx d; - - while ( remainder < divisor ) - { - remainder <<= 1; - if ( IS_MSB_SET(dividend) ) - { - remainder |= 1; - } - - d = dividend; - dividend <<= 1; - - nBits--; - } - - // undo the last loop iteration - dividend = d; - remainder >>= 1; - nBits++; - - for ( size_t i = 0; i < nBits; i++ ) - { - remainder <<= 1; - if ( IS_MSB_SET(dividend) ) - { - remainder |= 1; - } - - wxULongLongWx t = remainder - divisor; - dividend <<= 1; - quotient <<= 1; - if ( !IS_MSB_SET(t) ) - { - quotient |= 1; - - remainder = t; - } - } - } -} - -wxLongLongWx wxLongLongWx::operator/(const wxLongLongWx& ll) const -{ - wxLongLongWx quotient, remainder; - - Divide(ll, quotient, remainder); - - return quotient; -} - -wxULongLongWx wxULongLongWx::operator/(const wxULongLongWx& ll) const -{ - wxULongLongWx quotient, remainder; - - Divide(ll, quotient, remainder); - - return quotient; -} - -wxLongLongWx& wxLongLongWx::operator/=(const wxLongLongWx& ll) -{ - wxLongLongWx quotient, remainder; - - Divide(ll, quotient, remainder); - - *this = quotient; - - return *this; -} - -wxULongLongWx& wxULongLongWx::operator/=(const wxULongLongWx& ll) -{ - wxULongLongWx quotient, remainder; - - Divide(ll, quotient, remainder); - - *this = quotient; - - return *this; -} - -wxLongLongWx wxLongLongWx::operator%(const wxLongLongWx& ll) const -{ - wxLongLongWx quotient, remainder; - - Divide(ll, quotient, remainder); - - return remainder; -} - -wxULongLongWx wxULongLongWx::operator%(const wxULongLongWx& ll) const -{ - wxULongLongWx quotient, remainder; - - Divide(ll, quotient, remainder); - - return remainder; -} - -// ---------------------------------------------------------------------------- -// misc -// ---------------------------------------------------------------------------- - -// temporary - just for testing -void *wxLongLongWx::asArray(void) const -{ - static unsigned char temp[8]; - - temp[0] = (char)((m_hi >> 24) & 0xFF); - temp[1] = (char)((m_hi >> 16) & 0xFF); - temp[2] = (char)((m_hi >> 8) & 0xFF); - temp[3] = (char)((m_hi >> 0) & 0xFF); - temp[4] = (char)((m_lo >> 24) & 0xFF); - temp[5] = (char)((m_lo >> 16) & 0xFF); - temp[6] = (char)((m_lo >> 8) & 0xFF); - temp[7] = (char)((m_lo >> 0) & 0xFF); - - return temp; -} - -void *wxULongLongWx::asArray(void) const -{ - static unsigned char temp[8]; - - temp[0] = (char)((m_hi >> 24) & 0xFF); - temp[1] = (char)((m_hi >> 16) & 0xFF); - temp[2] = (char)((m_hi >> 8) & 0xFF); - temp[3] = (char)((m_hi >> 0) & 0xFF); - temp[4] = (char)((m_lo >> 24) & 0xFF); - temp[5] = (char)((m_lo >> 16) & 0xFF); - temp[6] = (char)((m_lo >> 8) & 0xFF); - temp[7] = (char)((m_lo >> 0) & 0xFF); - - return temp; -} - -#endif // wxUSE_LONGLONG_WX - -#define LL_TO_STRING(name) \ - wxString name::ToString() const \ - { \ - /* TODO: this is awfully inefficient, anything better? */ \ - wxString result; \ - \ - name ll = *this; \ - \ - bool neg = ll < 0; \ - if ( neg ) \ - { \ - while ( ll != 0 ) \ - { \ - long digit = (ll % 10).ToLong(); \ - result.Prepend((wxChar)(_T('0') - digit)); \ - ll /= 10; \ - } \ - } \ - else \ - { \ - while ( ll != 0 ) \ - { \ - long digit = (ll % 10).ToLong(); \ - result.Prepend((wxChar)(_T('0') + digit)); \ - ll /= 10; \ - } \ - } \ - \ - if ( result.empty() ) \ - result = _T('0'); \ - else if ( neg ) \ - result.Prepend(_T('-')); \ - \ - return result; \ - } - -#define ULL_TO_STRING(name) \ - wxString name::ToString() const \ - { \ - /* TODO: this is awfully inefficient, anything better? */ \ - wxString result; \ - \ - name ll = *this; \ - \ - while ( ll != 0 ) \ - { \ - result.Prepend((wxChar)(_T('0') + (ll % 10).ToULong())); \ - ll /= 10; \ - } \ - \ - if ( result.empty() ) \ - result = _T('0'); \ - \ - return result; \ - } - -#if wxUSE_LONGLONG_NATIVE - LL_TO_STRING(wxLongLongNative) - ULL_TO_STRING(wxULongLongNative) -#endif - -#if wxUSE_LONGLONG_WX - LL_TO_STRING(wxLongLongWx) - ULL_TO_STRING(wxULongLongWx) -#endif - -#if wxUSE_STD_IOSTREAM - -// input/output -WXDLLIMPEXP_BASE -wxSTD ostream& operator<< (wxSTD ostream& o, const wxLongLong& ll) -{ - return o << ll.ToString(); -} - -WXDLLIMPEXP_BASE -wxSTD ostream& operator<< (wxSTD ostream& o, const wxULongLong& ll) -{ - return o << ll.ToString(); -} - -#endif // wxUSE_STD_IOSTREAM - -WXDLLIMPEXP_BASE wxString& operator<< (wxString& s, const wxLongLong& ll) -{ - return s << ll.ToString(); -} - -WXDLLIMPEXP_BASE wxString& operator<< (wxString& s, const wxULongLong& ll) -{ - return s << ll.ToString(); -} - -#if wxUSE_STREAMS - -WXDLLIMPEXP_BASE wxTextOutputStream& operator<< (wxTextOutputStream& o, const wxULongLong& ll) -{ - return o << ll.ToString(); -} - -WXDLLIMPEXP_BASE wxTextOutputStream& operator<< (wxTextOutputStream& o, const wxLongLong& ll) -{ - return o << ll.ToString(); -} - -#define READ_STRING_CHAR(s, idx, len) ((wxChar) ((idx!=len) ? s[idx++] : 0)) - -WXDLLIMPEXP_BASE class wxTextInputStream &operator>>(class wxTextInputStream &o, wxULongLong &ll) -{ - wxString s = o.ReadWord(); - - ll = wxULongLong(0l, 0l); - size_t length = s.length(); - size_t idx = 0; - - wxChar ch = READ_STRING_CHAR(s, idx, length); - - // Skip WS - while (ch==wxT(' ') || ch==wxT('\t')) - ch = READ_STRING_CHAR(s, idx, length); - - // Read number - wxULongLong multiplier(0l, 10l); - while (ch>=wxT('0') && ch<=wxT('9')) { - long lValue = (unsigned) (ch - wxT('0')); - ll = ll * multiplier + wxULongLong(0l, lValue); - ch = READ_STRING_CHAR(s, idx, length); - } - - return o; -} - -WXDLLIMPEXP_BASE class wxTextInputStream &operator>>(class wxTextInputStream &o, wxLongLong &ll) -{ - wxString s = o.ReadWord(); - - ll = wxLongLong(0l, 0l); - size_t length = s.length(); - size_t idx = 0; - - wxChar ch = READ_STRING_CHAR(s, idx, length); - - // Skip WS - while (ch==wxT(' ') || ch==wxT('\t')) - ch = READ_STRING_CHAR(s, idx, length); - - // Ask for sign - int iSign = 1; - if (ch==wxT('-') || ch==wxT('+')) { - iSign = ((ch==wxT('-')) ? -1 : 1); - ch = READ_STRING_CHAR(s, idx, length); - } - - // Read number - wxLongLong multiplier(0l, 10l); - while (ch>=wxT('0') && ch<=wxT('9')) { - long lValue = (unsigned) (ch - wxT('0')); - ll = ll * multiplier + wxLongLong(0l, lValue); - ch = READ_STRING_CHAR(s, idx, length); - } - -#if wxUSE_LONGLONG_NATIVE - ll = ll * wxLongLong((wxLongLong_t) iSign); -#else - ll = ll * wxLongLong((long) iSign); -#endif - - return o; -} - -#if wxUSE_LONGLONG_NATIVE - -WXDLLIMPEXP_BASE class wxTextOutputStream &operator<<(class wxTextOutputStream &o, wxULongLong_t value) -{ - return o << wxULongLong(value).ToString(); -} - -WXDLLIMPEXP_BASE class wxTextOutputStream &operator<<(class wxTextOutputStream &o, wxLongLong_t value) -{ - return o << wxLongLong(value).ToString(); -} - -WXDLLIMPEXP_BASE class wxTextInputStream &operator>>(class wxTextInputStream &o, wxULongLong_t &value) -{ - wxULongLong ll; - o >> ll; - value = ll.GetValue(); - return o; -} - -WXDLLIMPEXP_BASE class wxTextInputStream &operator>>(class wxTextInputStream &o, wxLongLong_t &value) -{ - wxLongLong ll; - o >> ll; - value = ll.GetValue(); - return o; -} - -#endif // wxUSE_LONGLONG_NATIVE - -#endif // wxUSE_STREAMS - -#endif // wxUSE_LONGLONG +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/longlong.cpp +// Purpose: implementation of wxLongLongNative +// Author: Jeffrey C. Ollie , Vadim Zeitlin +// Remarks: this class is not public in wxWidgets 2.0! It is intentionally +// not documented and is for private use only. +// Modified by: +// Created: 10.02.99 +// RCS-ID: $Id: longlong.cpp 40750 2006-08-22 19:04:45Z MW $ +// Copyright: (c) 1998 Vadim Zeitlin +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// headers +// ============================================================================ + +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_LONGLONG + +#include "wx/longlong.h" + +#ifndef WX_PRECOMP + #include "wx/math.h" // for fabs() +#endif + +#if wxUSE_STREAMS + #include "wx/txtstrm.h" +#endif + +#include // for memset() + +#include "wx/ioswrap.h" + +// ============================================================================ +// implementation +// ============================================================================ + +#if wxUSE_LONGLONG_NATIVE + +// ---------------------------------------------------------------------------- +// misc +// ---------------------------------------------------------------------------- + +void *wxLongLongNative::asArray() const +{ + static unsigned char temp[8]; + + temp[0] = wx_truncate_cast(unsigned char, ((m_ll >> 56) & 0xFF)); + temp[1] = wx_truncate_cast(unsigned char, ((m_ll >> 48) & 0xFF)); + temp[2] = wx_truncate_cast(unsigned char, ((m_ll >> 40) & 0xFF)); + temp[3] = wx_truncate_cast(unsigned char, ((m_ll >> 32) & 0xFF)); + temp[4] = wx_truncate_cast(unsigned char, ((m_ll >> 24) & 0xFF)); + temp[5] = wx_truncate_cast(unsigned char, ((m_ll >> 16) & 0xFF)); + temp[6] = wx_truncate_cast(unsigned char, ((m_ll >> 8) & 0xFF)); + temp[7] = wx_truncate_cast(unsigned char, ((m_ll >> 0) & 0xFF)); + + return temp; +} + +void *wxULongLongNative::asArray() const +{ + static unsigned char temp[8]; + + temp[0] = wx_truncate_cast(unsigned char, ((m_ll >> 56) & 0xFF)); + temp[1] = wx_truncate_cast(unsigned char, ((m_ll >> 48) & 0xFF)); + temp[2] = wx_truncate_cast(unsigned char, ((m_ll >> 40) & 0xFF)); + temp[3] = wx_truncate_cast(unsigned char, ((m_ll >> 32) & 0xFF)); + temp[4] = wx_truncate_cast(unsigned char, ((m_ll >> 24) & 0xFF)); + temp[5] = wx_truncate_cast(unsigned char, ((m_ll >> 16) & 0xFF)); + temp[6] = wx_truncate_cast(unsigned char, ((m_ll >> 8) & 0xFF)); + temp[7] = wx_truncate_cast(unsigned char, ((m_ll >> 0) & 0xFF)); + + return temp; +} + +#if wxUSE_LONGLONG_WX +wxLongLongNative::wxLongLongNative(wxLongLongWx ll) +{ + // assign first to avoid precision loss! + m_ll = ll.GetHi(); + m_ll <<= 32; + m_ll |= ll.GetLo(); +} + +wxLongLongNative& wxLongLongNative::operator=(wxLongLongWx ll) +{ + // assign first to avoid precision loss! + m_ll = ll.GetHi(); + m_ll <<= 32; + m_ll |= ll.GetLo(); + return *this; +} + +wxLongLongNative& wxLongLongNative::operator=(const class wxULongLongWx &ll) +{ + // assign first to avoid precision loss! + m_ll = ll.GetHi(); + m_ll <<= 32; + m_ll |= ll.GetLo(); + return *this; +} + +wxULongLongNative::wxULongLongNative(const class wxULongLongWx &ll) +{ + // assign first to avoid precision loss! + m_ll = ll.GetHi(); + m_ll <<= 32; + m_ll |= ((unsigned long) ll.GetLo()); +} + +wxULongLongNative& wxULongLongNative::operator=(wxLongLongWx ll) +{ + // assign first to avoid precision loss! + m_ll = ll.GetHi(); + m_ll <<= 32; + m_ll |= ((unsigned long) ll.GetLo()); + return *this; +} + +wxULongLongNative& wxULongLongNative::operator=(const class wxULongLongWx &ll) +{ + // assign first to avoid precision loss! + m_ll = ll.GetHi(); + m_ll <<= 32; + m_ll |= ((unsigned long) ll.GetLo()); + return *this; +} +#endif + +#endif // wxUSE_LONGLONG_NATIVE + +// ============================================================================ +// wxLongLongWx: emulation of 'long long' using 2 longs +// ============================================================================ + +#if wxUSE_LONGLONG_WX + +// Set value from unsigned wxULongLongWx +wxLongLongWx &wxLongLongWx::operator=(const class wxULongLongWx &ll) +{ + m_hi = (unsigned long) ll.GetHi(); + m_lo = ll.GetLo(); + return *this; +} + +// assignment +wxLongLongWx& wxLongLongWx::Assign(double d) +{ + bool positive = d >= 0; + d = fabs(d); + if ( d <= ULONG_MAX ) + { + m_hi = 0; + m_lo = (long)d; + } + else + { + m_hi = (unsigned long)(d / (1.0 + (double)ULONG_MAX)); + m_lo = (unsigned long)(d - ((double)m_hi * (1.0 + (double)ULONG_MAX))); + } + +#ifdef wxLONGLONG_TEST_MODE + m_ll = (wxLongLong_t)d; + + Check(); +#endif // wxLONGLONG_TEST_MODE + + if ( !positive ) + Negate(); + + return *this; +} + +double wxLongLongWx::ToDouble() const +{ + double d = m_hi; + d *= 1.0 + (double)ULONG_MAX; + d += m_lo; + +#ifdef wxLONGLONG_TEST_MODE + wxASSERT( d == m_ll ); +#endif // wxLONGLONG_TEST_MODE + + return d; +} + +double wxULongLongWx::ToDouble() const +{ + unsigned double d = m_hi; + d *= 1.0 + (double)ULONG_MAX; + d += m_lo; + +#ifdef wxLONGLONG_TEST_MODE + wxASSERT( d == m_ll ); +#endif // wxLONGLONG_TEST_MODE + + return d; +} + +wxLongLongWx wxLongLongWx::operator<<(int shift) const +{ + wxLongLongWx ll(*this); + ll <<= shift; + + return ll; +} + +wxULongLongWx wxULongLongWx::operator<<(int shift) const +{ + wxULongLongWx ll(*this); + ll <<= shift; + + return ll; +} + +wxLongLongWx& wxLongLongWx::operator<<=(int shift) +{ + if (shift != 0) + { + if (shift < 32) + { + m_hi <<= shift; + m_hi |= m_lo >> (32 - shift); + m_lo <<= shift; + } + else + { + m_hi = m_lo << (shift - 32); + m_lo = 0; + } + } + +#ifdef wxLONGLONG_TEST_MODE + m_ll <<= shift; + + Check(); +#endif // wxLONGLONG_TEST_MODE + + return *this; +} + +wxULongLongWx& wxULongLongWx::operator<<=(int shift) +{ + if (shift != 0) + { + if (shift < 32) + { + m_hi <<= shift; + m_hi |= m_lo >> (32 - shift); + m_lo <<= shift; + } + else + { + m_hi = m_lo << (shift - 32); + m_lo = 0; + } + } + +#ifdef wxLONGLONG_TEST_MODE + m_ll <<= shift; + + Check(); +#endif // wxLONGLONG_TEST_MODE + + return *this; +} + +wxLongLongWx wxLongLongWx::operator>>(int shift) const +{ + wxLongLongWx ll(*this); + ll >>= shift; + + return ll; +} + +wxULongLongWx wxULongLongWx::operator>>(int shift) const +{ + wxULongLongWx ll(*this); + ll >>= shift; + + return ll; +} + +wxLongLongWx& wxLongLongWx::operator>>=(int shift) +{ + if (shift != 0) + { + if (shift < 32) + { + m_lo >>= shift; + m_lo |= m_hi << (32 - shift); + m_hi >>= shift; + } + else + { + m_lo = m_hi >> (shift - 32); + m_hi = (m_hi < 0 ? -1L : 0); + } + } + +#ifdef wxLONGLONG_TEST_MODE + m_ll >>= shift; + + Check(); +#endif // wxLONGLONG_TEST_MODE + + return *this; +} + +wxULongLongWx& wxULongLongWx::operator>>=(int shift) +{ + if (shift != 0) + { + if (shift < 32) + { + m_lo >>= shift; + m_lo |= m_hi << (32 - shift); + m_hi >>= shift; + } + else + { + m_lo = m_hi >> (shift - 32); + m_hi = 0; + } + } + +#ifdef wxLONGLONG_TEST_MODE + m_ll >>= shift; + + Check(); +#endif // wxLONGLONG_TEST_MODE + + return *this; +} + +wxLongLongWx wxLongLongWx::operator+(const wxLongLongWx& ll) const +{ + wxLongLongWx res(*this); + res += ll; + + return res; +} + +wxULongLongWx wxULongLongWx::operator+(const wxULongLongWx& ll) const +{ + wxULongLongWx res(*this); + res += ll; + + return res; +} + +wxLongLongWx wxLongLongWx::operator+(long l) const +{ + wxLongLongWx res(*this); + res += l; + + return res; +} + +wxULongLongWx wxULongLongWx::operator+(unsigned long l) const +{ + wxULongLongWx res(*this); + res += l; + + return res; +} + +wxLongLongWx& wxLongLongWx::operator+=(const wxLongLongWx& ll) +{ + unsigned long previous = m_lo; + + m_lo += ll.m_lo; + m_hi += ll.m_hi; + + if ((m_lo < previous) || (m_lo < ll.m_lo)) + m_hi++; + +#ifdef wxLONGLONG_TEST_MODE + m_ll += ll.m_ll; + + Check(); +#endif // wxLONGLONG_TEST_MODE + + return *this; +} + +wxULongLongWx& wxULongLongWx::operator+=(const wxULongLongWx& ll) +{ + unsigned long previous = m_lo; + + m_lo += ll.m_lo; + m_hi += ll.m_hi; + + if ((m_lo < previous) || (m_lo < ll.m_lo)) + m_hi++; + +#ifdef wxLONGLONG_TEST_MODE + m_ll += ll.m_ll; + + Check(); +#endif // wxLONGLONG_TEST_MODE + + return *this; +} + +wxLongLongWx& wxLongLongWx::operator+=(long l) +{ + unsigned long previous = m_lo; + + m_lo += l; + if (l < 0) + m_hi += -1l; + + if ((m_lo < previous) || (m_lo < (unsigned long)l)) + m_hi++; + +#ifdef wxLONGLONG_TEST_MODE + m_ll += l; + + Check(); +#endif // wxLONGLONG_TEST_MODE + + return *this; +} + +wxULongLongWx& wxULongLongWx::operator+=(unsigned long l) +{ + unsigned long previous = m_lo; + + m_lo += l; + + if ((m_lo < previous) || (m_lo < l)) + m_hi++; + +#ifdef wxLONGLONG_TEST_MODE + m_ll += l; + + Check(); +#endif // wxLONGLONG_TEST_MODE + + return *this; +} + +// pre increment +wxLongLongWx& wxLongLongWx::operator++() +{ + m_lo++; + if (m_lo == 0) + m_hi++; + +#ifdef wxLONGLONG_TEST_MODE + m_ll++; + + Check(); +#endif // wxLONGLONG_TEST_MODE + + return *this; +} + +wxULongLongWx& wxULongLongWx::operator++() +{ + m_lo++; + if (m_lo == 0) + m_hi++; + +#ifdef wxLONGLONG_TEST_MODE + m_ll++; + + Check(); +#endif // wxLONGLONG_TEST_MODE + + return *this; +} + +// negation +wxLongLongWx wxLongLongWx::operator-() const +{ + wxLongLongWx res(*this); + res.Negate(); + + return res; +} + +wxLongLongWx& wxLongLongWx::Negate() +{ + m_hi = ~m_hi; + m_lo = ~m_lo; + + m_lo++; + if ( m_lo == 0 ) + m_hi++; + +#ifdef wxLONGLONG_TEST_MODE + m_ll = -m_ll; + + Check(); +#endif // wxLONGLONG_TEST_MODE + + return *this; +} + +// subtraction + +wxLongLongWx wxLongLongWx::operator-(const wxLongLongWx& ll) const +{ + wxLongLongWx res(*this); + res -= ll; + + return res; +} + +wxLongLongWx wxULongLongWx::operator-(const wxULongLongWx& ll) const +{ + wxASSERT(m_hi <= LONG_MAX ); + wxASSERT(ll.m_hi <= LONG_MAX ); + + wxLongLongWx res( (long)m_hi , m_lo ); + wxLongLongWx op( (long)ll.m_hi , ll.m_lo ); + res -= op; + + return res; +} + +wxLongLongWx& wxLongLongWx::operator-=(const wxLongLongWx& ll) +{ + unsigned long previous = m_lo; + + m_lo -= ll.m_lo; + m_hi -= ll.m_hi; + + if (previous < ll.m_lo) + m_hi--; + +#ifdef wxLONGLONG_TEST_MODE + m_ll -= ll.m_ll; + + Check(); +#endif // wxLONGLONG_TEST_MODE + + return *this; +} + +wxULongLongWx& wxULongLongWx::operator-=(const wxULongLongWx& ll) +{ + unsigned long previous = m_lo; + + m_lo -= ll.m_lo; + m_hi -= ll.m_hi; + + if (previous < ll.m_lo) + m_hi--; + +#ifdef wxLONGLONG_TEST_MODE + m_ll -= ll.m_ll; + + Check(); +#endif // wxLONGLONG_TEST_MODE + + return *this; +} + +// pre decrement +wxLongLongWx& wxLongLongWx::operator--() +{ + m_lo--; + if (m_lo == 0xFFFFFFFF) + m_hi--; + +#ifdef wxLONGLONG_TEST_MODE + m_ll--; + + Check(); +#endif // wxLONGLONG_TEST_MODE + + return *this; +} + +wxULongLongWx& wxULongLongWx::operator--() +{ + m_lo--; + if (m_lo == 0xFFFFFFFF) + m_hi--; + +#ifdef wxLONGLONG_TEST_MODE + m_ll--; + + Check(); +#endif // wxLONGLONG_TEST_MODE + + return *this; +} + +// comparison operators + +bool wxLongLongWx::operator<(const wxLongLongWx& ll) const +{ + if ( m_hi < ll.m_hi ) + return true; + else if ( m_hi == ll.m_hi ) + return m_lo < ll.m_lo; + else + return false; +} + +bool wxULongLongWx::operator<(const wxULongLongWx& ll) const +{ + if ( m_hi < ll.m_hi ) + return true; + else if ( m_hi == ll.m_hi ) + return m_lo < ll.m_lo; + else + return false; +} + +bool wxLongLongWx::operator>(const wxLongLongWx& ll) const +{ + if ( m_hi > ll.m_hi ) + return true; + else if ( m_hi == ll.m_hi ) + return m_lo > ll.m_lo; + else + return false; +} + +bool wxULongLongWx::operator>(const wxULongLongWx& ll) const +{ + if ( m_hi > ll.m_hi ) + return true; + else if ( m_hi == ll.m_hi ) + return m_lo > ll.m_lo; + else + return false; +} + +// bitwise operators + +wxLongLongWx wxLongLongWx::operator&(const wxLongLongWx& ll) const +{ + return wxLongLongWx(m_hi & ll.m_hi, m_lo & ll.m_lo); +} + +wxULongLongWx wxULongLongWx::operator&(const wxULongLongWx& ll) const +{ + return wxULongLongWx(m_hi & ll.m_hi, m_lo & ll.m_lo); +} + +wxLongLongWx wxLongLongWx::operator|(const wxLongLongWx& ll) const +{ + return wxLongLongWx(m_hi | ll.m_hi, m_lo | ll.m_lo); +} + +wxULongLongWx wxULongLongWx::operator|(const wxULongLongWx& ll) const +{ + return wxULongLongWx(m_hi | ll.m_hi, m_lo | ll.m_lo); +} + +wxLongLongWx wxLongLongWx::operator^(const wxLongLongWx& ll) const +{ + return wxLongLongWx(m_hi ^ ll.m_hi, m_lo ^ ll.m_lo); +} + +wxULongLongWx wxULongLongWx::operator^(const wxULongLongWx& ll) const +{ + return wxULongLongWx(m_hi ^ ll.m_hi, m_lo ^ ll.m_lo); +} + +wxLongLongWx& wxLongLongWx::operator&=(const wxLongLongWx& ll) +{ + m_lo &= ll.m_lo; + m_hi &= ll.m_hi; + +#ifdef wxLONGLONG_TEST_MODE + m_ll &= ll.m_ll; + + Check(); +#endif // wxLONGLONG_TEST_MODE + + return *this; +} + +wxULongLongWx& wxULongLongWx::operator&=(const wxULongLongWx& ll) +{ + m_lo &= ll.m_lo; + m_hi &= ll.m_hi; + +#ifdef wxLONGLONG_TEST_MODE + m_ll &= ll.m_ll; + + Check(); +#endif // wxLONGLONG_TEST_MODE + + return *this; +} + +wxLongLongWx& wxLongLongWx::operator|=(const wxLongLongWx& ll) +{ + m_lo |= ll.m_lo; + m_hi |= ll.m_hi; + +#ifdef wxLONGLONG_TEST_MODE + m_ll |= ll.m_ll; + + Check(); +#endif // wxLONGLONG_TEST_MODE + + return *this; +} + +wxULongLongWx& wxULongLongWx::operator|=(const wxULongLongWx& ll) +{ + m_lo |= ll.m_lo; + m_hi |= ll.m_hi; + +#ifdef wxLONGLONG_TEST_MODE + m_ll |= ll.m_ll; + + Check(); +#endif // wxLONGLONG_TEST_MODE + + return *this; +} + +wxLongLongWx& wxLongLongWx::operator^=(const wxLongLongWx& ll) +{ + m_lo ^= ll.m_lo; + m_hi ^= ll.m_hi; + +#ifdef wxLONGLONG_TEST_MODE + m_ll ^= ll.m_ll; + + Check(); +#endif // wxLONGLONG_TEST_MODE + + return *this; +} + +wxULongLongWx& wxULongLongWx::operator^=(const wxULongLongWx& ll) +{ + m_lo ^= ll.m_lo; + m_hi ^= ll.m_hi; + +#ifdef wxLONGLONG_TEST_MODE + m_ll ^= ll.m_ll; + + Check(); +#endif // wxLONGLONG_TEST_MODE + + return *this; +} + +wxLongLongWx wxLongLongWx::operator~() const +{ + return wxLongLongWx(~m_hi, ~m_lo); +} + +wxULongLongWx wxULongLongWx::operator~() const +{ + return wxULongLongWx(~m_hi, ~m_lo); +} + +// multiplication + +wxLongLongWx wxLongLongWx::operator*(const wxLongLongWx& ll) const +{ + wxLongLongWx res(*this); + res *= ll; + + return res; +} + +wxULongLongWx wxULongLongWx::operator*(const wxULongLongWx& ll) const +{ + wxULongLongWx res(*this); + res *= ll; + + return res; +} + +wxLongLongWx& wxLongLongWx::operator*=(const wxLongLongWx& ll) +{ + wxLongLongWx t(m_hi, m_lo); + wxLongLongWx q(ll.m_hi, ll.m_lo); + + m_hi = m_lo = 0; + +#ifdef wxLONGLONG_TEST_MODE + wxLongLong_t llOld = m_ll; + m_ll = 0; +#endif // wxLONGLONG_TEST_MODE + + int counter = 0; + do + { + if ((q.m_lo & 1) != 0) + *this += t; + q >>= 1; + t <<= 1; + counter++; + } + while ((counter < 64) && ((q.m_hi != 0) || (q.m_lo != 0))); + +#ifdef wxLONGLONG_TEST_MODE + m_ll = llOld * ll.m_ll; + + Check(); +#endif // wxLONGLONG_TEST_MODE + + return *this; +} + +wxULongLongWx& wxULongLongWx::operator*=(const wxULongLongWx& ll) +{ + wxULongLongWx t(m_hi, m_lo); + wxULongLongWx q(ll.m_hi, ll.m_lo); + + m_hi = m_lo = 0; + +#ifdef wxLONGLONG_TEST_MODE + wxULongLong_t llOld = m_ll; + m_ll = 0; +#endif // wxLONGLONG_TEST_MODE + + int counter = 0; + do + { + if ((q.m_lo & 1) != 0) + *this += t; + q >>= 1; + t <<= 1; + counter++; + } + while ((counter < 64) && ((q.m_hi != 0) || (q.m_lo != 0))); + +#ifdef wxLONGLONG_TEST_MODE + m_ll = llOld * ll.m_ll; + + Check(); +#endif // wxLONGLONG_TEST_MODE + + return *this; +} + +// division + +#define IS_MSB_SET(ll) ((ll.GetHi()) & (1 << (8*sizeof(long) - 1))) + +void wxLongLongWx::Divide(const wxLongLongWx& divisorIn, + wxLongLongWx& quotient, + wxLongLongWx& remainderIO) const +{ + if ((divisorIn.m_lo == 0) && (divisorIn.m_hi == 0)) + { + // provoke division by zero error and silence the compilers warnings + // about an expression without effect and unused variable + long dummy = divisorIn.m_lo/divisorIn.m_hi; + dummy += 0; + } + + // VZ: I'm writing this in a hurry and it's surely not the fastest way to + // do this - any improvements are more than welcome + // + // code inspired by the snippet at + // http://www.bearcave.com/software/divide.htm + // + // Copyright notice: + // + // Use of this program, for any purpose, is granted the author, Ian + // Kaplan, as long as this copyright notice is included in the source + // code or any source code derived from this program. The user assumes + // all responsibility for using this code. + + // init everything + wxULongLongWx dividend, divisor, remainder; + + quotient = 0l; + remainder = 0l; + + // always do unsigned division and adjust the signs later: in C integer + // division, the sign of the remainder is the same as the sign of the + // dividend, while the sign of the quotient is the product of the signs of + // the dividend and divisor. Of course, we also always have + // + // dividend = quotient*divisor + remainder + // + // with 0 <= abs(remainder) < abs(divisor) + bool negRemainder = GetHi() < 0; + bool negQuotient = false; // assume positive + if ( GetHi() < 0 ) + { + negQuotient = !negQuotient; + dividend = -*this; + } else { + dividend = *this; + } + if ( divisorIn.GetHi() < 0 ) + { + negQuotient = !negQuotient; + divisor = -divisorIn; + } else { + divisor = divisorIn; + } + + // check for some particular cases + if ( divisor > dividend ) + { + remainder = dividend; + } + else if ( divisor == dividend ) + { + quotient = 1l; + } + else + { + // here: dividend > divisor and both are positive: do unsigned division + size_t nBits = 64u; + wxLongLongWx d; + + while ( remainder < divisor ) + { + remainder <<= 1; + if ( IS_MSB_SET(dividend) ) + { + remainder |= 1; + } + + d = dividend; + dividend <<= 1; + + nBits--; + } + + // undo the last loop iteration + dividend = d; + remainder >>= 1; + nBits++; + + for ( size_t i = 0; i < nBits; i++ ) + { + remainder <<= 1; + if ( IS_MSB_SET(dividend) ) + { + remainder |= 1; + } + + wxLongLongWx t = remainder - divisor; + dividend <<= 1; + quotient <<= 1; + if ( !IS_MSB_SET(t) ) + { + quotient |= 1; + + remainder = t; + } + } + } + + remainderIO = remainder; + + // adjust signs + if ( negRemainder ) + { + remainderIO = -remainderIO; + } + + if ( negQuotient ) + { + quotient = -quotient; + } +} + +void wxULongLongWx::Divide(const wxULongLongWx& divisorIn, + wxULongLongWx& quotient, + wxULongLongWx& remainder) const +{ + if ((divisorIn.m_lo == 0) && (divisorIn.m_hi == 0)) + { + // provoke division by zero error and silence the compilers warnings + // about an expression without effect and unused variable + unsigned long dummy = divisorIn.m_lo/divisorIn.m_hi; + dummy += 0; + } + + // VZ: I'm writing this in a hurry and it's surely not the fastest way to + // do this - any improvements are more than welcome + // + // code inspired by the snippet at + // http://www.bearcave.com/software/divide.htm + // + // Copyright notice: + // + // Use of this program, for any purpose, is granted the author, Ian + // Kaplan, as long as this copyright notice is included in the source + // code or any source code derived from this program. The user assumes + // all responsibility for using this code. + + // init everything + wxULongLongWx dividend = *this, + divisor = divisorIn; + + quotient = 0l; + remainder = 0l; + + // check for some particular cases + if ( divisor > dividend ) + { + remainder = dividend; + } + else if ( divisor == dividend ) + { + quotient = 1l; + } + else + { + // here: dividend > divisor + size_t nBits = 64u; + wxULongLongWx d; + + while ( remainder < divisor ) + { + remainder <<= 1; + if ( IS_MSB_SET(dividend) ) + { + remainder |= 1; + } + + d = dividend; + dividend <<= 1; + + nBits--; + } + + // undo the last loop iteration + dividend = d; + remainder >>= 1; + nBits++; + + for ( size_t i = 0; i < nBits; i++ ) + { + remainder <<= 1; + if ( IS_MSB_SET(dividend) ) + { + remainder |= 1; + } + + wxULongLongWx t = remainder - divisor; + dividend <<= 1; + quotient <<= 1; + if ( !IS_MSB_SET(t) ) + { + quotient |= 1; + + remainder = t; + } + } + } +} + +wxLongLongWx wxLongLongWx::operator/(const wxLongLongWx& ll) const +{ + wxLongLongWx quotient, remainder; + + Divide(ll, quotient, remainder); + + return quotient; +} + +wxULongLongWx wxULongLongWx::operator/(const wxULongLongWx& ll) const +{ + wxULongLongWx quotient, remainder; + + Divide(ll, quotient, remainder); + + return quotient; +} + +wxLongLongWx& wxLongLongWx::operator/=(const wxLongLongWx& ll) +{ + wxLongLongWx quotient, remainder; + + Divide(ll, quotient, remainder); + + *this = quotient; + + return *this; +} + +wxULongLongWx& wxULongLongWx::operator/=(const wxULongLongWx& ll) +{ + wxULongLongWx quotient, remainder; + + Divide(ll, quotient, remainder); + + *this = quotient; + + return *this; +} + +wxLongLongWx wxLongLongWx::operator%(const wxLongLongWx& ll) const +{ + wxLongLongWx quotient, remainder; + + Divide(ll, quotient, remainder); + + return remainder; +} + +wxULongLongWx wxULongLongWx::operator%(const wxULongLongWx& ll) const +{ + wxULongLongWx quotient, remainder; + + Divide(ll, quotient, remainder); + + return remainder; +} + +// ---------------------------------------------------------------------------- +// misc +// ---------------------------------------------------------------------------- + +// temporary - just for testing +void *wxLongLongWx::asArray(void) const +{ + static unsigned char temp[8]; + + temp[0] = (char)((m_hi >> 24) & 0xFF); + temp[1] = (char)((m_hi >> 16) & 0xFF); + temp[2] = (char)((m_hi >> 8) & 0xFF); + temp[3] = (char)((m_hi >> 0) & 0xFF); + temp[4] = (char)((m_lo >> 24) & 0xFF); + temp[5] = (char)((m_lo >> 16) & 0xFF); + temp[6] = (char)((m_lo >> 8) & 0xFF); + temp[7] = (char)((m_lo >> 0) & 0xFF); + + return temp; +} + +void *wxULongLongWx::asArray(void) const +{ + static unsigned char temp[8]; + + temp[0] = (char)((m_hi >> 24) & 0xFF); + temp[1] = (char)((m_hi >> 16) & 0xFF); + temp[2] = (char)((m_hi >> 8) & 0xFF); + temp[3] = (char)((m_hi >> 0) & 0xFF); + temp[4] = (char)((m_lo >> 24) & 0xFF); + temp[5] = (char)((m_lo >> 16) & 0xFF); + temp[6] = (char)((m_lo >> 8) & 0xFF); + temp[7] = (char)((m_lo >> 0) & 0xFF); + + return temp; +} + +#endif // wxUSE_LONGLONG_WX + +#define LL_TO_STRING(name) \ + wxString name::ToString() const \ + { \ + /* TODO: this is awfully inefficient, anything better? */ \ + wxString result; \ + \ + name ll = *this; \ + \ + bool neg = ll < 0; \ + if ( neg ) \ + { \ + while ( ll != 0 ) \ + { \ + long digit = (ll % 10).ToLong(); \ + result.Prepend((wxChar)(_T('0') - digit)); \ + ll /= 10; \ + } \ + } \ + else \ + { \ + while ( ll != 0 ) \ + { \ + long digit = (ll % 10).ToLong(); \ + result.Prepend((wxChar)(_T('0') + digit)); \ + ll /= 10; \ + } \ + } \ + \ + if ( result.empty() ) \ + result = _T('0'); \ + else if ( neg ) \ + result.Prepend(_T('-')); \ + \ + return result; \ + } + +#define ULL_TO_STRING(name) \ + wxString name::ToString() const \ + { \ + /* TODO: this is awfully inefficient, anything better? */ \ + wxString result; \ + \ + name ll = *this; \ + \ + while ( ll != 0 ) \ + { \ + result.Prepend((wxChar)(_T('0') + (ll % 10).ToULong())); \ + ll /= 10; \ + } \ + \ + if ( result.empty() ) \ + result = _T('0'); \ + \ + return result; \ + } + +#if wxUSE_LONGLONG_NATIVE + LL_TO_STRING(wxLongLongNative) + ULL_TO_STRING(wxULongLongNative) +#endif + +#if wxUSE_LONGLONG_WX + LL_TO_STRING(wxLongLongWx) + ULL_TO_STRING(wxULongLongWx) +#endif + +#if wxUSE_STD_IOSTREAM + +// input/output +WXDLLIMPEXP_BASE +wxSTD ostream& operator<< (wxSTD ostream& o, const wxLongLong& ll) +{ + return o << ll.ToString(); +} + +WXDLLIMPEXP_BASE +wxSTD ostream& operator<< (wxSTD ostream& o, const wxULongLong& ll) +{ + return o << ll.ToString(); +} + +#endif // wxUSE_STD_IOSTREAM + +WXDLLIMPEXP_BASE wxString& operator<< (wxString& s, const wxLongLong& ll) +{ + return s << ll.ToString(); +} + +WXDLLIMPEXP_BASE wxString& operator<< (wxString& s, const wxULongLong& ll) +{ + return s << ll.ToString(); +} + +#if wxUSE_STREAMS + +WXDLLIMPEXP_BASE wxTextOutputStream& operator<< (wxTextOutputStream& o, const wxULongLong& ll) +{ + return o << ll.ToString(); +} + +WXDLLIMPEXP_BASE wxTextOutputStream& operator<< (wxTextOutputStream& o, const wxLongLong& ll) +{ + return o << ll.ToString(); +} + +#define READ_STRING_CHAR(s, idx, len) ((wxChar) ((idx!=len) ? s[idx++] : 0)) + +WXDLLIMPEXP_BASE class wxTextInputStream &operator>>(class wxTextInputStream &o, wxULongLong &ll) +{ + wxString s = o.ReadWord(); + + ll = wxULongLong(0l, 0l); + size_t length = s.length(); + size_t idx = 0; + + wxChar ch = READ_STRING_CHAR(s, idx, length); + + // Skip WS + while (ch==wxT(' ') || ch==wxT('\t')) + ch = READ_STRING_CHAR(s, idx, length); + + // Read number + wxULongLong multiplier(0l, 10l); + while (ch>=wxT('0') && ch<=wxT('9')) { + long lValue = (unsigned) (ch - wxT('0')); + ll = ll * multiplier + wxULongLong(0l, lValue); + ch = READ_STRING_CHAR(s, idx, length); + } + + return o; +} + +WXDLLIMPEXP_BASE class wxTextInputStream &operator>>(class wxTextInputStream &o, wxLongLong &ll) +{ + wxString s = o.ReadWord(); + + ll = wxLongLong(0l, 0l); + size_t length = s.length(); + size_t idx = 0; + + wxChar ch = READ_STRING_CHAR(s, idx, length); + + // Skip WS + while (ch==wxT(' ') || ch==wxT('\t')) + ch = READ_STRING_CHAR(s, idx, length); + + // Ask for sign + int iSign = 1; + if (ch==wxT('-') || ch==wxT('+')) { + iSign = ((ch==wxT('-')) ? -1 : 1); + ch = READ_STRING_CHAR(s, idx, length); + } + + // Read number + wxLongLong multiplier(0l, 10l); + while (ch>=wxT('0') && ch<=wxT('9')) { + long lValue = (unsigned) (ch - wxT('0')); + ll = ll * multiplier + wxLongLong(0l, lValue); + ch = READ_STRING_CHAR(s, idx, length); + } + +#if wxUSE_LONGLONG_NATIVE + ll = ll * wxLongLong((wxLongLong_t) iSign); +#else + ll = ll * wxLongLong((long) iSign); +#endif + + return o; +} + +#if wxUSE_LONGLONG_NATIVE + +WXDLLIMPEXP_BASE class wxTextOutputStream &operator<<(class wxTextOutputStream &o, wxULongLong_t value) +{ + return o << wxULongLong(value).ToString(); +} + +WXDLLIMPEXP_BASE class wxTextOutputStream &operator<<(class wxTextOutputStream &o, wxLongLong_t value) +{ + return o << wxLongLong(value).ToString(); +} + +WXDLLIMPEXP_BASE class wxTextInputStream &operator>>(class wxTextInputStream &o, wxULongLong_t &value) +{ + wxULongLong ll; + o >> ll; + value = ll.GetValue(); + return o; +} + +WXDLLIMPEXP_BASE class wxTextInputStream &operator>>(class wxTextInputStream &o, wxLongLong_t &value) +{ + wxLongLong ll; + o >> ll; + value = ll.GetValue(); + return o; +} + +#endif // wxUSE_LONGLONG_NATIVE + +#endif // wxUSE_STREAMS + +#endif // wxUSE_LONGLONG diff --git a/Externals/wxWidgets/src/common/matrix.cpp b/Externals/wxWidgets/src/common/matrix.cpp index e0fe8b002d..4903aca392 100644 --- a/Externals/wxWidgets/src/common/matrix.cpp +++ b/Externals/wxWidgets/src/common/matrix.cpp @@ -1,601 +1,601 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: src/common/matrix.cpp -// Purpose: wxTransformMatrix class -// Author: Chris Breeze, Julian Smart -// Modified by: Klaas Holwerda -// Created: 01/02/97 -// RCS-ID: $Id: matrix.cpp 39745 2006-06-15 17:58:49Z ABX $ -// Copyright: (c) Julian Smart -// Licence: wxWindows licence -/////////////////////////////////////////////////////////////////////////////// - -// Note: this is intended to be used in wxDC at some point to replace -// the current system of scaling/translation. It is not yet used. - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#include "wx/matrix.h" - -#ifndef WX_PRECOMP - #include "wx/math.h" -#endif - -static const double pi = M_PI; - -wxTransformMatrix::wxTransformMatrix(void) -{ - m_isIdentity = false; - - Identity(); -} - -wxTransformMatrix::wxTransformMatrix(const wxTransformMatrix& mat) - : wxObject() -{ - (*this) = mat; -} - -double wxTransformMatrix::GetValue(int col, int row) const -{ - if (row < 0 || row > 2 || col < 0 || col > 2) - return 0.0; - - return m_matrix[col][row]; -} - -void wxTransformMatrix::SetValue(int col, int row, double value) -{ - if (row < 0 || row > 2 || col < 0 || col > 2) - return; - - m_matrix[col][row] = value; - m_isIdentity = IsIdentity1(); -} - -void wxTransformMatrix::operator = (const wxTransformMatrix& mat) -{ - int i, j; - for (i = 0; i < 3; i++) - { - for (j = 0; j < 3; j++) - { - m_matrix[i][j] = mat.m_matrix[i][j]; - } - } - m_isIdentity = mat.m_isIdentity; -} - -bool wxTransformMatrix::operator == (const wxTransformMatrix& mat) const -{ - if (m_isIdentity && mat.m_isIdentity) - return true; - - int i, j; - for (i = 0; i < 3; i++) - { - for (j = 0; j < 3; j++) - { - if ( !wxIsSameDouble(m_matrix[i][j], mat.m_matrix[i][j]) ) - return false; - } - } - return true; -} - -bool wxTransformMatrix::operator != (const wxTransformMatrix& mat) const -{ - return (! ((*this) == mat)); -} - -double& wxTransformMatrix::operator()(int col, int row) -{ - if (row < 0 || row > 2 || col < 0 || col > 2) - return m_matrix[0][0]; - - return m_matrix[col][row]; -} - -double wxTransformMatrix::operator()(int col, int row) const -{ - if (row < 0 || row > 2 || col < 0 || col > 2) - return 0.0; - - return m_matrix[col][row]; -} - -// Invert matrix -bool wxTransformMatrix::Invert(void) -{ - double inverseMatrix[3][3]; - - // calculate the adjoint - inverseMatrix[0][0] = wxCalculateDet(m_matrix[1][1],m_matrix[2][1],m_matrix[1][2],m_matrix[2][2]); - inverseMatrix[0][1] = -wxCalculateDet(m_matrix[0][1],m_matrix[2][1],m_matrix[0][2],m_matrix[2][2]); - inverseMatrix[0][2] = wxCalculateDet(m_matrix[0][1],m_matrix[1][1],m_matrix[0][2],m_matrix[1][2]); - - inverseMatrix[1][0] = -wxCalculateDet(m_matrix[1][0],m_matrix[2][0],m_matrix[1][2],m_matrix[2][2]); - inverseMatrix[1][1] = wxCalculateDet(m_matrix[0][0],m_matrix[2][0],m_matrix[0][2],m_matrix[2][2]); - inverseMatrix[1][2] = -wxCalculateDet(m_matrix[0][0],m_matrix[1][0],m_matrix[0][2],m_matrix[1][2]); - - inverseMatrix[2][0] = wxCalculateDet(m_matrix[1][0],m_matrix[2][0],m_matrix[1][1],m_matrix[2][1]); - inverseMatrix[2][1] = -wxCalculateDet(m_matrix[0][0],m_matrix[2][0],m_matrix[0][1],m_matrix[2][1]); - inverseMatrix[2][2] = wxCalculateDet(m_matrix[0][0],m_matrix[1][0],m_matrix[0][1],m_matrix[1][1]); - - // now divide by the determinant - double det = m_matrix[0][0] * inverseMatrix[0][0] + m_matrix[0][1] * inverseMatrix[1][0] + m_matrix[0][2] * inverseMatrix[2][0]; - if ( wxIsNullDouble(det) ) - return false; - - inverseMatrix[0][0] /= det; inverseMatrix[1][0] /= det; inverseMatrix[2][0] /= det; - inverseMatrix[0][1] /= det; inverseMatrix[1][1] /= det; inverseMatrix[2][1] /= det; - inverseMatrix[0][2] /= det; inverseMatrix[1][2] /= det; inverseMatrix[2][2] /= det; - - for (int i = 0; i < 3; i++) - { - for (int j = 0; j < 3; j++) - { - m_matrix[i][j] = inverseMatrix[i][j]; - } - } - m_isIdentity = IsIdentity1(); - return true; -} - -// Make into identity matrix -bool wxTransformMatrix::Identity(void) -{ - m_matrix[0][0] = m_matrix[1][1] = m_matrix[2][2] = 1.0; - m_matrix[1][0] = m_matrix[2][0] = m_matrix[0][1] = m_matrix[2][1] = m_matrix[0][2] = m_matrix[1][2] = 0.0; - m_isIdentity = true; - - return true; -} - -// Scale by scale (isotropic scaling i.e. the same in x and y): -// | scale 0 0 | -// matrix' = | 0 scale 0 | x matrix -// | 0 0 scale | -// -bool wxTransformMatrix::Scale(double scale) -{ - int i, j; - for (i = 0; i < 3; i++) - { - for (j = 0; j < 3; j++) - { - m_matrix[i][j] *= scale; - } - } - m_isIdentity = IsIdentity1(); - - return true; -} - - -// scale a matrix in 2D -// -// xs 0 xc(1-xs) -// 0 ys yc(1-ys) -// 0 0 1 -// -wxTransformMatrix& wxTransformMatrix::Scale(const double &xs, const double &ys,const double &xc, const double &yc) -{ - double r00,r10,r20,r01,r11,r21; - - if (m_isIdentity) - { - double tx = xc*(1-xs); - double ty = yc*(1-ys); - r00 = xs; - r10 = 0; - r20 = tx; - r01 = 0; - r11 = ys; - r21 = ty; - } - else if ( !wxIsNullDouble(xc) || !wxIsNullDouble(yc) ) - { - double tx = xc*(1-xs); - double ty = yc*(1-ys); - r00 = xs * m_matrix[0][0]; - r10 = xs * m_matrix[1][0]; - r20 = xs * m_matrix[2][0] + tx; - r01 = ys * m_matrix[0][1]; - r11 = ys * m_matrix[1][1]; - r21 = ys * m_matrix[2][1] + ty; - } - else - { - r00 = xs * m_matrix[0][0]; - r10 = xs * m_matrix[1][0]; - r20 = xs * m_matrix[2][0]; - r01 = ys * m_matrix[0][1]; - r11 = ys * m_matrix[1][1]; - r21 = ys * m_matrix[2][1]; - } - - m_matrix[0][0] = r00; - m_matrix[1][0] = r10; - m_matrix[2][0] = r20; - m_matrix[0][1] = r01; - m_matrix[1][1] = r11; - m_matrix[2][1] = r21; - -/* or like this - // first translate to origin O - (*this).Translate(-x_cen, -y_cen); - - // now do the scaling - wxTransformMatrix scale; - scale.m_matrix[0][0] = x_fac; - scale.m_matrix[1][1] = y_fac; - scale.m_isIdentity = IsIdentity1(); - - *this = scale * (*this); - - // translate back from origin to x_cen, y_cen - (*this).Translate(x_cen, y_cen); -*/ - - m_isIdentity = IsIdentity1(); - - return *this; -} - - -// mirror a matrix in x, y -// -// -1 0 0 Y-mirror -// 0 -1 0 X-mirror -// 0 0 -1 Z-mirror -wxTransformMatrix& wxTransformMatrix::Mirror(bool x, bool y) -{ - wxTransformMatrix temp; - if (x) - { - temp.m_matrix[1][1] = -1; - temp.m_isIdentity=false; - } - if (y) - { - temp.m_matrix[0][0] = -1; - temp.m_isIdentity=false; - } - - *this = temp * (*this); - m_isIdentity = IsIdentity1(); - return *this; -} - -// Translate by dx, dy: -// | 1 0 dx | -// matrix' = | 0 1 dy | x matrix -// | 0 0 1 | -// -bool wxTransformMatrix::Translate(double dx, double dy) -{ - int i; - for (i = 0; i < 3; i++) - m_matrix[i][0] += dx * m_matrix[i][2]; - for (i = 0; i < 3; i++) - m_matrix[i][1] += dy * m_matrix[i][2]; - - m_isIdentity = IsIdentity1(); - - return true; -} - -// Rotate clockwise by the given number of degrees: -// | cos sin 0 | -// matrix' = | -sin cos 0 | x matrix -// | 0 0 1 | -bool wxTransformMatrix::Rotate(double degrees) -{ - Rotate(-degrees,0,0); - return true; -} - -// counter clockwise rotate around a point -// -// cos(r) -sin(r) x(1-cos(r))+y(sin(r) -// sin(r) cos(r) y(1-cos(r))-x(sin(r) -// 0 0 1 -wxTransformMatrix& wxTransformMatrix::Rotate(const double °rees, const double &x, const double &y) -{ - double angle = degrees * pi / 180.0; - double c = cos(angle); - double s = sin(angle); - double r00,r10,r20,r01,r11,r21; - - if (m_isIdentity) - { - double tx = x*(1-c)+y*s; - double ty = y*(1-c)-x*s; - r00 = c ; - r10 = -s; - r20 = tx; - r01 = s; - r11 = c; - r21 = ty; - } - else if ( !wxIsNullDouble(x) || !wxIsNullDouble(y) ) - { - double tx = x*(1-c)+y*s; - double ty = y*(1-c)-x*s; - r00 = c * m_matrix[0][0] - s * m_matrix[0][1] + tx * m_matrix[0][2]; - r10 = c * m_matrix[1][0] - s * m_matrix[1][1] + tx * m_matrix[1][2]; - r20 = c * m_matrix[2][0] - s * m_matrix[2][1] + tx;// * m_matrix[2][2]; - r01 = c * m_matrix[0][1] + s * m_matrix[0][0] + ty * m_matrix[0][2]; - r11 = c * m_matrix[1][1] + s * m_matrix[1][0] + ty * m_matrix[1][2]; - r21 = c * m_matrix[2][1] + s * m_matrix[2][0] + ty;// * m_matrix[2][2]; - } - else - { - r00 = c * m_matrix[0][0] - s * m_matrix[0][1]; - r10 = c * m_matrix[1][0] - s * m_matrix[1][1]; - r20 = c * m_matrix[2][0] - s * m_matrix[2][1]; - r01 = c * m_matrix[0][1] + s * m_matrix[0][0]; - r11 = c * m_matrix[1][1] + s * m_matrix[1][0]; - r21 = c * m_matrix[2][1] + s * m_matrix[2][0]; - } - - m_matrix[0][0] = r00; - m_matrix[1][0] = r10; - m_matrix[2][0] = r20; - m_matrix[0][1] = r01; - m_matrix[1][1] = r11; - m_matrix[2][1] = r21; - -/* or like this - wxTransformMatrix rotate; - rotate.m_matrix[2][0] = tx; - rotate.m_matrix[2][1] = ty; - - rotate.m_matrix[0][0] = c; - rotate.m_matrix[0][1] = s; - - rotate.m_matrix[1][0] = -s; - rotate.m_matrix[1][1] = c; - - rotate.m_isIdentity=false; - *this = rotate * (*this); -*/ - m_isIdentity = IsIdentity1(); - - return *this; -} - -// Transform a point from logical to device coordinates -bool wxTransformMatrix::TransformPoint(double x, double y, double& tx, double& ty) const -{ - if (IsIdentity()) - { - tx = x; ty = y; return true; - } - - tx = x * m_matrix[0][0] + y * m_matrix[1][0] + m_matrix[2][0]; - ty = x * m_matrix[0][1] + y * m_matrix[1][1] + m_matrix[2][1]; - - return true; -} - -// Transform a point from device to logical coordinates. - -// Example of use: -// wxTransformMatrix mat = dc.GetTransformation(); -// mat.Invert(); -// mat.InverseTransformPoint(x, y, x1, y1); -// OR (shorthand:) -// dc.LogicalToDevice(x, y, x1, y1); -// The latter is slightly less efficient if we're doing several -// conversions, since the matrix is inverted several times. -bool wxTransformMatrix::InverseTransformPoint(double x, double y, double& tx, double& ty) const -{ - if (IsIdentity()) - { - tx = x; - ty = y; - return true; - } - - const double z = (1.0 - m_matrix[0][2] * x - m_matrix[1][2] * y) / m_matrix[2][2]; - if ( wxIsNullDouble(z) ) - return false; - - tx = x * m_matrix[0][0] + y * m_matrix[1][0] + z * m_matrix[2][0]; - ty = x * m_matrix[0][1] + y * m_matrix[1][1] + z * m_matrix[2][1]; - return true; -} - -wxTransformMatrix& wxTransformMatrix::operator*=(const double& t) -{ - for (int i = 0; i < 3; i++) - for (int j = 0; j < 3; j++) - m_matrix[i][j]*= t; - m_isIdentity = IsIdentity1(); - return *this; -} - -wxTransformMatrix& wxTransformMatrix::operator/=(const double& t) -{ - for (int i = 0; i < 3; i++) - for (int j = 0; j < 3; j++) - m_matrix[i][j]/= t; - m_isIdentity = IsIdentity1(); - return *this; -} - -wxTransformMatrix& wxTransformMatrix::operator+=(const wxTransformMatrix& mat) -{ - for (int i = 0; i < 3; i++) - for (int j = 0; j < 3; j++) - m_matrix[i][j] += mat.m_matrix[i][j]; - m_isIdentity = IsIdentity1(); - return *this; -} - -wxTransformMatrix& wxTransformMatrix::operator-=(const wxTransformMatrix& mat) -{ - for (int i = 0; i < 3; i++) - for (int j = 0; j < 3; j++) - m_matrix[i][j] -= mat.m_matrix[i][j]; - m_isIdentity = IsIdentity1(); - return *this; -} - -wxTransformMatrix& wxTransformMatrix::operator*=(const wxTransformMatrix& mat) -{ - - if (mat.m_isIdentity) - return *this; - if (m_isIdentity) - { - *this = mat; - return *this; - } - else - { - wxTransformMatrix result; - for (int i = 0; i < 3; i++) - { - for (int j = 0; j < 3; j++) - { - double sum = 0; - for (int k = 0; k < 3; k++) - sum += m_matrix[k][i] * mat.m_matrix[j][k]; - result.m_matrix[j][i] = sum; - } - } - *this = result; - } - - m_isIdentity = IsIdentity1(); - return *this; -} - - -// constant operators -wxTransformMatrix wxTransformMatrix::operator*(const double& t) const -{ - wxTransformMatrix result = *this; - result *= t; - result.m_isIdentity = result.IsIdentity1(); - return result; -} - -wxTransformMatrix wxTransformMatrix::operator/(const double& t) const -{ - wxTransformMatrix result = *this; -// wxASSERT(t!=0); - result /= t; - result.m_isIdentity = result.IsIdentity1(); - return result; -} - -wxTransformMatrix wxTransformMatrix::operator+(const wxTransformMatrix& m) const -{ - wxTransformMatrix result = *this; - result += m; - result.m_isIdentity = result.IsIdentity1(); - return result; -} - -wxTransformMatrix wxTransformMatrix::operator-(const wxTransformMatrix& m) const -{ - wxTransformMatrix result = *this; - result -= m; - result.m_isIdentity = result.IsIdentity1(); - return result; -} - - -wxTransformMatrix wxTransformMatrix::operator*(const wxTransformMatrix& m) const -{ - wxTransformMatrix result = *this; - result *= m; - result.m_isIdentity = result.IsIdentity1(); - return result; -} - - -wxTransformMatrix wxTransformMatrix::operator-() const -{ - wxTransformMatrix result = *this; - for (int i = 0; i < 3; i++) - for (int j = 0; j < 3; j++) - result.m_matrix[i][j] = -(this->m_matrix[i][j]); - result.m_isIdentity = result.IsIdentity1(); - return result; -} - -static double CheckInt(double getal) -{ - // check if the number is very close to an integer - if ( (ceil(getal) - getal) < 0.0001) - return ceil(getal); - - else if ( (getal - floor(getal)) < 0.0001) - return floor(getal); - - return getal; - -} - -double wxTransformMatrix::Get_scaleX() -{ - double scale_factor; - double rot_angle = CheckInt(atan2(m_matrix[1][0],m_matrix[0][0])*180/pi); - if ( !wxIsSameDouble(rot_angle, 90) && !wxIsSameDouble(rot_angle, -90) ) - scale_factor = m_matrix[0][0]/cos((rot_angle/180)*pi); - else - scale_factor = m_matrix[0][0]/sin((rot_angle/180)*pi); // er kan nl. niet door 0 gedeeld worden ! - - scale_factor = CheckInt(scale_factor); - if (scale_factor < 0) - scale_factor = -scale_factor; - - return scale_factor; -} - -double wxTransformMatrix::Get_scaleY() -{ - double scale_factor; - double rot_angle = CheckInt(atan2(m_matrix[1][0],m_matrix[0][0])*180/pi); - if ( !wxIsSameDouble(rot_angle, 90) && !wxIsSameDouble(rot_angle, -90) ) - scale_factor = m_matrix[1][1]/cos((rot_angle/180)*pi); - else - scale_factor = m_matrix[1][1]/sin((rot_angle/180)*pi); // er kan nl. niet door 0 gedeeld worden ! - - scale_factor = CheckInt(scale_factor); - if (scale_factor < 0) - - scale_factor = -scale_factor; - - return scale_factor; - -} - -double wxTransformMatrix::GetRotation() -{ - double temp1 = GetValue(0,0); // for angle calculation - double temp2 = GetValue(0,1); // - - // Rotation - double rot_angle = atan2(temp2,temp1)*180/pi; - - rot_angle = CheckInt(rot_angle); - return rot_angle; -} - -void wxTransformMatrix::SetRotation(double rotation) -{ - double x=GetValue(2,0); - double y=GetValue(2,1); - Rotate(-GetRotation(), x, y); - Rotate(rotation, x, y); -} +/////////////////////////////////////////////////////////////////////////////// +// Name: src/common/matrix.cpp +// Purpose: wxTransformMatrix class +// Author: Chris Breeze, Julian Smart +// Modified by: Klaas Holwerda +// Created: 01/02/97 +// RCS-ID: $Id: matrix.cpp 39745 2006-06-15 17:58:49Z ABX $ +// Copyright: (c) Julian Smart +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +// Note: this is intended to be used in wxDC at some point to replace +// the current system of scaling/translation. It is not yet used. + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#include "wx/matrix.h" + +#ifndef WX_PRECOMP + #include "wx/math.h" +#endif + +static const double pi = M_PI; + +wxTransformMatrix::wxTransformMatrix(void) +{ + m_isIdentity = false; + + Identity(); +} + +wxTransformMatrix::wxTransformMatrix(const wxTransformMatrix& mat) + : wxObject() +{ + (*this) = mat; +} + +double wxTransformMatrix::GetValue(int col, int row) const +{ + if (row < 0 || row > 2 || col < 0 || col > 2) + return 0.0; + + return m_matrix[col][row]; +} + +void wxTransformMatrix::SetValue(int col, int row, double value) +{ + if (row < 0 || row > 2 || col < 0 || col > 2) + return; + + m_matrix[col][row] = value; + m_isIdentity = IsIdentity1(); +} + +void wxTransformMatrix::operator = (const wxTransformMatrix& mat) +{ + int i, j; + for (i = 0; i < 3; i++) + { + for (j = 0; j < 3; j++) + { + m_matrix[i][j] = mat.m_matrix[i][j]; + } + } + m_isIdentity = mat.m_isIdentity; +} + +bool wxTransformMatrix::operator == (const wxTransformMatrix& mat) const +{ + if (m_isIdentity && mat.m_isIdentity) + return true; + + int i, j; + for (i = 0; i < 3; i++) + { + for (j = 0; j < 3; j++) + { + if ( !wxIsSameDouble(m_matrix[i][j], mat.m_matrix[i][j]) ) + return false; + } + } + return true; +} + +bool wxTransformMatrix::operator != (const wxTransformMatrix& mat) const +{ + return (! ((*this) == mat)); +} + +double& wxTransformMatrix::operator()(int col, int row) +{ + if (row < 0 || row > 2 || col < 0 || col > 2) + return m_matrix[0][0]; + + return m_matrix[col][row]; +} + +double wxTransformMatrix::operator()(int col, int row) const +{ + if (row < 0 || row > 2 || col < 0 || col > 2) + return 0.0; + + return m_matrix[col][row]; +} + +// Invert matrix +bool wxTransformMatrix::Invert(void) +{ + double inverseMatrix[3][3]; + + // calculate the adjoint + inverseMatrix[0][0] = wxCalculateDet(m_matrix[1][1],m_matrix[2][1],m_matrix[1][2],m_matrix[2][2]); + inverseMatrix[0][1] = -wxCalculateDet(m_matrix[0][1],m_matrix[2][1],m_matrix[0][2],m_matrix[2][2]); + inverseMatrix[0][2] = wxCalculateDet(m_matrix[0][1],m_matrix[1][1],m_matrix[0][2],m_matrix[1][2]); + + inverseMatrix[1][0] = -wxCalculateDet(m_matrix[1][0],m_matrix[2][0],m_matrix[1][2],m_matrix[2][2]); + inverseMatrix[1][1] = wxCalculateDet(m_matrix[0][0],m_matrix[2][0],m_matrix[0][2],m_matrix[2][2]); + inverseMatrix[1][2] = -wxCalculateDet(m_matrix[0][0],m_matrix[1][0],m_matrix[0][2],m_matrix[1][2]); + + inverseMatrix[2][0] = wxCalculateDet(m_matrix[1][0],m_matrix[2][0],m_matrix[1][1],m_matrix[2][1]); + inverseMatrix[2][1] = -wxCalculateDet(m_matrix[0][0],m_matrix[2][0],m_matrix[0][1],m_matrix[2][1]); + inverseMatrix[2][2] = wxCalculateDet(m_matrix[0][0],m_matrix[1][0],m_matrix[0][1],m_matrix[1][1]); + + // now divide by the determinant + double det = m_matrix[0][0] * inverseMatrix[0][0] + m_matrix[0][1] * inverseMatrix[1][0] + m_matrix[0][2] * inverseMatrix[2][0]; + if ( wxIsNullDouble(det) ) + return false; + + inverseMatrix[0][0] /= det; inverseMatrix[1][0] /= det; inverseMatrix[2][0] /= det; + inverseMatrix[0][1] /= det; inverseMatrix[1][1] /= det; inverseMatrix[2][1] /= det; + inverseMatrix[0][2] /= det; inverseMatrix[1][2] /= det; inverseMatrix[2][2] /= det; + + for (int i = 0; i < 3; i++) + { + for (int j = 0; j < 3; j++) + { + m_matrix[i][j] = inverseMatrix[i][j]; + } + } + m_isIdentity = IsIdentity1(); + return true; +} + +// Make into identity matrix +bool wxTransformMatrix::Identity(void) +{ + m_matrix[0][0] = m_matrix[1][1] = m_matrix[2][2] = 1.0; + m_matrix[1][0] = m_matrix[2][0] = m_matrix[0][1] = m_matrix[2][1] = m_matrix[0][2] = m_matrix[1][2] = 0.0; + m_isIdentity = true; + + return true; +} + +// Scale by scale (isotropic scaling i.e. the same in x and y): +// | scale 0 0 | +// matrix' = | 0 scale 0 | x matrix +// | 0 0 scale | +// +bool wxTransformMatrix::Scale(double scale) +{ + int i, j; + for (i = 0; i < 3; i++) + { + for (j = 0; j < 3; j++) + { + m_matrix[i][j] *= scale; + } + } + m_isIdentity = IsIdentity1(); + + return true; +} + + +// scale a matrix in 2D +// +// xs 0 xc(1-xs) +// 0 ys yc(1-ys) +// 0 0 1 +// +wxTransformMatrix& wxTransformMatrix::Scale(const double &xs, const double &ys,const double &xc, const double &yc) +{ + double r00,r10,r20,r01,r11,r21; + + if (m_isIdentity) + { + double tx = xc*(1-xs); + double ty = yc*(1-ys); + r00 = xs; + r10 = 0; + r20 = tx; + r01 = 0; + r11 = ys; + r21 = ty; + } + else if ( !wxIsNullDouble(xc) || !wxIsNullDouble(yc) ) + { + double tx = xc*(1-xs); + double ty = yc*(1-ys); + r00 = xs * m_matrix[0][0]; + r10 = xs * m_matrix[1][0]; + r20 = xs * m_matrix[2][0] + tx; + r01 = ys * m_matrix[0][1]; + r11 = ys * m_matrix[1][1]; + r21 = ys * m_matrix[2][1] + ty; + } + else + { + r00 = xs * m_matrix[0][0]; + r10 = xs * m_matrix[1][0]; + r20 = xs * m_matrix[2][0]; + r01 = ys * m_matrix[0][1]; + r11 = ys * m_matrix[1][1]; + r21 = ys * m_matrix[2][1]; + } + + m_matrix[0][0] = r00; + m_matrix[1][0] = r10; + m_matrix[2][0] = r20; + m_matrix[0][1] = r01; + m_matrix[1][1] = r11; + m_matrix[2][1] = r21; + +/* or like this + // first translate to origin O + (*this).Translate(-x_cen, -y_cen); + + // now do the scaling + wxTransformMatrix scale; + scale.m_matrix[0][0] = x_fac; + scale.m_matrix[1][1] = y_fac; + scale.m_isIdentity = IsIdentity1(); + + *this = scale * (*this); + + // translate back from origin to x_cen, y_cen + (*this).Translate(x_cen, y_cen); +*/ + + m_isIdentity = IsIdentity1(); + + return *this; +} + + +// mirror a matrix in x, y +// +// -1 0 0 Y-mirror +// 0 -1 0 X-mirror +// 0 0 -1 Z-mirror +wxTransformMatrix& wxTransformMatrix::Mirror(bool x, bool y) +{ + wxTransformMatrix temp; + if (x) + { + temp.m_matrix[1][1] = -1; + temp.m_isIdentity=false; + } + if (y) + { + temp.m_matrix[0][0] = -1; + temp.m_isIdentity=false; + } + + *this = temp * (*this); + m_isIdentity = IsIdentity1(); + return *this; +} + +// Translate by dx, dy: +// | 1 0 dx | +// matrix' = | 0 1 dy | x matrix +// | 0 0 1 | +// +bool wxTransformMatrix::Translate(double dx, double dy) +{ + int i; + for (i = 0; i < 3; i++) + m_matrix[i][0] += dx * m_matrix[i][2]; + for (i = 0; i < 3; i++) + m_matrix[i][1] += dy * m_matrix[i][2]; + + m_isIdentity = IsIdentity1(); + + return true; +} + +// Rotate clockwise by the given number of degrees: +// | cos sin 0 | +// matrix' = | -sin cos 0 | x matrix +// | 0 0 1 | +bool wxTransformMatrix::Rotate(double degrees) +{ + Rotate(-degrees,0,0); + return true; +} + +// counter clockwise rotate around a point +// +// cos(r) -sin(r) x(1-cos(r))+y(sin(r) +// sin(r) cos(r) y(1-cos(r))-x(sin(r) +// 0 0 1 +wxTransformMatrix& wxTransformMatrix::Rotate(const double °rees, const double &x, const double &y) +{ + double angle = degrees * pi / 180.0; + double c = cos(angle); + double s = sin(angle); + double r00,r10,r20,r01,r11,r21; + + if (m_isIdentity) + { + double tx = x*(1-c)+y*s; + double ty = y*(1-c)-x*s; + r00 = c ; + r10 = -s; + r20 = tx; + r01 = s; + r11 = c; + r21 = ty; + } + else if ( !wxIsNullDouble(x) || !wxIsNullDouble(y) ) + { + double tx = x*(1-c)+y*s; + double ty = y*(1-c)-x*s; + r00 = c * m_matrix[0][0] - s * m_matrix[0][1] + tx * m_matrix[0][2]; + r10 = c * m_matrix[1][0] - s * m_matrix[1][1] + tx * m_matrix[1][2]; + r20 = c * m_matrix[2][0] - s * m_matrix[2][1] + tx;// * m_matrix[2][2]; + r01 = c * m_matrix[0][1] + s * m_matrix[0][0] + ty * m_matrix[0][2]; + r11 = c * m_matrix[1][1] + s * m_matrix[1][0] + ty * m_matrix[1][2]; + r21 = c * m_matrix[2][1] + s * m_matrix[2][0] + ty;// * m_matrix[2][2]; + } + else + { + r00 = c * m_matrix[0][0] - s * m_matrix[0][1]; + r10 = c * m_matrix[1][0] - s * m_matrix[1][1]; + r20 = c * m_matrix[2][0] - s * m_matrix[2][1]; + r01 = c * m_matrix[0][1] + s * m_matrix[0][0]; + r11 = c * m_matrix[1][1] + s * m_matrix[1][0]; + r21 = c * m_matrix[2][1] + s * m_matrix[2][0]; + } + + m_matrix[0][0] = r00; + m_matrix[1][0] = r10; + m_matrix[2][0] = r20; + m_matrix[0][1] = r01; + m_matrix[1][1] = r11; + m_matrix[2][1] = r21; + +/* or like this + wxTransformMatrix rotate; + rotate.m_matrix[2][0] = tx; + rotate.m_matrix[2][1] = ty; + + rotate.m_matrix[0][0] = c; + rotate.m_matrix[0][1] = s; + + rotate.m_matrix[1][0] = -s; + rotate.m_matrix[1][1] = c; + + rotate.m_isIdentity=false; + *this = rotate * (*this); +*/ + m_isIdentity = IsIdentity1(); + + return *this; +} + +// Transform a point from logical to device coordinates +bool wxTransformMatrix::TransformPoint(double x, double y, double& tx, double& ty) const +{ + if (IsIdentity()) + { + tx = x; ty = y; return true; + } + + tx = x * m_matrix[0][0] + y * m_matrix[1][0] + m_matrix[2][0]; + ty = x * m_matrix[0][1] + y * m_matrix[1][1] + m_matrix[2][1]; + + return true; +} + +// Transform a point from device to logical coordinates. + +// Example of use: +// wxTransformMatrix mat = dc.GetTransformation(); +// mat.Invert(); +// mat.InverseTransformPoint(x, y, x1, y1); +// OR (shorthand:) +// dc.LogicalToDevice(x, y, x1, y1); +// The latter is slightly less efficient if we're doing several +// conversions, since the matrix is inverted several times. +bool wxTransformMatrix::InverseTransformPoint(double x, double y, double& tx, double& ty) const +{ + if (IsIdentity()) + { + tx = x; + ty = y; + return true; + } + + const double z = (1.0 - m_matrix[0][2] * x - m_matrix[1][2] * y) / m_matrix[2][2]; + if ( wxIsNullDouble(z) ) + return false; + + tx = x * m_matrix[0][0] + y * m_matrix[1][0] + z * m_matrix[2][0]; + ty = x * m_matrix[0][1] + y * m_matrix[1][1] + z * m_matrix[2][1]; + return true; +} + +wxTransformMatrix& wxTransformMatrix::operator*=(const double& t) +{ + for (int i = 0; i < 3; i++) + for (int j = 0; j < 3; j++) + m_matrix[i][j]*= t; + m_isIdentity = IsIdentity1(); + return *this; +} + +wxTransformMatrix& wxTransformMatrix::operator/=(const double& t) +{ + for (int i = 0; i < 3; i++) + for (int j = 0; j < 3; j++) + m_matrix[i][j]/= t; + m_isIdentity = IsIdentity1(); + return *this; +} + +wxTransformMatrix& wxTransformMatrix::operator+=(const wxTransformMatrix& mat) +{ + for (int i = 0; i < 3; i++) + for (int j = 0; j < 3; j++) + m_matrix[i][j] += mat.m_matrix[i][j]; + m_isIdentity = IsIdentity1(); + return *this; +} + +wxTransformMatrix& wxTransformMatrix::operator-=(const wxTransformMatrix& mat) +{ + for (int i = 0; i < 3; i++) + for (int j = 0; j < 3; j++) + m_matrix[i][j] -= mat.m_matrix[i][j]; + m_isIdentity = IsIdentity1(); + return *this; +} + +wxTransformMatrix& wxTransformMatrix::operator*=(const wxTransformMatrix& mat) +{ + + if (mat.m_isIdentity) + return *this; + if (m_isIdentity) + { + *this = mat; + return *this; + } + else + { + wxTransformMatrix result; + for (int i = 0; i < 3; i++) + { + for (int j = 0; j < 3; j++) + { + double sum = 0; + for (int k = 0; k < 3; k++) + sum += m_matrix[k][i] * mat.m_matrix[j][k]; + result.m_matrix[j][i] = sum; + } + } + *this = result; + } + + m_isIdentity = IsIdentity1(); + return *this; +} + + +// constant operators +wxTransformMatrix wxTransformMatrix::operator*(const double& t) const +{ + wxTransformMatrix result = *this; + result *= t; + result.m_isIdentity = result.IsIdentity1(); + return result; +} + +wxTransformMatrix wxTransformMatrix::operator/(const double& t) const +{ + wxTransformMatrix result = *this; +// wxASSERT(t!=0); + result /= t; + result.m_isIdentity = result.IsIdentity1(); + return result; +} + +wxTransformMatrix wxTransformMatrix::operator+(const wxTransformMatrix& m) const +{ + wxTransformMatrix result = *this; + result += m; + result.m_isIdentity = result.IsIdentity1(); + return result; +} + +wxTransformMatrix wxTransformMatrix::operator-(const wxTransformMatrix& m) const +{ + wxTransformMatrix result = *this; + result -= m; + result.m_isIdentity = result.IsIdentity1(); + return result; +} + + +wxTransformMatrix wxTransformMatrix::operator*(const wxTransformMatrix& m) const +{ + wxTransformMatrix result = *this; + result *= m; + result.m_isIdentity = result.IsIdentity1(); + return result; +} + + +wxTransformMatrix wxTransformMatrix::operator-() const +{ + wxTransformMatrix result = *this; + for (int i = 0; i < 3; i++) + for (int j = 0; j < 3; j++) + result.m_matrix[i][j] = -(this->m_matrix[i][j]); + result.m_isIdentity = result.IsIdentity1(); + return result; +} + +static double CheckInt(double getal) +{ + // check if the number is very close to an integer + if ( (ceil(getal) - getal) < 0.0001) + return ceil(getal); + + else if ( (getal - floor(getal)) < 0.0001) + return floor(getal); + + return getal; + +} + +double wxTransformMatrix::Get_scaleX() +{ + double scale_factor; + double rot_angle = CheckInt(atan2(m_matrix[1][0],m_matrix[0][0])*180/pi); + if ( !wxIsSameDouble(rot_angle, 90) && !wxIsSameDouble(rot_angle, -90) ) + scale_factor = m_matrix[0][0]/cos((rot_angle/180)*pi); + else + scale_factor = m_matrix[0][0]/sin((rot_angle/180)*pi); // er kan nl. niet door 0 gedeeld worden ! + + scale_factor = CheckInt(scale_factor); + if (scale_factor < 0) + scale_factor = -scale_factor; + + return scale_factor; +} + +double wxTransformMatrix::Get_scaleY() +{ + double scale_factor; + double rot_angle = CheckInt(atan2(m_matrix[1][0],m_matrix[0][0])*180/pi); + if ( !wxIsSameDouble(rot_angle, 90) && !wxIsSameDouble(rot_angle, -90) ) + scale_factor = m_matrix[1][1]/cos((rot_angle/180)*pi); + else + scale_factor = m_matrix[1][1]/sin((rot_angle/180)*pi); // er kan nl. niet door 0 gedeeld worden ! + + scale_factor = CheckInt(scale_factor); + if (scale_factor < 0) + + scale_factor = -scale_factor; + + return scale_factor; + +} + +double wxTransformMatrix::GetRotation() +{ + double temp1 = GetValue(0,0); // for angle calculation + double temp2 = GetValue(0,1); // + + // Rotation + double rot_angle = atan2(temp2,temp1)*180/pi; + + rot_angle = CheckInt(rot_angle); + return rot_angle; +} + +void wxTransformMatrix::SetRotation(double rotation) +{ + double x=GetValue(2,0); + double y=GetValue(2,1); + Rotate(-GetRotation(), x, y); + Rotate(rotation, x, y); +} diff --git a/Externals/wxWidgets/src/common/mediactrlcmn.cpp b/Externals/wxWidgets/src/common/mediactrlcmn.cpp index 4585eed501..4c25559d6b 100644 --- a/Externals/wxWidgets/src/common/mediactrlcmn.cpp +++ b/Externals/wxWidgets/src/common/mediactrlcmn.cpp @@ -1,559 +1,559 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/mediactrl.cpp -// Purpose: wxMediaCtrl common code -// Author: Ryan Norton -// Modified by: -// Created: 11/07/04 -// RCS-ID: $Id: mediactrlcmn.cpp 42816 2006-10-31 08:50:17Z RD $ -// Copyright: (c) Ryan Norton -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// TODO: Platform specific backend defaults? - -//=========================================================================== -// Definitions -//=========================================================================== - -//--------------------------------------------------------------------------- -// Pre-compiled header stuff -//--------------------------------------------------------------------------- - -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_MEDIACTRL - -#ifndef WX_PRECOMP - #include "wx/hash.h" -#endif - -//--------------------------------------------------------------------------- -// Includes -//--------------------------------------------------------------------------- -#include "wx/mediactrl.h" - -//=========================================================================== -// -// Implementation -// -//=========================================================================== - -//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -// RTTI and Event implementations -//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - -IMPLEMENT_CLASS(wxMediaCtrl, wxControl) -DEFINE_EVENT_TYPE(wxEVT_MEDIA_STATECHANGED) -DEFINE_EVENT_TYPE(wxEVT_MEDIA_PLAY) -DEFINE_EVENT_TYPE(wxEVT_MEDIA_PAUSE) -IMPLEMENT_CLASS(wxMediaBackend, wxObject) -IMPLEMENT_DYNAMIC_CLASS(wxMediaEvent, wxEvent) -DEFINE_EVENT_TYPE(wxEVT_MEDIA_FINISHED) -DEFINE_EVENT_TYPE(wxEVT_MEDIA_LOADED) -DEFINE_EVENT_TYPE(wxEVT_MEDIA_STOP) - -//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -// -// wxMediaCtrl -// -//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - -//--------------------------------------------------------------------------- -// wxMediaBackend Destructor -// -// This is here because the DARWIN gcc compiler badly screwed up and -// needs the destructor implementation in the source -//--------------------------------------------------------------------------- -wxMediaBackend::~wxMediaBackend() -{ -} - -//--------------------------------------------------------------------------- -// wxMediaCtrl::Create (file version) -// wxMediaCtrl::Create (URL version) -// -// Searches for a backend that is installed on the system (backends -// starting with lower characters in the alphabet are given priority), -// and creates the control from it -// -// This searches by searching the global RTTI hashtable, class by class, -// attempting to call CreateControl on each one found that is a derivative -// of wxMediaBackend - if it succeeded Create returns true, otherwise -// it keeps iterating through the hashmap. -//--------------------------------------------------------------------------- -bool wxMediaCtrl::Create(wxWindow* parent, wxWindowID id, - const wxString& fileName, - const wxPoint& pos, - const wxSize& size, - long style, - const wxString& szBackend, - const wxValidator& validator, - const wxString& name) -{ - if(!szBackend.empty()) - { - wxClassInfo* pClassInfo = wxClassInfo::FindClass(szBackend); - - if(!pClassInfo || !DoCreate(pClassInfo, parent, id, - pos, size, style, validator, name)) - { - m_imp = NULL; - return false; - } - - if (!fileName.empty()) - { - if (!Load(fileName)) - { - delete m_imp; - m_imp = NULL; - return false; - } - } - - SetInitialSize(size); - return true; - } - else - { - wxClassInfo::sm_classTable->BeginFind(); - - wxClassInfo* classInfo; - - while((classInfo = NextBackend()) != NULL) - { - if(!DoCreate(classInfo, parent, id, - pos, size, style, validator, name)) - continue; - - if (!fileName.empty()) - { - if (Load(fileName)) - { - SetInitialSize(size); - return true; - } - else - delete m_imp; - } - else - { - SetInitialSize(size); - return true; - } - } - - m_imp = NULL; - return false; - } -} - -bool wxMediaCtrl::Create(wxWindow* parent, wxWindowID id, - const wxURI& location, - const wxPoint& pos, - const wxSize& size, - long style, - const wxString& szBackend, - const wxValidator& validator, - const wxString& name) -{ - if(!szBackend.empty()) - { - wxClassInfo* pClassInfo = wxClassInfo::FindClass(szBackend); - if(!pClassInfo || !DoCreate(pClassInfo, parent, id, - pos, size, style, validator, name)) - { - m_imp = NULL; - return false; - } - - if (!Load(location)) - { - delete m_imp; - m_imp = NULL; - return false; - } - - SetInitialSize(size); - return true; - } - else - { - wxClassInfo::sm_classTable->BeginFind(); - - wxClassInfo* classInfo; - - while((classInfo = NextBackend()) != NULL) - { - if(!DoCreate(classInfo, parent, id, - pos, size, style, validator, name)) - continue; - - if (Load(location)) - { - SetInitialSize(size); - return true; - } - else - delete m_imp; - } - - m_imp = NULL; - return false; - } -} - -//--------------------------------------------------------------------------- -// wxMediaCtrl::DoCreate -// -// Attempts to create the control from a backend -//--------------------------------------------------------------------------- -bool wxMediaCtrl::DoCreate(wxClassInfo* classInfo, - wxWindow* parent, wxWindowID id, - const wxPoint& pos, - const wxSize& size, - long style, - const wxValidator& validator, - const wxString& name) -{ - m_imp = (wxMediaBackend*)classInfo->CreateObject(); - - if( m_imp->CreateControl(this, parent, id, pos, size, - style, validator, name) ) - { - return true; - } - - delete m_imp; - return false; -} - -//--------------------------------------------------------------------------- -// wxMediaCtrl::NextBackend (static) -// -// -// Search through the RTTI hashmap one at a -// time, attempting to create each derivative -// of wxMediaBackend -// -// -// STL isn't compatible with and will have a compilation error -// on a wxNode, however, wxHashTable::compatibility_iterator is -// incompatible with the old 2.4 stable version - but since -// we're in 2.5+ only we don't need to worry about the new version -//--------------------------------------------------------------------------- -wxClassInfo* wxMediaCtrl::NextBackend() -{ - wxHashTable::compatibility_iterator - node = wxClassInfo::sm_classTable->Next(); - while (node) - { - wxClassInfo* classInfo = (wxClassInfo *)node->GetData(); - if ( classInfo->IsKindOf(CLASSINFO(wxMediaBackend)) && - classInfo != CLASSINFO(wxMediaBackend) ) - { - return classInfo; - } - node = wxClassInfo::sm_classTable->Next(); - } - - // - // Nope - couldn't successfully find one... fail - // - return NULL; -} - - -//--------------------------------------------------------------------------- -// wxMediaCtrl Destructor -// -// Free up the backend if it exists -//--------------------------------------------------------------------------- -wxMediaCtrl::~wxMediaCtrl() -{ - if (m_imp) - delete m_imp; -} - -//--------------------------------------------------------------------------- -// wxMediaCtrl::Load (file version) -// wxMediaCtrl::Load (URL version) -// wxMediaCtrl::Load (URL & Proxy version) -// wxMediaCtrl::Load (wxInputStream version) -// -// Here we call load of the backend - keeping -// track of whether it was successful or not - which -// will determine which later method calls work -//--------------------------------------------------------------------------- -bool wxMediaCtrl::Load(const wxString& fileName) -{ - if(m_imp) - return (m_bLoaded = m_imp->Load(fileName)); - return false; -} - -bool wxMediaCtrl::Load(const wxURI& location) -{ - if(m_imp) - return (m_bLoaded = m_imp->Load(location)); - return false; -} - -bool wxMediaCtrl::Load(const wxURI& location, const wxURI& proxy) -{ - if(m_imp) - return (m_bLoaded = m_imp->Load(location, proxy)); - return false; -} - -//--------------------------------------------------------------------------- -// wxMediaCtrl::Play -// wxMediaCtrl::Pause -// wxMediaCtrl::Stop -// wxMediaCtrl::GetPlaybackRate -// wxMediaCtrl::SetPlaybackRate -// wxMediaCtrl::Seek --> SetPosition -// wxMediaCtrl::Tell --> GetPosition -// wxMediaCtrl::Length --> GetDuration -// wxMediaCtrl::GetState -// wxMediaCtrl::DoGetBestSize -// wxMediaCtrl::SetVolume -// wxMediaCtrl::GetVolume -// wxMediaCtrl::ShowInterface -// wxMediaCtrl::GetDownloadProgress -// wxMediaCtrl::GetDownloadTotal -// -// 1) Check to see whether the backend exists and is loading -// 2) Call the backend's version of the method, returning success -// if the backend's version succeeds -//--------------------------------------------------------------------------- -bool wxMediaCtrl::Play() -{ - if(m_imp && m_bLoaded) - return m_imp->Play(); - return 0; -} - -bool wxMediaCtrl::Pause() -{ - if(m_imp && m_bLoaded) - return m_imp->Pause(); - return 0; -} - -bool wxMediaCtrl::Stop() -{ - if(m_imp && m_bLoaded) - return m_imp->Stop(); - return 0; -} - -double wxMediaCtrl::GetPlaybackRate() -{ - if(m_imp && m_bLoaded) - return m_imp->GetPlaybackRate(); - return 0; -} - -bool wxMediaCtrl::SetPlaybackRate(double dRate) -{ - if(m_imp && m_bLoaded) - return m_imp->SetPlaybackRate(dRate); - return false; -} - -wxFileOffset wxMediaCtrl::Seek(wxFileOffset where, wxSeekMode mode) -{ - wxFileOffset offset; - - switch (mode) - { - case wxFromStart: - offset = where; - break; - case wxFromEnd: - offset = Length() - where; - break; -// case wxFromCurrent: - default: - offset = Tell() + where; - break; - } - - if(m_imp && m_bLoaded && m_imp->SetPosition(offset)) - return offset; - return wxInvalidOffset; -} - -wxFileOffset wxMediaCtrl::Tell() -{ - if(m_imp && m_bLoaded) - return (wxFileOffset) m_imp->GetPosition().ToLong(); - return wxInvalidOffset; -} - -wxFileOffset wxMediaCtrl::Length() -{ - if(m_imp && m_bLoaded) - return (wxFileOffset) m_imp->GetDuration().ToLong(); - return wxInvalidOffset; -} - -wxMediaState wxMediaCtrl::GetState() -{ - if(m_imp && m_bLoaded) - return m_imp->GetState(); - return wxMEDIASTATE_STOPPED; -} - -wxSize wxMediaCtrl::DoGetBestSize() const -{ - if(m_imp) - return m_imp->GetVideoSize(); - return wxSize(0,0); -} - -double wxMediaCtrl::GetVolume() -{ - if(m_imp && m_bLoaded) - return m_imp->GetVolume(); - return 0.0; -} - -bool wxMediaCtrl::SetVolume(double dVolume) -{ - if(m_imp && m_bLoaded) - return m_imp->SetVolume(dVolume); - return false; -} - -bool wxMediaCtrl::ShowPlayerControls(wxMediaCtrlPlayerControls flags) -{ - if(m_imp) - return m_imp->ShowPlayerControls(flags); - return false; -} - -wxFileOffset wxMediaCtrl::GetDownloadProgress() -{ - if(m_imp && m_bLoaded) - return (wxFileOffset) m_imp->GetDownloadProgress().ToLong(); - return wxInvalidOffset; -} - -wxFileOffset wxMediaCtrl::GetDownloadTotal() -{ - if(m_imp && m_bLoaded) - return (wxFileOffset) m_imp->GetDownloadTotal().ToLong(); - return wxInvalidOffset; -} - -//--------------------------------------------------------------------------- -// wxMediaCtrl::DoMoveWindow -// -// 1) Call parent's version so that our control's window moves where -// it's supposed to -// 2) If the backend exists and is loaded, move the video -// of the media to where our control's window is now located -//--------------------------------------------------------------------------- -void wxMediaCtrl::DoMoveWindow(int x, int y, int w, int h) -{ - wxControl::DoMoveWindow(x,y,w,h); - - if(m_imp) - m_imp->Move(x, y, w, h); -} - -//--------------------------------------------------------------------------- -// wxMediaCtrl::MacVisibilityChanged -//--------------------------------------------------------------------------- -#ifdef __WXMAC__ -void wxMediaCtrl::MacVisibilityChanged() -{ - wxControl::MacVisibilityChanged(); - - if(m_imp) - m_imp->MacVisibilityChanged(); -} -#endif - -//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -// -// wxMediaBackendCommonBase -// -//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - -void wxMediaBackendCommonBase::NotifyMovieSizeChanged() -{ - // our best size changed after opening a new file - m_ctrl->InvalidateBestSize(); - m_ctrl->SetSize(m_ctrl->GetSize()); - - // if the parent of the control has a sizer ask it to refresh our size - wxWindow * const parent = m_ctrl->GetParent(); - if ( parent->GetSizer() ) - { - m_ctrl->GetParent()->Layout(); - m_ctrl->GetParent()->Refresh(); - m_ctrl->GetParent()->Update(); - } -} - -void wxMediaBackendCommonBase::NotifyMovieLoaded() -{ - NotifyMovieSizeChanged(); - - // notify about movie being fully loaded - QueueEvent(wxEVT_MEDIA_LOADED); -} - -bool wxMediaBackendCommonBase::SendStopEvent() -{ - wxMediaEvent theEvent(wxEVT_MEDIA_STOP, m_ctrl->GetId()); - - return !m_ctrl->ProcessEvent(theEvent) || theEvent.IsAllowed(); -} - -void wxMediaBackendCommonBase::QueueEvent(wxEventType evtType) -{ - wxMediaEvent theEvent(evtType, m_ctrl->GetId()); - m_ctrl->AddPendingEvent(theEvent); -} - -void wxMediaBackendCommonBase::QueuePlayEvent() -{ - QueueEvent(wxEVT_MEDIA_STATECHANGED); - QueueEvent(wxEVT_MEDIA_PLAY); -} - -void wxMediaBackendCommonBase::QueuePauseEvent() -{ - QueueEvent(wxEVT_MEDIA_STATECHANGED); - QueueEvent(wxEVT_MEDIA_PAUSE); -} - -void wxMediaBackendCommonBase::QueueStopEvent() -{ - QueueEvent(wxEVT_MEDIA_STATECHANGED); - QueueEvent(wxEVT_MEDIA_STOP); -} - - -// -// Force link default backends in - -// see http://wiki.wxwidgets.org/wiki.pl?RTTI -// -#include "wx/html/forcelnk.h" - -#ifdef __WXMSW__ // MSW has huge backends so we do it seperately -FORCE_LINK(wxmediabackend_am) -FORCE_LINK(wxmediabackend_wmp10) -#else -FORCE_LINK(basewxmediabackends) -#endif - -#endif //wxUSE_MEDIACTRL +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/mediactrl.cpp +// Purpose: wxMediaCtrl common code +// Author: Ryan Norton +// Modified by: +// Created: 11/07/04 +// RCS-ID: $Id: mediactrlcmn.cpp 42816 2006-10-31 08:50:17Z RD $ +// Copyright: (c) Ryan Norton +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// TODO: Platform specific backend defaults? + +//=========================================================================== +// Definitions +//=========================================================================== + +//--------------------------------------------------------------------------- +// Pre-compiled header stuff +//--------------------------------------------------------------------------- + +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_MEDIACTRL + +#ifndef WX_PRECOMP + #include "wx/hash.h" +#endif + +//--------------------------------------------------------------------------- +// Includes +//--------------------------------------------------------------------------- +#include "wx/mediactrl.h" + +//=========================================================================== +// +// Implementation +// +//=========================================================================== + +//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// RTTI and Event implementations +//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +IMPLEMENT_CLASS(wxMediaCtrl, wxControl) +DEFINE_EVENT_TYPE(wxEVT_MEDIA_STATECHANGED) +DEFINE_EVENT_TYPE(wxEVT_MEDIA_PLAY) +DEFINE_EVENT_TYPE(wxEVT_MEDIA_PAUSE) +IMPLEMENT_CLASS(wxMediaBackend, wxObject) +IMPLEMENT_DYNAMIC_CLASS(wxMediaEvent, wxEvent) +DEFINE_EVENT_TYPE(wxEVT_MEDIA_FINISHED) +DEFINE_EVENT_TYPE(wxEVT_MEDIA_LOADED) +DEFINE_EVENT_TYPE(wxEVT_MEDIA_STOP) + +//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// +// wxMediaCtrl +// +//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +//--------------------------------------------------------------------------- +// wxMediaBackend Destructor +// +// This is here because the DARWIN gcc compiler badly screwed up and +// needs the destructor implementation in the source +//--------------------------------------------------------------------------- +wxMediaBackend::~wxMediaBackend() +{ +} + +//--------------------------------------------------------------------------- +// wxMediaCtrl::Create (file version) +// wxMediaCtrl::Create (URL version) +// +// Searches for a backend that is installed on the system (backends +// starting with lower characters in the alphabet are given priority), +// and creates the control from it +// +// This searches by searching the global RTTI hashtable, class by class, +// attempting to call CreateControl on each one found that is a derivative +// of wxMediaBackend - if it succeeded Create returns true, otherwise +// it keeps iterating through the hashmap. +//--------------------------------------------------------------------------- +bool wxMediaCtrl::Create(wxWindow* parent, wxWindowID id, + const wxString& fileName, + const wxPoint& pos, + const wxSize& size, + long style, + const wxString& szBackend, + const wxValidator& validator, + const wxString& name) +{ + if(!szBackend.empty()) + { + wxClassInfo* pClassInfo = wxClassInfo::FindClass(szBackend); + + if(!pClassInfo || !DoCreate(pClassInfo, parent, id, + pos, size, style, validator, name)) + { + m_imp = NULL; + return false; + } + + if (!fileName.empty()) + { + if (!Load(fileName)) + { + delete m_imp; + m_imp = NULL; + return false; + } + } + + SetInitialSize(size); + return true; + } + else + { + wxClassInfo::sm_classTable->BeginFind(); + + wxClassInfo* classInfo; + + while((classInfo = NextBackend()) != NULL) + { + if(!DoCreate(classInfo, parent, id, + pos, size, style, validator, name)) + continue; + + if (!fileName.empty()) + { + if (Load(fileName)) + { + SetInitialSize(size); + return true; + } + else + delete m_imp; + } + else + { + SetInitialSize(size); + return true; + } + } + + m_imp = NULL; + return false; + } +} + +bool wxMediaCtrl::Create(wxWindow* parent, wxWindowID id, + const wxURI& location, + const wxPoint& pos, + const wxSize& size, + long style, + const wxString& szBackend, + const wxValidator& validator, + const wxString& name) +{ + if(!szBackend.empty()) + { + wxClassInfo* pClassInfo = wxClassInfo::FindClass(szBackend); + if(!pClassInfo || !DoCreate(pClassInfo, parent, id, + pos, size, style, validator, name)) + { + m_imp = NULL; + return false; + } + + if (!Load(location)) + { + delete m_imp; + m_imp = NULL; + return false; + } + + SetInitialSize(size); + return true; + } + else + { + wxClassInfo::sm_classTable->BeginFind(); + + wxClassInfo* classInfo; + + while((classInfo = NextBackend()) != NULL) + { + if(!DoCreate(classInfo, parent, id, + pos, size, style, validator, name)) + continue; + + if (Load(location)) + { + SetInitialSize(size); + return true; + } + else + delete m_imp; + } + + m_imp = NULL; + return false; + } +} + +//--------------------------------------------------------------------------- +// wxMediaCtrl::DoCreate +// +// Attempts to create the control from a backend +//--------------------------------------------------------------------------- +bool wxMediaCtrl::DoCreate(wxClassInfo* classInfo, + wxWindow* parent, wxWindowID id, + const wxPoint& pos, + const wxSize& size, + long style, + const wxValidator& validator, + const wxString& name) +{ + m_imp = (wxMediaBackend*)classInfo->CreateObject(); + + if( m_imp->CreateControl(this, parent, id, pos, size, + style, validator, name) ) + { + return true; + } + + delete m_imp; + return false; +} + +//--------------------------------------------------------------------------- +// wxMediaCtrl::NextBackend (static) +// +// +// Search through the RTTI hashmap one at a +// time, attempting to create each derivative +// of wxMediaBackend +// +// +// STL isn't compatible with and will have a compilation error +// on a wxNode, however, wxHashTable::compatibility_iterator is +// incompatible with the old 2.4 stable version - but since +// we're in 2.5+ only we don't need to worry about the new version +//--------------------------------------------------------------------------- +wxClassInfo* wxMediaCtrl::NextBackend() +{ + wxHashTable::compatibility_iterator + node = wxClassInfo::sm_classTable->Next(); + while (node) + { + wxClassInfo* classInfo = (wxClassInfo *)node->GetData(); + if ( classInfo->IsKindOf(CLASSINFO(wxMediaBackend)) && + classInfo != CLASSINFO(wxMediaBackend) ) + { + return classInfo; + } + node = wxClassInfo::sm_classTable->Next(); + } + + // + // Nope - couldn't successfully find one... fail + // + return NULL; +} + + +//--------------------------------------------------------------------------- +// wxMediaCtrl Destructor +// +// Free up the backend if it exists +//--------------------------------------------------------------------------- +wxMediaCtrl::~wxMediaCtrl() +{ + if (m_imp) + delete m_imp; +} + +//--------------------------------------------------------------------------- +// wxMediaCtrl::Load (file version) +// wxMediaCtrl::Load (URL version) +// wxMediaCtrl::Load (URL & Proxy version) +// wxMediaCtrl::Load (wxInputStream version) +// +// Here we call load of the backend - keeping +// track of whether it was successful or not - which +// will determine which later method calls work +//--------------------------------------------------------------------------- +bool wxMediaCtrl::Load(const wxString& fileName) +{ + if(m_imp) + return (m_bLoaded = m_imp->Load(fileName)); + return false; +} + +bool wxMediaCtrl::Load(const wxURI& location) +{ + if(m_imp) + return (m_bLoaded = m_imp->Load(location)); + return false; +} + +bool wxMediaCtrl::Load(const wxURI& location, const wxURI& proxy) +{ + if(m_imp) + return (m_bLoaded = m_imp->Load(location, proxy)); + return false; +} + +//--------------------------------------------------------------------------- +// wxMediaCtrl::Play +// wxMediaCtrl::Pause +// wxMediaCtrl::Stop +// wxMediaCtrl::GetPlaybackRate +// wxMediaCtrl::SetPlaybackRate +// wxMediaCtrl::Seek --> SetPosition +// wxMediaCtrl::Tell --> GetPosition +// wxMediaCtrl::Length --> GetDuration +// wxMediaCtrl::GetState +// wxMediaCtrl::DoGetBestSize +// wxMediaCtrl::SetVolume +// wxMediaCtrl::GetVolume +// wxMediaCtrl::ShowInterface +// wxMediaCtrl::GetDownloadProgress +// wxMediaCtrl::GetDownloadTotal +// +// 1) Check to see whether the backend exists and is loading +// 2) Call the backend's version of the method, returning success +// if the backend's version succeeds +//--------------------------------------------------------------------------- +bool wxMediaCtrl::Play() +{ + if(m_imp && m_bLoaded) + return m_imp->Play(); + return 0; +} + +bool wxMediaCtrl::Pause() +{ + if(m_imp && m_bLoaded) + return m_imp->Pause(); + return 0; +} + +bool wxMediaCtrl::Stop() +{ + if(m_imp && m_bLoaded) + return m_imp->Stop(); + return 0; +} + +double wxMediaCtrl::GetPlaybackRate() +{ + if(m_imp && m_bLoaded) + return m_imp->GetPlaybackRate(); + return 0; +} + +bool wxMediaCtrl::SetPlaybackRate(double dRate) +{ + if(m_imp && m_bLoaded) + return m_imp->SetPlaybackRate(dRate); + return false; +} + +wxFileOffset wxMediaCtrl::Seek(wxFileOffset where, wxSeekMode mode) +{ + wxFileOffset offset; + + switch (mode) + { + case wxFromStart: + offset = where; + break; + case wxFromEnd: + offset = Length() - where; + break; +// case wxFromCurrent: + default: + offset = Tell() + where; + break; + } + + if(m_imp && m_bLoaded && m_imp->SetPosition(offset)) + return offset; + return wxInvalidOffset; +} + +wxFileOffset wxMediaCtrl::Tell() +{ + if(m_imp && m_bLoaded) + return (wxFileOffset) m_imp->GetPosition().ToLong(); + return wxInvalidOffset; +} + +wxFileOffset wxMediaCtrl::Length() +{ + if(m_imp && m_bLoaded) + return (wxFileOffset) m_imp->GetDuration().ToLong(); + return wxInvalidOffset; +} + +wxMediaState wxMediaCtrl::GetState() +{ + if(m_imp && m_bLoaded) + return m_imp->GetState(); + return wxMEDIASTATE_STOPPED; +} + +wxSize wxMediaCtrl::DoGetBestSize() const +{ + if(m_imp) + return m_imp->GetVideoSize(); + return wxSize(0,0); +} + +double wxMediaCtrl::GetVolume() +{ + if(m_imp && m_bLoaded) + return m_imp->GetVolume(); + return 0.0; +} + +bool wxMediaCtrl::SetVolume(double dVolume) +{ + if(m_imp && m_bLoaded) + return m_imp->SetVolume(dVolume); + return false; +} + +bool wxMediaCtrl::ShowPlayerControls(wxMediaCtrlPlayerControls flags) +{ + if(m_imp) + return m_imp->ShowPlayerControls(flags); + return false; +} + +wxFileOffset wxMediaCtrl::GetDownloadProgress() +{ + if(m_imp && m_bLoaded) + return (wxFileOffset) m_imp->GetDownloadProgress().ToLong(); + return wxInvalidOffset; +} + +wxFileOffset wxMediaCtrl::GetDownloadTotal() +{ + if(m_imp && m_bLoaded) + return (wxFileOffset) m_imp->GetDownloadTotal().ToLong(); + return wxInvalidOffset; +} + +//--------------------------------------------------------------------------- +// wxMediaCtrl::DoMoveWindow +// +// 1) Call parent's version so that our control's window moves where +// it's supposed to +// 2) If the backend exists and is loaded, move the video +// of the media to where our control's window is now located +//--------------------------------------------------------------------------- +void wxMediaCtrl::DoMoveWindow(int x, int y, int w, int h) +{ + wxControl::DoMoveWindow(x,y,w,h); + + if(m_imp) + m_imp->Move(x, y, w, h); +} + +//--------------------------------------------------------------------------- +// wxMediaCtrl::MacVisibilityChanged +//--------------------------------------------------------------------------- +#ifdef __WXMAC__ +void wxMediaCtrl::MacVisibilityChanged() +{ + wxControl::MacVisibilityChanged(); + + if(m_imp) + m_imp->MacVisibilityChanged(); +} +#endif + +//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// +// wxMediaBackendCommonBase +// +//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +void wxMediaBackendCommonBase::NotifyMovieSizeChanged() +{ + // our best size changed after opening a new file + m_ctrl->InvalidateBestSize(); + m_ctrl->SetSize(m_ctrl->GetSize()); + + // if the parent of the control has a sizer ask it to refresh our size + wxWindow * const parent = m_ctrl->GetParent(); + if ( parent->GetSizer() ) + { + m_ctrl->GetParent()->Layout(); + m_ctrl->GetParent()->Refresh(); + m_ctrl->GetParent()->Update(); + } +} + +void wxMediaBackendCommonBase::NotifyMovieLoaded() +{ + NotifyMovieSizeChanged(); + + // notify about movie being fully loaded + QueueEvent(wxEVT_MEDIA_LOADED); +} + +bool wxMediaBackendCommonBase::SendStopEvent() +{ + wxMediaEvent theEvent(wxEVT_MEDIA_STOP, m_ctrl->GetId()); + + return !m_ctrl->ProcessEvent(theEvent) || theEvent.IsAllowed(); +} + +void wxMediaBackendCommonBase::QueueEvent(wxEventType evtType) +{ + wxMediaEvent theEvent(evtType, m_ctrl->GetId()); + m_ctrl->AddPendingEvent(theEvent); +} + +void wxMediaBackendCommonBase::QueuePlayEvent() +{ + QueueEvent(wxEVT_MEDIA_STATECHANGED); + QueueEvent(wxEVT_MEDIA_PLAY); +} + +void wxMediaBackendCommonBase::QueuePauseEvent() +{ + QueueEvent(wxEVT_MEDIA_STATECHANGED); + QueueEvent(wxEVT_MEDIA_PAUSE); +} + +void wxMediaBackendCommonBase::QueueStopEvent() +{ + QueueEvent(wxEVT_MEDIA_STATECHANGED); + QueueEvent(wxEVT_MEDIA_STOP); +} + + +// +// Force link default backends in - +// see http://wiki.wxwidgets.org/wiki.pl?RTTI +// +#include "wx/html/forcelnk.h" + +#ifdef __WXMSW__ // MSW has huge backends so we do it seperately +FORCE_LINK(wxmediabackend_am) +FORCE_LINK(wxmediabackend_wmp10) +#else +FORCE_LINK(basewxmediabackends) +#endif + +#endif //wxUSE_MEDIACTRL diff --git a/Externals/wxWidgets/src/common/memory.cpp b/Externals/wxWidgets/src/common/memory.cpp index d01f1a061c..e3a1d7866e 100644 --- a/Externals/wxWidgets/src/common/memory.cpp +++ b/Externals/wxWidgets/src/common/memory.cpp @@ -1,1148 +1,1148 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/memory.cpp -// Purpose: Memory checking implementation -// Author: Arthur Seaton, Julian Smart -// Modified by: -// Created: 04/01/98 -// RCS-ID: $Id: memory.cpp 41054 2006-09-07 19:01:45Z ABX $ -// Copyright: (c) Julian Smart -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT - -#include "wx/memory.h" - -#ifndef WX_PRECOMP - #ifdef __WXMSW__ - #include "wx/msw/wrapwin.h" - #endif - #include "wx/utils.h" - #include "wx/app.h" - #include "wx/hash.h" - #include "wx/log.h" -#endif - -#if wxUSE_THREADS - #include "wx/thread.h" -#endif - -#include - -#include "wx/ioswrap.h" - -#if !defined(__WATCOMC__) && !(defined(__VMS__) && ( __VMS_VER < 70000000 ) )\ - && !defined( __MWERKS__ ) && !defined(__SALFORDC__) -#include -#endif - -#include -#include - -#if wxUSE_THREADS && defined(__WXDEBUG__) -#define USE_THREADSAFE_MEMORY_ALLOCATION 1 -#else -#define USE_THREADSAFE_MEMORY_ALLOCATION 0 -#endif - - -#ifdef new -#undef new -#endif - -// wxDebugContext wxTheDebugContext; -/* - Redefine new and delete so that we can pick up situations where: - - we overwrite or underwrite areas of malloc'd memory. - - we use uninitialise variables - Only do this in debug mode. - - We change new to get enough memory to allocate a struct, followed - by the caller's requested memory, followed by a tag. The struct - is used to create a doubly linked list of these areas and also - contains another tag. The tags are used to determine when the area - has been over/under written. -*/ - - -/* - Values which are used to set the markers which will be tested for - under/over write. There are 3 of these, one in the struct, one - immediately after the struct but before the caller requested memory and - one immediately after the requested memory. -*/ -#define MemStartCheck 0x23A8 -#define MemMidCheck 0xA328 -#define MemEndCheck 0x8A32 -#define MemFillChar 0xAF -#define MemStructId 0x666D - -/* - External interface for the wxMemStruct class. Others are - defined inline within the class def. Here we only need to be able - to add and delete nodes from the list and handle errors in some way. -*/ - -/* - Used for internal "this shouldn't happen" type of errors. -*/ -void wxMemStruct::ErrorMsg (const char * mesg) -{ - wxLogMessage(wxT("wxWidgets memory checking error: %s"), mesg); - PrintNode (); -} - -/* - Used when we find an overwrite or an underwrite error. -*/ -void wxMemStruct::ErrorMsg () -{ - wxLogMessage(wxT("wxWidgets over/underwrite memory error:")); - PrintNode (); -} - - -/* - We want to find out if pointers have been overwritten as soon as is - possible, so test everything before we dereference it. Of course it's still - quite possible that, if things have been overwritten, this function will - fall over, but the only way of dealing with that would cost too much in terms - of time. -*/ -int wxMemStruct::AssertList () -{ - if (wxDebugContext::GetHead () != 0 && ! (wxDebugContext::GetHead ())->AssertIt () || - wxDebugContext::GetTail () != 0 && ! wxDebugContext::GetTail ()->AssertIt ()) { - ErrorMsg ("Head or tail pointers trashed"); - return 0; - } - return 1; -} - - -/* - Check that the thing we're pointing to has the correct id for a wxMemStruct - object and also that it's previous and next pointers are pointing at objects - which have valid ids. - This is definitely not perfect since we could fall over just trying to access - any of the slots which we use here, but I think it's about the best that I - can do without doing something like taking all new wxMemStruct pointers and - comparing them against all known pointer within the list and then only - doing this sort of check _after_ you've found the pointer in the list. That - would be safer, but also much more time consuming. -*/ -int wxMemStruct::AssertIt () -{ - return (m_id == MemStructId && - (m_prev == 0 || m_prev->m_id == MemStructId) && - (m_next == 0 || m_next->m_id == MemStructId)); -} - - -/* - Additions are always at the tail of the list. - Returns 0 on error, non-zero on success. -*/ -int wxMemStruct::Append () -{ - if (! AssertList ()) - return 0; - - if (wxDebugContext::GetHead () == 0) { - if (wxDebugContext::GetTail () != 0) { - ErrorMsg ("Null list should have a null tail pointer"); - return 0; - } - (void) wxDebugContext::SetHead (this); - (void) wxDebugContext::SetTail (this); - } else { - wxDebugContext::GetTail ()->m_next = this; - this->m_prev = wxDebugContext::GetTail (); - (void) wxDebugContext::SetTail (this); - } - return 1; -} - - -/* - Don't actually free up anything here as the space which is used - by the node will be free'd up when the whole block is free'd. - Returns 0 on error, non-zero on success. -*/ -int wxMemStruct::Unlink () -{ - if (! AssertList ()) - return 0; - - if (wxDebugContext::GetHead () == 0 || wxDebugContext::GetTail () == 0) { - ErrorMsg ("Trying to remove node from empty list"); - return 0; - } - - // Handle the part of the list before this node. - if (m_prev == 0) { - if (this != wxDebugContext::GetHead ()) { - ErrorMsg ("No previous node for non-head node"); - return 0; - } - (void) wxDebugContext::SetHead (m_next); - } else { - if (! m_prev->AssertIt ()) { - ErrorMsg ("Trashed previous pointer"); - return 0; - } - - if (m_prev->m_next != this) { - ErrorMsg ("List is inconsistent"); - return 0; - } - m_prev->m_next = m_next; - } - - // Handle the part of the list after this node. - if (m_next == 0) { - if (this != wxDebugContext::GetTail ()) { - ErrorMsg ("No next node for non-tail node"); - return 0; - } - (void) wxDebugContext::SetTail (m_prev); - } else { - if (! m_next->AssertIt ()) { - ErrorMsg ("Trashed next pointer"); - return 0; - } - - if (m_next->m_prev != this) { - ErrorMsg ("List is inconsistent"); - return 0; - } - m_next->m_prev = m_prev; - } - - return 1; -} - - - -/* - Checks a node and block of memory to see that the markers are still - intact. -*/ -int wxMemStruct::CheckBlock () -{ - int nFailures = 0; - - if (m_firstMarker != MemStartCheck) { - nFailures++; - ErrorMsg (); - } - - char * pointer = wxDebugContext::MidMarkerPos ((char *) this); - if (* (wxMarkerType *) pointer != MemMidCheck) { - nFailures++; - ErrorMsg (); - } - - pointer = wxDebugContext::EndMarkerPos ((char *) this, RequestSize ()); - if (* (wxMarkerType *) pointer != MemEndCheck) { - nFailures++; - ErrorMsg (); - } - - return nFailures; -} - - -/* - Check the list of nodes to see if they are all ok. -*/ -int wxMemStruct::CheckAllPrevious () -{ - int nFailures = 0; - - for (wxMemStruct * st = this->m_prev; st != 0; st = st->m_prev) { - if (st->AssertIt ()) - nFailures += st->CheckBlock (); - else - return -1; - } - - return nFailures; -} - - -/* - When we delete a node we set the id slot to a specific value and then test - against this to see if a nodes have been deleted previously. I don't - just set the entire memory to the fillChar because then I'd be overwriting - useful stuff like the vtbl which may be needed to output the error message - including the file name and line numbers. Without this info the whole point - of this class is lost! -*/ -void wxMemStruct::SetDeleted () -{ - m_id = MemFillChar; -} - -int wxMemStruct::IsDeleted () -{ - return (m_id == MemFillChar); -} - - -/* - Print out a single node. There are many far better ways of doing this - but this will suffice for now. -*/ -void wxMemStruct::PrintNode () -{ - if (m_isObject) - { - wxObject *obj = (wxObject *)m_actualData; - wxClassInfo *info = obj->GetClassInfo(); - - // Let's put this in standard form so IDEs can load the file at the appropriate - // line - wxString msg; - - if (m_fileName) - msg.Printf(wxT("%s(%d): "), m_fileName, (int)m_lineNum); - - if (info && info->GetClassName()) - msg += info->GetClassName(); - else - msg += wxT("object"); - - wxString msg2; - msg2.Printf(wxT(" at 0x%lX, size %d"), (long)GetActualData(), (int)RequestSize()); - msg += msg2; - - wxLogMessage(msg); - } - else - { - wxString msg; - - if (m_fileName) - msg.Printf(wxT("%s(%d): "), m_fileName, (int)m_lineNum); - msg += wxT("non-object data"); - wxString msg2; - msg2.Printf(wxT(" at 0x%lX, size %d\n"), (long)GetActualData(), (int)RequestSize()); - msg += msg2; - - wxLogMessage(msg); - } -} - -void wxMemStruct::Dump () -{ - if (!ValidateNode()) return; - - if (m_isObject) - { - wxObject *obj = (wxObject *)m_actualData; - - wxString msg; - if (m_fileName) - msg.Printf(wxT("%s(%d): "), m_fileName, (int)m_lineNum); - - - /* TODO: We no longer have a stream (using wxLogDebug) so we can't dump it. - * Instead, do what wxObject::Dump does. - * What should we do long-term, eliminate Dumping? Or specify - * that MyClass::Dump should use wxLogDebug? Ugh. - obj->Dump(wxDebugContext::GetStream()); - */ - - if (obj->GetClassInfo() && obj->GetClassInfo()->GetClassName()) - msg += obj->GetClassInfo()->GetClassName(); - else - msg += wxT("unknown object class"); - - wxString msg2; - msg2.Printf(wxT(" at 0x%lX, size %d"), (long)GetActualData(), (int)RequestSize()); - msg += msg2; - - wxDebugContext::OutputDumpLine(msg); - } - else - { - wxString msg; - if (m_fileName) - msg.Printf(wxT("%s(%d): "), m_fileName, (int)m_lineNum); - - wxString msg2; - msg2.Printf(wxT("non-object data at 0x%lX, size %d"), (long)GetActualData(), (int)RequestSize() ); - msg += msg2; - wxDebugContext::OutputDumpLine(msg); - } -} - - -/* - Validate a node. Check to see that the node is "clean" in the sense - that nothing has over/underwritten it etc. -*/ -int wxMemStruct::ValidateNode () -{ - char * startPointer = (char *) this; - if (!AssertIt ()) { - if (IsDeleted ()) - ErrorMsg ("Object already deleted"); - else { - // Can't use the error routines as we have no recognisable object. -#ifndef __WXGTK__ - wxLogMessage(wxT("Can't verify memory struct - all bets are off!")); -#endif - } - return 0; - } - -/* - int i; - for (i = 0; i < wxDebugContext::TotSize (requestSize ()); i++) - cout << startPointer [i]; - cout << endl; -*/ - if (Marker () != MemStartCheck) - ErrorMsg (); - if (* (wxMarkerType *) wxDebugContext::MidMarkerPos (startPointer) != MemMidCheck) - ErrorMsg (); - if (* (wxMarkerType *) wxDebugContext::EndMarkerPos (startPointer, - RequestSize ()) != - MemEndCheck) - ErrorMsg (); - - // Back to before the extra buffer and check that - // we can still read what we originally wrote. - if (Marker () != MemStartCheck || - * (wxMarkerType *) wxDebugContext::MidMarkerPos (startPointer) - != MemMidCheck || - * (wxMarkerType *) wxDebugContext::EndMarkerPos (startPointer, - RequestSize ()) != MemEndCheck) - { - ErrorMsg (); - return 0; - } - - return 1; -} - -/* - The wxDebugContext class. -*/ - -wxMemStruct *wxDebugContext::m_head = NULL; -wxMemStruct *wxDebugContext::m_tail = NULL; - -bool wxDebugContext::m_checkPrevious = false; -int wxDebugContext::debugLevel = 1; -bool wxDebugContext::debugOn = true; -wxMemStruct *wxDebugContext::checkPoint = NULL; - -// For faster alignment calculation -static wxMarkerType markerCalc[2]; -int wxDebugContext::m_balign = (int)((char *)&markerCalc[1] - (char*)&markerCalc[0]); -int wxDebugContext::m_balignmask = (int)((char *)&markerCalc[1] - (char*)&markerCalc[0]) - 1; - -wxDebugContext::wxDebugContext(void) -{ -} - -wxDebugContext::~wxDebugContext(void) -{ -} - -/* - Work out the positions of the markers by creating an array of 2 markers - and comparing the addresses of the 2 elements. Use this number as the - alignment for markers. -*/ -size_t wxDebugContext::CalcAlignment () -{ - wxMarkerType ar[2]; - return (char *) &ar[1] - (char *) &ar[0]; -} - - -char * wxDebugContext::StructPos (const char * buf) -{ - return (char *) buf; -} - -char * wxDebugContext::MidMarkerPos (const char * buf) -{ - return StructPos (buf) + PaddedSize (sizeof (wxMemStruct)); -} - -char * wxDebugContext::CallerMemPos (const char * buf) -{ - return MidMarkerPos (buf) + PaddedSize (sizeof(wxMarkerType)); -} - - -char * wxDebugContext::EndMarkerPos (const char * buf, const size_t size) -{ - return CallerMemPos (buf) + PaddedSize (size); -} - - -/* - Slightly different as this takes a pointer to the start of the caller - requested region and returns a pointer to the start of the buffer. - */ -char * wxDebugContext::StartPos (const char * caller) -{ - return ((char *) (caller - wxDebugContext::PaddedSize (sizeof(wxMarkerType)) - - wxDebugContext::PaddedSize (sizeof (wxMemStruct)))); -} - -/* - We may need padding between various parts of the allocated memory. - Given a size of memory, this returns the amount of memory which should - be allocated in order to allow for alignment of the following object. - - I don't know how portable this stuff is, but it seems to work for me at - the moment. It would be real nice if I knew more about this! - - // Note: this function is now obsolete (along with CalcAlignment) - // because the calculations are done statically, for greater speed. -*/ -size_t wxDebugContext::GetPadding (const size_t size) -{ - size_t pad = size % CalcAlignment (); - return (pad) ? sizeof(wxMarkerType) - pad : 0; -} - -size_t wxDebugContext::PaddedSize (const size_t size) -{ - // Added by Terry Farnham to replace - // slow GetPadding call. - int padb; - - padb = size & m_balignmask; - if(padb) - return(size + m_balign - padb); - else - return(size); -} - -/* - Returns the total amount of memory which we need to get from the system - in order to satisfy a caller request. This includes space for the struct - plus markers and the caller's memory as well. -*/ -size_t wxDebugContext::TotSize (const size_t reqSize) -{ - return (PaddedSize (sizeof (wxMemStruct)) + PaddedSize (reqSize) + - 2 * sizeof(wxMarkerType)); -} - - -/* - Traverse the list of nodes executing the given function on each node. -*/ -void wxDebugContext::TraverseList (PmSFV func, wxMemStruct *from) -{ - if (!from) - from = wxDebugContext::GetHead (); - - wxMemStruct * st = NULL; - for (st = from; st != 0; st = st->m_next) - { - void* data = st->GetActualData(); -// if ((data != (void*)m_debugStream) && (data != (void*) m_streamBuf)) - if (data != (void*) wxLog::GetActiveTarget()) - { - (st->*func) (); - } - } -} - - -/* - Print out the list. - */ -bool wxDebugContext::PrintList (void) -{ -#ifdef __WXDEBUG__ - TraverseList ((PmSFV)&wxMemStruct::PrintNode, (checkPoint ? checkPoint->m_next : (wxMemStruct*)NULL)); - - return true; -#else - return false; -#endif -} - -bool wxDebugContext::Dump(void) -{ -#ifdef __WXDEBUG__ - { - wxChar* appName = (wxChar*) wxT("application"); - wxString appNameStr; - if (wxTheApp) - { - appNameStr = wxTheApp->GetAppName(); - appName = WXSTRINGCAST appNameStr; - OutputDumpLine(wxT("----- Memory dump of %s at %s -----"), appName, WXSTRINGCAST wxNow() ); - } - else - { - OutputDumpLine( wxT("----- Memory dump -----") ); - } - } - - TraverseList ((PmSFV)&wxMemStruct::Dump, (checkPoint ? checkPoint->m_next : (wxMemStruct*)NULL)); - - OutputDumpLine(wxEmptyString); - OutputDumpLine(wxEmptyString); - - return true; -#else - return false; -#endif -} - -#ifdef __WXDEBUG__ -struct wxDebugStatsStruct -{ - long instanceCount; - long totalSize; - wxChar *instanceClass; - wxDebugStatsStruct *next; -}; - -static wxDebugStatsStruct *FindStatsStruct(wxDebugStatsStruct *st, wxChar *name) -{ - while (st) - { - if (wxStrcmp(st->instanceClass, name) == 0) - return st; - st = st->next; - } - return NULL; -} - -static wxDebugStatsStruct *InsertStatsStruct(wxDebugStatsStruct *head, wxDebugStatsStruct *st) -{ - st->next = head; - return st; -} -#endif - -bool wxDebugContext::PrintStatistics(bool detailed) -{ -#ifdef __WXDEBUG__ - { - wxChar* appName = (wxChar*) wxT("application"); - wxString appNameStr; - if (wxTheApp) - { - appNameStr = wxTheApp->GetAppName(); - appName = WXSTRINGCAST appNameStr; - OutputDumpLine(wxT("----- Memory statistics of %s at %s -----"), appName, WXSTRINGCAST wxNow() ); - } - else - { - OutputDumpLine( wxT("----- Memory statistics -----") ); - } - } - - bool currentMode = GetDebugMode(); - SetDebugMode(false); - - long noNonObjectNodes = 0; - long noObjectNodes = 0; - long totalSize = 0; - - wxDebugStatsStruct *list = NULL; - - wxMemStruct *from = (checkPoint ? checkPoint->m_next : (wxMemStruct*)NULL ); - if (!from) - from = wxDebugContext::GetHead (); - - wxMemStruct *st; - for (st = from; st != 0; st = st->m_next) - { - void* data = st->GetActualData(); - if (detailed && (data != (void*) wxLog::GetActiveTarget())) - { - wxChar *className = (wxChar*) wxT("nonobject"); - if (st->m_isObject && st->GetActualData()) - { - wxObject *obj = (wxObject *)st->GetActualData(); - if (obj->GetClassInfo()->GetClassName()) - className = (wxChar*)obj->GetClassInfo()->GetClassName(); - } - wxDebugStatsStruct *stats = FindStatsStruct(list, className); - if (!stats) - { - stats = (wxDebugStatsStruct *)malloc(sizeof(wxDebugStatsStruct)); - stats->instanceClass = className; - stats->instanceCount = 0; - stats->totalSize = 0; - list = InsertStatsStruct(list, stats); - } - stats->instanceCount ++; - stats->totalSize += st->RequestSize(); - } - - if (data != (void*) wxLog::GetActiveTarget()) - { - totalSize += st->RequestSize(); - if (st->m_isObject) - noObjectNodes ++; - else - noNonObjectNodes ++; - } - } - - if (detailed) - { - while (list) - { - OutputDumpLine(wxT("%ld objects of class %s, total size %ld"), - list->instanceCount, list->instanceClass, list->totalSize); - wxDebugStatsStruct *old = list; - list = old->next; - free((char *)old); - } - OutputDumpLine(wxEmptyString); - } - - SetDebugMode(currentMode); - - OutputDumpLine(wxT("Number of object items: %ld"), noObjectNodes); - OutputDumpLine(wxT("Number of non-object items: %ld"), noNonObjectNodes); - OutputDumpLine(wxT("Total allocated size: %ld"), totalSize); - OutputDumpLine(wxEmptyString); - OutputDumpLine(wxEmptyString); - - return true; -#else - (void)detailed; - return false; -#endif -} - -bool wxDebugContext::PrintClasses(void) -{ - { - wxChar* appName = (wxChar*) wxT("application"); - wxString appNameStr; - if (wxTheApp) - { - appNameStr = wxTheApp->GetAppName(); - appName = WXSTRINGCAST appNameStr; - wxLogMessage(wxT("----- Classes in %s -----"), appName); - } - } - - int n = 0; - wxHashTable::compatibility_iterator node; - wxClassInfo *info; - - wxClassInfo::sm_classTable->BeginFind(); - node = wxClassInfo::sm_classTable->Next(); - while (node) - { - info = (wxClassInfo *)node->GetData(); - if (info->GetClassName()) - { - wxString msg(info->GetClassName()); - msg += wxT(" "); - - if (info->GetBaseClassName1() && !info->GetBaseClassName2()) - { - msg += wxT("is a "); - msg += info->GetBaseClassName1(); - } - else if (info->GetBaseClassName1() && info->GetBaseClassName2()) - { - msg += wxT("is a "); - msg += info->GetBaseClassName1() ; - msg += wxT(", "); - msg += info->GetBaseClassName2() ; - } - if (info->GetConstructor()) - msg += wxT(": dynamic"); - - wxLogMessage(msg); - } - node = wxClassInfo::sm_classTable->Next(); - n ++; - } - wxLogMessage(wxEmptyString); - wxLogMessage(wxT("There are %d classes derived from wxObject."), n); - wxLogMessage(wxEmptyString); - wxLogMessage(wxEmptyString); - return true; -} - -void wxDebugContext::SetCheckpoint(bool all) -{ - if (all) - checkPoint = NULL; - else - checkPoint = m_tail; -} - -// Checks all nodes since checkpoint, or since start. -int wxDebugContext::Check(bool checkAll) -{ - int nFailures = 0; - - wxMemStruct *from = (checkPoint ? checkPoint->m_next : (wxMemStruct*)NULL ); - if (!from || checkAll) - from = wxDebugContext::GetHead (); - - for (wxMemStruct * st = from; st != 0; st = st->m_next) - { - if (st->AssertIt ()) - nFailures += st->CheckBlock (); - else - return -1; - } - - return nFailures; -} - -// Count the number of non-wxDebugContext-related objects -// that are outstanding -int wxDebugContext::CountObjectsLeft(bool sinceCheckpoint) -{ - int n = 0; - - wxMemStruct *from = NULL; - if (sinceCheckpoint && checkPoint) - from = checkPoint->m_next; - else - from = wxDebugContext::GetHead () ; - - for (wxMemStruct * st = from; st != 0; st = st->m_next) - { - void* data = st->GetActualData(); - if (data != (void*) wxLog::GetActiveTarget()) - n ++; - } - - return n ; -} - -// This function is used to output the dump -void wxDebugContext::OutputDumpLine(const wxChar *szFormat, ...) -{ - // a buffer of 2048 bytes should be long enough for a file name - // and a class name - wxChar buf[2048]; - int count; - va_list argptr; - va_start(argptr, szFormat); - buf[sizeof(buf)/sizeof(wxChar)-1] = _T('\0'); - - // keep 3 bytes for a \r\n\0 - count = wxVsnprintf(buf, sizeof(buf)/sizeof(wxChar)-3, szFormat, argptr); - - if ( count < 0 ) - count = sizeof(buf)/sizeof(wxChar)-3; - buf[count]=_T('\r'); - buf[count+1]=_T('\n'); - buf[count+2]=_T('\0'); - - wxMessageOutputDebug dbgout; - dbgout.Printf(buf); -} - - -#if USE_THREADSAFE_MEMORY_ALLOCATION -static bool memSectionOk = false; - -class MemoryCriticalSection : public wxCriticalSection -{ -public: - MemoryCriticalSection() { - memSectionOk = true; - } - ~MemoryCriticalSection() { - memSectionOk = false; - } -}; - -class MemoryCriticalSectionLocker -{ -public: - inline MemoryCriticalSectionLocker(wxCriticalSection& critsect) - : m_critsect(critsect), m_locked(memSectionOk) { if(m_locked) m_critsect.Enter(); } - inline ~MemoryCriticalSectionLocker() { if(m_locked) m_critsect.Leave(); } - -private: - // no assignment operator nor copy ctor - MemoryCriticalSectionLocker(const MemoryCriticalSectionLocker&); - MemoryCriticalSectionLocker& operator=(const MemoryCriticalSectionLocker&); - - wxCriticalSection& m_critsect; - bool m_locked; -}; - -static MemoryCriticalSection memLocker; - -#endif // USE_THREADSAFE_MEMORY_ALLOCATION - - -#ifdef __WXDEBUG__ -#if !(defined(__WXMSW__) && (defined(WXUSINGDLL) || defined(WXMAKINGDLL_BASE))) -#if wxUSE_GLOBAL_MEMORY_OPERATORS -void * operator new (size_t size, wxChar * fileName, int lineNum) -{ - return wxDebugAlloc(size, fileName, lineNum, false, false); -} - -void * operator new (size_t size) -{ - return wxDebugAlloc(size, NULL, 0, false); -} - -void operator delete (void * buf) -{ - wxDebugFree(buf, false); -} - -#if wxUSE_ARRAY_MEMORY_OPERATORS -void * operator new[] (size_t size) -{ - return wxDebugAlloc(size, NULL, 0, false, true); -} - -void * operator new[] (size_t size, wxChar * fileName, int lineNum) -{ - return wxDebugAlloc(size, fileName, lineNum, false, true); -} - -void operator delete[] (void * buf) -{ - wxDebugFree(buf, true); -} -#endif // wxUSE_ARRAY_MEMORY_OPERATORS -#endif // wxUSE_GLOBAL_MEMORY_OPERATORS -#endif // !(defined(__WXMSW__) && (defined(WXUSINGDLL) || defined(WXMAKINGDLL_BASE))) - -// TODO: store whether this is a vector or not. -void * wxDebugAlloc(size_t size, wxChar * fileName, int lineNum, bool isObject, bool WXUNUSED(isVect) ) -{ -#if USE_THREADSAFE_MEMORY_ALLOCATION - MemoryCriticalSectionLocker lock(memLocker); -#endif - - // If not in debugging allocation mode, do the normal thing - // so we don't leave any trace of ourselves in the node list. - -#if defined(__VISAGECPP__) && (__IBMCPP__ < 400 || __IBMC__ < 400 ) -// VA 3.0 still has trouble in here - return (void *)malloc(size); -#endif - if (!wxDebugContext::GetDebugMode()) - { - return (void *)malloc(size); - } - - int totSize = wxDebugContext::TotSize (size); - char * buf = (char *) malloc(totSize); - if (!buf) { - wxLogMessage(wxT("Call to malloc (%ld) failed."), (long)size); - return 0; - } - wxMemStruct * st = (wxMemStruct *)buf; - st->m_firstMarker = MemStartCheck; - st->m_reqSize = size; - st->m_fileName = fileName; - st->m_lineNum = lineNum; - st->m_id = MemStructId; - st->m_prev = 0; - st->m_next = 0; - st->m_isObject = isObject; - - // Errors from Append() shouldn't really happen - but just in case! - if (st->Append () == 0) { - st->ErrorMsg ("Trying to append new node"); - } - - if (wxDebugContext::GetCheckPrevious ()) { - if (st->CheckAllPrevious () < 0) { - st->ErrorMsg ("Checking previous nodes"); - } - } - - // Set up the extra markers at the middle and end. - char * ptr = wxDebugContext::MidMarkerPos (buf); - * (wxMarkerType *) ptr = MemMidCheck; - ptr = wxDebugContext::EndMarkerPos (buf, size); - * (wxMarkerType *) ptr = MemEndCheck; - - // pointer returned points to the start of the caller's - // usable area. - void *m_actualData = (void *) wxDebugContext::CallerMemPos (buf); - st->m_actualData = m_actualData; - - return m_actualData; -} - -// TODO: check whether was allocated as a vector -void wxDebugFree(void * buf, bool WXUNUSED(isVect) ) -{ -#if USE_THREADSAFE_MEMORY_ALLOCATION - MemoryCriticalSectionLocker lock(memLocker); -#endif - - if (!buf) - return; - -#if defined(__VISAGECPP__) && (__IBMCPP__ < 400 || __IBMC__ < 400 ) -// VA 3.0 still has trouble in here - free((char *)buf); -#endif - // If not in debugging allocation mode, do the normal thing - // so we don't leave any trace of ourselves in the node list. - if (!wxDebugContext::GetDebugMode()) - { - free((char *)buf); - return; - } - - // Points to the start of the entire allocated area. - char * startPointer = wxDebugContext::StartPos ((char *) buf); - // Find the struct and make sure that it's identifiable. - wxMemStruct * st = (wxMemStruct *) wxDebugContext::StructPos (startPointer); - - if (! st->ValidateNode ()) - return; - - // If this is the current checkpoint, we need to - // move the checkpoint back so it points to a valid - // node. - if (st == wxDebugContext::checkPoint) - wxDebugContext::checkPoint = wxDebugContext::checkPoint->m_prev; - - if (! st->Unlink ()) - { - st->ErrorMsg ("Unlinking deleted node"); - } - - // Now put in the fill char into the id slot and the caller requested - // memory locations. - st->SetDeleted (); - (void) memset (wxDebugContext::CallerMemPos (startPointer), MemFillChar, - st->RequestSize ()); - - free((char *)st); -} - -#endif // __WXDEBUG__ - -// Trace: send output to the current debugging stream -void wxTrace(const wxChar * ...) -{ -#if 1 - wxFAIL_MSG(wxT("wxTrace is now obsolete. Please use wxDebugXXX instead.")); -#else - va_list ap; - static wxChar buffer[512]; - - va_start(ap, fmt); - -#ifdef __WXMSW__ - wvsprintf(buffer,fmt,ap) ; -#else - vsprintf(buffer,fmt,ap) ; -#endif - - va_end(ap); - - if (wxDebugContext::HasStream()) - { - wxDebugContext::GetStream() << buffer; - wxDebugContext::GetStream().flush(); - } - else -#ifdef __WXMSW__ -#ifdef __WIN32__ - OutputDebugString((LPCTSTR)buffer) ; -#else - OutputDebugString((const char*) buffer) ; -#endif -#else - fprintf(stderr, buffer); -#endif -#endif -} - -// Trace with level -void wxTraceLevel(int, const wxChar * ...) -{ -#if 1 - wxFAIL_MSG(wxT("wxTrace is now obsolete. Please use wxDebugXXX instead.")); -#else - if (wxDebugContext::GetLevel() < level) - return; - - va_list ap; - static wxChar buffer[512]; - - va_start(ap, fmt); - -#ifdef __WXMSW__ - wxWvsprintf(buffer,fmt,ap) ; -#else - vsprintf(buffer,fmt,ap) ; -#endif - - va_end(ap); - - if (wxDebugContext::HasStream()) - { - wxDebugContext::GetStream() << buffer; - wxDebugContext::GetStream().flush(); - } - else -#ifdef __WXMSW__ -#ifdef __WIN32__ - OutputDebugString((LPCTSTR)buffer) ; -#else - OutputDebugString((const char*) buffer) ; -#endif -#else - fprintf(stderr, buffer); -#endif -#endif -} - -//---------------------------------------------------------------------------- -// Final cleanup after all global objects in all files have been destroyed -//---------------------------------------------------------------------------- - -// Don't set it to 0 by dynamic initialization -// Some compilers will really do the assignment later -// All global variables are initialized to 0 at the very beginning, and this is just fine. -int wxDebugContextDumpDelayCounter::sm_count; - -void wxDebugContextDumpDelayCounter::DoDump() -{ - if (wxDebugContext::CountObjectsLeft(true) > 0) - { - wxDebugContext::OutputDumpLine(wxT("There were memory leaks.\n")); - wxDebugContext::Dump(); - wxDebugContext::PrintStatistics(); - } -} - -// Even if there is nothing else, make sure that there is at -// least one cleanup counter object -static wxDebugContextDumpDelayCounter wxDebugContextDumpDelayCounter_One; - -#endif // (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/memory.cpp +// Purpose: Memory checking implementation +// Author: Arthur Seaton, Julian Smart +// Modified by: +// Created: 04/01/98 +// RCS-ID: $Id: memory.cpp 41054 2006-09-07 19:01:45Z ABX $ +// Copyright: (c) Julian Smart +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT + +#include "wx/memory.h" + +#ifndef WX_PRECOMP + #ifdef __WXMSW__ + #include "wx/msw/wrapwin.h" + #endif + #include "wx/utils.h" + #include "wx/app.h" + #include "wx/hash.h" + #include "wx/log.h" +#endif + +#if wxUSE_THREADS + #include "wx/thread.h" +#endif + +#include + +#include "wx/ioswrap.h" + +#if !defined(__WATCOMC__) && !(defined(__VMS__) && ( __VMS_VER < 70000000 ) )\ + && !defined( __MWERKS__ ) && !defined(__SALFORDC__) +#include +#endif + +#include +#include + +#if wxUSE_THREADS && defined(__WXDEBUG__) +#define USE_THREADSAFE_MEMORY_ALLOCATION 1 +#else +#define USE_THREADSAFE_MEMORY_ALLOCATION 0 +#endif + + +#ifdef new +#undef new +#endif + +// wxDebugContext wxTheDebugContext; +/* + Redefine new and delete so that we can pick up situations where: + - we overwrite or underwrite areas of malloc'd memory. + - we use uninitialise variables + Only do this in debug mode. + + We change new to get enough memory to allocate a struct, followed + by the caller's requested memory, followed by a tag. The struct + is used to create a doubly linked list of these areas and also + contains another tag. The tags are used to determine when the area + has been over/under written. +*/ + + +/* + Values which are used to set the markers which will be tested for + under/over write. There are 3 of these, one in the struct, one + immediately after the struct but before the caller requested memory and + one immediately after the requested memory. +*/ +#define MemStartCheck 0x23A8 +#define MemMidCheck 0xA328 +#define MemEndCheck 0x8A32 +#define MemFillChar 0xAF +#define MemStructId 0x666D + +/* + External interface for the wxMemStruct class. Others are + defined inline within the class def. Here we only need to be able + to add and delete nodes from the list and handle errors in some way. +*/ + +/* + Used for internal "this shouldn't happen" type of errors. +*/ +void wxMemStruct::ErrorMsg (const char * mesg) +{ + wxLogMessage(wxT("wxWidgets memory checking error: %s"), mesg); + PrintNode (); +} + +/* + Used when we find an overwrite or an underwrite error. +*/ +void wxMemStruct::ErrorMsg () +{ + wxLogMessage(wxT("wxWidgets over/underwrite memory error:")); + PrintNode (); +} + + +/* + We want to find out if pointers have been overwritten as soon as is + possible, so test everything before we dereference it. Of course it's still + quite possible that, if things have been overwritten, this function will + fall over, but the only way of dealing with that would cost too much in terms + of time. +*/ +int wxMemStruct::AssertList () +{ + if (wxDebugContext::GetHead () != 0 && ! (wxDebugContext::GetHead ())->AssertIt () || + wxDebugContext::GetTail () != 0 && ! wxDebugContext::GetTail ()->AssertIt ()) { + ErrorMsg ("Head or tail pointers trashed"); + return 0; + } + return 1; +} + + +/* + Check that the thing we're pointing to has the correct id for a wxMemStruct + object and also that it's previous and next pointers are pointing at objects + which have valid ids. + This is definitely not perfect since we could fall over just trying to access + any of the slots which we use here, but I think it's about the best that I + can do without doing something like taking all new wxMemStruct pointers and + comparing them against all known pointer within the list and then only + doing this sort of check _after_ you've found the pointer in the list. That + would be safer, but also much more time consuming. +*/ +int wxMemStruct::AssertIt () +{ + return (m_id == MemStructId && + (m_prev == 0 || m_prev->m_id == MemStructId) && + (m_next == 0 || m_next->m_id == MemStructId)); +} + + +/* + Additions are always at the tail of the list. + Returns 0 on error, non-zero on success. +*/ +int wxMemStruct::Append () +{ + if (! AssertList ()) + return 0; + + if (wxDebugContext::GetHead () == 0) { + if (wxDebugContext::GetTail () != 0) { + ErrorMsg ("Null list should have a null tail pointer"); + return 0; + } + (void) wxDebugContext::SetHead (this); + (void) wxDebugContext::SetTail (this); + } else { + wxDebugContext::GetTail ()->m_next = this; + this->m_prev = wxDebugContext::GetTail (); + (void) wxDebugContext::SetTail (this); + } + return 1; +} + + +/* + Don't actually free up anything here as the space which is used + by the node will be free'd up when the whole block is free'd. + Returns 0 on error, non-zero on success. +*/ +int wxMemStruct::Unlink () +{ + if (! AssertList ()) + return 0; + + if (wxDebugContext::GetHead () == 0 || wxDebugContext::GetTail () == 0) { + ErrorMsg ("Trying to remove node from empty list"); + return 0; + } + + // Handle the part of the list before this node. + if (m_prev == 0) { + if (this != wxDebugContext::GetHead ()) { + ErrorMsg ("No previous node for non-head node"); + return 0; + } + (void) wxDebugContext::SetHead (m_next); + } else { + if (! m_prev->AssertIt ()) { + ErrorMsg ("Trashed previous pointer"); + return 0; + } + + if (m_prev->m_next != this) { + ErrorMsg ("List is inconsistent"); + return 0; + } + m_prev->m_next = m_next; + } + + // Handle the part of the list after this node. + if (m_next == 0) { + if (this != wxDebugContext::GetTail ()) { + ErrorMsg ("No next node for non-tail node"); + return 0; + } + (void) wxDebugContext::SetTail (m_prev); + } else { + if (! m_next->AssertIt ()) { + ErrorMsg ("Trashed next pointer"); + return 0; + } + + if (m_next->m_prev != this) { + ErrorMsg ("List is inconsistent"); + return 0; + } + m_next->m_prev = m_prev; + } + + return 1; +} + + + +/* + Checks a node and block of memory to see that the markers are still + intact. +*/ +int wxMemStruct::CheckBlock () +{ + int nFailures = 0; + + if (m_firstMarker != MemStartCheck) { + nFailures++; + ErrorMsg (); + } + + char * pointer = wxDebugContext::MidMarkerPos ((char *) this); + if (* (wxMarkerType *) pointer != MemMidCheck) { + nFailures++; + ErrorMsg (); + } + + pointer = wxDebugContext::EndMarkerPos ((char *) this, RequestSize ()); + if (* (wxMarkerType *) pointer != MemEndCheck) { + nFailures++; + ErrorMsg (); + } + + return nFailures; +} + + +/* + Check the list of nodes to see if they are all ok. +*/ +int wxMemStruct::CheckAllPrevious () +{ + int nFailures = 0; + + for (wxMemStruct * st = this->m_prev; st != 0; st = st->m_prev) { + if (st->AssertIt ()) + nFailures += st->CheckBlock (); + else + return -1; + } + + return nFailures; +} + + +/* + When we delete a node we set the id slot to a specific value and then test + against this to see if a nodes have been deleted previously. I don't + just set the entire memory to the fillChar because then I'd be overwriting + useful stuff like the vtbl which may be needed to output the error message + including the file name and line numbers. Without this info the whole point + of this class is lost! +*/ +void wxMemStruct::SetDeleted () +{ + m_id = MemFillChar; +} + +int wxMemStruct::IsDeleted () +{ + return (m_id == MemFillChar); +} + + +/* + Print out a single node. There are many far better ways of doing this + but this will suffice for now. +*/ +void wxMemStruct::PrintNode () +{ + if (m_isObject) + { + wxObject *obj = (wxObject *)m_actualData; + wxClassInfo *info = obj->GetClassInfo(); + + // Let's put this in standard form so IDEs can load the file at the appropriate + // line + wxString msg; + + if (m_fileName) + msg.Printf(wxT("%s(%d): "), m_fileName, (int)m_lineNum); + + if (info && info->GetClassName()) + msg += info->GetClassName(); + else + msg += wxT("object"); + + wxString msg2; + msg2.Printf(wxT(" at 0x%lX, size %d"), (long)GetActualData(), (int)RequestSize()); + msg += msg2; + + wxLogMessage(msg); + } + else + { + wxString msg; + + if (m_fileName) + msg.Printf(wxT("%s(%d): "), m_fileName, (int)m_lineNum); + msg += wxT("non-object data"); + wxString msg2; + msg2.Printf(wxT(" at 0x%lX, size %d\n"), (long)GetActualData(), (int)RequestSize()); + msg += msg2; + + wxLogMessage(msg); + } +} + +void wxMemStruct::Dump () +{ + if (!ValidateNode()) return; + + if (m_isObject) + { + wxObject *obj = (wxObject *)m_actualData; + + wxString msg; + if (m_fileName) + msg.Printf(wxT("%s(%d): "), m_fileName, (int)m_lineNum); + + + /* TODO: We no longer have a stream (using wxLogDebug) so we can't dump it. + * Instead, do what wxObject::Dump does. + * What should we do long-term, eliminate Dumping? Or specify + * that MyClass::Dump should use wxLogDebug? Ugh. + obj->Dump(wxDebugContext::GetStream()); + */ + + if (obj->GetClassInfo() && obj->GetClassInfo()->GetClassName()) + msg += obj->GetClassInfo()->GetClassName(); + else + msg += wxT("unknown object class"); + + wxString msg2; + msg2.Printf(wxT(" at 0x%lX, size %d"), (long)GetActualData(), (int)RequestSize()); + msg += msg2; + + wxDebugContext::OutputDumpLine(msg); + } + else + { + wxString msg; + if (m_fileName) + msg.Printf(wxT("%s(%d): "), m_fileName, (int)m_lineNum); + + wxString msg2; + msg2.Printf(wxT("non-object data at 0x%lX, size %d"), (long)GetActualData(), (int)RequestSize() ); + msg += msg2; + wxDebugContext::OutputDumpLine(msg); + } +} + + +/* + Validate a node. Check to see that the node is "clean" in the sense + that nothing has over/underwritten it etc. +*/ +int wxMemStruct::ValidateNode () +{ + char * startPointer = (char *) this; + if (!AssertIt ()) { + if (IsDeleted ()) + ErrorMsg ("Object already deleted"); + else { + // Can't use the error routines as we have no recognisable object. +#ifndef __WXGTK__ + wxLogMessage(wxT("Can't verify memory struct - all bets are off!")); +#endif + } + return 0; + } + +/* + int i; + for (i = 0; i < wxDebugContext::TotSize (requestSize ()); i++) + cout << startPointer [i]; + cout << endl; +*/ + if (Marker () != MemStartCheck) + ErrorMsg (); + if (* (wxMarkerType *) wxDebugContext::MidMarkerPos (startPointer) != MemMidCheck) + ErrorMsg (); + if (* (wxMarkerType *) wxDebugContext::EndMarkerPos (startPointer, + RequestSize ()) != + MemEndCheck) + ErrorMsg (); + + // Back to before the extra buffer and check that + // we can still read what we originally wrote. + if (Marker () != MemStartCheck || + * (wxMarkerType *) wxDebugContext::MidMarkerPos (startPointer) + != MemMidCheck || + * (wxMarkerType *) wxDebugContext::EndMarkerPos (startPointer, + RequestSize ()) != MemEndCheck) + { + ErrorMsg (); + return 0; + } + + return 1; +} + +/* + The wxDebugContext class. +*/ + +wxMemStruct *wxDebugContext::m_head = NULL; +wxMemStruct *wxDebugContext::m_tail = NULL; + +bool wxDebugContext::m_checkPrevious = false; +int wxDebugContext::debugLevel = 1; +bool wxDebugContext::debugOn = true; +wxMemStruct *wxDebugContext::checkPoint = NULL; + +// For faster alignment calculation +static wxMarkerType markerCalc[2]; +int wxDebugContext::m_balign = (int)((char *)&markerCalc[1] - (char*)&markerCalc[0]); +int wxDebugContext::m_balignmask = (int)((char *)&markerCalc[1] - (char*)&markerCalc[0]) - 1; + +wxDebugContext::wxDebugContext(void) +{ +} + +wxDebugContext::~wxDebugContext(void) +{ +} + +/* + Work out the positions of the markers by creating an array of 2 markers + and comparing the addresses of the 2 elements. Use this number as the + alignment for markers. +*/ +size_t wxDebugContext::CalcAlignment () +{ + wxMarkerType ar[2]; + return (char *) &ar[1] - (char *) &ar[0]; +} + + +char * wxDebugContext::StructPos (const char * buf) +{ + return (char *) buf; +} + +char * wxDebugContext::MidMarkerPos (const char * buf) +{ + return StructPos (buf) + PaddedSize (sizeof (wxMemStruct)); +} + +char * wxDebugContext::CallerMemPos (const char * buf) +{ + return MidMarkerPos (buf) + PaddedSize (sizeof(wxMarkerType)); +} + + +char * wxDebugContext::EndMarkerPos (const char * buf, const size_t size) +{ + return CallerMemPos (buf) + PaddedSize (size); +} + + +/* + Slightly different as this takes a pointer to the start of the caller + requested region and returns a pointer to the start of the buffer. + */ +char * wxDebugContext::StartPos (const char * caller) +{ + return ((char *) (caller - wxDebugContext::PaddedSize (sizeof(wxMarkerType)) - + wxDebugContext::PaddedSize (sizeof (wxMemStruct)))); +} + +/* + We may need padding between various parts of the allocated memory. + Given a size of memory, this returns the amount of memory which should + be allocated in order to allow for alignment of the following object. + + I don't know how portable this stuff is, but it seems to work for me at + the moment. It would be real nice if I knew more about this! + + // Note: this function is now obsolete (along with CalcAlignment) + // because the calculations are done statically, for greater speed. +*/ +size_t wxDebugContext::GetPadding (const size_t size) +{ + size_t pad = size % CalcAlignment (); + return (pad) ? sizeof(wxMarkerType) - pad : 0; +} + +size_t wxDebugContext::PaddedSize (const size_t size) +{ + // Added by Terry Farnham to replace + // slow GetPadding call. + int padb; + + padb = size & m_balignmask; + if(padb) + return(size + m_balign - padb); + else + return(size); +} + +/* + Returns the total amount of memory which we need to get from the system + in order to satisfy a caller request. This includes space for the struct + plus markers and the caller's memory as well. +*/ +size_t wxDebugContext::TotSize (const size_t reqSize) +{ + return (PaddedSize (sizeof (wxMemStruct)) + PaddedSize (reqSize) + + 2 * sizeof(wxMarkerType)); +} + + +/* + Traverse the list of nodes executing the given function on each node. +*/ +void wxDebugContext::TraverseList (PmSFV func, wxMemStruct *from) +{ + if (!from) + from = wxDebugContext::GetHead (); + + wxMemStruct * st = NULL; + for (st = from; st != 0; st = st->m_next) + { + void* data = st->GetActualData(); +// if ((data != (void*)m_debugStream) && (data != (void*) m_streamBuf)) + if (data != (void*) wxLog::GetActiveTarget()) + { + (st->*func) (); + } + } +} + + +/* + Print out the list. + */ +bool wxDebugContext::PrintList (void) +{ +#ifdef __WXDEBUG__ + TraverseList ((PmSFV)&wxMemStruct::PrintNode, (checkPoint ? checkPoint->m_next : (wxMemStruct*)NULL)); + + return true; +#else + return false; +#endif +} + +bool wxDebugContext::Dump(void) +{ +#ifdef __WXDEBUG__ + { + wxChar* appName = (wxChar*) wxT("application"); + wxString appNameStr; + if (wxTheApp) + { + appNameStr = wxTheApp->GetAppName(); + appName = WXSTRINGCAST appNameStr; + OutputDumpLine(wxT("----- Memory dump of %s at %s -----"), appName, WXSTRINGCAST wxNow() ); + } + else + { + OutputDumpLine( wxT("----- Memory dump -----") ); + } + } + + TraverseList ((PmSFV)&wxMemStruct::Dump, (checkPoint ? checkPoint->m_next : (wxMemStruct*)NULL)); + + OutputDumpLine(wxEmptyString); + OutputDumpLine(wxEmptyString); + + return true; +#else + return false; +#endif +} + +#ifdef __WXDEBUG__ +struct wxDebugStatsStruct +{ + long instanceCount; + long totalSize; + wxChar *instanceClass; + wxDebugStatsStruct *next; +}; + +static wxDebugStatsStruct *FindStatsStruct(wxDebugStatsStruct *st, wxChar *name) +{ + while (st) + { + if (wxStrcmp(st->instanceClass, name) == 0) + return st; + st = st->next; + } + return NULL; +} + +static wxDebugStatsStruct *InsertStatsStruct(wxDebugStatsStruct *head, wxDebugStatsStruct *st) +{ + st->next = head; + return st; +} +#endif + +bool wxDebugContext::PrintStatistics(bool detailed) +{ +#ifdef __WXDEBUG__ + { + wxChar* appName = (wxChar*) wxT("application"); + wxString appNameStr; + if (wxTheApp) + { + appNameStr = wxTheApp->GetAppName(); + appName = WXSTRINGCAST appNameStr; + OutputDumpLine(wxT("----- Memory statistics of %s at %s -----"), appName, WXSTRINGCAST wxNow() ); + } + else + { + OutputDumpLine( wxT("----- Memory statistics -----") ); + } + } + + bool currentMode = GetDebugMode(); + SetDebugMode(false); + + long noNonObjectNodes = 0; + long noObjectNodes = 0; + long totalSize = 0; + + wxDebugStatsStruct *list = NULL; + + wxMemStruct *from = (checkPoint ? checkPoint->m_next : (wxMemStruct*)NULL ); + if (!from) + from = wxDebugContext::GetHead (); + + wxMemStruct *st; + for (st = from; st != 0; st = st->m_next) + { + void* data = st->GetActualData(); + if (detailed && (data != (void*) wxLog::GetActiveTarget())) + { + wxChar *className = (wxChar*) wxT("nonobject"); + if (st->m_isObject && st->GetActualData()) + { + wxObject *obj = (wxObject *)st->GetActualData(); + if (obj->GetClassInfo()->GetClassName()) + className = (wxChar*)obj->GetClassInfo()->GetClassName(); + } + wxDebugStatsStruct *stats = FindStatsStruct(list, className); + if (!stats) + { + stats = (wxDebugStatsStruct *)malloc(sizeof(wxDebugStatsStruct)); + stats->instanceClass = className; + stats->instanceCount = 0; + stats->totalSize = 0; + list = InsertStatsStruct(list, stats); + } + stats->instanceCount ++; + stats->totalSize += st->RequestSize(); + } + + if (data != (void*) wxLog::GetActiveTarget()) + { + totalSize += st->RequestSize(); + if (st->m_isObject) + noObjectNodes ++; + else + noNonObjectNodes ++; + } + } + + if (detailed) + { + while (list) + { + OutputDumpLine(wxT("%ld objects of class %s, total size %ld"), + list->instanceCount, list->instanceClass, list->totalSize); + wxDebugStatsStruct *old = list; + list = old->next; + free((char *)old); + } + OutputDumpLine(wxEmptyString); + } + + SetDebugMode(currentMode); + + OutputDumpLine(wxT("Number of object items: %ld"), noObjectNodes); + OutputDumpLine(wxT("Number of non-object items: %ld"), noNonObjectNodes); + OutputDumpLine(wxT("Total allocated size: %ld"), totalSize); + OutputDumpLine(wxEmptyString); + OutputDumpLine(wxEmptyString); + + return true; +#else + (void)detailed; + return false; +#endif +} + +bool wxDebugContext::PrintClasses(void) +{ + { + wxChar* appName = (wxChar*) wxT("application"); + wxString appNameStr; + if (wxTheApp) + { + appNameStr = wxTheApp->GetAppName(); + appName = WXSTRINGCAST appNameStr; + wxLogMessage(wxT("----- Classes in %s -----"), appName); + } + } + + int n = 0; + wxHashTable::compatibility_iterator node; + wxClassInfo *info; + + wxClassInfo::sm_classTable->BeginFind(); + node = wxClassInfo::sm_classTable->Next(); + while (node) + { + info = (wxClassInfo *)node->GetData(); + if (info->GetClassName()) + { + wxString msg(info->GetClassName()); + msg += wxT(" "); + + if (info->GetBaseClassName1() && !info->GetBaseClassName2()) + { + msg += wxT("is a "); + msg += info->GetBaseClassName1(); + } + else if (info->GetBaseClassName1() && info->GetBaseClassName2()) + { + msg += wxT("is a "); + msg += info->GetBaseClassName1() ; + msg += wxT(", "); + msg += info->GetBaseClassName2() ; + } + if (info->GetConstructor()) + msg += wxT(": dynamic"); + + wxLogMessage(msg); + } + node = wxClassInfo::sm_classTable->Next(); + n ++; + } + wxLogMessage(wxEmptyString); + wxLogMessage(wxT("There are %d classes derived from wxObject."), n); + wxLogMessage(wxEmptyString); + wxLogMessage(wxEmptyString); + return true; +} + +void wxDebugContext::SetCheckpoint(bool all) +{ + if (all) + checkPoint = NULL; + else + checkPoint = m_tail; +} + +// Checks all nodes since checkpoint, or since start. +int wxDebugContext::Check(bool checkAll) +{ + int nFailures = 0; + + wxMemStruct *from = (checkPoint ? checkPoint->m_next : (wxMemStruct*)NULL ); + if (!from || checkAll) + from = wxDebugContext::GetHead (); + + for (wxMemStruct * st = from; st != 0; st = st->m_next) + { + if (st->AssertIt ()) + nFailures += st->CheckBlock (); + else + return -1; + } + + return nFailures; +} + +// Count the number of non-wxDebugContext-related objects +// that are outstanding +int wxDebugContext::CountObjectsLeft(bool sinceCheckpoint) +{ + int n = 0; + + wxMemStruct *from = NULL; + if (sinceCheckpoint && checkPoint) + from = checkPoint->m_next; + else + from = wxDebugContext::GetHead () ; + + for (wxMemStruct * st = from; st != 0; st = st->m_next) + { + void* data = st->GetActualData(); + if (data != (void*) wxLog::GetActiveTarget()) + n ++; + } + + return n ; +} + +// This function is used to output the dump +void wxDebugContext::OutputDumpLine(const wxChar *szFormat, ...) +{ + // a buffer of 2048 bytes should be long enough for a file name + // and a class name + wxChar buf[2048]; + int count; + va_list argptr; + va_start(argptr, szFormat); + buf[sizeof(buf)/sizeof(wxChar)-1] = _T('\0'); + + // keep 3 bytes for a \r\n\0 + count = wxVsnprintf(buf, sizeof(buf)/sizeof(wxChar)-3, szFormat, argptr); + + if ( count < 0 ) + count = sizeof(buf)/sizeof(wxChar)-3; + buf[count]=_T('\r'); + buf[count+1]=_T('\n'); + buf[count+2]=_T('\0'); + + wxMessageOutputDebug dbgout; + dbgout.Printf(buf); +} + + +#if USE_THREADSAFE_MEMORY_ALLOCATION +static bool memSectionOk = false; + +class MemoryCriticalSection : public wxCriticalSection +{ +public: + MemoryCriticalSection() { + memSectionOk = true; + } + ~MemoryCriticalSection() { + memSectionOk = false; + } +}; + +class MemoryCriticalSectionLocker +{ +public: + inline MemoryCriticalSectionLocker(wxCriticalSection& critsect) + : m_critsect(critsect), m_locked(memSectionOk) { if(m_locked) m_critsect.Enter(); } + inline ~MemoryCriticalSectionLocker() { if(m_locked) m_critsect.Leave(); } + +private: + // no assignment operator nor copy ctor + MemoryCriticalSectionLocker(const MemoryCriticalSectionLocker&); + MemoryCriticalSectionLocker& operator=(const MemoryCriticalSectionLocker&); + + wxCriticalSection& m_critsect; + bool m_locked; +}; + +static MemoryCriticalSection memLocker; + +#endif // USE_THREADSAFE_MEMORY_ALLOCATION + + +#ifdef __WXDEBUG__ +#if !(defined(__WXMSW__) && (defined(WXUSINGDLL) || defined(WXMAKINGDLL_BASE))) +#if wxUSE_GLOBAL_MEMORY_OPERATORS +void * operator new (size_t size, wxChar * fileName, int lineNum) +{ + return wxDebugAlloc(size, fileName, lineNum, false, false); +} + +void * operator new (size_t size) +{ + return wxDebugAlloc(size, NULL, 0, false); +} + +void operator delete (void * buf) +{ + wxDebugFree(buf, false); +} + +#if wxUSE_ARRAY_MEMORY_OPERATORS +void * operator new[] (size_t size) +{ + return wxDebugAlloc(size, NULL, 0, false, true); +} + +void * operator new[] (size_t size, wxChar * fileName, int lineNum) +{ + return wxDebugAlloc(size, fileName, lineNum, false, true); +} + +void operator delete[] (void * buf) +{ + wxDebugFree(buf, true); +} +#endif // wxUSE_ARRAY_MEMORY_OPERATORS +#endif // wxUSE_GLOBAL_MEMORY_OPERATORS +#endif // !(defined(__WXMSW__) && (defined(WXUSINGDLL) || defined(WXMAKINGDLL_BASE))) + +// TODO: store whether this is a vector or not. +void * wxDebugAlloc(size_t size, wxChar * fileName, int lineNum, bool isObject, bool WXUNUSED(isVect) ) +{ +#if USE_THREADSAFE_MEMORY_ALLOCATION + MemoryCriticalSectionLocker lock(memLocker); +#endif + + // If not in debugging allocation mode, do the normal thing + // so we don't leave any trace of ourselves in the node list. + +#if defined(__VISAGECPP__) && (__IBMCPP__ < 400 || __IBMC__ < 400 ) +// VA 3.0 still has trouble in here + return (void *)malloc(size); +#endif + if (!wxDebugContext::GetDebugMode()) + { + return (void *)malloc(size); + } + + int totSize = wxDebugContext::TotSize (size); + char * buf = (char *) malloc(totSize); + if (!buf) { + wxLogMessage(wxT("Call to malloc (%ld) failed."), (long)size); + return 0; + } + wxMemStruct * st = (wxMemStruct *)buf; + st->m_firstMarker = MemStartCheck; + st->m_reqSize = size; + st->m_fileName = fileName; + st->m_lineNum = lineNum; + st->m_id = MemStructId; + st->m_prev = 0; + st->m_next = 0; + st->m_isObject = isObject; + + // Errors from Append() shouldn't really happen - but just in case! + if (st->Append () == 0) { + st->ErrorMsg ("Trying to append new node"); + } + + if (wxDebugContext::GetCheckPrevious ()) { + if (st->CheckAllPrevious () < 0) { + st->ErrorMsg ("Checking previous nodes"); + } + } + + // Set up the extra markers at the middle and end. + char * ptr = wxDebugContext::MidMarkerPos (buf); + * (wxMarkerType *) ptr = MemMidCheck; + ptr = wxDebugContext::EndMarkerPos (buf, size); + * (wxMarkerType *) ptr = MemEndCheck; + + // pointer returned points to the start of the caller's + // usable area. + void *m_actualData = (void *) wxDebugContext::CallerMemPos (buf); + st->m_actualData = m_actualData; + + return m_actualData; +} + +// TODO: check whether was allocated as a vector +void wxDebugFree(void * buf, bool WXUNUSED(isVect) ) +{ +#if USE_THREADSAFE_MEMORY_ALLOCATION + MemoryCriticalSectionLocker lock(memLocker); +#endif + + if (!buf) + return; + +#if defined(__VISAGECPP__) && (__IBMCPP__ < 400 || __IBMC__ < 400 ) +// VA 3.0 still has trouble in here + free((char *)buf); +#endif + // If not in debugging allocation mode, do the normal thing + // so we don't leave any trace of ourselves in the node list. + if (!wxDebugContext::GetDebugMode()) + { + free((char *)buf); + return; + } + + // Points to the start of the entire allocated area. + char * startPointer = wxDebugContext::StartPos ((char *) buf); + // Find the struct and make sure that it's identifiable. + wxMemStruct * st = (wxMemStruct *) wxDebugContext::StructPos (startPointer); + + if (! st->ValidateNode ()) + return; + + // If this is the current checkpoint, we need to + // move the checkpoint back so it points to a valid + // node. + if (st == wxDebugContext::checkPoint) + wxDebugContext::checkPoint = wxDebugContext::checkPoint->m_prev; + + if (! st->Unlink ()) + { + st->ErrorMsg ("Unlinking deleted node"); + } + + // Now put in the fill char into the id slot and the caller requested + // memory locations. + st->SetDeleted (); + (void) memset (wxDebugContext::CallerMemPos (startPointer), MemFillChar, + st->RequestSize ()); + + free((char *)st); +} + +#endif // __WXDEBUG__ + +// Trace: send output to the current debugging stream +void wxTrace(const wxChar * ...) +{ +#if 1 + wxFAIL_MSG(wxT("wxTrace is now obsolete. Please use wxDebugXXX instead.")); +#else + va_list ap; + static wxChar buffer[512]; + + va_start(ap, fmt); + +#ifdef __WXMSW__ + wvsprintf(buffer,fmt,ap) ; +#else + vsprintf(buffer,fmt,ap) ; +#endif + + va_end(ap); + + if (wxDebugContext::HasStream()) + { + wxDebugContext::GetStream() << buffer; + wxDebugContext::GetStream().flush(); + } + else +#ifdef __WXMSW__ +#ifdef __WIN32__ + OutputDebugString((LPCTSTR)buffer) ; +#else + OutputDebugString((const char*) buffer) ; +#endif +#else + fprintf(stderr, buffer); +#endif +#endif +} + +// Trace with level +void wxTraceLevel(int, const wxChar * ...) +{ +#if 1 + wxFAIL_MSG(wxT("wxTrace is now obsolete. Please use wxDebugXXX instead.")); +#else + if (wxDebugContext::GetLevel() < level) + return; + + va_list ap; + static wxChar buffer[512]; + + va_start(ap, fmt); + +#ifdef __WXMSW__ + wxWvsprintf(buffer,fmt,ap) ; +#else + vsprintf(buffer,fmt,ap) ; +#endif + + va_end(ap); + + if (wxDebugContext::HasStream()) + { + wxDebugContext::GetStream() << buffer; + wxDebugContext::GetStream().flush(); + } + else +#ifdef __WXMSW__ +#ifdef __WIN32__ + OutputDebugString((LPCTSTR)buffer) ; +#else + OutputDebugString((const char*) buffer) ; +#endif +#else + fprintf(stderr, buffer); +#endif +#endif +} + +//---------------------------------------------------------------------------- +// Final cleanup after all global objects in all files have been destroyed +//---------------------------------------------------------------------------- + +// Don't set it to 0 by dynamic initialization +// Some compilers will really do the assignment later +// All global variables are initialized to 0 at the very beginning, and this is just fine. +int wxDebugContextDumpDelayCounter::sm_count; + +void wxDebugContextDumpDelayCounter::DoDump() +{ + if (wxDebugContext::CountObjectsLeft(true) > 0) + { + wxDebugContext::OutputDumpLine(wxT("There were memory leaks.\n")); + wxDebugContext::Dump(); + wxDebugContext::PrintStatistics(); + } +} + +// Even if there is nothing else, make sure that there is at +// least one cleanup counter object +static wxDebugContextDumpDelayCounter wxDebugContextDumpDelayCounter_One; + +#endif // (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT diff --git a/Externals/wxWidgets/src/common/menucmn.cpp b/Externals/wxWidgets/src/common/menucmn.cpp index 9dbba3c749..241ddb765c 100644 --- a/Externals/wxWidgets/src/common/menucmn.cpp +++ b/Externals/wxWidgets/src/common/menucmn.cpp @@ -1,1165 +1,1165 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: src/common/menucmn.cpp -// Purpose: wxMenu and wxMenuBar methods common to all ports -// Author: Vadim Zeitlin -// Modified by: -// Created: 26.10.99 -// RCS-ID: $Id: menucmn.cpp 51361 2008-01-24 18:12:55Z PC $ -// Copyright: (c) wxWidgets team -// Licence: wxWindows licence -/////////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_MENUS - -#include - -#ifndef WX_PRECOMP - #include "wx/intl.h" - #include "wx/log.h" - #include "wx/menu.h" -#endif - -#include "wx/stockitem.h" - -// ---------------------------------------------------------------------------- -// template lists -// ---------------------------------------------------------------------------- - -#include "wx/listimpl.cpp" - -WX_DEFINE_LIST(wxMenuList) -WX_DEFINE_LIST(wxMenuItemList) - -// ============================================================================ -// implementation -// ============================================================================ - -// ---------------------------------------------------------------------------- -// wxAcceleratorEntry -// ---------------------------------------------------------------------------- - - -#if wxUSE_ACCEL - -static const struct wxKeyName -{ - wxKeyCode code; - const wxChar *name; -} wxKeyNames[] = -{ - { WXK_DELETE, wxTRANSLATE("DEL") }, - { WXK_DELETE, wxTRANSLATE("DELETE") }, - { WXK_BACK, wxTRANSLATE("BACK") }, - { WXK_INSERT, wxTRANSLATE("INS") }, - { WXK_INSERT, wxTRANSLATE("INSERT") }, - { WXK_RETURN, wxTRANSLATE("ENTER") }, - { WXK_RETURN, wxTRANSLATE("RETURN") }, - { WXK_PAGEUP, wxTRANSLATE("PGUP") }, - { WXK_PAGEDOWN, wxTRANSLATE("PGDN") }, - { WXK_LEFT, wxTRANSLATE("LEFT") }, - { WXK_RIGHT, wxTRANSLATE("RIGHT") }, - { WXK_UP, wxTRANSLATE("UP") }, - { WXK_DOWN, wxTRANSLATE("DOWN") }, - { WXK_HOME, wxTRANSLATE("HOME") }, - { WXK_END, wxTRANSLATE("END") }, - { WXK_SPACE, wxTRANSLATE("SPACE") }, - { WXK_TAB, wxTRANSLATE("TAB") }, - { WXK_ESCAPE, wxTRANSLATE("ESC") }, - { WXK_ESCAPE, wxTRANSLATE("ESCAPE") }, - { WXK_CANCEL, wxTRANSLATE("CANCEL") }, - { WXK_CLEAR, wxTRANSLATE("CLEAR") }, - { WXK_MENU, wxTRANSLATE("MENU") }, - { WXK_PAUSE, wxTRANSLATE("PAUSE") }, - { WXK_CAPITAL, wxTRANSLATE("CAPITAL") }, - { WXK_SELECT, wxTRANSLATE("SELECT") }, - { WXK_PRINT, wxTRANSLATE("PRINT") }, - { WXK_EXECUTE, wxTRANSLATE("EXECUTE") }, - { WXK_SNAPSHOT, wxTRANSLATE("SNAPSHOT") }, - { WXK_HELP, wxTRANSLATE("HELP") }, - { WXK_ADD, wxTRANSLATE("ADD") }, - { WXK_SEPARATOR, wxTRANSLATE("SEPARATOR") }, - { WXK_SUBTRACT, wxTRANSLATE("SUBTRACT") }, - { WXK_DECIMAL, wxTRANSLATE("DECIMAL") }, - { WXK_DIVIDE, wxTRANSLATE("DIVIDE") }, - { WXK_NUMLOCK, wxTRANSLATE("NUM_LOCK") }, - { WXK_SCROLL, wxTRANSLATE("SCROLL_LOCK") }, - { WXK_PAGEUP, wxTRANSLATE("PAGEUP") }, - { WXK_PAGEDOWN, wxTRANSLATE("PAGEDOWN") }, - { WXK_NUMPAD_SPACE, wxTRANSLATE("KP_SPACE") }, - { WXK_NUMPAD_TAB, wxTRANSLATE("KP_TAB") }, - { WXK_NUMPAD_ENTER, wxTRANSLATE("KP_ENTER") }, - { WXK_NUMPAD_HOME, wxTRANSLATE("KP_HOME") }, - { WXK_NUMPAD_LEFT, wxTRANSLATE("KP_LEFT") }, - { WXK_NUMPAD_UP, wxTRANSLATE("KP_UP") }, - { WXK_NUMPAD_RIGHT, wxTRANSLATE("KP_RIGHT") }, - { WXK_NUMPAD_DOWN, wxTRANSLATE("KP_DOWN") }, - { WXK_NUMPAD_PAGEUP, wxTRANSLATE("KP_PRIOR") }, - { WXK_NUMPAD_PAGEUP, wxTRANSLATE("KP_PAGEUP") }, - { WXK_NUMPAD_PAGEDOWN, wxTRANSLATE("KP_NEXT") }, - { WXK_NUMPAD_PAGEDOWN, wxTRANSLATE("KP_PAGEDOWN") }, - { WXK_NUMPAD_END, wxTRANSLATE("KP_END") }, - { WXK_NUMPAD_BEGIN, wxTRANSLATE("KP_BEGIN") }, - { WXK_NUMPAD_INSERT, wxTRANSLATE("KP_INSERT") }, - { WXK_NUMPAD_DELETE, wxTRANSLATE("KP_DELETE") }, - { WXK_NUMPAD_EQUAL, wxTRANSLATE("KP_EQUAL") }, - { WXK_NUMPAD_MULTIPLY, wxTRANSLATE("KP_MULTIPLY") }, - { WXK_NUMPAD_ADD, wxTRANSLATE("KP_ADD") }, - { WXK_NUMPAD_SEPARATOR, wxTRANSLATE("KP_SEPARATOR") }, - { WXK_NUMPAD_SUBTRACT, wxTRANSLATE("KP_SUBTRACT") }, - { WXK_NUMPAD_DECIMAL, wxTRANSLATE("KP_DECIMAL") }, - { WXK_NUMPAD_DIVIDE, wxTRANSLATE("KP_DIVIDE") }, - { WXK_WINDOWS_LEFT, wxTRANSLATE("WINDOWS_LEFT") }, - { WXK_WINDOWS_RIGHT, wxTRANSLATE("WINDOWS_RIGHT") }, - { WXK_WINDOWS_MENU, wxTRANSLATE("WINDOWS_MENU") }, - { WXK_COMMAND, wxTRANSLATE("COMMAND") }, -}; - -// return true if the 2 strings refer to the same accel -// -// as accels can be either translated or not, check for both possibilities and -// also compare case-insensitively as the key names case doesn't count -static inline bool CompareAccelString(const wxString& str, const wxChar *accel) -{ - return str.CmpNoCase(accel) == 0 -#if wxUSE_INTL - || str.CmpNoCase(wxGetTranslation(accel)) == 0 -#endif - ; -} - -// return prefixCode+number if the string is of the form "" and -// 0 if it isn't -// -// first and last parameter specify the valid domain for "number" part -static int - IsNumberedAccelKey(const wxString& str, - const wxChar *prefix, - wxKeyCode prefixCode, - unsigned first, - unsigned last) -{ - const size_t lenPrefix = wxStrlen(prefix); - if ( !CompareAccelString(str.Left(lenPrefix), prefix) ) - return 0; - - unsigned long num; - if ( !str.Mid(lenPrefix).ToULong(&num) ) - return 0; - - if ( num < first || num > last ) - { - // this must be a mistake, chances that this is a valid name of another - // key are vanishingly small - wxLogDebug(_T("Invalid key string \"%s\""), str.c_str()); - return 0; - } - - return prefixCode + num - first; -} - -/* static */ -bool -wxAcceleratorEntry::ParseAccel(const wxString& text, int *flagsOut, int *keyOut) -{ - // the parser won't like trailing spaces - wxString label = text; - label.Trim(true); // the initial \t must be preserved so don't strip leading whitespaces - - // check for accelerators: they are given after '\t' - int posTab = label.Find(wxT('\t')); - if ( posTab == wxNOT_FOUND ) - { - return false; - } - - // parse the accelerator string - int accelFlags = wxACCEL_NORMAL; - wxString current; - for ( size_t n = (size_t)posTab + 1; n < label.length(); n++ ) - { - if ( (label[n] == '+') || (label[n] == '-') ) - { - if ( CompareAccelString(current, wxTRANSLATE("ctrl")) ) - accelFlags |= wxACCEL_CTRL; - else if ( CompareAccelString(current, wxTRANSLATE("alt")) ) - accelFlags |= wxACCEL_ALT; - else if ( CompareAccelString(current, wxTRANSLATE("shift")) ) - accelFlags |= wxACCEL_SHIFT; - else // not a recognized modifier name - { - // we may have "Ctrl-+", for example, but we still want to - // catch typos like "Crtl-A" so only give the warning if we - // have something before the current '+' or '-', else take - // it as a literal symbol - if ( current.empty() ) - { - current += label[n]; - - // skip clearing it below - continue; - } - else - { - wxLogDebug(wxT("Unknown accel modifier: '%s'"), - current.c_str()); - } - } - - current.clear(); - } - else // not special character - { - current += (wxChar) wxTolower(label[n]); - } - } - - int keyCode; - const size_t len = current.length(); - switch ( len ) - { - case 0: - wxLogDebug(wxT("No accel key found, accel string ignored.")); - return false; - - case 1: - // it's just a letter - keyCode = current[0U]; - - // if the key is used with any modifiers, make it an uppercase one - // because Ctrl-A and Ctrl-a are the same; but keep it as is if it's - // used alone as 'a' and 'A' are different - if ( accelFlags != wxACCEL_NORMAL ) - keyCode = wxToupper(keyCode); - break; - - default: - keyCode = IsNumberedAccelKey(current, wxTRANSLATE("F"), - WXK_F1, 1, 12); - if ( !keyCode ) - { - for ( size_t n = 0; n < WXSIZEOF(wxKeyNames); n++ ) - { - const wxKeyName& kn = wxKeyNames[n]; - if ( CompareAccelString(current, kn.name) ) - { - keyCode = kn.code; - break; - } - } - } - - if ( !keyCode ) - keyCode = IsNumberedAccelKey(current, wxTRANSLATE("KP_"), - WXK_NUMPAD0, 0, 9); - if ( !keyCode ) - keyCode = IsNumberedAccelKey(current, wxTRANSLATE("SPECIAL"), - WXK_SPECIAL1, 1, 20); - - if ( !keyCode ) - { - wxLogDebug(wxT("Unrecognized accel key '%s', accel string ignored."), - current.c_str()); - return false; - } - } - - - wxASSERT_MSG( keyCode, _T("logic error: should have key code here") ); - - if ( flagsOut ) - *flagsOut = accelFlags; - if ( keyOut ) - *keyOut = keyCode; - - return true; -} - -/* static */ -wxAcceleratorEntry *wxAcceleratorEntry::Create(const wxString& str) -{ - int flags, - keyCode; - if ( !ParseAccel(str, &flags, &keyCode) ) - return NULL; - - return new wxAcceleratorEntry(flags, keyCode); -} - -bool wxAcceleratorEntry::FromString(const wxString& str) -{ - return ParseAccel(str, &m_flags, &m_keyCode); -} - -wxString wxAcceleratorEntry::ToString() const -{ - wxString text; - - int flags = GetFlags(); - if ( flags & wxACCEL_ALT ) - text += _("Alt-"); - if ( flags & wxACCEL_CTRL ) - text += _("Ctrl-"); - if ( flags & wxACCEL_SHIFT ) - text += _("Shift-"); - - const int code = GetKeyCode(); - - if ( code >= WXK_F1 && code <= WXK_F12 ) - text << _("F") << code - WXK_F1 + 1; - else if ( code >= WXK_NUMPAD0 && code <= WXK_NUMPAD9 ) - text << _("KP_") << code - WXK_NUMPAD0; - else if ( code >= WXK_SPECIAL1 && code <= WXK_SPECIAL20 ) - text << _("SPECIAL") << code - WXK_SPECIAL1 + 1; - else // check the named keys - { - size_t n; - for ( n = 0; n < WXSIZEOF(wxKeyNames); n++ ) - { - const wxKeyName& kn = wxKeyNames[n]; - if ( code == kn.code ) - { - text << wxGetTranslation(kn.name); - break; - } - } - - if ( n == WXSIZEOF(wxKeyNames) ) - { - // must be a simple key - if ( -#if !wxUSE_UNICODE - isascii(code) && -#endif // ANSI - wxIsalnum(code) ) - { - text << (wxChar)code; - } - else - { - wxFAIL_MSG( wxT("unknown keyboard accelerator code") ); - } - } - } - - return text; -} - -wxAcceleratorEntry *wxGetAccelFromString(const wxString& label) -{ - return wxAcceleratorEntry::Create(label); -} - -#endif // wxUSE_ACCEL - - -// ---------------------------------------------------------------------------- -// wxMenuItem -// ---------------------------------------------------------------------------- - -wxMenuItemBase::wxMenuItemBase(wxMenu *parentMenu, - int id, - const wxString& text, - const wxString& help, - wxItemKind kind, - wxMenu *subMenu) -{ - wxASSERT_MSG( parentMenu != NULL, wxT("menuitem should have a menu") ); - - m_parentMenu = parentMenu; - m_subMenu = subMenu; - m_isEnabled = true; - m_isChecked = false; - m_id = id; - m_kind = kind; - if (m_id == wxID_ANY) - m_id = wxNewId(); - if (m_id == wxID_SEPARATOR) - m_kind = wxITEM_SEPARATOR; - - SetText(text); - SetHelp(help); -} - -wxMenuItemBase::~wxMenuItemBase() -{ - delete m_subMenu; -} - -#if wxUSE_ACCEL - -wxAcceleratorEntry *wxMenuItemBase::GetAccel() const -{ - return wxAcceleratorEntry::Create(GetText()); -} - -void wxMenuItemBase::SetAccel(wxAcceleratorEntry *accel) -{ - wxString text = m_text.BeforeFirst(wxT('\t')); - if ( accel ) - { - text += wxT('\t'); - text += accel->ToString(); - } - - SetText(text); -} - -#endif // wxUSE_ACCEL - -void wxMenuItemBase::SetText(const wxString& str) -{ - m_text = str; - - if ( m_text.empty() && !IsSeparator() ) - { - wxASSERT_MSG( wxIsStockID(GetId()), - wxT("A non-stock menu item with an empty label?") ); - m_text = wxGetStockLabel(GetId(), wxSTOCK_WITH_ACCELERATOR | - wxSTOCK_WITH_MNEMONIC); - } -} - -void wxMenuItemBase::SetHelp(const wxString& str) -{ - m_help = str; - - if ( m_help.empty() && !IsSeparator() && wxIsStockID(GetId()) ) - { - // get a stock help string - m_help = wxGetStockHelpString(GetId()); - } -} - -wxString wxMenuItemBase::GetLabelText(const wxString& label) -{ - return GetLabelFromText(label); -} - -bool wxMenuBase::ms_locked = true; - -// ---------------------------------------------------------------------------- -// wxMenu ctor and dtor -// ---------------------------------------------------------------------------- - -void wxMenuBase::Init(long style) -{ - m_menuBar = (wxMenuBar *)NULL; - m_menuParent = (wxMenu *)NULL; - - m_invokingWindow = (wxWindow *)NULL; - m_style = style; - m_clientData = (void *)NULL; - m_eventHandler = this; -} - -wxMenuBase::~wxMenuBase() -{ - WX_CLEAR_LIST(wxMenuItemList, m_items); -} - -// ---------------------------------------------------------------------------- -// wxMenu item adding/removing -// ---------------------------------------------------------------------------- - -void wxMenuBase::AddSubMenu(wxMenu *submenu) -{ - wxCHECK_RET( submenu, _T("can't add a NULL submenu") ); - - submenu->SetParent((wxMenu *)this); -} - -wxMenuItem* wxMenuBase::DoAppend(wxMenuItem *item) -{ - wxCHECK_MSG( item, NULL, wxT("invalid item in wxMenu::Append()") ); - - m_items.Append(item); - item->SetMenu((wxMenu*)this); - if ( item->IsSubMenu() ) - { - AddSubMenu(item->GetSubMenu()); - } - - return item; -} - -wxMenuItem* wxMenuBase::Insert(size_t pos, wxMenuItem *item) -{ - wxCHECK_MSG( item, NULL, wxT("invalid item in wxMenu::Insert") ); - - if ( pos == GetMenuItemCount() ) - { - return DoAppend(item); - } - else - { - wxCHECK_MSG( pos < GetMenuItemCount(), NULL, - wxT("invalid index in wxMenu::Insert") ); - - return DoInsert(pos, item); - } -} - -wxMenuItem* wxMenuBase::DoInsert(size_t pos, wxMenuItem *item) -{ - wxCHECK_MSG( item, NULL, wxT("invalid item in wxMenu::Insert()") ); - - wxMenuItemList::compatibility_iterator node = m_items.Item(pos); - wxCHECK_MSG( node, NULL, wxT("invalid index in wxMenu::Insert()") ); - - m_items.Insert(node, item); - item->SetMenu((wxMenu*)this); - if ( item->IsSubMenu() ) - { - AddSubMenu(item->GetSubMenu()); - } - - return item; -} - -wxMenuItem *wxMenuBase::Remove(wxMenuItem *item) -{ - wxCHECK_MSG( item, NULL, wxT("invalid item in wxMenu::Remove") ); - - return DoRemove(item); -} - -wxMenuItem *wxMenuBase::DoRemove(wxMenuItem *item) -{ - wxMenuItemList::compatibility_iterator node = m_items.Find(item); - - // if we get here, the item is valid or one of Remove() functions is broken - wxCHECK_MSG( node, NULL, wxT("bug in wxMenu::Remove logic") ); - - // we detach the item, but we do delete the list node (i.e. don't call - // DetachNode() here!) - m_items.Erase(node); - - // item isn't attached to anything any more - item->SetMenu((wxMenu *)NULL); - wxMenu *submenu = item->GetSubMenu(); - if ( submenu ) - { - submenu->SetParent((wxMenu *)NULL); - if ( submenu->IsAttached() ) - submenu->Detach(); - } - - return item; -} - -bool wxMenuBase::Delete(wxMenuItem *item) -{ - wxCHECK_MSG( item, false, wxT("invalid item in wxMenu::Delete") ); - - return DoDelete(item); -} - -bool wxMenuBase::DoDelete(wxMenuItem *item) -{ - wxMenuItem *item2 = DoRemove(item); - wxCHECK_MSG( item2, false, wxT("failed to delete menu item") ); - - // don't delete the submenu - item2->SetSubMenu((wxMenu *)NULL); - - delete item2; - - return true; -} - -bool wxMenuBase::Destroy(wxMenuItem *item) -{ - wxCHECK_MSG( item, false, wxT("invalid item in wxMenu::Destroy") ); - - return DoDestroy(item); -} - -bool wxMenuBase::DoDestroy(wxMenuItem *item) -{ - wxMenuItem *item2 = DoRemove(item); - wxCHECK_MSG( item2, false, wxT("failed to delete menu item") ); - - delete item2; - - return true; -} - -// ---------------------------------------------------------------------------- -// wxMenu searching for items -// ---------------------------------------------------------------------------- - -// Finds the item id matching the given string, wxNOT_FOUND if not found. -int wxMenuBase::FindItem(const wxString& text) const -{ - wxString label = wxMenuItem::GetLabelFromText(text); - for ( wxMenuItemList::compatibility_iterator node = m_items.GetFirst(); - node; - node = node->GetNext() ) - { - wxMenuItem *item = node->GetData(); - if ( item->IsSubMenu() ) - { - int rc = item->GetSubMenu()->FindItem(label); - if ( rc != wxNOT_FOUND ) - return rc; - } - - // we execute this code for submenus as well to alllow finding them by - // name just like the ordinary items - if ( !item->IsSeparator() ) - { - if ( item->GetLabel() == label ) - return item->GetId(); - } - } - - return wxNOT_FOUND; -} - -// recursive search for item by id -wxMenuItem *wxMenuBase::FindItem(int itemId, wxMenu **itemMenu) const -{ - if ( itemMenu ) - *itemMenu = NULL; - - wxMenuItem *item = NULL; - for ( wxMenuItemList::compatibility_iterator node = m_items.GetFirst(); - node && !item; - node = node->GetNext() ) - { - item = node->GetData(); - - if ( item->GetId() == itemId ) - { - if ( itemMenu ) - *itemMenu = (wxMenu *)this; - } - else if ( item->IsSubMenu() ) - { - item = item->GetSubMenu()->FindItem(itemId, itemMenu); - } - else - { - // don't exit the loop - item = NULL; - } - } - - return item; -} - -// non recursive search -wxMenuItem *wxMenuBase::FindChildItem(int id, size_t *ppos) const -{ - wxMenuItem *item = (wxMenuItem *)NULL; - wxMenuItemList::compatibility_iterator node = GetMenuItems().GetFirst(); - - size_t pos; - for ( pos = 0; node; pos++ ) - { - if ( node->GetData()->GetId() == id ) - { - item = node->GetData(); - - break; - } - - node = node->GetNext(); - } - - if ( ppos ) - { - *ppos = item ? pos : (size_t)wxNOT_FOUND; - } - - return item; -} - -// find by position -wxMenuItem* wxMenuBase::FindItemByPosition(size_t position) const -{ - wxCHECK_MSG( position < m_items.GetCount(), NULL, - _T("wxMenu::FindItemByPosition(): invalid menu index") ); - - return m_items.Item( position )->GetData(); -} - -// ---------------------------------------------------------------------------- -// wxMenu helpers used by derived classes -// ---------------------------------------------------------------------------- - -// Update a menu and all submenus recursively. source is the object that has -// the update event handlers defined for it. If NULL, the menu or associated -// window will be used. -void wxMenuBase::UpdateUI(wxEvtHandler* source) -{ - if (GetInvokingWindow()) - { - // Don't update menus if the parent - // frame is about to get deleted - wxWindow *tlw = wxGetTopLevelParent( GetInvokingWindow() ); - if (tlw && wxPendingDelete.Member(tlw)) - return; - } - - if ( !source && GetInvokingWindow() ) - source = GetInvokingWindow()->GetEventHandler(); - if ( !source ) - source = GetEventHandler(); - if ( !source ) - source = this; - - wxMenuItemList::compatibility_iterator node = GetMenuItems().GetFirst(); - while ( node ) - { - wxMenuItem* item = node->GetData(); - if ( !item->IsSeparator() ) - { - wxWindowID id = item->GetId(); - wxUpdateUIEvent event(id); - event.SetEventObject( source ); - - if ( source->ProcessEvent(event) ) - { - // if anything changed, update the changed attribute - if (event.GetSetText()) - SetLabel(id, event.GetText()); - if (event.GetSetChecked()) - Check(id, event.GetChecked()); - if (event.GetSetEnabled()) - Enable(id, event.GetEnabled()); - } - - // recurse to the submenus - if ( item->GetSubMenu() ) - item->GetSubMenu()->UpdateUI(source); - } - //else: item is a separator (which doesn't process update UI events) - - node = node->GetNext(); - } -} - -bool wxMenuBase::SendEvent(int id, int checked) -{ - wxCommandEvent event(wxEVT_COMMAND_MENU_SELECTED, id); - event.SetEventObject(this); - event.SetInt(checked); - - bool processed = false; - - // Try the menu's event handler - // if ( !processed ) - { - wxEvtHandler *handler = GetEventHandler(); - if ( handler ) - processed = handler->ProcessEvent(event); - } - - // Try the window the menu was popped up from (and up through the - // hierarchy) - if ( !processed ) - { - const wxMenuBase *menu = this; - while ( menu ) - { - wxWindow *win = menu->GetInvokingWindow(); - if ( win ) - { - processed = win->GetEventHandler()->ProcessEvent(event); - break; - } - - menu = menu->GetParent(); - } - } - - return processed; -} - -// ---------------------------------------------------------------------------- -// wxMenu attaching/detaching to/from menu bar -// ---------------------------------------------------------------------------- - -wxMenuBar* wxMenuBase::GetMenuBar() const -{ - if(GetParent()) - return GetParent()->GetMenuBar(); - return m_menuBar; -} - -void wxMenuBase::Attach(wxMenuBarBase *menubar) -{ - // use Detach() instead! - wxASSERT_MSG( menubar, _T("menu can't be attached to NULL menubar") ); - - // use IsAttached() to prevent this from happening - wxASSERT_MSG( !m_menuBar, _T("attaching menu twice?") ); - - m_menuBar = (wxMenuBar *)menubar; -} - -void wxMenuBase::Detach() -{ - // use IsAttached() to prevent this from happening - wxASSERT_MSG( m_menuBar, _T("detaching unattached menu?") ); - - m_menuBar = NULL; -} - -// ---------------------------------------------------------------------------- -// wxMenu functions forwarded to wxMenuItem -// ---------------------------------------------------------------------------- - -void wxMenuBase::Enable( int id, bool enable ) -{ - wxMenuItem *item = FindItem(id); - - wxCHECK_RET( item, wxT("wxMenu::Enable: no such item") ); - - item->Enable(enable); -} - -bool wxMenuBase::IsEnabled( int id ) const -{ - wxMenuItem *item = FindItem(id); - - wxCHECK_MSG( item, false, wxT("wxMenu::IsEnabled: no such item") ); - - return item->IsEnabled(); -} - -void wxMenuBase::Check( int id, bool enable ) -{ - wxMenuItem *item = FindItem(id); - - wxCHECK_RET( item, wxT("wxMenu::Check: no such item") ); - - item->Check(enable); -} - -bool wxMenuBase::IsChecked( int id ) const -{ - wxMenuItem *item = FindItem(id); - - wxCHECK_MSG( item, false, wxT("wxMenu::IsChecked: no such item") ); - - return item->IsChecked(); -} - -void wxMenuBase::SetLabel( int id, const wxString &label ) -{ - wxMenuItem *item = FindItem(id); - - wxCHECK_RET( item, wxT("wxMenu::SetLabel: no such item") ); - - item->SetText(label); -} - -wxString wxMenuBase::GetLabel( int id ) const -{ - wxMenuItem *item = FindItem(id); - - wxCHECK_MSG( item, wxEmptyString, wxT("wxMenu::GetLabel: no such item") ); - - return item->GetText(); -} - -void wxMenuBase::SetHelpString( int id, const wxString& helpString ) -{ - wxMenuItem *item = FindItem(id); - - wxCHECK_RET( item, wxT("wxMenu::SetHelpString: no such item") ); - - item->SetHelp( helpString ); -} - -wxString wxMenuBase::GetHelpString( int id ) const -{ - wxMenuItem *item = FindItem(id); - - wxCHECK_MSG( item, wxEmptyString, wxT("wxMenu::GetHelpString: no such item") ); - - return item->GetHelp(); -} - -// ---------------------------------------------------------------------------- -// wxMenuBarBase ctor and dtor -// ---------------------------------------------------------------------------- - -wxMenuBarBase::wxMenuBarBase() -{ - // not attached yet - m_menuBarFrame = NULL; -} - -wxMenuBarBase::~wxMenuBarBase() -{ - WX_CLEAR_LIST(wxMenuList, m_menus); -} - -// ---------------------------------------------------------------------------- -// wxMenuBar item access: the base class versions manage m_menus list, the -// derived class should reflect the changes in the real menubar -// ---------------------------------------------------------------------------- - -wxMenu *wxMenuBarBase::GetMenu(size_t pos) const -{ - wxMenuList::compatibility_iterator node = m_menus.Item(pos); - wxCHECK_MSG( node, NULL, wxT("bad index in wxMenuBar::GetMenu()") ); - - return node->GetData(); -} - -bool wxMenuBarBase::Append(wxMenu *menu, const wxString& WXUNUSED(title)) -{ - wxCHECK_MSG( menu, false, wxT("can't append NULL menu") ); - - m_menus.Append(menu); - menu->Attach(this); - - return true; -} - -bool wxMenuBarBase::Insert(size_t pos, wxMenu *menu, - const wxString& title) -{ - if ( pos == m_menus.GetCount() ) - { - return wxMenuBarBase::Append(menu, title); - } - else // not at the end - { - wxCHECK_MSG( menu, false, wxT("can't insert NULL menu") ); - - wxMenuList::compatibility_iterator node = m_menus.Item(pos); - wxCHECK_MSG( node, false, wxT("bad index in wxMenuBar::Insert()") ); - - m_menus.Insert(node, menu); - menu->Attach(this); - - return true; - } -} - -wxMenu *wxMenuBarBase::Replace(size_t pos, wxMenu *menu, - const wxString& WXUNUSED(title)) -{ - wxCHECK_MSG( menu, NULL, wxT("can't insert NULL menu") ); - - wxMenuList::compatibility_iterator node = m_menus.Item(pos); - wxCHECK_MSG( node, NULL, wxT("bad index in wxMenuBar::Replace()") ); - - wxMenu *menuOld = node->GetData(); - node->SetData(menu); - - menu->Attach(this); - menuOld->Detach(); - - return menuOld; -} - -wxMenu *wxMenuBarBase::Remove(size_t pos) -{ - wxMenuList::compatibility_iterator node = m_menus.Item(pos); - wxCHECK_MSG( node, NULL, wxT("bad index in wxMenuBar::Remove()") ); - - wxMenu *menu = node->GetData(); - m_menus.Erase(node); - menu->Detach(); - - return menu; -} - -int wxMenuBarBase::FindMenu(const wxString& title) const -{ - wxString label = wxMenuItem::GetLabelFromText(title); - - size_t count = GetMenuCount(); - for ( size_t i = 0; i < count; i++ ) - { - wxString title2 = GetLabelTop(i); - if ( (title2 == title) || - (wxMenuItem::GetLabelFromText(title2) == label) ) - { - // found - return (int)i; - } - } - - return wxNOT_FOUND; - -} - -// ---------------------------------------------------------------------------- -// wxMenuBar attaching/detaching to/from the frame -// ---------------------------------------------------------------------------- - -void wxMenuBarBase::Attach(wxFrame *frame) -{ - wxASSERT_MSG( !IsAttached(), wxT("menubar already attached!") ); - - m_menuBarFrame = frame; -} - -void wxMenuBarBase::Detach() -{ - wxASSERT_MSG( IsAttached(), wxT("detaching unattached menubar") ); - - m_menuBarFrame = NULL; -} - -// ---------------------------------------------------------------------------- -// wxMenuBar searching for items -// ---------------------------------------------------------------------------- - -wxMenuItem *wxMenuBarBase::FindItem(int id, wxMenu **menu) const -{ - if ( menu ) - *menu = NULL; - - wxMenuItem *item = NULL; - size_t count = GetMenuCount(), i; - wxMenuList::const_iterator it; - for ( i = 0, it = m_menus.begin(); !item && (i < count); i++, it++ ) - { - item = (*it)->FindItem(id, menu); - } - - return item; -} - -int wxMenuBarBase::FindMenuItem(const wxString& menu, const wxString& item) const -{ - wxString label = wxMenuItem::GetLabelFromText(menu); - - int i = 0; - wxMenuList::compatibility_iterator node; - for ( node = m_menus.GetFirst(); node; node = node->GetNext(), i++ ) - { - if ( label == wxMenuItem::GetLabelFromText(GetLabelTop(i)) ) - return node->GetData()->FindItem(item); - } - - return wxNOT_FOUND; -} - -// --------------------------------------------------------------------------- -// wxMenuBar functions forwarded to wxMenuItem -// --------------------------------------------------------------------------- - -void wxMenuBarBase::Enable(int id, bool enable) -{ - wxMenuItem *item = FindItem(id); - - wxCHECK_RET( item, wxT("attempt to enable an item which doesn't exist") ); - - item->Enable(enable); -} - -void wxMenuBarBase::Check(int id, bool check) -{ - wxMenuItem *item = FindItem(id); - - wxCHECK_RET( item, wxT("attempt to check an item which doesn't exist") ); - wxCHECK_RET( item->IsCheckable(), wxT("attempt to check an uncheckable item") ); - - item->Check(check); -} - -bool wxMenuBarBase::IsChecked(int id) const -{ - wxMenuItem *item = FindItem(id); - - wxCHECK_MSG( item, false, wxT("wxMenuBar::IsChecked(): no such item") ); - - return item->IsChecked(); -} - -bool wxMenuBarBase::IsEnabled(int id) const -{ - wxMenuItem *item = FindItem(id); - - wxCHECK_MSG( item, false, wxT("wxMenuBar::IsEnabled(): no such item") ); - - return item->IsEnabled(); -} - -void wxMenuBarBase::SetLabel(int id, const wxString& label) -{ - wxMenuItem *item = FindItem(id); - - wxCHECK_RET( item, wxT("wxMenuBar::SetLabel(): no such item") ); - - item->SetText(label); -} - -wxString wxMenuBarBase::GetLabel(int id) const -{ - wxMenuItem *item = FindItem(id); - - wxCHECK_MSG( item, wxEmptyString, - wxT("wxMenuBar::GetLabel(): no such item") ); - - return item->GetText(); -} - -void wxMenuBarBase::SetHelpString(int id, const wxString& helpString) -{ - wxMenuItem *item = FindItem(id); - - wxCHECK_RET( item, wxT("wxMenuBar::SetHelpString(): no such item") ); - - item->SetHelp(helpString); -} - -wxString wxMenuBarBase::GetHelpString(int id) const -{ - wxMenuItem *item = FindItem(id); - - wxCHECK_MSG( item, wxEmptyString, - wxT("wxMenuBar::GetHelpString(): no such item") ); - - return item->GetHelp(); -} - -void wxMenuBarBase::UpdateMenus( void ) -{ - wxEvtHandler* source; - wxMenu* menu; - int nCount = GetMenuCount(); - for (int n = 0; n < nCount; n++) - { - menu = GetMenu( n ); - if (menu != NULL) - { - source = menu->GetEventHandler(); - if (source != NULL) - menu->UpdateUI( source ); - } - } -} - -// Get the text only, from the label -wxString wxMenuBarBase::GetMenuLabelText(size_t pos) const -{ - return wxMenuItem::GetLabelText(((wxMenuBar*)this)->GetMenuLabel(pos)); -} - - -#endif // wxUSE_MENUS +/////////////////////////////////////////////////////////////////////////////// +// Name: src/common/menucmn.cpp +// Purpose: wxMenu and wxMenuBar methods common to all ports +// Author: Vadim Zeitlin +// Modified by: +// Created: 26.10.99 +// RCS-ID: $Id: menucmn.cpp 51361 2008-01-24 18:12:55Z PC $ +// Copyright: (c) wxWidgets team +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_MENUS + +#include + +#ifndef WX_PRECOMP + #include "wx/intl.h" + #include "wx/log.h" + #include "wx/menu.h" +#endif + +#include "wx/stockitem.h" + +// ---------------------------------------------------------------------------- +// template lists +// ---------------------------------------------------------------------------- + +#include "wx/listimpl.cpp" + +WX_DEFINE_LIST(wxMenuList) +WX_DEFINE_LIST(wxMenuItemList) + +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// wxAcceleratorEntry +// ---------------------------------------------------------------------------- + + +#if wxUSE_ACCEL + +static const struct wxKeyName +{ + wxKeyCode code; + const wxChar *name; +} wxKeyNames[] = +{ + { WXK_DELETE, wxTRANSLATE("DEL") }, + { WXK_DELETE, wxTRANSLATE("DELETE") }, + { WXK_BACK, wxTRANSLATE("BACK") }, + { WXK_INSERT, wxTRANSLATE("INS") }, + { WXK_INSERT, wxTRANSLATE("INSERT") }, + { WXK_RETURN, wxTRANSLATE("ENTER") }, + { WXK_RETURN, wxTRANSLATE("RETURN") }, + { WXK_PAGEUP, wxTRANSLATE("PGUP") }, + { WXK_PAGEDOWN, wxTRANSLATE("PGDN") }, + { WXK_LEFT, wxTRANSLATE("LEFT") }, + { WXK_RIGHT, wxTRANSLATE("RIGHT") }, + { WXK_UP, wxTRANSLATE("UP") }, + { WXK_DOWN, wxTRANSLATE("DOWN") }, + { WXK_HOME, wxTRANSLATE("HOME") }, + { WXK_END, wxTRANSLATE("END") }, + { WXK_SPACE, wxTRANSLATE("SPACE") }, + { WXK_TAB, wxTRANSLATE("TAB") }, + { WXK_ESCAPE, wxTRANSLATE("ESC") }, + { WXK_ESCAPE, wxTRANSLATE("ESCAPE") }, + { WXK_CANCEL, wxTRANSLATE("CANCEL") }, + { WXK_CLEAR, wxTRANSLATE("CLEAR") }, + { WXK_MENU, wxTRANSLATE("MENU") }, + { WXK_PAUSE, wxTRANSLATE("PAUSE") }, + { WXK_CAPITAL, wxTRANSLATE("CAPITAL") }, + { WXK_SELECT, wxTRANSLATE("SELECT") }, + { WXK_PRINT, wxTRANSLATE("PRINT") }, + { WXK_EXECUTE, wxTRANSLATE("EXECUTE") }, + { WXK_SNAPSHOT, wxTRANSLATE("SNAPSHOT") }, + { WXK_HELP, wxTRANSLATE("HELP") }, + { WXK_ADD, wxTRANSLATE("ADD") }, + { WXK_SEPARATOR, wxTRANSLATE("SEPARATOR") }, + { WXK_SUBTRACT, wxTRANSLATE("SUBTRACT") }, + { WXK_DECIMAL, wxTRANSLATE("DECIMAL") }, + { WXK_DIVIDE, wxTRANSLATE("DIVIDE") }, + { WXK_NUMLOCK, wxTRANSLATE("NUM_LOCK") }, + { WXK_SCROLL, wxTRANSLATE("SCROLL_LOCK") }, + { WXK_PAGEUP, wxTRANSLATE("PAGEUP") }, + { WXK_PAGEDOWN, wxTRANSLATE("PAGEDOWN") }, + { WXK_NUMPAD_SPACE, wxTRANSLATE("KP_SPACE") }, + { WXK_NUMPAD_TAB, wxTRANSLATE("KP_TAB") }, + { WXK_NUMPAD_ENTER, wxTRANSLATE("KP_ENTER") }, + { WXK_NUMPAD_HOME, wxTRANSLATE("KP_HOME") }, + { WXK_NUMPAD_LEFT, wxTRANSLATE("KP_LEFT") }, + { WXK_NUMPAD_UP, wxTRANSLATE("KP_UP") }, + { WXK_NUMPAD_RIGHT, wxTRANSLATE("KP_RIGHT") }, + { WXK_NUMPAD_DOWN, wxTRANSLATE("KP_DOWN") }, + { WXK_NUMPAD_PAGEUP, wxTRANSLATE("KP_PRIOR") }, + { WXK_NUMPAD_PAGEUP, wxTRANSLATE("KP_PAGEUP") }, + { WXK_NUMPAD_PAGEDOWN, wxTRANSLATE("KP_NEXT") }, + { WXK_NUMPAD_PAGEDOWN, wxTRANSLATE("KP_PAGEDOWN") }, + { WXK_NUMPAD_END, wxTRANSLATE("KP_END") }, + { WXK_NUMPAD_BEGIN, wxTRANSLATE("KP_BEGIN") }, + { WXK_NUMPAD_INSERT, wxTRANSLATE("KP_INSERT") }, + { WXK_NUMPAD_DELETE, wxTRANSLATE("KP_DELETE") }, + { WXK_NUMPAD_EQUAL, wxTRANSLATE("KP_EQUAL") }, + { WXK_NUMPAD_MULTIPLY, wxTRANSLATE("KP_MULTIPLY") }, + { WXK_NUMPAD_ADD, wxTRANSLATE("KP_ADD") }, + { WXK_NUMPAD_SEPARATOR, wxTRANSLATE("KP_SEPARATOR") }, + { WXK_NUMPAD_SUBTRACT, wxTRANSLATE("KP_SUBTRACT") }, + { WXK_NUMPAD_DECIMAL, wxTRANSLATE("KP_DECIMAL") }, + { WXK_NUMPAD_DIVIDE, wxTRANSLATE("KP_DIVIDE") }, + { WXK_WINDOWS_LEFT, wxTRANSLATE("WINDOWS_LEFT") }, + { WXK_WINDOWS_RIGHT, wxTRANSLATE("WINDOWS_RIGHT") }, + { WXK_WINDOWS_MENU, wxTRANSLATE("WINDOWS_MENU") }, + { WXK_COMMAND, wxTRANSLATE("COMMAND") }, +}; + +// return true if the 2 strings refer to the same accel +// +// as accels can be either translated or not, check for both possibilities and +// also compare case-insensitively as the key names case doesn't count +static inline bool CompareAccelString(const wxString& str, const wxChar *accel) +{ + return str.CmpNoCase(accel) == 0 +#if wxUSE_INTL + || str.CmpNoCase(wxGetTranslation(accel)) == 0 +#endif + ; +} + +// return prefixCode+number if the string is of the form "" and +// 0 if it isn't +// +// first and last parameter specify the valid domain for "number" part +static int + IsNumberedAccelKey(const wxString& str, + const wxChar *prefix, + wxKeyCode prefixCode, + unsigned first, + unsigned last) +{ + const size_t lenPrefix = wxStrlen(prefix); + if ( !CompareAccelString(str.Left(lenPrefix), prefix) ) + return 0; + + unsigned long num; + if ( !str.Mid(lenPrefix).ToULong(&num) ) + return 0; + + if ( num < first || num > last ) + { + // this must be a mistake, chances that this is a valid name of another + // key are vanishingly small + wxLogDebug(_T("Invalid key string \"%s\""), str.c_str()); + return 0; + } + + return prefixCode + num - first; +} + +/* static */ +bool +wxAcceleratorEntry::ParseAccel(const wxString& text, int *flagsOut, int *keyOut) +{ + // the parser won't like trailing spaces + wxString label = text; + label.Trim(true); // the initial \t must be preserved so don't strip leading whitespaces + + // check for accelerators: they are given after '\t' + int posTab = label.Find(wxT('\t')); + if ( posTab == wxNOT_FOUND ) + { + return false; + } + + // parse the accelerator string + int accelFlags = wxACCEL_NORMAL; + wxString current; + for ( size_t n = (size_t)posTab + 1; n < label.length(); n++ ) + { + if ( (label[n] == '+') || (label[n] == '-') ) + { + if ( CompareAccelString(current, wxTRANSLATE("ctrl")) ) + accelFlags |= wxACCEL_CTRL; + else if ( CompareAccelString(current, wxTRANSLATE("alt")) ) + accelFlags |= wxACCEL_ALT; + else if ( CompareAccelString(current, wxTRANSLATE("shift")) ) + accelFlags |= wxACCEL_SHIFT; + else // not a recognized modifier name + { + // we may have "Ctrl-+", for example, but we still want to + // catch typos like "Crtl-A" so only give the warning if we + // have something before the current '+' or '-', else take + // it as a literal symbol + if ( current.empty() ) + { + current += label[n]; + + // skip clearing it below + continue; + } + else + { + wxLogDebug(wxT("Unknown accel modifier: '%s'"), + current.c_str()); + } + } + + current.clear(); + } + else // not special character + { + current += (wxChar) wxTolower(label[n]); + } + } + + int keyCode; + const size_t len = current.length(); + switch ( len ) + { + case 0: + wxLogDebug(wxT("No accel key found, accel string ignored.")); + return false; + + case 1: + // it's just a letter + keyCode = current[0U]; + + // if the key is used with any modifiers, make it an uppercase one + // because Ctrl-A and Ctrl-a are the same; but keep it as is if it's + // used alone as 'a' and 'A' are different + if ( accelFlags != wxACCEL_NORMAL ) + keyCode = wxToupper(keyCode); + break; + + default: + keyCode = IsNumberedAccelKey(current, wxTRANSLATE("F"), + WXK_F1, 1, 12); + if ( !keyCode ) + { + for ( size_t n = 0; n < WXSIZEOF(wxKeyNames); n++ ) + { + const wxKeyName& kn = wxKeyNames[n]; + if ( CompareAccelString(current, kn.name) ) + { + keyCode = kn.code; + break; + } + } + } + + if ( !keyCode ) + keyCode = IsNumberedAccelKey(current, wxTRANSLATE("KP_"), + WXK_NUMPAD0, 0, 9); + if ( !keyCode ) + keyCode = IsNumberedAccelKey(current, wxTRANSLATE("SPECIAL"), + WXK_SPECIAL1, 1, 20); + + if ( !keyCode ) + { + wxLogDebug(wxT("Unrecognized accel key '%s', accel string ignored."), + current.c_str()); + return false; + } + } + + + wxASSERT_MSG( keyCode, _T("logic error: should have key code here") ); + + if ( flagsOut ) + *flagsOut = accelFlags; + if ( keyOut ) + *keyOut = keyCode; + + return true; +} + +/* static */ +wxAcceleratorEntry *wxAcceleratorEntry::Create(const wxString& str) +{ + int flags, + keyCode; + if ( !ParseAccel(str, &flags, &keyCode) ) + return NULL; + + return new wxAcceleratorEntry(flags, keyCode); +} + +bool wxAcceleratorEntry::FromString(const wxString& str) +{ + return ParseAccel(str, &m_flags, &m_keyCode); +} + +wxString wxAcceleratorEntry::ToString() const +{ + wxString text; + + int flags = GetFlags(); + if ( flags & wxACCEL_ALT ) + text += _("Alt-"); + if ( flags & wxACCEL_CTRL ) + text += _("Ctrl-"); + if ( flags & wxACCEL_SHIFT ) + text += _("Shift-"); + + const int code = GetKeyCode(); + + if ( code >= WXK_F1 && code <= WXK_F12 ) + text << _("F") << code - WXK_F1 + 1; + else if ( code >= WXK_NUMPAD0 && code <= WXK_NUMPAD9 ) + text << _("KP_") << code - WXK_NUMPAD0; + else if ( code >= WXK_SPECIAL1 && code <= WXK_SPECIAL20 ) + text << _("SPECIAL") << code - WXK_SPECIAL1 + 1; + else // check the named keys + { + size_t n; + for ( n = 0; n < WXSIZEOF(wxKeyNames); n++ ) + { + const wxKeyName& kn = wxKeyNames[n]; + if ( code == kn.code ) + { + text << wxGetTranslation(kn.name); + break; + } + } + + if ( n == WXSIZEOF(wxKeyNames) ) + { + // must be a simple key + if ( +#if !wxUSE_UNICODE + isascii(code) && +#endif // ANSI + wxIsalnum(code) ) + { + text << (wxChar)code; + } + else + { + wxFAIL_MSG( wxT("unknown keyboard accelerator code") ); + } + } + } + + return text; +} + +wxAcceleratorEntry *wxGetAccelFromString(const wxString& label) +{ + return wxAcceleratorEntry::Create(label); +} + +#endif // wxUSE_ACCEL + + +// ---------------------------------------------------------------------------- +// wxMenuItem +// ---------------------------------------------------------------------------- + +wxMenuItemBase::wxMenuItemBase(wxMenu *parentMenu, + int id, + const wxString& text, + const wxString& help, + wxItemKind kind, + wxMenu *subMenu) +{ + wxASSERT_MSG( parentMenu != NULL, wxT("menuitem should have a menu") ); + + m_parentMenu = parentMenu; + m_subMenu = subMenu; + m_isEnabled = true; + m_isChecked = false; + m_id = id; + m_kind = kind; + if (m_id == wxID_ANY) + m_id = wxNewId(); + if (m_id == wxID_SEPARATOR) + m_kind = wxITEM_SEPARATOR; + + SetText(text); + SetHelp(help); +} + +wxMenuItemBase::~wxMenuItemBase() +{ + delete m_subMenu; +} + +#if wxUSE_ACCEL + +wxAcceleratorEntry *wxMenuItemBase::GetAccel() const +{ + return wxAcceleratorEntry::Create(GetText()); +} + +void wxMenuItemBase::SetAccel(wxAcceleratorEntry *accel) +{ + wxString text = m_text.BeforeFirst(wxT('\t')); + if ( accel ) + { + text += wxT('\t'); + text += accel->ToString(); + } + + SetText(text); +} + +#endif // wxUSE_ACCEL + +void wxMenuItemBase::SetText(const wxString& str) +{ + m_text = str; + + if ( m_text.empty() && !IsSeparator() ) + { + wxASSERT_MSG( wxIsStockID(GetId()), + wxT("A non-stock menu item with an empty label?") ); + m_text = wxGetStockLabel(GetId(), wxSTOCK_WITH_ACCELERATOR | + wxSTOCK_WITH_MNEMONIC); + } +} + +void wxMenuItemBase::SetHelp(const wxString& str) +{ + m_help = str; + + if ( m_help.empty() && !IsSeparator() && wxIsStockID(GetId()) ) + { + // get a stock help string + m_help = wxGetStockHelpString(GetId()); + } +} + +wxString wxMenuItemBase::GetLabelText(const wxString& label) +{ + return GetLabelFromText(label); +} + +bool wxMenuBase::ms_locked = true; + +// ---------------------------------------------------------------------------- +// wxMenu ctor and dtor +// ---------------------------------------------------------------------------- + +void wxMenuBase::Init(long style) +{ + m_menuBar = (wxMenuBar *)NULL; + m_menuParent = (wxMenu *)NULL; + + m_invokingWindow = (wxWindow *)NULL; + m_style = style; + m_clientData = (void *)NULL; + m_eventHandler = this; +} + +wxMenuBase::~wxMenuBase() +{ + WX_CLEAR_LIST(wxMenuItemList, m_items); +} + +// ---------------------------------------------------------------------------- +// wxMenu item adding/removing +// ---------------------------------------------------------------------------- + +void wxMenuBase::AddSubMenu(wxMenu *submenu) +{ + wxCHECK_RET( submenu, _T("can't add a NULL submenu") ); + + submenu->SetParent((wxMenu *)this); +} + +wxMenuItem* wxMenuBase::DoAppend(wxMenuItem *item) +{ + wxCHECK_MSG( item, NULL, wxT("invalid item in wxMenu::Append()") ); + + m_items.Append(item); + item->SetMenu((wxMenu*)this); + if ( item->IsSubMenu() ) + { + AddSubMenu(item->GetSubMenu()); + } + + return item; +} + +wxMenuItem* wxMenuBase::Insert(size_t pos, wxMenuItem *item) +{ + wxCHECK_MSG( item, NULL, wxT("invalid item in wxMenu::Insert") ); + + if ( pos == GetMenuItemCount() ) + { + return DoAppend(item); + } + else + { + wxCHECK_MSG( pos < GetMenuItemCount(), NULL, + wxT("invalid index in wxMenu::Insert") ); + + return DoInsert(pos, item); + } +} + +wxMenuItem* wxMenuBase::DoInsert(size_t pos, wxMenuItem *item) +{ + wxCHECK_MSG( item, NULL, wxT("invalid item in wxMenu::Insert()") ); + + wxMenuItemList::compatibility_iterator node = m_items.Item(pos); + wxCHECK_MSG( node, NULL, wxT("invalid index in wxMenu::Insert()") ); + + m_items.Insert(node, item); + item->SetMenu((wxMenu*)this); + if ( item->IsSubMenu() ) + { + AddSubMenu(item->GetSubMenu()); + } + + return item; +} + +wxMenuItem *wxMenuBase::Remove(wxMenuItem *item) +{ + wxCHECK_MSG( item, NULL, wxT("invalid item in wxMenu::Remove") ); + + return DoRemove(item); +} + +wxMenuItem *wxMenuBase::DoRemove(wxMenuItem *item) +{ + wxMenuItemList::compatibility_iterator node = m_items.Find(item); + + // if we get here, the item is valid or one of Remove() functions is broken + wxCHECK_MSG( node, NULL, wxT("bug in wxMenu::Remove logic") ); + + // we detach the item, but we do delete the list node (i.e. don't call + // DetachNode() here!) + m_items.Erase(node); + + // item isn't attached to anything any more + item->SetMenu((wxMenu *)NULL); + wxMenu *submenu = item->GetSubMenu(); + if ( submenu ) + { + submenu->SetParent((wxMenu *)NULL); + if ( submenu->IsAttached() ) + submenu->Detach(); + } + + return item; +} + +bool wxMenuBase::Delete(wxMenuItem *item) +{ + wxCHECK_MSG( item, false, wxT("invalid item in wxMenu::Delete") ); + + return DoDelete(item); +} + +bool wxMenuBase::DoDelete(wxMenuItem *item) +{ + wxMenuItem *item2 = DoRemove(item); + wxCHECK_MSG( item2, false, wxT("failed to delete menu item") ); + + // don't delete the submenu + item2->SetSubMenu((wxMenu *)NULL); + + delete item2; + + return true; +} + +bool wxMenuBase::Destroy(wxMenuItem *item) +{ + wxCHECK_MSG( item, false, wxT("invalid item in wxMenu::Destroy") ); + + return DoDestroy(item); +} + +bool wxMenuBase::DoDestroy(wxMenuItem *item) +{ + wxMenuItem *item2 = DoRemove(item); + wxCHECK_MSG( item2, false, wxT("failed to delete menu item") ); + + delete item2; + + return true; +} + +// ---------------------------------------------------------------------------- +// wxMenu searching for items +// ---------------------------------------------------------------------------- + +// Finds the item id matching the given string, wxNOT_FOUND if not found. +int wxMenuBase::FindItem(const wxString& text) const +{ + wxString label = wxMenuItem::GetLabelFromText(text); + for ( wxMenuItemList::compatibility_iterator node = m_items.GetFirst(); + node; + node = node->GetNext() ) + { + wxMenuItem *item = node->GetData(); + if ( item->IsSubMenu() ) + { + int rc = item->GetSubMenu()->FindItem(label); + if ( rc != wxNOT_FOUND ) + return rc; + } + + // we execute this code for submenus as well to alllow finding them by + // name just like the ordinary items + if ( !item->IsSeparator() ) + { + if ( item->GetLabel() == label ) + return item->GetId(); + } + } + + return wxNOT_FOUND; +} + +// recursive search for item by id +wxMenuItem *wxMenuBase::FindItem(int itemId, wxMenu **itemMenu) const +{ + if ( itemMenu ) + *itemMenu = NULL; + + wxMenuItem *item = NULL; + for ( wxMenuItemList::compatibility_iterator node = m_items.GetFirst(); + node && !item; + node = node->GetNext() ) + { + item = node->GetData(); + + if ( item->GetId() == itemId ) + { + if ( itemMenu ) + *itemMenu = (wxMenu *)this; + } + else if ( item->IsSubMenu() ) + { + item = item->GetSubMenu()->FindItem(itemId, itemMenu); + } + else + { + // don't exit the loop + item = NULL; + } + } + + return item; +} + +// non recursive search +wxMenuItem *wxMenuBase::FindChildItem(int id, size_t *ppos) const +{ + wxMenuItem *item = (wxMenuItem *)NULL; + wxMenuItemList::compatibility_iterator node = GetMenuItems().GetFirst(); + + size_t pos; + for ( pos = 0; node; pos++ ) + { + if ( node->GetData()->GetId() == id ) + { + item = node->GetData(); + + break; + } + + node = node->GetNext(); + } + + if ( ppos ) + { + *ppos = item ? pos : (size_t)wxNOT_FOUND; + } + + return item; +} + +// find by position +wxMenuItem* wxMenuBase::FindItemByPosition(size_t position) const +{ + wxCHECK_MSG( position < m_items.GetCount(), NULL, + _T("wxMenu::FindItemByPosition(): invalid menu index") ); + + return m_items.Item( position )->GetData(); +} + +// ---------------------------------------------------------------------------- +// wxMenu helpers used by derived classes +// ---------------------------------------------------------------------------- + +// Update a menu and all submenus recursively. source is the object that has +// the update event handlers defined for it. If NULL, the menu or associated +// window will be used. +void wxMenuBase::UpdateUI(wxEvtHandler* source) +{ + if (GetInvokingWindow()) + { + // Don't update menus if the parent + // frame is about to get deleted + wxWindow *tlw = wxGetTopLevelParent( GetInvokingWindow() ); + if (tlw && wxPendingDelete.Member(tlw)) + return; + } + + if ( !source && GetInvokingWindow() ) + source = GetInvokingWindow()->GetEventHandler(); + if ( !source ) + source = GetEventHandler(); + if ( !source ) + source = this; + + wxMenuItemList::compatibility_iterator node = GetMenuItems().GetFirst(); + while ( node ) + { + wxMenuItem* item = node->GetData(); + if ( !item->IsSeparator() ) + { + wxWindowID id = item->GetId(); + wxUpdateUIEvent event(id); + event.SetEventObject( source ); + + if ( source->ProcessEvent(event) ) + { + // if anything changed, update the changed attribute + if (event.GetSetText()) + SetLabel(id, event.GetText()); + if (event.GetSetChecked()) + Check(id, event.GetChecked()); + if (event.GetSetEnabled()) + Enable(id, event.GetEnabled()); + } + + // recurse to the submenus + if ( item->GetSubMenu() ) + item->GetSubMenu()->UpdateUI(source); + } + //else: item is a separator (which doesn't process update UI events) + + node = node->GetNext(); + } +} + +bool wxMenuBase::SendEvent(int id, int checked) +{ + wxCommandEvent event(wxEVT_COMMAND_MENU_SELECTED, id); + event.SetEventObject(this); + event.SetInt(checked); + + bool processed = false; + + // Try the menu's event handler + // if ( !processed ) + { + wxEvtHandler *handler = GetEventHandler(); + if ( handler ) + processed = handler->ProcessEvent(event); + } + + // Try the window the menu was popped up from (and up through the + // hierarchy) + if ( !processed ) + { + const wxMenuBase *menu = this; + while ( menu ) + { + wxWindow *win = menu->GetInvokingWindow(); + if ( win ) + { + processed = win->GetEventHandler()->ProcessEvent(event); + break; + } + + menu = menu->GetParent(); + } + } + + return processed; +} + +// ---------------------------------------------------------------------------- +// wxMenu attaching/detaching to/from menu bar +// ---------------------------------------------------------------------------- + +wxMenuBar* wxMenuBase::GetMenuBar() const +{ + if(GetParent()) + return GetParent()->GetMenuBar(); + return m_menuBar; +} + +void wxMenuBase::Attach(wxMenuBarBase *menubar) +{ + // use Detach() instead! + wxASSERT_MSG( menubar, _T("menu can't be attached to NULL menubar") ); + + // use IsAttached() to prevent this from happening + wxASSERT_MSG( !m_menuBar, _T("attaching menu twice?") ); + + m_menuBar = (wxMenuBar *)menubar; +} + +void wxMenuBase::Detach() +{ + // use IsAttached() to prevent this from happening + wxASSERT_MSG( m_menuBar, _T("detaching unattached menu?") ); + + m_menuBar = NULL; +} + +// ---------------------------------------------------------------------------- +// wxMenu functions forwarded to wxMenuItem +// ---------------------------------------------------------------------------- + +void wxMenuBase::Enable( int id, bool enable ) +{ + wxMenuItem *item = FindItem(id); + + wxCHECK_RET( item, wxT("wxMenu::Enable: no such item") ); + + item->Enable(enable); +} + +bool wxMenuBase::IsEnabled( int id ) const +{ + wxMenuItem *item = FindItem(id); + + wxCHECK_MSG( item, false, wxT("wxMenu::IsEnabled: no such item") ); + + return item->IsEnabled(); +} + +void wxMenuBase::Check( int id, bool enable ) +{ + wxMenuItem *item = FindItem(id); + + wxCHECK_RET( item, wxT("wxMenu::Check: no such item") ); + + item->Check(enable); +} + +bool wxMenuBase::IsChecked( int id ) const +{ + wxMenuItem *item = FindItem(id); + + wxCHECK_MSG( item, false, wxT("wxMenu::IsChecked: no such item") ); + + return item->IsChecked(); +} + +void wxMenuBase::SetLabel( int id, const wxString &label ) +{ + wxMenuItem *item = FindItem(id); + + wxCHECK_RET( item, wxT("wxMenu::SetLabel: no such item") ); + + item->SetText(label); +} + +wxString wxMenuBase::GetLabel( int id ) const +{ + wxMenuItem *item = FindItem(id); + + wxCHECK_MSG( item, wxEmptyString, wxT("wxMenu::GetLabel: no such item") ); + + return item->GetText(); +} + +void wxMenuBase::SetHelpString( int id, const wxString& helpString ) +{ + wxMenuItem *item = FindItem(id); + + wxCHECK_RET( item, wxT("wxMenu::SetHelpString: no such item") ); + + item->SetHelp( helpString ); +} + +wxString wxMenuBase::GetHelpString( int id ) const +{ + wxMenuItem *item = FindItem(id); + + wxCHECK_MSG( item, wxEmptyString, wxT("wxMenu::GetHelpString: no such item") ); + + return item->GetHelp(); +} + +// ---------------------------------------------------------------------------- +// wxMenuBarBase ctor and dtor +// ---------------------------------------------------------------------------- + +wxMenuBarBase::wxMenuBarBase() +{ + // not attached yet + m_menuBarFrame = NULL; +} + +wxMenuBarBase::~wxMenuBarBase() +{ + WX_CLEAR_LIST(wxMenuList, m_menus); +} + +// ---------------------------------------------------------------------------- +// wxMenuBar item access: the base class versions manage m_menus list, the +// derived class should reflect the changes in the real menubar +// ---------------------------------------------------------------------------- + +wxMenu *wxMenuBarBase::GetMenu(size_t pos) const +{ + wxMenuList::compatibility_iterator node = m_menus.Item(pos); + wxCHECK_MSG( node, NULL, wxT("bad index in wxMenuBar::GetMenu()") ); + + return node->GetData(); +} + +bool wxMenuBarBase::Append(wxMenu *menu, const wxString& WXUNUSED(title)) +{ + wxCHECK_MSG( menu, false, wxT("can't append NULL menu") ); + + m_menus.Append(menu); + menu->Attach(this); + + return true; +} + +bool wxMenuBarBase::Insert(size_t pos, wxMenu *menu, + const wxString& title) +{ + if ( pos == m_menus.GetCount() ) + { + return wxMenuBarBase::Append(menu, title); + } + else // not at the end + { + wxCHECK_MSG( menu, false, wxT("can't insert NULL menu") ); + + wxMenuList::compatibility_iterator node = m_menus.Item(pos); + wxCHECK_MSG( node, false, wxT("bad index in wxMenuBar::Insert()") ); + + m_menus.Insert(node, menu); + menu->Attach(this); + + return true; + } +} + +wxMenu *wxMenuBarBase::Replace(size_t pos, wxMenu *menu, + const wxString& WXUNUSED(title)) +{ + wxCHECK_MSG( menu, NULL, wxT("can't insert NULL menu") ); + + wxMenuList::compatibility_iterator node = m_menus.Item(pos); + wxCHECK_MSG( node, NULL, wxT("bad index in wxMenuBar::Replace()") ); + + wxMenu *menuOld = node->GetData(); + node->SetData(menu); + + menu->Attach(this); + menuOld->Detach(); + + return menuOld; +} + +wxMenu *wxMenuBarBase::Remove(size_t pos) +{ + wxMenuList::compatibility_iterator node = m_menus.Item(pos); + wxCHECK_MSG( node, NULL, wxT("bad index in wxMenuBar::Remove()") ); + + wxMenu *menu = node->GetData(); + m_menus.Erase(node); + menu->Detach(); + + return menu; +} + +int wxMenuBarBase::FindMenu(const wxString& title) const +{ + wxString label = wxMenuItem::GetLabelFromText(title); + + size_t count = GetMenuCount(); + for ( size_t i = 0; i < count; i++ ) + { + wxString title2 = GetLabelTop(i); + if ( (title2 == title) || + (wxMenuItem::GetLabelFromText(title2) == label) ) + { + // found + return (int)i; + } + } + + return wxNOT_FOUND; + +} + +// ---------------------------------------------------------------------------- +// wxMenuBar attaching/detaching to/from the frame +// ---------------------------------------------------------------------------- + +void wxMenuBarBase::Attach(wxFrame *frame) +{ + wxASSERT_MSG( !IsAttached(), wxT("menubar already attached!") ); + + m_menuBarFrame = frame; +} + +void wxMenuBarBase::Detach() +{ + wxASSERT_MSG( IsAttached(), wxT("detaching unattached menubar") ); + + m_menuBarFrame = NULL; +} + +// ---------------------------------------------------------------------------- +// wxMenuBar searching for items +// ---------------------------------------------------------------------------- + +wxMenuItem *wxMenuBarBase::FindItem(int id, wxMenu **menu) const +{ + if ( menu ) + *menu = NULL; + + wxMenuItem *item = NULL; + size_t count = GetMenuCount(), i; + wxMenuList::const_iterator it; + for ( i = 0, it = m_menus.begin(); !item && (i < count); i++, it++ ) + { + item = (*it)->FindItem(id, menu); + } + + return item; +} + +int wxMenuBarBase::FindMenuItem(const wxString& menu, const wxString& item) const +{ + wxString label = wxMenuItem::GetLabelFromText(menu); + + int i = 0; + wxMenuList::compatibility_iterator node; + for ( node = m_menus.GetFirst(); node; node = node->GetNext(), i++ ) + { + if ( label == wxMenuItem::GetLabelFromText(GetLabelTop(i)) ) + return node->GetData()->FindItem(item); + } + + return wxNOT_FOUND; +} + +// --------------------------------------------------------------------------- +// wxMenuBar functions forwarded to wxMenuItem +// --------------------------------------------------------------------------- + +void wxMenuBarBase::Enable(int id, bool enable) +{ + wxMenuItem *item = FindItem(id); + + wxCHECK_RET( item, wxT("attempt to enable an item which doesn't exist") ); + + item->Enable(enable); +} + +void wxMenuBarBase::Check(int id, bool check) +{ + wxMenuItem *item = FindItem(id); + + wxCHECK_RET( item, wxT("attempt to check an item which doesn't exist") ); + wxCHECK_RET( item->IsCheckable(), wxT("attempt to check an uncheckable item") ); + + item->Check(check); +} + +bool wxMenuBarBase::IsChecked(int id) const +{ + wxMenuItem *item = FindItem(id); + + wxCHECK_MSG( item, false, wxT("wxMenuBar::IsChecked(): no such item") ); + + return item->IsChecked(); +} + +bool wxMenuBarBase::IsEnabled(int id) const +{ + wxMenuItem *item = FindItem(id); + + wxCHECK_MSG( item, false, wxT("wxMenuBar::IsEnabled(): no such item") ); + + return item->IsEnabled(); +} + +void wxMenuBarBase::SetLabel(int id, const wxString& label) +{ + wxMenuItem *item = FindItem(id); + + wxCHECK_RET( item, wxT("wxMenuBar::SetLabel(): no such item") ); + + item->SetText(label); +} + +wxString wxMenuBarBase::GetLabel(int id) const +{ + wxMenuItem *item = FindItem(id); + + wxCHECK_MSG( item, wxEmptyString, + wxT("wxMenuBar::GetLabel(): no such item") ); + + return item->GetText(); +} + +void wxMenuBarBase::SetHelpString(int id, const wxString& helpString) +{ + wxMenuItem *item = FindItem(id); + + wxCHECK_RET( item, wxT("wxMenuBar::SetHelpString(): no such item") ); + + item->SetHelp(helpString); +} + +wxString wxMenuBarBase::GetHelpString(int id) const +{ + wxMenuItem *item = FindItem(id); + + wxCHECK_MSG( item, wxEmptyString, + wxT("wxMenuBar::GetHelpString(): no such item") ); + + return item->GetHelp(); +} + +void wxMenuBarBase::UpdateMenus( void ) +{ + wxEvtHandler* source; + wxMenu* menu; + int nCount = GetMenuCount(); + for (int n = 0; n < nCount; n++) + { + menu = GetMenu( n ); + if (menu != NULL) + { + source = menu->GetEventHandler(); + if (source != NULL) + menu->UpdateUI( source ); + } + } +} + +// Get the text only, from the label +wxString wxMenuBarBase::GetMenuLabelText(size_t pos) const +{ + return wxMenuItem::GetLabelText(((wxMenuBar*)this)->GetMenuLabel(pos)); +} + + +#endif // wxUSE_MENUS diff --git a/Externals/wxWidgets/src/common/mimecmn.cpp b/Externals/wxWidgets/src/common/mimecmn.cpp index 87320c1494..8f914e3472 100644 --- a/Externals/wxWidgets/src/common/mimecmn.cpp +++ b/Externals/wxWidgets/src/common/mimecmn.cpp @@ -1,752 +1,752 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/mimecmn.cpp -// Purpose: classes and functions to manage MIME types -// Author: Vadim Zeitlin -// Modified by: -// Chris Elliott (biol75@york.ac.uk) 5 Dec 00: write support for Win32 -// Created: 23.09.98 -// RCS-ID: $Id: mimecmn.cpp 47027 2007-06-29 18:23:39Z VZ $ -// Copyright: (c) 1998 Vadim Zeitlin -// Licence: wxWindows licence (part of wxExtra library) -///////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// for compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_MIMETYPE - -#include "wx/mimetype.h" - -#ifndef WX_PRECOMP - #include "wx/dynarray.h" - #include "wx/string.h" - #include "wx/intl.h" - #include "wx/log.h" - #include "wx/module.h" -#endif //WX_PRECOMP - -#include "wx/file.h" -#include "wx/iconloc.h" -#include "wx/confbase.h" - -// other standard headers -#include - -// implementation classes: -#if defined(__WXMSW__) - #include "wx/msw/mimetype.h" -#elif defined(__WXMAC__) - #include "wx/mac/mimetype.h" -#elif defined(__WXPM__) || defined (__EMX__) - #include "wx/os2/mimetype.h" - #undef __UNIX__ -#elif defined(__DOS__) - #include "wx/msdos/mimetype.h" -#else // Unix - #include "wx/unix/mimetype.h" -#endif - -// ============================================================================ -// common classes -// ============================================================================ - -// ---------------------------------------------------------------------------- -// wxMimeTypeCommands -// ---------------------------------------------------------------------------- - -void -wxMimeTypeCommands::AddOrReplaceVerb(const wxString& verb, const wxString& cmd) -{ - int n = m_verbs.Index(verb, false /* ignore case */); - if ( n == wxNOT_FOUND ) - { - m_verbs.Add(verb); - m_commands.Add(cmd); - } - else - { - m_commands[n] = cmd; - } -} - -wxString -wxMimeTypeCommands::GetCommandForVerb(const wxString& verb, size_t *idx) const -{ - wxString s; - - int n = m_verbs.Index(verb); - if ( n != wxNOT_FOUND ) - { - s = m_commands[(size_t)n]; - if ( idx ) - *idx = n; - } - else if ( idx ) - { - // different from any valid index - *idx = (size_t)-1; - } - - return s; -} - -wxString wxMimeTypeCommands::GetVerbCmd(size_t n) const -{ - return m_verbs[n] + wxT('=') + m_commands[n]; -} - -// ---------------------------------------------------------------------------- -// wxFileTypeInfo -// ---------------------------------------------------------------------------- - -wxFileTypeInfo::wxFileTypeInfo(const wxChar *mimeType, - const wxChar *openCmd, - const wxChar *printCmd, - const wxChar *desc, - ...) - : m_mimeType(mimeType), - m_openCmd(openCmd), - m_printCmd(printCmd), - m_desc(desc) -{ - va_list argptr; - va_start(argptr, desc); - - for ( ;; ) - { - // icc gives this warning in its own va_arg() macro, argh -#ifdef __INTELC__ - #pragma warning(push) - #pragma warning(disable: 1684) -#endif - - const wxChar *ext = va_arg(argptr, const wxChar *); - -#ifdef __INTELC__ - #pragma warning(pop) -#endif - if ( !ext ) - { - // NULL terminates the list - break; - } - - m_exts.Add(ext); - } - - va_end(argptr); -} - - -wxFileTypeInfo::wxFileTypeInfo(const wxArrayString& sArray) -{ - m_mimeType = sArray [0u]; - m_openCmd = sArray [1u]; - m_printCmd = sArray [2u]; - m_desc = sArray [3u]; - - size_t count = sArray.GetCount(); - for ( size_t i = 4; i < count; i++ ) - { - m_exts.Add(sArray[i]); - } -} - -#include "wx/arrimpl.cpp" -WX_DEFINE_OBJARRAY(wxArrayFileTypeInfo) - -// ============================================================================ -// implementation of the wrapper classes -// ============================================================================ - -// ---------------------------------------------------------------------------- -// wxFileType -// ---------------------------------------------------------------------------- - -/* static */ -wxString wxFileType::ExpandCommand(const wxString& command, - const wxFileType::MessageParameters& params) -{ - bool hasFilename = false; - - wxString str; - for ( const wxChar *pc = command.c_str(); *pc != wxT('\0'); pc++ ) { - if ( *pc == wxT('%') ) { - switch ( *++pc ) { - case wxT('s'): - // '%s' expands into file name (quoted because it might - // contain spaces) - except if there are already quotes - // there because otherwise some programs may get confused - // by double double quotes -#if 0 - if ( *(pc - 2) == wxT('"') ) - str << params.GetFileName(); - else - str << wxT('"') << params.GetFileName() << wxT('"'); -#endif - str << params.GetFileName(); - hasFilename = true; - break; - - case wxT('t'): - // '%t' expands into MIME type (quote it too just to be - // consistent) - str << wxT('\'') << params.GetMimeType() << wxT('\''); - break; - - case wxT('{'): - { - const wxChar *pEnd = wxStrchr(pc, wxT('}')); - if ( pEnd == NULL ) { - wxString mimetype; - wxLogWarning(_("Unmatched '{' in an entry for mime type %s."), - params.GetMimeType().c_str()); - str << wxT("%{"); - } - else { - wxString param(pc + 1, pEnd - pc - 1); - str << wxT('\'') << params.GetParamValue(param) << wxT('\''); - pc = pEnd; - } - } - break; - - case wxT('n'): - case wxT('F'): - // TODO %n is the number of parts, %F is an array containing - // the names of temp files these parts were written to - // and their mime types. - break; - - default: - wxLogDebug(wxT("Unknown field %%%c in command '%s'."), - *pc, command.c_str()); - str << *pc; - } - } - else { - str << *pc; - } - } - - // metamail(1) man page states that if the mailcap entry doesn't have '%s' - // the program will accept the data on stdin so normally we should append - // "< %s" to the end of the command in such case, but not all commands - // behave like this, in particular a common test is 'test -n "$DISPLAY"' - // and appending "< %s" to this command makes the test fail... I don't - // know of the correct solution, try to guess what we have to do. - - // test now carried out on reading file so test should never get here - if ( !hasFilename && !str.empty() -#ifdef __UNIX__ - && !str.StartsWith(_T("test ")) -#endif // Unix - ) { - str << wxT(" < '") << params.GetFileName() << wxT('\''); - } - - return str; -} - -wxFileType::wxFileType(const wxFileTypeInfo& info) -{ - m_info = &info; - m_impl = NULL; -} - -wxFileType::wxFileType() -{ - m_info = NULL; - m_impl = new wxFileTypeImpl; -} - -wxFileType::~wxFileType() -{ - if ( m_impl ) - delete m_impl; -} - -bool wxFileType::GetExtensions(wxArrayString& extensions) -{ - if ( m_info ) - { - extensions = m_info->GetExtensions(); - return true; - } - - return m_impl->GetExtensions(extensions); -} - -bool wxFileType::GetMimeType(wxString *mimeType) const -{ - wxCHECK_MSG( mimeType, false, _T("invalid parameter in GetMimeType") ); - - if ( m_info ) - { - *mimeType = m_info->GetMimeType(); - - return true; - } - - return m_impl->GetMimeType(mimeType); -} - -bool wxFileType::GetMimeTypes(wxArrayString& mimeTypes) const -{ - if ( m_info ) - { - mimeTypes.Clear(); - mimeTypes.Add(m_info->GetMimeType()); - - return true; - } - - return m_impl->GetMimeTypes(mimeTypes); -} - -bool wxFileType::GetIcon(wxIconLocation *iconLoc) const -{ - if ( m_info ) - { - if ( iconLoc ) - { - iconLoc->SetFileName(m_info->GetIconFile()); -#ifdef __WXMSW__ - iconLoc->SetIndex(m_info->GetIconIndex()); -#endif // __WXMSW__ - } - - return true; - } - - return m_impl->GetIcon(iconLoc); -} - -bool -wxFileType::GetIcon(wxIconLocation *iconloc, - const MessageParameters& params) const -{ - if ( !GetIcon(iconloc) ) - { - return false; - } - - // we may have "%s" in the icon location string, at least under Windows, so - // expand this - if ( iconloc ) - { - iconloc->SetFileName(ExpandCommand(iconloc->GetFileName(), params)); - } - - return true; -} - -bool wxFileType::GetDescription(wxString *desc) const -{ - wxCHECK_MSG( desc, false, _T("invalid parameter in GetDescription") ); - - if ( m_info ) - { - *desc = m_info->GetDescription(); - - return true; - } - - return m_impl->GetDescription(desc); -} - -bool -wxFileType::GetOpenCommand(wxString *openCmd, - const wxFileType::MessageParameters& params) const -{ - wxCHECK_MSG( openCmd, false, _T("invalid parameter in GetOpenCommand") ); - - if ( m_info ) - { - *openCmd = ExpandCommand(m_info->GetOpenCommand(), params); - - return true; - } - - return m_impl->GetOpenCommand(openCmd, params); -} - -wxString wxFileType::GetOpenCommand(const wxString& filename) const -{ - wxString cmd; - if ( !GetOpenCommand(&cmd, filename) ) - { - // return empty string to indicate an error - cmd.clear(); - } - - return cmd; -} - -bool -wxFileType::GetPrintCommand(wxString *printCmd, - const wxFileType::MessageParameters& params) const -{ - wxCHECK_MSG( printCmd, false, _T("invalid parameter in GetPrintCommand") ); - - if ( m_info ) - { - *printCmd = ExpandCommand(m_info->GetPrintCommand(), params); - - return true; - } - - return m_impl->GetPrintCommand(printCmd, params); -} - - -size_t wxFileType::GetAllCommands(wxArrayString *verbs, - wxArrayString *commands, - const wxFileType::MessageParameters& params) const -{ - if ( verbs ) - verbs->Clear(); - if ( commands ) - commands->Clear(); - -#if defined (__WXMSW__) || defined(__UNIX__) - return m_impl->GetAllCommands(verbs, commands, params); -#else // !__WXMSW__ || Unix - // we don't know how to retrieve all commands, so just try the 2 we know - // about - size_t count = 0; - wxString cmd; - if ( GetOpenCommand(&cmd, params) ) - { - if ( verbs ) - verbs->Add(_T("Open")); - if ( commands ) - commands->Add(cmd); - count++; - } - - if ( GetPrintCommand(&cmd, params) ) - { - if ( verbs ) - verbs->Add(_T("Print")); - if ( commands ) - commands->Add(cmd); - - count++; - } - - return count; -#endif // __WXMSW__/| __UNIX__ -} - -bool wxFileType::Unassociate() -{ -#if defined(__WXMSW__) - return m_impl->Unassociate(); -#elif defined(__UNIX__) - return m_impl->Unassociate(this); -#else - wxFAIL_MSG( _T("not implemented") ); // TODO - return false; -#endif -} - -bool wxFileType::SetCommand(const wxString& cmd, - const wxString& verb, - bool overwriteprompt) -{ -#if defined (__WXMSW__) || defined(__UNIX__) - return m_impl->SetCommand(cmd, verb, overwriteprompt); -#else - wxUnusedVar(cmd); - wxUnusedVar(verb); - wxUnusedVar(overwriteprompt); - wxFAIL_MSG(_T("not implemented")); - return false; -#endif -} - -bool wxFileType::SetDefaultIcon(const wxString& cmd, int index) -{ - wxString sTmp = cmd; -#ifdef __WXMSW__ - // VZ: should we do this? - // chris elliott : only makes sense in MS windows - if ( sTmp.empty() ) - GetOpenCommand(&sTmp, wxFileType::MessageParameters(wxEmptyString, wxEmptyString)); -#endif - wxCHECK_MSG( !sTmp.empty(), false, _T("need the icon file") ); - -#if defined (__WXMSW__) || defined(__UNIX__) - return m_impl->SetDefaultIcon (cmd, index); -#else - wxUnusedVar(index); - wxFAIL_MSG(_T("not implemented")); - return false; -#endif -} - -// ---------------------------------------------------------------------------- -// wxMimeTypesManagerFactory -// ---------------------------------------------------------------------------- - -wxMimeTypesManagerFactory *wxMimeTypesManagerFactory::m_factory = NULL; - -/* static */ -void wxMimeTypesManagerFactory::Set(wxMimeTypesManagerFactory *factory) -{ - delete m_factory; - - m_factory = factory; -} - -/* static */ -wxMimeTypesManagerFactory *wxMimeTypesManagerFactory::Get() -{ - if ( !m_factory ) - m_factory = new wxMimeTypesManagerFactory; - - return m_factory; -} - -wxMimeTypesManagerImpl *wxMimeTypesManagerFactory::CreateMimeTypesManagerImpl() -{ - return new wxMimeTypesManagerImpl; -} - -// ---------------------------------------------------------------------------- -// wxMimeTypesManager -// ---------------------------------------------------------------------------- - -void wxMimeTypesManager::EnsureImpl() -{ - if ( !m_impl ) - m_impl = wxMimeTypesManagerFactory::Get()->CreateMimeTypesManagerImpl(); -} - -bool wxMimeTypesManager::IsOfType(const wxString& mimeType, - const wxString& wildcard) -{ - wxASSERT_MSG( mimeType.Find(wxT('*')) == wxNOT_FOUND, - wxT("first MIME type can't contain wildcards") ); - - // all comparaisons are case insensitive (2nd arg of IsSameAs() is false) - if ( wildcard.BeforeFirst(wxT('/')). - IsSameAs(mimeType.BeforeFirst(wxT('/')), false) ) - { - wxString strSubtype = wildcard.AfterFirst(wxT('/')); - - if ( strSubtype == wxT("*") || - strSubtype.IsSameAs(mimeType.AfterFirst(wxT('/')), false) ) - { - // matches (either exactly or it's a wildcard) - return true; - } - } - - return false; -} - -wxMimeTypesManager::wxMimeTypesManager() -{ - m_impl = NULL; -} - -wxMimeTypesManager::~wxMimeTypesManager() -{ - if ( m_impl ) - delete m_impl; -} - -bool wxMimeTypesManager::Unassociate(wxFileType *ft) -{ - EnsureImpl(); - -#if defined(__UNIX__) && !defined(__CYGWIN__) && !defined(__WINE__) - return m_impl->Unassociate(ft); -#else - return ft->Unassociate(); -#endif -} - - -wxFileType * -wxMimeTypesManager::Associate(const wxFileTypeInfo& ftInfo) -{ - EnsureImpl(); - -#if defined(__WXMSW__) || defined(__UNIX__) - return m_impl->Associate(ftInfo); -#else // other platforms - wxUnusedVar(ftInfo); - wxFAIL_MSG( _T("not implemented") ); // TODO - return NULL; -#endif // platforms -} - -wxFileType * -wxMimeTypesManager::GetFileTypeFromExtension(const wxString& ext) -{ - EnsureImpl(); - - wxString::const_iterator i = ext.begin(); - const wxString::const_iterator end = ext.end(); - wxString extWithoutDot; - if ( i != end && *i == '.' ) - extWithoutDot.assign(++i, ext.end()); - else - extWithoutDot = ext; - - wxCHECK_MSG( !ext.empty(), NULL, _T("extension can't be empty") ); - - wxFileType *ft = m_impl->GetFileTypeFromExtension(extWithoutDot); - - if ( !ft ) { - // check the fallbacks - // - // TODO linear search is potentially slow, perhaps we should use a - // sorted array? - size_t count = m_fallbacks.GetCount(); - for ( size_t n = 0; n < count; n++ ) { - if ( m_fallbacks[n].GetExtensions().Index(ext) != wxNOT_FOUND ) { - ft = new wxFileType(m_fallbacks[n]); - - break; - } - } - } - - return ft; -} - -wxFileType * -wxMimeTypesManager::GetFileTypeFromMimeType(const wxString& mimeType) -{ - EnsureImpl(); - wxFileType *ft = m_impl->GetFileTypeFromMimeType(mimeType); - - if ( !ft ) { - // check the fallbacks - // - // TODO linear search is potentially slow, perhaps we should use a - // sorted array? - size_t count = m_fallbacks.GetCount(); - for ( size_t n = 0; n < count; n++ ) { - if ( wxMimeTypesManager::IsOfType(mimeType, - m_fallbacks[n].GetMimeType()) ) { - ft = new wxFileType(m_fallbacks[n]); - - break; - } - } - } - - return ft; -} - -bool wxMimeTypesManager::ReadMailcap(const wxString& filename, bool fallback) -{ - EnsureImpl(); - return m_impl->ReadMailcap(filename, fallback); -} - -bool wxMimeTypesManager::ReadMimeTypes(const wxString& filename) -{ - EnsureImpl(); - return m_impl->ReadMimeTypes(filename); -} - -void wxMimeTypesManager::AddFallbacks(const wxFileTypeInfo *filetypes) -{ - EnsureImpl(); - for ( const wxFileTypeInfo *ft = filetypes; ft && ft->IsValid(); ft++ ) { - AddFallback(*ft); - } -} - -size_t wxMimeTypesManager::EnumAllFileTypes(wxArrayString& mimetypes) -{ - EnsureImpl(); - size_t countAll = m_impl->EnumAllFileTypes(mimetypes); - - // add the fallback filetypes - size_t count = m_fallbacks.GetCount(); - for ( size_t n = 0; n < count; n++ ) { - if ( mimetypes.Index(m_fallbacks[n].GetMimeType()) == wxNOT_FOUND ) { - mimetypes.Add(m_fallbacks[n].GetMimeType()); - countAll++; - } - } - - return countAll; -} - -void wxMimeTypesManager::Initialize(int mcapStyle, - const wxString& sExtraDir) -{ -#if defined(__UNIX__) && !defined(__CYGWIN__) && !defined(__WINE__) - EnsureImpl(); - - m_impl->Initialize(mcapStyle, sExtraDir); -#else - (void)mcapStyle; - (void)sExtraDir; -#endif // Unix -} - -// and this function clears all the data from the manager -void wxMimeTypesManager::ClearData() -{ -#if defined(__UNIX__) && !defined(__CYGWIN__) && !defined(__WINE__) - EnsureImpl(); - - m_impl->ClearData(); -#endif // Unix -} - -// ---------------------------------------------------------------------------- -// global data and wxMimeTypeCmnModule -// ---------------------------------------------------------------------------- - -// private object -static wxMimeTypesManager gs_mimeTypesManager; - -// and public pointer -wxMimeTypesManager *wxTheMimeTypesManager = &gs_mimeTypesManager; - -class wxMimeTypeCmnModule: public wxModule -{ -public: - wxMimeTypeCmnModule() : wxModule() { } - - virtual bool OnInit() { return true; } - virtual void OnExit() - { - wxMimeTypesManagerFactory::Set(NULL); - - if ( gs_mimeTypesManager.m_impl != NULL ) - { - delete gs_mimeTypesManager.m_impl; - gs_mimeTypesManager.m_impl = NULL; - gs_mimeTypesManager.m_fallbacks.Clear(); - } - } - - DECLARE_DYNAMIC_CLASS(wxMimeTypeCmnModule) -}; - -IMPLEMENT_DYNAMIC_CLASS(wxMimeTypeCmnModule, wxModule) - -#endif // wxUSE_MIMETYPE +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/mimecmn.cpp +// Purpose: classes and functions to manage MIME types +// Author: Vadim Zeitlin +// Modified by: +// Chris Elliott (biol75@york.ac.uk) 5 Dec 00: write support for Win32 +// Created: 23.09.98 +// RCS-ID: $Id: mimecmn.cpp 47027 2007-06-29 18:23:39Z VZ $ +// Copyright: (c) 1998 Vadim Zeitlin +// Licence: wxWindows licence (part of wxExtra library) +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// for compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_MIMETYPE + +#include "wx/mimetype.h" + +#ifndef WX_PRECOMP + #include "wx/dynarray.h" + #include "wx/string.h" + #include "wx/intl.h" + #include "wx/log.h" + #include "wx/module.h" +#endif //WX_PRECOMP + +#include "wx/file.h" +#include "wx/iconloc.h" +#include "wx/confbase.h" + +// other standard headers +#include + +// implementation classes: +#if defined(__WXMSW__) + #include "wx/msw/mimetype.h" +#elif defined(__WXMAC__) + #include "wx/mac/mimetype.h" +#elif defined(__WXPM__) || defined (__EMX__) + #include "wx/os2/mimetype.h" + #undef __UNIX__ +#elif defined(__DOS__) + #include "wx/msdos/mimetype.h" +#else // Unix + #include "wx/unix/mimetype.h" +#endif + +// ============================================================================ +// common classes +// ============================================================================ + +// ---------------------------------------------------------------------------- +// wxMimeTypeCommands +// ---------------------------------------------------------------------------- + +void +wxMimeTypeCommands::AddOrReplaceVerb(const wxString& verb, const wxString& cmd) +{ + int n = m_verbs.Index(verb, false /* ignore case */); + if ( n == wxNOT_FOUND ) + { + m_verbs.Add(verb); + m_commands.Add(cmd); + } + else + { + m_commands[n] = cmd; + } +} + +wxString +wxMimeTypeCommands::GetCommandForVerb(const wxString& verb, size_t *idx) const +{ + wxString s; + + int n = m_verbs.Index(verb); + if ( n != wxNOT_FOUND ) + { + s = m_commands[(size_t)n]; + if ( idx ) + *idx = n; + } + else if ( idx ) + { + // different from any valid index + *idx = (size_t)-1; + } + + return s; +} + +wxString wxMimeTypeCommands::GetVerbCmd(size_t n) const +{ + return m_verbs[n] + wxT('=') + m_commands[n]; +} + +// ---------------------------------------------------------------------------- +// wxFileTypeInfo +// ---------------------------------------------------------------------------- + +wxFileTypeInfo::wxFileTypeInfo(const wxChar *mimeType, + const wxChar *openCmd, + const wxChar *printCmd, + const wxChar *desc, + ...) + : m_mimeType(mimeType), + m_openCmd(openCmd), + m_printCmd(printCmd), + m_desc(desc) +{ + va_list argptr; + va_start(argptr, desc); + + for ( ;; ) + { + // icc gives this warning in its own va_arg() macro, argh +#ifdef __INTELC__ + #pragma warning(push) + #pragma warning(disable: 1684) +#endif + + const wxChar *ext = va_arg(argptr, const wxChar *); + +#ifdef __INTELC__ + #pragma warning(pop) +#endif + if ( !ext ) + { + // NULL terminates the list + break; + } + + m_exts.Add(ext); + } + + va_end(argptr); +} + + +wxFileTypeInfo::wxFileTypeInfo(const wxArrayString& sArray) +{ + m_mimeType = sArray [0u]; + m_openCmd = sArray [1u]; + m_printCmd = sArray [2u]; + m_desc = sArray [3u]; + + size_t count = sArray.GetCount(); + for ( size_t i = 4; i < count; i++ ) + { + m_exts.Add(sArray[i]); + } +} + +#include "wx/arrimpl.cpp" +WX_DEFINE_OBJARRAY(wxArrayFileTypeInfo) + +// ============================================================================ +// implementation of the wrapper classes +// ============================================================================ + +// ---------------------------------------------------------------------------- +// wxFileType +// ---------------------------------------------------------------------------- + +/* static */ +wxString wxFileType::ExpandCommand(const wxString& command, + const wxFileType::MessageParameters& params) +{ + bool hasFilename = false; + + wxString str; + for ( const wxChar *pc = command.c_str(); *pc != wxT('\0'); pc++ ) { + if ( *pc == wxT('%') ) { + switch ( *++pc ) { + case wxT('s'): + // '%s' expands into file name (quoted because it might + // contain spaces) - except if there are already quotes + // there because otherwise some programs may get confused + // by double double quotes +#if 0 + if ( *(pc - 2) == wxT('"') ) + str << params.GetFileName(); + else + str << wxT('"') << params.GetFileName() << wxT('"'); +#endif + str << params.GetFileName(); + hasFilename = true; + break; + + case wxT('t'): + // '%t' expands into MIME type (quote it too just to be + // consistent) + str << wxT('\'') << params.GetMimeType() << wxT('\''); + break; + + case wxT('{'): + { + const wxChar *pEnd = wxStrchr(pc, wxT('}')); + if ( pEnd == NULL ) { + wxString mimetype; + wxLogWarning(_("Unmatched '{' in an entry for mime type %s."), + params.GetMimeType().c_str()); + str << wxT("%{"); + } + else { + wxString param(pc + 1, pEnd - pc - 1); + str << wxT('\'') << params.GetParamValue(param) << wxT('\''); + pc = pEnd; + } + } + break; + + case wxT('n'): + case wxT('F'): + // TODO %n is the number of parts, %F is an array containing + // the names of temp files these parts were written to + // and their mime types. + break; + + default: + wxLogDebug(wxT("Unknown field %%%c in command '%s'."), + *pc, command.c_str()); + str << *pc; + } + } + else { + str << *pc; + } + } + + // metamail(1) man page states that if the mailcap entry doesn't have '%s' + // the program will accept the data on stdin so normally we should append + // "< %s" to the end of the command in such case, but not all commands + // behave like this, in particular a common test is 'test -n "$DISPLAY"' + // and appending "< %s" to this command makes the test fail... I don't + // know of the correct solution, try to guess what we have to do. + + // test now carried out on reading file so test should never get here + if ( !hasFilename && !str.empty() +#ifdef __UNIX__ + && !str.StartsWith(_T("test ")) +#endif // Unix + ) { + str << wxT(" < '") << params.GetFileName() << wxT('\''); + } + + return str; +} + +wxFileType::wxFileType(const wxFileTypeInfo& info) +{ + m_info = &info; + m_impl = NULL; +} + +wxFileType::wxFileType() +{ + m_info = NULL; + m_impl = new wxFileTypeImpl; +} + +wxFileType::~wxFileType() +{ + if ( m_impl ) + delete m_impl; +} + +bool wxFileType::GetExtensions(wxArrayString& extensions) +{ + if ( m_info ) + { + extensions = m_info->GetExtensions(); + return true; + } + + return m_impl->GetExtensions(extensions); +} + +bool wxFileType::GetMimeType(wxString *mimeType) const +{ + wxCHECK_MSG( mimeType, false, _T("invalid parameter in GetMimeType") ); + + if ( m_info ) + { + *mimeType = m_info->GetMimeType(); + + return true; + } + + return m_impl->GetMimeType(mimeType); +} + +bool wxFileType::GetMimeTypes(wxArrayString& mimeTypes) const +{ + if ( m_info ) + { + mimeTypes.Clear(); + mimeTypes.Add(m_info->GetMimeType()); + + return true; + } + + return m_impl->GetMimeTypes(mimeTypes); +} + +bool wxFileType::GetIcon(wxIconLocation *iconLoc) const +{ + if ( m_info ) + { + if ( iconLoc ) + { + iconLoc->SetFileName(m_info->GetIconFile()); +#ifdef __WXMSW__ + iconLoc->SetIndex(m_info->GetIconIndex()); +#endif // __WXMSW__ + } + + return true; + } + + return m_impl->GetIcon(iconLoc); +} + +bool +wxFileType::GetIcon(wxIconLocation *iconloc, + const MessageParameters& params) const +{ + if ( !GetIcon(iconloc) ) + { + return false; + } + + // we may have "%s" in the icon location string, at least under Windows, so + // expand this + if ( iconloc ) + { + iconloc->SetFileName(ExpandCommand(iconloc->GetFileName(), params)); + } + + return true; +} + +bool wxFileType::GetDescription(wxString *desc) const +{ + wxCHECK_MSG( desc, false, _T("invalid parameter in GetDescription") ); + + if ( m_info ) + { + *desc = m_info->GetDescription(); + + return true; + } + + return m_impl->GetDescription(desc); +} + +bool +wxFileType::GetOpenCommand(wxString *openCmd, + const wxFileType::MessageParameters& params) const +{ + wxCHECK_MSG( openCmd, false, _T("invalid parameter in GetOpenCommand") ); + + if ( m_info ) + { + *openCmd = ExpandCommand(m_info->GetOpenCommand(), params); + + return true; + } + + return m_impl->GetOpenCommand(openCmd, params); +} + +wxString wxFileType::GetOpenCommand(const wxString& filename) const +{ + wxString cmd; + if ( !GetOpenCommand(&cmd, filename) ) + { + // return empty string to indicate an error + cmd.clear(); + } + + return cmd; +} + +bool +wxFileType::GetPrintCommand(wxString *printCmd, + const wxFileType::MessageParameters& params) const +{ + wxCHECK_MSG( printCmd, false, _T("invalid parameter in GetPrintCommand") ); + + if ( m_info ) + { + *printCmd = ExpandCommand(m_info->GetPrintCommand(), params); + + return true; + } + + return m_impl->GetPrintCommand(printCmd, params); +} + + +size_t wxFileType::GetAllCommands(wxArrayString *verbs, + wxArrayString *commands, + const wxFileType::MessageParameters& params) const +{ + if ( verbs ) + verbs->Clear(); + if ( commands ) + commands->Clear(); + +#if defined (__WXMSW__) || defined(__UNIX__) + return m_impl->GetAllCommands(verbs, commands, params); +#else // !__WXMSW__ || Unix + // we don't know how to retrieve all commands, so just try the 2 we know + // about + size_t count = 0; + wxString cmd; + if ( GetOpenCommand(&cmd, params) ) + { + if ( verbs ) + verbs->Add(_T("Open")); + if ( commands ) + commands->Add(cmd); + count++; + } + + if ( GetPrintCommand(&cmd, params) ) + { + if ( verbs ) + verbs->Add(_T("Print")); + if ( commands ) + commands->Add(cmd); + + count++; + } + + return count; +#endif // __WXMSW__/| __UNIX__ +} + +bool wxFileType::Unassociate() +{ +#if defined(__WXMSW__) + return m_impl->Unassociate(); +#elif defined(__UNIX__) + return m_impl->Unassociate(this); +#else + wxFAIL_MSG( _T("not implemented") ); // TODO + return false; +#endif +} + +bool wxFileType::SetCommand(const wxString& cmd, + const wxString& verb, + bool overwriteprompt) +{ +#if defined (__WXMSW__) || defined(__UNIX__) + return m_impl->SetCommand(cmd, verb, overwriteprompt); +#else + wxUnusedVar(cmd); + wxUnusedVar(verb); + wxUnusedVar(overwriteprompt); + wxFAIL_MSG(_T("not implemented")); + return false; +#endif +} + +bool wxFileType::SetDefaultIcon(const wxString& cmd, int index) +{ + wxString sTmp = cmd; +#ifdef __WXMSW__ + // VZ: should we do this? + // chris elliott : only makes sense in MS windows + if ( sTmp.empty() ) + GetOpenCommand(&sTmp, wxFileType::MessageParameters(wxEmptyString, wxEmptyString)); +#endif + wxCHECK_MSG( !sTmp.empty(), false, _T("need the icon file") ); + +#if defined (__WXMSW__) || defined(__UNIX__) + return m_impl->SetDefaultIcon (cmd, index); +#else + wxUnusedVar(index); + wxFAIL_MSG(_T("not implemented")); + return false; +#endif +} + +// ---------------------------------------------------------------------------- +// wxMimeTypesManagerFactory +// ---------------------------------------------------------------------------- + +wxMimeTypesManagerFactory *wxMimeTypesManagerFactory::m_factory = NULL; + +/* static */ +void wxMimeTypesManagerFactory::Set(wxMimeTypesManagerFactory *factory) +{ + delete m_factory; + + m_factory = factory; +} + +/* static */ +wxMimeTypesManagerFactory *wxMimeTypesManagerFactory::Get() +{ + if ( !m_factory ) + m_factory = new wxMimeTypesManagerFactory; + + return m_factory; +} + +wxMimeTypesManagerImpl *wxMimeTypesManagerFactory::CreateMimeTypesManagerImpl() +{ + return new wxMimeTypesManagerImpl; +} + +// ---------------------------------------------------------------------------- +// wxMimeTypesManager +// ---------------------------------------------------------------------------- + +void wxMimeTypesManager::EnsureImpl() +{ + if ( !m_impl ) + m_impl = wxMimeTypesManagerFactory::Get()->CreateMimeTypesManagerImpl(); +} + +bool wxMimeTypesManager::IsOfType(const wxString& mimeType, + const wxString& wildcard) +{ + wxASSERT_MSG( mimeType.Find(wxT('*')) == wxNOT_FOUND, + wxT("first MIME type can't contain wildcards") ); + + // all comparaisons are case insensitive (2nd arg of IsSameAs() is false) + if ( wildcard.BeforeFirst(wxT('/')). + IsSameAs(mimeType.BeforeFirst(wxT('/')), false) ) + { + wxString strSubtype = wildcard.AfterFirst(wxT('/')); + + if ( strSubtype == wxT("*") || + strSubtype.IsSameAs(mimeType.AfterFirst(wxT('/')), false) ) + { + // matches (either exactly or it's a wildcard) + return true; + } + } + + return false; +} + +wxMimeTypesManager::wxMimeTypesManager() +{ + m_impl = NULL; +} + +wxMimeTypesManager::~wxMimeTypesManager() +{ + if ( m_impl ) + delete m_impl; +} + +bool wxMimeTypesManager::Unassociate(wxFileType *ft) +{ + EnsureImpl(); + +#if defined(__UNIX__) && !defined(__CYGWIN__) && !defined(__WINE__) + return m_impl->Unassociate(ft); +#else + return ft->Unassociate(); +#endif +} + + +wxFileType * +wxMimeTypesManager::Associate(const wxFileTypeInfo& ftInfo) +{ + EnsureImpl(); + +#if defined(__WXMSW__) || defined(__UNIX__) + return m_impl->Associate(ftInfo); +#else // other platforms + wxUnusedVar(ftInfo); + wxFAIL_MSG( _T("not implemented") ); // TODO + return NULL; +#endif // platforms +} + +wxFileType * +wxMimeTypesManager::GetFileTypeFromExtension(const wxString& ext) +{ + EnsureImpl(); + + wxString::const_iterator i = ext.begin(); + const wxString::const_iterator end = ext.end(); + wxString extWithoutDot; + if ( i != end && *i == '.' ) + extWithoutDot.assign(++i, ext.end()); + else + extWithoutDot = ext; + + wxCHECK_MSG( !ext.empty(), NULL, _T("extension can't be empty") ); + + wxFileType *ft = m_impl->GetFileTypeFromExtension(extWithoutDot); + + if ( !ft ) { + // check the fallbacks + // + // TODO linear search is potentially slow, perhaps we should use a + // sorted array? + size_t count = m_fallbacks.GetCount(); + for ( size_t n = 0; n < count; n++ ) { + if ( m_fallbacks[n].GetExtensions().Index(ext) != wxNOT_FOUND ) { + ft = new wxFileType(m_fallbacks[n]); + + break; + } + } + } + + return ft; +} + +wxFileType * +wxMimeTypesManager::GetFileTypeFromMimeType(const wxString& mimeType) +{ + EnsureImpl(); + wxFileType *ft = m_impl->GetFileTypeFromMimeType(mimeType); + + if ( !ft ) { + // check the fallbacks + // + // TODO linear search is potentially slow, perhaps we should use a + // sorted array? + size_t count = m_fallbacks.GetCount(); + for ( size_t n = 0; n < count; n++ ) { + if ( wxMimeTypesManager::IsOfType(mimeType, + m_fallbacks[n].GetMimeType()) ) { + ft = new wxFileType(m_fallbacks[n]); + + break; + } + } + } + + return ft; +} + +bool wxMimeTypesManager::ReadMailcap(const wxString& filename, bool fallback) +{ + EnsureImpl(); + return m_impl->ReadMailcap(filename, fallback); +} + +bool wxMimeTypesManager::ReadMimeTypes(const wxString& filename) +{ + EnsureImpl(); + return m_impl->ReadMimeTypes(filename); +} + +void wxMimeTypesManager::AddFallbacks(const wxFileTypeInfo *filetypes) +{ + EnsureImpl(); + for ( const wxFileTypeInfo *ft = filetypes; ft && ft->IsValid(); ft++ ) { + AddFallback(*ft); + } +} + +size_t wxMimeTypesManager::EnumAllFileTypes(wxArrayString& mimetypes) +{ + EnsureImpl(); + size_t countAll = m_impl->EnumAllFileTypes(mimetypes); + + // add the fallback filetypes + size_t count = m_fallbacks.GetCount(); + for ( size_t n = 0; n < count; n++ ) { + if ( mimetypes.Index(m_fallbacks[n].GetMimeType()) == wxNOT_FOUND ) { + mimetypes.Add(m_fallbacks[n].GetMimeType()); + countAll++; + } + } + + return countAll; +} + +void wxMimeTypesManager::Initialize(int mcapStyle, + const wxString& sExtraDir) +{ +#if defined(__UNIX__) && !defined(__CYGWIN__) && !defined(__WINE__) + EnsureImpl(); + + m_impl->Initialize(mcapStyle, sExtraDir); +#else + (void)mcapStyle; + (void)sExtraDir; +#endif // Unix +} + +// and this function clears all the data from the manager +void wxMimeTypesManager::ClearData() +{ +#if defined(__UNIX__) && !defined(__CYGWIN__) && !defined(__WINE__) + EnsureImpl(); + + m_impl->ClearData(); +#endif // Unix +} + +// ---------------------------------------------------------------------------- +// global data and wxMimeTypeCmnModule +// ---------------------------------------------------------------------------- + +// private object +static wxMimeTypesManager gs_mimeTypesManager; + +// and public pointer +wxMimeTypesManager *wxTheMimeTypesManager = &gs_mimeTypesManager; + +class wxMimeTypeCmnModule: public wxModule +{ +public: + wxMimeTypeCmnModule() : wxModule() { } + + virtual bool OnInit() { return true; } + virtual void OnExit() + { + wxMimeTypesManagerFactory::Set(NULL); + + if ( gs_mimeTypesManager.m_impl != NULL ) + { + delete gs_mimeTypesManager.m_impl; + gs_mimeTypesManager.m_impl = NULL; + gs_mimeTypesManager.m_fallbacks.Clear(); + } + } + + DECLARE_DYNAMIC_CLASS(wxMimeTypeCmnModule) +}; + +IMPLEMENT_DYNAMIC_CLASS(wxMimeTypeCmnModule, wxModule) + +#endif // wxUSE_MIMETYPE diff --git a/Externals/wxWidgets/src/common/module.cpp b/Externals/wxWidgets/src/common/module.cpp index ba5732e781..d4d963b631 100644 --- a/Externals/wxWidgets/src/common/module.cpp +++ b/Externals/wxWidgets/src/common/module.cpp @@ -1,202 +1,202 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/module.cpp -// Purpose: Modules initialization/destruction -// Author: Wolfram Gloger/adapted by Guilhem Lavaux -// Modified by: -// Created: 04/11/98 -// RCS-ID: $Id: module.cpp 39677 2006-06-11 22:19:12Z VZ $ -// Copyright: (c) Wolfram Gloger and Guilhem Lavaux -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#include "wx/module.h" - -#ifndef WX_PRECOMP - #include "wx/hash.h" - #include "wx/intl.h" - #include "wx/log.h" -#endif - -#include "wx/listimpl.cpp" - -#define TRACE_MODULE _T("module") - -WX_DEFINE_LIST(wxModuleList) - -IMPLEMENT_CLASS(wxModule, wxObject) - -wxModuleList wxModule::m_modules; - -void wxModule::RegisterModule(wxModule* module) -{ - module->m_state = State_Registered; - m_modules.Append(module); -} - -void wxModule::UnregisterModule(wxModule* module) -{ - m_modules.DeleteObject(module); - delete module; -} - -// Collect up all module-derived classes, create an instance of each, -// and register them. -void wxModule::RegisterModules() -{ - wxHashTable::compatibility_iterator node; - wxClassInfo* classInfo; - - wxClassInfo::sm_classTable->BeginFind(); - node = wxClassInfo::sm_classTable->Next(); - while (node) - { - classInfo = (wxClassInfo *)node->GetData(); - if ( classInfo->IsKindOf(CLASSINFO(wxModule)) && - (classInfo != (& (wxModule::ms_classInfo))) ) - { - wxLogTrace(TRACE_MODULE, wxT("Registering module %s"), - classInfo->GetClassName()); - wxModule* module = (wxModule *)classInfo->CreateObject(); - RegisterModule(module); - } - node = wxClassInfo::sm_classTable->Next(); - } -} - -bool wxModule::DoInitializeModule(wxModule *module, - wxModuleList &initializedModules) -{ - if ( module->m_state == State_Initializing ) - { - wxLogError(_("Circular dependency involving module \"%s\" detected."), - module->GetClassInfo()->GetClassName()); - return false; - } - - module->m_state = State_Initializing; - - const wxArrayClassInfo& dependencies = module->m_dependencies; - - // satisfy module dependencies by loading them before the current module - for ( unsigned int i = 0; i < dependencies.size(); ++i ) - { - wxClassInfo * cinfo = dependencies[i]; - - // Check if the module is already initialized - wxModuleList::compatibility_iterator node; - for ( node = initializedModules.GetFirst(); node; node = node->GetNext() ) - { - if ( node->GetData()->GetClassInfo() == cinfo ) - break; - } - - if ( node ) - { - // this dependency is already initialized, nothing to do - continue; - } - - // find the module in the registered modules list - for ( node = m_modules.GetFirst(); node; node = node->GetNext() ) - { - wxModule *moduleDep = node->GetData(); - if ( moduleDep->GetClassInfo() == cinfo ) - { - if ( !DoInitializeModule(moduleDep, initializedModules ) ) - { - // failed to initialize a dependency, so fail this one too - return false; - } - - break; - } - } - - if ( !node ) - { - wxLogError(_("Dependency \"%s\" of module \"%s\" doesn't exist."), - cinfo->GetClassName(), - module->GetClassInfo()->GetClassName()); - return false; - } - } - - if ( !module->Init() ) - { - wxLogError(_("Module \"%s\" initialization failed"), - module->GetClassInfo()->GetClassName()); - return false; - } - - wxLogTrace(TRACE_MODULE, wxT("Module \"%s\" initialized"), - module->GetClassInfo()->GetClassName()); - - module->m_state = State_Initialized; - initializedModules.Append(module); - - return true; -} - -// Initialize user-defined modules -bool wxModule::InitializeModules() -{ - wxModuleList initializedModules; - - for ( wxModuleList::compatibility_iterator node = m_modules.GetFirst(); - node; - node = node->GetNext() ) - { - wxModule *module = node->GetData(); - - // the module could have been already initialized as dependency of - // another one - if ( module->m_state == State_Registered ) - { - if ( !DoInitializeModule( module, initializedModules ) ) - { - // failed to initialize all modules, so clean up the already - // initialized ones - DoCleanUpModules(initializedModules); - - return false; - } - } - } - - // remember the real initialisation order - m_modules = initializedModules; - - return true; -} - -// Clean up all currently initialized modules -void wxModule::DoCleanUpModules(const wxModuleList& modules) -{ - // cleanup user-defined modules in the reverse order compared to their - // initialization -- this ensures that dependencies are respected - for ( wxModuleList::compatibility_iterator node = modules.GetLast(); - node; - node = node->GetPrevious() ) - { - wxLogTrace(TRACE_MODULE, wxT("Cleanup module %s"), - node->GetData()->GetClassInfo()->GetClassName()); - - wxModule * module = node->GetData(); - - wxASSERT_MSG( module->m_state == State_Initialized, - _T("not initialized module being cleaned up") ); - - module->Exit(); - module->m_state = State_Registered; - } - - // clear all modules, even the non-initialized ones - WX_CLEAR_LIST(wxModuleList, m_modules); -} +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/module.cpp +// Purpose: Modules initialization/destruction +// Author: Wolfram Gloger/adapted by Guilhem Lavaux +// Modified by: +// Created: 04/11/98 +// RCS-ID: $Id: module.cpp 39677 2006-06-11 22:19:12Z VZ $ +// Copyright: (c) Wolfram Gloger and Guilhem Lavaux +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#include "wx/module.h" + +#ifndef WX_PRECOMP + #include "wx/hash.h" + #include "wx/intl.h" + #include "wx/log.h" +#endif + +#include "wx/listimpl.cpp" + +#define TRACE_MODULE _T("module") + +WX_DEFINE_LIST(wxModuleList) + +IMPLEMENT_CLASS(wxModule, wxObject) + +wxModuleList wxModule::m_modules; + +void wxModule::RegisterModule(wxModule* module) +{ + module->m_state = State_Registered; + m_modules.Append(module); +} + +void wxModule::UnregisterModule(wxModule* module) +{ + m_modules.DeleteObject(module); + delete module; +} + +// Collect up all module-derived classes, create an instance of each, +// and register them. +void wxModule::RegisterModules() +{ + wxHashTable::compatibility_iterator node; + wxClassInfo* classInfo; + + wxClassInfo::sm_classTable->BeginFind(); + node = wxClassInfo::sm_classTable->Next(); + while (node) + { + classInfo = (wxClassInfo *)node->GetData(); + if ( classInfo->IsKindOf(CLASSINFO(wxModule)) && + (classInfo != (& (wxModule::ms_classInfo))) ) + { + wxLogTrace(TRACE_MODULE, wxT("Registering module %s"), + classInfo->GetClassName()); + wxModule* module = (wxModule *)classInfo->CreateObject(); + RegisterModule(module); + } + node = wxClassInfo::sm_classTable->Next(); + } +} + +bool wxModule::DoInitializeModule(wxModule *module, + wxModuleList &initializedModules) +{ + if ( module->m_state == State_Initializing ) + { + wxLogError(_("Circular dependency involving module \"%s\" detected."), + module->GetClassInfo()->GetClassName()); + return false; + } + + module->m_state = State_Initializing; + + const wxArrayClassInfo& dependencies = module->m_dependencies; + + // satisfy module dependencies by loading them before the current module + for ( unsigned int i = 0; i < dependencies.size(); ++i ) + { + wxClassInfo * cinfo = dependencies[i]; + + // Check if the module is already initialized + wxModuleList::compatibility_iterator node; + for ( node = initializedModules.GetFirst(); node; node = node->GetNext() ) + { + if ( node->GetData()->GetClassInfo() == cinfo ) + break; + } + + if ( node ) + { + // this dependency is already initialized, nothing to do + continue; + } + + // find the module in the registered modules list + for ( node = m_modules.GetFirst(); node; node = node->GetNext() ) + { + wxModule *moduleDep = node->GetData(); + if ( moduleDep->GetClassInfo() == cinfo ) + { + if ( !DoInitializeModule(moduleDep, initializedModules ) ) + { + // failed to initialize a dependency, so fail this one too + return false; + } + + break; + } + } + + if ( !node ) + { + wxLogError(_("Dependency \"%s\" of module \"%s\" doesn't exist."), + cinfo->GetClassName(), + module->GetClassInfo()->GetClassName()); + return false; + } + } + + if ( !module->Init() ) + { + wxLogError(_("Module \"%s\" initialization failed"), + module->GetClassInfo()->GetClassName()); + return false; + } + + wxLogTrace(TRACE_MODULE, wxT("Module \"%s\" initialized"), + module->GetClassInfo()->GetClassName()); + + module->m_state = State_Initialized; + initializedModules.Append(module); + + return true; +} + +// Initialize user-defined modules +bool wxModule::InitializeModules() +{ + wxModuleList initializedModules; + + for ( wxModuleList::compatibility_iterator node = m_modules.GetFirst(); + node; + node = node->GetNext() ) + { + wxModule *module = node->GetData(); + + // the module could have been already initialized as dependency of + // another one + if ( module->m_state == State_Registered ) + { + if ( !DoInitializeModule( module, initializedModules ) ) + { + // failed to initialize all modules, so clean up the already + // initialized ones + DoCleanUpModules(initializedModules); + + return false; + } + } + } + + // remember the real initialisation order + m_modules = initializedModules; + + return true; +} + +// Clean up all currently initialized modules +void wxModule::DoCleanUpModules(const wxModuleList& modules) +{ + // cleanup user-defined modules in the reverse order compared to their + // initialization -- this ensures that dependencies are respected + for ( wxModuleList::compatibility_iterator node = modules.GetLast(); + node; + node = node->GetPrevious() ) + { + wxLogTrace(TRACE_MODULE, wxT("Cleanup module %s"), + node->GetData()->GetClassInfo()->GetClassName()); + + wxModule * module = node->GetData(); + + wxASSERT_MSG( module->m_state == State_Initialized, + _T("not initialized module being cleaned up") ); + + module->Exit(); + module->m_state = State_Registered; + } + + // clear all modules, even the non-initialized ones + WX_CLEAR_LIST(wxModuleList, m_modules); +} diff --git a/Externals/wxWidgets/src/common/msgout.cpp b/Externals/wxWidgets/src/common/msgout.cpp index 1b2026ba92..ebeed13be0 100644 --- a/Externals/wxWidgets/src/common/msgout.cpp +++ b/Externals/wxWidgets/src/common/msgout.cpp @@ -1,222 +1,222 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/msgout.cpp -// Purpose: wxMessageOutput implementation -// Author: Mattia Barbon -// Modified by: -// Created: 17.07.02 -// RCS-ID: $Id: msgout.cpp 38920 2006-04-26 08:21:31Z ABX $ -// Copyright: (c) the wxWidgets team -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// --------------------------------------------------------------------------- -// headers -// --------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#if defined(__BORLANDC__) - #pragma hdrstop -#endif - -#ifndef WX_PRECOMP - #include "wx/string.h" - #include "wx/ffile.h" - #include "wx/app.h" - #include "wx/intl.h" - #include "wx/log.h" - #if wxUSE_GUI - #include "wx/msgdlg.h" - #endif // wxUSE_GUI -#endif - -#include "wx/msgout.h" -#include "wx/apptrait.h" -#include -#include - -#if defined(__WINDOWS__) - #include "wx/msw/private.h" -#endif -#ifdef __WXMAC__ - #include "wx/mac/private.h" -#endif - -// =========================================================================== -// implementation -// =========================================================================== - -#if wxUSE_BASE - -// ---------------------------------------------------------------------------- -// wxMessageOutput -// ---------------------------------------------------------------------------- - -wxMessageOutput* wxMessageOutput::ms_msgOut = 0; - -wxMessageOutput* wxMessageOutput::Get() -{ - if ( !ms_msgOut && wxTheApp ) - { - ms_msgOut = wxTheApp->GetTraits()->CreateMessageOutput(); - } - - return ms_msgOut; -} - -wxMessageOutput* wxMessageOutput::Set(wxMessageOutput* msgout) -{ - wxMessageOutput* old = ms_msgOut; - ms_msgOut = msgout; - return old; -} - -// ---------------------------------------------------------------------------- -// wxMessageOutputBest -// ---------------------------------------------------------------------------- - -#ifdef __WINDOWS__ - -// check if we're running in a console under Windows -static inline bool IsInConsole() -{ -#ifdef __WXWINCE__ - return false; -#else // !__WXWINCE__ - HANDLE hStdErr = ::GetStdHandle(STD_ERROR_HANDLE); - return hStdErr && hStdErr != INVALID_HANDLE_VALUE; -#endif // __WXWINCE__/!__WXWINCE__ -} - -#endif // __WINDOWS__ - -void wxMessageOutputBest::Printf(const wxChar* format, ...) -{ - va_list args; - va_start(args, format); - wxString out; - - out.PrintfV(format, args); - va_end(args); - -#ifdef __WINDOWS__ - if ( !IsInConsole() ) - { - ::MessageBox(NULL, out, _T("wxWidgets"), MB_ICONINFORMATION | MB_OK); - } - else -#endif // __WINDOWS__/!__WINDOWS__ - { - fprintf(stderr, "%s", (const char*) out.mb_str()); - } -} - -// ---------------------------------------------------------------------------- -// wxMessageOutputStderr -// ---------------------------------------------------------------------------- - -void wxMessageOutputStderr::Printf(const wxChar* format, ...) -{ - va_list args; - va_start(args, format); - wxString out; - - out.PrintfV(format, args); - va_end(args); - - fprintf(stderr, "%s", (const char*) out.mb_str()); -} - -// ---------------------------------------------------------------------------- -// wxMessageOutputDebug -// ---------------------------------------------------------------------------- - -void wxMessageOutputDebug::Printf(const wxChar* format, ...) -{ - wxString out; - - va_list args; - va_start(args, format); - - out.PrintfV(format, args); - va_end(args); - -#if defined(__WXMSW__) && !defined(__WXMICROWIN__) - out.Replace(wxT("\t"), wxT(" ")); - out.Replace(wxT("\n"), wxT("\r\n")); - ::OutputDebugString(out); -#elif defined(__WXMAC__) && !defined(__DARWIN__) - if ( wxIsDebuggerRunning() ) - { - Str255 pstr; - wxString output = out + wxT(";g") ; - wxMacStringToPascal(output.c_str(), pstr); - - #ifdef __powerc - DebugStr(pstr); - #else - SysBreakStr(pstr); - #endif - } -#else - wxFputs( out , stderr ) ; - if ( out.Right(1) != wxT("\n") ) - wxFputs( wxT("\n") , stderr ) ; - fflush( stderr ) ; -#endif // platform -} - -// ---------------------------------------------------------------------------- -// wxMessageOutputLog -// ---------------------------------------------------------------------------- - -void wxMessageOutputLog::Printf(const wxChar* format, ...) -{ - wxString out; - - va_list args; - va_start(args, format); - - out.PrintfV(format, args); - va_end(args); - - out.Replace(wxT("\t"), wxT(" ")); - - ::wxLogMessage(wxT("%s"), out.c_str()); -} - -#endif // wxUSE_BASE - -// ---------------------------------------------------------------------------- -// wxMessageOutputMessageBox -// ---------------------------------------------------------------------------- - -#if wxUSE_GUI - -void wxMessageOutputMessageBox::Printf(const wxChar* format, ...) -{ - va_list args; - va_start(args, format); - wxString out; - - out.PrintfV(format, args); - va_end(args); - - // the native MSW msg box understands the TABs, others don't -#ifndef __WXMSW__ - out.Replace(wxT("\t"), wxT(" ")); -#endif - - wxString title; - if ( wxTheApp ) - title.Printf(_("%s message"), wxTheApp->GetAppName().c_str()); - - ::wxMessageBox(out, title); -} - -#endif // wxUSE_GUI +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/msgout.cpp +// Purpose: wxMessageOutput implementation +// Author: Mattia Barbon +// Modified by: +// Created: 17.07.02 +// RCS-ID: $Id: msgout.cpp 38920 2006-04-26 08:21:31Z ABX $ +// Copyright: (c) the wxWidgets team +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// --------------------------------------------------------------------------- +// headers +// --------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#if defined(__BORLANDC__) + #pragma hdrstop +#endif + +#ifndef WX_PRECOMP + #include "wx/string.h" + #include "wx/ffile.h" + #include "wx/app.h" + #include "wx/intl.h" + #include "wx/log.h" + #if wxUSE_GUI + #include "wx/msgdlg.h" + #endif // wxUSE_GUI +#endif + +#include "wx/msgout.h" +#include "wx/apptrait.h" +#include +#include + +#if defined(__WINDOWS__) + #include "wx/msw/private.h" +#endif +#ifdef __WXMAC__ + #include "wx/mac/private.h" +#endif + +// =========================================================================== +// implementation +// =========================================================================== + +#if wxUSE_BASE + +// ---------------------------------------------------------------------------- +// wxMessageOutput +// ---------------------------------------------------------------------------- + +wxMessageOutput* wxMessageOutput::ms_msgOut = 0; + +wxMessageOutput* wxMessageOutput::Get() +{ + if ( !ms_msgOut && wxTheApp ) + { + ms_msgOut = wxTheApp->GetTraits()->CreateMessageOutput(); + } + + return ms_msgOut; +} + +wxMessageOutput* wxMessageOutput::Set(wxMessageOutput* msgout) +{ + wxMessageOutput* old = ms_msgOut; + ms_msgOut = msgout; + return old; +} + +// ---------------------------------------------------------------------------- +// wxMessageOutputBest +// ---------------------------------------------------------------------------- + +#ifdef __WINDOWS__ + +// check if we're running in a console under Windows +static inline bool IsInConsole() +{ +#ifdef __WXWINCE__ + return false; +#else // !__WXWINCE__ + HANDLE hStdErr = ::GetStdHandle(STD_ERROR_HANDLE); + return hStdErr && hStdErr != INVALID_HANDLE_VALUE; +#endif // __WXWINCE__/!__WXWINCE__ +} + +#endif // __WINDOWS__ + +void wxMessageOutputBest::Printf(const wxChar* format, ...) +{ + va_list args; + va_start(args, format); + wxString out; + + out.PrintfV(format, args); + va_end(args); + +#ifdef __WINDOWS__ + if ( !IsInConsole() ) + { + ::MessageBox(NULL, out, _T("wxWidgets"), MB_ICONINFORMATION | MB_OK); + } + else +#endif // __WINDOWS__/!__WINDOWS__ + { + fprintf(stderr, "%s", (const char*) out.mb_str()); + } +} + +// ---------------------------------------------------------------------------- +// wxMessageOutputStderr +// ---------------------------------------------------------------------------- + +void wxMessageOutputStderr::Printf(const wxChar* format, ...) +{ + va_list args; + va_start(args, format); + wxString out; + + out.PrintfV(format, args); + va_end(args); + + fprintf(stderr, "%s", (const char*) out.mb_str()); +} + +// ---------------------------------------------------------------------------- +// wxMessageOutputDebug +// ---------------------------------------------------------------------------- + +void wxMessageOutputDebug::Printf(const wxChar* format, ...) +{ + wxString out; + + va_list args; + va_start(args, format); + + out.PrintfV(format, args); + va_end(args); + +#if defined(__WXMSW__) && !defined(__WXMICROWIN__) + out.Replace(wxT("\t"), wxT(" ")); + out.Replace(wxT("\n"), wxT("\r\n")); + ::OutputDebugString(out); +#elif defined(__WXMAC__) && !defined(__DARWIN__) + if ( wxIsDebuggerRunning() ) + { + Str255 pstr; + wxString output = out + wxT(";g") ; + wxMacStringToPascal(output.c_str(), pstr); + + #ifdef __powerc + DebugStr(pstr); + #else + SysBreakStr(pstr); + #endif + } +#else + wxFputs( out , stderr ) ; + if ( out.Right(1) != wxT("\n") ) + wxFputs( wxT("\n") , stderr ) ; + fflush( stderr ) ; +#endif // platform +} + +// ---------------------------------------------------------------------------- +// wxMessageOutputLog +// ---------------------------------------------------------------------------- + +void wxMessageOutputLog::Printf(const wxChar* format, ...) +{ + wxString out; + + va_list args; + va_start(args, format); + + out.PrintfV(format, args); + va_end(args); + + out.Replace(wxT("\t"), wxT(" ")); + + ::wxLogMessage(wxT("%s"), out.c_str()); +} + +#endif // wxUSE_BASE + +// ---------------------------------------------------------------------------- +// wxMessageOutputMessageBox +// ---------------------------------------------------------------------------- + +#if wxUSE_GUI + +void wxMessageOutputMessageBox::Printf(const wxChar* format, ...) +{ + va_list args; + va_start(args, format); + wxString out; + + out.PrintfV(format, args); + va_end(args); + + // the native MSW msg box understands the TABs, others don't +#ifndef __WXMSW__ + out.Replace(wxT("\t"), wxT(" ")); +#endif + + wxString title; + if ( wxTheApp ) + title.Printf(_("%s message"), wxTheApp->GetAppName().c_str()); + + ::wxMessageBox(out, title); +} + +#endif // wxUSE_GUI diff --git a/Externals/wxWidgets/src/common/mstream.cpp b/Externals/wxWidgets/src/common/mstream.cpp index 35aac92927..cbefd2a7c0 100644 --- a/Externals/wxWidgets/src/common/mstream.cpp +++ b/Externals/wxWidgets/src/common/mstream.cpp @@ -1,174 +1,174 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/mstream.cpp -// Purpose: "Memory stream" classes -// Author: Guilhem Lavaux -// Modified by: VZ (23.11.00): general code review -// Created: 04/01/98 -// RCS-ID: $Id: mstream.cpp 39001 2006-05-03 21:50:35Z ABX $ -// Copyright: (c) Guilhem Lavaux -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_STREAMS - -#include "wx/mstream.h" - -#ifndef WX_PRECOMP - #include "wx/stream.h" -#endif //WX_PRECOMP - -#include - -// ============================================================================ -// implementation -// ============================================================================ - -// ---------------------------------------------------------------------------- -// wxMemoryInputStream -// ---------------------------------------------------------------------------- - -wxMemoryInputStream::wxMemoryInputStream(const void *data, size_t len) -{ - m_i_streambuf = new wxStreamBuffer(wxStreamBuffer::read); - m_i_streambuf->SetBufferIO((void *)data, len); // const_cast - m_i_streambuf->SetIntPosition(0); // seek to start pos - m_i_streambuf->Fixed(true); - - m_length = len; -} - -wxMemoryInputStream::wxMemoryInputStream(const wxMemoryOutputStream& stream) -{ - const wxFileOffset lenFile = stream.GetLength(); - if ( lenFile == wxInvalidOffset ) - { - m_i_streambuf = NULL; - m_lasterror = wxSTREAM_EOF; - return; - } - - const size_t len = wx_truncate_cast(size_t, lenFile); - wxASSERT_MSG( len == lenFile + size_t(0), _T("huge files not supported") ); - - m_i_streambuf = new wxStreamBuffer(wxStreamBuffer::read); - m_i_streambuf->SetBufferIO(len); // create buffer - stream.CopyTo(m_i_streambuf->GetBufferStart(), len); - m_i_streambuf->SetIntPosition(0); // seek to start pos - m_i_streambuf->Fixed(true); - m_length = len; -} - -wxMemoryInputStream::~wxMemoryInputStream() -{ - delete m_i_streambuf; -} - -char wxMemoryInputStream::Peek() -{ - char *buf = (char *)m_i_streambuf->GetBufferStart(); - size_t pos = m_i_streambuf->GetIntPosition(); - if ( pos == m_length ) - { - m_lasterror = wxSTREAM_READ_ERROR; - - return 0; - } - - return buf[pos]; -} - -size_t wxMemoryInputStream::OnSysRead(void *buffer, size_t nbytes) -{ - size_t pos = m_i_streambuf->GetIntPosition(); - if ( pos == m_length ) - { - m_lasterror = wxSTREAM_EOF; - - return 0; - } - - m_i_streambuf->Read(buffer, nbytes); - m_lasterror = wxSTREAM_NO_ERROR; - - return m_i_streambuf->GetIntPosition() - pos; -} - -wxFileOffset wxMemoryInputStream::OnSysSeek(wxFileOffset pos, wxSeekMode mode) -{ - return m_i_streambuf->Seek(pos, mode); -} - -wxFileOffset wxMemoryInputStream::OnSysTell() const -{ - return m_i_streambuf->Tell(); -} - -// ---------------------------------------------------------------------------- -// wxMemoryOutputStream -// ---------------------------------------------------------------------------- - -wxMemoryOutputStream::wxMemoryOutputStream(void *data, size_t len) -{ - m_o_streambuf = new wxStreamBuffer(wxStreamBuffer::write); - if ( data ) - m_o_streambuf->SetBufferIO(data, len); - m_o_streambuf->Fixed(false); - m_o_streambuf->Flushable(false); -} - -wxMemoryOutputStream::~wxMemoryOutputStream() -{ - delete m_o_streambuf; -} - -size_t wxMemoryOutputStream::OnSysWrite(const void *buffer, size_t nbytes) -{ - size_t oldpos = m_o_streambuf->GetIntPosition(); - m_o_streambuf->Write(buffer, nbytes); - size_t newpos = m_o_streambuf->GetIntPosition(); - - // FIXME can someone please explain what this does? (VZ) - if ( !newpos ) - newpos = m_o_streambuf->GetBufferSize(); - - return newpos - oldpos; -} - -wxFileOffset wxMemoryOutputStream::OnSysSeek(wxFileOffset pos, wxSeekMode mode) -{ - return m_o_streambuf->Seek(pos, mode); -} - -wxFileOffset wxMemoryOutputStream::OnSysTell() const -{ - return m_o_streambuf->Tell(); -} - -size_t wxMemoryOutputStream::CopyTo(void *buffer, size_t len) const -{ - wxCHECK_MSG( buffer, 0, _T("must have buffer to CopyTo") ); - - if ( len > GetSize() ) - len = GetSize(); - - memcpy(buffer, m_o_streambuf->GetBufferStart(), len); - - return len; -} - -#endif // wxUSE_STREAMS +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/mstream.cpp +// Purpose: "Memory stream" classes +// Author: Guilhem Lavaux +// Modified by: VZ (23.11.00): general code review +// Created: 04/01/98 +// RCS-ID: $Id: mstream.cpp 39001 2006-05-03 21:50:35Z ABX $ +// Copyright: (c) Guilhem Lavaux +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_STREAMS + +#include "wx/mstream.h" + +#ifndef WX_PRECOMP + #include "wx/stream.h" +#endif //WX_PRECOMP + +#include + +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// wxMemoryInputStream +// ---------------------------------------------------------------------------- + +wxMemoryInputStream::wxMemoryInputStream(const void *data, size_t len) +{ + m_i_streambuf = new wxStreamBuffer(wxStreamBuffer::read); + m_i_streambuf->SetBufferIO((void *)data, len); // const_cast + m_i_streambuf->SetIntPosition(0); // seek to start pos + m_i_streambuf->Fixed(true); + + m_length = len; +} + +wxMemoryInputStream::wxMemoryInputStream(const wxMemoryOutputStream& stream) +{ + const wxFileOffset lenFile = stream.GetLength(); + if ( lenFile == wxInvalidOffset ) + { + m_i_streambuf = NULL; + m_lasterror = wxSTREAM_EOF; + return; + } + + const size_t len = wx_truncate_cast(size_t, lenFile); + wxASSERT_MSG( len == lenFile + size_t(0), _T("huge files not supported") ); + + m_i_streambuf = new wxStreamBuffer(wxStreamBuffer::read); + m_i_streambuf->SetBufferIO(len); // create buffer + stream.CopyTo(m_i_streambuf->GetBufferStart(), len); + m_i_streambuf->SetIntPosition(0); // seek to start pos + m_i_streambuf->Fixed(true); + m_length = len; +} + +wxMemoryInputStream::~wxMemoryInputStream() +{ + delete m_i_streambuf; +} + +char wxMemoryInputStream::Peek() +{ + char *buf = (char *)m_i_streambuf->GetBufferStart(); + size_t pos = m_i_streambuf->GetIntPosition(); + if ( pos == m_length ) + { + m_lasterror = wxSTREAM_READ_ERROR; + + return 0; + } + + return buf[pos]; +} + +size_t wxMemoryInputStream::OnSysRead(void *buffer, size_t nbytes) +{ + size_t pos = m_i_streambuf->GetIntPosition(); + if ( pos == m_length ) + { + m_lasterror = wxSTREAM_EOF; + + return 0; + } + + m_i_streambuf->Read(buffer, nbytes); + m_lasterror = wxSTREAM_NO_ERROR; + + return m_i_streambuf->GetIntPosition() - pos; +} + +wxFileOffset wxMemoryInputStream::OnSysSeek(wxFileOffset pos, wxSeekMode mode) +{ + return m_i_streambuf->Seek(pos, mode); +} + +wxFileOffset wxMemoryInputStream::OnSysTell() const +{ + return m_i_streambuf->Tell(); +} + +// ---------------------------------------------------------------------------- +// wxMemoryOutputStream +// ---------------------------------------------------------------------------- + +wxMemoryOutputStream::wxMemoryOutputStream(void *data, size_t len) +{ + m_o_streambuf = new wxStreamBuffer(wxStreamBuffer::write); + if ( data ) + m_o_streambuf->SetBufferIO(data, len); + m_o_streambuf->Fixed(false); + m_o_streambuf->Flushable(false); +} + +wxMemoryOutputStream::~wxMemoryOutputStream() +{ + delete m_o_streambuf; +} + +size_t wxMemoryOutputStream::OnSysWrite(const void *buffer, size_t nbytes) +{ + size_t oldpos = m_o_streambuf->GetIntPosition(); + m_o_streambuf->Write(buffer, nbytes); + size_t newpos = m_o_streambuf->GetIntPosition(); + + // FIXME can someone please explain what this does? (VZ) + if ( !newpos ) + newpos = m_o_streambuf->GetBufferSize(); + + return newpos - oldpos; +} + +wxFileOffset wxMemoryOutputStream::OnSysSeek(wxFileOffset pos, wxSeekMode mode) +{ + return m_o_streambuf->Seek(pos, mode); +} + +wxFileOffset wxMemoryOutputStream::OnSysTell() const +{ + return m_o_streambuf->Tell(); +} + +size_t wxMemoryOutputStream::CopyTo(void *buffer, size_t len) const +{ + wxCHECK_MSG( buffer, 0, _T("must have buffer to CopyTo") ); + + if ( len > GetSize() ) + len = GetSize(); + + memcpy(buffer, m_o_streambuf->GetBufferStart(), len); + + return len; +} + +#endif // wxUSE_STREAMS diff --git a/Externals/wxWidgets/src/common/nbkbase.cpp b/Externals/wxWidgets/src/common/nbkbase.cpp index b63c93585a..011f53e16a 100644 --- a/Externals/wxWidgets/src/common/nbkbase.cpp +++ b/Externals/wxWidgets/src/common/nbkbase.cpp @@ -1,84 +1,84 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: src/common/nbkbase.cpp -// Purpose: common wxNotebook methods -// Author: Vadim Zeitlin -// Modified by: -// Created: 02.07.01 -// RCS-ID: $Id: nbkbase.cpp 41764 2006-10-08 23:41:52Z VZ $ -// Copyright: (c) 2001 Vadim Zeitlin -// Licence: wxWindows licence -/////////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_NOTEBOOK - -#ifndef WX_PRECOMP -#endif //WX_PRECOMP - -#include "wx/notebook.h" - -// ============================================================================ -// implementation -// ============================================================================ - -// ---------------------------------------------------------------------------- -// geometry -// ---------------------------------------------------------------------------- - -wxSize wxNotebookBase::CalcSizeFromPage(const wxSize& sizePage) const -{ - // this is, of course, totally bogus -- but we must do something by - // default because not all ports implement this - wxSize sizeTotal = sizePage; - - if ( HasFlag(wxBK_LEFT) || HasFlag(wxBK_RIGHT) ) - { - sizeTotal.x += 90; - sizeTotal.y += 10; - } - else // tabs on top/bottom side - { - sizeTotal.x += 10; - sizeTotal.y += 40; - } - - return sizeTotal; -} - -// ---------------------------------------------------------------------------- -// events -// ---------------------------------------------------------------------------- - -bool wxNotebookBase::SendPageChangingEvent(int nPage) -{ - wxNotebookEvent event(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGING, GetId()); - event.SetSelection(nPage); - event.SetOldSelection(GetSelection()); - event.SetEventObject(this); - return !GetEventHandler()->ProcessEvent(event) || event.IsAllowed(); -} - -void wxNotebookBase::SendPageChangedEvent(int nPageOld, int nPageNew) -{ - wxNotebookEvent event(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED, GetId()); - event.SetSelection(nPageNew == -1 ? GetSelection() : nPageNew); - event.SetOldSelection(nPageOld); - event.SetEventObject(this); - GetEventHandler()->ProcessEvent(event); -} - -#endif // wxUSE_NOTEBOOK +/////////////////////////////////////////////////////////////////////////////// +// Name: src/common/nbkbase.cpp +// Purpose: common wxNotebook methods +// Author: Vadim Zeitlin +// Modified by: +// Created: 02.07.01 +// RCS-ID: $Id: nbkbase.cpp 41764 2006-10-08 23:41:52Z VZ $ +// Copyright: (c) 2001 Vadim Zeitlin +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_NOTEBOOK + +#ifndef WX_PRECOMP +#endif //WX_PRECOMP + +#include "wx/notebook.h" + +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// geometry +// ---------------------------------------------------------------------------- + +wxSize wxNotebookBase::CalcSizeFromPage(const wxSize& sizePage) const +{ + // this is, of course, totally bogus -- but we must do something by + // default because not all ports implement this + wxSize sizeTotal = sizePage; + + if ( HasFlag(wxBK_LEFT) || HasFlag(wxBK_RIGHT) ) + { + sizeTotal.x += 90; + sizeTotal.y += 10; + } + else // tabs on top/bottom side + { + sizeTotal.x += 10; + sizeTotal.y += 40; + } + + return sizeTotal; +} + +// ---------------------------------------------------------------------------- +// events +// ---------------------------------------------------------------------------- + +bool wxNotebookBase::SendPageChangingEvent(int nPage) +{ + wxNotebookEvent event(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGING, GetId()); + event.SetSelection(nPage); + event.SetOldSelection(GetSelection()); + event.SetEventObject(this); + return !GetEventHandler()->ProcessEvent(event) || event.IsAllowed(); +} + +void wxNotebookBase::SendPageChangedEvent(int nPageOld, int nPageNew) +{ + wxNotebookEvent event(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED, GetId()); + event.SetSelection(nPageNew == -1 ? GetSelection() : nPageNew); + event.SetOldSelection(nPageOld); + event.SetEventObject(this); + GetEventHandler()->ProcessEvent(event); +} + +#endif // wxUSE_NOTEBOOK diff --git a/Externals/wxWidgets/src/common/object.cpp b/Externals/wxWidgets/src/common/object.cpp index 6250513dc1..dc01ccf504 100644 --- a/Externals/wxWidgets/src/common/object.cpp +++ b/Externals/wxWidgets/src/common/object.cpp @@ -1,365 +1,365 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/object.cpp -// Purpose: wxObject implementation -// Author: Julian Smart -// Modified by: Ron Lee -// Created: 04/01/98 -// RCS-ID: $Id: object.cpp 40111 2006-07-15 22:21:44Z MW $ -// Copyright: (c) 1998 Julian Smart -// (c) 2001 Ron Lee -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#ifndef WX_PRECOMP - #include "wx/object.h" - #include "wx/hash.h" - #include "wx/memory.h" -#endif - -#include - -#if defined(__WXDEBUG__) || wxUSE_DEBUG_CONTEXT - #if defined(__VISAGECPP__) - #define DEBUG_PRINTF(NAME) { static int raz=0; \ - printf( #NAME " %i\n",raz); fflush(stdout); raz++; } - #else - #define DEBUG_PRINTF(NAME) - #endif -#endif // __WXDEBUG__ || wxUSE_DEBUG_CONTEXT - -// we must disable optimizations for VC.NET because otherwise its too eager -// linker discards wxClassInfo objects in release build thus breaking many, -// many things -#if defined __VISUALC__ && __VISUALC__ >= 1300 - #pragma optimize("", off) -#endif - -#if wxUSE_EXTENDED_RTTI -const wxClassInfo* wxObject::ms_classParents[] = { NULL } ; - wxObject* wxVariantToObjectConverterwxObject ( wxxVariant &data ) -{ return data.wxTEMPLATED_MEMBER_CALL(Get , wxObject*) ; } - wxObject* wxVariantOfPtrToObjectConverterwxObject ( wxxVariant &data ) -{ return &data.wxTEMPLATED_MEMBER_CALL(Get , wxObject) ; } - wxxVariant wxObjectToVariantConverterwxObject ( wxObject *data ) - { return wxxVariant( dynamic_cast (data) ) ; } - wxClassInfo wxObject::ms_classInfo(ms_classParents , wxEmptyString , wxT("wxObject"), - (int) sizeof(wxObject), \ - (wxObjectConstructorFn) 0 , - (wxPropertyInfo*) NULL,(wxHandlerInfo*) NULL,0 , 0 , - 0 , wxVariantOfPtrToObjectConverterwxObject , wxVariantToObjectConverterwxObject , wxObjectToVariantConverterwxObject); - template<> void wxStringReadValue(const wxString & , wxObject * & ){assert(0) ;} - template<> void wxStringWriteValue(wxString & , wxObject* const & ){assert(0) ;} - template<> void wxStringReadValue(const wxString & , wxObject & ){assert(0) ;} - template<> void wxStringWriteValue(wxString & , wxObject const & ){assert(0) ;} - wxClassTypeInfo s_typeInfo(wxT_OBJECT_PTR , &wxObject::ms_classInfo , NULL , NULL , typeid(wxObject*).name() ) ; - wxClassTypeInfo s_typeInfowxObject(wxT_OBJECT , &wxObject::ms_classInfo , NULL , NULL , typeid(wxObject).name() ) ; -#else -wxClassInfo wxObject::ms_classInfo( wxT("wxObject"), 0, 0, - (int) sizeof(wxObject), - (wxObjectConstructorFn) 0 ); -#endif - -// restore optimizations -#if defined __VISUALC__ && __VISUALC__ >= 1300 - #pragma optimize("", on) -#endif - -wxClassInfo* wxClassInfo::sm_first = NULL; -wxHashTable* wxClassInfo::sm_classTable = NULL; - -// when using XTI, this method is already implemented inline inside -// DECLARE_DYNAMIC_CLASS but otherwise we intentionally make this function -// non-inline because this allows us to have a non-inline virtual function in -// all wx classes and this solves linking problems for HP-UX native toolchain -// and possibly others (we could make dtor non-inline as well but it's more -// useful to keep it inline than this function) -#if !wxUSE_EXTENDED_RTTI - -wxClassInfo *wxObject::GetClassInfo() const -{ - return &wxObject::ms_classInfo; -} - -#endif // wxUSE_EXTENDED_RTTI - -// this variable exists only so that we can avoid 'always true/false' warnings -const bool wxFalse = false; - -// Is this object a kind of (a subclass of) 'info'? -// E.g. is wxWindow a kind of wxObject? -// Go from this class to superclass, taking into account -// two possible base classes. -bool wxObject::IsKindOf(wxClassInfo *info) const -{ - wxClassInfo *thisInfo = GetClassInfo(); - return (thisInfo) ? thisInfo->IsKindOf(info) : false ; -} - -#if defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING && defined( new ) - #undef new -#endif - - -#ifdef _WX_WANT_NEW_SIZET_WXCHAR_INT -void *wxObject::operator new ( size_t size, const wxChar *fileName, int lineNum ) -{ - return wxDebugAlloc(size, (wxChar*) fileName, lineNum, true); -} -#endif - -#ifdef _WX_WANT_DELETE_VOID -void wxObject::operator delete ( void *buf ) -{ - wxDebugFree(buf); -} -#endif - -#ifdef _WX_WANT_DELETE_VOID_CONSTCHAR_SIZET -void wxObject::operator delete ( void *buf, const char *_fname, size_t _line ) -{ - wxDebugFree(buf); -} -#endif - -#ifdef _WX_WANT_DELETE_VOID_WXCHAR_INT -void wxObject::operator delete ( void *buf, const wxChar *WXUNUSED(fileName), int WXUNUSED(lineNum) ) -{ - wxDebugFree(buf); -} -#endif - -#ifdef _WX_WANT_ARRAY_NEW_SIZET_WXCHAR_INT -void *wxObject::operator new[] ( size_t size, const wxChar* fileName, int lineNum ) -{ - return wxDebugAlloc(size, (wxChar*) fileName, lineNum, true, true); -} -#endif - -#ifdef _WX_WANT_ARRAY_DELETE_VOID -void wxObject::operator delete[] ( void *buf ) -{ - wxDebugFree(buf, true); -} -#endif - -#ifdef _WX_WANT_ARRAY_DELETE_VOID_WXCHAR_INT -void wxObject::operator delete[] (void * buf, const wxChar* WXUNUSED(fileName), int WXUNUSED(lineNum) ) -{ - wxDebugFree(buf, true); -} -#endif - - -// ---------------------------------------------------------------------------- -// wxClassInfo -// ---------------------------------------------------------------------------- - -wxClassInfo::~wxClassInfo() -{ - // remove this object from the linked list of all class infos: if we don't - // do it, loading/unloading a DLL containing static wxClassInfo objects is - // not going to work - if ( this == sm_first ) - { - sm_first = m_next; - } - else - { - wxClassInfo *info = sm_first; - while (info) - { - if ( info->m_next == this ) - { - info->m_next = m_next; - break; - } - - info = info->m_next; - } - } - Unregister(); -} - -wxClassInfo *wxClassInfo::FindClass(const wxChar *className) -{ - if ( sm_classTable ) - { - return (wxClassInfo *)wxClassInfo::sm_classTable->Get(className); - } - else - { - for ( wxClassInfo *info = sm_first; info ; info = info->m_next ) - { - if ( wxStrcmp(info->GetClassName(), className) == 0 ) - return info; - } - - return NULL; - } -} - -// This function wasn't written to be reentrant but there is a possiblity of -// reentrance if something it does causes a shared lib to load and register -// classes. On Solaris this happens when the wxHashTable is newed, so the first -// part of the function has been modified to handle it, and a wxASSERT checks -// against reentrance in the remainder of the function. - -void wxClassInfo::Register() -{ - if ( !sm_classTable ) - { - wxHashTable *classTable = new wxHashTable(wxKEY_STRING); - - // check for reentrance - if ( sm_classTable ) - delete classTable; - else - sm_classTable = classTable; - } - -#ifdef __WXDEBUG__ - // reentrance guard - see note above - static int entry = 0; - wxASSERT_MSG(++entry == 1, _T("wxClassInfo::Register() reentrance")); -#endif - - // Using IMPLEMENT_DYNAMIC_CLASS() macro twice (which may happen if you - // link any object module twice mistakenly, or link twice against wx shared - // library) will break this function because it will enter an infinite loop - // and eventually die with "out of memory" - as this is quite hard to - // detect if you're unaware of this, try to do some checks here. - wxASSERT_MSG( sm_classTable->Get(m_className) == NULL, - wxString::Format - ( - _T("Class \"%s\" already in RTTI table - have you used IMPLEMENT_DYNAMIC_CLASS() multiple times or linked some object file twice)?"), - m_className - ) - ); - - sm_classTable->Put(m_className, (wxObject *)this); - -#ifdef __WXDEBUG__ - --entry; -#endif -} - -void wxClassInfo::Unregister() -{ - if ( sm_classTable ) - { - sm_classTable->Delete(m_className); - if ( sm_classTable->GetCount() == 0 ) - { - delete sm_classTable; - sm_classTable = NULL; - } - } -} - -wxObject *wxCreateDynamicObject(const wxChar *name) -{ -#if defined(__WXDEBUG__) || wxUSE_DEBUG_CONTEXT - DEBUG_PRINTF(wxObject *wxCreateDynamicObject) -#endif - - if ( wxClassInfo::sm_classTable ) - { - wxClassInfo *info = (wxClassInfo *)wxClassInfo::sm_classTable->Get(name); - return info ? info->CreateObject() : NULL; - } - else // no sm_classTable yet - { - for ( wxClassInfo *info = wxClassInfo::sm_first; - info; - info = info->m_next ) - { - if (info->m_className && wxStrcmp(info->m_className, name) == 0) - return info->CreateObject(); - } - - return NULL; - } -} - - -// ---------------------------------------------------------------------------- -// wxObject -// ---------------------------------------------------------------------------- - -void wxObject::Ref(const wxObject& clone) -{ -#if defined(__WXDEBUG__) || wxUSE_DEBUG_CONTEXT - DEBUG_PRINTF(wxObject::Ref) -#endif - - // nothing to be done - if (m_refData == clone.m_refData) - return; - - // delete reference to old data - UnRef(); - - // reference new data - if ( clone.m_refData ) - { - m_refData = clone.m_refData; - ++(m_refData->m_count); - } -} - -void wxObject::UnRef() -{ - if ( m_refData ) - { - wxASSERT_MSG( m_refData->m_count > 0, _T("invalid ref data count") ); - - if ( --m_refData->m_count == 0 ) - delete m_refData; - m_refData = NULL; - } -} - -void wxObject::AllocExclusive() -{ - if ( !m_refData ) - { - m_refData = CreateRefData(); - } - else if ( m_refData->GetRefCount() > 1 ) - { - // note that ref is not going to be destroyed in this case - const wxObjectRefData* ref = m_refData; - UnRef(); - - // ... so we can still access it - m_refData = CloneRefData(ref); - } - //else: ref count is 1, we are exclusive owners of m_refData anyhow - - wxASSERT_MSG( m_refData && m_refData->GetRefCount() == 1, - _T("wxObject::AllocExclusive() failed.") ); -} - -wxObjectRefData *wxObject::CreateRefData() const -{ - // if you use AllocExclusive() you must override this method - wxFAIL_MSG( _T("CreateRefData() must be overridden if called!") ); - - return NULL; -} - -wxObjectRefData * -wxObject::CloneRefData(const wxObjectRefData * WXUNUSED(data)) const -{ - // if you use AllocExclusive() you must override this method - wxFAIL_MSG( _T("CloneRefData() must be overridden if called!") ); - - return NULL; -} +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/object.cpp +// Purpose: wxObject implementation +// Author: Julian Smart +// Modified by: Ron Lee +// Created: 04/01/98 +// RCS-ID: $Id: object.cpp 40111 2006-07-15 22:21:44Z MW $ +// Copyright: (c) 1998 Julian Smart +// (c) 2001 Ron Lee +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#ifndef WX_PRECOMP + #include "wx/object.h" + #include "wx/hash.h" + #include "wx/memory.h" +#endif + +#include + +#if defined(__WXDEBUG__) || wxUSE_DEBUG_CONTEXT + #if defined(__VISAGECPP__) + #define DEBUG_PRINTF(NAME) { static int raz=0; \ + printf( #NAME " %i\n",raz); fflush(stdout); raz++; } + #else + #define DEBUG_PRINTF(NAME) + #endif +#endif // __WXDEBUG__ || wxUSE_DEBUG_CONTEXT + +// we must disable optimizations for VC.NET because otherwise its too eager +// linker discards wxClassInfo objects in release build thus breaking many, +// many things +#if defined __VISUALC__ && __VISUALC__ >= 1300 + #pragma optimize("", off) +#endif + +#if wxUSE_EXTENDED_RTTI +const wxClassInfo* wxObject::ms_classParents[] = { NULL } ; + wxObject* wxVariantToObjectConverterwxObject ( wxxVariant &data ) +{ return data.wxTEMPLATED_MEMBER_CALL(Get , wxObject*) ; } + wxObject* wxVariantOfPtrToObjectConverterwxObject ( wxxVariant &data ) +{ return &data.wxTEMPLATED_MEMBER_CALL(Get , wxObject) ; } + wxxVariant wxObjectToVariantConverterwxObject ( wxObject *data ) + { return wxxVariant( dynamic_cast (data) ) ; } + wxClassInfo wxObject::ms_classInfo(ms_classParents , wxEmptyString , wxT("wxObject"), + (int) sizeof(wxObject), \ + (wxObjectConstructorFn) 0 , + (wxPropertyInfo*) NULL,(wxHandlerInfo*) NULL,0 , 0 , + 0 , wxVariantOfPtrToObjectConverterwxObject , wxVariantToObjectConverterwxObject , wxObjectToVariantConverterwxObject); + template<> void wxStringReadValue(const wxString & , wxObject * & ){assert(0) ;} + template<> void wxStringWriteValue(wxString & , wxObject* const & ){assert(0) ;} + template<> void wxStringReadValue(const wxString & , wxObject & ){assert(0) ;} + template<> void wxStringWriteValue(wxString & , wxObject const & ){assert(0) ;} + wxClassTypeInfo s_typeInfo(wxT_OBJECT_PTR , &wxObject::ms_classInfo , NULL , NULL , typeid(wxObject*).name() ) ; + wxClassTypeInfo s_typeInfowxObject(wxT_OBJECT , &wxObject::ms_classInfo , NULL , NULL , typeid(wxObject).name() ) ; +#else +wxClassInfo wxObject::ms_classInfo( wxT("wxObject"), 0, 0, + (int) sizeof(wxObject), + (wxObjectConstructorFn) 0 ); +#endif + +// restore optimizations +#if defined __VISUALC__ && __VISUALC__ >= 1300 + #pragma optimize("", on) +#endif + +wxClassInfo* wxClassInfo::sm_first = NULL; +wxHashTable* wxClassInfo::sm_classTable = NULL; + +// when using XTI, this method is already implemented inline inside +// DECLARE_DYNAMIC_CLASS but otherwise we intentionally make this function +// non-inline because this allows us to have a non-inline virtual function in +// all wx classes and this solves linking problems for HP-UX native toolchain +// and possibly others (we could make dtor non-inline as well but it's more +// useful to keep it inline than this function) +#if !wxUSE_EXTENDED_RTTI + +wxClassInfo *wxObject::GetClassInfo() const +{ + return &wxObject::ms_classInfo; +} + +#endif // wxUSE_EXTENDED_RTTI + +// this variable exists only so that we can avoid 'always true/false' warnings +const bool wxFalse = false; + +// Is this object a kind of (a subclass of) 'info'? +// E.g. is wxWindow a kind of wxObject? +// Go from this class to superclass, taking into account +// two possible base classes. +bool wxObject::IsKindOf(wxClassInfo *info) const +{ + wxClassInfo *thisInfo = GetClassInfo(); + return (thisInfo) ? thisInfo->IsKindOf(info) : false ; +} + +#if defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING && defined( new ) + #undef new +#endif + + +#ifdef _WX_WANT_NEW_SIZET_WXCHAR_INT +void *wxObject::operator new ( size_t size, const wxChar *fileName, int lineNum ) +{ + return wxDebugAlloc(size, (wxChar*) fileName, lineNum, true); +} +#endif + +#ifdef _WX_WANT_DELETE_VOID +void wxObject::operator delete ( void *buf ) +{ + wxDebugFree(buf); +} +#endif + +#ifdef _WX_WANT_DELETE_VOID_CONSTCHAR_SIZET +void wxObject::operator delete ( void *buf, const char *_fname, size_t _line ) +{ + wxDebugFree(buf); +} +#endif + +#ifdef _WX_WANT_DELETE_VOID_WXCHAR_INT +void wxObject::operator delete ( void *buf, const wxChar *WXUNUSED(fileName), int WXUNUSED(lineNum) ) +{ + wxDebugFree(buf); +} +#endif + +#ifdef _WX_WANT_ARRAY_NEW_SIZET_WXCHAR_INT +void *wxObject::operator new[] ( size_t size, const wxChar* fileName, int lineNum ) +{ + return wxDebugAlloc(size, (wxChar*) fileName, lineNum, true, true); +} +#endif + +#ifdef _WX_WANT_ARRAY_DELETE_VOID +void wxObject::operator delete[] ( void *buf ) +{ + wxDebugFree(buf, true); +} +#endif + +#ifdef _WX_WANT_ARRAY_DELETE_VOID_WXCHAR_INT +void wxObject::operator delete[] (void * buf, const wxChar* WXUNUSED(fileName), int WXUNUSED(lineNum) ) +{ + wxDebugFree(buf, true); +} +#endif + + +// ---------------------------------------------------------------------------- +// wxClassInfo +// ---------------------------------------------------------------------------- + +wxClassInfo::~wxClassInfo() +{ + // remove this object from the linked list of all class infos: if we don't + // do it, loading/unloading a DLL containing static wxClassInfo objects is + // not going to work + if ( this == sm_first ) + { + sm_first = m_next; + } + else + { + wxClassInfo *info = sm_first; + while (info) + { + if ( info->m_next == this ) + { + info->m_next = m_next; + break; + } + + info = info->m_next; + } + } + Unregister(); +} + +wxClassInfo *wxClassInfo::FindClass(const wxChar *className) +{ + if ( sm_classTable ) + { + return (wxClassInfo *)wxClassInfo::sm_classTable->Get(className); + } + else + { + for ( wxClassInfo *info = sm_first; info ; info = info->m_next ) + { + if ( wxStrcmp(info->GetClassName(), className) == 0 ) + return info; + } + + return NULL; + } +} + +// This function wasn't written to be reentrant but there is a possiblity of +// reentrance if something it does causes a shared lib to load and register +// classes. On Solaris this happens when the wxHashTable is newed, so the first +// part of the function has been modified to handle it, and a wxASSERT checks +// against reentrance in the remainder of the function. + +void wxClassInfo::Register() +{ + if ( !sm_classTable ) + { + wxHashTable *classTable = new wxHashTable(wxKEY_STRING); + + // check for reentrance + if ( sm_classTable ) + delete classTable; + else + sm_classTable = classTable; + } + +#ifdef __WXDEBUG__ + // reentrance guard - see note above + static int entry = 0; + wxASSERT_MSG(++entry == 1, _T("wxClassInfo::Register() reentrance")); +#endif + + // Using IMPLEMENT_DYNAMIC_CLASS() macro twice (which may happen if you + // link any object module twice mistakenly, or link twice against wx shared + // library) will break this function because it will enter an infinite loop + // and eventually die with "out of memory" - as this is quite hard to + // detect if you're unaware of this, try to do some checks here. + wxASSERT_MSG( sm_classTable->Get(m_className) == NULL, + wxString::Format + ( + _T("Class \"%s\" already in RTTI table - have you used IMPLEMENT_DYNAMIC_CLASS() multiple times or linked some object file twice)?"), + m_className + ) + ); + + sm_classTable->Put(m_className, (wxObject *)this); + +#ifdef __WXDEBUG__ + --entry; +#endif +} + +void wxClassInfo::Unregister() +{ + if ( sm_classTable ) + { + sm_classTable->Delete(m_className); + if ( sm_classTable->GetCount() == 0 ) + { + delete sm_classTable; + sm_classTable = NULL; + } + } +} + +wxObject *wxCreateDynamicObject(const wxChar *name) +{ +#if defined(__WXDEBUG__) || wxUSE_DEBUG_CONTEXT + DEBUG_PRINTF(wxObject *wxCreateDynamicObject) +#endif + + if ( wxClassInfo::sm_classTable ) + { + wxClassInfo *info = (wxClassInfo *)wxClassInfo::sm_classTable->Get(name); + return info ? info->CreateObject() : NULL; + } + else // no sm_classTable yet + { + for ( wxClassInfo *info = wxClassInfo::sm_first; + info; + info = info->m_next ) + { + if (info->m_className && wxStrcmp(info->m_className, name) == 0) + return info->CreateObject(); + } + + return NULL; + } +} + + +// ---------------------------------------------------------------------------- +// wxObject +// ---------------------------------------------------------------------------- + +void wxObject::Ref(const wxObject& clone) +{ +#if defined(__WXDEBUG__) || wxUSE_DEBUG_CONTEXT + DEBUG_PRINTF(wxObject::Ref) +#endif + + // nothing to be done + if (m_refData == clone.m_refData) + return; + + // delete reference to old data + UnRef(); + + // reference new data + if ( clone.m_refData ) + { + m_refData = clone.m_refData; + ++(m_refData->m_count); + } +} + +void wxObject::UnRef() +{ + if ( m_refData ) + { + wxASSERT_MSG( m_refData->m_count > 0, _T("invalid ref data count") ); + + if ( --m_refData->m_count == 0 ) + delete m_refData; + m_refData = NULL; + } +} + +void wxObject::AllocExclusive() +{ + if ( !m_refData ) + { + m_refData = CreateRefData(); + } + else if ( m_refData->GetRefCount() > 1 ) + { + // note that ref is not going to be destroyed in this case + const wxObjectRefData* ref = m_refData; + UnRef(); + + // ... so we can still access it + m_refData = CloneRefData(ref); + } + //else: ref count is 1, we are exclusive owners of m_refData anyhow + + wxASSERT_MSG( m_refData && m_refData->GetRefCount() == 1, + _T("wxObject::AllocExclusive() failed.") ); +} + +wxObjectRefData *wxObject::CreateRefData() const +{ + // if you use AllocExclusive() you must override this method + wxFAIL_MSG( _T("CreateRefData() must be overridden if called!") ); + + return NULL; +} + +wxObjectRefData * +wxObject::CloneRefData(const wxObjectRefData * WXUNUSED(data)) const +{ + // if you use AllocExclusive() you must override this method + wxFAIL_MSG( _T("CloneRefData() must be overridden if called!") ); + + return NULL; +} diff --git a/Externals/wxWidgets/src/common/overlaycmn.cpp b/Externals/wxWidgets/src/common/overlaycmn.cpp index d745289851..7867edb0ec 100644 --- a/Externals/wxWidgets/src/common/overlaycmn.cpp +++ b/Externals/wxWidgets/src/common/overlaycmn.cpp @@ -1,197 +1,197 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/overlaycmn.cpp -// Purpose: common wxOverlay code -// Author: Stefan Csomor -// Modified by: -// Created: 2006-10-20 -// RCS-ID: $Id: overlaycmn.cpp 42397 2006-10-25 12:12:56Z VS $ -// Copyright: (c) wxWidgets team -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#include "wx/overlay.h" -#include "wx/private/overlay.h" -#include "wx/dcclient.h" -#include "wx/dcmemory.h" - -// ============================================================================ -// implementation -// ============================================================================ - -// ---------------------------------------------------------------------------- -// wxOverlay -// ---------------------------------------------------------------------------- - -wxOverlay::wxOverlay() -{ - m_impl = new wxOverlayImpl(); - m_inDrawing = false; -} - -wxOverlay::~wxOverlay() -{ - delete m_impl; -} - -bool wxOverlay::IsOk() -{ - return m_impl->IsOk(); -} - -void wxOverlay::Init( wxWindowDC* dc, int x , int y , int width , int height ) -{ - m_impl->Init(dc, x, y, width, height); -} - -void wxOverlay::BeginDrawing( wxWindowDC* dc) -{ - m_impl->BeginDrawing(dc); - m_inDrawing = true ; -} - -void wxOverlay::EndDrawing( wxWindowDC* dc) -{ - m_impl->EndDrawing(dc); - m_inDrawing = false ; -} - -void wxOverlay::Clear( wxWindowDC* dc) -{ - m_impl->Clear(dc); -} - -void wxOverlay::Reset() -{ - wxASSERT_MSG(m_inDrawing==false,wxT("cannot reset overlay during drawing")); - m_impl->Reset(); -} - - -// ---------------------------------------------------------------------------- -// wxDCOverlay -// ---------------------------------------------------------------------------- - -wxDCOverlay::wxDCOverlay(wxOverlay &overlay, wxWindowDC *dc, int x , int y , int width , int height) : - m_overlay(overlay) -{ - Init(dc, x, y, width, height); -} - -wxDCOverlay::wxDCOverlay(wxOverlay &overlay, wxWindowDC *dc) : - m_overlay(overlay) -{ - int width; - int height; - dc->GetSize(&width,&height); - Init(dc, 0, 0, width, height); -} - -wxDCOverlay::~wxDCOverlay() -{ - m_overlay.EndDrawing(m_dc); -} - -void wxDCOverlay::Init(wxWindowDC *dc, int x , int y , int width , int height ) -{ - m_dc = dc ; - if ( !m_overlay.IsOk() ) - { - m_overlay.Init(dc,x,y,width,height); - } - m_overlay.BeginDrawing(dc); -} - -void wxDCOverlay::Clear() -{ - m_overlay.Clear(m_dc); -} - -// ---------------------------------------------------------------------------- -// generic implementation of wxOverlayImpl -// ---------------------------------------------------------------------------- - -#ifndef wxHAS_NATIVE_OVERLAY - -wxOverlayImpl::wxOverlayImpl() -{ -#if defined(__WXGTK__) || defined(__WXMSW__) - m_window = NULL ; -#endif - m_x = m_y = m_width = m_height = 0 ; -} - -wxOverlayImpl::~wxOverlayImpl() -{ -} - -bool wxOverlayImpl::IsOk() -{ - return m_bmpSaved.Ok() ; -} - -void wxOverlayImpl::Init( wxWindowDC* dc, int x , int y , int width , int height ) -{ -#if defined(__WXGTK__) - m_window = dc->m_owner; -#else - #if defined (__WXMSW__) - m_window = dc->GetWindow(); - #endif // __WXMSW__ - -#endif - wxMemoryDC dcMem ; - m_bmpSaved.Create( width, height ); - dcMem.SelectObject( m_bmpSaved ); - m_x = x ; - m_y = y ; - m_width = width ; - m_height = height ; -#if defined(__WXGTK__) && !defined(__WX_DC_BLIT_FIXED__) - wxPoint pt = dc->GetDeviceOrigin(); - x += pt.x; - y += pt.y; -#endif // broken wxGTK wxDC::Blit - dcMem.Blit(0, 0, m_width, m_height, - dc, x, y); - dcMem.SelectObject( wxNullBitmap ); -} - -void wxOverlayImpl::Clear(wxWindowDC* dc) -{ - wxMemoryDC dcMem ; - dcMem.SelectObject( m_bmpSaved ); - dc->Blit( m_x, m_y, m_width, m_height , &dcMem , 0 , 0 ); - dcMem.SelectObject( wxNullBitmap ); -} - -void wxOverlayImpl::Reset() -{ - m_bmpSaved = wxBitmap(); -} - -void wxOverlayImpl::BeginDrawing(wxWindowDC* WXUNUSED(dc)) -{ -} - -void wxOverlayImpl::EndDrawing(wxWindowDC* WXUNUSED(dc)) -{ -} - -#endif // !wxHAS_NATIVE_OVERLAY - - +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/overlaycmn.cpp +// Purpose: common wxOverlay code +// Author: Stefan Csomor +// Modified by: +// Created: 2006-10-20 +// RCS-ID: $Id: overlaycmn.cpp 42397 2006-10-25 12:12:56Z VS $ +// Copyright: (c) wxWidgets team +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#include "wx/overlay.h" +#include "wx/private/overlay.h" +#include "wx/dcclient.h" +#include "wx/dcmemory.h" + +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// wxOverlay +// ---------------------------------------------------------------------------- + +wxOverlay::wxOverlay() +{ + m_impl = new wxOverlayImpl(); + m_inDrawing = false; +} + +wxOverlay::~wxOverlay() +{ + delete m_impl; +} + +bool wxOverlay::IsOk() +{ + return m_impl->IsOk(); +} + +void wxOverlay::Init( wxWindowDC* dc, int x , int y , int width , int height ) +{ + m_impl->Init(dc, x, y, width, height); +} + +void wxOverlay::BeginDrawing( wxWindowDC* dc) +{ + m_impl->BeginDrawing(dc); + m_inDrawing = true ; +} + +void wxOverlay::EndDrawing( wxWindowDC* dc) +{ + m_impl->EndDrawing(dc); + m_inDrawing = false ; +} + +void wxOverlay::Clear( wxWindowDC* dc) +{ + m_impl->Clear(dc); +} + +void wxOverlay::Reset() +{ + wxASSERT_MSG(m_inDrawing==false,wxT("cannot reset overlay during drawing")); + m_impl->Reset(); +} + + +// ---------------------------------------------------------------------------- +// wxDCOverlay +// ---------------------------------------------------------------------------- + +wxDCOverlay::wxDCOverlay(wxOverlay &overlay, wxWindowDC *dc, int x , int y , int width , int height) : + m_overlay(overlay) +{ + Init(dc, x, y, width, height); +} + +wxDCOverlay::wxDCOverlay(wxOverlay &overlay, wxWindowDC *dc) : + m_overlay(overlay) +{ + int width; + int height; + dc->GetSize(&width,&height); + Init(dc, 0, 0, width, height); +} + +wxDCOverlay::~wxDCOverlay() +{ + m_overlay.EndDrawing(m_dc); +} + +void wxDCOverlay::Init(wxWindowDC *dc, int x , int y , int width , int height ) +{ + m_dc = dc ; + if ( !m_overlay.IsOk() ) + { + m_overlay.Init(dc,x,y,width,height); + } + m_overlay.BeginDrawing(dc); +} + +void wxDCOverlay::Clear() +{ + m_overlay.Clear(m_dc); +} + +// ---------------------------------------------------------------------------- +// generic implementation of wxOverlayImpl +// ---------------------------------------------------------------------------- + +#ifndef wxHAS_NATIVE_OVERLAY + +wxOverlayImpl::wxOverlayImpl() +{ +#if defined(__WXGTK__) || defined(__WXMSW__) + m_window = NULL ; +#endif + m_x = m_y = m_width = m_height = 0 ; +} + +wxOverlayImpl::~wxOverlayImpl() +{ +} + +bool wxOverlayImpl::IsOk() +{ + return m_bmpSaved.Ok() ; +} + +void wxOverlayImpl::Init( wxWindowDC* dc, int x , int y , int width , int height ) +{ +#if defined(__WXGTK__) + m_window = dc->m_owner; +#else + #if defined (__WXMSW__) + m_window = dc->GetWindow(); + #endif // __WXMSW__ + +#endif + wxMemoryDC dcMem ; + m_bmpSaved.Create( width, height ); + dcMem.SelectObject( m_bmpSaved ); + m_x = x ; + m_y = y ; + m_width = width ; + m_height = height ; +#if defined(__WXGTK__) && !defined(__WX_DC_BLIT_FIXED__) + wxPoint pt = dc->GetDeviceOrigin(); + x += pt.x; + y += pt.y; +#endif // broken wxGTK wxDC::Blit + dcMem.Blit(0, 0, m_width, m_height, + dc, x, y); + dcMem.SelectObject( wxNullBitmap ); +} + +void wxOverlayImpl::Clear(wxWindowDC* dc) +{ + wxMemoryDC dcMem ; + dcMem.SelectObject( m_bmpSaved ); + dc->Blit( m_x, m_y, m_width, m_height , &dcMem , 0 , 0 ); + dcMem.SelectObject( wxNullBitmap ); +} + +void wxOverlayImpl::Reset() +{ + m_bmpSaved = wxBitmap(); +} + +void wxOverlayImpl::BeginDrawing(wxWindowDC* WXUNUSED(dc)) +{ +} + +void wxOverlayImpl::EndDrawing(wxWindowDC* WXUNUSED(dc)) +{ +} + +#endif // !wxHAS_NATIVE_OVERLAY + + diff --git a/Externals/wxWidgets/src/common/paper.cpp b/Externals/wxWidgets/src/common/paper.cpp index 7e7997fcf3..e0a014230e 100644 --- a/Externals/wxWidgets/src/common/paper.cpp +++ b/Externals/wxWidgets/src/common/paper.cpp @@ -1,373 +1,373 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/paper.cpp -// Purpose: Paper size classes -// Author: Julian Smart -// Modified by: -// Created: 04/01/98 -// RCS-ID: $Id: paper.cpp 41054 2006-09-07 19:01:45Z ABX $ -// Copyright: (c) Julian Smart -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_PRINTING_ARCHITECTURE - -#ifndef WX_PRECOMP - #if defined(__WXMSW__) - #include "wx/msw/wrapcdlg.h" - #endif // MSW - #include "wx/utils.h" - #include "wx/settings.h" - #include "wx/intl.h" - #include "wx/module.h" -#endif - -#include "wx/paper.h" - -#include -#include - -#ifdef __WXMSW__ - #ifndef __WIN32__ - #include - #endif -#endif - // End __WXMSW__ - -IMPLEMENT_DYNAMIC_CLASS(wxPrintPaperType, wxObject) -// IMPLEMENT_DYNAMIC_CLASS(wxPrintPaperDatabase, wxList) - -/* - * Paper size database for all platforms - */ - -wxPrintPaperType::wxPrintPaperType() -{ - m_paperId = wxPAPER_NONE; - m_platformId = 0; - m_paperName = wxEmptyString; - m_width = 0; - m_height = 0; -} - -wxPrintPaperType::wxPrintPaperType(wxPaperSize paperId, int platformId, const wxString& name, int w, int h) -{ - m_paperId = paperId; - m_platformId = platformId; - m_paperName = name; - m_width = w; - m_height = h; -} - -// Get width and height in points (1/72th of an inch) -wxSize wxPrintPaperType::GetSizeDeviceUnits() const -{ - return wxSize( (int) ((m_width / 10.0) / (25.4 / 72.0)), (int) ((m_height / 10.0) / (25.4 / 72.0)) ); -} - -/* - * Print paper database for PostScript - */ - -WX_DECLARE_LIST(wxPrintPaperType, wxPrintPaperTypeList); -#include "wx/listimpl.cpp" -WX_DEFINE_LIST(wxPrintPaperTypeList) - -wxPrintPaperDatabase* wxThePrintPaperDatabase = (wxPrintPaperDatabase*) NULL; - -wxPrintPaperDatabase::wxPrintPaperDatabase() -{ - m_map = new wxStringToPrintPaperTypeHashMap; - m_list = new wxPrintPaperTypeList; -} - -wxPrintPaperDatabase::~wxPrintPaperDatabase() -{ - ClearDatabase(); -} - -void wxPrintPaperDatabase::CreateDatabase() -{ - WXADDPAPER(wxPAPER_LETTER, DMPAPER_LETTER, wxTRANSLATE("Letter, 8 1/2 x 11 in"), 2159, 2794); - WXADDPAPER(wxPAPER_LEGAL, DMPAPER_LEGAL, wxTRANSLATE("Legal, 8 1/2 x 14 in"), 2159, 3556); - WXADDPAPER(wxPAPER_A4, DMPAPER_A4, wxTRANSLATE("A4 sheet, 210 x 297 mm"), 2100, 2970); - WXADDPAPER(wxPAPER_CSHEET, DMPAPER_CSHEET, wxTRANSLATE("C sheet, 17 x 22 in"), 4318, 5588); - WXADDPAPER(wxPAPER_DSHEET, DMPAPER_DSHEET, wxTRANSLATE("D sheet, 22 x 34 in"), 5588, 8636); - WXADDPAPER(wxPAPER_ESHEET, DMPAPER_ESHEET, wxTRANSLATE("E sheet, 34 x 44 in"), 8636, 11176); - WXADDPAPER(wxPAPER_LETTERSMALL, DMPAPER_LETTERSMALL, wxTRANSLATE("Letter Small, 8 1/2 x 11 in"), 2159, 2794); - WXADDPAPER(wxPAPER_TABLOID, DMPAPER_TABLOID, wxTRANSLATE("Tabloid, 11 x 17 in"), 2794, 4318); - WXADDPAPER(wxPAPER_LEDGER, DMPAPER_LEDGER, wxTRANSLATE("Ledger, 17 x 11 in"), 4318, 2794); - WXADDPAPER(wxPAPER_STATEMENT, DMPAPER_STATEMENT, wxTRANSLATE("Statement, 5 1/2 x 8 1/2 in"), 1397, 2159); - WXADDPAPER(wxPAPER_EXECUTIVE, DMPAPER_EXECUTIVE, wxTRANSLATE("Executive, 7 1/4 x 10 1/2 in"), 1842, 2667); - WXADDPAPER(wxPAPER_A3, DMPAPER_A3, wxTRANSLATE("A3 sheet, 297 x 420 mm"), 2970, 4200); - WXADDPAPER(wxPAPER_A4SMALL, DMPAPER_A4SMALL, wxTRANSLATE("A4 small sheet, 210 x 297 mm"), 2100, 2970); - WXADDPAPER(wxPAPER_A5, DMPAPER_A5, wxTRANSLATE("A5 sheet, 148 x 210 mm"), 1480, 2100); - WXADDPAPER(wxPAPER_B4, DMPAPER_B4, wxTRANSLATE("B4 sheet, 250 x 354 mm"), 2500, 3540); - WXADDPAPER(wxPAPER_B5, DMPAPER_B5, wxTRANSLATE("B5 sheet, 182 x 257 millimeter"), 1820, 2570); - WXADDPAPER(wxPAPER_FOLIO, DMPAPER_FOLIO, wxTRANSLATE("Folio, 8 1/2 x 13 in"), 2159, 3302); - WXADDPAPER(wxPAPER_QUARTO, DMPAPER_QUARTO, wxTRANSLATE("Quarto, 215 x 275 mm"), 2150, 2750); - WXADDPAPER(wxPAPER_10X14, DMPAPER_10X14, wxTRANSLATE("10 x 14 in"), 2540, 3556); - WXADDPAPER(wxPAPER_11X17, DMPAPER_11X17, wxTRANSLATE("11 x 17 in"), 2794, 4318); - WXADDPAPER(wxPAPER_NOTE, DMPAPER_NOTE, wxTRANSLATE("Note, 8 1/2 x 11 in"), 2159, 2794); - WXADDPAPER(wxPAPER_ENV_9, DMPAPER_ENV_9, wxTRANSLATE("#9 Envelope, 3 7/8 x 8 7/8 in"), 984, 2254); - WXADDPAPER(wxPAPER_ENV_10, DMPAPER_ENV_10, wxTRANSLATE("#10 Envelope, 4 1/8 x 9 1/2 in"), 1048, 2413); - WXADDPAPER(wxPAPER_ENV_11, DMPAPER_ENV_11, wxTRANSLATE("#11 Envelope, 4 1/2 x 10 3/8 in"), 1143, 2635); - WXADDPAPER(wxPAPER_ENV_12, DMPAPER_ENV_12, wxTRANSLATE("#12 Envelope, 4 3/4 x 11 in"), 1206, 2794); - WXADDPAPER(wxPAPER_ENV_14, DMPAPER_ENV_14, wxTRANSLATE("#14 Envelope, 5 x 11 1/2 in"), 1270, 2921); - WXADDPAPER(wxPAPER_ENV_DL, DMPAPER_ENV_DL, wxTRANSLATE("DL Envelope, 110 x 220 mm"), 1100, 2200); - WXADDPAPER(wxPAPER_ENV_C5, DMPAPER_ENV_C5, wxTRANSLATE("C5 Envelope, 162 x 229 mm"), 1620, 2290); - WXADDPAPER(wxPAPER_ENV_C3, DMPAPER_ENV_C3, wxTRANSLATE("C3 Envelope, 324 x 458 mm"), 3240, 4580); - WXADDPAPER(wxPAPER_ENV_C4, DMPAPER_ENV_C4, wxTRANSLATE("C4 Envelope, 229 x 324 mm"), 2290, 3240); - WXADDPAPER(wxPAPER_ENV_C6, DMPAPER_ENV_C6, wxTRANSLATE("C6 Envelope, 114 x 162 mm"), 1140, 1620); - WXADDPAPER(wxPAPER_ENV_C65, DMPAPER_ENV_C65, wxTRANSLATE("C65 Envelope, 114 x 229 mm"), 1140, 2290); - WXADDPAPER(wxPAPER_ENV_B4, DMPAPER_ENV_B4, wxTRANSLATE("B4 Envelope, 250 x 353 mm"), 2500, 3530); - WXADDPAPER(wxPAPER_ENV_B5, DMPAPER_ENV_B5, wxTRANSLATE("B5 Envelope, 176 x 250 mm"), 1760, 2500); - WXADDPAPER(wxPAPER_ENV_B6, DMPAPER_ENV_B6, wxTRANSLATE("B6 Envelope, 176 x 125 mm"), 1760, 1250); - WXADDPAPER(wxPAPER_ENV_ITALY, DMPAPER_ENV_ITALY, wxTRANSLATE("Italy Envelope, 110 x 230 mm"), 1100, 2300); - WXADDPAPER(wxPAPER_ENV_MONARCH, DMPAPER_ENV_MONARCH, wxTRANSLATE("Monarch Envelope, 3 7/8 x 7 1/2 in"), 984, 1905); - WXADDPAPER(wxPAPER_ENV_PERSONAL, DMPAPER_ENV_PERSONAL, wxTRANSLATE("6 3/4 Envelope, 3 5/8 x 6 1/2 in"), 921, 1651); - WXADDPAPER(wxPAPER_FANFOLD_US, DMPAPER_FANFOLD_US, wxTRANSLATE("US Std Fanfold, 14 7/8 x 11 in"), 3778, 2794); - WXADDPAPER(wxPAPER_FANFOLD_STD_GERMAN, DMPAPER_FANFOLD_STD_GERMAN, wxTRANSLATE("German Std Fanfold, 8 1/2 x 12 in"), 2159, 3048); - WXADDPAPER(wxPAPER_FANFOLD_LGL_GERMAN, DMPAPER_FANFOLD_LGL_GERMAN, wxTRANSLATE("German Legal Fanfold, 8 1/2 x 13 in"), 2159, 3302); - - WXADDPAPER(wxPAPER_ISO_B4, DMPAPER_ISO_B4, wxTRANSLATE("B4 (ISO) 250 x 353 mm"), 2500, 2530); - WXADDPAPER(wxPAPER_JAPANESE_POSTCARD, DMPAPER_JAPANESE_POSTCARD, wxTRANSLATE("Japanese Postcard 100 x 148 mm"), 1000, 1480); - WXADDPAPER(wxPAPER_9X11, DMPAPER_9X11, wxTRANSLATE("9 x 11 in"), 2286, 2794); - WXADDPAPER(wxPAPER_10X11, DMPAPER_10X11, wxTRANSLATE("10 x 11 in"), 2540, 2794); - WXADDPAPER(wxPAPER_15X11, DMPAPER_15X11, wxTRANSLATE("15 x 11 in"), 3810, 2794); - WXADDPAPER(wxPAPER_ENV_INVITE, DMPAPER_ENV_INVITE, wxTRANSLATE("Envelope Invite 220 x 220 mm"), 2200, 2200); - WXADDPAPER(wxPAPER_LETTER_EXTRA, DMPAPER_LETTER_EXTRA, wxTRANSLATE("Letter Extra 9 1/2 x 12 in"), 2413, 3048); - WXADDPAPER(wxPAPER_LEGAL_EXTRA, DMPAPER_LEGAL_EXTRA, wxTRANSLATE("Legal Extra 9 1/2 x 15 in"), 2413, 3810); - WXADDPAPER(wxPAPER_TABLOID_EXTRA, DMPAPER_TABLOID_EXTRA, wxTRANSLATE("Tabloid Extra 11.69 x 18 in"), 2969, 4572); - WXADDPAPER(wxPAPER_A4_EXTRA, DMPAPER_A4_EXTRA, wxTRANSLATE("A4 Extra 9.27 x 12.69 in"), 2355, 3223); - WXADDPAPER(wxPAPER_LETTER_TRANSVERSE, DMPAPER_LETTER_TRANSVERSE, wxTRANSLATE("Letter Transverse 8 1/2 x 11 in"), 2159, 2794); - WXADDPAPER(wxPAPER_A4_TRANSVERSE, DMPAPER_A4_TRANSVERSE, wxTRANSLATE("A4 Transverse 210 x 297 mm"), 2100, 2970); - WXADDPAPER(wxPAPER_LETTER_EXTRA_TRANSVERSE, DMPAPER_LETTER_EXTRA_TRANSVERSE, wxTRANSLATE("Letter Extra Transverse 9.275 x 12 in"), 2355, 3048); - WXADDPAPER(wxPAPER_A_PLUS, DMPAPER_A_PLUS, wxTRANSLATE("SuperA/SuperA/A4 227 x 356 mm"), 2270, 3560); - WXADDPAPER(wxPAPER_B_PLUS, DMPAPER_B_PLUS, wxTRANSLATE("SuperB/SuperB/A3 305 x 487 mm"), 3050, 4870); - WXADDPAPER(wxPAPER_LETTER_PLUS, DMPAPER_LETTER_PLUS, wxTRANSLATE("Letter Plus 8 1/2 x 12.69 in"), 2159, 3223); - WXADDPAPER(wxPAPER_A4_PLUS, DMPAPER_A4_PLUS, wxTRANSLATE("A4 Plus 210 x 330 mm"), 2100, 3300); - WXADDPAPER(wxPAPER_A5_TRANSVERSE, DMPAPER_A5_TRANSVERSE, wxTRANSLATE("A5 Transverse 148 x 210 mm"), 1480, 2100); - WXADDPAPER(wxPAPER_B5_TRANSVERSE, DMPAPER_B5_TRANSVERSE, wxTRANSLATE("B5 (JIS) Transverse 182 x 257 mm"), 1820, 2570); - WXADDPAPER(wxPAPER_A3_EXTRA, DMPAPER_A3_EXTRA, wxTRANSLATE("A3 Extra 322 x 445 mm"), 3220, 4450); - WXADDPAPER(wxPAPER_A5_EXTRA, DMPAPER_A5_EXTRA, wxTRANSLATE("A5 Extra 174 x 235 mm"), 1740, 2350); - WXADDPAPER(wxPAPER_B5_EXTRA, DMPAPER_B5_EXTRA, wxTRANSLATE("B5 (ISO) Extra 201 x 276 mm"), 2010, 2760); - WXADDPAPER(wxPAPER_A2, DMPAPER_A2, wxTRANSLATE("A2 420 x 594 mm"), 4200, 5940); - WXADDPAPER(wxPAPER_A3_TRANSVERSE, DMPAPER_A3_TRANSVERSE, wxTRANSLATE("A3 Transverse 297 x 420 mm"), 2970, 4200); - WXADDPAPER(wxPAPER_A3_EXTRA_TRANSVERSE,DMPAPER_A3_EXTRA_TRANSVERSE,wxTRANSLATE("A3 Extra Transverse 322 x 445 mm"), 3220, 4450); - - WXADDPAPER(wxPAPER_DBL_JAPANESE_POSTCARD, 69, wxTRANSLATE("Japanese Double Postcard 200 x 148 mm"), 2000, 1480); - WXADDPAPER(wxPAPER_A6, 70, wxTRANSLATE("A6 105 x 148 mm"), 1050, 1480); - WXADDPAPER(wxPAPER_JENV_KAKU2, 71, wxTRANSLATE("Japanese Envelope Kaku #2"), 2400, 3320); - WXADDPAPER(wxPAPER_JENV_KAKU3, 72, wxTRANSLATE("Japanese Envelope Kaku #3"), 2160, 2770); - WXADDPAPER(wxPAPER_JENV_CHOU3, 73, wxTRANSLATE("Japanese Envelope Chou #3"), 1200, 2350); - WXADDPAPER(wxPAPER_JENV_CHOU4, 74, wxTRANSLATE("Japanese Envelope Chou #4"), 900, 2050); - WXADDPAPER(wxPAPER_LETTER_ROTATED, 75, wxTRANSLATE("Letter Rotated 11 x 8 1/2 in"), 2794, 2159); - WXADDPAPER(wxPAPER_A3_ROTATED, 76, wxTRANSLATE("A3 Rotated 420 x 297 mm"), 4200, 2970); - WXADDPAPER(wxPAPER_A4_ROTATED, 77, wxTRANSLATE("A4 Rotated 297 x 210 mm"), 2970, 2100); - WXADDPAPER(wxPAPER_A5_ROTATED, 78, wxTRANSLATE("A5 Rotated 210 x 148 mm"), 2100, 1480); - WXADDPAPER(wxPAPER_B4_JIS_ROTATED, 79, wxTRANSLATE("B4 (JIS) Rotated 364 x 257 mm"), 3640, 2570); - WXADDPAPER(wxPAPER_B5_JIS_ROTATED, 80, wxTRANSLATE("B5 (JIS) Rotated 257 x 182 mm"), 2570, 1820); - WXADDPAPER(wxPAPER_JAPANESE_POSTCARD_ROTATED, 81, wxTRANSLATE("Japanese Postcard Rotated 148 x 100 mm"), 1480, 1000); - WXADDPAPER(wxPAPER_DBL_JAPANESE_POSTCARD_ROTATED, 82, wxTRANSLATE("Double Japanese Postcard Rotated 148 x 200 mm"), 1480, 2000); - WXADDPAPER(wxPAPER_A6_ROTATED, 83, wxTRANSLATE("A6 Rotated 148 x 105 mm"), 1480, 1050); - WXADDPAPER(wxPAPER_JENV_KAKU2_ROTATED, 84, wxTRANSLATE("Japanese Envelope Kaku #2 Rotated"), 3320, 2400); - WXADDPAPER(wxPAPER_JENV_KAKU3_ROTATED, 85, wxTRANSLATE("Japanese Envelope Kaku #3 Rotated"), 2770, 2160); - WXADDPAPER(wxPAPER_JENV_CHOU3_ROTATED, 86, wxTRANSLATE("Japanese Envelope Chou #3 Rotated"), 2350, 1200); - WXADDPAPER(wxPAPER_JENV_CHOU4_ROTATED, 87, wxTRANSLATE("Japanese Envelope Chou #4 Rotated"), 2050, 900); - WXADDPAPER(wxPAPER_B6_JIS, 88, wxTRANSLATE("B6 (JIS) 128 x 182 mm"), 1280, 1820); - WXADDPAPER(wxPAPER_B6_JIS_ROTATED, 89, wxTRANSLATE("B6 (JIS) Rotated 182 x 128 mm"), 1920, 1280); - WXADDPAPER(wxPAPER_12X11, 90, wxTRANSLATE("12 x 11 in"), 3048, 2794); - WXADDPAPER(wxPAPER_JENV_YOU4, 91, wxTRANSLATE("Japanese Envelope You #4"), 2350, 1050); - WXADDPAPER(wxPAPER_JENV_YOU4_ROTATED, 92, wxTRANSLATE("Japanese Envelope You #4 Rotated"), 1050, 2350); - WXADDPAPER(wxPAPER_P16K, 93, wxTRANSLATE("PRC 16K 146 x 215 mm"), 1460, 2150); - WXADDPAPER(wxPAPER_P32K, 94, wxTRANSLATE("PRC 32K 97 x 151 mm"), 970, 1510); - WXADDPAPER(wxPAPER_P32KBIG, 95, wxTRANSLATE("PRC 32K(Big) 97 x 151 mm"), 970, 1510); - WXADDPAPER(wxPAPER_PENV_1, 96, wxTRANSLATE("PRC Envelope #1 102 x 165 mm"), 1020, 1650); - WXADDPAPER(wxPAPER_PENV_2, 97, wxTRANSLATE("PRC Envelope #2 102 x 176 mm"), 1020, 1760); - WXADDPAPER(wxPAPER_PENV_3, 98, wxTRANSLATE("PRC Envelope #3 125 x 176 mm"), 1250, 1760); - WXADDPAPER(wxPAPER_PENV_4, 99, wxTRANSLATE("PRC Envelope #4 110 x 208 mm"), 1100, 2080); - WXADDPAPER(wxPAPER_PENV_5, 100, wxTRANSLATE("PRC Envelope #5 110 x 220 mm"), 1100, 2200); - WXADDPAPER(wxPAPER_PENV_6, 101, wxTRANSLATE("PRC Envelope #6 120 x 230 mm"), 1200, 2300); - WXADDPAPER(wxPAPER_PENV_7, 102, wxTRANSLATE("PRC Envelope #7 160 x 230 mm"), 1600, 2300); - WXADDPAPER(wxPAPER_PENV_8, 103, wxTRANSLATE("PRC Envelope #8 120 x 309 mm"), 1200, 3090); - WXADDPAPER(wxPAPER_PENV_9, 104, wxTRANSLATE("PRC Envelope #9 229 x 324 mm"), 2290, 3240); - WXADDPAPER(wxPAPER_PENV_10, 105, wxTRANSLATE("PRC Envelope #10 324 x 458 mm"), 3240, 4580); - WXADDPAPER(wxPAPER_P16K_ROTATED, 106, wxTRANSLATE("PRC 16K Rotated"), 2150, 1460); - WXADDPAPER(wxPAPER_P32K_ROTATED, 107, wxTRANSLATE("PRC 32K Rotated"), 1510, 970); - WXADDPAPER(wxPAPER_P32KBIG_ROTATED, 108, wxTRANSLATE("PRC 32K(Big) Rotated"), 1510, 970); - WXADDPAPER(wxPAPER_PENV_1_ROTATED, 109, wxTRANSLATE("PRC Envelope #1 Rotated 165 x 102 mm"), 1650, 1020); - WXADDPAPER(wxPAPER_PENV_2_ROTATED, 110, wxTRANSLATE("PRC Envelope #2 Rotated 176 x 102 mm"), 1760, 1020); - WXADDPAPER(wxPAPER_PENV_3_ROTATED, 111, wxTRANSLATE("PRC Envelope #3 Rotated 176 x 125 mm"), 1760, 1250); - WXADDPAPER(wxPAPER_PENV_4_ROTATED, 112, wxTRANSLATE("PRC Envelope #4 Rotated 208 x 110 mm"), 2080, 1100); - WXADDPAPER(wxPAPER_PENV_5_ROTATED, 113, wxTRANSLATE("PRC Envelope #5 Rotated 220 x 110 mm"), 2200, 1100); - WXADDPAPER(wxPAPER_PENV_6_ROTATED, 114, wxTRANSLATE("PRC Envelope #6 Rotated 230 x 120 mm"), 2300, 1200); - WXADDPAPER(wxPAPER_PENV_7_ROTATED, 115, wxTRANSLATE("PRC Envelope #7 Rotated 230 x 160 mm"), 2300, 1600); - WXADDPAPER(wxPAPER_PENV_8_ROTATED, 116, wxTRANSLATE("PRC Envelope #8 Rotated 309 x 120 mm"), 3090, 1200); - WXADDPAPER(wxPAPER_PENV_9_ROTATED, 117, wxTRANSLATE("PRC Envelope #9 Rotated 324 x 229 mm"), 3240, 2290); - WXADDPAPER(wxPAPER_PENV_10_ROTATED, 118, wxTRANSLATE("PRC Envelope #10 Rotated 458 x 324 mm"), 4580, 3240); -} - -void wxPrintPaperDatabase::ClearDatabase() -{ - delete m_list; - WX_CLEAR_HASH_MAP(wxStringToPrintPaperTypeHashMap, *m_map); - delete m_map; -} - -void wxPrintPaperDatabase::AddPaperType(wxPaperSize paperId, const wxString& name, int w, int h) -{ - wxPrintPaperType* tmp = new wxPrintPaperType(paperId, 0, name, w, h); - (*m_map)[name] = tmp; - m_list->push_back(tmp); -} - -void wxPrintPaperDatabase::AddPaperType(wxPaperSize paperId, int platformId, const wxString& name, int w, int h) -{ - wxPrintPaperType* tmp = new wxPrintPaperType(paperId, platformId, name, w, h); - (*m_map)[name] = tmp; - m_list->push_back(tmp); -} - -wxPrintPaperType *wxPrintPaperDatabase::FindPaperType(const wxString& name) -{ - wxStringToPrintPaperTypeHashMap::iterator it = m_map->find(name); - if (it != m_map->end()) - return it->second; - else - return NULL; -} - -wxPrintPaperType *wxPrintPaperDatabase::FindPaperType(wxPaperSize id) -{ - typedef wxStringToPrintPaperTypeHashMap::iterator iterator; - - for (iterator it = m_map->begin(), en = m_map->end(); it != en; ++it) - { - wxPrintPaperType* paperType = it->second; - if (paperType->GetId() == id) - return paperType; - } - - return NULL; -} - -wxPrintPaperType *wxPrintPaperDatabase::FindPaperTypeByPlatformId(int id) -{ - typedef wxStringToPrintPaperTypeHashMap::iterator iterator; - - for (iterator it = m_map->begin(), en = m_map->end(); it != en; ++it) - { - wxPrintPaperType* paperType = it->second; - if (paperType->GetPlatformId() == id) - return paperType; - } - - return NULL; -} - -wxPrintPaperType *wxPrintPaperDatabase::FindPaperType(const wxSize& sz) -{ - typedef wxStringToPrintPaperTypeHashMap::iterator iterator; - - for (iterator it = m_map->begin(), en = m_map->end(); it != en; ++it) - { - wxPrintPaperType* paperType = it->second; - wxSize paperSize = paperType->GetSize() ; - if ( abs( paperSize.x - sz.x ) < 10 && abs( paperSize.y - sz.y ) < 10 ) - return paperType; - } - - return NULL; -} - -// Convert name to size id -wxPaperSize wxPrintPaperDatabase::ConvertNameToId(const wxString& name) -{ - wxPrintPaperType* type = FindPaperType(name); - if (type) - return type->GetId(); - else - return wxPAPER_NONE; -} - -// Convert size id to name -wxString wxPrintPaperDatabase::ConvertIdToName(wxPaperSize paperId) -{ - wxPrintPaperType* type = FindPaperType(paperId); - if (type) - return type->GetName(); - else - return wxEmptyString; -} - -// Get the paper size -wxSize wxPrintPaperDatabase::GetSize(wxPaperSize paperId) -{ - wxPrintPaperType* type = FindPaperType(paperId); - if (type) - return type->GetSize(); - else - return wxSize(0,0); -} - -// Get the paper size -wxPaperSize wxPrintPaperDatabase::GetSize(const wxSize& size) -{ - wxPrintPaperType* type = FindPaperType(size); - if (type) - return type->GetId(); - else - return wxPAPER_NONE; -} - -// QUICK and DIRTY -size_t wxPrintPaperDatabase::GetCount() const -{ - return m_list->GetCount(); -} - -wxPrintPaperType* wxPrintPaperDatabase::Item(size_t index) const -{ - return m_list->Item(index)->GetData(); -} - -// A module to allow initialization/cleanup of print paper -// things without calling these functions from app.cpp. - -class WXDLLEXPORT wxPrintPaperModule: public wxModule -{ -DECLARE_DYNAMIC_CLASS(wxPrintPaperModule) -public: - wxPrintPaperModule() {} - bool OnInit(); - void OnExit(); -}; - -IMPLEMENT_DYNAMIC_CLASS(wxPrintPaperModule, wxModule) - -/* - * Initialization/cleanup module - */ - -bool wxPrintPaperModule::OnInit() -{ - wxThePrintPaperDatabase = new wxPrintPaperDatabase; - wxThePrintPaperDatabase->CreateDatabase(); - - return true; -} - -void wxPrintPaperModule::OnExit() -{ - delete wxThePrintPaperDatabase; - wxThePrintPaperDatabase = NULL; -} - -#endif // wxUSE_PRINTING_ARCHITECTURE +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/paper.cpp +// Purpose: Paper size classes +// Author: Julian Smart +// Modified by: +// Created: 04/01/98 +// RCS-ID: $Id: paper.cpp 41054 2006-09-07 19:01:45Z ABX $ +// Copyright: (c) Julian Smart +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_PRINTING_ARCHITECTURE + +#ifndef WX_PRECOMP + #if defined(__WXMSW__) + #include "wx/msw/wrapcdlg.h" + #endif // MSW + #include "wx/utils.h" + #include "wx/settings.h" + #include "wx/intl.h" + #include "wx/module.h" +#endif + +#include "wx/paper.h" + +#include +#include + +#ifdef __WXMSW__ + #ifndef __WIN32__ + #include + #endif +#endif + // End __WXMSW__ + +IMPLEMENT_DYNAMIC_CLASS(wxPrintPaperType, wxObject) +// IMPLEMENT_DYNAMIC_CLASS(wxPrintPaperDatabase, wxList) + +/* + * Paper size database for all platforms + */ + +wxPrintPaperType::wxPrintPaperType() +{ + m_paperId = wxPAPER_NONE; + m_platformId = 0; + m_paperName = wxEmptyString; + m_width = 0; + m_height = 0; +} + +wxPrintPaperType::wxPrintPaperType(wxPaperSize paperId, int platformId, const wxString& name, int w, int h) +{ + m_paperId = paperId; + m_platformId = platformId; + m_paperName = name; + m_width = w; + m_height = h; +} + +// Get width and height in points (1/72th of an inch) +wxSize wxPrintPaperType::GetSizeDeviceUnits() const +{ + return wxSize( (int) ((m_width / 10.0) / (25.4 / 72.0)), (int) ((m_height / 10.0) / (25.4 / 72.0)) ); +} + +/* + * Print paper database for PostScript + */ + +WX_DECLARE_LIST(wxPrintPaperType, wxPrintPaperTypeList); +#include "wx/listimpl.cpp" +WX_DEFINE_LIST(wxPrintPaperTypeList) + +wxPrintPaperDatabase* wxThePrintPaperDatabase = (wxPrintPaperDatabase*) NULL; + +wxPrintPaperDatabase::wxPrintPaperDatabase() +{ + m_map = new wxStringToPrintPaperTypeHashMap; + m_list = new wxPrintPaperTypeList; +} + +wxPrintPaperDatabase::~wxPrintPaperDatabase() +{ + ClearDatabase(); +} + +void wxPrintPaperDatabase::CreateDatabase() +{ + WXADDPAPER(wxPAPER_LETTER, DMPAPER_LETTER, wxTRANSLATE("Letter, 8 1/2 x 11 in"), 2159, 2794); + WXADDPAPER(wxPAPER_LEGAL, DMPAPER_LEGAL, wxTRANSLATE("Legal, 8 1/2 x 14 in"), 2159, 3556); + WXADDPAPER(wxPAPER_A4, DMPAPER_A4, wxTRANSLATE("A4 sheet, 210 x 297 mm"), 2100, 2970); + WXADDPAPER(wxPAPER_CSHEET, DMPAPER_CSHEET, wxTRANSLATE("C sheet, 17 x 22 in"), 4318, 5588); + WXADDPAPER(wxPAPER_DSHEET, DMPAPER_DSHEET, wxTRANSLATE("D sheet, 22 x 34 in"), 5588, 8636); + WXADDPAPER(wxPAPER_ESHEET, DMPAPER_ESHEET, wxTRANSLATE("E sheet, 34 x 44 in"), 8636, 11176); + WXADDPAPER(wxPAPER_LETTERSMALL, DMPAPER_LETTERSMALL, wxTRANSLATE("Letter Small, 8 1/2 x 11 in"), 2159, 2794); + WXADDPAPER(wxPAPER_TABLOID, DMPAPER_TABLOID, wxTRANSLATE("Tabloid, 11 x 17 in"), 2794, 4318); + WXADDPAPER(wxPAPER_LEDGER, DMPAPER_LEDGER, wxTRANSLATE("Ledger, 17 x 11 in"), 4318, 2794); + WXADDPAPER(wxPAPER_STATEMENT, DMPAPER_STATEMENT, wxTRANSLATE("Statement, 5 1/2 x 8 1/2 in"), 1397, 2159); + WXADDPAPER(wxPAPER_EXECUTIVE, DMPAPER_EXECUTIVE, wxTRANSLATE("Executive, 7 1/4 x 10 1/2 in"), 1842, 2667); + WXADDPAPER(wxPAPER_A3, DMPAPER_A3, wxTRANSLATE("A3 sheet, 297 x 420 mm"), 2970, 4200); + WXADDPAPER(wxPAPER_A4SMALL, DMPAPER_A4SMALL, wxTRANSLATE("A4 small sheet, 210 x 297 mm"), 2100, 2970); + WXADDPAPER(wxPAPER_A5, DMPAPER_A5, wxTRANSLATE("A5 sheet, 148 x 210 mm"), 1480, 2100); + WXADDPAPER(wxPAPER_B4, DMPAPER_B4, wxTRANSLATE("B4 sheet, 250 x 354 mm"), 2500, 3540); + WXADDPAPER(wxPAPER_B5, DMPAPER_B5, wxTRANSLATE("B5 sheet, 182 x 257 millimeter"), 1820, 2570); + WXADDPAPER(wxPAPER_FOLIO, DMPAPER_FOLIO, wxTRANSLATE("Folio, 8 1/2 x 13 in"), 2159, 3302); + WXADDPAPER(wxPAPER_QUARTO, DMPAPER_QUARTO, wxTRANSLATE("Quarto, 215 x 275 mm"), 2150, 2750); + WXADDPAPER(wxPAPER_10X14, DMPAPER_10X14, wxTRANSLATE("10 x 14 in"), 2540, 3556); + WXADDPAPER(wxPAPER_11X17, DMPAPER_11X17, wxTRANSLATE("11 x 17 in"), 2794, 4318); + WXADDPAPER(wxPAPER_NOTE, DMPAPER_NOTE, wxTRANSLATE("Note, 8 1/2 x 11 in"), 2159, 2794); + WXADDPAPER(wxPAPER_ENV_9, DMPAPER_ENV_9, wxTRANSLATE("#9 Envelope, 3 7/8 x 8 7/8 in"), 984, 2254); + WXADDPAPER(wxPAPER_ENV_10, DMPAPER_ENV_10, wxTRANSLATE("#10 Envelope, 4 1/8 x 9 1/2 in"), 1048, 2413); + WXADDPAPER(wxPAPER_ENV_11, DMPAPER_ENV_11, wxTRANSLATE("#11 Envelope, 4 1/2 x 10 3/8 in"), 1143, 2635); + WXADDPAPER(wxPAPER_ENV_12, DMPAPER_ENV_12, wxTRANSLATE("#12 Envelope, 4 3/4 x 11 in"), 1206, 2794); + WXADDPAPER(wxPAPER_ENV_14, DMPAPER_ENV_14, wxTRANSLATE("#14 Envelope, 5 x 11 1/2 in"), 1270, 2921); + WXADDPAPER(wxPAPER_ENV_DL, DMPAPER_ENV_DL, wxTRANSLATE("DL Envelope, 110 x 220 mm"), 1100, 2200); + WXADDPAPER(wxPAPER_ENV_C5, DMPAPER_ENV_C5, wxTRANSLATE("C5 Envelope, 162 x 229 mm"), 1620, 2290); + WXADDPAPER(wxPAPER_ENV_C3, DMPAPER_ENV_C3, wxTRANSLATE("C3 Envelope, 324 x 458 mm"), 3240, 4580); + WXADDPAPER(wxPAPER_ENV_C4, DMPAPER_ENV_C4, wxTRANSLATE("C4 Envelope, 229 x 324 mm"), 2290, 3240); + WXADDPAPER(wxPAPER_ENV_C6, DMPAPER_ENV_C6, wxTRANSLATE("C6 Envelope, 114 x 162 mm"), 1140, 1620); + WXADDPAPER(wxPAPER_ENV_C65, DMPAPER_ENV_C65, wxTRANSLATE("C65 Envelope, 114 x 229 mm"), 1140, 2290); + WXADDPAPER(wxPAPER_ENV_B4, DMPAPER_ENV_B4, wxTRANSLATE("B4 Envelope, 250 x 353 mm"), 2500, 3530); + WXADDPAPER(wxPAPER_ENV_B5, DMPAPER_ENV_B5, wxTRANSLATE("B5 Envelope, 176 x 250 mm"), 1760, 2500); + WXADDPAPER(wxPAPER_ENV_B6, DMPAPER_ENV_B6, wxTRANSLATE("B6 Envelope, 176 x 125 mm"), 1760, 1250); + WXADDPAPER(wxPAPER_ENV_ITALY, DMPAPER_ENV_ITALY, wxTRANSLATE("Italy Envelope, 110 x 230 mm"), 1100, 2300); + WXADDPAPER(wxPAPER_ENV_MONARCH, DMPAPER_ENV_MONARCH, wxTRANSLATE("Monarch Envelope, 3 7/8 x 7 1/2 in"), 984, 1905); + WXADDPAPER(wxPAPER_ENV_PERSONAL, DMPAPER_ENV_PERSONAL, wxTRANSLATE("6 3/4 Envelope, 3 5/8 x 6 1/2 in"), 921, 1651); + WXADDPAPER(wxPAPER_FANFOLD_US, DMPAPER_FANFOLD_US, wxTRANSLATE("US Std Fanfold, 14 7/8 x 11 in"), 3778, 2794); + WXADDPAPER(wxPAPER_FANFOLD_STD_GERMAN, DMPAPER_FANFOLD_STD_GERMAN, wxTRANSLATE("German Std Fanfold, 8 1/2 x 12 in"), 2159, 3048); + WXADDPAPER(wxPAPER_FANFOLD_LGL_GERMAN, DMPAPER_FANFOLD_LGL_GERMAN, wxTRANSLATE("German Legal Fanfold, 8 1/2 x 13 in"), 2159, 3302); + + WXADDPAPER(wxPAPER_ISO_B4, DMPAPER_ISO_B4, wxTRANSLATE("B4 (ISO) 250 x 353 mm"), 2500, 2530); + WXADDPAPER(wxPAPER_JAPANESE_POSTCARD, DMPAPER_JAPANESE_POSTCARD, wxTRANSLATE("Japanese Postcard 100 x 148 mm"), 1000, 1480); + WXADDPAPER(wxPAPER_9X11, DMPAPER_9X11, wxTRANSLATE("9 x 11 in"), 2286, 2794); + WXADDPAPER(wxPAPER_10X11, DMPAPER_10X11, wxTRANSLATE("10 x 11 in"), 2540, 2794); + WXADDPAPER(wxPAPER_15X11, DMPAPER_15X11, wxTRANSLATE("15 x 11 in"), 3810, 2794); + WXADDPAPER(wxPAPER_ENV_INVITE, DMPAPER_ENV_INVITE, wxTRANSLATE("Envelope Invite 220 x 220 mm"), 2200, 2200); + WXADDPAPER(wxPAPER_LETTER_EXTRA, DMPAPER_LETTER_EXTRA, wxTRANSLATE("Letter Extra 9 1/2 x 12 in"), 2413, 3048); + WXADDPAPER(wxPAPER_LEGAL_EXTRA, DMPAPER_LEGAL_EXTRA, wxTRANSLATE("Legal Extra 9 1/2 x 15 in"), 2413, 3810); + WXADDPAPER(wxPAPER_TABLOID_EXTRA, DMPAPER_TABLOID_EXTRA, wxTRANSLATE("Tabloid Extra 11.69 x 18 in"), 2969, 4572); + WXADDPAPER(wxPAPER_A4_EXTRA, DMPAPER_A4_EXTRA, wxTRANSLATE("A4 Extra 9.27 x 12.69 in"), 2355, 3223); + WXADDPAPER(wxPAPER_LETTER_TRANSVERSE, DMPAPER_LETTER_TRANSVERSE, wxTRANSLATE("Letter Transverse 8 1/2 x 11 in"), 2159, 2794); + WXADDPAPER(wxPAPER_A4_TRANSVERSE, DMPAPER_A4_TRANSVERSE, wxTRANSLATE("A4 Transverse 210 x 297 mm"), 2100, 2970); + WXADDPAPER(wxPAPER_LETTER_EXTRA_TRANSVERSE, DMPAPER_LETTER_EXTRA_TRANSVERSE, wxTRANSLATE("Letter Extra Transverse 9.275 x 12 in"), 2355, 3048); + WXADDPAPER(wxPAPER_A_PLUS, DMPAPER_A_PLUS, wxTRANSLATE("SuperA/SuperA/A4 227 x 356 mm"), 2270, 3560); + WXADDPAPER(wxPAPER_B_PLUS, DMPAPER_B_PLUS, wxTRANSLATE("SuperB/SuperB/A3 305 x 487 mm"), 3050, 4870); + WXADDPAPER(wxPAPER_LETTER_PLUS, DMPAPER_LETTER_PLUS, wxTRANSLATE("Letter Plus 8 1/2 x 12.69 in"), 2159, 3223); + WXADDPAPER(wxPAPER_A4_PLUS, DMPAPER_A4_PLUS, wxTRANSLATE("A4 Plus 210 x 330 mm"), 2100, 3300); + WXADDPAPER(wxPAPER_A5_TRANSVERSE, DMPAPER_A5_TRANSVERSE, wxTRANSLATE("A5 Transverse 148 x 210 mm"), 1480, 2100); + WXADDPAPER(wxPAPER_B5_TRANSVERSE, DMPAPER_B5_TRANSVERSE, wxTRANSLATE("B5 (JIS) Transverse 182 x 257 mm"), 1820, 2570); + WXADDPAPER(wxPAPER_A3_EXTRA, DMPAPER_A3_EXTRA, wxTRANSLATE("A3 Extra 322 x 445 mm"), 3220, 4450); + WXADDPAPER(wxPAPER_A5_EXTRA, DMPAPER_A5_EXTRA, wxTRANSLATE("A5 Extra 174 x 235 mm"), 1740, 2350); + WXADDPAPER(wxPAPER_B5_EXTRA, DMPAPER_B5_EXTRA, wxTRANSLATE("B5 (ISO) Extra 201 x 276 mm"), 2010, 2760); + WXADDPAPER(wxPAPER_A2, DMPAPER_A2, wxTRANSLATE("A2 420 x 594 mm"), 4200, 5940); + WXADDPAPER(wxPAPER_A3_TRANSVERSE, DMPAPER_A3_TRANSVERSE, wxTRANSLATE("A3 Transverse 297 x 420 mm"), 2970, 4200); + WXADDPAPER(wxPAPER_A3_EXTRA_TRANSVERSE,DMPAPER_A3_EXTRA_TRANSVERSE,wxTRANSLATE("A3 Extra Transverse 322 x 445 mm"), 3220, 4450); + + WXADDPAPER(wxPAPER_DBL_JAPANESE_POSTCARD, 69, wxTRANSLATE("Japanese Double Postcard 200 x 148 mm"), 2000, 1480); + WXADDPAPER(wxPAPER_A6, 70, wxTRANSLATE("A6 105 x 148 mm"), 1050, 1480); + WXADDPAPER(wxPAPER_JENV_KAKU2, 71, wxTRANSLATE("Japanese Envelope Kaku #2"), 2400, 3320); + WXADDPAPER(wxPAPER_JENV_KAKU3, 72, wxTRANSLATE("Japanese Envelope Kaku #3"), 2160, 2770); + WXADDPAPER(wxPAPER_JENV_CHOU3, 73, wxTRANSLATE("Japanese Envelope Chou #3"), 1200, 2350); + WXADDPAPER(wxPAPER_JENV_CHOU4, 74, wxTRANSLATE("Japanese Envelope Chou #4"), 900, 2050); + WXADDPAPER(wxPAPER_LETTER_ROTATED, 75, wxTRANSLATE("Letter Rotated 11 x 8 1/2 in"), 2794, 2159); + WXADDPAPER(wxPAPER_A3_ROTATED, 76, wxTRANSLATE("A3 Rotated 420 x 297 mm"), 4200, 2970); + WXADDPAPER(wxPAPER_A4_ROTATED, 77, wxTRANSLATE("A4 Rotated 297 x 210 mm"), 2970, 2100); + WXADDPAPER(wxPAPER_A5_ROTATED, 78, wxTRANSLATE("A5 Rotated 210 x 148 mm"), 2100, 1480); + WXADDPAPER(wxPAPER_B4_JIS_ROTATED, 79, wxTRANSLATE("B4 (JIS) Rotated 364 x 257 mm"), 3640, 2570); + WXADDPAPER(wxPAPER_B5_JIS_ROTATED, 80, wxTRANSLATE("B5 (JIS) Rotated 257 x 182 mm"), 2570, 1820); + WXADDPAPER(wxPAPER_JAPANESE_POSTCARD_ROTATED, 81, wxTRANSLATE("Japanese Postcard Rotated 148 x 100 mm"), 1480, 1000); + WXADDPAPER(wxPAPER_DBL_JAPANESE_POSTCARD_ROTATED, 82, wxTRANSLATE("Double Japanese Postcard Rotated 148 x 200 mm"), 1480, 2000); + WXADDPAPER(wxPAPER_A6_ROTATED, 83, wxTRANSLATE("A6 Rotated 148 x 105 mm"), 1480, 1050); + WXADDPAPER(wxPAPER_JENV_KAKU2_ROTATED, 84, wxTRANSLATE("Japanese Envelope Kaku #2 Rotated"), 3320, 2400); + WXADDPAPER(wxPAPER_JENV_KAKU3_ROTATED, 85, wxTRANSLATE("Japanese Envelope Kaku #3 Rotated"), 2770, 2160); + WXADDPAPER(wxPAPER_JENV_CHOU3_ROTATED, 86, wxTRANSLATE("Japanese Envelope Chou #3 Rotated"), 2350, 1200); + WXADDPAPER(wxPAPER_JENV_CHOU4_ROTATED, 87, wxTRANSLATE("Japanese Envelope Chou #4 Rotated"), 2050, 900); + WXADDPAPER(wxPAPER_B6_JIS, 88, wxTRANSLATE("B6 (JIS) 128 x 182 mm"), 1280, 1820); + WXADDPAPER(wxPAPER_B6_JIS_ROTATED, 89, wxTRANSLATE("B6 (JIS) Rotated 182 x 128 mm"), 1920, 1280); + WXADDPAPER(wxPAPER_12X11, 90, wxTRANSLATE("12 x 11 in"), 3048, 2794); + WXADDPAPER(wxPAPER_JENV_YOU4, 91, wxTRANSLATE("Japanese Envelope You #4"), 2350, 1050); + WXADDPAPER(wxPAPER_JENV_YOU4_ROTATED, 92, wxTRANSLATE("Japanese Envelope You #4 Rotated"), 1050, 2350); + WXADDPAPER(wxPAPER_P16K, 93, wxTRANSLATE("PRC 16K 146 x 215 mm"), 1460, 2150); + WXADDPAPER(wxPAPER_P32K, 94, wxTRANSLATE("PRC 32K 97 x 151 mm"), 970, 1510); + WXADDPAPER(wxPAPER_P32KBIG, 95, wxTRANSLATE("PRC 32K(Big) 97 x 151 mm"), 970, 1510); + WXADDPAPER(wxPAPER_PENV_1, 96, wxTRANSLATE("PRC Envelope #1 102 x 165 mm"), 1020, 1650); + WXADDPAPER(wxPAPER_PENV_2, 97, wxTRANSLATE("PRC Envelope #2 102 x 176 mm"), 1020, 1760); + WXADDPAPER(wxPAPER_PENV_3, 98, wxTRANSLATE("PRC Envelope #3 125 x 176 mm"), 1250, 1760); + WXADDPAPER(wxPAPER_PENV_4, 99, wxTRANSLATE("PRC Envelope #4 110 x 208 mm"), 1100, 2080); + WXADDPAPER(wxPAPER_PENV_5, 100, wxTRANSLATE("PRC Envelope #5 110 x 220 mm"), 1100, 2200); + WXADDPAPER(wxPAPER_PENV_6, 101, wxTRANSLATE("PRC Envelope #6 120 x 230 mm"), 1200, 2300); + WXADDPAPER(wxPAPER_PENV_7, 102, wxTRANSLATE("PRC Envelope #7 160 x 230 mm"), 1600, 2300); + WXADDPAPER(wxPAPER_PENV_8, 103, wxTRANSLATE("PRC Envelope #8 120 x 309 mm"), 1200, 3090); + WXADDPAPER(wxPAPER_PENV_9, 104, wxTRANSLATE("PRC Envelope #9 229 x 324 mm"), 2290, 3240); + WXADDPAPER(wxPAPER_PENV_10, 105, wxTRANSLATE("PRC Envelope #10 324 x 458 mm"), 3240, 4580); + WXADDPAPER(wxPAPER_P16K_ROTATED, 106, wxTRANSLATE("PRC 16K Rotated"), 2150, 1460); + WXADDPAPER(wxPAPER_P32K_ROTATED, 107, wxTRANSLATE("PRC 32K Rotated"), 1510, 970); + WXADDPAPER(wxPAPER_P32KBIG_ROTATED, 108, wxTRANSLATE("PRC 32K(Big) Rotated"), 1510, 970); + WXADDPAPER(wxPAPER_PENV_1_ROTATED, 109, wxTRANSLATE("PRC Envelope #1 Rotated 165 x 102 mm"), 1650, 1020); + WXADDPAPER(wxPAPER_PENV_2_ROTATED, 110, wxTRANSLATE("PRC Envelope #2 Rotated 176 x 102 mm"), 1760, 1020); + WXADDPAPER(wxPAPER_PENV_3_ROTATED, 111, wxTRANSLATE("PRC Envelope #3 Rotated 176 x 125 mm"), 1760, 1250); + WXADDPAPER(wxPAPER_PENV_4_ROTATED, 112, wxTRANSLATE("PRC Envelope #4 Rotated 208 x 110 mm"), 2080, 1100); + WXADDPAPER(wxPAPER_PENV_5_ROTATED, 113, wxTRANSLATE("PRC Envelope #5 Rotated 220 x 110 mm"), 2200, 1100); + WXADDPAPER(wxPAPER_PENV_6_ROTATED, 114, wxTRANSLATE("PRC Envelope #6 Rotated 230 x 120 mm"), 2300, 1200); + WXADDPAPER(wxPAPER_PENV_7_ROTATED, 115, wxTRANSLATE("PRC Envelope #7 Rotated 230 x 160 mm"), 2300, 1600); + WXADDPAPER(wxPAPER_PENV_8_ROTATED, 116, wxTRANSLATE("PRC Envelope #8 Rotated 309 x 120 mm"), 3090, 1200); + WXADDPAPER(wxPAPER_PENV_9_ROTATED, 117, wxTRANSLATE("PRC Envelope #9 Rotated 324 x 229 mm"), 3240, 2290); + WXADDPAPER(wxPAPER_PENV_10_ROTATED, 118, wxTRANSLATE("PRC Envelope #10 Rotated 458 x 324 mm"), 4580, 3240); +} + +void wxPrintPaperDatabase::ClearDatabase() +{ + delete m_list; + WX_CLEAR_HASH_MAP(wxStringToPrintPaperTypeHashMap, *m_map); + delete m_map; +} + +void wxPrintPaperDatabase::AddPaperType(wxPaperSize paperId, const wxString& name, int w, int h) +{ + wxPrintPaperType* tmp = new wxPrintPaperType(paperId, 0, name, w, h); + (*m_map)[name] = tmp; + m_list->push_back(tmp); +} + +void wxPrintPaperDatabase::AddPaperType(wxPaperSize paperId, int platformId, const wxString& name, int w, int h) +{ + wxPrintPaperType* tmp = new wxPrintPaperType(paperId, platformId, name, w, h); + (*m_map)[name] = tmp; + m_list->push_back(tmp); +} + +wxPrintPaperType *wxPrintPaperDatabase::FindPaperType(const wxString& name) +{ + wxStringToPrintPaperTypeHashMap::iterator it = m_map->find(name); + if (it != m_map->end()) + return it->second; + else + return NULL; +} + +wxPrintPaperType *wxPrintPaperDatabase::FindPaperType(wxPaperSize id) +{ + typedef wxStringToPrintPaperTypeHashMap::iterator iterator; + + for (iterator it = m_map->begin(), en = m_map->end(); it != en; ++it) + { + wxPrintPaperType* paperType = it->second; + if (paperType->GetId() == id) + return paperType; + } + + return NULL; +} + +wxPrintPaperType *wxPrintPaperDatabase::FindPaperTypeByPlatformId(int id) +{ + typedef wxStringToPrintPaperTypeHashMap::iterator iterator; + + for (iterator it = m_map->begin(), en = m_map->end(); it != en; ++it) + { + wxPrintPaperType* paperType = it->second; + if (paperType->GetPlatformId() == id) + return paperType; + } + + return NULL; +} + +wxPrintPaperType *wxPrintPaperDatabase::FindPaperType(const wxSize& sz) +{ + typedef wxStringToPrintPaperTypeHashMap::iterator iterator; + + for (iterator it = m_map->begin(), en = m_map->end(); it != en; ++it) + { + wxPrintPaperType* paperType = it->second; + wxSize paperSize = paperType->GetSize() ; + if ( abs( paperSize.x - sz.x ) < 10 && abs( paperSize.y - sz.y ) < 10 ) + return paperType; + } + + return NULL; +} + +// Convert name to size id +wxPaperSize wxPrintPaperDatabase::ConvertNameToId(const wxString& name) +{ + wxPrintPaperType* type = FindPaperType(name); + if (type) + return type->GetId(); + else + return wxPAPER_NONE; +} + +// Convert size id to name +wxString wxPrintPaperDatabase::ConvertIdToName(wxPaperSize paperId) +{ + wxPrintPaperType* type = FindPaperType(paperId); + if (type) + return type->GetName(); + else + return wxEmptyString; +} + +// Get the paper size +wxSize wxPrintPaperDatabase::GetSize(wxPaperSize paperId) +{ + wxPrintPaperType* type = FindPaperType(paperId); + if (type) + return type->GetSize(); + else + return wxSize(0,0); +} + +// Get the paper size +wxPaperSize wxPrintPaperDatabase::GetSize(const wxSize& size) +{ + wxPrintPaperType* type = FindPaperType(size); + if (type) + return type->GetId(); + else + return wxPAPER_NONE; +} + +// QUICK and DIRTY +size_t wxPrintPaperDatabase::GetCount() const +{ + return m_list->GetCount(); +} + +wxPrintPaperType* wxPrintPaperDatabase::Item(size_t index) const +{ + return m_list->Item(index)->GetData(); +} + +// A module to allow initialization/cleanup of print paper +// things without calling these functions from app.cpp. + +class WXDLLEXPORT wxPrintPaperModule: public wxModule +{ +DECLARE_DYNAMIC_CLASS(wxPrintPaperModule) +public: + wxPrintPaperModule() {} + bool OnInit(); + void OnExit(); +}; + +IMPLEMENT_DYNAMIC_CLASS(wxPrintPaperModule, wxModule) + +/* + * Initialization/cleanup module + */ + +bool wxPrintPaperModule::OnInit() +{ + wxThePrintPaperDatabase = new wxPrintPaperDatabase; + wxThePrintPaperDatabase->CreateDatabase(); + + return true; +} + +void wxPrintPaperModule::OnExit() +{ + delete wxThePrintPaperDatabase; + wxThePrintPaperDatabase = NULL; +} + +#endif // wxUSE_PRINTING_ARCHITECTURE diff --git a/Externals/wxWidgets/src/common/pickerbase.cpp b/Externals/wxWidgets/src/common/pickerbase.cpp index d95110fdc9..0526b5764c 100644 --- a/Externals/wxWidgets/src/common/pickerbase.cpp +++ b/Externals/wxWidgets/src/common/pickerbase.cpp @@ -1,175 +1,175 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: src/common/pickerbase.cpp -// Purpose: wxPickerBase class implementation -// Author: Francesco Montorsi -// Modified by: -// Created: 15/04/2006 -// RCS-ID: $Id: pickerbase.cpp 52566 2008-03-16 13:50:17Z JS $ -// Copyright: (c) Francesco Montorsi -// Licence: wxWindows licence -/////////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_COLOURPICKERCTRL || \ - wxUSE_DIRPICKERCTRL || \ - wxUSE_FILEPICKERCTRL || \ - wxUSE_FONTPICKERCTRL - -#include "wx/pickerbase.h" -#include "wx/tooltip.h" - -#ifndef WX_PRECOMP - #include "wx/textctrl.h" -#endif - - -// ============================================================================ -// implementation -// ============================================================================ - -IMPLEMENT_ABSTRACT_CLASS(wxPickerBase, wxControl) - -BEGIN_EVENT_TABLE(wxPickerBase, wxControl) - EVT_SIZE(wxPickerBase::OnSize) - WX_EVENT_TABLE_CONTROL_CONTAINER(wxPickerBase) -END_EVENT_TABLE() -WX_DELEGATE_TO_CONTROL_CONTAINER(wxPickerBase, wxControl) - - -// ---------------------------------------------------------------------------- -// wxPickerBase -// ---------------------------------------------------------------------------- - -bool wxPickerBase::CreateBase(wxWindow *parent, - wxWindowID id, - const wxString &text, - const wxPoint& pos, - const wxSize& size, - long style, - const wxValidator& validator, - const wxString& name) -{ - // remove any border style from our style as wxPickerBase's window must be - // invisible (user styles must be set on the textctrl or the platform-dependent picker) - style &= ~wxBORDER_MASK; - if (!wxControl::Create(parent, id, pos, size, style | wxNO_BORDER | wxTAB_TRAVERSAL, - validator, name)) - return false; - - m_sizer = new wxBoxSizer(wxHORIZONTAL); - - if (HasFlag(wxPB_USE_TEXTCTRL)) - { - // NOTE: the style of this class (wxPickerBase) and the style of the - // attached text control are different: GetTextCtrlStyle() extracts - // the styles related to the textctrl from the styles passed here - m_text = new wxTextCtrl(this, wxID_ANY, wxEmptyString, - wxDefaultPosition, wxDefaultSize, - GetTextCtrlStyle(style)); - if (!m_text) - { - wxFAIL_MSG( wxT("wxPickerBase's textctrl creation failed") ); - return false; - } - - // set the maximum lenght allowed for this textctrl. - // This is very important since any change to it will trigger an update in - // the m_picker; for very long strings, this real-time synchronization could - // become a CPU-blocker and thus should be avoided. - // 32 characters will be more than enough for all common uses. - m_text->SetMaxLength(32); - - // set the initial contents of the textctrl - m_text->SetValue(text); - - m_text->Connect(m_text->GetId(), wxEVT_COMMAND_TEXT_UPDATED, - wxCommandEventHandler(wxPickerBase::OnTextCtrlUpdate), - NULL, this); - m_text->Connect(m_text->GetId(), wxEVT_KILL_FOCUS, - wxFocusEventHandler(wxPickerBase::OnTextCtrlKillFocus), - NULL, this); - - m_text->Connect(m_text->GetId(), wxEVT_DESTROY, - wxWindowDestroyEventHandler(wxPickerBase::OnTextCtrlDelete), - NULL, this); - - // the text control's proportion values defaults to 2 - m_sizer->Add(m_text, 2, GetDefaultTextCtrlFlag(), 5); - } - - return true; -} - -void wxPickerBase::PostCreation() -{ - // the picker's proportion value defaults to 1 when there's no text control - // associated with it - in that case it defaults to 0 - m_sizer->Add(m_picker, HasTextCtrl() ? 0 : 1, GetDefaultPickerCtrlFlag(), 5); - - SetSizer(m_sizer); - SetMinSize( m_sizer->GetMinSize() ); -} - -#if wxUSE_TOOLTIPS - -void wxPickerBase::DoSetToolTip(wxToolTip *tip) -{ - // don't set the tooltip on us but rather on our two child windows - // as otherwise it would appear only when the cursor is placed on the - // small area around the child windows which belong to wxPickerBase - m_picker->SetToolTip(tip); - - // do a copy as wxWindow will own the pointer we pass - if ( m_text ) - m_text->SetToolTip(tip ? new wxToolTip(tip->GetTip()) : NULL); -} - -#endif // wxUSE_TOOLTIPS - -// ---------------------------------------------------------------------------- -// wxPickerBase - event handlers -// ---------------------------------------------------------------------------- - -void wxPickerBase::OnTextCtrlKillFocus(wxFocusEvent &) -{ - wxASSERT(m_text); - - // don't leave the textctrl empty - if (m_text->GetValue().empty()) - UpdateTextCtrlFromPicker(); -} - -void wxPickerBase::OnTextCtrlDelete(wxWindowDestroyEvent &) -{ - // the textctrl has been deleted; our pointer is invalid! - m_text = NULL; -} - -void wxPickerBase::OnTextCtrlUpdate(wxCommandEvent &) -{ - // for each text-change, update the picker - UpdatePickerFromTextCtrl(); -} - -void wxPickerBase::OnSize(wxSizeEvent &event) -{ - if (GetAutoLayout()) - Layout(); - event.Skip(); -} - -#endif // Any picker in use +/////////////////////////////////////////////////////////////////////////////// +// Name: src/common/pickerbase.cpp +// Purpose: wxPickerBase class implementation +// Author: Francesco Montorsi +// Modified by: +// Created: 15/04/2006 +// RCS-ID: $Id: pickerbase.cpp 52566 2008-03-16 13:50:17Z JS $ +// Copyright: (c) Francesco Montorsi +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_COLOURPICKERCTRL || \ + wxUSE_DIRPICKERCTRL || \ + wxUSE_FILEPICKERCTRL || \ + wxUSE_FONTPICKERCTRL + +#include "wx/pickerbase.h" +#include "wx/tooltip.h" + +#ifndef WX_PRECOMP + #include "wx/textctrl.h" +#endif + + +// ============================================================================ +// implementation +// ============================================================================ + +IMPLEMENT_ABSTRACT_CLASS(wxPickerBase, wxControl) + +BEGIN_EVENT_TABLE(wxPickerBase, wxControl) + EVT_SIZE(wxPickerBase::OnSize) + WX_EVENT_TABLE_CONTROL_CONTAINER(wxPickerBase) +END_EVENT_TABLE() +WX_DELEGATE_TO_CONTROL_CONTAINER(wxPickerBase, wxControl) + + +// ---------------------------------------------------------------------------- +// wxPickerBase +// ---------------------------------------------------------------------------- + +bool wxPickerBase::CreateBase(wxWindow *parent, + wxWindowID id, + const wxString &text, + const wxPoint& pos, + const wxSize& size, + long style, + const wxValidator& validator, + const wxString& name) +{ + // remove any border style from our style as wxPickerBase's window must be + // invisible (user styles must be set on the textctrl or the platform-dependent picker) + style &= ~wxBORDER_MASK; + if (!wxControl::Create(parent, id, pos, size, style | wxNO_BORDER | wxTAB_TRAVERSAL, + validator, name)) + return false; + + m_sizer = new wxBoxSizer(wxHORIZONTAL); + + if (HasFlag(wxPB_USE_TEXTCTRL)) + { + // NOTE: the style of this class (wxPickerBase) and the style of the + // attached text control are different: GetTextCtrlStyle() extracts + // the styles related to the textctrl from the styles passed here + m_text = new wxTextCtrl(this, wxID_ANY, wxEmptyString, + wxDefaultPosition, wxDefaultSize, + GetTextCtrlStyle(style)); + if (!m_text) + { + wxFAIL_MSG( wxT("wxPickerBase's textctrl creation failed") ); + return false; + } + + // set the maximum lenght allowed for this textctrl. + // This is very important since any change to it will trigger an update in + // the m_picker; for very long strings, this real-time synchronization could + // become a CPU-blocker and thus should be avoided. + // 32 characters will be more than enough for all common uses. + m_text->SetMaxLength(32); + + // set the initial contents of the textctrl + m_text->SetValue(text); + + m_text->Connect(m_text->GetId(), wxEVT_COMMAND_TEXT_UPDATED, + wxCommandEventHandler(wxPickerBase::OnTextCtrlUpdate), + NULL, this); + m_text->Connect(m_text->GetId(), wxEVT_KILL_FOCUS, + wxFocusEventHandler(wxPickerBase::OnTextCtrlKillFocus), + NULL, this); + + m_text->Connect(m_text->GetId(), wxEVT_DESTROY, + wxWindowDestroyEventHandler(wxPickerBase::OnTextCtrlDelete), + NULL, this); + + // the text control's proportion values defaults to 2 + m_sizer->Add(m_text, 2, GetDefaultTextCtrlFlag(), 5); + } + + return true; +} + +void wxPickerBase::PostCreation() +{ + // the picker's proportion value defaults to 1 when there's no text control + // associated with it - in that case it defaults to 0 + m_sizer->Add(m_picker, HasTextCtrl() ? 0 : 1, GetDefaultPickerCtrlFlag(), 5); + + SetSizer(m_sizer); + SetMinSize( m_sizer->GetMinSize() ); +} + +#if wxUSE_TOOLTIPS + +void wxPickerBase::DoSetToolTip(wxToolTip *tip) +{ + // don't set the tooltip on us but rather on our two child windows + // as otherwise it would appear only when the cursor is placed on the + // small area around the child windows which belong to wxPickerBase + m_picker->SetToolTip(tip); + + // do a copy as wxWindow will own the pointer we pass + if ( m_text ) + m_text->SetToolTip(tip ? new wxToolTip(tip->GetTip()) : NULL); +} + +#endif // wxUSE_TOOLTIPS + +// ---------------------------------------------------------------------------- +// wxPickerBase - event handlers +// ---------------------------------------------------------------------------- + +void wxPickerBase::OnTextCtrlKillFocus(wxFocusEvent &) +{ + wxASSERT(m_text); + + // don't leave the textctrl empty + if (m_text->GetValue().empty()) + UpdateTextCtrlFromPicker(); +} + +void wxPickerBase::OnTextCtrlDelete(wxWindowDestroyEvent &) +{ + // the textctrl has been deleted; our pointer is invalid! + m_text = NULL; +} + +void wxPickerBase::OnTextCtrlUpdate(wxCommandEvent &) +{ + // for each text-change, update the picker + UpdatePickerFromTextCtrl(); +} + +void wxPickerBase::OnSize(wxSizeEvent &event) +{ + if (GetAutoLayout()) + Layout(); + event.Skip(); +} + +#endif // Any picker in use diff --git a/Externals/wxWidgets/src/common/platinfo.cpp b/Externals/wxWidgets/src/common/platinfo.cpp index c61fc393d3..bf33db2e6b 100644 --- a/Externals/wxWidgets/src/common/platinfo.cpp +++ b/Externals/wxWidgets/src/common/platinfo.cpp @@ -1,336 +1,336 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: src/common/platinfo.cpp -// Purpose: implements wxPlatformInfo class -// Author: Francesco Montorsi -// Modified by: -// Created: 07.07.2006 (based on wxToolkitInfo) -// RCS-ID: $Id: platinfo.cpp 44078 2006-12-30 21:46:22Z SN $ -// Copyright: (c) 2006 Francesco Montorsi -// License: wxWindows license -/////////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// for compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#include "wx/platinfo.h" - -#ifndef WX_PRECOMP - #include "wx/app.h" - #include "wx/utils.h" -#endif //WX_PRECOMP - -#include "wx/apptrait.h" - -// global object -// VERY IMPORTANT: do not use the default constructor since it would -// try to init the wxPlatformInfo instance using -// gs_platInfo itself! -static wxPlatformInfo gs_platInfo(wxPORT_UNKNOWN); - -// ---------------------------------------------------------------------------- -// constants -// ---------------------------------------------------------------------------- - -static const wxChar* const wxOperatingSystemIdNames[] = -{ - _T("Apple Mac OS"), - _T("Apple Mac OS X"), - - _T("Microsoft Windows 9X"), - _T("Microsoft Windows NT"), - _T("Microsoft Windows Micro"), - _T("Microsoft Windows CE"), - - _T("Linux"), - _T("FreeBSD"), - _T("OpenBSD"), - _T("NetBSD"), - - _T("SunOS"), - _T("AIX"), - _T("HPUX"), - - _T("Other Unix"), - _T("Other Unix"), - - _T("DOS"), - _T("OS/2") -}; - -static const wxChar* const wxPortIdNames[] = -{ - _T("wxBase"), - _T("wxMSW"), - _T("wxMotif"), - _T("wxGTK"), - _T("wxMGL"), - _T("wxX11"), - _T("wxOS2"), - _T("wxMac"), - _T("wxCocoa"), - _T("wxWinCE"), - _T("wxPalmOS"), - _T("wxDFB") -}; - -static const wxChar* const wxArchitectureNames[] = -{ - _T("32 bit"), - _T("64 bit") -}; - -static const wxChar* const wxEndiannessNames[] = -{ - _T("Big endian"), - _T("Little endian"), - _T("PDP endian") -}; - -// ---------------------------------------------------------------------------- -// local functions -// ---------------------------------------------------------------------------- - -// returns log in base 2 of the value, this maps the enum values to the -// corresponding indices -static unsigned wxGetIndexFromEnumValue(int value) -{ - wxCHECK_MSG( value, (unsigned)-1, _T("invalid enum value") ); - - int n = 0; - while ( !(value & 1) ) - { - value >>= 1; - n++; - } - - wxASSERT_MSG( value == 1, _T("more than one bit set in enum value") ); - - return n; -} - -// ---------------------------------------------------------------------------- -// wxPlatformInfo -// ---------------------------------------------------------------------------- - -wxPlatformInfo::wxPlatformInfo() -{ - // just copy platform info for currently running platform - *this = Get(); -} - -wxPlatformInfo::wxPlatformInfo(wxPortId pid, int tkMajor, int tkMinor, - wxOperatingSystemId id, int osMajor, int osMinor, - wxArchitecture arch, - wxEndianness endian, - bool usingUniversal) -{ - m_tkVersionMajor = tkMajor; - m_tkVersionMinor = tkMinor; - m_port = pid; - m_usingUniversal = usingUniversal; - - m_os = id; - m_osVersionMajor = osMajor; - m_osVersionMinor = osMinor; - - m_endian = endian; - m_arch = arch; -} - -bool wxPlatformInfo::operator==(const wxPlatformInfo &t) const -{ - return m_tkVersionMajor == t.m_tkVersionMajor && - m_tkVersionMinor == t.m_tkVersionMinor && - m_osVersionMajor == t.m_osVersionMajor && - m_osVersionMinor == t.m_osVersionMinor && - m_os == t.m_os && - m_port == t.m_port && - m_usingUniversal == t.m_usingUniversal && - m_arch == t.m_arch && - m_endian == t.m_endian; -} - -void wxPlatformInfo::InitForCurrentPlatform() -{ - // autodetect all informations - const wxAppTraits * const traits = wxTheApp ? wxTheApp->GetTraits() : NULL; - if ( !traits ) - { - wxFAIL_MSG( _T("failed to initialize wxPlatformInfo") ); - - m_port = wxPORT_UNKNOWN; - m_usingUniversal = false; - m_tkVersionMajor = - m_tkVersionMinor = 0; - } - else - { - m_port = traits->GetToolkitVersion(&m_tkVersionMajor, &m_tkVersionMinor); - m_usingUniversal = traits->IsUsingUniversalWidgets(); - } - - m_os = wxGetOsVersion(&m_osVersionMajor, &m_osVersionMinor); - m_endian = wxIsPlatformLittleEndian() ? wxENDIAN_LITTLE : wxENDIAN_BIG; - m_arch = wxIsPlatform64Bit() ? wxARCH_64 : wxARCH_32; -} - -/* static */ -const wxPlatformInfo& wxPlatformInfo::Get() -{ - static bool initialized = false; - if ( !initialized ) - { - gs_platInfo.InitForCurrentPlatform(); - initialized = true; - } - - return gs_platInfo; -} - - - -// ---------------------------------------------------------------------------- -// wxPlatformInfo - enum -> string conversions -// ---------------------------------------------------------------------------- - -wxString wxPlatformInfo::GetOperatingSystemFamilyName(wxOperatingSystemId os) -{ - const wxChar* string = _T("Unknown"); - if ( os & wxOS_MAC ) - string = _T("Macintosh"); - else if ( os & wxOS_WINDOWS ) - string = _T("Windows"); - else if ( os & wxOS_UNIX ) - string = _T("Unix"); - else if ( os == wxOS_DOS ) - string = _T("DOS"); - else if ( os == wxOS_OS2 ) - string = _T("OS/2"); - - return string; -} - -wxString wxPlatformInfo::GetOperatingSystemIdName(wxOperatingSystemId os) -{ - const unsigned idx = wxGetIndexFromEnumValue(os); - - wxCHECK_MSG( idx < WXSIZEOF(wxOperatingSystemIdNames), wxEmptyString, - _T("invalid OS id") ); - - return wxOperatingSystemIdNames[idx]; -} - -wxString wxPlatformInfo::GetPortIdName(wxPortId port, bool usingUniversal) -{ - const unsigned idx = wxGetIndexFromEnumValue(port); - - wxCHECK_MSG( idx < WXSIZEOF(wxPortIdNames), wxEmptyString, - _T("invalid port id") ); - - wxString ret = wxPortIdNames[idx]; - - if ( usingUniversal ) - ret += wxT("/wxUniversal"); - - return ret; -} - -wxString wxPlatformInfo::GetPortIdShortName(wxPortId port, bool usingUniversal) -{ - const unsigned idx = wxGetIndexFromEnumValue(port); - - wxCHECK_MSG( idx < WXSIZEOF(wxPortIdNames), wxEmptyString, - _T("invalid port id") ); - - wxString ret = wxPortIdNames[idx]; - ret = ret.Mid(2).Lower(); // remove 'wx' prefix - - if ( usingUniversal ) - ret += wxT("univ"); - - return ret; -} - -wxString wxPlatformInfo::GetArchName(wxArchitecture arch) -{ - wxCOMPILE_TIME_ASSERT( WXSIZEOF(wxArchitectureNames) == wxARCH_MAX, - wxArchitectureNamesMismatch ); - - return wxArchitectureNames[arch]; -} - -wxString wxPlatformInfo::GetEndiannessName(wxEndianness end) -{ - wxCOMPILE_TIME_ASSERT( WXSIZEOF(wxEndiannessNames) == wxENDIAN_MAX, - wxEndiannessNamesMismatch ); - - return wxEndiannessNames[end]; -} - - -// ---------------------------------------------------------------------------- -// wxPlatformInfo - string -> enum conversions -// ---------------------------------------------------------------------------- - -wxOperatingSystemId wxPlatformInfo::GetOperatingSystemId(const wxString &str) -{ - for ( size_t i = 0; i < WXSIZEOF(wxOperatingSystemIdNames); i++ ) - { - if ( wxString(wxOperatingSystemIdNames[i]).CmpNoCase(str) == 0 ) - return (wxOperatingSystemId)(1 << i); - } - - return wxOS_UNKNOWN; -} - -wxPortId wxPlatformInfo::GetPortId(const wxString &str) -{ - // recognize both short and long port names - for ( size_t i = 0; i < WXSIZEOF(wxPortIdNames); i++ ) - { - wxPortId current = (wxPortId)(1 << i); - - if ( wxString(wxPortIdNames[i]).CmpNoCase(str) == 0 || - GetPortIdShortName(current, true).CmpNoCase(str) == 0 || - GetPortIdShortName(current, false).CmpNoCase(str) == 0 ) - return current; - } - - return wxPORT_UNKNOWN; -} - -wxArchitecture wxPlatformInfo::GetArch(const wxString &arch) -{ - if ( arch.Contains(wxT("32")) ) - return wxARCH_32; - - if ( arch.Contains(wxT("64")) ) - return wxARCH_64; - - return wxARCH_INVALID; -} - -wxEndianness wxPlatformInfo::GetEndianness(const wxString& end) -{ - wxString endl(end.Lower()); - if ( end.StartsWith(wxT("little")) ) - return wxENDIAN_LITTLE; - - if ( end.StartsWith(wxT("big")) ) - return wxENDIAN_BIG; - - return wxENDIAN_INVALID; -} - +/////////////////////////////////////////////////////////////////////////////// +// Name: src/common/platinfo.cpp +// Purpose: implements wxPlatformInfo class +// Author: Francesco Montorsi +// Modified by: +// Created: 07.07.2006 (based on wxToolkitInfo) +// RCS-ID: $Id: platinfo.cpp 44078 2006-12-30 21:46:22Z SN $ +// Copyright: (c) 2006 Francesco Montorsi +// License: wxWindows license +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// for compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#include "wx/platinfo.h" + +#ifndef WX_PRECOMP + #include "wx/app.h" + #include "wx/utils.h" +#endif //WX_PRECOMP + +#include "wx/apptrait.h" + +// global object +// VERY IMPORTANT: do not use the default constructor since it would +// try to init the wxPlatformInfo instance using +// gs_platInfo itself! +static wxPlatformInfo gs_platInfo(wxPORT_UNKNOWN); + +// ---------------------------------------------------------------------------- +// constants +// ---------------------------------------------------------------------------- + +static const wxChar* const wxOperatingSystemIdNames[] = +{ + _T("Apple Mac OS"), + _T("Apple Mac OS X"), + + _T("Microsoft Windows 9X"), + _T("Microsoft Windows NT"), + _T("Microsoft Windows Micro"), + _T("Microsoft Windows CE"), + + _T("Linux"), + _T("FreeBSD"), + _T("OpenBSD"), + _T("NetBSD"), + + _T("SunOS"), + _T("AIX"), + _T("HPUX"), + + _T("Other Unix"), + _T("Other Unix"), + + _T("DOS"), + _T("OS/2") +}; + +static const wxChar* const wxPortIdNames[] = +{ + _T("wxBase"), + _T("wxMSW"), + _T("wxMotif"), + _T("wxGTK"), + _T("wxMGL"), + _T("wxX11"), + _T("wxOS2"), + _T("wxMac"), + _T("wxCocoa"), + _T("wxWinCE"), + _T("wxPalmOS"), + _T("wxDFB") +}; + +static const wxChar* const wxArchitectureNames[] = +{ + _T("32 bit"), + _T("64 bit") +}; + +static const wxChar* const wxEndiannessNames[] = +{ + _T("Big endian"), + _T("Little endian"), + _T("PDP endian") +}; + +// ---------------------------------------------------------------------------- +// local functions +// ---------------------------------------------------------------------------- + +// returns log in base 2 of the value, this maps the enum values to the +// corresponding indices +static unsigned wxGetIndexFromEnumValue(int value) +{ + wxCHECK_MSG( value, (unsigned)-1, _T("invalid enum value") ); + + int n = 0; + while ( !(value & 1) ) + { + value >>= 1; + n++; + } + + wxASSERT_MSG( value == 1, _T("more than one bit set in enum value") ); + + return n; +} + +// ---------------------------------------------------------------------------- +// wxPlatformInfo +// ---------------------------------------------------------------------------- + +wxPlatformInfo::wxPlatformInfo() +{ + // just copy platform info for currently running platform + *this = Get(); +} + +wxPlatformInfo::wxPlatformInfo(wxPortId pid, int tkMajor, int tkMinor, + wxOperatingSystemId id, int osMajor, int osMinor, + wxArchitecture arch, + wxEndianness endian, + bool usingUniversal) +{ + m_tkVersionMajor = tkMajor; + m_tkVersionMinor = tkMinor; + m_port = pid; + m_usingUniversal = usingUniversal; + + m_os = id; + m_osVersionMajor = osMajor; + m_osVersionMinor = osMinor; + + m_endian = endian; + m_arch = arch; +} + +bool wxPlatformInfo::operator==(const wxPlatformInfo &t) const +{ + return m_tkVersionMajor == t.m_tkVersionMajor && + m_tkVersionMinor == t.m_tkVersionMinor && + m_osVersionMajor == t.m_osVersionMajor && + m_osVersionMinor == t.m_osVersionMinor && + m_os == t.m_os && + m_port == t.m_port && + m_usingUniversal == t.m_usingUniversal && + m_arch == t.m_arch && + m_endian == t.m_endian; +} + +void wxPlatformInfo::InitForCurrentPlatform() +{ + // autodetect all informations + const wxAppTraits * const traits = wxTheApp ? wxTheApp->GetTraits() : NULL; + if ( !traits ) + { + wxFAIL_MSG( _T("failed to initialize wxPlatformInfo") ); + + m_port = wxPORT_UNKNOWN; + m_usingUniversal = false; + m_tkVersionMajor = + m_tkVersionMinor = 0; + } + else + { + m_port = traits->GetToolkitVersion(&m_tkVersionMajor, &m_tkVersionMinor); + m_usingUniversal = traits->IsUsingUniversalWidgets(); + } + + m_os = wxGetOsVersion(&m_osVersionMajor, &m_osVersionMinor); + m_endian = wxIsPlatformLittleEndian() ? wxENDIAN_LITTLE : wxENDIAN_BIG; + m_arch = wxIsPlatform64Bit() ? wxARCH_64 : wxARCH_32; +} + +/* static */ +const wxPlatformInfo& wxPlatformInfo::Get() +{ + static bool initialized = false; + if ( !initialized ) + { + gs_platInfo.InitForCurrentPlatform(); + initialized = true; + } + + return gs_platInfo; +} + + + +// ---------------------------------------------------------------------------- +// wxPlatformInfo - enum -> string conversions +// ---------------------------------------------------------------------------- + +wxString wxPlatformInfo::GetOperatingSystemFamilyName(wxOperatingSystemId os) +{ + const wxChar* string = _T("Unknown"); + if ( os & wxOS_MAC ) + string = _T("Macintosh"); + else if ( os & wxOS_WINDOWS ) + string = _T("Windows"); + else if ( os & wxOS_UNIX ) + string = _T("Unix"); + else if ( os == wxOS_DOS ) + string = _T("DOS"); + else if ( os == wxOS_OS2 ) + string = _T("OS/2"); + + return string; +} + +wxString wxPlatformInfo::GetOperatingSystemIdName(wxOperatingSystemId os) +{ + const unsigned idx = wxGetIndexFromEnumValue(os); + + wxCHECK_MSG( idx < WXSIZEOF(wxOperatingSystemIdNames), wxEmptyString, + _T("invalid OS id") ); + + return wxOperatingSystemIdNames[idx]; +} + +wxString wxPlatformInfo::GetPortIdName(wxPortId port, bool usingUniversal) +{ + const unsigned idx = wxGetIndexFromEnumValue(port); + + wxCHECK_MSG( idx < WXSIZEOF(wxPortIdNames), wxEmptyString, + _T("invalid port id") ); + + wxString ret = wxPortIdNames[idx]; + + if ( usingUniversal ) + ret += wxT("/wxUniversal"); + + return ret; +} + +wxString wxPlatformInfo::GetPortIdShortName(wxPortId port, bool usingUniversal) +{ + const unsigned idx = wxGetIndexFromEnumValue(port); + + wxCHECK_MSG( idx < WXSIZEOF(wxPortIdNames), wxEmptyString, + _T("invalid port id") ); + + wxString ret = wxPortIdNames[idx]; + ret = ret.Mid(2).Lower(); // remove 'wx' prefix + + if ( usingUniversal ) + ret += wxT("univ"); + + return ret; +} + +wxString wxPlatformInfo::GetArchName(wxArchitecture arch) +{ + wxCOMPILE_TIME_ASSERT( WXSIZEOF(wxArchitectureNames) == wxARCH_MAX, + wxArchitectureNamesMismatch ); + + return wxArchitectureNames[arch]; +} + +wxString wxPlatformInfo::GetEndiannessName(wxEndianness end) +{ + wxCOMPILE_TIME_ASSERT( WXSIZEOF(wxEndiannessNames) == wxENDIAN_MAX, + wxEndiannessNamesMismatch ); + + return wxEndiannessNames[end]; +} + + +// ---------------------------------------------------------------------------- +// wxPlatformInfo - string -> enum conversions +// ---------------------------------------------------------------------------- + +wxOperatingSystemId wxPlatformInfo::GetOperatingSystemId(const wxString &str) +{ + for ( size_t i = 0; i < WXSIZEOF(wxOperatingSystemIdNames); i++ ) + { + if ( wxString(wxOperatingSystemIdNames[i]).CmpNoCase(str) == 0 ) + return (wxOperatingSystemId)(1 << i); + } + + return wxOS_UNKNOWN; +} + +wxPortId wxPlatformInfo::GetPortId(const wxString &str) +{ + // recognize both short and long port names + for ( size_t i = 0; i < WXSIZEOF(wxPortIdNames); i++ ) + { + wxPortId current = (wxPortId)(1 << i); + + if ( wxString(wxPortIdNames[i]).CmpNoCase(str) == 0 || + GetPortIdShortName(current, true).CmpNoCase(str) == 0 || + GetPortIdShortName(current, false).CmpNoCase(str) == 0 ) + return current; + } + + return wxPORT_UNKNOWN; +} + +wxArchitecture wxPlatformInfo::GetArch(const wxString &arch) +{ + if ( arch.Contains(wxT("32")) ) + return wxARCH_32; + + if ( arch.Contains(wxT("64")) ) + return wxARCH_64; + + return wxARCH_INVALID; +} + +wxEndianness wxPlatformInfo::GetEndianness(const wxString& end) +{ + wxString endl(end.Lower()); + if ( end.StartsWith(wxT("little")) ) + return wxENDIAN_LITTLE; + + if ( end.StartsWith(wxT("big")) ) + return wxENDIAN_BIG; + + return wxENDIAN_INVALID; +} + diff --git a/Externals/wxWidgets/src/common/popupcmn.cpp b/Externals/wxWidgets/src/common/popupcmn.cpp index fc92158a8d..dafa9609c0 100644 --- a/Externals/wxWidgets/src/common/popupcmn.cpp +++ b/Externals/wxWidgets/src/common/popupcmn.cpp @@ -1,595 +1,595 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: src/common/popupcmn.cpp -// Purpose: implementation of wxPopupTransientWindow -// Author: Vadim Zeitlin -// Modified by: -// Created: 06.01.01 -// RCS-ID: $Id: popupcmn.cpp 49643 2007-11-05 16:55:13Z SC $ -// Copyright: (c) 2001 Vadim Zeitlin -// License: wxWindows licence -/////////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_POPUPWIN - -#include "wx/popupwin.h" - -#ifndef WX_PRECOMP - #include "wx/combobox.h" // wxComboCtrl - #include "wx/app.h" // wxPostEvent - #include "wx/log.h" -#endif //WX_PRECOMP - -#include "wx/recguard.h" - -#ifdef __WXUNIVERSAL__ - #include "wx/univ/renderer.h" - #include "wx/scrolbar.h" -#endif // __WXUNIVERSAL__ - -#ifdef __WXGTK__ - #include -#endif -#ifdef __WXX11__ -#include "wx/x11/private.h" -#endif - -IMPLEMENT_DYNAMIC_CLASS(wxPopupWindow, wxWindow) -IMPLEMENT_DYNAMIC_CLASS(wxPopupTransientWindow, wxPopupWindow) - -#if wxUSE_COMBOBOX && defined(__WXUNIVERSAL__) - IMPLEMENT_DYNAMIC_CLASS(wxPopupComboWindow, wxPopupTransientWindow) -#endif - -// ---------------------------------------------------------------------------- -// private classes -// ---------------------------------------------------------------------------- - -// event handlers which we use to intercept events which cause the popup to -// disappear -class wxPopupWindowHandler : public wxEvtHandler -{ -public: - wxPopupWindowHandler(wxPopupTransientWindow *popup) : m_popup(popup) {} - -protected: - // event handlers - void OnLeftDown(wxMouseEvent& event); - -private: - wxPopupTransientWindow *m_popup; - - DECLARE_EVENT_TABLE() - DECLARE_NO_COPY_CLASS(wxPopupWindowHandler) -}; - -class wxPopupFocusHandler : public wxEvtHandler -{ -public: - wxPopupFocusHandler(wxPopupTransientWindow *popup) : m_popup(popup) {} - -protected: - void OnKillFocus(wxFocusEvent& event); - void OnKeyDown(wxKeyEvent& event); - -private: - wxPopupTransientWindow *m_popup; - - DECLARE_EVENT_TABLE() - DECLARE_NO_COPY_CLASS(wxPopupFocusHandler) -}; - -// ---------------------------------------------------------------------------- -// event tables -// ---------------------------------------------------------------------------- - -BEGIN_EVENT_TABLE(wxPopupWindowHandler, wxEvtHandler) - EVT_LEFT_DOWN(wxPopupWindowHandler::OnLeftDown) -END_EVENT_TABLE() - -BEGIN_EVENT_TABLE(wxPopupFocusHandler, wxEvtHandler) - EVT_KILL_FOCUS(wxPopupFocusHandler::OnKillFocus) - EVT_KEY_DOWN(wxPopupFocusHandler::OnKeyDown) -END_EVENT_TABLE() - -BEGIN_EVENT_TABLE(wxPopupTransientWindow, wxPopupWindow) -#if defined( __WXMSW__ ) || defined( __WXMAC__ ) - EVT_IDLE(wxPopupTransientWindow::OnIdle) -#endif -END_EVENT_TABLE() - -// ============================================================================ -// implementation -// ============================================================================ - -// ---------------------------------------------------------------------------- -// wxPopupWindowBase -// ---------------------------------------------------------------------------- - -wxPopupWindowBase::~wxPopupWindowBase() -{ - // this destructor is required for Darwin -} - -bool wxPopupWindowBase::Create(wxWindow* WXUNUSED(parent), int WXUNUSED(flags)) -{ - return true; -} - -void wxPopupWindowBase::Position(const wxPoint& ptOrigin, - const wxSize& size) -{ - wxSize sizeScreen = wxGetDisplaySize(), - sizeSelf = GetSize(); - - // is there enough space to put the popup below the window (where we put it - // by default)? - wxCoord y = ptOrigin.y + size.y; - if ( y + sizeSelf.y > sizeScreen.y ) - { - // check if there is enough space above - if ( ptOrigin.y > sizeSelf.y ) - { - // do position the control above the window - y -= size.y + sizeSelf.y; - } - //else: not enough space below nor above, leave below - } - - // now check left/right too - wxCoord x = ptOrigin.x; - - if ( wxTheApp->GetLayoutDirection() == wxLayout_RightToLeft ) - { - // shift the window to the left instead of the right. - x -= size.x; - x -= sizeSelf.x; // also shift it by window width. - } - else - x += size.x; - - - if ( x + sizeSelf.x > sizeScreen.x ) - { - // check if there is enough space to the left - if ( ptOrigin.x > sizeSelf.x ) - { - // do position the control to the left - x -= size.x + sizeSelf.x; - } - //else: not enough space there neither, leave in default position - } - - Move(x, y, wxSIZE_NO_ADJUSTMENTS); -} - -// ---------------------------------------------------------------------------- -// wxPopupTransientWindow -// ---------------------------------------------------------------------------- - -void wxPopupTransientWindow::Init() -{ - m_child = - m_focus = (wxWindow *)NULL; - - m_handlerFocus = NULL; - m_handlerPopup = NULL; -} - -wxPopupTransientWindow::wxPopupTransientWindow(wxWindow *parent, int style) -{ - Init(); - - (void)Create(parent, style); -} - -wxPopupTransientWindow::~wxPopupTransientWindow() -{ - if (m_handlerPopup && m_handlerPopup->GetNextHandler()) - PopHandlers(); - - wxASSERT(!m_handlerFocus || !m_handlerFocus->GetNextHandler()); - wxASSERT(!m_handlerPopup || !m_handlerPopup->GetNextHandler()); - - delete m_handlerFocus; - delete m_handlerPopup; -} - -void wxPopupTransientWindow::PopHandlers() -{ - if ( m_child ) - { - if ( !m_child->RemoveEventHandler(m_handlerPopup) ) - { - // something is very wrong and someone else probably deleted our - // handler - so don't risk deleting it second time - m_handlerPopup = NULL; - } - if (m_child->HasCapture()) - { - m_child->ReleaseMouse(); - } - m_child = NULL; - } - - if ( m_focus ) - { - if ( !m_focus->RemoveEventHandler(m_handlerFocus) ) - { - // see above - m_handlerFocus = NULL; - } - } - m_focus = NULL; -} - -void wxPopupTransientWindow::Popup(wxWindow *winFocus) -{ - const wxWindowList& children = GetChildren(); - if ( children.GetCount() ) - { - m_child = children.GetFirst()->GetData(); - } - else - { - m_child = this; - } - - Show(); - - // There is is a problem if these are still in use - wxASSERT(!m_handlerFocus || !m_handlerFocus->GetNextHandler()); - wxASSERT(!m_handlerPopup || !m_handlerPopup->GetNextHandler()); - - if (!m_handlerPopup) - m_handlerPopup = new wxPopupWindowHandler(this); - - m_child->PushEventHandler(m_handlerPopup); - - m_focus = winFocus ? winFocus : this; - m_focus->SetFocus(); - -#if defined( __WXMSW__ ) || defined( __WXMAC__ ) - // MSW doesn't allow to set focus to the popup window, but we need to - // subclass the window which has the focus, and not winFocus passed in or - // otherwise everything else breaks down - m_focus = FindFocus(); -#elif defined(__WXGTK__) - // GTK+ catches the activate events from the popup - // window, not the focus events from the child window - m_focus = this; -#endif - - if ( m_focus ) - { - if (!m_handlerFocus) - m_handlerFocus = new wxPopupFocusHandler(this); - - m_focus->PushEventHandler(m_handlerFocus); - } -} - -bool wxPopupTransientWindow::Show( bool show ) -{ -#ifdef __WXGTK__ - if (!show) - { - gdk_pointer_ungrab( (guint32)GDK_CURRENT_TIME ); - - gtk_grab_remove( m_widget ); - } -#endif - -#ifdef __WXX11__ - if (!show) - { - XUngrabPointer( wxGlobalDisplay(), CurrentTime ); - } -#endif - -#if defined( __WXMSW__ ) || defined( __WMAC__ ) - if (!show && m_child && m_child->HasCapture()) - { - m_child->ReleaseMouse(); - } -#endif - - bool ret = wxPopupWindow::Show( show ); - -#ifdef __WXGTK__ - if (show) - { - gtk_grab_add( m_widget ); - - gdk_pointer_grab( m_widget->window, TRUE, - (GdkEventMask) - (GDK_BUTTON_PRESS_MASK | - GDK_BUTTON_RELEASE_MASK | - GDK_POINTER_MOTION_HINT_MASK | - GDK_POINTER_MOTION_MASK), - (GdkWindow *) NULL, - (GdkCursor *) NULL, - (guint32)GDK_CURRENT_TIME ); - } -#endif - -#ifdef __WXX11__ - if (show) - { - Window xwindow = (Window) m_clientWindow; - - /* int res =*/ XGrabPointer(wxGlobalDisplay(), xwindow, - True, - ButtonPressMask | ButtonReleaseMask | ButtonMotionMask | EnterWindowMask | LeaveWindowMask | PointerMotionMask, - GrabModeAsync, - GrabModeAsync, - None, - None, - CurrentTime ); - } -#endif - -#if defined( __WXMSW__ ) || defined( __WMAC__ ) - if (show && m_child) - { - // Assume that the mouse is outside the popup to begin with - m_child->CaptureMouse(); - } -#endif - - return ret; -} - -void wxPopupTransientWindow::Dismiss() -{ - Hide(); - PopHandlers(); -} - -void wxPopupTransientWindow::DismissAndNotify() -{ - Dismiss(); - OnDismiss(); -} - -void wxPopupTransientWindow::OnDismiss() -{ - // nothing to do here - but it may be interesting for derived class -} - -bool wxPopupTransientWindow::ProcessLeftDown(wxMouseEvent& WXUNUSED(event)) -{ - // no special processing here - return false; -} - -#if defined( __WXMSW__ ) || defined( __WXMAC__ ) -void wxPopupTransientWindow::OnIdle(wxIdleEvent& event) -{ - event.Skip(); - - if (IsShown() && m_child) - { - wxPoint pos = ScreenToClient(wxGetMousePosition()); - wxRect rect(GetSize()); - - if ( rect.Contains(pos) ) - { - if ( m_child->HasCapture() ) - { - m_child->ReleaseMouse(); - } - } - else - { - if ( !m_child->HasCapture() ) - { - m_child->CaptureMouse(); - } - } - } -} -#endif // __WXMSW__ - - -#if wxUSE_COMBOBOX && defined(__WXUNIVERSAL__) - -// ---------------------------------------------------------------------------- -// wxPopupComboWindow -// ---------------------------------------------------------------------------- - -BEGIN_EVENT_TABLE(wxPopupComboWindow, wxPopupTransientWindow) - EVT_KEY_DOWN(wxPopupComboWindow::OnKeyDown) -END_EVENT_TABLE() - -wxPopupComboWindow::wxPopupComboWindow(wxComboCtrl *parent) - : wxPopupTransientWindow(parent) -{ - m_combo = parent; -} - -bool wxPopupComboWindow::Create(wxComboCtrl *parent) -{ - m_combo = parent; - - return wxPopupWindow::Create(parent); -} - -void wxPopupComboWindow::PositionNearCombo() -{ - // the origin point must be in screen coords - wxPoint ptOrigin = m_combo->ClientToScreen(wxPoint(0,0)); - -#if 0 //def __WXUNIVERSAL__ - // account for the fact that (0, 0) is not the top left corner of the - // window: there is also the border - wxRect rectBorders = m_combo->GetRenderer()-> - GetBorderDimensions(m_combo->GetBorder()); - ptOrigin.x -= rectBorders.x; - ptOrigin.y -= rectBorders.y; -#endif // __WXUNIVERSAL__ - - // position below or above the combobox: the width is 0 to put it exactly - // below us, not to the left or to the right - Position(ptOrigin, wxSize(0, m_combo->GetSize().y)); -} - -void wxPopupComboWindow::OnDismiss() -{ - m_combo->OnPopupDismiss(); -} - -void wxPopupComboWindow::OnKeyDown(wxKeyEvent& event) -{ - m_combo->ProcessEvent(event); -} - -#endif // wxUSE_COMBOBOX && defined(__WXUNIVERSAL__) - -// ---------------------------------------------------------------------------- -// wxPopupWindowHandler -// ---------------------------------------------------------------------------- - -void wxPopupWindowHandler::OnLeftDown(wxMouseEvent& event) -{ - // let the window have it first (we're the first event handler in the chain - // of handlers for this window) - if ( m_popup->ProcessLeftDown(event) ) - { - return; - } - - wxPoint pos = event.GetPosition(); - - // in non-Univ ports the system manages scrollbars for us -#if defined(__WXUNIVERSAL__) && wxUSE_SCROLLBAR - // scrollbar on which the click occurred - wxWindow *sbar = NULL; -#endif // __WXUNIVERSAL__ && wxUSE_SCROLLBAR - - wxWindow *win = (wxWindow *)event.GetEventObject(); - - switch ( win->HitTest(pos.x, pos.y) ) - { - case wxHT_WINDOW_OUTSIDE: - { - // do the coords translation now as after DismissAndNotify() - // m_popup may be destroyed - wxMouseEvent event2(event); - - m_popup->ClientToScreen(&event2.m_x, &event2.m_y); - - // clicking outside a popup dismisses it - m_popup->DismissAndNotify(); - - // dismissing a tooltip shouldn't waste a click, i.e. you - // should be able to dismiss it and press the button with the - // same click, so repost this event to the window beneath us - wxWindow *winUnder = wxFindWindowAtPoint(event2.GetPosition()); - if ( winUnder ) - { - // translate the event coords to the ones of the window - // which is going to get the event - winUnder->ScreenToClient(&event2.m_x, &event2.m_y); - - event2.SetEventObject(winUnder); - wxPostEvent(winUnder, event2); - } - } - break; - -#if defined(__WXUNIVERSAL__) && wxUSE_SCROLLBAR - case wxHT_WINDOW_HORZ_SCROLLBAR: - sbar = win->GetScrollbar(wxHORIZONTAL); - break; - - case wxHT_WINDOW_VERT_SCROLLBAR: - sbar = win->GetScrollbar(wxVERTICAL); - break; -#endif // __WXUNIVERSAL__ && wxUSE_SCROLLBAR - - default: - // forgot to update the switch after adding a new hit test code? - wxFAIL_MSG( _T("unexpected HitTest() return value") ); - // fall through - - case wxHT_WINDOW_CORNER: - // don't actually know if this one is good for anything, but let it - // pass just in case - - case wxHT_WINDOW_INSIDE: - // let the normal processing take place - event.Skip(); - break; - } - -#if defined(__WXUNIVERSAL__) && wxUSE_SCROLLBAR - if ( sbar ) - { - // translate the event coordinates to the scrollbar ones - pos = sbar->ScreenToClient(win->ClientToScreen(pos)); - - // and give the event to it - wxMouseEvent event2 = event; - event2.m_x = pos.x; - event2.m_y = pos.y; - - (void)sbar->GetEventHandler()->ProcessEvent(event2); - } -#endif // __WXUNIVERSAL__ && wxUSE_SCROLLBAR -} - -// ---------------------------------------------------------------------------- -// wxPopupFocusHandler -// ---------------------------------------------------------------------------- - -void wxPopupFocusHandler::OnKillFocus(wxFocusEvent& event) -{ - // when we lose focus we always disappear - unless it goes to the popup (in - // which case we don't really lose it) - wxWindow *win = event.GetWindow(); - while ( win ) - { - if ( win == m_popup ) - return; - win = win->GetParent(); - } - - m_popup->DismissAndNotify(); -} - -void wxPopupFocusHandler::OnKeyDown(wxKeyEvent& event) -{ - // we can be associated with the popup itself in which case we should avoid - // infinite recursion - static int s_inside; - wxRecursionGuard guard(s_inside); - if ( guard.IsInside() ) - { - event.Skip(); - return; - } - - // let the window have it first, it might process the keys - if ( !m_popup->GetEventHandler()->ProcessEvent(event) ) - { - // by default, dismiss the popup - m_popup->DismissAndNotify(); - } -} - -#endif // wxUSE_POPUPWIN +/////////////////////////////////////////////////////////////////////////////// +// Name: src/common/popupcmn.cpp +// Purpose: implementation of wxPopupTransientWindow +// Author: Vadim Zeitlin +// Modified by: +// Created: 06.01.01 +// RCS-ID: $Id: popupcmn.cpp 49643 2007-11-05 16:55:13Z SC $ +// Copyright: (c) 2001 Vadim Zeitlin +// License: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_POPUPWIN + +#include "wx/popupwin.h" + +#ifndef WX_PRECOMP + #include "wx/combobox.h" // wxComboCtrl + #include "wx/app.h" // wxPostEvent + #include "wx/log.h" +#endif //WX_PRECOMP + +#include "wx/recguard.h" + +#ifdef __WXUNIVERSAL__ + #include "wx/univ/renderer.h" + #include "wx/scrolbar.h" +#endif // __WXUNIVERSAL__ + +#ifdef __WXGTK__ + #include +#endif +#ifdef __WXX11__ +#include "wx/x11/private.h" +#endif + +IMPLEMENT_DYNAMIC_CLASS(wxPopupWindow, wxWindow) +IMPLEMENT_DYNAMIC_CLASS(wxPopupTransientWindow, wxPopupWindow) + +#if wxUSE_COMBOBOX && defined(__WXUNIVERSAL__) + IMPLEMENT_DYNAMIC_CLASS(wxPopupComboWindow, wxPopupTransientWindow) +#endif + +// ---------------------------------------------------------------------------- +// private classes +// ---------------------------------------------------------------------------- + +// event handlers which we use to intercept events which cause the popup to +// disappear +class wxPopupWindowHandler : public wxEvtHandler +{ +public: + wxPopupWindowHandler(wxPopupTransientWindow *popup) : m_popup(popup) {} + +protected: + // event handlers + void OnLeftDown(wxMouseEvent& event); + +private: + wxPopupTransientWindow *m_popup; + + DECLARE_EVENT_TABLE() + DECLARE_NO_COPY_CLASS(wxPopupWindowHandler) +}; + +class wxPopupFocusHandler : public wxEvtHandler +{ +public: + wxPopupFocusHandler(wxPopupTransientWindow *popup) : m_popup(popup) {} + +protected: + void OnKillFocus(wxFocusEvent& event); + void OnKeyDown(wxKeyEvent& event); + +private: + wxPopupTransientWindow *m_popup; + + DECLARE_EVENT_TABLE() + DECLARE_NO_COPY_CLASS(wxPopupFocusHandler) +}; + +// ---------------------------------------------------------------------------- +// event tables +// ---------------------------------------------------------------------------- + +BEGIN_EVENT_TABLE(wxPopupWindowHandler, wxEvtHandler) + EVT_LEFT_DOWN(wxPopupWindowHandler::OnLeftDown) +END_EVENT_TABLE() + +BEGIN_EVENT_TABLE(wxPopupFocusHandler, wxEvtHandler) + EVT_KILL_FOCUS(wxPopupFocusHandler::OnKillFocus) + EVT_KEY_DOWN(wxPopupFocusHandler::OnKeyDown) +END_EVENT_TABLE() + +BEGIN_EVENT_TABLE(wxPopupTransientWindow, wxPopupWindow) +#if defined( __WXMSW__ ) || defined( __WXMAC__ ) + EVT_IDLE(wxPopupTransientWindow::OnIdle) +#endif +END_EVENT_TABLE() + +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// wxPopupWindowBase +// ---------------------------------------------------------------------------- + +wxPopupWindowBase::~wxPopupWindowBase() +{ + // this destructor is required for Darwin +} + +bool wxPopupWindowBase::Create(wxWindow* WXUNUSED(parent), int WXUNUSED(flags)) +{ + return true; +} + +void wxPopupWindowBase::Position(const wxPoint& ptOrigin, + const wxSize& size) +{ + wxSize sizeScreen = wxGetDisplaySize(), + sizeSelf = GetSize(); + + // is there enough space to put the popup below the window (where we put it + // by default)? + wxCoord y = ptOrigin.y + size.y; + if ( y + sizeSelf.y > sizeScreen.y ) + { + // check if there is enough space above + if ( ptOrigin.y > sizeSelf.y ) + { + // do position the control above the window + y -= size.y + sizeSelf.y; + } + //else: not enough space below nor above, leave below + } + + // now check left/right too + wxCoord x = ptOrigin.x; + + if ( wxTheApp->GetLayoutDirection() == wxLayout_RightToLeft ) + { + // shift the window to the left instead of the right. + x -= size.x; + x -= sizeSelf.x; // also shift it by window width. + } + else + x += size.x; + + + if ( x + sizeSelf.x > sizeScreen.x ) + { + // check if there is enough space to the left + if ( ptOrigin.x > sizeSelf.x ) + { + // do position the control to the left + x -= size.x + sizeSelf.x; + } + //else: not enough space there neither, leave in default position + } + + Move(x, y, wxSIZE_NO_ADJUSTMENTS); +} + +// ---------------------------------------------------------------------------- +// wxPopupTransientWindow +// ---------------------------------------------------------------------------- + +void wxPopupTransientWindow::Init() +{ + m_child = + m_focus = (wxWindow *)NULL; + + m_handlerFocus = NULL; + m_handlerPopup = NULL; +} + +wxPopupTransientWindow::wxPopupTransientWindow(wxWindow *parent, int style) +{ + Init(); + + (void)Create(parent, style); +} + +wxPopupTransientWindow::~wxPopupTransientWindow() +{ + if (m_handlerPopup && m_handlerPopup->GetNextHandler()) + PopHandlers(); + + wxASSERT(!m_handlerFocus || !m_handlerFocus->GetNextHandler()); + wxASSERT(!m_handlerPopup || !m_handlerPopup->GetNextHandler()); + + delete m_handlerFocus; + delete m_handlerPopup; +} + +void wxPopupTransientWindow::PopHandlers() +{ + if ( m_child ) + { + if ( !m_child->RemoveEventHandler(m_handlerPopup) ) + { + // something is very wrong and someone else probably deleted our + // handler - so don't risk deleting it second time + m_handlerPopup = NULL; + } + if (m_child->HasCapture()) + { + m_child->ReleaseMouse(); + } + m_child = NULL; + } + + if ( m_focus ) + { + if ( !m_focus->RemoveEventHandler(m_handlerFocus) ) + { + // see above + m_handlerFocus = NULL; + } + } + m_focus = NULL; +} + +void wxPopupTransientWindow::Popup(wxWindow *winFocus) +{ + const wxWindowList& children = GetChildren(); + if ( children.GetCount() ) + { + m_child = children.GetFirst()->GetData(); + } + else + { + m_child = this; + } + + Show(); + + // There is is a problem if these are still in use + wxASSERT(!m_handlerFocus || !m_handlerFocus->GetNextHandler()); + wxASSERT(!m_handlerPopup || !m_handlerPopup->GetNextHandler()); + + if (!m_handlerPopup) + m_handlerPopup = new wxPopupWindowHandler(this); + + m_child->PushEventHandler(m_handlerPopup); + + m_focus = winFocus ? winFocus : this; + m_focus->SetFocus(); + +#if defined( __WXMSW__ ) || defined( __WXMAC__ ) + // MSW doesn't allow to set focus to the popup window, but we need to + // subclass the window which has the focus, and not winFocus passed in or + // otherwise everything else breaks down + m_focus = FindFocus(); +#elif defined(__WXGTK__) + // GTK+ catches the activate events from the popup + // window, not the focus events from the child window + m_focus = this; +#endif + + if ( m_focus ) + { + if (!m_handlerFocus) + m_handlerFocus = new wxPopupFocusHandler(this); + + m_focus->PushEventHandler(m_handlerFocus); + } +} + +bool wxPopupTransientWindow::Show( bool show ) +{ +#ifdef __WXGTK__ + if (!show) + { + gdk_pointer_ungrab( (guint32)GDK_CURRENT_TIME ); + + gtk_grab_remove( m_widget ); + } +#endif + +#ifdef __WXX11__ + if (!show) + { + XUngrabPointer( wxGlobalDisplay(), CurrentTime ); + } +#endif + +#if defined( __WXMSW__ ) || defined( __WMAC__ ) + if (!show && m_child && m_child->HasCapture()) + { + m_child->ReleaseMouse(); + } +#endif + + bool ret = wxPopupWindow::Show( show ); + +#ifdef __WXGTK__ + if (show) + { + gtk_grab_add( m_widget ); + + gdk_pointer_grab( m_widget->window, TRUE, + (GdkEventMask) + (GDK_BUTTON_PRESS_MASK | + GDK_BUTTON_RELEASE_MASK | + GDK_POINTER_MOTION_HINT_MASK | + GDK_POINTER_MOTION_MASK), + (GdkWindow *) NULL, + (GdkCursor *) NULL, + (guint32)GDK_CURRENT_TIME ); + } +#endif + +#ifdef __WXX11__ + if (show) + { + Window xwindow = (Window) m_clientWindow; + + /* int res =*/ XGrabPointer(wxGlobalDisplay(), xwindow, + True, + ButtonPressMask | ButtonReleaseMask | ButtonMotionMask | EnterWindowMask | LeaveWindowMask | PointerMotionMask, + GrabModeAsync, + GrabModeAsync, + None, + None, + CurrentTime ); + } +#endif + +#if defined( __WXMSW__ ) || defined( __WMAC__ ) + if (show && m_child) + { + // Assume that the mouse is outside the popup to begin with + m_child->CaptureMouse(); + } +#endif + + return ret; +} + +void wxPopupTransientWindow::Dismiss() +{ + Hide(); + PopHandlers(); +} + +void wxPopupTransientWindow::DismissAndNotify() +{ + Dismiss(); + OnDismiss(); +} + +void wxPopupTransientWindow::OnDismiss() +{ + // nothing to do here - but it may be interesting for derived class +} + +bool wxPopupTransientWindow::ProcessLeftDown(wxMouseEvent& WXUNUSED(event)) +{ + // no special processing here + return false; +} + +#if defined( __WXMSW__ ) || defined( __WXMAC__ ) +void wxPopupTransientWindow::OnIdle(wxIdleEvent& event) +{ + event.Skip(); + + if (IsShown() && m_child) + { + wxPoint pos = ScreenToClient(wxGetMousePosition()); + wxRect rect(GetSize()); + + if ( rect.Contains(pos) ) + { + if ( m_child->HasCapture() ) + { + m_child->ReleaseMouse(); + } + } + else + { + if ( !m_child->HasCapture() ) + { + m_child->CaptureMouse(); + } + } + } +} +#endif // __WXMSW__ + + +#if wxUSE_COMBOBOX && defined(__WXUNIVERSAL__) + +// ---------------------------------------------------------------------------- +// wxPopupComboWindow +// ---------------------------------------------------------------------------- + +BEGIN_EVENT_TABLE(wxPopupComboWindow, wxPopupTransientWindow) + EVT_KEY_DOWN(wxPopupComboWindow::OnKeyDown) +END_EVENT_TABLE() + +wxPopupComboWindow::wxPopupComboWindow(wxComboCtrl *parent) + : wxPopupTransientWindow(parent) +{ + m_combo = parent; +} + +bool wxPopupComboWindow::Create(wxComboCtrl *parent) +{ + m_combo = parent; + + return wxPopupWindow::Create(parent); +} + +void wxPopupComboWindow::PositionNearCombo() +{ + // the origin point must be in screen coords + wxPoint ptOrigin = m_combo->ClientToScreen(wxPoint(0,0)); + +#if 0 //def __WXUNIVERSAL__ + // account for the fact that (0, 0) is not the top left corner of the + // window: there is also the border + wxRect rectBorders = m_combo->GetRenderer()-> + GetBorderDimensions(m_combo->GetBorder()); + ptOrigin.x -= rectBorders.x; + ptOrigin.y -= rectBorders.y; +#endif // __WXUNIVERSAL__ + + // position below or above the combobox: the width is 0 to put it exactly + // below us, not to the left or to the right + Position(ptOrigin, wxSize(0, m_combo->GetSize().y)); +} + +void wxPopupComboWindow::OnDismiss() +{ + m_combo->OnPopupDismiss(); +} + +void wxPopupComboWindow::OnKeyDown(wxKeyEvent& event) +{ + m_combo->ProcessEvent(event); +} + +#endif // wxUSE_COMBOBOX && defined(__WXUNIVERSAL__) + +// ---------------------------------------------------------------------------- +// wxPopupWindowHandler +// ---------------------------------------------------------------------------- + +void wxPopupWindowHandler::OnLeftDown(wxMouseEvent& event) +{ + // let the window have it first (we're the first event handler in the chain + // of handlers for this window) + if ( m_popup->ProcessLeftDown(event) ) + { + return; + } + + wxPoint pos = event.GetPosition(); + + // in non-Univ ports the system manages scrollbars for us +#if defined(__WXUNIVERSAL__) && wxUSE_SCROLLBAR + // scrollbar on which the click occurred + wxWindow *sbar = NULL; +#endif // __WXUNIVERSAL__ && wxUSE_SCROLLBAR + + wxWindow *win = (wxWindow *)event.GetEventObject(); + + switch ( win->HitTest(pos.x, pos.y) ) + { + case wxHT_WINDOW_OUTSIDE: + { + // do the coords translation now as after DismissAndNotify() + // m_popup may be destroyed + wxMouseEvent event2(event); + + m_popup->ClientToScreen(&event2.m_x, &event2.m_y); + + // clicking outside a popup dismisses it + m_popup->DismissAndNotify(); + + // dismissing a tooltip shouldn't waste a click, i.e. you + // should be able to dismiss it and press the button with the + // same click, so repost this event to the window beneath us + wxWindow *winUnder = wxFindWindowAtPoint(event2.GetPosition()); + if ( winUnder ) + { + // translate the event coords to the ones of the window + // which is going to get the event + winUnder->ScreenToClient(&event2.m_x, &event2.m_y); + + event2.SetEventObject(winUnder); + wxPostEvent(winUnder, event2); + } + } + break; + +#if defined(__WXUNIVERSAL__) && wxUSE_SCROLLBAR + case wxHT_WINDOW_HORZ_SCROLLBAR: + sbar = win->GetScrollbar(wxHORIZONTAL); + break; + + case wxHT_WINDOW_VERT_SCROLLBAR: + sbar = win->GetScrollbar(wxVERTICAL); + break; +#endif // __WXUNIVERSAL__ && wxUSE_SCROLLBAR + + default: + // forgot to update the switch after adding a new hit test code? + wxFAIL_MSG( _T("unexpected HitTest() return value") ); + // fall through + + case wxHT_WINDOW_CORNER: + // don't actually know if this one is good for anything, but let it + // pass just in case + + case wxHT_WINDOW_INSIDE: + // let the normal processing take place + event.Skip(); + break; + } + +#if defined(__WXUNIVERSAL__) && wxUSE_SCROLLBAR + if ( sbar ) + { + // translate the event coordinates to the scrollbar ones + pos = sbar->ScreenToClient(win->ClientToScreen(pos)); + + // and give the event to it + wxMouseEvent event2 = event; + event2.m_x = pos.x; + event2.m_y = pos.y; + + (void)sbar->GetEventHandler()->ProcessEvent(event2); + } +#endif // __WXUNIVERSAL__ && wxUSE_SCROLLBAR +} + +// ---------------------------------------------------------------------------- +// wxPopupFocusHandler +// ---------------------------------------------------------------------------- + +void wxPopupFocusHandler::OnKillFocus(wxFocusEvent& event) +{ + // when we lose focus we always disappear - unless it goes to the popup (in + // which case we don't really lose it) + wxWindow *win = event.GetWindow(); + while ( win ) + { + if ( win == m_popup ) + return; + win = win->GetParent(); + } + + m_popup->DismissAndNotify(); +} + +void wxPopupFocusHandler::OnKeyDown(wxKeyEvent& event) +{ + // we can be associated with the popup itself in which case we should avoid + // infinite recursion + static int s_inside; + wxRecursionGuard guard(s_inside); + if ( guard.IsInside() ) + { + event.Skip(); + return; + } + + // let the window have it first, it might process the keys + if ( !m_popup->GetEventHandler()->ProcessEvent(event) ) + { + // by default, dismiss the popup + m_popup->DismissAndNotify(); + } +} + +#endif // wxUSE_POPUPWIN diff --git a/Externals/wxWidgets/src/common/powercmn.cpp b/Externals/wxWidgets/src/common/powercmn.cpp index 82f28c416e..cf2086ff84 100644 --- a/Externals/wxWidgets/src/common/powercmn.cpp +++ b/Externals/wxWidgets/src/common/powercmn.cpp @@ -1,59 +1,59 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: src/common/powercmn.cpp -// Purpose: power event types and stubs for power functions -// Author: Vadim Zeitlin -// Modified by: -// Created: 2006-05-27 -// RCS-ID: $Id: powercmn.cpp 48811 2007-09-19 23:11:28Z RD $ -// Copyright: (c) 2006 Vadim Zeitlin -// Licence: wxWindows licence -/////////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// for compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#ifndef WX_PRECOMP -#endif //WX_PRECOMP - -#include "wx/power.h" - -// ============================================================================ -// implementation -// ============================================================================ - -#ifdef wxHAS_POWER_EVENTS - DEFINE_EVENT_TYPE(wxEVT_POWER_SUSPENDING) - DEFINE_EVENT_TYPE(wxEVT_POWER_SUSPENDED) - DEFINE_EVENT_TYPE(wxEVT_POWER_SUSPEND_CANCEL) - DEFINE_EVENT_TYPE(wxEVT_POWER_RESUME) - - IMPLEMENT_ABSTRACT_CLASS(wxPowerEvent, wxEvent) -#endif - -// provide stubs for the systems not implementing these functions -#if !defined(__WXPALMOS__) && !defined(__WXMSW__) - -wxPowerType wxGetPowerType() -{ - return wxPOWER_UNKNOWN; -} - -wxBatteryState wxGetBatteryState() -{ - return wxBATTERY_UNKNOWN_STATE; -} - -#endif // systems without power management functions - +/////////////////////////////////////////////////////////////////////////////// +// Name: src/common/powercmn.cpp +// Purpose: power event types and stubs for power functions +// Author: Vadim Zeitlin +// Modified by: +// Created: 2006-05-27 +// RCS-ID: $Id: powercmn.cpp 48811 2007-09-19 23:11:28Z RD $ +// Copyright: (c) 2006 Vadim Zeitlin +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// for compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#ifndef WX_PRECOMP +#endif //WX_PRECOMP + +#include "wx/power.h" + +// ============================================================================ +// implementation +// ============================================================================ + +#ifdef wxHAS_POWER_EVENTS + DEFINE_EVENT_TYPE(wxEVT_POWER_SUSPENDING) + DEFINE_EVENT_TYPE(wxEVT_POWER_SUSPENDED) + DEFINE_EVENT_TYPE(wxEVT_POWER_SUSPEND_CANCEL) + DEFINE_EVENT_TYPE(wxEVT_POWER_RESUME) + + IMPLEMENT_ABSTRACT_CLASS(wxPowerEvent, wxEvent) +#endif + +// provide stubs for the systems not implementing these functions +#if !defined(__WXPALMOS__) && !defined(__WXMSW__) + +wxPowerType wxGetPowerType() +{ + return wxPOWER_UNKNOWN; +} + +wxBatteryState wxGetBatteryState() +{ + return wxBATTERY_UNKNOWN_STATE; +} + +#endif // systems without power management functions + diff --git a/Externals/wxWidgets/src/common/prntbase.cpp b/Externals/wxWidgets/src/common/prntbase.cpp index 1eb29887ff..e007758765 100644 --- a/Externals/wxWidgets/src/common/prntbase.cpp +++ b/Externals/wxWidgets/src/common/prntbase.cpp @@ -1,1761 +1,1761 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/prntbase.cpp -// Purpose: Printing framework base class implementation -// Author: Julian Smart -// Modified by: -// Created: 04/01/98 -// RCS-ID: $Id: prntbase.cpp 42763 2006-10-30 20:34:25Z VZ $ -// Copyright: (c) Julian Smart -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_PRINTING_ARCHITECTURE - -#include "wx/dcprint.h" - -#ifndef WX_PRECOMP - #if defined(__WXMSW__) - #include "wx/msw/wrapcdlg.h" - #endif // MSW - #include "wx/utils.h" - #include "wx/dc.h" - #include "wx/app.h" - #include "wx/math.h" - #include "wx/msgdlg.h" - #include "wx/layout.h" - #include "wx/choice.h" - #include "wx/button.h" - #include "wx/settings.h" - #include "wx/dcmemory.h" - #include "wx/stattext.h" - #include "wx/intl.h" - #include "wx/textdlg.h" - #include "wx/sizer.h" - #include "wx/module.h" -#endif // !WX_PRECOMP - -#include "wx/prntbase.h" -#include "wx/printdlg.h" -#include "wx/print.h" -#include "wx/dcprint.h" - -#include -#include - -#if defined(__WXMSW__) && !defined(__WXUNIVERSAL__) -#include "wx/msw/printdlg.h" -#elif defined(__WXMAC__) -#include "wx/mac/printdlg.h" -#include "wx/mac/private/print.h" -#else -#include "wx/generic/prntdlgg.h" -#include "wx/dcps.h" -#endif - -#ifdef __WXMSW__ - #ifndef __WIN32__ - #include - #endif -#endif // __WXMSW__ - -//---------------------------------------------------------------------------- -// wxPrintFactory -//---------------------------------------------------------------------------- - -wxPrintFactory *wxPrintFactory::m_factory = NULL; - -void wxPrintFactory::SetPrintFactory( wxPrintFactory *factory ) -{ - if (wxPrintFactory::m_factory) - delete wxPrintFactory::m_factory; - - wxPrintFactory::m_factory = factory; -} - -wxPrintFactory *wxPrintFactory::GetFactory() -{ - if (!wxPrintFactory::m_factory) - wxPrintFactory::m_factory = new wxNativePrintFactory; - - return wxPrintFactory::m_factory; -} - -//---------------------------------------------------------------------------- -// wxNativePrintFactory -//---------------------------------------------------------------------------- - -wxPrinterBase *wxNativePrintFactory::CreatePrinter( wxPrintDialogData *data ) -{ -#if defined(__WXMSW__) && !defined(__WXUNIVERSAL__) - return new wxWindowsPrinter( data ); -#elif defined(__WXMAC__) - return new wxMacPrinter( data ); -#elif defined(__WXPM__) - return new wxOS2Printer( data ); -#else - return new wxPostScriptPrinter( data ); -#endif -} - -wxPrintPreviewBase *wxNativePrintFactory::CreatePrintPreview( wxPrintout *preview, - wxPrintout *printout, wxPrintDialogData *data ) -{ -#if defined(__WXMSW__) && !defined(__WXUNIVERSAL__) - return new wxWindowsPrintPreview( preview, printout, data ); -#elif defined(__WXMAC__) - return new wxMacPrintPreview( preview, printout, data ); -#elif defined(__WXPM__) - return new wxOS2PrintPreview( preview, printout, data ); -#else - return new wxPostScriptPrintPreview( preview, printout, data ); -#endif -} - -wxPrintPreviewBase *wxNativePrintFactory::CreatePrintPreview( wxPrintout *preview, - wxPrintout *printout, wxPrintData *data ) -{ -#if defined(__WXMSW__) && !defined(__WXUNIVERSAL__) - return new wxWindowsPrintPreview( preview, printout, data ); -#elif defined(__WXMAC__) - return new wxMacPrintPreview( preview, printout, data ); -#elif defined(__WXPM__) - return new wxOS2PrintPreview( preview, printout, data ); -#else - return new wxPostScriptPrintPreview( preview, printout, data ); -#endif -} - -wxPrintDialogBase *wxNativePrintFactory::CreatePrintDialog( wxWindow *parent, - wxPrintDialogData *data ) -{ -#if defined(__WXMSW__) && !defined(__WXUNIVERSAL__) - return new wxWindowsPrintDialog( parent, data ); -#elif defined(__WXMAC__) - return new wxMacPrintDialog( parent, data ); -#else - return new wxGenericPrintDialog( parent, data ); -#endif -} - -wxPrintDialogBase *wxNativePrintFactory::CreatePrintDialog( wxWindow *parent, - wxPrintData *data ) -{ -#if defined(__WXMSW__) && !defined(__WXUNIVERSAL__) - return new wxWindowsPrintDialog( parent, data ); -#elif defined(__WXMAC__) - return new wxMacPrintDialog( parent, data ); -#else - return new wxGenericPrintDialog( parent, data ); -#endif -} - -wxPageSetupDialogBase *wxNativePrintFactory::CreatePageSetupDialog( wxWindow *parent, - wxPageSetupDialogData *data ) -{ -#if defined(__WXMSW__) && !defined(__WXUNIVERSAL__) - return new wxWindowsPageSetupDialog( parent, data ); -#elif defined(__WXMAC__) - return new wxMacPageSetupDialog( parent, data ); -#else - return new wxGenericPageSetupDialog( parent, data ); -#endif -} - -bool wxNativePrintFactory::HasPrintSetupDialog() -{ -#if defined(__WXMSW__) && !defined(__WXUNIVERSAL__) - return false; -#elif defined(__WXMAC__) - return false; -#else - // Only here do we need to provide the print setup - // dialog ourselves, the other platforms either have - // none, don't make it accessible or let you configure - // the printer from the wxPrintDialog anyway. - return true; -#endif - -} - -wxDialog *wxNativePrintFactory::CreatePrintSetupDialog( wxWindow *parent, - wxPrintData *data ) -{ -#if defined(__WXMSW__) && !defined(__WXUNIVERSAL__) - wxUnusedVar(parent); - wxUnusedVar(data); - return NULL; -#elif defined(__WXMAC__) - wxUnusedVar(parent); - wxUnusedVar(data); - return NULL; -#else - // Only here do we need to provide the print setup - // dialog ourselves, the other platforms either have - // none, don't make it accessible or let you configure - // the printer from the wxPrintDialog anyway. - return new wxGenericPrintSetupDialog( parent, data ); -#endif -} - -wxDC* wxNativePrintFactory::CreatePrinterDC( const wxPrintData& data ) -{ -#if defined(__WXMSW__) && !defined(__WXUNIVERSAL__) - return new wxPrinterDC(data); -#elif defined(__WXMAC__) - return new wxPrinterDC(data); -#else - return new wxPostScriptDC(data); -#endif -} - -bool wxNativePrintFactory::HasOwnPrintToFile() -{ - // Only relevant for PostScript and here the - // setup dialog provides no "print to file" - // option. In the GNOME setup dialog, the - // setup dialog has its own print to file. - return false; -} - -bool wxNativePrintFactory::HasPrinterLine() -{ - // Only relevant for PostScript for now - return true; -} - -wxString wxNativePrintFactory::CreatePrinterLine() -{ - // Only relevant for PostScript for now - - // We should query "lpstat -d" here - return _("Generic PostScript"); -} - -bool wxNativePrintFactory::HasStatusLine() -{ - // Only relevant for PostScript for now - return true; -} - -wxString wxNativePrintFactory::CreateStatusLine() -{ - // Only relevant for PostScript for now - - // We should query "lpstat -r" or "lpstat -p" here - return _("Ready"); -} - -wxPrintNativeDataBase *wxNativePrintFactory::CreatePrintNativeData() -{ -#if defined(__WXMSW__) && !defined(__WXUNIVERSAL__) - return new wxWindowsPrintNativeData; -#elif defined(__WXMAC__) - return new wxMacCarbonPrintData; -#else - return new wxPostScriptPrintNativeData; -#endif -} - -//---------------------------------------------------------------------------- -// wxPrintNativeDataBase -//---------------------------------------------------------------------------- - -IMPLEMENT_ABSTRACT_CLASS(wxPrintNativeDataBase, wxObject) - -wxPrintNativeDataBase::wxPrintNativeDataBase() -{ - m_ref = 1; -} - -//---------------------------------------------------------------------------- -// wxPrintFactoryModule -//---------------------------------------------------------------------------- - -class wxPrintFactoryModule: public wxModule -{ -public: - wxPrintFactoryModule() {} - bool OnInit() { return true; } - void OnExit() { wxPrintFactory::SetPrintFactory( NULL ); } - -private: - DECLARE_DYNAMIC_CLASS(wxPrintFactoryModule) -}; - -IMPLEMENT_DYNAMIC_CLASS(wxPrintFactoryModule, wxModule) - -//---------------------------------------------------------------------------- -// wxPrinterBase -//---------------------------------------------------------------------------- - -IMPLEMENT_CLASS(wxPrinterBase, wxObject) - -wxPrinterBase::wxPrinterBase(wxPrintDialogData *data) -{ - m_currentPrintout = (wxPrintout *) NULL; - sm_abortWindow = (wxWindow *) NULL; - sm_abortIt = false; - if (data) - m_printDialogData = (*data); - sm_lastError = wxPRINTER_NO_ERROR; -} - -wxWindow *wxPrinterBase::sm_abortWindow = (wxWindow *) NULL; -bool wxPrinterBase::sm_abortIt = false; -wxPrinterError wxPrinterBase::sm_lastError = wxPRINTER_NO_ERROR; - -wxPrinterBase::~wxPrinterBase() -{ -} - -wxWindow *wxPrinterBase::CreateAbortWindow(wxWindow *parent, wxPrintout * printout) -{ - wxPrintAbortDialog *dialog = new wxPrintAbortDialog(parent, _("Printing ") , wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE); - - wxBoxSizer *button_sizer = new wxBoxSizer( wxVERTICAL ); - button_sizer->Add( new wxStaticText(dialog, wxID_ANY, _("Please wait while printing\n") + printout->GetTitle() ), 0, wxALL, 10 ); - button_sizer->Add( new wxButton( dialog, wxID_CANCEL, wxT("Cancel") ), 0, wxALL | wxALIGN_CENTER, 10 ); - - dialog->SetAutoLayout( true ); - dialog->SetSizer( button_sizer ); - - button_sizer->Fit(dialog); - button_sizer->SetSizeHints (dialog) ; - - return dialog; -} - -void wxPrinterBase::ReportError(wxWindow *parent, wxPrintout *WXUNUSED(printout), const wxString& message) -{ - wxMessageBox(message, _("Printing Error"), wxOK, parent); -} - -wxPrintDialogData& wxPrinterBase::GetPrintDialogData() const -{ - return (wxPrintDialogData&) m_printDialogData; -} - -//---------------------------------------------------------------------------- -// wxPrinter -//---------------------------------------------------------------------------- - -IMPLEMENT_CLASS(wxPrinter, wxPrinterBase) - -wxPrinter::wxPrinter(wxPrintDialogData *data) -{ - m_pimpl = wxPrintFactory::GetFactory()->CreatePrinter( data ); -} - -wxPrinter::~wxPrinter() -{ - delete m_pimpl; -} - -wxWindow *wxPrinter::CreateAbortWindow(wxWindow *parent, wxPrintout *printout) -{ - return m_pimpl->CreateAbortWindow( parent, printout ); -} - -void wxPrinter::ReportError(wxWindow *parent, wxPrintout *printout, const wxString& message) -{ - m_pimpl->ReportError( parent, printout, message ); -} - -bool wxPrinter::Setup(wxWindow *parent) -{ - return m_pimpl->Setup( parent ); -} - -bool wxPrinter::Print(wxWindow *parent, wxPrintout *printout, bool prompt) -{ - return m_pimpl->Print( parent, printout, prompt ); -} - -wxDC* wxPrinter::PrintDialog(wxWindow *parent) -{ - return m_pimpl->PrintDialog( parent ); -} - -wxPrintDialogData& wxPrinter::GetPrintDialogData() const -{ - return m_pimpl->GetPrintDialogData(); -} - -// --------------------------------------------------------------------------- -// wxPrintDialogBase: the dialog for printing. -// --------------------------------------------------------------------------- - -IMPLEMENT_ABSTRACT_CLASS(wxPrintDialogBase, wxDialog) - -wxPrintDialogBase::wxPrintDialogBase(wxWindow *parent, - wxWindowID id, - const wxString &title, - const wxPoint &pos, - const wxSize &size, - long style) - : wxDialog( parent, id, title.empty() ? wxString(_("Print")) : title, - pos, size, style ) -{ -} - -// --------------------------------------------------------------------------- -// wxPrintDialog: the dialog for printing -// --------------------------------------------------------------------------- - -IMPLEMENT_CLASS(wxPrintDialog, wxObject) - -wxPrintDialog::wxPrintDialog(wxWindow *parent, wxPrintDialogData* data) -{ - m_pimpl = wxPrintFactory::GetFactory()->CreatePrintDialog( parent, data ); -} - -wxPrintDialog::wxPrintDialog(wxWindow *parent, wxPrintData* data) -{ - m_pimpl = wxPrintFactory::GetFactory()->CreatePrintDialog( parent, data ); -} - -wxPrintDialog::~wxPrintDialog() -{ - delete m_pimpl; -} - -int wxPrintDialog::ShowModal() -{ - return m_pimpl->ShowModal(); -} - -wxPrintDialogData& wxPrintDialog::GetPrintDialogData() -{ - return m_pimpl->GetPrintDialogData(); -} - -wxPrintData& wxPrintDialog::GetPrintData() -{ - return m_pimpl->GetPrintData(); -} - -wxDC *wxPrintDialog::GetPrintDC() -{ - return m_pimpl->GetPrintDC(); -} - -// --------------------------------------------------------------------------- -// wxPageSetupDialogBase: the page setup dialog -// --------------------------------------------------------------------------- - -IMPLEMENT_ABSTRACT_CLASS(wxPageSetupDialogBase, wxDialog) - -wxPageSetupDialogBase::wxPageSetupDialogBase(wxWindow *parent, - wxWindowID id, - const wxString &title, - const wxPoint &pos, - const wxSize &size, - long style) - : wxDialog( parent, id, title.empty() ? wxString(_("Page setup")) : title, - pos, size, style ) -{ -} - -// --------------------------------------------------------------------------- -// wxPageSetupDialog: the page setup dialog -// --------------------------------------------------------------------------- - -IMPLEMENT_CLASS(wxPageSetupDialog, wxObject) - -wxPageSetupDialog::wxPageSetupDialog(wxWindow *parent, wxPageSetupDialogData *data ) -{ - m_pimpl = wxPrintFactory::GetFactory()->CreatePageSetupDialog( parent, data ); -} - -wxPageSetupDialog::~wxPageSetupDialog() -{ - delete m_pimpl; -} - -int wxPageSetupDialog::ShowModal() -{ - return m_pimpl->ShowModal(); -} - -wxPageSetupDialogData& wxPageSetupDialog::GetPageSetupDialogData() -{ - return m_pimpl->GetPageSetupDialogData(); -} - -// old name -wxPageSetupDialogData& wxPageSetupDialog::GetPageSetupData() -{ - return m_pimpl->GetPageSetupDialogData(); -} - -//---------------------------------------------------------------------------- -// wxPrintAbortDialog -//---------------------------------------------------------------------------- - -BEGIN_EVENT_TABLE(wxPrintAbortDialog, wxDialog) - EVT_BUTTON(wxID_CANCEL, wxPrintAbortDialog::OnCancel) -END_EVENT_TABLE() - -void wxPrintAbortDialog::OnCancel(wxCommandEvent& WXUNUSED(event)) -{ - wxPrinterBase::sm_abortIt = true; - wxPrinterBase::sm_abortWindow->Show(false); - wxPrinterBase::sm_abortWindow->Close(true); - wxPrinterBase::sm_abortWindow = (wxWindow *) NULL; -} - -//---------------------------------------------------------------------------- -// wxPrintout -//---------------------------------------------------------------------------- - -IMPLEMENT_ABSTRACT_CLASS(wxPrintout, wxObject) - -wxPrintout::wxPrintout(const wxString& title) -{ - m_printoutTitle = title ; - m_printoutDC = (wxDC *) NULL; - m_pageWidthMM = 0; - m_pageHeightMM = 0; - m_pageWidthPixels = 0; - m_pageHeightPixels = 0; - m_PPIScreenX = 0; - m_PPIScreenY = 0; - m_PPIPrinterX = 0; - m_PPIPrinterY = 0; - m_isPreview = false; -} - -wxPrintout::~wxPrintout() -{ -} - -bool wxPrintout::OnBeginDocument(int WXUNUSED(startPage), int WXUNUSED(endPage)) -{ - return GetDC()->StartDoc(_("Printing ") + m_printoutTitle); -} - -void wxPrintout::OnEndDocument() -{ - GetDC()->EndDoc(); -} - -void wxPrintout::OnBeginPrinting() -{ -} - -void wxPrintout::OnEndPrinting() -{ -} - -bool wxPrintout::HasPage(int page) -{ - return (page == 1); -} - -void wxPrintout::GetPageInfo(int *minPage, int *maxPage, int *fromPage, int *toPage) -{ - *minPage = 1; - *maxPage = 32000; - *fromPage = 1; - *toPage = 1; -} - -void wxPrintout::FitThisSizeToPaper(const wxSize& imageSize) -{ - // Set the DC scale and origin so that the given image size fits within the - // entire page and the origin is at the top left corner of the page. Note - // that with most printers, portions of the page will be non-printable. Use - // this if you're managing your own page margins. - if (!m_printoutDC) return; - wxRect paperRect = GetPaperRectPixels(); - wxCoord pw, ph; - GetPageSizePixels(&pw, &ph); - wxCoord w, h; - m_printoutDC->GetSize(&w, &h); - float scaleX = ((float(paperRect.width) * w) / (float(pw) * imageSize.x)); - float scaleY = ((float(paperRect.height) * h) / (float(ph) * imageSize.y)); - float actualScale = wxMin(scaleX, scaleY); - m_printoutDC->SetUserScale(actualScale, actualScale); - m_printoutDC->SetDeviceOrigin(0, 0); - wxRect logicalPaperRect = GetLogicalPaperRect(); - SetLogicalOrigin(logicalPaperRect.x, logicalPaperRect.y); -} - -void wxPrintout::FitThisSizeToPage(const wxSize& imageSize) -{ - // Set the DC scale and origin so that the given image size fits within the - // printable area of the page and the origin is at the top left corner of - // the printable area. - if (!m_printoutDC) return; - int w, h; - m_printoutDC->GetSize(&w, &h); - float scaleX = float(w) / imageSize.x; - float scaleY = float(h) / imageSize.y; - float actualScale = wxMin(scaleX, scaleY); - m_printoutDC->SetUserScale(actualScale, actualScale); - m_printoutDC->SetDeviceOrigin(0, 0); -} - -void wxPrintout::FitThisSizeToPageMargins(const wxSize& imageSize, const wxPageSetupDialogData& pageSetupData) -{ - // Set the DC scale and origin so that the given image size fits within the - // page margins defined in the given wxPageSetupDialogData object and the - // origin is at the top left corner of the page margins. - if (!m_printoutDC) return; - wxRect paperRect = GetPaperRectPixels(); - wxCoord pw, ph; - GetPageSizePixels(&pw, &ph); - wxPoint topLeft = pageSetupData.GetMarginTopLeft(); - wxPoint bottomRight = pageSetupData.GetMarginBottomRight(); - wxCoord mw, mh; - GetPageSizeMM(&mw, &mh); - float mmToDeviceX = float(pw) / mw; - float mmToDeviceY = float(ph) / mh; - wxRect pageMarginsRect(paperRect.x + wxRound(mmToDeviceX * topLeft.x), - paperRect.y + wxRound(mmToDeviceY * topLeft.y), - paperRect.width - wxRound(mmToDeviceX * (topLeft.x + bottomRight.x)), - paperRect.height - wxRound(mmToDeviceY * (topLeft.y + bottomRight.y))); - wxCoord w, h; - m_printoutDC->GetSize(&w, &h); - float scaleX = (float(pageMarginsRect.width) * w) / (float(pw) * imageSize.x); - float scaleY = (float(pageMarginsRect.height) * h) / (float(ph) * imageSize.y); - float actualScale = wxMin(scaleX, scaleY); - m_printoutDC->SetUserScale(actualScale, actualScale); - m_printoutDC->SetDeviceOrigin(0, 0); - wxRect logicalPageMarginsRect = GetLogicalPageMarginsRect(pageSetupData); - SetLogicalOrigin(logicalPageMarginsRect.x, logicalPageMarginsRect.y); -} - -void wxPrintout::MapScreenSizeToPaper() -{ - // Set the DC scale so that an image on the screen is the same size on the - // paper and the origin is at the top left of the paper. Note that with most - // printers, portions of the page will be cut off. Use this if you're - // managing your own page margins. - if (!m_printoutDC) return; - MapScreenSizeToPage(); - wxRect logicalPaperRect = GetLogicalPaperRect(); - SetLogicalOrigin(logicalPaperRect.x, logicalPaperRect.y); -} - -void wxPrintout::MapScreenSizeToPage() -{ - // Set the DC scale and origin so that an image on the screen is the same - // size on the paper and the origin is at the top left of the printable area. - if (!m_printoutDC) return; - int ppiScreenX, ppiScreenY; - GetPPIScreen(&ppiScreenX, &ppiScreenY); - int ppiPrinterX, ppiPrinterY; - GetPPIPrinter(&ppiPrinterX, &ppiPrinterY); - int w, h; - m_printoutDC->GetSize(&w, &h); - int pageSizePixelsX, pageSizePixelsY; - GetPageSizePixels(&pageSizePixelsX, &pageSizePixelsY); - float userScaleX = (float(ppiPrinterX) * w) / (float(ppiScreenX) * pageSizePixelsX); - float userScaleY = (float(ppiPrinterY) * h) / (float(ppiScreenY) * pageSizePixelsY); - m_printoutDC->SetUserScale(userScaleX, userScaleY); - m_printoutDC->SetDeviceOrigin(0, 0); -} - -void wxPrintout::MapScreenSizeToPageMargins(const wxPageSetupDialogData& pageSetupData) -{ - // Set the DC scale so that an image on the screen is the same size on the - // paper and the origin is at the top left of the page margins defined by - // the given wxPageSetupDialogData object. - if (!m_printoutDC) return; - MapScreenSizeToPage(); - wxRect logicalPageMarginsRect = GetLogicalPageMarginsRect(pageSetupData); - SetLogicalOrigin(logicalPageMarginsRect.x, logicalPageMarginsRect.y); -} - -void wxPrintout::MapScreenSizeToDevice() -{ - // Set the DC scale so that a screen pixel is the same size as a device - // pixel and the origin is at the top left of the printable area. - if (!m_printoutDC) return; - int w, h; - m_printoutDC->GetSize(&w, &h); - int pageSizePixelsX, pageSizePixelsY; - GetPageSizePixels(&pageSizePixelsX, &pageSizePixelsY); - float userScaleX = float(w) / pageSizePixelsX; - float userScaleY = float(h) / pageSizePixelsY; - m_printoutDC->SetUserScale(userScaleX, userScaleY); - m_printoutDC->SetDeviceOrigin(0, 0); -} - -wxRect wxPrintout::GetLogicalPaperRect() const -{ - // Return the rectangle in logical units that corresponds to the paper - // rectangle. - wxRect paperRect = GetPaperRectPixels(); - wxCoord pw, ph; - GetPageSizePixels(&pw, &ph); - wxCoord w, h; - m_printoutDC->GetSize(&w, &h); - if (w == pw && h == ph) { - // this DC matches the printed page, so no scaling - return wxRect(m_printoutDC->DeviceToLogicalX(paperRect.x), - m_printoutDC->DeviceToLogicalY(paperRect.y), - m_printoutDC->DeviceToLogicalXRel(paperRect.width), - m_printoutDC->DeviceToLogicalYRel(paperRect.height)); - } - // This DC doesn't match the printed page, so we have to scale. - float scaleX = float(w) / pw; - float scaleY = float(h) / ph; - return wxRect(m_printoutDC->DeviceToLogicalX(wxRound(paperRect.x * scaleX)), - m_printoutDC->DeviceToLogicalY(wxRound(paperRect.y * scaleY)), - m_printoutDC->DeviceToLogicalXRel(wxRound(paperRect.width * scaleX)), - m_printoutDC->DeviceToLogicalYRel(wxRound(paperRect.height * scaleY))); -} - -wxRect wxPrintout::GetLogicalPageRect() const -{ - // Return the rectangle in logical units that corresponds to the printable - // area. - int w, h; - m_printoutDC->GetSize(&w, &h); - return wxRect(m_printoutDC->DeviceToLogicalX(0), - m_printoutDC->DeviceToLogicalY(0), - m_printoutDC->DeviceToLogicalXRel(w), - m_printoutDC->DeviceToLogicalYRel(h)); -} - -wxRect wxPrintout::GetLogicalPageMarginsRect(const wxPageSetupDialogData& pageSetupData) const -{ - // Return the rectangle in logical units that corresponds to the region - // within the page margins as specified by the given wxPageSetupDialogData - // object. - wxRect paperRect = GetPaperRectPixels(); - wxCoord pw, ph; - GetPageSizePixels(&pw, &ph); - wxPoint topLeft = pageSetupData.GetMarginTopLeft(); - wxPoint bottomRight = pageSetupData.GetMarginBottomRight(); - wxCoord mw, mh; - GetPageSizeMM(&mw, &mh); - float mmToDeviceX = float(pw) / mw; - float mmToDeviceY = float(ph) / mh; - wxRect pageMarginsRect(paperRect.x + wxRound(mmToDeviceX * topLeft.x), - paperRect.y + wxRound(mmToDeviceY * topLeft.y), - paperRect.width - wxRound(mmToDeviceX * (topLeft.x + bottomRight.x)), - paperRect.height - wxRound(mmToDeviceY * (topLeft.y + bottomRight.y))); - wxCoord w, h; - m_printoutDC->GetSize(&w, &h); - if (w == pw && h == ph) { - // this DC matches the printed page, so no scaling - return wxRect(m_printoutDC->DeviceToLogicalX(pageMarginsRect.x), - m_printoutDC->DeviceToLogicalY(pageMarginsRect.y), - m_printoutDC->DeviceToLogicalXRel(pageMarginsRect.width), - m_printoutDC->DeviceToLogicalYRel(pageMarginsRect.height)); - } - // This DC doesn't match the printed page, so we have to scale. - float scaleX = float(w) / pw; - float scaleY = float(h) / ph; - return wxRect(m_printoutDC->DeviceToLogicalX(wxRound(pageMarginsRect.x * scaleX)), - m_printoutDC->DeviceToLogicalY(wxRound(pageMarginsRect.y * scaleY)), - m_printoutDC->DeviceToLogicalXRel(wxRound(pageMarginsRect.width * scaleX)), - m_printoutDC->DeviceToLogicalYRel(wxRound(pageMarginsRect.height * scaleY))); -} - -void wxPrintout::SetLogicalOrigin(wxCoord x, wxCoord y) -{ - // Set the device origin by specifying a point in logical coordinates. - m_printoutDC->SetDeviceOrigin(m_printoutDC->LogicalToDeviceX(x), - m_printoutDC->LogicalToDeviceY(y)); -} - -void wxPrintout::OffsetLogicalOrigin(wxCoord xoff, wxCoord yoff) -{ - // Offset the device origin by a specified distance in device coordinates. - wxCoord x = m_printoutDC->LogicalToDeviceX(0); - wxCoord y = m_printoutDC->LogicalToDeviceY(0); - m_printoutDC->SetDeviceOrigin(x + m_printoutDC->LogicalToDeviceXRel(xoff), - y + m_printoutDC->LogicalToDeviceYRel(yoff)); -} - - -//---------------------------------------------------------------------------- -// wxPreviewCanvas -//---------------------------------------------------------------------------- - -IMPLEMENT_CLASS(wxPreviewCanvas, wxWindow) - -BEGIN_EVENT_TABLE(wxPreviewCanvas, wxScrolledWindow) - EVT_PAINT(wxPreviewCanvas::OnPaint) - EVT_CHAR(wxPreviewCanvas::OnChar) - EVT_SYS_COLOUR_CHANGED(wxPreviewCanvas::OnSysColourChanged) -#if wxUSE_MOUSEWHEEL - EVT_MOUSEWHEEL(wxPreviewCanvas::OnMouseWheel) -#endif -END_EVENT_TABLE() - -// VZ: the current code doesn't refresh properly without -// wxFULL_REPAINT_ON_RESIZE, this must be fixed as otherwise we have -// really horrible flicker when resizing the preview frame, but without -// this style it simply doesn't work correctly at all... -wxPreviewCanvas::wxPreviewCanvas(wxPrintPreviewBase *preview, wxWindow *parent, - const wxPoint& pos, const wxSize& size, long style, const wxString& name): -wxScrolledWindow(parent, wxID_ANY, pos, size, style | wxFULL_REPAINT_ON_RESIZE, name) -{ - m_printPreview = preview; -#ifdef __WXMAC__ - // The app workspace colour is always white, but we should have - // a contrast with the page. - wxSystemColour colourIndex = wxSYS_COLOUR_3DDKSHADOW; -#elif defined(__WXGTK__) - wxSystemColour colourIndex = wxSYS_COLOUR_BTNFACE; -#else - wxSystemColour colourIndex = wxSYS_COLOUR_APPWORKSPACE; -#endif - SetBackgroundColour(wxSystemSettings::GetColour(colourIndex)); - - SetScrollbars(10, 10, 100, 100); -} - -wxPreviewCanvas::~wxPreviewCanvas() -{ -} - -void wxPreviewCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) -{ - wxPaintDC dc(this); - PrepareDC( dc ); - -/* -#ifdef __WXGTK__ - if (!GetUpdateRegion().IsEmpty()) - dc.SetClippingRegion( GetUpdateRegion() ); -#endif -*/ - - if (m_printPreview) - { - m_printPreview->PaintPage(this, dc); - } -} - -// Responds to colour changes, and passes event on to children. -void wxPreviewCanvas::OnSysColourChanged(wxSysColourChangedEvent& event) -{ -#ifdef __WXMAC__ - // The app workspace colour is always white, but we should have - // a contrast with the page. - wxSystemColour colourIndex = wxSYS_COLOUR_3DDKSHADOW; -#elif defined(__WXGTK__) - wxSystemColour colourIndex = wxSYS_COLOUR_BTNFACE; -#else - wxSystemColour colourIndex = wxSYS_COLOUR_APPWORKSPACE; -#endif - SetBackgroundColour(wxSystemSettings::GetColour(colourIndex)); - Refresh(); - - // Propagate the event to the non-top-level children - wxWindow::OnSysColourChanged(event); -} - -void wxPreviewCanvas::OnChar(wxKeyEvent &event) -{ - wxPreviewControlBar* controlBar = ((wxPreviewFrame*) GetParent())->GetControlBar(); - if (event.GetKeyCode() == WXK_ESCAPE) - { - ((wxPreviewFrame*) GetParent())->Close(true); - return; - } - else if (event.GetKeyCode() == WXK_TAB) - { - controlBar->OnGoto(); - return; - } - else if (event.GetKeyCode() == WXK_RETURN) - { - controlBar->OnPrint(); - return; - } - - if (!event.ControlDown()) - { - event.Skip(); - return; - } - - switch(event.GetKeyCode()) - { - case WXK_PAGEDOWN: - controlBar->OnNext(); break; - case WXK_PAGEUP: - controlBar->OnPrevious(); break; - case WXK_HOME: - controlBar->OnFirst(); break; - case WXK_END: - controlBar->OnLast(); break; - default: - event.Skip(); - } -} - -#if wxUSE_MOUSEWHEEL - -void wxPreviewCanvas::OnMouseWheel(wxMouseEvent& event) -{ - wxPreviewControlBar * - controlBar = wxStaticCast(GetParent(), wxPreviewFrame)->GetControlBar(); - - if ( controlBar ) - { - if ( event.ControlDown() && event.GetWheelRotation() != 0 ) - { - int currentZoom = controlBar->GetZoomControl(); - - int delta; - if ( currentZoom < 100 ) - delta = 5; - else if ( currentZoom <= 120 ) - delta = 10; - else - delta = 50; - - if ( event.GetWheelRotation() > 0 ) - delta = -delta; - - int newZoom = currentZoom + delta; - if ( newZoom < 10 ) - newZoom = 10; - if ( newZoom > 200 ) - newZoom = 200; - if ( newZoom != currentZoom ) - { - controlBar->SetZoomControl(newZoom); - m_printPreview->SetZoom(newZoom); - Refresh(); - } - return; - } - } - - event.Skip(); -} - -#endif // wxUSE_MOUSEWHEEL - -//---------------------------------------------------------------------------- -// wxPreviewControlBar -//---------------------------------------------------------------------------- - -IMPLEMENT_CLASS(wxPreviewControlBar, wxWindow) - -BEGIN_EVENT_TABLE(wxPreviewControlBar, wxPanel) - EVT_BUTTON(wxID_PREVIEW_CLOSE, wxPreviewControlBar::OnWindowClose) - EVT_BUTTON(wxID_PREVIEW_PRINT, wxPreviewControlBar::OnPrintButton) - EVT_BUTTON(wxID_PREVIEW_PREVIOUS, wxPreviewControlBar::OnPreviousButton) - EVT_BUTTON(wxID_PREVIEW_NEXT, wxPreviewControlBar::OnNextButton) - EVT_BUTTON(wxID_PREVIEW_FIRST, wxPreviewControlBar::OnFirstButton) - EVT_BUTTON(wxID_PREVIEW_LAST, wxPreviewControlBar::OnLastButton) - EVT_BUTTON(wxID_PREVIEW_GOTO, wxPreviewControlBar::OnGotoButton) - EVT_CHOICE(wxID_PREVIEW_ZOOM, wxPreviewControlBar::OnZoom) - EVT_PAINT(wxPreviewControlBar::OnPaint) -END_EVENT_TABLE() - -wxPreviewControlBar::wxPreviewControlBar(wxPrintPreviewBase *preview, long buttons, - wxWindow *parent, const wxPoint& pos, const wxSize& size, - long style, const wxString& name): -wxPanel(parent, wxID_ANY, pos, size, style, name) -{ - m_printPreview = preview; - m_closeButton = (wxButton *) NULL; - m_nextPageButton = (wxButton *) NULL; - m_previousPageButton = (wxButton *) NULL; - m_printButton = (wxButton *) NULL; - m_zoomControl = (wxChoice *) NULL; - m_buttonFlags = buttons; -} - -wxPreviewControlBar::~wxPreviewControlBar() -{ -} - -void wxPreviewControlBar::OnPaint(wxPaintEvent& WXUNUSED(event)) -{ - wxPaintDC dc(this); - - int w, h; - GetSize(&w, &h); - dc.SetPen(*wxBLACK_PEN); - dc.SetBrush(*wxTRANSPARENT_BRUSH); - dc.DrawLine( 0, h-1, w, h-1 ); -} - -void wxPreviewControlBar::OnWindowClose(wxCommandEvent& WXUNUSED(event)) -{ - wxPreviewFrame *frame = (wxPreviewFrame *)GetParent(); - frame->Close(true); -} - -void wxPreviewControlBar::OnPrint(void) -{ - wxPrintPreviewBase *preview = GetPrintPreview(); - preview->Print(true); -} - -void wxPreviewControlBar::OnNext(void) -{ - wxPrintPreviewBase *preview = GetPrintPreview(); - if (preview) - { - int currentPage = preview->GetCurrentPage(); - if ((preview->GetMaxPage() > 0) && - (currentPage < preview->GetMaxPage()) && - preview->GetPrintout()->HasPage(currentPage + 1)) - { - preview->SetCurrentPage(currentPage + 1); - } - } -} - -void wxPreviewControlBar::OnPrevious(void) -{ - wxPrintPreviewBase *preview = GetPrintPreview(); - if (preview) - { - int currentPage = preview->GetCurrentPage(); - if ((preview->GetMinPage() > 0) && - (currentPage > preview->GetMinPage()) && - preview->GetPrintout()->HasPage(currentPage - 1)) - { - preview->SetCurrentPage(currentPage - 1); - } - } -} - -void wxPreviewControlBar::OnFirst(void) -{ - wxPrintPreviewBase *preview = GetPrintPreview(); - if (preview) - { - int currentPage = preview->GetMinPage(); - if (preview->GetPrintout()->HasPage(currentPage)) - { - preview->SetCurrentPage(currentPage); - } - } -} - -void wxPreviewControlBar::OnLast(void) -{ - wxPrintPreviewBase *preview = GetPrintPreview(); - if (preview) - { - int currentPage = preview->GetMaxPage(); - if (preview->GetPrintout()->HasPage(currentPage)) - { - preview->SetCurrentPage(currentPage); - } - } -} - -void wxPreviewControlBar::OnGoto(void) -{ - wxPrintPreviewBase *preview = GetPrintPreview(); - if (preview) - { - long currentPage; - - if (preview->GetMinPage() > 0) - { - wxString strPrompt; - wxString strPage; - - strPrompt.Printf( _("Enter a page number between %d and %d:"), - preview->GetMinPage(), preview->GetMaxPage()); - strPage.Printf( wxT("%d"), preview->GetCurrentPage() ); - - strPage = - wxGetTextFromUser( strPrompt, _("Goto Page"), strPage, GetParent()); - - if ( strPage.ToLong( ¤tPage ) ) - if (preview->GetPrintout()->HasPage(currentPage)) - { - preview->SetCurrentPage(currentPage); - } - } - } -} - -void wxPreviewControlBar::OnZoom(wxCommandEvent& WXUNUSED(event)) -{ - int zoom = GetZoomControl(); - if (GetPrintPreview()) - GetPrintPreview()->SetZoom(zoom); -} - -void wxPreviewControlBar::CreateButtons() -{ - SetSize(0, 0, 400, 40); - - wxBoxSizer *item0 = new wxBoxSizer( wxHORIZONTAL ); - - m_closeButton = new wxButton( this, wxID_PREVIEW_CLOSE, _("&Close"), wxDefaultPosition, wxDefaultSize, 0 ); - item0->Add( m_closeButton, 0, wxALIGN_CENTRE|wxALL, 5 ); - - if (m_buttonFlags & wxPREVIEW_PRINT) - { - m_printButton = new wxButton( this, wxID_PREVIEW_PRINT, _("&Print..."), wxDefaultPosition, wxDefaultSize, 0 ); - item0->Add( m_printButton, 0, wxALIGN_CENTRE|wxALL, 5 ); - } - - // Exact-fit buttons are too tiny on wxUniversal - int navButtonStyle; - wxSize navButtonSize; -#ifdef __WXUNIVERSAL__ - navButtonStyle = 0; - navButtonSize = wxSize(40, m_closeButton->GetSize().y); -#else - navButtonStyle = wxBU_EXACTFIT; - navButtonSize = wxDefaultSize; -#endif - - if (m_buttonFlags & wxPREVIEW_FIRST) - { - m_firstPageButton = new wxButton( this, wxID_PREVIEW_FIRST, _("|<<"), wxDefaultPosition, navButtonSize, navButtonStyle ); - item0->Add( m_firstPageButton, 0, wxALIGN_CENTRE|wxALL, 5 ); - } - - if (m_buttonFlags & wxPREVIEW_PREVIOUS) - { - m_previousPageButton = new wxButton( this, wxID_PREVIEW_PREVIOUS, _("<<"), wxDefaultPosition, navButtonSize, navButtonStyle ); - item0->Add( m_previousPageButton, 0, wxALIGN_CENTRE|wxRIGHT|wxTOP|wxBOTTOM, 5 ); - } - - if (m_buttonFlags & wxPREVIEW_NEXT) - { - m_nextPageButton = new wxButton( this, wxID_PREVIEW_NEXT, _(">>"), wxDefaultPosition, navButtonSize, navButtonStyle ); - item0->Add( m_nextPageButton, 0, wxALIGN_CENTRE|wxRIGHT|wxTOP|wxBOTTOM, 5 ); - } - - if (m_buttonFlags & wxPREVIEW_LAST) - { - m_lastPageButton = new wxButton( this, wxID_PREVIEW_LAST, _(">>|"), wxDefaultPosition, navButtonSize, navButtonStyle ); - item0->Add( m_lastPageButton, 0, wxALIGN_CENTRE|wxRIGHT|wxTOP|wxBOTTOM, 5 ); - } - - if (m_buttonFlags & wxPREVIEW_GOTO) - { - m_gotoPageButton = new wxButton( this, wxID_PREVIEW_GOTO, _("&Goto..."), wxDefaultPosition, wxDefaultSize, 0 ); - item0->Add( m_gotoPageButton, 0, wxALIGN_CENTRE|wxALL, 5 ); - } - - if (m_buttonFlags & wxPREVIEW_ZOOM) - { - wxString choices[] = - { - wxT("10%"), wxT("15%"), wxT("20%"), wxT("25%"), wxT("30%"), wxT("35%"), wxT("40%"), wxT("45%"), wxT("50%"), wxT("55%"), - wxT("60%"), wxT("65%"), wxT("70%"), wxT("75%"), wxT("80%"), wxT("85%"), wxT("90%"), wxT("95%"), wxT("100%"), wxT("110%"), - wxT("120%"), wxT("150%"), wxT("200%") - }; - int n = WXSIZEOF(choices); - - m_zoomControl = new wxChoice( this, wxID_PREVIEW_ZOOM, wxDefaultPosition, wxSize(70,wxDefaultCoord), n, choices, 0 ); - item0->Add( m_zoomControl, 0, wxALIGN_CENTRE|wxALL, 5 ); - SetZoomControl(m_printPreview->GetZoom()); - } - - SetSizer(item0); - item0->Fit(this); -} - -void wxPreviewControlBar::SetZoomControl(int zoom) -{ - if (m_zoomControl) - { - int n, count = m_zoomControl->GetCount(); - long val; - for (n=0; nGetString(n).BeforeFirst(wxT('%')).ToLong(&val) && - (val >= long(zoom))) - { - m_zoomControl->SetSelection(n); - return; - } - } - - m_zoomControl->SetSelection(count-1); - } -} - -int wxPreviewControlBar::GetZoomControl() -{ - if (m_zoomControl && (m_zoomControl->GetStringSelection() != wxEmptyString)) - { - long val; - if (m_zoomControl->GetStringSelection().BeforeFirst(wxT('%')).ToLong(&val)) - return int(val); - } - - return 0; -} - - -/* -* Preview frame -*/ - -IMPLEMENT_CLASS(wxPreviewFrame, wxFrame) - -BEGIN_EVENT_TABLE(wxPreviewFrame, wxFrame) - EVT_CLOSE(wxPreviewFrame::OnCloseWindow) -END_EVENT_TABLE() - -wxPreviewFrame::wxPreviewFrame(wxPrintPreviewBase *preview, wxWindow *parent, const wxString& title, - const wxPoint& pos, const wxSize& size, long style, const wxString& name): -wxFrame(parent, wxID_ANY, title, pos, size, style, name) -{ - m_printPreview = preview; - m_controlBar = NULL; - m_previewCanvas = NULL; - m_windowDisabler = NULL; - - // Give the application icon -#ifdef __WXMSW__ - wxFrame* topFrame = wxDynamicCast(wxTheApp->GetTopWindow(), wxFrame); - if (topFrame) - SetIcon(topFrame->GetIcon()); -#endif -} - -wxPreviewFrame::~wxPreviewFrame() -{ -} - -void wxPreviewFrame::OnCloseWindow(wxCloseEvent& WXUNUSED(event)) -{ - if (m_windowDisabler) - delete m_windowDisabler; - - // Need to delete the printout and the print preview - wxPrintout *printout = m_printPreview->GetPrintout(); - if (printout) - { - delete printout; - m_printPreview->SetPrintout(NULL); - m_printPreview->SetCanvas(NULL); - m_printPreview->SetFrame(NULL); - } - delete m_printPreview; - - Destroy(); -} - -void wxPreviewFrame::Initialize() -{ -#if wxUSE_STATUSBAR - CreateStatusBar(); -#endif - CreateCanvas(); - CreateControlBar(); - - m_printPreview->SetCanvas(m_previewCanvas); - m_printPreview->SetFrame(this); - - wxBoxSizer *item0 = new wxBoxSizer( wxVERTICAL ); - - item0->Add( m_controlBar, 0, wxGROW|wxALIGN_CENTER_VERTICAL, 5 ); - item0->Add( m_previewCanvas, 1, wxGROW|wxALIGN_CENTER_VERTICAL, 5 ); - - SetAutoLayout( true ); - SetSizer( item0 ); - - m_windowDisabler = new wxWindowDisabler(this); - - Layout(); - - m_printPreview->AdjustScrollbars(m_previewCanvas); - m_previewCanvas->SetFocus(); - m_controlBar->SetFocus(); -} - -void wxPreviewFrame::CreateCanvas() -{ - m_previewCanvas = new wxPreviewCanvas(m_printPreview, this); -} - -void wxPreviewFrame::CreateControlBar() -{ - long buttons = wxPREVIEW_DEFAULT; - if (m_printPreview->GetPrintoutForPrinting()) - buttons |= wxPREVIEW_PRINT; - - m_controlBar = new wxPreviewControlBar(m_printPreview, buttons, this, wxPoint(0,0), wxSize(400, 40)); - m_controlBar->CreateButtons(); -} - -/* -* Print preview -*/ - -IMPLEMENT_CLASS(wxPrintPreviewBase, wxObject) - -wxPrintPreviewBase::wxPrintPreviewBase(wxPrintout *printout, - wxPrintout *printoutForPrinting, - wxPrintData *data) -{ - if (data) - m_printDialogData = (*data); - - Init(printout, printoutForPrinting); -} - -wxPrintPreviewBase::wxPrintPreviewBase(wxPrintout *printout, - wxPrintout *printoutForPrinting, - wxPrintDialogData *data) -{ - if (data) - m_printDialogData = (*data); - - Init(printout, printoutForPrinting); -} - -void wxPrintPreviewBase::Init(wxPrintout *printout, - wxPrintout *printoutForPrinting) -{ - m_isOk = true; - m_previewPrintout = printout; - if (m_previewPrintout) - m_previewPrintout->SetIsPreview(true); - - m_printPrintout = printoutForPrinting; - - m_previewCanvas = NULL; - m_previewFrame = NULL; - m_previewBitmap = NULL; - m_currentPage = 1; - m_currentZoom = 70; - m_topMargin = 40; - m_leftMargin = 40; - m_pageWidth = 0; - m_pageHeight = 0; - m_printingPrepared = false; - m_minPage = 1; - m_maxPage = 1; -} - -wxPrintPreviewBase::~wxPrintPreviewBase() -{ - if (m_previewPrintout) - delete m_previewPrintout; - if (m_previewBitmap) - delete m_previewBitmap; - if (m_printPrintout) - delete m_printPrintout; -} - -bool wxPrintPreviewBase::SetCurrentPage(int pageNum) -{ - if (m_currentPage == pageNum) - return true; - - m_currentPage = pageNum; - if (m_previewBitmap) - { - delete m_previewBitmap; - m_previewBitmap = NULL; - } - - if (m_previewCanvas) - { - AdjustScrollbars(m_previewCanvas); - - if (!RenderPage(pageNum)) - return false; - m_previewCanvas->Refresh(); - m_previewCanvas->SetFocus(); - } - return true; -} - -int wxPrintPreviewBase::GetCurrentPage() const - { return m_currentPage; } -void wxPrintPreviewBase::SetPrintout(wxPrintout *printout) - { m_previewPrintout = printout; } -wxPrintout *wxPrintPreviewBase::GetPrintout() const - { return m_previewPrintout; } -wxPrintout *wxPrintPreviewBase::GetPrintoutForPrinting() const - { return m_printPrintout; } -void wxPrintPreviewBase::SetFrame(wxFrame *frame) - { m_previewFrame = frame; } -void wxPrintPreviewBase::SetCanvas(wxPreviewCanvas *canvas) - { m_previewCanvas = canvas; } -wxFrame *wxPrintPreviewBase::GetFrame() const - { return m_previewFrame; } -wxPreviewCanvas *wxPrintPreviewBase::GetCanvas() const - { return m_previewCanvas; } - -void wxPrintPreviewBase::CalcRects(wxPreviewCanvas *canvas, wxRect& pageRect, wxRect& paperRect) -{ - // Calculate the rectangles for the printable area of the page and the - // entire paper as they appear on the canvas on-screen. - int canvasWidth, canvasHeight; - canvas->GetSize(&canvasWidth, &canvasHeight); - - float zoomScale = float(m_currentZoom) / 100; - float screenPrintableWidth = zoomScale * m_pageWidth * m_previewScaleX; - float screenPrintableHeight = zoomScale * m_pageHeight * m_previewScaleY; - - wxRect devicePaperRect = m_previewPrintout->GetPaperRectPixels(); - wxCoord devicePrintableWidth, devicePrintableHeight; - m_previewPrintout->GetPageSizePixels(&devicePrintableWidth, &devicePrintableHeight); - float scaleX = screenPrintableWidth / devicePrintableWidth; - float scaleY = screenPrintableHeight / devicePrintableHeight; - paperRect.width = wxCoord(scaleX * devicePaperRect.width); - paperRect.height = wxCoord(scaleY * devicePaperRect.height); - - paperRect.x = wxCoord((canvasWidth - paperRect.width)/ 2.0); - if (paperRect.x < m_leftMargin) - paperRect.x = m_leftMargin; - paperRect.y = wxCoord((canvasHeight - paperRect.height)/ 2.0); - if (paperRect.y < m_topMargin) - paperRect.y = m_topMargin; - - pageRect.x = paperRect.x - wxCoord(scaleX * devicePaperRect.x); - pageRect.y = paperRect.y - wxCoord(scaleY * devicePaperRect.y); - pageRect.width = wxCoord(screenPrintableWidth); - pageRect.height = wxCoord(screenPrintableHeight); -} - - -bool wxPrintPreviewBase::PaintPage(wxPreviewCanvas *canvas, wxDC& dc) -{ - DrawBlankPage(canvas, dc); - - if (!m_previewBitmap) - if (!RenderPage(m_currentPage)) - return false; - if (!m_previewBitmap) - return false; - if (!canvas) - return false; - - wxRect pageRect, paperRect; - CalcRects(canvas, pageRect, paperRect); - wxMemoryDC temp_dc; - temp_dc.SelectObject(*m_previewBitmap); - - dc.Blit(pageRect.x, pageRect.y, - m_previewBitmap->GetWidth(), m_previewBitmap->GetHeight(), &temp_dc, 0, 0); - - temp_dc.SelectObject(wxNullBitmap); - return true; -} - -// Adjusts the scrollbars for the current scale -void wxPrintPreviewBase::AdjustScrollbars(wxPreviewCanvas *canvas) -{ - if (!canvas) - return ; - - wxRect pageRect, paperRect; - CalcRects(canvas, pageRect, paperRect); - int totalWidth = paperRect.width + 2 * m_leftMargin; - int totalHeight = paperRect.height + 2 * m_topMargin; - int scrollUnitsX = totalWidth / 10; - int scrollUnitsY = totalHeight / 10; - wxSize virtualSize = canvas->GetVirtualSize(); - if (virtualSize.GetWidth() != totalWidth || virtualSize.GetHeight() != totalHeight) - canvas->SetScrollbars(10, 10, scrollUnitsX, scrollUnitsY, 0, 0, true); -} - -bool wxPrintPreviewBase::RenderPage(int pageNum) -{ - wxBusyCursor busy; - - if (!m_previewCanvas) - { - wxFAIL_MSG(_T("wxPrintPreviewBase::RenderPage: must use wxPrintPreviewBase::SetCanvas to let me know about the canvas!")); - return false; - } - - wxRect pageRect, paperRect; - CalcRects(m_previewCanvas, pageRect, paperRect); - - if (!m_previewBitmap) - { - m_previewBitmap = new wxBitmap(pageRect.width, pageRect.height); - - if (!m_previewBitmap || !m_previewBitmap->Ok()) - { - if (m_previewBitmap) { - delete m_previewBitmap; - m_previewBitmap = NULL; - } - wxMessageBox(_("Sorry, not enough memory to create a preview."), _("Print Preview Failure"), wxOK); - return false; - } - } - - wxMemoryDC memoryDC; - memoryDC.SelectObject(*m_previewBitmap); - - memoryDC.Clear(); - - m_previewPrintout->SetDC(&memoryDC); - m_previewPrintout->SetPageSizePixels(m_pageWidth, m_pageHeight); - - // Need to delay OnPreparePrinting until here, so we have enough information. - if (!m_printingPrepared) - { - m_previewPrintout->OnPreparePrinting(); - int selFrom, selTo; - m_previewPrintout->GetPageInfo(&m_minPage, &m_maxPage, &selFrom, &selTo); - m_printingPrepared = true; - } - - m_previewPrintout->OnBeginPrinting(); - - if (!m_previewPrintout->OnBeginDocument(m_printDialogData.GetFromPage(), m_printDialogData.GetToPage())) - { - wxMessageBox(_("Could not start document preview."), _("Print Preview Failure"), wxOK); - - memoryDC.SelectObject(wxNullBitmap); - - delete m_previewBitmap; - m_previewBitmap = NULL; - return false; - } - - m_previewPrintout->OnPrintPage(pageNum); - m_previewPrintout->OnEndDocument(); - m_previewPrintout->OnEndPrinting(); - - m_previewPrintout->SetDC(NULL); - - memoryDC.SelectObject(wxNullBitmap); - -#if wxUSE_STATUSBAR - wxString status; - if (m_maxPage != 0) - status = wxString::Format(_("Page %d of %d"), pageNum, m_maxPage); - else - status = wxString::Format(_("Page %d"), pageNum); - - if (m_previewFrame) - m_previewFrame->SetStatusText(status); -#endif - - return true; -} - -bool wxPrintPreviewBase::DrawBlankPage(wxPreviewCanvas *canvas, wxDC& dc) -{ - wxRect pageRect, paperRect; - - CalcRects(canvas, pageRect, paperRect); - - // Draw shadow, allowing for 1-pixel border AROUND the actual paper - wxCoord shadowOffset = 4; - - dc.SetPen(*wxBLACK_PEN); - dc.SetBrush(*wxBLACK_BRUSH); - dc.DrawRectangle(paperRect.x + shadowOffset, paperRect.y + paperRect.height + 1, - paperRect.width, shadowOffset); - - dc.DrawRectangle(paperRect.x + paperRect.width, paperRect.y + shadowOffset, - shadowOffset, paperRect.height); - - // Draw blank page allowing for 1-pixel border AROUND the actual paper - dc.SetPen(*wxBLACK_PEN); - dc.SetBrush(*wxWHITE_BRUSH); - dc.DrawRectangle(paperRect.x - 2, paperRect.y - 1, - paperRect.width + 3, paperRect.height + 2); - - return true; -} - -void wxPrintPreviewBase::SetZoom(int percent) -{ - if (m_currentZoom == percent) - return; - - m_currentZoom = percent; - if (m_previewBitmap) - { - delete m_previewBitmap; - m_previewBitmap = NULL; - } - - if (m_previewCanvas) - { - AdjustScrollbars(m_previewCanvas); - RenderPage(m_currentPage); - ((wxScrolledWindow *) m_previewCanvas)->Scroll(0, 0); - m_previewCanvas->ClearBackground(); - m_previewCanvas->Refresh(); - m_previewCanvas->SetFocus(); - } -} - -wxPrintDialogData& wxPrintPreviewBase::GetPrintDialogData() -{ - return m_printDialogData; -} - -int wxPrintPreviewBase::GetZoom() const -{ return m_currentZoom; } -int wxPrintPreviewBase::GetMaxPage() const -{ return m_maxPage; } -int wxPrintPreviewBase::GetMinPage() const -{ return m_minPage; } -bool wxPrintPreviewBase::IsOk() const -{ return m_isOk; } -void wxPrintPreviewBase::SetOk(bool ok) -{ m_isOk = ok; } - -//---------------------------------------------------------------------------- -// wxPrintPreview -//---------------------------------------------------------------------------- - -IMPLEMENT_CLASS(wxPrintPreview, wxPrintPreviewBase) - -wxPrintPreview::wxPrintPreview(wxPrintout *printout, - wxPrintout *printoutForPrinting, - wxPrintDialogData *data) : - wxPrintPreviewBase( printout, printoutForPrinting, data ) -{ - m_pimpl = wxPrintFactory::GetFactory()-> - CreatePrintPreview( printout, printoutForPrinting, data ); -} - -wxPrintPreview::wxPrintPreview(wxPrintout *printout, - wxPrintout *printoutForPrinting, - wxPrintData *data ) : - wxPrintPreviewBase( printout, printoutForPrinting, data ) -{ - m_pimpl = wxPrintFactory::GetFactory()-> - CreatePrintPreview( printout, printoutForPrinting, data ); -} - -wxPrintPreview::~wxPrintPreview() -{ - delete m_pimpl; - - // don't delete twice - m_printPrintout = NULL; - m_previewPrintout = NULL; - m_previewBitmap = NULL; -} - -bool wxPrintPreview::SetCurrentPage(int pageNum) -{ - return m_pimpl->SetCurrentPage( pageNum ); -} - -int wxPrintPreview::GetCurrentPage() const -{ - return m_pimpl->GetCurrentPage(); -} - -void wxPrintPreview::SetPrintout(wxPrintout *printout) -{ - m_pimpl->SetPrintout( printout ); -} - -wxPrintout *wxPrintPreview::GetPrintout() const -{ - return m_pimpl->GetPrintout(); -} - -wxPrintout *wxPrintPreview::GetPrintoutForPrinting() const -{ - return m_pimpl->GetPrintoutForPrinting(); -} - -void wxPrintPreview::SetFrame(wxFrame *frame) -{ - m_pimpl->SetFrame( frame ); -} - -void wxPrintPreview::SetCanvas(wxPreviewCanvas *canvas) -{ - m_pimpl->SetCanvas( canvas ); -} - -wxFrame *wxPrintPreview::GetFrame() const -{ - return m_pimpl->GetFrame(); -} - -wxPreviewCanvas *wxPrintPreview::GetCanvas() const -{ - return m_pimpl->GetCanvas(); -} - -bool wxPrintPreview::PaintPage(wxPreviewCanvas *canvas, wxDC& dc) -{ - return m_pimpl->PaintPage( canvas, dc ); -} - -bool wxPrintPreview::DrawBlankPage(wxPreviewCanvas *canvas, wxDC& dc) -{ - return m_pimpl->DrawBlankPage( canvas, dc ); -} - -void wxPrintPreview::AdjustScrollbars(wxPreviewCanvas *canvas) -{ - m_pimpl->AdjustScrollbars( canvas ); -} - -bool wxPrintPreview::RenderPage(int pageNum) -{ - return m_pimpl->RenderPage( pageNum ); -} - -void wxPrintPreview::SetZoom(int percent) -{ - m_pimpl->SetZoom( percent ); -} - -int wxPrintPreview::GetZoom() const -{ - return m_pimpl->GetZoom(); -} - -wxPrintDialogData& wxPrintPreview::GetPrintDialogData() -{ - return m_pimpl->GetPrintDialogData(); -} - -int wxPrintPreview::GetMaxPage() const -{ - return m_pimpl->GetMaxPage(); -} - -int wxPrintPreview::GetMinPage() const -{ - return m_pimpl->GetMinPage(); -} - -bool wxPrintPreview::IsOk() const -{ - return m_pimpl->Ok(); -} - -void wxPrintPreview::SetOk(bool ok) -{ - m_pimpl->SetOk( ok ); -} - -bool wxPrintPreview::Print(bool interactive) -{ - return m_pimpl->Print( interactive ); -} - -void wxPrintPreview::DetermineScaling() -{ - m_pimpl->DetermineScaling(); -} - -#endif // wxUSE_PRINTING_ARCHITECTURE +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/prntbase.cpp +// Purpose: Printing framework base class implementation +// Author: Julian Smart +// Modified by: +// Created: 04/01/98 +// RCS-ID: $Id: prntbase.cpp 42763 2006-10-30 20:34:25Z VZ $ +// Copyright: (c) Julian Smart +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_PRINTING_ARCHITECTURE + +#include "wx/dcprint.h" + +#ifndef WX_PRECOMP + #if defined(__WXMSW__) + #include "wx/msw/wrapcdlg.h" + #endif // MSW + #include "wx/utils.h" + #include "wx/dc.h" + #include "wx/app.h" + #include "wx/math.h" + #include "wx/msgdlg.h" + #include "wx/layout.h" + #include "wx/choice.h" + #include "wx/button.h" + #include "wx/settings.h" + #include "wx/dcmemory.h" + #include "wx/stattext.h" + #include "wx/intl.h" + #include "wx/textdlg.h" + #include "wx/sizer.h" + #include "wx/module.h" +#endif // !WX_PRECOMP + +#include "wx/prntbase.h" +#include "wx/printdlg.h" +#include "wx/print.h" +#include "wx/dcprint.h" + +#include +#include + +#if defined(__WXMSW__) && !defined(__WXUNIVERSAL__) +#include "wx/msw/printdlg.h" +#elif defined(__WXMAC__) +#include "wx/mac/printdlg.h" +#include "wx/mac/private/print.h" +#else +#include "wx/generic/prntdlgg.h" +#include "wx/dcps.h" +#endif + +#ifdef __WXMSW__ + #ifndef __WIN32__ + #include + #endif +#endif // __WXMSW__ + +//---------------------------------------------------------------------------- +// wxPrintFactory +//---------------------------------------------------------------------------- + +wxPrintFactory *wxPrintFactory::m_factory = NULL; + +void wxPrintFactory::SetPrintFactory( wxPrintFactory *factory ) +{ + if (wxPrintFactory::m_factory) + delete wxPrintFactory::m_factory; + + wxPrintFactory::m_factory = factory; +} + +wxPrintFactory *wxPrintFactory::GetFactory() +{ + if (!wxPrintFactory::m_factory) + wxPrintFactory::m_factory = new wxNativePrintFactory; + + return wxPrintFactory::m_factory; +} + +//---------------------------------------------------------------------------- +// wxNativePrintFactory +//---------------------------------------------------------------------------- + +wxPrinterBase *wxNativePrintFactory::CreatePrinter( wxPrintDialogData *data ) +{ +#if defined(__WXMSW__) && !defined(__WXUNIVERSAL__) + return new wxWindowsPrinter( data ); +#elif defined(__WXMAC__) + return new wxMacPrinter( data ); +#elif defined(__WXPM__) + return new wxOS2Printer( data ); +#else + return new wxPostScriptPrinter( data ); +#endif +} + +wxPrintPreviewBase *wxNativePrintFactory::CreatePrintPreview( wxPrintout *preview, + wxPrintout *printout, wxPrintDialogData *data ) +{ +#if defined(__WXMSW__) && !defined(__WXUNIVERSAL__) + return new wxWindowsPrintPreview( preview, printout, data ); +#elif defined(__WXMAC__) + return new wxMacPrintPreview( preview, printout, data ); +#elif defined(__WXPM__) + return new wxOS2PrintPreview( preview, printout, data ); +#else + return new wxPostScriptPrintPreview( preview, printout, data ); +#endif +} + +wxPrintPreviewBase *wxNativePrintFactory::CreatePrintPreview( wxPrintout *preview, + wxPrintout *printout, wxPrintData *data ) +{ +#if defined(__WXMSW__) && !defined(__WXUNIVERSAL__) + return new wxWindowsPrintPreview( preview, printout, data ); +#elif defined(__WXMAC__) + return new wxMacPrintPreview( preview, printout, data ); +#elif defined(__WXPM__) + return new wxOS2PrintPreview( preview, printout, data ); +#else + return new wxPostScriptPrintPreview( preview, printout, data ); +#endif +} + +wxPrintDialogBase *wxNativePrintFactory::CreatePrintDialog( wxWindow *parent, + wxPrintDialogData *data ) +{ +#if defined(__WXMSW__) && !defined(__WXUNIVERSAL__) + return new wxWindowsPrintDialog( parent, data ); +#elif defined(__WXMAC__) + return new wxMacPrintDialog( parent, data ); +#else + return new wxGenericPrintDialog( parent, data ); +#endif +} + +wxPrintDialogBase *wxNativePrintFactory::CreatePrintDialog( wxWindow *parent, + wxPrintData *data ) +{ +#if defined(__WXMSW__) && !defined(__WXUNIVERSAL__) + return new wxWindowsPrintDialog( parent, data ); +#elif defined(__WXMAC__) + return new wxMacPrintDialog( parent, data ); +#else + return new wxGenericPrintDialog( parent, data ); +#endif +} + +wxPageSetupDialogBase *wxNativePrintFactory::CreatePageSetupDialog( wxWindow *parent, + wxPageSetupDialogData *data ) +{ +#if defined(__WXMSW__) && !defined(__WXUNIVERSAL__) + return new wxWindowsPageSetupDialog( parent, data ); +#elif defined(__WXMAC__) + return new wxMacPageSetupDialog( parent, data ); +#else + return new wxGenericPageSetupDialog( parent, data ); +#endif +} + +bool wxNativePrintFactory::HasPrintSetupDialog() +{ +#if defined(__WXMSW__) && !defined(__WXUNIVERSAL__) + return false; +#elif defined(__WXMAC__) + return false; +#else + // Only here do we need to provide the print setup + // dialog ourselves, the other platforms either have + // none, don't make it accessible or let you configure + // the printer from the wxPrintDialog anyway. + return true; +#endif + +} + +wxDialog *wxNativePrintFactory::CreatePrintSetupDialog( wxWindow *parent, + wxPrintData *data ) +{ +#if defined(__WXMSW__) && !defined(__WXUNIVERSAL__) + wxUnusedVar(parent); + wxUnusedVar(data); + return NULL; +#elif defined(__WXMAC__) + wxUnusedVar(parent); + wxUnusedVar(data); + return NULL; +#else + // Only here do we need to provide the print setup + // dialog ourselves, the other platforms either have + // none, don't make it accessible or let you configure + // the printer from the wxPrintDialog anyway. + return new wxGenericPrintSetupDialog( parent, data ); +#endif +} + +wxDC* wxNativePrintFactory::CreatePrinterDC( const wxPrintData& data ) +{ +#if defined(__WXMSW__) && !defined(__WXUNIVERSAL__) + return new wxPrinterDC(data); +#elif defined(__WXMAC__) + return new wxPrinterDC(data); +#else + return new wxPostScriptDC(data); +#endif +} + +bool wxNativePrintFactory::HasOwnPrintToFile() +{ + // Only relevant for PostScript and here the + // setup dialog provides no "print to file" + // option. In the GNOME setup dialog, the + // setup dialog has its own print to file. + return false; +} + +bool wxNativePrintFactory::HasPrinterLine() +{ + // Only relevant for PostScript for now + return true; +} + +wxString wxNativePrintFactory::CreatePrinterLine() +{ + // Only relevant for PostScript for now + + // We should query "lpstat -d" here + return _("Generic PostScript"); +} + +bool wxNativePrintFactory::HasStatusLine() +{ + // Only relevant for PostScript for now + return true; +} + +wxString wxNativePrintFactory::CreateStatusLine() +{ + // Only relevant for PostScript for now + + // We should query "lpstat -r" or "lpstat -p" here + return _("Ready"); +} + +wxPrintNativeDataBase *wxNativePrintFactory::CreatePrintNativeData() +{ +#if defined(__WXMSW__) && !defined(__WXUNIVERSAL__) + return new wxWindowsPrintNativeData; +#elif defined(__WXMAC__) + return new wxMacCarbonPrintData; +#else + return new wxPostScriptPrintNativeData; +#endif +} + +//---------------------------------------------------------------------------- +// wxPrintNativeDataBase +//---------------------------------------------------------------------------- + +IMPLEMENT_ABSTRACT_CLASS(wxPrintNativeDataBase, wxObject) + +wxPrintNativeDataBase::wxPrintNativeDataBase() +{ + m_ref = 1; +} + +//---------------------------------------------------------------------------- +// wxPrintFactoryModule +//---------------------------------------------------------------------------- + +class wxPrintFactoryModule: public wxModule +{ +public: + wxPrintFactoryModule() {} + bool OnInit() { return true; } + void OnExit() { wxPrintFactory::SetPrintFactory( NULL ); } + +private: + DECLARE_DYNAMIC_CLASS(wxPrintFactoryModule) +}; + +IMPLEMENT_DYNAMIC_CLASS(wxPrintFactoryModule, wxModule) + +//---------------------------------------------------------------------------- +// wxPrinterBase +//---------------------------------------------------------------------------- + +IMPLEMENT_CLASS(wxPrinterBase, wxObject) + +wxPrinterBase::wxPrinterBase(wxPrintDialogData *data) +{ + m_currentPrintout = (wxPrintout *) NULL; + sm_abortWindow = (wxWindow *) NULL; + sm_abortIt = false; + if (data) + m_printDialogData = (*data); + sm_lastError = wxPRINTER_NO_ERROR; +} + +wxWindow *wxPrinterBase::sm_abortWindow = (wxWindow *) NULL; +bool wxPrinterBase::sm_abortIt = false; +wxPrinterError wxPrinterBase::sm_lastError = wxPRINTER_NO_ERROR; + +wxPrinterBase::~wxPrinterBase() +{ +} + +wxWindow *wxPrinterBase::CreateAbortWindow(wxWindow *parent, wxPrintout * printout) +{ + wxPrintAbortDialog *dialog = new wxPrintAbortDialog(parent, _("Printing ") , wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE); + + wxBoxSizer *button_sizer = new wxBoxSizer( wxVERTICAL ); + button_sizer->Add( new wxStaticText(dialog, wxID_ANY, _("Please wait while printing\n") + printout->GetTitle() ), 0, wxALL, 10 ); + button_sizer->Add( new wxButton( dialog, wxID_CANCEL, wxT("Cancel") ), 0, wxALL | wxALIGN_CENTER, 10 ); + + dialog->SetAutoLayout( true ); + dialog->SetSizer( button_sizer ); + + button_sizer->Fit(dialog); + button_sizer->SetSizeHints (dialog) ; + + return dialog; +} + +void wxPrinterBase::ReportError(wxWindow *parent, wxPrintout *WXUNUSED(printout), const wxString& message) +{ + wxMessageBox(message, _("Printing Error"), wxOK, parent); +} + +wxPrintDialogData& wxPrinterBase::GetPrintDialogData() const +{ + return (wxPrintDialogData&) m_printDialogData; +} + +//---------------------------------------------------------------------------- +// wxPrinter +//---------------------------------------------------------------------------- + +IMPLEMENT_CLASS(wxPrinter, wxPrinterBase) + +wxPrinter::wxPrinter(wxPrintDialogData *data) +{ + m_pimpl = wxPrintFactory::GetFactory()->CreatePrinter( data ); +} + +wxPrinter::~wxPrinter() +{ + delete m_pimpl; +} + +wxWindow *wxPrinter::CreateAbortWindow(wxWindow *parent, wxPrintout *printout) +{ + return m_pimpl->CreateAbortWindow( parent, printout ); +} + +void wxPrinter::ReportError(wxWindow *parent, wxPrintout *printout, const wxString& message) +{ + m_pimpl->ReportError( parent, printout, message ); +} + +bool wxPrinter::Setup(wxWindow *parent) +{ + return m_pimpl->Setup( parent ); +} + +bool wxPrinter::Print(wxWindow *parent, wxPrintout *printout, bool prompt) +{ + return m_pimpl->Print( parent, printout, prompt ); +} + +wxDC* wxPrinter::PrintDialog(wxWindow *parent) +{ + return m_pimpl->PrintDialog( parent ); +} + +wxPrintDialogData& wxPrinter::GetPrintDialogData() const +{ + return m_pimpl->GetPrintDialogData(); +} + +// --------------------------------------------------------------------------- +// wxPrintDialogBase: the dialog for printing. +// --------------------------------------------------------------------------- + +IMPLEMENT_ABSTRACT_CLASS(wxPrintDialogBase, wxDialog) + +wxPrintDialogBase::wxPrintDialogBase(wxWindow *parent, + wxWindowID id, + const wxString &title, + const wxPoint &pos, + const wxSize &size, + long style) + : wxDialog( parent, id, title.empty() ? wxString(_("Print")) : title, + pos, size, style ) +{ +} + +// --------------------------------------------------------------------------- +// wxPrintDialog: the dialog for printing +// --------------------------------------------------------------------------- + +IMPLEMENT_CLASS(wxPrintDialog, wxObject) + +wxPrintDialog::wxPrintDialog(wxWindow *parent, wxPrintDialogData* data) +{ + m_pimpl = wxPrintFactory::GetFactory()->CreatePrintDialog( parent, data ); +} + +wxPrintDialog::wxPrintDialog(wxWindow *parent, wxPrintData* data) +{ + m_pimpl = wxPrintFactory::GetFactory()->CreatePrintDialog( parent, data ); +} + +wxPrintDialog::~wxPrintDialog() +{ + delete m_pimpl; +} + +int wxPrintDialog::ShowModal() +{ + return m_pimpl->ShowModal(); +} + +wxPrintDialogData& wxPrintDialog::GetPrintDialogData() +{ + return m_pimpl->GetPrintDialogData(); +} + +wxPrintData& wxPrintDialog::GetPrintData() +{ + return m_pimpl->GetPrintData(); +} + +wxDC *wxPrintDialog::GetPrintDC() +{ + return m_pimpl->GetPrintDC(); +} + +// --------------------------------------------------------------------------- +// wxPageSetupDialogBase: the page setup dialog +// --------------------------------------------------------------------------- + +IMPLEMENT_ABSTRACT_CLASS(wxPageSetupDialogBase, wxDialog) + +wxPageSetupDialogBase::wxPageSetupDialogBase(wxWindow *parent, + wxWindowID id, + const wxString &title, + const wxPoint &pos, + const wxSize &size, + long style) + : wxDialog( parent, id, title.empty() ? wxString(_("Page setup")) : title, + pos, size, style ) +{ +} + +// --------------------------------------------------------------------------- +// wxPageSetupDialog: the page setup dialog +// --------------------------------------------------------------------------- + +IMPLEMENT_CLASS(wxPageSetupDialog, wxObject) + +wxPageSetupDialog::wxPageSetupDialog(wxWindow *parent, wxPageSetupDialogData *data ) +{ + m_pimpl = wxPrintFactory::GetFactory()->CreatePageSetupDialog( parent, data ); +} + +wxPageSetupDialog::~wxPageSetupDialog() +{ + delete m_pimpl; +} + +int wxPageSetupDialog::ShowModal() +{ + return m_pimpl->ShowModal(); +} + +wxPageSetupDialogData& wxPageSetupDialog::GetPageSetupDialogData() +{ + return m_pimpl->GetPageSetupDialogData(); +} + +// old name +wxPageSetupDialogData& wxPageSetupDialog::GetPageSetupData() +{ + return m_pimpl->GetPageSetupDialogData(); +} + +//---------------------------------------------------------------------------- +// wxPrintAbortDialog +//---------------------------------------------------------------------------- + +BEGIN_EVENT_TABLE(wxPrintAbortDialog, wxDialog) + EVT_BUTTON(wxID_CANCEL, wxPrintAbortDialog::OnCancel) +END_EVENT_TABLE() + +void wxPrintAbortDialog::OnCancel(wxCommandEvent& WXUNUSED(event)) +{ + wxPrinterBase::sm_abortIt = true; + wxPrinterBase::sm_abortWindow->Show(false); + wxPrinterBase::sm_abortWindow->Close(true); + wxPrinterBase::sm_abortWindow = (wxWindow *) NULL; +} + +//---------------------------------------------------------------------------- +// wxPrintout +//---------------------------------------------------------------------------- + +IMPLEMENT_ABSTRACT_CLASS(wxPrintout, wxObject) + +wxPrintout::wxPrintout(const wxString& title) +{ + m_printoutTitle = title ; + m_printoutDC = (wxDC *) NULL; + m_pageWidthMM = 0; + m_pageHeightMM = 0; + m_pageWidthPixels = 0; + m_pageHeightPixels = 0; + m_PPIScreenX = 0; + m_PPIScreenY = 0; + m_PPIPrinterX = 0; + m_PPIPrinterY = 0; + m_isPreview = false; +} + +wxPrintout::~wxPrintout() +{ +} + +bool wxPrintout::OnBeginDocument(int WXUNUSED(startPage), int WXUNUSED(endPage)) +{ + return GetDC()->StartDoc(_("Printing ") + m_printoutTitle); +} + +void wxPrintout::OnEndDocument() +{ + GetDC()->EndDoc(); +} + +void wxPrintout::OnBeginPrinting() +{ +} + +void wxPrintout::OnEndPrinting() +{ +} + +bool wxPrintout::HasPage(int page) +{ + return (page == 1); +} + +void wxPrintout::GetPageInfo(int *minPage, int *maxPage, int *fromPage, int *toPage) +{ + *minPage = 1; + *maxPage = 32000; + *fromPage = 1; + *toPage = 1; +} + +void wxPrintout::FitThisSizeToPaper(const wxSize& imageSize) +{ + // Set the DC scale and origin so that the given image size fits within the + // entire page and the origin is at the top left corner of the page. Note + // that with most printers, portions of the page will be non-printable. Use + // this if you're managing your own page margins. + if (!m_printoutDC) return; + wxRect paperRect = GetPaperRectPixels(); + wxCoord pw, ph; + GetPageSizePixels(&pw, &ph); + wxCoord w, h; + m_printoutDC->GetSize(&w, &h); + float scaleX = ((float(paperRect.width) * w) / (float(pw) * imageSize.x)); + float scaleY = ((float(paperRect.height) * h) / (float(ph) * imageSize.y)); + float actualScale = wxMin(scaleX, scaleY); + m_printoutDC->SetUserScale(actualScale, actualScale); + m_printoutDC->SetDeviceOrigin(0, 0); + wxRect logicalPaperRect = GetLogicalPaperRect(); + SetLogicalOrigin(logicalPaperRect.x, logicalPaperRect.y); +} + +void wxPrintout::FitThisSizeToPage(const wxSize& imageSize) +{ + // Set the DC scale and origin so that the given image size fits within the + // printable area of the page and the origin is at the top left corner of + // the printable area. + if (!m_printoutDC) return; + int w, h; + m_printoutDC->GetSize(&w, &h); + float scaleX = float(w) / imageSize.x; + float scaleY = float(h) / imageSize.y; + float actualScale = wxMin(scaleX, scaleY); + m_printoutDC->SetUserScale(actualScale, actualScale); + m_printoutDC->SetDeviceOrigin(0, 0); +} + +void wxPrintout::FitThisSizeToPageMargins(const wxSize& imageSize, const wxPageSetupDialogData& pageSetupData) +{ + // Set the DC scale and origin so that the given image size fits within the + // page margins defined in the given wxPageSetupDialogData object and the + // origin is at the top left corner of the page margins. + if (!m_printoutDC) return; + wxRect paperRect = GetPaperRectPixels(); + wxCoord pw, ph; + GetPageSizePixels(&pw, &ph); + wxPoint topLeft = pageSetupData.GetMarginTopLeft(); + wxPoint bottomRight = pageSetupData.GetMarginBottomRight(); + wxCoord mw, mh; + GetPageSizeMM(&mw, &mh); + float mmToDeviceX = float(pw) / mw; + float mmToDeviceY = float(ph) / mh; + wxRect pageMarginsRect(paperRect.x + wxRound(mmToDeviceX * topLeft.x), + paperRect.y + wxRound(mmToDeviceY * topLeft.y), + paperRect.width - wxRound(mmToDeviceX * (topLeft.x + bottomRight.x)), + paperRect.height - wxRound(mmToDeviceY * (topLeft.y + bottomRight.y))); + wxCoord w, h; + m_printoutDC->GetSize(&w, &h); + float scaleX = (float(pageMarginsRect.width) * w) / (float(pw) * imageSize.x); + float scaleY = (float(pageMarginsRect.height) * h) / (float(ph) * imageSize.y); + float actualScale = wxMin(scaleX, scaleY); + m_printoutDC->SetUserScale(actualScale, actualScale); + m_printoutDC->SetDeviceOrigin(0, 0); + wxRect logicalPageMarginsRect = GetLogicalPageMarginsRect(pageSetupData); + SetLogicalOrigin(logicalPageMarginsRect.x, logicalPageMarginsRect.y); +} + +void wxPrintout::MapScreenSizeToPaper() +{ + // Set the DC scale so that an image on the screen is the same size on the + // paper and the origin is at the top left of the paper. Note that with most + // printers, portions of the page will be cut off. Use this if you're + // managing your own page margins. + if (!m_printoutDC) return; + MapScreenSizeToPage(); + wxRect logicalPaperRect = GetLogicalPaperRect(); + SetLogicalOrigin(logicalPaperRect.x, logicalPaperRect.y); +} + +void wxPrintout::MapScreenSizeToPage() +{ + // Set the DC scale and origin so that an image on the screen is the same + // size on the paper and the origin is at the top left of the printable area. + if (!m_printoutDC) return; + int ppiScreenX, ppiScreenY; + GetPPIScreen(&ppiScreenX, &ppiScreenY); + int ppiPrinterX, ppiPrinterY; + GetPPIPrinter(&ppiPrinterX, &ppiPrinterY); + int w, h; + m_printoutDC->GetSize(&w, &h); + int pageSizePixelsX, pageSizePixelsY; + GetPageSizePixels(&pageSizePixelsX, &pageSizePixelsY); + float userScaleX = (float(ppiPrinterX) * w) / (float(ppiScreenX) * pageSizePixelsX); + float userScaleY = (float(ppiPrinterY) * h) / (float(ppiScreenY) * pageSizePixelsY); + m_printoutDC->SetUserScale(userScaleX, userScaleY); + m_printoutDC->SetDeviceOrigin(0, 0); +} + +void wxPrintout::MapScreenSizeToPageMargins(const wxPageSetupDialogData& pageSetupData) +{ + // Set the DC scale so that an image on the screen is the same size on the + // paper and the origin is at the top left of the page margins defined by + // the given wxPageSetupDialogData object. + if (!m_printoutDC) return; + MapScreenSizeToPage(); + wxRect logicalPageMarginsRect = GetLogicalPageMarginsRect(pageSetupData); + SetLogicalOrigin(logicalPageMarginsRect.x, logicalPageMarginsRect.y); +} + +void wxPrintout::MapScreenSizeToDevice() +{ + // Set the DC scale so that a screen pixel is the same size as a device + // pixel and the origin is at the top left of the printable area. + if (!m_printoutDC) return; + int w, h; + m_printoutDC->GetSize(&w, &h); + int pageSizePixelsX, pageSizePixelsY; + GetPageSizePixels(&pageSizePixelsX, &pageSizePixelsY); + float userScaleX = float(w) / pageSizePixelsX; + float userScaleY = float(h) / pageSizePixelsY; + m_printoutDC->SetUserScale(userScaleX, userScaleY); + m_printoutDC->SetDeviceOrigin(0, 0); +} + +wxRect wxPrintout::GetLogicalPaperRect() const +{ + // Return the rectangle in logical units that corresponds to the paper + // rectangle. + wxRect paperRect = GetPaperRectPixels(); + wxCoord pw, ph; + GetPageSizePixels(&pw, &ph); + wxCoord w, h; + m_printoutDC->GetSize(&w, &h); + if (w == pw && h == ph) { + // this DC matches the printed page, so no scaling + return wxRect(m_printoutDC->DeviceToLogicalX(paperRect.x), + m_printoutDC->DeviceToLogicalY(paperRect.y), + m_printoutDC->DeviceToLogicalXRel(paperRect.width), + m_printoutDC->DeviceToLogicalYRel(paperRect.height)); + } + // This DC doesn't match the printed page, so we have to scale. + float scaleX = float(w) / pw; + float scaleY = float(h) / ph; + return wxRect(m_printoutDC->DeviceToLogicalX(wxRound(paperRect.x * scaleX)), + m_printoutDC->DeviceToLogicalY(wxRound(paperRect.y * scaleY)), + m_printoutDC->DeviceToLogicalXRel(wxRound(paperRect.width * scaleX)), + m_printoutDC->DeviceToLogicalYRel(wxRound(paperRect.height * scaleY))); +} + +wxRect wxPrintout::GetLogicalPageRect() const +{ + // Return the rectangle in logical units that corresponds to the printable + // area. + int w, h; + m_printoutDC->GetSize(&w, &h); + return wxRect(m_printoutDC->DeviceToLogicalX(0), + m_printoutDC->DeviceToLogicalY(0), + m_printoutDC->DeviceToLogicalXRel(w), + m_printoutDC->DeviceToLogicalYRel(h)); +} + +wxRect wxPrintout::GetLogicalPageMarginsRect(const wxPageSetupDialogData& pageSetupData) const +{ + // Return the rectangle in logical units that corresponds to the region + // within the page margins as specified by the given wxPageSetupDialogData + // object. + wxRect paperRect = GetPaperRectPixels(); + wxCoord pw, ph; + GetPageSizePixels(&pw, &ph); + wxPoint topLeft = pageSetupData.GetMarginTopLeft(); + wxPoint bottomRight = pageSetupData.GetMarginBottomRight(); + wxCoord mw, mh; + GetPageSizeMM(&mw, &mh); + float mmToDeviceX = float(pw) / mw; + float mmToDeviceY = float(ph) / mh; + wxRect pageMarginsRect(paperRect.x + wxRound(mmToDeviceX * topLeft.x), + paperRect.y + wxRound(mmToDeviceY * topLeft.y), + paperRect.width - wxRound(mmToDeviceX * (topLeft.x + bottomRight.x)), + paperRect.height - wxRound(mmToDeviceY * (topLeft.y + bottomRight.y))); + wxCoord w, h; + m_printoutDC->GetSize(&w, &h); + if (w == pw && h == ph) { + // this DC matches the printed page, so no scaling + return wxRect(m_printoutDC->DeviceToLogicalX(pageMarginsRect.x), + m_printoutDC->DeviceToLogicalY(pageMarginsRect.y), + m_printoutDC->DeviceToLogicalXRel(pageMarginsRect.width), + m_printoutDC->DeviceToLogicalYRel(pageMarginsRect.height)); + } + // This DC doesn't match the printed page, so we have to scale. + float scaleX = float(w) / pw; + float scaleY = float(h) / ph; + return wxRect(m_printoutDC->DeviceToLogicalX(wxRound(pageMarginsRect.x * scaleX)), + m_printoutDC->DeviceToLogicalY(wxRound(pageMarginsRect.y * scaleY)), + m_printoutDC->DeviceToLogicalXRel(wxRound(pageMarginsRect.width * scaleX)), + m_printoutDC->DeviceToLogicalYRel(wxRound(pageMarginsRect.height * scaleY))); +} + +void wxPrintout::SetLogicalOrigin(wxCoord x, wxCoord y) +{ + // Set the device origin by specifying a point in logical coordinates. + m_printoutDC->SetDeviceOrigin(m_printoutDC->LogicalToDeviceX(x), + m_printoutDC->LogicalToDeviceY(y)); +} + +void wxPrintout::OffsetLogicalOrigin(wxCoord xoff, wxCoord yoff) +{ + // Offset the device origin by a specified distance in device coordinates. + wxCoord x = m_printoutDC->LogicalToDeviceX(0); + wxCoord y = m_printoutDC->LogicalToDeviceY(0); + m_printoutDC->SetDeviceOrigin(x + m_printoutDC->LogicalToDeviceXRel(xoff), + y + m_printoutDC->LogicalToDeviceYRel(yoff)); +} + + +//---------------------------------------------------------------------------- +// wxPreviewCanvas +//---------------------------------------------------------------------------- + +IMPLEMENT_CLASS(wxPreviewCanvas, wxWindow) + +BEGIN_EVENT_TABLE(wxPreviewCanvas, wxScrolledWindow) + EVT_PAINT(wxPreviewCanvas::OnPaint) + EVT_CHAR(wxPreviewCanvas::OnChar) + EVT_SYS_COLOUR_CHANGED(wxPreviewCanvas::OnSysColourChanged) +#if wxUSE_MOUSEWHEEL + EVT_MOUSEWHEEL(wxPreviewCanvas::OnMouseWheel) +#endif +END_EVENT_TABLE() + +// VZ: the current code doesn't refresh properly without +// wxFULL_REPAINT_ON_RESIZE, this must be fixed as otherwise we have +// really horrible flicker when resizing the preview frame, but without +// this style it simply doesn't work correctly at all... +wxPreviewCanvas::wxPreviewCanvas(wxPrintPreviewBase *preview, wxWindow *parent, + const wxPoint& pos, const wxSize& size, long style, const wxString& name): +wxScrolledWindow(parent, wxID_ANY, pos, size, style | wxFULL_REPAINT_ON_RESIZE, name) +{ + m_printPreview = preview; +#ifdef __WXMAC__ + // The app workspace colour is always white, but we should have + // a contrast with the page. + wxSystemColour colourIndex = wxSYS_COLOUR_3DDKSHADOW; +#elif defined(__WXGTK__) + wxSystemColour colourIndex = wxSYS_COLOUR_BTNFACE; +#else + wxSystemColour colourIndex = wxSYS_COLOUR_APPWORKSPACE; +#endif + SetBackgroundColour(wxSystemSettings::GetColour(colourIndex)); + + SetScrollbars(10, 10, 100, 100); +} + +wxPreviewCanvas::~wxPreviewCanvas() +{ +} + +void wxPreviewCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) +{ + wxPaintDC dc(this); + PrepareDC( dc ); + +/* +#ifdef __WXGTK__ + if (!GetUpdateRegion().IsEmpty()) + dc.SetClippingRegion( GetUpdateRegion() ); +#endif +*/ + + if (m_printPreview) + { + m_printPreview->PaintPage(this, dc); + } +} + +// Responds to colour changes, and passes event on to children. +void wxPreviewCanvas::OnSysColourChanged(wxSysColourChangedEvent& event) +{ +#ifdef __WXMAC__ + // The app workspace colour is always white, but we should have + // a contrast with the page. + wxSystemColour colourIndex = wxSYS_COLOUR_3DDKSHADOW; +#elif defined(__WXGTK__) + wxSystemColour colourIndex = wxSYS_COLOUR_BTNFACE; +#else + wxSystemColour colourIndex = wxSYS_COLOUR_APPWORKSPACE; +#endif + SetBackgroundColour(wxSystemSettings::GetColour(colourIndex)); + Refresh(); + + // Propagate the event to the non-top-level children + wxWindow::OnSysColourChanged(event); +} + +void wxPreviewCanvas::OnChar(wxKeyEvent &event) +{ + wxPreviewControlBar* controlBar = ((wxPreviewFrame*) GetParent())->GetControlBar(); + if (event.GetKeyCode() == WXK_ESCAPE) + { + ((wxPreviewFrame*) GetParent())->Close(true); + return; + } + else if (event.GetKeyCode() == WXK_TAB) + { + controlBar->OnGoto(); + return; + } + else if (event.GetKeyCode() == WXK_RETURN) + { + controlBar->OnPrint(); + return; + } + + if (!event.ControlDown()) + { + event.Skip(); + return; + } + + switch(event.GetKeyCode()) + { + case WXK_PAGEDOWN: + controlBar->OnNext(); break; + case WXK_PAGEUP: + controlBar->OnPrevious(); break; + case WXK_HOME: + controlBar->OnFirst(); break; + case WXK_END: + controlBar->OnLast(); break; + default: + event.Skip(); + } +} + +#if wxUSE_MOUSEWHEEL + +void wxPreviewCanvas::OnMouseWheel(wxMouseEvent& event) +{ + wxPreviewControlBar * + controlBar = wxStaticCast(GetParent(), wxPreviewFrame)->GetControlBar(); + + if ( controlBar ) + { + if ( event.ControlDown() && event.GetWheelRotation() != 0 ) + { + int currentZoom = controlBar->GetZoomControl(); + + int delta; + if ( currentZoom < 100 ) + delta = 5; + else if ( currentZoom <= 120 ) + delta = 10; + else + delta = 50; + + if ( event.GetWheelRotation() > 0 ) + delta = -delta; + + int newZoom = currentZoom + delta; + if ( newZoom < 10 ) + newZoom = 10; + if ( newZoom > 200 ) + newZoom = 200; + if ( newZoom != currentZoom ) + { + controlBar->SetZoomControl(newZoom); + m_printPreview->SetZoom(newZoom); + Refresh(); + } + return; + } + } + + event.Skip(); +} + +#endif // wxUSE_MOUSEWHEEL + +//---------------------------------------------------------------------------- +// wxPreviewControlBar +//---------------------------------------------------------------------------- + +IMPLEMENT_CLASS(wxPreviewControlBar, wxWindow) + +BEGIN_EVENT_TABLE(wxPreviewControlBar, wxPanel) + EVT_BUTTON(wxID_PREVIEW_CLOSE, wxPreviewControlBar::OnWindowClose) + EVT_BUTTON(wxID_PREVIEW_PRINT, wxPreviewControlBar::OnPrintButton) + EVT_BUTTON(wxID_PREVIEW_PREVIOUS, wxPreviewControlBar::OnPreviousButton) + EVT_BUTTON(wxID_PREVIEW_NEXT, wxPreviewControlBar::OnNextButton) + EVT_BUTTON(wxID_PREVIEW_FIRST, wxPreviewControlBar::OnFirstButton) + EVT_BUTTON(wxID_PREVIEW_LAST, wxPreviewControlBar::OnLastButton) + EVT_BUTTON(wxID_PREVIEW_GOTO, wxPreviewControlBar::OnGotoButton) + EVT_CHOICE(wxID_PREVIEW_ZOOM, wxPreviewControlBar::OnZoom) + EVT_PAINT(wxPreviewControlBar::OnPaint) +END_EVENT_TABLE() + +wxPreviewControlBar::wxPreviewControlBar(wxPrintPreviewBase *preview, long buttons, + wxWindow *parent, const wxPoint& pos, const wxSize& size, + long style, const wxString& name): +wxPanel(parent, wxID_ANY, pos, size, style, name) +{ + m_printPreview = preview; + m_closeButton = (wxButton *) NULL; + m_nextPageButton = (wxButton *) NULL; + m_previousPageButton = (wxButton *) NULL; + m_printButton = (wxButton *) NULL; + m_zoomControl = (wxChoice *) NULL; + m_buttonFlags = buttons; +} + +wxPreviewControlBar::~wxPreviewControlBar() +{ +} + +void wxPreviewControlBar::OnPaint(wxPaintEvent& WXUNUSED(event)) +{ + wxPaintDC dc(this); + + int w, h; + GetSize(&w, &h); + dc.SetPen(*wxBLACK_PEN); + dc.SetBrush(*wxTRANSPARENT_BRUSH); + dc.DrawLine( 0, h-1, w, h-1 ); +} + +void wxPreviewControlBar::OnWindowClose(wxCommandEvent& WXUNUSED(event)) +{ + wxPreviewFrame *frame = (wxPreviewFrame *)GetParent(); + frame->Close(true); +} + +void wxPreviewControlBar::OnPrint(void) +{ + wxPrintPreviewBase *preview = GetPrintPreview(); + preview->Print(true); +} + +void wxPreviewControlBar::OnNext(void) +{ + wxPrintPreviewBase *preview = GetPrintPreview(); + if (preview) + { + int currentPage = preview->GetCurrentPage(); + if ((preview->GetMaxPage() > 0) && + (currentPage < preview->GetMaxPage()) && + preview->GetPrintout()->HasPage(currentPage + 1)) + { + preview->SetCurrentPage(currentPage + 1); + } + } +} + +void wxPreviewControlBar::OnPrevious(void) +{ + wxPrintPreviewBase *preview = GetPrintPreview(); + if (preview) + { + int currentPage = preview->GetCurrentPage(); + if ((preview->GetMinPage() > 0) && + (currentPage > preview->GetMinPage()) && + preview->GetPrintout()->HasPage(currentPage - 1)) + { + preview->SetCurrentPage(currentPage - 1); + } + } +} + +void wxPreviewControlBar::OnFirst(void) +{ + wxPrintPreviewBase *preview = GetPrintPreview(); + if (preview) + { + int currentPage = preview->GetMinPage(); + if (preview->GetPrintout()->HasPage(currentPage)) + { + preview->SetCurrentPage(currentPage); + } + } +} + +void wxPreviewControlBar::OnLast(void) +{ + wxPrintPreviewBase *preview = GetPrintPreview(); + if (preview) + { + int currentPage = preview->GetMaxPage(); + if (preview->GetPrintout()->HasPage(currentPage)) + { + preview->SetCurrentPage(currentPage); + } + } +} + +void wxPreviewControlBar::OnGoto(void) +{ + wxPrintPreviewBase *preview = GetPrintPreview(); + if (preview) + { + long currentPage; + + if (preview->GetMinPage() > 0) + { + wxString strPrompt; + wxString strPage; + + strPrompt.Printf( _("Enter a page number between %d and %d:"), + preview->GetMinPage(), preview->GetMaxPage()); + strPage.Printf( wxT("%d"), preview->GetCurrentPage() ); + + strPage = + wxGetTextFromUser( strPrompt, _("Goto Page"), strPage, GetParent()); + + if ( strPage.ToLong( ¤tPage ) ) + if (preview->GetPrintout()->HasPage(currentPage)) + { + preview->SetCurrentPage(currentPage); + } + } + } +} + +void wxPreviewControlBar::OnZoom(wxCommandEvent& WXUNUSED(event)) +{ + int zoom = GetZoomControl(); + if (GetPrintPreview()) + GetPrintPreview()->SetZoom(zoom); +} + +void wxPreviewControlBar::CreateButtons() +{ + SetSize(0, 0, 400, 40); + + wxBoxSizer *item0 = new wxBoxSizer( wxHORIZONTAL ); + + m_closeButton = new wxButton( this, wxID_PREVIEW_CLOSE, _("&Close"), wxDefaultPosition, wxDefaultSize, 0 ); + item0->Add( m_closeButton, 0, wxALIGN_CENTRE|wxALL, 5 ); + + if (m_buttonFlags & wxPREVIEW_PRINT) + { + m_printButton = new wxButton( this, wxID_PREVIEW_PRINT, _("&Print..."), wxDefaultPosition, wxDefaultSize, 0 ); + item0->Add( m_printButton, 0, wxALIGN_CENTRE|wxALL, 5 ); + } + + // Exact-fit buttons are too tiny on wxUniversal + int navButtonStyle; + wxSize navButtonSize; +#ifdef __WXUNIVERSAL__ + navButtonStyle = 0; + navButtonSize = wxSize(40, m_closeButton->GetSize().y); +#else + navButtonStyle = wxBU_EXACTFIT; + navButtonSize = wxDefaultSize; +#endif + + if (m_buttonFlags & wxPREVIEW_FIRST) + { + m_firstPageButton = new wxButton( this, wxID_PREVIEW_FIRST, _("|<<"), wxDefaultPosition, navButtonSize, navButtonStyle ); + item0->Add( m_firstPageButton, 0, wxALIGN_CENTRE|wxALL, 5 ); + } + + if (m_buttonFlags & wxPREVIEW_PREVIOUS) + { + m_previousPageButton = new wxButton( this, wxID_PREVIEW_PREVIOUS, _("<<"), wxDefaultPosition, navButtonSize, navButtonStyle ); + item0->Add( m_previousPageButton, 0, wxALIGN_CENTRE|wxRIGHT|wxTOP|wxBOTTOM, 5 ); + } + + if (m_buttonFlags & wxPREVIEW_NEXT) + { + m_nextPageButton = new wxButton( this, wxID_PREVIEW_NEXT, _(">>"), wxDefaultPosition, navButtonSize, navButtonStyle ); + item0->Add( m_nextPageButton, 0, wxALIGN_CENTRE|wxRIGHT|wxTOP|wxBOTTOM, 5 ); + } + + if (m_buttonFlags & wxPREVIEW_LAST) + { + m_lastPageButton = new wxButton( this, wxID_PREVIEW_LAST, _(">>|"), wxDefaultPosition, navButtonSize, navButtonStyle ); + item0->Add( m_lastPageButton, 0, wxALIGN_CENTRE|wxRIGHT|wxTOP|wxBOTTOM, 5 ); + } + + if (m_buttonFlags & wxPREVIEW_GOTO) + { + m_gotoPageButton = new wxButton( this, wxID_PREVIEW_GOTO, _("&Goto..."), wxDefaultPosition, wxDefaultSize, 0 ); + item0->Add( m_gotoPageButton, 0, wxALIGN_CENTRE|wxALL, 5 ); + } + + if (m_buttonFlags & wxPREVIEW_ZOOM) + { + wxString choices[] = + { + wxT("10%"), wxT("15%"), wxT("20%"), wxT("25%"), wxT("30%"), wxT("35%"), wxT("40%"), wxT("45%"), wxT("50%"), wxT("55%"), + wxT("60%"), wxT("65%"), wxT("70%"), wxT("75%"), wxT("80%"), wxT("85%"), wxT("90%"), wxT("95%"), wxT("100%"), wxT("110%"), + wxT("120%"), wxT("150%"), wxT("200%") + }; + int n = WXSIZEOF(choices); + + m_zoomControl = new wxChoice( this, wxID_PREVIEW_ZOOM, wxDefaultPosition, wxSize(70,wxDefaultCoord), n, choices, 0 ); + item0->Add( m_zoomControl, 0, wxALIGN_CENTRE|wxALL, 5 ); + SetZoomControl(m_printPreview->GetZoom()); + } + + SetSizer(item0); + item0->Fit(this); +} + +void wxPreviewControlBar::SetZoomControl(int zoom) +{ + if (m_zoomControl) + { + int n, count = m_zoomControl->GetCount(); + long val; + for (n=0; nGetString(n).BeforeFirst(wxT('%')).ToLong(&val) && + (val >= long(zoom))) + { + m_zoomControl->SetSelection(n); + return; + } + } + + m_zoomControl->SetSelection(count-1); + } +} + +int wxPreviewControlBar::GetZoomControl() +{ + if (m_zoomControl && (m_zoomControl->GetStringSelection() != wxEmptyString)) + { + long val; + if (m_zoomControl->GetStringSelection().BeforeFirst(wxT('%')).ToLong(&val)) + return int(val); + } + + return 0; +} + + +/* +* Preview frame +*/ + +IMPLEMENT_CLASS(wxPreviewFrame, wxFrame) + +BEGIN_EVENT_TABLE(wxPreviewFrame, wxFrame) + EVT_CLOSE(wxPreviewFrame::OnCloseWindow) +END_EVENT_TABLE() + +wxPreviewFrame::wxPreviewFrame(wxPrintPreviewBase *preview, wxWindow *parent, const wxString& title, + const wxPoint& pos, const wxSize& size, long style, const wxString& name): +wxFrame(parent, wxID_ANY, title, pos, size, style, name) +{ + m_printPreview = preview; + m_controlBar = NULL; + m_previewCanvas = NULL; + m_windowDisabler = NULL; + + // Give the application icon +#ifdef __WXMSW__ + wxFrame* topFrame = wxDynamicCast(wxTheApp->GetTopWindow(), wxFrame); + if (topFrame) + SetIcon(topFrame->GetIcon()); +#endif +} + +wxPreviewFrame::~wxPreviewFrame() +{ +} + +void wxPreviewFrame::OnCloseWindow(wxCloseEvent& WXUNUSED(event)) +{ + if (m_windowDisabler) + delete m_windowDisabler; + + // Need to delete the printout and the print preview + wxPrintout *printout = m_printPreview->GetPrintout(); + if (printout) + { + delete printout; + m_printPreview->SetPrintout(NULL); + m_printPreview->SetCanvas(NULL); + m_printPreview->SetFrame(NULL); + } + delete m_printPreview; + + Destroy(); +} + +void wxPreviewFrame::Initialize() +{ +#if wxUSE_STATUSBAR + CreateStatusBar(); +#endif + CreateCanvas(); + CreateControlBar(); + + m_printPreview->SetCanvas(m_previewCanvas); + m_printPreview->SetFrame(this); + + wxBoxSizer *item0 = new wxBoxSizer( wxVERTICAL ); + + item0->Add( m_controlBar, 0, wxGROW|wxALIGN_CENTER_VERTICAL, 5 ); + item0->Add( m_previewCanvas, 1, wxGROW|wxALIGN_CENTER_VERTICAL, 5 ); + + SetAutoLayout( true ); + SetSizer( item0 ); + + m_windowDisabler = new wxWindowDisabler(this); + + Layout(); + + m_printPreview->AdjustScrollbars(m_previewCanvas); + m_previewCanvas->SetFocus(); + m_controlBar->SetFocus(); +} + +void wxPreviewFrame::CreateCanvas() +{ + m_previewCanvas = new wxPreviewCanvas(m_printPreview, this); +} + +void wxPreviewFrame::CreateControlBar() +{ + long buttons = wxPREVIEW_DEFAULT; + if (m_printPreview->GetPrintoutForPrinting()) + buttons |= wxPREVIEW_PRINT; + + m_controlBar = new wxPreviewControlBar(m_printPreview, buttons, this, wxPoint(0,0), wxSize(400, 40)); + m_controlBar->CreateButtons(); +} + +/* +* Print preview +*/ + +IMPLEMENT_CLASS(wxPrintPreviewBase, wxObject) + +wxPrintPreviewBase::wxPrintPreviewBase(wxPrintout *printout, + wxPrintout *printoutForPrinting, + wxPrintData *data) +{ + if (data) + m_printDialogData = (*data); + + Init(printout, printoutForPrinting); +} + +wxPrintPreviewBase::wxPrintPreviewBase(wxPrintout *printout, + wxPrintout *printoutForPrinting, + wxPrintDialogData *data) +{ + if (data) + m_printDialogData = (*data); + + Init(printout, printoutForPrinting); +} + +void wxPrintPreviewBase::Init(wxPrintout *printout, + wxPrintout *printoutForPrinting) +{ + m_isOk = true; + m_previewPrintout = printout; + if (m_previewPrintout) + m_previewPrintout->SetIsPreview(true); + + m_printPrintout = printoutForPrinting; + + m_previewCanvas = NULL; + m_previewFrame = NULL; + m_previewBitmap = NULL; + m_currentPage = 1; + m_currentZoom = 70; + m_topMargin = 40; + m_leftMargin = 40; + m_pageWidth = 0; + m_pageHeight = 0; + m_printingPrepared = false; + m_minPage = 1; + m_maxPage = 1; +} + +wxPrintPreviewBase::~wxPrintPreviewBase() +{ + if (m_previewPrintout) + delete m_previewPrintout; + if (m_previewBitmap) + delete m_previewBitmap; + if (m_printPrintout) + delete m_printPrintout; +} + +bool wxPrintPreviewBase::SetCurrentPage(int pageNum) +{ + if (m_currentPage == pageNum) + return true; + + m_currentPage = pageNum; + if (m_previewBitmap) + { + delete m_previewBitmap; + m_previewBitmap = NULL; + } + + if (m_previewCanvas) + { + AdjustScrollbars(m_previewCanvas); + + if (!RenderPage(pageNum)) + return false; + m_previewCanvas->Refresh(); + m_previewCanvas->SetFocus(); + } + return true; +} + +int wxPrintPreviewBase::GetCurrentPage() const + { return m_currentPage; } +void wxPrintPreviewBase::SetPrintout(wxPrintout *printout) + { m_previewPrintout = printout; } +wxPrintout *wxPrintPreviewBase::GetPrintout() const + { return m_previewPrintout; } +wxPrintout *wxPrintPreviewBase::GetPrintoutForPrinting() const + { return m_printPrintout; } +void wxPrintPreviewBase::SetFrame(wxFrame *frame) + { m_previewFrame = frame; } +void wxPrintPreviewBase::SetCanvas(wxPreviewCanvas *canvas) + { m_previewCanvas = canvas; } +wxFrame *wxPrintPreviewBase::GetFrame() const + { return m_previewFrame; } +wxPreviewCanvas *wxPrintPreviewBase::GetCanvas() const + { return m_previewCanvas; } + +void wxPrintPreviewBase::CalcRects(wxPreviewCanvas *canvas, wxRect& pageRect, wxRect& paperRect) +{ + // Calculate the rectangles for the printable area of the page and the + // entire paper as they appear on the canvas on-screen. + int canvasWidth, canvasHeight; + canvas->GetSize(&canvasWidth, &canvasHeight); + + float zoomScale = float(m_currentZoom) / 100; + float screenPrintableWidth = zoomScale * m_pageWidth * m_previewScaleX; + float screenPrintableHeight = zoomScale * m_pageHeight * m_previewScaleY; + + wxRect devicePaperRect = m_previewPrintout->GetPaperRectPixels(); + wxCoord devicePrintableWidth, devicePrintableHeight; + m_previewPrintout->GetPageSizePixels(&devicePrintableWidth, &devicePrintableHeight); + float scaleX = screenPrintableWidth / devicePrintableWidth; + float scaleY = screenPrintableHeight / devicePrintableHeight; + paperRect.width = wxCoord(scaleX * devicePaperRect.width); + paperRect.height = wxCoord(scaleY * devicePaperRect.height); + + paperRect.x = wxCoord((canvasWidth - paperRect.width)/ 2.0); + if (paperRect.x < m_leftMargin) + paperRect.x = m_leftMargin; + paperRect.y = wxCoord((canvasHeight - paperRect.height)/ 2.0); + if (paperRect.y < m_topMargin) + paperRect.y = m_topMargin; + + pageRect.x = paperRect.x - wxCoord(scaleX * devicePaperRect.x); + pageRect.y = paperRect.y - wxCoord(scaleY * devicePaperRect.y); + pageRect.width = wxCoord(screenPrintableWidth); + pageRect.height = wxCoord(screenPrintableHeight); +} + + +bool wxPrintPreviewBase::PaintPage(wxPreviewCanvas *canvas, wxDC& dc) +{ + DrawBlankPage(canvas, dc); + + if (!m_previewBitmap) + if (!RenderPage(m_currentPage)) + return false; + if (!m_previewBitmap) + return false; + if (!canvas) + return false; + + wxRect pageRect, paperRect; + CalcRects(canvas, pageRect, paperRect); + wxMemoryDC temp_dc; + temp_dc.SelectObject(*m_previewBitmap); + + dc.Blit(pageRect.x, pageRect.y, + m_previewBitmap->GetWidth(), m_previewBitmap->GetHeight(), &temp_dc, 0, 0); + + temp_dc.SelectObject(wxNullBitmap); + return true; +} + +// Adjusts the scrollbars for the current scale +void wxPrintPreviewBase::AdjustScrollbars(wxPreviewCanvas *canvas) +{ + if (!canvas) + return ; + + wxRect pageRect, paperRect; + CalcRects(canvas, pageRect, paperRect); + int totalWidth = paperRect.width + 2 * m_leftMargin; + int totalHeight = paperRect.height + 2 * m_topMargin; + int scrollUnitsX = totalWidth / 10; + int scrollUnitsY = totalHeight / 10; + wxSize virtualSize = canvas->GetVirtualSize(); + if (virtualSize.GetWidth() != totalWidth || virtualSize.GetHeight() != totalHeight) + canvas->SetScrollbars(10, 10, scrollUnitsX, scrollUnitsY, 0, 0, true); +} + +bool wxPrintPreviewBase::RenderPage(int pageNum) +{ + wxBusyCursor busy; + + if (!m_previewCanvas) + { + wxFAIL_MSG(_T("wxPrintPreviewBase::RenderPage: must use wxPrintPreviewBase::SetCanvas to let me know about the canvas!")); + return false; + } + + wxRect pageRect, paperRect; + CalcRects(m_previewCanvas, pageRect, paperRect); + + if (!m_previewBitmap) + { + m_previewBitmap = new wxBitmap(pageRect.width, pageRect.height); + + if (!m_previewBitmap || !m_previewBitmap->Ok()) + { + if (m_previewBitmap) { + delete m_previewBitmap; + m_previewBitmap = NULL; + } + wxMessageBox(_("Sorry, not enough memory to create a preview."), _("Print Preview Failure"), wxOK); + return false; + } + } + + wxMemoryDC memoryDC; + memoryDC.SelectObject(*m_previewBitmap); + + memoryDC.Clear(); + + m_previewPrintout->SetDC(&memoryDC); + m_previewPrintout->SetPageSizePixels(m_pageWidth, m_pageHeight); + + // Need to delay OnPreparePrinting until here, so we have enough information. + if (!m_printingPrepared) + { + m_previewPrintout->OnPreparePrinting(); + int selFrom, selTo; + m_previewPrintout->GetPageInfo(&m_minPage, &m_maxPage, &selFrom, &selTo); + m_printingPrepared = true; + } + + m_previewPrintout->OnBeginPrinting(); + + if (!m_previewPrintout->OnBeginDocument(m_printDialogData.GetFromPage(), m_printDialogData.GetToPage())) + { + wxMessageBox(_("Could not start document preview."), _("Print Preview Failure"), wxOK); + + memoryDC.SelectObject(wxNullBitmap); + + delete m_previewBitmap; + m_previewBitmap = NULL; + return false; + } + + m_previewPrintout->OnPrintPage(pageNum); + m_previewPrintout->OnEndDocument(); + m_previewPrintout->OnEndPrinting(); + + m_previewPrintout->SetDC(NULL); + + memoryDC.SelectObject(wxNullBitmap); + +#if wxUSE_STATUSBAR + wxString status; + if (m_maxPage != 0) + status = wxString::Format(_("Page %d of %d"), pageNum, m_maxPage); + else + status = wxString::Format(_("Page %d"), pageNum); + + if (m_previewFrame) + m_previewFrame->SetStatusText(status); +#endif + + return true; +} + +bool wxPrintPreviewBase::DrawBlankPage(wxPreviewCanvas *canvas, wxDC& dc) +{ + wxRect pageRect, paperRect; + + CalcRects(canvas, pageRect, paperRect); + + // Draw shadow, allowing for 1-pixel border AROUND the actual paper + wxCoord shadowOffset = 4; + + dc.SetPen(*wxBLACK_PEN); + dc.SetBrush(*wxBLACK_BRUSH); + dc.DrawRectangle(paperRect.x + shadowOffset, paperRect.y + paperRect.height + 1, + paperRect.width, shadowOffset); + + dc.DrawRectangle(paperRect.x + paperRect.width, paperRect.y + shadowOffset, + shadowOffset, paperRect.height); + + // Draw blank page allowing for 1-pixel border AROUND the actual paper + dc.SetPen(*wxBLACK_PEN); + dc.SetBrush(*wxWHITE_BRUSH); + dc.DrawRectangle(paperRect.x - 2, paperRect.y - 1, + paperRect.width + 3, paperRect.height + 2); + + return true; +} + +void wxPrintPreviewBase::SetZoom(int percent) +{ + if (m_currentZoom == percent) + return; + + m_currentZoom = percent; + if (m_previewBitmap) + { + delete m_previewBitmap; + m_previewBitmap = NULL; + } + + if (m_previewCanvas) + { + AdjustScrollbars(m_previewCanvas); + RenderPage(m_currentPage); + ((wxScrolledWindow *) m_previewCanvas)->Scroll(0, 0); + m_previewCanvas->ClearBackground(); + m_previewCanvas->Refresh(); + m_previewCanvas->SetFocus(); + } +} + +wxPrintDialogData& wxPrintPreviewBase::GetPrintDialogData() +{ + return m_printDialogData; +} + +int wxPrintPreviewBase::GetZoom() const +{ return m_currentZoom; } +int wxPrintPreviewBase::GetMaxPage() const +{ return m_maxPage; } +int wxPrintPreviewBase::GetMinPage() const +{ return m_minPage; } +bool wxPrintPreviewBase::IsOk() const +{ return m_isOk; } +void wxPrintPreviewBase::SetOk(bool ok) +{ m_isOk = ok; } + +//---------------------------------------------------------------------------- +// wxPrintPreview +//---------------------------------------------------------------------------- + +IMPLEMENT_CLASS(wxPrintPreview, wxPrintPreviewBase) + +wxPrintPreview::wxPrintPreview(wxPrintout *printout, + wxPrintout *printoutForPrinting, + wxPrintDialogData *data) : + wxPrintPreviewBase( printout, printoutForPrinting, data ) +{ + m_pimpl = wxPrintFactory::GetFactory()-> + CreatePrintPreview( printout, printoutForPrinting, data ); +} + +wxPrintPreview::wxPrintPreview(wxPrintout *printout, + wxPrintout *printoutForPrinting, + wxPrintData *data ) : + wxPrintPreviewBase( printout, printoutForPrinting, data ) +{ + m_pimpl = wxPrintFactory::GetFactory()-> + CreatePrintPreview( printout, printoutForPrinting, data ); +} + +wxPrintPreview::~wxPrintPreview() +{ + delete m_pimpl; + + // don't delete twice + m_printPrintout = NULL; + m_previewPrintout = NULL; + m_previewBitmap = NULL; +} + +bool wxPrintPreview::SetCurrentPage(int pageNum) +{ + return m_pimpl->SetCurrentPage( pageNum ); +} + +int wxPrintPreview::GetCurrentPage() const +{ + return m_pimpl->GetCurrentPage(); +} + +void wxPrintPreview::SetPrintout(wxPrintout *printout) +{ + m_pimpl->SetPrintout( printout ); +} + +wxPrintout *wxPrintPreview::GetPrintout() const +{ + return m_pimpl->GetPrintout(); +} + +wxPrintout *wxPrintPreview::GetPrintoutForPrinting() const +{ + return m_pimpl->GetPrintoutForPrinting(); +} + +void wxPrintPreview::SetFrame(wxFrame *frame) +{ + m_pimpl->SetFrame( frame ); +} + +void wxPrintPreview::SetCanvas(wxPreviewCanvas *canvas) +{ + m_pimpl->SetCanvas( canvas ); +} + +wxFrame *wxPrintPreview::GetFrame() const +{ + return m_pimpl->GetFrame(); +} + +wxPreviewCanvas *wxPrintPreview::GetCanvas() const +{ + return m_pimpl->GetCanvas(); +} + +bool wxPrintPreview::PaintPage(wxPreviewCanvas *canvas, wxDC& dc) +{ + return m_pimpl->PaintPage( canvas, dc ); +} + +bool wxPrintPreview::DrawBlankPage(wxPreviewCanvas *canvas, wxDC& dc) +{ + return m_pimpl->DrawBlankPage( canvas, dc ); +} + +void wxPrintPreview::AdjustScrollbars(wxPreviewCanvas *canvas) +{ + m_pimpl->AdjustScrollbars( canvas ); +} + +bool wxPrintPreview::RenderPage(int pageNum) +{ + return m_pimpl->RenderPage( pageNum ); +} + +void wxPrintPreview::SetZoom(int percent) +{ + m_pimpl->SetZoom( percent ); +} + +int wxPrintPreview::GetZoom() const +{ + return m_pimpl->GetZoom(); +} + +wxPrintDialogData& wxPrintPreview::GetPrintDialogData() +{ + return m_pimpl->GetPrintDialogData(); +} + +int wxPrintPreview::GetMaxPage() const +{ + return m_pimpl->GetMaxPage(); +} + +int wxPrintPreview::GetMinPage() const +{ + return m_pimpl->GetMinPage(); +} + +bool wxPrintPreview::IsOk() const +{ + return m_pimpl->Ok(); +} + +void wxPrintPreview::SetOk(bool ok) +{ + m_pimpl->SetOk( ok ); +} + +bool wxPrintPreview::Print(bool interactive) +{ + return m_pimpl->Print( interactive ); +} + +void wxPrintPreview::DetermineScaling() +{ + m_pimpl->DetermineScaling(); +} + +#endif // wxUSE_PRINTING_ARCHITECTURE diff --git a/Externals/wxWidgets/src/common/process.cpp b/Externals/wxWidgets/src/common/process.cpp index 3c0ae358c7..9e8681ad29 100644 --- a/Externals/wxWidgets/src/common/process.cpp +++ b/Externals/wxWidgets/src/common/process.cpp @@ -1,172 +1,172 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: process.cpp -// Purpose: Process termination classes -// Author: Guilhem Lavaux -// Modified by: Vadim Zeitlin to check error codes, added Detach() method -// Created: 24/06/98 -// RCS-ID: $Id: process.cpp 42702 2006-10-30 09:03:18Z JS $ -// Copyright: (c) Guilhem Lavaux -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#include "wx/process.h" - -// ---------------------------------------------------------------------------- -// event tables and such -// ---------------------------------------------------------------------------- - -DEFINE_EVENT_TYPE(wxEVT_END_PROCESS) - -IMPLEMENT_DYNAMIC_CLASS(wxProcess, wxEvtHandler) -IMPLEMENT_DYNAMIC_CLASS(wxProcessEvent, wxEvent) - -// ============================================================================ -// wxProcess implementation -// ============================================================================ - -// ---------------------------------------------------------------------------- -// wxProcess creation -// ---------------------------------------------------------------------------- - -void wxProcess::Init(wxEvtHandler *parent, int id, int flags) -{ - if ( parent ) - SetNextHandler(parent); - - m_id = id; - m_pid = 0; - m_redirect = (flags & wxPROCESS_REDIRECT) != 0; - -#if wxUSE_STREAMS - m_inputStream = NULL; - m_errorStream = NULL; - m_outputStream = NULL; -#endif // wxUSE_STREAMS -} - -/* static */ -wxProcess *wxProcess::Open(const wxString& cmd, int flags) -{ - wxASSERT_MSG( !(flags & wxEXEC_SYNC), wxT("wxEXEC_SYNC should not be used." )); - wxProcess *process = new wxProcess(wxPROCESS_REDIRECT); - long pid = wxExecute(cmd, flags, process); - if( !pid ) - { - // couldn't launch the process - delete process; - return NULL; - } - - process->SetPid(pid); - - return process; -} - -// ---------------------------------------------------------------------------- -// wxProcess termination -// ---------------------------------------------------------------------------- - -wxProcess::~wxProcess() -{ -#if wxUSE_STREAMS - delete m_inputStream; - delete m_errorStream; - delete m_outputStream; -#endif // wxUSE_STREAMS -} - -void wxProcess::OnTerminate(int pid, int status) -{ - wxProcessEvent event(m_id, pid, status); - - if ( !ProcessEvent(event) ) - delete this; - //else: the object which processed the event is responsible for deleting - // us! -} - -void wxProcess::Detach() -{ - SetNextHandler(NULL); -} - -// ---------------------------------------------------------------------------- -// process IO redirection -// ---------------------------------------------------------------------------- - -#if wxUSE_STREAMS - -void wxProcess::SetPipeStreams(wxInputStream *inputSstream, - wxOutputStream *outputStream, - wxInputStream *errorStream) -{ - m_inputStream = inputSstream; - m_errorStream = errorStream; - m_outputStream = outputStream; -} - -bool wxProcess::IsInputOpened() const -{ - return m_inputStream && m_inputStream->GetLastError() != wxSTREAM_EOF; -} - -bool wxProcess::IsInputAvailable() const -{ - return m_inputStream && m_inputStream->CanRead(); -} - -bool wxProcess::IsErrorAvailable() const -{ - return m_errorStream && m_errorStream->CanRead(); -} - -#endif // wxUSE_STREAMS - -// ---------------------------------------------------------------------------- -// process killing -// ---------------------------------------------------------------------------- - -/* static */ -wxKillError wxProcess::Kill(int pid, wxSignal sig, int flags) -{ - wxKillError rc; - (void)wxKill(pid, sig, &rc, flags); - - return rc; -} - -/* static */ -bool wxProcess::Exists(int pid) -{ - switch ( Kill(pid, wxSIGNONE) ) - { - case wxKILL_OK: - case wxKILL_ACCESS_DENIED: - return true; - - default: - case wxKILL_ERROR: - case wxKILL_BAD_SIGNAL: - wxFAIL_MSG( _T("unexpected wxProcess::Kill() return code") ); - // fall through - - case wxKILL_NO_PROCESS: - return false; - } -} - +///////////////////////////////////////////////////////////////////////////// +// Name: process.cpp +// Purpose: Process termination classes +// Author: Guilhem Lavaux +// Modified by: Vadim Zeitlin to check error codes, added Detach() method +// Created: 24/06/98 +// RCS-ID: $Id: process.cpp 42702 2006-10-30 09:03:18Z JS $ +// Copyright: (c) Guilhem Lavaux +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#include "wx/process.h" + +// ---------------------------------------------------------------------------- +// event tables and such +// ---------------------------------------------------------------------------- + +DEFINE_EVENT_TYPE(wxEVT_END_PROCESS) + +IMPLEMENT_DYNAMIC_CLASS(wxProcess, wxEvtHandler) +IMPLEMENT_DYNAMIC_CLASS(wxProcessEvent, wxEvent) + +// ============================================================================ +// wxProcess implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// wxProcess creation +// ---------------------------------------------------------------------------- + +void wxProcess::Init(wxEvtHandler *parent, int id, int flags) +{ + if ( parent ) + SetNextHandler(parent); + + m_id = id; + m_pid = 0; + m_redirect = (flags & wxPROCESS_REDIRECT) != 0; + +#if wxUSE_STREAMS + m_inputStream = NULL; + m_errorStream = NULL; + m_outputStream = NULL; +#endif // wxUSE_STREAMS +} + +/* static */ +wxProcess *wxProcess::Open(const wxString& cmd, int flags) +{ + wxASSERT_MSG( !(flags & wxEXEC_SYNC), wxT("wxEXEC_SYNC should not be used." )); + wxProcess *process = new wxProcess(wxPROCESS_REDIRECT); + long pid = wxExecute(cmd, flags, process); + if( !pid ) + { + // couldn't launch the process + delete process; + return NULL; + } + + process->SetPid(pid); + + return process; +} + +// ---------------------------------------------------------------------------- +// wxProcess termination +// ---------------------------------------------------------------------------- + +wxProcess::~wxProcess() +{ +#if wxUSE_STREAMS + delete m_inputStream; + delete m_errorStream; + delete m_outputStream; +#endif // wxUSE_STREAMS +} + +void wxProcess::OnTerminate(int pid, int status) +{ + wxProcessEvent event(m_id, pid, status); + + if ( !ProcessEvent(event) ) + delete this; + //else: the object which processed the event is responsible for deleting + // us! +} + +void wxProcess::Detach() +{ + SetNextHandler(NULL); +} + +// ---------------------------------------------------------------------------- +// process IO redirection +// ---------------------------------------------------------------------------- + +#if wxUSE_STREAMS + +void wxProcess::SetPipeStreams(wxInputStream *inputSstream, + wxOutputStream *outputStream, + wxInputStream *errorStream) +{ + m_inputStream = inputSstream; + m_errorStream = errorStream; + m_outputStream = outputStream; +} + +bool wxProcess::IsInputOpened() const +{ + return m_inputStream && m_inputStream->GetLastError() != wxSTREAM_EOF; +} + +bool wxProcess::IsInputAvailable() const +{ + return m_inputStream && m_inputStream->CanRead(); +} + +bool wxProcess::IsErrorAvailable() const +{ + return m_errorStream && m_errorStream->CanRead(); +} + +#endif // wxUSE_STREAMS + +// ---------------------------------------------------------------------------- +// process killing +// ---------------------------------------------------------------------------- + +/* static */ +wxKillError wxProcess::Kill(int pid, wxSignal sig, int flags) +{ + wxKillError rc; + (void)wxKill(pid, sig, &rc, flags); + + return rc; +} + +/* static */ +bool wxProcess::Exists(int pid) +{ + switch ( Kill(pid, wxSIGNONE) ) + { + case wxKILL_OK: + case wxKILL_ACCESS_DENIED: + return true; + + default: + case wxKILL_ERROR: + case wxKILL_BAD_SIGNAL: + wxFAIL_MSG( _T("unexpected wxProcess::Kill() return code") ); + // fall through + + case wxKILL_NO_PROCESS: + return false; + } +} + diff --git a/Externals/wxWidgets/src/common/protocol.cpp b/Externals/wxWidgets/src/common/protocol.cpp index 1bbf85e0b2..2e2d84fe02 100644 --- a/Externals/wxWidgets/src/common/protocol.cpp +++ b/Externals/wxWidgets/src/common/protocol.cpp @@ -1,215 +1,215 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/protocol.cpp -// Purpose: Implement protocol base class -// Author: Guilhem Lavaux -// Modified by: -// Created: 07/07/1997 -// RCS-ID: $Id: protocol.cpp 40943 2006-08-31 19:31:43Z ABX $ -// Copyright: (c) 1997, 1998 Guilhem Lavaux -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_PROTOCOL - -#include "wx/protocol/protocol.h" - -#ifndef WX_PRECOMP - #include "wx/module.h" -#endif - -#include "wx/url.h" - -#include - -///////////////////////////////////////////////////////////////// -// wxProtoInfo -///////////////////////////////////////////////////////////////// - -/* - * -------------------------------------------------------------- - * --------- wxProtoInfo CONSTRUCTOR ---------------------------- - * -------------------------------------------------------------- - */ - -wxProtoInfo::wxProtoInfo(const wxChar *name, const wxChar *serv, - const bool need_host1, wxClassInfo *info) - : m_protoname(name), - m_servname(serv) -{ - m_cinfo = info; - m_needhost = need_host1; -#if wxUSE_URL - next = wxURL::ms_protocols; - wxURL::ms_protocols = this; -#else - next = NULL; -#endif -} - -///////////////////////////////////////////////////////////////// -// wxProtocol /////////////////////////////////////////////////// -///////////////////////////////////////////////////////////////// - -#if wxUSE_SOCKETS -IMPLEMENT_ABSTRACT_CLASS(wxProtocol, wxSocketClient) -#else -IMPLEMENT_ABSTRACT_CLASS(wxProtocol, wxObject) -#endif - -wxProtocol::wxProtocol() -#if wxUSE_SOCKETS - : wxSocketClient() -#endif -{ -} - -#if wxUSE_SOCKETS -bool wxProtocol::Reconnect() -{ - wxIPV4address addr; - - if (!GetPeer(addr)) - { - Close(); - return false; - } - - if (!Close()) - return false; - - if (!Connect(addr)) - return false; - - return true; -} - -// ---------------------------------------------------------------------------- -// Read a line from socket -// ---------------------------------------------------------------------------- - -/* static */ -wxProtocolError wxProtocol::ReadLine(wxSocketBase *sock, wxString& result) -{ - static const int LINE_BUF = 4095; - - result.clear(); - - wxCharBuffer buf(LINE_BUF); - char *pBuf = buf.data(); - while ( sock->WaitForRead() ) - { - // peek at the socket to see if there is a CRLF - sock->Peek(pBuf, LINE_BUF); - - size_t nRead = sock->LastCount(); - if ( !nRead && sock->Error() ) - return wxPROTO_NETERR; - - // look for "\r\n" paying attention to a special case: "\r\n" could - // have been split by buffer boundary, so check also for \r at the end - // of the last chunk and \n at the beginning of this one - pBuf[nRead] = '\0'; - const char *eol = strchr(pBuf, '\n'); - - // if we found '\n', is there a '\r' as well? - if ( eol ) - { - if ( eol == pBuf ) - { - // check for case of "\r\n" being split - if ( result.empty() || result.Last() != _T('\r') ) - { - // ignore the stray '\n' - eol = NULL; - } - //else: ok, got real EOL - - // read just this '\n' and restart - nRead = 1; - } - else // '\n' in the middle of the buffer - { - // in any case, read everything up to and including '\n' - nRead = eol - pBuf + 1; - - if ( eol[-1] != '\r' ) - { - // as above, simply ignore stray '\n' - eol = NULL; - } - } - } - - sock->Read(pBuf, nRead); - if ( sock->LastCount() != nRead ) - return wxPROTO_NETERR; - - pBuf[nRead] = '\0'; - result += wxString::FromAscii(pBuf); - - if ( eol ) - { - // remove trailing "\r\n" - result.RemoveLast(2); - - return wxPROTO_NOERR; - } - } - - return wxPROTO_NETERR; -} - -wxProtocolError wxProtocol::ReadLine(wxString& result) -{ - return ReadLine(this, result); -} - -// old function which only chops '\n' and not '\r\n' -wxProtocolError GetLine(wxSocketBase *sock, wxString& result) -{ -#define PROTO_BSIZE 2048 - size_t avail, size; - char tmp_buf[PROTO_BSIZE], tmp_str[PROTO_BSIZE]; - char *ret; - bool found; - - avail = sock->Read(tmp_buf, PROTO_BSIZE).LastCount(); - if (sock->Error() || avail == 0) - return wxPROTO_NETERR; - - memcpy(tmp_str, tmp_buf, avail); - - // Not implemented on all systems - // ret = (char *)memccpy(tmp_str, tmp_buf, '\n', avail); - found = false; - for (ret=tmp_str;ret < (tmp_str+avail); ret++) - if (*ret == '\n') - { - found = true; - break; - } - - if (!found) - return wxPROTO_PROTERR; - - *ret = 0; - - result = wxString::FromAscii( tmp_str ); - result = result.Left(result.length()-1); - - size = ret-tmp_str+1; - sock->Unread(&tmp_buf[size], avail-size); - - return wxPROTO_NOERR; -#undef PROTO_BSIZE -} -#endif // wxUSE_SOCKETS - -#endif // wxUSE_PROTOCOL +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/protocol.cpp +// Purpose: Implement protocol base class +// Author: Guilhem Lavaux +// Modified by: +// Created: 07/07/1997 +// RCS-ID: $Id: protocol.cpp 40943 2006-08-31 19:31:43Z ABX $ +// Copyright: (c) 1997, 1998 Guilhem Lavaux +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_PROTOCOL + +#include "wx/protocol/protocol.h" + +#ifndef WX_PRECOMP + #include "wx/module.h" +#endif + +#include "wx/url.h" + +#include + +///////////////////////////////////////////////////////////////// +// wxProtoInfo +///////////////////////////////////////////////////////////////// + +/* + * -------------------------------------------------------------- + * --------- wxProtoInfo CONSTRUCTOR ---------------------------- + * -------------------------------------------------------------- + */ + +wxProtoInfo::wxProtoInfo(const wxChar *name, const wxChar *serv, + const bool need_host1, wxClassInfo *info) + : m_protoname(name), + m_servname(serv) +{ + m_cinfo = info; + m_needhost = need_host1; +#if wxUSE_URL + next = wxURL::ms_protocols; + wxURL::ms_protocols = this; +#else + next = NULL; +#endif +} + +///////////////////////////////////////////////////////////////// +// wxProtocol /////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////// + +#if wxUSE_SOCKETS +IMPLEMENT_ABSTRACT_CLASS(wxProtocol, wxSocketClient) +#else +IMPLEMENT_ABSTRACT_CLASS(wxProtocol, wxObject) +#endif + +wxProtocol::wxProtocol() +#if wxUSE_SOCKETS + : wxSocketClient() +#endif +{ +} + +#if wxUSE_SOCKETS +bool wxProtocol::Reconnect() +{ + wxIPV4address addr; + + if (!GetPeer(addr)) + { + Close(); + return false; + } + + if (!Close()) + return false; + + if (!Connect(addr)) + return false; + + return true; +} + +// ---------------------------------------------------------------------------- +// Read a line from socket +// ---------------------------------------------------------------------------- + +/* static */ +wxProtocolError wxProtocol::ReadLine(wxSocketBase *sock, wxString& result) +{ + static const int LINE_BUF = 4095; + + result.clear(); + + wxCharBuffer buf(LINE_BUF); + char *pBuf = buf.data(); + while ( sock->WaitForRead() ) + { + // peek at the socket to see if there is a CRLF + sock->Peek(pBuf, LINE_BUF); + + size_t nRead = sock->LastCount(); + if ( !nRead && sock->Error() ) + return wxPROTO_NETERR; + + // look for "\r\n" paying attention to a special case: "\r\n" could + // have been split by buffer boundary, so check also for \r at the end + // of the last chunk and \n at the beginning of this one + pBuf[nRead] = '\0'; + const char *eol = strchr(pBuf, '\n'); + + // if we found '\n', is there a '\r' as well? + if ( eol ) + { + if ( eol == pBuf ) + { + // check for case of "\r\n" being split + if ( result.empty() || result.Last() != _T('\r') ) + { + // ignore the stray '\n' + eol = NULL; + } + //else: ok, got real EOL + + // read just this '\n' and restart + nRead = 1; + } + else // '\n' in the middle of the buffer + { + // in any case, read everything up to and including '\n' + nRead = eol - pBuf + 1; + + if ( eol[-1] != '\r' ) + { + // as above, simply ignore stray '\n' + eol = NULL; + } + } + } + + sock->Read(pBuf, nRead); + if ( sock->LastCount() != nRead ) + return wxPROTO_NETERR; + + pBuf[nRead] = '\0'; + result += wxString::FromAscii(pBuf); + + if ( eol ) + { + // remove trailing "\r\n" + result.RemoveLast(2); + + return wxPROTO_NOERR; + } + } + + return wxPROTO_NETERR; +} + +wxProtocolError wxProtocol::ReadLine(wxString& result) +{ + return ReadLine(this, result); +} + +// old function which only chops '\n' and not '\r\n' +wxProtocolError GetLine(wxSocketBase *sock, wxString& result) +{ +#define PROTO_BSIZE 2048 + size_t avail, size; + char tmp_buf[PROTO_BSIZE], tmp_str[PROTO_BSIZE]; + char *ret; + bool found; + + avail = sock->Read(tmp_buf, PROTO_BSIZE).LastCount(); + if (sock->Error() || avail == 0) + return wxPROTO_NETERR; + + memcpy(tmp_str, tmp_buf, avail); + + // Not implemented on all systems + // ret = (char *)memccpy(tmp_str, tmp_buf, '\n', avail); + found = false; + for (ret=tmp_str;ret < (tmp_str+avail); ret++) + if (*ret == '\n') + { + found = true; + break; + } + + if (!found) + return wxPROTO_PROTERR; + + *ret = 0; + + result = wxString::FromAscii( tmp_str ); + result = result.Left(result.length()-1); + + size = ret-tmp_str+1; + sock->Unread(&tmp_buf[size], avail-size); + + return wxPROTO_NOERR; +#undef PROTO_BSIZE +} +#endif // wxUSE_SOCKETS + +#endif // wxUSE_PROTOCOL diff --git a/Externals/wxWidgets/src/common/quantize.cpp b/Externals/wxWidgets/src/common/quantize.cpp index 85d0f1fc1b..7ffa7b19a5 100644 --- a/Externals/wxWidgets/src/common/quantize.cpp +++ b/Externals/wxWidgets/src/common/quantize.cpp @@ -1,1654 +1,1654 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/quantize.cpp -// Purpose: wxQuantize implementation -// Author: Julian Smart -// Modified by: -// Created: 22/6/2000 -// RCS-ID: $Id: quantize.cpp 39957 2006-07-03 19:02:54Z ABX $ -// Copyright: (c) Thomas G. Lane, Vaclav Slavik, Julian Smart -// Licence: wxWindows licence + JPEG library licence -///////////////////////////////////////////////////////////////////////////// - -/* - * jquant2.c - * - * Copyright (C) 1991-1996, Thomas G. Lane. - * This file is part of the Independent JPEG Group's software. - * For conditions of distribution and use, see the accompanying README file. - * - * This file contains 2-pass color quantization (color mapping) routines. - * These routines provide selection of a custom color map for an image, - * followed by mapping of the image to that color map, with optional - * Floyd-Steinberg dithering. - * It is also possible to use just the second pass to map to an arbitrary - * externally-given color map. - * - * Note: ordered dithering is not supported, since there isn't any fast - * way to compute intercolor distances; it's unclear that ordered dither's - * fundamental assumptions even hold with an irregularly spaced color map. - */ - -/* modified by Vaclav Slavik for use as jpeglib-independent module */ - -// For compilers that support precompilation, includes "wx/wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ -#pragma hdrstop -#endif - -#if wxUSE_IMAGE - -#include "wx/quantize.h" - -#ifndef WX_PRECOMP - #include "wx/palette.h" - #include "wx/image.h" -#endif - -#ifdef __WXMSW__ - #include "wx/msw/private.h" -#endif - -#include -#include - -#if defined(__OS2__) -#define RGB_RED_OS2 0 -#define RGB_GREEN_OS2 1 -#define RGB_BLUE_OS2 2 -#else -#define RGB_RED 0 -#define RGB_GREEN 1 -#define RGB_BLUE 2 -#endif -#define RGB_PIXELSIZE 3 - -#define MAXJSAMPLE 255 -#define CENTERJSAMPLE 128 -#define BITS_IN_JSAMPLE 8 -#define GETJSAMPLE(value) ((int) (value)) - -#define RIGHT_SHIFT(x,shft) ((x) >> (shft)) - -typedef unsigned short UINT16; -typedef signed short INT16; -#if !(defined(__WATCOMC__) && (defined(__WXMSW__) || defined(__WXMOTIF__))) -typedef signed int INT32; -#endif - -typedef unsigned char JSAMPLE; -typedef JSAMPLE *JSAMPROW; -typedef JSAMPROW *JSAMPARRAY; -typedef unsigned int JDIMENSION; - -typedef struct { - void *cquantize; - JDIMENSION output_width; - JSAMPARRAY colormap; - int actual_number_of_colors; - int desired_number_of_colors; - JSAMPLE *sample_range_limit, *srl_orig; -} j_decompress; - -#if defined(__WINDOWS__) && !defined(__WXMICROWIN__) - #define JMETHOD(type,methodname,arglist) type (__cdecl methodname) arglist -#else - #define JMETHOD(type,methodname,arglist) type (methodname) arglist -#endif - -typedef j_decompress *j_decompress_ptr; -struct jpeg_color_quantizer { - JMETHOD(void, start_pass, (j_decompress_ptr cinfo, bool is_pre_scan)); - JMETHOD(void, color_quantize, (j_decompress_ptr cinfo, - JSAMPARRAY input_buf, JSAMPARRAY output_buf, - int num_rows)); - JMETHOD(void, finish_pass, (j_decompress_ptr cinfo)); - JMETHOD(void, new_color_map, (j_decompress_ptr cinfo)); -}; - - - - -/* - * This module implements the well-known Heckbert paradigm for color - * quantization. Most of the ideas used here can be traced back to - * Heckbert's seminal paper - * Heckbert, Paul. "Color Image Quantization for Frame Buffer Display", - * Proc. SIGGRAPH '82, Computer Graphics v.16 #3 (July 1982), pp 297-304. - * - * In the first pass over the image, we accumulate a histogram showing the - * usage count of each possible color. To keep the histogram to a reasonable - * size, we reduce the precision of the input; typical practice is to retain - * 5 or 6 bits per color, so that 8 or 4 different input values are counted - * in the same histogram cell. - * - * Next, the color-selection step begins with a box representing the whole - * color space, and repeatedly splits the "largest" remaining box until we - * have as many boxes as desired colors. Then the mean color in each - * remaining box becomes one of the possible output colors. - * - * The second pass over the image maps each input pixel to the closest output - * color (optionally after applying a Floyd-Steinberg dithering correction). - * This mapping is logically trivial, but making it go fast enough requires - * considerable care. - * - * Heckbert-style quantizers vary a good deal in their policies for choosing - * the "largest" box and deciding where to cut it. The particular policies - * used here have proved out well in experimental comparisons, but better ones - * may yet be found. - * - * In earlier versions of the IJG code, this module quantized in YCbCr color - * space, processing the raw upsampled data without a color conversion step. - * This allowed the color conversion math to be done only once per colormap - * entry, not once per pixel. However, that optimization precluded other - * useful optimizations (such as merging color conversion with upsampling) - * and it also interfered with desired capabilities such as quantizing to an - * externally-supplied colormap. We have therefore abandoned that approach. - * The present code works in the post-conversion color space, typically RGB. - * - * To improve the visual quality of the results, we actually work in scaled - * RGB space, giving G distances more weight than R, and R in turn more than - * B. To do everything in integer math, we must use integer scale factors. - * The 2/3/1 scale factors used here correspond loosely to the relative - * weights of the colors in the NTSC grayscale equation. - * If you want to use this code to quantize a non-RGB color space, you'll - * probably need to change these scale factors. - */ - -#define R_SCALE 2 /* scale R distances by this much */ -#define G_SCALE 3 /* scale G distances by this much */ -#define B_SCALE 1 /* and B by this much */ - -/* Relabel R/G/B as components 0/1/2, respecting the RGB ordering defined - * in jmorecfg.h. As the code stands, it will do the right thing for R,G,B - * and B,G,R orders. If you define some other weird order in jmorecfg.h, - * you'll get compile errors until you extend this logic. In that case - * you'll probably want to tweak the histogram sizes too. - */ - -#if defined(__OS2__) - -#if RGB_RED_OS2 == 0 -#define C0_SCALE R_SCALE -#endif -#if RGB_BLUE_OS2 == 0 -#define C0_SCALE B_SCALE -#endif -#if RGB_GREEN_OS2 == 1 -#define C1_SCALE G_SCALE -#endif -#if RGB_RED_OS2 == 2 -#define C2_SCALE R_SCALE -#endif -#if RGB_BLUE_OS2 == 2 -#define C2_SCALE B_SCALE -#endif - -#else - -#if RGB_RED == 0 -#define C0_SCALE R_SCALE -#endif -#if RGB_BLUE == 0 -#define C0_SCALE B_SCALE -#endif -#if RGB_GREEN == 1 -#define C1_SCALE G_SCALE -#endif -#if RGB_RED == 2 -#define C2_SCALE R_SCALE -#endif -#if RGB_BLUE == 2 -#define C2_SCALE B_SCALE -#endif - -#endif - -/* - * First we have the histogram data structure and routines for creating it. - * - * The number of bits of precision can be adjusted by changing these symbols. - * We recommend keeping 6 bits for G and 5 each for R and B. - * If you have plenty of memory and cycles, 6 bits all around gives marginally - * better results; if you are short of memory, 5 bits all around will save - * some space but degrade the results. - * To maintain a fully accurate histogram, we'd need to allocate a "long" - * (preferably unsigned long) for each cell. In practice this is overkill; - * we can get by with 16 bits per cell. Few of the cell counts will overflow, - * and clamping those that do overflow to the maximum value will give close- - * enough results. This reduces the recommended histogram size from 256Kb - * to 128Kb, which is a useful savings on PC-class machines. - * (In the second pass the histogram space is re-used for pixel mapping data; - * in that capacity, each cell must be able to store zero to the number of - * desired colors. 16 bits/cell is plenty for that too.) - * Since the JPEG code is intended to run in small memory model on 80x86 - * machines, we can't just allocate the histogram in one chunk. Instead - * of a true 3-D array, we use a row of pointers to 2-D arrays. Each - * pointer corresponds to a C0 value (typically 2^5 = 32 pointers) and - * each 2-D array has 2^6*2^5 = 2048 or 2^6*2^6 = 4096 entries. Note that - * on 80x86 machines, the pointer row is in near memory but the actual - * arrays are in far memory (same arrangement as we use for image arrays). - */ - -#define MAXNUMCOLORS (MAXJSAMPLE+1) /* maximum size of colormap */ - -/* These will do the right thing for either R,G,B or B,G,R color order, - * but you may not like the results for other color orders. - */ -#define HIST_C0_BITS 5 /* bits of precision in R/B histogram */ -#define HIST_C1_BITS 6 /* bits of precision in G histogram */ -#define HIST_C2_BITS 5 /* bits of precision in B/R histogram */ - -/* Number of elements along histogram axes. */ -#define HIST_C0_ELEMS (1<cquantize; - register JSAMPROW ptr; - register histptr histp; - register hist3d histogram = cquantize->histogram; - int row; - JDIMENSION col; - JDIMENSION width = cinfo->output_width; - - for (row = 0; row < num_rows; row++) { - ptr = input_buf[row]; - for (col = width; col > 0; col--) { - - { - - /* get pixel value and index into the histogram */ - histp = & histogram[GETJSAMPLE(ptr[0]) >> C0_SHIFT] - [GETJSAMPLE(ptr[1]) >> C1_SHIFT] - [GETJSAMPLE(ptr[2]) >> C2_SHIFT]; - /* increment, check for overflow and undo increment if so. */ - if (++(*histp) <= 0) - (*histp)--; - } - ptr += 3; - } - } -} - - -/* - * Next we have the really interesting routines: selection of a colormap - * given the completed histogram. - * These routines work with a list of "boxes", each representing a rectangular - * subset of the input color space (to histogram precision). - */ - -typedef struct { - /* The bounds of the box (inclusive); expressed as histogram indexes */ - int c0min, c0max; - int c1min, c1max; - int c2min, c2max; - /* The volume (actually 2-norm) of the box */ - INT32 volume; - /* The number of nonzero histogram cells within this box */ - long colorcount; -} box; - -typedef box * boxptr; - - -boxptr -find_biggest_color_pop (boxptr boxlist, int numboxes) -/* Find the splittable box with the largest color population */ -/* Returns NULL if no splittable boxes remain */ -{ - register boxptr boxp; - register int i; - register long maxc = 0; - boxptr which = NULL; - - for (i = 0, boxp = boxlist; i < numboxes; i++, boxp++) { - if (boxp->colorcount > maxc && boxp->volume > 0) { - which = boxp; - maxc = boxp->colorcount; - } - } - return which; -} - - -boxptr -find_biggest_volume (boxptr boxlist, int numboxes) -/* Find the splittable box with the largest (scaled) volume */ -/* Returns NULL if no splittable boxes remain */ -{ - register boxptr boxp; - register int i; - register INT32 maxv = 0; - boxptr which = NULL; - - for (i = 0, boxp = boxlist; i < numboxes; i++, boxp++) { - if (boxp->volume > maxv) { - which = boxp; - maxv = boxp->volume; - } - } - return which; -} - - -void -update_box (j_decompress_ptr cinfo, boxptr boxp) -/* Shrink the min/max bounds of a box to enclose only nonzero elements, */ -/* and recompute its volume and population */ -{ - my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; - hist3d histogram = cquantize->histogram; - histptr histp; - int c0,c1,c2; - int c0min,c0max,c1min,c1max,c2min,c2max; - INT32 dist0,dist1,dist2; - long ccount; - - c0min = boxp->c0min; c0max = boxp->c0max; - c1min = boxp->c1min; c1max = boxp->c1max; - c2min = boxp->c2min; c2max = boxp->c2max; - - if (c0max > c0min) - for (c0 = c0min; c0 <= c0max; c0++) - for (c1 = c1min; c1 <= c1max; c1++) { - histp = & histogram[c0][c1][c2min]; - for (c2 = c2min; c2 <= c2max; c2++) - if (*histp++ != 0) { - boxp->c0min = c0min = c0; - goto have_c0min; - } - } - have_c0min: - if (c0max > c0min) - for (c0 = c0max; c0 >= c0min; c0--) - for (c1 = c1min; c1 <= c1max; c1++) { - histp = & histogram[c0][c1][c2min]; - for (c2 = c2min; c2 <= c2max; c2++) - if (*histp++ != 0) { - boxp->c0max = c0max = c0; - goto have_c0max; - } - } - have_c0max: - if (c1max > c1min) - for (c1 = c1min; c1 <= c1max; c1++) - for (c0 = c0min; c0 <= c0max; c0++) { - histp = & histogram[c0][c1][c2min]; - for (c2 = c2min; c2 <= c2max; c2++) - if (*histp++ != 0) { - boxp->c1min = c1min = c1; - goto have_c1min; - } - } - have_c1min: - if (c1max > c1min) - for (c1 = c1max; c1 >= c1min; c1--) - for (c0 = c0min; c0 <= c0max; c0++) { - histp = & histogram[c0][c1][c2min]; - for (c2 = c2min; c2 <= c2max; c2++) - if (*histp++ != 0) { - boxp->c1max = c1max = c1; - goto have_c1max; - } - } - have_c1max: - if (c2max > c2min) - for (c2 = c2min; c2 <= c2max; c2++) - for (c0 = c0min; c0 <= c0max; c0++) { - histp = & histogram[c0][c1min][c2]; - for (c1 = c1min; c1 <= c1max; c1++, histp += HIST_C2_ELEMS) - if (*histp != 0) { - boxp->c2min = c2min = c2; - goto have_c2min; - } - } - have_c2min: - if (c2max > c2min) - for (c2 = c2max; c2 >= c2min; c2--) - for (c0 = c0min; c0 <= c0max; c0++) { - histp = & histogram[c0][c1min][c2]; - for (c1 = c1min; c1 <= c1max; c1++, histp += HIST_C2_ELEMS) - if (*histp != 0) { - boxp->c2max = c2max = c2; - goto have_c2max; - } - } - have_c2max: - - /* Update box volume. - * We use 2-norm rather than real volume here; this biases the method - * against making long narrow boxes, and it has the side benefit that - * a box is splittable iff norm > 0. - * Since the differences are expressed in histogram-cell units, - * we have to shift back to JSAMPLE units to get consistent distances; - * after which, we scale according to the selected distance scale factors. - */ - dist0 = ((c0max - c0min) << C0_SHIFT) * C0_SCALE; - dist1 = ((c1max - c1min) << C1_SHIFT) * C1_SCALE; - dist2 = ((c2max - c2min) << C2_SHIFT) * C2_SCALE; - boxp->volume = dist0*dist0 + dist1*dist1 + dist2*dist2; - - /* Now scan remaining volume of box and compute population */ - ccount = 0; - for (c0 = c0min; c0 <= c0max; c0++) - for (c1 = c1min; c1 <= c1max; c1++) { - histp = & histogram[c0][c1][c2min]; - for (c2 = c2min; c2 <= c2max; c2++, histp++) - if (*histp != 0) { - ccount++; - } - } - boxp->colorcount = ccount; -} - - -int -median_cut (j_decompress_ptr cinfo, boxptr boxlist, int numboxes, - int desired_colors) -/* Repeatedly select and split the largest box until we have enough boxes */ -{ - int n,lb; - int c0,c1,c2,cmax; - register boxptr b1,b2; - - while (numboxes < desired_colors) { - /* Select box to split. - * Current algorithm: by population for first half, then by volume. - */ - if ((numboxes*2) <= desired_colors) { - b1 = find_biggest_color_pop(boxlist, numboxes); - } else { - b1 = find_biggest_volume(boxlist, numboxes); - } - if (b1 == NULL) /* no splittable boxes left! */ - break; - b2 = &boxlist[numboxes]; /* where new box will go */ - /* Copy the color bounds to the new box. */ - b2->c0max = b1->c0max; b2->c1max = b1->c1max; b2->c2max = b1->c2max; - b2->c0min = b1->c0min; b2->c1min = b1->c1min; b2->c2min = b1->c2min; - /* Choose which axis to split the box on. - * Current algorithm: longest scaled axis. - * See notes in update_box about scaling distances. - */ - c0 = ((b1->c0max - b1->c0min) << C0_SHIFT) * C0_SCALE; - c1 = ((b1->c1max - b1->c1min) << C1_SHIFT) * C1_SCALE; - c2 = ((b1->c2max - b1->c2min) << C2_SHIFT) * C2_SCALE; - /* We want to break any ties in favor of green, then red, blue last. - * This code does the right thing for R,G,B or B,G,R color orders only. - */ -#if defined(__VISAGECPP__) - -#if RGB_RED_OS2 == 0 - cmax = c1; n = 1; - if (c0 > cmax) { cmax = c0; n = 0; } - if (c2 > cmax) { n = 2; } -#else - cmax = c1; n = 1; - if (c2 > cmax) { cmax = c2; n = 2; } - if (c0 > cmax) { n = 0; } -#endif - -#else - -#if RGB_RED == 0 - cmax = c1; n = 1; - if (c0 > cmax) { cmax = c0; n = 0; } - if (c2 > cmax) { n = 2; } -#else - cmax = c1; n = 1; - if (c2 > cmax) { cmax = c2; n = 2; } - if (c0 > cmax) { n = 0; } -#endif - -#endif - /* Choose split point along selected axis, and update box bounds. - * Current algorithm: split at halfway point. - * (Since the box has been shrunk to minimum volume, - * any split will produce two nonempty subboxes.) - * Note that lb value is max for lower box, so must be < old max. - */ - switch (n) { - case 0: - lb = (b1->c0max + b1->c0min) / 2; - b1->c0max = lb; - b2->c0min = lb+1; - break; - case 1: - lb = (b1->c1max + b1->c1min) / 2; - b1->c1max = lb; - b2->c1min = lb+1; - break; - case 2: - lb = (b1->c2max + b1->c2min) / 2; - b1->c2max = lb; - b2->c2min = lb+1; - break; - } - /* Update stats for boxes */ - update_box(cinfo, b1); - update_box(cinfo, b2); - numboxes++; - } - return numboxes; -} - - -void -compute_color (j_decompress_ptr cinfo, boxptr boxp, int icolor) -/* Compute representative color for a box, put it in colormap[icolor] */ -{ - /* Current algorithm: mean weighted by pixels (not colors) */ - /* Note it is important to get the rounding correct! */ - my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; - hist3d histogram = cquantize->histogram; - histptr histp; - int c0,c1,c2; - int c0min,c0max,c1min,c1max,c2min,c2max; - long count; - long total = 0; - long c0total = 0; - long c1total = 0; - long c2total = 0; - - c0min = boxp->c0min; c0max = boxp->c0max; - c1min = boxp->c1min; c1max = boxp->c1max; - c2min = boxp->c2min; c2max = boxp->c2max; - - for (c0 = c0min; c0 <= c0max; c0++) - for (c1 = c1min; c1 <= c1max; c1++) { - histp = & histogram[c0][c1][c2min]; - for (c2 = c2min; c2 <= c2max; c2++) { - if ((count = *histp++) != 0) { - total += count; - c0total += ((c0 << C0_SHIFT) + ((1<>1)) * count; - c1total += ((c1 << C1_SHIFT) + ((1<>1)) * count; - c2total += ((c2 << C2_SHIFT) + ((1<>1)) * count; - } - } - } - - cinfo->colormap[0][icolor] = (JSAMPLE) ((c0total + (total>>1)) / total); - cinfo->colormap[1][icolor] = (JSAMPLE) ((c1total + (total>>1)) / total); - cinfo->colormap[2][icolor] = (JSAMPLE) ((c2total + (total>>1)) / total); -} - - -static void -select_colors (j_decompress_ptr cinfo, int desired_colors) -/* Master routine for color selection */ -{ - boxptr boxlist; - int numboxes; - int i; - - /* Allocate workspace for box list */ - boxlist = (boxptr) malloc(desired_colors * sizeof(box)); - /* Initialize one box containing whole space */ - numboxes = 1; - boxlist[0].c0min = 0; - boxlist[0].c0max = MAXJSAMPLE >> C0_SHIFT; - boxlist[0].c1min = 0; - boxlist[0].c1max = MAXJSAMPLE >> C1_SHIFT; - boxlist[0].c2min = 0; - boxlist[0].c2max = MAXJSAMPLE >> C2_SHIFT; - /* Shrink it to actually-used volume and set its statistics */ - update_box(cinfo, & boxlist[0]); - /* Perform median-cut to produce final box list */ - numboxes = median_cut(cinfo, boxlist, numboxes, desired_colors); - /* Compute the representative color for each box, fill colormap */ - for (i = 0; i < numboxes; i++) - compute_color(cinfo, & boxlist[i], i); - cinfo->actual_number_of_colors = numboxes; - - free(boxlist); //FIXME?? I don't know if this is correct - VS -} - - -/* - * These routines are concerned with the time-critical task of mapping input - * colors to the nearest color in the selected colormap. - * - * We re-use the histogram space as an "inverse color map", essentially a - * cache for the results of nearest-color searches. All colors within a - * histogram cell will be mapped to the same colormap entry, namely the one - * closest to the cell's center. This may not be quite the closest entry to - * the actual input color, but it's almost as good. A zero in the cache - * indicates we haven't found the nearest color for that cell yet; the array - * is cleared to zeroes before starting the mapping pass. When we find the - * nearest color for a cell, its colormap index plus one is recorded in the - * cache for future use. The pass2 scanning routines call fill_inverse_cmap - * when they need to use an unfilled entry in the cache. - * - * Our method of efficiently finding nearest colors is based on the "locally - * sorted search" idea described by Heckbert and on the incremental distance - * calculation described by Spencer W. Thomas in chapter III.1 of Graphics - * Gems II (James Arvo, ed. Academic Press, 1991). Thomas points out that - * the distances from a given colormap entry to each cell of the histogram can - * be computed quickly using an incremental method: the differences between - * distances to adjacent cells themselves differ by a constant. This allows a - * fairly fast implementation of the "brute force" approach of computing the - * distance from every colormap entry to every histogram cell. Unfortunately, - * it needs a work array to hold the best-distance-so-far for each histogram - * cell (because the inner loop has to be over cells, not colormap entries). - * The work array elements have to be INT32s, so the work array would need - * 256Kb at our recommended precision. This is not feasible in DOS machines. - * - * To get around these problems, we apply Thomas' method to compute the - * nearest colors for only the cells within a small subbox of the histogram. - * The work array need be only as big as the subbox, so the memory usage - * problem is solved. Furthermore, we need not fill subboxes that are never - * referenced in pass2; many images use only part of the color gamut, so a - * fair amount of work is saved. An additional advantage of this - * approach is that we can apply Heckbert's locality criterion to quickly - * eliminate colormap entries that are far away from the subbox; typically - * three-fourths of the colormap entries are rejected by Heckbert's criterion, - * and we need not compute their distances to individual cells in the subbox. - * The speed of this approach is heavily influenced by the subbox size: too - * small means too much overhead, too big loses because Heckbert's criterion - * can't eliminate as many colormap entries. Empirically the best subbox - * size seems to be about 1/512th of the histogram (1/8th in each direction). - * - * Thomas' article also describes a refined method which is asymptotically - * faster than the brute-force method, but it is also far more complex and - * cannot efficiently be applied to small subboxes. It is therefore not - * useful for programs intended to be portable to DOS machines. On machines - * with plenty of memory, filling the whole histogram in one shot with Thomas' - * refined method might be faster than the present code --- but then again, - * it might not be any faster, and it's certainly more complicated. - */ - - -/* log2(histogram cells in update box) for each axis; this can be adjusted */ -#define BOX_C0_LOG (HIST_C0_BITS-3) -#define BOX_C1_LOG (HIST_C1_BITS-3) -#define BOX_C2_LOG (HIST_C2_BITS-3) - -#define BOX_C0_ELEMS (1<actual_number_of_colors; - int maxc0, maxc1, maxc2; - int centerc0, centerc1, centerc2; - int i, x, ncolors; - INT32 minmaxdist, min_dist, max_dist, tdist; - INT32 mindist[MAXNUMCOLORS]; /* min distance to colormap entry i */ - - /* Compute true coordinates of update box's upper corner and center. - * Actually we compute the coordinates of the center of the upper-corner - * histogram cell, which are the upper bounds of the volume we care about. - * Note that since ">>" rounds down, the "center" values may be closer to - * min than to max; hence comparisons to them must be "<=", not "<". - */ - maxc0 = minc0 + ((1 << BOX_C0_SHIFT) - (1 << C0_SHIFT)); - centerc0 = (minc0 + maxc0) >> 1; - maxc1 = minc1 + ((1 << BOX_C1_SHIFT) - (1 << C1_SHIFT)); - centerc1 = (minc1 + maxc1) >> 1; - maxc2 = minc2 + ((1 << BOX_C2_SHIFT) - (1 << C2_SHIFT)); - centerc2 = (minc2 + maxc2) >> 1; - - /* For each color in colormap, find: - * 1. its minimum squared-distance to any point in the update box - * (zero if color is within update box); - * 2. its maximum squared-distance to any point in the update box. - * Both of these can be found by considering only the corners of the box. - * We save the minimum distance for each color in mindist[]; - * only the smallest maximum distance is of interest. - */ - minmaxdist = 0x7FFFFFFFL; - - for (i = 0; i < numcolors; i++) { - /* We compute the squared-c0-distance term, then add in the other two. */ - x = GETJSAMPLE(cinfo->colormap[0][i]); - if (x < minc0) { - tdist = (x - minc0) * C0_SCALE; - min_dist = tdist*tdist; - tdist = (x - maxc0) * C0_SCALE; - max_dist = tdist*tdist; - } else if (x > maxc0) { - tdist = (x - maxc0) * C0_SCALE; - min_dist = tdist*tdist; - tdist = (x - minc0) * C0_SCALE; - max_dist = tdist*tdist; - } else { - /* within cell range so no contribution to min_dist */ - min_dist = 0; - if (x <= centerc0) { - tdist = (x - maxc0) * C0_SCALE; - max_dist = tdist*tdist; - } else { - tdist = (x - minc0) * C0_SCALE; - max_dist = tdist*tdist; - } - } - - x = GETJSAMPLE(cinfo->colormap[1][i]); - if (x < minc1) { - tdist = (x - minc1) * C1_SCALE; - min_dist += tdist*tdist; - tdist = (x - maxc1) * C1_SCALE; - max_dist += tdist*tdist; - } else if (x > maxc1) { - tdist = (x - maxc1) * C1_SCALE; - min_dist += tdist*tdist; - tdist = (x - minc1) * C1_SCALE; - max_dist += tdist*tdist; - } else { - /* within cell range so no contribution to min_dist */ - if (x <= centerc1) { - tdist = (x - maxc1) * C1_SCALE; - max_dist += tdist*tdist; - } else { - tdist = (x - minc1) * C1_SCALE; - max_dist += tdist*tdist; - } - } - - x = GETJSAMPLE(cinfo->colormap[2][i]); - if (x < minc2) { - tdist = (x - minc2) * C2_SCALE; - min_dist += tdist*tdist; - tdist = (x - maxc2) * C2_SCALE; - max_dist += tdist*tdist; - } else if (x > maxc2) { - tdist = (x - maxc2) * C2_SCALE; - min_dist += tdist*tdist; - tdist = (x - minc2) * C2_SCALE; - max_dist += tdist*tdist; - } else { - /* within cell range so no contribution to min_dist */ - if (x <= centerc2) { - tdist = (x - maxc2) * C2_SCALE; - max_dist += tdist*tdist; - } else { - tdist = (x - minc2) * C2_SCALE; - max_dist += tdist*tdist; - } - } - - mindist[i] = min_dist; /* save away the results */ - if (max_dist < minmaxdist) - minmaxdist = max_dist; - } - - /* Now we know that no cell in the update box is more than minmaxdist - * away from some colormap entry. Therefore, only colors that are - * within minmaxdist of some part of the box need be considered. - */ - ncolors = 0; - for (i = 0; i < numcolors; i++) { - if (mindist[i] <= minmaxdist) - colorlist[ncolors++] = (JSAMPLE) i; - } - return ncolors; -} - - -static void -find_best_colors (j_decompress_ptr cinfo, int minc0, int minc1, int minc2, - int numcolors, JSAMPLE colorlist[], JSAMPLE bestcolor[]) -/* Find the closest colormap entry for each cell in the update box, - * given the list of candidate colors prepared by find_nearby_colors. - * Return the indexes of the closest entries in the bestcolor[] array. - * This routine uses Thomas' incremental distance calculation method to - * find the distance from a colormap entry to successive cells in the box. - */ -{ - int ic0, ic1, ic2; - int i, icolor; - register INT32 * bptr; /* pointer into bestdist[] array */ - JSAMPLE * cptr; /* pointer into bestcolor[] array */ - INT32 dist0, dist1; /* initial distance values */ - register INT32 dist2; /* current distance in inner loop */ - INT32 xx0, xx1; /* distance increments */ - register INT32 xx2; - INT32 inc0, inc1, inc2; /* initial values for increments */ - /* This array holds the distance to the nearest-so-far color for each cell */ - INT32 bestdist[BOX_C0_ELEMS * BOX_C1_ELEMS * BOX_C2_ELEMS]; - - /* Initialize best-distance for each cell of the update box */ - bptr = bestdist; - for (i = BOX_C0_ELEMS*BOX_C1_ELEMS*BOX_C2_ELEMS-1; i >= 0; i--) - *bptr++ = 0x7FFFFFFFL; - - /* For each color selected by find_nearby_colors, - * compute its distance to the center of each cell in the box. - * If that's less than best-so-far, update best distance and color number. - */ - - /* Nominal steps between cell centers ("x" in Thomas article) */ -#define STEP_C0 ((1 << C0_SHIFT) * C0_SCALE) -#define STEP_C1 ((1 << C1_SHIFT) * C1_SCALE) -#define STEP_C2 ((1 << C2_SHIFT) * C2_SCALE) - - for (i = 0; i < numcolors; i++) { - icolor = GETJSAMPLE(colorlist[i]); - /* Compute (square of) distance from minc0/c1/c2 to this color */ - inc0 = (minc0 - GETJSAMPLE(cinfo->colormap[0][icolor])) * C0_SCALE; - dist0 = inc0*inc0; - inc1 = (minc1 - GETJSAMPLE(cinfo->colormap[1][icolor])) * C1_SCALE; - dist0 += inc1*inc1; - inc2 = (minc2 - GETJSAMPLE(cinfo->colormap[2][icolor])) * C2_SCALE; - dist0 += inc2*inc2; - /* Form the initial difference increments */ - inc0 = inc0 * (2 * STEP_C0) + STEP_C0 * STEP_C0; - inc1 = inc1 * (2 * STEP_C1) + STEP_C1 * STEP_C1; - inc2 = inc2 * (2 * STEP_C2) + STEP_C2 * STEP_C2; - /* Now loop over all cells in box, updating distance per Thomas method */ - bptr = bestdist; - cptr = bestcolor; - xx0 = inc0; - for (ic0 = BOX_C0_ELEMS-1; ic0 >= 0; ic0--) { - dist1 = dist0; - xx1 = inc1; - for (ic1 = BOX_C1_ELEMS-1; ic1 >= 0; ic1--) { - dist2 = dist1; - xx2 = inc2; - for (ic2 = BOX_C2_ELEMS-1; ic2 >= 0; ic2--) { - if (dist2 < *bptr) { - *bptr = dist2; - *cptr = (JSAMPLE) icolor; - } - dist2 += xx2; - xx2 += 2 * STEP_C2 * STEP_C2; - bptr++; - cptr++; - } - dist1 += xx1; - xx1 += 2 * STEP_C1 * STEP_C1; - } - dist0 += xx0; - xx0 += 2 * STEP_C0 * STEP_C0; - } - } -} - - -static void -fill_inverse_cmap (j_decompress_ptr cinfo, int c0, int c1, int c2) -/* Fill the inverse-colormap entries in the update box that contains */ -/* histogram cell c0/c1/c2. (Only that one cell MUST be filled, but */ -/* we can fill as many others as we wish.) */ -{ - my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; - hist3d histogram = cquantize->histogram; - int minc0, minc1, minc2; /* lower left corner of update box */ - int ic0, ic1, ic2; - register JSAMPLE * cptr; /* pointer into bestcolor[] array */ - register histptr cachep; /* pointer into main cache array */ - /* This array lists the candidate colormap indexes. */ - JSAMPLE colorlist[MAXNUMCOLORS]; - int numcolors; /* number of candidate colors */ - /* This array holds the actually closest colormap index for each cell. */ - JSAMPLE bestcolor[BOX_C0_ELEMS * BOX_C1_ELEMS * BOX_C2_ELEMS]; - - /* Convert cell coordinates to update box ID */ - c0 >>= BOX_C0_LOG; - c1 >>= BOX_C1_LOG; - c2 >>= BOX_C2_LOG; - - /* Compute true coordinates of update box's origin corner. - * Actually we compute the coordinates of the center of the corner - * histogram cell, which are the lower bounds of the volume we care about. - */ - minc0 = (c0 << BOX_C0_SHIFT) + ((1 << C0_SHIFT) >> 1); - minc1 = (c1 << BOX_C1_SHIFT) + ((1 << C1_SHIFT) >> 1); - minc2 = (c2 << BOX_C2_SHIFT) + ((1 << C2_SHIFT) >> 1); - - /* Determine which colormap entries are close enough to be candidates - * for the nearest entry to some cell in the update box. - */ - numcolors = find_nearby_colors(cinfo, minc0, minc1, minc2, colorlist); - - /* Determine the actually nearest colors. */ - find_best_colors(cinfo, minc0, minc1, minc2, numcolors, colorlist, - bestcolor); - - /* Save the best color numbers (plus 1) in the main cache array */ - c0 <<= BOX_C0_LOG; /* convert ID back to base cell indexes */ - c1 <<= BOX_C1_LOG; - c2 <<= BOX_C2_LOG; - cptr = bestcolor; - for (ic0 = 0; ic0 < BOX_C0_ELEMS; ic0++) { - for (ic1 = 0; ic1 < BOX_C1_ELEMS; ic1++) { - cachep = & histogram[c0+ic0][c1+ic1][c2]; - for (ic2 = 0; ic2 < BOX_C2_ELEMS; ic2++) { - *cachep++ = (histcell) (GETJSAMPLE(*cptr++) + 1); - } - } - } -} - - -/* - * Map some rows of pixels to the output colormapped representation. - */ - -void -pass2_no_dither (j_decompress_ptr cinfo, - JSAMPARRAY input_buf, JSAMPARRAY output_buf, int num_rows) -/* This version performs no dithering */ -{ - my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; - hist3d histogram = cquantize->histogram; - register JSAMPROW inptr, outptr; - register histptr cachep; - register int c0, c1, c2; - int row; - JDIMENSION col; - JDIMENSION width = cinfo->output_width; - - for (row = 0; row < num_rows; row++) { - inptr = input_buf[row]; - outptr = output_buf[row]; - for (col = width; col > 0; col--) { - /* get pixel value and index into the cache */ - c0 = GETJSAMPLE(*inptr++) >> C0_SHIFT; - c1 = GETJSAMPLE(*inptr++) >> C1_SHIFT; - c2 = GETJSAMPLE(*inptr++) >> C2_SHIFT; - cachep = & histogram[c0][c1][c2]; - /* If we have not seen this color before, find nearest colormap entry */ - /* and update the cache */ - if (*cachep == 0) - fill_inverse_cmap(cinfo, c0,c1,c2); - /* Now emit the colormap index for this cell */ - *outptr++ = (JSAMPLE) (*cachep - 1); - } - } -} - - -void -pass2_fs_dither (j_decompress_ptr cinfo, - JSAMPARRAY input_buf, JSAMPARRAY output_buf, int num_rows) -/* This version performs Floyd-Steinberg dithering */ -{ - my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; - hist3d histogram = cquantize->histogram; - register LOCFSERROR cur0, cur1, cur2; /* current error or pixel value */ - LOCFSERROR belowerr0, belowerr1, belowerr2; /* error for pixel below cur */ - LOCFSERROR bpreverr0, bpreverr1, bpreverr2; /* error for below/prev col */ - register FSERRPTR errorptr; /* => fserrors[] at column before current */ - JSAMPROW inptr; /* => current input pixel */ - JSAMPROW outptr; /* => current output pixel */ - histptr cachep; - int dir; /* +1 or -1 depending on direction */ - int dir3; /* 3*dir, for advancing inptr & errorptr */ - int row; - JDIMENSION col; - JDIMENSION width = cinfo->output_width; - JSAMPLE *range_limit = cinfo->sample_range_limit; - int *error_limit = cquantize->error_limiter; - JSAMPROW colormap0 = cinfo->colormap[0]; - JSAMPROW colormap1 = cinfo->colormap[1]; - JSAMPROW colormap2 = cinfo->colormap[2]; - - - for (row = 0; row < num_rows; row++) { - inptr = input_buf[row]; - outptr = output_buf[row]; - if (cquantize->on_odd_row) { - /* work right to left in this row */ - inptr += (width-1) * 3; /* so point to rightmost pixel */ - outptr += width-1; - dir = -1; - dir3 = -3; - errorptr = cquantize->fserrors + (width+1)*3; /* => entry after last column */ - cquantize->on_odd_row = false; /* flip for next time */ - } else { - /* work left to right in this row */ - dir = 1; - dir3 = 3; - errorptr = cquantize->fserrors; /* => entry before first real column */ - cquantize->on_odd_row = true; /* flip for next time */ - } - /* Preset error values: no error propagated to first pixel from left */ - cur0 = cur1 = cur2 = 0; - /* and no error propagated to row below yet */ - belowerr0 = belowerr1 = belowerr2 = 0; - bpreverr0 = bpreverr1 = bpreverr2 = 0; - - for (col = width; col > 0; col--) { - /* curN holds the error propagated from the previous pixel on the - * current line. Add the error propagated from the previous line - * to form the complete error correction term for this pixel, and - * round the error term (which is expressed * 16) to an integer. - * RIGHT_SHIFT rounds towards minus infinity, so adding 8 is correct - * for either sign of the error value. - * Note: errorptr points to *previous* column's array entry. - */ - cur0 = RIGHT_SHIFT(cur0 + errorptr[dir3+0] + 8, 4); - cur1 = RIGHT_SHIFT(cur1 + errorptr[dir3+1] + 8, 4); - cur2 = RIGHT_SHIFT(cur2 + errorptr[dir3+2] + 8, 4); - /* Limit the error using transfer function set by init_error_limit. - * See comments with init_error_limit for rationale. - */ - cur0 = error_limit[cur0]; - cur1 = error_limit[cur1]; - cur2 = error_limit[cur2]; - /* Form pixel value + error, and range-limit to 0..MAXJSAMPLE. - * The maximum error is +- MAXJSAMPLE (or less with error limiting); - * this sets the required size of the range_limit array. - */ - cur0 += GETJSAMPLE(inptr[0]); - cur1 += GETJSAMPLE(inptr[1]); - cur2 += GETJSAMPLE(inptr[2]); - cur0 = GETJSAMPLE(range_limit[cur0]); - cur1 = GETJSAMPLE(range_limit[cur1]); - cur2 = GETJSAMPLE(range_limit[cur2]); - /* Index into the cache with adjusted pixel value */ - cachep = & histogram[cur0>>C0_SHIFT][cur1>>C1_SHIFT][cur2>>C2_SHIFT]; - /* If we have not seen this color before, find nearest colormap */ - /* entry and update the cache */ - if (*cachep == 0) - fill_inverse_cmap(cinfo, cur0>>C0_SHIFT,cur1>>C1_SHIFT,cur2>>C2_SHIFT); - /* Now emit the colormap index for this cell */ - { register int pixcode = *cachep - 1; - *outptr = (JSAMPLE) pixcode; - /* Compute representation error for this pixel */ - cur0 -= GETJSAMPLE(colormap0[pixcode]); - cur1 -= GETJSAMPLE(colormap1[pixcode]); - cur2 -= GETJSAMPLE(colormap2[pixcode]); - } - /* Compute error fractions to be propagated to adjacent pixels. - * Add these into the running sums, and simultaneously shift the - * next-line error sums left by 1 column. - */ - { register LOCFSERROR bnexterr, delta; - - bnexterr = cur0; /* Process component 0 */ - delta = cur0 * 2; - cur0 += delta; /* form error * 3 */ - errorptr[0] = (FSERROR) (bpreverr0 + cur0); - cur0 += delta; /* form error * 5 */ - bpreverr0 = belowerr0 + cur0; - belowerr0 = bnexterr; - cur0 += delta; /* form error * 7 */ - bnexterr = cur1; /* Process component 1 */ - delta = cur1 * 2; - cur1 += delta; /* form error * 3 */ - errorptr[1] = (FSERROR) (bpreverr1 + cur1); - cur1 += delta; /* form error * 5 */ - bpreverr1 = belowerr1 + cur1; - belowerr1 = bnexterr; - cur1 += delta; /* form error * 7 */ - bnexterr = cur2; /* Process component 2 */ - delta = cur2 * 2; - cur2 += delta; /* form error * 3 */ - errorptr[2] = (FSERROR) (bpreverr2 + cur2); - cur2 += delta; /* form error * 5 */ - bpreverr2 = belowerr2 + cur2; - belowerr2 = bnexterr; - cur2 += delta; /* form error * 7 */ - } - /* At this point curN contains the 7/16 error value to be propagated - * to the next pixel on the current line, and all the errors for the - * next line have been shifted over. We are therefore ready to move on. - */ - inptr += dir3; /* Advance pixel pointers to next column */ - outptr += dir; - errorptr += dir3; /* advance errorptr to current column */ - } - /* Post-loop cleanup: we must unload the final error values into the - * final fserrors[] entry. Note we need not unload belowerrN because - * it is for the dummy column before or after the actual array. - */ - errorptr[0] = (FSERROR) bpreverr0; /* unload prev errs into array */ - errorptr[1] = (FSERROR) bpreverr1; - errorptr[2] = (FSERROR) bpreverr2; - } -} - - -/* - * Initialize the error-limiting transfer function (lookup table). - * The raw F-S error computation can potentially compute error values of up to - * +- MAXJSAMPLE. But we want the maximum correction applied to a pixel to be - * much less, otherwise obviously wrong pixels will be created. (Typical - * effects include weird fringes at color-area boundaries, isolated bright - * pixels in a dark area, etc.) The standard advice for avoiding this problem - * is to ensure that the "corners" of the color cube are allocated as output - * colors; then repeated errors in the same direction cannot cause cascading - * error buildup. However, that only prevents the error from getting - * completely out of hand; Aaron Giles reports that error limiting improves - * the results even with corner colors allocated. - * A simple clamping of the error values to about +- MAXJSAMPLE/8 works pretty - * well, but the smoother transfer function used below is even better. Thanks - * to Aaron Giles for this idea. - */ - -static void -init_error_limit (j_decompress_ptr cinfo) -/* Allocate and fill in the error_limiter table */ -{ - my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; - int * table; - int in, out; - - table = (int *) malloc((MAXJSAMPLE*2+1) * sizeof(int)); - table += MAXJSAMPLE; /* so can index -MAXJSAMPLE .. +MAXJSAMPLE */ - cquantize->error_limiter = table; - -#define STEPSIZE ((MAXJSAMPLE+1)/16) - /* Map errors 1:1 up to +- MAXJSAMPLE/16 */ - out = 0; - for (in = 0; in < STEPSIZE; in++, out++) { - table[in] = out; table[-in] = -out; - } - /* Map errors 1:2 up to +- 3*MAXJSAMPLE/16 */ - for (; in < STEPSIZE*3; in++, out += (in&1) ? 0 : 1) { - table[in] = out; table[-in] = -out; - } - /* Clamp the rest to final out value (which is (MAXJSAMPLE+1)/8) */ - for (; in <= MAXJSAMPLE; in++) { - table[in] = out; table[-in] = -out; - } -#undef STEPSIZE -} - - -/* - * Finish up at the end of each pass. - */ - -void -finish_pass1 (j_decompress_ptr cinfo) -{ - my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; - - /* Select the representative colors and fill in cinfo->colormap */ - cinfo->colormap = cquantize->sv_colormap; - select_colors(cinfo, cquantize->desired); - /* Force next pass to zero the color index table */ - cquantize->needs_zeroed = true; -} - - -void -finish_pass2 (j_decompress_ptr WXUNUSED(cinfo)) -{ - /* no work */ -} - - -/* - * Initialize for each processing pass. - */ - -void -start_pass_2_quant (j_decompress_ptr cinfo, bool is_pre_scan) -{ - my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; - hist3d histogram = cquantize->histogram; - - if (is_pre_scan) { - /* Set up method pointers */ - cquantize->pub.color_quantize = prescan_quantize; - cquantize->pub.finish_pass = finish_pass1; - cquantize->needs_zeroed = true; /* Always zero histogram */ - } else { - /* Set up method pointers */ - cquantize->pub.color_quantize = pass2_fs_dither; - cquantize->pub.finish_pass = finish_pass2; - - { - size_t arraysize = (size_t) ((cinfo->output_width + 2) * - (3 * sizeof(FSERROR))); - /* Allocate Floyd-Steinberg workspace if we didn't already. */ - if (cquantize->fserrors == NULL) - cquantize->fserrors = (INT16*) malloc(arraysize); - /* Initialize the propagated errors to zero. */ - memset((void *) cquantize->fserrors, 0, arraysize); - /* Make the error-limit table if we didn't already. */ - if (cquantize->error_limiter == NULL) - init_error_limit(cinfo); - cquantize->on_odd_row = false; - } - - } - /* Zero the histogram or inverse color map, if necessary */ - if (cquantize->needs_zeroed) { - for (int i = 0; i < HIST_C0_ELEMS; i++) { - memset((void *) histogram[i], 0, - HIST_C1_ELEMS*HIST_C2_ELEMS * sizeof(histcell)); - } - cquantize->needs_zeroed = false; - } -} - - -/* - * Switch to a new external colormap between output passes. - */ - -void -new_color_map_2_quant (j_decompress_ptr cinfo) -{ - my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; - - /* Reset the inverse color map */ - cquantize->needs_zeroed = true; -} - - -/* - * Module initialization routine for 2-pass color quantization. - */ - -void -jinit_2pass_quantizer (j_decompress_ptr cinfo) -{ - my_cquantize_ptr cquantize; - int i; - - cquantize = (my_cquantize_ptr) malloc(sizeof(my_cquantizer)); - cinfo->cquantize = (jpeg_color_quantizer *) cquantize; - cquantize->pub.start_pass = start_pass_2_quant; - cquantize->pub.new_color_map = new_color_map_2_quant; - cquantize->fserrors = NULL; /* flag optional arrays not allocated */ - cquantize->error_limiter = NULL; - - - /* Allocate the histogram/inverse colormap storage */ - cquantize->histogram = (hist3d) malloc(HIST_C0_ELEMS * sizeof(hist2d)); - for (i = 0; i < HIST_C0_ELEMS; i++) { - cquantize->histogram[i] = (hist2d) malloc(HIST_C1_ELEMS*HIST_C2_ELEMS * sizeof(histcell)); - } - cquantize->needs_zeroed = true; /* histogram is garbage now */ - - /* Allocate storage for the completed colormap, if required. - * We do this now since it is storage and may affect - * the memory manager's space calculations. - */ - { - /* Make sure color count is acceptable */ - int desired = cinfo->desired_number_of_colors; - - cquantize->sv_colormap = (JSAMPARRAY) malloc(sizeof(JSAMPROW) * 3); - cquantize->sv_colormap[0] = (JSAMPROW) malloc(sizeof(JSAMPLE) * desired); - cquantize->sv_colormap[1] = (JSAMPROW) malloc(sizeof(JSAMPLE) * desired); - cquantize->sv_colormap[2] = (JSAMPROW) malloc(sizeof(JSAMPLE) * desired); - - cquantize->desired = desired; - } - - /* Allocate Floyd-Steinberg workspace if necessary. - * This isn't really needed until pass 2, but again it is storage. - * Although we will cope with a later change in dither_mode, - * we do not promise to honor max_memory_to_use if dither_mode changes. - */ - { - cquantize->fserrors = (FSERRPTR) malloc( - (size_t) ((cinfo->output_width + 2) * (3 * sizeof(FSERROR)))); - /* Might as well create the error-limiting table too. */ - init_error_limit(cinfo); - } -} - - - - - - - - - - -void -prepare_range_limit_table (j_decompress_ptr cinfo) -/* Allocate and fill in the sample_range_limit table */ -{ - JSAMPLE * table; - int i; - - table = (JSAMPLE *) malloc((5 * (MAXJSAMPLE+1) + CENTERJSAMPLE) * sizeof(JSAMPLE)); - cinfo->srl_orig = table; - table += (MAXJSAMPLE+1); /* allow negative subscripts of simple table */ - cinfo->sample_range_limit = table; - /* First segment of "simple" table: limit[x] = 0 for x < 0 */ - memset(table - (MAXJSAMPLE+1), 0, (MAXJSAMPLE+1) * sizeof(JSAMPLE)); - /* Main part of "simple" table: limit[x] = x */ - for (i = 0; i <= MAXJSAMPLE; i++) - table[i] = (JSAMPLE) i; - table += CENTERJSAMPLE; /* Point to where post-IDCT table starts */ - /* End of simple table, rest of first half of post-IDCT table */ - for (i = CENTERJSAMPLE; i < 2*(MAXJSAMPLE+1); i++) - table[i] = MAXJSAMPLE; - /* Second half of post-IDCT table */ - memset(table + (2 * (MAXJSAMPLE+1)), 0, - (2 * (MAXJSAMPLE+1) - CENTERJSAMPLE) * sizeof(JSAMPLE)); - memcpy(table + (4 * (MAXJSAMPLE+1) - CENTERJSAMPLE), - cinfo->sample_range_limit, CENTERJSAMPLE * sizeof(JSAMPLE)); -} - - - - -/* - * wxQuantize - */ - -IMPLEMENT_DYNAMIC_CLASS(wxQuantize, wxObject) - -void wxQuantize::DoQuantize(unsigned w, unsigned h, unsigned char **in_rows, unsigned char **out_rows, - unsigned char *palette, int desiredNoColours) -{ - j_decompress dec; - my_cquantize_ptr cquantize; - - dec.output_width = w; - dec.desired_number_of_colors = desiredNoColours; - prepare_range_limit_table(&dec); - jinit_2pass_quantizer(&dec); - cquantize = (my_cquantize_ptr) dec.cquantize; - - - cquantize->pub.start_pass(&dec, true); - cquantize->pub.color_quantize(&dec, in_rows, out_rows, h); - cquantize->pub.finish_pass(&dec); - - cquantize->pub.start_pass(&dec, false); - cquantize->pub.color_quantize(&dec, in_rows, out_rows, h); - cquantize->pub.finish_pass(&dec); - - - for (int i = 0; i < dec.desired_number_of_colors; i++) { - palette[3 * i + 0] = dec.colormap[0][i]; - palette[3 * i + 1] = dec.colormap[1][i]; - palette[3 * i + 2] = dec.colormap[2][i]; - } - - for (int ii = 0; ii < HIST_C0_ELEMS; ii++) free(cquantize->histogram[ii]); - free(cquantize->histogram); - free(dec.colormap[0]); - free(dec.colormap[1]); - free(dec.colormap[2]); - free(dec.colormap); - free(dec.srl_orig); - - //free(cquantize->error_limiter); - free((void*)(cquantize->error_limiter - MAXJSAMPLE)); // To reverse what was done to it - - free(cquantize->fserrors); - free(cquantize); -} - -// TODO: somehow make use of the Windows system colours, rather than ignoring them for the -// purposes of quantization. - -bool wxQuantize::Quantize(const wxImage& src, wxImage& dest, - wxPalette** pPalette, - int desiredNoColours, - unsigned char** eightBitData, - int flags) - -{ - int i; - - int windowsSystemColourCount = 20; - - int paletteShift = 0; - - // Shift the palette up by the number of Windows system colours, - // if necessary - if (flags & wxQUANTIZE_INCLUDE_WINDOWS_COLOURS) - paletteShift = windowsSystemColourCount; - - // Make room for the Windows system colours -#ifdef __WXMSW__ - if ((flags & wxQUANTIZE_INCLUDE_WINDOWS_COLOURS) && (desiredNoColours > (256 - windowsSystemColourCount))) - desiredNoColours = 256 - windowsSystemColourCount; -#endif - - // create rows info: - int h = src.GetHeight(); - int w = src.GetWidth(); - unsigned char **rows = new unsigned char *[h]; - unsigned char *imgdt = src.GetData(); - for (i = 0; i < h; i++) - rows[i] = imgdt + 3/*RGB*/ * w * i; - - unsigned char palette[3*256]; - - // This is the image as represented by palette indexes. - unsigned char *data8bit = new unsigned char[w * h]; - unsigned char **outrows = new unsigned char *[h]; - for (i = 0; i < h; i++) - outrows[i] = data8bit + w * i; - - //RGB->palette - DoQuantize(w, h, rows, outrows, palette, desiredNoColours); - - delete[] rows; - delete[] outrows; - - // palette->RGB(max.256) - - if (flags & wxQUANTIZE_FILL_DESTINATION_IMAGE) - { - if (!dest.Ok()) - dest.Create(w, h); - - imgdt = dest.GetData(); - for (i = 0; i < w * h; i++) - { - unsigned char c = data8bit[i]; - imgdt[3 * i + 0/*R*/] = palette[3 * c + 0]; - imgdt[3 * i + 1/*G*/] = palette[3 * c + 1]; - imgdt[3 * i + 2/*B*/] = palette[3 * c + 2]; - } - } - - if (eightBitData && (flags & wxQUANTIZE_RETURN_8BIT_DATA)) - { -#ifdef __WXMSW__ - if (flags & wxQUANTIZE_INCLUDE_WINDOWS_COLOURS) - { - // We need to shift the palette entries up - // to make room for the Windows system colours. - for (i = 0; i < w * h; i++) - data8bit[i] = (unsigned char)(data8bit[i] + paletteShift); - } -#endif - *eightBitData = data8bit; - } - else - delete[] data8bit; - -#if wxUSE_PALETTE - // Make a wxWidgets palette - if (pPalette) - { - unsigned char* r = new unsigned char[256]; - unsigned char* g = new unsigned char[256]; - unsigned char* b = new unsigned char[256]; - -#ifdef __WXMSW__ - // Fill the first 20 entries with Windows system colours - if (flags & wxQUANTIZE_INCLUDE_WINDOWS_COLOURS) - { - HDC hDC = ::GetDC(NULL); - PALETTEENTRY* entries = new PALETTEENTRY[windowsSystemColourCount]; - ::GetSystemPaletteEntries(hDC, 0, windowsSystemColourCount, entries); - ::ReleaseDC(NULL, hDC); - - for (i = 0; i < windowsSystemColourCount; i++) - { - r[i] = entries[i].peRed; - g[i] = entries[i].peGreen; - b[i] = entries[i].peBlue; - } - delete[] entries; - } -#endif - - for (i = 0; i < desiredNoColours; i++) - { - r[i+paletteShift] = palette[i*3 + 0]; - g[i+paletteShift] = palette[i*3 + 1]; - b[i+paletteShift] = palette[i*3 + 2]; - } - - // Blank out any remaining palette entries - for (i = desiredNoColours+paletteShift; i < 256; i++) - { - r[i] = 0; - g[i] = 0; - b[i] = 0; - } - *pPalette = new wxPalette(256, r, g, b); - delete[] r; - delete[] g; - delete[] b; - } -#endif // wxUSE_PALETTE - - return true; -} - -// This version sets a palette in the destination image so you don't -// have to manage it yourself. - -bool wxQuantize::Quantize(const wxImage& src, - wxImage& dest, - int desiredNoColours, - unsigned char** eightBitData, - int flags) -{ - wxPalette* palette = NULL; - if ( !Quantize(src, dest, & palette, desiredNoColours, eightBitData, flags) ) - return false; - -#if wxUSE_PALETTE - if (palette) - { - dest.SetPalette(* palette); - delete palette; - } -#endif // wxUSE_PALETTE - - return true; -} - -#endif - // wxUSE_IMAGE +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/quantize.cpp +// Purpose: wxQuantize implementation +// Author: Julian Smart +// Modified by: +// Created: 22/6/2000 +// RCS-ID: $Id: quantize.cpp 39957 2006-07-03 19:02:54Z ABX $ +// Copyright: (c) Thomas G. Lane, Vaclav Slavik, Julian Smart +// Licence: wxWindows licence + JPEG library licence +///////////////////////////////////////////////////////////////////////////// + +/* + * jquant2.c + * + * Copyright (C) 1991-1996, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains 2-pass color quantization (color mapping) routines. + * These routines provide selection of a custom color map for an image, + * followed by mapping of the image to that color map, with optional + * Floyd-Steinberg dithering. + * It is also possible to use just the second pass to map to an arbitrary + * externally-given color map. + * + * Note: ordered dithering is not supported, since there isn't any fast + * way to compute intercolor distances; it's unclear that ordered dither's + * fundamental assumptions even hold with an irregularly spaced color map. + */ + +/* modified by Vaclav Slavik for use as jpeglib-independent module */ + +// For compilers that support precompilation, includes "wx/wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ +#pragma hdrstop +#endif + +#if wxUSE_IMAGE + +#include "wx/quantize.h" + +#ifndef WX_PRECOMP + #include "wx/palette.h" + #include "wx/image.h" +#endif + +#ifdef __WXMSW__ + #include "wx/msw/private.h" +#endif + +#include +#include + +#if defined(__OS2__) +#define RGB_RED_OS2 0 +#define RGB_GREEN_OS2 1 +#define RGB_BLUE_OS2 2 +#else +#define RGB_RED 0 +#define RGB_GREEN 1 +#define RGB_BLUE 2 +#endif +#define RGB_PIXELSIZE 3 + +#define MAXJSAMPLE 255 +#define CENTERJSAMPLE 128 +#define BITS_IN_JSAMPLE 8 +#define GETJSAMPLE(value) ((int) (value)) + +#define RIGHT_SHIFT(x,shft) ((x) >> (shft)) + +typedef unsigned short UINT16; +typedef signed short INT16; +#if !(defined(__WATCOMC__) && (defined(__WXMSW__) || defined(__WXMOTIF__))) +typedef signed int INT32; +#endif + +typedef unsigned char JSAMPLE; +typedef JSAMPLE *JSAMPROW; +typedef JSAMPROW *JSAMPARRAY; +typedef unsigned int JDIMENSION; + +typedef struct { + void *cquantize; + JDIMENSION output_width; + JSAMPARRAY colormap; + int actual_number_of_colors; + int desired_number_of_colors; + JSAMPLE *sample_range_limit, *srl_orig; +} j_decompress; + +#if defined(__WINDOWS__) && !defined(__WXMICROWIN__) + #define JMETHOD(type,methodname,arglist) type (__cdecl methodname) arglist +#else + #define JMETHOD(type,methodname,arglist) type (methodname) arglist +#endif + +typedef j_decompress *j_decompress_ptr; +struct jpeg_color_quantizer { + JMETHOD(void, start_pass, (j_decompress_ptr cinfo, bool is_pre_scan)); + JMETHOD(void, color_quantize, (j_decompress_ptr cinfo, + JSAMPARRAY input_buf, JSAMPARRAY output_buf, + int num_rows)); + JMETHOD(void, finish_pass, (j_decompress_ptr cinfo)); + JMETHOD(void, new_color_map, (j_decompress_ptr cinfo)); +}; + + + + +/* + * This module implements the well-known Heckbert paradigm for color + * quantization. Most of the ideas used here can be traced back to + * Heckbert's seminal paper + * Heckbert, Paul. "Color Image Quantization for Frame Buffer Display", + * Proc. SIGGRAPH '82, Computer Graphics v.16 #3 (July 1982), pp 297-304. + * + * In the first pass over the image, we accumulate a histogram showing the + * usage count of each possible color. To keep the histogram to a reasonable + * size, we reduce the precision of the input; typical practice is to retain + * 5 or 6 bits per color, so that 8 or 4 different input values are counted + * in the same histogram cell. + * + * Next, the color-selection step begins with a box representing the whole + * color space, and repeatedly splits the "largest" remaining box until we + * have as many boxes as desired colors. Then the mean color in each + * remaining box becomes one of the possible output colors. + * + * The second pass over the image maps each input pixel to the closest output + * color (optionally after applying a Floyd-Steinberg dithering correction). + * This mapping is logically trivial, but making it go fast enough requires + * considerable care. + * + * Heckbert-style quantizers vary a good deal in their policies for choosing + * the "largest" box and deciding where to cut it. The particular policies + * used here have proved out well in experimental comparisons, but better ones + * may yet be found. + * + * In earlier versions of the IJG code, this module quantized in YCbCr color + * space, processing the raw upsampled data without a color conversion step. + * This allowed the color conversion math to be done only once per colormap + * entry, not once per pixel. However, that optimization precluded other + * useful optimizations (such as merging color conversion with upsampling) + * and it also interfered with desired capabilities such as quantizing to an + * externally-supplied colormap. We have therefore abandoned that approach. + * The present code works in the post-conversion color space, typically RGB. + * + * To improve the visual quality of the results, we actually work in scaled + * RGB space, giving G distances more weight than R, and R in turn more than + * B. To do everything in integer math, we must use integer scale factors. + * The 2/3/1 scale factors used here correspond loosely to the relative + * weights of the colors in the NTSC grayscale equation. + * If you want to use this code to quantize a non-RGB color space, you'll + * probably need to change these scale factors. + */ + +#define R_SCALE 2 /* scale R distances by this much */ +#define G_SCALE 3 /* scale G distances by this much */ +#define B_SCALE 1 /* and B by this much */ + +/* Relabel R/G/B as components 0/1/2, respecting the RGB ordering defined + * in jmorecfg.h. As the code stands, it will do the right thing for R,G,B + * and B,G,R orders. If you define some other weird order in jmorecfg.h, + * you'll get compile errors until you extend this logic. In that case + * you'll probably want to tweak the histogram sizes too. + */ + +#if defined(__OS2__) + +#if RGB_RED_OS2 == 0 +#define C0_SCALE R_SCALE +#endif +#if RGB_BLUE_OS2 == 0 +#define C0_SCALE B_SCALE +#endif +#if RGB_GREEN_OS2 == 1 +#define C1_SCALE G_SCALE +#endif +#if RGB_RED_OS2 == 2 +#define C2_SCALE R_SCALE +#endif +#if RGB_BLUE_OS2 == 2 +#define C2_SCALE B_SCALE +#endif + +#else + +#if RGB_RED == 0 +#define C0_SCALE R_SCALE +#endif +#if RGB_BLUE == 0 +#define C0_SCALE B_SCALE +#endif +#if RGB_GREEN == 1 +#define C1_SCALE G_SCALE +#endif +#if RGB_RED == 2 +#define C2_SCALE R_SCALE +#endif +#if RGB_BLUE == 2 +#define C2_SCALE B_SCALE +#endif + +#endif + +/* + * First we have the histogram data structure and routines for creating it. + * + * The number of bits of precision can be adjusted by changing these symbols. + * We recommend keeping 6 bits for G and 5 each for R and B. + * If you have plenty of memory and cycles, 6 bits all around gives marginally + * better results; if you are short of memory, 5 bits all around will save + * some space but degrade the results. + * To maintain a fully accurate histogram, we'd need to allocate a "long" + * (preferably unsigned long) for each cell. In practice this is overkill; + * we can get by with 16 bits per cell. Few of the cell counts will overflow, + * and clamping those that do overflow to the maximum value will give close- + * enough results. This reduces the recommended histogram size from 256Kb + * to 128Kb, which is a useful savings on PC-class machines. + * (In the second pass the histogram space is re-used for pixel mapping data; + * in that capacity, each cell must be able to store zero to the number of + * desired colors. 16 bits/cell is plenty for that too.) + * Since the JPEG code is intended to run in small memory model on 80x86 + * machines, we can't just allocate the histogram in one chunk. Instead + * of a true 3-D array, we use a row of pointers to 2-D arrays. Each + * pointer corresponds to a C0 value (typically 2^5 = 32 pointers) and + * each 2-D array has 2^6*2^5 = 2048 or 2^6*2^6 = 4096 entries. Note that + * on 80x86 machines, the pointer row is in near memory but the actual + * arrays are in far memory (same arrangement as we use for image arrays). + */ + +#define MAXNUMCOLORS (MAXJSAMPLE+1) /* maximum size of colormap */ + +/* These will do the right thing for either R,G,B or B,G,R color order, + * but you may not like the results for other color orders. + */ +#define HIST_C0_BITS 5 /* bits of precision in R/B histogram */ +#define HIST_C1_BITS 6 /* bits of precision in G histogram */ +#define HIST_C2_BITS 5 /* bits of precision in B/R histogram */ + +/* Number of elements along histogram axes. */ +#define HIST_C0_ELEMS (1<cquantize; + register JSAMPROW ptr; + register histptr histp; + register hist3d histogram = cquantize->histogram; + int row; + JDIMENSION col; + JDIMENSION width = cinfo->output_width; + + for (row = 0; row < num_rows; row++) { + ptr = input_buf[row]; + for (col = width; col > 0; col--) { + + { + + /* get pixel value and index into the histogram */ + histp = & histogram[GETJSAMPLE(ptr[0]) >> C0_SHIFT] + [GETJSAMPLE(ptr[1]) >> C1_SHIFT] + [GETJSAMPLE(ptr[2]) >> C2_SHIFT]; + /* increment, check for overflow and undo increment if so. */ + if (++(*histp) <= 0) + (*histp)--; + } + ptr += 3; + } + } +} + + +/* + * Next we have the really interesting routines: selection of a colormap + * given the completed histogram. + * These routines work with a list of "boxes", each representing a rectangular + * subset of the input color space (to histogram precision). + */ + +typedef struct { + /* The bounds of the box (inclusive); expressed as histogram indexes */ + int c0min, c0max; + int c1min, c1max; + int c2min, c2max; + /* The volume (actually 2-norm) of the box */ + INT32 volume; + /* The number of nonzero histogram cells within this box */ + long colorcount; +} box; + +typedef box * boxptr; + + +boxptr +find_biggest_color_pop (boxptr boxlist, int numboxes) +/* Find the splittable box with the largest color population */ +/* Returns NULL if no splittable boxes remain */ +{ + register boxptr boxp; + register int i; + register long maxc = 0; + boxptr which = NULL; + + for (i = 0, boxp = boxlist; i < numboxes; i++, boxp++) { + if (boxp->colorcount > maxc && boxp->volume > 0) { + which = boxp; + maxc = boxp->colorcount; + } + } + return which; +} + + +boxptr +find_biggest_volume (boxptr boxlist, int numboxes) +/* Find the splittable box with the largest (scaled) volume */ +/* Returns NULL if no splittable boxes remain */ +{ + register boxptr boxp; + register int i; + register INT32 maxv = 0; + boxptr which = NULL; + + for (i = 0, boxp = boxlist; i < numboxes; i++, boxp++) { + if (boxp->volume > maxv) { + which = boxp; + maxv = boxp->volume; + } + } + return which; +} + + +void +update_box (j_decompress_ptr cinfo, boxptr boxp) +/* Shrink the min/max bounds of a box to enclose only nonzero elements, */ +/* and recompute its volume and population */ +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + hist3d histogram = cquantize->histogram; + histptr histp; + int c0,c1,c2; + int c0min,c0max,c1min,c1max,c2min,c2max; + INT32 dist0,dist1,dist2; + long ccount; + + c0min = boxp->c0min; c0max = boxp->c0max; + c1min = boxp->c1min; c1max = boxp->c1max; + c2min = boxp->c2min; c2max = boxp->c2max; + + if (c0max > c0min) + for (c0 = c0min; c0 <= c0max; c0++) + for (c1 = c1min; c1 <= c1max; c1++) { + histp = & histogram[c0][c1][c2min]; + for (c2 = c2min; c2 <= c2max; c2++) + if (*histp++ != 0) { + boxp->c0min = c0min = c0; + goto have_c0min; + } + } + have_c0min: + if (c0max > c0min) + for (c0 = c0max; c0 >= c0min; c0--) + for (c1 = c1min; c1 <= c1max; c1++) { + histp = & histogram[c0][c1][c2min]; + for (c2 = c2min; c2 <= c2max; c2++) + if (*histp++ != 0) { + boxp->c0max = c0max = c0; + goto have_c0max; + } + } + have_c0max: + if (c1max > c1min) + for (c1 = c1min; c1 <= c1max; c1++) + for (c0 = c0min; c0 <= c0max; c0++) { + histp = & histogram[c0][c1][c2min]; + for (c2 = c2min; c2 <= c2max; c2++) + if (*histp++ != 0) { + boxp->c1min = c1min = c1; + goto have_c1min; + } + } + have_c1min: + if (c1max > c1min) + for (c1 = c1max; c1 >= c1min; c1--) + for (c0 = c0min; c0 <= c0max; c0++) { + histp = & histogram[c0][c1][c2min]; + for (c2 = c2min; c2 <= c2max; c2++) + if (*histp++ != 0) { + boxp->c1max = c1max = c1; + goto have_c1max; + } + } + have_c1max: + if (c2max > c2min) + for (c2 = c2min; c2 <= c2max; c2++) + for (c0 = c0min; c0 <= c0max; c0++) { + histp = & histogram[c0][c1min][c2]; + for (c1 = c1min; c1 <= c1max; c1++, histp += HIST_C2_ELEMS) + if (*histp != 0) { + boxp->c2min = c2min = c2; + goto have_c2min; + } + } + have_c2min: + if (c2max > c2min) + for (c2 = c2max; c2 >= c2min; c2--) + for (c0 = c0min; c0 <= c0max; c0++) { + histp = & histogram[c0][c1min][c2]; + for (c1 = c1min; c1 <= c1max; c1++, histp += HIST_C2_ELEMS) + if (*histp != 0) { + boxp->c2max = c2max = c2; + goto have_c2max; + } + } + have_c2max: + + /* Update box volume. + * We use 2-norm rather than real volume here; this biases the method + * against making long narrow boxes, and it has the side benefit that + * a box is splittable iff norm > 0. + * Since the differences are expressed in histogram-cell units, + * we have to shift back to JSAMPLE units to get consistent distances; + * after which, we scale according to the selected distance scale factors. + */ + dist0 = ((c0max - c0min) << C0_SHIFT) * C0_SCALE; + dist1 = ((c1max - c1min) << C1_SHIFT) * C1_SCALE; + dist2 = ((c2max - c2min) << C2_SHIFT) * C2_SCALE; + boxp->volume = dist0*dist0 + dist1*dist1 + dist2*dist2; + + /* Now scan remaining volume of box and compute population */ + ccount = 0; + for (c0 = c0min; c0 <= c0max; c0++) + for (c1 = c1min; c1 <= c1max; c1++) { + histp = & histogram[c0][c1][c2min]; + for (c2 = c2min; c2 <= c2max; c2++, histp++) + if (*histp != 0) { + ccount++; + } + } + boxp->colorcount = ccount; +} + + +int +median_cut (j_decompress_ptr cinfo, boxptr boxlist, int numboxes, + int desired_colors) +/* Repeatedly select and split the largest box until we have enough boxes */ +{ + int n,lb; + int c0,c1,c2,cmax; + register boxptr b1,b2; + + while (numboxes < desired_colors) { + /* Select box to split. + * Current algorithm: by population for first half, then by volume. + */ + if ((numboxes*2) <= desired_colors) { + b1 = find_biggest_color_pop(boxlist, numboxes); + } else { + b1 = find_biggest_volume(boxlist, numboxes); + } + if (b1 == NULL) /* no splittable boxes left! */ + break; + b2 = &boxlist[numboxes]; /* where new box will go */ + /* Copy the color bounds to the new box. */ + b2->c0max = b1->c0max; b2->c1max = b1->c1max; b2->c2max = b1->c2max; + b2->c0min = b1->c0min; b2->c1min = b1->c1min; b2->c2min = b1->c2min; + /* Choose which axis to split the box on. + * Current algorithm: longest scaled axis. + * See notes in update_box about scaling distances. + */ + c0 = ((b1->c0max - b1->c0min) << C0_SHIFT) * C0_SCALE; + c1 = ((b1->c1max - b1->c1min) << C1_SHIFT) * C1_SCALE; + c2 = ((b1->c2max - b1->c2min) << C2_SHIFT) * C2_SCALE; + /* We want to break any ties in favor of green, then red, blue last. + * This code does the right thing for R,G,B or B,G,R color orders only. + */ +#if defined(__VISAGECPP__) + +#if RGB_RED_OS2 == 0 + cmax = c1; n = 1; + if (c0 > cmax) { cmax = c0; n = 0; } + if (c2 > cmax) { n = 2; } +#else + cmax = c1; n = 1; + if (c2 > cmax) { cmax = c2; n = 2; } + if (c0 > cmax) { n = 0; } +#endif + +#else + +#if RGB_RED == 0 + cmax = c1; n = 1; + if (c0 > cmax) { cmax = c0; n = 0; } + if (c2 > cmax) { n = 2; } +#else + cmax = c1; n = 1; + if (c2 > cmax) { cmax = c2; n = 2; } + if (c0 > cmax) { n = 0; } +#endif + +#endif + /* Choose split point along selected axis, and update box bounds. + * Current algorithm: split at halfway point. + * (Since the box has been shrunk to minimum volume, + * any split will produce two nonempty subboxes.) + * Note that lb value is max for lower box, so must be < old max. + */ + switch (n) { + case 0: + lb = (b1->c0max + b1->c0min) / 2; + b1->c0max = lb; + b2->c0min = lb+1; + break; + case 1: + lb = (b1->c1max + b1->c1min) / 2; + b1->c1max = lb; + b2->c1min = lb+1; + break; + case 2: + lb = (b1->c2max + b1->c2min) / 2; + b1->c2max = lb; + b2->c2min = lb+1; + break; + } + /* Update stats for boxes */ + update_box(cinfo, b1); + update_box(cinfo, b2); + numboxes++; + } + return numboxes; +} + + +void +compute_color (j_decompress_ptr cinfo, boxptr boxp, int icolor) +/* Compute representative color for a box, put it in colormap[icolor] */ +{ + /* Current algorithm: mean weighted by pixels (not colors) */ + /* Note it is important to get the rounding correct! */ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + hist3d histogram = cquantize->histogram; + histptr histp; + int c0,c1,c2; + int c0min,c0max,c1min,c1max,c2min,c2max; + long count; + long total = 0; + long c0total = 0; + long c1total = 0; + long c2total = 0; + + c0min = boxp->c0min; c0max = boxp->c0max; + c1min = boxp->c1min; c1max = boxp->c1max; + c2min = boxp->c2min; c2max = boxp->c2max; + + for (c0 = c0min; c0 <= c0max; c0++) + for (c1 = c1min; c1 <= c1max; c1++) { + histp = & histogram[c0][c1][c2min]; + for (c2 = c2min; c2 <= c2max; c2++) { + if ((count = *histp++) != 0) { + total += count; + c0total += ((c0 << C0_SHIFT) + ((1<>1)) * count; + c1total += ((c1 << C1_SHIFT) + ((1<>1)) * count; + c2total += ((c2 << C2_SHIFT) + ((1<>1)) * count; + } + } + } + + cinfo->colormap[0][icolor] = (JSAMPLE) ((c0total + (total>>1)) / total); + cinfo->colormap[1][icolor] = (JSAMPLE) ((c1total + (total>>1)) / total); + cinfo->colormap[2][icolor] = (JSAMPLE) ((c2total + (total>>1)) / total); +} + + +static void +select_colors (j_decompress_ptr cinfo, int desired_colors) +/* Master routine for color selection */ +{ + boxptr boxlist; + int numboxes; + int i; + + /* Allocate workspace for box list */ + boxlist = (boxptr) malloc(desired_colors * sizeof(box)); + /* Initialize one box containing whole space */ + numboxes = 1; + boxlist[0].c0min = 0; + boxlist[0].c0max = MAXJSAMPLE >> C0_SHIFT; + boxlist[0].c1min = 0; + boxlist[0].c1max = MAXJSAMPLE >> C1_SHIFT; + boxlist[0].c2min = 0; + boxlist[0].c2max = MAXJSAMPLE >> C2_SHIFT; + /* Shrink it to actually-used volume and set its statistics */ + update_box(cinfo, & boxlist[0]); + /* Perform median-cut to produce final box list */ + numboxes = median_cut(cinfo, boxlist, numboxes, desired_colors); + /* Compute the representative color for each box, fill colormap */ + for (i = 0; i < numboxes; i++) + compute_color(cinfo, & boxlist[i], i); + cinfo->actual_number_of_colors = numboxes; + + free(boxlist); //FIXME?? I don't know if this is correct - VS +} + + +/* + * These routines are concerned with the time-critical task of mapping input + * colors to the nearest color in the selected colormap. + * + * We re-use the histogram space as an "inverse color map", essentially a + * cache for the results of nearest-color searches. All colors within a + * histogram cell will be mapped to the same colormap entry, namely the one + * closest to the cell's center. This may not be quite the closest entry to + * the actual input color, but it's almost as good. A zero in the cache + * indicates we haven't found the nearest color for that cell yet; the array + * is cleared to zeroes before starting the mapping pass. When we find the + * nearest color for a cell, its colormap index plus one is recorded in the + * cache for future use. The pass2 scanning routines call fill_inverse_cmap + * when they need to use an unfilled entry in the cache. + * + * Our method of efficiently finding nearest colors is based on the "locally + * sorted search" idea described by Heckbert and on the incremental distance + * calculation described by Spencer W. Thomas in chapter III.1 of Graphics + * Gems II (James Arvo, ed. Academic Press, 1991). Thomas points out that + * the distances from a given colormap entry to each cell of the histogram can + * be computed quickly using an incremental method: the differences between + * distances to adjacent cells themselves differ by a constant. This allows a + * fairly fast implementation of the "brute force" approach of computing the + * distance from every colormap entry to every histogram cell. Unfortunately, + * it needs a work array to hold the best-distance-so-far for each histogram + * cell (because the inner loop has to be over cells, not colormap entries). + * The work array elements have to be INT32s, so the work array would need + * 256Kb at our recommended precision. This is not feasible in DOS machines. + * + * To get around these problems, we apply Thomas' method to compute the + * nearest colors for only the cells within a small subbox of the histogram. + * The work array need be only as big as the subbox, so the memory usage + * problem is solved. Furthermore, we need not fill subboxes that are never + * referenced in pass2; many images use only part of the color gamut, so a + * fair amount of work is saved. An additional advantage of this + * approach is that we can apply Heckbert's locality criterion to quickly + * eliminate colormap entries that are far away from the subbox; typically + * three-fourths of the colormap entries are rejected by Heckbert's criterion, + * and we need not compute their distances to individual cells in the subbox. + * The speed of this approach is heavily influenced by the subbox size: too + * small means too much overhead, too big loses because Heckbert's criterion + * can't eliminate as many colormap entries. Empirically the best subbox + * size seems to be about 1/512th of the histogram (1/8th in each direction). + * + * Thomas' article also describes a refined method which is asymptotically + * faster than the brute-force method, but it is also far more complex and + * cannot efficiently be applied to small subboxes. It is therefore not + * useful for programs intended to be portable to DOS machines. On machines + * with plenty of memory, filling the whole histogram in one shot with Thomas' + * refined method might be faster than the present code --- but then again, + * it might not be any faster, and it's certainly more complicated. + */ + + +/* log2(histogram cells in update box) for each axis; this can be adjusted */ +#define BOX_C0_LOG (HIST_C0_BITS-3) +#define BOX_C1_LOG (HIST_C1_BITS-3) +#define BOX_C2_LOG (HIST_C2_BITS-3) + +#define BOX_C0_ELEMS (1<actual_number_of_colors; + int maxc0, maxc1, maxc2; + int centerc0, centerc1, centerc2; + int i, x, ncolors; + INT32 minmaxdist, min_dist, max_dist, tdist; + INT32 mindist[MAXNUMCOLORS]; /* min distance to colormap entry i */ + + /* Compute true coordinates of update box's upper corner and center. + * Actually we compute the coordinates of the center of the upper-corner + * histogram cell, which are the upper bounds of the volume we care about. + * Note that since ">>" rounds down, the "center" values may be closer to + * min than to max; hence comparisons to them must be "<=", not "<". + */ + maxc0 = minc0 + ((1 << BOX_C0_SHIFT) - (1 << C0_SHIFT)); + centerc0 = (minc0 + maxc0) >> 1; + maxc1 = minc1 + ((1 << BOX_C1_SHIFT) - (1 << C1_SHIFT)); + centerc1 = (minc1 + maxc1) >> 1; + maxc2 = minc2 + ((1 << BOX_C2_SHIFT) - (1 << C2_SHIFT)); + centerc2 = (minc2 + maxc2) >> 1; + + /* For each color in colormap, find: + * 1. its minimum squared-distance to any point in the update box + * (zero if color is within update box); + * 2. its maximum squared-distance to any point in the update box. + * Both of these can be found by considering only the corners of the box. + * We save the minimum distance for each color in mindist[]; + * only the smallest maximum distance is of interest. + */ + minmaxdist = 0x7FFFFFFFL; + + for (i = 0; i < numcolors; i++) { + /* We compute the squared-c0-distance term, then add in the other two. */ + x = GETJSAMPLE(cinfo->colormap[0][i]); + if (x < minc0) { + tdist = (x - minc0) * C0_SCALE; + min_dist = tdist*tdist; + tdist = (x - maxc0) * C0_SCALE; + max_dist = tdist*tdist; + } else if (x > maxc0) { + tdist = (x - maxc0) * C0_SCALE; + min_dist = tdist*tdist; + tdist = (x - minc0) * C0_SCALE; + max_dist = tdist*tdist; + } else { + /* within cell range so no contribution to min_dist */ + min_dist = 0; + if (x <= centerc0) { + tdist = (x - maxc0) * C0_SCALE; + max_dist = tdist*tdist; + } else { + tdist = (x - minc0) * C0_SCALE; + max_dist = tdist*tdist; + } + } + + x = GETJSAMPLE(cinfo->colormap[1][i]); + if (x < minc1) { + tdist = (x - minc1) * C1_SCALE; + min_dist += tdist*tdist; + tdist = (x - maxc1) * C1_SCALE; + max_dist += tdist*tdist; + } else if (x > maxc1) { + tdist = (x - maxc1) * C1_SCALE; + min_dist += tdist*tdist; + tdist = (x - minc1) * C1_SCALE; + max_dist += tdist*tdist; + } else { + /* within cell range so no contribution to min_dist */ + if (x <= centerc1) { + tdist = (x - maxc1) * C1_SCALE; + max_dist += tdist*tdist; + } else { + tdist = (x - minc1) * C1_SCALE; + max_dist += tdist*tdist; + } + } + + x = GETJSAMPLE(cinfo->colormap[2][i]); + if (x < minc2) { + tdist = (x - minc2) * C2_SCALE; + min_dist += tdist*tdist; + tdist = (x - maxc2) * C2_SCALE; + max_dist += tdist*tdist; + } else if (x > maxc2) { + tdist = (x - maxc2) * C2_SCALE; + min_dist += tdist*tdist; + tdist = (x - minc2) * C2_SCALE; + max_dist += tdist*tdist; + } else { + /* within cell range so no contribution to min_dist */ + if (x <= centerc2) { + tdist = (x - maxc2) * C2_SCALE; + max_dist += tdist*tdist; + } else { + tdist = (x - minc2) * C2_SCALE; + max_dist += tdist*tdist; + } + } + + mindist[i] = min_dist; /* save away the results */ + if (max_dist < minmaxdist) + minmaxdist = max_dist; + } + + /* Now we know that no cell in the update box is more than minmaxdist + * away from some colormap entry. Therefore, only colors that are + * within minmaxdist of some part of the box need be considered. + */ + ncolors = 0; + for (i = 0; i < numcolors; i++) { + if (mindist[i] <= minmaxdist) + colorlist[ncolors++] = (JSAMPLE) i; + } + return ncolors; +} + + +static void +find_best_colors (j_decompress_ptr cinfo, int minc0, int minc1, int minc2, + int numcolors, JSAMPLE colorlist[], JSAMPLE bestcolor[]) +/* Find the closest colormap entry for each cell in the update box, + * given the list of candidate colors prepared by find_nearby_colors. + * Return the indexes of the closest entries in the bestcolor[] array. + * This routine uses Thomas' incremental distance calculation method to + * find the distance from a colormap entry to successive cells in the box. + */ +{ + int ic0, ic1, ic2; + int i, icolor; + register INT32 * bptr; /* pointer into bestdist[] array */ + JSAMPLE * cptr; /* pointer into bestcolor[] array */ + INT32 dist0, dist1; /* initial distance values */ + register INT32 dist2; /* current distance in inner loop */ + INT32 xx0, xx1; /* distance increments */ + register INT32 xx2; + INT32 inc0, inc1, inc2; /* initial values for increments */ + /* This array holds the distance to the nearest-so-far color for each cell */ + INT32 bestdist[BOX_C0_ELEMS * BOX_C1_ELEMS * BOX_C2_ELEMS]; + + /* Initialize best-distance for each cell of the update box */ + bptr = bestdist; + for (i = BOX_C0_ELEMS*BOX_C1_ELEMS*BOX_C2_ELEMS-1; i >= 0; i--) + *bptr++ = 0x7FFFFFFFL; + + /* For each color selected by find_nearby_colors, + * compute its distance to the center of each cell in the box. + * If that's less than best-so-far, update best distance and color number. + */ + + /* Nominal steps between cell centers ("x" in Thomas article) */ +#define STEP_C0 ((1 << C0_SHIFT) * C0_SCALE) +#define STEP_C1 ((1 << C1_SHIFT) * C1_SCALE) +#define STEP_C2 ((1 << C2_SHIFT) * C2_SCALE) + + for (i = 0; i < numcolors; i++) { + icolor = GETJSAMPLE(colorlist[i]); + /* Compute (square of) distance from minc0/c1/c2 to this color */ + inc0 = (minc0 - GETJSAMPLE(cinfo->colormap[0][icolor])) * C0_SCALE; + dist0 = inc0*inc0; + inc1 = (minc1 - GETJSAMPLE(cinfo->colormap[1][icolor])) * C1_SCALE; + dist0 += inc1*inc1; + inc2 = (minc2 - GETJSAMPLE(cinfo->colormap[2][icolor])) * C2_SCALE; + dist0 += inc2*inc2; + /* Form the initial difference increments */ + inc0 = inc0 * (2 * STEP_C0) + STEP_C0 * STEP_C0; + inc1 = inc1 * (2 * STEP_C1) + STEP_C1 * STEP_C1; + inc2 = inc2 * (2 * STEP_C2) + STEP_C2 * STEP_C2; + /* Now loop over all cells in box, updating distance per Thomas method */ + bptr = bestdist; + cptr = bestcolor; + xx0 = inc0; + for (ic0 = BOX_C0_ELEMS-1; ic0 >= 0; ic0--) { + dist1 = dist0; + xx1 = inc1; + for (ic1 = BOX_C1_ELEMS-1; ic1 >= 0; ic1--) { + dist2 = dist1; + xx2 = inc2; + for (ic2 = BOX_C2_ELEMS-1; ic2 >= 0; ic2--) { + if (dist2 < *bptr) { + *bptr = dist2; + *cptr = (JSAMPLE) icolor; + } + dist2 += xx2; + xx2 += 2 * STEP_C2 * STEP_C2; + bptr++; + cptr++; + } + dist1 += xx1; + xx1 += 2 * STEP_C1 * STEP_C1; + } + dist0 += xx0; + xx0 += 2 * STEP_C0 * STEP_C0; + } + } +} + + +static void +fill_inverse_cmap (j_decompress_ptr cinfo, int c0, int c1, int c2) +/* Fill the inverse-colormap entries in the update box that contains */ +/* histogram cell c0/c1/c2. (Only that one cell MUST be filled, but */ +/* we can fill as many others as we wish.) */ +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + hist3d histogram = cquantize->histogram; + int minc0, minc1, minc2; /* lower left corner of update box */ + int ic0, ic1, ic2; + register JSAMPLE * cptr; /* pointer into bestcolor[] array */ + register histptr cachep; /* pointer into main cache array */ + /* This array lists the candidate colormap indexes. */ + JSAMPLE colorlist[MAXNUMCOLORS]; + int numcolors; /* number of candidate colors */ + /* This array holds the actually closest colormap index for each cell. */ + JSAMPLE bestcolor[BOX_C0_ELEMS * BOX_C1_ELEMS * BOX_C2_ELEMS]; + + /* Convert cell coordinates to update box ID */ + c0 >>= BOX_C0_LOG; + c1 >>= BOX_C1_LOG; + c2 >>= BOX_C2_LOG; + + /* Compute true coordinates of update box's origin corner. + * Actually we compute the coordinates of the center of the corner + * histogram cell, which are the lower bounds of the volume we care about. + */ + minc0 = (c0 << BOX_C0_SHIFT) + ((1 << C0_SHIFT) >> 1); + minc1 = (c1 << BOX_C1_SHIFT) + ((1 << C1_SHIFT) >> 1); + minc2 = (c2 << BOX_C2_SHIFT) + ((1 << C2_SHIFT) >> 1); + + /* Determine which colormap entries are close enough to be candidates + * for the nearest entry to some cell in the update box. + */ + numcolors = find_nearby_colors(cinfo, minc0, minc1, minc2, colorlist); + + /* Determine the actually nearest colors. */ + find_best_colors(cinfo, minc0, minc1, minc2, numcolors, colorlist, + bestcolor); + + /* Save the best color numbers (plus 1) in the main cache array */ + c0 <<= BOX_C0_LOG; /* convert ID back to base cell indexes */ + c1 <<= BOX_C1_LOG; + c2 <<= BOX_C2_LOG; + cptr = bestcolor; + for (ic0 = 0; ic0 < BOX_C0_ELEMS; ic0++) { + for (ic1 = 0; ic1 < BOX_C1_ELEMS; ic1++) { + cachep = & histogram[c0+ic0][c1+ic1][c2]; + for (ic2 = 0; ic2 < BOX_C2_ELEMS; ic2++) { + *cachep++ = (histcell) (GETJSAMPLE(*cptr++) + 1); + } + } + } +} + + +/* + * Map some rows of pixels to the output colormapped representation. + */ + +void +pass2_no_dither (j_decompress_ptr cinfo, + JSAMPARRAY input_buf, JSAMPARRAY output_buf, int num_rows) +/* This version performs no dithering */ +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + hist3d histogram = cquantize->histogram; + register JSAMPROW inptr, outptr; + register histptr cachep; + register int c0, c1, c2; + int row; + JDIMENSION col; + JDIMENSION width = cinfo->output_width; + + for (row = 0; row < num_rows; row++) { + inptr = input_buf[row]; + outptr = output_buf[row]; + for (col = width; col > 0; col--) { + /* get pixel value and index into the cache */ + c0 = GETJSAMPLE(*inptr++) >> C0_SHIFT; + c1 = GETJSAMPLE(*inptr++) >> C1_SHIFT; + c2 = GETJSAMPLE(*inptr++) >> C2_SHIFT; + cachep = & histogram[c0][c1][c2]; + /* If we have not seen this color before, find nearest colormap entry */ + /* and update the cache */ + if (*cachep == 0) + fill_inverse_cmap(cinfo, c0,c1,c2); + /* Now emit the colormap index for this cell */ + *outptr++ = (JSAMPLE) (*cachep - 1); + } + } +} + + +void +pass2_fs_dither (j_decompress_ptr cinfo, + JSAMPARRAY input_buf, JSAMPARRAY output_buf, int num_rows) +/* This version performs Floyd-Steinberg dithering */ +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + hist3d histogram = cquantize->histogram; + register LOCFSERROR cur0, cur1, cur2; /* current error or pixel value */ + LOCFSERROR belowerr0, belowerr1, belowerr2; /* error for pixel below cur */ + LOCFSERROR bpreverr0, bpreverr1, bpreverr2; /* error for below/prev col */ + register FSERRPTR errorptr; /* => fserrors[] at column before current */ + JSAMPROW inptr; /* => current input pixel */ + JSAMPROW outptr; /* => current output pixel */ + histptr cachep; + int dir; /* +1 or -1 depending on direction */ + int dir3; /* 3*dir, for advancing inptr & errorptr */ + int row; + JDIMENSION col; + JDIMENSION width = cinfo->output_width; + JSAMPLE *range_limit = cinfo->sample_range_limit; + int *error_limit = cquantize->error_limiter; + JSAMPROW colormap0 = cinfo->colormap[0]; + JSAMPROW colormap1 = cinfo->colormap[1]; + JSAMPROW colormap2 = cinfo->colormap[2]; + + + for (row = 0; row < num_rows; row++) { + inptr = input_buf[row]; + outptr = output_buf[row]; + if (cquantize->on_odd_row) { + /* work right to left in this row */ + inptr += (width-1) * 3; /* so point to rightmost pixel */ + outptr += width-1; + dir = -1; + dir3 = -3; + errorptr = cquantize->fserrors + (width+1)*3; /* => entry after last column */ + cquantize->on_odd_row = false; /* flip for next time */ + } else { + /* work left to right in this row */ + dir = 1; + dir3 = 3; + errorptr = cquantize->fserrors; /* => entry before first real column */ + cquantize->on_odd_row = true; /* flip for next time */ + } + /* Preset error values: no error propagated to first pixel from left */ + cur0 = cur1 = cur2 = 0; + /* and no error propagated to row below yet */ + belowerr0 = belowerr1 = belowerr2 = 0; + bpreverr0 = bpreverr1 = bpreverr2 = 0; + + for (col = width; col > 0; col--) { + /* curN holds the error propagated from the previous pixel on the + * current line. Add the error propagated from the previous line + * to form the complete error correction term for this pixel, and + * round the error term (which is expressed * 16) to an integer. + * RIGHT_SHIFT rounds towards minus infinity, so adding 8 is correct + * for either sign of the error value. + * Note: errorptr points to *previous* column's array entry. + */ + cur0 = RIGHT_SHIFT(cur0 + errorptr[dir3+0] + 8, 4); + cur1 = RIGHT_SHIFT(cur1 + errorptr[dir3+1] + 8, 4); + cur2 = RIGHT_SHIFT(cur2 + errorptr[dir3+2] + 8, 4); + /* Limit the error using transfer function set by init_error_limit. + * See comments with init_error_limit for rationale. + */ + cur0 = error_limit[cur0]; + cur1 = error_limit[cur1]; + cur2 = error_limit[cur2]; + /* Form pixel value + error, and range-limit to 0..MAXJSAMPLE. + * The maximum error is +- MAXJSAMPLE (or less with error limiting); + * this sets the required size of the range_limit array. + */ + cur0 += GETJSAMPLE(inptr[0]); + cur1 += GETJSAMPLE(inptr[1]); + cur2 += GETJSAMPLE(inptr[2]); + cur0 = GETJSAMPLE(range_limit[cur0]); + cur1 = GETJSAMPLE(range_limit[cur1]); + cur2 = GETJSAMPLE(range_limit[cur2]); + /* Index into the cache with adjusted pixel value */ + cachep = & histogram[cur0>>C0_SHIFT][cur1>>C1_SHIFT][cur2>>C2_SHIFT]; + /* If we have not seen this color before, find nearest colormap */ + /* entry and update the cache */ + if (*cachep == 0) + fill_inverse_cmap(cinfo, cur0>>C0_SHIFT,cur1>>C1_SHIFT,cur2>>C2_SHIFT); + /* Now emit the colormap index for this cell */ + { register int pixcode = *cachep - 1; + *outptr = (JSAMPLE) pixcode; + /* Compute representation error for this pixel */ + cur0 -= GETJSAMPLE(colormap0[pixcode]); + cur1 -= GETJSAMPLE(colormap1[pixcode]); + cur2 -= GETJSAMPLE(colormap2[pixcode]); + } + /* Compute error fractions to be propagated to adjacent pixels. + * Add these into the running sums, and simultaneously shift the + * next-line error sums left by 1 column. + */ + { register LOCFSERROR bnexterr, delta; + + bnexterr = cur0; /* Process component 0 */ + delta = cur0 * 2; + cur0 += delta; /* form error * 3 */ + errorptr[0] = (FSERROR) (bpreverr0 + cur0); + cur0 += delta; /* form error * 5 */ + bpreverr0 = belowerr0 + cur0; + belowerr0 = bnexterr; + cur0 += delta; /* form error * 7 */ + bnexterr = cur1; /* Process component 1 */ + delta = cur1 * 2; + cur1 += delta; /* form error * 3 */ + errorptr[1] = (FSERROR) (bpreverr1 + cur1); + cur1 += delta; /* form error * 5 */ + bpreverr1 = belowerr1 + cur1; + belowerr1 = bnexterr; + cur1 += delta; /* form error * 7 */ + bnexterr = cur2; /* Process component 2 */ + delta = cur2 * 2; + cur2 += delta; /* form error * 3 */ + errorptr[2] = (FSERROR) (bpreverr2 + cur2); + cur2 += delta; /* form error * 5 */ + bpreverr2 = belowerr2 + cur2; + belowerr2 = bnexterr; + cur2 += delta; /* form error * 7 */ + } + /* At this point curN contains the 7/16 error value to be propagated + * to the next pixel on the current line, and all the errors for the + * next line have been shifted over. We are therefore ready to move on. + */ + inptr += dir3; /* Advance pixel pointers to next column */ + outptr += dir; + errorptr += dir3; /* advance errorptr to current column */ + } + /* Post-loop cleanup: we must unload the final error values into the + * final fserrors[] entry. Note we need not unload belowerrN because + * it is for the dummy column before or after the actual array. + */ + errorptr[0] = (FSERROR) bpreverr0; /* unload prev errs into array */ + errorptr[1] = (FSERROR) bpreverr1; + errorptr[2] = (FSERROR) bpreverr2; + } +} + + +/* + * Initialize the error-limiting transfer function (lookup table). + * The raw F-S error computation can potentially compute error values of up to + * +- MAXJSAMPLE. But we want the maximum correction applied to a pixel to be + * much less, otherwise obviously wrong pixels will be created. (Typical + * effects include weird fringes at color-area boundaries, isolated bright + * pixels in a dark area, etc.) The standard advice for avoiding this problem + * is to ensure that the "corners" of the color cube are allocated as output + * colors; then repeated errors in the same direction cannot cause cascading + * error buildup. However, that only prevents the error from getting + * completely out of hand; Aaron Giles reports that error limiting improves + * the results even with corner colors allocated. + * A simple clamping of the error values to about +- MAXJSAMPLE/8 works pretty + * well, but the smoother transfer function used below is even better. Thanks + * to Aaron Giles for this idea. + */ + +static void +init_error_limit (j_decompress_ptr cinfo) +/* Allocate and fill in the error_limiter table */ +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + int * table; + int in, out; + + table = (int *) malloc((MAXJSAMPLE*2+1) * sizeof(int)); + table += MAXJSAMPLE; /* so can index -MAXJSAMPLE .. +MAXJSAMPLE */ + cquantize->error_limiter = table; + +#define STEPSIZE ((MAXJSAMPLE+1)/16) + /* Map errors 1:1 up to +- MAXJSAMPLE/16 */ + out = 0; + for (in = 0; in < STEPSIZE; in++, out++) { + table[in] = out; table[-in] = -out; + } + /* Map errors 1:2 up to +- 3*MAXJSAMPLE/16 */ + for (; in < STEPSIZE*3; in++, out += (in&1) ? 0 : 1) { + table[in] = out; table[-in] = -out; + } + /* Clamp the rest to final out value (which is (MAXJSAMPLE+1)/8) */ + for (; in <= MAXJSAMPLE; in++) { + table[in] = out; table[-in] = -out; + } +#undef STEPSIZE +} + + +/* + * Finish up at the end of each pass. + */ + +void +finish_pass1 (j_decompress_ptr cinfo) +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + + /* Select the representative colors and fill in cinfo->colormap */ + cinfo->colormap = cquantize->sv_colormap; + select_colors(cinfo, cquantize->desired); + /* Force next pass to zero the color index table */ + cquantize->needs_zeroed = true; +} + + +void +finish_pass2 (j_decompress_ptr WXUNUSED(cinfo)) +{ + /* no work */ +} + + +/* + * Initialize for each processing pass. + */ + +void +start_pass_2_quant (j_decompress_ptr cinfo, bool is_pre_scan) +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + hist3d histogram = cquantize->histogram; + + if (is_pre_scan) { + /* Set up method pointers */ + cquantize->pub.color_quantize = prescan_quantize; + cquantize->pub.finish_pass = finish_pass1; + cquantize->needs_zeroed = true; /* Always zero histogram */ + } else { + /* Set up method pointers */ + cquantize->pub.color_quantize = pass2_fs_dither; + cquantize->pub.finish_pass = finish_pass2; + + { + size_t arraysize = (size_t) ((cinfo->output_width + 2) * + (3 * sizeof(FSERROR))); + /* Allocate Floyd-Steinberg workspace if we didn't already. */ + if (cquantize->fserrors == NULL) + cquantize->fserrors = (INT16*) malloc(arraysize); + /* Initialize the propagated errors to zero. */ + memset((void *) cquantize->fserrors, 0, arraysize); + /* Make the error-limit table if we didn't already. */ + if (cquantize->error_limiter == NULL) + init_error_limit(cinfo); + cquantize->on_odd_row = false; + } + + } + /* Zero the histogram or inverse color map, if necessary */ + if (cquantize->needs_zeroed) { + for (int i = 0; i < HIST_C0_ELEMS; i++) { + memset((void *) histogram[i], 0, + HIST_C1_ELEMS*HIST_C2_ELEMS * sizeof(histcell)); + } + cquantize->needs_zeroed = false; + } +} + + +/* + * Switch to a new external colormap between output passes. + */ + +void +new_color_map_2_quant (j_decompress_ptr cinfo) +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + + /* Reset the inverse color map */ + cquantize->needs_zeroed = true; +} + + +/* + * Module initialization routine for 2-pass color quantization. + */ + +void +jinit_2pass_quantizer (j_decompress_ptr cinfo) +{ + my_cquantize_ptr cquantize; + int i; + + cquantize = (my_cquantize_ptr) malloc(sizeof(my_cquantizer)); + cinfo->cquantize = (jpeg_color_quantizer *) cquantize; + cquantize->pub.start_pass = start_pass_2_quant; + cquantize->pub.new_color_map = new_color_map_2_quant; + cquantize->fserrors = NULL; /* flag optional arrays not allocated */ + cquantize->error_limiter = NULL; + + + /* Allocate the histogram/inverse colormap storage */ + cquantize->histogram = (hist3d) malloc(HIST_C0_ELEMS * sizeof(hist2d)); + for (i = 0; i < HIST_C0_ELEMS; i++) { + cquantize->histogram[i] = (hist2d) malloc(HIST_C1_ELEMS*HIST_C2_ELEMS * sizeof(histcell)); + } + cquantize->needs_zeroed = true; /* histogram is garbage now */ + + /* Allocate storage for the completed colormap, if required. + * We do this now since it is storage and may affect + * the memory manager's space calculations. + */ + { + /* Make sure color count is acceptable */ + int desired = cinfo->desired_number_of_colors; + + cquantize->sv_colormap = (JSAMPARRAY) malloc(sizeof(JSAMPROW) * 3); + cquantize->sv_colormap[0] = (JSAMPROW) malloc(sizeof(JSAMPLE) * desired); + cquantize->sv_colormap[1] = (JSAMPROW) malloc(sizeof(JSAMPLE) * desired); + cquantize->sv_colormap[2] = (JSAMPROW) malloc(sizeof(JSAMPLE) * desired); + + cquantize->desired = desired; + } + + /* Allocate Floyd-Steinberg workspace if necessary. + * This isn't really needed until pass 2, but again it is storage. + * Although we will cope with a later change in dither_mode, + * we do not promise to honor max_memory_to_use if dither_mode changes. + */ + { + cquantize->fserrors = (FSERRPTR) malloc( + (size_t) ((cinfo->output_width + 2) * (3 * sizeof(FSERROR)))); + /* Might as well create the error-limiting table too. */ + init_error_limit(cinfo); + } +} + + + + + + + + + + +void +prepare_range_limit_table (j_decompress_ptr cinfo) +/* Allocate and fill in the sample_range_limit table */ +{ + JSAMPLE * table; + int i; + + table = (JSAMPLE *) malloc((5 * (MAXJSAMPLE+1) + CENTERJSAMPLE) * sizeof(JSAMPLE)); + cinfo->srl_orig = table; + table += (MAXJSAMPLE+1); /* allow negative subscripts of simple table */ + cinfo->sample_range_limit = table; + /* First segment of "simple" table: limit[x] = 0 for x < 0 */ + memset(table - (MAXJSAMPLE+1), 0, (MAXJSAMPLE+1) * sizeof(JSAMPLE)); + /* Main part of "simple" table: limit[x] = x */ + for (i = 0; i <= MAXJSAMPLE; i++) + table[i] = (JSAMPLE) i; + table += CENTERJSAMPLE; /* Point to where post-IDCT table starts */ + /* End of simple table, rest of first half of post-IDCT table */ + for (i = CENTERJSAMPLE; i < 2*(MAXJSAMPLE+1); i++) + table[i] = MAXJSAMPLE; + /* Second half of post-IDCT table */ + memset(table + (2 * (MAXJSAMPLE+1)), 0, + (2 * (MAXJSAMPLE+1) - CENTERJSAMPLE) * sizeof(JSAMPLE)); + memcpy(table + (4 * (MAXJSAMPLE+1) - CENTERJSAMPLE), + cinfo->sample_range_limit, CENTERJSAMPLE * sizeof(JSAMPLE)); +} + + + + +/* + * wxQuantize + */ + +IMPLEMENT_DYNAMIC_CLASS(wxQuantize, wxObject) + +void wxQuantize::DoQuantize(unsigned w, unsigned h, unsigned char **in_rows, unsigned char **out_rows, + unsigned char *palette, int desiredNoColours) +{ + j_decompress dec; + my_cquantize_ptr cquantize; + + dec.output_width = w; + dec.desired_number_of_colors = desiredNoColours; + prepare_range_limit_table(&dec); + jinit_2pass_quantizer(&dec); + cquantize = (my_cquantize_ptr) dec.cquantize; + + + cquantize->pub.start_pass(&dec, true); + cquantize->pub.color_quantize(&dec, in_rows, out_rows, h); + cquantize->pub.finish_pass(&dec); + + cquantize->pub.start_pass(&dec, false); + cquantize->pub.color_quantize(&dec, in_rows, out_rows, h); + cquantize->pub.finish_pass(&dec); + + + for (int i = 0; i < dec.desired_number_of_colors; i++) { + palette[3 * i + 0] = dec.colormap[0][i]; + palette[3 * i + 1] = dec.colormap[1][i]; + palette[3 * i + 2] = dec.colormap[2][i]; + } + + for (int ii = 0; ii < HIST_C0_ELEMS; ii++) free(cquantize->histogram[ii]); + free(cquantize->histogram); + free(dec.colormap[0]); + free(dec.colormap[1]); + free(dec.colormap[2]); + free(dec.colormap); + free(dec.srl_orig); + + //free(cquantize->error_limiter); + free((void*)(cquantize->error_limiter - MAXJSAMPLE)); // To reverse what was done to it + + free(cquantize->fserrors); + free(cquantize); +} + +// TODO: somehow make use of the Windows system colours, rather than ignoring them for the +// purposes of quantization. + +bool wxQuantize::Quantize(const wxImage& src, wxImage& dest, + wxPalette** pPalette, + int desiredNoColours, + unsigned char** eightBitData, + int flags) + +{ + int i; + + int windowsSystemColourCount = 20; + + int paletteShift = 0; + + // Shift the palette up by the number of Windows system colours, + // if necessary + if (flags & wxQUANTIZE_INCLUDE_WINDOWS_COLOURS) + paletteShift = windowsSystemColourCount; + + // Make room for the Windows system colours +#ifdef __WXMSW__ + if ((flags & wxQUANTIZE_INCLUDE_WINDOWS_COLOURS) && (desiredNoColours > (256 - windowsSystemColourCount))) + desiredNoColours = 256 - windowsSystemColourCount; +#endif + + // create rows info: + int h = src.GetHeight(); + int w = src.GetWidth(); + unsigned char **rows = new unsigned char *[h]; + unsigned char *imgdt = src.GetData(); + for (i = 0; i < h; i++) + rows[i] = imgdt + 3/*RGB*/ * w * i; + + unsigned char palette[3*256]; + + // This is the image as represented by palette indexes. + unsigned char *data8bit = new unsigned char[w * h]; + unsigned char **outrows = new unsigned char *[h]; + for (i = 0; i < h; i++) + outrows[i] = data8bit + w * i; + + //RGB->palette + DoQuantize(w, h, rows, outrows, palette, desiredNoColours); + + delete[] rows; + delete[] outrows; + + // palette->RGB(max.256) + + if (flags & wxQUANTIZE_FILL_DESTINATION_IMAGE) + { + if (!dest.Ok()) + dest.Create(w, h); + + imgdt = dest.GetData(); + for (i = 0; i < w * h; i++) + { + unsigned char c = data8bit[i]; + imgdt[3 * i + 0/*R*/] = palette[3 * c + 0]; + imgdt[3 * i + 1/*G*/] = palette[3 * c + 1]; + imgdt[3 * i + 2/*B*/] = palette[3 * c + 2]; + } + } + + if (eightBitData && (flags & wxQUANTIZE_RETURN_8BIT_DATA)) + { +#ifdef __WXMSW__ + if (flags & wxQUANTIZE_INCLUDE_WINDOWS_COLOURS) + { + // We need to shift the palette entries up + // to make room for the Windows system colours. + for (i = 0; i < w * h; i++) + data8bit[i] = (unsigned char)(data8bit[i] + paletteShift); + } +#endif + *eightBitData = data8bit; + } + else + delete[] data8bit; + +#if wxUSE_PALETTE + // Make a wxWidgets palette + if (pPalette) + { + unsigned char* r = new unsigned char[256]; + unsigned char* g = new unsigned char[256]; + unsigned char* b = new unsigned char[256]; + +#ifdef __WXMSW__ + // Fill the first 20 entries with Windows system colours + if (flags & wxQUANTIZE_INCLUDE_WINDOWS_COLOURS) + { + HDC hDC = ::GetDC(NULL); + PALETTEENTRY* entries = new PALETTEENTRY[windowsSystemColourCount]; + ::GetSystemPaletteEntries(hDC, 0, windowsSystemColourCount, entries); + ::ReleaseDC(NULL, hDC); + + for (i = 0; i < windowsSystemColourCount; i++) + { + r[i] = entries[i].peRed; + g[i] = entries[i].peGreen; + b[i] = entries[i].peBlue; + } + delete[] entries; + } +#endif + + for (i = 0; i < desiredNoColours; i++) + { + r[i+paletteShift] = palette[i*3 + 0]; + g[i+paletteShift] = palette[i*3 + 1]; + b[i+paletteShift] = palette[i*3 + 2]; + } + + // Blank out any remaining palette entries + for (i = desiredNoColours+paletteShift; i < 256; i++) + { + r[i] = 0; + g[i] = 0; + b[i] = 0; + } + *pPalette = new wxPalette(256, r, g, b); + delete[] r; + delete[] g; + delete[] b; + } +#endif // wxUSE_PALETTE + + return true; +} + +// This version sets a palette in the destination image so you don't +// have to manage it yourself. + +bool wxQuantize::Quantize(const wxImage& src, + wxImage& dest, + int desiredNoColours, + unsigned char** eightBitData, + int flags) +{ + wxPalette* palette = NULL; + if ( !Quantize(src, dest, & palette, desiredNoColours, eightBitData, flags) ) + return false; + +#if wxUSE_PALETTE + if (palette) + { + dest.SetPalette(* palette); + delete palette; + } +#endif // wxUSE_PALETTE + + return true; +} + +#endif + // wxUSE_IMAGE diff --git a/Externals/wxWidgets/src/common/radiocmn.cpp b/Externals/wxWidgets/src/common/radiocmn.cpp index fe26b79537..79c2a52c9c 100644 --- a/Externals/wxWidgets/src/common/radiocmn.cpp +++ b/Externals/wxWidgets/src/common/radiocmn.cpp @@ -1,294 +1,294 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: src/common/radiocmn.cpp -// Purpose: wxRadioBox methods common to all ports -// Author: Vadim Zeitlin -// Modified by: -// Created: 03.06.01 -// RCS-ID: $Id: radiocmn.cpp 39676 2006-06-11 21:13:13Z VZ $ -// Copyright: (c) 2001 Vadim Zeitlin -// License: wxWindows licence -/////////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_RADIOBOX - -#ifndef WX_PRECOMP - #include "wx/radiobox.h" -#endif //WX_PRECOMP - -#if wxUSE_TOOLTIPS - #include "wx/tooltip.h" -#endif // wxUSE_TOOLTIPS - -#if wxUSE_HELP - #include "wx/cshelp.h" -#endif - -// ============================================================================ -// implementation -// ============================================================================ - -void wxRadioBoxBase::SetMajorDim(unsigned int majorDim, long style) -{ - wxCHECK_RET( majorDim != 0, _T("major radiobox dimension can't be 0") ); - - m_majorDim = majorDim; - - int minorDim = (GetCount() + m_majorDim - 1) / m_majorDim; - - if ( style & wxRA_SPECIFY_COLS ) - { - m_numCols = majorDim; - m_numRows = minorDim; - } - else // wxRA_SPECIFY_ROWS - { - m_numCols = minorDim; - m_numRows = majorDim; - } -} - -int wxRadioBoxBase::GetNextItem(int item, wxDirection dir, long style) const -{ - int count = GetCount(), - numCols = GetColumnCount(), - numRows = GetRowCount(); - - bool horz = (style & wxRA_SPECIFY_COLS) != 0; - - switch ( dir ) - { - case wxUP: - if ( horz ) - { - item -= numCols; - } - else // vertical layout - { - if ( !item-- ) - item = count - 1; - } - break; - - case wxLEFT: - if ( horz ) - { - if ( !item-- ) - item = count - 1; - } - else // vertical layout - { - item -= numRows; - } - break; - - case wxDOWN: - if ( horz ) - { - item += numCols; - } - else // vertical layout - { - if ( ++item == count ) - item = 0; - } - break; - - case wxRIGHT: - if ( horz ) - { - if ( ++item == count ) - item = 0; - } - else // vertical layout - { - item += numRows; - } - break; - - default: - wxFAIL_MSG( _T("unexpected wxDirection value") ); - return wxNOT_FOUND; - } - - // ensure that the item is in range [0..count) - if ( item < 0 ) - { - // first map the item to the one in the same column but in the last row - item += count; - - // now there are 2 cases: either it is the first item of the last row - // in which case we need to wrap again and get to the last item or we - // can just go to the previous item - if ( item % (horz ? numCols : numRows) ) - item--; - else - item = count - 1; - } - else if ( item >= count ) - { - // same logic as above - item -= count; - - // ... except that we need to check if this is not the last item, not - // the first one - if ( (item + 1) % (horz ? numCols : numRows) ) - item++; - else - item = 0; - } - - wxASSERT_MSG( item < count && item >= 0, - _T("logic error in wxRadioBox::GetNextItem()") ); - - return item; -} - -#if wxUSE_TOOLTIPS - -void wxRadioBoxBase::SetItemToolTip(unsigned int item, const wxString& text) -{ - wxASSERT_MSG( item < GetCount(), _T("Invalid item index") ); - - // extend the array to have entries for all our items on first use - if ( !m_itemsTooltips ) - { - m_itemsTooltips = new wxToolTipArray; - m_itemsTooltips->resize(GetCount()); - } - - wxToolTip *tooltip = (*m_itemsTooltips)[item]; - - bool changed = true; - if ( text.empty() ) - { - if ( tooltip ) - { - // delete the tooltip - delete tooltip; - tooltip = NULL; - } - else // nothing to do - { - changed = false; - } - } - else // non empty tooltip text - { - if ( tooltip ) - { - // just change the existing tooltip text, don't change the tooltip - tooltip->SetTip(text); - changed = false; - } - else // no tooltip yet - { - // create the new one - tooltip = new wxToolTip(text); - } - } - - if ( changed ) - { - (*m_itemsTooltips)[item] = tooltip; - DoSetItemToolTip(item, tooltip); - } -} - -void -wxRadioBoxBase::DoSetItemToolTip(unsigned int WXUNUSED(item), - wxToolTip * WXUNUSED(tooltip)) -{ - // per-item tooltips not implemented by default -} - -#endif // wxUSE_TOOLTIPS - -wxRadioBoxBase::~wxRadioBoxBase() -{ -#if wxUSE_TOOLTIPS - if ( m_itemsTooltips ) - { - const size_t n = m_itemsTooltips->size(); - for ( size_t i = 0; i < n; i++ ) - delete (*m_itemsTooltips)[i]; - - delete m_itemsTooltips; - } -#endif // wxUSE_TOOLTIPS -} - -#if wxUSE_HELP - -// set helptext for a particular item -void wxRadioBoxBase::SetItemHelpText(unsigned int n, const wxString& helpText) -{ - wxCHECK_RET( n < GetCount(), _T("Invalid item index") ); - - if ( m_itemsHelpTexts.empty() ) - { - // once-only initialization of the array: reserve space for all items - m_itemsHelpTexts.Add(wxEmptyString, GetCount()); - } - - m_itemsHelpTexts[n] = helpText; -} - -// retrieve helptext for a particular item -wxString wxRadioBoxBase::GetItemHelpText( unsigned int n ) const -{ - wxCHECK_MSG( n < GetCount(), wxEmptyString, _T("Invalid item index") ); - - return m_itemsHelpTexts.empty() ? wxString() : m_itemsHelpTexts[n]; -} - -// return help text for the item for which wxEVT_HELP was generated. -wxString wxRadioBoxBase::DoGetHelpTextAtPoint(const wxWindow *derived, - const wxPoint& pt, - wxHelpEvent::Origin origin) const -{ - const int item = origin == wxHelpEvent::Origin_HelpButton - ? GetItemFromPoint(pt) - : GetSelection(); - - if ( item != wxNOT_FOUND ) - { - wxString text = GetItemHelpText(wx_static_cast(unsigned int, item)); - if( !text.empty() ) - return text; - } - - return derived->wxWindowBase::GetHelpTextAtPoint(pt, origin); -} - -#endif // wxUSE_HELP - -#if WXWIN_COMPATIBILITY_2_4 - -// these functions are deprecated and don't do anything -int wxRadioBoxBase::GetNumberOfRowsOrCols() const -{ - return 1; -} - -void wxRadioBoxBase::SetNumberOfRowsOrCols(int WXUNUSED(n)) -{ -} - -#endif // WXWIN_COMPATIBILITY_2_4 - -#endif // wxUSE_RADIOBOX +/////////////////////////////////////////////////////////////////////////////// +// Name: src/common/radiocmn.cpp +// Purpose: wxRadioBox methods common to all ports +// Author: Vadim Zeitlin +// Modified by: +// Created: 03.06.01 +// RCS-ID: $Id: radiocmn.cpp 39676 2006-06-11 21:13:13Z VZ $ +// Copyright: (c) 2001 Vadim Zeitlin +// License: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_RADIOBOX + +#ifndef WX_PRECOMP + #include "wx/radiobox.h" +#endif //WX_PRECOMP + +#if wxUSE_TOOLTIPS + #include "wx/tooltip.h" +#endif // wxUSE_TOOLTIPS + +#if wxUSE_HELP + #include "wx/cshelp.h" +#endif + +// ============================================================================ +// implementation +// ============================================================================ + +void wxRadioBoxBase::SetMajorDim(unsigned int majorDim, long style) +{ + wxCHECK_RET( majorDim != 0, _T("major radiobox dimension can't be 0") ); + + m_majorDim = majorDim; + + int minorDim = (GetCount() + m_majorDim - 1) / m_majorDim; + + if ( style & wxRA_SPECIFY_COLS ) + { + m_numCols = majorDim; + m_numRows = minorDim; + } + else // wxRA_SPECIFY_ROWS + { + m_numCols = minorDim; + m_numRows = majorDim; + } +} + +int wxRadioBoxBase::GetNextItem(int item, wxDirection dir, long style) const +{ + int count = GetCount(), + numCols = GetColumnCount(), + numRows = GetRowCount(); + + bool horz = (style & wxRA_SPECIFY_COLS) != 0; + + switch ( dir ) + { + case wxUP: + if ( horz ) + { + item -= numCols; + } + else // vertical layout + { + if ( !item-- ) + item = count - 1; + } + break; + + case wxLEFT: + if ( horz ) + { + if ( !item-- ) + item = count - 1; + } + else // vertical layout + { + item -= numRows; + } + break; + + case wxDOWN: + if ( horz ) + { + item += numCols; + } + else // vertical layout + { + if ( ++item == count ) + item = 0; + } + break; + + case wxRIGHT: + if ( horz ) + { + if ( ++item == count ) + item = 0; + } + else // vertical layout + { + item += numRows; + } + break; + + default: + wxFAIL_MSG( _T("unexpected wxDirection value") ); + return wxNOT_FOUND; + } + + // ensure that the item is in range [0..count) + if ( item < 0 ) + { + // first map the item to the one in the same column but in the last row + item += count; + + // now there are 2 cases: either it is the first item of the last row + // in which case we need to wrap again and get to the last item or we + // can just go to the previous item + if ( item % (horz ? numCols : numRows) ) + item--; + else + item = count - 1; + } + else if ( item >= count ) + { + // same logic as above + item -= count; + + // ... except that we need to check if this is not the last item, not + // the first one + if ( (item + 1) % (horz ? numCols : numRows) ) + item++; + else + item = 0; + } + + wxASSERT_MSG( item < count && item >= 0, + _T("logic error in wxRadioBox::GetNextItem()") ); + + return item; +} + +#if wxUSE_TOOLTIPS + +void wxRadioBoxBase::SetItemToolTip(unsigned int item, const wxString& text) +{ + wxASSERT_MSG( item < GetCount(), _T("Invalid item index") ); + + // extend the array to have entries for all our items on first use + if ( !m_itemsTooltips ) + { + m_itemsTooltips = new wxToolTipArray; + m_itemsTooltips->resize(GetCount()); + } + + wxToolTip *tooltip = (*m_itemsTooltips)[item]; + + bool changed = true; + if ( text.empty() ) + { + if ( tooltip ) + { + // delete the tooltip + delete tooltip; + tooltip = NULL; + } + else // nothing to do + { + changed = false; + } + } + else // non empty tooltip text + { + if ( tooltip ) + { + // just change the existing tooltip text, don't change the tooltip + tooltip->SetTip(text); + changed = false; + } + else // no tooltip yet + { + // create the new one + tooltip = new wxToolTip(text); + } + } + + if ( changed ) + { + (*m_itemsTooltips)[item] = tooltip; + DoSetItemToolTip(item, tooltip); + } +} + +void +wxRadioBoxBase::DoSetItemToolTip(unsigned int WXUNUSED(item), + wxToolTip * WXUNUSED(tooltip)) +{ + // per-item tooltips not implemented by default +} + +#endif // wxUSE_TOOLTIPS + +wxRadioBoxBase::~wxRadioBoxBase() +{ +#if wxUSE_TOOLTIPS + if ( m_itemsTooltips ) + { + const size_t n = m_itemsTooltips->size(); + for ( size_t i = 0; i < n; i++ ) + delete (*m_itemsTooltips)[i]; + + delete m_itemsTooltips; + } +#endif // wxUSE_TOOLTIPS +} + +#if wxUSE_HELP + +// set helptext for a particular item +void wxRadioBoxBase::SetItemHelpText(unsigned int n, const wxString& helpText) +{ + wxCHECK_RET( n < GetCount(), _T("Invalid item index") ); + + if ( m_itemsHelpTexts.empty() ) + { + // once-only initialization of the array: reserve space for all items + m_itemsHelpTexts.Add(wxEmptyString, GetCount()); + } + + m_itemsHelpTexts[n] = helpText; +} + +// retrieve helptext for a particular item +wxString wxRadioBoxBase::GetItemHelpText( unsigned int n ) const +{ + wxCHECK_MSG( n < GetCount(), wxEmptyString, _T("Invalid item index") ); + + return m_itemsHelpTexts.empty() ? wxString() : m_itemsHelpTexts[n]; +} + +// return help text for the item for which wxEVT_HELP was generated. +wxString wxRadioBoxBase::DoGetHelpTextAtPoint(const wxWindow *derived, + const wxPoint& pt, + wxHelpEvent::Origin origin) const +{ + const int item = origin == wxHelpEvent::Origin_HelpButton + ? GetItemFromPoint(pt) + : GetSelection(); + + if ( item != wxNOT_FOUND ) + { + wxString text = GetItemHelpText(wx_static_cast(unsigned int, item)); + if( !text.empty() ) + return text; + } + + return derived->wxWindowBase::GetHelpTextAtPoint(pt, origin); +} + +#endif // wxUSE_HELP + +#if WXWIN_COMPATIBILITY_2_4 + +// these functions are deprecated and don't do anything +int wxRadioBoxBase::GetNumberOfRowsOrCols() const +{ + return 1; +} + +void wxRadioBoxBase::SetNumberOfRowsOrCols(int WXUNUSED(n)) +{ +} + +#endif // WXWIN_COMPATIBILITY_2_4 + +#endif // wxUSE_RADIOBOX diff --git a/Externals/wxWidgets/src/common/regex.cpp b/Externals/wxWidgets/src/common/regex.cpp index 33af348ad5..6591132747 100644 --- a/Externals/wxWidgets/src/common/regex.cpp +++ b/Externals/wxWidgets/src/common/regex.cpp @@ -1,686 +1,686 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: src/common/regex.cpp -// Purpose: regular expression matching -// Author: Karsten Ballueder and Vadim Zeitlin -// Modified by: -// Created: 13.07.01 -// RCS-ID: $Id: regex.cpp 50711 2007-12-15 02:57:58Z VZ $ -// Copyright: (c) 2000 Karsten Ballueder -// 2001 Vadim Zeitlin -// Licence: wxWindows licence -/////////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_REGEX - -#ifndef WX_PRECOMP - #include "wx/object.h" - #include "wx/string.h" - #include "wx/log.h" - #include "wx/intl.h" -#endif //WX_PRECOMP - -// FreeBSD, Watcom and DMars require this, CW doesn't have nor need it. -// Others also don't seem to need it. If you have an error related to -// (not) including please report details to -// wx-dev@lists.wxwindows.org -#if defined(__UNIX__) || defined(__WATCOMC__) || defined(__DIGITALMARS__) -# include -#endif - -#include -#include "wx/regex.h" - -// WXREGEX_USING_BUILTIN defined when using the built-in regex lib -// WXREGEX_USING_RE_SEARCH defined when using re_search in the GNU regex lib -// WXREGEX_IF_NEED_LEN() wrap the len parameter only used with the built-in -// or GNU regex -// WXREGEX_CONVERT_TO_MB defined when the regex lib is using chars and -// wxChar is wide, so conversion must be done -// WXREGEX_CHAR(x) Convert wxChar to wxRegChar -// -#ifdef __REG_NOFRONT -# define WXREGEX_USING_BUILTIN -# define WXREGEX_IF_NEED_LEN(x) ,x -# define WXREGEX_CHAR(x) x -#else -# ifdef HAVE_RE_SEARCH -# define WXREGEX_IF_NEED_LEN(x) ,x -# define WXREGEX_USING_RE_SEARCH -# else -# define WXREGEX_IF_NEED_LEN(x) -# endif -# if wxUSE_UNICODE -# define WXREGEX_CONVERT_TO_MB -# endif -# define WXREGEX_CHAR(x) wxConvertWX2MB(x) -# define wx_regfree regfree -# define wx_regerror regerror -#endif - -// ---------------------------------------------------------------------------- -// private classes -// ---------------------------------------------------------------------------- - -#ifndef WXREGEX_USING_RE_SEARCH - -// the array of offsets for the matches, the usual POSIX regmatch_t array. -class wxRegExMatches -{ -public: - typedef regmatch_t *match_type; - - wxRegExMatches(size_t n) { m_matches = new regmatch_t[n]; } - ~wxRegExMatches() { delete [] m_matches; } - - // we just use casts here because the fields of regmatch_t struct may be 64 - // bit but we're limited to size_t in our public API and are not going to - // change it because operating on strings longer than 4GB using it is - // absolutely impractical anyhow - size_t Start(size_t n) const - { - return wx_truncate_cast(size_t, m_matches[n].rm_so); - } - - size_t End(size_t n) const - { - return wx_truncate_cast(size_t, m_matches[n].rm_eo); - } - - regmatch_t *get() const { return m_matches; } - -private: - regmatch_t *m_matches; -}; - -#else // WXREGEX_USING_RE_SEARCH - -// the array of offsets for the matches, the struct used by the GNU lib -class wxRegExMatches -{ -public: - typedef re_registers *match_type; - - wxRegExMatches(size_t n) - { - m_matches.num_regs = n; - m_matches.start = new regoff_t[n]; - m_matches.end = new regoff_t[n]; - } - - ~wxRegExMatches() - { - delete [] m_matches.start; - delete [] m_matches.end; - } - - size_t Start(size_t n) const { return m_matches.start[n]; } - size_t End(size_t n) const { return m_matches.end[n]; } - - re_registers *get() { return &m_matches; } - -private: - re_registers m_matches; -}; - -#endif // WXREGEX_USING_RE_SEARCH - -// the character type used by the regular expression engine -#ifndef WXREGEX_CONVERT_TO_MB -typedef wxChar wxRegChar; -#else -typedef char wxRegChar; -#endif - -// the real implementation of wxRegEx -class wxRegExImpl -{ -public: - // ctor and dtor - wxRegExImpl(); - ~wxRegExImpl(); - - // return true if Compile() had been called successfully - bool IsValid() const { return m_isCompiled; } - - // RE operations - bool Compile(const wxString& expr, int flags = 0); - bool Matches(const wxRegChar *str, int flags - WXREGEX_IF_NEED_LEN(size_t len)) const; - bool GetMatch(size_t *start, size_t *len, size_t index = 0) const; - size_t GetMatchCount() const; - int Replace(wxString *pattern, const wxString& replacement, - size_t maxMatches = 0) const; - -private: - // return the string containing the error message for the given err code - wxString GetErrorMsg(int errorcode, bool badconv) const; - - // init the members - void Init() - { - m_isCompiled = false; - m_Matches = NULL; - m_nMatches = 0; - } - - // free the RE if compiled - void Free() - { - if ( IsValid() ) - { - wx_regfree(&m_RegEx); - } - - delete m_Matches; - } - - // free the RE if any and reinit the members - void Reinit() - { - Free(); - Init(); - } - - // compiled RE - regex_t m_RegEx; - - // the subexpressions data - wxRegExMatches *m_Matches; - size_t m_nMatches; - - // true if m_RegEx is valid - bool m_isCompiled; -}; - - -// ============================================================================ -// implementation -// ============================================================================ - -// ---------------------------------------------------------------------------- -// wxRegExImpl -// ---------------------------------------------------------------------------- - -wxRegExImpl::wxRegExImpl() -{ - Init(); -} - -wxRegExImpl::~wxRegExImpl() -{ - Free(); -} - -wxString wxRegExImpl::GetErrorMsg(int errorcode, bool badconv) const -{ -#ifdef WXREGEX_CONVERT_TO_MB - // currently only needed when using system library in Unicode mode - if ( badconv ) - { - return _("conversion to 8-bit encoding failed"); - } -#else - // 'use' badconv to avoid a compiler warning - (void)badconv; -#endif - - wxString szError; - - // first get the string length needed - int len = wx_regerror(errorcode, &m_RegEx, NULL, 0); - if ( len > 0 ) - { - char* szcmbError = new char[++len]; - - (void)wx_regerror(errorcode, &m_RegEx, szcmbError, len); - - szError = wxConvertMB2WX(szcmbError); - delete [] szcmbError; - } - else // regerror() returned 0 - { - szError = _("unknown error"); - } - - return szError; -} - -bool wxRegExImpl::Compile(const wxString& expr, int flags) -{ - Reinit(); - -#ifdef WX_NO_REGEX_ADVANCED -# define FLAVORS wxRE_BASIC -#else -# define FLAVORS (wxRE_ADVANCED | wxRE_BASIC) - wxASSERT_MSG( (flags & FLAVORS) != FLAVORS, - _T("incompatible flags in wxRegEx::Compile") ); -#endif - wxASSERT_MSG( !(flags & ~(FLAVORS | wxRE_ICASE | wxRE_NOSUB | wxRE_NEWLINE)), - _T("unrecognized flags in wxRegEx::Compile") ); - - // translate our flags to regcomp() ones - int flagsRE = 0; - if ( !(flags & wxRE_BASIC) ) -#ifndef WX_NO_REGEX_ADVANCED - if (flags & wxRE_ADVANCED) - flagsRE |= REG_ADVANCED; - else -#endif - flagsRE |= REG_EXTENDED; - if ( flags & wxRE_ICASE ) - flagsRE |= REG_ICASE; - if ( flags & wxRE_NOSUB ) - flagsRE |= REG_NOSUB; - if ( flags & wxRE_NEWLINE ) - flagsRE |= REG_NEWLINE; - - // compile it -#ifdef WXREGEX_USING_BUILTIN - bool conv = true; - int errorcode = wx_re_comp(&m_RegEx, expr, expr.length(), flagsRE); -#else - const wxWX2MBbuf conv = expr.mbc_str(); - int errorcode = conv ? regcomp(&m_RegEx, conv, flagsRE) : REG_BADPAT; -#endif - - if ( errorcode ) - { - wxLogError(_("Invalid regular expression '%s': %s"), - expr.c_str(), GetErrorMsg(errorcode, !conv).c_str()); - - m_isCompiled = false; - } - else // ok - { - // don't allocate the matches array now, but do it later if necessary - if ( flags & wxRE_NOSUB ) - { - // we don't need it at all - m_nMatches = 0; - } - else - { - // we will alloc the array later (only if really needed) but count - // the number of sub-expressions in the regex right now - - // there is always one for the whole expression - m_nMatches = 1; - - // and some more for bracketed subexperessions - for ( const wxChar *cptr = expr.c_str(); *cptr; cptr++ ) - { - if ( *cptr == _T('\\') ) - { - // in basic RE syntax groups are inside \(...\) - if ( *++cptr == _T('(') && (flags & wxRE_BASIC) ) - { - m_nMatches++; - } - } - else if ( *cptr == _T('(') && !(flags & wxRE_BASIC) ) - { - // we know that the previous character is not an unquoted - // backslash because it would have been eaten above, so we - // have a bare '(' and this indicates a group start for the - // extended syntax. '(?' is used for extensions by perl- - // like REs (e.g. advanced), and is not valid for POSIX - // extended, so ignore them always. - if ( cptr[1] != _T('?') ) - m_nMatches++; - } - } - } - - m_isCompiled = true; - } - - return IsValid(); -} - -#ifdef WXREGEX_USING_RE_SEARCH - -// On GNU, regexec is implemented as a wrapper around re_search. re_search -// requires a length parameter which the POSIX regexec does not have, -// therefore regexec must do a strlen on the search text each time it is -// called. This can drastically affect performance when matching is done in -// a loop along a string, such as during a search and replace. Therefore if -// re_search is detected by configure, it is used directly. -// -static int ReSearch(const regex_t *preg, - const char *text, - size_t len, - re_registers *matches, - int eflags) -{ - regex_t *pattern = wx_const_cast(regex_t*, preg); - - pattern->not_bol = (eflags & REG_NOTBOL) != 0; - pattern->not_eol = (eflags & REG_NOTEOL) != 0; - pattern->regs_allocated = REGS_FIXED; - - int ret = re_search(pattern, text, len, 0, len, matches); - return ret >= 0 ? 0 : REG_NOMATCH; -} - -#endif // WXREGEX_USING_RE_SEARCH - -bool wxRegExImpl::Matches(const wxRegChar *str, - int flags - WXREGEX_IF_NEED_LEN(size_t len)) const -{ - wxCHECK_MSG( IsValid(), false, _T("must successfully Compile() first") ); - - // translate our flags to regexec() ones - wxASSERT_MSG( !(flags & ~(wxRE_NOTBOL | wxRE_NOTEOL)), - _T("unrecognized flags in wxRegEx::Matches") ); - - int flagsRE = 0; - if ( flags & wxRE_NOTBOL ) - flagsRE |= REG_NOTBOL; - if ( flags & wxRE_NOTEOL ) - flagsRE |= REG_NOTEOL; - - // allocate matches array if needed - wxRegExImpl *self = wxConstCast(this, wxRegExImpl); - if ( !m_Matches && m_nMatches ) - { - self->m_Matches = new wxRegExMatches(m_nMatches); - } - - wxRegExMatches::match_type matches = m_Matches ? m_Matches->get() : NULL; - - // do match it -#if defined WXREGEX_USING_BUILTIN - int rc = wx_re_exec(&self->m_RegEx, str, len, NULL, m_nMatches, matches, flagsRE); -#elif defined WXREGEX_USING_RE_SEARCH - int rc = str ? ReSearch(&self->m_RegEx, str, len, matches, flagsRE) : REG_BADPAT; -#else - int rc = str ? regexec(&self->m_RegEx, str, m_nMatches, matches, flagsRE) : REG_BADPAT; -#endif - - switch ( rc ) - { - case 0: - // matched successfully - return true; - - default: - // an error occurred - wxLogError(_("Failed to find match for regular expression: %s"), - GetErrorMsg(rc, !str).c_str()); - // fall through - - case REG_NOMATCH: - // no match - return false; - } -} - -bool wxRegExImpl::GetMatch(size_t *start, size_t *len, size_t index) const -{ - wxCHECK_MSG( IsValid(), false, _T("must successfully Compile() first") ); - wxCHECK_MSG( m_nMatches, false, _T("can't use with wxRE_NOSUB") ); - wxCHECK_MSG( m_Matches, false, _T("must call Matches() first") ); - wxCHECK_MSG( index < m_nMatches, false, _T("invalid match index") ); - - if ( start ) - *start = m_Matches->Start(index); - if ( len ) - *len = m_Matches->End(index) - m_Matches->Start(index); - - return true; -} - -size_t wxRegExImpl::GetMatchCount() const -{ - wxCHECK_MSG( IsValid(), 0, _T("must successfully Compile() first") ); - wxCHECK_MSG( m_nMatches, 0, _T("can't use with wxRE_NOSUB") ); - - return m_nMatches; -} - -int wxRegExImpl::Replace(wxString *text, - const wxString& replacement, - size_t maxMatches) const -{ - wxCHECK_MSG( text, wxNOT_FOUND, _T("NULL text in wxRegEx::Replace") ); - wxCHECK_MSG( IsValid(), wxNOT_FOUND, _T("must successfully Compile() first") ); - - // the input string -#ifndef WXREGEX_CONVERT_TO_MB - const wxChar *textstr = text->c_str(); - size_t textlen = text->length(); -#else - const wxWX2MBbuf textstr = WXREGEX_CHAR(*text); - if (!textstr) - { - wxLogError(_("Failed to find match for regular expression: %s"), - GetErrorMsg(0, true).c_str()); - return 0; - } - size_t textlen = strlen(textstr); - text->clear(); -#endif - - // the replacement text - wxString textNew; - - // the result, allow 25% extra - wxString result; - result.reserve(5 * textlen / 4); - - // attempt at optimization: don't iterate over the string if it doesn't - // contain back references at all - bool mayHaveBackrefs = - replacement.find_first_of(_T("\\&")) != wxString::npos; - - if ( !mayHaveBackrefs ) - { - textNew = replacement; - } - - // the position where we start looking for the match - size_t matchStart = 0; - - // number of replacement made: we won't make more than maxMatches of them - // (unless maxMatches is 0 which doesn't limit the number of replacements) - size_t countRepl = 0; - - // note that "^" shouldn't match after the first call to Matches() so we - // use wxRE_NOTBOL to prevent it from happening - while ( (!maxMatches || countRepl < maxMatches) && - Matches(textstr + matchStart, - countRepl ? wxRE_NOTBOL : 0 - WXREGEX_IF_NEED_LEN(textlen - matchStart)) ) - { - // the string possibly contains back references: we need to calculate - // the replacement text anew after each match - if ( mayHaveBackrefs ) - { - mayHaveBackrefs = false; - textNew.clear(); - textNew.reserve(replacement.length()); - - for ( const wxChar *p = replacement.c_str(); *p; p++ ) - { - size_t index = (size_t)-1; - - if ( *p == _T('\\') ) - { - if ( wxIsdigit(*++p) ) - { - // back reference - wxChar *end; - index = (size_t)wxStrtoul(p, &end, 10); - p = end - 1; // -1 to compensate for p++ in the loop - } - //else: backslash used as escape character - } - else if ( *p == _T('&') ) - { - // treat this as "\0" for compatbility with ed and such - index = 0; - } - - // do we have a back reference? - if ( index != (size_t)-1 ) - { - // yes, get its text - size_t start, len; - if ( !GetMatch(&start, &len, index) ) - { - wxFAIL_MSG( _T("invalid back reference") ); - - // just eat it... - } - else - { - textNew += wxString(textstr + matchStart + start, - *wxConvCurrent, len); - - mayHaveBackrefs = true; - } - } - else // ordinary character - { - textNew += *p; - } - } - } - - size_t start, len; - if ( !GetMatch(&start, &len) ) - { - // we did have match as Matches() returned true above! - wxFAIL_MSG( _T("internal logic error in wxRegEx::Replace") ); - - return wxNOT_FOUND; - } - - // an insurance against implementations that don't grow exponentially - // to ensure building the result takes linear time - if (result.capacity() < result.length() + start + textNew.length()) - result.reserve(2 * result.length()); - -#ifndef WXREGEX_CONVERT_TO_MB - result.append(*text, matchStart, start); -#else - result.append(wxString(textstr + matchStart, *wxConvCurrent, start)); -#endif - matchStart += start; - result.append(textNew); - - countRepl++; - - matchStart += len; - } - -#ifndef WXREGEX_CONVERT_TO_MB - result.append(*text, matchStart, wxString::npos); -#else - result.append(wxString(textstr + matchStart, *wxConvCurrent)); -#endif - *text = result; - - return countRepl; -} - -// ---------------------------------------------------------------------------- -// wxRegEx: all methods are mostly forwarded to wxRegExImpl -// ---------------------------------------------------------------------------- - -void wxRegEx::Init() -{ - m_impl = NULL; -} - -wxRegEx::~wxRegEx() -{ - delete m_impl; -} - -bool wxRegEx::Compile(const wxString& expr, int flags) -{ - if ( !m_impl ) - { - m_impl = new wxRegExImpl; - } - - if ( !m_impl->Compile(expr, flags) ) - { - // error message already given in wxRegExImpl::Compile - delete m_impl; - m_impl = NULL; - - return false; - } - - return true; -} - -bool wxRegEx::Matches(const wxChar *str, int flags, size_t len) const -{ - wxCHECK_MSG( IsValid(), false, _T("must successfully Compile() first") ); - (void)len; - - return m_impl->Matches(WXREGEX_CHAR(str), flags WXREGEX_IF_NEED_LEN(len)); -} - -bool wxRegEx::Matches(const wxChar *str, int flags) const -{ - wxCHECK_MSG( IsValid(), false, _T("must successfully Compile() first") ); - - return m_impl->Matches(WXREGEX_CHAR(str), - flags - WXREGEX_IF_NEED_LEN(wxStrlen(str))); -} - -bool wxRegEx::GetMatch(size_t *start, size_t *len, size_t index) const -{ - wxCHECK_MSG( IsValid(), false, _T("must successfully Compile() first") ); - - return m_impl->GetMatch(start, len, index); -} - -wxString wxRegEx::GetMatch(const wxString& text, size_t index) const -{ - size_t start, len; - if ( !GetMatch(&start, &len, index) ) - return wxEmptyString; - - return text.Mid(start, len); -} - -size_t wxRegEx::GetMatchCount() const -{ - wxCHECK_MSG( IsValid(), 0, _T("must successfully Compile() first") ); - - return m_impl->GetMatchCount(); -} - -int wxRegEx::Replace(wxString *pattern, - const wxString& replacement, - size_t maxMatches) const -{ - wxCHECK_MSG( IsValid(), wxNOT_FOUND, _T("must successfully Compile() first") ); - - return m_impl->Replace(pattern, replacement, maxMatches); -} - -#endif // wxUSE_REGEX +/////////////////////////////////////////////////////////////////////////////// +// Name: src/common/regex.cpp +// Purpose: regular expression matching +// Author: Karsten Ballueder and Vadim Zeitlin +// Modified by: +// Created: 13.07.01 +// RCS-ID: $Id: regex.cpp 50711 2007-12-15 02:57:58Z VZ $ +// Copyright: (c) 2000 Karsten Ballueder +// 2001 Vadim Zeitlin +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_REGEX + +#ifndef WX_PRECOMP + #include "wx/object.h" + #include "wx/string.h" + #include "wx/log.h" + #include "wx/intl.h" +#endif //WX_PRECOMP + +// FreeBSD, Watcom and DMars require this, CW doesn't have nor need it. +// Others also don't seem to need it. If you have an error related to +// (not) including please report details to +// wx-dev@lists.wxwindows.org +#if defined(__UNIX__) || defined(__WATCOMC__) || defined(__DIGITALMARS__) +# include +#endif + +#include +#include "wx/regex.h" + +// WXREGEX_USING_BUILTIN defined when using the built-in regex lib +// WXREGEX_USING_RE_SEARCH defined when using re_search in the GNU regex lib +// WXREGEX_IF_NEED_LEN() wrap the len parameter only used with the built-in +// or GNU regex +// WXREGEX_CONVERT_TO_MB defined when the regex lib is using chars and +// wxChar is wide, so conversion must be done +// WXREGEX_CHAR(x) Convert wxChar to wxRegChar +// +#ifdef __REG_NOFRONT +# define WXREGEX_USING_BUILTIN +# define WXREGEX_IF_NEED_LEN(x) ,x +# define WXREGEX_CHAR(x) x +#else +# ifdef HAVE_RE_SEARCH +# define WXREGEX_IF_NEED_LEN(x) ,x +# define WXREGEX_USING_RE_SEARCH +# else +# define WXREGEX_IF_NEED_LEN(x) +# endif +# if wxUSE_UNICODE +# define WXREGEX_CONVERT_TO_MB +# endif +# define WXREGEX_CHAR(x) wxConvertWX2MB(x) +# define wx_regfree regfree +# define wx_regerror regerror +#endif + +// ---------------------------------------------------------------------------- +// private classes +// ---------------------------------------------------------------------------- + +#ifndef WXREGEX_USING_RE_SEARCH + +// the array of offsets for the matches, the usual POSIX regmatch_t array. +class wxRegExMatches +{ +public: + typedef regmatch_t *match_type; + + wxRegExMatches(size_t n) { m_matches = new regmatch_t[n]; } + ~wxRegExMatches() { delete [] m_matches; } + + // we just use casts here because the fields of regmatch_t struct may be 64 + // bit but we're limited to size_t in our public API and are not going to + // change it because operating on strings longer than 4GB using it is + // absolutely impractical anyhow + size_t Start(size_t n) const + { + return wx_truncate_cast(size_t, m_matches[n].rm_so); + } + + size_t End(size_t n) const + { + return wx_truncate_cast(size_t, m_matches[n].rm_eo); + } + + regmatch_t *get() const { return m_matches; } + +private: + regmatch_t *m_matches; +}; + +#else // WXREGEX_USING_RE_SEARCH + +// the array of offsets for the matches, the struct used by the GNU lib +class wxRegExMatches +{ +public: + typedef re_registers *match_type; + + wxRegExMatches(size_t n) + { + m_matches.num_regs = n; + m_matches.start = new regoff_t[n]; + m_matches.end = new regoff_t[n]; + } + + ~wxRegExMatches() + { + delete [] m_matches.start; + delete [] m_matches.end; + } + + size_t Start(size_t n) const { return m_matches.start[n]; } + size_t End(size_t n) const { return m_matches.end[n]; } + + re_registers *get() { return &m_matches; } + +private: + re_registers m_matches; +}; + +#endif // WXREGEX_USING_RE_SEARCH + +// the character type used by the regular expression engine +#ifndef WXREGEX_CONVERT_TO_MB +typedef wxChar wxRegChar; +#else +typedef char wxRegChar; +#endif + +// the real implementation of wxRegEx +class wxRegExImpl +{ +public: + // ctor and dtor + wxRegExImpl(); + ~wxRegExImpl(); + + // return true if Compile() had been called successfully + bool IsValid() const { return m_isCompiled; } + + // RE operations + bool Compile(const wxString& expr, int flags = 0); + bool Matches(const wxRegChar *str, int flags + WXREGEX_IF_NEED_LEN(size_t len)) const; + bool GetMatch(size_t *start, size_t *len, size_t index = 0) const; + size_t GetMatchCount() const; + int Replace(wxString *pattern, const wxString& replacement, + size_t maxMatches = 0) const; + +private: + // return the string containing the error message for the given err code + wxString GetErrorMsg(int errorcode, bool badconv) const; + + // init the members + void Init() + { + m_isCompiled = false; + m_Matches = NULL; + m_nMatches = 0; + } + + // free the RE if compiled + void Free() + { + if ( IsValid() ) + { + wx_regfree(&m_RegEx); + } + + delete m_Matches; + } + + // free the RE if any and reinit the members + void Reinit() + { + Free(); + Init(); + } + + // compiled RE + regex_t m_RegEx; + + // the subexpressions data + wxRegExMatches *m_Matches; + size_t m_nMatches; + + // true if m_RegEx is valid + bool m_isCompiled; +}; + + +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// wxRegExImpl +// ---------------------------------------------------------------------------- + +wxRegExImpl::wxRegExImpl() +{ + Init(); +} + +wxRegExImpl::~wxRegExImpl() +{ + Free(); +} + +wxString wxRegExImpl::GetErrorMsg(int errorcode, bool badconv) const +{ +#ifdef WXREGEX_CONVERT_TO_MB + // currently only needed when using system library in Unicode mode + if ( badconv ) + { + return _("conversion to 8-bit encoding failed"); + } +#else + // 'use' badconv to avoid a compiler warning + (void)badconv; +#endif + + wxString szError; + + // first get the string length needed + int len = wx_regerror(errorcode, &m_RegEx, NULL, 0); + if ( len > 0 ) + { + char* szcmbError = new char[++len]; + + (void)wx_regerror(errorcode, &m_RegEx, szcmbError, len); + + szError = wxConvertMB2WX(szcmbError); + delete [] szcmbError; + } + else // regerror() returned 0 + { + szError = _("unknown error"); + } + + return szError; +} + +bool wxRegExImpl::Compile(const wxString& expr, int flags) +{ + Reinit(); + +#ifdef WX_NO_REGEX_ADVANCED +# define FLAVORS wxRE_BASIC +#else +# define FLAVORS (wxRE_ADVANCED | wxRE_BASIC) + wxASSERT_MSG( (flags & FLAVORS) != FLAVORS, + _T("incompatible flags in wxRegEx::Compile") ); +#endif + wxASSERT_MSG( !(flags & ~(FLAVORS | wxRE_ICASE | wxRE_NOSUB | wxRE_NEWLINE)), + _T("unrecognized flags in wxRegEx::Compile") ); + + // translate our flags to regcomp() ones + int flagsRE = 0; + if ( !(flags & wxRE_BASIC) ) +#ifndef WX_NO_REGEX_ADVANCED + if (flags & wxRE_ADVANCED) + flagsRE |= REG_ADVANCED; + else +#endif + flagsRE |= REG_EXTENDED; + if ( flags & wxRE_ICASE ) + flagsRE |= REG_ICASE; + if ( flags & wxRE_NOSUB ) + flagsRE |= REG_NOSUB; + if ( flags & wxRE_NEWLINE ) + flagsRE |= REG_NEWLINE; + + // compile it +#ifdef WXREGEX_USING_BUILTIN + bool conv = true; + int errorcode = wx_re_comp(&m_RegEx, expr, expr.length(), flagsRE); +#else + const wxWX2MBbuf conv = expr.mbc_str(); + int errorcode = conv ? regcomp(&m_RegEx, conv, flagsRE) : REG_BADPAT; +#endif + + if ( errorcode ) + { + wxLogError(_("Invalid regular expression '%s': %s"), + expr.c_str(), GetErrorMsg(errorcode, !conv).c_str()); + + m_isCompiled = false; + } + else // ok + { + // don't allocate the matches array now, but do it later if necessary + if ( flags & wxRE_NOSUB ) + { + // we don't need it at all + m_nMatches = 0; + } + else + { + // we will alloc the array later (only if really needed) but count + // the number of sub-expressions in the regex right now + + // there is always one for the whole expression + m_nMatches = 1; + + // and some more for bracketed subexperessions + for ( const wxChar *cptr = expr.c_str(); *cptr; cptr++ ) + { + if ( *cptr == _T('\\') ) + { + // in basic RE syntax groups are inside \(...\) + if ( *++cptr == _T('(') && (flags & wxRE_BASIC) ) + { + m_nMatches++; + } + } + else if ( *cptr == _T('(') && !(flags & wxRE_BASIC) ) + { + // we know that the previous character is not an unquoted + // backslash because it would have been eaten above, so we + // have a bare '(' and this indicates a group start for the + // extended syntax. '(?' is used for extensions by perl- + // like REs (e.g. advanced), and is not valid for POSIX + // extended, so ignore them always. + if ( cptr[1] != _T('?') ) + m_nMatches++; + } + } + } + + m_isCompiled = true; + } + + return IsValid(); +} + +#ifdef WXREGEX_USING_RE_SEARCH + +// On GNU, regexec is implemented as a wrapper around re_search. re_search +// requires a length parameter which the POSIX regexec does not have, +// therefore regexec must do a strlen on the search text each time it is +// called. This can drastically affect performance when matching is done in +// a loop along a string, such as during a search and replace. Therefore if +// re_search is detected by configure, it is used directly. +// +static int ReSearch(const regex_t *preg, + const char *text, + size_t len, + re_registers *matches, + int eflags) +{ + regex_t *pattern = wx_const_cast(regex_t*, preg); + + pattern->not_bol = (eflags & REG_NOTBOL) != 0; + pattern->not_eol = (eflags & REG_NOTEOL) != 0; + pattern->regs_allocated = REGS_FIXED; + + int ret = re_search(pattern, text, len, 0, len, matches); + return ret >= 0 ? 0 : REG_NOMATCH; +} + +#endif // WXREGEX_USING_RE_SEARCH + +bool wxRegExImpl::Matches(const wxRegChar *str, + int flags + WXREGEX_IF_NEED_LEN(size_t len)) const +{ + wxCHECK_MSG( IsValid(), false, _T("must successfully Compile() first") ); + + // translate our flags to regexec() ones + wxASSERT_MSG( !(flags & ~(wxRE_NOTBOL | wxRE_NOTEOL)), + _T("unrecognized flags in wxRegEx::Matches") ); + + int flagsRE = 0; + if ( flags & wxRE_NOTBOL ) + flagsRE |= REG_NOTBOL; + if ( flags & wxRE_NOTEOL ) + flagsRE |= REG_NOTEOL; + + // allocate matches array if needed + wxRegExImpl *self = wxConstCast(this, wxRegExImpl); + if ( !m_Matches && m_nMatches ) + { + self->m_Matches = new wxRegExMatches(m_nMatches); + } + + wxRegExMatches::match_type matches = m_Matches ? m_Matches->get() : NULL; + + // do match it +#if defined WXREGEX_USING_BUILTIN + int rc = wx_re_exec(&self->m_RegEx, str, len, NULL, m_nMatches, matches, flagsRE); +#elif defined WXREGEX_USING_RE_SEARCH + int rc = str ? ReSearch(&self->m_RegEx, str, len, matches, flagsRE) : REG_BADPAT; +#else + int rc = str ? regexec(&self->m_RegEx, str, m_nMatches, matches, flagsRE) : REG_BADPAT; +#endif + + switch ( rc ) + { + case 0: + // matched successfully + return true; + + default: + // an error occurred + wxLogError(_("Failed to find match for regular expression: %s"), + GetErrorMsg(rc, !str).c_str()); + // fall through + + case REG_NOMATCH: + // no match + return false; + } +} + +bool wxRegExImpl::GetMatch(size_t *start, size_t *len, size_t index) const +{ + wxCHECK_MSG( IsValid(), false, _T("must successfully Compile() first") ); + wxCHECK_MSG( m_nMatches, false, _T("can't use with wxRE_NOSUB") ); + wxCHECK_MSG( m_Matches, false, _T("must call Matches() first") ); + wxCHECK_MSG( index < m_nMatches, false, _T("invalid match index") ); + + if ( start ) + *start = m_Matches->Start(index); + if ( len ) + *len = m_Matches->End(index) - m_Matches->Start(index); + + return true; +} + +size_t wxRegExImpl::GetMatchCount() const +{ + wxCHECK_MSG( IsValid(), 0, _T("must successfully Compile() first") ); + wxCHECK_MSG( m_nMatches, 0, _T("can't use with wxRE_NOSUB") ); + + return m_nMatches; +} + +int wxRegExImpl::Replace(wxString *text, + const wxString& replacement, + size_t maxMatches) const +{ + wxCHECK_MSG( text, wxNOT_FOUND, _T("NULL text in wxRegEx::Replace") ); + wxCHECK_MSG( IsValid(), wxNOT_FOUND, _T("must successfully Compile() first") ); + + // the input string +#ifndef WXREGEX_CONVERT_TO_MB + const wxChar *textstr = text->c_str(); + size_t textlen = text->length(); +#else + const wxWX2MBbuf textstr = WXREGEX_CHAR(*text); + if (!textstr) + { + wxLogError(_("Failed to find match for regular expression: %s"), + GetErrorMsg(0, true).c_str()); + return 0; + } + size_t textlen = strlen(textstr); + text->clear(); +#endif + + // the replacement text + wxString textNew; + + // the result, allow 25% extra + wxString result; + result.reserve(5 * textlen / 4); + + // attempt at optimization: don't iterate over the string if it doesn't + // contain back references at all + bool mayHaveBackrefs = + replacement.find_first_of(_T("\\&")) != wxString::npos; + + if ( !mayHaveBackrefs ) + { + textNew = replacement; + } + + // the position where we start looking for the match + size_t matchStart = 0; + + // number of replacement made: we won't make more than maxMatches of them + // (unless maxMatches is 0 which doesn't limit the number of replacements) + size_t countRepl = 0; + + // note that "^" shouldn't match after the first call to Matches() so we + // use wxRE_NOTBOL to prevent it from happening + while ( (!maxMatches || countRepl < maxMatches) && + Matches(textstr + matchStart, + countRepl ? wxRE_NOTBOL : 0 + WXREGEX_IF_NEED_LEN(textlen - matchStart)) ) + { + // the string possibly contains back references: we need to calculate + // the replacement text anew after each match + if ( mayHaveBackrefs ) + { + mayHaveBackrefs = false; + textNew.clear(); + textNew.reserve(replacement.length()); + + for ( const wxChar *p = replacement.c_str(); *p; p++ ) + { + size_t index = (size_t)-1; + + if ( *p == _T('\\') ) + { + if ( wxIsdigit(*++p) ) + { + // back reference + wxChar *end; + index = (size_t)wxStrtoul(p, &end, 10); + p = end - 1; // -1 to compensate for p++ in the loop + } + //else: backslash used as escape character + } + else if ( *p == _T('&') ) + { + // treat this as "\0" for compatbility with ed and such + index = 0; + } + + // do we have a back reference? + if ( index != (size_t)-1 ) + { + // yes, get its text + size_t start, len; + if ( !GetMatch(&start, &len, index) ) + { + wxFAIL_MSG( _T("invalid back reference") ); + + // just eat it... + } + else + { + textNew += wxString(textstr + matchStart + start, + *wxConvCurrent, len); + + mayHaveBackrefs = true; + } + } + else // ordinary character + { + textNew += *p; + } + } + } + + size_t start, len; + if ( !GetMatch(&start, &len) ) + { + // we did have match as Matches() returned true above! + wxFAIL_MSG( _T("internal logic error in wxRegEx::Replace") ); + + return wxNOT_FOUND; + } + + // an insurance against implementations that don't grow exponentially + // to ensure building the result takes linear time + if (result.capacity() < result.length() + start + textNew.length()) + result.reserve(2 * result.length()); + +#ifndef WXREGEX_CONVERT_TO_MB + result.append(*text, matchStart, start); +#else + result.append(wxString(textstr + matchStart, *wxConvCurrent, start)); +#endif + matchStart += start; + result.append(textNew); + + countRepl++; + + matchStart += len; + } + +#ifndef WXREGEX_CONVERT_TO_MB + result.append(*text, matchStart, wxString::npos); +#else + result.append(wxString(textstr + matchStart, *wxConvCurrent)); +#endif + *text = result; + + return countRepl; +} + +// ---------------------------------------------------------------------------- +// wxRegEx: all methods are mostly forwarded to wxRegExImpl +// ---------------------------------------------------------------------------- + +void wxRegEx::Init() +{ + m_impl = NULL; +} + +wxRegEx::~wxRegEx() +{ + delete m_impl; +} + +bool wxRegEx::Compile(const wxString& expr, int flags) +{ + if ( !m_impl ) + { + m_impl = new wxRegExImpl; + } + + if ( !m_impl->Compile(expr, flags) ) + { + // error message already given in wxRegExImpl::Compile + delete m_impl; + m_impl = NULL; + + return false; + } + + return true; +} + +bool wxRegEx::Matches(const wxChar *str, int flags, size_t len) const +{ + wxCHECK_MSG( IsValid(), false, _T("must successfully Compile() first") ); + (void)len; + + return m_impl->Matches(WXREGEX_CHAR(str), flags WXREGEX_IF_NEED_LEN(len)); +} + +bool wxRegEx::Matches(const wxChar *str, int flags) const +{ + wxCHECK_MSG( IsValid(), false, _T("must successfully Compile() first") ); + + return m_impl->Matches(WXREGEX_CHAR(str), + flags + WXREGEX_IF_NEED_LEN(wxStrlen(str))); +} + +bool wxRegEx::GetMatch(size_t *start, size_t *len, size_t index) const +{ + wxCHECK_MSG( IsValid(), false, _T("must successfully Compile() first") ); + + return m_impl->GetMatch(start, len, index); +} + +wxString wxRegEx::GetMatch(const wxString& text, size_t index) const +{ + size_t start, len; + if ( !GetMatch(&start, &len, index) ) + return wxEmptyString; + + return text.Mid(start, len); +} + +size_t wxRegEx::GetMatchCount() const +{ + wxCHECK_MSG( IsValid(), 0, _T("must successfully Compile() first") ); + + return m_impl->GetMatchCount(); +} + +int wxRegEx::Replace(wxString *pattern, + const wxString& replacement, + size_t maxMatches) const +{ + wxCHECK_MSG( IsValid(), wxNOT_FOUND, _T("must successfully Compile() first") ); + + return m_impl->Replace(pattern, replacement, maxMatches); +} + +#endif // wxUSE_REGEX diff --git a/Externals/wxWidgets/src/common/rendcmn.cpp b/Externals/wxWidgets/src/common/rendcmn.cpp index 9d77c390be..702ffb4fa5 100644 --- a/Externals/wxWidgets/src/common/rendcmn.cpp +++ b/Externals/wxWidgets/src/common/rendcmn.cpp @@ -1,208 +1,208 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: src/common/rendcmn.cpp -// Purpose: wxRendererNative common functions -// Author: Vadim Zeitlin -// Modified by: -// Created: 28.07.03 -// RCS-ID: $Id: rendcmn.cpp 41216 2006-09-14 16:04:18Z ABX $ -// Copyright: (c) 2003 Vadim Zeitlin -// License: wxWindows license -/////////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#ifndef WX_PRECOMP - #include "wx/app.h" - #include "wx/log.h" - #include "wx/intl.h" -#endif //WX_PRECOMP - -#include "wx/apptrait.h" -#include "wx/renderer.h" - -#include "wx/ptr_scpd.h" - -#if wxUSE_DYNLIB_CLASS - #include "wx/dynlib.h" -#endif // wxUSE_DYNLIB_CLASS - -// ---------------------------------------------------------------------------- -// wxRendererPtr: auto pointer holding the global renderer -// ---------------------------------------------------------------------------- - -wxDECLARE_SCOPED_PTR(wxRendererNative, wxRendererPtrBase) -wxDEFINE_SCOPED_PTR(wxRendererNative, wxRendererPtrBase) - -class wxRendererPtr : public wxRendererPtrBase -{ -public: - // return true if we have a renderer, false otherwise - bool IsOk() - { - if ( !m_initialized ) - { - // only try to create the renderer once - m_initialized = true; - - DoInit(); - } - - return get() != NULL; - } - - // return the global and unique wxRendererPtr - static wxRendererPtr& Get(); - -private: - wxRendererPtr() : wxRendererPtrBase(NULL) { m_initialized = false; } - - void DoInit() - { - wxAppTraits *traits = wxTheApp ? wxTheApp->GetTraits() : NULL; - if ( traits ) - { - // ask the traits object to create a renderer for us - reset(traits->CreateRenderer()); - } - } - - bool m_initialized; - - // just to suppress a gcc warning - friend class wxRendererPtrDummyFriend; - - DECLARE_NO_COPY_CLASS(wxRendererPtr) -}; - -// return the global and unique wxRendererPtr -/*static*/ wxRendererPtr& wxRendererPtr::Get() -{ - static wxRendererPtr s_renderer; - - return s_renderer; -} - -#if wxUSE_DYNLIB_CLASS - -// ---------------------------------------------------------------------------- -// wxRendererFromDynLib: represents a renderer dynamically loaded from a DLL -// ---------------------------------------------------------------------------- - -class wxRendererFromDynLib : public wxDelegateRendererNative -{ -public: - // create the object wrapping the given renderer created from this DLL - // - // we take ownership of the pointer and will delete it (and also unload the - // DLL) when we're deleted - wxRendererFromDynLib(wxDynamicLibrary& dll, wxRendererNative *renderer) - : wxDelegateRendererNative(*renderer), - m_renderer(renderer), - m_dllHandle(dll.Detach()) - { - } - - virtual ~wxRendererFromDynLib() - { - delete m_renderer; - wxDynamicLibrary::Unload(m_dllHandle); - } - -private: - wxRendererNative *m_renderer; - wxDllType m_dllHandle; -}; - -#endif // wxUSE_DYNLIB_CLASS - -// ============================================================================ -// wxRendererNative implementation -// ============================================================================ - -wxRendererNative::~wxRendererNative() -{ - // empty but necessary -} - -// ---------------------------------------------------------------------------- -// Managing the global renderer -// ---------------------------------------------------------------------------- - -/* static */ -wxRendererNative& wxRendererNative::Get() -{ - wxRendererPtr& renderer = wxRendererPtr::Get(); - - return renderer.IsOk() ? *renderer.get() : GetDefault(); -} - -/* static */ -wxRendererNative *wxRendererNative::Set(wxRendererNative *rendererNew) -{ - wxRendererPtr& renderer = wxRendererPtr::Get(); - - wxRendererNative *rendererOld = renderer.release(); - - renderer.reset(rendererNew); - - return rendererOld; -} - - -// ---------------------------------------------------------------------------- -// Dynamic renderers loading -// ---------------------------------------------------------------------------- - -#if wxUSE_DYNLIB_CLASS - -/* static */ -wxRendererNative *wxRendererNative::Load(const wxString& name) -{ - wxString fullname = wxDynamicLibrary::CanonicalizePluginName(name); - - wxDynamicLibrary dll(fullname); - if ( !dll.IsLoaded() ) - return NULL; - - // each theme DLL must export a wxCreateRenderer() function with this - // signature - typedef wxRendererNative *(*wxCreateRenderer_t)(); - - wxDYNLIB_FUNCTION(wxCreateRenderer_t, wxCreateRenderer, dll); - if ( !pfnwxCreateRenderer ) - return NULL; - - // create a renderer object - wxRendererNative *renderer = (*pfnwxCreateRenderer)(); - if ( !renderer ) - return NULL; - - // check that its version is compatible with ours - wxRendererVersion ver = renderer->GetVersion(); - if ( !wxRendererVersion::IsCompatible(ver) ) - { - wxLogError(_("Renderer \"%s\" has incompatible version %d.%d and couldn't be loaded."), - name.c_str(), ver.version, ver.age); - delete renderer; - - return NULL; - } - - // finally wrap the renderer in an object which will delete it and unload - // the library when it is deleted and return it to the caller - return new wxRendererFromDynLib(dll, renderer); -} - -#endif // wxUSE_DYNLIB_CLASS +/////////////////////////////////////////////////////////////////////////////// +// Name: src/common/rendcmn.cpp +// Purpose: wxRendererNative common functions +// Author: Vadim Zeitlin +// Modified by: +// Created: 28.07.03 +// RCS-ID: $Id: rendcmn.cpp 41216 2006-09-14 16:04:18Z ABX $ +// Copyright: (c) 2003 Vadim Zeitlin +// License: wxWindows license +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#ifndef WX_PRECOMP + #include "wx/app.h" + #include "wx/log.h" + #include "wx/intl.h" +#endif //WX_PRECOMP + +#include "wx/apptrait.h" +#include "wx/renderer.h" + +#include "wx/ptr_scpd.h" + +#if wxUSE_DYNLIB_CLASS + #include "wx/dynlib.h" +#endif // wxUSE_DYNLIB_CLASS + +// ---------------------------------------------------------------------------- +// wxRendererPtr: auto pointer holding the global renderer +// ---------------------------------------------------------------------------- + +wxDECLARE_SCOPED_PTR(wxRendererNative, wxRendererPtrBase) +wxDEFINE_SCOPED_PTR(wxRendererNative, wxRendererPtrBase) + +class wxRendererPtr : public wxRendererPtrBase +{ +public: + // return true if we have a renderer, false otherwise + bool IsOk() + { + if ( !m_initialized ) + { + // only try to create the renderer once + m_initialized = true; + + DoInit(); + } + + return get() != NULL; + } + + // return the global and unique wxRendererPtr + static wxRendererPtr& Get(); + +private: + wxRendererPtr() : wxRendererPtrBase(NULL) { m_initialized = false; } + + void DoInit() + { + wxAppTraits *traits = wxTheApp ? wxTheApp->GetTraits() : NULL; + if ( traits ) + { + // ask the traits object to create a renderer for us + reset(traits->CreateRenderer()); + } + } + + bool m_initialized; + + // just to suppress a gcc warning + friend class wxRendererPtrDummyFriend; + + DECLARE_NO_COPY_CLASS(wxRendererPtr) +}; + +// return the global and unique wxRendererPtr +/*static*/ wxRendererPtr& wxRendererPtr::Get() +{ + static wxRendererPtr s_renderer; + + return s_renderer; +} + +#if wxUSE_DYNLIB_CLASS + +// ---------------------------------------------------------------------------- +// wxRendererFromDynLib: represents a renderer dynamically loaded from a DLL +// ---------------------------------------------------------------------------- + +class wxRendererFromDynLib : public wxDelegateRendererNative +{ +public: + // create the object wrapping the given renderer created from this DLL + // + // we take ownership of the pointer and will delete it (and also unload the + // DLL) when we're deleted + wxRendererFromDynLib(wxDynamicLibrary& dll, wxRendererNative *renderer) + : wxDelegateRendererNative(*renderer), + m_renderer(renderer), + m_dllHandle(dll.Detach()) + { + } + + virtual ~wxRendererFromDynLib() + { + delete m_renderer; + wxDynamicLibrary::Unload(m_dllHandle); + } + +private: + wxRendererNative *m_renderer; + wxDllType m_dllHandle; +}; + +#endif // wxUSE_DYNLIB_CLASS + +// ============================================================================ +// wxRendererNative implementation +// ============================================================================ + +wxRendererNative::~wxRendererNative() +{ + // empty but necessary +} + +// ---------------------------------------------------------------------------- +// Managing the global renderer +// ---------------------------------------------------------------------------- + +/* static */ +wxRendererNative& wxRendererNative::Get() +{ + wxRendererPtr& renderer = wxRendererPtr::Get(); + + return renderer.IsOk() ? *renderer.get() : GetDefault(); +} + +/* static */ +wxRendererNative *wxRendererNative::Set(wxRendererNative *rendererNew) +{ + wxRendererPtr& renderer = wxRendererPtr::Get(); + + wxRendererNative *rendererOld = renderer.release(); + + renderer.reset(rendererNew); + + return rendererOld; +} + + +// ---------------------------------------------------------------------------- +// Dynamic renderers loading +// ---------------------------------------------------------------------------- + +#if wxUSE_DYNLIB_CLASS + +/* static */ +wxRendererNative *wxRendererNative::Load(const wxString& name) +{ + wxString fullname = wxDynamicLibrary::CanonicalizePluginName(name); + + wxDynamicLibrary dll(fullname); + if ( !dll.IsLoaded() ) + return NULL; + + // each theme DLL must export a wxCreateRenderer() function with this + // signature + typedef wxRendererNative *(*wxCreateRenderer_t)(); + + wxDYNLIB_FUNCTION(wxCreateRenderer_t, wxCreateRenderer, dll); + if ( !pfnwxCreateRenderer ) + return NULL; + + // create a renderer object + wxRendererNative *renderer = (*pfnwxCreateRenderer)(); + if ( !renderer ) + return NULL; + + // check that its version is compatible with ours + wxRendererVersion ver = renderer->GetVersion(); + if ( !wxRendererVersion::IsCompatible(ver) ) + { + wxLogError(_("Renderer \"%s\" has incompatible version %d.%d and couldn't be loaded."), + name.c_str(), ver.version, ver.age); + delete renderer; + + return NULL; + } + + // finally wrap the renderer in an object which will delete it and unload + // the library when it is deleted and return it to the caller + return new wxRendererFromDynLib(dll, renderer); +} + +#endif // wxUSE_DYNLIB_CLASS diff --git a/Externals/wxWidgets/src/common/rgncmn.cpp b/Externals/wxWidgets/src/common/rgncmn.cpp index ca5ff249d3..0f9c8b216f 100644 --- a/Externals/wxWidgets/src/common/rgncmn.cpp +++ b/Externals/wxWidgets/src/common/rgncmn.cpp @@ -1,192 +1,192 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/rgncmn.cpp -// Purpose: Methods of wxRegion that have a generic implementation -// Author: Robin Dunn -// Modified by: -// Created: 27-Mar-2003 -// RCS-ID: $Id: rgncmn.cpp 41901 2006-10-10 17:33:49Z PC $ -// Copyright: (c) Robin Dunn -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#include "wx/region.h" - -#ifndef WX_PRECOMP - #include "wx/dcmemory.h" - #include "wx/bitmap.h" - #include "wx/image.h" -#endif //WX_PRECOMP - -// ============================================================================ -// wxRegionBase implementation -// ============================================================================ - -// ---------------------------------------------------------------------------- -// region comparision -// ---------------------------------------------------------------------------- - -bool wxRegionBase::IsEqual(const wxRegion& region) const -{ - if ( m_refData == region.GetRefData() ) - { - // regions are identical, hence equal - return true; - } - - if ( !m_refData || !region.GetRefData() ) - { - // one, but not both, of the regions is invalid - return false; - } - - return DoIsEqual(region); -} - -// ---------------------------------------------------------------------------- -// region to/from bitmap conversions -// ---------------------------------------------------------------------------- - -wxBitmap wxRegionBase::ConvertToBitmap() const -{ - wxRect box = GetBox(); - wxBitmap bmp(box.GetRight(), box.GetBottom()); - wxMemoryDC dc; - dc.SelectObject(bmp); - dc.SetBackground(*wxBLACK_BRUSH); - dc.Clear(); - dc.SetClippingRegion(*wx_static_cast(const wxRegion *, this)); - dc.SetBackground(*wxWHITE_BRUSH); - dc.Clear(); - dc.SelectObject(wxNullBitmap); - return bmp; -} - -#if wxUSE_IMAGE - -static bool DoRegionUnion(wxRegionBase& region, - const wxImage& image, - unsigned char loR, - unsigned char loG, - unsigned char loB, - int tolerance) -{ - unsigned char hiR, hiG, hiB; - - hiR = (unsigned char)wxMin(0xFF, loR + tolerance); - hiG = (unsigned char)wxMin(0xFF, loG + tolerance); - hiB = (unsigned char)wxMin(0xFF, loB + tolerance); - - // Loop through the image row by row, pixel by pixel, building up - // rectangles to add to the region. - int width = image.GetWidth(); - int height = image.GetHeight(); - for (int y=0; y < height; y++) - { - wxRect rect; - rect.y = y; - rect.height = 1; - - for (int x=0; x < width; x++) - { - // search for a continuous range of non-transparent pixels - int x0 = x; - while ( x < width) - { - unsigned char R = image.GetRed(x,y); - unsigned char G = image.GetGreen(x,y); - unsigned char B = image.GetBlue(x,y); - if (( R >= loR && R <= hiR) && - ( G >= loG && G <= hiG) && - ( B >= loB && B <= hiB)) // It's transparent - break; - x++; - } - - // Add the run of non-transparent pixels (if any) to the region - if (x > x0) { - rect.x = x0; - rect.width = x - x0; - region.Union(rect); - } - } - } - - return true; -} - - -bool wxRegionBase::Union(const wxBitmap& bmp) -{ - if (bmp.GetMask()) - { - wxImage image = bmp.ConvertToImage(); - wxASSERT_MSG( image.HasMask(), _T("wxBitmap::ConvertToImage doesn't preserve mask?") ); - return DoRegionUnion(*this, image, - image.GetMaskRed(), - image.GetMaskGreen(), - image.GetMaskBlue(), - 0); - } - else - { - return Union(0, 0, bmp.GetWidth(), bmp.GetHeight()); - } -} - -bool wxRegionBase::Union(const wxBitmap& bmp, - const wxColour& transColour, - int tolerance) -{ - wxImage image = bmp.ConvertToImage(); - return DoRegionUnion(*this, image, - transColour.Red(), - transColour.Green(), - transColour.Blue(), - tolerance); -} - -#endif // wxUSE_IMAGE - -#ifdef wxHAS_REGION_COMBINE -// ============================================================================ -// wxRegionWithCombine -// ============================================================================ - -// implement some wxRegionBase pure virtuals in terms of Combine() -bool wxRegionWithCombine::DoUnionWithRect(const wxRect& rect) -{ - return Combine(rect, wxRGN_OR); -} - -bool wxRegionWithCombine::DoUnionWithRegion(const wxRegion& region) -{ - return DoCombine(region, wxRGN_OR); -} - -bool wxRegionWithCombine::DoIntersect(const wxRegion& region) -{ - return DoCombine(region, wxRGN_AND); -} - -bool wxRegionWithCombine::DoSubtract(const wxRegion& region) -{ - return DoCombine(region, wxRGN_DIFF); -} - -bool wxRegionWithCombine::DoXor(const wxRegion& region) -{ - return DoCombine(region, wxRGN_XOR); -} - -#endif // wxHAS_REGION_COMBINE +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/rgncmn.cpp +// Purpose: Methods of wxRegion that have a generic implementation +// Author: Robin Dunn +// Modified by: +// Created: 27-Mar-2003 +// RCS-ID: $Id: rgncmn.cpp 41901 2006-10-10 17:33:49Z PC $ +// Copyright: (c) Robin Dunn +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#include "wx/region.h" + +#ifndef WX_PRECOMP + #include "wx/dcmemory.h" + #include "wx/bitmap.h" + #include "wx/image.h" +#endif //WX_PRECOMP + +// ============================================================================ +// wxRegionBase implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// region comparision +// ---------------------------------------------------------------------------- + +bool wxRegionBase::IsEqual(const wxRegion& region) const +{ + if ( m_refData == region.GetRefData() ) + { + // regions are identical, hence equal + return true; + } + + if ( !m_refData || !region.GetRefData() ) + { + // one, but not both, of the regions is invalid + return false; + } + + return DoIsEqual(region); +} + +// ---------------------------------------------------------------------------- +// region to/from bitmap conversions +// ---------------------------------------------------------------------------- + +wxBitmap wxRegionBase::ConvertToBitmap() const +{ + wxRect box = GetBox(); + wxBitmap bmp(box.GetRight(), box.GetBottom()); + wxMemoryDC dc; + dc.SelectObject(bmp); + dc.SetBackground(*wxBLACK_BRUSH); + dc.Clear(); + dc.SetClippingRegion(*wx_static_cast(const wxRegion *, this)); + dc.SetBackground(*wxWHITE_BRUSH); + dc.Clear(); + dc.SelectObject(wxNullBitmap); + return bmp; +} + +#if wxUSE_IMAGE + +static bool DoRegionUnion(wxRegionBase& region, + const wxImage& image, + unsigned char loR, + unsigned char loG, + unsigned char loB, + int tolerance) +{ + unsigned char hiR, hiG, hiB; + + hiR = (unsigned char)wxMin(0xFF, loR + tolerance); + hiG = (unsigned char)wxMin(0xFF, loG + tolerance); + hiB = (unsigned char)wxMin(0xFF, loB + tolerance); + + // Loop through the image row by row, pixel by pixel, building up + // rectangles to add to the region. + int width = image.GetWidth(); + int height = image.GetHeight(); + for (int y=0; y < height; y++) + { + wxRect rect; + rect.y = y; + rect.height = 1; + + for (int x=0; x < width; x++) + { + // search for a continuous range of non-transparent pixels + int x0 = x; + while ( x < width) + { + unsigned char R = image.GetRed(x,y); + unsigned char G = image.GetGreen(x,y); + unsigned char B = image.GetBlue(x,y); + if (( R >= loR && R <= hiR) && + ( G >= loG && G <= hiG) && + ( B >= loB && B <= hiB)) // It's transparent + break; + x++; + } + + // Add the run of non-transparent pixels (if any) to the region + if (x > x0) { + rect.x = x0; + rect.width = x - x0; + region.Union(rect); + } + } + } + + return true; +} + + +bool wxRegionBase::Union(const wxBitmap& bmp) +{ + if (bmp.GetMask()) + { + wxImage image = bmp.ConvertToImage(); + wxASSERT_MSG( image.HasMask(), _T("wxBitmap::ConvertToImage doesn't preserve mask?") ); + return DoRegionUnion(*this, image, + image.GetMaskRed(), + image.GetMaskGreen(), + image.GetMaskBlue(), + 0); + } + else + { + return Union(0, 0, bmp.GetWidth(), bmp.GetHeight()); + } +} + +bool wxRegionBase::Union(const wxBitmap& bmp, + const wxColour& transColour, + int tolerance) +{ + wxImage image = bmp.ConvertToImage(); + return DoRegionUnion(*this, image, + transColour.Red(), + transColour.Green(), + transColour.Blue(), + tolerance); +} + +#endif // wxUSE_IMAGE + +#ifdef wxHAS_REGION_COMBINE +// ============================================================================ +// wxRegionWithCombine +// ============================================================================ + +// implement some wxRegionBase pure virtuals in terms of Combine() +bool wxRegionWithCombine::DoUnionWithRect(const wxRect& rect) +{ + return Combine(rect, wxRGN_OR); +} + +bool wxRegionWithCombine::DoUnionWithRegion(const wxRegion& region) +{ + return DoCombine(region, wxRGN_OR); +} + +bool wxRegionWithCombine::DoIntersect(const wxRegion& region) +{ + return DoCombine(region, wxRGN_AND); +} + +bool wxRegionWithCombine::DoSubtract(const wxRegion& region) +{ + return DoCombine(region, wxRGN_DIFF); +} + +bool wxRegionWithCombine::DoXor(const wxRegion& region) +{ + return DoCombine(region, wxRGN_XOR); +} + +#endif // wxHAS_REGION_COMBINE diff --git a/Externals/wxWidgets/src/common/sckaddr.cpp b/Externals/wxWidgets/src/common/sckaddr.cpp index ab7a1aa715..efbe3850ec 100644 --- a/Externals/wxWidgets/src/common/sckaddr.cpp +++ b/Externals/wxWidgets/src/common/sckaddr.cpp @@ -1,349 +1,349 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/sckaddr.cpp -// Purpose: Network address manager -// Author: Guilhem Lavaux -// Modified by: -// Created: 26/04/97 -// RCS-ID: $Id: sckaddr.cpp 38787 2006-04-18 07:24:35Z ABX $ -// Copyright: (c) 1997, 1998 Guilhem Lavaux -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_SOCKETS - -#ifndef WX_PRECOMP - #include "wx/object.h" - #include "wx/log.h" - #include "wx/intl.h" - - #include - #include - #include - - #if !defined(__MWERKS__) && !defined(__SALFORDC__) - #include - #endif -#endif // !WX_PRECOMP - -#include "wx/gsocket.h" -#include "wx/socket.h" -#include "wx/sckaddr.h" - -IMPLEMENT_ABSTRACT_CLASS(wxSockAddress, wxObject) -IMPLEMENT_ABSTRACT_CLASS(wxIPaddress, wxSockAddress) -IMPLEMENT_DYNAMIC_CLASS(wxIPV4address, wxIPaddress) -#if wxUSE_IPV6 -IMPLEMENT_DYNAMIC_CLASS(wxIPV6address, wxIPaddress) -#endif -#if defined(__UNIX__) && !defined(__WINDOWS__) && !defined(__WINE__) && (!defined(__WXMAC__) || defined(__DARWIN__)) -IMPLEMENT_DYNAMIC_CLASS(wxUNIXaddress, wxSockAddress) -#endif - -// --------------------------------------------------------------------------- -// wxSockAddress -// --------------------------------------------------------------------------- - -void wxSockAddress::Init() -{ - if ( !wxSocketBase::IsInitialized() ) - { - // we must do it before using GAddress_XXX functions - (void)wxSocketBase::Initialize(); - } -} - -wxSockAddress::wxSockAddress() -{ - Init(); - - m_address = GAddress_new(); -} - -wxSockAddress::wxSockAddress(const wxSockAddress& other) - : wxObject() -{ - Init(); - - m_address = GAddress_copy(other.m_address); -} - -wxSockAddress::~wxSockAddress() -{ - GAddress_destroy(m_address); -} - -void wxSockAddress::SetAddress(GAddress *address) -{ - if ( address != m_address ) - { - GAddress_destroy(m_address); - m_address = GAddress_copy(address); - } -} - -wxSockAddress& wxSockAddress::operator=(const wxSockAddress& addr) -{ - SetAddress(addr.GetAddress()); - return *this; -} - -void wxSockAddress::Clear() -{ - GAddress_destroy(m_address); - m_address = GAddress_new(); -} - -// --------------------------------------------------------------------------- -// wxIPaddress -// --------------------------------------------------------------------------- - -wxIPaddress::wxIPaddress() - : wxSockAddress() -{ -} - -wxIPaddress::wxIPaddress(const wxIPaddress& other) - : wxSockAddress(other) -{ -} - -wxIPaddress::~wxIPaddress() -{ -} - -// --------------------------------------------------------------------------- -// wxIPV4address -// --------------------------------------------------------------------------- - -wxIPV4address::wxIPV4address() - : wxIPaddress() -{ -} - -wxIPV4address::wxIPV4address(const wxIPV4address& other) - : wxIPaddress(other) -{ -} - -wxIPV4address::~wxIPV4address() -{ -} - -bool wxIPV4address::Hostname(const wxString& name) -{ - // Some people are sometimes fool. - if (name.empty()) - { - wxLogWarning( _("Trying to solve a NULL hostname: giving up") ); - return false; - } - m_origHostname = name; - return (GAddress_INET_SetHostName(m_address, name.mb_str()) == GSOCK_NOERROR); -} - -bool wxIPV4address::Hostname(unsigned long addr) -{ - bool rv = (GAddress_INET_SetHostAddress(m_address, addr) == GSOCK_NOERROR); - if (rv) - m_origHostname = Hostname(); - else - m_origHostname = wxEmptyString; - return rv; -} - -bool wxIPV4address::Service(const wxString& name) -{ - return (GAddress_INET_SetPortName(m_address, name.mb_str(), "tcp") == GSOCK_NOERROR); -} - -bool wxIPV4address::Service(unsigned short port) -{ - return (GAddress_INET_SetPort(m_address, port) == GSOCK_NOERROR); -} - -bool wxIPV4address::LocalHost() -{ - return (GAddress_INET_SetHostName(m_address, "localhost") == GSOCK_NOERROR); -} - -bool wxIPV4address::IsLocalHost() const -{ - return (Hostname() == wxT("localhost") || IPAddress() == wxT("127.0.0.1")); -} - -bool wxIPV4address::AnyAddress() -{ - return (GAddress_INET_SetAnyAddress(m_address) == GSOCK_NOERROR); -} - -wxString wxIPV4address::Hostname() const -{ - char hostname[1024]; - - hostname[0] = 0; - GAddress_INET_GetHostName(m_address, hostname, 1024); - return wxString::FromAscii(hostname); -} - -unsigned short wxIPV4address::Service() const -{ - return GAddress_INET_GetPort(m_address); -} - -wxSockAddress *wxIPV4address::Clone() const -{ - wxIPV4address *addr = new wxIPV4address(*this); - addr->m_origHostname = m_origHostname; - return addr; -} - -wxString wxIPV4address::IPAddress() const -{ - unsigned long raw = GAddress_INET_GetHostAddress(m_address); - return wxString::Format(_T("%lu.%lu.%lu.%lu"), - (raw>>24) & 0xff, - (raw>>16) & 0xff, - (raw>>8) & 0xff, - raw & 0xff - ); -} - -bool wxIPV4address::operator==(const wxIPV4address& addr) const -{ - return Hostname().Cmp(addr.Hostname().c_str()) == 0 && - Service() == addr.Service(); -} - -#if wxUSE_IPV6 -// --------------------------------------------------------------------------- -// wxIPV6address -// --------------------------------------------------------------------------- - -wxIPV6address::wxIPV6address() - : wxIPaddress() -{ -} - -wxIPV6address::wxIPV6address(const wxIPV6address& other) - : wxIPaddress(other) -{ -} - -wxIPV6address::~wxIPV6address() -{ -} - -bool wxIPV6address::Hostname(const wxString& name) -{ - if (name.empty()) - { - wxLogWarning( _("Trying to solve a NULL hostname: giving up") ); - return false; - } - return (GAddress_INET_SetHostName(m_address, name.mb_str()) == GSOCK_NOERROR); -} - -bool wxIPV6address::Hostname(unsigned char[16] WXUNUSED(addr)) -{ - return true; -} - -bool wxIPV6address::Service(const wxString& name) -{ - return (GAddress_INET_SetPortName(m_address, name.mb_str(), "tcp") == GSOCK_NOERROR); -} - -bool wxIPV6address::Service(unsigned short port) -{ - return (GAddress_INET_SetPort(m_address, port) == GSOCK_NOERROR); -} - -bool wxIPV6address::LocalHost() -{ - return (GAddress_INET_SetHostName(m_address, "localhost") == GSOCK_NOERROR); -} - -bool wxIPV6address::IsLocalHost() const -{ - return (Hostname() == wxT("localhost") || IPAddress() == wxT("127.0.0.1")); -} - -bool wxIPV6address::AnyAddress() -{ - return (GAddress_INET_SetAnyAddress(m_address) == GSOCK_NOERROR); -} - -wxString wxIPV6address::IPAddress() const -{ - unsigned long raw = GAddress_INET_GetHostAddress(m_address); - return wxString::Format( - _T("%u.%u.%u.%u"), - (unsigned char)((raw>>24) & 0xff), - (unsigned char)((raw>>16) & 0xff), - (unsigned char)((raw>>8) & 0xff), - (unsigned char)(raw & 0xff) - ); -} - -wxString wxIPV6address::Hostname() const -{ - char hostname[1024]; - - hostname[0] = 0; - GAddress_INET_GetHostName(m_address, hostname, 1024); - return wxString::FromAscii(hostname); -} - -unsigned short wxIPV6address::Service() const -{ - return GAddress_INET_GetPort(m_address); -} - -#endif // wxUSE_IPV6 - -#if defined(__UNIX__) && !defined(__WINDOWS__) && !defined(__WINE__) && (!defined(__WXMAC__) || defined(__DARWIN__)) - -// --------------------------------------------------------------------------- -// wxUNIXaddress -// --------------------------------------------------------------------------- - -wxUNIXaddress::wxUNIXaddress() - : wxSockAddress() -{ -} - -wxUNIXaddress::wxUNIXaddress(const wxUNIXaddress& other) - : wxSockAddress(other) -{ -} - -wxUNIXaddress::~wxUNIXaddress() -{ -} - -void wxUNIXaddress::Filename(const wxString& fname) -{ - GAddress_UNIX_SetPath(m_address, fname.fn_str()); -} - -wxString wxUNIXaddress::Filename() -{ - char path[1024]; - - path[0] = 0; - GAddress_UNIX_GetPath(m_address, path, 1024); - - return wxString::FromAscii(path); -} - -#endif // __UNIX__ - -#endif - // wxUSE_SOCKETS +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/sckaddr.cpp +// Purpose: Network address manager +// Author: Guilhem Lavaux +// Modified by: +// Created: 26/04/97 +// RCS-ID: $Id: sckaddr.cpp 38787 2006-04-18 07:24:35Z ABX $ +// Copyright: (c) 1997, 1998 Guilhem Lavaux +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_SOCKETS + +#ifndef WX_PRECOMP + #include "wx/object.h" + #include "wx/log.h" + #include "wx/intl.h" + + #include + #include + #include + + #if !defined(__MWERKS__) && !defined(__SALFORDC__) + #include + #endif +#endif // !WX_PRECOMP + +#include "wx/gsocket.h" +#include "wx/socket.h" +#include "wx/sckaddr.h" + +IMPLEMENT_ABSTRACT_CLASS(wxSockAddress, wxObject) +IMPLEMENT_ABSTRACT_CLASS(wxIPaddress, wxSockAddress) +IMPLEMENT_DYNAMIC_CLASS(wxIPV4address, wxIPaddress) +#if wxUSE_IPV6 +IMPLEMENT_DYNAMIC_CLASS(wxIPV6address, wxIPaddress) +#endif +#if defined(__UNIX__) && !defined(__WINDOWS__) && !defined(__WINE__) && (!defined(__WXMAC__) || defined(__DARWIN__)) +IMPLEMENT_DYNAMIC_CLASS(wxUNIXaddress, wxSockAddress) +#endif + +// --------------------------------------------------------------------------- +// wxSockAddress +// --------------------------------------------------------------------------- + +void wxSockAddress::Init() +{ + if ( !wxSocketBase::IsInitialized() ) + { + // we must do it before using GAddress_XXX functions + (void)wxSocketBase::Initialize(); + } +} + +wxSockAddress::wxSockAddress() +{ + Init(); + + m_address = GAddress_new(); +} + +wxSockAddress::wxSockAddress(const wxSockAddress& other) + : wxObject() +{ + Init(); + + m_address = GAddress_copy(other.m_address); +} + +wxSockAddress::~wxSockAddress() +{ + GAddress_destroy(m_address); +} + +void wxSockAddress::SetAddress(GAddress *address) +{ + if ( address != m_address ) + { + GAddress_destroy(m_address); + m_address = GAddress_copy(address); + } +} + +wxSockAddress& wxSockAddress::operator=(const wxSockAddress& addr) +{ + SetAddress(addr.GetAddress()); + return *this; +} + +void wxSockAddress::Clear() +{ + GAddress_destroy(m_address); + m_address = GAddress_new(); +} + +// --------------------------------------------------------------------------- +// wxIPaddress +// --------------------------------------------------------------------------- + +wxIPaddress::wxIPaddress() + : wxSockAddress() +{ +} + +wxIPaddress::wxIPaddress(const wxIPaddress& other) + : wxSockAddress(other) +{ +} + +wxIPaddress::~wxIPaddress() +{ +} + +// --------------------------------------------------------------------------- +// wxIPV4address +// --------------------------------------------------------------------------- + +wxIPV4address::wxIPV4address() + : wxIPaddress() +{ +} + +wxIPV4address::wxIPV4address(const wxIPV4address& other) + : wxIPaddress(other) +{ +} + +wxIPV4address::~wxIPV4address() +{ +} + +bool wxIPV4address::Hostname(const wxString& name) +{ + // Some people are sometimes fool. + if (name.empty()) + { + wxLogWarning( _("Trying to solve a NULL hostname: giving up") ); + return false; + } + m_origHostname = name; + return (GAddress_INET_SetHostName(m_address, name.mb_str()) == GSOCK_NOERROR); +} + +bool wxIPV4address::Hostname(unsigned long addr) +{ + bool rv = (GAddress_INET_SetHostAddress(m_address, addr) == GSOCK_NOERROR); + if (rv) + m_origHostname = Hostname(); + else + m_origHostname = wxEmptyString; + return rv; +} + +bool wxIPV4address::Service(const wxString& name) +{ + return (GAddress_INET_SetPortName(m_address, name.mb_str(), "tcp") == GSOCK_NOERROR); +} + +bool wxIPV4address::Service(unsigned short port) +{ + return (GAddress_INET_SetPort(m_address, port) == GSOCK_NOERROR); +} + +bool wxIPV4address::LocalHost() +{ + return (GAddress_INET_SetHostName(m_address, "localhost") == GSOCK_NOERROR); +} + +bool wxIPV4address::IsLocalHost() const +{ + return (Hostname() == wxT("localhost") || IPAddress() == wxT("127.0.0.1")); +} + +bool wxIPV4address::AnyAddress() +{ + return (GAddress_INET_SetAnyAddress(m_address) == GSOCK_NOERROR); +} + +wxString wxIPV4address::Hostname() const +{ + char hostname[1024]; + + hostname[0] = 0; + GAddress_INET_GetHostName(m_address, hostname, 1024); + return wxString::FromAscii(hostname); +} + +unsigned short wxIPV4address::Service() const +{ + return GAddress_INET_GetPort(m_address); +} + +wxSockAddress *wxIPV4address::Clone() const +{ + wxIPV4address *addr = new wxIPV4address(*this); + addr->m_origHostname = m_origHostname; + return addr; +} + +wxString wxIPV4address::IPAddress() const +{ + unsigned long raw = GAddress_INET_GetHostAddress(m_address); + return wxString::Format(_T("%lu.%lu.%lu.%lu"), + (raw>>24) & 0xff, + (raw>>16) & 0xff, + (raw>>8) & 0xff, + raw & 0xff + ); +} + +bool wxIPV4address::operator==(const wxIPV4address& addr) const +{ + return Hostname().Cmp(addr.Hostname().c_str()) == 0 && + Service() == addr.Service(); +} + +#if wxUSE_IPV6 +// --------------------------------------------------------------------------- +// wxIPV6address +// --------------------------------------------------------------------------- + +wxIPV6address::wxIPV6address() + : wxIPaddress() +{ +} + +wxIPV6address::wxIPV6address(const wxIPV6address& other) + : wxIPaddress(other) +{ +} + +wxIPV6address::~wxIPV6address() +{ +} + +bool wxIPV6address::Hostname(const wxString& name) +{ + if (name.empty()) + { + wxLogWarning( _("Trying to solve a NULL hostname: giving up") ); + return false; + } + return (GAddress_INET_SetHostName(m_address, name.mb_str()) == GSOCK_NOERROR); +} + +bool wxIPV6address::Hostname(unsigned char[16] WXUNUSED(addr)) +{ + return true; +} + +bool wxIPV6address::Service(const wxString& name) +{ + return (GAddress_INET_SetPortName(m_address, name.mb_str(), "tcp") == GSOCK_NOERROR); +} + +bool wxIPV6address::Service(unsigned short port) +{ + return (GAddress_INET_SetPort(m_address, port) == GSOCK_NOERROR); +} + +bool wxIPV6address::LocalHost() +{ + return (GAddress_INET_SetHostName(m_address, "localhost") == GSOCK_NOERROR); +} + +bool wxIPV6address::IsLocalHost() const +{ + return (Hostname() == wxT("localhost") || IPAddress() == wxT("127.0.0.1")); +} + +bool wxIPV6address::AnyAddress() +{ + return (GAddress_INET_SetAnyAddress(m_address) == GSOCK_NOERROR); +} + +wxString wxIPV6address::IPAddress() const +{ + unsigned long raw = GAddress_INET_GetHostAddress(m_address); + return wxString::Format( + _T("%u.%u.%u.%u"), + (unsigned char)((raw>>24) & 0xff), + (unsigned char)((raw>>16) & 0xff), + (unsigned char)((raw>>8) & 0xff), + (unsigned char)(raw & 0xff) + ); +} + +wxString wxIPV6address::Hostname() const +{ + char hostname[1024]; + + hostname[0] = 0; + GAddress_INET_GetHostName(m_address, hostname, 1024); + return wxString::FromAscii(hostname); +} + +unsigned short wxIPV6address::Service() const +{ + return GAddress_INET_GetPort(m_address); +} + +#endif // wxUSE_IPV6 + +#if defined(__UNIX__) && !defined(__WINDOWS__) && !defined(__WINE__) && (!defined(__WXMAC__) || defined(__DARWIN__)) + +// --------------------------------------------------------------------------- +// wxUNIXaddress +// --------------------------------------------------------------------------- + +wxUNIXaddress::wxUNIXaddress() + : wxSockAddress() +{ +} + +wxUNIXaddress::wxUNIXaddress(const wxUNIXaddress& other) + : wxSockAddress(other) +{ +} + +wxUNIXaddress::~wxUNIXaddress() +{ +} + +void wxUNIXaddress::Filename(const wxString& fname) +{ + GAddress_UNIX_SetPath(m_address, fname.fn_str()); +} + +wxString wxUNIXaddress::Filename() +{ + char path[1024]; + + path[0] = 0; + GAddress_UNIX_GetPath(m_address, path, 1024); + + return wxString::FromAscii(path); +} + +#endif // __UNIX__ + +#endif + // wxUSE_SOCKETS diff --git a/Externals/wxWidgets/src/common/sckfile.cpp b/Externals/wxWidgets/src/common/sckfile.cpp index b7ccf97ce7..87ef23a3bc 100644 --- a/Externals/wxWidgets/src/common/sckfile.cpp +++ b/Externals/wxWidgets/src/common/sckfile.cpp @@ -1,57 +1,57 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/sckfile.cpp -// Purpose: File protocol -// Author: Guilhem Lavaux -// Modified by: -// Created: 20/07/97 -// RCS-ID: $Id: sckfile.cpp 43836 2006-12-06 19:20:40Z VZ $ -// Copyright: (c) 1997, 1998 Guilhem Lavaux -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_STREAMS && wxUSE_PROTOCOL_FILE - -#ifndef WX_PRECOMP -#endif - -#include "wx/uri.h" -#include "wx/wfstream.h" -#include "wx/protocol/file.h" - -IMPLEMENT_DYNAMIC_CLASS(wxFileProto, wxProtocol) -IMPLEMENT_PROTOCOL(wxFileProto, wxT("file"), NULL, false) - -wxFileProto::wxFileProto() - : wxProtocol() -{ - m_error = wxPROTO_NOERR; -} - -wxFileProto::~wxFileProto() -{ -} - -wxInputStream *wxFileProto::GetInputStream(const wxString& path) -{ - wxFileInputStream *retval = new wxFileInputStream(wxURI::Unescape(path)); - if ( retval->Ok() ) - { - m_error = wxPROTO_NOERR; - - return retval; - } - - m_error = wxPROTO_NOFILE; - delete retval; - - return NULL; -} - -#endif // wxUSE_STREAMS && wxUSE_PROTOCOL_FILE +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/sckfile.cpp +// Purpose: File protocol +// Author: Guilhem Lavaux +// Modified by: +// Created: 20/07/97 +// RCS-ID: $Id: sckfile.cpp 43836 2006-12-06 19:20:40Z VZ $ +// Copyright: (c) 1997, 1998 Guilhem Lavaux +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_STREAMS && wxUSE_PROTOCOL_FILE + +#ifndef WX_PRECOMP +#endif + +#include "wx/uri.h" +#include "wx/wfstream.h" +#include "wx/protocol/file.h" + +IMPLEMENT_DYNAMIC_CLASS(wxFileProto, wxProtocol) +IMPLEMENT_PROTOCOL(wxFileProto, wxT("file"), NULL, false) + +wxFileProto::wxFileProto() + : wxProtocol() +{ + m_error = wxPROTO_NOERR; +} + +wxFileProto::~wxFileProto() +{ +} + +wxInputStream *wxFileProto::GetInputStream(const wxString& path) +{ + wxFileInputStream *retval = new wxFileInputStream(wxURI::Unescape(path)); + if ( retval->Ok() ) + { + m_error = wxPROTO_NOERR; + + return retval; + } + + m_error = wxPROTO_NOFILE; + delete retval; + + return NULL; +} + +#endif // wxUSE_STREAMS && wxUSE_PROTOCOL_FILE diff --git a/Externals/wxWidgets/src/common/sckipc.cpp b/Externals/wxWidgets/src/common/sckipc.cpp index 3f29491194..e170eb6599 100644 --- a/Externals/wxWidgets/src/common/sckipc.cpp +++ b/Externals/wxWidgets/src/common/sckipc.cpp @@ -1,769 +1,769 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/sckipc.cpp -// Purpose: Interprocess communication implementation (wxSocket version) -// Author: Julian Smart -// Modified by: Guilhem Lavaux (big rewrite) May 1997, 1998 -// Guillermo Rodriguez (updated for wxSocket v2) Jan 2000 -// (callbacks deprecated) Mar 2000 -// Vadim Zeitlin (added support for Unix sockets) Apr 2002 -// Created: 1993 -// RCS-ID: $Id: sckipc.cpp 41982 2006-10-13 09:00:06Z RR $ -// Copyright: (c) Julian Smart 1993 -// (c) Guilhem Lavaux 1997, 1998 -// (c) 2000 Guillermo Rodriguez -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// ========================================================================== -// declarations -// ========================================================================== - -// -------------------------------------------------------------------------- -// headers -// -------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_SOCKETS && wxUSE_IPC && wxUSE_STREAMS - -#include "wx/sckipc.h" - -#ifndef WX_PRECOMP - #include "wx/log.h" - #include "wx/event.h" - #include "wx/module.h" -#endif - -#include -#include -#include - -#include "wx/socket.h" - -// -------------------------------------------------------------------------- -// macros and constants -// -------------------------------------------------------------------------- - -// It seems to be already defined somewhere in the Xt includes. -#ifndef __XT__ -// Message codes -enum -{ - IPC_EXECUTE = 1, - IPC_REQUEST, - IPC_POKE, - IPC_ADVISE_START, - IPC_ADVISE_REQUEST, - IPC_ADVISE, - IPC_ADVISE_STOP, - IPC_REQUEST_REPLY, - IPC_FAIL, - IPC_CONNECT, - IPC_DISCONNECT -}; -#endif - -// All sockets will be created with the following flags -#define SCKIPC_FLAGS (wxSOCKET_WAITALL) - -// headers needed for umask() -#ifdef __UNIX_LIKE__ - #include - #include -#endif // __UNIX_LIKE__ - -// ---------------------------------------------------------------------------- -// private functions -// ---------------------------------------------------------------------------- - -// get the address object for the given server name, the caller must delete it -static wxSockAddress * -GetAddressFromName(const wxString& serverName, const wxString& host = wxEmptyString) -{ - // we always use INET sockets under non-Unix systems -#if defined(__UNIX__) && !defined(__WINDOWS__) && !defined(__WINE__) && (!defined(__WXMAC__) || defined(__DARWIN__)) - // under Unix, if the server name looks like a path, create a AF_UNIX - // socket instead of AF_INET one - if ( serverName.Find(_T('/')) != wxNOT_FOUND ) - { - wxUNIXaddress *addr = new wxUNIXaddress; - addr->Filename(serverName); - - return addr; - } -#endif // Unix/!Unix - { - wxIPV4address *addr = new wxIPV4address; - addr->Service(serverName); - if ( !host.empty() ) - { - addr->Hostname(host); - } - - return addr; - } -} - -// -------------------------------------------------------------------------- -// wxTCPEventHandler stuff (private class) -// -------------------------------------------------------------------------- - -class wxTCPEventHandler : public wxEvtHandler -{ -public: - wxTCPEventHandler() : wxEvtHandler() {} - - void Client_OnRequest(wxSocketEvent& event); - void Server_OnRequest(wxSocketEvent& event); - - DECLARE_EVENT_TABLE() - DECLARE_NO_COPY_CLASS(wxTCPEventHandler) -}; - -enum -{ - _CLIENT_ONREQUEST_ID = 1000, - _SERVER_ONREQUEST_ID -}; - -static wxTCPEventHandler *gs_handler = NULL; - -// ========================================================================== -// implementation -// ========================================================================== - -IMPLEMENT_DYNAMIC_CLASS(wxTCPServer, wxServerBase) -IMPLEMENT_DYNAMIC_CLASS(wxTCPClient, wxClientBase) -IMPLEMENT_CLASS(wxTCPConnection, wxConnectionBase) - -// -------------------------------------------------------------------------- -// wxTCPClient -// -------------------------------------------------------------------------- - -wxTCPClient::wxTCPClient () : wxClientBase() -{ -} - -wxTCPClient::~wxTCPClient () -{ -} - -bool wxTCPClient::ValidHost(const wxString& host) -{ - wxIPV4address addr; - - return addr.Hostname(host); -} - -wxConnectionBase *wxTCPClient::MakeConnection (const wxString& host, - const wxString& serverName, - const wxString& topic) -{ - wxSockAddress *addr = GetAddressFromName(serverName, host); - if ( !addr ) - return NULL; - - wxSocketClient *client = new wxSocketClient(SCKIPC_FLAGS); - wxSocketStream *stream = new wxSocketStream(*client); - wxDataInputStream *data_is = new wxDataInputStream(*stream); - wxDataOutputStream *data_os = new wxDataOutputStream(*stream); - - bool ok = client->Connect(*addr); - delete addr; - - if ( ok ) - { - unsigned char msg; - - // Send topic name, and enquire whether this has succeeded - data_os->Write8(IPC_CONNECT); - data_os->WriteString(topic); - - msg = data_is->Read8(); - - // OK! Confirmation. - if (msg == IPC_CONNECT) - { - wxTCPConnection *connection = (wxTCPConnection *)OnMakeConnection (); - - if (connection) - { - if (connection->IsKindOf(CLASSINFO(wxTCPConnection))) - { - connection->m_topic = topic; - connection->m_sock = client; - connection->m_sockstrm = stream; - connection->m_codeci = data_is; - connection->m_codeco = data_os; - client->SetEventHandler(*gs_handler, _CLIENT_ONREQUEST_ID); - client->SetClientData(connection); - client->SetNotify(wxSOCKET_INPUT_FLAG | wxSOCKET_LOST_FLAG); - client->Notify(true); - return connection; - } - else - { - delete connection; - // and fall through to delete everything else - } - } - } - } - - // Something went wrong, delete everything - delete data_is; - delete data_os; - delete stream; - client->Destroy(); - - return NULL; -} - -wxConnectionBase *wxTCPClient::OnMakeConnection() -{ - return new wxTCPConnection(); -} - -// -------------------------------------------------------------------------- -// wxTCPServer -// -------------------------------------------------------------------------- - -wxTCPServer::wxTCPServer () : wxServerBase() -{ - m_server = NULL; -} - -bool wxTCPServer::Create(const wxString& serverName) -{ - // Destroy previous server, if any - if (m_server) - { - m_server->SetClientData(NULL); - m_server->Destroy(); - m_server = NULL; - } - - wxSockAddress *addr = GetAddressFromName(serverName); - if ( !addr ) - return false; - -#ifdef __UNIX_LIKE__ - mode_t umaskOld; - if ( addr->Type() == wxSockAddress::UNIX ) - { - // ensure that the file doesn't exist as otherwise calling socket() would - // fail - int rc = remove(serverName.fn_str()); - if ( rc < 0 && errno != ENOENT ) - { - delete addr; - - return false; - } - - // also set the umask to prevent the others from reading our file - umaskOld = umask(077); - } - else - { - // unused anyhow but shut down the compiler warnings - umaskOld = 0; - } -#endif // __UNIX_LIKE__ - - // Create a socket listening on the specified port - m_server = new wxSocketServer(*addr, SCKIPC_FLAGS); - -#ifdef __UNIX_LIKE__ - if ( addr->Type() == wxSockAddress::UNIX ) - { - // restore the umask - umask(umaskOld); - - // save the file name to remove it later - m_filename = serverName; - } -#endif // __UNIX_LIKE__ - - delete addr; - - if (!m_server->Ok()) - { - m_server->Destroy(); - m_server = NULL; - - return false; - } - - m_server->SetEventHandler(*gs_handler, _SERVER_ONREQUEST_ID); - m_server->SetClientData(this); - m_server->SetNotify(wxSOCKET_CONNECTION_FLAG); - m_server->Notify(true); - - return true; -} - -wxTCPServer::~wxTCPServer() -{ - if (m_server) - { - m_server->SetClientData(NULL); - m_server->Destroy(); - } - -#ifdef __UNIX_LIKE__ - if ( !m_filename.empty() ) - { - if ( remove(m_filename.fn_str()) != 0 ) - { - wxLogDebug(_T("Stale AF_UNIX file '%s' left."), m_filename.c_str()); - } - } -#endif // __UNIX_LIKE__ -} - -wxConnectionBase *wxTCPServer::OnAcceptConnection( const wxString& WXUNUSED(topic) ) -{ - return new wxTCPConnection(); -} - -// -------------------------------------------------------------------------- -// wxTCPConnection -// -------------------------------------------------------------------------- - -wxTCPConnection::wxTCPConnection () : wxConnectionBase() -{ - m_sock = NULL; - m_sockstrm = NULL; - m_codeci = NULL; - m_codeco = NULL; -} - -wxTCPConnection::wxTCPConnection(wxChar *buffer, int size) - : wxConnectionBase(buffer, size) -{ - m_sock = NULL; - m_sockstrm = NULL; - m_codeci = NULL; - m_codeco = NULL; -} - -wxTCPConnection::~wxTCPConnection () -{ - Disconnect(); - - if (m_sock) - { - m_sock->SetClientData(NULL); - m_sock->Destroy(); - } - - /* Delete after destroy */ - wxDELETE(m_codeci); - wxDELETE(m_codeco); - wxDELETE(m_sockstrm); -} - -void wxTCPConnection::Compress(bool WXUNUSED(on)) -{ - // Use wxLZWStream -} - -// Calls that CLIENT can make. -bool wxTCPConnection::Disconnect () -{ - if ( !GetConnected() ) - return true; - // Send the the disconnect message to the peer. - m_codeco->Write8(IPC_DISCONNECT); - m_sock->Notify(false); - m_sock->Close(); - SetConnected(false); - - return true; -} - -bool wxTCPConnection::Execute(const wxChar *data, int size, wxIPCFormat format) -{ - if (!m_sock->IsConnected()) - return false; - - // Prepare EXECUTE message - m_codeco->Write8(IPC_EXECUTE); - m_codeco->Write8(format); - - if (size < 0) - size = (wxStrlen(data) + 1) * sizeof(wxChar); // includes final NUL - - m_codeco->Write32(size); - m_sockstrm->Write(data, size); - - return true; -} - -wxChar *wxTCPConnection::Request (const wxString& item, int *size, wxIPCFormat format) -{ - if (!m_sock->IsConnected()) - return NULL; - - m_codeco->Write8(IPC_REQUEST); - m_codeco->WriteString(item); - m_codeco->Write8(format); - - // If Unpack doesn't initialize it. - int ret; - - ret = m_codeci->Read8(); - if (ret == IPC_FAIL) - return NULL; - else - { - size_t s; - - s = m_codeci->Read32(); - - wxChar *data = GetBufferAtLeast( s ); - wxASSERT_MSG(data != NULL, - _T("Buffer too small in wxTCPConnection::Request") ); - m_sockstrm->Read(data, s); - - if (size) - *size = s; - return data; - } -} - -bool wxTCPConnection::Poke (const wxString& item, wxChar *data, int size, wxIPCFormat format) -{ - if (!m_sock->IsConnected()) - return false; - - m_codeco->Write8(IPC_POKE); - m_codeco->WriteString(item); - m_codeco->Write8(format); - - if (size < 0) - size = (wxStrlen(data) + 1) * sizeof(wxChar); // includes final NUL - - m_codeco->Write32(size); - m_sockstrm->Write(data, size); - - return true; -} - -bool wxTCPConnection::StartAdvise (const wxString& item) -{ - int ret; - - if (!m_sock->IsConnected()) - return false; - - m_codeco->Write8(IPC_ADVISE_START); - m_codeco->WriteString(item); - - ret = m_codeci->Read8(); - - if (ret != IPC_FAIL) - return true; - else - return false; -} - -bool wxTCPConnection::StopAdvise (const wxString& item) -{ - int msg; - - if (!m_sock->IsConnected()) - return false; - - m_codeco->Write8(IPC_ADVISE_STOP); - m_codeco->WriteString(item); - - msg = m_codeci->Read8(); - - if (msg != IPC_FAIL) - return true; - else - return false; -} - -// Calls that SERVER can make -bool wxTCPConnection::Advise (const wxString& item, - wxChar *data, int size, wxIPCFormat format) -{ - if (!m_sock->IsConnected()) - return false; - - m_codeco->Write8(IPC_ADVISE); - m_codeco->WriteString(item); - m_codeco->Write8(format); - - if (size < 0) - size = (wxStrlen(data) + 1) * sizeof(wxChar); // includes final NUL - - m_codeco->Write32(size); - m_sockstrm->Write(data, size); - - return true; -} - -// -------------------------------------------------------------------------- -// wxTCPEventHandler (private class) -// -------------------------------------------------------------------------- - -BEGIN_EVENT_TABLE(wxTCPEventHandler, wxEvtHandler) - EVT_SOCKET(_CLIENT_ONREQUEST_ID, wxTCPEventHandler::Client_OnRequest) - EVT_SOCKET(_SERVER_ONREQUEST_ID, wxTCPEventHandler::Server_OnRequest) -END_EVENT_TABLE() - -void wxTCPEventHandler::Client_OnRequest(wxSocketEvent &event) -{ - wxSocketBase *sock = event.GetSocket(); - if (!sock) { /* No socket, no glory */ - return ; - } - wxSocketNotify evt = event.GetSocketEvent(); - wxTCPConnection *connection = (wxTCPConnection *)(sock->GetClientData()); - - // This socket is being deleted; skip this event - if (!connection) - return; - - wxDataInputStream *codeci; - wxDataOutputStream *codeco; - wxSocketStream *sockstrm; - wxString topic_name = connection->m_topic; - wxString item; - - // We lost the connection: destroy everything - if (evt == wxSOCKET_LOST) - { - sock->Notify(false); - sock->Close(); - connection->OnDisconnect(); - return; - } - - // Receive message number. - codeci = connection->m_codeci; - codeco = connection->m_codeco; - sockstrm = connection->m_sockstrm; - int msg = codeci->Read8(); - - switch (msg) - { - case IPC_EXECUTE: - { - wxChar *data; - size_t size; - wxIPCFormat format; - - format = (wxIPCFormat)codeci->Read8(); - size = codeci->Read32(); - - data = connection->GetBufferAtLeast( size ); - wxASSERT_MSG(data != NULL, - _T("Buffer too small in wxTCPEventHandler::Client_OnRequest") ); - sockstrm->Read(data, size); - - connection->OnExecute (topic_name, data, size, format); - - break; - } - case IPC_ADVISE: - { - wxChar *data; - size_t size; - wxIPCFormat format; - - item = codeci->ReadString(); - format = (wxIPCFormat)codeci->Read8(); - size = codeci->Read32(); - data = connection->GetBufferAtLeast( size ); - wxASSERT_MSG(data != NULL, - _T("Buffer too small in wxTCPEventHandler::Client_OnRequest") ); - sockstrm->Read(data, size); - - connection->OnAdvise (topic_name, item, data, size, format); - - break; - } - case IPC_ADVISE_START: - { - item = codeci->ReadString(); - - bool ok = connection->OnStartAdvise (topic_name, item); - if (ok) - codeco->Write8(IPC_ADVISE_START); - else - codeco->Write8(IPC_FAIL); - - break; - } - case IPC_ADVISE_STOP: - { - item = codeci->ReadString(); - - bool ok = connection->OnStopAdvise (topic_name, item); - if (ok) - codeco->Write8(IPC_ADVISE_STOP); - else - codeco->Write8(IPC_FAIL); - - break; - } - case IPC_POKE: - { - wxIPCFormat format; - size_t size; - wxChar *data; - - item = codeci->ReadString(); - format = (wxIPCFormat)codeci->Read8(); - size = codeci->Read32(); - data = connection->GetBufferAtLeast( size ); - wxASSERT_MSG(data != NULL, - _T("Buffer too small in wxTCPEventHandler::Client_OnRequest") ); - sockstrm->Read(data, size); - - connection->OnPoke (topic_name, item, data, size, format); - - break; - } - case IPC_REQUEST: - { - wxIPCFormat format; - - item = codeci->ReadString(); - format = (wxIPCFormat)codeci->Read8(); - - int user_size = -1; - wxChar *user_data = connection->OnRequest (topic_name, item, &user_size, format); - - if (user_data) - { - codeco->Write8(IPC_REQUEST_REPLY); - - if (user_size == -1) - user_size = (wxStrlen(user_data) + 1) * sizeof(wxChar); // includes final NUL - - codeco->Write32(user_size); - sockstrm->Write(user_data, user_size); - } - else - codeco->Write8(IPC_FAIL); - - break; - } - case IPC_DISCONNECT: - { - sock->Notify(false); - sock->Close(); - connection->SetConnected(false); - connection->OnDisconnect(); - break; - } - default: - codeco->Write8(IPC_FAIL); - break; - } -} - -void wxTCPEventHandler::Server_OnRequest(wxSocketEvent &event) -{ - wxSocketServer *server = (wxSocketServer *) event.GetSocket(); - if (!server) { /* No server, Then exit */ - return ; - } - wxTCPServer *ipcserv = (wxTCPServer *) server->GetClientData(); - - // This socket is being deleted; skip this event - if (!ipcserv) - return; - - if (event.GetSocketEvent() != wxSOCKET_CONNECTION) - return; - - // Accept the connection, getting a new socket - wxSocketBase *sock = server->Accept(); - if (!sock) { /* No socket, no glory */ - return ; - } - if (!sock->Ok()) - { - sock->Destroy(); - return; - } - - wxSocketStream *stream = new wxSocketStream(*sock); - wxDataInputStream *codeci = new wxDataInputStream(*stream); - wxDataOutputStream *codeco = new wxDataOutputStream(*stream); - - int msg; - msg = codeci->Read8(); - - if (msg == IPC_CONNECT) - { - wxString topic_name; - topic_name = codeci->ReadString(); - - wxTCPConnection *new_connection = - (wxTCPConnection *)ipcserv->OnAcceptConnection (topic_name); - - if (new_connection) - { - if (new_connection->IsKindOf(CLASSINFO(wxTCPConnection))) - { - // Acknowledge success - codeco->Write8(IPC_CONNECT); - new_connection->m_topic = topic_name; - new_connection->m_sock = sock; - new_connection->m_sockstrm = stream; - new_connection->m_codeci = codeci; - new_connection->m_codeco = codeco; - sock->SetEventHandler(*gs_handler, _CLIENT_ONREQUEST_ID); - sock->SetClientData(new_connection); - sock->SetNotify(wxSOCKET_INPUT_FLAG | wxSOCKET_LOST_FLAG); - sock->Notify(true); - return; - } - else - { - delete new_connection; - // and fall through to delete everything else - } - } - } - - // Something went wrong, send failure message and delete everything - codeco->Write8(IPC_FAIL); - - delete codeco; - delete codeci; - delete stream; - sock->Destroy(); -} - -// -------------------------------------------------------------------------- -// wxTCPEventHandlerModule (private class) -// -------------------------------------------------------------------------- - -class wxTCPEventHandlerModule: public wxModule -{ - DECLARE_DYNAMIC_CLASS(wxTCPEventHandlerModule) - -public: - bool OnInit() { gs_handler = new wxTCPEventHandler(); return true; } - void OnExit() { wxDELETE(gs_handler); } -}; - -IMPLEMENT_DYNAMIC_CLASS(wxTCPEventHandlerModule, wxModule) - - -#endif - // wxUSE_SOCKETS && wxUSE_IPC && wxUSE_STREAMS +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/sckipc.cpp +// Purpose: Interprocess communication implementation (wxSocket version) +// Author: Julian Smart +// Modified by: Guilhem Lavaux (big rewrite) May 1997, 1998 +// Guillermo Rodriguez (updated for wxSocket v2) Jan 2000 +// (callbacks deprecated) Mar 2000 +// Vadim Zeitlin (added support for Unix sockets) Apr 2002 +// Created: 1993 +// RCS-ID: $Id: sckipc.cpp 41982 2006-10-13 09:00:06Z RR $ +// Copyright: (c) Julian Smart 1993 +// (c) Guilhem Lavaux 1997, 1998 +// (c) 2000 Guillermo Rodriguez +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ========================================================================== +// declarations +// ========================================================================== + +// -------------------------------------------------------------------------- +// headers +// -------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_SOCKETS && wxUSE_IPC && wxUSE_STREAMS + +#include "wx/sckipc.h" + +#ifndef WX_PRECOMP + #include "wx/log.h" + #include "wx/event.h" + #include "wx/module.h" +#endif + +#include +#include +#include + +#include "wx/socket.h" + +// -------------------------------------------------------------------------- +// macros and constants +// -------------------------------------------------------------------------- + +// It seems to be already defined somewhere in the Xt includes. +#ifndef __XT__ +// Message codes +enum +{ + IPC_EXECUTE = 1, + IPC_REQUEST, + IPC_POKE, + IPC_ADVISE_START, + IPC_ADVISE_REQUEST, + IPC_ADVISE, + IPC_ADVISE_STOP, + IPC_REQUEST_REPLY, + IPC_FAIL, + IPC_CONNECT, + IPC_DISCONNECT +}; +#endif + +// All sockets will be created with the following flags +#define SCKIPC_FLAGS (wxSOCKET_WAITALL) + +// headers needed for umask() +#ifdef __UNIX_LIKE__ + #include + #include +#endif // __UNIX_LIKE__ + +// ---------------------------------------------------------------------------- +// private functions +// ---------------------------------------------------------------------------- + +// get the address object for the given server name, the caller must delete it +static wxSockAddress * +GetAddressFromName(const wxString& serverName, const wxString& host = wxEmptyString) +{ + // we always use INET sockets under non-Unix systems +#if defined(__UNIX__) && !defined(__WINDOWS__) && !defined(__WINE__) && (!defined(__WXMAC__) || defined(__DARWIN__)) + // under Unix, if the server name looks like a path, create a AF_UNIX + // socket instead of AF_INET one + if ( serverName.Find(_T('/')) != wxNOT_FOUND ) + { + wxUNIXaddress *addr = new wxUNIXaddress; + addr->Filename(serverName); + + return addr; + } +#endif // Unix/!Unix + { + wxIPV4address *addr = new wxIPV4address; + addr->Service(serverName); + if ( !host.empty() ) + { + addr->Hostname(host); + } + + return addr; + } +} + +// -------------------------------------------------------------------------- +// wxTCPEventHandler stuff (private class) +// -------------------------------------------------------------------------- + +class wxTCPEventHandler : public wxEvtHandler +{ +public: + wxTCPEventHandler() : wxEvtHandler() {} + + void Client_OnRequest(wxSocketEvent& event); + void Server_OnRequest(wxSocketEvent& event); + + DECLARE_EVENT_TABLE() + DECLARE_NO_COPY_CLASS(wxTCPEventHandler) +}; + +enum +{ + _CLIENT_ONREQUEST_ID = 1000, + _SERVER_ONREQUEST_ID +}; + +static wxTCPEventHandler *gs_handler = NULL; + +// ========================================================================== +// implementation +// ========================================================================== + +IMPLEMENT_DYNAMIC_CLASS(wxTCPServer, wxServerBase) +IMPLEMENT_DYNAMIC_CLASS(wxTCPClient, wxClientBase) +IMPLEMENT_CLASS(wxTCPConnection, wxConnectionBase) + +// -------------------------------------------------------------------------- +// wxTCPClient +// -------------------------------------------------------------------------- + +wxTCPClient::wxTCPClient () : wxClientBase() +{ +} + +wxTCPClient::~wxTCPClient () +{ +} + +bool wxTCPClient::ValidHost(const wxString& host) +{ + wxIPV4address addr; + + return addr.Hostname(host); +} + +wxConnectionBase *wxTCPClient::MakeConnection (const wxString& host, + const wxString& serverName, + const wxString& topic) +{ + wxSockAddress *addr = GetAddressFromName(serverName, host); + if ( !addr ) + return NULL; + + wxSocketClient *client = new wxSocketClient(SCKIPC_FLAGS); + wxSocketStream *stream = new wxSocketStream(*client); + wxDataInputStream *data_is = new wxDataInputStream(*stream); + wxDataOutputStream *data_os = new wxDataOutputStream(*stream); + + bool ok = client->Connect(*addr); + delete addr; + + if ( ok ) + { + unsigned char msg; + + // Send topic name, and enquire whether this has succeeded + data_os->Write8(IPC_CONNECT); + data_os->WriteString(topic); + + msg = data_is->Read8(); + + // OK! Confirmation. + if (msg == IPC_CONNECT) + { + wxTCPConnection *connection = (wxTCPConnection *)OnMakeConnection (); + + if (connection) + { + if (connection->IsKindOf(CLASSINFO(wxTCPConnection))) + { + connection->m_topic = topic; + connection->m_sock = client; + connection->m_sockstrm = stream; + connection->m_codeci = data_is; + connection->m_codeco = data_os; + client->SetEventHandler(*gs_handler, _CLIENT_ONREQUEST_ID); + client->SetClientData(connection); + client->SetNotify(wxSOCKET_INPUT_FLAG | wxSOCKET_LOST_FLAG); + client->Notify(true); + return connection; + } + else + { + delete connection; + // and fall through to delete everything else + } + } + } + } + + // Something went wrong, delete everything + delete data_is; + delete data_os; + delete stream; + client->Destroy(); + + return NULL; +} + +wxConnectionBase *wxTCPClient::OnMakeConnection() +{ + return new wxTCPConnection(); +} + +// -------------------------------------------------------------------------- +// wxTCPServer +// -------------------------------------------------------------------------- + +wxTCPServer::wxTCPServer () : wxServerBase() +{ + m_server = NULL; +} + +bool wxTCPServer::Create(const wxString& serverName) +{ + // Destroy previous server, if any + if (m_server) + { + m_server->SetClientData(NULL); + m_server->Destroy(); + m_server = NULL; + } + + wxSockAddress *addr = GetAddressFromName(serverName); + if ( !addr ) + return false; + +#ifdef __UNIX_LIKE__ + mode_t umaskOld; + if ( addr->Type() == wxSockAddress::UNIX ) + { + // ensure that the file doesn't exist as otherwise calling socket() would + // fail + int rc = remove(serverName.fn_str()); + if ( rc < 0 && errno != ENOENT ) + { + delete addr; + + return false; + } + + // also set the umask to prevent the others from reading our file + umaskOld = umask(077); + } + else + { + // unused anyhow but shut down the compiler warnings + umaskOld = 0; + } +#endif // __UNIX_LIKE__ + + // Create a socket listening on the specified port + m_server = new wxSocketServer(*addr, SCKIPC_FLAGS); + +#ifdef __UNIX_LIKE__ + if ( addr->Type() == wxSockAddress::UNIX ) + { + // restore the umask + umask(umaskOld); + + // save the file name to remove it later + m_filename = serverName; + } +#endif // __UNIX_LIKE__ + + delete addr; + + if (!m_server->Ok()) + { + m_server->Destroy(); + m_server = NULL; + + return false; + } + + m_server->SetEventHandler(*gs_handler, _SERVER_ONREQUEST_ID); + m_server->SetClientData(this); + m_server->SetNotify(wxSOCKET_CONNECTION_FLAG); + m_server->Notify(true); + + return true; +} + +wxTCPServer::~wxTCPServer() +{ + if (m_server) + { + m_server->SetClientData(NULL); + m_server->Destroy(); + } + +#ifdef __UNIX_LIKE__ + if ( !m_filename.empty() ) + { + if ( remove(m_filename.fn_str()) != 0 ) + { + wxLogDebug(_T("Stale AF_UNIX file '%s' left."), m_filename.c_str()); + } + } +#endif // __UNIX_LIKE__ +} + +wxConnectionBase *wxTCPServer::OnAcceptConnection( const wxString& WXUNUSED(topic) ) +{ + return new wxTCPConnection(); +} + +// -------------------------------------------------------------------------- +// wxTCPConnection +// -------------------------------------------------------------------------- + +wxTCPConnection::wxTCPConnection () : wxConnectionBase() +{ + m_sock = NULL; + m_sockstrm = NULL; + m_codeci = NULL; + m_codeco = NULL; +} + +wxTCPConnection::wxTCPConnection(wxChar *buffer, int size) + : wxConnectionBase(buffer, size) +{ + m_sock = NULL; + m_sockstrm = NULL; + m_codeci = NULL; + m_codeco = NULL; +} + +wxTCPConnection::~wxTCPConnection () +{ + Disconnect(); + + if (m_sock) + { + m_sock->SetClientData(NULL); + m_sock->Destroy(); + } + + /* Delete after destroy */ + wxDELETE(m_codeci); + wxDELETE(m_codeco); + wxDELETE(m_sockstrm); +} + +void wxTCPConnection::Compress(bool WXUNUSED(on)) +{ + // Use wxLZWStream +} + +// Calls that CLIENT can make. +bool wxTCPConnection::Disconnect () +{ + if ( !GetConnected() ) + return true; + // Send the the disconnect message to the peer. + m_codeco->Write8(IPC_DISCONNECT); + m_sock->Notify(false); + m_sock->Close(); + SetConnected(false); + + return true; +} + +bool wxTCPConnection::Execute(const wxChar *data, int size, wxIPCFormat format) +{ + if (!m_sock->IsConnected()) + return false; + + // Prepare EXECUTE message + m_codeco->Write8(IPC_EXECUTE); + m_codeco->Write8(format); + + if (size < 0) + size = (wxStrlen(data) + 1) * sizeof(wxChar); // includes final NUL + + m_codeco->Write32(size); + m_sockstrm->Write(data, size); + + return true; +} + +wxChar *wxTCPConnection::Request (const wxString& item, int *size, wxIPCFormat format) +{ + if (!m_sock->IsConnected()) + return NULL; + + m_codeco->Write8(IPC_REQUEST); + m_codeco->WriteString(item); + m_codeco->Write8(format); + + // If Unpack doesn't initialize it. + int ret; + + ret = m_codeci->Read8(); + if (ret == IPC_FAIL) + return NULL; + else + { + size_t s; + + s = m_codeci->Read32(); + + wxChar *data = GetBufferAtLeast( s ); + wxASSERT_MSG(data != NULL, + _T("Buffer too small in wxTCPConnection::Request") ); + m_sockstrm->Read(data, s); + + if (size) + *size = s; + return data; + } +} + +bool wxTCPConnection::Poke (const wxString& item, wxChar *data, int size, wxIPCFormat format) +{ + if (!m_sock->IsConnected()) + return false; + + m_codeco->Write8(IPC_POKE); + m_codeco->WriteString(item); + m_codeco->Write8(format); + + if (size < 0) + size = (wxStrlen(data) + 1) * sizeof(wxChar); // includes final NUL + + m_codeco->Write32(size); + m_sockstrm->Write(data, size); + + return true; +} + +bool wxTCPConnection::StartAdvise (const wxString& item) +{ + int ret; + + if (!m_sock->IsConnected()) + return false; + + m_codeco->Write8(IPC_ADVISE_START); + m_codeco->WriteString(item); + + ret = m_codeci->Read8(); + + if (ret != IPC_FAIL) + return true; + else + return false; +} + +bool wxTCPConnection::StopAdvise (const wxString& item) +{ + int msg; + + if (!m_sock->IsConnected()) + return false; + + m_codeco->Write8(IPC_ADVISE_STOP); + m_codeco->WriteString(item); + + msg = m_codeci->Read8(); + + if (msg != IPC_FAIL) + return true; + else + return false; +} + +// Calls that SERVER can make +bool wxTCPConnection::Advise (const wxString& item, + wxChar *data, int size, wxIPCFormat format) +{ + if (!m_sock->IsConnected()) + return false; + + m_codeco->Write8(IPC_ADVISE); + m_codeco->WriteString(item); + m_codeco->Write8(format); + + if (size < 0) + size = (wxStrlen(data) + 1) * sizeof(wxChar); // includes final NUL + + m_codeco->Write32(size); + m_sockstrm->Write(data, size); + + return true; +} + +// -------------------------------------------------------------------------- +// wxTCPEventHandler (private class) +// -------------------------------------------------------------------------- + +BEGIN_EVENT_TABLE(wxTCPEventHandler, wxEvtHandler) + EVT_SOCKET(_CLIENT_ONREQUEST_ID, wxTCPEventHandler::Client_OnRequest) + EVT_SOCKET(_SERVER_ONREQUEST_ID, wxTCPEventHandler::Server_OnRequest) +END_EVENT_TABLE() + +void wxTCPEventHandler::Client_OnRequest(wxSocketEvent &event) +{ + wxSocketBase *sock = event.GetSocket(); + if (!sock) { /* No socket, no glory */ + return ; + } + wxSocketNotify evt = event.GetSocketEvent(); + wxTCPConnection *connection = (wxTCPConnection *)(sock->GetClientData()); + + // This socket is being deleted; skip this event + if (!connection) + return; + + wxDataInputStream *codeci; + wxDataOutputStream *codeco; + wxSocketStream *sockstrm; + wxString topic_name = connection->m_topic; + wxString item; + + // We lost the connection: destroy everything + if (evt == wxSOCKET_LOST) + { + sock->Notify(false); + sock->Close(); + connection->OnDisconnect(); + return; + } + + // Receive message number. + codeci = connection->m_codeci; + codeco = connection->m_codeco; + sockstrm = connection->m_sockstrm; + int msg = codeci->Read8(); + + switch (msg) + { + case IPC_EXECUTE: + { + wxChar *data; + size_t size; + wxIPCFormat format; + + format = (wxIPCFormat)codeci->Read8(); + size = codeci->Read32(); + + data = connection->GetBufferAtLeast( size ); + wxASSERT_MSG(data != NULL, + _T("Buffer too small in wxTCPEventHandler::Client_OnRequest") ); + sockstrm->Read(data, size); + + connection->OnExecute (topic_name, data, size, format); + + break; + } + case IPC_ADVISE: + { + wxChar *data; + size_t size; + wxIPCFormat format; + + item = codeci->ReadString(); + format = (wxIPCFormat)codeci->Read8(); + size = codeci->Read32(); + data = connection->GetBufferAtLeast( size ); + wxASSERT_MSG(data != NULL, + _T("Buffer too small in wxTCPEventHandler::Client_OnRequest") ); + sockstrm->Read(data, size); + + connection->OnAdvise (topic_name, item, data, size, format); + + break; + } + case IPC_ADVISE_START: + { + item = codeci->ReadString(); + + bool ok = connection->OnStartAdvise (topic_name, item); + if (ok) + codeco->Write8(IPC_ADVISE_START); + else + codeco->Write8(IPC_FAIL); + + break; + } + case IPC_ADVISE_STOP: + { + item = codeci->ReadString(); + + bool ok = connection->OnStopAdvise (topic_name, item); + if (ok) + codeco->Write8(IPC_ADVISE_STOP); + else + codeco->Write8(IPC_FAIL); + + break; + } + case IPC_POKE: + { + wxIPCFormat format; + size_t size; + wxChar *data; + + item = codeci->ReadString(); + format = (wxIPCFormat)codeci->Read8(); + size = codeci->Read32(); + data = connection->GetBufferAtLeast( size ); + wxASSERT_MSG(data != NULL, + _T("Buffer too small in wxTCPEventHandler::Client_OnRequest") ); + sockstrm->Read(data, size); + + connection->OnPoke (topic_name, item, data, size, format); + + break; + } + case IPC_REQUEST: + { + wxIPCFormat format; + + item = codeci->ReadString(); + format = (wxIPCFormat)codeci->Read8(); + + int user_size = -1; + wxChar *user_data = connection->OnRequest (topic_name, item, &user_size, format); + + if (user_data) + { + codeco->Write8(IPC_REQUEST_REPLY); + + if (user_size == -1) + user_size = (wxStrlen(user_data) + 1) * sizeof(wxChar); // includes final NUL + + codeco->Write32(user_size); + sockstrm->Write(user_data, user_size); + } + else + codeco->Write8(IPC_FAIL); + + break; + } + case IPC_DISCONNECT: + { + sock->Notify(false); + sock->Close(); + connection->SetConnected(false); + connection->OnDisconnect(); + break; + } + default: + codeco->Write8(IPC_FAIL); + break; + } +} + +void wxTCPEventHandler::Server_OnRequest(wxSocketEvent &event) +{ + wxSocketServer *server = (wxSocketServer *) event.GetSocket(); + if (!server) { /* No server, Then exit */ + return ; + } + wxTCPServer *ipcserv = (wxTCPServer *) server->GetClientData(); + + // This socket is being deleted; skip this event + if (!ipcserv) + return; + + if (event.GetSocketEvent() != wxSOCKET_CONNECTION) + return; + + // Accept the connection, getting a new socket + wxSocketBase *sock = server->Accept(); + if (!sock) { /* No socket, no glory */ + return ; + } + if (!sock->Ok()) + { + sock->Destroy(); + return; + } + + wxSocketStream *stream = new wxSocketStream(*sock); + wxDataInputStream *codeci = new wxDataInputStream(*stream); + wxDataOutputStream *codeco = new wxDataOutputStream(*stream); + + int msg; + msg = codeci->Read8(); + + if (msg == IPC_CONNECT) + { + wxString topic_name; + topic_name = codeci->ReadString(); + + wxTCPConnection *new_connection = + (wxTCPConnection *)ipcserv->OnAcceptConnection (topic_name); + + if (new_connection) + { + if (new_connection->IsKindOf(CLASSINFO(wxTCPConnection))) + { + // Acknowledge success + codeco->Write8(IPC_CONNECT); + new_connection->m_topic = topic_name; + new_connection->m_sock = sock; + new_connection->m_sockstrm = stream; + new_connection->m_codeci = codeci; + new_connection->m_codeco = codeco; + sock->SetEventHandler(*gs_handler, _CLIENT_ONREQUEST_ID); + sock->SetClientData(new_connection); + sock->SetNotify(wxSOCKET_INPUT_FLAG | wxSOCKET_LOST_FLAG); + sock->Notify(true); + return; + } + else + { + delete new_connection; + // and fall through to delete everything else + } + } + } + + // Something went wrong, send failure message and delete everything + codeco->Write8(IPC_FAIL); + + delete codeco; + delete codeci; + delete stream; + sock->Destroy(); +} + +// -------------------------------------------------------------------------- +// wxTCPEventHandlerModule (private class) +// -------------------------------------------------------------------------- + +class wxTCPEventHandlerModule: public wxModule +{ + DECLARE_DYNAMIC_CLASS(wxTCPEventHandlerModule) + +public: + bool OnInit() { gs_handler = new wxTCPEventHandler(); return true; } + void OnExit() { wxDELETE(gs_handler); } +}; + +IMPLEMENT_DYNAMIC_CLASS(wxTCPEventHandlerModule, wxModule) + + +#endif + // wxUSE_SOCKETS && wxUSE_IPC && wxUSE_STREAMS diff --git a/Externals/wxWidgets/src/common/sckstrm.cpp b/Externals/wxWidgets/src/common/sckstrm.cpp index 658e3e57ed..ae4d847620 100644 --- a/Externals/wxWidgets/src/common/sckstrm.cpp +++ b/Externals/wxWidgets/src/common/sckstrm.cpp @@ -1,135 +1,135 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/sckstrm.cpp -// Purpose: wxSocket*Stream -// Author: Guilhem Lavaux -// Modified by: -// Created: 17/07/97 -// RCS-ID: $Id: sckstrm.cpp 42897 2006-11-01 10:21:24Z JS $ -// Copyright: (c) -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_SOCKETS && wxUSE_STREAMS - -#include "wx/sckstrm.h" - -#ifndef WX_PRECOMP - #include "wx/stream.h" -#endif - -#include "wx/socket.h" - -// --------------------------------------------------------------------------- -// wxSocketOutputStream -// --------------------------------------------------------------------------- - -wxSocketOutputStream::wxSocketOutputStream(wxSocketBase& s) - : m_o_socket(&s) -{ -} - -wxSocketOutputStream::~wxSocketOutputStream() -{ -} - -size_t wxSocketOutputStream::OnSysWrite(const void *buffer, size_t size) -{ - size_t ret = m_o_socket->Write((const char *)buffer, size).LastCount(); - m_lasterror = m_o_socket->Error() ? wxSTREAM_WRITE_ERROR : wxSTREAM_NO_ERROR; - return ret; - - // Patch 1476893 caused Advise to hang, needs further investigation -#if 0 - const char *buf = (const char *)buffer; - size_t count = 0; - - while ( count < size && m_o_socket->WaitForWrite() ) - { - const size_t ret = m_o_socket->Write(buf, size - count).LastCount(); - - buf += ret; - count += ret; - - if ( m_o_socket->Error() ) - { - if (m_o_socket->LastError() != wxSOCKET_WOULDBLOCK) - { - m_lasterror = wxSTREAM_WRITE_ERROR; - return count; - } - } - } - - m_lasterror = wxSTREAM_NO_ERROR; - return count; -#endif -} - -// --------------------------------------------------------------------------- -// wxSocketInputStream -// --------------------------------------------------------------------------- - -wxSocketInputStream::wxSocketInputStream(wxSocketBase& s) - : m_i_socket(&s) -{ -} - -wxSocketInputStream::~wxSocketInputStream() -{ -} - -size_t wxSocketInputStream::OnSysRead(void *buffer, size_t size) -{ - size_t ret = m_i_socket->Read((char *)buffer, size).LastCount(); - m_lasterror = m_i_socket->Error() ? wxSTREAM_READ_ERROR : wxSTREAM_NO_ERROR; - return ret; - - // Patch 1476893 caused Advise to hang, needs further investigation -#if 0 - char *buf = (char *)buffer; - size_t count = 0; - - while ( count < size && m_i_socket->WaitForRead() ) - { - const size_t ret = m_i_socket->Read(buf, size - count).LastCount(); - - buf += ret; - count += ret; - - if ( m_i_socket->Error() ) - { - if (m_i_socket->LastError() != wxSOCKET_WOULDBLOCK) - { - m_lasterror = wxSTREAM_READ_ERROR; - return count; - } - } - } - - m_lasterror = wxSTREAM_NO_ERROR; - return count; -#endif -} - -// --------------------------------------------------------------------------- -// wxSocketStream -// --------------------------------------------------------------------------- - -wxSocketStream::wxSocketStream(wxSocketBase& s) - : wxSocketInputStream(s), wxSocketOutputStream(s) -{ -} - -wxSocketStream::~wxSocketStream() -{ -} - -#endif - // wxUSE_STREAMS && wxUSE_SOCKETS +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/sckstrm.cpp +// Purpose: wxSocket*Stream +// Author: Guilhem Lavaux +// Modified by: +// Created: 17/07/97 +// RCS-ID: $Id: sckstrm.cpp 42897 2006-11-01 10:21:24Z JS $ +// Copyright: (c) +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_SOCKETS && wxUSE_STREAMS + +#include "wx/sckstrm.h" + +#ifndef WX_PRECOMP + #include "wx/stream.h" +#endif + +#include "wx/socket.h" + +// --------------------------------------------------------------------------- +// wxSocketOutputStream +// --------------------------------------------------------------------------- + +wxSocketOutputStream::wxSocketOutputStream(wxSocketBase& s) + : m_o_socket(&s) +{ +} + +wxSocketOutputStream::~wxSocketOutputStream() +{ +} + +size_t wxSocketOutputStream::OnSysWrite(const void *buffer, size_t size) +{ + size_t ret = m_o_socket->Write((const char *)buffer, size).LastCount(); + m_lasterror = m_o_socket->Error() ? wxSTREAM_WRITE_ERROR : wxSTREAM_NO_ERROR; + return ret; + + // Patch 1476893 caused Advise to hang, needs further investigation +#if 0 + const char *buf = (const char *)buffer; + size_t count = 0; + + while ( count < size && m_o_socket->WaitForWrite() ) + { + const size_t ret = m_o_socket->Write(buf, size - count).LastCount(); + + buf += ret; + count += ret; + + if ( m_o_socket->Error() ) + { + if (m_o_socket->LastError() != wxSOCKET_WOULDBLOCK) + { + m_lasterror = wxSTREAM_WRITE_ERROR; + return count; + } + } + } + + m_lasterror = wxSTREAM_NO_ERROR; + return count; +#endif +} + +// --------------------------------------------------------------------------- +// wxSocketInputStream +// --------------------------------------------------------------------------- + +wxSocketInputStream::wxSocketInputStream(wxSocketBase& s) + : m_i_socket(&s) +{ +} + +wxSocketInputStream::~wxSocketInputStream() +{ +} + +size_t wxSocketInputStream::OnSysRead(void *buffer, size_t size) +{ + size_t ret = m_i_socket->Read((char *)buffer, size).LastCount(); + m_lasterror = m_i_socket->Error() ? wxSTREAM_READ_ERROR : wxSTREAM_NO_ERROR; + return ret; + + // Patch 1476893 caused Advise to hang, needs further investigation +#if 0 + char *buf = (char *)buffer; + size_t count = 0; + + while ( count < size && m_i_socket->WaitForRead() ) + { + const size_t ret = m_i_socket->Read(buf, size - count).LastCount(); + + buf += ret; + count += ret; + + if ( m_i_socket->Error() ) + { + if (m_i_socket->LastError() != wxSOCKET_WOULDBLOCK) + { + m_lasterror = wxSTREAM_READ_ERROR; + return count; + } + } + } + + m_lasterror = wxSTREAM_NO_ERROR; + return count; +#endif +} + +// --------------------------------------------------------------------------- +// wxSocketStream +// --------------------------------------------------------------------------- + +wxSocketStream::wxSocketStream(wxSocketBase& s) + : wxSocketInputStream(s), wxSocketOutputStream(s) +{ +} + +wxSocketStream::~wxSocketStream() +{ +} + +#endif + // wxUSE_STREAMS && wxUSE_SOCKETS diff --git a/Externals/wxWidgets/src/common/settcmn.cpp b/Externals/wxWidgets/src/common/settcmn.cpp index 2aa32ea0d9..334a8f8b8a 100644 --- a/Externals/wxWidgets/src/common/settcmn.cpp +++ b/Externals/wxWidgets/src/common/settcmn.cpp @@ -1,88 +1,88 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/settcmn.cpp -// Purpose: common (to all ports) wxWindow functions -// Author: Robert Roebling -// RCS-ID: $Id: settcmn.cpp 39310 2006-05-24 07:16:32Z ABX $ -// Copyright: (c) wxWidgets team -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#include "wx/settings.h" - -#ifndef WX_PRECOMP - #include "wx/utils.h" -#endif //WX_PRECOMP - -// ---------------------------------------------------------------------------- -// static data -// ---------------------------------------------------------------------------- - -wxSystemScreenType wxSystemSettings::ms_screen = wxSYS_SCREEN_NONE; - -// ---------------------------------------------------------------------------- -// ---------------------------------------------------------------------------- - -wxSystemScreenType wxSystemSettings::GetScreenType() -{ - if (ms_screen == wxSYS_SCREEN_NONE) - { - // wxUniv will be used on small devices, too. - int x = GetMetric( wxSYS_SCREEN_X ); - - ms_screen = wxSYS_SCREEN_DESKTOP; - - if (x < 800) - ms_screen = wxSYS_SCREEN_SMALL; - - if (x < 640) - ms_screen = wxSYS_SCREEN_PDA; - - if (x < 200) - ms_screen = wxSYS_SCREEN_TINY; - - // This is probably a bug, but VNC seems to report 0 - if (x < 10) - ms_screen = wxSYS_SCREEN_DESKTOP; - } - - return ms_screen; -} - -void wxSystemSettings::SetScreenType( wxSystemScreenType screen ) -{ - ms_screen = screen; -} - -#if WXWIN_COMPATIBILITY_2_4 - -wxColour wxSystemSettings::GetSystemColour(int index) -{ - return GetColour((wxSystemColour)index); -} - -wxFont wxSystemSettings::GetSystemFont(int index) -{ - return GetFont((wxSystemFont)index); -} - -int wxSystemSettings::GetSystemMetric(int index) -{ - return GetMetric((wxSystemMetric)index); -} - -#endif // WXWIN_COMPATIBILITY_2_4 +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/settcmn.cpp +// Purpose: common (to all ports) wxWindow functions +// Author: Robert Roebling +// RCS-ID: $Id: settcmn.cpp 39310 2006-05-24 07:16:32Z ABX $ +// Copyright: (c) wxWidgets team +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#include "wx/settings.h" + +#ifndef WX_PRECOMP + #include "wx/utils.h" +#endif //WX_PRECOMP + +// ---------------------------------------------------------------------------- +// static data +// ---------------------------------------------------------------------------- + +wxSystemScreenType wxSystemSettings::ms_screen = wxSYS_SCREEN_NONE; + +// ---------------------------------------------------------------------------- +// ---------------------------------------------------------------------------- + +wxSystemScreenType wxSystemSettings::GetScreenType() +{ + if (ms_screen == wxSYS_SCREEN_NONE) + { + // wxUniv will be used on small devices, too. + int x = GetMetric( wxSYS_SCREEN_X ); + + ms_screen = wxSYS_SCREEN_DESKTOP; + + if (x < 800) + ms_screen = wxSYS_SCREEN_SMALL; + + if (x < 640) + ms_screen = wxSYS_SCREEN_PDA; + + if (x < 200) + ms_screen = wxSYS_SCREEN_TINY; + + // This is probably a bug, but VNC seems to report 0 + if (x < 10) + ms_screen = wxSYS_SCREEN_DESKTOP; + } + + return ms_screen; +} + +void wxSystemSettings::SetScreenType( wxSystemScreenType screen ) +{ + ms_screen = screen; +} + +#if WXWIN_COMPATIBILITY_2_4 + +wxColour wxSystemSettings::GetSystemColour(int index) +{ + return GetColour((wxSystemColour)index); +} + +wxFont wxSystemSettings::GetSystemFont(int index) +{ + return GetFont((wxSystemFont)index); +} + +int wxSystemSettings::GetSystemMetric(int index) +{ + return GetMetric((wxSystemMetric)index); +} + +#endif // WXWIN_COMPATIBILITY_2_4 diff --git a/Externals/wxWidgets/src/common/sizer.cpp b/Externals/wxWidgets/src/common/sizer.cpp index 1db16c8f74..80ff21a6d7 100644 --- a/Externals/wxWidgets/src/common/sizer.cpp +++ b/Externals/wxWidgets/src/common/sizer.cpp @@ -1,2261 +1,2261 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/sizer.cpp -// Purpose: provide new wxSizer class for layout -// Author: Robert Roebling and Robin Dunn, contributions by -// Dirk Holtwick, Ron Lee -// Modified by: Ron Lee -// Created: -// RCS-ID: $Id: sizer.cpp 52359 2008-03-06 13:48:50Z VS $ -// Copyright: (c) Robin Dunn, Robert Roebling -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#include "wx/display.h" -#include "wx/sizer.h" - -#ifndef WX_PRECOMP - #include "wx/string.h" - #include "wx/intl.h" - #include "wx/math.h" - #include "wx/utils.h" - #include "wx/settings.h" - #include "wx/button.h" - #include "wx/statbox.h" - #include "wx/toplevel.h" -#endif // WX_PRECOMP - -#include "wx/listimpl.cpp" - -#if WXWIN_COMPATIBILITY_2_4 - #include "wx/notebook.h" -#endif - -//--------------------------------------------------------------------------- - -IMPLEMENT_CLASS(wxSizerItem, wxObject) -IMPLEMENT_CLASS(wxSizer, wxObject) -IMPLEMENT_CLASS(wxGridSizer, wxSizer) -IMPLEMENT_CLASS(wxFlexGridSizer, wxGridSizer) -IMPLEMENT_CLASS(wxBoxSizer, wxSizer) -#if wxUSE_STATBOX -IMPLEMENT_CLASS(wxStaticBoxSizer, wxBoxSizer) -#endif -#if wxUSE_BUTTON -IMPLEMENT_CLASS(wxStdDialogButtonSizer, wxBoxSizer) -#endif - -WX_DEFINE_EXPORTED_LIST( wxSizerItemList ) - -/* - TODO PROPERTIES - sizeritem - object - object_ref - minsize - option - flag - border - spacer - option - flag - borfder - boxsizer - orient - staticboxsizer - orient - label - gridsizer - rows - cols - vgap - hgap - flexgridsizer - rows - cols - vgap - hgap - growablerows - growablecols - minsize -*/ - - -// ---------------------------------------------------------------------------- -// wxSizerFlags -// ---------------------------------------------------------------------------- - -wxSizerFlags& wxSizerFlags::ReserveSpaceEvenIfHidden() -{ - m_flags |= wxRESERVE_SPACE_EVEN_IF_HIDDEN; - return *this; -} - -// ---------------------------------------------------------------------------- -// wxSizerItem -// ---------------------------------------------------------------------------- - -void wxSizerItem::Init(const wxSizerFlags& flags) -{ - Init(); - - m_proportion = flags.GetProportion(); - m_flag = flags.GetFlags(); - m_border = flags.GetBorderInPixels(); -} - -wxSizerItem::wxSizerItem() -{ - Init(); - - m_proportion = 0; - m_border = 0; - m_flag = 0; - - m_kind = Item_None; -} - -// window item -void wxSizerItem::SetWindow(wxWindow *window) -{ - wxCHECK_RET( window, _T("NULL window in wxSizerItem::SetWindow()") ); - - m_kind = Item_Window; - m_window = window; - - // window doesn't become smaller than its initial size, whatever happens - m_minSize = window->GetSize(); - - if ( m_flag & wxFIXED_MINSIZE ) - window->SetMinSize(m_minSize); - - // aspect ratio calculated from initial size - SetRatio(m_minSize); -} - -wxSizerItem::wxSizerItem(wxWindow *window, - int proportion, - int flag, - int border, - wxObject* userData) - : m_proportion(proportion), - m_border(border), - m_flag(flag), - m_userData(userData) -{ - SetWindow(window); -} - -// sizer item -void wxSizerItem::SetSizer(wxSizer *sizer) -{ - m_kind = Item_Sizer; - m_sizer = sizer; -} - -wxSizerItem::wxSizerItem(wxSizer *sizer, - int proportion, - int flag, - int border, - wxObject* userData) - : m_proportion(proportion), - m_border(border), - m_flag(flag), - m_ratio(0.0), - m_userData(userData) -{ - SetSizer(sizer); - - // m_minSize is set later -} - -// spacer item -void wxSizerItem::SetSpacer(const wxSize& size) -{ - m_kind = Item_Spacer; - m_spacer = new wxSizerSpacer(size); - m_minSize = size; - SetRatio(size); -} - -wxSizerItem::wxSizerItem(int width, - int height, - int proportion, - int flag, - int border, - wxObject* userData) - : m_minSize(width, height), // minimal size is the initial size - m_proportion(proportion), - m_border(border), - m_flag(flag), - m_userData(userData) -{ - SetSpacer(width, height); -} - -wxSizerItem::~wxSizerItem() -{ - delete m_userData; - - switch ( m_kind ) - { - case Item_None: - break; - - case Item_Window: - m_window->SetContainingSizer(NULL); - break; - - case Item_Sizer: - delete m_sizer; - break; - - case Item_Spacer: - delete m_spacer; - break; - - case Item_Max: - default: - wxFAIL_MSG( _T("unexpected wxSizerItem::m_kind") ); - } -} - -wxSize wxSizerItem::GetSpacer() const -{ - wxSize size; - if ( m_kind == Item_Spacer ) - size = m_spacer->GetSize(); - - return size; -} - - -wxSize wxSizerItem::GetSize() const -{ - wxSize ret; - switch ( m_kind ) - { - case Item_None: - break; - - case Item_Window: - ret = m_window->GetSize(); - break; - - case Item_Sizer: - ret = m_sizer->GetSize(); - break; - - case Item_Spacer: - ret = m_spacer->GetSize(); - break; - - case Item_Max: - default: - wxFAIL_MSG( _T("unexpected wxSizerItem::m_kind") ); - } - - if (m_flag & wxWEST) - ret.x += m_border; - if (m_flag & wxEAST) - ret.x += m_border; - if (m_flag & wxNORTH) - ret.y += m_border; - if (m_flag & wxSOUTH) - ret.y += m_border; - - return ret; -} - -wxSize wxSizerItem::CalcMin() -{ - if (IsSizer()) - { - m_minSize = m_sizer->GetMinSize(); - - // if we have to preserve aspect ratio _AND_ this is - // the first-time calculation, consider ret to be initial size - if ( (m_flag & wxSHAPED) && wxIsNullDouble(m_ratio) ) - SetRatio(m_minSize); - } - else if ( IsWindow() ) - { - // Since the size of the window may change during runtime, we - // should use the current minimal/best size. - m_minSize = m_window->GetEffectiveMinSize(); - } - - return GetMinSizeWithBorder(); -} - -wxSize wxSizerItem::GetMinSizeWithBorder() const -{ - wxSize ret = m_minSize; - - if (m_flag & wxWEST) - ret.x += m_border; - if (m_flag & wxEAST) - ret.x += m_border; - if (m_flag & wxNORTH) - ret.y += m_border; - if (m_flag & wxSOUTH) - ret.y += m_border; - - return ret; -} - - -void wxSizerItem::SetDimension( const wxPoint& pos_, const wxSize& size_ ) -{ - wxPoint pos = pos_; - wxSize size = size_; - if (m_flag & wxSHAPED) - { - // adjust aspect ratio - int rwidth = (int) (size.y * m_ratio); - if (rwidth > size.x) - { - // fit horizontally - int rheight = (int) (size.x / m_ratio); - // add vertical space - if (m_flag & wxALIGN_CENTER_VERTICAL) - pos.y += (size.y - rheight) / 2; - else if (m_flag & wxALIGN_BOTTOM) - pos.y += (size.y - rheight); - // use reduced dimensions - size.y =rheight; - } - else if (rwidth < size.x) - { - // add horizontal space - if (m_flag & wxALIGN_CENTER_HORIZONTAL) - pos.x += (size.x - rwidth) / 2; - else if (m_flag & wxALIGN_RIGHT) - pos.x += (size.x - rwidth); - size.x = rwidth; - } - } - - // This is what GetPosition() returns. Since we calculate - // borders afterwards, GetPosition() will be the left/top - // corner of the surrounding border. - m_pos = pos; - - if (m_flag & wxWEST) - { - pos.x += m_border; - size.x -= m_border; - } - if (m_flag & wxEAST) - { - size.x -= m_border; - } - if (m_flag & wxNORTH) - { - pos.y += m_border; - size.y -= m_border; - } - if (m_flag & wxSOUTH) - { - size.y -= m_border; - } - - if (size.x < 0) - size.x = 0; - if (size.y < 0) - size.y = 0; - - m_rect = wxRect(pos, size); - - switch ( m_kind ) - { - case Item_None: - wxFAIL_MSG( _T("can't set size of uninitialized sizer item") ); - break; - - case Item_Window: - m_window->SetSize(pos.x, pos.y, size.x, size.y, - wxSIZE_ALLOW_MINUS_ONE); - break; - - case Item_Sizer: - m_sizer->SetDimension(pos.x, pos.y, size.x, size.y); - break; - - case Item_Spacer: - m_spacer->SetSize(size); - break; - - case Item_Max: - default: - wxFAIL_MSG( _T("unexpected wxSizerItem::m_kind") ); - } -} - -void wxSizerItem::DeleteWindows() -{ - switch ( m_kind ) - { - case Item_None: - case Item_Spacer: - break; - - case Item_Window: - //We are deleting the window from this sizer - normally - //the window destroys the sizer associated with it, - //which might destroy this, which we don't want - m_window->SetContainingSizer(NULL); - m_window->Destroy(); - //Putting this after the switch will result in a spacer - //not being deleted properly on destruction - m_kind = Item_None; - break; - - case Item_Sizer: - m_sizer->DeleteWindows(); - break; - - case Item_Max: - default: - wxFAIL_MSG( _T("unexpected wxSizerItem::m_kind") ); - } - -} - -void wxSizerItem::Show( bool show ) -{ - switch ( m_kind ) - { - case Item_None: - wxFAIL_MSG( _T("can't show uninitialized sizer item") ); - break; - - case Item_Window: - m_window->Show(show); - break; - - case Item_Sizer: - m_sizer->Show(show); - break; - - case Item_Spacer: - m_spacer->Show(show); - break; - - case Item_Max: - default: - wxFAIL_MSG( _T("unexpected wxSizerItem::m_kind") ); - } -} - -bool wxSizerItem::IsShown() const -{ - switch ( m_kind ) - { - case Item_None: - // we may be called from CalcMin(), just return false so that we're - // not used - break; - - case Item_Window: - return m_window->IsShown(); - - case Item_Sizer: - // arbitrarily decide that if at least one of our elements is - // shown, so are we (this arbitrariness is the reason for - // deprecating this function) - { - // Some apps (such as dialog editors) depend on an empty sizer still - // being laid out correctly and reporting the correct size and position. - if (m_sizer->GetChildren().GetCount() == 0) - return true; - - for ( wxSizerItemList::compatibility_iterator - node = m_sizer->GetChildren().GetFirst(); - node; - node = node->GetNext() ) - { - if ( node->GetData()->IsShown() ) - return true; - } - } - return false; - - case Item_Spacer: - return m_spacer->IsShown(); - - case Item_Max: - default: - wxFAIL_MSG( _T("unexpected wxSizerItem::m_kind") ); - } - - return false; -} - -// This is a helper to support wxRESERVE_SPACE_EVEN_IF_HIDDEN. In wx 2.9+, -// this flag is respected by IsShown(), but not in wx 2.8. -bool wxSizerItem::ShouldAccountFor() const -{ - if ( m_flag & wxRESERVE_SPACE_EVEN_IF_HIDDEN ) - return true; - - if ( IsSizer() ) - { - // this mirrors wxSizerItem::IsShown() code above - const wxSizerItemList& children = m_sizer->GetChildren(); - if ( children.GetCount() == 0 ) - return true; - - for ( wxSizerItemList::compatibility_iterator - node = children.GetFirst(); - node; - node = node->GetNext() ) - { - if ( node->GetData()->ShouldAccountFor() ) - return true; - } - return false; - } - else - { - return IsShown(); - } -} - - -#if WXWIN_COMPATIBILITY_2_6 -void wxSizerItem::SetOption( int option ) -{ - SetProportion( option ); -} - -int wxSizerItem::GetOption() const -{ - return GetProportion(); -} -#endif // WXWIN_COMPATIBILITY_2_6 - - -//--------------------------------------------------------------------------- -// wxSizer -//--------------------------------------------------------------------------- - -wxSizer::~wxSizer() -{ - WX_CLEAR_LIST(wxSizerItemList, m_children); -} - -wxSizerItem* wxSizer::Insert( size_t index, wxSizerItem *item ) -{ - m_children.Insert( index, item ); - - if ( item->GetWindow() ) - item->GetWindow()->SetContainingSizer( this ); - - if ( item->GetSizer() ) - item->GetSizer()->SetContainingWindow( m_containingWindow ); - - return item; -} - -void wxSizer::SetContainingWindow(wxWindow *win) -{ - if ( win == m_containingWindow ) - return; - - m_containingWindow = win; - - // set the same window for all nested sizers as well, they also are in the - // same window - for ( wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); - node; - node = node->GetNext() ) - { - wxSizerItem *const item = node->GetData(); - wxSizer *const sizer = item->GetSizer(); - - if ( sizer ) - { - sizer->SetContainingWindow(win); - } - } -} - -#if WXWIN_COMPATIBILITY_2_6 -bool wxSizer::Remove( wxWindow *window ) -{ - return Detach( window ); -} -#endif // WXWIN_COMPATIBILITY_2_6 - -bool wxSizer::Remove( wxSizer *sizer ) -{ - wxASSERT_MSG( sizer, _T("Removing NULL sizer") ); - - wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); - while (node) - { - wxSizerItem *item = node->GetData(); - - if (item->GetSizer() == sizer) - { - delete item; - m_children.Erase( node ); - return true; - } - - node = node->GetNext(); - } - - return false; -} - -bool wxSizer::Remove( int index ) -{ - wxCHECK_MSG( index >= 0 && (size_t)index < m_children.GetCount(), - false, - _T("Remove index is out of range") ); - - wxSizerItemList::compatibility_iterator node = m_children.Item( index ); - - wxCHECK_MSG( node, false, _T("Failed to find child node") ); - - wxSizerItem *item = node->GetData(); - - if ( item->IsWindow() ) - item->GetWindow()->SetContainingSizer( NULL ); - - delete item; - m_children.Erase( node ); - return true; -} - -bool wxSizer::Detach( wxSizer *sizer ) -{ - wxASSERT_MSG( sizer, _T("Detaching NULL sizer") ); - - wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); - while (node) - { - wxSizerItem *item = node->GetData(); - - if (item->GetSizer() == sizer) - { - item->DetachSizer(); - delete item; - m_children.Erase( node ); - return true; - } - node = node->GetNext(); - } - - return false; -} - -bool wxSizer::Detach( wxWindow *window ) -{ - wxASSERT_MSG( window, _T("Detaching NULL window") ); - - wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); - while (node) - { - wxSizerItem *item = node->GetData(); - - if (item->GetWindow() == window) - { - item->GetWindow()->SetContainingSizer( NULL ); - delete item; - m_children.Erase( node ); - return true; - } - node = node->GetNext(); - } - - return false; -} - -bool wxSizer::Detach( int index ) -{ - wxCHECK_MSG( index >= 0 && (size_t)index < m_children.GetCount(), - false, - _T("Detach index is out of range") ); - - wxSizerItemList::compatibility_iterator node = m_children.Item( index ); - - wxCHECK_MSG( node, false, _T("Failed to find child node") ); - - wxSizerItem *item = node->GetData(); - - if ( item->IsSizer() ) - item->DetachSizer(); - else if ( item->IsWindow() ) - item->GetWindow()->SetContainingSizer( NULL ); - - delete item; - m_children.Erase( node ); - return true; -} - -bool wxSizer::Replace( wxWindow *oldwin, wxWindow *newwin, bool recursive ) -{ - wxASSERT_MSG( oldwin, _T("Replacing NULL window") ); - wxASSERT_MSG( newwin, _T("Replacing with NULL window") ); - - wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); - while (node) - { - wxSizerItem *item = node->GetData(); - - if (item->GetWindow() == oldwin) - { - item->GetWindow()->SetContainingSizer( NULL ); - item->SetWindow(newwin); - newwin->SetContainingSizer( this ); - return true; - } - else if (recursive && item->IsSizer()) - { - if (item->GetSizer()->Replace( oldwin, newwin, true )) - return true; - } - - node = node->GetNext(); - } - - return false; -} - -bool wxSizer::Replace( wxSizer *oldsz, wxSizer *newsz, bool recursive ) -{ - wxASSERT_MSG( oldsz, _T("Replacing NULL sizer") ); - wxASSERT_MSG( newsz, _T("Replacing with NULL sizer") ); - - wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); - while (node) - { - wxSizerItem *item = node->GetData(); - - if (item->GetSizer() == oldsz) - { - wxSizer *old = item->GetSizer(); - item->SetSizer(newsz); - delete old; - return true; - } - else if (recursive && item->IsSizer()) - { - if (item->GetSizer()->Replace( oldsz, newsz, true )) - return true; - } - - node = node->GetNext(); - } - - return false; -} - -bool wxSizer::Replace( size_t old, wxSizerItem *newitem ) -{ - wxCHECK_MSG( old < m_children.GetCount(), false, _T("Replace index is out of range") ); - wxASSERT_MSG( newitem, _T("Replacing with NULL item") ); - - wxSizerItemList::compatibility_iterator node = m_children.Item( old ); - - wxCHECK_MSG( node, false, _T("Failed to find child node") ); - - wxSizerItem *item = node->GetData(); - node->SetData(newitem); - delete item; - - return true; -} - -void wxSizer::Clear( bool delete_windows ) -{ - // First clear the ContainingSizer pointers - wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); - while (node) - { - wxSizerItem *item = node->GetData(); - - if (item->IsWindow()) - item->GetWindow()->SetContainingSizer( NULL ); - node = node->GetNext(); - } - - // Destroy the windows if needed - if (delete_windows) - DeleteWindows(); - - // Now empty the list - WX_CLEAR_LIST(wxSizerItemList, m_children); -} - -void wxSizer::DeleteWindows() -{ - wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); - while (node) - { - wxSizerItem *item = node->GetData(); - - item->DeleteWindows(); - node = node->GetNext(); - } -} - -wxSize wxSizer::ComputeFittingWindowSize(wxWindow *window) -{ - // take the min size by default and limit it by max size - wxSize size = GetMinWindowSize(window); - wxSize sizeMax = GetMaxWindowSize(window); - - wxTopLevelWindow *tlw = wxDynamicCast(window, wxTopLevelWindow); - if ( tlw ) - { - // hack for small screen devices where TLWs are always full screen - if ( tlw->IsAlwaysMaximized() ) - { - size = tlw->GetSize(); - } - else // normal situation - { - // limit the window to the size of the display it is on - int disp = wxDisplay::GetFromWindow(window); - if ( disp == wxNOT_FOUND ) - { - // or, if we don't know which one it is, of the main one - disp = 0; - } - - sizeMax = wxDisplay(disp).GetClientArea().GetSize(); - } - } - - if ( sizeMax.x != wxDefaultCoord && size.x > sizeMax.x ) - size.x = sizeMax.x; - if ( sizeMax.y != wxDefaultCoord && size.y > sizeMax.y ) - size.y = sizeMax.y; - - return size; -} - -wxSize wxSizer::ComputeFittingClientSize(wxWindow *window) -{ - wxCHECK_MSG( window, wxDefaultSize, _T("window can't be NULL") ); - - return window->WindowToClientSize(ComputeFittingWindowSize(window)); -} - -wxSize wxSizer::Fit( wxWindow *window ) -{ - wxSize size = ComputeFittingWindowSize(window); - window->SetSize(size); - return size; -} - -void wxSizer::FitInside( wxWindow *window ) -{ - wxSize size; - if (window->IsTopLevel()) - size = VirtualFitSize( window ); - else - size = GetMinClientSize( window ); - - window->SetVirtualSize( size ); -} - -void wxSizer::Layout() -{ - // (re)calculates minimums needed for each item and other preparations - // for layout - CalcMin(); - - // Applies the layout and repositions/resizes the items - RecalcSizes(); -} - -void wxSizer::SetSizeHints( wxWindow *window ) -{ - // Preserve the window's max size hints, but set the - // lower bound according to the sizer calculations. - - // This is equivalent to calling Fit(), except that we need to set - // the size hints _in between_ the two steps performed by Fit - // (1. ComputeFittingWindowSize, 2. SetSize). That's because - // otherwise SetSize() could have no effect if there already are - // size hints in effect that forbid requested size. - const wxSize size = ComputeFittingWindowSize(window); - - window->SetSizeHints( size.x, - size.y, - window->GetMaxWidth(), - window->GetMaxHeight() ); - - window->SetSize(size); -} - -void wxSizer::SetVirtualSizeHints( wxWindow *window ) -{ - // Preserve the window's max size hints, but set the - // lower bound according to the sizer calculations. - - FitInside( window ); - wxSize size( window->GetVirtualSize() ); - window->SetVirtualSizeHints( size.x, - size.y, - window->GetMaxWidth(), - window->GetMaxHeight() ); -} - -wxSize wxSizer::GetMaxWindowSize( wxWindow *window ) const -{ - return window->GetMaxSize(); -} - -wxSize wxSizer::GetMinWindowSize( wxWindow *window ) -{ - wxSize minSize( GetMinSize() ); - wxSize size( window->GetSize() ); - wxSize client_size( window->GetClientSize() ); - - return wxSize( minSize.x+size.x-client_size.x, - minSize.y+size.y-client_size.y ); -} - -// TODO on mac we need a function that determines how much free space this -// min size contains, in order to make sure that we have 20 pixels of free -// space around the controls -wxSize wxSizer::GetMaxClientSize( wxWindow *window ) const -{ - wxSize maxSize( window->GetMaxSize() ); - - if ( maxSize != wxDefaultSize ) - { - wxSize size( window->GetSize() ); - wxSize client_size( window->GetClientSize() ); - - return wxSize( maxSize.x + client_size.x - size.x, - maxSize.y + client_size.y - size.y ); - } - else - return wxDefaultSize; -} - -wxSize wxSizer::GetMinClientSize( wxWindow *WXUNUSED(window) ) -{ - return GetMinSize(); // Already returns client size. -} - -wxSize wxSizer::VirtualFitSize( wxWindow *window ) -{ - wxSize size = GetMinClientSize( window ); - wxSize sizeMax = GetMaxClientSize( window ); - - // Limit the size if sizeMax != wxDefaultSize - - if ( size.x > sizeMax.x && sizeMax.x != wxDefaultCoord ) - size.x = sizeMax.x; - if ( size.y > sizeMax.y && sizeMax.y != wxDefaultCoord ) - size.y = sizeMax.y; - - return size; -} - -void wxSizer::SetDimension( int x, int y, int width, int height ) -{ - m_position.x = x; - m_position.y = y; - m_size.x = width; - m_size.y = height; - Layout(); -} - -wxSize wxSizer::GetMinSize() -{ - wxSize ret( CalcMin() ); - if (ret.x < m_minSize.x) ret.x = m_minSize.x; - if (ret.y < m_minSize.y) ret.y = m_minSize.y; - return ret; -} - -void wxSizer::DoSetMinSize( int width, int height ) -{ - m_minSize.x = width; - m_minSize.y = height; -} - -bool wxSizer::DoSetItemMinSize( wxWindow *window, int width, int height ) -{ - wxASSERT_MSG( window, _T("SetMinSize for NULL window") ); - - // Is it our immediate child? - - wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); - while (node) - { - wxSizerItem *item = node->GetData(); - - if (item->GetWindow() == window) - { - item->SetMinSize( width, height ); - return true; - } - node = node->GetNext(); - } - - // No? Search any subsizers we own then - - node = m_children.GetFirst(); - while (node) - { - wxSizerItem *item = node->GetData(); - - if ( item->GetSizer() && - item->GetSizer()->DoSetItemMinSize( window, width, height ) ) - { - // A child sizer found the requested windw, exit. - return true; - } - node = node->GetNext(); - } - - return false; -} - -bool wxSizer::DoSetItemMinSize( wxSizer *sizer, int width, int height ) -{ - wxASSERT_MSG( sizer, _T("SetMinSize for NULL sizer") ); - - // Is it our immediate child? - - wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); - while (node) - { - wxSizerItem *item = node->GetData(); - - if (item->GetSizer() == sizer) - { - item->GetSizer()->DoSetMinSize( width, height ); - return true; - } - node = node->GetNext(); - } - - // No? Search any subsizers we own then - - node = m_children.GetFirst(); - while (node) - { - wxSizerItem *item = node->GetData(); - - if ( item->GetSizer() && - item->GetSizer()->DoSetItemMinSize( sizer, width, height ) ) - { - // A child found the requested sizer, exit. - return true; - } - node = node->GetNext(); - } - - return false; -} - -bool wxSizer::DoSetItemMinSize( size_t index, int width, int height ) -{ - wxSizerItemList::compatibility_iterator node = m_children.Item( index ); - - wxCHECK_MSG( node, false, _T("Failed to find child node") ); - - wxSizerItem *item = node->GetData(); - - if (item->GetSizer()) - { - // Sizers contains the minimal size in them, if not calculated ... - item->GetSizer()->DoSetMinSize( width, height ); - } - else - { - // ... but the minimal size of spacers and windows is stored via the item - item->SetMinSize( width, height ); - } - - return true; -} - -wxSizerItem* wxSizer::GetItem( wxWindow *window, bool recursive ) -{ - wxASSERT_MSG( window, _T("GetItem for NULL window") ); - - wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); - while (node) - { - wxSizerItem *item = node->GetData(); - - if (item->GetWindow() == window) - { - return item; - } - else if (recursive && item->IsSizer()) - { - wxSizerItem *subitem = item->GetSizer()->GetItem( window, true ); - if (subitem) - return subitem; - } - - node = node->GetNext(); - } - - return NULL; -} - -wxSizerItem* wxSizer::GetItem( wxSizer *sizer, bool recursive ) -{ - wxASSERT_MSG( sizer, _T("GetItem for NULL sizer") ); - - wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); - while (node) - { - wxSizerItem *item = node->GetData(); - - if (item->GetSizer() == sizer) - { - return item; - } - else if (recursive && item->IsSizer()) - { - wxSizerItem *subitem = item->GetSizer()->GetItem( sizer, true ); - if (subitem) - return subitem; - } - - node = node->GetNext(); - } - - return NULL; -} - -wxSizerItem* wxSizer::GetItem( size_t index ) -{ - wxCHECK_MSG( index < m_children.GetCount(), - NULL, - _T("GetItem index is out of range") ); - - return m_children.Item( index )->GetData(); -} - -bool wxSizer::Show( wxWindow *window, bool show, bool recursive ) -{ - wxSizerItem *item = GetItem( window, recursive ); - - if ( item ) - { - item->Show( show ); - return true; - } - - return false; -} - -bool wxSizer::Show( wxSizer *sizer, bool show, bool recursive ) -{ - wxSizerItem *item = GetItem( sizer, recursive ); - - if ( item ) - { - item->Show( show ); - return true; - } - - return false; -} - -bool wxSizer::Show( size_t index, bool show) -{ - wxSizerItem *item = GetItem( index ); - - if ( item ) - { - item->Show( show ); - return true; - } - - return false; -} - -void wxSizer::ShowItems( bool show ) -{ - wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); - while (node) - { - node->GetData()->Show( show ); - node = node->GetNext(); - } -} - -bool wxSizer::IsShown( wxWindow *window ) const -{ - wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); - while (node) - { - wxSizerItem *item = node->GetData(); - - if (item->GetWindow() == window) - { - return item->IsShown(); - } - node = node->GetNext(); - } - - wxFAIL_MSG( _T("IsShown failed to find sizer item") ); - - return false; -} - -bool wxSizer::IsShown( wxSizer *sizer ) const -{ - wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); - while (node) - { - wxSizerItem *item = node->GetData(); - - if (item->GetSizer() == sizer) - { - return item->IsShown(); - } - node = node->GetNext(); - } - - wxFAIL_MSG( _T("IsShown failed to find sizer item") ); - - return false; -} - -bool wxSizer::IsShown( size_t index ) const -{ - wxCHECK_MSG( index < m_children.GetCount(), - false, - _T("IsShown index is out of range") ); - - return m_children.Item( index )->GetData()->IsShown(); -} - - -//--------------------------------------------------------------------------- -// wxGridSizer -//--------------------------------------------------------------------------- - -wxGridSizer::wxGridSizer( int rows, int cols, int vgap, int hgap ) - : m_rows( ( cols == 0 && rows == 0 ) ? 1 : rows ) - , m_cols( cols ) - , m_vgap( vgap ) - , m_hgap( hgap ) -{ -} - -wxGridSizer::wxGridSizer( int cols, int vgap, int hgap ) - : m_rows( cols == 0 ? 1 : 0 ) - , m_cols( cols ) - , m_vgap( vgap ) - , m_hgap( hgap ) -{ -} - -int wxGridSizer::CalcRowsCols(int& nrows, int& ncols) const -{ - int nitems = m_children.GetCount(); - if ( nitems) - { - if ( m_cols ) - { - ncols = m_cols; - nrows = (nitems + m_cols - 1) / m_cols; - } - else if ( m_rows ) - { - ncols = (nitems + m_rows - 1) / m_rows; - nrows = m_rows; - } - else // 0 columns, 0 rows? - { - wxFAIL_MSG( _T("grid sizer must have either rows or columns fixed") ); - - nrows = ncols = 0; - } - } - - return nitems; -} - -void wxGridSizer::RecalcSizes() -{ - int nitems, nrows, ncols; - if ( (nitems = CalcRowsCols(nrows, ncols)) == 0 ) - return; - - wxSize sz( GetSize() ); - wxPoint pt( GetPosition() ); - - int w = (sz.x - (ncols - 1) * m_hgap) / ncols; - int h = (sz.y - (nrows - 1) * m_vgap) / nrows; - - int x = pt.x; - for (int c = 0; c < ncols; c++) - { - int y = pt.y; - for (int r = 0; r < nrows; r++) - { - int i = r * ncols + c; - if (i < nitems) - { - wxSizerItemList::compatibility_iterator node = m_children.Item( i ); - - wxASSERT_MSG( node, _T("Failed to find SizerItemList node") ); - - SetItemBounds( node->GetData(), x, y, w, h); - } - y = y + h + m_vgap; - } - x = x + w + m_hgap; - } -} - -wxSize wxGridSizer::CalcMin() -{ - int nrows, ncols; - if ( CalcRowsCols(nrows, ncols) == 0 ) - return wxSize(); - - // Find the max width and height for any component - int w = 0; - int h = 0; - - wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); - while (node) - { - wxSizerItem *item = node->GetData(); - wxSize sz( item->CalcMin() ); - - w = wxMax( w, sz.x ); - h = wxMax( h, sz.y ); - - node = node->GetNext(); - } - - return wxSize( ncols * w + (ncols-1) * m_hgap, - nrows * h + (nrows-1) * m_vgap ); -} - -void wxGridSizer::SetItemBounds( wxSizerItem *item, int x, int y, int w, int h ) -{ - wxPoint pt( x,y ); - wxSize sz( item->GetMinSizeWithBorder() ); - int flag = item->GetFlag(); - - if ((flag & wxEXPAND) || (flag & wxSHAPED)) - { - sz = wxSize(w, h); - } - else - { - if (flag & wxALIGN_CENTER_HORIZONTAL) - { - pt.x = x + (w - sz.x) / 2; - } - else if (flag & wxALIGN_RIGHT) - { - pt.x = x + (w - sz.x); - } - - if (flag & wxALIGN_CENTER_VERTICAL) - { - pt.y = y + (h - sz.y) / 2; - } - else if (flag & wxALIGN_BOTTOM) - { - pt.y = y + (h - sz.y); - } - } - - item->SetDimension(pt, sz); -} - -//--------------------------------------------------------------------------- -// wxFlexGridSizer -//--------------------------------------------------------------------------- - -wxFlexGridSizer::wxFlexGridSizer( int rows, int cols, int vgap, int hgap ) - : wxGridSizer( rows, cols, vgap, hgap ), - m_flexDirection(wxBOTH), - m_growMode(wxFLEX_GROWMODE_SPECIFIED) -{ -} - -wxFlexGridSizer::wxFlexGridSizer( int cols, int vgap, int hgap ) - : wxGridSizer( cols, vgap, hgap ), - m_flexDirection(wxBOTH), - m_growMode(wxFLEX_GROWMODE_SPECIFIED) -{ -} - -wxFlexGridSizer::~wxFlexGridSizer() -{ -} - -void wxFlexGridSizer::RecalcSizes() -{ - int nitems, nrows, ncols; - if ( (nitems = CalcRowsCols(nrows, ncols)) == 0 ) - return; - - wxPoint pt( GetPosition() ); - wxSize sz( GetSize() ); - - AdjustForGrowables(sz, m_calculatedMinSize, nrows, ncols); - - sz = wxSize( pt.x + sz.x, pt.y + sz.y ); - - int x = pt.x; - for (int c = 0; c < ncols; c++) - { - int y = pt.y; - for (int r = 0; r < nrows; r++) - { - int i = r * ncols + c; - if (i < nitems) - { - wxSizerItemList::compatibility_iterator node = m_children.Item( i ); - - wxASSERT_MSG( node, _T("Failed to find node") ); - - int w = wxMax( 0, wxMin( m_colWidths[c], sz.x - x ) ); - int h = wxMax( 0, wxMin( m_rowHeights[r], sz.y - y ) ); - - SetItemBounds( node->GetData(), x, y, w, h); - } - if (m_rowHeights[r] != -1) - y = y + m_rowHeights[r] + m_vgap; - } - if (m_colWidths[c] != -1) - x = x + m_colWidths[c] + m_hgap; - } -} - -wxSize wxFlexGridSizer::CalcMin() -{ - int nrows, - ncols; - size_t i, s; - - // Number of rows/columns can change as items are added or removed. - if ( !CalcRowsCols(nrows, ncols) ) - return wxSize(); - - m_rowHeights.SetCount(nrows); - m_colWidths.SetCount(ncols); - - // We have to recalcuate the sizes in case the item minimum size has - // changed since the previous layout, or the item has been hidden using - // wxSizer::Show(). If all the items in a row/column are hidden, the final - // dimension of the row/column will be -1, indicating that the column - // itself is hidden. - for( s = m_rowHeights.GetCount(), i = 0; i < s; ++i ) - m_rowHeights[ i ] = -1; - for( s = m_colWidths.GetCount(), i = 0; i < s; ++i ) - m_colWidths[ i ] = -1; - - wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); - - i = 0; - while (node) - { - wxSizerItem *item = node->GetData(); - if ( item->ShouldAccountFor() ) - { - wxSize sz( item->CalcMin() ); - int row = i / ncols; - int col = i % ncols; - - m_rowHeights[ row ] = wxMax( wxMax( 0, sz.y ), m_rowHeights[ row ] ); - m_colWidths[ col ] = wxMax( wxMax( 0, sz.x ), m_colWidths[ col ] ); - } - - node = node->GetNext(); - i++; - } - - AdjustForFlexDirection(); - - // Sum total minimum size, including gaps between rows/columns. - // -1 is used as a magic number meaning empty column. - int width = 0; - for (int col = 0; col < ncols; col++) - if ( m_colWidths[ col ] != -1 ) - width += m_colWidths[ col ] + m_hgap; - if (width > 0) - width -= m_hgap; - - int height = 0; - for (int row = 0; row < nrows; row++) - if ( m_rowHeights[ row ] != -1 ) - height += m_rowHeights[ row ] + m_vgap; - if (height > 0) - height -= m_vgap; - - m_calculatedMinSize = wxSize( width, height ); - return m_calculatedMinSize; -} - -void wxFlexGridSizer::AdjustForFlexDirection() -{ - // the logic in CalcMin works when we resize flexibly in both directions - // but maybe this is not the case - if ( m_flexDirection != wxBOTH ) - { - // select the array corresponding to the direction in which we do *not* - // resize flexibly - wxArrayInt& array = m_flexDirection == wxVERTICAL ? m_colWidths - : m_rowHeights; - - const size_t count = array.GetCount(); - - // find the largest value in this array - size_t n; - int largest = 0; - - for ( n = 0; n < count; ++n ) - { - if ( array[n] > largest ) - largest = array[n]; - } - - // and now fill it with the largest value - for ( n = 0; n < count; ++n ) - { - // don't touch hidden rows - if ( array[n] != -1 ) - array[n] = largest; - } - } -} - - -void wxFlexGridSizer::AdjustForGrowables(const wxSize& sz, const wxSize& minsz, - int nrows, int ncols) -{ - // what to do with the rows? by default, resize them proportionally - if ( sz.y > minsz.y && ( (m_flexDirection & wxVERTICAL) || (m_growMode == wxFLEX_GROWMODE_SPECIFIED) ) ) - { - int sum_proportions = 0; - int growable_space = 0; - int num = 0; - size_t idx; - for (idx = 0; idx < m_growableRows.GetCount(); idx++) - { - // Since the number of rows/columns can change as items are - // inserted/deleted, we need to verify at runtime that the - // requested growable rows/columns are still valid. - if (m_growableRows[idx] >= nrows) - continue; - - // If all items in a row/column are hidden, that row/column will - // have a dimension of -1. This causes the row/column to be - // hidden completely. - if (m_rowHeights[ m_growableRows[idx] ] == -1) - continue; - sum_proportions += m_growableRowsProportions[idx]; - growable_space += m_rowHeights[ m_growableRows[idx] ]; - num++; - } - - if (num > 0) - { - for (idx = 0; idx < m_growableRows.GetCount(); idx++) - { - if (m_growableRows[idx] >= nrows ) - continue; - if (m_rowHeights[ m_growableRows[idx] ] != -1) - { - int delta = (sz.y - minsz.y); - if (sum_proportions == 0) - delta = (delta/num) + m_rowHeights[ m_growableRows[idx] ]; - else - delta = ((delta+growable_space)*m_growableRowsProportions[idx]) / sum_proportions; - m_rowHeights[ m_growableRows[idx] ] = delta; - } - } - } - } - else if ( (m_growMode == wxFLEX_GROWMODE_ALL) && (sz.y > minsz.y) ) - { - // rounding problem? - for ( int row = 0; row < nrows; ++row ) - m_rowHeights[ row ] = sz.y / nrows; - } - - // the same logic as above but for the columns - if ( sz.x > minsz.x && ( (m_flexDirection & wxHORIZONTAL) || (m_growMode == wxFLEX_GROWMODE_SPECIFIED) ) ) - { - int sum_proportions = 0; - int growable_space = 0; - int num = 0; - size_t idx; - for (idx = 0; idx < m_growableCols.GetCount(); idx++) - { - // Since the number of rows/columns can change as items are - // inserted/deleted, we need to verify at runtime that the - // requested growable rows/columns are still valid. - if (m_growableCols[idx] >= ncols) - continue; - - // If all items in a row/column are hidden, that row/column will - // have a dimension of -1. This causes the column to be hidden - // completely. - if (m_colWidths[ m_growableCols[idx] ] == -1) - continue; - sum_proportions += m_growableColsProportions[idx]; - growable_space += m_colWidths[ m_growableCols[idx] ]; - num++; - } - - if (num > 0) - { - for (idx = 0; idx < m_growableCols.GetCount(); idx++) - { - if (m_growableCols[idx] >= ncols ) - continue; - if (m_colWidths[ m_growableCols[idx] ] != -1) - { - int delta = (sz.x - minsz.x); - if (sum_proportions == 0) - delta = (delta/num) + m_colWidths[ m_growableCols[idx] ]; - else - delta = ((delta+growable_space)*m_growableColsProportions[idx])/sum_proportions; - m_colWidths[ m_growableCols[idx] ] = delta; - } - } - } - } - else if ( (m_growMode == wxFLEX_GROWMODE_ALL) && (sz.x > minsz.x) ) - { - for ( int col=0; col < ncols; ++col ) - m_colWidths[ col ] = sz.x / ncols; - } -} - - -void wxFlexGridSizer::AddGrowableRow( size_t idx, int proportion ) -{ - m_growableRows.Add( idx ); - m_growableRowsProportions.Add( proportion ); -} - -void wxFlexGridSizer::AddGrowableCol( size_t idx, int proportion ) -{ - m_growableCols.Add( idx ); - m_growableColsProportions.Add( proportion ); -} - -// helper function for RemoveGrowableCol/Row() -static void -DoRemoveFromArrays(size_t idx, wxArrayInt& items, wxArrayInt& proportions) -{ - const size_t count = items.size(); - for ( size_t n = 0; n < count; n++ ) - { - if ( (size_t)items[n] == idx ) - { - items.RemoveAt(n); - proportions.RemoveAt(n); - return; - } - } - - wxFAIL_MSG( _T("column/row is already not growable") ); -} - -void wxFlexGridSizer::RemoveGrowableCol( size_t idx ) -{ - DoRemoveFromArrays(idx, m_growableCols, m_growableColsProportions); -} - -void wxFlexGridSizer::RemoveGrowableRow( size_t idx ) -{ - DoRemoveFromArrays(idx, m_growableRows, m_growableRowsProportions); -} - -//--------------------------------------------------------------------------- -// wxBoxSizer -//--------------------------------------------------------------------------- - -wxBoxSizer::wxBoxSizer( int orient ) - : m_orient( orient ) -{ -} - -void wxBoxSizer::RecalcSizes() -{ - if (m_children.GetCount() == 0) - return; - - int delta = 0; - if (m_stretchable) - { - if (m_orient == wxHORIZONTAL) - delta = m_size.x - m_fixedWidth; - else - delta = m_size.y - m_fixedHeight; - } - - wxPoint pt( m_position ); - - int stretchable = m_stretchable; - wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); - while (node) - { - wxSizerItem *item = node->GetData(); - - if (item->ShouldAccountFor()) - { - wxSize size( item->GetMinSizeWithBorder() ); - - if (m_orient == wxVERTICAL) - { - wxCoord height = size.y; - if (item->GetProportion()) - { - // Because of at least one visible item has non-zero - // proportion then m_stretchable is not zero - height = (delta * item->GetProportion()) / stretchable; - delta -= height; - stretchable -= item->GetProportion(); - } - - wxPoint child_pos( pt ); - wxSize child_size( size.x, height ); - - if (item->GetFlag() & (wxEXPAND | wxSHAPED)) - child_size.x = m_size.x; - else if (item->GetFlag() & wxALIGN_RIGHT) - child_pos.x += m_size.x - size.x; - else if (item->GetFlag() & (wxCENTER | wxALIGN_CENTER_HORIZONTAL)) - // XXX wxCENTER is added for backward compatibility; - // wxALIGN_CENTER should be used in new code - child_pos.x += (m_size.x - size.x) / 2; - - item->SetDimension( child_pos, child_size ); - - pt.y += height; - } - else - { - wxCoord width = size.x; - if (item->GetProportion()) - { - // Because of at least one visible item has non-zero - // proportion then m_stretchable is not zero - width = (delta * item->GetProportion()) / stretchable; - delta -= width; - stretchable -= item->GetProportion(); - } - - wxPoint child_pos( pt ); - wxSize child_size( width, size.y ); - - if (item->GetFlag() & (wxEXPAND | wxSHAPED)) - child_size.y = m_size.y; - else if (item->GetFlag() & wxALIGN_BOTTOM) - child_pos.y += m_size.y - size.y; - else if (item->GetFlag() & (wxCENTER | wxALIGN_CENTER_VERTICAL)) - // XXX wxCENTER is added for backward compatibility; - // wxALIGN_CENTER should be used in new code - child_pos.y += (m_size.y - size.y) / 2; - - if ( m_containingWindow ) - { - child_pos.x = m_containingWindow->AdjustForLayoutDirection - ( - child_pos.x, - width, - m_size.x - ); - } - - item->SetDimension( child_pos, child_size ); - - pt.x += width; - } - } - - node = node->GetNext(); - } -} - -wxSize wxBoxSizer::CalcMin() -{ - if (m_children.GetCount() == 0) - return wxSize(); - - m_stretchable = 0; - m_minWidth = 0; - m_minHeight = 0; - m_fixedWidth = 0; - m_fixedHeight = 0; - - // precalc item minsizes and count proportions - wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); - while (node) - { - wxSizerItem *item = node->GetData(); - - if ( item->ShouldAccountFor() ) - { - item->CalcMin(); // result is stored in the item - - m_stretchable += item->GetProportion(); - } - - node = node->GetNext(); - } - - // Total minimum size (width or height) of sizer - int maxMinSize = 0; - - node = m_children.GetFirst(); - while (node) - { - wxSizerItem *item = node->GetData(); - - if (item->ShouldAccountFor() && item->GetProportion() != 0) - { - int stretch = item->GetProportion(); - wxSize size( item->GetMinSizeWithBorder() ); - int minSize; - - // Integer division rounded up is (a + b - 1) / b - // Round up needed in order to guarantee that all - // all items will have size not less then their min size - if (m_orient == wxHORIZONTAL) - minSize = ( size.x*m_stretchable + stretch - 1)/stretch; - else - minSize = ( size.y*m_stretchable + stretch - 1)/stretch; - - if (minSize > maxMinSize) - maxMinSize = minSize; - } - node = node->GetNext(); - } - - // Calculate overall minimum size - node = m_children.GetFirst(); - while (node) - { - wxSizerItem *item = node->GetData(); - - if (item->ShouldAccountFor()) - { - wxSize size( item->GetMinSizeWithBorder() ); - if (item->GetProportion() != 0) - { - if (m_orient == wxHORIZONTAL) - size.x = (maxMinSize*item->GetProportion())/m_stretchable; - else - size.y = (maxMinSize*item->GetProportion())/m_stretchable; - } - else - { - if (m_orient == wxVERTICAL) - { - m_fixedHeight += size.y; - m_fixedWidth = wxMax( m_fixedWidth, size.x ); - } - else - { - m_fixedWidth += size.x; - m_fixedHeight = wxMax( m_fixedHeight, size.y ); - } - } - - if (m_orient == wxHORIZONTAL) - { - m_minWidth += size.x; - m_minHeight = wxMax( m_minHeight, size.y ); - } - else - { - m_minHeight += size.y; - m_minWidth = wxMax( m_minWidth, size.x ); - } - } - node = node->GetNext(); - } - - return wxSize( m_minWidth, m_minHeight ); -} - -//--------------------------------------------------------------------------- -// wxStaticBoxSizer -//--------------------------------------------------------------------------- - -#if wxUSE_STATBOX - -wxStaticBoxSizer::wxStaticBoxSizer( wxStaticBox *box, int orient ) - : wxBoxSizer( orient ), - m_staticBox( box ) -{ - wxASSERT_MSG( box, wxT("wxStaticBoxSizer needs a static box") ); - - // do this so that our Detach() is called if the static box is destroyed - // before we are - m_staticBox->SetContainingSizer(this); -} - -wxStaticBoxSizer::wxStaticBoxSizer(int orient, wxWindow *win, const wxString& s) - : wxBoxSizer(orient), - m_staticBox(new wxStaticBox(win, wxID_ANY, s)) -{ - // same as above - m_staticBox->SetContainingSizer(this); -} - -wxStaticBoxSizer::~wxStaticBoxSizer() -{ - delete m_staticBox; -} - -static void GetStaticBoxBorders( wxStaticBox *box, - int *borderTop, - int *borderOther) -{ - // this has to be done platform by platform as there is no way to - // guess the thickness of a wxStaticBox border - box->GetBordersForSizer(borderTop, borderOther); -} - -void wxStaticBoxSizer::RecalcSizes() -{ - int top_border, other_border; - GetStaticBoxBorders(m_staticBox, &top_border, &other_border); - - m_staticBox->SetSize( m_position.x, m_position.y, m_size.x, m_size.y ); - - wxPoint old_pos( m_position ); - m_position.x += other_border; - m_position.y += top_border; - wxSize old_size( m_size ); - m_size.x -= 2*other_border; - m_size.y -= top_border + other_border; - - wxBoxSizer::RecalcSizes(); - - m_position = old_pos; - m_size = old_size; -} - -wxSize wxStaticBoxSizer::CalcMin() -{ - int top_border, other_border; - GetStaticBoxBorders(m_staticBox, &top_border, &other_border); - - wxSize ret( wxBoxSizer::CalcMin() ); - ret.x += 2*other_border; - ret.y += other_border + top_border; - - return ret; -} - -void wxStaticBoxSizer::ShowItems( bool show ) -{ - m_staticBox->Show( show ); - wxBoxSizer::ShowItems( show ); -} - -bool wxStaticBoxSizer::Detach( wxWindow *window ) -{ - // avoid deleting m_staticBox in our dtor if it's being detached from the - // sizer (which can happen because it's being already destroyed for - // example) - if ( window == m_staticBox ) - { - m_staticBox = NULL; - return true; - } - - return wxSizer::Detach( window ); -} - -#endif // wxUSE_STATBOX - -#if wxUSE_BUTTON - -wxStdDialogButtonSizer::wxStdDialogButtonSizer() - : wxBoxSizer(wxHORIZONTAL) -{ - // Vertical buttons with lots of space on either side - // looks rubbish on WinCE, so let's not do this for now. - // If we are going to use vertical buttons, we should - // put the sizer to the right of other controls in the dialog, - // and that's beyond the scope of this sizer. -#ifndef __WXWINCE__ - bool is_pda = (wxSystemSettings::GetScreenType() <= wxSYS_SCREEN_PDA); - // If we have a PDA screen, put yes/no button over - // all other buttons, otherwise on the left side. - if (is_pda) - m_orient = wxVERTICAL; -#endif - - m_buttonAffirmative = NULL; - m_buttonApply = NULL; - m_buttonNegative = NULL; - m_buttonCancel = NULL; - m_buttonHelp = NULL; -} - -void wxStdDialogButtonSizer::AddButton(wxButton *mybutton) -{ - switch (mybutton->GetId()) - { - case wxID_OK: - case wxID_YES: - case wxID_SAVE: - m_buttonAffirmative = mybutton; - break; - case wxID_APPLY: - m_buttonApply = mybutton; - break; - case wxID_NO: - m_buttonNegative = mybutton; - break; - case wxID_CANCEL: - m_buttonCancel = mybutton; - break; - case wxID_HELP: - case wxID_CONTEXT_HELP: - m_buttonHelp = mybutton; - break; - default: - break; - } -} - -void wxStdDialogButtonSizer::SetAffirmativeButton( wxButton *button ) -{ - m_buttonAffirmative = button; -} - -void wxStdDialogButtonSizer::SetNegativeButton( wxButton *button ) -{ - m_buttonNegative = button; -} - -void wxStdDialogButtonSizer::SetCancelButton( wxButton *button ) -{ - m_buttonCancel = button; -} - -void wxStdDialogButtonSizer::Realize() -{ -#ifdef __WXMAC__ - Add(0, 0, 0, wxLEFT, 6); - if (m_buttonHelp) - Add((wxWindow*)m_buttonHelp, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 6); - - if (m_buttonNegative){ - // HIG POLICE BULLETIN - destructive buttons need extra padding - // 24 pixels on either side - Add((wxWindow*)m_buttonNegative, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 12); - } - - // extra whitespace between help/negative and cancel/ok buttons - Add(0, 0, 1, wxEXPAND, 0); - - if (m_buttonCancel){ - Add((wxWindow*)m_buttonCancel, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 6); - // Cancel or help should be default - // m_buttonCancel->SetDefaultButton(); - } - - // Ugh, Mac doesn't really have apply dialogs, so I'll just - // figure the best place is between Cancel and OK - if (m_buttonApply) - Add((wxWindow*)m_buttonApply, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 6); - - if (m_buttonAffirmative){ - Add((wxWindow*)m_buttonAffirmative, 0, wxALIGN_CENTRE | wxLEFT, 6); - - if (m_buttonAffirmative->GetId() == wxID_SAVE){ - // these buttons have set labels under Mac so we should use them - m_buttonAffirmative->SetLabel(_("Save")); - if (m_buttonNegative) - m_buttonNegative->SetLabel(_("Don't Save")); - } - } - - // Extra space around and at the right - Add(12, 24); -#elif defined(__WXGTK20__) - Add(0, 0, 0, wxLEFT, 9); - if (m_buttonHelp) - Add((wxWindow*)m_buttonHelp, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 3); - - // extra whitespace between help and cancel/ok buttons - Add(0, 0, 1, wxEXPAND, 0); - - if (m_buttonNegative){ - Add((wxWindow*)m_buttonNegative, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 3); - } - - if (m_buttonCancel){ - Add((wxWindow*)m_buttonCancel, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 3); - // Cancel or help should be default - // m_buttonCancel->SetDefaultButton(); - } - - if (m_buttonApply) - Add((wxWindow*)m_buttonApply, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 3); - - if (m_buttonAffirmative) - Add((wxWindow*)m_buttonAffirmative, 0, wxALIGN_CENTRE | wxLEFT, 6); -#elif defined(__WXMSW__) - // Windows - - // right-justify buttons - Add(0, 0, 1, wxEXPAND, 0); - - if (m_buttonAffirmative){ - Add((wxWindow*)m_buttonAffirmative, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonAffirmative->ConvertDialogToPixels(wxSize(2, 0)).x); - } - - if (m_buttonNegative){ - Add((wxWindow*)m_buttonNegative, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonNegative->ConvertDialogToPixels(wxSize(2, 0)).x); - } - - if (m_buttonCancel){ - Add((wxWindow*)m_buttonCancel, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonCancel->ConvertDialogToPixels(wxSize(2, 0)).x); - } - if (m_buttonApply) - Add((wxWindow*)m_buttonApply, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonApply->ConvertDialogToPixels(wxSize(2, 0)).x); - - if (m_buttonHelp) - Add((wxWindow*)m_buttonHelp, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonHelp->ConvertDialogToPixels(wxSize(2, 0)).x); -#else - // GTK+1 and any other platform - - // Add(0, 0, 0, wxLEFT, 5); // Not sure what this was for but it unbalances the dialog - if (m_buttonHelp) - Add((wxWindow*)m_buttonHelp, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonHelp->ConvertDialogToPixels(wxSize(4, 0)).x); - - // extra whitespace between help and cancel/ok buttons - Add(0, 0, 1, wxEXPAND, 0); - - if (m_buttonApply) - Add((wxWindow*)m_buttonApply, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonApply->ConvertDialogToPixels(wxSize(4, 0)).x); - - if (m_buttonAffirmative){ - Add((wxWindow*)m_buttonAffirmative, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonAffirmative->ConvertDialogToPixels(wxSize(4, 0)).x); - } - - if (m_buttonNegative){ - Add((wxWindow*)m_buttonNegative, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonNegative->ConvertDialogToPixels(wxSize(4, 0)).x); - } - - if (m_buttonCancel){ - Add((wxWindow*)m_buttonCancel, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonCancel->ConvertDialogToPixels(wxSize(4, 0)).x); - // Cancel or help should be default - // m_buttonCancel->SetDefaultButton(); - } - -#endif -} - -#endif // wxUSE_BUTTON - -#if WXWIN_COMPATIBILITY_2_4 - -// ---------------------------------------------------------------------------- -// wxNotebookSizer -// ---------------------------------------------------------------------------- - -#if wxUSE_BOOKCTRL -IMPLEMENT_CLASS(wxBookCtrlSizer, wxSizer) -#if wxUSE_NOTEBOOK -IMPLEMENT_CLASS(wxNotebookSizer, wxBookCtrlSizer) -#endif // wxUSE_NOTEBOOK -#endif // wxUSE_BOOKCTRL - -#if wxUSE_BOOKCTRL - -#if WXWIN_COMPATIBILITY_2_6 - -wxBookCtrlSizer::wxBookCtrlSizer(wxBookCtrlBase *bookctrl) - : m_bookctrl(bookctrl) -{ - wxASSERT_MSG( bookctrl, wxT("wxBookCtrlSizer needs a control") ); -} - -#endif // WXWIN_COMPATIBILITY_2_6 - -void wxBookCtrlSizer::RecalcSizes() -{ - m_bookctrl->SetSize( m_position.x, m_position.y, m_size.x, m_size.y ); -} - -wxSize wxBookCtrlSizer::CalcMin() -{ - wxSize sizeBorder = m_bookctrl->CalcSizeFromPage(wxSize(0,0)); - - sizeBorder.x += 5; - sizeBorder.y += 5; - - if ( m_bookctrl->GetPageCount() == 0 ) - { - return wxSize(sizeBorder.x + 10, sizeBorder.y + 10); - } - - int maxX = 0; - int maxY = 0; - - wxWindowList::compatibility_iterator - node = m_bookctrl->GetChildren().GetFirst(); - while (node) - { - wxWindow *item = node->GetData(); - wxSizer *itemsizer = item->GetSizer(); - - if (itemsizer) - { - wxSize subsize( itemsizer->CalcMin() ); - - if (subsize.x > maxX) - maxX = subsize.x; - if (subsize.y > maxY) - maxY = subsize.y; - } - - node = node->GetNext(); - } - - return wxSize( maxX, maxY ) + sizeBorder; -} - -#if wxUSE_NOTEBOOK - -#if WXWIN_COMPATIBILITY_2_6 - -wxNotebookSizer::wxNotebookSizer(wxNotebook *nb) -{ - wxASSERT_MSG( nb, wxT("wxNotebookSizer needs a control") ); - m_bookctrl = nb; -} - -#endif // WXWIN_COMPATIBILITY_2_6 - -#endif // wxUSE_NOTEBOOOK -#endif // wxUSE_BOOKCTRL - -#endif // WXWIN_COMPATIBILITY_2_4 +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/sizer.cpp +// Purpose: provide new wxSizer class for layout +// Author: Robert Roebling and Robin Dunn, contributions by +// Dirk Holtwick, Ron Lee +// Modified by: Ron Lee +// Created: +// RCS-ID: $Id: sizer.cpp 52359 2008-03-06 13:48:50Z VS $ +// Copyright: (c) Robin Dunn, Robert Roebling +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#include "wx/display.h" +#include "wx/sizer.h" + +#ifndef WX_PRECOMP + #include "wx/string.h" + #include "wx/intl.h" + #include "wx/math.h" + #include "wx/utils.h" + #include "wx/settings.h" + #include "wx/button.h" + #include "wx/statbox.h" + #include "wx/toplevel.h" +#endif // WX_PRECOMP + +#include "wx/listimpl.cpp" + +#if WXWIN_COMPATIBILITY_2_4 + #include "wx/notebook.h" +#endif + +//--------------------------------------------------------------------------- + +IMPLEMENT_CLASS(wxSizerItem, wxObject) +IMPLEMENT_CLASS(wxSizer, wxObject) +IMPLEMENT_CLASS(wxGridSizer, wxSizer) +IMPLEMENT_CLASS(wxFlexGridSizer, wxGridSizer) +IMPLEMENT_CLASS(wxBoxSizer, wxSizer) +#if wxUSE_STATBOX +IMPLEMENT_CLASS(wxStaticBoxSizer, wxBoxSizer) +#endif +#if wxUSE_BUTTON +IMPLEMENT_CLASS(wxStdDialogButtonSizer, wxBoxSizer) +#endif + +WX_DEFINE_EXPORTED_LIST( wxSizerItemList ) + +/* + TODO PROPERTIES + sizeritem + object + object_ref + minsize + option + flag + border + spacer + option + flag + borfder + boxsizer + orient + staticboxsizer + orient + label + gridsizer + rows + cols + vgap + hgap + flexgridsizer + rows + cols + vgap + hgap + growablerows + growablecols + minsize +*/ + + +// ---------------------------------------------------------------------------- +// wxSizerFlags +// ---------------------------------------------------------------------------- + +wxSizerFlags& wxSizerFlags::ReserveSpaceEvenIfHidden() +{ + m_flags |= wxRESERVE_SPACE_EVEN_IF_HIDDEN; + return *this; +} + +// ---------------------------------------------------------------------------- +// wxSizerItem +// ---------------------------------------------------------------------------- + +void wxSizerItem::Init(const wxSizerFlags& flags) +{ + Init(); + + m_proportion = flags.GetProportion(); + m_flag = flags.GetFlags(); + m_border = flags.GetBorderInPixels(); +} + +wxSizerItem::wxSizerItem() +{ + Init(); + + m_proportion = 0; + m_border = 0; + m_flag = 0; + + m_kind = Item_None; +} + +// window item +void wxSizerItem::SetWindow(wxWindow *window) +{ + wxCHECK_RET( window, _T("NULL window in wxSizerItem::SetWindow()") ); + + m_kind = Item_Window; + m_window = window; + + // window doesn't become smaller than its initial size, whatever happens + m_minSize = window->GetSize(); + + if ( m_flag & wxFIXED_MINSIZE ) + window->SetMinSize(m_minSize); + + // aspect ratio calculated from initial size + SetRatio(m_minSize); +} + +wxSizerItem::wxSizerItem(wxWindow *window, + int proportion, + int flag, + int border, + wxObject* userData) + : m_proportion(proportion), + m_border(border), + m_flag(flag), + m_userData(userData) +{ + SetWindow(window); +} + +// sizer item +void wxSizerItem::SetSizer(wxSizer *sizer) +{ + m_kind = Item_Sizer; + m_sizer = sizer; +} + +wxSizerItem::wxSizerItem(wxSizer *sizer, + int proportion, + int flag, + int border, + wxObject* userData) + : m_proportion(proportion), + m_border(border), + m_flag(flag), + m_ratio(0.0), + m_userData(userData) +{ + SetSizer(sizer); + + // m_minSize is set later +} + +// spacer item +void wxSizerItem::SetSpacer(const wxSize& size) +{ + m_kind = Item_Spacer; + m_spacer = new wxSizerSpacer(size); + m_minSize = size; + SetRatio(size); +} + +wxSizerItem::wxSizerItem(int width, + int height, + int proportion, + int flag, + int border, + wxObject* userData) + : m_minSize(width, height), // minimal size is the initial size + m_proportion(proportion), + m_border(border), + m_flag(flag), + m_userData(userData) +{ + SetSpacer(width, height); +} + +wxSizerItem::~wxSizerItem() +{ + delete m_userData; + + switch ( m_kind ) + { + case Item_None: + break; + + case Item_Window: + m_window->SetContainingSizer(NULL); + break; + + case Item_Sizer: + delete m_sizer; + break; + + case Item_Spacer: + delete m_spacer; + break; + + case Item_Max: + default: + wxFAIL_MSG( _T("unexpected wxSizerItem::m_kind") ); + } +} + +wxSize wxSizerItem::GetSpacer() const +{ + wxSize size; + if ( m_kind == Item_Spacer ) + size = m_spacer->GetSize(); + + return size; +} + + +wxSize wxSizerItem::GetSize() const +{ + wxSize ret; + switch ( m_kind ) + { + case Item_None: + break; + + case Item_Window: + ret = m_window->GetSize(); + break; + + case Item_Sizer: + ret = m_sizer->GetSize(); + break; + + case Item_Spacer: + ret = m_spacer->GetSize(); + break; + + case Item_Max: + default: + wxFAIL_MSG( _T("unexpected wxSizerItem::m_kind") ); + } + + if (m_flag & wxWEST) + ret.x += m_border; + if (m_flag & wxEAST) + ret.x += m_border; + if (m_flag & wxNORTH) + ret.y += m_border; + if (m_flag & wxSOUTH) + ret.y += m_border; + + return ret; +} + +wxSize wxSizerItem::CalcMin() +{ + if (IsSizer()) + { + m_minSize = m_sizer->GetMinSize(); + + // if we have to preserve aspect ratio _AND_ this is + // the first-time calculation, consider ret to be initial size + if ( (m_flag & wxSHAPED) && wxIsNullDouble(m_ratio) ) + SetRatio(m_minSize); + } + else if ( IsWindow() ) + { + // Since the size of the window may change during runtime, we + // should use the current minimal/best size. + m_minSize = m_window->GetEffectiveMinSize(); + } + + return GetMinSizeWithBorder(); +} + +wxSize wxSizerItem::GetMinSizeWithBorder() const +{ + wxSize ret = m_minSize; + + if (m_flag & wxWEST) + ret.x += m_border; + if (m_flag & wxEAST) + ret.x += m_border; + if (m_flag & wxNORTH) + ret.y += m_border; + if (m_flag & wxSOUTH) + ret.y += m_border; + + return ret; +} + + +void wxSizerItem::SetDimension( const wxPoint& pos_, const wxSize& size_ ) +{ + wxPoint pos = pos_; + wxSize size = size_; + if (m_flag & wxSHAPED) + { + // adjust aspect ratio + int rwidth = (int) (size.y * m_ratio); + if (rwidth > size.x) + { + // fit horizontally + int rheight = (int) (size.x / m_ratio); + // add vertical space + if (m_flag & wxALIGN_CENTER_VERTICAL) + pos.y += (size.y - rheight) / 2; + else if (m_flag & wxALIGN_BOTTOM) + pos.y += (size.y - rheight); + // use reduced dimensions + size.y =rheight; + } + else if (rwidth < size.x) + { + // add horizontal space + if (m_flag & wxALIGN_CENTER_HORIZONTAL) + pos.x += (size.x - rwidth) / 2; + else if (m_flag & wxALIGN_RIGHT) + pos.x += (size.x - rwidth); + size.x = rwidth; + } + } + + // This is what GetPosition() returns. Since we calculate + // borders afterwards, GetPosition() will be the left/top + // corner of the surrounding border. + m_pos = pos; + + if (m_flag & wxWEST) + { + pos.x += m_border; + size.x -= m_border; + } + if (m_flag & wxEAST) + { + size.x -= m_border; + } + if (m_flag & wxNORTH) + { + pos.y += m_border; + size.y -= m_border; + } + if (m_flag & wxSOUTH) + { + size.y -= m_border; + } + + if (size.x < 0) + size.x = 0; + if (size.y < 0) + size.y = 0; + + m_rect = wxRect(pos, size); + + switch ( m_kind ) + { + case Item_None: + wxFAIL_MSG( _T("can't set size of uninitialized sizer item") ); + break; + + case Item_Window: + m_window->SetSize(pos.x, pos.y, size.x, size.y, + wxSIZE_ALLOW_MINUS_ONE); + break; + + case Item_Sizer: + m_sizer->SetDimension(pos.x, pos.y, size.x, size.y); + break; + + case Item_Spacer: + m_spacer->SetSize(size); + break; + + case Item_Max: + default: + wxFAIL_MSG( _T("unexpected wxSizerItem::m_kind") ); + } +} + +void wxSizerItem::DeleteWindows() +{ + switch ( m_kind ) + { + case Item_None: + case Item_Spacer: + break; + + case Item_Window: + //We are deleting the window from this sizer - normally + //the window destroys the sizer associated with it, + //which might destroy this, which we don't want + m_window->SetContainingSizer(NULL); + m_window->Destroy(); + //Putting this after the switch will result in a spacer + //not being deleted properly on destruction + m_kind = Item_None; + break; + + case Item_Sizer: + m_sizer->DeleteWindows(); + break; + + case Item_Max: + default: + wxFAIL_MSG( _T("unexpected wxSizerItem::m_kind") ); + } + +} + +void wxSizerItem::Show( bool show ) +{ + switch ( m_kind ) + { + case Item_None: + wxFAIL_MSG( _T("can't show uninitialized sizer item") ); + break; + + case Item_Window: + m_window->Show(show); + break; + + case Item_Sizer: + m_sizer->Show(show); + break; + + case Item_Spacer: + m_spacer->Show(show); + break; + + case Item_Max: + default: + wxFAIL_MSG( _T("unexpected wxSizerItem::m_kind") ); + } +} + +bool wxSizerItem::IsShown() const +{ + switch ( m_kind ) + { + case Item_None: + // we may be called from CalcMin(), just return false so that we're + // not used + break; + + case Item_Window: + return m_window->IsShown(); + + case Item_Sizer: + // arbitrarily decide that if at least one of our elements is + // shown, so are we (this arbitrariness is the reason for + // deprecating this function) + { + // Some apps (such as dialog editors) depend on an empty sizer still + // being laid out correctly and reporting the correct size and position. + if (m_sizer->GetChildren().GetCount() == 0) + return true; + + for ( wxSizerItemList::compatibility_iterator + node = m_sizer->GetChildren().GetFirst(); + node; + node = node->GetNext() ) + { + if ( node->GetData()->IsShown() ) + return true; + } + } + return false; + + case Item_Spacer: + return m_spacer->IsShown(); + + case Item_Max: + default: + wxFAIL_MSG( _T("unexpected wxSizerItem::m_kind") ); + } + + return false; +} + +// This is a helper to support wxRESERVE_SPACE_EVEN_IF_HIDDEN. In wx 2.9+, +// this flag is respected by IsShown(), but not in wx 2.8. +bool wxSizerItem::ShouldAccountFor() const +{ + if ( m_flag & wxRESERVE_SPACE_EVEN_IF_HIDDEN ) + return true; + + if ( IsSizer() ) + { + // this mirrors wxSizerItem::IsShown() code above + const wxSizerItemList& children = m_sizer->GetChildren(); + if ( children.GetCount() == 0 ) + return true; + + for ( wxSizerItemList::compatibility_iterator + node = children.GetFirst(); + node; + node = node->GetNext() ) + { + if ( node->GetData()->ShouldAccountFor() ) + return true; + } + return false; + } + else + { + return IsShown(); + } +} + + +#if WXWIN_COMPATIBILITY_2_6 +void wxSizerItem::SetOption( int option ) +{ + SetProportion( option ); +} + +int wxSizerItem::GetOption() const +{ + return GetProportion(); +} +#endif // WXWIN_COMPATIBILITY_2_6 + + +//--------------------------------------------------------------------------- +// wxSizer +//--------------------------------------------------------------------------- + +wxSizer::~wxSizer() +{ + WX_CLEAR_LIST(wxSizerItemList, m_children); +} + +wxSizerItem* wxSizer::Insert( size_t index, wxSizerItem *item ) +{ + m_children.Insert( index, item ); + + if ( item->GetWindow() ) + item->GetWindow()->SetContainingSizer( this ); + + if ( item->GetSizer() ) + item->GetSizer()->SetContainingWindow( m_containingWindow ); + + return item; +} + +void wxSizer::SetContainingWindow(wxWindow *win) +{ + if ( win == m_containingWindow ) + return; + + m_containingWindow = win; + + // set the same window for all nested sizers as well, they also are in the + // same window + for ( wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); + node; + node = node->GetNext() ) + { + wxSizerItem *const item = node->GetData(); + wxSizer *const sizer = item->GetSizer(); + + if ( sizer ) + { + sizer->SetContainingWindow(win); + } + } +} + +#if WXWIN_COMPATIBILITY_2_6 +bool wxSizer::Remove( wxWindow *window ) +{ + return Detach( window ); +} +#endif // WXWIN_COMPATIBILITY_2_6 + +bool wxSizer::Remove( wxSizer *sizer ) +{ + wxASSERT_MSG( sizer, _T("Removing NULL sizer") ); + + wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); + while (node) + { + wxSizerItem *item = node->GetData(); + + if (item->GetSizer() == sizer) + { + delete item; + m_children.Erase( node ); + return true; + } + + node = node->GetNext(); + } + + return false; +} + +bool wxSizer::Remove( int index ) +{ + wxCHECK_MSG( index >= 0 && (size_t)index < m_children.GetCount(), + false, + _T("Remove index is out of range") ); + + wxSizerItemList::compatibility_iterator node = m_children.Item( index ); + + wxCHECK_MSG( node, false, _T("Failed to find child node") ); + + wxSizerItem *item = node->GetData(); + + if ( item->IsWindow() ) + item->GetWindow()->SetContainingSizer( NULL ); + + delete item; + m_children.Erase( node ); + return true; +} + +bool wxSizer::Detach( wxSizer *sizer ) +{ + wxASSERT_MSG( sizer, _T("Detaching NULL sizer") ); + + wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); + while (node) + { + wxSizerItem *item = node->GetData(); + + if (item->GetSizer() == sizer) + { + item->DetachSizer(); + delete item; + m_children.Erase( node ); + return true; + } + node = node->GetNext(); + } + + return false; +} + +bool wxSizer::Detach( wxWindow *window ) +{ + wxASSERT_MSG( window, _T("Detaching NULL window") ); + + wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); + while (node) + { + wxSizerItem *item = node->GetData(); + + if (item->GetWindow() == window) + { + item->GetWindow()->SetContainingSizer( NULL ); + delete item; + m_children.Erase( node ); + return true; + } + node = node->GetNext(); + } + + return false; +} + +bool wxSizer::Detach( int index ) +{ + wxCHECK_MSG( index >= 0 && (size_t)index < m_children.GetCount(), + false, + _T("Detach index is out of range") ); + + wxSizerItemList::compatibility_iterator node = m_children.Item( index ); + + wxCHECK_MSG( node, false, _T("Failed to find child node") ); + + wxSizerItem *item = node->GetData(); + + if ( item->IsSizer() ) + item->DetachSizer(); + else if ( item->IsWindow() ) + item->GetWindow()->SetContainingSizer( NULL ); + + delete item; + m_children.Erase( node ); + return true; +} + +bool wxSizer::Replace( wxWindow *oldwin, wxWindow *newwin, bool recursive ) +{ + wxASSERT_MSG( oldwin, _T("Replacing NULL window") ); + wxASSERT_MSG( newwin, _T("Replacing with NULL window") ); + + wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); + while (node) + { + wxSizerItem *item = node->GetData(); + + if (item->GetWindow() == oldwin) + { + item->GetWindow()->SetContainingSizer( NULL ); + item->SetWindow(newwin); + newwin->SetContainingSizer( this ); + return true; + } + else if (recursive && item->IsSizer()) + { + if (item->GetSizer()->Replace( oldwin, newwin, true )) + return true; + } + + node = node->GetNext(); + } + + return false; +} + +bool wxSizer::Replace( wxSizer *oldsz, wxSizer *newsz, bool recursive ) +{ + wxASSERT_MSG( oldsz, _T("Replacing NULL sizer") ); + wxASSERT_MSG( newsz, _T("Replacing with NULL sizer") ); + + wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); + while (node) + { + wxSizerItem *item = node->GetData(); + + if (item->GetSizer() == oldsz) + { + wxSizer *old = item->GetSizer(); + item->SetSizer(newsz); + delete old; + return true; + } + else if (recursive && item->IsSizer()) + { + if (item->GetSizer()->Replace( oldsz, newsz, true )) + return true; + } + + node = node->GetNext(); + } + + return false; +} + +bool wxSizer::Replace( size_t old, wxSizerItem *newitem ) +{ + wxCHECK_MSG( old < m_children.GetCount(), false, _T("Replace index is out of range") ); + wxASSERT_MSG( newitem, _T("Replacing with NULL item") ); + + wxSizerItemList::compatibility_iterator node = m_children.Item( old ); + + wxCHECK_MSG( node, false, _T("Failed to find child node") ); + + wxSizerItem *item = node->GetData(); + node->SetData(newitem); + delete item; + + return true; +} + +void wxSizer::Clear( bool delete_windows ) +{ + // First clear the ContainingSizer pointers + wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); + while (node) + { + wxSizerItem *item = node->GetData(); + + if (item->IsWindow()) + item->GetWindow()->SetContainingSizer( NULL ); + node = node->GetNext(); + } + + // Destroy the windows if needed + if (delete_windows) + DeleteWindows(); + + // Now empty the list + WX_CLEAR_LIST(wxSizerItemList, m_children); +} + +void wxSizer::DeleteWindows() +{ + wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); + while (node) + { + wxSizerItem *item = node->GetData(); + + item->DeleteWindows(); + node = node->GetNext(); + } +} + +wxSize wxSizer::ComputeFittingWindowSize(wxWindow *window) +{ + // take the min size by default and limit it by max size + wxSize size = GetMinWindowSize(window); + wxSize sizeMax = GetMaxWindowSize(window); + + wxTopLevelWindow *tlw = wxDynamicCast(window, wxTopLevelWindow); + if ( tlw ) + { + // hack for small screen devices where TLWs are always full screen + if ( tlw->IsAlwaysMaximized() ) + { + size = tlw->GetSize(); + } + else // normal situation + { + // limit the window to the size of the display it is on + int disp = wxDisplay::GetFromWindow(window); + if ( disp == wxNOT_FOUND ) + { + // or, if we don't know which one it is, of the main one + disp = 0; + } + + sizeMax = wxDisplay(disp).GetClientArea().GetSize(); + } + } + + if ( sizeMax.x != wxDefaultCoord && size.x > sizeMax.x ) + size.x = sizeMax.x; + if ( sizeMax.y != wxDefaultCoord && size.y > sizeMax.y ) + size.y = sizeMax.y; + + return size; +} + +wxSize wxSizer::ComputeFittingClientSize(wxWindow *window) +{ + wxCHECK_MSG( window, wxDefaultSize, _T("window can't be NULL") ); + + return window->WindowToClientSize(ComputeFittingWindowSize(window)); +} + +wxSize wxSizer::Fit( wxWindow *window ) +{ + wxSize size = ComputeFittingWindowSize(window); + window->SetSize(size); + return size; +} + +void wxSizer::FitInside( wxWindow *window ) +{ + wxSize size; + if (window->IsTopLevel()) + size = VirtualFitSize( window ); + else + size = GetMinClientSize( window ); + + window->SetVirtualSize( size ); +} + +void wxSizer::Layout() +{ + // (re)calculates minimums needed for each item and other preparations + // for layout + CalcMin(); + + // Applies the layout and repositions/resizes the items + RecalcSizes(); +} + +void wxSizer::SetSizeHints( wxWindow *window ) +{ + // Preserve the window's max size hints, but set the + // lower bound according to the sizer calculations. + + // This is equivalent to calling Fit(), except that we need to set + // the size hints _in between_ the two steps performed by Fit + // (1. ComputeFittingWindowSize, 2. SetSize). That's because + // otherwise SetSize() could have no effect if there already are + // size hints in effect that forbid requested size. + const wxSize size = ComputeFittingWindowSize(window); + + window->SetSizeHints( size.x, + size.y, + window->GetMaxWidth(), + window->GetMaxHeight() ); + + window->SetSize(size); +} + +void wxSizer::SetVirtualSizeHints( wxWindow *window ) +{ + // Preserve the window's max size hints, but set the + // lower bound according to the sizer calculations. + + FitInside( window ); + wxSize size( window->GetVirtualSize() ); + window->SetVirtualSizeHints( size.x, + size.y, + window->GetMaxWidth(), + window->GetMaxHeight() ); +} + +wxSize wxSizer::GetMaxWindowSize( wxWindow *window ) const +{ + return window->GetMaxSize(); +} + +wxSize wxSizer::GetMinWindowSize( wxWindow *window ) +{ + wxSize minSize( GetMinSize() ); + wxSize size( window->GetSize() ); + wxSize client_size( window->GetClientSize() ); + + return wxSize( minSize.x+size.x-client_size.x, + minSize.y+size.y-client_size.y ); +} + +// TODO on mac we need a function that determines how much free space this +// min size contains, in order to make sure that we have 20 pixels of free +// space around the controls +wxSize wxSizer::GetMaxClientSize( wxWindow *window ) const +{ + wxSize maxSize( window->GetMaxSize() ); + + if ( maxSize != wxDefaultSize ) + { + wxSize size( window->GetSize() ); + wxSize client_size( window->GetClientSize() ); + + return wxSize( maxSize.x + client_size.x - size.x, + maxSize.y + client_size.y - size.y ); + } + else + return wxDefaultSize; +} + +wxSize wxSizer::GetMinClientSize( wxWindow *WXUNUSED(window) ) +{ + return GetMinSize(); // Already returns client size. +} + +wxSize wxSizer::VirtualFitSize( wxWindow *window ) +{ + wxSize size = GetMinClientSize( window ); + wxSize sizeMax = GetMaxClientSize( window ); + + // Limit the size if sizeMax != wxDefaultSize + + if ( size.x > sizeMax.x && sizeMax.x != wxDefaultCoord ) + size.x = sizeMax.x; + if ( size.y > sizeMax.y && sizeMax.y != wxDefaultCoord ) + size.y = sizeMax.y; + + return size; +} + +void wxSizer::SetDimension( int x, int y, int width, int height ) +{ + m_position.x = x; + m_position.y = y; + m_size.x = width; + m_size.y = height; + Layout(); +} + +wxSize wxSizer::GetMinSize() +{ + wxSize ret( CalcMin() ); + if (ret.x < m_minSize.x) ret.x = m_minSize.x; + if (ret.y < m_minSize.y) ret.y = m_minSize.y; + return ret; +} + +void wxSizer::DoSetMinSize( int width, int height ) +{ + m_minSize.x = width; + m_minSize.y = height; +} + +bool wxSizer::DoSetItemMinSize( wxWindow *window, int width, int height ) +{ + wxASSERT_MSG( window, _T("SetMinSize for NULL window") ); + + // Is it our immediate child? + + wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); + while (node) + { + wxSizerItem *item = node->GetData(); + + if (item->GetWindow() == window) + { + item->SetMinSize( width, height ); + return true; + } + node = node->GetNext(); + } + + // No? Search any subsizers we own then + + node = m_children.GetFirst(); + while (node) + { + wxSizerItem *item = node->GetData(); + + if ( item->GetSizer() && + item->GetSizer()->DoSetItemMinSize( window, width, height ) ) + { + // A child sizer found the requested windw, exit. + return true; + } + node = node->GetNext(); + } + + return false; +} + +bool wxSizer::DoSetItemMinSize( wxSizer *sizer, int width, int height ) +{ + wxASSERT_MSG( sizer, _T("SetMinSize for NULL sizer") ); + + // Is it our immediate child? + + wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); + while (node) + { + wxSizerItem *item = node->GetData(); + + if (item->GetSizer() == sizer) + { + item->GetSizer()->DoSetMinSize( width, height ); + return true; + } + node = node->GetNext(); + } + + // No? Search any subsizers we own then + + node = m_children.GetFirst(); + while (node) + { + wxSizerItem *item = node->GetData(); + + if ( item->GetSizer() && + item->GetSizer()->DoSetItemMinSize( sizer, width, height ) ) + { + // A child found the requested sizer, exit. + return true; + } + node = node->GetNext(); + } + + return false; +} + +bool wxSizer::DoSetItemMinSize( size_t index, int width, int height ) +{ + wxSizerItemList::compatibility_iterator node = m_children.Item( index ); + + wxCHECK_MSG( node, false, _T("Failed to find child node") ); + + wxSizerItem *item = node->GetData(); + + if (item->GetSizer()) + { + // Sizers contains the minimal size in them, if not calculated ... + item->GetSizer()->DoSetMinSize( width, height ); + } + else + { + // ... but the minimal size of spacers and windows is stored via the item + item->SetMinSize( width, height ); + } + + return true; +} + +wxSizerItem* wxSizer::GetItem( wxWindow *window, bool recursive ) +{ + wxASSERT_MSG( window, _T("GetItem for NULL window") ); + + wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); + while (node) + { + wxSizerItem *item = node->GetData(); + + if (item->GetWindow() == window) + { + return item; + } + else if (recursive && item->IsSizer()) + { + wxSizerItem *subitem = item->GetSizer()->GetItem( window, true ); + if (subitem) + return subitem; + } + + node = node->GetNext(); + } + + return NULL; +} + +wxSizerItem* wxSizer::GetItem( wxSizer *sizer, bool recursive ) +{ + wxASSERT_MSG( sizer, _T("GetItem for NULL sizer") ); + + wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); + while (node) + { + wxSizerItem *item = node->GetData(); + + if (item->GetSizer() == sizer) + { + return item; + } + else if (recursive && item->IsSizer()) + { + wxSizerItem *subitem = item->GetSizer()->GetItem( sizer, true ); + if (subitem) + return subitem; + } + + node = node->GetNext(); + } + + return NULL; +} + +wxSizerItem* wxSizer::GetItem( size_t index ) +{ + wxCHECK_MSG( index < m_children.GetCount(), + NULL, + _T("GetItem index is out of range") ); + + return m_children.Item( index )->GetData(); +} + +bool wxSizer::Show( wxWindow *window, bool show, bool recursive ) +{ + wxSizerItem *item = GetItem( window, recursive ); + + if ( item ) + { + item->Show( show ); + return true; + } + + return false; +} + +bool wxSizer::Show( wxSizer *sizer, bool show, bool recursive ) +{ + wxSizerItem *item = GetItem( sizer, recursive ); + + if ( item ) + { + item->Show( show ); + return true; + } + + return false; +} + +bool wxSizer::Show( size_t index, bool show) +{ + wxSizerItem *item = GetItem( index ); + + if ( item ) + { + item->Show( show ); + return true; + } + + return false; +} + +void wxSizer::ShowItems( bool show ) +{ + wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); + while (node) + { + node->GetData()->Show( show ); + node = node->GetNext(); + } +} + +bool wxSizer::IsShown( wxWindow *window ) const +{ + wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); + while (node) + { + wxSizerItem *item = node->GetData(); + + if (item->GetWindow() == window) + { + return item->IsShown(); + } + node = node->GetNext(); + } + + wxFAIL_MSG( _T("IsShown failed to find sizer item") ); + + return false; +} + +bool wxSizer::IsShown( wxSizer *sizer ) const +{ + wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); + while (node) + { + wxSizerItem *item = node->GetData(); + + if (item->GetSizer() == sizer) + { + return item->IsShown(); + } + node = node->GetNext(); + } + + wxFAIL_MSG( _T("IsShown failed to find sizer item") ); + + return false; +} + +bool wxSizer::IsShown( size_t index ) const +{ + wxCHECK_MSG( index < m_children.GetCount(), + false, + _T("IsShown index is out of range") ); + + return m_children.Item( index )->GetData()->IsShown(); +} + + +//--------------------------------------------------------------------------- +// wxGridSizer +//--------------------------------------------------------------------------- + +wxGridSizer::wxGridSizer( int rows, int cols, int vgap, int hgap ) + : m_rows( ( cols == 0 && rows == 0 ) ? 1 : rows ) + , m_cols( cols ) + , m_vgap( vgap ) + , m_hgap( hgap ) +{ +} + +wxGridSizer::wxGridSizer( int cols, int vgap, int hgap ) + : m_rows( cols == 0 ? 1 : 0 ) + , m_cols( cols ) + , m_vgap( vgap ) + , m_hgap( hgap ) +{ +} + +int wxGridSizer::CalcRowsCols(int& nrows, int& ncols) const +{ + int nitems = m_children.GetCount(); + if ( nitems) + { + if ( m_cols ) + { + ncols = m_cols; + nrows = (nitems + m_cols - 1) / m_cols; + } + else if ( m_rows ) + { + ncols = (nitems + m_rows - 1) / m_rows; + nrows = m_rows; + } + else // 0 columns, 0 rows? + { + wxFAIL_MSG( _T("grid sizer must have either rows or columns fixed") ); + + nrows = ncols = 0; + } + } + + return nitems; +} + +void wxGridSizer::RecalcSizes() +{ + int nitems, nrows, ncols; + if ( (nitems = CalcRowsCols(nrows, ncols)) == 0 ) + return; + + wxSize sz( GetSize() ); + wxPoint pt( GetPosition() ); + + int w = (sz.x - (ncols - 1) * m_hgap) / ncols; + int h = (sz.y - (nrows - 1) * m_vgap) / nrows; + + int x = pt.x; + for (int c = 0; c < ncols; c++) + { + int y = pt.y; + for (int r = 0; r < nrows; r++) + { + int i = r * ncols + c; + if (i < nitems) + { + wxSizerItemList::compatibility_iterator node = m_children.Item( i ); + + wxASSERT_MSG( node, _T("Failed to find SizerItemList node") ); + + SetItemBounds( node->GetData(), x, y, w, h); + } + y = y + h + m_vgap; + } + x = x + w + m_hgap; + } +} + +wxSize wxGridSizer::CalcMin() +{ + int nrows, ncols; + if ( CalcRowsCols(nrows, ncols) == 0 ) + return wxSize(); + + // Find the max width and height for any component + int w = 0; + int h = 0; + + wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); + while (node) + { + wxSizerItem *item = node->GetData(); + wxSize sz( item->CalcMin() ); + + w = wxMax( w, sz.x ); + h = wxMax( h, sz.y ); + + node = node->GetNext(); + } + + return wxSize( ncols * w + (ncols-1) * m_hgap, + nrows * h + (nrows-1) * m_vgap ); +} + +void wxGridSizer::SetItemBounds( wxSizerItem *item, int x, int y, int w, int h ) +{ + wxPoint pt( x,y ); + wxSize sz( item->GetMinSizeWithBorder() ); + int flag = item->GetFlag(); + + if ((flag & wxEXPAND) || (flag & wxSHAPED)) + { + sz = wxSize(w, h); + } + else + { + if (flag & wxALIGN_CENTER_HORIZONTAL) + { + pt.x = x + (w - sz.x) / 2; + } + else if (flag & wxALIGN_RIGHT) + { + pt.x = x + (w - sz.x); + } + + if (flag & wxALIGN_CENTER_VERTICAL) + { + pt.y = y + (h - sz.y) / 2; + } + else if (flag & wxALIGN_BOTTOM) + { + pt.y = y + (h - sz.y); + } + } + + item->SetDimension(pt, sz); +} + +//--------------------------------------------------------------------------- +// wxFlexGridSizer +//--------------------------------------------------------------------------- + +wxFlexGridSizer::wxFlexGridSizer( int rows, int cols, int vgap, int hgap ) + : wxGridSizer( rows, cols, vgap, hgap ), + m_flexDirection(wxBOTH), + m_growMode(wxFLEX_GROWMODE_SPECIFIED) +{ +} + +wxFlexGridSizer::wxFlexGridSizer( int cols, int vgap, int hgap ) + : wxGridSizer( cols, vgap, hgap ), + m_flexDirection(wxBOTH), + m_growMode(wxFLEX_GROWMODE_SPECIFIED) +{ +} + +wxFlexGridSizer::~wxFlexGridSizer() +{ +} + +void wxFlexGridSizer::RecalcSizes() +{ + int nitems, nrows, ncols; + if ( (nitems = CalcRowsCols(nrows, ncols)) == 0 ) + return; + + wxPoint pt( GetPosition() ); + wxSize sz( GetSize() ); + + AdjustForGrowables(sz, m_calculatedMinSize, nrows, ncols); + + sz = wxSize( pt.x + sz.x, pt.y + sz.y ); + + int x = pt.x; + for (int c = 0; c < ncols; c++) + { + int y = pt.y; + for (int r = 0; r < nrows; r++) + { + int i = r * ncols + c; + if (i < nitems) + { + wxSizerItemList::compatibility_iterator node = m_children.Item( i ); + + wxASSERT_MSG( node, _T("Failed to find node") ); + + int w = wxMax( 0, wxMin( m_colWidths[c], sz.x - x ) ); + int h = wxMax( 0, wxMin( m_rowHeights[r], sz.y - y ) ); + + SetItemBounds( node->GetData(), x, y, w, h); + } + if (m_rowHeights[r] != -1) + y = y + m_rowHeights[r] + m_vgap; + } + if (m_colWidths[c] != -1) + x = x + m_colWidths[c] + m_hgap; + } +} + +wxSize wxFlexGridSizer::CalcMin() +{ + int nrows, + ncols; + size_t i, s; + + // Number of rows/columns can change as items are added or removed. + if ( !CalcRowsCols(nrows, ncols) ) + return wxSize(); + + m_rowHeights.SetCount(nrows); + m_colWidths.SetCount(ncols); + + // We have to recalcuate the sizes in case the item minimum size has + // changed since the previous layout, or the item has been hidden using + // wxSizer::Show(). If all the items in a row/column are hidden, the final + // dimension of the row/column will be -1, indicating that the column + // itself is hidden. + for( s = m_rowHeights.GetCount(), i = 0; i < s; ++i ) + m_rowHeights[ i ] = -1; + for( s = m_colWidths.GetCount(), i = 0; i < s; ++i ) + m_colWidths[ i ] = -1; + + wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); + + i = 0; + while (node) + { + wxSizerItem *item = node->GetData(); + if ( item->ShouldAccountFor() ) + { + wxSize sz( item->CalcMin() ); + int row = i / ncols; + int col = i % ncols; + + m_rowHeights[ row ] = wxMax( wxMax( 0, sz.y ), m_rowHeights[ row ] ); + m_colWidths[ col ] = wxMax( wxMax( 0, sz.x ), m_colWidths[ col ] ); + } + + node = node->GetNext(); + i++; + } + + AdjustForFlexDirection(); + + // Sum total minimum size, including gaps between rows/columns. + // -1 is used as a magic number meaning empty column. + int width = 0; + for (int col = 0; col < ncols; col++) + if ( m_colWidths[ col ] != -1 ) + width += m_colWidths[ col ] + m_hgap; + if (width > 0) + width -= m_hgap; + + int height = 0; + for (int row = 0; row < nrows; row++) + if ( m_rowHeights[ row ] != -1 ) + height += m_rowHeights[ row ] + m_vgap; + if (height > 0) + height -= m_vgap; + + m_calculatedMinSize = wxSize( width, height ); + return m_calculatedMinSize; +} + +void wxFlexGridSizer::AdjustForFlexDirection() +{ + // the logic in CalcMin works when we resize flexibly in both directions + // but maybe this is not the case + if ( m_flexDirection != wxBOTH ) + { + // select the array corresponding to the direction in which we do *not* + // resize flexibly + wxArrayInt& array = m_flexDirection == wxVERTICAL ? m_colWidths + : m_rowHeights; + + const size_t count = array.GetCount(); + + // find the largest value in this array + size_t n; + int largest = 0; + + for ( n = 0; n < count; ++n ) + { + if ( array[n] > largest ) + largest = array[n]; + } + + // and now fill it with the largest value + for ( n = 0; n < count; ++n ) + { + // don't touch hidden rows + if ( array[n] != -1 ) + array[n] = largest; + } + } +} + + +void wxFlexGridSizer::AdjustForGrowables(const wxSize& sz, const wxSize& minsz, + int nrows, int ncols) +{ + // what to do with the rows? by default, resize them proportionally + if ( sz.y > minsz.y && ( (m_flexDirection & wxVERTICAL) || (m_growMode == wxFLEX_GROWMODE_SPECIFIED) ) ) + { + int sum_proportions = 0; + int growable_space = 0; + int num = 0; + size_t idx; + for (idx = 0; idx < m_growableRows.GetCount(); idx++) + { + // Since the number of rows/columns can change as items are + // inserted/deleted, we need to verify at runtime that the + // requested growable rows/columns are still valid. + if (m_growableRows[idx] >= nrows) + continue; + + // If all items in a row/column are hidden, that row/column will + // have a dimension of -1. This causes the row/column to be + // hidden completely. + if (m_rowHeights[ m_growableRows[idx] ] == -1) + continue; + sum_proportions += m_growableRowsProportions[idx]; + growable_space += m_rowHeights[ m_growableRows[idx] ]; + num++; + } + + if (num > 0) + { + for (idx = 0; idx < m_growableRows.GetCount(); idx++) + { + if (m_growableRows[idx] >= nrows ) + continue; + if (m_rowHeights[ m_growableRows[idx] ] != -1) + { + int delta = (sz.y - minsz.y); + if (sum_proportions == 0) + delta = (delta/num) + m_rowHeights[ m_growableRows[idx] ]; + else + delta = ((delta+growable_space)*m_growableRowsProportions[idx]) / sum_proportions; + m_rowHeights[ m_growableRows[idx] ] = delta; + } + } + } + } + else if ( (m_growMode == wxFLEX_GROWMODE_ALL) && (sz.y > minsz.y) ) + { + // rounding problem? + for ( int row = 0; row < nrows; ++row ) + m_rowHeights[ row ] = sz.y / nrows; + } + + // the same logic as above but for the columns + if ( sz.x > minsz.x && ( (m_flexDirection & wxHORIZONTAL) || (m_growMode == wxFLEX_GROWMODE_SPECIFIED) ) ) + { + int sum_proportions = 0; + int growable_space = 0; + int num = 0; + size_t idx; + for (idx = 0; idx < m_growableCols.GetCount(); idx++) + { + // Since the number of rows/columns can change as items are + // inserted/deleted, we need to verify at runtime that the + // requested growable rows/columns are still valid. + if (m_growableCols[idx] >= ncols) + continue; + + // If all items in a row/column are hidden, that row/column will + // have a dimension of -1. This causes the column to be hidden + // completely. + if (m_colWidths[ m_growableCols[idx] ] == -1) + continue; + sum_proportions += m_growableColsProportions[idx]; + growable_space += m_colWidths[ m_growableCols[idx] ]; + num++; + } + + if (num > 0) + { + for (idx = 0; idx < m_growableCols.GetCount(); idx++) + { + if (m_growableCols[idx] >= ncols ) + continue; + if (m_colWidths[ m_growableCols[idx] ] != -1) + { + int delta = (sz.x - minsz.x); + if (sum_proportions == 0) + delta = (delta/num) + m_colWidths[ m_growableCols[idx] ]; + else + delta = ((delta+growable_space)*m_growableColsProportions[idx])/sum_proportions; + m_colWidths[ m_growableCols[idx] ] = delta; + } + } + } + } + else if ( (m_growMode == wxFLEX_GROWMODE_ALL) && (sz.x > minsz.x) ) + { + for ( int col=0; col < ncols; ++col ) + m_colWidths[ col ] = sz.x / ncols; + } +} + + +void wxFlexGridSizer::AddGrowableRow( size_t idx, int proportion ) +{ + m_growableRows.Add( idx ); + m_growableRowsProportions.Add( proportion ); +} + +void wxFlexGridSizer::AddGrowableCol( size_t idx, int proportion ) +{ + m_growableCols.Add( idx ); + m_growableColsProportions.Add( proportion ); +} + +// helper function for RemoveGrowableCol/Row() +static void +DoRemoveFromArrays(size_t idx, wxArrayInt& items, wxArrayInt& proportions) +{ + const size_t count = items.size(); + for ( size_t n = 0; n < count; n++ ) + { + if ( (size_t)items[n] == idx ) + { + items.RemoveAt(n); + proportions.RemoveAt(n); + return; + } + } + + wxFAIL_MSG( _T("column/row is already not growable") ); +} + +void wxFlexGridSizer::RemoveGrowableCol( size_t idx ) +{ + DoRemoveFromArrays(idx, m_growableCols, m_growableColsProportions); +} + +void wxFlexGridSizer::RemoveGrowableRow( size_t idx ) +{ + DoRemoveFromArrays(idx, m_growableRows, m_growableRowsProportions); +} + +//--------------------------------------------------------------------------- +// wxBoxSizer +//--------------------------------------------------------------------------- + +wxBoxSizer::wxBoxSizer( int orient ) + : m_orient( orient ) +{ +} + +void wxBoxSizer::RecalcSizes() +{ + if (m_children.GetCount() == 0) + return; + + int delta = 0; + if (m_stretchable) + { + if (m_orient == wxHORIZONTAL) + delta = m_size.x - m_fixedWidth; + else + delta = m_size.y - m_fixedHeight; + } + + wxPoint pt( m_position ); + + int stretchable = m_stretchable; + wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); + while (node) + { + wxSizerItem *item = node->GetData(); + + if (item->ShouldAccountFor()) + { + wxSize size( item->GetMinSizeWithBorder() ); + + if (m_orient == wxVERTICAL) + { + wxCoord height = size.y; + if (item->GetProportion()) + { + // Because of at least one visible item has non-zero + // proportion then m_stretchable is not zero + height = (delta * item->GetProportion()) / stretchable; + delta -= height; + stretchable -= item->GetProportion(); + } + + wxPoint child_pos( pt ); + wxSize child_size( size.x, height ); + + if (item->GetFlag() & (wxEXPAND | wxSHAPED)) + child_size.x = m_size.x; + else if (item->GetFlag() & wxALIGN_RIGHT) + child_pos.x += m_size.x - size.x; + else if (item->GetFlag() & (wxCENTER | wxALIGN_CENTER_HORIZONTAL)) + // XXX wxCENTER is added for backward compatibility; + // wxALIGN_CENTER should be used in new code + child_pos.x += (m_size.x - size.x) / 2; + + item->SetDimension( child_pos, child_size ); + + pt.y += height; + } + else + { + wxCoord width = size.x; + if (item->GetProportion()) + { + // Because of at least one visible item has non-zero + // proportion then m_stretchable is not zero + width = (delta * item->GetProportion()) / stretchable; + delta -= width; + stretchable -= item->GetProportion(); + } + + wxPoint child_pos( pt ); + wxSize child_size( width, size.y ); + + if (item->GetFlag() & (wxEXPAND | wxSHAPED)) + child_size.y = m_size.y; + else if (item->GetFlag() & wxALIGN_BOTTOM) + child_pos.y += m_size.y - size.y; + else if (item->GetFlag() & (wxCENTER | wxALIGN_CENTER_VERTICAL)) + // XXX wxCENTER is added for backward compatibility; + // wxALIGN_CENTER should be used in new code + child_pos.y += (m_size.y - size.y) / 2; + + if ( m_containingWindow ) + { + child_pos.x = m_containingWindow->AdjustForLayoutDirection + ( + child_pos.x, + width, + m_size.x + ); + } + + item->SetDimension( child_pos, child_size ); + + pt.x += width; + } + } + + node = node->GetNext(); + } +} + +wxSize wxBoxSizer::CalcMin() +{ + if (m_children.GetCount() == 0) + return wxSize(); + + m_stretchable = 0; + m_minWidth = 0; + m_minHeight = 0; + m_fixedWidth = 0; + m_fixedHeight = 0; + + // precalc item minsizes and count proportions + wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); + while (node) + { + wxSizerItem *item = node->GetData(); + + if ( item->ShouldAccountFor() ) + { + item->CalcMin(); // result is stored in the item + + m_stretchable += item->GetProportion(); + } + + node = node->GetNext(); + } + + // Total minimum size (width or height) of sizer + int maxMinSize = 0; + + node = m_children.GetFirst(); + while (node) + { + wxSizerItem *item = node->GetData(); + + if (item->ShouldAccountFor() && item->GetProportion() != 0) + { + int stretch = item->GetProportion(); + wxSize size( item->GetMinSizeWithBorder() ); + int minSize; + + // Integer division rounded up is (a + b - 1) / b + // Round up needed in order to guarantee that all + // all items will have size not less then their min size + if (m_orient == wxHORIZONTAL) + minSize = ( size.x*m_stretchable + stretch - 1)/stretch; + else + minSize = ( size.y*m_stretchable + stretch - 1)/stretch; + + if (minSize > maxMinSize) + maxMinSize = minSize; + } + node = node->GetNext(); + } + + // Calculate overall minimum size + node = m_children.GetFirst(); + while (node) + { + wxSizerItem *item = node->GetData(); + + if (item->ShouldAccountFor()) + { + wxSize size( item->GetMinSizeWithBorder() ); + if (item->GetProportion() != 0) + { + if (m_orient == wxHORIZONTAL) + size.x = (maxMinSize*item->GetProportion())/m_stretchable; + else + size.y = (maxMinSize*item->GetProportion())/m_stretchable; + } + else + { + if (m_orient == wxVERTICAL) + { + m_fixedHeight += size.y; + m_fixedWidth = wxMax( m_fixedWidth, size.x ); + } + else + { + m_fixedWidth += size.x; + m_fixedHeight = wxMax( m_fixedHeight, size.y ); + } + } + + if (m_orient == wxHORIZONTAL) + { + m_minWidth += size.x; + m_minHeight = wxMax( m_minHeight, size.y ); + } + else + { + m_minHeight += size.y; + m_minWidth = wxMax( m_minWidth, size.x ); + } + } + node = node->GetNext(); + } + + return wxSize( m_minWidth, m_minHeight ); +} + +//--------------------------------------------------------------------------- +// wxStaticBoxSizer +//--------------------------------------------------------------------------- + +#if wxUSE_STATBOX + +wxStaticBoxSizer::wxStaticBoxSizer( wxStaticBox *box, int orient ) + : wxBoxSizer( orient ), + m_staticBox( box ) +{ + wxASSERT_MSG( box, wxT("wxStaticBoxSizer needs a static box") ); + + // do this so that our Detach() is called if the static box is destroyed + // before we are + m_staticBox->SetContainingSizer(this); +} + +wxStaticBoxSizer::wxStaticBoxSizer(int orient, wxWindow *win, const wxString& s) + : wxBoxSizer(orient), + m_staticBox(new wxStaticBox(win, wxID_ANY, s)) +{ + // same as above + m_staticBox->SetContainingSizer(this); +} + +wxStaticBoxSizer::~wxStaticBoxSizer() +{ + delete m_staticBox; +} + +static void GetStaticBoxBorders( wxStaticBox *box, + int *borderTop, + int *borderOther) +{ + // this has to be done platform by platform as there is no way to + // guess the thickness of a wxStaticBox border + box->GetBordersForSizer(borderTop, borderOther); +} + +void wxStaticBoxSizer::RecalcSizes() +{ + int top_border, other_border; + GetStaticBoxBorders(m_staticBox, &top_border, &other_border); + + m_staticBox->SetSize( m_position.x, m_position.y, m_size.x, m_size.y ); + + wxPoint old_pos( m_position ); + m_position.x += other_border; + m_position.y += top_border; + wxSize old_size( m_size ); + m_size.x -= 2*other_border; + m_size.y -= top_border + other_border; + + wxBoxSizer::RecalcSizes(); + + m_position = old_pos; + m_size = old_size; +} + +wxSize wxStaticBoxSizer::CalcMin() +{ + int top_border, other_border; + GetStaticBoxBorders(m_staticBox, &top_border, &other_border); + + wxSize ret( wxBoxSizer::CalcMin() ); + ret.x += 2*other_border; + ret.y += other_border + top_border; + + return ret; +} + +void wxStaticBoxSizer::ShowItems( bool show ) +{ + m_staticBox->Show( show ); + wxBoxSizer::ShowItems( show ); +} + +bool wxStaticBoxSizer::Detach( wxWindow *window ) +{ + // avoid deleting m_staticBox in our dtor if it's being detached from the + // sizer (which can happen because it's being already destroyed for + // example) + if ( window == m_staticBox ) + { + m_staticBox = NULL; + return true; + } + + return wxSizer::Detach( window ); +} + +#endif // wxUSE_STATBOX + +#if wxUSE_BUTTON + +wxStdDialogButtonSizer::wxStdDialogButtonSizer() + : wxBoxSizer(wxHORIZONTAL) +{ + // Vertical buttons with lots of space on either side + // looks rubbish on WinCE, so let's not do this for now. + // If we are going to use vertical buttons, we should + // put the sizer to the right of other controls in the dialog, + // and that's beyond the scope of this sizer. +#ifndef __WXWINCE__ + bool is_pda = (wxSystemSettings::GetScreenType() <= wxSYS_SCREEN_PDA); + // If we have a PDA screen, put yes/no button over + // all other buttons, otherwise on the left side. + if (is_pda) + m_orient = wxVERTICAL; +#endif + + m_buttonAffirmative = NULL; + m_buttonApply = NULL; + m_buttonNegative = NULL; + m_buttonCancel = NULL; + m_buttonHelp = NULL; +} + +void wxStdDialogButtonSizer::AddButton(wxButton *mybutton) +{ + switch (mybutton->GetId()) + { + case wxID_OK: + case wxID_YES: + case wxID_SAVE: + m_buttonAffirmative = mybutton; + break; + case wxID_APPLY: + m_buttonApply = mybutton; + break; + case wxID_NO: + m_buttonNegative = mybutton; + break; + case wxID_CANCEL: + m_buttonCancel = mybutton; + break; + case wxID_HELP: + case wxID_CONTEXT_HELP: + m_buttonHelp = mybutton; + break; + default: + break; + } +} + +void wxStdDialogButtonSizer::SetAffirmativeButton( wxButton *button ) +{ + m_buttonAffirmative = button; +} + +void wxStdDialogButtonSizer::SetNegativeButton( wxButton *button ) +{ + m_buttonNegative = button; +} + +void wxStdDialogButtonSizer::SetCancelButton( wxButton *button ) +{ + m_buttonCancel = button; +} + +void wxStdDialogButtonSizer::Realize() +{ +#ifdef __WXMAC__ + Add(0, 0, 0, wxLEFT, 6); + if (m_buttonHelp) + Add((wxWindow*)m_buttonHelp, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 6); + + if (m_buttonNegative){ + // HIG POLICE BULLETIN - destructive buttons need extra padding + // 24 pixels on either side + Add((wxWindow*)m_buttonNegative, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 12); + } + + // extra whitespace between help/negative and cancel/ok buttons + Add(0, 0, 1, wxEXPAND, 0); + + if (m_buttonCancel){ + Add((wxWindow*)m_buttonCancel, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 6); + // Cancel or help should be default + // m_buttonCancel->SetDefaultButton(); + } + + // Ugh, Mac doesn't really have apply dialogs, so I'll just + // figure the best place is between Cancel and OK + if (m_buttonApply) + Add((wxWindow*)m_buttonApply, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 6); + + if (m_buttonAffirmative){ + Add((wxWindow*)m_buttonAffirmative, 0, wxALIGN_CENTRE | wxLEFT, 6); + + if (m_buttonAffirmative->GetId() == wxID_SAVE){ + // these buttons have set labels under Mac so we should use them + m_buttonAffirmative->SetLabel(_("Save")); + if (m_buttonNegative) + m_buttonNegative->SetLabel(_("Don't Save")); + } + } + + // Extra space around and at the right + Add(12, 24); +#elif defined(__WXGTK20__) + Add(0, 0, 0, wxLEFT, 9); + if (m_buttonHelp) + Add((wxWindow*)m_buttonHelp, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 3); + + // extra whitespace between help and cancel/ok buttons + Add(0, 0, 1, wxEXPAND, 0); + + if (m_buttonNegative){ + Add((wxWindow*)m_buttonNegative, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 3); + } + + if (m_buttonCancel){ + Add((wxWindow*)m_buttonCancel, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 3); + // Cancel or help should be default + // m_buttonCancel->SetDefaultButton(); + } + + if (m_buttonApply) + Add((wxWindow*)m_buttonApply, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 3); + + if (m_buttonAffirmative) + Add((wxWindow*)m_buttonAffirmative, 0, wxALIGN_CENTRE | wxLEFT, 6); +#elif defined(__WXMSW__) + // Windows + + // right-justify buttons + Add(0, 0, 1, wxEXPAND, 0); + + if (m_buttonAffirmative){ + Add((wxWindow*)m_buttonAffirmative, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonAffirmative->ConvertDialogToPixels(wxSize(2, 0)).x); + } + + if (m_buttonNegative){ + Add((wxWindow*)m_buttonNegative, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonNegative->ConvertDialogToPixels(wxSize(2, 0)).x); + } + + if (m_buttonCancel){ + Add((wxWindow*)m_buttonCancel, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonCancel->ConvertDialogToPixels(wxSize(2, 0)).x); + } + if (m_buttonApply) + Add((wxWindow*)m_buttonApply, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonApply->ConvertDialogToPixels(wxSize(2, 0)).x); + + if (m_buttonHelp) + Add((wxWindow*)m_buttonHelp, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonHelp->ConvertDialogToPixels(wxSize(2, 0)).x); +#else + // GTK+1 and any other platform + + // Add(0, 0, 0, wxLEFT, 5); // Not sure what this was for but it unbalances the dialog + if (m_buttonHelp) + Add((wxWindow*)m_buttonHelp, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonHelp->ConvertDialogToPixels(wxSize(4, 0)).x); + + // extra whitespace between help and cancel/ok buttons + Add(0, 0, 1, wxEXPAND, 0); + + if (m_buttonApply) + Add((wxWindow*)m_buttonApply, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonApply->ConvertDialogToPixels(wxSize(4, 0)).x); + + if (m_buttonAffirmative){ + Add((wxWindow*)m_buttonAffirmative, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonAffirmative->ConvertDialogToPixels(wxSize(4, 0)).x); + } + + if (m_buttonNegative){ + Add((wxWindow*)m_buttonNegative, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonNegative->ConvertDialogToPixels(wxSize(4, 0)).x); + } + + if (m_buttonCancel){ + Add((wxWindow*)m_buttonCancel, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonCancel->ConvertDialogToPixels(wxSize(4, 0)).x); + // Cancel or help should be default + // m_buttonCancel->SetDefaultButton(); + } + +#endif +} + +#endif // wxUSE_BUTTON + +#if WXWIN_COMPATIBILITY_2_4 + +// ---------------------------------------------------------------------------- +// wxNotebookSizer +// ---------------------------------------------------------------------------- + +#if wxUSE_BOOKCTRL +IMPLEMENT_CLASS(wxBookCtrlSizer, wxSizer) +#if wxUSE_NOTEBOOK +IMPLEMENT_CLASS(wxNotebookSizer, wxBookCtrlSizer) +#endif // wxUSE_NOTEBOOK +#endif // wxUSE_BOOKCTRL + +#if wxUSE_BOOKCTRL + +#if WXWIN_COMPATIBILITY_2_6 + +wxBookCtrlSizer::wxBookCtrlSizer(wxBookCtrlBase *bookctrl) + : m_bookctrl(bookctrl) +{ + wxASSERT_MSG( bookctrl, wxT("wxBookCtrlSizer needs a control") ); +} + +#endif // WXWIN_COMPATIBILITY_2_6 + +void wxBookCtrlSizer::RecalcSizes() +{ + m_bookctrl->SetSize( m_position.x, m_position.y, m_size.x, m_size.y ); +} + +wxSize wxBookCtrlSizer::CalcMin() +{ + wxSize sizeBorder = m_bookctrl->CalcSizeFromPage(wxSize(0,0)); + + sizeBorder.x += 5; + sizeBorder.y += 5; + + if ( m_bookctrl->GetPageCount() == 0 ) + { + return wxSize(sizeBorder.x + 10, sizeBorder.y + 10); + } + + int maxX = 0; + int maxY = 0; + + wxWindowList::compatibility_iterator + node = m_bookctrl->GetChildren().GetFirst(); + while (node) + { + wxWindow *item = node->GetData(); + wxSizer *itemsizer = item->GetSizer(); + + if (itemsizer) + { + wxSize subsize( itemsizer->CalcMin() ); + + if (subsize.x > maxX) + maxX = subsize.x; + if (subsize.y > maxY) + maxY = subsize.y; + } + + node = node->GetNext(); + } + + return wxSize( maxX, maxY ) + sizeBorder; +} + +#if wxUSE_NOTEBOOK + +#if WXWIN_COMPATIBILITY_2_6 + +wxNotebookSizer::wxNotebookSizer(wxNotebook *nb) +{ + wxASSERT_MSG( nb, wxT("wxNotebookSizer needs a control") ); + m_bookctrl = nb; +} + +#endif // WXWIN_COMPATIBILITY_2_6 + +#endif // wxUSE_NOTEBOOOK +#endif // wxUSE_BOOKCTRL + +#endif // WXWIN_COMPATIBILITY_2_4 diff --git a/Externals/wxWidgets/src/common/socket.cpp b/Externals/wxWidgets/src/common/socket.cpp index 6cdcfb2bcc..fce138f069 100644 --- a/Externals/wxWidgets/src/common/socket.cpp +++ b/Externals/wxWidgets/src/common/socket.cpp @@ -1,1420 +1,1420 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/socket.cpp -// Purpose: Socket handler classes -// Authors: Guilhem Lavaux, Guillermo Rodriguez Garcia -// Created: April 1997 -// Copyright: (C) 1999-1997, Guilhem Lavaux -// (C) 2000-1999, Guillermo Rodriguez Garcia -// RCS_ID: $Id: socket.cpp 44662 2007-03-07 23:21:48Z VZ $ -// License: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// ========================================================================== -// Declarations -// ========================================================================== - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_SOCKETS - -#include "wx/socket.h" - -#ifndef WX_PRECOMP - #include "wx/object.h" - #include "wx/string.h" - #include "wx/intl.h" - #include "wx/log.h" - #include "wx/event.h" - #include "wx/app.h" - #include "wx/utils.h" - #include "wx/timer.h" - #include "wx/module.h" -#endif - -#include "wx/apptrait.h" - -#include "wx/sckaddr.h" -#include "wx/datetime.h" - -// DLL options compatibility check: -#include "wx/build.h" -WX_CHECK_BUILD_OPTIONS("wxNet") - -// -------------------------------------------------------------------------- -// macros and constants -// -------------------------------------------------------------------------- - -// discard buffer -#define MAX_DISCARD_SIZE (10 * 1024) - -// what to do within waits: we have 2 cases: from the main thread itself we -// have to call wxYield() to let the events (including the GUI events and the -// low-level (not wxWidgets) events from GSocket) be processed. From another -// thread it is enough to just call wxThread::Yield() which will give away the -// rest of our time slice: the explanation is that the events will be processed -// by the main thread anyhow, without calling wxYield(), but we don't want to -// eat the CPU time uselessly while sitting in the loop waiting for the data -#if wxUSE_THREADS - #define PROCESS_EVENTS() \ - { \ - if ( wxThread::IsMain() ) \ - wxYield(); \ - else \ - wxThread::Yield(); \ - } -#else // !wxUSE_THREADS - #define PROCESS_EVENTS() wxYield() -#endif // wxUSE_THREADS/!wxUSE_THREADS - -#define wxTRACE_Socket _T("wxSocket") - -// -------------------------------------------------------------------------- -// wxWin macros -// -------------------------------------------------------------------------- - -IMPLEMENT_CLASS(wxSocketBase, wxObject) -IMPLEMENT_CLASS(wxSocketServer, wxSocketBase) -IMPLEMENT_CLASS(wxSocketClient, wxSocketBase) -IMPLEMENT_CLASS(wxDatagramSocket, wxSocketBase) -IMPLEMENT_DYNAMIC_CLASS(wxSocketEvent, wxEvent) - -// -------------------------------------------------------------------------- -// private classes -// -------------------------------------------------------------------------- - -class wxSocketState : public wxObject -{ -public: - wxSocketFlags m_flags; - wxSocketEventFlags m_eventmask; - bool m_notify; - void *m_clientData; - -public: - wxSocketState() : wxObject() {} - - DECLARE_NO_COPY_CLASS(wxSocketState) -}; - -// ========================================================================== -// wxSocketBase -// ========================================================================== - -// -------------------------------------------------------------------------- -// Initialization and shutdown -// -------------------------------------------------------------------------- - -// FIXME-MT: all this is MT-unsafe, of course, we should protect all accesses -// to m_countInit with a crit section -size_t wxSocketBase::m_countInit = 0; - -bool wxSocketBase::IsInitialized() -{ - return m_countInit > 0; -} - -bool wxSocketBase::Initialize() -{ - if ( !m_countInit++ ) - { - /* - Details: Initialize() creates a hidden window as a sink for socket - events, such as 'read completed'. wxMSW has only one message loop - for the main thread. If Initialize is called in a secondary thread, - the socket window will be created for the secondary thread, but - since there is no message loop on this thread, it will never - receive events and all socket operations will time out. - BTW, the main thread must not be stopped using sleep or block - on a semaphore (a bad idea in any case) or socket operations - will time out. - - On the Mac side, Initialize() stores a pointer to the CFRunLoop for - the main thread. Because secondary threads do not have run loops, - adding event notifications to the "Current" loop would have no - effect at all, events would never fire. - */ - wxASSERT_MSG( wxIsMainThread(), - wxT("Call wxSocketBase::Initialize() from the main thread first!")); - - wxAppTraits *traits = wxAppConsole::GetInstance() ? - wxAppConsole::GetInstance()->GetTraits() : NULL; - GSocketGUIFunctionsTable *functions = - traits ? traits->GetSocketGUIFunctionsTable() : NULL; - GSocket_SetGUIFunctions(functions); - - if ( !GSocket_Init() ) - { - m_countInit--; - - return false; - } - } - - return true; -} - -void wxSocketBase::Shutdown() -{ - // we should be initialized - wxASSERT_MSG( m_countInit, _T("extra call to Shutdown()") ); - if ( --m_countInit == 0 ) - { - GSocket_Cleanup(); - } -} - -// -------------------------------------------------------------------------- -// Ctor and dtor -// -------------------------------------------------------------------------- - -void wxSocketBase::Init() -{ - m_socket = NULL; - m_type = wxSOCKET_UNINIT; - - // state - m_flags = 0; - m_connected = - m_establishing = - m_reading = - m_writing = - m_error = false; - m_lcount = 0; - m_timeout = 600; - m_beingDeleted = false; - - // pushback buffer - m_unread = NULL; - m_unrd_size = 0; - m_unrd_cur = 0; - - // events - m_id = wxID_ANY; - m_handler = NULL; - m_clientData = NULL; - m_notify = false; - m_eventmask = 0; - - if ( !IsInitialized() ) - { - // this Initialize() will be undone by wxSocketModule::OnExit(), all the - // other calls to it should be matched by a call to Shutdown() - Initialize(); - } -} - -wxSocketBase::wxSocketBase() -{ - Init(); -} - -wxSocketBase::wxSocketBase(wxSocketFlags flags, wxSocketType type) -{ - Init(); - - m_flags = flags; - m_type = type; -} - -wxSocketBase::~wxSocketBase() -{ - // Just in case the app called Destroy() *and* then deleted - // the socket immediately: don't leave dangling pointers. - wxAppTraits *traits = wxTheApp ? wxTheApp->GetTraits() : NULL; - if ( traits ) - traits->RemoveFromPendingDelete(this); - - // Shutdown and close the socket - if (!m_beingDeleted) - Close(); - - // Destroy the GSocket object - if (m_socket) - delete m_socket; - - // Free the pushback buffer - if (m_unread) - free(m_unread); -} - -bool wxSocketBase::Destroy() -{ - // Delayed destruction: the socket will be deleted during the next - // idle loop iteration. This ensures that all pending events have - // been processed. - m_beingDeleted = true; - - // Shutdown and close the socket - Close(); - - // Supress events from now on - Notify(false); - - // schedule this object for deletion - wxAppTraits *traits = wxTheApp ? wxTheApp->GetTraits() : NULL; - if ( traits ) - { - // let the traits object decide what to do with us - traits->ScheduleForDestroy(this); - } - else // no app or no traits - { - // in wxBase we might have no app object at all, don't leak memory - delete this; - } - - return true; -} - -// -------------------------------------------------------------------------- -// Basic IO calls -// -------------------------------------------------------------------------- - -// The following IO operations update m_error and m_lcount: -// {Read, Write, ReadMsg, WriteMsg, Peek, Unread, Discard} -// -// TODO: Should Connect, Accept and AcceptWith update m_error? - -bool wxSocketBase::Close() -{ - // Interrupt pending waits - InterruptWait(); - - if (m_socket) - { - // Disable callbacks - m_socket->UnsetCallback(GSOCK_INPUT_FLAG | GSOCK_OUTPUT_FLAG | - GSOCK_LOST_FLAG | GSOCK_CONNECTION_FLAG); - - // Shutdown the connection - m_socket->Shutdown(); - } - - m_connected = false; - m_establishing = false; - return true; -} - -wxSocketBase& wxSocketBase::Read(void* buffer, wxUint32 nbytes) -{ - // Mask read events - m_reading = true; - - m_lcount = _Read(buffer, nbytes); - - // If in wxSOCKET_WAITALL mode, all bytes should have been read. - if (m_flags & wxSOCKET_WAITALL) - m_error = (m_lcount != nbytes); - else - m_error = (m_lcount == 0); - - // Allow read events from now on - m_reading = false; - - return *this; -} - -wxUint32 wxSocketBase::_Read(void* buffer, wxUint32 nbytes) -{ - int total; - - // Try the pushback buffer first - total = GetPushback(buffer, nbytes, false); - nbytes -= total; - buffer = (char *)buffer + total; - - // Return now in one of the following cases: - // - the socket is invalid, - // - we got all the data - if ( !m_socket || - !nbytes ) - return total; - - // Possible combinations (they are checked in this order) - // wxSOCKET_NOWAIT - // wxSOCKET_WAITALL (with or without wxSOCKET_BLOCK) - // wxSOCKET_BLOCK - // wxSOCKET_NONE - // - int ret; - if (m_flags & wxSOCKET_NOWAIT) - { - m_socket->SetNonBlocking(1); - ret = m_socket->Read((char *)buffer, nbytes); - m_socket->SetNonBlocking(0); - - if (ret > 0) - total += ret; - } - else - { - bool more = true; - - while (more) - { - if ( !(m_flags & wxSOCKET_BLOCK) && !WaitForRead() ) - break; - - ret = m_socket->Read((char *)buffer, nbytes); - - if (ret > 0) - { - total += ret; - nbytes -= ret; - buffer = (char *)buffer + ret; - } - - // If we got here and wxSOCKET_WAITALL is not set, we can leave - // now. Otherwise, wait until we recv all the data or until there - // is an error. - // - more = (ret > 0 && nbytes > 0 && (m_flags & wxSOCKET_WAITALL)); - } - } - - return total; -} - -wxSocketBase& wxSocketBase::ReadMsg(void* buffer, wxUint32 nbytes) -{ - wxUint32 len, len2, sig, total; - bool error; - int old_flags; - struct - { - unsigned char sig[4]; - unsigned char len[4]; - } msg; - - // Mask read events - m_reading = true; - - total = 0; - error = true; - old_flags = m_flags; - SetFlags((m_flags & wxSOCKET_BLOCK) | wxSOCKET_WAITALL); - - if (_Read(&msg, sizeof(msg)) != sizeof(msg)) - goto exit; - - sig = (wxUint32)msg.sig[0]; - sig |= (wxUint32)(msg.sig[1] << 8); - sig |= (wxUint32)(msg.sig[2] << 16); - sig |= (wxUint32)(msg.sig[3] << 24); - - if (sig != 0xfeeddead) - { - wxLogWarning(_("wxSocket: invalid signature in ReadMsg.")); - goto exit; - } - - len = (wxUint32)msg.len[0]; - len |= (wxUint32)(msg.len[1] << 8); - len |= (wxUint32)(msg.len[2] << 16); - len |= (wxUint32)(msg.len[3] << 24); - - if (len > nbytes) - { - len2 = len - nbytes; - len = nbytes; - } - else - len2 = 0; - - // Don't attemp to read if the msg was zero bytes long. - if (len) - { - total = _Read(buffer, len); - - if (total != len) - goto exit; - } - if (len2) - { - char *discard_buffer = new char[MAX_DISCARD_SIZE]; - long discard_len; - - // NOTE: discarded bytes don't add to m_lcount. - do - { - discard_len = ((len2 > MAX_DISCARD_SIZE)? MAX_DISCARD_SIZE : len2); - discard_len = _Read(discard_buffer, (wxUint32)discard_len); - len2 -= (wxUint32)discard_len; - } - while ((discard_len > 0) && len2); - - delete [] discard_buffer; - - if (len2 != 0) - goto exit; - } - if (_Read(&msg, sizeof(msg)) != sizeof(msg)) - goto exit; - - sig = (wxUint32)msg.sig[0]; - sig |= (wxUint32)(msg.sig[1] << 8); - sig |= (wxUint32)(msg.sig[2] << 16); - sig |= (wxUint32)(msg.sig[3] << 24); - - if (sig != 0xdeadfeed) - { - wxLogWarning(_("wxSocket: invalid signature in ReadMsg.")); - goto exit; - } - - // everything was OK - error = false; - -exit: - m_error = error; - m_lcount = total; - m_reading = false; - SetFlags(old_flags); - - return *this; -} - -wxSocketBase& wxSocketBase::Peek(void* buffer, wxUint32 nbytes) -{ - // Mask read events - m_reading = true; - - m_lcount = _Read(buffer, nbytes); - Pushback(buffer, m_lcount); - - // If in wxSOCKET_WAITALL mode, all bytes should have been read. - if (m_flags & wxSOCKET_WAITALL) - m_error = (m_lcount != nbytes); - else - m_error = (m_lcount == 0); - - // Allow read events again - m_reading = false; - - return *this; -} - -wxSocketBase& wxSocketBase::Write(const void *buffer, wxUint32 nbytes) -{ - // Mask write events - m_writing = true; - - m_lcount = _Write(buffer, nbytes); - - // If in wxSOCKET_WAITALL mode, all bytes should have been written. - if (m_flags & wxSOCKET_WAITALL) - m_error = (m_lcount != nbytes); - else - m_error = (m_lcount == 0); - - // Allow write events again - m_writing = false; - - return *this; -} - -wxUint32 wxSocketBase::_Write(const void *buffer, wxUint32 nbytes) -{ - wxUint32 total = 0; - - // If the socket is invalid or parameters are ill, return immediately - if (!m_socket || !buffer || !nbytes) - return 0; - - // Possible combinations (they are checked in this order) - // wxSOCKET_NOWAIT - // wxSOCKET_WAITALL (with or without wxSOCKET_BLOCK) - // wxSOCKET_BLOCK - // wxSOCKET_NONE - // - int ret; - if (m_flags & wxSOCKET_NOWAIT) - { - m_socket->SetNonBlocking(1); - ret = m_socket->Write((const char *)buffer, nbytes); - m_socket->SetNonBlocking(0); - - if (ret > 0) - total = ret; - } - else - { - bool more = true; - - while (more) - { - if ( !(m_flags & wxSOCKET_BLOCK) && !WaitForWrite() ) - break; - - ret = m_socket->Write((const char *)buffer, nbytes); - - if (ret > 0) - { - total += ret; - nbytes -= ret; - buffer = (const char *)buffer + ret; - } - - // If we got here and wxSOCKET_WAITALL is not set, we can leave - // now. Otherwise, wait until we send all the data or until there - // is an error. - // - more = (ret > 0 && nbytes > 0 && (m_flags & wxSOCKET_WAITALL)); - } - } - - return total; -} - -wxSocketBase& wxSocketBase::WriteMsg(const void *buffer, wxUint32 nbytes) -{ - wxUint32 total; - bool error; - struct - { - unsigned char sig[4]; - unsigned char len[4]; - } msg; - - // Mask write events - m_writing = true; - - error = true; - total = 0; - SetFlags((m_flags & wxSOCKET_BLOCK) | wxSOCKET_WAITALL); - - msg.sig[0] = (unsigned char) 0xad; - msg.sig[1] = (unsigned char) 0xde; - msg.sig[2] = (unsigned char) 0xed; - msg.sig[3] = (unsigned char) 0xfe; - - msg.len[0] = (unsigned char) (nbytes & 0xff); - msg.len[1] = (unsigned char) ((nbytes >> 8) & 0xff); - msg.len[2] = (unsigned char) ((nbytes >> 16) & 0xff); - msg.len[3] = (unsigned char) ((nbytes >> 24) & 0xff); - - if (_Write(&msg, sizeof(msg)) < sizeof(msg)) - goto exit; - - total = _Write(buffer, nbytes); - - if (total < nbytes) - goto exit; - - msg.sig[0] = (unsigned char) 0xed; - msg.sig[1] = (unsigned char) 0xfe; - msg.sig[2] = (unsigned char) 0xad; - msg.sig[3] = (unsigned char) 0xde; - msg.len[0] = msg.len[1] = msg.len[2] = msg.len[3] = (char) 0; - - if ((_Write(&msg, sizeof(msg))) < sizeof(msg)) - goto exit; - - // everything was OK - error = false; - -exit: - m_error = error; - m_lcount = total; - m_writing = false; - - return *this; -} - -wxSocketBase& wxSocketBase::Unread(const void *buffer, wxUint32 nbytes) -{ - if (nbytes != 0) - Pushback(buffer, nbytes); - - m_error = false; - m_lcount = nbytes; - - return *this; -} - -wxSocketBase& wxSocketBase::Discard() -{ - char *buffer = new char[MAX_DISCARD_SIZE]; - wxUint32 ret; - wxUint32 total = 0; - - // Mask read events - m_reading = true; - - SetFlags(wxSOCKET_NOWAIT); - - do - { - ret = _Read(buffer, MAX_DISCARD_SIZE); - total += ret; - } - while (ret == MAX_DISCARD_SIZE); - - delete[] buffer; - m_lcount = total; - m_error = false; - - // Allow read events again - m_reading = false; - - return *this; -} - -// -------------------------------------------------------------------------- -// Wait functions -// -------------------------------------------------------------------------- - -// All Wait functions poll the socket using GSocket_Select() to -// check for the specified combination of conditions, until one -// of these conditions become true, an error occurs, or the -// timeout elapses. The polling loop calls PROCESS_EVENTS(), so -// this won't block the GUI. - -bool wxSocketBase::_Wait(long seconds, - long milliseconds, - wxSocketEventFlags flags) -{ - GSocketEventFlags result; - long timeout; - - // Set this to true to interrupt ongoing waits - m_interrupt = false; - - // Check for valid socket - if (!m_socket) - return false; - - // Check for valid timeout value. - if (seconds != -1) - timeout = seconds * 1000 + milliseconds; - else - timeout = m_timeout * 1000; - - bool has_event_loop = wxTheApp->GetTraits() ? (wxTheApp->GetTraits()->GetSocketGUIFunctionsTable() ? true : false) : false; - - // Wait in an active polling loop. - // - // NOTE: We duplicate some of the code in OnRequest, but this doesn't - // hurt. It has to be here because the (GSocket) event might arrive - // a bit delayed, and it has to be in OnRequest as well because we - // don't know whether the Wait functions are being used. - // - // Do this at least once (important if timeout == 0, when - // we are just polling). Also, if just polling, do not yield. - - wxDateTime current_time = wxDateTime::UNow(); - unsigned int time_limit = (current_time.GetTicks() * 1000) + current_time.GetMillisecond() + timeout; - bool done = false; - bool valid_result = false; - - if (!has_event_loop) - { - // This is used to avoid a busy loop on wxBase - having a select - // timeout of 50 ms per iteration should be enough. - if (timeout > 50) - m_socket->SetTimeout(50); - else - m_socket->SetTimeout(timeout); - } - - while (!done) - { - result = m_socket->Select(flags | GSOCK_LOST_FLAG); - - // Incoming connection (server) or connection established (client) - if (result & GSOCK_CONNECTION_FLAG) - { - m_connected = true; - m_establishing = false; - valid_result = true; - break; - } - - // Data available or output buffer ready - if ((result & GSOCK_INPUT_FLAG) || (result & GSOCK_OUTPUT_FLAG)) - { - valid_result = true; - break; - } - - // Connection lost - if (result & GSOCK_LOST_FLAG) - { - m_connected = false; - m_establishing = false; - valid_result = ((flags & GSOCK_LOST_FLAG) != 0); - break; - } - - // Wait more? - current_time = wxDateTime::UNow(); - int time_left = time_limit - ((current_time.GetTicks() * 1000) + current_time.GetMillisecond()); - if ((!timeout) || (time_left <= 0) || (m_interrupt)) - done = true; - else - { - if (has_event_loop) - { - PROCESS_EVENTS(); - } - else - { - // If there's less than 50 ms left, just call select with that timeout. - if (time_left < 50) - m_socket->SetTimeout(time_left); - } - } - } - - // Set timeout back to original value (we overwrote it for polling) - if (!has_event_loop) - m_socket->SetTimeout(m_timeout*1000); - - return valid_result; -} - -bool wxSocketBase::Wait(long seconds, long milliseconds) -{ - return _Wait(seconds, milliseconds, GSOCK_INPUT_FLAG | - GSOCK_OUTPUT_FLAG | - GSOCK_CONNECTION_FLAG | - GSOCK_LOST_FLAG); -} - -bool wxSocketBase::WaitForRead(long seconds, long milliseconds) -{ - // Check pushback buffer before entering _Wait - if (m_unread) - return true; - - // Note that GSOCK_INPUT_LOST has to be explicitly passed to - // _Wait because of the semantics of WaitForRead: a return - // value of true means that a GSocket_Read call will return - // immediately, not that there is actually data to read. - - return _Wait(seconds, milliseconds, GSOCK_INPUT_FLAG | - GSOCK_LOST_FLAG); -} - - -bool wxSocketBase::WaitForWrite(long seconds, long milliseconds) -{ - return _Wait(seconds, milliseconds, GSOCK_OUTPUT_FLAG); -} - -bool wxSocketBase::WaitForLost(long seconds, long milliseconds) -{ - return _Wait(seconds, milliseconds, GSOCK_LOST_FLAG); -} - -// -------------------------------------------------------------------------- -// Miscellaneous -// -------------------------------------------------------------------------- - -// -// Get local or peer address -// - -bool wxSocketBase::GetPeer(wxSockAddress& addr_man) const -{ - GAddress *peer; - - if (!m_socket) - return false; - - peer = m_socket->GetPeer(); - - // copying a null address would just trigger an assert anyway - - if (!peer) - return false; - - addr_man.SetAddress(peer); - GAddress_destroy(peer); - - return true; -} - -bool wxSocketBase::GetLocal(wxSockAddress& addr_man) const -{ - GAddress *local; - - if (!m_socket) - return false; - - local = m_socket->GetLocal(); - addr_man.SetAddress(local); - GAddress_destroy(local); - - return true; -} - -// -// Save and restore socket state -// - -void wxSocketBase::SaveState() -{ - wxSocketState *state; - - state = new wxSocketState(); - - state->m_flags = m_flags; - state->m_notify = m_notify; - state->m_eventmask = m_eventmask; - state->m_clientData = m_clientData; - - m_states.Append(state); -} - -void wxSocketBase::RestoreState() -{ - wxList::compatibility_iterator node; - wxSocketState *state; - - node = m_states.GetLast(); - if (!node) - return; - - state = (wxSocketState *)node->GetData(); - - m_flags = state->m_flags; - m_notify = state->m_notify; - m_eventmask = state->m_eventmask; - m_clientData = state->m_clientData; - - m_states.Erase(node); - delete state; -} - -// -// Timeout and flags -// - -void wxSocketBase::SetTimeout(long seconds) -{ - m_timeout = seconds; - - if (m_socket) - m_socket->SetTimeout(m_timeout * 1000); -} - -void wxSocketBase::SetFlags(wxSocketFlags flags) -{ - m_flags = flags; -} - - -// -------------------------------------------------------------------------- -// Event handling -// -------------------------------------------------------------------------- - -// A note on how events are processed, which is probably the most -// difficult thing to get working right while keeping the same API -// and functionality for all platforms. -// -// When GSocket detects an event, it calls wx_socket_callback, which in -// turn just calls wxSocketBase::OnRequest in the corresponding wxSocket -// object. OnRequest does some housekeeping, and if the event is to be -// propagated to the user, it creates a new wxSocketEvent object and -// posts it. The event is not processed immediately, but delayed with -// AddPendingEvent instead. This is necessary in order to decouple the -// event processing from wx_socket_callback; otherwise, subsequent IO -// calls made from the user event handler would fail, as gtk callbacks -// are not reentrant. -// -// Note that, unlike events, user callbacks (now deprecated) are _not_ -// decoupled from wx_socket_callback and thus they suffer from a variety -// of problems. Avoid them where possible and use events instead. - -extern "C" -void LINKAGEMODE wx_socket_callback(GSocket * WXUNUSED(socket), - GSocketEvent notification, - char *cdata) -{ - wxSocketBase *sckobj = (wxSocketBase *)cdata; - - sckobj->OnRequest((wxSocketNotify) notification); -} - -void wxSocketBase::OnRequest(wxSocketNotify notification) -{ - // NOTE: We duplicate some of the code in _Wait, but this doesn't - // hurt. It has to be here because the (GSocket) event might arrive - // a bit delayed, and it has to be in _Wait as well because we don't - // know whether the Wait functions are being used. - - switch(notification) - { - case wxSOCKET_CONNECTION: - m_establishing = false; - m_connected = true; - break; - - // If we are in the middle of a R/W operation, do not - // propagate events to users. Also, filter 'late' events - // which are no longer valid. - - case wxSOCKET_INPUT: - if (m_reading || !m_socket->Select(GSOCK_INPUT_FLAG)) - return; - break; - - case wxSOCKET_OUTPUT: - if (m_writing || !m_socket->Select(GSOCK_OUTPUT_FLAG)) - return; - break; - - case wxSOCKET_LOST: - m_connected = false; - m_establishing = false; - break; - - default: - break; - } - - // Schedule the event - - wxSocketEventFlags flag = 0; - wxUnusedVar(flag); - switch (notification) - { - case GSOCK_INPUT: flag = GSOCK_INPUT_FLAG; break; - case GSOCK_OUTPUT: flag = GSOCK_OUTPUT_FLAG; break; - case GSOCK_CONNECTION: flag = GSOCK_CONNECTION_FLAG; break; - case GSOCK_LOST: flag = GSOCK_LOST_FLAG; break; - default: - wxLogWarning(_("wxSocket: unknown event!.")); - return; - } - - if (((m_eventmask & flag) == flag) && m_notify) - { - if (m_handler) - { - wxSocketEvent event(m_id); - event.m_event = notification; - event.m_clientData = m_clientData; - event.SetEventObject(this); - - m_handler->AddPendingEvent(event); - } - } -} - -void wxSocketBase::Notify(bool notify) -{ - m_notify = notify; -} - -void wxSocketBase::SetNotify(wxSocketEventFlags flags) -{ - m_eventmask = flags; -} - -void wxSocketBase::SetEventHandler(wxEvtHandler& handler, int id) -{ - m_handler = &handler; - m_id = id; -} - -// -------------------------------------------------------------------------- -// Pushback buffer -// -------------------------------------------------------------------------- - -void wxSocketBase::Pushback(const void *buffer, wxUint32 size) -{ - if (!size) return; - - if (m_unread == NULL) - m_unread = malloc(size); - else - { - void *tmp; - - tmp = malloc(m_unrd_size + size); - memcpy((char *)tmp + size, m_unread, m_unrd_size); - free(m_unread); - - m_unread = tmp; - } - - m_unrd_size += size; - - memcpy(m_unread, buffer, size); -} - -wxUint32 wxSocketBase::GetPushback(void *buffer, wxUint32 size, bool peek) -{ - if (!m_unrd_size) - return 0; - - if (size > (m_unrd_size-m_unrd_cur)) - size = m_unrd_size-m_unrd_cur; - - memcpy(buffer, (char *)m_unread + m_unrd_cur, size); - - if (!peek) - { - m_unrd_cur += size; - if (m_unrd_size == m_unrd_cur) - { - free(m_unread); - m_unread = NULL; - m_unrd_size = 0; - m_unrd_cur = 0; - } - } - - return size; -} - - -// ========================================================================== -// wxSocketServer -// ========================================================================== - -// -------------------------------------------------------------------------- -// Ctor -// -------------------------------------------------------------------------- - -wxSocketServer::wxSocketServer(const wxSockAddress& addr_man, - wxSocketFlags flags) - : wxSocketBase(flags, wxSOCKET_SERVER) -{ - wxLogTrace( wxTRACE_Socket, _T("Opening wxSocketServer") ); - - m_socket = GSocket_new(); - - if (!m_socket) - { - wxLogTrace( wxTRACE_Socket, _T("*** GSocket_new failed") ); - return; - } - - // Setup the socket as server - - m_socket->SetLocal(addr_man.GetAddress()); - - if (GetFlags() & wxSOCKET_REUSEADDR) { - m_socket->SetReusable(); - } - - if (m_socket->SetServer() != GSOCK_NOERROR) - { - delete m_socket; - m_socket = NULL; - - wxLogTrace( wxTRACE_Socket, _T("*** GSocket_SetServer failed") ); - return; - } - - m_socket->SetTimeout(m_timeout * 1000); - m_socket->SetCallback(GSOCK_INPUT_FLAG | GSOCK_OUTPUT_FLAG | - GSOCK_LOST_FLAG | GSOCK_CONNECTION_FLAG, - wx_socket_callback, (char *)this); -} - -// -------------------------------------------------------------------------- -// Accept -// -------------------------------------------------------------------------- - -bool wxSocketServer::AcceptWith(wxSocketBase& sock, bool wait) -{ - GSocket *child_socket; - - if (!m_socket) - return false; - - // If wait == false, then the call should be nonblocking. - // When we are finished, we put the socket to blocking mode - // again. - - if (!wait) - m_socket->SetNonBlocking(1); - - child_socket = m_socket->WaitConnection(); - - if (!wait) - m_socket->SetNonBlocking(0); - - if (!child_socket) - return false; - - sock.m_type = wxSOCKET_BASE; - sock.m_socket = child_socket; - sock.m_connected = true; - - sock.m_socket->SetTimeout(sock.m_timeout * 1000); - sock.m_socket->SetCallback(GSOCK_INPUT_FLAG | GSOCK_OUTPUT_FLAG | - GSOCK_LOST_FLAG | GSOCK_CONNECTION_FLAG, - wx_socket_callback, (char *)&sock); - - return true; -} - -wxSocketBase *wxSocketServer::Accept(bool wait) -{ - wxSocketBase* sock = new wxSocketBase(); - - sock->SetFlags(m_flags); - - if (!AcceptWith(*sock, wait)) - { - sock->Destroy(); - sock = NULL; - } - - return sock; -} - -bool wxSocketServer::WaitForAccept(long seconds, long milliseconds) -{ - return _Wait(seconds, milliseconds, GSOCK_CONNECTION_FLAG); -} - -bool wxSocketBase::GetOption(int level, int optname, void *optval, int *optlen) -{ - wxASSERT_MSG( m_socket, _T("Socket not initialised") ); - - if (m_socket->GetSockOpt(level, optname, optval, optlen) - != GSOCK_NOERROR) - { - return false; - } - return true; -} - -bool wxSocketBase::SetOption(int level, int optname, const void *optval, - int optlen) -{ - wxASSERT_MSG( m_socket, _T("Socket not initialised") ); - - if (m_socket->SetSockOpt(level, optname, optval, optlen) - != GSOCK_NOERROR) - { - return false; - } - return true; -} - -bool wxSocketBase::SetLocal(wxIPV4address& local) -{ - GAddress* la = local.GetAddress(); - - // If the address is valid, save it for use when we call Connect - if (la && la->m_addr) - { - m_localAddress = local; - - return true; - } - - return false; -} - -// ========================================================================== -// wxSocketClient -// ========================================================================== - -// -------------------------------------------------------------------------- -// Ctor and dtor -// -------------------------------------------------------------------------- - -wxSocketClient::wxSocketClient(wxSocketFlags flags) - : wxSocketBase(flags, wxSOCKET_CLIENT) -{ -} - -wxSocketClient::~wxSocketClient() -{ -} - -// -------------------------------------------------------------------------- -// Connect -// -------------------------------------------------------------------------- - -bool wxSocketClient::DoConnect(wxSockAddress& addr_man, wxSockAddress* local, bool wait) -{ - GSocketError err; - - if (m_socket) - { - // Shutdown and destroy the socket - Close(); - delete m_socket; - } - - m_socket = GSocket_new(); - m_connected = false; - m_establishing = false; - - if (!m_socket) - return false; - - m_socket->SetTimeout(m_timeout * 1000); - m_socket->SetCallback(GSOCK_INPUT_FLAG | GSOCK_OUTPUT_FLAG | - GSOCK_LOST_FLAG | GSOCK_CONNECTION_FLAG, - wx_socket_callback, (char *)this); - - // If wait == false, then the call should be nonblocking. - // When we are finished, we put the socket to blocking mode - // again. - - if (!wait) - m_socket->SetNonBlocking(1); - - // Reuse makes sense for clients too, if we are trying to rebind to the same port - if (GetFlags() & wxSOCKET_REUSEADDR) - { - m_socket->SetReusable(); - } - - // If no local address was passed and one has been set, use the one that was Set - if (!local && m_localAddress.GetAddress()) - { - local = &m_localAddress; - } - - // Bind to the local IP address and port, when provided - if (local) - { - GAddress* la = local->GetAddress(); - - if (la && la->m_addr) - m_socket->SetLocal(la); - } - - m_socket->SetPeer(addr_man.GetAddress()); - err = m_socket->Connect(GSOCK_STREAMED); - - if (!wait) - m_socket->SetNonBlocking(0); - - if (err != GSOCK_NOERROR) - { - if (err == GSOCK_WOULDBLOCK) - m_establishing = true; - - return false; - } - - m_connected = true; - return true; -} - -bool wxSocketClient::Connect(wxSockAddress& addr_man, bool wait) -{ - return (DoConnect(addr_man, NULL, wait)); -} - -bool wxSocketClient::Connect(wxSockAddress& addr_man, wxSockAddress& local, bool wait) -{ - return (DoConnect(addr_man, &local, wait)); -} - -bool wxSocketClient::WaitOnConnect(long seconds, long milliseconds) -{ - if (m_connected) // Already connected - return true; - - if (!m_establishing || !m_socket) // No connection in progress - return false; - - return _Wait(seconds, milliseconds, GSOCK_CONNECTION_FLAG | - GSOCK_LOST_FLAG); -} - -// ========================================================================== -// wxDatagramSocket -// ========================================================================== - -/* NOTE: experimental stuff - might change */ - -wxDatagramSocket::wxDatagramSocket( const wxSockAddress& addr, - wxSocketFlags flags ) - : wxSocketBase( flags, wxSOCKET_DATAGRAM ) -{ - // Create the socket - m_socket = GSocket_new(); - - if (!m_socket) - { - wxFAIL_MSG( _T("datagram socket not new'd") ); - return; - } - // Setup the socket as non connection oriented - m_socket->SetLocal(addr.GetAddress()); - if (flags & wxSOCKET_REUSEADDR) - { - m_socket->SetReusable(); - } - if ( m_socket->SetNonOriented() != GSOCK_NOERROR ) - { - delete m_socket; - m_socket = NULL; - return; - } - - // Initialize all stuff - m_connected = false; - m_establishing = false; - m_socket->SetTimeout( m_timeout ); - m_socket->SetCallback( GSOCK_INPUT_FLAG | GSOCK_OUTPUT_FLAG | - GSOCK_LOST_FLAG | GSOCK_CONNECTION_FLAG, - wx_socket_callback, (char*)this ); -} - -wxDatagramSocket& wxDatagramSocket::RecvFrom( wxSockAddress& addr, - void* buf, - wxUint32 nBytes ) -{ - Read(buf, nBytes); - GetPeer(addr); - return (*this); -} - -wxDatagramSocket& wxDatagramSocket::SendTo( const wxSockAddress& addr, - const void* buf, - wxUint32 nBytes ) -{ - wxASSERT_MSG( m_socket, _T("Socket not initialised") ); - - m_socket->SetPeer(addr.GetAddress()); - Write(buf, nBytes); - return (*this); -} - -// ========================================================================== -// wxSocketModule -// ========================================================================== - -class wxSocketModule : public wxModule -{ -public: - virtual bool OnInit() - { - // wxSocketBase will call GSocket_Init() itself when/if needed - return true; - } - - virtual void OnExit() - { - if ( wxSocketBase::IsInitialized() ) - wxSocketBase::Shutdown(); - } - -private: - DECLARE_DYNAMIC_CLASS(wxSocketModule) -}; - -IMPLEMENT_DYNAMIC_CLASS(wxSocketModule, wxModule) - -#endif - // wxUSE_SOCKETS +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/socket.cpp +// Purpose: Socket handler classes +// Authors: Guilhem Lavaux, Guillermo Rodriguez Garcia +// Created: April 1997 +// Copyright: (C) 1999-1997, Guilhem Lavaux +// (C) 2000-1999, Guillermo Rodriguez Garcia +// RCS_ID: $Id: socket.cpp 44662 2007-03-07 23:21:48Z VZ $ +// License: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ========================================================================== +// Declarations +// ========================================================================== + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_SOCKETS + +#include "wx/socket.h" + +#ifndef WX_PRECOMP + #include "wx/object.h" + #include "wx/string.h" + #include "wx/intl.h" + #include "wx/log.h" + #include "wx/event.h" + #include "wx/app.h" + #include "wx/utils.h" + #include "wx/timer.h" + #include "wx/module.h" +#endif + +#include "wx/apptrait.h" + +#include "wx/sckaddr.h" +#include "wx/datetime.h" + +// DLL options compatibility check: +#include "wx/build.h" +WX_CHECK_BUILD_OPTIONS("wxNet") + +// -------------------------------------------------------------------------- +// macros and constants +// -------------------------------------------------------------------------- + +// discard buffer +#define MAX_DISCARD_SIZE (10 * 1024) + +// what to do within waits: we have 2 cases: from the main thread itself we +// have to call wxYield() to let the events (including the GUI events and the +// low-level (not wxWidgets) events from GSocket) be processed. From another +// thread it is enough to just call wxThread::Yield() which will give away the +// rest of our time slice: the explanation is that the events will be processed +// by the main thread anyhow, without calling wxYield(), but we don't want to +// eat the CPU time uselessly while sitting in the loop waiting for the data +#if wxUSE_THREADS + #define PROCESS_EVENTS() \ + { \ + if ( wxThread::IsMain() ) \ + wxYield(); \ + else \ + wxThread::Yield(); \ + } +#else // !wxUSE_THREADS + #define PROCESS_EVENTS() wxYield() +#endif // wxUSE_THREADS/!wxUSE_THREADS + +#define wxTRACE_Socket _T("wxSocket") + +// -------------------------------------------------------------------------- +// wxWin macros +// -------------------------------------------------------------------------- + +IMPLEMENT_CLASS(wxSocketBase, wxObject) +IMPLEMENT_CLASS(wxSocketServer, wxSocketBase) +IMPLEMENT_CLASS(wxSocketClient, wxSocketBase) +IMPLEMENT_CLASS(wxDatagramSocket, wxSocketBase) +IMPLEMENT_DYNAMIC_CLASS(wxSocketEvent, wxEvent) + +// -------------------------------------------------------------------------- +// private classes +// -------------------------------------------------------------------------- + +class wxSocketState : public wxObject +{ +public: + wxSocketFlags m_flags; + wxSocketEventFlags m_eventmask; + bool m_notify; + void *m_clientData; + +public: + wxSocketState() : wxObject() {} + + DECLARE_NO_COPY_CLASS(wxSocketState) +}; + +// ========================================================================== +// wxSocketBase +// ========================================================================== + +// -------------------------------------------------------------------------- +// Initialization and shutdown +// -------------------------------------------------------------------------- + +// FIXME-MT: all this is MT-unsafe, of course, we should protect all accesses +// to m_countInit with a crit section +size_t wxSocketBase::m_countInit = 0; + +bool wxSocketBase::IsInitialized() +{ + return m_countInit > 0; +} + +bool wxSocketBase::Initialize() +{ + if ( !m_countInit++ ) + { + /* + Details: Initialize() creates a hidden window as a sink for socket + events, such as 'read completed'. wxMSW has only one message loop + for the main thread. If Initialize is called in a secondary thread, + the socket window will be created for the secondary thread, but + since there is no message loop on this thread, it will never + receive events and all socket operations will time out. + BTW, the main thread must not be stopped using sleep or block + on a semaphore (a bad idea in any case) or socket operations + will time out. + + On the Mac side, Initialize() stores a pointer to the CFRunLoop for + the main thread. Because secondary threads do not have run loops, + adding event notifications to the "Current" loop would have no + effect at all, events would never fire. + */ + wxASSERT_MSG( wxIsMainThread(), + wxT("Call wxSocketBase::Initialize() from the main thread first!")); + + wxAppTraits *traits = wxAppConsole::GetInstance() ? + wxAppConsole::GetInstance()->GetTraits() : NULL; + GSocketGUIFunctionsTable *functions = + traits ? traits->GetSocketGUIFunctionsTable() : NULL; + GSocket_SetGUIFunctions(functions); + + if ( !GSocket_Init() ) + { + m_countInit--; + + return false; + } + } + + return true; +} + +void wxSocketBase::Shutdown() +{ + // we should be initialized + wxASSERT_MSG( m_countInit, _T("extra call to Shutdown()") ); + if ( --m_countInit == 0 ) + { + GSocket_Cleanup(); + } +} + +// -------------------------------------------------------------------------- +// Ctor and dtor +// -------------------------------------------------------------------------- + +void wxSocketBase::Init() +{ + m_socket = NULL; + m_type = wxSOCKET_UNINIT; + + // state + m_flags = 0; + m_connected = + m_establishing = + m_reading = + m_writing = + m_error = false; + m_lcount = 0; + m_timeout = 600; + m_beingDeleted = false; + + // pushback buffer + m_unread = NULL; + m_unrd_size = 0; + m_unrd_cur = 0; + + // events + m_id = wxID_ANY; + m_handler = NULL; + m_clientData = NULL; + m_notify = false; + m_eventmask = 0; + + if ( !IsInitialized() ) + { + // this Initialize() will be undone by wxSocketModule::OnExit(), all the + // other calls to it should be matched by a call to Shutdown() + Initialize(); + } +} + +wxSocketBase::wxSocketBase() +{ + Init(); +} + +wxSocketBase::wxSocketBase(wxSocketFlags flags, wxSocketType type) +{ + Init(); + + m_flags = flags; + m_type = type; +} + +wxSocketBase::~wxSocketBase() +{ + // Just in case the app called Destroy() *and* then deleted + // the socket immediately: don't leave dangling pointers. + wxAppTraits *traits = wxTheApp ? wxTheApp->GetTraits() : NULL; + if ( traits ) + traits->RemoveFromPendingDelete(this); + + // Shutdown and close the socket + if (!m_beingDeleted) + Close(); + + // Destroy the GSocket object + if (m_socket) + delete m_socket; + + // Free the pushback buffer + if (m_unread) + free(m_unread); +} + +bool wxSocketBase::Destroy() +{ + // Delayed destruction: the socket will be deleted during the next + // idle loop iteration. This ensures that all pending events have + // been processed. + m_beingDeleted = true; + + // Shutdown and close the socket + Close(); + + // Supress events from now on + Notify(false); + + // schedule this object for deletion + wxAppTraits *traits = wxTheApp ? wxTheApp->GetTraits() : NULL; + if ( traits ) + { + // let the traits object decide what to do with us + traits->ScheduleForDestroy(this); + } + else // no app or no traits + { + // in wxBase we might have no app object at all, don't leak memory + delete this; + } + + return true; +} + +// -------------------------------------------------------------------------- +// Basic IO calls +// -------------------------------------------------------------------------- + +// The following IO operations update m_error and m_lcount: +// {Read, Write, ReadMsg, WriteMsg, Peek, Unread, Discard} +// +// TODO: Should Connect, Accept and AcceptWith update m_error? + +bool wxSocketBase::Close() +{ + // Interrupt pending waits + InterruptWait(); + + if (m_socket) + { + // Disable callbacks + m_socket->UnsetCallback(GSOCK_INPUT_FLAG | GSOCK_OUTPUT_FLAG | + GSOCK_LOST_FLAG | GSOCK_CONNECTION_FLAG); + + // Shutdown the connection + m_socket->Shutdown(); + } + + m_connected = false; + m_establishing = false; + return true; +} + +wxSocketBase& wxSocketBase::Read(void* buffer, wxUint32 nbytes) +{ + // Mask read events + m_reading = true; + + m_lcount = _Read(buffer, nbytes); + + // If in wxSOCKET_WAITALL mode, all bytes should have been read. + if (m_flags & wxSOCKET_WAITALL) + m_error = (m_lcount != nbytes); + else + m_error = (m_lcount == 0); + + // Allow read events from now on + m_reading = false; + + return *this; +} + +wxUint32 wxSocketBase::_Read(void* buffer, wxUint32 nbytes) +{ + int total; + + // Try the pushback buffer first + total = GetPushback(buffer, nbytes, false); + nbytes -= total; + buffer = (char *)buffer + total; + + // Return now in one of the following cases: + // - the socket is invalid, + // - we got all the data + if ( !m_socket || + !nbytes ) + return total; + + // Possible combinations (they are checked in this order) + // wxSOCKET_NOWAIT + // wxSOCKET_WAITALL (with or without wxSOCKET_BLOCK) + // wxSOCKET_BLOCK + // wxSOCKET_NONE + // + int ret; + if (m_flags & wxSOCKET_NOWAIT) + { + m_socket->SetNonBlocking(1); + ret = m_socket->Read((char *)buffer, nbytes); + m_socket->SetNonBlocking(0); + + if (ret > 0) + total += ret; + } + else + { + bool more = true; + + while (more) + { + if ( !(m_flags & wxSOCKET_BLOCK) && !WaitForRead() ) + break; + + ret = m_socket->Read((char *)buffer, nbytes); + + if (ret > 0) + { + total += ret; + nbytes -= ret; + buffer = (char *)buffer + ret; + } + + // If we got here and wxSOCKET_WAITALL is not set, we can leave + // now. Otherwise, wait until we recv all the data or until there + // is an error. + // + more = (ret > 0 && nbytes > 0 && (m_flags & wxSOCKET_WAITALL)); + } + } + + return total; +} + +wxSocketBase& wxSocketBase::ReadMsg(void* buffer, wxUint32 nbytes) +{ + wxUint32 len, len2, sig, total; + bool error; + int old_flags; + struct + { + unsigned char sig[4]; + unsigned char len[4]; + } msg; + + // Mask read events + m_reading = true; + + total = 0; + error = true; + old_flags = m_flags; + SetFlags((m_flags & wxSOCKET_BLOCK) | wxSOCKET_WAITALL); + + if (_Read(&msg, sizeof(msg)) != sizeof(msg)) + goto exit; + + sig = (wxUint32)msg.sig[0]; + sig |= (wxUint32)(msg.sig[1] << 8); + sig |= (wxUint32)(msg.sig[2] << 16); + sig |= (wxUint32)(msg.sig[3] << 24); + + if (sig != 0xfeeddead) + { + wxLogWarning(_("wxSocket: invalid signature in ReadMsg.")); + goto exit; + } + + len = (wxUint32)msg.len[0]; + len |= (wxUint32)(msg.len[1] << 8); + len |= (wxUint32)(msg.len[2] << 16); + len |= (wxUint32)(msg.len[3] << 24); + + if (len > nbytes) + { + len2 = len - nbytes; + len = nbytes; + } + else + len2 = 0; + + // Don't attemp to read if the msg was zero bytes long. + if (len) + { + total = _Read(buffer, len); + + if (total != len) + goto exit; + } + if (len2) + { + char *discard_buffer = new char[MAX_DISCARD_SIZE]; + long discard_len; + + // NOTE: discarded bytes don't add to m_lcount. + do + { + discard_len = ((len2 > MAX_DISCARD_SIZE)? MAX_DISCARD_SIZE : len2); + discard_len = _Read(discard_buffer, (wxUint32)discard_len); + len2 -= (wxUint32)discard_len; + } + while ((discard_len > 0) && len2); + + delete [] discard_buffer; + + if (len2 != 0) + goto exit; + } + if (_Read(&msg, sizeof(msg)) != sizeof(msg)) + goto exit; + + sig = (wxUint32)msg.sig[0]; + sig |= (wxUint32)(msg.sig[1] << 8); + sig |= (wxUint32)(msg.sig[2] << 16); + sig |= (wxUint32)(msg.sig[3] << 24); + + if (sig != 0xdeadfeed) + { + wxLogWarning(_("wxSocket: invalid signature in ReadMsg.")); + goto exit; + } + + // everything was OK + error = false; + +exit: + m_error = error; + m_lcount = total; + m_reading = false; + SetFlags(old_flags); + + return *this; +} + +wxSocketBase& wxSocketBase::Peek(void* buffer, wxUint32 nbytes) +{ + // Mask read events + m_reading = true; + + m_lcount = _Read(buffer, nbytes); + Pushback(buffer, m_lcount); + + // If in wxSOCKET_WAITALL mode, all bytes should have been read. + if (m_flags & wxSOCKET_WAITALL) + m_error = (m_lcount != nbytes); + else + m_error = (m_lcount == 0); + + // Allow read events again + m_reading = false; + + return *this; +} + +wxSocketBase& wxSocketBase::Write(const void *buffer, wxUint32 nbytes) +{ + // Mask write events + m_writing = true; + + m_lcount = _Write(buffer, nbytes); + + // If in wxSOCKET_WAITALL mode, all bytes should have been written. + if (m_flags & wxSOCKET_WAITALL) + m_error = (m_lcount != nbytes); + else + m_error = (m_lcount == 0); + + // Allow write events again + m_writing = false; + + return *this; +} + +wxUint32 wxSocketBase::_Write(const void *buffer, wxUint32 nbytes) +{ + wxUint32 total = 0; + + // If the socket is invalid or parameters are ill, return immediately + if (!m_socket || !buffer || !nbytes) + return 0; + + // Possible combinations (they are checked in this order) + // wxSOCKET_NOWAIT + // wxSOCKET_WAITALL (with or without wxSOCKET_BLOCK) + // wxSOCKET_BLOCK + // wxSOCKET_NONE + // + int ret; + if (m_flags & wxSOCKET_NOWAIT) + { + m_socket->SetNonBlocking(1); + ret = m_socket->Write((const char *)buffer, nbytes); + m_socket->SetNonBlocking(0); + + if (ret > 0) + total = ret; + } + else + { + bool more = true; + + while (more) + { + if ( !(m_flags & wxSOCKET_BLOCK) && !WaitForWrite() ) + break; + + ret = m_socket->Write((const char *)buffer, nbytes); + + if (ret > 0) + { + total += ret; + nbytes -= ret; + buffer = (const char *)buffer + ret; + } + + // If we got here and wxSOCKET_WAITALL is not set, we can leave + // now. Otherwise, wait until we send all the data or until there + // is an error. + // + more = (ret > 0 && nbytes > 0 && (m_flags & wxSOCKET_WAITALL)); + } + } + + return total; +} + +wxSocketBase& wxSocketBase::WriteMsg(const void *buffer, wxUint32 nbytes) +{ + wxUint32 total; + bool error; + struct + { + unsigned char sig[4]; + unsigned char len[4]; + } msg; + + // Mask write events + m_writing = true; + + error = true; + total = 0; + SetFlags((m_flags & wxSOCKET_BLOCK) | wxSOCKET_WAITALL); + + msg.sig[0] = (unsigned char) 0xad; + msg.sig[1] = (unsigned char) 0xde; + msg.sig[2] = (unsigned char) 0xed; + msg.sig[3] = (unsigned char) 0xfe; + + msg.len[0] = (unsigned char) (nbytes & 0xff); + msg.len[1] = (unsigned char) ((nbytes >> 8) & 0xff); + msg.len[2] = (unsigned char) ((nbytes >> 16) & 0xff); + msg.len[3] = (unsigned char) ((nbytes >> 24) & 0xff); + + if (_Write(&msg, sizeof(msg)) < sizeof(msg)) + goto exit; + + total = _Write(buffer, nbytes); + + if (total < nbytes) + goto exit; + + msg.sig[0] = (unsigned char) 0xed; + msg.sig[1] = (unsigned char) 0xfe; + msg.sig[2] = (unsigned char) 0xad; + msg.sig[3] = (unsigned char) 0xde; + msg.len[0] = msg.len[1] = msg.len[2] = msg.len[3] = (char) 0; + + if ((_Write(&msg, sizeof(msg))) < sizeof(msg)) + goto exit; + + // everything was OK + error = false; + +exit: + m_error = error; + m_lcount = total; + m_writing = false; + + return *this; +} + +wxSocketBase& wxSocketBase::Unread(const void *buffer, wxUint32 nbytes) +{ + if (nbytes != 0) + Pushback(buffer, nbytes); + + m_error = false; + m_lcount = nbytes; + + return *this; +} + +wxSocketBase& wxSocketBase::Discard() +{ + char *buffer = new char[MAX_DISCARD_SIZE]; + wxUint32 ret; + wxUint32 total = 0; + + // Mask read events + m_reading = true; + + SetFlags(wxSOCKET_NOWAIT); + + do + { + ret = _Read(buffer, MAX_DISCARD_SIZE); + total += ret; + } + while (ret == MAX_DISCARD_SIZE); + + delete[] buffer; + m_lcount = total; + m_error = false; + + // Allow read events again + m_reading = false; + + return *this; +} + +// -------------------------------------------------------------------------- +// Wait functions +// -------------------------------------------------------------------------- + +// All Wait functions poll the socket using GSocket_Select() to +// check for the specified combination of conditions, until one +// of these conditions become true, an error occurs, or the +// timeout elapses. The polling loop calls PROCESS_EVENTS(), so +// this won't block the GUI. + +bool wxSocketBase::_Wait(long seconds, + long milliseconds, + wxSocketEventFlags flags) +{ + GSocketEventFlags result; + long timeout; + + // Set this to true to interrupt ongoing waits + m_interrupt = false; + + // Check for valid socket + if (!m_socket) + return false; + + // Check for valid timeout value. + if (seconds != -1) + timeout = seconds * 1000 + milliseconds; + else + timeout = m_timeout * 1000; + + bool has_event_loop = wxTheApp->GetTraits() ? (wxTheApp->GetTraits()->GetSocketGUIFunctionsTable() ? true : false) : false; + + // Wait in an active polling loop. + // + // NOTE: We duplicate some of the code in OnRequest, but this doesn't + // hurt. It has to be here because the (GSocket) event might arrive + // a bit delayed, and it has to be in OnRequest as well because we + // don't know whether the Wait functions are being used. + // + // Do this at least once (important if timeout == 0, when + // we are just polling). Also, if just polling, do not yield. + + wxDateTime current_time = wxDateTime::UNow(); + unsigned int time_limit = (current_time.GetTicks() * 1000) + current_time.GetMillisecond() + timeout; + bool done = false; + bool valid_result = false; + + if (!has_event_loop) + { + // This is used to avoid a busy loop on wxBase - having a select + // timeout of 50 ms per iteration should be enough. + if (timeout > 50) + m_socket->SetTimeout(50); + else + m_socket->SetTimeout(timeout); + } + + while (!done) + { + result = m_socket->Select(flags | GSOCK_LOST_FLAG); + + // Incoming connection (server) or connection established (client) + if (result & GSOCK_CONNECTION_FLAG) + { + m_connected = true; + m_establishing = false; + valid_result = true; + break; + } + + // Data available or output buffer ready + if ((result & GSOCK_INPUT_FLAG) || (result & GSOCK_OUTPUT_FLAG)) + { + valid_result = true; + break; + } + + // Connection lost + if (result & GSOCK_LOST_FLAG) + { + m_connected = false; + m_establishing = false; + valid_result = ((flags & GSOCK_LOST_FLAG) != 0); + break; + } + + // Wait more? + current_time = wxDateTime::UNow(); + int time_left = time_limit - ((current_time.GetTicks() * 1000) + current_time.GetMillisecond()); + if ((!timeout) || (time_left <= 0) || (m_interrupt)) + done = true; + else + { + if (has_event_loop) + { + PROCESS_EVENTS(); + } + else + { + // If there's less than 50 ms left, just call select with that timeout. + if (time_left < 50) + m_socket->SetTimeout(time_left); + } + } + } + + // Set timeout back to original value (we overwrote it for polling) + if (!has_event_loop) + m_socket->SetTimeout(m_timeout*1000); + + return valid_result; +} + +bool wxSocketBase::Wait(long seconds, long milliseconds) +{ + return _Wait(seconds, milliseconds, GSOCK_INPUT_FLAG | + GSOCK_OUTPUT_FLAG | + GSOCK_CONNECTION_FLAG | + GSOCK_LOST_FLAG); +} + +bool wxSocketBase::WaitForRead(long seconds, long milliseconds) +{ + // Check pushback buffer before entering _Wait + if (m_unread) + return true; + + // Note that GSOCK_INPUT_LOST has to be explicitly passed to + // _Wait because of the semantics of WaitForRead: a return + // value of true means that a GSocket_Read call will return + // immediately, not that there is actually data to read. + + return _Wait(seconds, milliseconds, GSOCK_INPUT_FLAG | + GSOCK_LOST_FLAG); +} + + +bool wxSocketBase::WaitForWrite(long seconds, long milliseconds) +{ + return _Wait(seconds, milliseconds, GSOCK_OUTPUT_FLAG); +} + +bool wxSocketBase::WaitForLost(long seconds, long milliseconds) +{ + return _Wait(seconds, milliseconds, GSOCK_LOST_FLAG); +} + +// -------------------------------------------------------------------------- +// Miscellaneous +// -------------------------------------------------------------------------- + +// +// Get local or peer address +// + +bool wxSocketBase::GetPeer(wxSockAddress& addr_man) const +{ + GAddress *peer; + + if (!m_socket) + return false; + + peer = m_socket->GetPeer(); + + // copying a null address would just trigger an assert anyway + + if (!peer) + return false; + + addr_man.SetAddress(peer); + GAddress_destroy(peer); + + return true; +} + +bool wxSocketBase::GetLocal(wxSockAddress& addr_man) const +{ + GAddress *local; + + if (!m_socket) + return false; + + local = m_socket->GetLocal(); + addr_man.SetAddress(local); + GAddress_destroy(local); + + return true; +} + +// +// Save and restore socket state +// + +void wxSocketBase::SaveState() +{ + wxSocketState *state; + + state = new wxSocketState(); + + state->m_flags = m_flags; + state->m_notify = m_notify; + state->m_eventmask = m_eventmask; + state->m_clientData = m_clientData; + + m_states.Append(state); +} + +void wxSocketBase::RestoreState() +{ + wxList::compatibility_iterator node; + wxSocketState *state; + + node = m_states.GetLast(); + if (!node) + return; + + state = (wxSocketState *)node->GetData(); + + m_flags = state->m_flags; + m_notify = state->m_notify; + m_eventmask = state->m_eventmask; + m_clientData = state->m_clientData; + + m_states.Erase(node); + delete state; +} + +// +// Timeout and flags +// + +void wxSocketBase::SetTimeout(long seconds) +{ + m_timeout = seconds; + + if (m_socket) + m_socket->SetTimeout(m_timeout * 1000); +} + +void wxSocketBase::SetFlags(wxSocketFlags flags) +{ + m_flags = flags; +} + + +// -------------------------------------------------------------------------- +// Event handling +// -------------------------------------------------------------------------- + +// A note on how events are processed, which is probably the most +// difficult thing to get working right while keeping the same API +// and functionality for all platforms. +// +// When GSocket detects an event, it calls wx_socket_callback, which in +// turn just calls wxSocketBase::OnRequest in the corresponding wxSocket +// object. OnRequest does some housekeeping, and if the event is to be +// propagated to the user, it creates a new wxSocketEvent object and +// posts it. The event is not processed immediately, but delayed with +// AddPendingEvent instead. This is necessary in order to decouple the +// event processing from wx_socket_callback; otherwise, subsequent IO +// calls made from the user event handler would fail, as gtk callbacks +// are not reentrant. +// +// Note that, unlike events, user callbacks (now deprecated) are _not_ +// decoupled from wx_socket_callback and thus they suffer from a variety +// of problems. Avoid them where possible and use events instead. + +extern "C" +void LINKAGEMODE wx_socket_callback(GSocket * WXUNUSED(socket), + GSocketEvent notification, + char *cdata) +{ + wxSocketBase *sckobj = (wxSocketBase *)cdata; + + sckobj->OnRequest((wxSocketNotify) notification); +} + +void wxSocketBase::OnRequest(wxSocketNotify notification) +{ + // NOTE: We duplicate some of the code in _Wait, but this doesn't + // hurt. It has to be here because the (GSocket) event might arrive + // a bit delayed, and it has to be in _Wait as well because we don't + // know whether the Wait functions are being used. + + switch(notification) + { + case wxSOCKET_CONNECTION: + m_establishing = false; + m_connected = true; + break; + + // If we are in the middle of a R/W operation, do not + // propagate events to users. Also, filter 'late' events + // which are no longer valid. + + case wxSOCKET_INPUT: + if (m_reading || !m_socket->Select(GSOCK_INPUT_FLAG)) + return; + break; + + case wxSOCKET_OUTPUT: + if (m_writing || !m_socket->Select(GSOCK_OUTPUT_FLAG)) + return; + break; + + case wxSOCKET_LOST: + m_connected = false; + m_establishing = false; + break; + + default: + break; + } + + // Schedule the event + + wxSocketEventFlags flag = 0; + wxUnusedVar(flag); + switch (notification) + { + case GSOCK_INPUT: flag = GSOCK_INPUT_FLAG; break; + case GSOCK_OUTPUT: flag = GSOCK_OUTPUT_FLAG; break; + case GSOCK_CONNECTION: flag = GSOCK_CONNECTION_FLAG; break; + case GSOCK_LOST: flag = GSOCK_LOST_FLAG; break; + default: + wxLogWarning(_("wxSocket: unknown event!.")); + return; + } + + if (((m_eventmask & flag) == flag) && m_notify) + { + if (m_handler) + { + wxSocketEvent event(m_id); + event.m_event = notification; + event.m_clientData = m_clientData; + event.SetEventObject(this); + + m_handler->AddPendingEvent(event); + } + } +} + +void wxSocketBase::Notify(bool notify) +{ + m_notify = notify; +} + +void wxSocketBase::SetNotify(wxSocketEventFlags flags) +{ + m_eventmask = flags; +} + +void wxSocketBase::SetEventHandler(wxEvtHandler& handler, int id) +{ + m_handler = &handler; + m_id = id; +} + +// -------------------------------------------------------------------------- +// Pushback buffer +// -------------------------------------------------------------------------- + +void wxSocketBase::Pushback(const void *buffer, wxUint32 size) +{ + if (!size) return; + + if (m_unread == NULL) + m_unread = malloc(size); + else + { + void *tmp; + + tmp = malloc(m_unrd_size + size); + memcpy((char *)tmp + size, m_unread, m_unrd_size); + free(m_unread); + + m_unread = tmp; + } + + m_unrd_size += size; + + memcpy(m_unread, buffer, size); +} + +wxUint32 wxSocketBase::GetPushback(void *buffer, wxUint32 size, bool peek) +{ + if (!m_unrd_size) + return 0; + + if (size > (m_unrd_size-m_unrd_cur)) + size = m_unrd_size-m_unrd_cur; + + memcpy(buffer, (char *)m_unread + m_unrd_cur, size); + + if (!peek) + { + m_unrd_cur += size; + if (m_unrd_size == m_unrd_cur) + { + free(m_unread); + m_unread = NULL; + m_unrd_size = 0; + m_unrd_cur = 0; + } + } + + return size; +} + + +// ========================================================================== +// wxSocketServer +// ========================================================================== + +// -------------------------------------------------------------------------- +// Ctor +// -------------------------------------------------------------------------- + +wxSocketServer::wxSocketServer(const wxSockAddress& addr_man, + wxSocketFlags flags) + : wxSocketBase(flags, wxSOCKET_SERVER) +{ + wxLogTrace( wxTRACE_Socket, _T("Opening wxSocketServer") ); + + m_socket = GSocket_new(); + + if (!m_socket) + { + wxLogTrace( wxTRACE_Socket, _T("*** GSocket_new failed") ); + return; + } + + // Setup the socket as server + + m_socket->SetLocal(addr_man.GetAddress()); + + if (GetFlags() & wxSOCKET_REUSEADDR) { + m_socket->SetReusable(); + } + + if (m_socket->SetServer() != GSOCK_NOERROR) + { + delete m_socket; + m_socket = NULL; + + wxLogTrace( wxTRACE_Socket, _T("*** GSocket_SetServer failed") ); + return; + } + + m_socket->SetTimeout(m_timeout * 1000); + m_socket->SetCallback(GSOCK_INPUT_FLAG | GSOCK_OUTPUT_FLAG | + GSOCK_LOST_FLAG | GSOCK_CONNECTION_FLAG, + wx_socket_callback, (char *)this); +} + +// -------------------------------------------------------------------------- +// Accept +// -------------------------------------------------------------------------- + +bool wxSocketServer::AcceptWith(wxSocketBase& sock, bool wait) +{ + GSocket *child_socket; + + if (!m_socket) + return false; + + // If wait == false, then the call should be nonblocking. + // When we are finished, we put the socket to blocking mode + // again. + + if (!wait) + m_socket->SetNonBlocking(1); + + child_socket = m_socket->WaitConnection(); + + if (!wait) + m_socket->SetNonBlocking(0); + + if (!child_socket) + return false; + + sock.m_type = wxSOCKET_BASE; + sock.m_socket = child_socket; + sock.m_connected = true; + + sock.m_socket->SetTimeout(sock.m_timeout * 1000); + sock.m_socket->SetCallback(GSOCK_INPUT_FLAG | GSOCK_OUTPUT_FLAG | + GSOCK_LOST_FLAG | GSOCK_CONNECTION_FLAG, + wx_socket_callback, (char *)&sock); + + return true; +} + +wxSocketBase *wxSocketServer::Accept(bool wait) +{ + wxSocketBase* sock = new wxSocketBase(); + + sock->SetFlags(m_flags); + + if (!AcceptWith(*sock, wait)) + { + sock->Destroy(); + sock = NULL; + } + + return sock; +} + +bool wxSocketServer::WaitForAccept(long seconds, long milliseconds) +{ + return _Wait(seconds, milliseconds, GSOCK_CONNECTION_FLAG); +} + +bool wxSocketBase::GetOption(int level, int optname, void *optval, int *optlen) +{ + wxASSERT_MSG( m_socket, _T("Socket not initialised") ); + + if (m_socket->GetSockOpt(level, optname, optval, optlen) + != GSOCK_NOERROR) + { + return false; + } + return true; +} + +bool wxSocketBase::SetOption(int level, int optname, const void *optval, + int optlen) +{ + wxASSERT_MSG( m_socket, _T("Socket not initialised") ); + + if (m_socket->SetSockOpt(level, optname, optval, optlen) + != GSOCK_NOERROR) + { + return false; + } + return true; +} + +bool wxSocketBase::SetLocal(wxIPV4address& local) +{ + GAddress* la = local.GetAddress(); + + // If the address is valid, save it for use when we call Connect + if (la && la->m_addr) + { + m_localAddress = local; + + return true; + } + + return false; +} + +// ========================================================================== +// wxSocketClient +// ========================================================================== + +// -------------------------------------------------------------------------- +// Ctor and dtor +// -------------------------------------------------------------------------- + +wxSocketClient::wxSocketClient(wxSocketFlags flags) + : wxSocketBase(flags, wxSOCKET_CLIENT) +{ +} + +wxSocketClient::~wxSocketClient() +{ +} + +// -------------------------------------------------------------------------- +// Connect +// -------------------------------------------------------------------------- + +bool wxSocketClient::DoConnect(wxSockAddress& addr_man, wxSockAddress* local, bool wait) +{ + GSocketError err; + + if (m_socket) + { + // Shutdown and destroy the socket + Close(); + delete m_socket; + } + + m_socket = GSocket_new(); + m_connected = false; + m_establishing = false; + + if (!m_socket) + return false; + + m_socket->SetTimeout(m_timeout * 1000); + m_socket->SetCallback(GSOCK_INPUT_FLAG | GSOCK_OUTPUT_FLAG | + GSOCK_LOST_FLAG | GSOCK_CONNECTION_FLAG, + wx_socket_callback, (char *)this); + + // If wait == false, then the call should be nonblocking. + // When we are finished, we put the socket to blocking mode + // again. + + if (!wait) + m_socket->SetNonBlocking(1); + + // Reuse makes sense for clients too, if we are trying to rebind to the same port + if (GetFlags() & wxSOCKET_REUSEADDR) + { + m_socket->SetReusable(); + } + + // If no local address was passed and one has been set, use the one that was Set + if (!local && m_localAddress.GetAddress()) + { + local = &m_localAddress; + } + + // Bind to the local IP address and port, when provided + if (local) + { + GAddress* la = local->GetAddress(); + + if (la && la->m_addr) + m_socket->SetLocal(la); + } + + m_socket->SetPeer(addr_man.GetAddress()); + err = m_socket->Connect(GSOCK_STREAMED); + + if (!wait) + m_socket->SetNonBlocking(0); + + if (err != GSOCK_NOERROR) + { + if (err == GSOCK_WOULDBLOCK) + m_establishing = true; + + return false; + } + + m_connected = true; + return true; +} + +bool wxSocketClient::Connect(wxSockAddress& addr_man, bool wait) +{ + return (DoConnect(addr_man, NULL, wait)); +} + +bool wxSocketClient::Connect(wxSockAddress& addr_man, wxSockAddress& local, bool wait) +{ + return (DoConnect(addr_man, &local, wait)); +} + +bool wxSocketClient::WaitOnConnect(long seconds, long milliseconds) +{ + if (m_connected) // Already connected + return true; + + if (!m_establishing || !m_socket) // No connection in progress + return false; + + return _Wait(seconds, milliseconds, GSOCK_CONNECTION_FLAG | + GSOCK_LOST_FLAG); +} + +// ========================================================================== +// wxDatagramSocket +// ========================================================================== + +/* NOTE: experimental stuff - might change */ + +wxDatagramSocket::wxDatagramSocket( const wxSockAddress& addr, + wxSocketFlags flags ) + : wxSocketBase( flags, wxSOCKET_DATAGRAM ) +{ + // Create the socket + m_socket = GSocket_new(); + + if (!m_socket) + { + wxFAIL_MSG( _T("datagram socket not new'd") ); + return; + } + // Setup the socket as non connection oriented + m_socket->SetLocal(addr.GetAddress()); + if (flags & wxSOCKET_REUSEADDR) + { + m_socket->SetReusable(); + } + if ( m_socket->SetNonOriented() != GSOCK_NOERROR ) + { + delete m_socket; + m_socket = NULL; + return; + } + + // Initialize all stuff + m_connected = false; + m_establishing = false; + m_socket->SetTimeout( m_timeout ); + m_socket->SetCallback( GSOCK_INPUT_FLAG | GSOCK_OUTPUT_FLAG | + GSOCK_LOST_FLAG | GSOCK_CONNECTION_FLAG, + wx_socket_callback, (char*)this ); +} + +wxDatagramSocket& wxDatagramSocket::RecvFrom( wxSockAddress& addr, + void* buf, + wxUint32 nBytes ) +{ + Read(buf, nBytes); + GetPeer(addr); + return (*this); +} + +wxDatagramSocket& wxDatagramSocket::SendTo( const wxSockAddress& addr, + const void* buf, + wxUint32 nBytes ) +{ + wxASSERT_MSG( m_socket, _T("Socket not initialised") ); + + m_socket->SetPeer(addr.GetAddress()); + Write(buf, nBytes); + return (*this); +} + +// ========================================================================== +// wxSocketModule +// ========================================================================== + +class wxSocketModule : public wxModule +{ +public: + virtual bool OnInit() + { + // wxSocketBase will call GSocket_Init() itself when/if needed + return true; + } + + virtual void OnExit() + { + if ( wxSocketBase::IsInitialized() ) + wxSocketBase::Shutdown(); + } + +private: + DECLARE_DYNAMIC_CLASS(wxSocketModule) +}; + +IMPLEMENT_DYNAMIC_CLASS(wxSocketModule, wxModule) + +#endif + // wxUSE_SOCKETS diff --git a/Externals/wxWidgets/src/common/socketevtdispatch.cpp b/Externals/wxWidgets/src/common/socketevtdispatch.cpp index 221f92e482..546b4c5205 100644 --- a/Externals/wxWidgets/src/common/socketevtdispatch.cpp +++ b/Externals/wxWidgets/src/common/socketevtdispatch.cpp @@ -1,339 +1,339 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: src/common/socketevtdispatch.cpp -// Purpose: implements wxSocketEventDispatcher for platforms with no -// socket events notification -// Author: Angel Vidal -// Modified by: -// Created: 08.24.06 -// RCS-ID: $Id: socketevtdispatch.cpp 43976 2006-12-14 14:13:57Z VS $ -// Copyright: (c) 2006 Angel vidal -// License: wxWindows licence -/////////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// for compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#if wxUSE_SOCKETS - -#include "wx/private/socketevtdispatch.h" -#include "wx/module.h" -#include "wx/unix/private.h" -#include "wx/gsocket.h" -#include "wx/unix/gsockunx.h" - -#ifndef WX_PRECOMP - #include "wx/hash.h" -#endif - -#include -#include - -#ifdef HAVE_SYS_SELECT_H -# include -#endif - -// ============================================================================ -// implementation -// ============================================================================ - -// ---------------------------------------------------------------------------- -// wxSocketEventDispatcherEntry -// ---------------------------------------------------------------------------- - -class wxSocketEventDispatcherEntry: public wxObject -{ - public: - wxSocketEventDispatcherEntry() - { - m_fdInput = -1; m_fdOutput = -1; - m_socket = NULL; - } - - int m_fdInput; - int m_fdOutput; - GSocket* m_socket; -}; - -// ---------------------------------------------------------------------------- -// wxSocketEventDispatcher -// ---------------------------------------------------------------------------- - -wxSocketEventDispatcher* wxSocketEventDispatcher::ms_instance = NULL; - -/* static */ -wxSocketEventDispatcher& wxSocketEventDispatcher::Get() -{ - if ( !ms_instance ) - ms_instance = new wxSocketEventDispatcher; - return *ms_instance; -} - -wxSocketEventDispatcherEntry* wxSocketEventDispatcher::FindEntry(int fd) -{ - wxSocketEventDispatcherEntry* entry = - (wxSocketEventDispatcherEntry*) wxHashTable::Get(fd); - return entry; -} - -void -wxSocketEventDispatcher::RegisterCallback(int fd, - wxSocketEventDispatcherType socketType, - GSocket* socket) -{ - wxSocketEventDispatcherEntry* entry = FindEntry(fd); - if (!entry) - { - entry = new wxSocketEventDispatcherEntry(); - Put(fd, entry); - } - - if (socketType == wxSocketEventDispatcherInput) - entry->m_fdInput = fd; - else - entry->m_fdOutput = fd; - - entry->m_socket = socket; -} - -void -wxSocketEventDispatcher::UnregisterCallback(int fd, - wxSocketEventDispatcherType socketType) -{ - wxSocketEventDispatcherEntry* entry = FindEntry(fd); - if (entry) - { - if (socketType == wxSocketEventDispatcherInput) - entry->m_fdInput = -1; - else - entry->m_fdOutput = -1; - - if (entry->m_fdInput == -1 && entry->m_fdOutput == -1) - { - entry->m_socket = NULL; - Delete(fd); - delete entry; - } - } -} - -int wxSocketEventDispatcher::FillSets(fd_set* readset, fd_set* writeset) -{ - int max_fd = 0; - - wxFD_ZERO(readset); - wxFD_ZERO(writeset); - - BeginFind(); - wxHashTable::compatibility_iterator node = Next(); - while (node) - { - wxSocketEventDispatcherEntry* entry = - (wxSocketEventDispatcherEntry*) node->GetData(); - - if (entry->m_fdInput != -1) - { - wxFD_SET(entry->m_fdInput, readset); - if (entry->m_fdInput > max_fd) - max_fd = entry->m_fdInput; - } - - if (entry->m_fdOutput != -1) - { - wxFD_SET(entry->m_fdOutput, writeset); - if (entry->m_fdOutput > max_fd) - max_fd = entry->m_fdOutput; - } - - node = Next(); - } - - return max_fd; -} - -void wxSocketEventDispatcher::AddEvents(fd_set* readset, fd_set* writeset) -{ - BeginFind(); - wxHashTable::compatibility_iterator node = Next(); - while (node) - { - // We have to store the next node here, because the event processing can - // destroy the object before we call Next() - - wxHashTable::compatibility_iterator next_node = Next(); - - wxSocketEventDispatcherEntry* entry = - (wxSocketEventDispatcherEntry*) node->GetData(); - - wxCHECK_RET(entry->m_socket, wxT("Critical: Processing a NULL socket in wxSocketEventDispatcher")); - - if (entry->m_fdInput != -1 && wxFD_ISSET(entry->m_fdInput, readset)) - entry->m_socket->Detected_Read(); - - if (entry->m_fdOutput != -1 && wxFD_ISSET(entry->m_fdOutput, writeset)) - entry->m_socket->Detected_Write();; - - node = next_node; - } -} - -void wxSocketEventDispatcher::RunLoop(int timeout) -{ - struct timeval tv; - tv.tv_sec = 0; - tv.tv_usec = timeout; - fd_set readset; - fd_set writeset; - - int max_fd = FillSets( &readset, &writeset); - if (select( max_fd+1, &readset, &writeset, NULL, &tv ) == 0) - { - // No socket input/output. Don't add events. - return; - } - else - { - AddEvents(&readset, &writeset); - } -} - -// ---------------------------------------------------------------------------- -// wxSocketEventDispatcherModule -// ---------------------------------------------------------------------------- - -class wxSocketEventDispatcherModule: public wxModule -{ -public: - bool OnInit() { return true; } - void OnExit() { wxDELETE(wxSocketEventDispatcher::ms_instance); } - -private: - DECLARE_DYNAMIC_CLASS(wxSocketEventDispatcherModule) -}; - -IMPLEMENT_DYNAMIC_CLASS(wxSocketEventDispatcherModule, wxModule) - - -// ---------------------------------------------------------------------------- -// GSocket interface -// ---------------------------------------------------------------------------- - -bool GSocketGUIFunctionsTableConcrete::CanUseEventLoop() -{ - return true; -} - -bool GSocketGUIFunctionsTableConcrete::OnInit(void) -{ - return 1; -} - -void GSocketGUIFunctionsTableConcrete::OnExit(void) -{ -} - -bool GSocketGUIFunctionsTableConcrete::Init_Socket(GSocket *socket) -{ - int *m_id; - - socket->m_gui_dependent = (char *)malloc(sizeof(int)*2); - m_id = (int *)(socket->m_gui_dependent); - - m_id[0] = -1; - m_id[1] = -1; - - return true; -} - -void GSocketGUIFunctionsTableConcrete::Destroy_Socket(GSocket *socket) -{ - free(socket->m_gui_dependent); -} - -void GSocketGUIFunctionsTableConcrete::Install_Callback(GSocket *socket, - GSocketEvent event) -{ - int *m_id = (int *)(socket->m_gui_dependent); - int c; - - if (socket->m_fd == -1) - return; - - switch (event) - { - case GSOCK_LOST: /* fall-through */ - case GSOCK_INPUT: c = 0; break; - case GSOCK_OUTPUT: c = 1; break; - case GSOCK_CONNECTION: c = ((socket->m_server) ? 0 : 1); break; - default: return; - } - -#if 0 - if (m_id[c] != -1) - XtRemoveInput(m_id[c]); -#endif /* 0 */ - - if (c == 0) - { - m_id[0] = socket->m_fd; - - wxSocketEventDispatcher::Get().RegisterCallback( - socket->m_fd, wxSocketEventDispatcherInput, socket); - } - else - { - m_id[1] = socket->m_fd; - - wxSocketEventDispatcher::Get().RegisterCallback( - socket->m_fd, wxSocketEventDispatcherOutput, socket); - } -} - -void GSocketGUIFunctionsTableConcrete::Uninstall_Callback(GSocket *socket, - GSocketEvent event) -{ - int *m_id = (int *)(socket->m_gui_dependent); - int c; - - switch (event) - { - case GSOCK_LOST: /* fall-through */ - case GSOCK_INPUT: c = 0; break; - case GSOCK_OUTPUT: c = 1; break; - case GSOCK_CONNECTION: c = ((socket->m_server) ? 0 : 1); break; - default: return; - } - - if (m_id[c] != -1) - { - if (c == 0) - wxSocketEventDispatcher::Get().UnregisterCallback( - m_id[c], wxSocketEventDispatcherInput); - else - wxSocketEventDispatcher::Get().UnregisterCallback( - m_id[c], wxSocketEventDispatcherOutput); - } - - m_id[c] = -1; -} - -void GSocketGUIFunctionsTableConcrete::Enable_Events(GSocket *socket) -{ - Install_Callback(socket, GSOCK_INPUT); - Install_Callback(socket, GSOCK_OUTPUT); -} - -void GSocketGUIFunctionsTableConcrete::Disable_Events(GSocket *socket) -{ - Uninstall_Callback(socket, GSOCK_INPUT); - Uninstall_Callback(socket, GSOCK_OUTPUT); -} - -#endif // wxUSE_SOCKETS +/////////////////////////////////////////////////////////////////////////////// +// Name: src/common/socketevtdispatch.cpp +// Purpose: implements wxSocketEventDispatcher for platforms with no +// socket events notification +// Author: Angel Vidal +// Modified by: +// Created: 08.24.06 +// RCS-ID: $Id: socketevtdispatch.cpp 43976 2006-12-14 14:13:57Z VS $ +// Copyright: (c) 2006 Angel vidal +// License: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// for compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#if wxUSE_SOCKETS + +#include "wx/private/socketevtdispatch.h" +#include "wx/module.h" +#include "wx/unix/private.h" +#include "wx/gsocket.h" +#include "wx/unix/gsockunx.h" + +#ifndef WX_PRECOMP + #include "wx/hash.h" +#endif + +#include +#include + +#ifdef HAVE_SYS_SELECT_H +# include +#endif + +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// wxSocketEventDispatcherEntry +// ---------------------------------------------------------------------------- + +class wxSocketEventDispatcherEntry: public wxObject +{ + public: + wxSocketEventDispatcherEntry() + { + m_fdInput = -1; m_fdOutput = -1; + m_socket = NULL; + } + + int m_fdInput; + int m_fdOutput; + GSocket* m_socket; +}; + +// ---------------------------------------------------------------------------- +// wxSocketEventDispatcher +// ---------------------------------------------------------------------------- + +wxSocketEventDispatcher* wxSocketEventDispatcher::ms_instance = NULL; + +/* static */ +wxSocketEventDispatcher& wxSocketEventDispatcher::Get() +{ + if ( !ms_instance ) + ms_instance = new wxSocketEventDispatcher; + return *ms_instance; +} + +wxSocketEventDispatcherEntry* wxSocketEventDispatcher::FindEntry(int fd) +{ + wxSocketEventDispatcherEntry* entry = + (wxSocketEventDispatcherEntry*) wxHashTable::Get(fd); + return entry; +} + +void +wxSocketEventDispatcher::RegisterCallback(int fd, + wxSocketEventDispatcherType socketType, + GSocket* socket) +{ + wxSocketEventDispatcherEntry* entry = FindEntry(fd); + if (!entry) + { + entry = new wxSocketEventDispatcherEntry(); + Put(fd, entry); + } + + if (socketType == wxSocketEventDispatcherInput) + entry->m_fdInput = fd; + else + entry->m_fdOutput = fd; + + entry->m_socket = socket; +} + +void +wxSocketEventDispatcher::UnregisterCallback(int fd, + wxSocketEventDispatcherType socketType) +{ + wxSocketEventDispatcherEntry* entry = FindEntry(fd); + if (entry) + { + if (socketType == wxSocketEventDispatcherInput) + entry->m_fdInput = -1; + else + entry->m_fdOutput = -1; + + if (entry->m_fdInput == -1 && entry->m_fdOutput == -1) + { + entry->m_socket = NULL; + Delete(fd); + delete entry; + } + } +} + +int wxSocketEventDispatcher::FillSets(fd_set* readset, fd_set* writeset) +{ + int max_fd = 0; + + wxFD_ZERO(readset); + wxFD_ZERO(writeset); + + BeginFind(); + wxHashTable::compatibility_iterator node = Next(); + while (node) + { + wxSocketEventDispatcherEntry* entry = + (wxSocketEventDispatcherEntry*) node->GetData(); + + if (entry->m_fdInput != -1) + { + wxFD_SET(entry->m_fdInput, readset); + if (entry->m_fdInput > max_fd) + max_fd = entry->m_fdInput; + } + + if (entry->m_fdOutput != -1) + { + wxFD_SET(entry->m_fdOutput, writeset); + if (entry->m_fdOutput > max_fd) + max_fd = entry->m_fdOutput; + } + + node = Next(); + } + + return max_fd; +} + +void wxSocketEventDispatcher::AddEvents(fd_set* readset, fd_set* writeset) +{ + BeginFind(); + wxHashTable::compatibility_iterator node = Next(); + while (node) + { + // We have to store the next node here, because the event processing can + // destroy the object before we call Next() + + wxHashTable::compatibility_iterator next_node = Next(); + + wxSocketEventDispatcherEntry* entry = + (wxSocketEventDispatcherEntry*) node->GetData(); + + wxCHECK_RET(entry->m_socket, wxT("Critical: Processing a NULL socket in wxSocketEventDispatcher")); + + if (entry->m_fdInput != -1 && wxFD_ISSET(entry->m_fdInput, readset)) + entry->m_socket->Detected_Read(); + + if (entry->m_fdOutput != -1 && wxFD_ISSET(entry->m_fdOutput, writeset)) + entry->m_socket->Detected_Write();; + + node = next_node; + } +} + +void wxSocketEventDispatcher::RunLoop(int timeout) +{ + struct timeval tv; + tv.tv_sec = 0; + tv.tv_usec = timeout; + fd_set readset; + fd_set writeset; + + int max_fd = FillSets( &readset, &writeset); + if (select( max_fd+1, &readset, &writeset, NULL, &tv ) == 0) + { + // No socket input/output. Don't add events. + return; + } + else + { + AddEvents(&readset, &writeset); + } +} + +// ---------------------------------------------------------------------------- +// wxSocketEventDispatcherModule +// ---------------------------------------------------------------------------- + +class wxSocketEventDispatcherModule: public wxModule +{ +public: + bool OnInit() { return true; } + void OnExit() { wxDELETE(wxSocketEventDispatcher::ms_instance); } + +private: + DECLARE_DYNAMIC_CLASS(wxSocketEventDispatcherModule) +}; + +IMPLEMENT_DYNAMIC_CLASS(wxSocketEventDispatcherModule, wxModule) + + +// ---------------------------------------------------------------------------- +// GSocket interface +// ---------------------------------------------------------------------------- + +bool GSocketGUIFunctionsTableConcrete::CanUseEventLoop() +{ + return true; +} + +bool GSocketGUIFunctionsTableConcrete::OnInit(void) +{ + return 1; +} + +void GSocketGUIFunctionsTableConcrete::OnExit(void) +{ +} + +bool GSocketGUIFunctionsTableConcrete::Init_Socket(GSocket *socket) +{ + int *m_id; + + socket->m_gui_dependent = (char *)malloc(sizeof(int)*2); + m_id = (int *)(socket->m_gui_dependent); + + m_id[0] = -1; + m_id[1] = -1; + + return true; +} + +void GSocketGUIFunctionsTableConcrete::Destroy_Socket(GSocket *socket) +{ + free(socket->m_gui_dependent); +} + +void GSocketGUIFunctionsTableConcrete::Install_Callback(GSocket *socket, + GSocketEvent event) +{ + int *m_id = (int *)(socket->m_gui_dependent); + int c; + + if (socket->m_fd == -1) + return; + + switch (event) + { + case GSOCK_LOST: /* fall-through */ + case GSOCK_INPUT: c = 0; break; + case GSOCK_OUTPUT: c = 1; break; + case GSOCK_CONNECTION: c = ((socket->m_server) ? 0 : 1); break; + default: return; + } + +#if 0 + if (m_id[c] != -1) + XtRemoveInput(m_id[c]); +#endif /* 0 */ + + if (c == 0) + { + m_id[0] = socket->m_fd; + + wxSocketEventDispatcher::Get().RegisterCallback( + socket->m_fd, wxSocketEventDispatcherInput, socket); + } + else + { + m_id[1] = socket->m_fd; + + wxSocketEventDispatcher::Get().RegisterCallback( + socket->m_fd, wxSocketEventDispatcherOutput, socket); + } +} + +void GSocketGUIFunctionsTableConcrete::Uninstall_Callback(GSocket *socket, + GSocketEvent event) +{ + int *m_id = (int *)(socket->m_gui_dependent); + int c; + + switch (event) + { + case GSOCK_LOST: /* fall-through */ + case GSOCK_INPUT: c = 0; break; + case GSOCK_OUTPUT: c = 1; break; + case GSOCK_CONNECTION: c = ((socket->m_server) ? 0 : 1); break; + default: return; + } + + if (m_id[c] != -1) + { + if (c == 0) + wxSocketEventDispatcher::Get().UnregisterCallback( + m_id[c], wxSocketEventDispatcherInput); + else + wxSocketEventDispatcher::Get().UnregisterCallback( + m_id[c], wxSocketEventDispatcherOutput); + } + + m_id[c] = -1; +} + +void GSocketGUIFunctionsTableConcrete::Enable_Events(GSocket *socket) +{ + Install_Callback(socket, GSOCK_INPUT); + Install_Callback(socket, GSOCK_OUTPUT); +} + +void GSocketGUIFunctionsTableConcrete::Disable_Events(GSocket *socket) +{ + Uninstall_Callback(socket, GSOCK_INPUT); + Uninstall_Callback(socket, GSOCK_OUTPUT); +} + +#endif // wxUSE_SOCKETS diff --git a/Externals/wxWidgets/src/common/srchcmn.cpp b/Externals/wxWidgets/src/common/srchcmn.cpp index 3c05e828c4..093577f5ca 100644 --- a/Externals/wxWidgets/src/common/srchcmn.cpp +++ b/Externals/wxWidgets/src/common/srchcmn.cpp @@ -1,42 +1,42 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/srchcmn.cpp -// Purpose: common (to all ports) bits of wxSearchCtrl -// Author: Robin Dunn -// Modified by: -// Created: 19-Dec-2006 -// RCS-ID: $Id: srchcmn.cpp 43939 2006-12-11 20:32:16Z KO $ -// Copyright: (c) wxWidgets team -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_SEARCHCTRL - -#include "wx/srchctrl.h" - -#ifndef WX_PRECOMP -#endif - -// ---------------------------------------------------------------------------- - -const wxChar wxSearchCtrlNameStr[] = wxT("searchCtrl"); - -DEFINE_EVENT_TYPE(wxEVT_COMMAND_SEARCHCTRL_CANCEL_BTN) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_SEARCHCTRL_SEARCH_BTN) - - -#endif // wxUSE_SEARCHCTRL +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/srchcmn.cpp +// Purpose: common (to all ports) bits of wxSearchCtrl +// Author: Robin Dunn +// Modified by: +// Created: 19-Dec-2006 +// RCS-ID: $Id: srchcmn.cpp 43939 2006-12-11 20:32:16Z KO $ +// Copyright: (c) wxWidgets team +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_SEARCHCTRL + +#include "wx/srchctrl.h" + +#ifndef WX_PRECOMP +#endif + +// ---------------------------------------------------------------------------- + +const wxChar wxSearchCtrlNameStr[] = wxT("searchCtrl"); + +DEFINE_EVENT_TYPE(wxEVT_COMMAND_SEARCHCTRL_CANCEL_BTN) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_SEARCHCTRL_SEARCH_BTN) + + +#endif // wxUSE_SEARCHCTRL diff --git a/Externals/wxWidgets/src/common/sstream.cpp b/Externals/wxWidgets/src/common/sstream.cpp index 80129c50fb..3d792b1741 100644 --- a/Externals/wxWidgets/src/common/sstream.cpp +++ b/Externals/wxWidgets/src/common/sstream.cpp @@ -1,235 +1,235 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: common/sstream.cpp -// Purpose: string-based streams implementation -// Author: Vadim Zeitlin -// Modified by: Ryan Norton (UTF8 UNICODE) -// Created: 2004-09-19 -// RCS-ID: $Id: sstream.cpp 45772 2007-05-03 02:19:16Z VZ $ -// Copyright: (c) 2004 Vadim Zeitlin -// Licence: wxWindows licence -/////////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_STREAMS - -#include "wx/sstream.h" - -#if wxUSE_UNICODE - #include "wx/hashmap.h" -#endif - -// ============================================================================ -// wxStringInputStream implementation -// ============================================================================ - -// ---------------------------------------------------------------------------- -// construction/destruction -// ---------------------------------------------------------------------------- - -// TODO: Do we want to include the null char in the stream? If so then -// just add +1 to m_len in the ctor -wxStringInputStream::wxStringInputStream(const wxString& s) -#if wxUSE_UNICODE - : m_str(s), m_buf(wxMBConvUTF8().cWX2MB(s).release()), m_len(strlen(m_buf)) -#else - : m_str(s), m_buf((char*)s.c_str()), m_len(s.length()) -#endif -{ -#if wxUSE_UNICODE - wxASSERT_MSG(m_buf != NULL, _T("Could not convert string to UTF8!")); -#endif - m_pos = 0; -} - -wxStringInputStream::~wxStringInputStream() -{ -#if wxUSE_UNICODE - // Note: wx[W]CharBuffer uses malloc()/free() - free(m_buf); -#endif -} - -// ---------------------------------------------------------------------------- -// getlength -// ---------------------------------------------------------------------------- - -wxFileOffset wxStringInputStream::GetLength() const -{ - return m_len; -} - -// ---------------------------------------------------------------------------- -// seek/tell -// ---------------------------------------------------------------------------- - -wxFileOffset wxStringInputStream::OnSysSeek(wxFileOffset ofs, wxSeekMode mode) -{ - switch ( mode ) - { - case wxFromStart: - // nothing to do, ofs already ok - break; - - case wxFromEnd: - ofs += m_len; - break; - - case wxFromCurrent: - ofs += m_pos; - break; - - default: - wxFAIL_MSG( _T("invalid seek mode") ); - return wxInvalidOffset; - } - - if ( ofs < 0 || ofs > wx_static_cast(wxFileOffset, m_len) ) - return wxInvalidOffset; - - // FIXME: this can't be right - m_pos = wx_truncate_cast(size_t, ofs); - - return ofs; -} - -wxFileOffset wxStringInputStream::OnSysTell() const -{ - return wx_static_cast(wxFileOffset, m_pos); -} - -// ---------------------------------------------------------------------------- -// actual IO -// ---------------------------------------------------------------------------- - -size_t wxStringInputStream::OnSysRead(void *buffer, size_t size) -{ - const size_t sizeMax = m_len - m_pos; - - if ( size >= sizeMax ) - { - if ( sizeMax == 0 ) - { - m_lasterror = wxSTREAM_EOF; - return 0; - } - - size = sizeMax; - } - - memcpy(buffer, m_buf + m_pos, size); - m_pos += size; - - return size; -} - -// ============================================================================ -// wxStringOutputStream implementation -// ============================================================================ - -// ---------------------------------------------------------------------------- -// seek/tell -// ---------------------------------------------------------------------------- - -wxFileOffset wxStringOutputStream::OnSysTell() const -{ - return wx_static_cast(wxFileOffset, m_pos); -} - -// ---------------------------------------------------------------------------- -// actual IO -// ---------------------------------------------------------------------------- - -#if wxUSE_UNICODE - -// we can't add a member to wxStringOutputStream in 2.8 branch without breaking -// backwards binary compatibility, so we emulate it by using a hash indexed by -// wxStringOutputStream pointers - -// can't use wxCharBuffer as it has incorrect copying semantics and doesn't -// store the length which we need here -WX_DECLARE_VOIDPTR_HASH_MAP(wxMemoryBuffer, wxStringStreamUnconvBuffers); - -static wxStringStreamUnconvBuffers gs_unconverted; - -wxStringOutputStream::~wxStringOutputStream() -{ - // TODO: check that nothing remains (i.e. the unconverted buffer is empty)? - gs_unconverted.erase(this); -} - -#endif // wxUSE_UNICODE - -size_t wxStringOutputStream::OnSysWrite(const void *buffer, size_t size) -{ - const char *p = wx_static_cast(const char *, buffer); - -#if wxUSE_UNICODE - // the part of the string we have here may be incomplete, i.e. it can stop - // in the middle of an UTF-8 character and so converting it would fail; if - // this is the case, accumulate the part which we failed to convert until - // we get the rest (and also take into account the part which we might have - // left unconverted before) - const char *src; - size_t srcLen; - wxMemoryBuffer& unconv = gs_unconverted[this]; - if ( unconv.GetDataLen() ) - { - // append the new data to the data remaining since the last time - unconv.AppendData(p, size); - src = unconv; - srcLen = unconv.GetDataLen(); - } - else // no unconverted data left, avoid extra copy - { - src = p; - srcLen = size; - } - - wxWCharBuffer wbuf(m_conv.cMB2WC(src, srcLen, NULL /* out len */)); - if ( wbuf ) - { - // conversion succeeded, clear the unconverted buffer - unconv = wxMemoryBuffer(0); - - *m_str += wbuf; - } - else // conversion failed - { - // remember unconverted data if there had been none before (otherwise - // we've already got it in the buffer) - if ( src == p ) - unconv.AppendData(src, srcLen); - - // pretend that we wrote the data anyhow, otherwise the caller would - // believe there was an error and this might not be the case, but do - // not update m_pos as m_str hasn't changed - return size; - } -#else // !wxUSE_UNICODE - // append directly, no conversion necessary - m_str->Append(wxString(p, size)); -#endif // wxUSE_UNICODE/!wxUSE_UNICODE - - // update position - m_pos += size; - - // return number of bytes actually written - return size; -} - -#endif // wxUSE_STREAMS - +/////////////////////////////////////////////////////////////////////////////// +// Name: common/sstream.cpp +// Purpose: string-based streams implementation +// Author: Vadim Zeitlin +// Modified by: Ryan Norton (UTF8 UNICODE) +// Created: 2004-09-19 +// RCS-ID: $Id: sstream.cpp 45772 2007-05-03 02:19:16Z VZ $ +// Copyright: (c) 2004 Vadim Zeitlin +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_STREAMS + +#include "wx/sstream.h" + +#if wxUSE_UNICODE + #include "wx/hashmap.h" +#endif + +// ============================================================================ +// wxStringInputStream implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// construction/destruction +// ---------------------------------------------------------------------------- + +// TODO: Do we want to include the null char in the stream? If so then +// just add +1 to m_len in the ctor +wxStringInputStream::wxStringInputStream(const wxString& s) +#if wxUSE_UNICODE + : m_str(s), m_buf(wxMBConvUTF8().cWX2MB(s).release()), m_len(strlen(m_buf)) +#else + : m_str(s), m_buf((char*)s.c_str()), m_len(s.length()) +#endif +{ +#if wxUSE_UNICODE + wxASSERT_MSG(m_buf != NULL, _T("Could not convert string to UTF8!")); +#endif + m_pos = 0; +} + +wxStringInputStream::~wxStringInputStream() +{ +#if wxUSE_UNICODE + // Note: wx[W]CharBuffer uses malloc()/free() + free(m_buf); +#endif +} + +// ---------------------------------------------------------------------------- +// getlength +// ---------------------------------------------------------------------------- + +wxFileOffset wxStringInputStream::GetLength() const +{ + return m_len; +} + +// ---------------------------------------------------------------------------- +// seek/tell +// ---------------------------------------------------------------------------- + +wxFileOffset wxStringInputStream::OnSysSeek(wxFileOffset ofs, wxSeekMode mode) +{ + switch ( mode ) + { + case wxFromStart: + // nothing to do, ofs already ok + break; + + case wxFromEnd: + ofs += m_len; + break; + + case wxFromCurrent: + ofs += m_pos; + break; + + default: + wxFAIL_MSG( _T("invalid seek mode") ); + return wxInvalidOffset; + } + + if ( ofs < 0 || ofs > wx_static_cast(wxFileOffset, m_len) ) + return wxInvalidOffset; + + // FIXME: this can't be right + m_pos = wx_truncate_cast(size_t, ofs); + + return ofs; +} + +wxFileOffset wxStringInputStream::OnSysTell() const +{ + return wx_static_cast(wxFileOffset, m_pos); +} + +// ---------------------------------------------------------------------------- +// actual IO +// ---------------------------------------------------------------------------- + +size_t wxStringInputStream::OnSysRead(void *buffer, size_t size) +{ + const size_t sizeMax = m_len - m_pos; + + if ( size >= sizeMax ) + { + if ( sizeMax == 0 ) + { + m_lasterror = wxSTREAM_EOF; + return 0; + } + + size = sizeMax; + } + + memcpy(buffer, m_buf + m_pos, size); + m_pos += size; + + return size; +} + +// ============================================================================ +// wxStringOutputStream implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// seek/tell +// ---------------------------------------------------------------------------- + +wxFileOffset wxStringOutputStream::OnSysTell() const +{ + return wx_static_cast(wxFileOffset, m_pos); +} + +// ---------------------------------------------------------------------------- +// actual IO +// ---------------------------------------------------------------------------- + +#if wxUSE_UNICODE + +// we can't add a member to wxStringOutputStream in 2.8 branch without breaking +// backwards binary compatibility, so we emulate it by using a hash indexed by +// wxStringOutputStream pointers + +// can't use wxCharBuffer as it has incorrect copying semantics and doesn't +// store the length which we need here +WX_DECLARE_VOIDPTR_HASH_MAP(wxMemoryBuffer, wxStringStreamUnconvBuffers); + +static wxStringStreamUnconvBuffers gs_unconverted; + +wxStringOutputStream::~wxStringOutputStream() +{ + // TODO: check that nothing remains (i.e. the unconverted buffer is empty)? + gs_unconverted.erase(this); +} + +#endif // wxUSE_UNICODE + +size_t wxStringOutputStream::OnSysWrite(const void *buffer, size_t size) +{ + const char *p = wx_static_cast(const char *, buffer); + +#if wxUSE_UNICODE + // the part of the string we have here may be incomplete, i.e. it can stop + // in the middle of an UTF-8 character and so converting it would fail; if + // this is the case, accumulate the part which we failed to convert until + // we get the rest (and also take into account the part which we might have + // left unconverted before) + const char *src; + size_t srcLen; + wxMemoryBuffer& unconv = gs_unconverted[this]; + if ( unconv.GetDataLen() ) + { + // append the new data to the data remaining since the last time + unconv.AppendData(p, size); + src = unconv; + srcLen = unconv.GetDataLen(); + } + else // no unconverted data left, avoid extra copy + { + src = p; + srcLen = size; + } + + wxWCharBuffer wbuf(m_conv.cMB2WC(src, srcLen, NULL /* out len */)); + if ( wbuf ) + { + // conversion succeeded, clear the unconverted buffer + unconv = wxMemoryBuffer(0); + + *m_str += wbuf; + } + else // conversion failed + { + // remember unconverted data if there had been none before (otherwise + // we've already got it in the buffer) + if ( src == p ) + unconv.AppendData(src, srcLen); + + // pretend that we wrote the data anyhow, otherwise the caller would + // believe there was an error and this might not be the case, but do + // not update m_pos as m_str hasn't changed + return size; + } +#else // !wxUSE_UNICODE + // append directly, no conversion necessary + m_str->Append(wxString(p, size)); +#endif // wxUSE_UNICODE/!wxUSE_UNICODE + + // update position + m_pos += size; + + // return number of bytes actually written + return size; +} + +#endif // wxUSE_STREAMS + diff --git a/Externals/wxWidgets/src/common/statbar.cpp b/Externals/wxWidgets/src/common/statbar.cpp index 69a32456ce..82de44f332 100644 --- a/Externals/wxWidgets/src/common/statbar.cpp +++ b/Externals/wxWidgets/src/common/statbar.cpp @@ -1,368 +1,368 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: src/common/statbar.cpp -// Purpose: wxStatusBarBase implementation -// Author: Vadim Zeitlin -// Modified by: -// Created: 14.10.01 -// RCS-ID: $Id: statbar.cpp 42171 2006-10-20 14:54:14Z VS $ -// Copyright: (c) 2001 Vadim Zeitlin -// License: wxWindows licence -/////////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_STATUSBAR - -#include "wx/statusbr.h" - -#ifndef WX_PRECOMP - #include "wx/frame.h" -#endif //WX_PRECOMP - -#include "wx/listimpl.cpp" -WX_DEFINE_LIST(wxListString) - -const wxChar wxStatusBarNameStr[] = wxT("statusBar"); - -// ============================================================================ -// wxStatusBarBase implementation -// ============================================================================ - -IMPLEMENT_DYNAMIC_CLASS(wxStatusBar, wxWindow) - -// ---------------------------------------------------------------------------- -// ctor/dtor -// ---------------------------------------------------------------------------- - -wxStatusBarBase::wxStatusBarBase() -{ - m_nFields = 0; - - InitWidths(); - InitStacks(); - InitStyles(); -} - -wxStatusBarBase::~wxStatusBarBase() -{ - FreeWidths(); - FreeStacks(); - FreeStyles(); - - // notify the frame that it doesn't have a status bar any longer to avoid - // dangling pointers - wxFrame *frame = wxDynamicCast(GetParent(), wxFrame); - if ( frame && frame->GetStatusBar() == this ) - { - frame->SetStatusBar(NULL); - } -} - -// ---------------------------------------------------------------------------- -// widths array handling -// ---------------------------------------------------------------------------- - -void wxStatusBarBase::InitWidths() -{ - m_statusWidths = NULL; -} - -void wxStatusBarBase::FreeWidths() -{ - delete [] m_statusWidths; -} - -// ---------------------------------------------------------------------------- -// styles array handling -// ---------------------------------------------------------------------------- - -void wxStatusBarBase::InitStyles() -{ - m_statusStyles = NULL; -} - -void wxStatusBarBase::FreeStyles() -{ - delete [] m_statusStyles; -} - -// ---------------------------------------------------------------------------- -// field widths -// ---------------------------------------------------------------------------- - -void wxStatusBarBase::SetFieldsCount(int number, const int *widths) -{ - wxCHECK_RET( number > 0, _T("invalid field number in SetFieldsCount") ); - - bool refresh = false; - - if ( number != m_nFields ) - { - // copy stacks if present - if(m_statusTextStacks) - { - wxListString **newStacks = new wxListString*[number]; - size_t i, j, max = wxMin(number, m_nFields); - - // copy old stacks - for(i = 0; i < max; ++i) - newStacks[i] = m_statusTextStacks[i]; - // free old stacks in excess - for(j = i; j < (size_t)m_nFields; ++j) - { - if(m_statusTextStacks[j]) - { - m_statusTextStacks[j]->Clear(); - delete m_statusTextStacks[j]; - } - } - // initialize new stacks to NULL - for(j = i; j < (size_t)number; ++j) - newStacks[j] = 0; - - m_statusTextStacks = newStacks; - } - - // Resize styles array - if (m_statusStyles) - { - int *oldStyles = m_statusStyles; - m_statusStyles = new int[number]; - int i, max = wxMin(number, m_nFields); - - // copy old styles - for (i = 0; i < max; ++i) - m_statusStyles[i] = oldStyles[i]; - - // initialize new styles to wxSB_NORMAL - for (i = max; i < number; ++i) - m_statusStyles[i] = wxSB_NORMAL; - - // free old styles - delete [] oldStyles; - } - - - m_nFields = number; - - ReinitWidths(); - - refresh = true; - } - //else: keep the old m_statusWidths if we had them - - if ( widths ) - { - SetStatusWidths(number, widths); - - // already done from SetStatusWidths() - refresh = false; - } - - if ( refresh ) - Refresh(); -} - -void wxStatusBarBase::SetStatusWidths(int WXUNUSED_UNLESS_DEBUG(n), - const int widths[]) -{ - wxCHECK_RET( widths, _T("NULL pointer in SetStatusWidths") ); - - wxASSERT_MSG( n == m_nFields, _T("field number mismatch") ); - - if ( !m_statusWidths ) - m_statusWidths = new int[m_nFields]; - - for ( int i = 0; i < m_nFields; i++ ) - { - m_statusWidths[i] = widths[i]; - } - - // update the display after the widths changed - Refresh(); -} - -void wxStatusBarBase::SetStatusStyles(int WXUNUSED_UNLESS_DEBUG(n), - const int styles[]) -{ - wxCHECK_RET( styles, _T("NULL pointer in SetStatusStyles") ); - - wxASSERT_MSG( n == m_nFields, _T("field number mismatch") ); - - if ( !m_statusStyles ) - m_statusStyles = new int[m_nFields]; - - for ( int i = 0; i < m_nFields; i++ ) - { - m_statusStyles[i] = styles[i]; - } - - // update the display after the widths changed - Refresh(); -} - -wxArrayInt wxStatusBarBase::CalculateAbsWidths(wxCoord widthTotal) const -{ - wxArrayInt widths; - - if ( m_statusWidths == NULL ) - { - if ( m_nFields ) - { - // Default: all fields have the same width. This is not always - // possible to do exactly (if widthTotal is not divisible by - // m_nFields) - if that happens, we distribute the extra pixels - // among all fields: - int widthToUse = widthTotal; - - for ( int i = m_nFields; i > 0; i-- ) - { - // divide the unassigned width evently between the - // not yet processed fields: - int w = widthToUse / i; - widths.Add(w); - widthToUse -= w; - } - - } - //else: we're empty anyhow - } - else // have explicit status widths - { - // calculate the total width of all the fixed width fields and the - // total number of var field widths counting with multiplicity - int nTotalWidth = 0, - nVarCount = 0, - i; - for ( i = 0; i < m_nFields; i++ ) - { - if ( m_statusWidths[i] >= 0 ) - { - nTotalWidth += m_statusWidths[i]; - } - else - { - nVarCount += -m_statusWidths[i]; - } - } - - // the amount of extra width we have per each var width field - int widthExtra = widthTotal - nTotalWidth; - - // do fill the array - for ( i = 0; i < m_nFields; i++ ) - { - if ( m_statusWidths[i] >= 0 ) - { - widths.Add(m_statusWidths[i]); - } - else - { - int nVarWidth = widthExtra > 0 ? (widthExtra * -m_statusWidths[i]) / nVarCount : 0; - nVarCount += m_statusWidths[i]; - widthExtra -= nVarWidth; - widths.Add(nVarWidth); - } - } - } - - return widths; -} - -// ---------------------------------------------------------------------------- -// text stacks handling -// ---------------------------------------------------------------------------- - -void wxStatusBarBase::InitStacks() -{ - m_statusTextStacks = NULL; -} - -void wxStatusBarBase::FreeStacks() -{ - if ( !m_statusTextStacks ) - return; - - for ( size_t i = 0; i < (size_t)m_nFields; ++i ) - { - if ( m_statusTextStacks[i] ) - { - wxListString& t = *m_statusTextStacks[i]; - WX_CLEAR_LIST(wxListString, t); - delete m_statusTextStacks[i]; - } - } - - delete[] m_statusTextStacks; -} - -// ---------------------------------------------------------------------------- -// text stacks -// ---------------------------------------------------------------------------- - -void wxStatusBarBase::PushStatusText(const wxString& text, int number) -{ - wxListString* st = GetOrCreateStatusStack(number); - // This long-winded way around avoids an internal compiler error - // in VC++ 6 with RTTI enabled - wxString tmp1(GetStatusText(number)); - wxString* tmp = new wxString(tmp1); - st->Insert(tmp); - SetStatusText(text, number); -} - -void wxStatusBarBase::PopStatusText(int number) -{ - wxListString *st = GetStatusStack(number); - wxCHECK_RET( st, _T("Unbalanced PushStatusText/PopStatusText") ); - wxListString::compatibility_iterator top = st->GetFirst(); - - SetStatusText(*top->GetData(), number); - delete top->GetData(); - st->Erase(top); - if(st->GetCount() == 0) - { - delete st; - m_statusTextStacks[number] = 0; - } -} - -wxListString *wxStatusBarBase::GetStatusStack(int i) const -{ - if(!m_statusTextStacks) - return 0; - return m_statusTextStacks[i]; -} - -wxListString *wxStatusBarBase::GetOrCreateStatusStack(int i) -{ - if(!m_statusTextStacks) - { - m_statusTextStacks = new wxListString*[m_nFields]; - - size_t j; - for(j = 0; j < (size_t)m_nFields; ++j) m_statusTextStacks[j] = 0; - } - - if(!m_statusTextStacks[i]) - { - m_statusTextStacks[i] = new wxListString(); - } - - return m_statusTextStacks[i]; -} - -#endif // wxUSE_STATUSBAR +/////////////////////////////////////////////////////////////////////////////// +// Name: src/common/statbar.cpp +// Purpose: wxStatusBarBase implementation +// Author: Vadim Zeitlin +// Modified by: +// Created: 14.10.01 +// RCS-ID: $Id: statbar.cpp 42171 2006-10-20 14:54:14Z VS $ +// Copyright: (c) 2001 Vadim Zeitlin +// License: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_STATUSBAR + +#include "wx/statusbr.h" + +#ifndef WX_PRECOMP + #include "wx/frame.h" +#endif //WX_PRECOMP + +#include "wx/listimpl.cpp" +WX_DEFINE_LIST(wxListString) + +const wxChar wxStatusBarNameStr[] = wxT("statusBar"); + +// ============================================================================ +// wxStatusBarBase implementation +// ============================================================================ + +IMPLEMENT_DYNAMIC_CLASS(wxStatusBar, wxWindow) + +// ---------------------------------------------------------------------------- +// ctor/dtor +// ---------------------------------------------------------------------------- + +wxStatusBarBase::wxStatusBarBase() +{ + m_nFields = 0; + + InitWidths(); + InitStacks(); + InitStyles(); +} + +wxStatusBarBase::~wxStatusBarBase() +{ + FreeWidths(); + FreeStacks(); + FreeStyles(); + + // notify the frame that it doesn't have a status bar any longer to avoid + // dangling pointers + wxFrame *frame = wxDynamicCast(GetParent(), wxFrame); + if ( frame && frame->GetStatusBar() == this ) + { + frame->SetStatusBar(NULL); + } +} + +// ---------------------------------------------------------------------------- +// widths array handling +// ---------------------------------------------------------------------------- + +void wxStatusBarBase::InitWidths() +{ + m_statusWidths = NULL; +} + +void wxStatusBarBase::FreeWidths() +{ + delete [] m_statusWidths; +} + +// ---------------------------------------------------------------------------- +// styles array handling +// ---------------------------------------------------------------------------- + +void wxStatusBarBase::InitStyles() +{ + m_statusStyles = NULL; +} + +void wxStatusBarBase::FreeStyles() +{ + delete [] m_statusStyles; +} + +// ---------------------------------------------------------------------------- +// field widths +// ---------------------------------------------------------------------------- + +void wxStatusBarBase::SetFieldsCount(int number, const int *widths) +{ + wxCHECK_RET( number > 0, _T("invalid field number in SetFieldsCount") ); + + bool refresh = false; + + if ( number != m_nFields ) + { + // copy stacks if present + if(m_statusTextStacks) + { + wxListString **newStacks = new wxListString*[number]; + size_t i, j, max = wxMin(number, m_nFields); + + // copy old stacks + for(i = 0; i < max; ++i) + newStacks[i] = m_statusTextStacks[i]; + // free old stacks in excess + for(j = i; j < (size_t)m_nFields; ++j) + { + if(m_statusTextStacks[j]) + { + m_statusTextStacks[j]->Clear(); + delete m_statusTextStacks[j]; + } + } + // initialize new stacks to NULL + for(j = i; j < (size_t)number; ++j) + newStacks[j] = 0; + + m_statusTextStacks = newStacks; + } + + // Resize styles array + if (m_statusStyles) + { + int *oldStyles = m_statusStyles; + m_statusStyles = new int[number]; + int i, max = wxMin(number, m_nFields); + + // copy old styles + for (i = 0; i < max; ++i) + m_statusStyles[i] = oldStyles[i]; + + // initialize new styles to wxSB_NORMAL + for (i = max; i < number; ++i) + m_statusStyles[i] = wxSB_NORMAL; + + // free old styles + delete [] oldStyles; + } + + + m_nFields = number; + + ReinitWidths(); + + refresh = true; + } + //else: keep the old m_statusWidths if we had them + + if ( widths ) + { + SetStatusWidths(number, widths); + + // already done from SetStatusWidths() + refresh = false; + } + + if ( refresh ) + Refresh(); +} + +void wxStatusBarBase::SetStatusWidths(int WXUNUSED_UNLESS_DEBUG(n), + const int widths[]) +{ + wxCHECK_RET( widths, _T("NULL pointer in SetStatusWidths") ); + + wxASSERT_MSG( n == m_nFields, _T("field number mismatch") ); + + if ( !m_statusWidths ) + m_statusWidths = new int[m_nFields]; + + for ( int i = 0; i < m_nFields; i++ ) + { + m_statusWidths[i] = widths[i]; + } + + // update the display after the widths changed + Refresh(); +} + +void wxStatusBarBase::SetStatusStyles(int WXUNUSED_UNLESS_DEBUG(n), + const int styles[]) +{ + wxCHECK_RET( styles, _T("NULL pointer in SetStatusStyles") ); + + wxASSERT_MSG( n == m_nFields, _T("field number mismatch") ); + + if ( !m_statusStyles ) + m_statusStyles = new int[m_nFields]; + + for ( int i = 0; i < m_nFields; i++ ) + { + m_statusStyles[i] = styles[i]; + } + + // update the display after the widths changed + Refresh(); +} + +wxArrayInt wxStatusBarBase::CalculateAbsWidths(wxCoord widthTotal) const +{ + wxArrayInt widths; + + if ( m_statusWidths == NULL ) + { + if ( m_nFields ) + { + // Default: all fields have the same width. This is not always + // possible to do exactly (if widthTotal is not divisible by + // m_nFields) - if that happens, we distribute the extra pixels + // among all fields: + int widthToUse = widthTotal; + + for ( int i = m_nFields; i > 0; i-- ) + { + // divide the unassigned width evently between the + // not yet processed fields: + int w = widthToUse / i; + widths.Add(w); + widthToUse -= w; + } + + } + //else: we're empty anyhow + } + else // have explicit status widths + { + // calculate the total width of all the fixed width fields and the + // total number of var field widths counting with multiplicity + int nTotalWidth = 0, + nVarCount = 0, + i; + for ( i = 0; i < m_nFields; i++ ) + { + if ( m_statusWidths[i] >= 0 ) + { + nTotalWidth += m_statusWidths[i]; + } + else + { + nVarCount += -m_statusWidths[i]; + } + } + + // the amount of extra width we have per each var width field + int widthExtra = widthTotal - nTotalWidth; + + // do fill the array + for ( i = 0; i < m_nFields; i++ ) + { + if ( m_statusWidths[i] >= 0 ) + { + widths.Add(m_statusWidths[i]); + } + else + { + int nVarWidth = widthExtra > 0 ? (widthExtra * -m_statusWidths[i]) / nVarCount : 0; + nVarCount += m_statusWidths[i]; + widthExtra -= nVarWidth; + widths.Add(nVarWidth); + } + } + } + + return widths; +} + +// ---------------------------------------------------------------------------- +// text stacks handling +// ---------------------------------------------------------------------------- + +void wxStatusBarBase::InitStacks() +{ + m_statusTextStacks = NULL; +} + +void wxStatusBarBase::FreeStacks() +{ + if ( !m_statusTextStacks ) + return; + + for ( size_t i = 0; i < (size_t)m_nFields; ++i ) + { + if ( m_statusTextStacks[i] ) + { + wxListString& t = *m_statusTextStacks[i]; + WX_CLEAR_LIST(wxListString, t); + delete m_statusTextStacks[i]; + } + } + + delete[] m_statusTextStacks; +} + +// ---------------------------------------------------------------------------- +// text stacks +// ---------------------------------------------------------------------------- + +void wxStatusBarBase::PushStatusText(const wxString& text, int number) +{ + wxListString* st = GetOrCreateStatusStack(number); + // This long-winded way around avoids an internal compiler error + // in VC++ 6 with RTTI enabled + wxString tmp1(GetStatusText(number)); + wxString* tmp = new wxString(tmp1); + st->Insert(tmp); + SetStatusText(text, number); +} + +void wxStatusBarBase::PopStatusText(int number) +{ + wxListString *st = GetStatusStack(number); + wxCHECK_RET( st, _T("Unbalanced PushStatusText/PopStatusText") ); + wxListString::compatibility_iterator top = st->GetFirst(); + + SetStatusText(*top->GetData(), number); + delete top->GetData(); + st->Erase(top); + if(st->GetCount() == 0) + { + delete st; + m_statusTextStacks[number] = 0; + } +} + +wxListString *wxStatusBarBase::GetStatusStack(int i) const +{ + if(!m_statusTextStacks) + return 0; + return m_statusTextStacks[i]; +} + +wxListString *wxStatusBarBase::GetOrCreateStatusStack(int i) +{ + if(!m_statusTextStacks) + { + m_statusTextStacks = new wxListString*[m_nFields]; + + size_t j; + for(j = 0; j < (size_t)m_nFields; ++j) m_statusTextStacks[j] = 0; + } + + if(!m_statusTextStacks[i]) + { + m_statusTextStacks[i] = new wxListString(); + } + + return m_statusTextStacks[i]; +} + +#endif // wxUSE_STATUSBAR diff --git a/Externals/wxWidgets/src/common/stdpbase.cpp b/Externals/wxWidgets/src/common/stdpbase.cpp index a8212c90f0..f2d4ff6b02 100644 --- a/Externals/wxWidgets/src/common/stdpbase.cpp +++ b/Externals/wxWidgets/src/common/stdpbase.cpp @@ -1,172 +1,172 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: common/stdpbase.cpp -// Purpose: wxStandardPathsBase methods common to all ports -// Author: Vadim Zeitlin -// Modified by: -// Created: 2004-10-19 -// RCS-ID: $Id: stdpbase.cpp 53093 2008-04-08 13:51:17Z JS $ -// Copyright: (c) 2004 Vadim Zeitlin -// License: wxWindows license -/////////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// for compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_STDPATHS - -#ifndef WX_PRECOMP - #include "wx/app.h" -#endif //WX_PRECOMP -#include "wx/apptrait.h" - -#include "wx/filename.h" -#include "wx/stdpaths.h" - -#if defined(__UNIX__) && !defined(__WXMAC__) -#include "wx/log.h" -#include "wx/textfile.h" -#endif - -// ---------------------------------------------------------------------------- -// module globals -// ---------------------------------------------------------------------------- - -static wxStandardPaths gs_stdPaths; - -// ============================================================================ -// implementation -// ============================================================================ - -/* static */ -wxStandardPathsBase& wxStandardPathsBase::Get() -{ - wxAppTraits * const traits = wxTheApp ? wxTheApp->GetTraits() : NULL; - wxCHECK_MSG( traits, gs_stdPaths, _T("create wxApp before calling this") ); - - return traits->GetStandardPaths(); -} - -wxString wxStandardPathsBase::GetExecutablePath() const -{ - if ( !wxTheApp || !wxTheApp->argv ) - return wxEmptyString; - - wxString argv0 = wxTheApp->argv[0]; - if (wxIsAbsolutePath(argv0)) - return argv0; - - // Search PATH.environment variable... - wxPathList pathlist; - pathlist.AddEnvList(wxT("PATH")); - wxString path = pathlist.FindAbsoluteValidPath(argv0); - if ( path.empty() ) - return argv0; // better than nothing - - wxFileName filename(path); - filename.Normalize(); - return filename.GetFullPath(); -} - -wxStandardPathsBase& wxAppTraitsBase::GetStandardPaths() -{ - return gs_stdPaths; -} - -wxStandardPathsBase::~wxStandardPathsBase() -{ - // nothing to do here -} - -wxString wxStandardPathsBase::GetLocalDataDir() const -{ - return GetDataDir(); -} - -wxString wxStandardPathsBase::GetUserLocalDataDir() const -{ - return GetUserDataDir(); -} - -wxString wxStandardPathsBase::GetDocumentsDir() const -{ -#if defined(__UNIX__) && !defined(__WXMAC__) - { - wxLogNull logNull; - wxString homeDir = wxFileName::GetHomeDir(); - wxString configPath; - if (wxGetenv(wxT("XDG_CONFIG_HOME"))) - configPath = wxGetenv(wxT("XDG_CONFIG_HOME")); - else - configPath = homeDir + wxT("/.config"); - wxString dirsFile = configPath + wxT("/user-dirs.dirs"); - if (wxFileExists(dirsFile)) - { - wxTextFile textFile; - if (textFile.Open(dirsFile)) - { - size_t i; - for (i = 0; i < textFile.GetLineCount(); i++) - { - wxString line(textFile[i]); - int pos = line.Find(wxT("XDG_DOCUMENTS_DIR")); - if (pos != wxNOT_FOUND) - { - wxString value = line.AfterFirst(wxT('=')); - value.Replace(wxT("$HOME"), homeDir); - value.Trim(true); - value.Trim(false); - if (!value.IsEmpty() && wxDirExists(value)) - return value; - else - break; - } - } - } - } - } -#endif - - return wxFileName::GetHomeDir(); -} - -// return the temporary directory for the current user -wxString wxStandardPathsBase::GetTempDir() const -{ - return wxFileName::GetTempDir(); -} - -/* static */ -wxString wxStandardPathsBase::AppendAppName(const wxString& dir) -{ - wxString subdir(dir); - - // empty string indicates that an error has occurred, don't touch it then - if ( !subdir.empty() ) - { - const wxString appname = wxTheApp->GetAppName(); - if ( !appname.empty() ) - { - const wxChar ch = *(subdir.end() - 1); - if ( !wxFileName::IsPathSeparator(ch) && ch != _T('.') ) - subdir += wxFileName::GetPathSeparator(); - - subdir += appname; - } - } - - return subdir; -} - -#endif // wxUSE_STDPATHS +/////////////////////////////////////////////////////////////////////////////// +// Name: common/stdpbase.cpp +// Purpose: wxStandardPathsBase methods common to all ports +// Author: Vadim Zeitlin +// Modified by: +// Created: 2004-10-19 +// RCS-ID: $Id: stdpbase.cpp 53093 2008-04-08 13:51:17Z JS $ +// Copyright: (c) 2004 Vadim Zeitlin +// License: wxWindows license +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// for compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_STDPATHS + +#ifndef WX_PRECOMP + #include "wx/app.h" +#endif //WX_PRECOMP +#include "wx/apptrait.h" + +#include "wx/filename.h" +#include "wx/stdpaths.h" + +#if defined(__UNIX__) && !defined(__WXMAC__) +#include "wx/log.h" +#include "wx/textfile.h" +#endif + +// ---------------------------------------------------------------------------- +// module globals +// ---------------------------------------------------------------------------- + +static wxStandardPaths gs_stdPaths; + +// ============================================================================ +// implementation +// ============================================================================ + +/* static */ +wxStandardPathsBase& wxStandardPathsBase::Get() +{ + wxAppTraits * const traits = wxTheApp ? wxTheApp->GetTraits() : NULL; + wxCHECK_MSG( traits, gs_stdPaths, _T("create wxApp before calling this") ); + + return traits->GetStandardPaths(); +} + +wxString wxStandardPathsBase::GetExecutablePath() const +{ + if ( !wxTheApp || !wxTheApp->argv ) + return wxEmptyString; + + wxString argv0 = wxTheApp->argv[0]; + if (wxIsAbsolutePath(argv0)) + return argv0; + + // Search PATH.environment variable... + wxPathList pathlist; + pathlist.AddEnvList(wxT("PATH")); + wxString path = pathlist.FindAbsoluteValidPath(argv0); + if ( path.empty() ) + return argv0; // better than nothing + + wxFileName filename(path); + filename.Normalize(); + return filename.GetFullPath(); +} + +wxStandardPathsBase& wxAppTraitsBase::GetStandardPaths() +{ + return gs_stdPaths; +} + +wxStandardPathsBase::~wxStandardPathsBase() +{ + // nothing to do here +} + +wxString wxStandardPathsBase::GetLocalDataDir() const +{ + return GetDataDir(); +} + +wxString wxStandardPathsBase::GetUserLocalDataDir() const +{ + return GetUserDataDir(); +} + +wxString wxStandardPathsBase::GetDocumentsDir() const +{ +#if defined(__UNIX__) && !defined(__WXMAC__) + { + wxLogNull logNull; + wxString homeDir = wxFileName::GetHomeDir(); + wxString configPath; + if (wxGetenv(wxT("XDG_CONFIG_HOME"))) + configPath = wxGetenv(wxT("XDG_CONFIG_HOME")); + else + configPath = homeDir + wxT("/.config"); + wxString dirsFile = configPath + wxT("/user-dirs.dirs"); + if (wxFileExists(dirsFile)) + { + wxTextFile textFile; + if (textFile.Open(dirsFile)) + { + size_t i; + for (i = 0; i < textFile.GetLineCount(); i++) + { + wxString line(textFile[i]); + int pos = line.Find(wxT("XDG_DOCUMENTS_DIR")); + if (pos != wxNOT_FOUND) + { + wxString value = line.AfterFirst(wxT('=')); + value.Replace(wxT("$HOME"), homeDir); + value.Trim(true); + value.Trim(false); + if (!value.IsEmpty() && wxDirExists(value)) + return value; + else + break; + } + } + } + } + } +#endif + + return wxFileName::GetHomeDir(); +} + +// return the temporary directory for the current user +wxString wxStandardPathsBase::GetTempDir() const +{ + return wxFileName::GetTempDir(); +} + +/* static */ +wxString wxStandardPathsBase::AppendAppName(const wxString& dir) +{ + wxString subdir(dir); + + // empty string indicates that an error has occurred, don't touch it then + if ( !subdir.empty() ) + { + const wxString appname = wxTheApp->GetAppName(); + if ( !appname.empty() ) + { + const wxChar ch = *(subdir.end() - 1); + if ( !wxFileName::IsPathSeparator(ch) && ch != _T('.') ) + subdir += wxFileName::GetPathSeparator(); + + subdir += appname; + } + } + + return subdir; +} + +#endif // wxUSE_STDPATHS diff --git a/Externals/wxWidgets/src/common/stockitem.cpp b/Externals/wxWidgets/src/common/stockitem.cpp index 4708f3903f..b026793bbb 100644 --- a/Externals/wxWidgets/src/common/stockitem.cpp +++ b/Externals/wxWidgets/src/common/stockitem.cpp @@ -1,278 +1,278 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: src/common/stockitem.cpp -// Purpose: Stock buttons, menu and toolbar items labels -// Author: Vaclav Slavik -// Modified by: -// Created: 2004-08-15 -// RCS-ID: $Id: stockitem.cpp 42936 2006-11-02 10:42:42Z JS $ -// Copyright: (c) Vaclav Slavik, 2004 -// Licence: wxWindows licence -/////////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#include "wx/stockitem.h" - -#ifndef WX_PRECOMP - #include "wx/intl.h" - #include "wx/utils.h" // for wxStripMenuCodes() -#endif - -bool wxIsStockID(wxWindowID id) -{ - switch (id) - { - case wxID_ABOUT: - case wxID_ADD: - case wxID_APPLY: - case wxID_BOLD: - case wxID_CANCEL: - case wxID_CLEAR: - case wxID_CLOSE: - case wxID_COPY: - case wxID_CUT: - case wxID_DELETE: - case wxID_EDIT: - case wxID_FIND: - case wxID_FILE: - case wxID_REPLACE: - case wxID_BACKWARD: - case wxID_DOWN: - case wxID_FORWARD: - case wxID_UP: - case wxID_HELP: - case wxID_HOME: - case wxID_INDENT: - case wxID_INDEX: - case wxID_ITALIC: - case wxID_JUSTIFY_CENTER: - case wxID_JUSTIFY_FILL: - case wxID_JUSTIFY_LEFT: - case wxID_JUSTIFY_RIGHT: - case wxID_NEW: - case wxID_NO: - case wxID_OK: - case wxID_OPEN: - case wxID_PASTE: - case wxID_PREFERENCES: - case wxID_PRINT: - case wxID_PREVIEW: - case wxID_PROPERTIES: - case wxID_EXIT: - case wxID_REDO: - case wxID_REFRESH: - case wxID_REMOVE: - case wxID_REVERT_TO_SAVED: - case wxID_SAVE: - case wxID_SAVEAS: - case wxID_SELECTALL: - case wxID_STOP: - case wxID_UNDELETE: - case wxID_UNDERLINE: - case wxID_UNDO: - case wxID_UNINDENT: - case wxID_YES: - case wxID_ZOOM_100: - case wxID_ZOOM_FIT: - case wxID_ZOOM_IN: - case wxID_ZOOM_OUT: - return true; - - default: - return false; - } -} - -wxString wxGetStockLabel(wxWindowID id, long flags) -{ - wxString stockLabel; - - #define STOCKITEM(stockid, label) \ - case stockid: \ - stockLabel = label; \ - break; - - switch (id) - { - STOCKITEM(wxID_ABOUT, _("&About")) - STOCKITEM(wxID_ADD, _("Add")) - STOCKITEM(wxID_APPLY, _("&Apply")) - STOCKITEM(wxID_BOLD, _("&Bold")) - STOCKITEM(wxID_CANCEL, _("&Cancel")) - STOCKITEM(wxID_CLEAR, _("&Clear")) - STOCKITEM(wxID_CLOSE, _("&Close")) - STOCKITEM(wxID_COPY, _("&Copy")) - STOCKITEM(wxID_CUT, _("Cu&t")) - STOCKITEM(wxID_DELETE, _("&Delete")) - STOCKITEM(wxID_EDIT, _("&Edit")) - STOCKITEM(wxID_FIND, _("&Find")) - STOCKITEM(wxID_FILE, _("&File")) - STOCKITEM(wxID_REPLACE, _("Rep&lace")) - STOCKITEM(wxID_BACKWARD, _("&Back")) - STOCKITEM(wxID_DOWN, _("&Down")) - STOCKITEM(wxID_FORWARD, _("&Forward")) - STOCKITEM(wxID_UP, _("&Up")) - STOCKITEM(wxID_HELP, _("&Help")) - STOCKITEM(wxID_HOME, _("&Home")) - STOCKITEM(wxID_INDENT, _("Indent")) - STOCKITEM(wxID_INDEX, _("&Index")) - STOCKITEM(wxID_ITALIC, _("&Italic")) - STOCKITEM(wxID_JUSTIFY_CENTER, _("Centered")) - STOCKITEM(wxID_JUSTIFY_FILL, _("Justified")) - STOCKITEM(wxID_JUSTIFY_LEFT, _("Align Left")) - STOCKITEM(wxID_JUSTIFY_RIGHT, _("Align Right")) - STOCKITEM(wxID_NEW, _("&New")) - STOCKITEM(wxID_NO, _("&No")) - STOCKITEM(wxID_OK, _("&OK")) - STOCKITEM(wxID_OPEN, _("&Open")) - STOCKITEM(wxID_PASTE, _("&Paste")) - STOCKITEM(wxID_PREFERENCES, _("&Preferences")) - STOCKITEM(wxID_PRINT, _("&Print")) - STOCKITEM(wxID_PREVIEW, _("Print previe&w")) - STOCKITEM(wxID_PROPERTIES, _("&Properties")) - STOCKITEM(wxID_EXIT, _("&Quit")) - STOCKITEM(wxID_REDO, _("&Redo")) - STOCKITEM(wxID_REFRESH, _("Refresh")) - STOCKITEM(wxID_REMOVE, _("Remove")) - STOCKITEM(wxID_REVERT_TO_SAVED, _("Revert to Saved")) - STOCKITEM(wxID_SAVE, _("&Save")) - STOCKITEM(wxID_SAVEAS, _("Save &As...")) - STOCKITEM(wxID_SELECTALL, _("Select all")) - STOCKITEM(wxID_STOP, _("&Stop")) - STOCKITEM(wxID_UNDELETE, _("Undelete")) - STOCKITEM(wxID_UNDERLINE, _("&Underline")) - STOCKITEM(wxID_UNDO, _("&Undo")) - STOCKITEM(wxID_UNINDENT, _("&Unindent")) - STOCKITEM(wxID_YES, _("&Yes")) - STOCKITEM(wxID_ZOOM_100, _("&Actual Size")) - STOCKITEM(wxID_ZOOM_FIT, _("Zoom to &Fit")) - STOCKITEM(wxID_ZOOM_IN, _("Zoom &In")) - STOCKITEM(wxID_ZOOM_OUT, _("Zoom &Out")) - - default: - wxFAIL_MSG( _T("invalid stock item ID") ); - break; - }; - - #undef STOCKITEM - - if ( !(flags & wxSTOCK_WITH_MNEMONIC) ) - { - stockLabel = wxStripMenuCodes(stockLabel); - } - -#if wxUSE_ACCEL - if ( !stockLabel.empty() && (flags & wxSTOCK_WITH_ACCELERATOR) ) - { - wxAcceleratorEntry accel = wxGetStockAccelerator(id); - if (accel.IsOk()) - stockLabel << _T('\t') << accel.ToString(); - } -#endif // wxUSE_ACCEL - - return stockLabel; -} - -wxString wxGetStockHelpString(wxWindowID id, wxStockHelpStringClient client) -{ - wxString stockHelp; - - #define STOCKITEM(stockid, ctx, helpstr) \ - case stockid: \ - if (client==ctx) stockHelp = helpstr; \ - break; - - switch (id) - { - // NB: these help string should be not too specific as they could be used - // in completely different programs! - STOCKITEM(wxID_ABOUT, wxSTOCK_MENU, _("Show about dialog")) - STOCKITEM(wxID_COPY, wxSTOCK_MENU, _("Copy selection")) - STOCKITEM(wxID_CUT, wxSTOCK_MENU, _("Cut selection")) - STOCKITEM(wxID_DELETE, wxSTOCK_MENU, _("Delete selection")) - STOCKITEM(wxID_REPLACE, wxSTOCK_MENU, _("Replace selection")) - STOCKITEM(wxID_PASTE, wxSTOCK_MENU, _("Paste selection")) - STOCKITEM(wxID_EXIT, wxSTOCK_MENU, _("Quit this program")) - STOCKITEM(wxID_REDO, wxSTOCK_MENU, _("Redo last action")) - STOCKITEM(wxID_UNDO, wxSTOCK_MENU, _("Undo last action")) - STOCKITEM(wxID_CLOSE, wxSTOCK_MENU, _("Close current document")) - STOCKITEM(wxID_SAVE, wxSTOCK_MENU, _("Save current document")) - STOCKITEM(wxID_SAVEAS, wxSTOCK_MENU, _("Save current document with a different filename")) - - default: - // there's no stock help string for this ID / client - return wxEmptyString; - } - - #undef STOCKITEM - - return stockHelp; -} - -#if wxUSE_ACCEL - -wxAcceleratorEntry wxGetStockAccelerator(wxWindowID id) -{ - wxAcceleratorEntry ret; - - #define STOCKITEM(stockid, flags, keycode) \ - case stockid: \ - ret.Set(flags, keycode, stockid); \ - break; - - switch (id) - { - STOCKITEM(wxID_COPY, wxACCEL_CTRL,'C') - STOCKITEM(wxID_CUT, wxACCEL_CTRL,'X') - STOCKITEM(wxID_FIND, wxACCEL_CTRL,'F') - STOCKITEM(wxID_REPLACE, wxACCEL_CTRL,'R') - STOCKITEM(wxID_HELP, wxACCEL_CTRL,'H') - STOCKITEM(wxID_NEW, wxACCEL_CTRL,'N') - STOCKITEM(wxID_OPEN, wxACCEL_CTRL,'O') - STOCKITEM(wxID_PASTE, wxACCEL_CTRL,'V') - STOCKITEM(wxID_SAVE, wxACCEL_CTRL,'S') - - default: - // set the wxAcceleratorEntry to return into an invalid state: - // there's no stock accelerator for that. - ret.Set(0, 0, id); - break; - }; - - #undef STOCKITEM - - // always use wxAcceleratorEntry::IsOk on returned value ! - return ret; -} - -#endif // wxUSE_ACCEL - -bool wxIsStockLabel(wxWindowID id, const wxString& label) -{ - if (label.empty()) - return true; - - wxString stock = wxGetStockLabel(id); - - if (label == stock) - return true; - - stock.Replace(_T("&"), wxEmptyString); - if (label == stock) - return true; - - return false; -} +/////////////////////////////////////////////////////////////////////////////// +// Name: src/common/stockitem.cpp +// Purpose: Stock buttons, menu and toolbar items labels +// Author: Vaclav Slavik +// Modified by: +// Created: 2004-08-15 +// RCS-ID: $Id: stockitem.cpp 42936 2006-11-02 10:42:42Z JS $ +// Copyright: (c) Vaclav Slavik, 2004 +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#include "wx/stockitem.h" + +#ifndef WX_PRECOMP + #include "wx/intl.h" + #include "wx/utils.h" // for wxStripMenuCodes() +#endif + +bool wxIsStockID(wxWindowID id) +{ + switch (id) + { + case wxID_ABOUT: + case wxID_ADD: + case wxID_APPLY: + case wxID_BOLD: + case wxID_CANCEL: + case wxID_CLEAR: + case wxID_CLOSE: + case wxID_COPY: + case wxID_CUT: + case wxID_DELETE: + case wxID_EDIT: + case wxID_FIND: + case wxID_FILE: + case wxID_REPLACE: + case wxID_BACKWARD: + case wxID_DOWN: + case wxID_FORWARD: + case wxID_UP: + case wxID_HELP: + case wxID_HOME: + case wxID_INDENT: + case wxID_INDEX: + case wxID_ITALIC: + case wxID_JUSTIFY_CENTER: + case wxID_JUSTIFY_FILL: + case wxID_JUSTIFY_LEFT: + case wxID_JUSTIFY_RIGHT: + case wxID_NEW: + case wxID_NO: + case wxID_OK: + case wxID_OPEN: + case wxID_PASTE: + case wxID_PREFERENCES: + case wxID_PRINT: + case wxID_PREVIEW: + case wxID_PROPERTIES: + case wxID_EXIT: + case wxID_REDO: + case wxID_REFRESH: + case wxID_REMOVE: + case wxID_REVERT_TO_SAVED: + case wxID_SAVE: + case wxID_SAVEAS: + case wxID_SELECTALL: + case wxID_STOP: + case wxID_UNDELETE: + case wxID_UNDERLINE: + case wxID_UNDO: + case wxID_UNINDENT: + case wxID_YES: + case wxID_ZOOM_100: + case wxID_ZOOM_FIT: + case wxID_ZOOM_IN: + case wxID_ZOOM_OUT: + return true; + + default: + return false; + } +} + +wxString wxGetStockLabel(wxWindowID id, long flags) +{ + wxString stockLabel; + + #define STOCKITEM(stockid, label) \ + case stockid: \ + stockLabel = label; \ + break; + + switch (id) + { + STOCKITEM(wxID_ABOUT, _("&About")) + STOCKITEM(wxID_ADD, _("Add")) + STOCKITEM(wxID_APPLY, _("&Apply")) + STOCKITEM(wxID_BOLD, _("&Bold")) + STOCKITEM(wxID_CANCEL, _("&Cancel")) + STOCKITEM(wxID_CLEAR, _("&Clear")) + STOCKITEM(wxID_CLOSE, _("&Close")) + STOCKITEM(wxID_COPY, _("&Copy")) + STOCKITEM(wxID_CUT, _("Cu&t")) + STOCKITEM(wxID_DELETE, _("&Delete")) + STOCKITEM(wxID_EDIT, _("&Edit")) + STOCKITEM(wxID_FIND, _("&Find")) + STOCKITEM(wxID_FILE, _("&File")) + STOCKITEM(wxID_REPLACE, _("Rep&lace")) + STOCKITEM(wxID_BACKWARD, _("&Back")) + STOCKITEM(wxID_DOWN, _("&Down")) + STOCKITEM(wxID_FORWARD, _("&Forward")) + STOCKITEM(wxID_UP, _("&Up")) + STOCKITEM(wxID_HELP, _("&Help")) + STOCKITEM(wxID_HOME, _("&Home")) + STOCKITEM(wxID_INDENT, _("Indent")) + STOCKITEM(wxID_INDEX, _("&Index")) + STOCKITEM(wxID_ITALIC, _("&Italic")) + STOCKITEM(wxID_JUSTIFY_CENTER, _("Centered")) + STOCKITEM(wxID_JUSTIFY_FILL, _("Justified")) + STOCKITEM(wxID_JUSTIFY_LEFT, _("Align Left")) + STOCKITEM(wxID_JUSTIFY_RIGHT, _("Align Right")) + STOCKITEM(wxID_NEW, _("&New")) + STOCKITEM(wxID_NO, _("&No")) + STOCKITEM(wxID_OK, _("&OK")) + STOCKITEM(wxID_OPEN, _("&Open")) + STOCKITEM(wxID_PASTE, _("&Paste")) + STOCKITEM(wxID_PREFERENCES, _("&Preferences")) + STOCKITEM(wxID_PRINT, _("&Print")) + STOCKITEM(wxID_PREVIEW, _("Print previe&w")) + STOCKITEM(wxID_PROPERTIES, _("&Properties")) + STOCKITEM(wxID_EXIT, _("&Quit")) + STOCKITEM(wxID_REDO, _("&Redo")) + STOCKITEM(wxID_REFRESH, _("Refresh")) + STOCKITEM(wxID_REMOVE, _("Remove")) + STOCKITEM(wxID_REVERT_TO_SAVED, _("Revert to Saved")) + STOCKITEM(wxID_SAVE, _("&Save")) + STOCKITEM(wxID_SAVEAS, _("Save &As...")) + STOCKITEM(wxID_SELECTALL, _("Select all")) + STOCKITEM(wxID_STOP, _("&Stop")) + STOCKITEM(wxID_UNDELETE, _("Undelete")) + STOCKITEM(wxID_UNDERLINE, _("&Underline")) + STOCKITEM(wxID_UNDO, _("&Undo")) + STOCKITEM(wxID_UNINDENT, _("&Unindent")) + STOCKITEM(wxID_YES, _("&Yes")) + STOCKITEM(wxID_ZOOM_100, _("&Actual Size")) + STOCKITEM(wxID_ZOOM_FIT, _("Zoom to &Fit")) + STOCKITEM(wxID_ZOOM_IN, _("Zoom &In")) + STOCKITEM(wxID_ZOOM_OUT, _("Zoom &Out")) + + default: + wxFAIL_MSG( _T("invalid stock item ID") ); + break; + }; + + #undef STOCKITEM + + if ( !(flags & wxSTOCK_WITH_MNEMONIC) ) + { + stockLabel = wxStripMenuCodes(stockLabel); + } + +#if wxUSE_ACCEL + if ( !stockLabel.empty() && (flags & wxSTOCK_WITH_ACCELERATOR) ) + { + wxAcceleratorEntry accel = wxGetStockAccelerator(id); + if (accel.IsOk()) + stockLabel << _T('\t') << accel.ToString(); + } +#endif // wxUSE_ACCEL + + return stockLabel; +} + +wxString wxGetStockHelpString(wxWindowID id, wxStockHelpStringClient client) +{ + wxString stockHelp; + + #define STOCKITEM(stockid, ctx, helpstr) \ + case stockid: \ + if (client==ctx) stockHelp = helpstr; \ + break; + + switch (id) + { + // NB: these help string should be not too specific as they could be used + // in completely different programs! + STOCKITEM(wxID_ABOUT, wxSTOCK_MENU, _("Show about dialog")) + STOCKITEM(wxID_COPY, wxSTOCK_MENU, _("Copy selection")) + STOCKITEM(wxID_CUT, wxSTOCK_MENU, _("Cut selection")) + STOCKITEM(wxID_DELETE, wxSTOCK_MENU, _("Delete selection")) + STOCKITEM(wxID_REPLACE, wxSTOCK_MENU, _("Replace selection")) + STOCKITEM(wxID_PASTE, wxSTOCK_MENU, _("Paste selection")) + STOCKITEM(wxID_EXIT, wxSTOCK_MENU, _("Quit this program")) + STOCKITEM(wxID_REDO, wxSTOCK_MENU, _("Redo last action")) + STOCKITEM(wxID_UNDO, wxSTOCK_MENU, _("Undo last action")) + STOCKITEM(wxID_CLOSE, wxSTOCK_MENU, _("Close current document")) + STOCKITEM(wxID_SAVE, wxSTOCK_MENU, _("Save current document")) + STOCKITEM(wxID_SAVEAS, wxSTOCK_MENU, _("Save current document with a different filename")) + + default: + // there's no stock help string for this ID / client + return wxEmptyString; + } + + #undef STOCKITEM + + return stockHelp; +} + +#if wxUSE_ACCEL + +wxAcceleratorEntry wxGetStockAccelerator(wxWindowID id) +{ + wxAcceleratorEntry ret; + + #define STOCKITEM(stockid, flags, keycode) \ + case stockid: \ + ret.Set(flags, keycode, stockid); \ + break; + + switch (id) + { + STOCKITEM(wxID_COPY, wxACCEL_CTRL,'C') + STOCKITEM(wxID_CUT, wxACCEL_CTRL,'X') + STOCKITEM(wxID_FIND, wxACCEL_CTRL,'F') + STOCKITEM(wxID_REPLACE, wxACCEL_CTRL,'R') + STOCKITEM(wxID_HELP, wxACCEL_CTRL,'H') + STOCKITEM(wxID_NEW, wxACCEL_CTRL,'N') + STOCKITEM(wxID_OPEN, wxACCEL_CTRL,'O') + STOCKITEM(wxID_PASTE, wxACCEL_CTRL,'V') + STOCKITEM(wxID_SAVE, wxACCEL_CTRL,'S') + + default: + // set the wxAcceleratorEntry to return into an invalid state: + // there's no stock accelerator for that. + ret.Set(0, 0, id); + break; + }; + + #undef STOCKITEM + + // always use wxAcceleratorEntry::IsOk on returned value ! + return ret; +} + +#endif // wxUSE_ACCEL + +bool wxIsStockLabel(wxWindowID id, const wxString& label) +{ + if (label.empty()) + return true; + + wxString stock = wxGetStockLabel(id); + + if (label == stock) + return true; + + stock.Replace(_T("&"), wxEmptyString); + if (label == stock) + return true; + + return false; +} diff --git a/Externals/wxWidgets/src/common/stopwatch.cpp b/Externals/wxWidgets/src/common/stopwatch.cpp index 1c8bbdaed5..eefbae7e91 100644 --- a/Externals/wxWidgets/src/common/stopwatch.cpp +++ b/Externals/wxWidgets/src/common/stopwatch.cpp @@ -1,372 +1,372 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: src/common/stopwatch.cpp -// Purpose: wxStopWatch and other non-GUI stuff from wx/timer.h -// Author: -// Original version by Julian Smart -// Vadim Zeitlin got rid of all ifdefs (11.12.99) -// Sylvain Bougnoux added wxStopWatch class -// Guillermo Rodriguez rewrote from scratch (Dic/99) -// Modified by: -// Created: 20.06.2003 (extracted from common/timercmn.cpp) -// RCS-ID: $Id: stopwatch.cpp 41054 2006-09-07 19:01:45Z ABX $ -// Copyright: (c) 1998-2003 wxWidgets Team -// License: wxWindows license -/////////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// for compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#include "wx/stopwatch.h" - -#ifndef WX_PRECOMP - #ifdef __WXMSW__ - #include "wx/msw/wrapwin.h" - #endif - #include "wx/intl.h" - #include "wx/log.h" -#endif //WX_PRECOMP - -// ---------------------------------------------------------------------------- -// System headers -// ---------------------------------------------------------------------------- - -#if defined(__WIN32__) && !defined(HAVE_FTIME) && !defined(__MWERKS__) && !defined(__WXWINCE__) - #define HAVE_FTIME -#endif - -#if defined(__VISAGECPP__) && !defined(HAVE_FTIME) - #define HAVE_FTIME -# if __IBMCPP__ >= 400 - # define ftime(x) _ftime(x) -# endif -#endif - -#if defined(__MWERKS__) && defined(__WXMSW__) -# undef HAVE_FTIME -# undef HAVE_GETTIMEOFDAY -#endif - -#ifndef __WXWINCE__ -#include -#else -#include "wx/msw/private.h" -#include "wx/msw/wince/time.h" -#endif - -#if !defined(__WXMAC__) && !defined(__WXWINCE__) - #include // for time_t -#endif - -#if defined(HAVE_GETTIMEOFDAY) - #include - #include -#elif defined(HAVE_FTIME) - #include -#endif - -#ifdef __WXMAC__ -#ifndef __DARWIN__ - #include - #include -#else - #include -#endif -#endif - -#ifdef __WXPALMOS__ - #include - #include - #include -#endif - -// ---------------------------------------------------------------------------- -// macros -// ---------------------------------------------------------------------------- - -// on some really old systems gettimeofday() doesn't have the second argument, -// define wxGetTimeOfDay() to hide this difference -#ifdef HAVE_GETTIMEOFDAY - #ifdef WX_GETTIMEOFDAY_NO_TZ - struct timezone; - #define wxGetTimeOfDay(tv, tz) gettimeofday(tv) - #else - #define wxGetTimeOfDay(tv, tz) gettimeofday((tv), (tz)) - #endif -#endif // HAVE_GETTIMEOFDAY - -// ============================================================================ -// implementation -// ============================================================================ - -// ---------------------------------------------------------------------------- -// wxStopWatch -// ---------------------------------------------------------------------------- - -#if wxUSE_STOPWATCH - -void wxStopWatch::Start(long t) -{ -#if 0 -// __WXMSW__ - LARGE_INTEGER frequency_li; - ::QueryPerformanceFrequency( &frequency_li ); - m_frequency = frequency_li.QuadPart; - if (m_frequency == 0) - { - m_t0 = wxGetLocalTimeMillis() - t; - } - else - { - LARGE_INTEGER counter_li; - ::QueryPerformanceCounter( &counter_li ); - wxLongLong counter = counter_li.QuadPart; - m_t0 = (counter * 10000 / m_frequency) - t*10; - } -#else - m_t0 = wxGetLocalTimeMillis() - t; -#endif - m_pause = 0; - m_pauseCount = 0; -} - -long wxStopWatch::GetElapsedTime() const -{ -#if 0 -//__WXMSW__ - if (m_frequency == 0) - { - return (wxGetLocalTimeMillis() - m_t0).GetLo(); - } - else - { - LARGE_INTEGER counter_li; - ::QueryPerformanceCounter( &counter_li ); - wxLongLong counter = counter_li.QuadPart; - wxLongLong res = (counter * 10000 / m_frequency) - m_t0; - return res.GetLo() / 10; - } -#else - return (wxGetLocalTimeMillis() - m_t0).GetLo(); -#endif -} - -long wxStopWatch::Time() const -{ - return m_pauseCount ? m_pause : GetElapsedTime(); -} - -#endif // wxUSE_STOPWATCH - -// ---------------------------------------------------------------------------- -// old timer functions superceded by wxStopWatch -// ---------------------------------------------------------------------------- - -#if wxUSE_LONGLONG - -static wxLongLong wxStartTime = 0l; - -// starts the global timer -void wxStartTimer() -{ - wxStartTime = wxGetLocalTimeMillis(); -} - -// Returns elapsed time in milliseconds -long wxGetElapsedTime(bool resetTimer) -{ - wxLongLong oldTime = wxStartTime; - wxLongLong newTime = wxGetLocalTimeMillis(); - - if ( resetTimer ) - wxStartTime = newTime; - - return (newTime - oldTime).GetLo(); -} - -#endif // wxUSE_LONGLONG - -// ---------------------------------------------------------------------------- -// the functions to get the current time and timezone info -// ---------------------------------------------------------------------------- - -// Get local time as seconds since 00:00:00, Jan 1st 1970 -long wxGetLocalTime() -{ - struct tm tm; - time_t t0, t1; - - // This cannot be made static because mktime can overwrite it. - // - memset(&tm, 0, sizeof(tm)); - tm.tm_year = 70; - tm.tm_mon = 0; - tm.tm_mday = 5; // not Jan 1st 1970 due to mktime 'feature' - tm.tm_hour = 0; - tm.tm_min = 0; - tm.tm_sec = 0; - tm.tm_isdst = -1; // let mktime guess - - // Note that mktime assumes that the struct tm contains local time. - // - t1 = time(&t1); // now - t0 = mktime(&tm); // origin - - // Return the difference in seconds. - // - if (( t0 != (time_t)-1 ) && ( t1 != (time_t)-1 )) - return (long)difftime(t1, t0) + (60 * 60 * 24 * 4); - - wxLogSysError(_("Failed to get the local system time")); - return -1; -} - -// Get UTC time as seconds since 00:00:00, Jan 1st 1970 -long wxGetUTCTime() -{ - return (long)time(NULL); -} - -#if wxUSE_LONGLONG - -// Get local time as milliseconds since 00:00:00, Jan 1st 1970 -wxLongLong wxGetLocalTimeMillis() -{ - wxLongLong val = 1000l; - - // If possible, use a function which avoids conversions from - // broken-up time structures to milliseconds - -#if defined(__WXPALMOS__) - DateTimeType thenst; - thenst.second = 0; - thenst.minute = 0; - thenst.hour = 0; - thenst.day = 1; - thenst.month = 1; - thenst.year = 1970; - thenst.weekDay = 5; - uint32_t now = TimGetSeconds(); - uint32_t then = TimDateTimeToSeconds (&thenst); - return SysTimeToMilliSecs(SysTimeInSecs(now - then)); -#elif defined(__WXMSW__) && (defined(__WINE__) || defined(__MWERKS__)) - // This should probably be the way all WXMSW compilers should do it - // Go direct to the OS for time - - SYSTEMTIME thenst = { 1970, 1, 4, 1, 0, 0, 0, 0 }; // 00:00:00 Jan 1st 1970 - FILETIME thenft; - SystemTimeToFileTime( &thenst, &thenft ); - wxLongLong then( thenft.dwHighDateTime, thenft.dwLowDateTime ); // time in 100 nanoseconds - - SYSTEMTIME nowst; - GetLocalTime( &nowst ); - FILETIME nowft; - SystemTimeToFileTime( &nowst, &nowft ); - wxLongLong now( nowft.dwHighDateTime, nowft.dwLowDateTime ); // time in 100 nanoseconds - - return ( now - then ) / 10000.0; // time from 00:00:00 Jan 1st 1970 to now in milliseconds - -#elif defined(HAVE_GETTIMEOFDAY) - struct timeval tp; - if ( wxGetTimeOfDay(&tp, (struct timezone *)NULL) != -1 ) - { - val *= tp.tv_sec; - return (val + (tp.tv_usec / 1000)); - } - else - { - wxLogError(_("wxGetTimeOfDay failed.")); - return 0; - } -#elif defined(HAVE_FTIME) - struct timeb tp; - - // ftime() is void and not int in some mingw32 headers, so don't - // test the return code (well, it shouldn't fail anyhow...) - (void)::ftime(&tp); - val *= tp.time; - return (val + tp.millitm); -#elif defined(__WXMAC__) - - static UInt64 gMilliAtStart = 0; - - Nanoseconds upTime = AbsoluteToNanoseconds( UpTime() ); - - if ( gMilliAtStart == 0 ) - { - time_t start = time(NULL); - gMilliAtStart = ((UInt64) start) * 1000000L; - gMilliAtStart -= upTime.lo / 1000 ; - gMilliAtStart -= ( ( (UInt64) upTime.hi ) << 32 ) / (1000 * 1000); - } - - UInt64 millival = gMilliAtStart; - millival += upTime.lo / (1000 * 1000); - millival += ( ( (UInt64) upTime.hi ) << 32 ) / (1000 * 1000); - val = millival; - - return val; -#else // no gettimeofday() nor ftime() - // We use wxGetLocalTime() to get the seconds since - // 00:00:00 Jan 1st 1970 and then whatever is available - // to get millisecond resolution. - // - // NOTE that this might lead to a problem if the clocks - // use different sources, so this approach should be - // avoided where possible. - - val *= wxGetLocalTime(); - -// GRG: This will go soon as all WIN32 seem to have ftime -// JACS: unfortunately not. WinCE doesn't have it. -#if defined (__WIN32__) - // If your platform/compiler needs to use two different functions - // to get ms resolution, please do NOT just shut off these warnings, - // drop me a line instead at - - // FIXME -#ifndef __WXWINCE__ - #warning "Possible clock skew bug in wxGetLocalTimeMillis()!" -#endif - - SYSTEMTIME st; - ::GetLocalTime(&st); - val += st.wMilliseconds; -#else // !Win32 - // If your platform/compiler does not support ms resolution please - // do NOT just shut off these warnings, drop me a line instead at - // - - #if defined(__VISUALC__) || defined (__WATCOMC__) - #pragma message("wxStopWatch will be up to second resolution!") - #elif defined(__BORLANDC__) - #pragma message "wxStopWatch will be up to second resolution!" - #else - #warning "wxStopWatch will be up to second resolution!" - #endif // compiler -#endif - - return val; - -#endif // time functions -} - -#else // !wxUSE_LONGLONG - -double wxGetLocalTimeMillis(void) -{ - return (double(clock()) / double(CLOCKS_PER_SEC)) * 1000.0; -} - -#endif // wxUSE_LONGLONG/!wxUSE_LONGLONG +/////////////////////////////////////////////////////////////////////////////// +// Name: src/common/stopwatch.cpp +// Purpose: wxStopWatch and other non-GUI stuff from wx/timer.h +// Author: +// Original version by Julian Smart +// Vadim Zeitlin got rid of all ifdefs (11.12.99) +// Sylvain Bougnoux added wxStopWatch class +// Guillermo Rodriguez rewrote from scratch (Dic/99) +// Modified by: +// Created: 20.06.2003 (extracted from common/timercmn.cpp) +// RCS-ID: $Id: stopwatch.cpp 41054 2006-09-07 19:01:45Z ABX $ +// Copyright: (c) 1998-2003 wxWidgets Team +// License: wxWindows license +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// for compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#include "wx/stopwatch.h" + +#ifndef WX_PRECOMP + #ifdef __WXMSW__ + #include "wx/msw/wrapwin.h" + #endif + #include "wx/intl.h" + #include "wx/log.h" +#endif //WX_PRECOMP + +// ---------------------------------------------------------------------------- +// System headers +// ---------------------------------------------------------------------------- + +#if defined(__WIN32__) && !defined(HAVE_FTIME) && !defined(__MWERKS__) && !defined(__WXWINCE__) + #define HAVE_FTIME +#endif + +#if defined(__VISAGECPP__) && !defined(HAVE_FTIME) + #define HAVE_FTIME +# if __IBMCPP__ >= 400 + # define ftime(x) _ftime(x) +# endif +#endif + +#if defined(__MWERKS__) && defined(__WXMSW__) +# undef HAVE_FTIME +# undef HAVE_GETTIMEOFDAY +#endif + +#ifndef __WXWINCE__ +#include +#else +#include "wx/msw/private.h" +#include "wx/msw/wince/time.h" +#endif + +#if !defined(__WXMAC__) && !defined(__WXWINCE__) + #include // for time_t +#endif + +#if defined(HAVE_GETTIMEOFDAY) + #include + #include +#elif defined(HAVE_FTIME) + #include +#endif + +#ifdef __WXMAC__ +#ifndef __DARWIN__ + #include + #include +#else + #include +#endif +#endif + +#ifdef __WXPALMOS__ + #include + #include + #include +#endif + +// ---------------------------------------------------------------------------- +// macros +// ---------------------------------------------------------------------------- + +// on some really old systems gettimeofday() doesn't have the second argument, +// define wxGetTimeOfDay() to hide this difference +#ifdef HAVE_GETTIMEOFDAY + #ifdef WX_GETTIMEOFDAY_NO_TZ + struct timezone; + #define wxGetTimeOfDay(tv, tz) gettimeofday(tv) + #else + #define wxGetTimeOfDay(tv, tz) gettimeofday((tv), (tz)) + #endif +#endif // HAVE_GETTIMEOFDAY + +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// wxStopWatch +// ---------------------------------------------------------------------------- + +#if wxUSE_STOPWATCH + +void wxStopWatch::Start(long t) +{ +#if 0 +// __WXMSW__ + LARGE_INTEGER frequency_li; + ::QueryPerformanceFrequency( &frequency_li ); + m_frequency = frequency_li.QuadPart; + if (m_frequency == 0) + { + m_t0 = wxGetLocalTimeMillis() - t; + } + else + { + LARGE_INTEGER counter_li; + ::QueryPerformanceCounter( &counter_li ); + wxLongLong counter = counter_li.QuadPart; + m_t0 = (counter * 10000 / m_frequency) - t*10; + } +#else + m_t0 = wxGetLocalTimeMillis() - t; +#endif + m_pause = 0; + m_pauseCount = 0; +} + +long wxStopWatch::GetElapsedTime() const +{ +#if 0 +//__WXMSW__ + if (m_frequency == 0) + { + return (wxGetLocalTimeMillis() - m_t0).GetLo(); + } + else + { + LARGE_INTEGER counter_li; + ::QueryPerformanceCounter( &counter_li ); + wxLongLong counter = counter_li.QuadPart; + wxLongLong res = (counter * 10000 / m_frequency) - m_t0; + return res.GetLo() / 10; + } +#else + return (wxGetLocalTimeMillis() - m_t0).GetLo(); +#endif +} + +long wxStopWatch::Time() const +{ + return m_pauseCount ? m_pause : GetElapsedTime(); +} + +#endif // wxUSE_STOPWATCH + +// ---------------------------------------------------------------------------- +// old timer functions superceded by wxStopWatch +// ---------------------------------------------------------------------------- + +#if wxUSE_LONGLONG + +static wxLongLong wxStartTime = 0l; + +// starts the global timer +void wxStartTimer() +{ + wxStartTime = wxGetLocalTimeMillis(); +} + +// Returns elapsed time in milliseconds +long wxGetElapsedTime(bool resetTimer) +{ + wxLongLong oldTime = wxStartTime; + wxLongLong newTime = wxGetLocalTimeMillis(); + + if ( resetTimer ) + wxStartTime = newTime; + + return (newTime - oldTime).GetLo(); +} + +#endif // wxUSE_LONGLONG + +// ---------------------------------------------------------------------------- +// the functions to get the current time and timezone info +// ---------------------------------------------------------------------------- + +// Get local time as seconds since 00:00:00, Jan 1st 1970 +long wxGetLocalTime() +{ + struct tm tm; + time_t t0, t1; + + // This cannot be made static because mktime can overwrite it. + // + memset(&tm, 0, sizeof(tm)); + tm.tm_year = 70; + tm.tm_mon = 0; + tm.tm_mday = 5; // not Jan 1st 1970 due to mktime 'feature' + tm.tm_hour = 0; + tm.tm_min = 0; + tm.tm_sec = 0; + tm.tm_isdst = -1; // let mktime guess + + // Note that mktime assumes that the struct tm contains local time. + // + t1 = time(&t1); // now + t0 = mktime(&tm); // origin + + // Return the difference in seconds. + // + if (( t0 != (time_t)-1 ) && ( t1 != (time_t)-1 )) + return (long)difftime(t1, t0) + (60 * 60 * 24 * 4); + + wxLogSysError(_("Failed to get the local system time")); + return -1; +} + +// Get UTC time as seconds since 00:00:00, Jan 1st 1970 +long wxGetUTCTime() +{ + return (long)time(NULL); +} + +#if wxUSE_LONGLONG + +// Get local time as milliseconds since 00:00:00, Jan 1st 1970 +wxLongLong wxGetLocalTimeMillis() +{ + wxLongLong val = 1000l; + + // If possible, use a function which avoids conversions from + // broken-up time structures to milliseconds + +#if defined(__WXPALMOS__) + DateTimeType thenst; + thenst.second = 0; + thenst.minute = 0; + thenst.hour = 0; + thenst.day = 1; + thenst.month = 1; + thenst.year = 1970; + thenst.weekDay = 5; + uint32_t now = TimGetSeconds(); + uint32_t then = TimDateTimeToSeconds (&thenst); + return SysTimeToMilliSecs(SysTimeInSecs(now - then)); +#elif defined(__WXMSW__) && (defined(__WINE__) || defined(__MWERKS__)) + // This should probably be the way all WXMSW compilers should do it + // Go direct to the OS for time + + SYSTEMTIME thenst = { 1970, 1, 4, 1, 0, 0, 0, 0 }; // 00:00:00 Jan 1st 1970 + FILETIME thenft; + SystemTimeToFileTime( &thenst, &thenft ); + wxLongLong then( thenft.dwHighDateTime, thenft.dwLowDateTime ); // time in 100 nanoseconds + + SYSTEMTIME nowst; + GetLocalTime( &nowst ); + FILETIME nowft; + SystemTimeToFileTime( &nowst, &nowft ); + wxLongLong now( nowft.dwHighDateTime, nowft.dwLowDateTime ); // time in 100 nanoseconds + + return ( now - then ) / 10000.0; // time from 00:00:00 Jan 1st 1970 to now in milliseconds + +#elif defined(HAVE_GETTIMEOFDAY) + struct timeval tp; + if ( wxGetTimeOfDay(&tp, (struct timezone *)NULL) != -1 ) + { + val *= tp.tv_sec; + return (val + (tp.tv_usec / 1000)); + } + else + { + wxLogError(_("wxGetTimeOfDay failed.")); + return 0; + } +#elif defined(HAVE_FTIME) + struct timeb tp; + + // ftime() is void and not int in some mingw32 headers, so don't + // test the return code (well, it shouldn't fail anyhow...) + (void)::ftime(&tp); + val *= tp.time; + return (val + tp.millitm); +#elif defined(__WXMAC__) + + static UInt64 gMilliAtStart = 0; + + Nanoseconds upTime = AbsoluteToNanoseconds( UpTime() ); + + if ( gMilliAtStart == 0 ) + { + time_t start = time(NULL); + gMilliAtStart = ((UInt64) start) * 1000000L; + gMilliAtStart -= upTime.lo / 1000 ; + gMilliAtStart -= ( ( (UInt64) upTime.hi ) << 32 ) / (1000 * 1000); + } + + UInt64 millival = gMilliAtStart; + millival += upTime.lo / (1000 * 1000); + millival += ( ( (UInt64) upTime.hi ) << 32 ) / (1000 * 1000); + val = millival; + + return val; +#else // no gettimeofday() nor ftime() + // We use wxGetLocalTime() to get the seconds since + // 00:00:00 Jan 1st 1970 and then whatever is available + // to get millisecond resolution. + // + // NOTE that this might lead to a problem if the clocks + // use different sources, so this approach should be + // avoided where possible. + + val *= wxGetLocalTime(); + +// GRG: This will go soon as all WIN32 seem to have ftime +// JACS: unfortunately not. WinCE doesn't have it. +#if defined (__WIN32__) + // If your platform/compiler needs to use two different functions + // to get ms resolution, please do NOT just shut off these warnings, + // drop me a line instead at + + // FIXME +#ifndef __WXWINCE__ + #warning "Possible clock skew bug in wxGetLocalTimeMillis()!" +#endif + + SYSTEMTIME st; + ::GetLocalTime(&st); + val += st.wMilliseconds; +#else // !Win32 + // If your platform/compiler does not support ms resolution please + // do NOT just shut off these warnings, drop me a line instead at + // + + #if defined(__VISUALC__) || defined (__WATCOMC__) + #pragma message("wxStopWatch will be up to second resolution!") + #elif defined(__BORLANDC__) + #pragma message "wxStopWatch will be up to second resolution!" + #else + #warning "wxStopWatch will be up to second resolution!" + #endif // compiler +#endif + + return val; + +#endif // time functions +} + +#else // !wxUSE_LONGLONG + +double wxGetLocalTimeMillis(void) +{ + return (double(clock()) / double(CLOCKS_PER_SEC)) * 1000.0; +} + +#endif // wxUSE_LONGLONG/!wxUSE_LONGLONG diff --git a/Externals/wxWidgets/src/common/strconv.cpp b/Externals/wxWidgets/src/common/strconv.cpp index 3de2fe6a9b..56f580de44 100644 --- a/Externals/wxWidgets/src/common/strconv.cpp +++ b/Externals/wxWidgets/src/common/strconv.cpp @@ -1,3697 +1,3697 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/strconv.cpp -// Purpose: Unicode conversion classes -// Author: Ove Kaaven, Robert Roebling, Vadim Zeitlin, Vaclav Slavik, -// Ryan Norton, Fredrik Roubert (UTF7) -// Modified by: -// Created: 29/01/98 -// RCS-ID: $Id: strconv.cpp 45921 2007-05-09 18:10:26Z VZ $ -// Copyright: (c) 1999 Ove Kaaven, Robert Roebling, Vaclav Slavik -// (c) 2000-2003 Vadim Zeitlin -// (c) 2004 Ryan Norton, Fredrik Roubert -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifndef WX_PRECOMP - #ifdef __WXMSW__ - #include "wx/msw/missing.h" - #endif - #include "wx/intl.h" - #include "wx/log.h" - #include "wx/utils.h" - #include "wx/hashmap.h" -#endif - -#include "wx/strconv.h" - -#if wxUSE_WCHAR_T - -#ifdef __WINDOWS__ - #include "wx/msw/private.h" -#endif - -#ifndef __WXWINCE__ -#include -#endif - -#include -#include -#include - -#if defined(__WIN32__) && !defined(__WXMICROWIN__) - #define wxHAVE_WIN32_MB2WC -#endif - -#ifdef __SALFORDC__ - #include -#endif - -#ifdef HAVE_ICONV - #include - #include "wx/thread.h" -#endif - -#include "wx/encconv.h" -#include "wx/fontmap.h" - -#ifdef __WXMAC__ -#ifndef __DARWIN__ -#include -#include -#include -#endif - -// includes Mac headers -#include "wx/mac/private.h" -#endif - - -#define TRACE_STRCONV _T("strconv") - -// WC_UTF16 is defined only if sizeof(wchar_t) == 2, otherwise it's supposed to -// be 4 bytes -#if SIZEOF_WCHAR_T == 2 - #define WC_UTF16 -#endif - - -// ============================================================================ -// implementation -// ============================================================================ - -// helper function of cMB2WC(): check if n bytes at this location are all NUL -static bool NotAllNULs(const char *p, size_t n) -{ - while ( n && *p++ == '\0' ) - n--; - - return n != 0; -} - -// ---------------------------------------------------------------------------- -// UTF-16 en/decoding to/from UCS-4 with surrogates handling -// ---------------------------------------------------------------------------- - -static size_t encode_utf16(wxUint32 input, wxUint16 *output) -{ - if (input <= 0xffff) - { - if (output) - *output = (wxUint16) input; - - return 1; - } - else if (input >= 0x110000) - { - return wxCONV_FAILED; - } - else - { - if (output) - { - *output++ = (wxUint16) ((input >> 10) + 0xd7c0); - *output = (wxUint16) ((input & 0x3ff) + 0xdc00); - } - - return 2; - } -} - -static size_t decode_utf16(const wxUint16* input, wxUint32& output) -{ - if ((*input < 0xd800) || (*input > 0xdfff)) - { - output = *input; - return 1; - } - else if ((input[1] < 0xdc00) || (input[1] > 0xdfff)) - { - output = *input; - return wxCONV_FAILED; - } - else - { - output = ((input[0] - 0xd7c0) << 10) + (input[1] - 0xdc00); - return 2; - } -} - -#ifdef WC_UTF16 - typedef wchar_t wxDecodeSurrogate_t; -#else // !WC_UTF16 - typedef wxUint16 wxDecodeSurrogate_t; -#endif // WC_UTF16/!WC_UTF16 - -// returns the next UTF-32 character from the wchar_t buffer and advances the -// pointer to the character after this one -// -// if an invalid character is found, *pSrc is set to NULL, the caller must -// check for this -static wxUint32 wxDecodeSurrogate(const wxDecodeSurrogate_t **pSrc) -{ - wxUint32 out; - const size_t - n = decode_utf16(wx_reinterpret_cast(const wxUint16 *, *pSrc), out); - if ( n == wxCONV_FAILED ) - *pSrc = NULL; - else - *pSrc += n; - - return out; -} - -// ---------------------------------------------------------------------------- -// wxMBConv -// ---------------------------------------------------------------------------- - -size_t -wxMBConv::ToWChar(wchar_t *dst, size_t dstLen, - const char *src, size_t srcLen) const -{ - // although new conversion classes are supposed to implement this function - // directly, the existins ones only implement the old MB2WC() and so, to - // avoid to have to rewrite all conversion classes at once, we provide a - // default (but not efficient) implementation of this one in terms of the - // old function by copying the input to ensure that it's NUL-terminated and - // then using MB2WC() to convert it - - // the number of chars [which would be] written to dst [if it were not NULL] - size_t dstWritten = 0; - - // the number of NULs terminating this string - size_t nulLen = 0; // not really needed, but just to avoid warnings - - // if we were not given the input size we just have to assume that the - // string is properly terminated as we have no way of knowing how long it - // is anyhow, but if we do have the size check whether there are enough - // NULs at the end - wxCharBuffer bufTmp; - const char *srcEnd; - if ( srcLen != wxNO_LEN ) - { - // we need to know how to find the end of this string - nulLen = GetMBNulLen(); - if ( nulLen == wxCONV_FAILED ) - return wxCONV_FAILED; - - // if there are enough NULs we can avoid the copy - if ( srcLen < nulLen || NotAllNULs(src + srcLen - nulLen, nulLen) ) - { - // make a copy in order to properly NUL-terminate the string - bufTmp = wxCharBuffer(srcLen + nulLen - 1 /* 1 will be added */); - char * const p = bufTmp.data(); - memcpy(p, src, srcLen); - for ( char *s = p + srcLen; s < p + srcLen + nulLen; s++ ) - *s = '\0'; - - src = bufTmp; - } - - srcEnd = src + srcLen; - } - else // quit after the first loop iteration - { - srcEnd = NULL; - } - - for ( ;; ) - { - // try to convert the current chunk - size_t lenChunk = MB2WC(NULL, src, 0); - if ( lenChunk == wxCONV_FAILED ) - return wxCONV_FAILED; - - lenChunk++; // for the L'\0' at the end of this chunk - - dstWritten += lenChunk; - - if ( lenChunk == 1 ) - { - // nothing left in the input string, conversion succeeded - break; - } - - if ( dst ) - { - if ( dstWritten > dstLen ) - return wxCONV_FAILED; - - if ( MB2WC(dst, src, lenChunk) == wxCONV_FAILED ) - return wxCONV_FAILED; - - dst += lenChunk; - } - - if ( !srcEnd ) - { - // we convert just one chunk in this case as this is the entire - // string anyhow - break; - } - - // advance the input pointer past the end of this chunk - while ( NotAllNULs(src, nulLen) ) - { - // notice that we must skip over multiple bytes here as we suppose - // that if NUL takes 2 or 4 bytes, then all the other characters do - // too and so if advanced by a single byte we might erroneously - // detect sequences of NUL bytes in the middle of the input - src += nulLen; - } - - src += nulLen; // skipping over its terminator as well - - // note that ">=" (and not just "==") is needed here as the terminator - // we skipped just above could be inside or just after the buffer - // delimited by inEnd - if ( src >= srcEnd ) - break; - } - - return dstWritten; -} - -size_t -wxMBConv::FromWChar(char *dst, size_t dstLen, - const wchar_t *src, size_t srcLen) const -{ - // the number of chars [which would be] written to dst [if it were not NULL] - size_t dstWritten = 0; - - // make a copy of the input string unless it is already properly - // NUL-terminated - // - // if we don't know its length we have no choice but to assume that it is, - // indeed, properly terminated - wxWCharBuffer bufTmp; - if ( srcLen == wxNO_LEN ) - { - srcLen = wxWcslen(src) + 1; - } - else if ( srcLen != 0 && src[srcLen - 1] != L'\0' ) - { - // make a copy in order to properly NUL-terminate the string - bufTmp = wxWCharBuffer(srcLen); - memcpy(bufTmp.data(), src, srcLen * sizeof(wchar_t)); - src = bufTmp; - } - - const size_t lenNul = GetMBNulLen(); - for ( const wchar_t * const srcEnd = src + srcLen; - src < srcEnd; - src += wxWcslen(src) + 1 /* skip L'\0' too */ ) - { - // try to convert the current chunk - size_t lenChunk = WC2MB(NULL, src, 0); - - if ( lenChunk == wxCONV_FAILED ) - return wxCONV_FAILED; - - lenChunk += lenNul; - dstWritten += lenChunk; - - if ( dst ) - { - if ( dstWritten > dstLen ) - return wxCONV_FAILED; - - if ( WC2MB(dst, src, lenChunk) == wxCONV_FAILED ) - return wxCONV_FAILED; - - dst += lenChunk; - } - } - - return dstWritten; -} - -size_t wxMBConv::MB2WC(wchar_t *outBuff, const char *inBuff, size_t outLen) const -{ - size_t rc = ToWChar(outBuff, outLen, inBuff); - if ( rc != wxCONV_FAILED ) - { - // ToWChar() returns the buffer length, i.e. including the trailing - // NUL, while this method doesn't take it into account - rc--; - } - - return rc; -} - -size_t wxMBConv::WC2MB(char *outBuff, const wchar_t *inBuff, size_t outLen) const -{ - size_t rc = FromWChar(outBuff, outLen, inBuff); - if ( rc != wxCONV_FAILED ) - { - rc -= GetMBNulLen(); - } - - return rc; -} - -wxMBConv::~wxMBConv() -{ - // nothing to do here (necessary for Darwin linking probably) -} - -const wxWCharBuffer wxMBConv::cMB2WC(const char *psz) const -{ - if ( psz ) - { - // calculate the length of the buffer needed first - const size_t nLen = MB2WC(NULL, psz, 0); - if ( nLen != wxCONV_FAILED ) - { - // now do the actual conversion - wxWCharBuffer buf(nLen /* +1 added implicitly */); - - // +1 for the trailing NULL - if ( MB2WC(buf.data(), psz, nLen + 1) != wxCONV_FAILED ) - return buf; - } - } - - return wxWCharBuffer(); -} - -const wxCharBuffer wxMBConv::cWC2MB(const wchar_t *pwz) const -{ - if ( pwz ) - { - const size_t nLen = WC2MB(NULL, pwz, 0); - if ( nLen != wxCONV_FAILED ) - { - // extra space for trailing NUL(s) - static const size_t extraLen = GetMaxMBNulLen(); - - wxCharBuffer buf(nLen + extraLen - 1); - if ( WC2MB(buf.data(), pwz, nLen + extraLen) != wxCONV_FAILED ) - return buf; - } - } - - return wxCharBuffer(); -} - -const wxWCharBuffer -wxMBConv::cMB2WC(const char *inBuff, size_t inLen, size_t *outLen) const -{ - const size_t dstLen = ToWChar(NULL, 0, inBuff, inLen); - if ( dstLen != wxCONV_FAILED ) - { - wxWCharBuffer wbuf(dstLen - 1); - if ( ToWChar(wbuf.data(), dstLen, inBuff, inLen) != wxCONV_FAILED ) - { - if ( outLen ) - { - *outLen = dstLen; - if ( wbuf[dstLen - 1] == L'\0' ) - (*outLen)--; - } - - return wbuf; - } - } - - if ( outLen ) - *outLen = 0; - - return wxWCharBuffer(); -} - -const wxCharBuffer -wxMBConv::cWC2MB(const wchar_t *inBuff, size_t inLen, size_t *outLen) const -{ - size_t dstLen = FromWChar(NULL, 0, inBuff, inLen); - if ( dstLen != wxCONV_FAILED ) - { - // special case of empty input: can't allocate 0 size buffer below as - // wxCharBuffer insists on NUL-terminating it - wxCharBuffer buf(dstLen ? dstLen - 1 : 1); - if ( FromWChar(buf.data(), dstLen, inBuff, inLen) != wxCONV_FAILED ) - { - if ( outLen ) - { - *outLen = dstLen; - - const size_t nulLen = GetMBNulLen(); - if ( dstLen >= nulLen && - !NotAllNULs(buf.data() + dstLen - nulLen, nulLen) ) - { - // in this case the output is NUL-terminated and we're not - // supposed to count NUL - *outLen -= nulLen; - } - } - - return buf; - } - } - - if ( outLen ) - *outLen = 0; - - return wxCharBuffer(); -} - -// ---------------------------------------------------------------------------- -// wxMBConvLibc -// ---------------------------------------------------------------------------- - -size_t wxMBConvLibc::MB2WC(wchar_t *buf, const char *psz, size_t n) const -{ - return wxMB2WC(buf, psz, n); -} - -size_t wxMBConvLibc::WC2MB(char *buf, const wchar_t *psz, size_t n) const -{ - return wxWC2MB(buf, psz, n); -} - -// ---------------------------------------------------------------------------- -// wxConvBrokenFileNames -// ---------------------------------------------------------------------------- - -#ifdef __UNIX__ - -wxConvBrokenFileNames::wxConvBrokenFileNames(const wxChar *charset) -{ - if ( !charset || wxStricmp(charset, _T("UTF-8")) == 0 - || wxStricmp(charset, _T("UTF8")) == 0 ) - m_conv = new wxMBConvUTF8(wxMBConvUTF8::MAP_INVALID_UTF8_TO_PUA); - else - m_conv = new wxCSConv(charset); -} - -#endif // __UNIX__ - -// ---------------------------------------------------------------------------- -// UTF-7 -// ---------------------------------------------------------------------------- - -// Implementation (C) 2004 Fredrik Roubert - -// -// BASE64 decoding table -// -static const unsigned char utf7unb64[] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0x3e, 0xff, 0xff, 0xff, 0x3f, - 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, - 0x3c, 0x3d, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, - 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, - 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, - 0x17, 0x18, 0x19, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, - 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, - 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, - 0x31, 0x32, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; - -size_t wxMBConvUTF7::MB2WC(wchar_t *buf, const char *psz, size_t n) const -{ - size_t len = 0; - - while ( *psz && (!buf || (len < n)) ) - { - unsigned char cc = *psz++; - if (cc != '+') - { - // plain ASCII char - if (buf) - *buf++ = cc; - len++; - } - else if (*psz == '-') - { - // encoded plus sign - if (buf) - *buf++ = cc; - len++; - psz++; - } - else // start of BASE64 encoded string - { - bool lsb, ok; - unsigned int d, l; - for ( ok = lsb = false, d = 0, l = 0; - (cc = utf7unb64[(unsigned char)*psz]) != 0xff; - psz++ ) - { - d <<= 6; - d += cc; - for (l += 6; l >= 8; lsb = !lsb) - { - unsigned char c = (unsigned char)((d >> (l -= 8)) % 256); - if (lsb) - { - if (buf) - *buf++ |= c; - len ++; - } - else - { - if (buf) - *buf = (wchar_t)(c << 8); - } - - ok = true; - } - } - - if ( !ok ) - { - // in valid UTF7 we should have valid characters after '+' - return wxCONV_FAILED; - } - - if (*psz == '-') - psz++; - } - } - - if ( buf && (len < n) ) - *buf = '\0'; - - return len; -} - -// -// BASE64 encoding table -// -static const unsigned char utf7enb64[] = -{ - 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', - 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', - 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', - 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', - 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', - 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', - 'w', 'x', 'y', 'z', '0', '1', '2', '3', - '4', '5', '6', '7', '8', '9', '+', '/' -}; - -// -// UTF-7 encoding table -// -// 0 - Set D (directly encoded characters) -// 1 - Set O (optional direct characters) -// 2 - whitespace characters (optional) -// 3 - special characters -// -static const unsigned char utf7encode[128] = -{ - 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 3, 3, 2, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 2, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 3, 0, 0, 0, 3, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, - 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 3, 1, 1, 1, - 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 3, 3 -}; - -size_t wxMBConvUTF7::WC2MB(char *buf, const wchar_t *psz, size_t n) const -{ - size_t len = 0; - - while (*psz && ((!buf) || (len < n))) - { - wchar_t cc = *psz++; - if (cc < 0x80 && utf7encode[cc] < 1) - { - // plain ASCII char - if (buf) - *buf++ = (char)cc; - - len++; - } -#ifndef WC_UTF16 - else if (((wxUint32)cc) > 0xffff) - { - // no surrogate pair generation (yet?) - return wxCONV_FAILED; - } -#endif - else - { - if (buf) - *buf++ = '+'; - - len++; - if (cc != '+') - { - // BASE64 encode string - unsigned int lsb, d, l; - for (d = 0, l = 0; /*nothing*/; psz++) - { - for (lsb = 0; lsb < 2; lsb ++) - { - d <<= 8; - d += lsb ? cc & 0xff : (cc & 0xff00) >> 8; - - for (l += 8; l >= 6; ) - { - l -= 6; - if (buf) - *buf++ = utf7enb64[(d >> l) % 64]; - len++; - } - } - - cc = *psz; - if (!(cc) || (cc < 0x80 && utf7encode[cc] < 1)) - break; - } - - if (l != 0) - { - if (buf) - *buf++ = utf7enb64[((d % 16) << (6 - l)) % 64]; - - len++; - } - } - - if (buf) - *buf++ = '-'; - len++; - } - } - - if (buf && (len < n)) - *buf = 0; - - return len; -} - -// ---------------------------------------------------------------------------- -// UTF-8 -// ---------------------------------------------------------------------------- - -static wxUint32 utf8_max[]= - { 0x7f, 0x7ff, 0xffff, 0x1fffff, 0x3ffffff, 0x7fffffff, 0xffffffff }; - -// boundaries of the private use area we use to (temporarily) remap invalid -// characters invalid in a UTF-8 encoded string -const wxUint32 wxUnicodePUA = 0x100000; -const wxUint32 wxUnicodePUAEnd = wxUnicodePUA + 256; - -size_t wxMBConvUTF8::MB2WC(wchar_t *buf, const char *psz, size_t n) const -{ - size_t len = 0; - - while (*psz && ((!buf) || (len < n))) - { - const char *opsz = psz; - bool invalid = false; - unsigned char cc = *psz++, fc = cc; - unsigned cnt; - for (cnt = 0; fc & 0x80; cnt++) - fc <<= 1; - - if (!cnt) - { - // plain ASCII char - if (buf) - *buf++ = cc; - len++; - - // escape the escape character for octal escapes - if ((m_options & MAP_INVALID_UTF8_TO_OCTAL) - && cc == '\\' && (!buf || len < n)) - { - if (buf) - *buf++ = cc; - len++; - } - } - else - { - cnt--; - if (!cnt) - { - // invalid UTF-8 sequence - invalid = true; - } - else - { - unsigned ocnt = cnt - 1; - wxUint32 res = cc & (0x3f >> cnt); - while (cnt--) - { - cc = *psz; - if ((cc & 0xC0) != 0x80) - { - // invalid UTF-8 sequence - invalid = true; - break; - } - - psz++; - res = (res << 6) | (cc & 0x3f); - } - - if (invalid || res <= utf8_max[ocnt]) - { - // illegal UTF-8 encoding - invalid = true; - } - else if ((m_options & MAP_INVALID_UTF8_TO_PUA) && - res >= wxUnicodePUA && res < wxUnicodePUAEnd) - { - // if one of our PUA characters turns up externally - // it must also be treated as an illegal sequence - // (a bit like you have to escape an escape character) - invalid = true; - } - else - { -#ifdef WC_UTF16 - // cast is ok because wchar_t == wxUuint16 if WC_UTF16 - size_t pa = encode_utf16(res, (wxUint16 *)buf); - if (pa == wxCONV_FAILED) - { - invalid = true; - } - else - { - if (buf) - buf += pa; - len += pa; - } -#else // !WC_UTF16 - if (buf) - *buf++ = (wchar_t)res; - len++; -#endif // WC_UTF16/!WC_UTF16 - } - } - - if (invalid) - { - if (m_options & MAP_INVALID_UTF8_TO_PUA) - { - while (opsz < psz && (!buf || len < n)) - { -#ifdef WC_UTF16 - // cast is ok because wchar_t == wxUuint16 if WC_UTF16 - size_t pa = encode_utf16((unsigned char)*opsz + wxUnicodePUA, (wxUint16 *)buf); - wxASSERT(pa != wxCONV_FAILED); - if (buf) - buf += pa; - opsz++; - len += pa; -#else - if (buf) - *buf++ = (wchar_t)(wxUnicodePUA + (unsigned char)*opsz); - opsz++; - len++; -#endif - } - } - else if (m_options & MAP_INVALID_UTF8_TO_OCTAL) - { - while (opsz < psz && (!buf || len < n)) - { - if ( buf && len + 3 < n ) - { - unsigned char on = *opsz; - *buf++ = L'\\'; - *buf++ = (wchar_t)( L'0' + on / 0100 ); - *buf++ = (wchar_t)( L'0' + (on % 0100) / 010 ); - *buf++ = (wchar_t)( L'0' + on % 010 ); - } - - opsz++; - len += 4; - } - } - else // MAP_INVALID_UTF8_NOT - { - return wxCONV_FAILED; - } - } - } - } - - if (buf && (len < n)) - *buf = 0; - - return len; -} - -static inline bool isoctal(wchar_t wch) -{ - return L'0' <= wch && wch <= L'7'; -} - -size_t wxMBConvUTF8::WC2MB(char *buf, const wchar_t *psz, size_t n) const -{ - size_t len = 0; - - while (*psz && ((!buf) || (len < n))) - { - wxUint32 cc; - -#ifdef WC_UTF16 - // cast is ok for WC_UTF16 - size_t pa = decode_utf16((const wxUint16 *)psz, cc); - psz += (pa == wxCONV_FAILED) ? 1 : pa; -#else - cc = (*psz++) & 0x7fffffff; -#endif - - if ( (m_options & MAP_INVALID_UTF8_TO_PUA) - && cc >= wxUnicodePUA && cc < wxUnicodePUAEnd ) - { - if (buf) - *buf++ = (char)(cc - wxUnicodePUA); - len++; - } - else if ( (m_options & MAP_INVALID_UTF8_TO_OCTAL) - && cc == L'\\' && psz[0] == L'\\' ) - { - if (buf) - *buf++ = (char)cc; - psz++; - len++; - } - else if ( (m_options & MAP_INVALID_UTF8_TO_OCTAL) && - cc == L'\\' && - isoctal(psz[0]) && isoctal(psz[1]) && isoctal(psz[2]) ) - { - if (buf) - { - *buf++ = (char) ((psz[0] - L'0') * 0100 + - (psz[1] - L'0') * 010 + - (psz[2] - L'0')); - } - - psz += 3; - len++; - } - else - { - unsigned cnt; - for (cnt = 0; cc > utf8_max[cnt]; cnt++) - { - } - - if (!cnt) - { - // plain ASCII char - if (buf) - *buf++ = (char) cc; - len++; - } - else - { - len += cnt + 1; - if (buf) - { - *buf++ = (char) ((-128 >> cnt) | ((cc >> (cnt * 6)) & (0x3f >> cnt))); - while (cnt--) - *buf++ = (char) (0x80 | ((cc >> (cnt * 6)) & 0x3f)); - } - } - } - } - - if (buf && (len < n)) - *buf = 0; - - return len; -} - -// ============================================================================ -// UTF-16 -// ============================================================================ - -#ifdef WORDS_BIGENDIAN - #define wxMBConvUTF16straight wxMBConvUTF16BE - #define wxMBConvUTF16swap wxMBConvUTF16LE -#else - #define wxMBConvUTF16swap wxMBConvUTF16BE - #define wxMBConvUTF16straight wxMBConvUTF16LE -#endif - -/* static */ -size_t wxMBConvUTF16Base::GetLength(const char *src, size_t srcLen) -{ - if ( srcLen == wxNO_LEN ) - { - // count the number of bytes in input, including the trailing NULs - const wxUint16 *inBuff = wx_reinterpret_cast(const wxUint16 *, src); - for ( srcLen = 1; *inBuff++; srcLen++ ) - ; - - srcLen *= BYTES_PER_CHAR; - } - else // we already have the length - { - // we can only convert an entire number of UTF-16 characters - if ( srcLen % BYTES_PER_CHAR ) - return wxCONV_FAILED; - } - - return srcLen; -} - -// case when in-memory representation is UTF-16 too -#ifdef WC_UTF16 - -// ---------------------------------------------------------------------------- -// conversions without endianness change -// ---------------------------------------------------------------------------- - -size_t -wxMBConvUTF16straight::ToWChar(wchar_t *dst, size_t dstLen, - const char *src, size_t srcLen) const -{ - // set up the scene for using memcpy() (which is presumably more efficient - // than copying the bytes one by one) - srcLen = GetLength(src, srcLen); - if ( srcLen == wxNO_LEN ) - return wxCONV_FAILED; - - const size_t inLen = srcLen / BYTES_PER_CHAR; - if ( dst ) - { - if ( dstLen < inLen ) - return wxCONV_FAILED; - - memcpy(dst, src, srcLen); - } - - return inLen; -} - -size_t -wxMBConvUTF16straight::FromWChar(char *dst, size_t dstLen, - const wchar_t *src, size_t srcLen) const -{ - if ( srcLen == wxNO_LEN ) - srcLen = wxWcslen(src) + 1; - - srcLen *= BYTES_PER_CHAR; - - if ( dst ) - { - if ( dstLen < srcLen ) - return wxCONV_FAILED; - - memcpy(dst, src, srcLen); - } - - return srcLen; -} - -// ---------------------------------------------------------------------------- -// endian-reversing conversions -// ---------------------------------------------------------------------------- - -size_t -wxMBConvUTF16swap::ToWChar(wchar_t *dst, size_t dstLen, - const char *src, size_t srcLen) const -{ - srcLen = GetLength(src, srcLen); - if ( srcLen == wxNO_LEN ) - return wxCONV_FAILED; - - srcLen /= BYTES_PER_CHAR; - - if ( dst ) - { - if ( dstLen < srcLen ) - return wxCONV_FAILED; - - const wxUint16 *inBuff = wx_reinterpret_cast(const wxUint16 *, src); - for ( size_t n = 0; n < srcLen; n++, inBuff++ ) - { - *dst++ = wxUINT16_SWAP_ALWAYS(*inBuff); - } - } - - return srcLen; -} - -size_t -wxMBConvUTF16swap::FromWChar(char *dst, size_t dstLen, - const wchar_t *src, size_t srcLen) const -{ - if ( srcLen == wxNO_LEN ) - srcLen = wxWcslen(src) + 1; - - srcLen *= BYTES_PER_CHAR; - - if ( dst ) - { - if ( dstLen < srcLen ) - return wxCONV_FAILED; - - wxUint16 *outBuff = wx_reinterpret_cast(wxUint16 *, dst); - for ( size_t n = 0; n < srcLen; n += BYTES_PER_CHAR, src++ ) - { - *outBuff++ = wxUINT16_SWAP_ALWAYS(*src); - } - } - - return srcLen; -} - -#else // !WC_UTF16: wchar_t is UTF-32 - -// ---------------------------------------------------------------------------- -// conversions without endianness change -// ---------------------------------------------------------------------------- - -size_t -wxMBConvUTF16straight::ToWChar(wchar_t *dst, size_t dstLen, - const char *src, size_t srcLen) const -{ - srcLen = GetLength(src, srcLen); - if ( srcLen == wxNO_LEN ) - return wxCONV_FAILED; - - const size_t inLen = srcLen / BYTES_PER_CHAR; - if ( !dst ) - { - // optimization: return maximal space which could be needed for this - // string even if the real size could be smaller if the buffer contains - // any surrogates - return inLen; - } - - size_t outLen = 0; - const wxUint16 *inBuff = wx_reinterpret_cast(const wxUint16 *, src); - for ( const wxUint16 * const inEnd = inBuff + inLen; inBuff < inEnd; ) - { - const wxUint32 ch = wxDecodeSurrogate(&inBuff); - if ( !inBuff ) - return wxCONV_FAILED; - - if ( ++outLen > dstLen ) - return wxCONV_FAILED; - - *dst++ = ch; - } - - - return outLen; -} - -size_t -wxMBConvUTF16straight::FromWChar(char *dst, size_t dstLen, - const wchar_t *src, size_t srcLen) const -{ - if ( srcLen == wxNO_LEN ) - srcLen = wxWcslen(src) + 1; - - size_t outLen = 0; - wxUint16 *outBuff = wx_reinterpret_cast(wxUint16 *, dst); - for ( size_t n = 0; n < srcLen; n++ ) - { - wxUint16 cc[2]; - const size_t numChars = encode_utf16(*src++, cc); - if ( numChars == wxCONV_FAILED ) - return wxCONV_FAILED; - - outLen += numChars * BYTES_PER_CHAR; - if ( outBuff ) - { - if ( outLen > dstLen ) - return wxCONV_FAILED; - - *outBuff++ = cc[0]; - if ( numChars == 2 ) - { - // second character of a surrogate - *outBuff++ = cc[1]; - } - } - } - - return outLen; -} - -// ---------------------------------------------------------------------------- -// endian-reversing conversions -// ---------------------------------------------------------------------------- - -size_t -wxMBConvUTF16swap::ToWChar(wchar_t *dst, size_t dstLen, - const char *src, size_t srcLen) const -{ - srcLen = GetLength(src, srcLen); - if ( srcLen == wxNO_LEN ) - return wxCONV_FAILED; - - const size_t inLen = srcLen / BYTES_PER_CHAR; - if ( !dst ) - { - // optimization: return maximal space which could be needed for this - // string even if the real size could be smaller if the buffer contains - // any surrogates - return inLen; - } - - size_t outLen = 0; - const wxUint16 *inBuff = wx_reinterpret_cast(const wxUint16 *, src); - for ( const wxUint16 * const inEnd = inBuff + inLen; inBuff < inEnd; ) - { - wxUint32 ch; - wxUint16 tmp[2]; - - tmp[0] = wxUINT16_SWAP_ALWAYS(*inBuff); - inBuff++; - tmp[1] = wxUINT16_SWAP_ALWAYS(*inBuff); - - const size_t numChars = decode_utf16(tmp, ch); - if ( numChars == wxCONV_FAILED ) - return wxCONV_FAILED; - - if ( numChars == 2 ) - inBuff++; - - if ( ++outLen > dstLen ) - return wxCONV_FAILED; - - *dst++ = ch; - } - - - return outLen; -} - -size_t -wxMBConvUTF16swap::FromWChar(char *dst, size_t dstLen, - const wchar_t *src, size_t srcLen) const -{ - if ( srcLen == wxNO_LEN ) - srcLen = wxWcslen(src) + 1; - - size_t outLen = 0; - wxUint16 *outBuff = wx_reinterpret_cast(wxUint16 *, dst); - for ( const wchar_t *srcEnd = src + srcLen; src < srcEnd; src++ ) - { - wxUint16 cc[2]; - const size_t numChars = encode_utf16(*src, cc); - if ( numChars == wxCONV_FAILED ) - return wxCONV_FAILED; - - outLen += numChars * BYTES_PER_CHAR; - if ( outBuff ) - { - if ( outLen > dstLen ) - return wxCONV_FAILED; - - *outBuff++ = wxUINT16_SWAP_ALWAYS(cc[0]); - if ( numChars == 2 ) - { - // second character of a surrogate - *outBuff++ = wxUINT16_SWAP_ALWAYS(cc[1]); - } - } - } - - return outLen; -} - -#endif // WC_UTF16/!WC_UTF16 - - -// ============================================================================ -// UTF-32 -// ============================================================================ - -#ifdef WORDS_BIGENDIAN - #define wxMBConvUTF32straight wxMBConvUTF32BE - #define wxMBConvUTF32swap wxMBConvUTF32LE -#else - #define wxMBConvUTF32swap wxMBConvUTF32BE - #define wxMBConvUTF32straight wxMBConvUTF32LE -#endif - - -WXDLLIMPEXP_DATA_BASE(wxMBConvUTF32LE) wxConvUTF32LE; -WXDLLIMPEXP_DATA_BASE(wxMBConvUTF32BE) wxConvUTF32BE; - -/* static */ -size_t wxMBConvUTF32Base::GetLength(const char *src, size_t srcLen) -{ - if ( srcLen == wxNO_LEN ) - { - // count the number of bytes in input, including the trailing NULs - const wxUint32 *inBuff = wx_reinterpret_cast(const wxUint32 *, src); - for ( srcLen = 1; *inBuff++; srcLen++ ) - ; - - srcLen *= BYTES_PER_CHAR; - } - else // we already have the length - { - // we can only convert an entire number of UTF-32 characters - if ( srcLen % BYTES_PER_CHAR ) - return wxCONV_FAILED; - } - - return srcLen; -} - -// case when in-memory representation is UTF-16 -#ifdef WC_UTF16 - -// ---------------------------------------------------------------------------- -// conversions without endianness change -// ---------------------------------------------------------------------------- - -size_t -wxMBConvUTF32straight::ToWChar(wchar_t *dst, size_t dstLen, - const char *src, size_t srcLen) const -{ - srcLen = GetLength(src, srcLen); - if ( srcLen == wxNO_LEN ) - return wxCONV_FAILED; - - const wxUint32 *inBuff = wx_reinterpret_cast(const wxUint32 *, src); - const size_t inLen = srcLen / BYTES_PER_CHAR; - size_t outLen = 0; - for ( size_t n = 0; n < inLen; n++ ) - { - wxUint16 cc[2]; - const size_t numChars = encode_utf16(*inBuff++, cc); - if ( numChars == wxCONV_FAILED ) - return wxCONV_FAILED; - - outLen += numChars; - if ( dst ) - { - if ( outLen > dstLen ) - return wxCONV_FAILED; - - *dst++ = cc[0]; - if ( numChars == 2 ) - { - // second character of a surrogate - *dst++ = cc[1]; - } - } - } - - return outLen; -} - -size_t -wxMBConvUTF32straight::FromWChar(char *dst, size_t dstLen, - const wchar_t *src, size_t srcLen) const -{ - if ( srcLen == wxNO_LEN ) - srcLen = wxWcslen(src) + 1; - - if ( !dst ) - { - // optimization: return maximal space which could be needed for this - // string instead of the exact amount which could be less if there are - // any surrogates in the input - // - // we consider that surrogates are rare enough to make it worthwhile to - // avoid running the loop below at the cost of slightly extra memory - // consumption - return srcLen * BYTES_PER_CHAR; - } - - wxUint32 *outBuff = wx_reinterpret_cast(wxUint32 *, dst); - size_t outLen = 0; - for ( const wchar_t * const srcEnd = src + srcLen; src < srcEnd; ) - { - const wxUint32 ch = wxDecodeSurrogate(&src); - if ( !src ) - return wxCONV_FAILED; - - outLen += BYTES_PER_CHAR; - - if ( outLen > dstLen ) - return wxCONV_FAILED; - - *outBuff++ = ch; - } - - return outLen; -} - -// ---------------------------------------------------------------------------- -// endian-reversing conversions -// ---------------------------------------------------------------------------- - -size_t -wxMBConvUTF32swap::ToWChar(wchar_t *dst, size_t dstLen, - const char *src, size_t srcLen) const -{ - srcLen = GetLength(src, srcLen); - if ( srcLen == wxNO_LEN ) - return wxCONV_FAILED; - - const wxUint32 *inBuff = wx_reinterpret_cast(const wxUint32 *, src); - const size_t inLen = srcLen / BYTES_PER_CHAR; - size_t outLen = 0; - for ( size_t n = 0; n < inLen; n++, inBuff++ ) - { - wxUint16 cc[2]; - const size_t numChars = encode_utf16(wxUINT32_SWAP_ALWAYS(*inBuff), cc); - if ( numChars == wxCONV_FAILED ) - return wxCONV_FAILED; - - outLen += numChars; - if ( dst ) - { - if ( outLen > dstLen ) - return wxCONV_FAILED; - - *dst++ = cc[0]; - if ( numChars == 2 ) - { - // second character of a surrogate - *dst++ = cc[1]; - } - } - } - - return outLen; -} - -size_t -wxMBConvUTF32swap::FromWChar(char *dst, size_t dstLen, - const wchar_t *src, size_t srcLen) const -{ - if ( srcLen == wxNO_LEN ) - srcLen = wxWcslen(src) + 1; - - if ( !dst ) - { - // optimization: return maximal space which could be needed for this - // string instead of the exact amount which could be less if there are - // any surrogates in the input - // - // we consider that surrogates are rare enough to make it worthwhile to - // avoid running the loop below at the cost of slightly extra memory - // consumption - return srcLen*BYTES_PER_CHAR; - } - - wxUint32 *outBuff = wx_reinterpret_cast(wxUint32 *, dst); - size_t outLen = 0; - for ( const wchar_t * const srcEnd = src + srcLen; src < srcEnd; ) - { - const wxUint32 ch = wxDecodeSurrogate(&src); - if ( !src ) - return wxCONV_FAILED; - - outLen += BYTES_PER_CHAR; - - if ( outLen > dstLen ) - return wxCONV_FAILED; - - *outBuff++ = wxUINT32_SWAP_ALWAYS(ch); - } - - return outLen; -} - -#else // !WC_UTF16: wchar_t is UTF-32 - -// ---------------------------------------------------------------------------- -// conversions without endianness change -// ---------------------------------------------------------------------------- - -size_t -wxMBConvUTF32straight::ToWChar(wchar_t *dst, size_t dstLen, - const char *src, size_t srcLen) const -{ - // use memcpy() as it should be much faster than hand-written loop - srcLen = GetLength(src, srcLen); - if ( srcLen == wxNO_LEN ) - return wxCONV_FAILED; - - const size_t inLen = srcLen/BYTES_PER_CHAR; - if ( dst ) - { - if ( dstLen < inLen ) - return wxCONV_FAILED; - - memcpy(dst, src, srcLen); - } - - return inLen; -} - -size_t -wxMBConvUTF32straight::FromWChar(char *dst, size_t dstLen, - const wchar_t *src, size_t srcLen) const -{ - if ( srcLen == wxNO_LEN ) - srcLen = wxWcslen(src) + 1; - - srcLen *= BYTES_PER_CHAR; - - if ( dst ) - { - if ( dstLen < srcLen ) - return wxCONV_FAILED; - - memcpy(dst, src, srcLen); - } - - return srcLen; -} - -// ---------------------------------------------------------------------------- -// endian-reversing conversions -// ---------------------------------------------------------------------------- - -size_t -wxMBConvUTF32swap::ToWChar(wchar_t *dst, size_t dstLen, - const char *src, size_t srcLen) const -{ - srcLen = GetLength(src, srcLen); - if ( srcLen == wxNO_LEN ) - return wxCONV_FAILED; - - srcLen /= BYTES_PER_CHAR; - - if ( dst ) - { - if ( dstLen < srcLen ) - return wxCONV_FAILED; - - const wxUint32 *inBuff = wx_reinterpret_cast(const wxUint32 *, src); - for ( size_t n = 0; n < srcLen; n++, inBuff++ ) - { - *dst++ = wxUINT32_SWAP_ALWAYS(*inBuff); - } - } - - return srcLen; -} - -size_t -wxMBConvUTF32swap::FromWChar(char *dst, size_t dstLen, - const wchar_t *src, size_t srcLen) const -{ - if ( srcLen == wxNO_LEN ) - srcLen = wxWcslen(src) + 1; - - srcLen *= BYTES_PER_CHAR; - - if ( dst ) - { - if ( dstLen < srcLen ) - return wxCONV_FAILED; - - wxUint32 *outBuff = wx_reinterpret_cast(wxUint32 *, dst); - for ( size_t n = 0; n < srcLen; n += BYTES_PER_CHAR, src++ ) - { - *outBuff++ = wxUINT32_SWAP_ALWAYS(*src); - } - } - - return srcLen; -} - -#endif // WC_UTF16/!WC_UTF16 - - -// ============================================================================ -// The classes doing conversion using the iconv_xxx() functions -// ============================================================================ - -#ifdef HAVE_ICONV - -// VS: glibc 2.1.3 is broken in that iconv() conversion to/from UCS4 fails with -// E2BIG if output buffer is _exactly_ as big as needed. Such case is -// (unless there's yet another bug in glibc) the only case when iconv() -// returns with (size_t)-1 (which means error) and says there are 0 bytes -// left in the input buffer -- when _real_ error occurs, -// bytes-left-in-input buffer is non-zero. Hence, this alternative test for -// iconv() failure. -// [This bug does not appear in glibc 2.2.] -#if defined(__GLIBC__) && __GLIBC__ == 2 && __GLIBC_MINOR__ <= 1 -#define ICONV_FAILED(cres, bufLeft) ((cres == (size_t)-1) && \ - (errno != E2BIG || bufLeft != 0)) -#else -#define ICONV_FAILED(cres, bufLeft) (cres == (size_t)-1) -#endif - -#define ICONV_CHAR_CAST(x) ((ICONV_CONST char **)(x)) - -#define ICONV_T_INVALID ((iconv_t)-1) - -#if SIZEOF_WCHAR_T == 4 - #define WC_BSWAP wxUINT32_SWAP_ALWAYS - #define WC_ENC wxFONTENCODING_UTF32 -#elif SIZEOF_WCHAR_T == 2 - #define WC_BSWAP wxUINT16_SWAP_ALWAYS - #define WC_ENC wxFONTENCODING_UTF16 -#else // sizeof(wchar_t) != 2 nor 4 - // does this ever happen? - #error "Unknown sizeof(wchar_t): please report this to wx-dev@lists.wxwindows.org" -#endif - -// ---------------------------------------------------------------------------- -// wxMBConv_iconv: encapsulates an iconv character set -// ---------------------------------------------------------------------------- - -class wxMBConv_iconv : public wxMBConv -{ -public: - wxMBConv_iconv(const wxChar *name); - virtual ~wxMBConv_iconv(); - - virtual size_t MB2WC(wchar_t *buf, const char *psz, size_t n) const; - virtual size_t WC2MB(char *buf, const wchar_t *psz, size_t n) const; - - // classify this encoding as explained in wxMBConv::GetMBNulLen() comment - virtual size_t GetMBNulLen() const; - - virtual wxMBConv *Clone() const - { - wxMBConv_iconv *p = new wxMBConv_iconv(m_name); - p->m_minMBCharWidth = m_minMBCharWidth; - return p; - } - - bool IsOk() const - { return (m2w != ICONV_T_INVALID) && (w2m != ICONV_T_INVALID); } - -protected: - // the iconv handlers used to translate from multibyte - // to wide char and in the other direction - iconv_t m2w, - w2m; - -#if wxUSE_THREADS - // guards access to m2w and w2m objects - wxMutex m_iconvMutex; -#endif - -private: - // the name (for iconv_open()) of a wide char charset -- if none is - // available on this machine, it will remain NULL - static wxString ms_wcCharsetName; - - // true if the wide char encoding we use (i.e. ms_wcCharsetName) has - // different endian-ness than the native one - static bool ms_wcNeedsSwap; - - - // name of the encoding handled by this conversion - wxString m_name; - - // cached result of GetMBNulLen(); set to 0 meaning "unknown" - // initially - size_t m_minMBCharWidth; -}; - -// make the constructor available for unit testing -WXDLLIMPEXP_BASE wxMBConv* new_wxMBConv_iconv( const wxChar* name ) -{ - wxMBConv_iconv* result = new wxMBConv_iconv( name ); - if ( !result->IsOk() ) - { - delete result; - return 0; - } - - return result; -} - -wxString wxMBConv_iconv::ms_wcCharsetName; -bool wxMBConv_iconv::ms_wcNeedsSwap = false; - -wxMBConv_iconv::wxMBConv_iconv(const wxChar *name) - : m_name(name) -{ - m_minMBCharWidth = 0; - - // iconv operates with chars, not wxChars, but luckily it uses only ASCII - // names for the charsets - const wxCharBuffer cname(wxString(name).ToAscii()); - - // check for charset that represents wchar_t: - if ( ms_wcCharsetName.empty() ) - { - wxLogTrace(TRACE_STRCONV, _T("Looking for wide char codeset:")); - -#if wxUSE_FONTMAP - const wxChar **names = wxFontMapperBase::GetAllEncodingNames(WC_ENC); -#else // !wxUSE_FONTMAP - static const wxChar *names_static[] = - { -#if SIZEOF_WCHAR_T == 4 - _T("UCS-4"), -#elif SIZEOF_WCHAR_T = 2 - _T("UCS-2"), -#endif - NULL - }; - const wxChar **names = names_static; -#endif // wxUSE_FONTMAP/!wxUSE_FONTMAP - - for ( ; *names && ms_wcCharsetName.empty(); ++names ) - { - const wxString nameCS(*names); - - // first try charset with explicit bytesex info (e.g. "UCS-4LE"): - wxString nameXE(nameCS); - -#ifdef WORDS_BIGENDIAN - nameXE += _T("BE"); -#else // little endian - nameXE += _T("LE"); -#endif - - wxLogTrace(TRACE_STRCONV, _T(" trying charset \"%s\""), - nameXE.c_str()); - - m2w = iconv_open(nameXE.ToAscii(), cname); - if ( m2w == ICONV_T_INVALID ) - { - // try charset w/o bytesex info (e.g. "UCS4") - wxLogTrace(TRACE_STRCONV, _T(" trying charset \"%s\""), - nameCS.c_str()); - m2w = iconv_open(nameCS.ToAscii(), cname); - - // and check for bytesex ourselves: - if ( m2w != ICONV_T_INVALID ) - { - char buf[2], *bufPtr; - wchar_t wbuf[2], *wbufPtr; - size_t insz, outsz; - size_t res; - - buf[0] = 'A'; - buf[1] = 0; - wbuf[0] = 0; - insz = 2; - outsz = SIZEOF_WCHAR_T * 2; - wbufPtr = wbuf; - bufPtr = buf; - - res = iconv( - m2w, ICONV_CHAR_CAST(&bufPtr), &insz, - (char**)&wbufPtr, &outsz); - - if (ICONV_FAILED(res, insz)) - { - wxLogLastError(wxT("iconv")); - wxLogError(_("Conversion to charset '%s' doesn't work."), - nameCS.c_str()); - } - else // ok, can convert to this encoding, remember it - { - ms_wcCharsetName = nameCS; - ms_wcNeedsSwap = wbuf[0] != (wchar_t)buf[0]; - } - } - } - else // use charset not requiring byte swapping - { - ms_wcCharsetName = nameXE; - } - } - - wxLogTrace(TRACE_STRCONV, - wxT("iconv wchar_t charset is \"%s\"%s"), - ms_wcCharsetName.empty() ? _T("") - : ms_wcCharsetName.c_str(), - ms_wcNeedsSwap ? _T(" (needs swap)") - : _T("")); - } - else // we already have ms_wcCharsetName - { - m2w = iconv_open(ms_wcCharsetName.ToAscii(), cname); - } - - if ( ms_wcCharsetName.empty() ) - { - w2m = ICONV_T_INVALID; - } - else - { - w2m = iconv_open(cname, ms_wcCharsetName.ToAscii()); - if ( w2m == ICONV_T_INVALID ) - { - wxLogTrace(TRACE_STRCONV, - wxT("\"%s\" -> \"%s\" works but not the converse!?"), - ms_wcCharsetName.c_str(), cname.data()); - } - } -} - -wxMBConv_iconv::~wxMBConv_iconv() -{ - if ( m2w != ICONV_T_INVALID ) - iconv_close(m2w); - if ( w2m != ICONV_T_INVALID ) - iconv_close(w2m); -} - -size_t wxMBConv_iconv::MB2WC(wchar_t *buf, const char *psz, size_t n) const -{ - // find the string length: notice that must be done differently for - // NUL-terminated strings and UTF-16/32 which are terminated with 2/4 NULs - size_t inbuf; - const size_t nulLen = GetMBNulLen(); - switch ( nulLen ) - { - default: - return wxCONV_FAILED; - - case 1: - inbuf = strlen(psz); // arguably more optimized than our version - break; - - case 2: - case 4: - // for UTF-16/32 not only we need to have 2/4 consecutive NULs but - // they also have to start at character boundary and not span two - // adjacent characters - const char *p; - for ( p = psz; NotAllNULs(p, nulLen); p += nulLen ) - ; - inbuf = p - psz; - break; - } - -#if wxUSE_THREADS - // NB: iconv() is MT-safe, but each thread must use its own iconv_t handle. - // Unfortunately there are a couple of global wxCSConv objects such as - // wxConvLocal that are used all over wx code, so we have to make sure - // the handle is used by at most one thread at the time. Otherwise - // only a few wx classes would be safe to use from non-main threads - // as MB<->WC conversion would fail "randomly". - wxMutexLocker lock(wxConstCast(this, wxMBConv_iconv)->m_iconvMutex); -#endif // wxUSE_THREADS - - size_t outbuf = n * SIZEOF_WCHAR_T; - size_t res, cres; - // VS: Use these instead of psz, buf because iconv() modifies its arguments: - wchar_t *bufPtr = buf; - const char *pszPtr = psz; - - if (buf) - { - // have destination buffer, convert there - cres = iconv(m2w, - ICONV_CHAR_CAST(&pszPtr), &inbuf, - (char**)&bufPtr, &outbuf); - res = n - (outbuf / SIZEOF_WCHAR_T); - - if (ms_wcNeedsSwap) - { - // convert to native endianness - for ( unsigned i = 0; i < res; i++ ) - buf[n] = WC_BSWAP(buf[i]); - } - - // NUL-terminate the string if there is any space left - if (res < n) - buf[res] = 0; - } - else - { - // no destination buffer... convert using temp buffer - // to calculate destination buffer requirement - wchar_t tbuf[8]; - res = 0; - - do - { - bufPtr = tbuf; - outbuf = 8 * SIZEOF_WCHAR_T; - - cres = iconv(m2w, - ICONV_CHAR_CAST(&pszPtr), &inbuf, - (char**)&bufPtr, &outbuf ); - - res += 8 - (outbuf / SIZEOF_WCHAR_T); - } - while ((cres == (size_t)-1) && (errno == E2BIG)); - } - - if (ICONV_FAILED(cres, inbuf)) - { - //VS: it is ok if iconv fails, hence trace only - wxLogTrace(TRACE_STRCONV, wxT("iconv failed: %s"), wxSysErrorMsg(wxSysErrorCode())); - return wxCONV_FAILED; - } - - return res; -} - -size_t wxMBConv_iconv::WC2MB(char *buf, const wchar_t *psz, size_t n) const -{ -#if wxUSE_THREADS - // NB: explained in MB2WC - wxMutexLocker lock(wxConstCast(this, wxMBConv_iconv)->m_iconvMutex); -#endif - - size_t inlen = wxWcslen(psz); - size_t inbuf = inlen * SIZEOF_WCHAR_T; - size_t outbuf = n; - size_t res, cres; - - wchar_t *tmpbuf = 0; - - if (ms_wcNeedsSwap) - { - // need to copy to temp buffer to switch endianness - // (doing WC_BSWAP twice on the original buffer won't help, as it - // could be in read-only memory, or be accessed in some other thread) - tmpbuf = (wchar_t *)malloc(inbuf + SIZEOF_WCHAR_T); - for ( size_t i = 0; i < inlen; i++ ) - tmpbuf[n] = WC_BSWAP(psz[i]); - - tmpbuf[inlen] = L'\0'; - psz = tmpbuf; - } - - if (buf) - { - // have destination buffer, convert there - cres = iconv( w2m, ICONV_CHAR_CAST(&psz), &inbuf, &buf, &outbuf ); - - res = n - outbuf; - - // NB: iconv was given only wcslen(psz) characters on input, and so - // it couldn't convert the trailing zero. Let's do it ourselves - // if there's some room left for it in the output buffer. - if (res < n) - buf[0] = 0; - } - else - { - // no destination buffer: convert using temp buffer - // to calculate destination buffer requirement - char tbuf[16]; - res = 0; - do - { - buf = tbuf; - outbuf = 16; - - cres = iconv( w2m, ICONV_CHAR_CAST(&psz), &inbuf, &buf, &outbuf ); - - res += 16 - outbuf; - } - while ((cres == (size_t)-1) && (errno == E2BIG)); - } - - if (ms_wcNeedsSwap) - { - free(tmpbuf); - } - - if (ICONV_FAILED(cres, inbuf)) - { - wxLogTrace(TRACE_STRCONV, wxT("iconv failed: %s"), wxSysErrorMsg(wxSysErrorCode())); - return wxCONV_FAILED; - } - - return res; -} - -size_t wxMBConv_iconv::GetMBNulLen() const -{ - if ( m_minMBCharWidth == 0 ) - { - wxMBConv_iconv * const self = wxConstCast(this, wxMBConv_iconv); - -#if wxUSE_THREADS - // NB: explained in MB2WC - wxMutexLocker lock(self->m_iconvMutex); -#endif - - wchar_t *wnul = L""; - char buf[8]; // should be enough for NUL in any encoding - size_t inLen = sizeof(wchar_t), - outLen = WXSIZEOF(buf); - char *inBuff = (char *)wnul; - char *outBuff = buf; - if ( iconv(w2m, ICONV_CHAR_CAST(&inBuff), &inLen, &outBuff, &outLen) == (size_t)-1 ) - { - self->m_minMBCharWidth = (size_t)-1; - } - else // ok - { - self->m_minMBCharWidth = outBuff - buf; - } - } - - return m_minMBCharWidth; -} - -#endif // HAVE_ICONV - - -// ============================================================================ -// Win32 conversion classes -// ============================================================================ - -#ifdef wxHAVE_WIN32_MB2WC - -// from utils.cpp -#if wxUSE_FONTMAP -extern WXDLLIMPEXP_BASE long wxCharsetToCodepage(const wxChar *charset); -extern WXDLLIMPEXP_BASE long wxEncodingToCodepage(wxFontEncoding encoding); -#endif - -class wxMBConv_win32 : public wxMBConv -{ -public: - wxMBConv_win32() - { - m_CodePage = CP_ACP; - m_minMBCharWidth = 0; - } - - wxMBConv_win32(const wxMBConv_win32& conv) - : wxMBConv() - { - m_CodePage = conv.m_CodePage; - m_minMBCharWidth = conv.m_minMBCharWidth; - } - -#if wxUSE_FONTMAP - wxMBConv_win32(const wxChar* name) - { - m_CodePage = wxCharsetToCodepage(name); - m_minMBCharWidth = 0; - } - - wxMBConv_win32(wxFontEncoding encoding) - { - m_CodePage = wxEncodingToCodepage(encoding); - m_minMBCharWidth = 0; - } -#endif // wxUSE_FONTMAP - - virtual size_t MB2WC(wchar_t *buf, const char *psz, size_t n) const - { - // note that we have to use MB_ERR_INVALID_CHARS flag as it without it - // the behaviour is not compatible with the Unix version (using iconv) - // and break the library itself, e.g. wxTextInputStream::NextChar() - // wouldn't work if reading an incomplete MB char didn't result in an - // error - // - // Moreover, MB_ERR_INVALID_CHARS is only supported on Win 2K SP4 or - // Win XP or newer and it is not supported for UTF-[78] so we always - // use our own conversions in this case. See - // http://blogs.msdn.com/michkap/archive/2005/04/19/409566.aspx - // http://msdn.microsoft.com/library/en-us/intl/unicode_17si.asp - if ( m_CodePage == CP_UTF8 ) - { - return wxConvUTF8.MB2WC(buf, psz, n); - } - - if ( m_CodePage == CP_UTF7 ) - { - return wxConvUTF7.MB2WC(buf, psz, n); - } - - int flags = 0; - if ( (m_CodePage < 50000 && m_CodePage != CP_SYMBOL) && - IsAtLeastWin2kSP4() ) - { - flags = MB_ERR_INVALID_CHARS; - } - - const size_t len = ::MultiByteToWideChar - ( - m_CodePage, // code page - flags, // flags: fall on error - psz, // input string - -1, // its length (NUL-terminated) - buf, // output string - buf ? n : 0 // size of output buffer - ); - if ( !len ) - { - // function totally failed - return wxCONV_FAILED; - } - - // if we were really converting and didn't use MB_ERR_INVALID_CHARS, - // check if we succeeded, by doing a double trip: - if ( !flags && buf ) - { - const size_t mbLen = strlen(psz); - wxCharBuffer mbBuf(mbLen); - if ( ::WideCharToMultiByte - ( - m_CodePage, - 0, - buf, - -1, - mbBuf.data(), - mbLen + 1, // size in bytes, not length - NULL, - NULL - ) == 0 || - strcmp(mbBuf, psz) != 0 ) - { - // we didn't obtain the same thing we started from, hence - // the conversion was lossy and we consider that it failed - return wxCONV_FAILED; - } - } - - // note that it returns count of written chars for buf != NULL and size - // of the needed buffer for buf == NULL so in either case the length of - // the string (which never includes the terminating NUL) is one less - return len - 1; - } - - virtual size_t WC2MB(char *buf, const wchar_t *pwz, size_t n) const - { - /* - we have a problem here: by default, WideCharToMultiByte() may - replace characters unrepresentable in the target code page with bad - quality approximations such as turning "1/2" symbol (U+00BD) into - "1" for the code pages which don't have it and we, obviously, want - to avoid this at any price - - the trouble is that this function does it _silently_, i.e. it won't - even tell us whether it did or not... Win98/2000 and higher provide - WC_NO_BEST_FIT_CHARS but it doesn't work for the older systems and - we have to resort to a round trip, i.e. check that converting back - results in the same string -- this is, of course, expensive but - otherwise we simply can't be sure to not garble the data. - */ - - // determine if we can rely on WC_NO_BEST_FIT_CHARS: according to MSDN - // it doesn't work with CJK encodings (which we test for rather roughly - // here...) nor with UTF-7/8 nor, of course, with Windows versions not - // supporting it - BOOL usedDef wxDUMMY_INITIALIZE(false); - BOOL *pUsedDef; - int flags; - if ( CanUseNoBestFit() && m_CodePage < 50000 ) - { - // it's our lucky day - flags = WC_NO_BEST_FIT_CHARS; - pUsedDef = &usedDef; - } - else // old system or unsupported encoding - { - flags = 0; - pUsedDef = NULL; - } - - const size_t len = ::WideCharToMultiByte - ( - m_CodePage, // code page - flags, // either none or no best fit - pwz, // input string - -1, // it is (wide) NUL-terminated - buf, // output buffer - buf ? n : 0, // and its size - NULL, // default "replacement" char - pUsedDef // [out] was it used? - ); - - if ( !len ) - { - // function totally failed - return wxCONV_FAILED; - } - - // if we were really converting, check if we succeeded - if ( buf ) - { - if ( flags ) - { - // check if the conversion failed, i.e. if any replacements - // were done - if ( usedDef ) - return wxCONV_FAILED; - } - else // we must resort to double tripping... - { - wxWCharBuffer wcBuf(n); - if ( MB2WC(wcBuf.data(), buf, n) == wxCONV_FAILED || - wcscmp(wcBuf, pwz) != 0 ) - { - // we didn't obtain the same thing we started from, hence - // the conversion was lossy and we consider that it failed - return wxCONV_FAILED; - } - } - } - - // see the comment above for the reason of "len - 1" - return len - 1; - } - - virtual size_t GetMBNulLen() const - { - if ( m_minMBCharWidth == 0 ) - { - int len = ::WideCharToMultiByte - ( - m_CodePage, // code page - 0, // no flags - L"", // input string - 1, // translate just the NUL - NULL, // output buffer - 0, // and its size - NULL, // no replacement char - NULL // [out] don't care if it was used - ); - - wxMBConv_win32 * const self = wxConstCast(this, wxMBConv_win32); - switch ( len ) - { - default: - wxLogDebug(_T("Unexpected NUL length %d"), len); - self->m_minMBCharWidth = (size_t)-1; - break; - - case 0: - self->m_minMBCharWidth = (size_t)-1; - break; - - case 1: - case 2: - case 4: - self->m_minMBCharWidth = len; - break; - } - } - - return m_minMBCharWidth; - } - - virtual wxMBConv *Clone() const { return new wxMBConv_win32(*this); } - - bool IsOk() const { return m_CodePage != -1; } - -private: - static bool CanUseNoBestFit() - { - static int s_isWin98Or2k = -1; - - if ( s_isWin98Or2k == -1 ) - { - int verMaj, verMin; - switch ( wxGetOsVersion(&verMaj, &verMin) ) - { - case wxOS_WINDOWS_9X: - s_isWin98Or2k = verMaj >= 4 && verMin >= 10; - break; - - case wxOS_WINDOWS_NT: - s_isWin98Or2k = verMaj >= 5; - break; - - default: - // unknown: be conservative by default - s_isWin98Or2k = 0; - break; - } - - wxASSERT_MSG( s_isWin98Or2k != -1, _T("should be set above") ); - } - - return s_isWin98Or2k == 1; - } - - static bool IsAtLeastWin2kSP4() - { -#ifdef __WXWINCE__ - return false; -#else - static int s_isAtLeastWin2kSP4 = -1; - - if ( s_isAtLeastWin2kSP4 == -1 ) - { - OSVERSIONINFOEX ver; - - memset(&ver, 0, sizeof(ver)); - ver.dwOSVersionInfoSize = sizeof(ver); - GetVersionEx((OSVERSIONINFO*)&ver); - - s_isAtLeastWin2kSP4 = - ((ver.dwMajorVersion > 5) || // Vista+ - (ver.dwMajorVersion == 5 && ver.dwMinorVersion > 0) || // XP/2003 - (ver.dwMajorVersion == 5 && ver.dwMinorVersion == 0 && - ver.wServicePackMajor >= 4)) // 2000 SP4+ - ? 1 : 0; - } - - return s_isAtLeastWin2kSP4 == 1; -#endif - } - - - // the code page we're working with - long m_CodePage; - - // cached result of GetMBNulLen(), set to 0 initially meaning - // "unknown" - size_t m_minMBCharWidth; -}; - -#endif // wxHAVE_WIN32_MB2WC - -// ============================================================================ -// Cocoa conversion classes -// ============================================================================ - -#if defined(__WXCOCOA__) - -// RN: There is no UTF-32 support in either Core Foundation or Cocoa. -// Strangely enough, internally Core Foundation uses -// UTF-32 internally quite a bit - its just not public (yet). - -#include -#include - -CFStringEncoding wxCFStringEncFromFontEnc(wxFontEncoding encoding) -{ - CFStringEncoding enc = kCFStringEncodingInvalidId ; - - switch (encoding) - { - case wxFONTENCODING_DEFAULT : - enc = CFStringGetSystemEncoding(); - break ; - - case wxFONTENCODING_ISO8859_1 : - enc = kCFStringEncodingISOLatin1 ; - break ; - case wxFONTENCODING_ISO8859_2 : - enc = kCFStringEncodingISOLatin2; - break ; - case wxFONTENCODING_ISO8859_3 : - enc = kCFStringEncodingISOLatin3 ; - break ; - case wxFONTENCODING_ISO8859_4 : - enc = kCFStringEncodingISOLatin4; - break ; - case wxFONTENCODING_ISO8859_5 : - enc = kCFStringEncodingISOLatinCyrillic; - break ; - case wxFONTENCODING_ISO8859_6 : - enc = kCFStringEncodingISOLatinArabic; - break ; - case wxFONTENCODING_ISO8859_7 : - enc = kCFStringEncodingISOLatinGreek; - break ; - case wxFONTENCODING_ISO8859_8 : - enc = kCFStringEncodingISOLatinHebrew; - break ; - case wxFONTENCODING_ISO8859_9 : - enc = kCFStringEncodingISOLatin5; - break ; - case wxFONTENCODING_ISO8859_10 : - enc = kCFStringEncodingISOLatin6; - break ; - case wxFONTENCODING_ISO8859_11 : - enc = kCFStringEncodingISOLatinThai; - break ; - case wxFONTENCODING_ISO8859_13 : - enc = kCFStringEncodingISOLatin7; - break ; - case wxFONTENCODING_ISO8859_14 : - enc = kCFStringEncodingISOLatin8; - break ; - case wxFONTENCODING_ISO8859_15 : - enc = kCFStringEncodingISOLatin9; - break ; - - case wxFONTENCODING_KOI8 : - enc = kCFStringEncodingKOI8_R; - break ; - case wxFONTENCODING_ALTERNATIVE : // MS-DOS CP866 - enc = kCFStringEncodingDOSRussian; - break ; - -// case wxFONTENCODING_BULGARIAN : -// enc = ; -// break ; - - case wxFONTENCODING_CP437 : - enc = kCFStringEncodingDOSLatinUS ; - break ; - case wxFONTENCODING_CP850 : - enc = kCFStringEncodingDOSLatin1; - break ; - case wxFONTENCODING_CP852 : - enc = kCFStringEncodingDOSLatin2; - break ; - case wxFONTENCODING_CP855 : - enc = kCFStringEncodingDOSCyrillic; - break ; - case wxFONTENCODING_CP866 : - enc = kCFStringEncodingDOSRussian ; - break ; - case wxFONTENCODING_CP874 : - enc = kCFStringEncodingDOSThai; - break ; - case wxFONTENCODING_CP932 : - enc = kCFStringEncodingDOSJapanese; - break ; - case wxFONTENCODING_CP936 : - enc = kCFStringEncodingDOSChineseSimplif ; - break ; - case wxFONTENCODING_CP949 : - enc = kCFStringEncodingDOSKorean; - break ; - case wxFONTENCODING_CP950 : - enc = kCFStringEncodingDOSChineseTrad; - break ; - case wxFONTENCODING_CP1250 : - enc = kCFStringEncodingWindowsLatin2; - break ; - case wxFONTENCODING_CP1251 : - enc = kCFStringEncodingWindowsCyrillic ; - break ; - case wxFONTENCODING_CP1252 : - enc = kCFStringEncodingWindowsLatin1 ; - break ; - case wxFONTENCODING_CP1253 : - enc = kCFStringEncodingWindowsGreek; - break ; - case wxFONTENCODING_CP1254 : - enc = kCFStringEncodingWindowsLatin5; - break ; - case wxFONTENCODING_CP1255 : - enc = kCFStringEncodingWindowsHebrew ; - break ; - case wxFONTENCODING_CP1256 : - enc = kCFStringEncodingWindowsArabic ; - break ; - case wxFONTENCODING_CP1257 : - enc = kCFStringEncodingWindowsBalticRim; - break ; -// This only really encodes to UTF7 (if that) evidently -// case wxFONTENCODING_UTF7 : -// enc = kCFStringEncodingNonLossyASCII ; -// break ; - case wxFONTENCODING_UTF8 : - enc = kCFStringEncodingUTF8 ; - break ; - case wxFONTENCODING_EUC_JP : - enc = kCFStringEncodingEUC_JP; - break ; - case wxFONTENCODING_UTF16 : - enc = kCFStringEncodingUnicode ; - break ; - case wxFONTENCODING_MACROMAN : - enc = kCFStringEncodingMacRoman ; - break ; - case wxFONTENCODING_MACJAPANESE : - enc = kCFStringEncodingMacJapanese ; - break ; - case wxFONTENCODING_MACCHINESETRAD : - enc = kCFStringEncodingMacChineseTrad ; - break ; - case wxFONTENCODING_MACKOREAN : - enc = kCFStringEncodingMacKorean ; - break ; - case wxFONTENCODING_MACARABIC : - enc = kCFStringEncodingMacArabic ; - break ; - case wxFONTENCODING_MACHEBREW : - enc = kCFStringEncodingMacHebrew ; - break ; - case wxFONTENCODING_MACGREEK : - enc = kCFStringEncodingMacGreek ; - break ; - case wxFONTENCODING_MACCYRILLIC : - enc = kCFStringEncodingMacCyrillic ; - break ; - case wxFONTENCODING_MACDEVANAGARI : - enc = kCFStringEncodingMacDevanagari ; - break ; - case wxFONTENCODING_MACGURMUKHI : - enc = kCFStringEncodingMacGurmukhi ; - break ; - case wxFONTENCODING_MACGUJARATI : - enc = kCFStringEncodingMacGujarati ; - break ; - case wxFONTENCODING_MACORIYA : - enc = kCFStringEncodingMacOriya ; - break ; - case wxFONTENCODING_MACBENGALI : - enc = kCFStringEncodingMacBengali ; - break ; - case wxFONTENCODING_MACTAMIL : - enc = kCFStringEncodingMacTamil ; - break ; - case wxFONTENCODING_MACTELUGU : - enc = kCFStringEncodingMacTelugu ; - break ; - case wxFONTENCODING_MACKANNADA : - enc = kCFStringEncodingMacKannada ; - break ; - case wxFONTENCODING_MACMALAJALAM : - enc = kCFStringEncodingMacMalayalam ; - break ; - case wxFONTENCODING_MACSINHALESE : - enc = kCFStringEncodingMacSinhalese ; - break ; - case wxFONTENCODING_MACBURMESE : - enc = kCFStringEncodingMacBurmese ; - break ; - case wxFONTENCODING_MACKHMER : - enc = kCFStringEncodingMacKhmer ; - break ; - case wxFONTENCODING_MACTHAI : - enc = kCFStringEncodingMacThai ; - break ; - case wxFONTENCODING_MACLAOTIAN : - enc = kCFStringEncodingMacLaotian ; - break ; - case wxFONTENCODING_MACGEORGIAN : - enc = kCFStringEncodingMacGeorgian ; - break ; - case wxFONTENCODING_MACARMENIAN : - enc = kCFStringEncodingMacArmenian ; - break ; - case wxFONTENCODING_MACCHINESESIMP : - enc = kCFStringEncodingMacChineseSimp ; - break ; - case wxFONTENCODING_MACTIBETAN : - enc = kCFStringEncodingMacTibetan ; - break ; - case wxFONTENCODING_MACMONGOLIAN : - enc = kCFStringEncodingMacMongolian ; - break ; - case wxFONTENCODING_MACETHIOPIC : - enc = kCFStringEncodingMacEthiopic ; - break ; - case wxFONTENCODING_MACCENTRALEUR : - enc = kCFStringEncodingMacCentralEurRoman ; - break ; - case wxFONTENCODING_MACVIATNAMESE : - enc = kCFStringEncodingMacVietnamese ; - break ; - case wxFONTENCODING_MACARABICEXT : - enc = kCFStringEncodingMacExtArabic ; - break ; - case wxFONTENCODING_MACSYMBOL : - enc = kCFStringEncodingMacSymbol ; - break ; - case wxFONTENCODING_MACDINGBATS : - enc = kCFStringEncodingMacDingbats ; - break ; - case wxFONTENCODING_MACTURKISH : - enc = kCFStringEncodingMacTurkish ; - break ; - case wxFONTENCODING_MACCROATIAN : - enc = kCFStringEncodingMacCroatian ; - break ; - case wxFONTENCODING_MACICELANDIC : - enc = kCFStringEncodingMacIcelandic ; - break ; - case wxFONTENCODING_MACROMANIAN : - enc = kCFStringEncodingMacRomanian ; - break ; - case wxFONTENCODING_MACCELTIC : - enc = kCFStringEncodingMacCeltic ; - break ; - case wxFONTENCODING_MACGAELIC : - enc = kCFStringEncodingMacGaelic ; - break ; -// case wxFONTENCODING_MACKEYBOARD : -// enc = kCFStringEncodingMacKeyboardGlyphs ; -// break ; - - default : - // because gcc is picky - break ; - } - - return enc ; -} - -class wxMBConv_cocoa : public wxMBConv -{ -public: - wxMBConv_cocoa() - { - Init(CFStringGetSystemEncoding()) ; - } - - wxMBConv_cocoa(const wxMBConv_cocoa& conv) - { - m_encoding = conv.m_encoding; - } - -#if wxUSE_FONTMAP - wxMBConv_cocoa(const wxChar* name) - { - Init( wxCFStringEncFromFontEnc(wxFontMapperBase::Get()->CharsetToEncoding(name, false) ) ) ; - } -#endif - - wxMBConv_cocoa(wxFontEncoding encoding) - { - Init( wxCFStringEncFromFontEnc(encoding) ); - } - - virtual ~wxMBConv_cocoa() - { - } - - void Init( CFStringEncoding encoding) - { - m_encoding = encoding ; - } - - size_t MB2WC(wchar_t * szOut, const char * szUnConv, size_t nOutSize) const - { - wxASSERT(szUnConv); - - CFStringRef theString = CFStringCreateWithBytes ( - NULL, //the allocator - (const UInt8*)szUnConv, - strlen(szUnConv), - m_encoding, - false //no BOM/external representation - ); - - wxASSERT(theString); - - size_t nOutLength = CFStringGetLength(theString); - - if (szOut == NULL) - { - CFRelease(theString); - return nOutLength; - } - - CFRange theRange = { 0, nOutSize }; - -#if SIZEOF_WCHAR_T == 4 - UniChar* szUniCharBuffer = new UniChar[nOutSize]; -#endif - - CFStringGetCharacters(theString, theRange, szUniCharBuffer); - - CFRelease(theString); - - szUniCharBuffer[nOutLength] = '\0'; - -#if SIZEOF_WCHAR_T == 4 - wxMBConvUTF16 converter; - converter.MB2WC( szOut, (const char*)szUniCharBuffer, nOutSize ); - delete [] szUniCharBuffer; -#endif - - return nOutLength; - } - - size_t WC2MB(char *szOut, const wchar_t *szUnConv, size_t nOutSize) const - { - wxASSERT(szUnConv); - - size_t nRealOutSize; - size_t nBufSize = wxWcslen(szUnConv); - UniChar* szUniBuffer = (UniChar*) szUnConv; - -#if SIZEOF_WCHAR_T == 4 - wxMBConvUTF16 converter ; - nBufSize = converter.WC2MB( NULL, szUnConv, 0 ); - szUniBuffer = new UniChar[ (nBufSize / sizeof(UniChar)) + 1]; - converter.WC2MB( (char*) szUniBuffer, szUnConv, nBufSize + sizeof(UniChar)); - nBufSize /= sizeof(UniChar); -#endif - - CFStringRef theString = CFStringCreateWithCharactersNoCopy( - NULL, //allocator - szUniBuffer, - nBufSize, - kCFAllocatorNull //deallocator - we want to deallocate it ourselves - ); - - wxASSERT(theString); - - //Note that CER puts a BOM when converting to unicode - //so we check and use getchars instead in that case - if (m_encoding == kCFStringEncodingUnicode) - { - if (szOut != NULL) - CFStringGetCharacters(theString, CFRangeMake(0, nOutSize - 1), (UniChar*) szOut); - - nRealOutSize = CFStringGetLength(theString) + 1; - } - else - { - CFStringGetBytes( - theString, - CFRangeMake(0, CFStringGetLength(theString)), - m_encoding, - 0, //what to put in characters that can't be converted - - //0 tells CFString to return NULL if it meets such a character - false, //not an external representation - (UInt8*) szOut, - nOutSize, - (CFIndex*) &nRealOutSize - ); - } - - CFRelease(theString); - -#if SIZEOF_WCHAR_T == 4 - delete[] szUniBuffer; -#endif - - return nRealOutSize - 1; - } - - virtual wxMBConv *Clone() const { return new wxMBConv_cocoa(*this); } - - bool IsOk() const - { - return m_encoding != kCFStringEncodingInvalidId && - CFStringIsEncodingAvailable(m_encoding); - } - -private: - CFStringEncoding m_encoding ; -}; - -#endif // defined(__WXCOCOA__) - -// ============================================================================ -// Mac conversion classes -// ============================================================================ - -#if defined(__WXMAC__) && defined(TARGET_CARBON) - -class wxMBConv_mac : public wxMBConv -{ -public: - wxMBConv_mac() - { - Init(CFStringGetSystemEncoding()) ; - } - - wxMBConv_mac(const wxMBConv_mac& conv) - { - Init(conv.m_char_encoding); - } - -#if wxUSE_FONTMAP - wxMBConv_mac(const wxChar* name) - { - Init( wxMacGetSystemEncFromFontEnc( wxFontMapperBase::Get()->CharsetToEncoding(name, false) ) ); - } -#endif - - wxMBConv_mac(wxFontEncoding encoding) - { - Init( wxMacGetSystemEncFromFontEnc(encoding) ); - } - - virtual ~wxMBConv_mac() - { - OSStatus status = noErr ; - if (m_MB2WC_converter) - status = TECDisposeConverter(m_MB2WC_converter); - if (m_WC2MB_converter) - status = TECDisposeConverter(m_WC2MB_converter); - } - - void Init( TextEncodingBase encoding,TextEncodingVariant encodingVariant = kTextEncodingDefaultVariant , - TextEncodingFormat encodingFormat = kTextEncodingDefaultFormat) - { - m_MB2WC_converter = NULL ; - m_WC2MB_converter = NULL ; - m_char_encoding = CreateTextEncoding(encoding, encodingVariant, encodingFormat) ; - m_unicode_encoding = CreateTextEncoding(kTextEncodingUnicodeDefault, 0, kUnicode16BitFormat) ; - } - - virtual void CreateIfNeeded() const - { - if ( m_MB2WC_converter == NULL && m_WC2MB_converter == NULL ) - { - OSStatus status = noErr ; - status = TECCreateConverter(&m_MB2WC_converter, - m_char_encoding, - m_unicode_encoding); - wxASSERT_MSG( status == noErr , _("Unable to create TextEncodingConverter")) ; - status = TECCreateConverter(&m_WC2MB_converter, - m_unicode_encoding, - m_char_encoding); - wxASSERT_MSG( status == noErr , _("Unable to create TextEncodingConverter")) ; - } - } - - size_t MB2WC(wchar_t *buf, const char *psz, size_t n) const - { - CreateIfNeeded() ; - OSStatus status = noErr ; - ByteCount byteOutLen ; - ByteCount byteInLen = strlen(psz) + 1; - wchar_t *tbuf = NULL ; - UniChar* ubuf = NULL ; - size_t res = 0 ; - - if (buf == NULL) - { - // Apple specs say at least 32 - n = wxMax( 32, byteInLen ) ; - tbuf = (wchar_t*) malloc( n * SIZEOF_WCHAR_T ) ; - } - - ByteCount byteBufferLen = n * sizeof( UniChar ) ; - -#if SIZEOF_WCHAR_T == 4 - ubuf = (UniChar*) malloc( byteBufferLen + 2 ) ; -#else - ubuf = (UniChar*) (buf ? buf : tbuf) ; -#endif - - status = TECConvertText( - m_MB2WC_converter, (ConstTextPtr) psz, byteInLen, &byteInLen, - (TextPtr) ubuf, byteBufferLen, &byteOutLen); - -#if SIZEOF_WCHAR_T == 4 - // we have to terminate here, because n might be larger for the trailing zero, and if UniChar - // is not properly terminated we get random characters at the end - ubuf[byteOutLen / sizeof( UniChar ) ] = 0 ; - wxMBConvUTF16 converter ; - res = converter.MB2WC( (buf ? buf : tbuf), (const char*)ubuf, n ) ; - free( ubuf ) ; -#else - res = byteOutLen / sizeof( UniChar ) ; -#endif - - if ( buf == NULL ) - free(tbuf) ; - - if ( buf && res < n) - buf[res] = 0; - - return res ; - } - - size_t WC2MB(char *buf, const wchar_t *psz, size_t n) const - { - CreateIfNeeded() ; - OSStatus status = noErr ; - ByteCount byteOutLen ; - ByteCount byteInLen = wxWcslen(psz) * SIZEOF_WCHAR_T ; - - char *tbuf = NULL ; - - if (buf == NULL) - { - // Apple specs say at least 32 - n = wxMax( 32, ((byteInLen / SIZEOF_WCHAR_T) * 8) + SIZEOF_WCHAR_T ); - tbuf = (char*) malloc( n ) ; - } - - ByteCount byteBufferLen = n ; - UniChar* ubuf = NULL ; - -#if SIZEOF_WCHAR_T == 4 - wxMBConvUTF16 converter ; - size_t unicharlen = converter.WC2MB( NULL, psz, 0 ) ; - byteInLen = unicharlen ; - ubuf = (UniChar*) malloc( byteInLen + 2 ) ; - converter.WC2MB( (char*) ubuf, psz, unicharlen + 2 ) ; -#else - ubuf = (UniChar*) psz ; -#endif - - status = TECConvertText( - m_WC2MB_converter, (ConstTextPtr) ubuf, byteInLen, &byteInLen, - (TextPtr) (buf ? buf : tbuf), byteBufferLen, &byteOutLen); - -#if SIZEOF_WCHAR_T == 4 - free( ubuf ) ; -#endif - - if ( buf == NULL ) - free(tbuf) ; - - size_t res = byteOutLen ; - if ( buf && res < n) - { - buf[res] = 0; - - //we need to double-trip to verify it didn't insert any ? in place - //of bogus characters - wxWCharBuffer wcBuf(n); - size_t pszlen = wxWcslen(psz); - if ( MB2WC(wcBuf.data(), buf, n) == wxCONV_FAILED || - wxWcslen(wcBuf) != pszlen || - memcmp(wcBuf, psz, pszlen * sizeof(wchar_t)) != 0 ) - { - // we didn't obtain the same thing we started from, hence - // the conversion was lossy and we consider that it failed - return wxCONV_FAILED; - } - } - - return res ; - } - - virtual wxMBConv *Clone() const { return new wxMBConv_mac(*this); } - - bool IsOk() const - { - CreateIfNeeded() ; - return m_MB2WC_converter != NULL && m_WC2MB_converter != NULL; - } - -protected : - mutable TECObjectRef m_MB2WC_converter; - mutable TECObjectRef m_WC2MB_converter; - - TextEncodingBase m_char_encoding; - TextEncodingBase m_unicode_encoding; -}; - -// MB is decomposed (D) normalized UTF8 - -class wxMBConv_macUTF8D : public wxMBConv_mac -{ -public : - wxMBConv_macUTF8D() - { - Init( kTextEncodingUnicodeDefault , kUnicodeNoSubset , kUnicodeUTF8Format ) ; - m_uni = NULL; - m_uniBack = NULL ; - } - - virtual ~wxMBConv_macUTF8D() - { - if (m_uni!=NULL) - DisposeUnicodeToTextInfo(&m_uni); - if (m_uniBack!=NULL) - DisposeUnicodeToTextInfo(&m_uniBack); - } - - size_t WC2MB(char *buf, const wchar_t *psz, size_t n) const - { - CreateIfNeeded() ; - OSStatus status = noErr ; - ByteCount byteOutLen ; - ByteCount byteInLen = wxWcslen(psz) * SIZEOF_WCHAR_T ; - - char *tbuf = NULL ; - - if (buf == NULL) - { - // Apple specs say at least 32 - n = wxMax( 32, ((byteInLen / SIZEOF_WCHAR_T) * 8) + SIZEOF_WCHAR_T ); - tbuf = (char*) malloc( n ) ; - } - - ByteCount byteBufferLen = n ; - UniChar* ubuf = NULL ; - -#if SIZEOF_WCHAR_T == 4 - wxMBConvUTF16 converter ; - size_t unicharlen = converter.WC2MB( NULL, psz, 0 ) ; - byteInLen = unicharlen ; - ubuf = (UniChar*) malloc( byteInLen + 2 ) ; - converter.WC2MB( (char*) ubuf, psz, unicharlen + 2 ) ; -#else - ubuf = (UniChar*) psz ; -#endif - - // ubuf is a non-decomposed UniChar buffer - - ByteCount dcubuflen = byteInLen * 2 + 2 ; - ByteCount dcubufread , dcubufwritten ; - UniChar *dcubuf = (UniChar*) malloc( dcubuflen ) ; - - ConvertFromUnicodeToText( m_uni , byteInLen , ubuf , - kUnicodeDefaultDirectionMask, 0, NULL, NULL, NULL, dcubuflen , &dcubufread , &dcubufwritten , dcubuf ) ; - - // we now convert that decomposed buffer into UTF8 - - status = TECConvertText( - m_WC2MB_converter, (ConstTextPtr) dcubuf, dcubufwritten, &dcubufread, - (TextPtr) (buf ? buf : tbuf), byteBufferLen, &byteOutLen); - - free( dcubuf ); - -#if SIZEOF_WCHAR_T == 4 - free( ubuf ) ; -#endif - - if ( buf == NULL ) - free(tbuf) ; - - size_t res = byteOutLen ; - if ( buf && res < n) - { - buf[res] = 0; - // don't test for round-trip fidelity yet, we cannot guarantee it yet - } - - return res ; - } - - size_t MB2WC(wchar_t *buf, const char *psz, size_t n) const - { - CreateIfNeeded() ; - OSStatus status = noErr ; - ByteCount byteOutLen ; - ByteCount byteInLen = strlen(psz) + 1; - wchar_t *tbuf = NULL ; - UniChar* ubuf = NULL ; - size_t res = 0 ; - - if (buf == NULL) - { - // Apple specs say at least 32 - n = wxMax( 32, byteInLen ) ; - tbuf = (wchar_t*) malloc( n * SIZEOF_WCHAR_T ) ; - } - - ByteCount byteBufferLen = n * sizeof( UniChar ) ; - -#if SIZEOF_WCHAR_T == 4 - ubuf = (UniChar*) malloc( byteBufferLen + 2 ) ; -#else - ubuf = (UniChar*) (buf ? buf : tbuf) ; -#endif - - ByteCount dcubuflen = byteBufferLen * 2 + 2 ; - ByteCount dcubufread , dcubufwritten ; - UniChar *dcubuf = (UniChar*) malloc( dcubuflen ) ; - - status = TECConvertText( - m_MB2WC_converter, (ConstTextPtr) psz, byteInLen, &byteInLen, - (TextPtr) dcubuf, dcubuflen, &byteOutLen); - // we have to terminate here, because n might be larger for the trailing zero, and if UniChar - // is not properly terminated we get random characters at the end - dcubuf[byteOutLen / sizeof( UniChar ) ] = 0 ; - - // now from the decomposed UniChar to properly composed uniChar - ConvertFromUnicodeToText( m_uniBack , byteOutLen , dcubuf , - kUnicodeDefaultDirectionMask, 0, NULL, NULL, NULL, dcubuflen , &dcubufread , &dcubufwritten , ubuf ) ; - - free( dcubuf ); - byteOutLen = dcubufwritten ; - ubuf[byteOutLen / sizeof( UniChar ) ] = 0 ; - - -#if SIZEOF_WCHAR_T == 4 - wxMBConvUTF16 converter ; - res = converter.MB2WC( (buf ? buf : tbuf), (const char*)ubuf, n ) ; - free( ubuf ) ; -#else - res = byteOutLen / sizeof( UniChar ) ; -#endif - - if ( buf == NULL ) - free(tbuf) ; - - if ( buf && res < n) - buf[res] = 0; - - return res ; - } - - virtual void CreateIfNeeded() const - { - wxMBConv_mac::CreateIfNeeded() ; - if ( m_uni == NULL ) - { - m_map.unicodeEncoding = CreateTextEncoding(kTextEncodingUnicodeDefault, - kUnicodeNoSubset, kTextEncodingDefaultFormat); - m_map.otherEncoding = CreateTextEncoding(kTextEncodingUnicodeDefault, - kUnicodeCanonicalDecompVariant, kTextEncodingDefaultFormat); - m_map.mappingVersion = kUnicodeUseLatestMapping; - - OSStatus err = CreateUnicodeToTextInfo(&m_map, &m_uni); - wxASSERT_MSG( err == noErr , _(" Couldn't create the UnicodeConverter")) ; - - m_map.unicodeEncoding = CreateTextEncoding(kTextEncodingUnicodeDefault, - kUnicodeNoSubset, kTextEncodingDefaultFormat); - m_map.otherEncoding = CreateTextEncoding(kTextEncodingUnicodeDefault, - kUnicodeCanonicalCompVariant, kTextEncodingDefaultFormat); - m_map.mappingVersion = kUnicodeUseLatestMapping; - err = CreateUnicodeToTextInfo(&m_map, &m_uniBack); - wxASSERT_MSG( err == noErr , _(" Couldn't create the UnicodeConverter")) ; - } - } -protected : - mutable UnicodeToTextInfo m_uni; - mutable UnicodeToTextInfo m_uniBack; - mutable UnicodeMapping m_map; -}; -#endif // defined(__WXMAC__) && defined(TARGET_CARBON) - -// ============================================================================ -// wxEncodingConverter based conversion classes -// ============================================================================ - -#if wxUSE_FONTMAP - -class wxMBConv_wxwin : public wxMBConv -{ -private: - void Init() - { - m_ok = m2w.Init(m_enc, wxFONTENCODING_UNICODE) && - w2m.Init(wxFONTENCODING_UNICODE, m_enc); - } - -public: - // temporarily just use wxEncodingConverter stuff, - // so that it works while a better implementation is built - wxMBConv_wxwin(const wxChar* name) - { - if (name) - m_enc = wxFontMapperBase::Get()->CharsetToEncoding(name, false); - else - m_enc = wxFONTENCODING_SYSTEM; - - Init(); - } - - wxMBConv_wxwin(wxFontEncoding enc) - { - m_enc = enc; - - Init(); - } - - size_t MB2WC(wchar_t *buf, const char *psz, size_t WXUNUSED(n)) const - { - size_t inbuf = strlen(psz); - if (buf) - { - if (!m2w.Convert(psz, buf)) - return wxCONV_FAILED; - } - return inbuf; - } - - size_t WC2MB(char *buf, const wchar_t *psz, size_t WXUNUSED(n)) const - { - const size_t inbuf = wxWcslen(psz); - if (buf) - { - if (!w2m.Convert(psz, buf)) - return wxCONV_FAILED; - } - - return inbuf; - } - - virtual size_t GetMBNulLen() const - { - switch ( m_enc ) - { - case wxFONTENCODING_UTF16BE: - case wxFONTENCODING_UTF16LE: - return 2; - - case wxFONTENCODING_UTF32BE: - case wxFONTENCODING_UTF32LE: - return 4; - - default: - return 1; - } - } - - virtual wxMBConv *Clone() const { return new wxMBConv_wxwin(m_enc); } - - bool IsOk() const { return m_ok; } - -public: - wxFontEncoding m_enc; - wxEncodingConverter m2w, w2m; - -private: - // were we initialized successfully? - bool m_ok; - - DECLARE_NO_COPY_CLASS(wxMBConv_wxwin) -}; - -// make the constructors available for unit testing -WXDLLIMPEXP_BASE wxMBConv* new_wxMBConv_wxwin( const wxChar* name ) -{ - wxMBConv_wxwin* result = new wxMBConv_wxwin( name ); - if ( !result->IsOk() ) - { - delete result; - return 0; - } - - return result; -} - -#endif // wxUSE_FONTMAP - -// ============================================================================ -// wxCSConv implementation -// ============================================================================ - -void wxCSConv::Init() -{ - m_name = NULL; - m_convReal = NULL; - m_deferred = true; -} - -wxCSConv::wxCSConv(const wxChar *charset) -{ - Init(); - - if ( charset ) - { - SetName(charset); - } - -#if wxUSE_FONTMAP - m_encoding = wxFontMapperBase::GetEncodingFromName(charset); -#else - m_encoding = wxFONTENCODING_SYSTEM; -#endif -} - -wxCSConv::wxCSConv(wxFontEncoding encoding) -{ - if ( encoding == wxFONTENCODING_MAX || encoding == wxFONTENCODING_DEFAULT ) - { - wxFAIL_MSG( _T("invalid encoding value in wxCSConv ctor") ); - - encoding = wxFONTENCODING_SYSTEM; - } - - Init(); - - m_encoding = encoding; -} - -wxCSConv::~wxCSConv() -{ - Clear(); -} - -wxCSConv::wxCSConv(const wxCSConv& conv) - : wxMBConv() -{ - Init(); - - SetName(conv.m_name); - m_encoding = conv.m_encoding; -} - -wxCSConv& wxCSConv::operator=(const wxCSConv& conv) -{ - Clear(); - - SetName(conv.m_name); - m_encoding = conv.m_encoding; - - return *this; -} - -void wxCSConv::Clear() -{ - free(m_name); - delete m_convReal; - - m_name = NULL; - m_convReal = NULL; -} - -void wxCSConv::SetName(const wxChar *charset) -{ - if (charset) - { - m_name = wxStrdup(charset); - m_deferred = true; - } -} - -#if wxUSE_FONTMAP - -WX_DECLARE_HASH_MAP( wxFontEncoding, wxString, wxIntegerHash, wxIntegerEqual, - wxEncodingNameCache ); - -static wxEncodingNameCache gs_nameCache; -#endif - -wxMBConv *wxCSConv::DoCreate() const -{ -#if wxUSE_FONTMAP - wxLogTrace(TRACE_STRCONV, - wxT("creating conversion for %s"), - (m_name ? m_name - : wxFontMapperBase::GetEncodingName(m_encoding).c_str())); -#endif // wxUSE_FONTMAP - - // check for the special case of ASCII or ISO8859-1 charset: as we have - // special knowledge of it anyhow, we don't need to create a special - // conversion object - if ( m_encoding == wxFONTENCODING_ISO8859_1 || - m_encoding == wxFONTENCODING_DEFAULT ) - { - // don't convert at all - return NULL; - } - - // we trust OS to do conversion better than we can so try external - // conversion methods first - // - // the full order is: - // 1. OS conversion (iconv() under Unix or Win32 API) - // 2. hard coded conversions for UTF - // 3. wxEncodingConverter as fall back - - // step (1) -#ifdef HAVE_ICONV -#if !wxUSE_FONTMAP - if ( m_name ) -#endif // !wxUSE_FONTMAP - { - wxString name(m_name); -#if wxUSE_FONTMAP - wxFontEncoding encoding(m_encoding); -#endif - - if ( !name.empty() ) - { - wxMBConv_iconv *conv = new wxMBConv_iconv(name); - if ( conv->IsOk() ) - return conv; - - delete conv; - -#if wxUSE_FONTMAP - encoding = - wxFontMapperBase::Get()->CharsetToEncoding(name, false); -#endif // wxUSE_FONTMAP - } -#if wxUSE_FONTMAP - { - const wxEncodingNameCache::iterator it = gs_nameCache.find(encoding); - if ( it != gs_nameCache.end() ) - { - if ( it->second.empty() ) - return NULL; - - wxMBConv_iconv *conv = new wxMBConv_iconv(it->second); - if ( conv->IsOk() ) - return conv; - - delete conv; - } - - const wxChar** names = wxFontMapperBase::GetAllEncodingNames(encoding); - // CS : in case this does not return valid names (eg for MacRoman) encoding - // got a 'failure' entry in the cache all the same, although it just has to - // be created using a different method, so only store failed iconv creation - // attempts (or perhaps we shoulnd't do this at all ?) - if ( names[0] != NULL ) - { - for ( ; *names; ++names ) - { - wxMBConv_iconv *conv = new wxMBConv_iconv(*names); - if ( conv->IsOk() ) - { - gs_nameCache[encoding] = *names; - return conv; - } - - delete conv; - } - - gs_nameCache[encoding] = _T(""); // cache the failure - } - } -#endif // wxUSE_FONTMAP - } -#endif // HAVE_ICONV - -#ifdef wxHAVE_WIN32_MB2WC - { -#if wxUSE_FONTMAP - wxMBConv_win32 *conv = m_name ? new wxMBConv_win32(m_name) - : new wxMBConv_win32(m_encoding); - if ( conv->IsOk() ) - return conv; - - delete conv; -#else - return NULL; -#endif - } -#endif // wxHAVE_WIN32_MB2WC - -#if defined(__WXMAC__) - { - // leave UTF16 and UTF32 to the built-ins of wx - if ( m_name || ( m_encoding < wxFONTENCODING_UTF16BE || - ( m_encoding >= wxFONTENCODING_MACMIN && m_encoding <= wxFONTENCODING_MACMAX ) ) ) - { -#if wxUSE_FONTMAP - wxMBConv_mac *conv = m_name ? new wxMBConv_mac(m_name) - : new wxMBConv_mac(m_encoding); -#else - wxMBConv_mac *conv = new wxMBConv_mac(m_encoding); -#endif - if ( conv->IsOk() ) - return conv; - - delete conv; - } - } -#endif - -#if defined(__WXCOCOA__) - { - if ( m_name || ( m_encoding <= wxFONTENCODING_UTF16 ) ) - { -#if wxUSE_FONTMAP - wxMBConv_cocoa *conv = m_name ? new wxMBConv_cocoa(m_name) - : new wxMBConv_cocoa(m_encoding); -#else - wxMBConv_cocoa *conv = new wxMBConv_cocoa(m_encoding); -#endif - - if ( conv->IsOk() ) - return conv; - - delete conv; - } - } -#endif - // step (2) - wxFontEncoding enc = m_encoding; -#if wxUSE_FONTMAP - if ( enc == wxFONTENCODING_SYSTEM && m_name ) - { - // use "false" to suppress interactive dialogs -- we can be called from - // anywhere and popping up a dialog from here is the last thing we want to - // do - enc = wxFontMapperBase::Get()->CharsetToEncoding(m_name, false); - } -#endif // wxUSE_FONTMAP - - switch ( enc ) - { - case wxFONTENCODING_UTF7: - return new wxMBConvUTF7; - - case wxFONTENCODING_UTF8: - return new wxMBConvUTF8; - - case wxFONTENCODING_UTF16BE: - return new wxMBConvUTF16BE; - - case wxFONTENCODING_UTF16LE: - return new wxMBConvUTF16LE; - - case wxFONTENCODING_UTF32BE: - return new wxMBConvUTF32BE; - - case wxFONTENCODING_UTF32LE: - return new wxMBConvUTF32LE; - - default: - // nothing to do but put here to suppress gcc warnings - break; - } - - // step (3) -#if wxUSE_FONTMAP - { - wxMBConv_wxwin *conv = m_name ? new wxMBConv_wxwin(m_name) - : new wxMBConv_wxwin(m_encoding); - if ( conv->IsOk() ) - return conv; - - delete conv; - } -#endif // wxUSE_FONTMAP - - // NB: This is a hack to prevent deadlock. What could otherwise happen - // in Unicode build: wxConvLocal creation ends up being here - // because of some failure and logs the error. But wxLog will try to - // attach a timestamp, for which it will need wxConvLocal (to convert - // time to char* and then wchar_t*), but that fails, tries to log the - // error, but wxLog has an (already locked) critical section that - // guards the static buffer. - static bool alreadyLoggingError = false; - if (!alreadyLoggingError) - { - alreadyLoggingError = true; - wxLogError(_("Cannot convert from the charset '%s'!"), - m_name ? m_name - : -#if wxUSE_FONTMAP - wxFontMapperBase::GetEncodingDescription(m_encoding).c_str() -#else // !wxUSE_FONTMAP - wxString::Format(_("encoding %i"), m_encoding).c_str() -#endif // wxUSE_FONTMAP/!wxUSE_FONTMAP - ); - - alreadyLoggingError = false; - } - - return NULL; -} - -void wxCSConv::CreateConvIfNeeded() const -{ - if ( m_deferred ) - { - wxCSConv *self = (wxCSConv *)this; // const_cast - - // if we don't have neither the name nor the encoding, use the default - // encoding for this system - if ( !m_name && m_encoding == wxFONTENCODING_SYSTEM ) - { -#if wxUSE_INTL - self->m_name = wxStrdup(wxLocale::GetSystemEncodingName()); -#else - // fallback to some reasonable default: - self->m_encoding = wxFONTENCODING_ISO8859_1; -#endif // wxUSE_INTL - } - - self->m_convReal = DoCreate(); - self->m_deferred = false; - } -} - -bool wxCSConv::IsOk() const -{ - CreateConvIfNeeded(); - - // special case: no convReal created for wxFONTENCODING_ISO8859_1 - if ( m_encoding == wxFONTENCODING_ISO8859_1 ) - return true; // always ok as we do it ourselves - - // m_convReal->IsOk() is called at its own creation, so we know it must - // be ok if m_convReal is non-NULL - return m_convReal != NULL; -} - -size_t wxCSConv::ToWChar(wchar_t *dst, size_t dstLen, - const char *src, size_t srcLen) const -{ - CreateConvIfNeeded(); - - if (m_convReal) - return m_convReal->ToWChar(dst, dstLen, src, srcLen); - - // latin-1 (direct) - return wxMBConv::ToWChar(dst, dstLen, src, srcLen); -} - -size_t wxCSConv::FromWChar(char *dst, size_t dstLen, - const wchar_t *src, size_t srcLen) const -{ - CreateConvIfNeeded(); - - if (m_convReal) - return m_convReal->FromWChar(dst, dstLen, src, srcLen); - - // latin-1 (direct) - return wxMBConv::FromWChar(dst, dstLen, src, srcLen); -} - -size_t wxCSConv::MB2WC(wchar_t *buf, const char *psz, size_t n) const -{ - CreateConvIfNeeded(); - - if (m_convReal) - return m_convReal->MB2WC(buf, psz, n); - - // latin-1 (direct) - size_t len = strlen(psz); - - if (buf) - { - for (size_t c = 0; c <= len; c++) - buf[c] = (unsigned char)(psz[c]); - } - - return len; -} - -size_t wxCSConv::WC2MB(char *buf, const wchar_t *psz, size_t n) const -{ - CreateConvIfNeeded(); - - if (m_convReal) - return m_convReal->WC2MB(buf, psz, n); - - // latin-1 (direct) - const size_t len = wxWcslen(psz); - if (buf) - { - for (size_t c = 0; c <= len; c++) - { - if (psz[c] > 0xFF) - return wxCONV_FAILED; - - buf[c] = (char)psz[c]; - } - } - else - { - for (size_t c = 0; c <= len; c++) - { - if (psz[c] > 0xFF) - return wxCONV_FAILED; - } - } - - return len; -} - -size_t wxCSConv::GetMBNulLen() const -{ - CreateConvIfNeeded(); - - if ( m_convReal ) - { - return m_convReal->GetMBNulLen(); - } - - return 1; -} - -// ---------------------------------------------------------------------------- -// globals -// ---------------------------------------------------------------------------- - -#ifdef __WINDOWS__ - static wxMBConv_win32 wxConvLibcObj; -#elif defined(__WXMAC__) && !defined(__MACH__) - static wxMBConv_mac wxConvLibcObj ; -#else - static wxMBConvLibc wxConvLibcObj; -#endif - -static wxCSConv wxConvLocalObj(wxFONTENCODING_SYSTEM); -static wxCSConv wxConvISO8859_1Obj(wxFONTENCODING_ISO8859_1); -static wxMBConvUTF7 wxConvUTF7Obj; -static wxMBConvUTF8 wxConvUTF8Obj; -#if defined(__WXMAC__) && defined(TARGET_CARBON) -static wxMBConv_macUTF8D wxConvMacUTF8DObj; -#endif -WXDLLIMPEXP_DATA_BASE(wxMBConv&) wxConvLibc = wxConvLibcObj; -WXDLLIMPEXP_DATA_BASE(wxCSConv&) wxConvLocal = wxConvLocalObj; -WXDLLIMPEXP_DATA_BASE(wxCSConv&) wxConvISO8859_1 = wxConvISO8859_1Obj; -WXDLLIMPEXP_DATA_BASE(wxMBConvUTF7&) wxConvUTF7 = wxConvUTF7Obj; -WXDLLIMPEXP_DATA_BASE(wxMBConvUTF8&) wxConvUTF8 = wxConvUTF8Obj; -WXDLLIMPEXP_DATA_BASE(wxMBConv *) wxConvCurrent = &wxConvLibcObj; -WXDLLIMPEXP_DATA_BASE(wxMBConv *) wxConvUI = &wxConvLocal; -WXDLLIMPEXP_DATA_BASE(wxMBConv *) wxConvFileName = & -#ifdef __WXOSX__ -#if defined(__WXMAC__) && defined(TARGET_CARBON) - wxConvMacUTF8DObj; -#else - wxConvUTF8Obj; -#endif -#else // !__WXOSX__ - wxConvLibcObj; -#endif // __WXOSX__/!__WXOSX__ - -#if wxUSE_UNICODE - -wxWCharBuffer wxSafeConvertMB2WX(const char *s) -{ - if ( !s ) - return wxWCharBuffer(); - - wxWCharBuffer wbuf(wxConvLibc.cMB2WX(s)); - if ( !wbuf ) - wbuf = wxConvUTF8.cMB2WX(s); - if ( !wbuf ) - wbuf = wxConvISO8859_1.cMB2WX(s); - - return wbuf; -} - -wxCharBuffer wxSafeConvertWX2MB(const wchar_t *ws) -{ - if ( !ws ) - return wxCharBuffer(); - - wxCharBuffer buf(wxConvLibc.cWX2MB(ws)); - if ( !buf ) - buf = wxMBConvUTF8(wxMBConvUTF8::MAP_INVALID_UTF8_TO_OCTAL).cWX2MB(ws); - - return buf; -} - -#endif // wxUSE_UNICODE - -#else // !wxUSE_WCHAR_T - -// stand-ins in absence of wchar_t -WXDLLIMPEXP_DATA_BASE(wxMBConv) wxConvLibc, - wxConvISO8859_1, - wxConvLocal, - wxConvUTF8; - -WXDLLIMPEXP_DATA_BASE(wxMBConv *) wxConvCurrent = NULL; - -#endif // wxUSE_WCHAR_T/!wxUSE_WCHAR_T +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/strconv.cpp +// Purpose: Unicode conversion classes +// Author: Ove Kaaven, Robert Roebling, Vadim Zeitlin, Vaclav Slavik, +// Ryan Norton, Fredrik Roubert (UTF7) +// Modified by: +// Created: 29/01/98 +// RCS-ID: $Id: strconv.cpp 45921 2007-05-09 18:10:26Z VZ $ +// Copyright: (c) 1999 Ove Kaaven, Robert Roebling, Vaclav Slavik +// (c) 2000-2003 Vadim Zeitlin +// (c) 2004 Ryan Norton, Fredrik Roubert +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifndef WX_PRECOMP + #ifdef __WXMSW__ + #include "wx/msw/missing.h" + #endif + #include "wx/intl.h" + #include "wx/log.h" + #include "wx/utils.h" + #include "wx/hashmap.h" +#endif + +#include "wx/strconv.h" + +#if wxUSE_WCHAR_T + +#ifdef __WINDOWS__ + #include "wx/msw/private.h" +#endif + +#ifndef __WXWINCE__ +#include +#endif + +#include +#include +#include + +#if defined(__WIN32__) && !defined(__WXMICROWIN__) + #define wxHAVE_WIN32_MB2WC +#endif + +#ifdef __SALFORDC__ + #include +#endif + +#ifdef HAVE_ICONV + #include + #include "wx/thread.h" +#endif + +#include "wx/encconv.h" +#include "wx/fontmap.h" + +#ifdef __WXMAC__ +#ifndef __DARWIN__ +#include +#include +#include +#endif + +// includes Mac headers +#include "wx/mac/private.h" +#endif + + +#define TRACE_STRCONV _T("strconv") + +// WC_UTF16 is defined only if sizeof(wchar_t) == 2, otherwise it's supposed to +// be 4 bytes +#if SIZEOF_WCHAR_T == 2 + #define WC_UTF16 +#endif + + +// ============================================================================ +// implementation +// ============================================================================ + +// helper function of cMB2WC(): check if n bytes at this location are all NUL +static bool NotAllNULs(const char *p, size_t n) +{ + while ( n && *p++ == '\0' ) + n--; + + return n != 0; +} + +// ---------------------------------------------------------------------------- +// UTF-16 en/decoding to/from UCS-4 with surrogates handling +// ---------------------------------------------------------------------------- + +static size_t encode_utf16(wxUint32 input, wxUint16 *output) +{ + if (input <= 0xffff) + { + if (output) + *output = (wxUint16) input; + + return 1; + } + else if (input >= 0x110000) + { + return wxCONV_FAILED; + } + else + { + if (output) + { + *output++ = (wxUint16) ((input >> 10) + 0xd7c0); + *output = (wxUint16) ((input & 0x3ff) + 0xdc00); + } + + return 2; + } +} + +static size_t decode_utf16(const wxUint16* input, wxUint32& output) +{ + if ((*input < 0xd800) || (*input > 0xdfff)) + { + output = *input; + return 1; + } + else if ((input[1] < 0xdc00) || (input[1] > 0xdfff)) + { + output = *input; + return wxCONV_FAILED; + } + else + { + output = ((input[0] - 0xd7c0) << 10) + (input[1] - 0xdc00); + return 2; + } +} + +#ifdef WC_UTF16 + typedef wchar_t wxDecodeSurrogate_t; +#else // !WC_UTF16 + typedef wxUint16 wxDecodeSurrogate_t; +#endif // WC_UTF16/!WC_UTF16 + +// returns the next UTF-32 character from the wchar_t buffer and advances the +// pointer to the character after this one +// +// if an invalid character is found, *pSrc is set to NULL, the caller must +// check for this +static wxUint32 wxDecodeSurrogate(const wxDecodeSurrogate_t **pSrc) +{ + wxUint32 out; + const size_t + n = decode_utf16(wx_reinterpret_cast(const wxUint16 *, *pSrc), out); + if ( n == wxCONV_FAILED ) + *pSrc = NULL; + else + *pSrc += n; + + return out; +} + +// ---------------------------------------------------------------------------- +// wxMBConv +// ---------------------------------------------------------------------------- + +size_t +wxMBConv::ToWChar(wchar_t *dst, size_t dstLen, + const char *src, size_t srcLen) const +{ + // although new conversion classes are supposed to implement this function + // directly, the existins ones only implement the old MB2WC() and so, to + // avoid to have to rewrite all conversion classes at once, we provide a + // default (but not efficient) implementation of this one in terms of the + // old function by copying the input to ensure that it's NUL-terminated and + // then using MB2WC() to convert it + + // the number of chars [which would be] written to dst [if it were not NULL] + size_t dstWritten = 0; + + // the number of NULs terminating this string + size_t nulLen = 0; // not really needed, but just to avoid warnings + + // if we were not given the input size we just have to assume that the + // string is properly terminated as we have no way of knowing how long it + // is anyhow, but if we do have the size check whether there are enough + // NULs at the end + wxCharBuffer bufTmp; + const char *srcEnd; + if ( srcLen != wxNO_LEN ) + { + // we need to know how to find the end of this string + nulLen = GetMBNulLen(); + if ( nulLen == wxCONV_FAILED ) + return wxCONV_FAILED; + + // if there are enough NULs we can avoid the copy + if ( srcLen < nulLen || NotAllNULs(src + srcLen - nulLen, nulLen) ) + { + // make a copy in order to properly NUL-terminate the string + bufTmp = wxCharBuffer(srcLen + nulLen - 1 /* 1 will be added */); + char * const p = bufTmp.data(); + memcpy(p, src, srcLen); + for ( char *s = p + srcLen; s < p + srcLen + nulLen; s++ ) + *s = '\0'; + + src = bufTmp; + } + + srcEnd = src + srcLen; + } + else // quit after the first loop iteration + { + srcEnd = NULL; + } + + for ( ;; ) + { + // try to convert the current chunk + size_t lenChunk = MB2WC(NULL, src, 0); + if ( lenChunk == wxCONV_FAILED ) + return wxCONV_FAILED; + + lenChunk++; // for the L'\0' at the end of this chunk + + dstWritten += lenChunk; + + if ( lenChunk == 1 ) + { + // nothing left in the input string, conversion succeeded + break; + } + + if ( dst ) + { + if ( dstWritten > dstLen ) + return wxCONV_FAILED; + + if ( MB2WC(dst, src, lenChunk) == wxCONV_FAILED ) + return wxCONV_FAILED; + + dst += lenChunk; + } + + if ( !srcEnd ) + { + // we convert just one chunk in this case as this is the entire + // string anyhow + break; + } + + // advance the input pointer past the end of this chunk + while ( NotAllNULs(src, nulLen) ) + { + // notice that we must skip over multiple bytes here as we suppose + // that if NUL takes 2 or 4 bytes, then all the other characters do + // too and so if advanced by a single byte we might erroneously + // detect sequences of NUL bytes in the middle of the input + src += nulLen; + } + + src += nulLen; // skipping over its terminator as well + + // note that ">=" (and not just "==") is needed here as the terminator + // we skipped just above could be inside or just after the buffer + // delimited by inEnd + if ( src >= srcEnd ) + break; + } + + return dstWritten; +} + +size_t +wxMBConv::FromWChar(char *dst, size_t dstLen, + const wchar_t *src, size_t srcLen) const +{ + // the number of chars [which would be] written to dst [if it were not NULL] + size_t dstWritten = 0; + + // make a copy of the input string unless it is already properly + // NUL-terminated + // + // if we don't know its length we have no choice but to assume that it is, + // indeed, properly terminated + wxWCharBuffer bufTmp; + if ( srcLen == wxNO_LEN ) + { + srcLen = wxWcslen(src) + 1; + } + else if ( srcLen != 0 && src[srcLen - 1] != L'\0' ) + { + // make a copy in order to properly NUL-terminate the string + bufTmp = wxWCharBuffer(srcLen); + memcpy(bufTmp.data(), src, srcLen * sizeof(wchar_t)); + src = bufTmp; + } + + const size_t lenNul = GetMBNulLen(); + for ( const wchar_t * const srcEnd = src + srcLen; + src < srcEnd; + src += wxWcslen(src) + 1 /* skip L'\0' too */ ) + { + // try to convert the current chunk + size_t lenChunk = WC2MB(NULL, src, 0); + + if ( lenChunk == wxCONV_FAILED ) + return wxCONV_FAILED; + + lenChunk += lenNul; + dstWritten += lenChunk; + + if ( dst ) + { + if ( dstWritten > dstLen ) + return wxCONV_FAILED; + + if ( WC2MB(dst, src, lenChunk) == wxCONV_FAILED ) + return wxCONV_FAILED; + + dst += lenChunk; + } + } + + return dstWritten; +} + +size_t wxMBConv::MB2WC(wchar_t *outBuff, const char *inBuff, size_t outLen) const +{ + size_t rc = ToWChar(outBuff, outLen, inBuff); + if ( rc != wxCONV_FAILED ) + { + // ToWChar() returns the buffer length, i.e. including the trailing + // NUL, while this method doesn't take it into account + rc--; + } + + return rc; +} + +size_t wxMBConv::WC2MB(char *outBuff, const wchar_t *inBuff, size_t outLen) const +{ + size_t rc = FromWChar(outBuff, outLen, inBuff); + if ( rc != wxCONV_FAILED ) + { + rc -= GetMBNulLen(); + } + + return rc; +} + +wxMBConv::~wxMBConv() +{ + // nothing to do here (necessary for Darwin linking probably) +} + +const wxWCharBuffer wxMBConv::cMB2WC(const char *psz) const +{ + if ( psz ) + { + // calculate the length of the buffer needed first + const size_t nLen = MB2WC(NULL, psz, 0); + if ( nLen != wxCONV_FAILED ) + { + // now do the actual conversion + wxWCharBuffer buf(nLen /* +1 added implicitly */); + + // +1 for the trailing NULL + if ( MB2WC(buf.data(), psz, nLen + 1) != wxCONV_FAILED ) + return buf; + } + } + + return wxWCharBuffer(); +} + +const wxCharBuffer wxMBConv::cWC2MB(const wchar_t *pwz) const +{ + if ( pwz ) + { + const size_t nLen = WC2MB(NULL, pwz, 0); + if ( nLen != wxCONV_FAILED ) + { + // extra space for trailing NUL(s) + static const size_t extraLen = GetMaxMBNulLen(); + + wxCharBuffer buf(nLen + extraLen - 1); + if ( WC2MB(buf.data(), pwz, nLen + extraLen) != wxCONV_FAILED ) + return buf; + } + } + + return wxCharBuffer(); +} + +const wxWCharBuffer +wxMBConv::cMB2WC(const char *inBuff, size_t inLen, size_t *outLen) const +{ + const size_t dstLen = ToWChar(NULL, 0, inBuff, inLen); + if ( dstLen != wxCONV_FAILED ) + { + wxWCharBuffer wbuf(dstLen - 1); + if ( ToWChar(wbuf.data(), dstLen, inBuff, inLen) != wxCONV_FAILED ) + { + if ( outLen ) + { + *outLen = dstLen; + if ( wbuf[dstLen - 1] == L'\0' ) + (*outLen)--; + } + + return wbuf; + } + } + + if ( outLen ) + *outLen = 0; + + return wxWCharBuffer(); +} + +const wxCharBuffer +wxMBConv::cWC2MB(const wchar_t *inBuff, size_t inLen, size_t *outLen) const +{ + size_t dstLen = FromWChar(NULL, 0, inBuff, inLen); + if ( dstLen != wxCONV_FAILED ) + { + // special case of empty input: can't allocate 0 size buffer below as + // wxCharBuffer insists on NUL-terminating it + wxCharBuffer buf(dstLen ? dstLen - 1 : 1); + if ( FromWChar(buf.data(), dstLen, inBuff, inLen) != wxCONV_FAILED ) + { + if ( outLen ) + { + *outLen = dstLen; + + const size_t nulLen = GetMBNulLen(); + if ( dstLen >= nulLen && + !NotAllNULs(buf.data() + dstLen - nulLen, nulLen) ) + { + // in this case the output is NUL-terminated and we're not + // supposed to count NUL + *outLen -= nulLen; + } + } + + return buf; + } + } + + if ( outLen ) + *outLen = 0; + + return wxCharBuffer(); +} + +// ---------------------------------------------------------------------------- +// wxMBConvLibc +// ---------------------------------------------------------------------------- + +size_t wxMBConvLibc::MB2WC(wchar_t *buf, const char *psz, size_t n) const +{ + return wxMB2WC(buf, psz, n); +} + +size_t wxMBConvLibc::WC2MB(char *buf, const wchar_t *psz, size_t n) const +{ + return wxWC2MB(buf, psz, n); +} + +// ---------------------------------------------------------------------------- +// wxConvBrokenFileNames +// ---------------------------------------------------------------------------- + +#ifdef __UNIX__ + +wxConvBrokenFileNames::wxConvBrokenFileNames(const wxChar *charset) +{ + if ( !charset || wxStricmp(charset, _T("UTF-8")) == 0 + || wxStricmp(charset, _T("UTF8")) == 0 ) + m_conv = new wxMBConvUTF8(wxMBConvUTF8::MAP_INVALID_UTF8_TO_PUA); + else + m_conv = new wxCSConv(charset); +} + +#endif // __UNIX__ + +// ---------------------------------------------------------------------------- +// UTF-7 +// ---------------------------------------------------------------------------- + +// Implementation (C) 2004 Fredrik Roubert + +// +// BASE64 decoding table +// +static const unsigned char utf7unb64[] = +{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x3e, 0xff, 0xff, 0xff, 0x3f, + 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, + 0x3c, 0x3d, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, + 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, + 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, + 0x17, 0x18, 0x19, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, + 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, + 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, + 0x31, 0x32, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff +}; + +size_t wxMBConvUTF7::MB2WC(wchar_t *buf, const char *psz, size_t n) const +{ + size_t len = 0; + + while ( *psz && (!buf || (len < n)) ) + { + unsigned char cc = *psz++; + if (cc != '+') + { + // plain ASCII char + if (buf) + *buf++ = cc; + len++; + } + else if (*psz == '-') + { + // encoded plus sign + if (buf) + *buf++ = cc; + len++; + psz++; + } + else // start of BASE64 encoded string + { + bool lsb, ok; + unsigned int d, l; + for ( ok = lsb = false, d = 0, l = 0; + (cc = utf7unb64[(unsigned char)*psz]) != 0xff; + psz++ ) + { + d <<= 6; + d += cc; + for (l += 6; l >= 8; lsb = !lsb) + { + unsigned char c = (unsigned char)((d >> (l -= 8)) % 256); + if (lsb) + { + if (buf) + *buf++ |= c; + len ++; + } + else + { + if (buf) + *buf = (wchar_t)(c << 8); + } + + ok = true; + } + } + + if ( !ok ) + { + // in valid UTF7 we should have valid characters after '+' + return wxCONV_FAILED; + } + + if (*psz == '-') + psz++; + } + } + + if ( buf && (len < n) ) + *buf = '\0'; + + return len; +} + +// +// BASE64 encoding table +// +static const unsigned char utf7enb64[] = +{ + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', + 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', + 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', + 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', + 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', + 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', + 'w', 'x', 'y', 'z', '0', '1', '2', '3', + '4', '5', '6', '7', '8', '9', '+', '/' +}; + +// +// UTF-7 encoding table +// +// 0 - Set D (directly encoded characters) +// 1 - Set O (optional direct characters) +// 2 - whitespace characters (optional) +// 3 - special characters +// +static const unsigned char utf7encode[128] = +{ + 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 3, 3, 2, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 2, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 3, 0, 0, 0, 3, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 3, 1, 1, 1, + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 3, 3 +}; + +size_t wxMBConvUTF7::WC2MB(char *buf, const wchar_t *psz, size_t n) const +{ + size_t len = 0; + + while (*psz && ((!buf) || (len < n))) + { + wchar_t cc = *psz++; + if (cc < 0x80 && utf7encode[cc] < 1) + { + // plain ASCII char + if (buf) + *buf++ = (char)cc; + + len++; + } +#ifndef WC_UTF16 + else if (((wxUint32)cc) > 0xffff) + { + // no surrogate pair generation (yet?) + return wxCONV_FAILED; + } +#endif + else + { + if (buf) + *buf++ = '+'; + + len++; + if (cc != '+') + { + // BASE64 encode string + unsigned int lsb, d, l; + for (d = 0, l = 0; /*nothing*/; psz++) + { + for (lsb = 0; lsb < 2; lsb ++) + { + d <<= 8; + d += lsb ? cc & 0xff : (cc & 0xff00) >> 8; + + for (l += 8; l >= 6; ) + { + l -= 6; + if (buf) + *buf++ = utf7enb64[(d >> l) % 64]; + len++; + } + } + + cc = *psz; + if (!(cc) || (cc < 0x80 && utf7encode[cc] < 1)) + break; + } + + if (l != 0) + { + if (buf) + *buf++ = utf7enb64[((d % 16) << (6 - l)) % 64]; + + len++; + } + } + + if (buf) + *buf++ = '-'; + len++; + } + } + + if (buf && (len < n)) + *buf = 0; + + return len; +} + +// ---------------------------------------------------------------------------- +// UTF-8 +// ---------------------------------------------------------------------------- + +static wxUint32 utf8_max[]= + { 0x7f, 0x7ff, 0xffff, 0x1fffff, 0x3ffffff, 0x7fffffff, 0xffffffff }; + +// boundaries of the private use area we use to (temporarily) remap invalid +// characters invalid in a UTF-8 encoded string +const wxUint32 wxUnicodePUA = 0x100000; +const wxUint32 wxUnicodePUAEnd = wxUnicodePUA + 256; + +size_t wxMBConvUTF8::MB2WC(wchar_t *buf, const char *psz, size_t n) const +{ + size_t len = 0; + + while (*psz && ((!buf) || (len < n))) + { + const char *opsz = psz; + bool invalid = false; + unsigned char cc = *psz++, fc = cc; + unsigned cnt; + for (cnt = 0; fc & 0x80; cnt++) + fc <<= 1; + + if (!cnt) + { + // plain ASCII char + if (buf) + *buf++ = cc; + len++; + + // escape the escape character for octal escapes + if ((m_options & MAP_INVALID_UTF8_TO_OCTAL) + && cc == '\\' && (!buf || len < n)) + { + if (buf) + *buf++ = cc; + len++; + } + } + else + { + cnt--; + if (!cnt) + { + // invalid UTF-8 sequence + invalid = true; + } + else + { + unsigned ocnt = cnt - 1; + wxUint32 res = cc & (0x3f >> cnt); + while (cnt--) + { + cc = *psz; + if ((cc & 0xC0) != 0x80) + { + // invalid UTF-8 sequence + invalid = true; + break; + } + + psz++; + res = (res << 6) | (cc & 0x3f); + } + + if (invalid || res <= utf8_max[ocnt]) + { + // illegal UTF-8 encoding + invalid = true; + } + else if ((m_options & MAP_INVALID_UTF8_TO_PUA) && + res >= wxUnicodePUA && res < wxUnicodePUAEnd) + { + // if one of our PUA characters turns up externally + // it must also be treated as an illegal sequence + // (a bit like you have to escape an escape character) + invalid = true; + } + else + { +#ifdef WC_UTF16 + // cast is ok because wchar_t == wxUuint16 if WC_UTF16 + size_t pa = encode_utf16(res, (wxUint16 *)buf); + if (pa == wxCONV_FAILED) + { + invalid = true; + } + else + { + if (buf) + buf += pa; + len += pa; + } +#else // !WC_UTF16 + if (buf) + *buf++ = (wchar_t)res; + len++; +#endif // WC_UTF16/!WC_UTF16 + } + } + + if (invalid) + { + if (m_options & MAP_INVALID_UTF8_TO_PUA) + { + while (opsz < psz && (!buf || len < n)) + { +#ifdef WC_UTF16 + // cast is ok because wchar_t == wxUuint16 if WC_UTF16 + size_t pa = encode_utf16((unsigned char)*opsz + wxUnicodePUA, (wxUint16 *)buf); + wxASSERT(pa != wxCONV_FAILED); + if (buf) + buf += pa; + opsz++; + len += pa; +#else + if (buf) + *buf++ = (wchar_t)(wxUnicodePUA + (unsigned char)*opsz); + opsz++; + len++; +#endif + } + } + else if (m_options & MAP_INVALID_UTF8_TO_OCTAL) + { + while (opsz < psz && (!buf || len < n)) + { + if ( buf && len + 3 < n ) + { + unsigned char on = *opsz; + *buf++ = L'\\'; + *buf++ = (wchar_t)( L'0' + on / 0100 ); + *buf++ = (wchar_t)( L'0' + (on % 0100) / 010 ); + *buf++ = (wchar_t)( L'0' + on % 010 ); + } + + opsz++; + len += 4; + } + } + else // MAP_INVALID_UTF8_NOT + { + return wxCONV_FAILED; + } + } + } + } + + if (buf && (len < n)) + *buf = 0; + + return len; +} + +static inline bool isoctal(wchar_t wch) +{ + return L'0' <= wch && wch <= L'7'; +} + +size_t wxMBConvUTF8::WC2MB(char *buf, const wchar_t *psz, size_t n) const +{ + size_t len = 0; + + while (*psz && ((!buf) || (len < n))) + { + wxUint32 cc; + +#ifdef WC_UTF16 + // cast is ok for WC_UTF16 + size_t pa = decode_utf16((const wxUint16 *)psz, cc); + psz += (pa == wxCONV_FAILED) ? 1 : pa; +#else + cc = (*psz++) & 0x7fffffff; +#endif + + if ( (m_options & MAP_INVALID_UTF8_TO_PUA) + && cc >= wxUnicodePUA && cc < wxUnicodePUAEnd ) + { + if (buf) + *buf++ = (char)(cc - wxUnicodePUA); + len++; + } + else if ( (m_options & MAP_INVALID_UTF8_TO_OCTAL) + && cc == L'\\' && psz[0] == L'\\' ) + { + if (buf) + *buf++ = (char)cc; + psz++; + len++; + } + else if ( (m_options & MAP_INVALID_UTF8_TO_OCTAL) && + cc == L'\\' && + isoctal(psz[0]) && isoctal(psz[1]) && isoctal(psz[2]) ) + { + if (buf) + { + *buf++ = (char) ((psz[0] - L'0') * 0100 + + (psz[1] - L'0') * 010 + + (psz[2] - L'0')); + } + + psz += 3; + len++; + } + else + { + unsigned cnt; + for (cnt = 0; cc > utf8_max[cnt]; cnt++) + { + } + + if (!cnt) + { + // plain ASCII char + if (buf) + *buf++ = (char) cc; + len++; + } + else + { + len += cnt + 1; + if (buf) + { + *buf++ = (char) ((-128 >> cnt) | ((cc >> (cnt * 6)) & (0x3f >> cnt))); + while (cnt--) + *buf++ = (char) (0x80 | ((cc >> (cnt * 6)) & 0x3f)); + } + } + } + } + + if (buf && (len < n)) + *buf = 0; + + return len; +} + +// ============================================================================ +// UTF-16 +// ============================================================================ + +#ifdef WORDS_BIGENDIAN + #define wxMBConvUTF16straight wxMBConvUTF16BE + #define wxMBConvUTF16swap wxMBConvUTF16LE +#else + #define wxMBConvUTF16swap wxMBConvUTF16BE + #define wxMBConvUTF16straight wxMBConvUTF16LE +#endif + +/* static */ +size_t wxMBConvUTF16Base::GetLength(const char *src, size_t srcLen) +{ + if ( srcLen == wxNO_LEN ) + { + // count the number of bytes in input, including the trailing NULs + const wxUint16 *inBuff = wx_reinterpret_cast(const wxUint16 *, src); + for ( srcLen = 1; *inBuff++; srcLen++ ) + ; + + srcLen *= BYTES_PER_CHAR; + } + else // we already have the length + { + // we can only convert an entire number of UTF-16 characters + if ( srcLen % BYTES_PER_CHAR ) + return wxCONV_FAILED; + } + + return srcLen; +} + +// case when in-memory representation is UTF-16 too +#ifdef WC_UTF16 + +// ---------------------------------------------------------------------------- +// conversions without endianness change +// ---------------------------------------------------------------------------- + +size_t +wxMBConvUTF16straight::ToWChar(wchar_t *dst, size_t dstLen, + const char *src, size_t srcLen) const +{ + // set up the scene for using memcpy() (which is presumably more efficient + // than copying the bytes one by one) + srcLen = GetLength(src, srcLen); + if ( srcLen == wxNO_LEN ) + return wxCONV_FAILED; + + const size_t inLen = srcLen / BYTES_PER_CHAR; + if ( dst ) + { + if ( dstLen < inLen ) + return wxCONV_FAILED; + + memcpy(dst, src, srcLen); + } + + return inLen; +} + +size_t +wxMBConvUTF16straight::FromWChar(char *dst, size_t dstLen, + const wchar_t *src, size_t srcLen) const +{ + if ( srcLen == wxNO_LEN ) + srcLen = wxWcslen(src) + 1; + + srcLen *= BYTES_PER_CHAR; + + if ( dst ) + { + if ( dstLen < srcLen ) + return wxCONV_FAILED; + + memcpy(dst, src, srcLen); + } + + return srcLen; +} + +// ---------------------------------------------------------------------------- +// endian-reversing conversions +// ---------------------------------------------------------------------------- + +size_t +wxMBConvUTF16swap::ToWChar(wchar_t *dst, size_t dstLen, + const char *src, size_t srcLen) const +{ + srcLen = GetLength(src, srcLen); + if ( srcLen == wxNO_LEN ) + return wxCONV_FAILED; + + srcLen /= BYTES_PER_CHAR; + + if ( dst ) + { + if ( dstLen < srcLen ) + return wxCONV_FAILED; + + const wxUint16 *inBuff = wx_reinterpret_cast(const wxUint16 *, src); + for ( size_t n = 0; n < srcLen; n++, inBuff++ ) + { + *dst++ = wxUINT16_SWAP_ALWAYS(*inBuff); + } + } + + return srcLen; +} + +size_t +wxMBConvUTF16swap::FromWChar(char *dst, size_t dstLen, + const wchar_t *src, size_t srcLen) const +{ + if ( srcLen == wxNO_LEN ) + srcLen = wxWcslen(src) + 1; + + srcLen *= BYTES_PER_CHAR; + + if ( dst ) + { + if ( dstLen < srcLen ) + return wxCONV_FAILED; + + wxUint16 *outBuff = wx_reinterpret_cast(wxUint16 *, dst); + for ( size_t n = 0; n < srcLen; n += BYTES_PER_CHAR, src++ ) + { + *outBuff++ = wxUINT16_SWAP_ALWAYS(*src); + } + } + + return srcLen; +} + +#else // !WC_UTF16: wchar_t is UTF-32 + +// ---------------------------------------------------------------------------- +// conversions without endianness change +// ---------------------------------------------------------------------------- + +size_t +wxMBConvUTF16straight::ToWChar(wchar_t *dst, size_t dstLen, + const char *src, size_t srcLen) const +{ + srcLen = GetLength(src, srcLen); + if ( srcLen == wxNO_LEN ) + return wxCONV_FAILED; + + const size_t inLen = srcLen / BYTES_PER_CHAR; + if ( !dst ) + { + // optimization: return maximal space which could be needed for this + // string even if the real size could be smaller if the buffer contains + // any surrogates + return inLen; + } + + size_t outLen = 0; + const wxUint16 *inBuff = wx_reinterpret_cast(const wxUint16 *, src); + for ( const wxUint16 * const inEnd = inBuff + inLen; inBuff < inEnd; ) + { + const wxUint32 ch = wxDecodeSurrogate(&inBuff); + if ( !inBuff ) + return wxCONV_FAILED; + + if ( ++outLen > dstLen ) + return wxCONV_FAILED; + + *dst++ = ch; + } + + + return outLen; +} + +size_t +wxMBConvUTF16straight::FromWChar(char *dst, size_t dstLen, + const wchar_t *src, size_t srcLen) const +{ + if ( srcLen == wxNO_LEN ) + srcLen = wxWcslen(src) + 1; + + size_t outLen = 0; + wxUint16 *outBuff = wx_reinterpret_cast(wxUint16 *, dst); + for ( size_t n = 0; n < srcLen; n++ ) + { + wxUint16 cc[2]; + const size_t numChars = encode_utf16(*src++, cc); + if ( numChars == wxCONV_FAILED ) + return wxCONV_FAILED; + + outLen += numChars * BYTES_PER_CHAR; + if ( outBuff ) + { + if ( outLen > dstLen ) + return wxCONV_FAILED; + + *outBuff++ = cc[0]; + if ( numChars == 2 ) + { + // second character of a surrogate + *outBuff++ = cc[1]; + } + } + } + + return outLen; +} + +// ---------------------------------------------------------------------------- +// endian-reversing conversions +// ---------------------------------------------------------------------------- + +size_t +wxMBConvUTF16swap::ToWChar(wchar_t *dst, size_t dstLen, + const char *src, size_t srcLen) const +{ + srcLen = GetLength(src, srcLen); + if ( srcLen == wxNO_LEN ) + return wxCONV_FAILED; + + const size_t inLen = srcLen / BYTES_PER_CHAR; + if ( !dst ) + { + // optimization: return maximal space which could be needed for this + // string even if the real size could be smaller if the buffer contains + // any surrogates + return inLen; + } + + size_t outLen = 0; + const wxUint16 *inBuff = wx_reinterpret_cast(const wxUint16 *, src); + for ( const wxUint16 * const inEnd = inBuff + inLen; inBuff < inEnd; ) + { + wxUint32 ch; + wxUint16 tmp[2]; + + tmp[0] = wxUINT16_SWAP_ALWAYS(*inBuff); + inBuff++; + tmp[1] = wxUINT16_SWAP_ALWAYS(*inBuff); + + const size_t numChars = decode_utf16(tmp, ch); + if ( numChars == wxCONV_FAILED ) + return wxCONV_FAILED; + + if ( numChars == 2 ) + inBuff++; + + if ( ++outLen > dstLen ) + return wxCONV_FAILED; + + *dst++ = ch; + } + + + return outLen; +} + +size_t +wxMBConvUTF16swap::FromWChar(char *dst, size_t dstLen, + const wchar_t *src, size_t srcLen) const +{ + if ( srcLen == wxNO_LEN ) + srcLen = wxWcslen(src) + 1; + + size_t outLen = 0; + wxUint16 *outBuff = wx_reinterpret_cast(wxUint16 *, dst); + for ( const wchar_t *srcEnd = src + srcLen; src < srcEnd; src++ ) + { + wxUint16 cc[2]; + const size_t numChars = encode_utf16(*src, cc); + if ( numChars == wxCONV_FAILED ) + return wxCONV_FAILED; + + outLen += numChars * BYTES_PER_CHAR; + if ( outBuff ) + { + if ( outLen > dstLen ) + return wxCONV_FAILED; + + *outBuff++ = wxUINT16_SWAP_ALWAYS(cc[0]); + if ( numChars == 2 ) + { + // second character of a surrogate + *outBuff++ = wxUINT16_SWAP_ALWAYS(cc[1]); + } + } + } + + return outLen; +} + +#endif // WC_UTF16/!WC_UTF16 + + +// ============================================================================ +// UTF-32 +// ============================================================================ + +#ifdef WORDS_BIGENDIAN + #define wxMBConvUTF32straight wxMBConvUTF32BE + #define wxMBConvUTF32swap wxMBConvUTF32LE +#else + #define wxMBConvUTF32swap wxMBConvUTF32BE + #define wxMBConvUTF32straight wxMBConvUTF32LE +#endif + + +WXDLLIMPEXP_DATA_BASE(wxMBConvUTF32LE) wxConvUTF32LE; +WXDLLIMPEXP_DATA_BASE(wxMBConvUTF32BE) wxConvUTF32BE; + +/* static */ +size_t wxMBConvUTF32Base::GetLength(const char *src, size_t srcLen) +{ + if ( srcLen == wxNO_LEN ) + { + // count the number of bytes in input, including the trailing NULs + const wxUint32 *inBuff = wx_reinterpret_cast(const wxUint32 *, src); + for ( srcLen = 1; *inBuff++; srcLen++ ) + ; + + srcLen *= BYTES_PER_CHAR; + } + else // we already have the length + { + // we can only convert an entire number of UTF-32 characters + if ( srcLen % BYTES_PER_CHAR ) + return wxCONV_FAILED; + } + + return srcLen; +} + +// case when in-memory representation is UTF-16 +#ifdef WC_UTF16 + +// ---------------------------------------------------------------------------- +// conversions without endianness change +// ---------------------------------------------------------------------------- + +size_t +wxMBConvUTF32straight::ToWChar(wchar_t *dst, size_t dstLen, + const char *src, size_t srcLen) const +{ + srcLen = GetLength(src, srcLen); + if ( srcLen == wxNO_LEN ) + return wxCONV_FAILED; + + const wxUint32 *inBuff = wx_reinterpret_cast(const wxUint32 *, src); + const size_t inLen = srcLen / BYTES_PER_CHAR; + size_t outLen = 0; + for ( size_t n = 0; n < inLen; n++ ) + { + wxUint16 cc[2]; + const size_t numChars = encode_utf16(*inBuff++, cc); + if ( numChars == wxCONV_FAILED ) + return wxCONV_FAILED; + + outLen += numChars; + if ( dst ) + { + if ( outLen > dstLen ) + return wxCONV_FAILED; + + *dst++ = cc[0]; + if ( numChars == 2 ) + { + // second character of a surrogate + *dst++ = cc[1]; + } + } + } + + return outLen; +} + +size_t +wxMBConvUTF32straight::FromWChar(char *dst, size_t dstLen, + const wchar_t *src, size_t srcLen) const +{ + if ( srcLen == wxNO_LEN ) + srcLen = wxWcslen(src) + 1; + + if ( !dst ) + { + // optimization: return maximal space which could be needed for this + // string instead of the exact amount which could be less if there are + // any surrogates in the input + // + // we consider that surrogates are rare enough to make it worthwhile to + // avoid running the loop below at the cost of slightly extra memory + // consumption + return srcLen * BYTES_PER_CHAR; + } + + wxUint32 *outBuff = wx_reinterpret_cast(wxUint32 *, dst); + size_t outLen = 0; + for ( const wchar_t * const srcEnd = src + srcLen; src < srcEnd; ) + { + const wxUint32 ch = wxDecodeSurrogate(&src); + if ( !src ) + return wxCONV_FAILED; + + outLen += BYTES_PER_CHAR; + + if ( outLen > dstLen ) + return wxCONV_FAILED; + + *outBuff++ = ch; + } + + return outLen; +} + +// ---------------------------------------------------------------------------- +// endian-reversing conversions +// ---------------------------------------------------------------------------- + +size_t +wxMBConvUTF32swap::ToWChar(wchar_t *dst, size_t dstLen, + const char *src, size_t srcLen) const +{ + srcLen = GetLength(src, srcLen); + if ( srcLen == wxNO_LEN ) + return wxCONV_FAILED; + + const wxUint32 *inBuff = wx_reinterpret_cast(const wxUint32 *, src); + const size_t inLen = srcLen / BYTES_PER_CHAR; + size_t outLen = 0; + for ( size_t n = 0; n < inLen; n++, inBuff++ ) + { + wxUint16 cc[2]; + const size_t numChars = encode_utf16(wxUINT32_SWAP_ALWAYS(*inBuff), cc); + if ( numChars == wxCONV_FAILED ) + return wxCONV_FAILED; + + outLen += numChars; + if ( dst ) + { + if ( outLen > dstLen ) + return wxCONV_FAILED; + + *dst++ = cc[0]; + if ( numChars == 2 ) + { + // second character of a surrogate + *dst++ = cc[1]; + } + } + } + + return outLen; +} + +size_t +wxMBConvUTF32swap::FromWChar(char *dst, size_t dstLen, + const wchar_t *src, size_t srcLen) const +{ + if ( srcLen == wxNO_LEN ) + srcLen = wxWcslen(src) + 1; + + if ( !dst ) + { + // optimization: return maximal space which could be needed for this + // string instead of the exact amount which could be less if there are + // any surrogates in the input + // + // we consider that surrogates are rare enough to make it worthwhile to + // avoid running the loop below at the cost of slightly extra memory + // consumption + return srcLen*BYTES_PER_CHAR; + } + + wxUint32 *outBuff = wx_reinterpret_cast(wxUint32 *, dst); + size_t outLen = 0; + for ( const wchar_t * const srcEnd = src + srcLen; src < srcEnd; ) + { + const wxUint32 ch = wxDecodeSurrogate(&src); + if ( !src ) + return wxCONV_FAILED; + + outLen += BYTES_PER_CHAR; + + if ( outLen > dstLen ) + return wxCONV_FAILED; + + *outBuff++ = wxUINT32_SWAP_ALWAYS(ch); + } + + return outLen; +} + +#else // !WC_UTF16: wchar_t is UTF-32 + +// ---------------------------------------------------------------------------- +// conversions without endianness change +// ---------------------------------------------------------------------------- + +size_t +wxMBConvUTF32straight::ToWChar(wchar_t *dst, size_t dstLen, + const char *src, size_t srcLen) const +{ + // use memcpy() as it should be much faster than hand-written loop + srcLen = GetLength(src, srcLen); + if ( srcLen == wxNO_LEN ) + return wxCONV_FAILED; + + const size_t inLen = srcLen/BYTES_PER_CHAR; + if ( dst ) + { + if ( dstLen < inLen ) + return wxCONV_FAILED; + + memcpy(dst, src, srcLen); + } + + return inLen; +} + +size_t +wxMBConvUTF32straight::FromWChar(char *dst, size_t dstLen, + const wchar_t *src, size_t srcLen) const +{ + if ( srcLen == wxNO_LEN ) + srcLen = wxWcslen(src) + 1; + + srcLen *= BYTES_PER_CHAR; + + if ( dst ) + { + if ( dstLen < srcLen ) + return wxCONV_FAILED; + + memcpy(dst, src, srcLen); + } + + return srcLen; +} + +// ---------------------------------------------------------------------------- +// endian-reversing conversions +// ---------------------------------------------------------------------------- + +size_t +wxMBConvUTF32swap::ToWChar(wchar_t *dst, size_t dstLen, + const char *src, size_t srcLen) const +{ + srcLen = GetLength(src, srcLen); + if ( srcLen == wxNO_LEN ) + return wxCONV_FAILED; + + srcLen /= BYTES_PER_CHAR; + + if ( dst ) + { + if ( dstLen < srcLen ) + return wxCONV_FAILED; + + const wxUint32 *inBuff = wx_reinterpret_cast(const wxUint32 *, src); + for ( size_t n = 0; n < srcLen; n++, inBuff++ ) + { + *dst++ = wxUINT32_SWAP_ALWAYS(*inBuff); + } + } + + return srcLen; +} + +size_t +wxMBConvUTF32swap::FromWChar(char *dst, size_t dstLen, + const wchar_t *src, size_t srcLen) const +{ + if ( srcLen == wxNO_LEN ) + srcLen = wxWcslen(src) + 1; + + srcLen *= BYTES_PER_CHAR; + + if ( dst ) + { + if ( dstLen < srcLen ) + return wxCONV_FAILED; + + wxUint32 *outBuff = wx_reinterpret_cast(wxUint32 *, dst); + for ( size_t n = 0; n < srcLen; n += BYTES_PER_CHAR, src++ ) + { + *outBuff++ = wxUINT32_SWAP_ALWAYS(*src); + } + } + + return srcLen; +} + +#endif // WC_UTF16/!WC_UTF16 + + +// ============================================================================ +// The classes doing conversion using the iconv_xxx() functions +// ============================================================================ + +#ifdef HAVE_ICONV + +// VS: glibc 2.1.3 is broken in that iconv() conversion to/from UCS4 fails with +// E2BIG if output buffer is _exactly_ as big as needed. Such case is +// (unless there's yet another bug in glibc) the only case when iconv() +// returns with (size_t)-1 (which means error) and says there are 0 bytes +// left in the input buffer -- when _real_ error occurs, +// bytes-left-in-input buffer is non-zero. Hence, this alternative test for +// iconv() failure. +// [This bug does not appear in glibc 2.2.] +#if defined(__GLIBC__) && __GLIBC__ == 2 && __GLIBC_MINOR__ <= 1 +#define ICONV_FAILED(cres, bufLeft) ((cres == (size_t)-1) && \ + (errno != E2BIG || bufLeft != 0)) +#else +#define ICONV_FAILED(cres, bufLeft) (cres == (size_t)-1) +#endif + +#define ICONV_CHAR_CAST(x) ((ICONV_CONST char **)(x)) + +#define ICONV_T_INVALID ((iconv_t)-1) + +#if SIZEOF_WCHAR_T == 4 + #define WC_BSWAP wxUINT32_SWAP_ALWAYS + #define WC_ENC wxFONTENCODING_UTF32 +#elif SIZEOF_WCHAR_T == 2 + #define WC_BSWAP wxUINT16_SWAP_ALWAYS + #define WC_ENC wxFONTENCODING_UTF16 +#else // sizeof(wchar_t) != 2 nor 4 + // does this ever happen? + #error "Unknown sizeof(wchar_t): please report this to wx-dev@lists.wxwindows.org" +#endif + +// ---------------------------------------------------------------------------- +// wxMBConv_iconv: encapsulates an iconv character set +// ---------------------------------------------------------------------------- + +class wxMBConv_iconv : public wxMBConv +{ +public: + wxMBConv_iconv(const wxChar *name); + virtual ~wxMBConv_iconv(); + + virtual size_t MB2WC(wchar_t *buf, const char *psz, size_t n) const; + virtual size_t WC2MB(char *buf, const wchar_t *psz, size_t n) const; + + // classify this encoding as explained in wxMBConv::GetMBNulLen() comment + virtual size_t GetMBNulLen() const; + + virtual wxMBConv *Clone() const + { + wxMBConv_iconv *p = new wxMBConv_iconv(m_name); + p->m_minMBCharWidth = m_minMBCharWidth; + return p; + } + + bool IsOk() const + { return (m2w != ICONV_T_INVALID) && (w2m != ICONV_T_INVALID); } + +protected: + // the iconv handlers used to translate from multibyte + // to wide char and in the other direction + iconv_t m2w, + w2m; + +#if wxUSE_THREADS + // guards access to m2w and w2m objects + wxMutex m_iconvMutex; +#endif + +private: + // the name (for iconv_open()) of a wide char charset -- if none is + // available on this machine, it will remain NULL + static wxString ms_wcCharsetName; + + // true if the wide char encoding we use (i.e. ms_wcCharsetName) has + // different endian-ness than the native one + static bool ms_wcNeedsSwap; + + + // name of the encoding handled by this conversion + wxString m_name; + + // cached result of GetMBNulLen(); set to 0 meaning "unknown" + // initially + size_t m_minMBCharWidth; +}; + +// make the constructor available for unit testing +WXDLLIMPEXP_BASE wxMBConv* new_wxMBConv_iconv( const wxChar* name ) +{ + wxMBConv_iconv* result = new wxMBConv_iconv( name ); + if ( !result->IsOk() ) + { + delete result; + return 0; + } + + return result; +} + +wxString wxMBConv_iconv::ms_wcCharsetName; +bool wxMBConv_iconv::ms_wcNeedsSwap = false; + +wxMBConv_iconv::wxMBConv_iconv(const wxChar *name) + : m_name(name) +{ + m_minMBCharWidth = 0; + + // iconv operates with chars, not wxChars, but luckily it uses only ASCII + // names for the charsets + const wxCharBuffer cname(wxString(name).ToAscii()); + + // check for charset that represents wchar_t: + if ( ms_wcCharsetName.empty() ) + { + wxLogTrace(TRACE_STRCONV, _T("Looking for wide char codeset:")); + +#if wxUSE_FONTMAP + const wxChar **names = wxFontMapperBase::GetAllEncodingNames(WC_ENC); +#else // !wxUSE_FONTMAP + static const wxChar *names_static[] = + { +#if SIZEOF_WCHAR_T == 4 + _T("UCS-4"), +#elif SIZEOF_WCHAR_T = 2 + _T("UCS-2"), +#endif + NULL + }; + const wxChar **names = names_static; +#endif // wxUSE_FONTMAP/!wxUSE_FONTMAP + + for ( ; *names && ms_wcCharsetName.empty(); ++names ) + { + const wxString nameCS(*names); + + // first try charset with explicit bytesex info (e.g. "UCS-4LE"): + wxString nameXE(nameCS); + +#ifdef WORDS_BIGENDIAN + nameXE += _T("BE"); +#else // little endian + nameXE += _T("LE"); +#endif + + wxLogTrace(TRACE_STRCONV, _T(" trying charset \"%s\""), + nameXE.c_str()); + + m2w = iconv_open(nameXE.ToAscii(), cname); + if ( m2w == ICONV_T_INVALID ) + { + // try charset w/o bytesex info (e.g. "UCS4") + wxLogTrace(TRACE_STRCONV, _T(" trying charset \"%s\""), + nameCS.c_str()); + m2w = iconv_open(nameCS.ToAscii(), cname); + + // and check for bytesex ourselves: + if ( m2w != ICONV_T_INVALID ) + { + char buf[2], *bufPtr; + wchar_t wbuf[2], *wbufPtr; + size_t insz, outsz; + size_t res; + + buf[0] = 'A'; + buf[1] = 0; + wbuf[0] = 0; + insz = 2; + outsz = SIZEOF_WCHAR_T * 2; + wbufPtr = wbuf; + bufPtr = buf; + + res = iconv( + m2w, ICONV_CHAR_CAST(&bufPtr), &insz, + (char**)&wbufPtr, &outsz); + + if (ICONV_FAILED(res, insz)) + { + wxLogLastError(wxT("iconv")); + wxLogError(_("Conversion to charset '%s' doesn't work."), + nameCS.c_str()); + } + else // ok, can convert to this encoding, remember it + { + ms_wcCharsetName = nameCS; + ms_wcNeedsSwap = wbuf[0] != (wchar_t)buf[0]; + } + } + } + else // use charset not requiring byte swapping + { + ms_wcCharsetName = nameXE; + } + } + + wxLogTrace(TRACE_STRCONV, + wxT("iconv wchar_t charset is \"%s\"%s"), + ms_wcCharsetName.empty() ? _T("") + : ms_wcCharsetName.c_str(), + ms_wcNeedsSwap ? _T(" (needs swap)") + : _T("")); + } + else // we already have ms_wcCharsetName + { + m2w = iconv_open(ms_wcCharsetName.ToAscii(), cname); + } + + if ( ms_wcCharsetName.empty() ) + { + w2m = ICONV_T_INVALID; + } + else + { + w2m = iconv_open(cname, ms_wcCharsetName.ToAscii()); + if ( w2m == ICONV_T_INVALID ) + { + wxLogTrace(TRACE_STRCONV, + wxT("\"%s\" -> \"%s\" works but not the converse!?"), + ms_wcCharsetName.c_str(), cname.data()); + } + } +} + +wxMBConv_iconv::~wxMBConv_iconv() +{ + if ( m2w != ICONV_T_INVALID ) + iconv_close(m2w); + if ( w2m != ICONV_T_INVALID ) + iconv_close(w2m); +} + +size_t wxMBConv_iconv::MB2WC(wchar_t *buf, const char *psz, size_t n) const +{ + // find the string length: notice that must be done differently for + // NUL-terminated strings and UTF-16/32 which are terminated with 2/4 NULs + size_t inbuf; + const size_t nulLen = GetMBNulLen(); + switch ( nulLen ) + { + default: + return wxCONV_FAILED; + + case 1: + inbuf = strlen(psz); // arguably more optimized than our version + break; + + case 2: + case 4: + // for UTF-16/32 not only we need to have 2/4 consecutive NULs but + // they also have to start at character boundary and not span two + // adjacent characters + const char *p; + for ( p = psz; NotAllNULs(p, nulLen); p += nulLen ) + ; + inbuf = p - psz; + break; + } + +#if wxUSE_THREADS + // NB: iconv() is MT-safe, but each thread must use its own iconv_t handle. + // Unfortunately there are a couple of global wxCSConv objects such as + // wxConvLocal that are used all over wx code, so we have to make sure + // the handle is used by at most one thread at the time. Otherwise + // only a few wx classes would be safe to use from non-main threads + // as MB<->WC conversion would fail "randomly". + wxMutexLocker lock(wxConstCast(this, wxMBConv_iconv)->m_iconvMutex); +#endif // wxUSE_THREADS + + size_t outbuf = n * SIZEOF_WCHAR_T; + size_t res, cres; + // VS: Use these instead of psz, buf because iconv() modifies its arguments: + wchar_t *bufPtr = buf; + const char *pszPtr = psz; + + if (buf) + { + // have destination buffer, convert there + cres = iconv(m2w, + ICONV_CHAR_CAST(&pszPtr), &inbuf, + (char**)&bufPtr, &outbuf); + res = n - (outbuf / SIZEOF_WCHAR_T); + + if (ms_wcNeedsSwap) + { + // convert to native endianness + for ( unsigned i = 0; i < res; i++ ) + buf[n] = WC_BSWAP(buf[i]); + } + + // NUL-terminate the string if there is any space left + if (res < n) + buf[res] = 0; + } + else + { + // no destination buffer... convert using temp buffer + // to calculate destination buffer requirement + wchar_t tbuf[8]; + res = 0; + + do + { + bufPtr = tbuf; + outbuf = 8 * SIZEOF_WCHAR_T; + + cres = iconv(m2w, + ICONV_CHAR_CAST(&pszPtr), &inbuf, + (char**)&bufPtr, &outbuf ); + + res += 8 - (outbuf / SIZEOF_WCHAR_T); + } + while ((cres == (size_t)-1) && (errno == E2BIG)); + } + + if (ICONV_FAILED(cres, inbuf)) + { + //VS: it is ok if iconv fails, hence trace only + wxLogTrace(TRACE_STRCONV, wxT("iconv failed: %s"), wxSysErrorMsg(wxSysErrorCode())); + return wxCONV_FAILED; + } + + return res; +} + +size_t wxMBConv_iconv::WC2MB(char *buf, const wchar_t *psz, size_t n) const +{ +#if wxUSE_THREADS + // NB: explained in MB2WC + wxMutexLocker lock(wxConstCast(this, wxMBConv_iconv)->m_iconvMutex); +#endif + + size_t inlen = wxWcslen(psz); + size_t inbuf = inlen * SIZEOF_WCHAR_T; + size_t outbuf = n; + size_t res, cres; + + wchar_t *tmpbuf = 0; + + if (ms_wcNeedsSwap) + { + // need to copy to temp buffer to switch endianness + // (doing WC_BSWAP twice on the original buffer won't help, as it + // could be in read-only memory, or be accessed in some other thread) + tmpbuf = (wchar_t *)malloc(inbuf + SIZEOF_WCHAR_T); + for ( size_t i = 0; i < inlen; i++ ) + tmpbuf[n] = WC_BSWAP(psz[i]); + + tmpbuf[inlen] = L'\0'; + psz = tmpbuf; + } + + if (buf) + { + // have destination buffer, convert there + cres = iconv( w2m, ICONV_CHAR_CAST(&psz), &inbuf, &buf, &outbuf ); + + res = n - outbuf; + + // NB: iconv was given only wcslen(psz) characters on input, and so + // it couldn't convert the trailing zero. Let's do it ourselves + // if there's some room left for it in the output buffer. + if (res < n) + buf[0] = 0; + } + else + { + // no destination buffer: convert using temp buffer + // to calculate destination buffer requirement + char tbuf[16]; + res = 0; + do + { + buf = tbuf; + outbuf = 16; + + cres = iconv( w2m, ICONV_CHAR_CAST(&psz), &inbuf, &buf, &outbuf ); + + res += 16 - outbuf; + } + while ((cres == (size_t)-1) && (errno == E2BIG)); + } + + if (ms_wcNeedsSwap) + { + free(tmpbuf); + } + + if (ICONV_FAILED(cres, inbuf)) + { + wxLogTrace(TRACE_STRCONV, wxT("iconv failed: %s"), wxSysErrorMsg(wxSysErrorCode())); + return wxCONV_FAILED; + } + + return res; +} + +size_t wxMBConv_iconv::GetMBNulLen() const +{ + if ( m_minMBCharWidth == 0 ) + { + wxMBConv_iconv * const self = wxConstCast(this, wxMBConv_iconv); + +#if wxUSE_THREADS + // NB: explained in MB2WC + wxMutexLocker lock(self->m_iconvMutex); +#endif + + wchar_t *wnul = L""; + char buf[8]; // should be enough for NUL in any encoding + size_t inLen = sizeof(wchar_t), + outLen = WXSIZEOF(buf); + char *inBuff = (char *)wnul; + char *outBuff = buf; + if ( iconv(w2m, ICONV_CHAR_CAST(&inBuff), &inLen, &outBuff, &outLen) == (size_t)-1 ) + { + self->m_minMBCharWidth = (size_t)-1; + } + else // ok + { + self->m_minMBCharWidth = outBuff - buf; + } + } + + return m_minMBCharWidth; +} + +#endif // HAVE_ICONV + + +// ============================================================================ +// Win32 conversion classes +// ============================================================================ + +#ifdef wxHAVE_WIN32_MB2WC + +// from utils.cpp +#if wxUSE_FONTMAP +extern WXDLLIMPEXP_BASE long wxCharsetToCodepage(const wxChar *charset); +extern WXDLLIMPEXP_BASE long wxEncodingToCodepage(wxFontEncoding encoding); +#endif + +class wxMBConv_win32 : public wxMBConv +{ +public: + wxMBConv_win32() + { + m_CodePage = CP_ACP; + m_minMBCharWidth = 0; + } + + wxMBConv_win32(const wxMBConv_win32& conv) + : wxMBConv() + { + m_CodePage = conv.m_CodePage; + m_minMBCharWidth = conv.m_minMBCharWidth; + } + +#if wxUSE_FONTMAP + wxMBConv_win32(const wxChar* name) + { + m_CodePage = wxCharsetToCodepage(name); + m_minMBCharWidth = 0; + } + + wxMBConv_win32(wxFontEncoding encoding) + { + m_CodePage = wxEncodingToCodepage(encoding); + m_minMBCharWidth = 0; + } +#endif // wxUSE_FONTMAP + + virtual size_t MB2WC(wchar_t *buf, const char *psz, size_t n) const + { + // note that we have to use MB_ERR_INVALID_CHARS flag as it without it + // the behaviour is not compatible with the Unix version (using iconv) + // and break the library itself, e.g. wxTextInputStream::NextChar() + // wouldn't work if reading an incomplete MB char didn't result in an + // error + // + // Moreover, MB_ERR_INVALID_CHARS is only supported on Win 2K SP4 or + // Win XP or newer and it is not supported for UTF-[78] so we always + // use our own conversions in this case. See + // http://blogs.msdn.com/michkap/archive/2005/04/19/409566.aspx + // http://msdn.microsoft.com/library/en-us/intl/unicode_17si.asp + if ( m_CodePage == CP_UTF8 ) + { + return wxConvUTF8.MB2WC(buf, psz, n); + } + + if ( m_CodePage == CP_UTF7 ) + { + return wxConvUTF7.MB2WC(buf, psz, n); + } + + int flags = 0; + if ( (m_CodePage < 50000 && m_CodePage != CP_SYMBOL) && + IsAtLeastWin2kSP4() ) + { + flags = MB_ERR_INVALID_CHARS; + } + + const size_t len = ::MultiByteToWideChar + ( + m_CodePage, // code page + flags, // flags: fall on error + psz, // input string + -1, // its length (NUL-terminated) + buf, // output string + buf ? n : 0 // size of output buffer + ); + if ( !len ) + { + // function totally failed + return wxCONV_FAILED; + } + + // if we were really converting and didn't use MB_ERR_INVALID_CHARS, + // check if we succeeded, by doing a double trip: + if ( !flags && buf ) + { + const size_t mbLen = strlen(psz); + wxCharBuffer mbBuf(mbLen); + if ( ::WideCharToMultiByte + ( + m_CodePage, + 0, + buf, + -1, + mbBuf.data(), + mbLen + 1, // size in bytes, not length + NULL, + NULL + ) == 0 || + strcmp(mbBuf, psz) != 0 ) + { + // we didn't obtain the same thing we started from, hence + // the conversion was lossy and we consider that it failed + return wxCONV_FAILED; + } + } + + // note that it returns count of written chars for buf != NULL and size + // of the needed buffer for buf == NULL so in either case the length of + // the string (which never includes the terminating NUL) is one less + return len - 1; + } + + virtual size_t WC2MB(char *buf, const wchar_t *pwz, size_t n) const + { + /* + we have a problem here: by default, WideCharToMultiByte() may + replace characters unrepresentable in the target code page with bad + quality approximations such as turning "1/2" symbol (U+00BD) into + "1" for the code pages which don't have it and we, obviously, want + to avoid this at any price + + the trouble is that this function does it _silently_, i.e. it won't + even tell us whether it did or not... Win98/2000 and higher provide + WC_NO_BEST_FIT_CHARS but it doesn't work for the older systems and + we have to resort to a round trip, i.e. check that converting back + results in the same string -- this is, of course, expensive but + otherwise we simply can't be sure to not garble the data. + */ + + // determine if we can rely on WC_NO_BEST_FIT_CHARS: according to MSDN + // it doesn't work with CJK encodings (which we test for rather roughly + // here...) nor with UTF-7/8 nor, of course, with Windows versions not + // supporting it + BOOL usedDef wxDUMMY_INITIALIZE(false); + BOOL *pUsedDef; + int flags; + if ( CanUseNoBestFit() && m_CodePage < 50000 ) + { + // it's our lucky day + flags = WC_NO_BEST_FIT_CHARS; + pUsedDef = &usedDef; + } + else // old system or unsupported encoding + { + flags = 0; + pUsedDef = NULL; + } + + const size_t len = ::WideCharToMultiByte + ( + m_CodePage, // code page + flags, // either none or no best fit + pwz, // input string + -1, // it is (wide) NUL-terminated + buf, // output buffer + buf ? n : 0, // and its size + NULL, // default "replacement" char + pUsedDef // [out] was it used? + ); + + if ( !len ) + { + // function totally failed + return wxCONV_FAILED; + } + + // if we were really converting, check if we succeeded + if ( buf ) + { + if ( flags ) + { + // check if the conversion failed, i.e. if any replacements + // were done + if ( usedDef ) + return wxCONV_FAILED; + } + else // we must resort to double tripping... + { + wxWCharBuffer wcBuf(n); + if ( MB2WC(wcBuf.data(), buf, n) == wxCONV_FAILED || + wcscmp(wcBuf, pwz) != 0 ) + { + // we didn't obtain the same thing we started from, hence + // the conversion was lossy and we consider that it failed + return wxCONV_FAILED; + } + } + } + + // see the comment above for the reason of "len - 1" + return len - 1; + } + + virtual size_t GetMBNulLen() const + { + if ( m_minMBCharWidth == 0 ) + { + int len = ::WideCharToMultiByte + ( + m_CodePage, // code page + 0, // no flags + L"", // input string + 1, // translate just the NUL + NULL, // output buffer + 0, // and its size + NULL, // no replacement char + NULL // [out] don't care if it was used + ); + + wxMBConv_win32 * const self = wxConstCast(this, wxMBConv_win32); + switch ( len ) + { + default: + wxLogDebug(_T("Unexpected NUL length %d"), len); + self->m_minMBCharWidth = (size_t)-1; + break; + + case 0: + self->m_minMBCharWidth = (size_t)-1; + break; + + case 1: + case 2: + case 4: + self->m_minMBCharWidth = len; + break; + } + } + + return m_minMBCharWidth; + } + + virtual wxMBConv *Clone() const { return new wxMBConv_win32(*this); } + + bool IsOk() const { return m_CodePage != -1; } + +private: + static bool CanUseNoBestFit() + { + static int s_isWin98Or2k = -1; + + if ( s_isWin98Or2k == -1 ) + { + int verMaj, verMin; + switch ( wxGetOsVersion(&verMaj, &verMin) ) + { + case wxOS_WINDOWS_9X: + s_isWin98Or2k = verMaj >= 4 && verMin >= 10; + break; + + case wxOS_WINDOWS_NT: + s_isWin98Or2k = verMaj >= 5; + break; + + default: + // unknown: be conservative by default + s_isWin98Or2k = 0; + break; + } + + wxASSERT_MSG( s_isWin98Or2k != -1, _T("should be set above") ); + } + + return s_isWin98Or2k == 1; + } + + static bool IsAtLeastWin2kSP4() + { +#ifdef __WXWINCE__ + return false; +#else + static int s_isAtLeastWin2kSP4 = -1; + + if ( s_isAtLeastWin2kSP4 == -1 ) + { + OSVERSIONINFOEX ver; + + memset(&ver, 0, sizeof(ver)); + ver.dwOSVersionInfoSize = sizeof(ver); + GetVersionEx((OSVERSIONINFO*)&ver); + + s_isAtLeastWin2kSP4 = + ((ver.dwMajorVersion > 5) || // Vista+ + (ver.dwMajorVersion == 5 && ver.dwMinorVersion > 0) || // XP/2003 + (ver.dwMajorVersion == 5 && ver.dwMinorVersion == 0 && + ver.wServicePackMajor >= 4)) // 2000 SP4+ + ? 1 : 0; + } + + return s_isAtLeastWin2kSP4 == 1; +#endif + } + + + // the code page we're working with + long m_CodePage; + + // cached result of GetMBNulLen(), set to 0 initially meaning + // "unknown" + size_t m_minMBCharWidth; +}; + +#endif // wxHAVE_WIN32_MB2WC + +// ============================================================================ +// Cocoa conversion classes +// ============================================================================ + +#if defined(__WXCOCOA__) + +// RN: There is no UTF-32 support in either Core Foundation or Cocoa. +// Strangely enough, internally Core Foundation uses +// UTF-32 internally quite a bit - its just not public (yet). + +#include +#include + +CFStringEncoding wxCFStringEncFromFontEnc(wxFontEncoding encoding) +{ + CFStringEncoding enc = kCFStringEncodingInvalidId ; + + switch (encoding) + { + case wxFONTENCODING_DEFAULT : + enc = CFStringGetSystemEncoding(); + break ; + + case wxFONTENCODING_ISO8859_1 : + enc = kCFStringEncodingISOLatin1 ; + break ; + case wxFONTENCODING_ISO8859_2 : + enc = kCFStringEncodingISOLatin2; + break ; + case wxFONTENCODING_ISO8859_3 : + enc = kCFStringEncodingISOLatin3 ; + break ; + case wxFONTENCODING_ISO8859_4 : + enc = kCFStringEncodingISOLatin4; + break ; + case wxFONTENCODING_ISO8859_5 : + enc = kCFStringEncodingISOLatinCyrillic; + break ; + case wxFONTENCODING_ISO8859_6 : + enc = kCFStringEncodingISOLatinArabic; + break ; + case wxFONTENCODING_ISO8859_7 : + enc = kCFStringEncodingISOLatinGreek; + break ; + case wxFONTENCODING_ISO8859_8 : + enc = kCFStringEncodingISOLatinHebrew; + break ; + case wxFONTENCODING_ISO8859_9 : + enc = kCFStringEncodingISOLatin5; + break ; + case wxFONTENCODING_ISO8859_10 : + enc = kCFStringEncodingISOLatin6; + break ; + case wxFONTENCODING_ISO8859_11 : + enc = kCFStringEncodingISOLatinThai; + break ; + case wxFONTENCODING_ISO8859_13 : + enc = kCFStringEncodingISOLatin7; + break ; + case wxFONTENCODING_ISO8859_14 : + enc = kCFStringEncodingISOLatin8; + break ; + case wxFONTENCODING_ISO8859_15 : + enc = kCFStringEncodingISOLatin9; + break ; + + case wxFONTENCODING_KOI8 : + enc = kCFStringEncodingKOI8_R; + break ; + case wxFONTENCODING_ALTERNATIVE : // MS-DOS CP866 + enc = kCFStringEncodingDOSRussian; + break ; + +// case wxFONTENCODING_BULGARIAN : +// enc = ; +// break ; + + case wxFONTENCODING_CP437 : + enc = kCFStringEncodingDOSLatinUS ; + break ; + case wxFONTENCODING_CP850 : + enc = kCFStringEncodingDOSLatin1; + break ; + case wxFONTENCODING_CP852 : + enc = kCFStringEncodingDOSLatin2; + break ; + case wxFONTENCODING_CP855 : + enc = kCFStringEncodingDOSCyrillic; + break ; + case wxFONTENCODING_CP866 : + enc = kCFStringEncodingDOSRussian ; + break ; + case wxFONTENCODING_CP874 : + enc = kCFStringEncodingDOSThai; + break ; + case wxFONTENCODING_CP932 : + enc = kCFStringEncodingDOSJapanese; + break ; + case wxFONTENCODING_CP936 : + enc = kCFStringEncodingDOSChineseSimplif ; + break ; + case wxFONTENCODING_CP949 : + enc = kCFStringEncodingDOSKorean; + break ; + case wxFONTENCODING_CP950 : + enc = kCFStringEncodingDOSChineseTrad; + break ; + case wxFONTENCODING_CP1250 : + enc = kCFStringEncodingWindowsLatin2; + break ; + case wxFONTENCODING_CP1251 : + enc = kCFStringEncodingWindowsCyrillic ; + break ; + case wxFONTENCODING_CP1252 : + enc = kCFStringEncodingWindowsLatin1 ; + break ; + case wxFONTENCODING_CP1253 : + enc = kCFStringEncodingWindowsGreek; + break ; + case wxFONTENCODING_CP1254 : + enc = kCFStringEncodingWindowsLatin5; + break ; + case wxFONTENCODING_CP1255 : + enc = kCFStringEncodingWindowsHebrew ; + break ; + case wxFONTENCODING_CP1256 : + enc = kCFStringEncodingWindowsArabic ; + break ; + case wxFONTENCODING_CP1257 : + enc = kCFStringEncodingWindowsBalticRim; + break ; +// This only really encodes to UTF7 (if that) evidently +// case wxFONTENCODING_UTF7 : +// enc = kCFStringEncodingNonLossyASCII ; +// break ; + case wxFONTENCODING_UTF8 : + enc = kCFStringEncodingUTF8 ; + break ; + case wxFONTENCODING_EUC_JP : + enc = kCFStringEncodingEUC_JP; + break ; + case wxFONTENCODING_UTF16 : + enc = kCFStringEncodingUnicode ; + break ; + case wxFONTENCODING_MACROMAN : + enc = kCFStringEncodingMacRoman ; + break ; + case wxFONTENCODING_MACJAPANESE : + enc = kCFStringEncodingMacJapanese ; + break ; + case wxFONTENCODING_MACCHINESETRAD : + enc = kCFStringEncodingMacChineseTrad ; + break ; + case wxFONTENCODING_MACKOREAN : + enc = kCFStringEncodingMacKorean ; + break ; + case wxFONTENCODING_MACARABIC : + enc = kCFStringEncodingMacArabic ; + break ; + case wxFONTENCODING_MACHEBREW : + enc = kCFStringEncodingMacHebrew ; + break ; + case wxFONTENCODING_MACGREEK : + enc = kCFStringEncodingMacGreek ; + break ; + case wxFONTENCODING_MACCYRILLIC : + enc = kCFStringEncodingMacCyrillic ; + break ; + case wxFONTENCODING_MACDEVANAGARI : + enc = kCFStringEncodingMacDevanagari ; + break ; + case wxFONTENCODING_MACGURMUKHI : + enc = kCFStringEncodingMacGurmukhi ; + break ; + case wxFONTENCODING_MACGUJARATI : + enc = kCFStringEncodingMacGujarati ; + break ; + case wxFONTENCODING_MACORIYA : + enc = kCFStringEncodingMacOriya ; + break ; + case wxFONTENCODING_MACBENGALI : + enc = kCFStringEncodingMacBengali ; + break ; + case wxFONTENCODING_MACTAMIL : + enc = kCFStringEncodingMacTamil ; + break ; + case wxFONTENCODING_MACTELUGU : + enc = kCFStringEncodingMacTelugu ; + break ; + case wxFONTENCODING_MACKANNADA : + enc = kCFStringEncodingMacKannada ; + break ; + case wxFONTENCODING_MACMALAJALAM : + enc = kCFStringEncodingMacMalayalam ; + break ; + case wxFONTENCODING_MACSINHALESE : + enc = kCFStringEncodingMacSinhalese ; + break ; + case wxFONTENCODING_MACBURMESE : + enc = kCFStringEncodingMacBurmese ; + break ; + case wxFONTENCODING_MACKHMER : + enc = kCFStringEncodingMacKhmer ; + break ; + case wxFONTENCODING_MACTHAI : + enc = kCFStringEncodingMacThai ; + break ; + case wxFONTENCODING_MACLAOTIAN : + enc = kCFStringEncodingMacLaotian ; + break ; + case wxFONTENCODING_MACGEORGIAN : + enc = kCFStringEncodingMacGeorgian ; + break ; + case wxFONTENCODING_MACARMENIAN : + enc = kCFStringEncodingMacArmenian ; + break ; + case wxFONTENCODING_MACCHINESESIMP : + enc = kCFStringEncodingMacChineseSimp ; + break ; + case wxFONTENCODING_MACTIBETAN : + enc = kCFStringEncodingMacTibetan ; + break ; + case wxFONTENCODING_MACMONGOLIAN : + enc = kCFStringEncodingMacMongolian ; + break ; + case wxFONTENCODING_MACETHIOPIC : + enc = kCFStringEncodingMacEthiopic ; + break ; + case wxFONTENCODING_MACCENTRALEUR : + enc = kCFStringEncodingMacCentralEurRoman ; + break ; + case wxFONTENCODING_MACVIATNAMESE : + enc = kCFStringEncodingMacVietnamese ; + break ; + case wxFONTENCODING_MACARABICEXT : + enc = kCFStringEncodingMacExtArabic ; + break ; + case wxFONTENCODING_MACSYMBOL : + enc = kCFStringEncodingMacSymbol ; + break ; + case wxFONTENCODING_MACDINGBATS : + enc = kCFStringEncodingMacDingbats ; + break ; + case wxFONTENCODING_MACTURKISH : + enc = kCFStringEncodingMacTurkish ; + break ; + case wxFONTENCODING_MACCROATIAN : + enc = kCFStringEncodingMacCroatian ; + break ; + case wxFONTENCODING_MACICELANDIC : + enc = kCFStringEncodingMacIcelandic ; + break ; + case wxFONTENCODING_MACROMANIAN : + enc = kCFStringEncodingMacRomanian ; + break ; + case wxFONTENCODING_MACCELTIC : + enc = kCFStringEncodingMacCeltic ; + break ; + case wxFONTENCODING_MACGAELIC : + enc = kCFStringEncodingMacGaelic ; + break ; +// case wxFONTENCODING_MACKEYBOARD : +// enc = kCFStringEncodingMacKeyboardGlyphs ; +// break ; + + default : + // because gcc is picky + break ; + } + + return enc ; +} + +class wxMBConv_cocoa : public wxMBConv +{ +public: + wxMBConv_cocoa() + { + Init(CFStringGetSystemEncoding()) ; + } + + wxMBConv_cocoa(const wxMBConv_cocoa& conv) + { + m_encoding = conv.m_encoding; + } + +#if wxUSE_FONTMAP + wxMBConv_cocoa(const wxChar* name) + { + Init( wxCFStringEncFromFontEnc(wxFontMapperBase::Get()->CharsetToEncoding(name, false) ) ) ; + } +#endif + + wxMBConv_cocoa(wxFontEncoding encoding) + { + Init( wxCFStringEncFromFontEnc(encoding) ); + } + + virtual ~wxMBConv_cocoa() + { + } + + void Init( CFStringEncoding encoding) + { + m_encoding = encoding ; + } + + size_t MB2WC(wchar_t * szOut, const char * szUnConv, size_t nOutSize) const + { + wxASSERT(szUnConv); + + CFStringRef theString = CFStringCreateWithBytes ( + NULL, //the allocator + (const UInt8*)szUnConv, + strlen(szUnConv), + m_encoding, + false //no BOM/external representation + ); + + wxASSERT(theString); + + size_t nOutLength = CFStringGetLength(theString); + + if (szOut == NULL) + { + CFRelease(theString); + return nOutLength; + } + + CFRange theRange = { 0, nOutSize }; + +#if SIZEOF_WCHAR_T == 4 + UniChar* szUniCharBuffer = new UniChar[nOutSize]; +#endif + + CFStringGetCharacters(theString, theRange, szUniCharBuffer); + + CFRelease(theString); + + szUniCharBuffer[nOutLength] = '\0'; + +#if SIZEOF_WCHAR_T == 4 + wxMBConvUTF16 converter; + converter.MB2WC( szOut, (const char*)szUniCharBuffer, nOutSize ); + delete [] szUniCharBuffer; +#endif + + return nOutLength; + } + + size_t WC2MB(char *szOut, const wchar_t *szUnConv, size_t nOutSize) const + { + wxASSERT(szUnConv); + + size_t nRealOutSize; + size_t nBufSize = wxWcslen(szUnConv); + UniChar* szUniBuffer = (UniChar*) szUnConv; + +#if SIZEOF_WCHAR_T == 4 + wxMBConvUTF16 converter ; + nBufSize = converter.WC2MB( NULL, szUnConv, 0 ); + szUniBuffer = new UniChar[ (nBufSize / sizeof(UniChar)) + 1]; + converter.WC2MB( (char*) szUniBuffer, szUnConv, nBufSize + sizeof(UniChar)); + nBufSize /= sizeof(UniChar); +#endif + + CFStringRef theString = CFStringCreateWithCharactersNoCopy( + NULL, //allocator + szUniBuffer, + nBufSize, + kCFAllocatorNull //deallocator - we want to deallocate it ourselves + ); + + wxASSERT(theString); + + //Note that CER puts a BOM when converting to unicode + //so we check and use getchars instead in that case + if (m_encoding == kCFStringEncodingUnicode) + { + if (szOut != NULL) + CFStringGetCharacters(theString, CFRangeMake(0, nOutSize - 1), (UniChar*) szOut); + + nRealOutSize = CFStringGetLength(theString) + 1; + } + else + { + CFStringGetBytes( + theString, + CFRangeMake(0, CFStringGetLength(theString)), + m_encoding, + 0, //what to put in characters that can't be converted - + //0 tells CFString to return NULL if it meets such a character + false, //not an external representation + (UInt8*) szOut, + nOutSize, + (CFIndex*) &nRealOutSize + ); + } + + CFRelease(theString); + +#if SIZEOF_WCHAR_T == 4 + delete[] szUniBuffer; +#endif + + return nRealOutSize - 1; + } + + virtual wxMBConv *Clone() const { return new wxMBConv_cocoa(*this); } + + bool IsOk() const + { + return m_encoding != kCFStringEncodingInvalidId && + CFStringIsEncodingAvailable(m_encoding); + } + +private: + CFStringEncoding m_encoding ; +}; + +#endif // defined(__WXCOCOA__) + +// ============================================================================ +// Mac conversion classes +// ============================================================================ + +#if defined(__WXMAC__) && defined(TARGET_CARBON) + +class wxMBConv_mac : public wxMBConv +{ +public: + wxMBConv_mac() + { + Init(CFStringGetSystemEncoding()) ; + } + + wxMBConv_mac(const wxMBConv_mac& conv) + { + Init(conv.m_char_encoding); + } + +#if wxUSE_FONTMAP + wxMBConv_mac(const wxChar* name) + { + Init( wxMacGetSystemEncFromFontEnc( wxFontMapperBase::Get()->CharsetToEncoding(name, false) ) ); + } +#endif + + wxMBConv_mac(wxFontEncoding encoding) + { + Init( wxMacGetSystemEncFromFontEnc(encoding) ); + } + + virtual ~wxMBConv_mac() + { + OSStatus status = noErr ; + if (m_MB2WC_converter) + status = TECDisposeConverter(m_MB2WC_converter); + if (m_WC2MB_converter) + status = TECDisposeConverter(m_WC2MB_converter); + } + + void Init( TextEncodingBase encoding,TextEncodingVariant encodingVariant = kTextEncodingDefaultVariant , + TextEncodingFormat encodingFormat = kTextEncodingDefaultFormat) + { + m_MB2WC_converter = NULL ; + m_WC2MB_converter = NULL ; + m_char_encoding = CreateTextEncoding(encoding, encodingVariant, encodingFormat) ; + m_unicode_encoding = CreateTextEncoding(kTextEncodingUnicodeDefault, 0, kUnicode16BitFormat) ; + } + + virtual void CreateIfNeeded() const + { + if ( m_MB2WC_converter == NULL && m_WC2MB_converter == NULL ) + { + OSStatus status = noErr ; + status = TECCreateConverter(&m_MB2WC_converter, + m_char_encoding, + m_unicode_encoding); + wxASSERT_MSG( status == noErr , _("Unable to create TextEncodingConverter")) ; + status = TECCreateConverter(&m_WC2MB_converter, + m_unicode_encoding, + m_char_encoding); + wxASSERT_MSG( status == noErr , _("Unable to create TextEncodingConverter")) ; + } + } + + size_t MB2WC(wchar_t *buf, const char *psz, size_t n) const + { + CreateIfNeeded() ; + OSStatus status = noErr ; + ByteCount byteOutLen ; + ByteCount byteInLen = strlen(psz) + 1; + wchar_t *tbuf = NULL ; + UniChar* ubuf = NULL ; + size_t res = 0 ; + + if (buf == NULL) + { + // Apple specs say at least 32 + n = wxMax( 32, byteInLen ) ; + tbuf = (wchar_t*) malloc( n * SIZEOF_WCHAR_T ) ; + } + + ByteCount byteBufferLen = n * sizeof( UniChar ) ; + +#if SIZEOF_WCHAR_T == 4 + ubuf = (UniChar*) malloc( byteBufferLen + 2 ) ; +#else + ubuf = (UniChar*) (buf ? buf : tbuf) ; +#endif + + status = TECConvertText( + m_MB2WC_converter, (ConstTextPtr) psz, byteInLen, &byteInLen, + (TextPtr) ubuf, byteBufferLen, &byteOutLen); + +#if SIZEOF_WCHAR_T == 4 + // we have to terminate here, because n might be larger for the trailing zero, and if UniChar + // is not properly terminated we get random characters at the end + ubuf[byteOutLen / sizeof( UniChar ) ] = 0 ; + wxMBConvUTF16 converter ; + res = converter.MB2WC( (buf ? buf : tbuf), (const char*)ubuf, n ) ; + free( ubuf ) ; +#else + res = byteOutLen / sizeof( UniChar ) ; +#endif + + if ( buf == NULL ) + free(tbuf) ; + + if ( buf && res < n) + buf[res] = 0; + + return res ; + } + + size_t WC2MB(char *buf, const wchar_t *psz, size_t n) const + { + CreateIfNeeded() ; + OSStatus status = noErr ; + ByteCount byteOutLen ; + ByteCount byteInLen = wxWcslen(psz) * SIZEOF_WCHAR_T ; + + char *tbuf = NULL ; + + if (buf == NULL) + { + // Apple specs say at least 32 + n = wxMax( 32, ((byteInLen / SIZEOF_WCHAR_T) * 8) + SIZEOF_WCHAR_T ); + tbuf = (char*) malloc( n ) ; + } + + ByteCount byteBufferLen = n ; + UniChar* ubuf = NULL ; + +#if SIZEOF_WCHAR_T == 4 + wxMBConvUTF16 converter ; + size_t unicharlen = converter.WC2MB( NULL, psz, 0 ) ; + byteInLen = unicharlen ; + ubuf = (UniChar*) malloc( byteInLen + 2 ) ; + converter.WC2MB( (char*) ubuf, psz, unicharlen + 2 ) ; +#else + ubuf = (UniChar*) psz ; +#endif + + status = TECConvertText( + m_WC2MB_converter, (ConstTextPtr) ubuf, byteInLen, &byteInLen, + (TextPtr) (buf ? buf : tbuf), byteBufferLen, &byteOutLen); + +#if SIZEOF_WCHAR_T == 4 + free( ubuf ) ; +#endif + + if ( buf == NULL ) + free(tbuf) ; + + size_t res = byteOutLen ; + if ( buf && res < n) + { + buf[res] = 0; + + //we need to double-trip to verify it didn't insert any ? in place + //of bogus characters + wxWCharBuffer wcBuf(n); + size_t pszlen = wxWcslen(psz); + if ( MB2WC(wcBuf.data(), buf, n) == wxCONV_FAILED || + wxWcslen(wcBuf) != pszlen || + memcmp(wcBuf, psz, pszlen * sizeof(wchar_t)) != 0 ) + { + // we didn't obtain the same thing we started from, hence + // the conversion was lossy and we consider that it failed + return wxCONV_FAILED; + } + } + + return res ; + } + + virtual wxMBConv *Clone() const { return new wxMBConv_mac(*this); } + + bool IsOk() const + { + CreateIfNeeded() ; + return m_MB2WC_converter != NULL && m_WC2MB_converter != NULL; + } + +protected : + mutable TECObjectRef m_MB2WC_converter; + mutable TECObjectRef m_WC2MB_converter; + + TextEncodingBase m_char_encoding; + TextEncodingBase m_unicode_encoding; +}; + +// MB is decomposed (D) normalized UTF8 + +class wxMBConv_macUTF8D : public wxMBConv_mac +{ +public : + wxMBConv_macUTF8D() + { + Init( kTextEncodingUnicodeDefault , kUnicodeNoSubset , kUnicodeUTF8Format ) ; + m_uni = NULL; + m_uniBack = NULL ; + } + + virtual ~wxMBConv_macUTF8D() + { + if (m_uni!=NULL) + DisposeUnicodeToTextInfo(&m_uni); + if (m_uniBack!=NULL) + DisposeUnicodeToTextInfo(&m_uniBack); + } + + size_t WC2MB(char *buf, const wchar_t *psz, size_t n) const + { + CreateIfNeeded() ; + OSStatus status = noErr ; + ByteCount byteOutLen ; + ByteCount byteInLen = wxWcslen(psz) * SIZEOF_WCHAR_T ; + + char *tbuf = NULL ; + + if (buf == NULL) + { + // Apple specs say at least 32 + n = wxMax( 32, ((byteInLen / SIZEOF_WCHAR_T) * 8) + SIZEOF_WCHAR_T ); + tbuf = (char*) malloc( n ) ; + } + + ByteCount byteBufferLen = n ; + UniChar* ubuf = NULL ; + +#if SIZEOF_WCHAR_T == 4 + wxMBConvUTF16 converter ; + size_t unicharlen = converter.WC2MB( NULL, psz, 0 ) ; + byteInLen = unicharlen ; + ubuf = (UniChar*) malloc( byteInLen + 2 ) ; + converter.WC2MB( (char*) ubuf, psz, unicharlen + 2 ) ; +#else + ubuf = (UniChar*) psz ; +#endif + + // ubuf is a non-decomposed UniChar buffer + + ByteCount dcubuflen = byteInLen * 2 + 2 ; + ByteCount dcubufread , dcubufwritten ; + UniChar *dcubuf = (UniChar*) malloc( dcubuflen ) ; + + ConvertFromUnicodeToText( m_uni , byteInLen , ubuf , + kUnicodeDefaultDirectionMask, 0, NULL, NULL, NULL, dcubuflen , &dcubufread , &dcubufwritten , dcubuf ) ; + + // we now convert that decomposed buffer into UTF8 + + status = TECConvertText( + m_WC2MB_converter, (ConstTextPtr) dcubuf, dcubufwritten, &dcubufread, + (TextPtr) (buf ? buf : tbuf), byteBufferLen, &byteOutLen); + + free( dcubuf ); + +#if SIZEOF_WCHAR_T == 4 + free( ubuf ) ; +#endif + + if ( buf == NULL ) + free(tbuf) ; + + size_t res = byteOutLen ; + if ( buf && res < n) + { + buf[res] = 0; + // don't test for round-trip fidelity yet, we cannot guarantee it yet + } + + return res ; + } + + size_t MB2WC(wchar_t *buf, const char *psz, size_t n) const + { + CreateIfNeeded() ; + OSStatus status = noErr ; + ByteCount byteOutLen ; + ByteCount byteInLen = strlen(psz) + 1; + wchar_t *tbuf = NULL ; + UniChar* ubuf = NULL ; + size_t res = 0 ; + + if (buf == NULL) + { + // Apple specs say at least 32 + n = wxMax( 32, byteInLen ) ; + tbuf = (wchar_t*) malloc( n * SIZEOF_WCHAR_T ) ; + } + + ByteCount byteBufferLen = n * sizeof( UniChar ) ; + +#if SIZEOF_WCHAR_T == 4 + ubuf = (UniChar*) malloc( byteBufferLen + 2 ) ; +#else + ubuf = (UniChar*) (buf ? buf : tbuf) ; +#endif + + ByteCount dcubuflen = byteBufferLen * 2 + 2 ; + ByteCount dcubufread , dcubufwritten ; + UniChar *dcubuf = (UniChar*) malloc( dcubuflen ) ; + + status = TECConvertText( + m_MB2WC_converter, (ConstTextPtr) psz, byteInLen, &byteInLen, + (TextPtr) dcubuf, dcubuflen, &byteOutLen); + // we have to terminate here, because n might be larger for the trailing zero, and if UniChar + // is not properly terminated we get random characters at the end + dcubuf[byteOutLen / sizeof( UniChar ) ] = 0 ; + + // now from the decomposed UniChar to properly composed uniChar + ConvertFromUnicodeToText( m_uniBack , byteOutLen , dcubuf , + kUnicodeDefaultDirectionMask, 0, NULL, NULL, NULL, dcubuflen , &dcubufread , &dcubufwritten , ubuf ) ; + + free( dcubuf ); + byteOutLen = dcubufwritten ; + ubuf[byteOutLen / sizeof( UniChar ) ] = 0 ; + + +#if SIZEOF_WCHAR_T == 4 + wxMBConvUTF16 converter ; + res = converter.MB2WC( (buf ? buf : tbuf), (const char*)ubuf, n ) ; + free( ubuf ) ; +#else + res = byteOutLen / sizeof( UniChar ) ; +#endif + + if ( buf == NULL ) + free(tbuf) ; + + if ( buf && res < n) + buf[res] = 0; + + return res ; + } + + virtual void CreateIfNeeded() const + { + wxMBConv_mac::CreateIfNeeded() ; + if ( m_uni == NULL ) + { + m_map.unicodeEncoding = CreateTextEncoding(kTextEncodingUnicodeDefault, + kUnicodeNoSubset, kTextEncodingDefaultFormat); + m_map.otherEncoding = CreateTextEncoding(kTextEncodingUnicodeDefault, + kUnicodeCanonicalDecompVariant, kTextEncodingDefaultFormat); + m_map.mappingVersion = kUnicodeUseLatestMapping; + + OSStatus err = CreateUnicodeToTextInfo(&m_map, &m_uni); + wxASSERT_MSG( err == noErr , _(" Couldn't create the UnicodeConverter")) ; + + m_map.unicodeEncoding = CreateTextEncoding(kTextEncodingUnicodeDefault, + kUnicodeNoSubset, kTextEncodingDefaultFormat); + m_map.otherEncoding = CreateTextEncoding(kTextEncodingUnicodeDefault, + kUnicodeCanonicalCompVariant, kTextEncodingDefaultFormat); + m_map.mappingVersion = kUnicodeUseLatestMapping; + err = CreateUnicodeToTextInfo(&m_map, &m_uniBack); + wxASSERT_MSG( err == noErr , _(" Couldn't create the UnicodeConverter")) ; + } + } +protected : + mutable UnicodeToTextInfo m_uni; + mutable UnicodeToTextInfo m_uniBack; + mutable UnicodeMapping m_map; +}; +#endif // defined(__WXMAC__) && defined(TARGET_CARBON) + +// ============================================================================ +// wxEncodingConverter based conversion classes +// ============================================================================ + +#if wxUSE_FONTMAP + +class wxMBConv_wxwin : public wxMBConv +{ +private: + void Init() + { + m_ok = m2w.Init(m_enc, wxFONTENCODING_UNICODE) && + w2m.Init(wxFONTENCODING_UNICODE, m_enc); + } + +public: + // temporarily just use wxEncodingConverter stuff, + // so that it works while a better implementation is built + wxMBConv_wxwin(const wxChar* name) + { + if (name) + m_enc = wxFontMapperBase::Get()->CharsetToEncoding(name, false); + else + m_enc = wxFONTENCODING_SYSTEM; + + Init(); + } + + wxMBConv_wxwin(wxFontEncoding enc) + { + m_enc = enc; + + Init(); + } + + size_t MB2WC(wchar_t *buf, const char *psz, size_t WXUNUSED(n)) const + { + size_t inbuf = strlen(psz); + if (buf) + { + if (!m2w.Convert(psz, buf)) + return wxCONV_FAILED; + } + return inbuf; + } + + size_t WC2MB(char *buf, const wchar_t *psz, size_t WXUNUSED(n)) const + { + const size_t inbuf = wxWcslen(psz); + if (buf) + { + if (!w2m.Convert(psz, buf)) + return wxCONV_FAILED; + } + + return inbuf; + } + + virtual size_t GetMBNulLen() const + { + switch ( m_enc ) + { + case wxFONTENCODING_UTF16BE: + case wxFONTENCODING_UTF16LE: + return 2; + + case wxFONTENCODING_UTF32BE: + case wxFONTENCODING_UTF32LE: + return 4; + + default: + return 1; + } + } + + virtual wxMBConv *Clone() const { return new wxMBConv_wxwin(m_enc); } + + bool IsOk() const { return m_ok; } + +public: + wxFontEncoding m_enc; + wxEncodingConverter m2w, w2m; + +private: + // were we initialized successfully? + bool m_ok; + + DECLARE_NO_COPY_CLASS(wxMBConv_wxwin) +}; + +// make the constructors available for unit testing +WXDLLIMPEXP_BASE wxMBConv* new_wxMBConv_wxwin( const wxChar* name ) +{ + wxMBConv_wxwin* result = new wxMBConv_wxwin( name ); + if ( !result->IsOk() ) + { + delete result; + return 0; + } + + return result; +} + +#endif // wxUSE_FONTMAP + +// ============================================================================ +// wxCSConv implementation +// ============================================================================ + +void wxCSConv::Init() +{ + m_name = NULL; + m_convReal = NULL; + m_deferred = true; +} + +wxCSConv::wxCSConv(const wxChar *charset) +{ + Init(); + + if ( charset ) + { + SetName(charset); + } + +#if wxUSE_FONTMAP + m_encoding = wxFontMapperBase::GetEncodingFromName(charset); +#else + m_encoding = wxFONTENCODING_SYSTEM; +#endif +} + +wxCSConv::wxCSConv(wxFontEncoding encoding) +{ + if ( encoding == wxFONTENCODING_MAX || encoding == wxFONTENCODING_DEFAULT ) + { + wxFAIL_MSG( _T("invalid encoding value in wxCSConv ctor") ); + + encoding = wxFONTENCODING_SYSTEM; + } + + Init(); + + m_encoding = encoding; +} + +wxCSConv::~wxCSConv() +{ + Clear(); +} + +wxCSConv::wxCSConv(const wxCSConv& conv) + : wxMBConv() +{ + Init(); + + SetName(conv.m_name); + m_encoding = conv.m_encoding; +} + +wxCSConv& wxCSConv::operator=(const wxCSConv& conv) +{ + Clear(); + + SetName(conv.m_name); + m_encoding = conv.m_encoding; + + return *this; +} + +void wxCSConv::Clear() +{ + free(m_name); + delete m_convReal; + + m_name = NULL; + m_convReal = NULL; +} + +void wxCSConv::SetName(const wxChar *charset) +{ + if (charset) + { + m_name = wxStrdup(charset); + m_deferred = true; + } +} + +#if wxUSE_FONTMAP + +WX_DECLARE_HASH_MAP( wxFontEncoding, wxString, wxIntegerHash, wxIntegerEqual, + wxEncodingNameCache ); + +static wxEncodingNameCache gs_nameCache; +#endif + +wxMBConv *wxCSConv::DoCreate() const +{ +#if wxUSE_FONTMAP + wxLogTrace(TRACE_STRCONV, + wxT("creating conversion for %s"), + (m_name ? m_name + : wxFontMapperBase::GetEncodingName(m_encoding).c_str())); +#endif // wxUSE_FONTMAP + + // check for the special case of ASCII or ISO8859-1 charset: as we have + // special knowledge of it anyhow, we don't need to create a special + // conversion object + if ( m_encoding == wxFONTENCODING_ISO8859_1 || + m_encoding == wxFONTENCODING_DEFAULT ) + { + // don't convert at all + return NULL; + } + + // we trust OS to do conversion better than we can so try external + // conversion methods first + // + // the full order is: + // 1. OS conversion (iconv() under Unix or Win32 API) + // 2. hard coded conversions for UTF + // 3. wxEncodingConverter as fall back + + // step (1) +#ifdef HAVE_ICONV +#if !wxUSE_FONTMAP + if ( m_name ) +#endif // !wxUSE_FONTMAP + { + wxString name(m_name); +#if wxUSE_FONTMAP + wxFontEncoding encoding(m_encoding); +#endif + + if ( !name.empty() ) + { + wxMBConv_iconv *conv = new wxMBConv_iconv(name); + if ( conv->IsOk() ) + return conv; + + delete conv; + +#if wxUSE_FONTMAP + encoding = + wxFontMapperBase::Get()->CharsetToEncoding(name, false); +#endif // wxUSE_FONTMAP + } +#if wxUSE_FONTMAP + { + const wxEncodingNameCache::iterator it = gs_nameCache.find(encoding); + if ( it != gs_nameCache.end() ) + { + if ( it->second.empty() ) + return NULL; + + wxMBConv_iconv *conv = new wxMBConv_iconv(it->second); + if ( conv->IsOk() ) + return conv; + + delete conv; + } + + const wxChar** names = wxFontMapperBase::GetAllEncodingNames(encoding); + // CS : in case this does not return valid names (eg for MacRoman) encoding + // got a 'failure' entry in the cache all the same, although it just has to + // be created using a different method, so only store failed iconv creation + // attempts (or perhaps we shoulnd't do this at all ?) + if ( names[0] != NULL ) + { + for ( ; *names; ++names ) + { + wxMBConv_iconv *conv = new wxMBConv_iconv(*names); + if ( conv->IsOk() ) + { + gs_nameCache[encoding] = *names; + return conv; + } + + delete conv; + } + + gs_nameCache[encoding] = _T(""); // cache the failure + } + } +#endif // wxUSE_FONTMAP + } +#endif // HAVE_ICONV + +#ifdef wxHAVE_WIN32_MB2WC + { +#if wxUSE_FONTMAP + wxMBConv_win32 *conv = m_name ? new wxMBConv_win32(m_name) + : new wxMBConv_win32(m_encoding); + if ( conv->IsOk() ) + return conv; + + delete conv; +#else + return NULL; +#endif + } +#endif // wxHAVE_WIN32_MB2WC + +#if defined(__WXMAC__) + { + // leave UTF16 and UTF32 to the built-ins of wx + if ( m_name || ( m_encoding < wxFONTENCODING_UTF16BE || + ( m_encoding >= wxFONTENCODING_MACMIN && m_encoding <= wxFONTENCODING_MACMAX ) ) ) + { +#if wxUSE_FONTMAP + wxMBConv_mac *conv = m_name ? new wxMBConv_mac(m_name) + : new wxMBConv_mac(m_encoding); +#else + wxMBConv_mac *conv = new wxMBConv_mac(m_encoding); +#endif + if ( conv->IsOk() ) + return conv; + + delete conv; + } + } +#endif + +#if defined(__WXCOCOA__) + { + if ( m_name || ( m_encoding <= wxFONTENCODING_UTF16 ) ) + { +#if wxUSE_FONTMAP + wxMBConv_cocoa *conv = m_name ? new wxMBConv_cocoa(m_name) + : new wxMBConv_cocoa(m_encoding); +#else + wxMBConv_cocoa *conv = new wxMBConv_cocoa(m_encoding); +#endif + + if ( conv->IsOk() ) + return conv; + + delete conv; + } + } +#endif + // step (2) + wxFontEncoding enc = m_encoding; +#if wxUSE_FONTMAP + if ( enc == wxFONTENCODING_SYSTEM && m_name ) + { + // use "false" to suppress interactive dialogs -- we can be called from + // anywhere and popping up a dialog from here is the last thing we want to + // do + enc = wxFontMapperBase::Get()->CharsetToEncoding(m_name, false); + } +#endif // wxUSE_FONTMAP + + switch ( enc ) + { + case wxFONTENCODING_UTF7: + return new wxMBConvUTF7; + + case wxFONTENCODING_UTF8: + return new wxMBConvUTF8; + + case wxFONTENCODING_UTF16BE: + return new wxMBConvUTF16BE; + + case wxFONTENCODING_UTF16LE: + return new wxMBConvUTF16LE; + + case wxFONTENCODING_UTF32BE: + return new wxMBConvUTF32BE; + + case wxFONTENCODING_UTF32LE: + return new wxMBConvUTF32LE; + + default: + // nothing to do but put here to suppress gcc warnings + break; + } + + // step (3) +#if wxUSE_FONTMAP + { + wxMBConv_wxwin *conv = m_name ? new wxMBConv_wxwin(m_name) + : new wxMBConv_wxwin(m_encoding); + if ( conv->IsOk() ) + return conv; + + delete conv; + } +#endif // wxUSE_FONTMAP + + // NB: This is a hack to prevent deadlock. What could otherwise happen + // in Unicode build: wxConvLocal creation ends up being here + // because of some failure and logs the error. But wxLog will try to + // attach a timestamp, for which it will need wxConvLocal (to convert + // time to char* and then wchar_t*), but that fails, tries to log the + // error, but wxLog has an (already locked) critical section that + // guards the static buffer. + static bool alreadyLoggingError = false; + if (!alreadyLoggingError) + { + alreadyLoggingError = true; + wxLogError(_("Cannot convert from the charset '%s'!"), + m_name ? m_name + : +#if wxUSE_FONTMAP + wxFontMapperBase::GetEncodingDescription(m_encoding).c_str() +#else // !wxUSE_FONTMAP + wxString::Format(_("encoding %i"), m_encoding).c_str() +#endif // wxUSE_FONTMAP/!wxUSE_FONTMAP + ); + + alreadyLoggingError = false; + } + + return NULL; +} + +void wxCSConv::CreateConvIfNeeded() const +{ + if ( m_deferred ) + { + wxCSConv *self = (wxCSConv *)this; // const_cast + + // if we don't have neither the name nor the encoding, use the default + // encoding for this system + if ( !m_name && m_encoding == wxFONTENCODING_SYSTEM ) + { +#if wxUSE_INTL + self->m_name = wxStrdup(wxLocale::GetSystemEncodingName()); +#else + // fallback to some reasonable default: + self->m_encoding = wxFONTENCODING_ISO8859_1; +#endif // wxUSE_INTL + } + + self->m_convReal = DoCreate(); + self->m_deferred = false; + } +} + +bool wxCSConv::IsOk() const +{ + CreateConvIfNeeded(); + + // special case: no convReal created for wxFONTENCODING_ISO8859_1 + if ( m_encoding == wxFONTENCODING_ISO8859_1 ) + return true; // always ok as we do it ourselves + + // m_convReal->IsOk() is called at its own creation, so we know it must + // be ok if m_convReal is non-NULL + return m_convReal != NULL; +} + +size_t wxCSConv::ToWChar(wchar_t *dst, size_t dstLen, + const char *src, size_t srcLen) const +{ + CreateConvIfNeeded(); + + if (m_convReal) + return m_convReal->ToWChar(dst, dstLen, src, srcLen); + + // latin-1 (direct) + return wxMBConv::ToWChar(dst, dstLen, src, srcLen); +} + +size_t wxCSConv::FromWChar(char *dst, size_t dstLen, + const wchar_t *src, size_t srcLen) const +{ + CreateConvIfNeeded(); + + if (m_convReal) + return m_convReal->FromWChar(dst, dstLen, src, srcLen); + + // latin-1 (direct) + return wxMBConv::FromWChar(dst, dstLen, src, srcLen); +} + +size_t wxCSConv::MB2WC(wchar_t *buf, const char *psz, size_t n) const +{ + CreateConvIfNeeded(); + + if (m_convReal) + return m_convReal->MB2WC(buf, psz, n); + + // latin-1 (direct) + size_t len = strlen(psz); + + if (buf) + { + for (size_t c = 0; c <= len; c++) + buf[c] = (unsigned char)(psz[c]); + } + + return len; +} + +size_t wxCSConv::WC2MB(char *buf, const wchar_t *psz, size_t n) const +{ + CreateConvIfNeeded(); + + if (m_convReal) + return m_convReal->WC2MB(buf, psz, n); + + // latin-1 (direct) + const size_t len = wxWcslen(psz); + if (buf) + { + for (size_t c = 0; c <= len; c++) + { + if (psz[c] > 0xFF) + return wxCONV_FAILED; + + buf[c] = (char)psz[c]; + } + } + else + { + for (size_t c = 0; c <= len; c++) + { + if (psz[c] > 0xFF) + return wxCONV_FAILED; + } + } + + return len; +} + +size_t wxCSConv::GetMBNulLen() const +{ + CreateConvIfNeeded(); + + if ( m_convReal ) + { + return m_convReal->GetMBNulLen(); + } + + return 1; +} + +// ---------------------------------------------------------------------------- +// globals +// ---------------------------------------------------------------------------- + +#ifdef __WINDOWS__ + static wxMBConv_win32 wxConvLibcObj; +#elif defined(__WXMAC__) && !defined(__MACH__) + static wxMBConv_mac wxConvLibcObj ; +#else + static wxMBConvLibc wxConvLibcObj; +#endif + +static wxCSConv wxConvLocalObj(wxFONTENCODING_SYSTEM); +static wxCSConv wxConvISO8859_1Obj(wxFONTENCODING_ISO8859_1); +static wxMBConvUTF7 wxConvUTF7Obj; +static wxMBConvUTF8 wxConvUTF8Obj; +#if defined(__WXMAC__) && defined(TARGET_CARBON) +static wxMBConv_macUTF8D wxConvMacUTF8DObj; +#endif +WXDLLIMPEXP_DATA_BASE(wxMBConv&) wxConvLibc = wxConvLibcObj; +WXDLLIMPEXP_DATA_BASE(wxCSConv&) wxConvLocal = wxConvLocalObj; +WXDLLIMPEXP_DATA_BASE(wxCSConv&) wxConvISO8859_1 = wxConvISO8859_1Obj; +WXDLLIMPEXP_DATA_BASE(wxMBConvUTF7&) wxConvUTF7 = wxConvUTF7Obj; +WXDLLIMPEXP_DATA_BASE(wxMBConvUTF8&) wxConvUTF8 = wxConvUTF8Obj; +WXDLLIMPEXP_DATA_BASE(wxMBConv *) wxConvCurrent = &wxConvLibcObj; +WXDLLIMPEXP_DATA_BASE(wxMBConv *) wxConvUI = &wxConvLocal; +WXDLLIMPEXP_DATA_BASE(wxMBConv *) wxConvFileName = & +#ifdef __WXOSX__ +#if defined(__WXMAC__) && defined(TARGET_CARBON) + wxConvMacUTF8DObj; +#else + wxConvUTF8Obj; +#endif +#else // !__WXOSX__ + wxConvLibcObj; +#endif // __WXOSX__/!__WXOSX__ + +#if wxUSE_UNICODE + +wxWCharBuffer wxSafeConvertMB2WX(const char *s) +{ + if ( !s ) + return wxWCharBuffer(); + + wxWCharBuffer wbuf(wxConvLibc.cMB2WX(s)); + if ( !wbuf ) + wbuf = wxConvUTF8.cMB2WX(s); + if ( !wbuf ) + wbuf = wxConvISO8859_1.cMB2WX(s); + + return wbuf; +} + +wxCharBuffer wxSafeConvertWX2MB(const wchar_t *ws) +{ + if ( !ws ) + return wxCharBuffer(); + + wxCharBuffer buf(wxConvLibc.cWX2MB(ws)); + if ( !buf ) + buf = wxMBConvUTF8(wxMBConvUTF8::MAP_INVALID_UTF8_TO_OCTAL).cWX2MB(ws); + + return buf; +} + +#endif // wxUSE_UNICODE + +#else // !wxUSE_WCHAR_T + +// stand-ins in absence of wchar_t +WXDLLIMPEXP_DATA_BASE(wxMBConv) wxConvLibc, + wxConvISO8859_1, + wxConvLocal, + wxConvUTF8; + +WXDLLIMPEXP_DATA_BASE(wxMBConv *) wxConvCurrent = NULL; + +#endif // wxUSE_WCHAR_T/!wxUSE_WCHAR_T diff --git a/Externals/wxWidgets/src/common/stream.cpp b/Externals/wxWidgets/src/common/stream.cpp index b743641076..27a9a7cc81 100644 --- a/Externals/wxWidgets/src/common/stream.cpp +++ b/Externals/wxWidgets/src/common/stream.cpp @@ -1,1388 +1,1388 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/stream.cpp -// Purpose: wxStream base classes -// Author: Guilhem Lavaux -// Modified by: VZ (23.11.00) to fix realloc()ing new[]ed memory, -// general code review -// Created: 11/07/98 -// RCS-ID: $Id: stream.cpp 51662 2008-02-11 20:23:29Z VZ $ -// Copyright: (c) Guilhem Lavaux -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_STREAMS - -#include "wx/stream.h" - -#ifndef WX_PRECOMP - #include "wx/log.h" -#endif - -#include -#include "wx/datstrm.h" -#include "wx/textfile.h" - -// ---------------------------------------------------------------------------- -// constants -// ---------------------------------------------------------------------------- - -// the temporary buffer size used when copying from stream to stream -#define BUF_TEMP_SIZE 4096 - -// ============================================================================ -// implementation -// ============================================================================ - -// ---------------------------------------------------------------------------- -// wxStreamBuffer -// ---------------------------------------------------------------------------- - -void wxStreamBuffer::SetError(wxStreamError err) -{ - if ( m_stream && m_stream->m_lasterror == wxSTREAM_NO_ERROR ) - m_stream->m_lasterror = err; -} - -void wxStreamBuffer::InitBuffer() -{ - m_buffer_start = - m_buffer_end = - m_buffer_pos = NULL; - m_buffer_size = 0; - - // if we are going to allocate the buffer, we should free it later as well - m_destroybuf = true; -} - -void wxStreamBuffer::Init() -{ - InitBuffer(); - - m_fixed = true; -} - -wxStreamBuffer::wxStreamBuffer(BufMode mode) -{ - Init(); - - m_stream = NULL; - m_mode = mode; - - m_flushable = false; -} - -wxStreamBuffer::wxStreamBuffer(wxStreamBase& stream, BufMode mode) -{ - Init(); - - m_stream = &stream; - m_mode = mode; - - m_flushable = true; -} - -wxStreamBuffer::wxStreamBuffer(const wxStreamBuffer& buffer) -{ - // doing this has big chances to lead to a crash when the source buffer is - // destroyed (otherwise assume the caller knows what he does) - wxASSERT_MSG( !buffer.m_destroybuf, - _T("it's a bad idea to copy this buffer") ); - - m_buffer_start = buffer.m_buffer_start; - m_buffer_end = buffer.m_buffer_end; - m_buffer_pos = buffer.m_buffer_pos; - m_buffer_size = buffer.m_buffer_size; - m_fixed = buffer.m_fixed; - m_flushable = buffer.m_flushable; - m_stream = buffer.m_stream; - m_mode = buffer.m_mode; - m_destroybuf = false; -} - -void wxStreamBuffer::FreeBuffer() -{ - if ( m_destroybuf ) - { - free(m_buffer_start); - m_buffer_start = NULL; - } -} - -wxStreamBuffer::~wxStreamBuffer() -{ - FreeBuffer(); -} - -wxInputStream *wxStreamBuffer::GetInputStream() const -{ - return m_mode == write ? NULL : (wxInputStream *)m_stream; -} - -wxOutputStream *wxStreamBuffer::GetOutputStream() const -{ - return m_mode == read ? NULL : (wxOutputStream *)m_stream; -} - -void wxStreamBuffer::SetBufferIO(void *buffer_start, - void *buffer_end, - bool takeOwnership) -{ - SetBufferIO(buffer_start, (char *)buffer_end - (char *)buffer_start, - takeOwnership); -} - -void wxStreamBuffer::SetBufferIO(void *start, - size_t len, - bool takeOwnership) -{ - // start by freeing the old buffer - FreeBuffer(); - - m_buffer_start = (char *)start; - m_buffer_end = m_buffer_start + len; - - m_buffer_size = len; - - // if we own it, we free it - m_destroybuf = takeOwnership; - - ResetBuffer(); -} - -void wxStreamBuffer::SetBufferIO(size_t bufsize) -{ - if ( bufsize ) - { - // this will free the old buffer and allocate the new one - SetBufferIO(malloc(bufsize), bufsize, true /* take ownership */); - } - else // no buffer size => no buffer - { - // still free the old one - FreeBuffer(); - InitBuffer(); - } -} - -void wxStreamBuffer::ResetBuffer() -{ - if ( m_stream ) - { - m_stream->Reset(); - m_stream->m_lastcount = 0; - } - - m_buffer_pos = m_mode == read && m_flushable - ? m_buffer_end - : m_buffer_start; -} - -// fill the buffer with as much data as possible (only for read buffers) -bool wxStreamBuffer::FillBuffer() -{ - wxInputStream *inStream = GetInputStream(); - - // It's legal to have no stream, so we don't complain about it just return false - if ( !inStream ) - return false; - - size_t count = inStream->OnSysRead(m_buffer_start, m_buffer_size); - if ( !count ) - return false; - - m_buffer_end = m_buffer_start + count; - m_buffer_pos = m_buffer_start; - - return true; -} - -// write the buffer contents to the stream (only for write buffers) -bool wxStreamBuffer::FlushBuffer() -{ - wxCHECK_MSG( m_flushable, false, _T("can't flush this buffer") ); - - // FIXME: what is this check for? (VZ) - if ( m_buffer_pos == m_buffer_start ) - return false; - - wxOutputStream *outStream = GetOutputStream(); - - wxCHECK_MSG( outStream, false, _T("should have a stream in wxStreamBuffer") ); - - size_t current = m_buffer_pos - m_buffer_start; - size_t count = outStream->OnSysWrite(m_buffer_start, current); - if ( count != current ) - return false; - - m_buffer_pos = m_buffer_start; - - return true; -} - -size_t wxStreamBuffer::GetDataLeft() -{ - /* Why is this done? RR. */ - if ( m_buffer_pos == m_buffer_end && m_flushable) - FillBuffer(); - - return GetBytesLeft(); -} - -// copy up to size bytes from our buffer into the provided one -void wxStreamBuffer::GetFromBuffer(void *buffer, size_t size) -{ - // don't get more bytes than left in the buffer - size_t left = GetBytesLeft(); - - if ( size > left ) - size = left; - - memcpy(buffer, m_buffer_pos, size); - m_buffer_pos += size; -} - -// copy the contents of the provided buffer into this one -void wxStreamBuffer::PutToBuffer(const void *buffer, size_t size) -{ - size_t left = GetBytesLeft(); - - if ( size > left ) - { - if ( m_fixed ) - { - // we can't realloc the buffer, so just copy what we can - size = left; - } - else // !m_fixed - { - // realloc the buffer to have enough space for the data - size_t delta = m_buffer_pos - m_buffer_start; - - char *startOld = m_buffer_start; - m_buffer_size += size; - m_buffer_start = (char *)realloc(m_buffer_start, m_buffer_size); - if ( !m_buffer_start ) - { - // don't leak memory if realloc() failed - m_buffer_start = startOld; - m_buffer_size -= size; - - // what else can we do? - return; - } - - // adjust the pointers invalidated by realloc() - m_buffer_pos = m_buffer_start + delta; - m_buffer_end = m_buffer_start + m_buffer_size; - } - } - - memcpy(m_buffer_pos, buffer, size); - m_buffer_pos += size; -} - -void wxStreamBuffer::PutChar(char c) -{ - wxOutputStream *outStream = GetOutputStream(); - - wxCHECK_RET( outStream, _T("should have a stream in wxStreamBuffer") ); - - // if we don't have buffer at all, just forward this call to the stream, - if ( !HasBuffer() ) - { - outStream->OnSysWrite(&c, sizeof(c)); - } - else - { - // otherwise check we have enough space left - if ( !GetDataLeft() && !FlushBuffer() ) - { - // we don't - SetError(wxSTREAM_WRITE_ERROR); - } - else - { - PutToBuffer(&c, sizeof(c)); - m_stream->m_lastcount = 1; - } - } -} - -char wxStreamBuffer::Peek() -{ - wxCHECK_MSG( m_stream && HasBuffer(), 0, - _T("should have the stream and the buffer in wxStreamBuffer") ); - - if ( !GetDataLeft() ) - { - SetError(wxSTREAM_READ_ERROR); - return 0; - } - - char c; - GetFromBuffer(&c, sizeof(c)); - m_buffer_pos--; - - return c; -} - -char wxStreamBuffer::GetChar() -{ - wxInputStream *inStream = GetInputStream(); - - wxCHECK_MSG( inStream, 0, _T("should have a stream in wxStreamBuffer") ); - - char c; - if ( !HasBuffer() ) - { - inStream->OnSysRead(&c, sizeof(c)); - } - else - { - if ( !GetDataLeft() ) - { - SetError(wxSTREAM_READ_ERROR); - c = 0; - } - else - { - GetFromBuffer(&c, sizeof(c)); - m_stream->m_lastcount = 1; - } - } - - return c; -} - -size_t wxStreamBuffer::Read(void *buffer, size_t size) -{ - wxASSERT_MSG( buffer, _T("Warning: Null pointer is about to be used") ); - - /* Clear buffer first */ - memset(buffer, 0x00, size); - - // lasterror is reset before all new IO calls - if ( m_stream ) - m_stream->Reset(); - - size_t readBytes; - if ( !HasBuffer() ) - { - wxInputStream *inStream = GetInputStream(); - - wxCHECK_MSG( inStream, 0, _T("should have a stream in wxStreamBuffer") ); - - readBytes = inStream->OnSysRead(buffer, size); - } - else // we have a buffer, use it - { - size_t orig_size = size; - - while ( size > 0 ) - { - size_t left = GetDataLeft(); - - // if the requested number of bytes if greater than the buffer - // size, read data in chunks - if ( size > left ) - { - GetFromBuffer(buffer, left); - size -= left; - buffer = (char *)buffer + left; - - if ( !FillBuffer() ) - { - SetError(wxSTREAM_EOF); - break; - } - } - else // otherwise just do it in one gulp - { - GetFromBuffer(buffer, size); - size = 0; - } - } - - readBytes = orig_size - size; - } - - if ( m_stream ) - m_stream->m_lastcount = readBytes; - - return readBytes; -} - -// this should really be called "Copy()" -size_t wxStreamBuffer::Read(wxStreamBuffer *dbuf) -{ - wxCHECK_MSG( m_mode != write, 0, _T("can't read from this buffer") ); - - char buf[BUF_TEMP_SIZE]; - size_t nRead, - total = 0; - - do - { - nRead = Read(buf, WXSIZEOF(buf)); - if ( nRead ) - { - nRead = dbuf->Write(buf, nRead); - total += nRead; - } - } - while ( nRead ); - - return total; -} - -size_t wxStreamBuffer::Write(const void *buffer, size_t size) -{ - wxASSERT_MSG( buffer, _T("Warning: Null pointer is about to be send") ); - - if (m_stream) - { - // lasterror is reset before all new IO calls - m_stream->Reset(); - } - - size_t ret; - - if ( !HasBuffer() && m_fixed ) - { - wxOutputStream *outStream = GetOutputStream(); - - wxCHECK_MSG( outStream, 0, _T("should have a stream in wxStreamBuffer") ); - - // no buffer, just forward the call to the stream - ret = outStream->OnSysWrite(buffer, size); - } - else // we [may] have a buffer, use it - { - size_t orig_size = size; - - while ( size > 0 ) - { - size_t left = GetBytesLeft(); - - // if the buffer is too large to fit in the stream buffer, split - // it in smaller parts - // - // NB: If stream buffer isn't fixed (as for wxMemoryOutputStream), - // we always go to the second case. - // - // FIXME: fine, but if it fails we should (re)try writing it by - // chunks as this will (hopefully) always work (VZ) - - if ( size > left && m_fixed ) - { - PutToBuffer(buffer, left); - size -= left; - buffer = (char *)buffer + left; - - if ( !FlushBuffer() ) - { - SetError(wxSTREAM_WRITE_ERROR); - - break; - } - - m_buffer_pos = m_buffer_start; - } - else // we can do it in one gulp - { - PutToBuffer(buffer, size); - size = 0; - } - } - - ret = orig_size - size; - } - - if (m_stream) - { - // i am not entirely sure what we do this for - m_stream->m_lastcount = ret; - } - - return ret; -} - -size_t wxStreamBuffer::Write(wxStreamBuffer *sbuf) -{ - wxCHECK_MSG( m_mode != read, 0, _T("can't write to this buffer") ); - wxCHECK_MSG( sbuf->m_mode != write, 0, _T("can't read from that buffer") ); - - char buf[BUF_TEMP_SIZE]; - size_t nWrite, - total = 0; - - do - { - size_t nRead = sbuf->Read(buf, WXSIZEOF(buf)); - if ( nRead ) - { - nWrite = Write(buf, nRead); - if ( nWrite < nRead ) - { - // put back data we couldn't copy - wxInputStream *in_stream = (wxInputStream *)sbuf->GetStream(); - - in_stream->Ungetch(buf + nWrite, nRead - nWrite); - } - - total += nWrite; - } - else - { - nWrite = 0; - } - } - while ( nWrite == WXSIZEOF(buf) ); - - return total; -} - -wxFileOffset wxStreamBuffer::Seek(wxFileOffset pos, wxSeekMode mode) -{ - wxFileOffset ret_off, diff; - - wxFileOffset last_access = GetLastAccess(); - - if ( !m_flushable ) - { - switch (mode) - { - case wxFromStart: - diff = pos; - break; - - case wxFromCurrent: - diff = pos + GetIntPosition(); - break; - - case wxFromEnd: - diff = pos + last_access; - break; - - default: - wxFAIL_MSG( _T("invalid seek mode") ); - - return wxInvalidOffset; - } - if (diff < 0 || diff > last_access) - return wxInvalidOffset; - size_t int_diff = wx_truncate_cast(size_t, diff); - wxCHECK_MSG( (wxFileOffset)int_diff == diff, wxInvalidOffset, wxT("huge file not supported") ); - SetIntPosition(int_diff); - return diff; - } - - switch ( mode ) - { - case wxFromStart: - // We'll try to compute an internal position later ... - ret_off = m_stream->OnSysSeek(pos, wxFromStart); - ResetBuffer(); - return ret_off; - - case wxFromCurrent: - diff = pos + GetIntPosition(); - - if ( (diff > last_access) || (diff < 0) ) - { - // We must take into account the fact that we have read - // something previously. - ret_off = m_stream->OnSysSeek(diff-last_access, wxFromCurrent); - ResetBuffer(); - return ret_off; - } - else - { - size_t int_diff = wx_truncate_cast(size_t, diff); - wxCHECK_MSG( (wxFileOffset)int_diff == diff, wxInvalidOffset, wxT("huge file not supported") ); - SetIntPosition(int_diff); - return pos; - } - - case wxFromEnd: - // Hard to compute: always seek to the requested position. - ret_off = m_stream->OnSysSeek(pos, wxFromEnd); - ResetBuffer(); - return ret_off; - } - - return wxInvalidOffset; -} - -wxFileOffset wxStreamBuffer::Tell() const -{ - wxFileOffset pos; - - // ask the stream for position if we have a real one - if ( m_stream ) - { - pos = m_stream->OnSysTell(); - if ( pos == wxInvalidOffset ) - return wxInvalidOffset; - } - else // no associated stream - { - pos = 0; - } - - pos += GetIntPosition(); - - if ( m_mode == read && m_flushable ) - pos -= GetLastAccess(); - - return pos; -} - -// ---------------------------------------------------------------------------- -// wxStreamBase -// ---------------------------------------------------------------------------- - -wxStreamBase::wxStreamBase() -{ - m_lasterror = wxSTREAM_NO_ERROR; - m_lastcount = 0; -} - -wxStreamBase::~wxStreamBase() -{ -} - -size_t wxStreamBase::GetSize() const -{ - wxFileOffset length = GetLength(); - if ( length == (wxFileOffset)wxInvalidOffset ) - return 0; - - const size_t len = wx_truncate_cast(size_t, length); - wxASSERT_MSG( len == length + size_t(0), _T("large files not supported") ); - - return len; -} - -wxFileOffset wxStreamBase::OnSysSeek(wxFileOffset WXUNUSED(seek), wxSeekMode WXUNUSED(mode)) -{ - return wxInvalidOffset; -} - -wxFileOffset wxStreamBase::OnSysTell() const -{ - return wxInvalidOffset; -} - -// ---------------------------------------------------------------------------- -// wxInputStream -// ---------------------------------------------------------------------------- - -wxInputStream::wxInputStream() -{ - m_wback = NULL; - m_wbacksize = - m_wbackcur = 0; -} - -wxInputStream::~wxInputStream() -{ - free(m_wback); -} - -bool wxInputStream::CanRead() const -{ - // we don't know if there is anything to read or not and by default we - // prefer to be optimistic and try to read data unless we know for sure - // there is no more of it - return m_lasterror != wxSTREAM_EOF; -} - -bool wxInputStream::Eof() const -{ - // the only way the base class can know we're at EOF is when we'd already - // tried to read beyond it in which case last error is set accordingly - return GetLastError() == wxSTREAM_EOF; -} - -char *wxInputStream::AllocSpaceWBack(size_t needed_size) -{ - // get number of bytes left from previous wback buffer - size_t toget = m_wbacksize - m_wbackcur; - - // allocate a buffer large enough to hold prev + new data - char *temp_b = (char *)malloc(needed_size + toget); - - if (!temp_b) - return NULL; - - // copy previous data (and free old buffer) if needed - if (m_wback) - { - memmove(temp_b + needed_size, m_wback + m_wbackcur, toget); - free(m_wback); - } - - // done - m_wback = temp_b; - m_wbackcur = 0; - m_wbacksize = needed_size + toget; - - return m_wback; -} - -size_t wxInputStream::GetWBack(void *buf, size_t size) -{ - wxASSERT_MSG( buf, _T("Warning: Null pointer is about to be used") ); - - /* Clear buffer first */ - memset(buf, 0x00, size); - - if (!m_wback) - return 0; - - // how many bytes do we have in the buffer? - size_t toget = m_wbacksize - m_wbackcur; - - if ( size < toget ) - { - // we won't read everything - toget = size; - } - - // copy the data from the cache - memcpy(buf, m_wback + m_wbackcur, toget); - - m_wbackcur += toget; - if ( m_wbackcur == m_wbacksize ) - { - // TODO: should we really free it here all the time? maybe keep it? - free(m_wback); - m_wback = NULL; - m_wbacksize = 0; - m_wbackcur = 0; - } - - // return the number of bytes copied - return toget; -} - -size_t wxInputStream::Ungetch(const void *buf, size_t bufsize) -{ - wxASSERT_MSG( buf, _T("Warning: Null pointer is about to be used in Ungetch()") ); - - if ( m_lasterror != wxSTREAM_NO_ERROR && m_lasterror != wxSTREAM_EOF ) - { - // can't operate on this stream until the error is cleared - return 0; - } - - char *ptrback = AllocSpaceWBack(bufsize); - if (!ptrback) - return 0; - - // Eof() shouldn't return true any longer - if ( m_lasterror == wxSTREAM_EOF ) - m_lasterror = wxSTREAM_NO_ERROR; - - memcpy(ptrback, buf, bufsize); - return bufsize; -} - -bool wxInputStream::Ungetch(char c) -{ - return Ungetch(&c, sizeof(c)) != 0; -} - -int wxInputStream::GetC() -{ - unsigned char c; - Read(&c, sizeof(c)); - return LastRead() ? c : wxEOF; -} - -wxInputStream& wxInputStream::Read(void *buf, size_t size) -{ - wxASSERT_MSG( buf, _T("Warning: Null pointer is about to be read") ); - - char *p = (char *)buf; - m_lastcount = 0; - - size_t read = GetWBack(buf, size); - for ( ;; ) - { - size -= read; - m_lastcount += read; - p += read; - - if ( !size ) - { - // we read the requested amount of data - break; - } - - if ( p != buf && !CanRead() ) - { - // we have already read something and we would block in OnSysRead() - // now: don't do it but return immediately - break; - } - - read = OnSysRead(p, size); - if ( !read ) - { - // no more data available - break; - } - } - - return *this; -} - -char wxInputStream::Peek() -{ - char c; - Read(&c, sizeof(c)); - if (m_lasterror == wxSTREAM_NO_ERROR) - { - Ungetch(c); - return c; - } - - return 0; -} - -wxInputStream& wxInputStream::Read(wxOutputStream& stream_out) -{ - size_t lastcount = 0; - char buf[BUF_TEMP_SIZE]; - - for ( ;; ) - { - size_t bytes_read = Read(buf, WXSIZEOF(buf)).LastRead(); - if ( !bytes_read ) - break; - - if ( stream_out.Write(buf, bytes_read).LastWrite() != bytes_read ) - break; - - lastcount += bytes_read; - } - - m_lastcount = lastcount; - - return *this; -} - -wxFileOffset wxInputStream::SeekI(wxFileOffset pos, wxSeekMode mode) -{ - // RR: This code is duplicated in wxBufferedInputStream. This is - // not really a good design, but buffered stream are different - // from all other in that they handle two stream-related objects, - // the stream buffer and parent stream. - - // I don't know whether it should be put as well in wxFileInputStream::OnSysSeek - if (m_lasterror==wxSTREAM_EOF) - m_lasterror=wxSTREAM_NO_ERROR; - - /* RR: A call to SeekI() will automatically invalidate any previous - call to Ungetch(), otherwise it would be possible to SeekI() to - one position, unread some bytes there, SeekI() to another position - and the data would be corrupted. - - GRG: Could add code here to try to navigate within the wback - buffer if possible, but is it really needed? It would only work - when seeking in wxFromCurrent mode, else it would invalidate - anyway... */ - - if (m_wback) - { - wxLogDebug( wxT("Seeking in stream which has data written back to it.") ); - - free(m_wback); - m_wback = NULL; - m_wbacksize = 0; - m_wbackcur = 0; - } - - return OnSysSeek(pos, mode); -} - -wxFileOffset wxInputStream::TellI() const -{ - wxFileOffset pos = OnSysTell(); - - if (pos != wxInvalidOffset) - pos -= (m_wbacksize - m_wbackcur); - - return pos; -} - - -// ---------------------------------------------------------------------------- -// wxOutputStream -// ---------------------------------------------------------------------------- - -wxOutputStream::wxOutputStream() -{ -} - -wxOutputStream::~wxOutputStream() -{ -} - -size_t wxOutputStream::OnSysWrite(const void * WXUNUSED(buffer), - size_t WXUNUSED(bufsize)) -{ - return 0; -} - -void wxOutputStream::PutC(char c) -{ - Write(&c, sizeof(c)); -} - -wxOutputStream& wxOutputStream::Write(const void *buffer, size_t size) -{ - m_lastcount = OnSysWrite(buffer, size); - return *this; -} - -wxOutputStream& wxOutputStream::Write(wxInputStream& stream_in) -{ - stream_in.Read(*this); - return *this; -} - -wxFileOffset wxOutputStream::TellO() const -{ - return OnSysTell(); -} - -wxFileOffset wxOutputStream::SeekO(wxFileOffset pos, wxSeekMode mode) -{ - return OnSysSeek(pos, mode); -} - -void wxOutputStream::Sync() -{ -} - - -// ---------------------------------------------------------------------------- -// wxCountingOutputStream -// ---------------------------------------------------------------------------- - -wxCountingOutputStream::wxCountingOutputStream () -{ - m_currentPos = 0; -} - -wxFileOffset wxCountingOutputStream::GetLength() const -{ - return m_lastcount; -} - -size_t wxCountingOutputStream::OnSysWrite(const void *WXUNUSED(buffer), - size_t size) -{ - m_currentPos += size; - if (m_currentPos > m_lastcount) - m_lastcount = m_currentPos; - - return m_currentPos; -} - -wxFileOffset wxCountingOutputStream::OnSysSeek(wxFileOffset pos, wxSeekMode mode) -{ - ssize_t new_pos = wx_truncate_cast(ssize_t, pos); - - switch ( mode ) - { - case wxFromStart: - wxCHECK_MSG( (wxFileOffset)new_pos == pos, wxInvalidOffset, wxT("huge position not supported") ); - break; - - case wxFromEnd: - new_pos = m_lastcount + new_pos; - wxCHECK_MSG( (wxFileOffset)new_pos == (wxFileOffset)(m_lastcount + pos), wxInvalidOffset, wxT("huge position not supported") ); - break; - - case wxFromCurrent: - new_pos = m_currentPos + new_pos; - wxCHECK_MSG( (wxFileOffset)new_pos == (wxFileOffset)(m_currentPos + pos), wxInvalidOffset, wxT("huge position not supported") ); - break; - - default: - wxFAIL_MSG( _T("invalid seek mode") ); - return wxInvalidOffset; - } - - m_currentPos = new_pos; - - if (m_currentPos > m_lastcount) - m_lastcount = m_currentPos; - - return m_currentPos; -} - -wxFileOffset wxCountingOutputStream::OnSysTell() const -{ - return m_currentPos; -} - -// ---------------------------------------------------------------------------- -// wxFilterInputStream -// ---------------------------------------------------------------------------- - -wxFilterInputStream::wxFilterInputStream() - : m_parent_i_stream(NULL), - m_owns(false) -{ -} - -wxFilterInputStream::wxFilterInputStream(wxInputStream& stream) - : m_parent_i_stream(&stream), - m_owns(false) -{ -} - -wxFilterInputStream::wxFilterInputStream(wxInputStream *stream) - : m_parent_i_stream(stream), - m_owns(true) -{ -} - -wxFilterInputStream::~wxFilterInputStream() -{ - if (m_owns) - delete m_parent_i_stream; -} - -// ---------------------------------------------------------------------------- -// wxFilterOutputStream -// ---------------------------------------------------------------------------- - -wxFilterOutputStream::wxFilterOutputStream() - : m_parent_o_stream(NULL), - m_owns(false) -{ -} - -wxFilterOutputStream::wxFilterOutputStream(wxOutputStream& stream) - : m_parent_o_stream(&stream), - m_owns(false) -{ -} - -wxFilterOutputStream::wxFilterOutputStream(wxOutputStream *stream) - : m_parent_o_stream(stream), - m_owns(true) -{ -} - -bool wxFilterOutputStream::Close() -{ - if (m_parent_o_stream && m_owns) - return m_parent_o_stream->Close(); - else - return true; -} - -wxFilterOutputStream::~wxFilterOutputStream() -{ - if (m_owns) - delete m_parent_o_stream; -} - -// ---------------------------------------------------------------------------- -// wxFilterClassFactoryBase -// ---------------------------------------------------------------------------- - -IMPLEMENT_ABSTRACT_CLASS(wxFilterClassFactoryBase, wxObject) - -wxString wxFilterClassFactoryBase::PopExtension(const wxString& location) const -{ - return location.substr(0, FindExtension(location)); -} - -wxString::size_type wxFilterClassFactoryBase::FindExtension( - const wxChar *location) const -{ - size_t len = wxStrlen(location); - - for (const wxChar *const *p = GetProtocols(wxSTREAM_FILEEXT); *p; p++) - { - size_t l = wxStrlen(*p); - - if (l <= len && wxStrcmp(*p, location + len - l) == 0) - return len - l; - } - - return wxString::npos; -} - -bool wxFilterClassFactoryBase::CanHandle(const wxChar *protocol, - wxStreamProtocolType type) const -{ - if (type == wxSTREAM_FILEEXT) - return FindExtension(protocol) != wxString::npos; - else - for (const wxChar *const *p = GetProtocols(type); *p; p++) - if (wxStrcmp(*p, protocol) == 0) - return true; - - return false; -} - -// ---------------------------------------------------------------------------- -// wxFilterClassFactory -// ---------------------------------------------------------------------------- - -IMPLEMENT_ABSTRACT_CLASS(wxFilterClassFactory, wxFilterClassFactoryBase) - -wxFilterClassFactory *wxFilterClassFactory::sm_first = NULL; - -void wxFilterClassFactory::Remove() -{ - if (m_next != this) - { - wxFilterClassFactory **pp = &sm_first; - - while (*pp != this) - pp = &(*pp)->m_next; - - *pp = m_next; - - m_next = this; - } -} - -// ---------------------------------------------------------------------------- -// wxBufferedInputStream -// ---------------------------------------------------------------------------- - -wxBufferedInputStream::wxBufferedInputStream(wxInputStream& s, - wxStreamBuffer *buffer) - : wxFilterInputStream(s) -{ - if ( buffer ) - { - // use the buffer provided by the user - m_i_streambuf = buffer; - } - else // create a default buffer - { - m_i_streambuf = new wxStreamBuffer(*this, wxStreamBuffer::read); - - m_i_streambuf->SetBufferIO(1024); - } -} - -wxBufferedInputStream::~wxBufferedInputStream() -{ - m_parent_i_stream->SeekI(-(wxFileOffset)m_i_streambuf->GetBytesLeft(), - wxFromCurrent); - - delete m_i_streambuf; -} - -char wxBufferedInputStream::Peek() -{ - return m_i_streambuf->Peek(); -} - -wxInputStream& wxBufferedInputStream::Read(void *buf, size_t size) -{ - // reset the error flag - Reset(); - - // first read from the already cached data - m_lastcount = GetWBack(buf, size); - - // do we have to read anything more? - if ( m_lastcount < size ) - { - size -= m_lastcount; - buf = (char *)buf + m_lastcount; - - // the call to wxStreamBuffer::Read() below may reset our m_lastcount - // (but it also may not do it if the buffer is associated to another - // existing stream and wasn't created by us), so save it - size_t countOld = m_lastcount; - - // the new count of the bytes read is the count of bytes read this time - m_lastcount = m_i_streambuf->Read(buf, size); - - // plus those we had read before - m_lastcount += countOld; - } - - return *this; -} - -wxFileOffset wxBufferedInputStream::SeekI(wxFileOffset pos, wxSeekMode mode) -{ - // RR: Look at wxInputStream for comments. - - if (m_lasterror==wxSTREAM_EOF) - Reset(); - - if (m_wback) - { - wxLogDebug( wxT("Seeking in stream which has data written back to it.") ); - - free(m_wback); - m_wback = NULL; - m_wbacksize = 0; - m_wbackcur = 0; - } - - return m_i_streambuf->Seek(pos, mode); -} - -wxFileOffset wxBufferedInputStream::TellI() const -{ - wxFileOffset pos = m_i_streambuf->Tell(); - - if (pos != wxInvalidOffset) - pos -= (m_wbacksize - m_wbackcur); - - return pos; -} - -size_t wxBufferedInputStream::OnSysRead(void *buffer, size_t bufsize) -{ - return m_parent_i_stream->Read(buffer, bufsize).LastRead(); -} - -wxFileOffset wxBufferedInputStream::OnSysSeek(wxFileOffset seek, wxSeekMode mode) -{ - return m_parent_i_stream->SeekI(seek, mode); -} - -wxFileOffset wxBufferedInputStream::OnSysTell() const -{ - return m_parent_i_stream->TellI(); -} - -void wxBufferedInputStream::SetInputStreamBuffer(wxStreamBuffer *buffer) -{ - wxCHECK_RET( buffer, _T("wxBufferedInputStream needs buffer") ); - - delete m_i_streambuf; - m_i_streambuf = buffer; -} - -// ---------------------------------------------------------------------------- -// wxBufferedOutputStream -// ---------------------------------------------------------------------------- - -wxBufferedOutputStream::wxBufferedOutputStream(wxOutputStream& s, - wxStreamBuffer *buffer) - : wxFilterOutputStream(s) -{ - if ( buffer ) - { - m_o_streambuf = buffer; - } - else // create a default one - { - m_o_streambuf = new wxStreamBuffer(*this, wxStreamBuffer::write); - - m_o_streambuf->SetBufferIO(1024); - } -} - -wxBufferedOutputStream::~wxBufferedOutputStream() -{ - Sync(); - delete m_o_streambuf; -} - -bool wxBufferedOutputStream::Close() -{ - Sync(); - return IsOk(); -} - - -wxOutputStream& wxBufferedOutputStream::Write(const void *buffer, size_t size) -{ - m_lastcount = 0; - m_o_streambuf->Write(buffer, size); - return *this; -} - -wxFileOffset wxBufferedOutputStream::SeekO(wxFileOffset pos, wxSeekMode mode) -{ - Sync(); - return m_o_streambuf->Seek(pos, mode); -} - -wxFileOffset wxBufferedOutputStream::TellO() const -{ - return m_o_streambuf->Tell(); -} - -void wxBufferedOutputStream::Sync() -{ - m_o_streambuf->FlushBuffer(); - m_parent_o_stream->Sync(); -} - -size_t wxBufferedOutputStream::OnSysWrite(const void *buffer, size_t bufsize) -{ - return m_parent_o_stream->Write(buffer, bufsize).LastWrite(); -} - -wxFileOffset wxBufferedOutputStream::OnSysSeek(wxFileOffset seek, wxSeekMode mode) -{ - return m_parent_o_stream->SeekO(seek, mode); -} - -wxFileOffset wxBufferedOutputStream::OnSysTell() const -{ - return m_parent_o_stream->TellO(); -} - -wxFileOffset wxBufferedOutputStream::GetLength() const -{ - return m_parent_o_stream->GetLength() + m_o_streambuf->GetIntPosition(); -} - -void wxBufferedOutputStream::SetOutputStreamBuffer(wxStreamBuffer *buffer) -{ - wxCHECK_RET( buffer, _T("wxBufferedOutputStream needs buffer") ); - - delete m_o_streambuf; - m_o_streambuf = buffer; -} - -// ---------------------------------------------------------------------------- -// Some IOManip function -// ---------------------------------------------------------------------------- - -wxOutputStream& wxEndL(wxOutputStream& stream) -{ - static const wxChar *eol = wxTextFile::GetEOL(); - - return stream.Write(eol, wxStrlen(eol)); -} - -#endif // wxUSE_STREAMS +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/stream.cpp +// Purpose: wxStream base classes +// Author: Guilhem Lavaux +// Modified by: VZ (23.11.00) to fix realloc()ing new[]ed memory, +// general code review +// Created: 11/07/98 +// RCS-ID: $Id: stream.cpp 51662 2008-02-11 20:23:29Z VZ $ +// Copyright: (c) Guilhem Lavaux +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_STREAMS + +#include "wx/stream.h" + +#ifndef WX_PRECOMP + #include "wx/log.h" +#endif + +#include +#include "wx/datstrm.h" +#include "wx/textfile.h" + +// ---------------------------------------------------------------------------- +// constants +// ---------------------------------------------------------------------------- + +// the temporary buffer size used when copying from stream to stream +#define BUF_TEMP_SIZE 4096 + +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// wxStreamBuffer +// ---------------------------------------------------------------------------- + +void wxStreamBuffer::SetError(wxStreamError err) +{ + if ( m_stream && m_stream->m_lasterror == wxSTREAM_NO_ERROR ) + m_stream->m_lasterror = err; +} + +void wxStreamBuffer::InitBuffer() +{ + m_buffer_start = + m_buffer_end = + m_buffer_pos = NULL; + m_buffer_size = 0; + + // if we are going to allocate the buffer, we should free it later as well + m_destroybuf = true; +} + +void wxStreamBuffer::Init() +{ + InitBuffer(); + + m_fixed = true; +} + +wxStreamBuffer::wxStreamBuffer(BufMode mode) +{ + Init(); + + m_stream = NULL; + m_mode = mode; + + m_flushable = false; +} + +wxStreamBuffer::wxStreamBuffer(wxStreamBase& stream, BufMode mode) +{ + Init(); + + m_stream = &stream; + m_mode = mode; + + m_flushable = true; +} + +wxStreamBuffer::wxStreamBuffer(const wxStreamBuffer& buffer) +{ + // doing this has big chances to lead to a crash when the source buffer is + // destroyed (otherwise assume the caller knows what he does) + wxASSERT_MSG( !buffer.m_destroybuf, + _T("it's a bad idea to copy this buffer") ); + + m_buffer_start = buffer.m_buffer_start; + m_buffer_end = buffer.m_buffer_end; + m_buffer_pos = buffer.m_buffer_pos; + m_buffer_size = buffer.m_buffer_size; + m_fixed = buffer.m_fixed; + m_flushable = buffer.m_flushable; + m_stream = buffer.m_stream; + m_mode = buffer.m_mode; + m_destroybuf = false; +} + +void wxStreamBuffer::FreeBuffer() +{ + if ( m_destroybuf ) + { + free(m_buffer_start); + m_buffer_start = NULL; + } +} + +wxStreamBuffer::~wxStreamBuffer() +{ + FreeBuffer(); +} + +wxInputStream *wxStreamBuffer::GetInputStream() const +{ + return m_mode == write ? NULL : (wxInputStream *)m_stream; +} + +wxOutputStream *wxStreamBuffer::GetOutputStream() const +{ + return m_mode == read ? NULL : (wxOutputStream *)m_stream; +} + +void wxStreamBuffer::SetBufferIO(void *buffer_start, + void *buffer_end, + bool takeOwnership) +{ + SetBufferIO(buffer_start, (char *)buffer_end - (char *)buffer_start, + takeOwnership); +} + +void wxStreamBuffer::SetBufferIO(void *start, + size_t len, + bool takeOwnership) +{ + // start by freeing the old buffer + FreeBuffer(); + + m_buffer_start = (char *)start; + m_buffer_end = m_buffer_start + len; + + m_buffer_size = len; + + // if we own it, we free it + m_destroybuf = takeOwnership; + + ResetBuffer(); +} + +void wxStreamBuffer::SetBufferIO(size_t bufsize) +{ + if ( bufsize ) + { + // this will free the old buffer and allocate the new one + SetBufferIO(malloc(bufsize), bufsize, true /* take ownership */); + } + else // no buffer size => no buffer + { + // still free the old one + FreeBuffer(); + InitBuffer(); + } +} + +void wxStreamBuffer::ResetBuffer() +{ + if ( m_stream ) + { + m_stream->Reset(); + m_stream->m_lastcount = 0; + } + + m_buffer_pos = m_mode == read && m_flushable + ? m_buffer_end + : m_buffer_start; +} + +// fill the buffer with as much data as possible (only for read buffers) +bool wxStreamBuffer::FillBuffer() +{ + wxInputStream *inStream = GetInputStream(); + + // It's legal to have no stream, so we don't complain about it just return false + if ( !inStream ) + return false; + + size_t count = inStream->OnSysRead(m_buffer_start, m_buffer_size); + if ( !count ) + return false; + + m_buffer_end = m_buffer_start + count; + m_buffer_pos = m_buffer_start; + + return true; +} + +// write the buffer contents to the stream (only for write buffers) +bool wxStreamBuffer::FlushBuffer() +{ + wxCHECK_MSG( m_flushable, false, _T("can't flush this buffer") ); + + // FIXME: what is this check for? (VZ) + if ( m_buffer_pos == m_buffer_start ) + return false; + + wxOutputStream *outStream = GetOutputStream(); + + wxCHECK_MSG( outStream, false, _T("should have a stream in wxStreamBuffer") ); + + size_t current = m_buffer_pos - m_buffer_start; + size_t count = outStream->OnSysWrite(m_buffer_start, current); + if ( count != current ) + return false; + + m_buffer_pos = m_buffer_start; + + return true; +} + +size_t wxStreamBuffer::GetDataLeft() +{ + /* Why is this done? RR. */ + if ( m_buffer_pos == m_buffer_end && m_flushable) + FillBuffer(); + + return GetBytesLeft(); +} + +// copy up to size bytes from our buffer into the provided one +void wxStreamBuffer::GetFromBuffer(void *buffer, size_t size) +{ + // don't get more bytes than left in the buffer + size_t left = GetBytesLeft(); + + if ( size > left ) + size = left; + + memcpy(buffer, m_buffer_pos, size); + m_buffer_pos += size; +} + +// copy the contents of the provided buffer into this one +void wxStreamBuffer::PutToBuffer(const void *buffer, size_t size) +{ + size_t left = GetBytesLeft(); + + if ( size > left ) + { + if ( m_fixed ) + { + // we can't realloc the buffer, so just copy what we can + size = left; + } + else // !m_fixed + { + // realloc the buffer to have enough space for the data + size_t delta = m_buffer_pos - m_buffer_start; + + char *startOld = m_buffer_start; + m_buffer_size += size; + m_buffer_start = (char *)realloc(m_buffer_start, m_buffer_size); + if ( !m_buffer_start ) + { + // don't leak memory if realloc() failed + m_buffer_start = startOld; + m_buffer_size -= size; + + // what else can we do? + return; + } + + // adjust the pointers invalidated by realloc() + m_buffer_pos = m_buffer_start + delta; + m_buffer_end = m_buffer_start + m_buffer_size; + } + } + + memcpy(m_buffer_pos, buffer, size); + m_buffer_pos += size; +} + +void wxStreamBuffer::PutChar(char c) +{ + wxOutputStream *outStream = GetOutputStream(); + + wxCHECK_RET( outStream, _T("should have a stream in wxStreamBuffer") ); + + // if we don't have buffer at all, just forward this call to the stream, + if ( !HasBuffer() ) + { + outStream->OnSysWrite(&c, sizeof(c)); + } + else + { + // otherwise check we have enough space left + if ( !GetDataLeft() && !FlushBuffer() ) + { + // we don't + SetError(wxSTREAM_WRITE_ERROR); + } + else + { + PutToBuffer(&c, sizeof(c)); + m_stream->m_lastcount = 1; + } + } +} + +char wxStreamBuffer::Peek() +{ + wxCHECK_MSG( m_stream && HasBuffer(), 0, + _T("should have the stream and the buffer in wxStreamBuffer") ); + + if ( !GetDataLeft() ) + { + SetError(wxSTREAM_READ_ERROR); + return 0; + } + + char c; + GetFromBuffer(&c, sizeof(c)); + m_buffer_pos--; + + return c; +} + +char wxStreamBuffer::GetChar() +{ + wxInputStream *inStream = GetInputStream(); + + wxCHECK_MSG( inStream, 0, _T("should have a stream in wxStreamBuffer") ); + + char c; + if ( !HasBuffer() ) + { + inStream->OnSysRead(&c, sizeof(c)); + } + else + { + if ( !GetDataLeft() ) + { + SetError(wxSTREAM_READ_ERROR); + c = 0; + } + else + { + GetFromBuffer(&c, sizeof(c)); + m_stream->m_lastcount = 1; + } + } + + return c; +} + +size_t wxStreamBuffer::Read(void *buffer, size_t size) +{ + wxASSERT_MSG( buffer, _T("Warning: Null pointer is about to be used") ); + + /* Clear buffer first */ + memset(buffer, 0x00, size); + + // lasterror is reset before all new IO calls + if ( m_stream ) + m_stream->Reset(); + + size_t readBytes; + if ( !HasBuffer() ) + { + wxInputStream *inStream = GetInputStream(); + + wxCHECK_MSG( inStream, 0, _T("should have a stream in wxStreamBuffer") ); + + readBytes = inStream->OnSysRead(buffer, size); + } + else // we have a buffer, use it + { + size_t orig_size = size; + + while ( size > 0 ) + { + size_t left = GetDataLeft(); + + // if the requested number of bytes if greater than the buffer + // size, read data in chunks + if ( size > left ) + { + GetFromBuffer(buffer, left); + size -= left; + buffer = (char *)buffer + left; + + if ( !FillBuffer() ) + { + SetError(wxSTREAM_EOF); + break; + } + } + else // otherwise just do it in one gulp + { + GetFromBuffer(buffer, size); + size = 0; + } + } + + readBytes = orig_size - size; + } + + if ( m_stream ) + m_stream->m_lastcount = readBytes; + + return readBytes; +} + +// this should really be called "Copy()" +size_t wxStreamBuffer::Read(wxStreamBuffer *dbuf) +{ + wxCHECK_MSG( m_mode != write, 0, _T("can't read from this buffer") ); + + char buf[BUF_TEMP_SIZE]; + size_t nRead, + total = 0; + + do + { + nRead = Read(buf, WXSIZEOF(buf)); + if ( nRead ) + { + nRead = dbuf->Write(buf, nRead); + total += nRead; + } + } + while ( nRead ); + + return total; +} + +size_t wxStreamBuffer::Write(const void *buffer, size_t size) +{ + wxASSERT_MSG( buffer, _T("Warning: Null pointer is about to be send") ); + + if (m_stream) + { + // lasterror is reset before all new IO calls + m_stream->Reset(); + } + + size_t ret; + + if ( !HasBuffer() && m_fixed ) + { + wxOutputStream *outStream = GetOutputStream(); + + wxCHECK_MSG( outStream, 0, _T("should have a stream in wxStreamBuffer") ); + + // no buffer, just forward the call to the stream + ret = outStream->OnSysWrite(buffer, size); + } + else // we [may] have a buffer, use it + { + size_t orig_size = size; + + while ( size > 0 ) + { + size_t left = GetBytesLeft(); + + // if the buffer is too large to fit in the stream buffer, split + // it in smaller parts + // + // NB: If stream buffer isn't fixed (as for wxMemoryOutputStream), + // we always go to the second case. + // + // FIXME: fine, but if it fails we should (re)try writing it by + // chunks as this will (hopefully) always work (VZ) + + if ( size > left && m_fixed ) + { + PutToBuffer(buffer, left); + size -= left; + buffer = (char *)buffer + left; + + if ( !FlushBuffer() ) + { + SetError(wxSTREAM_WRITE_ERROR); + + break; + } + + m_buffer_pos = m_buffer_start; + } + else // we can do it in one gulp + { + PutToBuffer(buffer, size); + size = 0; + } + } + + ret = orig_size - size; + } + + if (m_stream) + { + // i am not entirely sure what we do this for + m_stream->m_lastcount = ret; + } + + return ret; +} + +size_t wxStreamBuffer::Write(wxStreamBuffer *sbuf) +{ + wxCHECK_MSG( m_mode != read, 0, _T("can't write to this buffer") ); + wxCHECK_MSG( sbuf->m_mode != write, 0, _T("can't read from that buffer") ); + + char buf[BUF_TEMP_SIZE]; + size_t nWrite, + total = 0; + + do + { + size_t nRead = sbuf->Read(buf, WXSIZEOF(buf)); + if ( nRead ) + { + nWrite = Write(buf, nRead); + if ( nWrite < nRead ) + { + // put back data we couldn't copy + wxInputStream *in_stream = (wxInputStream *)sbuf->GetStream(); + + in_stream->Ungetch(buf + nWrite, nRead - nWrite); + } + + total += nWrite; + } + else + { + nWrite = 0; + } + } + while ( nWrite == WXSIZEOF(buf) ); + + return total; +} + +wxFileOffset wxStreamBuffer::Seek(wxFileOffset pos, wxSeekMode mode) +{ + wxFileOffset ret_off, diff; + + wxFileOffset last_access = GetLastAccess(); + + if ( !m_flushable ) + { + switch (mode) + { + case wxFromStart: + diff = pos; + break; + + case wxFromCurrent: + diff = pos + GetIntPosition(); + break; + + case wxFromEnd: + diff = pos + last_access; + break; + + default: + wxFAIL_MSG( _T("invalid seek mode") ); + + return wxInvalidOffset; + } + if (diff < 0 || diff > last_access) + return wxInvalidOffset; + size_t int_diff = wx_truncate_cast(size_t, diff); + wxCHECK_MSG( (wxFileOffset)int_diff == diff, wxInvalidOffset, wxT("huge file not supported") ); + SetIntPosition(int_diff); + return diff; + } + + switch ( mode ) + { + case wxFromStart: + // We'll try to compute an internal position later ... + ret_off = m_stream->OnSysSeek(pos, wxFromStart); + ResetBuffer(); + return ret_off; + + case wxFromCurrent: + diff = pos + GetIntPosition(); + + if ( (diff > last_access) || (diff < 0) ) + { + // We must take into account the fact that we have read + // something previously. + ret_off = m_stream->OnSysSeek(diff-last_access, wxFromCurrent); + ResetBuffer(); + return ret_off; + } + else + { + size_t int_diff = wx_truncate_cast(size_t, diff); + wxCHECK_MSG( (wxFileOffset)int_diff == diff, wxInvalidOffset, wxT("huge file not supported") ); + SetIntPosition(int_diff); + return pos; + } + + case wxFromEnd: + // Hard to compute: always seek to the requested position. + ret_off = m_stream->OnSysSeek(pos, wxFromEnd); + ResetBuffer(); + return ret_off; + } + + return wxInvalidOffset; +} + +wxFileOffset wxStreamBuffer::Tell() const +{ + wxFileOffset pos; + + // ask the stream for position if we have a real one + if ( m_stream ) + { + pos = m_stream->OnSysTell(); + if ( pos == wxInvalidOffset ) + return wxInvalidOffset; + } + else // no associated stream + { + pos = 0; + } + + pos += GetIntPosition(); + + if ( m_mode == read && m_flushable ) + pos -= GetLastAccess(); + + return pos; +} + +// ---------------------------------------------------------------------------- +// wxStreamBase +// ---------------------------------------------------------------------------- + +wxStreamBase::wxStreamBase() +{ + m_lasterror = wxSTREAM_NO_ERROR; + m_lastcount = 0; +} + +wxStreamBase::~wxStreamBase() +{ +} + +size_t wxStreamBase::GetSize() const +{ + wxFileOffset length = GetLength(); + if ( length == (wxFileOffset)wxInvalidOffset ) + return 0; + + const size_t len = wx_truncate_cast(size_t, length); + wxASSERT_MSG( len == length + size_t(0), _T("large files not supported") ); + + return len; +} + +wxFileOffset wxStreamBase::OnSysSeek(wxFileOffset WXUNUSED(seek), wxSeekMode WXUNUSED(mode)) +{ + return wxInvalidOffset; +} + +wxFileOffset wxStreamBase::OnSysTell() const +{ + return wxInvalidOffset; +} + +// ---------------------------------------------------------------------------- +// wxInputStream +// ---------------------------------------------------------------------------- + +wxInputStream::wxInputStream() +{ + m_wback = NULL; + m_wbacksize = + m_wbackcur = 0; +} + +wxInputStream::~wxInputStream() +{ + free(m_wback); +} + +bool wxInputStream::CanRead() const +{ + // we don't know if there is anything to read or not and by default we + // prefer to be optimistic and try to read data unless we know for sure + // there is no more of it + return m_lasterror != wxSTREAM_EOF; +} + +bool wxInputStream::Eof() const +{ + // the only way the base class can know we're at EOF is when we'd already + // tried to read beyond it in which case last error is set accordingly + return GetLastError() == wxSTREAM_EOF; +} + +char *wxInputStream::AllocSpaceWBack(size_t needed_size) +{ + // get number of bytes left from previous wback buffer + size_t toget = m_wbacksize - m_wbackcur; + + // allocate a buffer large enough to hold prev + new data + char *temp_b = (char *)malloc(needed_size + toget); + + if (!temp_b) + return NULL; + + // copy previous data (and free old buffer) if needed + if (m_wback) + { + memmove(temp_b + needed_size, m_wback + m_wbackcur, toget); + free(m_wback); + } + + // done + m_wback = temp_b; + m_wbackcur = 0; + m_wbacksize = needed_size + toget; + + return m_wback; +} + +size_t wxInputStream::GetWBack(void *buf, size_t size) +{ + wxASSERT_MSG( buf, _T("Warning: Null pointer is about to be used") ); + + /* Clear buffer first */ + memset(buf, 0x00, size); + + if (!m_wback) + return 0; + + // how many bytes do we have in the buffer? + size_t toget = m_wbacksize - m_wbackcur; + + if ( size < toget ) + { + // we won't read everything + toget = size; + } + + // copy the data from the cache + memcpy(buf, m_wback + m_wbackcur, toget); + + m_wbackcur += toget; + if ( m_wbackcur == m_wbacksize ) + { + // TODO: should we really free it here all the time? maybe keep it? + free(m_wback); + m_wback = NULL; + m_wbacksize = 0; + m_wbackcur = 0; + } + + // return the number of bytes copied + return toget; +} + +size_t wxInputStream::Ungetch(const void *buf, size_t bufsize) +{ + wxASSERT_MSG( buf, _T("Warning: Null pointer is about to be used in Ungetch()") ); + + if ( m_lasterror != wxSTREAM_NO_ERROR && m_lasterror != wxSTREAM_EOF ) + { + // can't operate on this stream until the error is cleared + return 0; + } + + char *ptrback = AllocSpaceWBack(bufsize); + if (!ptrback) + return 0; + + // Eof() shouldn't return true any longer + if ( m_lasterror == wxSTREAM_EOF ) + m_lasterror = wxSTREAM_NO_ERROR; + + memcpy(ptrback, buf, bufsize); + return bufsize; +} + +bool wxInputStream::Ungetch(char c) +{ + return Ungetch(&c, sizeof(c)) != 0; +} + +int wxInputStream::GetC() +{ + unsigned char c; + Read(&c, sizeof(c)); + return LastRead() ? c : wxEOF; +} + +wxInputStream& wxInputStream::Read(void *buf, size_t size) +{ + wxASSERT_MSG( buf, _T("Warning: Null pointer is about to be read") ); + + char *p = (char *)buf; + m_lastcount = 0; + + size_t read = GetWBack(buf, size); + for ( ;; ) + { + size -= read; + m_lastcount += read; + p += read; + + if ( !size ) + { + // we read the requested amount of data + break; + } + + if ( p != buf && !CanRead() ) + { + // we have already read something and we would block in OnSysRead() + // now: don't do it but return immediately + break; + } + + read = OnSysRead(p, size); + if ( !read ) + { + // no more data available + break; + } + } + + return *this; +} + +char wxInputStream::Peek() +{ + char c; + Read(&c, sizeof(c)); + if (m_lasterror == wxSTREAM_NO_ERROR) + { + Ungetch(c); + return c; + } + + return 0; +} + +wxInputStream& wxInputStream::Read(wxOutputStream& stream_out) +{ + size_t lastcount = 0; + char buf[BUF_TEMP_SIZE]; + + for ( ;; ) + { + size_t bytes_read = Read(buf, WXSIZEOF(buf)).LastRead(); + if ( !bytes_read ) + break; + + if ( stream_out.Write(buf, bytes_read).LastWrite() != bytes_read ) + break; + + lastcount += bytes_read; + } + + m_lastcount = lastcount; + + return *this; +} + +wxFileOffset wxInputStream::SeekI(wxFileOffset pos, wxSeekMode mode) +{ + // RR: This code is duplicated in wxBufferedInputStream. This is + // not really a good design, but buffered stream are different + // from all other in that they handle two stream-related objects, + // the stream buffer and parent stream. + + // I don't know whether it should be put as well in wxFileInputStream::OnSysSeek + if (m_lasterror==wxSTREAM_EOF) + m_lasterror=wxSTREAM_NO_ERROR; + + /* RR: A call to SeekI() will automatically invalidate any previous + call to Ungetch(), otherwise it would be possible to SeekI() to + one position, unread some bytes there, SeekI() to another position + and the data would be corrupted. + + GRG: Could add code here to try to navigate within the wback + buffer if possible, but is it really needed? It would only work + when seeking in wxFromCurrent mode, else it would invalidate + anyway... */ + + if (m_wback) + { + wxLogDebug( wxT("Seeking in stream which has data written back to it.") ); + + free(m_wback); + m_wback = NULL; + m_wbacksize = 0; + m_wbackcur = 0; + } + + return OnSysSeek(pos, mode); +} + +wxFileOffset wxInputStream::TellI() const +{ + wxFileOffset pos = OnSysTell(); + + if (pos != wxInvalidOffset) + pos -= (m_wbacksize - m_wbackcur); + + return pos; +} + + +// ---------------------------------------------------------------------------- +// wxOutputStream +// ---------------------------------------------------------------------------- + +wxOutputStream::wxOutputStream() +{ +} + +wxOutputStream::~wxOutputStream() +{ +} + +size_t wxOutputStream::OnSysWrite(const void * WXUNUSED(buffer), + size_t WXUNUSED(bufsize)) +{ + return 0; +} + +void wxOutputStream::PutC(char c) +{ + Write(&c, sizeof(c)); +} + +wxOutputStream& wxOutputStream::Write(const void *buffer, size_t size) +{ + m_lastcount = OnSysWrite(buffer, size); + return *this; +} + +wxOutputStream& wxOutputStream::Write(wxInputStream& stream_in) +{ + stream_in.Read(*this); + return *this; +} + +wxFileOffset wxOutputStream::TellO() const +{ + return OnSysTell(); +} + +wxFileOffset wxOutputStream::SeekO(wxFileOffset pos, wxSeekMode mode) +{ + return OnSysSeek(pos, mode); +} + +void wxOutputStream::Sync() +{ +} + + +// ---------------------------------------------------------------------------- +// wxCountingOutputStream +// ---------------------------------------------------------------------------- + +wxCountingOutputStream::wxCountingOutputStream () +{ + m_currentPos = 0; +} + +wxFileOffset wxCountingOutputStream::GetLength() const +{ + return m_lastcount; +} + +size_t wxCountingOutputStream::OnSysWrite(const void *WXUNUSED(buffer), + size_t size) +{ + m_currentPos += size; + if (m_currentPos > m_lastcount) + m_lastcount = m_currentPos; + + return m_currentPos; +} + +wxFileOffset wxCountingOutputStream::OnSysSeek(wxFileOffset pos, wxSeekMode mode) +{ + ssize_t new_pos = wx_truncate_cast(ssize_t, pos); + + switch ( mode ) + { + case wxFromStart: + wxCHECK_MSG( (wxFileOffset)new_pos == pos, wxInvalidOffset, wxT("huge position not supported") ); + break; + + case wxFromEnd: + new_pos = m_lastcount + new_pos; + wxCHECK_MSG( (wxFileOffset)new_pos == (wxFileOffset)(m_lastcount + pos), wxInvalidOffset, wxT("huge position not supported") ); + break; + + case wxFromCurrent: + new_pos = m_currentPos + new_pos; + wxCHECK_MSG( (wxFileOffset)new_pos == (wxFileOffset)(m_currentPos + pos), wxInvalidOffset, wxT("huge position not supported") ); + break; + + default: + wxFAIL_MSG( _T("invalid seek mode") ); + return wxInvalidOffset; + } + + m_currentPos = new_pos; + + if (m_currentPos > m_lastcount) + m_lastcount = m_currentPos; + + return m_currentPos; +} + +wxFileOffset wxCountingOutputStream::OnSysTell() const +{ + return m_currentPos; +} + +// ---------------------------------------------------------------------------- +// wxFilterInputStream +// ---------------------------------------------------------------------------- + +wxFilterInputStream::wxFilterInputStream() + : m_parent_i_stream(NULL), + m_owns(false) +{ +} + +wxFilterInputStream::wxFilterInputStream(wxInputStream& stream) + : m_parent_i_stream(&stream), + m_owns(false) +{ +} + +wxFilterInputStream::wxFilterInputStream(wxInputStream *stream) + : m_parent_i_stream(stream), + m_owns(true) +{ +} + +wxFilterInputStream::~wxFilterInputStream() +{ + if (m_owns) + delete m_parent_i_stream; +} + +// ---------------------------------------------------------------------------- +// wxFilterOutputStream +// ---------------------------------------------------------------------------- + +wxFilterOutputStream::wxFilterOutputStream() + : m_parent_o_stream(NULL), + m_owns(false) +{ +} + +wxFilterOutputStream::wxFilterOutputStream(wxOutputStream& stream) + : m_parent_o_stream(&stream), + m_owns(false) +{ +} + +wxFilterOutputStream::wxFilterOutputStream(wxOutputStream *stream) + : m_parent_o_stream(stream), + m_owns(true) +{ +} + +bool wxFilterOutputStream::Close() +{ + if (m_parent_o_stream && m_owns) + return m_parent_o_stream->Close(); + else + return true; +} + +wxFilterOutputStream::~wxFilterOutputStream() +{ + if (m_owns) + delete m_parent_o_stream; +} + +// ---------------------------------------------------------------------------- +// wxFilterClassFactoryBase +// ---------------------------------------------------------------------------- + +IMPLEMENT_ABSTRACT_CLASS(wxFilterClassFactoryBase, wxObject) + +wxString wxFilterClassFactoryBase::PopExtension(const wxString& location) const +{ + return location.substr(0, FindExtension(location)); +} + +wxString::size_type wxFilterClassFactoryBase::FindExtension( + const wxChar *location) const +{ + size_t len = wxStrlen(location); + + for (const wxChar *const *p = GetProtocols(wxSTREAM_FILEEXT); *p; p++) + { + size_t l = wxStrlen(*p); + + if (l <= len && wxStrcmp(*p, location + len - l) == 0) + return len - l; + } + + return wxString::npos; +} + +bool wxFilterClassFactoryBase::CanHandle(const wxChar *protocol, + wxStreamProtocolType type) const +{ + if (type == wxSTREAM_FILEEXT) + return FindExtension(protocol) != wxString::npos; + else + for (const wxChar *const *p = GetProtocols(type); *p; p++) + if (wxStrcmp(*p, protocol) == 0) + return true; + + return false; +} + +// ---------------------------------------------------------------------------- +// wxFilterClassFactory +// ---------------------------------------------------------------------------- + +IMPLEMENT_ABSTRACT_CLASS(wxFilterClassFactory, wxFilterClassFactoryBase) + +wxFilterClassFactory *wxFilterClassFactory::sm_first = NULL; + +void wxFilterClassFactory::Remove() +{ + if (m_next != this) + { + wxFilterClassFactory **pp = &sm_first; + + while (*pp != this) + pp = &(*pp)->m_next; + + *pp = m_next; + + m_next = this; + } +} + +// ---------------------------------------------------------------------------- +// wxBufferedInputStream +// ---------------------------------------------------------------------------- + +wxBufferedInputStream::wxBufferedInputStream(wxInputStream& s, + wxStreamBuffer *buffer) + : wxFilterInputStream(s) +{ + if ( buffer ) + { + // use the buffer provided by the user + m_i_streambuf = buffer; + } + else // create a default buffer + { + m_i_streambuf = new wxStreamBuffer(*this, wxStreamBuffer::read); + + m_i_streambuf->SetBufferIO(1024); + } +} + +wxBufferedInputStream::~wxBufferedInputStream() +{ + m_parent_i_stream->SeekI(-(wxFileOffset)m_i_streambuf->GetBytesLeft(), + wxFromCurrent); + + delete m_i_streambuf; +} + +char wxBufferedInputStream::Peek() +{ + return m_i_streambuf->Peek(); +} + +wxInputStream& wxBufferedInputStream::Read(void *buf, size_t size) +{ + // reset the error flag + Reset(); + + // first read from the already cached data + m_lastcount = GetWBack(buf, size); + + // do we have to read anything more? + if ( m_lastcount < size ) + { + size -= m_lastcount; + buf = (char *)buf + m_lastcount; + + // the call to wxStreamBuffer::Read() below may reset our m_lastcount + // (but it also may not do it if the buffer is associated to another + // existing stream and wasn't created by us), so save it + size_t countOld = m_lastcount; + + // the new count of the bytes read is the count of bytes read this time + m_lastcount = m_i_streambuf->Read(buf, size); + + // plus those we had read before + m_lastcount += countOld; + } + + return *this; +} + +wxFileOffset wxBufferedInputStream::SeekI(wxFileOffset pos, wxSeekMode mode) +{ + // RR: Look at wxInputStream for comments. + + if (m_lasterror==wxSTREAM_EOF) + Reset(); + + if (m_wback) + { + wxLogDebug( wxT("Seeking in stream which has data written back to it.") ); + + free(m_wback); + m_wback = NULL; + m_wbacksize = 0; + m_wbackcur = 0; + } + + return m_i_streambuf->Seek(pos, mode); +} + +wxFileOffset wxBufferedInputStream::TellI() const +{ + wxFileOffset pos = m_i_streambuf->Tell(); + + if (pos != wxInvalidOffset) + pos -= (m_wbacksize - m_wbackcur); + + return pos; +} + +size_t wxBufferedInputStream::OnSysRead(void *buffer, size_t bufsize) +{ + return m_parent_i_stream->Read(buffer, bufsize).LastRead(); +} + +wxFileOffset wxBufferedInputStream::OnSysSeek(wxFileOffset seek, wxSeekMode mode) +{ + return m_parent_i_stream->SeekI(seek, mode); +} + +wxFileOffset wxBufferedInputStream::OnSysTell() const +{ + return m_parent_i_stream->TellI(); +} + +void wxBufferedInputStream::SetInputStreamBuffer(wxStreamBuffer *buffer) +{ + wxCHECK_RET( buffer, _T("wxBufferedInputStream needs buffer") ); + + delete m_i_streambuf; + m_i_streambuf = buffer; +} + +// ---------------------------------------------------------------------------- +// wxBufferedOutputStream +// ---------------------------------------------------------------------------- + +wxBufferedOutputStream::wxBufferedOutputStream(wxOutputStream& s, + wxStreamBuffer *buffer) + : wxFilterOutputStream(s) +{ + if ( buffer ) + { + m_o_streambuf = buffer; + } + else // create a default one + { + m_o_streambuf = new wxStreamBuffer(*this, wxStreamBuffer::write); + + m_o_streambuf->SetBufferIO(1024); + } +} + +wxBufferedOutputStream::~wxBufferedOutputStream() +{ + Sync(); + delete m_o_streambuf; +} + +bool wxBufferedOutputStream::Close() +{ + Sync(); + return IsOk(); +} + + +wxOutputStream& wxBufferedOutputStream::Write(const void *buffer, size_t size) +{ + m_lastcount = 0; + m_o_streambuf->Write(buffer, size); + return *this; +} + +wxFileOffset wxBufferedOutputStream::SeekO(wxFileOffset pos, wxSeekMode mode) +{ + Sync(); + return m_o_streambuf->Seek(pos, mode); +} + +wxFileOffset wxBufferedOutputStream::TellO() const +{ + return m_o_streambuf->Tell(); +} + +void wxBufferedOutputStream::Sync() +{ + m_o_streambuf->FlushBuffer(); + m_parent_o_stream->Sync(); +} + +size_t wxBufferedOutputStream::OnSysWrite(const void *buffer, size_t bufsize) +{ + return m_parent_o_stream->Write(buffer, bufsize).LastWrite(); +} + +wxFileOffset wxBufferedOutputStream::OnSysSeek(wxFileOffset seek, wxSeekMode mode) +{ + return m_parent_o_stream->SeekO(seek, mode); +} + +wxFileOffset wxBufferedOutputStream::OnSysTell() const +{ + return m_parent_o_stream->TellO(); +} + +wxFileOffset wxBufferedOutputStream::GetLength() const +{ + return m_parent_o_stream->GetLength() + m_o_streambuf->GetIntPosition(); +} + +void wxBufferedOutputStream::SetOutputStreamBuffer(wxStreamBuffer *buffer) +{ + wxCHECK_RET( buffer, _T("wxBufferedOutputStream needs buffer") ); + + delete m_o_streambuf; + m_o_streambuf = buffer; +} + +// ---------------------------------------------------------------------------- +// Some IOManip function +// ---------------------------------------------------------------------------- + +wxOutputStream& wxEndL(wxOutputStream& stream) +{ + static const wxChar *eol = wxTextFile::GetEOL(); + + return stream.Write(eol, wxStrlen(eol)); +} + +#endif // wxUSE_STREAMS diff --git a/Externals/wxWidgets/src/common/string.cpp b/Externals/wxWidgets/src/common/string.cpp index 29cbeea6d9..d1034c7fe8 100644 --- a/Externals/wxWidgets/src/common/string.cpp +++ b/Externals/wxWidgets/src/common/string.cpp @@ -1,2632 +1,2632 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/string.cpp -// Purpose: wxString class -// Author: Vadim Zeitlin, Ryan Norton -// Modified by: -// Created: 29/01/98 -// RCS-ID: $Id: string.cpp 53702 2008-05-22 17:22:00Z SN $ -// Copyright: (c) 1998 Vadim Zeitlin -// (c) 2004 Ryan Norton -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -/* - * About ref counting: - * 1) all empty strings use g_strEmpty, nRefs = -1 (set in Init()) - * 2) AllocBuffer() sets nRefs to 1, Lock() increments it by one - * 3) Unlock() decrements nRefs and frees memory if it goes to 0 - */ - -// =========================================================================== -// headers, declarations, constants -// =========================================================================== - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#ifndef WX_PRECOMP - #include "wx/string.h" - #include "wx/intl.h" - #include "wx/thread.h" -#endif - -#include - -#ifndef __WXWINCE__ - #include -#endif - -#include -#include - -#ifdef __SALFORDC__ - #include -#endif - -// allocating extra space for each string consumes more memory but speeds up -// the concatenation operations (nLen is the current string's length) -// NB: EXTRA_ALLOC must be >= 0! -#define EXTRA_ALLOC (19 - nLen % 16) - -// --------------------------------------------------------------------------- -// static class variables definition -// --------------------------------------------------------------------------- - -#if !wxUSE_STL - //According to STL _must_ be a -1 size_t - const size_t wxStringBase::npos = (size_t) -1; -#endif - -// ---------------------------------------------------------------------------- -// static data -// ---------------------------------------------------------------------------- - -#if wxUSE_STL - -extern const wxChar WXDLLIMPEXP_BASE *wxEmptyString = _T(""); - -#else - -// for an empty string, GetStringData() will return this address: this -// structure has the same layout as wxStringData and it's data() method will -// return the empty string (dummy pointer) -static const struct -{ - wxStringData data; - wxChar dummy; -} g_strEmpty = { {-1, 0, 0}, wxT('\0') }; - -// empty C style string: points to 'string data' byte of g_strEmpty -extern const wxChar WXDLLIMPEXP_BASE *wxEmptyString = &g_strEmpty.dummy; - -#endif - -// ---------------------------------------------------------------------------- -// global functions -// ---------------------------------------------------------------------------- - -#if wxUSE_STD_IOSTREAM - -#include - -wxSTD ostream& operator<<(wxSTD ostream& os, const wxString& str) -{ -#ifdef __BORLANDC__ - os << str.mb_str(); -#else - os << str.c_str(); -#endif - return os; -} - -#endif // wxUSE_STD_IOSTREAM - -// ---------------------------------------------------------------------------- -// private classes -// ---------------------------------------------------------------------------- - -// this small class is used to gather statistics for performance tuning -//#define WXSTRING_STATISTICS -#ifdef WXSTRING_STATISTICS - class Averager - { - public: - Averager(const wxChar *sz) { m_sz = sz; m_nTotal = m_nCount = 0; } - ~Averager() - { wxPrintf("wxString: average %s = %f\n", m_sz, ((float)m_nTotal)/m_nCount); } - - void Add(size_t n) { m_nTotal += n; m_nCount++; } - - private: - size_t m_nCount, m_nTotal; - const wxChar *m_sz; - } g_averageLength("allocation size"), - g_averageSummandLength("summand length"), - g_averageConcatHit("hit probability in concat"), - g_averageInitialLength("initial string length"); - - #define STATISTICS_ADD(av, val) g_average##av.Add(val) -#else - #define STATISTICS_ADD(av, val) -#endif // WXSTRING_STATISTICS - -#if !wxUSE_STL - -// =========================================================================== -// wxStringData class deallocation -// =========================================================================== - -#if defined(__VISUALC__) && defined(_MT) && !defined(_DLL) -# pragma message (__FILE__ ": building with Multithreaded non DLL runtime has a performance impact on wxString!") -void wxStringData::Free() -{ - free(this); -} -#endif - -// =========================================================================== -// wxStringBase -// =========================================================================== - -// takes nLength elements of psz starting at nPos -void wxStringBase::InitWith(const wxChar *psz, size_t nPos, size_t nLength) -{ - Init(); - - // if the length is not given, assume the string to be NUL terminated - if ( nLength == npos ) { - wxASSERT_MSG( nPos <= wxStrlen(psz), _T("index out of bounds") ); - - nLength = wxStrlen(psz + nPos); - } - - STATISTICS_ADD(InitialLength, nLength); - - if ( nLength > 0 ) { - // trailing '\0' is written in AllocBuffer() - if ( !AllocBuffer(nLength) ) { - wxFAIL_MSG( _T("out of memory in wxStringBase::InitWith") ); - return; - } - wxTmemcpy(m_pchData, psz + nPos, nLength); - } -} - -// poor man's iterators are "void *" pointers -wxStringBase::wxStringBase(const void *pStart, const void *pEnd) -{ - if ( pEnd >= pStart ) - { - InitWith((const wxChar *)pStart, 0, - (const wxChar *)pEnd - (const wxChar *)pStart); - } - else - { - wxFAIL_MSG( _T("pStart is not before pEnd") ); - Init(); - } -} - -wxStringBase::wxStringBase(size_type n, wxChar ch) -{ - Init(); - append(n, ch); -} - -// --------------------------------------------------------------------------- -// memory allocation -// --------------------------------------------------------------------------- - -// allocates memory needed to store a C string of length nLen -bool wxStringBase::AllocBuffer(size_t nLen) -{ - // allocating 0 sized buffer doesn't make sense, all empty strings should - // reuse g_strEmpty - wxASSERT( nLen > 0 ); - - // make sure that we don't overflow - wxCHECK( nLen < (INT_MAX / sizeof(wxChar)) - - (sizeof(wxStringData) + EXTRA_ALLOC + 1), false ); - - STATISTICS_ADD(Length, nLen); - - // allocate memory: - // 1) one extra character for '\0' termination - // 2) sizeof(wxStringData) for housekeeping info - wxStringData* pData = (wxStringData*) - malloc(sizeof(wxStringData) + (nLen + EXTRA_ALLOC + 1)*sizeof(wxChar)); - - if ( pData == NULL ) { - // allocation failures are handled by the caller - return false; - } - - pData->nRefs = 1; - pData->nDataLength = nLen; - pData->nAllocLength = nLen + EXTRA_ALLOC; - m_pchData = pData->data(); // data starts after wxStringData - m_pchData[nLen] = wxT('\0'); - return true; -} - -// must be called before changing this string -bool wxStringBase::CopyBeforeWrite() -{ - wxStringData* pData = GetStringData(); - - if ( pData->IsShared() ) { - pData->Unlock(); // memory not freed because shared - size_t nLen = pData->nDataLength; - if ( !AllocBuffer(nLen) ) { - // allocation failures are handled by the caller - return false; - } - wxTmemcpy(m_pchData, pData->data(), nLen); - } - - wxASSERT( !GetStringData()->IsShared() ); // we must be the only owner - - return true; -} - -// must be called before replacing contents of this string -bool wxStringBase::AllocBeforeWrite(size_t nLen) -{ - wxASSERT( nLen != 0 ); // doesn't make any sense - - // must not share string and must have enough space - wxStringData* pData = GetStringData(); - if ( pData->IsShared() || pData->IsEmpty() ) { - // can't work with old buffer, get new one - pData->Unlock(); - if ( !AllocBuffer(nLen) ) { - // allocation failures are handled by the caller - return false; - } - } - else { - if ( nLen > pData->nAllocLength ) { - // realloc the buffer instead of calling malloc() again, this is more - // efficient - STATISTICS_ADD(Length, nLen); - - nLen += EXTRA_ALLOC; - - pData = (wxStringData*) - realloc(pData, sizeof(wxStringData) + (nLen + 1)*sizeof(wxChar)); - - if ( pData == NULL ) { - // allocation failures are handled by the caller - // keep previous data since reallocation failed - return false; - } - - pData->nAllocLength = nLen; - m_pchData = pData->data(); - } - } - - wxASSERT( !GetStringData()->IsShared() ); // we must be the only owner - - // it doesn't really matter what the string length is as it's going to be - // overwritten later but, for extra safety, set it to 0 for now as we may - // have some junk in m_pchData - GetStringData()->nDataLength = 0; - - return true; -} - -wxStringBase& wxStringBase::append(size_t n, wxChar ch) -{ - size_type len = length(); - - if ( !Alloc(len + n) || !CopyBeforeWrite() ) { - wxFAIL_MSG( _T("out of memory in wxStringBase::append") ); - } - GetStringData()->nDataLength = len + n; - m_pchData[len + n] = '\0'; - for ( size_t i = 0; i < n; ++i ) - m_pchData[len + i] = ch; - return *this; -} - -void wxStringBase::resize(size_t nSize, wxChar ch) -{ - size_t len = length(); - - if ( nSize < len ) - { - erase(begin() + nSize, end()); - } - else if ( nSize > len ) - { - append(nSize - len, ch); - } - //else: we have exactly the specified length, nothing to do -} - -// allocate enough memory for nLen characters -bool wxStringBase::Alloc(size_t nLen) -{ - wxStringData *pData = GetStringData(); - if ( pData->nAllocLength <= nLen ) { - if ( pData->IsEmpty() ) { - nLen += EXTRA_ALLOC; - - pData = (wxStringData *) - malloc(sizeof(wxStringData) + (nLen + 1)*sizeof(wxChar)); - - if ( pData == NULL ) { - // allocation failure handled by caller - return false; - } - - pData->nRefs = 1; - pData->nDataLength = 0; - pData->nAllocLength = nLen; - m_pchData = pData->data(); // data starts after wxStringData - m_pchData[0u] = wxT('\0'); - } - else if ( pData->IsShared() ) { - pData->Unlock(); // memory not freed because shared - size_t nOldLen = pData->nDataLength; - if ( !AllocBuffer(nLen) ) { - // allocation failure handled by caller - return false; - } - // +1 to copy the terminator, too - memcpy(m_pchData, pData->data(), (nOldLen+1)*sizeof(wxChar)); - GetStringData()->nDataLength = nOldLen; - } - else { - nLen += EXTRA_ALLOC; - - pData = (wxStringData *) - realloc(pData, sizeof(wxStringData) + (nLen + 1)*sizeof(wxChar)); - - if ( pData == NULL ) { - // allocation failure handled by caller - // keep previous data since reallocation failed - return false; - } - - // it's not important if the pointer changed or not (the check for this - // is not faster than assigning to m_pchData in all cases) - pData->nAllocLength = nLen; - m_pchData = pData->data(); - } - } - //else: we've already got enough - return true; -} - -wxStringBase::iterator wxStringBase::begin() -{ - if (length() > 0) - CopyBeforeWrite(); - return m_pchData; -} - -wxStringBase::iterator wxStringBase::end() -{ - if (length() > 0) - CopyBeforeWrite(); - return m_pchData + length(); -} - -wxStringBase::iterator wxStringBase::erase(iterator it) -{ - size_type idx = it - begin(); - erase(idx, 1); - return begin() + idx; -} - -wxStringBase& wxStringBase::erase(size_t nStart, size_t nLen) -{ - wxASSERT(nStart <= length()); - size_t strLen = length() - nStart; - // delete nLen or up to the end of the string characters - nLen = strLen < nLen ? strLen : nLen; - wxString strTmp(c_str(), nStart); - strTmp.append(c_str() + nStart + nLen, length() - nStart - nLen); - - swap(strTmp); - return *this; -} - -wxStringBase& wxStringBase::insert(size_t nPos, const wxChar *sz, size_t n) -{ - wxASSERT( nPos <= length() ); - - if ( n == npos ) n = wxStrlen(sz); - if ( n == 0 ) return *this; - - if ( !Alloc(length() + n) || !CopyBeforeWrite() ) { - wxFAIL_MSG( _T("out of memory in wxStringBase::insert") ); - } - - memmove(m_pchData + nPos + n, m_pchData + nPos, - (length() - nPos) * sizeof(wxChar)); - memcpy(m_pchData + nPos, sz, n * sizeof(wxChar)); - GetStringData()->nDataLength = length() + n; - m_pchData[length()] = '\0'; - - return *this; -} - -void wxStringBase::swap(wxStringBase& str) -{ - wxChar* tmp = str.m_pchData; - str.m_pchData = m_pchData; - m_pchData = tmp; -} - -size_t wxStringBase::find(const wxStringBase& str, size_t nStart) const -{ - // deal with the special case of empty string first - const size_t nLen = length(); - const size_t nLenOther = str.length(); - - if ( !nLenOther ) - { - // empty string is a substring of anything - return 0; - } - - if ( !nLen ) - { - // the other string is non empty so can't be our substring - return npos; - } - - wxASSERT( str.GetStringData()->IsValid() ); - wxASSERT( nStart <= nLen ); - - const wxChar * const other = str.c_str(); - - // anchor - const wxChar* p = (const wxChar*)wxTmemchr(c_str() + nStart, - *other, - nLen - nStart); - - if ( !p ) - return npos; - - while ( p - c_str() + nLenOther <= nLen && wxTmemcmp(p, other, nLenOther) ) - { - p++; - - // anchor again - p = (const wxChar*)wxTmemchr(p, *other, nLen - (p - c_str())); - - if ( !p ) - return npos; - } - - return p - c_str() + nLenOther <= nLen ? p - c_str() : npos; -} - -size_t wxStringBase::find(const wxChar* sz, size_t nStart, size_t n) const -{ - return find(wxStringBase(sz, n), nStart); -} - -size_t wxStringBase::find(wxChar ch, size_t nStart) const -{ - wxASSERT( nStart <= length() ); - - const wxChar *p = (const wxChar*)wxTmemchr(c_str() + nStart, ch, length() - nStart); - - return p == NULL ? npos : p - c_str(); -} - -size_t wxStringBase::rfind(const wxStringBase& str, size_t nStart) const -{ - wxASSERT( str.GetStringData()->IsValid() ); - wxASSERT( nStart == npos || nStart <= length() ); - - if ( length() >= str.length() ) - { - // avoids a corner case later - if ( length() == 0 && str.length() == 0 ) - return 0; - - // "top" is the point where search starts from - size_t top = length() - str.length(); - - if ( nStart == npos ) - nStart = length() - 1; - if ( nStart < top ) - top = nStart; - - const wxChar *cursor = c_str() + top; - do - { - if ( wxTmemcmp(cursor, str.c_str(), - str.length()) == 0 ) - { - return cursor - c_str(); - } - } while ( cursor-- > c_str() ); - } - - return npos; -} - -size_t wxStringBase::rfind(const wxChar* sz, size_t nStart, size_t n) const -{ - return rfind(wxStringBase(sz, n), nStart); -} - -size_t wxStringBase::rfind(wxChar ch, size_t nStart) const -{ - if ( nStart == npos ) - { - nStart = length(); - } - else - { - wxASSERT( nStart <= length() ); - } - - const wxChar *actual; - for ( actual = c_str() + ( nStart == npos ? length() : nStart + 1 ); - actual > c_str(); --actual ) - { - if ( *(actual - 1) == ch ) - return (actual - 1) - c_str(); - } - - return npos; -} - -size_t wxStringBase::find_first_of(const wxChar* sz, size_t nStart) const -{ - wxASSERT(nStart <= length()); - - size_t len = wxStrlen(sz); - - size_t i; - for(i = nStart; i < this->length(); ++i) - { - if (wxTmemchr(sz, *(c_str() + i), len)) - break; - } - - if(i == this->length()) - return npos; - else - return i; -} - -size_t wxStringBase::find_first_of(const wxChar* sz, size_t nStart, - size_t n) const -{ - return find_first_of(wxStringBase(sz, n), nStart); -} - -size_t wxStringBase::find_last_of(const wxChar* sz, size_t nStart) const -{ - if ( nStart == npos ) - { - nStart = length() - 1; - } - else - { - wxASSERT_MSG( nStart <= length(), - _T("invalid index in find_last_of()") ); - } - - size_t len = wxStrlen(sz); - - for ( const wxChar *p = c_str() + nStart; p >= c_str(); --p ) - { - if ( wxTmemchr(sz, *p, len) ) - return p - c_str(); - } - - return npos; -} - -size_t wxStringBase::find_last_of(const wxChar* sz, size_t nStart, - size_t n) const -{ - return find_last_of(wxStringBase(sz, n), nStart); -} - -size_t wxStringBase::find_first_not_of(const wxChar* sz, size_t nStart) const -{ - if ( nStart == npos ) - { - nStart = length(); - } - else - { - wxASSERT( nStart <= length() ); - } - - size_t len = wxStrlen(sz); - - size_t i; - for(i = nStart; i < this->length(); ++i) - { - if (!wxTmemchr(sz, *(c_str() + i), len)) - break; - } - - if(i == this->length()) - return npos; - else - return i; -} - -size_t wxStringBase::find_first_not_of(const wxChar* sz, size_t nStart, - size_t n) const -{ - return find_first_not_of(wxStringBase(sz, n), nStart); -} - -size_t wxStringBase::find_first_not_of(wxChar ch, size_t nStart) const -{ - wxASSERT( nStart <= length() ); - - for ( const wxChar *p = c_str() + nStart; *p; p++ ) - { - if ( *p != ch ) - return p - c_str(); - } - - return npos; -} - -size_t wxStringBase::find_last_not_of(const wxChar* sz, size_t nStart) const -{ - if ( nStart == npos ) - { - nStart = length() - 1; - } - else - { - wxASSERT( nStart <= length() ); - } - - size_t len = wxStrlen(sz); - - for ( const wxChar *p = c_str() + nStart; p >= c_str(); --p ) - { - if ( !wxTmemchr(sz, *p,len) ) - return p - c_str(); - } - - return npos; -} - -size_t wxStringBase::find_last_not_of(const wxChar* sz, size_t nStart, - size_t n) const -{ - return find_last_not_of(wxStringBase(sz, n), nStart); -} - -size_t wxStringBase::find_last_not_of(wxChar ch, size_t nStart) const -{ - if ( nStart == npos ) - { - nStart = length() - 1; - } - else - { - wxASSERT( nStart <= length() ); - } - - for ( const wxChar *p = c_str() + nStart; p >= c_str(); --p ) - { - if ( *p != ch ) - return p - c_str(); - } - - return npos; -} - -wxStringBase& wxStringBase::replace(size_t nStart, size_t nLen, - const wxChar *sz) -{ - wxASSERT_MSG( nStart <= length(), - _T("index out of bounds in wxStringBase::replace") ); - size_t strLen = length() - nStart; - nLen = strLen < nLen ? strLen : nLen; - - wxStringBase strTmp; - strTmp.reserve(length()); // micro optimisation to avoid multiple mem allocs - - //This is kind of inefficient, but its pretty good considering... - //we don't want to use character access operators here because on STL - //it will freeze the reference count of strTmp, which means a deep copy - //at the end when swap is called - // - //Also, we can't use append with the full character pointer and must - //do it manually because this string can contain null characters - for(size_t i1 = 0; i1 < nStart; ++i1) - strTmp.append(1, this->c_str()[i1]); - - //its safe to do the full version here because - //sz must be a normal c string - strTmp.append(sz); - - for(size_t i2 = nStart + nLen; i2 < length(); ++i2) - strTmp.append(1, this->c_str()[i2]); - - swap(strTmp); - return *this; -} - -wxStringBase& wxStringBase::replace(size_t nStart, size_t nLen, - size_t nCount, wxChar ch) -{ - return replace(nStart, nLen, wxStringBase(nCount, ch).c_str()); -} - -wxStringBase& wxStringBase::replace(size_t nStart, size_t nLen, - const wxStringBase& str, - size_t nStart2, size_t nLen2) -{ - return replace(nStart, nLen, str.substr(nStart2, nLen2)); -} - -wxStringBase& wxStringBase::replace(size_t nStart, size_t nLen, - const wxChar* sz, size_t nCount) -{ - return replace(nStart, nLen, wxStringBase(sz, nCount).c_str()); -} - -wxStringBase wxStringBase::substr(size_t nStart, size_t nLen) const -{ - if ( nLen == npos ) - nLen = length() - nStart; - return wxStringBase(*this, nStart, nLen); -} - -// assigns one string to another -wxStringBase& wxStringBase::operator=(const wxStringBase& stringSrc) -{ - wxASSERT( stringSrc.GetStringData()->IsValid() ); - - // don't copy string over itself - if ( m_pchData != stringSrc.m_pchData ) { - if ( stringSrc.GetStringData()->IsEmpty() ) { - Reinit(); - } - else { - // adjust references - GetStringData()->Unlock(); - m_pchData = stringSrc.m_pchData; - GetStringData()->Lock(); - } - } - - return *this; -} - -// assigns a single character -wxStringBase& wxStringBase::operator=(wxChar ch) -{ - if ( !AssignCopy(1, &ch) ) { - wxFAIL_MSG( _T("out of memory in wxStringBase::operator=(wxChar)") ); - } - return *this; -} - -// assigns C string -wxStringBase& wxStringBase::operator=(const wxChar *psz) -{ - if ( !AssignCopy(wxStrlen(psz), psz) ) { - wxFAIL_MSG( _T("out of memory in wxStringBase::operator=(const wxChar *)") ); - } - return *this; -} - -// helper function: does real copy -bool wxStringBase::AssignCopy(size_t nSrcLen, const wxChar *pszSrcData) -{ - if ( nSrcLen == 0 ) { - Reinit(); - } - else { - if ( !AllocBeforeWrite(nSrcLen) ) { - // allocation failure handled by caller - return false; - } - memcpy(m_pchData, pszSrcData, nSrcLen*sizeof(wxChar)); - GetStringData()->nDataLength = nSrcLen; - m_pchData[nSrcLen] = wxT('\0'); - } - return true; -} - -// --------------------------------------------------------------------------- -// string concatenation -// --------------------------------------------------------------------------- - -// add something to this string -bool wxStringBase::ConcatSelf(size_t nSrcLen, const wxChar *pszSrcData, - size_t nMaxLen) -{ - STATISTICS_ADD(SummandLength, nSrcLen); - - nSrcLen = nSrcLen < nMaxLen ? nSrcLen : nMaxLen; - - // concatenating an empty string is a NOP - if ( nSrcLen > 0 ) { - wxStringData *pData = GetStringData(); - size_t nLen = pData->nDataLength; - size_t nNewLen = nLen + nSrcLen; - - // take special care when appending part of this string to itself: the code - // below reallocates our buffer and this invalidates pszSrcData pointer so - // we have to copy it in another temporary string in this case (but avoid - // doing this unnecessarily) - if ( pszSrcData >= m_pchData && pszSrcData < m_pchData + nLen ) - { - wxStringBase tmp(pszSrcData, nSrcLen); - return ConcatSelf(nSrcLen, tmp.m_pchData, nSrcLen); - } - - // alloc new buffer if current is too small - if ( pData->IsShared() ) { - STATISTICS_ADD(ConcatHit, 0); - - // we have to allocate another buffer - wxStringData* pOldData = GetStringData(); - if ( !AllocBuffer(nNewLen) ) { - // allocation failure handled by caller - return false; - } - memcpy(m_pchData, pOldData->data(), nLen*sizeof(wxChar)); - pOldData->Unlock(); - } - else if ( nNewLen > pData->nAllocLength ) { - STATISTICS_ADD(ConcatHit, 0); - - reserve(nNewLen); - // we have to grow the buffer - if ( capacity() < nNewLen ) { - // allocation failure handled by caller - return false; - } - } - else { - STATISTICS_ADD(ConcatHit, 1); - - // the buffer is already big enough - } - - // should be enough space - wxASSERT( nNewLen <= GetStringData()->nAllocLength ); - - // fast concatenation - all is done in our buffer - memcpy(m_pchData + nLen, pszSrcData, nSrcLen*sizeof(wxChar)); - - m_pchData[nNewLen] = wxT('\0'); // put terminating '\0' - GetStringData()->nDataLength = nNewLen; // and fix the length - } - //else: the string to append was empty - return true; -} - -// --------------------------------------------------------------------------- -// simple sub-string extraction -// --------------------------------------------------------------------------- - -// helper function: clone the data attached to this string -bool wxStringBase::AllocCopy(wxString& dest, int nCopyLen, int nCopyIndex) const -{ - if ( nCopyLen == 0 ) { - dest.Init(); - } - else { - if ( !dest.AllocBuffer(nCopyLen) ) { - // allocation failure handled by caller - return false; - } - memcpy(dest.m_pchData, m_pchData + nCopyIndex, nCopyLen*sizeof(wxChar)); - } - return true; -} - -#endif // !wxUSE_STL - -#if !wxUSE_STL || !defined(HAVE_STD_STRING_COMPARE) - -#if !wxUSE_STL - #define STRINGCLASS wxStringBase -#else - #define STRINGCLASS wxString -#endif - -static inline int wxDoCmp(const wxChar* s1, size_t l1, - const wxChar* s2, size_t l2) -{ - if( l1 == l2 ) - return wxTmemcmp(s1, s2, l1); - else if( l1 < l2 ) - { - int ret = wxTmemcmp(s1, s2, l1); - return ret == 0 ? -1 : ret; - } - else - { - int ret = wxTmemcmp(s1, s2, l2); - return ret == 0 ? +1 : ret; - } -} - -int STRINGCLASS::compare(const wxStringBase& str) const -{ - return ::wxDoCmp(data(), length(), str.data(), str.length()); -} - -int STRINGCLASS::compare(size_t nStart, size_t nLen, - const wxStringBase& str) const -{ - wxASSERT(nStart <= length()); - size_type strLen = length() - nStart; - nLen = strLen < nLen ? strLen : nLen; - return ::wxDoCmp(data() + nStart, nLen, str.data(), str.length()); -} - -int STRINGCLASS::compare(size_t nStart, size_t nLen, - const wxStringBase& str, - size_t nStart2, size_t nLen2) const -{ - wxASSERT(nStart <= length()); - wxASSERT(nStart2 <= str.length()); - size_type strLen = length() - nStart, - strLen2 = str.length() - nStart2; - nLen = strLen < nLen ? strLen : nLen; - nLen2 = strLen2 < nLen2 ? strLen2 : nLen2; - return ::wxDoCmp(data() + nStart, nLen, str.data() + nStart2, nLen2); -} - -int STRINGCLASS::compare(const wxChar* sz) const -{ - size_t nLen = wxStrlen(sz); - return ::wxDoCmp(data(), length(), sz, nLen); -} - -int STRINGCLASS::compare(size_t nStart, size_t nLen, - const wxChar* sz, size_t nCount) const -{ - wxASSERT(nStart <= length()); - size_type strLen = length() - nStart; - nLen = strLen < nLen ? strLen : nLen; - if( nCount == npos ) - nCount = wxStrlen(sz); - - return ::wxDoCmp(data() + nStart, nLen, sz, nCount); -} - -#undef STRINGCLASS - -#endif // !wxUSE_STL || !defined(HAVE_STD_STRING_COMPARE) - -// =========================================================================== -// wxString class core -// =========================================================================== - -// --------------------------------------------------------------------------- -// construction and conversion -// --------------------------------------------------------------------------- - -#if wxUSE_UNICODE - -// from multibyte string -wxString::wxString(const char *psz, const wxMBConv& conv, size_t nLength) -{ - // anything to do? - if ( psz && nLength != 0 ) - { - if ( nLength == npos ) - { - nLength = wxNO_LEN; - } - - size_t nLenWide; - wxWCharBuffer wbuf = conv.cMB2WC(psz, nLength, &nLenWide); - - if ( nLenWide ) - assign(wbuf, nLenWide); - } -} - -//Convert wxString in Unicode mode to a multi-byte string -const wxCharBuffer wxString::mb_str(const wxMBConv& conv) const -{ - return conv.cWC2MB(c_str(), length() + 1 /* size, not length */, NULL); -} - -#else // ANSI - -#if wxUSE_WCHAR_T - -// from wide string -wxString::wxString(const wchar_t *pwz, const wxMBConv& conv, size_t nLength) -{ - // anything to do? - if ( pwz && nLength != 0 ) - { - if ( nLength == npos ) - { - nLength = wxNO_LEN; - } - - size_t nLenMB; - wxCharBuffer buf = conv.cWC2MB(pwz, nLength, &nLenMB); - - if ( nLenMB ) - assign(buf, nLenMB); - } -} - -//Converts this string to a wide character string if unicode -//mode is not enabled and wxUSE_WCHAR_T is enabled -const wxWCharBuffer wxString::wc_str(const wxMBConv& conv) const -{ - return conv.cMB2WC(c_str(), length() + 1 /* size, not length */, NULL); -} - -#endif // wxUSE_WCHAR_T - -#endif // Unicode/ANSI - -// shrink to minimal size (releasing extra memory) -bool wxString::Shrink() -{ - wxString tmp(begin(), end()); - swap(tmp); - return tmp.length() == length(); -} - -#if !wxUSE_STL -// get the pointer to writable buffer of (at least) nLen bytes -wxChar *wxString::GetWriteBuf(size_t nLen) -{ - if ( !AllocBeforeWrite(nLen) ) { - // allocation failure handled by caller - return NULL; - } - - wxASSERT( GetStringData()->nRefs == 1 ); - GetStringData()->Validate(false); - - return m_pchData; -} - -// put string back in a reasonable state after GetWriteBuf -void wxString::UngetWriteBuf() -{ - UngetWriteBuf(wxStrlen(m_pchData)); -} - -void wxString::UngetWriteBuf(size_t nLen) -{ - wxStringData * const pData = GetStringData(); - - wxASSERT_MSG( nLen < pData->nAllocLength, _T("buffer overrun") ); - - // the strings we store are always NUL-terminated - pData->data()[nLen] = _T('\0'); - pData->nDataLength = nLen; - pData->Validate(true); -} -#endif // !wxUSE_STL - -// --------------------------------------------------------------------------- -// data access -// --------------------------------------------------------------------------- - -// all functions are inline in string.h - -// --------------------------------------------------------------------------- -// assignment operators -// --------------------------------------------------------------------------- - -#if !wxUSE_UNICODE - -// same as 'signed char' variant -wxString& wxString::operator=(const unsigned char* psz) -{ - *this = (const char *)psz; - return *this; -} - -#if wxUSE_WCHAR_T -wxString& wxString::operator=(const wchar_t *pwz) -{ - wxString str(pwz); - swap(str); - return *this; -} -#endif - -#endif - -/* - * concatenation functions come in 5 flavours: - * string + string - * char + string and string + char - * C str + string and string + C str - */ - -wxString operator+(const wxString& str1, const wxString& str2) -{ -#if !wxUSE_STL - wxASSERT( str1.GetStringData()->IsValid() ); - wxASSERT( str2.GetStringData()->IsValid() ); -#endif - - wxString s = str1; - s += str2; - - return s; -} - -wxString operator+(const wxString& str, wxChar ch) -{ -#if !wxUSE_STL - wxASSERT( str.GetStringData()->IsValid() ); -#endif - - wxString s = str; - s += ch; - - return s; -} - -wxString operator+(wxChar ch, const wxString& str) -{ -#if !wxUSE_STL - wxASSERT( str.GetStringData()->IsValid() ); -#endif - - wxString s = ch; - s += str; - - return s; -} - -wxString operator+(const wxString& str, const wxChar *psz) -{ -#if !wxUSE_STL - wxASSERT( str.GetStringData()->IsValid() ); -#endif - - wxString s; - if ( !s.Alloc(wxStrlen(psz) + str.length()) ) { - wxFAIL_MSG( _T("out of memory in wxString::operator+") ); - } - s += str; - s += psz; - - return s; -} - -wxString operator+(const wxChar *psz, const wxString& str) -{ -#if !wxUSE_STL - wxASSERT( str.GetStringData()->IsValid() ); -#endif - - wxString s; - if ( !s.Alloc(wxStrlen(psz) + str.length()) ) { - wxFAIL_MSG( _T("out of memory in wxString::operator+") ); - } - s = psz; - s += str; - - return s; -} - -// =========================================================================== -// other common string functions -// =========================================================================== - -int wxString::Cmp(const wxString& s) const -{ - return compare(s); -} - -int wxString::Cmp(const wxChar* psz) const -{ - return compare(psz); -} - -static inline int wxDoCmpNoCase(const wxChar* s1, size_t l1, - const wxChar* s2, size_t l2) -{ - size_t i; - - if( l1 == l2 ) - { - for(i = 0; i < l1; ++i) - { - if(wxTolower(s1[i]) != wxTolower(s2[i])) - break; - } - return i == l1 ? 0 : wxTolower(s1[i]) < wxTolower(s2[i]) ? -1 : 1; - } - else if( l1 < l2 ) - { - for(i = 0; i < l1; ++i) - { - if(wxTolower(s1[i]) != wxTolower(s2[i])) - break; - } - return i == l1 ? -1 : wxTolower(s1[i]) < wxTolower(s2[i]) ? -1 : 1; - } - else - { - for(i = 0; i < l2; ++i) - { - if(wxTolower(s1[i]) != wxTolower(s2[i])) - break; - } - return i == l2 ? 1 : wxTolower(s1[i]) < wxTolower(s2[i]) ? -1 : 1; - } -} - -int wxString::CmpNoCase(const wxString& s) const -{ - return wxDoCmpNoCase(data(), length(), s.data(), s.length()); -} - -int wxString::CmpNoCase(const wxChar* psz) const -{ - int nLen = wxStrlen(psz); - - return wxDoCmpNoCase(data(), length(), psz, nLen); -} - - -#if wxUSE_UNICODE - -#ifdef __MWERKS__ -#ifndef __SCHAR_MAX__ -#define __SCHAR_MAX__ 127 -#endif -#endif - -wxString wxString::FromAscii(const char *ascii) -{ - if (!ascii) - return wxEmptyString; - - size_t len = strlen( ascii ); - wxString res; - - if ( len ) - { - wxStringBuffer buf(res, len); - - wchar_t *dest = buf; - - for ( ;; ) - { - if ( (*dest++ = (wchar_t)(unsigned char)*ascii++) == L'\0' ) - break; - } - } - - return res; -} - -wxString wxString::FromAscii(const char ascii) -{ - // What do we do with '\0' ? - - wxString res; - res += (wchar_t)(unsigned char) ascii; - - return res; -} - -const wxCharBuffer wxString::ToAscii() const -{ - // this will allocate enough space for the terminating NUL too - wxCharBuffer buffer(length()); - - - char *dest = buffer.data(); - - const wchar_t *pwc = c_str(); - for ( ;; ) - { - *dest++ = (char)(*pwc > SCHAR_MAX ? wxT('_') : *pwc); - - // the output string can't have embedded NULs anyhow, so we can safely - // stop at first of them even if we do have any - if ( !*pwc++ ) - break; - } - - return buffer; -} - -#endif // Unicode - -// extract string of length nCount starting at nFirst -wxString wxString::Mid(size_t nFirst, size_t nCount) const -{ - size_t nLen = length(); - - // default value of nCount is npos and means "till the end" - if ( nCount == npos ) - { - nCount = nLen - nFirst; - } - - // out-of-bounds requests return sensible things - if ( nFirst + nCount > nLen ) - { - nCount = nLen - nFirst; - } - - if ( nFirst > nLen ) - { - // AllocCopy() will return empty string - return wxEmptyString; - } - - wxString dest(*this, nFirst, nCount); - if ( dest.length() != nCount ) - { - wxFAIL_MSG( _T("out of memory in wxString::Mid") ); - } - - return dest; -} - -// check that the string starts with prefix and return the rest of the string -// in the provided pointer if it is not NULL, otherwise return false -bool wxString::StartsWith(const wxChar *prefix, wxString *rest) const -{ - wxASSERT_MSG( prefix, _T("invalid parameter in wxString::StartsWith") ); - - // first check if the beginning of the string matches the prefix: note - // that we don't have to check that we don't run out of this string as - // when we reach the terminating NUL, either prefix string ends too (and - // then it's ok) or we break out of the loop because there is no match - const wxChar *p = c_str(); - while ( *prefix ) - { - if ( *prefix++ != *p++ ) - { - // no match - return false; - } - } - - if ( rest ) - { - // put the rest of the string into provided pointer - *rest = p; - } - - return true; -} - - -// check that the string ends with suffix and return the rest of it in the -// provided pointer if it is not NULL, otherwise return false -bool wxString::EndsWith(const wxChar *suffix, wxString *rest) const -{ - wxASSERT_MSG( suffix, _T("invalid parameter in wxString::EndssWith") ); - - int start = length() - wxStrlen(suffix); - if ( start < 0 || wxStrcmp(c_str() + start, suffix) != 0 ) - return false; - - if ( rest ) - { - // put the rest of the string into provided pointer - rest->assign(*this, 0, start); - } - - return true; -} - - -// extract nCount last (rightmost) characters -wxString wxString::Right(size_t nCount) const -{ - if ( nCount > length() ) - nCount = length(); - - wxString dest(*this, length() - nCount, nCount); - if ( dest.length() != nCount ) { - wxFAIL_MSG( _T("out of memory in wxString::Right") ); - } - return dest; -} - -// get all characters after the last occurence of ch -// (returns the whole string if ch not found) -wxString wxString::AfterLast(wxChar ch) const -{ - wxString str; - int iPos = Find(ch, true); - if ( iPos == wxNOT_FOUND ) - str = *this; - else - str = c_str() + iPos + 1; - - return str; -} - -// extract nCount first (leftmost) characters -wxString wxString::Left(size_t nCount) const -{ - if ( nCount > length() ) - nCount = length(); - - wxString dest(*this, 0, nCount); - if ( dest.length() != nCount ) { - wxFAIL_MSG( _T("out of memory in wxString::Left") ); - } - return dest; -} - -// get all characters before the first occurence of ch -// (returns the whole string if ch not found) -wxString wxString::BeforeFirst(wxChar ch) const -{ - int iPos = Find(ch); - if ( iPos == wxNOT_FOUND ) iPos = length(); - return wxString(*this, 0, iPos); -} - -/// get all characters before the last occurence of ch -/// (returns empty string if ch not found) -wxString wxString::BeforeLast(wxChar ch) const -{ - wxString str; - int iPos = Find(ch, true); - if ( iPos != wxNOT_FOUND && iPos != 0 ) - str = wxString(c_str(), iPos); - - return str; -} - -/// get all characters after the first occurence of ch -/// (returns empty string if ch not found) -wxString wxString::AfterFirst(wxChar ch) const -{ - wxString str; - int iPos = Find(ch); - if ( iPos != wxNOT_FOUND ) - str = c_str() + iPos + 1; - - return str; -} - -// replace first (or all) occurences of some substring with another one -size_t wxString::Replace(const wxChar *szOld, - const wxChar *szNew, bool bReplaceAll) -{ - // if we tried to replace an empty string we'd enter an infinite loop below - wxCHECK_MSG( szOld && *szOld && szNew, 0, - _T("wxString::Replace(): invalid parameter") ); - - size_t uiCount = 0; // count of replacements made - - size_t uiOldLen = wxStrlen(szOld); - size_t uiNewLen = wxStrlen(szNew); - - size_t dwPos = 0; - - while ( this->c_str()[dwPos] != wxT('\0') ) - { - //DO NOT USE STRSTR HERE - //this string can contain embedded null characters, - //so strstr will function incorrectly - dwPos = find(szOld, dwPos); - if ( dwPos == npos ) - break; // exit the loop - else - { - //replace this occurance of the old string with the new one - replace(dwPos, uiOldLen, szNew, uiNewLen); - - //move up pos past the string that was replaced - dwPos += uiNewLen; - - //increase replace count - ++uiCount; - - // stop now? - if ( !bReplaceAll ) - break; // exit the loop - } - } - - return uiCount; -} - -bool wxString::IsAscii() const -{ - const wxChar *s = (const wxChar*) *this; - while(*s){ - if(!isascii(*s)) return(false); - s++; - } - return(true); -} - -bool wxString::IsWord() const -{ - const wxChar *s = (const wxChar*) *this; - while(*s){ - if(!wxIsalpha(*s)) return(false); - s++; - } - return(true); -} - -bool wxString::IsNumber() const -{ - const wxChar *s = (const wxChar*) *this; - if (wxStrlen(s)) - if ((s[0] == wxT('-')) || (s[0] == wxT('+'))) s++; - while(*s){ - if(!wxIsdigit(*s)) return(false); - s++; - } - return(true); -} - -wxString wxString::Strip(stripType w) const -{ - wxString s = *this; - if ( w & leading ) s.Trim(false); - if ( w & trailing ) s.Trim(true); - return s; -} - -// --------------------------------------------------------------------------- -// case conversion -// --------------------------------------------------------------------------- - -wxString& wxString::MakeUpper() -{ - for ( iterator it = begin(), en = end(); it != en; ++it ) - *it = (wxChar)wxToupper(*it); - - return *this; -} - -wxString& wxString::MakeLower() -{ - for ( iterator it = begin(), en = end(); it != en; ++it ) - *it = (wxChar)wxTolower(*it); - - return *this; -} - -// --------------------------------------------------------------------------- -// trimming and padding -// --------------------------------------------------------------------------- - -// some compilers (VC++ 6.0 not to name them) return true for a call to -// isspace('\xEA') in the C locale which seems to be broken to me, but we have -// to live with this by checking that the character is a 7 bit one - even if -// this may fail to detect some spaces (I don't know if Unicode doesn't have -// space-like symbols somewhere except in the first 128 chars), it is arguably -// still better than trimming away accented letters -inline int wxSafeIsspace(wxChar ch) { return (ch < 127) && wxIsspace(ch); } - -// trims spaces (in the sense of isspace) from left or right side -wxString& wxString::Trim(bool bFromRight) -{ - // first check if we're going to modify the string at all - if ( !empty() && - ( - (bFromRight && wxSafeIsspace(GetChar(length() - 1))) || - (!bFromRight && wxSafeIsspace(GetChar(0u))) - ) - ) - { - if ( bFromRight ) - { - // find last non-space character - reverse_iterator psz = rbegin(); - while ( (psz != rend()) && wxSafeIsspace(*psz) ) - psz++; - - // truncate at trailing space start - erase(psz.base(), end()); - } - else - { - // find first non-space character - iterator psz = begin(); - while ( (psz != end()) && wxSafeIsspace(*psz) ) - psz++; - - // fix up data and length - erase(begin(), psz); - } - } - - return *this; -} - -// adds nCount characters chPad to the string from either side -wxString& wxString::Pad(size_t nCount, wxChar chPad, bool bFromRight) -{ - wxString s(chPad, nCount); - - if ( bFromRight ) - *this += s; - else - { - s += *this; - swap(s); - } - - return *this; -} - -// truncate the string -wxString& wxString::Truncate(size_t uiLen) -{ - if ( uiLen < length() ) - { - erase(begin() + uiLen, end()); - } - //else: nothing to do, string is already short enough - - return *this; -} - -// --------------------------------------------------------------------------- -// finding (return wxNOT_FOUND if not found and index otherwise) -// --------------------------------------------------------------------------- - -// find a character -int wxString::Find(wxChar ch, bool bFromEnd) const -{ - size_type idx = bFromEnd ? find_last_of(ch) : find_first_of(ch); - - return (idx == npos) ? wxNOT_FOUND : (int)idx; -} - -// find a sub-string (like strstr) -int wxString::Find(const wxChar *pszSub) const -{ - size_type idx = find(pszSub); - - return (idx == npos) ? wxNOT_FOUND : (int)idx; -} - -// ---------------------------------------------------------------------------- -// conversion to numbers -// ---------------------------------------------------------------------------- - -// the implementation of all the functions below is exactly the same so factor -// it out - -template -bool wxStringToIntType(const wxChar *start, - T *val, - int base, - F func) -{ - wxCHECK_MSG( val, false, _T("NULL output pointer") ); - wxASSERT_MSG( !base || (base > 1 && base <= 36), _T("invalid base") ); - -#ifndef __WXWINCE__ - errno = 0; -#endif - - wxChar *end; - *val = (*func)(start, &end, base); - - // return true only if scan was stopped by the terminating NUL and if the - // string was not empty to start with and no under/overflow occurred - return !*end && (end != start) -#ifndef __WXWINCE__ - && (errno != ERANGE) -#endif - ; -} - -bool wxString::ToLong(long *val, int base) const -{ - return wxStringToIntType(c_str(), val, base, wxStrtol); -} - -bool wxString::ToULong(unsigned long *val, int base) const -{ - return wxStringToIntType(c_str(), val, base, wxStrtoul); -} - -bool wxString::ToLongLong(wxLongLong_t *val, int base) const -{ -#ifdef wxHAS_STRTOLL - return wxStringToIntType(c_str(), val, base, wxStrtoll); -#else - // TODO: implement this ourselves - wxUnusedVar(val); - wxUnusedVar(base); - return false; -#endif // wxHAS_STRTOLL -} - -bool wxString::ToULongLong(wxULongLong_t *val, int base) const -{ -#ifdef wxHAS_STRTOLL - return wxStringToIntType(c_str(), val, base, wxStrtoull); -#else - // TODO: implement this ourselves - wxUnusedVar(val); - wxUnusedVar(base); - return false; -#endif -} - -bool wxString::ToDouble(double *val) const -{ - wxCHECK_MSG( val, false, _T("NULL pointer in wxString::ToDouble") ); - -#ifndef __WXWINCE__ - errno = 0; -#endif - - const wxChar *start = c_str(); - wxChar *end; - *val = wxStrtod(start, &end); - - // return true only if scan was stopped by the terminating NUL and if the - // string was not empty to start with and no under/overflow occurred - return !*end && (end != start) -#ifndef __WXWINCE__ - && (errno != ERANGE) -#endif - ; -} - -// --------------------------------------------------------------------------- -// formatted output -// --------------------------------------------------------------------------- - -/* static */ -wxString wxString::Format(const wxChar *pszFormat, ...) -{ - va_list argptr; - va_start(argptr, pszFormat); - - wxString s; - s.PrintfV(pszFormat, argptr); - - va_end(argptr); - - return s; -} - -/* static */ -wxString wxString::FormatV(const wxChar *pszFormat, va_list argptr) -{ - wxString s; - s.PrintfV(pszFormat, argptr); - return s; -} - -int wxString::Printf(const wxChar *pszFormat, ...) -{ - va_list argptr; - va_start(argptr, pszFormat); - - int iLen = PrintfV(pszFormat, argptr); - - va_end(argptr); - - return iLen; -} - -/* - Uses wxVsnprintf and places the result into the this string. - - In ANSI build, wxVsnprintf is effectively vsnprintf but in Unicode build - it is vswprintf. Due to a discrepancy between vsnprintf and vswprintf in - the ISO C99 (and thus SUSv3) standard the return value for the case of - an undersized buffer is inconsistent. For conforming vsnprintf - implementations the function must return the number of characters that - would have been printed had the buffer been large enough. For conforming - vswprintf implementations the function must return a negative number - and set errno. - - What vswprintf sets errno to is undefined but Darwin seems to set it to - EOVERFLOW. The only expected errno are EILSEQ and EINVAL. Both of - those are defined in the standard and backed up by several conformance - statements. Note that ENOMEM mentioned in the manual page does not - apply to swprintf, only wprintf and fwprintf. - - Official manual page: - http://www.opengroup.org/onlinepubs/009695399/functions/swprintf.html - - Some conformance statements (AIX, Solaris): - http://www.opengroup.org/csq/view.mhtml?RID=ibm%2FSD1%2F3 - http://www.theopengroup.org/csq/view.mhtml?norationale=1&noreferences=1&RID=Fujitsu%2FSE2%2F10 - - Since EILSEQ and EINVAL are rather common but EOVERFLOW is not and since - EILSEQ and EINVAL are specifically defined to mean the error is other than - an undersized buffer and no other errno are defined we treat those two - as meaning hard errors and everything else gets the old behavior which - is to keep looping and increasing buffer size until the function succeeds. - - In practice it's impossible to determine before compilation which behavior - may be used. The vswprintf function may have vsnprintf-like behavior or - vice-versa. Behavior detected on one release can theoretically change - with an updated release. Not to mention that configure testing for it - would require the test to be run on the host system, not the build system - which makes cross compilation difficult. Therefore, we make no assumptions - about behavior and try our best to handle every known case, including the - case where wxVsnprintf returns a negative number and fails to set errno. - - There is yet one more non-standard implementation and that is our own. - Fortunately, that can be detected at compile-time. - - On top of all that, ISO C99 explicitly defines snprintf to write a null - character to the last position of the specified buffer. That would be at - at the given buffer size minus 1. It is supposed to do this even if it - turns out that the buffer is sized too small. - - Darwin (tested on 10.5) follows the C99 behavior exactly. - - Glibc 2.6 almost follows the C99 behavior except vswprintf never sets - errno even when it fails. However, it only seems to ever fail due - to an undersized buffer. -*/ -int wxString::PrintfV(const wxChar* pszFormat, va_list argptr) -{ - int size = 1024; - - for ( ;; ) - { - // Allocate 1 more character than we tell wxVsnprintf about - // just in case it is buggy. - // FIXME: I have a feeling that the underlying function was not buggy - // and I suspect it was to fix the buf[size] = '\0' line below - wxStringBuffer tmp(*this, size + 1); - wxChar *buf = tmp; - - if ( !buf ) - { - // out of memory - return -1; - } - - // wxVsnprintf() may modify the original arg pointer, so pass it - // only a copy - va_list argptrcopy; - wxVaCopy(argptrcopy, argptr); - -#ifndef __WXWINCE__ - // Set errno to 0 to make it determinate if wxVsnprintf fails to set it. - errno = 0; -#endif - int len = wxVsnprintf(buf, size, pszFormat, argptrcopy); - va_end(argptrcopy); - - // some implementations of vsnprintf() don't NUL terminate - // the string if there is not enough space for it so - // always do it manually - // FIXME: This really seems to be the wrong and would be an off-by-one - // bug except the code above allocates an extra character. - buf[size] = _T('\0'); - - // vsnprintf() may return either -1 (traditional Unix behaviour) or the - // total number of characters which would have been written if the - // buffer were large enough (newer standards such as Unix98) - if ( len < 0 ) - { -#if wxUSE_WXVSNPRINTF - // we know that our own implementation of wxVsnprintf() returns -1 - // only for a format error - thus there's something wrong with - // the user's format string - return -1; -#else // assume that system version only returns error if not enough space -#if !defined(__WXWINCE__) && (!defined(__OS2__) || defined(__INNOTEK_LIBC__)) - if( (errno == EILSEQ) || (errno == EINVAL) ) - // If errno was set to one of the two well-known hard errors - // then fail immediately to avoid an infinite loop. - return -1; - else -#endif // __WXWINCE__ - // still not enough, as we don't know how much we need, double the - // current size of the buffer - size *= 2; -#endif // wxUSE_WXVSNPRINTF/!wxUSE_WXVSNPRINTF - } - else if ( len >= size ) - { -#if wxUSE_WXVSNPRINTF - // we know that our own implementation of wxVsnprintf() returns - // size+1 when there's not enough space but that's not the size - // of the required buffer! - size *= 2; // so we just double the current size of the buffer -#else - // some vsnprintf() implementations NUL-terminate the buffer and - // some don't in len == size case, to be safe always add 1 - // FIXME: I don't quite understand this comment. The vsnprintf - // function is specifically defined to return the number of - // characters printed not including the null terminator. - // So OF COURSE you need to add 1 to get the right buffer size. - // The following line is definitely correct, no question. - size = len + 1; -#endif - } - else // ok, there was enough space - { - break; - } - } - - // we could have overshot - Shrink(); - - return length(); -} - -// ---------------------------------------------------------------------------- -// misc other operations -// ---------------------------------------------------------------------------- - -// returns true if the string matches the pattern which may contain '*' and -// '?' metacharacters (as usual, '?' matches any character and '*' any number -// of them) -bool wxString::Matches(const wxChar *pszMask) const -{ - // I disable this code as it doesn't seem to be faster (in fact, it seems - // to be much slower) than the old, hand-written code below and using it - // here requires always linking with libregex even if the user code doesn't - // use it -#if 0 // wxUSE_REGEX - // first translate the shell-like mask into a regex - wxString pattern; - pattern.reserve(wxStrlen(pszMask)); - - pattern += _T('^'); - while ( *pszMask ) - { - switch ( *pszMask ) - { - case _T('?'): - pattern += _T('.'); - break; - - case _T('*'): - pattern += _T(".*"); - break; - - case _T('^'): - case _T('.'): - case _T('$'): - case _T('('): - case _T(')'): - case _T('|'): - case _T('+'): - case _T('\\'): - // these characters are special in a RE, quote them - // (however note that we don't quote '[' and ']' to allow - // using them for Unix shell like matching) - pattern += _T('\\'); - // fall through - - default: - pattern += *pszMask; - } - - pszMask++; - } - pattern += _T('$'); - - // and now use it - return wxRegEx(pattern, wxRE_NOSUB | wxRE_EXTENDED).Matches(c_str()); -#else // !wxUSE_REGEX - // TODO: this is, of course, awfully inefficient... - - // the char currently being checked - const wxChar *pszTxt = c_str(); - - // the last location where '*' matched - const wxChar *pszLastStarInText = NULL; - const wxChar *pszLastStarInMask = NULL; - -match: - for ( ; *pszMask != wxT('\0'); pszMask++, pszTxt++ ) { - switch ( *pszMask ) { - case wxT('?'): - if ( *pszTxt == wxT('\0') ) - return false; - - // pszTxt and pszMask will be incremented in the loop statement - - break; - - case wxT('*'): - { - // remember where we started to be able to backtrack later - pszLastStarInText = pszTxt; - pszLastStarInMask = pszMask; - - // ignore special chars immediately following this one - // (should this be an error?) - while ( *pszMask == wxT('*') || *pszMask == wxT('?') ) - pszMask++; - - // if there is nothing more, match - if ( *pszMask == wxT('\0') ) - return true; - - // are there any other metacharacters in the mask? - size_t uiLenMask; - const wxChar *pEndMask = wxStrpbrk(pszMask, wxT("*?")); - - if ( pEndMask != NULL ) { - // we have to match the string between two metachars - uiLenMask = pEndMask - pszMask; - } - else { - // we have to match the remainder of the string - uiLenMask = wxStrlen(pszMask); - } - - wxString strToMatch(pszMask, uiLenMask); - const wxChar* pMatch = wxStrstr(pszTxt, strToMatch); - if ( pMatch == NULL ) - return false; - - // -1 to compensate "++" in the loop - pszTxt = pMatch + uiLenMask - 1; - pszMask += uiLenMask - 1; - } - break; - - default: - if ( *pszMask != *pszTxt ) - return false; - break; - } - } - - // match only if nothing left - if ( *pszTxt == wxT('\0') ) - return true; - - // if we failed to match, backtrack if we can - if ( pszLastStarInText ) { - pszTxt = pszLastStarInText + 1; - pszMask = pszLastStarInMask; - - pszLastStarInText = NULL; - - // don't bother resetting pszLastStarInMask, it's unnecessary - - goto match; - } - - return false; -#endif // wxUSE_REGEX/!wxUSE_REGEX -} - -// Count the number of chars -int wxString::Freq(wxChar ch) const -{ - int count = 0; - int len = length(); - for (int i = 0; i < len; i++) - { - if (GetChar(i) == ch) - count ++; - } - return count; -} - -// convert to upper case, return the copy of the string -wxString wxString::Upper() const -{ wxString s(*this); return s.MakeUpper(); } - -// convert to lower case, return the copy of the string -wxString wxString::Lower() const { wxString s(*this); return s.MakeLower(); } - -int wxString::sprintf(const wxChar *pszFormat, ...) - { - va_list argptr; - va_start(argptr, pszFormat); - int iLen = PrintfV(pszFormat, argptr); - va_end(argptr); - return iLen; - } - -// ============================================================================ -// ArrayString -// ============================================================================ - -#include "wx/arrstr.h" - -wxArrayString::wxArrayString(size_t sz, const wxChar** a) -{ -#if !wxUSE_STL - Init(false); -#endif - for (size_t i=0; i < sz; i++) - Add(a[i]); -} - -wxArrayString::wxArrayString(size_t sz, const wxString* a) -{ -#if !wxUSE_STL - Init(false); -#endif - for (size_t i=0; i < sz; i++) - Add(a[i]); -} - -#if !wxUSE_STL - -// size increment = min(50% of current size, ARRAY_MAXSIZE_INCREMENT) -#define ARRAY_MAXSIZE_INCREMENT 4096 - -#ifndef ARRAY_DEFAULT_INITIAL_SIZE // also defined in dynarray.h -#define ARRAY_DEFAULT_INITIAL_SIZE (16) -#endif - -#define STRING(p) ((wxString *)(&(p))) - -// ctor -void wxArrayString::Init(bool autoSort) -{ - m_nSize = - m_nCount = 0; - m_pItems = (wxChar **) NULL; - m_autoSort = autoSort; -} - -// copy ctor -wxArrayString::wxArrayString(const wxArrayString& src) -{ - Init(src.m_autoSort); - - *this = src; -} - -// assignment operator -wxArrayString& wxArrayString::operator=(const wxArrayString& src) -{ - if ( m_nSize > 0 ) - Clear(); - - Copy(src); - - m_autoSort = src.m_autoSort; - - return *this; -} - -void wxArrayString::Copy(const wxArrayString& src) -{ - if ( src.m_nCount > ARRAY_DEFAULT_INITIAL_SIZE ) - Alloc(src.m_nCount); - - for ( size_t n = 0; n < src.m_nCount; n++ ) - Add(src[n]); -} - -// grow the array -void wxArrayString::Grow(size_t nIncrement) -{ - // only do it if no more place - if ( (m_nSize - m_nCount) < nIncrement ) { - // if ARRAY_DEFAULT_INITIAL_SIZE were set to 0, the initially empty would - // be never resized! - #if ARRAY_DEFAULT_INITIAL_SIZE == 0 - #error "ARRAY_DEFAULT_INITIAL_SIZE must be > 0!" - #endif - - if ( m_nSize == 0 ) { - // was empty, alloc some memory - m_nSize = ARRAY_DEFAULT_INITIAL_SIZE; - if (m_nSize < nIncrement) - m_nSize = nIncrement; - m_pItems = new wxChar *[m_nSize]; - } - else { - // otherwise when it's called for the first time, nIncrement would be 0 - // and the array would never be expanded - // add 50% but not too much - size_t ndefIncrement = m_nSize < ARRAY_DEFAULT_INITIAL_SIZE - ? ARRAY_DEFAULT_INITIAL_SIZE : m_nSize >> 1; - if ( ndefIncrement > ARRAY_MAXSIZE_INCREMENT ) - ndefIncrement = ARRAY_MAXSIZE_INCREMENT; - if ( nIncrement < ndefIncrement ) - nIncrement = ndefIncrement; - m_nSize += nIncrement; - wxChar **pNew = new wxChar *[m_nSize]; - - // copy data to new location - memcpy(pNew, m_pItems, m_nCount*sizeof(wxChar *)); - - // delete old memory (but do not release the strings!) - wxDELETEA(m_pItems); - - m_pItems = pNew; - } - } -} - -void wxArrayString::Free() -{ - for ( size_t n = 0; n < m_nCount; n++ ) { - STRING(m_pItems[n])->GetStringData()->Unlock(); - } -} - -// deletes all the strings from the list -void wxArrayString::Empty() -{ - Free(); - - m_nCount = 0; -} - -// as Empty, but also frees memory -void wxArrayString::Clear() -{ - Free(); - - m_nSize = - m_nCount = 0; - - wxDELETEA(m_pItems); -} - -// dtor -wxArrayString::~wxArrayString() -{ - Free(); - - wxDELETEA(m_pItems); -} - -void wxArrayString::reserve(size_t nSize) -{ - Alloc(nSize); -} - -// pre-allocates memory (frees the previous data!) -void wxArrayString::Alloc(size_t nSize) -{ - // only if old buffer was not big enough - if ( nSize > m_nSize ) { - wxChar **pNew = new wxChar *[nSize]; - if ( !pNew ) - return; - - memcpy(pNew, m_pItems, m_nCount*sizeof(wxChar *)); - delete [] m_pItems; - - m_pItems = pNew; - m_nSize = nSize; - } -} - -// minimizes the memory usage by freeing unused memory -void wxArrayString::Shrink() -{ - // only do it if we have some memory to free - if( m_nCount < m_nSize ) { - // allocates exactly as much memory as we need - wxChar **pNew = new wxChar *[m_nCount]; - - // copy data to new location - memcpy(pNew, m_pItems, m_nCount*sizeof(wxChar *)); - delete [] m_pItems; - m_pItems = pNew; - } -} - -#if WXWIN_COMPATIBILITY_2_4 - -// return a wxString[] as required for some control ctors. -wxString* wxArrayString::GetStringArray() const -{ - wxString *array = 0; - - if( m_nCount > 0 ) - { - array = new wxString[m_nCount]; - for( size_t i = 0; i < m_nCount; i++ ) - array[i] = m_pItems[i]; - } - - return array; -} - -void wxArrayString::Remove(size_t nIndex, size_t nRemove) -{ - RemoveAt(nIndex, nRemove); -} - -#endif // WXWIN_COMPATIBILITY_2_4 - -// searches the array for an item (forward or backwards) -int wxArrayString::Index(const wxChar *sz, bool bCase, bool bFromEnd) const -{ - if ( m_autoSort ) { - // use binary search in the sorted array - wxASSERT_MSG( bCase && !bFromEnd, - wxT("search parameters ignored for auto sorted array") ); - - size_t i, - lo = 0, - hi = m_nCount; - int res; - while ( lo < hi ) { - i = (lo + hi)/2; - - res = wxStrcmp(sz, m_pItems[i]); - if ( res < 0 ) - hi = i; - else if ( res > 0 ) - lo = i + 1; - else - return i; - } - - return wxNOT_FOUND; - } - else { - // use linear search in unsorted array - if ( bFromEnd ) { - if ( m_nCount > 0 ) { - size_t ui = m_nCount; - do { - if ( STRING(m_pItems[--ui])->IsSameAs(sz, bCase) ) - return ui; - } - while ( ui != 0 ); - } - } - else { - for( size_t ui = 0; ui < m_nCount; ui++ ) { - if( STRING(m_pItems[ui])->IsSameAs(sz, bCase) ) - return ui; - } - } - } - - return wxNOT_FOUND; -} - -// add item at the end -size_t wxArrayString::Add(const wxString& str, size_t nInsert) -{ - if ( m_autoSort ) { - // insert the string at the correct position to keep the array sorted - size_t i, - lo = 0, - hi = m_nCount; - int res; - while ( lo < hi ) { - i = (lo + hi)/2; - - res = str.Cmp(m_pItems[i]); - if ( res < 0 ) - hi = i; - else if ( res > 0 ) - lo = i + 1; - else { - lo = hi = i; - break; - } - } - - wxASSERT_MSG( lo == hi, wxT("binary search broken") ); - - Insert(str, lo, nInsert); - - return (size_t)lo; - } - else { - wxASSERT( str.GetStringData()->IsValid() ); - - Grow(nInsert); - - for (size_t i = 0; i < nInsert; i++) - { - // the string data must not be deleted! - str.GetStringData()->Lock(); - - // just append - m_pItems[m_nCount + i] = (wxChar *)str.c_str(); // const_cast - } - size_t ret = m_nCount; - m_nCount += nInsert; - return ret; - } -} - -// add item at the given position -void wxArrayString::Insert(const wxString& str, size_t nIndex, size_t nInsert) -{ - wxASSERT( str.GetStringData()->IsValid() ); - - wxCHECK_RET( nIndex <= m_nCount, wxT("bad index in wxArrayString::Insert") ); - wxCHECK_RET( m_nCount <= m_nCount + nInsert, - wxT("array size overflow in wxArrayString::Insert") ); - - Grow(nInsert); - - memmove(&m_pItems[nIndex + nInsert], &m_pItems[nIndex], - (m_nCount - nIndex)*sizeof(wxChar *)); - - for (size_t i = 0; i < nInsert; i++) - { - str.GetStringData()->Lock(); - m_pItems[nIndex + i] = (wxChar *)str.c_str(); - } - m_nCount += nInsert; -} - -// range insert (STL 23.2.4.3) -void -wxArrayString::insert(iterator it, const_iterator first, const_iterator last) -{ - const int idx = it - begin(); - - // grow it once - Grow(last - first); - - // reset "it" since it can change inside Grow() - it = begin() + idx; - - while ( first != last ) - { - it = insert(it, *first); - - // insert returns an iterator to the last element inserted but we need - // insert the next after this one, that is before the next one - ++it; - - ++first; - } -} - -// expand the array -void wxArrayString::SetCount(size_t count) -{ - Alloc(count); - - wxString s; - while ( m_nCount < count ) - m_pItems[m_nCount++] = (wxChar *)s.c_str(); -} - -// removes item from array (by index) -void wxArrayString::RemoveAt(size_t nIndex, size_t nRemove) -{ - wxCHECK_RET( nIndex < m_nCount, wxT("bad index in wxArrayString::Remove") ); - wxCHECK_RET( nIndex + nRemove <= m_nCount, - wxT("removing too many elements in wxArrayString::Remove") ); - - // release our lock - for (size_t i = 0; i < nRemove; i++) - Item(nIndex + i).GetStringData()->Unlock(); - - memmove(&m_pItems[nIndex], &m_pItems[nIndex + nRemove], - (m_nCount - nIndex - nRemove)*sizeof(wxChar *)); - m_nCount -= nRemove; -} - -// removes item from array (by value) -void wxArrayString::Remove(const wxChar *sz) -{ - int iIndex = Index(sz); - - wxCHECK_RET( iIndex != wxNOT_FOUND, - wxT("removing inexistent element in wxArrayString::Remove") ); - - RemoveAt(iIndex); -} - -void wxArrayString::assign(const_iterator first, const_iterator last) -{ - reserve(last - first); - for(; first != last; ++first) - push_back(*first); -} - -// ---------------------------------------------------------------------------- -// sorting -// ---------------------------------------------------------------------------- - -// we can only sort one array at a time with the quick-sort based -// implementation -#if wxUSE_THREADS - // need a critical section to protect access to gs_compareFunction and - // gs_sortAscending variables - static wxCriticalSection gs_critsectStringSort; -#endif // wxUSE_THREADS - -// function to use for string comparaison -static wxArrayString::CompareFunction gs_compareFunction = NULL; - -// if we don't use the compare function, this flag tells us if we sort the -// array in ascending or descending order -static bool gs_sortAscending = true; - -// function which is called by quick sort -extern "C" int wxC_CALLING_CONV // LINKAGEMODE -wxStringCompareFunction(const void *first, const void *second) -{ - wxString *strFirst = (wxString *)first; - wxString *strSecond = (wxString *)second; - - if ( gs_compareFunction ) { - return gs_compareFunction(*strFirst, *strSecond); - } - else { - // maybe we should use wxStrcoll - int result = strFirst->Cmp(*strSecond); - - return gs_sortAscending ? result : -result; - } -} - -// sort array elements using passed comparaison function -void wxArrayString::Sort(CompareFunction compareFunction) -{ - wxCRIT_SECT_LOCKER(lockCmpFunc, gs_critsectStringSort); - - wxASSERT( !gs_compareFunction ); // must have been reset to NULL - gs_compareFunction = compareFunction; - - DoSort(); - - // reset it to NULL so that Sort(bool) will work the next time - gs_compareFunction = NULL; -} - -extern "C" -{ - typedef int (wxC_CALLING_CONV * wxStringCompareFn)(const void *first, - const void *second); -} - -void wxArrayString::Sort(CompareFunction2 compareFunction) -{ - qsort(m_pItems, m_nCount, sizeof(wxChar *), (wxStringCompareFn)compareFunction); -} - -void wxArrayString::Sort(bool reverseOrder) -{ - Sort(reverseOrder ? wxStringSortDescending : wxStringSortAscending); -} - -void wxArrayString::DoSort() -{ - wxCHECK_RET( !m_autoSort, wxT("can't use this method with sorted arrays") ); - - // just sort the pointers using qsort() - of course it only works because - // wxString() *is* a pointer to its data - qsort(m_pItems, m_nCount, sizeof(wxChar *), wxStringCompareFunction); -} - -bool wxArrayString::operator==(const wxArrayString& a) const -{ - if ( m_nCount != a.m_nCount ) - return false; - - for ( size_t n = 0; n < m_nCount; n++ ) - { - if ( Item(n) != a[n] ) - return false; - } - - return true; -} - -#endif // !wxUSE_STL - -int wxCMPFUNC_CONV wxStringSortAscending(wxString* s1, wxString* s2) -{ - return s1->Cmp(*s2); -} - -int wxCMPFUNC_CONV wxStringSortDescending(wxString* s1, wxString* s2) -{ - return -s1->Cmp(*s2); -} +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/string.cpp +// Purpose: wxString class +// Author: Vadim Zeitlin, Ryan Norton +// Modified by: +// Created: 29/01/98 +// RCS-ID: $Id: string.cpp 53702 2008-05-22 17:22:00Z SN $ +// Copyright: (c) 1998 Vadim Zeitlin +// (c) 2004 Ryan Norton +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +/* + * About ref counting: + * 1) all empty strings use g_strEmpty, nRefs = -1 (set in Init()) + * 2) AllocBuffer() sets nRefs to 1, Lock() increments it by one + * 3) Unlock() decrements nRefs and frees memory if it goes to 0 + */ + +// =========================================================================== +// headers, declarations, constants +// =========================================================================== + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#ifndef WX_PRECOMP + #include "wx/string.h" + #include "wx/intl.h" + #include "wx/thread.h" +#endif + +#include + +#ifndef __WXWINCE__ + #include +#endif + +#include +#include + +#ifdef __SALFORDC__ + #include +#endif + +// allocating extra space for each string consumes more memory but speeds up +// the concatenation operations (nLen is the current string's length) +// NB: EXTRA_ALLOC must be >= 0! +#define EXTRA_ALLOC (19 - nLen % 16) + +// --------------------------------------------------------------------------- +// static class variables definition +// --------------------------------------------------------------------------- + +#if !wxUSE_STL + //According to STL _must_ be a -1 size_t + const size_t wxStringBase::npos = (size_t) -1; +#endif + +// ---------------------------------------------------------------------------- +// static data +// ---------------------------------------------------------------------------- + +#if wxUSE_STL + +extern const wxChar WXDLLIMPEXP_BASE *wxEmptyString = _T(""); + +#else + +// for an empty string, GetStringData() will return this address: this +// structure has the same layout as wxStringData and it's data() method will +// return the empty string (dummy pointer) +static const struct +{ + wxStringData data; + wxChar dummy; +} g_strEmpty = { {-1, 0, 0}, wxT('\0') }; + +// empty C style string: points to 'string data' byte of g_strEmpty +extern const wxChar WXDLLIMPEXP_BASE *wxEmptyString = &g_strEmpty.dummy; + +#endif + +// ---------------------------------------------------------------------------- +// global functions +// ---------------------------------------------------------------------------- + +#if wxUSE_STD_IOSTREAM + +#include + +wxSTD ostream& operator<<(wxSTD ostream& os, const wxString& str) +{ +#ifdef __BORLANDC__ + os << str.mb_str(); +#else + os << str.c_str(); +#endif + return os; +} + +#endif // wxUSE_STD_IOSTREAM + +// ---------------------------------------------------------------------------- +// private classes +// ---------------------------------------------------------------------------- + +// this small class is used to gather statistics for performance tuning +//#define WXSTRING_STATISTICS +#ifdef WXSTRING_STATISTICS + class Averager + { + public: + Averager(const wxChar *sz) { m_sz = sz; m_nTotal = m_nCount = 0; } + ~Averager() + { wxPrintf("wxString: average %s = %f\n", m_sz, ((float)m_nTotal)/m_nCount); } + + void Add(size_t n) { m_nTotal += n; m_nCount++; } + + private: + size_t m_nCount, m_nTotal; + const wxChar *m_sz; + } g_averageLength("allocation size"), + g_averageSummandLength("summand length"), + g_averageConcatHit("hit probability in concat"), + g_averageInitialLength("initial string length"); + + #define STATISTICS_ADD(av, val) g_average##av.Add(val) +#else + #define STATISTICS_ADD(av, val) +#endif // WXSTRING_STATISTICS + +#if !wxUSE_STL + +// =========================================================================== +// wxStringData class deallocation +// =========================================================================== + +#if defined(__VISUALC__) && defined(_MT) && !defined(_DLL) +# pragma message (__FILE__ ": building with Multithreaded non DLL runtime has a performance impact on wxString!") +void wxStringData::Free() +{ + free(this); +} +#endif + +// =========================================================================== +// wxStringBase +// =========================================================================== + +// takes nLength elements of psz starting at nPos +void wxStringBase::InitWith(const wxChar *psz, size_t nPos, size_t nLength) +{ + Init(); + + // if the length is not given, assume the string to be NUL terminated + if ( nLength == npos ) { + wxASSERT_MSG( nPos <= wxStrlen(psz), _T("index out of bounds") ); + + nLength = wxStrlen(psz + nPos); + } + + STATISTICS_ADD(InitialLength, nLength); + + if ( nLength > 0 ) { + // trailing '\0' is written in AllocBuffer() + if ( !AllocBuffer(nLength) ) { + wxFAIL_MSG( _T("out of memory in wxStringBase::InitWith") ); + return; + } + wxTmemcpy(m_pchData, psz + nPos, nLength); + } +} + +// poor man's iterators are "void *" pointers +wxStringBase::wxStringBase(const void *pStart, const void *pEnd) +{ + if ( pEnd >= pStart ) + { + InitWith((const wxChar *)pStart, 0, + (const wxChar *)pEnd - (const wxChar *)pStart); + } + else + { + wxFAIL_MSG( _T("pStart is not before pEnd") ); + Init(); + } +} + +wxStringBase::wxStringBase(size_type n, wxChar ch) +{ + Init(); + append(n, ch); +} + +// --------------------------------------------------------------------------- +// memory allocation +// --------------------------------------------------------------------------- + +// allocates memory needed to store a C string of length nLen +bool wxStringBase::AllocBuffer(size_t nLen) +{ + // allocating 0 sized buffer doesn't make sense, all empty strings should + // reuse g_strEmpty + wxASSERT( nLen > 0 ); + + // make sure that we don't overflow + wxCHECK( nLen < (INT_MAX / sizeof(wxChar)) - + (sizeof(wxStringData) + EXTRA_ALLOC + 1), false ); + + STATISTICS_ADD(Length, nLen); + + // allocate memory: + // 1) one extra character for '\0' termination + // 2) sizeof(wxStringData) for housekeeping info + wxStringData* pData = (wxStringData*) + malloc(sizeof(wxStringData) + (nLen + EXTRA_ALLOC + 1)*sizeof(wxChar)); + + if ( pData == NULL ) { + // allocation failures are handled by the caller + return false; + } + + pData->nRefs = 1; + pData->nDataLength = nLen; + pData->nAllocLength = nLen + EXTRA_ALLOC; + m_pchData = pData->data(); // data starts after wxStringData + m_pchData[nLen] = wxT('\0'); + return true; +} + +// must be called before changing this string +bool wxStringBase::CopyBeforeWrite() +{ + wxStringData* pData = GetStringData(); + + if ( pData->IsShared() ) { + pData->Unlock(); // memory not freed because shared + size_t nLen = pData->nDataLength; + if ( !AllocBuffer(nLen) ) { + // allocation failures are handled by the caller + return false; + } + wxTmemcpy(m_pchData, pData->data(), nLen); + } + + wxASSERT( !GetStringData()->IsShared() ); // we must be the only owner + + return true; +} + +// must be called before replacing contents of this string +bool wxStringBase::AllocBeforeWrite(size_t nLen) +{ + wxASSERT( nLen != 0 ); // doesn't make any sense + + // must not share string and must have enough space + wxStringData* pData = GetStringData(); + if ( pData->IsShared() || pData->IsEmpty() ) { + // can't work with old buffer, get new one + pData->Unlock(); + if ( !AllocBuffer(nLen) ) { + // allocation failures are handled by the caller + return false; + } + } + else { + if ( nLen > pData->nAllocLength ) { + // realloc the buffer instead of calling malloc() again, this is more + // efficient + STATISTICS_ADD(Length, nLen); + + nLen += EXTRA_ALLOC; + + pData = (wxStringData*) + realloc(pData, sizeof(wxStringData) + (nLen + 1)*sizeof(wxChar)); + + if ( pData == NULL ) { + // allocation failures are handled by the caller + // keep previous data since reallocation failed + return false; + } + + pData->nAllocLength = nLen; + m_pchData = pData->data(); + } + } + + wxASSERT( !GetStringData()->IsShared() ); // we must be the only owner + + // it doesn't really matter what the string length is as it's going to be + // overwritten later but, for extra safety, set it to 0 for now as we may + // have some junk in m_pchData + GetStringData()->nDataLength = 0; + + return true; +} + +wxStringBase& wxStringBase::append(size_t n, wxChar ch) +{ + size_type len = length(); + + if ( !Alloc(len + n) || !CopyBeforeWrite() ) { + wxFAIL_MSG( _T("out of memory in wxStringBase::append") ); + } + GetStringData()->nDataLength = len + n; + m_pchData[len + n] = '\0'; + for ( size_t i = 0; i < n; ++i ) + m_pchData[len + i] = ch; + return *this; +} + +void wxStringBase::resize(size_t nSize, wxChar ch) +{ + size_t len = length(); + + if ( nSize < len ) + { + erase(begin() + nSize, end()); + } + else if ( nSize > len ) + { + append(nSize - len, ch); + } + //else: we have exactly the specified length, nothing to do +} + +// allocate enough memory for nLen characters +bool wxStringBase::Alloc(size_t nLen) +{ + wxStringData *pData = GetStringData(); + if ( pData->nAllocLength <= nLen ) { + if ( pData->IsEmpty() ) { + nLen += EXTRA_ALLOC; + + pData = (wxStringData *) + malloc(sizeof(wxStringData) + (nLen + 1)*sizeof(wxChar)); + + if ( pData == NULL ) { + // allocation failure handled by caller + return false; + } + + pData->nRefs = 1; + pData->nDataLength = 0; + pData->nAllocLength = nLen; + m_pchData = pData->data(); // data starts after wxStringData + m_pchData[0u] = wxT('\0'); + } + else if ( pData->IsShared() ) { + pData->Unlock(); // memory not freed because shared + size_t nOldLen = pData->nDataLength; + if ( !AllocBuffer(nLen) ) { + // allocation failure handled by caller + return false; + } + // +1 to copy the terminator, too + memcpy(m_pchData, pData->data(), (nOldLen+1)*sizeof(wxChar)); + GetStringData()->nDataLength = nOldLen; + } + else { + nLen += EXTRA_ALLOC; + + pData = (wxStringData *) + realloc(pData, sizeof(wxStringData) + (nLen + 1)*sizeof(wxChar)); + + if ( pData == NULL ) { + // allocation failure handled by caller + // keep previous data since reallocation failed + return false; + } + + // it's not important if the pointer changed or not (the check for this + // is not faster than assigning to m_pchData in all cases) + pData->nAllocLength = nLen; + m_pchData = pData->data(); + } + } + //else: we've already got enough + return true; +} + +wxStringBase::iterator wxStringBase::begin() +{ + if (length() > 0) + CopyBeforeWrite(); + return m_pchData; +} + +wxStringBase::iterator wxStringBase::end() +{ + if (length() > 0) + CopyBeforeWrite(); + return m_pchData + length(); +} + +wxStringBase::iterator wxStringBase::erase(iterator it) +{ + size_type idx = it - begin(); + erase(idx, 1); + return begin() + idx; +} + +wxStringBase& wxStringBase::erase(size_t nStart, size_t nLen) +{ + wxASSERT(nStart <= length()); + size_t strLen = length() - nStart; + // delete nLen or up to the end of the string characters + nLen = strLen < nLen ? strLen : nLen; + wxString strTmp(c_str(), nStart); + strTmp.append(c_str() + nStart + nLen, length() - nStart - nLen); + + swap(strTmp); + return *this; +} + +wxStringBase& wxStringBase::insert(size_t nPos, const wxChar *sz, size_t n) +{ + wxASSERT( nPos <= length() ); + + if ( n == npos ) n = wxStrlen(sz); + if ( n == 0 ) return *this; + + if ( !Alloc(length() + n) || !CopyBeforeWrite() ) { + wxFAIL_MSG( _T("out of memory in wxStringBase::insert") ); + } + + memmove(m_pchData + nPos + n, m_pchData + nPos, + (length() - nPos) * sizeof(wxChar)); + memcpy(m_pchData + nPos, sz, n * sizeof(wxChar)); + GetStringData()->nDataLength = length() + n; + m_pchData[length()] = '\0'; + + return *this; +} + +void wxStringBase::swap(wxStringBase& str) +{ + wxChar* tmp = str.m_pchData; + str.m_pchData = m_pchData; + m_pchData = tmp; +} + +size_t wxStringBase::find(const wxStringBase& str, size_t nStart) const +{ + // deal with the special case of empty string first + const size_t nLen = length(); + const size_t nLenOther = str.length(); + + if ( !nLenOther ) + { + // empty string is a substring of anything + return 0; + } + + if ( !nLen ) + { + // the other string is non empty so can't be our substring + return npos; + } + + wxASSERT( str.GetStringData()->IsValid() ); + wxASSERT( nStart <= nLen ); + + const wxChar * const other = str.c_str(); + + // anchor + const wxChar* p = (const wxChar*)wxTmemchr(c_str() + nStart, + *other, + nLen - nStart); + + if ( !p ) + return npos; + + while ( p - c_str() + nLenOther <= nLen && wxTmemcmp(p, other, nLenOther) ) + { + p++; + + // anchor again + p = (const wxChar*)wxTmemchr(p, *other, nLen - (p - c_str())); + + if ( !p ) + return npos; + } + + return p - c_str() + nLenOther <= nLen ? p - c_str() : npos; +} + +size_t wxStringBase::find(const wxChar* sz, size_t nStart, size_t n) const +{ + return find(wxStringBase(sz, n), nStart); +} + +size_t wxStringBase::find(wxChar ch, size_t nStart) const +{ + wxASSERT( nStart <= length() ); + + const wxChar *p = (const wxChar*)wxTmemchr(c_str() + nStart, ch, length() - nStart); + + return p == NULL ? npos : p - c_str(); +} + +size_t wxStringBase::rfind(const wxStringBase& str, size_t nStart) const +{ + wxASSERT( str.GetStringData()->IsValid() ); + wxASSERT( nStart == npos || nStart <= length() ); + + if ( length() >= str.length() ) + { + // avoids a corner case later + if ( length() == 0 && str.length() == 0 ) + return 0; + + // "top" is the point where search starts from + size_t top = length() - str.length(); + + if ( nStart == npos ) + nStart = length() - 1; + if ( nStart < top ) + top = nStart; + + const wxChar *cursor = c_str() + top; + do + { + if ( wxTmemcmp(cursor, str.c_str(), + str.length()) == 0 ) + { + return cursor - c_str(); + } + } while ( cursor-- > c_str() ); + } + + return npos; +} + +size_t wxStringBase::rfind(const wxChar* sz, size_t nStart, size_t n) const +{ + return rfind(wxStringBase(sz, n), nStart); +} + +size_t wxStringBase::rfind(wxChar ch, size_t nStart) const +{ + if ( nStart == npos ) + { + nStart = length(); + } + else + { + wxASSERT( nStart <= length() ); + } + + const wxChar *actual; + for ( actual = c_str() + ( nStart == npos ? length() : nStart + 1 ); + actual > c_str(); --actual ) + { + if ( *(actual - 1) == ch ) + return (actual - 1) - c_str(); + } + + return npos; +} + +size_t wxStringBase::find_first_of(const wxChar* sz, size_t nStart) const +{ + wxASSERT(nStart <= length()); + + size_t len = wxStrlen(sz); + + size_t i; + for(i = nStart; i < this->length(); ++i) + { + if (wxTmemchr(sz, *(c_str() + i), len)) + break; + } + + if(i == this->length()) + return npos; + else + return i; +} + +size_t wxStringBase::find_first_of(const wxChar* sz, size_t nStart, + size_t n) const +{ + return find_first_of(wxStringBase(sz, n), nStart); +} + +size_t wxStringBase::find_last_of(const wxChar* sz, size_t nStart) const +{ + if ( nStart == npos ) + { + nStart = length() - 1; + } + else + { + wxASSERT_MSG( nStart <= length(), + _T("invalid index in find_last_of()") ); + } + + size_t len = wxStrlen(sz); + + for ( const wxChar *p = c_str() + nStart; p >= c_str(); --p ) + { + if ( wxTmemchr(sz, *p, len) ) + return p - c_str(); + } + + return npos; +} + +size_t wxStringBase::find_last_of(const wxChar* sz, size_t nStart, + size_t n) const +{ + return find_last_of(wxStringBase(sz, n), nStart); +} + +size_t wxStringBase::find_first_not_of(const wxChar* sz, size_t nStart) const +{ + if ( nStart == npos ) + { + nStart = length(); + } + else + { + wxASSERT( nStart <= length() ); + } + + size_t len = wxStrlen(sz); + + size_t i; + for(i = nStart; i < this->length(); ++i) + { + if (!wxTmemchr(sz, *(c_str() + i), len)) + break; + } + + if(i == this->length()) + return npos; + else + return i; +} + +size_t wxStringBase::find_first_not_of(const wxChar* sz, size_t nStart, + size_t n) const +{ + return find_first_not_of(wxStringBase(sz, n), nStart); +} + +size_t wxStringBase::find_first_not_of(wxChar ch, size_t nStart) const +{ + wxASSERT( nStart <= length() ); + + for ( const wxChar *p = c_str() + nStart; *p; p++ ) + { + if ( *p != ch ) + return p - c_str(); + } + + return npos; +} + +size_t wxStringBase::find_last_not_of(const wxChar* sz, size_t nStart) const +{ + if ( nStart == npos ) + { + nStart = length() - 1; + } + else + { + wxASSERT( nStart <= length() ); + } + + size_t len = wxStrlen(sz); + + for ( const wxChar *p = c_str() + nStart; p >= c_str(); --p ) + { + if ( !wxTmemchr(sz, *p,len) ) + return p - c_str(); + } + + return npos; +} + +size_t wxStringBase::find_last_not_of(const wxChar* sz, size_t nStart, + size_t n) const +{ + return find_last_not_of(wxStringBase(sz, n), nStart); +} + +size_t wxStringBase::find_last_not_of(wxChar ch, size_t nStart) const +{ + if ( nStart == npos ) + { + nStart = length() - 1; + } + else + { + wxASSERT( nStart <= length() ); + } + + for ( const wxChar *p = c_str() + nStart; p >= c_str(); --p ) + { + if ( *p != ch ) + return p - c_str(); + } + + return npos; +} + +wxStringBase& wxStringBase::replace(size_t nStart, size_t nLen, + const wxChar *sz) +{ + wxASSERT_MSG( nStart <= length(), + _T("index out of bounds in wxStringBase::replace") ); + size_t strLen = length() - nStart; + nLen = strLen < nLen ? strLen : nLen; + + wxStringBase strTmp; + strTmp.reserve(length()); // micro optimisation to avoid multiple mem allocs + + //This is kind of inefficient, but its pretty good considering... + //we don't want to use character access operators here because on STL + //it will freeze the reference count of strTmp, which means a deep copy + //at the end when swap is called + // + //Also, we can't use append with the full character pointer and must + //do it manually because this string can contain null characters + for(size_t i1 = 0; i1 < nStart; ++i1) + strTmp.append(1, this->c_str()[i1]); + + //its safe to do the full version here because + //sz must be a normal c string + strTmp.append(sz); + + for(size_t i2 = nStart + nLen; i2 < length(); ++i2) + strTmp.append(1, this->c_str()[i2]); + + swap(strTmp); + return *this; +} + +wxStringBase& wxStringBase::replace(size_t nStart, size_t nLen, + size_t nCount, wxChar ch) +{ + return replace(nStart, nLen, wxStringBase(nCount, ch).c_str()); +} + +wxStringBase& wxStringBase::replace(size_t nStart, size_t nLen, + const wxStringBase& str, + size_t nStart2, size_t nLen2) +{ + return replace(nStart, nLen, str.substr(nStart2, nLen2)); +} + +wxStringBase& wxStringBase::replace(size_t nStart, size_t nLen, + const wxChar* sz, size_t nCount) +{ + return replace(nStart, nLen, wxStringBase(sz, nCount).c_str()); +} + +wxStringBase wxStringBase::substr(size_t nStart, size_t nLen) const +{ + if ( nLen == npos ) + nLen = length() - nStart; + return wxStringBase(*this, nStart, nLen); +} + +// assigns one string to another +wxStringBase& wxStringBase::operator=(const wxStringBase& stringSrc) +{ + wxASSERT( stringSrc.GetStringData()->IsValid() ); + + // don't copy string over itself + if ( m_pchData != stringSrc.m_pchData ) { + if ( stringSrc.GetStringData()->IsEmpty() ) { + Reinit(); + } + else { + // adjust references + GetStringData()->Unlock(); + m_pchData = stringSrc.m_pchData; + GetStringData()->Lock(); + } + } + + return *this; +} + +// assigns a single character +wxStringBase& wxStringBase::operator=(wxChar ch) +{ + if ( !AssignCopy(1, &ch) ) { + wxFAIL_MSG( _T("out of memory in wxStringBase::operator=(wxChar)") ); + } + return *this; +} + +// assigns C string +wxStringBase& wxStringBase::operator=(const wxChar *psz) +{ + if ( !AssignCopy(wxStrlen(psz), psz) ) { + wxFAIL_MSG( _T("out of memory in wxStringBase::operator=(const wxChar *)") ); + } + return *this; +} + +// helper function: does real copy +bool wxStringBase::AssignCopy(size_t nSrcLen, const wxChar *pszSrcData) +{ + if ( nSrcLen == 0 ) { + Reinit(); + } + else { + if ( !AllocBeforeWrite(nSrcLen) ) { + // allocation failure handled by caller + return false; + } + memcpy(m_pchData, pszSrcData, nSrcLen*sizeof(wxChar)); + GetStringData()->nDataLength = nSrcLen; + m_pchData[nSrcLen] = wxT('\0'); + } + return true; +} + +// --------------------------------------------------------------------------- +// string concatenation +// --------------------------------------------------------------------------- + +// add something to this string +bool wxStringBase::ConcatSelf(size_t nSrcLen, const wxChar *pszSrcData, + size_t nMaxLen) +{ + STATISTICS_ADD(SummandLength, nSrcLen); + + nSrcLen = nSrcLen < nMaxLen ? nSrcLen : nMaxLen; + + // concatenating an empty string is a NOP + if ( nSrcLen > 0 ) { + wxStringData *pData = GetStringData(); + size_t nLen = pData->nDataLength; + size_t nNewLen = nLen + nSrcLen; + + // take special care when appending part of this string to itself: the code + // below reallocates our buffer and this invalidates pszSrcData pointer so + // we have to copy it in another temporary string in this case (but avoid + // doing this unnecessarily) + if ( pszSrcData >= m_pchData && pszSrcData < m_pchData + nLen ) + { + wxStringBase tmp(pszSrcData, nSrcLen); + return ConcatSelf(nSrcLen, tmp.m_pchData, nSrcLen); + } + + // alloc new buffer if current is too small + if ( pData->IsShared() ) { + STATISTICS_ADD(ConcatHit, 0); + + // we have to allocate another buffer + wxStringData* pOldData = GetStringData(); + if ( !AllocBuffer(nNewLen) ) { + // allocation failure handled by caller + return false; + } + memcpy(m_pchData, pOldData->data(), nLen*sizeof(wxChar)); + pOldData->Unlock(); + } + else if ( nNewLen > pData->nAllocLength ) { + STATISTICS_ADD(ConcatHit, 0); + + reserve(nNewLen); + // we have to grow the buffer + if ( capacity() < nNewLen ) { + // allocation failure handled by caller + return false; + } + } + else { + STATISTICS_ADD(ConcatHit, 1); + + // the buffer is already big enough + } + + // should be enough space + wxASSERT( nNewLen <= GetStringData()->nAllocLength ); + + // fast concatenation - all is done in our buffer + memcpy(m_pchData + nLen, pszSrcData, nSrcLen*sizeof(wxChar)); + + m_pchData[nNewLen] = wxT('\0'); // put terminating '\0' + GetStringData()->nDataLength = nNewLen; // and fix the length + } + //else: the string to append was empty + return true; +} + +// --------------------------------------------------------------------------- +// simple sub-string extraction +// --------------------------------------------------------------------------- + +// helper function: clone the data attached to this string +bool wxStringBase::AllocCopy(wxString& dest, int nCopyLen, int nCopyIndex) const +{ + if ( nCopyLen == 0 ) { + dest.Init(); + } + else { + if ( !dest.AllocBuffer(nCopyLen) ) { + // allocation failure handled by caller + return false; + } + memcpy(dest.m_pchData, m_pchData + nCopyIndex, nCopyLen*sizeof(wxChar)); + } + return true; +} + +#endif // !wxUSE_STL + +#if !wxUSE_STL || !defined(HAVE_STD_STRING_COMPARE) + +#if !wxUSE_STL + #define STRINGCLASS wxStringBase +#else + #define STRINGCLASS wxString +#endif + +static inline int wxDoCmp(const wxChar* s1, size_t l1, + const wxChar* s2, size_t l2) +{ + if( l1 == l2 ) + return wxTmemcmp(s1, s2, l1); + else if( l1 < l2 ) + { + int ret = wxTmemcmp(s1, s2, l1); + return ret == 0 ? -1 : ret; + } + else + { + int ret = wxTmemcmp(s1, s2, l2); + return ret == 0 ? +1 : ret; + } +} + +int STRINGCLASS::compare(const wxStringBase& str) const +{ + return ::wxDoCmp(data(), length(), str.data(), str.length()); +} + +int STRINGCLASS::compare(size_t nStart, size_t nLen, + const wxStringBase& str) const +{ + wxASSERT(nStart <= length()); + size_type strLen = length() - nStart; + nLen = strLen < nLen ? strLen : nLen; + return ::wxDoCmp(data() + nStart, nLen, str.data(), str.length()); +} + +int STRINGCLASS::compare(size_t nStart, size_t nLen, + const wxStringBase& str, + size_t nStart2, size_t nLen2) const +{ + wxASSERT(nStart <= length()); + wxASSERT(nStart2 <= str.length()); + size_type strLen = length() - nStart, + strLen2 = str.length() - nStart2; + nLen = strLen < nLen ? strLen : nLen; + nLen2 = strLen2 < nLen2 ? strLen2 : nLen2; + return ::wxDoCmp(data() + nStart, nLen, str.data() + nStart2, nLen2); +} + +int STRINGCLASS::compare(const wxChar* sz) const +{ + size_t nLen = wxStrlen(sz); + return ::wxDoCmp(data(), length(), sz, nLen); +} + +int STRINGCLASS::compare(size_t nStart, size_t nLen, + const wxChar* sz, size_t nCount) const +{ + wxASSERT(nStart <= length()); + size_type strLen = length() - nStart; + nLen = strLen < nLen ? strLen : nLen; + if( nCount == npos ) + nCount = wxStrlen(sz); + + return ::wxDoCmp(data() + nStart, nLen, sz, nCount); +} + +#undef STRINGCLASS + +#endif // !wxUSE_STL || !defined(HAVE_STD_STRING_COMPARE) + +// =========================================================================== +// wxString class core +// =========================================================================== + +// --------------------------------------------------------------------------- +// construction and conversion +// --------------------------------------------------------------------------- + +#if wxUSE_UNICODE + +// from multibyte string +wxString::wxString(const char *psz, const wxMBConv& conv, size_t nLength) +{ + // anything to do? + if ( psz && nLength != 0 ) + { + if ( nLength == npos ) + { + nLength = wxNO_LEN; + } + + size_t nLenWide; + wxWCharBuffer wbuf = conv.cMB2WC(psz, nLength, &nLenWide); + + if ( nLenWide ) + assign(wbuf, nLenWide); + } +} + +//Convert wxString in Unicode mode to a multi-byte string +const wxCharBuffer wxString::mb_str(const wxMBConv& conv) const +{ + return conv.cWC2MB(c_str(), length() + 1 /* size, not length */, NULL); +} + +#else // ANSI + +#if wxUSE_WCHAR_T + +// from wide string +wxString::wxString(const wchar_t *pwz, const wxMBConv& conv, size_t nLength) +{ + // anything to do? + if ( pwz && nLength != 0 ) + { + if ( nLength == npos ) + { + nLength = wxNO_LEN; + } + + size_t nLenMB; + wxCharBuffer buf = conv.cWC2MB(pwz, nLength, &nLenMB); + + if ( nLenMB ) + assign(buf, nLenMB); + } +} + +//Converts this string to a wide character string if unicode +//mode is not enabled and wxUSE_WCHAR_T is enabled +const wxWCharBuffer wxString::wc_str(const wxMBConv& conv) const +{ + return conv.cMB2WC(c_str(), length() + 1 /* size, not length */, NULL); +} + +#endif // wxUSE_WCHAR_T + +#endif // Unicode/ANSI + +// shrink to minimal size (releasing extra memory) +bool wxString::Shrink() +{ + wxString tmp(begin(), end()); + swap(tmp); + return tmp.length() == length(); +} + +#if !wxUSE_STL +// get the pointer to writable buffer of (at least) nLen bytes +wxChar *wxString::GetWriteBuf(size_t nLen) +{ + if ( !AllocBeforeWrite(nLen) ) { + // allocation failure handled by caller + return NULL; + } + + wxASSERT( GetStringData()->nRefs == 1 ); + GetStringData()->Validate(false); + + return m_pchData; +} + +// put string back in a reasonable state after GetWriteBuf +void wxString::UngetWriteBuf() +{ + UngetWriteBuf(wxStrlen(m_pchData)); +} + +void wxString::UngetWriteBuf(size_t nLen) +{ + wxStringData * const pData = GetStringData(); + + wxASSERT_MSG( nLen < pData->nAllocLength, _T("buffer overrun") ); + + // the strings we store are always NUL-terminated + pData->data()[nLen] = _T('\0'); + pData->nDataLength = nLen; + pData->Validate(true); +} +#endif // !wxUSE_STL + +// --------------------------------------------------------------------------- +// data access +// --------------------------------------------------------------------------- + +// all functions are inline in string.h + +// --------------------------------------------------------------------------- +// assignment operators +// --------------------------------------------------------------------------- + +#if !wxUSE_UNICODE + +// same as 'signed char' variant +wxString& wxString::operator=(const unsigned char* psz) +{ + *this = (const char *)psz; + return *this; +} + +#if wxUSE_WCHAR_T +wxString& wxString::operator=(const wchar_t *pwz) +{ + wxString str(pwz); + swap(str); + return *this; +} +#endif + +#endif + +/* + * concatenation functions come in 5 flavours: + * string + string + * char + string and string + char + * C str + string and string + C str + */ + +wxString operator+(const wxString& str1, const wxString& str2) +{ +#if !wxUSE_STL + wxASSERT( str1.GetStringData()->IsValid() ); + wxASSERT( str2.GetStringData()->IsValid() ); +#endif + + wxString s = str1; + s += str2; + + return s; +} + +wxString operator+(const wxString& str, wxChar ch) +{ +#if !wxUSE_STL + wxASSERT( str.GetStringData()->IsValid() ); +#endif + + wxString s = str; + s += ch; + + return s; +} + +wxString operator+(wxChar ch, const wxString& str) +{ +#if !wxUSE_STL + wxASSERT( str.GetStringData()->IsValid() ); +#endif + + wxString s = ch; + s += str; + + return s; +} + +wxString operator+(const wxString& str, const wxChar *psz) +{ +#if !wxUSE_STL + wxASSERT( str.GetStringData()->IsValid() ); +#endif + + wxString s; + if ( !s.Alloc(wxStrlen(psz) + str.length()) ) { + wxFAIL_MSG( _T("out of memory in wxString::operator+") ); + } + s += str; + s += psz; + + return s; +} + +wxString operator+(const wxChar *psz, const wxString& str) +{ +#if !wxUSE_STL + wxASSERT( str.GetStringData()->IsValid() ); +#endif + + wxString s; + if ( !s.Alloc(wxStrlen(psz) + str.length()) ) { + wxFAIL_MSG( _T("out of memory in wxString::operator+") ); + } + s = psz; + s += str; + + return s; +} + +// =========================================================================== +// other common string functions +// =========================================================================== + +int wxString::Cmp(const wxString& s) const +{ + return compare(s); +} + +int wxString::Cmp(const wxChar* psz) const +{ + return compare(psz); +} + +static inline int wxDoCmpNoCase(const wxChar* s1, size_t l1, + const wxChar* s2, size_t l2) +{ + size_t i; + + if( l1 == l2 ) + { + for(i = 0; i < l1; ++i) + { + if(wxTolower(s1[i]) != wxTolower(s2[i])) + break; + } + return i == l1 ? 0 : wxTolower(s1[i]) < wxTolower(s2[i]) ? -1 : 1; + } + else if( l1 < l2 ) + { + for(i = 0; i < l1; ++i) + { + if(wxTolower(s1[i]) != wxTolower(s2[i])) + break; + } + return i == l1 ? -1 : wxTolower(s1[i]) < wxTolower(s2[i]) ? -1 : 1; + } + else + { + for(i = 0; i < l2; ++i) + { + if(wxTolower(s1[i]) != wxTolower(s2[i])) + break; + } + return i == l2 ? 1 : wxTolower(s1[i]) < wxTolower(s2[i]) ? -1 : 1; + } +} + +int wxString::CmpNoCase(const wxString& s) const +{ + return wxDoCmpNoCase(data(), length(), s.data(), s.length()); +} + +int wxString::CmpNoCase(const wxChar* psz) const +{ + int nLen = wxStrlen(psz); + + return wxDoCmpNoCase(data(), length(), psz, nLen); +} + + +#if wxUSE_UNICODE + +#ifdef __MWERKS__ +#ifndef __SCHAR_MAX__ +#define __SCHAR_MAX__ 127 +#endif +#endif + +wxString wxString::FromAscii(const char *ascii) +{ + if (!ascii) + return wxEmptyString; + + size_t len = strlen( ascii ); + wxString res; + + if ( len ) + { + wxStringBuffer buf(res, len); + + wchar_t *dest = buf; + + for ( ;; ) + { + if ( (*dest++ = (wchar_t)(unsigned char)*ascii++) == L'\0' ) + break; + } + } + + return res; +} + +wxString wxString::FromAscii(const char ascii) +{ + // What do we do with '\0' ? + + wxString res; + res += (wchar_t)(unsigned char) ascii; + + return res; +} + +const wxCharBuffer wxString::ToAscii() const +{ + // this will allocate enough space for the terminating NUL too + wxCharBuffer buffer(length()); + + + char *dest = buffer.data(); + + const wchar_t *pwc = c_str(); + for ( ;; ) + { + *dest++ = (char)(*pwc > SCHAR_MAX ? wxT('_') : *pwc); + + // the output string can't have embedded NULs anyhow, so we can safely + // stop at first of them even if we do have any + if ( !*pwc++ ) + break; + } + + return buffer; +} + +#endif // Unicode + +// extract string of length nCount starting at nFirst +wxString wxString::Mid(size_t nFirst, size_t nCount) const +{ + size_t nLen = length(); + + // default value of nCount is npos and means "till the end" + if ( nCount == npos ) + { + nCount = nLen - nFirst; + } + + // out-of-bounds requests return sensible things + if ( nFirst + nCount > nLen ) + { + nCount = nLen - nFirst; + } + + if ( nFirst > nLen ) + { + // AllocCopy() will return empty string + return wxEmptyString; + } + + wxString dest(*this, nFirst, nCount); + if ( dest.length() != nCount ) + { + wxFAIL_MSG( _T("out of memory in wxString::Mid") ); + } + + return dest; +} + +// check that the string starts with prefix and return the rest of the string +// in the provided pointer if it is not NULL, otherwise return false +bool wxString::StartsWith(const wxChar *prefix, wxString *rest) const +{ + wxASSERT_MSG( prefix, _T("invalid parameter in wxString::StartsWith") ); + + // first check if the beginning of the string matches the prefix: note + // that we don't have to check that we don't run out of this string as + // when we reach the terminating NUL, either prefix string ends too (and + // then it's ok) or we break out of the loop because there is no match + const wxChar *p = c_str(); + while ( *prefix ) + { + if ( *prefix++ != *p++ ) + { + // no match + return false; + } + } + + if ( rest ) + { + // put the rest of the string into provided pointer + *rest = p; + } + + return true; +} + + +// check that the string ends with suffix and return the rest of it in the +// provided pointer if it is not NULL, otherwise return false +bool wxString::EndsWith(const wxChar *suffix, wxString *rest) const +{ + wxASSERT_MSG( suffix, _T("invalid parameter in wxString::EndssWith") ); + + int start = length() - wxStrlen(suffix); + if ( start < 0 || wxStrcmp(c_str() + start, suffix) != 0 ) + return false; + + if ( rest ) + { + // put the rest of the string into provided pointer + rest->assign(*this, 0, start); + } + + return true; +} + + +// extract nCount last (rightmost) characters +wxString wxString::Right(size_t nCount) const +{ + if ( nCount > length() ) + nCount = length(); + + wxString dest(*this, length() - nCount, nCount); + if ( dest.length() != nCount ) { + wxFAIL_MSG( _T("out of memory in wxString::Right") ); + } + return dest; +} + +// get all characters after the last occurence of ch +// (returns the whole string if ch not found) +wxString wxString::AfterLast(wxChar ch) const +{ + wxString str; + int iPos = Find(ch, true); + if ( iPos == wxNOT_FOUND ) + str = *this; + else + str = c_str() + iPos + 1; + + return str; +} + +// extract nCount first (leftmost) characters +wxString wxString::Left(size_t nCount) const +{ + if ( nCount > length() ) + nCount = length(); + + wxString dest(*this, 0, nCount); + if ( dest.length() != nCount ) { + wxFAIL_MSG( _T("out of memory in wxString::Left") ); + } + return dest; +} + +// get all characters before the first occurence of ch +// (returns the whole string if ch not found) +wxString wxString::BeforeFirst(wxChar ch) const +{ + int iPos = Find(ch); + if ( iPos == wxNOT_FOUND ) iPos = length(); + return wxString(*this, 0, iPos); +} + +/// get all characters before the last occurence of ch +/// (returns empty string if ch not found) +wxString wxString::BeforeLast(wxChar ch) const +{ + wxString str; + int iPos = Find(ch, true); + if ( iPos != wxNOT_FOUND && iPos != 0 ) + str = wxString(c_str(), iPos); + + return str; +} + +/// get all characters after the first occurence of ch +/// (returns empty string if ch not found) +wxString wxString::AfterFirst(wxChar ch) const +{ + wxString str; + int iPos = Find(ch); + if ( iPos != wxNOT_FOUND ) + str = c_str() + iPos + 1; + + return str; +} + +// replace first (or all) occurences of some substring with another one +size_t wxString::Replace(const wxChar *szOld, + const wxChar *szNew, bool bReplaceAll) +{ + // if we tried to replace an empty string we'd enter an infinite loop below + wxCHECK_MSG( szOld && *szOld && szNew, 0, + _T("wxString::Replace(): invalid parameter") ); + + size_t uiCount = 0; // count of replacements made + + size_t uiOldLen = wxStrlen(szOld); + size_t uiNewLen = wxStrlen(szNew); + + size_t dwPos = 0; + + while ( this->c_str()[dwPos] != wxT('\0') ) + { + //DO NOT USE STRSTR HERE + //this string can contain embedded null characters, + //so strstr will function incorrectly + dwPos = find(szOld, dwPos); + if ( dwPos == npos ) + break; // exit the loop + else + { + //replace this occurance of the old string with the new one + replace(dwPos, uiOldLen, szNew, uiNewLen); + + //move up pos past the string that was replaced + dwPos += uiNewLen; + + //increase replace count + ++uiCount; + + // stop now? + if ( !bReplaceAll ) + break; // exit the loop + } + } + + return uiCount; +} + +bool wxString::IsAscii() const +{ + const wxChar *s = (const wxChar*) *this; + while(*s){ + if(!isascii(*s)) return(false); + s++; + } + return(true); +} + +bool wxString::IsWord() const +{ + const wxChar *s = (const wxChar*) *this; + while(*s){ + if(!wxIsalpha(*s)) return(false); + s++; + } + return(true); +} + +bool wxString::IsNumber() const +{ + const wxChar *s = (const wxChar*) *this; + if (wxStrlen(s)) + if ((s[0] == wxT('-')) || (s[0] == wxT('+'))) s++; + while(*s){ + if(!wxIsdigit(*s)) return(false); + s++; + } + return(true); +} + +wxString wxString::Strip(stripType w) const +{ + wxString s = *this; + if ( w & leading ) s.Trim(false); + if ( w & trailing ) s.Trim(true); + return s; +} + +// --------------------------------------------------------------------------- +// case conversion +// --------------------------------------------------------------------------- + +wxString& wxString::MakeUpper() +{ + for ( iterator it = begin(), en = end(); it != en; ++it ) + *it = (wxChar)wxToupper(*it); + + return *this; +} + +wxString& wxString::MakeLower() +{ + for ( iterator it = begin(), en = end(); it != en; ++it ) + *it = (wxChar)wxTolower(*it); + + return *this; +} + +// --------------------------------------------------------------------------- +// trimming and padding +// --------------------------------------------------------------------------- + +// some compilers (VC++ 6.0 not to name them) return true for a call to +// isspace('\xEA') in the C locale which seems to be broken to me, but we have +// to live with this by checking that the character is a 7 bit one - even if +// this may fail to detect some spaces (I don't know if Unicode doesn't have +// space-like symbols somewhere except in the first 128 chars), it is arguably +// still better than trimming away accented letters +inline int wxSafeIsspace(wxChar ch) { return (ch < 127) && wxIsspace(ch); } + +// trims spaces (in the sense of isspace) from left or right side +wxString& wxString::Trim(bool bFromRight) +{ + // first check if we're going to modify the string at all + if ( !empty() && + ( + (bFromRight && wxSafeIsspace(GetChar(length() - 1))) || + (!bFromRight && wxSafeIsspace(GetChar(0u))) + ) + ) + { + if ( bFromRight ) + { + // find last non-space character + reverse_iterator psz = rbegin(); + while ( (psz != rend()) && wxSafeIsspace(*psz) ) + psz++; + + // truncate at trailing space start + erase(psz.base(), end()); + } + else + { + // find first non-space character + iterator psz = begin(); + while ( (psz != end()) && wxSafeIsspace(*psz) ) + psz++; + + // fix up data and length + erase(begin(), psz); + } + } + + return *this; +} + +// adds nCount characters chPad to the string from either side +wxString& wxString::Pad(size_t nCount, wxChar chPad, bool bFromRight) +{ + wxString s(chPad, nCount); + + if ( bFromRight ) + *this += s; + else + { + s += *this; + swap(s); + } + + return *this; +} + +// truncate the string +wxString& wxString::Truncate(size_t uiLen) +{ + if ( uiLen < length() ) + { + erase(begin() + uiLen, end()); + } + //else: nothing to do, string is already short enough + + return *this; +} + +// --------------------------------------------------------------------------- +// finding (return wxNOT_FOUND if not found and index otherwise) +// --------------------------------------------------------------------------- + +// find a character +int wxString::Find(wxChar ch, bool bFromEnd) const +{ + size_type idx = bFromEnd ? find_last_of(ch) : find_first_of(ch); + + return (idx == npos) ? wxNOT_FOUND : (int)idx; +} + +// find a sub-string (like strstr) +int wxString::Find(const wxChar *pszSub) const +{ + size_type idx = find(pszSub); + + return (idx == npos) ? wxNOT_FOUND : (int)idx; +} + +// ---------------------------------------------------------------------------- +// conversion to numbers +// ---------------------------------------------------------------------------- + +// the implementation of all the functions below is exactly the same so factor +// it out + +template +bool wxStringToIntType(const wxChar *start, + T *val, + int base, + F func) +{ + wxCHECK_MSG( val, false, _T("NULL output pointer") ); + wxASSERT_MSG( !base || (base > 1 && base <= 36), _T("invalid base") ); + +#ifndef __WXWINCE__ + errno = 0; +#endif + + wxChar *end; + *val = (*func)(start, &end, base); + + // return true only if scan was stopped by the terminating NUL and if the + // string was not empty to start with and no under/overflow occurred + return !*end && (end != start) +#ifndef __WXWINCE__ + && (errno != ERANGE) +#endif + ; +} + +bool wxString::ToLong(long *val, int base) const +{ + return wxStringToIntType(c_str(), val, base, wxStrtol); +} + +bool wxString::ToULong(unsigned long *val, int base) const +{ + return wxStringToIntType(c_str(), val, base, wxStrtoul); +} + +bool wxString::ToLongLong(wxLongLong_t *val, int base) const +{ +#ifdef wxHAS_STRTOLL + return wxStringToIntType(c_str(), val, base, wxStrtoll); +#else + // TODO: implement this ourselves + wxUnusedVar(val); + wxUnusedVar(base); + return false; +#endif // wxHAS_STRTOLL +} + +bool wxString::ToULongLong(wxULongLong_t *val, int base) const +{ +#ifdef wxHAS_STRTOLL + return wxStringToIntType(c_str(), val, base, wxStrtoull); +#else + // TODO: implement this ourselves + wxUnusedVar(val); + wxUnusedVar(base); + return false; +#endif +} + +bool wxString::ToDouble(double *val) const +{ + wxCHECK_MSG( val, false, _T("NULL pointer in wxString::ToDouble") ); + +#ifndef __WXWINCE__ + errno = 0; +#endif + + const wxChar *start = c_str(); + wxChar *end; + *val = wxStrtod(start, &end); + + // return true only if scan was stopped by the terminating NUL and if the + // string was not empty to start with and no under/overflow occurred + return !*end && (end != start) +#ifndef __WXWINCE__ + && (errno != ERANGE) +#endif + ; +} + +// --------------------------------------------------------------------------- +// formatted output +// --------------------------------------------------------------------------- + +/* static */ +wxString wxString::Format(const wxChar *pszFormat, ...) +{ + va_list argptr; + va_start(argptr, pszFormat); + + wxString s; + s.PrintfV(pszFormat, argptr); + + va_end(argptr); + + return s; +} + +/* static */ +wxString wxString::FormatV(const wxChar *pszFormat, va_list argptr) +{ + wxString s; + s.PrintfV(pszFormat, argptr); + return s; +} + +int wxString::Printf(const wxChar *pszFormat, ...) +{ + va_list argptr; + va_start(argptr, pszFormat); + + int iLen = PrintfV(pszFormat, argptr); + + va_end(argptr); + + return iLen; +} + +/* + Uses wxVsnprintf and places the result into the this string. + + In ANSI build, wxVsnprintf is effectively vsnprintf but in Unicode build + it is vswprintf. Due to a discrepancy between vsnprintf and vswprintf in + the ISO C99 (and thus SUSv3) standard the return value for the case of + an undersized buffer is inconsistent. For conforming vsnprintf + implementations the function must return the number of characters that + would have been printed had the buffer been large enough. For conforming + vswprintf implementations the function must return a negative number + and set errno. + + What vswprintf sets errno to is undefined but Darwin seems to set it to + EOVERFLOW. The only expected errno are EILSEQ and EINVAL. Both of + those are defined in the standard and backed up by several conformance + statements. Note that ENOMEM mentioned in the manual page does not + apply to swprintf, only wprintf and fwprintf. + + Official manual page: + http://www.opengroup.org/onlinepubs/009695399/functions/swprintf.html + + Some conformance statements (AIX, Solaris): + http://www.opengroup.org/csq/view.mhtml?RID=ibm%2FSD1%2F3 + http://www.theopengroup.org/csq/view.mhtml?norationale=1&noreferences=1&RID=Fujitsu%2FSE2%2F10 + + Since EILSEQ and EINVAL are rather common but EOVERFLOW is not and since + EILSEQ and EINVAL are specifically defined to mean the error is other than + an undersized buffer and no other errno are defined we treat those two + as meaning hard errors and everything else gets the old behavior which + is to keep looping and increasing buffer size until the function succeeds. + + In practice it's impossible to determine before compilation which behavior + may be used. The vswprintf function may have vsnprintf-like behavior or + vice-versa. Behavior detected on one release can theoretically change + with an updated release. Not to mention that configure testing for it + would require the test to be run on the host system, not the build system + which makes cross compilation difficult. Therefore, we make no assumptions + about behavior and try our best to handle every known case, including the + case where wxVsnprintf returns a negative number and fails to set errno. + + There is yet one more non-standard implementation and that is our own. + Fortunately, that can be detected at compile-time. + + On top of all that, ISO C99 explicitly defines snprintf to write a null + character to the last position of the specified buffer. That would be at + at the given buffer size minus 1. It is supposed to do this even if it + turns out that the buffer is sized too small. + + Darwin (tested on 10.5) follows the C99 behavior exactly. + + Glibc 2.6 almost follows the C99 behavior except vswprintf never sets + errno even when it fails. However, it only seems to ever fail due + to an undersized buffer. +*/ +int wxString::PrintfV(const wxChar* pszFormat, va_list argptr) +{ + int size = 1024; + + for ( ;; ) + { + // Allocate 1 more character than we tell wxVsnprintf about + // just in case it is buggy. + // FIXME: I have a feeling that the underlying function was not buggy + // and I suspect it was to fix the buf[size] = '\0' line below + wxStringBuffer tmp(*this, size + 1); + wxChar *buf = tmp; + + if ( !buf ) + { + // out of memory + return -1; + } + + // wxVsnprintf() may modify the original arg pointer, so pass it + // only a copy + va_list argptrcopy; + wxVaCopy(argptrcopy, argptr); + +#ifndef __WXWINCE__ + // Set errno to 0 to make it determinate if wxVsnprintf fails to set it. + errno = 0; +#endif + int len = wxVsnprintf(buf, size, pszFormat, argptrcopy); + va_end(argptrcopy); + + // some implementations of vsnprintf() don't NUL terminate + // the string if there is not enough space for it so + // always do it manually + // FIXME: This really seems to be the wrong and would be an off-by-one + // bug except the code above allocates an extra character. + buf[size] = _T('\0'); + + // vsnprintf() may return either -1 (traditional Unix behaviour) or the + // total number of characters which would have been written if the + // buffer were large enough (newer standards such as Unix98) + if ( len < 0 ) + { +#if wxUSE_WXVSNPRINTF + // we know that our own implementation of wxVsnprintf() returns -1 + // only for a format error - thus there's something wrong with + // the user's format string + return -1; +#else // assume that system version only returns error if not enough space +#if !defined(__WXWINCE__) && (!defined(__OS2__) || defined(__INNOTEK_LIBC__)) + if( (errno == EILSEQ) || (errno == EINVAL) ) + // If errno was set to one of the two well-known hard errors + // then fail immediately to avoid an infinite loop. + return -1; + else +#endif // __WXWINCE__ + // still not enough, as we don't know how much we need, double the + // current size of the buffer + size *= 2; +#endif // wxUSE_WXVSNPRINTF/!wxUSE_WXVSNPRINTF + } + else if ( len >= size ) + { +#if wxUSE_WXVSNPRINTF + // we know that our own implementation of wxVsnprintf() returns + // size+1 when there's not enough space but that's not the size + // of the required buffer! + size *= 2; // so we just double the current size of the buffer +#else + // some vsnprintf() implementations NUL-terminate the buffer and + // some don't in len == size case, to be safe always add 1 + // FIXME: I don't quite understand this comment. The vsnprintf + // function is specifically defined to return the number of + // characters printed not including the null terminator. + // So OF COURSE you need to add 1 to get the right buffer size. + // The following line is definitely correct, no question. + size = len + 1; +#endif + } + else // ok, there was enough space + { + break; + } + } + + // we could have overshot + Shrink(); + + return length(); +} + +// ---------------------------------------------------------------------------- +// misc other operations +// ---------------------------------------------------------------------------- + +// returns true if the string matches the pattern which may contain '*' and +// '?' metacharacters (as usual, '?' matches any character and '*' any number +// of them) +bool wxString::Matches(const wxChar *pszMask) const +{ + // I disable this code as it doesn't seem to be faster (in fact, it seems + // to be much slower) than the old, hand-written code below and using it + // here requires always linking with libregex even if the user code doesn't + // use it +#if 0 // wxUSE_REGEX + // first translate the shell-like mask into a regex + wxString pattern; + pattern.reserve(wxStrlen(pszMask)); + + pattern += _T('^'); + while ( *pszMask ) + { + switch ( *pszMask ) + { + case _T('?'): + pattern += _T('.'); + break; + + case _T('*'): + pattern += _T(".*"); + break; + + case _T('^'): + case _T('.'): + case _T('$'): + case _T('('): + case _T(')'): + case _T('|'): + case _T('+'): + case _T('\\'): + // these characters are special in a RE, quote them + // (however note that we don't quote '[' and ']' to allow + // using them for Unix shell like matching) + pattern += _T('\\'); + // fall through + + default: + pattern += *pszMask; + } + + pszMask++; + } + pattern += _T('$'); + + // and now use it + return wxRegEx(pattern, wxRE_NOSUB | wxRE_EXTENDED).Matches(c_str()); +#else // !wxUSE_REGEX + // TODO: this is, of course, awfully inefficient... + + // the char currently being checked + const wxChar *pszTxt = c_str(); + + // the last location where '*' matched + const wxChar *pszLastStarInText = NULL; + const wxChar *pszLastStarInMask = NULL; + +match: + for ( ; *pszMask != wxT('\0'); pszMask++, pszTxt++ ) { + switch ( *pszMask ) { + case wxT('?'): + if ( *pszTxt == wxT('\0') ) + return false; + + // pszTxt and pszMask will be incremented in the loop statement + + break; + + case wxT('*'): + { + // remember where we started to be able to backtrack later + pszLastStarInText = pszTxt; + pszLastStarInMask = pszMask; + + // ignore special chars immediately following this one + // (should this be an error?) + while ( *pszMask == wxT('*') || *pszMask == wxT('?') ) + pszMask++; + + // if there is nothing more, match + if ( *pszMask == wxT('\0') ) + return true; + + // are there any other metacharacters in the mask? + size_t uiLenMask; + const wxChar *pEndMask = wxStrpbrk(pszMask, wxT("*?")); + + if ( pEndMask != NULL ) { + // we have to match the string between two metachars + uiLenMask = pEndMask - pszMask; + } + else { + // we have to match the remainder of the string + uiLenMask = wxStrlen(pszMask); + } + + wxString strToMatch(pszMask, uiLenMask); + const wxChar* pMatch = wxStrstr(pszTxt, strToMatch); + if ( pMatch == NULL ) + return false; + + // -1 to compensate "++" in the loop + pszTxt = pMatch + uiLenMask - 1; + pszMask += uiLenMask - 1; + } + break; + + default: + if ( *pszMask != *pszTxt ) + return false; + break; + } + } + + // match only if nothing left + if ( *pszTxt == wxT('\0') ) + return true; + + // if we failed to match, backtrack if we can + if ( pszLastStarInText ) { + pszTxt = pszLastStarInText + 1; + pszMask = pszLastStarInMask; + + pszLastStarInText = NULL; + + // don't bother resetting pszLastStarInMask, it's unnecessary + + goto match; + } + + return false; +#endif // wxUSE_REGEX/!wxUSE_REGEX +} + +// Count the number of chars +int wxString::Freq(wxChar ch) const +{ + int count = 0; + int len = length(); + for (int i = 0; i < len; i++) + { + if (GetChar(i) == ch) + count ++; + } + return count; +} + +// convert to upper case, return the copy of the string +wxString wxString::Upper() const +{ wxString s(*this); return s.MakeUpper(); } + +// convert to lower case, return the copy of the string +wxString wxString::Lower() const { wxString s(*this); return s.MakeLower(); } + +int wxString::sprintf(const wxChar *pszFormat, ...) + { + va_list argptr; + va_start(argptr, pszFormat); + int iLen = PrintfV(pszFormat, argptr); + va_end(argptr); + return iLen; + } + +// ============================================================================ +// ArrayString +// ============================================================================ + +#include "wx/arrstr.h" + +wxArrayString::wxArrayString(size_t sz, const wxChar** a) +{ +#if !wxUSE_STL + Init(false); +#endif + for (size_t i=0; i < sz; i++) + Add(a[i]); +} + +wxArrayString::wxArrayString(size_t sz, const wxString* a) +{ +#if !wxUSE_STL + Init(false); +#endif + for (size_t i=0; i < sz; i++) + Add(a[i]); +} + +#if !wxUSE_STL + +// size increment = min(50% of current size, ARRAY_MAXSIZE_INCREMENT) +#define ARRAY_MAXSIZE_INCREMENT 4096 + +#ifndef ARRAY_DEFAULT_INITIAL_SIZE // also defined in dynarray.h +#define ARRAY_DEFAULT_INITIAL_SIZE (16) +#endif + +#define STRING(p) ((wxString *)(&(p))) + +// ctor +void wxArrayString::Init(bool autoSort) +{ + m_nSize = + m_nCount = 0; + m_pItems = (wxChar **) NULL; + m_autoSort = autoSort; +} + +// copy ctor +wxArrayString::wxArrayString(const wxArrayString& src) +{ + Init(src.m_autoSort); + + *this = src; +} + +// assignment operator +wxArrayString& wxArrayString::operator=(const wxArrayString& src) +{ + if ( m_nSize > 0 ) + Clear(); + + Copy(src); + + m_autoSort = src.m_autoSort; + + return *this; +} + +void wxArrayString::Copy(const wxArrayString& src) +{ + if ( src.m_nCount > ARRAY_DEFAULT_INITIAL_SIZE ) + Alloc(src.m_nCount); + + for ( size_t n = 0; n < src.m_nCount; n++ ) + Add(src[n]); +} + +// grow the array +void wxArrayString::Grow(size_t nIncrement) +{ + // only do it if no more place + if ( (m_nSize - m_nCount) < nIncrement ) { + // if ARRAY_DEFAULT_INITIAL_SIZE were set to 0, the initially empty would + // be never resized! + #if ARRAY_DEFAULT_INITIAL_SIZE == 0 + #error "ARRAY_DEFAULT_INITIAL_SIZE must be > 0!" + #endif + + if ( m_nSize == 0 ) { + // was empty, alloc some memory + m_nSize = ARRAY_DEFAULT_INITIAL_SIZE; + if (m_nSize < nIncrement) + m_nSize = nIncrement; + m_pItems = new wxChar *[m_nSize]; + } + else { + // otherwise when it's called for the first time, nIncrement would be 0 + // and the array would never be expanded + // add 50% but not too much + size_t ndefIncrement = m_nSize < ARRAY_DEFAULT_INITIAL_SIZE + ? ARRAY_DEFAULT_INITIAL_SIZE : m_nSize >> 1; + if ( ndefIncrement > ARRAY_MAXSIZE_INCREMENT ) + ndefIncrement = ARRAY_MAXSIZE_INCREMENT; + if ( nIncrement < ndefIncrement ) + nIncrement = ndefIncrement; + m_nSize += nIncrement; + wxChar **pNew = new wxChar *[m_nSize]; + + // copy data to new location + memcpy(pNew, m_pItems, m_nCount*sizeof(wxChar *)); + + // delete old memory (but do not release the strings!) + wxDELETEA(m_pItems); + + m_pItems = pNew; + } + } +} + +void wxArrayString::Free() +{ + for ( size_t n = 0; n < m_nCount; n++ ) { + STRING(m_pItems[n])->GetStringData()->Unlock(); + } +} + +// deletes all the strings from the list +void wxArrayString::Empty() +{ + Free(); + + m_nCount = 0; +} + +// as Empty, but also frees memory +void wxArrayString::Clear() +{ + Free(); + + m_nSize = + m_nCount = 0; + + wxDELETEA(m_pItems); +} + +// dtor +wxArrayString::~wxArrayString() +{ + Free(); + + wxDELETEA(m_pItems); +} + +void wxArrayString::reserve(size_t nSize) +{ + Alloc(nSize); +} + +// pre-allocates memory (frees the previous data!) +void wxArrayString::Alloc(size_t nSize) +{ + // only if old buffer was not big enough + if ( nSize > m_nSize ) { + wxChar **pNew = new wxChar *[nSize]; + if ( !pNew ) + return; + + memcpy(pNew, m_pItems, m_nCount*sizeof(wxChar *)); + delete [] m_pItems; + + m_pItems = pNew; + m_nSize = nSize; + } +} + +// minimizes the memory usage by freeing unused memory +void wxArrayString::Shrink() +{ + // only do it if we have some memory to free + if( m_nCount < m_nSize ) { + // allocates exactly as much memory as we need + wxChar **pNew = new wxChar *[m_nCount]; + + // copy data to new location + memcpy(pNew, m_pItems, m_nCount*sizeof(wxChar *)); + delete [] m_pItems; + m_pItems = pNew; + } +} + +#if WXWIN_COMPATIBILITY_2_4 + +// return a wxString[] as required for some control ctors. +wxString* wxArrayString::GetStringArray() const +{ + wxString *array = 0; + + if( m_nCount > 0 ) + { + array = new wxString[m_nCount]; + for( size_t i = 0; i < m_nCount; i++ ) + array[i] = m_pItems[i]; + } + + return array; +} + +void wxArrayString::Remove(size_t nIndex, size_t nRemove) +{ + RemoveAt(nIndex, nRemove); +} + +#endif // WXWIN_COMPATIBILITY_2_4 + +// searches the array for an item (forward or backwards) +int wxArrayString::Index(const wxChar *sz, bool bCase, bool bFromEnd) const +{ + if ( m_autoSort ) { + // use binary search in the sorted array + wxASSERT_MSG( bCase && !bFromEnd, + wxT("search parameters ignored for auto sorted array") ); + + size_t i, + lo = 0, + hi = m_nCount; + int res; + while ( lo < hi ) { + i = (lo + hi)/2; + + res = wxStrcmp(sz, m_pItems[i]); + if ( res < 0 ) + hi = i; + else if ( res > 0 ) + lo = i + 1; + else + return i; + } + + return wxNOT_FOUND; + } + else { + // use linear search in unsorted array + if ( bFromEnd ) { + if ( m_nCount > 0 ) { + size_t ui = m_nCount; + do { + if ( STRING(m_pItems[--ui])->IsSameAs(sz, bCase) ) + return ui; + } + while ( ui != 0 ); + } + } + else { + for( size_t ui = 0; ui < m_nCount; ui++ ) { + if( STRING(m_pItems[ui])->IsSameAs(sz, bCase) ) + return ui; + } + } + } + + return wxNOT_FOUND; +} + +// add item at the end +size_t wxArrayString::Add(const wxString& str, size_t nInsert) +{ + if ( m_autoSort ) { + // insert the string at the correct position to keep the array sorted + size_t i, + lo = 0, + hi = m_nCount; + int res; + while ( lo < hi ) { + i = (lo + hi)/2; + + res = str.Cmp(m_pItems[i]); + if ( res < 0 ) + hi = i; + else if ( res > 0 ) + lo = i + 1; + else { + lo = hi = i; + break; + } + } + + wxASSERT_MSG( lo == hi, wxT("binary search broken") ); + + Insert(str, lo, nInsert); + + return (size_t)lo; + } + else { + wxASSERT( str.GetStringData()->IsValid() ); + + Grow(nInsert); + + for (size_t i = 0; i < nInsert; i++) + { + // the string data must not be deleted! + str.GetStringData()->Lock(); + + // just append + m_pItems[m_nCount + i] = (wxChar *)str.c_str(); // const_cast + } + size_t ret = m_nCount; + m_nCount += nInsert; + return ret; + } +} + +// add item at the given position +void wxArrayString::Insert(const wxString& str, size_t nIndex, size_t nInsert) +{ + wxASSERT( str.GetStringData()->IsValid() ); + + wxCHECK_RET( nIndex <= m_nCount, wxT("bad index in wxArrayString::Insert") ); + wxCHECK_RET( m_nCount <= m_nCount + nInsert, + wxT("array size overflow in wxArrayString::Insert") ); + + Grow(nInsert); + + memmove(&m_pItems[nIndex + nInsert], &m_pItems[nIndex], + (m_nCount - nIndex)*sizeof(wxChar *)); + + for (size_t i = 0; i < nInsert; i++) + { + str.GetStringData()->Lock(); + m_pItems[nIndex + i] = (wxChar *)str.c_str(); + } + m_nCount += nInsert; +} + +// range insert (STL 23.2.4.3) +void +wxArrayString::insert(iterator it, const_iterator first, const_iterator last) +{ + const int idx = it - begin(); + + // grow it once + Grow(last - first); + + // reset "it" since it can change inside Grow() + it = begin() + idx; + + while ( first != last ) + { + it = insert(it, *first); + + // insert returns an iterator to the last element inserted but we need + // insert the next after this one, that is before the next one + ++it; + + ++first; + } +} + +// expand the array +void wxArrayString::SetCount(size_t count) +{ + Alloc(count); + + wxString s; + while ( m_nCount < count ) + m_pItems[m_nCount++] = (wxChar *)s.c_str(); +} + +// removes item from array (by index) +void wxArrayString::RemoveAt(size_t nIndex, size_t nRemove) +{ + wxCHECK_RET( nIndex < m_nCount, wxT("bad index in wxArrayString::Remove") ); + wxCHECK_RET( nIndex + nRemove <= m_nCount, + wxT("removing too many elements in wxArrayString::Remove") ); + + // release our lock + for (size_t i = 0; i < nRemove; i++) + Item(nIndex + i).GetStringData()->Unlock(); + + memmove(&m_pItems[nIndex], &m_pItems[nIndex + nRemove], + (m_nCount - nIndex - nRemove)*sizeof(wxChar *)); + m_nCount -= nRemove; +} + +// removes item from array (by value) +void wxArrayString::Remove(const wxChar *sz) +{ + int iIndex = Index(sz); + + wxCHECK_RET( iIndex != wxNOT_FOUND, + wxT("removing inexistent element in wxArrayString::Remove") ); + + RemoveAt(iIndex); +} + +void wxArrayString::assign(const_iterator first, const_iterator last) +{ + reserve(last - first); + for(; first != last; ++first) + push_back(*first); +} + +// ---------------------------------------------------------------------------- +// sorting +// ---------------------------------------------------------------------------- + +// we can only sort one array at a time with the quick-sort based +// implementation +#if wxUSE_THREADS + // need a critical section to protect access to gs_compareFunction and + // gs_sortAscending variables + static wxCriticalSection gs_critsectStringSort; +#endif // wxUSE_THREADS + +// function to use for string comparaison +static wxArrayString::CompareFunction gs_compareFunction = NULL; + +// if we don't use the compare function, this flag tells us if we sort the +// array in ascending or descending order +static bool gs_sortAscending = true; + +// function which is called by quick sort +extern "C" int wxC_CALLING_CONV // LINKAGEMODE +wxStringCompareFunction(const void *first, const void *second) +{ + wxString *strFirst = (wxString *)first; + wxString *strSecond = (wxString *)second; + + if ( gs_compareFunction ) { + return gs_compareFunction(*strFirst, *strSecond); + } + else { + // maybe we should use wxStrcoll + int result = strFirst->Cmp(*strSecond); + + return gs_sortAscending ? result : -result; + } +} + +// sort array elements using passed comparaison function +void wxArrayString::Sort(CompareFunction compareFunction) +{ + wxCRIT_SECT_LOCKER(lockCmpFunc, gs_critsectStringSort); + + wxASSERT( !gs_compareFunction ); // must have been reset to NULL + gs_compareFunction = compareFunction; + + DoSort(); + + // reset it to NULL so that Sort(bool) will work the next time + gs_compareFunction = NULL; +} + +extern "C" +{ + typedef int (wxC_CALLING_CONV * wxStringCompareFn)(const void *first, + const void *second); +} + +void wxArrayString::Sort(CompareFunction2 compareFunction) +{ + qsort(m_pItems, m_nCount, sizeof(wxChar *), (wxStringCompareFn)compareFunction); +} + +void wxArrayString::Sort(bool reverseOrder) +{ + Sort(reverseOrder ? wxStringSortDescending : wxStringSortAscending); +} + +void wxArrayString::DoSort() +{ + wxCHECK_RET( !m_autoSort, wxT("can't use this method with sorted arrays") ); + + // just sort the pointers using qsort() - of course it only works because + // wxString() *is* a pointer to its data + qsort(m_pItems, m_nCount, sizeof(wxChar *), wxStringCompareFunction); +} + +bool wxArrayString::operator==(const wxArrayString& a) const +{ + if ( m_nCount != a.m_nCount ) + return false; + + for ( size_t n = 0; n < m_nCount; n++ ) + { + if ( Item(n) != a[n] ) + return false; + } + + return true; +} + +#endif // !wxUSE_STL + +int wxCMPFUNC_CONV wxStringSortAscending(wxString* s1, wxString* s2) +{ + return s1->Cmp(*s2); +} + +int wxCMPFUNC_CONV wxStringSortDescending(wxString* s1, wxString* s2) +{ + return -s1->Cmp(*s2); +} diff --git a/Externals/wxWidgets/src/common/sysopt.cpp b/Externals/wxWidgets/src/common/sysopt.cpp index 93a5039660..7a61ad01b7 100644 --- a/Externals/wxWidgets/src/common/sysopt.cpp +++ b/Externals/wxWidgets/src/common/sysopt.cpp @@ -1,111 +1,111 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/sysopt.cpp -// Purpose: wxSystemOptions -// Author: Julian Smart -// Modified by: -// Created: 2001-07-10 -// RCS-ID: $Id: sysopt.cpp 39851 2006-06-27 14:33:14Z VZ $ -// Copyright: (c) Julian Smart -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// --------------------------------------------------------------------------- -// headers -// --------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#if defined(__BORLANDC__) - #pragma hdrstop -#endif - -#if wxUSE_SYSTEM_OPTIONS - -#include "wx/sysopt.h" - -#ifndef WX_PRECOMP - #include "wx/app.h" - #include "wx/list.h" - #include "wx/string.h" - #include "wx/arrstr.h" -#endif - -// ---------------------------------------------------------------------------- -// private globals -// ---------------------------------------------------------------------------- - -static wxArrayString gs_optionNames, - gs_optionValues; - -// ============================================================================ -// wxSystemOptions implementation -// ============================================================================ - -// Option functions (arbitrary name/value mapping) -void wxSystemOptions::SetOption(const wxString& name, const wxString& value) -{ - int idx = gs_optionNames.Index(name, false); - if (idx == wxNOT_FOUND) - { - gs_optionNames.Add(name); - gs_optionValues.Add(value); - } - else - { - gs_optionNames[idx] = name; - gs_optionValues[idx] = value; - } -} - -void wxSystemOptions::SetOption(const wxString& name, int value) -{ - SetOption(name, wxString::Format(wxT("%d"), value)); -} - -wxString wxSystemOptions::GetOption(const wxString& name) -{ - wxString val; - - int idx = gs_optionNames.Index(name, false); - if ( idx != wxNOT_FOUND ) - { - val = gs_optionValues[idx]; - } - else // not set explicitely - { - // look in the environment: first for a variable named "wx_appname_name" - // which can be set to affect the behaviour or just this application - // and then for "wx_name" which can be set to change the option globally - wxString var(name); - var.Replace(_T("."), _T("_")); // '.'s not allowed in env var names - - wxString appname; - if ( wxTheApp ) - appname = wxTheApp->GetAppName(); - - if ( !appname.empty() ) - val = wxGetenv(_T("wx_") + appname + _T('_') + var); - - if ( val.empty() ) - val = wxGetenv(_T("wx_") + var); - } - - return val; -} - -int wxSystemOptions::GetOptionInt(const wxString& name) -{ - return wxAtoi(GetOption(name)); -} - -bool wxSystemOptions::HasOption(const wxString& name) -{ - return !GetOption(name).empty(); -} - -#endif // wxUSE_SYSTEM_OPTIONS +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/sysopt.cpp +// Purpose: wxSystemOptions +// Author: Julian Smart +// Modified by: +// Created: 2001-07-10 +// RCS-ID: $Id: sysopt.cpp 39851 2006-06-27 14:33:14Z VZ $ +// Copyright: (c) Julian Smart +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// --------------------------------------------------------------------------- +// headers +// --------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#if defined(__BORLANDC__) + #pragma hdrstop +#endif + +#if wxUSE_SYSTEM_OPTIONS + +#include "wx/sysopt.h" + +#ifndef WX_PRECOMP + #include "wx/app.h" + #include "wx/list.h" + #include "wx/string.h" + #include "wx/arrstr.h" +#endif + +// ---------------------------------------------------------------------------- +// private globals +// ---------------------------------------------------------------------------- + +static wxArrayString gs_optionNames, + gs_optionValues; + +// ============================================================================ +// wxSystemOptions implementation +// ============================================================================ + +// Option functions (arbitrary name/value mapping) +void wxSystemOptions::SetOption(const wxString& name, const wxString& value) +{ + int idx = gs_optionNames.Index(name, false); + if (idx == wxNOT_FOUND) + { + gs_optionNames.Add(name); + gs_optionValues.Add(value); + } + else + { + gs_optionNames[idx] = name; + gs_optionValues[idx] = value; + } +} + +void wxSystemOptions::SetOption(const wxString& name, int value) +{ + SetOption(name, wxString::Format(wxT("%d"), value)); +} + +wxString wxSystemOptions::GetOption(const wxString& name) +{ + wxString val; + + int idx = gs_optionNames.Index(name, false); + if ( idx != wxNOT_FOUND ) + { + val = gs_optionValues[idx]; + } + else // not set explicitely + { + // look in the environment: first for a variable named "wx_appname_name" + // which can be set to affect the behaviour or just this application + // and then for "wx_name" which can be set to change the option globally + wxString var(name); + var.Replace(_T("."), _T("_")); // '.'s not allowed in env var names + + wxString appname; + if ( wxTheApp ) + appname = wxTheApp->GetAppName(); + + if ( !appname.empty() ) + val = wxGetenv(_T("wx_") + appname + _T('_') + var); + + if ( val.empty() ) + val = wxGetenv(_T("wx_") + var); + } + + return val; +} + +int wxSystemOptions::GetOptionInt(const wxString& name) +{ + return wxAtoi(GetOption(name)); +} + +bool wxSystemOptions::HasOption(const wxString& name) +{ + return !GetOption(name).empty(); +} + +#endif // wxUSE_SYSTEM_OPTIONS diff --git a/Externals/wxWidgets/src/common/tarstrm.cpp b/Externals/wxWidgets/src/common/tarstrm.cpp index 2a9693c554..c07f29ccae 100644 --- a/Externals/wxWidgets/src/common/tarstrm.cpp +++ b/Externals/wxWidgets/src/common/tarstrm.cpp @@ -1,1529 +1,1529 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: tarstrm.cpp -// Purpose: Streams for Tar files -// Author: Mike Wetherell -// RCS-ID: $Id: tarstrm.cpp 53248 2008-04-17 17:29:22Z MW $ -// Copyright: (c) 2004 Mike Wetherell -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_TARSTREAM - -#include "wx/tarstrm.h" - -#ifndef WX_PRECOMP - #include "wx/intl.h" - #include "wx/log.h" - #include "wx/utils.h" -#endif - -#include "wx/buffer.h" -#include "wx/datetime.h" -#include "wx/ptr_scpd.h" -#include "wx/filename.h" -#include "wx/thread.h" - -#include - -#ifdef __UNIX__ -#include -#include -#endif - - -///////////////////////////////////////////////////////////////////////////// -// constants - -enum { - TAR_NAME, - TAR_MODE, - TAR_UID, - TAR_GID, - TAR_SIZE, - TAR_MTIME, - TAR_CHKSUM, - TAR_TYPEFLAG, - TAR_LINKNAME, - TAR_MAGIC, - TAR_VERSION, - TAR_UNAME, - TAR_GNAME, - TAR_DEVMAJOR, - TAR_DEVMINOR, - TAR_PREFIX, - TAR_UNUSED, - TAR_NUMFIELDS -}; - -enum { - TAR_BLOCKSIZE = 512 -}; - -// checksum type -enum { - SUM_UNKNOWN, - SUM_UNSIGNED, - SUM_SIGNED -}; - -// type of input tar -enum { - TYPE_OLDTAR, // fields after TAR_LINKNAME are invalid - TYPE_GNUTAR, // all fields except TAR_PREFIX are valid - TYPE_USTAR // all fields are valid -}; - -// signatures -static const char *USTAR_MAGIC = "ustar"; -static const char *USTAR_VERSION = "00"; -static const char *GNU_MAGIC = "ustar "; -static const char *GNU_VERION = " "; - -IMPLEMENT_DYNAMIC_CLASS(wxTarEntry, wxArchiveEntry) -IMPLEMENT_DYNAMIC_CLASS(wxTarClassFactory, wxArchiveClassFactory) - - -///////////////////////////////////////////////////////////////////////////// -// Class factory - -static wxTarClassFactory g_wxTarClassFactory; - -wxTarClassFactory::wxTarClassFactory() -{ - if (this == &g_wxTarClassFactory) - PushFront(); -} - -const wxChar * const * -wxTarClassFactory::GetProtocols(wxStreamProtocolType type) const -{ - static const wxChar *protocols[] = { _T("tar"), NULL }; - static const wxChar *mimetypes[] = { _T("application/x-tar"), NULL }; - static const wxChar *fileexts[] = { _T(".tar"), NULL }; - static const wxChar *empty[] = { NULL }; - - switch (type) { - case wxSTREAM_PROTOCOL: return protocols; - case wxSTREAM_MIMETYPE: return mimetypes; - case wxSTREAM_FILEEXT: return fileexts; - default: return empty; - } -} - - -///////////////////////////////////////////////////////////////////////////// -// tar header block - -typedef wxFileOffset wxTarNumber; - -struct wxTarField { const wxChar *name; int pos; }; - -class wxTarHeaderBlock -{ -public: - wxTarHeaderBlock() - { memset(data, 0, sizeof(data)); } - wxTarHeaderBlock(const wxTarHeaderBlock& hb) - { memcpy(data, hb.data, sizeof(data)); } - - bool Read(wxInputStream& in); - bool Write(wxOutputStream& out); - inline bool WriteField(wxOutputStream& out, int id); - - bool IsAllZeros() const; - wxUint32 Sum(bool SignedSum = false); - wxUint32 SumField(int id); - - char *Get(int id) { return data + fields[id].pos + id; } - static size_t Len(int id) { return fields[id + 1].pos - fields[id].pos; } - static const wxChar *Name(int id) { return fields[id].name; } - static size_t Offset(int id) { return fields[id].pos; } - - bool SetOctal(int id, wxTarNumber n); - wxTarNumber GetOctal(int id); - bool SetPath(const wxString& name, wxMBConv& conv); - -private: - char data[TAR_BLOCKSIZE + TAR_NUMFIELDS]; - static const wxTarField fields[]; - static void check(); -}; - -wxDEFINE_SCOPED_PTR_TYPE(wxTarHeaderBlock) - -// A table giving the field names and offsets in a tar header block -const wxTarField wxTarHeaderBlock::fields[] = -{ - { _T("name"), 0 }, // 100 - { _T("mode"), 100 }, // 8 - { _T("uid"), 108 }, // 8 - { _T("gid"), 116 }, // 8 - { _T("size"), 124 }, // 12 - { _T("mtime"), 136 }, // 12 - { _T("chksum"), 148 }, // 8 - { _T("typeflag"), 156 }, // 1 - { _T("linkname"), 157 }, // 100 - { _T("magic"), 257 }, // 6 - { _T("version"), 263 }, // 2 - { _T("uname"), 265 }, // 32 - { _T("gname"), 297 }, // 32 - { _T("devmajor"), 329 }, // 8 - { _T("devminor"), 337 }, // 8 - { _T("prefix"), 345 }, // 155 - { _T("unused"), 500 }, // 12 - { NULL, TAR_BLOCKSIZE } -}; - -void wxTarHeaderBlock::check() -{ -#if 0 - wxCOMPILE_TIME_ASSERT( - WXSIZEOF(fields) == TAR_NUMFIELDS + 1, - Wrong_number_of_elements_in_fields_table - ); -#endif -} - -bool wxTarHeaderBlock::IsAllZeros() const -{ - const char *p = data; - for (size_t i = 0; i < sizeof(data); i++) - if (p[i]) - return false; - return true; -} - -wxUint32 wxTarHeaderBlock::Sum(bool SignedSum /*=false*/) -{ - // the chksum field itself should be blanks during the calculation - memset(Get(TAR_CHKSUM), ' ', Len(TAR_CHKSUM)); - const char *p = data; - wxUint32 n = 0; - - if (SignedSum) - for (size_t i = 0; i < sizeof(data); i++) - n += (signed char)p[i]; - else - for (size_t i = 0; i < sizeof(data); i++) - n += (unsigned char)p[i]; - - return n; -} - -wxUint32 wxTarHeaderBlock::SumField(int id) -{ - unsigned char *p = (unsigned char*)Get(id); - unsigned char *q = p + Len(id); - wxUint32 n = 0; - - while (p < q) - n += *p++; - - return n; -} - -bool wxTarHeaderBlock::Read(wxInputStream& in) -{ - bool ok = true; - - for (int id = 0; id < TAR_NUMFIELDS && ok; id++) - ok = in.Read(Get(id), Len(id)).LastRead() == Len(id); - - return ok; -} - -bool wxTarHeaderBlock::Write(wxOutputStream& out) -{ - bool ok = true; - - for (int id = 0; id < TAR_NUMFIELDS && ok; id++) - ok = WriteField(out, id); - - return ok; -} - -inline bool wxTarHeaderBlock::WriteField(wxOutputStream& out, int id) -{ - return out.Write(Get(id), Len(id)).LastWrite() == Len(id); -} - -wxTarNumber wxTarHeaderBlock::GetOctal(int id) -{ - wxTarNumber n = 0; - const char *p = Get(id); - while (*p == ' ') - p++; - while (*p >= '0' && *p < '8') - n = (n << 3) | (*p++ - '0'); - return n; -} - -bool wxTarHeaderBlock::SetOctal(int id, wxTarNumber n) -{ - // set an octal field, return true if the number fits - char *field = Get(id); - char *p = field + Len(id); - *--p = 0; - while (p > field) { - *--p = char('0' + (n & 7)); - n >>= 3; - } - return n == 0; -} - -bool wxTarHeaderBlock::SetPath(const wxString& name, wxMBConv& conv) -{ - bool badconv = false; - -#if wxUSE_UNICODE - wxCharBuffer nameBuf = name.mb_str(conv); - - // if the conversion fails make an approximation - if (!nameBuf) { - badconv = true; - size_t len = name.length(); - wxCharBuffer approx(len); - for (size_t i = 0; i < len; i++) - approx.data()[i] = name[i] & ~0x7F ? '_' : name[i]; - nameBuf = approx; - } - - const char *mbName = nameBuf; -#else - const char *mbName = name.c_str(); - (void)conv; -#endif - - bool fits; - bool notGoingToFit = false; - size_t len = strlen(mbName); - size_t maxname = Len(TAR_NAME); - size_t maxprefix = Len(TAR_PREFIX); - size_t i = 0; - size_t nexti = 0; - - for (;;) { - fits = i < maxprefix && len - i <= maxname; - - if (!fits) { - const char *p = strchr(mbName + i, '/'); - if (p) - nexti = p - mbName + 1; - if (!p || nexti - 1 > maxprefix) - notGoingToFit = true; - } - - if (fits || notGoingToFit) { - strncpy(Get(TAR_NAME), mbName + i, maxname); - if (i > 0) - strncpy(Get(TAR_PREFIX), mbName, i - 1); - break; - } - - i = nexti; - } - - return fits && !badconv; -} - - -///////////////////////////////////////////////////////////////////////////// -// Some helpers - -static wxFileOffset RoundUpSize(wxFileOffset size, int factor = 1) -{ - wxFileOffset chunk = TAR_BLOCKSIZE * factor; - return ((size + chunk - 1) / chunk) * chunk; -} - -#ifdef __UNIX__ - -static wxString wxTarUserName(int uid) -{ - struct passwd *ppw; - -#ifdef HAVE_GETPWUID_R -#if defined HAVE_SYSCONF && defined _SC_GETPW_R_SIZE_MAX - long pwsize = sysconf(_SC_GETPW_R_SIZE_MAX); - size_t bufsize(wxMin(wxMax(1024l, pwsize), 32768l)); -#else - size_t bufsize = 1024; -#endif - wxCharBuffer buf(bufsize); - struct passwd pw; - - memset(&pw, 0, sizeof(pw)); - if (getpwuid_r(uid, &pw, buf.data(), bufsize, &ppw) == 0 && pw.pw_name) - return wxString(pw.pw_name, wxConvLibc); -#else - if ((ppw = getpwuid(uid)) != NULL) - return wxString(ppw->pw_name, wxConvLibc); -#endif - return _("unknown"); -} - -static wxString wxTarGroupName(int gid) -{ - struct group *pgr; -#ifdef HAVE_GETGRGID_R -#if defined HAVE_SYSCONF && defined _SC_GETGR_R_SIZE_MAX - long grsize = sysconf(_SC_GETGR_R_SIZE_MAX); - size_t bufsize(wxMin(wxMax(1024l, grsize), 32768l)); -#else - size_t bufsize = 1024; -#endif - wxCharBuffer buf(bufsize); - struct group gr; - - memset(&gr, 0, sizeof(gr)); - if (getgrgid_r(gid, &gr, buf.data(), bufsize, &pgr) == 0 && gr.gr_name) - return wxString(gr.gr_name, wxConvLibc); -#else - if ((pgr = getgrgid(gid)) != NULL) - return wxString(pgr->gr_name, wxConvLibc); -#endif - return _("unknown"); -} - -#endif // __UNIX__ - -// Cache the user and group names since getting them can be expensive, -// get both names and ids at the same time. -// -struct wxTarUser -{ - wxTarUser(); - ~wxTarUser() { delete [] uname; delete [] gname; } - - int uid; - int gid; - - wxChar *uname; - wxChar *gname; -}; - -wxTarUser::wxTarUser() -{ -#ifdef __UNIX__ - uid = getuid(); - gid = getgid(); - wxString usr = wxTarUserName(uid); - wxString grp = wxTarGroupName(gid); -#else - uid = 0; - gid = 0; - wxString usr = wxGetUserId(); - wxString grp = _("unknown"); -#endif - - uname = new wxChar[usr.length() + 1]; - wxStrcpy(uname, usr.c_str()); - - gname = new wxChar[grp.length() + 1]; - wxStrcpy(gname, grp.c_str()); -} - -static const wxTarUser& wxGetTarUser() -{ -#if wxUSE_THREADS - static wxCriticalSection cs; - wxCriticalSectionLocker lock(cs); -#endif - static wxTarUser tu; - return tu; -} - -// ignore the size field for entry types 3, 4, 5 and 6 -// -static inline wxFileOffset GetDataSize(const wxTarEntry& entry) -{ - switch (entry.GetTypeFlag()) { - case wxTAR_CHRTYPE: - case wxTAR_BLKTYPE: - case wxTAR_DIRTYPE: - case wxTAR_FIFOTYPE: - return 0; - default: - return entry.GetSize(); - } -} - - -///////////////////////////////////////////////////////////////////////////// -// Tar Entry -// Holds all the meta-data for a file in the tar - -wxTarEntry::wxTarEntry(const wxString& name /*=wxEmptyString*/, - const wxDateTime& dt /*=wxDateTime::Now()*/, - wxFileOffset size /*=0*/) - : m_Mode(0644), - m_IsModeSet(false), - m_UserId(wxGetTarUser().uid), - m_GroupId(wxGetTarUser().gid), - m_Size(size), - m_Offset(wxInvalidOffset), - m_ModifyTime(dt), - m_TypeFlag(wxTAR_REGTYPE), - m_UserName(wxGetTarUser().uname), - m_GroupName(wxGetTarUser().gname), - m_DevMajor(~0), - m_DevMinor(~0) -{ - if (!name.empty()) - SetName(name); -} - -wxTarEntry::~wxTarEntry() -{ -} - -wxTarEntry::wxTarEntry(const wxTarEntry& e) - : wxArchiveEntry(), - m_Name(e.m_Name), - m_Mode(e.m_Mode), - m_IsModeSet(e.m_IsModeSet), - m_UserId(e.m_UserId), - m_GroupId(e.m_GroupId), - m_Size(e.m_Size), - m_Offset(e.m_Offset), - m_ModifyTime(e.m_ModifyTime), - m_AccessTime(e.m_AccessTime), - m_CreateTime(e.m_CreateTime), - m_TypeFlag(e.m_TypeFlag), - m_LinkName(e.m_LinkName), - m_UserName(e.m_UserName), - m_GroupName(e.m_GroupName), - m_DevMajor(e.m_DevMajor), - m_DevMinor(e.m_DevMinor) -{ -} - -wxTarEntry& wxTarEntry::operator=(const wxTarEntry& e) -{ - if (&e != this) { - m_Name = e.m_Name; - m_Mode = e.m_Mode; - m_IsModeSet = e.m_IsModeSet; - m_UserId = e.m_UserId; - m_GroupId = e.m_GroupId; - m_Size = e.m_Size; - m_Offset = e.m_Offset; - m_ModifyTime = e.m_ModifyTime; - m_AccessTime = e.m_AccessTime; - m_CreateTime = e.m_CreateTime; - m_TypeFlag = e.m_TypeFlag; - m_LinkName = e.m_LinkName; - m_UserName = e.m_UserName; - m_GroupName = e.m_GroupName; - m_DevMajor = e.m_DevMajor; - m_DevMinor = e.m_DevMinor; - } - return *this; -} - -wxString wxTarEntry::GetName(wxPathFormat format /*=wxPATH_NATIVE*/) const -{ - bool isDir = IsDir() && !m_Name.empty(); - - // optimisations for common (and easy) cases - switch (wxFileName::GetFormat(format)) { - case wxPATH_DOS: - { - wxString name(isDir ? m_Name + _T("\\") : m_Name); - for (size_t i = 0; i < name.length(); i++) - if (name[i] == _T('/')) - name[i] = _T('\\'); - return name; - } - - case wxPATH_UNIX: - return isDir ? m_Name + _T("/") : m_Name; - - default: - ; - } - - wxFileName fn; - - if (isDir) - fn.AssignDir(m_Name, wxPATH_UNIX); - else - fn.Assign(m_Name, wxPATH_UNIX); - - return fn.GetFullPath(format); -} - -void wxTarEntry::SetName(const wxString& name, wxPathFormat format) -{ - bool isDir; - m_Name = GetInternalName(name, format, &isDir); - SetIsDir(isDir); -} - -// Static - Internally tars and zips use forward slashes for the path -// separator, absolute paths aren't allowed, and directory names have a -// trailing slash. This function converts a path into this internal format, -// but without a trailing slash for a directory. -// -wxString wxTarEntry::GetInternalName(const wxString& name, - wxPathFormat format /*=wxPATH_NATIVE*/, - bool *pIsDir /*=NULL*/) -{ - wxString internal; - - if (wxFileName::GetFormat(format) != wxPATH_UNIX) - internal = wxFileName(name, format).GetFullPath(wxPATH_UNIX); - else - internal = name; - - bool isDir = !internal.empty() && internal.Last() == '/'; - if (pIsDir) - *pIsDir = isDir; - if (isDir) - internal.erase(internal.length() - 1); - - while (!internal.empty() && *internal.begin() == '/') - internal.erase(0, 1); - while (!internal.empty() && internal.compare(0, 2, _T("./")) == 0) - internal.erase(0, 2); - if (internal == _T(".") || internal == _T("..")) - internal = wxEmptyString; - - return internal; -} - -bool wxTarEntry::IsDir() const -{ - return m_TypeFlag == wxTAR_DIRTYPE; -} - -void wxTarEntry::SetIsDir(bool isDir) -{ - if (isDir) - m_TypeFlag = wxTAR_DIRTYPE; - else if (m_TypeFlag == wxTAR_DIRTYPE) - m_TypeFlag = wxTAR_REGTYPE; -} - -void wxTarEntry::SetIsReadOnly(bool isReadOnly) -{ - if (isReadOnly) - m_Mode &= ~0222; - else - m_Mode |= 0200; -} - -int wxTarEntry::GetMode() const -{ - if (m_IsModeSet || !IsDir()) - return m_Mode; - else - return m_Mode | 0111; - -} - -void wxTarEntry::SetMode(int mode) -{ - m_Mode = mode & 07777; - m_IsModeSet = true; -} - - -///////////////////////////////////////////////////////////////////////////// -// Input stream - -wxDECLARE_SCOPED_PTR(wxTarEntry, wxTarEntryPtr_) -wxDEFINE_SCOPED_PTR (wxTarEntry, wxTarEntryPtr_) - -wxTarInputStream::wxTarInputStream(wxInputStream& stream, - wxMBConv& conv /*=wxConvLocal*/) - : wxArchiveInputStream(stream, conv) -{ - Init(); -} - -wxTarInputStream::wxTarInputStream(wxInputStream *stream, - wxMBConv& conv /*=wxConvLocal*/) - : wxArchiveInputStream(stream, conv) -{ - Init(); -} - -void wxTarInputStream::Init() -{ - m_pos = wxInvalidOffset; - m_offset = 0; - m_size = wxInvalidOffset; - m_sumType = SUM_UNKNOWN; - m_tarType = TYPE_USTAR; - m_hdr = new wxTarHeaderBlock; - m_HeaderRecs = NULL; - m_GlobalHeaderRecs = NULL; - m_lasterror = m_parent_i_stream->GetLastError(); -} - -wxTarInputStream::~wxTarInputStream() -{ - delete m_hdr; - delete m_HeaderRecs; - delete m_GlobalHeaderRecs; -} - -wxTarEntry *wxTarInputStream::GetNextEntry() -{ - m_lasterror = ReadHeaders(); - - if (!IsOk()) - return NULL; - - wxTarEntryPtr_ entry(new wxTarEntry); - - entry->SetMode(GetHeaderNumber(TAR_MODE)); - entry->SetUserId(GetHeaderNumber(TAR_UID)); - entry->SetGroupId(GetHeaderNumber(TAR_UID)); - entry->SetSize(GetHeaderNumber(TAR_SIZE)); - - entry->SetOffset(m_offset); - - entry->SetDateTime(GetHeaderDate(_T("mtime"))); - entry->SetAccessTime(GetHeaderDate(_T("atime"))); - entry->SetCreateTime(GetHeaderDate(_T("ctime"))); - - entry->SetTypeFlag(*m_hdr->Get(TAR_TYPEFLAG)); - bool isDir = entry->IsDir(); - - entry->SetLinkName(GetHeaderString(TAR_LINKNAME)); - - if (m_tarType != TYPE_OLDTAR) { - entry->SetUserName(GetHeaderString(TAR_UNAME)); - entry->SetGroupName(GetHeaderString(TAR_GNAME)); - - entry->SetDevMajor(GetHeaderNumber(TAR_DEVMAJOR)); - entry->SetDevMinor(GetHeaderNumber(TAR_DEVMINOR)); - } - - entry->SetName(GetHeaderPath(), wxPATH_UNIX); - if (isDir) - entry->SetIsDir(); - - if (m_HeaderRecs) - m_HeaderRecs->clear(); - - m_size = GetDataSize(*entry); - m_pos = 0; - - return entry.release(); -} - -bool wxTarInputStream::OpenEntry(wxTarEntry& entry) -{ - wxFileOffset offset = entry.GetOffset(); - - if (GetLastError() != wxSTREAM_READ_ERROR - && m_parent_i_stream->IsSeekable() - && m_parent_i_stream->SeekI(offset) == offset) - { - m_offset = offset; - m_size = GetDataSize(entry); - m_pos = 0; - m_lasterror = wxSTREAM_NO_ERROR; - return true; - } else { - m_lasterror = wxSTREAM_READ_ERROR; - return false; - } -} - -bool wxTarInputStream::OpenEntry(wxArchiveEntry& entry) -{ - wxTarEntry *tarEntry = wxStaticCast(&entry, wxTarEntry); - return tarEntry ? OpenEntry(*tarEntry) : false; -} - -bool wxTarInputStream::CloseEntry() -{ - if (m_lasterror == wxSTREAM_READ_ERROR) - return false; - if (!IsOpened()) - return true; - - wxFileOffset size = RoundUpSize(m_size); - wxFileOffset remainder = size - m_pos; - - if (remainder && m_parent_i_stream->IsSeekable()) { - wxLogNull nolog; - if (m_parent_i_stream->SeekI(remainder, wxFromCurrent) - != wxInvalidOffset) - remainder = 0; - } - - if (remainder) { - const int BUFSIZE = 8192; - wxCharBuffer buf(BUFSIZE); - - while (remainder > 0 && m_parent_i_stream->IsOk()) - remainder -= m_parent_i_stream->Read( - buf.data(), wxMin(BUFSIZE, remainder)).LastRead(); - } - - m_pos = wxInvalidOffset; - m_offset += size; - m_lasterror = m_parent_i_stream->GetLastError(); - - return IsOk(); -} - -wxStreamError wxTarInputStream::ReadHeaders() -{ - if (!CloseEntry()) - return wxSTREAM_READ_ERROR; - - bool done = false; - - while (!done) { - m_hdr->Read(*m_parent_i_stream); - if (m_parent_i_stream->Eof()) - wxLogError(_("incomplete header block in tar")); - if (!*m_parent_i_stream) - return wxSTREAM_READ_ERROR; - m_offset += TAR_BLOCKSIZE; - - // an all-zero header marks the end of the tar - if (m_hdr->IsAllZeros()) - return wxSTREAM_EOF; - - // the checksum is supposed to be the unsigned sum of the header bytes, - // but there have been versions of tar that used the signed sum, so - // accept that too, but only if used throughout. - wxUint32 chksum = m_hdr->GetOctal(TAR_CHKSUM); - bool ok = false; - - if (m_sumType != SUM_SIGNED) { - ok = chksum == m_hdr->Sum(); - if (m_sumType == SUM_UNKNOWN) - m_sumType = ok ? SUM_UNSIGNED : SUM_SIGNED; - } - if (m_sumType == SUM_SIGNED) - ok = chksum == m_hdr->Sum(true); - if (!ok) { - wxLogError(_("checksum failure reading tar header block")); - return wxSTREAM_READ_ERROR; - } - - if (strcmp(m_hdr->Get(TAR_MAGIC), USTAR_MAGIC) == 0) - m_tarType = TYPE_USTAR; - else if (strcmp(m_hdr->Get(TAR_MAGIC), GNU_MAGIC) == 0 && - strcmp(m_hdr->Get(TAR_VERSION), GNU_VERION) == 0) - m_tarType = TYPE_GNUTAR; - else - m_tarType = TYPE_OLDTAR; - - if (m_tarType != TYPE_USTAR) - break; - - switch (*m_hdr->Get(TAR_TYPEFLAG)) { - case 'g': ReadExtendedHeader(m_GlobalHeaderRecs); break; - case 'x': ReadExtendedHeader(m_HeaderRecs); break; - default: done = true; - } - } - - return wxSTREAM_NO_ERROR; -} - -wxString wxTarInputStream::GetExtendedHeader(const wxString& key) const -{ - wxTarHeaderRecords::iterator it; - - // look at normal extended header records first - if (m_HeaderRecs) { - it = m_HeaderRecs->find(key); - if (it != m_HeaderRecs->end()) - return wxString(it->second.wc_str(wxConvUTF8), GetConv()); - } - - // if not found, look at the global header records - if (m_GlobalHeaderRecs) { - it = m_GlobalHeaderRecs->find(key); - if (it != m_GlobalHeaderRecs->end()) - return wxString(it->second.wc_str(wxConvUTF8), GetConv()); - } - - return wxEmptyString; -} - -wxString wxTarInputStream::GetHeaderPath() const -{ - wxString path; - - if ((path = GetExtendedHeader(_T("path"))) != wxEmptyString) - return path; - - path = wxString(m_hdr->Get(TAR_NAME), GetConv()); - if (m_tarType != TYPE_USTAR) - return path; - - const char *prefix = m_hdr->Get(TAR_PREFIX); - return *prefix ? wxString(prefix, GetConv()) + _T("/") + path : path; -} - -wxDateTime wxTarInputStream::GetHeaderDate(const wxString& key) const -{ - wxString value; - - // try extended header, stored as decimal seconds since the epoch - if ((value = GetExtendedHeader(key)) != wxEmptyString) { - wxLongLong ll; - ll.Assign(wxAtof(value) * 1000.0); - return ll; - } - - if (key == _T("mtime")) - return wxLongLong(m_hdr->GetOctal(TAR_MTIME)) * 1000L; - - return wxDateTime(); -} - -wxTarNumber wxTarInputStream::GetHeaderNumber(int id) const -{ - wxString value; - - if ((value = GetExtendedHeader(m_hdr->Name(id))) != wxEmptyString) { - wxTarNumber n = 0; - const wxChar *p = value; - while (*p == ' ') - p++; - while (isdigit(*p)) - n = n * 10 + (*p++ - '0'); - return n; - } else { - return m_hdr->GetOctal(id); - } -} - -wxString wxTarInputStream::GetHeaderString(int id) const -{ - wxString value; - - if ((value = GetExtendedHeader(m_hdr->Name(id))) != wxEmptyString) - return value; - - return wxString(m_hdr->Get(id), GetConv()); -} - -// An extended header consists of one or more records, each constructed: -// "%d %s=%s\n", , , -// is the byte length, and are UTF-8 - -bool wxTarInputStream::ReadExtendedHeader(wxTarHeaderRecords*& recs) -{ - if (!recs) - recs = new wxTarHeaderRecords; - - // round length up to a whole number of blocks - size_t len = m_hdr->GetOctal(TAR_SIZE); - size_t size = RoundUpSize(len); - - // read in the whole header since it should be small - wxCharBuffer buf(size); - size_t lastread = m_parent_i_stream->Read(buf.data(), size).LastRead(); - if (lastread < len) - len = lastread; - buf.data()[len] = 0; - m_offset += lastread; - - size_t recPos, recSize; - bool ok = true; - - for (recPos = 0; recPos < len; recPos += recSize) { - char *pRec = buf.data() + recPos; - char *p = pRec; - - // read the record size (byte count in ascii decimal) - recSize = 0; - while (isdigit((unsigned char) *p)) - recSize = recSize * 10 + *p++ - '0'; - - // validity checks - if (recPos + recSize > len) - break; - if (recSize < p - pRec + (size_t)3 || *p != ' ' - || pRec[recSize - 1] != '\012') { - ok = false; - continue; - } - - // replace the final '\n' with a nul, to terminate value - pRec[recSize - 1] = 0; - // the key is here, following the space - char *pKey = ++p; - - // look forward for the '=', the value follows - while (*p && *p != '=') - p++; - if (!*p) { - ok = false; - continue; - } - // replace the '=' with a nul, to terminate the key - *p++ = 0; - - wxString key(wxConvUTF8.cMB2WC(pKey), GetConv()); - wxString value(wxConvUTF8.cMB2WC(p), GetConv()); - - // an empty value unsets a previously given value - if (value.empty()) - recs->erase(key); - else - (*recs)[key] = value; - } - - if (!ok || recPos < len || size != lastread) { - wxLogWarning(_("invalid data in extended tar header")); - return false; - } - - return true; -} - -wxFileOffset wxTarInputStream::OnSysSeek(wxFileOffset pos, wxSeekMode mode) -{ - if (!IsOpened()) { - wxLogError(_("tar entry not open")); - m_lasterror = wxSTREAM_READ_ERROR; - } - if (!IsOk()) - return wxInvalidOffset; - - switch (mode) { - case wxFromStart: break; - case wxFromCurrent: pos += m_pos; break; - case wxFromEnd: pos += m_size; break; - } - - if (pos < 0 || m_parent_i_stream->SeekI(m_offset + pos) == wxInvalidOffset) - return wxInvalidOffset; - - m_pos = pos; - return m_pos; -} - -size_t wxTarInputStream::OnSysRead(void *buffer, size_t size) -{ - if (!IsOpened()) { - wxLogError(_("tar entry not open")); - m_lasterror = wxSTREAM_READ_ERROR; - } - if (!IsOk() || !size) - return 0; - - if (m_pos >= m_size) - size = 0; - else if (m_pos + size > m_size + (size_t)0) - size = m_size - m_pos; - - size_t lastread = m_parent_i_stream->Read(buffer, size).LastRead(); - m_pos += lastread; - - if (m_pos >= m_size) { - m_lasterror = wxSTREAM_EOF; - } else if (!m_parent_i_stream->IsOk()) { - // any other error will have been reported by the underlying stream - if (m_parent_i_stream->Eof()) - wxLogError(_("unexpected end of file")); - m_lasterror = wxSTREAM_READ_ERROR; - } - - return lastread; -} - - -///////////////////////////////////////////////////////////////////////////// -// Output stream - -wxTarOutputStream::wxTarOutputStream(wxOutputStream& stream, - wxTarFormat format /*=wxTAR_PAX*/, - wxMBConv& conv /*=wxConvLocal*/) - : wxArchiveOutputStream(stream, conv) -{ - Init(format); -} - -wxTarOutputStream::wxTarOutputStream(wxOutputStream *stream, - wxTarFormat format /*=wxTAR_PAX*/, - wxMBConv& conv /*=wxConvLocal*/) - : wxArchiveOutputStream(stream, conv) -{ - Init(format); -} - -void wxTarOutputStream::Init(wxTarFormat format) -{ - m_pos = wxInvalidOffset; - m_maxpos = wxInvalidOffset; - m_size = wxInvalidOffset; - m_headpos = wxInvalidOffset; - m_datapos = wxInvalidOffset; - m_tarstart = wxInvalidOffset; - m_tarsize = 0; - m_pax = format == wxTAR_PAX; - m_BlockingFactor = m_pax ? 10 : 20; - m_chksum = 0; - m_large = false; - m_hdr = new wxTarHeaderBlock; - m_hdr2 = NULL; - m_extendedHdr = NULL; - m_extendedSize = 0; - m_lasterror = m_parent_o_stream->GetLastError(); -} - -wxTarOutputStream::~wxTarOutputStream() -{ - if (m_tarsize) - Close(); - delete m_hdr; - delete m_hdr2; - delete [] m_extendedHdr; -} - -bool wxTarOutputStream::PutNextEntry(wxTarEntry *entry) -{ - wxTarEntryPtr_ e(entry); - - if (!CloseEntry()) - return false; - - if (!m_tarsize) { - wxLogNull nolog; - m_tarstart = m_parent_o_stream->TellO(); - } - - if (m_tarstart != wxInvalidOffset) - m_headpos = m_tarstart + m_tarsize; - - if (WriteHeaders(*e)) { - m_pos = 0; - m_maxpos = 0; - m_size = GetDataSize(*e); - if (m_tarstart != wxInvalidOffset) - m_datapos = m_tarstart + m_tarsize; - - // types that are not allowd any data - const char nodata[] = { - wxTAR_LNKTYPE, wxTAR_SYMTYPE, wxTAR_CHRTYPE, wxTAR_BLKTYPE, - wxTAR_DIRTYPE, wxTAR_FIFOTYPE, 0 - }; - int typeflag = e->GetTypeFlag(); - - // pax does now allow data for wxTAR_LNKTYPE - if (!m_pax || typeflag != wxTAR_LNKTYPE) - if (strchr(nodata, typeflag) != NULL) - CloseEntry(); - } - - return IsOk(); -} - -bool wxTarOutputStream::PutNextEntry(const wxString& name, - const wxDateTime& dt, - wxFileOffset size) -{ - return PutNextEntry(new wxTarEntry(name, dt, size)); -} - -bool wxTarOutputStream::PutNextDirEntry(const wxString& name, - const wxDateTime& dt) -{ - wxTarEntry *entry = new wxTarEntry(name, dt); - entry->SetIsDir(); - return PutNextEntry(entry); -} - -bool wxTarOutputStream::PutNextEntry(wxArchiveEntry *entry) -{ - wxTarEntry *tarEntry = wxStaticCast(entry, wxTarEntry); - if (!tarEntry) - delete entry; - return PutNextEntry(tarEntry); -} - -bool wxTarOutputStream::CopyEntry(wxTarEntry *entry, - wxTarInputStream& inputStream) -{ - if (PutNextEntry(entry)) - Write(inputStream); - return IsOk() && inputStream.Eof(); -} - -bool wxTarOutputStream::CopyEntry(wxArchiveEntry *entry, - wxArchiveInputStream& inputStream) -{ - if (PutNextEntry(entry)) - Write(inputStream); - return IsOk() && inputStream.Eof(); -} - -bool wxTarOutputStream::CloseEntry() -{ - if (!IsOpened()) - return true; - - if (m_pos < m_maxpos) { - wxASSERT(m_parent_o_stream->IsSeekable()); - m_parent_o_stream->SeekO(m_datapos + m_maxpos); - m_lasterror = m_parent_o_stream->GetLastError(); - m_pos = m_maxpos; - } - - if (IsOk()) { - wxFileOffset size = RoundUpSize(m_pos); - if (size > m_pos) { - memset(m_hdr, 0, size - m_pos); - m_parent_o_stream->Write(m_hdr, size - m_pos); - m_lasterror = m_parent_o_stream->GetLastError(); - } - m_tarsize += size; - } - - if (IsOk() && m_pos != m_size) - ModifyHeader(); - - m_pos = wxInvalidOffset; - m_maxpos = wxInvalidOffset; - m_size = wxInvalidOffset; - m_headpos = wxInvalidOffset; - m_datapos = wxInvalidOffset; - - return IsOk(); -} - -bool wxTarOutputStream::Close() -{ - if (!CloseEntry()) - return false; - - memset(m_hdr, 0, sizeof(*m_hdr)); - int count = (RoundUpSize(m_tarsize + 2 * TAR_BLOCKSIZE, m_BlockingFactor) - - m_tarsize) / TAR_BLOCKSIZE; - while (count--) - m_parent_o_stream->Write(m_hdr, TAR_BLOCKSIZE); - - m_tarsize = 0; - m_tarstart = wxInvalidOffset; - m_lasterror = m_parent_o_stream->GetLastError(); - return IsOk(); -} - -bool wxTarOutputStream::WriteHeaders(wxTarEntry& entry) -{ - memset(m_hdr, 0, sizeof(*m_hdr)); - - SetHeaderPath(entry.GetName(wxPATH_UNIX)); - - SetHeaderNumber(TAR_MODE, entry.GetMode()); - SetHeaderNumber(TAR_UID, entry.GetUserId()); - SetHeaderNumber(TAR_GID, entry.GetGroupId()); - - if (entry.GetSize() == wxInvalidOffset) - entry.SetSize(0); - m_large = !SetHeaderNumber(TAR_SIZE, entry.GetSize()); - - SetHeaderDate(_T("mtime"), entry.GetDateTime()); - if (entry.GetAccessTime().IsValid()) - SetHeaderDate(_T("atime"), entry.GetAccessTime()); - if (entry.GetCreateTime().IsValid()) - SetHeaderDate(_T("ctime"), entry.GetCreateTime()); - - *m_hdr->Get(TAR_TYPEFLAG) = char(entry.GetTypeFlag()); - - strcpy(m_hdr->Get(TAR_MAGIC), USTAR_MAGIC); - strcpy(m_hdr->Get(TAR_VERSION), USTAR_VERSION); - - SetHeaderString(TAR_LINKNAME, entry.GetLinkName()); - SetHeaderString(TAR_UNAME, entry.GetUserName()); - SetHeaderString(TAR_GNAME, entry.GetGroupName()); - - if (~entry.GetDevMajor()) - SetHeaderNumber(TAR_DEVMAJOR, entry.GetDevMajor()); - if (~entry.GetDevMinor()) - SetHeaderNumber(TAR_DEVMINOR, entry.GetDevMinor()); - - m_chksum = m_hdr->Sum(); - m_hdr->SetOctal(TAR_CHKSUM, m_chksum); - if (!m_large) - m_chksum -= m_hdr->SumField(TAR_SIZE); - - // The main header is now fully prepared so we know what extended headers - // (if any) will be needed. Output any extended headers before writing - // the main header. - if (m_extendedHdr && *m_extendedHdr) { - wxASSERT(m_pax); - // the extended headers are written to the tar as a file entry, - // so prepare a regular header block for the pseudo-file. - if (!m_hdr2) - m_hdr2 = new wxTarHeaderBlock; - memset(m_hdr2, 0, sizeof(*m_hdr2)); - - // an old tar that doesn't understand extended headers will - // extract it as a file, so give these fields reasonable values - // so that the user will have access to read and remove it. - m_hdr2->SetPath(PaxHeaderPath(_T("%d/PaxHeaders.%p/%f"), - entry.GetName(wxPATH_UNIX)), GetConv()); - m_hdr2->SetOctal(TAR_MODE, 0600); - strcpy(m_hdr2->Get(TAR_UID), m_hdr->Get(TAR_UID)); - strcpy(m_hdr2->Get(TAR_GID), m_hdr->Get(TAR_GID)); - size_t length = strlen(m_extendedHdr); - m_hdr2->SetOctal(TAR_SIZE, length); - strcpy(m_hdr2->Get(TAR_MTIME), m_hdr->Get(TAR_MTIME)); - *m_hdr2->Get(TAR_TYPEFLAG) = 'x'; - strcpy(m_hdr2->Get(TAR_MAGIC), USTAR_MAGIC); - strcpy(m_hdr2->Get(TAR_VERSION), USTAR_VERSION); - strcpy(m_hdr2->Get(TAR_UNAME), m_hdr->Get(TAR_UNAME)); - strcpy(m_hdr2->Get(TAR_GNAME), m_hdr->Get(TAR_GNAME)); - - m_hdr2->SetOctal(TAR_CHKSUM, m_hdr2->Sum()); - - m_hdr2->Write(*m_parent_o_stream); - m_tarsize += TAR_BLOCKSIZE; - - size_t rounded = RoundUpSize(length); - memset(m_extendedHdr + length, 0, rounded - length); - m_parent_o_stream->Write(m_extendedHdr, rounded); - m_tarsize += rounded; - - *m_extendedHdr = 0; - } - - // if don't have extended headers just report error - if (!m_badfit.empty()) { - wxASSERT(!m_pax); - wxLogWarning(_("%s did not fit the tar header for entry '%s'"), - m_badfit.c_str(), entry.GetName().c_str()); - m_badfit.clear(); - } - - m_hdr->Write(*m_parent_o_stream); - m_tarsize += TAR_BLOCKSIZE; - m_lasterror = m_parent_o_stream->GetLastError(); - - return IsOk(); -} - -wxString wxTarOutputStream::PaxHeaderPath(const wxString& format, - const wxString& path) -{ - wxString d = path.BeforeLast(_T('/')); - wxString f = path.AfterLast(_T('/')); - wxString ret; - - if (d.empty()) - d = _T("."); - - ret.reserve(format.length() + path.length() + 16); - - size_t begin = 0; - size_t end; - - for (;;) { - end = format.find('%', begin); - if (end == wxString::npos || end + 1 >= format.length()) - break; - ret << format.substr(begin, end - begin); - switch (format[end + 1]) { - case 'd': ret << d; break; - case 'f': ret << f; break; - case 'p': ret << wxGetProcessId(); break; - case '%': ret << _T("%"); break; - } - begin = end + 2; - } - - ret << format.substr(begin); - - return ret; -} - -bool wxTarOutputStream::ModifyHeader() -{ - wxFileOffset originalPos = wxInvalidOffset; - wxFileOffset sizePos = wxInvalidOffset; - - if (!m_large && m_headpos != wxInvalidOffset - && m_parent_o_stream->IsSeekable()) - { - wxLogNull nolog; - originalPos = m_parent_o_stream->TellO(); - if (originalPos != wxInvalidOffset) - sizePos = - m_parent_o_stream->SeekO(m_headpos + m_hdr->Offset(TAR_SIZE)); - } - - if (sizePos == wxInvalidOffset || !m_hdr->SetOctal(TAR_SIZE, m_pos)) { - wxLogError(_("incorrect size given for tar entry")); - m_lasterror = wxSTREAM_WRITE_ERROR; - return false; - } - - m_chksum += m_hdr->SumField(TAR_SIZE); - m_hdr->SetOctal(TAR_CHKSUM, m_chksum); - wxFileOffset sumPos = m_headpos + m_hdr->Offset(TAR_CHKSUM); - - return - m_hdr->WriteField(*m_parent_o_stream, TAR_SIZE) && - m_parent_o_stream->SeekO(sumPos) == sumPos && - m_hdr->WriteField(*m_parent_o_stream, TAR_CHKSUM) && - m_parent_o_stream->SeekO(originalPos) == originalPos; -} - -void wxTarOutputStream::SetHeaderPath(const wxString& name) -{ - if (!m_hdr->SetPath(name, GetConv()) || (m_pax && !name.IsAscii())) - SetExtendedHeader(_T("path"), name); -} - -bool wxTarOutputStream::SetHeaderNumber(int id, wxTarNumber n) -{ - if (m_hdr->SetOctal(id, n)) { - return true; - } else { - SetExtendedHeader(m_hdr->Name(id), wxLongLong(n).ToString()); - return false; - } -} - -void wxTarOutputStream::SetHeaderString(int id, const wxString& str) -{ - strncpy(m_hdr->Get(id), str.mb_str(GetConv()), m_hdr->Len(id)); - if (str.length() > m_hdr->Len(id)) - SetExtendedHeader(m_hdr->Name(id), str); -} - -void wxTarOutputStream::SetHeaderDate(const wxString& key, - const wxDateTime& datetime) -{ - wxLongLong ll = datetime.IsValid() ? datetime.GetValue() : wxLongLong(0); - wxLongLong secs = ll / 1000L; - - if (key != _T("mtime") - || !m_hdr->SetOctal(TAR_MTIME, wxTarNumber(secs.GetValue())) - || secs <= 0 || secs >= 0x7fffffff) - { - wxString str; - if (ll >= LONG_MIN && ll <= LONG_MAX) { - str.Printf(_T("%g"), ll.ToLong() / 1000.0); - } else { - str = ll.ToString(); - str.insert(str.end() - 3, '.'); - } - SetExtendedHeader(key, str); - } -} - -void wxTarOutputStream::SetExtendedHeader(const wxString& key, - const wxString& value) -{ - if (m_pax) { - const wxWX2WCbuf wide_key = key.wc_str(GetConv()); - const wxCharBuffer utf_key = wxConvUTF8.cWC2MB(wide_key); - - const wxWX2WCbuf wide_value = value.wc_str(GetConv()); - const wxCharBuffer utf_value = wxConvUTF8.cWC2MB(wide_value); - - // a small buffer to format the length field in - char buf[32]; - // length of "99=\n" - unsigned long length = strlen(utf_value) + strlen(utf_key) + 5; - sprintf(buf, "%lu", length); - // the length includes itself - size_t lenlen = strlen(buf); - if (lenlen != 2) { - length += lenlen - 2; - sprintf(buf, "%lu", length); - if (strlen(buf) > lenlen) - sprintf(buf, "%lu", ++length); - } - - // reallocate m_extendedHdr if it's not big enough - if (m_extendedSize < length) { - size_t rounded = RoundUpSize(length); - m_extendedSize <<= 1; - if (rounded > m_extendedSize) - m_extendedSize = rounded; - char *oldHdr = m_extendedHdr; - m_extendedHdr = new char[m_extendedSize]; - if (oldHdr) { - strcpy(m_extendedHdr, oldHdr); - delete oldHdr; - } else { - *m_extendedHdr = 0; - } - } - - // append the new record - char *append = strchr(m_extendedHdr, 0); - sprintf(append, "%s %s=%s\012", buf, - (const char*)utf_key, (const char*)utf_value); - } - else { - // if not pax then make a list of fields to report as errors - if (!m_badfit.empty()) - m_badfit += _T(", "); - m_badfit += key; - } -} - -void wxTarOutputStream::Sync() -{ - m_parent_o_stream->Sync(); -} - -wxFileOffset wxTarOutputStream::OnSysSeek(wxFileOffset pos, wxSeekMode mode) -{ - if (!IsOpened()) { - wxLogError(_("tar entry not open")); - m_lasterror = wxSTREAM_WRITE_ERROR; - } - if (!IsOk() || m_datapos == wxInvalidOffset) - return wxInvalidOffset; - - switch (mode) { - case wxFromStart: break; - case wxFromCurrent: pos += m_pos; break; - case wxFromEnd: pos += m_maxpos; break; - } - - if (pos < 0 || m_parent_o_stream->SeekO(m_datapos + pos) == wxInvalidOffset) - return wxInvalidOffset; - - m_pos = pos; - return m_pos; -} - -size_t wxTarOutputStream::OnSysWrite(const void *buffer, size_t size) -{ - if (!IsOpened()) { - wxLogError(_("tar entry not open")); - m_lasterror = wxSTREAM_WRITE_ERROR; - } - if (!IsOk() || !size) - return 0; - - size_t lastwrite = m_parent_o_stream->Write(buffer, size).LastWrite(); - m_pos += lastwrite; - if (m_pos > m_maxpos) - m_maxpos = m_pos; - - if (lastwrite != size) - m_lasterror = wxSTREAM_WRITE_ERROR; - - return lastwrite; -} - -#endif // wxUSE_TARSTREAM +///////////////////////////////////////////////////////////////////////////// +// Name: tarstrm.cpp +// Purpose: Streams for Tar files +// Author: Mike Wetherell +// RCS-ID: $Id: tarstrm.cpp 53248 2008-04-17 17:29:22Z MW $ +// Copyright: (c) 2004 Mike Wetherell +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_TARSTREAM + +#include "wx/tarstrm.h" + +#ifndef WX_PRECOMP + #include "wx/intl.h" + #include "wx/log.h" + #include "wx/utils.h" +#endif + +#include "wx/buffer.h" +#include "wx/datetime.h" +#include "wx/ptr_scpd.h" +#include "wx/filename.h" +#include "wx/thread.h" + +#include + +#ifdef __UNIX__ +#include +#include +#endif + + +///////////////////////////////////////////////////////////////////////////// +// constants + +enum { + TAR_NAME, + TAR_MODE, + TAR_UID, + TAR_GID, + TAR_SIZE, + TAR_MTIME, + TAR_CHKSUM, + TAR_TYPEFLAG, + TAR_LINKNAME, + TAR_MAGIC, + TAR_VERSION, + TAR_UNAME, + TAR_GNAME, + TAR_DEVMAJOR, + TAR_DEVMINOR, + TAR_PREFIX, + TAR_UNUSED, + TAR_NUMFIELDS +}; + +enum { + TAR_BLOCKSIZE = 512 +}; + +// checksum type +enum { + SUM_UNKNOWN, + SUM_UNSIGNED, + SUM_SIGNED +}; + +// type of input tar +enum { + TYPE_OLDTAR, // fields after TAR_LINKNAME are invalid + TYPE_GNUTAR, // all fields except TAR_PREFIX are valid + TYPE_USTAR // all fields are valid +}; + +// signatures +static const char *USTAR_MAGIC = "ustar"; +static const char *USTAR_VERSION = "00"; +static const char *GNU_MAGIC = "ustar "; +static const char *GNU_VERION = " "; + +IMPLEMENT_DYNAMIC_CLASS(wxTarEntry, wxArchiveEntry) +IMPLEMENT_DYNAMIC_CLASS(wxTarClassFactory, wxArchiveClassFactory) + + +///////////////////////////////////////////////////////////////////////////// +// Class factory + +static wxTarClassFactory g_wxTarClassFactory; + +wxTarClassFactory::wxTarClassFactory() +{ + if (this == &g_wxTarClassFactory) + PushFront(); +} + +const wxChar * const * +wxTarClassFactory::GetProtocols(wxStreamProtocolType type) const +{ + static const wxChar *protocols[] = { _T("tar"), NULL }; + static const wxChar *mimetypes[] = { _T("application/x-tar"), NULL }; + static const wxChar *fileexts[] = { _T(".tar"), NULL }; + static const wxChar *empty[] = { NULL }; + + switch (type) { + case wxSTREAM_PROTOCOL: return protocols; + case wxSTREAM_MIMETYPE: return mimetypes; + case wxSTREAM_FILEEXT: return fileexts; + default: return empty; + } +} + + +///////////////////////////////////////////////////////////////////////////// +// tar header block + +typedef wxFileOffset wxTarNumber; + +struct wxTarField { const wxChar *name; int pos; }; + +class wxTarHeaderBlock +{ +public: + wxTarHeaderBlock() + { memset(data, 0, sizeof(data)); } + wxTarHeaderBlock(const wxTarHeaderBlock& hb) + { memcpy(data, hb.data, sizeof(data)); } + + bool Read(wxInputStream& in); + bool Write(wxOutputStream& out); + inline bool WriteField(wxOutputStream& out, int id); + + bool IsAllZeros() const; + wxUint32 Sum(bool SignedSum = false); + wxUint32 SumField(int id); + + char *Get(int id) { return data + fields[id].pos + id; } + static size_t Len(int id) { return fields[id + 1].pos - fields[id].pos; } + static const wxChar *Name(int id) { return fields[id].name; } + static size_t Offset(int id) { return fields[id].pos; } + + bool SetOctal(int id, wxTarNumber n); + wxTarNumber GetOctal(int id); + bool SetPath(const wxString& name, wxMBConv& conv); + +private: + char data[TAR_BLOCKSIZE + TAR_NUMFIELDS]; + static const wxTarField fields[]; + static void check(); +}; + +wxDEFINE_SCOPED_PTR_TYPE(wxTarHeaderBlock) + +// A table giving the field names and offsets in a tar header block +const wxTarField wxTarHeaderBlock::fields[] = +{ + { _T("name"), 0 }, // 100 + { _T("mode"), 100 }, // 8 + { _T("uid"), 108 }, // 8 + { _T("gid"), 116 }, // 8 + { _T("size"), 124 }, // 12 + { _T("mtime"), 136 }, // 12 + { _T("chksum"), 148 }, // 8 + { _T("typeflag"), 156 }, // 1 + { _T("linkname"), 157 }, // 100 + { _T("magic"), 257 }, // 6 + { _T("version"), 263 }, // 2 + { _T("uname"), 265 }, // 32 + { _T("gname"), 297 }, // 32 + { _T("devmajor"), 329 }, // 8 + { _T("devminor"), 337 }, // 8 + { _T("prefix"), 345 }, // 155 + { _T("unused"), 500 }, // 12 + { NULL, TAR_BLOCKSIZE } +}; + +void wxTarHeaderBlock::check() +{ +#if 0 + wxCOMPILE_TIME_ASSERT( + WXSIZEOF(fields) == TAR_NUMFIELDS + 1, + Wrong_number_of_elements_in_fields_table + ); +#endif +} + +bool wxTarHeaderBlock::IsAllZeros() const +{ + const char *p = data; + for (size_t i = 0; i < sizeof(data); i++) + if (p[i]) + return false; + return true; +} + +wxUint32 wxTarHeaderBlock::Sum(bool SignedSum /*=false*/) +{ + // the chksum field itself should be blanks during the calculation + memset(Get(TAR_CHKSUM), ' ', Len(TAR_CHKSUM)); + const char *p = data; + wxUint32 n = 0; + + if (SignedSum) + for (size_t i = 0; i < sizeof(data); i++) + n += (signed char)p[i]; + else + for (size_t i = 0; i < sizeof(data); i++) + n += (unsigned char)p[i]; + + return n; +} + +wxUint32 wxTarHeaderBlock::SumField(int id) +{ + unsigned char *p = (unsigned char*)Get(id); + unsigned char *q = p + Len(id); + wxUint32 n = 0; + + while (p < q) + n += *p++; + + return n; +} + +bool wxTarHeaderBlock::Read(wxInputStream& in) +{ + bool ok = true; + + for (int id = 0; id < TAR_NUMFIELDS && ok; id++) + ok = in.Read(Get(id), Len(id)).LastRead() == Len(id); + + return ok; +} + +bool wxTarHeaderBlock::Write(wxOutputStream& out) +{ + bool ok = true; + + for (int id = 0; id < TAR_NUMFIELDS && ok; id++) + ok = WriteField(out, id); + + return ok; +} + +inline bool wxTarHeaderBlock::WriteField(wxOutputStream& out, int id) +{ + return out.Write(Get(id), Len(id)).LastWrite() == Len(id); +} + +wxTarNumber wxTarHeaderBlock::GetOctal(int id) +{ + wxTarNumber n = 0; + const char *p = Get(id); + while (*p == ' ') + p++; + while (*p >= '0' && *p < '8') + n = (n << 3) | (*p++ - '0'); + return n; +} + +bool wxTarHeaderBlock::SetOctal(int id, wxTarNumber n) +{ + // set an octal field, return true if the number fits + char *field = Get(id); + char *p = field + Len(id); + *--p = 0; + while (p > field) { + *--p = char('0' + (n & 7)); + n >>= 3; + } + return n == 0; +} + +bool wxTarHeaderBlock::SetPath(const wxString& name, wxMBConv& conv) +{ + bool badconv = false; + +#if wxUSE_UNICODE + wxCharBuffer nameBuf = name.mb_str(conv); + + // if the conversion fails make an approximation + if (!nameBuf) { + badconv = true; + size_t len = name.length(); + wxCharBuffer approx(len); + for (size_t i = 0; i < len; i++) + approx.data()[i] = name[i] & ~0x7F ? '_' : name[i]; + nameBuf = approx; + } + + const char *mbName = nameBuf; +#else + const char *mbName = name.c_str(); + (void)conv; +#endif + + bool fits; + bool notGoingToFit = false; + size_t len = strlen(mbName); + size_t maxname = Len(TAR_NAME); + size_t maxprefix = Len(TAR_PREFIX); + size_t i = 0; + size_t nexti = 0; + + for (;;) { + fits = i < maxprefix && len - i <= maxname; + + if (!fits) { + const char *p = strchr(mbName + i, '/'); + if (p) + nexti = p - mbName + 1; + if (!p || nexti - 1 > maxprefix) + notGoingToFit = true; + } + + if (fits || notGoingToFit) { + strncpy(Get(TAR_NAME), mbName + i, maxname); + if (i > 0) + strncpy(Get(TAR_PREFIX), mbName, i - 1); + break; + } + + i = nexti; + } + + return fits && !badconv; +} + + +///////////////////////////////////////////////////////////////////////////// +// Some helpers + +static wxFileOffset RoundUpSize(wxFileOffset size, int factor = 1) +{ + wxFileOffset chunk = TAR_BLOCKSIZE * factor; + return ((size + chunk - 1) / chunk) * chunk; +} + +#ifdef __UNIX__ + +static wxString wxTarUserName(int uid) +{ + struct passwd *ppw; + +#ifdef HAVE_GETPWUID_R +#if defined HAVE_SYSCONF && defined _SC_GETPW_R_SIZE_MAX + long pwsize = sysconf(_SC_GETPW_R_SIZE_MAX); + size_t bufsize(wxMin(wxMax(1024l, pwsize), 32768l)); +#else + size_t bufsize = 1024; +#endif + wxCharBuffer buf(bufsize); + struct passwd pw; + + memset(&pw, 0, sizeof(pw)); + if (getpwuid_r(uid, &pw, buf.data(), bufsize, &ppw) == 0 && pw.pw_name) + return wxString(pw.pw_name, wxConvLibc); +#else + if ((ppw = getpwuid(uid)) != NULL) + return wxString(ppw->pw_name, wxConvLibc); +#endif + return _("unknown"); +} + +static wxString wxTarGroupName(int gid) +{ + struct group *pgr; +#ifdef HAVE_GETGRGID_R +#if defined HAVE_SYSCONF && defined _SC_GETGR_R_SIZE_MAX + long grsize = sysconf(_SC_GETGR_R_SIZE_MAX); + size_t bufsize(wxMin(wxMax(1024l, grsize), 32768l)); +#else + size_t bufsize = 1024; +#endif + wxCharBuffer buf(bufsize); + struct group gr; + + memset(&gr, 0, sizeof(gr)); + if (getgrgid_r(gid, &gr, buf.data(), bufsize, &pgr) == 0 && gr.gr_name) + return wxString(gr.gr_name, wxConvLibc); +#else + if ((pgr = getgrgid(gid)) != NULL) + return wxString(pgr->gr_name, wxConvLibc); +#endif + return _("unknown"); +} + +#endif // __UNIX__ + +// Cache the user and group names since getting them can be expensive, +// get both names and ids at the same time. +// +struct wxTarUser +{ + wxTarUser(); + ~wxTarUser() { delete [] uname; delete [] gname; } + + int uid; + int gid; + + wxChar *uname; + wxChar *gname; +}; + +wxTarUser::wxTarUser() +{ +#ifdef __UNIX__ + uid = getuid(); + gid = getgid(); + wxString usr = wxTarUserName(uid); + wxString grp = wxTarGroupName(gid); +#else + uid = 0; + gid = 0; + wxString usr = wxGetUserId(); + wxString grp = _("unknown"); +#endif + + uname = new wxChar[usr.length() + 1]; + wxStrcpy(uname, usr.c_str()); + + gname = new wxChar[grp.length() + 1]; + wxStrcpy(gname, grp.c_str()); +} + +static const wxTarUser& wxGetTarUser() +{ +#if wxUSE_THREADS + static wxCriticalSection cs; + wxCriticalSectionLocker lock(cs); +#endif + static wxTarUser tu; + return tu; +} + +// ignore the size field for entry types 3, 4, 5 and 6 +// +static inline wxFileOffset GetDataSize(const wxTarEntry& entry) +{ + switch (entry.GetTypeFlag()) { + case wxTAR_CHRTYPE: + case wxTAR_BLKTYPE: + case wxTAR_DIRTYPE: + case wxTAR_FIFOTYPE: + return 0; + default: + return entry.GetSize(); + } +} + + +///////////////////////////////////////////////////////////////////////////// +// Tar Entry +// Holds all the meta-data for a file in the tar + +wxTarEntry::wxTarEntry(const wxString& name /*=wxEmptyString*/, + const wxDateTime& dt /*=wxDateTime::Now()*/, + wxFileOffset size /*=0*/) + : m_Mode(0644), + m_IsModeSet(false), + m_UserId(wxGetTarUser().uid), + m_GroupId(wxGetTarUser().gid), + m_Size(size), + m_Offset(wxInvalidOffset), + m_ModifyTime(dt), + m_TypeFlag(wxTAR_REGTYPE), + m_UserName(wxGetTarUser().uname), + m_GroupName(wxGetTarUser().gname), + m_DevMajor(~0), + m_DevMinor(~0) +{ + if (!name.empty()) + SetName(name); +} + +wxTarEntry::~wxTarEntry() +{ +} + +wxTarEntry::wxTarEntry(const wxTarEntry& e) + : wxArchiveEntry(), + m_Name(e.m_Name), + m_Mode(e.m_Mode), + m_IsModeSet(e.m_IsModeSet), + m_UserId(e.m_UserId), + m_GroupId(e.m_GroupId), + m_Size(e.m_Size), + m_Offset(e.m_Offset), + m_ModifyTime(e.m_ModifyTime), + m_AccessTime(e.m_AccessTime), + m_CreateTime(e.m_CreateTime), + m_TypeFlag(e.m_TypeFlag), + m_LinkName(e.m_LinkName), + m_UserName(e.m_UserName), + m_GroupName(e.m_GroupName), + m_DevMajor(e.m_DevMajor), + m_DevMinor(e.m_DevMinor) +{ +} + +wxTarEntry& wxTarEntry::operator=(const wxTarEntry& e) +{ + if (&e != this) { + m_Name = e.m_Name; + m_Mode = e.m_Mode; + m_IsModeSet = e.m_IsModeSet; + m_UserId = e.m_UserId; + m_GroupId = e.m_GroupId; + m_Size = e.m_Size; + m_Offset = e.m_Offset; + m_ModifyTime = e.m_ModifyTime; + m_AccessTime = e.m_AccessTime; + m_CreateTime = e.m_CreateTime; + m_TypeFlag = e.m_TypeFlag; + m_LinkName = e.m_LinkName; + m_UserName = e.m_UserName; + m_GroupName = e.m_GroupName; + m_DevMajor = e.m_DevMajor; + m_DevMinor = e.m_DevMinor; + } + return *this; +} + +wxString wxTarEntry::GetName(wxPathFormat format /*=wxPATH_NATIVE*/) const +{ + bool isDir = IsDir() && !m_Name.empty(); + + // optimisations for common (and easy) cases + switch (wxFileName::GetFormat(format)) { + case wxPATH_DOS: + { + wxString name(isDir ? m_Name + _T("\\") : m_Name); + for (size_t i = 0; i < name.length(); i++) + if (name[i] == _T('/')) + name[i] = _T('\\'); + return name; + } + + case wxPATH_UNIX: + return isDir ? m_Name + _T("/") : m_Name; + + default: + ; + } + + wxFileName fn; + + if (isDir) + fn.AssignDir(m_Name, wxPATH_UNIX); + else + fn.Assign(m_Name, wxPATH_UNIX); + + return fn.GetFullPath(format); +} + +void wxTarEntry::SetName(const wxString& name, wxPathFormat format) +{ + bool isDir; + m_Name = GetInternalName(name, format, &isDir); + SetIsDir(isDir); +} + +// Static - Internally tars and zips use forward slashes for the path +// separator, absolute paths aren't allowed, and directory names have a +// trailing slash. This function converts a path into this internal format, +// but without a trailing slash for a directory. +// +wxString wxTarEntry::GetInternalName(const wxString& name, + wxPathFormat format /*=wxPATH_NATIVE*/, + bool *pIsDir /*=NULL*/) +{ + wxString internal; + + if (wxFileName::GetFormat(format) != wxPATH_UNIX) + internal = wxFileName(name, format).GetFullPath(wxPATH_UNIX); + else + internal = name; + + bool isDir = !internal.empty() && internal.Last() == '/'; + if (pIsDir) + *pIsDir = isDir; + if (isDir) + internal.erase(internal.length() - 1); + + while (!internal.empty() && *internal.begin() == '/') + internal.erase(0, 1); + while (!internal.empty() && internal.compare(0, 2, _T("./")) == 0) + internal.erase(0, 2); + if (internal == _T(".") || internal == _T("..")) + internal = wxEmptyString; + + return internal; +} + +bool wxTarEntry::IsDir() const +{ + return m_TypeFlag == wxTAR_DIRTYPE; +} + +void wxTarEntry::SetIsDir(bool isDir) +{ + if (isDir) + m_TypeFlag = wxTAR_DIRTYPE; + else if (m_TypeFlag == wxTAR_DIRTYPE) + m_TypeFlag = wxTAR_REGTYPE; +} + +void wxTarEntry::SetIsReadOnly(bool isReadOnly) +{ + if (isReadOnly) + m_Mode &= ~0222; + else + m_Mode |= 0200; +} + +int wxTarEntry::GetMode() const +{ + if (m_IsModeSet || !IsDir()) + return m_Mode; + else + return m_Mode | 0111; + +} + +void wxTarEntry::SetMode(int mode) +{ + m_Mode = mode & 07777; + m_IsModeSet = true; +} + + +///////////////////////////////////////////////////////////////////////////// +// Input stream + +wxDECLARE_SCOPED_PTR(wxTarEntry, wxTarEntryPtr_) +wxDEFINE_SCOPED_PTR (wxTarEntry, wxTarEntryPtr_) + +wxTarInputStream::wxTarInputStream(wxInputStream& stream, + wxMBConv& conv /*=wxConvLocal*/) + : wxArchiveInputStream(stream, conv) +{ + Init(); +} + +wxTarInputStream::wxTarInputStream(wxInputStream *stream, + wxMBConv& conv /*=wxConvLocal*/) + : wxArchiveInputStream(stream, conv) +{ + Init(); +} + +void wxTarInputStream::Init() +{ + m_pos = wxInvalidOffset; + m_offset = 0; + m_size = wxInvalidOffset; + m_sumType = SUM_UNKNOWN; + m_tarType = TYPE_USTAR; + m_hdr = new wxTarHeaderBlock; + m_HeaderRecs = NULL; + m_GlobalHeaderRecs = NULL; + m_lasterror = m_parent_i_stream->GetLastError(); +} + +wxTarInputStream::~wxTarInputStream() +{ + delete m_hdr; + delete m_HeaderRecs; + delete m_GlobalHeaderRecs; +} + +wxTarEntry *wxTarInputStream::GetNextEntry() +{ + m_lasterror = ReadHeaders(); + + if (!IsOk()) + return NULL; + + wxTarEntryPtr_ entry(new wxTarEntry); + + entry->SetMode(GetHeaderNumber(TAR_MODE)); + entry->SetUserId(GetHeaderNumber(TAR_UID)); + entry->SetGroupId(GetHeaderNumber(TAR_UID)); + entry->SetSize(GetHeaderNumber(TAR_SIZE)); + + entry->SetOffset(m_offset); + + entry->SetDateTime(GetHeaderDate(_T("mtime"))); + entry->SetAccessTime(GetHeaderDate(_T("atime"))); + entry->SetCreateTime(GetHeaderDate(_T("ctime"))); + + entry->SetTypeFlag(*m_hdr->Get(TAR_TYPEFLAG)); + bool isDir = entry->IsDir(); + + entry->SetLinkName(GetHeaderString(TAR_LINKNAME)); + + if (m_tarType != TYPE_OLDTAR) { + entry->SetUserName(GetHeaderString(TAR_UNAME)); + entry->SetGroupName(GetHeaderString(TAR_GNAME)); + + entry->SetDevMajor(GetHeaderNumber(TAR_DEVMAJOR)); + entry->SetDevMinor(GetHeaderNumber(TAR_DEVMINOR)); + } + + entry->SetName(GetHeaderPath(), wxPATH_UNIX); + if (isDir) + entry->SetIsDir(); + + if (m_HeaderRecs) + m_HeaderRecs->clear(); + + m_size = GetDataSize(*entry); + m_pos = 0; + + return entry.release(); +} + +bool wxTarInputStream::OpenEntry(wxTarEntry& entry) +{ + wxFileOffset offset = entry.GetOffset(); + + if (GetLastError() != wxSTREAM_READ_ERROR + && m_parent_i_stream->IsSeekable() + && m_parent_i_stream->SeekI(offset) == offset) + { + m_offset = offset; + m_size = GetDataSize(entry); + m_pos = 0; + m_lasterror = wxSTREAM_NO_ERROR; + return true; + } else { + m_lasterror = wxSTREAM_READ_ERROR; + return false; + } +} + +bool wxTarInputStream::OpenEntry(wxArchiveEntry& entry) +{ + wxTarEntry *tarEntry = wxStaticCast(&entry, wxTarEntry); + return tarEntry ? OpenEntry(*tarEntry) : false; +} + +bool wxTarInputStream::CloseEntry() +{ + if (m_lasterror == wxSTREAM_READ_ERROR) + return false; + if (!IsOpened()) + return true; + + wxFileOffset size = RoundUpSize(m_size); + wxFileOffset remainder = size - m_pos; + + if (remainder && m_parent_i_stream->IsSeekable()) { + wxLogNull nolog; + if (m_parent_i_stream->SeekI(remainder, wxFromCurrent) + != wxInvalidOffset) + remainder = 0; + } + + if (remainder) { + const int BUFSIZE = 8192; + wxCharBuffer buf(BUFSIZE); + + while (remainder > 0 && m_parent_i_stream->IsOk()) + remainder -= m_parent_i_stream->Read( + buf.data(), wxMin(BUFSIZE, remainder)).LastRead(); + } + + m_pos = wxInvalidOffset; + m_offset += size; + m_lasterror = m_parent_i_stream->GetLastError(); + + return IsOk(); +} + +wxStreamError wxTarInputStream::ReadHeaders() +{ + if (!CloseEntry()) + return wxSTREAM_READ_ERROR; + + bool done = false; + + while (!done) { + m_hdr->Read(*m_parent_i_stream); + if (m_parent_i_stream->Eof()) + wxLogError(_("incomplete header block in tar")); + if (!*m_parent_i_stream) + return wxSTREAM_READ_ERROR; + m_offset += TAR_BLOCKSIZE; + + // an all-zero header marks the end of the tar + if (m_hdr->IsAllZeros()) + return wxSTREAM_EOF; + + // the checksum is supposed to be the unsigned sum of the header bytes, + // but there have been versions of tar that used the signed sum, so + // accept that too, but only if used throughout. + wxUint32 chksum = m_hdr->GetOctal(TAR_CHKSUM); + bool ok = false; + + if (m_sumType != SUM_SIGNED) { + ok = chksum == m_hdr->Sum(); + if (m_sumType == SUM_UNKNOWN) + m_sumType = ok ? SUM_UNSIGNED : SUM_SIGNED; + } + if (m_sumType == SUM_SIGNED) + ok = chksum == m_hdr->Sum(true); + if (!ok) { + wxLogError(_("checksum failure reading tar header block")); + return wxSTREAM_READ_ERROR; + } + + if (strcmp(m_hdr->Get(TAR_MAGIC), USTAR_MAGIC) == 0) + m_tarType = TYPE_USTAR; + else if (strcmp(m_hdr->Get(TAR_MAGIC), GNU_MAGIC) == 0 && + strcmp(m_hdr->Get(TAR_VERSION), GNU_VERION) == 0) + m_tarType = TYPE_GNUTAR; + else + m_tarType = TYPE_OLDTAR; + + if (m_tarType != TYPE_USTAR) + break; + + switch (*m_hdr->Get(TAR_TYPEFLAG)) { + case 'g': ReadExtendedHeader(m_GlobalHeaderRecs); break; + case 'x': ReadExtendedHeader(m_HeaderRecs); break; + default: done = true; + } + } + + return wxSTREAM_NO_ERROR; +} + +wxString wxTarInputStream::GetExtendedHeader(const wxString& key) const +{ + wxTarHeaderRecords::iterator it; + + // look at normal extended header records first + if (m_HeaderRecs) { + it = m_HeaderRecs->find(key); + if (it != m_HeaderRecs->end()) + return wxString(it->second.wc_str(wxConvUTF8), GetConv()); + } + + // if not found, look at the global header records + if (m_GlobalHeaderRecs) { + it = m_GlobalHeaderRecs->find(key); + if (it != m_GlobalHeaderRecs->end()) + return wxString(it->second.wc_str(wxConvUTF8), GetConv()); + } + + return wxEmptyString; +} + +wxString wxTarInputStream::GetHeaderPath() const +{ + wxString path; + + if ((path = GetExtendedHeader(_T("path"))) != wxEmptyString) + return path; + + path = wxString(m_hdr->Get(TAR_NAME), GetConv()); + if (m_tarType != TYPE_USTAR) + return path; + + const char *prefix = m_hdr->Get(TAR_PREFIX); + return *prefix ? wxString(prefix, GetConv()) + _T("/") + path : path; +} + +wxDateTime wxTarInputStream::GetHeaderDate(const wxString& key) const +{ + wxString value; + + // try extended header, stored as decimal seconds since the epoch + if ((value = GetExtendedHeader(key)) != wxEmptyString) { + wxLongLong ll; + ll.Assign(wxAtof(value) * 1000.0); + return ll; + } + + if (key == _T("mtime")) + return wxLongLong(m_hdr->GetOctal(TAR_MTIME)) * 1000L; + + return wxDateTime(); +} + +wxTarNumber wxTarInputStream::GetHeaderNumber(int id) const +{ + wxString value; + + if ((value = GetExtendedHeader(m_hdr->Name(id))) != wxEmptyString) { + wxTarNumber n = 0; + const wxChar *p = value; + while (*p == ' ') + p++; + while (isdigit(*p)) + n = n * 10 + (*p++ - '0'); + return n; + } else { + return m_hdr->GetOctal(id); + } +} + +wxString wxTarInputStream::GetHeaderString(int id) const +{ + wxString value; + + if ((value = GetExtendedHeader(m_hdr->Name(id))) != wxEmptyString) + return value; + + return wxString(m_hdr->Get(id), GetConv()); +} + +// An extended header consists of one or more records, each constructed: +// "%d %s=%s\n", , , +// is the byte length, and are UTF-8 + +bool wxTarInputStream::ReadExtendedHeader(wxTarHeaderRecords*& recs) +{ + if (!recs) + recs = new wxTarHeaderRecords; + + // round length up to a whole number of blocks + size_t len = m_hdr->GetOctal(TAR_SIZE); + size_t size = RoundUpSize(len); + + // read in the whole header since it should be small + wxCharBuffer buf(size); + size_t lastread = m_parent_i_stream->Read(buf.data(), size).LastRead(); + if (lastread < len) + len = lastread; + buf.data()[len] = 0; + m_offset += lastread; + + size_t recPos, recSize; + bool ok = true; + + for (recPos = 0; recPos < len; recPos += recSize) { + char *pRec = buf.data() + recPos; + char *p = pRec; + + // read the record size (byte count in ascii decimal) + recSize = 0; + while (isdigit((unsigned char) *p)) + recSize = recSize * 10 + *p++ - '0'; + + // validity checks + if (recPos + recSize > len) + break; + if (recSize < p - pRec + (size_t)3 || *p != ' ' + || pRec[recSize - 1] != '\012') { + ok = false; + continue; + } + + // replace the final '\n' with a nul, to terminate value + pRec[recSize - 1] = 0; + // the key is here, following the space + char *pKey = ++p; + + // look forward for the '=', the value follows + while (*p && *p != '=') + p++; + if (!*p) { + ok = false; + continue; + } + // replace the '=' with a nul, to terminate the key + *p++ = 0; + + wxString key(wxConvUTF8.cMB2WC(pKey), GetConv()); + wxString value(wxConvUTF8.cMB2WC(p), GetConv()); + + // an empty value unsets a previously given value + if (value.empty()) + recs->erase(key); + else + (*recs)[key] = value; + } + + if (!ok || recPos < len || size != lastread) { + wxLogWarning(_("invalid data in extended tar header")); + return false; + } + + return true; +} + +wxFileOffset wxTarInputStream::OnSysSeek(wxFileOffset pos, wxSeekMode mode) +{ + if (!IsOpened()) { + wxLogError(_("tar entry not open")); + m_lasterror = wxSTREAM_READ_ERROR; + } + if (!IsOk()) + return wxInvalidOffset; + + switch (mode) { + case wxFromStart: break; + case wxFromCurrent: pos += m_pos; break; + case wxFromEnd: pos += m_size; break; + } + + if (pos < 0 || m_parent_i_stream->SeekI(m_offset + pos) == wxInvalidOffset) + return wxInvalidOffset; + + m_pos = pos; + return m_pos; +} + +size_t wxTarInputStream::OnSysRead(void *buffer, size_t size) +{ + if (!IsOpened()) { + wxLogError(_("tar entry not open")); + m_lasterror = wxSTREAM_READ_ERROR; + } + if (!IsOk() || !size) + return 0; + + if (m_pos >= m_size) + size = 0; + else if (m_pos + size > m_size + (size_t)0) + size = m_size - m_pos; + + size_t lastread = m_parent_i_stream->Read(buffer, size).LastRead(); + m_pos += lastread; + + if (m_pos >= m_size) { + m_lasterror = wxSTREAM_EOF; + } else if (!m_parent_i_stream->IsOk()) { + // any other error will have been reported by the underlying stream + if (m_parent_i_stream->Eof()) + wxLogError(_("unexpected end of file")); + m_lasterror = wxSTREAM_READ_ERROR; + } + + return lastread; +} + + +///////////////////////////////////////////////////////////////////////////// +// Output stream + +wxTarOutputStream::wxTarOutputStream(wxOutputStream& stream, + wxTarFormat format /*=wxTAR_PAX*/, + wxMBConv& conv /*=wxConvLocal*/) + : wxArchiveOutputStream(stream, conv) +{ + Init(format); +} + +wxTarOutputStream::wxTarOutputStream(wxOutputStream *stream, + wxTarFormat format /*=wxTAR_PAX*/, + wxMBConv& conv /*=wxConvLocal*/) + : wxArchiveOutputStream(stream, conv) +{ + Init(format); +} + +void wxTarOutputStream::Init(wxTarFormat format) +{ + m_pos = wxInvalidOffset; + m_maxpos = wxInvalidOffset; + m_size = wxInvalidOffset; + m_headpos = wxInvalidOffset; + m_datapos = wxInvalidOffset; + m_tarstart = wxInvalidOffset; + m_tarsize = 0; + m_pax = format == wxTAR_PAX; + m_BlockingFactor = m_pax ? 10 : 20; + m_chksum = 0; + m_large = false; + m_hdr = new wxTarHeaderBlock; + m_hdr2 = NULL; + m_extendedHdr = NULL; + m_extendedSize = 0; + m_lasterror = m_parent_o_stream->GetLastError(); +} + +wxTarOutputStream::~wxTarOutputStream() +{ + if (m_tarsize) + Close(); + delete m_hdr; + delete m_hdr2; + delete [] m_extendedHdr; +} + +bool wxTarOutputStream::PutNextEntry(wxTarEntry *entry) +{ + wxTarEntryPtr_ e(entry); + + if (!CloseEntry()) + return false; + + if (!m_tarsize) { + wxLogNull nolog; + m_tarstart = m_parent_o_stream->TellO(); + } + + if (m_tarstart != wxInvalidOffset) + m_headpos = m_tarstart + m_tarsize; + + if (WriteHeaders(*e)) { + m_pos = 0; + m_maxpos = 0; + m_size = GetDataSize(*e); + if (m_tarstart != wxInvalidOffset) + m_datapos = m_tarstart + m_tarsize; + + // types that are not allowd any data + const char nodata[] = { + wxTAR_LNKTYPE, wxTAR_SYMTYPE, wxTAR_CHRTYPE, wxTAR_BLKTYPE, + wxTAR_DIRTYPE, wxTAR_FIFOTYPE, 0 + }; + int typeflag = e->GetTypeFlag(); + + // pax does now allow data for wxTAR_LNKTYPE + if (!m_pax || typeflag != wxTAR_LNKTYPE) + if (strchr(nodata, typeflag) != NULL) + CloseEntry(); + } + + return IsOk(); +} + +bool wxTarOutputStream::PutNextEntry(const wxString& name, + const wxDateTime& dt, + wxFileOffset size) +{ + return PutNextEntry(new wxTarEntry(name, dt, size)); +} + +bool wxTarOutputStream::PutNextDirEntry(const wxString& name, + const wxDateTime& dt) +{ + wxTarEntry *entry = new wxTarEntry(name, dt); + entry->SetIsDir(); + return PutNextEntry(entry); +} + +bool wxTarOutputStream::PutNextEntry(wxArchiveEntry *entry) +{ + wxTarEntry *tarEntry = wxStaticCast(entry, wxTarEntry); + if (!tarEntry) + delete entry; + return PutNextEntry(tarEntry); +} + +bool wxTarOutputStream::CopyEntry(wxTarEntry *entry, + wxTarInputStream& inputStream) +{ + if (PutNextEntry(entry)) + Write(inputStream); + return IsOk() && inputStream.Eof(); +} + +bool wxTarOutputStream::CopyEntry(wxArchiveEntry *entry, + wxArchiveInputStream& inputStream) +{ + if (PutNextEntry(entry)) + Write(inputStream); + return IsOk() && inputStream.Eof(); +} + +bool wxTarOutputStream::CloseEntry() +{ + if (!IsOpened()) + return true; + + if (m_pos < m_maxpos) { + wxASSERT(m_parent_o_stream->IsSeekable()); + m_parent_o_stream->SeekO(m_datapos + m_maxpos); + m_lasterror = m_parent_o_stream->GetLastError(); + m_pos = m_maxpos; + } + + if (IsOk()) { + wxFileOffset size = RoundUpSize(m_pos); + if (size > m_pos) { + memset(m_hdr, 0, size - m_pos); + m_parent_o_stream->Write(m_hdr, size - m_pos); + m_lasterror = m_parent_o_stream->GetLastError(); + } + m_tarsize += size; + } + + if (IsOk() && m_pos != m_size) + ModifyHeader(); + + m_pos = wxInvalidOffset; + m_maxpos = wxInvalidOffset; + m_size = wxInvalidOffset; + m_headpos = wxInvalidOffset; + m_datapos = wxInvalidOffset; + + return IsOk(); +} + +bool wxTarOutputStream::Close() +{ + if (!CloseEntry()) + return false; + + memset(m_hdr, 0, sizeof(*m_hdr)); + int count = (RoundUpSize(m_tarsize + 2 * TAR_BLOCKSIZE, m_BlockingFactor) + - m_tarsize) / TAR_BLOCKSIZE; + while (count--) + m_parent_o_stream->Write(m_hdr, TAR_BLOCKSIZE); + + m_tarsize = 0; + m_tarstart = wxInvalidOffset; + m_lasterror = m_parent_o_stream->GetLastError(); + return IsOk(); +} + +bool wxTarOutputStream::WriteHeaders(wxTarEntry& entry) +{ + memset(m_hdr, 0, sizeof(*m_hdr)); + + SetHeaderPath(entry.GetName(wxPATH_UNIX)); + + SetHeaderNumber(TAR_MODE, entry.GetMode()); + SetHeaderNumber(TAR_UID, entry.GetUserId()); + SetHeaderNumber(TAR_GID, entry.GetGroupId()); + + if (entry.GetSize() == wxInvalidOffset) + entry.SetSize(0); + m_large = !SetHeaderNumber(TAR_SIZE, entry.GetSize()); + + SetHeaderDate(_T("mtime"), entry.GetDateTime()); + if (entry.GetAccessTime().IsValid()) + SetHeaderDate(_T("atime"), entry.GetAccessTime()); + if (entry.GetCreateTime().IsValid()) + SetHeaderDate(_T("ctime"), entry.GetCreateTime()); + + *m_hdr->Get(TAR_TYPEFLAG) = char(entry.GetTypeFlag()); + + strcpy(m_hdr->Get(TAR_MAGIC), USTAR_MAGIC); + strcpy(m_hdr->Get(TAR_VERSION), USTAR_VERSION); + + SetHeaderString(TAR_LINKNAME, entry.GetLinkName()); + SetHeaderString(TAR_UNAME, entry.GetUserName()); + SetHeaderString(TAR_GNAME, entry.GetGroupName()); + + if (~entry.GetDevMajor()) + SetHeaderNumber(TAR_DEVMAJOR, entry.GetDevMajor()); + if (~entry.GetDevMinor()) + SetHeaderNumber(TAR_DEVMINOR, entry.GetDevMinor()); + + m_chksum = m_hdr->Sum(); + m_hdr->SetOctal(TAR_CHKSUM, m_chksum); + if (!m_large) + m_chksum -= m_hdr->SumField(TAR_SIZE); + + // The main header is now fully prepared so we know what extended headers + // (if any) will be needed. Output any extended headers before writing + // the main header. + if (m_extendedHdr && *m_extendedHdr) { + wxASSERT(m_pax); + // the extended headers are written to the tar as a file entry, + // so prepare a regular header block for the pseudo-file. + if (!m_hdr2) + m_hdr2 = new wxTarHeaderBlock; + memset(m_hdr2, 0, sizeof(*m_hdr2)); + + // an old tar that doesn't understand extended headers will + // extract it as a file, so give these fields reasonable values + // so that the user will have access to read and remove it. + m_hdr2->SetPath(PaxHeaderPath(_T("%d/PaxHeaders.%p/%f"), + entry.GetName(wxPATH_UNIX)), GetConv()); + m_hdr2->SetOctal(TAR_MODE, 0600); + strcpy(m_hdr2->Get(TAR_UID), m_hdr->Get(TAR_UID)); + strcpy(m_hdr2->Get(TAR_GID), m_hdr->Get(TAR_GID)); + size_t length = strlen(m_extendedHdr); + m_hdr2->SetOctal(TAR_SIZE, length); + strcpy(m_hdr2->Get(TAR_MTIME), m_hdr->Get(TAR_MTIME)); + *m_hdr2->Get(TAR_TYPEFLAG) = 'x'; + strcpy(m_hdr2->Get(TAR_MAGIC), USTAR_MAGIC); + strcpy(m_hdr2->Get(TAR_VERSION), USTAR_VERSION); + strcpy(m_hdr2->Get(TAR_UNAME), m_hdr->Get(TAR_UNAME)); + strcpy(m_hdr2->Get(TAR_GNAME), m_hdr->Get(TAR_GNAME)); + + m_hdr2->SetOctal(TAR_CHKSUM, m_hdr2->Sum()); + + m_hdr2->Write(*m_parent_o_stream); + m_tarsize += TAR_BLOCKSIZE; + + size_t rounded = RoundUpSize(length); + memset(m_extendedHdr + length, 0, rounded - length); + m_parent_o_stream->Write(m_extendedHdr, rounded); + m_tarsize += rounded; + + *m_extendedHdr = 0; + } + + // if don't have extended headers just report error + if (!m_badfit.empty()) { + wxASSERT(!m_pax); + wxLogWarning(_("%s did not fit the tar header for entry '%s'"), + m_badfit.c_str(), entry.GetName().c_str()); + m_badfit.clear(); + } + + m_hdr->Write(*m_parent_o_stream); + m_tarsize += TAR_BLOCKSIZE; + m_lasterror = m_parent_o_stream->GetLastError(); + + return IsOk(); +} + +wxString wxTarOutputStream::PaxHeaderPath(const wxString& format, + const wxString& path) +{ + wxString d = path.BeforeLast(_T('/')); + wxString f = path.AfterLast(_T('/')); + wxString ret; + + if (d.empty()) + d = _T("."); + + ret.reserve(format.length() + path.length() + 16); + + size_t begin = 0; + size_t end; + + for (;;) { + end = format.find('%', begin); + if (end == wxString::npos || end + 1 >= format.length()) + break; + ret << format.substr(begin, end - begin); + switch (format[end + 1]) { + case 'd': ret << d; break; + case 'f': ret << f; break; + case 'p': ret << wxGetProcessId(); break; + case '%': ret << _T("%"); break; + } + begin = end + 2; + } + + ret << format.substr(begin); + + return ret; +} + +bool wxTarOutputStream::ModifyHeader() +{ + wxFileOffset originalPos = wxInvalidOffset; + wxFileOffset sizePos = wxInvalidOffset; + + if (!m_large && m_headpos != wxInvalidOffset + && m_parent_o_stream->IsSeekable()) + { + wxLogNull nolog; + originalPos = m_parent_o_stream->TellO(); + if (originalPos != wxInvalidOffset) + sizePos = + m_parent_o_stream->SeekO(m_headpos + m_hdr->Offset(TAR_SIZE)); + } + + if (sizePos == wxInvalidOffset || !m_hdr->SetOctal(TAR_SIZE, m_pos)) { + wxLogError(_("incorrect size given for tar entry")); + m_lasterror = wxSTREAM_WRITE_ERROR; + return false; + } + + m_chksum += m_hdr->SumField(TAR_SIZE); + m_hdr->SetOctal(TAR_CHKSUM, m_chksum); + wxFileOffset sumPos = m_headpos + m_hdr->Offset(TAR_CHKSUM); + + return + m_hdr->WriteField(*m_parent_o_stream, TAR_SIZE) && + m_parent_o_stream->SeekO(sumPos) == sumPos && + m_hdr->WriteField(*m_parent_o_stream, TAR_CHKSUM) && + m_parent_o_stream->SeekO(originalPos) == originalPos; +} + +void wxTarOutputStream::SetHeaderPath(const wxString& name) +{ + if (!m_hdr->SetPath(name, GetConv()) || (m_pax && !name.IsAscii())) + SetExtendedHeader(_T("path"), name); +} + +bool wxTarOutputStream::SetHeaderNumber(int id, wxTarNumber n) +{ + if (m_hdr->SetOctal(id, n)) { + return true; + } else { + SetExtendedHeader(m_hdr->Name(id), wxLongLong(n).ToString()); + return false; + } +} + +void wxTarOutputStream::SetHeaderString(int id, const wxString& str) +{ + strncpy(m_hdr->Get(id), str.mb_str(GetConv()), m_hdr->Len(id)); + if (str.length() > m_hdr->Len(id)) + SetExtendedHeader(m_hdr->Name(id), str); +} + +void wxTarOutputStream::SetHeaderDate(const wxString& key, + const wxDateTime& datetime) +{ + wxLongLong ll = datetime.IsValid() ? datetime.GetValue() : wxLongLong(0); + wxLongLong secs = ll / 1000L; + + if (key != _T("mtime") + || !m_hdr->SetOctal(TAR_MTIME, wxTarNumber(secs.GetValue())) + || secs <= 0 || secs >= 0x7fffffff) + { + wxString str; + if (ll >= LONG_MIN && ll <= LONG_MAX) { + str.Printf(_T("%g"), ll.ToLong() / 1000.0); + } else { + str = ll.ToString(); + str.insert(str.end() - 3, '.'); + } + SetExtendedHeader(key, str); + } +} + +void wxTarOutputStream::SetExtendedHeader(const wxString& key, + const wxString& value) +{ + if (m_pax) { + const wxWX2WCbuf wide_key = key.wc_str(GetConv()); + const wxCharBuffer utf_key = wxConvUTF8.cWC2MB(wide_key); + + const wxWX2WCbuf wide_value = value.wc_str(GetConv()); + const wxCharBuffer utf_value = wxConvUTF8.cWC2MB(wide_value); + + // a small buffer to format the length field in + char buf[32]; + // length of "99=\n" + unsigned long length = strlen(utf_value) + strlen(utf_key) + 5; + sprintf(buf, "%lu", length); + // the length includes itself + size_t lenlen = strlen(buf); + if (lenlen != 2) { + length += lenlen - 2; + sprintf(buf, "%lu", length); + if (strlen(buf) > lenlen) + sprintf(buf, "%lu", ++length); + } + + // reallocate m_extendedHdr if it's not big enough + if (m_extendedSize < length) { + size_t rounded = RoundUpSize(length); + m_extendedSize <<= 1; + if (rounded > m_extendedSize) + m_extendedSize = rounded; + char *oldHdr = m_extendedHdr; + m_extendedHdr = new char[m_extendedSize]; + if (oldHdr) { + strcpy(m_extendedHdr, oldHdr); + delete oldHdr; + } else { + *m_extendedHdr = 0; + } + } + + // append the new record + char *append = strchr(m_extendedHdr, 0); + sprintf(append, "%s %s=%s\012", buf, + (const char*)utf_key, (const char*)utf_value); + } + else { + // if not pax then make a list of fields to report as errors + if (!m_badfit.empty()) + m_badfit += _T(", "); + m_badfit += key; + } +} + +void wxTarOutputStream::Sync() +{ + m_parent_o_stream->Sync(); +} + +wxFileOffset wxTarOutputStream::OnSysSeek(wxFileOffset pos, wxSeekMode mode) +{ + if (!IsOpened()) { + wxLogError(_("tar entry not open")); + m_lasterror = wxSTREAM_WRITE_ERROR; + } + if (!IsOk() || m_datapos == wxInvalidOffset) + return wxInvalidOffset; + + switch (mode) { + case wxFromStart: break; + case wxFromCurrent: pos += m_pos; break; + case wxFromEnd: pos += m_maxpos; break; + } + + if (pos < 0 || m_parent_o_stream->SeekO(m_datapos + pos) == wxInvalidOffset) + return wxInvalidOffset; + + m_pos = pos; + return m_pos; +} + +size_t wxTarOutputStream::OnSysWrite(const void *buffer, size_t size) +{ + if (!IsOpened()) { + wxLogError(_("tar entry not open")); + m_lasterror = wxSTREAM_WRITE_ERROR; + } + if (!IsOk() || !size) + return 0; + + size_t lastwrite = m_parent_o_stream->Write(buffer, size).LastWrite(); + m_pos += lastwrite; + if (m_pos > m_maxpos) + m_maxpos = m_pos; + + if (lastwrite != size) + m_lasterror = wxSTREAM_WRITE_ERROR; + + return lastwrite; +} + +#endif // wxUSE_TARSTREAM diff --git a/Externals/wxWidgets/src/common/taskbarcmn.cpp b/Externals/wxWidgets/src/common/taskbarcmn.cpp index ef923d4d5d..def6bbdf6b 100644 --- a/Externals/wxWidgets/src/common/taskbarcmn.cpp +++ b/Externals/wxWidgets/src/common/taskbarcmn.cpp @@ -1,54 +1,54 @@ -///////////////////////////////////////////////////////////////////////// -// File: src/common/taskbarcmn.cpp -// Purpose: Common parts of wxTaskBarIcon class -// Author: Julian Smart -// Modified by: -// Created: 04/04/2003 -// RCS-ID: $Id: taskbarcmn.cpp 44138 2007-01-07 19:44:14Z VZ $ -// Copyright: (c) Julian Smart, 2003 -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#ifdef wxHAS_TASK_BAR_ICON - -#ifndef WX_PRECOMP - #include "wx/app.h" - #include "wx/menu.h" -#endif - -// DLL options compatibility check: -WX_CHECK_BUILD_OPTIONS("wxAdvanced") - -#include "wx/taskbar.h" - -DEFINE_EVENT_TYPE( wxEVT_TASKBAR_MOVE ) -DEFINE_EVENT_TYPE( wxEVT_TASKBAR_LEFT_DOWN ) -DEFINE_EVENT_TYPE( wxEVT_TASKBAR_LEFT_UP ) -DEFINE_EVENT_TYPE( wxEVT_TASKBAR_RIGHT_DOWN ) -DEFINE_EVENT_TYPE( wxEVT_TASKBAR_RIGHT_UP ) -DEFINE_EVENT_TYPE( wxEVT_TASKBAR_LEFT_DCLICK ) -DEFINE_EVENT_TYPE( wxEVT_TASKBAR_RIGHT_DCLICK ) - - -BEGIN_EVENT_TABLE(wxTaskBarIconBase, wxEvtHandler) - EVT_TASKBAR_CLICK(wxTaskBarIconBase::OnRightButtonDown) -END_EVENT_TABLE() - -void wxTaskBarIconBase::OnRightButtonDown(wxTaskBarIconEvent& WXUNUSED(event)) -{ - wxMenu *menu = CreatePopupMenu(); - if (menu) - { - PopupMenu(menu); - delete menu; - } -} - -#endif // defined(wxHAS_TASK_BAR_ICON) +///////////////////////////////////////////////////////////////////////// +// File: src/common/taskbarcmn.cpp +// Purpose: Common parts of wxTaskBarIcon class +// Author: Julian Smart +// Modified by: +// Created: 04/04/2003 +// RCS-ID: $Id: taskbarcmn.cpp 44138 2007-01-07 19:44:14Z VZ $ +// Copyright: (c) Julian Smart, 2003 +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#ifdef wxHAS_TASK_BAR_ICON + +#ifndef WX_PRECOMP + #include "wx/app.h" + #include "wx/menu.h" +#endif + +// DLL options compatibility check: +WX_CHECK_BUILD_OPTIONS("wxAdvanced") + +#include "wx/taskbar.h" + +DEFINE_EVENT_TYPE( wxEVT_TASKBAR_MOVE ) +DEFINE_EVENT_TYPE( wxEVT_TASKBAR_LEFT_DOWN ) +DEFINE_EVENT_TYPE( wxEVT_TASKBAR_LEFT_UP ) +DEFINE_EVENT_TYPE( wxEVT_TASKBAR_RIGHT_DOWN ) +DEFINE_EVENT_TYPE( wxEVT_TASKBAR_RIGHT_UP ) +DEFINE_EVENT_TYPE( wxEVT_TASKBAR_LEFT_DCLICK ) +DEFINE_EVENT_TYPE( wxEVT_TASKBAR_RIGHT_DCLICK ) + + +BEGIN_EVENT_TABLE(wxTaskBarIconBase, wxEvtHandler) + EVT_TASKBAR_CLICK(wxTaskBarIconBase::OnRightButtonDown) +END_EVENT_TABLE() + +void wxTaskBarIconBase::OnRightButtonDown(wxTaskBarIconEvent& WXUNUSED(event)) +{ + wxMenu *menu = CreatePopupMenu(); + if (menu) + { + PopupMenu(menu); + delete menu; + } +} + +#endif // defined(wxHAS_TASK_BAR_ICON) diff --git a/Externals/wxWidgets/src/common/tbarbase.cpp b/Externals/wxWidgets/src/common/tbarbase.cpp index 2b1459c6bc..084d17c064 100644 --- a/Externals/wxWidgets/src/common/tbarbase.cpp +++ b/Externals/wxWidgets/src/common/tbarbase.cpp @@ -1,746 +1,746 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/tbarbase.cpp -// Purpose: wxToolBarBase implementation -// Author: Julian Smart -// Modified by: VZ at 11.12.99 (wxScrollableToolBar split off) -// Created: 04/01/98 -// RCS-ID: $Id: tbarbase.cpp 42840 2006-10-31 13:09:08Z VZ $ -// Copyright: (c) Julian Smart -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_TOOLBAR - -#include "wx/toolbar.h" - -#ifndef WX_PRECOMP - #include "wx/control.h" - #include "wx/frame.h" - #include "wx/settings.h" - #include "wx/image.h" -#endif - -// ---------------------------------------------------------------------------- -// wxWidgets macros -// ---------------------------------------------------------------------------- - -BEGIN_EVENT_TABLE(wxToolBarBase, wxControl) -END_EVENT_TABLE() - -#include "wx/listimpl.cpp" - -WX_DEFINE_LIST(wxToolBarToolsList) - -// ============================================================================ -// implementation -// ============================================================================ - -// ---------------------------------------------------------------------------- -// wxToolBarToolBase -// ---------------------------------------------------------------------------- - -IMPLEMENT_DYNAMIC_CLASS(wxToolBarToolBase, wxObject) - -bool wxToolBarToolBase::Enable(bool enable) -{ - if ( m_enabled == enable ) - return false; - - m_enabled = enable; - - return true; -} - -bool wxToolBarToolBase::Toggle(bool toggle) -{ - wxASSERT_MSG( CanBeToggled(), _T("can't toggle this tool") ); - - if ( m_toggled == toggle ) - return false; - - m_toggled = toggle; - - return true; -} - -bool wxToolBarToolBase::SetToggle(bool toggle) -{ - wxItemKind kind = toggle ? wxITEM_CHECK : wxITEM_NORMAL; - if ( m_kind == kind ) - return false; - - m_kind = kind; - - return true; -} - -bool wxToolBarToolBase::SetShortHelp(const wxString& help) -{ - if ( m_shortHelpString == help ) - return false; - - m_shortHelpString = help; - - return true; -} - -bool wxToolBarToolBase::SetLongHelp(const wxString& help) -{ - if ( m_longHelpString == help ) - return false; - - m_longHelpString = help; - - return true; -} - -// ---------------------------------------------------------------------------- -// wxToolBarBase adding/deleting items -// ---------------------------------------------------------------------------- - -wxToolBarBase::wxToolBarBase() -{ - // the list owns the pointers - m_xMargin = m_yMargin = 0; - m_maxRows = m_maxCols = 0; - m_toolPacking = m_toolSeparation = 0; - m_defaultWidth = 16; - m_defaultHeight = 15; -} - -void wxToolBarBase::FixupStyle() -{ - if ( !HasFlag(wxTB_TOP | wxTB_LEFT | wxTB_RIGHT | wxTB_BOTTOM) ) - { - // this is the default - m_windowStyle |= wxTB_TOP; - } -} - -wxToolBarToolBase *wxToolBarBase::DoAddTool(int id, - const wxString& label, - const wxBitmap& bitmap, - const wxBitmap& bmpDisabled, - wxItemKind kind, - const wxString& shortHelp, - const wxString& longHelp, - wxObject *clientData, - wxCoord WXUNUSED(xPos), - wxCoord WXUNUSED(yPos)) -{ - InvalidateBestSize(); - return InsertTool(GetToolsCount(), id, label, bitmap, bmpDisabled, - kind, shortHelp, longHelp, clientData); -} - -wxToolBarToolBase *wxToolBarBase::InsertTool(size_t pos, - int id, - const wxString& label, - const wxBitmap& bitmap, - const wxBitmap& bmpDisabled, - wxItemKind kind, - const wxString& shortHelp, - const wxString& longHelp, - wxObject *clientData) -{ - wxCHECK_MSG( pos <= GetToolsCount(), (wxToolBarToolBase *)NULL, - _T("invalid position in wxToolBar::InsertTool()") ); - - wxToolBarToolBase *tool = CreateTool(id, label, bitmap, bmpDisabled, kind, - clientData, shortHelp, longHelp); - - if ( !InsertTool(pos, tool) ) - { - delete tool; - - return NULL; - } - - return tool; -} - -wxToolBarToolBase *wxToolBarBase::AddTool(wxToolBarToolBase *tool) -{ - return InsertTool(GetToolsCount(), tool); -} - -wxToolBarToolBase * -wxToolBarBase::InsertTool(size_t pos, wxToolBarToolBase *tool) -{ - wxCHECK_MSG( pos <= GetToolsCount(), (wxToolBarToolBase *)NULL, - _T("invalid position in wxToolBar::InsertTool()") ); - - if ( !tool || !DoInsertTool(pos, tool) ) - { - return NULL; - } - - m_tools.Insert(pos, tool); - - return tool; -} - -wxToolBarToolBase *wxToolBarBase::AddControl(wxControl *control) -{ - return InsertControl(GetToolsCount(), control); -} - -wxToolBarToolBase *wxToolBarBase::InsertControl(size_t pos, wxControl *control) -{ - wxCHECK_MSG( control, (wxToolBarToolBase *)NULL, - _T("toolbar: can't insert NULL control") ); - - wxCHECK_MSG( control->GetParent() == this, (wxToolBarToolBase *)NULL, - _T("control must have toolbar as parent") ); - - wxCHECK_MSG( pos <= GetToolsCount(), (wxToolBarToolBase *)NULL, - _T("invalid position in wxToolBar::InsertControl()") ); - - wxToolBarToolBase *tool = CreateTool(control); - - if ( !InsertTool(pos, tool) ) - { - delete tool; - - return NULL; - } - - return tool; -} - -wxControl *wxToolBarBase::FindControl( int id ) -{ - for ( wxToolBarToolsList::compatibility_iterator node = m_tools.GetFirst(); - node; - node = node->GetNext() ) - { - const wxToolBarToolBase * const tool = node->GetData(); - if ( tool->IsControl() ) - { - wxControl * const control = tool->GetControl(); - - if ( !control ) - { - wxFAIL_MSG( _T("NULL control in toolbar?") ); - } - else if ( control->GetId() == id ) - { - // found - return control; - } - } - } - - return NULL; -} - -wxToolBarToolBase *wxToolBarBase::AddSeparator() -{ - return InsertSeparator(GetToolsCount()); -} - -wxToolBarToolBase *wxToolBarBase::InsertSeparator(size_t pos) -{ - wxCHECK_MSG( pos <= GetToolsCount(), (wxToolBarToolBase *)NULL, - _T("invalid position in wxToolBar::InsertSeparator()") ); - - wxToolBarToolBase *tool = CreateTool(wxID_SEPARATOR, - wxEmptyString, - wxNullBitmap, wxNullBitmap, - wxITEM_SEPARATOR, (wxObject *)NULL, - wxEmptyString, wxEmptyString); - - if ( !tool || !DoInsertTool(pos, tool) ) - { - delete tool; - - return NULL; - } - - m_tools.Insert(pos, tool); - - return tool; -} - -wxToolBarToolBase *wxToolBarBase::RemoveTool(int id) -{ - size_t pos = 0; - wxToolBarToolsList::compatibility_iterator node; - for ( node = m_tools.GetFirst(); node; node = node->GetNext() ) - { - if ( node->GetData()->GetId() == id ) - break; - - pos++; - } - - if ( !node ) - { - // don't give any error messages - sometimes we might call RemoveTool() - // without knowing whether the tool is or not in the toolbar - return (wxToolBarToolBase *)NULL; - } - - wxToolBarToolBase *tool = node->GetData(); - if ( !DoDeleteTool(pos, tool) ) - { - return (wxToolBarToolBase *)NULL; - } - - m_tools.Erase(node); - - return tool; -} - -bool wxToolBarBase::DeleteToolByPos(size_t pos) -{ - wxCHECK_MSG( pos < GetToolsCount(), false, - _T("invalid position in wxToolBar::DeleteToolByPos()") ); - - wxToolBarToolsList::compatibility_iterator node = m_tools.Item(pos); - - if ( !DoDeleteTool(pos, node->GetData()) ) - { - return false; - } - - delete node->GetData(); - m_tools.Erase(node); - - return true; -} - -bool wxToolBarBase::DeleteTool(int id) -{ - size_t pos = 0; - wxToolBarToolsList::compatibility_iterator node; - for ( node = m_tools.GetFirst(); node; node = node->GetNext() ) - { - if ( node->GetData()->GetId() == id ) - break; - - pos++; - } - - if ( !node || !DoDeleteTool(pos, node->GetData()) ) - { - return false; - } - - delete node->GetData(); - m_tools.Erase(node); - - return true; -} - -wxToolBarToolBase *wxToolBarBase::FindById(int id) const -{ - wxToolBarToolBase *tool = (wxToolBarToolBase *)NULL; - - for ( wxToolBarToolsList::compatibility_iterator node = m_tools.GetFirst(); - node; - node = node->GetNext() ) - { - tool = node->GetData(); - if ( tool->GetId() == id ) - { - // found - break; - } - - tool = NULL; - } - - return tool; -} - -void wxToolBarBase::UnToggleRadioGroup(wxToolBarToolBase *tool) -{ - wxCHECK_RET( tool, _T("NULL tool in wxToolBarTool::UnToggleRadioGroup") ); - - if ( !tool->IsButton() || tool->GetKind() != wxITEM_RADIO ) - return; - - wxToolBarToolsList::compatibility_iterator node = m_tools.Find(tool); - wxCHECK_RET( node, _T("invalid tool in wxToolBarTool::UnToggleRadioGroup") ); - - wxToolBarToolsList::compatibility_iterator nodeNext = node->GetNext(); - while ( nodeNext ) - { - wxToolBarToolBase *toolNext = nodeNext->GetData(); - - if ( !toolNext->IsButton() || toolNext->GetKind() != wxITEM_RADIO ) - break; - - if ( toolNext->Toggle(false) ) - { - DoToggleTool(toolNext, false); - } - - nodeNext = nodeNext->GetNext(); - } - - wxToolBarToolsList::compatibility_iterator nodePrev = node->GetPrevious(); - while ( nodePrev ) - { - wxToolBarToolBase *toolNext = nodePrev->GetData(); - - if ( !toolNext->IsButton() || toolNext->GetKind() != wxITEM_RADIO ) - break; - - if ( toolNext->Toggle(false) ) - { - DoToggleTool(toolNext, false); - } - - nodePrev = nodePrev->GetPrevious(); - } -} - -void wxToolBarBase::ClearTools() -{ - while ( GetToolsCount() ) - { - DeleteToolByPos(0); - } -} - -bool wxToolBarBase::Realize() -{ - return true; -} - -wxToolBarBase::~wxToolBarBase() -{ - WX_CLEAR_LIST(wxToolBarToolsList, m_tools); - - // notify the frame that it doesn't have a tool bar any longer to avoid - // dangling pointers - wxFrame *frame = wxDynamicCast(GetParent(), wxFrame); - if ( frame && frame->GetToolBar() == this ) - { - frame->SetToolBar(NULL); - } -} - -// ---------------------------------------------------------------------------- -// wxToolBarBase tools state -// ---------------------------------------------------------------------------- - -void wxToolBarBase::EnableTool(int id, bool enable) -{ - wxToolBarToolBase *tool = FindById(id); - if ( tool ) - { - if ( tool->Enable(enable) ) - { - DoEnableTool(tool, enable); - } - } -} - -void wxToolBarBase::ToggleTool(int id, bool toggle) -{ - wxToolBarToolBase *tool = FindById(id); - if ( tool && tool->CanBeToggled() ) - { - if ( tool->Toggle(toggle) ) - { - UnToggleRadioGroup(tool); - DoToggleTool(tool, toggle); - } - } -} - -void wxToolBarBase::SetToggle(int id, bool toggle) -{ - wxToolBarToolBase *tool = FindById(id); - if ( tool ) - { - if ( tool->SetToggle(toggle) ) - { - DoSetToggle(tool, toggle); - } - } -} - -void wxToolBarBase::SetToolShortHelp(int id, const wxString& help) -{ - wxToolBarToolBase *tool = FindById(id); - if ( tool ) - { - (void)tool->SetShortHelp(help); - } -} - -void wxToolBarBase::SetToolLongHelp(int id, const wxString& help) -{ - wxToolBarToolBase *tool = FindById(id); - if ( tool ) - { - (void)tool->SetLongHelp(help); - } -} - -wxObject *wxToolBarBase::GetToolClientData(int id) const -{ - wxToolBarToolBase *tool = FindById(id); - - return tool ? tool->GetClientData() : (wxObject *)NULL; -} - -void wxToolBarBase::SetToolClientData(int id, wxObject *clientData) -{ - wxToolBarToolBase *tool = FindById(id); - - wxCHECK_RET( tool, _T("no such tool in wxToolBar::SetToolClientData") ); - - tool->SetClientData(clientData); -} - -int wxToolBarBase::GetToolPos(int id) const -{ - size_t pos = 0; - wxToolBarToolsList::compatibility_iterator node; - - for ( node = m_tools.GetFirst(); node; node = node->GetNext() ) - { - if ( node->GetData()->GetId() == id ) - return pos; - - pos++; - } - - return wxNOT_FOUND; -} - -bool wxToolBarBase::GetToolState(int id) const -{ - wxToolBarToolBase *tool = FindById(id); - wxCHECK_MSG( tool, false, _T("no such tool") ); - - return tool->IsToggled(); -} - -bool wxToolBarBase::GetToolEnabled(int id) const -{ - wxToolBarToolBase *tool = FindById(id); - wxCHECK_MSG( tool, false, _T("no such tool") ); - - return tool->IsEnabled(); -} - -wxString wxToolBarBase::GetToolShortHelp(int id) const -{ - wxToolBarToolBase *tool = FindById(id); - wxCHECK_MSG( tool, wxEmptyString, _T("no such tool") ); - - return tool->GetShortHelp(); -} - -wxString wxToolBarBase::GetToolLongHelp(int id) const -{ - wxToolBarToolBase *tool = FindById(id); - wxCHECK_MSG( tool, wxEmptyString, _T("no such tool") ); - - return tool->GetLongHelp(); -} - -// ---------------------------------------------------------------------------- -// wxToolBarBase geometry -// ---------------------------------------------------------------------------- - -void wxToolBarBase::SetMargins(int x, int y) -{ - m_xMargin = x; - m_yMargin = y; -} - -void wxToolBarBase::SetRows(int WXUNUSED(nRows)) -{ - // nothing -} - -// ---------------------------------------------------------------------------- -// event processing -// ---------------------------------------------------------------------------- - -// Only allow toggle if returns true -bool wxToolBarBase::OnLeftClick(int id, bool toggleDown) -{ - wxCommandEvent event(wxEVT_COMMAND_TOOL_CLICKED, id); - event.SetEventObject(this); - - // we use SetInt() to make wxCommandEvent::IsChecked() return toggleDown - event.SetInt((int)toggleDown); - - // and SetExtraLong() for backwards compatibility - event.SetExtraLong((long)toggleDown); - - // Send events to this toolbar instead (and thence up the window hierarchy) - GetEventHandler()->ProcessEvent(event); - - return true; -} - -// Call when right button down. -void wxToolBarBase::OnRightClick(int id, - long WXUNUSED(x), - long WXUNUSED(y)) -{ - wxCommandEvent event(wxEVT_COMMAND_TOOL_RCLICKED, id); - event.SetEventObject(this); - event.SetInt(id); - - GetEventHandler()->ProcessEvent(event); -} - -// Called when the mouse cursor enters a tool bitmap (no button pressed). -// Argument is wxID_ANY if mouse is exiting the toolbar. -// Note that for this event, the id of the window is used, -// and the integer parameter of wxCommandEvent is used to retrieve -// the tool id. -void wxToolBarBase::OnMouseEnter(int id) -{ - wxCommandEvent event(wxEVT_COMMAND_TOOL_ENTER, GetId()); - event.SetEventObject(this); - event.SetInt(id); - - wxFrame *frame = wxDynamicCast(GetParent(), wxFrame); - if( frame ) - { - wxString help; - wxToolBarToolBase* tool = id == wxID_ANY ? (wxToolBarToolBase*)NULL : FindById(id); - if(tool) - help = tool->GetLongHelp(); - frame->DoGiveHelp( help, id != wxID_ANY ); - } - - (void)GetEventHandler()->ProcessEvent(event); -} - -// ---------------------------------------------------------------------------- -// UI updates -// ---------------------------------------------------------------------------- - -// Do the toolbar button updates (check for EVT_UPDATE_UI handlers) -void wxToolBarBase::UpdateWindowUI(long flags) -{ - wxWindowBase::UpdateWindowUI(flags); - - // There is no sense in updating the toolbar UI - // if the parent window is about to get destroyed - wxWindow *tlw = wxGetTopLevelParent( this ); - if (tlw && wxPendingDelete.Member( tlw )) - return; - - wxEvtHandler* evtHandler = GetEventHandler() ; - - for ( wxToolBarToolsList::compatibility_iterator node = m_tools.GetFirst(); - node; - node = node->GetNext() ) - { - int id = node->GetData()->GetId(); - - wxUpdateUIEvent event(id); - event.SetEventObject(this); - - if ( evtHandler->ProcessEvent(event) ) - { - if ( event.GetSetEnabled() ) - EnableTool(id, event.GetEnabled()); - if ( event.GetSetChecked() ) - ToggleTool(id, event.GetChecked()); -#if 0 - if ( event.GetSetText() ) - // Set tooltip? -#endif // 0 - } - } -} - -#if wxUSE_IMAGE - -/* - * Make a greyed-out image suitable for disabled buttons. - * This code is adapted from wxNewBitmapButton in FL. - */ - -bool wxCreateGreyedImage(const wxImage& src, wxImage& dst) -{ - dst = src.Copy(); - - unsigned char rBg, gBg, bBg; - if ( src.HasMask() ) - { - src.GetOrFindMaskColour(&rBg, &gBg, &bBg); - dst.SetMaskColour(rBg, gBg, bBg); - } - else // assuming the pixels along the edges are of the background color - { - rBg = src.GetRed(0, 0); - gBg = src.GetGreen(0, 0); - bBg = src.GetBlue(0, 0); - } - - const wxColour colBg(rBg, gBg, bBg); - - const wxColour colDark = wxSystemSettings::GetColour(wxSYS_COLOUR_3DSHADOW); - const wxColour colLight = wxSystemSettings::GetColour(wxSYS_COLOUR_3DHIGHLIGHT); - - // Second attempt, just making things monochrome - const int width = src.GetWidth(); - const int height = src.GetHeight(); - - for ( int x = 0; x < width; x++ ) - { - for ( int y = 0; y < height; y++ ) - { - const int r = src.GetRed(x, y); - const int g = src.GetGreen(x, y); - const int b = src.GetBlue(x, y); - - if ( r == rBg && g == gBg && b == bBg ) - { - // Leave the background colour as-is - continue; - } - - // Change light things to the background colour - wxColour col; - if ( r >= (colLight.Red() - 50) && - g >= (colLight.Green() - 50) && - b >= (colLight.Blue() - 50) ) - { - col = colBg; - } - else // Change dark things to really dark - { - col = colDark; - } - - dst.SetRGB(x, y, col.Red(), col.Green(), col.Blue()); - } - } - - return true; -} - -#endif // wxUSE_IMAGE - -#endif // wxUSE_TOOLBAR +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/tbarbase.cpp +// Purpose: wxToolBarBase implementation +// Author: Julian Smart +// Modified by: VZ at 11.12.99 (wxScrollableToolBar split off) +// Created: 04/01/98 +// RCS-ID: $Id: tbarbase.cpp 42840 2006-10-31 13:09:08Z VZ $ +// Copyright: (c) Julian Smart +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_TOOLBAR + +#include "wx/toolbar.h" + +#ifndef WX_PRECOMP + #include "wx/control.h" + #include "wx/frame.h" + #include "wx/settings.h" + #include "wx/image.h" +#endif + +// ---------------------------------------------------------------------------- +// wxWidgets macros +// ---------------------------------------------------------------------------- + +BEGIN_EVENT_TABLE(wxToolBarBase, wxControl) +END_EVENT_TABLE() + +#include "wx/listimpl.cpp" + +WX_DEFINE_LIST(wxToolBarToolsList) + +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// wxToolBarToolBase +// ---------------------------------------------------------------------------- + +IMPLEMENT_DYNAMIC_CLASS(wxToolBarToolBase, wxObject) + +bool wxToolBarToolBase::Enable(bool enable) +{ + if ( m_enabled == enable ) + return false; + + m_enabled = enable; + + return true; +} + +bool wxToolBarToolBase::Toggle(bool toggle) +{ + wxASSERT_MSG( CanBeToggled(), _T("can't toggle this tool") ); + + if ( m_toggled == toggle ) + return false; + + m_toggled = toggle; + + return true; +} + +bool wxToolBarToolBase::SetToggle(bool toggle) +{ + wxItemKind kind = toggle ? wxITEM_CHECK : wxITEM_NORMAL; + if ( m_kind == kind ) + return false; + + m_kind = kind; + + return true; +} + +bool wxToolBarToolBase::SetShortHelp(const wxString& help) +{ + if ( m_shortHelpString == help ) + return false; + + m_shortHelpString = help; + + return true; +} + +bool wxToolBarToolBase::SetLongHelp(const wxString& help) +{ + if ( m_longHelpString == help ) + return false; + + m_longHelpString = help; + + return true; +} + +// ---------------------------------------------------------------------------- +// wxToolBarBase adding/deleting items +// ---------------------------------------------------------------------------- + +wxToolBarBase::wxToolBarBase() +{ + // the list owns the pointers + m_xMargin = m_yMargin = 0; + m_maxRows = m_maxCols = 0; + m_toolPacking = m_toolSeparation = 0; + m_defaultWidth = 16; + m_defaultHeight = 15; +} + +void wxToolBarBase::FixupStyle() +{ + if ( !HasFlag(wxTB_TOP | wxTB_LEFT | wxTB_RIGHT | wxTB_BOTTOM) ) + { + // this is the default + m_windowStyle |= wxTB_TOP; + } +} + +wxToolBarToolBase *wxToolBarBase::DoAddTool(int id, + const wxString& label, + const wxBitmap& bitmap, + const wxBitmap& bmpDisabled, + wxItemKind kind, + const wxString& shortHelp, + const wxString& longHelp, + wxObject *clientData, + wxCoord WXUNUSED(xPos), + wxCoord WXUNUSED(yPos)) +{ + InvalidateBestSize(); + return InsertTool(GetToolsCount(), id, label, bitmap, bmpDisabled, + kind, shortHelp, longHelp, clientData); +} + +wxToolBarToolBase *wxToolBarBase::InsertTool(size_t pos, + int id, + const wxString& label, + const wxBitmap& bitmap, + const wxBitmap& bmpDisabled, + wxItemKind kind, + const wxString& shortHelp, + const wxString& longHelp, + wxObject *clientData) +{ + wxCHECK_MSG( pos <= GetToolsCount(), (wxToolBarToolBase *)NULL, + _T("invalid position in wxToolBar::InsertTool()") ); + + wxToolBarToolBase *tool = CreateTool(id, label, bitmap, bmpDisabled, kind, + clientData, shortHelp, longHelp); + + if ( !InsertTool(pos, tool) ) + { + delete tool; + + return NULL; + } + + return tool; +} + +wxToolBarToolBase *wxToolBarBase::AddTool(wxToolBarToolBase *tool) +{ + return InsertTool(GetToolsCount(), tool); +} + +wxToolBarToolBase * +wxToolBarBase::InsertTool(size_t pos, wxToolBarToolBase *tool) +{ + wxCHECK_MSG( pos <= GetToolsCount(), (wxToolBarToolBase *)NULL, + _T("invalid position in wxToolBar::InsertTool()") ); + + if ( !tool || !DoInsertTool(pos, tool) ) + { + return NULL; + } + + m_tools.Insert(pos, tool); + + return tool; +} + +wxToolBarToolBase *wxToolBarBase::AddControl(wxControl *control) +{ + return InsertControl(GetToolsCount(), control); +} + +wxToolBarToolBase *wxToolBarBase::InsertControl(size_t pos, wxControl *control) +{ + wxCHECK_MSG( control, (wxToolBarToolBase *)NULL, + _T("toolbar: can't insert NULL control") ); + + wxCHECK_MSG( control->GetParent() == this, (wxToolBarToolBase *)NULL, + _T("control must have toolbar as parent") ); + + wxCHECK_MSG( pos <= GetToolsCount(), (wxToolBarToolBase *)NULL, + _T("invalid position in wxToolBar::InsertControl()") ); + + wxToolBarToolBase *tool = CreateTool(control); + + if ( !InsertTool(pos, tool) ) + { + delete tool; + + return NULL; + } + + return tool; +} + +wxControl *wxToolBarBase::FindControl( int id ) +{ + for ( wxToolBarToolsList::compatibility_iterator node = m_tools.GetFirst(); + node; + node = node->GetNext() ) + { + const wxToolBarToolBase * const tool = node->GetData(); + if ( tool->IsControl() ) + { + wxControl * const control = tool->GetControl(); + + if ( !control ) + { + wxFAIL_MSG( _T("NULL control in toolbar?") ); + } + else if ( control->GetId() == id ) + { + // found + return control; + } + } + } + + return NULL; +} + +wxToolBarToolBase *wxToolBarBase::AddSeparator() +{ + return InsertSeparator(GetToolsCount()); +} + +wxToolBarToolBase *wxToolBarBase::InsertSeparator(size_t pos) +{ + wxCHECK_MSG( pos <= GetToolsCount(), (wxToolBarToolBase *)NULL, + _T("invalid position in wxToolBar::InsertSeparator()") ); + + wxToolBarToolBase *tool = CreateTool(wxID_SEPARATOR, + wxEmptyString, + wxNullBitmap, wxNullBitmap, + wxITEM_SEPARATOR, (wxObject *)NULL, + wxEmptyString, wxEmptyString); + + if ( !tool || !DoInsertTool(pos, tool) ) + { + delete tool; + + return NULL; + } + + m_tools.Insert(pos, tool); + + return tool; +} + +wxToolBarToolBase *wxToolBarBase::RemoveTool(int id) +{ + size_t pos = 0; + wxToolBarToolsList::compatibility_iterator node; + for ( node = m_tools.GetFirst(); node; node = node->GetNext() ) + { + if ( node->GetData()->GetId() == id ) + break; + + pos++; + } + + if ( !node ) + { + // don't give any error messages - sometimes we might call RemoveTool() + // without knowing whether the tool is or not in the toolbar + return (wxToolBarToolBase *)NULL; + } + + wxToolBarToolBase *tool = node->GetData(); + if ( !DoDeleteTool(pos, tool) ) + { + return (wxToolBarToolBase *)NULL; + } + + m_tools.Erase(node); + + return tool; +} + +bool wxToolBarBase::DeleteToolByPos(size_t pos) +{ + wxCHECK_MSG( pos < GetToolsCount(), false, + _T("invalid position in wxToolBar::DeleteToolByPos()") ); + + wxToolBarToolsList::compatibility_iterator node = m_tools.Item(pos); + + if ( !DoDeleteTool(pos, node->GetData()) ) + { + return false; + } + + delete node->GetData(); + m_tools.Erase(node); + + return true; +} + +bool wxToolBarBase::DeleteTool(int id) +{ + size_t pos = 0; + wxToolBarToolsList::compatibility_iterator node; + for ( node = m_tools.GetFirst(); node; node = node->GetNext() ) + { + if ( node->GetData()->GetId() == id ) + break; + + pos++; + } + + if ( !node || !DoDeleteTool(pos, node->GetData()) ) + { + return false; + } + + delete node->GetData(); + m_tools.Erase(node); + + return true; +} + +wxToolBarToolBase *wxToolBarBase::FindById(int id) const +{ + wxToolBarToolBase *tool = (wxToolBarToolBase *)NULL; + + for ( wxToolBarToolsList::compatibility_iterator node = m_tools.GetFirst(); + node; + node = node->GetNext() ) + { + tool = node->GetData(); + if ( tool->GetId() == id ) + { + // found + break; + } + + tool = NULL; + } + + return tool; +} + +void wxToolBarBase::UnToggleRadioGroup(wxToolBarToolBase *tool) +{ + wxCHECK_RET( tool, _T("NULL tool in wxToolBarTool::UnToggleRadioGroup") ); + + if ( !tool->IsButton() || tool->GetKind() != wxITEM_RADIO ) + return; + + wxToolBarToolsList::compatibility_iterator node = m_tools.Find(tool); + wxCHECK_RET( node, _T("invalid tool in wxToolBarTool::UnToggleRadioGroup") ); + + wxToolBarToolsList::compatibility_iterator nodeNext = node->GetNext(); + while ( nodeNext ) + { + wxToolBarToolBase *toolNext = nodeNext->GetData(); + + if ( !toolNext->IsButton() || toolNext->GetKind() != wxITEM_RADIO ) + break; + + if ( toolNext->Toggle(false) ) + { + DoToggleTool(toolNext, false); + } + + nodeNext = nodeNext->GetNext(); + } + + wxToolBarToolsList::compatibility_iterator nodePrev = node->GetPrevious(); + while ( nodePrev ) + { + wxToolBarToolBase *toolNext = nodePrev->GetData(); + + if ( !toolNext->IsButton() || toolNext->GetKind() != wxITEM_RADIO ) + break; + + if ( toolNext->Toggle(false) ) + { + DoToggleTool(toolNext, false); + } + + nodePrev = nodePrev->GetPrevious(); + } +} + +void wxToolBarBase::ClearTools() +{ + while ( GetToolsCount() ) + { + DeleteToolByPos(0); + } +} + +bool wxToolBarBase::Realize() +{ + return true; +} + +wxToolBarBase::~wxToolBarBase() +{ + WX_CLEAR_LIST(wxToolBarToolsList, m_tools); + + // notify the frame that it doesn't have a tool bar any longer to avoid + // dangling pointers + wxFrame *frame = wxDynamicCast(GetParent(), wxFrame); + if ( frame && frame->GetToolBar() == this ) + { + frame->SetToolBar(NULL); + } +} + +// ---------------------------------------------------------------------------- +// wxToolBarBase tools state +// ---------------------------------------------------------------------------- + +void wxToolBarBase::EnableTool(int id, bool enable) +{ + wxToolBarToolBase *tool = FindById(id); + if ( tool ) + { + if ( tool->Enable(enable) ) + { + DoEnableTool(tool, enable); + } + } +} + +void wxToolBarBase::ToggleTool(int id, bool toggle) +{ + wxToolBarToolBase *tool = FindById(id); + if ( tool && tool->CanBeToggled() ) + { + if ( tool->Toggle(toggle) ) + { + UnToggleRadioGroup(tool); + DoToggleTool(tool, toggle); + } + } +} + +void wxToolBarBase::SetToggle(int id, bool toggle) +{ + wxToolBarToolBase *tool = FindById(id); + if ( tool ) + { + if ( tool->SetToggle(toggle) ) + { + DoSetToggle(tool, toggle); + } + } +} + +void wxToolBarBase::SetToolShortHelp(int id, const wxString& help) +{ + wxToolBarToolBase *tool = FindById(id); + if ( tool ) + { + (void)tool->SetShortHelp(help); + } +} + +void wxToolBarBase::SetToolLongHelp(int id, const wxString& help) +{ + wxToolBarToolBase *tool = FindById(id); + if ( tool ) + { + (void)tool->SetLongHelp(help); + } +} + +wxObject *wxToolBarBase::GetToolClientData(int id) const +{ + wxToolBarToolBase *tool = FindById(id); + + return tool ? tool->GetClientData() : (wxObject *)NULL; +} + +void wxToolBarBase::SetToolClientData(int id, wxObject *clientData) +{ + wxToolBarToolBase *tool = FindById(id); + + wxCHECK_RET( tool, _T("no such tool in wxToolBar::SetToolClientData") ); + + tool->SetClientData(clientData); +} + +int wxToolBarBase::GetToolPos(int id) const +{ + size_t pos = 0; + wxToolBarToolsList::compatibility_iterator node; + + for ( node = m_tools.GetFirst(); node; node = node->GetNext() ) + { + if ( node->GetData()->GetId() == id ) + return pos; + + pos++; + } + + return wxNOT_FOUND; +} + +bool wxToolBarBase::GetToolState(int id) const +{ + wxToolBarToolBase *tool = FindById(id); + wxCHECK_MSG( tool, false, _T("no such tool") ); + + return tool->IsToggled(); +} + +bool wxToolBarBase::GetToolEnabled(int id) const +{ + wxToolBarToolBase *tool = FindById(id); + wxCHECK_MSG( tool, false, _T("no such tool") ); + + return tool->IsEnabled(); +} + +wxString wxToolBarBase::GetToolShortHelp(int id) const +{ + wxToolBarToolBase *tool = FindById(id); + wxCHECK_MSG( tool, wxEmptyString, _T("no such tool") ); + + return tool->GetShortHelp(); +} + +wxString wxToolBarBase::GetToolLongHelp(int id) const +{ + wxToolBarToolBase *tool = FindById(id); + wxCHECK_MSG( tool, wxEmptyString, _T("no such tool") ); + + return tool->GetLongHelp(); +} + +// ---------------------------------------------------------------------------- +// wxToolBarBase geometry +// ---------------------------------------------------------------------------- + +void wxToolBarBase::SetMargins(int x, int y) +{ + m_xMargin = x; + m_yMargin = y; +} + +void wxToolBarBase::SetRows(int WXUNUSED(nRows)) +{ + // nothing +} + +// ---------------------------------------------------------------------------- +// event processing +// ---------------------------------------------------------------------------- + +// Only allow toggle if returns true +bool wxToolBarBase::OnLeftClick(int id, bool toggleDown) +{ + wxCommandEvent event(wxEVT_COMMAND_TOOL_CLICKED, id); + event.SetEventObject(this); + + // we use SetInt() to make wxCommandEvent::IsChecked() return toggleDown + event.SetInt((int)toggleDown); + + // and SetExtraLong() for backwards compatibility + event.SetExtraLong((long)toggleDown); + + // Send events to this toolbar instead (and thence up the window hierarchy) + GetEventHandler()->ProcessEvent(event); + + return true; +} + +// Call when right button down. +void wxToolBarBase::OnRightClick(int id, + long WXUNUSED(x), + long WXUNUSED(y)) +{ + wxCommandEvent event(wxEVT_COMMAND_TOOL_RCLICKED, id); + event.SetEventObject(this); + event.SetInt(id); + + GetEventHandler()->ProcessEvent(event); +} + +// Called when the mouse cursor enters a tool bitmap (no button pressed). +// Argument is wxID_ANY if mouse is exiting the toolbar. +// Note that for this event, the id of the window is used, +// and the integer parameter of wxCommandEvent is used to retrieve +// the tool id. +void wxToolBarBase::OnMouseEnter(int id) +{ + wxCommandEvent event(wxEVT_COMMAND_TOOL_ENTER, GetId()); + event.SetEventObject(this); + event.SetInt(id); + + wxFrame *frame = wxDynamicCast(GetParent(), wxFrame); + if( frame ) + { + wxString help; + wxToolBarToolBase* tool = id == wxID_ANY ? (wxToolBarToolBase*)NULL : FindById(id); + if(tool) + help = tool->GetLongHelp(); + frame->DoGiveHelp( help, id != wxID_ANY ); + } + + (void)GetEventHandler()->ProcessEvent(event); +} + +// ---------------------------------------------------------------------------- +// UI updates +// ---------------------------------------------------------------------------- + +// Do the toolbar button updates (check for EVT_UPDATE_UI handlers) +void wxToolBarBase::UpdateWindowUI(long flags) +{ + wxWindowBase::UpdateWindowUI(flags); + + // There is no sense in updating the toolbar UI + // if the parent window is about to get destroyed + wxWindow *tlw = wxGetTopLevelParent( this ); + if (tlw && wxPendingDelete.Member( tlw )) + return; + + wxEvtHandler* evtHandler = GetEventHandler() ; + + for ( wxToolBarToolsList::compatibility_iterator node = m_tools.GetFirst(); + node; + node = node->GetNext() ) + { + int id = node->GetData()->GetId(); + + wxUpdateUIEvent event(id); + event.SetEventObject(this); + + if ( evtHandler->ProcessEvent(event) ) + { + if ( event.GetSetEnabled() ) + EnableTool(id, event.GetEnabled()); + if ( event.GetSetChecked() ) + ToggleTool(id, event.GetChecked()); +#if 0 + if ( event.GetSetText() ) + // Set tooltip? +#endif // 0 + } + } +} + +#if wxUSE_IMAGE + +/* + * Make a greyed-out image suitable for disabled buttons. + * This code is adapted from wxNewBitmapButton in FL. + */ + +bool wxCreateGreyedImage(const wxImage& src, wxImage& dst) +{ + dst = src.Copy(); + + unsigned char rBg, gBg, bBg; + if ( src.HasMask() ) + { + src.GetOrFindMaskColour(&rBg, &gBg, &bBg); + dst.SetMaskColour(rBg, gBg, bBg); + } + else // assuming the pixels along the edges are of the background color + { + rBg = src.GetRed(0, 0); + gBg = src.GetGreen(0, 0); + bBg = src.GetBlue(0, 0); + } + + const wxColour colBg(rBg, gBg, bBg); + + const wxColour colDark = wxSystemSettings::GetColour(wxSYS_COLOUR_3DSHADOW); + const wxColour colLight = wxSystemSettings::GetColour(wxSYS_COLOUR_3DHIGHLIGHT); + + // Second attempt, just making things monochrome + const int width = src.GetWidth(); + const int height = src.GetHeight(); + + for ( int x = 0; x < width; x++ ) + { + for ( int y = 0; y < height; y++ ) + { + const int r = src.GetRed(x, y); + const int g = src.GetGreen(x, y); + const int b = src.GetBlue(x, y); + + if ( r == rBg && g == gBg && b == bBg ) + { + // Leave the background colour as-is + continue; + } + + // Change light things to the background colour + wxColour col; + if ( r >= (colLight.Red() - 50) && + g >= (colLight.Green() - 50) && + b >= (colLight.Blue() - 50) ) + { + col = colBg; + } + else // Change dark things to really dark + { + col = colDark; + } + + dst.SetRGB(x, y, col.Red(), col.Green(), col.Blue()); + } + } + + return true; +} + +#endif // wxUSE_IMAGE + +#endif // wxUSE_TOOLBAR diff --git a/Externals/wxWidgets/src/common/textbuf.cpp b/Externals/wxWidgets/src/common/textbuf.cpp index 7aab707430..6f97b98ca3 100644 --- a/Externals/wxWidgets/src/common/textbuf.cpp +++ b/Externals/wxWidgets/src/common/textbuf.cpp @@ -1,284 +1,284 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: src/common/textbuf.cpp -// Purpose: implementation of wxTextBuffer class -// Created: 14.11.01 -// Author: Morten Hanssen, Vadim Zeitlin -// RCS-ID: $Id: textbuf.cpp 38570 2006-04-05 14:37:47Z VZ $ -// Copyright: (c) 1998-2001 wxWidgets team -// Licence: wxWindows licence -/////////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// headers -// ============================================================================ - -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif //__BORLANDC__ - -#ifndef WX_PRECOMP - #include "wx/string.h" - #include "wx/intl.h" - #include "wx/log.h" -#endif - -#include "wx/textbuf.h" - -// ============================================================================ -// wxTextBuffer class implementation -// ============================================================================ - -// ---------------------------------------------------------------------------- -// static methods (always compiled in) -// ---------------------------------------------------------------------------- - -// default type is the native one -// the native type under Mac OS X is: -// - Unix when compiling with the Apple Developer Tools (__UNIX__) -// - Mac when compiling with CodeWarrior (__WXMAC__) - -const wxTextFileType wxTextBuffer::typeDefault = -#if defined(__WINDOWS__) || defined(__DOS__) || defined(__PALMOS__) - wxTextFileType_Dos; -#elif defined(__UNIX__) - wxTextFileType_Unix; -#elif defined(__WXMAC__) - wxTextFileType_Mac; -#elif defined(__OS2__) - wxTextFileType_Os2; -#else - wxTextFileType_None; - #error "wxTextBuffer: unsupported platform." -#endif - -const wxChar *wxTextBuffer::GetEOL(wxTextFileType type) -{ - switch ( type ) { - default: - wxFAIL_MSG(wxT("bad buffer type in wxTextBuffer::GetEOL.")); - // fall through nevertheless - we must return something... - - case wxTextFileType_None: return wxEmptyString; - case wxTextFileType_Unix: return wxT("\n"); - case wxTextFileType_Dos: return wxT("\r\n"); - case wxTextFileType_Mac: return wxT("\r"); - } -} - -wxString wxTextBuffer::Translate(const wxString& text, wxTextFileType type) -{ - // don't do anything if there is nothing to do - if ( type == wxTextFileType_None ) - return text; - - // nor if it is empty - if ( text.empty() ) - return text; - - wxString eol = GetEOL(type), result; - - // optimization: we know that the length of the new string will be about - // the same as the length of the old one, so prealloc memory to aviod - // unnecessary relocations - result.Alloc(text.Len()); - - wxChar chLast = 0; - for ( const wxChar *pc = text.c_str(); *pc; pc++ ) - { - wxChar ch = *pc; - switch ( ch ) { - case _T('\n'): - // Dos/Unix line termination - result += eol; - chLast = 0; - break; - - case _T('\r'): - if ( chLast == _T('\r') ) { - // Mac empty line - result += eol; - } - else { - // just remember it: we don't know whether it is just "\r" - // or "\r\n" yet - chLast = _T('\r'); - } - break; - - default: - if ( chLast == _T('\r') ) { - // Mac line termination - result += eol; - - // reset chLast to avoid inserting another eol before the - // next character - chLast = 0; - } - - // add to the current line - result += ch; - } - } - - if ( chLast ) { - // trailing '\r' - result += eol; - } - - return result; -} - -#if wxUSE_TEXTBUFFER - -wxString wxTextBuffer::ms_eof; - -// ---------------------------------------------------------------------------- -// ctors & dtor -// ---------------------------------------------------------------------------- - -wxTextBuffer::wxTextBuffer(const wxString& strBufferName) - : m_strBufferName(strBufferName) -{ - m_nCurLine = 0; - m_isOpened = false; -} - -wxTextBuffer::~wxTextBuffer() -{ - // required here for Darwin -} - -// ---------------------------------------------------------------------------- -// buffer operations -// ---------------------------------------------------------------------------- - -bool wxTextBuffer::Exists() const -{ - return OnExists(); -} - -bool wxTextBuffer::Create(const wxString& strBufferName) -{ - m_strBufferName = strBufferName; - - return Create(); -} - -bool wxTextBuffer::Create() -{ - // buffer name must be either given in ctor or in Create(const wxString&) - wxASSERT( !m_strBufferName.empty() ); - - // if the buffer already exists do nothing - if ( Exists() ) return false; - - if ( !OnOpen(m_strBufferName, WriteAccess) ) - return false; - - OnClose(); - return true; -} - -bool wxTextBuffer::Open(const wxString& strBufferName, const wxMBConv& conv) -{ - m_strBufferName = strBufferName; - - return Open(conv); -} - -bool wxTextBuffer::Open(const wxMBConv& conv) -{ - // buffer name must be either given in ctor or in Open(const wxString&) - wxASSERT( !m_strBufferName.empty() ); - - // open buffer in read-only mode - if ( !OnOpen(m_strBufferName, ReadAccess) ) - return false; - - // read buffer into memory - m_isOpened = OnRead(conv); - - OnClose(); - - return m_isOpened; -} - -// analyse some lines of the buffer trying to guess it's type. -// if it fails, it assumes the native type for our platform. -wxTextFileType wxTextBuffer::GuessType() const -{ - wxASSERT( IsOpened() ); - - // scan the buffer lines - size_t nUnix = 0, // number of '\n's alone - nDos = 0, // number of '\r\n' - nMac = 0; // number of '\r's - - // we take MAX_LINES_SCAN in the beginning, middle and the end of buffer - #define MAX_LINES_SCAN (10) - size_t nCount = m_aLines.Count() / 3, - nScan = nCount > 3*MAX_LINES_SCAN ? MAX_LINES_SCAN : nCount / 3; - - #define AnalyseLine(n) \ - switch ( m_aTypes[n] ) { \ - case wxTextFileType_Unix: nUnix++; break; \ - case wxTextFileType_Dos: nDos++; break; \ - case wxTextFileType_Mac: nMac++; break; \ - default: wxFAIL_MSG(_("unknown line terminator")); \ - } - - size_t n; - for ( n = 0; n < nScan; n++ ) // the beginning - AnalyseLine(n); - for ( n = (nCount - nScan)/2; n < (nCount + nScan)/2; n++ ) - AnalyseLine(n); - for ( n = nCount - nScan; n < nCount; n++ ) - AnalyseLine(n); - - #undef AnalyseLine - - // interpret the results (FIXME far from being even 50% fool proof) - if ( nScan > 0 && nDos + nUnix + nMac == 0 ) { - // no newlines at all - wxLogWarning(_("'%s' is probably a binary buffer."), m_strBufferName.c_str()); - } - else { - #define GREATER_OF(t1, t2) n##t1 == n##t2 ? typeDefault \ - : n##t1 > n##t2 \ - ? wxTextFileType_##t1 \ - : wxTextFileType_##t2 - -#if !defined(__WATCOMC__) || wxCHECK_WATCOM_VERSION(1,4) - if ( nDos > nUnix ) - return GREATER_OF(Dos, Mac); - else if ( nDos < nUnix ) - return GREATER_OF(Unix, Mac); - else { - // nDos == nUnix - return nMac > nDos ? wxTextFileType_Mac : typeDefault; - } -#endif // __WATCOMC__ - - #undef GREATER_OF - } - - return typeDefault; -} - - -bool wxTextBuffer::Close() -{ - Clear(); - m_isOpened = false; - - return true; -} - -bool wxTextBuffer::Write(wxTextFileType typeNew, const wxMBConv& conv) -{ - return OnWrite(typeNew, conv); -} - -#endif // wxUSE_TEXTBUFFER +/////////////////////////////////////////////////////////////////////////////// +// Name: src/common/textbuf.cpp +// Purpose: implementation of wxTextBuffer class +// Created: 14.11.01 +// Author: Morten Hanssen, Vadim Zeitlin +// RCS-ID: $Id: textbuf.cpp 38570 2006-04-05 14:37:47Z VZ $ +// Copyright: (c) 1998-2001 wxWidgets team +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// headers +// ============================================================================ + +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif //__BORLANDC__ + +#ifndef WX_PRECOMP + #include "wx/string.h" + #include "wx/intl.h" + #include "wx/log.h" +#endif + +#include "wx/textbuf.h" + +// ============================================================================ +// wxTextBuffer class implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// static methods (always compiled in) +// ---------------------------------------------------------------------------- + +// default type is the native one +// the native type under Mac OS X is: +// - Unix when compiling with the Apple Developer Tools (__UNIX__) +// - Mac when compiling with CodeWarrior (__WXMAC__) + +const wxTextFileType wxTextBuffer::typeDefault = +#if defined(__WINDOWS__) || defined(__DOS__) || defined(__PALMOS__) + wxTextFileType_Dos; +#elif defined(__UNIX__) + wxTextFileType_Unix; +#elif defined(__WXMAC__) + wxTextFileType_Mac; +#elif defined(__OS2__) + wxTextFileType_Os2; +#else + wxTextFileType_None; + #error "wxTextBuffer: unsupported platform." +#endif + +const wxChar *wxTextBuffer::GetEOL(wxTextFileType type) +{ + switch ( type ) { + default: + wxFAIL_MSG(wxT("bad buffer type in wxTextBuffer::GetEOL.")); + // fall through nevertheless - we must return something... + + case wxTextFileType_None: return wxEmptyString; + case wxTextFileType_Unix: return wxT("\n"); + case wxTextFileType_Dos: return wxT("\r\n"); + case wxTextFileType_Mac: return wxT("\r"); + } +} + +wxString wxTextBuffer::Translate(const wxString& text, wxTextFileType type) +{ + // don't do anything if there is nothing to do + if ( type == wxTextFileType_None ) + return text; + + // nor if it is empty + if ( text.empty() ) + return text; + + wxString eol = GetEOL(type), result; + + // optimization: we know that the length of the new string will be about + // the same as the length of the old one, so prealloc memory to aviod + // unnecessary relocations + result.Alloc(text.Len()); + + wxChar chLast = 0; + for ( const wxChar *pc = text.c_str(); *pc; pc++ ) + { + wxChar ch = *pc; + switch ( ch ) { + case _T('\n'): + // Dos/Unix line termination + result += eol; + chLast = 0; + break; + + case _T('\r'): + if ( chLast == _T('\r') ) { + // Mac empty line + result += eol; + } + else { + // just remember it: we don't know whether it is just "\r" + // or "\r\n" yet + chLast = _T('\r'); + } + break; + + default: + if ( chLast == _T('\r') ) { + // Mac line termination + result += eol; + + // reset chLast to avoid inserting another eol before the + // next character + chLast = 0; + } + + // add to the current line + result += ch; + } + } + + if ( chLast ) { + // trailing '\r' + result += eol; + } + + return result; +} + +#if wxUSE_TEXTBUFFER + +wxString wxTextBuffer::ms_eof; + +// ---------------------------------------------------------------------------- +// ctors & dtor +// ---------------------------------------------------------------------------- + +wxTextBuffer::wxTextBuffer(const wxString& strBufferName) + : m_strBufferName(strBufferName) +{ + m_nCurLine = 0; + m_isOpened = false; +} + +wxTextBuffer::~wxTextBuffer() +{ + // required here for Darwin +} + +// ---------------------------------------------------------------------------- +// buffer operations +// ---------------------------------------------------------------------------- + +bool wxTextBuffer::Exists() const +{ + return OnExists(); +} + +bool wxTextBuffer::Create(const wxString& strBufferName) +{ + m_strBufferName = strBufferName; + + return Create(); +} + +bool wxTextBuffer::Create() +{ + // buffer name must be either given in ctor or in Create(const wxString&) + wxASSERT( !m_strBufferName.empty() ); + + // if the buffer already exists do nothing + if ( Exists() ) return false; + + if ( !OnOpen(m_strBufferName, WriteAccess) ) + return false; + + OnClose(); + return true; +} + +bool wxTextBuffer::Open(const wxString& strBufferName, const wxMBConv& conv) +{ + m_strBufferName = strBufferName; + + return Open(conv); +} + +bool wxTextBuffer::Open(const wxMBConv& conv) +{ + // buffer name must be either given in ctor or in Open(const wxString&) + wxASSERT( !m_strBufferName.empty() ); + + // open buffer in read-only mode + if ( !OnOpen(m_strBufferName, ReadAccess) ) + return false; + + // read buffer into memory + m_isOpened = OnRead(conv); + + OnClose(); + + return m_isOpened; +} + +// analyse some lines of the buffer trying to guess it's type. +// if it fails, it assumes the native type for our platform. +wxTextFileType wxTextBuffer::GuessType() const +{ + wxASSERT( IsOpened() ); + + // scan the buffer lines + size_t nUnix = 0, // number of '\n's alone + nDos = 0, // number of '\r\n' + nMac = 0; // number of '\r's + + // we take MAX_LINES_SCAN in the beginning, middle and the end of buffer + #define MAX_LINES_SCAN (10) + size_t nCount = m_aLines.Count() / 3, + nScan = nCount > 3*MAX_LINES_SCAN ? MAX_LINES_SCAN : nCount / 3; + + #define AnalyseLine(n) \ + switch ( m_aTypes[n] ) { \ + case wxTextFileType_Unix: nUnix++; break; \ + case wxTextFileType_Dos: nDos++; break; \ + case wxTextFileType_Mac: nMac++; break; \ + default: wxFAIL_MSG(_("unknown line terminator")); \ + } + + size_t n; + for ( n = 0; n < nScan; n++ ) // the beginning + AnalyseLine(n); + for ( n = (nCount - nScan)/2; n < (nCount + nScan)/2; n++ ) + AnalyseLine(n); + for ( n = nCount - nScan; n < nCount; n++ ) + AnalyseLine(n); + + #undef AnalyseLine + + // interpret the results (FIXME far from being even 50% fool proof) + if ( nScan > 0 && nDos + nUnix + nMac == 0 ) { + // no newlines at all + wxLogWarning(_("'%s' is probably a binary buffer."), m_strBufferName.c_str()); + } + else { + #define GREATER_OF(t1, t2) n##t1 == n##t2 ? typeDefault \ + : n##t1 > n##t2 \ + ? wxTextFileType_##t1 \ + : wxTextFileType_##t2 + +#if !defined(__WATCOMC__) || wxCHECK_WATCOM_VERSION(1,4) + if ( nDos > nUnix ) + return GREATER_OF(Dos, Mac); + else if ( nDos < nUnix ) + return GREATER_OF(Unix, Mac); + else { + // nDos == nUnix + return nMac > nDos ? wxTextFileType_Mac : typeDefault; + } +#endif // __WATCOMC__ + + #undef GREATER_OF + } + + return typeDefault; +} + + +bool wxTextBuffer::Close() +{ + Clear(); + m_isOpened = false; + + return true; +} + +bool wxTextBuffer::Write(wxTextFileType typeNew, const wxMBConv& conv) +{ + return OnWrite(typeNew, conv); +} + +#endif // wxUSE_TEXTBUFFER diff --git a/Externals/wxWidgets/src/common/textcmn.cpp b/Externals/wxWidgets/src/common/textcmn.cpp index 121df9633f..4b39879820 100644 --- a/Externals/wxWidgets/src/common/textcmn.cpp +++ b/Externals/wxWidgets/src/common/textcmn.cpp @@ -1,553 +1,553 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: src/common/textcmn.cpp -// Purpose: implementation of platform-independent functions of wxTextCtrl -// Author: Julian Smart -// Modified by: -// Created: 13.07.99 -// RCS-ID: $Id: textcmn.cpp 41754 2006-10-08 22:40:14Z VZ $ -// Copyright: (c) wxWidgets team -// Licence: wxWindows licence -/////////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// for compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#ifndef WX_PRECOMP - #include "wx/event.h" -#endif // WX_PRECOMP - -#if wxUSE_TEXTCTRL - -#include "wx/textctrl.h" - -#ifndef WX_PRECOMP - #include "wx/intl.h" - #include "wx/log.h" -#endif // WX_PRECOMP - -#include "wx/ffile.h" - -// ---------------------------------------------------------------------------- -// macros -// ---------------------------------------------------------------------------- - -// we don't have any objects of type wxTextCtrlBase in the program, only -// wxTextCtrl, so this cast is safe -#define TEXTCTRL(ptr) ((wxTextCtrl *)(ptr)) - -// ============================================================================ -// implementation -// ============================================================================ - -IMPLEMENT_DYNAMIC_CLASS(wxTextUrlEvent, wxCommandEvent) - -DEFINE_EVENT_TYPE(wxEVT_COMMAND_TEXT_UPDATED) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_TEXT_ENTER) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_TEXT_URL) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_TEXT_MAXLEN) - -IMPLEMENT_ABSTRACT_CLASS(wxTextCtrlBase, wxControl) - -// ---------------------------------------------------------------------------- -// style functions - not implemented here -// ---------------------------------------------------------------------------- - -wxTextAttr::wxTextAttr(const wxColour& colText, - const wxColour& colBack, - const wxFont& font, - wxTextAttrAlignment alignment) - : m_colText(colText), m_colBack(colBack), m_font(font), m_textAlignment(alignment) -{ - m_flags = 0; - m_leftIndent = 0; - m_leftSubIndent = 0; - m_rightIndent = 0; - if (m_colText.Ok()) m_flags |= wxTEXT_ATTR_TEXT_COLOUR; - if (m_colBack.Ok()) m_flags |= wxTEXT_ATTR_BACKGROUND_COLOUR; - if (m_font.Ok()) m_flags |= wxTEXT_ATTR_FONT; - if (alignment != wxTEXT_ALIGNMENT_DEFAULT) - m_flags |= wxTEXT_ATTR_ALIGNMENT; -} - -void wxTextAttr::Init() -{ - m_textAlignment = wxTEXT_ALIGNMENT_DEFAULT; - m_flags = 0; - m_leftIndent = 0; - m_leftSubIndent = 0; - m_rightIndent = 0; -} - -/* static */ -wxTextAttr wxTextAttr::Combine(const wxTextAttr& attr, - const wxTextAttr& attrDef, - const wxTextCtrlBase *text) -{ - wxFont font = attr.GetFont(); - if ( !font.Ok() ) - { - font = attrDef.GetFont(); - - if ( text && !font.Ok() ) - font = text->GetFont(); - } - - wxColour colFg = attr.GetTextColour(); - if ( !colFg.Ok() ) - { - colFg = attrDef.GetTextColour(); - - if ( text && !colFg.Ok() ) - colFg = text->GetForegroundColour(); - } - - wxColour colBg = attr.GetBackgroundColour(); - if ( !colBg.Ok() ) - { - colBg = attrDef.GetBackgroundColour(); - - if ( text && !colBg.Ok() ) - colBg = text->GetBackgroundColour(); - } - - wxTextAttr newAttr(colFg, colBg, font); - - if (attr.HasAlignment()) - newAttr.SetAlignment(attr.GetAlignment()); - else if (attrDef.HasAlignment()) - newAttr.SetAlignment(attrDef.GetAlignment()); - - if (attr.HasTabs()) - newAttr.SetTabs(attr.GetTabs()); - else if (attrDef.HasTabs()) - newAttr.SetTabs(attrDef.GetTabs()); - - if (attr.HasLeftIndent()) - newAttr.SetLeftIndent(attr.GetLeftIndent(), attr.GetLeftSubIndent()); - else if (attrDef.HasLeftIndent()) - newAttr.SetLeftIndent(attrDef.GetLeftIndent(), attr.GetLeftSubIndent()); - - if (attr.HasRightIndent()) - newAttr.SetRightIndent(attr.GetRightIndent()); - else if (attrDef.HasRightIndent()) - newAttr.SetRightIndent(attrDef.GetRightIndent()); - - return newAttr; -} - -void wxTextAttr::operator= (const wxTextAttr& attr) -{ - m_font = attr.m_font; - m_colText = attr.m_colText; - m_colBack = attr.m_colBack; - m_textAlignment = attr.m_textAlignment; - m_leftIndent = attr.m_leftIndent; - m_leftSubIndent = attr.m_leftSubIndent; - m_rightIndent = attr.m_rightIndent; - m_tabs = attr.m_tabs; - m_flags = attr.m_flags; -} - - -// apply styling to text range -bool wxTextCtrlBase::SetStyle(long WXUNUSED(start), long WXUNUSED(end), - const wxTextAttr& WXUNUSED(style)) -{ - // to be implemented in derived TextCtrl classes - return false; -} - -// get the styling at the given position -bool wxTextCtrlBase::GetStyle(long WXUNUSED(position), wxTextAttr& WXUNUSED(style)) -{ - // to be implemented in derived TextCtrl classes - return false; -} - -// change default text attributes -bool wxTextCtrlBase::SetDefaultStyle(const wxTextAttr& style) -{ - // keep the old attributes if the new style doesn't specify them unless the - // new style is empty - then reset m_defaultStyle (as there is no other way - // to do it) - if ( style.IsDefault() ) - m_defaultStyle = style; - else - m_defaultStyle = wxTextAttr::Combine(style, m_defaultStyle, this); - - return true; -} - -// get default text attributes -const wxTextAttr& wxTextCtrlBase::GetDefaultStyle() const -{ - return m_defaultStyle; -} - -// ---------------------------------------------------------------------------- -// file IO functions -// ---------------------------------------------------------------------------- - -bool wxTextCtrlBase::DoLoadFile(const wxString& filename, int WXUNUSED(fileType)) -{ -#if wxUSE_FFILE - wxFFile file(filename); - if ( file.IsOpened() ) - { - wxString text; - if ( file.ReadAll(&text) ) - { - SetValue(text); - - DiscardEdits(); - - m_filename = filename; - - return true; - } - } - - wxLogError(_("File couldn't be loaded.")); -#endif // wxUSE_FFILE - - return false; -} - -bool wxTextCtrlBase::SaveFile(const wxString& filename, int fileType) -{ - wxString filenameToUse = filename.empty() ? m_filename : filename; - if ( filenameToUse.empty() ) - { - // what kind of message to give? is it an error or a program bug? - wxLogDebug(wxT("Can't save textctrl to file without filename.")); - - return false; - } - - return DoSaveFile(filenameToUse, fileType); -} - -bool wxTextCtrlBase::DoSaveFile(const wxString& filename, int WXUNUSED(fileType)) -{ -#if wxUSE_FFILE - wxFFile file(filename, _T("w")); - if ( file.IsOpened() && file.Write(GetValue()) ) - { - // if it worked, save for future calls - m_filename = filename; - - // it's not modified any longer - DiscardEdits(); - - return true; - } -#endif // wxUSE_FFILE - - wxLogError(_("The text couldn't be saved.")); - - return false; -} - -// ---------------------------------------------------------------------------- -// stream-like insertion operator -// ---------------------------------------------------------------------------- - -wxTextCtrl& wxTextCtrlBase::operator<<(const wxString& s) -{ - AppendText(s); - return *TEXTCTRL(this); -} - -wxTextCtrl& wxTextCtrlBase::operator<<(float f) -{ - wxString str; - str.Printf(wxT("%.2f"), f); - AppendText(str); - return *TEXTCTRL(this); -} - -wxTextCtrl& wxTextCtrlBase::operator<<(double d) -{ - wxString str; - str.Printf(wxT("%.2f"), d); - AppendText(str); - return *TEXTCTRL(this); -} - -wxTextCtrl& wxTextCtrlBase::operator<<(int i) -{ - wxString str; - str.Printf(wxT("%d"), i); - AppendText(str); - return *TEXTCTRL(this); -} - -wxTextCtrl& wxTextCtrlBase::operator<<(long i) -{ - wxString str; - str.Printf(wxT("%ld"), i); - AppendText(str); - return *TEXTCTRL(this); -} - -wxTextCtrl& wxTextCtrlBase::operator<<(const wxChar c) -{ - return operator<<(wxString(c)); -} - -// ---------------------------------------------------------------------------- -// streambuf methods implementation -// ---------------------------------------------------------------------------- - -#if wxHAS_TEXT_WINDOW_STREAM - -int wxTextCtrlBase::overflow(int c) -{ - AppendText((wxChar)c); - - // return something different from EOF - return 0; -} - -#endif // wxHAS_TEXT_WINDOW_STREAM - -// ---------------------------------------------------------------------------- -// clipboard stuff -// ---------------------------------------------------------------------------- - -bool wxTextCtrlBase::CanCopy() const -{ - // can copy if there's a selection - long from, to; - GetSelection(&from, &to); - return from != to; -} - -bool wxTextCtrlBase::CanCut() const -{ - // can cut if there's a selection and if we're not read only - return CanCopy() && IsEditable(); -} - -bool wxTextCtrlBase::CanPaste() const -{ - // can paste if we are not read only - return IsEditable(); -} - -// ---------------------------------------------------------------------------- -// emulating key presses -// ---------------------------------------------------------------------------- - -#ifdef __WIN32__ -// the generic version is unused in wxMSW -bool wxTextCtrlBase::EmulateKeyPress(const wxKeyEvent& WXUNUSED(event)) -{ - return false; -} -#else // !__WIN32__ -bool wxTextCtrlBase::EmulateKeyPress(const wxKeyEvent& event) -{ - wxChar ch = 0; - int keycode = event.GetKeyCode(); - switch ( keycode ) - { - case WXK_NUMPAD0: - case WXK_NUMPAD1: - case WXK_NUMPAD2: - case WXK_NUMPAD3: - case WXK_NUMPAD4: - case WXK_NUMPAD5: - case WXK_NUMPAD6: - case WXK_NUMPAD7: - case WXK_NUMPAD8: - case WXK_NUMPAD9: - ch = (wxChar)(_T('0') + keycode - WXK_NUMPAD0); - break; - - case WXK_MULTIPLY: - case WXK_NUMPAD_MULTIPLY: - ch = _T('*'); - break; - - case WXK_ADD: - case WXK_NUMPAD_ADD: - ch = _T('+'); - break; - - case WXK_SUBTRACT: - case WXK_NUMPAD_SUBTRACT: - ch = _T('-'); - break; - - case WXK_DECIMAL: - case WXK_NUMPAD_DECIMAL: - ch = _T('.'); - break; - - case WXK_DIVIDE: - case WXK_NUMPAD_DIVIDE: - ch = _T('/'); - break; - - case WXK_DELETE: - case WXK_NUMPAD_DELETE: - // delete the character at cursor - { - const long pos = GetInsertionPoint(); - if ( pos < GetLastPosition() ) - Remove(pos, pos + 1); - } - break; - - case WXK_BACK: - // delete the character before the cursor - { - const long pos = GetInsertionPoint(); - if ( pos > 0 ) - Remove(pos - 1, pos); - } - break; - - default: -#if wxUSE_UNICODE - if ( event.GetUnicodeKey() ) - { - ch = event.GetUnicodeKey(); - } - else -#endif - if ( keycode < 256 && keycode >= 0 && wxIsprint(keycode) ) - { - // FIXME this is not going to work for non letters... - if ( !event.ShiftDown() ) - { - keycode = wxTolower(keycode); - } - - ch = (wxChar)keycode; - } - else - { - ch = _T('\0'); - } - } - - if ( ch ) - { - WriteText(ch); - - return true; - } - - return false; -} -#endif // !__WIN32__ - -// ---------------------------------------------------------------------------- -// selection and ranges -// ---------------------------------------------------------------------------- - -void wxTextCtrlBase::SelectAll() -{ - SetSelection(0, GetLastPosition()); -} - -wxString wxTextCtrlBase::GetStringSelection() const -{ - long from, to; - GetSelection(&from, &to); - - return GetRange(from, to); -} - -wxString wxTextCtrlBase::GetRange(long from, long to) const -{ - wxString sel; - if ( from < to ) - { - sel = GetValue().Mid(from, to - from); - } - - return sel; -} - -// do the window-specific processing after processing the update event -void wxTextCtrlBase::DoUpdateWindowUI(wxUpdateUIEvent& event) -{ - // call inherited, but skip the wxControl's version, and call directly the - // wxWindow's one instead, because the only reason why we are overriding this - // function is that we want to use SetValue() instead of wxControl::SetLabel() - wxWindowBase::DoUpdateWindowUI(event); - - // update text - if ( event.GetSetText() ) - { - if ( event.GetText() != GetValue() ) - SetValue(event.GetText()); - } -} - -// ---------------------------------------------------------------------------- -// hit testing -// ---------------------------------------------------------------------------- - -wxTextCtrlHitTestResult -wxTextCtrlBase::HitTest(const wxPoint& pt, wxTextCoord *x, wxTextCoord *y) const -{ - // implement in terms of the other overload as the native ports typically - // can get the position and not (x, y) pair directly (although wxUniv - // directly gets x and y -- and so overrides this method as well) - long pos; - wxTextCtrlHitTestResult rc = HitTest(pt, &pos); - - if ( rc != wxTE_HT_UNKNOWN ) - { - PositionToXY(pos, x, y); - } - - return rc; -} - -wxTextCtrlHitTestResult -wxTextCtrlBase::HitTest(const wxPoint& WXUNUSED(pt), - long * WXUNUSED(pos)) const -{ - // not implemented - return wxTE_HT_UNKNOWN; -} - -// ---------------------------------------------------------------------------- -// events -// ---------------------------------------------------------------------------- - -void wxTextCtrlBase::SendTextUpdatedEvent() -{ - wxCommandEvent event(wxEVT_COMMAND_TEXT_UPDATED, GetId()); - - // do not do this as it could be very inefficient if the text control - // contains a lot of text and we're not using ref-counted wxString - // implementation -- instead, event.GetString() will query the control for - // its current text if needed - //event.SetString(GetValue()); - - event.SetEventObject(this); - GetEventHandler()->ProcessEvent(event); -} - -#else // !wxUSE_TEXTCTRL - -// define this one even if !wxUSE_TEXTCTRL because it is also used by other -// controls (wxComboBox and wxSpinCtrl) - -DEFINE_EVENT_TYPE(wxEVT_COMMAND_TEXT_UPDATED) - -#endif // wxUSE_TEXTCTRL/!wxUSE_TEXTCTRL +/////////////////////////////////////////////////////////////////////////////// +// Name: src/common/textcmn.cpp +// Purpose: implementation of platform-independent functions of wxTextCtrl +// Author: Julian Smart +// Modified by: +// Created: 13.07.99 +// RCS-ID: $Id: textcmn.cpp 41754 2006-10-08 22:40:14Z VZ $ +// Copyright: (c) wxWidgets team +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// for compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#ifndef WX_PRECOMP + #include "wx/event.h" +#endif // WX_PRECOMP + +#if wxUSE_TEXTCTRL + +#include "wx/textctrl.h" + +#ifndef WX_PRECOMP + #include "wx/intl.h" + #include "wx/log.h" +#endif // WX_PRECOMP + +#include "wx/ffile.h" + +// ---------------------------------------------------------------------------- +// macros +// ---------------------------------------------------------------------------- + +// we don't have any objects of type wxTextCtrlBase in the program, only +// wxTextCtrl, so this cast is safe +#define TEXTCTRL(ptr) ((wxTextCtrl *)(ptr)) + +// ============================================================================ +// implementation +// ============================================================================ + +IMPLEMENT_DYNAMIC_CLASS(wxTextUrlEvent, wxCommandEvent) + +DEFINE_EVENT_TYPE(wxEVT_COMMAND_TEXT_UPDATED) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_TEXT_ENTER) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_TEXT_URL) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_TEXT_MAXLEN) + +IMPLEMENT_ABSTRACT_CLASS(wxTextCtrlBase, wxControl) + +// ---------------------------------------------------------------------------- +// style functions - not implemented here +// ---------------------------------------------------------------------------- + +wxTextAttr::wxTextAttr(const wxColour& colText, + const wxColour& colBack, + const wxFont& font, + wxTextAttrAlignment alignment) + : m_colText(colText), m_colBack(colBack), m_font(font), m_textAlignment(alignment) +{ + m_flags = 0; + m_leftIndent = 0; + m_leftSubIndent = 0; + m_rightIndent = 0; + if (m_colText.Ok()) m_flags |= wxTEXT_ATTR_TEXT_COLOUR; + if (m_colBack.Ok()) m_flags |= wxTEXT_ATTR_BACKGROUND_COLOUR; + if (m_font.Ok()) m_flags |= wxTEXT_ATTR_FONT; + if (alignment != wxTEXT_ALIGNMENT_DEFAULT) + m_flags |= wxTEXT_ATTR_ALIGNMENT; +} + +void wxTextAttr::Init() +{ + m_textAlignment = wxTEXT_ALIGNMENT_DEFAULT; + m_flags = 0; + m_leftIndent = 0; + m_leftSubIndent = 0; + m_rightIndent = 0; +} + +/* static */ +wxTextAttr wxTextAttr::Combine(const wxTextAttr& attr, + const wxTextAttr& attrDef, + const wxTextCtrlBase *text) +{ + wxFont font = attr.GetFont(); + if ( !font.Ok() ) + { + font = attrDef.GetFont(); + + if ( text && !font.Ok() ) + font = text->GetFont(); + } + + wxColour colFg = attr.GetTextColour(); + if ( !colFg.Ok() ) + { + colFg = attrDef.GetTextColour(); + + if ( text && !colFg.Ok() ) + colFg = text->GetForegroundColour(); + } + + wxColour colBg = attr.GetBackgroundColour(); + if ( !colBg.Ok() ) + { + colBg = attrDef.GetBackgroundColour(); + + if ( text && !colBg.Ok() ) + colBg = text->GetBackgroundColour(); + } + + wxTextAttr newAttr(colFg, colBg, font); + + if (attr.HasAlignment()) + newAttr.SetAlignment(attr.GetAlignment()); + else if (attrDef.HasAlignment()) + newAttr.SetAlignment(attrDef.GetAlignment()); + + if (attr.HasTabs()) + newAttr.SetTabs(attr.GetTabs()); + else if (attrDef.HasTabs()) + newAttr.SetTabs(attrDef.GetTabs()); + + if (attr.HasLeftIndent()) + newAttr.SetLeftIndent(attr.GetLeftIndent(), attr.GetLeftSubIndent()); + else if (attrDef.HasLeftIndent()) + newAttr.SetLeftIndent(attrDef.GetLeftIndent(), attr.GetLeftSubIndent()); + + if (attr.HasRightIndent()) + newAttr.SetRightIndent(attr.GetRightIndent()); + else if (attrDef.HasRightIndent()) + newAttr.SetRightIndent(attrDef.GetRightIndent()); + + return newAttr; +} + +void wxTextAttr::operator= (const wxTextAttr& attr) +{ + m_font = attr.m_font; + m_colText = attr.m_colText; + m_colBack = attr.m_colBack; + m_textAlignment = attr.m_textAlignment; + m_leftIndent = attr.m_leftIndent; + m_leftSubIndent = attr.m_leftSubIndent; + m_rightIndent = attr.m_rightIndent; + m_tabs = attr.m_tabs; + m_flags = attr.m_flags; +} + + +// apply styling to text range +bool wxTextCtrlBase::SetStyle(long WXUNUSED(start), long WXUNUSED(end), + const wxTextAttr& WXUNUSED(style)) +{ + // to be implemented in derived TextCtrl classes + return false; +} + +// get the styling at the given position +bool wxTextCtrlBase::GetStyle(long WXUNUSED(position), wxTextAttr& WXUNUSED(style)) +{ + // to be implemented in derived TextCtrl classes + return false; +} + +// change default text attributes +bool wxTextCtrlBase::SetDefaultStyle(const wxTextAttr& style) +{ + // keep the old attributes if the new style doesn't specify them unless the + // new style is empty - then reset m_defaultStyle (as there is no other way + // to do it) + if ( style.IsDefault() ) + m_defaultStyle = style; + else + m_defaultStyle = wxTextAttr::Combine(style, m_defaultStyle, this); + + return true; +} + +// get default text attributes +const wxTextAttr& wxTextCtrlBase::GetDefaultStyle() const +{ + return m_defaultStyle; +} + +// ---------------------------------------------------------------------------- +// file IO functions +// ---------------------------------------------------------------------------- + +bool wxTextCtrlBase::DoLoadFile(const wxString& filename, int WXUNUSED(fileType)) +{ +#if wxUSE_FFILE + wxFFile file(filename); + if ( file.IsOpened() ) + { + wxString text; + if ( file.ReadAll(&text) ) + { + SetValue(text); + + DiscardEdits(); + + m_filename = filename; + + return true; + } + } + + wxLogError(_("File couldn't be loaded.")); +#endif // wxUSE_FFILE + + return false; +} + +bool wxTextCtrlBase::SaveFile(const wxString& filename, int fileType) +{ + wxString filenameToUse = filename.empty() ? m_filename : filename; + if ( filenameToUse.empty() ) + { + // what kind of message to give? is it an error or a program bug? + wxLogDebug(wxT("Can't save textctrl to file without filename.")); + + return false; + } + + return DoSaveFile(filenameToUse, fileType); +} + +bool wxTextCtrlBase::DoSaveFile(const wxString& filename, int WXUNUSED(fileType)) +{ +#if wxUSE_FFILE + wxFFile file(filename, _T("w")); + if ( file.IsOpened() && file.Write(GetValue()) ) + { + // if it worked, save for future calls + m_filename = filename; + + // it's not modified any longer + DiscardEdits(); + + return true; + } +#endif // wxUSE_FFILE + + wxLogError(_("The text couldn't be saved.")); + + return false; +} + +// ---------------------------------------------------------------------------- +// stream-like insertion operator +// ---------------------------------------------------------------------------- + +wxTextCtrl& wxTextCtrlBase::operator<<(const wxString& s) +{ + AppendText(s); + return *TEXTCTRL(this); +} + +wxTextCtrl& wxTextCtrlBase::operator<<(float f) +{ + wxString str; + str.Printf(wxT("%.2f"), f); + AppendText(str); + return *TEXTCTRL(this); +} + +wxTextCtrl& wxTextCtrlBase::operator<<(double d) +{ + wxString str; + str.Printf(wxT("%.2f"), d); + AppendText(str); + return *TEXTCTRL(this); +} + +wxTextCtrl& wxTextCtrlBase::operator<<(int i) +{ + wxString str; + str.Printf(wxT("%d"), i); + AppendText(str); + return *TEXTCTRL(this); +} + +wxTextCtrl& wxTextCtrlBase::operator<<(long i) +{ + wxString str; + str.Printf(wxT("%ld"), i); + AppendText(str); + return *TEXTCTRL(this); +} + +wxTextCtrl& wxTextCtrlBase::operator<<(const wxChar c) +{ + return operator<<(wxString(c)); +} + +// ---------------------------------------------------------------------------- +// streambuf methods implementation +// ---------------------------------------------------------------------------- + +#if wxHAS_TEXT_WINDOW_STREAM + +int wxTextCtrlBase::overflow(int c) +{ + AppendText((wxChar)c); + + // return something different from EOF + return 0; +} + +#endif // wxHAS_TEXT_WINDOW_STREAM + +// ---------------------------------------------------------------------------- +// clipboard stuff +// ---------------------------------------------------------------------------- + +bool wxTextCtrlBase::CanCopy() const +{ + // can copy if there's a selection + long from, to; + GetSelection(&from, &to); + return from != to; +} + +bool wxTextCtrlBase::CanCut() const +{ + // can cut if there's a selection and if we're not read only + return CanCopy() && IsEditable(); +} + +bool wxTextCtrlBase::CanPaste() const +{ + // can paste if we are not read only + return IsEditable(); +} + +// ---------------------------------------------------------------------------- +// emulating key presses +// ---------------------------------------------------------------------------- + +#ifdef __WIN32__ +// the generic version is unused in wxMSW +bool wxTextCtrlBase::EmulateKeyPress(const wxKeyEvent& WXUNUSED(event)) +{ + return false; +} +#else // !__WIN32__ +bool wxTextCtrlBase::EmulateKeyPress(const wxKeyEvent& event) +{ + wxChar ch = 0; + int keycode = event.GetKeyCode(); + switch ( keycode ) + { + case WXK_NUMPAD0: + case WXK_NUMPAD1: + case WXK_NUMPAD2: + case WXK_NUMPAD3: + case WXK_NUMPAD4: + case WXK_NUMPAD5: + case WXK_NUMPAD6: + case WXK_NUMPAD7: + case WXK_NUMPAD8: + case WXK_NUMPAD9: + ch = (wxChar)(_T('0') + keycode - WXK_NUMPAD0); + break; + + case WXK_MULTIPLY: + case WXK_NUMPAD_MULTIPLY: + ch = _T('*'); + break; + + case WXK_ADD: + case WXK_NUMPAD_ADD: + ch = _T('+'); + break; + + case WXK_SUBTRACT: + case WXK_NUMPAD_SUBTRACT: + ch = _T('-'); + break; + + case WXK_DECIMAL: + case WXK_NUMPAD_DECIMAL: + ch = _T('.'); + break; + + case WXK_DIVIDE: + case WXK_NUMPAD_DIVIDE: + ch = _T('/'); + break; + + case WXK_DELETE: + case WXK_NUMPAD_DELETE: + // delete the character at cursor + { + const long pos = GetInsertionPoint(); + if ( pos < GetLastPosition() ) + Remove(pos, pos + 1); + } + break; + + case WXK_BACK: + // delete the character before the cursor + { + const long pos = GetInsertionPoint(); + if ( pos > 0 ) + Remove(pos - 1, pos); + } + break; + + default: +#if wxUSE_UNICODE + if ( event.GetUnicodeKey() ) + { + ch = event.GetUnicodeKey(); + } + else +#endif + if ( keycode < 256 && keycode >= 0 && wxIsprint(keycode) ) + { + // FIXME this is not going to work for non letters... + if ( !event.ShiftDown() ) + { + keycode = wxTolower(keycode); + } + + ch = (wxChar)keycode; + } + else + { + ch = _T('\0'); + } + } + + if ( ch ) + { + WriteText(ch); + + return true; + } + + return false; +} +#endif // !__WIN32__ + +// ---------------------------------------------------------------------------- +// selection and ranges +// ---------------------------------------------------------------------------- + +void wxTextCtrlBase::SelectAll() +{ + SetSelection(0, GetLastPosition()); +} + +wxString wxTextCtrlBase::GetStringSelection() const +{ + long from, to; + GetSelection(&from, &to); + + return GetRange(from, to); +} + +wxString wxTextCtrlBase::GetRange(long from, long to) const +{ + wxString sel; + if ( from < to ) + { + sel = GetValue().Mid(from, to - from); + } + + return sel; +} + +// do the window-specific processing after processing the update event +void wxTextCtrlBase::DoUpdateWindowUI(wxUpdateUIEvent& event) +{ + // call inherited, but skip the wxControl's version, and call directly the + // wxWindow's one instead, because the only reason why we are overriding this + // function is that we want to use SetValue() instead of wxControl::SetLabel() + wxWindowBase::DoUpdateWindowUI(event); + + // update text + if ( event.GetSetText() ) + { + if ( event.GetText() != GetValue() ) + SetValue(event.GetText()); + } +} + +// ---------------------------------------------------------------------------- +// hit testing +// ---------------------------------------------------------------------------- + +wxTextCtrlHitTestResult +wxTextCtrlBase::HitTest(const wxPoint& pt, wxTextCoord *x, wxTextCoord *y) const +{ + // implement in terms of the other overload as the native ports typically + // can get the position and not (x, y) pair directly (although wxUniv + // directly gets x and y -- and so overrides this method as well) + long pos; + wxTextCtrlHitTestResult rc = HitTest(pt, &pos); + + if ( rc != wxTE_HT_UNKNOWN ) + { + PositionToXY(pos, x, y); + } + + return rc; +} + +wxTextCtrlHitTestResult +wxTextCtrlBase::HitTest(const wxPoint& WXUNUSED(pt), + long * WXUNUSED(pos)) const +{ + // not implemented + return wxTE_HT_UNKNOWN; +} + +// ---------------------------------------------------------------------------- +// events +// ---------------------------------------------------------------------------- + +void wxTextCtrlBase::SendTextUpdatedEvent() +{ + wxCommandEvent event(wxEVT_COMMAND_TEXT_UPDATED, GetId()); + + // do not do this as it could be very inefficient if the text control + // contains a lot of text and we're not using ref-counted wxString + // implementation -- instead, event.GetString() will query the control for + // its current text if needed + //event.SetString(GetValue()); + + event.SetEventObject(this); + GetEventHandler()->ProcessEvent(event); +} + +#else // !wxUSE_TEXTCTRL + +// define this one even if !wxUSE_TEXTCTRL because it is also used by other +// controls (wxComboBox and wxSpinCtrl) + +DEFINE_EVENT_TYPE(wxEVT_COMMAND_TEXT_UPDATED) + +#endif // wxUSE_TEXTCTRL/!wxUSE_TEXTCTRL diff --git a/Externals/wxWidgets/src/common/textfile.cpp b/Externals/wxWidgets/src/common/textfile.cpp index 80dc4cc1cb..d873e1d971 100644 --- a/Externals/wxWidgets/src/common/textfile.cpp +++ b/Externals/wxWidgets/src/common/textfile.cpp @@ -1,295 +1,295 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: src/common/textfile.cpp -// Purpose: implementation of wxTextFile class -// Author: Vadim Zeitlin -// Modified by: -// Created: 03.04.98 -// RCS-ID: $Id: textfile.cpp 49298 2007-10-21 18:05:49Z SC $ -// Copyright: (c) 1998 Vadim Zeitlin -// Licence: wxWindows licence -/////////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// headers -// ============================================================================ - -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif //__BORLANDC__ - -#if !wxUSE_FILE || !wxUSE_TEXTBUFFER - #undef wxUSE_TEXTFILE - #define wxUSE_TEXTFILE 0 -#endif // wxUSE_FILE - -#if wxUSE_TEXTFILE - -#ifndef WX_PRECOMP - #include "wx/string.h" - #include "wx/intl.h" - #include "wx/file.h" - #include "wx/log.h" -#endif - -#include "wx/textfile.h" -#include "wx/filename.h" -#include "wx/buffer.h" - -// ============================================================================ -// wxTextFile class implementation -// ============================================================================ - -wxTextFile::wxTextFile(const wxString& strFileName) - : wxTextBuffer(strFileName) -{ -} - - -// ---------------------------------------------------------------------------- -// file operations -// ---------------------------------------------------------------------------- - -bool wxTextFile::OnExists() const -{ - return wxFile::Exists(m_strBufferName); -} - - -bool wxTextFile::OnOpen(const wxString &strBufferName, wxTextBufferOpenMode OpenMode) -{ - wxFile::OpenMode FileOpenMode; - - switch ( OpenMode ) - { - default: - wxFAIL_MSG( _T("unknown open mode in wxTextFile::Open") ); - // fall through - - case ReadAccess : - FileOpenMode = wxFile::read; - break; - - case WriteAccess : - FileOpenMode = wxFile::write; - break; - } - - return m_file.Open(strBufferName.c_str(), FileOpenMode); -} - - -bool wxTextFile::OnClose() -{ - return m_file.Close(); -} - - -bool wxTextFile::OnRead(const wxMBConv& conv) -{ - // file should be opened - wxASSERT_MSG( m_file.IsOpened(), _T("can't read closed file") ); - - // read the entire file in memory: this is not the most efficient thing to - // do but there is no good way to avoid it in Unicode build because if we - // read the file block by block we can't convert each block to Unicode - // separately (the last multibyte char in the block might be only partially - // read and so the conversion would fail) and, as the file contents is kept - // in memory by wxTextFile anyhow, it shouldn't be a big problem to read - // the file entirely - size_t bufSize = 0, - bufPos = 0; - char block[1024]; - wxCharBuffer buf; - - // first determine if the file is seekable or not and so whether we can - // determine its length in advance - wxFileOffset fileLength; - { - wxLogNull logNull; - fileLength = m_file.Length(); - } - - // some non-seekable files under /proc under Linux pretend that they're - // seekable but always return 0; others do return an error - const bool seekable = fileLength != wxInvalidOffset && fileLength != 0; - if ( seekable ) - { - // we know the required length, so set the buffer size in advance - bufSize = fileLength; - if ( !buf.extend(bufSize - 1 /* it adds 1 internally */) ) - return false; - - // if the file is seekable, also check that we're at its beginning - wxASSERT_MSG( m_file.Tell() == 0, _T("should be at start of file") ); - } - - for ( ;; ) - { - ssize_t nRead = m_file.Read(block, WXSIZEOF(block)); - - if ( nRead == wxInvalidOffset ) - { - // read error (error message already given in wxFile::Read) - return false; - } - - if ( nRead == 0 ) - { - // if no bytes have been read, presumably this is a valid-but-empty file - if ( bufPos == 0 ) - return true; - - // otherwise we've finished reading the file - break; - } - - if ( seekable ) - { - // this shouldn't happen but don't overwrite the buffer if it does - wxCHECK_MSG( bufPos + nRead <= bufSize, false, - _T("read more than file length?") ); - } - else // !seekable - { - // for non-seekable files we have to allocate more memory on the go - if ( !buf.extend(bufPos + nRead - 1 /* it adds 1 internally */) ) - return false; - } - - // append to the buffer - memcpy(buf.data() + bufPos, block, nRead); - bufPos += nRead; - } - - if ( !seekable ) - { - bufSize = bufPos; - } - - const wxString str(buf, conv, bufPos); - - // there's no risk of this happening in ANSI build -#if wxUSE_UNICODE - if ( bufSize > 4 && str.empty() ) - { - wxLogError(_("Failed to convert file \"%s\" to Unicode."), GetName()); - return false; - } -#endif // wxUSE_UNICODE - - free(buf.release()); // we don't need this memory any more - - - // now break the buffer in lines - - // last processed character, we need to know if it was a CR or not - wxChar chLast = '\0'; - - // the beginning of the current line, changes inside the loop - wxString::const_iterator lineStart = str.begin(); - const wxString::const_iterator end = str.end(); - for ( wxString::const_iterator p = lineStart; p != end; p++ ) - { - const wxChar ch = *p; - switch ( ch ) - { - case '\n': - // could be a DOS or Unix EOL - if ( chLast == '\r' ) - { - if ( p - 1 >= lineStart ) - { - AddLine(wxString(lineStart, p - 1), wxTextFileType_Dos); - } - else - { - // there were two line endings, so add an empty line: - AddLine(wxEmptyString, wxTextFileType_Dos); - } - } - else // bare '\n', Unix style - { - AddLine(wxString(lineStart, p), wxTextFileType_Unix); - } - - lineStart = p + 1; - break; - - case '\r': - if ( chLast == '\r' ) - { - if ( p - 1 >= lineStart ) - { - AddLine(wxString(lineStart, p - 1), wxTextFileType_Mac); - } - // Mac empty line - AddLine(wxEmptyString, wxTextFileType_Mac); - lineStart = p + 1; - } - //else: we don't know what this is yet -- could be a Mac EOL or - // start of DOS EOL so wait for next char - break; - - default: - if ( chLast == '\r' ) - { - // Mac line termination - if ( p - 1 >= lineStart ) - { - AddLine(wxString(lineStart, p - 1), wxTextFileType_Mac); - } - else - { - // there were two line endings, so add an empty line: - AddLine(wxEmptyString, wxTextFileType_Mac); - } - lineStart = p; - } - } - - chLast = ch; - } - - // anything in the last line? - if ( lineStart != end ) - { - // add unterminated last line - AddLine(wxString(lineStart, end), wxTextFileType_None); - } - - return true; -} - - -bool wxTextFile::OnWrite(wxTextFileType typeNew, const wxMBConv& conv) -{ - wxFileName fn = m_strBufferName; - - // We do NOT want wxPATH_NORM_CASE here, or the case will not - // be preserved. - if ( !fn.IsAbsolute() ) - fn.Normalize(wxPATH_NORM_ENV_VARS | wxPATH_NORM_DOTS | wxPATH_NORM_TILDE | - wxPATH_NORM_ABSOLUTE | wxPATH_NORM_LONG); - - wxTempFile fileTmp(fn.GetFullPath()); - - if ( !fileTmp.IsOpened() ) { - wxLogError(_("can't write buffer '%s' to disk."), m_strBufferName.c_str()); - return false; - } - - size_t nCount = GetLineCount(); - for ( size_t n = 0; n < nCount; n++ ) { - fileTmp.Write(GetLine(n) + - GetEOL(typeNew == wxTextFileType_None ? GetLineType(n) - : typeNew), - conv); - } - - // replace the old file with this one - return fileTmp.Commit(); -} - -#endif // wxUSE_TEXTFILE +/////////////////////////////////////////////////////////////////////////////// +// Name: src/common/textfile.cpp +// Purpose: implementation of wxTextFile class +// Author: Vadim Zeitlin +// Modified by: +// Created: 03.04.98 +// RCS-ID: $Id: textfile.cpp 49298 2007-10-21 18:05:49Z SC $ +// Copyright: (c) 1998 Vadim Zeitlin +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// headers +// ============================================================================ + +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif //__BORLANDC__ + +#if !wxUSE_FILE || !wxUSE_TEXTBUFFER + #undef wxUSE_TEXTFILE + #define wxUSE_TEXTFILE 0 +#endif // wxUSE_FILE + +#if wxUSE_TEXTFILE + +#ifndef WX_PRECOMP + #include "wx/string.h" + #include "wx/intl.h" + #include "wx/file.h" + #include "wx/log.h" +#endif + +#include "wx/textfile.h" +#include "wx/filename.h" +#include "wx/buffer.h" + +// ============================================================================ +// wxTextFile class implementation +// ============================================================================ + +wxTextFile::wxTextFile(const wxString& strFileName) + : wxTextBuffer(strFileName) +{ +} + + +// ---------------------------------------------------------------------------- +// file operations +// ---------------------------------------------------------------------------- + +bool wxTextFile::OnExists() const +{ + return wxFile::Exists(m_strBufferName); +} + + +bool wxTextFile::OnOpen(const wxString &strBufferName, wxTextBufferOpenMode OpenMode) +{ + wxFile::OpenMode FileOpenMode; + + switch ( OpenMode ) + { + default: + wxFAIL_MSG( _T("unknown open mode in wxTextFile::Open") ); + // fall through + + case ReadAccess : + FileOpenMode = wxFile::read; + break; + + case WriteAccess : + FileOpenMode = wxFile::write; + break; + } + + return m_file.Open(strBufferName.c_str(), FileOpenMode); +} + + +bool wxTextFile::OnClose() +{ + return m_file.Close(); +} + + +bool wxTextFile::OnRead(const wxMBConv& conv) +{ + // file should be opened + wxASSERT_MSG( m_file.IsOpened(), _T("can't read closed file") ); + + // read the entire file in memory: this is not the most efficient thing to + // do but there is no good way to avoid it in Unicode build because if we + // read the file block by block we can't convert each block to Unicode + // separately (the last multibyte char in the block might be only partially + // read and so the conversion would fail) and, as the file contents is kept + // in memory by wxTextFile anyhow, it shouldn't be a big problem to read + // the file entirely + size_t bufSize = 0, + bufPos = 0; + char block[1024]; + wxCharBuffer buf; + + // first determine if the file is seekable or not and so whether we can + // determine its length in advance + wxFileOffset fileLength; + { + wxLogNull logNull; + fileLength = m_file.Length(); + } + + // some non-seekable files under /proc under Linux pretend that they're + // seekable but always return 0; others do return an error + const bool seekable = fileLength != wxInvalidOffset && fileLength != 0; + if ( seekable ) + { + // we know the required length, so set the buffer size in advance + bufSize = fileLength; + if ( !buf.extend(bufSize - 1 /* it adds 1 internally */) ) + return false; + + // if the file is seekable, also check that we're at its beginning + wxASSERT_MSG( m_file.Tell() == 0, _T("should be at start of file") ); + } + + for ( ;; ) + { + ssize_t nRead = m_file.Read(block, WXSIZEOF(block)); + + if ( nRead == wxInvalidOffset ) + { + // read error (error message already given in wxFile::Read) + return false; + } + + if ( nRead == 0 ) + { + // if no bytes have been read, presumably this is a valid-but-empty file + if ( bufPos == 0 ) + return true; + + // otherwise we've finished reading the file + break; + } + + if ( seekable ) + { + // this shouldn't happen but don't overwrite the buffer if it does + wxCHECK_MSG( bufPos + nRead <= bufSize, false, + _T("read more than file length?") ); + } + else // !seekable + { + // for non-seekable files we have to allocate more memory on the go + if ( !buf.extend(bufPos + nRead - 1 /* it adds 1 internally */) ) + return false; + } + + // append to the buffer + memcpy(buf.data() + bufPos, block, nRead); + bufPos += nRead; + } + + if ( !seekable ) + { + bufSize = bufPos; + } + + const wxString str(buf, conv, bufPos); + + // there's no risk of this happening in ANSI build +#if wxUSE_UNICODE + if ( bufSize > 4 && str.empty() ) + { + wxLogError(_("Failed to convert file \"%s\" to Unicode."), GetName()); + return false; + } +#endif // wxUSE_UNICODE + + free(buf.release()); // we don't need this memory any more + + + // now break the buffer in lines + + // last processed character, we need to know if it was a CR or not + wxChar chLast = '\0'; + + // the beginning of the current line, changes inside the loop + wxString::const_iterator lineStart = str.begin(); + const wxString::const_iterator end = str.end(); + for ( wxString::const_iterator p = lineStart; p != end; p++ ) + { + const wxChar ch = *p; + switch ( ch ) + { + case '\n': + // could be a DOS or Unix EOL + if ( chLast == '\r' ) + { + if ( p - 1 >= lineStart ) + { + AddLine(wxString(lineStart, p - 1), wxTextFileType_Dos); + } + else + { + // there were two line endings, so add an empty line: + AddLine(wxEmptyString, wxTextFileType_Dos); + } + } + else // bare '\n', Unix style + { + AddLine(wxString(lineStart, p), wxTextFileType_Unix); + } + + lineStart = p + 1; + break; + + case '\r': + if ( chLast == '\r' ) + { + if ( p - 1 >= lineStart ) + { + AddLine(wxString(lineStart, p - 1), wxTextFileType_Mac); + } + // Mac empty line + AddLine(wxEmptyString, wxTextFileType_Mac); + lineStart = p + 1; + } + //else: we don't know what this is yet -- could be a Mac EOL or + // start of DOS EOL so wait for next char + break; + + default: + if ( chLast == '\r' ) + { + // Mac line termination + if ( p - 1 >= lineStart ) + { + AddLine(wxString(lineStart, p - 1), wxTextFileType_Mac); + } + else + { + // there were two line endings, so add an empty line: + AddLine(wxEmptyString, wxTextFileType_Mac); + } + lineStart = p; + } + } + + chLast = ch; + } + + // anything in the last line? + if ( lineStart != end ) + { + // add unterminated last line + AddLine(wxString(lineStart, end), wxTextFileType_None); + } + + return true; +} + + +bool wxTextFile::OnWrite(wxTextFileType typeNew, const wxMBConv& conv) +{ + wxFileName fn = m_strBufferName; + + // We do NOT want wxPATH_NORM_CASE here, or the case will not + // be preserved. + if ( !fn.IsAbsolute() ) + fn.Normalize(wxPATH_NORM_ENV_VARS | wxPATH_NORM_DOTS | wxPATH_NORM_TILDE | + wxPATH_NORM_ABSOLUTE | wxPATH_NORM_LONG); + + wxTempFile fileTmp(fn.GetFullPath()); + + if ( !fileTmp.IsOpened() ) { + wxLogError(_("can't write buffer '%s' to disk."), m_strBufferName.c_str()); + return false; + } + + size_t nCount = GetLineCount(); + for ( size_t n = 0; n < nCount; n++ ) { + fileTmp.Write(GetLine(n) + + GetEOL(typeNew == wxTextFileType_None ? GetLineType(n) + : typeNew), + conv); + } + + // replace the old file with this one + return fileTmp.Commit(); +} + +#endif // wxUSE_TEXTFILE diff --git a/Externals/wxWidgets/src/common/timercmn.cpp b/Externals/wxWidgets/src/common/timercmn.cpp index dd5fc39c00..43062b46de 100644 --- a/Externals/wxWidgets/src/common/timercmn.cpp +++ b/Externals/wxWidgets/src/common/timercmn.cpp @@ -1,88 +1,88 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: common/timercmn.cpp -// Purpose: wxTimerBase implementation -// Author: Julian Smart, Guillermo Rodriguez, Vadim Zeitlin -// Modified by: VZ: extracted all non-wxTimer stuff in stopwatch.cpp (20.06.03) -// Created: 04/01/98 -// RCS-ID: $Id: timercmn.cpp 35650 2005-09-23 12:56:45Z MR $ -// Copyright: (c) Julian Smart -// (c) 1999 Guillermo Rodriguez -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// wxWin headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_TIMER - -#ifndef WX_PRECOMP - #include "wx/timer.h" -#endif - -// ---------------------------------------------------------------------------- -// wxWin macros -// ---------------------------------------------------------------------------- - -IMPLEMENT_DYNAMIC_CLASS(wxTimerEvent, wxEvent) - -// ============================================================================ -// wxTimerBase implementation -// ============================================================================ - -wxTimerBase::~wxTimerBase() -{ - // this destructor is required for Darwin -} - -void wxTimerBase::Notify() -{ - // the base class version generates an event if it has owner - which it - // should because otherwise nobody can process timer events - wxCHECK_RET( m_owner, _T("wxTimer::Notify() should be overridden.") ); - - wxTimerEvent event(m_idTimer, m_milli); - event.SetEventObject(this); - (void)m_owner->ProcessEvent(event); -} - -bool wxTimerBase::Start(int milliseconds, bool oneShot) -{ - // under MSW timers only work when they're started from the main thread so - // let the caller know about it -#if wxUSE_THREADS - wxASSERT_MSG( wxThread::IsMain(), - _T("timer can only be started from the main thread") ); -#endif // wxUSE_THREADS - - if ( IsRunning() ) - { - // not stopping the already running timer might work for some - // platforms (no problems under MSW) but leads to mysterious crashes - // on the others (GTK), so to be on the safe side do it here - Stop(); - } - - if ( milliseconds != -1 ) - { - m_milli = milliseconds; - } - - m_oneShot = oneShot; - - return true; -} - -#endif // wxUSE_TIMER - +///////////////////////////////////////////////////////////////////////////// +// Name: common/timercmn.cpp +// Purpose: wxTimerBase implementation +// Author: Julian Smart, Guillermo Rodriguez, Vadim Zeitlin +// Modified by: VZ: extracted all non-wxTimer stuff in stopwatch.cpp (20.06.03) +// Created: 04/01/98 +// RCS-ID: $Id: timercmn.cpp 35650 2005-09-23 12:56:45Z MR $ +// Copyright: (c) Julian Smart +// (c) 1999 Guillermo Rodriguez +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// wxWin headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_TIMER + +#ifndef WX_PRECOMP + #include "wx/timer.h" +#endif + +// ---------------------------------------------------------------------------- +// wxWin macros +// ---------------------------------------------------------------------------- + +IMPLEMENT_DYNAMIC_CLASS(wxTimerEvent, wxEvent) + +// ============================================================================ +// wxTimerBase implementation +// ============================================================================ + +wxTimerBase::~wxTimerBase() +{ + // this destructor is required for Darwin +} + +void wxTimerBase::Notify() +{ + // the base class version generates an event if it has owner - which it + // should because otherwise nobody can process timer events + wxCHECK_RET( m_owner, _T("wxTimer::Notify() should be overridden.") ); + + wxTimerEvent event(m_idTimer, m_milli); + event.SetEventObject(this); + (void)m_owner->ProcessEvent(event); +} + +bool wxTimerBase::Start(int milliseconds, bool oneShot) +{ + // under MSW timers only work when they're started from the main thread so + // let the caller know about it +#if wxUSE_THREADS + wxASSERT_MSG( wxThread::IsMain(), + _T("timer can only be started from the main thread") ); +#endif // wxUSE_THREADS + + if ( IsRunning() ) + { + // not stopping the already running timer might work for some + // platforms (no problems under MSW) but leads to mysterious crashes + // on the others (GTK), so to be on the safe side do it here + Stop(); + } + + if ( milliseconds != -1 ) + { + m_milli = milliseconds; + } + + m_oneShot = oneShot; + + return true; +} + +#endif // wxUSE_TIMER + diff --git a/Externals/wxWidgets/src/common/tokenzr.cpp b/Externals/wxWidgets/src/common/tokenzr.cpp index 448a6651f0..b539458f86 100644 --- a/Externals/wxWidgets/src/common/tokenzr.cpp +++ b/Externals/wxWidgets/src/common/tokenzr.cpp @@ -1,229 +1,229 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/tokenzr.cpp -// Purpose: String tokenizer -// Author: Guilhem Lavaux -// Modified by: Vadim Zeitlin (almost full rewrite) -// Created: 04/22/98 -// RCS-ID: $Id: tokenzr.cpp 39694 2006-06-13 11:30:40Z ABX $ -// Copyright: (c) Guilhem Lavaux -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#include "wx/tokenzr.h" - -#ifndef WX_PRECOMP - #include "wx/arrstr.h" -#endif - -// Required for wxIs... functions -#include - -// ============================================================================ -// implementation -// ============================================================================ - -// ---------------------------------------------------------------------------- -// wxStringTokenizer construction -// ---------------------------------------------------------------------------- - -wxStringTokenizer::wxStringTokenizer(const wxString& str, - const wxString& delims, - wxStringTokenizerMode mode) -{ - SetString(str, delims, mode); -} - -void wxStringTokenizer::SetString(const wxString& str, - const wxString& delims, - wxStringTokenizerMode mode) -{ - if ( mode == wxTOKEN_DEFAULT ) - { - // by default, we behave like strtok() if the delimiters are only - // whitespace characters and as wxTOKEN_RET_EMPTY otherwise (for - // whitespace delimiters, strtok() behaviour is better because we want - // to count consecutive spaces as one delimiter) - const wxChar *p; - for ( p = delims.c_str(); *p; p++ ) - { - if ( !wxIsspace(*p) ) - break; - } - - if ( *p ) - { - // not whitespace char in delims - mode = wxTOKEN_RET_EMPTY; - } - else - { - // only whitespaces - mode = wxTOKEN_STRTOK; - } - } - - m_delims = delims; - m_mode = mode; - - Reinit(str); -} - -void wxStringTokenizer::Reinit(const wxString& str) -{ - wxASSERT_MSG( IsOk(), _T("you should call SetString() first") ); - - m_string = str; - m_pos = 0; - m_lastDelim = _T('\0'); -} - -// ---------------------------------------------------------------------------- -// access to the tokens -// ---------------------------------------------------------------------------- - -// do we have more of them? -bool wxStringTokenizer::HasMoreTokens() const -{ - wxCHECK_MSG( IsOk(), false, _T("you should call SetString() first") ); - - if ( m_string.find_first_not_of(m_delims, m_pos) != wxString::npos ) - { - // there are non delimiter characters left, so we do have more tokens - return true; - } - - switch ( m_mode ) - { - case wxTOKEN_RET_EMPTY: - case wxTOKEN_RET_DELIMS: - // special hack for wxTOKEN_RET_EMPTY: we should return the initial - // empty token even if there are only delimiters after it - return m_pos == 0 && !m_string.empty(); - - case wxTOKEN_RET_EMPTY_ALL: - // special hack for wxTOKEN_RET_EMPTY_ALL: we can know if we had - // already returned the trailing empty token after the last - // delimiter by examining m_lastDelim: it is set to NUL if we run - // up to the end of the string in GetNextToken(), but if it is not - // NUL yet we still have this last token to return even if m_pos is - // already at m_string.length() - return m_pos < m_string.length() || m_lastDelim != _T('\0'); - - case wxTOKEN_INVALID: - case wxTOKEN_DEFAULT: - wxFAIL_MSG( _T("unexpected tokenizer mode") ); - // fall through - - case wxTOKEN_STRTOK: - // never return empty delimiters - break; - } - - return false; -} - -// count the number of (remaining) tokens in the string -size_t wxStringTokenizer::CountTokens() const -{ - wxCHECK_MSG( IsOk(), 0, _T("you should call SetString() first") ); - - // VZ: this function is IMHO not very useful, so it's probably not very - // important if its implementation here is not as efficient as it - // could be -- but OTOH like this we're sure to get the correct answer - // in all modes - wxStringTokenizer tkz(m_string.c_str() + m_pos, m_delims, m_mode); - - size_t count = 0; - while ( tkz.HasMoreTokens() ) - { - count++; - - (void)tkz.GetNextToken(); - } - - return count; -} - -// ---------------------------------------------------------------------------- -// token extraction -// ---------------------------------------------------------------------------- - -wxString wxStringTokenizer::GetNextToken() -{ - wxString token; - do - { - if ( !HasMoreTokens() ) - { - break; - } - - // find the end of this token - size_t pos = m_string.find_first_of(m_delims, m_pos); - - // and the start of the next one - if ( pos == wxString::npos ) - { - // no more delimiters, the token is everything till the end of - // string - token.assign(m_string, m_pos, wxString::npos); - - // skip the token - m_pos = m_string.length(); - - // it wasn't terminated - m_lastDelim = _T('\0'); - } - else // we found a delimiter at pos - { - // in wxTOKEN_RET_DELIMS mode we return the delimiter character - // with token, otherwise leave it out - size_t len = pos - m_pos; - if ( m_mode == wxTOKEN_RET_DELIMS ) - len++; - - token.assign(m_string, m_pos, len); - - // skip the token and the trailing delimiter - m_pos = pos + 1; - - m_lastDelim = m_string[pos]; - } - } - while ( !AllowEmpty() && token.empty() ); - - return token; -} - -// ---------------------------------------------------------------------------- -// public functions -// ---------------------------------------------------------------------------- - -wxArrayString wxStringTokenize(const wxString& str, - const wxString& delims, - wxStringTokenizerMode mode) -{ - wxArrayString tokens; - wxStringTokenizer tk(str, delims, mode); - while ( tk.HasMoreTokens() ) - { - tokens.Add(tk.GetNextToken()); - } - - return tokens; -} +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/tokenzr.cpp +// Purpose: String tokenizer +// Author: Guilhem Lavaux +// Modified by: Vadim Zeitlin (almost full rewrite) +// Created: 04/22/98 +// RCS-ID: $Id: tokenzr.cpp 39694 2006-06-13 11:30:40Z ABX $ +// Copyright: (c) Guilhem Lavaux +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#include "wx/tokenzr.h" + +#ifndef WX_PRECOMP + #include "wx/arrstr.h" +#endif + +// Required for wxIs... functions +#include + +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// wxStringTokenizer construction +// ---------------------------------------------------------------------------- + +wxStringTokenizer::wxStringTokenizer(const wxString& str, + const wxString& delims, + wxStringTokenizerMode mode) +{ + SetString(str, delims, mode); +} + +void wxStringTokenizer::SetString(const wxString& str, + const wxString& delims, + wxStringTokenizerMode mode) +{ + if ( mode == wxTOKEN_DEFAULT ) + { + // by default, we behave like strtok() if the delimiters are only + // whitespace characters and as wxTOKEN_RET_EMPTY otherwise (for + // whitespace delimiters, strtok() behaviour is better because we want + // to count consecutive spaces as one delimiter) + const wxChar *p; + for ( p = delims.c_str(); *p; p++ ) + { + if ( !wxIsspace(*p) ) + break; + } + + if ( *p ) + { + // not whitespace char in delims + mode = wxTOKEN_RET_EMPTY; + } + else + { + // only whitespaces + mode = wxTOKEN_STRTOK; + } + } + + m_delims = delims; + m_mode = mode; + + Reinit(str); +} + +void wxStringTokenizer::Reinit(const wxString& str) +{ + wxASSERT_MSG( IsOk(), _T("you should call SetString() first") ); + + m_string = str; + m_pos = 0; + m_lastDelim = _T('\0'); +} + +// ---------------------------------------------------------------------------- +// access to the tokens +// ---------------------------------------------------------------------------- + +// do we have more of them? +bool wxStringTokenizer::HasMoreTokens() const +{ + wxCHECK_MSG( IsOk(), false, _T("you should call SetString() first") ); + + if ( m_string.find_first_not_of(m_delims, m_pos) != wxString::npos ) + { + // there are non delimiter characters left, so we do have more tokens + return true; + } + + switch ( m_mode ) + { + case wxTOKEN_RET_EMPTY: + case wxTOKEN_RET_DELIMS: + // special hack for wxTOKEN_RET_EMPTY: we should return the initial + // empty token even if there are only delimiters after it + return m_pos == 0 && !m_string.empty(); + + case wxTOKEN_RET_EMPTY_ALL: + // special hack for wxTOKEN_RET_EMPTY_ALL: we can know if we had + // already returned the trailing empty token after the last + // delimiter by examining m_lastDelim: it is set to NUL if we run + // up to the end of the string in GetNextToken(), but if it is not + // NUL yet we still have this last token to return even if m_pos is + // already at m_string.length() + return m_pos < m_string.length() || m_lastDelim != _T('\0'); + + case wxTOKEN_INVALID: + case wxTOKEN_DEFAULT: + wxFAIL_MSG( _T("unexpected tokenizer mode") ); + // fall through + + case wxTOKEN_STRTOK: + // never return empty delimiters + break; + } + + return false; +} + +// count the number of (remaining) tokens in the string +size_t wxStringTokenizer::CountTokens() const +{ + wxCHECK_MSG( IsOk(), 0, _T("you should call SetString() first") ); + + // VZ: this function is IMHO not very useful, so it's probably not very + // important if its implementation here is not as efficient as it + // could be -- but OTOH like this we're sure to get the correct answer + // in all modes + wxStringTokenizer tkz(m_string.c_str() + m_pos, m_delims, m_mode); + + size_t count = 0; + while ( tkz.HasMoreTokens() ) + { + count++; + + (void)tkz.GetNextToken(); + } + + return count; +} + +// ---------------------------------------------------------------------------- +// token extraction +// ---------------------------------------------------------------------------- + +wxString wxStringTokenizer::GetNextToken() +{ + wxString token; + do + { + if ( !HasMoreTokens() ) + { + break; + } + + // find the end of this token + size_t pos = m_string.find_first_of(m_delims, m_pos); + + // and the start of the next one + if ( pos == wxString::npos ) + { + // no more delimiters, the token is everything till the end of + // string + token.assign(m_string, m_pos, wxString::npos); + + // skip the token + m_pos = m_string.length(); + + // it wasn't terminated + m_lastDelim = _T('\0'); + } + else // we found a delimiter at pos + { + // in wxTOKEN_RET_DELIMS mode we return the delimiter character + // with token, otherwise leave it out + size_t len = pos - m_pos; + if ( m_mode == wxTOKEN_RET_DELIMS ) + len++; + + token.assign(m_string, m_pos, len); + + // skip the token and the trailing delimiter + m_pos = pos + 1; + + m_lastDelim = m_string[pos]; + } + } + while ( !AllowEmpty() && token.empty() ); + + return token; +} + +// ---------------------------------------------------------------------------- +// public functions +// ---------------------------------------------------------------------------- + +wxArrayString wxStringTokenize(const wxString& str, + const wxString& delims, + wxStringTokenizerMode mode) +{ + wxArrayString tokens; + wxStringTokenizer tk(str, delims, mode); + while ( tk.HasMoreTokens() ) + { + tokens.Add(tk.GetNextToken()); + } + + return tokens; +} diff --git a/Externals/wxWidgets/src/common/toplvcmn.cpp b/Externals/wxWidgets/src/common/toplvcmn.cpp index badf84ed25..304dd3ca74 100644 --- a/Externals/wxWidgets/src/common/toplvcmn.cpp +++ b/Externals/wxWidgets/src/common/toplvcmn.cpp @@ -1,431 +1,431 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/toplvcmn.cpp -// Purpose: common (for all platforms) wxTopLevelWindow functions -// Author: Julian Smart, Vadim Zeitlin -// Created: 01/02/97 -// Id: $Id: toplvcmn.cpp 53617 2008-05-17 12:56:18Z VZ $ -// Copyright: (c) 1998 Robert Roebling and Julian Smart -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#include "wx/toplevel.h" - -#ifndef WX_PRECOMP - #include "wx/dcclient.h" - #include "wx/app.h" -#endif // WX_PRECOMP - -#include "wx/display.h" - -// ---------------------------------------------------------------------------- -// event table -// ---------------------------------------------------------------------------- - -BEGIN_EVENT_TABLE(wxTopLevelWindowBase, wxWindow) - EVT_CLOSE(wxTopLevelWindowBase::OnCloseWindow) - EVT_SIZE(wxTopLevelWindowBase::OnSize) -END_EVENT_TABLE() - -// ============================================================================ -// implementation -// ============================================================================ - -IMPLEMENT_ABSTRACT_CLASS(wxTopLevelWindow, wxWindow) - -// ---------------------------------------------------------------------------- -// construction/destruction -// ---------------------------------------------------------------------------- - -wxTopLevelWindowBase::wxTopLevelWindowBase() -{ - // Unlike windows, top level windows are created hidden by default. - m_isShown = false; - m_winDefault = NULL; - m_winTmpDefault = NULL; -} - -wxTopLevelWindowBase::~wxTopLevelWindowBase() -{ - // don't let wxTheApp keep any stale pointers to us - if ( wxTheApp && wxTheApp->GetTopWindow() == this ) - wxTheApp->SetTopWindow(NULL); - - wxTopLevelWindows.DeleteObject(this); - - if ( IsLastBeforeExit() ) - { - // no other (important) windows left, quit the app - wxTheApp->ExitMainLoop(); - } -} - -bool wxTopLevelWindowBase::Destroy() -{ - // delayed destruction: the frame will be deleted during the next idle - // loop iteration - if ( !wxPendingDelete.Member(this) ) - wxPendingDelete.Append(this); - -#ifdef __WXMAC__ - // on mac we know that objects will always be deleted after this event - // has been handled, using Hide we avoid erratic redraws during window - // tear down - Hide(); -#else // !__WXMAC__ - // normally we want to hide the window immediately so that it doesn't get - // stuck on the screen while it's being destroyed, however we shouldn't - // hide the last visible window as then we might not get any idle events - // any more as no events will be sent to the hidden window and without idle - // events we won't prune wxPendingDelete list and the application won't - // terminate - for ( wxWindowList::const_iterator i = wxTopLevelWindows.begin(), - end = wxTopLevelWindows.end(); - i != end; - ++i ) - { - wxTopLevelWindow * const win = wx_static_cast(wxTopLevelWindow *, *i); - if ( win != this && win->IsShown() ) - { - // there remains at least one other visible TLW, we can hide this - // one - Hide(); - - break; - } - } -#endif // __WXMAC__/!__WXMAC__ - - return true; -} - -bool wxTopLevelWindowBase::IsLastBeforeExit() const -{ - // first of all, automatically exiting the app on last window close can be - // completely disabled at wxTheApp level - if ( !wxTheApp || !wxTheApp->GetExitOnFrameDelete() ) - return false; - - wxWindowList::const_iterator i; - const wxWindowList::const_iterator end = wxTopLevelWindows.end(); - - // then decide whether we should exit at all - for ( i = wxTopLevelWindows.begin(); i != end; ++i ) - { - wxTopLevelWindow * const win = wx_static_cast(wxTopLevelWindow *, *i); - if ( win->ShouldPreventAppExit() ) - { - // there remains at least one important TLW, don't exit - return false; - } - } - - // if yes, close all the other windows: this could still fail - for ( i = wxTopLevelWindows.begin(); i != end; ++i ) - { - // don't close twice the windows which are already marked for deletion - wxTopLevelWindow * const win = wx_static_cast(wxTopLevelWindow *, *i); - if ( !wxPendingDelete.Member(win) && !win->Close() ) - { - // one of the windows refused to close, don't exit - // - // NB: of course, by now some other windows could have been already - // closed but there is really nothing we can do about it as we - // have no way just to ask the window if it can close without - // forcing it to do it - return false; - } - } - - return true; -} - -// ---------------------------------------------------------------------------- -// wxTopLevelWindow geometry -// ---------------------------------------------------------------------------- - -void wxTopLevelWindowBase::SetMinSize(const wxSize& minSize) -{ - SetSizeHints( minSize.x, minSize.y, GetMaxWidth(), GetMaxHeight() ); -} - -void wxTopLevelWindowBase::SetMaxSize(const wxSize& maxSize) -{ - SetSizeHints( GetMinWidth(), GetMinHeight(), maxSize.x, maxSize.y ); -} - -// set the min/max size of the window -void wxTopLevelWindowBase::DoSetSizeHints(int minW, int minH, - int maxW, int maxH, - int WXUNUSED(incW), int WXUNUSED(incH)) -{ - // setting min width greater than max width leads to infinite loops under - // X11 and generally doesn't make any sense, so don't allow it - wxCHECK_RET( (minW == wxDefaultCoord || maxW == wxDefaultCoord || minW <= maxW) && - (minH == wxDefaultCoord || maxH == wxDefaultCoord || minH <= maxH), - _T("min width/height must be less than max width/height!") ); - - m_minWidth = minW; - m_maxWidth = maxW; - m_minHeight = minH; - m_maxHeight = maxH; -} - -void wxTopLevelWindowBase::GetRectForTopLevelChildren(int *x, int *y, int *w, int *h) -{ - GetPosition(x,y); - GetSize(w,h); -} - -/* static */ -wxSize wxTopLevelWindowBase::GetDefaultSize() -{ - wxSize size = wxGetClientDisplayRect().GetSize(); - - // create proportionally bigger windows on small screens - if ( size.x >= 1024 ) - size.x = 400; - else if ( size.x >= 800 ) - size.x = 300; - else if ( size.x >= 320 ) - size.x = 240; - - if ( size.y >= 768 ) - size.y = 250; - else if ( size.y > 200 ) - { - size.y *= 2; - size.y /= 3; - } - - return size; -} - -void wxTopLevelWindowBase::DoCentre(int dir) -{ - // on some platforms centering top level windows is impossible - // because they are always maximized by guidelines or limitations - if(IsAlwaysMaximized()) - return; - - // we need the display rect anyhow so store it first: notice that we should - // be centered on the same display as our parent window, the display of - // this window itself is not really defined yet - int nDisplay = wxDisplay::GetFromWindow(GetParent() ? GetParent() : this); - wxDisplay dpy(nDisplay == wxNOT_FOUND ? 0 : nDisplay); - const wxRect rectDisplay(dpy.GetClientArea()); - - // what should we centre this window on? - wxRect rectParent; - if ( !(dir & wxCENTRE_ON_SCREEN) && GetParent() ) - { - // centre on parent window: notice that we need screen coordinates for - // positioning this TLW - rectParent = GetParent()->GetScreenRect(); - - // if the parent is entirely off screen (happens at least with MDI - // parent frame under Mac but could happen elsewhere too if the frame - // was hidden/moved away for some reason), don't use it as otherwise - // this window wouldn't be visible at all - if ( !rectDisplay.Contains(rectParent.GetTopLeft()) && - !rectParent.Contains(rectParent.GetBottomRight()) ) - { - // this is enough to make IsEmpty() test below pass - rectParent.width = 0; - } - } - - if ( rectParent.IsEmpty() ) - { - // we were explicitely asked to centre this window on the entire screen - // or if we have no parent anyhow and so can't centre on it - rectParent = rectDisplay; - } - - // centering maximized window on screen is no-op - if((rectParent == rectDisplay) && IsMaximized()) - return; - - if ( !(dir & wxBOTH) ) - dir |= wxBOTH; // if neither is specified, center in both directions - - // the new window rect candidate - wxRect rect = GetRect().CentreIn(rectParent, dir & ~wxCENTRE_ON_SCREEN); - - // we don't want to place the window off screen if Centre() is called as - // this is (almost?) never wanted and it would be very difficult to prevent - // it from happening from the user code if we didn't check for it here - if ( !rectDisplay.Contains(rect.GetTopLeft()) ) - { - // move the window just enough to make the corner visible - int dx = rectDisplay.GetLeft() - rect.GetLeft(); - int dy = rectDisplay.GetTop() - rect.GetTop(); - rect.Offset(dx > 0 ? dx : 0, dy > 0 ? dy : 0); - } - - if ( !rectDisplay.Contains(rect.GetBottomRight()) ) - { - // do the same for this corner too - int dx = rectDisplay.GetRight() - rect.GetRight(); - int dy = rectDisplay.GetBottom() - rect.GetBottom(); - rect.Offset(dx < 0 ? dx : 0, dy < 0 ? dy : 0); - } - - // the window top left and bottom right corner are both visible now and - // although the window might still be not entirely on screen (with 2 - // staggered displays for example) we wouldn't be able to improve the - // layout much in such case, so we stop here - - // -1 could be valid coordinate here if there are several displays - SetSize(rect, wxSIZE_ALLOW_MINUS_ONE); -} - -// ---------------------------------------------------------------------------- -// wxTopLevelWindow size management: we exclude the areas taken by -// menu/status/toolbars from the client area, so the client area is what's -// really available for the frame contents -// ---------------------------------------------------------------------------- - -void wxTopLevelWindowBase::DoScreenToClient(int *x, int *y) const -{ - wxWindow::DoScreenToClient(x, y); - - // translate the wxWindow client coords to our client coords - wxPoint pt(GetClientAreaOrigin()); - if ( x ) - *x -= pt.x; - if ( y ) - *y -= pt.y; -} - -void wxTopLevelWindowBase::DoClientToScreen(int *x, int *y) const -{ - // our client area origin (0, 0) may be really something like (0, 30) for - // wxWindow if we have a toolbar, account for it before translating - wxPoint pt(GetClientAreaOrigin()); - if ( x ) - *x += pt.x; - if ( y ) - *y += pt.y; - - wxWindow::DoClientToScreen(x, y); -} - -bool wxTopLevelWindowBase::IsAlwaysMaximized() const -{ -#if defined(__SMARTPHONE__) || defined(__POCKETPC__) - return true; -#else - return false; -#endif -} - -// ---------------------------------------------------------------------------- -// event handlers -// ---------------------------------------------------------------------------- - -// default resizing behaviour - if only ONE subwindow, resize to fill the -// whole client area -void wxTopLevelWindowBase::DoLayout() -{ - // if we're using constraints or sizers - do use them - if ( GetAutoLayout() ) - { - Layout(); - } - else - { - // do we have _exactly_ one child? - wxWindow *child = (wxWindow *)NULL; - for ( wxWindowList::compatibility_iterator node = GetChildren().GetFirst(); - node; - node = node->GetNext() ) - { - wxWindow *win = node->GetData(); - - // exclude top level and managed windows (status bar isn't - // currently in the children list except under wxMac anyhow, but - // it makes no harm to test for it) - if ( !win->IsTopLevel() && !IsOneOfBars(win) ) - { - if ( child ) - { - return; // it's our second subwindow - nothing to do - } - - child = win; - } - } - - // do we have any children at all? - if ( child && child->IsShown() ) - { - // exactly one child - set it's size to fill the whole frame - int clientW, clientH; - DoGetClientSize(&clientW, &clientH); - - child->SetSize(0, 0, clientW, clientH); - } - } -} - -// The default implementation for the close window event. -void wxTopLevelWindowBase::OnCloseWindow(wxCloseEvent& WXUNUSED(event)) -{ - Destroy(); -} - -bool wxTopLevelWindowBase::SendIconizeEvent(bool iconized) -{ - wxIconizeEvent event(GetId(), iconized); - event.SetEventObject(this); - - return GetEventHandler()->ProcessEvent(event); -} - -// do the window-specific processing after processing the update event -void wxTopLevelWindowBase::DoUpdateWindowUI(wxUpdateUIEvent& event) -{ - // call inherited, but skip the wxControl's version, and call directly the - // wxWindow's one instead, because the only reason why we are overriding this - // function is that we want to use SetTitle() instead of wxControl::SetLabel() - wxWindowBase::DoUpdateWindowUI(event); - - // update title - if ( event.GetSetText() ) - { - if ( event.GetText() != GetTitle() ) - SetTitle(event.GetText()); - } -} - -void wxTopLevelWindowBase::RequestUserAttention(int WXUNUSED(flags)) -{ - // it's probably better than do nothing, isn't it? - Raise(); -} - -void wxTopLevelWindowBase::RemoveChild(wxWindowBase *child) -{ - if ( child == m_winDefault ) - m_winDefault = NULL; - - if ( child == m_winTmpDefault ) - m_winTmpDefault = NULL; - - wxWindow::RemoveChild(child); -} +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/toplvcmn.cpp +// Purpose: common (for all platforms) wxTopLevelWindow functions +// Author: Julian Smart, Vadim Zeitlin +// Created: 01/02/97 +// Id: $Id: toplvcmn.cpp 53617 2008-05-17 12:56:18Z VZ $ +// Copyright: (c) 1998 Robert Roebling and Julian Smart +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#include "wx/toplevel.h" + +#ifndef WX_PRECOMP + #include "wx/dcclient.h" + #include "wx/app.h" +#endif // WX_PRECOMP + +#include "wx/display.h" + +// ---------------------------------------------------------------------------- +// event table +// ---------------------------------------------------------------------------- + +BEGIN_EVENT_TABLE(wxTopLevelWindowBase, wxWindow) + EVT_CLOSE(wxTopLevelWindowBase::OnCloseWindow) + EVT_SIZE(wxTopLevelWindowBase::OnSize) +END_EVENT_TABLE() + +// ============================================================================ +// implementation +// ============================================================================ + +IMPLEMENT_ABSTRACT_CLASS(wxTopLevelWindow, wxWindow) + +// ---------------------------------------------------------------------------- +// construction/destruction +// ---------------------------------------------------------------------------- + +wxTopLevelWindowBase::wxTopLevelWindowBase() +{ + // Unlike windows, top level windows are created hidden by default. + m_isShown = false; + m_winDefault = NULL; + m_winTmpDefault = NULL; +} + +wxTopLevelWindowBase::~wxTopLevelWindowBase() +{ + // don't let wxTheApp keep any stale pointers to us + if ( wxTheApp && wxTheApp->GetTopWindow() == this ) + wxTheApp->SetTopWindow(NULL); + + wxTopLevelWindows.DeleteObject(this); + + if ( IsLastBeforeExit() ) + { + // no other (important) windows left, quit the app + wxTheApp->ExitMainLoop(); + } +} + +bool wxTopLevelWindowBase::Destroy() +{ + // delayed destruction: the frame will be deleted during the next idle + // loop iteration + if ( !wxPendingDelete.Member(this) ) + wxPendingDelete.Append(this); + +#ifdef __WXMAC__ + // on mac we know that objects will always be deleted after this event + // has been handled, using Hide we avoid erratic redraws during window + // tear down + Hide(); +#else // !__WXMAC__ + // normally we want to hide the window immediately so that it doesn't get + // stuck on the screen while it's being destroyed, however we shouldn't + // hide the last visible window as then we might not get any idle events + // any more as no events will be sent to the hidden window and without idle + // events we won't prune wxPendingDelete list and the application won't + // terminate + for ( wxWindowList::const_iterator i = wxTopLevelWindows.begin(), + end = wxTopLevelWindows.end(); + i != end; + ++i ) + { + wxTopLevelWindow * const win = wx_static_cast(wxTopLevelWindow *, *i); + if ( win != this && win->IsShown() ) + { + // there remains at least one other visible TLW, we can hide this + // one + Hide(); + + break; + } + } +#endif // __WXMAC__/!__WXMAC__ + + return true; +} + +bool wxTopLevelWindowBase::IsLastBeforeExit() const +{ + // first of all, automatically exiting the app on last window close can be + // completely disabled at wxTheApp level + if ( !wxTheApp || !wxTheApp->GetExitOnFrameDelete() ) + return false; + + wxWindowList::const_iterator i; + const wxWindowList::const_iterator end = wxTopLevelWindows.end(); + + // then decide whether we should exit at all + for ( i = wxTopLevelWindows.begin(); i != end; ++i ) + { + wxTopLevelWindow * const win = wx_static_cast(wxTopLevelWindow *, *i); + if ( win->ShouldPreventAppExit() ) + { + // there remains at least one important TLW, don't exit + return false; + } + } + + // if yes, close all the other windows: this could still fail + for ( i = wxTopLevelWindows.begin(); i != end; ++i ) + { + // don't close twice the windows which are already marked for deletion + wxTopLevelWindow * const win = wx_static_cast(wxTopLevelWindow *, *i); + if ( !wxPendingDelete.Member(win) && !win->Close() ) + { + // one of the windows refused to close, don't exit + // + // NB: of course, by now some other windows could have been already + // closed but there is really nothing we can do about it as we + // have no way just to ask the window if it can close without + // forcing it to do it + return false; + } + } + + return true; +} + +// ---------------------------------------------------------------------------- +// wxTopLevelWindow geometry +// ---------------------------------------------------------------------------- + +void wxTopLevelWindowBase::SetMinSize(const wxSize& minSize) +{ + SetSizeHints( minSize.x, minSize.y, GetMaxWidth(), GetMaxHeight() ); +} + +void wxTopLevelWindowBase::SetMaxSize(const wxSize& maxSize) +{ + SetSizeHints( GetMinWidth(), GetMinHeight(), maxSize.x, maxSize.y ); +} + +// set the min/max size of the window +void wxTopLevelWindowBase::DoSetSizeHints(int minW, int minH, + int maxW, int maxH, + int WXUNUSED(incW), int WXUNUSED(incH)) +{ + // setting min width greater than max width leads to infinite loops under + // X11 and generally doesn't make any sense, so don't allow it + wxCHECK_RET( (minW == wxDefaultCoord || maxW == wxDefaultCoord || minW <= maxW) && + (minH == wxDefaultCoord || maxH == wxDefaultCoord || minH <= maxH), + _T("min width/height must be less than max width/height!") ); + + m_minWidth = minW; + m_maxWidth = maxW; + m_minHeight = minH; + m_maxHeight = maxH; +} + +void wxTopLevelWindowBase::GetRectForTopLevelChildren(int *x, int *y, int *w, int *h) +{ + GetPosition(x,y); + GetSize(w,h); +} + +/* static */ +wxSize wxTopLevelWindowBase::GetDefaultSize() +{ + wxSize size = wxGetClientDisplayRect().GetSize(); + + // create proportionally bigger windows on small screens + if ( size.x >= 1024 ) + size.x = 400; + else if ( size.x >= 800 ) + size.x = 300; + else if ( size.x >= 320 ) + size.x = 240; + + if ( size.y >= 768 ) + size.y = 250; + else if ( size.y > 200 ) + { + size.y *= 2; + size.y /= 3; + } + + return size; +} + +void wxTopLevelWindowBase::DoCentre(int dir) +{ + // on some platforms centering top level windows is impossible + // because they are always maximized by guidelines or limitations + if(IsAlwaysMaximized()) + return; + + // we need the display rect anyhow so store it first: notice that we should + // be centered on the same display as our parent window, the display of + // this window itself is not really defined yet + int nDisplay = wxDisplay::GetFromWindow(GetParent() ? GetParent() : this); + wxDisplay dpy(nDisplay == wxNOT_FOUND ? 0 : nDisplay); + const wxRect rectDisplay(dpy.GetClientArea()); + + // what should we centre this window on? + wxRect rectParent; + if ( !(dir & wxCENTRE_ON_SCREEN) && GetParent() ) + { + // centre on parent window: notice that we need screen coordinates for + // positioning this TLW + rectParent = GetParent()->GetScreenRect(); + + // if the parent is entirely off screen (happens at least with MDI + // parent frame under Mac but could happen elsewhere too if the frame + // was hidden/moved away for some reason), don't use it as otherwise + // this window wouldn't be visible at all + if ( !rectDisplay.Contains(rectParent.GetTopLeft()) && + !rectParent.Contains(rectParent.GetBottomRight()) ) + { + // this is enough to make IsEmpty() test below pass + rectParent.width = 0; + } + } + + if ( rectParent.IsEmpty() ) + { + // we were explicitely asked to centre this window on the entire screen + // or if we have no parent anyhow and so can't centre on it + rectParent = rectDisplay; + } + + // centering maximized window on screen is no-op + if((rectParent == rectDisplay) && IsMaximized()) + return; + + if ( !(dir & wxBOTH) ) + dir |= wxBOTH; // if neither is specified, center in both directions + + // the new window rect candidate + wxRect rect = GetRect().CentreIn(rectParent, dir & ~wxCENTRE_ON_SCREEN); + + // we don't want to place the window off screen if Centre() is called as + // this is (almost?) never wanted and it would be very difficult to prevent + // it from happening from the user code if we didn't check for it here + if ( !rectDisplay.Contains(rect.GetTopLeft()) ) + { + // move the window just enough to make the corner visible + int dx = rectDisplay.GetLeft() - rect.GetLeft(); + int dy = rectDisplay.GetTop() - rect.GetTop(); + rect.Offset(dx > 0 ? dx : 0, dy > 0 ? dy : 0); + } + + if ( !rectDisplay.Contains(rect.GetBottomRight()) ) + { + // do the same for this corner too + int dx = rectDisplay.GetRight() - rect.GetRight(); + int dy = rectDisplay.GetBottom() - rect.GetBottom(); + rect.Offset(dx < 0 ? dx : 0, dy < 0 ? dy : 0); + } + + // the window top left and bottom right corner are both visible now and + // although the window might still be not entirely on screen (with 2 + // staggered displays for example) we wouldn't be able to improve the + // layout much in such case, so we stop here + + // -1 could be valid coordinate here if there are several displays + SetSize(rect, wxSIZE_ALLOW_MINUS_ONE); +} + +// ---------------------------------------------------------------------------- +// wxTopLevelWindow size management: we exclude the areas taken by +// menu/status/toolbars from the client area, so the client area is what's +// really available for the frame contents +// ---------------------------------------------------------------------------- + +void wxTopLevelWindowBase::DoScreenToClient(int *x, int *y) const +{ + wxWindow::DoScreenToClient(x, y); + + // translate the wxWindow client coords to our client coords + wxPoint pt(GetClientAreaOrigin()); + if ( x ) + *x -= pt.x; + if ( y ) + *y -= pt.y; +} + +void wxTopLevelWindowBase::DoClientToScreen(int *x, int *y) const +{ + // our client area origin (0, 0) may be really something like (0, 30) for + // wxWindow if we have a toolbar, account for it before translating + wxPoint pt(GetClientAreaOrigin()); + if ( x ) + *x += pt.x; + if ( y ) + *y += pt.y; + + wxWindow::DoClientToScreen(x, y); +} + +bool wxTopLevelWindowBase::IsAlwaysMaximized() const +{ +#if defined(__SMARTPHONE__) || defined(__POCKETPC__) + return true; +#else + return false; +#endif +} + +// ---------------------------------------------------------------------------- +// event handlers +// ---------------------------------------------------------------------------- + +// default resizing behaviour - if only ONE subwindow, resize to fill the +// whole client area +void wxTopLevelWindowBase::DoLayout() +{ + // if we're using constraints or sizers - do use them + if ( GetAutoLayout() ) + { + Layout(); + } + else + { + // do we have _exactly_ one child? + wxWindow *child = (wxWindow *)NULL; + for ( wxWindowList::compatibility_iterator node = GetChildren().GetFirst(); + node; + node = node->GetNext() ) + { + wxWindow *win = node->GetData(); + + // exclude top level and managed windows (status bar isn't + // currently in the children list except under wxMac anyhow, but + // it makes no harm to test for it) + if ( !win->IsTopLevel() && !IsOneOfBars(win) ) + { + if ( child ) + { + return; // it's our second subwindow - nothing to do + } + + child = win; + } + } + + // do we have any children at all? + if ( child && child->IsShown() ) + { + // exactly one child - set it's size to fill the whole frame + int clientW, clientH; + DoGetClientSize(&clientW, &clientH); + + child->SetSize(0, 0, clientW, clientH); + } + } +} + +// The default implementation for the close window event. +void wxTopLevelWindowBase::OnCloseWindow(wxCloseEvent& WXUNUSED(event)) +{ + Destroy(); +} + +bool wxTopLevelWindowBase::SendIconizeEvent(bool iconized) +{ + wxIconizeEvent event(GetId(), iconized); + event.SetEventObject(this); + + return GetEventHandler()->ProcessEvent(event); +} + +// do the window-specific processing after processing the update event +void wxTopLevelWindowBase::DoUpdateWindowUI(wxUpdateUIEvent& event) +{ + // call inherited, but skip the wxControl's version, and call directly the + // wxWindow's one instead, because the only reason why we are overriding this + // function is that we want to use SetTitle() instead of wxControl::SetLabel() + wxWindowBase::DoUpdateWindowUI(event); + + // update title + if ( event.GetSetText() ) + { + if ( event.GetText() != GetTitle() ) + SetTitle(event.GetText()); + } +} + +void wxTopLevelWindowBase::RequestUserAttention(int WXUNUSED(flags)) +{ + // it's probably better than do nothing, isn't it? + Raise(); +} + +void wxTopLevelWindowBase::RemoveChild(wxWindowBase *child) +{ + if ( child == m_winDefault ) + m_winDefault = NULL; + + if ( child == m_winTmpDefault ) + m_winTmpDefault = NULL; + + wxWindow::RemoveChild(child); +} diff --git a/Externals/wxWidgets/src/common/treebase.cpp b/Externals/wxWidgets/src/common/treebase.cpp index 2299e994e0..8613ab1d32 100644 --- a/Externals/wxWidgets/src/common/treebase.cpp +++ b/Externals/wxWidgets/src/common/treebase.cpp @@ -1,239 +1,239 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: treebase.cpp -// Purpose: Base wxTreeCtrl classes -// Author: Julian Smart -// Created: 01/02/97 -// Modified: -// Id: $Id: treebase.cpp 51356 2008-01-24 11:23:30Z VZ $ -// Copyright: (c) 1998 Robert Roebling, Julian Smart et al -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// ============================================================================= -// declarations -// ============================================================================= - -// ----------------------------------------------------------------------------- -// headers -// ----------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_TREECTRL - -#include "wx/treectrl.h" -#include "wx/imaglist.h" - -// ---------------------------------------------------------------------------- -// events -// ---------------------------------------------------------------------------- - -DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_BEGIN_DRAG) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_BEGIN_RDRAG) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_BEGIN_LABEL_EDIT) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_END_LABEL_EDIT) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_DELETE_ITEM) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_GET_INFO) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_SET_INFO) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_ITEM_EXPANDED) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_ITEM_EXPANDING) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_ITEM_COLLAPSED) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_ITEM_COLLAPSING) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_SEL_CHANGED) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_SEL_CHANGING) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_KEY_DOWN) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_ITEM_ACTIVATED) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_ITEM_RIGHT_CLICK) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_ITEM_MIDDLE_CLICK) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_END_DRAG) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_STATE_IMAGE_CLICK) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_ITEM_GETTOOLTIP) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_ITEM_MENU) - -// ---------------------------------------------------------------------------- -// Tree event -// ---------------------------------------------------------------------------- - -IMPLEMENT_ABSTRACT_CLASS(wxTreeEvent, wxNotifyEvent) - - -wxTreeEvent::wxTreeEvent(wxEventType commandType, - wxTreeCtrlBase *tree, - const wxTreeItemId& item) - : wxNotifyEvent(commandType, tree->GetId()), - m_item(item) -{ - m_editCancelled = false; - - SetEventObject(tree); - - if ( item.IsOk() ) - SetClientObject(tree->GetItemData(item)); -} - -wxTreeEvent::wxTreeEvent(wxEventType commandType, int id) - : wxNotifyEvent(commandType, id) -{ - m_itemOld = 0l; - m_editCancelled = false; -} - -wxTreeEvent::wxTreeEvent(const wxTreeEvent & event) - : wxNotifyEvent(event) -{ - m_evtKey = event.m_evtKey; - m_item = event.m_item; - m_itemOld = event.m_itemOld; - m_pointDrag = event.m_pointDrag; - m_label = event.m_label; - m_editCancelled = event.m_editCancelled; -} - -// ---------------------------------------------------------------------------- -// wxTreeCtrlBase -// ---------------------------------------------------------------------------- - -wxTreeCtrlBase::~wxTreeCtrlBase() -{ - if (m_ownsImageListNormal) - delete m_imageListNormal; - if (m_ownsImageListState) - delete m_imageListState; -} - -static void -wxGetBestTreeSize(const wxTreeCtrlBase* treeCtrl, wxTreeItemId id, wxSize& size) -{ - wxRect rect; - - if ( treeCtrl->GetBoundingRect(id, rect, true /* just the item */) ) - { - // Translate to logical position so we get the full extent -#if defined(__WXMSW__) && !defined(__WXUNIVERSAL__) - rect.x += treeCtrl->GetScrollPos(wxHORIZONTAL); - rect.y += treeCtrl->GetScrollPos(wxVERTICAL); -#endif - - size.IncTo(wxSize(rect.GetRight(), rect.GetBottom())); - } - - wxTreeItemIdValue cookie; - for ( wxTreeItemId item = treeCtrl->GetFirstChild(id, cookie); - item.IsOk(); - item = treeCtrl->GetNextChild(id, cookie) ) - { - wxGetBestTreeSize(treeCtrl, item, size); - } -} - -wxSize wxTreeCtrlBase::DoGetBestSize() const -{ - wxSize size; - - // this doesn't really compute the total bounding rectangle of all items - // but a not too bad guess of it which has the advantage of not having to - // examine all (potentially hundreds or thousands) items in the control - - if (GetQuickBestSize()) - { - for ( wxTreeItemId item = GetRootItem(); - item.IsOk(); - item = GetLastChild(item) ) - { - wxRect rect; - - // last parameter is "true" to get only the dimensions of the text - // label, we don't want to get the entire item width as it's determined - // by the current size - if ( GetBoundingRect(item, rect, true) ) - { - if ( size.x < rect.x + rect.width ) - size.x = rect.x + rect.width; - if ( size.y < rect.y + rect.height ) - size.y = rect.y + rect.height; - } - } - } - else // use precise, if potentially slow, size computation method - { - // iterate over all items recursively - wxTreeItemId idRoot = GetRootItem(); - if ( idRoot.IsOk() ) - wxGetBestTreeSize(this, idRoot, size); - } - - // need some minimal size even for empty tree - if ( !size.x || !size.y ) - size = wxControl::DoGetBestSize(); - else - { - // Add border size - size += GetWindowBorderSize(); - - CacheBestSize(size); - } - - return size; -} - -void wxTreeCtrlBase::ExpandAll() -{ - if ( IsEmpty() ) - return; - - ExpandAllChildren(GetRootItem()); -} - -void wxTreeCtrlBase::ExpandAllChildren(const wxTreeItemId& item) -{ - // expand this item first, this might result in its children being added on - // the fly - if ( item != GetRootItem() || !HasFlag(wxTR_HIDE_ROOT) ) - Expand(item); - //else: expanding hidden root item is unsupported and unnecessary - - // then (recursively) expand all the children - wxTreeItemIdValue cookie; - for ( wxTreeItemId idCurr = GetFirstChild(item, cookie); - idCurr.IsOk(); - idCurr = GetNextChild(item, cookie) ) - { - ExpandAllChildren(idCurr); - } -} - -void wxTreeCtrlBase::CollapseAll() -{ - if ( IsEmpty() ) - return; - - CollapseAllChildren(GetRootItem()); -} - -void wxTreeCtrlBase::CollapseAllChildren(const wxTreeItemId& item) -{ - // first (recursively) collapse all the children - wxTreeItemIdValue cookie; - for ( wxTreeItemId idCurr = GetFirstChild(item, cookie); - idCurr.IsOk(); - idCurr = GetNextChild(item, cookie) ) - { - CollapseAllChildren(idCurr); - } - - // then collapse this element too - Collapse(item); -} - -bool wxTreeCtrlBase::IsEmpty() const -{ - return !GetRootItem().IsOk(); -} - -#endif // wxUSE_TREECTRL - +///////////////////////////////////////////////////////////////////////////// +// Name: treebase.cpp +// Purpose: Base wxTreeCtrl classes +// Author: Julian Smart +// Created: 01/02/97 +// Modified: +// Id: $Id: treebase.cpp 51356 2008-01-24 11:23:30Z VZ $ +// Copyright: (c) 1998 Robert Roebling, Julian Smart et al +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================= +// declarations +// ============================================================================= + +// ----------------------------------------------------------------------------- +// headers +// ----------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_TREECTRL + +#include "wx/treectrl.h" +#include "wx/imaglist.h" + +// ---------------------------------------------------------------------------- +// events +// ---------------------------------------------------------------------------- + +DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_BEGIN_DRAG) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_BEGIN_RDRAG) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_BEGIN_LABEL_EDIT) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_END_LABEL_EDIT) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_DELETE_ITEM) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_GET_INFO) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_SET_INFO) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_ITEM_EXPANDED) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_ITEM_EXPANDING) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_ITEM_COLLAPSED) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_ITEM_COLLAPSING) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_SEL_CHANGED) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_SEL_CHANGING) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_KEY_DOWN) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_ITEM_ACTIVATED) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_ITEM_RIGHT_CLICK) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_ITEM_MIDDLE_CLICK) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_END_DRAG) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_STATE_IMAGE_CLICK) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_ITEM_GETTOOLTIP) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_ITEM_MENU) + +// ---------------------------------------------------------------------------- +// Tree event +// ---------------------------------------------------------------------------- + +IMPLEMENT_ABSTRACT_CLASS(wxTreeEvent, wxNotifyEvent) + + +wxTreeEvent::wxTreeEvent(wxEventType commandType, + wxTreeCtrlBase *tree, + const wxTreeItemId& item) + : wxNotifyEvent(commandType, tree->GetId()), + m_item(item) +{ + m_editCancelled = false; + + SetEventObject(tree); + + if ( item.IsOk() ) + SetClientObject(tree->GetItemData(item)); +} + +wxTreeEvent::wxTreeEvent(wxEventType commandType, int id) + : wxNotifyEvent(commandType, id) +{ + m_itemOld = 0l; + m_editCancelled = false; +} + +wxTreeEvent::wxTreeEvent(const wxTreeEvent & event) + : wxNotifyEvent(event) +{ + m_evtKey = event.m_evtKey; + m_item = event.m_item; + m_itemOld = event.m_itemOld; + m_pointDrag = event.m_pointDrag; + m_label = event.m_label; + m_editCancelled = event.m_editCancelled; +} + +// ---------------------------------------------------------------------------- +// wxTreeCtrlBase +// ---------------------------------------------------------------------------- + +wxTreeCtrlBase::~wxTreeCtrlBase() +{ + if (m_ownsImageListNormal) + delete m_imageListNormal; + if (m_ownsImageListState) + delete m_imageListState; +} + +static void +wxGetBestTreeSize(const wxTreeCtrlBase* treeCtrl, wxTreeItemId id, wxSize& size) +{ + wxRect rect; + + if ( treeCtrl->GetBoundingRect(id, rect, true /* just the item */) ) + { + // Translate to logical position so we get the full extent +#if defined(__WXMSW__) && !defined(__WXUNIVERSAL__) + rect.x += treeCtrl->GetScrollPos(wxHORIZONTAL); + rect.y += treeCtrl->GetScrollPos(wxVERTICAL); +#endif + + size.IncTo(wxSize(rect.GetRight(), rect.GetBottom())); + } + + wxTreeItemIdValue cookie; + for ( wxTreeItemId item = treeCtrl->GetFirstChild(id, cookie); + item.IsOk(); + item = treeCtrl->GetNextChild(id, cookie) ) + { + wxGetBestTreeSize(treeCtrl, item, size); + } +} + +wxSize wxTreeCtrlBase::DoGetBestSize() const +{ + wxSize size; + + // this doesn't really compute the total bounding rectangle of all items + // but a not too bad guess of it which has the advantage of not having to + // examine all (potentially hundreds or thousands) items in the control + + if (GetQuickBestSize()) + { + for ( wxTreeItemId item = GetRootItem(); + item.IsOk(); + item = GetLastChild(item) ) + { + wxRect rect; + + // last parameter is "true" to get only the dimensions of the text + // label, we don't want to get the entire item width as it's determined + // by the current size + if ( GetBoundingRect(item, rect, true) ) + { + if ( size.x < rect.x + rect.width ) + size.x = rect.x + rect.width; + if ( size.y < rect.y + rect.height ) + size.y = rect.y + rect.height; + } + } + } + else // use precise, if potentially slow, size computation method + { + // iterate over all items recursively + wxTreeItemId idRoot = GetRootItem(); + if ( idRoot.IsOk() ) + wxGetBestTreeSize(this, idRoot, size); + } + + // need some minimal size even for empty tree + if ( !size.x || !size.y ) + size = wxControl::DoGetBestSize(); + else + { + // Add border size + size += GetWindowBorderSize(); + + CacheBestSize(size); + } + + return size; +} + +void wxTreeCtrlBase::ExpandAll() +{ + if ( IsEmpty() ) + return; + + ExpandAllChildren(GetRootItem()); +} + +void wxTreeCtrlBase::ExpandAllChildren(const wxTreeItemId& item) +{ + // expand this item first, this might result in its children being added on + // the fly + if ( item != GetRootItem() || !HasFlag(wxTR_HIDE_ROOT) ) + Expand(item); + //else: expanding hidden root item is unsupported and unnecessary + + // then (recursively) expand all the children + wxTreeItemIdValue cookie; + for ( wxTreeItemId idCurr = GetFirstChild(item, cookie); + idCurr.IsOk(); + idCurr = GetNextChild(item, cookie) ) + { + ExpandAllChildren(idCurr); + } +} + +void wxTreeCtrlBase::CollapseAll() +{ + if ( IsEmpty() ) + return; + + CollapseAllChildren(GetRootItem()); +} + +void wxTreeCtrlBase::CollapseAllChildren(const wxTreeItemId& item) +{ + // first (recursively) collapse all the children + wxTreeItemIdValue cookie; + for ( wxTreeItemId idCurr = GetFirstChild(item, cookie); + idCurr.IsOk(); + idCurr = GetNextChild(item, cookie) ) + { + CollapseAllChildren(idCurr); + } + + // then collapse this element too + Collapse(item); +} + +bool wxTreeCtrlBase::IsEmpty() const +{ + return !GetRootItem().IsOk(); +} + +#endif // wxUSE_TREECTRL + diff --git a/Externals/wxWidgets/src/common/txtstrm.cpp b/Externals/wxWidgets/src/common/txtstrm.cpp index 0da50befdc..3dad170121 100644 --- a/Externals/wxWidgets/src/common/txtstrm.cpp +++ b/Externals/wxWidgets/src/common/txtstrm.cpp @@ -1,520 +1,520 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: src/common/txtstrm.cpp -// Purpose: Text stream classes -// Author: Guilhem Lavaux -// Modified by: -// Created: 28/06/98 -// RCS-ID: $Id: txtstrm.cpp 48920 2007-09-24 13:11:36Z JS $ -// Copyright: (c) Guilhem Lavaux -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_STREAMS - -#include "wx/txtstrm.h" -#include - - -// ---------------------------------------------------------------------------- -// constants -// ---------------------------------------------------------------------------- - -// Unix: "\n" -// Dos: "\r\n" -// Mac: "\r" - -// ---------------------------------------------------------------------------- -// wxTextInputStream -// ---------------------------------------------------------------------------- - -#if wxUSE_UNICODE -wxTextInputStream::wxTextInputStream(wxInputStream &s, - const wxString &sep, - const wxMBConv& conv) - : m_input(s), m_separators(sep), m_conv(conv.Clone()) -{ - memset((void*)m_lastBytes, 0, 10); -} -#else -wxTextInputStream::wxTextInputStream(wxInputStream &s, const wxString &sep) - : m_input(s), m_separators(sep) -{ - memset((void*)m_lastBytes, 0, 10); -} -#endif - -wxTextInputStream::~wxTextInputStream() -{ -#if wxUSE_UNICODE - delete m_conv; -#endif // wxUSE_UNICODE -} - -void wxTextInputStream::UngetLast() -{ - size_t byteCount = 0; - while(m_lastBytes[byteCount]) // pseudo ANSI strlen (even for Unicode!) - byteCount++; - m_input.Ungetch(m_lastBytes, byteCount); - memset((void*)m_lastBytes, 0, 10); -} - -wxChar wxTextInputStream::NextChar() -{ -#if wxUSE_UNICODE - wxChar wbuf[2]; - memset((void*)m_lastBytes, 0, 10); - for(size_t inlen = 0; inlen < 9; inlen++) - { - // actually read the next character - m_lastBytes[inlen] = m_input.GetC(); - - if(m_input.LastRead() <= 0) - return wxEOT; - - if ( m_conv->ToWChar(wbuf, WXSIZEOF(wbuf), m_lastBytes, inlen + 1) - != wxCONV_FAILED ) - return wbuf[0]; - } - // there should be no encoding which requires more than nine bytes for one character... - return wxEOT; -#else - m_lastBytes[0] = m_input.GetC(); - - if(m_input.LastRead() <= 0) - return wxEOT; - - return m_lastBytes[0]; -#endif - -} - -wxChar wxTextInputStream::NextNonSeparators() -{ - for (;;) - { - wxChar c = NextChar(); - if (c == wxEOT) return (wxChar) 0; - - if (c != wxT('\n') && - c != wxT('\r') && - !m_separators.Contains(c)) - return c; - } - -} - -bool wxTextInputStream::EatEOL(const wxChar &c) -{ - if (c == wxT('\n')) return true; // eat on UNIX - - if (c == wxT('\r')) // eat on both Mac and DOS - { - wxChar c2 = NextChar(); - if(c2 == wxEOT) return true; // end of stream reached, had enough :-) - - if (c2 != wxT('\n')) UngetLast(); // Don't eat on Mac - return true; - } - - return false; -} - -wxUint32 wxTextInputStream::Read32(int base) -{ - wxASSERT_MSG( !base || (base > 1 && base <= 36), _T("invalid base") ); - if(!m_input) return 0; - - wxString word = ReadWord(); - if(word.empty()) - return 0; - return wxStrtoul(word.c_str(), 0, base); -} - -wxUint16 wxTextInputStream::Read16(int base) -{ - return (wxUint16)Read32(base); -} - -wxUint8 wxTextInputStream::Read8(int base) -{ - return (wxUint8)Read32(base); -} - -wxInt32 wxTextInputStream::Read32S(int base) -{ - wxASSERT_MSG( !base || (base > 1 && base <= 36), _T("invalid base") ); - if(!m_input) return 0; - - wxString word = ReadWord(); - if(word.empty()) - return 0; - return wxStrtol(word.c_str(), 0, base); -} - -wxInt16 wxTextInputStream::Read16S(int base) -{ - return (wxInt16)Read32S(base); -} - -wxInt8 wxTextInputStream::Read8S(int base) -{ - return (wxInt8)Read32S(base); -} - -double wxTextInputStream::ReadDouble() -{ - if(!m_input) return 0; - wxString word = ReadWord(); - if(word.empty()) - return 0; - return wxStrtod(word.c_str(), 0); -} - -#if WXWIN_COMPATIBILITY_2_6 - -wxString wxTextInputStream::ReadString() -{ - return ReadLine(); -} - -#endif // WXWIN_COMPATIBILITY_2_6 - -wxString wxTextInputStream::ReadLine() -{ - wxString line; - - while ( !m_input.Eof() ) - { - wxChar c = NextChar(); - if(c == wxEOT) - break; - - if (EatEOL(c)) - break; - - line += c; - } - - return line; -} - -wxString wxTextInputStream::ReadWord() -{ - wxString word; - - if ( !m_input ) - return word; - - wxChar c = NextNonSeparators(); - if ( !c ) - return word; - - word += c; - - while ( !m_input.Eof() ) - { - c = NextChar(); - if(c == wxEOT) - break; - - if (m_separators.Contains(c)) - break; - - if (EatEOL(c)) - break; - - word += c; - } - - return word; -} - -wxTextInputStream& wxTextInputStream::operator>>(wxString& word) -{ - word = ReadWord(); - return *this; -} - -wxTextInputStream& wxTextInputStream::operator>>(char& c) -{ - c = m_input.GetC(); - if(m_input.LastRead() <= 0) c = 0; - - if (EatEOL(c)) - c = '\n'; - - return *this; -} - -#if wxUSE_UNICODE && wxWCHAR_T_IS_REAL_TYPE - -wxTextInputStream& wxTextInputStream::operator>>(wchar_t& wc) -{ - wc = GetChar(); - - return *this; -} - -#endif // wxUSE_UNICODE - -wxTextInputStream& wxTextInputStream::operator>>(wxInt16& i) -{ - i = (wxInt16)Read16(); - return *this; -} - -wxTextInputStream& wxTextInputStream::operator>>(wxInt32& i) -{ - i = (wxInt32)Read32(); - return *this; -} - -wxTextInputStream& wxTextInputStream::operator>>(wxUint16& i) -{ - i = Read16(); - return *this; -} - -wxTextInputStream& wxTextInputStream::operator>>(wxUint32& i) -{ - i = Read32(); - return *this; -} - -wxTextInputStream& wxTextInputStream::operator>>(double& i) -{ - i = ReadDouble(); - return *this; -} - -wxTextInputStream& wxTextInputStream::operator>>(float& f) -{ - f = (float)ReadDouble(); - return *this; -} - - - -#if wxUSE_UNICODE -wxTextOutputStream::wxTextOutputStream(wxOutputStream& s, - wxEOL mode, - const wxMBConv& conv) - : m_output(s), m_conv(conv.Clone()) -#else -wxTextOutputStream::wxTextOutputStream(wxOutputStream& s, wxEOL mode) - : m_output(s) -#endif -{ - m_mode = mode; - if (m_mode == wxEOL_NATIVE) - { -#if defined(__WXMSW__) || defined(__WXPM__) - m_mode = wxEOL_DOS; -#elif defined(__WXMAC__) && !defined(__DARWIN__) - m_mode = wxEOL_MAC; -#else - m_mode = wxEOL_UNIX; -#endif - } -} - -wxTextOutputStream::~wxTextOutputStream() -{ -#if wxUSE_UNICODE - delete m_conv; -#endif // wxUSE_UNICODE -} - -void wxTextOutputStream::SetMode(wxEOL mode) -{ - m_mode = mode; - if (m_mode == wxEOL_NATIVE) - { -#if defined(__WXMSW__) || defined(__WXPM__) - m_mode = wxEOL_DOS; -#elif defined(__WXMAC__) && !defined(__DARWIN__) - m_mode = wxEOL_MAC; -#else - m_mode = wxEOL_UNIX; -#endif - } -} - -void wxTextOutputStream::Write32(wxUint32 i) -{ - wxString str; - str.Printf(wxT("%u"), i); - - WriteString(str); -} - -void wxTextOutputStream::Write16(wxUint16 i) -{ - wxString str; - str.Printf(wxT("%u"), (unsigned)i); - - WriteString(str); -} - -void wxTextOutputStream::Write8(wxUint8 i) -{ - wxString str; - str.Printf(wxT("%u"), (unsigned)i); - - WriteString(str); -} - -void wxTextOutputStream::WriteDouble(double d) -{ - wxString str; - - str.Printf(wxT("%f"), d); - WriteString(str); -} - -void wxTextOutputStream::WriteString(const wxString& string) -{ - size_t len = string.length(); - - wxString out; - out.reserve(len); - - for ( size_t i = 0; i < len; i++ ) - { - const wxChar c = string[i]; - if ( c == wxT('\n') ) - { - switch ( m_mode ) - { - case wxEOL_DOS: - out << _T("\r\n"); - continue; - - case wxEOL_MAC: - out << _T('\r'); - continue; - - default: - wxFAIL_MSG( _T("unknown EOL mode in wxTextOutputStream") ); - // fall through - - case wxEOL_UNIX: - // don't treat '\n' specially - ; - } - } - - out << c; - } - -#if wxUSE_UNICODE - wxCharBuffer buffer = m_conv->cWC2MB(out, out.length(), &len); - m_output.Write(buffer, len); -#else - m_output.Write(out.c_str(), out.length() ); -#endif -} - -wxTextOutputStream& wxTextOutputStream::PutChar(wxChar c) -{ -#if wxUSE_UNICODE - WriteString( wxString(&c, *m_conv, 1) ); -#else - WriteString( wxString(&c, wxConvLocal, 1) ); -#endif - return *this; -} - -wxTextOutputStream& wxTextOutputStream::operator<<(const wxChar *string) -{ - WriteString( wxString(string) ); - return *this; -} - -wxTextOutputStream& wxTextOutputStream::operator<<(const wxString& string) -{ - WriteString( string ); - return *this; -} - -wxTextOutputStream& wxTextOutputStream::operator<<(char c) -{ - WriteString( wxString::FromAscii(c) ); - - return *this; -} - -#if wxUSE_UNICODE && wxWCHAR_T_IS_REAL_TYPE - -wxTextOutputStream& wxTextOutputStream::operator<<(wchar_t wc) -{ - WriteString( wxString(&wc, *m_conv, 1) ); - - return *this; -} - -#endif // wxUSE_UNICODE - -wxTextOutputStream& wxTextOutputStream::operator<<(wxInt16 c) -{ - wxString str; - str.Printf(wxT("%d"), (signed int)c); - WriteString(str); - - return *this; -} - -wxTextOutputStream& wxTextOutputStream::operator<<(wxInt32 c) -{ - wxString str; - str.Printf(wxT("%ld"), (signed long)c); - WriteString(str); - - return *this; -} - -wxTextOutputStream& wxTextOutputStream::operator<<(wxUint16 c) -{ - wxString str; - str.Printf(wxT("%u"), (unsigned int)c); - WriteString(str); - - return *this; -} - -wxTextOutputStream& wxTextOutputStream::operator<<(wxUint32 c) -{ - wxString str; - str.Printf(wxT("%lu"), (unsigned long)c); - WriteString(str); - - return *this; -} - -wxTextOutputStream &wxTextOutputStream::operator<<(double f) -{ - WriteDouble(f); - return *this; -} - -wxTextOutputStream& wxTextOutputStream::operator<<(float f) -{ - WriteDouble((double)f); - return *this; -} - -wxTextOutputStream &endl( wxTextOutputStream &stream ) -{ - return stream.PutChar(wxT('\n')); -} - -#endif - // wxUSE_STREAMS +/////////////////////////////////////////////////////////////////////////////// +// Name: src/common/txtstrm.cpp +// Purpose: Text stream classes +// Author: Guilhem Lavaux +// Modified by: +// Created: 28/06/98 +// RCS-ID: $Id: txtstrm.cpp 48920 2007-09-24 13:11:36Z JS $ +// Copyright: (c) Guilhem Lavaux +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_STREAMS + +#include "wx/txtstrm.h" +#include + + +// ---------------------------------------------------------------------------- +// constants +// ---------------------------------------------------------------------------- + +// Unix: "\n" +// Dos: "\r\n" +// Mac: "\r" + +// ---------------------------------------------------------------------------- +// wxTextInputStream +// ---------------------------------------------------------------------------- + +#if wxUSE_UNICODE +wxTextInputStream::wxTextInputStream(wxInputStream &s, + const wxString &sep, + const wxMBConv& conv) + : m_input(s), m_separators(sep), m_conv(conv.Clone()) +{ + memset((void*)m_lastBytes, 0, 10); +} +#else +wxTextInputStream::wxTextInputStream(wxInputStream &s, const wxString &sep) + : m_input(s), m_separators(sep) +{ + memset((void*)m_lastBytes, 0, 10); +} +#endif + +wxTextInputStream::~wxTextInputStream() +{ +#if wxUSE_UNICODE + delete m_conv; +#endif // wxUSE_UNICODE +} + +void wxTextInputStream::UngetLast() +{ + size_t byteCount = 0; + while(m_lastBytes[byteCount]) // pseudo ANSI strlen (even for Unicode!) + byteCount++; + m_input.Ungetch(m_lastBytes, byteCount); + memset((void*)m_lastBytes, 0, 10); +} + +wxChar wxTextInputStream::NextChar() +{ +#if wxUSE_UNICODE + wxChar wbuf[2]; + memset((void*)m_lastBytes, 0, 10); + for(size_t inlen = 0; inlen < 9; inlen++) + { + // actually read the next character + m_lastBytes[inlen] = m_input.GetC(); + + if(m_input.LastRead() <= 0) + return wxEOT; + + if ( m_conv->ToWChar(wbuf, WXSIZEOF(wbuf), m_lastBytes, inlen + 1) + != wxCONV_FAILED ) + return wbuf[0]; + } + // there should be no encoding which requires more than nine bytes for one character... + return wxEOT; +#else + m_lastBytes[0] = m_input.GetC(); + + if(m_input.LastRead() <= 0) + return wxEOT; + + return m_lastBytes[0]; +#endif + +} + +wxChar wxTextInputStream::NextNonSeparators() +{ + for (;;) + { + wxChar c = NextChar(); + if (c == wxEOT) return (wxChar) 0; + + if (c != wxT('\n') && + c != wxT('\r') && + !m_separators.Contains(c)) + return c; + } + +} + +bool wxTextInputStream::EatEOL(const wxChar &c) +{ + if (c == wxT('\n')) return true; // eat on UNIX + + if (c == wxT('\r')) // eat on both Mac and DOS + { + wxChar c2 = NextChar(); + if(c2 == wxEOT) return true; // end of stream reached, had enough :-) + + if (c2 != wxT('\n')) UngetLast(); // Don't eat on Mac + return true; + } + + return false; +} + +wxUint32 wxTextInputStream::Read32(int base) +{ + wxASSERT_MSG( !base || (base > 1 && base <= 36), _T("invalid base") ); + if(!m_input) return 0; + + wxString word = ReadWord(); + if(word.empty()) + return 0; + return wxStrtoul(word.c_str(), 0, base); +} + +wxUint16 wxTextInputStream::Read16(int base) +{ + return (wxUint16)Read32(base); +} + +wxUint8 wxTextInputStream::Read8(int base) +{ + return (wxUint8)Read32(base); +} + +wxInt32 wxTextInputStream::Read32S(int base) +{ + wxASSERT_MSG( !base || (base > 1 && base <= 36), _T("invalid base") ); + if(!m_input) return 0; + + wxString word = ReadWord(); + if(word.empty()) + return 0; + return wxStrtol(word.c_str(), 0, base); +} + +wxInt16 wxTextInputStream::Read16S(int base) +{ + return (wxInt16)Read32S(base); +} + +wxInt8 wxTextInputStream::Read8S(int base) +{ + return (wxInt8)Read32S(base); +} + +double wxTextInputStream::ReadDouble() +{ + if(!m_input) return 0; + wxString word = ReadWord(); + if(word.empty()) + return 0; + return wxStrtod(word.c_str(), 0); +} + +#if WXWIN_COMPATIBILITY_2_6 + +wxString wxTextInputStream::ReadString() +{ + return ReadLine(); +} + +#endif // WXWIN_COMPATIBILITY_2_6 + +wxString wxTextInputStream::ReadLine() +{ + wxString line; + + while ( !m_input.Eof() ) + { + wxChar c = NextChar(); + if(c == wxEOT) + break; + + if (EatEOL(c)) + break; + + line += c; + } + + return line; +} + +wxString wxTextInputStream::ReadWord() +{ + wxString word; + + if ( !m_input ) + return word; + + wxChar c = NextNonSeparators(); + if ( !c ) + return word; + + word += c; + + while ( !m_input.Eof() ) + { + c = NextChar(); + if(c == wxEOT) + break; + + if (m_separators.Contains(c)) + break; + + if (EatEOL(c)) + break; + + word += c; + } + + return word; +} + +wxTextInputStream& wxTextInputStream::operator>>(wxString& word) +{ + word = ReadWord(); + return *this; +} + +wxTextInputStream& wxTextInputStream::operator>>(char& c) +{ + c = m_input.GetC(); + if(m_input.LastRead() <= 0) c = 0; + + if (EatEOL(c)) + c = '\n'; + + return *this; +} + +#if wxUSE_UNICODE && wxWCHAR_T_IS_REAL_TYPE + +wxTextInputStream& wxTextInputStream::operator>>(wchar_t& wc) +{ + wc = GetChar(); + + return *this; +} + +#endif // wxUSE_UNICODE + +wxTextInputStream& wxTextInputStream::operator>>(wxInt16& i) +{ + i = (wxInt16)Read16(); + return *this; +} + +wxTextInputStream& wxTextInputStream::operator>>(wxInt32& i) +{ + i = (wxInt32)Read32(); + return *this; +} + +wxTextInputStream& wxTextInputStream::operator>>(wxUint16& i) +{ + i = Read16(); + return *this; +} + +wxTextInputStream& wxTextInputStream::operator>>(wxUint32& i) +{ + i = Read32(); + return *this; +} + +wxTextInputStream& wxTextInputStream::operator>>(double& i) +{ + i = ReadDouble(); + return *this; +} + +wxTextInputStream& wxTextInputStream::operator>>(float& f) +{ + f = (float)ReadDouble(); + return *this; +} + + + +#if wxUSE_UNICODE +wxTextOutputStream::wxTextOutputStream(wxOutputStream& s, + wxEOL mode, + const wxMBConv& conv) + : m_output(s), m_conv(conv.Clone()) +#else +wxTextOutputStream::wxTextOutputStream(wxOutputStream& s, wxEOL mode) + : m_output(s) +#endif +{ + m_mode = mode; + if (m_mode == wxEOL_NATIVE) + { +#if defined(__WXMSW__) || defined(__WXPM__) + m_mode = wxEOL_DOS; +#elif defined(__WXMAC__) && !defined(__DARWIN__) + m_mode = wxEOL_MAC; +#else + m_mode = wxEOL_UNIX; +#endif + } +} + +wxTextOutputStream::~wxTextOutputStream() +{ +#if wxUSE_UNICODE + delete m_conv; +#endif // wxUSE_UNICODE +} + +void wxTextOutputStream::SetMode(wxEOL mode) +{ + m_mode = mode; + if (m_mode == wxEOL_NATIVE) + { +#if defined(__WXMSW__) || defined(__WXPM__) + m_mode = wxEOL_DOS; +#elif defined(__WXMAC__) && !defined(__DARWIN__) + m_mode = wxEOL_MAC; +#else + m_mode = wxEOL_UNIX; +#endif + } +} + +void wxTextOutputStream::Write32(wxUint32 i) +{ + wxString str; + str.Printf(wxT("%u"), i); + + WriteString(str); +} + +void wxTextOutputStream::Write16(wxUint16 i) +{ + wxString str; + str.Printf(wxT("%u"), (unsigned)i); + + WriteString(str); +} + +void wxTextOutputStream::Write8(wxUint8 i) +{ + wxString str; + str.Printf(wxT("%u"), (unsigned)i); + + WriteString(str); +} + +void wxTextOutputStream::WriteDouble(double d) +{ + wxString str; + + str.Printf(wxT("%f"), d); + WriteString(str); +} + +void wxTextOutputStream::WriteString(const wxString& string) +{ + size_t len = string.length(); + + wxString out; + out.reserve(len); + + for ( size_t i = 0; i < len; i++ ) + { + const wxChar c = string[i]; + if ( c == wxT('\n') ) + { + switch ( m_mode ) + { + case wxEOL_DOS: + out << _T("\r\n"); + continue; + + case wxEOL_MAC: + out << _T('\r'); + continue; + + default: + wxFAIL_MSG( _T("unknown EOL mode in wxTextOutputStream") ); + // fall through + + case wxEOL_UNIX: + // don't treat '\n' specially + ; + } + } + + out << c; + } + +#if wxUSE_UNICODE + wxCharBuffer buffer = m_conv->cWC2MB(out, out.length(), &len); + m_output.Write(buffer, len); +#else + m_output.Write(out.c_str(), out.length() ); +#endif +} + +wxTextOutputStream& wxTextOutputStream::PutChar(wxChar c) +{ +#if wxUSE_UNICODE + WriteString( wxString(&c, *m_conv, 1) ); +#else + WriteString( wxString(&c, wxConvLocal, 1) ); +#endif + return *this; +} + +wxTextOutputStream& wxTextOutputStream::operator<<(const wxChar *string) +{ + WriteString( wxString(string) ); + return *this; +} + +wxTextOutputStream& wxTextOutputStream::operator<<(const wxString& string) +{ + WriteString( string ); + return *this; +} + +wxTextOutputStream& wxTextOutputStream::operator<<(char c) +{ + WriteString( wxString::FromAscii(c) ); + + return *this; +} + +#if wxUSE_UNICODE && wxWCHAR_T_IS_REAL_TYPE + +wxTextOutputStream& wxTextOutputStream::operator<<(wchar_t wc) +{ + WriteString( wxString(&wc, *m_conv, 1) ); + + return *this; +} + +#endif // wxUSE_UNICODE + +wxTextOutputStream& wxTextOutputStream::operator<<(wxInt16 c) +{ + wxString str; + str.Printf(wxT("%d"), (signed int)c); + WriteString(str); + + return *this; +} + +wxTextOutputStream& wxTextOutputStream::operator<<(wxInt32 c) +{ + wxString str; + str.Printf(wxT("%ld"), (signed long)c); + WriteString(str); + + return *this; +} + +wxTextOutputStream& wxTextOutputStream::operator<<(wxUint16 c) +{ + wxString str; + str.Printf(wxT("%u"), (unsigned int)c); + WriteString(str); + + return *this; +} + +wxTextOutputStream& wxTextOutputStream::operator<<(wxUint32 c) +{ + wxString str; + str.Printf(wxT("%lu"), (unsigned long)c); + WriteString(str); + + return *this; +} + +wxTextOutputStream &wxTextOutputStream::operator<<(double f) +{ + WriteDouble(f); + return *this; +} + +wxTextOutputStream& wxTextOutputStream::operator<<(float f) +{ + WriteDouble((double)f); + return *this; +} + +wxTextOutputStream &endl( wxTextOutputStream &stream ) +{ + return stream.PutChar(wxT('\n')); +} + +#endif + // wxUSE_STREAMS diff --git a/Externals/wxWidgets/src/common/uri.cpp b/Externals/wxWidgets/src/common/uri.cpp index 4c3e2f031d..a2ac7bde62 100644 --- a/Externals/wxWidgets/src/common/uri.cpp +++ b/Externals/wxWidgets/src/common/uri.cpp @@ -1,1298 +1,1298 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: uri.cpp -// Purpose: Implementation of a uri parser -// Author: Ryan Norton -// Created: 10/26/04 -// RCS-ID: $Id: uri.cpp 37403 2006-02-09 03:09:36Z VZ $ -// Copyright: (c) 2004 Ryan Norton -// Licence: wxWindows -///////////////////////////////////////////////////////////////////////////// - -// =========================================================================== -// declarations -// =========================================================================== - -// --------------------------------------------------------------------------- -// headers -// --------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#include "wx/uri.h" - -// --------------------------------------------------------------------------- -// definitions -// --------------------------------------------------------------------------- - -IMPLEMENT_CLASS(wxURI, wxObject) - -// =========================================================================== -// implementation -// =========================================================================== - -// --------------------------------------------------------------------------- -// utilities -// --------------------------------------------------------------------------- - -// --------------------------------------------------------------------------- -// -// wxURI -// -// --------------------------------------------------------------------------- - -// --------------------------------------------------------------------------- -// Constructors -// --------------------------------------------------------------------------- - -wxURI::wxURI() : m_hostType(wxURI_REGNAME), m_fields(0) -{ -} - -wxURI::wxURI(const wxString& uri) : m_hostType(wxURI_REGNAME), m_fields(0) -{ - Create(uri); -} - -wxURI::wxURI(const wxURI& uri) : wxObject(), m_hostType(wxURI_REGNAME), m_fields(0) -{ - Assign(uri); -} - -// --------------------------------------------------------------------------- -// Destructor and cleanup -// --------------------------------------------------------------------------- - -wxURI::~wxURI() -{ - Clear(); -} - -void wxURI::Clear() -{ - m_scheme = m_userinfo = m_server = m_port = m_path = - m_query = m_fragment = wxEmptyString; - - m_hostType = wxURI_REGNAME; - - m_fields = 0; -} - -// --------------------------------------------------------------------------- -// Create -// -// This creates the URI - all we do here is call the main parsing method -// --------------------------------------------------------------------------- - -const wxChar* wxURI::Create(const wxString& uri) -{ - if (m_fields) - Clear(); - - return Parse(uri); -} - -// --------------------------------------------------------------------------- -// Escape Methods -// -// TranslateEscape unencodes a 3 character URL escape sequence -// -// Escape encodes an invalid URI character into a 3 character sequence -// -// IsEscape determines if the input string contains an escape sequence, -// if it does, then it moves the input string past the escape sequence -// -// Unescape unencodes all 3 character URL escape sequences in a wxString -// --------------------------------------------------------------------------- - -wxChar wxURI::TranslateEscape(const wxChar* s) -{ - wxASSERT_MSG( IsHex(s[0]) && IsHex(s[1]), wxT("Invalid escape sequence!")); - - return wx_truncate_cast(wxChar, (CharToHex(s[0]) << 4 ) | CharToHex(s[1])); -} - -wxString wxURI::Unescape(const wxString& uri) -{ - wxString new_uri; - - for(size_t i = 0; i < uri.length(); ++i) - { - if (uri[i] == wxT('%')) - { - new_uri += wxURI::TranslateEscape( &(uri.c_str()[i+1]) ); - i += 2; - } - else - new_uri += uri[i]; - } - - return new_uri; -} - -void wxURI::Escape(wxString& s, const wxChar& c) -{ - const wxChar* hdig = wxT("0123456789abcdef"); - s += wxT('%'); - s += hdig[(c >> 4) & 15]; - s += hdig[c & 15]; -} - -bool wxURI::IsEscape(const wxChar*& uri) -{ - // pct-encoded = "%" HEXDIG HEXDIG - if(*uri == wxT('%') && IsHex(*(uri+1)) && IsHex(*(uri+2))) - return true; - else - return false; -} - -// --------------------------------------------------------------------------- -// GetUser -// GetPassword -// -// Gets the username and password via the old URL method. -// --------------------------------------------------------------------------- -wxString wxURI::GetUser() const -{ - size_t dwPasswordPos = m_userinfo.find(':'); - - if (dwPasswordPos == wxString::npos) - dwPasswordPos = 0; - - return m_userinfo(0, dwPasswordPos); -} - -wxString wxURI::GetPassword() const -{ - size_t dwPasswordPos = m_userinfo.find(':'); - - if (dwPasswordPos == wxString::npos) - return wxT(""); - else - return m_userinfo(dwPasswordPos+1, m_userinfo.length() + 1); -} - -// --------------------------------------------------------------------------- -// BuildURI -// -// BuildURI() builds the entire URI into a useable -// representation, including proper identification characters such as slashes -// -// BuildUnescapedURI() does the same thing as BuildURI(), only it unescapes -// the components that accept escape sequences -// --------------------------------------------------------------------------- - -wxString wxURI::BuildURI() const -{ - wxString ret; - - if (HasScheme()) - ret = ret + m_scheme + wxT(":"); - - if (HasServer()) - { - ret += wxT("//"); - - if (HasUserInfo()) - ret = ret + m_userinfo + wxT("@"); - - ret += m_server; - - if (HasPort()) - ret = ret + wxT(":") + m_port; - } - - ret += m_path; - - if (HasQuery()) - ret = ret + wxT("?") + m_query; - - if (HasFragment()) - ret = ret + wxT("#") + m_fragment; - - return ret; -} - -wxString wxURI::BuildUnescapedURI() const -{ - wxString ret; - - if (HasScheme()) - ret = ret + m_scheme + wxT(":"); - - if (HasServer()) - { - ret += wxT("//"); - - if (HasUserInfo()) - ret = ret + wxURI::Unescape(m_userinfo) + wxT("@"); - - if (m_hostType == wxURI_REGNAME) - ret += wxURI::Unescape(m_server); - else - ret += m_server; - - if (HasPort()) - ret = ret + wxT(":") + m_port; - } - - ret += wxURI::Unescape(m_path); - - if (HasQuery()) - ret = ret + wxT("?") + wxURI::Unescape(m_query); - - if (HasFragment()) - ret = ret + wxT("#") + wxURI::Unescape(m_fragment); - - return ret; -} - -// --------------------------------------------------------------------------- -// Assignment -// --------------------------------------------------------------------------- - -wxURI& wxURI::Assign(const wxURI& uri) -{ - //assign fields - m_fields = uri.m_fields; - - //ref over components - m_scheme = uri.m_scheme; - m_userinfo = uri.m_userinfo; - m_server = uri.m_server; - m_hostType = uri.m_hostType; - m_port = uri.m_port; - m_path = uri.m_path; - m_query = uri.m_query; - m_fragment = uri.m_fragment; - - return *this; -} - -wxURI& wxURI::operator = (const wxURI& uri) -{ - return Assign(uri); -} - -wxURI& wxURI::operator = (const wxString& string) -{ - Create(string); - return *this; -} - -// --------------------------------------------------------------------------- -// Comparison -// --------------------------------------------------------------------------- - -bool wxURI::operator == (const wxURI& uri) const -{ - if (HasScheme()) - { - if(m_scheme != uri.m_scheme) - return false; - } - else if (uri.HasScheme()) - return false; - - - if (HasServer()) - { - if (HasUserInfo()) - { - if (m_userinfo != uri.m_userinfo) - return false; - } - else if (uri.HasUserInfo()) - return false; - - if (m_server != uri.m_server || - m_hostType != uri.m_hostType) - return false; - - if (HasPort()) - { - if(m_port != uri.m_port) - return false; - } - else if (uri.HasPort()) - return false; - } - else if (uri.HasServer()) - return false; - - - if (HasPath()) - { - if(m_path != uri.m_path) - return false; - } - else if (uri.HasPath()) - return false; - - if (HasQuery()) - { - if (m_query != uri.m_query) - return false; - } - else if (uri.HasQuery()) - return false; - - if (HasFragment()) - { - if (m_fragment != uri.m_fragment) - return false; - } - else if (uri.HasFragment()) - return false; - - return true; -} - -// --------------------------------------------------------------------------- -// IsReference -// -// if there is no authority or scheme, it is a reference -// --------------------------------------------------------------------------- - -bool wxURI::IsReference() const -{ return !HasScheme() || !HasServer(); } - -// --------------------------------------------------------------------------- -// Parse -// -// Master URI parsing method. Just calls the individual parsing methods -// -// URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ] -// URI-reference = URI / relative -// --------------------------------------------------------------------------- - -const wxChar* wxURI::Parse(const wxChar* uri) -{ - uri = ParseScheme(uri); - uri = ParseAuthority(uri); - uri = ParsePath(uri); - uri = ParseQuery(uri); - return ParseFragment(uri); -} - -// --------------------------------------------------------------------------- -// ParseXXX -// -// Individual parsers for each URI component -// --------------------------------------------------------------------------- - -const wxChar* wxURI::ParseScheme(const wxChar* uri) -{ - wxASSERT(uri != NULL); - - //copy of the uri - used for figuring out - //length of each component - const wxChar* uricopy = uri; - - //Does the uri have a scheme (first character alpha)? - if (IsAlpha(*uri)) - { - m_scheme += *uri++; - - //scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." ) - while (IsAlpha(*uri) || IsDigit(*uri) || - *uri == wxT('+') || - *uri == wxT('-') || - *uri == wxT('.')) - { - m_scheme += *uri++; - } - - //valid scheme? - if (*uri == wxT(':')) - { - //mark the scheme as valid - m_fields |= wxURI_SCHEME; - - //move reference point up to input buffer - uricopy = ++uri; - } - else - //relative uri with relative path reference - m_scheme = wxEmptyString; - } -// else - //relative uri with _possible_ relative path reference - - return uricopy; -} - -const wxChar* wxURI::ParseAuthority(const wxChar* uri) -{ - // authority = [ userinfo "@" ] host [ ":" port ] - if (*uri == wxT('/') && *(uri+1) == wxT('/')) - { - //skip past the two slashes - uri += 2; - - // ############# DEVIATION FROM RFC ######################### - // Don't parse the server component for file URIs - if(m_scheme != wxT("file")) - { - //normal way - uri = ParseUserInfo(uri); - uri = ParseServer(uri); - return ParsePort(uri); - } - } - - return uri; -} - -const wxChar* wxURI::ParseUserInfo(const wxChar* uri) -{ - wxASSERT(uri != NULL); - - //copy of the uri - used for figuring out - //length of each component - const wxChar* uricopy = uri; - - // userinfo = *( unreserved / pct-encoded / sub-delims / ":" ) - while(*uri && *uri != wxT('@') && *uri != wxT('/') && *uri != wxT('#') && *uri != wxT('?')) - { - if(IsUnreserved(*uri) || - IsSubDelim(*uri) || *uri == wxT(':')) - m_userinfo += *uri++; - else if (IsEscape(uri)) - { - m_userinfo += *uri++; - m_userinfo += *uri++; - m_userinfo += *uri++; - } - else - Escape(m_userinfo, *uri++); - } - - if(*uri == wxT('@')) - { - //valid userinfo - m_fields |= wxURI_USERINFO; - - uricopy = ++uri; - } - else - m_userinfo = wxEmptyString; - - return uricopy; -} - -const wxChar* wxURI::ParseServer(const wxChar* uri) -{ - wxASSERT(uri != NULL); - - //copy of the uri - used for figuring out - //length of each component - const wxChar* uricopy = uri; - - // host = IP-literal / IPv4address / reg-name - // IP-literal = "[" ( IPv6address / IPvFuture ) "]" - if (*uri == wxT('[')) - { - ++uri; //some compilers don't support *&ing a ++* - if (ParseIPv6address(uri) && *uri == wxT(']')) - { - ++uri; - m_hostType = wxURI_IPV6ADDRESS; - - wxStringBufferLength theBuffer(m_server, uri - uricopy); - wxTmemcpy(theBuffer, uricopy, uri-uricopy); - theBuffer.SetLength(uri-uricopy); - } - else - { - uri = uricopy; - - ++uri; //some compilers don't support *&ing a ++* - if (ParseIPvFuture(uri) && *uri == wxT(']')) - { - ++uri; - m_hostType = wxURI_IPVFUTURE; - - wxStringBufferLength theBuffer(m_server, uri - uricopy); - wxTmemcpy(theBuffer, uricopy, uri-uricopy); - theBuffer.SetLength(uri-uricopy); - } - else - uri = uricopy; - } - } - else - { - if (ParseIPv4address(uri)) - { - m_hostType = wxURI_IPV4ADDRESS; - - wxStringBufferLength theBuffer(m_server, uri - uricopy); - wxTmemcpy(theBuffer, uricopy, uri-uricopy); - theBuffer.SetLength(uri-uricopy); - } - else - uri = uricopy; - } - - if(m_hostType == wxURI_REGNAME) - { - uri = uricopy; - // reg-name = *( unreserved / pct-encoded / sub-delims ) - while(*uri && *uri != wxT('/') && *uri != wxT(':') && *uri != wxT('#') && *uri != wxT('?')) - { - if(IsUnreserved(*uri) || IsSubDelim(*uri)) - m_server += *uri++; - else if (IsEscape(uri)) - { - m_server += *uri++; - m_server += *uri++; - m_server += *uri++; - } - else - Escape(m_server, *uri++); - } - } - - //mark the server as valid - m_fields |= wxURI_SERVER; - - return uri; -} - - -const wxChar* wxURI::ParsePort(const wxChar* uri) -{ - wxASSERT(uri != NULL); - - // port = *DIGIT - if(*uri == wxT(':')) - { - ++uri; - while(IsDigit(*uri)) - { - m_port += *uri++; - } - - //mark the port as valid - m_fields |= wxURI_PORT; - } - - return uri; -} - -const wxChar* wxURI::ParsePath(const wxChar* uri, bool bReference, bool bNormalize) -{ - wxASSERT(uri != NULL); - - //copy of the uri - used for figuring out - //length of each component - const wxChar* uricopy = uri; - - /// hier-part = "//" authority path-abempty - /// / path-absolute - /// / path-rootless - /// / path-empty - /// - /// relative-part = "//" authority path-abempty - /// / path-absolute - /// / path-noscheme - /// / path-empty - /// - /// path-abempty = *( "/" segment ) - /// path-absolute = "/" [ segment-nz *( "/" segment ) ] - /// path-noscheme = segment-nz-nc *( "/" segment ) - /// path-rootless = segment-nz *( "/" segment ) - /// path-empty = 0 - /// - /// segment = *pchar - /// segment-nz = 1*pchar - /// segment-nz-nc = 1*( unreserved / pct-encoded / sub-delims / "@" ) - /// ; non-zero-length segment without any colon ":" - /// - /// pchar = unreserved / pct-encoded / sub-delims / ":" / "@" - if (*uri == wxT('/')) - { - m_path += *uri++; - - while(*uri && *uri != wxT('#') && *uri != wxT('?')) - { - if( IsUnreserved(*uri) || IsSubDelim(*uri) || - *uri == wxT(':') || *uri == wxT('@') || *uri == wxT('/')) - m_path += *uri++; - else if (IsEscape(uri)) - { - m_path += *uri++; - m_path += *uri++; - m_path += *uri++; - } - else - Escape(m_path, *uri++); - } - - if (bNormalize) - { - wxStringBufferLength theBuffer(m_path, m_path.length() + 1); -#if wxUSE_STL - wxTmemcpy(theBuffer, m_path.c_str(), m_path.length()+1); -#endif - Normalize(theBuffer, true); - theBuffer.SetLength(wxStrlen(theBuffer)); - } - //mark the path as valid - m_fields |= wxURI_PATH; - } - else if(*uri) //Relative path - { - if (bReference) - { - //no colon allowed - while(*uri && *uri != wxT('#') && *uri != wxT('?')) - { - if(IsUnreserved(*uri) || IsSubDelim(*uri) || - *uri == wxT('@') || *uri == wxT('/')) - m_path += *uri++; - else if (IsEscape(uri)) - { - m_path += *uri++; - m_path += *uri++; - m_path += *uri++; - } - else - Escape(m_path, *uri++); - } - } - else - { - while(*uri && *uri != wxT('#') && *uri != wxT('?')) - { - if(IsUnreserved(*uri) || IsSubDelim(*uri) || - *uri == wxT(':') || *uri == wxT('@') || *uri == wxT('/')) - m_path += *uri++; - else if (IsEscape(uri)) - { - m_path += *uri++; - m_path += *uri++; - m_path += *uri++; - } - else - Escape(m_path, *uri++); - } - } - - if (uri != uricopy) - { - if (bNormalize) - { - wxStringBufferLength theBuffer(m_path, m_path.length() + 1); -#if wxUSE_STL - wxTmemcpy(theBuffer, m_path.c_str(), m_path.length()+1); -#endif - Normalize(theBuffer); - theBuffer.SetLength(wxStrlen(theBuffer)); - } - - //mark the path as valid - m_fields |= wxURI_PATH; - } - } - - return uri; -} - - -const wxChar* wxURI::ParseQuery(const wxChar* uri) -{ - wxASSERT(uri != NULL); - - // query = *( pchar / "/" / "?" ) - if (*uri == wxT('?')) - { - ++uri; - while(*uri && *uri != wxT('#')) - { - if (IsUnreserved(*uri) || IsSubDelim(*uri) || - *uri == wxT(':') || *uri == wxT('@') || *uri == wxT('/') || *uri == wxT('?')) - m_query += *uri++; - else if (IsEscape(uri)) - { - m_query += *uri++; - m_query += *uri++; - m_query += *uri++; - } - else - Escape(m_query, *uri++); - } - - //mark the server as valid - m_fields |= wxURI_QUERY; - } - - return uri; -} - - -const wxChar* wxURI::ParseFragment(const wxChar* uri) -{ - wxASSERT(uri != NULL); - - // fragment = *( pchar / "/" / "?" ) - if (*uri == wxT('#')) - { - ++uri; - while(*uri) - { - if (IsUnreserved(*uri) || IsSubDelim(*uri) || - *uri == wxT(':') || *uri == wxT('@') || *uri == wxT('/') || *uri == wxT('?')) - m_fragment += *uri++; - else if (IsEscape(uri)) - { - m_fragment += *uri++; - m_fragment += *uri++; - m_fragment += *uri++; - } - else - Escape(m_fragment, *uri++); - } - - //mark the server as valid - m_fields |= wxURI_FRAGMENT; - } - - return uri; -} - -// --------------------------------------------------------------------------- -// Resolve -// -// Builds missing components of this uri from a base uri -// -// A version of the algorithm outlined in the RFC is used here -// (it is shown in comments) -// -// Note that an empty URI inherits all components -// --------------------------------------------------------------------------- - -void wxURI::Resolve(const wxURI& base, int flags) -{ - wxASSERT_MSG(!base.IsReference(), - wxT("wxURI to inherit from must not be a reference!")); - - // If we arn't being strict, enable the older (pre-RFC2396) - // loophole that allows this uri to inherit other - // properties from the base uri - even if the scheme - // is defined - if ( !(flags & wxURI_STRICT) && - HasScheme() && base.HasScheme() && - m_scheme == base.m_scheme ) - { - m_fields -= wxURI_SCHEME; - } - - - // Do nothing if this is an absolute wxURI - // if defined(R.scheme) then - // T.scheme = R.scheme; - // T.authority = R.authority; - // T.path = remove_dot_segments(R.path); - // T.query = R.query; - if (HasScheme()) - { - return; - } - - //No scheme - inherit - m_scheme = base.m_scheme; - m_fields |= wxURI_SCHEME; - - // All we need to do for relative URIs with an - // authority component is just inherit the scheme - // if defined(R.authority) then - // T.authority = R.authority; - // T.path = remove_dot_segments(R.path); - // T.query = R.query; - if (HasServer()) - { - return; - } - - //No authority - inherit - if (base.HasUserInfo()) - { - m_userinfo = base.m_userinfo; - m_fields |= wxURI_USERINFO; - } - - m_server = base.m_server; - m_hostType = base.m_hostType; - m_fields |= wxURI_SERVER; - - if (base.HasPort()) - { - m_port = base.m_port; - m_fields |= wxURI_PORT; - } - - - // Simple path inheritance from base - if (!HasPath()) - { - // T.path = Base.path; - m_path = base.m_path; - m_fields |= wxURI_PATH; - - - // if defined(R.query) then - // T.query = R.query; - // else - // T.query = Base.query; - // endif; - if (!HasQuery()) - { - m_query = base.m_query; - m_fields |= wxURI_QUERY; - } - } - else - { - // if (R.path starts-with "/") then - // T.path = remove_dot_segments(R.path); - // else - // T.path = merge(Base.path, R.path); - // T.path = remove_dot_segments(T.path); - // endif; - // T.query = R.query; - if (m_path[0u] != wxT('/')) - { - //Merge paths - const wxChar* op = m_path.c_str(); - const wxChar* bp = base.m_path.c_str() + base.m_path.Length(); - - //not a ending directory? move up - if (base.m_path[0] && *(bp-1) != wxT('/')) - UpTree(base.m_path, bp); - - //normalize directories - while(*op == wxT('.') && *(op+1) == wxT('.') && - (*(op+2) == '\0' || *(op+2) == wxT('/')) ) - { - UpTree(base.m_path, bp); - - if (*(op+2) == '\0') - op += 2; - else - op += 3; - } - - m_path = base.m_path.substr(0, bp - base.m_path.c_str()) + - m_path.substr((op - m_path.c_str()), m_path.Length()); - } - } - - //T.fragment = R.fragment; -} - -// --------------------------------------------------------------------------- -// UpTree -// -// Moves a URI path up a directory -// --------------------------------------------------------------------------- - -//static -void wxURI::UpTree(const wxChar* uristart, const wxChar*& uri) -{ - if (uri != uristart && *(uri-1) == wxT('/')) - { - uri -= 2; - } - - for(;uri != uristart; --uri) - { - if (*uri == wxT('/')) - { - ++uri; - break; - } - } - - //!!!TODO:HACK!!!// - if (uri == uristart && *uri == wxT('/')) - ++uri; - //!!!// -} - -// --------------------------------------------------------------------------- -// Normalize -// -// Normalizes directories in-place -// -// I.E. ./ and . are ignored -// -// ../ and .. are removed if a directory is before it, along -// with that directory (leading .. and ../ are kept) -// --------------------------------------------------------------------------- - -//static -void wxURI::Normalize(wxChar* s, bool bIgnoreLeads) -{ - wxChar* cp = s; - wxChar* bp = s; - - if(s[0] == wxT('/')) - ++bp; - - while(*cp) - { - if (*cp == wxT('.') && (*(cp+1) == wxT('/') || *(cp+1) == '\0') - && (bp == cp || *(cp-1) == wxT('/'))) - { - //. _or_ ./ - ignore - if (*(cp+1) == '\0') - cp += 1; - else - cp += 2; - } - else if (*cp == wxT('.') && *(cp+1) == wxT('.') && - (*(cp+2) == wxT('/') || *(cp+2) == '\0') - && (bp == cp || *(cp-1) == wxT('/'))) - { - //.. _or_ ../ - go up the tree - if (s != bp) - { - UpTree((const wxChar*)bp, (const wxChar*&)s); - - if (*(cp+2) == '\0') - cp += 2; - else - cp += 3; - } - else if (!bIgnoreLeads) - - { - *bp++ = *cp++; - *bp++ = *cp++; - if (*cp) - *bp++ = *cp++; - - s = bp; - } - else - { - if (*(cp+2) == '\0') - cp += 2; - else - cp += 3; - } - } - else - *s++ = *cp++; - } - - *s = '\0'; -} - -// --------------------------------------------------------------------------- -// ParseH16 -// -// Parses 1 to 4 hex values. Returns true if the first character of the input -// string is a valid hex character. It is the caller's responsability to move -// the input string back to its original position on failure. -// --------------------------------------------------------------------------- - -bool wxURI::ParseH16(const wxChar*& uri) -{ - // h16 = 1*4HEXDIG - if(!IsHex(*++uri)) - return false; - - if(IsHex(*++uri) && IsHex(*++uri) && IsHex(*++uri)) - ++uri; - - return true; -} - -// --------------------------------------------------------------------------- -// ParseIPXXX -// -// Parses a certain version of an IP address and moves the input string past -// it. Returns true if the input string contains the proper version of an ip -// address. It is the caller's responsability to move the input string back -// to its original position on failure. -// --------------------------------------------------------------------------- - -bool wxURI::ParseIPv4address(const wxChar*& uri) -{ - //IPv4address = dec-octet "." dec-octet "." dec-octet "." dec-octet - // - //dec-octet = DIGIT ; 0-9 - // / %x31-39 DIGIT ; 10-99 - // / "1" 2DIGIT ; 100-199 - // / "2" %x30-34 DIGIT ; 200-249 - // / "25" %x30-35 ; 250-255 - size_t iIPv4 = 0; - if (IsDigit(*uri)) - { - ++iIPv4; - - - //each ip part must be between 0-255 (dupe of version in for loop) - if( IsDigit(*++uri) && IsDigit(*++uri) && - //100 or less (note !) - !( (*(uri-2) < wxT('2')) || - //240 or less - (*(uri-2) == wxT('2') && - (*(uri-1) < wxT('5') || (*(uri-1) == wxT('5') && *uri <= wxT('5'))) - ) - ) - ) - { - return false; - } - - if(IsDigit(*uri))++uri; - - //compilers should unroll this loop - for(; iIPv4 < 4; ++iIPv4) - { - if (*uri != wxT('.') || !IsDigit(*++uri)) - break; - - //each ip part must be between 0-255 - if( IsDigit(*++uri) && IsDigit(*++uri) && - //100 or less (note !) - !( (*(uri-2) < wxT('2')) || - //240 or less - (*(uri-2) == wxT('2') && - (*(uri-1) < wxT('5') || (*(uri-1) == wxT('5') && *uri <= wxT('5'))) - ) - ) - ) - { - return false; - } - if(IsDigit(*uri))++uri; - } - } - return iIPv4 == 4; -} - -bool wxURI::ParseIPv6address(const wxChar*& uri) -{ - // IPv6address = 6( h16 ":" ) ls32 - // / "::" 5( h16 ":" ) ls32 - // / [ h16 ] "::" 4( h16 ":" ) ls32 - // / [ *1( h16 ":" ) h16 ] "::" 3( h16 ":" ) ls32 - // / [ *2( h16 ":" ) h16 ] "::" 2( h16 ":" ) ls32 - // / [ *3( h16 ":" ) h16 ] "::" h16 ":" ls32 - // / [ *4( h16 ":" ) h16 ] "::" ls32 - // / [ *5( h16 ":" ) h16 ] "::" h16 - // / [ *6( h16 ":" ) h16 ] "::" - - size_t numPrefix = 0, - maxPostfix; - - bool bEndHex = false; - - for( ; numPrefix < 6; ++numPrefix) - { - if(!ParseH16(uri)) - { - --uri; - bEndHex = true; - break; - } - - if(*uri != wxT(':')) - { - break; - } - } - - if(!bEndHex && !ParseH16(uri)) - { - --uri; - - if (numPrefix) - return false; - - if (*uri == wxT(':')) - { - if (*++uri != wxT(':')) - return false; - - maxPostfix = 5; - } - else - maxPostfix = 6; - } - else - { - if (*uri != wxT(':') || *(uri+1) != wxT(':')) - { - if (numPrefix != 6) - return false; - - while (*--uri != wxT(':')) {} - ++uri; - - const wxChar* uristart = uri; - //parse ls32 - // ls32 = ( h16 ":" h16 ) / IPv4address - if (ParseH16(uri) && *uri == wxT(':') && ParseH16(uri)) - return true; - - uri = uristart; - - if (ParseIPv4address(uri)) - return true; - else - return false; - } - else - { - uri += 2; - - if (numPrefix > 3) - maxPostfix = 0; - else - maxPostfix = 4 - numPrefix; - } - } - - bool bAllowAltEnding = maxPostfix == 0; - - for(; maxPostfix != 0; --maxPostfix) - { - if(!ParseH16(uri) || *uri != wxT(':')) - return false; - } - - if(numPrefix <= 4) - { - const wxChar* uristart = uri; - //parse ls32 - // ls32 = ( h16 ":" h16 ) / IPv4address - if (ParseH16(uri) && *uri == wxT(':') && ParseH16(uri)) - return true; - - uri = uristart; - - if (ParseIPv4address(uri)) - return true; - - uri = uristart; - - if (!bAllowAltEnding) - return false; - } - - if(numPrefix <= 5 && ParseH16(uri)) - return true; - - return true; -} - -bool wxURI::ParseIPvFuture(const wxChar*& uri) -{ - // IPvFuture = "v" 1*HEXDIG "." 1*( unreserved / sub-delims / ":" ) - if (*++uri != wxT('v') || !IsHex(*++uri)) - return false; - - while (IsHex(*++uri)) {} - - if (*uri != wxT('.') || !(IsUnreserved(*++uri) || IsSubDelim(*uri) || *uri == wxT(':'))) - return false; - - while(IsUnreserved(*++uri) || IsSubDelim(*uri) || *uri == wxT(':')) {} - - return true; -} - - -// --------------------------------------------------------------------------- -// CharToHex -// -// Converts a character into a numeric hexidecimal value, or 0 if the -// passed in character is not a valid hex character -// --------------------------------------------------------------------------- - -//static -wxChar wxURI::CharToHex(const wxChar& c) -{ - if ((c >= wxT('A')) && (c <= wxT('Z'))) return wxChar(c - wxT('A') + 0x0A); - if ((c >= wxT('a')) && (c <= wxT('z'))) return wxChar(c - wxT('a') + 0x0a); - if ((c >= wxT('0')) && (c <= wxT('9'))) return wxChar(c - wxT('0') + 0x00); - - return 0; -} - -// --------------------------------------------------------------------------- -// IsXXX -// -// Returns true if the passed in character meets the criteria of the method -// --------------------------------------------------------------------------- - -//! unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~" -bool wxURI::IsUnreserved (const wxChar& c) -{ return IsAlpha(c) || IsDigit(c) || - c == wxT('-') || - c == wxT('.') || - c == wxT('_') || - c == wxT('~') //tilde - ; -} - -bool wxURI::IsReserved (const wxChar& c) -{ - return IsGenDelim(c) || IsSubDelim(c); -} - -//! gen-delims = ":" / "/" / "?" / "#" / "[" / "]" / "@" -bool wxURI::IsGenDelim (const wxChar& c) -{ - return c == wxT(':') || - c == wxT('/') || - c == wxT('?') || - c == wxT('#') || - c == wxT('[') || - c == wxT(']') || - c == wxT('@'); -} - -//! sub-delims = "!" / "$" / "&" / "'" / "(" / ")" -//! / "*" / "+" / "," / ";" / "=" -bool wxURI::IsSubDelim (const wxChar& c) -{ - return c == wxT('!') || - c == wxT('$') || - c == wxT('&') || - c == wxT('\'') || - c == wxT('(') || - c == wxT(')') || - c == wxT('*') || - c == wxT('+') || - c == wxT(',') || - c == wxT(';') || - c == wxT('=') - ; -} - -bool wxURI::IsHex(const wxChar& c) -{ return IsDigit(c) || (c >= wxT('a') && c <= wxT('f')) || (c >= wxT('A') && c <= wxT('F')); } - -bool wxURI::IsAlpha(const wxChar& c) -{ return (c >= wxT('a') && c <= wxT('z')) || (c >= wxT('A') && c <= wxT('Z')); } - -bool wxURI::IsDigit(const wxChar& c) -{ return c >= wxT('0') && c <= wxT('9'); } - - -//end of uri.cpp - - - +///////////////////////////////////////////////////////////////////////////// +// Name: uri.cpp +// Purpose: Implementation of a uri parser +// Author: Ryan Norton +// Created: 10/26/04 +// RCS-ID: $Id: uri.cpp 37403 2006-02-09 03:09:36Z VZ $ +// Copyright: (c) 2004 Ryan Norton +// Licence: wxWindows +///////////////////////////////////////////////////////////////////////////// + +// =========================================================================== +// declarations +// =========================================================================== + +// --------------------------------------------------------------------------- +// headers +// --------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#include "wx/uri.h" + +// --------------------------------------------------------------------------- +// definitions +// --------------------------------------------------------------------------- + +IMPLEMENT_CLASS(wxURI, wxObject) + +// =========================================================================== +// implementation +// =========================================================================== + +// --------------------------------------------------------------------------- +// utilities +// --------------------------------------------------------------------------- + +// --------------------------------------------------------------------------- +// +// wxURI +// +// --------------------------------------------------------------------------- + +// --------------------------------------------------------------------------- +// Constructors +// --------------------------------------------------------------------------- + +wxURI::wxURI() : m_hostType(wxURI_REGNAME), m_fields(0) +{ +} + +wxURI::wxURI(const wxString& uri) : m_hostType(wxURI_REGNAME), m_fields(0) +{ + Create(uri); +} + +wxURI::wxURI(const wxURI& uri) : wxObject(), m_hostType(wxURI_REGNAME), m_fields(0) +{ + Assign(uri); +} + +// --------------------------------------------------------------------------- +// Destructor and cleanup +// --------------------------------------------------------------------------- + +wxURI::~wxURI() +{ + Clear(); +} + +void wxURI::Clear() +{ + m_scheme = m_userinfo = m_server = m_port = m_path = + m_query = m_fragment = wxEmptyString; + + m_hostType = wxURI_REGNAME; + + m_fields = 0; +} + +// --------------------------------------------------------------------------- +// Create +// +// This creates the URI - all we do here is call the main parsing method +// --------------------------------------------------------------------------- + +const wxChar* wxURI::Create(const wxString& uri) +{ + if (m_fields) + Clear(); + + return Parse(uri); +} + +// --------------------------------------------------------------------------- +// Escape Methods +// +// TranslateEscape unencodes a 3 character URL escape sequence +// +// Escape encodes an invalid URI character into a 3 character sequence +// +// IsEscape determines if the input string contains an escape sequence, +// if it does, then it moves the input string past the escape sequence +// +// Unescape unencodes all 3 character URL escape sequences in a wxString +// --------------------------------------------------------------------------- + +wxChar wxURI::TranslateEscape(const wxChar* s) +{ + wxASSERT_MSG( IsHex(s[0]) && IsHex(s[1]), wxT("Invalid escape sequence!")); + + return wx_truncate_cast(wxChar, (CharToHex(s[0]) << 4 ) | CharToHex(s[1])); +} + +wxString wxURI::Unescape(const wxString& uri) +{ + wxString new_uri; + + for(size_t i = 0; i < uri.length(); ++i) + { + if (uri[i] == wxT('%')) + { + new_uri += wxURI::TranslateEscape( &(uri.c_str()[i+1]) ); + i += 2; + } + else + new_uri += uri[i]; + } + + return new_uri; +} + +void wxURI::Escape(wxString& s, const wxChar& c) +{ + const wxChar* hdig = wxT("0123456789abcdef"); + s += wxT('%'); + s += hdig[(c >> 4) & 15]; + s += hdig[c & 15]; +} + +bool wxURI::IsEscape(const wxChar*& uri) +{ + // pct-encoded = "%" HEXDIG HEXDIG + if(*uri == wxT('%') && IsHex(*(uri+1)) && IsHex(*(uri+2))) + return true; + else + return false; +} + +// --------------------------------------------------------------------------- +// GetUser +// GetPassword +// +// Gets the username and password via the old URL method. +// --------------------------------------------------------------------------- +wxString wxURI::GetUser() const +{ + size_t dwPasswordPos = m_userinfo.find(':'); + + if (dwPasswordPos == wxString::npos) + dwPasswordPos = 0; + + return m_userinfo(0, dwPasswordPos); +} + +wxString wxURI::GetPassword() const +{ + size_t dwPasswordPos = m_userinfo.find(':'); + + if (dwPasswordPos == wxString::npos) + return wxT(""); + else + return m_userinfo(dwPasswordPos+1, m_userinfo.length() + 1); +} + +// --------------------------------------------------------------------------- +// BuildURI +// +// BuildURI() builds the entire URI into a useable +// representation, including proper identification characters such as slashes +// +// BuildUnescapedURI() does the same thing as BuildURI(), only it unescapes +// the components that accept escape sequences +// --------------------------------------------------------------------------- + +wxString wxURI::BuildURI() const +{ + wxString ret; + + if (HasScheme()) + ret = ret + m_scheme + wxT(":"); + + if (HasServer()) + { + ret += wxT("//"); + + if (HasUserInfo()) + ret = ret + m_userinfo + wxT("@"); + + ret += m_server; + + if (HasPort()) + ret = ret + wxT(":") + m_port; + } + + ret += m_path; + + if (HasQuery()) + ret = ret + wxT("?") + m_query; + + if (HasFragment()) + ret = ret + wxT("#") + m_fragment; + + return ret; +} + +wxString wxURI::BuildUnescapedURI() const +{ + wxString ret; + + if (HasScheme()) + ret = ret + m_scheme + wxT(":"); + + if (HasServer()) + { + ret += wxT("//"); + + if (HasUserInfo()) + ret = ret + wxURI::Unescape(m_userinfo) + wxT("@"); + + if (m_hostType == wxURI_REGNAME) + ret += wxURI::Unescape(m_server); + else + ret += m_server; + + if (HasPort()) + ret = ret + wxT(":") + m_port; + } + + ret += wxURI::Unescape(m_path); + + if (HasQuery()) + ret = ret + wxT("?") + wxURI::Unescape(m_query); + + if (HasFragment()) + ret = ret + wxT("#") + wxURI::Unescape(m_fragment); + + return ret; +} + +// --------------------------------------------------------------------------- +// Assignment +// --------------------------------------------------------------------------- + +wxURI& wxURI::Assign(const wxURI& uri) +{ + //assign fields + m_fields = uri.m_fields; + + //ref over components + m_scheme = uri.m_scheme; + m_userinfo = uri.m_userinfo; + m_server = uri.m_server; + m_hostType = uri.m_hostType; + m_port = uri.m_port; + m_path = uri.m_path; + m_query = uri.m_query; + m_fragment = uri.m_fragment; + + return *this; +} + +wxURI& wxURI::operator = (const wxURI& uri) +{ + return Assign(uri); +} + +wxURI& wxURI::operator = (const wxString& string) +{ + Create(string); + return *this; +} + +// --------------------------------------------------------------------------- +// Comparison +// --------------------------------------------------------------------------- + +bool wxURI::operator == (const wxURI& uri) const +{ + if (HasScheme()) + { + if(m_scheme != uri.m_scheme) + return false; + } + else if (uri.HasScheme()) + return false; + + + if (HasServer()) + { + if (HasUserInfo()) + { + if (m_userinfo != uri.m_userinfo) + return false; + } + else if (uri.HasUserInfo()) + return false; + + if (m_server != uri.m_server || + m_hostType != uri.m_hostType) + return false; + + if (HasPort()) + { + if(m_port != uri.m_port) + return false; + } + else if (uri.HasPort()) + return false; + } + else if (uri.HasServer()) + return false; + + + if (HasPath()) + { + if(m_path != uri.m_path) + return false; + } + else if (uri.HasPath()) + return false; + + if (HasQuery()) + { + if (m_query != uri.m_query) + return false; + } + else if (uri.HasQuery()) + return false; + + if (HasFragment()) + { + if (m_fragment != uri.m_fragment) + return false; + } + else if (uri.HasFragment()) + return false; + + return true; +} + +// --------------------------------------------------------------------------- +// IsReference +// +// if there is no authority or scheme, it is a reference +// --------------------------------------------------------------------------- + +bool wxURI::IsReference() const +{ return !HasScheme() || !HasServer(); } + +// --------------------------------------------------------------------------- +// Parse +// +// Master URI parsing method. Just calls the individual parsing methods +// +// URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ] +// URI-reference = URI / relative +// --------------------------------------------------------------------------- + +const wxChar* wxURI::Parse(const wxChar* uri) +{ + uri = ParseScheme(uri); + uri = ParseAuthority(uri); + uri = ParsePath(uri); + uri = ParseQuery(uri); + return ParseFragment(uri); +} + +// --------------------------------------------------------------------------- +// ParseXXX +// +// Individual parsers for each URI component +// --------------------------------------------------------------------------- + +const wxChar* wxURI::ParseScheme(const wxChar* uri) +{ + wxASSERT(uri != NULL); + + //copy of the uri - used for figuring out + //length of each component + const wxChar* uricopy = uri; + + //Does the uri have a scheme (first character alpha)? + if (IsAlpha(*uri)) + { + m_scheme += *uri++; + + //scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." ) + while (IsAlpha(*uri) || IsDigit(*uri) || + *uri == wxT('+') || + *uri == wxT('-') || + *uri == wxT('.')) + { + m_scheme += *uri++; + } + + //valid scheme? + if (*uri == wxT(':')) + { + //mark the scheme as valid + m_fields |= wxURI_SCHEME; + + //move reference point up to input buffer + uricopy = ++uri; + } + else + //relative uri with relative path reference + m_scheme = wxEmptyString; + } +// else + //relative uri with _possible_ relative path reference + + return uricopy; +} + +const wxChar* wxURI::ParseAuthority(const wxChar* uri) +{ + // authority = [ userinfo "@" ] host [ ":" port ] + if (*uri == wxT('/') && *(uri+1) == wxT('/')) + { + //skip past the two slashes + uri += 2; + + // ############# DEVIATION FROM RFC ######################### + // Don't parse the server component for file URIs + if(m_scheme != wxT("file")) + { + //normal way + uri = ParseUserInfo(uri); + uri = ParseServer(uri); + return ParsePort(uri); + } + } + + return uri; +} + +const wxChar* wxURI::ParseUserInfo(const wxChar* uri) +{ + wxASSERT(uri != NULL); + + //copy of the uri - used for figuring out + //length of each component + const wxChar* uricopy = uri; + + // userinfo = *( unreserved / pct-encoded / sub-delims / ":" ) + while(*uri && *uri != wxT('@') && *uri != wxT('/') && *uri != wxT('#') && *uri != wxT('?')) + { + if(IsUnreserved(*uri) || + IsSubDelim(*uri) || *uri == wxT(':')) + m_userinfo += *uri++; + else if (IsEscape(uri)) + { + m_userinfo += *uri++; + m_userinfo += *uri++; + m_userinfo += *uri++; + } + else + Escape(m_userinfo, *uri++); + } + + if(*uri == wxT('@')) + { + //valid userinfo + m_fields |= wxURI_USERINFO; + + uricopy = ++uri; + } + else + m_userinfo = wxEmptyString; + + return uricopy; +} + +const wxChar* wxURI::ParseServer(const wxChar* uri) +{ + wxASSERT(uri != NULL); + + //copy of the uri - used for figuring out + //length of each component + const wxChar* uricopy = uri; + + // host = IP-literal / IPv4address / reg-name + // IP-literal = "[" ( IPv6address / IPvFuture ) "]" + if (*uri == wxT('[')) + { + ++uri; //some compilers don't support *&ing a ++* + if (ParseIPv6address(uri) && *uri == wxT(']')) + { + ++uri; + m_hostType = wxURI_IPV6ADDRESS; + + wxStringBufferLength theBuffer(m_server, uri - uricopy); + wxTmemcpy(theBuffer, uricopy, uri-uricopy); + theBuffer.SetLength(uri-uricopy); + } + else + { + uri = uricopy; + + ++uri; //some compilers don't support *&ing a ++* + if (ParseIPvFuture(uri) && *uri == wxT(']')) + { + ++uri; + m_hostType = wxURI_IPVFUTURE; + + wxStringBufferLength theBuffer(m_server, uri - uricopy); + wxTmemcpy(theBuffer, uricopy, uri-uricopy); + theBuffer.SetLength(uri-uricopy); + } + else + uri = uricopy; + } + } + else + { + if (ParseIPv4address(uri)) + { + m_hostType = wxURI_IPV4ADDRESS; + + wxStringBufferLength theBuffer(m_server, uri - uricopy); + wxTmemcpy(theBuffer, uricopy, uri-uricopy); + theBuffer.SetLength(uri-uricopy); + } + else + uri = uricopy; + } + + if(m_hostType == wxURI_REGNAME) + { + uri = uricopy; + // reg-name = *( unreserved / pct-encoded / sub-delims ) + while(*uri && *uri != wxT('/') && *uri != wxT(':') && *uri != wxT('#') && *uri != wxT('?')) + { + if(IsUnreserved(*uri) || IsSubDelim(*uri)) + m_server += *uri++; + else if (IsEscape(uri)) + { + m_server += *uri++; + m_server += *uri++; + m_server += *uri++; + } + else + Escape(m_server, *uri++); + } + } + + //mark the server as valid + m_fields |= wxURI_SERVER; + + return uri; +} + + +const wxChar* wxURI::ParsePort(const wxChar* uri) +{ + wxASSERT(uri != NULL); + + // port = *DIGIT + if(*uri == wxT(':')) + { + ++uri; + while(IsDigit(*uri)) + { + m_port += *uri++; + } + + //mark the port as valid + m_fields |= wxURI_PORT; + } + + return uri; +} + +const wxChar* wxURI::ParsePath(const wxChar* uri, bool bReference, bool bNormalize) +{ + wxASSERT(uri != NULL); + + //copy of the uri - used for figuring out + //length of each component + const wxChar* uricopy = uri; + + /// hier-part = "//" authority path-abempty + /// / path-absolute + /// / path-rootless + /// / path-empty + /// + /// relative-part = "//" authority path-abempty + /// / path-absolute + /// / path-noscheme + /// / path-empty + /// + /// path-abempty = *( "/" segment ) + /// path-absolute = "/" [ segment-nz *( "/" segment ) ] + /// path-noscheme = segment-nz-nc *( "/" segment ) + /// path-rootless = segment-nz *( "/" segment ) + /// path-empty = 0 + /// + /// segment = *pchar + /// segment-nz = 1*pchar + /// segment-nz-nc = 1*( unreserved / pct-encoded / sub-delims / "@" ) + /// ; non-zero-length segment without any colon ":" + /// + /// pchar = unreserved / pct-encoded / sub-delims / ":" / "@" + if (*uri == wxT('/')) + { + m_path += *uri++; + + while(*uri && *uri != wxT('#') && *uri != wxT('?')) + { + if( IsUnreserved(*uri) || IsSubDelim(*uri) || + *uri == wxT(':') || *uri == wxT('@') || *uri == wxT('/')) + m_path += *uri++; + else if (IsEscape(uri)) + { + m_path += *uri++; + m_path += *uri++; + m_path += *uri++; + } + else + Escape(m_path, *uri++); + } + + if (bNormalize) + { + wxStringBufferLength theBuffer(m_path, m_path.length() + 1); +#if wxUSE_STL + wxTmemcpy(theBuffer, m_path.c_str(), m_path.length()+1); +#endif + Normalize(theBuffer, true); + theBuffer.SetLength(wxStrlen(theBuffer)); + } + //mark the path as valid + m_fields |= wxURI_PATH; + } + else if(*uri) //Relative path + { + if (bReference) + { + //no colon allowed + while(*uri && *uri != wxT('#') && *uri != wxT('?')) + { + if(IsUnreserved(*uri) || IsSubDelim(*uri) || + *uri == wxT('@') || *uri == wxT('/')) + m_path += *uri++; + else if (IsEscape(uri)) + { + m_path += *uri++; + m_path += *uri++; + m_path += *uri++; + } + else + Escape(m_path, *uri++); + } + } + else + { + while(*uri && *uri != wxT('#') && *uri != wxT('?')) + { + if(IsUnreserved(*uri) || IsSubDelim(*uri) || + *uri == wxT(':') || *uri == wxT('@') || *uri == wxT('/')) + m_path += *uri++; + else if (IsEscape(uri)) + { + m_path += *uri++; + m_path += *uri++; + m_path += *uri++; + } + else + Escape(m_path, *uri++); + } + } + + if (uri != uricopy) + { + if (bNormalize) + { + wxStringBufferLength theBuffer(m_path, m_path.length() + 1); +#if wxUSE_STL + wxTmemcpy(theBuffer, m_path.c_str(), m_path.length()+1); +#endif + Normalize(theBuffer); + theBuffer.SetLength(wxStrlen(theBuffer)); + } + + //mark the path as valid + m_fields |= wxURI_PATH; + } + } + + return uri; +} + + +const wxChar* wxURI::ParseQuery(const wxChar* uri) +{ + wxASSERT(uri != NULL); + + // query = *( pchar / "/" / "?" ) + if (*uri == wxT('?')) + { + ++uri; + while(*uri && *uri != wxT('#')) + { + if (IsUnreserved(*uri) || IsSubDelim(*uri) || + *uri == wxT(':') || *uri == wxT('@') || *uri == wxT('/') || *uri == wxT('?')) + m_query += *uri++; + else if (IsEscape(uri)) + { + m_query += *uri++; + m_query += *uri++; + m_query += *uri++; + } + else + Escape(m_query, *uri++); + } + + //mark the server as valid + m_fields |= wxURI_QUERY; + } + + return uri; +} + + +const wxChar* wxURI::ParseFragment(const wxChar* uri) +{ + wxASSERT(uri != NULL); + + // fragment = *( pchar / "/" / "?" ) + if (*uri == wxT('#')) + { + ++uri; + while(*uri) + { + if (IsUnreserved(*uri) || IsSubDelim(*uri) || + *uri == wxT(':') || *uri == wxT('@') || *uri == wxT('/') || *uri == wxT('?')) + m_fragment += *uri++; + else if (IsEscape(uri)) + { + m_fragment += *uri++; + m_fragment += *uri++; + m_fragment += *uri++; + } + else + Escape(m_fragment, *uri++); + } + + //mark the server as valid + m_fields |= wxURI_FRAGMENT; + } + + return uri; +} + +// --------------------------------------------------------------------------- +// Resolve +// +// Builds missing components of this uri from a base uri +// +// A version of the algorithm outlined in the RFC is used here +// (it is shown in comments) +// +// Note that an empty URI inherits all components +// --------------------------------------------------------------------------- + +void wxURI::Resolve(const wxURI& base, int flags) +{ + wxASSERT_MSG(!base.IsReference(), + wxT("wxURI to inherit from must not be a reference!")); + + // If we arn't being strict, enable the older (pre-RFC2396) + // loophole that allows this uri to inherit other + // properties from the base uri - even if the scheme + // is defined + if ( !(flags & wxURI_STRICT) && + HasScheme() && base.HasScheme() && + m_scheme == base.m_scheme ) + { + m_fields -= wxURI_SCHEME; + } + + + // Do nothing if this is an absolute wxURI + // if defined(R.scheme) then + // T.scheme = R.scheme; + // T.authority = R.authority; + // T.path = remove_dot_segments(R.path); + // T.query = R.query; + if (HasScheme()) + { + return; + } + + //No scheme - inherit + m_scheme = base.m_scheme; + m_fields |= wxURI_SCHEME; + + // All we need to do for relative URIs with an + // authority component is just inherit the scheme + // if defined(R.authority) then + // T.authority = R.authority; + // T.path = remove_dot_segments(R.path); + // T.query = R.query; + if (HasServer()) + { + return; + } + + //No authority - inherit + if (base.HasUserInfo()) + { + m_userinfo = base.m_userinfo; + m_fields |= wxURI_USERINFO; + } + + m_server = base.m_server; + m_hostType = base.m_hostType; + m_fields |= wxURI_SERVER; + + if (base.HasPort()) + { + m_port = base.m_port; + m_fields |= wxURI_PORT; + } + + + // Simple path inheritance from base + if (!HasPath()) + { + // T.path = Base.path; + m_path = base.m_path; + m_fields |= wxURI_PATH; + + + // if defined(R.query) then + // T.query = R.query; + // else + // T.query = Base.query; + // endif; + if (!HasQuery()) + { + m_query = base.m_query; + m_fields |= wxURI_QUERY; + } + } + else + { + // if (R.path starts-with "/") then + // T.path = remove_dot_segments(R.path); + // else + // T.path = merge(Base.path, R.path); + // T.path = remove_dot_segments(T.path); + // endif; + // T.query = R.query; + if (m_path[0u] != wxT('/')) + { + //Merge paths + const wxChar* op = m_path.c_str(); + const wxChar* bp = base.m_path.c_str() + base.m_path.Length(); + + //not a ending directory? move up + if (base.m_path[0] && *(bp-1) != wxT('/')) + UpTree(base.m_path, bp); + + //normalize directories + while(*op == wxT('.') && *(op+1) == wxT('.') && + (*(op+2) == '\0' || *(op+2) == wxT('/')) ) + { + UpTree(base.m_path, bp); + + if (*(op+2) == '\0') + op += 2; + else + op += 3; + } + + m_path = base.m_path.substr(0, bp - base.m_path.c_str()) + + m_path.substr((op - m_path.c_str()), m_path.Length()); + } + } + + //T.fragment = R.fragment; +} + +// --------------------------------------------------------------------------- +// UpTree +// +// Moves a URI path up a directory +// --------------------------------------------------------------------------- + +//static +void wxURI::UpTree(const wxChar* uristart, const wxChar*& uri) +{ + if (uri != uristart && *(uri-1) == wxT('/')) + { + uri -= 2; + } + + for(;uri != uristart; --uri) + { + if (*uri == wxT('/')) + { + ++uri; + break; + } + } + + //!!!TODO:HACK!!!// + if (uri == uristart && *uri == wxT('/')) + ++uri; + //!!!// +} + +// --------------------------------------------------------------------------- +// Normalize +// +// Normalizes directories in-place +// +// I.E. ./ and . are ignored +// +// ../ and .. are removed if a directory is before it, along +// with that directory (leading .. and ../ are kept) +// --------------------------------------------------------------------------- + +//static +void wxURI::Normalize(wxChar* s, bool bIgnoreLeads) +{ + wxChar* cp = s; + wxChar* bp = s; + + if(s[0] == wxT('/')) + ++bp; + + while(*cp) + { + if (*cp == wxT('.') && (*(cp+1) == wxT('/') || *(cp+1) == '\0') + && (bp == cp || *(cp-1) == wxT('/'))) + { + //. _or_ ./ - ignore + if (*(cp+1) == '\0') + cp += 1; + else + cp += 2; + } + else if (*cp == wxT('.') && *(cp+1) == wxT('.') && + (*(cp+2) == wxT('/') || *(cp+2) == '\0') + && (bp == cp || *(cp-1) == wxT('/'))) + { + //.. _or_ ../ - go up the tree + if (s != bp) + { + UpTree((const wxChar*)bp, (const wxChar*&)s); + + if (*(cp+2) == '\0') + cp += 2; + else + cp += 3; + } + else if (!bIgnoreLeads) + + { + *bp++ = *cp++; + *bp++ = *cp++; + if (*cp) + *bp++ = *cp++; + + s = bp; + } + else + { + if (*(cp+2) == '\0') + cp += 2; + else + cp += 3; + } + } + else + *s++ = *cp++; + } + + *s = '\0'; +} + +// --------------------------------------------------------------------------- +// ParseH16 +// +// Parses 1 to 4 hex values. Returns true if the first character of the input +// string is a valid hex character. It is the caller's responsability to move +// the input string back to its original position on failure. +// --------------------------------------------------------------------------- + +bool wxURI::ParseH16(const wxChar*& uri) +{ + // h16 = 1*4HEXDIG + if(!IsHex(*++uri)) + return false; + + if(IsHex(*++uri) && IsHex(*++uri) && IsHex(*++uri)) + ++uri; + + return true; +} + +// --------------------------------------------------------------------------- +// ParseIPXXX +// +// Parses a certain version of an IP address and moves the input string past +// it. Returns true if the input string contains the proper version of an ip +// address. It is the caller's responsability to move the input string back +// to its original position on failure. +// --------------------------------------------------------------------------- + +bool wxURI::ParseIPv4address(const wxChar*& uri) +{ + //IPv4address = dec-octet "." dec-octet "." dec-octet "." dec-octet + // + //dec-octet = DIGIT ; 0-9 + // / %x31-39 DIGIT ; 10-99 + // / "1" 2DIGIT ; 100-199 + // / "2" %x30-34 DIGIT ; 200-249 + // / "25" %x30-35 ; 250-255 + size_t iIPv4 = 0; + if (IsDigit(*uri)) + { + ++iIPv4; + + + //each ip part must be between 0-255 (dupe of version in for loop) + if( IsDigit(*++uri) && IsDigit(*++uri) && + //100 or less (note !) + !( (*(uri-2) < wxT('2')) || + //240 or less + (*(uri-2) == wxT('2') && + (*(uri-1) < wxT('5') || (*(uri-1) == wxT('5') && *uri <= wxT('5'))) + ) + ) + ) + { + return false; + } + + if(IsDigit(*uri))++uri; + + //compilers should unroll this loop + for(; iIPv4 < 4; ++iIPv4) + { + if (*uri != wxT('.') || !IsDigit(*++uri)) + break; + + //each ip part must be between 0-255 + if( IsDigit(*++uri) && IsDigit(*++uri) && + //100 or less (note !) + !( (*(uri-2) < wxT('2')) || + //240 or less + (*(uri-2) == wxT('2') && + (*(uri-1) < wxT('5') || (*(uri-1) == wxT('5') && *uri <= wxT('5'))) + ) + ) + ) + { + return false; + } + if(IsDigit(*uri))++uri; + } + } + return iIPv4 == 4; +} + +bool wxURI::ParseIPv6address(const wxChar*& uri) +{ + // IPv6address = 6( h16 ":" ) ls32 + // / "::" 5( h16 ":" ) ls32 + // / [ h16 ] "::" 4( h16 ":" ) ls32 + // / [ *1( h16 ":" ) h16 ] "::" 3( h16 ":" ) ls32 + // / [ *2( h16 ":" ) h16 ] "::" 2( h16 ":" ) ls32 + // / [ *3( h16 ":" ) h16 ] "::" h16 ":" ls32 + // / [ *4( h16 ":" ) h16 ] "::" ls32 + // / [ *5( h16 ":" ) h16 ] "::" h16 + // / [ *6( h16 ":" ) h16 ] "::" + + size_t numPrefix = 0, + maxPostfix; + + bool bEndHex = false; + + for( ; numPrefix < 6; ++numPrefix) + { + if(!ParseH16(uri)) + { + --uri; + bEndHex = true; + break; + } + + if(*uri != wxT(':')) + { + break; + } + } + + if(!bEndHex && !ParseH16(uri)) + { + --uri; + + if (numPrefix) + return false; + + if (*uri == wxT(':')) + { + if (*++uri != wxT(':')) + return false; + + maxPostfix = 5; + } + else + maxPostfix = 6; + } + else + { + if (*uri != wxT(':') || *(uri+1) != wxT(':')) + { + if (numPrefix != 6) + return false; + + while (*--uri != wxT(':')) {} + ++uri; + + const wxChar* uristart = uri; + //parse ls32 + // ls32 = ( h16 ":" h16 ) / IPv4address + if (ParseH16(uri) && *uri == wxT(':') && ParseH16(uri)) + return true; + + uri = uristart; + + if (ParseIPv4address(uri)) + return true; + else + return false; + } + else + { + uri += 2; + + if (numPrefix > 3) + maxPostfix = 0; + else + maxPostfix = 4 - numPrefix; + } + } + + bool bAllowAltEnding = maxPostfix == 0; + + for(; maxPostfix != 0; --maxPostfix) + { + if(!ParseH16(uri) || *uri != wxT(':')) + return false; + } + + if(numPrefix <= 4) + { + const wxChar* uristart = uri; + //parse ls32 + // ls32 = ( h16 ":" h16 ) / IPv4address + if (ParseH16(uri) && *uri == wxT(':') && ParseH16(uri)) + return true; + + uri = uristart; + + if (ParseIPv4address(uri)) + return true; + + uri = uristart; + + if (!bAllowAltEnding) + return false; + } + + if(numPrefix <= 5 && ParseH16(uri)) + return true; + + return true; +} + +bool wxURI::ParseIPvFuture(const wxChar*& uri) +{ + // IPvFuture = "v" 1*HEXDIG "." 1*( unreserved / sub-delims / ":" ) + if (*++uri != wxT('v') || !IsHex(*++uri)) + return false; + + while (IsHex(*++uri)) {} + + if (*uri != wxT('.') || !(IsUnreserved(*++uri) || IsSubDelim(*uri) || *uri == wxT(':'))) + return false; + + while(IsUnreserved(*++uri) || IsSubDelim(*uri) || *uri == wxT(':')) {} + + return true; +} + + +// --------------------------------------------------------------------------- +// CharToHex +// +// Converts a character into a numeric hexidecimal value, or 0 if the +// passed in character is not a valid hex character +// --------------------------------------------------------------------------- + +//static +wxChar wxURI::CharToHex(const wxChar& c) +{ + if ((c >= wxT('A')) && (c <= wxT('Z'))) return wxChar(c - wxT('A') + 0x0A); + if ((c >= wxT('a')) && (c <= wxT('z'))) return wxChar(c - wxT('a') + 0x0a); + if ((c >= wxT('0')) && (c <= wxT('9'))) return wxChar(c - wxT('0') + 0x00); + + return 0; +} + +// --------------------------------------------------------------------------- +// IsXXX +// +// Returns true if the passed in character meets the criteria of the method +// --------------------------------------------------------------------------- + +//! unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~" +bool wxURI::IsUnreserved (const wxChar& c) +{ return IsAlpha(c) || IsDigit(c) || + c == wxT('-') || + c == wxT('.') || + c == wxT('_') || + c == wxT('~') //tilde + ; +} + +bool wxURI::IsReserved (const wxChar& c) +{ + return IsGenDelim(c) || IsSubDelim(c); +} + +//! gen-delims = ":" / "/" / "?" / "#" / "[" / "]" / "@" +bool wxURI::IsGenDelim (const wxChar& c) +{ + return c == wxT(':') || + c == wxT('/') || + c == wxT('?') || + c == wxT('#') || + c == wxT('[') || + c == wxT(']') || + c == wxT('@'); +} + +//! sub-delims = "!" / "$" / "&" / "'" / "(" / ")" +//! / "*" / "+" / "," / ";" / "=" +bool wxURI::IsSubDelim (const wxChar& c) +{ + return c == wxT('!') || + c == wxT('$') || + c == wxT('&') || + c == wxT('\'') || + c == wxT('(') || + c == wxT(')') || + c == wxT('*') || + c == wxT('+') || + c == wxT(',') || + c == wxT(';') || + c == wxT('=') + ; +} + +bool wxURI::IsHex(const wxChar& c) +{ return IsDigit(c) || (c >= wxT('a') && c <= wxT('f')) || (c >= wxT('A') && c <= wxT('F')); } + +bool wxURI::IsAlpha(const wxChar& c) +{ return (c >= wxT('a') && c <= wxT('z')) || (c >= wxT('A') && c <= wxT('Z')); } + +bool wxURI::IsDigit(const wxChar& c) +{ return c >= wxT('0') && c <= wxT('9'); } + + +//end of uri.cpp + + + diff --git a/Externals/wxWidgets/src/common/url.cpp b/Externals/wxWidgets/src/common/url.cpp index 4313a3ffec..e7619b1c97 100644 --- a/Externals/wxWidgets/src/common/url.cpp +++ b/Externals/wxWidgets/src/common/url.cpp @@ -1,533 +1,533 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/url.cpp -// Purpose: URL parser -// Author: Guilhem Lavaux -// Modified by: -// Created: 20/07/1997 -// RCS-ID: $Id: url.cpp 49798 2007-11-09 23:17:49Z VZ $ -// Copyright: (c) 1997, 1998 Guilhem Lavaux -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_URL - -#include "wx/url.h" - -#ifndef WX_PRECOMP - #include "wx/list.h" - #include "wx/string.h" - #include "wx/utils.h" - #include "wx/module.h" -#endif - -#include -#include - -IMPLEMENT_CLASS(wxProtoInfo, wxObject) -IMPLEMENT_CLASS(wxURL, wxURI) - -// Protocols list -wxProtoInfo *wxURL::ms_protocols = NULL; - -// Enforce linking of protocol classes: -USE_PROTOCOL(wxFileProto) - -#if wxUSE_PROTOCOL_HTTP -USE_PROTOCOL(wxHTTP) - - wxHTTP *wxURL::ms_proxyDefault = NULL; - bool wxURL::ms_useDefaultProxy = false; -#endif - -#if wxUSE_PROTOCOL_FTP -USE_PROTOCOL(wxFTP) -#endif - -// -------------------------------------------------------------- -// -// wxURL -// -// -------------------------------------------------------------- - -// -------------------------------------------------------------- -// Construction -// -------------------------------------------------------------- - -wxURL::wxURL(const wxString& url) : wxURI(url) -{ - Init(url); - ParseURL(); -} - -wxURL::wxURL(const wxURI& url) : wxURI(url) -{ - Init(url.BuildURI()); - ParseURL(); -} - -void wxURL::Init(const wxString& url) -{ - m_protocol = NULL; - m_error = wxURL_NOERR; - m_url = url; -#if wxUSE_URL_NATIVE - m_nativeImp = CreateNativeImpObject(); -#endif - -#if wxUSE_PROTOCOL_HTTP - if ( ms_useDefaultProxy && !ms_proxyDefault ) - { - SetDefaultProxy( wxGetenv(wxT("HTTP_PROXY")) ); - - if ( !ms_proxyDefault ) - { - // don't try again - ms_useDefaultProxy = false; - } - } - - m_useProxy = ms_proxyDefault != NULL; - m_proxy = ms_proxyDefault; -#endif // wxUSE_PROTOCOL_HTTP - -} - -// -------------------------------------------------------------- -// Assignment -// -------------------------------------------------------------- - -wxURL& wxURL::operator = (const wxURI& url) -{ - wxURI::operator = (url); - Init(url.BuildURI()); - ParseURL(); - return *this; -} -wxURL& wxURL::operator = (const wxString& url) -{ - wxURI::operator = (url); - Init(url); - ParseURL(); - return *this; -} - -// -------------------------------------------------------------- -// ParseURL -// -// Builds the URL and takes care of the old protocol stuff -// -------------------------------------------------------------- - -bool wxURL::ParseURL() -{ - // If the URL was already parsed (m_protocol != NULL), pass this section. - if (!m_protocol) - { - // Clean up - CleanData(); - - // Make sure we have a protocol/scheme - if (!HasScheme()) - { - m_error = wxURL_SNTXERR; - return false; - } - - // Find and create the protocol object - if (!FetchProtocol()) - { - m_error = wxURL_NOPROTO; - return false; - } - - // Do we need a host name ? - if (m_protoinfo->m_needhost) - { - // Make sure we have one, then - if (!HasServer()) - { - m_error = wxURL_SNTXERR; - return false; - } - } - } - -#if wxUSE_PROTOCOL_HTTP - if (m_useProxy) - { - // Third, we rebuild the URL. - m_url = m_scheme + wxT(":"); - if (m_protoinfo->m_needhost) - m_url = m_url + wxT("//") + m_server; - - // We initialize specific variables. - m_protocol = m_proxy; // FIXME: we should clone the protocol - } -#endif // wxUSE_PROTOCOL_HTTP - - m_error = wxURL_NOERR; - return true; -} - -// -------------------------------------------------------------- -// Destruction/Cleanup -// -------------------------------------------------------------- - -void wxURL::CleanData() -{ -#if wxUSE_PROTOCOL_HTTP - if (!m_useProxy) -#endif // wxUSE_PROTOCOL_HTTP - if (m_protocol) - // Need to safely delete the socket (pending events) - m_protocol->Destroy(); -} - -wxURL::~wxURL() -{ - CleanData(); -#if wxUSE_PROTOCOL_HTTP - if (m_proxy && m_proxy != ms_proxyDefault) - delete m_proxy; -#endif // wxUSE_PROTOCOL_HTTP -#if wxUSE_URL_NATIVE - delete m_nativeImp; -#endif -} - -// -------------------------------------------------------------- -// FetchProtocol -// -------------------------------------------------------------- - -bool wxURL::FetchProtocol() -{ - wxProtoInfo *info = ms_protocols; - - while (info) - { - if (m_scheme == info->m_protoname) - { - if (m_port.IsNull()) - m_port = info->m_servname; - m_protoinfo = info; - m_protocol = (wxProtocol *)m_protoinfo->m_cinfo->CreateObject(); - return true; - } - info = info->next; - } - return false; -} - -// -------------------------------------------------------------- -// GetInputStream -// -------------------------------------------------------------- - -wxInputStream *wxURL::GetInputStream() -{ - if (!m_protocol) - { - m_error = wxURL_NOPROTO; - return NULL; - } - - m_error = wxURL_NOERR; - if (HasUserInfo()) - { - size_t dwPasswordPos = m_userinfo.find(':'); - - if (dwPasswordPos == wxString::npos) - m_protocol->SetUser(m_userinfo); - else - { - m_protocol->SetUser(m_userinfo(0, dwPasswordPos)); - m_protocol->SetPassword(m_userinfo(dwPasswordPos+1, m_userinfo.length() + 1)); - } - } - -#if wxUSE_URL_NATIVE - // give the native implementation to return a better stream - // such as the native WinINet functionality under MS-Windows - if (m_nativeImp) - { - wxInputStream *rc; - rc = m_nativeImp->GetInputStream(this); - if (rc != 0) - return rc; - } - // else use the standard behaviour -#endif // wxUSE_URL_NATIVE - -#if wxUSE_SOCKETS - wxIPV4address addr; - - // m_protoinfo is NULL when we use a proxy - if (!m_useProxy && m_protoinfo->m_needhost) - { - if (!addr.Hostname(m_server)) - { - m_error = wxURL_NOHOST; - return NULL; - } - - addr.Service(m_port); - - if (!m_protocol->Connect(addr, true)) // Watcom needs the 2nd arg for some reason - { - m_error = wxURL_CONNERR; - return NULL; - } - } -#endif - - wxString fullPath; - - // When we use a proxy, we have to pass the whole URL to it. - if (m_useProxy) - fullPath += m_url; - - if(m_path.empty()) - fullPath += wxT("/"); - else - fullPath += m_path; - - if (HasQuery()) - fullPath += wxT("?") + m_query; - - if (HasFragment()) - fullPath += wxT("#") + m_fragment; - - wxInputStream *the_i_stream = m_protocol->GetInputStream(fullPath); - - if (!the_i_stream) - { - m_error = wxURL_PROTOERR; - return NULL; - } - - return the_i_stream; -} - -#if wxUSE_PROTOCOL_HTTP -void wxURL::SetDefaultProxy(const wxString& url_proxy) -{ - if ( !url_proxy ) - { - if ( ms_proxyDefault ) - { - ms_proxyDefault->Close(); - delete ms_proxyDefault; - ms_proxyDefault = NULL; - } - } - else - { - wxString tmp_str = url_proxy; - int pos = tmp_str.Find(wxT(':')); - if (pos == wxNOT_FOUND) - return; - - wxString hostname = tmp_str(0, pos), - port = tmp_str(pos+1, tmp_str.length()-pos); - wxIPV4address addr; - - if (!addr.Hostname(hostname)) - return; - if (!addr.Service(port)) - return; - - if (ms_proxyDefault) - // Finally, when all is right, we connect the new proxy. - ms_proxyDefault->Close(); - else - ms_proxyDefault = new wxHTTP(); - ms_proxyDefault->Connect(addr, true); // Watcom needs the 2nd arg for some reason - } -} - -void wxURL::SetProxy(const wxString& url_proxy) -{ - if ( !url_proxy ) - { - if ( m_proxy && m_proxy != ms_proxyDefault ) - { - m_proxy->Close(); - delete m_proxy; - } - - m_useProxy = false; - } - else - { - wxString tmp_str; - wxString hostname, port; - int pos; - wxIPV4address addr; - - tmp_str = url_proxy; - pos = tmp_str.Find(wxT(':')); - // This is an invalid proxy name. - if (pos == wxNOT_FOUND) - return; - - hostname = tmp_str(0, pos); - port = tmp_str(pos+1, tmp_str.length()-pos); - - addr.Hostname(hostname); - addr.Service(port); - - // Finally, create the whole stuff. - if (m_proxy && m_proxy != ms_proxyDefault) - delete m_proxy; - m_proxy = new wxHTTP(); - m_proxy->Connect(addr, true); // Watcom needs the 2nd arg for some reason - - CleanData(); - // Reparse url. - m_useProxy = true; - ParseURL(); - } -} -#endif // wxUSE_PROTOCOL_HTTP - -// ---------------------------------------------------------------------- -// wxURLModule -// -// A module which deletes the default proxy if we created it -// ---------------------------------------------------------------------- - -#if wxUSE_SOCKETS - -class wxURLModule : public wxModule -{ -public: - wxURLModule(); - - virtual bool OnInit(); - virtual void OnExit(); - -private: - DECLARE_DYNAMIC_CLASS(wxURLModule) -}; - -IMPLEMENT_DYNAMIC_CLASS(wxURLModule, wxModule) - -wxURLModule::wxURLModule() -{ - // we must be cleaned up before wxSocketModule as otherwise deleting - // ms_proxyDefault from our OnExit() won't work (and can actually crash) - AddDependency(wxClassInfo::FindClass(_T("wxSocketModule"))); -} - -bool wxURLModule::OnInit() -{ -#if wxUSE_PROTOCOL_HTTP - // env var HTTP_PROXY contains the address of the default proxy to use if - // set, but don't try to create this proxy right now because it will slow - // down the program startup (especially if there is no DNS server - // available, in which case it may take up to 1 minute) - - if ( wxGetenv(_T("HTTP_PROXY")) ) - { - wxURL::ms_useDefaultProxy = true; - } -#endif // wxUSE_PROTOCOL_HTTP - return true; -} - -void wxURLModule::OnExit() -{ -#if wxUSE_PROTOCOL_HTTP - delete wxURL::ms_proxyDefault; - wxURL::ms_proxyDefault = NULL; -#endif // wxUSE_PROTOCOL_HTTP -} - -#endif // wxUSE_SOCKETS - -// --------------------------------------------------------------------------- -// -// wxURL Compatibility -// -// --------------------------------------------------------------------------- - -#if WXWIN_COMPATIBILITY_2_4 - -#include "wx/url.h" - -wxString wxURL::GetProtocolName() const -{ - return m_scheme; -} - -wxString wxURL::GetHostName() const -{ - return m_server; -} - -wxString wxURL::GetPath() const -{ - return m_path; -} - -//Note that this old code really doesn't convert to a URI that well and looks -//more like a dirty hack than anything else... - -wxString wxURL::ConvertToValidURI(const wxString& uri, const wxChar* delims) -{ - wxString out_str; - wxString hexa_code; - size_t i; - - for (i = 0; i < uri.Len(); i++) - { - wxChar c = uri.GetChar(i); - - if (c == wxT(' ')) - { - // GRG, Apr/2000: changed to "%20" instead of '+' - - out_str += wxT("%20"); - } - else - { - // GRG, Apr/2000: modified according to the URI definition (RFC 2396) - // - // - Alphanumeric characters are never escaped - // - Unreserved marks are never escaped - // - Delimiters must be escaped if they appear within a component - // but not if they are used to separate components. Here we have - // no clear way to distinguish between these two cases, so they - // are escaped unless they are passed in the 'delims' parameter - // (allowed delimiters). - - static const wxChar marks[] = wxT("-_.!~*()'"); - - if ( !wxIsalnum(c) && !wxStrchr(marks, c) && !wxStrchr(delims, c) ) - { - hexa_code.Printf(wxT("%%%02X"), c); - out_str += hexa_code; - } - else - { - out_str += c; - } - } - } - - return out_str; -} - -wxString wxURL::ConvertFromURI(const wxString& uri) -{ - return wxURI::Unescape(uri); -} - -#endif //WXWIN_COMPATIBILITY_2_4 - -#endif // wxUSE_URL +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/url.cpp +// Purpose: URL parser +// Author: Guilhem Lavaux +// Modified by: +// Created: 20/07/1997 +// RCS-ID: $Id: url.cpp 49798 2007-11-09 23:17:49Z VZ $ +// Copyright: (c) 1997, 1998 Guilhem Lavaux +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_URL + +#include "wx/url.h" + +#ifndef WX_PRECOMP + #include "wx/list.h" + #include "wx/string.h" + #include "wx/utils.h" + #include "wx/module.h" +#endif + +#include +#include + +IMPLEMENT_CLASS(wxProtoInfo, wxObject) +IMPLEMENT_CLASS(wxURL, wxURI) + +// Protocols list +wxProtoInfo *wxURL::ms_protocols = NULL; + +// Enforce linking of protocol classes: +USE_PROTOCOL(wxFileProto) + +#if wxUSE_PROTOCOL_HTTP +USE_PROTOCOL(wxHTTP) + + wxHTTP *wxURL::ms_proxyDefault = NULL; + bool wxURL::ms_useDefaultProxy = false; +#endif + +#if wxUSE_PROTOCOL_FTP +USE_PROTOCOL(wxFTP) +#endif + +// -------------------------------------------------------------- +// +// wxURL +// +// -------------------------------------------------------------- + +// -------------------------------------------------------------- +// Construction +// -------------------------------------------------------------- + +wxURL::wxURL(const wxString& url) : wxURI(url) +{ + Init(url); + ParseURL(); +} + +wxURL::wxURL(const wxURI& url) : wxURI(url) +{ + Init(url.BuildURI()); + ParseURL(); +} + +void wxURL::Init(const wxString& url) +{ + m_protocol = NULL; + m_error = wxURL_NOERR; + m_url = url; +#if wxUSE_URL_NATIVE + m_nativeImp = CreateNativeImpObject(); +#endif + +#if wxUSE_PROTOCOL_HTTP + if ( ms_useDefaultProxy && !ms_proxyDefault ) + { + SetDefaultProxy( wxGetenv(wxT("HTTP_PROXY")) ); + + if ( !ms_proxyDefault ) + { + // don't try again + ms_useDefaultProxy = false; + } + } + + m_useProxy = ms_proxyDefault != NULL; + m_proxy = ms_proxyDefault; +#endif // wxUSE_PROTOCOL_HTTP + +} + +// -------------------------------------------------------------- +// Assignment +// -------------------------------------------------------------- + +wxURL& wxURL::operator = (const wxURI& url) +{ + wxURI::operator = (url); + Init(url.BuildURI()); + ParseURL(); + return *this; +} +wxURL& wxURL::operator = (const wxString& url) +{ + wxURI::operator = (url); + Init(url); + ParseURL(); + return *this; +} + +// -------------------------------------------------------------- +// ParseURL +// +// Builds the URL and takes care of the old protocol stuff +// -------------------------------------------------------------- + +bool wxURL::ParseURL() +{ + // If the URL was already parsed (m_protocol != NULL), pass this section. + if (!m_protocol) + { + // Clean up + CleanData(); + + // Make sure we have a protocol/scheme + if (!HasScheme()) + { + m_error = wxURL_SNTXERR; + return false; + } + + // Find and create the protocol object + if (!FetchProtocol()) + { + m_error = wxURL_NOPROTO; + return false; + } + + // Do we need a host name ? + if (m_protoinfo->m_needhost) + { + // Make sure we have one, then + if (!HasServer()) + { + m_error = wxURL_SNTXERR; + return false; + } + } + } + +#if wxUSE_PROTOCOL_HTTP + if (m_useProxy) + { + // Third, we rebuild the URL. + m_url = m_scheme + wxT(":"); + if (m_protoinfo->m_needhost) + m_url = m_url + wxT("//") + m_server; + + // We initialize specific variables. + m_protocol = m_proxy; // FIXME: we should clone the protocol + } +#endif // wxUSE_PROTOCOL_HTTP + + m_error = wxURL_NOERR; + return true; +} + +// -------------------------------------------------------------- +// Destruction/Cleanup +// -------------------------------------------------------------- + +void wxURL::CleanData() +{ +#if wxUSE_PROTOCOL_HTTP + if (!m_useProxy) +#endif // wxUSE_PROTOCOL_HTTP + if (m_protocol) + // Need to safely delete the socket (pending events) + m_protocol->Destroy(); +} + +wxURL::~wxURL() +{ + CleanData(); +#if wxUSE_PROTOCOL_HTTP + if (m_proxy && m_proxy != ms_proxyDefault) + delete m_proxy; +#endif // wxUSE_PROTOCOL_HTTP +#if wxUSE_URL_NATIVE + delete m_nativeImp; +#endif +} + +// -------------------------------------------------------------- +// FetchProtocol +// -------------------------------------------------------------- + +bool wxURL::FetchProtocol() +{ + wxProtoInfo *info = ms_protocols; + + while (info) + { + if (m_scheme == info->m_protoname) + { + if (m_port.IsNull()) + m_port = info->m_servname; + m_protoinfo = info; + m_protocol = (wxProtocol *)m_protoinfo->m_cinfo->CreateObject(); + return true; + } + info = info->next; + } + return false; +} + +// -------------------------------------------------------------- +// GetInputStream +// -------------------------------------------------------------- + +wxInputStream *wxURL::GetInputStream() +{ + if (!m_protocol) + { + m_error = wxURL_NOPROTO; + return NULL; + } + + m_error = wxURL_NOERR; + if (HasUserInfo()) + { + size_t dwPasswordPos = m_userinfo.find(':'); + + if (dwPasswordPos == wxString::npos) + m_protocol->SetUser(m_userinfo); + else + { + m_protocol->SetUser(m_userinfo(0, dwPasswordPos)); + m_protocol->SetPassword(m_userinfo(dwPasswordPos+1, m_userinfo.length() + 1)); + } + } + +#if wxUSE_URL_NATIVE + // give the native implementation to return a better stream + // such as the native WinINet functionality under MS-Windows + if (m_nativeImp) + { + wxInputStream *rc; + rc = m_nativeImp->GetInputStream(this); + if (rc != 0) + return rc; + } + // else use the standard behaviour +#endif // wxUSE_URL_NATIVE + +#if wxUSE_SOCKETS + wxIPV4address addr; + + // m_protoinfo is NULL when we use a proxy + if (!m_useProxy && m_protoinfo->m_needhost) + { + if (!addr.Hostname(m_server)) + { + m_error = wxURL_NOHOST; + return NULL; + } + + addr.Service(m_port); + + if (!m_protocol->Connect(addr, true)) // Watcom needs the 2nd arg for some reason + { + m_error = wxURL_CONNERR; + return NULL; + } + } +#endif + + wxString fullPath; + + // When we use a proxy, we have to pass the whole URL to it. + if (m_useProxy) + fullPath += m_url; + + if(m_path.empty()) + fullPath += wxT("/"); + else + fullPath += m_path; + + if (HasQuery()) + fullPath += wxT("?") + m_query; + + if (HasFragment()) + fullPath += wxT("#") + m_fragment; + + wxInputStream *the_i_stream = m_protocol->GetInputStream(fullPath); + + if (!the_i_stream) + { + m_error = wxURL_PROTOERR; + return NULL; + } + + return the_i_stream; +} + +#if wxUSE_PROTOCOL_HTTP +void wxURL::SetDefaultProxy(const wxString& url_proxy) +{ + if ( !url_proxy ) + { + if ( ms_proxyDefault ) + { + ms_proxyDefault->Close(); + delete ms_proxyDefault; + ms_proxyDefault = NULL; + } + } + else + { + wxString tmp_str = url_proxy; + int pos = tmp_str.Find(wxT(':')); + if (pos == wxNOT_FOUND) + return; + + wxString hostname = tmp_str(0, pos), + port = tmp_str(pos+1, tmp_str.length()-pos); + wxIPV4address addr; + + if (!addr.Hostname(hostname)) + return; + if (!addr.Service(port)) + return; + + if (ms_proxyDefault) + // Finally, when all is right, we connect the new proxy. + ms_proxyDefault->Close(); + else + ms_proxyDefault = new wxHTTP(); + ms_proxyDefault->Connect(addr, true); // Watcom needs the 2nd arg for some reason + } +} + +void wxURL::SetProxy(const wxString& url_proxy) +{ + if ( !url_proxy ) + { + if ( m_proxy && m_proxy != ms_proxyDefault ) + { + m_proxy->Close(); + delete m_proxy; + } + + m_useProxy = false; + } + else + { + wxString tmp_str; + wxString hostname, port; + int pos; + wxIPV4address addr; + + tmp_str = url_proxy; + pos = tmp_str.Find(wxT(':')); + // This is an invalid proxy name. + if (pos == wxNOT_FOUND) + return; + + hostname = tmp_str(0, pos); + port = tmp_str(pos+1, tmp_str.length()-pos); + + addr.Hostname(hostname); + addr.Service(port); + + // Finally, create the whole stuff. + if (m_proxy && m_proxy != ms_proxyDefault) + delete m_proxy; + m_proxy = new wxHTTP(); + m_proxy->Connect(addr, true); // Watcom needs the 2nd arg for some reason + + CleanData(); + // Reparse url. + m_useProxy = true; + ParseURL(); + } +} +#endif // wxUSE_PROTOCOL_HTTP + +// ---------------------------------------------------------------------- +// wxURLModule +// +// A module which deletes the default proxy if we created it +// ---------------------------------------------------------------------- + +#if wxUSE_SOCKETS + +class wxURLModule : public wxModule +{ +public: + wxURLModule(); + + virtual bool OnInit(); + virtual void OnExit(); + +private: + DECLARE_DYNAMIC_CLASS(wxURLModule) +}; + +IMPLEMENT_DYNAMIC_CLASS(wxURLModule, wxModule) + +wxURLModule::wxURLModule() +{ + // we must be cleaned up before wxSocketModule as otherwise deleting + // ms_proxyDefault from our OnExit() won't work (and can actually crash) + AddDependency(wxClassInfo::FindClass(_T("wxSocketModule"))); +} + +bool wxURLModule::OnInit() +{ +#if wxUSE_PROTOCOL_HTTP + // env var HTTP_PROXY contains the address of the default proxy to use if + // set, but don't try to create this proxy right now because it will slow + // down the program startup (especially if there is no DNS server + // available, in which case it may take up to 1 minute) + + if ( wxGetenv(_T("HTTP_PROXY")) ) + { + wxURL::ms_useDefaultProxy = true; + } +#endif // wxUSE_PROTOCOL_HTTP + return true; +} + +void wxURLModule::OnExit() +{ +#if wxUSE_PROTOCOL_HTTP + delete wxURL::ms_proxyDefault; + wxURL::ms_proxyDefault = NULL; +#endif // wxUSE_PROTOCOL_HTTP +} + +#endif // wxUSE_SOCKETS + +// --------------------------------------------------------------------------- +// +// wxURL Compatibility +// +// --------------------------------------------------------------------------- + +#if WXWIN_COMPATIBILITY_2_4 + +#include "wx/url.h" + +wxString wxURL::GetProtocolName() const +{ + return m_scheme; +} + +wxString wxURL::GetHostName() const +{ + return m_server; +} + +wxString wxURL::GetPath() const +{ + return m_path; +} + +//Note that this old code really doesn't convert to a URI that well and looks +//more like a dirty hack than anything else... + +wxString wxURL::ConvertToValidURI(const wxString& uri, const wxChar* delims) +{ + wxString out_str; + wxString hexa_code; + size_t i; + + for (i = 0; i < uri.Len(); i++) + { + wxChar c = uri.GetChar(i); + + if (c == wxT(' ')) + { + // GRG, Apr/2000: changed to "%20" instead of '+' + + out_str += wxT("%20"); + } + else + { + // GRG, Apr/2000: modified according to the URI definition (RFC 2396) + // + // - Alphanumeric characters are never escaped + // - Unreserved marks are never escaped + // - Delimiters must be escaped if they appear within a component + // but not if they are used to separate components. Here we have + // no clear way to distinguish between these two cases, so they + // are escaped unless they are passed in the 'delims' parameter + // (allowed delimiters). + + static const wxChar marks[] = wxT("-_.!~*()'"); + + if ( !wxIsalnum(c) && !wxStrchr(marks, c) && !wxStrchr(delims, c) ) + { + hexa_code.Printf(wxT("%%%02X"), c); + out_str += hexa_code; + } + else + { + out_str += c; + } + } + } + + return out_str; +} + +wxString wxURL::ConvertFromURI(const wxString& uri) +{ + return wxURI::Unescape(uri); +} + +#endif //WXWIN_COMPATIBILITY_2_4 + +#endif // wxUSE_URL diff --git a/Externals/wxWidgets/src/common/utilscmn.cpp b/Externals/wxWidgets/src/common/utilscmn.cpp index cbf133426e..254de204ef 100644 --- a/Externals/wxWidgets/src/common/utilscmn.cpp +++ b/Externals/wxWidgets/src/common/utilscmn.cpp @@ -1,1412 +1,1412 @@ -// Name: src/common/utilscmn.cpp -// Purpose: Miscellaneous utility functions and classes -// Author: Julian Smart -// Modified by: -// Created: 29/01/98 -// RCS-ID: $Id: utilscmn.cpp 51328 2008-01-22 10:19:39Z VS $ -// Copyright: (c) 1998 Julian Smart -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#ifndef WX_PRECOMP - #include "wx/app.h" - #include "wx/string.h" - #include "wx/utils.h" - #include "wx/intl.h" - #include "wx/log.h" - - #if wxUSE_GUI - #include "wx/window.h" - #include "wx/frame.h" - #include "wx/menu.h" - #include "wx/msgdlg.h" - #include "wx/textdlg.h" - #include "wx/textctrl.h" // for wxTE_PASSWORD - #if wxUSE_ACCEL - #include "wx/menuitem.h" - #include "wx/accel.h" - #endif // wxUSE_ACCEL - #endif // wxUSE_GUI -#endif // WX_PRECOMP - -#include "wx/apptrait.h" - -#include "wx/process.h" -#include "wx/txtstrm.h" -#include "wx/uri.h" -#include "wx/mimetype.h" -#include "wx/config.h" - -#if defined(__WXWINCE__) && wxUSE_DATETIME -#include "wx/datetime.h" -#endif - -#include -#include -#include -#include - -#if !wxONLY_WATCOM_EARLIER_THAN(1,4) - #if !(defined(_MSC_VER) && (_MSC_VER > 800)) - #include - #endif -#endif - -#if wxUSE_GUI - #include "wx/colordlg.h" - #include "wx/fontdlg.h" - #include "wx/notebook.h" - #include "wx/statusbr.h" -#endif // wxUSE_GUI - -#ifndef __WXWINCE__ -#include -#else -#include "wx/msw/wince/time.h" -#endif - -#ifdef __WXMAC__ -#include "wx/mac/private.h" -#ifndef __DARWIN__ -#include "InternetConfig.h" -#endif -#endif - -#if !defined(__MWERKS__) && !defined(__WXWINCE__) - #include - #include -#endif - -#if defined(__WXMSW__) - #include "wx/msw/private.h" - #include "wx/msw/registry.h" - #include // needed for SHELLEXECUTEINFO -#endif - -#if wxUSE_BASE - -// ---------------------------------------------------------------------------- -// common data -// ---------------------------------------------------------------------------- - -// ============================================================================ -// implementation -// ============================================================================ - -#if WXWIN_COMPATIBILITY_2_4 - -wxChar * -copystring (const wxChar *s) -{ - if (s == NULL) s = wxEmptyString; - size_t len = wxStrlen (s) + 1; - - wxChar *news = new wxChar[len]; - memcpy (news, s, len * sizeof(wxChar)); // Should be the fastest - - return news; -} - -#endif // WXWIN_COMPATIBILITY_2_4 - -// ---------------------------------------------------------------------------- -// String <-> Number conversions (deprecated) -// ---------------------------------------------------------------------------- - -#if WXWIN_COMPATIBILITY_2_4 - -WXDLLIMPEXP_DATA_BASE(const wxChar *) wxFloatToStringStr = wxT("%.2f"); -WXDLLIMPEXP_DATA_BASE(const wxChar *) wxDoubleToStringStr = wxT("%.2f"); - -void -StringToFloat (const wxChar *s, float *number) -{ - if (s && *s && number) - *number = (float) wxStrtod (s, (wxChar **) NULL); -} - -void -StringToDouble (const wxChar *s, double *number) -{ - if (s && *s && number) - *number = wxStrtod (s, (wxChar **) NULL); -} - -wxChar * -FloatToString (float number, const wxChar *fmt) -{ - static wxChar buf[256]; - - wxSprintf (buf, fmt, number); - return buf; -} - -wxChar * -DoubleToString (double number, const wxChar *fmt) -{ - static wxChar buf[256]; - - wxSprintf (buf, fmt, number); - return buf; -} - -void -StringToInt (const wxChar *s, int *number) -{ - if (s && *s && number) - *number = (int) wxStrtol (s, (wxChar **) NULL, 10); -} - -void -StringToLong (const wxChar *s, long *number) -{ - if (s && *s && number) - *number = wxStrtol (s, (wxChar **) NULL, 10); -} - -wxChar * -IntToString (int number) -{ - static wxChar buf[20]; - - wxSprintf (buf, wxT("%d"), number); - return buf; -} - -wxChar * -LongToString (long number) -{ - static wxChar buf[20]; - - wxSprintf (buf, wxT("%ld"), number); - return buf; -} - -#endif // WXWIN_COMPATIBILITY_2_4 - -// Array used in DecToHex conversion routine. -static wxChar hexArray[] = wxT("0123456789ABCDEF"); - -// Convert 2-digit hex number to decimal -int wxHexToDec(const wxString& buf) -{ - int firstDigit, secondDigit; - - if (buf.GetChar(0) >= wxT('A')) - firstDigit = buf.GetChar(0) - wxT('A') + 10; - else - firstDigit = buf.GetChar(0) - wxT('0'); - - if (buf.GetChar(1) >= wxT('A')) - secondDigit = buf.GetChar(1) - wxT('A') + 10; - else - secondDigit = buf.GetChar(1) - wxT('0'); - - return (firstDigit & 0xF) * 16 + (secondDigit & 0xF ); -} - -// Convert decimal integer to 2-character hex string -void wxDecToHex(int dec, wxChar *buf) -{ - int firstDigit = (int)(dec/16.0); - int secondDigit = (int)(dec - (firstDigit*16.0)); - buf[0] = hexArray[firstDigit]; - buf[1] = hexArray[secondDigit]; - buf[2] = 0; -} - -// Convert decimal integer to 2-character hex string -wxString wxDecToHex(int dec) -{ - wxChar buf[3]; - wxDecToHex(dec, buf); - return wxString(buf); -} - -// ---------------------------------------------------------------------------- -// misc functions -// ---------------------------------------------------------------------------- - -// Return the current date/time -wxString wxNow() -{ -#ifdef __WXWINCE__ -#if wxUSE_DATETIME - wxDateTime now = wxDateTime::Now(); - return now.Format(); -#else - return wxEmptyString; -#endif -#else - time_t now = time((time_t *) NULL); - char *date = ctime(&now); - date[24] = '\0'; - return wxString::FromAscii(date); -#endif -} - -void wxUsleep(unsigned long milliseconds) -{ - wxMilliSleep(milliseconds); -} - -const wxChar *wxGetInstallPrefix() -{ - wxString prefix; - - if ( wxGetEnv(wxT("WXPREFIX"), &prefix) ) - return prefix.c_str(); - -#ifdef wxINSTALL_PREFIX - return wxT(wxINSTALL_PREFIX); -#else - return wxEmptyString; -#endif -} - -wxString wxGetDataDir() -{ - wxString dir = wxGetInstallPrefix(); - dir << wxFILE_SEP_PATH << wxT("share") << wxFILE_SEP_PATH << wxT("wx"); - return dir; -} - -bool wxIsPlatformLittleEndian() -{ - // Are we little or big endian? This method is from Harbison & Steele. - union - { - long l; - char c[sizeof(long)]; - } u; - u.l = 1; - - return u.c[0] == 1; -} - - -/* - * Class to make it easier to specify platform-dependent values - */ - -wxArrayInt* wxPlatform::sm_customPlatforms = NULL; - -void wxPlatform::Copy(const wxPlatform& platform) -{ - m_longValue = platform.m_longValue; - m_doubleValue = platform.m_doubleValue; - m_stringValue = platform.m_stringValue; -} - -wxPlatform wxPlatform::If(int platform, long value) -{ - if (Is(platform)) - return wxPlatform(value); - else - return wxPlatform(); -} - -wxPlatform wxPlatform::IfNot(int platform, long value) -{ - if (!Is(platform)) - return wxPlatform(value); - else - return wxPlatform(); -} - -wxPlatform& wxPlatform::ElseIf(int platform, long value) -{ - if (Is(platform)) - m_longValue = value; - return *this; -} - -wxPlatform& wxPlatform::ElseIfNot(int platform, long value) -{ - if (!Is(platform)) - m_longValue = value; - return *this; -} - -wxPlatform wxPlatform::If(int platform, double value) -{ - if (Is(platform)) - return wxPlatform(value); - else - return wxPlatform(); -} - -wxPlatform wxPlatform::IfNot(int platform, double value) -{ - if (!Is(platform)) - return wxPlatform(value); - else - return wxPlatform(); -} - -wxPlatform& wxPlatform::ElseIf(int platform, double value) -{ - if (Is(platform)) - m_doubleValue = value; - return *this; -} - -wxPlatform& wxPlatform::ElseIfNot(int platform, double value) -{ - if (!Is(platform)) - m_doubleValue = value; - return *this; -} - -wxPlatform wxPlatform::If(int platform, const wxString& value) -{ - if (Is(platform)) - return wxPlatform(value); - else - return wxPlatform(); -} - -wxPlatform wxPlatform::IfNot(int platform, const wxString& value) -{ - if (!Is(platform)) - return wxPlatform(value); - else - return wxPlatform(); -} - -wxPlatform& wxPlatform::ElseIf(int platform, const wxString& value) -{ - if (Is(platform)) - m_stringValue = value; - return *this; -} - -wxPlatform& wxPlatform::ElseIfNot(int platform, const wxString& value) -{ - if (!Is(platform)) - m_stringValue = value; - return *this; -} - -wxPlatform& wxPlatform::Else(long value) -{ - m_longValue = value; - return *this; -} - -wxPlatform& wxPlatform::Else(double value) -{ - m_doubleValue = value; - return *this; -} - -wxPlatform& wxPlatform::Else(const wxString& value) -{ - m_stringValue = value; - return *this; -} - -void wxPlatform::AddPlatform(int platform) -{ - if (!sm_customPlatforms) - sm_customPlatforms = new wxArrayInt; - sm_customPlatforms->Add(platform); -} - -void wxPlatform::ClearPlatforms() -{ - delete sm_customPlatforms; - sm_customPlatforms = NULL; -} - -/// Function for testing current platform - -bool wxPlatform::Is(int platform) -{ -#ifdef __WXMSW__ - if (platform == wxOS_WINDOWS) - return true; -#endif -#ifdef __WXWINCE__ - if (platform == wxOS_WINDOWS_CE) - return true; -#endif - -#if 0 - -// FIXME: wxWinPocketPC and wxWinSmartPhone are unknown symbols - -#if defined(__WXWINCE__) && defined(__POCKETPC__) - if (platform == wxWinPocketPC) - return true; -#endif -#if defined(__WXWINCE__) && defined(__SMARTPHONE__) - if (platform == wxWinSmartPhone) - return true; -#endif - -#endif - -#ifdef __WXGTK__ - if (platform == wxPORT_GTK) - return true; -#endif -#ifdef __WXMAC__ - if (platform == wxPORT_MAC) - return true; -#endif -#ifdef __WXX11__ - if (platform == wxPORT_X11) - return true; -#endif -#ifdef __UNIX__ - if (platform == wxOS_UNIX) - return true; -#endif -#ifdef __WXMGL__ - if (platform == wxPORT_MGL) - return true; -#endif -#ifdef __OS2__ - if (platform == wxOS_OS2) - return true; -#endif -#ifdef __WXPM__ - if (platform == wxPORT_PM) - return true; -#endif -#ifdef __WXCOCOA__ - if (platform == wxPORT_MAC) - return true; -#endif - - if (sm_customPlatforms && sm_customPlatforms->Index(platform) != wxNOT_FOUND) - return true; - - return false; -} - -// ---------------------------------------------------------------------------- -// network and user id functions -// ---------------------------------------------------------------------------- - -// Get Full RFC822 style email address -bool wxGetEmailAddress(wxChar *address, int maxSize) -{ - wxString email = wxGetEmailAddress(); - if ( !email ) - return false; - - wxStrncpy(address, email, maxSize - 1); - address[maxSize - 1] = wxT('\0'); - - return true; -} - -wxString wxGetEmailAddress() -{ - wxString email; - - wxString host = wxGetFullHostName(); - if ( !host.empty() ) - { - wxString user = wxGetUserId(); - if ( !user.empty() ) - { - email << user << wxT('@') << host; - } - } - - return email; -} - -wxString wxGetUserId() -{ - static const int maxLoginLen = 256; // FIXME arbitrary number - - wxString buf; - bool ok = wxGetUserId(wxStringBuffer(buf, maxLoginLen), maxLoginLen); - - if ( !ok ) - buf.Empty(); - - return buf; -} - -wxString wxGetUserName() -{ - static const int maxUserNameLen = 1024; // FIXME arbitrary number - - wxString buf; - bool ok = wxGetUserName(wxStringBuffer(buf, maxUserNameLen), maxUserNameLen); - - if ( !ok ) - buf.Empty(); - - return buf; -} - -wxString wxGetHostName() -{ - static const size_t hostnameSize = 257; - - wxString buf; - bool ok = wxGetHostName(wxStringBuffer(buf, hostnameSize), hostnameSize); - - if ( !ok ) - buf.Empty(); - - return buf; -} - -wxString wxGetFullHostName() -{ - static const size_t hostnameSize = 257; - - wxString buf; - bool ok = wxGetFullHostName(wxStringBuffer(buf, hostnameSize), hostnameSize); - - if ( !ok ) - buf.Empty(); - - return buf; -} - -wxString wxGetHomeDir() -{ - wxString home; - wxGetHomeDir(&home); - - return home; -} - -#if 0 - -wxString wxGetCurrentDir() -{ - wxString dir; - size_t len = 1024; - bool ok; - do - { - ok = getcwd(dir.GetWriteBuf(len + 1), len) != NULL; - dir.UngetWriteBuf(); - - if ( !ok ) - { - if ( errno != ERANGE ) - { - wxLogSysError(_T("Failed to get current directory")); - - return wxEmptyString; - } - else - { - // buffer was too small, retry with a larger one - len *= 2; - } - } - //else: ok - } while ( !ok ); - - return dir; -} - -#endif // 0 - -// ---------------------------------------------------------------------------- -// wxExecute -// ---------------------------------------------------------------------------- - -// wxDoExecuteWithCapture() helper: reads an entire stream into one array -// -// returns true if ok, false if error -#if wxUSE_STREAMS -static bool ReadAll(wxInputStream *is, wxArrayString& output) -{ - wxCHECK_MSG( is, false, _T("NULL stream in wxExecute()?") ); - - // the stream could be already at EOF or in wxSTREAM_BROKEN_PIPE state - is->Reset(); - - wxTextInputStream tis(*is); - - for ( ;; ) - { - wxString line = tis.ReadLine(); - - // check for EOF before other errors as it's not really an error - if ( is->Eof() ) - { - // add the last, possibly incomplete, line - if ( !line.empty() ) - output.Add(line); - break; - } - - // any other error is fatal - if ( !*is ) - return false; - - output.Add(line); - } - - return true; -} -#endif // wxUSE_STREAMS - -// this is a private function because it hasn't a clean interface: the first -// array is passed by reference, the second by pointer - instead we have 2 -// public versions of wxExecute() below -static long wxDoExecuteWithCapture(const wxString& command, - wxArrayString& output, - wxArrayString* error, - int flags) -{ - // create a wxProcess which will capture the output - wxProcess *process = new wxProcess; - process->Redirect(); - - long rc = wxExecute(command, wxEXEC_SYNC | flags, process); - -#if wxUSE_STREAMS - if ( rc != -1 ) - { - if ( !ReadAll(process->GetInputStream(), output) ) - rc = -1; - - if ( error ) - { - if ( !ReadAll(process->GetErrorStream(), *error) ) - rc = -1; - } - - } -#else - wxUnusedVar(output); - wxUnusedVar(error); -#endif // wxUSE_STREAMS/!wxUSE_STREAMS - - delete process; - - return rc; -} - -long wxExecute(const wxString& command, wxArrayString& output, int flags) -{ - return wxDoExecuteWithCapture(command, output, NULL, flags); -} - -long wxExecute(const wxString& command, - wxArrayString& output, - wxArrayString& error, - int flags) -{ - return wxDoExecuteWithCapture(command, output, &error, flags); -} - -// ---------------------------------------------------------------------------- -// Launch default browser -// ---------------------------------------------------------------------------- - -#include "wx/private/browserhack28.h" - -static bool wxLaunchDefaultBrowserBaseImpl(const wxString& url, int flags); - -// Use wxLaunchDefaultBrowserBaseImpl by default -static wxLaunchDefaultBrowserImpl_t s_launchBrowserImpl = &wxLaunchDefaultBrowserBaseImpl; - -// Function the GUI library can call to provide a better implementation -WXDLLIMPEXP_BASE void wxSetLaunchDefaultBrowserImpl(wxLaunchDefaultBrowserImpl_t newImpl) -{ - s_launchBrowserImpl = newImpl!=NULL ? newImpl : &wxLaunchDefaultBrowserBaseImpl; -} - -static bool wxLaunchDefaultBrowserBaseImpl(const wxString& url, int flags) -{ - wxUnusedVar(flags); - -#if defined(__WXMSW__) - -#if wxUSE_IPC - if ( flags & wxBROWSER_NEW_WINDOW ) - { - // ShellExecuteEx() opens the URL in an existing window by default so - // we can't use it if we need a new window - wxURI uri(url); - wxRegKey key(wxRegKey::HKCR, uri.GetScheme() + _T("\\shell\\open")); - if ( !key.Exists() ) - { - // try default browser, it must be registered at least for http URLs - key.SetName(wxRegKey::HKCR, _T("http\\shell\\open")); - } - - if ( key.Exists() ) - { - wxRegKey keyDDE(key, wxT("DDEExec")); - if ( keyDDE.Exists() ) - { - const wxString ddeTopic = wxRegKey(keyDDE, wxT("topic")); - - // we only know the syntax of WWW_OpenURL DDE request for IE, - // optimistically assume that all other browsers are compatible - // with it - wxString ddeCmd; - bool ok = ddeTopic == wxT("WWW_OpenURL"); - if ( ok ) - { - ddeCmd = keyDDE.QueryDefaultValue(); - ok = !ddeCmd.empty(); - } - - if ( ok ) - { - // for WWW_OpenURL, the index of the window to open the URL - // in is -1 (meaning "current") by default, replace it with - // 0 which means "new" (see KB article 160957) - ok = ddeCmd.Replace(wxT("-1"), wxT("0"), - false /* only first occurence */) == 1; - } - - if ( ok ) - { - // and also replace the parameters: the topic should - // contain a placeholder for the URL - ok = ddeCmd.Replace(wxT("%1"), url, false) == 1; - } - - if ( ok ) - { - // try to send it the DDE request now but ignore the errors - wxLogNull noLog; - - const wxString ddeServer = wxRegKey(keyDDE, wxT("application")); - if ( wxExecuteDDE(ddeServer, ddeTopic, ddeCmd) ) - return true; - - // this is not necessarily an error: maybe browser is - // simply not running, but no matter, in any case we're - // going to launch it using ShellExecuteEx() below now and - // we shouldn't try to open a new window if we open a new - // browser anyhow - } - } - } - } -#endif // wxUSE_IPC - - WinStruct sei; - sei.lpFile = url.c_str(); - sei.lpVerb = _T("open"); - sei.nShow = SW_SHOWNORMAL; - - ::ShellExecuteEx(&sei); - - const int nResult = (int) sei.hInstApp; - - // Firefox returns file not found for some reason, so make an exception - // for it - if ( nResult > 32 || nResult == SE_ERR_FNF ) - { -#ifdef __WXDEBUG__ - // Log something if SE_ERR_FNF happens - if ( nResult == SE_ERR_FNF ) - wxLogDebug(wxT("SE_ERR_FNF from ShellExecute -- maybe FireFox?")); -#endif // __WXDEBUG__ - return true; - } -#elif defined(__WXMAC__) - OSStatus err; - ICInstance inst; - long int startSel; - long int endSel; - - err = ICStart(&inst, 'STKA'); // put your app creator code here - if (err == noErr) - { -#if !TARGET_CARBON - err = ICFindConfigFile(inst, 0, NULL); -#endif - if (err == noErr) - { - ConstStr255Param hint = 0; - startSel = 0; - endSel = url.length(); - err = ICLaunchURL(inst, hint, url.fn_str(), endSel, &startSel, &endSel); - if (err != noErr) - wxLogDebug(wxT("ICLaunchURL error %d"), (int) err); - } - ICStop(inst); - return true; - } - else - { - wxLogDebug(wxT("ICStart error %d"), (int) err); - return false; - } -#else - // (non-Mac, non-MSW) - -#ifdef __UNIX__ - - // Our best best is to use xdg-open from freedesktop.org cross-desktop - // compatibility suite xdg-utils - // (see http://portland.freedesktop.org/wiki/) -- this is installed on - // most modern distributions and may be tweaked by them to handle - // distribution specifics. Only if that fails, try to find the right - // browser ourselves. - wxString path, xdg_open; - if ( wxGetEnv(_T("PATH"), &path) && - wxFindFileInPath(&xdg_open, path, _T("xdg-open")) ) - { - if ( wxExecute(xdg_open + _T(" ") + url) ) - return true; - } - - wxString desktop = wxTheApp->GetTraits()->GetDesktopEnvironment(); - - // GNOME and KDE desktops have some applications which should be always installed - // together with their main parts, which give us the - if (desktop == wxT("GNOME")) - { - wxArrayString errors; - wxArrayString output; - - // gconf will tell us the path of the application to use as browser - long res = wxExecute( wxT("gconftool-2 --get /desktop/gnome/applications/browser/exec"), - output, errors, wxEXEC_NODISABLE ); - if (res >= 0 && errors.GetCount() == 0) - { - wxString cmd = output[0]; - cmd << _T(' ') << url; - if (wxExecute(cmd)) - return true; - } - } - else if (desktop == wxT("KDE")) - { - // kfmclient directly opens the given URL - if (wxExecute(wxT("kfmclient openURL ") + url)) - return true; - } -#endif - - bool ok = false; - wxString cmd; - -#if wxUSE_MIMETYPE - wxFileType *ft = wxTheMimeTypesManager->GetFileTypeFromExtension(_T("html")); - if ( ft ) - { - wxString mt; - ft->GetMimeType(&mt); - - ok = ft->GetOpenCommand(&cmd, wxFileType::MessageParameters(url)); - delete ft; - } -#endif // wxUSE_MIMETYPE - - if ( !ok || cmd.empty() ) - { - // fallback to checking for the BROWSER environment variable - cmd = wxGetenv(wxT("BROWSER")); - if ( !cmd.empty() ) - cmd << _T(' ') << url; - } - - ok = ( !cmd.empty() && wxExecute(cmd) ); - if (ok) - return ok; - - // no file type for HTML extension - wxLogError(_T("No default application configured for HTML files.")); - -#endif // !wxUSE_MIMETYPE && !__WXMSW__ - return false; -} - -bool wxLaunchDefaultBrowser(const wxString& urlOrig, int flags) -{ - // set the scheme of url to http if it does not have one - // RR: This doesn't work if the url is just a local path - wxString url(urlOrig); - wxURI uri(url); - if ( !uri.HasScheme() ) - { - if (wxFileExists(urlOrig)) - url.Prepend( wxT("file://") ); - else - url.Prepend(wxT("http://")); - } - - if(s_launchBrowserImpl(url, flags)) - return true; - - wxLogSysError(_T("Failed to open URL \"%s\" in default browser."), - url.c_str()); - - return false; -} - -// ---------------------------------------------------------------------------- -// wxApp::Yield() wrappers for backwards compatibility -// ---------------------------------------------------------------------------- - -bool wxYield() -{ - return wxTheApp && wxTheApp->Yield(); -} - -bool wxYieldIfNeeded() -{ - return wxTheApp && wxTheApp->Yield(true); -} - -#endif // wxUSE_BASE - -// ============================================================================ -// GUI-only functions from now on -// ============================================================================ - -#if wxUSE_GUI - -// Id generation -static long wxCurrentId = 100; - -long wxNewId() -{ - // skip the part of IDs space that contains hard-coded values: - if (wxCurrentId == wxID_LOWEST) - wxCurrentId = wxID_HIGHEST + 1; - - return wxCurrentId++; -} - -long -wxGetCurrentId(void) { return wxCurrentId; } - -void -wxRegisterId (long id) -{ - if (id >= wxCurrentId) - wxCurrentId = id + 1; -} - -// ---------------------------------------------------------------------------- -// Menu accelerators related functions -// ---------------------------------------------------------------------------- - -wxChar *wxStripMenuCodes(const wxChar *in, wxChar *out) -{ -#if wxUSE_MENUS - wxString s = wxMenuItem::GetLabelFromText(in); -#else - wxString str(in); - wxString s = wxStripMenuCodes(str); -#endif // wxUSE_MENUS - if ( out ) - { - // go smash their buffer if it's not big enough - I love char * params - memcpy(out, s.c_str(), s.length() * sizeof(wxChar)); - } - else - { - // MYcopystring - for easier search... - out = new wxChar[s.length() + 1]; - wxStrcpy(out, s.c_str()); - } - - return out; -} - -wxString wxStripMenuCodes(const wxString& in, int flags) -{ - wxASSERT_MSG( flags, _T("this is useless to call without any flags") ); - - wxString out; - - size_t len = in.length(); - out.reserve(len); - - for ( size_t n = 0; n < len; n++ ) - { - wxChar ch = in[n]; - if ( (flags & wxStrip_Mnemonics) && ch == _T('&') ) - { - // skip it, it is used to introduce the accel char (or to quote - // itself in which case it should still be skipped): note that it - // can't be the last character of the string - if ( ++n == len ) - { - wxLogDebug(_T("Invalid menu string '%s'"), in.c_str()); - } - else - { - // use the next char instead - ch = in[n]; - } - } - else if ( (flags & wxStrip_Accel) && ch == _T('\t') ) - { - // everything after TAB is accel string, exit the loop - break; - } - - out += ch; - } - - return out; -} - -// ---------------------------------------------------------------------------- -// Window search functions -// ---------------------------------------------------------------------------- - -/* - * If parent is non-NULL, look through children for a label or title - * matching the specified string. If NULL, look through all top-level windows. - * - */ - -wxWindow * -wxFindWindowByLabel (const wxString& title, wxWindow * parent) -{ - return wxWindow::FindWindowByLabel( title, parent ); -} - - -/* - * If parent is non-NULL, look through children for a name - * matching the specified string. If NULL, look through all top-level windows. - * - */ - -wxWindow * -wxFindWindowByName (const wxString& name, wxWindow * parent) -{ - return wxWindow::FindWindowByName( name, parent ); -} - -// Returns menu item id or wxNOT_FOUND if none. -int -wxFindMenuItemId (wxFrame * frame, const wxString& menuString, const wxString& itemString) -{ -#if wxUSE_MENUS - wxMenuBar *menuBar = frame->GetMenuBar (); - if ( menuBar ) - return menuBar->FindMenuItem (menuString, itemString); -#endif // wxUSE_MENUS - - return wxNOT_FOUND; -} - -// Try to find the deepest child that contains 'pt'. -// We go backwards, to try to allow for controls that are spacially -// within other controls, but are still siblings (e.g. buttons within -// static boxes). Static boxes are likely to be created _before_ controls -// that sit inside them. -wxWindow* wxFindWindowAtPoint(wxWindow* win, const wxPoint& pt) -{ - if (!win->IsShown()) - return NULL; - - // Hack for wxNotebook case: at least in wxGTK, all pages - // claim to be shown, so we must only deal with the selected one. -#if wxUSE_NOTEBOOK - if (win->IsKindOf(CLASSINFO(wxNotebook))) - { - wxNotebook* nb = (wxNotebook*) win; - int sel = nb->GetSelection(); - if (sel >= 0) - { - wxWindow* child = nb->GetPage(sel); - wxWindow* foundWin = wxFindWindowAtPoint(child, pt); - if (foundWin) - return foundWin; - } - } -#endif - - wxWindowList::compatibility_iterator node = win->GetChildren().GetLast(); - while (node) - { - wxWindow* child = node->GetData(); - wxWindow* foundWin = wxFindWindowAtPoint(child, pt); - if (foundWin) - return foundWin; - node = node->GetPrevious(); - } - - wxPoint pos = win->GetPosition(); - wxSize sz = win->GetSize(); - if ( !win->IsTopLevel() && win->GetParent() ) - { - pos = win->GetParent()->ClientToScreen(pos); - } - - wxRect rect(pos, sz); - if (rect.Contains(pt)) - return win; - - return NULL; -} - -wxWindow* wxGenericFindWindowAtPoint(const wxPoint& pt) -{ - // Go backwards through the list since windows - // on top are likely to have been appended most - // recently. - wxWindowList::compatibility_iterator node = wxTopLevelWindows.GetLast(); - while (node) - { - wxWindow* win = node->GetData(); - wxWindow* found = wxFindWindowAtPoint(win, pt); - if (found) - return found; - node = node->GetPrevious(); - } - return NULL; -} - -// ---------------------------------------------------------------------------- -// GUI helpers -// ---------------------------------------------------------------------------- - -/* - * N.B. these convenience functions must be separate from msgdlgg.cpp, textdlgg.cpp - * since otherwise the generic code may be pulled in unnecessarily. - */ - -#if wxUSE_MSGDLG - -int wxMessageBox(const wxString& message, const wxString& caption, long style, - wxWindow *parent, int WXUNUSED(x), int WXUNUSED(y) ) -{ - long decorated_style = style; - - if ( ( style & ( wxICON_EXCLAMATION | wxICON_HAND | wxICON_INFORMATION | wxICON_QUESTION ) ) == 0 ) - { - decorated_style |= ( style & wxYES ) ? wxICON_QUESTION : wxICON_INFORMATION ; - } - - wxMessageDialog dialog(parent, message, caption, decorated_style); - - int ans = dialog.ShowModal(); - switch ( ans ) - { - case wxID_OK: - return wxOK; - case wxID_YES: - return wxYES; - case wxID_NO: - return wxNO; - case wxID_CANCEL: - return wxCANCEL; - } - - wxFAIL_MSG( _T("unexpected return code from wxMessageDialog") ); - - return wxCANCEL; -} - -#endif // wxUSE_MSGDLG - -#if wxUSE_TEXTDLG - -wxString wxGetTextFromUser(const wxString& message, const wxString& caption, - const wxString& defaultValue, wxWindow *parent, - wxCoord x, wxCoord y, bool centre ) -{ - wxString str; - long style = wxTextEntryDialogStyle; - - if (centre) - style |= wxCENTRE; - else - style &= ~wxCENTRE; - - wxTextEntryDialog dialog(parent, message, caption, defaultValue, style, wxPoint(x, y)); - - if (dialog.ShowModal() == wxID_OK) - { - str = dialog.GetValue(); - } - - return str; -} - -wxString wxGetPasswordFromUser(const wxString& message, - const wxString& caption, - const wxString& defaultValue, - wxWindow *parent, - wxCoord x, wxCoord y, bool centre ) -{ - wxString str; - long style = wxTextEntryDialogStyle; - - if (centre) - style |= wxCENTRE; - else - style &= ~wxCENTRE; - - wxPasswordEntryDialog dialog(parent, message, caption, defaultValue, - style, wxPoint(x, y)); - if ( dialog.ShowModal() == wxID_OK ) - { - str = dialog.GetValue(); - } - - return str; -} - -#endif // wxUSE_TEXTDLG - -#if wxUSE_COLOURDLG - -wxColour wxGetColourFromUser(wxWindow *parent, const wxColour& colInit, const wxString& caption) -{ - wxColourData data; - data.SetChooseFull(true); - if ( colInit.Ok() ) - { - data.SetColour((wxColour &)colInit); // const_cast - } - - wxColour colRet; - wxColourDialog dialog(parent, &data); - if (!caption.empty()) - dialog.SetTitle(caption); - if ( dialog.ShowModal() == wxID_OK ) - { - colRet = dialog.GetColourData().GetColour(); - } - //else: leave it invalid - - return colRet; -} - -#endif // wxUSE_COLOURDLG - -#if wxUSE_FONTDLG - -wxFont wxGetFontFromUser(wxWindow *parent, const wxFont& fontInit, const wxString& caption) -{ - wxFontData data; - if ( fontInit.Ok() ) - { - data.SetInitialFont(fontInit); - } - - wxFont fontRet; - wxFontDialog dialog(parent, data); - if (!caption.empty()) - dialog.SetTitle(caption); - if ( dialog.ShowModal() == wxID_OK ) - { - fontRet = dialog.GetFontData().GetChosenFont(); - } - //else: leave it invalid - - return fontRet; -} - -#endif // wxUSE_FONTDLG - -// ---------------------------------------------------------------------------- -// wxSafeYield and supporting functions -// ---------------------------------------------------------------------------- - -void wxEnableTopLevelWindows(bool enable) -{ - wxWindowList::compatibility_iterator node; - for ( node = wxTopLevelWindows.GetFirst(); node; node = node->GetNext() ) - node->GetData()->Enable(enable); -} - -wxWindowDisabler::wxWindowDisabler(wxWindow *winToSkip) -{ - // remember the top level windows which were already disabled, so that we - // don't reenable them later - m_winDisabled = NULL; - - wxWindowList::compatibility_iterator node; - for ( node = wxTopLevelWindows.GetFirst(); node; node = node->GetNext() ) - { - wxWindow *winTop = node->GetData(); - if ( winTop == winToSkip ) - continue; - - // we don't need to disable the hidden or already disabled windows - if ( winTop->IsEnabled() && winTop->IsShown() ) - { - winTop->Disable(); - } - else - { - if ( !m_winDisabled ) - { - m_winDisabled = new wxWindowList; - } - - m_winDisabled->Append(winTop); - } - } -} - -wxWindowDisabler::~wxWindowDisabler() -{ - wxWindowList::compatibility_iterator node; - for ( node = wxTopLevelWindows.GetFirst(); node; node = node->GetNext() ) - { - wxWindow *winTop = node->GetData(); - if ( !m_winDisabled || !m_winDisabled->Find(winTop) ) - { - winTop->Enable(); - } - //else: had been already disabled, don't reenable - } - - delete m_winDisabled; -} - -// Yield to other apps/messages and disable user input to all windows except -// the given one -bool wxSafeYield(wxWindow *win, bool onlyIfNeeded) -{ - wxWindowDisabler wd(win); - - bool rc; - if (onlyIfNeeded) - rc = wxYieldIfNeeded(); - else - rc = wxYield(); - - return rc; -} - -// Don't synthesize KeyUp events holding down a key and producing KeyDown -// events with autorepeat. On by default and always on in wxMSW. wxGTK version -// in utilsgtk.cpp. -#ifndef __WXGTK__ -bool wxSetDetectableAutoRepeat( bool WXUNUSED(flag) ) -{ - return true; // detectable auto-repeat is the only mode MSW supports -} -#endif // !wxGTK - -#endif // wxUSE_GUI +// Name: src/common/utilscmn.cpp +// Purpose: Miscellaneous utility functions and classes +// Author: Julian Smart +// Modified by: +// Created: 29/01/98 +// RCS-ID: $Id: utilscmn.cpp 51328 2008-01-22 10:19:39Z VS $ +// Copyright: (c) 1998 Julian Smart +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#ifndef WX_PRECOMP + #include "wx/app.h" + #include "wx/string.h" + #include "wx/utils.h" + #include "wx/intl.h" + #include "wx/log.h" + + #if wxUSE_GUI + #include "wx/window.h" + #include "wx/frame.h" + #include "wx/menu.h" + #include "wx/msgdlg.h" + #include "wx/textdlg.h" + #include "wx/textctrl.h" // for wxTE_PASSWORD + #if wxUSE_ACCEL + #include "wx/menuitem.h" + #include "wx/accel.h" + #endif // wxUSE_ACCEL + #endif // wxUSE_GUI +#endif // WX_PRECOMP + +#include "wx/apptrait.h" + +#include "wx/process.h" +#include "wx/txtstrm.h" +#include "wx/uri.h" +#include "wx/mimetype.h" +#include "wx/config.h" + +#if defined(__WXWINCE__) && wxUSE_DATETIME +#include "wx/datetime.h" +#endif + +#include +#include +#include +#include + +#if !wxONLY_WATCOM_EARLIER_THAN(1,4) + #if !(defined(_MSC_VER) && (_MSC_VER > 800)) + #include + #endif +#endif + +#if wxUSE_GUI + #include "wx/colordlg.h" + #include "wx/fontdlg.h" + #include "wx/notebook.h" + #include "wx/statusbr.h" +#endif // wxUSE_GUI + +#ifndef __WXWINCE__ +#include +#else +#include "wx/msw/wince/time.h" +#endif + +#ifdef __WXMAC__ +#include "wx/mac/private.h" +#ifndef __DARWIN__ +#include "InternetConfig.h" +#endif +#endif + +#if !defined(__MWERKS__) && !defined(__WXWINCE__) + #include + #include +#endif + +#if defined(__WXMSW__) + #include "wx/msw/private.h" + #include "wx/msw/registry.h" + #include // needed for SHELLEXECUTEINFO +#endif + +#if wxUSE_BASE + +// ---------------------------------------------------------------------------- +// common data +// ---------------------------------------------------------------------------- + +// ============================================================================ +// implementation +// ============================================================================ + +#if WXWIN_COMPATIBILITY_2_4 + +wxChar * +copystring (const wxChar *s) +{ + if (s == NULL) s = wxEmptyString; + size_t len = wxStrlen (s) + 1; + + wxChar *news = new wxChar[len]; + memcpy (news, s, len * sizeof(wxChar)); // Should be the fastest + + return news; +} + +#endif // WXWIN_COMPATIBILITY_2_4 + +// ---------------------------------------------------------------------------- +// String <-> Number conversions (deprecated) +// ---------------------------------------------------------------------------- + +#if WXWIN_COMPATIBILITY_2_4 + +WXDLLIMPEXP_DATA_BASE(const wxChar *) wxFloatToStringStr = wxT("%.2f"); +WXDLLIMPEXP_DATA_BASE(const wxChar *) wxDoubleToStringStr = wxT("%.2f"); + +void +StringToFloat (const wxChar *s, float *number) +{ + if (s && *s && number) + *number = (float) wxStrtod (s, (wxChar **) NULL); +} + +void +StringToDouble (const wxChar *s, double *number) +{ + if (s && *s && number) + *number = wxStrtod (s, (wxChar **) NULL); +} + +wxChar * +FloatToString (float number, const wxChar *fmt) +{ + static wxChar buf[256]; + + wxSprintf (buf, fmt, number); + return buf; +} + +wxChar * +DoubleToString (double number, const wxChar *fmt) +{ + static wxChar buf[256]; + + wxSprintf (buf, fmt, number); + return buf; +} + +void +StringToInt (const wxChar *s, int *number) +{ + if (s && *s && number) + *number = (int) wxStrtol (s, (wxChar **) NULL, 10); +} + +void +StringToLong (const wxChar *s, long *number) +{ + if (s && *s && number) + *number = wxStrtol (s, (wxChar **) NULL, 10); +} + +wxChar * +IntToString (int number) +{ + static wxChar buf[20]; + + wxSprintf (buf, wxT("%d"), number); + return buf; +} + +wxChar * +LongToString (long number) +{ + static wxChar buf[20]; + + wxSprintf (buf, wxT("%ld"), number); + return buf; +} + +#endif // WXWIN_COMPATIBILITY_2_4 + +// Array used in DecToHex conversion routine. +static wxChar hexArray[] = wxT("0123456789ABCDEF"); + +// Convert 2-digit hex number to decimal +int wxHexToDec(const wxString& buf) +{ + int firstDigit, secondDigit; + + if (buf.GetChar(0) >= wxT('A')) + firstDigit = buf.GetChar(0) - wxT('A') + 10; + else + firstDigit = buf.GetChar(0) - wxT('0'); + + if (buf.GetChar(1) >= wxT('A')) + secondDigit = buf.GetChar(1) - wxT('A') + 10; + else + secondDigit = buf.GetChar(1) - wxT('0'); + + return (firstDigit & 0xF) * 16 + (secondDigit & 0xF ); +} + +// Convert decimal integer to 2-character hex string +void wxDecToHex(int dec, wxChar *buf) +{ + int firstDigit = (int)(dec/16.0); + int secondDigit = (int)(dec - (firstDigit*16.0)); + buf[0] = hexArray[firstDigit]; + buf[1] = hexArray[secondDigit]; + buf[2] = 0; +} + +// Convert decimal integer to 2-character hex string +wxString wxDecToHex(int dec) +{ + wxChar buf[3]; + wxDecToHex(dec, buf); + return wxString(buf); +} + +// ---------------------------------------------------------------------------- +// misc functions +// ---------------------------------------------------------------------------- + +// Return the current date/time +wxString wxNow() +{ +#ifdef __WXWINCE__ +#if wxUSE_DATETIME + wxDateTime now = wxDateTime::Now(); + return now.Format(); +#else + return wxEmptyString; +#endif +#else + time_t now = time((time_t *) NULL); + char *date = ctime(&now); + date[24] = '\0'; + return wxString::FromAscii(date); +#endif +} + +void wxUsleep(unsigned long milliseconds) +{ + wxMilliSleep(milliseconds); +} + +const wxChar *wxGetInstallPrefix() +{ + wxString prefix; + + if ( wxGetEnv(wxT("WXPREFIX"), &prefix) ) + return prefix.c_str(); + +#ifdef wxINSTALL_PREFIX + return wxT(wxINSTALL_PREFIX); +#else + return wxEmptyString; +#endif +} + +wxString wxGetDataDir() +{ + wxString dir = wxGetInstallPrefix(); + dir << wxFILE_SEP_PATH << wxT("share") << wxFILE_SEP_PATH << wxT("wx"); + return dir; +} + +bool wxIsPlatformLittleEndian() +{ + // Are we little or big endian? This method is from Harbison & Steele. + union + { + long l; + char c[sizeof(long)]; + } u; + u.l = 1; + + return u.c[0] == 1; +} + + +/* + * Class to make it easier to specify platform-dependent values + */ + +wxArrayInt* wxPlatform::sm_customPlatforms = NULL; + +void wxPlatform::Copy(const wxPlatform& platform) +{ + m_longValue = platform.m_longValue; + m_doubleValue = platform.m_doubleValue; + m_stringValue = platform.m_stringValue; +} + +wxPlatform wxPlatform::If(int platform, long value) +{ + if (Is(platform)) + return wxPlatform(value); + else + return wxPlatform(); +} + +wxPlatform wxPlatform::IfNot(int platform, long value) +{ + if (!Is(platform)) + return wxPlatform(value); + else + return wxPlatform(); +} + +wxPlatform& wxPlatform::ElseIf(int platform, long value) +{ + if (Is(platform)) + m_longValue = value; + return *this; +} + +wxPlatform& wxPlatform::ElseIfNot(int platform, long value) +{ + if (!Is(platform)) + m_longValue = value; + return *this; +} + +wxPlatform wxPlatform::If(int platform, double value) +{ + if (Is(platform)) + return wxPlatform(value); + else + return wxPlatform(); +} + +wxPlatform wxPlatform::IfNot(int platform, double value) +{ + if (!Is(platform)) + return wxPlatform(value); + else + return wxPlatform(); +} + +wxPlatform& wxPlatform::ElseIf(int platform, double value) +{ + if (Is(platform)) + m_doubleValue = value; + return *this; +} + +wxPlatform& wxPlatform::ElseIfNot(int platform, double value) +{ + if (!Is(platform)) + m_doubleValue = value; + return *this; +} + +wxPlatform wxPlatform::If(int platform, const wxString& value) +{ + if (Is(platform)) + return wxPlatform(value); + else + return wxPlatform(); +} + +wxPlatform wxPlatform::IfNot(int platform, const wxString& value) +{ + if (!Is(platform)) + return wxPlatform(value); + else + return wxPlatform(); +} + +wxPlatform& wxPlatform::ElseIf(int platform, const wxString& value) +{ + if (Is(platform)) + m_stringValue = value; + return *this; +} + +wxPlatform& wxPlatform::ElseIfNot(int platform, const wxString& value) +{ + if (!Is(platform)) + m_stringValue = value; + return *this; +} + +wxPlatform& wxPlatform::Else(long value) +{ + m_longValue = value; + return *this; +} + +wxPlatform& wxPlatform::Else(double value) +{ + m_doubleValue = value; + return *this; +} + +wxPlatform& wxPlatform::Else(const wxString& value) +{ + m_stringValue = value; + return *this; +} + +void wxPlatform::AddPlatform(int platform) +{ + if (!sm_customPlatforms) + sm_customPlatforms = new wxArrayInt; + sm_customPlatforms->Add(platform); +} + +void wxPlatform::ClearPlatforms() +{ + delete sm_customPlatforms; + sm_customPlatforms = NULL; +} + +/// Function for testing current platform + +bool wxPlatform::Is(int platform) +{ +#ifdef __WXMSW__ + if (platform == wxOS_WINDOWS) + return true; +#endif +#ifdef __WXWINCE__ + if (platform == wxOS_WINDOWS_CE) + return true; +#endif + +#if 0 + +// FIXME: wxWinPocketPC and wxWinSmartPhone are unknown symbols + +#if defined(__WXWINCE__) && defined(__POCKETPC__) + if (platform == wxWinPocketPC) + return true; +#endif +#if defined(__WXWINCE__) && defined(__SMARTPHONE__) + if (platform == wxWinSmartPhone) + return true; +#endif + +#endif + +#ifdef __WXGTK__ + if (platform == wxPORT_GTK) + return true; +#endif +#ifdef __WXMAC__ + if (platform == wxPORT_MAC) + return true; +#endif +#ifdef __WXX11__ + if (platform == wxPORT_X11) + return true; +#endif +#ifdef __UNIX__ + if (platform == wxOS_UNIX) + return true; +#endif +#ifdef __WXMGL__ + if (platform == wxPORT_MGL) + return true; +#endif +#ifdef __OS2__ + if (platform == wxOS_OS2) + return true; +#endif +#ifdef __WXPM__ + if (platform == wxPORT_PM) + return true; +#endif +#ifdef __WXCOCOA__ + if (platform == wxPORT_MAC) + return true; +#endif + + if (sm_customPlatforms && sm_customPlatforms->Index(platform) != wxNOT_FOUND) + return true; + + return false; +} + +// ---------------------------------------------------------------------------- +// network and user id functions +// ---------------------------------------------------------------------------- + +// Get Full RFC822 style email address +bool wxGetEmailAddress(wxChar *address, int maxSize) +{ + wxString email = wxGetEmailAddress(); + if ( !email ) + return false; + + wxStrncpy(address, email, maxSize - 1); + address[maxSize - 1] = wxT('\0'); + + return true; +} + +wxString wxGetEmailAddress() +{ + wxString email; + + wxString host = wxGetFullHostName(); + if ( !host.empty() ) + { + wxString user = wxGetUserId(); + if ( !user.empty() ) + { + email << user << wxT('@') << host; + } + } + + return email; +} + +wxString wxGetUserId() +{ + static const int maxLoginLen = 256; // FIXME arbitrary number + + wxString buf; + bool ok = wxGetUserId(wxStringBuffer(buf, maxLoginLen), maxLoginLen); + + if ( !ok ) + buf.Empty(); + + return buf; +} + +wxString wxGetUserName() +{ + static const int maxUserNameLen = 1024; // FIXME arbitrary number + + wxString buf; + bool ok = wxGetUserName(wxStringBuffer(buf, maxUserNameLen), maxUserNameLen); + + if ( !ok ) + buf.Empty(); + + return buf; +} + +wxString wxGetHostName() +{ + static const size_t hostnameSize = 257; + + wxString buf; + bool ok = wxGetHostName(wxStringBuffer(buf, hostnameSize), hostnameSize); + + if ( !ok ) + buf.Empty(); + + return buf; +} + +wxString wxGetFullHostName() +{ + static const size_t hostnameSize = 257; + + wxString buf; + bool ok = wxGetFullHostName(wxStringBuffer(buf, hostnameSize), hostnameSize); + + if ( !ok ) + buf.Empty(); + + return buf; +} + +wxString wxGetHomeDir() +{ + wxString home; + wxGetHomeDir(&home); + + return home; +} + +#if 0 + +wxString wxGetCurrentDir() +{ + wxString dir; + size_t len = 1024; + bool ok; + do + { + ok = getcwd(dir.GetWriteBuf(len + 1), len) != NULL; + dir.UngetWriteBuf(); + + if ( !ok ) + { + if ( errno != ERANGE ) + { + wxLogSysError(_T("Failed to get current directory")); + + return wxEmptyString; + } + else + { + // buffer was too small, retry with a larger one + len *= 2; + } + } + //else: ok + } while ( !ok ); + + return dir; +} + +#endif // 0 + +// ---------------------------------------------------------------------------- +// wxExecute +// ---------------------------------------------------------------------------- + +// wxDoExecuteWithCapture() helper: reads an entire stream into one array +// +// returns true if ok, false if error +#if wxUSE_STREAMS +static bool ReadAll(wxInputStream *is, wxArrayString& output) +{ + wxCHECK_MSG( is, false, _T("NULL stream in wxExecute()?") ); + + // the stream could be already at EOF or in wxSTREAM_BROKEN_PIPE state + is->Reset(); + + wxTextInputStream tis(*is); + + for ( ;; ) + { + wxString line = tis.ReadLine(); + + // check for EOF before other errors as it's not really an error + if ( is->Eof() ) + { + // add the last, possibly incomplete, line + if ( !line.empty() ) + output.Add(line); + break; + } + + // any other error is fatal + if ( !*is ) + return false; + + output.Add(line); + } + + return true; +} +#endif // wxUSE_STREAMS + +// this is a private function because it hasn't a clean interface: the first +// array is passed by reference, the second by pointer - instead we have 2 +// public versions of wxExecute() below +static long wxDoExecuteWithCapture(const wxString& command, + wxArrayString& output, + wxArrayString* error, + int flags) +{ + // create a wxProcess which will capture the output + wxProcess *process = new wxProcess; + process->Redirect(); + + long rc = wxExecute(command, wxEXEC_SYNC | flags, process); + +#if wxUSE_STREAMS + if ( rc != -1 ) + { + if ( !ReadAll(process->GetInputStream(), output) ) + rc = -1; + + if ( error ) + { + if ( !ReadAll(process->GetErrorStream(), *error) ) + rc = -1; + } + + } +#else + wxUnusedVar(output); + wxUnusedVar(error); +#endif // wxUSE_STREAMS/!wxUSE_STREAMS + + delete process; + + return rc; +} + +long wxExecute(const wxString& command, wxArrayString& output, int flags) +{ + return wxDoExecuteWithCapture(command, output, NULL, flags); +} + +long wxExecute(const wxString& command, + wxArrayString& output, + wxArrayString& error, + int flags) +{ + return wxDoExecuteWithCapture(command, output, &error, flags); +} + +// ---------------------------------------------------------------------------- +// Launch default browser +// ---------------------------------------------------------------------------- + +#include "wx/private/browserhack28.h" + +static bool wxLaunchDefaultBrowserBaseImpl(const wxString& url, int flags); + +// Use wxLaunchDefaultBrowserBaseImpl by default +static wxLaunchDefaultBrowserImpl_t s_launchBrowserImpl = &wxLaunchDefaultBrowserBaseImpl; + +// Function the GUI library can call to provide a better implementation +WXDLLIMPEXP_BASE void wxSetLaunchDefaultBrowserImpl(wxLaunchDefaultBrowserImpl_t newImpl) +{ + s_launchBrowserImpl = newImpl!=NULL ? newImpl : &wxLaunchDefaultBrowserBaseImpl; +} + +static bool wxLaunchDefaultBrowserBaseImpl(const wxString& url, int flags) +{ + wxUnusedVar(flags); + +#if defined(__WXMSW__) + +#if wxUSE_IPC + if ( flags & wxBROWSER_NEW_WINDOW ) + { + // ShellExecuteEx() opens the URL in an existing window by default so + // we can't use it if we need a new window + wxURI uri(url); + wxRegKey key(wxRegKey::HKCR, uri.GetScheme() + _T("\\shell\\open")); + if ( !key.Exists() ) + { + // try default browser, it must be registered at least for http URLs + key.SetName(wxRegKey::HKCR, _T("http\\shell\\open")); + } + + if ( key.Exists() ) + { + wxRegKey keyDDE(key, wxT("DDEExec")); + if ( keyDDE.Exists() ) + { + const wxString ddeTopic = wxRegKey(keyDDE, wxT("topic")); + + // we only know the syntax of WWW_OpenURL DDE request for IE, + // optimistically assume that all other browsers are compatible + // with it + wxString ddeCmd; + bool ok = ddeTopic == wxT("WWW_OpenURL"); + if ( ok ) + { + ddeCmd = keyDDE.QueryDefaultValue(); + ok = !ddeCmd.empty(); + } + + if ( ok ) + { + // for WWW_OpenURL, the index of the window to open the URL + // in is -1 (meaning "current") by default, replace it with + // 0 which means "new" (see KB article 160957) + ok = ddeCmd.Replace(wxT("-1"), wxT("0"), + false /* only first occurence */) == 1; + } + + if ( ok ) + { + // and also replace the parameters: the topic should + // contain a placeholder for the URL + ok = ddeCmd.Replace(wxT("%1"), url, false) == 1; + } + + if ( ok ) + { + // try to send it the DDE request now but ignore the errors + wxLogNull noLog; + + const wxString ddeServer = wxRegKey(keyDDE, wxT("application")); + if ( wxExecuteDDE(ddeServer, ddeTopic, ddeCmd) ) + return true; + + // this is not necessarily an error: maybe browser is + // simply not running, but no matter, in any case we're + // going to launch it using ShellExecuteEx() below now and + // we shouldn't try to open a new window if we open a new + // browser anyhow + } + } + } + } +#endif // wxUSE_IPC + + WinStruct sei; + sei.lpFile = url.c_str(); + sei.lpVerb = _T("open"); + sei.nShow = SW_SHOWNORMAL; + + ::ShellExecuteEx(&sei); + + const int nResult = (int) sei.hInstApp; + + // Firefox returns file not found for some reason, so make an exception + // for it + if ( nResult > 32 || nResult == SE_ERR_FNF ) + { +#ifdef __WXDEBUG__ + // Log something if SE_ERR_FNF happens + if ( nResult == SE_ERR_FNF ) + wxLogDebug(wxT("SE_ERR_FNF from ShellExecute -- maybe FireFox?")); +#endif // __WXDEBUG__ + return true; + } +#elif defined(__WXMAC__) + OSStatus err; + ICInstance inst; + long int startSel; + long int endSel; + + err = ICStart(&inst, 'STKA'); // put your app creator code here + if (err == noErr) + { +#if !TARGET_CARBON + err = ICFindConfigFile(inst, 0, NULL); +#endif + if (err == noErr) + { + ConstStr255Param hint = 0; + startSel = 0; + endSel = url.length(); + err = ICLaunchURL(inst, hint, url.fn_str(), endSel, &startSel, &endSel); + if (err != noErr) + wxLogDebug(wxT("ICLaunchURL error %d"), (int) err); + } + ICStop(inst); + return true; + } + else + { + wxLogDebug(wxT("ICStart error %d"), (int) err); + return false; + } +#else + // (non-Mac, non-MSW) + +#ifdef __UNIX__ + + // Our best best is to use xdg-open from freedesktop.org cross-desktop + // compatibility suite xdg-utils + // (see http://portland.freedesktop.org/wiki/) -- this is installed on + // most modern distributions and may be tweaked by them to handle + // distribution specifics. Only if that fails, try to find the right + // browser ourselves. + wxString path, xdg_open; + if ( wxGetEnv(_T("PATH"), &path) && + wxFindFileInPath(&xdg_open, path, _T("xdg-open")) ) + { + if ( wxExecute(xdg_open + _T(" ") + url) ) + return true; + } + + wxString desktop = wxTheApp->GetTraits()->GetDesktopEnvironment(); + + // GNOME and KDE desktops have some applications which should be always installed + // together with their main parts, which give us the + if (desktop == wxT("GNOME")) + { + wxArrayString errors; + wxArrayString output; + + // gconf will tell us the path of the application to use as browser + long res = wxExecute( wxT("gconftool-2 --get /desktop/gnome/applications/browser/exec"), + output, errors, wxEXEC_NODISABLE ); + if (res >= 0 && errors.GetCount() == 0) + { + wxString cmd = output[0]; + cmd << _T(' ') << url; + if (wxExecute(cmd)) + return true; + } + } + else if (desktop == wxT("KDE")) + { + // kfmclient directly opens the given URL + if (wxExecute(wxT("kfmclient openURL ") + url)) + return true; + } +#endif + + bool ok = false; + wxString cmd; + +#if wxUSE_MIMETYPE + wxFileType *ft = wxTheMimeTypesManager->GetFileTypeFromExtension(_T("html")); + if ( ft ) + { + wxString mt; + ft->GetMimeType(&mt); + + ok = ft->GetOpenCommand(&cmd, wxFileType::MessageParameters(url)); + delete ft; + } +#endif // wxUSE_MIMETYPE + + if ( !ok || cmd.empty() ) + { + // fallback to checking for the BROWSER environment variable + cmd = wxGetenv(wxT("BROWSER")); + if ( !cmd.empty() ) + cmd << _T(' ') << url; + } + + ok = ( !cmd.empty() && wxExecute(cmd) ); + if (ok) + return ok; + + // no file type for HTML extension + wxLogError(_T("No default application configured for HTML files.")); + +#endif // !wxUSE_MIMETYPE && !__WXMSW__ + return false; +} + +bool wxLaunchDefaultBrowser(const wxString& urlOrig, int flags) +{ + // set the scheme of url to http if it does not have one + // RR: This doesn't work if the url is just a local path + wxString url(urlOrig); + wxURI uri(url); + if ( !uri.HasScheme() ) + { + if (wxFileExists(urlOrig)) + url.Prepend( wxT("file://") ); + else + url.Prepend(wxT("http://")); + } + + if(s_launchBrowserImpl(url, flags)) + return true; + + wxLogSysError(_T("Failed to open URL \"%s\" in default browser."), + url.c_str()); + + return false; +} + +// ---------------------------------------------------------------------------- +// wxApp::Yield() wrappers for backwards compatibility +// ---------------------------------------------------------------------------- + +bool wxYield() +{ + return wxTheApp && wxTheApp->Yield(); +} + +bool wxYieldIfNeeded() +{ + return wxTheApp && wxTheApp->Yield(true); +} + +#endif // wxUSE_BASE + +// ============================================================================ +// GUI-only functions from now on +// ============================================================================ + +#if wxUSE_GUI + +// Id generation +static long wxCurrentId = 100; + +long wxNewId() +{ + // skip the part of IDs space that contains hard-coded values: + if (wxCurrentId == wxID_LOWEST) + wxCurrentId = wxID_HIGHEST + 1; + + return wxCurrentId++; +} + +long +wxGetCurrentId(void) { return wxCurrentId; } + +void +wxRegisterId (long id) +{ + if (id >= wxCurrentId) + wxCurrentId = id + 1; +} + +// ---------------------------------------------------------------------------- +// Menu accelerators related functions +// ---------------------------------------------------------------------------- + +wxChar *wxStripMenuCodes(const wxChar *in, wxChar *out) +{ +#if wxUSE_MENUS + wxString s = wxMenuItem::GetLabelFromText(in); +#else + wxString str(in); + wxString s = wxStripMenuCodes(str); +#endif // wxUSE_MENUS + if ( out ) + { + // go smash their buffer if it's not big enough - I love char * params + memcpy(out, s.c_str(), s.length() * sizeof(wxChar)); + } + else + { + // MYcopystring - for easier search... + out = new wxChar[s.length() + 1]; + wxStrcpy(out, s.c_str()); + } + + return out; +} + +wxString wxStripMenuCodes(const wxString& in, int flags) +{ + wxASSERT_MSG( flags, _T("this is useless to call without any flags") ); + + wxString out; + + size_t len = in.length(); + out.reserve(len); + + for ( size_t n = 0; n < len; n++ ) + { + wxChar ch = in[n]; + if ( (flags & wxStrip_Mnemonics) && ch == _T('&') ) + { + // skip it, it is used to introduce the accel char (or to quote + // itself in which case it should still be skipped): note that it + // can't be the last character of the string + if ( ++n == len ) + { + wxLogDebug(_T("Invalid menu string '%s'"), in.c_str()); + } + else + { + // use the next char instead + ch = in[n]; + } + } + else if ( (flags & wxStrip_Accel) && ch == _T('\t') ) + { + // everything after TAB is accel string, exit the loop + break; + } + + out += ch; + } + + return out; +} + +// ---------------------------------------------------------------------------- +// Window search functions +// ---------------------------------------------------------------------------- + +/* + * If parent is non-NULL, look through children for a label or title + * matching the specified string. If NULL, look through all top-level windows. + * + */ + +wxWindow * +wxFindWindowByLabel (const wxString& title, wxWindow * parent) +{ + return wxWindow::FindWindowByLabel( title, parent ); +} + + +/* + * If parent is non-NULL, look through children for a name + * matching the specified string. If NULL, look through all top-level windows. + * + */ + +wxWindow * +wxFindWindowByName (const wxString& name, wxWindow * parent) +{ + return wxWindow::FindWindowByName( name, parent ); +} + +// Returns menu item id or wxNOT_FOUND if none. +int +wxFindMenuItemId (wxFrame * frame, const wxString& menuString, const wxString& itemString) +{ +#if wxUSE_MENUS + wxMenuBar *menuBar = frame->GetMenuBar (); + if ( menuBar ) + return menuBar->FindMenuItem (menuString, itemString); +#endif // wxUSE_MENUS + + return wxNOT_FOUND; +} + +// Try to find the deepest child that contains 'pt'. +// We go backwards, to try to allow for controls that are spacially +// within other controls, but are still siblings (e.g. buttons within +// static boxes). Static boxes are likely to be created _before_ controls +// that sit inside them. +wxWindow* wxFindWindowAtPoint(wxWindow* win, const wxPoint& pt) +{ + if (!win->IsShown()) + return NULL; + + // Hack for wxNotebook case: at least in wxGTK, all pages + // claim to be shown, so we must only deal with the selected one. +#if wxUSE_NOTEBOOK + if (win->IsKindOf(CLASSINFO(wxNotebook))) + { + wxNotebook* nb = (wxNotebook*) win; + int sel = nb->GetSelection(); + if (sel >= 0) + { + wxWindow* child = nb->GetPage(sel); + wxWindow* foundWin = wxFindWindowAtPoint(child, pt); + if (foundWin) + return foundWin; + } + } +#endif + + wxWindowList::compatibility_iterator node = win->GetChildren().GetLast(); + while (node) + { + wxWindow* child = node->GetData(); + wxWindow* foundWin = wxFindWindowAtPoint(child, pt); + if (foundWin) + return foundWin; + node = node->GetPrevious(); + } + + wxPoint pos = win->GetPosition(); + wxSize sz = win->GetSize(); + if ( !win->IsTopLevel() && win->GetParent() ) + { + pos = win->GetParent()->ClientToScreen(pos); + } + + wxRect rect(pos, sz); + if (rect.Contains(pt)) + return win; + + return NULL; +} + +wxWindow* wxGenericFindWindowAtPoint(const wxPoint& pt) +{ + // Go backwards through the list since windows + // on top are likely to have been appended most + // recently. + wxWindowList::compatibility_iterator node = wxTopLevelWindows.GetLast(); + while (node) + { + wxWindow* win = node->GetData(); + wxWindow* found = wxFindWindowAtPoint(win, pt); + if (found) + return found; + node = node->GetPrevious(); + } + return NULL; +} + +// ---------------------------------------------------------------------------- +// GUI helpers +// ---------------------------------------------------------------------------- + +/* + * N.B. these convenience functions must be separate from msgdlgg.cpp, textdlgg.cpp + * since otherwise the generic code may be pulled in unnecessarily. + */ + +#if wxUSE_MSGDLG + +int wxMessageBox(const wxString& message, const wxString& caption, long style, + wxWindow *parent, int WXUNUSED(x), int WXUNUSED(y) ) +{ + long decorated_style = style; + + if ( ( style & ( wxICON_EXCLAMATION | wxICON_HAND | wxICON_INFORMATION | wxICON_QUESTION ) ) == 0 ) + { + decorated_style |= ( style & wxYES ) ? wxICON_QUESTION : wxICON_INFORMATION ; + } + + wxMessageDialog dialog(parent, message, caption, decorated_style); + + int ans = dialog.ShowModal(); + switch ( ans ) + { + case wxID_OK: + return wxOK; + case wxID_YES: + return wxYES; + case wxID_NO: + return wxNO; + case wxID_CANCEL: + return wxCANCEL; + } + + wxFAIL_MSG( _T("unexpected return code from wxMessageDialog") ); + + return wxCANCEL; +} + +#endif // wxUSE_MSGDLG + +#if wxUSE_TEXTDLG + +wxString wxGetTextFromUser(const wxString& message, const wxString& caption, + const wxString& defaultValue, wxWindow *parent, + wxCoord x, wxCoord y, bool centre ) +{ + wxString str; + long style = wxTextEntryDialogStyle; + + if (centre) + style |= wxCENTRE; + else + style &= ~wxCENTRE; + + wxTextEntryDialog dialog(parent, message, caption, defaultValue, style, wxPoint(x, y)); + + if (dialog.ShowModal() == wxID_OK) + { + str = dialog.GetValue(); + } + + return str; +} + +wxString wxGetPasswordFromUser(const wxString& message, + const wxString& caption, + const wxString& defaultValue, + wxWindow *parent, + wxCoord x, wxCoord y, bool centre ) +{ + wxString str; + long style = wxTextEntryDialogStyle; + + if (centre) + style |= wxCENTRE; + else + style &= ~wxCENTRE; + + wxPasswordEntryDialog dialog(parent, message, caption, defaultValue, + style, wxPoint(x, y)); + if ( dialog.ShowModal() == wxID_OK ) + { + str = dialog.GetValue(); + } + + return str; +} + +#endif // wxUSE_TEXTDLG + +#if wxUSE_COLOURDLG + +wxColour wxGetColourFromUser(wxWindow *parent, const wxColour& colInit, const wxString& caption) +{ + wxColourData data; + data.SetChooseFull(true); + if ( colInit.Ok() ) + { + data.SetColour((wxColour &)colInit); // const_cast + } + + wxColour colRet; + wxColourDialog dialog(parent, &data); + if (!caption.empty()) + dialog.SetTitle(caption); + if ( dialog.ShowModal() == wxID_OK ) + { + colRet = dialog.GetColourData().GetColour(); + } + //else: leave it invalid + + return colRet; +} + +#endif // wxUSE_COLOURDLG + +#if wxUSE_FONTDLG + +wxFont wxGetFontFromUser(wxWindow *parent, const wxFont& fontInit, const wxString& caption) +{ + wxFontData data; + if ( fontInit.Ok() ) + { + data.SetInitialFont(fontInit); + } + + wxFont fontRet; + wxFontDialog dialog(parent, data); + if (!caption.empty()) + dialog.SetTitle(caption); + if ( dialog.ShowModal() == wxID_OK ) + { + fontRet = dialog.GetFontData().GetChosenFont(); + } + //else: leave it invalid + + return fontRet; +} + +#endif // wxUSE_FONTDLG + +// ---------------------------------------------------------------------------- +// wxSafeYield and supporting functions +// ---------------------------------------------------------------------------- + +void wxEnableTopLevelWindows(bool enable) +{ + wxWindowList::compatibility_iterator node; + for ( node = wxTopLevelWindows.GetFirst(); node; node = node->GetNext() ) + node->GetData()->Enable(enable); +} + +wxWindowDisabler::wxWindowDisabler(wxWindow *winToSkip) +{ + // remember the top level windows which were already disabled, so that we + // don't reenable them later + m_winDisabled = NULL; + + wxWindowList::compatibility_iterator node; + for ( node = wxTopLevelWindows.GetFirst(); node; node = node->GetNext() ) + { + wxWindow *winTop = node->GetData(); + if ( winTop == winToSkip ) + continue; + + // we don't need to disable the hidden or already disabled windows + if ( winTop->IsEnabled() && winTop->IsShown() ) + { + winTop->Disable(); + } + else + { + if ( !m_winDisabled ) + { + m_winDisabled = new wxWindowList; + } + + m_winDisabled->Append(winTop); + } + } +} + +wxWindowDisabler::~wxWindowDisabler() +{ + wxWindowList::compatibility_iterator node; + for ( node = wxTopLevelWindows.GetFirst(); node; node = node->GetNext() ) + { + wxWindow *winTop = node->GetData(); + if ( !m_winDisabled || !m_winDisabled->Find(winTop) ) + { + winTop->Enable(); + } + //else: had been already disabled, don't reenable + } + + delete m_winDisabled; +} + +// Yield to other apps/messages and disable user input to all windows except +// the given one +bool wxSafeYield(wxWindow *win, bool onlyIfNeeded) +{ + wxWindowDisabler wd(win); + + bool rc; + if (onlyIfNeeded) + rc = wxYieldIfNeeded(); + else + rc = wxYield(); + + return rc; +} + +// Don't synthesize KeyUp events holding down a key and producing KeyDown +// events with autorepeat. On by default and always on in wxMSW. wxGTK version +// in utilsgtk.cpp. +#ifndef __WXGTK__ +bool wxSetDetectableAutoRepeat( bool WXUNUSED(flag) ) +{ + return true; // detectable auto-repeat is the only mode MSW supports +} +#endif // !wxGTK + +#endif // wxUSE_GUI diff --git a/Externals/wxWidgets/src/common/valgen.cpp b/Externals/wxWidgets/src/common/valgen.cpp index 9b206483a7..b010537ce2 100644 --- a/Externals/wxWidgets/src/common/valgen.cpp +++ b/Externals/wxWidgets/src/common/valgen.cpp @@ -1,591 +1,591 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/valgen.cpp -// Purpose: wxGenericValidator class -// Author: Kevin Smith -// Modified by: -// Created: Jan 22 1999 -// RCS-ID: $Id: valgen.cpp 39463 2006-05-29 21:26:35Z ABX $ -// Copyright: (c) 1999 Kevin Smith -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_VALIDATORS - -#ifndef WX_PRECOMP - #include "wx/dynarray.h" - #include "wx/utils.h" - #include "wx/intl.h" - #include "wx/choice.h" - #include "wx/combobox.h" - #include "wx/radiobox.h" - #include "wx/radiobut.h" - #include "wx/checkbox.h" - #include "wx/scrolbar.h" - #include "wx/gauge.h" - #include "wx/stattext.h" - #include "wx/textctrl.h" - #include "wx/button.h" - #include "wx/listbox.h" - #include "wx/slider.h" - #include "wx/checklst.h" -#endif - -#include "wx/spinctrl.h" - -#if wxUSE_SPINBTN - #include "wx/spinbutt.h" -#endif -#if wxUSE_TOGGLEBTN - #include "wx/tglbtn.h" -#endif - -#include "wx/valgen.h" - -IMPLEMENT_CLASS(wxGenericValidator, wxValidator) - -wxGenericValidator::wxGenericValidator(bool *val) -{ - Initialize(); - m_pBool = val; -} - -wxGenericValidator::wxGenericValidator(int *val) -{ - Initialize(); - m_pInt = val; -} - -wxGenericValidator::wxGenericValidator(wxString *val) -{ - Initialize(); - m_pString = val; -} - -wxGenericValidator::wxGenericValidator(wxArrayInt *val) -{ - Initialize(); - m_pArrayInt = val; -} - -wxGenericValidator::wxGenericValidator(const wxGenericValidator& val) - : wxValidator() -{ - Copy(val); -} - -bool wxGenericValidator::Copy(const wxGenericValidator& val) -{ - wxValidator::Copy(val); - - m_pBool = val.m_pBool; - m_pInt = val.m_pInt; - m_pString = val.m_pString; - m_pArrayInt = val.m_pArrayInt; - - return true; -} - -// Called to transfer data to the window -bool wxGenericValidator::TransferToWindow(void) -{ - if ( !m_validatorWindow ) - return false; - - // bool controls -#if wxUSE_CHECKBOX - if (m_validatorWindow->IsKindOf(CLASSINFO(wxCheckBox)) ) - { - wxCheckBox* pControl = (wxCheckBox*) m_validatorWindow; - if (m_pBool) - { - pControl->SetValue(*m_pBool); - return true; - } - } else -#endif -#if wxUSE_RADIOBTN - if (m_validatorWindow->IsKindOf(CLASSINFO(wxRadioButton)) ) - { - wxRadioButton* pControl = (wxRadioButton*) m_validatorWindow; - if (m_pBool) - { - pControl->SetValue(*m_pBool) ; - return true; - } - } else -#endif -#if wxUSE_TOGGLEBTN - if (m_validatorWindow->IsKindOf(CLASSINFO(wxToggleButton)) ) - { - wxToggleButton * pControl = (wxToggleButton *) m_validatorWindow; - if (m_pBool) - { - pControl->SetValue(*m_pBool); - return true; - } - } else -#endif - - // int controls -#if wxUSE_GAUGE - if (m_validatorWindow->IsKindOf(CLASSINFO(wxGauge)) ) - { - wxGauge* pControl = (wxGauge*) m_validatorWindow; - if (m_pInt) - { - pControl->SetValue(*m_pInt); - return true; - } - } else -#endif -#if wxUSE_RADIOBOX - if (m_validatorWindow->IsKindOf(CLASSINFO(wxRadioBox)) ) - { - wxRadioBox* pControl = (wxRadioBox*) m_validatorWindow; - if (m_pInt) - { - pControl->SetSelection(*m_pInt) ; - return true; - } - } else -#endif -#if wxUSE_SCROLLBAR - if (m_validatorWindow->IsKindOf(CLASSINFO(wxScrollBar)) ) - { - wxScrollBar* pControl = (wxScrollBar*) m_validatorWindow; - if (m_pInt) - { - pControl->SetThumbPosition(*m_pInt) ; - return true; - } - } else -#endif -#if wxUSE_SPINCTRL && !defined(__WXMOTIF__) - if (m_validatorWindow->IsKindOf(CLASSINFO(wxSpinCtrl)) ) - { - wxSpinCtrl* pControl = (wxSpinCtrl*) m_validatorWindow; - if (m_pInt) - { - pControl->SetValue(*m_pInt); - return true; - } - } else -#endif -#if wxUSE_SPINBTN - if (m_validatorWindow->IsKindOf(CLASSINFO(wxSpinButton)) ) - { - wxSpinButton* pControl = (wxSpinButton*) m_validatorWindow; - if (m_pInt) - { - pControl->SetValue(*m_pInt) ; - return true; - } - } else -#endif -#if wxUSE_SLIDER - if (m_validatorWindow->IsKindOf(CLASSINFO(wxSlider)) ) - { - wxSlider* pControl = (wxSlider*) m_validatorWindow; - if (m_pInt) - { - pControl->SetValue(*m_pInt) ; - return true; - } - } else -#endif - - // string controls -#if wxUSE_BUTTON - if (m_validatorWindow->IsKindOf(CLASSINFO(wxButton)) ) - { - wxButton* pControl = (wxButton*) m_validatorWindow; - if (m_pString) - { - pControl->SetLabel(*m_pString) ; - return true; - } - } else -#endif -#if wxUSE_COMBOBOX - if (m_validatorWindow->IsKindOf(CLASSINFO(wxComboBox)) ) - { - wxComboBox* pControl = (wxComboBox*) m_validatorWindow; - if (m_pInt) - { - pControl->SetSelection(*m_pInt) ; - return true; - } - else if (m_pString) - { - if (pControl->FindString(* m_pString) != wxNOT_FOUND) - { - pControl->SetStringSelection(* m_pString); - } - if ((m_validatorWindow->GetWindowStyle() & wxCB_READONLY) == 0) - { - pControl->SetValue(* m_pString); - } - return true; - } - } else -#endif -#if wxUSE_CHOICE - if (m_validatorWindow->IsKindOf(CLASSINFO(wxChoice)) ) - { - wxChoice* pControl = (wxChoice*) m_validatorWindow; - if (m_pInt) - { - pControl->SetSelection(*m_pInt) ; - return true; - } - else if (m_pString) - { - if (pControl->FindString(* m_pString) != wxNOT_FOUND) - { - pControl->SetStringSelection(* m_pString); - } - return true; - } - } else -#endif -#if wxUSE_STATTEXT - if (m_validatorWindow->IsKindOf(CLASSINFO(wxStaticText)) ) - { - wxStaticText* pControl = (wxStaticText*) m_validatorWindow; - if (m_pString) - { - pControl->SetLabel(*m_pString) ; - return true; - } - } else -#endif -#if wxUSE_TEXTCTRL - if (m_validatorWindow->IsKindOf(CLASSINFO(wxTextCtrl)) ) - { - wxTextCtrl* pControl = (wxTextCtrl*) m_validatorWindow; - if (m_pString) - { - pControl->SetValue(*m_pString) ; - return true; - } - else if (m_pInt) - { - wxString str; - str.Printf(wxT("%d"), *m_pInt); - pControl->SetValue(str); - return true; - } - } else -#endif - - // array controls -#if wxUSE_CHECKLISTBOX - // NOTE: wxCheckListBox is a wxListBox, so wxCheckListBox MUST come first: - if (m_validatorWindow->IsKindOf(CLASSINFO(wxCheckListBox)) ) - { - wxCheckListBox* pControl = (wxCheckListBox*) m_validatorWindow; - if (m_pArrayInt) - { - // clear all selections - size_t i, - count = pControl->GetCount(); - for ( i = 0 ; i < count; i++ ) - pControl->Check(i, false); - - // select each item in our array - count = m_pArrayInt->GetCount(); - for ( i = 0 ; i < count; i++ ) - pControl->Check(m_pArrayInt->Item(i)); - - return true; - } - else - return false; - } else -#endif -#if wxUSE_LISTBOX - if (m_validatorWindow->IsKindOf(CLASSINFO(wxListBox)) ) - { - wxListBox* pControl = (wxListBox*) m_validatorWindow; - if (m_pArrayInt) - { - // clear all selections - size_t i, - count = pControl->GetCount(); - for ( i = 0 ; i < count; i++ ) - pControl->Deselect(i); - - // select each item in our array - count = m_pArrayInt->GetCount(); - for ( i = 0 ; i < count; i++ ) - pControl->SetSelection(m_pArrayInt->Item(i)); - - return true; - } - } else -#endif - ; // to match the last 'else' above - - // unrecognized control, or bad pointer - return false; -} - -// Called to transfer data from the window -bool wxGenericValidator::TransferFromWindow(void) -{ - if ( !m_validatorWindow ) - return false; - - // BOOL CONTROLS ************************************** -#if wxUSE_CHECKBOX - if (m_validatorWindow->IsKindOf(CLASSINFO(wxCheckBox)) ) - { - wxCheckBox* pControl = (wxCheckBox*) m_validatorWindow; - if (m_pBool) - { - *m_pBool = pControl->GetValue() ; - return true; - } - } else -#endif -#if wxUSE_RADIOBTN - if (m_validatorWindow->IsKindOf(CLASSINFO(wxRadioButton)) ) - { - wxRadioButton* pControl = (wxRadioButton*) m_validatorWindow; - if (m_pBool) - { - *m_pBool = pControl->GetValue() ; - return true; - } - } else -#endif -#if wxUSE_TOGGLEBTN - if (m_validatorWindow->IsKindOf(CLASSINFO(wxToggleButton)) ) - { - wxToggleButton *pControl = (wxToggleButton *) m_validatorWindow; - if (m_pBool) - { - *m_pBool = pControl->GetValue() ; - return true; - } - } else -#endif - - // INT CONTROLS *************************************** -#if wxUSE_GAUGE - if (m_validatorWindow->IsKindOf(CLASSINFO(wxGauge)) ) - { - wxGauge* pControl = (wxGauge*) m_validatorWindow; - if (m_pInt) - { - *m_pInt = pControl->GetValue() ; - return true; - } - } else -#endif -#if wxUSE_RADIOBOX - if (m_validatorWindow->IsKindOf(CLASSINFO(wxRadioBox)) ) - { - wxRadioBox* pControl = (wxRadioBox*) m_validatorWindow; - if (m_pInt) - { - *m_pInt = pControl->GetSelection() ; - return true; - } - } else -#endif -#if wxUSE_SCROLLBAR - if (m_validatorWindow->IsKindOf(CLASSINFO(wxScrollBar)) ) - { - wxScrollBar* pControl = (wxScrollBar*) m_validatorWindow; - if (m_pInt) - { - *m_pInt = pControl->GetThumbPosition() ; - return true; - } - } else -#endif -#if wxUSE_SPINCTRL && !defined(__WXMOTIF__) - if (m_validatorWindow->IsKindOf(CLASSINFO(wxSpinCtrl)) ) - { - wxSpinCtrl* pControl = (wxSpinCtrl*) m_validatorWindow; - if (m_pInt) - { - *m_pInt=pControl->GetValue(); - return true; - } - } else -#endif -#if wxUSE_SPINBTN - if (m_validatorWindow->IsKindOf(CLASSINFO(wxSpinButton)) ) - { - wxSpinButton* pControl = (wxSpinButton*) m_validatorWindow; - if (m_pInt) - { - *m_pInt = pControl->GetValue() ; - return true; - } - } else -#endif -#if wxUSE_SLIDER - if (m_validatorWindow->IsKindOf(CLASSINFO(wxSlider)) ) - { - wxSlider* pControl = (wxSlider*) m_validatorWindow; - if (m_pInt) - { - *m_pInt = pControl->GetValue() ; - return true; - } - } else -#endif - - // STRING CONTROLS ************************************ -#if wxUSE_BUTTON - if (m_validatorWindow->IsKindOf(CLASSINFO(wxButton)) ) - { - wxButton* pControl = (wxButton*) m_validatorWindow; - if (m_pString) - { - *m_pString = pControl->GetLabel() ; - return true; - } - } else -#endif -#if wxUSE_COMBOBOX - if (m_validatorWindow->IsKindOf(CLASSINFO(wxComboBox)) ) - { - wxComboBox* pControl = (wxComboBox*) m_validatorWindow; - if (m_pInt) - { - *m_pInt = pControl->GetSelection() ; - return true; - } - else if (m_pString) - { - if (m_validatorWindow->GetWindowStyle() & wxCB_READONLY) - *m_pString = pControl->GetStringSelection(); - else - *m_pString = pControl->GetValue(); - return true; - } - } else -#endif -#if wxUSE_CHOICE - if (m_validatorWindow->IsKindOf(CLASSINFO(wxChoice)) ) - { - wxChoice* pControl = (wxChoice*) m_validatorWindow; - if (m_pInt) - { - *m_pInt = pControl->GetSelection() ; - return true; - } - else if (m_pString) - { - *m_pString = pControl->GetStringSelection(); - return true; - } - } else -#endif -#if wxUSE_STATTEXT - if (m_validatorWindow->IsKindOf(CLASSINFO(wxStaticText)) ) - { - wxStaticText* pControl = (wxStaticText*) m_validatorWindow; - if (m_pString) - { - *m_pString = pControl->GetLabel() ; - return true; - } - } else -#endif -#if wxUSE_TEXTCTRL - if (m_validatorWindow->IsKindOf(CLASSINFO(wxTextCtrl)) ) - { - wxTextCtrl* pControl = (wxTextCtrl*) m_validatorWindow; - if (m_pString) - { - *m_pString = pControl->GetValue() ; - return true; - } - else if (m_pInt) - { - *m_pInt = wxAtoi(pControl->GetValue()); - return true; - } - } else -#endif - - // ARRAY CONTROLS ************************************* -#if wxUSE_CHECKLISTBOX - // NOTE: wxCheckListBox isa wxListBox, so wxCheckListBox MUST come first: - if (m_validatorWindow->IsKindOf(CLASSINFO(wxCheckListBox)) ) - { - wxCheckListBox* pControl = (wxCheckListBox*) m_validatorWindow; - if (m_pArrayInt) - { - // clear our array - m_pArrayInt->Clear(); - - // add each selected item to our array - size_t i, - count = pControl->GetCount(); - for ( i = 0; i < count; i++ ) - { - if (pControl->IsChecked(i)) - m_pArrayInt->Add(i); - } - - return true; - } - else - return false; - } else -#endif -#if wxUSE_LISTBOX - if (m_validatorWindow->IsKindOf(CLASSINFO(wxListBox)) ) - { - wxListBox* pControl = (wxListBox*) m_validatorWindow; - if (m_pArrayInt) - { - // clear our array - m_pArrayInt->Clear(); - - // add each selected item to our array - size_t i, - count = pControl->GetCount(); - for ( i = 0; i < count; i++ ) - { - if (pControl->IsSelected(i)) - m_pArrayInt->Add(i); - } - - return true; - } - } else -#endif - - // unrecognized control, or bad pointer - return false; - - return false; -} - -/* - Called by constructors to initialize ALL data members -*/ -void wxGenericValidator::Initialize() -{ - m_pBool = 0; - m_pInt = 0; - m_pString = 0; - m_pArrayInt = 0; -} - -#endif - // wxUSE_VALIDATORS +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/valgen.cpp +// Purpose: wxGenericValidator class +// Author: Kevin Smith +// Modified by: +// Created: Jan 22 1999 +// RCS-ID: $Id: valgen.cpp 39463 2006-05-29 21:26:35Z ABX $ +// Copyright: (c) 1999 Kevin Smith +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_VALIDATORS + +#ifndef WX_PRECOMP + #include "wx/dynarray.h" + #include "wx/utils.h" + #include "wx/intl.h" + #include "wx/choice.h" + #include "wx/combobox.h" + #include "wx/radiobox.h" + #include "wx/radiobut.h" + #include "wx/checkbox.h" + #include "wx/scrolbar.h" + #include "wx/gauge.h" + #include "wx/stattext.h" + #include "wx/textctrl.h" + #include "wx/button.h" + #include "wx/listbox.h" + #include "wx/slider.h" + #include "wx/checklst.h" +#endif + +#include "wx/spinctrl.h" + +#if wxUSE_SPINBTN + #include "wx/spinbutt.h" +#endif +#if wxUSE_TOGGLEBTN + #include "wx/tglbtn.h" +#endif + +#include "wx/valgen.h" + +IMPLEMENT_CLASS(wxGenericValidator, wxValidator) + +wxGenericValidator::wxGenericValidator(bool *val) +{ + Initialize(); + m_pBool = val; +} + +wxGenericValidator::wxGenericValidator(int *val) +{ + Initialize(); + m_pInt = val; +} + +wxGenericValidator::wxGenericValidator(wxString *val) +{ + Initialize(); + m_pString = val; +} + +wxGenericValidator::wxGenericValidator(wxArrayInt *val) +{ + Initialize(); + m_pArrayInt = val; +} + +wxGenericValidator::wxGenericValidator(const wxGenericValidator& val) + : wxValidator() +{ + Copy(val); +} + +bool wxGenericValidator::Copy(const wxGenericValidator& val) +{ + wxValidator::Copy(val); + + m_pBool = val.m_pBool; + m_pInt = val.m_pInt; + m_pString = val.m_pString; + m_pArrayInt = val.m_pArrayInt; + + return true; +} + +// Called to transfer data to the window +bool wxGenericValidator::TransferToWindow(void) +{ + if ( !m_validatorWindow ) + return false; + + // bool controls +#if wxUSE_CHECKBOX + if (m_validatorWindow->IsKindOf(CLASSINFO(wxCheckBox)) ) + { + wxCheckBox* pControl = (wxCheckBox*) m_validatorWindow; + if (m_pBool) + { + pControl->SetValue(*m_pBool); + return true; + } + } else +#endif +#if wxUSE_RADIOBTN + if (m_validatorWindow->IsKindOf(CLASSINFO(wxRadioButton)) ) + { + wxRadioButton* pControl = (wxRadioButton*) m_validatorWindow; + if (m_pBool) + { + pControl->SetValue(*m_pBool) ; + return true; + } + } else +#endif +#if wxUSE_TOGGLEBTN + if (m_validatorWindow->IsKindOf(CLASSINFO(wxToggleButton)) ) + { + wxToggleButton * pControl = (wxToggleButton *) m_validatorWindow; + if (m_pBool) + { + pControl->SetValue(*m_pBool); + return true; + } + } else +#endif + + // int controls +#if wxUSE_GAUGE + if (m_validatorWindow->IsKindOf(CLASSINFO(wxGauge)) ) + { + wxGauge* pControl = (wxGauge*) m_validatorWindow; + if (m_pInt) + { + pControl->SetValue(*m_pInt); + return true; + } + } else +#endif +#if wxUSE_RADIOBOX + if (m_validatorWindow->IsKindOf(CLASSINFO(wxRadioBox)) ) + { + wxRadioBox* pControl = (wxRadioBox*) m_validatorWindow; + if (m_pInt) + { + pControl->SetSelection(*m_pInt) ; + return true; + } + } else +#endif +#if wxUSE_SCROLLBAR + if (m_validatorWindow->IsKindOf(CLASSINFO(wxScrollBar)) ) + { + wxScrollBar* pControl = (wxScrollBar*) m_validatorWindow; + if (m_pInt) + { + pControl->SetThumbPosition(*m_pInt) ; + return true; + } + } else +#endif +#if wxUSE_SPINCTRL && !defined(__WXMOTIF__) + if (m_validatorWindow->IsKindOf(CLASSINFO(wxSpinCtrl)) ) + { + wxSpinCtrl* pControl = (wxSpinCtrl*) m_validatorWindow; + if (m_pInt) + { + pControl->SetValue(*m_pInt); + return true; + } + } else +#endif +#if wxUSE_SPINBTN + if (m_validatorWindow->IsKindOf(CLASSINFO(wxSpinButton)) ) + { + wxSpinButton* pControl = (wxSpinButton*) m_validatorWindow; + if (m_pInt) + { + pControl->SetValue(*m_pInt) ; + return true; + } + } else +#endif +#if wxUSE_SLIDER + if (m_validatorWindow->IsKindOf(CLASSINFO(wxSlider)) ) + { + wxSlider* pControl = (wxSlider*) m_validatorWindow; + if (m_pInt) + { + pControl->SetValue(*m_pInt) ; + return true; + } + } else +#endif + + // string controls +#if wxUSE_BUTTON + if (m_validatorWindow->IsKindOf(CLASSINFO(wxButton)) ) + { + wxButton* pControl = (wxButton*) m_validatorWindow; + if (m_pString) + { + pControl->SetLabel(*m_pString) ; + return true; + } + } else +#endif +#if wxUSE_COMBOBOX + if (m_validatorWindow->IsKindOf(CLASSINFO(wxComboBox)) ) + { + wxComboBox* pControl = (wxComboBox*) m_validatorWindow; + if (m_pInt) + { + pControl->SetSelection(*m_pInt) ; + return true; + } + else if (m_pString) + { + if (pControl->FindString(* m_pString) != wxNOT_FOUND) + { + pControl->SetStringSelection(* m_pString); + } + if ((m_validatorWindow->GetWindowStyle() & wxCB_READONLY) == 0) + { + pControl->SetValue(* m_pString); + } + return true; + } + } else +#endif +#if wxUSE_CHOICE + if (m_validatorWindow->IsKindOf(CLASSINFO(wxChoice)) ) + { + wxChoice* pControl = (wxChoice*) m_validatorWindow; + if (m_pInt) + { + pControl->SetSelection(*m_pInt) ; + return true; + } + else if (m_pString) + { + if (pControl->FindString(* m_pString) != wxNOT_FOUND) + { + pControl->SetStringSelection(* m_pString); + } + return true; + } + } else +#endif +#if wxUSE_STATTEXT + if (m_validatorWindow->IsKindOf(CLASSINFO(wxStaticText)) ) + { + wxStaticText* pControl = (wxStaticText*) m_validatorWindow; + if (m_pString) + { + pControl->SetLabel(*m_pString) ; + return true; + } + } else +#endif +#if wxUSE_TEXTCTRL + if (m_validatorWindow->IsKindOf(CLASSINFO(wxTextCtrl)) ) + { + wxTextCtrl* pControl = (wxTextCtrl*) m_validatorWindow; + if (m_pString) + { + pControl->SetValue(*m_pString) ; + return true; + } + else if (m_pInt) + { + wxString str; + str.Printf(wxT("%d"), *m_pInt); + pControl->SetValue(str); + return true; + } + } else +#endif + + // array controls +#if wxUSE_CHECKLISTBOX + // NOTE: wxCheckListBox is a wxListBox, so wxCheckListBox MUST come first: + if (m_validatorWindow->IsKindOf(CLASSINFO(wxCheckListBox)) ) + { + wxCheckListBox* pControl = (wxCheckListBox*) m_validatorWindow; + if (m_pArrayInt) + { + // clear all selections + size_t i, + count = pControl->GetCount(); + for ( i = 0 ; i < count; i++ ) + pControl->Check(i, false); + + // select each item in our array + count = m_pArrayInt->GetCount(); + for ( i = 0 ; i < count; i++ ) + pControl->Check(m_pArrayInt->Item(i)); + + return true; + } + else + return false; + } else +#endif +#if wxUSE_LISTBOX + if (m_validatorWindow->IsKindOf(CLASSINFO(wxListBox)) ) + { + wxListBox* pControl = (wxListBox*) m_validatorWindow; + if (m_pArrayInt) + { + // clear all selections + size_t i, + count = pControl->GetCount(); + for ( i = 0 ; i < count; i++ ) + pControl->Deselect(i); + + // select each item in our array + count = m_pArrayInt->GetCount(); + for ( i = 0 ; i < count; i++ ) + pControl->SetSelection(m_pArrayInt->Item(i)); + + return true; + } + } else +#endif + ; // to match the last 'else' above + + // unrecognized control, or bad pointer + return false; +} + +// Called to transfer data from the window +bool wxGenericValidator::TransferFromWindow(void) +{ + if ( !m_validatorWindow ) + return false; + + // BOOL CONTROLS ************************************** +#if wxUSE_CHECKBOX + if (m_validatorWindow->IsKindOf(CLASSINFO(wxCheckBox)) ) + { + wxCheckBox* pControl = (wxCheckBox*) m_validatorWindow; + if (m_pBool) + { + *m_pBool = pControl->GetValue() ; + return true; + } + } else +#endif +#if wxUSE_RADIOBTN + if (m_validatorWindow->IsKindOf(CLASSINFO(wxRadioButton)) ) + { + wxRadioButton* pControl = (wxRadioButton*) m_validatorWindow; + if (m_pBool) + { + *m_pBool = pControl->GetValue() ; + return true; + } + } else +#endif +#if wxUSE_TOGGLEBTN + if (m_validatorWindow->IsKindOf(CLASSINFO(wxToggleButton)) ) + { + wxToggleButton *pControl = (wxToggleButton *) m_validatorWindow; + if (m_pBool) + { + *m_pBool = pControl->GetValue() ; + return true; + } + } else +#endif + + // INT CONTROLS *************************************** +#if wxUSE_GAUGE + if (m_validatorWindow->IsKindOf(CLASSINFO(wxGauge)) ) + { + wxGauge* pControl = (wxGauge*) m_validatorWindow; + if (m_pInt) + { + *m_pInt = pControl->GetValue() ; + return true; + } + } else +#endif +#if wxUSE_RADIOBOX + if (m_validatorWindow->IsKindOf(CLASSINFO(wxRadioBox)) ) + { + wxRadioBox* pControl = (wxRadioBox*) m_validatorWindow; + if (m_pInt) + { + *m_pInt = pControl->GetSelection() ; + return true; + } + } else +#endif +#if wxUSE_SCROLLBAR + if (m_validatorWindow->IsKindOf(CLASSINFO(wxScrollBar)) ) + { + wxScrollBar* pControl = (wxScrollBar*) m_validatorWindow; + if (m_pInt) + { + *m_pInt = pControl->GetThumbPosition() ; + return true; + } + } else +#endif +#if wxUSE_SPINCTRL && !defined(__WXMOTIF__) + if (m_validatorWindow->IsKindOf(CLASSINFO(wxSpinCtrl)) ) + { + wxSpinCtrl* pControl = (wxSpinCtrl*) m_validatorWindow; + if (m_pInt) + { + *m_pInt=pControl->GetValue(); + return true; + } + } else +#endif +#if wxUSE_SPINBTN + if (m_validatorWindow->IsKindOf(CLASSINFO(wxSpinButton)) ) + { + wxSpinButton* pControl = (wxSpinButton*) m_validatorWindow; + if (m_pInt) + { + *m_pInt = pControl->GetValue() ; + return true; + } + } else +#endif +#if wxUSE_SLIDER + if (m_validatorWindow->IsKindOf(CLASSINFO(wxSlider)) ) + { + wxSlider* pControl = (wxSlider*) m_validatorWindow; + if (m_pInt) + { + *m_pInt = pControl->GetValue() ; + return true; + } + } else +#endif + + // STRING CONTROLS ************************************ +#if wxUSE_BUTTON + if (m_validatorWindow->IsKindOf(CLASSINFO(wxButton)) ) + { + wxButton* pControl = (wxButton*) m_validatorWindow; + if (m_pString) + { + *m_pString = pControl->GetLabel() ; + return true; + } + } else +#endif +#if wxUSE_COMBOBOX + if (m_validatorWindow->IsKindOf(CLASSINFO(wxComboBox)) ) + { + wxComboBox* pControl = (wxComboBox*) m_validatorWindow; + if (m_pInt) + { + *m_pInt = pControl->GetSelection() ; + return true; + } + else if (m_pString) + { + if (m_validatorWindow->GetWindowStyle() & wxCB_READONLY) + *m_pString = pControl->GetStringSelection(); + else + *m_pString = pControl->GetValue(); + return true; + } + } else +#endif +#if wxUSE_CHOICE + if (m_validatorWindow->IsKindOf(CLASSINFO(wxChoice)) ) + { + wxChoice* pControl = (wxChoice*) m_validatorWindow; + if (m_pInt) + { + *m_pInt = pControl->GetSelection() ; + return true; + } + else if (m_pString) + { + *m_pString = pControl->GetStringSelection(); + return true; + } + } else +#endif +#if wxUSE_STATTEXT + if (m_validatorWindow->IsKindOf(CLASSINFO(wxStaticText)) ) + { + wxStaticText* pControl = (wxStaticText*) m_validatorWindow; + if (m_pString) + { + *m_pString = pControl->GetLabel() ; + return true; + } + } else +#endif +#if wxUSE_TEXTCTRL + if (m_validatorWindow->IsKindOf(CLASSINFO(wxTextCtrl)) ) + { + wxTextCtrl* pControl = (wxTextCtrl*) m_validatorWindow; + if (m_pString) + { + *m_pString = pControl->GetValue() ; + return true; + } + else if (m_pInt) + { + *m_pInt = wxAtoi(pControl->GetValue()); + return true; + } + } else +#endif + + // ARRAY CONTROLS ************************************* +#if wxUSE_CHECKLISTBOX + // NOTE: wxCheckListBox isa wxListBox, so wxCheckListBox MUST come first: + if (m_validatorWindow->IsKindOf(CLASSINFO(wxCheckListBox)) ) + { + wxCheckListBox* pControl = (wxCheckListBox*) m_validatorWindow; + if (m_pArrayInt) + { + // clear our array + m_pArrayInt->Clear(); + + // add each selected item to our array + size_t i, + count = pControl->GetCount(); + for ( i = 0; i < count; i++ ) + { + if (pControl->IsChecked(i)) + m_pArrayInt->Add(i); + } + + return true; + } + else + return false; + } else +#endif +#if wxUSE_LISTBOX + if (m_validatorWindow->IsKindOf(CLASSINFO(wxListBox)) ) + { + wxListBox* pControl = (wxListBox*) m_validatorWindow; + if (m_pArrayInt) + { + // clear our array + m_pArrayInt->Clear(); + + // add each selected item to our array + size_t i, + count = pControl->GetCount(); + for ( i = 0; i < count; i++ ) + { + if (pControl->IsSelected(i)) + m_pArrayInt->Add(i); + } + + return true; + } + } else +#endif + + // unrecognized control, or bad pointer + return false; + + return false; +} + +/* + Called by constructors to initialize ALL data members +*/ +void wxGenericValidator::Initialize() +{ + m_pBool = 0; + m_pInt = 0; + m_pString = 0; + m_pArrayInt = 0; +} + +#endif + // wxUSE_VALIDATORS diff --git a/Externals/wxWidgets/src/common/validate.cpp b/Externals/wxWidgets/src/common/validate.cpp index d4ba5e61af..e01711baeb 100644 --- a/Externals/wxWidgets/src/common/validate.cpp +++ b/Externals/wxWidgets/src/common/validate.cpp @@ -1,45 +1,45 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/validate.cpp -// Purpose: wxValidator -// Author: Julian Smart -// Modified by: -// Created: 04/01/98 -// RCS-ID: $Id: validate.cpp 39656 2006-06-09 21:21:53Z ABX $ -// Copyright: (c) Julian Smart -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_VALIDATORS - -#include "wx/validate.h" - -#ifndef WX_PRECOMP - #include "wx/window.h" -#endif - -const wxValidator wxDefaultValidator; - -IMPLEMENT_DYNAMIC_CLASS(wxValidator, wxEvtHandler) - -// VZ: personally, I think true would be more appropriate - these bells are -// _annoying_ -bool wxValidator::ms_isSilent = false; - -wxValidator::wxValidator() -{ - m_validatorWindow = (wxWindow *) NULL; -} - -wxValidator::~wxValidator() -{ -} - -#endif - // wxUSE_VALIDATORS +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/validate.cpp +// Purpose: wxValidator +// Author: Julian Smart +// Modified by: +// Created: 04/01/98 +// RCS-ID: $Id: validate.cpp 39656 2006-06-09 21:21:53Z ABX $ +// Copyright: (c) Julian Smart +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_VALIDATORS + +#include "wx/validate.h" + +#ifndef WX_PRECOMP + #include "wx/window.h" +#endif + +const wxValidator wxDefaultValidator; + +IMPLEMENT_DYNAMIC_CLASS(wxValidator, wxEvtHandler) + +// VZ: personally, I think true would be more appropriate - these bells are +// _annoying_ +bool wxValidator::ms_isSilent = false; + +wxValidator::wxValidator() +{ + m_validatorWindow = (wxWindow *) NULL; +} + +wxValidator::~wxValidator() +{ +} + +#endif + // wxUSE_VALIDATORS diff --git a/Externals/wxWidgets/src/common/valtext.cpp b/Externals/wxWidgets/src/common/valtext.cpp index e9eba332a1..6f3d8b5609 100644 --- a/Externals/wxWidgets/src/common/valtext.cpp +++ b/Externals/wxWidgets/src/common/valtext.cpp @@ -1,344 +1,344 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/valtext.cpp -// Purpose: wxTextValidator -// Author: Julian Smart -// Modified by: -// Created: 04/01/98 -// RCS-ID: $Id: valtext.cpp 39656 2006-06-09 21:21:53Z ABX $ -// Copyright: (c) Julian Smart -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_VALIDATORS && wxUSE_TEXTCTRL - -#include "wx/valtext.h" - -#ifndef WX_PRECOMP - #include - #include "wx/textctrl.h" - #include "wx/utils.h" - #include "wx/msgdlg.h" - #include "wx/intl.h" -#endif - -#include -#include -#include - -#ifdef __SALFORDC__ - #include -#endif - -IMPLEMENT_DYNAMIC_CLASS(wxTextValidator, wxValidator) - -BEGIN_EVENT_TABLE(wxTextValidator, wxValidator) - EVT_CHAR(wxTextValidator::OnChar) -END_EVENT_TABLE() - -static bool wxIsNumeric(const wxString& val); - -wxTextValidator::wxTextValidator(long style, wxString *val) -{ - m_validatorStyle = style; - m_stringValue = val; -/* - m_refData = new wxVTextRefData; - - M_VTEXTDATA->m_validatorStyle = style; - M_VTEXTDATA->m_stringValue = val; -*/ -} - -wxTextValidator::wxTextValidator(const wxTextValidator& val) - : wxValidator() -{ - Copy(val); -} - -bool wxTextValidator::Copy(const wxTextValidator& val) -{ - wxValidator::Copy(val); - - m_validatorStyle = val.m_validatorStyle; - m_stringValue = val.m_stringValue; - - m_includes = val.m_includes; - m_excludes = val.m_excludes; - - return true; -} - -static bool wxIsAlpha(const wxString& val) -{ - int i; - for ( i = 0; i < (int)val.length(); i++) - { - if (!wxIsalpha(val[i])) - return false; - } - return true; -} - -static bool wxIsAlphaNumeric(const wxString& val) -{ - int i; - for ( i = 0; i < (int)val.length(); i++) - { - if (!wxIsalnum(val[i])) - return false; - } - return true; -} - -// Called when the value in the window must be validated. -// This function can pop up an error message. -bool wxTextValidator::Validate(wxWindow *parent) -{ - if( !CheckValidator() ) - return false; - - wxTextCtrl *control = (wxTextCtrl *) m_validatorWindow; - - // If window is disabled, simply return - if ( !control->IsEnabled() ) - return true; - - wxString val(control->GetValue()); - - bool ok = true; - - // NB: this format string should contian exactly one '%s' - wxString errormsg; - - bool includes = (m_validatorStyle & wxFILTER_INCLUDE_LIST) != 0; - if ( includes || (m_validatorStyle & wxFILTER_EXCLUDE_LIST) ) - { - // if includes, it's only ok to have the members of the list, - // otherwise it's only ok to have non-members - ok = includes == (m_includes.Index(val) != wxNOT_FOUND); - if ( !ok ) - { - errormsg = _("'%s' is invalid"); - } - } - else if ( (m_validatorStyle & wxFILTER_ASCII) && !val.IsAscii() ) - { - ok = false; - - errormsg = _("'%s' should only contain ASCII characters."); - } - else if ( (m_validatorStyle & wxFILTER_ALPHA) && !wxIsAlpha(val) ) - { - ok = false; - - errormsg = _("'%s' should only contain alphabetic characters."); - } - else if ( (m_validatorStyle & wxFILTER_ALPHANUMERIC) && !wxIsAlphaNumeric(val)) - { - ok = false; - - errormsg = _("'%s' should only contain alphabetic or numeric characters."); - } - else if ( (m_validatorStyle & wxFILTER_NUMERIC) && !wxIsNumeric(val)) - { - ok = false; - - errormsg = _("'%s' should be numeric."); - } - else if ( (m_validatorStyle & wxFILTER_INCLUDE_CHAR_LIST) && !IsInCharIncludes(val)) - { - //it's only ok to have the members of the list - errormsg = _("'%s' is invalid"); - ok = false; - } - else if ( (m_validatorStyle & wxFILTER_EXCLUDE_CHAR_LIST) && !IsNotInCharExcludes(val)) - { - // it's only ok to have non-members of the list - errormsg = _("'%s' is invalid"); - ok = false; - } - - if ( !ok ) - { - wxASSERT_MSG( !errormsg.empty(), _T("you forgot to set errormsg") ); - - m_validatorWindow->SetFocus(); - - wxString buf; - buf.Printf(errormsg, val.c_str()); - - wxMessageBox(buf, _("Validation conflict"), - wxOK | wxICON_EXCLAMATION, parent); - } - - return ok; -} - -// Called to transfer data to the window -bool wxTextValidator::TransferToWindow(void) -{ - if( !CheckValidator() ) - return false; - - if ( m_stringValue ) - { - wxTextCtrl *control = (wxTextCtrl *) m_validatorWindow; - control->SetValue(* m_stringValue); - } - - return true; -} - -// Called to transfer data to the window -bool wxTextValidator::TransferFromWindow(void) -{ - if( !CheckValidator() ) - return false; - - if ( m_stringValue ) - { - wxTextCtrl *control = (wxTextCtrl *) m_validatorWindow; - *m_stringValue = control->GetValue(); - } - - return true; -} - -#if WXWIN_COMPATIBILITY_2_4 - -inline void wxCopyStringListToArrayString(wxArrayString& to, const wxStringList& from) -{ - to.Clear(); - - for ( wxStringList::compatibility_iterator pNode = from.GetFirst(); - pNode; - pNode = pNode->GetNext() ) - { - to.Add(pNode->GetData()); - } -} - -inline void wxCopyArrayStringToStringList(wxStringList& to, const wxArrayString& from) -{ - to.Clear(); - - for(size_t i = 0; i < from.GetCount(); ++i) - to.Add(from[i]); -} - -wxStringList& wxTextValidator::GetIncludeList() -{ - wxCopyArrayStringToStringList(m_includeList, m_includes); - return m_includeList; -} - -wxStringList& wxTextValidator::GetExcludeList() -{ - wxCopyArrayStringToStringList(m_excludeList, m_excludes); - return m_excludeList; -} - -void wxTextValidator::SetIncludeList(const wxStringList& list) -{ - wxCopyStringListToArrayString(m_includes, list); -} - -void wxTextValidator::SetExcludeList(const wxStringList& list) -{ - wxCopyStringListToArrayString(m_excludes, list); -} - -bool wxTextValidator::IsInCharIncludeList(const wxString& val) -{ - return IsInCharIncludes(val); -} - -bool wxTextValidator::IsNotInCharExcludeList(const wxString& val) -{ - return IsNotInCharExcludes(val); -} - -#endif //compat 2.4 - - -bool wxTextValidator::IsInCharIncludes(const wxString& val) -{ - size_t i; - for ( i = 0; i < val.length(); i++) - { - if (m_includes.Index((wxString) val[i]) == wxNOT_FOUND) - return false; - } - return true; -} - -bool wxTextValidator::IsNotInCharExcludes(const wxString& val) -{ - size_t i; - for ( i = 0; i < val.length(); i++) - { - if (m_excludes.Index((wxString) val[i]) != wxNOT_FOUND) - return false; - } - return true; -} - -void wxTextValidator::OnChar(wxKeyEvent& event) -{ -/* - if ( !M_VTEXTDATA ) - return; -*/ - - if ( m_validatorWindow ) - { - int keyCode = event.GetKeyCode(); - - // we don't filter special keys and Delete - if ( - !(keyCode < WXK_SPACE || keyCode == WXK_DELETE || keyCode > WXK_START) && - ( - ((m_validatorStyle & wxFILTER_INCLUDE_CHAR_LIST) && !IsInCharIncludes(wxString((wxChar) keyCode, 1))) || - ((m_validatorStyle & wxFILTER_EXCLUDE_CHAR_LIST) && !IsNotInCharExcludes(wxString((wxChar) keyCode, 1))) || - ((m_validatorStyle & wxFILTER_ASCII) && !isascii(keyCode)) || - ((m_validatorStyle & wxFILTER_ALPHA) && !wxIsalpha(keyCode)) || - ((m_validatorStyle & wxFILTER_ALPHANUMERIC) && !wxIsalnum(keyCode)) || - ((m_validatorStyle & wxFILTER_NUMERIC) && !wxIsdigit(keyCode) - && keyCode != wxT('.') && keyCode != wxT(',') && keyCode != wxT('-') && keyCode != wxT('+') && keyCode != wxT('e') && keyCode != wxT('E')) - ) - ) - { - if ( !wxValidator::IsSilent() ) - wxBell(); - - // eat message - return; - } - } - - event.Skip(); -} - -static bool wxIsNumeric(const wxString& val) -{ - int i; - for ( i = 0; i < (int)val.length(); i++) - { - // Allow for "," (French) as well as "." -- in future we should - // use wxSystemSettings or other to do better localisation - if ((!wxIsdigit(val[i])) && (val[i] != wxT('.')) && (val[i] != wxT(',')) && (val[i] != wxT('e')) && (val[i] != wxT('E')) && (val[i] != wxT('+')) && (val[i] != wxT('-'))) - return false; - } - return true; -} - - -#endif - // wxUSE_VALIDATORS && wxUSE_TEXTCTRL +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/valtext.cpp +// Purpose: wxTextValidator +// Author: Julian Smart +// Modified by: +// Created: 04/01/98 +// RCS-ID: $Id: valtext.cpp 39656 2006-06-09 21:21:53Z ABX $ +// Copyright: (c) Julian Smart +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_VALIDATORS && wxUSE_TEXTCTRL + +#include "wx/valtext.h" + +#ifndef WX_PRECOMP + #include + #include "wx/textctrl.h" + #include "wx/utils.h" + #include "wx/msgdlg.h" + #include "wx/intl.h" +#endif + +#include +#include +#include + +#ifdef __SALFORDC__ + #include +#endif + +IMPLEMENT_DYNAMIC_CLASS(wxTextValidator, wxValidator) + +BEGIN_EVENT_TABLE(wxTextValidator, wxValidator) + EVT_CHAR(wxTextValidator::OnChar) +END_EVENT_TABLE() + +static bool wxIsNumeric(const wxString& val); + +wxTextValidator::wxTextValidator(long style, wxString *val) +{ + m_validatorStyle = style; + m_stringValue = val; +/* + m_refData = new wxVTextRefData; + + M_VTEXTDATA->m_validatorStyle = style; + M_VTEXTDATA->m_stringValue = val; +*/ +} + +wxTextValidator::wxTextValidator(const wxTextValidator& val) + : wxValidator() +{ + Copy(val); +} + +bool wxTextValidator::Copy(const wxTextValidator& val) +{ + wxValidator::Copy(val); + + m_validatorStyle = val.m_validatorStyle; + m_stringValue = val.m_stringValue; + + m_includes = val.m_includes; + m_excludes = val.m_excludes; + + return true; +} + +static bool wxIsAlpha(const wxString& val) +{ + int i; + for ( i = 0; i < (int)val.length(); i++) + { + if (!wxIsalpha(val[i])) + return false; + } + return true; +} + +static bool wxIsAlphaNumeric(const wxString& val) +{ + int i; + for ( i = 0; i < (int)val.length(); i++) + { + if (!wxIsalnum(val[i])) + return false; + } + return true; +} + +// Called when the value in the window must be validated. +// This function can pop up an error message. +bool wxTextValidator::Validate(wxWindow *parent) +{ + if( !CheckValidator() ) + return false; + + wxTextCtrl *control = (wxTextCtrl *) m_validatorWindow; + + // If window is disabled, simply return + if ( !control->IsEnabled() ) + return true; + + wxString val(control->GetValue()); + + bool ok = true; + + // NB: this format string should contian exactly one '%s' + wxString errormsg; + + bool includes = (m_validatorStyle & wxFILTER_INCLUDE_LIST) != 0; + if ( includes || (m_validatorStyle & wxFILTER_EXCLUDE_LIST) ) + { + // if includes, it's only ok to have the members of the list, + // otherwise it's only ok to have non-members + ok = includes == (m_includes.Index(val) != wxNOT_FOUND); + if ( !ok ) + { + errormsg = _("'%s' is invalid"); + } + } + else if ( (m_validatorStyle & wxFILTER_ASCII) && !val.IsAscii() ) + { + ok = false; + + errormsg = _("'%s' should only contain ASCII characters."); + } + else if ( (m_validatorStyle & wxFILTER_ALPHA) && !wxIsAlpha(val) ) + { + ok = false; + + errormsg = _("'%s' should only contain alphabetic characters."); + } + else if ( (m_validatorStyle & wxFILTER_ALPHANUMERIC) && !wxIsAlphaNumeric(val)) + { + ok = false; + + errormsg = _("'%s' should only contain alphabetic or numeric characters."); + } + else if ( (m_validatorStyle & wxFILTER_NUMERIC) && !wxIsNumeric(val)) + { + ok = false; + + errormsg = _("'%s' should be numeric."); + } + else if ( (m_validatorStyle & wxFILTER_INCLUDE_CHAR_LIST) && !IsInCharIncludes(val)) + { + //it's only ok to have the members of the list + errormsg = _("'%s' is invalid"); + ok = false; + } + else if ( (m_validatorStyle & wxFILTER_EXCLUDE_CHAR_LIST) && !IsNotInCharExcludes(val)) + { + // it's only ok to have non-members of the list + errormsg = _("'%s' is invalid"); + ok = false; + } + + if ( !ok ) + { + wxASSERT_MSG( !errormsg.empty(), _T("you forgot to set errormsg") ); + + m_validatorWindow->SetFocus(); + + wxString buf; + buf.Printf(errormsg, val.c_str()); + + wxMessageBox(buf, _("Validation conflict"), + wxOK | wxICON_EXCLAMATION, parent); + } + + return ok; +} + +// Called to transfer data to the window +bool wxTextValidator::TransferToWindow(void) +{ + if( !CheckValidator() ) + return false; + + if ( m_stringValue ) + { + wxTextCtrl *control = (wxTextCtrl *) m_validatorWindow; + control->SetValue(* m_stringValue); + } + + return true; +} + +// Called to transfer data to the window +bool wxTextValidator::TransferFromWindow(void) +{ + if( !CheckValidator() ) + return false; + + if ( m_stringValue ) + { + wxTextCtrl *control = (wxTextCtrl *) m_validatorWindow; + *m_stringValue = control->GetValue(); + } + + return true; +} + +#if WXWIN_COMPATIBILITY_2_4 + +inline void wxCopyStringListToArrayString(wxArrayString& to, const wxStringList& from) +{ + to.Clear(); + + for ( wxStringList::compatibility_iterator pNode = from.GetFirst(); + pNode; + pNode = pNode->GetNext() ) + { + to.Add(pNode->GetData()); + } +} + +inline void wxCopyArrayStringToStringList(wxStringList& to, const wxArrayString& from) +{ + to.Clear(); + + for(size_t i = 0; i < from.GetCount(); ++i) + to.Add(from[i]); +} + +wxStringList& wxTextValidator::GetIncludeList() +{ + wxCopyArrayStringToStringList(m_includeList, m_includes); + return m_includeList; +} + +wxStringList& wxTextValidator::GetExcludeList() +{ + wxCopyArrayStringToStringList(m_excludeList, m_excludes); + return m_excludeList; +} + +void wxTextValidator::SetIncludeList(const wxStringList& list) +{ + wxCopyStringListToArrayString(m_includes, list); +} + +void wxTextValidator::SetExcludeList(const wxStringList& list) +{ + wxCopyStringListToArrayString(m_excludes, list); +} + +bool wxTextValidator::IsInCharIncludeList(const wxString& val) +{ + return IsInCharIncludes(val); +} + +bool wxTextValidator::IsNotInCharExcludeList(const wxString& val) +{ + return IsNotInCharExcludes(val); +} + +#endif //compat 2.4 + + +bool wxTextValidator::IsInCharIncludes(const wxString& val) +{ + size_t i; + for ( i = 0; i < val.length(); i++) + { + if (m_includes.Index((wxString) val[i]) == wxNOT_FOUND) + return false; + } + return true; +} + +bool wxTextValidator::IsNotInCharExcludes(const wxString& val) +{ + size_t i; + for ( i = 0; i < val.length(); i++) + { + if (m_excludes.Index((wxString) val[i]) != wxNOT_FOUND) + return false; + } + return true; +} + +void wxTextValidator::OnChar(wxKeyEvent& event) +{ +/* + if ( !M_VTEXTDATA ) + return; +*/ + + if ( m_validatorWindow ) + { + int keyCode = event.GetKeyCode(); + + // we don't filter special keys and Delete + if ( + !(keyCode < WXK_SPACE || keyCode == WXK_DELETE || keyCode > WXK_START) && + ( + ((m_validatorStyle & wxFILTER_INCLUDE_CHAR_LIST) && !IsInCharIncludes(wxString((wxChar) keyCode, 1))) || + ((m_validatorStyle & wxFILTER_EXCLUDE_CHAR_LIST) && !IsNotInCharExcludes(wxString((wxChar) keyCode, 1))) || + ((m_validatorStyle & wxFILTER_ASCII) && !isascii(keyCode)) || + ((m_validatorStyle & wxFILTER_ALPHA) && !wxIsalpha(keyCode)) || + ((m_validatorStyle & wxFILTER_ALPHANUMERIC) && !wxIsalnum(keyCode)) || + ((m_validatorStyle & wxFILTER_NUMERIC) && !wxIsdigit(keyCode) + && keyCode != wxT('.') && keyCode != wxT(',') && keyCode != wxT('-') && keyCode != wxT('+') && keyCode != wxT('e') && keyCode != wxT('E')) + ) + ) + { + if ( !wxValidator::IsSilent() ) + wxBell(); + + // eat message + return; + } + } + + event.Skip(); +} + +static bool wxIsNumeric(const wxString& val) +{ + int i; + for ( i = 0; i < (int)val.length(); i++) + { + // Allow for "," (French) as well as "." -- in future we should + // use wxSystemSettings or other to do better localisation + if ((!wxIsdigit(val[i])) && (val[i] != wxT('.')) && (val[i] != wxT(',')) && (val[i] != wxT('e')) && (val[i] != wxT('E')) && (val[i] != wxT('+')) && (val[i] != wxT('-'))) + return false; + } + return true; +} + + +#endif + // wxUSE_VALIDATORS && wxUSE_TEXTCTRL diff --git a/Externals/wxWidgets/src/common/variant.cpp b/Externals/wxWidgets/src/common/variant.cpp index 76bb93950f..4f39b6e9c2 100644 --- a/Externals/wxWidgets/src/common/variant.cpp +++ b/Externals/wxWidgets/src/common/variant.cpp @@ -1,2030 +1,2030 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/variant.cpp -// Purpose: wxVariant class, container for any type -// Author: Julian Smart -// Modified by: -// Created: 10/09/98 -// RCS-ID: $Id: variant.cpp 45498 2007-04-16 13:03:05Z VZ $ -// Copyright: (c) -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx/wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#include "wx/variant.h" - -#if wxUSE_VARIANT - -#ifndef WX_PRECOMP - #include "wx/string.h" - #include "wx/math.h" - #if wxUSE_STREAMS - #include "wx/stream.h" - #endif -#endif - -#if wxUSE_STD_IOSTREAM - #if wxUSE_IOSTREAMH - #include - #else - #include - #endif -#endif - -#if defined(__MWERKS__) && __MSL__ >= 0x6000 -namespace std {} -using namespace std ; -#endif - -#if wxUSE_STREAMS - #include "wx/txtstrm.h" -#endif - -#include "wx/string.h" -#include "wx/tokenzr.h" - -IMPLEMENT_ABSTRACT_CLASS(wxVariantData, wxObject) - -wxVariant WXDLLIMPEXP_BASE wxNullVariant; - - -/* - * wxVariant - */ - -IMPLEMENT_DYNAMIC_CLASS(wxVariant, wxObject) - -wxVariant::wxVariant() -{ - m_data = (wxVariantData*) NULL; -} - -bool wxVariant::IsNull() const -{ - return (m_data == (wxVariantData*) NULL); -} - -void wxVariant::MakeNull() -{ - UnRef(); -} - -void wxVariant::Clear() -{ - m_name = wxEmptyString; -} - -wxVariant::wxVariant(const wxVariant& variant) - : wxObject() -{ - m_data = (wxVariantData*) NULL; - - if (!variant.IsNull()) - Ref(variant); - - m_name = variant.m_name; -} - -wxVariant::wxVariant(wxVariantData* data, const wxString& name) // User-defined data -{ - m_data = data; - m_name = name; -} - -wxVariant::~wxVariant() -{ - UnRef(); -} - -// Assignment -void wxVariant::operator= (const wxVariant& variant) -{ - Ref(variant); - m_name = variant.m_name; -} - -// myVariant = new wxStringVariantData("hello") -void wxVariant::operator= (wxVariantData* variantData) -{ - UnRef(); - m_data = variantData; -} - -bool wxVariant::operator== (const wxVariant& variant) const -{ - if (IsNull() || variant.IsNull()) - return (IsNull() == variant.IsNull()); - - return (GetData()->Eq(* variant.GetData())); -} - -bool wxVariant::operator!= (const wxVariant& variant) const -{ - return (!(*this == variant)); -} - - -wxString wxVariant::MakeString() const -{ - if (!IsNull()) - { - wxString str; - if (GetData()->Write(str)) - return str; - } - return wxEmptyString; -} - -void wxVariant::SetData(wxVariantData* data) -{ - UnRef(); - m_data = data; -} - -void wxVariant::Ref(const wxVariant& clone) -{ - // nothing to be done - if (m_data == clone.m_data) - return; - - // delete reference to old data - UnRef(); - - // reference new data - if ( clone.m_data ) - { - m_data = clone.m_data; - m_data->m_count++; - } -} - - -void wxVariant::UnRef() -{ - if ( m_data ) - { - wxASSERT_MSG( m_data->m_count > 0, _T("invalid ref data count") ); - - m_data->DecRef(); - m_data = NULL; - } -} - - -// Returns a string representing the type of the variant, -// e.g. "string", "bool", "list", "double", "long" -wxString wxVariant::GetType() const -{ - if (IsNull()) - return wxString(wxT("null")); - else - return GetData()->GetType(); -} - - -bool wxVariant::IsType(const wxString& type) const -{ - return (GetType() == type); -} - -bool wxVariant::IsValueKindOf(const wxClassInfo* type) const -{ - wxClassInfo* info=GetData()->GetValueClassInfo(); - return info ? info->IsKindOf(type) : false ; -} - - -// ----------------------------------------------------------------- -// wxVariantDataLong -// ----------------------------------------------------------------- - -class WXDLLIMPEXP_BASE wxVariantDataLong: public wxVariantData -{ -DECLARE_DYNAMIC_CLASS(wxVariantDataLong) -public: - wxVariantDataLong() { m_value = 0; } - wxVariantDataLong(long value) { m_value = value; } - - inline long GetValue() const { return m_value; } - inline void SetValue(long value) { m_value = value; } - - virtual bool Eq(wxVariantData& data) const; - - virtual bool Read(wxString& str); - virtual bool Write(wxString& str) const; -#if wxUSE_STD_IOSTREAM - virtual bool Read(wxSTD istream& str); - virtual bool Write(wxSTD ostream& str) const; -#endif -#if wxUSE_STREAMS - virtual bool Read(wxInputStream& str); - virtual bool Write(wxOutputStream &str) const; -#endif // wxUSE_STREAMS - - virtual wxString GetType() const { return wxT("long"); } - -protected: - long m_value; -}; - -IMPLEMENT_DYNAMIC_CLASS(wxVariantDataLong, wxVariantData) - -bool wxVariantDataLong::Eq(wxVariantData& data) const -{ - wxASSERT_MSG( (data.GetType() == wxT("long")), wxT("wxVariantDataLong::Eq: argument mismatch") ); - - wxVariantDataLong& otherData = (wxVariantDataLong&) data; - - return (otherData.m_value == m_value); -} - -#if wxUSE_STD_IOSTREAM -bool wxVariantDataLong::Write(wxSTD ostream& str) const -{ - wxString s; - Write(s); - str << (const char*) s.mb_str(); - return true; -} -#endif - -bool wxVariantDataLong::Write(wxString& str) const -{ - str.Printf(wxT("%ld"), m_value); - return true; -} - -#if wxUSE_STD_IOSTREAM -bool wxVariantDataLong::Read(wxSTD istream& str) -{ - str >> m_value; - return true; -} -#endif - -#if wxUSE_STREAMS -bool wxVariantDataLong::Write(wxOutputStream& str) const -{ - wxTextOutputStream s(str); - - s.Write32((size_t)m_value); - return true; -} - -bool wxVariantDataLong::Read(wxInputStream& str) -{ - wxTextInputStream s(str); - m_value = s.Read32(); - return true; -} -#endif // wxUSE_STREAMS - -bool wxVariantDataLong::Read(wxString& str) -{ - m_value = wxAtol((const wxChar*) str); - return true; -} - -// wxVariant - -wxVariant::wxVariant(long val, const wxString& name) -{ - m_data = new wxVariantDataLong(val); - m_name = name; -} - -wxVariant::wxVariant(int val, const wxString& name) -{ - m_data = new wxVariantDataLong((long)val); - m_name = name; -} - -wxVariant::wxVariant(short val, const wxString& name) -{ - m_data = new wxVariantDataLong((long)val); - m_name = name; -} - -bool wxVariant::operator== (long value) const -{ - long thisValue; - if (!Convert(&thisValue)) - return false; - else - return (value == thisValue); -} - -bool wxVariant::operator!= (long value) const -{ - return (!((*this) == value)); -} - -void wxVariant::operator= (long value) -{ - if (GetType() == wxT("long") && - m_data->GetRefCount() == 1) - { - ((wxVariantDataLong*)GetData())->SetValue(value); - } - else - { - UnRef(); - m_data = new wxVariantDataLong(value); - } -} - -long wxVariant::GetLong() const -{ - long value; - if (Convert(& value)) - return value; - else - { - wxFAIL_MSG(wxT("Could not convert to a long")); - return 0; - } -} - -// ----------------------------------------------------------------- -// wxVariantDoubleData -// ----------------------------------------------------------------- - -class WXDLLIMPEXP_BASE wxVariantDoubleData: public wxVariantData -{ -DECLARE_DYNAMIC_CLASS(wxVariantDoubleData) -public: - wxVariantDoubleData() { m_value = 0.0; } - wxVariantDoubleData(double value) { m_value = value; } - - inline double GetValue() const { return m_value; } - inline void SetValue(double value) { m_value = value; } - - virtual bool Eq(wxVariantData& data) const; - virtual bool Read(wxString& str); -#if wxUSE_STD_IOSTREAM - virtual bool Write(wxSTD ostream& str) const; -#endif - virtual bool Write(wxString& str) const; -#if wxUSE_STD_IOSTREAM - virtual bool Read(wxSTD istream& str); -#endif -#if wxUSE_STREAMS - virtual bool Read(wxInputStream& str); - virtual bool Write(wxOutputStream &str) const; -#endif // wxUSE_STREAMS - virtual wxString GetType() const { return wxT("double"); } - -protected: - double m_value; -}; - -IMPLEMENT_DYNAMIC_CLASS(wxVariantDoubleData, wxVariantData) - -bool wxVariantDoubleData::Eq(wxVariantData& data) const -{ - wxASSERT_MSG( (data.GetType() == wxT("double")), wxT("wxVariantDoubleData::Eq: argument mismatch") ); - - wxVariantDoubleData& otherData = (wxVariantDoubleData&) data; - - return wxIsSameDouble(otherData.m_value, m_value); -} - -#if wxUSE_STD_IOSTREAM -bool wxVariantDoubleData::Write(wxSTD ostream& str) const -{ - wxString s; - Write(s); - str << (const char*) s.mb_str(); - return true; -} -#endif - -bool wxVariantDoubleData::Write(wxString& str) const -{ - str.Printf(wxT("%.14g"), m_value); - return true; -} - -#if wxUSE_STD_IOSTREAM -bool wxVariantDoubleData::Read(wxSTD istream& str) -{ - str >> m_value; - return true; -} -#endif - -#if wxUSE_STREAMS -bool wxVariantDoubleData::Write(wxOutputStream& str) const -{ - wxTextOutputStream s(str); - s.WriteDouble((double)m_value); - return true; -} - -bool wxVariantDoubleData::Read(wxInputStream& str) -{ - wxTextInputStream s(str); - m_value = (float)s.ReadDouble(); - return true; -} -#endif // wxUSE_STREAMS - -bool wxVariantDoubleData::Read(wxString& str) -{ - m_value = wxAtof((const wxChar*) str); - return true; -} - -// wxVariant double code - -wxVariant::wxVariant(double val, const wxString& name) -{ - m_data = new wxVariantDoubleData(val); - m_name = name; -} - -bool wxVariant::operator== (double value) const -{ - double thisValue; - if (!Convert(&thisValue)) - return false; - - return wxIsSameDouble(value, thisValue); -} - -bool wxVariant::operator!= (double value) const -{ - return (!((*this) == value)); -} - -void wxVariant::operator= (double value) -{ - if (GetType() == wxT("double") && - m_data->GetRefCount() == 1) - { - ((wxVariantDoubleData*)GetData())->SetValue(value); - } - else - { - UnRef(); - m_data = new wxVariantDoubleData(value); - } -} - -double wxVariant::GetDouble() const -{ - double value; - if (Convert(& value)) - return value; - else - { - wxFAIL_MSG(wxT("Could not convert to a double number")); - return 0.0; - } -} - -// ----------------------------------------------------------------- -// wxVariantBoolData -// ----------------------------------------------------------------- - -#ifdef HAVE_BOOL - -class WXDLLIMPEXP_BASE wxVariantDataBool: public wxVariantData -{ -DECLARE_DYNAMIC_CLASS(wxVariantDataBool) -public: - wxVariantDataBool() { m_value = 0; } - wxVariantDataBool(bool value) { m_value = value; } - - inline bool GetValue() const { return m_value; } - inline void SetValue(bool value) { m_value = value; } - - virtual bool Eq(wxVariantData& data) const; -#if wxUSE_STD_IOSTREAM - virtual bool Write(wxSTD ostream& str) const; -#endif - virtual bool Write(wxString& str) const; - virtual bool Read(wxString& str); -#if wxUSE_STD_IOSTREAM - virtual bool Read(wxSTD istream& str); -#endif -#if wxUSE_STREAMS - virtual bool Read(wxInputStream& str); - virtual bool Write(wxOutputStream& str) const; -#endif // wxUSE_STREAMS - virtual wxString GetType() const { return wxT("bool"); } - -protected: - bool m_value; -}; - -IMPLEMENT_DYNAMIC_CLASS(wxVariantDataBool, wxVariantData) - -bool wxVariantDataBool::Eq(wxVariantData& data) const -{ - wxASSERT_MSG( (data.GetType() == wxT("bool")), wxT("wxVariantDataBool::Eq: argument mismatch") ); - - wxVariantDataBool& otherData = (wxVariantDataBool&) data; - - return (otherData.m_value == m_value); -} - -#if wxUSE_STD_IOSTREAM -bool wxVariantDataBool::Write(wxSTD ostream& str) const -{ - wxString s; - Write(s); - str << (const char*) s.mb_str(); - return true; -} -#endif - -bool wxVariantDataBool::Write(wxString& str) const -{ - str.Printf(wxT("%d"), (int) m_value); - return true; -} - -#if wxUSE_STD_IOSTREAM -bool wxVariantDataBool::Read(wxSTD istream& WXUNUSED(str)) -{ - wxFAIL_MSG(wxT("Unimplemented")); -// str >> (long) m_value; - return false; -} -#endif - -#if wxUSE_STREAMS -bool wxVariantDataBool::Write(wxOutputStream& str) const -{ - wxTextOutputStream s(str); - - s.Write8(m_value); - return true; -} - -bool wxVariantDataBool::Read(wxInputStream& str) -{ - wxTextInputStream s(str); - - m_value = s.Read8() != 0; - return true; -} -#endif // wxUSE_STREAMS - -bool wxVariantDataBool::Read(wxString& str) -{ - m_value = (wxAtol((const wxChar*) str) != 0); - return true; -} - -// wxVariant **** - -wxVariant::wxVariant(bool val, const wxString& name) -{ - m_data = new wxVariantDataBool(val); - m_name = name; -} - -bool wxVariant::operator== (bool value) const -{ - bool thisValue; - if (!Convert(&thisValue)) - return false; - else - return (value == thisValue); -} - -bool wxVariant::operator!= (bool value) const -{ - return (!((*this) == value)); -} - -void wxVariant::operator= (bool value) -{ - if (GetType() == wxT("bool") && - m_data->GetRefCount() == 1) - { - ((wxVariantDataBool*)GetData())->SetValue(value); - } - else - { - UnRef(); - m_data = new wxVariantDataBool(value); - } -} - -bool wxVariant::GetBool() const -{ - bool value; - if (Convert(& value)) - return value; - else - { - wxFAIL_MSG(wxT("Could not convert to a bool")); - return 0; - } -} - -#endif // HAVE_BOOL - -// ----------------------------------------------------------------- -// wxVariantDataChar -// ----------------------------------------------------------------- - -class WXDLLIMPEXP_BASE wxVariantDataChar: public wxVariantData -{ -DECLARE_DYNAMIC_CLASS(wxVariantDataChar) -public: - wxVariantDataChar() { m_value = 0; } - wxVariantDataChar(wxChar value) { m_value = value; } - - inline wxChar GetValue() const { return m_value; } - inline void SetValue(wxChar value) { m_value = value; } - - virtual bool Eq(wxVariantData& data) const; -#if wxUSE_STD_IOSTREAM - virtual bool Read(wxSTD istream& str); - virtual bool Write(wxSTD ostream& str) const; -#endif - virtual bool Read(wxString& str); - virtual bool Write(wxString& str) const; -#if wxUSE_STREAMS - virtual bool Read(wxInputStream& str); - virtual bool Write(wxOutputStream& str) const; -#endif // wxUSE_STREAMS - virtual wxString GetType() const { return wxT("char"); } - -protected: - wxChar m_value; -}; - -IMPLEMENT_DYNAMIC_CLASS(wxVariantDataChar, wxVariantData) - -bool wxVariantDataChar::Eq(wxVariantData& data) const -{ - wxASSERT_MSG( (data.GetType() == wxT("char")), wxT("wxVariantDataChar::Eq: argument mismatch") ); - - wxVariantDataChar& otherData = (wxVariantDataChar&) data; - - return (otherData.m_value == m_value); -} - -#if wxUSE_STD_IOSTREAM -bool wxVariantDataChar::Write(wxSTD ostream& str) const -{ - wxString s; - Write(s); - str << (const char*) s.mb_str(); - return true; -} -#endif - -bool wxVariantDataChar::Write(wxString& str) const -{ - str.Printf(wxT("%c"), m_value); - return true; -} - -#if wxUSE_STD_IOSTREAM -bool wxVariantDataChar::Read(wxSTD istream& WXUNUSED(str)) -{ - wxFAIL_MSG(wxT("Unimplemented")); - - return false; -} -#endif - -#if wxUSE_STREAMS -bool wxVariantDataChar::Write(wxOutputStream& str) const -{ - wxTextOutputStream s(str); - - s << m_value; - - return true; -} - -bool wxVariantDataChar::Read(wxInputStream& str) -{ - wxTextInputStream s(str); - - s >> m_value; - - return true; -} -#endif // wxUSE_STREAMS - -bool wxVariantDataChar::Read(wxString& str) -{ - m_value = str[size_t(0)]; - return true; -} - -wxVariant::wxVariant(wxChar val, const wxString& name) -{ - m_data = new wxVariantDataChar(val); - m_name = name; -} - -bool wxVariant::operator== (wxChar value) const -{ - wxChar thisValue; - if (!Convert(&thisValue)) - return false; - else - return (value == thisValue); -} - -bool wxVariant::operator!= (wxChar value) const -{ - return (!((*this) == value)); -} - -void wxVariant::operator= (wxChar value) -{ - if (GetType() == wxT("char") && - m_data->GetRefCount() == 1) - { - ((wxVariantDataChar*)GetData())->SetValue(value); - } - else - { - UnRef(); - m_data = new wxVariantDataChar(value); - } -} - -wxChar wxVariant::GetChar() const -{ - wxChar value; - if (Convert(& value)) - return value; - else - { - wxFAIL_MSG(wxT("Could not convert to a char")); - return 0; - } -} - -// ---------------------------------------------------------------------------- -// wxVariantDataString -// ---------------------------------------------------------------------------- - -class WXDLLIMPEXP_BASE wxVariantDataString: public wxVariantData -{ -DECLARE_DYNAMIC_CLASS(wxVariantDataString) -public: - wxVariantDataString() { } - wxVariantDataString(const wxString& value) { m_value = value; } - - inline wxString GetValue() const { return m_value; } - inline void SetValue(const wxString& value) { m_value = value; } - - virtual bool Eq(wxVariantData& data) const; -#if wxUSE_STD_IOSTREAM - virtual bool Write(wxSTD ostream& str) const; -#endif - virtual bool Read(wxString& str); - virtual bool Write(wxString& str) const; -#if wxUSE_STD_IOSTREAM - virtual bool Read(wxSTD istream& WXUNUSED(str)) { return false; } -#endif -#if wxUSE_STREAMS - virtual bool Read(wxInputStream& str); - virtual bool Write(wxOutputStream& str) const; -#endif // wxUSE_STREAMS - virtual wxString GetType() const { return wxT("string"); } - -protected: - wxString m_value; -}; - -bool wxVariantDataString::Eq(wxVariantData& data) const -{ - wxASSERT_MSG( (data.GetType() == wxT("string")), wxT("wxVariantDataString::Eq: argument mismatch") ); - - wxVariantDataString& otherData = (wxVariantDataString&) data; - - return (otherData.m_value == m_value); -} - -#if wxUSE_STD_IOSTREAM -bool wxVariantDataString::Write(wxSTD ostream& str) const -{ - str << (const char*) m_value.mb_str(); - return true; -} -#endif - -bool wxVariantDataString::Write(wxString& str) const -{ - str = m_value; - return true; -} - -#if wxUSE_STREAMS -bool wxVariantDataString::Write(wxOutputStream& str) const -{ - // why doesn't wxOutputStream::operator<< take "const wxString&" - wxTextOutputStream s(str); - s.WriteString(m_value); - return true; -} - -bool wxVariantDataString::Read(wxInputStream& str) -{ - wxTextInputStream s(str); - - m_value = s.ReadLine(); - return true; -} -#endif // wxUSE_STREAMS - -bool wxVariantDataString::Read(wxString& str) -{ - m_value = str; - return true; -} - -IMPLEMENT_DYNAMIC_CLASS(wxVariantDataString, wxVariantData) - -// wxVariant **** - -wxVariant::wxVariant(const wxString& val, const wxString& name) -{ - m_data = new wxVariantDataString(val); - m_name = name; -} - -wxVariant::wxVariant(const wxChar* val, const wxString& name) -{ - m_data = new wxVariantDataString(wxString(val)); - m_name = name; -} - -bool wxVariant::operator== (const wxString& value) const -{ - wxString thisValue; - if (!Convert(&thisValue)) - return false; - - return value == thisValue; -} - -bool wxVariant::operator!= (const wxString& value) const -{ - return (!((*this) == value)); -} - -void wxVariant::operator= (const wxString& value) -{ - if (GetType() == wxT("string") && - m_data->GetRefCount() == 1) - { - ((wxVariantDataString*)GetData())->SetValue(value); - } - else - { - UnRef(); - m_data = new wxVariantDataString(value); - } -} - -void wxVariant::operator= (const wxChar* value) -{ - if (GetType() == wxT("string") && - m_data->GetRefCount() == 1) - { - ((wxVariantDataString*)GetData())->SetValue(wxString(value)); - } - else - { - UnRef(); - m_data = new wxVariantDataString(wxString(value)); - } -} - -wxString wxVariant::GetString() const -{ - wxString value; - if (!Convert(& value)) - { - wxFAIL_MSG(wxT("Could not convert to a string")); - } - - return value; -} - -// ---------------------------------------------------------------------------- -// wxVariantDataWxObjectPtr -// ---------------------------------------------------------------------------- - -class wxVariantDataWxObjectPtr: public wxVariantData -{ -DECLARE_DYNAMIC_CLASS(wxVariantDataWxObjectPtr) -public: - wxVariantDataWxObjectPtr() { } - wxVariantDataWxObjectPtr(wxObject* value) { m_value = value; } - - inline wxObject* GetValue() const { return m_value; } - inline void SetValue(wxObject* value) { m_value = value; } - - virtual bool Eq(wxVariantData& data) const; -#if wxUSE_STD_IOSTREAM - virtual bool Write(wxSTD ostream& str) const; -#endif - virtual bool Write(wxString& str) const; -#if wxUSE_STD_IOSTREAM - virtual bool Read(wxSTD istream& str); -#endif - virtual bool Read(wxString& str); - virtual wxString GetType() const ; - virtual wxVariantData* Clone() { return new wxVariantDataWxObjectPtr; } - - virtual wxClassInfo* GetValueClassInfo() ; -protected: - wxObject* m_value; - - DECLARE_NO_COPY_CLASS(wxVariantDataWxObjectPtr) -}; - -IMPLEMENT_DYNAMIC_CLASS(wxVariantDataWxObjectPtr, wxVariantData) - -bool wxVariantDataWxObjectPtr::Eq(wxVariantData& data) const -{ - wxASSERT_MSG( wxIsKindOf((&data), wxVariantDataWxObjectPtr), wxT("wxVariantDataWxObjectPtr::Eq: argument mismatch") ); - - wxVariantDataWxObjectPtr& otherData = (wxVariantDataWxObjectPtr&) data; - - return (otherData.m_value == m_value); -} - -wxString wxVariantDataWxObjectPtr::GetType() const -{ - wxString returnVal(wxT("wxObject")); - if (m_value) { - returnVal = m_value->GetClassInfo()->GetClassName(); - } - return returnVal; -} - -wxClassInfo* wxVariantDataWxObjectPtr::GetValueClassInfo() -{ - wxClassInfo* returnVal=NULL; - - if (m_value) returnVal = m_value->GetClassInfo(); - - return returnVal; -} - -#if wxUSE_STD_IOSTREAM -bool wxVariantDataWxObjectPtr::Write(wxSTD ostream& str) const -{ - wxString s; - Write(s); - str << (const char*) s.mb_str(); - return true; -} -#endif - -bool wxVariantDataWxObjectPtr::Write(wxString& str) const -{ - str.Printf(wxT("%s(%p)"), GetType().c_str(), wx_static_cast(void*, m_value)); - return true; -} - -#if wxUSE_STD_IOSTREAM -bool wxVariantDataWxObjectPtr::Read(wxSTD istream& WXUNUSED(str)) -{ - // Not implemented - return false; -} -#endif - -bool wxVariantDataWxObjectPtr::Read(wxString& WXUNUSED(str)) -{ - // Not implemented - return false; -} - -// wxVariant - -wxVariant::wxVariant( wxObject* val, const wxString& name) -{ - m_data = new wxVariantDataWxObjectPtr(val); - m_name = name; -} - -bool wxVariant::operator== (wxObject* value) const -{ - return (value == ((wxVariantDataWxObjectPtr*)GetData())->GetValue()); -} - -bool wxVariant::operator!= (wxObject* value) const -{ - return (!((*this) == (wxObject*) value)); -} - -void wxVariant::operator= (wxObject* value) -{ - UnRef(); - m_data = new wxVariantDataWxObjectPtr(value); -} - -wxObject* wxVariant::GetWxObjectPtr() const -{ - wxASSERT(wxIsKindOf(GetData(), wxVariantDataWxObjectPtr)); - return (wxObject*) ((wxVariantDataWxObjectPtr*) m_data)->GetValue(); -} - -// ---------------------------------------------------------------------------- -// wxVariantDataVoidPtr -// ---------------------------------------------------------------------------- - -class wxVariantDataVoidPtr: public wxVariantData -{ -DECLARE_DYNAMIC_CLASS(wxVariantDataVoidPtr) -public: - wxVariantDataVoidPtr() { } - wxVariantDataVoidPtr(void* value) { m_value = value; } - - inline void* GetValue() const { return m_value; } - inline void SetValue(void* value) { m_value = value; } - - virtual bool Eq(wxVariantData& data) const; -#if wxUSE_STD_IOSTREAM - virtual bool Write(wxSTD ostream& str) const; -#endif - virtual bool Write(wxString& str) const; -#if wxUSE_STD_IOSTREAM - virtual bool Read(wxSTD istream& str); -#endif - virtual bool Read(wxString& str); - virtual wxString GetType() const { return wxT("void*"); } - virtual wxVariantData* Clone() { return new wxVariantDataVoidPtr; } - -protected: - void* m_value; - - DECLARE_NO_COPY_CLASS(wxVariantDataVoidPtr) -}; - -IMPLEMENT_DYNAMIC_CLASS(wxVariantDataVoidPtr, wxVariantData) - -bool wxVariantDataVoidPtr::Eq(wxVariantData& data) const -{ - wxASSERT_MSG( (data.GetType() == wxT("void*")), wxT("wxVariantDataVoidPtr::Eq: argument mismatch") ); - - wxVariantDataVoidPtr& otherData = (wxVariantDataVoidPtr&) data; - - return (otherData.m_value == m_value); -} - -#if wxUSE_STD_IOSTREAM -bool wxVariantDataVoidPtr::Write(wxSTD ostream& str) const -{ - wxString s; - Write(s); - str << (const char*) s.mb_str(); - return true; -} -#endif - -bool wxVariantDataVoidPtr::Write(wxString& str) const -{ - str.Printf(wxT("%p"), m_value); - return true; -} - -#if wxUSE_STD_IOSTREAM -bool wxVariantDataVoidPtr::Read(wxSTD istream& WXUNUSED(str)) -{ - // Not implemented - return false; -} -#endif - -bool wxVariantDataVoidPtr::Read(wxString& WXUNUSED(str)) -{ - // Not implemented - return false; -} - -// wxVariant - -wxVariant::wxVariant( void* val, const wxString& name) -{ - m_data = new wxVariantDataVoidPtr(val); - m_name = name; -} - -bool wxVariant::operator== (void* value) const -{ - return (value == ((wxVariantDataVoidPtr*)GetData())->GetValue()); -} - -bool wxVariant::operator!= (void* value) const -{ - return (!((*this) == (void*) value)); -} - -void wxVariant::operator= (void* value) -{ - if (GetType() == wxT("void*") && - m_data->GetRefCount() == 1) - { - ((wxVariantDataVoidPtr*)GetData())->SetValue(value); - } - else - { - UnRef(); - m_data = new wxVariantDataVoidPtr(value); - } -} - -void* wxVariant::GetVoidPtr() const -{ - wxASSERT( (GetType() == wxT("void*")) ); - - return (void*) ((wxVariantDataVoidPtr*) m_data)->GetValue(); -} - -// ---------------------------------------------------------------------------- -// wxVariantDataDateTime -// ---------------------------------------------------------------------------- - -#if wxUSE_DATETIME - -class wxVariantDataDateTime: public wxVariantData -{ - DECLARE_DYNAMIC_CLASS(wxVariantDataDateTime) - -public: - wxVariantDataDateTime() { } - wxVariantDataDateTime(const wxDateTime& value) { m_value = value; } -#if wxUSE_ODBC - wxVariantDataDateTime(const TIME_STRUCT* valptr) - { m_value = wxDateTime(valptr->hour, valptr->minute, valptr->second); } - wxVariantDataDateTime(const DATE_STRUCT* valptr) - { m_value = wxDateTime(valptr->day, (wxDateTime::Month) (valptr->month - 1),valptr->year); } - wxVariantDataDateTime(const TIMESTAMP_STRUCT* valptr) - { m_value = wxDateTime(valptr->day, (wxDateTime::Month) (valptr->month - 1), valptr->year, - valptr->hour, valptr->minute, valptr->second, (wxDateTime::wxDateTime_t)valptr->fraction ); } -#endif //ODBC - - inline wxDateTime GetValue() const { return m_value; } - inline void SetValue(const wxDateTime& value) { m_value = value; } - - virtual bool Eq(wxVariantData& data) const; -#if wxUSE_STD_IOSTREAM - virtual bool Write(wxSTD ostream& str) const; -#endif - virtual bool Write(wxString& str) const; -#if wxUSE_STD_IOSTREAM - virtual bool Read(wxSTD istream& str); -#endif - virtual bool Read(wxString& str); - virtual wxString GetType() const { return wxT("datetime"); } - virtual wxVariantData* Clone() { return new wxVariantDataDateTime; } - -protected: - wxDateTime m_value; -}; - - -IMPLEMENT_DYNAMIC_CLASS(wxVariantDataDateTime, wxVariantData) - -bool wxVariantDataDateTime::Eq(wxVariantData& data) const -{ - wxASSERT_MSG( (data.GetType() == wxT("datetime")), wxT("wxVariantDataDateTime::Eq: argument mismatch") ); - - wxVariantDataDateTime& otherData = (wxVariantDataDateTime&) data; - - return (otherData.m_value == m_value); -} - - -#if wxUSE_STD_IOSTREAM -bool wxVariantDataDateTime::Write(wxSTD ostream& str) const -{ - wxString value; - Write( value ); - str << value.c_str(); - return true; -} -#endif - - -bool wxVariantDataDateTime::Write(wxString& str) const -{ - str = m_value.Format(); - return true; -} - - -#if wxUSE_STD_IOSTREAM -bool wxVariantDataDateTime::Read(wxSTD istream& WXUNUSED(str)) -{ - // Not implemented - return false; -} -#endif - - -bool wxVariantDataDateTime::Read(wxString& str) -{ - if(! m_value.ParseDateTime(str)) - return false; - return true; -} - -// wxVariant - -wxVariant::wxVariant(const wxDateTime& val, const wxString& name) // Date -{ - m_data = new wxVariantDataDateTime(val); - m_name = name; -} - -#if wxUSE_ODBC -wxVariant::wxVariant(const TIME_STRUCT* valptr, const wxString& name) // Date -{ - m_data = new wxVariantDataDateTime(valptr); - m_name = name; -} - -wxVariant::wxVariant(const TIMESTAMP_STRUCT* valptr, const wxString& name) // Date -{ - m_data = new wxVariantDataDateTime(valptr); - m_name = name; -} - -wxVariant::wxVariant(const DATE_STRUCT* valptr, const wxString& name) // Date -{ - m_data = new wxVariantDataDateTime(valptr); - m_name = name; -} -#endif // wxUSE_ODBC - -bool wxVariant::operator== (const wxDateTime& value) const -{ - wxDateTime thisValue; - if (!Convert(&thisValue)) - return false; - - return value.IsEqualTo(thisValue); -} - -bool wxVariant::operator!= (const wxDateTime& value) const -{ - return (!((*this) == value)); -} - -void wxVariant::operator= (const wxDateTime& value) -{ - if (GetType() == wxT("datetime") && - m_data->GetRefCount() == 1) - { - ((wxVariantDataDateTime*)GetData())->SetValue(value); - } - else - { - UnRef(); - m_data = new wxVariantDataDateTime(value); - } -} - -#if wxUSE_ODBC -void wxVariant::operator= (const DATE_STRUCT* value) -{ - UnRef(); - m_data = new wxVariantDataDateTime(value); -} - -void wxVariant::operator= (const TIME_STRUCT* value) -{ - UnRef(); - m_data = new wxVariantDataDateTime(value); -} - -void wxVariant::operator= (const TIMESTAMP_STRUCT* value) -{ - UnRef(); - m_data = new wxVariantDataDateTime(value); -} - -#endif // wxUSE_ODBC - -wxDateTime wxVariant::GetDateTime() const -{ - wxDateTime value; - if (!Convert(& value)) - { - wxFAIL_MSG(wxT("Could not convert to a datetime")); - } - - return value; -} - -#endif // wxUSE_DATETIME - -// ---------------------------------------------------------------------------- -// wxVariantDataArrayString -// ---------------------------------------------------------------------------- - -class wxVariantDataArrayString: public wxVariantData -{ -public: - wxVariantDataArrayString() { } - wxVariantDataArrayString(const wxArrayString& value) { m_value = value; } - - wxArrayString GetValue() const { return m_value; } - void SetValue(const wxArrayString& value) { m_value = value; } - - virtual bool Eq(wxVariantData& data) const; -#if wxUSE_STD_IOSTREAM - virtual bool Write(wxSTD ostream& str) const; -#endif - virtual bool Write(wxString& str) const; -#if wxUSE_STD_IOSTREAM - virtual bool Read(wxSTD istream& str); -#endif - virtual bool Read(wxString& str); - virtual wxString GetType() const { return wxT("arrstring"); } - virtual wxVariantData* Clone() { return new wxVariantDataArrayString; } - -protected: - wxArrayString m_value; - - DECLARE_DYNAMIC_CLASS(wxVariantDataArrayString) -}; - -IMPLEMENT_DYNAMIC_CLASS(wxVariantDataArrayString, wxVariantData) - -bool wxVariantDataArrayString::Eq(wxVariantData& data) const -{ - wxASSERT_MSG( data.GetType() == GetType(), wxT("wxVariantDataArrayString::Eq: argument mismatch") ); - - wxVariantDataArrayString& otherData = (wxVariantDataArrayString&) data; - - return otherData.m_value == m_value; -} - -#if wxUSE_STD_IOSTREAM -bool wxVariantDataArrayString::Write(wxSTD ostream& WXUNUSED(str)) const -{ - // Not implemented - return false; -} -#endif - -bool wxVariantDataArrayString::Write(wxString& str) const -{ - size_t count = m_value.GetCount(); - for ( size_t n = 0; n < count; n++ ) - { - if ( n ) - str += _T(';'); - - str += m_value[n]; - } - - return true; -} - - -#if wxUSE_STD_IOSTREAM -bool wxVariantDataArrayString::Read(wxSTD istream& WXUNUSED(str)) -{ - // Not implemented - return false; -} -#endif - - -bool wxVariantDataArrayString::Read(wxString& str) -{ - wxStringTokenizer tk(str, _T(";")); - while ( tk.HasMoreTokens() ) - { - m_value.Add(tk.GetNextToken()); - } - - return true; -} - -// wxVariant - -wxVariant::wxVariant(const wxArrayString& val, const wxString& name) // Strings -{ - m_data = new wxVariantDataArrayString(val); - m_name = name; -} - -bool wxVariant::operator==(const wxArrayString& WXUNUSED(value)) const -{ - wxFAIL_MSG( _T("TODO") ); - - return false; -} - -bool wxVariant::operator!=(const wxArrayString& value) const -{ - return !(*this == value); -} - -void wxVariant::operator=(const wxArrayString& value) -{ - if (GetType() == wxT("arrstring") && - m_data->GetRefCount() == 1) - { - ((wxVariantDataArrayString *)GetData())->SetValue(value); - } - else - { - UnRef(); - m_data = new wxVariantDataArrayString(value); - } -} - -wxArrayString wxVariant::GetArrayString() const -{ - if ( GetType() == wxT("arrstring") ) - return ((wxVariantDataArrayString *)GetData())->GetValue(); - - return wxArrayString(); -} - -// ---------------------------------------------------------------------------- -// wxVariantDataList -// ---------------------------------------------------------------------------- - -class WXDLLIMPEXP_BASE wxVariantDataList: public wxVariantData -{ -DECLARE_DYNAMIC_CLASS(wxVariantDataList) -public: - wxVariantDataList() {} - wxVariantDataList(const wxList& list); - virtual ~wxVariantDataList(); - - wxList& GetValue() { return m_value; } - void SetValue(const wxList& value) ; - - virtual bool Eq(wxVariantData& data) const; -#if wxUSE_STD_IOSTREAM - virtual bool Write(wxSTD ostream& str) const; -#endif - virtual bool Write(wxString& str) const; -#if wxUSE_STD_IOSTREAM - virtual bool Read(wxSTD istream& str); -#endif - virtual bool Read(wxString& str); - virtual wxString GetType() const { return wxT("list"); } - - void Clear(); - -protected: - wxList m_value; -}; - -IMPLEMENT_DYNAMIC_CLASS(wxVariantDataList, wxVariantData) - -wxVariantDataList::wxVariantDataList(const wxList& list) -{ - SetValue(list); -} - -wxVariantDataList::~wxVariantDataList() -{ - Clear(); -} - -void wxVariantDataList::SetValue(const wxList& value) -{ - Clear(); - wxList::compatibility_iterator node = value.GetFirst(); - while (node) - { - wxVariant* var = (wxVariant*) node->GetData(); - m_value.Append(new wxVariant(*var)); - node = node->GetNext(); - } -} - -void wxVariantDataList::Clear() -{ - wxList::compatibility_iterator node = m_value.GetFirst(); - while (node) - { - wxVariant* var = (wxVariant*) node->GetData(); - delete var; - node = node->GetNext(); - } - m_value.Clear(); -} - -bool wxVariantDataList::Eq(wxVariantData& data) const -{ - wxASSERT_MSG( (data.GetType() == wxT("list")), wxT("wxVariantDataList::Eq: argument mismatch") ); - - wxVariantDataList& listData = (wxVariantDataList&) data; - wxList::compatibility_iterator node1 = m_value.GetFirst(); - wxList::compatibility_iterator node2 = listData.GetValue().GetFirst(); - while (node1 && node2) - { - wxVariant* var1 = (wxVariant*) node1->GetData(); - wxVariant* var2 = (wxVariant*) node2->GetData(); - if ((*var1) != (*var2)) - return false; - node1 = node1->GetNext(); - node2 = node2->GetNext(); - } - if (node1 || node2) return false; - return true; -} - -#if wxUSE_STD_IOSTREAM -bool wxVariantDataList::Write(wxSTD ostream& str) const -{ - wxString s; - Write(s); - str << (const char*) s.mb_str(); - return true; -} -#endif - -bool wxVariantDataList::Write(wxString& str) const -{ - str = wxEmptyString; - wxList::compatibility_iterator node = m_value.GetFirst(); - while (node) - { - wxVariant* var = (wxVariant*) node->GetData(); - if (node != m_value.GetFirst()) - str += wxT(" "); - wxString str1; - str += var->MakeString(); - node = node->GetNext(); - } - - return true; -} - -#if wxUSE_STD_IOSTREAM -bool wxVariantDataList::Read(wxSTD istream& WXUNUSED(str)) -{ - wxFAIL_MSG(wxT("Unimplemented")); - // TODO - return false; -} -#endif - -bool wxVariantDataList::Read(wxString& WXUNUSED(str)) -{ - wxFAIL_MSG(wxT("Unimplemented")); - // TODO - return false; -} - -// wxVariant - -wxVariant::wxVariant(const wxList& val, const wxString& name) // List of variants -{ - m_data = new wxVariantDataList(val); - m_name = name; -} - -bool wxVariant::operator== (const wxList& value) const -{ - wxASSERT_MSG( (GetType() == wxT("list")), wxT("Invalid type for == operator") ); - - wxVariantDataList other(value); - return (GetData()->Eq(other)); -} - -bool wxVariant::operator!= (const wxList& value) const -{ - return (!((*this) == value)); -} - -void wxVariant::operator= (const wxList& value) -{ - if (GetType() == wxT("list") && - m_data->GetRefCount() == 1) - { - ((wxVariantDataList*)GetData())->SetValue(value); - } - else - { - UnRef(); - m_data = new wxVariantDataList(value); - } -} - -wxList& wxVariant::GetList() const -{ - wxASSERT( (GetType() == wxT("list")) ); - - return (wxList&) ((wxVariantDataList*) m_data)->GetValue(); -} - -// Make empty list -void wxVariant::NullList() -{ - SetData(new wxVariantDataList()); -} - -// Append to list -void wxVariant::Append(const wxVariant& value) -{ - wxList& list = GetList(); - - list.Append(new wxVariant(value)); -} - -// Insert at front of list -void wxVariant::Insert(const wxVariant& value) -{ - wxList& list = GetList(); - - list.Insert(new wxVariant(value)); -} - -// Returns true if the variant is a member of the list -bool wxVariant::Member(const wxVariant& value) const -{ - wxList& list = GetList(); - - wxList::compatibility_iterator node = list.GetFirst(); - while (node) - { - wxVariant* other = (wxVariant*) node->GetData(); - if (value == *other) - return true; - node = node->GetNext(); - } - return false; -} - -// Deletes the nth element of the list -bool wxVariant::Delete(size_t item) -{ - wxList& list = GetList(); - - wxASSERT_MSG( (item < list.GetCount()), wxT("Invalid index to Delete") ); - wxList::compatibility_iterator node = list.Item(item); - wxVariant* variant = (wxVariant*) node->GetData(); - delete variant; - list.Erase(node); - return true; -} - -// Clear list -void wxVariant::ClearList() -{ - if (!IsNull() && (GetType() == wxT("list"))) - { - ((wxVariantDataList*) m_data)->Clear(); - } - else - { - if (!GetType().IsSameAs(wxT("list"))) - UnRef(); - - m_data = new wxVariantDataList; - } -} - -#if WXWIN_COMPATIBILITY_2_4 - -// ---------------------------------------------------------------------------- -// wxVariantDataStringList -// ---------------------------------------------------------------------------- - -class WXDLLIMPEXP_BASE wxVariantDataStringList: public wxVariantData -{ -DECLARE_DYNAMIC_CLASS(wxVariantDataStringList) -public: - wxVariantDataStringList() {} - wxVariantDataStringList(const wxStringList& list) { m_value = list; } - - wxStringList& GetValue() const { return (wxStringList&) m_value; } - void SetValue(const wxStringList& value); - - virtual bool Eq(wxVariantData& data) const; -#if wxUSE_STD_IOSTREAM - virtual bool Write(wxSTD ostream& str) const; -#endif - virtual bool Write(wxString& str) const; -#if wxUSE_STD_IOSTREAM - virtual bool Read(wxSTD istream& str); -#endif - virtual bool Read(wxString& str); - virtual wxString GetType() const { return wxT("stringlist"); }; - -protected: - wxStringList m_value; -}; - -IMPLEMENT_DYNAMIC_CLASS(wxVariantDataStringList, wxVariantData) - -void wxVariantDataStringList::SetValue(const wxStringList& value) -{ - m_value = value; -} - -bool wxVariantDataStringList::Eq(wxVariantData& data) const -{ - wxASSERT_MSG( (data.GetType() == wxT("stringlist")), wxT("wxVariantDataStringList::Eq: argument mismatch") ); - - wxVariantDataStringList& listData = (wxVariantDataStringList&) data; - wxStringList::compatibility_iterator node1 = m_value.GetFirst(); - wxStringList::compatibility_iterator node2 = listData.GetValue().GetFirst(); - while (node1 && node2) - { - wxString str1 ( node1->GetData() ); - wxString str2 ( node2->GetData() ); - if (str1 != str2) - return false; - node1 = node1->GetNext(); - node2 = node2->GetNext(); - } - if (node1 || node2) return false; - return true; -} - -#if wxUSE_STD_IOSTREAM -bool wxVariantDataStringList::Write(wxSTD ostream& str) const -{ - wxString s; - Write(s); - str << (const char*) s.mb_str(); - return true; -} -#endif - -bool wxVariantDataStringList::Write(wxString& str) const -{ - str.Empty(); - wxStringList::compatibility_iterator node = m_value.GetFirst(); - while (node) - { - const wxChar* s = node->GetData(); - if (node != m_value.GetFirst()) - str += wxT(" "); - str += s; - node = node->GetNext(); - } - - return true; -} - -#if wxUSE_STD_IOSTREAM -bool wxVariantDataStringList::Read(wxSTD istream& WXUNUSED(str)) -{ - wxFAIL_MSG(wxT("Unimplemented")); - // TODO - return false; -} -#endif - -bool wxVariantDataStringList::Read(wxString& WXUNUSED(str)) -{ - wxFAIL_MSG(wxT("Unimplemented")); - // TODO - return false; -} - -#endif //2.4 compat - -#if WXWIN_COMPATIBILITY_2_4 - -wxVariant::wxVariant(const wxStringList& val, const wxString& name) -{ - m_data = new wxVariantDataStringList(val); - m_name = name; -} - -bool wxVariant::operator== (const wxStringList& value) const -{ - wxASSERT_MSG( (GetType() == wxT("stringlist")), wxT("Invalid type for == operator") ); - - wxVariantDataStringList other(value); - return (GetData()->Eq(other)); -} - -bool wxVariant::operator!= (const wxStringList& value) const -{ - wxASSERT_MSG( (GetType() == wxT("stringlist")), wxT("Invalid type for == operator") ); - - wxVariantDataStringList other(value); - return !(GetData()->Eq(other)); -} - -void wxVariant::operator= (const wxStringList& value) -{ - if (GetType() == wxT("stringlist") && - m_data->GetRefCount() == 1) - { - ((wxVariantDataStringList*)GetData())->SetValue(value); - } - else - { - UnRef(); - m_data = new wxVariantDataStringList(value); - } -} - -// wxVariant - -wxStringList& wxVariant::GetStringList() const -{ - wxASSERT( (GetType() == wxT("stringlist")) ); - - return (wxStringList&) ((wxVariantDataStringList*) m_data)->GetValue(); -} - -#endif - -// Treat a list variant as an array -wxVariant wxVariant::operator[] (size_t idx) const -{ -#if WXWIN_COMPATIBILITY_2_4 - wxASSERT_MSG( (GetType() == wxT("list") || GetType() == wxT("stringlist")), wxT("Invalid type for array operator") ); -#else - wxASSERT_MSG( GetType() == wxT("list"), wxT("Invalid type for array operator") ); -#endif - - if (GetType() == wxT("list")) - { - wxVariantDataList* data = (wxVariantDataList*) m_data; - wxASSERT_MSG( (idx < data->GetValue().GetCount()), wxT("Invalid index for array") ); - return * (wxVariant*) (data->GetValue().Item(idx)->GetData()); - } -#if WXWIN_COMPATIBILITY_2_4 - else if (GetType() == wxT("stringlist")) - { - wxVariantDataStringList* data = (wxVariantDataStringList*) m_data; - wxASSERT_MSG( (idx < data->GetValue().GetCount()), wxT("Invalid index for array") ); - - wxString str( (const wxChar*) (data->GetValue().Item(idx)->GetData()) ); - wxVariant variant( str ); - return variant; - } -#endif - return wxNullVariant; -} - -wxVariant& wxVariant::operator[] (size_t idx) -{ - // We can't return a reference to a variant for a string list, since the string - // is actually stored as a char*, not a variant. - - wxASSERT_MSG( (GetType() == wxT("list")), wxT("Invalid type for array operator") ); - - wxVariantDataList* data = (wxVariantDataList*) m_data; - wxASSERT_MSG( (idx < data->GetValue().GetCount()), wxT("Invalid index for array") ); - - return * (wxVariant*) (data->GetValue().Item(idx)->GetData()); -} - -// Return the number of elements in a list -size_t wxVariant::GetCount() const -{ -#if WXWIN_COMPATIBILITY_2_4 - wxASSERT_MSG( (GetType() == wxT("list") || GetType() == wxT("stringlist")), wxT("Invalid type for GetCount()") ); -#else - wxASSERT_MSG( GetType() == wxT("list"), wxT("Invalid type for GetCount()") ); -#endif - - if (GetType() == wxT("list")) - { - wxVariantDataList* data = (wxVariantDataList*) m_data; - return data->GetValue().GetCount(); - } -#if WXWIN_COMPATIBILITY_2_4 - else if (GetType() == wxT("stringlist")) - { - wxVariantDataStringList* data = (wxVariantDataStringList*) m_data; - return data->GetValue().GetCount(); - } -#endif - return 0; -} - -// ---------------------------------------------------------------------------- -// Type conversion -// ---------------------------------------------------------------------------- - -bool wxVariant::Convert(long* value) const -{ - wxString type(GetType()); - if (type == wxT("double")) - *value = (long) (((wxVariantDoubleData*)GetData())->GetValue()); - else if (type == wxT("long")) - *value = ((wxVariantDataLong*)GetData())->GetValue(); -#ifdef HAVE_BOOL - else if (type == wxT("bool")) - *value = (long) (((wxVariantDataBool*)GetData())->GetValue()); -#endif - else if (type == wxT("string")) - *value = wxAtol((const wxChar*) ((wxVariantDataString*)GetData())->GetValue()); - else - return false; - - return true; -} - -bool wxVariant::Convert(bool* value) const -{ - wxString type(GetType()); - if (type == wxT("double")) - *value = ((int) (((wxVariantDoubleData*)GetData())->GetValue()) != 0); - else if (type == wxT("long")) - *value = (((wxVariantDataLong*)GetData())->GetValue() != 0); -#ifdef HAVE_BOOL - else if (type == wxT("bool")) - *value = ((wxVariantDataBool*)GetData())->GetValue(); -#endif - else if (type == wxT("string")) - { - wxString val(((wxVariantDataString*)GetData())->GetValue()); - val.MakeLower(); - if (val == wxT("true") || val == wxT("yes") || val == wxT('1') ) - *value = true; - else if (val == wxT("false") || val == wxT("no") || val == wxT('0') ) - *value = false; - else - return false; - } - else - return false; - - return true; -} - -bool wxVariant::Convert(double* value) const -{ - wxString type(GetType()); - if (type == wxT("double")) - *value = ((wxVariantDoubleData*)GetData())->GetValue(); - else if (type == wxT("long")) - *value = (double) (((wxVariantDataLong*)GetData())->GetValue()); -#ifdef HAVE_BOOL - else if (type == wxT("bool")) - *value = (double) (((wxVariantDataBool*)GetData())->GetValue()); -#endif - else if (type == wxT("string")) - *value = (double) wxAtof((const wxChar*) ((wxVariantDataString*)GetData())->GetValue()); - else - return false; - - return true; -} - -bool wxVariant::Convert(wxChar* value) const -{ - wxString type(GetType()); - if (type == wxT("char")) - *value = ((wxVariantDataChar*)GetData())->GetValue(); - else if (type == wxT("long")) - *value = (char) (((wxVariantDataLong*)GetData())->GetValue()); -#ifdef HAVE_BOOL - else if (type == wxT("bool")) - *value = (char) (((wxVariantDataBool*)GetData())->GetValue()); -#endif - else - return false; - - return true; -} - -bool wxVariant::Convert(wxString* value) const -{ - *value = MakeString(); - return true; -} - -#if wxUSE_DATETIME -bool wxVariant::Convert(wxDateTime* value) const -{ - wxString type(GetType()); - if (type == wxT("datetime")) - { - *value = ((wxVariantDataDateTime*)GetData())->GetValue(); - return true; - } - // Fallback to string conversion - wxString val; - return Convert(&val) && - (value->ParseDateTime(val) || value->ParseDate(val) || value->ParseTime(val)); -} -#endif // wxUSE_DATETIME - -#endif // wxUSE_VARIANT +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/variant.cpp +// Purpose: wxVariant class, container for any type +// Author: Julian Smart +// Modified by: +// Created: 10/09/98 +// RCS-ID: $Id: variant.cpp 45498 2007-04-16 13:03:05Z VZ $ +// Copyright: (c) +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx/wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#include "wx/variant.h" + +#if wxUSE_VARIANT + +#ifndef WX_PRECOMP + #include "wx/string.h" + #include "wx/math.h" + #if wxUSE_STREAMS + #include "wx/stream.h" + #endif +#endif + +#if wxUSE_STD_IOSTREAM + #if wxUSE_IOSTREAMH + #include + #else + #include + #endif +#endif + +#if defined(__MWERKS__) && __MSL__ >= 0x6000 +namespace std {} +using namespace std ; +#endif + +#if wxUSE_STREAMS + #include "wx/txtstrm.h" +#endif + +#include "wx/string.h" +#include "wx/tokenzr.h" + +IMPLEMENT_ABSTRACT_CLASS(wxVariantData, wxObject) + +wxVariant WXDLLIMPEXP_BASE wxNullVariant; + + +/* + * wxVariant + */ + +IMPLEMENT_DYNAMIC_CLASS(wxVariant, wxObject) + +wxVariant::wxVariant() +{ + m_data = (wxVariantData*) NULL; +} + +bool wxVariant::IsNull() const +{ + return (m_data == (wxVariantData*) NULL); +} + +void wxVariant::MakeNull() +{ + UnRef(); +} + +void wxVariant::Clear() +{ + m_name = wxEmptyString; +} + +wxVariant::wxVariant(const wxVariant& variant) + : wxObject() +{ + m_data = (wxVariantData*) NULL; + + if (!variant.IsNull()) + Ref(variant); + + m_name = variant.m_name; +} + +wxVariant::wxVariant(wxVariantData* data, const wxString& name) // User-defined data +{ + m_data = data; + m_name = name; +} + +wxVariant::~wxVariant() +{ + UnRef(); +} + +// Assignment +void wxVariant::operator= (const wxVariant& variant) +{ + Ref(variant); + m_name = variant.m_name; +} + +// myVariant = new wxStringVariantData("hello") +void wxVariant::operator= (wxVariantData* variantData) +{ + UnRef(); + m_data = variantData; +} + +bool wxVariant::operator== (const wxVariant& variant) const +{ + if (IsNull() || variant.IsNull()) + return (IsNull() == variant.IsNull()); + + return (GetData()->Eq(* variant.GetData())); +} + +bool wxVariant::operator!= (const wxVariant& variant) const +{ + return (!(*this == variant)); +} + + +wxString wxVariant::MakeString() const +{ + if (!IsNull()) + { + wxString str; + if (GetData()->Write(str)) + return str; + } + return wxEmptyString; +} + +void wxVariant::SetData(wxVariantData* data) +{ + UnRef(); + m_data = data; +} + +void wxVariant::Ref(const wxVariant& clone) +{ + // nothing to be done + if (m_data == clone.m_data) + return; + + // delete reference to old data + UnRef(); + + // reference new data + if ( clone.m_data ) + { + m_data = clone.m_data; + m_data->m_count++; + } +} + + +void wxVariant::UnRef() +{ + if ( m_data ) + { + wxASSERT_MSG( m_data->m_count > 0, _T("invalid ref data count") ); + + m_data->DecRef(); + m_data = NULL; + } +} + + +// Returns a string representing the type of the variant, +// e.g. "string", "bool", "list", "double", "long" +wxString wxVariant::GetType() const +{ + if (IsNull()) + return wxString(wxT("null")); + else + return GetData()->GetType(); +} + + +bool wxVariant::IsType(const wxString& type) const +{ + return (GetType() == type); +} + +bool wxVariant::IsValueKindOf(const wxClassInfo* type) const +{ + wxClassInfo* info=GetData()->GetValueClassInfo(); + return info ? info->IsKindOf(type) : false ; +} + + +// ----------------------------------------------------------------- +// wxVariantDataLong +// ----------------------------------------------------------------- + +class WXDLLIMPEXP_BASE wxVariantDataLong: public wxVariantData +{ +DECLARE_DYNAMIC_CLASS(wxVariantDataLong) +public: + wxVariantDataLong() { m_value = 0; } + wxVariantDataLong(long value) { m_value = value; } + + inline long GetValue() const { return m_value; } + inline void SetValue(long value) { m_value = value; } + + virtual bool Eq(wxVariantData& data) const; + + virtual bool Read(wxString& str); + virtual bool Write(wxString& str) const; +#if wxUSE_STD_IOSTREAM + virtual bool Read(wxSTD istream& str); + virtual bool Write(wxSTD ostream& str) const; +#endif +#if wxUSE_STREAMS + virtual bool Read(wxInputStream& str); + virtual bool Write(wxOutputStream &str) const; +#endif // wxUSE_STREAMS + + virtual wxString GetType() const { return wxT("long"); } + +protected: + long m_value; +}; + +IMPLEMENT_DYNAMIC_CLASS(wxVariantDataLong, wxVariantData) + +bool wxVariantDataLong::Eq(wxVariantData& data) const +{ + wxASSERT_MSG( (data.GetType() == wxT("long")), wxT("wxVariantDataLong::Eq: argument mismatch") ); + + wxVariantDataLong& otherData = (wxVariantDataLong&) data; + + return (otherData.m_value == m_value); +} + +#if wxUSE_STD_IOSTREAM +bool wxVariantDataLong::Write(wxSTD ostream& str) const +{ + wxString s; + Write(s); + str << (const char*) s.mb_str(); + return true; +} +#endif + +bool wxVariantDataLong::Write(wxString& str) const +{ + str.Printf(wxT("%ld"), m_value); + return true; +} + +#if wxUSE_STD_IOSTREAM +bool wxVariantDataLong::Read(wxSTD istream& str) +{ + str >> m_value; + return true; +} +#endif + +#if wxUSE_STREAMS +bool wxVariantDataLong::Write(wxOutputStream& str) const +{ + wxTextOutputStream s(str); + + s.Write32((size_t)m_value); + return true; +} + +bool wxVariantDataLong::Read(wxInputStream& str) +{ + wxTextInputStream s(str); + m_value = s.Read32(); + return true; +} +#endif // wxUSE_STREAMS + +bool wxVariantDataLong::Read(wxString& str) +{ + m_value = wxAtol((const wxChar*) str); + return true; +} + +// wxVariant + +wxVariant::wxVariant(long val, const wxString& name) +{ + m_data = new wxVariantDataLong(val); + m_name = name; +} + +wxVariant::wxVariant(int val, const wxString& name) +{ + m_data = new wxVariantDataLong((long)val); + m_name = name; +} + +wxVariant::wxVariant(short val, const wxString& name) +{ + m_data = new wxVariantDataLong((long)val); + m_name = name; +} + +bool wxVariant::operator== (long value) const +{ + long thisValue; + if (!Convert(&thisValue)) + return false; + else + return (value == thisValue); +} + +bool wxVariant::operator!= (long value) const +{ + return (!((*this) == value)); +} + +void wxVariant::operator= (long value) +{ + if (GetType() == wxT("long") && + m_data->GetRefCount() == 1) + { + ((wxVariantDataLong*)GetData())->SetValue(value); + } + else + { + UnRef(); + m_data = new wxVariantDataLong(value); + } +} + +long wxVariant::GetLong() const +{ + long value; + if (Convert(& value)) + return value; + else + { + wxFAIL_MSG(wxT("Could not convert to a long")); + return 0; + } +} + +// ----------------------------------------------------------------- +// wxVariantDoubleData +// ----------------------------------------------------------------- + +class WXDLLIMPEXP_BASE wxVariantDoubleData: public wxVariantData +{ +DECLARE_DYNAMIC_CLASS(wxVariantDoubleData) +public: + wxVariantDoubleData() { m_value = 0.0; } + wxVariantDoubleData(double value) { m_value = value; } + + inline double GetValue() const { return m_value; } + inline void SetValue(double value) { m_value = value; } + + virtual bool Eq(wxVariantData& data) const; + virtual bool Read(wxString& str); +#if wxUSE_STD_IOSTREAM + virtual bool Write(wxSTD ostream& str) const; +#endif + virtual bool Write(wxString& str) const; +#if wxUSE_STD_IOSTREAM + virtual bool Read(wxSTD istream& str); +#endif +#if wxUSE_STREAMS + virtual bool Read(wxInputStream& str); + virtual bool Write(wxOutputStream &str) const; +#endif // wxUSE_STREAMS + virtual wxString GetType() const { return wxT("double"); } + +protected: + double m_value; +}; + +IMPLEMENT_DYNAMIC_CLASS(wxVariantDoubleData, wxVariantData) + +bool wxVariantDoubleData::Eq(wxVariantData& data) const +{ + wxASSERT_MSG( (data.GetType() == wxT("double")), wxT("wxVariantDoubleData::Eq: argument mismatch") ); + + wxVariantDoubleData& otherData = (wxVariantDoubleData&) data; + + return wxIsSameDouble(otherData.m_value, m_value); +} + +#if wxUSE_STD_IOSTREAM +bool wxVariantDoubleData::Write(wxSTD ostream& str) const +{ + wxString s; + Write(s); + str << (const char*) s.mb_str(); + return true; +} +#endif + +bool wxVariantDoubleData::Write(wxString& str) const +{ + str.Printf(wxT("%.14g"), m_value); + return true; +} + +#if wxUSE_STD_IOSTREAM +bool wxVariantDoubleData::Read(wxSTD istream& str) +{ + str >> m_value; + return true; +} +#endif + +#if wxUSE_STREAMS +bool wxVariantDoubleData::Write(wxOutputStream& str) const +{ + wxTextOutputStream s(str); + s.WriteDouble((double)m_value); + return true; +} + +bool wxVariantDoubleData::Read(wxInputStream& str) +{ + wxTextInputStream s(str); + m_value = (float)s.ReadDouble(); + return true; +} +#endif // wxUSE_STREAMS + +bool wxVariantDoubleData::Read(wxString& str) +{ + m_value = wxAtof((const wxChar*) str); + return true; +} + +// wxVariant double code + +wxVariant::wxVariant(double val, const wxString& name) +{ + m_data = new wxVariantDoubleData(val); + m_name = name; +} + +bool wxVariant::operator== (double value) const +{ + double thisValue; + if (!Convert(&thisValue)) + return false; + + return wxIsSameDouble(value, thisValue); +} + +bool wxVariant::operator!= (double value) const +{ + return (!((*this) == value)); +} + +void wxVariant::operator= (double value) +{ + if (GetType() == wxT("double") && + m_data->GetRefCount() == 1) + { + ((wxVariantDoubleData*)GetData())->SetValue(value); + } + else + { + UnRef(); + m_data = new wxVariantDoubleData(value); + } +} + +double wxVariant::GetDouble() const +{ + double value; + if (Convert(& value)) + return value; + else + { + wxFAIL_MSG(wxT("Could not convert to a double number")); + return 0.0; + } +} + +// ----------------------------------------------------------------- +// wxVariantBoolData +// ----------------------------------------------------------------- + +#ifdef HAVE_BOOL + +class WXDLLIMPEXP_BASE wxVariantDataBool: public wxVariantData +{ +DECLARE_DYNAMIC_CLASS(wxVariantDataBool) +public: + wxVariantDataBool() { m_value = 0; } + wxVariantDataBool(bool value) { m_value = value; } + + inline bool GetValue() const { return m_value; } + inline void SetValue(bool value) { m_value = value; } + + virtual bool Eq(wxVariantData& data) const; +#if wxUSE_STD_IOSTREAM + virtual bool Write(wxSTD ostream& str) const; +#endif + virtual bool Write(wxString& str) const; + virtual bool Read(wxString& str); +#if wxUSE_STD_IOSTREAM + virtual bool Read(wxSTD istream& str); +#endif +#if wxUSE_STREAMS + virtual bool Read(wxInputStream& str); + virtual bool Write(wxOutputStream& str) const; +#endif // wxUSE_STREAMS + virtual wxString GetType() const { return wxT("bool"); } + +protected: + bool m_value; +}; + +IMPLEMENT_DYNAMIC_CLASS(wxVariantDataBool, wxVariantData) + +bool wxVariantDataBool::Eq(wxVariantData& data) const +{ + wxASSERT_MSG( (data.GetType() == wxT("bool")), wxT("wxVariantDataBool::Eq: argument mismatch") ); + + wxVariantDataBool& otherData = (wxVariantDataBool&) data; + + return (otherData.m_value == m_value); +} + +#if wxUSE_STD_IOSTREAM +bool wxVariantDataBool::Write(wxSTD ostream& str) const +{ + wxString s; + Write(s); + str << (const char*) s.mb_str(); + return true; +} +#endif + +bool wxVariantDataBool::Write(wxString& str) const +{ + str.Printf(wxT("%d"), (int) m_value); + return true; +} + +#if wxUSE_STD_IOSTREAM +bool wxVariantDataBool::Read(wxSTD istream& WXUNUSED(str)) +{ + wxFAIL_MSG(wxT("Unimplemented")); +// str >> (long) m_value; + return false; +} +#endif + +#if wxUSE_STREAMS +bool wxVariantDataBool::Write(wxOutputStream& str) const +{ + wxTextOutputStream s(str); + + s.Write8(m_value); + return true; +} + +bool wxVariantDataBool::Read(wxInputStream& str) +{ + wxTextInputStream s(str); + + m_value = s.Read8() != 0; + return true; +} +#endif // wxUSE_STREAMS + +bool wxVariantDataBool::Read(wxString& str) +{ + m_value = (wxAtol((const wxChar*) str) != 0); + return true; +} + +// wxVariant **** + +wxVariant::wxVariant(bool val, const wxString& name) +{ + m_data = new wxVariantDataBool(val); + m_name = name; +} + +bool wxVariant::operator== (bool value) const +{ + bool thisValue; + if (!Convert(&thisValue)) + return false; + else + return (value == thisValue); +} + +bool wxVariant::operator!= (bool value) const +{ + return (!((*this) == value)); +} + +void wxVariant::operator= (bool value) +{ + if (GetType() == wxT("bool") && + m_data->GetRefCount() == 1) + { + ((wxVariantDataBool*)GetData())->SetValue(value); + } + else + { + UnRef(); + m_data = new wxVariantDataBool(value); + } +} + +bool wxVariant::GetBool() const +{ + bool value; + if (Convert(& value)) + return value; + else + { + wxFAIL_MSG(wxT("Could not convert to a bool")); + return 0; + } +} + +#endif // HAVE_BOOL + +// ----------------------------------------------------------------- +// wxVariantDataChar +// ----------------------------------------------------------------- + +class WXDLLIMPEXP_BASE wxVariantDataChar: public wxVariantData +{ +DECLARE_DYNAMIC_CLASS(wxVariantDataChar) +public: + wxVariantDataChar() { m_value = 0; } + wxVariantDataChar(wxChar value) { m_value = value; } + + inline wxChar GetValue() const { return m_value; } + inline void SetValue(wxChar value) { m_value = value; } + + virtual bool Eq(wxVariantData& data) const; +#if wxUSE_STD_IOSTREAM + virtual bool Read(wxSTD istream& str); + virtual bool Write(wxSTD ostream& str) const; +#endif + virtual bool Read(wxString& str); + virtual bool Write(wxString& str) const; +#if wxUSE_STREAMS + virtual bool Read(wxInputStream& str); + virtual bool Write(wxOutputStream& str) const; +#endif // wxUSE_STREAMS + virtual wxString GetType() const { return wxT("char"); } + +protected: + wxChar m_value; +}; + +IMPLEMENT_DYNAMIC_CLASS(wxVariantDataChar, wxVariantData) + +bool wxVariantDataChar::Eq(wxVariantData& data) const +{ + wxASSERT_MSG( (data.GetType() == wxT("char")), wxT("wxVariantDataChar::Eq: argument mismatch") ); + + wxVariantDataChar& otherData = (wxVariantDataChar&) data; + + return (otherData.m_value == m_value); +} + +#if wxUSE_STD_IOSTREAM +bool wxVariantDataChar::Write(wxSTD ostream& str) const +{ + wxString s; + Write(s); + str << (const char*) s.mb_str(); + return true; +} +#endif + +bool wxVariantDataChar::Write(wxString& str) const +{ + str.Printf(wxT("%c"), m_value); + return true; +} + +#if wxUSE_STD_IOSTREAM +bool wxVariantDataChar::Read(wxSTD istream& WXUNUSED(str)) +{ + wxFAIL_MSG(wxT("Unimplemented")); + + return false; +} +#endif + +#if wxUSE_STREAMS +bool wxVariantDataChar::Write(wxOutputStream& str) const +{ + wxTextOutputStream s(str); + + s << m_value; + + return true; +} + +bool wxVariantDataChar::Read(wxInputStream& str) +{ + wxTextInputStream s(str); + + s >> m_value; + + return true; +} +#endif // wxUSE_STREAMS + +bool wxVariantDataChar::Read(wxString& str) +{ + m_value = str[size_t(0)]; + return true; +} + +wxVariant::wxVariant(wxChar val, const wxString& name) +{ + m_data = new wxVariantDataChar(val); + m_name = name; +} + +bool wxVariant::operator== (wxChar value) const +{ + wxChar thisValue; + if (!Convert(&thisValue)) + return false; + else + return (value == thisValue); +} + +bool wxVariant::operator!= (wxChar value) const +{ + return (!((*this) == value)); +} + +void wxVariant::operator= (wxChar value) +{ + if (GetType() == wxT("char") && + m_data->GetRefCount() == 1) + { + ((wxVariantDataChar*)GetData())->SetValue(value); + } + else + { + UnRef(); + m_data = new wxVariantDataChar(value); + } +} + +wxChar wxVariant::GetChar() const +{ + wxChar value; + if (Convert(& value)) + return value; + else + { + wxFAIL_MSG(wxT("Could not convert to a char")); + return 0; + } +} + +// ---------------------------------------------------------------------------- +// wxVariantDataString +// ---------------------------------------------------------------------------- + +class WXDLLIMPEXP_BASE wxVariantDataString: public wxVariantData +{ +DECLARE_DYNAMIC_CLASS(wxVariantDataString) +public: + wxVariantDataString() { } + wxVariantDataString(const wxString& value) { m_value = value; } + + inline wxString GetValue() const { return m_value; } + inline void SetValue(const wxString& value) { m_value = value; } + + virtual bool Eq(wxVariantData& data) const; +#if wxUSE_STD_IOSTREAM + virtual bool Write(wxSTD ostream& str) const; +#endif + virtual bool Read(wxString& str); + virtual bool Write(wxString& str) const; +#if wxUSE_STD_IOSTREAM + virtual bool Read(wxSTD istream& WXUNUSED(str)) { return false; } +#endif +#if wxUSE_STREAMS + virtual bool Read(wxInputStream& str); + virtual bool Write(wxOutputStream& str) const; +#endif // wxUSE_STREAMS + virtual wxString GetType() const { return wxT("string"); } + +protected: + wxString m_value; +}; + +bool wxVariantDataString::Eq(wxVariantData& data) const +{ + wxASSERT_MSG( (data.GetType() == wxT("string")), wxT("wxVariantDataString::Eq: argument mismatch") ); + + wxVariantDataString& otherData = (wxVariantDataString&) data; + + return (otherData.m_value == m_value); +} + +#if wxUSE_STD_IOSTREAM +bool wxVariantDataString::Write(wxSTD ostream& str) const +{ + str << (const char*) m_value.mb_str(); + return true; +} +#endif + +bool wxVariantDataString::Write(wxString& str) const +{ + str = m_value; + return true; +} + +#if wxUSE_STREAMS +bool wxVariantDataString::Write(wxOutputStream& str) const +{ + // why doesn't wxOutputStream::operator<< take "const wxString&" + wxTextOutputStream s(str); + s.WriteString(m_value); + return true; +} + +bool wxVariantDataString::Read(wxInputStream& str) +{ + wxTextInputStream s(str); + + m_value = s.ReadLine(); + return true; +} +#endif // wxUSE_STREAMS + +bool wxVariantDataString::Read(wxString& str) +{ + m_value = str; + return true; +} + +IMPLEMENT_DYNAMIC_CLASS(wxVariantDataString, wxVariantData) + +// wxVariant **** + +wxVariant::wxVariant(const wxString& val, const wxString& name) +{ + m_data = new wxVariantDataString(val); + m_name = name; +} + +wxVariant::wxVariant(const wxChar* val, const wxString& name) +{ + m_data = new wxVariantDataString(wxString(val)); + m_name = name; +} + +bool wxVariant::operator== (const wxString& value) const +{ + wxString thisValue; + if (!Convert(&thisValue)) + return false; + + return value == thisValue; +} + +bool wxVariant::operator!= (const wxString& value) const +{ + return (!((*this) == value)); +} + +void wxVariant::operator= (const wxString& value) +{ + if (GetType() == wxT("string") && + m_data->GetRefCount() == 1) + { + ((wxVariantDataString*)GetData())->SetValue(value); + } + else + { + UnRef(); + m_data = new wxVariantDataString(value); + } +} + +void wxVariant::operator= (const wxChar* value) +{ + if (GetType() == wxT("string") && + m_data->GetRefCount() == 1) + { + ((wxVariantDataString*)GetData())->SetValue(wxString(value)); + } + else + { + UnRef(); + m_data = new wxVariantDataString(wxString(value)); + } +} + +wxString wxVariant::GetString() const +{ + wxString value; + if (!Convert(& value)) + { + wxFAIL_MSG(wxT("Could not convert to a string")); + } + + return value; +} + +// ---------------------------------------------------------------------------- +// wxVariantDataWxObjectPtr +// ---------------------------------------------------------------------------- + +class wxVariantDataWxObjectPtr: public wxVariantData +{ +DECLARE_DYNAMIC_CLASS(wxVariantDataWxObjectPtr) +public: + wxVariantDataWxObjectPtr() { } + wxVariantDataWxObjectPtr(wxObject* value) { m_value = value; } + + inline wxObject* GetValue() const { return m_value; } + inline void SetValue(wxObject* value) { m_value = value; } + + virtual bool Eq(wxVariantData& data) const; +#if wxUSE_STD_IOSTREAM + virtual bool Write(wxSTD ostream& str) const; +#endif + virtual bool Write(wxString& str) const; +#if wxUSE_STD_IOSTREAM + virtual bool Read(wxSTD istream& str); +#endif + virtual bool Read(wxString& str); + virtual wxString GetType() const ; + virtual wxVariantData* Clone() { return new wxVariantDataWxObjectPtr; } + + virtual wxClassInfo* GetValueClassInfo() ; +protected: + wxObject* m_value; + + DECLARE_NO_COPY_CLASS(wxVariantDataWxObjectPtr) +}; + +IMPLEMENT_DYNAMIC_CLASS(wxVariantDataWxObjectPtr, wxVariantData) + +bool wxVariantDataWxObjectPtr::Eq(wxVariantData& data) const +{ + wxASSERT_MSG( wxIsKindOf((&data), wxVariantDataWxObjectPtr), wxT("wxVariantDataWxObjectPtr::Eq: argument mismatch") ); + + wxVariantDataWxObjectPtr& otherData = (wxVariantDataWxObjectPtr&) data; + + return (otherData.m_value == m_value); +} + +wxString wxVariantDataWxObjectPtr::GetType() const +{ + wxString returnVal(wxT("wxObject")); + if (m_value) { + returnVal = m_value->GetClassInfo()->GetClassName(); + } + return returnVal; +} + +wxClassInfo* wxVariantDataWxObjectPtr::GetValueClassInfo() +{ + wxClassInfo* returnVal=NULL; + + if (m_value) returnVal = m_value->GetClassInfo(); + + return returnVal; +} + +#if wxUSE_STD_IOSTREAM +bool wxVariantDataWxObjectPtr::Write(wxSTD ostream& str) const +{ + wxString s; + Write(s); + str << (const char*) s.mb_str(); + return true; +} +#endif + +bool wxVariantDataWxObjectPtr::Write(wxString& str) const +{ + str.Printf(wxT("%s(%p)"), GetType().c_str(), wx_static_cast(void*, m_value)); + return true; +} + +#if wxUSE_STD_IOSTREAM +bool wxVariantDataWxObjectPtr::Read(wxSTD istream& WXUNUSED(str)) +{ + // Not implemented + return false; +} +#endif + +bool wxVariantDataWxObjectPtr::Read(wxString& WXUNUSED(str)) +{ + // Not implemented + return false; +} + +// wxVariant + +wxVariant::wxVariant( wxObject* val, const wxString& name) +{ + m_data = new wxVariantDataWxObjectPtr(val); + m_name = name; +} + +bool wxVariant::operator== (wxObject* value) const +{ + return (value == ((wxVariantDataWxObjectPtr*)GetData())->GetValue()); +} + +bool wxVariant::operator!= (wxObject* value) const +{ + return (!((*this) == (wxObject*) value)); +} + +void wxVariant::operator= (wxObject* value) +{ + UnRef(); + m_data = new wxVariantDataWxObjectPtr(value); +} + +wxObject* wxVariant::GetWxObjectPtr() const +{ + wxASSERT(wxIsKindOf(GetData(), wxVariantDataWxObjectPtr)); + return (wxObject*) ((wxVariantDataWxObjectPtr*) m_data)->GetValue(); +} + +// ---------------------------------------------------------------------------- +// wxVariantDataVoidPtr +// ---------------------------------------------------------------------------- + +class wxVariantDataVoidPtr: public wxVariantData +{ +DECLARE_DYNAMIC_CLASS(wxVariantDataVoidPtr) +public: + wxVariantDataVoidPtr() { } + wxVariantDataVoidPtr(void* value) { m_value = value; } + + inline void* GetValue() const { return m_value; } + inline void SetValue(void* value) { m_value = value; } + + virtual bool Eq(wxVariantData& data) const; +#if wxUSE_STD_IOSTREAM + virtual bool Write(wxSTD ostream& str) const; +#endif + virtual bool Write(wxString& str) const; +#if wxUSE_STD_IOSTREAM + virtual bool Read(wxSTD istream& str); +#endif + virtual bool Read(wxString& str); + virtual wxString GetType() const { return wxT("void*"); } + virtual wxVariantData* Clone() { return new wxVariantDataVoidPtr; } + +protected: + void* m_value; + + DECLARE_NO_COPY_CLASS(wxVariantDataVoidPtr) +}; + +IMPLEMENT_DYNAMIC_CLASS(wxVariantDataVoidPtr, wxVariantData) + +bool wxVariantDataVoidPtr::Eq(wxVariantData& data) const +{ + wxASSERT_MSG( (data.GetType() == wxT("void*")), wxT("wxVariantDataVoidPtr::Eq: argument mismatch") ); + + wxVariantDataVoidPtr& otherData = (wxVariantDataVoidPtr&) data; + + return (otherData.m_value == m_value); +} + +#if wxUSE_STD_IOSTREAM +bool wxVariantDataVoidPtr::Write(wxSTD ostream& str) const +{ + wxString s; + Write(s); + str << (const char*) s.mb_str(); + return true; +} +#endif + +bool wxVariantDataVoidPtr::Write(wxString& str) const +{ + str.Printf(wxT("%p"), m_value); + return true; +} + +#if wxUSE_STD_IOSTREAM +bool wxVariantDataVoidPtr::Read(wxSTD istream& WXUNUSED(str)) +{ + // Not implemented + return false; +} +#endif + +bool wxVariantDataVoidPtr::Read(wxString& WXUNUSED(str)) +{ + // Not implemented + return false; +} + +// wxVariant + +wxVariant::wxVariant( void* val, const wxString& name) +{ + m_data = new wxVariantDataVoidPtr(val); + m_name = name; +} + +bool wxVariant::operator== (void* value) const +{ + return (value == ((wxVariantDataVoidPtr*)GetData())->GetValue()); +} + +bool wxVariant::operator!= (void* value) const +{ + return (!((*this) == (void*) value)); +} + +void wxVariant::operator= (void* value) +{ + if (GetType() == wxT("void*") && + m_data->GetRefCount() == 1) + { + ((wxVariantDataVoidPtr*)GetData())->SetValue(value); + } + else + { + UnRef(); + m_data = new wxVariantDataVoidPtr(value); + } +} + +void* wxVariant::GetVoidPtr() const +{ + wxASSERT( (GetType() == wxT("void*")) ); + + return (void*) ((wxVariantDataVoidPtr*) m_data)->GetValue(); +} + +// ---------------------------------------------------------------------------- +// wxVariantDataDateTime +// ---------------------------------------------------------------------------- + +#if wxUSE_DATETIME + +class wxVariantDataDateTime: public wxVariantData +{ + DECLARE_DYNAMIC_CLASS(wxVariantDataDateTime) + +public: + wxVariantDataDateTime() { } + wxVariantDataDateTime(const wxDateTime& value) { m_value = value; } +#if wxUSE_ODBC + wxVariantDataDateTime(const TIME_STRUCT* valptr) + { m_value = wxDateTime(valptr->hour, valptr->minute, valptr->second); } + wxVariantDataDateTime(const DATE_STRUCT* valptr) + { m_value = wxDateTime(valptr->day, (wxDateTime::Month) (valptr->month - 1),valptr->year); } + wxVariantDataDateTime(const TIMESTAMP_STRUCT* valptr) + { m_value = wxDateTime(valptr->day, (wxDateTime::Month) (valptr->month - 1), valptr->year, + valptr->hour, valptr->minute, valptr->second, (wxDateTime::wxDateTime_t)valptr->fraction ); } +#endif //ODBC + + inline wxDateTime GetValue() const { return m_value; } + inline void SetValue(const wxDateTime& value) { m_value = value; } + + virtual bool Eq(wxVariantData& data) const; +#if wxUSE_STD_IOSTREAM + virtual bool Write(wxSTD ostream& str) const; +#endif + virtual bool Write(wxString& str) const; +#if wxUSE_STD_IOSTREAM + virtual bool Read(wxSTD istream& str); +#endif + virtual bool Read(wxString& str); + virtual wxString GetType() const { return wxT("datetime"); } + virtual wxVariantData* Clone() { return new wxVariantDataDateTime; } + +protected: + wxDateTime m_value; +}; + + +IMPLEMENT_DYNAMIC_CLASS(wxVariantDataDateTime, wxVariantData) + +bool wxVariantDataDateTime::Eq(wxVariantData& data) const +{ + wxASSERT_MSG( (data.GetType() == wxT("datetime")), wxT("wxVariantDataDateTime::Eq: argument mismatch") ); + + wxVariantDataDateTime& otherData = (wxVariantDataDateTime&) data; + + return (otherData.m_value == m_value); +} + + +#if wxUSE_STD_IOSTREAM +bool wxVariantDataDateTime::Write(wxSTD ostream& str) const +{ + wxString value; + Write( value ); + str << value.c_str(); + return true; +} +#endif + + +bool wxVariantDataDateTime::Write(wxString& str) const +{ + str = m_value.Format(); + return true; +} + + +#if wxUSE_STD_IOSTREAM +bool wxVariantDataDateTime::Read(wxSTD istream& WXUNUSED(str)) +{ + // Not implemented + return false; +} +#endif + + +bool wxVariantDataDateTime::Read(wxString& str) +{ + if(! m_value.ParseDateTime(str)) + return false; + return true; +} + +// wxVariant + +wxVariant::wxVariant(const wxDateTime& val, const wxString& name) // Date +{ + m_data = new wxVariantDataDateTime(val); + m_name = name; +} + +#if wxUSE_ODBC +wxVariant::wxVariant(const TIME_STRUCT* valptr, const wxString& name) // Date +{ + m_data = new wxVariantDataDateTime(valptr); + m_name = name; +} + +wxVariant::wxVariant(const TIMESTAMP_STRUCT* valptr, const wxString& name) // Date +{ + m_data = new wxVariantDataDateTime(valptr); + m_name = name; +} + +wxVariant::wxVariant(const DATE_STRUCT* valptr, const wxString& name) // Date +{ + m_data = new wxVariantDataDateTime(valptr); + m_name = name; +} +#endif // wxUSE_ODBC + +bool wxVariant::operator== (const wxDateTime& value) const +{ + wxDateTime thisValue; + if (!Convert(&thisValue)) + return false; + + return value.IsEqualTo(thisValue); +} + +bool wxVariant::operator!= (const wxDateTime& value) const +{ + return (!((*this) == value)); +} + +void wxVariant::operator= (const wxDateTime& value) +{ + if (GetType() == wxT("datetime") && + m_data->GetRefCount() == 1) + { + ((wxVariantDataDateTime*)GetData())->SetValue(value); + } + else + { + UnRef(); + m_data = new wxVariantDataDateTime(value); + } +} + +#if wxUSE_ODBC +void wxVariant::operator= (const DATE_STRUCT* value) +{ + UnRef(); + m_data = new wxVariantDataDateTime(value); +} + +void wxVariant::operator= (const TIME_STRUCT* value) +{ + UnRef(); + m_data = new wxVariantDataDateTime(value); +} + +void wxVariant::operator= (const TIMESTAMP_STRUCT* value) +{ + UnRef(); + m_data = new wxVariantDataDateTime(value); +} + +#endif // wxUSE_ODBC + +wxDateTime wxVariant::GetDateTime() const +{ + wxDateTime value; + if (!Convert(& value)) + { + wxFAIL_MSG(wxT("Could not convert to a datetime")); + } + + return value; +} + +#endif // wxUSE_DATETIME + +// ---------------------------------------------------------------------------- +// wxVariantDataArrayString +// ---------------------------------------------------------------------------- + +class wxVariantDataArrayString: public wxVariantData +{ +public: + wxVariantDataArrayString() { } + wxVariantDataArrayString(const wxArrayString& value) { m_value = value; } + + wxArrayString GetValue() const { return m_value; } + void SetValue(const wxArrayString& value) { m_value = value; } + + virtual bool Eq(wxVariantData& data) const; +#if wxUSE_STD_IOSTREAM + virtual bool Write(wxSTD ostream& str) const; +#endif + virtual bool Write(wxString& str) const; +#if wxUSE_STD_IOSTREAM + virtual bool Read(wxSTD istream& str); +#endif + virtual bool Read(wxString& str); + virtual wxString GetType() const { return wxT("arrstring"); } + virtual wxVariantData* Clone() { return new wxVariantDataArrayString; } + +protected: + wxArrayString m_value; + + DECLARE_DYNAMIC_CLASS(wxVariantDataArrayString) +}; + +IMPLEMENT_DYNAMIC_CLASS(wxVariantDataArrayString, wxVariantData) + +bool wxVariantDataArrayString::Eq(wxVariantData& data) const +{ + wxASSERT_MSG( data.GetType() == GetType(), wxT("wxVariantDataArrayString::Eq: argument mismatch") ); + + wxVariantDataArrayString& otherData = (wxVariantDataArrayString&) data; + + return otherData.m_value == m_value; +} + +#if wxUSE_STD_IOSTREAM +bool wxVariantDataArrayString::Write(wxSTD ostream& WXUNUSED(str)) const +{ + // Not implemented + return false; +} +#endif + +bool wxVariantDataArrayString::Write(wxString& str) const +{ + size_t count = m_value.GetCount(); + for ( size_t n = 0; n < count; n++ ) + { + if ( n ) + str += _T(';'); + + str += m_value[n]; + } + + return true; +} + + +#if wxUSE_STD_IOSTREAM +bool wxVariantDataArrayString::Read(wxSTD istream& WXUNUSED(str)) +{ + // Not implemented + return false; +} +#endif + + +bool wxVariantDataArrayString::Read(wxString& str) +{ + wxStringTokenizer tk(str, _T(";")); + while ( tk.HasMoreTokens() ) + { + m_value.Add(tk.GetNextToken()); + } + + return true; +} + +// wxVariant + +wxVariant::wxVariant(const wxArrayString& val, const wxString& name) // Strings +{ + m_data = new wxVariantDataArrayString(val); + m_name = name; +} + +bool wxVariant::operator==(const wxArrayString& WXUNUSED(value)) const +{ + wxFAIL_MSG( _T("TODO") ); + + return false; +} + +bool wxVariant::operator!=(const wxArrayString& value) const +{ + return !(*this == value); +} + +void wxVariant::operator=(const wxArrayString& value) +{ + if (GetType() == wxT("arrstring") && + m_data->GetRefCount() == 1) + { + ((wxVariantDataArrayString *)GetData())->SetValue(value); + } + else + { + UnRef(); + m_data = new wxVariantDataArrayString(value); + } +} + +wxArrayString wxVariant::GetArrayString() const +{ + if ( GetType() == wxT("arrstring") ) + return ((wxVariantDataArrayString *)GetData())->GetValue(); + + return wxArrayString(); +} + +// ---------------------------------------------------------------------------- +// wxVariantDataList +// ---------------------------------------------------------------------------- + +class WXDLLIMPEXP_BASE wxVariantDataList: public wxVariantData +{ +DECLARE_DYNAMIC_CLASS(wxVariantDataList) +public: + wxVariantDataList() {} + wxVariantDataList(const wxList& list); + virtual ~wxVariantDataList(); + + wxList& GetValue() { return m_value; } + void SetValue(const wxList& value) ; + + virtual bool Eq(wxVariantData& data) const; +#if wxUSE_STD_IOSTREAM + virtual bool Write(wxSTD ostream& str) const; +#endif + virtual bool Write(wxString& str) const; +#if wxUSE_STD_IOSTREAM + virtual bool Read(wxSTD istream& str); +#endif + virtual bool Read(wxString& str); + virtual wxString GetType() const { return wxT("list"); } + + void Clear(); + +protected: + wxList m_value; +}; + +IMPLEMENT_DYNAMIC_CLASS(wxVariantDataList, wxVariantData) + +wxVariantDataList::wxVariantDataList(const wxList& list) +{ + SetValue(list); +} + +wxVariantDataList::~wxVariantDataList() +{ + Clear(); +} + +void wxVariantDataList::SetValue(const wxList& value) +{ + Clear(); + wxList::compatibility_iterator node = value.GetFirst(); + while (node) + { + wxVariant* var = (wxVariant*) node->GetData(); + m_value.Append(new wxVariant(*var)); + node = node->GetNext(); + } +} + +void wxVariantDataList::Clear() +{ + wxList::compatibility_iterator node = m_value.GetFirst(); + while (node) + { + wxVariant* var = (wxVariant*) node->GetData(); + delete var; + node = node->GetNext(); + } + m_value.Clear(); +} + +bool wxVariantDataList::Eq(wxVariantData& data) const +{ + wxASSERT_MSG( (data.GetType() == wxT("list")), wxT("wxVariantDataList::Eq: argument mismatch") ); + + wxVariantDataList& listData = (wxVariantDataList&) data; + wxList::compatibility_iterator node1 = m_value.GetFirst(); + wxList::compatibility_iterator node2 = listData.GetValue().GetFirst(); + while (node1 && node2) + { + wxVariant* var1 = (wxVariant*) node1->GetData(); + wxVariant* var2 = (wxVariant*) node2->GetData(); + if ((*var1) != (*var2)) + return false; + node1 = node1->GetNext(); + node2 = node2->GetNext(); + } + if (node1 || node2) return false; + return true; +} + +#if wxUSE_STD_IOSTREAM +bool wxVariantDataList::Write(wxSTD ostream& str) const +{ + wxString s; + Write(s); + str << (const char*) s.mb_str(); + return true; +} +#endif + +bool wxVariantDataList::Write(wxString& str) const +{ + str = wxEmptyString; + wxList::compatibility_iterator node = m_value.GetFirst(); + while (node) + { + wxVariant* var = (wxVariant*) node->GetData(); + if (node != m_value.GetFirst()) + str += wxT(" "); + wxString str1; + str += var->MakeString(); + node = node->GetNext(); + } + + return true; +} + +#if wxUSE_STD_IOSTREAM +bool wxVariantDataList::Read(wxSTD istream& WXUNUSED(str)) +{ + wxFAIL_MSG(wxT("Unimplemented")); + // TODO + return false; +} +#endif + +bool wxVariantDataList::Read(wxString& WXUNUSED(str)) +{ + wxFAIL_MSG(wxT("Unimplemented")); + // TODO + return false; +} + +// wxVariant + +wxVariant::wxVariant(const wxList& val, const wxString& name) // List of variants +{ + m_data = new wxVariantDataList(val); + m_name = name; +} + +bool wxVariant::operator== (const wxList& value) const +{ + wxASSERT_MSG( (GetType() == wxT("list")), wxT("Invalid type for == operator") ); + + wxVariantDataList other(value); + return (GetData()->Eq(other)); +} + +bool wxVariant::operator!= (const wxList& value) const +{ + return (!((*this) == value)); +} + +void wxVariant::operator= (const wxList& value) +{ + if (GetType() == wxT("list") && + m_data->GetRefCount() == 1) + { + ((wxVariantDataList*)GetData())->SetValue(value); + } + else + { + UnRef(); + m_data = new wxVariantDataList(value); + } +} + +wxList& wxVariant::GetList() const +{ + wxASSERT( (GetType() == wxT("list")) ); + + return (wxList&) ((wxVariantDataList*) m_data)->GetValue(); +} + +// Make empty list +void wxVariant::NullList() +{ + SetData(new wxVariantDataList()); +} + +// Append to list +void wxVariant::Append(const wxVariant& value) +{ + wxList& list = GetList(); + + list.Append(new wxVariant(value)); +} + +// Insert at front of list +void wxVariant::Insert(const wxVariant& value) +{ + wxList& list = GetList(); + + list.Insert(new wxVariant(value)); +} + +// Returns true if the variant is a member of the list +bool wxVariant::Member(const wxVariant& value) const +{ + wxList& list = GetList(); + + wxList::compatibility_iterator node = list.GetFirst(); + while (node) + { + wxVariant* other = (wxVariant*) node->GetData(); + if (value == *other) + return true; + node = node->GetNext(); + } + return false; +} + +// Deletes the nth element of the list +bool wxVariant::Delete(size_t item) +{ + wxList& list = GetList(); + + wxASSERT_MSG( (item < list.GetCount()), wxT("Invalid index to Delete") ); + wxList::compatibility_iterator node = list.Item(item); + wxVariant* variant = (wxVariant*) node->GetData(); + delete variant; + list.Erase(node); + return true; +} + +// Clear list +void wxVariant::ClearList() +{ + if (!IsNull() && (GetType() == wxT("list"))) + { + ((wxVariantDataList*) m_data)->Clear(); + } + else + { + if (!GetType().IsSameAs(wxT("list"))) + UnRef(); + + m_data = new wxVariantDataList; + } +} + +#if WXWIN_COMPATIBILITY_2_4 + +// ---------------------------------------------------------------------------- +// wxVariantDataStringList +// ---------------------------------------------------------------------------- + +class WXDLLIMPEXP_BASE wxVariantDataStringList: public wxVariantData +{ +DECLARE_DYNAMIC_CLASS(wxVariantDataStringList) +public: + wxVariantDataStringList() {} + wxVariantDataStringList(const wxStringList& list) { m_value = list; } + + wxStringList& GetValue() const { return (wxStringList&) m_value; } + void SetValue(const wxStringList& value); + + virtual bool Eq(wxVariantData& data) const; +#if wxUSE_STD_IOSTREAM + virtual bool Write(wxSTD ostream& str) const; +#endif + virtual bool Write(wxString& str) const; +#if wxUSE_STD_IOSTREAM + virtual bool Read(wxSTD istream& str); +#endif + virtual bool Read(wxString& str); + virtual wxString GetType() const { return wxT("stringlist"); }; + +protected: + wxStringList m_value; +}; + +IMPLEMENT_DYNAMIC_CLASS(wxVariantDataStringList, wxVariantData) + +void wxVariantDataStringList::SetValue(const wxStringList& value) +{ + m_value = value; +} + +bool wxVariantDataStringList::Eq(wxVariantData& data) const +{ + wxASSERT_MSG( (data.GetType() == wxT("stringlist")), wxT("wxVariantDataStringList::Eq: argument mismatch") ); + + wxVariantDataStringList& listData = (wxVariantDataStringList&) data; + wxStringList::compatibility_iterator node1 = m_value.GetFirst(); + wxStringList::compatibility_iterator node2 = listData.GetValue().GetFirst(); + while (node1 && node2) + { + wxString str1 ( node1->GetData() ); + wxString str2 ( node2->GetData() ); + if (str1 != str2) + return false; + node1 = node1->GetNext(); + node2 = node2->GetNext(); + } + if (node1 || node2) return false; + return true; +} + +#if wxUSE_STD_IOSTREAM +bool wxVariantDataStringList::Write(wxSTD ostream& str) const +{ + wxString s; + Write(s); + str << (const char*) s.mb_str(); + return true; +} +#endif + +bool wxVariantDataStringList::Write(wxString& str) const +{ + str.Empty(); + wxStringList::compatibility_iterator node = m_value.GetFirst(); + while (node) + { + const wxChar* s = node->GetData(); + if (node != m_value.GetFirst()) + str += wxT(" "); + str += s; + node = node->GetNext(); + } + + return true; +} + +#if wxUSE_STD_IOSTREAM +bool wxVariantDataStringList::Read(wxSTD istream& WXUNUSED(str)) +{ + wxFAIL_MSG(wxT("Unimplemented")); + // TODO + return false; +} +#endif + +bool wxVariantDataStringList::Read(wxString& WXUNUSED(str)) +{ + wxFAIL_MSG(wxT("Unimplemented")); + // TODO + return false; +} + +#endif //2.4 compat + +#if WXWIN_COMPATIBILITY_2_4 + +wxVariant::wxVariant(const wxStringList& val, const wxString& name) +{ + m_data = new wxVariantDataStringList(val); + m_name = name; +} + +bool wxVariant::operator== (const wxStringList& value) const +{ + wxASSERT_MSG( (GetType() == wxT("stringlist")), wxT("Invalid type for == operator") ); + + wxVariantDataStringList other(value); + return (GetData()->Eq(other)); +} + +bool wxVariant::operator!= (const wxStringList& value) const +{ + wxASSERT_MSG( (GetType() == wxT("stringlist")), wxT("Invalid type for == operator") ); + + wxVariantDataStringList other(value); + return !(GetData()->Eq(other)); +} + +void wxVariant::operator= (const wxStringList& value) +{ + if (GetType() == wxT("stringlist") && + m_data->GetRefCount() == 1) + { + ((wxVariantDataStringList*)GetData())->SetValue(value); + } + else + { + UnRef(); + m_data = new wxVariantDataStringList(value); + } +} + +// wxVariant + +wxStringList& wxVariant::GetStringList() const +{ + wxASSERT( (GetType() == wxT("stringlist")) ); + + return (wxStringList&) ((wxVariantDataStringList*) m_data)->GetValue(); +} + +#endif + +// Treat a list variant as an array +wxVariant wxVariant::operator[] (size_t idx) const +{ +#if WXWIN_COMPATIBILITY_2_4 + wxASSERT_MSG( (GetType() == wxT("list") || GetType() == wxT("stringlist")), wxT("Invalid type for array operator") ); +#else + wxASSERT_MSG( GetType() == wxT("list"), wxT("Invalid type for array operator") ); +#endif + + if (GetType() == wxT("list")) + { + wxVariantDataList* data = (wxVariantDataList*) m_data; + wxASSERT_MSG( (idx < data->GetValue().GetCount()), wxT("Invalid index for array") ); + return * (wxVariant*) (data->GetValue().Item(idx)->GetData()); + } +#if WXWIN_COMPATIBILITY_2_4 + else if (GetType() == wxT("stringlist")) + { + wxVariantDataStringList* data = (wxVariantDataStringList*) m_data; + wxASSERT_MSG( (idx < data->GetValue().GetCount()), wxT("Invalid index for array") ); + + wxString str( (const wxChar*) (data->GetValue().Item(idx)->GetData()) ); + wxVariant variant( str ); + return variant; + } +#endif + return wxNullVariant; +} + +wxVariant& wxVariant::operator[] (size_t idx) +{ + // We can't return a reference to a variant for a string list, since the string + // is actually stored as a char*, not a variant. + + wxASSERT_MSG( (GetType() == wxT("list")), wxT("Invalid type for array operator") ); + + wxVariantDataList* data = (wxVariantDataList*) m_data; + wxASSERT_MSG( (idx < data->GetValue().GetCount()), wxT("Invalid index for array") ); + + return * (wxVariant*) (data->GetValue().Item(idx)->GetData()); +} + +// Return the number of elements in a list +size_t wxVariant::GetCount() const +{ +#if WXWIN_COMPATIBILITY_2_4 + wxASSERT_MSG( (GetType() == wxT("list") || GetType() == wxT("stringlist")), wxT("Invalid type for GetCount()") ); +#else + wxASSERT_MSG( GetType() == wxT("list"), wxT("Invalid type for GetCount()") ); +#endif + + if (GetType() == wxT("list")) + { + wxVariantDataList* data = (wxVariantDataList*) m_data; + return data->GetValue().GetCount(); + } +#if WXWIN_COMPATIBILITY_2_4 + else if (GetType() == wxT("stringlist")) + { + wxVariantDataStringList* data = (wxVariantDataStringList*) m_data; + return data->GetValue().GetCount(); + } +#endif + return 0; +} + +// ---------------------------------------------------------------------------- +// Type conversion +// ---------------------------------------------------------------------------- + +bool wxVariant::Convert(long* value) const +{ + wxString type(GetType()); + if (type == wxT("double")) + *value = (long) (((wxVariantDoubleData*)GetData())->GetValue()); + else if (type == wxT("long")) + *value = ((wxVariantDataLong*)GetData())->GetValue(); +#ifdef HAVE_BOOL + else if (type == wxT("bool")) + *value = (long) (((wxVariantDataBool*)GetData())->GetValue()); +#endif + else if (type == wxT("string")) + *value = wxAtol((const wxChar*) ((wxVariantDataString*)GetData())->GetValue()); + else + return false; + + return true; +} + +bool wxVariant::Convert(bool* value) const +{ + wxString type(GetType()); + if (type == wxT("double")) + *value = ((int) (((wxVariantDoubleData*)GetData())->GetValue()) != 0); + else if (type == wxT("long")) + *value = (((wxVariantDataLong*)GetData())->GetValue() != 0); +#ifdef HAVE_BOOL + else if (type == wxT("bool")) + *value = ((wxVariantDataBool*)GetData())->GetValue(); +#endif + else if (type == wxT("string")) + { + wxString val(((wxVariantDataString*)GetData())->GetValue()); + val.MakeLower(); + if (val == wxT("true") || val == wxT("yes") || val == wxT('1') ) + *value = true; + else if (val == wxT("false") || val == wxT("no") || val == wxT('0') ) + *value = false; + else + return false; + } + else + return false; + + return true; +} + +bool wxVariant::Convert(double* value) const +{ + wxString type(GetType()); + if (type == wxT("double")) + *value = ((wxVariantDoubleData*)GetData())->GetValue(); + else if (type == wxT("long")) + *value = (double) (((wxVariantDataLong*)GetData())->GetValue()); +#ifdef HAVE_BOOL + else if (type == wxT("bool")) + *value = (double) (((wxVariantDataBool*)GetData())->GetValue()); +#endif + else if (type == wxT("string")) + *value = (double) wxAtof((const wxChar*) ((wxVariantDataString*)GetData())->GetValue()); + else + return false; + + return true; +} + +bool wxVariant::Convert(wxChar* value) const +{ + wxString type(GetType()); + if (type == wxT("char")) + *value = ((wxVariantDataChar*)GetData())->GetValue(); + else if (type == wxT("long")) + *value = (char) (((wxVariantDataLong*)GetData())->GetValue()); +#ifdef HAVE_BOOL + else if (type == wxT("bool")) + *value = (char) (((wxVariantDataBool*)GetData())->GetValue()); +#endif + else + return false; + + return true; +} + +bool wxVariant::Convert(wxString* value) const +{ + *value = MakeString(); + return true; +} + +#if wxUSE_DATETIME +bool wxVariant::Convert(wxDateTime* value) const +{ + wxString type(GetType()); + if (type == wxT("datetime")) + { + *value = ((wxVariantDataDateTime*)GetData())->GetValue(); + return true; + } + // Fallback to string conversion + wxString val; + return Convert(&val) && + (value->ParseDateTime(val) || value->ParseDate(val) || value->ParseTime(val)); +} +#endif // wxUSE_DATETIME + +#endif // wxUSE_VARIANT diff --git a/Externals/wxWidgets/src/common/wfstream.cpp b/Externals/wxWidgets/src/common/wfstream.cpp index 30ece91557..be11ac49e4 100644 --- a/Externals/wxWidgets/src/common/wfstream.cpp +++ b/Externals/wxWidgets/src/common/wfstream.cpp @@ -1,406 +1,406 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/fstream.cpp -// Purpose: "File stream" classes -// Author: Julian Smart -// Modified by: -// Created: 11/07/98 -// RCS-ID: $Id: wfstream.cpp 44013 2006-12-19 13:49:26Z SC $ -// Copyright: (c) Guilhem Lavaux -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_STREAMS - -#include "wx/wfstream.h" - -#ifndef WX_PRECOMP - #include "wx/stream.h" -#endif - -#include - -#if wxUSE_FILE - -// ---------------------------------------------------------------------------- -// wxFileInputStream -// ---------------------------------------------------------------------------- - -wxFileInputStream::wxFileInputStream(const wxString& fileName) - : wxInputStream() -{ - m_file = new wxFile(fileName, wxFile::read); - m_file_destroy = true; - if ( !m_file->IsOpened() ) - m_lasterror = wxSTREAM_READ_ERROR; -} - -wxFileInputStream::wxFileInputStream() - : wxInputStream() -{ - m_file_destroy = false; - m_file = NULL; -} - -wxFileInputStream::wxFileInputStream(wxFile& file) -{ - m_file = &file; - m_file_destroy = false; -} - -wxFileInputStream::wxFileInputStream(int fd) -{ - m_file = new wxFile(fd); - m_file_destroy = true; -} - -wxFileInputStream::~wxFileInputStream() -{ - if (m_file_destroy) - delete m_file; -} - -wxFileOffset wxFileInputStream::GetLength() const -{ - return m_file->Length(); -} - -size_t wxFileInputStream::OnSysRead(void *buffer, size_t size) -{ - ssize_t ret = m_file->Read(buffer, size); - - // NB: we can't use a switch here because HP-UX CC doesn't allow - // switching over long long (which size_t is in 64bit mode) - - if ( !ret ) - { - // nothing read, so nothing more to read - m_lasterror = wxSTREAM_EOF; - } - else if ( ret == wxInvalidOffset ) - { - m_lasterror = wxSTREAM_READ_ERROR; - ret = 0; - } - else - { - // normal case - m_lasterror = wxSTREAM_NO_ERROR; - } - - return ret; -} - -wxFileOffset wxFileInputStream::OnSysSeek(wxFileOffset pos, wxSeekMode mode) -{ - return m_file->Seek(pos, mode); -} - -wxFileOffset wxFileInputStream::OnSysTell() const -{ - return m_file->Tell(); -} - -bool wxFileInputStream::IsOk() const -{ - return (wxStreamBase::IsOk() && m_file->IsOpened()); -} - -// ---------------------------------------------------------------------------- -// wxFileOutputStream -// ---------------------------------------------------------------------------- - -wxFileOutputStream::wxFileOutputStream(const wxString& fileName) -{ - m_file = new wxFile(fileName, wxFile::write); - m_file_destroy = true; - - if (!m_file->IsOpened()) - m_lasterror = wxSTREAM_WRITE_ERROR; -} - -wxFileOutputStream::wxFileOutputStream(wxFile& file) -{ - m_file = &file; - m_file_destroy = false; -} - -wxFileOutputStream::wxFileOutputStream() - : wxOutputStream() -{ - m_file_destroy = false; - m_file = NULL; -} - -wxFileOutputStream::wxFileOutputStream(int fd) -{ - m_file = new wxFile(fd); - m_file_destroy = true; -} - -wxFileOutputStream::~wxFileOutputStream() -{ - if (m_file_destroy) - { - Sync(); - delete m_file; - } -} - -size_t wxFileOutputStream::OnSysWrite(const void *buffer, size_t size) -{ - size_t ret = m_file->Write(buffer, size); - - m_lasterror = m_file->Error() ? wxSTREAM_WRITE_ERROR : wxSTREAM_NO_ERROR; - - return ret; -} - -wxFileOffset wxFileOutputStream::OnSysTell() const -{ - return m_file->Tell(); -} - -wxFileOffset wxFileOutputStream::OnSysSeek(wxFileOffset pos, wxSeekMode mode) -{ - return m_file->Seek(pos, mode); -} - -void wxFileOutputStream::Sync() -{ - wxOutputStream::Sync(); - m_file->Flush(); -} - -wxFileOffset wxFileOutputStream::GetLength() const -{ - return m_file->Length(); -} - -bool wxFileOutputStream::IsOk() const -{ - return (wxStreamBase::IsOk() && m_file->IsOpened()); -} - -// ---------------------------------------------------------------------------- -// wxTempFileOutputStream -// ---------------------------------------------------------------------------- - -wxTempFileOutputStream::wxTempFileOutputStream(const wxString& fileName) -{ - m_file = new wxTempFile(fileName); - - if (!m_file->IsOpened()) - m_lasterror = wxSTREAM_WRITE_ERROR; -} - -wxTempFileOutputStream::~wxTempFileOutputStream() -{ - if (m_file->IsOpened()) - Discard(); - delete m_file; -} - -size_t wxTempFileOutputStream::OnSysWrite(const void *buffer, size_t size) -{ - if (IsOk() && m_file->Write(buffer, size)) - return size; - m_lasterror = wxSTREAM_WRITE_ERROR; - return 0; -} - -// ---------------------------------------------------------------------------- -// wxFileStream -// ---------------------------------------------------------------------------- - -wxFileStream::wxFileStream(const wxString& fileName) - : wxFileInputStream(fileName) -{ - wxFileOutputStream::m_file = wxFileInputStream::m_file; -} - -#endif //wxUSE_FILE - -#if wxUSE_FFILE - -// ---------------------------------------------------------------------------- -// wxFFileInputStream -// ---------------------------------------------------------------------------- - -wxFFileInputStream::wxFFileInputStream(const wxString& fileName, - const wxChar *mode) - : wxInputStream() -{ - m_file = new wxFFile(fileName, mode); - m_file_destroy = true; - - if (!m_file->IsOpened()) - m_lasterror = wxSTREAM_WRITE_ERROR; -} - -wxFFileInputStream::wxFFileInputStream() - : wxInputStream() -{ - m_file = NULL; - m_file_destroy = false; -} - -wxFFileInputStream::wxFFileInputStream(wxFFile& file) -{ - m_file = &file; - m_file_destroy = false; -} - -wxFFileInputStream::wxFFileInputStream(FILE *file) -{ - m_file = new wxFFile(file); - m_file_destroy = true; -} - -wxFFileInputStream::~wxFFileInputStream() -{ - if (m_file_destroy) - delete m_file; -} - -wxFileOffset wxFFileInputStream::GetLength() const -{ - return m_file->Length(); -} - -size_t wxFFileInputStream::OnSysRead(void *buffer, size_t size) -{ - ssize_t ret = m_file->Read(buffer, size); - - // It is not safe to call Eof() if the file is not opened. - if (!m_file->IsOpened() || m_file->Eof()) - m_lasterror = wxSTREAM_EOF; - if (ret == wxInvalidOffset) - { - m_lasterror = wxSTREAM_READ_ERROR; - ret = 0; - } - - return ret; -} - -wxFileOffset wxFFileInputStream::OnSysSeek(wxFileOffset pos, wxSeekMode mode) -{ - return m_file->Seek(pos, mode) ? m_file->Tell() : wxInvalidOffset; -} - -wxFileOffset wxFFileInputStream::OnSysTell() const -{ - return m_file->Tell(); -} - -bool wxFFileInputStream::IsOk() const -{ - return (wxStreamBase::IsOk() && m_file->IsOpened()); -} - -// ---------------------------------------------------------------------------- -// wxFFileOutputStream -// ---------------------------------------------------------------------------- - -wxFFileOutputStream::wxFFileOutputStream(const wxString& fileName, - const wxChar *mode) -{ - m_file = new wxFFile(fileName, mode); - m_file_destroy = true; - - if (!m_file->IsOpened()) - { - m_lasterror = wxSTREAM_WRITE_ERROR; - } - else - { - if (m_file->Error()) - m_lasterror = wxSTREAM_WRITE_ERROR; - } -} - -wxFFileOutputStream::wxFFileOutputStream(wxFFile& file) -{ - m_file = &file; - m_file_destroy = false; -} - -wxFFileOutputStream::wxFFileOutputStream() - : wxOutputStream() -{ - m_file = NULL; - m_file_destroy = false; -} - -wxFFileOutputStream::wxFFileOutputStream(FILE *file) -{ - m_file = new wxFFile(file); - m_file_destroy = true; -} - -wxFFileOutputStream::~wxFFileOutputStream() -{ - if (m_file_destroy) - { - Sync(); - delete m_file; - } -} - -size_t wxFFileOutputStream::OnSysWrite(const void *buffer, size_t size) -{ - size_t ret = m_file->Write(buffer, size); - // It is not safe to call Error() if the file is not opened. - if (!m_file->IsOpened() || m_file->Error()) - m_lasterror = wxSTREAM_WRITE_ERROR; - else - m_lasterror = wxSTREAM_NO_ERROR; - return ret; -} - -wxFileOffset wxFFileOutputStream::OnSysTell() const -{ - return m_file->Tell(); -} - -wxFileOffset wxFFileOutputStream::OnSysSeek(wxFileOffset pos, wxSeekMode mode) -{ - return m_file->Seek(pos, mode) ? m_file->Tell() : wxInvalidOffset; -} - -void wxFFileOutputStream::Sync() -{ - wxOutputStream::Sync(); - m_file->Flush(); -} - -wxFileOffset wxFFileOutputStream::GetLength() const -{ - return m_file->Length(); -} - -bool wxFFileOutputStream::IsOk() const -{ - return (wxStreamBase::IsOk() && m_file->IsOpened()); -} - -// ---------------------------------------------------------------------------- -// wxFFileStream -// ---------------------------------------------------------------------------- - -wxFFileStream::wxFFileStream(const wxString& fileName) - : wxFFileInputStream(fileName) -{ - wxFFileOutputStream::m_file = wxFFileInputStream::m_file; -} - -#endif //wxUSE_FFILE - -#endif // wxUSE_STREAMS +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/fstream.cpp +// Purpose: "File stream" classes +// Author: Julian Smart +// Modified by: +// Created: 11/07/98 +// RCS-ID: $Id: wfstream.cpp 44013 2006-12-19 13:49:26Z SC $ +// Copyright: (c) Guilhem Lavaux +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_STREAMS + +#include "wx/wfstream.h" + +#ifndef WX_PRECOMP + #include "wx/stream.h" +#endif + +#include + +#if wxUSE_FILE + +// ---------------------------------------------------------------------------- +// wxFileInputStream +// ---------------------------------------------------------------------------- + +wxFileInputStream::wxFileInputStream(const wxString& fileName) + : wxInputStream() +{ + m_file = new wxFile(fileName, wxFile::read); + m_file_destroy = true; + if ( !m_file->IsOpened() ) + m_lasterror = wxSTREAM_READ_ERROR; +} + +wxFileInputStream::wxFileInputStream() + : wxInputStream() +{ + m_file_destroy = false; + m_file = NULL; +} + +wxFileInputStream::wxFileInputStream(wxFile& file) +{ + m_file = &file; + m_file_destroy = false; +} + +wxFileInputStream::wxFileInputStream(int fd) +{ + m_file = new wxFile(fd); + m_file_destroy = true; +} + +wxFileInputStream::~wxFileInputStream() +{ + if (m_file_destroy) + delete m_file; +} + +wxFileOffset wxFileInputStream::GetLength() const +{ + return m_file->Length(); +} + +size_t wxFileInputStream::OnSysRead(void *buffer, size_t size) +{ + ssize_t ret = m_file->Read(buffer, size); + + // NB: we can't use a switch here because HP-UX CC doesn't allow + // switching over long long (which size_t is in 64bit mode) + + if ( !ret ) + { + // nothing read, so nothing more to read + m_lasterror = wxSTREAM_EOF; + } + else if ( ret == wxInvalidOffset ) + { + m_lasterror = wxSTREAM_READ_ERROR; + ret = 0; + } + else + { + // normal case + m_lasterror = wxSTREAM_NO_ERROR; + } + + return ret; +} + +wxFileOffset wxFileInputStream::OnSysSeek(wxFileOffset pos, wxSeekMode mode) +{ + return m_file->Seek(pos, mode); +} + +wxFileOffset wxFileInputStream::OnSysTell() const +{ + return m_file->Tell(); +} + +bool wxFileInputStream::IsOk() const +{ + return (wxStreamBase::IsOk() && m_file->IsOpened()); +} + +// ---------------------------------------------------------------------------- +// wxFileOutputStream +// ---------------------------------------------------------------------------- + +wxFileOutputStream::wxFileOutputStream(const wxString& fileName) +{ + m_file = new wxFile(fileName, wxFile::write); + m_file_destroy = true; + + if (!m_file->IsOpened()) + m_lasterror = wxSTREAM_WRITE_ERROR; +} + +wxFileOutputStream::wxFileOutputStream(wxFile& file) +{ + m_file = &file; + m_file_destroy = false; +} + +wxFileOutputStream::wxFileOutputStream() + : wxOutputStream() +{ + m_file_destroy = false; + m_file = NULL; +} + +wxFileOutputStream::wxFileOutputStream(int fd) +{ + m_file = new wxFile(fd); + m_file_destroy = true; +} + +wxFileOutputStream::~wxFileOutputStream() +{ + if (m_file_destroy) + { + Sync(); + delete m_file; + } +} + +size_t wxFileOutputStream::OnSysWrite(const void *buffer, size_t size) +{ + size_t ret = m_file->Write(buffer, size); + + m_lasterror = m_file->Error() ? wxSTREAM_WRITE_ERROR : wxSTREAM_NO_ERROR; + + return ret; +} + +wxFileOffset wxFileOutputStream::OnSysTell() const +{ + return m_file->Tell(); +} + +wxFileOffset wxFileOutputStream::OnSysSeek(wxFileOffset pos, wxSeekMode mode) +{ + return m_file->Seek(pos, mode); +} + +void wxFileOutputStream::Sync() +{ + wxOutputStream::Sync(); + m_file->Flush(); +} + +wxFileOffset wxFileOutputStream::GetLength() const +{ + return m_file->Length(); +} + +bool wxFileOutputStream::IsOk() const +{ + return (wxStreamBase::IsOk() && m_file->IsOpened()); +} + +// ---------------------------------------------------------------------------- +// wxTempFileOutputStream +// ---------------------------------------------------------------------------- + +wxTempFileOutputStream::wxTempFileOutputStream(const wxString& fileName) +{ + m_file = new wxTempFile(fileName); + + if (!m_file->IsOpened()) + m_lasterror = wxSTREAM_WRITE_ERROR; +} + +wxTempFileOutputStream::~wxTempFileOutputStream() +{ + if (m_file->IsOpened()) + Discard(); + delete m_file; +} + +size_t wxTempFileOutputStream::OnSysWrite(const void *buffer, size_t size) +{ + if (IsOk() && m_file->Write(buffer, size)) + return size; + m_lasterror = wxSTREAM_WRITE_ERROR; + return 0; +} + +// ---------------------------------------------------------------------------- +// wxFileStream +// ---------------------------------------------------------------------------- + +wxFileStream::wxFileStream(const wxString& fileName) + : wxFileInputStream(fileName) +{ + wxFileOutputStream::m_file = wxFileInputStream::m_file; +} + +#endif //wxUSE_FILE + +#if wxUSE_FFILE + +// ---------------------------------------------------------------------------- +// wxFFileInputStream +// ---------------------------------------------------------------------------- + +wxFFileInputStream::wxFFileInputStream(const wxString& fileName, + const wxChar *mode) + : wxInputStream() +{ + m_file = new wxFFile(fileName, mode); + m_file_destroy = true; + + if (!m_file->IsOpened()) + m_lasterror = wxSTREAM_WRITE_ERROR; +} + +wxFFileInputStream::wxFFileInputStream() + : wxInputStream() +{ + m_file = NULL; + m_file_destroy = false; +} + +wxFFileInputStream::wxFFileInputStream(wxFFile& file) +{ + m_file = &file; + m_file_destroy = false; +} + +wxFFileInputStream::wxFFileInputStream(FILE *file) +{ + m_file = new wxFFile(file); + m_file_destroy = true; +} + +wxFFileInputStream::~wxFFileInputStream() +{ + if (m_file_destroy) + delete m_file; +} + +wxFileOffset wxFFileInputStream::GetLength() const +{ + return m_file->Length(); +} + +size_t wxFFileInputStream::OnSysRead(void *buffer, size_t size) +{ + ssize_t ret = m_file->Read(buffer, size); + + // It is not safe to call Eof() if the file is not opened. + if (!m_file->IsOpened() || m_file->Eof()) + m_lasterror = wxSTREAM_EOF; + if (ret == wxInvalidOffset) + { + m_lasterror = wxSTREAM_READ_ERROR; + ret = 0; + } + + return ret; +} + +wxFileOffset wxFFileInputStream::OnSysSeek(wxFileOffset pos, wxSeekMode mode) +{ + return m_file->Seek(pos, mode) ? m_file->Tell() : wxInvalidOffset; +} + +wxFileOffset wxFFileInputStream::OnSysTell() const +{ + return m_file->Tell(); +} + +bool wxFFileInputStream::IsOk() const +{ + return (wxStreamBase::IsOk() && m_file->IsOpened()); +} + +// ---------------------------------------------------------------------------- +// wxFFileOutputStream +// ---------------------------------------------------------------------------- + +wxFFileOutputStream::wxFFileOutputStream(const wxString& fileName, + const wxChar *mode) +{ + m_file = new wxFFile(fileName, mode); + m_file_destroy = true; + + if (!m_file->IsOpened()) + { + m_lasterror = wxSTREAM_WRITE_ERROR; + } + else + { + if (m_file->Error()) + m_lasterror = wxSTREAM_WRITE_ERROR; + } +} + +wxFFileOutputStream::wxFFileOutputStream(wxFFile& file) +{ + m_file = &file; + m_file_destroy = false; +} + +wxFFileOutputStream::wxFFileOutputStream() + : wxOutputStream() +{ + m_file = NULL; + m_file_destroy = false; +} + +wxFFileOutputStream::wxFFileOutputStream(FILE *file) +{ + m_file = new wxFFile(file); + m_file_destroy = true; +} + +wxFFileOutputStream::~wxFFileOutputStream() +{ + if (m_file_destroy) + { + Sync(); + delete m_file; + } +} + +size_t wxFFileOutputStream::OnSysWrite(const void *buffer, size_t size) +{ + size_t ret = m_file->Write(buffer, size); + // It is not safe to call Error() if the file is not opened. + if (!m_file->IsOpened() || m_file->Error()) + m_lasterror = wxSTREAM_WRITE_ERROR; + else + m_lasterror = wxSTREAM_NO_ERROR; + return ret; +} + +wxFileOffset wxFFileOutputStream::OnSysTell() const +{ + return m_file->Tell(); +} + +wxFileOffset wxFFileOutputStream::OnSysSeek(wxFileOffset pos, wxSeekMode mode) +{ + return m_file->Seek(pos, mode) ? m_file->Tell() : wxInvalidOffset; +} + +void wxFFileOutputStream::Sync() +{ + wxOutputStream::Sync(); + m_file->Flush(); +} + +wxFileOffset wxFFileOutputStream::GetLength() const +{ + return m_file->Length(); +} + +bool wxFFileOutputStream::IsOk() const +{ + return (wxStreamBase::IsOk() && m_file->IsOpened()); +} + +// ---------------------------------------------------------------------------- +// wxFFileStream +// ---------------------------------------------------------------------------- + +wxFFileStream::wxFFileStream(const wxString& fileName) + : wxFFileInputStream(fileName) +{ + wxFFileOutputStream::m_file = wxFFileInputStream::m_file; +} + +#endif //wxUSE_FFILE + +#endif // wxUSE_STREAMS diff --git a/Externals/wxWidgets/src/common/wincmn.cpp b/Externals/wxWidgets/src/common/wincmn.cpp index 5e772ce566..dd283b3572 100644 --- a/Externals/wxWidgets/src/common/wincmn.cpp +++ b/Externals/wxWidgets/src/common/wincmn.cpp @@ -1,3205 +1,3205 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/window.cpp -// Purpose: common (to all ports) wxWindow functions -// Author: Julian Smart, Vadim Zeitlin -// Modified by: -// Created: 13/07/98 -// RCS-ID: $Id: wincmn.cpp 52330 2008-03-05 14:19:38Z VS $ -// Copyright: (c) wxWidgets team -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#ifndef WX_PRECOMP - #include "wx/string.h" - #include "wx/log.h" - #include "wx/intl.h" - #include "wx/frame.h" - #include "wx/window.h" - #include "wx/control.h" - #include "wx/checkbox.h" - #include "wx/radiobut.h" - #include "wx/statbox.h" - #include "wx/textctrl.h" - #include "wx/settings.h" - #include "wx/dialog.h" - #include "wx/msgdlg.h" - #include "wx/statusbr.h" - #include "wx/toolbar.h" - #include "wx/dcclient.h" - #include "wx/scrolbar.h" - #include "wx/layout.h" - #include "wx/sizer.h" -#endif //WX_PRECOMP - -#if wxUSE_DRAG_AND_DROP - #include "wx/dnd.h" -#endif // wxUSE_DRAG_AND_DROP - -#if wxUSE_ACCESSIBILITY - #include "wx/access.h" -#endif - -#if wxUSE_HELP - #include "wx/cshelp.h" -#endif // wxUSE_HELP - -#if wxUSE_TOOLTIPS - #include "wx/tooltip.h" -#endif // wxUSE_TOOLTIPS - -#if wxUSE_CARET - #include "wx/caret.h" -#endif // wxUSE_CARET - -#if wxUSE_SYSTEM_OPTIONS - #include "wx/sysopt.h" -#endif - -// For reporting compile- and runtime version of GTK+ in the ctrl+alt+mclick dialog. -// The gtk includes don't pull any other headers in, at least not on my system - MR -#ifdef __WXGTK__ - #ifdef __WXGTK20__ - #include - #else - #include - #endif - extern const unsigned int gtk_major_version; - extern const unsigned int gtk_minor_version; - extern const unsigned int gtk_micro_version; -#endif - -#include "wx/platinfo.h" - -// Windows List -WXDLLIMPEXP_DATA_CORE(wxWindowList) wxTopLevelWindows; - -// ---------------------------------------------------------------------------- -// static data -// ---------------------------------------------------------------------------- - -#if defined(__WXPALMOS__) -int wxWindowBase::ms_lastControlId = 32767; -#elif defined(__WXPM__) -int wxWindowBase::ms_lastControlId = 2000; -#else -int wxWindowBase::ms_lastControlId = -200; -#endif - -IMPLEMENT_ABSTRACT_CLASS(wxWindowBase, wxEvtHandler) - -// ---------------------------------------------------------------------------- -// event table -// ---------------------------------------------------------------------------- - -BEGIN_EVENT_TABLE(wxWindowBase, wxEvtHandler) - EVT_SYS_COLOUR_CHANGED(wxWindowBase::OnSysColourChanged) - EVT_INIT_DIALOG(wxWindowBase::OnInitDialog) - EVT_MIDDLE_DOWN(wxWindowBase::OnMiddleClick) - -#if wxUSE_HELP - EVT_HELP(wxID_ANY, wxWindowBase::OnHelp) -#endif // wxUSE_HELP - -END_EVENT_TABLE() - -// ============================================================================ -// implementation of the common functionality of the wxWindow class -// ============================================================================ - -// ---------------------------------------------------------------------------- -// initialization -// ---------------------------------------------------------------------------- - -// the default initialization -wxWindowBase::wxWindowBase() -{ - // no window yet, no parent nor children - m_parent = (wxWindow *)NULL; - m_windowId = wxID_ANY; - - // no constraints on the minimal window size - m_minWidth = - m_maxWidth = wxDefaultCoord; - m_minHeight = - m_maxHeight = wxDefaultCoord; - - // invalidiated cache value - m_bestSizeCache = wxDefaultSize; - - // window are created enabled and visible by default - m_isShown = - m_isEnabled = true; - - // the default event handler is just this window - m_eventHandler = this; - -#if wxUSE_VALIDATORS - // no validator - m_windowValidator = (wxValidator *) NULL; -#endif // wxUSE_VALIDATORS - - // the colours/fonts are default for now, so leave m_font, - // m_backgroundColour and m_foregroundColour uninitialized and set those - m_hasBgCol = - m_hasFgCol = - m_hasFont = false; - m_inheritBgCol = - m_inheritFgCol = - m_inheritFont = false; - - // no style bits - m_exStyle = - m_windowStyle = 0; - - m_backgroundStyle = wxBG_STYLE_SYSTEM; - -#if wxUSE_CONSTRAINTS - // no constraints whatsoever - m_constraints = (wxLayoutConstraints *) NULL; - m_constraintsInvolvedIn = (wxWindowList *) NULL; -#endif // wxUSE_CONSTRAINTS - - m_windowSizer = (wxSizer *) NULL; - m_containingSizer = (wxSizer *) NULL; - m_autoLayout = false; - -#if wxUSE_DRAG_AND_DROP - m_dropTarget = (wxDropTarget *)NULL; -#endif // wxUSE_DRAG_AND_DROP - -#if wxUSE_TOOLTIPS - m_tooltip = (wxToolTip *)NULL; -#endif // wxUSE_TOOLTIPS - -#if wxUSE_CARET - m_caret = (wxCaret *)NULL; -#endif // wxUSE_CARET - -#if wxUSE_PALETTE - m_hasCustomPalette = false; -#endif // wxUSE_PALETTE - -#if wxUSE_ACCESSIBILITY - m_accessible = NULL; -#endif - - m_virtualSize = wxDefaultSize; - - m_scrollHelper = (wxScrollHelper *) NULL; - - m_minVirtualWidth = - m_maxVirtualWidth = wxDefaultCoord; - m_minVirtualHeight = - m_maxVirtualHeight = wxDefaultCoord; - - m_windowVariant = wxWINDOW_VARIANT_NORMAL; -#if wxUSE_SYSTEM_OPTIONS - if ( wxSystemOptions::HasOption(wxWINDOW_DEFAULT_VARIANT) ) - { - m_windowVariant = (wxWindowVariant) wxSystemOptions::GetOptionInt( wxWINDOW_DEFAULT_VARIANT ) ; - } -#endif - - // Whether we're using the current theme for this window (wxGTK only for now) - m_themeEnabled = false; - - // VZ: this one shouldn't exist... - m_isBeingDeleted = false; -} - -// common part of window creation process -bool wxWindowBase::CreateBase(wxWindowBase *parent, - wxWindowID id, - const wxPoint& WXUNUSED(pos), - const wxSize& WXUNUSED(size), - long style, - const wxValidator& wxVALIDATOR_PARAM(validator), - const wxString& name) -{ -#if wxUSE_STATBOX - // wxGTK doesn't allow to create controls with static box as the parent so - // this will result in a crash when the program is ported to wxGTK so warn - // the user about it - - // if you get this assert, the correct solution is to create the controls - // as siblings of the static box - wxASSERT_MSG( !parent || !wxDynamicCast(parent, wxStaticBox), - _T("wxStaticBox can't be used as a window parent!") ); -#endif // wxUSE_STATBOX - - // ids are limited to 16 bits under MSW so if you care about portability, - // it's not a good idea to use ids out of this range (and negative ids are - // reserved for wxWidgets own usage) - wxASSERT_MSG( id == wxID_ANY || (id >= 0 && id < 32767), - _T("invalid id value") ); - - // generate a new id if the user doesn't care about it - m_windowId = id == wxID_ANY ? NewControlId() : id; - - // don't use SetWindowStyleFlag() here, this function should only be called - // to change the flag after creation as it tries to reflect the changes in - // flags by updating the window dynamically and we don't need this here - m_windowStyle = style; - - SetName(name); - SetParent(parent); - -#if wxUSE_VALIDATORS - SetValidator(validator); -#endif // wxUSE_VALIDATORS - - // if the parent window has wxWS_EX_VALIDATE_RECURSIVELY set, we want to - // have it too - like this it's possible to set it only in the top level - // dialog/frame and all children will inherit it by defult - if ( parent && (parent->GetExtraStyle() & wxWS_EX_VALIDATE_RECURSIVELY) ) - { - SetExtraStyle(GetExtraStyle() | wxWS_EX_VALIDATE_RECURSIVELY); - } - - return true; -} - -bool wxWindowBase::ToggleWindowStyle(int flag) -{ - wxASSERT_MSG( flag, _T("flags with 0 value can't be toggled") ); - - bool rc; - long style = GetWindowStyleFlag(); - if ( style & flag ) - { - style &= ~flag; - rc = false; - } - else // currently off - { - style |= flag; - rc = true; - } - - SetWindowStyleFlag(style); - - return rc; -} - -// ---------------------------------------------------------------------------- -// destruction -// ---------------------------------------------------------------------------- - -// common clean up -wxWindowBase::~wxWindowBase() -{ - wxASSERT_MSG( GetCapture() != this, wxT("attempt to destroy window with mouse capture") ); - - // FIXME if these 2 cases result from programming errors in the user code - // we should probably assert here instead of silently fixing them - - // Just in case the window has been Closed, but we're then deleting - // immediately: don't leave dangling pointers. - wxPendingDelete.DeleteObject(this); - - // Just in case we've loaded a top-level window via LoadNativeDialog but - // we weren't a dialog class - wxTopLevelWindows.DeleteObject((wxWindow*)this); - - wxASSERT_MSG( GetChildren().GetCount() == 0, wxT("children not destroyed") ); - - // reset the top-level parent's default item if it is this widget - if ( m_parent ) - { - wxTopLevelWindow *tlw = wxDynamicCast(wxGetTopLevelParent((wxWindow*)this), - wxTopLevelWindow); - - if ( tlw ) - { - wxWindow* tmpDefaultItem = tlw->GetTmpDefaultItem(); - if ( tmpDefaultItem == this ) - tlw->SetTmpDefaultItem(NULL); - else if ( tmpDefaultItem ) - { - // A temporary default item masks the real default item, so - // temporarily unset the temporary default item so we can access the - // real default item. - tlw->SetTmpDefaultItem(NULL); - - if ( tlw->GetDefaultItem() == this ) - tlw->SetDefaultItem(NULL); - - // Set the temporary default item back. - tlw->SetTmpDefaultItem(tmpDefaultItem); - } - else if ( tlw->GetDefaultItem() == this ) - tlw->SetDefaultItem(NULL); - } - } - - // reset the dangling pointer our parent window may keep to us - if ( m_parent ) - { - m_parent->RemoveChild(this); - } - -#if wxUSE_CARET - delete m_caret; -#endif // wxUSE_CARET - -#if wxUSE_VALIDATORS - delete m_windowValidator; -#endif // wxUSE_VALIDATORS - -#if wxUSE_CONSTRAINTS - // Have to delete constraints/sizer FIRST otherwise sizers may try to look - // at deleted windows as they delete themselves. - DeleteRelatedConstraints(); - - if ( m_constraints ) - { - // This removes any dangling pointers to this window in other windows' - // constraintsInvolvedIn lists. - UnsetConstraints(m_constraints); - delete m_constraints; - m_constraints = NULL; - } -#endif // wxUSE_CONSTRAINTS - - if ( m_containingSizer ) - m_containingSizer->Detach( (wxWindow*)this ); - - delete m_windowSizer; - -#if wxUSE_DRAG_AND_DROP - delete m_dropTarget; -#endif // wxUSE_DRAG_AND_DROP - -#if wxUSE_TOOLTIPS - delete m_tooltip; -#endif // wxUSE_TOOLTIPS - -#if wxUSE_ACCESSIBILITY - delete m_accessible; -#endif - -#if wxUSE_HELP - // NB: this has to be called unconditionally, because we don't - // know whether this window has associated help text or not - wxHelpProvider *helpProvider = wxHelpProvider::Get(); - if ( helpProvider ) - helpProvider->RemoveHelp(this); -#endif -} - -void wxWindowBase::SendDestroyEvent() -{ - wxWindowDestroyEvent event; - event.SetEventObject(this); - event.SetId(GetId()); - GetEventHandler()->ProcessEvent(event); -} - -bool wxWindowBase::Destroy() -{ - delete this; - - return true; -} - -bool wxWindowBase::Close(bool force) -{ - wxCloseEvent event(wxEVT_CLOSE_WINDOW, m_windowId); - event.SetEventObject(this); - event.SetCanVeto(!force); - - // return false if window wasn't closed because the application vetoed the - // close event - return GetEventHandler()->ProcessEvent(event) && !event.GetVeto(); -} - -bool wxWindowBase::DestroyChildren() -{ - wxWindowList::compatibility_iterator node; - for ( ;; ) - { - // we iterate until the list becomes empty - node = GetChildren().GetFirst(); - if ( !node ) - break; - - wxWindow *child = node->GetData(); - - // note that we really want to call delete and not ->Destroy() here - // because we want to delete the child immediately, before we are - // deleted, and delayed deletion would result in problems as our (top - // level) child could outlive its parent - delete child; - - wxASSERT_MSG( !GetChildren().Find(child), - wxT("child didn't remove itself using RemoveChild()") ); - } - - return true; -} - -// ---------------------------------------------------------------------------- -// size/position related methods -// ---------------------------------------------------------------------------- - -// centre the window with respect to its parent in either (or both) directions -void wxWindowBase::DoCentre(int dir) -{ - wxCHECK_RET( !(dir & wxCENTRE_ON_SCREEN) && GetParent(), - _T("this method only implements centering child windows") ); - - SetSize(GetRect().CentreIn(GetParent()->GetClientSize(), dir)); -} - -// fits the window around the children -void wxWindowBase::Fit() -{ - if ( !GetChildren().empty() ) - { - SetSize(GetBestSize()); - } - //else: do nothing if we have no children -} - -// fits virtual size (ie. scrolled area etc.) around children -void wxWindowBase::FitInside() -{ - if ( GetChildren().GetCount() > 0 ) - { - SetVirtualSize( GetBestVirtualSize() ); - } -} - -// On Mac, scrollbars are explicitly children. -#ifdef __WXMAC__ -static bool wxHasRealChildren(const wxWindowBase* win) -{ - int realChildCount = 0; - - for ( wxWindowList::compatibility_iterator node = win->GetChildren().GetFirst(); - node; - node = node->GetNext() ) - { - wxWindow *win = node->GetData(); - if ( !win->IsTopLevel() && win->IsShown() && !win->IsKindOf(CLASSINFO(wxScrollBar))) - realChildCount ++; - } - return (realChildCount > 0); -} -#endif - -void wxWindowBase::InvalidateBestSize() -{ - m_bestSizeCache = wxDefaultSize; - - // parent's best size calculation may depend on its children's - // as long as child window we are in is not top level window itself - // (because the TLW size is never resized automatically) - // so let's invalidate it as well to be safe: - if (m_parent && !IsTopLevel()) - m_parent->InvalidateBestSize(); -} - -// return the size best suited for the current window -wxSize wxWindowBase::DoGetBestSize() const -{ - wxSize best; - - if ( m_windowSizer ) - { - // Adjust to window size, since the return value of GetWindowSizeForVirtualSize is - // expressed in window and not client size - wxSize minSize = m_windowSizer->GetMinSize(); - wxSize size(GetSize()); - wxSize clientSize(GetClientSize()); - - wxSize minWindowSize(minSize.x + size.x - clientSize.x, - minSize.y + size.y - clientSize.y); - - best = GetWindowSizeForVirtualSize(minWindowSize); - - return best; - } -#if wxUSE_CONSTRAINTS - else if ( m_constraints ) - { - wxConstCast(this, wxWindowBase)->SatisfyConstraints(); - - // our minimal acceptable size is such that all our windows fit inside - int maxX = 0, - maxY = 0; - - for ( wxWindowList::compatibility_iterator node = GetChildren().GetFirst(); - node; - node = node->GetNext() ) - { - wxLayoutConstraints *c = node->GetData()->GetConstraints(); - if ( !c ) - { - // it's not normal that we have an unconstrained child, but - // what can we do about it? - continue; - } - - int x = c->right.GetValue(), - y = c->bottom.GetValue(); - - if ( x > maxX ) - maxX = x; - - if ( y > maxY ) - maxY = y; - - // TODO: we must calculate the overlaps somehow, otherwise we - // will never return a size bigger than the current one :-( - } - - best = wxSize(maxX, maxY); - } -#endif // wxUSE_CONSTRAINTS - else if ( !GetChildren().empty() -#ifdef __WXMAC__ - && wxHasRealChildren(this) -#endif - ) - { - // our minimal acceptable size is such that all our visible child - // windows fit inside - int maxX = 0, - maxY = 0; - - for ( wxWindowList::compatibility_iterator node = GetChildren().GetFirst(); - node; - node = node->GetNext() ) - { - wxWindow *win = node->GetData(); - if ( win->IsTopLevel() - || !win->IsShown() -#if wxUSE_STATUSBAR - || wxDynamicCast(win, wxStatusBar) -#endif // wxUSE_STATUSBAR - ) - { - // dialogs and frames lie in different top level windows - - // don't deal with them here; as for the status bars, they - // don't lie in the client area at all - continue; - } - - int wx, wy, ww, wh; - win->GetPosition(&wx, &wy); - - // if the window hadn't been positioned yet, assume that it is in - // the origin - if ( wx == wxDefaultCoord ) - wx = 0; - if ( wy == wxDefaultCoord ) - wy = 0; - - win->GetSize(&ww, &wh); - if ( wx + ww > maxX ) - maxX = wx + ww; - if ( wy + wh > maxY ) - maxY = wy + wh; - } - - best = wxSize(maxX, maxY); - } - else // ! has children - { - // for a generic window there is no natural best size so, if the - // minimal size is not set, use the current size but take care to - // remember it as minimal size for the next time because our best size - // should be constant: otherwise we could get into a situation when the - // window is initially at some size, then expanded to a larger size and - // then, when the containing window is shrunk back (because our initial - // best size had been used for computing the parent min size), we can't - // be shrunk back any more because our best size is now bigger - wxSize size = GetMinSize(); - if ( !size.IsFullySpecified() ) - { - size.SetDefaults(GetSize()); - wxConstCast(this, wxWindowBase)->SetMinSize(size); - } - - // return as-is, unadjusted by the client size difference. - return size; - } - - // Add any difference between size and client size - wxSize diff = GetSize() - GetClientSize(); - best.x += wxMax(0, diff.x); - best.y += wxMax(0, diff.y); - - return best; -} - -// helper of GetWindowBorderSize(): as many ports don't implement support for -// wxSYS_BORDER/EDGE_X/Y metrics in their wxSystemSettings, use hard coded -// fallbacks in this case -static int wxGetMetricOrDefault(wxSystemMetric what) -{ - int rc = wxSystemSettings::GetMetric(what); - if ( rc == -1 ) - { - switch ( what ) - { - case wxSYS_BORDER_X: - case wxSYS_BORDER_Y: - // 2D border is by default 1 pixel wide - rc = 1; - break; - - case wxSYS_EDGE_X: - case wxSYS_EDGE_Y: - // 3D borders are by default 2 pixels - rc = 2; - break; - - default: - wxFAIL_MSG( _T("unexpected wxGetMetricOrDefault() argument") ); - rc = 0; - } - } - - return rc; -} - -wxSize wxWindowBase::GetWindowBorderSize() const -{ - wxSize size; - - switch ( GetBorder() ) - { - case wxBORDER_NONE: - // nothing to do, size is already (0, 0) - break; - - case wxBORDER_SIMPLE: - case wxBORDER_STATIC: - size.x = wxGetMetricOrDefault(wxSYS_BORDER_X); - size.y = wxGetMetricOrDefault(wxSYS_BORDER_Y); - break; - - case wxBORDER_SUNKEN: - case wxBORDER_RAISED: - size.x = wxMax(wxGetMetricOrDefault(wxSYS_EDGE_X), - wxGetMetricOrDefault(wxSYS_BORDER_X)); - size.y = wxMax(wxGetMetricOrDefault(wxSYS_EDGE_Y), - wxGetMetricOrDefault(wxSYS_BORDER_Y)); - break; - - case wxBORDER_DOUBLE: - size.x = wxGetMetricOrDefault(wxSYS_EDGE_X) + - wxGetMetricOrDefault(wxSYS_BORDER_X); - size.y = wxGetMetricOrDefault(wxSYS_EDGE_Y) + - wxGetMetricOrDefault(wxSYS_BORDER_Y); - break; - - default: - wxFAIL_MSG(_T("Unknown border style.")); - break; - } - - // we have borders on both sides - return size*2; -} - -wxSize wxWindowBase::GetEffectiveMinSize() const -{ - // merge the best size with the min size, giving priority to the min size - wxSize min = GetMinSize(); - if (min.x == wxDefaultCoord || min.y == wxDefaultCoord) - { - wxSize best = GetBestSize(); - if (min.x == wxDefaultCoord) min.x = best.x; - if (min.y == wxDefaultCoord) min.y = best.y; - } - return min; -} - - -void wxWindowBase::SetInitialSize(const wxSize& size) -{ - // Set the min size to the size passed in. This will usually either be - // wxDefaultSize or the size passed to this window's ctor/Create function. - SetMinSize(size); - - // Merge the size with the best size if needed - wxSize best = GetEffectiveMinSize(); - - // If the current size doesn't match then change it - if (GetSize() != best) - SetSize(best); -} - - -// by default the origin is not shifted -wxPoint wxWindowBase::GetClientAreaOrigin() const -{ - return wxPoint(0,0); -} - -wxSize wxWindowBase::ClientToWindowSize(const wxSize& size) const -{ - const wxSize diff(GetSize() - GetClientSize()); - - return wxSize(size.x == -1 ? -1 : size.x + diff.x, - size.y == -1 ? -1 : size.y + diff.y); -} - -wxSize wxWindowBase::WindowToClientSize(const wxSize& size) const -{ - const wxSize diff(GetSize() - GetClientSize()); - - return wxSize(size.x == -1 ? -1 : size.x - diff.x, - size.y == -1 ? -1 : size.y - diff.y); -} - -void wxWindowBase::SetWindowVariant( wxWindowVariant variant ) -{ - if ( m_windowVariant != variant ) - { - m_windowVariant = variant; - - DoSetWindowVariant(variant); - } -} - -void wxWindowBase::DoSetWindowVariant( wxWindowVariant variant ) -{ - // adjust the font height to correspond to our new variant (notice that - // we're only called if something really changed) - wxFont font = GetFont(); - int size = font.GetPointSize(); - switch ( variant ) - { - case wxWINDOW_VARIANT_NORMAL: - break; - - case wxWINDOW_VARIANT_SMALL: - size *= 3; - size /= 4; - break; - - case wxWINDOW_VARIANT_MINI: - size *= 2; - size /= 3; - break; - - case wxWINDOW_VARIANT_LARGE: - size *= 5; - size /= 4; - break; - - default: - wxFAIL_MSG(_T("unexpected window variant")); - break; - } - - font.SetPointSize(size); - SetFont(font); -} - -void wxWindowBase::DoSetSizeHints( int minW, int minH, - int maxW, int maxH, - int WXUNUSED(incW), int WXUNUSED(incH) ) -{ - wxCHECK_RET( (minW == wxDefaultCoord || maxW == wxDefaultCoord || minW <= maxW) && - (minH == wxDefaultCoord || maxH == wxDefaultCoord || minH <= maxH), - _T("min width/height must be less than max width/height!") ); - - m_minWidth = minW; - m_maxWidth = maxW; - m_minHeight = minH; - m_maxHeight = maxH; -} - - -void wxWindowBase::SetVirtualSizeHints( int minW, int minH, - int maxW, int maxH ) -{ - m_minVirtualWidth = minW; - m_maxVirtualWidth = maxW; - m_minVirtualHeight = minH; - m_maxVirtualHeight = maxH; -} - -void wxWindowBase::DoSetVirtualSize( int x, int y ) -{ - if ( m_minVirtualWidth != wxDefaultCoord && m_minVirtualWidth > x ) - x = m_minVirtualWidth; - if ( m_maxVirtualWidth != wxDefaultCoord && m_maxVirtualWidth < x ) - x = m_maxVirtualWidth; - if ( m_minVirtualHeight != wxDefaultCoord && m_minVirtualHeight > y ) - y = m_minVirtualHeight; - if ( m_maxVirtualHeight != wxDefaultCoord && m_maxVirtualHeight < y ) - y = m_maxVirtualHeight; - - m_virtualSize = wxSize(x, y); -} - -wxSize wxWindowBase::DoGetVirtualSize() const -{ - // we should use the entire client area so if it is greater than our - // virtual size, expand it to fit (otherwise if the window is big enough we - // wouldn't be using parts of it) - wxSize size = GetClientSize(); - if ( m_virtualSize.x > size.x ) - size.x = m_virtualSize.x; - - if ( m_virtualSize.y >= size.y ) - size.y = m_virtualSize.y; - - return size; -} - -void wxWindowBase::DoGetScreenPosition(int *x, int *y) const -{ - // screen position is the same as (0, 0) in client coords for non TLWs (and - // TLWs override this method) - if ( x ) - *x = 0; - if ( y ) - *y = 0; - - ClientToScreen(x, y); -} - -// ---------------------------------------------------------------------------- -// show/hide/enable/disable the window -// ---------------------------------------------------------------------------- - -bool wxWindowBase::Show(bool show) -{ - if ( show != m_isShown ) - { - m_isShown = show; - - return true; - } - else - { - return false; - } -} - -bool wxWindowBase::Enable(bool enable) -{ - if ( enable != m_isEnabled ) - { - m_isEnabled = enable; - - return true; - } - else - { - return false; - } -} - -bool wxWindowBase::IsShownOnScreen() const -{ - // A window is shown on screen if it itself is shown and so are all its - // parents. But if a window is toplevel one, then its always visible on - // screen if IsShown() returns true, even if it has a hidden parent. - return IsShown() && - (IsTopLevel() || !GetParent() || GetParent()->IsShownOnScreen()); -} - -// ---------------------------------------------------------------------------- -// RTTI -// ---------------------------------------------------------------------------- - -bool wxWindowBase::IsTopLevel() const -{ - return false; -} - -// ---------------------------------------------------------------------------- -// reparenting the window -// ---------------------------------------------------------------------------- - -void wxWindowBase::AddChild(wxWindowBase *child) -{ - wxCHECK_RET( child, wxT("can't add a NULL child") ); - - // this should never happen and it will lead to a crash later if it does - // because RemoveChild() will remove only one node from the children list - // and the other(s) one(s) will be left with dangling pointers in them - wxASSERT_MSG( !GetChildren().Find((wxWindow*)child), _T("AddChild() called twice") ); - - GetChildren().Append((wxWindow*)child); - child->SetParent(this); -} - -void wxWindowBase::RemoveChild(wxWindowBase *child) -{ - wxCHECK_RET( child, wxT("can't remove a NULL child") ); - - GetChildren().DeleteObject((wxWindow *)child); - child->SetParent(NULL); -} - -bool wxWindowBase::Reparent(wxWindowBase *newParent) -{ - wxWindow *oldParent = GetParent(); - if ( newParent == oldParent ) - { - // nothing done - return false; - } - - // unlink this window from the existing parent. - if ( oldParent ) - { - oldParent->RemoveChild(this); - } - else - { - wxTopLevelWindows.DeleteObject((wxWindow *)this); - } - - // add it to the new one - if ( newParent ) - { - newParent->AddChild(this); - } - else - { - wxTopLevelWindows.Append((wxWindow *)this); - } - - return true; -} - -// ---------------------------------------------------------------------------- -// event handler stuff -// ---------------------------------------------------------------------------- - -void wxWindowBase::PushEventHandler(wxEvtHandler *handler) -{ - wxEvtHandler *handlerOld = GetEventHandler(); - - handler->SetNextHandler(handlerOld); - - if ( handlerOld ) - GetEventHandler()->SetPreviousHandler(handler); - - SetEventHandler(handler); -} - -wxEvtHandler *wxWindowBase::PopEventHandler(bool deleteHandler) -{ - wxEvtHandler *handlerA = GetEventHandler(); - if ( handlerA ) - { - wxEvtHandler *handlerB = handlerA->GetNextHandler(); - handlerA->SetNextHandler((wxEvtHandler *)NULL); - - if ( handlerB ) - handlerB->SetPreviousHandler((wxEvtHandler *)NULL); - SetEventHandler(handlerB); - - if ( deleteHandler ) - { - delete handlerA; - handlerA = (wxEvtHandler *)NULL; - } - } - - return handlerA; -} - -bool wxWindowBase::RemoveEventHandler(wxEvtHandler *handler) -{ - wxCHECK_MSG( handler, false, _T("RemoveEventHandler(NULL) called") ); - - wxEvtHandler *handlerPrev = NULL, - *handlerCur = GetEventHandler(); - while ( handlerCur ) - { - wxEvtHandler *handlerNext = handlerCur->GetNextHandler(); - - if ( handlerCur == handler ) - { - if ( handlerPrev ) - { - handlerPrev->SetNextHandler(handlerNext); - } - else - { - SetEventHandler(handlerNext); - } - - if ( handlerNext ) - { - handlerNext->SetPreviousHandler ( handlerPrev ); - } - - handler->SetNextHandler(NULL); - handler->SetPreviousHandler(NULL); - - return true; - } - - handlerPrev = handlerCur; - handlerCur = handlerNext; - } - - wxFAIL_MSG( _T("where has the event handler gone?") ); - - return false; -} - -// ---------------------------------------------------------------------------- -// colours, fonts &c -// ---------------------------------------------------------------------------- - -void wxWindowBase::InheritAttributes() -{ - const wxWindowBase * const parent = GetParent(); - if ( !parent ) - return; - - // we only inherit attributes which had been explicitly set for the parent - // which ensures that this only happens if the user really wants it and - // not by default which wouldn't make any sense in modern GUIs where the - // controls don't all use the same fonts (nor colours) - if ( parent->m_inheritFont && !m_hasFont ) - SetFont(parent->GetFont()); - - // in addition, there is a possibility to explicitly forbid inheriting - // colours at each class level by overriding ShouldInheritColours() - if ( ShouldInheritColours() ) - { - if ( parent->m_inheritFgCol && !m_hasFgCol ) - SetForegroundColour(parent->GetForegroundColour()); - - // inheriting (solid) background colour is wrong as it totally breaks - // any kind of themed backgrounds - // - // instead, the controls should use the same background as their parent - // (ideally by not drawing it at all) -#if 0 - if ( parent->m_inheritBgCol && !m_hasBgCol ) - SetBackgroundColour(parent->GetBackgroundColour()); -#endif // 0 - } -} - -/* static */ wxVisualAttributes -wxWindowBase::GetClassDefaultAttributes(wxWindowVariant WXUNUSED(variant)) -{ - // it is important to return valid values for all attributes from here, - // GetXXX() below rely on this - wxVisualAttributes attrs; - attrs.font = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT); - attrs.colFg = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT); - - // On Smartphone/PocketPC, wxSYS_COLOUR_WINDOW is a better reflection of - // the usual background colour than wxSYS_COLOUR_BTNFACE. - // It's a pity that wxSYS_COLOUR_WINDOW isn't always a suitable background - // colour on other platforms. - -#if defined(__WXWINCE__) && (defined(__SMARTPHONE__) || defined(__POCKETPC__)) - attrs.colBg = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW); -#else - attrs.colBg = wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE); -#endif - return attrs; -} - -wxColour wxWindowBase::GetBackgroundColour() const -{ - if ( !m_backgroundColour.Ok() ) - { - wxASSERT_MSG( !m_hasBgCol, _T("we have invalid explicit bg colour?") ); - - // get our default background colour - wxColour colBg = GetDefaultAttributes().colBg; - - // we must return some valid colour to avoid redoing this every time - // and also to avoid surprizing the applications written for older - // wxWidgets versions where GetBackgroundColour() always returned - // something -- so give them something even if it doesn't make sense - // for this window (e.g. it has a themed background) - if ( !colBg.Ok() ) - colBg = GetClassDefaultAttributes().colBg; - - return colBg; - } - else - return m_backgroundColour; -} - -wxColour wxWindowBase::GetForegroundColour() const -{ - // logic is the same as above - if ( !m_hasFgCol && !m_foregroundColour.Ok() ) - { - wxASSERT_MSG( !m_hasFgCol, _T("we have invalid explicit fg colour?") ); - - wxColour colFg = GetDefaultAttributes().colFg; - - if ( !colFg.Ok() ) - colFg = GetClassDefaultAttributes().colFg; - - return colFg; - } - else - return m_foregroundColour; -} - -bool wxWindowBase::SetBackgroundColour( const wxColour &colour ) -{ - if ( colour == m_backgroundColour ) - return false; - - m_hasBgCol = colour.Ok(); - if ( m_backgroundStyle != wxBG_STYLE_CUSTOM ) - m_backgroundStyle = m_hasBgCol ? wxBG_STYLE_COLOUR : wxBG_STYLE_SYSTEM; - - m_inheritBgCol = m_hasBgCol; - m_backgroundColour = colour; - SetThemeEnabled( !m_hasBgCol && !m_foregroundColour.Ok() ); - return true; -} - -bool wxWindowBase::SetForegroundColour( const wxColour &colour ) -{ - if (colour == m_foregroundColour ) - return false; - - m_hasFgCol = colour.Ok(); - m_inheritFgCol = m_hasFgCol; - m_foregroundColour = colour; - SetThemeEnabled( !m_hasFgCol && !m_backgroundColour.Ok() ); - return true; -} - -bool wxWindowBase::SetCursor(const wxCursor& cursor) -{ - // setting an invalid cursor is ok, it means that we don't have any special - // cursor - if ( m_cursor.IsSameAs(cursor) ) - { - // no change - return false; - } - - m_cursor = cursor; - - return true; -} - -wxFont wxWindowBase::GetFont() const -{ - // logic is the same as in GetBackgroundColour() - if ( !m_font.Ok() ) - { - wxASSERT_MSG( !m_hasFont, _T("we have invalid explicit font?") ); - - wxFont font = GetDefaultAttributes().font; - if ( !font.Ok() ) - font = GetClassDefaultAttributes().font; - - return font; - } - else - return m_font; -} - -bool wxWindowBase::SetFont(const wxFont& font) -{ - if ( font == m_font ) - { - // no change - return false; - } - - m_font = font; - m_hasFont = font.Ok(); - m_inheritFont = m_hasFont; - - InvalidateBestSize(); - - return true; -} - -#if wxUSE_PALETTE - -void wxWindowBase::SetPalette(const wxPalette& pal) -{ - m_hasCustomPalette = true; - m_palette = pal; - - // VZ: can anyone explain me what do we do here? - wxWindowDC d((wxWindow *) this); - d.SetPalette(pal); -} - -wxWindow *wxWindowBase::GetAncestorWithCustomPalette() const -{ - wxWindow *win = (wxWindow *)this; - while ( win && !win->HasCustomPalette() ) - { - win = win->GetParent(); - } - - return win; -} - -#endif // wxUSE_PALETTE - -#if wxUSE_CARET -void wxWindowBase::SetCaret(wxCaret *caret) -{ - if ( m_caret ) - { - delete m_caret; - } - - m_caret = caret; - - if ( m_caret ) - { - wxASSERT_MSG( m_caret->GetWindow() == this, - wxT("caret should be created associated to this window") ); - } -} -#endif // wxUSE_CARET - -#if wxUSE_VALIDATORS -// ---------------------------------------------------------------------------- -// validators -// ---------------------------------------------------------------------------- - -void wxWindowBase::SetValidator(const wxValidator& validator) -{ - if ( m_windowValidator ) - delete m_windowValidator; - - m_windowValidator = (wxValidator *)validator.Clone(); - - if ( m_windowValidator ) - m_windowValidator->SetWindow(this); -} -#endif // wxUSE_VALIDATORS - -// ---------------------------------------------------------------------------- -// update region stuff -// ---------------------------------------------------------------------------- - -wxRect wxWindowBase::GetUpdateClientRect() const -{ - wxRegion rgnUpdate = GetUpdateRegion(); - rgnUpdate.Intersect(GetClientRect()); - wxRect rectUpdate = rgnUpdate.GetBox(); - wxPoint ptOrigin = GetClientAreaOrigin(); - rectUpdate.x -= ptOrigin.x; - rectUpdate.y -= ptOrigin.y; - - return rectUpdate; -} - -bool wxWindowBase::DoIsExposed(int x, int y) const -{ - return m_updateRegion.Contains(x, y) != wxOutRegion; -} - -bool wxWindowBase::DoIsExposed(int x, int y, int w, int h) const -{ - return m_updateRegion.Contains(x, y, w, h) != wxOutRegion; -} - -void wxWindowBase::ClearBackground() -{ - // wxGTK uses its own version, no need to add never used code -#ifndef __WXGTK__ - wxClientDC dc((wxWindow *)this); - wxBrush brush(GetBackgroundColour(), wxSOLID); - dc.SetBackground(brush); - dc.Clear(); -#endif // __WXGTK__ -} - -// ---------------------------------------------------------------------------- -// find child window by id or name -// ---------------------------------------------------------------------------- - -wxWindow *wxWindowBase::FindWindow(long id) const -{ - if ( id == m_windowId ) - return (wxWindow *)this; - - wxWindowBase *res = (wxWindow *)NULL; - wxWindowList::compatibility_iterator node; - for ( node = m_children.GetFirst(); node && !res; node = node->GetNext() ) - { - wxWindowBase *child = node->GetData(); - res = child->FindWindow( id ); - } - - return (wxWindow *)res; -} - -wxWindow *wxWindowBase::FindWindow(const wxString& name) const -{ - if ( name == m_windowName ) - return (wxWindow *)this; - - wxWindowBase *res = (wxWindow *)NULL; - wxWindowList::compatibility_iterator node; - for ( node = m_children.GetFirst(); node && !res; node = node->GetNext() ) - { - wxWindow *child = node->GetData(); - res = child->FindWindow(name); - } - - return (wxWindow *)res; -} - - -// find any window by id or name or label: If parent is non-NULL, look through -// children for a label or title matching the specified string. If NULL, look -// through all top-level windows. -// -// to avoid duplicating code we reuse the same helper function but with -// different comparators - -typedef bool (*wxFindWindowCmp)(const wxWindow *win, - const wxString& label, long id); - -static -bool wxFindWindowCmpLabels(const wxWindow *win, const wxString& label, - long WXUNUSED(id)) -{ - return win->GetLabel() == label; -} - -static -bool wxFindWindowCmpNames(const wxWindow *win, const wxString& label, - long WXUNUSED(id)) -{ - return win->GetName() == label; -} - -static -bool wxFindWindowCmpIds(const wxWindow *win, const wxString& WXUNUSED(label), - long id) -{ - return win->GetId() == id; -} - -// recursive helper for the FindWindowByXXX() functions -static -wxWindow *wxFindWindowRecursively(const wxWindow *parent, - const wxString& label, - long id, - wxFindWindowCmp cmp) -{ - if ( parent ) - { - // see if this is the one we're looking for - if ( (*cmp)(parent, label, id) ) - return (wxWindow *)parent; - - // It wasn't, so check all its children - for ( wxWindowList::compatibility_iterator node = parent->GetChildren().GetFirst(); - node; - node = node->GetNext() ) - { - // recursively check each child - wxWindow *win = (wxWindow *)node->GetData(); - wxWindow *retwin = wxFindWindowRecursively(win, label, id, cmp); - if (retwin) - return retwin; - } - } - - // Not found - return NULL; -} - -// helper for FindWindowByXXX() -static -wxWindow *wxFindWindowHelper(const wxWindow *parent, - const wxString& label, - long id, - wxFindWindowCmp cmp) -{ - if ( parent ) - { - // just check parent and all its children - return wxFindWindowRecursively(parent, label, id, cmp); - } - - // start at very top of wx's windows - for ( wxWindowList::compatibility_iterator node = wxTopLevelWindows.GetFirst(); - node; - node = node->GetNext() ) - { - // recursively check each window & its children - wxWindow *win = node->GetData(); - wxWindow *retwin = wxFindWindowRecursively(win, label, id, cmp); - if (retwin) - return retwin; - } - - return NULL; -} - -/* static */ -wxWindow * -wxWindowBase::FindWindowByLabel(const wxString& title, const wxWindow *parent) -{ - return wxFindWindowHelper(parent, title, 0, wxFindWindowCmpLabels); -} - -/* static */ -wxWindow * -wxWindowBase::FindWindowByName(const wxString& title, const wxWindow *parent) -{ - wxWindow *win = wxFindWindowHelper(parent, title, 0, wxFindWindowCmpNames); - - if ( !win ) - { - // fall back to the label - win = FindWindowByLabel(title, parent); - } - - return win; -} - -/* static */ -wxWindow * -wxWindowBase::FindWindowById( long id, const wxWindow* parent ) -{ - return wxFindWindowHelper(parent, wxEmptyString, id, wxFindWindowCmpIds); -} - -// ---------------------------------------------------------------------------- -// dialog oriented functions -// ---------------------------------------------------------------------------- - -void wxWindowBase::MakeModal(bool modal) -{ - // Disable all other windows - if ( IsTopLevel() ) - { - wxWindowList::compatibility_iterator node = wxTopLevelWindows.GetFirst(); - while (node) - { - wxWindow *win = node->GetData(); - if (win != this) - win->Enable(!modal); - - node = node->GetNext(); - } - } -} - -bool wxWindowBase::Validate() -{ -#if wxUSE_VALIDATORS - bool recurse = (GetExtraStyle() & wxWS_EX_VALIDATE_RECURSIVELY) != 0; - - wxWindowList::compatibility_iterator node; - for ( node = m_children.GetFirst(); node; node = node->GetNext() ) - { - wxWindowBase *child = node->GetData(); - wxValidator *validator = child->GetValidator(); - if ( validator && !validator->Validate((wxWindow *)this) ) - { - return false; - } - - if ( recurse && !child->Validate() ) - { - return false; - } - } -#endif // wxUSE_VALIDATORS - - return true; -} - -bool wxWindowBase::TransferDataToWindow() -{ -#if wxUSE_VALIDATORS - bool recurse = (GetExtraStyle() & wxWS_EX_VALIDATE_RECURSIVELY) != 0; - - wxWindowList::compatibility_iterator node; - for ( node = m_children.GetFirst(); node; node = node->GetNext() ) - { - wxWindowBase *child = node->GetData(); - wxValidator *validator = child->GetValidator(); - if ( validator && !validator->TransferToWindow() ) - { - wxLogWarning(_("Could not transfer data to window")); -#if wxUSE_LOG - wxLog::FlushActive(); -#endif // wxUSE_LOG - - return false; - } - - if ( recurse ) - { - if ( !child->TransferDataToWindow() ) - { - // warning already given - return false; - } - } - } -#endif // wxUSE_VALIDATORS - - return true; -} - -bool wxWindowBase::TransferDataFromWindow() -{ -#if wxUSE_VALIDATORS - bool recurse = (GetExtraStyle() & wxWS_EX_VALIDATE_RECURSIVELY) != 0; - - wxWindowList::compatibility_iterator node; - for ( node = m_children.GetFirst(); node; node = node->GetNext() ) - { - wxWindow *child = node->GetData(); - wxValidator *validator = child->GetValidator(); - if ( validator && !validator->TransferFromWindow() ) - { - // nop warning here because the application is supposed to give - // one itself - we don't know here what might have gone wrongly - - return false; - } - - if ( recurse ) - { - if ( !child->TransferDataFromWindow() ) - { - // warning already given - return false; - } - } - } -#endif // wxUSE_VALIDATORS - - return true; -} - -void wxWindowBase::InitDialog() -{ - wxInitDialogEvent event(GetId()); - event.SetEventObject( this ); - GetEventHandler()->ProcessEvent(event); -} - -// ---------------------------------------------------------------------------- -// context-sensitive help support -// ---------------------------------------------------------------------------- - -#if wxUSE_HELP - -// associate this help text with this window -void wxWindowBase::SetHelpText(const wxString& text) -{ - wxHelpProvider *helpProvider = wxHelpProvider::Get(); - if ( helpProvider ) - { - helpProvider->AddHelp(this, text); - } -} - -// associate this help text with all windows with the same id as this -// one -void wxWindowBase::SetHelpTextForId(const wxString& text) -{ - wxHelpProvider *helpProvider = wxHelpProvider::Get(); - if ( helpProvider ) - { - helpProvider->AddHelp(GetId(), text); - } -} - -// get the help string associated with this window (may be empty) -// default implementation forwards calls to the help provider -wxString -wxWindowBase::GetHelpTextAtPoint(const wxPoint & WXUNUSED(pt), - wxHelpEvent::Origin WXUNUSED(origin)) const -{ - wxString text; - wxHelpProvider *helpProvider = wxHelpProvider::Get(); - if ( helpProvider ) - { - text = helpProvider->GetHelp(this); - } - - return text; -} - -// show help for this window -void wxWindowBase::OnHelp(wxHelpEvent& event) -{ - wxHelpProvider *helpProvider = wxHelpProvider::Get(); - if ( helpProvider ) - { - wxPoint pos = event.GetPosition(); - const wxHelpEvent::Origin origin = event.GetOrigin(); - if ( origin == wxHelpEvent::Origin_Keyboard ) - { - // if the help event was generated from keyboard it shouldn't - // appear at the mouse position (which is still the only position - // associated with help event) if the mouse is far away, although - // we still do use the mouse position if it's over the window - // because we suppose the user looks approximately at the mouse - // already and so it would be more convenient than showing tooltip - // at some arbitrary position which can be quite far from it - const wxRect rectClient = GetClientRect(); - if ( !rectClient.Contains(ScreenToClient(pos)) ) - { - // position help slightly under and to the right of this window - pos = ClientToScreen(wxPoint( - 2*GetCharWidth(), - rectClient.height + GetCharHeight() - )); - } - } - - if ( helpProvider->ShowHelpAtPoint(this, pos, origin) ) - { - // skip the event.Skip() below - return; - } - } - - event.Skip(); -} - -#endif // wxUSE_HELP - -// ---------------------------------------------------------------------------- -// tooltips -// ---------------------------------------------------------------------------- - -#if wxUSE_TOOLTIPS - -void wxWindowBase::SetToolTip( const wxString &tip ) -{ - // don't create the new tooltip if we already have one - if ( m_tooltip ) - { - m_tooltip->SetTip( tip ); - } - else - { - SetToolTip( new wxToolTip( tip ) ); - } - - // setting empty tooltip text does not remove the tooltip any more - use - // SetToolTip((wxToolTip *)NULL) for this -} - -void wxWindowBase::DoSetToolTip(wxToolTip *tooltip) -{ - if ( m_tooltip != tooltip ) - { - if ( m_tooltip ) - delete m_tooltip; - - m_tooltip = tooltip; - } -} - -#endif // wxUSE_TOOLTIPS - -// ---------------------------------------------------------------------------- -// constraints and sizers -// ---------------------------------------------------------------------------- - -#if wxUSE_CONSTRAINTS - -void wxWindowBase::SetConstraints( wxLayoutConstraints *constraints ) -{ - if ( m_constraints ) - { - UnsetConstraints(m_constraints); - delete m_constraints; - } - m_constraints = constraints; - if ( m_constraints ) - { - // Make sure other windows know they're part of a 'meaningful relationship' - if ( m_constraints->left.GetOtherWindow() && (m_constraints->left.GetOtherWindow() != this) ) - m_constraints->left.GetOtherWindow()->AddConstraintReference(this); - if ( m_constraints->top.GetOtherWindow() && (m_constraints->top.GetOtherWindow() != this) ) - m_constraints->top.GetOtherWindow()->AddConstraintReference(this); - if ( m_constraints->right.GetOtherWindow() && (m_constraints->right.GetOtherWindow() != this) ) - m_constraints->right.GetOtherWindow()->AddConstraintReference(this); - if ( m_constraints->bottom.GetOtherWindow() && (m_constraints->bottom.GetOtherWindow() != this) ) - m_constraints->bottom.GetOtherWindow()->AddConstraintReference(this); - if ( m_constraints->width.GetOtherWindow() && (m_constraints->width.GetOtherWindow() != this) ) - m_constraints->width.GetOtherWindow()->AddConstraintReference(this); - if ( m_constraints->height.GetOtherWindow() && (m_constraints->height.GetOtherWindow() != this) ) - m_constraints->height.GetOtherWindow()->AddConstraintReference(this); - if ( m_constraints->centreX.GetOtherWindow() && (m_constraints->centreX.GetOtherWindow() != this) ) - m_constraints->centreX.GetOtherWindow()->AddConstraintReference(this); - if ( m_constraints->centreY.GetOtherWindow() && (m_constraints->centreY.GetOtherWindow() != this) ) - m_constraints->centreY.GetOtherWindow()->AddConstraintReference(this); - } -} - -// This removes any dangling pointers to this window in other windows' -// constraintsInvolvedIn lists. -void wxWindowBase::UnsetConstraints(wxLayoutConstraints *c) -{ - if ( c ) - { - if ( c->left.GetOtherWindow() && (c->top.GetOtherWindow() != this) ) - c->left.GetOtherWindow()->RemoveConstraintReference(this); - if ( c->top.GetOtherWindow() && (c->top.GetOtherWindow() != this) ) - c->top.GetOtherWindow()->RemoveConstraintReference(this); - if ( c->right.GetOtherWindow() && (c->right.GetOtherWindow() != this) ) - c->right.GetOtherWindow()->RemoveConstraintReference(this); - if ( c->bottom.GetOtherWindow() && (c->bottom.GetOtherWindow() != this) ) - c->bottom.GetOtherWindow()->RemoveConstraintReference(this); - if ( c->width.GetOtherWindow() && (c->width.GetOtherWindow() != this) ) - c->width.GetOtherWindow()->RemoveConstraintReference(this); - if ( c->height.GetOtherWindow() && (c->height.GetOtherWindow() != this) ) - c->height.GetOtherWindow()->RemoveConstraintReference(this); - if ( c->centreX.GetOtherWindow() && (c->centreX.GetOtherWindow() != this) ) - c->centreX.GetOtherWindow()->RemoveConstraintReference(this); - if ( c->centreY.GetOtherWindow() && (c->centreY.GetOtherWindow() != this) ) - c->centreY.GetOtherWindow()->RemoveConstraintReference(this); - } -} - -// Back-pointer to other windows we're involved with, so if we delete this -// window, we must delete any constraints we're involved with. -void wxWindowBase::AddConstraintReference(wxWindowBase *otherWin) -{ - if ( !m_constraintsInvolvedIn ) - m_constraintsInvolvedIn = new wxWindowList; - if ( !m_constraintsInvolvedIn->Find((wxWindow *)otherWin) ) - m_constraintsInvolvedIn->Append((wxWindow *)otherWin); -} - -// REMOVE back-pointer to other windows we're involved with. -void wxWindowBase::RemoveConstraintReference(wxWindowBase *otherWin) -{ - if ( m_constraintsInvolvedIn ) - m_constraintsInvolvedIn->DeleteObject((wxWindow *)otherWin); -} - -// Reset any constraints that mention this window -void wxWindowBase::DeleteRelatedConstraints() -{ - if ( m_constraintsInvolvedIn ) - { - wxWindowList::compatibility_iterator node = m_constraintsInvolvedIn->GetFirst(); - while (node) - { - wxWindow *win = node->GetData(); - wxLayoutConstraints *constr = win->GetConstraints(); - - // Reset any constraints involving this window - if ( constr ) - { - constr->left.ResetIfWin(this); - constr->top.ResetIfWin(this); - constr->right.ResetIfWin(this); - constr->bottom.ResetIfWin(this); - constr->width.ResetIfWin(this); - constr->height.ResetIfWin(this); - constr->centreX.ResetIfWin(this); - constr->centreY.ResetIfWin(this); - } - - wxWindowList::compatibility_iterator next = node->GetNext(); - m_constraintsInvolvedIn->Erase(node); - node = next; - } - - delete m_constraintsInvolvedIn; - m_constraintsInvolvedIn = (wxWindowList *) NULL; - } -} - -#endif // wxUSE_CONSTRAINTS - -void wxWindowBase::SetSizer(wxSizer *sizer, bool deleteOld) -{ - if ( sizer == m_windowSizer) - return; - - if ( m_windowSizer ) - { - m_windowSizer->SetContainingWindow(NULL); - - if ( deleteOld ) - delete m_windowSizer; - } - - m_windowSizer = sizer; - if ( m_windowSizer ) - { - m_windowSizer->SetContainingWindow((wxWindow *)this); - } - - SetAutoLayout(m_windowSizer != NULL); -} - -void wxWindowBase::SetSizerAndFit(wxSizer *sizer, bool deleteOld) -{ - SetSizer( sizer, deleteOld ); - sizer->SetSizeHints( (wxWindow*) this ); -} - - -void wxWindowBase::SetContainingSizer(wxSizer* sizer) -{ - // adding a window to a sizer twice is going to result in fatal and - // hard to debug problems later because when deleting the second - // associated wxSizerItem we're going to dereference a dangling - // pointer; so try to detect this as early as possible - wxASSERT_MSG( !sizer || m_containingSizer != sizer, - _T("Adding a window to the same sizer twice?") ); - - m_containingSizer = sizer; -} - -#if wxUSE_CONSTRAINTS - -void wxWindowBase::SatisfyConstraints() -{ - wxLayoutConstraints *constr = GetConstraints(); - bool wasOk = constr && constr->AreSatisfied(); - - ResetConstraints(); // Mark all constraints as unevaluated - - int noChanges = 1; - - // if we're a top level panel (i.e. our parent is frame/dialog), our - // own constraints will never be satisfied any more unless we do it - // here - if ( wasOk ) - { - while ( noChanges > 0 ) - { - LayoutPhase1(&noChanges); - } - } - - LayoutPhase2(&noChanges); -} - -#endif // wxUSE_CONSTRAINTS - -bool wxWindowBase::Layout() -{ - // If there is a sizer, use it instead of the constraints - if ( GetSizer() ) - { - int w = 0, h = 0; - GetVirtualSize(&w, &h); - GetSizer()->SetDimension( 0, 0, w, h ); - } -#if wxUSE_CONSTRAINTS - else - { - SatisfyConstraints(); // Find the right constraints values - SetConstraintSizes(); // Recursively set the real window sizes - } -#endif - - return true; -} - -#if wxUSE_CONSTRAINTS - -// first phase of the constraints evaluation: set our own constraints -bool wxWindowBase::LayoutPhase1(int *noChanges) -{ - wxLayoutConstraints *constr = GetConstraints(); - - return !constr || constr->SatisfyConstraints(this, noChanges); -} - -// second phase: set the constraints for our children -bool wxWindowBase::LayoutPhase2(int *noChanges) -{ - *noChanges = 0; - - // Layout children - DoPhase(1); - - // Layout grand children - DoPhase(2); - - return true; -} - -// Do a phase of evaluating child constraints -bool wxWindowBase::DoPhase(int phase) -{ - // the list containing the children for which the constraints are already - // set correctly - wxWindowList succeeded; - - // the max number of iterations we loop before concluding that we can't set - // the constraints - static const int maxIterations = 500; - - for ( int noIterations = 0; noIterations < maxIterations; noIterations++ ) - { - int noChanges = 0; - - // loop over all children setting their constraints - for ( wxWindowList::compatibility_iterator node = GetChildren().GetFirst(); - node; - node = node->GetNext() ) - { - wxWindow *child = node->GetData(); - if ( child->IsTopLevel() ) - { - // top level children are not inside our client area - continue; - } - - if ( !child->GetConstraints() || succeeded.Find(child) ) - { - // this one is either already ok or nothing we can do about it - continue; - } - - int tempNoChanges = 0; - bool success = phase == 1 ? child->LayoutPhase1(&tempNoChanges) - : child->LayoutPhase2(&tempNoChanges); - noChanges += tempNoChanges; - - if ( success ) - { - succeeded.Append(child); - } - } - - if ( !noChanges ) - { - // constraints are set - break; - } - } - - return true; -} - -void wxWindowBase::ResetConstraints() -{ - wxLayoutConstraints *constr = GetConstraints(); - if ( constr ) - { - constr->left.SetDone(false); - constr->top.SetDone(false); - constr->right.SetDone(false); - constr->bottom.SetDone(false); - constr->width.SetDone(false); - constr->height.SetDone(false); - constr->centreX.SetDone(false); - constr->centreY.SetDone(false); - } - - wxWindowList::compatibility_iterator node = GetChildren().GetFirst(); - while (node) - { - wxWindow *win = node->GetData(); - if ( !win->IsTopLevel() ) - win->ResetConstraints(); - node = node->GetNext(); - } -} - -// Need to distinguish between setting the 'fake' size for windows and sizers, -// and setting the real values. -void wxWindowBase::SetConstraintSizes(bool recurse) -{ - wxLayoutConstraints *constr = GetConstraints(); - if ( constr && constr->AreSatisfied() ) - { - int x = constr->left.GetValue(); - int y = constr->top.GetValue(); - int w = constr->width.GetValue(); - int h = constr->height.GetValue(); - - if ( (constr->width.GetRelationship() != wxAsIs ) || - (constr->height.GetRelationship() != wxAsIs) ) - { - SetSize(x, y, w, h); - } - else - { - // If we don't want to resize this window, just move it... - Move(x, y); - } - } - else if ( constr ) - { - wxLogDebug(wxT("Constraints not satisfied for %s named '%s'."), - GetClassInfo()->GetClassName(), - GetName().c_str()); - } - - if ( recurse ) - { - wxWindowList::compatibility_iterator node = GetChildren().GetFirst(); - while (node) - { - wxWindow *win = node->GetData(); - if ( !win->IsTopLevel() && win->GetConstraints() ) - win->SetConstraintSizes(); - node = node->GetNext(); - } - } -} - -// Only set the size/position of the constraint (if any) -void wxWindowBase::SetSizeConstraint(int x, int y, int w, int h) -{ - wxLayoutConstraints *constr = GetConstraints(); - if ( constr ) - { - if ( x != wxDefaultCoord ) - { - constr->left.SetValue(x); - constr->left.SetDone(true); - } - if ( y != wxDefaultCoord ) - { - constr->top.SetValue(y); - constr->top.SetDone(true); - } - if ( w != wxDefaultCoord ) - { - constr->width.SetValue(w); - constr->width.SetDone(true); - } - if ( h != wxDefaultCoord ) - { - constr->height.SetValue(h); - constr->height.SetDone(true); - } - } -} - -void wxWindowBase::MoveConstraint(int x, int y) -{ - wxLayoutConstraints *constr = GetConstraints(); - if ( constr ) - { - if ( x != wxDefaultCoord ) - { - constr->left.SetValue(x); - constr->left.SetDone(true); - } - if ( y != wxDefaultCoord ) - { - constr->top.SetValue(y); - constr->top.SetDone(true); - } - } -} - -void wxWindowBase::GetSizeConstraint(int *w, int *h) const -{ - wxLayoutConstraints *constr = GetConstraints(); - if ( constr ) - { - *w = constr->width.GetValue(); - *h = constr->height.GetValue(); - } - else - GetSize(w, h); -} - -void wxWindowBase::GetClientSizeConstraint(int *w, int *h) const -{ - wxLayoutConstraints *constr = GetConstraints(); - if ( constr ) - { - *w = constr->width.GetValue(); - *h = constr->height.GetValue(); - } - else - GetClientSize(w, h); -} - -void wxWindowBase::GetPositionConstraint(int *x, int *y) const -{ - wxLayoutConstraints *constr = GetConstraints(); - if ( constr ) - { - *x = constr->left.GetValue(); - *y = constr->top.GetValue(); - } - else - GetPosition(x, y); -} - -#endif // wxUSE_CONSTRAINTS - -void wxWindowBase::AdjustForParentClientOrigin(int& x, int& y, int sizeFlags) const -{ - // don't do it for the dialogs/frames - they float independently of their - // parent - if ( !IsTopLevel() ) - { - wxWindow *parent = GetParent(); - if ( !(sizeFlags & wxSIZE_NO_ADJUSTMENTS) && parent ) - { - wxPoint pt(parent->GetClientAreaOrigin()); - x += pt.x; - y += pt.y; - } - } -} - -// ---------------------------------------------------------------------------- -// Update UI processing -// ---------------------------------------------------------------------------- - -void wxWindowBase::UpdateWindowUI(long flags) -{ - wxUpdateUIEvent event(GetId()); - event.SetEventObject(this); - - if ( GetEventHandler()->ProcessEvent(event) ) - { - DoUpdateWindowUI(event); - } - - if (flags & wxUPDATE_UI_RECURSE) - { - wxWindowList::compatibility_iterator node = GetChildren().GetFirst(); - while (node) - { - wxWindow* child = (wxWindow*) node->GetData(); - child->UpdateWindowUI(flags); - node = node->GetNext(); - } - } -} - -// do the window-specific processing after processing the update event -void wxWindowBase::DoUpdateWindowUI(wxUpdateUIEvent& event) -{ - if ( event.GetSetEnabled() ) - Enable(event.GetEnabled()); - - if ( event.GetSetShown() ) - Show(event.GetShown()); -} - -// ---------------------------------------------------------------------------- -// dialog units translations -// ---------------------------------------------------------------------------- - -wxPoint wxWindowBase::ConvertPixelsToDialog(const wxPoint& pt) -{ - int charWidth = GetCharWidth(); - int charHeight = GetCharHeight(); - wxPoint pt2 = wxDefaultPosition; - if (pt.x != wxDefaultCoord) - pt2.x = (int) ((pt.x * 4) / charWidth); - if (pt.y != wxDefaultCoord) - pt2.y = (int) ((pt.y * 8) / charHeight); - - return pt2; -} - -wxPoint wxWindowBase::ConvertDialogToPixels(const wxPoint& pt) -{ - int charWidth = GetCharWidth(); - int charHeight = GetCharHeight(); - wxPoint pt2 = wxDefaultPosition; - if (pt.x != wxDefaultCoord) - pt2.x = (int) ((pt.x * charWidth) / 4); - if (pt.y != wxDefaultCoord) - pt2.y = (int) ((pt.y * charHeight) / 8); - - return pt2; -} - -// ---------------------------------------------------------------------------- -// event handlers -// ---------------------------------------------------------------------------- - -// propagate the colour change event to the subwindows -void wxWindowBase::OnSysColourChanged(wxSysColourChangedEvent& event) -{ - wxWindowList::compatibility_iterator node = GetChildren().GetFirst(); - while ( node ) - { - // Only propagate to non-top-level windows - wxWindow *win = node->GetData(); - if ( !win->IsTopLevel() ) - { - wxSysColourChangedEvent event2; - event.SetEventObject(win); - win->GetEventHandler()->ProcessEvent(event2); - } - - node = node->GetNext(); - } - - Refresh(); -} - -// the default action is to populate dialog with data when it's created, -// and nudge the UI into displaying itself correctly in case -// we've turned the wxUpdateUIEvents frequency down low. -void wxWindowBase::OnInitDialog( wxInitDialogEvent &WXUNUSED(event) ) -{ - TransferDataToWindow(); - - // Update the UI at this point - UpdateWindowUI(wxUPDATE_UI_RECURSE); -} - -// methods for drawing the sizers in a visible way -#ifdef __WXDEBUG__ - -static void DrawSizers(wxWindowBase *win); - -static void DrawBorder(wxWindowBase *win, const wxRect& rect, bool fill = false) -{ - wxClientDC dc((wxWindow *)win); - dc.SetPen(*wxRED_PEN); - dc.SetBrush(fill ? wxBrush(*wxRED, wxCROSSDIAG_HATCH): *wxTRANSPARENT_BRUSH); - dc.DrawRectangle(rect.Deflate(1, 1)); -} - -static void DrawSizer(wxWindowBase *win, wxSizer *sizer) -{ - const wxSizerItemList& items = sizer->GetChildren(); - for ( wxSizerItemList::const_iterator i = items.begin(), - end = items.end(); - i != end; - ++i ) - { - wxSizerItem *item = *i; - if ( item->IsSizer() ) - { - DrawBorder(win, item->GetRect().Deflate(2)); - DrawSizer(win, item->GetSizer()); - } - else if ( item->IsSpacer() ) - { - DrawBorder(win, item->GetRect().Deflate(2), true); - } - else if ( item->IsWindow() ) - { - DrawSizers(item->GetWindow()); - } - } -} - -static void DrawSizers(wxWindowBase *win) -{ - wxSizer *sizer = win->GetSizer(); - if ( sizer ) - { - DrawBorder(win, win->GetClientSize()); - DrawSizer(win, sizer); - } - else // no sizer, still recurse into the children - { - const wxWindowList& children = win->GetChildren(); - for ( wxWindowList::const_iterator i = children.begin(), - end = children.end(); - i != end; - ++i ) - { - DrawSizers(*i); - } - } -} - -#endif // __WXDEBUG__ - -// process special middle clicks -void wxWindowBase::OnMiddleClick( wxMouseEvent& event ) -{ - if ( event.ControlDown() && event.AltDown() ) - { -#ifdef __WXDEBUG__ - // Ctrl-Alt-Shift-mclick makes the sizers visible in debug builds - if ( event.ShiftDown() ) - { - DrawSizers(this); - return; - } -#endif // __WXDEBUG__ - -#if wxUSE_MSGDLG - // don't translate these strings, they're for diagnostics purposes only - wxString msg; - msg.Printf(_T("wxWidgets Library (%s port)\n") - _T("Version %d.%d.%d%s%s, compiled at %s %s\n") - _T("Runtime version of toolkit used is %d.%d.%s\n") - _T("Copyright (c) 1995-2007 wxWidgets team"), - wxPlatformInfo::Get().GetPortIdName().c_str(), - wxMAJOR_VERSION, - wxMINOR_VERSION, - wxRELEASE_NUMBER, -#if wxUSE_UNICODE - L" (Unicode)", -#else - wxEmptyString, -#endif -#ifdef __WXDEBUG__ - _T(" Debug build"), -#else - wxEmptyString, -#endif - __TDATE__, - __TTIME__, - wxPlatformInfo::Get().GetToolkitMajorVersion(), - wxPlatformInfo::Get().GetToolkitMinorVersion(), -#ifdef __WXGTK__ - wxString::Format(_T("\nThe compile-time GTK+ version is %d.%d.%d."), GTK_MAJOR_VERSION, GTK_MINOR_VERSION, GTK_MICRO_VERSION).c_str() -#else - wxEmptyString -#endif - ); - - wxMessageBox(msg, _T("wxWidgets information"), - wxICON_INFORMATION | wxOK, - (wxWindow *)this); - } - else -#endif // wxUSE_MSGDLG - { - event.Skip(); - } -} - -// ---------------------------------------------------------------------------- -// accessibility -// ---------------------------------------------------------------------------- - -#if wxUSE_ACCESSIBILITY -void wxWindowBase::SetAccessible(wxAccessible* accessible) -{ - if (m_accessible && (accessible != m_accessible)) - delete m_accessible; - m_accessible = accessible; - if (m_accessible) - m_accessible->SetWindow((wxWindow*) this); -} - -// Returns the accessible object, creating if necessary. -wxAccessible* wxWindowBase::GetOrCreateAccessible() -{ - if (!m_accessible) - m_accessible = CreateAccessible(); - return m_accessible; -} - -// Override to create a specific accessible object. -wxAccessible* wxWindowBase::CreateAccessible() -{ - return new wxWindowAccessible((wxWindow*) this); -} - -#endif - -// ---------------------------------------------------------------------------- -// list classes implementation -// ---------------------------------------------------------------------------- - -#if wxUSE_STL - -#include "wx/listimpl.cpp" -WX_DEFINE_LIST(wxWindowList) - -#else // !wxUSE_STL - -void wxWindowListNode::DeleteData() -{ - delete (wxWindow *)GetData(); -} - -#endif // wxUSE_STL/!wxUSE_STL - -// ---------------------------------------------------------------------------- -// borders -// ---------------------------------------------------------------------------- - -wxBorder wxWindowBase::GetBorder(long flags) const -{ - wxBorder border = (wxBorder)(flags & wxBORDER_MASK); - if ( border == wxBORDER_DEFAULT ) - { - border = GetDefaultBorder(); - } - - return border; -} - -wxBorder wxWindowBase::GetDefaultBorder() const -{ - return wxBORDER_NONE; -} - -// ---------------------------------------------------------------------------- -// hit testing -// ---------------------------------------------------------------------------- - -wxHitTest wxWindowBase::DoHitTest(wxCoord x, wxCoord y) const -{ - // here we just check if the point is inside the window or not - - // check the top and left border first - bool outside = x < 0 || y < 0; - if ( !outside ) - { - // check the right and bottom borders too - wxSize size = GetSize(); - outside = x >= size.x || y >= size.y; - } - - return outside ? wxHT_WINDOW_OUTSIDE : wxHT_WINDOW_INSIDE; -} - -// ---------------------------------------------------------------------------- -// mouse capture -// ---------------------------------------------------------------------------- - -struct WXDLLEXPORT wxWindowNext -{ - wxWindow *win; - wxWindowNext *next; -} *wxWindowBase::ms_winCaptureNext = NULL; -wxWindow *wxWindowBase::ms_winCaptureCurrent = NULL; -bool wxWindowBase::ms_winCaptureChanging = false; - -void wxWindowBase::CaptureMouse() -{ - wxLogTrace(_T("mousecapture"), _T("CaptureMouse(%p)"), wx_static_cast(void*, this)); - - wxASSERT_MSG( !ms_winCaptureChanging, _T("recursive CaptureMouse call?") ); - - ms_winCaptureChanging = true; - - wxWindow *winOld = GetCapture(); - if ( winOld ) - { - ((wxWindowBase*) winOld)->DoReleaseMouse(); - - // save it on stack - wxWindowNext *item = new wxWindowNext; - item->win = winOld; - item->next = ms_winCaptureNext; - ms_winCaptureNext = item; - } - //else: no mouse capture to save - - DoCaptureMouse(); - ms_winCaptureCurrent = (wxWindow*)this; - - ms_winCaptureChanging = false; -} - -void wxWindowBase::ReleaseMouse() -{ - wxLogTrace(_T("mousecapture"), _T("ReleaseMouse(%p)"), wx_static_cast(void*, this)); - - wxASSERT_MSG( !ms_winCaptureChanging, _T("recursive ReleaseMouse call?") ); - - wxASSERT_MSG( GetCapture() == this, wxT("attempt to release mouse, but this window hasn't captured it") ); - - ms_winCaptureChanging = true; - - DoReleaseMouse(); - ms_winCaptureCurrent = NULL; - - if ( ms_winCaptureNext ) - { - ((wxWindowBase*)ms_winCaptureNext->win)->DoCaptureMouse(); - ms_winCaptureCurrent = ms_winCaptureNext->win; - - wxWindowNext *item = ms_winCaptureNext; - ms_winCaptureNext = item->next; - delete item; - } - //else: stack is empty, no previous capture - - ms_winCaptureChanging = false; - - wxLogTrace(_T("mousecapture"), - (const wxChar *) _T("After ReleaseMouse() mouse is captured by %p"), - wx_static_cast(void*, GetCapture())); -} - -static void DoNotifyWindowAboutCaptureLost(wxWindow *win) -{ - wxMouseCaptureLostEvent event(win->GetId()); - event.SetEventObject(win); - if ( !win->GetEventHandler()->ProcessEvent(event) ) - { - // windows must handle this event, otherwise the app wouldn't behave - // correctly if it loses capture unexpectedly; see the discussion here: - // http://sourceforge.net/tracker/index.php?func=detail&aid=1153662&group_id=9863&atid=109863 - // http://article.gmane.org/gmane.comp.lib.wxwidgets.devel/82376 - wxFAIL_MSG( _T("window that captured the mouse didn't process wxEVT_MOUSE_CAPTURE_LOST") ); - } -} - -/* static */ -void wxWindowBase::NotifyCaptureLost() -{ - // don't do anything if capture lost was expected, i.e. resulted from - // a wx call to ReleaseMouse or CaptureMouse: - if ( ms_winCaptureChanging ) - return; - - // if the capture was lost unexpectedly, notify every window that has - // capture (on stack or current) about it and clear the stack: - - if ( ms_winCaptureCurrent ) - { - DoNotifyWindowAboutCaptureLost(ms_winCaptureCurrent); - ms_winCaptureCurrent = NULL; - } - - while ( ms_winCaptureNext ) - { - wxWindowNext *item = ms_winCaptureNext; - ms_winCaptureNext = item->next; - - DoNotifyWindowAboutCaptureLost(item->win); - - delete item; - } -} - -#if wxUSE_HOTKEY - -bool -wxWindowBase::RegisterHotKey(int WXUNUSED(hotkeyId), - int WXUNUSED(modifiers), - int WXUNUSED(keycode)) -{ - // not implemented - return false; -} - -bool wxWindowBase::UnregisterHotKey(int WXUNUSED(hotkeyId)) -{ - // not implemented - return false; -} - -#endif // wxUSE_HOTKEY - -// ---------------------------------------------------------------------------- -// event processing -// ---------------------------------------------------------------------------- - -bool wxWindowBase::TryValidator(wxEvent& wxVALIDATOR_PARAM(event)) -{ -#if wxUSE_VALIDATORS - // Can only use the validator of the window which - // is receiving the event - if ( event.GetEventObject() == this ) - { - wxValidator *validator = GetValidator(); - if ( validator && validator->ProcessEvent(event) ) - { - return true; - } - } -#endif // wxUSE_VALIDATORS - - return false; -} - -bool wxWindowBase::TryParent(wxEvent& event) -{ - // carry on up the parent-child hierarchy if the propagation count hasn't - // reached zero yet - if ( event.ShouldPropagate() ) - { - // honour the requests to stop propagation at this window: this is - // used by the dialogs, for example, to prevent processing the events - // from the dialog controls in the parent frame which rarely, if ever, - // makes sense - if ( !(GetExtraStyle() & wxWS_EX_BLOCK_EVENTS) ) - { - wxWindow *parent = GetParent(); - if ( parent && !parent->IsBeingDeleted() ) - { - wxPropagateOnce propagateOnce(event); - - return parent->GetEventHandler()->ProcessEvent(event); - } - } - } - - return wxEvtHandler::TryParent(event); -} - -// ---------------------------------------------------------------------------- -// window relationships -// ---------------------------------------------------------------------------- - -wxWindow *wxWindowBase::DoGetSibling(MoveKind order) const -{ - wxCHECK_MSG( GetParent(), NULL, - _T("GetPrev/NextSibling() don't work for TLWs!") ); - - wxWindowList& siblings = GetParent()->GetChildren(); - wxWindowList::compatibility_iterator i = siblings.Find((wxWindow *)this); - wxCHECK_MSG( i, NULL, _T("window not a child of its parent?") ); - - if ( order == MoveBefore ) - i = i->GetPrevious(); - else // MoveAfter - i = i->GetNext(); - - return i ? i->GetData() : NULL; -} - -// ---------------------------------------------------------------------------- -// keyboard navigation -// ---------------------------------------------------------------------------- - -// Navigates in the specified direction. -bool wxWindowBase::Navigate(int flags) -{ - wxNavigationKeyEvent eventNav; - eventNav.SetFlags(flags); - eventNav.SetEventObject(this); - if ( GetParent()->GetEventHandler()->ProcessEvent(eventNav) ) - { - return true; - } - return false; -} - -void wxWindowBase::DoMoveInTabOrder(wxWindow *win, MoveKind move) -{ - // check that we're not a top level window - wxCHECK_RET( GetParent(), - _T("MoveBefore/AfterInTabOrder() don't work for TLWs!") ); - - // detect the special case when we have nothing to do anyhow and when the - // code below wouldn't work - if ( win == this ) - return; - - // find the target window in the siblings list - wxWindowList& siblings = GetParent()->GetChildren(); - wxWindowList::compatibility_iterator i = siblings.Find(win); - wxCHECK_RET( i, _T("MoveBefore/AfterInTabOrder(): win is not a sibling") ); - - // unfortunately, when wxUSE_STL == 1 DetachNode() is not implemented so we - // can't just move the node around - wxWindow *self = (wxWindow *)this; - siblings.DeleteObject(self); - if ( move == MoveAfter ) - { - i = i->GetNext(); - } - - if ( i ) - { - siblings.Insert(i, self); - } - else // MoveAfter and win was the last sibling - { - siblings.Append(self); - } -} - -// ---------------------------------------------------------------------------- -// focus handling -// ---------------------------------------------------------------------------- - -/*static*/ wxWindow* wxWindowBase::FindFocus() -{ - wxWindowBase *win = DoFindFocus(); - return win ? win->GetMainWindowOfCompositeControl() : NULL; -} - -// ---------------------------------------------------------------------------- -// global functions -// ---------------------------------------------------------------------------- - -wxWindow* wxGetTopLevelParent(wxWindow *win) -{ - while ( win && !win->IsTopLevel() ) - win = win->GetParent(); - - return win; -} - -#if wxUSE_ACCESSIBILITY -// ---------------------------------------------------------------------------- -// accessible object for windows -// ---------------------------------------------------------------------------- - -// Can return either a child object, or an integer -// representing the child element, starting from 1. -wxAccStatus wxWindowAccessible::HitTest(const wxPoint& WXUNUSED(pt), int* WXUNUSED(childId), wxAccessible** WXUNUSED(childObject)) -{ - wxASSERT( GetWindow() != NULL ); - if (!GetWindow()) - return wxACC_FAIL; - - return wxACC_NOT_IMPLEMENTED; -} - -// Returns the rectangle for this object (id = 0) or a child element (id > 0). -wxAccStatus wxWindowAccessible::GetLocation(wxRect& rect, int elementId) -{ - wxASSERT( GetWindow() != NULL ); - if (!GetWindow()) - return wxACC_FAIL; - - wxWindow* win = NULL; - if (elementId == 0) - { - win = GetWindow(); - } - else - { - if (elementId <= (int) GetWindow()->GetChildren().GetCount()) - { - win = GetWindow()->GetChildren().Item(elementId-1)->GetData(); - } - else - return wxACC_FAIL; - } - if (win) - { - rect = win->GetRect(); - if (win->GetParent() && !win->IsKindOf(CLASSINFO(wxTopLevelWindow))) - rect.SetPosition(win->GetParent()->ClientToScreen(rect.GetPosition())); - return wxACC_OK; - } - - return wxACC_NOT_IMPLEMENTED; -} - -// Navigates from fromId to toId/toObject. -wxAccStatus wxWindowAccessible::Navigate(wxNavDir navDir, int fromId, - int* WXUNUSED(toId), wxAccessible** toObject) -{ - wxASSERT( GetWindow() != NULL ); - if (!GetWindow()) - return wxACC_FAIL; - - switch (navDir) - { - case wxNAVDIR_FIRSTCHILD: - { - if (GetWindow()->GetChildren().GetCount() == 0) - return wxACC_FALSE; - wxWindow* childWindow = (wxWindow*) GetWindow()->GetChildren().GetFirst()->GetData(); - *toObject = childWindow->GetOrCreateAccessible(); - - return wxACC_OK; - } - case wxNAVDIR_LASTCHILD: - { - if (GetWindow()->GetChildren().GetCount() == 0) - return wxACC_FALSE; - wxWindow* childWindow = (wxWindow*) GetWindow()->GetChildren().GetLast()->GetData(); - *toObject = childWindow->GetOrCreateAccessible(); - - return wxACC_OK; - } - case wxNAVDIR_RIGHT: - case wxNAVDIR_DOWN: - case wxNAVDIR_NEXT: - { - wxWindowList::compatibility_iterator node = - wxWindowList::compatibility_iterator(); - if (fromId == 0) - { - // Can't navigate to sibling of this window - // if we're a top-level window. - if (!GetWindow()->GetParent()) - return wxACC_NOT_IMPLEMENTED; - - node = GetWindow()->GetParent()->GetChildren().Find(GetWindow()); - } - else - { - if (fromId <= (int) GetWindow()->GetChildren().GetCount()) - node = GetWindow()->GetChildren().Item(fromId-1); - } - - if (node && node->GetNext()) - { - wxWindow* nextWindow = node->GetNext()->GetData(); - *toObject = nextWindow->GetOrCreateAccessible(); - return wxACC_OK; - } - else - return wxACC_FALSE; - } - case wxNAVDIR_LEFT: - case wxNAVDIR_UP: - case wxNAVDIR_PREVIOUS: - { - wxWindowList::compatibility_iterator node = - wxWindowList::compatibility_iterator(); - if (fromId == 0) - { - // Can't navigate to sibling of this window - // if we're a top-level window. - if (!GetWindow()->GetParent()) - return wxACC_NOT_IMPLEMENTED; - - node = GetWindow()->GetParent()->GetChildren().Find(GetWindow()); - } - else - { - if (fromId <= (int) GetWindow()->GetChildren().GetCount()) - node = GetWindow()->GetChildren().Item(fromId-1); - } - - if (node && node->GetPrevious()) - { - wxWindow* previousWindow = node->GetPrevious()->GetData(); - *toObject = previousWindow->GetOrCreateAccessible(); - return wxACC_OK; - } - else - return wxACC_FALSE; - } - } - - return wxACC_NOT_IMPLEMENTED; -} - -// Gets the name of the specified object. -wxAccStatus wxWindowAccessible::GetName(int childId, wxString* name) -{ - wxASSERT( GetWindow() != NULL ); - if (!GetWindow()) - return wxACC_FAIL; - - wxString title; - - // If a child, leave wxWidgets to call the function on the actual - // child object. - if (childId > 0) - return wxACC_NOT_IMPLEMENTED; - - // This will eventually be replaced by specialised - // accessible classes, one for each kind of wxWidgets - // control or window. -#if wxUSE_BUTTON - if (GetWindow()->IsKindOf(CLASSINFO(wxButton))) - title = ((wxButton*) GetWindow())->GetLabel(); - else -#endif - title = GetWindow()->GetName(); - - if (!title.empty()) - { - *name = title; - return wxACC_OK; - } - else - return wxACC_NOT_IMPLEMENTED; -} - -// Gets the number of children. -wxAccStatus wxWindowAccessible::GetChildCount(int* childId) -{ - wxASSERT( GetWindow() != NULL ); - if (!GetWindow()) - return wxACC_FAIL; - - *childId = (int) GetWindow()->GetChildren().GetCount(); - return wxACC_OK; -} - -// Gets the specified child (starting from 1). -// If *child is NULL and return value is wxACC_OK, -// this means that the child is a simple element and -// not an accessible object. -wxAccStatus wxWindowAccessible::GetChild(int childId, wxAccessible** child) -{ - wxASSERT( GetWindow() != NULL ); - if (!GetWindow()) - return wxACC_FAIL; - - if (childId == 0) - { - *child = this; - return wxACC_OK; - } - - if (childId > (int) GetWindow()->GetChildren().GetCount()) - return wxACC_FAIL; - - wxWindow* childWindow = GetWindow()->GetChildren().Item(childId-1)->GetData(); - *child = childWindow->GetOrCreateAccessible(); - if (*child) - return wxACC_OK; - else - return wxACC_FAIL; -} - -// Gets the parent, or NULL. -wxAccStatus wxWindowAccessible::GetParent(wxAccessible** parent) -{ - wxASSERT( GetWindow() != NULL ); - if (!GetWindow()) - return wxACC_FAIL; - - wxWindow* parentWindow = GetWindow()->GetParent(); - if (!parentWindow) - { - *parent = NULL; - return wxACC_OK; - } - else - { - *parent = parentWindow->GetOrCreateAccessible(); - if (*parent) - return wxACC_OK; - else - return wxACC_FAIL; - } -} - -// Performs the default action. childId is 0 (the action for this object) -// or > 0 (the action for a child). -// Return wxACC_NOT_SUPPORTED if there is no default action for this -// window (e.g. an edit control). -wxAccStatus wxWindowAccessible::DoDefaultAction(int WXUNUSED(childId)) -{ - wxASSERT( GetWindow() != NULL ); - if (!GetWindow()) - return wxACC_FAIL; - - return wxACC_NOT_IMPLEMENTED; -} - -// Gets the default action for this object (0) or > 0 (the action for a child). -// Return wxACC_OK even if there is no action. actionName is the action, or the empty -// string if there is no action. -// The retrieved string describes the action that is performed on an object, -// not what the object does as a result. For example, a toolbar button that prints -// a document has a default action of "Press" rather than "Prints the current document." -wxAccStatus wxWindowAccessible::GetDefaultAction(int WXUNUSED(childId), wxString* WXUNUSED(actionName)) -{ - wxASSERT( GetWindow() != NULL ); - if (!GetWindow()) - return wxACC_FAIL; - - return wxACC_NOT_IMPLEMENTED; -} - -// Returns the description for this object or a child. -wxAccStatus wxWindowAccessible::GetDescription(int WXUNUSED(childId), wxString* description) -{ - wxASSERT( GetWindow() != NULL ); - if (!GetWindow()) - return wxACC_FAIL; - - wxString ht(GetWindow()->GetHelpTextAtPoint(wxDefaultPosition, wxHelpEvent::Origin_Keyboard)); - if (!ht.empty()) - { - *description = ht; - return wxACC_OK; - } - return wxACC_NOT_IMPLEMENTED; -} - -// Returns help text for this object or a child, similar to tooltip text. -wxAccStatus wxWindowAccessible::GetHelpText(int WXUNUSED(childId), wxString* helpText) -{ - wxASSERT( GetWindow() != NULL ); - if (!GetWindow()) - return wxACC_FAIL; - - wxString ht(GetWindow()->GetHelpTextAtPoint(wxDefaultPosition, wxHelpEvent::Origin_Keyboard)); - if (!ht.empty()) - { - *helpText = ht; - return wxACC_OK; - } - return wxACC_NOT_IMPLEMENTED; -} - -// Returns the keyboard shortcut for this object or child. -// Return e.g. ALT+K -wxAccStatus wxWindowAccessible::GetKeyboardShortcut(int WXUNUSED(childId), wxString* WXUNUSED(shortcut)) -{ - wxASSERT( GetWindow() != NULL ); - if (!GetWindow()) - return wxACC_FAIL; - - return wxACC_NOT_IMPLEMENTED; -} - -// Returns a role constant. -wxAccStatus wxWindowAccessible::GetRole(int childId, wxAccRole* role) -{ - wxASSERT( GetWindow() != NULL ); - if (!GetWindow()) - return wxACC_FAIL; - - // If a child, leave wxWidgets to call the function on the actual - // child object. - if (childId > 0) - return wxACC_NOT_IMPLEMENTED; - - if (GetWindow()->IsKindOf(CLASSINFO(wxControl))) - return wxACC_NOT_IMPLEMENTED; -#if wxUSE_STATUSBAR - if (GetWindow()->IsKindOf(CLASSINFO(wxStatusBar))) - return wxACC_NOT_IMPLEMENTED; -#endif -#if wxUSE_TOOLBAR - if (GetWindow()->IsKindOf(CLASSINFO(wxToolBar))) - return wxACC_NOT_IMPLEMENTED; -#endif - - //*role = wxROLE_SYSTEM_CLIENT; - *role = wxROLE_SYSTEM_CLIENT; - return wxACC_OK; - - #if 0 - return wxACC_NOT_IMPLEMENTED; - #endif -} - -// Returns a state constant. -wxAccStatus wxWindowAccessible::GetState(int childId, long* state) -{ - wxASSERT( GetWindow() != NULL ); - if (!GetWindow()) - return wxACC_FAIL; - - // If a child, leave wxWidgets to call the function on the actual - // child object. - if (childId > 0) - return wxACC_NOT_IMPLEMENTED; - - if (GetWindow()->IsKindOf(CLASSINFO(wxControl))) - return wxACC_NOT_IMPLEMENTED; - -#if wxUSE_STATUSBAR - if (GetWindow()->IsKindOf(CLASSINFO(wxStatusBar))) - return wxACC_NOT_IMPLEMENTED; -#endif -#if wxUSE_TOOLBAR - if (GetWindow()->IsKindOf(CLASSINFO(wxToolBar))) - return wxACC_NOT_IMPLEMENTED; -#endif - - *state = 0; - return wxACC_OK; - - #if 0 - return wxACC_NOT_IMPLEMENTED; - #endif -} - -// Returns a localized string representing the value for the object -// or child. -wxAccStatus wxWindowAccessible::GetValue(int WXUNUSED(childId), wxString* WXUNUSED(strValue)) -{ - wxASSERT( GetWindow() != NULL ); - if (!GetWindow()) - return wxACC_FAIL; - - return wxACC_NOT_IMPLEMENTED; -} - -// Selects the object or child. -wxAccStatus wxWindowAccessible::Select(int WXUNUSED(childId), wxAccSelectionFlags WXUNUSED(selectFlags)) -{ - wxASSERT( GetWindow() != NULL ); - if (!GetWindow()) - return wxACC_FAIL; - - return wxACC_NOT_IMPLEMENTED; -} - -// Gets the window with the keyboard focus. -// If childId is 0 and child is NULL, no object in -// this subhierarchy has the focus. -// If this object has the focus, child should be 'this'. -wxAccStatus wxWindowAccessible::GetFocus(int* WXUNUSED(childId), wxAccessible** WXUNUSED(child)) -{ - wxASSERT( GetWindow() != NULL ); - if (!GetWindow()) - return wxACC_FAIL; - - return wxACC_NOT_IMPLEMENTED; -} - -#if wxUSE_VARIANT -// Gets a variant representing the selected children -// of this object. -// Acceptable values: -// - a null variant (IsNull() returns true) -// - a list variant (GetType() == wxT("list") -// - an integer representing the selected child element, -// or 0 if this object is selected (GetType() == wxT("long") -// - a "void*" pointer to a wxAccessible child object -wxAccStatus wxWindowAccessible::GetSelections(wxVariant* WXUNUSED(selections)) -{ - wxASSERT( GetWindow() != NULL ); - if (!GetWindow()) - return wxACC_FAIL; - - return wxACC_NOT_IMPLEMENTED; -} -#endif // wxUSE_VARIANT - -#endif // wxUSE_ACCESSIBILITY - -// ---------------------------------------------------------------------------- -// RTL support -// ---------------------------------------------------------------------------- - -wxCoord -wxWindowBase::AdjustForLayoutDirection(wxCoord x, - wxCoord width, - wxCoord widthTotal) const -{ - if ( GetLayoutDirection() == wxLayout_RightToLeft ) - { - x = widthTotal - x - width; - } - - return x; -} - +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/window.cpp +// Purpose: common (to all ports) wxWindow functions +// Author: Julian Smart, Vadim Zeitlin +// Modified by: +// Created: 13/07/98 +// RCS-ID: $Id: wincmn.cpp 52330 2008-03-05 14:19:38Z VS $ +// Copyright: (c) wxWidgets team +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#ifndef WX_PRECOMP + #include "wx/string.h" + #include "wx/log.h" + #include "wx/intl.h" + #include "wx/frame.h" + #include "wx/window.h" + #include "wx/control.h" + #include "wx/checkbox.h" + #include "wx/radiobut.h" + #include "wx/statbox.h" + #include "wx/textctrl.h" + #include "wx/settings.h" + #include "wx/dialog.h" + #include "wx/msgdlg.h" + #include "wx/statusbr.h" + #include "wx/toolbar.h" + #include "wx/dcclient.h" + #include "wx/scrolbar.h" + #include "wx/layout.h" + #include "wx/sizer.h" +#endif //WX_PRECOMP + +#if wxUSE_DRAG_AND_DROP + #include "wx/dnd.h" +#endif // wxUSE_DRAG_AND_DROP + +#if wxUSE_ACCESSIBILITY + #include "wx/access.h" +#endif + +#if wxUSE_HELP + #include "wx/cshelp.h" +#endif // wxUSE_HELP + +#if wxUSE_TOOLTIPS + #include "wx/tooltip.h" +#endif // wxUSE_TOOLTIPS + +#if wxUSE_CARET + #include "wx/caret.h" +#endif // wxUSE_CARET + +#if wxUSE_SYSTEM_OPTIONS + #include "wx/sysopt.h" +#endif + +// For reporting compile- and runtime version of GTK+ in the ctrl+alt+mclick dialog. +// The gtk includes don't pull any other headers in, at least not on my system - MR +#ifdef __WXGTK__ + #ifdef __WXGTK20__ + #include + #else + #include + #endif + extern const unsigned int gtk_major_version; + extern const unsigned int gtk_minor_version; + extern const unsigned int gtk_micro_version; +#endif + +#include "wx/platinfo.h" + +// Windows List +WXDLLIMPEXP_DATA_CORE(wxWindowList) wxTopLevelWindows; + +// ---------------------------------------------------------------------------- +// static data +// ---------------------------------------------------------------------------- + +#if defined(__WXPALMOS__) +int wxWindowBase::ms_lastControlId = 32767; +#elif defined(__WXPM__) +int wxWindowBase::ms_lastControlId = 2000; +#else +int wxWindowBase::ms_lastControlId = -200; +#endif + +IMPLEMENT_ABSTRACT_CLASS(wxWindowBase, wxEvtHandler) + +// ---------------------------------------------------------------------------- +// event table +// ---------------------------------------------------------------------------- + +BEGIN_EVENT_TABLE(wxWindowBase, wxEvtHandler) + EVT_SYS_COLOUR_CHANGED(wxWindowBase::OnSysColourChanged) + EVT_INIT_DIALOG(wxWindowBase::OnInitDialog) + EVT_MIDDLE_DOWN(wxWindowBase::OnMiddleClick) + +#if wxUSE_HELP + EVT_HELP(wxID_ANY, wxWindowBase::OnHelp) +#endif // wxUSE_HELP + +END_EVENT_TABLE() + +// ============================================================================ +// implementation of the common functionality of the wxWindow class +// ============================================================================ + +// ---------------------------------------------------------------------------- +// initialization +// ---------------------------------------------------------------------------- + +// the default initialization +wxWindowBase::wxWindowBase() +{ + // no window yet, no parent nor children + m_parent = (wxWindow *)NULL; + m_windowId = wxID_ANY; + + // no constraints on the minimal window size + m_minWidth = + m_maxWidth = wxDefaultCoord; + m_minHeight = + m_maxHeight = wxDefaultCoord; + + // invalidiated cache value + m_bestSizeCache = wxDefaultSize; + + // window are created enabled and visible by default + m_isShown = + m_isEnabled = true; + + // the default event handler is just this window + m_eventHandler = this; + +#if wxUSE_VALIDATORS + // no validator + m_windowValidator = (wxValidator *) NULL; +#endif // wxUSE_VALIDATORS + + // the colours/fonts are default for now, so leave m_font, + // m_backgroundColour and m_foregroundColour uninitialized and set those + m_hasBgCol = + m_hasFgCol = + m_hasFont = false; + m_inheritBgCol = + m_inheritFgCol = + m_inheritFont = false; + + // no style bits + m_exStyle = + m_windowStyle = 0; + + m_backgroundStyle = wxBG_STYLE_SYSTEM; + +#if wxUSE_CONSTRAINTS + // no constraints whatsoever + m_constraints = (wxLayoutConstraints *) NULL; + m_constraintsInvolvedIn = (wxWindowList *) NULL; +#endif // wxUSE_CONSTRAINTS + + m_windowSizer = (wxSizer *) NULL; + m_containingSizer = (wxSizer *) NULL; + m_autoLayout = false; + +#if wxUSE_DRAG_AND_DROP + m_dropTarget = (wxDropTarget *)NULL; +#endif // wxUSE_DRAG_AND_DROP + +#if wxUSE_TOOLTIPS + m_tooltip = (wxToolTip *)NULL; +#endif // wxUSE_TOOLTIPS + +#if wxUSE_CARET + m_caret = (wxCaret *)NULL; +#endif // wxUSE_CARET + +#if wxUSE_PALETTE + m_hasCustomPalette = false; +#endif // wxUSE_PALETTE + +#if wxUSE_ACCESSIBILITY + m_accessible = NULL; +#endif + + m_virtualSize = wxDefaultSize; + + m_scrollHelper = (wxScrollHelper *) NULL; + + m_minVirtualWidth = + m_maxVirtualWidth = wxDefaultCoord; + m_minVirtualHeight = + m_maxVirtualHeight = wxDefaultCoord; + + m_windowVariant = wxWINDOW_VARIANT_NORMAL; +#if wxUSE_SYSTEM_OPTIONS + if ( wxSystemOptions::HasOption(wxWINDOW_DEFAULT_VARIANT) ) + { + m_windowVariant = (wxWindowVariant) wxSystemOptions::GetOptionInt( wxWINDOW_DEFAULT_VARIANT ) ; + } +#endif + + // Whether we're using the current theme for this window (wxGTK only for now) + m_themeEnabled = false; + + // VZ: this one shouldn't exist... + m_isBeingDeleted = false; +} + +// common part of window creation process +bool wxWindowBase::CreateBase(wxWindowBase *parent, + wxWindowID id, + const wxPoint& WXUNUSED(pos), + const wxSize& WXUNUSED(size), + long style, + const wxValidator& wxVALIDATOR_PARAM(validator), + const wxString& name) +{ +#if wxUSE_STATBOX + // wxGTK doesn't allow to create controls with static box as the parent so + // this will result in a crash when the program is ported to wxGTK so warn + // the user about it + + // if you get this assert, the correct solution is to create the controls + // as siblings of the static box + wxASSERT_MSG( !parent || !wxDynamicCast(parent, wxStaticBox), + _T("wxStaticBox can't be used as a window parent!") ); +#endif // wxUSE_STATBOX + + // ids are limited to 16 bits under MSW so if you care about portability, + // it's not a good idea to use ids out of this range (and negative ids are + // reserved for wxWidgets own usage) + wxASSERT_MSG( id == wxID_ANY || (id >= 0 && id < 32767), + _T("invalid id value") ); + + // generate a new id if the user doesn't care about it + m_windowId = id == wxID_ANY ? NewControlId() : id; + + // don't use SetWindowStyleFlag() here, this function should only be called + // to change the flag after creation as it tries to reflect the changes in + // flags by updating the window dynamically and we don't need this here + m_windowStyle = style; + + SetName(name); + SetParent(parent); + +#if wxUSE_VALIDATORS + SetValidator(validator); +#endif // wxUSE_VALIDATORS + + // if the parent window has wxWS_EX_VALIDATE_RECURSIVELY set, we want to + // have it too - like this it's possible to set it only in the top level + // dialog/frame and all children will inherit it by defult + if ( parent && (parent->GetExtraStyle() & wxWS_EX_VALIDATE_RECURSIVELY) ) + { + SetExtraStyle(GetExtraStyle() | wxWS_EX_VALIDATE_RECURSIVELY); + } + + return true; +} + +bool wxWindowBase::ToggleWindowStyle(int flag) +{ + wxASSERT_MSG( flag, _T("flags with 0 value can't be toggled") ); + + bool rc; + long style = GetWindowStyleFlag(); + if ( style & flag ) + { + style &= ~flag; + rc = false; + } + else // currently off + { + style |= flag; + rc = true; + } + + SetWindowStyleFlag(style); + + return rc; +} + +// ---------------------------------------------------------------------------- +// destruction +// ---------------------------------------------------------------------------- + +// common clean up +wxWindowBase::~wxWindowBase() +{ + wxASSERT_MSG( GetCapture() != this, wxT("attempt to destroy window with mouse capture") ); + + // FIXME if these 2 cases result from programming errors in the user code + // we should probably assert here instead of silently fixing them + + // Just in case the window has been Closed, but we're then deleting + // immediately: don't leave dangling pointers. + wxPendingDelete.DeleteObject(this); + + // Just in case we've loaded a top-level window via LoadNativeDialog but + // we weren't a dialog class + wxTopLevelWindows.DeleteObject((wxWindow*)this); + + wxASSERT_MSG( GetChildren().GetCount() == 0, wxT("children not destroyed") ); + + // reset the top-level parent's default item if it is this widget + if ( m_parent ) + { + wxTopLevelWindow *tlw = wxDynamicCast(wxGetTopLevelParent((wxWindow*)this), + wxTopLevelWindow); + + if ( tlw ) + { + wxWindow* tmpDefaultItem = tlw->GetTmpDefaultItem(); + if ( tmpDefaultItem == this ) + tlw->SetTmpDefaultItem(NULL); + else if ( tmpDefaultItem ) + { + // A temporary default item masks the real default item, so + // temporarily unset the temporary default item so we can access the + // real default item. + tlw->SetTmpDefaultItem(NULL); + + if ( tlw->GetDefaultItem() == this ) + tlw->SetDefaultItem(NULL); + + // Set the temporary default item back. + tlw->SetTmpDefaultItem(tmpDefaultItem); + } + else if ( tlw->GetDefaultItem() == this ) + tlw->SetDefaultItem(NULL); + } + } + + // reset the dangling pointer our parent window may keep to us + if ( m_parent ) + { + m_parent->RemoveChild(this); + } + +#if wxUSE_CARET + delete m_caret; +#endif // wxUSE_CARET + +#if wxUSE_VALIDATORS + delete m_windowValidator; +#endif // wxUSE_VALIDATORS + +#if wxUSE_CONSTRAINTS + // Have to delete constraints/sizer FIRST otherwise sizers may try to look + // at deleted windows as they delete themselves. + DeleteRelatedConstraints(); + + if ( m_constraints ) + { + // This removes any dangling pointers to this window in other windows' + // constraintsInvolvedIn lists. + UnsetConstraints(m_constraints); + delete m_constraints; + m_constraints = NULL; + } +#endif // wxUSE_CONSTRAINTS + + if ( m_containingSizer ) + m_containingSizer->Detach( (wxWindow*)this ); + + delete m_windowSizer; + +#if wxUSE_DRAG_AND_DROP + delete m_dropTarget; +#endif // wxUSE_DRAG_AND_DROP + +#if wxUSE_TOOLTIPS + delete m_tooltip; +#endif // wxUSE_TOOLTIPS + +#if wxUSE_ACCESSIBILITY + delete m_accessible; +#endif + +#if wxUSE_HELP + // NB: this has to be called unconditionally, because we don't + // know whether this window has associated help text or not + wxHelpProvider *helpProvider = wxHelpProvider::Get(); + if ( helpProvider ) + helpProvider->RemoveHelp(this); +#endif +} + +void wxWindowBase::SendDestroyEvent() +{ + wxWindowDestroyEvent event; + event.SetEventObject(this); + event.SetId(GetId()); + GetEventHandler()->ProcessEvent(event); +} + +bool wxWindowBase::Destroy() +{ + delete this; + + return true; +} + +bool wxWindowBase::Close(bool force) +{ + wxCloseEvent event(wxEVT_CLOSE_WINDOW, m_windowId); + event.SetEventObject(this); + event.SetCanVeto(!force); + + // return false if window wasn't closed because the application vetoed the + // close event + return GetEventHandler()->ProcessEvent(event) && !event.GetVeto(); +} + +bool wxWindowBase::DestroyChildren() +{ + wxWindowList::compatibility_iterator node; + for ( ;; ) + { + // we iterate until the list becomes empty + node = GetChildren().GetFirst(); + if ( !node ) + break; + + wxWindow *child = node->GetData(); + + // note that we really want to call delete and not ->Destroy() here + // because we want to delete the child immediately, before we are + // deleted, and delayed deletion would result in problems as our (top + // level) child could outlive its parent + delete child; + + wxASSERT_MSG( !GetChildren().Find(child), + wxT("child didn't remove itself using RemoveChild()") ); + } + + return true; +} + +// ---------------------------------------------------------------------------- +// size/position related methods +// ---------------------------------------------------------------------------- + +// centre the window with respect to its parent in either (or both) directions +void wxWindowBase::DoCentre(int dir) +{ + wxCHECK_RET( !(dir & wxCENTRE_ON_SCREEN) && GetParent(), + _T("this method only implements centering child windows") ); + + SetSize(GetRect().CentreIn(GetParent()->GetClientSize(), dir)); +} + +// fits the window around the children +void wxWindowBase::Fit() +{ + if ( !GetChildren().empty() ) + { + SetSize(GetBestSize()); + } + //else: do nothing if we have no children +} + +// fits virtual size (ie. scrolled area etc.) around children +void wxWindowBase::FitInside() +{ + if ( GetChildren().GetCount() > 0 ) + { + SetVirtualSize( GetBestVirtualSize() ); + } +} + +// On Mac, scrollbars are explicitly children. +#ifdef __WXMAC__ +static bool wxHasRealChildren(const wxWindowBase* win) +{ + int realChildCount = 0; + + for ( wxWindowList::compatibility_iterator node = win->GetChildren().GetFirst(); + node; + node = node->GetNext() ) + { + wxWindow *win = node->GetData(); + if ( !win->IsTopLevel() && win->IsShown() && !win->IsKindOf(CLASSINFO(wxScrollBar))) + realChildCount ++; + } + return (realChildCount > 0); +} +#endif + +void wxWindowBase::InvalidateBestSize() +{ + m_bestSizeCache = wxDefaultSize; + + // parent's best size calculation may depend on its children's + // as long as child window we are in is not top level window itself + // (because the TLW size is never resized automatically) + // so let's invalidate it as well to be safe: + if (m_parent && !IsTopLevel()) + m_parent->InvalidateBestSize(); +} + +// return the size best suited for the current window +wxSize wxWindowBase::DoGetBestSize() const +{ + wxSize best; + + if ( m_windowSizer ) + { + // Adjust to window size, since the return value of GetWindowSizeForVirtualSize is + // expressed in window and not client size + wxSize minSize = m_windowSizer->GetMinSize(); + wxSize size(GetSize()); + wxSize clientSize(GetClientSize()); + + wxSize minWindowSize(minSize.x + size.x - clientSize.x, + minSize.y + size.y - clientSize.y); + + best = GetWindowSizeForVirtualSize(minWindowSize); + + return best; + } +#if wxUSE_CONSTRAINTS + else if ( m_constraints ) + { + wxConstCast(this, wxWindowBase)->SatisfyConstraints(); + + // our minimal acceptable size is such that all our windows fit inside + int maxX = 0, + maxY = 0; + + for ( wxWindowList::compatibility_iterator node = GetChildren().GetFirst(); + node; + node = node->GetNext() ) + { + wxLayoutConstraints *c = node->GetData()->GetConstraints(); + if ( !c ) + { + // it's not normal that we have an unconstrained child, but + // what can we do about it? + continue; + } + + int x = c->right.GetValue(), + y = c->bottom.GetValue(); + + if ( x > maxX ) + maxX = x; + + if ( y > maxY ) + maxY = y; + + // TODO: we must calculate the overlaps somehow, otherwise we + // will never return a size bigger than the current one :-( + } + + best = wxSize(maxX, maxY); + } +#endif // wxUSE_CONSTRAINTS + else if ( !GetChildren().empty() +#ifdef __WXMAC__ + && wxHasRealChildren(this) +#endif + ) + { + // our minimal acceptable size is such that all our visible child + // windows fit inside + int maxX = 0, + maxY = 0; + + for ( wxWindowList::compatibility_iterator node = GetChildren().GetFirst(); + node; + node = node->GetNext() ) + { + wxWindow *win = node->GetData(); + if ( win->IsTopLevel() + || !win->IsShown() +#if wxUSE_STATUSBAR + || wxDynamicCast(win, wxStatusBar) +#endif // wxUSE_STATUSBAR + ) + { + // dialogs and frames lie in different top level windows - + // don't deal with them here; as for the status bars, they + // don't lie in the client area at all + continue; + } + + int wx, wy, ww, wh; + win->GetPosition(&wx, &wy); + + // if the window hadn't been positioned yet, assume that it is in + // the origin + if ( wx == wxDefaultCoord ) + wx = 0; + if ( wy == wxDefaultCoord ) + wy = 0; + + win->GetSize(&ww, &wh); + if ( wx + ww > maxX ) + maxX = wx + ww; + if ( wy + wh > maxY ) + maxY = wy + wh; + } + + best = wxSize(maxX, maxY); + } + else // ! has children + { + // for a generic window there is no natural best size so, if the + // minimal size is not set, use the current size but take care to + // remember it as minimal size for the next time because our best size + // should be constant: otherwise we could get into a situation when the + // window is initially at some size, then expanded to a larger size and + // then, when the containing window is shrunk back (because our initial + // best size had been used for computing the parent min size), we can't + // be shrunk back any more because our best size is now bigger + wxSize size = GetMinSize(); + if ( !size.IsFullySpecified() ) + { + size.SetDefaults(GetSize()); + wxConstCast(this, wxWindowBase)->SetMinSize(size); + } + + // return as-is, unadjusted by the client size difference. + return size; + } + + // Add any difference between size and client size + wxSize diff = GetSize() - GetClientSize(); + best.x += wxMax(0, diff.x); + best.y += wxMax(0, diff.y); + + return best; +} + +// helper of GetWindowBorderSize(): as many ports don't implement support for +// wxSYS_BORDER/EDGE_X/Y metrics in their wxSystemSettings, use hard coded +// fallbacks in this case +static int wxGetMetricOrDefault(wxSystemMetric what) +{ + int rc = wxSystemSettings::GetMetric(what); + if ( rc == -1 ) + { + switch ( what ) + { + case wxSYS_BORDER_X: + case wxSYS_BORDER_Y: + // 2D border is by default 1 pixel wide + rc = 1; + break; + + case wxSYS_EDGE_X: + case wxSYS_EDGE_Y: + // 3D borders are by default 2 pixels + rc = 2; + break; + + default: + wxFAIL_MSG( _T("unexpected wxGetMetricOrDefault() argument") ); + rc = 0; + } + } + + return rc; +} + +wxSize wxWindowBase::GetWindowBorderSize() const +{ + wxSize size; + + switch ( GetBorder() ) + { + case wxBORDER_NONE: + // nothing to do, size is already (0, 0) + break; + + case wxBORDER_SIMPLE: + case wxBORDER_STATIC: + size.x = wxGetMetricOrDefault(wxSYS_BORDER_X); + size.y = wxGetMetricOrDefault(wxSYS_BORDER_Y); + break; + + case wxBORDER_SUNKEN: + case wxBORDER_RAISED: + size.x = wxMax(wxGetMetricOrDefault(wxSYS_EDGE_X), + wxGetMetricOrDefault(wxSYS_BORDER_X)); + size.y = wxMax(wxGetMetricOrDefault(wxSYS_EDGE_Y), + wxGetMetricOrDefault(wxSYS_BORDER_Y)); + break; + + case wxBORDER_DOUBLE: + size.x = wxGetMetricOrDefault(wxSYS_EDGE_X) + + wxGetMetricOrDefault(wxSYS_BORDER_X); + size.y = wxGetMetricOrDefault(wxSYS_EDGE_Y) + + wxGetMetricOrDefault(wxSYS_BORDER_Y); + break; + + default: + wxFAIL_MSG(_T("Unknown border style.")); + break; + } + + // we have borders on both sides + return size*2; +} + +wxSize wxWindowBase::GetEffectiveMinSize() const +{ + // merge the best size with the min size, giving priority to the min size + wxSize min = GetMinSize(); + if (min.x == wxDefaultCoord || min.y == wxDefaultCoord) + { + wxSize best = GetBestSize(); + if (min.x == wxDefaultCoord) min.x = best.x; + if (min.y == wxDefaultCoord) min.y = best.y; + } + return min; +} + + +void wxWindowBase::SetInitialSize(const wxSize& size) +{ + // Set the min size to the size passed in. This will usually either be + // wxDefaultSize or the size passed to this window's ctor/Create function. + SetMinSize(size); + + // Merge the size with the best size if needed + wxSize best = GetEffectiveMinSize(); + + // If the current size doesn't match then change it + if (GetSize() != best) + SetSize(best); +} + + +// by default the origin is not shifted +wxPoint wxWindowBase::GetClientAreaOrigin() const +{ + return wxPoint(0,0); +} + +wxSize wxWindowBase::ClientToWindowSize(const wxSize& size) const +{ + const wxSize diff(GetSize() - GetClientSize()); + + return wxSize(size.x == -1 ? -1 : size.x + diff.x, + size.y == -1 ? -1 : size.y + diff.y); +} + +wxSize wxWindowBase::WindowToClientSize(const wxSize& size) const +{ + const wxSize diff(GetSize() - GetClientSize()); + + return wxSize(size.x == -1 ? -1 : size.x - diff.x, + size.y == -1 ? -1 : size.y - diff.y); +} + +void wxWindowBase::SetWindowVariant( wxWindowVariant variant ) +{ + if ( m_windowVariant != variant ) + { + m_windowVariant = variant; + + DoSetWindowVariant(variant); + } +} + +void wxWindowBase::DoSetWindowVariant( wxWindowVariant variant ) +{ + // adjust the font height to correspond to our new variant (notice that + // we're only called if something really changed) + wxFont font = GetFont(); + int size = font.GetPointSize(); + switch ( variant ) + { + case wxWINDOW_VARIANT_NORMAL: + break; + + case wxWINDOW_VARIANT_SMALL: + size *= 3; + size /= 4; + break; + + case wxWINDOW_VARIANT_MINI: + size *= 2; + size /= 3; + break; + + case wxWINDOW_VARIANT_LARGE: + size *= 5; + size /= 4; + break; + + default: + wxFAIL_MSG(_T("unexpected window variant")); + break; + } + + font.SetPointSize(size); + SetFont(font); +} + +void wxWindowBase::DoSetSizeHints( int minW, int minH, + int maxW, int maxH, + int WXUNUSED(incW), int WXUNUSED(incH) ) +{ + wxCHECK_RET( (minW == wxDefaultCoord || maxW == wxDefaultCoord || minW <= maxW) && + (minH == wxDefaultCoord || maxH == wxDefaultCoord || minH <= maxH), + _T("min width/height must be less than max width/height!") ); + + m_minWidth = minW; + m_maxWidth = maxW; + m_minHeight = minH; + m_maxHeight = maxH; +} + + +void wxWindowBase::SetVirtualSizeHints( int minW, int minH, + int maxW, int maxH ) +{ + m_minVirtualWidth = minW; + m_maxVirtualWidth = maxW; + m_minVirtualHeight = minH; + m_maxVirtualHeight = maxH; +} + +void wxWindowBase::DoSetVirtualSize( int x, int y ) +{ + if ( m_minVirtualWidth != wxDefaultCoord && m_minVirtualWidth > x ) + x = m_minVirtualWidth; + if ( m_maxVirtualWidth != wxDefaultCoord && m_maxVirtualWidth < x ) + x = m_maxVirtualWidth; + if ( m_minVirtualHeight != wxDefaultCoord && m_minVirtualHeight > y ) + y = m_minVirtualHeight; + if ( m_maxVirtualHeight != wxDefaultCoord && m_maxVirtualHeight < y ) + y = m_maxVirtualHeight; + + m_virtualSize = wxSize(x, y); +} + +wxSize wxWindowBase::DoGetVirtualSize() const +{ + // we should use the entire client area so if it is greater than our + // virtual size, expand it to fit (otherwise if the window is big enough we + // wouldn't be using parts of it) + wxSize size = GetClientSize(); + if ( m_virtualSize.x > size.x ) + size.x = m_virtualSize.x; + + if ( m_virtualSize.y >= size.y ) + size.y = m_virtualSize.y; + + return size; +} + +void wxWindowBase::DoGetScreenPosition(int *x, int *y) const +{ + // screen position is the same as (0, 0) in client coords for non TLWs (and + // TLWs override this method) + if ( x ) + *x = 0; + if ( y ) + *y = 0; + + ClientToScreen(x, y); +} + +// ---------------------------------------------------------------------------- +// show/hide/enable/disable the window +// ---------------------------------------------------------------------------- + +bool wxWindowBase::Show(bool show) +{ + if ( show != m_isShown ) + { + m_isShown = show; + + return true; + } + else + { + return false; + } +} + +bool wxWindowBase::Enable(bool enable) +{ + if ( enable != m_isEnabled ) + { + m_isEnabled = enable; + + return true; + } + else + { + return false; + } +} + +bool wxWindowBase::IsShownOnScreen() const +{ + // A window is shown on screen if it itself is shown and so are all its + // parents. But if a window is toplevel one, then its always visible on + // screen if IsShown() returns true, even if it has a hidden parent. + return IsShown() && + (IsTopLevel() || !GetParent() || GetParent()->IsShownOnScreen()); +} + +// ---------------------------------------------------------------------------- +// RTTI +// ---------------------------------------------------------------------------- + +bool wxWindowBase::IsTopLevel() const +{ + return false; +} + +// ---------------------------------------------------------------------------- +// reparenting the window +// ---------------------------------------------------------------------------- + +void wxWindowBase::AddChild(wxWindowBase *child) +{ + wxCHECK_RET( child, wxT("can't add a NULL child") ); + + // this should never happen and it will lead to a crash later if it does + // because RemoveChild() will remove only one node from the children list + // and the other(s) one(s) will be left with dangling pointers in them + wxASSERT_MSG( !GetChildren().Find((wxWindow*)child), _T("AddChild() called twice") ); + + GetChildren().Append((wxWindow*)child); + child->SetParent(this); +} + +void wxWindowBase::RemoveChild(wxWindowBase *child) +{ + wxCHECK_RET( child, wxT("can't remove a NULL child") ); + + GetChildren().DeleteObject((wxWindow *)child); + child->SetParent(NULL); +} + +bool wxWindowBase::Reparent(wxWindowBase *newParent) +{ + wxWindow *oldParent = GetParent(); + if ( newParent == oldParent ) + { + // nothing done + return false; + } + + // unlink this window from the existing parent. + if ( oldParent ) + { + oldParent->RemoveChild(this); + } + else + { + wxTopLevelWindows.DeleteObject((wxWindow *)this); + } + + // add it to the new one + if ( newParent ) + { + newParent->AddChild(this); + } + else + { + wxTopLevelWindows.Append((wxWindow *)this); + } + + return true; +} + +// ---------------------------------------------------------------------------- +// event handler stuff +// ---------------------------------------------------------------------------- + +void wxWindowBase::PushEventHandler(wxEvtHandler *handler) +{ + wxEvtHandler *handlerOld = GetEventHandler(); + + handler->SetNextHandler(handlerOld); + + if ( handlerOld ) + GetEventHandler()->SetPreviousHandler(handler); + + SetEventHandler(handler); +} + +wxEvtHandler *wxWindowBase::PopEventHandler(bool deleteHandler) +{ + wxEvtHandler *handlerA = GetEventHandler(); + if ( handlerA ) + { + wxEvtHandler *handlerB = handlerA->GetNextHandler(); + handlerA->SetNextHandler((wxEvtHandler *)NULL); + + if ( handlerB ) + handlerB->SetPreviousHandler((wxEvtHandler *)NULL); + SetEventHandler(handlerB); + + if ( deleteHandler ) + { + delete handlerA; + handlerA = (wxEvtHandler *)NULL; + } + } + + return handlerA; +} + +bool wxWindowBase::RemoveEventHandler(wxEvtHandler *handler) +{ + wxCHECK_MSG( handler, false, _T("RemoveEventHandler(NULL) called") ); + + wxEvtHandler *handlerPrev = NULL, + *handlerCur = GetEventHandler(); + while ( handlerCur ) + { + wxEvtHandler *handlerNext = handlerCur->GetNextHandler(); + + if ( handlerCur == handler ) + { + if ( handlerPrev ) + { + handlerPrev->SetNextHandler(handlerNext); + } + else + { + SetEventHandler(handlerNext); + } + + if ( handlerNext ) + { + handlerNext->SetPreviousHandler ( handlerPrev ); + } + + handler->SetNextHandler(NULL); + handler->SetPreviousHandler(NULL); + + return true; + } + + handlerPrev = handlerCur; + handlerCur = handlerNext; + } + + wxFAIL_MSG( _T("where has the event handler gone?") ); + + return false; +} + +// ---------------------------------------------------------------------------- +// colours, fonts &c +// ---------------------------------------------------------------------------- + +void wxWindowBase::InheritAttributes() +{ + const wxWindowBase * const parent = GetParent(); + if ( !parent ) + return; + + // we only inherit attributes which had been explicitly set for the parent + // which ensures that this only happens if the user really wants it and + // not by default which wouldn't make any sense in modern GUIs where the + // controls don't all use the same fonts (nor colours) + if ( parent->m_inheritFont && !m_hasFont ) + SetFont(parent->GetFont()); + + // in addition, there is a possibility to explicitly forbid inheriting + // colours at each class level by overriding ShouldInheritColours() + if ( ShouldInheritColours() ) + { + if ( parent->m_inheritFgCol && !m_hasFgCol ) + SetForegroundColour(parent->GetForegroundColour()); + + // inheriting (solid) background colour is wrong as it totally breaks + // any kind of themed backgrounds + // + // instead, the controls should use the same background as their parent + // (ideally by not drawing it at all) +#if 0 + if ( parent->m_inheritBgCol && !m_hasBgCol ) + SetBackgroundColour(parent->GetBackgroundColour()); +#endif // 0 + } +} + +/* static */ wxVisualAttributes +wxWindowBase::GetClassDefaultAttributes(wxWindowVariant WXUNUSED(variant)) +{ + // it is important to return valid values for all attributes from here, + // GetXXX() below rely on this + wxVisualAttributes attrs; + attrs.font = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT); + attrs.colFg = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT); + + // On Smartphone/PocketPC, wxSYS_COLOUR_WINDOW is a better reflection of + // the usual background colour than wxSYS_COLOUR_BTNFACE. + // It's a pity that wxSYS_COLOUR_WINDOW isn't always a suitable background + // colour on other platforms. + +#if defined(__WXWINCE__) && (defined(__SMARTPHONE__) || defined(__POCKETPC__)) + attrs.colBg = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW); +#else + attrs.colBg = wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE); +#endif + return attrs; +} + +wxColour wxWindowBase::GetBackgroundColour() const +{ + if ( !m_backgroundColour.Ok() ) + { + wxASSERT_MSG( !m_hasBgCol, _T("we have invalid explicit bg colour?") ); + + // get our default background colour + wxColour colBg = GetDefaultAttributes().colBg; + + // we must return some valid colour to avoid redoing this every time + // and also to avoid surprizing the applications written for older + // wxWidgets versions where GetBackgroundColour() always returned + // something -- so give them something even if it doesn't make sense + // for this window (e.g. it has a themed background) + if ( !colBg.Ok() ) + colBg = GetClassDefaultAttributes().colBg; + + return colBg; + } + else + return m_backgroundColour; +} + +wxColour wxWindowBase::GetForegroundColour() const +{ + // logic is the same as above + if ( !m_hasFgCol && !m_foregroundColour.Ok() ) + { + wxASSERT_MSG( !m_hasFgCol, _T("we have invalid explicit fg colour?") ); + + wxColour colFg = GetDefaultAttributes().colFg; + + if ( !colFg.Ok() ) + colFg = GetClassDefaultAttributes().colFg; + + return colFg; + } + else + return m_foregroundColour; +} + +bool wxWindowBase::SetBackgroundColour( const wxColour &colour ) +{ + if ( colour == m_backgroundColour ) + return false; + + m_hasBgCol = colour.Ok(); + if ( m_backgroundStyle != wxBG_STYLE_CUSTOM ) + m_backgroundStyle = m_hasBgCol ? wxBG_STYLE_COLOUR : wxBG_STYLE_SYSTEM; + + m_inheritBgCol = m_hasBgCol; + m_backgroundColour = colour; + SetThemeEnabled( !m_hasBgCol && !m_foregroundColour.Ok() ); + return true; +} + +bool wxWindowBase::SetForegroundColour( const wxColour &colour ) +{ + if (colour == m_foregroundColour ) + return false; + + m_hasFgCol = colour.Ok(); + m_inheritFgCol = m_hasFgCol; + m_foregroundColour = colour; + SetThemeEnabled( !m_hasFgCol && !m_backgroundColour.Ok() ); + return true; +} + +bool wxWindowBase::SetCursor(const wxCursor& cursor) +{ + // setting an invalid cursor is ok, it means that we don't have any special + // cursor + if ( m_cursor.IsSameAs(cursor) ) + { + // no change + return false; + } + + m_cursor = cursor; + + return true; +} + +wxFont wxWindowBase::GetFont() const +{ + // logic is the same as in GetBackgroundColour() + if ( !m_font.Ok() ) + { + wxASSERT_MSG( !m_hasFont, _T("we have invalid explicit font?") ); + + wxFont font = GetDefaultAttributes().font; + if ( !font.Ok() ) + font = GetClassDefaultAttributes().font; + + return font; + } + else + return m_font; +} + +bool wxWindowBase::SetFont(const wxFont& font) +{ + if ( font == m_font ) + { + // no change + return false; + } + + m_font = font; + m_hasFont = font.Ok(); + m_inheritFont = m_hasFont; + + InvalidateBestSize(); + + return true; +} + +#if wxUSE_PALETTE + +void wxWindowBase::SetPalette(const wxPalette& pal) +{ + m_hasCustomPalette = true; + m_palette = pal; + + // VZ: can anyone explain me what do we do here? + wxWindowDC d((wxWindow *) this); + d.SetPalette(pal); +} + +wxWindow *wxWindowBase::GetAncestorWithCustomPalette() const +{ + wxWindow *win = (wxWindow *)this; + while ( win && !win->HasCustomPalette() ) + { + win = win->GetParent(); + } + + return win; +} + +#endif // wxUSE_PALETTE + +#if wxUSE_CARET +void wxWindowBase::SetCaret(wxCaret *caret) +{ + if ( m_caret ) + { + delete m_caret; + } + + m_caret = caret; + + if ( m_caret ) + { + wxASSERT_MSG( m_caret->GetWindow() == this, + wxT("caret should be created associated to this window") ); + } +} +#endif // wxUSE_CARET + +#if wxUSE_VALIDATORS +// ---------------------------------------------------------------------------- +// validators +// ---------------------------------------------------------------------------- + +void wxWindowBase::SetValidator(const wxValidator& validator) +{ + if ( m_windowValidator ) + delete m_windowValidator; + + m_windowValidator = (wxValidator *)validator.Clone(); + + if ( m_windowValidator ) + m_windowValidator->SetWindow(this); +} +#endif // wxUSE_VALIDATORS + +// ---------------------------------------------------------------------------- +// update region stuff +// ---------------------------------------------------------------------------- + +wxRect wxWindowBase::GetUpdateClientRect() const +{ + wxRegion rgnUpdate = GetUpdateRegion(); + rgnUpdate.Intersect(GetClientRect()); + wxRect rectUpdate = rgnUpdate.GetBox(); + wxPoint ptOrigin = GetClientAreaOrigin(); + rectUpdate.x -= ptOrigin.x; + rectUpdate.y -= ptOrigin.y; + + return rectUpdate; +} + +bool wxWindowBase::DoIsExposed(int x, int y) const +{ + return m_updateRegion.Contains(x, y) != wxOutRegion; +} + +bool wxWindowBase::DoIsExposed(int x, int y, int w, int h) const +{ + return m_updateRegion.Contains(x, y, w, h) != wxOutRegion; +} + +void wxWindowBase::ClearBackground() +{ + // wxGTK uses its own version, no need to add never used code +#ifndef __WXGTK__ + wxClientDC dc((wxWindow *)this); + wxBrush brush(GetBackgroundColour(), wxSOLID); + dc.SetBackground(brush); + dc.Clear(); +#endif // __WXGTK__ +} + +// ---------------------------------------------------------------------------- +// find child window by id or name +// ---------------------------------------------------------------------------- + +wxWindow *wxWindowBase::FindWindow(long id) const +{ + if ( id == m_windowId ) + return (wxWindow *)this; + + wxWindowBase *res = (wxWindow *)NULL; + wxWindowList::compatibility_iterator node; + for ( node = m_children.GetFirst(); node && !res; node = node->GetNext() ) + { + wxWindowBase *child = node->GetData(); + res = child->FindWindow( id ); + } + + return (wxWindow *)res; +} + +wxWindow *wxWindowBase::FindWindow(const wxString& name) const +{ + if ( name == m_windowName ) + return (wxWindow *)this; + + wxWindowBase *res = (wxWindow *)NULL; + wxWindowList::compatibility_iterator node; + for ( node = m_children.GetFirst(); node && !res; node = node->GetNext() ) + { + wxWindow *child = node->GetData(); + res = child->FindWindow(name); + } + + return (wxWindow *)res; +} + + +// find any window by id or name or label: If parent is non-NULL, look through +// children for a label or title matching the specified string. If NULL, look +// through all top-level windows. +// +// to avoid duplicating code we reuse the same helper function but with +// different comparators + +typedef bool (*wxFindWindowCmp)(const wxWindow *win, + const wxString& label, long id); + +static +bool wxFindWindowCmpLabels(const wxWindow *win, const wxString& label, + long WXUNUSED(id)) +{ + return win->GetLabel() == label; +} + +static +bool wxFindWindowCmpNames(const wxWindow *win, const wxString& label, + long WXUNUSED(id)) +{ + return win->GetName() == label; +} + +static +bool wxFindWindowCmpIds(const wxWindow *win, const wxString& WXUNUSED(label), + long id) +{ + return win->GetId() == id; +} + +// recursive helper for the FindWindowByXXX() functions +static +wxWindow *wxFindWindowRecursively(const wxWindow *parent, + const wxString& label, + long id, + wxFindWindowCmp cmp) +{ + if ( parent ) + { + // see if this is the one we're looking for + if ( (*cmp)(parent, label, id) ) + return (wxWindow *)parent; + + // It wasn't, so check all its children + for ( wxWindowList::compatibility_iterator node = parent->GetChildren().GetFirst(); + node; + node = node->GetNext() ) + { + // recursively check each child + wxWindow *win = (wxWindow *)node->GetData(); + wxWindow *retwin = wxFindWindowRecursively(win, label, id, cmp); + if (retwin) + return retwin; + } + } + + // Not found + return NULL; +} + +// helper for FindWindowByXXX() +static +wxWindow *wxFindWindowHelper(const wxWindow *parent, + const wxString& label, + long id, + wxFindWindowCmp cmp) +{ + if ( parent ) + { + // just check parent and all its children + return wxFindWindowRecursively(parent, label, id, cmp); + } + + // start at very top of wx's windows + for ( wxWindowList::compatibility_iterator node = wxTopLevelWindows.GetFirst(); + node; + node = node->GetNext() ) + { + // recursively check each window & its children + wxWindow *win = node->GetData(); + wxWindow *retwin = wxFindWindowRecursively(win, label, id, cmp); + if (retwin) + return retwin; + } + + return NULL; +} + +/* static */ +wxWindow * +wxWindowBase::FindWindowByLabel(const wxString& title, const wxWindow *parent) +{ + return wxFindWindowHelper(parent, title, 0, wxFindWindowCmpLabels); +} + +/* static */ +wxWindow * +wxWindowBase::FindWindowByName(const wxString& title, const wxWindow *parent) +{ + wxWindow *win = wxFindWindowHelper(parent, title, 0, wxFindWindowCmpNames); + + if ( !win ) + { + // fall back to the label + win = FindWindowByLabel(title, parent); + } + + return win; +} + +/* static */ +wxWindow * +wxWindowBase::FindWindowById( long id, const wxWindow* parent ) +{ + return wxFindWindowHelper(parent, wxEmptyString, id, wxFindWindowCmpIds); +} + +// ---------------------------------------------------------------------------- +// dialog oriented functions +// ---------------------------------------------------------------------------- + +void wxWindowBase::MakeModal(bool modal) +{ + // Disable all other windows + if ( IsTopLevel() ) + { + wxWindowList::compatibility_iterator node = wxTopLevelWindows.GetFirst(); + while (node) + { + wxWindow *win = node->GetData(); + if (win != this) + win->Enable(!modal); + + node = node->GetNext(); + } + } +} + +bool wxWindowBase::Validate() +{ +#if wxUSE_VALIDATORS + bool recurse = (GetExtraStyle() & wxWS_EX_VALIDATE_RECURSIVELY) != 0; + + wxWindowList::compatibility_iterator node; + for ( node = m_children.GetFirst(); node; node = node->GetNext() ) + { + wxWindowBase *child = node->GetData(); + wxValidator *validator = child->GetValidator(); + if ( validator && !validator->Validate((wxWindow *)this) ) + { + return false; + } + + if ( recurse && !child->Validate() ) + { + return false; + } + } +#endif // wxUSE_VALIDATORS + + return true; +} + +bool wxWindowBase::TransferDataToWindow() +{ +#if wxUSE_VALIDATORS + bool recurse = (GetExtraStyle() & wxWS_EX_VALIDATE_RECURSIVELY) != 0; + + wxWindowList::compatibility_iterator node; + for ( node = m_children.GetFirst(); node; node = node->GetNext() ) + { + wxWindowBase *child = node->GetData(); + wxValidator *validator = child->GetValidator(); + if ( validator && !validator->TransferToWindow() ) + { + wxLogWarning(_("Could not transfer data to window")); +#if wxUSE_LOG + wxLog::FlushActive(); +#endif // wxUSE_LOG + + return false; + } + + if ( recurse ) + { + if ( !child->TransferDataToWindow() ) + { + // warning already given + return false; + } + } + } +#endif // wxUSE_VALIDATORS + + return true; +} + +bool wxWindowBase::TransferDataFromWindow() +{ +#if wxUSE_VALIDATORS + bool recurse = (GetExtraStyle() & wxWS_EX_VALIDATE_RECURSIVELY) != 0; + + wxWindowList::compatibility_iterator node; + for ( node = m_children.GetFirst(); node; node = node->GetNext() ) + { + wxWindow *child = node->GetData(); + wxValidator *validator = child->GetValidator(); + if ( validator && !validator->TransferFromWindow() ) + { + // nop warning here because the application is supposed to give + // one itself - we don't know here what might have gone wrongly + + return false; + } + + if ( recurse ) + { + if ( !child->TransferDataFromWindow() ) + { + // warning already given + return false; + } + } + } +#endif // wxUSE_VALIDATORS + + return true; +} + +void wxWindowBase::InitDialog() +{ + wxInitDialogEvent event(GetId()); + event.SetEventObject( this ); + GetEventHandler()->ProcessEvent(event); +} + +// ---------------------------------------------------------------------------- +// context-sensitive help support +// ---------------------------------------------------------------------------- + +#if wxUSE_HELP + +// associate this help text with this window +void wxWindowBase::SetHelpText(const wxString& text) +{ + wxHelpProvider *helpProvider = wxHelpProvider::Get(); + if ( helpProvider ) + { + helpProvider->AddHelp(this, text); + } +} + +// associate this help text with all windows with the same id as this +// one +void wxWindowBase::SetHelpTextForId(const wxString& text) +{ + wxHelpProvider *helpProvider = wxHelpProvider::Get(); + if ( helpProvider ) + { + helpProvider->AddHelp(GetId(), text); + } +} + +// get the help string associated with this window (may be empty) +// default implementation forwards calls to the help provider +wxString +wxWindowBase::GetHelpTextAtPoint(const wxPoint & WXUNUSED(pt), + wxHelpEvent::Origin WXUNUSED(origin)) const +{ + wxString text; + wxHelpProvider *helpProvider = wxHelpProvider::Get(); + if ( helpProvider ) + { + text = helpProvider->GetHelp(this); + } + + return text; +} + +// show help for this window +void wxWindowBase::OnHelp(wxHelpEvent& event) +{ + wxHelpProvider *helpProvider = wxHelpProvider::Get(); + if ( helpProvider ) + { + wxPoint pos = event.GetPosition(); + const wxHelpEvent::Origin origin = event.GetOrigin(); + if ( origin == wxHelpEvent::Origin_Keyboard ) + { + // if the help event was generated from keyboard it shouldn't + // appear at the mouse position (which is still the only position + // associated with help event) if the mouse is far away, although + // we still do use the mouse position if it's over the window + // because we suppose the user looks approximately at the mouse + // already and so it would be more convenient than showing tooltip + // at some arbitrary position which can be quite far from it + const wxRect rectClient = GetClientRect(); + if ( !rectClient.Contains(ScreenToClient(pos)) ) + { + // position help slightly under and to the right of this window + pos = ClientToScreen(wxPoint( + 2*GetCharWidth(), + rectClient.height + GetCharHeight() + )); + } + } + + if ( helpProvider->ShowHelpAtPoint(this, pos, origin) ) + { + // skip the event.Skip() below + return; + } + } + + event.Skip(); +} + +#endif // wxUSE_HELP + +// ---------------------------------------------------------------------------- +// tooltips +// ---------------------------------------------------------------------------- + +#if wxUSE_TOOLTIPS + +void wxWindowBase::SetToolTip( const wxString &tip ) +{ + // don't create the new tooltip if we already have one + if ( m_tooltip ) + { + m_tooltip->SetTip( tip ); + } + else + { + SetToolTip( new wxToolTip( tip ) ); + } + + // setting empty tooltip text does not remove the tooltip any more - use + // SetToolTip((wxToolTip *)NULL) for this +} + +void wxWindowBase::DoSetToolTip(wxToolTip *tooltip) +{ + if ( m_tooltip != tooltip ) + { + if ( m_tooltip ) + delete m_tooltip; + + m_tooltip = tooltip; + } +} + +#endif // wxUSE_TOOLTIPS + +// ---------------------------------------------------------------------------- +// constraints and sizers +// ---------------------------------------------------------------------------- + +#if wxUSE_CONSTRAINTS + +void wxWindowBase::SetConstraints( wxLayoutConstraints *constraints ) +{ + if ( m_constraints ) + { + UnsetConstraints(m_constraints); + delete m_constraints; + } + m_constraints = constraints; + if ( m_constraints ) + { + // Make sure other windows know they're part of a 'meaningful relationship' + if ( m_constraints->left.GetOtherWindow() && (m_constraints->left.GetOtherWindow() != this) ) + m_constraints->left.GetOtherWindow()->AddConstraintReference(this); + if ( m_constraints->top.GetOtherWindow() && (m_constraints->top.GetOtherWindow() != this) ) + m_constraints->top.GetOtherWindow()->AddConstraintReference(this); + if ( m_constraints->right.GetOtherWindow() && (m_constraints->right.GetOtherWindow() != this) ) + m_constraints->right.GetOtherWindow()->AddConstraintReference(this); + if ( m_constraints->bottom.GetOtherWindow() && (m_constraints->bottom.GetOtherWindow() != this) ) + m_constraints->bottom.GetOtherWindow()->AddConstraintReference(this); + if ( m_constraints->width.GetOtherWindow() && (m_constraints->width.GetOtherWindow() != this) ) + m_constraints->width.GetOtherWindow()->AddConstraintReference(this); + if ( m_constraints->height.GetOtherWindow() && (m_constraints->height.GetOtherWindow() != this) ) + m_constraints->height.GetOtherWindow()->AddConstraintReference(this); + if ( m_constraints->centreX.GetOtherWindow() && (m_constraints->centreX.GetOtherWindow() != this) ) + m_constraints->centreX.GetOtherWindow()->AddConstraintReference(this); + if ( m_constraints->centreY.GetOtherWindow() && (m_constraints->centreY.GetOtherWindow() != this) ) + m_constraints->centreY.GetOtherWindow()->AddConstraintReference(this); + } +} + +// This removes any dangling pointers to this window in other windows' +// constraintsInvolvedIn lists. +void wxWindowBase::UnsetConstraints(wxLayoutConstraints *c) +{ + if ( c ) + { + if ( c->left.GetOtherWindow() && (c->top.GetOtherWindow() != this) ) + c->left.GetOtherWindow()->RemoveConstraintReference(this); + if ( c->top.GetOtherWindow() && (c->top.GetOtherWindow() != this) ) + c->top.GetOtherWindow()->RemoveConstraintReference(this); + if ( c->right.GetOtherWindow() && (c->right.GetOtherWindow() != this) ) + c->right.GetOtherWindow()->RemoveConstraintReference(this); + if ( c->bottom.GetOtherWindow() && (c->bottom.GetOtherWindow() != this) ) + c->bottom.GetOtherWindow()->RemoveConstraintReference(this); + if ( c->width.GetOtherWindow() && (c->width.GetOtherWindow() != this) ) + c->width.GetOtherWindow()->RemoveConstraintReference(this); + if ( c->height.GetOtherWindow() && (c->height.GetOtherWindow() != this) ) + c->height.GetOtherWindow()->RemoveConstraintReference(this); + if ( c->centreX.GetOtherWindow() && (c->centreX.GetOtherWindow() != this) ) + c->centreX.GetOtherWindow()->RemoveConstraintReference(this); + if ( c->centreY.GetOtherWindow() && (c->centreY.GetOtherWindow() != this) ) + c->centreY.GetOtherWindow()->RemoveConstraintReference(this); + } +} + +// Back-pointer to other windows we're involved with, so if we delete this +// window, we must delete any constraints we're involved with. +void wxWindowBase::AddConstraintReference(wxWindowBase *otherWin) +{ + if ( !m_constraintsInvolvedIn ) + m_constraintsInvolvedIn = new wxWindowList; + if ( !m_constraintsInvolvedIn->Find((wxWindow *)otherWin) ) + m_constraintsInvolvedIn->Append((wxWindow *)otherWin); +} + +// REMOVE back-pointer to other windows we're involved with. +void wxWindowBase::RemoveConstraintReference(wxWindowBase *otherWin) +{ + if ( m_constraintsInvolvedIn ) + m_constraintsInvolvedIn->DeleteObject((wxWindow *)otherWin); +} + +// Reset any constraints that mention this window +void wxWindowBase::DeleteRelatedConstraints() +{ + if ( m_constraintsInvolvedIn ) + { + wxWindowList::compatibility_iterator node = m_constraintsInvolvedIn->GetFirst(); + while (node) + { + wxWindow *win = node->GetData(); + wxLayoutConstraints *constr = win->GetConstraints(); + + // Reset any constraints involving this window + if ( constr ) + { + constr->left.ResetIfWin(this); + constr->top.ResetIfWin(this); + constr->right.ResetIfWin(this); + constr->bottom.ResetIfWin(this); + constr->width.ResetIfWin(this); + constr->height.ResetIfWin(this); + constr->centreX.ResetIfWin(this); + constr->centreY.ResetIfWin(this); + } + + wxWindowList::compatibility_iterator next = node->GetNext(); + m_constraintsInvolvedIn->Erase(node); + node = next; + } + + delete m_constraintsInvolvedIn; + m_constraintsInvolvedIn = (wxWindowList *) NULL; + } +} + +#endif // wxUSE_CONSTRAINTS + +void wxWindowBase::SetSizer(wxSizer *sizer, bool deleteOld) +{ + if ( sizer == m_windowSizer) + return; + + if ( m_windowSizer ) + { + m_windowSizer->SetContainingWindow(NULL); + + if ( deleteOld ) + delete m_windowSizer; + } + + m_windowSizer = sizer; + if ( m_windowSizer ) + { + m_windowSizer->SetContainingWindow((wxWindow *)this); + } + + SetAutoLayout(m_windowSizer != NULL); +} + +void wxWindowBase::SetSizerAndFit(wxSizer *sizer, bool deleteOld) +{ + SetSizer( sizer, deleteOld ); + sizer->SetSizeHints( (wxWindow*) this ); +} + + +void wxWindowBase::SetContainingSizer(wxSizer* sizer) +{ + // adding a window to a sizer twice is going to result in fatal and + // hard to debug problems later because when deleting the second + // associated wxSizerItem we're going to dereference a dangling + // pointer; so try to detect this as early as possible + wxASSERT_MSG( !sizer || m_containingSizer != sizer, + _T("Adding a window to the same sizer twice?") ); + + m_containingSizer = sizer; +} + +#if wxUSE_CONSTRAINTS + +void wxWindowBase::SatisfyConstraints() +{ + wxLayoutConstraints *constr = GetConstraints(); + bool wasOk = constr && constr->AreSatisfied(); + + ResetConstraints(); // Mark all constraints as unevaluated + + int noChanges = 1; + + // if we're a top level panel (i.e. our parent is frame/dialog), our + // own constraints will never be satisfied any more unless we do it + // here + if ( wasOk ) + { + while ( noChanges > 0 ) + { + LayoutPhase1(&noChanges); + } + } + + LayoutPhase2(&noChanges); +} + +#endif // wxUSE_CONSTRAINTS + +bool wxWindowBase::Layout() +{ + // If there is a sizer, use it instead of the constraints + if ( GetSizer() ) + { + int w = 0, h = 0; + GetVirtualSize(&w, &h); + GetSizer()->SetDimension( 0, 0, w, h ); + } +#if wxUSE_CONSTRAINTS + else + { + SatisfyConstraints(); // Find the right constraints values + SetConstraintSizes(); // Recursively set the real window sizes + } +#endif + + return true; +} + +#if wxUSE_CONSTRAINTS + +// first phase of the constraints evaluation: set our own constraints +bool wxWindowBase::LayoutPhase1(int *noChanges) +{ + wxLayoutConstraints *constr = GetConstraints(); + + return !constr || constr->SatisfyConstraints(this, noChanges); +} + +// second phase: set the constraints for our children +bool wxWindowBase::LayoutPhase2(int *noChanges) +{ + *noChanges = 0; + + // Layout children + DoPhase(1); + + // Layout grand children + DoPhase(2); + + return true; +} + +// Do a phase of evaluating child constraints +bool wxWindowBase::DoPhase(int phase) +{ + // the list containing the children for which the constraints are already + // set correctly + wxWindowList succeeded; + + // the max number of iterations we loop before concluding that we can't set + // the constraints + static const int maxIterations = 500; + + for ( int noIterations = 0; noIterations < maxIterations; noIterations++ ) + { + int noChanges = 0; + + // loop over all children setting their constraints + for ( wxWindowList::compatibility_iterator node = GetChildren().GetFirst(); + node; + node = node->GetNext() ) + { + wxWindow *child = node->GetData(); + if ( child->IsTopLevel() ) + { + // top level children are not inside our client area + continue; + } + + if ( !child->GetConstraints() || succeeded.Find(child) ) + { + // this one is either already ok or nothing we can do about it + continue; + } + + int tempNoChanges = 0; + bool success = phase == 1 ? child->LayoutPhase1(&tempNoChanges) + : child->LayoutPhase2(&tempNoChanges); + noChanges += tempNoChanges; + + if ( success ) + { + succeeded.Append(child); + } + } + + if ( !noChanges ) + { + // constraints are set + break; + } + } + + return true; +} + +void wxWindowBase::ResetConstraints() +{ + wxLayoutConstraints *constr = GetConstraints(); + if ( constr ) + { + constr->left.SetDone(false); + constr->top.SetDone(false); + constr->right.SetDone(false); + constr->bottom.SetDone(false); + constr->width.SetDone(false); + constr->height.SetDone(false); + constr->centreX.SetDone(false); + constr->centreY.SetDone(false); + } + + wxWindowList::compatibility_iterator node = GetChildren().GetFirst(); + while (node) + { + wxWindow *win = node->GetData(); + if ( !win->IsTopLevel() ) + win->ResetConstraints(); + node = node->GetNext(); + } +} + +// Need to distinguish between setting the 'fake' size for windows and sizers, +// and setting the real values. +void wxWindowBase::SetConstraintSizes(bool recurse) +{ + wxLayoutConstraints *constr = GetConstraints(); + if ( constr && constr->AreSatisfied() ) + { + int x = constr->left.GetValue(); + int y = constr->top.GetValue(); + int w = constr->width.GetValue(); + int h = constr->height.GetValue(); + + if ( (constr->width.GetRelationship() != wxAsIs ) || + (constr->height.GetRelationship() != wxAsIs) ) + { + SetSize(x, y, w, h); + } + else + { + // If we don't want to resize this window, just move it... + Move(x, y); + } + } + else if ( constr ) + { + wxLogDebug(wxT("Constraints not satisfied for %s named '%s'."), + GetClassInfo()->GetClassName(), + GetName().c_str()); + } + + if ( recurse ) + { + wxWindowList::compatibility_iterator node = GetChildren().GetFirst(); + while (node) + { + wxWindow *win = node->GetData(); + if ( !win->IsTopLevel() && win->GetConstraints() ) + win->SetConstraintSizes(); + node = node->GetNext(); + } + } +} + +// Only set the size/position of the constraint (if any) +void wxWindowBase::SetSizeConstraint(int x, int y, int w, int h) +{ + wxLayoutConstraints *constr = GetConstraints(); + if ( constr ) + { + if ( x != wxDefaultCoord ) + { + constr->left.SetValue(x); + constr->left.SetDone(true); + } + if ( y != wxDefaultCoord ) + { + constr->top.SetValue(y); + constr->top.SetDone(true); + } + if ( w != wxDefaultCoord ) + { + constr->width.SetValue(w); + constr->width.SetDone(true); + } + if ( h != wxDefaultCoord ) + { + constr->height.SetValue(h); + constr->height.SetDone(true); + } + } +} + +void wxWindowBase::MoveConstraint(int x, int y) +{ + wxLayoutConstraints *constr = GetConstraints(); + if ( constr ) + { + if ( x != wxDefaultCoord ) + { + constr->left.SetValue(x); + constr->left.SetDone(true); + } + if ( y != wxDefaultCoord ) + { + constr->top.SetValue(y); + constr->top.SetDone(true); + } + } +} + +void wxWindowBase::GetSizeConstraint(int *w, int *h) const +{ + wxLayoutConstraints *constr = GetConstraints(); + if ( constr ) + { + *w = constr->width.GetValue(); + *h = constr->height.GetValue(); + } + else + GetSize(w, h); +} + +void wxWindowBase::GetClientSizeConstraint(int *w, int *h) const +{ + wxLayoutConstraints *constr = GetConstraints(); + if ( constr ) + { + *w = constr->width.GetValue(); + *h = constr->height.GetValue(); + } + else + GetClientSize(w, h); +} + +void wxWindowBase::GetPositionConstraint(int *x, int *y) const +{ + wxLayoutConstraints *constr = GetConstraints(); + if ( constr ) + { + *x = constr->left.GetValue(); + *y = constr->top.GetValue(); + } + else + GetPosition(x, y); +} + +#endif // wxUSE_CONSTRAINTS + +void wxWindowBase::AdjustForParentClientOrigin(int& x, int& y, int sizeFlags) const +{ + // don't do it for the dialogs/frames - they float independently of their + // parent + if ( !IsTopLevel() ) + { + wxWindow *parent = GetParent(); + if ( !(sizeFlags & wxSIZE_NO_ADJUSTMENTS) && parent ) + { + wxPoint pt(parent->GetClientAreaOrigin()); + x += pt.x; + y += pt.y; + } + } +} + +// ---------------------------------------------------------------------------- +// Update UI processing +// ---------------------------------------------------------------------------- + +void wxWindowBase::UpdateWindowUI(long flags) +{ + wxUpdateUIEvent event(GetId()); + event.SetEventObject(this); + + if ( GetEventHandler()->ProcessEvent(event) ) + { + DoUpdateWindowUI(event); + } + + if (flags & wxUPDATE_UI_RECURSE) + { + wxWindowList::compatibility_iterator node = GetChildren().GetFirst(); + while (node) + { + wxWindow* child = (wxWindow*) node->GetData(); + child->UpdateWindowUI(flags); + node = node->GetNext(); + } + } +} + +// do the window-specific processing after processing the update event +void wxWindowBase::DoUpdateWindowUI(wxUpdateUIEvent& event) +{ + if ( event.GetSetEnabled() ) + Enable(event.GetEnabled()); + + if ( event.GetSetShown() ) + Show(event.GetShown()); +} + +// ---------------------------------------------------------------------------- +// dialog units translations +// ---------------------------------------------------------------------------- + +wxPoint wxWindowBase::ConvertPixelsToDialog(const wxPoint& pt) +{ + int charWidth = GetCharWidth(); + int charHeight = GetCharHeight(); + wxPoint pt2 = wxDefaultPosition; + if (pt.x != wxDefaultCoord) + pt2.x = (int) ((pt.x * 4) / charWidth); + if (pt.y != wxDefaultCoord) + pt2.y = (int) ((pt.y * 8) / charHeight); + + return pt2; +} + +wxPoint wxWindowBase::ConvertDialogToPixels(const wxPoint& pt) +{ + int charWidth = GetCharWidth(); + int charHeight = GetCharHeight(); + wxPoint pt2 = wxDefaultPosition; + if (pt.x != wxDefaultCoord) + pt2.x = (int) ((pt.x * charWidth) / 4); + if (pt.y != wxDefaultCoord) + pt2.y = (int) ((pt.y * charHeight) / 8); + + return pt2; +} + +// ---------------------------------------------------------------------------- +// event handlers +// ---------------------------------------------------------------------------- + +// propagate the colour change event to the subwindows +void wxWindowBase::OnSysColourChanged(wxSysColourChangedEvent& event) +{ + wxWindowList::compatibility_iterator node = GetChildren().GetFirst(); + while ( node ) + { + // Only propagate to non-top-level windows + wxWindow *win = node->GetData(); + if ( !win->IsTopLevel() ) + { + wxSysColourChangedEvent event2; + event.SetEventObject(win); + win->GetEventHandler()->ProcessEvent(event2); + } + + node = node->GetNext(); + } + + Refresh(); +} + +// the default action is to populate dialog with data when it's created, +// and nudge the UI into displaying itself correctly in case +// we've turned the wxUpdateUIEvents frequency down low. +void wxWindowBase::OnInitDialog( wxInitDialogEvent &WXUNUSED(event) ) +{ + TransferDataToWindow(); + + // Update the UI at this point + UpdateWindowUI(wxUPDATE_UI_RECURSE); +} + +// methods for drawing the sizers in a visible way +#ifdef __WXDEBUG__ + +static void DrawSizers(wxWindowBase *win); + +static void DrawBorder(wxWindowBase *win, const wxRect& rect, bool fill = false) +{ + wxClientDC dc((wxWindow *)win); + dc.SetPen(*wxRED_PEN); + dc.SetBrush(fill ? wxBrush(*wxRED, wxCROSSDIAG_HATCH): *wxTRANSPARENT_BRUSH); + dc.DrawRectangle(rect.Deflate(1, 1)); +} + +static void DrawSizer(wxWindowBase *win, wxSizer *sizer) +{ + const wxSizerItemList& items = sizer->GetChildren(); + for ( wxSizerItemList::const_iterator i = items.begin(), + end = items.end(); + i != end; + ++i ) + { + wxSizerItem *item = *i; + if ( item->IsSizer() ) + { + DrawBorder(win, item->GetRect().Deflate(2)); + DrawSizer(win, item->GetSizer()); + } + else if ( item->IsSpacer() ) + { + DrawBorder(win, item->GetRect().Deflate(2), true); + } + else if ( item->IsWindow() ) + { + DrawSizers(item->GetWindow()); + } + } +} + +static void DrawSizers(wxWindowBase *win) +{ + wxSizer *sizer = win->GetSizer(); + if ( sizer ) + { + DrawBorder(win, win->GetClientSize()); + DrawSizer(win, sizer); + } + else // no sizer, still recurse into the children + { + const wxWindowList& children = win->GetChildren(); + for ( wxWindowList::const_iterator i = children.begin(), + end = children.end(); + i != end; + ++i ) + { + DrawSizers(*i); + } + } +} + +#endif // __WXDEBUG__ + +// process special middle clicks +void wxWindowBase::OnMiddleClick( wxMouseEvent& event ) +{ + if ( event.ControlDown() && event.AltDown() ) + { +#ifdef __WXDEBUG__ + // Ctrl-Alt-Shift-mclick makes the sizers visible in debug builds + if ( event.ShiftDown() ) + { + DrawSizers(this); + return; + } +#endif // __WXDEBUG__ + +#if wxUSE_MSGDLG + // don't translate these strings, they're for diagnostics purposes only + wxString msg; + msg.Printf(_T("wxWidgets Library (%s port)\n") + _T("Version %d.%d.%d%s%s, compiled at %s %s\n") + _T("Runtime version of toolkit used is %d.%d.%s\n") + _T("Copyright (c) 1995-2007 wxWidgets team"), + wxPlatformInfo::Get().GetPortIdName().c_str(), + wxMAJOR_VERSION, + wxMINOR_VERSION, + wxRELEASE_NUMBER, +#if wxUSE_UNICODE + L" (Unicode)", +#else + wxEmptyString, +#endif +#ifdef __WXDEBUG__ + _T(" Debug build"), +#else + wxEmptyString, +#endif + __TDATE__, + __TTIME__, + wxPlatformInfo::Get().GetToolkitMajorVersion(), + wxPlatformInfo::Get().GetToolkitMinorVersion(), +#ifdef __WXGTK__ + wxString::Format(_T("\nThe compile-time GTK+ version is %d.%d.%d."), GTK_MAJOR_VERSION, GTK_MINOR_VERSION, GTK_MICRO_VERSION).c_str() +#else + wxEmptyString +#endif + ); + + wxMessageBox(msg, _T("wxWidgets information"), + wxICON_INFORMATION | wxOK, + (wxWindow *)this); + } + else +#endif // wxUSE_MSGDLG + { + event.Skip(); + } +} + +// ---------------------------------------------------------------------------- +// accessibility +// ---------------------------------------------------------------------------- + +#if wxUSE_ACCESSIBILITY +void wxWindowBase::SetAccessible(wxAccessible* accessible) +{ + if (m_accessible && (accessible != m_accessible)) + delete m_accessible; + m_accessible = accessible; + if (m_accessible) + m_accessible->SetWindow((wxWindow*) this); +} + +// Returns the accessible object, creating if necessary. +wxAccessible* wxWindowBase::GetOrCreateAccessible() +{ + if (!m_accessible) + m_accessible = CreateAccessible(); + return m_accessible; +} + +// Override to create a specific accessible object. +wxAccessible* wxWindowBase::CreateAccessible() +{ + return new wxWindowAccessible((wxWindow*) this); +} + +#endif + +// ---------------------------------------------------------------------------- +// list classes implementation +// ---------------------------------------------------------------------------- + +#if wxUSE_STL + +#include "wx/listimpl.cpp" +WX_DEFINE_LIST(wxWindowList) + +#else // !wxUSE_STL + +void wxWindowListNode::DeleteData() +{ + delete (wxWindow *)GetData(); +} + +#endif // wxUSE_STL/!wxUSE_STL + +// ---------------------------------------------------------------------------- +// borders +// ---------------------------------------------------------------------------- + +wxBorder wxWindowBase::GetBorder(long flags) const +{ + wxBorder border = (wxBorder)(flags & wxBORDER_MASK); + if ( border == wxBORDER_DEFAULT ) + { + border = GetDefaultBorder(); + } + + return border; +} + +wxBorder wxWindowBase::GetDefaultBorder() const +{ + return wxBORDER_NONE; +} + +// ---------------------------------------------------------------------------- +// hit testing +// ---------------------------------------------------------------------------- + +wxHitTest wxWindowBase::DoHitTest(wxCoord x, wxCoord y) const +{ + // here we just check if the point is inside the window or not + + // check the top and left border first + bool outside = x < 0 || y < 0; + if ( !outside ) + { + // check the right and bottom borders too + wxSize size = GetSize(); + outside = x >= size.x || y >= size.y; + } + + return outside ? wxHT_WINDOW_OUTSIDE : wxHT_WINDOW_INSIDE; +} + +// ---------------------------------------------------------------------------- +// mouse capture +// ---------------------------------------------------------------------------- + +struct WXDLLEXPORT wxWindowNext +{ + wxWindow *win; + wxWindowNext *next; +} *wxWindowBase::ms_winCaptureNext = NULL; +wxWindow *wxWindowBase::ms_winCaptureCurrent = NULL; +bool wxWindowBase::ms_winCaptureChanging = false; + +void wxWindowBase::CaptureMouse() +{ + wxLogTrace(_T("mousecapture"), _T("CaptureMouse(%p)"), wx_static_cast(void*, this)); + + wxASSERT_MSG( !ms_winCaptureChanging, _T("recursive CaptureMouse call?") ); + + ms_winCaptureChanging = true; + + wxWindow *winOld = GetCapture(); + if ( winOld ) + { + ((wxWindowBase*) winOld)->DoReleaseMouse(); + + // save it on stack + wxWindowNext *item = new wxWindowNext; + item->win = winOld; + item->next = ms_winCaptureNext; + ms_winCaptureNext = item; + } + //else: no mouse capture to save + + DoCaptureMouse(); + ms_winCaptureCurrent = (wxWindow*)this; + + ms_winCaptureChanging = false; +} + +void wxWindowBase::ReleaseMouse() +{ + wxLogTrace(_T("mousecapture"), _T("ReleaseMouse(%p)"), wx_static_cast(void*, this)); + + wxASSERT_MSG( !ms_winCaptureChanging, _T("recursive ReleaseMouse call?") ); + + wxASSERT_MSG( GetCapture() == this, wxT("attempt to release mouse, but this window hasn't captured it") ); + + ms_winCaptureChanging = true; + + DoReleaseMouse(); + ms_winCaptureCurrent = NULL; + + if ( ms_winCaptureNext ) + { + ((wxWindowBase*)ms_winCaptureNext->win)->DoCaptureMouse(); + ms_winCaptureCurrent = ms_winCaptureNext->win; + + wxWindowNext *item = ms_winCaptureNext; + ms_winCaptureNext = item->next; + delete item; + } + //else: stack is empty, no previous capture + + ms_winCaptureChanging = false; + + wxLogTrace(_T("mousecapture"), + (const wxChar *) _T("After ReleaseMouse() mouse is captured by %p"), + wx_static_cast(void*, GetCapture())); +} + +static void DoNotifyWindowAboutCaptureLost(wxWindow *win) +{ + wxMouseCaptureLostEvent event(win->GetId()); + event.SetEventObject(win); + if ( !win->GetEventHandler()->ProcessEvent(event) ) + { + // windows must handle this event, otherwise the app wouldn't behave + // correctly if it loses capture unexpectedly; see the discussion here: + // http://sourceforge.net/tracker/index.php?func=detail&aid=1153662&group_id=9863&atid=109863 + // http://article.gmane.org/gmane.comp.lib.wxwidgets.devel/82376 + wxFAIL_MSG( _T("window that captured the mouse didn't process wxEVT_MOUSE_CAPTURE_LOST") ); + } +} + +/* static */ +void wxWindowBase::NotifyCaptureLost() +{ + // don't do anything if capture lost was expected, i.e. resulted from + // a wx call to ReleaseMouse or CaptureMouse: + if ( ms_winCaptureChanging ) + return; + + // if the capture was lost unexpectedly, notify every window that has + // capture (on stack or current) about it and clear the stack: + + if ( ms_winCaptureCurrent ) + { + DoNotifyWindowAboutCaptureLost(ms_winCaptureCurrent); + ms_winCaptureCurrent = NULL; + } + + while ( ms_winCaptureNext ) + { + wxWindowNext *item = ms_winCaptureNext; + ms_winCaptureNext = item->next; + + DoNotifyWindowAboutCaptureLost(item->win); + + delete item; + } +} + +#if wxUSE_HOTKEY + +bool +wxWindowBase::RegisterHotKey(int WXUNUSED(hotkeyId), + int WXUNUSED(modifiers), + int WXUNUSED(keycode)) +{ + // not implemented + return false; +} + +bool wxWindowBase::UnregisterHotKey(int WXUNUSED(hotkeyId)) +{ + // not implemented + return false; +} + +#endif // wxUSE_HOTKEY + +// ---------------------------------------------------------------------------- +// event processing +// ---------------------------------------------------------------------------- + +bool wxWindowBase::TryValidator(wxEvent& wxVALIDATOR_PARAM(event)) +{ +#if wxUSE_VALIDATORS + // Can only use the validator of the window which + // is receiving the event + if ( event.GetEventObject() == this ) + { + wxValidator *validator = GetValidator(); + if ( validator && validator->ProcessEvent(event) ) + { + return true; + } + } +#endif // wxUSE_VALIDATORS + + return false; +} + +bool wxWindowBase::TryParent(wxEvent& event) +{ + // carry on up the parent-child hierarchy if the propagation count hasn't + // reached zero yet + if ( event.ShouldPropagate() ) + { + // honour the requests to stop propagation at this window: this is + // used by the dialogs, for example, to prevent processing the events + // from the dialog controls in the parent frame which rarely, if ever, + // makes sense + if ( !(GetExtraStyle() & wxWS_EX_BLOCK_EVENTS) ) + { + wxWindow *parent = GetParent(); + if ( parent && !parent->IsBeingDeleted() ) + { + wxPropagateOnce propagateOnce(event); + + return parent->GetEventHandler()->ProcessEvent(event); + } + } + } + + return wxEvtHandler::TryParent(event); +} + +// ---------------------------------------------------------------------------- +// window relationships +// ---------------------------------------------------------------------------- + +wxWindow *wxWindowBase::DoGetSibling(MoveKind order) const +{ + wxCHECK_MSG( GetParent(), NULL, + _T("GetPrev/NextSibling() don't work for TLWs!") ); + + wxWindowList& siblings = GetParent()->GetChildren(); + wxWindowList::compatibility_iterator i = siblings.Find((wxWindow *)this); + wxCHECK_MSG( i, NULL, _T("window not a child of its parent?") ); + + if ( order == MoveBefore ) + i = i->GetPrevious(); + else // MoveAfter + i = i->GetNext(); + + return i ? i->GetData() : NULL; +} + +// ---------------------------------------------------------------------------- +// keyboard navigation +// ---------------------------------------------------------------------------- + +// Navigates in the specified direction. +bool wxWindowBase::Navigate(int flags) +{ + wxNavigationKeyEvent eventNav; + eventNav.SetFlags(flags); + eventNav.SetEventObject(this); + if ( GetParent()->GetEventHandler()->ProcessEvent(eventNav) ) + { + return true; + } + return false; +} + +void wxWindowBase::DoMoveInTabOrder(wxWindow *win, MoveKind move) +{ + // check that we're not a top level window + wxCHECK_RET( GetParent(), + _T("MoveBefore/AfterInTabOrder() don't work for TLWs!") ); + + // detect the special case when we have nothing to do anyhow and when the + // code below wouldn't work + if ( win == this ) + return; + + // find the target window in the siblings list + wxWindowList& siblings = GetParent()->GetChildren(); + wxWindowList::compatibility_iterator i = siblings.Find(win); + wxCHECK_RET( i, _T("MoveBefore/AfterInTabOrder(): win is not a sibling") ); + + // unfortunately, when wxUSE_STL == 1 DetachNode() is not implemented so we + // can't just move the node around + wxWindow *self = (wxWindow *)this; + siblings.DeleteObject(self); + if ( move == MoveAfter ) + { + i = i->GetNext(); + } + + if ( i ) + { + siblings.Insert(i, self); + } + else // MoveAfter and win was the last sibling + { + siblings.Append(self); + } +} + +// ---------------------------------------------------------------------------- +// focus handling +// ---------------------------------------------------------------------------- + +/*static*/ wxWindow* wxWindowBase::FindFocus() +{ + wxWindowBase *win = DoFindFocus(); + return win ? win->GetMainWindowOfCompositeControl() : NULL; +} + +// ---------------------------------------------------------------------------- +// global functions +// ---------------------------------------------------------------------------- + +wxWindow* wxGetTopLevelParent(wxWindow *win) +{ + while ( win && !win->IsTopLevel() ) + win = win->GetParent(); + + return win; +} + +#if wxUSE_ACCESSIBILITY +// ---------------------------------------------------------------------------- +// accessible object for windows +// ---------------------------------------------------------------------------- + +// Can return either a child object, or an integer +// representing the child element, starting from 1. +wxAccStatus wxWindowAccessible::HitTest(const wxPoint& WXUNUSED(pt), int* WXUNUSED(childId), wxAccessible** WXUNUSED(childObject)) +{ + wxASSERT( GetWindow() != NULL ); + if (!GetWindow()) + return wxACC_FAIL; + + return wxACC_NOT_IMPLEMENTED; +} + +// Returns the rectangle for this object (id = 0) or a child element (id > 0). +wxAccStatus wxWindowAccessible::GetLocation(wxRect& rect, int elementId) +{ + wxASSERT( GetWindow() != NULL ); + if (!GetWindow()) + return wxACC_FAIL; + + wxWindow* win = NULL; + if (elementId == 0) + { + win = GetWindow(); + } + else + { + if (elementId <= (int) GetWindow()->GetChildren().GetCount()) + { + win = GetWindow()->GetChildren().Item(elementId-1)->GetData(); + } + else + return wxACC_FAIL; + } + if (win) + { + rect = win->GetRect(); + if (win->GetParent() && !win->IsKindOf(CLASSINFO(wxTopLevelWindow))) + rect.SetPosition(win->GetParent()->ClientToScreen(rect.GetPosition())); + return wxACC_OK; + } + + return wxACC_NOT_IMPLEMENTED; +} + +// Navigates from fromId to toId/toObject. +wxAccStatus wxWindowAccessible::Navigate(wxNavDir navDir, int fromId, + int* WXUNUSED(toId), wxAccessible** toObject) +{ + wxASSERT( GetWindow() != NULL ); + if (!GetWindow()) + return wxACC_FAIL; + + switch (navDir) + { + case wxNAVDIR_FIRSTCHILD: + { + if (GetWindow()->GetChildren().GetCount() == 0) + return wxACC_FALSE; + wxWindow* childWindow = (wxWindow*) GetWindow()->GetChildren().GetFirst()->GetData(); + *toObject = childWindow->GetOrCreateAccessible(); + + return wxACC_OK; + } + case wxNAVDIR_LASTCHILD: + { + if (GetWindow()->GetChildren().GetCount() == 0) + return wxACC_FALSE; + wxWindow* childWindow = (wxWindow*) GetWindow()->GetChildren().GetLast()->GetData(); + *toObject = childWindow->GetOrCreateAccessible(); + + return wxACC_OK; + } + case wxNAVDIR_RIGHT: + case wxNAVDIR_DOWN: + case wxNAVDIR_NEXT: + { + wxWindowList::compatibility_iterator node = + wxWindowList::compatibility_iterator(); + if (fromId == 0) + { + // Can't navigate to sibling of this window + // if we're a top-level window. + if (!GetWindow()->GetParent()) + return wxACC_NOT_IMPLEMENTED; + + node = GetWindow()->GetParent()->GetChildren().Find(GetWindow()); + } + else + { + if (fromId <= (int) GetWindow()->GetChildren().GetCount()) + node = GetWindow()->GetChildren().Item(fromId-1); + } + + if (node && node->GetNext()) + { + wxWindow* nextWindow = node->GetNext()->GetData(); + *toObject = nextWindow->GetOrCreateAccessible(); + return wxACC_OK; + } + else + return wxACC_FALSE; + } + case wxNAVDIR_LEFT: + case wxNAVDIR_UP: + case wxNAVDIR_PREVIOUS: + { + wxWindowList::compatibility_iterator node = + wxWindowList::compatibility_iterator(); + if (fromId == 0) + { + // Can't navigate to sibling of this window + // if we're a top-level window. + if (!GetWindow()->GetParent()) + return wxACC_NOT_IMPLEMENTED; + + node = GetWindow()->GetParent()->GetChildren().Find(GetWindow()); + } + else + { + if (fromId <= (int) GetWindow()->GetChildren().GetCount()) + node = GetWindow()->GetChildren().Item(fromId-1); + } + + if (node && node->GetPrevious()) + { + wxWindow* previousWindow = node->GetPrevious()->GetData(); + *toObject = previousWindow->GetOrCreateAccessible(); + return wxACC_OK; + } + else + return wxACC_FALSE; + } + } + + return wxACC_NOT_IMPLEMENTED; +} + +// Gets the name of the specified object. +wxAccStatus wxWindowAccessible::GetName(int childId, wxString* name) +{ + wxASSERT( GetWindow() != NULL ); + if (!GetWindow()) + return wxACC_FAIL; + + wxString title; + + // If a child, leave wxWidgets to call the function on the actual + // child object. + if (childId > 0) + return wxACC_NOT_IMPLEMENTED; + + // This will eventually be replaced by specialised + // accessible classes, one for each kind of wxWidgets + // control or window. +#if wxUSE_BUTTON + if (GetWindow()->IsKindOf(CLASSINFO(wxButton))) + title = ((wxButton*) GetWindow())->GetLabel(); + else +#endif + title = GetWindow()->GetName(); + + if (!title.empty()) + { + *name = title; + return wxACC_OK; + } + else + return wxACC_NOT_IMPLEMENTED; +} + +// Gets the number of children. +wxAccStatus wxWindowAccessible::GetChildCount(int* childId) +{ + wxASSERT( GetWindow() != NULL ); + if (!GetWindow()) + return wxACC_FAIL; + + *childId = (int) GetWindow()->GetChildren().GetCount(); + return wxACC_OK; +} + +// Gets the specified child (starting from 1). +// If *child is NULL and return value is wxACC_OK, +// this means that the child is a simple element and +// not an accessible object. +wxAccStatus wxWindowAccessible::GetChild(int childId, wxAccessible** child) +{ + wxASSERT( GetWindow() != NULL ); + if (!GetWindow()) + return wxACC_FAIL; + + if (childId == 0) + { + *child = this; + return wxACC_OK; + } + + if (childId > (int) GetWindow()->GetChildren().GetCount()) + return wxACC_FAIL; + + wxWindow* childWindow = GetWindow()->GetChildren().Item(childId-1)->GetData(); + *child = childWindow->GetOrCreateAccessible(); + if (*child) + return wxACC_OK; + else + return wxACC_FAIL; +} + +// Gets the parent, or NULL. +wxAccStatus wxWindowAccessible::GetParent(wxAccessible** parent) +{ + wxASSERT( GetWindow() != NULL ); + if (!GetWindow()) + return wxACC_FAIL; + + wxWindow* parentWindow = GetWindow()->GetParent(); + if (!parentWindow) + { + *parent = NULL; + return wxACC_OK; + } + else + { + *parent = parentWindow->GetOrCreateAccessible(); + if (*parent) + return wxACC_OK; + else + return wxACC_FAIL; + } +} + +// Performs the default action. childId is 0 (the action for this object) +// or > 0 (the action for a child). +// Return wxACC_NOT_SUPPORTED if there is no default action for this +// window (e.g. an edit control). +wxAccStatus wxWindowAccessible::DoDefaultAction(int WXUNUSED(childId)) +{ + wxASSERT( GetWindow() != NULL ); + if (!GetWindow()) + return wxACC_FAIL; + + return wxACC_NOT_IMPLEMENTED; +} + +// Gets the default action for this object (0) or > 0 (the action for a child). +// Return wxACC_OK even if there is no action. actionName is the action, or the empty +// string if there is no action. +// The retrieved string describes the action that is performed on an object, +// not what the object does as a result. For example, a toolbar button that prints +// a document has a default action of "Press" rather than "Prints the current document." +wxAccStatus wxWindowAccessible::GetDefaultAction(int WXUNUSED(childId), wxString* WXUNUSED(actionName)) +{ + wxASSERT( GetWindow() != NULL ); + if (!GetWindow()) + return wxACC_FAIL; + + return wxACC_NOT_IMPLEMENTED; +} + +// Returns the description for this object or a child. +wxAccStatus wxWindowAccessible::GetDescription(int WXUNUSED(childId), wxString* description) +{ + wxASSERT( GetWindow() != NULL ); + if (!GetWindow()) + return wxACC_FAIL; + + wxString ht(GetWindow()->GetHelpTextAtPoint(wxDefaultPosition, wxHelpEvent::Origin_Keyboard)); + if (!ht.empty()) + { + *description = ht; + return wxACC_OK; + } + return wxACC_NOT_IMPLEMENTED; +} + +// Returns help text for this object or a child, similar to tooltip text. +wxAccStatus wxWindowAccessible::GetHelpText(int WXUNUSED(childId), wxString* helpText) +{ + wxASSERT( GetWindow() != NULL ); + if (!GetWindow()) + return wxACC_FAIL; + + wxString ht(GetWindow()->GetHelpTextAtPoint(wxDefaultPosition, wxHelpEvent::Origin_Keyboard)); + if (!ht.empty()) + { + *helpText = ht; + return wxACC_OK; + } + return wxACC_NOT_IMPLEMENTED; +} + +// Returns the keyboard shortcut for this object or child. +// Return e.g. ALT+K +wxAccStatus wxWindowAccessible::GetKeyboardShortcut(int WXUNUSED(childId), wxString* WXUNUSED(shortcut)) +{ + wxASSERT( GetWindow() != NULL ); + if (!GetWindow()) + return wxACC_FAIL; + + return wxACC_NOT_IMPLEMENTED; +} + +// Returns a role constant. +wxAccStatus wxWindowAccessible::GetRole(int childId, wxAccRole* role) +{ + wxASSERT( GetWindow() != NULL ); + if (!GetWindow()) + return wxACC_FAIL; + + // If a child, leave wxWidgets to call the function on the actual + // child object. + if (childId > 0) + return wxACC_NOT_IMPLEMENTED; + + if (GetWindow()->IsKindOf(CLASSINFO(wxControl))) + return wxACC_NOT_IMPLEMENTED; +#if wxUSE_STATUSBAR + if (GetWindow()->IsKindOf(CLASSINFO(wxStatusBar))) + return wxACC_NOT_IMPLEMENTED; +#endif +#if wxUSE_TOOLBAR + if (GetWindow()->IsKindOf(CLASSINFO(wxToolBar))) + return wxACC_NOT_IMPLEMENTED; +#endif + + //*role = wxROLE_SYSTEM_CLIENT; + *role = wxROLE_SYSTEM_CLIENT; + return wxACC_OK; + + #if 0 + return wxACC_NOT_IMPLEMENTED; + #endif +} + +// Returns a state constant. +wxAccStatus wxWindowAccessible::GetState(int childId, long* state) +{ + wxASSERT( GetWindow() != NULL ); + if (!GetWindow()) + return wxACC_FAIL; + + // If a child, leave wxWidgets to call the function on the actual + // child object. + if (childId > 0) + return wxACC_NOT_IMPLEMENTED; + + if (GetWindow()->IsKindOf(CLASSINFO(wxControl))) + return wxACC_NOT_IMPLEMENTED; + +#if wxUSE_STATUSBAR + if (GetWindow()->IsKindOf(CLASSINFO(wxStatusBar))) + return wxACC_NOT_IMPLEMENTED; +#endif +#if wxUSE_TOOLBAR + if (GetWindow()->IsKindOf(CLASSINFO(wxToolBar))) + return wxACC_NOT_IMPLEMENTED; +#endif + + *state = 0; + return wxACC_OK; + + #if 0 + return wxACC_NOT_IMPLEMENTED; + #endif +} + +// Returns a localized string representing the value for the object +// or child. +wxAccStatus wxWindowAccessible::GetValue(int WXUNUSED(childId), wxString* WXUNUSED(strValue)) +{ + wxASSERT( GetWindow() != NULL ); + if (!GetWindow()) + return wxACC_FAIL; + + return wxACC_NOT_IMPLEMENTED; +} + +// Selects the object or child. +wxAccStatus wxWindowAccessible::Select(int WXUNUSED(childId), wxAccSelectionFlags WXUNUSED(selectFlags)) +{ + wxASSERT( GetWindow() != NULL ); + if (!GetWindow()) + return wxACC_FAIL; + + return wxACC_NOT_IMPLEMENTED; +} + +// Gets the window with the keyboard focus. +// If childId is 0 and child is NULL, no object in +// this subhierarchy has the focus. +// If this object has the focus, child should be 'this'. +wxAccStatus wxWindowAccessible::GetFocus(int* WXUNUSED(childId), wxAccessible** WXUNUSED(child)) +{ + wxASSERT( GetWindow() != NULL ); + if (!GetWindow()) + return wxACC_FAIL; + + return wxACC_NOT_IMPLEMENTED; +} + +#if wxUSE_VARIANT +// Gets a variant representing the selected children +// of this object. +// Acceptable values: +// - a null variant (IsNull() returns true) +// - a list variant (GetType() == wxT("list") +// - an integer representing the selected child element, +// or 0 if this object is selected (GetType() == wxT("long") +// - a "void*" pointer to a wxAccessible child object +wxAccStatus wxWindowAccessible::GetSelections(wxVariant* WXUNUSED(selections)) +{ + wxASSERT( GetWindow() != NULL ); + if (!GetWindow()) + return wxACC_FAIL; + + return wxACC_NOT_IMPLEMENTED; +} +#endif // wxUSE_VARIANT + +#endif // wxUSE_ACCESSIBILITY + +// ---------------------------------------------------------------------------- +// RTL support +// ---------------------------------------------------------------------------- + +wxCoord +wxWindowBase::AdjustForLayoutDirection(wxCoord x, + wxCoord width, + wxCoord widthTotal) const +{ + if ( GetLayoutDirection() == wxLayout_RightToLeft ) + { + x = widthTotal - x - width; + } + + return x; +} + diff --git a/Externals/wxWidgets/src/common/wxchar.cpp b/Externals/wxWidgets/src/common/wxchar.cpp index e89894106e..99a0977ac8 100644 --- a/Externals/wxWidgets/src/common/wxchar.cpp +++ b/Externals/wxWidgets/src/common/wxchar.cpp @@ -1,2287 +1,2287 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/wxchar.cpp -// Purpose: wxChar implementation -// Author: Ove Kaven -// Modified by: Ron Lee, Francesco Montorsi -// Created: 09/04/99 -// RCS-ID: $Id: wxchar.cpp 54071 2008-06-10 18:22:32Z VZ $ -// Copyright: (c) wxWidgets copyright -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// =========================================================================== -// headers, declarations, constants -// =========================================================================== - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#include "wx/wxchar.h" - -#define _ISOC9X_SOURCE 1 // to get vsscanf() -#define _BSD_SOURCE 1 // to still get strdup() - -#include -#include -#include - -#ifndef __WXWINCE__ - #include - #include -#else - #include "wx/msw/wince/time.h" -#endif - -#ifndef WX_PRECOMP - #include "wx/string.h" - #include "wx/hash.h" - #include "wx/utils.h" // for wxMin and wxMax - #include "wx/log.h" -#endif - -#if defined(__WIN32__) && defined(wxNEED_WX_CTYPE_H) - #include - #include - #include - #include -#endif - -#if defined(__MWERKS__) && __MSL__ >= 0x6000 -namespace std {} -using namespace std ; -#endif - -#if wxUSE_WCHAR_T -size_t WXDLLEXPORT wxMB2WC(wchar_t *buf, const char *psz, size_t n) -{ - // assume that we have mbsrtowcs() too if we have wcsrtombs() -#ifdef HAVE_WCSRTOMBS - mbstate_t mbstate; - memset(&mbstate, 0, sizeof(mbstate_t)); -#endif - - if (buf) { - if (!n || !*psz) { - if (n) *buf = wxT('\0'); - return 0; - } -#ifdef HAVE_WCSRTOMBS - return mbsrtowcs(buf, &psz, n, &mbstate); -#else - return wxMbstowcs(buf, psz, n); -#endif - } - - // note that we rely on common (and required by Unix98 but unfortunately not - // C99) extension which allows to call mbs(r)towcs() with NULL output pointer - // to just get the size of the needed buffer -- this is needed as otherwise - // we have no idea about how much space we need and if the CRT doesn't - // support it (the only currently known example being Metrowerks, see - // wx/wxchar.h) we don't use its mbstowcs() at all -#ifdef HAVE_WCSRTOMBS - return mbsrtowcs((wchar_t *) NULL, &psz, 0, &mbstate); -#else - return wxMbstowcs((wchar_t *) NULL, psz, 0); -#endif -} - -size_t WXDLLEXPORT wxWC2MB(char *buf, const wchar_t *pwz, size_t n) -{ -#ifdef HAVE_WCSRTOMBS - mbstate_t mbstate; - memset(&mbstate, 0, sizeof(mbstate_t)); -#endif - - if (buf) { - if (!n || !*pwz) { - // glibc2.1 chokes on null input - if (n) *buf = '\0'; - return 0; - } -#ifdef HAVE_WCSRTOMBS - return wcsrtombs(buf, &pwz, n, &mbstate); -#else - return wxWcstombs(buf, pwz, n); -#endif - } - -#ifdef HAVE_WCSRTOMBS - return wcsrtombs((char *) NULL, &pwz, 0, &mbstate); -#else - return wxWcstombs((char *) NULL, pwz, 0); -#endif -} -#endif // wxUSE_WCHAR_T - -bool WXDLLEXPORT wxOKlibc() -{ -#if wxUSE_WCHAR_T && defined(__UNIX__) && defined(__GLIBC__) && !defined(__WINE__) - // glibc 2.0 uses UTF-8 even when it shouldn't - wchar_t res = 0; - if ((MB_CUR_MAX == 2) && - (wxMB2WC(&res, "\xdd\xa5", 1) == 1) && - (res==0x765)) { - // this is UTF-8 allright, check whether that's what we want - char *cur_locale = setlocale(LC_CTYPE, NULL); - if ((strlen(cur_locale) < 4) || - (strcasecmp(cur_locale + strlen(cur_locale) - 4, "utf8")) || - (strcasecmp(cur_locale + strlen(cur_locale) - 5, "utf-8"))) { - // nope, don't use libc conversion - return false; - } - } -#endif - return true; -} - -// ============================================================================ -// printf() functions business -// ============================================================================ - -// special test mode: define all functions below even if we don't really need -// them to be able to test them -#ifdef wxTEST_PRINTF - #undef wxFprintf - #undef wxPrintf - #undef wxSprintf - #undef wxVfprintf - #undef wxVsprintf - #undef wxVprintf - #undef wxVsnprintf_ - #undef wxSnprintf_ - - #define wxNEED_WPRINTF - - int wxVfprintf( FILE *stream, const wxChar *format, va_list argptr ); -#endif - -// ---------------------------------------------------------------------------- -// implement [v]snprintf() if the system doesn't provide a safe one -// or if the system's one does not support positional parameters -// (very useful for i18n purposes) -// ---------------------------------------------------------------------------- - -#if !defined(wxVsnprintf_) - -#if !wxUSE_WXVSNPRINTF - #error wxUSE_WXVSNPRINTF must be 1 if our wxVsnprintf_ is used -#endif - -// wxUSE_STRUTILS says our wxVsnprintf_ implementation to use or not to -// use wxStrlen and wxStrncpy functions over one-char processing loops. -// -// Some benchmarking revealed that wxUSE_STRUTILS == 1 has the following -// effects: -// -> on Windows: -// when in ANSI mode, this setting does not change almost anything -// when in Unicode mode, it gives ~ 50% of slowdown ! -// -> on Linux: -// both in ANSI and Unicode mode it gives ~ 60% of speedup ! -// -#if defined(WIN32) && wxUSE_UNICODE -#define wxUSE_STRUTILS 0 -#else -#define wxUSE_STRUTILS 1 -#endif - -// some limits of our implementation -#define wxMAX_SVNPRINTF_ARGUMENTS 64 -#define wxMAX_SVNPRINTF_FLAGBUFFER_LEN 32 -#define wxMAX_SVNPRINTF_SCRATCHBUFFER_LEN 512 - -// prefer snprintf over sprintf -#if defined(__VISUALC__) || \ - (defined(__BORLANDC__) && __BORLANDC__ >= 0x540) - #define system_sprintf(buff, max, flags, data) \ - ::_snprintf(buff, max, flags, data) -#elif defined(HAVE_SNPRINTF) - #define system_sprintf(buff, max, flags, data) \ - ::snprintf(buff, max, flags, data) -#else // NB: at least sprintf() should always be available - // since 'max' is not used in this case, wxVsnprintf() should always - // ensure that 'buff' is big enough for all common needs - // (see wxMAX_SVNPRINTF_FLAGBUFFER_LEN and wxMAX_SVNPRINTF_SCRATCHBUFFER_LEN) - #define system_sprintf(buff, max, flags, data) \ - ::sprintf(buff, flags, data) - - #define SYSTEM_SPRINTF_IS_UNSAFE -#endif - -// the conversion specifiers accepted by wxVsnprintf_ -enum wxPrintfArgType { - wxPAT_INVALID = -1, - - wxPAT_INT, // %d, %i, %o, %u, %x, %X - wxPAT_LONGINT, // %ld, etc -#ifdef wxLongLong_t - wxPAT_LONGLONGINT, // %Ld, etc -#endif - wxPAT_SIZET, // %Zd, etc - - wxPAT_DOUBLE, // %e, %E, %f, %g, %G - wxPAT_LONGDOUBLE, // %le, etc - - wxPAT_POINTER, // %p - - wxPAT_CHAR, // %hc (in ANSI mode: %c, too) - wxPAT_WCHAR, // %lc (in Unicode mode: %c, too) - - wxPAT_PCHAR, // %s (related to a char *) - wxPAT_PWCHAR, // %s (related to a wchar_t *) - - wxPAT_NINT, // %n - wxPAT_NSHORTINT, // %hn - wxPAT_NLONGINT // %ln -}; - -// an argument passed to wxVsnprintf_ -typedef union { - int pad_int; // %d, %i, %o, %u, %x, %X - long int pad_longint; // %ld, etc -#ifdef wxLongLong_t - wxLongLong_t pad_longlongint; // %Ld, etc -#endif - size_t pad_sizet; // %Zd, etc - - double pad_double; // %e, %E, %f, %g, %G - long double pad_longdouble; // %le, etc - - void *pad_pointer; // %p - - char pad_char; // %hc (in ANSI mode: %c, too) - wchar_t pad_wchar; // %lc (in Unicode mode: %c, too) - - char *pad_pchar; // %s (related to a char *) - wchar_t *pad_pwchar; // %s (related to a wchar_t *) - - int *pad_nint; // %n - short int *pad_nshortint; // %hn - long int *pad_nlongint; // %ln -} wxPrintfArg; - - -// Contains parsed data relative to a conversion specifier given to -// wxVsnprintf_ and parsed from the format string -// NOTE: in C++ there is almost no difference between struct & classes thus -// there is no performance gain by using a struct here... -class wxPrintfConvSpec -{ -public: - - // the position of the argument relative to this conversion specifier - size_t m_pos; - - // the type of this conversion specifier - wxPrintfArgType m_type; - - // the minimum and maximum width - // when one of this var is set to -1 it means: use the following argument - // in the stack as minimum/maximum width for this conversion specifier - int m_nMinWidth, m_nMaxWidth; - - // does the argument need to the be aligned to left ? - bool m_bAlignLeft; - - // pointer to the '%' of this conversion specifier in the format string - // NOTE: this points somewhere in the string given to the Parse() function - - // it's task of the caller ensure that memory is still valid ! - const wxChar *m_pArgPos; - - // pointer to the last character of this conversion specifier in the - // format string - // NOTE: this points somewhere in the string given to the Parse() function - - // it's task of the caller ensure that memory is still valid ! - const wxChar *m_pArgEnd; - - // a little buffer where formatting flags like #+\.hlqLZ are stored by Parse() - // for use in Process() - // NB: even if this buffer is used only for numeric conversion specifiers and - // thus could be safely declared as a char[] buffer, we want it to be wxChar - // so that in Unicode builds we can avoid to convert its contents to Unicode - // chars when copying it in user's buffer. - char m_szFlags[wxMAX_SVNPRINTF_FLAGBUFFER_LEN]; - - -public: - - // we don't declare this as a constructor otherwise it would be called - // automatically and we don't want this: to be optimized, wxVsnprintf_ - // calls this function only on really-used instances of this class. - void Init(); - - // Parses the first conversion specifier in the given string, which must - // begin with a '%'. Returns false if the first '%' does not introduce a - // (valid) conversion specifier and thus should be ignored. - bool Parse(const wxChar *format); - - // Process this conversion specifier and puts the result in the given - // buffer. Returns the number of characters written in 'buf' or -1 if - // there's not enough space. - int Process(wxChar *buf, size_t lenMax, wxPrintfArg *p, size_t written); - - // Loads the argument of this conversion specifier from given va_list. - bool LoadArg(wxPrintfArg *p, va_list &argptr); - -private: - // An helper function of LoadArg() which is used to handle the '*' flag - void ReplaceAsteriskWith(int w); -}; - -void wxPrintfConvSpec::Init() -{ - m_nMinWidth = 0; - m_nMaxWidth = 0xFFFF; - m_pos = 0; - m_bAlignLeft = false; - m_pArgPos = m_pArgEnd = NULL; - m_type = wxPAT_INVALID; - - // this character will never be removed from m_szFlags array and - // is important when calling sprintf() in wxPrintfConvSpec::Process() ! - m_szFlags[0] = '%'; -} - -bool wxPrintfConvSpec::Parse(const wxChar *format) -{ - bool done = false; - - // temporary parse data - size_t flagofs = 1; - bool in_prec, // true if we found the dot in some previous iteration - prec_dot; // true if the dot has been already added to m_szFlags - int ilen = 0; - - m_bAlignLeft = in_prec = prec_dot = false; - m_pArgPos = m_pArgEnd = format; - do - { -#define CHECK_PREC \ - if (in_prec && !prec_dot) \ - { \ - m_szFlags[flagofs++] = '.'; \ - prec_dot = true; \ - } - - // what follows '%'? - const wxChar ch = *(++m_pArgEnd); - switch ( ch ) - { - case wxT('\0'): - return false; // not really an argument - - case wxT('%'): - return false; // not really an argument - - case wxT('#'): - case wxT('0'): - case wxT(' '): - case wxT('+'): - case wxT('\''): - CHECK_PREC - m_szFlags[flagofs++] = char(ch); - break; - - case wxT('-'): - CHECK_PREC - m_bAlignLeft = true; - m_szFlags[flagofs++] = char(ch); - break; - - case wxT('.'): - CHECK_PREC - in_prec = true; - prec_dot = false; - m_nMaxWidth = 0; - // dot will be auto-added to m_szFlags if non-negative - // number follows - break; - - case wxT('h'): - ilen = -1; - CHECK_PREC - m_szFlags[flagofs++] = char(ch); - break; - - case wxT('l'): - // NB: it's safe to use flagofs-1 as flagofs always start from 1 - if (m_szFlags[flagofs-1] == 'l') // 'll' modifier is the same as 'L' or 'q' - ilen = 2; - else - ilen = 1; - CHECK_PREC - m_szFlags[flagofs++] = char(ch); - break; - - case wxT('q'): - case wxT('L'): - ilen = 2; - CHECK_PREC - m_szFlags[flagofs++] = char(ch); - break; -#ifdef __WXMSW__ - // under Windows we support the special '%I64' notation as longlong - // integer conversion specifier for MSVC compatibility - // (it behaves exactly as '%lli' or '%Li' or '%qi') - case wxT('I'): - if (*(m_pArgEnd+1) != wxT('6') || - *(m_pArgEnd+2) != wxT('4')) - return false; // bad format - - m_pArgEnd++; - m_pArgEnd++; - - ilen = 2; - CHECK_PREC - m_szFlags[flagofs++] = char(ch); - m_szFlags[flagofs++] = '6'; - m_szFlags[flagofs++] = '4'; - break; -#endif // __WXMSW__ - - case wxT('Z'): - ilen = 3; - CHECK_PREC - m_szFlags[flagofs++] = char(ch); - break; - - case wxT('*'): - if (in_prec) - { - CHECK_PREC - - // tell Process() to use the next argument - // in the stack as maxwidth... - m_nMaxWidth = -1; - } - else - { - // tell Process() to use the next argument - // in the stack as minwidth... - m_nMinWidth = -1; - } - - // save the * in our formatting buffer... - // will be replaced later by Process() - m_szFlags[flagofs++] = char(ch); - break; - - case wxT('1'): case wxT('2'): case wxT('3'): - case wxT('4'): case wxT('5'): case wxT('6'): - case wxT('7'): case wxT('8'): case wxT('9'): - { - int len = 0; - CHECK_PREC - while ( (*m_pArgEnd >= wxT('0')) && - (*m_pArgEnd <= wxT('9')) ) - { - m_szFlags[flagofs++] = char(*m_pArgEnd); - len = len*10 + (*m_pArgEnd - wxT('0')); - m_pArgEnd++; - } - - if (in_prec) - m_nMaxWidth = len; - else - m_nMinWidth = len; - - m_pArgEnd--; // the main loop pre-increments n again - } - break; - - case wxT('$'): // a positional parameter (e.g. %2$s) ? - { - if (m_nMinWidth <= 0) - break; // ignore this formatting flag as no - // numbers are preceding it - - // remove from m_szFlags all digits previously added - do { - flagofs--; - } while (m_szFlags[flagofs] >= '1' && - m_szFlags[flagofs] <= '9'); - - // re-adjust the offset making it point to the - // next free char of m_szFlags - flagofs++; - - m_pos = m_nMinWidth; - m_nMinWidth = 0; - } - break; - - case wxT('d'): - case wxT('i'): - case wxT('o'): - case wxT('u'): - case wxT('x'): - case wxT('X'): - CHECK_PREC - m_szFlags[flagofs++] = char(ch); - m_szFlags[flagofs] = '\0'; - if (ilen == 0) - m_type = wxPAT_INT; - else if (ilen == -1) - // NB: 'short int' value passed through '...' - // is promoted to 'int', so we have to get - // an int from stack even if we need a short - m_type = wxPAT_INT; - else if (ilen == 1) - m_type = wxPAT_LONGINT; - else if (ilen == 2) -#ifdef wxLongLong_t - m_type = wxPAT_LONGLONGINT; -#else // !wxLongLong_t - m_type = wxPAT_LONGINT; -#endif // wxLongLong_t/!wxLongLong_t - else if (ilen == 3) - m_type = wxPAT_SIZET; - done = true; - break; - - case wxT('e'): - case wxT('E'): - case wxT('f'): - case wxT('g'): - case wxT('G'): - CHECK_PREC - m_szFlags[flagofs++] = char(ch); - m_szFlags[flagofs] = '\0'; - if (ilen == 2) - m_type = wxPAT_LONGDOUBLE; - else - m_type = wxPAT_DOUBLE; - done = true; - break; - - case wxT('p'): - m_type = wxPAT_POINTER; - m_szFlags[flagofs++] = char(ch); - m_szFlags[flagofs] = '\0'; - done = true; - break; - - case wxT('c'): - if (ilen == -1) - { - // in Unicode mode %hc == ANSI character - // and in ANSI mode, %hc == %c == ANSI... - m_type = wxPAT_CHAR; - } - else if (ilen == 1) - { - // in ANSI mode %lc == Unicode character - // and in Unicode mode, %lc == %c == Unicode... - m_type = wxPAT_WCHAR; - } - else - { -#if wxUSE_UNICODE - // in Unicode mode, %c == Unicode character - m_type = wxPAT_WCHAR; -#else - // in ANSI mode, %c == ANSI character - m_type = wxPAT_CHAR; -#endif - } - done = true; - break; - - case wxT('s'): - if (ilen == -1) - { - // Unicode mode wx extension: we'll let %hs mean non-Unicode - // strings (when in ANSI mode, %s == %hs == ANSI string) - m_type = wxPAT_PCHAR; - } - else if (ilen == 1) - { - // in Unicode mode, %ls == %s == Unicode string - // in ANSI mode, %ls == Unicode string - m_type = wxPAT_PWCHAR; - } - else - { -#if wxUSE_UNICODE - m_type = wxPAT_PWCHAR; -#else - m_type = wxPAT_PCHAR; -#endif - } - done = true; - break; - - case wxT('n'): - if (ilen == 0) - m_type = wxPAT_NINT; - else if (ilen == -1) - m_type = wxPAT_NSHORTINT; - else if (ilen >= 1) - m_type = wxPAT_NLONGINT; - done = true; - break; - - default: - // bad format, don't consider this an argument; - // leave it unchanged - return false; - } - - if (flagofs == wxMAX_SVNPRINTF_FLAGBUFFER_LEN) - { - wxLogDebug(wxT("Too many flags specified for a single conversion specifier!")); - return false; - } - } - while (!done); - - return true; // parsing was successful -} - - -void wxPrintfConvSpec::ReplaceAsteriskWith(int width) -{ - char temp[wxMAX_SVNPRINTF_FLAGBUFFER_LEN]; - - // find the first * in our flag buffer - char *pwidth = strchr(m_szFlags, '*'); - wxCHECK_RET(pwidth, _T("field width must be specified")); - - // save what follows the * (the +1 is to skip the asterisk itself!) - strcpy(temp, pwidth+1); - if (width < 0) - { - pwidth[0] = wxT('-'); - pwidth++; - } - - // replace * with the actual integer given as width -#ifndef SYSTEM_SPRINTF_IS_UNSAFE - int maxlen = (m_szFlags + wxMAX_SVNPRINTF_FLAGBUFFER_LEN - pwidth) / - sizeof(*m_szFlags); -#endif - int offset = system_sprintf(pwidth, maxlen, "%d", abs(width)); - - // restore after the expanded * what was following it - strcpy(pwidth+offset, temp); -} - -bool wxPrintfConvSpec::LoadArg(wxPrintfArg *p, va_list &argptr) -{ - // did the '*' width/precision specifier was used ? - if (m_nMaxWidth == -1) - { - // take the maxwidth specifier from the stack - m_nMaxWidth = va_arg(argptr, int); - if (m_nMaxWidth < 0) - m_nMaxWidth = 0; - else - ReplaceAsteriskWith(m_nMaxWidth); - } - - if (m_nMinWidth == -1) - { - // take the minwidth specifier from the stack - m_nMinWidth = va_arg(argptr, int); - - ReplaceAsteriskWith(m_nMinWidth); - if (m_nMinWidth < 0) - { - m_bAlignLeft = !m_bAlignLeft; - m_nMinWidth = -m_nMinWidth; - } - } - - switch (m_type) { - case wxPAT_INT: - p->pad_int = va_arg(argptr, int); - break; - case wxPAT_LONGINT: - p->pad_longint = va_arg(argptr, long int); - break; -#ifdef wxLongLong_t - case wxPAT_LONGLONGINT: - p->pad_longlongint = va_arg(argptr, wxLongLong_t); - break; -#endif // wxLongLong_t - case wxPAT_SIZET: - p->pad_sizet = va_arg(argptr, size_t); - break; - case wxPAT_DOUBLE: - p->pad_double = va_arg(argptr, double); - break; - case wxPAT_LONGDOUBLE: - p->pad_longdouble = va_arg(argptr, long double); - break; - case wxPAT_POINTER: - p->pad_pointer = va_arg(argptr, void *); - break; - - case wxPAT_CHAR: - p->pad_char = (char)va_arg(argptr, int); // char is promoted to int when passed through '...' - break; - case wxPAT_WCHAR: - p->pad_wchar = (wchar_t)va_arg(argptr, int); // char is promoted to int when passed through '...' - break; - - case wxPAT_PCHAR: - p->pad_pchar = va_arg(argptr, char *); - break; - case wxPAT_PWCHAR: - p->pad_pwchar = va_arg(argptr, wchar_t *); - break; - - case wxPAT_NINT: - p->pad_nint = va_arg(argptr, int *); - break; - case wxPAT_NSHORTINT: - p->pad_nshortint = va_arg(argptr, short int *); - break; - case wxPAT_NLONGINT: - p->pad_nlongint = va_arg(argptr, long int *); - break; - - case wxPAT_INVALID: - default: - return false; - } - - return true; // loading was successful -} - -int wxPrintfConvSpec::Process(wxChar *buf, size_t lenMax, wxPrintfArg *p, size_t written) -{ - // buffer to avoid dynamic memory allocation each time for small strings; - // note that this buffer is used only to hold results of number formatting, - // %s directly writes user's string in buf, without using szScratch - char szScratch[wxMAX_SVNPRINTF_SCRATCHBUFFER_LEN]; - size_t lenScratch = 0, lenCur = 0; - -#define APPEND_CH(ch) \ - { \ - if ( lenCur == lenMax ) \ - return -1; \ - \ - buf[lenCur++] = ch; \ - } - -#define APPEND_STR(s) \ - { \ - for ( const wxChar *p = s; *p; p++ ) \ - { \ - APPEND_CH(*p); \ - } \ - } - - switch ( m_type ) - { - case wxPAT_INT: - lenScratch = system_sprintf(szScratch, wxMAX_SVNPRINTF_SCRATCHBUFFER_LEN, m_szFlags, p->pad_int); - break; - - case wxPAT_LONGINT: - lenScratch = system_sprintf(szScratch, wxMAX_SVNPRINTF_SCRATCHBUFFER_LEN, m_szFlags, p->pad_longint); - break; - -#ifdef wxLongLong_t - case wxPAT_LONGLONGINT: - lenScratch = system_sprintf(szScratch, wxMAX_SVNPRINTF_SCRATCHBUFFER_LEN, m_szFlags, p->pad_longlongint); - break; -#endif // SIZEOF_LONG_LONG - - case wxPAT_SIZET: - lenScratch = system_sprintf(szScratch, wxMAX_SVNPRINTF_SCRATCHBUFFER_LEN, m_szFlags, p->pad_sizet); - break; - - case wxPAT_LONGDOUBLE: - lenScratch = system_sprintf(szScratch, wxMAX_SVNPRINTF_SCRATCHBUFFER_LEN, m_szFlags, p->pad_longdouble); - break; - - case wxPAT_DOUBLE: - lenScratch = system_sprintf(szScratch, wxMAX_SVNPRINTF_SCRATCHBUFFER_LEN, m_szFlags, p->pad_double); - break; - - case wxPAT_POINTER: - lenScratch = system_sprintf(szScratch, wxMAX_SVNPRINTF_SCRATCHBUFFER_LEN, m_szFlags, p->pad_pointer); - break; - - case wxPAT_CHAR: - case wxPAT_WCHAR: - { - wxChar val = -#if wxUSE_UNICODE - p->pad_wchar; - - if (m_type == wxPAT_CHAR) - { - // user passed a character explicitely indicated as ANSI... - const char buf[2] = { p->pad_char, 0 }; - val = wxString(buf, wxConvLibc)[0u]; - - //wprintf(L"converting ANSI=>Unicode"); // for debug - } -#else - p->pad_char; - -#if wxUSE_WCHAR_T - if (m_type == wxPAT_WCHAR) - { - // user passed a character explicitely indicated as Unicode... - const wchar_t buf[2] = { p->pad_wchar, 0 }; - val = wxString(buf, wxConvLibc)[0u]; - - //printf("converting Unicode=>ANSI"); // for debug - } -#endif -#endif - - size_t i; - - if (!m_bAlignLeft) - for (i = 1; i < (size_t)m_nMinWidth; i++) - APPEND_CH(_T(' ')); - - APPEND_CH(val); - - if (m_bAlignLeft) - for (i = 1; i < (size_t)m_nMinWidth; i++) - APPEND_CH(_T(' ')); - } - break; - - case wxPAT_PCHAR: - case wxPAT_PWCHAR: - { - wxString s; - const wxChar *val = -#if wxUSE_UNICODE - p->pad_pwchar; - - if (m_type == wxPAT_PCHAR) - { - // user passed a string explicitely indicated as ANSI... - val = s = wxString(p->pad_pchar, wxConvLibc); - - //wprintf(L"converting ANSI=>Unicode"); // for debug - } -#else - p->pad_pchar; - -#if wxUSE_WCHAR_T - if (m_type == wxPAT_PWCHAR) - { - // user passed a string explicitely indicated as Unicode... - val = s = wxString(p->pad_pwchar, wxConvLibc); - - //printf("converting Unicode=>ANSI"); // for debug - } -#endif -#endif - int len; - - if (val) - { -#if wxUSE_STRUTILS - // at this point we are sure that m_nMaxWidth is positive or null - // (see top of wxPrintfConvSpec::LoadArg) - len = wxMin((unsigned int)m_nMaxWidth, wxStrlen(val)); -#else - for ( len = 0; val[len] && (len < m_nMaxWidth); len++ ) - ; -#endif - } - else if (m_nMaxWidth >= 6) - { - val = wxT("(null)"); - len = 6; - } - else - { - val = wxEmptyString; - len = 0; - } - - int i; - - if (!m_bAlignLeft) - { - for (i = len; i < m_nMinWidth; i++) - APPEND_CH(_T(' ')); - } - -#if wxUSE_STRUTILS - len = wxMin((unsigned int)len, lenMax-lenCur); - wxStrncpy(buf+lenCur, val, len); - lenCur += len; -#else - for (i = 0; i < len; i++) - APPEND_CH(val[i]); -#endif - - if (m_bAlignLeft) - { - for (i = len; i < m_nMinWidth; i++) - APPEND_CH(_T(' ')); - } - } - break; - - case wxPAT_NINT: - *p->pad_nint = written; - break; - - case wxPAT_NSHORTINT: - *p->pad_nshortint = (short int)written; - break; - - case wxPAT_NLONGINT: - *p->pad_nlongint = written; - break; - - case wxPAT_INVALID: - default: - return -1; - } - - // if we used system's sprintf() then we now need to append the s_szScratch - // buffer to the given one... - switch (m_type) - { - case wxPAT_INT: - case wxPAT_LONGINT: -#ifdef wxLongLong_t - case wxPAT_LONGLONGINT: -#endif - case wxPAT_SIZET: - case wxPAT_LONGDOUBLE: - case wxPAT_DOUBLE: - case wxPAT_POINTER: - wxASSERT(lenScratch < wxMAX_SVNPRINTF_SCRATCHBUFFER_LEN); -#if !wxUSE_UNICODE - { - if (lenMax < lenScratch) - { - // fill output buffer and then return -1 - wxStrncpy(buf, szScratch, lenMax); - return -1; - } - wxStrncpy(buf, szScratch, lenScratch); - lenCur += lenScratch; - } -#else - { - // Copy the char scratch to the wide output. This requires - // conversion, but we can optimise by making use of the fact - // that we are formatting numbers, this should mean only 7-bit - // ascii characters are involved. - wxChar *bufptr = buf; - const wxChar *bufend = buf + lenMax; - const char *scratchptr = szScratch; - - // Simply copy each char to a wxChar, stopping on the first - // null or non-ascii byte. Checking '(signed char)*scratchptr - // > 0' is an extra optimisation over '*scratchptr != 0 && - // isascii(*scratchptr)', though it assumes signed char is - // 8-bit 2 complement. - while ((signed char)*scratchptr > 0 && bufptr != bufend) - *bufptr++ = *scratchptr++; - - if (bufptr == bufend) - return -1; - - lenCur += bufptr - buf; - - // check if the loop stopped on a non-ascii char, if yes then - // fall back to wxMB2WX - if (*scratchptr) - { - size_t len = wxMB2WX(bufptr, scratchptr, bufend - bufptr); - - if (len && len != (size_t)(-1)) - if (bufptr[len - 1]) - return -1; - else - lenCur += len; - } - } -#endif - break; - - default: - break; // all other cases were completed previously - } - - return lenCur; -} - -// Copy chars from source to dest converting '%%' to '%'. Takes at most maxIn -// chars from source and write at most outMax chars to dest, returns the -// number of chars actually written. Does not treat null specially. -// -static int wxCopyStrWithPercents( - size_t maxOut, - wxChar *dest, - size_t maxIn, - const wxChar *source) -{ - size_t written = 0; - - if (maxIn == 0) - return 0; - - size_t i; - for ( i = 0; i < maxIn-1 && written < maxOut; source++, i++) - { - dest[written++] = *source; - if (*(source+1) == wxT('%')) - { - // skip this additional '%' character - source++; - i++; - } - } - - if (i < maxIn && written < maxOut) - // copy last character inconditionally - dest[written++] = *source; - - return written; -} - -int WXDLLEXPORT wxVsnprintf_(wxChar *buf, size_t lenMax, - const wxChar *format, va_list argptr) -{ - // useful for debugging, to understand if we are really using this function - // rather than the system implementation -#if 0 - wprintf(L"Using wxVsnprintf_\n"); -#endif - - // required memory: - wxPrintfConvSpec arg[wxMAX_SVNPRINTF_ARGUMENTS]; - wxPrintfArg argdata[wxMAX_SVNPRINTF_ARGUMENTS]; - wxPrintfConvSpec *pspec[wxMAX_SVNPRINTF_ARGUMENTS] = { NULL }; - - size_t i; - - // number of characters in the buffer so far, must be less than lenMax - size_t lenCur = 0; - - size_t nargs = 0; - const wxChar *toparse = format; - - // parse the format string - bool posarg_present = false, nonposarg_present = false; - for (; *toparse != wxT('\0'); toparse++) - { - if (*toparse == wxT('%') ) - { - arg[nargs].Init(); - - // let's see if this is a (valid) conversion specifier... - if (arg[nargs].Parse(toparse)) - { - // ...yes it is - wxPrintfConvSpec *current = &arg[nargs]; - - // make toparse point to the end of this specifier - toparse = current->m_pArgEnd; - - if (current->m_pos > 0) - { - // the positionals start from number 1... adjust the index - current->m_pos--; - posarg_present = true; - } - else - { - // not a positional argument... - current->m_pos = nargs; - nonposarg_present = true; - } - - // this conversion specifier is tied to the pos-th argument... - pspec[current->m_pos] = current; - nargs++; - - if (nargs == wxMAX_SVNPRINTF_ARGUMENTS) - { - wxLogDebug(wxT("A single call to wxVsnprintf() has more than %d arguments; ") - wxT("ignoring all remaining arguments."), wxMAX_SVNPRINTF_ARGUMENTS); - break; // cannot handle any additional conv spec - } - } - else - { - // it's safe to look in the next character of toparse as at worst - // we'll hit its \0 - if (*(toparse+1) == wxT('%')) - toparse++; // the Parse() returned false because we've found a %% - } - } - } - - if (posarg_present && nonposarg_present) - { - buf[0] = 0; - return -1; // format strings with both positional and - } // non-positional conversion specifier are unsupported !! - - // on platforms where va_list is an array type, it is necessary to make a - // copy to be able to pass it to LoadArg as a reference. - bool ok = true; - va_list ap; - wxVaCopy(ap, argptr); - - // now load arguments from stack - for (i=0; i < nargs && ok; i++) - { - // !pspec[i] means that the user forgot a positional parameter (e.g. %$1s %$3s); - // LoadArg == false means that wxPrintfConvSpec::Parse failed to set the - // conversion specifier 'type' to a valid value... - ok = pspec[i] && pspec[i]->LoadArg(&argdata[i], ap); - } - - va_end(ap); - - // something failed while loading arguments from the variable list... - // (e.g. the user repeated twice the same positional argument) - if (!ok) - { - buf[0] = 0; - return -1; - } - - // finally, process each conversion specifier with its own argument - toparse = format; - for (i=0; i < nargs; i++) - { - // copy in the output buffer the portion of the format string between - // last specifier and the current one - size_t tocopy = ( arg[i].m_pArgPos - toparse ); - - lenCur += wxCopyStrWithPercents(lenMax - lenCur, buf + lenCur, - tocopy, toparse); - if (lenCur == lenMax) - { - buf[lenMax - 1] = 0; - return lenMax+1; // not enough space in the output buffer ! - } - - // process this specifier directly in the output buffer - int n = arg[i].Process(buf+lenCur, lenMax - lenCur, &argdata[arg[i].m_pos], lenCur); - if (n == -1) - { - buf[lenMax-1] = wxT('\0'); // be sure to always NUL-terminate the string - return lenMax+1; // not enough space in the output buffer ! - } - lenCur += n; - - // the +1 is because wxPrintfConvSpec::m_pArgEnd points to the last character - // of the format specifier, but we are not interested to it... - toparse = arg[i].m_pArgEnd + 1; - } - - // copy portion of the format string after last specifier - // NOTE: toparse is pointing to the character just after the last processed - // conversion specifier - // NOTE2: the +1 is because we want to copy also the '\0' - size_t tocopy = wxStrlen(format) + 1 - ( toparse - format ) ; - - lenCur += wxCopyStrWithPercents(lenMax - lenCur, buf + lenCur, - tocopy, toparse) - 1; - if (buf[lenCur]) - { - buf[lenCur] = 0; - return lenMax+1; // not enough space in the output buffer ! - } - - // Don't do: - // wxASSERT(lenCur == wxStrlen(buf)); - // in fact if we embedded NULLs in the output buffer (using %c with a '\0') - // such check would fail - - return lenCur; -} - -#undef APPEND_CH -#undef APPEND_STR -#undef CHECK_PREC - -#else // wxVsnprintf_ is defined - -#if wxUSE_WXVSNPRINTF - #error wxUSE_WXVSNPRINTF must be 0 if our wxVsnprintf_ is not used -#endif - -#endif // !wxVsnprintf_ - -#if !defined(wxSnprintf_) -int WXDLLEXPORT wxSnprintf_(wxChar *buf, size_t len, const wxChar *format, ...) -{ - va_list argptr; - va_start(argptr, format); - - int iLen = wxVsnprintf_(buf, len, format, argptr); - - va_end(argptr); - - return iLen; -} -#endif // wxSnprintf_ - -#if defined(__DMC__) - /* Digital Mars adds count to _stprintf (C99) so convert */ - #if wxUSE_UNICODE - int wxSprintf (wchar_t * __RESTRICT s, const wchar_t * __RESTRICT format, ... ) - { - va_list arglist; - - va_start( arglist, format ); - int iLen = swprintf ( s, -1, format, arglist ); - va_end( arglist ); - return iLen ; - } - - #endif // wxUSE_UNICODE - -#endif //__DMC__ - -#if defined(__MINGW32__) && ( defined(_STLPORT_VERSION) && _STLPORT_VERSION >= 0x510 ) - /* MinGW with STLPort 5.1 has clashing defines for _stprintf so use swprintf */ - /* STLPort 5.1 defines standard (C99) vswprintf() and swprintf() that takes count. */ - int wxSprintf (wchar_t * s, const wchar_t * format, ... ) - { - va_list arglist; - - va_start( arglist, format ); - int iLen = swprintf ( s, -1, format, arglist ); - va_end( arglist ); - return iLen ; - } -#endif // MINGW32 _STLPORT_VERSION >= 0x510 - -// ---------------------------------------------------------------------------- -// implement the standard IO functions for wide char if libc doesn't have them -// ---------------------------------------------------------------------------- - -#ifdef wxNEED_FPUTS -int wxFputs(const wchar_t *ws, FILE *stream) -{ - wxCharBuffer buf(wxConvLibc.cWC2MB(ws)); - if ( !buf ) - return -1; - - // counting the number of wide characters written isn't worth the trouble, - // simply distinguish between ok and error - return fputs(buf, stream) == -1 ? -1 : 0; -} -#endif // wxNEED_FPUTS - -#ifdef wxNEED_PUTS -int wxPuts(const wxChar *ws) -{ - int rc = wxFputs(ws, stdout); - if ( rc != -1 ) - { - if ( wxFputs(L"\n", stdout) == -1 ) - return -1; - - rc++; - } - - return rc; -} -#endif // wxNEED_PUTS - -#ifdef wxNEED_PUTC -int /* not wint_t */ wxPutc(wchar_t wc, FILE *stream) -{ - wchar_t ws[2] = { wc, L'\0' }; - - return wxFputs(ws, stream); -} -#endif // wxNEED_PUTC - -// NB: we only implement va_list functions here, the ones taking ... are -// defined below for wxNEED_PRINTF_CONVERSION case anyhow and we reuse -// the definitions there to avoid duplicating them here -#ifdef wxNEED_WPRINTF - -// TODO: implement the scanf() functions -int vwscanf(const wxChar *format, va_list argptr) -{ - wxFAIL_MSG( _T("TODO") ); - - return -1; -} - -int vswscanf(const wxChar *ws, const wxChar *format, va_list argptr) -{ - // The best we can do without proper Unicode support in glibc is to - // convert the strings into MB representation and run ANSI version - // of the function. This doesn't work with %c and %s because of difference - // in size of char and wchar_t, though. - - wxCHECK_MSG( wxStrstr(format, _T("%s")) == NULL, -1, - _T("incomplete vswscanf implementation doesn't allow %s") ); - wxCHECK_MSG( wxStrstr(format, _T("%c")) == NULL, -1, - _T("incomplete vswscanf implementation doesn't allow %c") ); - - va_list argcopy; - wxVaCopy(argcopy, argptr); - return vsscanf(wxConvLibc.cWX2MB(ws), wxConvLibc.cWX2MB(format), argcopy); -} - -int vfwscanf(FILE *stream, const wxChar *format, va_list argptr) -{ - wxFAIL_MSG( _T("TODO") ); - - return -1; -} - -#define vswprintf wxVsnprintf_ - -int vfwprintf(FILE *stream, const wxChar *format, va_list argptr) -{ - wxString s; - int rc = s.PrintfV(format, argptr); - - if ( rc != -1 ) - { - // we can't do much better without Unicode support in libc... - if ( fprintf(stream, "%s", (const char*)s.mb_str() ) == -1 ) - return -1; - } - - return rc; -} - -int vwprintf(const wxChar *format, va_list argptr) -{ - return wxVfprintf(stdout, format, argptr); -} - -#endif // wxNEED_WPRINTF - -#ifdef wxNEED_PRINTF_CONVERSION - -// ---------------------------------------------------------------------------- -// wxFormatConverter: class doing the "%s" -> "%ls" conversion -// ---------------------------------------------------------------------------- - -/* - Here are the gory details. We want to follow the Windows/MS conventions, - that is to have - - In ANSI mode: - - format specifier results in - ----------------------------------- - %c, %hc, %hC char - %lc, %C, %lC wchar_t - - In Unicode mode: - - format specifier results in - ----------------------------------- - %hc, %C, %hC char - %c, %lc, %lC wchar_t - - - while on POSIX systems we have %C identical to %lc and %c always means char - (in any mode) while %lc always means wchar_t, - - So to use native functions in order to get our semantics we must do the - following translations in Unicode mode (nothing to do in ANSI mode): - - wxWidgets specifier POSIX specifier - ---------------------------------------- - - %hc, %C, %hC %c - %c %lc - - - And, of course, the same should be done for %s as well. -*/ - -class wxFormatConverter -{ -public: - wxFormatConverter(const wxChar *format); - - // notice that we only translated the string if m_fmtOrig == NULL (as set - // by CopyAllBefore()), otherwise we should simply use the original format - operator const wxChar *() const - { return m_fmtOrig ? m_fmtOrig : m_fmt.c_str(); } - -private: - // copy another character to the translated format: this function does the - // copy if we are translating but doesn't do anything at all if we don't, - // so we don't create the translated format string at all unless we really - // need to (i.e. InsertFmtChar() is called) - wxChar CopyFmtChar(wxChar ch) - { - if ( !m_fmtOrig ) - { - // we're translating, do copy - m_fmt += ch; - } - else - { - // simply increase the count which should be copied by - // CopyAllBefore() later if needed - m_nCopied++; - } - - return ch; - } - - // insert an extra character - void InsertFmtChar(wxChar ch) - { - if ( m_fmtOrig ) - { - // so far we haven't translated anything yet - CopyAllBefore(); - } - - m_fmt += ch; - } - - void CopyAllBefore() - { - wxASSERT_MSG( m_fmtOrig && m_fmt.empty(), _T("logic error") ); - - m_fmt = wxString(m_fmtOrig, m_nCopied); - - // we won't need it any longer - m_fmtOrig = NULL; - } - - static bool IsFlagChar(wxChar ch) - { - return ch == _T('-') || ch == _T('+') || - ch == _T('0') || ch == _T(' ') || ch == _T('#'); - } - - void SkipDigits(const wxChar **ptpc) - { - while ( **ptpc >= _T('0') && **ptpc <= _T('9') ) - CopyFmtChar(*(*ptpc)++); - } - - // the translated format - wxString m_fmt; - - // the original format - const wxChar *m_fmtOrig; - - // the number of characters already copied - size_t m_nCopied; -}; - -wxFormatConverter::wxFormatConverter(const wxChar *format) -{ - m_fmtOrig = format; - m_nCopied = 0; - - while ( *format ) - { - if ( CopyFmtChar(*format++) == _T('%') ) - { - // skip any flags - while ( IsFlagChar(*format) ) - CopyFmtChar(*format++); - - // and possible width - if ( *format == _T('*') ) - CopyFmtChar(*format++); - else - SkipDigits(&format); - - // precision? - if ( *format == _T('.') ) - { - CopyFmtChar(*format++); - if ( *format == _T('*') ) - CopyFmtChar(*format++); - else - SkipDigits(&format); - } - - // next we can have a size modifier - enum - { - Default, - Short, - Long - } size; - - switch ( *format ) - { - case _T('h'): - size = Short; - format++; - break; - - case _T('l'): - // "ll" has a different meaning! - if ( format[1] != _T('l') ) - { - size = Long; - format++; - break; - } - //else: fall through - - default: - size = Default; - } - - // and finally we should have the type - switch ( *format ) - { - case _T('C'): - case _T('S'): - // %C and %hC -> %c and %lC -> %lc - if ( size == Long ) - CopyFmtChar(_T('l')); - - InsertFmtChar(*format++ == _T('C') ? _T('c') : _T('s')); - break; - - case _T('c'): - case _T('s'): - // %c -> %lc but %hc stays %hc and %lc is still %lc - if ( size == Default) - InsertFmtChar(_T('l')); - // fall through - - default: - // nothing special to do - if ( size != Default ) - CopyFmtChar(*(format - 1)); - CopyFmtChar(*format++); - } - } - } -} - -#else // !wxNEED_PRINTF_CONVERSION - // no conversion necessary - #define wxFormatConverter(x) (x) -#endif // wxNEED_PRINTF_CONVERSION/!wxNEED_PRINTF_CONVERSION - -#ifdef __WXDEBUG__ -// For testing the format converter -wxString wxConvertFormat(const wxChar *format) -{ - return wxString(wxFormatConverter(format)); -} -#endif - -// ---------------------------------------------------------------------------- -// wxPrintf(), wxScanf() and relatives -// ---------------------------------------------------------------------------- - -#if defined(wxNEED_PRINTF_CONVERSION) || defined(wxNEED_WPRINTF) - -int wxScanf( const wxChar *format, ... ) -{ - va_list argptr; - va_start(argptr, format); - - int ret = vwscanf(wxFormatConverter(format), argptr ); - - va_end(argptr); - - return ret; -} - -int wxSscanf( const wxChar *str, const wxChar *format, ... ) -{ - va_list argptr; - va_start(argptr, format); - - int ret = vswscanf( str, wxFormatConverter(format), argptr ); - - va_end(argptr); - - return ret; -} - -int wxFscanf( FILE *stream, const wxChar *format, ... ) -{ - va_list argptr; - va_start(argptr, format); - int ret = vfwscanf(stream, wxFormatConverter(format), argptr); - - va_end(argptr); - - return ret; -} - -int wxPrintf( const wxChar *format, ... ) -{ - va_list argptr; - va_start(argptr, format); - - int ret = vwprintf( wxFormatConverter(format), argptr ); - - va_end(argptr); - - return ret; -} - -#ifndef wxSnprintf -int wxSnprintf( wxChar *str, size_t size, const wxChar *format, ... ) -{ - va_list argptr; - va_start(argptr, format); - - int ret = vswprintf( str, size, wxFormatConverter(format), argptr ); - - // VsnprintfTestCase reveals that glibc's implementation of vswprintf - // doesn't nul terminate on truncation. - str[size - 1] = 0; - - va_end(argptr); - - return ret; -} -#endif // wxSnprintf - -int wxSprintf( wxChar *str, const wxChar *format, ... ) -{ - va_list argptr; - va_start(argptr, format); - - // note that wxString::FormatV() uses wxVsnprintf(), not wxSprintf(), so - // it's safe to implement this one in terms of it - wxString s(wxString::FormatV(format, argptr)); - wxStrcpy(str, s); - - va_end(argptr); - - return s.length(); -} - -int wxFprintf( FILE *stream, const wxChar *format, ... ) -{ - va_list argptr; - va_start( argptr, format ); - - int ret = vfwprintf( stream, wxFormatConverter(format), argptr ); - - va_end(argptr); - - return ret; -} - -int wxVsscanf( const wxChar *str, const wxChar *format, va_list argptr ) -{ - return vswscanf( str, wxFormatConverter(format), argptr ); -} - -int wxVfprintf( FILE *stream, const wxChar *format, va_list argptr ) -{ - return vfwprintf( stream, wxFormatConverter(format), argptr ); -} - -int wxVprintf( const wxChar *format, va_list argptr ) -{ - return vwprintf( wxFormatConverter(format), argptr ); -} - -#ifndef wxVsnprintf -int wxVsnprintf( wxChar *str, size_t size, const wxChar *format, va_list argptr ) -{ - return vswprintf( str, size, wxFormatConverter(format), argptr ); -} -#endif // wxVsnprintf - -int wxVsprintf( wxChar *str, const wxChar *format, va_list argptr ) -{ - // same as for wxSprintf() - return vswprintf(str, INT_MAX / 4, wxFormatConverter(format), argptr); -} - -#endif // wxNEED_PRINTF_CONVERSION - -#if wxUSE_WCHAR_T - -// ---------------------------------------------------------------------------- -// ctype.h stuff (currently unused) -// ---------------------------------------------------------------------------- - -#if defined(__WIN32__) && defined(wxNEED_WX_CTYPE_H) -inline WORD wxMSW_ctype(wxChar ch) -{ - WORD ret; - GetStringTypeEx(LOCALE_USER_DEFAULT, CT_CTYPE1, &ch, 1, &ret); - return ret; -} - -WXDLLEXPORT int wxIsalnum(wxChar ch) { return IsCharAlphaNumeric(ch); } -WXDLLEXPORT int wxIsalpha(wxChar ch) { return IsCharAlpha(ch); } -WXDLLEXPORT int wxIscntrl(wxChar ch) { return wxMSW_ctype(ch) & C1_CNTRL; } -WXDLLEXPORT int wxIsdigit(wxChar ch) { return wxMSW_ctype(ch) & C1_DIGIT; } -WXDLLEXPORT int wxIsgraph(wxChar ch) { return wxMSW_ctype(ch) & (C1_DIGIT|C1_PUNCT|C1_ALPHA); } -WXDLLEXPORT int wxIslower(wxChar ch) { return IsCharLower(ch); } -WXDLLEXPORT int wxIsprint(wxChar ch) { return wxMSW_ctype(ch) & (C1_DIGIT|C1_SPACE|C1_PUNCT|C1_ALPHA); } -WXDLLEXPORT int wxIspunct(wxChar ch) { return wxMSW_ctype(ch) & C1_PUNCT; } -WXDLLEXPORT int wxIsspace(wxChar ch) { return wxMSW_ctype(ch) & C1_SPACE; } -WXDLLEXPORT int wxIsupper(wxChar ch) { return IsCharUpper(ch); } -WXDLLEXPORT int wxIsxdigit(wxChar ch) { return wxMSW_ctype(ch) & C1_XDIGIT; } -WXDLLEXPORT int wxTolower(wxChar ch) { return (wxChar)CharLower((LPTSTR)(ch)); } -WXDLLEXPORT int wxToupper(wxChar ch) { return (wxChar)CharUpper((LPTSTR)(ch)); } -#endif - -#ifdef wxNEED_WX_MBSTOWCS - -WXDLLEXPORT size_t wxMbstowcs (wchar_t * out, const char * in, size_t outlen) -{ - if (!out) - { - size_t outsize = 0; - while(*in++) - outsize++; - return outsize; - } - - const char* origin = in; - - while (outlen-- && *in) - { - *out++ = (wchar_t) *in++; - } - - *out = '\0'; - - return in - origin; -} - -WXDLLEXPORT size_t wxWcstombs (char * out, const wchar_t * in, size_t outlen) -{ - if (!out) - { - size_t outsize = 0; - while(*in++) - outsize++; - return outsize; - } - - const wchar_t* origin = in; - - while (outlen-- && *in) - { - *out++ = (char) *in++; - } - - *out = '\0'; - - return in - origin; -} - -#endif // wxNEED_WX_MBSTOWCS - -#if defined(wxNEED_WX_CTYPE_H) - -#include - -#define cfalnumset CFCharacterSetGetPredefined(kCFCharacterSetAlphaNumeric) -#define cfalphaset CFCharacterSetGetPredefined(kCFCharacterSetLetter) -#define cfcntrlset CFCharacterSetGetPredefined(kCFCharacterSetControl) -#define cfdigitset CFCharacterSetGetPredefined(kCFCharacterSetDecimalDigit) -//CFCharacterSetRef cfgraphset = kCFCharacterSetControl && !' ' -#define cflowerset CFCharacterSetGetPredefined(kCFCharacterSetLowercaseLetter) -//CFCharacterSetRef cfprintset = !kCFCharacterSetControl -#define cfpunctset CFCharacterSetGetPredefined(kCFCharacterSetPunctuation) -#define cfspaceset CFCharacterSetGetPredefined(kCFCharacterSetWhitespaceAndNewline) -#define cfupperset CFCharacterSetGetPredefined(kCFCharacterSetUppercaseLetter) - -WXDLLEXPORT int wxIsalnum(wxChar ch) { return CFCharacterSetIsCharacterMember(cfalnumset, ch); } -WXDLLEXPORT int wxIsalpha(wxChar ch) { return CFCharacterSetIsCharacterMember(cfalphaset, ch); } -WXDLLEXPORT int wxIscntrl(wxChar ch) { return CFCharacterSetIsCharacterMember(cfcntrlset, ch); } -WXDLLEXPORT int wxIsdigit(wxChar ch) { return CFCharacterSetIsCharacterMember(cfdigitset, ch); } -WXDLLEXPORT int wxIsgraph(wxChar ch) { return !CFCharacterSetIsCharacterMember(cfcntrlset, ch) && ch != ' '; } -WXDLLEXPORT int wxIslower(wxChar ch) { return CFCharacterSetIsCharacterMember(cflowerset, ch); } -WXDLLEXPORT int wxIsprint(wxChar ch) { return !CFCharacterSetIsCharacterMember(cfcntrlset, ch); } -WXDLLEXPORT int wxIspunct(wxChar ch) { return CFCharacterSetIsCharacterMember(cfpunctset, ch); } -WXDLLEXPORT int wxIsspace(wxChar ch) { return CFCharacterSetIsCharacterMember(cfspaceset, ch); } -WXDLLEXPORT int wxIsupper(wxChar ch) { return CFCharacterSetIsCharacterMember(cfupperset, ch); } -WXDLLEXPORT int wxIsxdigit(wxChar ch) { return wxIsdigit(ch) || (ch>='a' && ch<='f') || (ch>='A' && ch<='F'); } -WXDLLEXPORT int wxTolower(wxChar ch) { return (wxChar)tolower((char)(ch)); } -WXDLLEXPORT int wxToupper(wxChar ch) { return (wxChar)toupper((char)(ch)); } - -#endif // wxNEED_WX_CTYPE_H - -#ifndef wxStrdupA - -WXDLLEXPORT char *wxStrdupA(const char *s) -{ - return strcpy((char *)malloc(strlen(s) + 1), s); -} - -#endif // wxStrdupA - -#ifndef wxStrdupW - -WXDLLEXPORT wchar_t * wxStrdupW(const wchar_t *pwz) -{ - size_t size = (wxWcslen(pwz) + 1) * sizeof(wchar_t); - wchar_t *ret = (wchar_t *) malloc(size); - memcpy(ret, pwz, size); - return ret; -} - -#endif // wxStrdupW - -#ifndef wxStricmp -int WXDLLEXPORT wxStricmp(const wxChar *psz1, const wxChar *psz2) -{ - register wxChar c1, c2; - do { - c1 = wxTolower(*psz1++); - c2 = wxTolower(*psz2++); - } while ( c1 && (c1 == c2) ); - return c1 - c2; -} -#endif - -#ifndef wxStricmp -int WXDLLEXPORT wxStrnicmp(const wxChar *s1, const wxChar *s2, size_t n) -{ - // initialize the variables just to suppress stupid gcc warning - register wxChar c1 = 0, c2 = 0; - while (n && ((c1 = wxTolower(*s1)) == (c2 = wxTolower(*s2)) ) && c1) n--, s1++, s2++; - if (n) { - if (c1 < c2) return -1; - if (c1 > c2) return 1; - } - return 0; -} -#endif - -#ifndef wxSetlocale -WXDLLEXPORT wxWCharBuffer wxSetlocale(int category, const wxChar *locale) -{ - char *localeOld = setlocale(category, wxConvLibc.cWX2MB(locale)); - - return wxWCharBuffer(wxConvLibc.cMB2WC(localeOld)); -} -#endif - -#if wxUSE_WCHAR_T && !defined(HAVE_WCSLEN) -WXDLLEXPORT size_t wxWcslen(const wchar_t *s) -{ - size_t n = 0; - while ( *s++ ) - n++; - - return n; -} -#endif - -// ---------------------------------------------------------------------------- -// string.h functions -// ---------------------------------------------------------------------------- - -#ifdef wxNEED_WX_STRING_H - -// RN: These need to be c externed for the regex lib -#ifdef __cplusplus -extern "C" { -#endif - -WXDLLEXPORT wxChar * wxStrcat(wxChar *dest, const wxChar *src) -{ - wxChar *ret = dest; - while (*dest) dest++; - while ((*dest++ = *src++)); - return ret; -} - -WXDLLEXPORT const wxChar * wxStrchr(const wxChar *s, wxChar c) -{ - // be careful here as the terminating NUL makes part of the string - while ( *s != c ) - { - if ( !*s++ ) - return NULL; - } - - return s; -} - -WXDLLEXPORT int wxStrcmp(const wxChar *s1, const wxChar *s2) -{ - while ((*s1 == *s2) && *s1) s1++, s2++; - if ((wxUChar)*s1 < (wxUChar)*s2) return -1; - if ((wxUChar)*s1 > (wxUChar)*s2) return 1; - return 0; -} - -WXDLLEXPORT wxChar * wxStrcpy(wxChar *dest, const wxChar *src) -{ - wxChar *ret = dest; - while ((*dest++ = *src++)); - return ret; -} - -WXDLLEXPORT size_t wxStrlen_(const wxChar *s) -{ - size_t n = 0; - while ( *s++ ) - n++; - - return n; -} - - -WXDLLEXPORT wxChar * wxStrncat(wxChar *dest, const wxChar *src, size_t n) -{ - wxChar *ret = dest; - while (*dest) dest++; - while (n && (*dest++ = *src++)) n--; - return ret; -} - -WXDLLEXPORT int wxStrncmp(const wxChar *s1, const wxChar *s2, size_t n) -{ - while (n && (*s1 == *s2) && *s1) n--, s1++, s2++; - if (n) { - if ((wxUChar)*s1 < (wxUChar)*s2) return -1; - if ((wxUChar)*s1 > (wxUChar)*s2) return 1; - } - return 0; -} - -WXDLLEXPORT wxChar * wxStrncpy(wxChar *dest, const wxChar *src, size_t n) -{ - wxChar *ret = dest; - while (n && (*dest++ = *src++)) n--; - while (n) *dest++=0, n--; // the docs specify padding with zeroes - return ret; -} - -WXDLLEXPORT const wxChar * wxStrpbrk(const wxChar *s, const wxChar *accept) -{ - while (*s && !wxStrchr(accept, *s)) - s++; - - return *s ? s : NULL; -} - -WXDLLEXPORT const wxChar * wxStrrchr(const wxChar *s, wxChar c) -{ - const wxChar *ret = NULL; - do - { - if ( *s == c ) - ret = s; - s++; - } - while ( *s ); - - return ret; -} - -WXDLLEXPORT size_t wxStrspn(const wxChar *s, const wxChar *accept) -{ - size_t len = 0; - while (wxStrchr(accept, *s++)) len++; - return len; -} - -WXDLLEXPORT const wxChar *wxStrstr(const wxChar *haystack, const wxChar *needle) -{ - wxASSERT_MSG( needle != NULL, _T("NULL argument in wxStrstr") ); - - // VZ: this is not exactly the most efficient string search algorithm... - - const size_t len = wxStrlen(needle); - - while ( const wxChar *fnd = wxStrchr(haystack, *needle) ) - { - if ( !wxStrncmp(fnd, needle, len) ) - return fnd; - - haystack = fnd + 1; - } - - return NULL; -} - -#ifdef __cplusplus -} -#endif - -WXDLLEXPORT double wxStrtod(const wxChar *nptr, wxChar **endptr) -{ - const wxChar decSep( -#if wxUSE_INTL - wxLocale::GetInfo(wxLOCALE_DECIMAL_POINT, wxLOCALE_CAT_NUMBER)[0] -#else - _T('.') -#endif - ); - const wxChar *start = nptr; - - while (wxIsspace(*nptr)) nptr++; - if (*nptr == wxT('+') || *nptr == wxT('-')) nptr++; - while (wxIsdigit(*nptr)) nptr++; - if (*nptr == decSep) { - nptr++; - while (wxIsdigit(*nptr)) nptr++; - } - if (*nptr == wxT('E') || *nptr == wxT('e')) { - nptr++; - if (*nptr == wxT('+') || *nptr == wxT('-')) nptr++; - while (wxIsdigit(*nptr)) nptr++; - } - - wxString data(start, nptr-start); - const wxWX2MBbuf dat = data.mb_str(wxConvLibc); - char *rdat = wxMBSTRINGCAST dat; - double ret = strtod(dat, &rdat); - - if (endptr) *endptr = (wxChar *)(start + (rdat - (const char *)dat)); - - return ret; -} - -WXDLLEXPORT long int wxStrtol(const wxChar *nptr, wxChar **endptr, int base) -{ - const wxChar *start = nptr; - - while (wxIsspace(*nptr)) nptr++; - if (*nptr == wxT('+') || *nptr == wxT('-')) nptr++; - if (((base == 0) || (base == 16)) && - (nptr[0] == wxT('0') && nptr[1] == wxT('x'))) { - nptr += 2; - base = 16; - } - else if ((base == 0) && (nptr[0] == wxT('0'))) base = 8; - else if (base == 0) base = 10; - - while ((wxIsdigit(*nptr) && (*nptr - wxT('0') < base)) || - (wxIsalpha(*nptr) && (wxToupper(*nptr) - wxT('A') + 10 < base))) nptr++; - - wxString data(start, nptr-start); - wxWX2MBbuf dat = data.mb_str(wxConvLibc); - char *rdat = wxMBSTRINGCAST dat; - long int ret = strtol(dat, &rdat, base); - - if (endptr) *endptr = (wxChar *)(start + (rdat - (const char *)dat)); - - return ret; -} - -WXDLLEXPORT unsigned long int wxStrtoul(const wxChar *nptr, wxChar **endptr, int base) -{ - return (unsigned long int) wxStrtol(nptr, endptr, base); -} - -#endif // wxNEED_WX_STRING_H - -#ifdef wxNEED_WX_STDIO_H -WXDLLEXPORT FILE * wxFopen(const wxChar *path, const wxChar *mode) -{ - char mode_buffer[10]; - for (size_t i = 0; i < wxStrlen(mode)+1; i++) - mode_buffer[i] = (char) mode[i]; - - return fopen( wxConvFile.cWX2MB(path), mode_buffer ); -} - -WXDLLEXPORT FILE * wxFreopen(const wxChar *path, const wxChar *mode, FILE *stream) -{ - char mode_buffer[10]; - for (size_t i = 0; i < wxStrlen(mode)+1; i++) - mode_buffer[i] = (char) mode[i]; - - return freopen( wxConvFile.cWX2MB(path), mode_buffer, stream ); -} - -WXDLLEXPORT int wxRemove(const wxChar *path) -{ - return remove( wxConvFile.cWX2MB(path) ); -} - -WXDLLEXPORT int wxRename(const wxChar *oldpath, const wxChar *newpath) -{ - return rename( wxConvFile.cWX2MB(oldpath), wxConvFile.cWX2MB(newpath) ); -} -#endif - -#ifndef wxAtof -double WXDLLEXPORT wxAtof(const wxChar *psz) -{ -#ifdef __WXWINCE__ - double d; - wxString str(psz); - if (str.ToDouble(& d)) - return d; - - return 0.0; -#else - return atof(wxConvLibc.cWX2MB(psz)); -#endif -} -#endif - -#ifdef wxNEED_WX_STDLIB_H -int WXDLLEXPORT wxAtoi(const wxChar *psz) -{ - return atoi(wxConvLibc.cWX2MB(psz)); -} - -long WXDLLEXPORT wxAtol(const wxChar *psz) -{ - return atol(wxConvLibc.cWX2MB(psz)); -} - -wxChar * WXDLLEXPORT wxGetenv(const wxChar *name) -{ -#if wxUSE_UNICODE - // NB: buffer returned by getenv() is allowed to be overwritten next - // time getenv() is called, so it is OK to use static string - // buffer to hold the data. - static wxWCharBuffer value((wxChar*)NULL); - value = wxConvLibc.cMB2WX(getenv(wxConvLibc.cWX2MB(name))); - return value.data(); -#else - return getenv(name); -#endif -} -#endif // wxNEED_WX_STDLIB_H - -#ifdef wxNEED_WXSYSTEM -int WXDLLEXPORT wxSystem(const wxChar *psz) -{ - return system(wxConvLibc.cWX2MB(psz)); -} -#endif // wxNEED_WXSYSTEM - -#ifdef wxNEED_WX_TIME_H -WXDLLEXPORT size_t -wxStrftime(wxChar *s, size_t maxsize, const wxChar *fmt, const struct tm *tm) -{ - if ( !maxsize ) - return 0; - - wxCharBuffer buf(maxsize); - - wxCharBuffer bufFmt(wxConvLibc.cWX2MB(fmt)); - if ( !bufFmt ) - return 0; - - size_t ret = strftime(buf.data(), maxsize, bufFmt, tm); - if ( !ret ) - return 0; - - wxWCharBuffer wbuf = wxConvLibc.cMB2WX(buf); - if ( !wbuf ) - return 0; - - wxStrncpy(s, wbuf, maxsize); - return wxStrlen(s); -} -#endif // wxNEED_WX_TIME_H - -#ifndef wxCtime -WXDLLEXPORT wxChar *wxCtime(const time_t *timep) -{ - // normally the string is 26 chars but give one more in case some broken - // DOS compiler decides to use "\r\n" instead of "\n" at the end - static wxChar buf[27]; - - // ctime() is guaranteed to return a string containing only ASCII - // characters, as its format is always the same for any locale - wxStrncpy(buf, wxString::FromAscii(ctime(timep)), WXSIZEOF(buf)); - buf[WXSIZEOF(buf) - 1] = _T('\0'); - - return buf; -} -#endif // wxCtime - -#endif // wxUSE_WCHAR_T - -// ---------------------------------------------------------------------------- -// functions which we may need even if !wxUSE_WCHAR_T -// ---------------------------------------------------------------------------- - -#ifndef wxStrtok - -WXDLLEXPORT wxChar * wxStrtok(wxChar *psz, const wxChar *delim, wxChar **save_ptr) -{ - if (!psz) - { - psz = *save_ptr; - if ( !psz ) - return NULL; - } - - psz += wxStrspn(psz, delim); - if (!*psz) - { - *save_ptr = (wxChar *)NULL; - return (wxChar *)NULL; - } - - wxChar *ret = psz; - psz = wxStrpbrk(psz, delim); - if (!psz) - { - *save_ptr = (wxChar*)NULL; - } - else - { - *psz = wxT('\0'); - *save_ptr = psz + 1; - } - - return ret; -} - -#endif // wxStrtok - -// ---------------------------------------------------------------------------- -// missing C RTL functions -// ---------------------------------------------------------------------------- - -#ifdef wxNEED_STRDUP - -char *strdup(const char *s) -{ - char *dest = (char*) malloc( strlen( s ) + 1 ) ; - if ( dest ) - strcpy( dest , s ) ; - return dest ; -} -#endif // wxNEED_STRDUP - -#if defined(__WXWINCE__) && (_WIN32_WCE <= 211) - -void *calloc( size_t num, size_t size ) -{ - void** ptr = (void **)malloc(num * size); - memset( ptr, 0, num * size); - return ptr; -} - -#endif // __WXWINCE__ <= 211 - -#ifdef __WXWINCE__ - -int wxRemove(const wxChar *path) -{ - return ::DeleteFile(path) == 0; -} - -#endif +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/wxchar.cpp +// Purpose: wxChar implementation +// Author: Ove Kaven +// Modified by: Ron Lee, Francesco Montorsi +// Created: 09/04/99 +// RCS-ID: $Id: wxchar.cpp 54071 2008-06-10 18:22:32Z VZ $ +// Copyright: (c) wxWidgets copyright +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// =========================================================================== +// headers, declarations, constants +// =========================================================================== + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#include "wx/wxchar.h" + +#define _ISOC9X_SOURCE 1 // to get vsscanf() +#define _BSD_SOURCE 1 // to still get strdup() + +#include +#include +#include + +#ifndef __WXWINCE__ + #include + #include +#else + #include "wx/msw/wince/time.h" +#endif + +#ifndef WX_PRECOMP + #include "wx/string.h" + #include "wx/hash.h" + #include "wx/utils.h" // for wxMin and wxMax + #include "wx/log.h" +#endif + +#if defined(__WIN32__) && defined(wxNEED_WX_CTYPE_H) + #include + #include + #include + #include +#endif + +#if defined(__MWERKS__) && __MSL__ >= 0x6000 +namespace std {} +using namespace std ; +#endif + +#if wxUSE_WCHAR_T +size_t WXDLLEXPORT wxMB2WC(wchar_t *buf, const char *psz, size_t n) +{ + // assume that we have mbsrtowcs() too if we have wcsrtombs() +#ifdef HAVE_WCSRTOMBS + mbstate_t mbstate; + memset(&mbstate, 0, sizeof(mbstate_t)); +#endif + + if (buf) { + if (!n || !*psz) { + if (n) *buf = wxT('\0'); + return 0; + } +#ifdef HAVE_WCSRTOMBS + return mbsrtowcs(buf, &psz, n, &mbstate); +#else + return wxMbstowcs(buf, psz, n); +#endif + } + + // note that we rely on common (and required by Unix98 but unfortunately not + // C99) extension which allows to call mbs(r)towcs() with NULL output pointer + // to just get the size of the needed buffer -- this is needed as otherwise + // we have no idea about how much space we need and if the CRT doesn't + // support it (the only currently known example being Metrowerks, see + // wx/wxchar.h) we don't use its mbstowcs() at all +#ifdef HAVE_WCSRTOMBS + return mbsrtowcs((wchar_t *) NULL, &psz, 0, &mbstate); +#else + return wxMbstowcs((wchar_t *) NULL, psz, 0); +#endif +} + +size_t WXDLLEXPORT wxWC2MB(char *buf, const wchar_t *pwz, size_t n) +{ +#ifdef HAVE_WCSRTOMBS + mbstate_t mbstate; + memset(&mbstate, 0, sizeof(mbstate_t)); +#endif + + if (buf) { + if (!n || !*pwz) { + // glibc2.1 chokes on null input + if (n) *buf = '\0'; + return 0; + } +#ifdef HAVE_WCSRTOMBS + return wcsrtombs(buf, &pwz, n, &mbstate); +#else + return wxWcstombs(buf, pwz, n); +#endif + } + +#ifdef HAVE_WCSRTOMBS + return wcsrtombs((char *) NULL, &pwz, 0, &mbstate); +#else + return wxWcstombs((char *) NULL, pwz, 0); +#endif +} +#endif // wxUSE_WCHAR_T + +bool WXDLLEXPORT wxOKlibc() +{ +#if wxUSE_WCHAR_T && defined(__UNIX__) && defined(__GLIBC__) && !defined(__WINE__) + // glibc 2.0 uses UTF-8 even when it shouldn't + wchar_t res = 0; + if ((MB_CUR_MAX == 2) && + (wxMB2WC(&res, "\xdd\xa5", 1) == 1) && + (res==0x765)) { + // this is UTF-8 allright, check whether that's what we want + char *cur_locale = setlocale(LC_CTYPE, NULL); + if ((strlen(cur_locale) < 4) || + (strcasecmp(cur_locale + strlen(cur_locale) - 4, "utf8")) || + (strcasecmp(cur_locale + strlen(cur_locale) - 5, "utf-8"))) { + // nope, don't use libc conversion + return false; + } + } +#endif + return true; +} + +// ============================================================================ +// printf() functions business +// ============================================================================ + +// special test mode: define all functions below even if we don't really need +// them to be able to test them +#ifdef wxTEST_PRINTF + #undef wxFprintf + #undef wxPrintf + #undef wxSprintf + #undef wxVfprintf + #undef wxVsprintf + #undef wxVprintf + #undef wxVsnprintf_ + #undef wxSnprintf_ + + #define wxNEED_WPRINTF + + int wxVfprintf( FILE *stream, const wxChar *format, va_list argptr ); +#endif + +// ---------------------------------------------------------------------------- +// implement [v]snprintf() if the system doesn't provide a safe one +// or if the system's one does not support positional parameters +// (very useful for i18n purposes) +// ---------------------------------------------------------------------------- + +#if !defined(wxVsnprintf_) + +#if !wxUSE_WXVSNPRINTF + #error wxUSE_WXVSNPRINTF must be 1 if our wxVsnprintf_ is used +#endif + +// wxUSE_STRUTILS says our wxVsnprintf_ implementation to use or not to +// use wxStrlen and wxStrncpy functions over one-char processing loops. +// +// Some benchmarking revealed that wxUSE_STRUTILS == 1 has the following +// effects: +// -> on Windows: +// when in ANSI mode, this setting does not change almost anything +// when in Unicode mode, it gives ~ 50% of slowdown ! +// -> on Linux: +// both in ANSI and Unicode mode it gives ~ 60% of speedup ! +// +#if defined(WIN32) && wxUSE_UNICODE +#define wxUSE_STRUTILS 0 +#else +#define wxUSE_STRUTILS 1 +#endif + +// some limits of our implementation +#define wxMAX_SVNPRINTF_ARGUMENTS 64 +#define wxMAX_SVNPRINTF_FLAGBUFFER_LEN 32 +#define wxMAX_SVNPRINTF_SCRATCHBUFFER_LEN 512 + +// prefer snprintf over sprintf +#if defined(__VISUALC__) || \ + (defined(__BORLANDC__) && __BORLANDC__ >= 0x540) + #define system_sprintf(buff, max, flags, data) \ + ::_snprintf(buff, max, flags, data) +#elif defined(HAVE_SNPRINTF) + #define system_sprintf(buff, max, flags, data) \ + ::snprintf(buff, max, flags, data) +#else // NB: at least sprintf() should always be available + // since 'max' is not used in this case, wxVsnprintf() should always + // ensure that 'buff' is big enough for all common needs + // (see wxMAX_SVNPRINTF_FLAGBUFFER_LEN and wxMAX_SVNPRINTF_SCRATCHBUFFER_LEN) + #define system_sprintf(buff, max, flags, data) \ + ::sprintf(buff, flags, data) + + #define SYSTEM_SPRINTF_IS_UNSAFE +#endif + +// the conversion specifiers accepted by wxVsnprintf_ +enum wxPrintfArgType { + wxPAT_INVALID = -1, + + wxPAT_INT, // %d, %i, %o, %u, %x, %X + wxPAT_LONGINT, // %ld, etc +#ifdef wxLongLong_t + wxPAT_LONGLONGINT, // %Ld, etc +#endif + wxPAT_SIZET, // %Zd, etc + + wxPAT_DOUBLE, // %e, %E, %f, %g, %G + wxPAT_LONGDOUBLE, // %le, etc + + wxPAT_POINTER, // %p + + wxPAT_CHAR, // %hc (in ANSI mode: %c, too) + wxPAT_WCHAR, // %lc (in Unicode mode: %c, too) + + wxPAT_PCHAR, // %s (related to a char *) + wxPAT_PWCHAR, // %s (related to a wchar_t *) + + wxPAT_NINT, // %n + wxPAT_NSHORTINT, // %hn + wxPAT_NLONGINT // %ln +}; + +// an argument passed to wxVsnprintf_ +typedef union { + int pad_int; // %d, %i, %o, %u, %x, %X + long int pad_longint; // %ld, etc +#ifdef wxLongLong_t + wxLongLong_t pad_longlongint; // %Ld, etc +#endif + size_t pad_sizet; // %Zd, etc + + double pad_double; // %e, %E, %f, %g, %G + long double pad_longdouble; // %le, etc + + void *pad_pointer; // %p + + char pad_char; // %hc (in ANSI mode: %c, too) + wchar_t pad_wchar; // %lc (in Unicode mode: %c, too) + + char *pad_pchar; // %s (related to a char *) + wchar_t *pad_pwchar; // %s (related to a wchar_t *) + + int *pad_nint; // %n + short int *pad_nshortint; // %hn + long int *pad_nlongint; // %ln +} wxPrintfArg; + + +// Contains parsed data relative to a conversion specifier given to +// wxVsnprintf_ and parsed from the format string +// NOTE: in C++ there is almost no difference between struct & classes thus +// there is no performance gain by using a struct here... +class wxPrintfConvSpec +{ +public: + + // the position of the argument relative to this conversion specifier + size_t m_pos; + + // the type of this conversion specifier + wxPrintfArgType m_type; + + // the minimum and maximum width + // when one of this var is set to -1 it means: use the following argument + // in the stack as minimum/maximum width for this conversion specifier + int m_nMinWidth, m_nMaxWidth; + + // does the argument need to the be aligned to left ? + bool m_bAlignLeft; + + // pointer to the '%' of this conversion specifier in the format string + // NOTE: this points somewhere in the string given to the Parse() function - + // it's task of the caller ensure that memory is still valid ! + const wxChar *m_pArgPos; + + // pointer to the last character of this conversion specifier in the + // format string + // NOTE: this points somewhere in the string given to the Parse() function - + // it's task of the caller ensure that memory is still valid ! + const wxChar *m_pArgEnd; + + // a little buffer where formatting flags like #+\.hlqLZ are stored by Parse() + // for use in Process() + // NB: even if this buffer is used only for numeric conversion specifiers and + // thus could be safely declared as a char[] buffer, we want it to be wxChar + // so that in Unicode builds we can avoid to convert its contents to Unicode + // chars when copying it in user's buffer. + char m_szFlags[wxMAX_SVNPRINTF_FLAGBUFFER_LEN]; + + +public: + + // we don't declare this as a constructor otherwise it would be called + // automatically and we don't want this: to be optimized, wxVsnprintf_ + // calls this function only on really-used instances of this class. + void Init(); + + // Parses the first conversion specifier in the given string, which must + // begin with a '%'. Returns false if the first '%' does not introduce a + // (valid) conversion specifier and thus should be ignored. + bool Parse(const wxChar *format); + + // Process this conversion specifier and puts the result in the given + // buffer. Returns the number of characters written in 'buf' or -1 if + // there's not enough space. + int Process(wxChar *buf, size_t lenMax, wxPrintfArg *p, size_t written); + + // Loads the argument of this conversion specifier from given va_list. + bool LoadArg(wxPrintfArg *p, va_list &argptr); + +private: + // An helper function of LoadArg() which is used to handle the '*' flag + void ReplaceAsteriskWith(int w); +}; + +void wxPrintfConvSpec::Init() +{ + m_nMinWidth = 0; + m_nMaxWidth = 0xFFFF; + m_pos = 0; + m_bAlignLeft = false; + m_pArgPos = m_pArgEnd = NULL; + m_type = wxPAT_INVALID; + + // this character will never be removed from m_szFlags array and + // is important when calling sprintf() in wxPrintfConvSpec::Process() ! + m_szFlags[0] = '%'; +} + +bool wxPrintfConvSpec::Parse(const wxChar *format) +{ + bool done = false; + + // temporary parse data + size_t flagofs = 1; + bool in_prec, // true if we found the dot in some previous iteration + prec_dot; // true if the dot has been already added to m_szFlags + int ilen = 0; + + m_bAlignLeft = in_prec = prec_dot = false; + m_pArgPos = m_pArgEnd = format; + do + { +#define CHECK_PREC \ + if (in_prec && !prec_dot) \ + { \ + m_szFlags[flagofs++] = '.'; \ + prec_dot = true; \ + } + + // what follows '%'? + const wxChar ch = *(++m_pArgEnd); + switch ( ch ) + { + case wxT('\0'): + return false; // not really an argument + + case wxT('%'): + return false; // not really an argument + + case wxT('#'): + case wxT('0'): + case wxT(' '): + case wxT('+'): + case wxT('\''): + CHECK_PREC + m_szFlags[flagofs++] = char(ch); + break; + + case wxT('-'): + CHECK_PREC + m_bAlignLeft = true; + m_szFlags[flagofs++] = char(ch); + break; + + case wxT('.'): + CHECK_PREC + in_prec = true; + prec_dot = false; + m_nMaxWidth = 0; + // dot will be auto-added to m_szFlags if non-negative + // number follows + break; + + case wxT('h'): + ilen = -1; + CHECK_PREC + m_szFlags[flagofs++] = char(ch); + break; + + case wxT('l'): + // NB: it's safe to use flagofs-1 as flagofs always start from 1 + if (m_szFlags[flagofs-1] == 'l') // 'll' modifier is the same as 'L' or 'q' + ilen = 2; + else + ilen = 1; + CHECK_PREC + m_szFlags[flagofs++] = char(ch); + break; + + case wxT('q'): + case wxT('L'): + ilen = 2; + CHECK_PREC + m_szFlags[flagofs++] = char(ch); + break; +#ifdef __WXMSW__ + // under Windows we support the special '%I64' notation as longlong + // integer conversion specifier for MSVC compatibility + // (it behaves exactly as '%lli' or '%Li' or '%qi') + case wxT('I'): + if (*(m_pArgEnd+1) != wxT('6') || + *(m_pArgEnd+2) != wxT('4')) + return false; // bad format + + m_pArgEnd++; + m_pArgEnd++; + + ilen = 2; + CHECK_PREC + m_szFlags[flagofs++] = char(ch); + m_szFlags[flagofs++] = '6'; + m_szFlags[flagofs++] = '4'; + break; +#endif // __WXMSW__ + + case wxT('Z'): + ilen = 3; + CHECK_PREC + m_szFlags[flagofs++] = char(ch); + break; + + case wxT('*'): + if (in_prec) + { + CHECK_PREC + + // tell Process() to use the next argument + // in the stack as maxwidth... + m_nMaxWidth = -1; + } + else + { + // tell Process() to use the next argument + // in the stack as minwidth... + m_nMinWidth = -1; + } + + // save the * in our formatting buffer... + // will be replaced later by Process() + m_szFlags[flagofs++] = char(ch); + break; + + case wxT('1'): case wxT('2'): case wxT('3'): + case wxT('4'): case wxT('5'): case wxT('6'): + case wxT('7'): case wxT('8'): case wxT('9'): + { + int len = 0; + CHECK_PREC + while ( (*m_pArgEnd >= wxT('0')) && + (*m_pArgEnd <= wxT('9')) ) + { + m_szFlags[flagofs++] = char(*m_pArgEnd); + len = len*10 + (*m_pArgEnd - wxT('0')); + m_pArgEnd++; + } + + if (in_prec) + m_nMaxWidth = len; + else + m_nMinWidth = len; + + m_pArgEnd--; // the main loop pre-increments n again + } + break; + + case wxT('$'): // a positional parameter (e.g. %2$s) ? + { + if (m_nMinWidth <= 0) + break; // ignore this formatting flag as no + // numbers are preceding it + + // remove from m_szFlags all digits previously added + do { + flagofs--; + } while (m_szFlags[flagofs] >= '1' && + m_szFlags[flagofs] <= '9'); + + // re-adjust the offset making it point to the + // next free char of m_szFlags + flagofs++; + + m_pos = m_nMinWidth; + m_nMinWidth = 0; + } + break; + + case wxT('d'): + case wxT('i'): + case wxT('o'): + case wxT('u'): + case wxT('x'): + case wxT('X'): + CHECK_PREC + m_szFlags[flagofs++] = char(ch); + m_szFlags[flagofs] = '\0'; + if (ilen == 0) + m_type = wxPAT_INT; + else if (ilen == -1) + // NB: 'short int' value passed through '...' + // is promoted to 'int', so we have to get + // an int from stack even if we need a short + m_type = wxPAT_INT; + else if (ilen == 1) + m_type = wxPAT_LONGINT; + else if (ilen == 2) +#ifdef wxLongLong_t + m_type = wxPAT_LONGLONGINT; +#else // !wxLongLong_t + m_type = wxPAT_LONGINT; +#endif // wxLongLong_t/!wxLongLong_t + else if (ilen == 3) + m_type = wxPAT_SIZET; + done = true; + break; + + case wxT('e'): + case wxT('E'): + case wxT('f'): + case wxT('g'): + case wxT('G'): + CHECK_PREC + m_szFlags[flagofs++] = char(ch); + m_szFlags[flagofs] = '\0'; + if (ilen == 2) + m_type = wxPAT_LONGDOUBLE; + else + m_type = wxPAT_DOUBLE; + done = true; + break; + + case wxT('p'): + m_type = wxPAT_POINTER; + m_szFlags[flagofs++] = char(ch); + m_szFlags[flagofs] = '\0'; + done = true; + break; + + case wxT('c'): + if (ilen == -1) + { + // in Unicode mode %hc == ANSI character + // and in ANSI mode, %hc == %c == ANSI... + m_type = wxPAT_CHAR; + } + else if (ilen == 1) + { + // in ANSI mode %lc == Unicode character + // and in Unicode mode, %lc == %c == Unicode... + m_type = wxPAT_WCHAR; + } + else + { +#if wxUSE_UNICODE + // in Unicode mode, %c == Unicode character + m_type = wxPAT_WCHAR; +#else + // in ANSI mode, %c == ANSI character + m_type = wxPAT_CHAR; +#endif + } + done = true; + break; + + case wxT('s'): + if (ilen == -1) + { + // Unicode mode wx extension: we'll let %hs mean non-Unicode + // strings (when in ANSI mode, %s == %hs == ANSI string) + m_type = wxPAT_PCHAR; + } + else if (ilen == 1) + { + // in Unicode mode, %ls == %s == Unicode string + // in ANSI mode, %ls == Unicode string + m_type = wxPAT_PWCHAR; + } + else + { +#if wxUSE_UNICODE + m_type = wxPAT_PWCHAR; +#else + m_type = wxPAT_PCHAR; +#endif + } + done = true; + break; + + case wxT('n'): + if (ilen == 0) + m_type = wxPAT_NINT; + else if (ilen == -1) + m_type = wxPAT_NSHORTINT; + else if (ilen >= 1) + m_type = wxPAT_NLONGINT; + done = true; + break; + + default: + // bad format, don't consider this an argument; + // leave it unchanged + return false; + } + + if (flagofs == wxMAX_SVNPRINTF_FLAGBUFFER_LEN) + { + wxLogDebug(wxT("Too many flags specified for a single conversion specifier!")); + return false; + } + } + while (!done); + + return true; // parsing was successful +} + + +void wxPrintfConvSpec::ReplaceAsteriskWith(int width) +{ + char temp[wxMAX_SVNPRINTF_FLAGBUFFER_LEN]; + + // find the first * in our flag buffer + char *pwidth = strchr(m_szFlags, '*'); + wxCHECK_RET(pwidth, _T("field width must be specified")); + + // save what follows the * (the +1 is to skip the asterisk itself!) + strcpy(temp, pwidth+1); + if (width < 0) + { + pwidth[0] = wxT('-'); + pwidth++; + } + + // replace * with the actual integer given as width +#ifndef SYSTEM_SPRINTF_IS_UNSAFE + int maxlen = (m_szFlags + wxMAX_SVNPRINTF_FLAGBUFFER_LEN - pwidth) / + sizeof(*m_szFlags); +#endif + int offset = system_sprintf(pwidth, maxlen, "%d", abs(width)); + + // restore after the expanded * what was following it + strcpy(pwidth+offset, temp); +} + +bool wxPrintfConvSpec::LoadArg(wxPrintfArg *p, va_list &argptr) +{ + // did the '*' width/precision specifier was used ? + if (m_nMaxWidth == -1) + { + // take the maxwidth specifier from the stack + m_nMaxWidth = va_arg(argptr, int); + if (m_nMaxWidth < 0) + m_nMaxWidth = 0; + else + ReplaceAsteriskWith(m_nMaxWidth); + } + + if (m_nMinWidth == -1) + { + // take the minwidth specifier from the stack + m_nMinWidth = va_arg(argptr, int); + + ReplaceAsteriskWith(m_nMinWidth); + if (m_nMinWidth < 0) + { + m_bAlignLeft = !m_bAlignLeft; + m_nMinWidth = -m_nMinWidth; + } + } + + switch (m_type) { + case wxPAT_INT: + p->pad_int = va_arg(argptr, int); + break; + case wxPAT_LONGINT: + p->pad_longint = va_arg(argptr, long int); + break; +#ifdef wxLongLong_t + case wxPAT_LONGLONGINT: + p->pad_longlongint = va_arg(argptr, wxLongLong_t); + break; +#endif // wxLongLong_t + case wxPAT_SIZET: + p->pad_sizet = va_arg(argptr, size_t); + break; + case wxPAT_DOUBLE: + p->pad_double = va_arg(argptr, double); + break; + case wxPAT_LONGDOUBLE: + p->pad_longdouble = va_arg(argptr, long double); + break; + case wxPAT_POINTER: + p->pad_pointer = va_arg(argptr, void *); + break; + + case wxPAT_CHAR: + p->pad_char = (char)va_arg(argptr, int); // char is promoted to int when passed through '...' + break; + case wxPAT_WCHAR: + p->pad_wchar = (wchar_t)va_arg(argptr, int); // char is promoted to int when passed through '...' + break; + + case wxPAT_PCHAR: + p->pad_pchar = va_arg(argptr, char *); + break; + case wxPAT_PWCHAR: + p->pad_pwchar = va_arg(argptr, wchar_t *); + break; + + case wxPAT_NINT: + p->pad_nint = va_arg(argptr, int *); + break; + case wxPAT_NSHORTINT: + p->pad_nshortint = va_arg(argptr, short int *); + break; + case wxPAT_NLONGINT: + p->pad_nlongint = va_arg(argptr, long int *); + break; + + case wxPAT_INVALID: + default: + return false; + } + + return true; // loading was successful +} + +int wxPrintfConvSpec::Process(wxChar *buf, size_t lenMax, wxPrintfArg *p, size_t written) +{ + // buffer to avoid dynamic memory allocation each time for small strings; + // note that this buffer is used only to hold results of number formatting, + // %s directly writes user's string in buf, without using szScratch + char szScratch[wxMAX_SVNPRINTF_SCRATCHBUFFER_LEN]; + size_t lenScratch = 0, lenCur = 0; + +#define APPEND_CH(ch) \ + { \ + if ( lenCur == lenMax ) \ + return -1; \ + \ + buf[lenCur++] = ch; \ + } + +#define APPEND_STR(s) \ + { \ + for ( const wxChar *p = s; *p; p++ ) \ + { \ + APPEND_CH(*p); \ + } \ + } + + switch ( m_type ) + { + case wxPAT_INT: + lenScratch = system_sprintf(szScratch, wxMAX_SVNPRINTF_SCRATCHBUFFER_LEN, m_szFlags, p->pad_int); + break; + + case wxPAT_LONGINT: + lenScratch = system_sprintf(szScratch, wxMAX_SVNPRINTF_SCRATCHBUFFER_LEN, m_szFlags, p->pad_longint); + break; + +#ifdef wxLongLong_t + case wxPAT_LONGLONGINT: + lenScratch = system_sprintf(szScratch, wxMAX_SVNPRINTF_SCRATCHBUFFER_LEN, m_szFlags, p->pad_longlongint); + break; +#endif // SIZEOF_LONG_LONG + + case wxPAT_SIZET: + lenScratch = system_sprintf(szScratch, wxMAX_SVNPRINTF_SCRATCHBUFFER_LEN, m_szFlags, p->pad_sizet); + break; + + case wxPAT_LONGDOUBLE: + lenScratch = system_sprintf(szScratch, wxMAX_SVNPRINTF_SCRATCHBUFFER_LEN, m_szFlags, p->pad_longdouble); + break; + + case wxPAT_DOUBLE: + lenScratch = system_sprintf(szScratch, wxMAX_SVNPRINTF_SCRATCHBUFFER_LEN, m_szFlags, p->pad_double); + break; + + case wxPAT_POINTER: + lenScratch = system_sprintf(szScratch, wxMAX_SVNPRINTF_SCRATCHBUFFER_LEN, m_szFlags, p->pad_pointer); + break; + + case wxPAT_CHAR: + case wxPAT_WCHAR: + { + wxChar val = +#if wxUSE_UNICODE + p->pad_wchar; + + if (m_type == wxPAT_CHAR) + { + // user passed a character explicitely indicated as ANSI... + const char buf[2] = { p->pad_char, 0 }; + val = wxString(buf, wxConvLibc)[0u]; + + //wprintf(L"converting ANSI=>Unicode"); // for debug + } +#else + p->pad_char; + +#if wxUSE_WCHAR_T + if (m_type == wxPAT_WCHAR) + { + // user passed a character explicitely indicated as Unicode... + const wchar_t buf[2] = { p->pad_wchar, 0 }; + val = wxString(buf, wxConvLibc)[0u]; + + //printf("converting Unicode=>ANSI"); // for debug + } +#endif +#endif + + size_t i; + + if (!m_bAlignLeft) + for (i = 1; i < (size_t)m_nMinWidth; i++) + APPEND_CH(_T(' ')); + + APPEND_CH(val); + + if (m_bAlignLeft) + for (i = 1; i < (size_t)m_nMinWidth; i++) + APPEND_CH(_T(' ')); + } + break; + + case wxPAT_PCHAR: + case wxPAT_PWCHAR: + { + wxString s; + const wxChar *val = +#if wxUSE_UNICODE + p->pad_pwchar; + + if (m_type == wxPAT_PCHAR) + { + // user passed a string explicitely indicated as ANSI... + val = s = wxString(p->pad_pchar, wxConvLibc); + + //wprintf(L"converting ANSI=>Unicode"); // for debug + } +#else + p->pad_pchar; + +#if wxUSE_WCHAR_T + if (m_type == wxPAT_PWCHAR) + { + // user passed a string explicitely indicated as Unicode... + val = s = wxString(p->pad_pwchar, wxConvLibc); + + //printf("converting Unicode=>ANSI"); // for debug + } +#endif +#endif + int len; + + if (val) + { +#if wxUSE_STRUTILS + // at this point we are sure that m_nMaxWidth is positive or null + // (see top of wxPrintfConvSpec::LoadArg) + len = wxMin((unsigned int)m_nMaxWidth, wxStrlen(val)); +#else + for ( len = 0; val[len] && (len < m_nMaxWidth); len++ ) + ; +#endif + } + else if (m_nMaxWidth >= 6) + { + val = wxT("(null)"); + len = 6; + } + else + { + val = wxEmptyString; + len = 0; + } + + int i; + + if (!m_bAlignLeft) + { + for (i = len; i < m_nMinWidth; i++) + APPEND_CH(_T(' ')); + } + +#if wxUSE_STRUTILS + len = wxMin((unsigned int)len, lenMax-lenCur); + wxStrncpy(buf+lenCur, val, len); + lenCur += len; +#else + for (i = 0; i < len; i++) + APPEND_CH(val[i]); +#endif + + if (m_bAlignLeft) + { + for (i = len; i < m_nMinWidth; i++) + APPEND_CH(_T(' ')); + } + } + break; + + case wxPAT_NINT: + *p->pad_nint = written; + break; + + case wxPAT_NSHORTINT: + *p->pad_nshortint = (short int)written; + break; + + case wxPAT_NLONGINT: + *p->pad_nlongint = written; + break; + + case wxPAT_INVALID: + default: + return -1; + } + + // if we used system's sprintf() then we now need to append the s_szScratch + // buffer to the given one... + switch (m_type) + { + case wxPAT_INT: + case wxPAT_LONGINT: +#ifdef wxLongLong_t + case wxPAT_LONGLONGINT: +#endif + case wxPAT_SIZET: + case wxPAT_LONGDOUBLE: + case wxPAT_DOUBLE: + case wxPAT_POINTER: + wxASSERT(lenScratch < wxMAX_SVNPRINTF_SCRATCHBUFFER_LEN); +#if !wxUSE_UNICODE + { + if (lenMax < lenScratch) + { + // fill output buffer and then return -1 + wxStrncpy(buf, szScratch, lenMax); + return -1; + } + wxStrncpy(buf, szScratch, lenScratch); + lenCur += lenScratch; + } +#else + { + // Copy the char scratch to the wide output. This requires + // conversion, but we can optimise by making use of the fact + // that we are formatting numbers, this should mean only 7-bit + // ascii characters are involved. + wxChar *bufptr = buf; + const wxChar *bufend = buf + lenMax; + const char *scratchptr = szScratch; + + // Simply copy each char to a wxChar, stopping on the first + // null or non-ascii byte. Checking '(signed char)*scratchptr + // > 0' is an extra optimisation over '*scratchptr != 0 && + // isascii(*scratchptr)', though it assumes signed char is + // 8-bit 2 complement. + while ((signed char)*scratchptr > 0 && bufptr != bufend) + *bufptr++ = *scratchptr++; + + if (bufptr == bufend) + return -1; + + lenCur += bufptr - buf; + + // check if the loop stopped on a non-ascii char, if yes then + // fall back to wxMB2WX + if (*scratchptr) + { + size_t len = wxMB2WX(bufptr, scratchptr, bufend - bufptr); + + if (len && len != (size_t)(-1)) + if (bufptr[len - 1]) + return -1; + else + lenCur += len; + } + } +#endif + break; + + default: + break; // all other cases were completed previously + } + + return lenCur; +} + +// Copy chars from source to dest converting '%%' to '%'. Takes at most maxIn +// chars from source and write at most outMax chars to dest, returns the +// number of chars actually written. Does not treat null specially. +// +static int wxCopyStrWithPercents( + size_t maxOut, + wxChar *dest, + size_t maxIn, + const wxChar *source) +{ + size_t written = 0; + + if (maxIn == 0) + return 0; + + size_t i; + for ( i = 0; i < maxIn-1 && written < maxOut; source++, i++) + { + dest[written++] = *source; + if (*(source+1) == wxT('%')) + { + // skip this additional '%' character + source++; + i++; + } + } + + if (i < maxIn && written < maxOut) + // copy last character inconditionally + dest[written++] = *source; + + return written; +} + +int WXDLLEXPORT wxVsnprintf_(wxChar *buf, size_t lenMax, + const wxChar *format, va_list argptr) +{ + // useful for debugging, to understand if we are really using this function + // rather than the system implementation +#if 0 + wprintf(L"Using wxVsnprintf_\n"); +#endif + + // required memory: + wxPrintfConvSpec arg[wxMAX_SVNPRINTF_ARGUMENTS]; + wxPrintfArg argdata[wxMAX_SVNPRINTF_ARGUMENTS]; + wxPrintfConvSpec *pspec[wxMAX_SVNPRINTF_ARGUMENTS] = { NULL }; + + size_t i; + + // number of characters in the buffer so far, must be less than lenMax + size_t lenCur = 0; + + size_t nargs = 0; + const wxChar *toparse = format; + + // parse the format string + bool posarg_present = false, nonposarg_present = false; + for (; *toparse != wxT('\0'); toparse++) + { + if (*toparse == wxT('%') ) + { + arg[nargs].Init(); + + // let's see if this is a (valid) conversion specifier... + if (arg[nargs].Parse(toparse)) + { + // ...yes it is + wxPrintfConvSpec *current = &arg[nargs]; + + // make toparse point to the end of this specifier + toparse = current->m_pArgEnd; + + if (current->m_pos > 0) + { + // the positionals start from number 1... adjust the index + current->m_pos--; + posarg_present = true; + } + else + { + // not a positional argument... + current->m_pos = nargs; + nonposarg_present = true; + } + + // this conversion specifier is tied to the pos-th argument... + pspec[current->m_pos] = current; + nargs++; + + if (nargs == wxMAX_SVNPRINTF_ARGUMENTS) + { + wxLogDebug(wxT("A single call to wxVsnprintf() has more than %d arguments; ") + wxT("ignoring all remaining arguments."), wxMAX_SVNPRINTF_ARGUMENTS); + break; // cannot handle any additional conv spec + } + } + else + { + // it's safe to look in the next character of toparse as at worst + // we'll hit its \0 + if (*(toparse+1) == wxT('%')) + toparse++; // the Parse() returned false because we've found a %% + } + } + } + + if (posarg_present && nonposarg_present) + { + buf[0] = 0; + return -1; // format strings with both positional and + } // non-positional conversion specifier are unsupported !! + + // on platforms where va_list is an array type, it is necessary to make a + // copy to be able to pass it to LoadArg as a reference. + bool ok = true; + va_list ap; + wxVaCopy(ap, argptr); + + // now load arguments from stack + for (i=0; i < nargs && ok; i++) + { + // !pspec[i] means that the user forgot a positional parameter (e.g. %$1s %$3s); + // LoadArg == false means that wxPrintfConvSpec::Parse failed to set the + // conversion specifier 'type' to a valid value... + ok = pspec[i] && pspec[i]->LoadArg(&argdata[i], ap); + } + + va_end(ap); + + // something failed while loading arguments from the variable list... + // (e.g. the user repeated twice the same positional argument) + if (!ok) + { + buf[0] = 0; + return -1; + } + + // finally, process each conversion specifier with its own argument + toparse = format; + for (i=0; i < nargs; i++) + { + // copy in the output buffer the portion of the format string between + // last specifier and the current one + size_t tocopy = ( arg[i].m_pArgPos - toparse ); + + lenCur += wxCopyStrWithPercents(lenMax - lenCur, buf + lenCur, + tocopy, toparse); + if (lenCur == lenMax) + { + buf[lenMax - 1] = 0; + return lenMax+1; // not enough space in the output buffer ! + } + + // process this specifier directly in the output buffer + int n = arg[i].Process(buf+lenCur, lenMax - lenCur, &argdata[arg[i].m_pos], lenCur); + if (n == -1) + { + buf[lenMax-1] = wxT('\0'); // be sure to always NUL-terminate the string + return lenMax+1; // not enough space in the output buffer ! + } + lenCur += n; + + // the +1 is because wxPrintfConvSpec::m_pArgEnd points to the last character + // of the format specifier, but we are not interested to it... + toparse = arg[i].m_pArgEnd + 1; + } + + // copy portion of the format string after last specifier + // NOTE: toparse is pointing to the character just after the last processed + // conversion specifier + // NOTE2: the +1 is because we want to copy also the '\0' + size_t tocopy = wxStrlen(format) + 1 - ( toparse - format ) ; + + lenCur += wxCopyStrWithPercents(lenMax - lenCur, buf + lenCur, + tocopy, toparse) - 1; + if (buf[lenCur]) + { + buf[lenCur] = 0; + return lenMax+1; // not enough space in the output buffer ! + } + + // Don't do: + // wxASSERT(lenCur == wxStrlen(buf)); + // in fact if we embedded NULLs in the output buffer (using %c with a '\0') + // such check would fail + + return lenCur; +} + +#undef APPEND_CH +#undef APPEND_STR +#undef CHECK_PREC + +#else // wxVsnprintf_ is defined + +#if wxUSE_WXVSNPRINTF + #error wxUSE_WXVSNPRINTF must be 0 if our wxVsnprintf_ is not used +#endif + +#endif // !wxVsnprintf_ + +#if !defined(wxSnprintf_) +int WXDLLEXPORT wxSnprintf_(wxChar *buf, size_t len, const wxChar *format, ...) +{ + va_list argptr; + va_start(argptr, format); + + int iLen = wxVsnprintf_(buf, len, format, argptr); + + va_end(argptr); + + return iLen; +} +#endif // wxSnprintf_ + +#if defined(__DMC__) + /* Digital Mars adds count to _stprintf (C99) so convert */ + #if wxUSE_UNICODE + int wxSprintf (wchar_t * __RESTRICT s, const wchar_t * __RESTRICT format, ... ) + { + va_list arglist; + + va_start( arglist, format ); + int iLen = swprintf ( s, -1, format, arglist ); + va_end( arglist ); + return iLen ; + } + + #endif // wxUSE_UNICODE + +#endif //__DMC__ + +#if defined(__MINGW32__) && ( defined(_STLPORT_VERSION) && _STLPORT_VERSION >= 0x510 ) + /* MinGW with STLPort 5.1 has clashing defines for _stprintf so use swprintf */ + /* STLPort 5.1 defines standard (C99) vswprintf() and swprintf() that takes count. */ + int wxSprintf (wchar_t * s, const wchar_t * format, ... ) + { + va_list arglist; + + va_start( arglist, format ); + int iLen = swprintf ( s, -1, format, arglist ); + va_end( arglist ); + return iLen ; + } +#endif // MINGW32 _STLPORT_VERSION >= 0x510 + +// ---------------------------------------------------------------------------- +// implement the standard IO functions for wide char if libc doesn't have them +// ---------------------------------------------------------------------------- + +#ifdef wxNEED_FPUTS +int wxFputs(const wchar_t *ws, FILE *stream) +{ + wxCharBuffer buf(wxConvLibc.cWC2MB(ws)); + if ( !buf ) + return -1; + + // counting the number of wide characters written isn't worth the trouble, + // simply distinguish between ok and error + return fputs(buf, stream) == -1 ? -1 : 0; +} +#endif // wxNEED_FPUTS + +#ifdef wxNEED_PUTS +int wxPuts(const wxChar *ws) +{ + int rc = wxFputs(ws, stdout); + if ( rc != -1 ) + { + if ( wxFputs(L"\n", stdout) == -1 ) + return -1; + + rc++; + } + + return rc; +} +#endif // wxNEED_PUTS + +#ifdef wxNEED_PUTC +int /* not wint_t */ wxPutc(wchar_t wc, FILE *stream) +{ + wchar_t ws[2] = { wc, L'\0' }; + + return wxFputs(ws, stream); +} +#endif // wxNEED_PUTC + +// NB: we only implement va_list functions here, the ones taking ... are +// defined below for wxNEED_PRINTF_CONVERSION case anyhow and we reuse +// the definitions there to avoid duplicating them here +#ifdef wxNEED_WPRINTF + +// TODO: implement the scanf() functions +int vwscanf(const wxChar *format, va_list argptr) +{ + wxFAIL_MSG( _T("TODO") ); + + return -1; +} + +int vswscanf(const wxChar *ws, const wxChar *format, va_list argptr) +{ + // The best we can do without proper Unicode support in glibc is to + // convert the strings into MB representation and run ANSI version + // of the function. This doesn't work with %c and %s because of difference + // in size of char and wchar_t, though. + + wxCHECK_MSG( wxStrstr(format, _T("%s")) == NULL, -1, + _T("incomplete vswscanf implementation doesn't allow %s") ); + wxCHECK_MSG( wxStrstr(format, _T("%c")) == NULL, -1, + _T("incomplete vswscanf implementation doesn't allow %c") ); + + va_list argcopy; + wxVaCopy(argcopy, argptr); + return vsscanf(wxConvLibc.cWX2MB(ws), wxConvLibc.cWX2MB(format), argcopy); +} + +int vfwscanf(FILE *stream, const wxChar *format, va_list argptr) +{ + wxFAIL_MSG( _T("TODO") ); + + return -1; +} + +#define vswprintf wxVsnprintf_ + +int vfwprintf(FILE *stream, const wxChar *format, va_list argptr) +{ + wxString s; + int rc = s.PrintfV(format, argptr); + + if ( rc != -1 ) + { + // we can't do much better without Unicode support in libc... + if ( fprintf(stream, "%s", (const char*)s.mb_str() ) == -1 ) + return -1; + } + + return rc; +} + +int vwprintf(const wxChar *format, va_list argptr) +{ + return wxVfprintf(stdout, format, argptr); +} + +#endif // wxNEED_WPRINTF + +#ifdef wxNEED_PRINTF_CONVERSION + +// ---------------------------------------------------------------------------- +// wxFormatConverter: class doing the "%s" -> "%ls" conversion +// ---------------------------------------------------------------------------- + +/* + Here are the gory details. We want to follow the Windows/MS conventions, + that is to have + + In ANSI mode: + + format specifier results in + ----------------------------------- + %c, %hc, %hC char + %lc, %C, %lC wchar_t + + In Unicode mode: + + format specifier results in + ----------------------------------- + %hc, %C, %hC char + %c, %lc, %lC wchar_t + + + while on POSIX systems we have %C identical to %lc and %c always means char + (in any mode) while %lc always means wchar_t, + + So to use native functions in order to get our semantics we must do the + following translations in Unicode mode (nothing to do in ANSI mode): + + wxWidgets specifier POSIX specifier + ---------------------------------------- + + %hc, %C, %hC %c + %c %lc + + + And, of course, the same should be done for %s as well. +*/ + +class wxFormatConverter +{ +public: + wxFormatConverter(const wxChar *format); + + // notice that we only translated the string if m_fmtOrig == NULL (as set + // by CopyAllBefore()), otherwise we should simply use the original format + operator const wxChar *() const + { return m_fmtOrig ? m_fmtOrig : m_fmt.c_str(); } + +private: + // copy another character to the translated format: this function does the + // copy if we are translating but doesn't do anything at all if we don't, + // so we don't create the translated format string at all unless we really + // need to (i.e. InsertFmtChar() is called) + wxChar CopyFmtChar(wxChar ch) + { + if ( !m_fmtOrig ) + { + // we're translating, do copy + m_fmt += ch; + } + else + { + // simply increase the count which should be copied by + // CopyAllBefore() later if needed + m_nCopied++; + } + + return ch; + } + + // insert an extra character + void InsertFmtChar(wxChar ch) + { + if ( m_fmtOrig ) + { + // so far we haven't translated anything yet + CopyAllBefore(); + } + + m_fmt += ch; + } + + void CopyAllBefore() + { + wxASSERT_MSG( m_fmtOrig && m_fmt.empty(), _T("logic error") ); + + m_fmt = wxString(m_fmtOrig, m_nCopied); + + // we won't need it any longer + m_fmtOrig = NULL; + } + + static bool IsFlagChar(wxChar ch) + { + return ch == _T('-') || ch == _T('+') || + ch == _T('0') || ch == _T(' ') || ch == _T('#'); + } + + void SkipDigits(const wxChar **ptpc) + { + while ( **ptpc >= _T('0') && **ptpc <= _T('9') ) + CopyFmtChar(*(*ptpc)++); + } + + // the translated format + wxString m_fmt; + + // the original format + const wxChar *m_fmtOrig; + + // the number of characters already copied + size_t m_nCopied; +}; + +wxFormatConverter::wxFormatConverter(const wxChar *format) +{ + m_fmtOrig = format; + m_nCopied = 0; + + while ( *format ) + { + if ( CopyFmtChar(*format++) == _T('%') ) + { + // skip any flags + while ( IsFlagChar(*format) ) + CopyFmtChar(*format++); + + // and possible width + if ( *format == _T('*') ) + CopyFmtChar(*format++); + else + SkipDigits(&format); + + // precision? + if ( *format == _T('.') ) + { + CopyFmtChar(*format++); + if ( *format == _T('*') ) + CopyFmtChar(*format++); + else + SkipDigits(&format); + } + + // next we can have a size modifier + enum + { + Default, + Short, + Long + } size; + + switch ( *format ) + { + case _T('h'): + size = Short; + format++; + break; + + case _T('l'): + // "ll" has a different meaning! + if ( format[1] != _T('l') ) + { + size = Long; + format++; + break; + } + //else: fall through + + default: + size = Default; + } + + // and finally we should have the type + switch ( *format ) + { + case _T('C'): + case _T('S'): + // %C and %hC -> %c and %lC -> %lc + if ( size == Long ) + CopyFmtChar(_T('l')); + + InsertFmtChar(*format++ == _T('C') ? _T('c') : _T('s')); + break; + + case _T('c'): + case _T('s'): + // %c -> %lc but %hc stays %hc and %lc is still %lc + if ( size == Default) + InsertFmtChar(_T('l')); + // fall through + + default: + // nothing special to do + if ( size != Default ) + CopyFmtChar(*(format - 1)); + CopyFmtChar(*format++); + } + } + } +} + +#else // !wxNEED_PRINTF_CONVERSION + // no conversion necessary + #define wxFormatConverter(x) (x) +#endif // wxNEED_PRINTF_CONVERSION/!wxNEED_PRINTF_CONVERSION + +#ifdef __WXDEBUG__ +// For testing the format converter +wxString wxConvertFormat(const wxChar *format) +{ + return wxString(wxFormatConverter(format)); +} +#endif + +// ---------------------------------------------------------------------------- +// wxPrintf(), wxScanf() and relatives +// ---------------------------------------------------------------------------- + +#if defined(wxNEED_PRINTF_CONVERSION) || defined(wxNEED_WPRINTF) + +int wxScanf( const wxChar *format, ... ) +{ + va_list argptr; + va_start(argptr, format); + + int ret = vwscanf(wxFormatConverter(format), argptr ); + + va_end(argptr); + + return ret; +} + +int wxSscanf( const wxChar *str, const wxChar *format, ... ) +{ + va_list argptr; + va_start(argptr, format); + + int ret = vswscanf( str, wxFormatConverter(format), argptr ); + + va_end(argptr); + + return ret; +} + +int wxFscanf( FILE *stream, const wxChar *format, ... ) +{ + va_list argptr; + va_start(argptr, format); + int ret = vfwscanf(stream, wxFormatConverter(format), argptr); + + va_end(argptr); + + return ret; +} + +int wxPrintf( const wxChar *format, ... ) +{ + va_list argptr; + va_start(argptr, format); + + int ret = vwprintf( wxFormatConverter(format), argptr ); + + va_end(argptr); + + return ret; +} + +#ifndef wxSnprintf +int wxSnprintf( wxChar *str, size_t size, const wxChar *format, ... ) +{ + va_list argptr; + va_start(argptr, format); + + int ret = vswprintf( str, size, wxFormatConverter(format), argptr ); + + // VsnprintfTestCase reveals that glibc's implementation of vswprintf + // doesn't nul terminate on truncation. + str[size - 1] = 0; + + va_end(argptr); + + return ret; +} +#endif // wxSnprintf + +int wxSprintf( wxChar *str, const wxChar *format, ... ) +{ + va_list argptr; + va_start(argptr, format); + + // note that wxString::FormatV() uses wxVsnprintf(), not wxSprintf(), so + // it's safe to implement this one in terms of it + wxString s(wxString::FormatV(format, argptr)); + wxStrcpy(str, s); + + va_end(argptr); + + return s.length(); +} + +int wxFprintf( FILE *stream, const wxChar *format, ... ) +{ + va_list argptr; + va_start( argptr, format ); + + int ret = vfwprintf( stream, wxFormatConverter(format), argptr ); + + va_end(argptr); + + return ret; +} + +int wxVsscanf( const wxChar *str, const wxChar *format, va_list argptr ) +{ + return vswscanf( str, wxFormatConverter(format), argptr ); +} + +int wxVfprintf( FILE *stream, const wxChar *format, va_list argptr ) +{ + return vfwprintf( stream, wxFormatConverter(format), argptr ); +} + +int wxVprintf( const wxChar *format, va_list argptr ) +{ + return vwprintf( wxFormatConverter(format), argptr ); +} + +#ifndef wxVsnprintf +int wxVsnprintf( wxChar *str, size_t size, const wxChar *format, va_list argptr ) +{ + return vswprintf( str, size, wxFormatConverter(format), argptr ); +} +#endif // wxVsnprintf + +int wxVsprintf( wxChar *str, const wxChar *format, va_list argptr ) +{ + // same as for wxSprintf() + return vswprintf(str, INT_MAX / 4, wxFormatConverter(format), argptr); +} + +#endif // wxNEED_PRINTF_CONVERSION + +#if wxUSE_WCHAR_T + +// ---------------------------------------------------------------------------- +// ctype.h stuff (currently unused) +// ---------------------------------------------------------------------------- + +#if defined(__WIN32__) && defined(wxNEED_WX_CTYPE_H) +inline WORD wxMSW_ctype(wxChar ch) +{ + WORD ret; + GetStringTypeEx(LOCALE_USER_DEFAULT, CT_CTYPE1, &ch, 1, &ret); + return ret; +} + +WXDLLEXPORT int wxIsalnum(wxChar ch) { return IsCharAlphaNumeric(ch); } +WXDLLEXPORT int wxIsalpha(wxChar ch) { return IsCharAlpha(ch); } +WXDLLEXPORT int wxIscntrl(wxChar ch) { return wxMSW_ctype(ch) & C1_CNTRL; } +WXDLLEXPORT int wxIsdigit(wxChar ch) { return wxMSW_ctype(ch) & C1_DIGIT; } +WXDLLEXPORT int wxIsgraph(wxChar ch) { return wxMSW_ctype(ch) & (C1_DIGIT|C1_PUNCT|C1_ALPHA); } +WXDLLEXPORT int wxIslower(wxChar ch) { return IsCharLower(ch); } +WXDLLEXPORT int wxIsprint(wxChar ch) { return wxMSW_ctype(ch) & (C1_DIGIT|C1_SPACE|C1_PUNCT|C1_ALPHA); } +WXDLLEXPORT int wxIspunct(wxChar ch) { return wxMSW_ctype(ch) & C1_PUNCT; } +WXDLLEXPORT int wxIsspace(wxChar ch) { return wxMSW_ctype(ch) & C1_SPACE; } +WXDLLEXPORT int wxIsupper(wxChar ch) { return IsCharUpper(ch); } +WXDLLEXPORT int wxIsxdigit(wxChar ch) { return wxMSW_ctype(ch) & C1_XDIGIT; } +WXDLLEXPORT int wxTolower(wxChar ch) { return (wxChar)CharLower((LPTSTR)(ch)); } +WXDLLEXPORT int wxToupper(wxChar ch) { return (wxChar)CharUpper((LPTSTR)(ch)); } +#endif + +#ifdef wxNEED_WX_MBSTOWCS + +WXDLLEXPORT size_t wxMbstowcs (wchar_t * out, const char * in, size_t outlen) +{ + if (!out) + { + size_t outsize = 0; + while(*in++) + outsize++; + return outsize; + } + + const char* origin = in; + + while (outlen-- && *in) + { + *out++ = (wchar_t) *in++; + } + + *out = '\0'; + + return in - origin; +} + +WXDLLEXPORT size_t wxWcstombs (char * out, const wchar_t * in, size_t outlen) +{ + if (!out) + { + size_t outsize = 0; + while(*in++) + outsize++; + return outsize; + } + + const wchar_t* origin = in; + + while (outlen-- && *in) + { + *out++ = (char) *in++; + } + + *out = '\0'; + + return in - origin; +} + +#endif // wxNEED_WX_MBSTOWCS + +#if defined(wxNEED_WX_CTYPE_H) + +#include + +#define cfalnumset CFCharacterSetGetPredefined(kCFCharacterSetAlphaNumeric) +#define cfalphaset CFCharacterSetGetPredefined(kCFCharacterSetLetter) +#define cfcntrlset CFCharacterSetGetPredefined(kCFCharacterSetControl) +#define cfdigitset CFCharacterSetGetPredefined(kCFCharacterSetDecimalDigit) +//CFCharacterSetRef cfgraphset = kCFCharacterSetControl && !' ' +#define cflowerset CFCharacterSetGetPredefined(kCFCharacterSetLowercaseLetter) +//CFCharacterSetRef cfprintset = !kCFCharacterSetControl +#define cfpunctset CFCharacterSetGetPredefined(kCFCharacterSetPunctuation) +#define cfspaceset CFCharacterSetGetPredefined(kCFCharacterSetWhitespaceAndNewline) +#define cfupperset CFCharacterSetGetPredefined(kCFCharacterSetUppercaseLetter) + +WXDLLEXPORT int wxIsalnum(wxChar ch) { return CFCharacterSetIsCharacterMember(cfalnumset, ch); } +WXDLLEXPORT int wxIsalpha(wxChar ch) { return CFCharacterSetIsCharacterMember(cfalphaset, ch); } +WXDLLEXPORT int wxIscntrl(wxChar ch) { return CFCharacterSetIsCharacterMember(cfcntrlset, ch); } +WXDLLEXPORT int wxIsdigit(wxChar ch) { return CFCharacterSetIsCharacterMember(cfdigitset, ch); } +WXDLLEXPORT int wxIsgraph(wxChar ch) { return !CFCharacterSetIsCharacterMember(cfcntrlset, ch) && ch != ' '; } +WXDLLEXPORT int wxIslower(wxChar ch) { return CFCharacterSetIsCharacterMember(cflowerset, ch); } +WXDLLEXPORT int wxIsprint(wxChar ch) { return !CFCharacterSetIsCharacterMember(cfcntrlset, ch); } +WXDLLEXPORT int wxIspunct(wxChar ch) { return CFCharacterSetIsCharacterMember(cfpunctset, ch); } +WXDLLEXPORT int wxIsspace(wxChar ch) { return CFCharacterSetIsCharacterMember(cfspaceset, ch); } +WXDLLEXPORT int wxIsupper(wxChar ch) { return CFCharacterSetIsCharacterMember(cfupperset, ch); } +WXDLLEXPORT int wxIsxdigit(wxChar ch) { return wxIsdigit(ch) || (ch>='a' && ch<='f') || (ch>='A' && ch<='F'); } +WXDLLEXPORT int wxTolower(wxChar ch) { return (wxChar)tolower((char)(ch)); } +WXDLLEXPORT int wxToupper(wxChar ch) { return (wxChar)toupper((char)(ch)); } + +#endif // wxNEED_WX_CTYPE_H + +#ifndef wxStrdupA + +WXDLLEXPORT char *wxStrdupA(const char *s) +{ + return strcpy((char *)malloc(strlen(s) + 1), s); +} + +#endif // wxStrdupA + +#ifndef wxStrdupW + +WXDLLEXPORT wchar_t * wxStrdupW(const wchar_t *pwz) +{ + size_t size = (wxWcslen(pwz) + 1) * sizeof(wchar_t); + wchar_t *ret = (wchar_t *) malloc(size); + memcpy(ret, pwz, size); + return ret; +} + +#endif // wxStrdupW + +#ifndef wxStricmp +int WXDLLEXPORT wxStricmp(const wxChar *psz1, const wxChar *psz2) +{ + register wxChar c1, c2; + do { + c1 = wxTolower(*psz1++); + c2 = wxTolower(*psz2++); + } while ( c1 && (c1 == c2) ); + return c1 - c2; +} +#endif + +#ifndef wxStricmp +int WXDLLEXPORT wxStrnicmp(const wxChar *s1, const wxChar *s2, size_t n) +{ + // initialize the variables just to suppress stupid gcc warning + register wxChar c1 = 0, c2 = 0; + while (n && ((c1 = wxTolower(*s1)) == (c2 = wxTolower(*s2)) ) && c1) n--, s1++, s2++; + if (n) { + if (c1 < c2) return -1; + if (c1 > c2) return 1; + } + return 0; +} +#endif + +#ifndef wxSetlocale +WXDLLEXPORT wxWCharBuffer wxSetlocale(int category, const wxChar *locale) +{ + char *localeOld = setlocale(category, wxConvLibc.cWX2MB(locale)); + + return wxWCharBuffer(wxConvLibc.cMB2WC(localeOld)); +} +#endif + +#if wxUSE_WCHAR_T && !defined(HAVE_WCSLEN) +WXDLLEXPORT size_t wxWcslen(const wchar_t *s) +{ + size_t n = 0; + while ( *s++ ) + n++; + + return n; +} +#endif + +// ---------------------------------------------------------------------------- +// string.h functions +// ---------------------------------------------------------------------------- + +#ifdef wxNEED_WX_STRING_H + +// RN: These need to be c externed for the regex lib +#ifdef __cplusplus +extern "C" { +#endif + +WXDLLEXPORT wxChar * wxStrcat(wxChar *dest, const wxChar *src) +{ + wxChar *ret = dest; + while (*dest) dest++; + while ((*dest++ = *src++)); + return ret; +} + +WXDLLEXPORT const wxChar * wxStrchr(const wxChar *s, wxChar c) +{ + // be careful here as the terminating NUL makes part of the string + while ( *s != c ) + { + if ( !*s++ ) + return NULL; + } + + return s; +} + +WXDLLEXPORT int wxStrcmp(const wxChar *s1, const wxChar *s2) +{ + while ((*s1 == *s2) && *s1) s1++, s2++; + if ((wxUChar)*s1 < (wxUChar)*s2) return -1; + if ((wxUChar)*s1 > (wxUChar)*s2) return 1; + return 0; +} + +WXDLLEXPORT wxChar * wxStrcpy(wxChar *dest, const wxChar *src) +{ + wxChar *ret = dest; + while ((*dest++ = *src++)); + return ret; +} + +WXDLLEXPORT size_t wxStrlen_(const wxChar *s) +{ + size_t n = 0; + while ( *s++ ) + n++; + + return n; +} + + +WXDLLEXPORT wxChar * wxStrncat(wxChar *dest, const wxChar *src, size_t n) +{ + wxChar *ret = dest; + while (*dest) dest++; + while (n && (*dest++ = *src++)) n--; + return ret; +} + +WXDLLEXPORT int wxStrncmp(const wxChar *s1, const wxChar *s2, size_t n) +{ + while (n && (*s1 == *s2) && *s1) n--, s1++, s2++; + if (n) { + if ((wxUChar)*s1 < (wxUChar)*s2) return -1; + if ((wxUChar)*s1 > (wxUChar)*s2) return 1; + } + return 0; +} + +WXDLLEXPORT wxChar * wxStrncpy(wxChar *dest, const wxChar *src, size_t n) +{ + wxChar *ret = dest; + while (n && (*dest++ = *src++)) n--; + while (n) *dest++=0, n--; // the docs specify padding with zeroes + return ret; +} + +WXDLLEXPORT const wxChar * wxStrpbrk(const wxChar *s, const wxChar *accept) +{ + while (*s && !wxStrchr(accept, *s)) + s++; + + return *s ? s : NULL; +} + +WXDLLEXPORT const wxChar * wxStrrchr(const wxChar *s, wxChar c) +{ + const wxChar *ret = NULL; + do + { + if ( *s == c ) + ret = s; + s++; + } + while ( *s ); + + return ret; +} + +WXDLLEXPORT size_t wxStrspn(const wxChar *s, const wxChar *accept) +{ + size_t len = 0; + while (wxStrchr(accept, *s++)) len++; + return len; +} + +WXDLLEXPORT const wxChar *wxStrstr(const wxChar *haystack, const wxChar *needle) +{ + wxASSERT_MSG( needle != NULL, _T("NULL argument in wxStrstr") ); + + // VZ: this is not exactly the most efficient string search algorithm... + + const size_t len = wxStrlen(needle); + + while ( const wxChar *fnd = wxStrchr(haystack, *needle) ) + { + if ( !wxStrncmp(fnd, needle, len) ) + return fnd; + + haystack = fnd + 1; + } + + return NULL; +} + +#ifdef __cplusplus +} +#endif + +WXDLLEXPORT double wxStrtod(const wxChar *nptr, wxChar **endptr) +{ + const wxChar decSep( +#if wxUSE_INTL + wxLocale::GetInfo(wxLOCALE_DECIMAL_POINT, wxLOCALE_CAT_NUMBER)[0] +#else + _T('.') +#endif + ); + const wxChar *start = nptr; + + while (wxIsspace(*nptr)) nptr++; + if (*nptr == wxT('+') || *nptr == wxT('-')) nptr++; + while (wxIsdigit(*nptr)) nptr++; + if (*nptr == decSep) { + nptr++; + while (wxIsdigit(*nptr)) nptr++; + } + if (*nptr == wxT('E') || *nptr == wxT('e')) { + nptr++; + if (*nptr == wxT('+') || *nptr == wxT('-')) nptr++; + while (wxIsdigit(*nptr)) nptr++; + } + + wxString data(start, nptr-start); + const wxWX2MBbuf dat = data.mb_str(wxConvLibc); + char *rdat = wxMBSTRINGCAST dat; + double ret = strtod(dat, &rdat); + + if (endptr) *endptr = (wxChar *)(start + (rdat - (const char *)dat)); + + return ret; +} + +WXDLLEXPORT long int wxStrtol(const wxChar *nptr, wxChar **endptr, int base) +{ + const wxChar *start = nptr; + + while (wxIsspace(*nptr)) nptr++; + if (*nptr == wxT('+') || *nptr == wxT('-')) nptr++; + if (((base == 0) || (base == 16)) && + (nptr[0] == wxT('0') && nptr[1] == wxT('x'))) { + nptr += 2; + base = 16; + } + else if ((base == 0) && (nptr[0] == wxT('0'))) base = 8; + else if (base == 0) base = 10; + + while ((wxIsdigit(*nptr) && (*nptr - wxT('0') < base)) || + (wxIsalpha(*nptr) && (wxToupper(*nptr) - wxT('A') + 10 < base))) nptr++; + + wxString data(start, nptr-start); + wxWX2MBbuf dat = data.mb_str(wxConvLibc); + char *rdat = wxMBSTRINGCAST dat; + long int ret = strtol(dat, &rdat, base); + + if (endptr) *endptr = (wxChar *)(start + (rdat - (const char *)dat)); + + return ret; +} + +WXDLLEXPORT unsigned long int wxStrtoul(const wxChar *nptr, wxChar **endptr, int base) +{ + return (unsigned long int) wxStrtol(nptr, endptr, base); +} + +#endif // wxNEED_WX_STRING_H + +#ifdef wxNEED_WX_STDIO_H +WXDLLEXPORT FILE * wxFopen(const wxChar *path, const wxChar *mode) +{ + char mode_buffer[10]; + for (size_t i = 0; i < wxStrlen(mode)+1; i++) + mode_buffer[i] = (char) mode[i]; + + return fopen( wxConvFile.cWX2MB(path), mode_buffer ); +} + +WXDLLEXPORT FILE * wxFreopen(const wxChar *path, const wxChar *mode, FILE *stream) +{ + char mode_buffer[10]; + for (size_t i = 0; i < wxStrlen(mode)+1; i++) + mode_buffer[i] = (char) mode[i]; + + return freopen( wxConvFile.cWX2MB(path), mode_buffer, stream ); +} + +WXDLLEXPORT int wxRemove(const wxChar *path) +{ + return remove( wxConvFile.cWX2MB(path) ); +} + +WXDLLEXPORT int wxRename(const wxChar *oldpath, const wxChar *newpath) +{ + return rename( wxConvFile.cWX2MB(oldpath), wxConvFile.cWX2MB(newpath) ); +} +#endif + +#ifndef wxAtof +double WXDLLEXPORT wxAtof(const wxChar *psz) +{ +#ifdef __WXWINCE__ + double d; + wxString str(psz); + if (str.ToDouble(& d)) + return d; + + return 0.0; +#else + return atof(wxConvLibc.cWX2MB(psz)); +#endif +} +#endif + +#ifdef wxNEED_WX_STDLIB_H +int WXDLLEXPORT wxAtoi(const wxChar *psz) +{ + return atoi(wxConvLibc.cWX2MB(psz)); +} + +long WXDLLEXPORT wxAtol(const wxChar *psz) +{ + return atol(wxConvLibc.cWX2MB(psz)); +} + +wxChar * WXDLLEXPORT wxGetenv(const wxChar *name) +{ +#if wxUSE_UNICODE + // NB: buffer returned by getenv() is allowed to be overwritten next + // time getenv() is called, so it is OK to use static string + // buffer to hold the data. + static wxWCharBuffer value((wxChar*)NULL); + value = wxConvLibc.cMB2WX(getenv(wxConvLibc.cWX2MB(name))); + return value.data(); +#else + return getenv(name); +#endif +} +#endif // wxNEED_WX_STDLIB_H + +#ifdef wxNEED_WXSYSTEM +int WXDLLEXPORT wxSystem(const wxChar *psz) +{ + return system(wxConvLibc.cWX2MB(psz)); +} +#endif // wxNEED_WXSYSTEM + +#ifdef wxNEED_WX_TIME_H +WXDLLEXPORT size_t +wxStrftime(wxChar *s, size_t maxsize, const wxChar *fmt, const struct tm *tm) +{ + if ( !maxsize ) + return 0; + + wxCharBuffer buf(maxsize); + + wxCharBuffer bufFmt(wxConvLibc.cWX2MB(fmt)); + if ( !bufFmt ) + return 0; + + size_t ret = strftime(buf.data(), maxsize, bufFmt, tm); + if ( !ret ) + return 0; + + wxWCharBuffer wbuf = wxConvLibc.cMB2WX(buf); + if ( !wbuf ) + return 0; + + wxStrncpy(s, wbuf, maxsize); + return wxStrlen(s); +} +#endif // wxNEED_WX_TIME_H + +#ifndef wxCtime +WXDLLEXPORT wxChar *wxCtime(const time_t *timep) +{ + // normally the string is 26 chars but give one more in case some broken + // DOS compiler decides to use "\r\n" instead of "\n" at the end + static wxChar buf[27]; + + // ctime() is guaranteed to return a string containing only ASCII + // characters, as its format is always the same for any locale + wxStrncpy(buf, wxString::FromAscii(ctime(timep)), WXSIZEOF(buf)); + buf[WXSIZEOF(buf) - 1] = _T('\0'); + + return buf; +} +#endif // wxCtime + +#endif // wxUSE_WCHAR_T + +// ---------------------------------------------------------------------------- +// functions which we may need even if !wxUSE_WCHAR_T +// ---------------------------------------------------------------------------- + +#ifndef wxStrtok + +WXDLLEXPORT wxChar * wxStrtok(wxChar *psz, const wxChar *delim, wxChar **save_ptr) +{ + if (!psz) + { + psz = *save_ptr; + if ( !psz ) + return NULL; + } + + psz += wxStrspn(psz, delim); + if (!*psz) + { + *save_ptr = (wxChar *)NULL; + return (wxChar *)NULL; + } + + wxChar *ret = psz; + psz = wxStrpbrk(psz, delim); + if (!psz) + { + *save_ptr = (wxChar*)NULL; + } + else + { + *psz = wxT('\0'); + *save_ptr = psz + 1; + } + + return ret; +} + +#endif // wxStrtok + +// ---------------------------------------------------------------------------- +// missing C RTL functions +// ---------------------------------------------------------------------------- + +#ifdef wxNEED_STRDUP + +char *strdup(const char *s) +{ + char *dest = (char*) malloc( strlen( s ) + 1 ) ; + if ( dest ) + strcpy( dest , s ) ; + return dest ; +} +#endif // wxNEED_STRDUP + +#if defined(__WXWINCE__) && (_WIN32_WCE <= 211) + +void *calloc( size_t num, size_t size ) +{ + void** ptr = (void **)malloc(num * size); + memset( ptr, 0, num * size); + return ptr; +} + +#endif // __WXWINCE__ <= 211 + +#ifdef __WXWINCE__ + +int wxRemove(const wxChar *path) +{ + return ::DeleteFile(path) == 0; +} + +#endif diff --git a/Externals/wxWidgets/src/common/xpmdecod.cpp b/Externals/wxWidgets/src/common/xpmdecod.cpp index 813fbf017f..2d98dd8750 100644 --- a/Externals/wxWidgets/src/common/xpmdecod.cpp +++ b/Externals/wxWidgets/src/common/xpmdecod.cpp @@ -1,814 +1,814 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/xpmdecod.cpp -// Purpose: wxXPMDecoder -// Author: John Cristy, Vaclav Slavik -// RCS-ID: $Id: xpmdecod.cpp 41689 2006-10-08 08:04:49Z PC $ -// Copyright: (c) John Cristy, Vaclav Slavik -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -/* - -This file is partially based on source code of ImageMagick by John Cristy. Its -license is as follows: - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% % -% % -% % -% X X PPPP M M % -% X X P P MM MM % -% X PPPP M M M % -% X X P M M % -% X X P M M % -% % -% % -% Read/Write ImageMagick Image Format. % -% % -% % -% Software Design % -% John Cristy % -% July 1992 % -% % -% % -% Copyright (C) 2001 ImageMagick Studio, a non-profit organization dedicated % -% to making software imaging solutions freely available. % -% % -% Permission is hereby granted, free of charge, to any person obtaining a % -% copy of this software and associated documentation files ("ImageMagick"), % -% to deal in ImageMagick without restriction, including without limitation % -% the rights to use, copy, modify, merge, publish, distribute, sublicense, % -% and/or sell copies of ImageMagick, and to permit persons to whom the % -% ImageMagick is furnished to do so, subject to the following conditions: % -% % -% The above copyright notice and this permission notice shall be included in % -% all copies or substantial portions of ImageMagick. % -% % -% The software is provided "as is", without warranty of any kind, express or % -% implied, including but not limited to the warranties of merchantability, % -% fitness for a particular purpose and noninfringement. In no event shall % -% ImageMagick Studio be liable for any claim, damages or other liability, % -% whether in an action of contract, tort or otherwise, arising from, out of % -% or in connection with ImageMagick or the use or other dealings in % -% ImageMagick. % -% % -% Except as contained in this notice, the name of the ImageMagick Studio % -% shall not be used in advertising or otherwise to promote the sale, use or % -% other dealings in ImageMagick without prior written authorization from the % -% ImageMagick Studio. % -% % -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% -% -*/ - -/* - * Also contains some pieces from libxpm and its modification for win32 by - * HeDu : - * - * Copyright (C) 1989-95 GROUPE BULL - * - * 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 - * GROUPE BULL 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. - * - * Except as contained in this notice, the name of GROUPE BULL shall not be - * used in advertising or otherwise to promote the sale, use or other dealings - * in this Software without prior written authorization from GROUPE BULL. - */ - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_IMAGE && wxUSE_XPM - -#include "wx/xpmdecod.h" - -#ifndef WX_PRECOMP - #include "wx/intl.h" - #include "wx/log.h" - #include "wx/utils.h" - #include "wx/hashmap.h" - #include "wx/stream.h" - #include "wx/image.h" -#endif - -#include -#include - -#if wxUSE_STREAMS -bool wxXPMDecoder::CanRead(wxInputStream& stream) -{ - unsigned char buf[9]; - - if ( !stream.Read(buf, WXSIZEOF(buf)) ) - return false; - - stream.SeekI(-(wxFileOffset)WXSIZEOF(buf), wxFromCurrent); - - return memcmp(buf, "/* XPM */", WXSIZEOF(buf)) == 0; -} - -wxImage wxXPMDecoder::ReadFile(wxInputStream& stream) -{ - size_t length = stream.GetSize(); - wxCHECK_MSG( length != 0, wxNullImage, - wxT("Cannot read XPM from stream of unknown size") ); - - // use a smart buffer to be sure to free memory even when we return on - // error - wxCharBuffer buffer(length); - - char *xpm_buffer = (char *)buffer.data(); - if ( stream.Read(xpm_buffer, length).GetLastError() == wxSTREAM_READ_ERROR ) - return wxNullImage; - xpm_buffer[length] = '\0'; - - /* - * Remove comments from the file: - */ - char *p, *q; - for (p = xpm_buffer; *p != '\0'; p++) - { - if ( (*p == '"') || (*p == '\'') ) - { - if (*p == '"') - { - for (p++; *p != '\0'; p++) - if ( (*p == '"') && (*(p - 1) != '\\') ) - break; - } - else // *p == '\'' - { - for (p++; *p != '\0'; p++) - if ( (*p == '\'') && (*(p - 1) != '\\') ) - break; - } - if (*p == '\0') - break; - continue; - } - if ( (*p != '/') || (*(p + 1) != '*') ) - continue; - for (q = p + 2; *q != '\0'; q++) - { - if ( (*q == '*') && (*(q + 1) == '/') ) - break; - } - - // memmove allows overlaps (unlike strcpy): - size_t cpylen = strlen(q + 2) + 1; - memmove(p, q + 2, cpylen); - } - - /* - * Remove unquoted characters: - */ - size_t i = 0; - for (p = xpm_buffer; *p != '\0'; p++) - { - if ( *p != '"' ) - continue; - for (q = p + 1; *q != '\0'; q++) - if (*q == '"') - break; - strncpy(xpm_buffer + i, p + 1, q - p - 1); - i += q - p - 1; - xpm_buffer[i++] = '\n'; - p = q + 1; - } - xpm_buffer[i] = '\0'; - - /* - * Create array of lines and convert \n's to \0's: - */ - const char **xpm_lines; - size_t lines_cnt = 0; - size_t line; - - for (p = xpm_buffer; *p != '\0'; p++) - { - if ( *p == '\n' ) - lines_cnt++; - } - - if ( !lines_cnt ) - { - // this doesn't really look an XPM image - return wxNullImage; - } - - xpm_lines = new const char*[lines_cnt + 1]; - xpm_lines[0] = xpm_buffer; - line = 1; - for (p = xpm_buffer; (*p != '\0') && (line < lines_cnt); p++) - { - if ( *p == '\n' ) - { - xpm_lines[line] = p + 1; - *p = '\0'; - line++; - } - } - - xpm_lines[lines_cnt] = NULL; - - /* - * Read the image: - */ - wxImage img = ReadData(xpm_lines); - - delete[] xpm_lines; - - return img; -} -#endif // wxUSE_STREAMS - - -/*****************************************************************************\ -* rgbtab.h * -* * -* A hard coded rgb.txt. To keep it short I removed all colornames with * -* trailing numbers, Blue3 etc, except the GrayXX. Sorry Grey-lovers I prefer * -* Gray ;-). But Grey is recognized on lookups, only on save Gray will be * -* used, maybe you want to do some substitue there too. * -* * -* To save memory the RGBs are coded in one long value, as done by the RGB * -* macro. * -* * -* Developed by HeDu 3/94 (hedu@cul-ipn.uni-kiel.de) * -\*****************************************************************************/ - - -typedef struct -{ - const char *name; - wxUint32 rgb; -} rgbRecord; - -#define myRGB(r,g,b) ((wxUint32)r<<16|(wxUint32)g<<8|(wxUint32)b) - -static rgbRecord theRGBRecords[] = -{ - {"aliceblue", myRGB(240, 248, 255)}, - {"antiquewhite", myRGB(250, 235, 215)}, - {"aquamarine", myRGB(50, 191, 193)}, - {"azure", myRGB(240, 255, 255)}, - {"beige", myRGB(245, 245, 220)}, - {"bisque", myRGB(255, 228, 196)}, - {"black", myRGB(0, 0, 0)}, - {"blanchedalmond", myRGB(255, 235, 205)}, - {"blue", myRGB(0, 0, 255)}, - {"blueviolet", myRGB(138, 43, 226)}, - {"brown", myRGB(165, 42, 42)}, - {"burlywood", myRGB(222, 184, 135)}, - {"cadetblue", myRGB(95, 146, 158)}, - {"chartreuse", myRGB(127, 255, 0)}, - {"chocolate", myRGB(210, 105, 30)}, - {"coral", myRGB(255, 114, 86)}, - {"cornflowerblue", myRGB(34, 34, 152)}, - {"cornsilk", myRGB(255, 248, 220)}, - {"cyan", myRGB(0, 255, 255)}, - {"darkgoldenrod", myRGB(184, 134, 11)}, - {"darkgreen", myRGB(0, 86, 45)}, - {"darkkhaki", myRGB(189, 183, 107)}, - {"darkolivegreen", myRGB(85, 86, 47)}, - {"darkorange", myRGB(255, 140, 0)}, - {"darkorchid", myRGB(139, 32, 139)}, - {"darksalmon", myRGB(233, 150, 122)}, - {"darkseagreen", myRGB(143, 188, 143)}, - {"darkslateblue", myRGB(56, 75, 102)}, - {"darkslategray", myRGB(47, 79, 79)}, - {"darkturquoise", myRGB(0, 166, 166)}, - {"darkviolet", myRGB(148, 0, 211)}, - {"deeppink", myRGB(255, 20, 147)}, - {"deepskyblue", myRGB(0, 191, 255)}, - {"dimgray", myRGB(84, 84, 84)}, - {"dodgerblue", myRGB(30, 144, 255)}, - {"firebrick", myRGB(142, 35, 35)}, - {"floralwhite", myRGB(255, 250, 240)}, - {"forestgreen", myRGB(80, 159, 105)}, - {"gainsboro", myRGB(220, 220, 220)}, - {"ghostwhite", myRGB(248, 248, 255)}, - {"gold", myRGB(218, 170, 0)}, - {"goldenrod", myRGB(239, 223, 132)}, - {"gray", myRGB(126, 126, 126)}, - {"gray0", myRGB(0, 0, 0)}, - {"gray1", myRGB(3, 3, 3)}, - {"gray10", myRGB(26, 26, 26)}, - {"gray100", myRGB(255, 255, 255)}, - {"gray11", myRGB(28, 28, 28)}, - {"gray12", myRGB(31, 31, 31)}, - {"gray13", myRGB(33, 33, 33)}, - {"gray14", myRGB(36, 36, 36)}, - {"gray15", myRGB(38, 38, 38)}, - {"gray16", myRGB(41, 41, 41)}, - {"gray17", myRGB(43, 43, 43)}, - {"gray18", myRGB(46, 46, 46)}, - {"gray19", myRGB(48, 48, 48)}, - {"gray2", myRGB(5, 5, 5)}, - {"gray20", myRGB(51, 51, 51)}, - {"gray21", myRGB(54, 54, 54)}, - {"gray22", myRGB(56, 56, 56)}, - {"gray23", myRGB(59, 59, 59)}, - {"gray24", myRGB(61, 61, 61)}, - {"gray25", myRGB(64, 64, 64)}, - {"gray26", myRGB(66, 66, 66)}, - {"gray27", myRGB(69, 69, 69)}, - {"gray28", myRGB(71, 71, 71)}, - {"gray29", myRGB(74, 74, 74)}, - {"gray3", myRGB(8, 8, 8)}, - {"gray30", myRGB(77, 77, 77)}, - {"gray31", myRGB(79, 79, 79)}, - {"gray32", myRGB(82, 82, 82)}, - {"gray33", myRGB(84, 84, 84)}, - {"gray34", myRGB(87, 87, 87)}, - {"gray35", myRGB(89, 89, 89)}, - {"gray36", myRGB(92, 92, 92)}, - {"gray37", myRGB(94, 94, 94)}, - {"gray38", myRGB(97, 97, 97)}, - {"gray39", myRGB(99, 99, 99)}, - {"gray4", myRGB(10, 10, 10)}, - {"gray40", myRGB(102, 102, 102)}, - {"gray41", myRGB(105, 105, 105)}, - {"gray42", myRGB(107, 107, 107)}, - {"gray43", myRGB(110, 110, 110)}, - {"gray44", myRGB(112, 112, 112)}, - {"gray45", myRGB(115, 115, 115)}, - {"gray46", myRGB(117, 117, 117)}, - {"gray47", myRGB(120, 120, 120)}, - {"gray48", myRGB(122, 122, 122)}, - {"gray49", myRGB(125, 125, 125)}, - {"gray5", myRGB(13, 13, 13)}, - {"gray50", myRGB(127, 127, 127)}, - {"gray51", myRGB(130, 130, 130)}, - {"gray52", myRGB(133, 133, 133)}, - {"gray53", myRGB(135, 135, 135)}, - {"gray54", myRGB(138, 138, 138)}, - {"gray55", myRGB(140, 140, 140)}, - {"gray56", myRGB(143, 143, 143)}, - {"gray57", myRGB(145, 145, 145)}, - {"gray58", myRGB(148, 148, 148)}, - {"gray59", myRGB(150, 150, 150)}, - {"gray6", myRGB(15, 15, 15)}, - {"gray60", myRGB(153, 153, 153)}, - {"gray61", myRGB(156, 156, 156)}, - {"gray62", myRGB(158, 158, 158)}, - {"gray63", myRGB(161, 161, 161)}, - {"gray64", myRGB(163, 163, 163)}, - {"gray65", myRGB(166, 166, 166)}, - {"gray66", myRGB(168, 168, 168)}, - {"gray67", myRGB(171, 171, 171)}, - {"gray68", myRGB(173, 173, 173)}, - {"gray69", myRGB(176, 176, 176)}, - {"gray7", myRGB(18, 18, 18)}, - {"gray70", myRGB(179, 179, 179)}, - {"gray71", myRGB(181, 181, 181)}, - {"gray72", myRGB(184, 184, 184)}, - {"gray73", myRGB(186, 186, 186)}, - {"gray74", myRGB(189, 189, 189)}, - {"gray75", myRGB(191, 191, 191)}, - {"gray76", myRGB(194, 194, 194)}, - {"gray77", myRGB(196, 196, 196)}, - {"gray78", myRGB(199, 199, 199)}, - {"gray79", myRGB(201, 201, 201)}, - {"gray8", myRGB(20, 20, 20)}, - {"gray80", myRGB(204, 204, 204)}, - {"gray81", myRGB(207, 207, 207)}, - {"gray82", myRGB(209, 209, 209)}, - {"gray83", myRGB(212, 212, 212)}, - {"gray84", myRGB(214, 214, 214)}, - {"gray85", myRGB(217, 217, 217)}, - {"gray86", myRGB(219, 219, 219)}, - {"gray87", myRGB(222, 222, 222)}, - {"gray88", myRGB(224, 224, 224)}, - {"gray89", myRGB(227, 227, 227)}, - {"gray9", myRGB(23, 23, 23)}, - {"gray90", myRGB(229, 229, 229)}, - {"gray91", myRGB(232, 232, 232)}, - {"gray92", myRGB(235, 235, 235)}, - {"gray93", myRGB(237, 237, 237)}, - {"gray94", myRGB(240, 240, 240)}, - {"gray95", myRGB(242, 242, 242)}, - {"gray96", myRGB(245, 245, 245)}, - {"gray97", myRGB(247, 247, 247)}, - {"gray98", myRGB(250, 250, 250)}, - {"gray99", myRGB(252, 252, 252)}, - {"green", myRGB(0, 255, 0)}, - {"greenyellow", myRGB(173, 255, 47)}, - {"honeydew", myRGB(240, 255, 240)}, - {"hotpink", myRGB(255, 105, 180)}, - {"indianred", myRGB(107, 57, 57)}, - {"ivory", myRGB(255, 255, 240)}, - {"khaki", myRGB(179, 179, 126)}, - {"lavender", myRGB(230, 230, 250)}, - {"lavenderblush", myRGB(255, 240, 245)}, - {"lawngreen", myRGB(124, 252, 0)}, - {"lemonchiffon", myRGB(255, 250, 205)}, - {"lightblue", myRGB(176, 226, 255)}, - {"lightcoral", myRGB(240, 128, 128)}, - {"lightcyan", myRGB(224, 255, 255)}, - {"lightgoldenrod", myRGB(238, 221, 130)}, - {"lightgoldenrodyellow", myRGB(250, 250, 210)}, - {"lightgray", myRGB(168, 168, 168)}, - {"lightpink", myRGB(255, 182, 193)}, - {"lightsalmon", myRGB(255, 160, 122)}, - {"lightseagreen", myRGB(32, 178, 170)}, - {"lightskyblue", myRGB(135, 206, 250)}, - {"lightslateblue", myRGB(132, 112, 255)}, - {"lightslategray", myRGB(119, 136, 153)}, - {"lightsteelblue", myRGB(124, 152, 211)}, - {"lightyellow", myRGB(255, 255, 224)}, - {"limegreen", myRGB(0, 175, 20)}, - {"linen", myRGB(250, 240, 230)}, - {"magenta", myRGB(255, 0, 255)}, - {"maroon", myRGB(143, 0, 82)}, - {"mediumaquamarine", myRGB(0, 147, 143)}, - {"mediumblue", myRGB(50, 50, 204)}, - {"mediumforestgreen", myRGB(50, 129, 75)}, - {"mediumgoldenrod", myRGB(209, 193, 102)}, - {"mediumorchid", myRGB(189, 82, 189)}, - {"mediumpurple", myRGB(147, 112, 219)}, - {"mediumseagreen", myRGB(52, 119, 102)}, - {"mediumslateblue", myRGB(106, 106, 141)}, - {"mediumspringgreen", myRGB(35, 142, 35)}, - {"mediumturquoise", myRGB(0, 210, 210)}, - {"mediumvioletred", myRGB(213, 32, 121)}, - {"midnightblue", myRGB(47, 47, 100)}, - {"mintcream", myRGB(245, 255, 250)}, - {"mistyrose", myRGB(255, 228, 225)}, - {"moccasin", myRGB(255, 228, 181)}, - {"navajowhite", myRGB(255, 222, 173)}, - {"navy", myRGB(35, 35, 117)}, - {"navyblue", myRGB(35, 35, 117)}, - {"oldlace", myRGB(253, 245, 230)}, - {"olivedrab", myRGB(107, 142, 35)}, - {"orange", myRGB(255, 135, 0)}, - {"orangered", myRGB(255, 69, 0)}, - {"orchid", myRGB(239, 132, 239)}, - {"palegoldenrod", myRGB(238, 232, 170)}, - {"palegreen", myRGB(115, 222, 120)}, - {"paleturquoise", myRGB(175, 238, 238)}, - {"palevioletred", myRGB(219, 112, 147)}, - {"papayawhip", myRGB(255, 239, 213)}, - {"peachpuff", myRGB(255, 218, 185)}, - {"peru", myRGB(205, 133, 63)}, - {"pink", myRGB(255, 181, 197)}, - {"plum", myRGB(197, 72, 155)}, - {"powderblue", myRGB(176, 224, 230)}, - {"purple", myRGB(160, 32, 240)}, - {"red", myRGB(255, 0, 0)}, - {"rosybrown", myRGB(188, 143, 143)}, - {"royalblue", myRGB(65, 105, 225)}, - {"saddlebrown", myRGB(139, 69, 19)}, - {"salmon", myRGB(233, 150, 122)}, - {"sandybrown", myRGB(244, 164, 96)}, - {"seagreen", myRGB(82, 149, 132)}, - {"seashell", myRGB(255, 245, 238)}, - {"sienna", myRGB(150, 82, 45)}, - {"silver", myRGB(192, 192, 192)}, - {"skyblue", myRGB(114, 159, 255)}, - {"slateblue", myRGB(126, 136, 171)}, - {"slategray", myRGB(112, 128, 144)}, - {"snow", myRGB(255, 250, 250)}, - {"springgreen", myRGB(65, 172, 65)}, - {"steelblue", myRGB(84, 112, 170)}, - {"tan", myRGB(222, 184, 135)}, - {"thistle", myRGB(216, 191, 216)}, - {"tomato", myRGB(255, 99, 71)}, - {"transparent", myRGB(0, 0, 1)}, - {"turquoise", myRGB(25, 204, 223)}, - {"violet", myRGB(156, 62, 206)}, - {"violetred", myRGB(243, 62, 150)}, - {"wheat", myRGB(245, 222, 179)}, - {"white", myRGB(255, 255, 255)}, - {"whitesmoke", myRGB(245, 245, 245)}, - {"yellow", myRGB(255, 255, 0)}, - {"yellowgreen", myRGB(50, 216, 56)}, - {NULL, myRGB(0, 0, 0)} -}; -static int numTheRGBRecords = 235; - -static unsigned char ParseHexadecimal(char digit1, char digit2) -{ - unsigned char i1, i2; - - if (digit1 >= 'a') - i1 = (unsigned char)(digit1 - 'a' + 0x0A); - else if (digit1 >= 'A') - i1 = (unsigned char)(digit1 - 'A' + 0x0A); - else - i1 = (unsigned char)(digit1 - '0'); - if (digit2 >= 'a') - i2 = (unsigned char)(digit2 - 'a' + 0x0A); - else if (digit2 >= 'A') - i2 = (unsigned char)(digit2 - 'A' + 0x0A); - else - i2 = (unsigned char)(digit2 - '0'); - return (unsigned char)(0x10 * i1 + i2); -} - -static bool GetRGBFromName(const char *inname, bool *isNone, - unsigned char *r, unsigned char*g, unsigned char *b) -{ - int left, right, middle; - int cmp; - wxUint32 rgbVal; - char *name; - char *grey, *p; - - // Neither #rrggbb nor #rrrrggggbbbb are in database, we parse them directly - size_t inname_len = strlen(inname); - if ( *inname == '#' && (inname_len == 7 || inname_len == 13)) - { - size_t ofs = (inname_len == 7) ? 2 : 4; - *r = ParseHexadecimal(inname[1], inname[2]); - *g = ParseHexadecimal(inname[1*ofs+1], inname[1*ofs+2]); - *b = ParseHexadecimal(inname[2*ofs+1], inname[2*ofs+2]); - *isNone = false; - return true; - } - - name = wxStrdupA(inname); - - // theRGBRecords[] has no names with spaces, and no grey, but a - // lot of gray... - - // so first extract ' ' - while ((p = strchr(name, ' ')) != NULL) - { - while (*(p)) // till eof of string - { - *p = *(p + 1); // copy to the left - p++; - } - } - // fold to lower case - p = name; - while (*p) - { - *p = (char)tolower(*p); - p++; - } - - // substitute Grey with Gray, else rgbtab.h would have more than 100 - // 'duplicate' entries - if ( (grey = strstr(name, "grey")) != NULL ) - grey[2] = 'a'; - - // check for special 'none' colour: - bool found; - if ( strcmp(name, "none") == 0 ) - { - *isNone = true; - found = true; - } - else // not "None" - { - found = false; - - // binary search: - left = 0; - right = numTheRGBRecords - 1; - do - { - middle = (left + right) / 2; - cmp = strcmp(name, theRGBRecords[middle].name); - if ( cmp == 0 ) - { - rgbVal = theRGBRecords[middle].rgb; - *r = (unsigned char)((rgbVal >> 16) & 0xFF); - *g = (unsigned char)((rgbVal >> 8) & 0xFF); - *b = (unsigned char)((rgbVal) & 0xFF); - *isNone = false; - found = true; - break; - } - else if ( cmp < 0 ) - { - right = middle - 1; - } - else // cmp > 0 - { - left = middle + 1; - } - } while (left <= right); - } - - free(name); - - return found; -} - -static const char *ParseColor(const char *data) -{ - static const char *targets[] = - {"c ", "g ", "g4 ", "m ", "b ", "s ", NULL}; - - const char *p, *r; - const char *q; - int i; - - for (i = 0; targets[i] != NULL; i++) - { - r = data; - for (q = targets[i]; *r != '\0'; r++) - { - if ( *r != *q ) - continue; - if ( !isspace((int) (*(r - 1))) ) - continue; - p = r; - for (;;) - { - if ( *q == '\0' ) - return p; - if ( *p++ != *q++ ) - break; - } - q = targets[i]; - } - } - return NULL; -} - -struct wxXPMColourMapData -{ - wxXPMColourMapData() { R = G = B = 0; } - unsigned char R,G,B; -}; -WX_DECLARE_STRING_HASH_MAP(wxXPMColourMapData, wxXPMColourMap); - -wxImage wxXPMDecoder::ReadData(const char* const* xpm_data) -{ - wxCHECK_MSG(xpm_data, wxNullImage, wxT("NULL XPM data") ); - - wxImage img; - int count; - unsigned width, height, colors_cnt, chars_per_pixel; - size_t i, j, i_key; - wxChar key[64]; - const char *clr_def; - bool hasMask; - wxXPMColourMap clr_tbl; - wxXPMColourMap::iterator it; - wxString maskKey; - - /* - * Read hints and initialize structures: - */ - - count = sscanf(xpm_data[0], "%u %u %u %u", - &width, &height, &colors_cnt, &chars_per_pixel); - if ( count != 4 || width * height * colors_cnt == 0 ) - { - wxLogError(_("XPM: incorrect header format!")); - return wxNullImage; - } - - // VS: XPM color map this large would be insane, since XPMs are encoded with - // 92 possible values on each position, 92^64 is *way* larger space than - // 8bit RGB... - wxCHECK_MSG(chars_per_pixel < 64, wxNullImage, wxT("XPM colormaps this large not supported.")); - - if ( !img.Create(width, height) ) - return wxNullImage; - - img.SetMask(false); - key[chars_per_pixel] = wxT('\0'); - hasMask = false; - - /* - * Create colour map: - */ - wxXPMColourMapData clr_data; - for (i = 0; i < colors_cnt; i++) - { - const char *xmpColLine = xpm_data[1 + i]; - - // we must have at least " x y" after the colour index, hence +5 - if ( !xmpColLine || strlen(xmpColLine) < chars_per_pixel + 5 ) - { - wxLogError(_("XPM: incorrect colour description in line %d"), - (int)(1 + i)); - return wxNullImage; - } - - for (i_key = 0; i_key < chars_per_pixel; i_key++) - key[i_key] = (wxChar)xmpColLine[i_key]; - clr_def = ParseColor(xmpColLine + chars_per_pixel); - - if ( clr_def == NULL ) - { - wxLogError(_("XPM: malformed colour definition '%s' at line %d!"), - xmpColLine, (int)(1 + i)); - return wxNullImage; - } - - bool isNone = false; - if ( !GetRGBFromName(clr_def, &isNone, - &clr_data.R, &clr_data.G, &clr_data.B) ) - { - wxLogError(_("XPM: malformed colour definition '%s' at line %d!"), - xmpColLine, (int)(1 + i)); - return wxNullImage; - } - - if ( isNone ) - { - img.SetMask(true); - img.SetMaskColour(255, 0, 255); - clr_data.R = - clr_data.B = 255; - clr_data.G = 0; - hasMask = true; - maskKey = key; - } - - clr_tbl[key] = clr_data; - } - - /* - * Modify colour entries with RGB = (255,0,255) to (255,0,254) if - * mask colour is present (so that existing pixels with (255,0,255) - * magenta colour are not incorrectly made transparent): - */ - if (hasMask) - { - for (it = clr_tbl.begin(); it != clr_tbl.end(); ++it) - { - if (it->second.R == 255 && it->second.G == 0 && - it->second.B == 255 && - it->first != maskKey) - { - it->second.B = 254; - } - } - } - - /* - * Parse image data: - */ - - unsigned char *img_data = img.GetData(); - wxXPMColourMap::iterator entry; - wxXPMColourMap::iterator end = clr_tbl.end(); - - for (j = 0; j < height; j++) - { - for (i = 0; i < width; i++, img_data += 3) - { - const char *xpmImgLine = xpm_data[1 + colors_cnt + j]; - if ( !xpmImgLine || strlen(xpmImgLine) < width*chars_per_pixel ) - { - wxLogError(_("XPM: truncated image data at line %d!"), - (int)(1 + colors_cnt + j)); - return wxNullImage; - } - - for (i_key = 0; i_key < chars_per_pixel; i_key++) - { - key[i_key] = (wxChar)xpmImgLine[chars_per_pixel * i + i_key]; - } - - entry = clr_tbl.find(key); - if ( entry == end ) - { - wxLogError(_("XPM: Malformed pixel data!")); - - // better return right now as otherwise we risk to flood the - // user with error messages as something seems to be seriously - // wrong with the file and so we could give this message for - // each remaining pixel if we don't bail out - return wxNullImage; - } - else - { - img_data[0] = entry->second.R; - img_data[1] = entry->second.G; - img_data[2] = entry->second.B; - } - } - } - - return img; -} - -#endif // wxUSE_IMAGE && wxUSE_XPM +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/xpmdecod.cpp +// Purpose: wxXPMDecoder +// Author: John Cristy, Vaclav Slavik +// RCS-ID: $Id: xpmdecod.cpp 41689 2006-10-08 08:04:49Z PC $ +// Copyright: (c) John Cristy, Vaclav Slavik +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +/* + +This file is partially based on source code of ImageMagick by John Cristy. Its +license is as follows: + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% % +% % +% % +% X X PPPP M M % +% X X P P MM MM % +% X PPPP M M M % +% X X P M M % +% X X P M M % +% % +% % +% Read/Write ImageMagick Image Format. % +% % +% % +% Software Design % +% John Cristy % +% July 1992 % +% % +% % +% Copyright (C) 2001 ImageMagick Studio, a non-profit organization dedicated % +% to making software imaging solutions freely available. % +% % +% Permission is hereby granted, free of charge, to any person obtaining a % +% copy of this software and associated documentation files ("ImageMagick"), % +% to deal in ImageMagick without restriction, including without limitation % +% the rights to use, copy, modify, merge, publish, distribute, sublicense, % +% and/or sell copies of ImageMagick, and to permit persons to whom the % +% ImageMagick is furnished to do so, subject to the following conditions: % +% % +% The above copyright notice and this permission notice shall be included in % +% all copies or substantial portions of ImageMagick. % +% % +% The software is provided "as is", without warranty of any kind, express or % +% implied, including but not limited to the warranties of merchantability, % +% fitness for a particular purpose and noninfringement. In no event shall % +% ImageMagick Studio be liable for any claim, damages or other liability, % +% whether in an action of contract, tort or otherwise, arising from, out of % +% or in connection with ImageMagick or the use or other dealings in % +% ImageMagick. % +% % +% Except as contained in this notice, the name of the ImageMagick Studio % +% shall not be used in advertising or otherwise to promote the sale, use or % +% other dealings in ImageMagick without prior written authorization from the % +% ImageMagick Studio. % +% % +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% +*/ + +/* + * Also contains some pieces from libxpm and its modification for win32 by + * HeDu : + * + * Copyright (C) 1989-95 GROUPE BULL + * + * 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 + * GROUPE BULL 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. + * + * Except as contained in this notice, the name of GROUPE BULL shall not be + * used in advertising or otherwise to promote the sale, use or other dealings + * in this Software without prior written authorization from GROUPE BULL. + */ + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_IMAGE && wxUSE_XPM + +#include "wx/xpmdecod.h" + +#ifndef WX_PRECOMP + #include "wx/intl.h" + #include "wx/log.h" + #include "wx/utils.h" + #include "wx/hashmap.h" + #include "wx/stream.h" + #include "wx/image.h" +#endif + +#include +#include + +#if wxUSE_STREAMS +bool wxXPMDecoder::CanRead(wxInputStream& stream) +{ + unsigned char buf[9]; + + if ( !stream.Read(buf, WXSIZEOF(buf)) ) + return false; + + stream.SeekI(-(wxFileOffset)WXSIZEOF(buf), wxFromCurrent); + + return memcmp(buf, "/* XPM */", WXSIZEOF(buf)) == 0; +} + +wxImage wxXPMDecoder::ReadFile(wxInputStream& stream) +{ + size_t length = stream.GetSize(); + wxCHECK_MSG( length != 0, wxNullImage, + wxT("Cannot read XPM from stream of unknown size") ); + + // use a smart buffer to be sure to free memory even when we return on + // error + wxCharBuffer buffer(length); + + char *xpm_buffer = (char *)buffer.data(); + if ( stream.Read(xpm_buffer, length).GetLastError() == wxSTREAM_READ_ERROR ) + return wxNullImage; + xpm_buffer[length] = '\0'; + + /* + * Remove comments from the file: + */ + char *p, *q; + for (p = xpm_buffer; *p != '\0'; p++) + { + if ( (*p == '"') || (*p == '\'') ) + { + if (*p == '"') + { + for (p++; *p != '\0'; p++) + if ( (*p == '"') && (*(p - 1) != '\\') ) + break; + } + else // *p == '\'' + { + for (p++; *p != '\0'; p++) + if ( (*p == '\'') && (*(p - 1) != '\\') ) + break; + } + if (*p == '\0') + break; + continue; + } + if ( (*p != '/') || (*(p + 1) != '*') ) + continue; + for (q = p + 2; *q != '\0'; q++) + { + if ( (*q == '*') && (*(q + 1) == '/') ) + break; + } + + // memmove allows overlaps (unlike strcpy): + size_t cpylen = strlen(q + 2) + 1; + memmove(p, q + 2, cpylen); + } + + /* + * Remove unquoted characters: + */ + size_t i = 0; + for (p = xpm_buffer; *p != '\0'; p++) + { + if ( *p != '"' ) + continue; + for (q = p + 1; *q != '\0'; q++) + if (*q == '"') + break; + strncpy(xpm_buffer + i, p + 1, q - p - 1); + i += q - p - 1; + xpm_buffer[i++] = '\n'; + p = q + 1; + } + xpm_buffer[i] = '\0'; + + /* + * Create array of lines and convert \n's to \0's: + */ + const char **xpm_lines; + size_t lines_cnt = 0; + size_t line; + + for (p = xpm_buffer; *p != '\0'; p++) + { + if ( *p == '\n' ) + lines_cnt++; + } + + if ( !lines_cnt ) + { + // this doesn't really look an XPM image + return wxNullImage; + } + + xpm_lines = new const char*[lines_cnt + 1]; + xpm_lines[0] = xpm_buffer; + line = 1; + for (p = xpm_buffer; (*p != '\0') && (line < lines_cnt); p++) + { + if ( *p == '\n' ) + { + xpm_lines[line] = p + 1; + *p = '\0'; + line++; + } + } + + xpm_lines[lines_cnt] = NULL; + + /* + * Read the image: + */ + wxImage img = ReadData(xpm_lines); + + delete[] xpm_lines; + + return img; +} +#endif // wxUSE_STREAMS + + +/*****************************************************************************\ +* rgbtab.h * +* * +* A hard coded rgb.txt. To keep it short I removed all colornames with * +* trailing numbers, Blue3 etc, except the GrayXX. Sorry Grey-lovers I prefer * +* Gray ;-). But Grey is recognized on lookups, only on save Gray will be * +* used, maybe you want to do some substitue there too. * +* * +* To save memory the RGBs are coded in one long value, as done by the RGB * +* macro. * +* * +* Developed by HeDu 3/94 (hedu@cul-ipn.uni-kiel.de) * +\*****************************************************************************/ + + +typedef struct +{ + const char *name; + wxUint32 rgb; +} rgbRecord; + +#define myRGB(r,g,b) ((wxUint32)r<<16|(wxUint32)g<<8|(wxUint32)b) + +static rgbRecord theRGBRecords[] = +{ + {"aliceblue", myRGB(240, 248, 255)}, + {"antiquewhite", myRGB(250, 235, 215)}, + {"aquamarine", myRGB(50, 191, 193)}, + {"azure", myRGB(240, 255, 255)}, + {"beige", myRGB(245, 245, 220)}, + {"bisque", myRGB(255, 228, 196)}, + {"black", myRGB(0, 0, 0)}, + {"blanchedalmond", myRGB(255, 235, 205)}, + {"blue", myRGB(0, 0, 255)}, + {"blueviolet", myRGB(138, 43, 226)}, + {"brown", myRGB(165, 42, 42)}, + {"burlywood", myRGB(222, 184, 135)}, + {"cadetblue", myRGB(95, 146, 158)}, + {"chartreuse", myRGB(127, 255, 0)}, + {"chocolate", myRGB(210, 105, 30)}, + {"coral", myRGB(255, 114, 86)}, + {"cornflowerblue", myRGB(34, 34, 152)}, + {"cornsilk", myRGB(255, 248, 220)}, + {"cyan", myRGB(0, 255, 255)}, + {"darkgoldenrod", myRGB(184, 134, 11)}, + {"darkgreen", myRGB(0, 86, 45)}, + {"darkkhaki", myRGB(189, 183, 107)}, + {"darkolivegreen", myRGB(85, 86, 47)}, + {"darkorange", myRGB(255, 140, 0)}, + {"darkorchid", myRGB(139, 32, 139)}, + {"darksalmon", myRGB(233, 150, 122)}, + {"darkseagreen", myRGB(143, 188, 143)}, + {"darkslateblue", myRGB(56, 75, 102)}, + {"darkslategray", myRGB(47, 79, 79)}, + {"darkturquoise", myRGB(0, 166, 166)}, + {"darkviolet", myRGB(148, 0, 211)}, + {"deeppink", myRGB(255, 20, 147)}, + {"deepskyblue", myRGB(0, 191, 255)}, + {"dimgray", myRGB(84, 84, 84)}, + {"dodgerblue", myRGB(30, 144, 255)}, + {"firebrick", myRGB(142, 35, 35)}, + {"floralwhite", myRGB(255, 250, 240)}, + {"forestgreen", myRGB(80, 159, 105)}, + {"gainsboro", myRGB(220, 220, 220)}, + {"ghostwhite", myRGB(248, 248, 255)}, + {"gold", myRGB(218, 170, 0)}, + {"goldenrod", myRGB(239, 223, 132)}, + {"gray", myRGB(126, 126, 126)}, + {"gray0", myRGB(0, 0, 0)}, + {"gray1", myRGB(3, 3, 3)}, + {"gray10", myRGB(26, 26, 26)}, + {"gray100", myRGB(255, 255, 255)}, + {"gray11", myRGB(28, 28, 28)}, + {"gray12", myRGB(31, 31, 31)}, + {"gray13", myRGB(33, 33, 33)}, + {"gray14", myRGB(36, 36, 36)}, + {"gray15", myRGB(38, 38, 38)}, + {"gray16", myRGB(41, 41, 41)}, + {"gray17", myRGB(43, 43, 43)}, + {"gray18", myRGB(46, 46, 46)}, + {"gray19", myRGB(48, 48, 48)}, + {"gray2", myRGB(5, 5, 5)}, + {"gray20", myRGB(51, 51, 51)}, + {"gray21", myRGB(54, 54, 54)}, + {"gray22", myRGB(56, 56, 56)}, + {"gray23", myRGB(59, 59, 59)}, + {"gray24", myRGB(61, 61, 61)}, + {"gray25", myRGB(64, 64, 64)}, + {"gray26", myRGB(66, 66, 66)}, + {"gray27", myRGB(69, 69, 69)}, + {"gray28", myRGB(71, 71, 71)}, + {"gray29", myRGB(74, 74, 74)}, + {"gray3", myRGB(8, 8, 8)}, + {"gray30", myRGB(77, 77, 77)}, + {"gray31", myRGB(79, 79, 79)}, + {"gray32", myRGB(82, 82, 82)}, + {"gray33", myRGB(84, 84, 84)}, + {"gray34", myRGB(87, 87, 87)}, + {"gray35", myRGB(89, 89, 89)}, + {"gray36", myRGB(92, 92, 92)}, + {"gray37", myRGB(94, 94, 94)}, + {"gray38", myRGB(97, 97, 97)}, + {"gray39", myRGB(99, 99, 99)}, + {"gray4", myRGB(10, 10, 10)}, + {"gray40", myRGB(102, 102, 102)}, + {"gray41", myRGB(105, 105, 105)}, + {"gray42", myRGB(107, 107, 107)}, + {"gray43", myRGB(110, 110, 110)}, + {"gray44", myRGB(112, 112, 112)}, + {"gray45", myRGB(115, 115, 115)}, + {"gray46", myRGB(117, 117, 117)}, + {"gray47", myRGB(120, 120, 120)}, + {"gray48", myRGB(122, 122, 122)}, + {"gray49", myRGB(125, 125, 125)}, + {"gray5", myRGB(13, 13, 13)}, + {"gray50", myRGB(127, 127, 127)}, + {"gray51", myRGB(130, 130, 130)}, + {"gray52", myRGB(133, 133, 133)}, + {"gray53", myRGB(135, 135, 135)}, + {"gray54", myRGB(138, 138, 138)}, + {"gray55", myRGB(140, 140, 140)}, + {"gray56", myRGB(143, 143, 143)}, + {"gray57", myRGB(145, 145, 145)}, + {"gray58", myRGB(148, 148, 148)}, + {"gray59", myRGB(150, 150, 150)}, + {"gray6", myRGB(15, 15, 15)}, + {"gray60", myRGB(153, 153, 153)}, + {"gray61", myRGB(156, 156, 156)}, + {"gray62", myRGB(158, 158, 158)}, + {"gray63", myRGB(161, 161, 161)}, + {"gray64", myRGB(163, 163, 163)}, + {"gray65", myRGB(166, 166, 166)}, + {"gray66", myRGB(168, 168, 168)}, + {"gray67", myRGB(171, 171, 171)}, + {"gray68", myRGB(173, 173, 173)}, + {"gray69", myRGB(176, 176, 176)}, + {"gray7", myRGB(18, 18, 18)}, + {"gray70", myRGB(179, 179, 179)}, + {"gray71", myRGB(181, 181, 181)}, + {"gray72", myRGB(184, 184, 184)}, + {"gray73", myRGB(186, 186, 186)}, + {"gray74", myRGB(189, 189, 189)}, + {"gray75", myRGB(191, 191, 191)}, + {"gray76", myRGB(194, 194, 194)}, + {"gray77", myRGB(196, 196, 196)}, + {"gray78", myRGB(199, 199, 199)}, + {"gray79", myRGB(201, 201, 201)}, + {"gray8", myRGB(20, 20, 20)}, + {"gray80", myRGB(204, 204, 204)}, + {"gray81", myRGB(207, 207, 207)}, + {"gray82", myRGB(209, 209, 209)}, + {"gray83", myRGB(212, 212, 212)}, + {"gray84", myRGB(214, 214, 214)}, + {"gray85", myRGB(217, 217, 217)}, + {"gray86", myRGB(219, 219, 219)}, + {"gray87", myRGB(222, 222, 222)}, + {"gray88", myRGB(224, 224, 224)}, + {"gray89", myRGB(227, 227, 227)}, + {"gray9", myRGB(23, 23, 23)}, + {"gray90", myRGB(229, 229, 229)}, + {"gray91", myRGB(232, 232, 232)}, + {"gray92", myRGB(235, 235, 235)}, + {"gray93", myRGB(237, 237, 237)}, + {"gray94", myRGB(240, 240, 240)}, + {"gray95", myRGB(242, 242, 242)}, + {"gray96", myRGB(245, 245, 245)}, + {"gray97", myRGB(247, 247, 247)}, + {"gray98", myRGB(250, 250, 250)}, + {"gray99", myRGB(252, 252, 252)}, + {"green", myRGB(0, 255, 0)}, + {"greenyellow", myRGB(173, 255, 47)}, + {"honeydew", myRGB(240, 255, 240)}, + {"hotpink", myRGB(255, 105, 180)}, + {"indianred", myRGB(107, 57, 57)}, + {"ivory", myRGB(255, 255, 240)}, + {"khaki", myRGB(179, 179, 126)}, + {"lavender", myRGB(230, 230, 250)}, + {"lavenderblush", myRGB(255, 240, 245)}, + {"lawngreen", myRGB(124, 252, 0)}, + {"lemonchiffon", myRGB(255, 250, 205)}, + {"lightblue", myRGB(176, 226, 255)}, + {"lightcoral", myRGB(240, 128, 128)}, + {"lightcyan", myRGB(224, 255, 255)}, + {"lightgoldenrod", myRGB(238, 221, 130)}, + {"lightgoldenrodyellow", myRGB(250, 250, 210)}, + {"lightgray", myRGB(168, 168, 168)}, + {"lightpink", myRGB(255, 182, 193)}, + {"lightsalmon", myRGB(255, 160, 122)}, + {"lightseagreen", myRGB(32, 178, 170)}, + {"lightskyblue", myRGB(135, 206, 250)}, + {"lightslateblue", myRGB(132, 112, 255)}, + {"lightslategray", myRGB(119, 136, 153)}, + {"lightsteelblue", myRGB(124, 152, 211)}, + {"lightyellow", myRGB(255, 255, 224)}, + {"limegreen", myRGB(0, 175, 20)}, + {"linen", myRGB(250, 240, 230)}, + {"magenta", myRGB(255, 0, 255)}, + {"maroon", myRGB(143, 0, 82)}, + {"mediumaquamarine", myRGB(0, 147, 143)}, + {"mediumblue", myRGB(50, 50, 204)}, + {"mediumforestgreen", myRGB(50, 129, 75)}, + {"mediumgoldenrod", myRGB(209, 193, 102)}, + {"mediumorchid", myRGB(189, 82, 189)}, + {"mediumpurple", myRGB(147, 112, 219)}, + {"mediumseagreen", myRGB(52, 119, 102)}, + {"mediumslateblue", myRGB(106, 106, 141)}, + {"mediumspringgreen", myRGB(35, 142, 35)}, + {"mediumturquoise", myRGB(0, 210, 210)}, + {"mediumvioletred", myRGB(213, 32, 121)}, + {"midnightblue", myRGB(47, 47, 100)}, + {"mintcream", myRGB(245, 255, 250)}, + {"mistyrose", myRGB(255, 228, 225)}, + {"moccasin", myRGB(255, 228, 181)}, + {"navajowhite", myRGB(255, 222, 173)}, + {"navy", myRGB(35, 35, 117)}, + {"navyblue", myRGB(35, 35, 117)}, + {"oldlace", myRGB(253, 245, 230)}, + {"olivedrab", myRGB(107, 142, 35)}, + {"orange", myRGB(255, 135, 0)}, + {"orangered", myRGB(255, 69, 0)}, + {"orchid", myRGB(239, 132, 239)}, + {"palegoldenrod", myRGB(238, 232, 170)}, + {"palegreen", myRGB(115, 222, 120)}, + {"paleturquoise", myRGB(175, 238, 238)}, + {"palevioletred", myRGB(219, 112, 147)}, + {"papayawhip", myRGB(255, 239, 213)}, + {"peachpuff", myRGB(255, 218, 185)}, + {"peru", myRGB(205, 133, 63)}, + {"pink", myRGB(255, 181, 197)}, + {"plum", myRGB(197, 72, 155)}, + {"powderblue", myRGB(176, 224, 230)}, + {"purple", myRGB(160, 32, 240)}, + {"red", myRGB(255, 0, 0)}, + {"rosybrown", myRGB(188, 143, 143)}, + {"royalblue", myRGB(65, 105, 225)}, + {"saddlebrown", myRGB(139, 69, 19)}, + {"salmon", myRGB(233, 150, 122)}, + {"sandybrown", myRGB(244, 164, 96)}, + {"seagreen", myRGB(82, 149, 132)}, + {"seashell", myRGB(255, 245, 238)}, + {"sienna", myRGB(150, 82, 45)}, + {"silver", myRGB(192, 192, 192)}, + {"skyblue", myRGB(114, 159, 255)}, + {"slateblue", myRGB(126, 136, 171)}, + {"slategray", myRGB(112, 128, 144)}, + {"snow", myRGB(255, 250, 250)}, + {"springgreen", myRGB(65, 172, 65)}, + {"steelblue", myRGB(84, 112, 170)}, + {"tan", myRGB(222, 184, 135)}, + {"thistle", myRGB(216, 191, 216)}, + {"tomato", myRGB(255, 99, 71)}, + {"transparent", myRGB(0, 0, 1)}, + {"turquoise", myRGB(25, 204, 223)}, + {"violet", myRGB(156, 62, 206)}, + {"violetred", myRGB(243, 62, 150)}, + {"wheat", myRGB(245, 222, 179)}, + {"white", myRGB(255, 255, 255)}, + {"whitesmoke", myRGB(245, 245, 245)}, + {"yellow", myRGB(255, 255, 0)}, + {"yellowgreen", myRGB(50, 216, 56)}, + {NULL, myRGB(0, 0, 0)} +}; +static int numTheRGBRecords = 235; + +static unsigned char ParseHexadecimal(char digit1, char digit2) +{ + unsigned char i1, i2; + + if (digit1 >= 'a') + i1 = (unsigned char)(digit1 - 'a' + 0x0A); + else if (digit1 >= 'A') + i1 = (unsigned char)(digit1 - 'A' + 0x0A); + else + i1 = (unsigned char)(digit1 - '0'); + if (digit2 >= 'a') + i2 = (unsigned char)(digit2 - 'a' + 0x0A); + else if (digit2 >= 'A') + i2 = (unsigned char)(digit2 - 'A' + 0x0A); + else + i2 = (unsigned char)(digit2 - '0'); + return (unsigned char)(0x10 * i1 + i2); +} + +static bool GetRGBFromName(const char *inname, bool *isNone, + unsigned char *r, unsigned char*g, unsigned char *b) +{ + int left, right, middle; + int cmp; + wxUint32 rgbVal; + char *name; + char *grey, *p; + + // Neither #rrggbb nor #rrrrggggbbbb are in database, we parse them directly + size_t inname_len = strlen(inname); + if ( *inname == '#' && (inname_len == 7 || inname_len == 13)) + { + size_t ofs = (inname_len == 7) ? 2 : 4; + *r = ParseHexadecimal(inname[1], inname[2]); + *g = ParseHexadecimal(inname[1*ofs+1], inname[1*ofs+2]); + *b = ParseHexadecimal(inname[2*ofs+1], inname[2*ofs+2]); + *isNone = false; + return true; + } + + name = wxStrdupA(inname); + + // theRGBRecords[] has no names with spaces, and no grey, but a + // lot of gray... + + // so first extract ' ' + while ((p = strchr(name, ' ')) != NULL) + { + while (*(p)) // till eof of string + { + *p = *(p + 1); // copy to the left + p++; + } + } + // fold to lower case + p = name; + while (*p) + { + *p = (char)tolower(*p); + p++; + } + + // substitute Grey with Gray, else rgbtab.h would have more than 100 + // 'duplicate' entries + if ( (grey = strstr(name, "grey")) != NULL ) + grey[2] = 'a'; + + // check for special 'none' colour: + bool found; + if ( strcmp(name, "none") == 0 ) + { + *isNone = true; + found = true; + } + else // not "None" + { + found = false; + + // binary search: + left = 0; + right = numTheRGBRecords - 1; + do + { + middle = (left + right) / 2; + cmp = strcmp(name, theRGBRecords[middle].name); + if ( cmp == 0 ) + { + rgbVal = theRGBRecords[middle].rgb; + *r = (unsigned char)((rgbVal >> 16) & 0xFF); + *g = (unsigned char)((rgbVal >> 8) & 0xFF); + *b = (unsigned char)((rgbVal) & 0xFF); + *isNone = false; + found = true; + break; + } + else if ( cmp < 0 ) + { + right = middle - 1; + } + else // cmp > 0 + { + left = middle + 1; + } + } while (left <= right); + } + + free(name); + + return found; +} + +static const char *ParseColor(const char *data) +{ + static const char *targets[] = + {"c ", "g ", "g4 ", "m ", "b ", "s ", NULL}; + + const char *p, *r; + const char *q; + int i; + + for (i = 0; targets[i] != NULL; i++) + { + r = data; + for (q = targets[i]; *r != '\0'; r++) + { + if ( *r != *q ) + continue; + if ( !isspace((int) (*(r - 1))) ) + continue; + p = r; + for (;;) + { + if ( *q == '\0' ) + return p; + if ( *p++ != *q++ ) + break; + } + q = targets[i]; + } + } + return NULL; +} + +struct wxXPMColourMapData +{ + wxXPMColourMapData() { R = G = B = 0; } + unsigned char R,G,B; +}; +WX_DECLARE_STRING_HASH_MAP(wxXPMColourMapData, wxXPMColourMap); + +wxImage wxXPMDecoder::ReadData(const char* const* xpm_data) +{ + wxCHECK_MSG(xpm_data, wxNullImage, wxT("NULL XPM data") ); + + wxImage img; + int count; + unsigned width, height, colors_cnt, chars_per_pixel; + size_t i, j, i_key; + wxChar key[64]; + const char *clr_def; + bool hasMask; + wxXPMColourMap clr_tbl; + wxXPMColourMap::iterator it; + wxString maskKey; + + /* + * Read hints and initialize structures: + */ + + count = sscanf(xpm_data[0], "%u %u %u %u", + &width, &height, &colors_cnt, &chars_per_pixel); + if ( count != 4 || width * height * colors_cnt == 0 ) + { + wxLogError(_("XPM: incorrect header format!")); + return wxNullImage; + } + + // VS: XPM color map this large would be insane, since XPMs are encoded with + // 92 possible values on each position, 92^64 is *way* larger space than + // 8bit RGB... + wxCHECK_MSG(chars_per_pixel < 64, wxNullImage, wxT("XPM colormaps this large not supported.")); + + if ( !img.Create(width, height) ) + return wxNullImage; + + img.SetMask(false); + key[chars_per_pixel] = wxT('\0'); + hasMask = false; + + /* + * Create colour map: + */ + wxXPMColourMapData clr_data; + for (i = 0; i < colors_cnt; i++) + { + const char *xmpColLine = xpm_data[1 + i]; + + // we must have at least " x y" after the colour index, hence +5 + if ( !xmpColLine || strlen(xmpColLine) < chars_per_pixel + 5 ) + { + wxLogError(_("XPM: incorrect colour description in line %d"), + (int)(1 + i)); + return wxNullImage; + } + + for (i_key = 0; i_key < chars_per_pixel; i_key++) + key[i_key] = (wxChar)xmpColLine[i_key]; + clr_def = ParseColor(xmpColLine + chars_per_pixel); + + if ( clr_def == NULL ) + { + wxLogError(_("XPM: malformed colour definition '%s' at line %d!"), + xmpColLine, (int)(1 + i)); + return wxNullImage; + } + + bool isNone = false; + if ( !GetRGBFromName(clr_def, &isNone, + &clr_data.R, &clr_data.G, &clr_data.B) ) + { + wxLogError(_("XPM: malformed colour definition '%s' at line %d!"), + xmpColLine, (int)(1 + i)); + return wxNullImage; + } + + if ( isNone ) + { + img.SetMask(true); + img.SetMaskColour(255, 0, 255); + clr_data.R = + clr_data.B = 255; + clr_data.G = 0; + hasMask = true; + maskKey = key; + } + + clr_tbl[key] = clr_data; + } + + /* + * Modify colour entries with RGB = (255,0,255) to (255,0,254) if + * mask colour is present (so that existing pixels with (255,0,255) + * magenta colour are not incorrectly made transparent): + */ + if (hasMask) + { + for (it = clr_tbl.begin(); it != clr_tbl.end(); ++it) + { + if (it->second.R == 255 && it->second.G == 0 && + it->second.B == 255 && + it->first != maskKey) + { + it->second.B = 254; + } + } + } + + /* + * Parse image data: + */ + + unsigned char *img_data = img.GetData(); + wxXPMColourMap::iterator entry; + wxXPMColourMap::iterator end = clr_tbl.end(); + + for (j = 0; j < height; j++) + { + for (i = 0; i < width; i++, img_data += 3) + { + const char *xpmImgLine = xpm_data[1 + colors_cnt + j]; + if ( !xpmImgLine || strlen(xpmImgLine) < width*chars_per_pixel ) + { + wxLogError(_("XPM: truncated image data at line %d!"), + (int)(1 + colors_cnt + j)); + return wxNullImage; + } + + for (i_key = 0; i_key < chars_per_pixel; i_key++) + { + key[i_key] = (wxChar)xpmImgLine[chars_per_pixel * i + i_key]; + } + + entry = clr_tbl.find(key); + if ( entry == end ) + { + wxLogError(_("XPM: Malformed pixel data!")); + + // better return right now as otherwise we risk to flood the + // user with error messages as something seems to be seriously + // wrong with the file and so we could give this message for + // each remaining pixel if we don't bail out + return wxNullImage; + } + else + { + img_data[0] = entry->second.R; + img_data[1] = entry->second.G; + img_data[2] = entry->second.B; + } + } + } + + return img; +} + +#endif // wxUSE_IMAGE && wxUSE_XPM diff --git a/Externals/wxWidgets/src/common/xti.cpp b/Externals/wxWidgets/src/common/xti.cpp index adbbd07bf3..9542896f78 100644 --- a/Externals/wxWidgets/src/common/xti.cpp +++ b/Externals/wxWidgets/src/common/xti.cpp @@ -1,767 +1,767 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/xti.cpp -// Purpose: runtime metadata information (extended class info -// Author: Stefan Csomor -// Modified by: -// Created: 27/07/03 -// RCS-ID: $Id: xti.cpp 38857 2006-04-20 07:31:44Z ABX $ -// Copyright: (c) 1997 Julian Smart -// (c) 2003 Stefan Csomor -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_EXTENDED_RTTI - -#ifndef WX_PRECOMP - #include "wx/object.h" - #include "wx/list.h" - #include "wx/hash.h" -#endif - -#include "wx/xti.h" -#include "wx/xml/xml.h" -#include "wx/tokenzr.h" -#include - -#include "wx/beforestd.h" -#include -#include -#include -#include "wx/afterstd.h" - -using namespace std ; - -// ---------------------------------------------------------------------------- -// Enum Support -// ---------------------------------------------------------------------------- - -wxEnumData::wxEnumData( wxEnumMemberData* data ) -{ - m_members = data ; - for ( m_count = 0; m_members[m_count].m_name ; m_count++) - {} ; -} - -bool wxEnumData::HasEnumMemberValue(const wxChar *name, int *value) const -{ - int i; - for (i = 0; m_members[i].m_name ; i++ ) - { - if (!wxStrcmp(name, m_members[i].m_name)) - { - if ( value ) - *value = m_members[i].m_value; - return true ; - } - } - return false ; -} - -int wxEnumData::GetEnumMemberValue(const wxChar *name) const -{ - int i; - for (i = 0; m_members[i].m_name ; i++ ) - { - if (!wxStrcmp(name, m_members[i].m_name)) - { - return m_members[i].m_value; - } - } - return 0 ; -} - -const wxChar *wxEnumData::GetEnumMemberName(int value) const -{ - int i; - for (i = 0; m_members[i].m_name ; i++) - if (value == m_members[i].m_value) - return m_members[i].m_name; - - return wxEmptyString ; -} - -int wxEnumData::GetEnumMemberValueByIndex( int idx ) const -{ - // we should cache the count in order to avoid out-of-bounds errors - return m_members[idx].m_value ; -} - -const wxChar * wxEnumData::GetEnumMemberNameByIndex( int idx ) const -{ - // we should cache the count in order to avoid out-of-bounds errors - return m_members[idx].m_name ; -} - -// ---------------------------------------------------------------------------- -// Type Information -// ---------------------------------------------------------------------------- -// ---------------------------------------------------------------------------- -// value streaming -// ---------------------------------------------------------------------------- - -// streamer specializations -// for all built-in types - -// bool - -template<> void wxStringReadValue(const wxString &s , bool &data ) -{ - int intdata ; - wxSscanf(s, _T("%d"), &intdata ) ; - data = (bool)intdata ; -} - -template<> void wxStringWriteValue(wxString &s , const bool &data ) -{ - s = wxString::Format(_T("%d"), data ) ; -} - -// char - -template<> void wxStringReadValue(const wxString &s , char &data ) -{ - int intdata ; - wxSscanf(s, _T("%d"), &intdata ) ; - data = char(intdata) ; -} - -template<> void wxStringWriteValue(wxString &s , const char &data ) -{ - s = wxString::Format(_T("%d"), data ) ; -} - -// unsigned char - -template<> void wxStringReadValue(const wxString &s , unsigned char &data ) -{ - int intdata ; - wxSscanf(s, _T("%d"), &intdata ) ; - data = (unsigned char)(intdata) ; -} - -template<> void wxStringWriteValue(wxString &s , const unsigned char &data ) -{ - s = wxString::Format(_T("%d"), data ) ; -} - -// int - -template<> void wxStringReadValue(const wxString &s , int &data ) -{ - wxSscanf(s, _T("%d"), &data ) ; -} - -template<> void wxStringWriteValue(wxString &s , const int &data ) -{ - s = wxString::Format(_T("%d"), data ) ; -} - -// unsigned int - -template<> void wxStringReadValue(const wxString &s , unsigned int &data ) -{ - wxSscanf(s, _T("%d"), &data ) ; -} - -template<> void wxStringWriteValue(wxString &s , const unsigned int &data ) -{ - s = wxString::Format(_T("%d"), data ) ; -} - -// long - -template<> void wxStringReadValue(const wxString &s , long &data ) -{ - wxSscanf(s, _T("%ld"), &data ) ; -} - -template<> void wxStringWriteValue(wxString &s , const long &data ) -{ - s = wxString::Format(_T("%ld"), data ) ; -} - -// unsigned long - -template<> void wxStringReadValue(const wxString &s , unsigned long &data ) -{ - wxSscanf(s, _T("%ld"), &data ) ; -} - -template<> void wxStringWriteValue(wxString &s , const unsigned long &data ) -{ - s = wxString::Format(_T("%ld"), data ) ; -} - -// float - -template<> void wxStringReadValue(const wxString &s , float &data ) -{ - wxSscanf(s, _T("%f"), &data ) ; -} - -template<> void wxStringWriteValue(wxString &s , const float &data ) -{ - s = wxString::Format(_T("%f"), data ) ; -} - -// double - -template<> void wxStringReadValue(const wxString &s , double &data ) -{ - wxSscanf(s, _T("%lf"), &data ) ; -} - -template<> void wxStringWriteValue(wxString &s , const double &data ) -{ - s = wxString::Format(_T("%lf"), data ) ; -} - -// wxString - -template<> void wxStringReadValue(const wxString &s , wxString &data ) -{ - data = s ; -} - -template<> void wxStringWriteValue(wxString &s , const wxString &data ) -{ - s = data ; -} - -// built-ins -// - -#if wxUSE_FUNC_TEMPLATE_POINTER -#define wxBUILTIN_TYPE_INFO( element , type ) \ - wxBuiltInTypeInfo s_typeInfo##type(element , &wxToStringConverter , &wxFromStringConverter , typeid(type).name()) ; -#else -#define wxBUILTIN_TYPE_INFO( element , type ) \ - void _toString##element( const wxxVariant& data , wxString &result ) { wxToStringConverter(data, result); } \ - void _fromString##element( const wxString& data , wxxVariant &result ) { wxFromStringConverter(data, result); } \ - wxBuiltInTypeInfo s_typeInfo##type(element , &_toString##element , &_fromString##element , typeid(type).name()) ; -#endif - -typedef unsigned char unsigned_char; -typedef unsigned int unsigned_int; -typedef unsigned long unsigned_long; - -wxBuiltInTypeInfo s_typeInfovoid( wxT_VOID , NULL , NULL , typeid(void).name()); -wxBUILTIN_TYPE_INFO( wxT_BOOL , bool); -wxBUILTIN_TYPE_INFO( wxT_CHAR , char); -wxBUILTIN_TYPE_INFO( wxT_UCHAR , unsigned_char); -wxBUILTIN_TYPE_INFO( wxT_INT , int); -wxBUILTIN_TYPE_INFO( wxT_UINT , unsigned_int); -wxBUILTIN_TYPE_INFO( wxT_LONG , long); -wxBUILTIN_TYPE_INFO( wxT_ULONG , unsigned_long); -wxBUILTIN_TYPE_INFO( wxT_FLOAT , float); -wxBUILTIN_TYPE_INFO( wxT_DOUBLE , double); -wxBUILTIN_TYPE_INFO( wxT_STRING , wxString); - - -// this are compiler induced specialization which are never used anywhere - -wxILLEGAL_TYPE_SPECIALIZATION( char const * ) -wxILLEGAL_TYPE_SPECIALIZATION( char * ) -wxILLEGAL_TYPE_SPECIALIZATION( unsigned char * ) -wxILLEGAL_TYPE_SPECIALIZATION( int * ) -wxILLEGAL_TYPE_SPECIALIZATION( bool * ) -wxILLEGAL_TYPE_SPECIALIZATION( long * ) -wxILLEGAL_TYPE_SPECIALIZATION( wxString * ) - -wxCOLLECTION_TYPE_INFO( wxString , wxArrayString ) ; - -template<> void wxCollectionToVariantArray( wxArrayString const &theArray, wxxVariantArray &value) -{ - wxArrayCollectionToVariantArray( theArray , value ) ; -} - -wxTypeInfoMap *wxTypeInfo::ms_typeTable = NULL ; - -wxTypeInfo *wxTypeInfo::FindType(const wxChar *typeName) -{ - wxTypeInfoMap::iterator iter = ms_typeTable->find(typeName) ; - wxASSERT_MSG( iter != ms_typeTable->end() , wxT("lookup for a non-existent type-info") ) ; - return (wxTypeInfo *)iter->second; -} - -#if wxUSE_UNICODE -wxClassTypeInfo::wxClassTypeInfo( wxTypeKind kind , wxClassInfo* classInfo , converterToString_t to , converterFromString_t from , const char *name) : -wxTypeInfo( kind , to , from , name) -{ wxASSERT_MSG( kind == wxT_OBJECT_PTR || kind == wxT_OBJECT , wxT("Illegal Kind for Enum Type")) ; m_classInfo = classInfo ;} -#endif - -wxClassTypeInfo::wxClassTypeInfo( wxTypeKind kind , wxClassInfo* classInfo , converterToString_t to , converterFromString_t from , const wxString &name) : -wxTypeInfo( kind , to , from , name) -{ wxASSERT_MSG( kind == wxT_OBJECT_PTR || kind == wxT_OBJECT , wxT("Illegal Kind for Enum Type")) ; m_classInfo = classInfo ;} - -wxDelegateTypeInfo::wxDelegateTypeInfo( int eventType , wxClassInfo* eventClass , converterToString_t to , converterFromString_t from ) : -wxTypeInfo ( wxT_DELEGATE , to , from , wxEmptyString ) -{ m_eventClass = eventClass ; m_eventType = eventType ; m_lastEventType = -1 ;} - -wxDelegateTypeInfo::wxDelegateTypeInfo( int eventType , int lastEventType , wxClassInfo* eventClass , converterToString_t to , converterFromString_t from ) : -wxTypeInfo ( wxT_DELEGATE , to , from , wxEmptyString ) -{ m_eventClass = eventClass ; m_eventType = eventType ; m_lastEventType = lastEventType; } - -void wxTypeInfo::Register() -{ - if ( ms_typeTable == NULL ) - ms_typeTable = new wxTypeInfoMap() ; - - if( !m_name.empty() ) - (*ms_typeTable)[m_name] = this ; -} - -void wxTypeInfo::Unregister() -{ - if( !m_name.empty() ) - ms_typeTable->erase(m_name); -} - -// removing header dependancy on string tokenizer - -void wxSetStringToArray( const wxString &s , wxArrayString &array ) -{ - wxStringTokenizer tokenizer(s, wxT("| \t\n"), wxTOKEN_STRTOK); - wxString flag; - array.Clear() ; - while (tokenizer.HasMoreTokens()) - { - array.Add(tokenizer.GetNextToken()) ; - } -} - -// ---------------------------------------------------------------------------- -// wxClassInfo -// ---------------------------------------------------------------------------- - -wxPropertyInfo::~wxPropertyInfo() -{ - if ( this == m_itsClass->m_firstProperty ) - { - m_itsClass->m_firstProperty = m_next; - } - else - { - wxPropertyInfo *info = m_itsClass->m_firstProperty; - while (info) - { - if ( info->m_next == this ) - { - info->m_next = m_next; - break; - } - - info = info->m_next; - } - } -} - -wxHandlerInfo::~wxHandlerInfo() -{ - if ( this == m_itsClass->m_firstHandler ) - { - m_itsClass->m_firstHandler = m_next; - } - else - { - wxHandlerInfo *info = m_itsClass->m_firstHandler; - while (info) - { - if ( info->m_next == this ) - { - info->m_next = m_next; - break; - } - - info = info->m_next; - } - } -} - -const wxPropertyAccessor *wxClassInfo::FindAccessor(const wxChar *PropertyName) const -{ - const wxPropertyInfo* info = FindPropertyInfo( PropertyName ) ; - - if ( info ) - return info->GetAccessor() ; - - return NULL ; -} - -wxPropertyInfo *wxClassInfo::FindPropertyInfoInThisClass (const wxChar *PropertyName) const -{ - wxPropertyInfo* info = m_firstProperty ; - - while( info ) - { - if ( wxStrcmp( info->GetName() , PropertyName ) == 0 ) - return info ; - info = info->GetNext() ; - } - - return 0; -} - -const wxPropertyInfo *wxClassInfo::FindPropertyInfo (const wxChar *PropertyName) const -{ - const wxPropertyInfo* info = FindPropertyInfoInThisClass( PropertyName ) ; - if ( info ) - return info ; - - const wxClassInfo** parents = GetParents() ; - for ( int i = 0 ; parents[i] ; ++ i ) - { - if ( ( info = parents[i]->FindPropertyInfo( PropertyName ) ) != NULL ) - return info ; - } - - return 0; -} - -wxHandlerInfo *wxClassInfo::FindHandlerInfoInThisClass (const wxChar *PropertyName) const -{ - wxHandlerInfo* info = m_firstHandler ; - - while( info ) - { - if ( wxStrcmp( info->GetName() , PropertyName ) == 0 ) - return info ; - info = info->GetNext() ; - } - - return 0; -} - -const wxHandlerInfo *wxClassInfo::FindHandlerInfo (const wxChar *PropertyName) const -{ - const wxHandlerInfo* info = FindHandlerInfoInThisClass( PropertyName ) ; - - if ( info ) - return info ; - - const wxClassInfo** parents = GetParents() ; - for ( int i = 0 ; parents[i] ; ++ i ) - { - if ( ( info = parents[i]->FindHandlerInfo( PropertyName ) ) != NULL ) - return info ; - } - - return 0; -} - -wxObjectStreamingCallback wxClassInfo::GetStreamingCallback() const -{ - if ( m_streamingCallback ) - return m_streamingCallback ; - - wxObjectStreamingCallback retval = NULL ; - const wxClassInfo** parents = GetParents() ; - for ( int i = 0 ; parents[i] && retval == NULL ; ++ i ) - { - retval = parents[i]->GetStreamingCallback() ; - } - return retval ; -} - -bool wxClassInfo::BeforeWriteObject( const wxObject *obj, wxWriter *streamer , wxPersister *persister , wxxVariantArray &metadata) const -{ - wxObjectStreamingCallback sb = GetStreamingCallback() ; - if ( sb ) - return (*sb)(obj , streamer , persister , metadata ) ; - - return true ; -} - -void wxClassInfo::SetProperty(wxObject *object, const wxChar *propertyName, const wxxVariant &value) const -{ - const wxPropertyAccessor *accessor; - - accessor = FindAccessor(propertyName); - wxASSERT(accessor->HasSetter()); - accessor->SetProperty( object , value ) ; -} - -wxxVariant wxClassInfo::GetProperty(wxObject *object, const wxChar *propertyName) const -{ - const wxPropertyAccessor *accessor; - - accessor = FindAccessor(propertyName); - wxASSERT(accessor->HasGetter()); - wxxVariant result ; - accessor->GetProperty(object,result); - return result ; -} - -wxxVariantArray wxClassInfo::GetPropertyCollection(wxObject *object, const wxChar *propertyName) const -{ - const wxPropertyAccessor *accessor; - - accessor = FindAccessor(propertyName); - wxASSERT(accessor->HasGetter()); - wxxVariantArray result ; - accessor->GetPropertyCollection(object,result); - return result ; -} - -void wxClassInfo::AddToPropertyCollection(wxObject *object, const wxChar *propertyName , const wxxVariant& value) const -{ - const wxPropertyAccessor *accessor; - - accessor = FindAccessor(propertyName); - wxASSERT(accessor->HasAdder()); - accessor->AddToPropertyCollection( object , value ) ; -} - -// void wxClassInfo::GetProperties( wxPropertyInfoMap &map ) const -// The map parameter (the name map that is) seems something special -// to MSVC and so we use a other name. -void wxClassInfo::GetProperties( wxPropertyInfoMap &infomap ) const -{ - const wxPropertyInfo *pi = GetFirstProperty() ; - while( pi ) - { - if ( infomap.find( pi->GetName() ) == infomap.end() ) - infomap[pi->GetName()] = (wxPropertyInfo*) pi ; - - pi = pi->GetNext() ; - } - - const wxClassInfo** parents = GetParents() ; - for ( int i = 0 ; parents[i] ; ++ i ) - { - parents[i]->GetProperties( infomap ) ; - } -} - -/* -VARIANT TO OBJECT -*/ - -wxObject* wxxVariant::GetAsObject() -{ - const wxClassTypeInfo *ti = dynamic_cast( m_data->GetTypeInfo() ) ; - if ( ti ) - return ti->GetClassInfo()->VariantToInstance(*this) ; - else - return NULL ; -} - -// ---------------------------------------------------------------------------- -// wxDynamicObject support -// ---------------------------------------------------------------------------- -// -// Dynamic Objects are objects that have a real superclass instance and carry their -// own attributes in a hash map. Like this it is possible to create the objects and -// stream them, as if their class information was already available from compiled data - -struct wxDynamicObject::wxDynamicObjectInternal -{ - wxDynamicObjectInternal() {} - -#if wxUSE_UNICODE - map m_properties ; -#else - map m_properties ; -#endif -} ; - -typedef list< wxDynamicObject* > wxDynamicObjectList ; - -struct wxDynamicClassInfo::wxDynamicClassInfoInternal -{ - wxDynamicObjectList m_dynamicObjects ; -} ; - -// instantiates this object with an instance of its superclass -wxDynamicObject::wxDynamicObject(wxObject* superClassInstance, const wxDynamicClassInfo *info) -{ - m_superClassInstance = superClassInstance ; - m_classInfo = info ; - m_data = new wxDynamicObjectInternal ; -} - -wxDynamicObject::~wxDynamicObject() -{ - dynamic_cast(m_classInfo)->m_data->m_dynamicObjects.remove( this ) ; - delete m_data ; - delete m_superClassInstance ; -} - -void wxDynamicObject::SetProperty (const wxChar *propertyName, const wxxVariant &value) -{ - wxASSERT_MSG(m_classInfo->FindPropertyInfoInThisClass(propertyName),wxT("Accessing Unknown Property in a Dynamic Object") ) ; - m_data->m_properties[propertyName] = value ; -} - -wxxVariant wxDynamicObject::GetProperty (const wxChar *propertyName) const -{ - wxASSERT_MSG(m_classInfo->FindPropertyInfoInThisClass(propertyName),wxT("Accessing Unknown Property in a Dynamic Object") ) ; - return m_data->m_properties[propertyName] ; -} - -void wxDynamicObject::RemoveProperty( const wxChar *propertyName ) -{ - wxASSERT_MSG(m_classInfo->FindPropertyInfoInThisClass(propertyName),wxT("Removing Unknown Property in a Dynamic Object") ) ; - m_data->m_properties.erase( propertyName ) ; -} - -void wxDynamicObject::RenameProperty( const wxChar *oldPropertyName , const wxChar *newPropertyName ) -{ - wxASSERT_MSG(m_classInfo->FindPropertyInfoInThisClass(oldPropertyName),wxT("Renaming Unknown Property in a Dynamic Object") ) ; - wxxVariant value = m_data->m_properties[oldPropertyName] ; - m_data->m_properties.erase( oldPropertyName ) ; - m_data->m_properties[newPropertyName] = value ; -} - - -// ---------------------------------------------------------------------------- -// wxDynamiClassInfo -// ---------------------------------------------------------------------------- - -wxDynamicClassInfo::wxDynamicClassInfo( const wxChar *unitName, const wxChar *className , const wxClassInfo* superClass ) : -wxClassInfo( unitName, className , new const wxClassInfo*[2]) -{ - GetParents()[0] = superClass ; - GetParents()[1] = NULL ; - m_data = new wxDynamicClassInfoInternal ; -} - -wxDynamicClassInfo::~wxDynamicClassInfo() -{ - delete[] GetParents() ; - delete m_data ; -} - -wxObject *wxDynamicClassInfo::AllocateObject() const -{ - wxObject* parent = GetParents()[0]->AllocateObject() ; - wxDynamicObject *obj = new wxDynamicObject( parent , this ) ; - m_data->m_dynamicObjects.push_back( obj ) ; - return obj ; -} - -void wxDynamicClassInfo::Create (wxObject *object, int paramCount, wxxVariant *params) const -{ - wxDynamicObject *dynobj = dynamic_cast< wxDynamicObject *>( object ) ; - wxASSERT_MSG( dynobj , wxT("cannot call wxDynamicClassInfo::Create on an object other than wxDynamicObject") ) ; - GetParents()[0]->Create( dynobj->GetSuperClassInstance() , paramCount , params ) ; -} - -// get number of parameters for constructor -int wxDynamicClassInfo::GetCreateParamCount() const -{ - return GetParents()[0]->GetCreateParamCount() ; -} - -// get i-th constructor parameter -const wxChar* wxDynamicClassInfo::GetCreateParamName(int i) const -{ - return GetParents()[0]->GetCreateParamName( i ) ; -} - -void wxDynamicClassInfo::SetProperty(wxObject *object, const wxChar *propertyName, const wxxVariant &value) const -{ - wxDynamicObject* dynobj = dynamic_cast< wxDynamicObject * >( object ) ; - wxASSERT_MSG( dynobj , wxT("cannot call wxDynamicClassInfo::SetProperty on an object other than wxDynamicObject") ) ; - if ( FindPropertyInfoInThisClass(propertyName) ) - dynobj->SetProperty( propertyName , value ) ; - else - GetParents()[0]->SetProperty( dynobj->GetSuperClassInstance() , propertyName , value ) ; -} - -wxxVariant wxDynamicClassInfo::GetProperty(wxObject *object, const wxChar *propertyName) const -{ - wxDynamicObject* dynobj = dynamic_cast< wxDynamicObject * >( object ) ; - wxASSERT_MSG( dynobj , wxT("cannot call wxDynamicClassInfo::SetProperty on an object other than wxDynamicObject") ) ; - if ( FindPropertyInfoInThisClass(propertyName) ) - return dynobj->GetProperty( propertyName ) ; - else - return GetParents()[0]->GetProperty( dynobj->GetSuperClassInstance() , propertyName ) ; -} - -void wxDynamicClassInfo::AddProperty( const wxChar *propertyName , const wxTypeInfo* typeInfo ) -{ - new wxPropertyInfo( m_firstProperty , this , propertyName , typeInfo->GetTypeName() , new wxGenericPropertyAccessor( propertyName ) , wxxVariant() ) ; -} - -void wxDynamicClassInfo::AddHandler( const wxChar *handlerName , wxObjectEventFunction address , const wxClassInfo* eventClassInfo ) -{ - new wxHandlerInfo( m_firstHandler , this , handlerName , address , eventClassInfo ) ; -} - -// removes an existing runtime-property -void wxDynamicClassInfo::RemoveProperty( const wxChar *propertyName ) -{ - for ( wxDynamicObjectList::iterator iter = m_data->m_dynamicObjects.begin() ; iter != m_data->m_dynamicObjects.end() ; ++iter ) - (*iter)->RemoveProperty( propertyName ) ; - delete FindPropertyInfoInThisClass(propertyName) ; -} - -// removes an existing runtime-handler -void wxDynamicClassInfo::RemoveHandler( const wxChar *handlerName ) -{ - delete FindHandlerInfoInThisClass(handlerName) ; -} - -// renames an existing runtime-property -void wxDynamicClassInfo::RenameProperty( const wxChar *oldPropertyName , const wxChar *newPropertyName ) -{ - wxPropertyInfo* pi = FindPropertyInfoInThisClass(oldPropertyName) ; - wxASSERT_MSG( pi ,wxT("not existing property") ) ; - pi->m_name = newPropertyName ; - dynamic_cast(pi->GetAccessor())->RenameProperty( oldPropertyName , newPropertyName ) ; - for ( wxDynamicObjectList::iterator iter = m_data->m_dynamicObjects.begin() ; iter != m_data->m_dynamicObjects.end() ; ++iter ) - (*iter)->RenameProperty( oldPropertyName , newPropertyName ) ; -} - -// renames an existing runtime-handler -void wxDynamicClassInfo::RenameHandler( const wxChar *oldHandlerName , const wxChar *newHandlerName ) -{ - wxASSERT_MSG(FindHandlerInfoInThisClass(oldHandlerName),wxT("not existing handler") ) ; - FindHandlerInfoInThisClass(oldHandlerName)->m_name = newHandlerName ; -} - -// ---------------------------------------------------------------------------- -// wxGenericPropertyAccessor -// ---------------------------------------------------------------------------- - -struct wxGenericPropertyAccessor::wxGenericPropertyAccessorInternal -{ - char filler ; -} ; - -wxGenericPropertyAccessor::wxGenericPropertyAccessor( const wxString& propertyName ) -: wxPropertyAccessor( NULL , NULL , NULL , NULL ) -{ - m_data = new wxGenericPropertyAccessorInternal ; - m_propertyName = propertyName ; - m_getterName = wxT("Get")+propertyName ; - m_setterName = wxT("Set")+propertyName ; -} - -wxGenericPropertyAccessor::~wxGenericPropertyAccessor() -{ - delete m_data ; -} -void wxGenericPropertyAccessor::SetProperty(wxObject *object, const wxxVariant &value) const -{ - wxDynamicObject* dynobj = dynamic_cast< wxDynamicObject * >( object ) ; - wxASSERT_MSG( dynobj , wxT("cannot call wxDynamicClassInfo::SetProperty on an object other than wxDynamicObject") ) ; - dynobj->SetProperty(m_propertyName , value ) ; -} - -void wxGenericPropertyAccessor::GetProperty(const wxObject *object, wxxVariant& value) const -{ - const wxDynamicObject* dynobj = dynamic_cast< const wxDynamicObject * >( object ) ; - wxASSERT_MSG( dynobj , wxT("cannot call wxDynamicClassInfo::SetProperty on an object other than wxDynamicObject") ) ; - value = dynobj->GetProperty( m_propertyName ) ; -} - -#endif // wxUSE_EXTENDED_RTTI +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/xti.cpp +// Purpose: runtime metadata information (extended class info +// Author: Stefan Csomor +// Modified by: +// Created: 27/07/03 +// RCS-ID: $Id: xti.cpp 38857 2006-04-20 07:31:44Z ABX $ +// Copyright: (c) 1997 Julian Smart +// (c) 2003 Stefan Csomor +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_EXTENDED_RTTI + +#ifndef WX_PRECOMP + #include "wx/object.h" + #include "wx/list.h" + #include "wx/hash.h" +#endif + +#include "wx/xti.h" +#include "wx/xml/xml.h" +#include "wx/tokenzr.h" +#include + +#include "wx/beforestd.h" +#include +#include +#include +#include "wx/afterstd.h" + +using namespace std ; + +// ---------------------------------------------------------------------------- +// Enum Support +// ---------------------------------------------------------------------------- + +wxEnumData::wxEnumData( wxEnumMemberData* data ) +{ + m_members = data ; + for ( m_count = 0; m_members[m_count].m_name ; m_count++) + {} ; +} + +bool wxEnumData::HasEnumMemberValue(const wxChar *name, int *value) const +{ + int i; + for (i = 0; m_members[i].m_name ; i++ ) + { + if (!wxStrcmp(name, m_members[i].m_name)) + { + if ( value ) + *value = m_members[i].m_value; + return true ; + } + } + return false ; +} + +int wxEnumData::GetEnumMemberValue(const wxChar *name) const +{ + int i; + for (i = 0; m_members[i].m_name ; i++ ) + { + if (!wxStrcmp(name, m_members[i].m_name)) + { + return m_members[i].m_value; + } + } + return 0 ; +} + +const wxChar *wxEnumData::GetEnumMemberName(int value) const +{ + int i; + for (i = 0; m_members[i].m_name ; i++) + if (value == m_members[i].m_value) + return m_members[i].m_name; + + return wxEmptyString ; +} + +int wxEnumData::GetEnumMemberValueByIndex( int idx ) const +{ + // we should cache the count in order to avoid out-of-bounds errors + return m_members[idx].m_value ; +} + +const wxChar * wxEnumData::GetEnumMemberNameByIndex( int idx ) const +{ + // we should cache the count in order to avoid out-of-bounds errors + return m_members[idx].m_name ; +} + +// ---------------------------------------------------------------------------- +// Type Information +// ---------------------------------------------------------------------------- +// ---------------------------------------------------------------------------- +// value streaming +// ---------------------------------------------------------------------------- + +// streamer specializations +// for all built-in types + +// bool + +template<> void wxStringReadValue(const wxString &s , bool &data ) +{ + int intdata ; + wxSscanf(s, _T("%d"), &intdata ) ; + data = (bool)intdata ; +} + +template<> void wxStringWriteValue(wxString &s , const bool &data ) +{ + s = wxString::Format(_T("%d"), data ) ; +} + +// char + +template<> void wxStringReadValue(const wxString &s , char &data ) +{ + int intdata ; + wxSscanf(s, _T("%d"), &intdata ) ; + data = char(intdata) ; +} + +template<> void wxStringWriteValue(wxString &s , const char &data ) +{ + s = wxString::Format(_T("%d"), data ) ; +} + +// unsigned char + +template<> void wxStringReadValue(const wxString &s , unsigned char &data ) +{ + int intdata ; + wxSscanf(s, _T("%d"), &intdata ) ; + data = (unsigned char)(intdata) ; +} + +template<> void wxStringWriteValue(wxString &s , const unsigned char &data ) +{ + s = wxString::Format(_T("%d"), data ) ; +} + +// int + +template<> void wxStringReadValue(const wxString &s , int &data ) +{ + wxSscanf(s, _T("%d"), &data ) ; +} + +template<> void wxStringWriteValue(wxString &s , const int &data ) +{ + s = wxString::Format(_T("%d"), data ) ; +} + +// unsigned int + +template<> void wxStringReadValue(const wxString &s , unsigned int &data ) +{ + wxSscanf(s, _T("%d"), &data ) ; +} + +template<> void wxStringWriteValue(wxString &s , const unsigned int &data ) +{ + s = wxString::Format(_T("%d"), data ) ; +} + +// long + +template<> void wxStringReadValue(const wxString &s , long &data ) +{ + wxSscanf(s, _T("%ld"), &data ) ; +} + +template<> void wxStringWriteValue(wxString &s , const long &data ) +{ + s = wxString::Format(_T("%ld"), data ) ; +} + +// unsigned long + +template<> void wxStringReadValue(const wxString &s , unsigned long &data ) +{ + wxSscanf(s, _T("%ld"), &data ) ; +} + +template<> void wxStringWriteValue(wxString &s , const unsigned long &data ) +{ + s = wxString::Format(_T("%ld"), data ) ; +} + +// float + +template<> void wxStringReadValue(const wxString &s , float &data ) +{ + wxSscanf(s, _T("%f"), &data ) ; +} + +template<> void wxStringWriteValue(wxString &s , const float &data ) +{ + s = wxString::Format(_T("%f"), data ) ; +} + +// double + +template<> void wxStringReadValue(const wxString &s , double &data ) +{ + wxSscanf(s, _T("%lf"), &data ) ; +} + +template<> void wxStringWriteValue(wxString &s , const double &data ) +{ + s = wxString::Format(_T("%lf"), data ) ; +} + +// wxString + +template<> void wxStringReadValue(const wxString &s , wxString &data ) +{ + data = s ; +} + +template<> void wxStringWriteValue(wxString &s , const wxString &data ) +{ + s = data ; +} + +// built-ins +// + +#if wxUSE_FUNC_TEMPLATE_POINTER +#define wxBUILTIN_TYPE_INFO( element , type ) \ + wxBuiltInTypeInfo s_typeInfo##type(element , &wxToStringConverter , &wxFromStringConverter , typeid(type).name()) ; +#else +#define wxBUILTIN_TYPE_INFO( element , type ) \ + void _toString##element( const wxxVariant& data , wxString &result ) { wxToStringConverter(data, result); } \ + void _fromString##element( const wxString& data , wxxVariant &result ) { wxFromStringConverter(data, result); } \ + wxBuiltInTypeInfo s_typeInfo##type(element , &_toString##element , &_fromString##element , typeid(type).name()) ; +#endif + +typedef unsigned char unsigned_char; +typedef unsigned int unsigned_int; +typedef unsigned long unsigned_long; + +wxBuiltInTypeInfo s_typeInfovoid( wxT_VOID , NULL , NULL , typeid(void).name()); +wxBUILTIN_TYPE_INFO( wxT_BOOL , bool); +wxBUILTIN_TYPE_INFO( wxT_CHAR , char); +wxBUILTIN_TYPE_INFO( wxT_UCHAR , unsigned_char); +wxBUILTIN_TYPE_INFO( wxT_INT , int); +wxBUILTIN_TYPE_INFO( wxT_UINT , unsigned_int); +wxBUILTIN_TYPE_INFO( wxT_LONG , long); +wxBUILTIN_TYPE_INFO( wxT_ULONG , unsigned_long); +wxBUILTIN_TYPE_INFO( wxT_FLOAT , float); +wxBUILTIN_TYPE_INFO( wxT_DOUBLE , double); +wxBUILTIN_TYPE_INFO( wxT_STRING , wxString); + + +// this are compiler induced specialization which are never used anywhere + +wxILLEGAL_TYPE_SPECIALIZATION( char const * ) +wxILLEGAL_TYPE_SPECIALIZATION( char * ) +wxILLEGAL_TYPE_SPECIALIZATION( unsigned char * ) +wxILLEGAL_TYPE_SPECIALIZATION( int * ) +wxILLEGAL_TYPE_SPECIALIZATION( bool * ) +wxILLEGAL_TYPE_SPECIALIZATION( long * ) +wxILLEGAL_TYPE_SPECIALIZATION( wxString * ) + +wxCOLLECTION_TYPE_INFO( wxString , wxArrayString ) ; + +template<> void wxCollectionToVariantArray( wxArrayString const &theArray, wxxVariantArray &value) +{ + wxArrayCollectionToVariantArray( theArray , value ) ; +} + +wxTypeInfoMap *wxTypeInfo::ms_typeTable = NULL ; + +wxTypeInfo *wxTypeInfo::FindType(const wxChar *typeName) +{ + wxTypeInfoMap::iterator iter = ms_typeTable->find(typeName) ; + wxASSERT_MSG( iter != ms_typeTable->end() , wxT("lookup for a non-existent type-info") ) ; + return (wxTypeInfo *)iter->second; +} + +#if wxUSE_UNICODE +wxClassTypeInfo::wxClassTypeInfo( wxTypeKind kind , wxClassInfo* classInfo , converterToString_t to , converterFromString_t from , const char *name) : +wxTypeInfo( kind , to , from , name) +{ wxASSERT_MSG( kind == wxT_OBJECT_PTR || kind == wxT_OBJECT , wxT("Illegal Kind for Enum Type")) ; m_classInfo = classInfo ;} +#endif + +wxClassTypeInfo::wxClassTypeInfo( wxTypeKind kind , wxClassInfo* classInfo , converterToString_t to , converterFromString_t from , const wxString &name) : +wxTypeInfo( kind , to , from , name) +{ wxASSERT_MSG( kind == wxT_OBJECT_PTR || kind == wxT_OBJECT , wxT("Illegal Kind for Enum Type")) ; m_classInfo = classInfo ;} + +wxDelegateTypeInfo::wxDelegateTypeInfo( int eventType , wxClassInfo* eventClass , converterToString_t to , converterFromString_t from ) : +wxTypeInfo ( wxT_DELEGATE , to , from , wxEmptyString ) +{ m_eventClass = eventClass ; m_eventType = eventType ; m_lastEventType = -1 ;} + +wxDelegateTypeInfo::wxDelegateTypeInfo( int eventType , int lastEventType , wxClassInfo* eventClass , converterToString_t to , converterFromString_t from ) : +wxTypeInfo ( wxT_DELEGATE , to , from , wxEmptyString ) +{ m_eventClass = eventClass ; m_eventType = eventType ; m_lastEventType = lastEventType; } + +void wxTypeInfo::Register() +{ + if ( ms_typeTable == NULL ) + ms_typeTable = new wxTypeInfoMap() ; + + if( !m_name.empty() ) + (*ms_typeTable)[m_name] = this ; +} + +void wxTypeInfo::Unregister() +{ + if( !m_name.empty() ) + ms_typeTable->erase(m_name); +} + +// removing header dependancy on string tokenizer + +void wxSetStringToArray( const wxString &s , wxArrayString &array ) +{ + wxStringTokenizer tokenizer(s, wxT("| \t\n"), wxTOKEN_STRTOK); + wxString flag; + array.Clear() ; + while (tokenizer.HasMoreTokens()) + { + array.Add(tokenizer.GetNextToken()) ; + } +} + +// ---------------------------------------------------------------------------- +// wxClassInfo +// ---------------------------------------------------------------------------- + +wxPropertyInfo::~wxPropertyInfo() +{ + if ( this == m_itsClass->m_firstProperty ) + { + m_itsClass->m_firstProperty = m_next; + } + else + { + wxPropertyInfo *info = m_itsClass->m_firstProperty; + while (info) + { + if ( info->m_next == this ) + { + info->m_next = m_next; + break; + } + + info = info->m_next; + } + } +} + +wxHandlerInfo::~wxHandlerInfo() +{ + if ( this == m_itsClass->m_firstHandler ) + { + m_itsClass->m_firstHandler = m_next; + } + else + { + wxHandlerInfo *info = m_itsClass->m_firstHandler; + while (info) + { + if ( info->m_next == this ) + { + info->m_next = m_next; + break; + } + + info = info->m_next; + } + } +} + +const wxPropertyAccessor *wxClassInfo::FindAccessor(const wxChar *PropertyName) const +{ + const wxPropertyInfo* info = FindPropertyInfo( PropertyName ) ; + + if ( info ) + return info->GetAccessor() ; + + return NULL ; +} + +wxPropertyInfo *wxClassInfo::FindPropertyInfoInThisClass (const wxChar *PropertyName) const +{ + wxPropertyInfo* info = m_firstProperty ; + + while( info ) + { + if ( wxStrcmp( info->GetName() , PropertyName ) == 0 ) + return info ; + info = info->GetNext() ; + } + + return 0; +} + +const wxPropertyInfo *wxClassInfo::FindPropertyInfo (const wxChar *PropertyName) const +{ + const wxPropertyInfo* info = FindPropertyInfoInThisClass( PropertyName ) ; + if ( info ) + return info ; + + const wxClassInfo** parents = GetParents() ; + for ( int i = 0 ; parents[i] ; ++ i ) + { + if ( ( info = parents[i]->FindPropertyInfo( PropertyName ) ) != NULL ) + return info ; + } + + return 0; +} + +wxHandlerInfo *wxClassInfo::FindHandlerInfoInThisClass (const wxChar *PropertyName) const +{ + wxHandlerInfo* info = m_firstHandler ; + + while( info ) + { + if ( wxStrcmp( info->GetName() , PropertyName ) == 0 ) + return info ; + info = info->GetNext() ; + } + + return 0; +} + +const wxHandlerInfo *wxClassInfo::FindHandlerInfo (const wxChar *PropertyName) const +{ + const wxHandlerInfo* info = FindHandlerInfoInThisClass( PropertyName ) ; + + if ( info ) + return info ; + + const wxClassInfo** parents = GetParents() ; + for ( int i = 0 ; parents[i] ; ++ i ) + { + if ( ( info = parents[i]->FindHandlerInfo( PropertyName ) ) != NULL ) + return info ; + } + + return 0; +} + +wxObjectStreamingCallback wxClassInfo::GetStreamingCallback() const +{ + if ( m_streamingCallback ) + return m_streamingCallback ; + + wxObjectStreamingCallback retval = NULL ; + const wxClassInfo** parents = GetParents() ; + for ( int i = 0 ; parents[i] && retval == NULL ; ++ i ) + { + retval = parents[i]->GetStreamingCallback() ; + } + return retval ; +} + +bool wxClassInfo::BeforeWriteObject( const wxObject *obj, wxWriter *streamer , wxPersister *persister , wxxVariantArray &metadata) const +{ + wxObjectStreamingCallback sb = GetStreamingCallback() ; + if ( sb ) + return (*sb)(obj , streamer , persister , metadata ) ; + + return true ; +} + +void wxClassInfo::SetProperty(wxObject *object, const wxChar *propertyName, const wxxVariant &value) const +{ + const wxPropertyAccessor *accessor; + + accessor = FindAccessor(propertyName); + wxASSERT(accessor->HasSetter()); + accessor->SetProperty( object , value ) ; +} + +wxxVariant wxClassInfo::GetProperty(wxObject *object, const wxChar *propertyName) const +{ + const wxPropertyAccessor *accessor; + + accessor = FindAccessor(propertyName); + wxASSERT(accessor->HasGetter()); + wxxVariant result ; + accessor->GetProperty(object,result); + return result ; +} + +wxxVariantArray wxClassInfo::GetPropertyCollection(wxObject *object, const wxChar *propertyName) const +{ + const wxPropertyAccessor *accessor; + + accessor = FindAccessor(propertyName); + wxASSERT(accessor->HasGetter()); + wxxVariantArray result ; + accessor->GetPropertyCollection(object,result); + return result ; +} + +void wxClassInfo::AddToPropertyCollection(wxObject *object, const wxChar *propertyName , const wxxVariant& value) const +{ + const wxPropertyAccessor *accessor; + + accessor = FindAccessor(propertyName); + wxASSERT(accessor->HasAdder()); + accessor->AddToPropertyCollection( object , value ) ; +} + +// void wxClassInfo::GetProperties( wxPropertyInfoMap &map ) const +// The map parameter (the name map that is) seems something special +// to MSVC and so we use a other name. +void wxClassInfo::GetProperties( wxPropertyInfoMap &infomap ) const +{ + const wxPropertyInfo *pi = GetFirstProperty() ; + while( pi ) + { + if ( infomap.find( pi->GetName() ) == infomap.end() ) + infomap[pi->GetName()] = (wxPropertyInfo*) pi ; + + pi = pi->GetNext() ; + } + + const wxClassInfo** parents = GetParents() ; + for ( int i = 0 ; parents[i] ; ++ i ) + { + parents[i]->GetProperties( infomap ) ; + } +} + +/* +VARIANT TO OBJECT +*/ + +wxObject* wxxVariant::GetAsObject() +{ + const wxClassTypeInfo *ti = dynamic_cast( m_data->GetTypeInfo() ) ; + if ( ti ) + return ti->GetClassInfo()->VariantToInstance(*this) ; + else + return NULL ; +} + +// ---------------------------------------------------------------------------- +// wxDynamicObject support +// ---------------------------------------------------------------------------- +// +// Dynamic Objects are objects that have a real superclass instance and carry their +// own attributes in a hash map. Like this it is possible to create the objects and +// stream them, as if their class information was already available from compiled data + +struct wxDynamicObject::wxDynamicObjectInternal +{ + wxDynamicObjectInternal() {} + +#if wxUSE_UNICODE + map m_properties ; +#else + map m_properties ; +#endif +} ; + +typedef list< wxDynamicObject* > wxDynamicObjectList ; + +struct wxDynamicClassInfo::wxDynamicClassInfoInternal +{ + wxDynamicObjectList m_dynamicObjects ; +} ; + +// instantiates this object with an instance of its superclass +wxDynamicObject::wxDynamicObject(wxObject* superClassInstance, const wxDynamicClassInfo *info) +{ + m_superClassInstance = superClassInstance ; + m_classInfo = info ; + m_data = new wxDynamicObjectInternal ; +} + +wxDynamicObject::~wxDynamicObject() +{ + dynamic_cast(m_classInfo)->m_data->m_dynamicObjects.remove( this ) ; + delete m_data ; + delete m_superClassInstance ; +} + +void wxDynamicObject::SetProperty (const wxChar *propertyName, const wxxVariant &value) +{ + wxASSERT_MSG(m_classInfo->FindPropertyInfoInThisClass(propertyName),wxT("Accessing Unknown Property in a Dynamic Object") ) ; + m_data->m_properties[propertyName] = value ; +} + +wxxVariant wxDynamicObject::GetProperty (const wxChar *propertyName) const +{ + wxASSERT_MSG(m_classInfo->FindPropertyInfoInThisClass(propertyName),wxT("Accessing Unknown Property in a Dynamic Object") ) ; + return m_data->m_properties[propertyName] ; +} + +void wxDynamicObject::RemoveProperty( const wxChar *propertyName ) +{ + wxASSERT_MSG(m_classInfo->FindPropertyInfoInThisClass(propertyName),wxT("Removing Unknown Property in a Dynamic Object") ) ; + m_data->m_properties.erase( propertyName ) ; +} + +void wxDynamicObject::RenameProperty( const wxChar *oldPropertyName , const wxChar *newPropertyName ) +{ + wxASSERT_MSG(m_classInfo->FindPropertyInfoInThisClass(oldPropertyName),wxT("Renaming Unknown Property in a Dynamic Object") ) ; + wxxVariant value = m_data->m_properties[oldPropertyName] ; + m_data->m_properties.erase( oldPropertyName ) ; + m_data->m_properties[newPropertyName] = value ; +} + + +// ---------------------------------------------------------------------------- +// wxDynamiClassInfo +// ---------------------------------------------------------------------------- + +wxDynamicClassInfo::wxDynamicClassInfo( const wxChar *unitName, const wxChar *className , const wxClassInfo* superClass ) : +wxClassInfo( unitName, className , new const wxClassInfo*[2]) +{ + GetParents()[0] = superClass ; + GetParents()[1] = NULL ; + m_data = new wxDynamicClassInfoInternal ; +} + +wxDynamicClassInfo::~wxDynamicClassInfo() +{ + delete[] GetParents() ; + delete m_data ; +} + +wxObject *wxDynamicClassInfo::AllocateObject() const +{ + wxObject* parent = GetParents()[0]->AllocateObject() ; + wxDynamicObject *obj = new wxDynamicObject( parent , this ) ; + m_data->m_dynamicObjects.push_back( obj ) ; + return obj ; +} + +void wxDynamicClassInfo::Create (wxObject *object, int paramCount, wxxVariant *params) const +{ + wxDynamicObject *dynobj = dynamic_cast< wxDynamicObject *>( object ) ; + wxASSERT_MSG( dynobj , wxT("cannot call wxDynamicClassInfo::Create on an object other than wxDynamicObject") ) ; + GetParents()[0]->Create( dynobj->GetSuperClassInstance() , paramCount , params ) ; +} + +// get number of parameters for constructor +int wxDynamicClassInfo::GetCreateParamCount() const +{ + return GetParents()[0]->GetCreateParamCount() ; +} + +// get i-th constructor parameter +const wxChar* wxDynamicClassInfo::GetCreateParamName(int i) const +{ + return GetParents()[0]->GetCreateParamName( i ) ; +} + +void wxDynamicClassInfo::SetProperty(wxObject *object, const wxChar *propertyName, const wxxVariant &value) const +{ + wxDynamicObject* dynobj = dynamic_cast< wxDynamicObject * >( object ) ; + wxASSERT_MSG( dynobj , wxT("cannot call wxDynamicClassInfo::SetProperty on an object other than wxDynamicObject") ) ; + if ( FindPropertyInfoInThisClass(propertyName) ) + dynobj->SetProperty( propertyName , value ) ; + else + GetParents()[0]->SetProperty( dynobj->GetSuperClassInstance() , propertyName , value ) ; +} + +wxxVariant wxDynamicClassInfo::GetProperty(wxObject *object, const wxChar *propertyName) const +{ + wxDynamicObject* dynobj = dynamic_cast< wxDynamicObject * >( object ) ; + wxASSERT_MSG( dynobj , wxT("cannot call wxDynamicClassInfo::SetProperty on an object other than wxDynamicObject") ) ; + if ( FindPropertyInfoInThisClass(propertyName) ) + return dynobj->GetProperty( propertyName ) ; + else + return GetParents()[0]->GetProperty( dynobj->GetSuperClassInstance() , propertyName ) ; +} + +void wxDynamicClassInfo::AddProperty( const wxChar *propertyName , const wxTypeInfo* typeInfo ) +{ + new wxPropertyInfo( m_firstProperty , this , propertyName , typeInfo->GetTypeName() , new wxGenericPropertyAccessor( propertyName ) , wxxVariant() ) ; +} + +void wxDynamicClassInfo::AddHandler( const wxChar *handlerName , wxObjectEventFunction address , const wxClassInfo* eventClassInfo ) +{ + new wxHandlerInfo( m_firstHandler , this , handlerName , address , eventClassInfo ) ; +} + +// removes an existing runtime-property +void wxDynamicClassInfo::RemoveProperty( const wxChar *propertyName ) +{ + for ( wxDynamicObjectList::iterator iter = m_data->m_dynamicObjects.begin() ; iter != m_data->m_dynamicObjects.end() ; ++iter ) + (*iter)->RemoveProperty( propertyName ) ; + delete FindPropertyInfoInThisClass(propertyName) ; +} + +// removes an existing runtime-handler +void wxDynamicClassInfo::RemoveHandler( const wxChar *handlerName ) +{ + delete FindHandlerInfoInThisClass(handlerName) ; +} + +// renames an existing runtime-property +void wxDynamicClassInfo::RenameProperty( const wxChar *oldPropertyName , const wxChar *newPropertyName ) +{ + wxPropertyInfo* pi = FindPropertyInfoInThisClass(oldPropertyName) ; + wxASSERT_MSG( pi ,wxT("not existing property") ) ; + pi->m_name = newPropertyName ; + dynamic_cast(pi->GetAccessor())->RenameProperty( oldPropertyName , newPropertyName ) ; + for ( wxDynamicObjectList::iterator iter = m_data->m_dynamicObjects.begin() ; iter != m_data->m_dynamicObjects.end() ; ++iter ) + (*iter)->RenameProperty( oldPropertyName , newPropertyName ) ; +} + +// renames an existing runtime-handler +void wxDynamicClassInfo::RenameHandler( const wxChar *oldHandlerName , const wxChar *newHandlerName ) +{ + wxASSERT_MSG(FindHandlerInfoInThisClass(oldHandlerName),wxT("not existing handler") ) ; + FindHandlerInfoInThisClass(oldHandlerName)->m_name = newHandlerName ; +} + +// ---------------------------------------------------------------------------- +// wxGenericPropertyAccessor +// ---------------------------------------------------------------------------- + +struct wxGenericPropertyAccessor::wxGenericPropertyAccessorInternal +{ + char filler ; +} ; + +wxGenericPropertyAccessor::wxGenericPropertyAccessor( const wxString& propertyName ) +: wxPropertyAccessor( NULL , NULL , NULL , NULL ) +{ + m_data = new wxGenericPropertyAccessorInternal ; + m_propertyName = propertyName ; + m_getterName = wxT("Get")+propertyName ; + m_setterName = wxT("Set")+propertyName ; +} + +wxGenericPropertyAccessor::~wxGenericPropertyAccessor() +{ + delete m_data ; +} +void wxGenericPropertyAccessor::SetProperty(wxObject *object, const wxxVariant &value) const +{ + wxDynamicObject* dynobj = dynamic_cast< wxDynamicObject * >( object ) ; + wxASSERT_MSG( dynobj , wxT("cannot call wxDynamicClassInfo::SetProperty on an object other than wxDynamicObject") ) ; + dynobj->SetProperty(m_propertyName , value ) ; +} + +void wxGenericPropertyAccessor::GetProperty(const wxObject *object, wxxVariant& value) const +{ + const wxDynamicObject* dynobj = dynamic_cast< const wxDynamicObject * >( object ) ; + wxASSERT_MSG( dynobj , wxT("cannot call wxDynamicClassInfo::SetProperty on an object other than wxDynamicObject") ) ; + value = dynobj->GetProperty( m_propertyName ) ; +} + +#endif // wxUSE_EXTENDED_RTTI diff --git a/Externals/wxWidgets/src/common/xtistrm.cpp b/Externals/wxWidgets/src/common/xtistrm.cpp index b1e7f53cba..eeb0cf4d5c 100644 --- a/Externals/wxWidgets/src/common/xtistrm.cpp +++ b/Externals/wxWidgets/src/common/xtistrm.cpp @@ -1,847 +1,847 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/xtistrm.cpp -// Purpose: streaming runtime metadata information -// Author: Stefan Csomor -// Modified by: -// Created: 27/07/03 -// RCS-ID: $Id: xtistrm.cpp 38939 2006-04-27 12:47:14Z ABX $ -// Copyright: (c) 2003 Stefan Csomor -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_EXTENDED_RTTI - -#include "wx/xtistrm.h" - -#ifndef WX_PRECOMP - #include "wx/object.h" - #include "wx/hash.h" - #include "wx/event.h" -#endif - -#include "wx/tokenzr.h" -#include "wx/txtstrm.h" - -#include "wx/beforestd.h" -#include -#include -#include -#include "wx/afterstd.h" - -using namespace std ; - -struct wxWriter::wxWriterInternal -{ - map< const wxObject* , int > m_writtenObjects ; - int m_nextId ; -} ; - -wxWriter::wxWriter() -{ - m_data = new wxWriterInternal ; - m_data->m_nextId = 0 ; -} - -wxWriter::~wxWriter() -{ - delete m_data ; -} - -struct wxWriter::wxWriterInternalPropertiesData -{ - char nothing ; -} ; - -void wxWriter::ClearObjectContext() -{ - delete m_data ; - m_data = new wxWriterInternal() ; - m_data->m_nextId = 0 ; -} - -void wxWriter::WriteObject(const wxObject *object, const wxClassInfo *classInfo , wxPersister *persister , const wxString &name , wxxVariantArray &metadata ) -{ - DoBeginWriteTopLevelEntry( name ) ; - WriteObject( object , classInfo , persister , false , metadata) ; - DoEndWriteTopLevelEntry( name ) ; -} - -void wxWriter::WriteObject(const wxObject *object, const wxClassInfo *classInfo , wxPersister *persister , bool isEmbedded, wxxVariantArray &metadata ) -{ - if ( !classInfo->BeforeWriteObject( object , this , persister , metadata) ) - return ; - - if ( persister->BeforeWriteObject( this , object , classInfo , metadata) ) - { - if ( object == NULL ) - DoWriteNullObject() ; - else if ( IsObjectKnown( object ) ) - DoWriteRepeatedObject( GetObjectID(object) ) ; - else - { - int oid = m_data->m_nextId++ ; - if ( !isEmbedded ) - m_data->m_writtenObjects[object] = oid ; - - // in case this object is a wxDynamicObject we also have to insert is superclass - // instance with the same id, so that object relations are streamed out correctly - const wxDynamicObject* dynobj = dynamic_cast( object ) ; - if ( !isEmbedded && dynobj ) - m_data->m_writtenObjects[dynobj->GetSuperClassInstance()] = oid ; - - DoBeginWriteObject( object , classInfo , oid , metadata ) ; - wxWriterInternalPropertiesData data ; - WriteAllProperties( object , classInfo , persister , &data ) ; - DoEndWriteObject( object , classInfo , oid ) ; - } - persister->AfterWriteObject( this ,object , classInfo ) ; - } -} - -void wxWriter::FindConnectEntry(const wxEvtHandler * evSource,const wxDelegateTypeInfo* dti, const wxObject* &sink , const wxHandlerInfo *&handler) -{ - wxList *dynamicEvents = evSource->GetDynamicEventTable() ; - - if ( dynamicEvents ) - { - wxList::compatibility_iterator node = dynamicEvents->GetFirst(); - while (node) - { - wxDynamicEventTableEntry *entry = (wxDynamicEventTableEntry*)node->GetData(); - - // find the match - if ( entry->m_fn && - (dti->GetEventType() == entry->m_eventType) && - (entry->m_id == -1 ) && - (entry->m_eventSink != NULL ) ) - { - sink = entry->m_eventSink ; - const wxClassInfo* sinkClassInfo = sink->GetClassInfo() ; - const wxHandlerInfo* sinkHandler = sinkClassInfo->GetFirstHandler() ; - while ( sinkHandler ) - { - if ( sinkHandler->GetEventFunction() == entry->m_fn ) - { - handler = sinkHandler ; - break ; - } - sinkHandler = sinkHandler->GetNext() ; - } - break ; - } - node = node->GetNext(); - } - } -} -void wxWriter::WriteAllProperties( const wxObject * obj , const wxClassInfo* ci , wxPersister *persister, wxWriterInternalPropertiesData * data ) -{ - wxPropertyInfoMap map ; - ci->GetProperties( map ) ; - for ( int i = 0 ; i < ci->GetCreateParamCount() ; ++i ) - { - wxString name = ci->GetCreateParamName(i) ; - const wxPropertyInfo* prop = map.find(name)->second ; - if ( prop ) - { - WriteOneProperty( obj , prop->GetDeclaringClass() , prop , persister , data ) ; - } - else - { - wxLogError( _("Create Parameter not found in declared RTTI Parameters") ) ; - } - map.erase( name ) ; - } - { // Extra block for broken compilers - for( wxPropertyInfoMap::iterator iter = map.begin() ; iter != map.end() ; ++iter ) - { - const wxPropertyInfo* prop = iter->second ; - if ( prop->GetFlags() & wxPROP_OBJECT_GRAPH ) - { - WriteOneProperty( obj , prop->GetDeclaringClass() , prop , persister , data ) ; - } - } - } - { // Extra block for broken compilers - for( wxPropertyInfoMap::iterator iter = map.begin() ; iter != map.end() ; ++iter ) - { - const wxPropertyInfo* prop = iter->second ; - if ( !(prop->GetFlags() & wxPROP_OBJECT_GRAPH) ) - { - WriteOneProperty( obj , prop->GetDeclaringClass() , prop , persister , data ) ; - } - } - } -} - -void wxWriter::WriteOneProperty( const wxObject *obj , const wxClassInfo* ci , const wxPropertyInfo* pi , wxPersister *persister , wxWriterInternalPropertiesData *WXUNUSED(data) ) -{ - if ( pi->GetFlags() & wxPROP_DONT_STREAM ) - return ; - - // make sure that we are picking the correct object for accessing the property - const wxDynamicObject* dynobj = dynamic_cast< const wxDynamicObject* > (obj ) ; - if ( dynobj && (dynamic_cast(ci) == NULL) ) - obj = dynobj->GetSuperClassInstance() ; - - if ( pi->GetTypeInfo()->GetKind() == wxT_COLLECTION ) - { - wxxVariantArray data ; - pi->GetAccessor()->GetPropertyCollection(obj, data) ; - const wxTypeInfo * elementType = dynamic_cast< const wxCollectionTypeInfo* >( pi->GetTypeInfo() )->GetElementType() ; - for ( size_t i = 0 ; i < data.GetCount() ; ++i ) - { - if ( i == 0 ) - DoBeginWriteProperty( pi ) ; - - DoBeginWriteElement() ; - wxxVariant value = data[i] ; - if ( persister->BeforeWriteProperty( this , obj, pi , value ) ) - { - const wxClassTypeInfo* cti = dynamic_cast< const wxClassTypeInfo* > ( elementType ) ; - if ( cti ) - { - const wxClassInfo* pci = cti->GetClassInfo() ; - wxObject *vobj = pci->VariantToInstance( value ) ; - wxxVariantArray md ; - WriteObject( vobj , (vobj ? vobj->GetClassInfo() : pci ) , persister , cti->GetKind()== wxT_OBJECT , md ) ; - } - else - { - DoWriteSimpleType( value ) ; - } - } - DoEndWriteElement() ; - if ( i == data.GetCount() - 1 ) - DoEndWriteProperty( pi ) ; - } - } - else - { - const wxDelegateTypeInfo* dti = dynamic_cast< const wxDelegateTypeInfo* > ( pi->GetTypeInfo() ) ; - if ( dti ) - { - const wxObject* sink = NULL ; - const wxHandlerInfo *handler = NULL ; - - const wxEvtHandler * evSource = dynamic_cast(obj) ; - if ( evSource ) - { - FindConnectEntry( evSource , dti , sink , handler ) ; - if ( persister->BeforeWriteDelegate( this , obj , ci , pi , sink , handler ) ) - { - if ( sink != NULL && handler != NULL ) - { - DoBeginWriteProperty( pi ) ; - if ( IsObjectKnown( sink ) ) - { - DoWriteDelegate( obj , ci , pi , sink , GetObjectID( sink ) , sink->GetClassInfo() , handler ) ; - DoEndWriteProperty( pi ) ; - } - else - { - wxLogError( _("Streaming delegates for not already streamed objects not yet supported") ) ; - } - } - } - } - else - { - wxLogError(_("Illegal Object Class (Non-wxEvtHandler) as Event Source") ) ; - } - } - else - { - wxxVariant value ; - pi->GetAccessor()->GetProperty(obj, value) ; - - // avoid streaming out void objects - if( value.IsEmpty() ) - return ; - - if ( pi->GetFlags() & wxPROP_ENUM_STORE_LONG ) - { - const wxEnumTypeInfo *eti = dynamic_cast( pi->GetTypeInfo() ) ; - if ( eti ) - { - eti->ConvertFromLong( value.wxTEMPLATED_MEMBER_CALL(Get , long) , value ) ; - } - else - { - wxLogError( _("Type must have enum - long conversion") ) ; - } - } - - // avoid streaming out default values - if ( pi->GetTypeInfo()->HasStringConverters() && !pi->GetDefaultValue().IsEmpty() ) - { - if ( value.GetAsString() == pi->GetDefaultValue().GetAsString() ) - return ; - } - - // avoid streaming out null objects - const wxClassTypeInfo* cti = dynamic_cast< const wxClassTypeInfo* > ( pi->GetTypeInfo() ) ; - - if ( cti && value.GetAsObject() == NULL ) - return ; - - if ( persister->BeforeWriteProperty( this , obj, pi , value ) ) - { - DoBeginWriteProperty( pi ) ; - if ( cti ) - { - const wxClassInfo* pci = cti->GetClassInfo() ; - wxObject *vobj = pci->VariantToInstance( value ) ; - if ( vobj && pi->GetTypeInfo()->HasStringConverters() ) - { - wxString stringValue ; - cti->ConvertToString( value , stringValue ) ; - wxxVariant convertedValue(stringValue) ; - DoWriteSimpleType( convertedValue ) ; - } - else - { - wxxVariantArray md ; - WriteObject( vobj , (vobj ? vobj->GetClassInfo() : pci ) , persister , cti->GetKind()== wxT_OBJECT , md) ; - } - } - else - { - DoWriteSimpleType( value ) ; - } - DoEndWriteProperty( pi ) ; - } - } - } -} - -int wxWriter::GetObjectID(const wxObject *obj) -{ - if ( !IsObjectKnown( obj ) ) - return wxInvalidObjectID ; - - return m_data->m_writtenObjects[obj] ; -} - -bool wxWriter::IsObjectKnown( const wxObject *obj ) -{ - return m_data->m_writtenObjects.find( obj ) != m_data->m_writtenObjects.end() ; -} - - -// ---------------------------------------------------------------------------- -// reading objects in -// ---------------------------------------------------------------------------- - -struct wxReader::wxReaderInternal -{ - map m_classInfos; -}; - -wxReader::wxReader() -{ - m_data = new wxReaderInternal; -} - -wxReader::~wxReader() -{ - delete m_data; -} - -wxClassInfo* wxReader::GetObjectClassInfo(int objectID) -{ - if ( objectID == wxNullObjectID || objectID == wxInvalidObjectID ) - { - wxLogError( _("Invalid or Null Object ID passed to GetObjectClassInfo" ) ) ; - return NULL ; - } - if ( m_data->m_classInfos.find(objectID) == m_data->m_classInfos.end() ) - { - wxLogError( _("Unknown Object passed to GetObjectClassInfo" ) ) ; - return NULL ; - } - return m_data->m_classInfos[objectID] ; -} - -void wxReader::SetObjectClassInfo(int objectID, wxClassInfo *classInfo ) -{ - if ( objectID == wxNullObjectID || objectID == wxInvalidObjectID ) - { - wxLogError( _("Invalid or Null Object ID passed to GetObjectClassInfo" ) ) ; - return ; - } - if ( m_data->m_classInfos.find(objectID) != m_data->m_classInfos.end() ) - { - wxLogError( _("Already Registered Object passed to SetObjectClassInfo" ) ) ; - return ; - } - m_data->m_classInfos[objectID] = classInfo ; -} - -bool wxReader::HasObjectClassInfo( int objectID ) -{ - if ( objectID == wxNullObjectID || objectID == wxInvalidObjectID ) - { - wxLogError( _("Invalid or Null Object ID passed to HasObjectClassInfo" ) ) ; - return NULL ; - } - return m_data->m_classInfos.find(objectID) != m_data->m_classInfos.end() ; -} - - -// ---------------------------------------------------------------------------- -// reading xml in -// ---------------------------------------------------------------------------- - -/* -Reading components has not to be extended for components -as properties are always sought by typeinfo over all levels -and create params are always toplevel class only -*/ - - -// ---------------------------------------------------------------------------- -// depersisting to memory -// ---------------------------------------------------------------------------- - -struct wxRuntimeDepersister::wxRuntimeDepersisterInternal -{ - map m_objects; - - void SetObject(int objectID, wxObject *obj ) - { - if ( m_objects.find(objectID) != m_objects.end() ) - { - wxLogError( _("Passing a already registered object to SetObject") ) ; - return ; - } - m_objects[objectID] = obj ; - } - wxObject* GetObject( int objectID ) - { - if ( objectID == wxNullObjectID ) - return NULL ; - if ( m_objects.find(objectID) == m_objects.end() ) - { - wxLogError( _("Passing an unkown object to GetObject") ) ; - return NULL ; - } - - return m_objects[objectID] ; - } -} ; - -wxRuntimeDepersister::wxRuntimeDepersister() -{ - m_data = new wxRuntimeDepersisterInternal() ; -} - -wxRuntimeDepersister::~wxRuntimeDepersister() -{ - delete m_data ; -} - -void wxRuntimeDepersister::AllocateObject(int objectID, wxClassInfo *classInfo , - wxxVariantArray &WXUNUSED(metadata)) -{ - wxObject *O; - O = classInfo->CreateObject(); - m_data->SetObject(objectID, O); -} - -void wxRuntimeDepersister::CreateObject(int objectID, - const wxClassInfo *classInfo, - int paramCount, - wxxVariant *params, - int *objectIdValues, - const wxClassInfo **objectClassInfos , - wxxVariantArray &WXUNUSED(metadata)) -{ - wxObject *o; - o = m_data->GetObject(objectID); - for ( int i = 0 ; i < paramCount ; ++i ) - { - if ( objectIdValues[i] != wxInvalidObjectID ) - { - wxObject *o; - o = m_data->GetObject(objectIdValues[i]); - // if this is a dynamic object and we are asked for another class - // than wxDynamicObject we cast it down manually. - wxDynamicObject *dyno = dynamic_cast< wxDynamicObject * > (o) ; - if ( dyno!=NULL && (objectClassInfos[i] != dyno->GetClassInfo()) ) - { - o = dyno->GetSuperClassInstance() ; - } - params[i] = objectClassInfos[i]->InstanceToVariant(o) ; - } - } - classInfo->Create(o, paramCount, params); -} - -void wxRuntimeDepersister::ConstructObject(int objectID, - const wxClassInfo *classInfo, - int paramCount, - wxxVariant *params, - int *objectIdValues, - const wxClassInfo **objectClassInfos , - wxxVariantArray &WXUNUSED(metadata)) -{ - wxObject *o; - for ( int i = 0 ; i < paramCount ; ++i ) - { - if ( objectIdValues[i] != wxInvalidObjectID ) - { - wxObject *o; - o = m_data->GetObject(objectIdValues[i]); - // if this is a dynamic object and we are asked for another class - // than wxDynamicObject we cast it down manually. - wxDynamicObject *dyno = dynamic_cast< wxDynamicObject * > (o) ; - if ( dyno!=NULL && (objectClassInfos[i] != dyno->GetClassInfo()) ) - { - o = dyno->GetSuperClassInstance() ; - } - params[i] = objectClassInfos[i]->InstanceToVariant(o) ; - } - } - o = classInfo->ConstructObject(paramCount, params); - m_data->SetObject(objectID, o); -} - - -void wxRuntimeDepersister::DestroyObject(int objectID, wxClassInfo *WXUNUSED(classInfo)) -{ - wxObject *o; - o = m_data->GetObject(objectID); - delete o ; -} - -void wxRuntimeDepersister::SetProperty(int objectID, - const wxClassInfo *classInfo, - const wxPropertyInfo* propertyInfo, - const wxxVariant &value) -{ - wxObject *o; - o = m_data->GetObject(objectID); - classInfo->SetProperty( o , propertyInfo->GetName() , value ) ; -} - -void wxRuntimeDepersister::SetPropertyAsObject(int objectID, - const wxClassInfo *classInfo, - const wxPropertyInfo* propertyInfo, - int valueObjectId) -{ - wxObject *o, *valo; - o = m_data->GetObject(objectID); - valo = m_data->GetObject(valueObjectId); - const wxClassInfo* valClassInfo = (dynamic_cast(propertyInfo->GetTypeInfo()))->GetClassInfo() ; - // if this is a dynamic object and we are asked for another class - // than wxDynamicObject we cast it down manually. - wxDynamicObject *dynvalo = dynamic_cast< wxDynamicObject * > (valo) ; - if ( dynvalo!=NULL && (valClassInfo != dynvalo->GetClassInfo()) ) - { - valo = dynvalo->GetSuperClassInstance() ; - } - - classInfo->SetProperty( o , propertyInfo->GetName() , valClassInfo->InstanceToVariant(valo) ) ; -} - -void wxRuntimeDepersister::SetConnect(int eventSourceObjectID, - const wxClassInfo *WXUNUSED(eventSourceClassInfo), - const wxPropertyInfo *delegateInfo , - const wxClassInfo *WXUNUSED(eventSinkClassInfo) , - const wxHandlerInfo* handlerInfo , - int eventSinkObjectID ) -{ - wxEvtHandler *ehsource = dynamic_cast< wxEvtHandler* >( m_data->GetObject( eventSourceObjectID ) ) ; - wxEvtHandler *ehsink = dynamic_cast< wxEvtHandler *>(m_data->GetObject(eventSinkObjectID) ) ; - - if ( ehsource && ehsink ) - { - const wxDelegateTypeInfo *delegateTypeInfo = dynamic_cast(delegateInfo->GetTypeInfo()); - if( delegateTypeInfo && delegateTypeInfo->GetLastEventType() == -1 ) - { - ehsource->Connect( -1 , delegateTypeInfo->GetEventType() , - handlerInfo->GetEventFunction() , NULL /*user data*/ , - ehsink ) ; - } - else - { - for ( wxEventType iter = delegateTypeInfo->GetEventType() ; iter <= delegateTypeInfo->GetLastEventType() ; ++iter ) - { - ehsource->Connect( -1 , iter , - handlerInfo->GetEventFunction() , NULL /*user data*/ , - ehsink ) ; - } - } - } -} - -wxObject *wxRuntimeDepersister::GetObject(int objectID) -{ - return m_data->GetObject( objectID ) ; -} - -// adds an element to a property collection -void wxRuntimeDepersister::AddToPropertyCollection( int objectID , - const wxClassInfo *classInfo, - const wxPropertyInfo* propertyInfo , - const wxxVariant &value) -{ - wxObject *o; - o = m_data->GetObject(objectID); - classInfo->AddToPropertyCollection( o , propertyInfo->GetName() , value ) ; -} - -// sets the corresponding property (value is an object) -void wxRuntimeDepersister::AddToPropertyCollectionAsObject(int objectID, - const wxClassInfo *classInfo, - const wxPropertyInfo* propertyInfo , - int valueObjectId) -{ - wxObject *o, *valo; - o = m_data->GetObject(objectID); - valo = m_data->GetObject(valueObjectId); - const wxCollectionTypeInfo * collectionTypeInfo = dynamic_cast< const wxCollectionTypeInfo * >(propertyInfo->GetTypeInfo() ) ; - const wxClassInfo* valClassInfo = (dynamic_cast(collectionTypeInfo->GetElementType()))->GetClassInfo() ; - // if this is a dynamic object and we are asked for another class - // than wxDynamicObject we cast it down manually. - wxDynamicObject *dynvalo = dynamic_cast< wxDynamicObject * > (valo) ; - if ( dynvalo!=NULL && (valClassInfo != dynvalo->GetClassInfo()) ) - { - valo = dynvalo->GetSuperClassInstance() ; - } - - classInfo->AddToPropertyCollection( o , propertyInfo->GetName() , valClassInfo->InstanceToVariant(valo) ) ; -} - -// ---------------------------------------------------------------------------- -// depersisting to code -// ---------------------------------------------------------------------------- - -struct wxCodeDepersister::wxCodeDepersisterInternal -{ -#if wxUSE_UNICODE - map m_objectNames ; -#else - map m_objectNames ; -#endif - - void SetObjectName(int objectID, const wxString &name ) - { - if ( m_objectNames.find(objectID) != m_objectNames.end() ) - { - wxLogError( _("Passing a already registered object to SetObjectName") ) ; - return ; - } - m_objectNames[objectID] = (const wxChar *)name; - } - - wxString GetObjectName( int objectID ) - { - if ( objectID == wxNullObjectID ) - return wxT("NULL") ; - - if ( m_objectNames.find(objectID) == m_objectNames.end() ) - { - wxLogError( _("Passing an unkown object to GetObject") ) ; - return wxEmptyString ; - } - return wxString( m_objectNames[objectID].c_str() ) ; - } -} ; - -wxCodeDepersister::wxCodeDepersister(wxTextOutputStream *out) -: m_fp(out) -{ - m_data = new wxCodeDepersisterInternal ; -} - -wxCodeDepersister::~wxCodeDepersister() -{ - delete m_data ; -} - -void wxCodeDepersister::AllocateObject(int objectID, wxClassInfo *classInfo , - wxxVariantArray &WXUNUSED(metadata)) -{ - wxString objectName = wxString::Format( wxT("LocalObject_%d") , objectID ) ; - m_fp->WriteString( wxString::Format( wxT("\t%s *%s = new %s;\n"), - classInfo->GetClassName(), - objectName.c_str(), - classInfo->GetClassName()) ); - m_data->SetObjectName( objectID , objectName ) ; -} - -void wxCodeDepersister::DestroyObject(int objectID, wxClassInfo *WXUNUSED(classInfo)) -{ - m_fp->WriteString( wxString::Format( wxT("\tdelete %s;\n"), - m_data->GetObjectName( objectID).c_str() ) ); -} - -wxString wxCodeDepersister::ValueAsCode( const wxxVariant ¶m ) -{ - wxString value ; - const wxTypeInfo* type = param.GetTypeInfo() ; - if ( type->GetKind() == wxT_CUSTOM ) - { - const wxCustomTypeInfo* cti = dynamic_cast(type) ; - if ( cti ) - { - value.Printf( wxT("%s(%s)"), cti->GetTypeName().c_str(),param.GetAsString().c_str() ); - } - else - { - wxLogError ( _("Internal error, illegal wxCustomTypeInfo") ) ; - } - } - else if ( type->GetKind() == wxT_STRING ) - { - value.Printf( wxT("\"%s\""),param.GetAsString().c_str() ); - } - else - { - value.Printf( wxT("%s"), param.GetAsString().c_str() ); - } - return value ; -} - -void wxCodeDepersister::CreateObject(int objectID, - const wxClassInfo *WXUNUSED(classInfo), - int paramCount, - wxxVariant *params, - int *objectIDValues, - const wxClassInfo **WXUNUSED(objectClassInfos) , - wxxVariantArray &WXUNUSED(metadata) - ) -{ - int i; - m_fp->WriteString( wxString::Format( wxT("\t%s->Create("), m_data->GetObjectName(objectID).c_str() ) ); - for (i = 0; i < paramCount; i++) - { - if ( objectIDValues[i] != wxInvalidObjectID ) - m_fp->WriteString( wxString::Format( wxT("%s"), m_data->GetObjectName( objectIDValues[i] ).c_str() ) ); - else - { - m_fp->WriteString( wxString::Format( wxT("%s"), ValueAsCode(params[i]).c_str() ) ); - } - if (i < paramCount - 1) - m_fp->WriteString( wxT(", ")); - } - m_fp->WriteString( wxT(");\n") ); -} - -void wxCodeDepersister::ConstructObject(int objectID, - const wxClassInfo *classInfo, - int paramCount, - wxxVariant *params, - int *objectIDValues, - const wxClassInfo **WXUNUSED(objectClassInfos) , - wxxVariantArray &WXUNUSED(metadata) - ) -{ - wxString objectName = wxString::Format( wxT("LocalObject_%d") , objectID ) ; - m_fp->WriteString( wxString::Format( wxT("\t%s *%s = new %s("), - classInfo->GetClassName(), - objectName.c_str(), - classInfo->GetClassName()) ); - m_data->SetObjectName( objectID , objectName ) ; - - int i; - for (i = 0; i < paramCount; i++) - { - if ( objectIDValues[i] != wxInvalidObjectID ) - m_fp->WriteString( wxString::Format( wxT("%s"), m_data->GetObjectName( objectIDValues[i] ).c_str() ) ); - else - { - m_fp->WriteString( wxString::Format( wxT("%s"), ValueAsCode(params[i]).c_str() ) ); - } - if (i < paramCount - 1) - m_fp->WriteString( wxT(", ") ); - } - m_fp->WriteString( wxT(");\n") ); -} - -void wxCodeDepersister::SetProperty(int objectID, - const wxClassInfo *WXUNUSED(classInfo), - const wxPropertyInfo* propertyInfo, - const wxxVariant &value) -{ - m_fp->WriteString( wxString::Format( wxT("\t%s->%s(%s);\n"), - m_data->GetObjectName(objectID).c_str(), - propertyInfo->GetAccessor()->GetSetterName().c_str(), - ValueAsCode(value).c_str()) ); -} - -void wxCodeDepersister::SetPropertyAsObject(int objectID, - const wxClassInfo *WXUNUSED(classInfo), - const wxPropertyInfo* propertyInfo, - int valueObjectId) -{ - if ( propertyInfo->GetTypeInfo()->GetKind() == wxT_OBJECT ) - m_fp->WriteString( wxString::Format( wxT("\t%s->%s(*%s);\n"), - m_data->GetObjectName(objectID).c_str(), - propertyInfo->GetAccessor()->GetSetterName().c_str(), - m_data->GetObjectName( valueObjectId).c_str() ) ); - else - m_fp->WriteString( wxString::Format( wxT("\t%s->%s(%s);\n"), - m_data->GetObjectName(objectID).c_str(), - propertyInfo->GetAccessor()->GetSetterName().c_str(), - m_data->GetObjectName( valueObjectId).c_str() ) ); -} - -void wxCodeDepersister::AddToPropertyCollection( int objectID , - const wxClassInfo *WXUNUSED(classInfo), - const wxPropertyInfo* propertyInfo , - const wxxVariant &value) -{ - m_fp->WriteString( wxString::Format( wxT("\t%s->%s(%s);\n"), - m_data->GetObjectName(objectID).c_str(), - propertyInfo->GetAccessor()->GetAdderName().c_str(), - ValueAsCode(value).c_str()) ); -} - -// sets the corresponding property (value is an object) -void wxCodeDepersister::AddToPropertyCollectionAsObject(int WXUNUSED(objectID), - const wxClassInfo *WXUNUSED(classInfo), - const wxPropertyInfo* WXUNUSED(propertyInfo) , - int WXUNUSED(valueObjectId)) -{ - // TODO -} - -void wxCodeDepersister::SetConnect(int eventSourceObjectID, - const wxClassInfo *WXUNUSED(eventSourceClassInfo), - const wxPropertyInfo *delegateInfo , - const wxClassInfo *eventSinkClassInfo , - const wxHandlerInfo* handlerInfo , - int eventSinkObjectID ) -{ - wxString ehsource = m_data->GetObjectName( eventSourceObjectID ) ; - wxString ehsink = m_data->GetObjectName(eventSinkObjectID) ; - wxString ehsinkClass = eventSinkClassInfo->GetClassName() ; - const wxDelegateTypeInfo *delegateTypeInfo = dynamic_cast(delegateInfo->GetTypeInfo()); - if ( delegateTypeInfo ) - { - int eventType = delegateTypeInfo->GetEventType() ; - wxString handlerName = handlerInfo->GetName() ; - - m_fp->WriteString( wxString::Format( wxT("\t%s->Connect( %s->GetId() , %d , (wxObjectEventFunction)(wxEventFunction) & %s::%s , NULL , %s ) ;") , - ehsource.c_str() , ehsource.c_str() , eventType , ehsinkClass.c_str() , handlerName.c_str() , ehsink.c_str() ) ); - } - else - { - wxLogError(_("delegate has no type info")); - } -} - -#include "wx/arrimpl.cpp" - -WX_DEFINE_OBJARRAY(wxxVariantArray); - -#endif // wxUSE_EXTENDED_RTTI +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/xtistrm.cpp +// Purpose: streaming runtime metadata information +// Author: Stefan Csomor +// Modified by: +// Created: 27/07/03 +// RCS-ID: $Id: xtistrm.cpp 38939 2006-04-27 12:47:14Z ABX $ +// Copyright: (c) 2003 Stefan Csomor +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_EXTENDED_RTTI + +#include "wx/xtistrm.h" + +#ifndef WX_PRECOMP + #include "wx/object.h" + #include "wx/hash.h" + #include "wx/event.h" +#endif + +#include "wx/tokenzr.h" +#include "wx/txtstrm.h" + +#include "wx/beforestd.h" +#include +#include +#include +#include "wx/afterstd.h" + +using namespace std ; + +struct wxWriter::wxWriterInternal +{ + map< const wxObject* , int > m_writtenObjects ; + int m_nextId ; +} ; + +wxWriter::wxWriter() +{ + m_data = new wxWriterInternal ; + m_data->m_nextId = 0 ; +} + +wxWriter::~wxWriter() +{ + delete m_data ; +} + +struct wxWriter::wxWriterInternalPropertiesData +{ + char nothing ; +} ; + +void wxWriter::ClearObjectContext() +{ + delete m_data ; + m_data = new wxWriterInternal() ; + m_data->m_nextId = 0 ; +} + +void wxWriter::WriteObject(const wxObject *object, const wxClassInfo *classInfo , wxPersister *persister , const wxString &name , wxxVariantArray &metadata ) +{ + DoBeginWriteTopLevelEntry( name ) ; + WriteObject( object , classInfo , persister , false , metadata) ; + DoEndWriteTopLevelEntry( name ) ; +} + +void wxWriter::WriteObject(const wxObject *object, const wxClassInfo *classInfo , wxPersister *persister , bool isEmbedded, wxxVariantArray &metadata ) +{ + if ( !classInfo->BeforeWriteObject( object , this , persister , metadata) ) + return ; + + if ( persister->BeforeWriteObject( this , object , classInfo , metadata) ) + { + if ( object == NULL ) + DoWriteNullObject() ; + else if ( IsObjectKnown( object ) ) + DoWriteRepeatedObject( GetObjectID(object) ) ; + else + { + int oid = m_data->m_nextId++ ; + if ( !isEmbedded ) + m_data->m_writtenObjects[object] = oid ; + + // in case this object is a wxDynamicObject we also have to insert is superclass + // instance with the same id, so that object relations are streamed out correctly + const wxDynamicObject* dynobj = dynamic_cast( object ) ; + if ( !isEmbedded && dynobj ) + m_data->m_writtenObjects[dynobj->GetSuperClassInstance()] = oid ; + + DoBeginWriteObject( object , classInfo , oid , metadata ) ; + wxWriterInternalPropertiesData data ; + WriteAllProperties( object , classInfo , persister , &data ) ; + DoEndWriteObject( object , classInfo , oid ) ; + } + persister->AfterWriteObject( this ,object , classInfo ) ; + } +} + +void wxWriter::FindConnectEntry(const wxEvtHandler * evSource,const wxDelegateTypeInfo* dti, const wxObject* &sink , const wxHandlerInfo *&handler) +{ + wxList *dynamicEvents = evSource->GetDynamicEventTable() ; + + if ( dynamicEvents ) + { + wxList::compatibility_iterator node = dynamicEvents->GetFirst(); + while (node) + { + wxDynamicEventTableEntry *entry = (wxDynamicEventTableEntry*)node->GetData(); + + // find the match + if ( entry->m_fn && + (dti->GetEventType() == entry->m_eventType) && + (entry->m_id == -1 ) && + (entry->m_eventSink != NULL ) ) + { + sink = entry->m_eventSink ; + const wxClassInfo* sinkClassInfo = sink->GetClassInfo() ; + const wxHandlerInfo* sinkHandler = sinkClassInfo->GetFirstHandler() ; + while ( sinkHandler ) + { + if ( sinkHandler->GetEventFunction() == entry->m_fn ) + { + handler = sinkHandler ; + break ; + } + sinkHandler = sinkHandler->GetNext() ; + } + break ; + } + node = node->GetNext(); + } + } +} +void wxWriter::WriteAllProperties( const wxObject * obj , const wxClassInfo* ci , wxPersister *persister, wxWriterInternalPropertiesData * data ) +{ + wxPropertyInfoMap map ; + ci->GetProperties( map ) ; + for ( int i = 0 ; i < ci->GetCreateParamCount() ; ++i ) + { + wxString name = ci->GetCreateParamName(i) ; + const wxPropertyInfo* prop = map.find(name)->second ; + if ( prop ) + { + WriteOneProperty( obj , prop->GetDeclaringClass() , prop , persister , data ) ; + } + else + { + wxLogError( _("Create Parameter not found in declared RTTI Parameters") ) ; + } + map.erase( name ) ; + } + { // Extra block for broken compilers + for( wxPropertyInfoMap::iterator iter = map.begin() ; iter != map.end() ; ++iter ) + { + const wxPropertyInfo* prop = iter->second ; + if ( prop->GetFlags() & wxPROP_OBJECT_GRAPH ) + { + WriteOneProperty( obj , prop->GetDeclaringClass() , prop , persister , data ) ; + } + } + } + { // Extra block for broken compilers + for( wxPropertyInfoMap::iterator iter = map.begin() ; iter != map.end() ; ++iter ) + { + const wxPropertyInfo* prop = iter->second ; + if ( !(prop->GetFlags() & wxPROP_OBJECT_GRAPH) ) + { + WriteOneProperty( obj , prop->GetDeclaringClass() , prop , persister , data ) ; + } + } + } +} + +void wxWriter::WriteOneProperty( const wxObject *obj , const wxClassInfo* ci , const wxPropertyInfo* pi , wxPersister *persister , wxWriterInternalPropertiesData *WXUNUSED(data) ) +{ + if ( pi->GetFlags() & wxPROP_DONT_STREAM ) + return ; + + // make sure that we are picking the correct object for accessing the property + const wxDynamicObject* dynobj = dynamic_cast< const wxDynamicObject* > (obj ) ; + if ( dynobj && (dynamic_cast(ci) == NULL) ) + obj = dynobj->GetSuperClassInstance() ; + + if ( pi->GetTypeInfo()->GetKind() == wxT_COLLECTION ) + { + wxxVariantArray data ; + pi->GetAccessor()->GetPropertyCollection(obj, data) ; + const wxTypeInfo * elementType = dynamic_cast< const wxCollectionTypeInfo* >( pi->GetTypeInfo() )->GetElementType() ; + for ( size_t i = 0 ; i < data.GetCount() ; ++i ) + { + if ( i == 0 ) + DoBeginWriteProperty( pi ) ; + + DoBeginWriteElement() ; + wxxVariant value = data[i] ; + if ( persister->BeforeWriteProperty( this , obj, pi , value ) ) + { + const wxClassTypeInfo* cti = dynamic_cast< const wxClassTypeInfo* > ( elementType ) ; + if ( cti ) + { + const wxClassInfo* pci = cti->GetClassInfo() ; + wxObject *vobj = pci->VariantToInstance( value ) ; + wxxVariantArray md ; + WriteObject( vobj , (vobj ? vobj->GetClassInfo() : pci ) , persister , cti->GetKind()== wxT_OBJECT , md ) ; + } + else + { + DoWriteSimpleType( value ) ; + } + } + DoEndWriteElement() ; + if ( i == data.GetCount() - 1 ) + DoEndWriteProperty( pi ) ; + } + } + else + { + const wxDelegateTypeInfo* dti = dynamic_cast< const wxDelegateTypeInfo* > ( pi->GetTypeInfo() ) ; + if ( dti ) + { + const wxObject* sink = NULL ; + const wxHandlerInfo *handler = NULL ; + + const wxEvtHandler * evSource = dynamic_cast(obj) ; + if ( evSource ) + { + FindConnectEntry( evSource , dti , sink , handler ) ; + if ( persister->BeforeWriteDelegate( this , obj , ci , pi , sink , handler ) ) + { + if ( sink != NULL && handler != NULL ) + { + DoBeginWriteProperty( pi ) ; + if ( IsObjectKnown( sink ) ) + { + DoWriteDelegate( obj , ci , pi , sink , GetObjectID( sink ) , sink->GetClassInfo() , handler ) ; + DoEndWriteProperty( pi ) ; + } + else + { + wxLogError( _("Streaming delegates for not already streamed objects not yet supported") ) ; + } + } + } + } + else + { + wxLogError(_("Illegal Object Class (Non-wxEvtHandler) as Event Source") ) ; + } + } + else + { + wxxVariant value ; + pi->GetAccessor()->GetProperty(obj, value) ; + + // avoid streaming out void objects + if( value.IsEmpty() ) + return ; + + if ( pi->GetFlags() & wxPROP_ENUM_STORE_LONG ) + { + const wxEnumTypeInfo *eti = dynamic_cast( pi->GetTypeInfo() ) ; + if ( eti ) + { + eti->ConvertFromLong( value.wxTEMPLATED_MEMBER_CALL(Get , long) , value ) ; + } + else + { + wxLogError( _("Type must have enum - long conversion") ) ; + } + } + + // avoid streaming out default values + if ( pi->GetTypeInfo()->HasStringConverters() && !pi->GetDefaultValue().IsEmpty() ) + { + if ( value.GetAsString() == pi->GetDefaultValue().GetAsString() ) + return ; + } + + // avoid streaming out null objects + const wxClassTypeInfo* cti = dynamic_cast< const wxClassTypeInfo* > ( pi->GetTypeInfo() ) ; + + if ( cti && value.GetAsObject() == NULL ) + return ; + + if ( persister->BeforeWriteProperty( this , obj, pi , value ) ) + { + DoBeginWriteProperty( pi ) ; + if ( cti ) + { + const wxClassInfo* pci = cti->GetClassInfo() ; + wxObject *vobj = pci->VariantToInstance( value ) ; + if ( vobj && pi->GetTypeInfo()->HasStringConverters() ) + { + wxString stringValue ; + cti->ConvertToString( value , stringValue ) ; + wxxVariant convertedValue(stringValue) ; + DoWriteSimpleType( convertedValue ) ; + } + else + { + wxxVariantArray md ; + WriteObject( vobj , (vobj ? vobj->GetClassInfo() : pci ) , persister , cti->GetKind()== wxT_OBJECT , md) ; + } + } + else + { + DoWriteSimpleType( value ) ; + } + DoEndWriteProperty( pi ) ; + } + } + } +} + +int wxWriter::GetObjectID(const wxObject *obj) +{ + if ( !IsObjectKnown( obj ) ) + return wxInvalidObjectID ; + + return m_data->m_writtenObjects[obj] ; +} + +bool wxWriter::IsObjectKnown( const wxObject *obj ) +{ + return m_data->m_writtenObjects.find( obj ) != m_data->m_writtenObjects.end() ; +} + + +// ---------------------------------------------------------------------------- +// reading objects in +// ---------------------------------------------------------------------------- + +struct wxReader::wxReaderInternal +{ + map m_classInfos; +}; + +wxReader::wxReader() +{ + m_data = new wxReaderInternal; +} + +wxReader::~wxReader() +{ + delete m_data; +} + +wxClassInfo* wxReader::GetObjectClassInfo(int objectID) +{ + if ( objectID == wxNullObjectID || objectID == wxInvalidObjectID ) + { + wxLogError( _("Invalid or Null Object ID passed to GetObjectClassInfo" ) ) ; + return NULL ; + } + if ( m_data->m_classInfos.find(objectID) == m_data->m_classInfos.end() ) + { + wxLogError( _("Unknown Object passed to GetObjectClassInfo" ) ) ; + return NULL ; + } + return m_data->m_classInfos[objectID] ; +} + +void wxReader::SetObjectClassInfo(int objectID, wxClassInfo *classInfo ) +{ + if ( objectID == wxNullObjectID || objectID == wxInvalidObjectID ) + { + wxLogError( _("Invalid or Null Object ID passed to GetObjectClassInfo" ) ) ; + return ; + } + if ( m_data->m_classInfos.find(objectID) != m_data->m_classInfos.end() ) + { + wxLogError( _("Already Registered Object passed to SetObjectClassInfo" ) ) ; + return ; + } + m_data->m_classInfos[objectID] = classInfo ; +} + +bool wxReader::HasObjectClassInfo( int objectID ) +{ + if ( objectID == wxNullObjectID || objectID == wxInvalidObjectID ) + { + wxLogError( _("Invalid or Null Object ID passed to HasObjectClassInfo" ) ) ; + return NULL ; + } + return m_data->m_classInfos.find(objectID) != m_data->m_classInfos.end() ; +} + + +// ---------------------------------------------------------------------------- +// reading xml in +// ---------------------------------------------------------------------------- + +/* +Reading components has not to be extended for components +as properties are always sought by typeinfo over all levels +and create params are always toplevel class only +*/ + + +// ---------------------------------------------------------------------------- +// depersisting to memory +// ---------------------------------------------------------------------------- + +struct wxRuntimeDepersister::wxRuntimeDepersisterInternal +{ + map m_objects; + + void SetObject(int objectID, wxObject *obj ) + { + if ( m_objects.find(objectID) != m_objects.end() ) + { + wxLogError( _("Passing a already registered object to SetObject") ) ; + return ; + } + m_objects[objectID] = obj ; + } + wxObject* GetObject( int objectID ) + { + if ( objectID == wxNullObjectID ) + return NULL ; + if ( m_objects.find(objectID) == m_objects.end() ) + { + wxLogError( _("Passing an unkown object to GetObject") ) ; + return NULL ; + } + + return m_objects[objectID] ; + } +} ; + +wxRuntimeDepersister::wxRuntimeDepersister() +{ + m_data = new wxRuntimeDepersisterInternal() ; +} + +wxRuntimeDepersister::~wxRuntimeDepersister() +{ + delete m_data ; +} + +void wxRuntimeDepersister::AllocateObject(int objectID, wxClassInfo *classInfo , + wxxVariantArray &WXUNUSED(metadata)) +{ + wxObject *O; + O = classInfo->CreateObject(); + m_data->SetObject(objectID, O); +} + +void wxRuntimeDepersister::CreateObject(int objectID, + const wxClassInfo *classInfo, + int paramCount, + wxxVariant *params, + int *objectIdValues, + const wxClassInfo **objectClassInfos , + wxxVariantArray &WXUNUSED(metadata)) +{ + wxObject *o; + o = m_data->GetObject(objectID); + for ( int i = 0 ; i < paramCount ; ++i ) + { + if ( objectIdValues[i] != wxInvalidObjectID ) + { + wxObject *o; + o = m_data->GetObject(objectIdValues[i]); + // if this is a dynamic object and we are asked for another class + // than wxDynamicObject we cast it down manually. + wxDynamicObject *dyno = dynamic_cast< wxDynamicObject * > (o) ; + if ( dyno!=NULL && (objectClassInfos[i] != dyno->GetClassInfo()) ) + { + o = dyno->GetSuperClassInstance() ; + } + params[i] = objectClassInfos[i]->InstanceToVariant(o) ; + } + } + classInfo->Create(o, paramCount, params); +} + +void wxRuntimeDepersister::ConstructObject(int objectID, + const wxClassInfo *classInfo, + int paramCount, + wxxVariant *params, + int *objectIdValues, + const wxClassInfo **objectClassInfos , + wxxVariantArray &WXUNUSED(metadata)) +{ + wxObject *o; + for ( int i = 0 ; i < paramCount ; ++i ) + { + if ( objectIdValues[i] != wxInvalidObjectID ) + { + wxObject *o; + o = m_data->GetObject(objectIdValues[i]); + // if this is a dynamic object and we are asked for another class + // than wxDynamicObject we cast it down manually. + wxDynamicObject *dyno = dynamic_cast< wxDynamicObject * > (o) ; + if ( dyno!=NULL && (objectClassInfos[i] != dyno->GetClassInfo()) ) + { + o = dyno->GetSuperClassInstance() ; + } + params[i] = objectClassInfos[i]->InstanceToVariant(o) ; + } + } + o = classInfo->ConstructObject(paramCount, params); + m_data->SetObject(objectID, o); +} + + +void wxRuntimeDepersister::DestroyObject(int objectID, wxClassInfo *WXUNUSED(classInfo)) +{ + wxObject *o; + o = m_data->GetObject(objectID); + delete o ; +} + +void wxRuntimeDepersister::SetProperty(int objectID, + const wxClassInfo *classInfo, + const wxPropertyInfo* propertyInfo, + const wxxVariant &value) +{ + wxObject *o; + o = m_data->GetObject(objectID); + classInfo->SetProperty( o , propertyInfo->GetName() , value ) ; +} + +void wxRuntimeDepersister::SetPropertyAsObject(int objectID, + const wxClassInfo *classInfo, + const wxPropertyInfo* propertyInfo, + int valueObjectId) +{ + wxObject *o, *valo; + o = m_data->GetObject(objectID); + valo = m_data->GetObject(valueObjectId); + const wxClassInfo* valClassInfo = (dynamic_cast(propertyInfo->GetTypeInfo()))->GetClassInfo() ; + // if this is a dynamic object and we are asked for another class + // than wxDynamicObject we cast it down manually. + wxDynamicObject *dynvalo = dynamic_cast< wxDynamicObject * > (valo) ; + if ( dynvalo!=NULL && (valClassInfo != dynvalo->GetClassInfo()) ) + { + valo = dynvalo->GetSuperClassInstance() ; + } + + classInfo->SetProperty( o , propertyInfo->GetName() , valClassInfo->InstanceToVariant(valo) ) ; +} + +void wxRuntimeDepersister::SetConnect(int eventSourceObjectID, + const wxClassInfo *WXUNUSED(eventSourceClassInfo), + const wxPropertyInfo *delegateInfo , + const wxClassInfo *WXUNUSED(eventSinkClassInfo) , + const wxHandlerInfo* handlerInfo , + int eventSinkObjectID ) +{ + wxEvtHandler *ehsource = dynamic_cast< wxEvtHandler* >( m_data->GetObject( eventSourceObjectID ) ) ; + wxEvtHandler *ehsink = dynamic_cast< wxEvtHandler *>(m_data->GetObject(eventSinkObjectID) ) ; + + if ( ehsource && ehsink ) + { + const wxDelegateTypeInfo *delegateTypeInfo = dynamic_cast(delegateInfo->GetTypeInfo()); + if( delegateTypeInfo && delegateTypeInfo->GetLastEventType() == -1 ) + { + ehsource->Connect( -1 , delegateTypeInfo->GetEventType() , + handlerInfo->GetEventFunction() , NULL /*user data*/ , + ehsink ) ; + } + else + { + for ( wxEventType iter = delegateTypeInfo->GetEventType() ; iter <= delegateTypeInfo->GetLastEventType() ; ++iter ) + { + ehsource->Connect( -1 , iter , + handlerInfo->GetEventFunction() , NULL /*user data*/ , + ehsink ) ; + } + } + } +} + +wxObject *wxRuntimeDepersister::GetObject(int objectID) +{ + return m_data->GetObject( objectID ) ; +} + +// adds an element to a property collection +void wxRuntimeDepersister::AddToPropertyCollection( int objectID , + const wxClassInfo *classInfo, + const wxPropertyInfo* propertyInfo , + const wxxVariant &value) +{ + wxObject *o; + o = m_data->GetObject(objectID); + classInfo->AddToPropertyCollection( o , propertyInfo->GetName() , value ) ; +} + +// sets the corresponding property (value is an object) +void wxRuntimeDepersister::AddToPropertyCollectionAsObject(int objectID, + const wxClassInfo *classInfo, + const wxPropertyInfo* propertyInfo , + int valueObjectId) +{ + wxObject *o, *valo; + o = m_data->GetObject(objectID); + valo = m_data->GetObject(valueObjectId); + const wxCollectionTypeInfo * collectionTypeInfo = dynamic_cast< const wxCollectionTypeInfo * >(propertyInfo->GetTypeInfo() ) ; + const wxClassInfo* valClassInfo = (dynamic_cast(collectionTypeInfo->GetElementType()))->GetClassInfo() ; + // if this is a dynamic object and we are asked for another class + // than wxDynamicObject we cast it down manually. + wxDynamicObject *dynvalo = dynamic_cast< wxDynamicObject * > (valo) ; + if ( dynvalo!=NULL && (valClassInfo != dynvalo->GetClassInfo()) ) + { + valo = dynvalo->GetSuperClassInstance() ; + } + + classInfo->AddToPropertyCollection( o , propertyInfo->GetName() , valClassInfo->InstanceToVariant(valo) ) ; +} + +// ---------------------------------------------------------------------------- +// depersisting to code +// ---------------------------------------------------------------------------- + +struct wxCodeDepersister::wxCodeDepersisterInternal +{ +#if wxUSE_UNICODE + map m_objectNames ; +#else + map m_objectNames ; +#endif + + void SetObjectName(int objectID, const wxString &name ) + { + if ( m_objectNames.find(objectID) != m_objectNames.end() ) + { + wxLogError( _("Passing a already registered object to SetObjectName") ) ; + return ; + } + m_objectNames[objectID] = (const wxChar *)name; + } + + wxString GetObjectName( int objectID ) + { + if ( objectID == wxNullObjectID ) + return wxT("NULL") ; + + if ( m_objectNames.find(objectID) == m_objectNames.end() ) + { + wxLogError( _("Passing an unkown object to GetObject") ) ; + return wxEmptyString ; + } + return wxString( m_objectNames[objectID].c_str() ) ; + } +} ; + +wxCodeDepersister::wxCodeDepersister(wxTextOutputStream *out) +: m_fp(out) +{ + m_data = new wxCodeDepersisterInternal ; +} + +wxCodeDepersister::~wxCodeDepersister() +{ + delete m_data ; +} + +void wxCodeDepersister::AllocateObject(int objectID, wxClassInfo *classInfo , + wxxVariantArray &WXUNUSED(metadata)) +{ + wxString objectName = wxString::Format( wxT("LocalObject_%d") , objectID ) ; + m_fp->WriteString( wxString::Format( wxT("\t%s *%s = new %s;\n"), + classInfo->GetClassName(), + objectName.c_str(), + classInfo->GetClassName()) ); + m_data->SetObjectName( objectID , objectName ) ; +} + +void wxCodeDepersister::DestroyObject(int objectID, wxClassInfo *WXUNUSED(classInfo)) +{ + m_fp->WriteString( wxString::Format( wxT("\tdelete %s;\n"), + m_data->GetObjectName( objectID).c_str() ) ); +} + +wxString wxCodeDepersister::ValueAsCode( const wxxVariant ¶m ) +{ + wxString value ; + const wxTypeInfo* type = param.GetTypeInfo() ; + if ( type->GetKind() == wxT_CUSTOM ) + { + const wxCustomTypeInfo* cti = dynamic_cast(type) ; + if ( cti ) + { + value.Printf( wxT("%s(%s)"), cti->GetTypeName().c_str(),param.GetAsString().c_str() ); + } + else + { + wxLogError ( _("Internal error, illegal wxCustomTypeInfo") ) ; + } + } + else if ( type->GetKind() == wxT_STRING ) + { + value.Printf( wxT("\"%s\""),param.GetAsString().c_str() ); + } + else + { + value.Printf( wxT("%s"), param.GetAsString().c_str() ); + } + return value ; +} + +void wxCodeDepersister::CreateObject(int objectID, + const wxClassInfo *WXUNUSED(classInfo), + int paramCount, + wxxVariant *params, + int *objectIDValues, + const wxClassInfo **WXUNUSED(objectClassInfos) , + wxxVariantArray &WXUNUSED(metadata) + ) +{ + int i; + m_fp->WriteString( wxString::Format( wxT("\t%s->Create("), m_data->GetObjectName(objectID).c_str() ) ); + for (i = 0; i < paramCount; i++) + { + if ( objectIDValues[i] != wxInvalidObjectID ) + m_fp->WriteString( wxString::Format( wxT("%s"), m_data->GetObjectName( objectIDValues[i] ).c_str() ) ); + else + { + m_fp->WriteString( wxString::Format( wxT("%s"), ValueAsCode(params[i]).c_str() ) ); + } + if (i < paramCount - 1) + m_fp->WriteString( wxT(", ")); + } + m_fp->WriteString( wxT(");\n") ); +} + +void wxCodeDepersister::ConstructObject(int objectID, + const wxClassInfo *classInfo, + int paramCount, + wxxVariant *params, + int *objectIDValues, + const wxClassInfo **WXUNUSED(objectClassInfos) , + wxxVariantArray &WXUNUSED(metadata) + ) +{ + wxString objectName = wxString::Format( wxT("LocalObject_%d") , objectID ) ; + m_fp->WriteString( wxString::Format( wxT("\t%s *%s = new %s("), + classInfo->GetClassName(), + objectName.c_str(), + classInfo->GetClassName()) ); + m_data->SetObjectName( objectID , objectName ) ; + + int i; + for (i = 0; i < paramCount; i++) + { + if ( objectIDValues[i] != wxInvalidObjectID ) + m_fp->WriteString( wxString::Format( wxT("%s"), m_data->GetObjectName( objectIDValues[i] ).c_str() ) ); + else + { + m_fp->WriteString( wxString::Format( wxT("%s"), ValueAsCode(params[i]).c_str() ) ); + } + if (i < paramCount - 1) + m_fp->WriteString( wxT(", ") ); + } + m_fp->WriteString( wxT(");\n") ); +} + +void wxCodeDepersister::SetProperty(int objectID, + const wxClassInfo *WXUNUSED(classInfo), + const wxPropertyInfo* propertyInfo, + const wxxVariant &value) +{ + m_fp->WriteString( wxString::Format( wxT("\t%s->%s(%s);\n"), + m_data->GetObjectName(objectID).c_str(), + propertyInfo->GetAccessor()->GetSetterName().c_str(), + ValueAsCode(value).c_str()) ); +} + +void wxCodeDepersister::SetPropertyAsObject(int objectID, + const wxClassInfo *WXUNUSED(classInfo), + const wxPropertyInfo* propertyInfo, + int valueObjectId) +{ + if ( propertyInfo->GetTypeInfo()->GetKind() == wxT_OBJECT ) + m_fp->WriteString( wxString::Format( wxT("\t%s->%s(*%s);\n"), + m_data->GetObjectName(objectID).c_str(), + propertyInfo->GetAccessor()->GetSetterName().c_str(), + m_data->GetObjectName( valueObjectId).c_str() ) ); + else + m_fp->WriteString( wxString::Format( wxT("\t%s->%s(%s);\n"), + m_data->GetObjectName(objectID).c_str(), + propertyInfo->GetAccessor()->GetSetterName().c_str(), + m_data->GetObjectName( valueObjectId).c_str() ) ); +} + +void wxCodeDepersister::AddToPropertyCollection( int objectID , + const wxClassInfo *WXUNUSED(classInfo), + const wxPropertyInfo* propertyInfo , + const wxxVariant &value) +{ + m_fp->WriteString( wxString::Format( wxT("\t%s->%s(%s);\n"), + m_data->GetObjectName(objectID).c_str(), + propertyInfo->GetAccessor()->GetAdderName().c_str(), + ValueAsCode(value).c_str()) ); +} + +// sets the corresponding property (value is an object) +void wxCodeDepersister::AddToPropertyCollectionAsObject(int WXUNUSED(objectID), + const wxClassInfo *WXUNUSED(classInfo), + const wxPropertyInfo* WXUNUSED(propertyInfo) , + int WXUNUSED(valueObjectId)) +{ + // TODO +} + +void wxCodeDepersister::SetConnect(int eventSourceObjectID, + const wxClassInfo *WXUNUSED(eventSourceClassInfo), + const wxPropertyInfo *delegateInfo , + const wxClassInfo *eventSinkClassInfo , + const wxHandlerInfo* handlerInfo , + int eventSinkObjectID ) +{ + wxString ehsource = m_data->GetObjectName( eventSourceObjectID ) ; + wxString ehsink = m_data->GetObjectName(eventSinkObjectID) ; + wxString ehsinkClass = eventSinkClassInfo->GetClassName() ; + const wxDelegateTypeInfo *delegateTypeInfo = dynamic_cast(delegateInfo->GetTypeInfo()); + if ( delegateTypeInfo ) + { + int eventType = delegateTypeInfo->GetEventType() ; + wxString handlerName = handlerInfo->GetName() ; + + m_fp->WriteString( wxString::Format( wxT("\t%s->Connect( %s->GetId() , %d , (wxObjectEventFunction)(wxEventFunction) & %s::%s , NULL , %s ) ;") , + ehsource.c_str() , ehsource.c_str() , eventType , ehsinkClass.c_str() , handlerName.c_str() , ehsink.c_str() ) ); + } + else + { + wxLogError(_("delegate has no type info")); + } +} + +#include "wx/arrimpl.cpp" + +WX_DEFINE_OBJARRAY(wxxVariantArray); + +#endif // wxUSE_EXTENDED_RTTI diff --git a/Externals/wxWidgets/src/common/xtixml.cpp b/Externals/wxWidgets/src/common/xtixml.cpp index 43a526046f..d229071cad 100644 --- a/Externals/wxWidgets/src/common/xtixml.cpp +++ b/Externals/wxWidgets/src/common/xtixml.cpp @@ -1,538 +1,538 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/xtixml.cpp -// Purpose: streaming runtime metadata information -// Author: Stefan Csomor -// Modified by: -// Created: 27/07/03 -// RCS-ID: $Id: xtixml.cpp 38939 2006-04-27 12:47:14Z ABX $ -// Copyright: (c) 2003 Stefan Csomor -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_EXTENDED_RTTI - -#include "wx/xtixml.h" - -#ifndef WX_PRECOMP - #include "wx/object.h" - #include "wx/hash.h" - #include "wx/event.h" -#endif - -#include "wx/xml/xml.h" -#include "wx/tokenzr.h" -#include "wx/txtstrm.h" - -#include "wx/xtistrm.h" - -#include "wx/beforestd.h" -#include -#include -#include -#include "wx/afterstd.h" - -using namespace std ; - -// -// XML Streaming -// - -// convenience functions - -void wxXmlAddContentToNode( wxXmlNode* node , const wxString& data ) -{ - node->AddChild(new wxXmlNode(wxXML_TEXT_NODE, wxT("value"), data ) ); -} - -wxString wxXmlGetContentFromNode( wxXmlNode *node ) -{ - if ( node->GetChildren() ) - return node->GetChildren()->GetContent() ; - else - return wxEmptyString ; -} - -struct wxXmlWriter::wxXmlWriterInternal -{ - wxXmlNode *m_root ; - wxXmlNode *m_current ; - vector< wxXmlNode * > m_objectStack ; - - void Push( wxXmlNode *newCurrent ) - { - m_objectStack.push_back( m_current ) ; - m_current = newCurrent ; - } - - void Pop() - { - m_current = m_objectStack.back() ; - m_objectStack.pop_back() ; - } -} ; - -wxXmlWriter::wxXmlWriter( wxXmlNode * rootnode ) -{ - m_data = new wxXmlWriterInternal() ; - m_data->m_root = rootnode ; - m_data->m_current = rootnode ; -} - -wxXmlWriter::~wxXmlWriter() -{ - delete m_data ; -} - -void wxXmlWriter::DoBeginWriteTopLevelEntry( const wxString &name ) -{ - wxXmlNode *pnode; - pnode = new wxXmlNode(wxXML_ELEMENT_NODE, wxT("entry")); - pnode->AddProperty(wxString(wxT("name")), name); - m_data->m_current->AddChild(pnode) ; - m_data->Push( pnode ) ; -} - -void wxXmlWriter::DoEndWriteTopLevelEntry( const wxString &WXUNUSED(name) ) -{ - m_data->Pop() ; -} - -void wxXmlWriter::DoBeginWriteObject(const wxObject *WXUNUSED(object), const wxClassInfo *classInfo, int objectID , wxxVariantArray &metadata ) -{ - wxXmlNode *pnode; - pnode = new wxXmlNode(wxXML_ELEMENT_NODE, wxT("object")); - pnode->AddProperty(wxT("class"), wxString(classInfo->GetClassName())); - pnode->AddProperty(wxT("id"), wxString::Format( wxT("%d") , objectID ) ); - - for ( size_t i = 0 ; i < metadata.GetCount() ; ++i ) - { - pnode->AddProperty( metadata[i].GetName() , metadata[i].GetAsString() ) ; - } - m_data->m_current->AddChild(pnode) ; - m_data->Push( pnode ) ; -} - -// end of writing the root object -void wxXmlWriter::DoEndWriteObject(const wxObject *WXUNUSED(object), const wxClassInfo *WXUNUSED(classInfo), int WXUNUSED(objectID) ) -{ - m_data->Pop() ; -} - -// writes a property in the stream format -void wxXmlWriter::DoWriteSimpleType( wxxVariant &value ) -{ - wxXmlAddContentToNode( m_data->m_current ,value.GetAsString() ) ; -} - -void wxXmlWriter::DoBeginWriteElement() -{ - wxXmlNode *pnode; - pnode = new wxXmlNode(wxXML_ELEMENT_NODE, wxT("element") ); - m_data->m_current->AddChild(pnode) ; - m_data->Push( pnode ) ; -} - -void wxXmlWriter::DoEndWriteElement() -{ - m_data->Pop() ; -} - -void wxXmlWriter::DoBeginWriteProperty(const wxPropertyInfo *pi ) -{ - wxXmlNode *pnode; - pnode = new wxXmlNode(wxXML_ELEMENT_NODE, wxT("prop") ); - pnode->AddProperty(wxT("name"), pi->GetName() ); - m_data->m_current->AddChild(pnode) ; - m_data->Push( pnode ) ; -} - -void wxXmlWriter::DoEndWriteProperty(const wxPropertyInfo *WXUNUSED(propInfo) ) -{ - m_data->Pop() ; -} - - - -// insert an object reference to an already written object -void wxXmlWriter::DoWriteRepeatedObject( int objectID ) -{ - wxXmlNode *pnode; - pnode = new wxXmlNode(wxXML_ELEMENT_NODE, wxT("object")); - pnode->AddProperty(wxString(wxT("href")), wxString::Format( wxT("%d") , objectID ) ); - m_data->m_current->AddChild(pnode) ; -} - -// insert a null reference -void wxXmlWriter::DoWriteNullObject() -{ - wxXmlNode *pnode; - pnode = new wxXmlNode(wxXML_ELEMENT_NODE, wxT("object")); - m_data->m_current->AddChild(pnode) ; -} - -// writes a delegate in the stream format -void wxXmlWriter::DoWriteDelegate( const wxObject *WXUNUSED(object), const wxClassInfo* WXUNUSED(classInfo) , const wxPropertyInfo *WXUNUSED(pi) , - const wxObject *eventSink, int sinkObjectID , const wxClassInfo* WXUNUSED(eventSinkClassInfo) , const wxHandlerInfo* handlerInfo ) -{ - if ( eventSink != NULL && handlerInfo != NULL ) - { - wxXmlAddContentToNode( m_data->m_current ,wxString::Format(wxT("%d.%s"), sinkObjectID , handlerInfo->GetName().c_str()) ) ; - } -} - -// ---------------------------------------------------------------------------- -// reading objects in -// ---------------------------------------------------------------------------- - - - -// ---------------------------------------------------------------------------- -// reading xml in -// ---------------------------------------------------------------------------- - -/* -Reading components has not to be extended for components -as properties are always sought by typeinfo over all levels -and create params are always toplevel class only -*/ - -int wxXmlReader::ReadComponent(wxXmlNode *node, wxDepersister *callbacks) -{ - wxASSERT_MSG( callbacks , wxT("Does not support reading without a Depersistor") ) ; - wxString className; - wxClassInfo *classInfo; - - wxxVariant *createParams ; - int *createParamOids ; - const wxClassInfo** createClassInfos ; - wxXmlNode *children; - int objectID; - wxString ObjectIdString ; - - children = node->GetChildren(); - if (!children) - { - // check for a null object or href - if (node->GetPropVal(wxT("href") , &ObjectIdString ) ) - { - objectID = atoi( ObjectIdString.ToAscii() ) ; - if ( HasObjectClassInfo( objectID ) ) - { - return objectID ; - } - else - { - wxLogError( _("Forward hrefs are not supported") ) ; - return wxInvalidObjectID ; - } - } - if ( !node->GetPropVal(wxT("id") , &ObjectIdString ) ) - { - return wxNullObjectID; - } - } - if (!node->GetPropVal(wxT("class"), &className)) - { - // No class name. Eek. FIXME: error handling - return wxInvalidObjectID; - } - classInfo = wxClassInfo::FindClass(className); - if ( classInfo == NULL ) - { - wxLogError( wxString::Format(_("unknown class %s"),className ) ) ; - return wxInvalidObjectID ; - } - - if ( children != NULL && children->GetType() == wxXML_TEXT_NODE ) - { - wxLogError(_("objects cannot have XML Text Nodes") ) ; - return wxInvalidObjectID; - } - if (!node->GetPropVal(wxT("id"), &ObjectIdString)) - { - wxLogError(_("Objects must have an id attribute") ) ; - // No object id. Eek. FIXME: error handling - return wxInvalidObjectID; - } - objectID = atoi( ObjectIdString.ToAscii() ) ; - // is this object already has been streamed in, return it here - if ( HasObjectClassInfo( objectID ) ) - { - wxLogError ( wxString::Format(_("Doubly used id : %d"), objectID ) ) ; - return wxInvalidObjectID ; - } - - // new object, start with allocation - // first make the object know to our internal registry - SetObjectClassInfo( objectID , classInfo ) ; - - wxxVariantArray metadata ; - wxXmlProperty *xp = node->GetProperties() ; - while ( xp ) - { - if ( xp->GetName() != wxString(wxT("class")) && xp->GetName() != wxString(wxT("id")) ) - { - metadata.Add( new wxxVariant( xp->GetValue() , xp->GetName() ) ) ; - } - xp = xp->GetNext() ; - } - if ( !classInfo->NeedsDirectConstruction() ) - callbacks->AllocateObject(objectID, classInfo, metadata); - - // - // stream back the Create parameters first - createParams = new wxxVariant[ classInfo->GetCreateParamCount() ] ; - createParamOids = new int[classInfo->GetCreateParamCount() ] ; - createClassInfos = new const wxClassInfo*[classInfo->GetCreateParamCount() ] ; - -#if wxUSE_UNICODE - typedef map PropertyNodes ; - typedef vector PropertyNames ; -#else - typedef map PropertyNodes ; - typedef vector PropertyNames ; -#endif - PropertyNodes propertyNodes ; - PropertyNames propertyNames ; - - while( children ) - { - wxString name ; - children->GetPropVal( wxT("name") , &name ) ; - propertyNames.push_back( name.c_str() ) ; - propertyNodes[name.c_str()] = children->GetChildren() ; - children = children->GetNext() ; - } - - for ( int i = 0 ; i GetCreateParamCount() ; ++i ) - { - const wxChar* paramName = classInfo->GetCreateParamName(i) ; - PropertyNodes::iterator propiter = propertyNodes.find( paramName ) ; - const wxPropertyInfo* pi = classInfo->FindPropertyInfo( paramName ) ; - if ( pi == 0 ) - { - wxLogError( wxString::Format(_("Unkown Property %s"),paramName) ) ; - } - // if we don't have the value of a create param set in the xml - // we use the default value - if ( propiter != propertyNodes.end() ) - { - wxXmlNode* prop = propiter->second ; - if ( pi->GetTypeInfo()->IsObjectType() ) - { - createParamOids[i] = ReadComponent( prop , callbacks ) ; - createClassInfos[i] = dynamic_cast(pi->GetTypeInfo())->GetClassInfo() ; - } - else - { - createParamOids[i] = wxInvalidObjectID ; - createParams[i] = ReadValue( prop , pi->GetTypeInfo() ) ; - if( pi->GetFlags() & wxPROP_ENUM_STORE_LONG ) - { - const wxEnumTypeInfo *eti = dynamic_cast( pi->GetTypeInfo() ) ; - if ( eti ) - { - long realval ; - eti->ConvertToLong( createParams[i] , realval ) ; - createParams[i] = wxxVariant( realval ) ; - } - else - { - wxLogError( _("Type must have enum - long conversion") ) ; - } - } - createClassInfos[i] = NULL ; - } - - for ( size_t j = 0 ; j < propertyNames.size() ; ++j ) - { - if ( propertyNames[j] == paramName ) - { - propertyNames[j] = wxEmptyString ; - break ; - } - } - } - else - { - if ( pi->GetTypeInfo()->IsObjectType() ) - { - createParamOids[i] = wxNullObjectID ; - createClassInfos[i] = dynamic_cast(pi->GetTypeInfo())->GetClassInfo() ; - } - else - { - createParams[i] = pi->GetDefaultValue() ; - createParamOids[i] = wxInvalidObjectID ; - } - } - } - - // got the parameters. Call the Create method - if ( classInfo->NeedsDirectConstruction() ) - callbacks->ConstructObject(objectID, classInfo, - classInfo->GetCreateParamCount(), - createParams, createParamOids, createClassInfos, metadata ); - else - callbacks->CreateObject(objectID, classInfo, - classInfo->GetCreateParamCount(), - createParams, createParamOids, createClassInfos, metadata ); - - // now stream in the rest of the properties, in the sequence their properties were written in the xml - for ( size_t j = 0 ; j < propertyNames.size() ; ++j ) - { - if ( propertyNames[j].length() ) - { - PropertyNodes::iterator propiter = propertyNodes.find( propertyNames[j] ) ; - if ( propiter != propertyNodes.end() ) - { - wxXmlNode* prop = propiter->second ; - const wxPropertyInfo* pi = classInfo->FindPropertyInfo( propertyNames[j].c_str() ) ; - if ( pi->GetTypeInfo()->GetKind() == wxT_COLLECTION ) - { - const wxCollectionTypeInfo* collType = dynamic_cast< const wxCollectionTypeInfo* >( pi->GetTypeInfo() ) ; - const wxTypeInfo * elementType = collType->GetElementType() ; - while( prop ) - { - if ( prop->GetName() != wxT("element") ) - { - wxLogError( _("A non empty collection must consist of 'element' nodes" ) ) ; - break ; - } - wxXmlNode* elementContent = prop->GetChildren() ; - if ( elementContent ) - { - // we skip empty elements - if ( elementType->IsObjectType() ) - { - int valueId = ReadComponent( elementContent , callbacks ) ; - if ( valueId != wxInvalidObjectID ) - { - if ( pi->GetAccessor()->HasAdder() ) - callbacks->AddToPropertyCollectionAsObject( objectID , classInfo , pi , valueId ) ; - // TODO for collections we must have a notation on taking over ownership or not - if ( elementType->GetKind() == wxT_OBJECT && valueId != wxNullObjectID ) - callbacks->DestroyObject( valueId , GetObjectClassInfo( valueId ) ) ; - } - } - else - { - wxxVariant elementValue = ReadValue( elementContent , elementType ) ; - if ( pi->GetAccessor()->HasAdder() ) - callbacks->AddToPropertyCollection( objectID , classInfo ,pi , elementValue ) ; - } - } - prop = prop->GetNext() ; - } - } - else if ( pi->GetTypeInfo()->IsObjectType() ) - { - // and object can either be streamed out a string or as an object - // in case we have no node, then the object's streaming out has been vetoed - if ( prop ) - { - if ( prop->GetName() == wxT("object") ) - { - int valueId = ReadComponent( prop , callbacks ) ; - if ( valueId != wxInvalidObjectID ) - { - callbacks->SetPropertyAsObject( objectID , classInfo , pi , valueId ) ; - if ( pi->GetTypeInfo()->GetKind() == wxT_OBJECT && valueId != wxNullObjectID ) - callbacks->DestroyObject( valueId , GetObjectClassInfo( valueId ) ) ; - } - } - else - { - wxASSERT( pi->GetTypeInfo()->HasStringConverters() ) ; - wxxVariant nodeval = ReadValue( prop , pi->GetTypeInfo() ) ; - callbacks->SetProperty( objectID, classInfo ,pi , nodeval ) ; - } - } - } - else if ( pi->GetTypeInfo()->IsDelegateType() ) - { - if ( prop ) - { - wxString resstring = prop->GetContent() ; - wxInt32 pos = resstring.Find('.') ; - if ( pos != wxNOT_FOUND ) - { - int sinkOid = atol(resstring.Left(pos).ToAscii()) ; - wxString handlerName = resstring.Mid(pos+1) ; - wxClassInfo* sinkClassInfo = GetObjectClassInfo( sinkOid ) ; - - callbacks->SetConnect( objectID , classInfo , pi , sinkClassInfo , - sinkClassInfo->FindHandlerInfo(handlerName) , sinkOid ) ; - } - else - { - wxLogError( _("incorrect event handler string, missing dot") ) ; - } - } - - } - else - { - wxxVariant nodeval = ReadValue( prop , pi->GetTypeInfo() ) ; - if( pi->GetFlags() & wxPROP_ENUM_STORE_LONG ) - { - const wxEnumTypeInfo *eti = dynamic_cast( pi->GetTypeInfo() ) ; - if ( eti ) - { - long realval ; - eti->ConvertToLong( nodeval , realval ) ; - nodeval = wxxVariant( realval ) ; - } - else - { - wxLogError( _("Type must have enum - long conversion") ) ; - } - } - callbacks->SetProperty( objectID, classInfo ,pi , nodeval ) ; - } - } - } - } - - delete[] createParams ; - delete[] createParamOids ; - delete[] createClassInfos ; - - return objectID; -} - -wxxVariant wxXmlReader::ReadValue(wxXmlNode *node, - const wxTypeInfo *type ) -{ - wxString content ; - if ( node ) - content = node->GetContent() ; - wxxVariant result ; - type->ConvertFromString( content , result ) ; - return result ; -} - -int wxXmlReader::ReadObject( const wxString &name , wxDepersister *callbacks) -{ - wxXmlNode *iter = m_parent->GetChildren() ; - while ( iter ) - { - wxString entryName ; - if ( iter->GetPropVal(wxT("name"), &entryName) ) - { - if ( entryName == name ) - return ReadComponent( iter->GetChildren() , callbacks ) ; - } - iter = iter->GetNext() ; - } - return wxInvalidObjectID ; -} - -#endif // wxUSE_EXTENDED_RTTI +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/xtixml.cpp +// Purpose: streaming runtime metadata information +// Author: Stefan Csomor +// Modified by: +// Created: 27/07/03 +// RCS-ID: $Id: xtixml.cpp 38939 2006-04-27 12:47:14Z ABX $ +// Copyright: (c) 2003 Stefan Csomor +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_EXTENDED_RTTI + +#include "wx/xtixml.h" + +#ifndef WX_PRECOMP + #include "wx/object.h" + #include "wx/hash.h" + #include "wx/event.h" +#endif + +#include "wx/xml/xml.h" +#include "wx/tokenzr.h" +#include "wx/txtstrm.h" + +#include "wx/xtistrm.h" + +#include "wx/beforestd.h" +#include +#include +#include +#include "wx/afterstd.h" + +using namespace std ; + +// +// XML Streaming +// + +// convenience functions + +void wxXmlAddContentToNode( wxXmlNode* node , const wxString& data ) +{ + node->AddChild(new wxXmlNode(wxXML_TEXT_NODE, wxT("value"), data ) ); +} + +wxString wxXmlGetContentFromNode( wxXmlNode *node ) +{ + if ( node->GetChildren() ) + return node->GetChildren()->GetContent() ; + else + return wxEmptyString ; +} + +struct wxXmlWriter::wxXmlWriterInternal +{ + wxXmlNode *m_root ; + wxXmlNode *m_current ; + vector< wxXmlNode * > m_objectStack ; + + void Push( wxXmlNode *newCurrent ) + { + m_objectStack.push_back( m_current ) ; + m_current = newCurrent ; + } + + void Pop() + { + m_current = m_objectStack.back() ; + m_objectStack.pop_back() ; + } +} ; + +wxXmlWriter::wxXmlWriter( wxXmlNode * rootnode ) +{ + m_data = new wxXmlWriterInternal() ; + m_data->m_root = rootnode ; + m_data->m_current = rootnode ; +} + +wxXmlWriter::~wxXmlWriter() +{ + delete m_data ; +} + +void wxXmlWriter::DoBeginWriteTopLevelEntry( const wxString &name ) +{ + wxXmlNode *pnode; + pnode = new wxXmlNode(wxXML_ELEMENT_NODE, wxT("entry")); + pnode->AddProperty(wxString(wxT("name")), name); + m_data->m_current->AddChild(pnode) ; + m_data->Push( pnode ) ; +} + +void wxXmlWriter::DoEndWriteTopLevelEntry( const wxString &WXUNUSED(name) ) +{ + m_data->Pop() ; +} + +void wxXmlWriter::DoBeginWriteObject(const wxObject *WXUNUSED(object), const wxClassInfo *classInfo, int objectID , wxxVariantArray &metadata ) +{ + wxXmlNode *pnode; + pnode = new wxXmlNode(wxXML_ELEMENT_NODE, wxT("object")); + pnode->AddProperty(wxT("class"), wxString(classInfo->GetClassName())); + pnode->AddProperty(wxT("id"), wxString::Format( wxT("%d") , objectID ) ); + + for ( size_t i = 0 ; i < metadata.GetCount() ; ++i ) + { + pnode->AddProperty( metadata[i].GetName() , metadata[i].GetAsString() ) ; + } + m_data->m_current->AddChild(pnode) ; + m_data->Push( pnode ) ; +} + +// end of writing the root object +void wxXmlWriter::DoEndWriteObject(const wxObject *WXUNUSED(object), const wxClassInfo *WXUNUSED(classInfo), int WXUNUSED(objectID) ) +{ + m_data->Pop() ; +} + +// writes a property in the stream format +void wxXmlWriter::DoWriteSimpleType( wxxVariant &value ) +{ + wxXmlAddContentToNode( m_data->m_current ,value.GetAsString() ) ; +} + +void wxXmlWriter::DoBeginWriteElement() +{ + wxXmlNode *pnode; + pnode = new wxXmlNode(wxXML_ELEMENT_NODE, wxT("element") ); + m_data->m_current->AddChild(pnode) ; + m_data->Push( pnode ) ; +} + +void wxXmlWriter::DoEndWriteElement() +{ + m_data->Pop() ; +} + +void wxXmlWriter::DoBeginWriteProperty(const wxPropertyInfo *pi ) +{ + wxXmlNode *pnode; + pnode = new wxXmlNode(wxXML_ELEMENT_NODE, wxT("prop") ); + pnode->AddProperty(wxT("name"), pi->GetName() ); + m_data->m_current->AddChild(pnode) ; + m_data->Push( pnode ) ; +} + +void wxXmlWriter::DoEndWriteProperty(const wxPropertyInfo *WXUNUSED(propInfo) ) +{ + m_data->Pop() ; +} + + + +// insert an object reference to an already written object +void wxXmlWriter::DoWriteRepeatedObject( int objectID ) +{ + wxXmlNode *pnode; + pnode = new wxXmlNode(wxXML_ELEMENT_NODE, wxT("object")); + pnode->AddProperty(wxString(wxT("href")), wxString::Format( wxT("%d") , objectID ) ); + m_data->m_current->AddChild(pnode) ; +} + +// insert a null reference +void wxXmlWriter::DoWriteNullObject() +{ + wxXmlNode *pnode; + pnode = new wxXmlNode(wxXML_ELEMENT_NODE, wxT("object")); + m_data->m_current->AddChild(pnode) ; +} + +// writes a delegate in the stream format +void wxXmlWriter::DoWriteDelegate( const wxObject *WXUNUSED(object), const wxClassInfo* WXUNUSED(classInfo) , const wxPropertyInfo *WXUNUSED(pi) , + const wxObject *eventSink, int sinkObjectID , const wxClassInfo* WXUNUSED(eventSinkClassInfo) , const wxHandlerInfo* handlerInfo ) +{ + if ( eventSink != NULL && handlerInfo != NULL ) + { + wxXmlAddContentToNode( m_data->m_current ,wxString::Format(wxT("%d.%s"), sinkObjectID , handlerInfo->GetName().c_str()) ) ; + } +} + +// ---------------------------------------------------------------------------- +// reading objects in +// ---------------------------------------------------------------------------- + + + +// ---------------------------------------------------------------------------- +// reading xml in +// ---------------------------------------------------------------------------- + +/* +Reading components has not to be extended for components +as properties are always sought by typeinfo over all levels +and create params are always toplevel class only +*/ + +int wxXmlReader::ReadComponent(wxXmlNode *node, wxDepersister *callbacks) +{ + wxASSERT_MSG( callbacks , wxT("Does not support reading without a Depersistor") ) ; + wxString className; + wxClassInfo *classInfo; + + wxxVariant *createParams ; + int *createParamOids ; + const wxClassInfo** createClassInfos ; + wxXmlNode *children; + int objectID; + wxString ObjectIdString ; + + children = node->GetChildren(); + if (!children) + { + // check for a null object or href + if (node->GetPropVal(wxT("href") , &ObjectIdString ) ) + { + objectID = atoi( ObjectIdString.ToAscii() ) ; + if ( HasObjectClassInfo( objectID ) ) + { + return objectID ; + } + else + { + wxLogError( _("Forward hrefs are not supported") ) ; + return wxInvalidObjectID ; + } + } + if ( !node->GetPropVal(wxT("id") , &ObjectIdString ) ) + { + return wxNullObjectID; + } + } + if (!node->GetPropVal(wxT("class"), &className)) + { + // No class name. Eek. FIXME: error handling + return wxInvalidObjectID; + } + classInfo = wxClassInfo::FindClass(className); + if ( classInfo == NULL ) + { + wxLogError( wxString::Format(_("unknown class %s"),className ) ) ; + return wxInvalidObjectID ; + } + + if ( children != NULL && children->GetType() == wxXML_TEXT_NODE ) + { + wxLogError(_("objects cannot have XML Text Nodes") ) ; + return wxInvalidObjectID; + } + if (!node->GetPropVal(wxT("id"), &ObjectIdString)) + { + wxLogError(_("Objects must have an id attribute") ) ; + // No object id. Eek. FIXME: error handling + return wxInvalidObjectID; + } + objectID = atoi( ObjectIdString.ToAscii() ) ; + // is this object already has been streamed in, return it here + if ( HasObjectClassInfo( objectID ) ) + { + wxLogError ( wxString::Format(_("Doubly used id : %d"), objectID ) ) ; + return wxInvalidObjectID ; + } + + // new object, start with allocation + // first make the object know to our internal registry + SetObjectClassInfo( objectID , classInfo ) ; + + wxxVariantArray metadata ; + wxXmlProperty *xp = node->GetProperties() ; + while ( xp ) + { + if ( xp->GetName() != wxString(wxT("class")) && xp->GetName() != wxString(wxT("id")) ) + { + metadata.Add( new wxxVariant( xp->GetValue() , xp->GetName() ) ) ; + } + xp = xp->GetNext() ; + } + if ( !classInfo->NeedsDirectConstruction() ) + callbacks->AllocateObject(objectID, classInfo, metadata); + + // + // stream back the Create parameters first + createParams = new wxxVariant[ classInfo->GetCreateParamCount() ] ; + createParamOids = new int[classInfo->GetCreateParamCount() ] ; + createClassInfos = new const wxClassInfo*[classInfo->GetCreateParamCount() ] ; + +#if wxUSE_UNICODE + typedef map PropertyNodes ; + typedef vector PropertyNames ; +#else + typedef map PropertyNodes ; + typedef vector PropertyNames ; +#endif + PropertyNodes propertyNodes ; + PropertyNames propertyNames ; + + while( children ) + { + wxString name ; + children->GetPropVal( wxT("name") , &name ) ; + propertyNames.push_back( name.c_str() ) ; + propertyNodes[name.c_str()] = children->GetChildren() ; + children = children->GetNext() ; + } + + for ( int i = 0 ; i GetCreateParamCount() ; ++i ) + { + const wxChar* paramName = classInfo->GetCreateParamName(i) ; + PropertyNodes::iterator propiter = propertyNodes.find( paramName ) ; + const wxPropertyInfo* pi = classInfo->FindPropertyInfo( paramName ) ; + if ( pi == 0 ) + { + wxLogError( wxString::Format(_("Unkown Property %s"),paramName) ) ; + } + // if we don't have the value of a create param set in the xml + // we use the default value + if ( propiter != propertyNodes.end() ) + { + wxXmlNode* prop = propiter->second ; + if ( pi->GetTypeInfo()->IsObjectType() ) + { + createParamOids[i] = ReadComponent( prop , callbacks ) ; + createClassInfos[i] = dynamic_cast(pi->GetTypeInfo())->GetClassInfo() ; + } + else + { + createParamOids[i] = wxInvalidObjectID ; + createParams[i] = ReadValue( prop , pi->GetTypeInfo() ) ; + if( pi->GetFlags() & wxPROP_ENUM_STORE_LONG ) + { + const wxEnumTypeInfo *eti = dynamic_cast( pi->GetTypeInfo() ) ; + if ( eti ) + { + long realval ; + eti->ConvertToLong( createParams[i] , realval ) ; + createParams[i] = wxxVariant( realval ) ; + } + else + { + wxLogError( _("Type must have enum - long conversion") ) ; + } + } + createClassInfos[i] = NULL ; + } + + for ( size_t j = 0 ; j < propertyNames.size() ; ++j ) + { + if ( propertyNames[j] == paramName ) + { + propertyNames[j] = wxEmptyString ; + break ; + } + } + } + else + { + if ( pi->GetTypeInfo()->IsObjectType() ) + { + createParamOids[i] = wxNullObjectID ; + createClassInfos[i] = dynamic_cast(pi->GetTypeInfo())->GetClassInfo() ; + } + else + { + createParams[i] = pi->GetDefaultValue() ; + createParamOids[i] = wxInvalidObjectID ; + } + } + } + + // got the parameters. Call the Create method + if ( classInfo->NeedsDirectConstruction() ) + callbacks->ConstructObject(objectID, classInfo, + classInfo->GetCreateParamCount(), + createParams, createParamOids, createClassInfos, metadata ); + else + callbacks->CreateObject(objectID, classInfo, + classInfo->GetCreateParamCount(), + createParams, createParamOids, createClassInfos, metadata ); + + // now stream in the rest of the properties, in the sequence their properties were written in the xml + for ( size_t j = 0 ; j < propertyNames.size() ; ++j ) + { + if ( propertyNames[j].length() ) + { + PropertyNodes::iterator propiter = propertyNodes.find( propertyNames[j] ) ; + if ( propiter != propertyNodes.end() ) + { + wxXmlNode* prop = propiter->second ; + const wxPropertyInfo* pi = classInfo->FindPropertyInfo( propertyNames[j].c_str() ) ; + if ( pi->GetTypeInfo()->GetKind() == wxT_COLLECTION ) + { + const wxCollectionTypeInfo* collType = dynamic_cast< const wxCollectionTypeInfo* >( pi->GetTypeInfo() ) ; + const wxTypeInfo * elementType = collType->GetElementType() ; + while( prop ) + { + if ( prop->GetName() != wxT("element") ) + { + wxLogError( _("A non empty collection must consist of 'element' nodes" ) ) ; + break ; + } + wxXmlNode* elementContent = prop->GetChildren() ; + if ( elementContent ) + { + // we skip empty elements + if ( elementType->IsObjectType() ) + { + int valueId = ReadComponent( elementContent , callbacks ) ; + if ( valueId != wxInvalidObjectID ) + { + if ( pi->GetAccessor()->HasAdder() ) + callbacks->AddToPropertyCollectionAsObject( objectID , classInfo , pi , valueId ) ; + // TODO for collections we must have a notation on taking over ownership or not + if ( elementType->GetKind() == wxT_OBJECT && valueId != wxNullObjectID ) + callbacks->DestroyObject( valueId , GetObjectClassInfo( valueId ) ) ; + } + } + else + { + wxxVariant elementValue = ReadValue( elementContent , elementType ) ; + if ( pi->GetAccessor()->HasAdder() ) + callbacks->AddToPropertyCollection( objectID , classInfo ,pi , elementValue ) ; + } + } + prop = prop->GetNext() ; + } + } + else if ( pi->GetTypeInfo()->IsObjectType() ) + { + // and object can either be streamed out a string or as an object + // in case we have no node, then the object's streaming out has been vetoed + if ( prop ) + { + if ( prop->GetName() == wxT("object") ) + { + int valueId = ReadComponent( prop , callbacks ) ; + if ( valueId != wxInvalidObjectID ) + { + callbacks->SetPropertyAsObject( objectID , classInfo , pi , valueId ) ; + if ( pi->GetTypeInfo()->GetKind() == wxT_OBJECT && valueId != wxNullObjectID ) + callbacks->DestroyObject( valueId , GetObjectClassInfo( valueId ) ) ; + } + } + else + { + wxASSERT( pi->GetTypeInfo()->HasStringConverters() ) ; + wxxVariant nodeval = ReadValue( prop , pi->GetTypeInfo() ) ; + callbacks->SetProperty( objectID, classInfo ,pi , nodeval ) ; + } + } + } + else if ( pi->GetTypeInfo()->IsDelegateType() ) + { + if ( prop ) + { + wxString resstring = prop->GetContent() ; + wxInt32 pos = resstring.Find('.') ; + if ( pos != wxNOT_FOUND ) + { + int sinkOid = atol(resstring.Left(pos).ToAscii()) ; + wxString handlerName = resstring.Mid(pos+1) ; + wxClassInfo* sinkClassInfo = GetObjectClassInfo( sinkOid ) ; + + callbacks->SetConnect( objectID , classInfo , pi , sinkClassInfo , + sinkClassInfo->FindHandlerInfo(handlerName) , sinkOid ) ; + } + else + { + wxLogError( _("incorrect event handler string, missing dot") ) ; + } + } + + } + else + { + wxxVariant nodeval = ReadValue( prop , pi->GetTypeInfo() ) ; + if( pi->GetFlags() & wxPROP_ENUM_STORE_LONG ) + { + const wxEnumTypeInfo *eti = dynamic_cast( pi->GetTypeInfo() ) ; + if ( eti ) + { + long realval ; + eti->ConvertToLong( nodeval , realval ) ; + nodeval = wxxVariant( realval ) ; + } + else + { + wxLogError( _("Type must have enum - long conversion") ) ; + } + } + callbacks->SetProperty( objectID, classInfo ,pi , nodeval ) ; + } + } + } + } + + delete[] createParams ; + delete[] createParamOids ; + delete[] createClassInfos ; + + return objectID; +} + +wxxVariant wxXmlReader::ReadValue(wxXmlNode *node, + const wxTypeInfo *type ) +{ + wxString content ; + if ( node ) + content = node->GetContent() ; + wxxVariant result ; + type->ConvertFromString( content , result ) ; + return result ; +} + +int wxXmlReader::ReadObject( const wxString &name , wxDepersister *callbacks) +{ + wxXmlNode *iter = m_parent->GetChildren() ; + while ( iter ) + { + wxString entryName ; + if ( iter->GetPropVal(wxT("name"), &entryName) ) + { + if ( entryName == name ) + return ReadComponent( iter->GetChildren() , callbacks ) ; + } + iter = iter->GetNext() ; + } + return wxInvalidObjectID ; +} + +#endif // wxUSE_EXTENDED_RTTI diff --git a/Externals/wxWidgets/src/common/zipstrm.cpp b/Externals/wxWidgets/src/common/zipstrm.cpp index 1cda3adce2..a77df8dc8e 100644 --- a/Externals/wxWidgets/src/common/zipstrm.cpp +++ b/Externals/wxWidgets/src/common/zipstrm.cpp @@ -1,2425 +1,2425 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/zipstrm.cpp -// Purpose: Streams for Zip files -// Author: Mike Wetherell -// RCS-ID: $Id: zipstrm.cpp 51009 2008-01-03 17:11:45Z MW $ -// Copyright: (c) Mike Wetherell -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_ZIPSTREAM - -#include "wx/zipstrm.h" - -#ifndef WX_PRECOMP - #include "wx/hashmap.h" - #include "wx/intl.h" - #include "wx/log.h" - #include "wx/utils.h" -#endif - -#include "wx/datstrm.h" -#include "wx/zstream.h" -#include "wx/mstream.h" -#include "wx/ptr_scpd.h" -#include "wx/wfstream.h" -#include "zlib.h" - -// value for the 'version needed to extract' field (20 means 2.0) -enum { - VERSION_NEEDED_TO_EXTRACT = 20 -}; - -// signatures for the various records (PKxx) -enum { - CENTRAL_MAGIC = 0x02014b50, // central directory record - LOCAL_MAGIC = 0x04034b50, // local header - END_MAGIC = 0x06054b50, // end of central directory record - SUMS_MAGIC = 0x08074b50 // data descriptor (info-zip) -}; - -// unix file attributes. zip stores them in the high 16 bits of the -// 'external attributes' field, hence the extra zeros. -enum { - wxZIP_S_IFMT = 0xF0000000, - wxZIP_S_IFDIR = 0x40000000, - wxZIP_S_IFREG = 0x80000000 -}; - -// minimum sizes for the various records -enum { - CENTRAL_SIZE = 46, - LOCAL_SIZE = 30, - END_SIZE = 22, - SUMS_SIZE = 12 -}; - -// The number of bytes that must be written to an wxZipOutputStream before -// a zip entry is created. The purpose of this latency is so that -// OpenCompressor() can see a little data before deciding which compressor -// it should use. -enum { - OUTPUT_LATENCY = 4096 -}; - -// Some offsets into the local header -enum { - SUMS_OFFSET = 14 -}; - -IMPLEMENT_DYNAMIC_CLASS(wxZipEntry, wxArchiveEntry) -IMPLEMENT_DYNAMIC_CLASS(wxZipClassFactory, wxArchiveClassFactory) - - -///////////////////////////////////////////////////////////////////////////// -// Helpers - -// read a string of a given length -// -static wxString ReadString(wxInputStream& stream, wxUint16 len, wxMBConv& conv) -{ - if (len == 0) - return wxEmptyString; - -#if wxUSE_UNICODE - wxCharBuffer buf(len); - stream.Read(buf.data(), len); - wxString str(buf, conv); -#else - wxString str; - (void)conv; - { - wxStringBuffer buf(str, len); - stream.Read(buf, len); - } -#endif - - return str; -} - -// Decode a little endian wxUint32 number from a character array -// -static inline wxUint32 CrackUint32(const char *m) -{ - const unsigned char *n = (const unsigned char*)m; - return (n[3] << 24) | (n[2] << 16) | (n[1] << 8) | n[0]; -} - -// Decode a little endian wxUint16 number from a character array -// -static inline wxUint16 CrackUint16(const char *m) -{ - const unsigned char *n = (const unsigned char*)m; - return (n[1] << 8) | n[0]; -} - -// Temporarily lower the logging level in debug mode to avoid a warning -// from SeekI about seeking on a stream with data written back to it. -// -static wxFileOffset QuietSeek(wxInputStream& stream, wxFileOffset pos) -{ -#if defined(__WXDEBUG__) && wxUSE_LOG - wxLogLevel level = wxLog::GetLogLevel(); - wxLog::SetLogLevel(wxLOG_Debug - 1); - wxFileOffset result = stream.SeekI(pos); - wxLog::SetLogLevel(level); - return result; -#else - return stream.SeekI(pos); -#endif -} - - -///////////////////////////////////////////////////////////////////////////// -// Class factory - -wxZipClassFactory g_wxZipClassFactory; - -wxZipClassFactory::wxZipClassFactory() -{ - if (this == &g_wxZipClassFactory) - PushFront(); -} - -const wxChar * const * -wxZipClassFactory::GetProtocols(wxStreamProtocolType type) const -{ - static const wxChar *protocols[] = { _T("zip"), NULL }; - static const wxChar *mimetypes[] = { _T("application/zip"), NULL }; - static const wxChar *fileexts[] = { _T(".zip"), _T(".htb"), NULL }; - static const wxChar *empty[] = { NULL }; - - switch (type) { - case wxSTREAM_PROTOCOL: return protocols; - case wxSTREAM_MIMETYPE: return mimetypes; - case wxSTREAM_FILEEXT: return fileexts; - default: return empty; - } -} - - -///////////////////////////////////////////////////////////////////////////// -// Read a zip header - -class wxZipHeader -{ -public: - wxZipHeader(wxInputStream& stream, size_t size); - - inline wxUint8 Read8(); - inline wxUint16 Read16(); - inline wxUint32 Read32(); - - const char *GetData() const { return m_data; } - size_t GetSize() const { return m_size; } - operator bool() const { return m_ok; } - - size_t Seek(size_t pos) { m_pos = pos; return m_pos; } - size_t Skip(size_t size) { m_pos += size; return m_pos; } - - wxZipHeader& operator>>(wxUint8& n) { n = Read8(); return *this; } - wxZipHeader& operator>>(wxUint16& n) { n = Read16(); return *this; } - wxZipHeader& operator>>(wxUint32& n) { n = Read32(); return *this; } - -private: - char m_data[64]; - size_t m_size; - size_t m_pos; - bool m_ok; -}; - -wxZipHeader::wxZipHeader(wxInputStream& stream, size_t size) - : m_size(0), - m_pos(0), - m_ok(false) -{ - wxCHECK_RET(size <= sizeof(m_data), _T("buffer too small")); - m_size = stream.Read(m_data, size).LastRead(); - m_ok = m_size == size; -} - -inline wxUint8 wxZipHeader::Read8() -{ - wxASSERT(m_pos < m_size); - return m_data[m_pos++]; -} - -inline wxUint16 wxZipHeader::Read16() -{ - wxASSERT(m_pos + 2 <= m_size); - wxUint16 n = CrackUint16(m_data + m_pos); - m_pos += 2; - return n; -} - -inline wxUint32 wxZipHeader::Read32() -{ - wxASSERT(m_pos + 4 <= m_size); - wxUint32 n = CrackUint32(m_data + m_pos); - m_pos += 4; - return n; -} - - -///////////////////////////////////////////////////////////////////////////// -// Stored input stream -// Trival decompressor for files which are 'stored' in the zip file. - -class wxStoredInputStream : public wxFilterInputStream -{ -public: - wxStoredInputStream(wxInputStream& stream); - - void Open(wxFileOffset len) { Close(); m_len = len; } - void Close() { m_pos = 0; m_lasterror = wxSTREAM_NO_ERROR; } - - virtual char Peek() { return wxInputStream::Peek(); } - virtual wxFileOffset GetLength() const { return m_len; } - -protected: - virtual size_t OnSysRead(void *buffer, size_t size); - virtual wxFileOffset OnSysTell() const { return m_pos; } - -private: - wxFileOffset m_pos; - wxFileOffset m_len; - - DECLARE_NO_COPY_CLASS(wxStoredInputStream) -}; - -wxStoredInputStream::wxStoredInputStream(wxInputStream& stream) - : wxFilterInputStream(stream), - m_pos(0), - m_len(0) -{ -} - -size_t wxStoredInputStream::OnSysRead(void *buffer, size_t size) -{ - size_t count = wx_truncate_cast(size_t, - wxMin(size + wxFileOffset(0), m_len - m_pos + size_t(0))); - count = m_parent_i_stream->Read(buffer, count).LastRead(); - m_pos += count; - - if (count < size) - m_lasterror = m_pos == m_len ? wxSTREAM_EOF : wxSTREAM_READ_ERROR; - - return count; -} - - -///////////////////////////////////////////////////////////////////////////// -// Stored output stream -// Trival compressor for files which are 'stored' in the zip file. - -class wxStoredOutputStream : public wxFilterOutputStream -{ -public: - wxStoredOutputStream(wxOutputStream& stream) : - wxFilterOutputStream(stream), m_pos(0) { } - - bool Close() { - m_pos = 0; - m_lasterror = wxSTREAM_NO_ERROR; - return true; - } - -protected: - virtual size_t OnSysWrite(const void *buffer, size_t size); - virtual wxFileOffset OnSysTell() const { return m_pos; } - -private: - wxFileOffset m_pos; - DECLARE_NO_COPY_CLASS(wxStoredOutputStream) -}; - -size_t wxStoredOutputStream::OnSysWrite(const void *buffer, size_t size) -{ - if (!IsOk() || !size) - return 0; - size_t count = m_parent_o_stream->Write(buffer, size).LastWrite(); - if (count != size) - m_lasterror = wxSTREAM_WRITE_ERROR; - m_pos += count; - return count; -} - - -///////////////////////////////////////////////////////////////////////////// -// wxRawInputStream -// -// Used to handle the unusal case of raw copying an entry of unknown -// length. This can only happen when the zip being copied from is being -// read from a non-seekable stream, and also was original written to a -// non-seekable stream. -// -// In this case there's no option but to decompress the stream to find -// it's length, but we can still write the raw compressed data to avoid the -// compression overhead (which is the greater one). -// -// Usage is like this: -// m_rawin = new wxRawInputStream(*m_parent_i_stream); -// m_decomp = m_rawin->Open(OpenDecompressor(m_rawin->GetTee())); -// -// The wxRawInputStream owns a wxTeeInputStream object, the role of which -// is something like the unix 'tee' command; it is a transparent filter, but -// allows the data read to be read a second time via an extra method 'GetData'. -// -// The wxRawInputStream then draws data through the tee using a decompressor -// then instead of returning the decompressed data, retuns the raw data -// from wxTeeInputStream::GetData(). - -class wxTeeInputStream : public wxFilterInputStream -{ -public: - wxTeeInputStream(wxInputStream& stream); - - size_t GetCount() const { return m_end - m_start; } - size_t GetData(char *buffer, size_t size); - - void Open(); - bool Final(); - - wxInputStream& Read(void *buffer, size_t size); - -protected: - virtual size_t OnSysRead(void *buffer, size_t size); - virtual wxFileOffset OnSysTell() const { return m_pos; } - -private: - wxFileOffset m_pos; - wxMemoryBuffer m_buf; - size_t m_start; - size_t m_end; - - DECLARE_NO_COPY_CLASS(wxTeeInputStream) -}; - -wxTeeInputStream::wxTeeInputStream(wxInputStream& stream) - : wxFilterInputStream(stream), - m_pos(0), m_buf(8192), m_start(0), m_end(0) -{ -} - -void wxTeeInputStream::Open() -{ - m_pos = m_start = m_end = 0; - m_lasterror = wxSTREAM_NO_ERROR; -} - -bool wxTeeInputStream::Final() -{ - bool final = m_end == m_buf.GetDataLen(); - m_end = m_buf.GetDataLen(); - return final; -} - -wxInputStream& wxTeeInputStream::Read(void *buffer, size_t size) -{ - size_t count = wxInputStream::Read(buffer, size).LastRead(); - m_end = m_buf.GetDataLen(); - m_buf.AppendData(buffer, count); - return *this; -} - -size_t wxTeeInputStream::OnSysRead(void *buffer, size_t size) -{ - size_t count = m_parent_i_stream->Read(buffer, size).LastRead(); - if (count < size) - m_lasterror = m_parent_i_stream->GetLastError(); - return count; -} - -size_t wxTeeInputStream::GetData(char *buffer, size_t size) -{ - if (m_wbacksize) { - size_t len = m_buf.GetDataLen(); - len = len > m_wbacksize ? len - m_wbacksize : 0; - m_buf.SetDataLen(len); - if (m_end > len) { - wxFAIL; // we've already returned data that's now being ungot - m_end = len; - } - m_parent_i_stream->Reset(); - m_parent_i_stream->Ungetch(m_wback, m_wbacksize); - free(m_wback); - m_wback = NULL; - m_wbacksize = 0; - m_wbackcur = 0; - } - - if (size > GetCount()) - size = GetCount(); - if (size) { - memcpy(buffer, m_buf + m_start, size); - m_start += size; - wxASSERT(m_start <= m_end); - } - - if (m_start == m_end && m_start > 0 && m_buf.GetDataLen() > 0) { - size_t len = m_buf.GetDataLen(); - char *buf = (char*)m_buf.GetWriteBuf(len); - len -= m_end; - memmove(buf, buf + m_end, len); - m_buf.UngetWriteBuf(len); - m_start = m_end = 0; - } - - return size; -} - -class wxRawInputStream : public wxFilterInputStream -{ -public: - wxRawInputStream(wxInputStream& stream); - virtual ~wxRawInputStream() { delete m_tee; } - - wxInputStream* Open(wxInputStream *decomp); - wxInputStream& GetTee() const { return *m_tee; } - -protected: - virtual size_t OnSysRead(void *buffer, size_t size); - virtual wxFileOffset OnSysTell() const { return m_pos; } - -private: - wxFileOffset m_pos; - wxTeeInputStream *m_tee; - - enum { BUFSIZE = 8192 }; - wxCharBuffer m_dummy; - - DECLARE_NO_COPY_CLASS(wxRawInputStream) -}; - -wxRawInputStream::wxRawInputStream(wxInputStream& stream) - : wxFilterInputStream(stream), - m_pos(0), - m_tee(new wxTeeInputStream(stream)), - m_dummy(BUFSIZE) -{ -} - -wxInputStream *wxRawInputStream::Open(wxInputStream *decomp) -{ - if (decomp) { - m_parent_i_stream = decomp; - m_pos = 0; - m_lasterror = wxSTREAM_NO_ERROR; - m_tee->Open(); - return this; - } else { - return NULL; - } -} - -size_t wxRawInputStream::OnSysRead(void *buffer, size_t size) -{ - char *buf = (char*)buffer; - size_t count = 0; - - while (count < size && IsOk()) - { - while (m_parent_i_stream->IsOk() && m_tee->GetCount() == 0) - m_parent_i_stream->Read(m_dummy.data(), BUFSIZE); - - size_t n = m_tee->GetData(buf + count, size - count); - count += n; - - if (n == 0 && m_tee->Final()) - m_lasterror = m_parent_i_stream->GetLastError(); - } - - m_pos += count; - return count; -} - - -///////////////////////////////////////////////////////////////////////////// -// Zlib streams than can be reused without recreating. - -class wxZlibOutputStream2 : public wxZlibOutputStream -{ -public: - wxZlibOutputStream2(wxOutputStream& stream, int level) : - wxZlibOutputStream(stream, level, wxZLIB_NO_HEADER) { } - - bool Open(wxOutputStream& stream); - bool Close() { DoFlush(true); m_pos = wxInvalidOffset; return IsOk(); } -}; - -bool wxZlibOutputStream2::Open(wxOutputStream& stream) -{ - wxCHECK(m_pos == wxInvalidOffset, false); - - m_deflate->next_out = m_z_buffer; - m_deflate->avail_out = m_z_size; - m_pos = 0; - m_lasterror = wxSTREAM_NO_ERROR; - m_parent_o_stream = &stream; - - if (deflateReset(m_deflate) != Z_OK) { - wxLogError(_("can't re-initialize zlib deflate stream")); - m_lasterror = wxSTREAM_WRITE_ERROR; - return false; - } - - return true; -} - -class wxZlibInputStream2 : public wxZlibInputStream -{ -public: - wxZlibInputStream2(wxInputStream& stream) : - wxZlibInputStream(stream, wxZLIB_NO_HEADER) { } - - bool Open(wxInputStream& stream); -}; - -bool wxZlibInputStream2::Open(wxInputStream& stream) -{ - m_inflate->avail_in = 0; - m_pos = 0; - m_lasterror = wxSTREAM_NO_ERROR; - m_parent_i_stream = &stream; - - if (inflateReset(m_inflate) != Z_OK) { - wxLogError(_("can't re-initialize zlib inflate stream")); - m_lasterror = wxSTREAM_READ_ERROR; - return false; - } - - return true; -} - - -///////////////////////////////////////////////////////////////////////////// -// Class to hold wxZipEntry's Extra and LocalExtra fields - -class wxZipMemory -{ -public: - wxZipMemory() : m_data(NULL), m_size(0), m_capacity(0), m_ref(1) { } - - wxZipMemory *AddRef() { m_ref++; return this; } - void Release() { if (--m_ref == 0) delete this; } - - char *GetData() const { return m_data; } - size_t GetSize() const { return m_size; } - size_t GetCapacity() const { return m_capacity; } - - wxZipMemory *Unique(size_t size); - -private: - ~wxZipMemory() { delete [] m_data; } - - char *m_data; - size_t m_size; - size_t m_capacity; - int m_ref; - - wxSUPPRESS_GCC_PRIVATE_DTOR_WARNING(wxZipMemory) -}; - -wxZipMemory *wxZipMemory::Unique(size_t size) -{ - wxZipMemory *zm; - - if (m_ref > 1) { - --m_ref; - zm = new wxZipMemory; - } else { - zm = this; - } - - if (zm->m_capacity < size) { - delete [] zm->m_data; - zm->m_data = new char[size]; - zm->m_capacity = size; - } - - zm->m_size = size; - return zm; -} - -static inline wxZipMemory *AddRef(wxZipMemory *zm) -{ - if (zm) - zm->AddRef(); - return zm; -} - -static inline void Release(wxZipMemory *zm) -{ - if (zm) - zm->Release(); -} - -static void Copy(wxZipMemory*& dest, wxZipMemory *src) -{ - Release(dest); - dest = AddRef(src); -} - -static void Unique(wxZipMemory*& zm, size_t size) -{ - if (!zm && size) - zm = new wxZipMemory; - if (zm) - zm = zm->Unique(size); -} - - -///////////////////////////////////////////////////////////////////////////// -// Collection of weak references to entries - -WX_DECLARE_HASH_MAP(long, wxZipEntry*, wxIntegerHash, - wxIntegerEqual, wxOffsetZipEntryMap_); - -class wxZipWeakLinks -{ -public: - wxZipWeakLinks() : m_ref(1) { } - - void Release(const wxZipInputStream* WXUNUSED(x)) - { if (--m_ref == 0) delete this; } - void Release(wxFileOffset key) - { RemoveEntry(key); if (--m_ref == 0) delete this; } - - wxZipWeakLinks *AddEntry(wxZipEntry *entry, wxFileOffset key); - void RemoveEntry(wxFileOffset key) - { m_entries.erase(wx_truncate_cast(key_type, key)); } - wxZipEntry *GetEntry(wxFileOffset key) const; - bool IsEmpty() const { return m_entries.empty(); } - -private: - ~wxZipWeakLinks() { wxASSERT(IsEmpty()); } - - typedef wxOffsetZipEntryMap_::key_type key_type; - - int m_ref; - wxOffsetZipEntryMap_ m_entries; - - wxSUPPRESS_GCC_PRIVATE_DTOR_WARNING(wxZipWeakLinks) -}; - -wxZipWeakLinks *wxZipWeakLinks::AddEntry(wxZipEntry *entry, wxFileOffset key) -{ - m_entries[wx_truncate_cast(key_type, key)] = entry; - m_ref++; - return this; -} - -wxZipEntry *wxZipWeakLinks::GetEntry(wxFileOffset key) const -{ - wxOffsetZipEntryMap_::const_iterator it = - m_entries.find(wx_truncate_cast(key_type, key)); - return it != m_entries.end() ? it->second : NULL; -} - - -///////////////////////////////////////////////////////////////////////////// -// ZipEntry - -wxZipEntry::wxZipEntry( - const wxString& name /*=wxEmptyString*/, - const wxDateTime& dt /*=wxDateTime::Now()*/, - wxFileOffset size /*=wxInvalidOffset*/) - : - m_SystemMadeBy(wxZIP_SYSTEM_MSDOS), - m_VersionMadeBy(wxMAJOR_VERSION * 10 + wxMINOR_VERSION), - m_VersionNeeded(VERSION_NEEDED_TO_EXTRACT), - m_Flags(0), - m_Method(wxZIP_METHOD_DEFAULT), - m_DateTime(dt), - m_Crc(0), - m_CompressedSize(wxInvalidOffset), - m_Size(size), - m_Key(wxInvalidOffset), - m_Offset(wxInvalidOffset), - m_DiskStart(0), - m_InternalAttributes(0), - m_ExternalAttributes(0), - m_Extra(NULL), - m_LocalExtra(NULL), - m_zipnotifier(NULL), - m_backlink(NULL) -{ - if (!name.empty()) - SetName(name); -} - -wxZipEntry::~wxZipEntry() -{ - if (m_backlink) - m_backlink->Release(m_Key); - Release(m_Extra); - Release(m_LocalExtra); -} - -wxZipEntry::wxZipEntry(const wxZipEntry& e) - : wxArchiveEntry(e), - m_SystemMadeBy(e.m_SystemMadeBy), - m_VersionMadeBy(e.m_VersionMadeBy), - m_VersionNeeded(e.m_VersionNeeded), - m_Flags(e.m_Flags), - m_Method(e.m_Method), - m_DateTime(e.m_DateTime), - m_Crc(e.m_Crc), - m_CompressedSize(e.m_CompressedSize), - m_Size(e.m_Size), - m_Name(e.m_Name), - m_Key(e.m_Key), - m_Offset(e.m_Offset), - m_Comment(e.m_Comment), - m_DiskStart(e.m_DiskStart), - m_InternalAttributes(e.m_InternalAttributes), - m_ExternalAttributes(e.m_ExternalAttributes), - m_Extra(AddRef(e.m_Extra)), - m_LocalExtra(AddRef(e.m_LocalExtra)), - m_zipnotifier(NULL), - m_backlink(NULL) -{ -} - -wxZipEntry& wxZipEntry::operator=(const wxZipEntry& e) -{ - if (&e != this) { - m_SystemMadeBy = e.m_SystemMadeBy; - m_VersionMadeBy = e.m_VersionMadeBy; - m_VersionNeeded = e.m_VersionNeeded; - m_Flags = e.m_Flags; - m_Method = e.m_Method; - m_DateTime = e.m_DateTime; - m_Crc = e.m_Crc; - m_CompressedSize = e.m_CompressedSize; - m_Size = e.m_Size; - m_Name = e.m_Name; - m_Key = e.m_Key; - m_Offset = e.m_Offset; - m_Comment = e.m_Comment; - m_DiskStart = e.m_DiskStart; - m_InternalAttributes = e.m_InternalAttributes; - m_ExternalAttributes = e.m_ExternalAttributes; - Copy(m_Extra, e.m_Extra); - Copy(m_LocalExtra, e.m_LocalExtra); - m_zipnotifier = NULL; - if (m_backlink) { - m_backlink->Release(m_Key); - m_backlink = NULL; - } - } - return *this; -} - -wxString wxZipEntry::GetName(wxPathFormat format /*=wxPATH_NATIVE*/) const -{ - bool isDir = IsDir() && !m_Name.empty(); - - // optimisations for common (and easy) cases - switch (wxFileName::GetFormat(format)) { - case wxPATH_DOS: - { - wxString name(isDir ? m_Name + _T("\\") : m_Name); - for (size_t i = 0; i < name.length(); i++) - if (name[i] == _T('/')) - name[i] = _T('\\'); - return name; - } - - case wxPATH_UNIX: - return isDir ? m_Name + _T("/") : m_Name; - - default: - ; - } - - wxFileName fn; - - if (isDir) - fn.AssignDir(m_Name, wxPATH_UNIX); - else - fn.Assign(m_Name, wxPATH_UNIX); - - return fn.GetFullPath(format); -} - -// Static - Internally tars and zips use forward slashes for the path -// separator, absolute paths aren't allowed, and directory names have a -// trailing slash. This function converts a path into this internal format, -// but without a trailing slash for a directory. -// -wxString wxZipEntry::GetInternalName(const wxString& name, - wxPathFormat format /*=wxPATH_NATIVE*/, - bool *pIsDir /*=NULL*/) -{ - wxString internal; - - if (wxFileName::GetFormat(format) != wxPATH_UNIX) - internal = wxFileName(name, format).GetFullPath(wxPATH_UNIX); - else - internal = name; - - bool isDir = !internal.empty() && internal.Last() == '/'; - if (pIsDir) - *pIsDir = isDir; - if (isDir) - internal.erase(internal.length() - 1); - - while (!internal.empty() && *internal.begin() == '/') - internal.erase(0, 1); - while (!internal.empty() && internal.compare(0, 2, _T("./")) == 0) - internal.erase(0, 2); - if (internal == _T(".") || internal == _T("..")) - internal = wxEmptyString; - - return internal; -} - -void wxZipEntry::SetSystemMadeBy(int system) -{ - int mode = GetMode(); - bool wasUnix = IsMadeByUnix(); - - m_SystemMadeBy = (wxUint8)system; - - if (!wasUnix && IsMadeByUnix()) { - SetIsDir(IsDir()); - SetMode(mode); - } else if (wasUnix && !IsMadeByUnix()) { - m_ExternalAttributes &= 0xffff; - } -} - -void wxZipEntry::SetIsDir(bool isDir /*=true*/) -{ - if (isDir) - m_ExternalAttributes |= wxZIP_A_SUBDIR; - else - m_ExternalAttributes &= ~wxZIP_A_SUBDIR; - - if (IsMadeByUnix()) { - m_ExternalAttributes &= ~wxZIP_S_IFMT; - if (isDir) - m_ExternalAttributes |= wxZIP_S_IFDIR; - else - m_ExternalAttributes |= wxZIP_S_IFREG; - } -} - -// Return unix style permission bits -// -int wxZipEntry::GetMode() const -{ - // return unix permissions if present - if (IsMadeByUnix()) - return (m_ExternalAttributes >> 16) & 0777; - - // otherwise synthesize from the dos attribs - int mode = 0644; - if (m_ExternalAttributes & wxZIP_A_RDONLY) - mode &= ~0200; - if (m_ExternalAttributes & wxZIP_A_SUBDIR) - mode |= 0111; - - return mode; -} - -// Set unix permissions -// -void wxZipEntry::SetMode(int mode) -{ - // Set dos attrib bits to be compatible - if (mode & 0222) - m_ExternalAttributes &= ~wxZIP_A_RDONLY; - else - m_ExternalAttributes |= wxZIP_A_RDONLY; - - // set the actual unix permission bits if the system type allows - if (IsMadeByUnix()) { - m_ExternalAttributes &= ~(0777L << 16); - m_ExternalAttributes |= (mode & 0777L) << 16; - } -} - -const char *wxZipEntry::GetExtra() const -{ - return m_Extra ? m_Extra->GetData() : NULL; -} - -size_t wxZipEntry::GetExtraLen() const -{ - return m_Extra ? m_Extra->GetSize() : 0; -} - -void wxZipEntry::SetExtra(const char *extra, size_t len) -{ - Unique(m_Extra, len); - if (len) - memcpy(m_Extra->GetData(), extra, len); -} - -const char *wxZipEntry::GetLocalExtra() const -{ - return m_LocalExtra ? m_LocalExtra->GetData() : NULL; -} - -size_t wxZipEntry::GetLocalExtraLen() const -{ - return m_LocalExtra ? m_LocalExtra->GetSize() : 0; -} - -void wxZipEntry::SetLocalExtra(const char *extra, size_t len) -{ - Unique(m_LocalExtra, len); - if (len) - memcpy(m_LocalExtra->GetData(), extra, len); -} - -void wxZipEntry::SetNotifier(wxZipNotifier& notifier) -{ - wxArchiveEntry::UnsetNotifier(); - m_zipnotifier = ¬ifier; - m_zipnotifier->OnEntryUpdated(*this); -} - -void wxZipEntry::Notify() -{ - if (m_zipnotifier) - m_zipnotifier->OnEntryUpdated(*this); - else if (GetNotifier()) - GetNotifier()->OnEntryUpdated(*this); -} - -void wxZipEntry::UnsetNotifier() -{ - wxArchiveEntry::UnsetNotifier(); - m_zipnotifier = NULL; -} - -size_t wxZipEntry::ReadLocal(wxInputStream& stream, wxMBConv& conv) -{ - wxUint16 nameLen, extraLen; - wxUint32 compressedSize, size, crc; - - wxZipHeader ds(stream, LOCAL_SIZE - 4); - if (!ds) - return 0; - - ds >> m_VersionNeeded >> m_Flags >> m_Method; - SetDateTime(wxDateTime().SetFromDOS(ds.Read32())); - ds >> crc >> compressedSize >> size >> nameLen >> extraLen; - - bool sumsValid = (m_Flags & wxZIP_SUMS_FOLLOW) == 0; - - if (sumsValid || crc) - m_Crc = crc; - if ((sumsValid || compressedSize) || m_Method == wxZIP_METHOD_STORE) - m_CompressedSize = compressedSize; - if ((sumsValid || size) || m_Method == wxZIP_METHOD_STORE) - m_Size = size; - - SetName(ReadString(stream, nameLen, conv), wxPATH_UNIX); - if (stream.LastRead() != nameLen + 0u) - return 0; - - if (extraLen || GetLocalExtraLen()) { - Unique(m_LocalExtra, extraLen); - if (extraLen) { - stream.Read(m_LocalExtra->GetData(), extraLen); - if (stream.LastRead() != extraLen + 0u) - return 0; - } - } - - return LOCAL_SIZE + nameLen + extraLen; -} - -size_t wxZipEntry::WriteLocal(wxOutputStream& stream, wxMBConv& conv) const -{ - wxString unixName = GetName(wxPATH_UNIX); - const wxWX2MBbuf name_buf = conv.cWX2MB(unixName); - const char *name = name_buf; - if (!name) name = ""; - wxUint16 nameLen = wx_truncate_cast(wxUint16, strlen(name)); - - wxDataOutputStream ds(stream); - - ds << m_VersionNeeded << m_Flags << m_Method; - ds.Write32(GetDateTime().GetAsDOS()); - - ds.Write32(m_Crc); - ds.Write32(m_CompressedSize != wxInvalidOffset ? - wx_truncate_cast(wxUint32, m_CompressedSize) : 0); - ds.Write32(m_Size != wxInvalidOffset ? - wx_truncate_cast(wxUint32, m_Size) : 0); - - ds << nameLen; - wxUint16 extraLen = wx_truncate_cast(wxUint16, GetLocalExtraLen()); - ds.Write16(extraLen); - - stream.Write(name, nameLen); - if (extraLen) - stream.Write(m_LocalExtra->GetData(), extraLen); - - return LOCAL_SIZE + nameLen + extraLen; -} - -size_t wxZipEntry::ReadCentral(wxInputStream& stream, wxMBConv& conv) -{ - wxUint16 nameLen, extraLen, commentLen; - - wxZipHeader ds(stream, CENTRAL_SIZE - 4); - if (!ds) - return 0; - - ds >> m_VersionMadeBy >> m_SystemMadeBy; - - SetVersionNeeded(ds.Read16()); - SetFlags(ds.Read16()); - SetMethod(ds.Read16()); - SetDateTime(wxDateTime().SetFromDOS(ds.Read32())); - SetCrc(ds.Read32()); - SetCompressedSize(ds.Read32()); - SetSize(ds.Read32()); - - ds >> nameLen >> extraLen >> commentLen - >> m_DiskStart >> m_InternalAttributes >> m_ExternalAttributes; - SetOffset(ds.Read32()); - - SetName(ReadString(stream, nameLen, conv), wxPATH_UNIX); - if (stream.LastRead() != nameLen + 0u) - return 0; - - if (extraLen || GetExtraLen()) { - Unique(m_Extra, extraLen); - if (extraLen) { - stream.Read(m_Extra->GetData(), extraLen); - if (stream.LastRead() != extraLen + 0u) - return 0; - } - } - - if (commentLen) { - m_Comment = ReadString(stream, commentLen, conv); - if (stream.LastRead() != commentLen + 0u) - return 0; - } else { - m_Comment.clear(); - } - - return CENTRAL_SIZE + nameLen + extraLen + commentLen; -} - -size_t wxZipEntry::WriteCentral(wxOutputStream& stream, wxMBConv& conv) const -{ - wxString unixName = GetName(wxPATH_UNIX); - const wxWX2MBbuf name_buf = conv.cWX2MB(unixName); - const char *name = name_buf; - if (!name) name = ""; - wxUint16 nameLen = wx_truncate_cast(wxUint16, strlen(name)); - - const wxWX2MBbuf comment_buf = conv.cWX2MB(m_Comment); - const char *comment = comment_buf; - if (!comment) comment = ""; - wxUint16 commentLen = wx_truncate_cast(wxUint16, strlen(comment)); - - wxUint16 extraLen = wx_truncate_cast(wxUint16, GetExtraLen()); - - wxDataOutputStream ds(stream); - - ds << CENTRAL_MAGIC << m_VersionMadeBy << m_SystemMadeBy; - - ds.Write16(wx_truncate_cast(wxUint16, GetVersionNeeded())); - ds.Write16(wx_truncate_cast(wxUint16, GetFlags())); - ds.Write16(wx_truncate_cast(wxUint16, GetMethod())); - ds.Write32(GetDateTime().GetAsDOS()); - ds.Write32(GetCrc()); - ds.Write32(wx_truncate_cast(wxUint32, GetCompressedSize())); - ds.Write32(wx_truncate_cast(wxUint32, GetSize())); - ds.Write16(nameLen); - ds.Write16(extraLen); - - ds << commentLen << m_DiskStart << m_InternalAttributes - << m_ExternalAttributes << wx_truncate_cast(wxUint32, GetOffset()); - - stream.Write(name, nameLen); - if (extraLen) - stream.Write(GetExtra(), extraLen); - stream.Write(comment, commentLen); - - return CENTRAL_SIZE + nameLen + extraLen + commentLen; -} - -// Info-zip prefixes this record with a signature, but pkzip doesn't. So if -// the 1st value is the signature then it is probably an info-zip record, -// though there is a small chance that it is in fact a pkzip record which -// happens to have the signature as it's CRC. -// -size_t wxZipEntry::ReadDescriptor(wxInputStream& stream) -{ - wxZipHeader ds(stream, SUMS_SIZE); - if (!ds) - return 0; - - m_Crc = ds.Read32(); - m_CompressedSize = ds.Read32(); - m_Size = ds.Read32(); - - // if 1st value is the signature then this is probably an info-zip record - if (m_Crc == SUMS_MAGIC) - { - wxZipHeader buf(stream, 8); - wxUint32 u1 = buf.GetSize() >= 4 ? buf.Read32() : (wxUint32)LOCAL_MAGIC; - wxUint32 u2 = buf.GetSize() == 8 ? buf.Read32() : 0; - - // look for the signature of the following record to decide which - if ((u1 == LOCAL_MAGIC || u1 == CENTRAL_MAGIC) && - (u2 != LOCAL_MAGIC && u2 != CENTRAL_MAGIC)) - { - // it's a pkzip style record after all! - if (buf.GetSize() > 0) - stream.Ungetch(buf.GetData(), buf.GetSize()); - } - else - { - // it's an info-zip record as expected - if (buf.GetSize() > 4) - stream.Ungetch(buf.GetData() + 4, buf.GetSize() - 4); - m_Crc = wx_truncate_cast(wxUint32, m_CompressedSize); - m_CompressedSize = m_Size; - m_Size = u1; - return SUMS_SIZE + 4; - } - } - - return SUMS_SIZE; -} - -size_t wxZipEntry::WriteDescriptor(wxOutputStream& stream, wxUint32 crc, - wxFileOffset compressedSize, wxFileOffset size) -{ - m_Crc = crc; - m_CompressedSize = compressedSize; - m_Size = size; - - wxDataOutputStream ds(stream); - - ds.Write32(crc); - ds.Write32(wx_truncate_cast(wxUint32, compressedSize)); - ds.Write32(wx_truncate_cast(wxUint32, size)); - - return SUMS_SIZE; -} - - -///////////////////////////////////////////////////////////////////////////// -// wxZipEndRec - holds the end of central directory record - -class wxZipEndRec -{ -public: - wxZipEndRec(); - - int GetDiskNumber() const { return m_DiskNumber; } - int GetStartDisk() const { return m_StartDisk; } - int GetEntriesHere() const { return m_EntriesHere; } - int GetTotalEntries() const { return m_TotalEntries; } - wxFileOffset GetSize() const { return m_Size; } - wxFileOffset GetOffset() const { return m_Offset; } - wxString GetComment() const { return m_Comment; } - - void SetDiskNumber(int num) - { m_DiskNumber = wx_truncate_cast(wxUint16, num); } - void SetStartDisk(int num) - { m_StartDisk = wx_truncate_cast(wxUint16, num); } - void SetEntriesHere(int num) - { m_EntriesHere = wx_truncate_cast(wxUint16, num); } - void SetTotalEntries(int num) - { m_TotalEntries = wx_truncate_cast(wxUint16, num); } - void SetSize(wxFileOffset size) - { m_Size = wx_truncate_cast(wxUint32, size); } - void SetOffset(wxFileOffset offset) - { m_Offset = wx_truncate_cast(wxUint32, offset); } - void SetComment(const wxString& comment) - { m_Comment = comment; } - - bool Read(wxInputStream& stream, wxMBConv& conv); - bool Write(wxOutputStream& stream, wxMBConv& conv) const; - -private: - wxUint16 m_DiskNumber; - wxUint16 m_StartDisk; - wxUint16 m_EntriesHere; - wxUint16 m_TotalEntries; - wxUint32 m_Size; - wxUint32 m_Offset; - wxString m_Comment; -}; - -wxZipEndRec::wxZipEndRec() - : m_DiskNumber(0), - m_StartDisk(0), - m_EntriesHere(0), - m_TotalEntries(0), - m_Size(0), - m_Offset(0) -{ -} - -bool wxZipEndRec::Write(wxOutputStream& stream, wxMBConv& conv) const -{ - const wxWX2MBbuf comment_buf = conv.cWX2MB(m_Comment); - const char *comment = comment_buf; - if (!comment) comment = ""; - wxUint16 commentLen = (wxUint16)strlen(comment); - - wxDataOutputStream ds(stream); - - ds << END_MAGIC << m_DiskNumber << m_StartDisk << m_EntriesHere - << m_TotalEntries << m_Size << m_Offset << commentLen; - - stream.Write(comment, commentLen); - - return stream.IsOk(); -} - -bool wxZipEndRec::Read(wxInputStream& stream, wxMBConv& conv) -{ - wxZipHeader ds(stream, END_SIZE - 4); - if (!ds) - return false; - - wxUint16 commentLen; - - ds >> m_DiskNumber >> m_StartDisk >> m_EntriesHere - >> m_TotalEntries >> m_Size >> m_Offset >> commentLen; - - if (commentLen) { - m_Comment = ReadString(stream, commentLen, conv); - if (stream.LastRead() != commentLen + 0u) - return false; - } - - if (m_DiskNumber != 0 || m_StartDisk != 0 || - m_EntriesHere != m_TotalEntries) - wxLogWarning(_("assuming this is a multi-part zip concatenated")); - - return true; -} - - -///////////////////////////////////////////////////////////////////////////// -// A weak link from an input stream to an output stream - -class wxZipStreamLink -{ -public: - wxZipStreamLink(wxZipOutputStream *stream) : m_ref(1), m_stream(stream) { } - - wxZipStreamLink *AddRef() { m_ref++; return this; } - wxZipOutputStream *GetOutputStream() const { return m_stream; } - - void Release(class wxZipInputStream *WXUNUSED(s)) - { if (--m_ref == 0) delete this; } - void Release(class wxZipOutputStream *WXUNUSED(s)) - { m_stream = NULL; if (--m_ref == 0) delete this; } - -private: - ~wxZipStreamLink() { } - - int m_ref; - wxZipOutputStream *m_stream; - - wxSUPPRESS_GCC_PRIVATE_DTOR_WARNING(wxZipStreamLink) -}; - - -///////////////////////////////////////////////////////////////////////////// -// Input stream - -// leave the default wxZipEntryPtr free for users -wxDECLARE_SCOPED_PTR(wxZipEntry, wxZipEntryPtr_) -wxDEFINE_SCOPED_PTR (wxZipEntry, wxZipEntryPtr_) - -// constructor -// -wxZipInputStream::wxZipInputStream(wxInputStream& stream, - wxMBConv& conv /*=wxConvLocal*/) - : wxArchiveInputStream(stream, conv) -{ - Init(); -} - -wxZipInputStream::wxZipInputStream(wxInputStream *stream, - wxMBConv& conv /*=wxConvLocal*/) - : wxArchiveInputStream(stream, conv) -{ - Init(); -} - -#if WXWIN_COMPATIBILITY_2_6 && wxUSE_FFILE - -// Part of the compatibility constructor, which has been made inline to -// avoid a problem with it not being exported by mingw 3.2.3 -// -void wxZipInputStream::Init(const wxString& file) -{ - // no error messages - wxLogNull nolog; - Init(); - m_allowSeeking = true; - wxFFileInputStream *ffile; - ffile = wx_static_cast(wxFFileInputStream*, m_parent_i_stream); - wxZipEntryPtr_ entry; - - if (ffile->Ok()) { - do { - entry.reset(GetNextEntry()); - } - while (entry.get() != NULL && entry->GetInternalName() != file); - } - - if (entry.get() == NULL) - m_lasterror = wxSTREAM_READ_ERROR; -} - -wxInputStream* wxZipInputStream::OpenFile(const wxString& archive) -{ - wxLogNull nolog; - return new wxFFileInputStream(archive); -} - -#endif // WXWIN_COMPATIBILITY_2_6 && wxUSE_FFILE - -void wxZipInputStream::Init() -{ - m_store = new wxStoredInputStream(*m_parent_i_stream); - m_inflate = NULL; - m_rawin = NULL; - m_raw = false; - m_headerSize = 0; - m_decomp = NULL; - m_parentSeekable = false; - m_weaklinks = new wxZipWeakLinks; - m_streamlink = NULL; - m_offsetAdjustment = 0; - m_position = wxInvalidOffset; - m_signature = 0; - m_TotalEntries = 0; - m_lasterror = m_parent_i_stream->GetLastError(); -#if WXWIN_COMPATIBILITY_2_6 - m_allowSeeking = false; -#endif -} - -wxZipInputStream::~wxZipInputStream() -{ - CloseDecompressor(m_decomp); - - delete m_store; - delete m_inflate; - delete m_rawin; - - m_weaklinks->Release(this); - - if (m_streamlink) - m_streamlink->Release(this); -} - -wxString wxZipInputStream::GetComment() -{ - if (m_position == wxInvalidOffset) - if (!LoadEndRecord()) - return wxEmptyString; - - if (!m_parentSeekable && Eof() && m_signature) { - m_lasterror = wxSTREAM_NO_ERROR; - m_lasterror = ReadLocal(true); - } - - return m_Comment; -} - -int wxZipInputStream::GetTotalEntries() -{ - if (m_position == wxInvalidOffset) - LoadEndRecord(); - return m_TotalEntries; -} - -wxZipStreamLink *wxZipInputStream::MakeLink(wxZipOutputStream *out) -{ - wxZipStreamLink *link = NULL; - - if (!m_parentSeekable && (IsOpened() || !Eof())) { - link = new wxZipStreamLink(out); - if (m_streamlink) - m_streamlink->Release(this); - m_streamlink = link->AddRef(); - } - - return link; -} - -bool wxZipInputStream::LoadEndRecord() -{ - wxCHECK(m_position == wxInvalidOffset, false); - if (!IsOk()) - return false; - - m_position = 0; - - // First find the end-of-central-directory record. - if (!FindEndRecord()) { - // failed, so either this is a non-seekable stream (ok), or not a zip - if (m_parentSeekable) { - m_lasterror = wxSTREAM_READ_ERROR; - wxLogError(_("invalid zip file")); - return false; - } - else { - wxLogNull nolog; - wxFileOffset pos = m_parent_i_stream->TellI(); - if (pos != wxInvalidOffset) - m_offsetAdjustment = m_position = pos; - return true; - } - } - - wxZipEndRec endrec; - - // Read in the end record - wxFileOffset endPos = m_parent_i_stream->TellI() - 4; - if (!endrec.Read(*m_parent_i_stream, GetConv())) - return false; - - m_TotalEntries = endrec.GetTotalEntries(); - m_Comment = endrec.GetComment(); - - // Now find the central-directory. we have the file offset of - // the CD, so look there first. - if (m_parent_i_stream->SeekI(endrec.GetOffset()) != wxInvalidOffset && - ReadSignature() == CENTRAL_MAGIC) { - m_signature = CENTRAL_MAGIC; - m_position = endrec.GetOffset(); - m_offsetAdjustment = 0; - return true; - } - - // If it's not there, then it could be that the zip has been appended - // to a self extractor, so take the CD size (also in endrec), subtract - // it from the file offset of the end-central-directory and look there. - if (m_parent_i_stream->SeekI(endPos - endrec.GetSize()) - != wxInvalidOffset && ReadSignature() == CENTRAL_MAGIC) { - m_signature = CENTRAL_MAGIC; - m_position = endPos - endrec.GetSize(); - m_offsetAdjustment = m_position - endrec.GetOffset(); - return true; - } - - wxLogError(_("can't find central directory in zip")); - m_lasterror = wxSTREAM_READ_ERROR; - return false; -} - -// Find the end-of-central-directory record. -// If found the stream will be positioned just past the 4 signature bytes. -// -bool wxZipInputStream::FindEndRecord() -{ - if (!m_parent_i_stream->IsSeekable()) - return false; - - // usually it's 22 bytes in size and the last thing in the file - { - wxLogNull nolog; - if (m_parent_i_stream->SeekI(-END_SIZE, wxFromEnd) == wxInvalidOffset) - return false; - } - - m_parentSeekable = true; - m_signature = 0; - char magic[4]; - if (m_parent_i_stream->Read(magic, 4).LastRead() != 4) - return false; - if ((m_signature = CrackUint32(magic)) == END_MAGIC) - return true; - - // unfortunately, the record has a comment field that can be up to 65535 - // bytes in length, so if the signature not found then search backwards. - wxFileOffset pos = m_parent_i_stream->TellI(); - const int BUFSIZE = 1024; - wxCharBuffer buf(BUFSIZE); - - memcpy(buf.data(), magic, 3); - wxFileOffset minpos = wxMax(pos - 65535L, 0); - - while (pos > minpos) { - size_t len = wx_truncate_cast(size_t, - pos - wxMax(pos - (BUFSIZE - 3), minpos)); - memcpy(buf.data() + len, buf, 3); - pos -= len; - - if (m_parent_i_stream->SeekI(pos, wxFromStart) == wxInvalidOffset || - m_parent_i_stream->Read(buf.data(), len).LastRead() != len) - return false; - - char *p = buf.data() + len; - - while (p-- > buf.data()) { - if ((m_signature = CrackUint32(p)) == END_MAGIC) { - size_t remainder = buf.data() + len - p; - if (remainder > 4) - m_parent_i_stream->Ungetch(p + 4, remainder - 4); - return true; - } - } - } - - return false; -} - -wxZipEntry *wxZipInputStream::GetNextEntry() -{ - if (m_position == wxInvalidOffset) - if (!LoadEndRecord()) - return NULL; - - m_lasterror = m_parentSeekable ? ReadCentral() : ReadLocal(); - if (!IsOk()) - return NULL; - - wxZipEntryPtr_ entry(new wxZipEntry(m_entry)); - entry->m_backlink = m_weaklinks->AddEntry(entry.get(), entry->GetKey()); - return entry.release(); -} - -wxStreamError wxZipInputStream::ReadCentral() -{ - if (!AtHeader()) - CloseEntry(); - - if (m_signature == END_MAGIC) - return wxSTREAM_EOF; - - if (m_signature != CENTRAL_MAGIC) { - wxLogError(_("error reading zip central directory")); - return wxSTREAM_READ_ERROR; - } - - if (QuietSeek(*m_parent_i_stream, m_position + 4) == wxInvalidOffset) - return wxSTREAM_READ_ERROR; - - size_t size = m_entry.ReadCentral(*m_parent_i_stream, GetConv()); - if (!size) { - m_signature = 0; - return wxSTREAM_READ_ERROR; - } - - m_position += size; - m_signature = ReadSignature(); - - if (m_offsetAdjustment) - m_entry.SetOffset(m_entry.GetOffset() + m_offsetAdjustment); - m_entry.SetKey(m_entry.GetOffset()); - - return wxSTREAM_NO_ERROR; -} - -wxStreamError wxZipInputStream::ReadLocal(bool readEndRec /*=false*/) -{ - if (!AtHeader()) - CloseEntry(); - - if (!m_signature) - m_signature = ReadSignature(); - - if (m_signature == CENTRAL_MAGIC || m_signature == END_MAGIC) { - if (m_streamlink && !m_streamlink->GetOutputStream()) { - m_streamlink->Release(this); - m_streamlink = NULL; - } - } - - while (m_signature == CENTRAL_MAGIC) { - if (m_weaklinks->IsEmpty() && m_streamlink == NULL) - return wxSTREAM_EOF; - - size_t size = m_entry.ReadCentral(*m_parent_i_stream, GetConv()); - m_position += size; - m_signature = 0; - if (!size) - return wxSTREAM_READ_ERROR; - - wxZipEntry *entry = m_weaklinks->GetEntry(m_entry.GetOffset()); - if (entry) { - entry->SetSystemMadeBy(m_entry.GetSystemMadeBy()); - entry->SetVersionMadeBy(m_entry.GetVersionMadeBy()); - entry->SetComment(m_entry.GetComment()); - entry->SetDiskStart(m_entry.GetDiskStart()); - entry->SetInternalAttributes(m_entry.GetInternalAttributes()); - entry->SetExternalAttributes(m_entry.GetExternalAttributes()); - Copy(entry->m_Extra, m_entry.m_Extra); - entry->Notify(); - m_weaklinks->RemoveEntry(entry->GetOffset()); - } - - m_signature = ReadSignature(); - } - - if (m_signature == END_MAGIC) { - if (readEndRec || m_streamlink) { - wxZipEndRec endrec; - endrec.Read(*m_parent_i_stream, GetConv()); - m_Comment = endrec.GetComment(); - m_signature = 0; - if (m_streamlink) { - m_streamlink->GetOutputStream()->SetComment(endrec.GetComment()); - m_streamlink->Release(this); - m_streamlink = NULL; - } - } - return wxSTREAM_EOF; - } - - if (m_signature == LOCAL_MAGIC) { - m_headerSize = m_entry.ReadLocal(*m_parent_i_stream, GetConv()); - m_signature = 0; - m_entry.SetOffset(m_position); - m_entry.SetKey(m_position); - - if (m_headerSize) { - m_TotalEntries++; - return wxSTREAM_NO_ERROR; - } - } - - wxLogError(_("error reading zip local header")); - return wxSTREAM_READ_ERROR; -} - -wxUint32 wxZipInputStream::ReadSignature() -{ - char magic[4]; - m_parent_i_stream->Read(magic, 4); - return m_parent_i_stream->LastRead() == 4 ? CrackUint32(magic) : 0; -} - -bool wxZipInputStream::OpenEntry(wxArchiveEntry& entry) -{ - wxZipEntry *zipEntry = wxStaticCast(&entry, wxZipEntry); - return zipEntry ? OpenEntry(*zipEntry) : false; -} - -// Open an entry -// -bool wxZipInputStream::DoOpen(wxZipEntry *entry, bool raw) -{ - if (m_position == wxInvalidOffset) - if (!LoadEndRecord()) - return false; - if (m_lasterror == wxSTREAM_READ_ERROR) - return false; - if (IsOpened()) - CloseEntry(); - - m_raw = raw; - - if (entry) { - if (AfterHeader() && entry->GetKey() == m_entry.GetOffset()) - return true; - // can only open the current entry on a non-seekable stream - wxCHECK(m_parentSeekable, false); - } - - m_lasterror = wxSTREAM_READ_ERROR; - - if (entry) - m_entry = *entry; - - if (m_parentSeekable) { - if (QuietSeek(*m_parent_i_stream, m_entry.GetOffset()) - == wxInvalidOffset) - return false; - if (ReadSignature() != LOCAL_MAGIC) { - wxLogError(_("bad zipfile offset to entry")); - return false; - } - } - - if (m_parentSeekable || AtHeader()) { - m_headerSize = m_entry.ReadLocal(*m_parent_i_stream, GetConv()); - if (m_headerSize && m_parentSeekable) { - wxZipEntry *ref = m_weaklinks->GetEntry(m_entry.GetKey()); - if (ref) { - Copy(ref->m_LocalExtra, m_entry.m_LocalExtra); - ref->Notify(); - m_weaklinks->RemoveEntry(ref->GetKey()); - } - if (entry && entry != ref) { - Copy(entry->m_LocalExtra, m_entry.m_LocalExtra); - entry->Notify(); - } - } - } - - if (m_headerSize) - m_lasterror = wxSTREAM_NO_ERROR; - return IsOk(); -} - -bool wxZipInputStream::OpenDecompressor(bool raw /*=false*/) -{ - wxASSERT(AfterHeader()); - - wxFileOffset compressedSize = m_entry.GetCompressedSize(); - - if (raw) - m_raw = true; - - if (m_raw) { - if (compressedSize != wxInvalidOffset) { - m_store->Open(compressedSize); - m_decomp = m_store; - } else { - if (!m_rawin) - m_rawin = new wxRawInputStream(*m_parent_i_stream); - m_decomp = m_rawin->Open(OpenDecompressor(m_rawin->GetTee())); - } - } else { - if (compressedSize != wxInvalidOffset && - (m_entry.GetMethod() != wxZIP_METHOD_DEFLATE || - wxZlibInputStream::CanHandleGZip())) { - m_store->Open(compressedSize); - m_decomp = OpenDecompressor(*m_store); - } else { - m_decomp = OpenDecompressor(*m_parent_i_stream); - } - } - - m_crcAccumulator = crc32(0, Z_NULL, 0); - m_lasterror = m_decomp ? m_decomp->GetLastError() : wxSTREAM_READ_ERROR; - return IsOk(); -} - -// Can be overriden to add support for additional decompression methods -// -wxInputStream *wxZipInputStream::OpenDecompressor(wxInputStream& stream) -{ - switch (m_entry.GetMethod()) { - case wxZIP_METHOD_STORE: - if (m_entry.GetSize() == wxInvalidOffset) { - wxLogError(_("stored file length not in Zip header")); - break; - } - m_store->Open(m_entry.GetSize()); - return m_store; - - case wxZIP_METHOD_DEFLATE: - if (!m_inflate) - m_inflate = new wxZlibInputStream2(stream); - else - m_inflate->Open(stream); - return m_inflate; - - default: - wxLogError(_("unsupported Zip compression method")); - } - - return NULL; -} - -bool wxZipInputStream::CloseDecompressor(wxInputStream *decomp) -{ - if (decomp && decomp == m_rawin) - return CloseDecompressor(m_rawin->GetFilterInputStream()); - if (decomp != m_store && decomp != m_inflate) - delete decomp; - return true; -} - -// Closes the current entry and positions the underlying stream at the start -// of the next entry -// -bool wxZipInputStream::CloseEntry() -{ - if (AtHeader()) - return true; - if (m_lasterror == wxSTREAM_READ_ERROR) - return false; - - if (!m_parentSeekable) { - if (!IsOpened() && !OpenDecompressor(true)) - return false; - - const int BUFSIZE = 8192; - wxCharBuffer buf(BUFSIZE); - while (IsOk()) - Read(buf.data(), BUFSIZE); - - m_position += m_headerSize + m_entry.GetCompressedSize(); - } - - if (m_lasterror == wxSTREAM_EOF) - m_lasterror = wxSTREAM_NO_ERROR; - - CloseDecompressor(m_decomp); - m_decomp = NULL; - m_entry = wxZipEntry(); - m_headerSize = 0; - m_raw = false; - - return IsOk(); -} - -size_t wxZipInputStream::OnSysRead(void *buffer, size_t size) -{ - if (!IsOpened()) - if ((AtHeader() && !DoOpen()) || !OpenDecompressor()) - m_lasterror = wxSTREAM_READ_ERROR; - if (!IsOk() || !size) - return 0; - - size_t count = m_decomp->Read(buffer, size).LastRead(); - if (!m_raw) - m_crcAccumulator = crc32(m_crcAccumulator, (Byte*)buffer, count); - if (count < size) - m_lasterror = m_decomp->GetLastError(); - - if (Eof()) { - if ((m_entry.GetFlags() & wxZIP_SUMS_FOLLOW) != 0) { - m_headerSize += m_entry.ReadDescriptor(*m_parent_i_stream); - wxZipEntry *entry = m_weaklinks->GetEntry(m_entry.GetKey()); - - if (entry) { - entry->SetCrc(m_entry.GetCrc()); - entry->SetCompressedSize(m_entry.GetCompressedSize()); - entry->SetSize(m_entry.GetSize()); - entry->Notify(); - } - } - - if (!m_raw) { - m_lasterror = wxSTREAM_READ_ERROR; - - if (m_entry.GetSize() != TellI()) - wxLogError(_("reading zip stream (entry %s): bad length"), - m_entry.GetName().c_str()); - else if (m_crcAccumulator != m_entry.GetCrc()) - wxLogError(_("reading zip stream (entry %s): bad crc"), - m_entry.GetName().c_str()); - else - m_lasterror = wxSTREAM_EOF; - } - } - - return count; -} - -#if WXWIN_COMPATIBILITY_2_6 - -// Borrowed from VS's zip stream (c) 1999 Vaclav Slavik -// -wxFileOffset wxZipInputStream::OnSysSeek(wxFileOffset seek, wxSeekMode mode) -{ - // seeking works when the stream is created with the compatibility - // constructor - if (!m_allowSeeking) - return wxInvalidOffset; - if (!IsOpened()) - if ((AtHeader() && !DoOpen()) || !OpenDecompressor()) - m_lasterror = wxSTREAM_READ_ERROR; - if (!IsOk()) - return wxInvalidOffset; - - // NB: since ZIP files don't natively support seeking, we have to - // implement a brute force workaround -- reading all the data - // between current and the new position (or between beginning of - // the file and new position...) - - wxFileOffset nextpos; - wxFileOffset pos = TellI(); - - switch ( mode ) - { - case wxFromCurrent : nextpos = seek + pos; break; - case wxFromStart : nextpos = seek; break; - case wxFromEnd : nextpos = GetLength() + seek; break; - default : nextpos = pos; break; /* just to fool compiler, never happens */ - } - - wxFileOffset toskip wxDUMMY_INITIALIZE(0); - if ( nextpos >= pos ) - { - toskip = nextpos - pos; - } - else - { - wxZipEntry current(m_entry); - if (!OpenEntry(current)) - { - m_lasterror = wxSTREAM_READ_ERROR; - return pos; - } - toskip = nextpos; - } - - if ( toskip > 0 ) - { - const int BUFSIZE = 4096; - size_t sz; - char buffer[BUFSIZE]; - while ( toskip > 0 ) - { - sz = wx_truncate_cast(size_t, wxMin(toskip, BUFSIZE)); - Read(buffer, sz); - toskip -= sz; - } - } - - pos = nextpos; - return pos; -} - -#endif // WXWIN_COMPATIBILITY_2_6 - - -///////////////////////////////////////////////////////////////////////////// -// Output stream - -#include "wx/listimpl.cpp" -WX_DEFINE_LIST(wxZipEntryList_) - -wxZipOutputStream::wxZipOutputStream(wxOutputStream& stream, - int level /*=-1*/, - wxMBConv& conv /*=wxConvLocal*/) - : wxArchiveOutputStream(stream, conv) -{ - Init(level); -} - -wxZipOutputStream::wxZipOutputStream(wxOutputStream *stream, - int level /*=-1*/, - wxMBConv& conv /*=wxConvLocal*/) - : wxArchiveOutputStream(stream, conv) -{ - Init(level); -} - -void wxZipOutputStream::Init(int level) -{ - m_store = new wxStoredOutputStream(*m_parent_o_stream); - m_deflate = NULL; - m_backlink = NULL; - m_initialData = new char[OUTPUT_LATENCY]; - m_initialSize = 0; - m_pending = NULL; - m_raw = false; - m_headerOffset = 0; - m_headerSize = 0; - m_entrySize = 0; - m_comp = NULL; - m_level = level; - m_offsetAdjustment = wxInvalidOffset; -} - -wxZipOutputStream::~wxZipOutputStream() -{ - Close(); - WX_CLEAR_LIST(wxZipEntryList_, m_entries); - delete m_store; - delete m_deflate; - delete m_pending; - delete [] m_initialData; - if (m_backlink) - m_backlink->Release(this); -} - -bool wxZipOutputStream::PutNextEntry( - const wxString& name, - const wxDateTime& dt /*=wxDateTime::Now()*/, - wxFileOffset size /*=wxInvalidOffset*/) -{ - return PutNextEntry(new wxZipEntry(name, dt, size)); -} - -bool wxZipOutputStream::PutNextDirEntry( - const wxString& name, - const wxDateTime& dt /*=wxDateTime::Now()*/) -{ - wxZipEntry *entry = new wxZipEntry(name, dt); - entry->SetIsDir(); - return PutNextEntry(entry); -} - -bool wxZipOutputStream::CopyEntry(wxZipEntry *entry, - wxZipInputStream& inputStream) -{ - wxZipEntryPtr_ e(entry); - - return - inputStream.DoOpen(e.get(), true) && - DoCreate(e.release(), true) && - Write(inputStream).IsOk() && inputStream.Eof(); -} - -bool wxZipOutputStream::PutNextEntry(wxArchiveEntry *entry) -{ - wxZipEntry *zipEntry = wxStaticCast(entry, wxZipEntry); - if (!zipEntry) - delete entry; - return PutNextEntry(zipEntry); -} - -bool wxZipOutputStream::CopyEntry(wxArchiveEntry *entry, - wxArchiveInputStream& stream) -{ - wxZipEntry *zipEntry = wxStaticCast(entry, wxZipEntry); - - if (!zipEntry || !stream.OpenEntry(*zipEntry)) { - delete entry; - return false; - } - - return CopyEntry(zipEntry, wx_static_cast(wxZipInputStream&, stream)); -} - -bool wxZipOutputStream::CopyArchiveMetaData(wxZipInputStream& inputStream) -{ - m_Comment = inputStream.GetComment(); - if (m_backlink) - m_backlink->Release(this); - m_backlink = inputStream.MakeLink(this); - return true; -} - -bool wxZipOutputStream::CopyArchiveMetaData(wxArchiveInputStream& stream) -{ - return CopyArchiveMetaData(wx_static_cast(wxZipInputStream&, stream)); -} - -void wxZipOutputStream::SetLevel(int level) -{ - if (level != m_level) { - if (m_comp != m_deflate) - delete m_deflate; - m_deflate = NULL; - m_level = level; - } -} - -bool wxZipOutputStream::DoCreate(wxZipEntry *entry, bool raw /*=false*/) -{ - CloseEntry(); - - m_pending = entry; - if (!m_pending) - return false; - - // write the signature bytes right away - wxDataOutputStream ds(*m_parent_o_stream); - ds << LOCAL_MAGIC; - - // and if this is the first entry test for seekability - if (m_headerOffset == 0 && m_parent_o_stream->IsSeekable()) { -#if wxUSE_LOG - bool logging = wxLog::IsEnabled(); - wxLogNull nolog; -#endif // wxUSE_LOG - wxFileOffset here = m_parent_o_stream->TellO(); - - if (here != wxInvalidOffset && here >= 4) { - if (m_parent_o_stream->SeekO(here - 4) == here - 4) { - m_offsetAdjustment = here - 4; -#if wxUSE_LOG - wxLog::EnableLogging(logging); -#endif // wxUSE_LOG - m_parent_o_stream->SeekO(here); - } - } - } - - m_pending->SetOffset(m_headerOffset); - - m_crcAccumulator = crc32(0, Z_NULL, 0); - - if (raw) - m_raw = true; - - m_lasterror = wxSTREAM_NO_ERROR; - return true; -} - -// Can be overriden to add support for additional compression methods -// -wxOutputStream *wxZipOutputStream::OpenCompressor( - wxOutputStream& stream, - wxZipEntry& entry, - const Buffer bufs[]) -{ - if (entry.GetMethod() == wxZIP_METHOD_DEFAULT) { - if (GetLevel() == 0 - && (IsParentSeekable() - || entry.GetCompressedSize() != wxInvalidOffset - || entry.GetSize() != wxInvalidOffset)) { - entry.SetMethod(wxZIP_METHOD_STORE); - } else { - int size = 0; - for (int i = 0; bufs[i].m_data; ++i) - size += bufs[i].m_size; - entry.SetMethod(size <= 6 ? - wxZIP_METHOD_STORE : wxZIP_METHOD_DEFLATE); - } - } - - switch (entry.GetMethod()) { - case wxZIP_METHOD_STORE: - if (entry.GetCompressedSize() == wxInvalidOffset) - entry.SetCompressedSize(entry.GetSize()); - return m_store; - - case wxZIP_METHOD_DEFLATE: - { - int defbits = wxZIP_DEFLATE_NORMAL; - switch (GetLevel()) { - case 0: case 1: - defbits = wxZIP_DEFLATE_SUPERFAST; - break; - case 2: case 3: case 4: - defbits = wxZIP_DEFLATE_FAST; - break; - case 8: case 9: - defbits = wxZIP_DEFLATE_EXTRA; - break; - } - entry.SetFlags((entry.GetFlags() & ~wxZIP_DEFLATE_MASK) | - defbits | wxZIP_SUMS_FOLLOW); - - if (!m_deflate) - m_deflate = new wxZlibOutputStream2(stream, GetLevel()); - else - m_deflate->Open(stream); - - return m_deflate; - } - - default: - wxLogError(_("unsupported Zip compression method")); - } - - return NULL; -} - -bool wxZipOutputStream::CloseCompressor(wxOutputStream *comp) -{ - if (comp == m_deflate) - m_deflate->Close(); - else if (comp != m_store) - delete comp; - return true; -} - -// This is called when OUPUT_LATENCY bytes has been written to the -// wxZipOutputStream to actually create the zip entry. -// -void wxZipOutputStream::CreatePendingEntry(const void *buffer, size_t size) -{ - wxASSERT(IsOk() && m_pending && !m_comp); - wxZipEntryPtr_ spPending(m_pending); - m_pending = NULL; - - Buffer bufs[] = { - { m_initialData, m_initialSize }, - { (const char*)buffer, size }, - { NULL, 0 } - }; - - if (m_raw) - m_comp = m_store; - else - m_comp = OpenCompressor(*m_store, *spPending, - m_initialSize ? bufs : bufs + 1); - - if (IsParentSeekable() - || (spPending->m_Crc - && spPending->m_CompressedSize != wxInvalidOffset - && spPending->m_Size != wxInvalidOffset)) - spPending->m_Flags &= ~wxZIP_SUMS_FOLLOW; - else - if (spPending->m_CompressedSize != wxInvalidOffset) - spPending->m_Flags |= wxZIP_SUMS_FOLLOW; - - m_headerSize = spPending->WriteLocal(*m_parent_o_stream, GetConv()); - m_lasterror = m_parent_o_stream->GetLastError(); - - if (IsOk()) { - m_entries.push_back(spPending.release()); - OnSysWrite(m_initialData, m_initialSize); - } - - m_initialSize = 0; -} - -// This is called to write out the zip entry when Close has been called -// before OUTPUT_LATENCY bytes has been written to the wxZipOutputStream. -// -void wxZipOutputStream::CreatePendingEntry() -{ - wxASSERT(IsOk() && m_pending && !m_comp); - wxZipEntryPtr_ spPending(m_pending); - m_pending = NULL; - m_lasterror = wxSTREAM_WRITE_ERROR; - - if (!m_raw) { - // Initially compresses the data to memory, then fall back to 'store' - // if the compressor makes the data larger rather than smaller. - wxMemoryOutputStream mem; - Buffer bufs[] = { { m_initialData, m_initialSize }, { NULL, 0 } }; - wxOutputStream *comp = OpenCompressor(mem, *spPending, bufs); - - if (!comp) - return; - if (comp != m_store) { - bool ok = comp->Write(m_initialData, m_initialSize).IsOk(); - CloseCompressor(comp); - if (!ok) - return; - } - - m_entrySize = m_initialSize; - m_crcAccumulator = crc32(0, (Byte*)m_initialData, m_initialSize); - - if (mem.GetSize() > 0 && mem.GetSize() < m_initialSize) { - m_initialSize = mem.GetSize(); - mem.CopyTo(m_initialData, m_initialSize); - } else { - spPending->SetMethod(wxZIP_METHOD_STORE); - } - - spPending->SetSize(m_entrySize); - spPending->SetCrc(m_crcAccumulator); - spPending->SetCompressedSize(m_initialSize); - } - - spPending->m_Flags &= ~wxZIP_SUMS_FOLLOW; - m_headerSize = spPending->WriteLocal(*m_parent_o_stream, GetConv()); - - if (m_parent_o_stream->IsOk()) { - m_entries.push_back(spPending.release()); - m_comp = m_store; - m_store->Write(m_initialData, m_initialSize); - } - - m_initialSize = 0; - m_lasterror = m_parent_o_stream->GetLastError(); -} - -// Write the 'central directory' and the 'end-central-directory' records. -// -bool wxZipOutputStream::Close() -{ - CloseEntry(); - - if (m_lasterror == wxSTREAM_WRITE_ERROR || m_entries.size() == 0) { - wxFilterOutputStream::Close(); - return false; - } - - wxZipEndRec endrec; - - endrec.SetEntriesHere(m_entries.size()); - endrec.SetTotalEntries(m_entries.size()); - endrec.SetOffset(m_headerOffset); - endrec.SetComment(m_Comment); - - wxZipEntryList_::iterator it; - wxFileOffset size = 0; - - for (it = m_entries.begin(); it != m_entries.end(); ++it) { - size += (*it)->WriteCentral(*m_parent_o_stream, GetConv()); - delete *it; - } - m_entries.clear(); - - endrec.SetSize(size); - endrec.Write(*m_parent_o_stream, GetConv()); - - m_lasterror = m_parent_o_stream->GetLastError(); - - if (!wxFilterOutputStream::Close() || !IsOk()) - return false; - m_lasterror = wxSTREAM_EOF; - return true; -} - -// Finish writing the current entry -// -bool wxZipOutputStream::CloseEntry() -{ - if (IsOk() && m_pending) - CreatePendingEntry(); - if (!IsOk()) - return false; - if (!m_comp) - return true; - - CloseCompressor(m_comp); - m_comp = NULL; - - wxFileOffset compressedSize = m_store->TellO(); - - wxZipEntry& entry = *m_entries.back(); - - // When writing raw the crc and size can't be checked - if (m_raw) { - m_crcAccumulator = entry.GetCrc(); - m_entrySize = entry.GetSize(); - } - - // Write the sums in the trailing 'data descriptor' if necessary - if (entry.m_Flags & wxZIP_SUMS_FOLLOW) { - wxASSERT(!IsParentSeekable()); - m_headerOffset += - entry.WriteDescriptor(*m_parent_o_stream, m_crcAccumulator, - compressedSize, m_entrySize); - m_lasterror = m_parent_o_stream->GetLastError(); - } - - // If the local header didn't have the correct crc and size written to - // it then seek back and fix it - else if (m_crcAccumulator != entry.GetCrc() - || m_entrySize != entry.GetSize() - || compressedSize != entry.GetCompressedSize()) - { - if (IsParentSeekable()) { - wxFileOffset here = m_parent_o_stream->TellO(); - wxFileOffset headerOffset = m_headerOffset + m_offsetAdjustment; - m_parent_o_stream->SeekO(headerOffset + SUMS_OFFSET); - entry.WriteDescriptor(*m_parent_o_stream, m_crcAccumulator, - compressedSize, m_entrySize); - m_parent_o_stream->SeekO(here); - m_lasterror = m_parent_o_stream->GetLastError(); - } else { - m_lasterror = wxSTREAM_WRITE_ERROR; - } - } - - m_headerOffset += m_headerSize + compressedSize; - m_headerSize = 0; - m_entrySize = 0; - m_store->Close(); - m_raw = false; - - if (IsOk()) - m_lasterror = m_parent_o_stream->GetLastError(); - else - wxLogError(_("error writing zip entry '%s': bad crc or length"), - entry.GetName().c_str()); - return IsOk(); -} - -void wxZipOutputStream::Sync() -{ - if (IsOk() && m_pending) - CreatePendingEntry(NULL, 0); - if (!m_comp) - m_lasterror = wxSTREAM_WRITE_ERROR; - if (IsOk()) { - m_comp->Sync(); - m_lasterror = m_comp->GetLastError(); - } -} - -size_t wxZipOutputStream::OnSysWrite(const void *buffer, size_t size) -{ - if (IsOk() && m_pending) { - if (m_initialSize + size < OUTPUT_LATENCY) { - memcpy(m_initialData + m_initialSize, buffer, size); - m_initialSize += size; - return size; - } else { - CreatePendingEntry(buffer, size); - } - } - - if (!m_comp) - m_lasterror = wxSTREAM_WRITE_ERROR; - if (!IsOk() || !size) - return 0; - - if (m_comp->Write(buffer, size).LastWrite() != size) - m_lasterror = wxSTREAM_WRITE_ERROR; - m_crcAccumulator = crc32(m_crcAccumulator, (Byte*)buffer, size); - m_entrySize += m_comp->LastWrite(); - - return m_comp->LastWrite(); -} - -#endif // wxUSE_ZIPSTREAM +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/zipstrm.cpp +// Purpose: Streams for Zip files +// Author: Mike Wetherell +// RCS-ID: $Id: zipstrm.cpp 51009 2008-01-03 17:11:45Z MW $ +// Copyright: (c) Mike Wetherell +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_ZIPSTREAM + +#include "wx/zipstrm.h" + +#ifndef WX_PRECOMP + #include "wx/hashmap.h" + #include "wx/intl.h" + #include "wx/log.h" + #include "wx/utils.h" +#endif + +#include "wx/datstrm.h" +#include "wx/zstream.h" +#include "wx/mstream.h" +#include "wx/ptr_scpd.h" +#include "wx/wfstream.h" +#include "zlib.h" + +// value for the 'version needed to extract' field (20 means 2.0) +enum { + VERSION_NEEDED_TO_EXTRACT = 20 +}; + +// signatures for the various records (PKxx) +enum { + CENTRAL_MAGIC = 0x02014b50, // central directory record + LOCAL_MAGIC = 0x04034b50, // local header + END_MAGIC = 0x06054b50, // end of central directory record + SUMS_MAGIC = 0x08074b50 // data descriptor (info-zip) +}; + +// unix file attributes. zip stores them in the high 16 bits of the +// 'external attributes' field, hence the extra zeros. +enum { + wxZIP_S_IFMT = 0xF0000000, + wxZIP_S_IFDIR = 0x40000000, + wxZIP_S_IFREG = 0x80000000 +}; + +// minimum sizes for the various records +enum { + CENTRAL_SIZE = 46, + LOCAL_SIZE = 30, + END_SIZE = 22, + SUMS_SIZE = 12 +}; + +// The number of bytes that must be written to an wxZipOutputStream before +// a zip entry is created. The purpose of this latency is so that +// OpenCompressor() can see a little data before deciding which compressor +// it should use. +enum { + OUTPUT_LATENCY = 4096 +}; + +// Some offsets into the local header +enum { + SUMS_OFFSET = 14 +}; + +IMPLEMENT_DYNAMIC_CLASS(wxZipEntry, wxArchiveEntry) +IMPLEMENT_DYNAMIC_CLASS(wxZipClassFactory, wxArchiveClassFactory) + + +///////////////////////////////////////////////////////////////////////////// +// Helpers + +// read a string of a given length +// +static wxString ReadString(wxInputStream& stream, wxUint16 len, wxMBConv& conv) +{ + if (len == 0) + return wxEmptyString; + +#if wxUSE_UNICODE + wxCharBuffer buf(len); + stream.Read(buf.data(), len); + wxString str(buf, conv); +#else + wxString str; + (void)conv; + { + wxStringBuffer buf(str, len); + stream.Read(buf, len); + } +#endif + + return str; +} + +// Decode a little endian wxUint32 number from a character array +// +static inline wxUint32 CrackUint32(const char *m) +{ + const unsigned char *n = (const unsigned char*)m; + return (n[3] << 24) | (n[2] << 16) | (n[1] << 8) | n[0]; +} + +// Decode a little endian wxUint16 number from a character array +// +static inline wxUint16 CrackUint16(const char *m) +{ + const unsigned char *n = (const unsigned char*)m; + return (n[1] << 8) | n[0]; +} + +// Temporarily lower the logging level in debug mode to avoid a warning +// from SeekI about seeking on a stream with data written back to it. +// +static wxFileOffset QuietSeek(wxInputStream& stream, wxFileOffset pos) +{ +#if defined(__WXDEBUG__) && wxUSE_LOG + wxLogLevel level = wxLog::GetLogLevel(); + wxLog::SetLogLevel(wxLOG_Debug - 1); + wxFileOffset result = stream.SeekI(pos); + wxLog::SetLogLevel(level); + return result; +#else + return stream.SeekI(pos); +#endif +} + + +///////////////////////////////////////////////////////////////////////////// +// Class factory + +wxZipClassFactory g_wxZipClassFactory; + +wxZipClassFactory::wxZipClassFactory() +{ + if (this == &g_wxZipClassFactory) + PushFront(); +} + +const wxChar * const * +wxZipClassFactory::GetProtocols(wxStreamProtocolType type) const +{ + static const wxChar *protocols[] = { _T("zip"), NULL }; + static const wxChar *mimetypes[] = { _T("application/zip"), NULL }; + static const wxChar *fileexts[] = { _T(".zip"), _T(".htb"), NULL }; + static const wxChar *empty[] = { NULL }; + + switch (type) { + case wxSTREAM_PROTOCOL: return protocols; + case wxSTREAM_MIMETYPE: return mimetypes; + case wxSTREAM_FILEEXT: return fileexts; + default: return empty; + } +} + + +///////////////////////////////////////////////////////////////////////////// +// Read a zip header + +class wxZipHeader +{ +public: + wxZipHeader(wxInputStream& stream, size_t size); + + inline wxUint8 Read8(); + inline wxUint16 Read16(); + inline wxUint32 Read32(); + + const char *GetData() const { return m_data; } + size_t GetSize() const { return m_size; } + operator bool() const { return m_ok; } + + size_t Seek(size_t pos) { m_pos = pos; return m_pos; } + size_t Skip(size_t size) { m_pos += size; return m_pos; } + + wxZipHeader& operator>>(wxUint8& n) { n = Read8(); return *this; } + wxZipHeader& operator>>(wxUint16& n) { n = Read16(); return *this; } + wxZipHeader& operator>>(wxUint32& n) { n = Read32(); return *this; } + +private: + char m_data[64]; + size_t m_size; + size_t m_pos; + bool m_ok; +}; + +wxZipHeader::wxZipHeader(wxInputStream& stream, size_t size) + : m_size(0), + m_pos(0), + m_ok(false) +{ + wxCHECK_RET(size <= sizeof(m_data), _T("buffer too small")); + m_size = stream.Read(m_data, size).LastRead(); + m_ok = m_size == size; +} + +inline wxUint8 wxZipHeader::Read8() +{ + wxASSERT(m_pos < m_size); + return m_data[m_pos++]; +} + +inline wxUint16 wxZipHeader::Read16() +{ + wxASSERT(m_pos + 2 <= m_size); + wxUint16 n = CrackUint16(m_data + m_pos); + m_pos += 2; + return n; +} + +inline wxUint32 wxZipHeader::Read32() +{ + wxASSERT(m_pos + 4 <= m_size); + wxUint32 n = CrackUint32(m_data + m_pos); + m_pos += 4; + return n; +} + + +///////////////////////////////////////////////////////////////////////////// +// Stored input stream +// Trival decompressor for files which are 'stored' in the zip file. + +class wxStoredInputStream : public wxFilterInputStream +{ +public: + wxStoredInputStream(wxInputStream& stream); + + void Open(wxFileOffset len) { Close(); m_len = len; } + void Close() { m_pos = 0; m_lasterror = wxSTREAM_NO_ERROR; } + + virtual char Peek() { return wxInputStream::Peek(); } + virtual wxFileOffset GetLength() const { return m_len; } + +protected: + virtual size_t OnSysRead(void *buffer, size_t size); + virtual wxFileOffset OnSysTell() const { return m_pos; } + +private: + wxFileOffset m_pos; + wxFileOffset m_len; + + DECLARE_NO_COPY_CLASS(wxStoredInputStream) +}; + +wxStoredInputStream::wxStoredInputStream(wxInputStream& stream) + : wxFilterInputStream(stream), + m_pos(0), + m_len(0) +{ +} + +size_t wxStoredInputStream::OnSysRead(void *buffer, size_t size) +{ + size_t count = wx_truncate_cast(size_t, + wxMin(size + wxFileOffset(0), m_len - m_pos + size_t(0))); + count = m_parent_i_stream->Read(buffer, count).LastRead(); + m_pos += count; + + if (count < size) + m_lasterror = m_pos == m_len ? wxSTREAM_EOF : wxSTREAM_READ_ERROR; + + return count; +} + + +///////////////////////////////////////////////////////////////////////////// +// Stored output stream +// Trival compressor for files which are 'stored' in the zip file. + +class wxStoredOutputStream : public wxFilterOutputStream +{ +public: + wxStoredOutputStream(wxOutputStream& stream) : + wxFilterOutputStream(stream), m_pos(0) { } + + bool Close() { + m_pos = 0; + m_lasterror = wxSTREAM_NO_ERROR; + return true; + } + +protected: + virtual size_t OnSysWrite(const void *buffer, size_t size); + virtual wxFileOffset OnSysTell() const { return m_pos; } + +private: + wxFileOffset m_pos; + DECLARE_NO_COPY_CLASS(wxStoredOutputStream) +}; + +size_t wxStoredOutputStream::OnSysWrite(const void *buffer, size_t size) +{ + if (!IsOk() || !size) + return 0; + size_t count = m_parent_o_stream->Write(buffer, size).LastWrite(); + if (count != size) + m_lasterror = wxSTREAM_WRITE_ERROR; + m_pos += count; + return count; +} + + +///////////////////////////////////////////////////////////////////////////// +// wxRawInputStream +// +// Used to handle the unusal case of raw copying an entry of unknown +// length. This can only happen when the zip being copied from is being +// read from a non-seekable stream, and also was original written to a +// non-seekable stream. +// +// In this case there's no option but to decompress the stream to find +// it's length, but we can still write the raw compressed data to avoid the +// compression overhead (which is the greater one). +// +// Usage is like this: +// m_rawin = new wxRawInputStream(*m_parent_i_stream); +// m_decomp = m_rawin->Open(OpenDecompressor(m_rawin->GetTee())); +// +// The wxRawInputStream owns a wxTeeInputStream object, the role of which +// is something like the unix 'tee' command; it is a transparent filter, but +// allows the data read to be read a second time via an extra method 'GetData'. +// +// The wxRawInputStream then draws data through the tee using a decompressor +// then instead of returning the decompressed data, retuns the raw data +// from wxTeeInputStream::GetData(). + +class wxTeeInputStream : public wxFilterInputStream +{ +public: + wxTeeInputStream(wxInputStream& stream); + + size_t GetCount() const { return m_end - m_start; } + size_t GetData(char *buffer, size_t size); + + void Open(); + bool Final(); + + wxInputStream& Read(void *buffer, size_t size); + +protected: + virtual size_t OnSysRead(void *buffer, size_t size); + virtual wxFileOffset OnSysTell() const { return m_pos; } + +private: + wxFileOffset m_pos; + wxMemoryBuffer m_buf; + size_t m_start; + size_t m_end; + + DECLARE_NO_COPY_CLASS(wxTeeInputStream) +}; + +wxTeeInputStream::wxTeeInputStream(wxInputStream& stream) + : wxFilterInputStream(stream), + m_pos(0), m_buf(8192), m_start(0), m_end(0) +{ +} + +void wxTeeInputStream::Open() +{ + m_pos = m_start = m_end = 0; + m_lasterror = wxSTREAM_NO_ERROR; +} + +bool wxTeeInputStream::Final() +{ + bool final = m_end == m_buf.GetDataLen(); + m_end = m_buf.GetDataLen(); + return final; +} + +wxInputStream& wxTeeInputStream::Read(void *buffer, size_t size) +{ + size_t count = wxInputStream::Read(buffer, size).LastRead(); + m_end = m_buf.GetDataLen(); + m_buf.AppendData(buffer, count); + return *this; +} + +size_t wxTeeInputStream::OnSysRead(void *buffer, size_t size) +{ + size_t count = m_parent_i_stream->Read(buffer, size).LastRead(); + if (count < size) + m_lasterror = m_parent_i_stream->GetLastError(); + return count; +} + +size_t wxTeeInputStream::GetData(char *buffer, size_t size) +{ + if (m_wbacksize) { + size_t len = m_buf.GetDataLen(); + len = len > m_wbacksize ? len - m_wbacksize : 0; + m_buf.SetDataLen(len); + if (m_end > len) { + wxFAIL; // we've already returned data that's now being ungot + m_end = len; + } + m_parent_i_stream->Reset(); + m_parent_i_stream->Ungetch(m_wback, m_wbacksize); + free(m_wback); + m_wback = NULL; + m_wbacksize = 0; + m_wbackcur = 0; + } + + if (size > GetCount()) + size = GetCount(); + if (size) { + memcpy(buffer, m_buf + m_start, size); + m_start += size; + wxASSERT(m_start <= m_end); + } + + if (m_start == m_end && m_start > 0 && m_buf.GetDataLen() > 0) { + size_t len = m_buf.GetDataLen(); + char *buf = (char*)m_buf.GetWriteBuf(len); + len -= m_end; + memmove(buf, buf + m_end, len); + m_buf.UngetWriteBuf(len); + m_start = m_end = 0; + } + + return size; +} + +class wxRawInputStream : public wxFilterInputStream +{ +public: + wxRawInputStream(wxInputStream& stream); + virtual ~wxRawInputStream() { delete m_tee; } + + wxInputStream* Open(wxInputStream *decomp); + wxInputStream& GetTee() const { return *m_tee; } + +protected: + virtual size_t OnSysRead(void *buffer, size_t size); + virtual wxFileOffset OnSysTell() const { return m_pos; } + +private: + wxFileOffset m_pos; + wxTeeInputStream *m_tee; + + enum { BUFSIZE = 8192 }; + wxCharBuffer m_dummy; + + DECLARE_NO_COPY_CLASS(wxRawInputStream) +}; + +wxRawInputStream::wxRawInputStream(wxInputStream& stream) + : wxFilterInputStream(stream), + m_pos(0), + m_tee(new wxTeeInputStream(stream)), + m_dummy(BUFSIZE) +{ +} + +wxInputStream *wxRawInputStream::Open(wxInputStream *decomp) +{ + if (decomp) { + m_parent_i_stream = decomp; + m_pos = 0; + m_lasterror = wxSTREAM_NO_ERROR; + m_tee->Open(); + return this; + } else { + return NULL; + } +} + +size_t wxRawInputStream::OnSysRead(void *buffer, size_t size) +{ + char *buf = (char*)buffer; + size_t count = 0; + + while (count < size && IsOk()) + { + while (m_parent_i_stream->IsOk() && m_tee->GetCount() == 0) + m_parent_i_stream->Read(m_dummy.data(), BUFSIZE); + + size_t n = m_tee->GetData(buf + count, size - count); + count += n; + + if (n == 0 && m_tee->Final()) + m_lasterror = m_parent_i_stream->GetLastError(); + } + + m_pos += count; + return count; +} + + +///////////////////////////////////////////////////////////////////////////// +// Zlib streams than can be reused without recreating. + +class wxZlibOutputStream2 : public wxZlibOutputStream +{ +public: + wxZlibOutputStream2(wxOutputStream& stream, int level) : + wxZlibOutputStream(stream, level, wxZLIB_NO_HEADER) { } + + bool Open(wxOutputStream& stream); + bool Close() { DoFlush(true); m_pos = wxInvalidOffset; return IsOk(); } +}; + +bool wxZlibOutputStream2::Open(wxOutputStream& stream) +{ + wxCHECK(m_pos == wxInvalidOffset, false); + + m_deflate->next_out = m_z_buffer; + m_deflate->avail_out = m_z_size; + m_pos = 0; + m_lasterror = wxSTREAM_NO_ERROR; + m_parent_o_stream = &stream; + + if (deflateReset(m_deflate) != Z_OK) { + wxLogError(_("can't re-initialize zlib deflate stream")); + m_lasterror = wxSTREAM_WRITE_ERROR; + return false; + } + + return true; +} + +class wxZlibInputStream2 : public wxZlibInputStream +{ +public: + wxZlibInputStream2(wxInputStream& stream) : + wxZlibInputStream(stream, wxZLIB_NO_HEADER) { } + + bool Open(wxInputStream& stream); +}; + +bool wxZlibInputStream2::Open(wxInputStream& stream) +{ + m_inflate->avail_in = 0; + m_pos = 0; + m_lasterror = wxSTREAM_NO_ERROR; + m_parent_i_stream = &stream; + + if (inflateReset(m_inflate) != Z_OK) { + wxLogError(_("can't re-initialize zlib inflate stream")); + m_lasterror = wxSTREAM_READ_ERROR; + return false; + } + + return true; +} + + +///////////////////////////////////////////////////////////////////////////// +// Class to hold wxZipEntry's Extra and LocalExtra fields + +class wxZipMemory +{ +public: + wxZipMemory() : m_data(NULL), m_size(0), m_capacity(0), m_ref(1) { } + + wxZipMemory *AddRef() { m_ref++; return this; } + void Release() { if (--m_ref == 0) delete this; } + + char *GetData() const { return m_data; } + size_t GetSize() const { return m_size; } + size_t GetCapacity() const { return m_capacity; } + + wxZipMemory *Unique(size_t size); + +private: + ~wxZipMemory() { delete [] m_data; } + + char *m_data; + size_t m_size; + size_t m_capacity; + int m_ref; + + wxSUPPRESS_GCC_PRIVATE_DTOR_WARNING(wxZipMemory) +}; + +wxZipMemory *wxZipMemory::Unique(size_t size) +{ + wxZipMemory *zm; + + if (m_ref > 1) { + --m_ref; + zm = new wxZipMemory; + } else { + zm = this; + } + + if (zm->m_capacity < size) { + delete [] zm->m_data; + zm->m_data = new char[size]; + zm->m_capacity = size; + } + + zm->m_size = size; + return zm; +} + +static inline wxZipMemory *AddRef(wxZipMemory *zm) +{ + if (zm) + zm->AddRef(); + return zm; +} + +static inline void Release(wxZipMemory *zm) +{ + if (zm) + zm->Release(); +} + +static void Copy(wxZipMemory*& dest, wxZipMemory *src) +{ + Release(dest); + dest = AddRef(src); +} + +static void Unique(wxZipMemory*& zm, size_t size) +{ + if (!zm && size) + zm = new wxZipMemory; + if (zm) + zm = zm->Unique(size); +} + + +///////////////////////////////////////////////////////////////////////////// +// Collection of weak references to entries + +WX_DECLARE_HASH_MAP(long, wxZipEntry*, wxIntegerHash, + wxIntegerEqual, wxOffsetZipEntryMap_); + +class wxZipWeakLinks +{ +public: + wxZipWeakLinks() : m_ref(1) { } + + void Release(const wxZipInputStream* WXUNUSED(x)) + { if (--m_ref == 0) delete this; } + void Release(wxFileOffset key) + { RemoveEntry(key); if (--m_ref == 0) delete this; } + + wxZipWeakLinks *AddEntry(wxZipEntry *entry, wxFileOffset key); + void RemoveEntry(wxFileOffset key) + { m_entries.erase(wx_truncate_cast(key_type, key)); } + wxZipEntry *GetEntry(wxFileOffset key) const; + bool IsEmpty() const { return m_entries.empty(); } + +private: + ~wxZipWeakLinks() { wxASSERT(IsEmpty()); } + + typedef wxOffsetZipEntryMap_::key_type key_type; + + int m_ref; + wxOffsetZipEntryMap_ m_entries; + + wxSUPPRESS_GCC_PRIVATE_DTOR_WARNING(wxZipWeakLinks) +}; + +wxZipWeakLinks *wxZipWeakLinks::AddEntry(wxZipEntry *entry, wxFileOffset key) +{ + m_entries[wx_truncate_cast(key_type, key)] = entry; + m_ref++; + return this; +} + +wxZipEntry *wxZipWeakLinks::GetEntry(wxFileOffset key) const +{ + wxOffsetZipEntryMap_::const_iterator it = + m_entries.find(wx_truncate_cast(key_type, key)); + return it != m_entries.end() ? it->second : NULL; +} + + +///////////////////////////////////////////////////////////////////////////// +// ZipEntry + +wxZipEntry::wxZipEntry( + const wxString& name /*=wxEmptyString*/, + const wxDateTime& dt /*=wxDateTime::Now()*/, + wxFileOffset size /*=wxInvalidOffset*/) + : + m_SystemMadeBy(wxZIP_SYSTEM_MSDOS), + m_VersionMadeBy(wxMAJOR_VERSION * 10 + wxMINOR_VERSION), + m_VersionNeeded(VERSION_NEEDED_TO_EXTRACT), + m_Flags(0), + m_Method(wxZIP_METHOD_DEFAULT), + m_DateTime(dt), + m_Crc(0), + m_CompressedSize(wxInvalidOffset), + m_Size(size), + m_Key(wxInvalidOffset), + m_Offset(wxInvalidOffset), + m_DiskStart(0), + m_InternalAttributes(0), + m_ExternalAttributes(0), + m_Extra(NULL), + m_LocalExtra(NULL), + m_zipnotifier(NULL), + m_backlink(NULL) +{ + if (!name.empty()) + SetName(name); +} + +wxZipEntry::~wxZipEntry() +{ + if (m_backlink) + m_backlink->Release(m_Key); + Release(m_Extra); + Release(m_LocalExtra); +} + +wxZipEntry::wxZipEntry(const wxZipEntry& e) + : wxArchiveEntry(e), + m_SystemMadeBy(e.m_SystemMadeBy), + m_VersionMadeBy(e.m_VersionMadeBy), + m_VersionNeeded(e.m_VersionNeeded), + m_Flags(e.m_Flags), + m_Method(e.m_Method), + m_DateTime(e.m_DateTime), + m_Crc(e.m_Crc), + m_CompressedSize(e.m_CompressedSize), + m_Size(e.m_Size), + m_Name(e.m_Name), + m_Key(e.m_Key), + m_Offset(e.m_Offset), + m_Comment(e.m_Comment), + m_DiskStart(e.m_DiskStart), + m_InternalAttributes(e.m_InternalAttributes), + m_ExternalAttributes(e.m_ExternalAttributes), + m_Extra(AddRef(e.m_Extra)), + m_LocalExtra(AddRef(e.m_LocalExtra)), + m_zipnotifier(NULL), + m_backlink(NULL) +{ +} + +wxZipEntry& wxZipEntry::operator=(const wxZipEntry& e) +{ + if (&e != this) { + m_SystemMadeBy = e.m_SystemMadeBy; + m_VersionMadeBy = e.m_VersionMadeBy; + m_VersionNeeded = e.m_VersionNeeded; + m_Flags = e.m_Flags; + m_Method = e.m_Method; + m_DateTime = e.m_DateTime; + m_Crc = e.m_Crc; + m_CompressedSize = e.m_CompressedSize; + m_Size = e.m_Size; + m_Name = e.m_Name; + m_Key = e.m_Key; + m_Offset = e.m_Offset; + m_Comment = e.m_Comment; + m_DiskStart = e.m_DiskStart; + m_InternalAttributes = e.m_InternalAttributes; + m_ExternalAttributes = e.m_ExternalAttributes; + Copy(m_Extra, e.m_Extra); + Copy(m_LocalExtra, e.m_LocalExtra); + m_zipnotifier = NULL; + if (m_backlink) { + m_backlink->Release(m_Key); + m_backlink = NULL; + } + } + return *this; +} + +wxString wxZipEntry::GetName(wxPathFormat format /*=wxPATH_NATIVE*/) const +{ + bool isDir = IsDir() && !m_Name.empty(); + + // optimisations for common (and easy) cases + switch (wxFileName::GetFormat(format)) { + case wxPATH_DOS: + { + wxString name(isDir ? m_Name + _T("\\") : m_Name); + for (size_t i = 0; i < name.length(); i++) + if (name[i] == _T('/')) + name[i] = _T('\\'); + return name; + } + + case wxPATH_UNIX: + return isDir ? m_Name + _T("/") : m_Name; + + default: + ; + } + + wxFileName fn; + + if (isDir) + fn.AssignDir(m_Name, wxPATH_UNIX); + else + fn.Assign(m_Name, wxPATH_UNIX); + + return fn.GetFullPath(format); +} + +// Static - Internally tars and zips use forward slashes for the path +// separator, absolute paths aren't allowed, and directory names have a +// trailing slash. This function converts a path into this internal format, +// but without a trailing slash for a directory. +// +wxString wxZipEntry::GetInternalName(const wxString& name, + wxPathFormat format /*=wxPATH_NATIVE*/, + bool *pIsDir /*=NULL*/) +{ + wxString internal; + + if (wxFileName::GetFormat(format) != wxPATH_UNIX) + internal = wxFileName(name, format).GetFullPath(wxPATH_UNIX); + else + internal = name; + + bool isDir = !internal.empty() && internal.Last() == '/'; + if (pIsDir) + *pIsDir = isDir; + if (isDir) + internal.erase(internal.length() - 1); + + while (!internal.empty() && *internal.begin() == '/') + internal.erase(0, 1); + while (!internal.empty() && internal.compare(0, 2, _T("./")) == 0) + internal.erase(0, 2); + if (internal == _T(".") || internal == _T("..")) + internal = wxEmptyString; + + return internal; +} + +void wxZipEntry::SetSystemMadeBy(int system) +{ + int mode = GetMode(); + bool wasUnix = IsMadeByUnix(); + + m_SystemMadeBy = (wxUint8)system; + + if (!wasUnix && IsMadeByUnix()) { + SetIsDir(IsDir()); + SetMode(mode); + } else if (wasUnix && !IsMadeByUnix()) { + m_ExternalAttributes &= 0xffff; + } +} + +void wxZipEntry::SetIsDir(bool isDir /*=true*/) +{ + if (isDir) + m_ExternalAttributes |= wxZIP_A_SUBDIR; + else + m_ExternalAttributes &= ~wxZIP_A_SUBDIR; + + if (IsMadeByUnix()) { + m_ExternalAttributes &= ~wxZIP_S_IFMT; + if (isDir) + m_ExternalAttributes |= wxZIP_S_IFDIR; + else + m_ExternalAttributes |= wxZIP_S_IFREG; + } +} + +// Return unix style permission bits +// +int wxZipEntry::GetMode() const +{ + // return unix permissions if present + if (IsMadeByUnix()) + return (m_ExternalAttributes >> 16) & 0777; + + // otherwise synthesize from the dos attribs + int mode = 0644; + if (m_ExternalAttributes & wxZIP_A_RDONLY) + mode &= ~0200; + if (m_ExternalAttributes & wxZIP_A_SUBDIR) + mode |= 0111; + + return mode; +} + +// Set unix permissions +// +void wxZipEntry::SetMode(int mode) +{ + // Set dos attrib bits to be compatible + if (mode & 0222) + m_ExternalAttributes &= ~wxZIP_A_RDONLY; + else + m_ExternalAttributes |= wxZIP_A_RDONLY; + + // set the actual unix permission bits if the system type allows + if (IsMadeByUnix()) { + m_ExternalAttributes &= ~(0777L << 16); + m_ExternalAttributes |= (mode & 0777L) << 16; + } +} + +const char *wxZipEntry::GetExtra() const +{ + return m_Extra ? m_Extra->GetData() : NULL; +} + +size_t wxZipEntry::GetExtraLen() const +{ + return m_Extra ? m_Extra->GetSize() : 0; +} + +void wxZipEntry::SetExtra(const char *extra, size_t len) +{ + Unique(m_Extra, len); + if (len) + memcpy(m_Extra->GetData(), extra, len); +} + +const char *wxZipEntry::GetLocalExtra() const +{ + return m_LocalExtra ? m_LocalExtra->GetData() : NULL; +} + +size_t wxZipEntry::GetLocalExtraLen() const +{ + return m_LocalExtra ? m_LocalExtra->GetSize() : 0; +} + +void wxZipEntry::SetLocalExtra(const char *extra, size_t len) +{ + Unique(m_LocalExtra, len); + if (len) + memcpy(m_LocalExtra->GetData(), extra, len); +} + +void wxZipEntry::SetNotifier(wxZipNotifier& notifier) +{ + wxArchiveEntry::UnsetNotifier(); + m_zipnotifier = ¬ifier; + m_zipnotifier->OnEntryUpdated(*this); +} + +void wxZipEntry::Notify() +{ + if (m_zipnotifier) + m_zipnotifier->OnEntryUpdated(*this); + else if (GetNotifier()) + GetNotifier()->OnEntryUpdated(*this); +} + +void wxZipEntry::UnsetNotifier() +{ + wxArchiveEntry::UnsetNotifier(); + m_zipnotifier = NULL; +} + +size_t wxZipEntry::ReadLocal(wxInputStream& stream, wxMBConv& conv) +{ + wxUint16 nameLen, extraLen; + wxUint32 compressedSize, size, crc; + + wxZipHeader ds(stream, LOCAL_SIZE - 4); + if (!ds) + return 0; + + ds >> m_VersionNeeded >> m_Flags >> m_Method; + SetDateTime(wxDateTime().SetFromDOS(ds.Read32())); + ds >> crc >> compressedSize >> size >> nameLen >> extraLen; + + bool sumsValid = (m_Flags & wxZIP_SUMS_FOLLOW) == 0; + + if (sumsValid || crc) + m_Crc = crc; + if ((sumsValid || compressedSize) || m_Method == wxZIP_METHOD_STORE) + m_CompressedSize = compressedSize; + if ((sumsValid || size) || m_Method == wxZIP_METHOD_STORE) + m_Size = size; + + SetName(ReadString(stream, nameLen, conv), wxPATH_UNIX); + if (stream.LastRead() != nameLen + 0u) + return 0; + + if (extraLen || GetLocalExtraLen()) { + Unique(m_LocalExtra, extraLen); + if (extraLen) { + stream.Read(m_LocalExtra->GetData(), extraLen); + if (stream.LastRead() != extraLen + 0u) + return 0; + } + } + + return LOCAL_SIZE + nameLen + extraLen; +} + +size_t wxZipEntry::WriteLocal(wxOutputStream& stream, wxMBConv& conv) const +{ + wxString unixName = GetName(wxPATH_UNIX); + const wxWX2MBbuf name_buf = conv.cWX2MB(unixName); + const char *name = name_buf; + if (!name) name = ""; + wxUint16 nameLen = wx_truncate_cast(wxUint16, strlen(name)); + + wxDataOutputStream ds(stream); + + ds << m_VersionNeeded << m_Flags << m_Method; + ds.Write32(GetDateTime().GetAsDOS()); + + ds.Write32(m_Crc); + ds.Write32(m_CompressedSize != wxInvalidOffset ? + wx_truncate_cast(wxUint32, m_CompressedSize) : 0); + ds.Write32(m_Size != wxInvalidOffset ? + wx_truncate_cast(wxUint32, m_Size) : 0); + + ds << nameLen; + wxUint16 extraLen = wx_truncate_cast(wxUint16, GetLocalExtraLen()); + ds.Write16(extraLen); + + stream.Write(name, nameLen); + if (extraLen) + stream.Write(m_LocalExtra->GetData(), extraLen); + + return LOCAL_SIZE + nameLen + extraLen; +} + +size_t wxZipEntry::ReadCentral(wxInputStream& stream, wxMBConv& conv) +{ + wxUint16 nameLen, extraLen, commentLen; + + wxZipHeader ds(stream, CENTRAL_SIZE - 4); + if (!ds) + return 0; + + ds >> m_VersionMadeBy >> m_SystemMadeBy; + + SetVersionNeeded(ds.Read16()); + SetFlags(ds.Read16()); + SetMethod(ds.Read16()); + SetDateTime(wxDateTime().SetFromDOS(ds.Read32())); + SetCrc(ds.Read32()); + SetCompressedSize(ds.Read32()); + SetSize(ds.Read32()); + + ds >> nameLen >> extraLen >> commentLen + >> m_DiskStart >> m_InternalAttributes >> m_ExternalAttributes; + SetOffset(ds.Read32()); + + SetName(ReadString(stream, nameLen, conv), wxPATH_UNIX); + if (stream.LastRead() != nameLen + 0u) + return 0; + + if (extraLen || GetExtraLen()) { + Unique(m_Extra, extraLen); + if (extraLen) { + stream.Read(m_Extra->GetData(), extraLen); + if (stream.LastRead() != extraLen + 0u) + return 0; + } + } + + if (commentLen) { + m_Comment = ReadString(stream, commentLen, conv); + if (stream.LastRead() != commentLen + 0u) + return 0; + } else { + m_Comment.clear(); + } + + return CENTRAL_SIZE + nameLen + extraLen + commentLen; +} + +size_t wxZipEntry::WriteCentral(wxOutputStream& stream, wxMBConv& conv) const +{ + wxString unixName = GetName(wxPATH_UNIX); + const wxWX2MBbuf name_buf = conv.cWX2MB(unixName); + const char *name = name_buf; + if (!name) name = ""; + wxUint16 nameLen = wx_truncate_cast(wxUint16, strlen(name)); + + const wxWX2MBbuf comment_buf = conv.cWX2MB(m_Comment); + const char *comment = comment_buf; + if (!comment) comment = ""; + wxUint16 commentLen = wx_truncate_cast(wxUint16, strlen(comment)); + + wxUint16 extraLen = wx_truncate_cast(wxUint16, GetExtraLen()); + + wxDataOutputStream ds(stream); + + ds << CENTRAL_MAGIC << m_VersionMadeBy << m_SystemMadeBy; + + ds.Write16(wx_truncate_cast(wxUint16, GetVersionNeeded())); + ds.Write16(wx_truncate_cast(wxUint16, GetFlags())); + ds.Write16(wx_truncate_cast(wxUint16, GetMethod())); + ds.Write32(GetDateTime().GetAsDOS()); + ds.Write32(GetCrc()); + ds.Write32(wx_truncate_cast(wxUint32, GetCompressedSize())); + ds.Write32(wx_truncate_cast(wxUint32, GetSize())); + ds.Write16(nameLen); + ds.Write16(extraLen); + + ds << commentLen << m_DiskStart << m_InternalAttributes + << m_ExternalAttributes << wx_truncate_cast(wxUint32, GetOffset()); + + stream.Write(name, nameLen); + if (extraLen) + stream.Write(GetExtra(), extraLen); + stream.Write(comment, commentLen); + + return CENTRAL_SIZE + nameLen + extraLen + commentLen; +} + +// Info-zip prefixes this record with a signature, but pkzip doesn't. So if +// the 1st value is the signature then it is probably an info-zip record, +// though there is a small chance that it is in fact a pkzip record which +// happens to have the signature as it's CRC. +// +size_t wxZipEntry::ReadDescriptor(wxInputStream& stream) +{ + wxZipHeader ds(stream, SUMS_SIZE); + if (!ds) + return 0; + + m_Crc = ds.Read32(); + m_CompressedSize = ds.Read32(); + m_Size = ds.Read32(); + + // if 1st value is the signature then this is probably an info-zip record + if (m_Crc == SUMS_MAGIC) + { + wxZipHeader buf(stream, 8); + wxUint32 u1 = buf.GetSize() >= 4 ? buf.Read32() : (wxUint32)LOCAL_MAGIC; + wxUint32 u2 = buf.GetSize() == 8 ? buf.Read32() : 0; + + // look for the signature of the following record to decide which + if ((u1 == LOCAL_MAGIC || u1 == CENTRAL_MAGIC) && + (u2 != LOCAL_MAGIC && u2 != CENTRAL_MAGIC)) + { + // it's a pkzip style record after all! + if (buf.GetSize() > 0) + stream.Ungetch(buf.GetData(), buf.GetSize()); + } + else + { + // it's an info-zip record as expected + if (buf.GetSize() > 4) + stream.Ungetch(buf.GetData() + 4, buf.GetSize() - 4); + m_Crc = wx_truncate_cast(wxUint32, m_CompressedSize); + m_CompressedSize = m_Size; + m_Size = u1; + return SUMS_SIZE + 4; + } + } + + return SUMS_SIZE; +} + +size_t wxZipEntry::WriteDescriptor(wxOutputStream& stream, wxUint32 crc, + wxFileOffset compressedSize, wxFileOffset size) +{ + m_Crc = crc; + m_CompressedSize = compressedSize; + m_Size = size; + + wxDataOutputStream ds(stream); + + ds.Write32(crc); + ds.Write32(wx_truncate_cast(wxUint32, compressedSize)); + ds.Write32(wx_truncate_cast(wxUint32, size)); + + return SUMS_SIZE; +} + + +///////////////////////////////////////////////////////////////////////////// +// wxZipEndRec - holds the end of central directory record + +class wxZipEndRec +{ +public: + wxZipEndRec(); + + int GetDiskNumber() const { return m_DiskNumber; } + int GetStartDisk() const { return m_StartDisk; } + int GetEntriesHere() const { return m_EntriesHere; } + int GetTotalEntries() const { return m_TotalEntries; } + wxFileOffset GetSize() const { return m_Size; } + wxFileOffset GetOffset() const { return m_Offset; } + wxString GetComment() const { return m_Comment; } + + void SetDiskNumber(int num) + { m_DiskNumber = wx_truncate_cast(wxUint16, num); } + void SetStartDisk(int num) + { m_StartDisk = wx_truncate_cast(wxUint16, num); } + void SetEntriesHere(int num) + { m_EntriesHere = wx_truncate_cast(wxUint16, num); } + void SetTotalEntries(int num) + { m_TotalEntries = wx_truncate_cast(wxUint16, num); } + void SetSize(wxFileOffset size) + { m_Size = wx_truncate_cast(wxUint32, size); } + void SetOffset(wxFileOffset offset) + { m_Offset = wx_truncate_cast(wxUint32, offset); } + void SetComment(const wxString& comment) + { m_Comment = comment; } + + bool Read(wxInputStream& stream, wxMBConv& conv); + bool Write(wxOutputStream& stream, wxMBConv& conv) const; + +private: + wxUint16 m_DiskNumber; + wxUint16 m_StartDisk; + wxUint16 m_EntriesHere; + wxUint16 m_TotalEntries; + wxUint32 m_Size; + wxUint32 m_Offset; + wxString m_Comment; +}; + +wxZipEndRec::wxZipEndRec() + : m_DiskNumber(0), + m_StartDisk(0), + m_EntriesHere(0), + m_TotalEntries(0), + m_Size(0), + m_Offset(0) +{ +} + +bool wxZipEndRec::Write(wxOutputStream& stream, wxMBConv& conv) const +{ + const wxWX2MBbuf comment_buf = conv.cWX2MB(m_Comment); + const char *comment = comment_buf; + if (!comment) comment = ""; + wxUint16 commentLen = (wxUint16)strlen(comment); + + wxDataOutputStream ds(stream); + + ds << END_MAGIC << m_DiskNumber << m_StartDisk << m_EntriesHere + << m_TotalEntries << m_Size << m_Offset << commentLen; + + stream.Write(comment, commentLen); + + return stream.IsOk(); +} + +bool wxZipEndRec::Read(wxInputStream& stream, wxMBConv& conv) +{ + wxZipHeader ds(stream, END_SIZE - 4); + if (!ds) + return false; + + wxUint16 commentLen; + + ds >> m_DiskNumber >> m_StartDisk >> m_EntriesHere + >> m_TotalEntries >> m_Size >> m_Offset >> commentLen; + + if (commentLen) { + m_Comment = ReadString(stream, commentLen, conv); + if (stream.LastRead() != commentLen + 0u) + return false; + } + + if (m_DiskNumber != 0 || m_StartDisk != 0 || + m_EntriesHere != m_TotalEntries) + wxLogWarning(_("assuming this is a multi-part zip concatenated")); + + return true; +} + + +///////////////////////////////////////////////////////////////////////////// +// A weak link from an input stream to an output stream + +class wxZipStreamLink +{ +public: + wxZipStreamLink(wxZipOutputStream *stream) : m_ref(1), m_stream(stream) { } + + wxZipStreamLink *AddRef() { m_ref++; return this; } + wxZipOutputStream *GetOutputStream() const { return m_stream; } + + void Release(class wxZipInputStream *WXUNUSED(s)) + { if (--m_ref == 0) delete this; } + void Release(class wxZipOutputStream *WXUNUSED(s)) + { m_stream = NULL; if (--m_ref == 0) delete this; } + +private: + ~wxZipStreamLink() { } + + int m_ref; + wxZipOutputStream *m_stream; + + wxSUPPRESS_GCC_PRIVATE_DTOR_WARNING(wxZipStreamLink) +}; + + +///////////////////////////////////////////////////////////////////////////// +// Input stream + +// leave the default wxZipEntryPtr free for users +wxDECLARE_SCOPED_PTR(wxZipEntry, wxZipEntryPtr_) +wxDEFINE_SCOPED_PTR (wxZipEntry, wxZipEntryPtr_) + +// constructor +// +wxZipInputStream::wxZipInputStream(wxInputStream& stream, + wxMBConv& conv /*=wxConvLocal*/) + : wxArchiveInputStream(stream, conv) +{ + Init(); +} + +wxZipInputStream::wxZipInputStream(wxInputStream *stream, + wxMBConv& conv /*=wxConvLocal*/) + : wxArchiveInputStream(stream, conv) +{ + Init(); +} + +#if WXWIN_COMPATIBILITY_2_6 && wxUSE_FFILE + +// Part of the compatibility constructor, which has been made inline to +// avoid a problem with it not being exported by mingw 3.2.3 +// +void wxZipInputStream::Init(const wxString& file) +{ + // no error messages + wxLogNull nolog; + Init(); + m_allowSeeking = true; + wxFFileInputStream *ffile; + ffile = wx_static_cast(wxFFileInputStream*, m_parent_i_stream); + wxZipEntryPtr_ entry; + + if (ffile->Ok()) { + do { + entry.reset(GetNextEntry()); + } + while (entry.get() != NULL && entry->GetInternalName() != file); + } + + if (entry.get() == NULL) + m_lasterror = wxSTREAM_READ_ERROR; +} + +wxInputStream* wxZipInputStream::OpenFile(const wxString& archive) +{ + wxLogNull nolog; + return new wxFFileInputStream(archive); +} + +#endif // WXWIN_COMPATIBILITY_2_6 && wxUSE_FFILE + +void wxZipInputStream::Init() +{ + m_store = new wxStoredInputStream(*m_parent_i_stream); + m_inflate = NULL; + m_rawin = NULL; + m_raw = false; + m_headerSize = 0; + m_decomp = NULL; + m_parentSeekable = false; + m_weaklinks = new wxZipWeakLinks; + m_streamlink = NULL; + m_offsetAdjustment = 0; + m_position = wxInvalidOffset; + m_signature = 0; + m_TotalEntries = 0; + m_lasterror = m_parent_i_stream->GetLastError(); +#if WXWIN_COMPATIBILITY_2_6 + m_allowSeeking = false; +#endif +} + +wxZipInputStream::~wxZipInputStream() +{ + CloseDecompressor(m_decomp); + + delete m_store; + delete m_inflate; + delete m_rawin; + + m_weaklinks->Release(this); + + if (m_streamlink) + m_streamlink->Release(this); +} + +wxString wxZipInputStream::GetComment() +{ + if (m_position == wxInvalidOffset) + if (!LoadEndRecord()) + return wxEmptyString; + + if (!m_parentSeekable && Eof() && m_signature) { + m_lasterror = wxSTREAM_NO_ERROR; + m_lasterror = ReadLocal(true); + } + + return m_Comment; +} + +int wxZipInputStream::GetTotalEntries() +{ + if (m_position == wxInvalidOffset) + LoadEndRecord(); + return m_TotalEntries; +} + +wxZipStreamLink *wxZipInputStream::MakeLink(wxZipOutputStream *out) +{ + wxZipStreamLink *link = NULL; + + if (!m_parentSeekable && (IsOpened() || !Eof())) { + link = new wxZipStreamLink(out); + if (m_streamlink) + m_streamlink->Release(this); + m_streamlink = link->AddRef(); + } + + return link; +} + +bool wxZipInputStream::LoadEndRecord() +{ + wxCHECK(m_position == wxInvalidOffset, false); + if (!IsOk()) + return false; + + m_position = 0; + + // First find the end-of-central-directory record. + if (!FindEndRecord()) { + // failed, so either this is a non-seekable stream (ok), or not a zip + if (m_parentSeekable) { + m_lasterror = wxSTREAM_READ_ERROR; + wxLogError(_("invalid zip file")); + return false; + } + else { + wxLogNull nolog; + wxFileOffset pos = m_parent_i_stream->TellI(); + if (pos != wxInvalidOffset) + m_offsetAdjustment = m_position = pos; + return true; + } + } + + wxZipEndRec endrec; + + // Read in the end record + wxFileOffset endPos = m_parent_i_stream->TellI() - 4; + if (!endrec.Read(*m_parent_i_stream, GetConv())) + return false; + + m_TotalEntries = endrec.GetTotalEntries(); + m_Comment = endrec.GetComment(); + + // Now find the central-directory. we have the file offset of + // the CD, so look there first. + if (m_parent_i_stream->SeekI(endrec.GetOffset()) != wxInvalidOffset && + ReadSignature() == CENTRAL_MAGIC) { + m_signature = CENTRAL_MAGIC; + m_position = endrec.GetOffset(); + m_offsetAdjustment = 0; + return true; + } + + // If it's not there, then it could be that the zip has been appended + // to a self extractor, so take the CD size (also in endrec), subtract + // it from the file offset of the end-central-directory and look there. + if (m_parent_i_stream->SeekI(endPos - endrec.GetSize()) + != wxInvalidOffset && ReadSignature() == CENTRAL_MAGIC) { + m_signature = CENTRAL_MAGIC; + m_position = endPos - endrec.GetSize(); + m_offsetAdjustment = m_position - endrec.GetOffset(); + return true; + } + + wxLogError(_("can't find central directory in zip")); + m_lasterror = wxSTREAM_READ_ERROR; + return false; +} + +// Find the end-of-central-directory record. +// If found the stream will be positioned just past the 4 signature bytes. +// +bool wxZipInputStream::FindEndRecord() +{ + if (!m_parent_i_stream->IsSeekable()) + return false; + + // usually it's 22 bytes in size and the last thing in the file + { + wxLogNull nolog; + if (m_parent_i_stream->SeekI(-END_SIZE, wxFromEnd) == wxInvalidOffset) + return false; + } + + m_parentSeekable = true; + m_signature = 0; + char magic[4]; + if (m_parent_i_stream->Read(magic, 4).LastRead() != 4) + return false; + if ((m_signature = CrackUint32(magic)) == END_MAGIC) + return true; + + // unfortunately, the record has a comment field that can be up to 65535 + // bytes in length, so if the signature not found then search backwards. + wxFileOffset pos = m_parent_i_stream->TellI(); + const int BUFSIZE = 1024; + wxCharBuffer buf(BUFSIZE); + + memcpy(buf.data(), magic, 3); + wxFileOffset minpos = wxMax(pos - 65535L, 0); + + while (pos > minpos) { + size_t len = wx_truncate_cast(size_t, + pos - wxMax(pos - (BUFSIZE - 3), minpos)); + memcpy(buf.data() + len, buf, 3); + pos -= len; + + if (m_parent_i_stream->SeekI(pos, wxFromStart) == wxInvalidOffset || + m_parent_i_stream->Read(buf.data(), len).LastRead() != len) + return false; + + char *p = buf.data() + len; + + while (p-- > buf.data()) { + if ((m_signature = CrackUint32(p)) == END_MAGIC) { + size_t remainder = buf.data() + len - p; + if (remainder > 4) + m_parent_i_stream->Ungetch(p + 4, remainder - 4); + return true; + } + } + } + + return false; +} + +wxZipEntry *wxZipInputStream::GetNextEntry() +{ + if (m_position == wxInvalidOffset) + if (!LoadEndRecord()) + return NULL; + + m_lasterror = m_parentSeekable ? ReadCentral() : ReadLocal(); + if (!IsOk()) + return NULL; + + wxZipEntryPtr_ entry(new wxZipEntry(m_entry)); + entry->m_backlink = m_weaklinks->AddEntry(entry.get(), entry->GetKey()); + return entry.release(); +} + +wxStreamError wxZipInputStream::ReadCentral() +{ + if (!AtHeader()) + CloseEntry(); + + if (m_signature == END_MAGIC) + return wxSTREAM_EOF; + + if (m_signature != CENTRAL_MAGIC) { + wxLogError(_("error reading zip central directory")); + return wxSTREAM_READ_ERROR; + } + + if (QuietSeek(*m_parent_i_stream, m_position + 4) == wxInvalidOffset) + return wxSTREAM_READ_ERROR; + + size_t size = m_entry.ReadCentral(*m_parent_i_stream, GetConv()); + if (!size) { + m_signature = 0; + return wxSTREAM_READ_ERROR; + } + + m_position += size; + m_signature = ReadSignature(); + + if (m_offsetAdjustment) + m_entry.SetOffset(m_entry.GetOffset() + m_offsetAdjustment); + m_entry.SetKey(m_entry.GetOffset()); + + return wxSTREAM_NO_ERROR; +} + +wxStreamError wxZipInputStream::ReadLocal(bool readEndRec /*=false*/) +{ + if (!AtHeader()) + CloseEntry(); + + if (!m_signature) + m_signature = ReadSignature(); + + if (m_signature == CENTRAL_MAGIC || m_signature == END_MAGIC) { + if (m_streamlink && !m_streamlink->GetOutputStream()) { + m_streamlink->Release(this); + m_streamlink = NULL; + } + } + + while (m_signature == CENTRAL_MAGIC) { + if (m_weaklinks->IsEmpty() && m_streamlink == NULL) + return wxSTREAM_EOF; + + size_t size = m_entry.ReadCentral(*m_parent_i_stream, GetConv()); + m_position += size; + m_signature = 0; + if (!size) + return wxSTREAM_READ_ERROR; + + wxZipEntry *entry = m_weaklinks->GetEntry(m_entry.GetOffset()); + if (entry) { + entry->SetSystemMadeBy(m_entry.GetSystemMadeBy()); + entry->SetVersionMadeBy(m_entry.GetVersionMadeBy()); + entry->SetComment(m_entry.GetComment()); + entry->SetDiskStart(m_entry.GetDiskStart()); + entry->SetInternalAttributes(m_entry.GetInternalAttributes()); + entry->SetExternalAttributes(m_entry.GetExternalAttributes()); + Copy(entry->m_Extra, m_entry.m_Extra); + entry->Notify(); + m_weaklinks->RemoveEntry(entry->GetOffset()); + } + + m_signature = ReadSignature(); + } + + if (m_signature == END_MAGIC) { + if (readEndRec || m_streamlink) { + wxZipEndRec endrec; + endrec.Read(*m_parent_i_stream, GetConv()); + m_Comment = endrec.GetComment(); + m_signature = 0; + if (m_streamlink) { + m_streamlink->GetOutputStream()->SetComment(endrec.GetComment()); + m_streamlink->Release(this); + m_streamlink = NULL; + } + } + return wxSTREAM_EOF; + } + + if (m_signature == LOCAL_MAGIC) { + m_headerSize = m_entry.ReadLocal(*m_parent_i_stream, GetConv()); + m_signature = 0; + m_entry.SetOffset(m_position); + m_entry.SetKey(m_position); + + if (m_headerSize) { + m_TotalEntries++; + return wxSTREAM_NO_ERROR; + } + } + + wxLogError(_("error reading zip local header")); + return wxSTREAM_READ_ERROR; +} + +wxUint32 wxZipInputStream::ReadSignature() +{ + char magic[4]; + m_parent_i_stream->Read(magic, 4); + return m_parent_i_stream->LastRead() == 4 ? CrackUint32(magic) : 0; +} + +bool wxZipInputStream::OpenEntry(wxArchiveEntry& entry) +{ + wxZipEntry *zipEntry = wxStaticCast(&entry, wxZipEntry); + return zipEntry ? OpenEntry(*zipEntry) : false; +} + +// Open an entry +// +bool wxZipInputStream::DoOpen(wxZipEntry *entry, bool raw) +{ + if (m_position == wxInvalidOffset) + if (!LoadEndRecord()) + return false; + if (m_lasterror == wxSTREAM_READ_ERROR) + return false; + if (IsOpened()) + CloseEntry(); + + m_raw = raw; + + if (entry) { + if (AfterHeader() && entry->GetKey() == m_entry.GetOffset()) + return true; + // can only open the current entry on a non-seekable stream + wxCHECK(m_parentSeekable, false); + } + + m_lasterror = wxSTREAM_READ_ERROR; + + if (entry) + m_entry = *entry; + + if (m_parentSeekable) { + if (QuietSeek(*m_parent_i_stream, m_entry.GetOffset()) + == wxInvalidOffset) + return false; + if (ReadSignature() != LOCAL_MAGIC) { + wxLogError(_("bad zipfile offset to entry")); + return false; + } + } + + if (m_parentSeekable || AtHeader()) { + m_headerSize = m_entry.ReadLocal(*m_parent_i_stream, GetConv()); + if (m_headerSize && m_parentSeekable) { + wxZipEntry *ref = m_weaklinks->GetEntry(m_entry.GetKey()); + if (ref) { + Copy(ref->m_LocalExtra, m_entry.m_LocalExtra); + ref->Notify(); + m_weaklinks->RemoveEntry(ref->GetKey()); + } + if (entry && entry != ref) { + Copy(entry->m_LocalExtra, m_entry.m_LocalExtra); + entry->Notify(); + } + } + } + + if (m_headerSize) + m_lasterror = wxSTREAM_NO_ERROR; + return IsOk(); +} + +bool wxZipInputStream::OpenDecompressor(bool raw /*=false*/) +{ + wxASSERT(AfterHeader()); + + wxFileOffset compressedSize = m_entry.GetCompressedSize(); + + if (raw) + m_raw = true; + + if (m_raw) { + if (compressedSize != wxInvalidOffset) { + m_store->Open(compressedSize); + m_decomp = m_store; + } else { + if (!m_rawin) + m_rawin = new wxRawInputStream(*m_parent_i_stream); + m_decomp = m_rawin->Open(OpenDecompressor(m_rawin->GetTee())); + } + } else { + if (compressedSize != wxInvalidOffset && + (m_entry.GetMethod() != wxZIP_METHOD_DEFLATE || + wxZlibInputStream::CanHandleGZip())) { + m_store->Open(compressedSize); + m_decomp = OpenDecompressor(*m_store); + } else { + m_decomp = OpenDecompressor(*m_parent_i_stream); + } + } + + m_crcAccumulator = crc32(0, Z_NULL, 0); + m_lasterror = m_decomp ? m_decomp->GetLastError() : wxSTREAM_READ_ERROR; + return IsOk(); +} + +// Can be overriden to add support for additional decompression methods +// +wxInputStream *wxZipInputStream::OpenDecompressor(wxInputStream& stream) +{ + switch (m_entry.GetMethod()) { + case wxZIP_METHOD_STORE: + if (m_entry.GetSize() == wxInvalidOffset) { + wxLogError(_("stored file length not in Zip header")); + break; + } + m_store->Open(m_entry.GetSize()); + return m_store; + + case wxZIP_METHOD_DEFLATE: + if (!m_inflate) + m_inflate = new wxZlibInputStream2(stream); + else + m_inflate->Open(stream); + return m_inflate; + + default: + wxLogError(_("unsupported Zip compression method")); + } + + return NULL; +} + +bool wxZipInputStream::CloseDecompressor(wxInputStream *decomp) +{ + if (decomp && decomp == m_rawin) + return CloseDecompressor(m_rawin->GetFilterInputStream()); + if (decomp != m_store && decomp != m_inflate) + delete decomp; + return true; +} + +// Closes the current entry and positions the underlying stream at the start +// of the next entry +// +bool wxZipInputStream::CloseEntry() +{ + if (AtHeader()) + return true; + if (m_lasterror == wxSTREAM_READ_ERROR) + return false; + + if (!m_parentSeekable) { + if (!IsOpened() && !OpenDecompressor(true)) + return false; + + const int BUFSIZE = 8192; + wxCharBuffer buf(BUFSIZE); + while (IsOk()) + Read(buf.data(), BUFSIZE); + + m_position += m_headerSize + m_entry.GetCompressedSize(); + } + + if (m_lasterror == wxSTREAM_EOF) + m_lasterror = wxSTREAM_NO_ERROR; + + CloseDecompressor(m_decomp); + m_decomp = NULL; + m_entry = wxZipEntry(); + m_headerSize = 0; + m_raw = false; + + return IsOk(); +} + +size_t wxZipInputStream::OnSysRead(void *buffer, size_t size) +{ + if (!IsOpened()) + if ((AtHeader() && !DoOpen()) || !OpenDecompressor()) + m_lasterror = wxSTREAM_READ_ERROR; + if (!IsOk() || !size) + return 0; + + size_t count = m_decomp->Read(buffer, size).LastRead(); + if (!m_raw) + m_crcAccumulator = crc32(m_crcAccumulator, (Byte*)buffer, count); + if (count < size) + m_lasterror = m_decomp->GetLastError(); + + if (Eof()) { + if ((m_entry.GetFlags() & wxZIP_SUMS_FOLLOW) != 0) { + m_headerSize += m_entry.ReadDescriptor(*m_parent_i_stream); + wxZipEntry *entry = m_weaklinks->GetEntry(m_entry.GetKey()); + + if (entry) { + entry->SetCrc(m_entry.GetCrc()); + entry->SetCompressedSize(m_entry.GetCompressedSize()); + entry->SetSize(m_entry.GetSize()); + entry->Notify(); + } + } + + if (!m_raw) { + m_lasterror = wxSTREAM_READ_ERROR; + + if (m_entry.GetSize() != TellI()) + wxLogError(_("reading zip stream (entry %s): bad length"), + m_entry.GetName().c_str()); + else if (m_crcAccumulator != m_entry.GetCrc()) + wxLogError(_("reading zip stream (entry %s): bad crc"), + m_entry.GetName().c_str()); + else + m_lasterror = wxSTREAM_EOF; + } + } + + return count; +} + +#if WXWIN_COMPATIBILITY_2_6 + +// Borrowed from VS's zip stream (c) 1999 Vaclav Slavik +// +wxFileOffset wxZipInputStream::OnSysSeek(wxFileOffset seek, wxSeekMode mode) +{ + // seeking works when the stream is created with the compatibility + // constructor + if (!m_allowSeeking) + return wxInvalidOffset; + if (!IsOpened()) + if ((AtHeader() && !DoOpen()) || !OpenDecompressor()) + m_lasterror = wxSTREAM_READ_ERROR; + if (!IsOk()) + return wxInvalidOffset; + + // NB: since ZIP files don't natively support seeking, we have to + // implement a brute force workaround -- reading all the data + // between current and the new position (or between beginning of + // the file and new position...) + + wxFileOffset nextpos; + wxFileOffset pos = TellI(); + + switch ( mode ) + { + case wxFromCurrent : nextpos = seek + pos; break; + case wxFromStart : nextpos = seek; break; + case wxFromEnd : nextpos = GetLength() + seek; break; + default : nextpos = pos; break; /* just to fool compiler, never happens */ + } + + wxFileOffset toskip wxDUMMY_INITIALIZE(0); + if ( nextpos >= pos ) + { + toskip = nextpos - pos; + } + else + { + wxZipEntry current(m_entry); + if (!OpenEntry(current)) + { + m_lasterror = wxSTREAM_READ_ERROR; + return pos; + } + toskip = nextpos; + } + + if ( toskip > 0 ) + { + const int BUFSIZE = 4096; + size_t sz; + char buffer[BUFSIZE]; + while ( toskip > 0 ) + { + sz = wx_truncate_cast(size_t, wxMin(toskip, BUFSIZE)); + Read(buffer, sz); + toskip -= sz; + } + } + + pos = nextpos; + return pos; +} + +#endif // WXWIN_COMPATIBILITY_2_6 + + +///////////////////////////////////////////////////////////////////////////// +// Output stream + +#include "wx/listimpl.cpp" +WX_DEFINE_LIST(wxZipEntryList_) + +wxZipOutputStream::wxZipOutputStream(wxOutputStream& stream, + int level /*=-1*/, + wxMBConv& conv /*=wxConvLocal*/) + : wxArchiveOutputStream(stream, conv) +{ + Init(level); +} + +wxZipOutputStream::wxZipOutputStream(wxOutputStream *stream, + int level /*=-1*/, + wxMBConv& conv /*=wxConvLocal*/) + : wxArchiveOutputStream(stream, conv) +{ + Init(level); +} + +void wxZipOutputStream::Init(int level) +{ + m_store = new wxStoredOutputStream(*m_parent_o_stream); + m_deflate = NULL; + m_backlink = NULL; + m_initialData = new char[OUTPUT_LATENCY]; + m_initialSize = 0; + m_pending = NULL; + m_raw = false; + m_headerOffset = 0; + m_headerSize = 0; + m_entrySize = 0; + m_comp = NULL; + m_level = level; + m_offsetAdjustment = wxInvalidOffset; +} + +wxZipOutputStream::~wxZipOutputStream() +{ + Close(); + WX_CLEAR_LIST(wxZipEntryList_, m_entries); + delete m_store; + delete m_deflate; + delete m_pending; + delete [] m_initialData; + if (m_backlink) + m_backlink->Release(this); +} + +bool wxZipOutputStream::PutNextEntry( + const wxString& name, + const wxDateTime& dt /*=wxDateTime::Now()*/, + wxFileOffset size /*=wxInvalidOffset*/) +{ + return PutNextEntry(new wxZipEntry(name, dt, size)); +} + +bool wxZipOutputStream::PutNextDirEntry( + const wxString& name, + const wxDateTime& dt /*=wxDateTime::Now()*/) +{ + wxZipEntry *entry = new wxZipEntry(name, dt); + entry->SetIsDir(); + return PutNextEntry(entry); +} + +bool wxZipOutputStream::CopyEntry(wxZipEntry *entry, + wxZipInputStream& inputStream) +{ + wxZipEntryPtr_ e(entry); + + return + inputStream.DoOpen(e.get(), true) && + DoCreate(e.release(), true) && + Write(inputStream).IsOk() && inputStream.Eof(); +} + +bool wxZipOutputStream::PutNextEntry(wxArchiveEntry *entry) +{ + wxZipEntry *zipEntry = wxStaticCast(entry, wxZipEntry); + if (!zipEntry) + delete entry; + return PutNextEntry(zipEntry); +} + +bool wxZipOutputStream::CopyEntry(wxArchiveEntry *entry, + wxArchiveInputStream& stream) +{ + wxZipEntry *zipEntry = wxStaticCast(entry, wxZipEntry); + + if (!zipEntry || !stream.OpenEntry(*zipEntry)) { + delete entry; + return false; + } + + return CopyEntry(zipEntry, wx_static_cast(wxZipInputStream&, stream)); +} + +bool wxZipOutputStream::CopyArchiveMetaData(wxZipInputStream& inputStream) +{ + m_Comment = inputStream.GetComment(); + if (m_backlink) + m_backlink->Release(this); + m_backlink = inputStream.MakeLink(this); + return true; +} + +bool wxZipOutputStream::CopyArchiveMetaData(wxArchiveInputStream& stream) +{ + return CopyArchiveMetaData(wx_static_cast(wxZipInputStream&, stream)); +} + +void wxZipOutputStream::SetLevel(int level) +{ + if (level != m_level) { + if (m_comp != m_deflate) + delete m_deflate; + m_deflate = NULL; + m_level = level; + } +} + +bool wxZipOutputStream::DoCreate(wxZipEntry *entry, bool raw /*=false*/) +{ + CloseEntry(); + + m_pending = entry; + if (!m_pending) + return false; + + // write the signature bytes right away + wxDataOutputStream ds(*m_parent_o_stream); + ds << LOCAL_MAGIC; + + // and if this is the first entry test for seekability + if (m_headerOffset == 0 && m_parent_o_stream->IsSeekable()) { +#if wxUSE_LOG + bool logging = wxLog::IsEnabled(); + wxLogNull nolog; +#endif // wxUSE_LOG + wxFileOffset here = m_parent_o_stream->TellO(); + + if (here != wxInvalidOffset && here >= 4) { + if (m_parent_o_stream->SeekO(here - 4) == here - 4) { + m_offsetAdjustment = here - 4; +#if wxUSE_LOG + wxLog::EnableLogging(logging); +#endif // wxUSE_LOG + m_parent_o_stream->SeekO(here); + } + } + } + + m_pending->SetOffset(m_headerOffset); + + m_crcAccumulator = crc32(0, Z_NULL, 0); + + if (raw) + m_raw = true; + + m_lasterror = wxSTREAM_NO_ERROR; + return true; +} + +// Can be overriden to add support for additional compression methods +// +wxOutputStream *wxZipOutputStream::OpenCompressor( + wxOutputStream& stream, + wxZipEntry& entry, + const Buffer bufs[]) +{ + if (entry.GetMethod() == wxZIP_METHOD_DEFAULT) { + if (GetLevel() == 0 + && (IsParentSeekable() + || entry.GetCompressedSize() != wxInvalidOffset + || entry.GetSize() != wxInvalidOffset)) { + entry.SetMethod(wxZIP_METHOD_STORE); + } else { + int size = 0; + for (int i = 0; bufs[i].m_data; ++i) + size += bufs[i].m_size; + entry.SetMethod(size <= 6 ? + wxZIP_METHOD_STORE : wxZIP_METHOD_DEFLATE); + } + } + + switch (entry.GetMethod()) { + case wxZIP_METHOD_STORE: + if (entry.GetCompressedSize() == wxInvalidOffset) + entry.SetCompressedSize(entry.GetSize()); + return m_store; + + case wxZIP_METHOD_DEFLATE: + { + int defbits = wxZIP_DEFLATE_NORMAL; + switch (GetLevel()) { + case 0: case 1: + defbits = wxZIP_DEFLATE_SUPERFAST; + break; + case 2: case 3: case 4: + defbits = wxZIP_DEFLATE_FAST; + break; + case 8: case 9: + defbits = wxZIP_DEFLATE_EXTRA; + break; + } + entry.SetFlags((entry.GetFlags() & ~wxZIP_DEFLATE_MASK) | + defbits | wxZIP_SUMS_FOLLOW); + + if (!m_deflate) + m_deflate = new wxZlibOutputStream2(stream, GetLevel()); + else + m_deflate->Open(stream); + + return m_deflate; + } + + default: + wxLogError(_("unsupported Zip compression method")); + } + + return NULL; +} + +bool wxZipOutputStream::CloseCompressor(wxOutputStream *comp) +{ + if (comp == m_deflate) + m_deflate->Close(); + else if (comp != m_store) + delete comp; + return true; +} + +// This is called when OUPUT_LATENCY bytes has been written to the +// wxZipOutputStream to actually create the zip entry. +// +void wxZipOutputStream::CreatePendingEntry(const void *buffer, size_t size) +{ + wxASSERT(IsOk() && m_pending && !m_comp); + wxZipEntryPtr_ spPending(m_pending); + m_pending = NULL; + + Buffer bufs[] = { + { m_initialData, m_initialSize }, + { (const char*)buffer, size }, + { NULL, 0 } + }; + + if (m_raw) + m_comp = m_store; + else + m_comp = OpenCompressor(*m_store, *spPending, + m_initialSize ? bufs : bufs + 1); + + if (IsParentSeekable() + || (spPending->m_Crc + && spPending->m_CompressedSize != wxInvalidOffset + && spPending->m_Size != wxInvalidOffset)) + spPending->m_Flags &= ~wxZIP_SUMS_FOLLOW; + else + if (spPending->m_CompressedSize != wxInvalidOffset) + spPending->m_Flags |= wxZIP_SUMS_FOLLOW; + + m_headerSize = spPending->WriteLocal(*m_parent_o_stream, GetConv()); + m_lasterror = m_parent_o_stream->GetLastError(); + + if (IsOk()) { + m_entries.push_back(spPending.release()); + OnSysWrite(m_initialData, m_initialSize); + } + + m_initialSize = 0; +} + +// This is called to write out the zip entry when Close has been called +// before OUTPUT_LATENCY bytes has been written to the wxZipOutputStream. +// +void wxZipOutputStream::CreatePendingEntry() +{ + wxASSERT(IsOk() && m_pending && !m_comp); + wxZipEntryPtr_ spPending(m_pending); + m_pending = NULL; + m_lasterror = wxSTREAM_WRITE_ERROR; + + if (!m_raw) { + // Initially compresses the data to memory, then fall back to 'store' + // if the compressor makes the data larger rather than smaller. + wxMemoryOutputStream mem; + Buffer bufs[] = { { m_initialData, m_initialSize }, { NULL, 0 } }; + wxOutputStream *comp = OpenCompressor(mem, *spPending, bufs); + + if (!comp) + return; + if (comp != m_store) { + bool ok = comp->Write(m_initialData, m_initialSize).IsOk(); + CloseCompressor(comp); + if (!ok) + return; + } + + m_entrySize = m_initialSize; + m_crcAccumulator = crc32(0, (Byte*)m_initialData, m_initialSize); + + if (mem.GetSize() > 0 && mem.GetSize() < m_initialSize) { + m_initialSize = mem.GetSize(); + mem.CopyTo(m_initialData, m_initialSize); + } else { + spPending->SetMethod(wxZIP_METHOD_STORE); + } + + spPending->SetSize(m_entrySize); + spPending->SetCrc(m_crcAccumulator); + spPending->SetCompressedSize(m_initialSize); + } + + spPending->m_Flags &= ~wxZIP_SUMS_FOLLOW; + m_headerSize = spPending->WriteLocal(*m_parent_o_stream, GetConv()); + + if (m_parent_o_stream->IsOk()) { + m_entries.push_back(spPending.release()); + m_comp = m_store; + m_store->Write(m_initialData, m_initialSize); + } + + m_initialSize = 0; + m_lasterror = m_parent_o_stream->GetLastError(); +} + +// Write the 'central directory' and the 'end-central-directory' records. +// +bool wxZipOutputStream::Close() +{ + CloseEntry(); + + if (m_lasterror == wxSTREAM_WRITE_ERROR || m_entries.size() == 0) { + wxFilterOutputStream::Close(); + return false; + } + + wxZipEndRec endrec; + + endrec.SetEntriesHere(m_entries.size()); + endrec.SetTotalEntries(m_entries.size()); + endrec.SetOffset(m_headerOffset); + endrec.SetComment(m_Comment); + + wxZipEntryList_::iterator it; + wxFileOffset size = 0; + + for (it = m_entries.begin(); it != m_entries.end(); ++it) { + size += (*it)->WriteCentral(*m_parent_o_stream, GetConv()); + delete *it; + } + m_entries.clear(); + + endrec.SetSize(size); + endrec.Write(*m_parent_o_stream, GetConv()); + + m_lasterror = m_parent_o_stream->GetLastError(); + + if (!wxFilterOutputStream::Close() || !IsOk()) + return false; + m_lasterror = wxSTREAM_EOF; + return true; +} + +// Finish writing the current entry +// +bool wxZipOutputStream::CloseEntry() +{ + if (IsOk() && m_pending) + CreatePendingEntry(); + if (!IsOk()) + return false; + if (!m_comp) + return true; + + CloseCompressor(m_comp); + m_comp = NULL; + + wxFileOffset compressedSize = m_store->TellO(); + + wxZipEntry& entry = *m_entries.back(); + + // When writing raw the crc and size can't be checked + if (m_raw) { + m_crcAccumulator = entry.GetCrc(); + m_entrySize = entry.GetSize(); + } + + // Write the sums in the trailing 'data descriptor' if necessary + if (entry.m_Flags & wxZIP_SUMS_FOLLOW) { + wxASSERT(!IsParentSeekable()); + m_headerOffset += + entry.WriteDescriptor(*m_parent_o_stream, m_crcAccumulator, + compressedSize, m_entrySize); + m_lasterror = m_parent_o_stream->GetLastError(); + } + + // If the local header didn't have the correct crc and size written to + // it then seek back and fix it + else if (m_crcAccumulator != entry.GetCrc() + || m_entrySize != entry.GetSize() + || compressedSize != entry.GetCompressedSize()) + { + if (IsParentSeekable()) { + wxFileOffset here = m_parent_o_stream->TellO(); + wxFileOffset headerOffset = m_headerOffset + m_offsetAdjustment; + m_parent_o_stream->SeekO(headerOffset + SUMS_OFFSET); + entry.WriteDescriptor(*m_parent_o_stream, m_crcAccumulator, + compressedSize, m_entrySize); + m_parent_o_stream->SeekO(here); + m_lasterror = m_parent_o_stream->GetLastError(); + } else { + m_lasterror = wxSTREAM_WRITE_ERROR; + } + } + + m_headerOffset += m_headerSize + compressedSize; + m_headerSize = 0; + m_entrySize = 0; + m_store->Close(); + m_raw = false; + + if (IsOk()) + m_lasterror = m_parent_o_stream->GetLastError(); + else + wxLogError(_("error writing zip entry '%s': bad crc or length"), + entry.GetName().c_str()); + return IsOk(); +} + +void wxZipOutputStream::Sync() +{ + if (IsOk() && m_pending) + CreatePendingEntry(NULL, 0); + if (!m_comp) + m_lasterror = wxSTREAM_WRITE_ERROR; + if (IsOk()) { + m_comp->Sync(); + m_lasterror = m_comp->GetLastError(); + } +} + +size_t wxZipOutputStream::OnSysWrite(const void *buffer, size_t size) +{ + if (IsOk() && m_pending) { + if (m_initialSize + size < OUTPUT_LATENCY) { + memcpy(m_initialData + m_initialSize, buffer, size); + m_initialSize += size; + return size; + } else { + CreatePendingEntry(buffer, size); + } + } + + if (!m_comp) + m_lasterror = wxSTREAM_WRITE_ERROR; + if (!IsOk() || !size) + return 0; + + if (m_comp->Write(buffer, size).LastWrite() != size) + m_lasterror = wxSTREAM_WRITE_ERROR; + m_crcAccumulator = crc32(m_crcAccumulator, (Byte*)buffer, size); + m_entrySize += m_comp->LastWrite(); + + return m_comp->LastWrite(); +} + +#endif // wxUSE_ZIPSTREAM diff --git a/Externals/wxWidgets/src/common/zstream.cpp b/Externals/wxWidgets/src/common/zstream.cpp index a3a4270071..8f66fce17f 100644 --- a/Externals/wxWidgets/src/common/zstream.cpp +++ b/Externals/wxWidgets/src/common/zstream.cpp @@ -1,428 +1,428 @@ -////////////////////////////////////////////////////////////////////////////// -// Name: src/common/zstream.cpp -// Purpose: Compressed stream classes -// Author: Guilhem Lavaux -// Modified by: Mike Wetherell -// Created: 11/07/98 -// RCS-ID: $Id: zstream.cpp 42621 2006-10-29 16:47:20Z MW $ -// Copyright: (c) Guilhem Lavaux -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_ZLIB && wxUSE_STREAMS - -#include "wx/zstream.h" - -#ifndef WX_PRECOMP - #include "wx/intl.h" - #include "wx/log.h" - #include "wx/utils.h" -#endif - - -// normally, the compiler options should contain -I../zlib, but it is -// apparently not the case for all MSW makefiles and so, unless we use -// configure (which defines __WX_SETUP_H__) or it is explicitly overridden by -// the user (who can define wxUSE_ZLIB_H_IN_PATH), we hardcode the path here -#if defined(__WXMSW__) && !defined(__WX_SETUP_H__) && !defined(wxUSE_ZLIB_H_IN_PATH) - #include "../zlib/zlib.h" -#else - #include "zlib.h" -#endif - -enum { - ZSTREAM_BUFFER_SIZE = 16384, - ZSTREAM_GZIP = 0x10, // gzip header - ZSTREAM_AUTO = 0x20 // auto detect between gzip and zlib -}; - - -///////////////////////////////////////////////////////////////////////////// -// Zlib Class factory - -IMPLEMENT_DYNAMIC_CLASS(wxZlibClassFactory, wxFilterClassFactory) - -static wxZlibClassFactory g_wxZlibClassFactory; - -wxZlibClassFactory::wxZlibClassFactory() -{ - if (this == &g_wxZlibClassFactory) - PushFront(); -} - -const wxChar * const * -wxZlibClassFactory::GetProtocols(wxStreamProtocolType type) const -{ - static const wxChar *mimes[] = { _T("application/x-deflate"), NULL }; - static const wxChar *encs[] = { _T("deflate"), NULL }; - static const wxChar *empty[] = { NULL }; - - switch (type) { - case wxSTREAM_MIMETYPE: return mimes; - case wxSTREAM_ENCODING: return encs; - default: return empty; - } -} - - -///////////////////////////////////////////////////////////////////////////// -// Gzip Class factory - -IMPLEMENT_DYNAMIC_CLASS(wxGzipClassFactory, wxFilterClassFactory) - -static wxGzipClassFactory g_wxGzipClassFactory; - -wxGzipClassFactory::wxGzipClassFactory() -{ - if (this == &g_wxGzipClassFactory && wxZlibInputStream::CanHandleGZip()) - PushFront(); -} - -const wxChar * const * -wxGzipClassFactory::GetProtocols(wxStreamProtocolType type) const -{ - static const wxChar *protos[] = - { _T("gzip"), NULL }; - static const wxChar *mimes[] = - { _T("application/gzip"), _T("application/x-gzip"), NULL }; - static const wxChar *encs[] = - { _T("gzip"), NULL }; - static const wxChar *exts[] = - { _T(".gz"), _T(".gzip"), NULL }; - static const wxChar *empty[] = - { NULL }; - - switch (type) { - case wxSTREAM_PROTOCOL: return protos; - case wxSTREAM_MIMETYPE: return mimes; - case wxSTREAM_ENCODING: return encs; - case wxSTREAM_FILEEXT: return exts; - default: return empty; - } -} - - -////////////////////// -// wxZlibInputStream -////////////////////// - -wxZlibInputStream::wxZlibInputStream(wxInputStream& stream, int flags) - : wxFilterInputStream(stream) -{ - Init(flags); -} - -wxZlibInputStream::wxZlibInputStream(wxInputStream *stream, int flags) - : wxFilterInputStream(stream) -{ - Init(flags); -} - -void wxZlibInputStream::Init(int flags) -{ - m_inflate = NULL; - m_z_buffer = new unsigned char[ZSTREAM_BUFFER_SIZE]; - m_z_size = ZSTREAM_BUFFER_SIZE; - m_pos = 0; - -#if WXWIN_COMPATIBILITY_2_4 - // treat compatibility mode as auto - m_24compatibilty = flags == wxZLIB_24COMPATIBLE; - if (m_24compatibilty) - flags = wxZLIB_AUTO; -#endif - - // if gzip is asked for but not supported... - if ((flags == wxZLIB_GZIP || flags == wxZLIB_AUTO) && !CanHandleGZip()) { - if (flags == wxZLIB_AUTO) { - // an error will come later if the input turns out not to be a zlib - flags = wxZLIB_ZLIB; - } - else { - wxLogError(_("Gzip not supported by this version of zlib")); - m_lasterror = wxSTREAM_READ_ERROR; - return; - } - } - - if (m_z_buffer) { - m_inflate = new z_stream_s; - - if (m_inflate) { - memset(m_inflate, 0, sizeof(z_stream_s)); - - // see zlib.h for documentation on windowBits - int windowBits = MAX_WBITS; - switch (flags) { - case wxZLIB_NO_HEADER: windowBits = -MAX_WBITS; break; - case wxZLIB_ZLIB: windowBits = MAX_WBITS; break; - case wxZLIB_GZIP: windowBits = MAX_WBITS | ZSTREAM_GZIP; break; - case wxZLIB_AUTO: windowBits = MAX_WBITS | ZSTREAM_AUTO; break; - default: wxFAIL_MSG(wxT("Invalid zlib flag")); - } - - if (inflateInit2(m_inflate, windowBits) == Z_OK) - return; - } - } - - wxLogError(_("Can't initialize zlib inflate stream.")); - m_lasterror = wxSTREAM_READ_ERROR; -} - -wxZlibInputStream::~wxZlibInputStream() -{ - inflateEnd(m_inflate); - delete m_inflate; - - delete [] m_z_buffer; -} - -size_t wxZlibInputStream::OnSysRead(void *buffer, size_t size) -{ - wxASSERT_MSG(m_inflate && m_z_buffer, wxT("Inflate stream not open")); - - if (!m_inflate || !m_z_buffer) - m_lasterror = wxSTREAM_READ_ERROR; - if (!IsOk() || !size) - return 0; - - int err = Z_OK; - m_inflate->next_out = (unsigned char *)buffer; - m_inflate->avail_out = size; - - while (err == Z_OK && m_inflate->avail_out > 0) { - if (m_inflate->avail_in == 0 && m_parent_i_stream->IsOk()) { - m_parent_i_stream->Read(m_z_buffer, m_z_size); - m_inflate->next_in = m_z_buffer; - m_inflate->avail_in = m_parent_i_stream->LastRead(); - } - err = inflate(m_inflate, Z_SYNC_FLUSH); - } - - switch (err) { - case Z_OK: - break; - - case Z_STREAM_END: - if (m_inflate->avail_out) { - // Unread any data taken from past the end of the deflate stream, so that - // any additional data can be read from the underlying stream (the crc - // in a gzip for example) - if (m_inflate->avail_in) { - m_parent_i_stream->Reset(); - m_parent_i_stream->Ungetch(m_inflate->next_in, m_inflate->avail_in); - m_inflate->avail_in = 0; - } - m_lasterror = wxSTREAM_EOF; - } - break; - - case Z_BUF_ERROR: - // Indicates that zlib was expecting more data, but the parent stream - // has none. Other than Eof the error will have been already reported - // by the parent strean, - m_lasterror = wxSTREAM_READ_ERROR; - if (m_parent_i_stream->Eof()) -#if WXWIN_COMPATIBILITY_2_4 - if (m_24compatibilty) - m_lasterror = wxSTREAM_EOF; - else -#endif - wxLogError(_("Can't read inflate stream: unexpected EOF in underlying stream.")); - break; - - default: - wxString msg(m_inflate->msg, *wxConvCurrent); - if (!msg) - msg = wxString::Format(_("zlib error %d"), err); - wxLogError(_("Can't read from inflate stream: %s"), msg.c_str()); - m_lasterror = wxSTREAM_READ_ERROR; - } - - size -= m_inflate->avail_out; - m_pos += size; - return size; -} - -/* static */ bool wxZlibInputStream::CanHandleGZip() -{ - const char *dot = strchr(zlibVersion(), '.'); - int major = atoi(zlibVersion()); - int minor = dot ? atoi(dot + 1) : 0; - return major > 1 || (major == 1 && minor >= 2); -} - - -////////////////////// -// wxZlibOutputStream -////////////////////// - -wxZlibOutputStream::wxZlibOutputStream(wxOutputStream& stream, - int level, - int flags) - : wxFilterOutputStream(stream) -{ - Init(level, flags); -} - -wxZlibOutputStream::wxZlibOutputStream(wxOutputStream *stream, - int level, - int flags) - : wxFilterOutputStream(stream) -{ - Init(level, flags); -} - -void wxZlibOutputStream::Init(int level, int flags) -{ - m_deflate = NULL; - m_z_buffer = new unsigned char[ZSTREAM_BUFFER_SIZE]; - m_z_size = ZSTREAM_BUFFER_SIZE; - m_pos = 0; - - if ( level == -1 ) - { - level = Z_DEFAULT_COMPRESSION; - } - else - { - wxASSERT_MSG(level >= 0 && level <= 9, wxT("wxZlibOutputStream compression level must be between 0 and 9!")); - } - - // if gzip is asked for but not supported... - if (flags == wxZLIB_GZIP && !CanHandleGZip()) { - wxLogError(_("Gzip not supported by this version of zlib")); - m_lasterror = wxSTREAM_WRITE_ERROR; - return; - } - - if (m_z_buffer) { - m_deflate = new z_stream_s; - - if (m_deflate) { - memset(m_deflate, 0, sizeof(z_stream_s)); - m_deflate->next_out = m_z_buffer; - m_deflate->avail_out = m_z_size; - - // see zlib.h for documentation on windowBits - int windowBits = MAX_WBITS; - switch (flags) { - case wxZLIB_NO_HEADER: windowBits = -MAX_WBITS; break; - case wxZLIB_ZLIB: windowBits = MAX_WBITS; break; - case wxZLIB_GZIP: windowBits = MAX_WBITS | ZSTREAM_GZIP; break; - default: wxFAIL_MSG(wxT("Invalid zlib flag")); - } - - if (deflateInit2(m_deflate, level, Z_DEFLATED, windowBits, - 8, Z_DEFAULT_STRATEGY) == Z_OK) - return; - } - } - - wxLogError(_("Can't initialize zlib deflate stream.")); - m_lasterror = wxSTREAM_WRITE_ERROR; -} - -bool wxZlibOutputStream::Close() - { - DoFlush(true); - deflateEnd(m_deflate); - delete m_deflate; - - m_deflate = NULL; - delete[] m_z_buffer; - m_z_buffer = NULL; - - return wxFilterOutputStream::Close() && IsOk(); - } - -void wxZlibOutputStream::DoFlush(bool final) -{ - if (!m_deflate || !m_z_buffer) - m_lasterror = wxSTREAM_WRITE_ERROR; - if (!IsOk()) - return; - - int err = Z_OK; - bool done = false; - - while (err == Z_OK || err == Z_STREAM_END) { - size_t len = m_z_size - m_deflate->avail_out; - if (len) { - if (m_parent_o_stream->Write(m_z_buffer, len).LastWrite() != len) { - m_lasterror = wxSTREAM_WRITE_ERROR; - wxLogDebug(wxT("wxZlibOutputStream: Error writing to underlying stream")); - break; - } - m_deflate->next_out = m_z_buffer; - m_deflate->avail_out = m_z_size; - } - - if (done) - break; - err = deflate(m_deflate, final ? Z_FINISH : Z_FULL_FLUSH); - done = m_deflate->avail_out != 0 || err == Z_STREAM_END; - } -} - -size_t wxZlibOutputStream::OnSysWrite(const void *buffer, size_t size) -{ - wxASSERT_MSG(m_deflate && m_z_buffer, wxT("Deflate stream not open")); - - if (!m_deflate || !m_z_buffer) - { - // notice that this will make IsOk() test just below return false - m_lasterror = wxSTREAM_WRITE_ERROR; - } - - if (!IsOk() || !size) - return 0; - - int err = Z_OK; - m_deflate->next_in = (unsigned char *)buffer; - m_deflate->avail_in = size; - - while (err == Z_OK && m_deflate->avail_in > 0) { - if (m_deflate->avail_out == 0) { - m_parent_o_stream->Write(m_z_buffer, m_z_size); - if (m_parent_o_stream->LastWrite() != m_z_size) { - m_lasterror = wxSTREAM_WRITE_ERROR; - wxLogDebug(wxT("wxZlibOutputStream: Error writing to underlying stream")); - break; - } - - m_deflate->next_out = m_z_buffer; - m_deflate->avail_out = m_z_size; - } - - err = deflate(m_deflate, Z_NO_FLUSH); - } - - if (err != Z_OK) { - m_lasterror = wxSTREAM_WRITE_ERROR; - wxString msg(m_deflate->msg, *wxConvCurrent); - if (!msg) - msg = wxString::Format(_("zlib error %d"), err); - wxLogError(_("Can't write to deflate stream: %s"), msg.c_str()); - } - - size -= m_deflate->avail_in; - m_pos += size; - return size; -} - -/* static */ bool wxZlibOutputStream::CanHandleGZip() -{ - return wxZlibInputStream::CanHandleGZip(); -} - -#endif - // wxUSE_ZLIB && wxUSE_STREAMS +////////////////////////////////////////////////////////////////////////////// +// Name: src/common/zstream.cpp +// Purpose: Compressed stream classes +// Author: Guilhem Lavaux +// Modified by: Mike Wetherell +// Created: 11/07/98 +// RCS-ID: $Id: zstream.cpp 42621 2006-10-29 16:47:20Z MW $ +// Copyright: (c) Guilhem Lavaux +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_ZLIB && wxUSE_STREAMS + +#include "wx/zstream.h" + +#ifndef WX_PRECOMP + #include "wx/intl.h" + #include "wx/log.h" + #include "wx/utils.h" +#endif + + +// normally, the compiler options should contain -I../zlib, but it is +// apparently not the case for all MSW makefiles and so, unless we use +// configure (which defines __WX_SETUP_H__) or it is explicitly overridden by +// the user (who can define wxUSE_ZLIB_H_IN_PATH), we hardcode the path here +#if defined(__WXMSW__) && !defined(__WX_SETUP_H__) && !defined(wxUSE_ZLIB_H_IN_PATH) + #include "../zlib/zlib.h" +#else + #include "zlib.h" +#endif + +enum { + ZSTREAM_BUFFER_SIZE = 16384, + ZSTREAM_GZIP = 0x10, // gzip header + ZSTREAM_AUTO = 0x20 // auto detect between gzip and zlib +}; + + +///////////////////////////////////////////////////////////////////////////// +// Zlib Class factory + +IMPLEMENT_DYNAMIC_CLASS(wxZlibClassFactory, wxFilterClassFactory) + +static wxZlibClassFactory g_wxZlibClassFactory; + +wxZlibClassFactory::wxZlibClassFactory() +{ + if (this == &g_wxZlibClassFactory) + PushFront(); +} + +const wxChar * const * +wxZlibClassFactory::GetProtocols(wxStreamProtocolType type) const +{ + static const wxChar *mimes[] = { _T("application/x-deflate"), NULL }; + static const wxChar *encs[] = { _T("deflate"), NULL }; + static const wxChar *empty[] = { NULL }; + + switch (type) { + case wxSTREAM_MIMETYPE: return mimes; + case wxSTREAM_ENCODING: return encs; + default: return empty; + } +} + + +///////////////////////////////////////////////////////////////////////////// +// Gzip Class factory + +IMPLEMENT_DYNAMIC_CLASS(wxGzipClassFactory, wxFilterClassFactory) + +static wxGzipClassFactory g_wxGzipClassFactory; + +wxGzipClassFactory::wxGzipClassFactory() +{ + if (this == &g_wxGzipClassFactory && wxZlibInputStream::CanHandleGZip()) + PushFront(); +} + +const wxChar * const * +wxGzipClassFactory::GetProtocols(wxStreamProtocolType type) const +{ + static const wxChar *protos[] = + { _T("gzip"), NULL }; + static const wxChar *mimes[] = + { _T("application/gzip"), _T("application/x-gzip"), NULL }; + static const wxChar *encs[] = + { _T("gzip"), NULL }; + static const wxChar *exts[] = + { _T(".gz"), _T(".gzip"), NULL }; + static const wxChar *empty[] = + { NULL }; + + switch (type) { + case wxSTREAM_PROTOCOL: return protos; + case wxSTREAM_MIMETYPE: return mimes; + case wxSTREAM_ENCODING: return encs; + case wxSTREAM_FILEEXT: return exts; + default: return empty; + } +} + + +////////////////////// +// wxZlibInputStream +////////////////////// + +wxZlibInputStream::wxZlibInputStream(wxInputStream& stream, int flags) + : wxFilterInputStream(stream) +{ + Init(flags); +} + +wxZlibInputStream::wxZlibInputStream(wxInputStream *stream, int flags) + : wxFilterInputStream(stream) +{ + Init(flags); +} + +void wxZlibInputStream::Init(int flags) +{ + m_inflate = NULL; + m_z_buffer = new unsigned char[ZSTREAM_BUFFER_SIZE]; + m_z_size = ZSTREAM_BUFFER_SIZE; + m_pos = 0; + +#if WXWIN_COMPATIBILITY_2_4 + // treat compatibility mode as auto + m_24compatibilty = flags == wxZLIB_24COMPATIBLE; + if (m_24compatibilty) + flags = wxZLIB_AUTO; +#endif + + // if gzip is asked for but not supported... + if ((flags == wxZLIB_GZIP || flags == wxZLIB_AUTO) && !CanHandleGZip()) { + if (flags == wxZLIB_AUTO) { + // an error will come later if the input turns out not to be a zlib + flags = wxZLIB_ZLIB; + } + else { + wxLogError(_("Gzip not supported by this version of zlib")); + m_lasterror = wxSTREAM_READ_ERROR; + return; + } + } + + if (m_z_buffer) { + m_inflate = new z_stream_s; + + if (m_inflate) { + memset(m_inflate, 0, sizeof(z_stream_s)); + + // see zlib.h for documentation on windowBits + int windowBits = MAX_WBITS; + switch (flags) { + case wxZLIB_NO_HEADER: windowBits = -MAX_WBITS; break; + case wxZLIB_ZLIB: windowBits = MAX_WBITS; break; + case wxZLIB_GZIP: windowBits = MAX_WBITS | ZSTREAM_GZIP; break; + case wxZLIB_AUTO: windowBits = MAX_WBITS | ZSTREAM_AUTO; break; + default: wxFAIL_MSG(wxT("Invalid zlib flag")); + } + + if (inflateInit2(m_inflate, windowBits) == Z_OK) + return; + } + } + + wxLogError(_("Can't initialize zlib inflate stream.")); + m_lasterror = wxSTREAM_READ_ERROR; +} + +wxZlibInputStream::~wxZlibInputStream() +{ + inflateEnd(m_inflate); + delete m_inflate; + + delete [] m_z_buffer; +} + +size_t wxZlibInputStream::OnSysRead(void *buffer, size_t size) +{ + wxASSERT_MSG(m_inflate && m_z_buffer, wxT("Inflate stream not open")); + + if (!m_inflate || !m_z_buffer) + m_lasterror = wxSTREAM_READ_ERROR; + if (!IsOk() || !size) + return 0; + + int err = Z_OK; + m_inflate->next_out = (unsigned char *)buffer; + m_inflate->avail_out = size; + + while (err == Z_OK && m_inflate->avail_out > 0) { + if (m_inflate->avail_in == 0 && m_parent_i_stream->IsOk()) { + m_parent_i_stream->Read(m_z_buffer, m_z_size); + m_inflate->next_in = m_z_buffer; + m_inflate->avail_in = m_parent_i_stream->LastRead(); + } + err = inflate(m_inflate, Z_SYNC_FLUSH); + } + + switch (err) { + case Z_OK: + break; + + case Z_STREAM_END: + if (m_inflate->avail_out) { + // Unread any data taken from past the end of the deflate stream, so that + // any additional data can be read from the underlying stream (the crc + // in a gzip for example) + if (m_inflate->avail_in) { + m_parent_i_stream->Reset(); + m_parent_i_stream->Ungetch(m_inflate->next_in, m_inflate->avail_in); + m_inflate->avail_in = 0; + } + m_lasterror = wxSTREAM_EOF; + } + break; + + case Z_BUF_ERROR: + // Indicates that zlib was expecting more data, but the parent stream + // has none. Other than Eof the error will have been already reported + // by the parent strean, + m_lasterror = wxSTREAM_READ_ERROR; + if (m_parent_i_stream->Eof()) +#if WXWIN_COMPATIBILITY_2_4 + if (m_24compatibilty) + m_lasterror = wxSTREAM_EOF; + else +#endif + wxLogError(_("Can't read inflate stream: unexpected EOF in underlying stream.")); + break; + + default: + wxString msg(m_inflate->msg, *wxConvCurrent); + if (!msg) + msg = wxString::Format(_("zlib error %d"), err); + wxLogError(_("Can't read from inflate stream: %s"), msg.c_str()); + m_lasterror = wxSTREAM_READ_ERROR; + } + + size -= m_inflate->avail_out; + m_pos += size; + return size; +} + +/* static */ bool wxZlibInputStream::CanHandleGZip() +{ + const char *dot = strchr(zlibVersion(), '.'); + int major = atoi(zlibVersion()); + int minor = dot ? atoi(dot + 1) : 0; + return major > 1 || (major == 1 && minor >= 2); +} + + +////////////////////// +// wxZlibOutputStream +////////////////////// + +wxZlibOutputStream::wxZlibOutputStream(wxOutputStream& stream, + int level, + int flags) + : wxFilterOutputStream(stream) +{ + Init(level, flags); +} + +wxZlibOutputStream::wxZlibOutputStream(wxOutputStream *stream, + int level, + int flags) + : wxFilterOutputStream(stream) +{ + Init(level, flags); +} + +void wxZlibOutputStream::Init(int level, int flags) +{ + m_deflate = NULL; + m_z_buffer = new unsigned char[ZSTREAM_BUFFER_SIZE]; + m_z_size = ZSTREAM_BUFFER_SIZE; + m_pos = 0; + + if ( level == -1 ) + { + level = Z_DEFAULT_COMPRESSION; + } + else + { + wxASSERT_MSG(level >= 0 && level <= 9, wxT("wxZlibOutputStream compression level must be between 0 and 9!")); + } + + // if gzip is asked for but not supported... + if (flags == wxZLIB_GZIP && !CanHandleGZip()) { + wxLogError(_("Gzip not supported by this version of zlib")); + m_lasterror = wxSTREAM_WRITE_ERROR; + return; + } + + if (m_z_buffer) { + m_deflate = new z_stream_s; + + if (m_deflate) { + memset(m_deflate, 0, sizeof(z_stream_s)); + m_deflate->next_out = m_z_buffer; + m_deflate->avail_out = m_z_size; + + // see zlib.h for documentation on windowBits + int windowBits = MAX_WBITS; + switch (flags) { + case wxZLIB_NO_HEADER: windowBits = -MAX_WBITS; break; + case wxZLIB_ZLIB: windowBits = MAX_WBITS; break; + case wxZLIB_GZIP: windowBits = MAX_WBITS | ZSTREAM_GZIP; break; + default: wxFAIL_MSG(wxT("Invalid zlib flag")); + } + + if (deflateInit2(m_deflate, level, Z_DEFLATED, windowBits, + 8, Z_DEFAULT_STRATEGY) == Z_OK) + return; + } + } + + wxLogError(_("Can't initialize zlib deflate stream.")); + m_lasterror = wxSTREAM_WRITE_ERROR; +} + +bool wxZlibOutputStream::Close() + { + DoFlush(true); + deflateEnd(m_deflate); + delete m_deflate; + + m_deflate = NULL; + delete[] m_z_buffer; + m_z_buffer = NULL; + + return wxFilterOutputStream::Close() && IsOk(); + } + +void wxZlibOutputStream::DoFlush(bool final) +{ + if (!m_deflate || !m_z_buffer) + m_lasterror = wxSTREAM_WRITE_ERROR; + if (!IsOk()) + return; + + int err = Z_OK; + bool done = false; + + while (err == Z_OK || err == Z_STREAM_END) { + size_t len = m_z_size - m_deflate->avail_out; + if (len) { + if (m_parent_o_stream->Write(m_z_buffer, len).LastWrite() != len) { + m_lasterror = wxSTREAM_WRITE_ERROR; + wxLogDebug(wxT("wxZlibOutputStream: Error writing to underlying stream")); + break; + } + m_deflate->next_out = m_z_buffer; + m_deflate->avail_out = m_z_size; + } + + if (done) + break; + err = deflate(m_deflate, final ? Z_FINISH : Z_FULL_FLUSH); + done = m_deflate->avail_out != 0 || err == Z_STREAM_END; + } +} + +size_t wxZlibOutputStream::OnSysWrite(const void *buffer, size_t size) +{ + wxASSERT_MSG(m_deflate && m_z_buffer, wxT("Deflate stream not open")); + + if (!m_deflate || !m_z_buffer) + { + // notice that this will make IsOk() test just below return false + m_lasterror = wxSTREAM_WRITE_ERROR; + } + + if (!IsOk() || !size) + return 0; + + int err = Z_OK; + m_deflate->next_in = (unsigned char *)buffer; + m_deflate->avail_in = size; + + while (err == Z_OK && m_deflate->avail_in > 0) { + if (m_deflate->avail_out == 0) { + m_parent_o_stream->Write(m_z_buffer, m_z_size); + if (m_parent_o_stream->LastWrite() != m_z_size) { + m_lasterror = wxSTREAM_WRITE_ERROR; + wxLogDebug(wxT("wxZlibOutputStream: Error writing to underlying stream")); + break; + } + + m_deflate->next_out = m_z_buffer; + m_deflate->avail_out = m_z_size; + } + + err = deflate(m_deflate, Z_NO_FLUSH); + } + + if (err != Z_OK) { + m_lasterror = wxSTREAM_WRITE_ERROR; + wxString msg(m_deflate->msg, *wxConvCurrent); + if (!msg) + msg = wxString::Format(_("zlib error %d"), err); + wxLogError(_("Can't write to deflate stream: %s"), msg.c_str()); + } + + size -= m_deflate->avail_in; + m_pos += size; + return size; +} + +/* static */ bool wxZlibOutputStream::CanHandleGZip() +{ + return wxZlibInputStream::CanHandleGZip(); +} + +#endif + // wxUSE_ZLIB && wxUSE_STREAMS diff --git a/Externals/wxWidgets/src/generic/aboutdlgg.cpp b/Externals/wxWidgets/src/generic/aboutdlgg.cpp index e5e5535839..5185af8d6e 100644 --- a/Externals/wxWidgets/src/generic/aboutdlgg.cpp +++ b/Externals/wxWidgets/src/generic/aboutdlgg.cpp @@ -1,245 +1,245 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: src/generic/aboutdlgg.cpp -// Purpose: implements wxGenericAboutBox() function -// Author: Vadim Zeitlin -// Created: 2006-10-08 -// RCS-ID: $Id: aboutdlgg.cpp 49560 2007-10-31 16:08:18Z VZ $ -// Copyright: (c) 2006 Vadim Zeitlin -// Licence: wxWindows licence -/////////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// for compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_ABOUTDLG - -#ifndef WX_PRECOMP - #include "wx/sizer.h" - #include "wx/statbmp.h" - #include "wx/stattext.h" - #include "wx/button.h" -#endif //WX_PRECOMP - -#include "wx/aboutdlg.h" -#include "wx/generic/aboutdlgg.h" - -#include "wx/hyperlink.h" -#include "wx/collpane.h" - -// ============================================================================ -// implementation -// ============================================================================ - -// helper function: returns all array elements in a single comma-separated and -// newline-terminated string -static wxString AllAsString(const wxArrayString& a) -{ - wxString s; - const size_t count = a.size(); - s.reserve(20*count); - for ( size_t n = 0; n < count; n++ ) - { - s << a[n] << (n == count - 1 ? _T("\n") : _T(", ")); - } - - return s; -} - -// ---------------------------------------------------------------------------- -// wxAboutDialogInfo -// ---------------------------------------------------------------------------- - -wxString wxAboutDialogInfo::GetDescriptionAndCredits() const -{ - wxString s = GetDescription(); - if ( !s.empty() ) - s << _T('\n'); - - if ( HasDevelopers() ) - s << _T('\n') << _("Developed by ") << AllAsString(GetDevelopers()); - - if ( HasDocWriters() ) - s << _T('\n') << _("Documentation by ") << AllAsString(GetDocWriters()); - - if ( HasArtists() ) - s << _T('\n') << _("Graphics art by ") << AllAsString(GetArtists()); - - if ( HasTranslators() ) - s << _T('\n') << _("Translations by ") << AllAsString(GetTranslators()); - - return s; -} - -wxIcon wxAboutDialogInfo::GetIcon() const -{ - wxIcon icon = m_icon; - if ( !icon.Ok() && wxTheApp ) - { - const wxTopLevelWindow * const - tlw = wxDynamicCast(wxTheApp->GetTopWindow(), wxTopLevelWindow); - if ( tlw ) - icon = tlw->GetIcon(); - } - - return icon; -} - -// ---------------------------------------------------------------------------- -// wxGenericAboutDialog -// ---------------------------------------------------------------------------- - -bool wxGenericAboutDialog::Create(const wxAboutDialogInfo& info) -{ - // TODO: should we use main frame as parent by default here? - if ( !wxDialog::Create(NULL, wxID_ANY, _("About ") + info.GetName(), - wxDefaultPosition, wxDefaultSize, wxRESIZE_BORDER|wxDEFAULT_DIALOG_STYLE) ) - return false; - - m_sizerText = new wxBoxSizer(wxVERTICAL); - wxString nameAndVersion = info.GetName(); - if ( info.HasVersion() ) - nameAndVersion << _T(' ') << info.GetVersion(); - wxStaticText *label = new wxStaticText(this, wxID_ANY, nameAndVersion); - wxFont fontBig(*wxNORMAL_FONT); - fontBig.SetPointSize(fontBig.GetPointSize() + 2); - fontBig.SetWeight(wxFONTWEIGHT_BOLD); - label->SetFont(fontBig); - - m_sizerText->Add(label, wxSizerFlags().Centre().Border()); - m_sizerText->AddSpacer(5); - - AddText(info.GetCopyright()); - AddText(info.GetDescription()); - - if ( info.HasWebSite() ) - { -#if wxUSE_HYPERLINKCTRL - AddControl(new wxHyperlinkCtrl(this, wxID_ANY, - info.GetWebSiteDescription(), - info.GetWebSiteURL())); -#else - AddText(info.GetWebSiteURL()); -#endif // wxUSE_HYPERLINKCTRL/!wxUSE_HYPERLINKCTRL - } - -#if wxUSE_COLLPANE - if ( info.HasLicence() ) - AddCollapsiblePane(_("License"), info.GetLicence()); - - if ( info.HasDevelopers() ) - AddCollapsiblePane(_("Developers"), - AllAsString(info.GetDevelopers())); - - if ( info.HasDocWriters() ) - AddCollapsiblePane(_("Documentation writers"), - AllAsString(info.GetDocWriters())); - - if ( info.HasArtists() ) - AddCollapsiblePane(_("Artists"), - AllAsString(info.GetArtists())); - - if ( info.HasTranslators() ) - AddCollapsiblePane(_("Translators"), - AllAsString(info.GetTranslators())); -#endif // wxUSE_COLLPANE - - DoAddCustomControls(); - - - wxSizer *sizerIconAndText = new wxBoxSizer(wxHORIZONTAL); -#if wxUSE_STATBMP - wxIcon icon = info.GetIcon(); - if ( icon.Ok() ) - { - sizerIconAndText->Add(new wxStaticBitmap(this, wxID_ANY, icon), - wxSizerFlags().Border(wxRIGHT)); - } -#endif // wxUSE_STATBMP - sizerIconAndText->Add(m_sizerText, wxSizerFlags(1).Expand()); - - wxSizer *sizerTop = new wxBoxSizer(wxVERTICAL); - sizerTop->Add(sizerIconAndText, wxSizerFlags(1).Expand().Border()); - - wxSizer *sizerBtns = CreateButtonSizer(wxOK); - if ( sizerBtns ) - { - sizerTop->Add(sizerBtns, wxSizerFlags().Expand().Border()); - } - - SetSizerAndFit(sizerTop); - - CentreOnScreen(); - - return true; -} - -void wxGenericAboutDialog::AddControl(wxWindow *win, const wxSizerFlags& flags) -{ - wxCHECK_RET( m_sizerText, _T("can only be called after Create()") ); - wxASSERT_MSG( win, _T("can't add NULL window to about dialog") ); - - m_sizerText->Add(win, flags); -} - -void wxGenericAboutDialog::AddControl(wxWindow *win) -{ - AddControl(win, wxSizerFlags().Border(wxDOWN).Centre()); -} - -void wxGenericAboutDialog::AddText(const wxString& text) -{ - if ( !text.empty() ) - AddControl(new wxStaticText(this, wxID_ANY, text)); -} - -void wxGenericAboutDialog::AddCollapsiblePane(const wxString& title, - const wxString& text) -{ - wxCollapsiblePane *pane = new wxCollapsiblePane(this, wxID_ANY, title); - wxStaticText *txt = new wxStaticText(pane->GetPane(), wxID_ANY, text, - wxDefaultPosition, wxDefaultSize, - wxALIGN_CENTRE); - - // don't make the text unreasonably wide - static const int maxWidth = wxGetDisplaySize().x/3; - txt->Wrap(maxWidth); - - // NB: all the wxCollapsiblePanes must be added with a null proportion value - m_sizerText->Add(pane, wxSizerFlags(0).Expand().Border(wxBOTTOM)); -} - -// ---------------------------------------------------------------------------- -// public functions -// ---------------------------------------------------------------------------- - -void wxGenericAboutBox(const wxAboutDialogInfo& info) -{ - wxGenericAboutDialog dlg(info); - dlg.ShowModal(); -} - -// currently wxAboutBox is implemented natively only under these platforms, for -// the others we provide a generic fallback here -#if !defined(__WXMSW__) && !defined(__WXMAC__) && !defined(__WXGTK26__) - -void wxAboutBox(const wxAboutDialogInfo& info) -{ - wxGenericAboutBox(info); -} - -#endif // platforms without native about dialog - - -#endif // wxUSE_ABOUTDLG +/////////////////////////////////////////////////////////////////////////////// +// Name: src/generic/aboutdlgg.cpp +// Purpose: implements wxGenericAboutBox() function +// Author: Vadim Zeitlin +// Created: 2006-10-08 +// RCS-ID: $Id: aboutdlgg.cpp 49560 2007-10-31 16:08:18Z VZ $ +// Copyright: (c) 2006 Vadim Zeitlin +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// for compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_ABOUTDLG + +#ifndef WX_PRECOMP + #include "wx/sizer.h" + #include "wx/statbmp.h" + #include "wx/stattext.h" + #include "wx/button.h" +#endif //WX_PRECOMP + +#include "wx/aboutdlg.h" +#include "wx/generic/aboutdlgg.h" + +#include "wx/hyperlink.h" +#include "wx/collpane.h" + +// ============================================================================ +// implementation +// ============================================================================ + +// helper function: returns all array elements in a single comma-separated and +// newline-terminated string +static wxString AllAsString(const wxArrayString& a) +{ + wxString s; + const size_t count = a.size(); + s.reserve(20*count); + for ( size_t n = 0; n < count; n++ ) + { + s << a[n] << (n == count - 1 ? _T("\n") : _T(", ")); + } + + return s; +} + +// ---------------------------------------------------------------------------- +// wxAboutDialogInfo +// ---------------------------------------------------------------------------- + +wxString wxAboutDialogInfo::GetDescriptionAndCredits() const +{ + wxString s = GetDescription(); + if ( !s.empty() ) + s << _T('\n'); + + if ( HasDevelopers() ) + s << _T('\n') << _("Developed by ") << AllAsString(GetDevelopers()); + + if ( HasDocWriters() ) + s << _T('\n') << _("Documentation by ") << AllAsString(GetDocWriters()); + + if ( HasArtists() ) + s << _T('\n') << _("Graphics art by ") << AllAsString(GetArtists()); + + if ( HasTranslators() ) + s << _T('\n') << _("Translations by ") << AllAsString(GetTranslators()); + + return s; +} + +wxIcon wxAboutDialogInfo::GetIcon() const +{ + wxIcon icon = m_icon; + if ( !icon.Ok() && wxTheApp ) + { + const wxTopLevelWindow * const + tlw = wxDynamicCast(wxTheApp->GetTopWindow(), wxTopLevelWindow); + if ( tlw ) + icon = tlw->GetIcon(); + } + + return icon; +} + +// ---------------------------------------------------------------------------- +// wxGenericAboutDialog +// ---------------------------------------------------------------------------- + +bool wxGenericAboutDialog::Create(const wxAboutDialogInfo& info) +{ + // TODO: should we use main frame as parent by default here? + if ( !wxDialog::Create(NULL, wxID_ANY, _("About ") + info.GetName(), + wxDefaultPosition, wxDefaultSize, wxRESIZE_BORDER|wxDEFAULT_DIALOG_STYLE) ) + return false; + + m_sizerText = new wxBoxSizer(wxVERTICAL); + wxString nameAndVersion = info.GetName(); + if ( info.HasVersion() ) + nameAndVersion << _T(' ') << info.GetVersion(); + wxStaticText *label = new wxStaticText(this, wxID_ANY, nameAndVersion); + wxFont fontBig(*wxNORMAL_FONT); + fontBig.SetPointSize(fontBig.GetPointSize() + 2); + fontBig.SetWeight(wxFONTWEIGHT_BOLD); + label->SetFont(fontBig); + + m_sizerText->Add(label, wxSizerFlags().Centre().Border()); + m_sizerText->AddSpacer(5); + + AddText(info.GetCopyright()); + AddText(info.GetDescription()); + + if ( info.HasWebSite() ) + { +#if wxUSE_HYPERLINKCTRL + AddControl(new wxHyperlinkCtrl(this, wxID_ANY, + info.GetWebSiteDescription(), + info.GetWebSiteURL())); +#else + AddText(info.GetWebSiteURL()); +#endif // wxUSE_HYPERLINKCTRL/!wxUSE_HYPERLINKCTRL + } + +#if wxUSE_COLLPANE + if ( info.HasLicence() ) + AddCollapsiblePane(_("License"), info.GetLicence()); + + if ( info.HasDevelopers() ) + AddCollapsiblePane(_("Developers"), + AllAsString(info.GetDevelopers())); + + if ( info.HasDocWriters() ) + AddCollapsiblePane(_("Documentation writers"), + AllAsString(info.GetDocWriters())); + + if ( info.HasArtists() ) + AddCollapsiblePane(_("Artists"), + AllAsString(info.GetArtists())); + + if ( info.HasTranslators() ) + AddCollapsiblePane(_("Translators"), + AllAsString(info.GetTranslators())); +#endif // wxUSE_COLLPANE + + DoAddCustomControls(); + + + wxSizer *sizerIconAndText = new wxBoxSizer(wxHORIZONTAL); +#if wxUSE_STATBMP + wxIcon icon = info.GetIcon(); + if ( icon.Ok() ) + { + sizerIconAndText->Add(new wxStaticBitmap(this, wxID_ANY, icon), + wxSizerFlags().Border(wxRIGHT)); + } +#endif // wxUSE_STATBMP + sizerIconAndText->Add(m_sizerText, wxSizerFlags(1).Expand()); + + wxSizer *sizerTop = new wxBoxSizer(wxVERTICAL); + sizerTop->Add(sizerIconAndText, wxSizerFlags(1).Expand().Border()); + + wxSizer *sizerBtns = CreateButtonSizer(wxOK); + if ( sizerBtns ) + { + sizerTop->Add(sizerBtns, wxSizerFlags().Expand().Border()); + } + + SetSizerAndFit(sizerTop); + + CentreOnScreen(); + + return true; +} + +void wxGenericAboutDialog::AddControl(wxWindow *win, const wxSizerFlags& flags) +{ + wxCHECK_RET( m_sizerText, _T("can only be called after Create()") ); + wxASSERT_MSG( win, _T("can't add NULL window to about dialog") ); + + m_sizerText->Add(win, flags); +} + +void wxGenericAboutDialog::AddControl(wxWindow *win) +{ + AddControl(win, wxSizerFlags().Border(wxDOWN).Centre()); +} + +void wxGenericAboutDialog::AddText(const wxString& text) +{ + if ( !text.empty() ) + AddControl(new wxStaticText(this, wxID_ANY, text)); +} + +void wxGenericAboutDialog::AddCollapsiblePane(const wxString& title, + const wxString& text) +{ + wxCollapsiblePane *pane = new wxCollapsiblePane(this, wxID_ANY, title); + wxStaticText *txt = new wxStaticText(pane->GetPane(), wxID_ANY, text, + wxDefaultPosition, wxDefaultSize, + wxALIGN_CENTRE); + + // don't make the text unreasonably wide + static const int maxWidth = wxGetDisplaySize().x/3; + txt->Wrap(maxWidth); + + // NB: all the wxCollapsiblePanes must be added with a null proportion value + m_sizerText->Add(pane, wxSizerFlags(0).Expand().Border(wxBOTTOM)); +} + +// ---------------------------------------------------------------------------- +// public functions +// ---------------------------------------------------------------------------- + +void wxGenericAboutBox(const wxAboutDialogInfo& info) +{ + wxGenericAboutDialog dlg(info); + dlg.ShowModal(); +} + +// currently wxAboutBox is implemented natively only under these platforms, for +// the others we provide a generic fallback here +#if !defined(__WXMSW__) && !defined(__WXMAC__) && !defined(__WXGTK26__) + +void wxAboutBox(const wxAboutDialogInfo& info) +{ + wxGenericAboutBox(info); +} + +#endif // platforms without native about dialog + + +#endif // wxUSE_ABOUTDLG diff --git a/Externals/wxWidgets/src/generic/accel.cpp b/Externals/wxWidgets/src/generic/accel.cpp index 232fa69e29..4153453444 100644 --- a/Externals/wxWidgets/src/generic/accel.cpp +++ b/Externals/wxWidgets/src/generic/accel.cpp @@ -1,220 +1,220 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: src/generic/accel.cpp -// Purpose: generic implementation of wxAcceleratorTable class -// Author: Robert Roebling -// Modified: VZ pn 31.05.01: use typed lists, Unicode cleanup, Add/Remove -// Id: $Id: accel.cpp 41751 2006-10-08 21:56:55Z VZ $ -// Copyright: (c) 1998 Robert Roebling -// Licence: wxWindows licence -/////////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_ACCEL - -#ifndef WX_PRECOMP - #include "wx/list.h" - #include "wx/event.h" -#endif // WX_PRECOMP - -#include "wx/accel.h" - -#include - -// ---------------------------------------------------------------------------- -// wxAccelList: a list of wxAcceleratorEntries -// ---------------------------------------------------------------------------- - -WX_DECLARE_LIST(wxAcceleratorEntry, wxAccelList); -#include "wx/listimpl.cpp" -WX_DEFINE_LIST(wxAccelList) - -// ---------------------------------------------------------------------------- -// wxAccelRefData: the data used by wxAcceleratorTable -// ---------------------------------------------------------------------------- - -class wxAccelRefData : public wxObjectRefData -{ -public: - wxAccelRefData() - { - } - - wxAccelRefData(const wxAccelRefData& data) - : wxObjectRefData() - { - m_accels = data.m_accels; - } - - virtual ~wxAccelRefData() - { - WX_CLEAR_LIST(wxAccelList, m_accels); - } - - wxAccelList m_accels; -}; - -// macro which can be used to access wxAccelRefData from wxAcceleratorTable -#define M_ACCELDATA ((wxAccelRefData *)m_refData) - - -// ============================================================================ -// implementation -// ============================================================================ - -// ---------------------------------------------------------------------------- -// wxAcceleratorTable ctors -// ---------------------------------------------------------------------------- - -IMPLEMENT_DYNAMIC_CLASS(wxAcceleratorTable, wxObject) - -wxAcceleratorTable::wxAcceleratorTable() -{ -} - -wxAcceleratorTable::wxAcceleratorTable(int n, const wxAcceleratorEntry entries[]) -{ - m_refData = new wxAccelRefData; - - for ( int i = 0; i < n; i++ ) - { - const wxAcceleratorEntry& entry = entries[i]; - - int keycode = entry.GetKeyCode(); - if ( isascii(keycode) ) - keycode = toupper(keycode); - - M_ACCELDATA->m_accels.Append(new wxAcceleratorEntry(entry.GetFlags(), - keycode, - entry.GetCommand())); - } -} - -wxAcceleratorTable::~wxAcceleratorTable() -{ -} - -bool wxAcceleratorTable::IsOk() const -{ - return m_refData != NULL; -} - -// ---------------------------------------------------------------------------- -// wxAcceleratorTable updating -// ---------------------------------------------------------------------------- - -void wxAcceleratorTable::Add(const wxAcceleratorEntry& entry) -{ - AllocExclusive(); - - if ( !m_refData ) - { - m_refData = new wxAccelRefData; - } - - M_ACCELDATA->m_accels.Append(new wxAcceleratorEntry(entry)); -} - -void wxAcceleratorTable::Remove(const wxAcceleratorEntry& entry) -{ - AllocExclusive(); - - wxAccelList::compatibility_iterator node = M_ACCELDATA->m_accels.GetFirst(); - while ( node ) - { - const wxAcceleratorEntry *entryCur = node->GetData(); - - // given entry contains only the information of the accelerator key - // because it was set that way during creation so do not use the - // comparison operator which also checks the command field - if ((entryCur->GetKeyCode() == entry.GetKeyCode()) && - (entryCur->GetFlags() == entry.GetFlags())) - { - delete node->GetData(); - M_ACCELDATA->m_accels.Erase(node); - - return; - } - - node = node->GetNext(); - } - - wxFAIL_MSG(_T("deleting inexistent accel from wxAcceleratorTable")); -} - -// ---------------------------------------------------------------------------- -// wxAcceleratorTable: find a command for the given key press -// ---------------------------------------------------------------------------- - -const wxAcceleratorEntry * -wxAcceleratorTable::GetEntry(const wxKeyEvent& event) const -{ - if ( !Ok() ) - { - // not an error, the accel table is just empty - return NULL; - } - - wxAccelList::compatibility_iterator node = M_ACCELDATA->m_accels.GetFirst(); - while ( node ) - { - const wxAcceleratorEntry *entry = node->GetData(); - - // is the key the same? - if ( event.m_keyCode == entry->GetKeyCode() ) - { - int flags = entry->GetFlags(); - - // now check flags - if ( (((flags & wxACCEL_CTRL) != 0) == event.ControlDown()) && - (((flags & wxACCEL_SHIFT) != 0) == event.ShiftDown()) && - (((flags & wxACCEL_ALT) != 0) == event.AltDown()) ) - { - return entry; - } - } - - node = node->GetNext(); - } - - return NULL; -} - -wxMenuItem *wxAcceleratorTable::GetMenuItem(const wxKeyEvent& event) const -{ - const wxAcceleratorEntry *entry = GetEntry(event); - - return entry ? entry->GetMenuItem() : NULL; -} - -int wxAcceleratorTable::GetCommand(const wxKeyEvent& event) const -{ - const wxAcceleratorEntry *entry = GetEntry(event); - - return entry ? entry->GetCommand() : -1; -} - -wxObjectRefData *wxAcceleratorTable::CreateRefData() const -{ - return new wxAccelRefData; -} - -wxObjectRefData *wxAcceleratorTable::CloneRefData(const wxObjectRefData *data) const -{ - return new wxAccelRefData(*(wxAccelRefData *)data); -} - -#endif // wxUSE_ACCEL +/////////////////////////////////////////////////////////////////////////////// +// Name: src/generic/accel.cpp +// Purpose: generic implementation of wxAcceleratorTable class +// Author: Robert Roebling +// Modified: VZ pn 31.05.01: use typed lists, Unicode cleanup, Add/Remove +// Id: $Id: accel.cpp 41751 2006-10-08 21:56:55Z VZ $ +// Copyright: (c) 1998 Robert Roebling +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_ACCEL + +#ifndef WX_PRECOMP + #include "wx/list.h" + #include "wx/event.h" +#endif // WX_PRECOMP + +#include "wx/accel.h" + +#include + +// ---------------------------------------------------------------------------- +// wxAccelList: a list of wxAcceleratorEntries +// ---------------------------------------------------------------------------- + +WX_DECLARE_LIST(wxAcceleratorEntry, wxAccelList); +#include "wx/listimpl.cpp" +WX_DEFINE_LIST(wxAccelList) + +// ---------------------------------------------------------------------------- +// wxAccelRefData: the data used by wxAcceleratorTable +// ---------------------------------------------------------------------------- + +class wxAccelRefData : public wxObjectRefData +{ +public: + wxAccelRefData() + { + } + + wxAccelRefData(const wxAccelRefData& data) + : wxObjectRefData() + { + m_accels = data.m_accels; + } + + virtual ~wxAccelRefData() + { + WX_CLEAR_LIST(wxAccelList, m_accels); + } + + wxAccelList m_accels; +}; + +// macro which can be used to access wxAccelRefData from wxAcceleratorTable +#define M_ACCELDATA ((wxAccelRefData *)m_refData) + + +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// wxAcceleratorTable ctors +// ---------------------------------------------------------------------------- + +IMPLEMENT_DYNAMIC_CLASS(wxAcceleratorTable, wxObject) + +wxAcceleratorTable::wxAcceleratorTable() +{ +} + +wxAcceleratorTable::wxAcceleratorTable(int n, const wxAcceleratorEntry entries[]) +{ + m_refData = new wxAccelRefData; + + for ( int i = 0; i < n; i++ ) + { + const wxAcceleratorEntry& entry = entries[i]; + + int keycode = entry.GetKeyCode(); + if ( isascii(keycode) ) + keycode = toupper(keycode); + + M_ACCELDATA->m_accels.Append(new wxAcceleratorEntry(entry.GetFlags(), + keycode, + entry.GetCommand())); + } +} + +wxAcceleratorTable::~wxAcceleratorTable() +{ +} + +bool wxAcceleratorTable::IsOk() const +{ + return m_refData != NULL; +} + +// ---------------------------------------------------------------------------- +// wxAcceleratorTable updating +// ---------------------------------------------------------------------------- + +void wxAcceleratorTable::Add(const wxAcceleratorEntry& entry) +{ + AllocExclusive(); + + if ( !m_refData ) + { + m_refData = new wxAccelRefData; + } + + M_ACCELDATA->m_accels.Append(new wxAcceleratorEntry(entry)); +} + +void wxAcceleratorTable::Remove(const wxAcceleratorEntry& entry) +{ + AllocExclusive(); + + wxAccelList::compatibility_iterator node = M_ACCELDATA->m_accels.GetFirst(); + while ( node ) + { + const wxAcceleratorEntry *entryCur = node->GetData(); + + // given entry contains only the information of the accelerator key + // because it was set that way during creation so do not use the + // comparison operator which also checks the command field + if ((entryCur->GetKeyCode() == entry.GetKeyCode()) && + (entryCur->GetFlags() == entry.GetFlags())) + { + delete node->GetData(); + M_ACCELDATA->m_accels.Erase(node); + + return; + } + + node = node->GetNext(); + } + + wxFAIL_MSG(_T("deleting inexistent accel from wxAcceleratorTable")); +} + +// ---------------------------------------------------------------------------- +// wxAcceleratorTable: find a command for the given key press +// ---------------------------------------------------------------------------- + +const wxAcceleratorEntry * +wxAcceleratorTable::GetEntry(const wxKeyEvent& event) const +{ + if ( !Ok() ) + { + // not an error, the accel table is just empty + return NULL; + } + + wxAccelList::compatibility_iterator node = M_ACCELDATA->m_accels.GetFirst(); + while ( node ) + { + const wxAcceleratorEntry *entry = node->GetData(); + + // is the key the same? + if ( event.m_keyCode == entry->GetKeyCode() ) + { + int flags = entry->GetFlags(); + + // now check flags + if ( (((flags & wxACCEL_CTRL) != 0) == event.ControlDown()) && + (((flags & wxACCEL_SHIFT) != 0) == event.ShiftDown()) && + (((flags & wxACCEL_ALT) != 0) == event.AltDown()) ) + { + return entry; + } + } + + node = node->GetNext(); + } + + return NULL; +} + +wxMenuItem *wxAcceleratorTable::GetMenuItem(const wxKeyEvent& event) const +{ + const wxAcceleratorEntry *entry = GetEntry(event); + + return entry ? entry->GetMenuItem() : NULL; +} + +int wxAcceleratorTable::GetCommand(const wxKeyEvent& event) const +{ + const wxAcceleratorEntry *entry = GetEntry(event); + + return entry ? entry->GetCommand() : -1; +} + +wxObjectRefData *wxAcceleratorTable::CreateRefData() const +{ + return new wxAccelRefData; +} + +wxObjectRefData *wxAcceleratorTable::CloneRefData(const wxObjectRefData *data) const +{ + return new wxAccelRefData(*(wxAccelRefData *)data); +} + +#endif // wxUSE_ACCEL diff --git a/Externals/wxWidgets/src/generic/animateg.cpp b/Externals/wxWidgets/src/generic/animateg.cpp index 83ec4a7eab..9f4447a622 100644 --- a/Externals/wxWidgets/src/generic/animateg.cpp +++ b/Externals/wxWidgets/src/generic/animateg.cpp @@ -1,690 +1,690 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: animateg.cpp -// Purpose: wxAnimation and wxAnimationCtrl -// Author: Julian Smart and Guillermo Rodriguez Garcia -// Modified by: Francesco Montorsi -// Created: 13/8/99 -// RCS-ID: $Id: animateg.cpp 48085 2007-08-15 11:36:50Z VZ $ -// Copyright: (c) Julian Smart and Guillermo Rodriguez Garcia -// Licence: wxWindows licence -/////////////////////////////////////////////////////////////////////////////// - -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif //__BORLANDC__ - -#if wxUSE_ANIMATIONCTRL && (!defined(__WXGTK20__) || defined(__WXUNIVERSAL__)) - -#include "wx/animate.h" - -#ifndef WX_PRECOMP - #include "wx/log.h" - #include "wx/image.h" - #include "wx/dcmemory.h" - #include "wx/dcclient.h" - #include "wx/module.h" -#endif - -#include "wx/wfstream.h" -#include "wx/gifdecod.h" -#include "wx/anidecod.h" - -#include "wx/listimpl.cpp" -WX_DEFINE_LIST(wxAnimationDecoderList) - -wxAnimationDecoderList wxAnimation::sm_handlers; - - -// ---------------------------------------------------------------------------- -// wxAnimation -// ---------------------------------------------------------------------------- - -IMPLEMENT_DYNAMIC_CLASS(wxAnimation, wxAnimationBase) -#define M_ANIMDATA wx_static_cast(wxAnimationDecoder*, m_refData) - -wxSize wxAnimation::GetSize() const -{ - wxCHECK_MSG( IsOk(), wxDefaultSize, wxT("invalid animation") ); - - return M_ANIMDATA->GetAnimationSize(); -} - -unsigned int wxAnimation::GetFrameCount() const -{ - wxCHECK_MSG( IsOk(), 0, wxT("invalid animation") ); - - return M_ANIMDATA->GetFrameCount(); -} - -wxImage wxAnimation::GetFrame(unsigned int i) const -{ - wxCHECK_MSG( IsOk(), wxNullImage, wxT("invalid animation") ); - - wxImage ret; - if (!M_ANIMDATA->ConvertToImage(i, &ret)) - return wxNullImage; - return ret; -} - -int wxAnimation::GetDelay(unsigned int i) const -{ - wxCHECK_MSG( IsOk(), 0, wxT("invalid animation") ); - - return M_ANIMDATA->GetDelay(i); -} - -wxPoint wxAnimation::GetFramePosition(unsigned int frame) const -{ - wxCHECK_MSG( IsOk(), wxDefaultPosition, wxT("invalid animation") ); - - return M_ANIMDATA->GetFramePosition(frame); -} - -wxSize wxAnimation::GetFrameSize(unsigned int frame) const -{ - wxCHECK_MSG( IsOk(), wxDefaultSize, wxT("invalid animation") ); - - return M_ANIMDATA->GetFrameSize(frame); -} - -wxAnimationDisposal wxAnimation::GetDisposalMethod(unsigned int frame) const -{ - wxCHECK_MSG( IsOk(), wxANIM_UNSPECIFIED, wxT("invalid animation") ); - - return M_ANIMDATA->GetDisposalMethod(frame); -} - -wxColour wxAnimation::GetTransparentColour(unsigned int frame) const -{ - wxCHECK_MSG( IsOk(), wxNullColour, wxT("invalid animation") ); - - return M_ANIMDATA->GetTransparentColour(frame); -} - -wxColour wxAnimation::GetBackgroundColour() const -{ - wxCHECK_MSG( IsOk(), wxNullColour, wxT("invalid animation") ); - - return M_ANIMDATA->GetBackgroundColour(); -} - -bool wxAnimation::LoadFile(const wxString& filename, wxAnimationType type) -{ - wxFileInputStream stream(filename); - if ( !stream.IsOk() ) - return false; - - return Load(stream, type); -} - -bool wxAnimation::Load(wxInputStream &stream, wxAnimationType type) -{ - UnRef(); - - const wxAnimationDecoder *handler; - if ( type == wxANIMATION_TYPE_ANY ) - { - for ( wxAnimationDecoderList::compatibility_iterator node = sm_handlers.GetFirst(); - node; node = node->GetNext() ) - { - handler=(const wxAnimationDecoder*)node->GetData(); - - if ( handler->CanRead(stream) ) - { - // do a copy of the handler from the static list which we will own - // as our reference data - m_refData = handler->Clone(); - return M_ANIMDATA->Load(stream); - } - - } - - wxLogWarning( _("No handler found for animation type.") ); - return false; - } - - handler = FindHandler(type); - - // do a copy of the handler from the static list which we will own - // as our reference data - m_refData = handler->Clone(); - - if (handler == NULL) - { - wxLogWarning( _("No animation handler for type %ld defined."), type ); - - return false; - } - - if (stream.IsSeekable() && !M_ANIMDATA->CanRead(stream)) - { - wxLogError(_("Animation file is not of type %ld."), type); - return false; - } - else - return M_ANIMDATA->Load(stream); -} - - -// ---------------------------------------------------------------------------- -// animation decoders -// ---------------------------------------------------------------------------- - -void wxAnimation::AddHandler( wxAnimationDecoder *handler ) -{ - // Check for an existing handler of the type being added. - if (FindHandler( handler->GetType() ) == 0) - { - sm_handlers.Append( handler ); - } - else - { - // This is not documented behaviour, merely the simplest 'fix' - // for preventing duplicate additions. If someone ever has - // a good reason to add and remove duplicate handlers (and they - // may) we should probably refcount the duplicates. - - wxLogDebug( _T("Adding duplicate animation handler for '%d' type"), - handler->GetType() ); - delete handler; - } -} - -void wxAnimation::InsertHandler( wxAnimationDecoder *handler ) -{ - // Check for an existing handler of the type being added. - if (FindHandler( handler->GetType() ) == 0) - { - sm_handlers.Insert( handler ); - } - else - { - // see AddHandler for additional comments. - wxLogDebug( _T("Inserting duplicate animation handler for '%d' type"), - handler->GetType() ); - delete handler; - } -} - -const wxAnimationDecoder *wxAnimation::FindHandler( wxAnimationType animType ) -{ - wxAnimationDecoderList::compatibility_iterator node = sm_handlers.GetFirst(); - while (node) - { - const wxAnimationDecoder *handler = (const wxAnimationDecoder *)node->GetData(); - if (handler->GetType() == animType) return handler; - node = node->GetNext(); - } - return 0; -} - -void wxAnimation::InitStandardHandlers() -{ -#if wxUSE_GIF - AddHandler(new wxGIFDecoder); -#endif // wxUSE_GIF -#if wxUSE_ICO_CUR - AddHandler(new wxANIDecoder); -#endif // wxUSE_ICO_CUR -} - -void wxAnimation::CleanUpHandlers() -{ - wxAnimationDecoderList::compatibility_iterator node = sm_handlers.GetFirst(); - while (node) - { - wxAnimationDecoder *handler = (wxAnimationDecoder *)node->GetData(); - wxAnimationDecoderList::compatibility_iterator next = node->GetNext(); - delete handler; - node = next; - } - - sm_handlers.Clear(); -} - - -// A module to allow wxAnimation initialization/cleanup -// without calling these functions from app.cpp or from -// the user's application. - -class wxAnimationModule: public wxModule -{ -DECLARE_DYNAMIC_CLASS(wxAnimationModule) -public: - wxAnimationModule() {} - bool OnInit() { wxAnimation::InitStandardHandlers(); return true; } - void OnExit() { wxAnimation::CleanUpHandlers(); } -}; - -IMPLEMENT_DYNAMIC_CLASS(wxAnimationModule, wxModule) - - -// ---------------------------------------------------------------------------- -// wxAnimationCtrl -// ---------------------------------------------------------------------------- - -IMPLEMENT_CLASS(wxAnimationCtrl, wxAnimationCtrlBase) -BEGIN_EVENT_TABLE(wxAnimationCtrl, wxAnimationCtrlBase) - EVT_PAINT(wxAnimationCtrl::OnPaint) - EVT_SIZE(wxAnimationCtrl::OnSize) - EVT_TIMER(wxID_ANY, wxAnimationCtrl::OnTimer) -END_EVENT_TABLE() - -void wxAnimationCtrl::Init() -{ - m_currentFrame = 0; - m_looped = false; - m_isPlaying = false; - - // use the window background colour by default to be consistent - // with the GTK+ native version - m_useWinBackgroundColour = true; -} - -bool wxAnimationCtrl::Create(wxWindow *parent, wxWindowID id, - const wxAnimation& animation, const wxPoint& pos, - const wxSize& size, long style, const wxString& name) -{ - m_timer.SetOwner(this); - - if (!base_type::Create(parent, id, pos, size, style, wxDefaultValidator, name)) - return false; - - // by default we get the same background colour of our parent - SetBackgroundColour(parent->GetBackgroundColour()); - - SetAnimation(animation); - - return true; -} - -wxAnimationCtrl::~wxAnimationCtrl() -{ - Stop(); -} - -bool wxAnimationCtrl::LoadFile(const wxString& filename, wxAnimationType type) -{ - wxAnimation anim; - if (!anim.LoadFile(filename, type) || - !anim.IsOk()) - return false; - - SetAnimation(anim); - return true; -} - -wxSize wxAnimationCtrl::DoGetBestSize() const -{ - if (m_animation.IsOk() && !this->HasFlag(wxAC_NO_AUTORESIZE)) - return m_animation.GetSize(); - - return wxSize(100, 100); -} - -void wxAnimationCtrl::SetAnimation(const wxAnimation& animation) -{ - if (IsPlaying()) - Stop(); - - // set new animation even if it's wxNullAnimation - m_animation = animation; - if (!m_animation.IsOk()) - { - DisplayStaticImage(); - return; - } - - if (m_animation.GetBackgroundColour() == wxNullColour) - SetUseWindowBackgroundColour(); - if (!this->HasFlag(wxAC_NO_AUTORESIZE)) - FitToAnimation(); - - DisplayStaticImage(); -} - -void wxAnimationCtrl::SetInactiveBitmap(const wxBitmap &bmp) -{ - // if the bitmap has an associated mask, we need to set our background to - // the colour of our parent otherwise when calling DrawCurrentFrame() - // (which uses the bitmap's mask), our background colour would be used for - // transparent areas - and that's not what we want (at least for - // consistency with the GTK version) - if ( bmp.GetMask() != NULL && GetParent() != NULL ) - SetBackgroundColour(GetParent()->GetBackgroundColour()); - - wxAnimationCtrlBase::SetInactiveBitmap(bmp); -} - -void wxAnimationCtrl::FitToAnimation() -{ - SetSize(m_animation.GetSize()); -} - -bool wxAnimationCtrl::SetBackgroundColour(const wxColour& colour) -{ - if ( !wxWindow::SetBackgroundColour(colour) ) - return false; - - // if not playing, then this change must be seen immediately (unless - // there's an inactive bitmap set which has higher priority than bg colour) - if ( !IsPlaying() ) - DisplayStaticImage(); - - return true; -} - - -// ---------------------------------------------------------------------------- -// wxAnimationCtrl - stop/play methods -// ---------------------------------------------------------------------------- - -void wxAnimationCtrl::Stop() -{ - m_timer.Stop(); - m_isPlaying = false; - - // reset frame counter - m_currentFrame = 0; - - DisplayStaticImage(); -} - -bool wxAnimationCtrl::Play(bool looped) -{ - if (!m_animation.IsOk()) - return false; - - m_looped = looped; - m_currentFrame = 0; - - if (!RebuildBackingStoreUpToFrame(0)) - return false; - - m_isPlaying = true; - - // do a ClearBackground() to avoid that e.g. the custom static bitmap which - // was eventually shown previously remains partially drawn - ClearBackground(); - - // DrawCurrentFrame() will use our updated backing store - wxClientDC clientDC(this); - DrawCurrentFrame(clientDC); - - // start the timer - int delay = m_animation.GetDelay(0); - if (delay == 0) - delay = 1; // 0 is invalid timeout for wxTimer. - m_timer.Start(delay, true); - - return true; -} - - - -// ---------------------------------------------------------------------------- -// wxAnimationCtrl - rendering methods -// ---------------------------------------------------------------------------- - -bool wxAnimationCtrl::RebuildBackingStoreUpToFrame(unsigned int frame) -{ - // if we've not created the backing store yet or it's too - // small, then recreate it - wxSize sz = m_animation.GetSize(), - winsz = GetClientSize(); - int w = wxMin(sz.GetWidth(), winsz.GetWidth()); - int h = wxMin(sz.GetHeight(), winsz.GetHeight()); - - if ( !m_backingStore.IsOk() || - m_backingStore.GetWidth() < w || m_backingStore.GetHeight() < h ) - { - if (!m_backingStore.Create(w, h)) - return false; - } - - wxMemoryDC dc; - dc.SelectObject(m_backingStore); - - // Draw the background - DisposeToBackground(dc); - - // Draw all intermediate frames that haven't been removed from the animation - for (unsigned int i = 0; i < frame; i++) - { - if (m_animation.GetDisposalMethod(i) == wxANIM_DONOTREMOVE || - m_animation.GetDisposalMethod(i) == wxANIM_UNSPECIFIED) - { - DrawFrame(dc, i); - } - else if (m_animation.GetDisposalMethod(i) == wxANIM_TOBACKGROUND) - DisposeToBackground(dc, m_animation.GetFramePosition(i), - m_animation.GetFrameSize(i)); - } - - // finally draw this frame - DrawFrame(dc, frame); - dc.SelectObject(wxNullBitmap); - - return true; -} - -void wxAnimationCtrl::IncrementalUpdateBackingStore() -{ - wxMemoryDC dc; - dc.SelectObject(m_backingStore); - - // OPTIMIZATION: - // since wxAnimationCtrl can only play animations forward, without skipping - // frames, we can be sure that m_backingStore contains the m_currentFrame-1 - // frame and thus we just need to dispose the m_currentFrame-1 frame and - // render the m_currentFrame-th one. - - if (m_currentFrame == 0) - { - // before drawing the first frame always dispose to bg colour - DisposeToBackground(dc); - } - else - { - switch (m_animation.GetDisposalMethod(m_currentFrame-1)) - { - case wxANIM_TOBACKGROUND: - DisposeToBackground(dc, m_animation.GetFramePosition(m_currentFrame-1), - m_animation.GetFrameSize(m_currentFrame-1)); - break; - - case wxANIM_TOPREVIOUS: - // this disposal should never be used too often. - // E.g. GIF specification explicitely say to keep the usage of this - // disposal limited to the minimum. - // In fact it may require a lot of time to restore - if (m_currentFrame == 1) - { - // if 0-th frame disposal is to restore to previous frame, - // the best we can do is to restore to background - DisposeToBackground(dc); - } - else - if (!RebuildBackingStoreUpToFrame(m_currentFrame-2)) - Stop(); - break; - - case wxANIM_DONOTREMOVE: - case wxANIM_UNSPECIFIED: - break; - } - } - - // now just draw the current frame on the top of the backing store - DrawFrame(dc, m_currentFrame); - dc.SelectObject(wxNullBitmap); -} - -void wxAnimationCtrl::DisplayStaticImage() -{ - wxASSERT(!IsPlaying()); - - // m_bmpStaticReal will be updated only if necessary... - UpdateStaticImage(); - - if (m_bmpStaticReal.IsOk()) - { - // copy the inactive bitmap in the backing store - // eventually using the mask if the static bitmap has one - if ( m_bmpStaticReal.GetMask() ) - { - wxMemoryDC temp; - temp.SelectObject(m_backingStore); - DisposeToBackground(temp); - temp.DrawBitmap(m_bmpStaticReal, 0, 0, true /* use mask */); - } - else - m_backingStore = m_bmpStaticReal; - } - else - { - // put in the backing store the first frame of the animation - if (!m_animation.IsOk() || - !RebuildBackingStoreUpToFrame(0)) - { - m_animation = wxNullAnimation; - DisposeToBackground(); - } - } - - Refresh(); -} - -void wxAnimationCtrl::DrawFrame(wxDC &dc, unsigned int frame) -{ - // PERFORMANCE NOTE: - // this draw stuff is not as fast as possible: the wxAnimationDecoder - // needs first to convert from its internal format to wxImage RGB24; - // the wxImage is then converted as a wxBitmap and finally blitted. - // If wxAnimationDecoder had a function to convert directly from its - // internal format to a port-specific wxBitmap, it would be somewhat faster. - wxBitmap bmp(m_animation.GetFrame(frame)); - dc.DrawBitmap(bmp, m_animation.GetFramePosition(frame), - true /* use mask */); -} - -void wxAnimationCtrl::DrawCurrentFrame(wxDC& dc) -{ - wxASSERT( m_backingStore.IsOk() ); - - // m_backingStore always contains the current frame - dc.DrawBitmap(m_backingStore, 0, 0, true /* use mask in case it's present */); -} - -void wxAnimationCtrl::DisposeToBackground() -{ - // clear the backing store - wxMemoryDC dc; - dc.SelectObject(m_backingStore); - if ( dc.IsOk() ) - DisposeToBackground(dc); -} - -void wxAnimationCtrl::DisposeToBackground(wxDC& dc) -{ - wxColour col = IsUsingWindowBackgroundColour() - ? GetBackgroundColour() - : m_animation.GetBackgroundColour(); - - wxBrush brush(col); - dc.SetBackground(brush); - dc.Clear(); -} - -void wxAnimationCtrl::DisposeToBackground(wxDC& dc, const wxPoint &pos, const wxSize &sz) -{ - wxColour col = IsUsingWindowBackgroundColour() - ? GetBackgroundColour() - : m_animation.GetBackgroundColour(); - wxBrush brush(col); - dc.SetBrush(brush); // SetBrush and not SetBackground !! - dc.SetPen(*wxTRANSPARENT_PEN); - dc.DrawRectangle(pos, sz); -} - -// ---------------------------------------------------------------------------- -// wxAnimationCtrl - event handlers -// ---------------------------------------------------------------------------- - -void wxAnimationCtrl::OnPaint(wxPaintEvent& WXUNUSED(event)) -{ - // VERY IMPORTANT: the wxPaintDC *must* be created in any case - wxPaintDC dc(this); - - if ( m_backingStore.IsOk() ) - { - // NOTE: we draw the bitmap explicitely ignoring the mask (if any); - // i.e. we don't want to combine the backing store with the - // possibly wrong preexisting contents of the window! - dc.DrawBitmap(m_backingStore, 0, 0, false /* no mask */); - } - else - { - // m_animation is not valid and thus we don't have a valid backing store... - // clear then our area to the background colour - DisposeToBackground(dc); - } -} - -void wxAnimationCtrl::OnTimer(wxTimerEvent &WXUNUSED(event)) -{ - m_currentFrame++; - if (m_currentFrame == m_animation.GetFrameCount()) - { - // Should a non-looped animation display the last frame? - if (!m_looped) - { - Stop(); - return; - } - else - m_currentFrame = 0; // let's restart - } - - IncrementalUpdateBackingStore(); - - wxClientDC dc(this); - DrawCurrentFrame(dc); - -#ifdef __WXMAC__ - // without this, the animation currently doesn't redraw under Mac - Refresh(); -#endif // __WXMAC__ - - // Set the timer for the next frame - int delay = m_animation.GetDelay(m_currentFrame); - if (delay == 0) - delay = 1; // 0 is invalid timeout for wxTimer. - m_timer.Start(delay, true); -} - -void wxAnimationCtrl::OnSize(wxSizeEvent &WXUNUSED(event)) -{ - // NB: resizing an animation control may take a lot of time - // for big animations as the backing store must be - // extended and rebuilt. Try to avoid it e.g. using - // a null proportion value for your wxAnimationCtrls - // when using them inside sizers. - if (m_animation.IsOk()) - { - // be careful to change the backing store *only* if we are - // playing the animation as otherwise we may be displaying - // the inactive bitmap and overwriting the backing store - // with the last played frame is wrong in this case - if (IsPlaying()) - { - if (!RebuildBackingStoreUpToFrame(m_currentFrame)) - Stop(); // in case we are playing - } - } -} - -#endif // wxUSE_ANIMATIONCTRL - +/////////////////////////////////////////////////////////////////////////////// +// Name: animateg.cpp +// Purpose: wxAnimation and wxAnimationCtrl +// Author: Julian Smart and Guillermo Rodriguez Garcia +// Modified by: Francesco Montorsi +// Created: 13/8/99 +// RCS-ID: $Id: animateg.cpp 48085 2007-08-15 11:36:50Z VZ $ +// Copyright: (c) Julian Smart and Guillermo Rodriguez Garcia +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif //__BORLANDC__ + +#if wxUSE_ANIMATIONCTRL && (!defined(__WXGTK20__) || defined(__WXUNIVERSAL__)) + +#include "wx/animate.h" + +#ifndef WX_PRECOMP + #include "wx/log.h" + #include "wx/image.h" + #include "wx/dcmemory.h" + #include "wx/dcclient.h" + #include "wx/module.h" +#endif + +#include "wx/wfstream.h" +#include "wx/gifdecod.h" +#include "wx/anidecod.h" + +#include "wx/listimpl.cpp" +WX_DEFINE_LIST(wxAnimationDecoderList) + +wxAnimationDecoderList wxAnimation::sm_handlers; + + +// ---------------------------------------------------------------------------- +// wxAnimation +// ---------------------------------------------------------------------------- + +IMPLEMENT_DYNAMIC_CLASS(wxAnimation, wxAnimationBase) +#define M_ANIMDATA wx_static_cast(wxAnimationDecoder*, m_refData) + +wxSize wxAnimation::GetSize() const +{ + wxCHECK_MSG( IsOk(), wxDefaultSize, wxT("invalid animation") ); + + return M_ANIMDATA->GetAnimationSize(); +} + +unsigned int wxAnimation::GetFrameCount() const +{ + wxCHECK_MSG( IsOk(), 0, wxT("invalid animation") ); + + return M_ANIMDATA->GetFrameCount(); +} + +wxImage wxAnimation::GetFrame(unsigned int i) const +{ + wxCHECK_MSG( IsOk(), wxNullImage, wxT("invalid animation") ); + + wxImage ret; + if (!M_ANIMDATA->ConvertToImage(i, &ret)) + return wxNullImage; + return ret; +} + +int wxAnimation::GetDelay(unsigned int i) const +{ + wxCHECK_MSG( IsOk(), 0, wxT("invalid animation") ); + + return M_ANIMDATA->GetDelay(i); +} + +wxPoint wxAnimation::GetFramePosition(unsigned int frame) const +{ + wxCHECK_MSG( IsOk(), wxDefaultPosition, wxT("invalid animation") ); + + return M_ANIMDATA->GetFramePosition(frame); +} + +wxSize wxAnimation::GetFrameSize(unsigned int frame) const +{ + wxCHECK_MSG( IsOk(), wxDefaultSize, wxT("invalid animation") ); + + return M_ANIMDATA->GetFrameSize(frame); +} + +wxAnimationDisposal wxAnimation::GetDisposalMethod(unsigned int frame) const +{ + wxCHECK_MSG( IsOk(), wxANIM_UNSPECIFIED, wxT("invalid animation") ); + + return M_ANIMDATA->GetDisposalMethod(frame); +} + +wxColour wxAnimation::GetTransparentColour(unsigned int frame) const +{ + wxCHECK_MSG( IsOk(), wxNullColour, wxT("invalid animation") ); + + return M_ANIMDATA->GetTransparentColour(frame); +} + +wxColour wxAnimation::GetBackgroundColour() const +{ + wxCHECK_MSG( IsOk(), wxNullColour, wxT("invalid animation") ); + + return M_ANIMDATA->GetBackgroundColour(); +} + +bool wxAnimation::LoadFile(const wxString& filename, wxAnimationType type) +{ + wxFileInputStream stream(filename); + if ( !stream.IsOk() ) + return false; + + return Load(stream, type); +} + +bool wxAnimation::Load(wxInputStream &stream, wxAnimationType type) +{ + UnRef(); + + const wxAnimationDecoder *handler; + if ( type == wxANIMATION_TYPE_ANY ) + { + for ( wxAnimationDecoderList::compatibility_iterator node = sm_handlers.GetFirst(); + node; node = node->GetNext() ) + { + handler=(const wxAnimationDecoder*)node->GetData(); + + if ( handler->CanRead(stream) ) + { + // do a copy of the handler from the static list which we will own + // as our reference data + m_refData = handler->Clone(); + return M_ANIMDATA->Load(stream); + } + + } + + wxLogWarning( _("No handler found for animation type.") ); + return false; + } + + handler = FindHandler(type); + + // do a copy of the handler from the static list which we will own + // as our reference data + m_refData = handler->Clone(); + + if (handler == NULL) + { + wxLogWarning( _("No animation handler for type %ld defined."), type ); + + return false; + } + + if (stream.IsSeekable() && !M_ANIMDATA->CanRead(stream)) + { + wxLogError(_("Animation file is not of type %ld."), type); + return false; + } + else + return M_ANIMDATA->Load(stream); +} + + +// ---------------------------------------------------------------------------- +// animation decoders +// ---------------------------------------------------------------------------- + +void wxAnimation::AddHandler( wxAnimationDecoder *handler ) +{ + // Check for an existing handler of the type being added. + if (FindHandler( handler->GetType() ) == 0) + { + sm_handlers.Append( handler ); + } + else + { + // This is not documented behaviour, merely the simplest 'fix' + // for preventing duplicate additions. If someone ever has + // a good reason to add and remove duplicate handlers (and they + // may) we should probably refcount the duplicates. + + wxLogDebug( _T("Adding duplicate animation handler for '%d' type"), + handler->GetType() ); + delete handler; + } +} + +void wxAnimation::InsertHandler( wxAnimationDecoder *handler ) +{ + // Check for an existing handler of the type being added. + if (FindHandler( handler->GetType() ) == 0) + { + sm_handlers.Insert( handler ); + } + else + { + // see AddHandler for additional comments. + wxLogDebug( _T("Inserting duplicate animation handler for '%d' type"), + handler->GetType() ); + delete handler; + } +} + +const wxAnimationDecoder *wxAnimation::FindHandler( wxAnimationType animType ) +{ + wxAnimationDecoderList::compatibility_iterator node = sm_handlers.GetFirst(); + while (node) + { + const wxAnimationDecoder *handler = (const wxAnimationDecoder *)node->GetData(); + if (handler->GetType() == animType) return handler; + node = node->GetNext(); + } + return 0; +} + +void wxAnimation::InitStandardHandlers() +{ +#if wxUSE_GIF + AddHandler(new wxGIFDecoder); +#endif // wxUSE_GIF +#if wxUSE_ICO_CUR + AddHandler(new wxANIDecoder); +#endif // wxUSE_ICO_CUR +} + +void wxAnimation::CleanUpHandlers() +{ + wxAnimationDecoderList::compatibility_iterator node = sm_handlers.GetFirst(); + while (node) + { + wxAnimationDecoder *handler = (wxAnimationDecoder *)node->GetData(); + wxAnimationDecoderList::compatibility_iterator next = node->GetNext(); + delete handler; + node = next; + } + + sm_handlers.Clear(); +} + + +// A module to allow wxAnimation initialization/cleanup +// without calling these functions from app.cpp or from +// the user's application. + +class wxAnimationModule: public wxModule +{ +DECLARE_DYNAMIC_CLASS(wxAnimationModule) +public: + wxAnimationModule() {} + bool OnInit() { wxAnimation::InitStandardHandlers(); return true; } + void OnExit() { wxAnimation::CleanUpHandlers(); } +}; + +IMPLEMENT_DYNAMIC_CLASS(wxAnimationModule, wxModule) + + +// ---------------------------------------------------------------------------- +// wxAnimationCtrl +// ---------------------------------------------------------------------------- + +IMPLEMENT_CLASS(wxAnimationCtrl, wxAnimationCtrlBase) +BEGIN_EVENT_TABLE(wxAnimationCtrl, wxAnimationCtrlBase) + EVT_PAINT(wxAnimationCtrl::OnPaint) + EVT_SIZE(wxAnimationCtrl::OnSize) + EVT_TIMER(wxID_ANY, wxAnimationCtrl::OnTimer) +END_EVENT_TABLE() + +void wxAnimationCtrl::Init() +{ + m_currentFrame = 0; + m_looped = false; + m_isPlaying = false; + + // use the window background colour by default to be consistent + // with the GTK+ native version + m_useWinBackgroundColour = true; +} + +bool wxAnimationCtrl::Create(wxWindow *parent, wxWindowID id, + const wxAnimation& animation, const wxPoint& pos, + const wxSize& size, long style, const wxString& name) +{ + m_timer.SetOwner(this); + + if (!base_type::Create(parent, id, pos, size, style, wxDefaultValidator, name)) + return false; + + // by default we get the same background colour of our parent + SetBackgroundColour(parent->GetBackgroundColour()); + + SetAnimation(animation); + + return true; +} + +wxAnimationCtrl::~wxAnimationCtrl() +{ + Stop(); +} + +bool wxAnimationCtrl::LoadFile(const wxString& filename, wxAnimationType type) +{ + wxAnimation anim; + if (!anim.LoadFile(filename, type) || + !anim.IsOk()) + return false; + + SetAnimation(anim); + return true; +} + +wxSize wxAnimationCtrl::DoGetBestSize() const +{ + if (m_animation.IsOk() && !this->HasFlag(wxAC_NO_AUTORESIZE)) + return m_animation.GetSize(); + + return wxSize(100, 100); +} + +void wxAnimationCtrl::SetAnimation(const wxAnimation& animation) +{ + if (IsPlaying()) + Stop(); + + // set new animation even if it's wxNullAnimation + m_animation = animation; + if (!m_animation.IsOk()) + { + DisplayStaticImage(); + return; + } + + if (m_animation.GetBackgroundColour() == wxNullColour) + SetUseWindowBackgroundColour(); + if (!this->HasFlag(wxAC_NO_AUTORESIZE)) + FitToAnimation(); + + DisplayStaticImage(); +} + +void wxAnimationCtrl::SetInactiveBitmap(const wxBitmap &bmp) +{ + // if the bitmap has an associated mask, we need to set our background to + // the colour of our parent otherwise when calling DrawCurrentFrame() + // (which uses the bitmap's mask), our background colour would be used for + // transparent areas - and that's not what we want (at least for + // consistency with the GTK version) + if ( bmp.GetMask() != NULL && GetParent() != NULL ) + SetBackgroundColour(GetParent()->GetBackgroundColour()); + + wxAnimationCtrlBase::SetInactiveBitmap(bmp); +} + +void wxAnimationCtrl::FitToAnimation() +{ + SetSize(m_animation.GetSize()); +} + +bool wxAnimationCtrl::SetBackgroundColour(const wxColour& colour) +{ + if ( !wxWindow::SetBackgroundColour(colour) ) + return false; + + // if not playing, then this change must be seen immediately (unless + // there's an inactive bitmap set which has higher priority than bg colour) + if ( !IsPlaying() ) + DisplayStaticImage(); + + return true; +} + + +// ---------------------------------------------------------------------------- +// wxAnimationCtrl - stop/play methods +// ---------------------------------------------------------------------------- + +void wxAnimationCtrl::Stop() +{ + m_timer.Stop(); + m_isPlaying = false; + + // reset frame counter + m_currentFrame = 0; + + DisplayStaticImage(); +} + +bool wxAnimationCtrl::Play(bool looped) +{ + if (!m_animation.IsOk()) + return false; + + m_looped = looped; + m_currentFrame = 0; + + if (!RebuildBackingStoreUpToFrame(0)) + return false; + + m_isPlaying = true; + + // do a ClearBackground() to avoid that e.g. the custom static bitmap which + // was eventually shown previously remains partially drawn + ClearBackground(); + + // DrawCurrentFrame() will use our updated backing store + wxClientDC clientDC(this); + DrawCurrentFrame(clientDC); + + // start the timer + int delay = m_animation.GetDelay(0); + if (delay == 0) + delay = 1; // 0 is invalid timeout for wxTimer. + m_timer.Start(delay, true); + + return true; +} + + + +// ---------------------------------------------------------------------------- +// wxAnimationCtrl - rendering methods +// ---------------------------------------------------------------------------- + +bool wxAnimationCtrl::RebuildBackingStoreUpToFrame(unsigned int frame) +{ + // if we've not created the backing store yet or it's too + // small, then recreate it + wxSize sz = m_animation.GetSize(), + winsz = GetClientSize(); + int w = wxMin(sz.GetWidth(), winsz.GetWidth()); + int h = wxMin(sz.GetHeight(), winsz.GetHeight()); + + if ( !m_backingStore.IsOk() || + m_backingStore.GetWidth() < w || m_backingStore.GetHeight() < h ) + { + if (!m_backingStore.Create(w, h)) + return false; + } + + wxMemoryDC dc; + dc.SelectObject(m_backingStore); + + // Draw the background + DisposeToBackground(dc); + + // Draw all intermediate frames that haven't been removed from the animation + for (unsigned int i = 0; i < frame; i++) + { + if (m_animation.GetDisposalMethod(i) == wxANIM_DONOTREMOVE || + m_animation.GetDisposalMethod(i) == wxANIM_UNSPECIFIED) + { + DrawFrame(dc, i); + } + else if (m_animation.GetDisposalMethod(i) == wxANIM_TOBACKGROUND) + DisposeToBackground(dc, m_animation.GetFramePosition(i), + m_animation.GetFrameSize(i)); + } + + // finally draw this frame + DrawFrame(dc, frame); + dc.SelectObject(wxNullBitmap); + + return true; +} + +void wxAnimationCtrl::IncrementalUpdateBackingStore() +{ + wxMemoryDC dc; + dc.SelectObject(m_backingStore); + + // OPTIMIZATION: + // since wxAnimationCtrl can only play animations forward, without skipping + // frames, we can be sure that m_backingStore contains the m_currentFrame-1 + // frame and thus we just need to dispose the m_currentFrame-1 frame and + // render the m_currentFrame-th one. + + if (m_currentFrame == 0) + { + // before drawing the first frame always dispose to bg colour + DisposeToBackground(dc); + } + else + { + switch (m_animation.GetDisposalMethod(m_currentFrame-1)) + { + case wxANIM_TOBACKGROUND: + DisposeToBackground(dc, m_animation.GetFramePosition(m_currentFrame-1), + m_animation.GetFrameSize(m_currentFrame-1)); + break; + + case wxANIM_TOPREVIOUS: + // this disposal should never be used too often. + // E.g. GIF specification explicitely say to keep the usage of this + // disposal limited to the minimum. + // In fact it may require a lot of time to restore + if (m_currentFrame == 1) + { + // if 0-th frame disposal is to restore to previous frame, + // the best we can do is to restore to background + DisposeToBackground(dc); + } + else + if (!RebuildBackingStoreUpToFrame(m_currentFrame-2)) + Stop(); + break; + + case wxANIM_DONOTREMOVE: + case wxANIM_UNSPECIFIED: + break; + } + } + + // now just draw the current frame on the top of the backing store + DrawFrame(dc, m_currentFrame); + dc.SelectObject(wxNullBitmap); +} + +void wxAnimationCtrl::DisplayStaticImage() +{ + wxASSERT(!IsPlaying()); + + // m_bmpStaticReal will be updated only if necessary... + UpdateStaticImage(); + + if (m_bmpStaticReal.IsOk()) + { + // copy the inactive bitmap in the backing store + // eventually using the mask if the static bitmap has one + if ( m_bmpStaticReal.GetMask() ) + { + wxMemoryDC temp; + temp.SelectObject(m_backingStore); + DisposeToBackground(temp); + temp.DrawBitmap(m_bmpStaticReal, 0, 0, true /* use mask */); + } + else + m_backingStore = m_bmpStaticReal; + } + else + { + // put in the backing store the first frame of the animation + if (!m_animation.IsOk() || + !RebuildBackingStoreUpToFrame(0)) + { + m_animation = wxNullAnimation; + DisposeToBackground(); + } + } + + Refresh(); +} + +void wxAnimationCtrl::DrawFrame(wxDC &dc, unsigned int frame) +{ + // PERFORMANCE NOTE: + // this draw stuff is not as fast as possible: the wxAnimationDecoder + // needs first to convert from its internal format to wxImage RGB24; + // the wxImage is then converted as a wxBitmap and finally blitted. + // If wxAnimationDecoder had a function to convert directly from its + // internal format to a port-specific wxBitmap, it would be somewhat faster. + wxBitmap bmp(m_animation.GetFrame(frame)); + dc.DrawBitmap(bmp, m_animation.GetFramePosition(frame), + true /* use mask */); +} + +void wxAnimationCtrl::DrawCurrentFrame(wxDC& dc) +{ + wxASSERT( m_backingStore.IsOk() ); + + // m_backingStore always contains the current frame + dc.DrawBitmap(m_backingStore, 0, 0, true /* use mask in case it's present */); +} + +void wxAnimationCtrl::DisposeToBackground() +{ + // clear the backing store + wxMemoryDC dc; + dc.SelectObject(m_backingStore); + if ( dc.IsOk() ) + DisposeToBackground(dc); +} + +void wxAnimationCtrl::DisposeToBackground(wxDC& dc) +{ + wxColour col = IsUsingWindowBackgroundColour() + ? GetBackgroundColour() + : m_animation.GetBackgroundColour(); + + wxBrush brush(col); + dc.SetBackground(brush); + dc.Clear(); +} + +void wxAnimationCtrl::DisposeToBackground(wxDC& dc, const wxPoint &pos, const wxSize &sz) +{ + wxColour col = IsUsingWindowBackgroundColour() + ? GetBackgroundColour() + : m_animation.GetBackgroundColour(); + wxBrush brush(col); + dc.SetBrush(brush); // SetBrush and not SetBackground !! + dc.SetPen(*wxTRANSPARENT_PEN); + dc.DrawRectangle(pos, sz); +} + +// ---------------------------------------------------------------------------- +// wxAnimationCtrl - event handlers +// ---------------------------------------------------------------------------- + +void wxAnimationCtrl::OnPaint(wxPaintEvent& WXUNUSED(event)) +{ + // VERY IMPORTANT: the wxPaintDC *must* be created in any case + wxPaintDC dc(this); + + if ( m_backingStore.IsOk() ) + { + // NOTE: we draw the bitmap explicitely ignoring the mask (if any); + // i.e. we don't want to combine the backing store with the + // possibly wrong preexisting contents of the window! + dc.DrawBitmap(m_backingStore, 0, 0, false /* no mask */); + } + else + { + // m_animation is not valid and thus we don't have a valid backing store... + // clear then our area to the background colour + DisposeToBackground(dc); + } +} + +void wxAnimationCtrl::OnTimer(wxTimerEvent &WXUNUSED(event)) +{ + m_currentFrame++; + if (m_currentFrame == m_animation.GetFrameCount()) + { + // Should a non-looped animation display the last frame? + if (!m_looped) + { + Stop(); + return; + } + else + m_currentFrame = 0; // let's restart + } + + IncrementalUpdateBackingStore(); + + wxClientDC dc(this); + DrawCurrentFrame(dc); + +#ifdef __WXMAC__ + // without this, the animation currently doesn't redraw under Mac + Refresh(); +#endif // __WXMAC__ + + // Set the timer for the next frame + int delay = m_animation.GetDelay(m_currentFrame); + if (delay == 0) + delay = 1; // 0 is invalid timeout for wxTimer. + m_timer.Start(delay, true); +} + +void wxAnimationCtrl::OnSize(wxSizeEvent &WXUNUSED(event)) +{ + // NB: resizing an animation control may take a lot of time + // for big animations as the backing store must be + // extended and rebuilt. Try to avoid it e.g. using + // a null proportion value for your wxAnimationCtrls + // when using them inside sizers. + if (m_animation.IsOk()) + { + // be careful to change the backing store *only* if we are + // playing the animation as otherwise we may be displaying + // the inactive bitmap and overwriting the backing store + // with the last played frame is wrong in this case + if (IsPlaying()) + { + if (!RebuildBackingStoreUpToFrame(m_currentFrame)) + Stop(); // in case we are playing + } + } +} + +#endif // wxUSE_ANIMATIONCTRL + diff --git a/Externals/wxWidgets/src/generic/bmpcboxg.cpp b/Externals/wxWidgets/src/generic/bmpcboxg.cpp index 1689e9d173..9a71ec9a1a 100644 --- a/Externals/wxWidgets/src/generic/bmpcboxg.cpp +++ b/Externals/wxWidgets/src/generic/bmpcboxg.cpp @@ -1,477 +1,477 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/generic/bmpcboxg.cpp -// Purpose: wxBitmapComboBox -// Author: Jaakko Salli -// Modified by: -// Created: Aug-31-2006 -// RCS-ID: $Id: bmpcboxg.cpp 44665 2007-03-07 23:29:03Z VZ $ -// Copyright: (c) 2005 Jaakko Salli -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_BITMAPCOMBOBOX - -#include "wx/bmpcbox.h" - -#if defined(wxGENERIC_BITMAPCOMBOBOX) - -#ifndef WX_PRECOMP - #include "wx/log.h" -#endif - -#include "wx/odcombo.h" -#include "wx/settings.h" -#include "wx/dc.h" - -#if wxUSE_IMAGE - #include "wx/image.h" -#endif - - -const wxChar wxBitmapComboBoxNameStr[] = wxT("bitmapComboBox"); - - -// These macros allow wxArrayPtrVoid to be used in more convenient manner -#define GetBitmapPtr(n) ((wxBitmap*)m_bitmaps[n]) - - -#define IMAGE_SPACING_RIGHT 4 // Space left of image - -#define IMAGE_SPACING_LEFT 4 // Space right of image, left of text - -#define IMAGE_SPACING_VERTICAL 2 // Space top and bottom of image - -#define IMAGE_SPACING_CTRL_VERTICAL 7 // Spacing used in control size calculation - -#define EXTRA_FONT_HEIGHT 0 // Add to increase min. height of list items - - -// ============================================================================ -// implementation -// ============================================================================ - - -BEGIN_EVENT_TABLE(wxBitmapComboBox, wxOwnerDrawnComboBox) - EVT_SIZE(wxBitmapComboBox::OnSize) -END_EVENT_TABLE() - - -IMPLEMENT_DYNAMIC_CLASS(wxBitmapComboBox, wxOwnerDrawnComboBox) - -void wxBitmapComboBox::Init() -{ - m_fontHeight = 0; - m_imgAreaWidth = 0; - m_inResize = false; -} - -wxBitmapComboBox::wxBitmapComboBox(wxWindow *parent, - wxWindowID id, - const wxString& value, - const wxPoint& pos, - const wxSize& size, - const wxArrayString& choices, - long style, - const wxValidator& validator, - const wxString& name) - : wxOwnerDrawnComboBox(), - wxBitmapComboBoxBase() -{ - Init(); - - Create(parent,id,value,pos,size,choices,style,validator,name); -} - -bool wxBitmapComboBox::Create(wxWindow *parent, - wxWindowID id, - const wxString& value, - const wxPoint& pos, - const wxSize& size, - const wxArrayString& choices, - long style, - const wxValidator& validator, - const wxString& name) -{ - if ( !wxOwnerDrawnComboBox::Create(parent, id, value, - pos, size, - choices, style, - validator, name) ) - { - return false; - } - - PostCreate(); - - return true; -} - -bool wxBitmapComboBox::Create(wxWindow *parent, - wxWindowID id, - const wxString& value, - const wxPoint& pos, - const wxSize& size, - int n, - const wxString choices[], - long style, - const wxValidator& validator, - const wxString& name) -{ - if ( !wxOwnerDrawnComboBox::Create(parent, id, value, - pos, size, n, - choices, style, - validator, name) ) - { - return false; - } - - PostCreate(); - - return true; -} - -void wxBitmapComboBox::PostCreate() -{ - m_fontHeight = GetCharHeight() + EXTRA_FONT_HEIGHT; - - while ( m_bitmaps.GetCount() < GetCount() ) - m_bitmaps.Add( new wxBitmap() ); -} - -wxBitmapComboBox::~wxBitmapComboBox() -{ - Clear(); -} - -// ---------------------------------------------------------------------------- -// Item manipulation -// ---------------------------------------------------------------------------- - -void wxBitmapComboBox::SetItemBitmap(unsigned int n, const wxBitmap& bitmap) -{ - wxCHECK_RET( n < GetCount(), wxT("invalid item index") ); - OnAddBitmap(bitmap); - *GetBitmapPtr(n) = bitmap; - - if ( (int)n == GetSelection() ) - Refresh(); -} - -wxBitmap wxBitmapComboBox::GetItemBitmap(unsigned int n) const -{ - wxCHECK_MSG( n < GetCount(), wxNullBitmap, wxT("invalid item index") ); - return *GetBitmapPtr(n); -} - -int wxBitmapComboBox::Insert(const wxString& item, const wxBitmap& bitmap, - unsigned int pos, void *clientData) -{ - int n = DoInsertWithImage(item, bitmap, pos); - if ( n != wxNOT_FOUND ) - SetClientData(n, clientData); - - return n; -} - -int wxBitmapComboBox::Insert(const wxString& item, const wxBitmap& bitmap, - unsigned int pos, wxClientData *clientData) -{ - int n = DoInsertWithImage(item, bitmap, pos); - if ( n != wxNOT_FOUND ) - SetClientObject(n, clientData); - - return n; -} - -bool wxBitmapComboBox::OnAddBitmap(const wxBitmap& bitmap) -{ - if ( bitmap.Ok() ) - { - int width = bitmap.GetWidth(); - int height = bitmap.GetHeight(); - - if ( m_usedImgSize.x <= 0 ) - { - // - // If size not yet determined, get it from this image. - m_usedImgSize.x = width; - m_usedImgSize.y = height; - - InvalidateBestSize(); - wxSize newSz = GetBestSize(); - wxSize sz = GetSize(); - if ( newSz.y > sz.y ) - SetSize(sz.x, newSz.y); - else - DetermineIndent(); - } - - wxCHECK_MSG(width == m_usedImgSize.x && height == m_usedImgSize.y, - false, - wxT("you can only add images of same size")); - } - - return true; -} - -bool wxBitmapComboBox::DoInsertBitmap(const wxBitmap& bitmap, unsigned int pos) -{ - if ( !OnAddBitmap(bitmap) ) - return false; - - // NB: We must try to set the image before DoInsert or - // DoAppend because OnMeasureItem might be called - // before it returns. - m_bitmaps.Insert( new wxBitmap(bitmap), pos); - - return true; -} - -int wxBitmapComboBox::DoAppendWithImage(const wxString& item, const wxBitmap& image) -{ - unsigned int pos = m_bitmaps.size(); - - if ( !DoInsertBitmap(image, pos) ) - return wxNOT_FOUND; - - int index = wxOwnerDrawnComboBox::DoAppend(item); - - if ( index < 0 ) - index = m_bitmaps.size(); - - // Need to re-check the index incase DoAppend sorted - if ( (unsigned int) index != pos ) - { - wxBitmap* bmp = GetBitmapPtr(pos); - m_bitmaps.RemoveAt(pos); - m_bitmaps.Insert(bmp, index); - } - - return index; -} - -int wxBitmapComboBox::DoInsertWithImage(const wxString& item, - const wxBitmap& image, - unsigned int pos) -{ - wxCHECK_MSG( IsValidInsert(pos), wxNOT_FOUND, wxT("invalid item index") ); - - if ( !DoInsertBitmap(image, pos) ) - return wxNOT_FOUND; - - return wxOwnerDrawnComboBox::DoInsert(item, pos); -} - -int wxBitmapComboBox::DoAppend(const wxString& item) -{ - return DoAppendWithImage(item, wxNullBitmap); -} - -int wxBitmapComboBox::DoInsert(const wxString& item, unsigned int pos) -{ - return DoInsertWithImage(item, wxNullBitmap, pos); -} - -void wxBitmapComboBox::Clear() -{ - wxOwnerDrawnComboBox::Clear(); - - unsigned int i; - - for ( i=0; i 0 ) - { - indent = m_usedImgSize.x + IMAGE_SPACING_LEFT + IMAGE_SPACING_RIGHT; - m_imgAreaWidth = indent; - - indent -= 3; - } - - SetCustomPaintWidth(indent); -} - -void wxBitmapComboBox::OnSize(wxSizeEvent& event) -{ - // Prevent infinite looping - if ( !m_inResize ) - { - m_inResize = true; - DetermineIndent(); - m_inResize = false; - } - - event.Skip(); -} - -wxSize wxBitmapComboBox::DoGetBestSize() const -{ - wxSize sz = wxOwnerDrawnComboBox::DoGetBestSize(); - - // Scale control to match height of highest image. - int h2 = m_usedImgSize.y + IMAGE_SPACING_CTRL_VERTICAL; - - if ( h2 > sz.y ) - sz.y = h2; - - CacheBestSize(sz); - return sz; -} - -// ---------------------------------------------------------------------------- -// wxBitmapComboBox miscellaneous -// ---------------------------------------------------------------------------- - -bool wxBitmapComboBox::SetFont(const wxFont& font) -{ - bool res = wxOwnerDrawnComboBox::SetFont(font); - m_fontHeight = GetCharHeight() + EXTRA_FONT_HEIGHT; - return res; -} - -// ---------------------------------------------------------------------------- -// wxBitmapComboBox item drawing and measuring -// ---------------------------------------------------------------------------- - -void wxBitmapComboBox::OnDrawBackground(wxDC& dc, - const wxRect& rect, - int item, - int flags) const -{ - if ( GetCustomPaintWidth() == 0 || - !(flags & wxODCB_PAINTING_SELECTED) || - item < 0 ) - { - wxOwnerDrawnComboBox::OnDrawBackground(dc, rect, item, flags); - return; - } - - // - // Just paint simple selection background under where is text - // (ie. emulate what MSW image choice does). - // - - int xPos = 0; // Starting x of selection rectangle - const int vSizeDec = 1; // Vertical size reduction of selection rectangle edges - - xPos = GetCustomPaintWidth() + 2; - - wxCoord x, y; - GetTextExtent(GetString(item), &x, &y, 0, 0); - - dc.SetTextForeground(wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT)); - - wxColour selCol = wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT); - dc.SetPen(selCol); - dc.SetBrush(selCol); - dc.DrawRectangle(rect.x+xPos, - rect.y+vSizeDec, - x + 4, - rect.height-(vSizeDec*2)); -} - -void wxBitmapComboBox::OnDrawItem(wxDC& dc, - const wxRect& rect, - int item, - int flags) const -{ - wxString text; - int imgAreaWidth = m_imgAreaWidth; - bool drawText; - - if ( imgAreaWidth == 0 ) - { - wxOwnerDrawnComboBox::OnDrawItem(dc, rect, item, flags); - return; - } - - if ( flags & wxODCB_PAINTING_CONTROL ) - { - text = GetValue(); - if ( HasFlag(wxCB_READONLY) ) - drawText = true; - else - drawText = false; - } - else - { - text = GetString(item); - drawText = true; - } - - const wxBitmap& bmp = *GetBitmapPtr(item); - if ( bmp.Ok() ) - { - wxCoord w = bmp.GetWidth(); - wxCoord h = bmp.GetHeight(); - - // Draw the image centered - dc.DrawBitmap(bmp, - rect.x + (m_usedImgSize.x-w)/2 + IMAGE_SPACING_LEFT, - rect.y + (rect.height-h)/2, - true); - } - - if ( drawText ) - dc.DrawText(GetString(item), - rect.x + imgAreaWidth + 1, - rect.y + (rect.height-dc.GetCharHeight())/2); -} - -wxCoord wxBitmapComboBox::OnMeasureItem(size_t WXUNUSED(item)) const -{ - int imgHeightArea = m_usedImgSize.y + 2; - return imgHeightArea > m_fontHeight ? imgHeightArea : m_fontHeight; -} - -wxCoord wxBitmapComboBox::OnMeasureItemWidth(size_t item) const -{ - wxCoord x, y; - GetTextExtent(GetString(item), &x, &y, 0, 0); - x += m_imgAreaWidth; - return x; -} - -#endif // defined(wxGENERIC_BITMAPCOMBOBOX) - -#endif // wxUSE_BITMAPCOMBOBOX +///////////////////////////////////////////////////////////////////////////// +// Name: src/generic/bmpcboxg.cpp +// Purpose: wxBitmapComboBox +// Author: Jaakko Salli +// Modified by: +// Created: Aug-31-2006 +// RCS-ID: $Id: bmpcboxg.cpp 44665 2007-03-07 23:29:03Z VZ $ +// Copyright: (c) 2005 Jaakko Salli +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_BITMAPCOMBOBOX + +#include "wx/bmpcbox.h" + +#if defined(wxGENERIC_BITMAPCOMBOBOX) + +#ifndef WX_PRECOMP + #include "wx/log.h" +#endif + +#include "wx/odcombo.h" +#include "wx/settings.h" +#include "wx/dc.h" + +#if wxUSE_IMAGE + #include "wx/image.h" +#endif + + +const wxChar wxBitmapComboBoxNameStr[] = wxT("bitmapComboBox"); + + +// These macros allow wxArrayPtrVoid to be used in more convenient manner +#define GetBitmapPtr(n) ((wxBitmap*)m_bitmaps[n]) + + +#define IMAGE_SPACING_RIGHT 4 // Space left of image + +#define IMAGE_SPACING_LEFT 4 // Space right of image, left of text + +#define IMAGE_SPACING_VERTICAL 2 // Space top and bottom of image + +#define IMAGE_SPACING_CTRL_VERTICAL 7 // Spacing used in control size calculation + +#define EXTRA_FONT_HEIGHT 0 // Add to increase min. height of list items + + +// ============================================================================ +// implementation +// ============================================================================ + + +BEGIN_EVENT_TABLE(wxBitmapComboBox, wxOwnerDrawnComboBox) + EVT_SIZE(wxBitmapComboBox::OnSize) +END_EVENT_TABLE() + + +IMPLEMENT_DYNAMIC_CLASS(wxBitmapComboBox, wxOwnerDrawnComboBox) + +void wxBitmapComboBox::Init() +{ + m_fontHeight = 0; + m_imgAreaWidth = 0; + m_inResize = false; +} + +wxBitmapComboBox::wxBitmapComboBox(wxWindow *parent, + wxWindowID id, + const wxString& value, + const wxPoint& pos, + const wxSize& size, + const wxArrayString& choices, + long style, + const wxValidator& validator, + const wxString& name) + : wxOwnerDrawnComboBox(), + wxBitmapComboBoxBase() +{ + Init(); + + Create(parent,id,value,pos,size,choices,style,validator,name); +} + +bool wxBitmapComboBox::Create(wxWindow *parent, + wxWindowID id, + const wxString& value, + const wxPoint& pos, + const wxSize& size, + const wxArrayString& choices, + long style, + const wxValidator& validator, + const wxString& name) +{ + if ( !wxOwnerDrawnComboBox::Create(parent, id, value, + pos, size, + choices, style, + validator, name) ) + { + return false; + } + + PostCreate(); + + return true; +} + +bool wxBitmapComboBox::Create(wxWindow *parent, + wxWindowID id, + const wxString& value, + const wxPoint& pos, + const wxSize& size, + int n, + const wxString choices[], + long style, + const wxValidator& validator, + const wxString& name) +{ + if ( !wxOwnerDrawnComboBox::Create(parent, id, value, + pos, size, n, + choices, style, + validator, name) ) + { + return false; + } + + PostCreate(); + + return true; +} + +void wxBitmapComboBox::PostCreate() +{ + m_fontHeight = GetCharHeight() + EXTRA_FONT_HEIGHT; + + while ( m_bitmaps.GetCount() < GetCount() ) + m_bitmaps.Add( new wxBitmap() ); +} + +wxBitmapComboBox::~wxBitmapComboBox() +{ + Clear(); +} + +// ---------------------------------------------------------------------------- +// Item manipulation +// ---------------------------------------------------------------------------- + +void wxBitmapComboBox::SetItemBitmap(unsigned int n, const wxBitmap& bitmap) +{ + wxCHECK_RET( n < GetCount(), wxT("invalid item index") ); + OnAddBitmap(bitmap); + *GetBitmapPtr(n) = bitmap; + + if ( (int)n == GetSelection() ) + Refresh(); +} + +wxBitmap wxBitmapComboBox::GetItemBitmap(unsigned int n) const +{ + wxCHECK_MSG( n < GetCount(), wxNullBitmap, wxT("invalid item index") ); + return *GetBitmapPtr(n); +} + +int wxBitmapComboBox::Insert(const wxString& item, const wxBitmap& bitmap, + unsigned int pos, void *clientData) +{ + int n = DoInsertWithImage(item, bitmap, pos); + if ( n != wxNOT_FOUND ) + SetClientData(n, clientData); + + return n; +} + +int wxBitmapComboBox::Insert(const wxString& item, const wxBitmap& bitmap, + unsigned int pos, wxClientData *clientData) +{ + int n = DoInsertWithImage(item, bitmap, pos); + if ( n != wxNOT_FOUND ) + SetClientObject(n, clientData); + + return n; +} + +bool wxBitmapComboBox::OnAddBitmap(const wxBitmap& bitmap) +{ + if ( bitmap.Ok() ) + { + int width = bitmap.GetWidth(); + int height = bitmap.GetHeight(); + + if ( m_usedImgSize.x <= 0 ) + { + // + // If size not yet determined, get it from this image. + m_usedImgSize.x = width; + m_usedImgSize.y = height; + + InvalidateBestSize(); + wxSize newSz = GetBestSize(); + wxSize sz = GetSize(); + if ( newSz.y > sz.y ) + SetSize(sz.x, newSz.y); + else + DetermineIndent(); + } + + wxCHECK_MSG(width == m_usedImgSize.x && height == m_usedImgSize.y, + false, + wxT("you can only add images of same size")); + } + + return true; +} + +bool wxBitmapComboBox::DoInsertBitmap(const wxBitmap& bitmap, unsigned int pos) +{ + if ( !OnAddBitmap(bitmap) ) + return false; + + // NB: We must try to set the image before DoInsert or + // DoAppend because OnMeasureItem might be called + // before it returns. + m_bitmaps.Insert( new wxBitmap(bitmap), pos); + + return true; +} + +int wxBitmapComboBox::DoAppendWithImage(const wxString& item, const wxBitmap& image) +{ + unsigned int pos = m_bitmaps.size(); + + if ( !DoInsertBitmap(image, pos) ) + return wxNOT_FOUND; + + int index = wxOwnerDrawnComboBox::DoAppend(item); + + if ( index < 0 ) + index = m_bitmaps.size(); + + // Need to re-check the index incase DoAppend sorted + if ( (unsigned int) index != pos ) + { + wxBitmap* bmp = GetBitmapPtr(pos); + m_bitmaps.RemoveAt(pos); + m_bitmaps.Insert(bmp, index); + } + + return index; +} + +int wxBitmapComboBox::DoInsertWithImage(const wxString& item, + const wxBitmap& image, + unsigned int pos) +{ + wxCHECK_MSG( IsValidInsert(pos), wxNOT_FOUND, wxT("invalid item index") ); + + if ( !DoInsertBitmap(image, pos) ) + return wxNOT_FOUND; + + return wxOwnerDrawnComboBox::DoInsert(item, pos); +} + +int wxBitmapComboBox::DoAppend(const wxString& item) +{ + return DoAppendWithImage(item, wxNullBitmap); +} + +int wxBitmapComboBox::DoInsert(const wxString& item, unsigned int pos) +{ + return DoInsertWithImage(item, wxNullBitmap, pos); +} + +void wxBitmapComboBox::Clear() +{ + wxOwnerDrawnComboBox::Clear(); + + unsigned int i; + + for ( i=0; i 0 ) + { + indent = m_usedImgSize.x + IMAGE_SPACING_LEFT + IMAGE_SPACING_RIGHT; + m_imgAreaWidth = indent; + + indent -= 3; + } + + SetCustomPaintWidth(indent); +} + +void wxBitmapComboBox::OnSize(wxSizeEvent& event) +{ + // Prevent infinite looping + if ( !m_inResize ) + { + m_inResize = true; + DetermineIndent(); + m_inResize = false; + } + + event.Skip(); +} + +wxSize wxBitmapComboBox::DoGetBestSize() const +{ + wxSize sz = wxOwnerDrawnComboBox::DoGetBestSize(); + + // Scale control to match height of highest image. + int h2 = m_usedImgSize.y + IMAGE_SPACING_CTRL_VERTICAL; + + if ( h2 > sz.y ) + sz.y = h2; + + CacheBestSize(sz); + return sz; +} + +// ---------------------------------------------------------------------------- +// wxBitmapComboBox miscellaneous +// ---------------------------------------------------------------------------- + +bool wxBitmapComboBox::SetFont(const wxFont& font) +{ + bool res = wxOwnerDrawnComboBox::SetFont(font); + m_fontHeight = GetCharHeight() + EXTRA_FONT_HEIGHT; + return res; +} + +// ---------------------------------------------------------------------------- +// wxBitmapComboBox item drawing and measuring +// ---------------------------------------------------------------------------- + +void wxBitmapComboBox::OnDrawBackground(wxDC& dc, + const wxRect& rect, + int item, + int flags) const +{ + if ( GetCustomPaintWidth() == 0 || + !(flags & wxODCB_PAINTING_SELECTED) || + item < 0 ) + { + wxOwnerDrawnComboBox::OnDrawBackground(dc, rect, item, flags); + return; + } + + // + // Just paint simple selection background under where is text + // (ie. emulate what MSW image choice does). + // + + int xPos = 0; // Starting x of selection rectangle + const int vSizeDec = 1; // Vertical size reduction of selection rectangle edges + + xPos = GetCustomPaintWidth() + 2; + + wxCoord x, y; + GetTextExtent(GetString(item), &x, &y, 0, 0); + + dc.SetTextForeground(wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT)); + + wxColour selCol = wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT); + dc.SetPen(selCol); + dc.SetBrush(selCol); + dc.DrawRectangle(rect.x+xPos, + rect.y+vSizeDec, + x + 4, + rect.height-(vSizeDec*2)); +} + +void wxBitmapComboBox::OnDrawItem(wxDC& dc, + const wxRect& rect, + int item, + int flags) const +{ + wxString text; + int imgAreaWidth = m_imgAreaWidth; + bool drawText; + + if ( imgAreaWidth == 0 ) + { + wxOwnerDrawnComboBox::OnDrawItem(dc, rect, item, flags); + return; + } + + if ( flags & wxODCB_PAINTING_CONTROL ) + { + text = GetValue(); + if ( HasFlag(wxCB_READONLY) ) + drawText = true; + else + drawText = false; + } + else + { + text = GetString(item); + drawText = true; + } + + const wxBitmap& bmp = *GetBitmapPtr(item); + if ( bmp.Ok() ) + { + wxCoord w = bmp.GetWidth(); + wxCoord h = bmp.GetHeight(); + + // Draw the image centered + dc.DrawBitmap(bmp, + rect.x + (m_usedImgSize.x-w)/2 + IMAGE_SPACING_LEFT, + rect.y + (rect.height-h)/2, + true); + } + + if ( drawText ) + dc.DrawText(GetString(item), + rect.x + imgAreaWidth + 1, + rect.y + (rect.height-dc.GetCharHeight())/2); +} + +wxCoord wxBitmapComboBox::OnMeasureItem(size_t WXUNUSED(item)) const +{ + int imgHeightArea = m_usedImgSize.y + 2; + return imgHeightArea > m_fontHeight ? imgHeightArea : m_fontHeight; +} + +wxCoord wxBitmapComboBox::OnMeasureItemWidth(size_t item) const +{ + wxCoord x, y; + GetTextExtent(GetString(item), &x, &y, 0, 0); + x += m_imgAreaWidth; + return x; +} + +#endif // defined(wxGENERIC_BITMAPCOMBOBOX) + +#endif // wxUSE_BITMAPCOMBOBOX diff --git a/Externals/wxWidgets/src/generic/busyinfo.cpp b/Externals/wxWidgets/src/generic/busyinfo.cpp index 257c233667..e57736122d 100644 --- a/Externals/wxWidgets/src/generic/busyinfo.cpp +++ b/Externals/wxWidgets/src/generic/busyinfo.cpp @@ -1,135 +1,135 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/generic/busyinfo.cpp -// Purpose: Information window when app is busy -// Author: Vaclav Slavik -// Copyright: (c) 1999 Vaclav Slavik -// RCS-ID: $Id: busyinfo.cpp 44898 2007-03-18 20:39:13Z VZ $ -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ -#pragma hdrstop -#endif - -#if wxUSE_BUSYINFO - -// for all others, include the necessary headers -#ifndef WX_PRECOMP - #include "wx/frame.h" - #include "wx/stattext.h" - #include "wx/panel.h" - #include "wx/utils.h" -#endif - -#include "wx/busyinfo.h" - -class WXDLLEXPORT wxInfoFrame : public wxFrame -{ -public: - wxInfoFrame(wxWindow *parent, const wxString& message); - -private: - DECLARE_NO_COPY_CLASS(wxInfoFrame) -}; - - -wxInfoFrame::wxInfoFrame(wxWindow *parent, const wxString& message) - : wxFrame(parent, wxID_ANY, wxT("Busy"), - wxDefaultPosition, wxDefaultSize, -#if defined(__WXX11__) - wxRESIZE_BORDER -#else - wxSIMPLE_BORDER -#endif - | wxFRAME_TOOL_WINDOW) -{ - wxPanel *panel = new wxPanel( this ); - wxStaticText *text = new wxStaticText(panel, wxID_ANY, message); - - panel->SetCursor(*wxHOURGLASS_CURSOR); - text->SetCursor(*wxHOURGLASS_CURSOR); - - // make the frame of at least the standard size (400*80) but big enough - // for the text we show - wxSize sizeText = text->GetBestSize(); -#ifdef __WXPM__ - int nX = 0; - int nY = 0; - int nWidth = 0; - int nHeight = 0; - int nParentHeight = parent->GetClientSize().y; - int nParentWidth = parent->GetClientSize().x; - int nColor; - - SetBackgroundColour(wxT("WHITE")); - nColor = (LONG)GetBackgroundColour().GetPixel(); - - ::WinSetPresParam( GetHwnd() - ,PP_BACKGROUNDCOLOR - ,sizeof(LONG) - ,(PVOID)&nColor - ); - panel->SetBackgroundColour(wxT("WHITE")); - nColor = (LONG)panel->GetBackgroundColour().GetPixel(); - - ::WinSetPresParam( GetHwndOf(panel) - ,PP_BACKGROUNDCOLOR - ,sizeof(LONG) - ,(PVOID)&nColor - ); - nWidth = wxMax(sizeText.x, 340) + 60; - nHeight = wxMax(sizeText.y, 40) + 40; - nX = (nParentWidth - nWidth) / 2; - nY = (nParentHeight / 2) - (nHeight / 2); - nY = nParentHeight - (nY + nHeight); - ::WinSetWindowPos( m_hFrame - ,HWND_TOP - ,nX - ,nY - ,nWidth - ,nHeight - ,SWP_SIZE | SWP_MOVE | SWP_ACTIVATE - ); - text->SetBackgroundColour(wxT("WHITE")); - nColor = (LONG)text->GetBackgroundColour().GetPixel(); - - ::WinSetPresParam( GetHwndOf(text) - ,PP_BACKGROUNDCOLOR - ,sizeof(LONG) - ,(PVOID)&nColor - ); - text->Center(wxBOTH); -#else - SetClientSize(wxMax(sizeText.x, 340) + 60, wxMax(sizeText.y, 40) + 40); - - // need to size the panel correctly first so that text->Centre() works - panel->SetSize(GetClientSize()); - - text->Centre(wxBOTH); - Centre(wxBOTH); -#endif -} - -wxBusyInfo::wxBusyInfo(const wxString& message, wxWindow *parent) -{ - m_InfoFrame = new wxInfoFrame( parent, message); - if ( parent && parent->HasFlag(wxSTAY_ON_TOP) ) - { - // we must have this flag to be in front of our parent if it has it - m_InfoFrame->SetWindowStyleFlag(wxSTAY_ON_TOP); - } - - m_InfoFrame->Show(true); - m_InfoFrame->Refresh(); - m_InfoFrame->Update(); -} - -wxBusyInfo::~wxBusyInfo() -{ - m_InfoFrame->Show(false); - m_InfoFrame->Close(); -} - -#endif // wxUSE_BUSYINFO +///////////////////////////////////////////////////////////////////////////// +// Name: src/generic/busyinfo.cpp +// Purpose: Information window when app is busy +// Author: Vaclav Slavik +// Copyright: (c) 1999 Vaclav Slavik +// RCS-ID: $Id: busyinfo.cpp 44898 2007-03-18 20:39:13Z VZ $ +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ +#pragma hdrstop +#endif + +#if wxUSE_BUSYINFO + +// for all others, include the necessary headers +#ifndef WX_PRECOMP + #include "wx/frame.h" + #include "wx/stattext.h" + #include "wx/panel.h" + #include "wx/utils.h" +#endif + +#include "wx/busyinfo.h" + +class WXDLLEXPORT wxInfoFrame : public wxFrame +{ +public: + wxInfoFrame(wxWindow *parent, const wxString& message); + +private: + DECLARE_NO_COPY_CLASS(wxInfoFrame) +}; + + +wxInfoFrame::wxInfoFrame(wxWindow *parent, const wxString& message) + : wxFrame(parent, wxID_ANY, wxT("Busy"), + wxDefaultPosition, wxDefaultSize, +#if defined(__WXX11__) + wxRESIZE_BORDER +#else + wxSIMPLE_BORDER +#endif + | wxFRAME_TOOL_WINDOW) +{ + wxPanel *panel = new wxPanel( this ); + wxStaticText *text = new wxStaticText(panel, wxID_ANY, message); + + panel->SetCursor(*wxHOURGLASS_CURSOR); + text->SetCursor(*wxHOURGLASS_CURSOR); + + // make the frame of at least the standard size (400*80) but big enough + // for the text we show + wxSize sizeText = text->GetBestSize(); +#ifdef __WXPM__ + int nX = 0; + int nY = 0; + int nWidth = 0; + int nHeight = 0; + int nParentHeight = parent->GetClientSize().y; + int nParentWidth = parent->GetClientSize().x; + int nColor; + + SetBackgroundColour(wxT("WHITE")); + nColor = (LONG)GetBackgroundColour().GetPixel(); + + ::WinSetPresParam( GetHwnd() + ,PP_BACKGROUNDCOLOR + ,sizeof(LONG) + ,(PVOID)&nColor + ); + panel->SetBackgroundColour(wxT("WHITE")); + nColor = (LONG)panel->GetBackgroundColour().GetPixel(); + + ::WinSetPresParam( GetHwndOf(panel) + ,PP_BACKGROUNDCOLOR + ,sizeof(LONG) + ,(PVOID)&nColor + ); + nWidth = wxMax(sizeText.x, 340) + 60; + nHeight = wxMax(sizeText.y, 40) + 40; + nX = (nParentWidth - nWidth) / 2; + nY = (nParentHeight / 2) - (nHeight / 2); + nY = nParentHeight - (nY + nHeight); + ::WinSetWindowPos( m_hFrame + ,HWND_TOP + ,nX + ,nY + ,nWidth + ,nHeight + ,SWP_SIZE | SWP_MOVE | SWP_ACTIVATE + ); + text->SetBackgroundColour(wxT("WHITE")); + nColor = (LONG)text->GetBackgroundColour().GetPixel(); + + ::WinSetPresParam( GetHwndOf(text) + ,PP_BACKGROUNDCOLOR + ,sizeof(LONG) + ,(PVOID)&nColor + ); + text->Center(wxBOTH); +#else + SetClientSize(wxMax(sizeText.x, 340) + 60, wxMax(sizeText.y, 40) + 40); + + // need to size the panel correctly first so that text->Centre() works + panel->SetSize(GetClientSize()); + + text->Centre(wxBOTH); + Centre(wxBOTH); +#endif +} + +wxBusyInfo::wxBusyInfo(const wxString& message, wxWindow *parent) +{ + m_InfoFrame = new wxInfoFrame( parent, message); + if ( parent && parent->HasFlag(wxSTAY_ON_TOP) ) + { + // we must have this flag to be in front of our parent if it has it + m_InfoFrame->SetWindowStyleFlag(wxSTAY_ON_TOP); + } + + m_InfoFrame->Show(true); + m_InfoFrame->Refresh(); + m_InfoFrame->Update(); +} + +wxBusyInfo::~wxBusyInfo() +{ + m_InfoFrame->Show(false); + m_InfoFrame->Close(); +} + +#endif // wxUSE_BUSYINFO diff --git a/Externals/wxWidgets/src/generic/buttonbar.cpp b/Externals/wxWidgets/src/generic/buttonbar.cpp index b229d7275e..f85918ba5d 100644 --- a/Externals/wxWidgets/src/generic/buttonbar.cpp +++ b/Externals/wxWidgets/src/generic/buttonbar.cpp @@ -1,555 +1,555 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/generic/buttonbar.cpp -// Purpose: wxButtonToolBar implementation -// Author: Julian Smart, after Robert Roebling, Vadim Zeitlin, SciTech -// Modified by: -// Created: 2006-04-13 -// Id: $Id: buttonbar.cpp 42816 2006-10-31 08:50:17Z RD $ -// Copyright: (c) Julian Smart, Robert Roebling, Vadim Zeitlin, -// SciTech Software, Inc. -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -// Currently, only for Mac as a toolbar replacement. -#if defined(__WXMAC__) && wxUSE_TOOLBAR && wxUSE_BMPBUTTON - -#include "wx/generic/buttonbar.h" - -#ifndef WX_PRECOMP - #include "wx/utils.h" - #include "wx/app.h" - #include "wx/log.h" - #include "wx/frame.h" - #include "wx/dcclient.h" - #include "wx/settings.h" - #include "wx/image.h" -#endif - -// ---------------------------------------------------------------------------- -// wxButtonToolBarTool: our implementation of wxToolBarToolBase -// ---------------------------------------------------------------------------- - -class WXDLLEXPORT wxButtonToolBarTool : public wxToolBarToolBase -{ -public: - wxButtonToolBarTool(wxButtonToolBar *tbar, - int id, - const wxString& label, - const wxBitmap& bmpNormal, - const wxBitmap& bmpDisabled, - wxItemKind kind, - wxObject *clientData, - const wxString& shortHelp, - const wxString& longHelp) - : wxToolBarToolBase(tbar, id, label, bmpNormal, bmpDisabled, kind, - clientData, shortHelp, longHelp) - { - m_x = m_y = wxDefaultCoord; - m_width = - m_height = 0; - - m_button = NULL; - } - - wxButtonToolBarTool(wxButtonToolBar *tbar, wxControl *control) - : wxToolBarToolBase(tbar, control) - { - m_x = m_y = wxDefaultCoord; - m_width = - m_height = 0; - m_button = NULL; - } - - wxBitmapButton* GetButton() const { return m_button; } - void SetButton(wxBitmapButton* button) { m_button = button; } - -public: - // the tool position (for controls) - wxCoord m_x; - wxCoord m_y; - wxCoord m_width; - wxCoord m_height; - -private: - // the control representing the button - wxBitmapButton* m_button; -}; - -// ============================================================================ -// wxButtonToolBar implementation -// ============================================================================ - -IMPLEMENT_DYNAMIC_CLASS(wxButtonToolBar, wxControl) - -BEGIN_EVENT_TABLE(wxButtonToolBar, wxControl) - EVT_BUTTON(wxID_ANY, wxButtonToolBar::OnCommand) - EVT_PAINT(wxButtonToolBar::OnPaint) - EVT_LEFT_UP(wxButtonToolBar::OnLeftUp) -END_EVENT_TABLE() - -// ---------------------------------------------------------------------------- -// wxButtonToolBar creation -// ---------------------------------------------------------------------------- - -void wxButtonToolBar::Init() -{ - // no tools yet - m_needsLayout = false; - - // unknown widths for the tools and separators - m_widthSeparator = wxDefaultCoord; - - m_maxWidth = m_maxHeight = 0; - - m_labelMargin = 2; - m_labelHeight = 0; - - SetMargins(8, 2); - SetToolPacking(8); -} - -bool wxButtonToolBar::Create(wxWindow *parent, - wxWindowID id, - const wxPoint& pos, - const wxSize& size, - long style, - const wxString& name) -{ - if ( !wxToolBarBase::Create(parent, id, pos, size, style, - wxDefaultValidator, name) ) - { - return false; - } - - // wxColour lightBackground(244, 244, 244); - - wxFont font(wxSMALL_FONT->GetPointSize(), wxNORMAL_FONT->GetFamily(), wxNORMAL_FONT->GetStyle(), wxNORMAL); - SetFont(font); - - // Calculate the label height if necessary - if (GetWindowStyle() & wxTB_TEXT) - { - wxClientDC dc(this); - dc.SetFont(font); - int w, h; - dc.GetTextExtent(wxT("X"), & w, & h); - m_labelHeight = h; - } - return true; -} - -wxButtonToolBar::~wxButtonToolBar() -{ -} - -// ---------------------------------------------------------------------------- -// wxButtonToolBar tool-related methods -// ---------------------------------------------------------------------------- - -wxToolBarToolBase *wxButtonToolBar::FindToolForPosition(wxCoord x, wxCoord y) const -{ - // check the "other" direction first: it must be inside the toolbar or we - // don't risk finding anything - if ( IsVertical() ) - { - if ( x < 0 || x > m_maxWidth ) - return NULL; - - // we always use x, even for a vertical toolbar, this makes the code - // below simpler - x = y; - } - else // horizontal - { - if ( y < 0 || y > m_maxHeight ) - return NULL; - } - - for ( wxToolBarToolsList::compatibility_iterator node = m_tools.GetFirst(); - node; - node = node->GetNext() ) - { - wxButtonToolBarTool *tool = (wxButtonToolBarTool*) node->GetData(); - wxRect rectTool = GetToolRect(tool); - - wxCoord startTool, endTool; - GetRectLimits(rectTool, &startTool, &endTool); - - if ( x >= startTool && x <= endTool ) - { - // don't return the separators from here, they don't accept any - // input anyhow - return tool->IsSeparator() ? NULL : tool; - } - } - - return NULL; -} - -void wxButtonToolBar::GetRectLimits(const wxRect& rect, - wxCoord *start, - wxCoord *end) const -{ - wxCHECK_RET( start && end, _T("NULL pointer in GetRectLimits") ); - - if ( IsVertical() ) - { - *start = rect.GetTop(); - *end = rect.GetBottom(); - } - else // horizontal - { - *start = rect.GetLeft(); - *end = rect.GetRight(); - } -} - - -void wxButtonToolBar::SetToolShortHelp(int id, const wxString& help) -{ - wxToolBarToolBase *tool = FindById(id); - - wxCHECK_RET( tool, _T("SetToolShortHelp: no such tool") ); - - // TODO: set tooltip/short help - tool->SetShortHelp(help); -} - -bool wxButtonToolBar::DoInsertTool(size_t WXUNUSED(pos), - wxToolBarToolBase * WXUNUSED(tool)) -{ - return true; -} - -bool wxButtonToolBar::DoDeleteTool(size_t WXUNUSED(pos), - wxToolBarToolBase * WXUNUSED(tool)) -{ - // TODO - return true; -} - -void wxButtonToolBar::DoEnableTool(wxToolBarToolBase *WXUNUSED(tool), bool WXUNUSED(enable)) -{ - // TODO -} - -void wxButtonToolBar::DoToggleTool(wxToolBarToolBase *WXUNUSED(tool), bool WXUNUSED(toggle)) -{ - // TODO -} - -void wxButtonToolBar::DoSetToggle(wxToolBarToolBase *WXUNUSED(tool), bool WXUNUSED(toggle)) -{ - // TODO -} - -wxToolBarToolBase *wxButtonToolBar::CreateTool(int id, - const wxString& label, - const wxBitmap& bmpNormal, - const wxBitmap& bmpDisabled, - wxItemKind kind, - wxObject *clientData, - const wxString& shortHelp, - const wxString& longHelp) -{ - return new wxButtonToolBarTool(this, id, label, bmpNormal, bmpDisabled, kind, - clientData, shortHelp, longHelp); -} - -wxToolBarToolBase *wxButtonToolBar::CreateTool(wxControl *control) -{ - return new wxButtonToolBarTool(this, control); -} - -// ---------------------------------------------------------------------------- -// wxButtonToolBar geometry -// ---------------------------------------------------------------------------- - -wxRect wxButtonToolBar::GetToolRect(wxToolBarToolBase *toolBase) const -{ - const wxButtonToolBarTool *tool = (wxButtonToolBarTool *)toolBase; - - wxRect rect; - - wxCHECK_MSG( tool, rect, _T("GetToolRect: NULL tool") ); - - // ensure that we always have the valid tool position - if ( m_needsLayout ) - { - wxConstCast(this, wxButtonToolBar)->DoLayout(); - } - - rect.x = tool->m_x - (m_toolPacking/2); - rect.y = tool->m_y; - - if ( IsVertical() ) - { - if (tool->IsButton()) - { - rect.width = m_defaultWidth; - rect.height = m_defaultHeight; - if (tool->GetButton()) - rect.SetSize(wxSize(tool->m_width, tool->m_height)); - } - else if (tool->IsSeparator()) - { - rect.width = m_defaultWidth; - rect.height = m_widthSeparator; - } - else // control - { - rect.width = tool->m_width; - rect.height = tool->m_height; - } - } - else // horizontal - { - if (tool->IsButton()) - { - rect.width = m_defaultWidth; - rect.height = m_defaultHeight; - if (tool->GetButton()) - rect.SetSize(wxSize(tool->m_width, tool->m_height)); - } - else if (tool->IsSeparator()) - { - rect.width = m_widthSeparator; - rect.height = m_defaultHeight; - } - else // control - { - rect.width = tool->m_width; - rect.height = tool->m_height; - } - } - - rect.width += m_toolPacking; - - return rect; -} - -bool wxButtonToolBar::Realize() -{ - if ( !wxToolBarBase::Realize() ) - return false; - - m_needsLayout = true; - DoLayout(); - - SetInitialSize(wxSize(m_maxWidth, m_maxHeight)); - - return true; -} - -void wxButtonToolBar::DoLayout() -{ - m_needsLayout = false; - - wxCoord x = m_xMargin, - y = m_yMargin; - - int maxHeight = 0; - - const wxCoord widthTool = IsVertical() ? m_defaultHeight : m_defaultWidth; - wxCoord margin = IsVertical() ? m_xMargin : m_yMargin; - wxCoord *pCur = IsVertical() ? &y : &x; - - // calculate the positions of all elements - for ( wxToolBarToolsList::compatibility_iterator node = m_tools.GetFirst(); - node; - node = node->GetNext() ) - { - wxButtonToolBarTool *tool = (wxButtonToolBarTool *) node->GetData(); - - tool->m_x = x; - tool->m_y = y; - - if (tool->IsButton()) - { - if (!tool->GetButton()) - { - wxBitmapButton* bmpButton = new wxBitmapButton(this, tool->GetId(), tool->GetNormalBitmap(), wxPoint(tool->m_x, tool->m_y), wxDefaultSize, - wxBU_AUTODRAW|wxBORDER_NONE); - if (!tool->GetShortHelp().empty()) - bmpButton->SetLabel(tool->GetShortHelp()); - - tool->SetButton(bmpButton); - } - else - { - tool->GetButton()->Move(wxPoint(tool->m_x, tool->m_y)); - } - - int w = widthTool; - if (tool->GetButton()) - { - wxSize sz = tool->GetButton()->GetSize(); - w = sz.x; - - if (m_labelHeight > 0) - { - sz.y += (m_labelHeight + m_labelMargin); - - if (!tool->GetShortHelp().empty()) - { - wxClientDC dc(this); - dc.SetFont(GetFont()); - int tw, th; - dc.GetTextExtent(tool->GetShortHelp(), & tw, & th); - - // If the label is bigger than the icon, the label width - // becomes the new tool width, and we need to centre the - // the bitmap in this box. - if (tw > sz.x) - { - int newX = int(tool->m_x + (tw - sz.x)/2.0); - tool->GetButton()->Move(newX, tool->m_y); - sz.x = tw; - } - } - } - - maxHeight = wxMax(maxHeight, sz.y); - - tool->m_width = sz.x; - tool->m_height = sz.y; - w = sz.x; - } - - *pCur += (w + GetToolPacking()); - } - else if (tool->IsSeparator()) - { - *pCur += m_widthSeparator; - } - else if (!IsVertical()) // horizontal control - { - wxControl *control = tool->GetControl(); - wxSize size = control->GetSize(); - tool->m_y += (m_defaultHeight - size.y)/2; - tool->m_width = size.x; - tool->m_height = size.y; - - *pCur += tool->m_width; - - maxHeight = wxMax(maxHeight, size.y); - } - *pCur += margin; - } - - // calculate the total toolbar size - m_maxWidth = x + 2*m_xMargin; - m_maxHeight = maxHeight + 2*m_yMargin; - - if ((GetWindowStyle() & wxTB_NODIVIDER) == 0) - m_maxHeight += 2; - -} - -wxSize wxButtonToolBar::DoGetBestClientSize() const -{ - return wxSize(m_maxWidth, m_maxHeight); -} - -// receives button commands -void wxButtonToolBar::OnCommand(wxCommandEvent& event) -{ - wxButtonToolBarTool* tool = (wxButtonToolBarTool*) FindById(event.GetId()); - if (!tool) - { - event.Skip(); - return; - } - - if (tool->CanBeToggled()) - tool->Toggle(tool->IsToggled()); - - // TODO: handle toggle items - OnLeftClick(event.GetId(), false); - - if (tool->GetKind() == wxITEM_RADIO) - UnToggleRadioGroup(tool); - - if (tool->CanBeToggled()) - Refresh(); -} - -// paints a border -void wxButtonToolBar::OnPaint(wxPaintEvent& event) -{ - wxPaintDC dc(this); - - dc.SetFont(GetFont()); - dc.SetBackgroundMode(wxTRANSPARENT); - - for ( wxToolBarToolsList::compatibility_iterator node = m_tools.GetFirst(); - node; - node = node->GetNext() ) - { - wxButtonToolBarTool *tool = (wxButtonToolBarTool*) node->GetData(); - wxRect rectTool = GetToolRect(tool); - if (tool->IsToggled()) - { - wxRect backgroundRect = rectTool; - backgroundRect.y = -1; backgroundRect.height = GetClientSize().y + 1; - wxBrush brush(wxColour(219, 219, 219)); - wxPen pen(wxColour(159, 159, 159)); - dc.SetBrush(brush); - dc.SetPen(pen); - dc.DrawRectangle(backgroundRect); - } - - if (m_labelHeight > 0 && !tool->GetShortHelp().empty()) - { - int tw, th; - dc.GetTextExtent(tool->GetShortHelp(), & tw, & th); - - int x = tool->m_x; - dc.DrawText(tool->GetShortHelp(), x, tool->m_y + tool->GetButton()->GetSize().y + m_labelMargin); - } - } - - if ((GetWindowStyle() & wxTB_NODIVIDER) == 0) - { - wxPen pen(wxColour(159, 159, 159)); - dc.SetPen(pen); - int x1 = 0; - int y1 = GetClientSize().y-1; - int x2 = GetClientSize().x; - int y2 = y1; - dc.DrawLine(x1, y1, x2, y2); - } -} - -// detects mouse clicks outside buttons -void wxButtonToolBar::OnLeftUp(wxMouseEvent& event) -{ - if (m_labelHeight > 0) - { - wxButtonToolBarTool* tool = (wxButtonToolBarTool*) FindToolForPosition(event.GetX(), event.GetY()); - if (tool && tool->GetButton() && (event.GetY() > (tool->m_y + tool->GetButton()->GetSize().y))) - { - wxCommandEvent event(wxEVT_COMMAND_BUTTON_CLICKED, tool->GetId()); - event.SetEventObject(tool->GetButton()); - if (!ProcessEvent(event)) - event.Skip(); - } - } -} - -#endif // wxUSE_TOOLBAR && wxUSE_BMPBUTTON +///////////////////////////////////////////////////////////////////////////// +// Name: src/generic/buttonbar.cpp +// Purpose: wxButtonToolBar implementation +// Author: Julian Smart, after Robert Roebling, Vadim Zeitlin, SciTech +// Modified by: +// Created: 2006-04-13 +// Id: $Id: buttonbar.cpp 42816 2006-10-31 08:50:17Z RD $ +// Copyright: (c) Julian Smart, Robert Roebling, Vadim Zeitlin, +// SciTech Software, Inc. +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +// Currently, only for Mac as a toolbar replacement. +#if defined(__WXMAC__) && wxUSE_TOOLBAR && wxUSE_BMPBUTTON + +#include "wx/generic/buttonbar.h" + +#ifndef WX_PRECOMP + #include "wx/utils.h" + #include "wx/app.h" + #include "wx/log.h" + #include "wx/frame.h" + #include "wx/dcclient.h" + #include "wx/settings.h" + #include "wx/image.h" +#endif + +// ---------------------------------------------------------------------------- +// wxButtonToolBarTool: our implementation of wxToolBarToolBase +// ---------------------------------------------------------------------------- + +class WXDLLEXPORT wxButtonToolBarTool : public wxToolBarToolBase +{ +public: + wxButtonToolBarTool(wxButtonToolBar *tbar, + int id, + const wxString& label, + const wxBitmap& bmpNormal, + const wxBitmap& bmpDisabled, + wxItemKind kind, + wxObject *clientData, + const wxString& shortHelp, + const wxString& longHelp) + : wxToolBarToolBase(tbar, id, label, bmpNormal, bmpDisabled, kind, + clientData, shortHelp, longHelp) + { + m_x = m_y = wxDefaultCoord; + m_width = + m_height = 0; + + m_button = NULL; + } + + wxButtonToolBarTool(wxButtonToolBar *tbar, wxControl *control) + : wxToolBarToolBase(tbar, control) + { + m_x = m_y = wxDefaultCoord; + m_width = + m_height = 0; + m_button = NULL; + } + + wxBitmapButton* GetButton() const { return m_button; } + void SetButton(wxBitmapButton* button) { m_button = button; } + +public: + // the tool position (for controls) + wxCoord m_x; + wxCoord m_y; + wxCoord m_width; + wxCoord m_height; + +private: + // the control representing the button + wxBitmapButton* m_button; +}; + +// ============================================================================ +// wxButtonToolBar implementation +// ============================================================================ + +IMPLEMENT_DYNAMIC_CLASS(wxButtonToolBar, wxControl) + +BEGIN_EVENT_TABLE(wxButtonToolBar, wxControl) + EVT_BUTTON(wxID_ANY, wxButtonToolBar::OnCommand) + EVT_PAINT(wxButtonToolBar::OnPaint) + EVT_LEFT_UP(wxButtonToolBar::OnLeftUp) +END_EVENT_TABLE() + +// ---------------------------------------------------------------------------- +// wxButtonToolBar creation +// ---------------------------------------------------------------------------- + +void wxButtonToolBar::Init() +{ + // no tools yet + m_needsLayout = false; + + // unknown widths for the tools and separators + m_widthSeparator = wxDefaultCoord; + + m_maxWidth = m_maxHeight = 0; + + m_labelMargin = 2; + m_labelHeight = 0; + + SetMargins(8, 2); + SetToolPacking(8); +} + +bool wxButtonToolBar::Create(wxWindow *parent, + wxWindowID id, + const wxPoint& pos, + const wxSize& size, + long style, + const wxString& name) +{ + if ( !wxToolBarBase::Create(parent, id, pos, size, style, + wxDefaultValidator, name) ) + { + return false; + } + + // wxColour lightBackground(244, 244, 244); + + wxFont font(wxSMALL_FONT->GetPointSize(), wxNORMAL_FONT->GetFamily(), wxNORMAL_FONT->GetStyle(), wxNORMAL); + SetFont(font); + + // Calculate the label height if necessary + if (GetWindowStyle() & wxTB_TEXT) + { + wxClientDC dc(this); + dc.SetFont(font); + int w, h; + dc.GetTextExtent(wxT("X"), & w, & h); + m_labelHeight = h; + } + return true; +} + +wxButtonToolBar::~wxButtonToolBar() +{ +} + +// ---------------------------------------------------------------------------- +// wxButtonToolBar tool-related methods +// ---------------------------------------------------------------------------- + +wxToolBarToolBase *wxButtonToolBar::FindToolForPosition(wxCoord x, wxCoord y) const +{ + // check the "other" direction first: it must be inside the toolbar or we + // don't risk finding anything + if ( IsVertical() ) + { + if ( x < 0 || x > m_maxWidth ) + return NULL; + + // we always use x, even for a vertical toolbar, this makes the code + // below simpler + x = y; + } + else // horizontal + { + if ( y < 0 || y > m_maxHeight ) + return NULL; + } + + for ( wxToolBarToolsList::compatibility_iterator node = m_tools.GetFirst(); + node; + node = node->GetNext() ) + { + wxButtonToolBarTool *tool = (wxButtonToolBarTool*) node->GetData(); + wxRect rectTool = GetToolRect(tool); + + wxCoord startTool, endTool; + GetRectLimits(rectTool, &startTool, &endTool); + + if ( x >= startTool && x <= endTool ) + { + // don't return the separators from here, they don't accept any + // input anyhow + return tool->IsSeparator() ? NULL : tool; + } + } + + return NULL; +} + +void wxButtonToolBar::GetRectLimits(const wxRect& rect, + wxCoord *start, + wxCoord *end) const +{ + wxCHECK_RET( start && end, _T("NULL pointer in GetRectLimits") ); + + if ( IsVertical() ) + { + *start = rect.GetTop(); + *end = rect.GetBottom(); + } + else // horizontal + { + *start = rect.GetLeft(); + *end = rect.GetRight(); + } +} + + +void wxButtonToolBar::SetToolShortHelp(int id, const wxString& help) +{ + wxToolBarToolBase *tool = FindById(id); + + wxCHECK_RET( tool, _T("SetToolShortHelp: no such tool") ); + + // TODO: set tooltip/short help + tool->SetShortHelp(help); +} + +bool wxButtonToolBar::DoInsertTool(size_t WXUNUSED(pos), + wxToolBarToolBase * WXUNUSED(tool)) +{ + return true; +} + +bool wxButtonToolBar::DoDeleteTool(size_t WXUNUSED(pos), + wxToolBarToolBase * WXUNUSED(tool)) +{ + // TODO + return true; +} + +void wxButtonToolBar::DoEnableTool(wxToolBarToolBase *WXUNUSED(tool), bool WXUNUSED(enable)) +{ + // TODO +} + +void wxButtonToolBar::DoToggleTool(wxToolBarToolBase *WXUNUSED(tool), bool WXUNUSED(toggle)) +{ + // TODO +} + +void wxButtonToolBar::DoSetToggle(wxToolBarToolBase *WXUNUSED(tool), bool WXUNUSED(toggle)) +{ + // TODO +} + +wxToolBarToolBase *wxButtonToolBar::CreateTool(int id, + const wxString& label, + const wxBitmap& bmpNormal, + const wxBitmap& bmpDisabled, + wxItemKind kind, + wxObject *clientData, + const wxString& shortHelp, + const wxString& longHelp) +{ + return new wxButtonToolBarTool(this, id, label, bmpNormal, bmpDisabled, kind, + clientData, shortHelp, longHelp); +} + +wxToolBarToolBase *wxButtonToolBar::CreateTool(wxControl *control) +{ + return new wxButtonToolBarTool(this, control); +} + +// ---------------------------------------------------------------------------- +// wxButtonToolBar geometry +// ---------------------------------------------------------------------------- + +wxRect wxButtonToolBar::GetToolRect(wxToolBarToolBase *toolBase) const +{ + const wxButtonToolBarTool *tool = (wxButtonToolBarTool *)toolBase; + + wxRect rect; + + wxCHECK_MSG( tool, rect, _T("GetToolRect: NULL tool") ); + + // ensure that we always have the valid tool position + if ( m_needsLayout ) + { + wxConstCast(this, wxButtonToolBar)->DoLayout(); + } + + rect.x = tool->m_x - (m_toolPacking/2); + rect.y = tool->m_y; + + if ( IsVertical() ) + { + if (tool->IsButton()) + { + rect.width = m_defaultWidth; + rect.height = m_defaultHeight; + if (tool->GetButton()) + rect.SetSize(wxSize(tool->m_width, tool->m_height)); + } + else if (tool->IsSeparator()) + { + rect.width = m_defaultWidth; + rect.height = m_widthSeparator; + } + else // control + { + rect.width = tool->m_width; + rect.height = tool->m_height; + } + } + else // horizontal + { + if (tool->IsButton()) + { + rect.width = m_defaultWidth; + rect.height = m_defaultHeight; + if (tool->GetButton()) + rect.SetSize(wxSize(tool->m_width, tool->m_height)); + } + else if (tool->IsSeparator()) + { + rect.width = m_widthSeparator; + rect.height = m_defaultHeight; + } + else // control + { + rect.width = tool->m_width; + rect.height = tool->m_height; + } + } + + rect.width += m_toolPacking; + + return rect; +} + +bool wxButtonToolBar::Realize() +{ + if ( !wxToolBarBase::Realize() ) + return false; + + m_needsLayout = true; + DoLayout(); + + SetInitialSize(wxSize(m_maxWidth, m_maxHeight)); + + return true; +} + +void wxButtonToolBar::DoLayout() +{ + m_needsLayout = false; + + wxCoord x = m_xMargin, + y = m_yMargin; + + int maxHeight = 0; + + const wxCoord widthTool = IsVertical() ? m_defaultHeight : m_defaultWidth; + wxCoord margin = IsVertical() ? m_xMargin : m_yMargin; + wxCoord *pCur = IsVertical() ? &y : &x; + + // calculate the positions of all elements + for ( wxToolBarToolsList::compatibility_iterator node = m_tools.GetFirst(); + node; + node = node->GetNext() ) + { + wxButtonToolBarTool *tool = (wxButtonToolBarTool *) node->GetData(); + + tool->m_x = x; + tool->m_y = y; + + if (tool->IsButton()) + { + if (!tool->GetButton()) + { + wxBitmapButton* bmpButton = new wxBitmapButton(this, tool->GetId(), tool->GetNormalBitmap(), wxPoint(tool->m_x, tool->m_y), wxDefaultSize, + wxBU_AUTODRAW|wxBORDER_NONE); + if (!tool->GetShortHelp().empty()) + bmpButton->SetLabel(tool->GetShortHelp()); + + tool->SetButton(bmpButton); + } + else + { + tool->GetButton()->Move(wxPoint(tool->m_x, tool->m_y)); + } + + int w = widthTool; + if (tool->GetButton()) + { + wxSize sz = tool->GetButton()->GetSize(); + w = sz.x; + + if (m_labelHeight > 0) + { + sz.y += (m_labelHeight + m_labelMargin); + + if (!tool->GetShortHelp().empty()) + { + wxClientDC dc(this); + dc.SetFont(GetFont()); + int tw, th; + dc.GetTextExtent(tool->GetShortHelp(), & tw, & th); + + // If the label is bigger than the icon, the label width + // becomes the new tool width, and we need to centre the + // the bitmap in this box. + if (tw > sz.x) + { + int newX = int(tool->m_x + (tw - sz.x)/2.0); + tool->GetButton()->Move(newX, tool->m_y); + sz.x = tw; + } + } + } + + maxHeight = wxMax(maxHeight, sz.y); + + tool->m_width = sz.x; + tool->m_height = sz.y; + w = sz.x; + } + + *pCur += (w + GetToolPacking()); + } + else if (tool->IsSeparator()) + { + *pCur += m_widthSeparator; + } + else if (!IsVertical()) // horizontal control + { + wxControl *control = tool->GetControl(); + wxSize size = control->GetSize(); + tool->m_y += (m_defaultHeight - size.y)/2; + tool->m_width = size.x; + tool->m_height = size.y; + + *pCur += tool->m_width; + + maxHeight = wxMax(maxHeight, size.y); + } + *pCur += margin; + } + + // calculate the total toolbar size + m_maxWidth = x + 2*m_xMargin; + m_maxHeight = maxHeight + 2*m_yMargin; + + if ((GetWindowStyle() & wxTB_NODIVIDER) == 0) + m_maxHeight += 2; + +} + +wxSize wxButtonToolBar::DoGetBestClientSize() const +{ + return wxSize(m_maxWidth, m_maxHeight); +} + +// receives button commands +void wxButtonToolBar::OnCommand(wxCommandEvent& event) +{ + wxButtonToolBarTool* tool = (wxButtonToolBarTool*) FindById(event.GetId()); + if (!tool) + { + event.Skip(); + return; + } + + if (tool->CanBeToggled()) + tool->Toggle(tool->IsToggled()); + + // TODO: handle toggle items + OnLeftClick(event.GetId(), false); + + if (tool->GetKind() == wxITEM_RADIO) + UnToggleRadioGroup(tool); + + if (tool->CanBeToggled()) + Refresh(); +} + +// paints a border +void wxButtonToolBar::OnPaint(wxPaintEvent& event) +{ + wxPaintDC dc(this); + + dc.SetFont(GetFont()); + dc.SetBackgroundMode(wxTRANSPARENT); + + for ( wxToolBarToolsList::compatibility_iterator node = m_tools.GetFirst(); + node; + node = node->GetNext() ) + { + wxButtonToolBarTool *tool = (wxButtonToolBarTool*) node->GetData(); + wxRect rectTool = GetToolRect(tool); + if (tool->IsToggled()) + { + wxRect backgroundRect = rectTool; + backgroundRect.y = -1; backgroundRect.height = GetClientSize().y + 1; + wxBrush brush(wxColour(219, 219, 219)); + wxPen pen(wxColour(159, 159, 159)); + dc.SetBrush(brush); + dc.SetPen(pen); + dc.DrawRectangle(backgroundRect); + } + + if (m_labelHeight > 0 && !tool->GetShortHelp().empty()) + { + int tw, th; + dc.GetTextExtent(tool->GetShortHelp(), & tw, & th); + + int x = tool->m_x; + dc.DrawText(tool->GetShortHelp(), x, tool->m_y + tool->GetButton()->GetSize().y + m_labelMargin); + } + } + + if ((GetWindowStyle() & wxTB_NODIVIDER) == 0) + { + wxPen pen(wxColour(159, 159, 159)); + dc.SetPen(pen); + int x1 = 0; + int y1 = GetClientSize().y-1; + int x2 = GetClientSize().x; + int y2 = y1; + dc.DrawLine(x1, y1, x2, y2); + } +} + +// detects mouse clicks outside buttons +void wxButtonToolBar::OnLeftUp(wxMouseEvent& event) +{ + if (m_labelHeight > 0) + { + wxButtonToolBarTool* tool = (wxButtonToolBarTool*) FindToolForPosition(event.GetX(), event.GetY()); + if (tool && tool->GetButton() && (event.GetY() > (tool->m_y + tool->GetButton()->GetSize().y))) + { + wxCommandEvent event(wxEVT_COMMAND_BUTTON_CLICKED, tool->GetId()); + event.SetEventObject(tool->GetButton()); + if (!ProcessEvent(event)) + event.Skip(); + } + } +} + +#endif // wxUSE_TOOLBAR && wxUSE_BMPBUTTON diff --git a/Externals/wxWidgets/src/generic/calctrl.cpp b/Externals/wxWidgets/src/generic/calctrl.cpp index 6624a6b971..44cb11a91d 100644 --- a/Externals/wxWidgets/src/generic/calctrl.cpp +++ b/Externals/wxWidgets/src/generic/calctrl.cpp @@ -1,1838 +1,1838 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: src/generic/calctrl.cpp -// Purpose: implementation fo the generic wxCalendarCtrl -// Author: Vadim Zeitlin -// Modified by: -// Created: 29.12.99 -// RCS-ID: $Id: calctrl.cpp 53987 2008-06-05 15:48:55Z VZ $ -// Copyright: (c) 1999 Vadim Zeitlin -// Licence: wxWindows licence -/////////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#ifndef WX_PRECOMP - #include "wx/dcclient.h" - #include "wx/settings.h" - #include "wx/brush.h" - #include "wx/combobox.h" - #include "wx/listbox.h" - #include "wx/stattext.h" - #include "wx/textctrl.h" -#endif //WX_PRECOMP - -#if wxUSE_CALENDARCTRL - -#include "wx/spinctrl.h" - -// if wxDatePickerCtrl code doesn't define the date event, do it here as we -// need it as well -#if !wxUSE_DATEPICKCTRL - #define _WX_DEFINE_DATE_EVENTS_ -#endif - -#include "wx/calctrl.h" - -#define DEBUG_PAINT 0 - -// ---------------------------------------------------------------------------- -// wxWin macros -// ---------------------------------------------------------------------------- - -BEGIN_EVENT_TABLE(wxCalendarCtrl, wxControl) - EVT_PAINT(wxCalendarCtrl::OnPaint) - - EVT_CHAR(wxCalendarCtrl::OnChar) - - EVT_LEFT_DOWN(wxCalendarCtrl::OnClick) - EVT_LEFT_DCLICK(wxCalendarCtrl::OnDClick) - - EVT_SYS_COLOUR_CHANGED(wxCalendarCtrl::OnSysColourChanged) -END_EVENT_TABLE() - -#if wxUSE_EXTENDED_RTTI -WX_DEFINE_FLAGS( wxCalendarCtrlStyle ) - -wxBEGIN_FLAGS( wxCalendarCtrlStyle ) - // new style border flags, we put them first to - // use them for streaming out - wxFLAGS_MEMBER(wxBORDER_SIMPLE) - wxFLAGS_MEMBER(wxBORDER_SUNKEN) - wxFLAGS_MEMBER(wxBORDER_DOUBLE) - wxFLAGS_MEMBER(wxBORDER_RAISED) - wxFLAGS_MEMBER(wxBORDER_STATIC) - wxFLAGS_MEMBER(wxBORDER_NONE) - - // old style border flags - wxFLAGS_MEMBER(wxSIMPLE_BORDER) - wxFLAGS_MEMBER(wxSUNKEN_BORDER) - wxFLAGS_MEMBER(wxDOUBLE_BORDER) - wxFLAGS_MEMBER(wxRAISED_BORDER) - wxFLAGS_MEMBER(wxSTATIC_BORDER) - wxFLAGS_MEMBER(wxBORDER) - - // standard window styles - wxFLAGS_MEMBER(wxTAB_TRAVERSAL) - wxFLAGS_MEMBER(wxCLIP_CHILDREN) - wxFLAGS_MEMBER(wxTRANSPARENT_WINDOW) - wxFLAGS_MEMBER(wxWANTS_CHARS) - wxFLAGS_MEMBER(wxFULL_REPAINT_ON_RESIZE) - wxFLAGS_MEMBER(wxALWAYS_SHOW_SB ) - wxFLAGS_MEMBER(wxVSCROLL) - wxFLAGS_MEMBER(wxHSCROLL) - - wxFLAGS_MEMBER(wxCAL_SUNDAY_FIRST) - wxFLAGS_MEMBER(wxCAL_MONDAY_FIRST) - wxFLAGS_MEMBER(wxCAL_SHOW_HOLIDAYS) - wxFLAGS_MEMBER(wxCAL_NO_YEAR_CHANGE) - wxFLAGS_MEMBER(wxCAL_NO_MONTH_CHANGE) - wxFLAGS_MEMBER(wxCAL_SEQUENTIAL_MONTH_SELECTION) - wxFLAGS_MEMBER(wxCAL_SHOW_SURROUNDING_WEEKS) - -wxEND_FLAGS( wxCalendarCtrlStyle ) - -IMPLEMENT_DYNAMIC_CLASS_XTI(wxCalendarCtrl, wxControl,"wx/calctrl.h") - -wxBEGIN_PROPERTIES_TABLE(wxCalendarCtrl) - wxEVENT_RANGE_PROPERTY( Updated , wxEVT_CALENDAR_SEL_CHANGED , wxEVT_CALENDAR_WEEKDAY_CLICKED , wxCalendarEvent ) - wxHIDE_PROPERTY( Children ) - wxPROPERTY( Date,wxDateTime, SetDate , GetDate, , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) - wxPROPERTY_FLAGS( WindowStyle , wxCalendarCtrlStyle , long , SetWindowStyleFlag , GetWindowStyleFlag , , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // style -wxEND_PROPERTIES_TABLE() - -wxBEGIN_HANDLERS_TABLE(wxCalendarCtrl) -wxEND_HANDLERS_TABLE() - -wxCONSTRUCTOR_6( wxCalendarCtrl , wxWindow* , Parent , wxWindowID , Id , wxDateTime , Date , wxPoint , Position , wxSize , Size , long , WindowStyle ) -#else -IMPLEMENT_DYNAMIC_CLASS(wxCalendarCtrl, wxControl) -#endif -IMPLEMENT_DYNAMIC_CLASS(wxCalendarEvent, wxDateEvent) - -// ---------------------------------------------------------------------------- -// events -// ---------------------------------------------------------------------------- - -DEFINE_EVENT_TYPE(wxEVT_CALENDAR_SEL_CHANGED) -DEFINE_EVENT_TYPE(wxEVT_CALENDAR_DAY_CHANGED) -DEFINE_EVENT_TYPE(wxEVT_CALENDAR_MONTH_CHANGED) -DEFINE_EVENT_TYPE(wxEVT_CALENDAR_YEAR_CHANGED) -DEFINE_EVENT_TYPE(wxEVT_CALENDAR_DOUBLECLICKED) -DEFINE_EVENT_TYPE(wxEVT_CALENDAR_WEEKDAY_CLICKED) - -// ============================================================================ -// implementation -// ============================================================================ - -// ---------------------------------------------------------------------------- -// wxCalendarCtrl -// ---------------------------------------------------------------------------- - -wxCalendarCtrl::wxCalendarCtrl(wxWindow *parent, - wxWindowID id, - const wxDateTime& date, - const wxPoint& pos, - const wxSize& size, - long style, - const wxString& name) -{ - Init(); - - (void)Create(parent, id, date, pos, size, style, name); -} - -void wxCalendarCtrl::Init() -{ - m_comboMonth = NULL; - m_spinYear = NULL; - m_staticYear = NULL; - m_staticMonth = NULL; - - m_userChangedYear = false; - - m_widthCol = - m_heightRow = 0; - - wxDateTime::WeekDay wd; - for ( wd = wxDateTime::Sun; wd < wxDateTime::Inv_WeekDay; wxNextWDay(wd) ) - { - m_weekdays[wd] = wxDateTime::GetWeekDayName(wd, wxDateTime::Name_Abbr); - } - - for ( size_t n = 0; n < WXSIZEOF(m_attrs); n++ ) - { - m_attrs[n] = NULL; - } - - InitColours(); -} - -void wxCalendarCtrl::InitColours() -{ - m_colHighlightFg = wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT); - m_colHighlightBg = wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT); - m_colBackground = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW); - m_colSorrounding = wxSystemSettings::GetColour(wxSYS_COLOUR_GRAYTEXT); - - m_colHolidayFg = *wxRED; - // don't set m_colHolidayBg - by default, same as our bg colour - - m_colHeaderFg = *wxBLUE; - m_colHeaderBg = *wxLIGHT_GREY; -} - -bool wxCalendarCtrl::Create(wxWindow *parent, - wxWindowID id, - const wxDateTime& date, - const wxPoint& pos, - const wxSize& size, - long style, - const wxString& name) -{ - if ( !wxControl::Create(parent, id, pos, size, - style | wxCLIP_CHILDREN | wxWANTS_CHARS | wxFULL_REPAINT_ON_RESIZE, - wxDefaultValidator, name) ) - { - return false; - } - - // needed to get the arrow keys normally used for the dialog navigation - SetWindowStyle(style | wxWANTS_CHARS); - - m_date = date.IsValid() ? date : wxDateTime::Today(); - - m_lowdate = wxDefaultDateTime; - m_highdate = wxDefaultDateTime; - - if ( !HasFlag(wxCAL_SEQUENTIAL_MONTH_SELECTION) ) - { - CreateYearSpinCtrl(); - m_staticYear = new wxStaticText(GetParent(), wxID_ANY, m_date.Format(_T("%Y")), - wxDefaultPosition, wxDefaultSize, - wxALIGN_CENTRE); - - CreateMonthComboBox(); - m_staticMonth = new wxStaticText(GetParent(), wxID_ANY, m_date.Format(_T("%B")), - wxDefaultPosition, wxDefaultSize, - wxALIGN_CENTRE); - } - - ShowCurrentControls(); - - // we need to set the position as well because the main control position - // is not the same as the one specified in pos if we have the controls - // above it - SetInitialSize(size); - SetPosition(pos); - - // Since we don't paint the whole background make sure that the platform - // will use the right one. - SetBackgroundColour(m_colBackground); - - SetHolidayAttrs(); - - return true; -} - -wxCalendarCtrl::~wxCalendarCtrl() -{ - for ( size_t n = 0; n < WXSIZEOF(m_attrs); n++ ) - { - delete m_attrs[n]; - } - - if ( !HasFlag(wxCAL_SEQUENTIAL_MONTH_SELECTION) ) - { - delete m_comboMonth; - delete m_staticMonth; - delete m_spinYear; - delete m_staticYear; - } -} - -void wxCalendarCtrl::SetWindowStyleFlag(long style) -{ - // changing this style doesn't work because the controls are not - // created/shown/hidden accordingly - wxASSERT_MSG( (style & wxCAL_SEQUENTIAL_MONTH_SELECTION) == - (m_windowStyle & wxCAL_SEQUENTIAL_MONTH_SELECTION), - _T("wxCAL_SEQUENTIAL_MONTH_SELECTION can't be changed after creation") ); - - wxControl::SetWindowStyleFlag(style); -} - -// ---------------------------------------------------------------------------- -// Create the wxComboBox and wxSpinCtrl -// ---------------------------------------------------------------------------- - -void wxCalendarCtrl::CreateMonthComboBox() -{ - m_comboMonth = new wxComboBox(GetParent(), wxID_ANY, - wxEmptyString, - wxDefaultPosition, - wxDefaultSize, - 0, NULL, - wxCB_READONLY | wxCLIP_SIBLINGS); - - wxDateTime::Month m; - for ( m = wxDateTime::Jan; m < wxDateTime::Inv_Month; wxNextMonth(m) ) - { - m_comboMonth->Append(wxDateTime::GetMonthName(m)); - } - - m_comboMonth->SetSelection(GetDate().GetMonth()); - m_comboMonth->SetSize(wxDefaultCoord, - wxDefaultCoord, - wxDefaultCoord, - wxDefaultCoord, - wxSIZE_AUTO_WIDTH|wxSIZE_AUTO_HEIGHT); - - m_comboMonth->Connect(m_comboMonth->GetId(), wxEVT_COMMAND_COMBOBOX_SELECTED, - wxCommandEventHandler(wxCalendarCtrl::OnMonthChange), - NULL, this); -} - -void wxCalendarCtrl::CreateYearSpinCtrl() -{ - m_spinYear = new wxSpinCtrl(GetParent(), wxID_ANY, - GetDate().Format(_T("%Y")), - wxDefaultPosition, - wxDefaultSize, - wxSP_ARROW_KEYS | wxCLIP_SIBLINGS, - -4300, 10000, GetDate().GetYear()); - - m_spinYear->Connect(m_spinYear->GetId(), wxEVT_COMMAND_TEXT_UPDATED, - wxCommandEventHandler(wxCalendarCtrl::OnYearTextChange), - NULL, this); - - m_spinYear->Connect(m_spinYear->GetId(), wxEVT_COMMAND_SPINCTRL_UPDATED, - wxCommandEventHandler(wxCalendarCtrl::OnYearChange), - NULL, this); -} - -// ---------------------------------------------------------------------------- -// forward wxWin functions to subcontrols -// ---------------------------------------------------------------------------- - -bool wxCalendarCtrl::Destroy() -{ - if ( m_staticYear ) - m_staticYear->Destroy(); - if ( m_spinYear ) - m_spinYear->Destroy(); - if ( m_comboMonth ) - m_comboMonth->Destroy(); - if ( m_staticMonth ) - m_staticMonth->Destroy(); - - m_staticYear = NULL; - m_spinYear = NULL; - m_comboMonth = NULL; - m_staticMonth = NULL; - - return wxControl::Destroy(); -} - -bool wxCalendarCtrl::Show(bool show) -{ - if ( !wxControl::Show(show) ) - { - return false; - } - - if ( !(GetWindowStyle() & wxCAL_SEQUENTIAL_MONTH_SELECTION) ) - { - if ( GetMonthControl() ) - { - GetMonthControl()->Show(show); - GetYearControl()->Show(show); - } - } - - return true; -} - -bool wxCalendarCtrl::Enable(bool enable) -{ - if ( !wxControl::Enable(enable) ) - { - return false; - } - - if ( !(GetWindowStyle() & wxCAL_SEQUENTIAL_MONTH_SELECTION) ) - { - GetMonthControl()->Enable(enable); - GetYearControl()->Enable(enable); - } - - return true; -} - -// ---------------------------------------------------------------------------- -// enable/disable month/year controls -// ---------------------------------------------------------------------------- - -void wxCalendarCtrl::ShowCurrentControls() -{ - if ( !HasFlag(wxCAL_SEQUENTIAL_MONTH_SELECTION) ) - { - if ( AllowMonthChange() ) - { - m_comboMonth->Show(); - m_staticMonth->Hide(); - - if ( AllowYearChange() ) - { - m_spinYear->Show(); - m_staticYear->Hide(); - - // skip the rest - return; - } - } - else - { - m_comboMonth->Hide(); - m_staticMonth->Show(); - } - - // year change not allowed here - m_spinYear->Hide(); - m_staticYear->Show(); - } - //else: these controls are not even created, don't show/hide them -} - -wxControl *wxCalendarCtrl::GetMonthControl() const -{ - return AllowMonthChange() ? (wxControl *)m_comboMonth : (wxControl *)m_staticMonth; -} - -wxControl *wxCalendarCtrl::GetYearControl() const -{ - return AllowYearChange() ? (wxControl *)m_spinYear : (wxControl *)m_staticYear; -} - -void wxCalendarCtrl::EnableYearChange(bool enable) -{ - if ( enable != AllowYearChange() ) - { - long style = GetWindowStyle(); - if ( enable ) - style &= ~wxCAL_NO_YEAR_CHANGE; - else - style |= wxCAL_NO_YEAR_CHANGE; - SetWindowStyle(style); - - ShowCurrentControls(); - if ( GetWindowStyle() & wxCAL_SEQUENTIAL_MONTH_SELECTION ) - { - Refresh(); - } - } -} - -void wxCalendarCtrl::EnableMonthChange(bool enable) -{ - if ( enable != AllowMonthChange() ) - { - long style = GetWindowStyle(); - if ( enable ) - style &= ~wxCAL_NO_MONTH_CHANGE; - else - style |= wxCAL_NO_MONTH_CHANGE; - SetWindowStyle(style); - - ShowCurrentControls(); - if ( GetWindowStyle() & wxCAL_SEQUENTIAL_MONTH_SELECTION ) - { - Refresh(); - } - } -} - -// ---------------------------------------------------------------------------- -// changing date -// ---------------------------------------------------------------------------- - -bool wxCalendarCtrl::SetDate(const wxDateTime& date) -{ - bool retval = true; - - bool sameMonth = m_date.GetMonth() == date.GetMonth(), - sameYear = m_date.GetYear() == date.GetYear(); - - if ( IsDateInRange(date) ) - { - if ( sameMonth && sameYear ) - { - // just change the day - ChangeDay(date); - } - else - { - if ( AllowMonthChange() && (AllowYearChange() || sameYear) ) - { - // change everything - m_date = date; - - if ( !(GetWindowStyle() & wxCAL_SEQUENTIAL_MONTH_SELECTION) ) - { - // update the controls - m_comboMonth->SetSelection(m_date.GetMonth()); - - if ( AllowYearChange() ) - { - if ( !m_userChangedYear ) - m_spinYear->SetValue(m_date.Format(_T("%Y"))); - } - } - - // as the month changed, holidays did too - SetHolidayAttrs(); - - // update the calendar - Refresh(); - } - else - { - // forbidden - retval = false; - } - } - } - - m_userChangedYear = false; - - return retval; -} - -void wxCalendarCtrl::ChangeDay(const wxDateTime& date) -{ - if ( m_date != date ) - { - // we need to refresh the row containing the old date and the one - // containing the new one - wxDateTime dateOld = m_date; - m_date = date; - - RefreshDate(dateOld); - - // if the date is in the same row, it was already drawn correctly - if ( GetWeek(m_date) != GetWeek(dateOld) ) - { - RefreshDate(m_date); - } - } -} - -void wxCalendarCtrl::SetDateAndNotify(const wxDateTime& date) -{ - wxDateTime::Tm tm1 = m_date.GetTm(), - tm2 = date.GetTm(); - - wxEventType type; - if ( tm1.year != tm2.year ) - type = wxEVT_CALENDAR_YEAR_CHANGED; - else if ( tm1.mon != tm2.mon ) - type = wxEVT_CALENDAR_MONTH_CHANGED; - else if ( tm1.mday != tm2.mday ) - type = wxEVT_CALENDAR_DAY_CHANGED; - else - return; - - if ( SetDate(date) ) - { - GenerateEvents(type, wxEVT_CALENDAR_SEL_CHANGED); - } -} - -// ---------------------------------------------------------------------------- -// date range -// ---------------------------------------------------------------------------- - -bool wxCalendarCtrl::SetLowerDateLimit(const wxDateTime& date /* = wxDefaultDateTime */) -{ - bool retval = true; - - if ( !(date.IsValid()) || ( ( m_highdate.IsValid() ) ? ( date <= m_highdate ) : true ) ) - { - m_lowdate = date; - } - else - { - retval = false; - } - - return retval; -} - -bool wxCalendarCtrl::SetUpperDateLimit(const wxDateTime& date /* = wxDefaultDateTime */) -{ - bool retval = true; - - if ( !(date.IsValid()) || ( ( m_lowdate.IsValid() ) ? ( date >= m_lowdate ) : true ) ) - { - m_highdate = date; - } - else - { - retval = false; - } - - return retval; -} - -bool wxCalendarCtrl::SetDateRange(const wxDateTime& lowerdate /* = wxDefaultDateTime */, const wxDateTime& upperdate /* = wxDefaultDateTime */) -{ - bool retval = true; - - if ( - ( !( lowerdate.IsValid() ) || ( ( upperdate.IsValid() ) ? ( lowerdate <= upperdate ) : true ) ) && - ( !( upperdate.IsValid() ) || ( ( lowerdate.IsValid() ) ? ( upperdate >= lowerdate ) : true ) ) ) - { - m_lowdate = lowerdate; - m_highdate = upperdate; - } - else - { - retval = false; - } - - return retval; -} - -// ---------------------------------------------------------------------------- -// date helpers -// ---------------------------------------------------------------------------- - -wxDateTime wxCalendarCtrl::GetStartDate() const -{ - wxDateTime::Tm tm = m_date.GetTm(); - - wxDateTime date = wxDateTime(1, tm.mon, tm.year); - - // rewind back - date.SetToPrevWeekDay(GetWindowStyle() & wxCAL_MONDAY_FIRST - ? wxDateTime::Mon : wxDateTime::Sun); - - if ( GetWindowStyle() & wxCAL_SHOW_SURROUNDING_WEEKS ) - { - // We want to offset the calendar if we start on the first.. - if ( date.GetDay() == 1 ) - { - date -= wxDateSpan::Week(); - } - } - - return date; -} - -bool wxCalendarCtrl::IsDateShown(const wxDateTime& date) const -{ - if ( !(GetWindowStyle() & wxCAL_SHOW_SURROUNDING_WEEKS) ) - { - return date.GetMonth() == m_date.GetMonth(); - } - else - { - return true; - } -} - -bool wxCalendarCtrl::IsDateInRange(const wxDateTime& date) const -{ - // Check if the given date is in the range specified - return ( ( ( m_lowdate.IsValid() ) ? ( date >= m_lowdate ) : true ) - && ( ( m_highdate.IsValid() ) ? ( date <= m_highdate ) : true ) ); -} - -bool wxCalendarCtrl::ChangeYear(wxDateTime* target) const -{ - bool retval = false; - - if ( !(IsDateInRange(*target)) ) - { - if ( target->GetYear() < m_date.GetYear() ) - { - if ( target->GetYear() >= GetLowerDateLimit().GetYear() ) - { - *target = GetLowerDateLimit(); - retval = true; - } - else - { - *target = m_date; - } - } - else - { - if ( target->GetYear() <= GetUpperDateLimit().GetYear() ) - { - *target = GetUpperDateLimit(); - retval = true; - } - else - { - *target = m_date; - } - } - } - else - { - retval = true; - } - - return retval; -} - -bool wxCalendarCtrl::ChangeMonth(wxDateTime* target) const -{ - bool retval = true; - - if ( !(IsDateInRange(*target)) ) - { - retval = false; - - if ( target->GetMonth() < m_date.GetMonth() ) - { - *target = GetLowerDateLimit(); - } - else - { - *target = GetUpperDateLimit(); - } - } - - return retval; -} - -size_t wxCalendarCtrl::GetWeek(const wxDateTime& date) const -{ - size_t retval = date.GetWeekOfMonth(GetWindowStyle() & wxCAL_MONDAY_FIRST - ? wxDateTime::Monday_First - : wxDateTime::Sunday_First); - - if ( (GetWindowStyle() & wxCAL_SHOW_SURROUNDING_WEEKS) ) - { - // we need to offset an extra week if we "start" on the 1st of the month - wxDateTime::Tm tm = date.GetTm(); - - wxDateTime datetest = wxDateTime(1, tm.mon, tm.year); - - // rewind back - datetest.SetToPrevWeekDay(GetWindowStyle() & wxCAL_MONDAY_FIRST - ? wxDateTime::Mon : wxDateTime::Sun); - - if ( datetest.GetDay() == 1 ) - { - retval += 1; - } - } - - return retval; -} - -// ---------------------------------------------------------------------------- -// size management -// ---------------------------------------------------------------------------- - -// this is a composite control and it must arrange its parts each time its -// size or position changes: the combobox and spinctrl are along the top of -// the available area and the calendar takes up therest of the space - -// the static controls are supposed to be always smaller than combo/spin so we -// always use the latter for size calculations and position the static to take -// the same space - -// the constants used for the layout -#define VERT_MARGIN 5 // distance between combo and calendar -#ifdef __WXMAC__ -#define HORZ_MARGIN 5 // spin -#else -#define HORZ_MARGIN 15 // spin -#endif -wxSize wxCalendarCtrl::DoGetBestSize() const -{ - // calc the size of the calendar - ((wxCalendarCtrl *)this)->RecalcGeometry(); // const_cast - - wxCoord width = 7*m_widthCol, - height = 7*m_heightRow + m_rowOffset + VERT_MARGIN; - - if ( !HasFlag(wxCAL_SEQUENTIAL_MONTH_SELECTION) ) - { - // the combobox doesn't report its height correctly (it returns the - // height including the drop down list) so don't use it - height += m_spinYear->GetBestSize().y; - - - wxCoord w2 = m_comboMonth->GetBestSize().x + HORZ_MARGIN + GetCharWidth()*6; - if (width < w2) - width = w2; - } - - if ( !HasFlag(wxBORDER_NONE) ) - { - // the border would clip the last line otherwise - height += 6; - width += 4; - } - - wxSize best(width, height); - CacheBestSize(best); - return best; -} - -void wxCalendarCtrl::DoSetSize(int x, int y, - int width, int height, - int sizeFlags) -{ - wxControl::DoSetSize(x, y, width, height, sizeFlags); -} - -void wxCalendarCtrl::DoMoveWindow(int x, int y, int width, int height) -{ - int yDiff; - - if ( !HasFlag(wxCAL_SEQUENTIAL_MONTH_SELECTION) && m_staticMonth ) - { - wxSize sizeCombo = m_comboMonth->GetEffectiveMinSize(); - wxSize sizeStatic = m_staticMonth->GetSize(); - wxSize sizeSpin = m_spinYear->GetSize(); - - // wxMSW sometimes reports the wrong combo height, - // so on this platform we'll use the spin control - // height instead. -#ifdef __WXMSW__ - int maxHeight = sizeSpin.y; - int requiredSpinHeight = -1; -#else - int maxHeight = sizeCombo.y; - int requiredSpinHeight = sizeCombo.y; -#endif - int dy = (maxHeight - sizeStatic.y) / 2; - m_comboMonth->Move(x, y); - m_staticMonth->SetSize(x, y + dy, sizeCombo.x, -1, sizeStatic.y); - - int xDiff = sizeCombo.x + HORZ_MARGIN; - - m_spinYear->SetSize(x + xDiff, y, width - xDiff, requiredSpinHeight); - m_staticYear->SetSize(x + xDiff, y + dy, width - xDiff, sizeStatic.y); - - yDiff = wxMax(sizeSpin.y, maxHeight) + VERT_MARGIN; - } - else // no controls on the top - { - yDiff = 0; - } - - wxControl::DoMoveWindow(x, y + yDiff, width, height - yDiff); -} - -void wxCalendarCtrl::DoGetPosition(int *x, int *y) const -{ - wxControl::DoGetPosition(x, y); -#ifndef __WXPM__ - if ( !HasFlag(wxCAL_SEQUENTIAL_MONTH_SELECTION) && GetMonthControl() ) - { - // our real top corner is not in this position - if ( y ) - { - *y -= GetMonthControl()->GetSize().y + VERT_MARGIN; - } - } -#endif -} - -void wxCalendarCtrl::DoGetSize(int *width, int *height) const -{ - wxControl::DoGetSize(width, height); -#ifndef __WXPM__ - if ( !HasFlag(wxCAL_SEQUENTIAL_MONTH_SELECTION) ) - { - // our real height is bigger - if ( height && GetMonthControl()) - { - *height += GetMonthControl()->GetSize().y + VERT_MARGIN; - } - } -#endif -} - -void wxCalendarCtrl::RecalcGeometry() -{ - wxClientDC dc(this); - - dc.SetFont(GetFont()); - - // determine the column width (weekday names are not necessarily wider - // than the numbers (in some languages), so let's not assume that they are) - m_widthCol = 0; - for ( int day = 10; day <= 31; day++) - { - wxCoord width; - dc.GetTextExtent(wxString::Format(wxT("%d"), day), &width, &m_heightRow); - if ( width > m_widthCol ) - { - // 1.5 times the width gives nice margins even if the weekday - // names are short - m_widthCol = width+width/2; - } - } - wxDateTime::WeekDay wd; - for ( wd = wxDateTime::Sun; wd < wxDateTime::Inv_WeekDay; wxNextWDay(wd) ) - { - wxCoord width; - dc.GetTextExtent(m_weekdays[wd], &width, &m_heightRow); - if ( width > m_widthCol ) - { - m_widthCol = width; - } - } - - // leave some margins - m_widthCol += 2; - m_heightRow += 2; - - m_rowOffset = HasFlag(wxCAL_SEQUENTIAL_MONTH_SELECTION) ? m_heightRow : 0; // conditional in relation to style -} - -// ---------------------------------------------------------------------------- -// drawing -// ---------------------------------------------------------------------------- - -void wxCalendarCtrl::OnPaint(wxPaintEvent& WXUNUSED(event)) -{ - wxPaintDC dc(this); - - dc.SetFont(GetFont()); - - RecalcGeometry(); - -#if DEBUG_PAINT - wxLogDebug("--- starting to paint, selection: %s, week %u\n", - m_date.Format("%a %d-%m-%Y %H:%M:%S").c_str(), - GetWeek(m_date)); -#endif - - wxCoord y = 0; - wxCoord x0 = wxMax( (GetSize().x - m_widthCol*7) /2 , 0 ); - - if ( HasFlag(wxCAL_SEQUENTIAL_MONTH_SELECTION) ) - { - // draw the sequential month-selector - - dc.SetBackgroundMode(wxTRANSPARENT); - dc.SetTextForeground(*wxBLACK); - dc.SetBrush(wxBrush(m_colHeaderBg, wxSOLID)); - dc.SetPen(wxPen(m_colHeaderBg, 1, wxSOLID)); - dc.DrawRectangle(0, y, GetClientSize().x, m_heightRow); - - // Get extent of month-name + year - wxCoord monthw, monthh; - wxString headertext = m_date.Format(wxT("%B %Y")); - dc.GetTextExtent(headertext, &monthw, &monthh); - - // draw month-name centered above weekdays - wxCoord monthx = ((m_widthCol * 7) - monthw) / 2 + x0; - wxCoord monthy = ((m_heightRow - monthh) / 2) + y; - dc.DrawText(headertext, monthx, monthy); - - // calculate the "month-arrows" - wxPoint leftarrow[3]; - wxPoint rightarrow[3]; - - int arrowheight = monthh / 2; - - leftarrow[0] = wxPoint(0, arrowheight / 2); - leftarrow[1] = wxPoint(arrowheight / 2, 0); - leftarrow[2] = wxPoint(arrowheight / 2, arrowheight - 1); - - rightarrow[0] = wxPoint(0,0); - rightarrow[1] = wxPoint(arrowheight / 2, arrowheight / 2); - rightarrow[2] = wxPoint(0, arrowheight - 1); - - // draw the "month-arrows" - - wxCoord arrowy = (m_heightRow - arrowheight) / 2; - wxCoord larrowx = (m_widthCol - (arrowheight / 2)) / 2 + x0; - wxCoord rarrowx = ((m_widthCol - (arrowheight / 2)) / 2) + m_widthCol*6 + x0; - m_leftArrowRect = m_rightArrowRect = wxRect(0,0,0,0); - - if ( AllowMonthChange() ) - { - wxDateTime ldpm = wxDateTime(1,m_date.GetMonth(), m_date.GetYear()) - wxDateSpan::Day(); // last day prev month - // Check if range permits change - if ( IsDateInRange(ldpm) && ( ( ldpm.GetYear() == m_date.GetYear() ) ? true : AllowYearChange() ) ) - { - m_leftArrowRect = wxRect(larrowx - 3, arrowy - 3, (arrowheight / 2) + 8, (arrowheight + 6)); - dc.SetBrush(*wxBLACK_BRUSH); - dc.SetPen(*wxBLACK_PEN); - dc.DrawPolygon(3, leftarrow, larrowx , arrowy, wxWINDING_RULE); - dc.SetBrush(*wxTRANSPARENT_BRUSH); - dc.DrawRectangle(m_leftArrowRect); - } - wxDateTime fdnm = wxDateTime(1,m_date.GetMonth(), m_date.GetYear()) + wxDateSpan::Month(); // first day next month - if ( IsDateInRange(fdnm) && ( ( fdnm.GetYear() == m_date.GetYear() ) ? true : AllowYearChange() ) ) - { - m_rightArrowRect = wxRect(rarrowx - 4, arrowy - 3, (arrowheight / 2) + 8, (arrowheight + 6)); - dc.SetBrush(*wxBLACK_BRUSH); - dc.SetPen(*wxBLACK_PEN); - dc.DrawPolygon(3, rightarrow, rarrowx , arrowy, wxWINDING_RULE); - dc.SetBrush(*wxTRANSPARENT_BRUSH); - dc.DrawRectangle(m_rightArrowRect); - } - } - - y += m_heightRow; - } - - // first draw the week days - if ( IsExposed(x0, y, x0 + 7*m_widthCol, m_heightRow) ) - { -#if DEBUG_PAINT - wxLogDebug("painting the header"); -#endif - - dc.SetBackgroundMode(wxTRANSPARENT); - dc.SetTextForeground(m_colHeaderFg); - dc.SetBrush(wxBrush(m_colHeaderBg, wxSOLID)); - dc.SetPen(wxPen(m_colHeaderBg, 1, wxSOLID)); - dc.DrawRectangle(0, y, GetClientSize().x, m_heightRow); - - bool startOnMonday = (GetWindowStyle() & wxCAL_MONDAY_FIRST) != 0; - for ( int wd = 0; wd < 7; wd++ ) - { - size_t n; - if ( startOnMonday ) - n = wd == 6 ? 0 : wd + 1; - else - n = wd; - wxCoord dayw, dayh; - dc.GetTextExtent(m_weekdays[n], &dayw, &dayh); - dc.DrawText(m_weekdays[n], x0 + (wd*m_widthCol) + ((m_widthCol- dayw) / 2), y); // center the day-name - } - } - - // then the calendar itself - dc.SetTextForeground(*wxBLACK); - //dc.SetFont(*wxNORMAL_FONT); - - y += m_heightRow; - wxDateTime date = GetStartDate(); - -#if DEBUG_PAINT - wxLogDebug("starting calendar from %s\n", - date.Format("%a %d-%m-%Y %H:%M:%S").c_str()); -#endif - - dc.SetBackgroundMode(wxSOLID); - for ( size_t nWeek = 1; nWeek <= 6; nWeek++, y += m_heightRow ) - { - // if the update region doesn't intersect this row, don't paint it - if ( !IsExposed(x0, y, x0 + 7*m_widthCol, m_heightRow - 1) ) - { - date += wxDateSpan::Week(); - - continue; - } - -#if DEBUG_PAINT - wxLogDebug("painting week %d at y = %d\n", nWeek, y); -#endif - - for ( int wd = 0; wd < 7; wd++ ) - { - dc.SetTextBackground(m_colBackground); - if ( IsDateShown(date) ) - { - // don't use wxDate::Format() which prepends 0s - unsigned int day = date.GetDay(); - wxString dayStr = wxString::Format(_T("%u"), day); - wxCoord width; - dc.GetTextExtent(dayStr, &width, (wxCoord *)NULL); - - bool changedColours = false, - changedFont = false; - - bool isSel = false; - wxCalendarDateAttr *attr = NULL; - - if ( date.GetMonth() != m_date.GetMonth() || !IsDateInRange(date) ) - { - // surrounding week or out-of-range - // draw "disabled" - dc.SetTextForeground(m_colSorrounding); - changedColours = true; - } - else - { - isSel = date.IsSameDate(m_date); - attr = m_attrs[day - 1]; - - if ( isSel ) - { - dc.SetTextForeground(m_colHighlightFg); - dc.SetTextBackground(m_colHighlightBg); - - changedColours = true; - } - else if ( attr ) - { - wxColour colFg, colBg; - - if ( attr->IsHoliday() ) - { - colFg = m_colHolidayFg; - colBg = m_colHolidayBg; - } - else - { - colFg = attr->GetTextColour(); - colBg = attr->GetBackgroundColour(); - } - - if ( colFg.Ok() ) - { - dc.SetTextForeground(colFg); - changedColours = true; - } - - if ( colBg.Ok() ) - { - dc.SetTextBackground(colBg); - changedColours = true; - } - - if ( attr->HasFont() ) - { - dc.SetFont(attr->GetFont()); - changedFont = true; - } - } - } - - wxCoord x = wd*m_widthCol + (m_widthCol - width) / 2 + x0; - dc.DrawText(dayStr, x, y + 1); - - if ( !isSel && attr && attr->HasBorder() ) - { - wxColour colBorder; - if ( attr->HasBorderColour() ) - { - colBorder = attr->GetBorderColour(); - } - else - { - colBorder = GetForegroundColour(); - } - - wxPen pen(colBorder, 1, wxSOLID); - dc.SetPen(pen); - dc.SetBrush(*wxTRANSPARENT_BRUSH); - - switch ( attr->GetBorder() ) - { - case wxCAL_BORDER_SQUARE: - dc.DrawRectangle(x - 2, y, - width + 4, m_heightRow); - break; - - case wxCAL_BORDER_ROUND: - dc.DrawEllipse(x - 2, y, - width + 4, m_heightRow); - break; - - default: - wxFAIL_MSG(_T("unknown border type")); - } - } - - if ( changedColours ) - { - dc.SetTextForeground(GetForegroundColour()); - dc.SetTextBackground(GetBackgroundColour()); - } - - if ( changedFont ) - { - dc.SetFont(GetFont()); - } - } - //else: just don't draw it - - date += wxDateSpan::Day(); - } - } - - // Greying out out-of-range background - bool showSurrounding = (GetWindowStyle() & wxCAL_SHOW_SURROUNDING_WEEKS) != 0; - - date = ( showSurrounding ) ? GetStartDate() : wxDateTime(1, m_date.GetMonth(), m_date.GetYear()); - if ( !IsDateInRange(date) ) - { - wxDateTime firstOOR = GetLowerDateLimit() - wxDateSpan::Day(); // first out-of-range - - wxBrush oorbrush = *wxLIGHT_GREY_BRUSH; - oorbrush.SetStyle(wxFDIAGONAL_HATCH); - - HighlightRange(&dc, date, firstOOR, wxTRANSPARENT_PEN, &oorbrush); - } - - date = ( showSurrounding ) ? GetStartDate() + wxDateSpan::Weeks(6) - wxDateSpan::Day() : wxDateTime().SetToLastMonthDay(m_date.GetMonth(), m_date.GetYear()); - if ( !IsDateInRange(date) ) - { - wxDateTime firstOOR = GetUpperDateLimit() + wxDateSpan::Day(); // first out-of-range - - wxBrush oorbrush = *wxLIGHT_GREY_BRUSH; - oorbrush.SetStyle(wxFDIAGONAL_HATCH); - - HighlightRange(&dc, firstOOR, date, wxTRANSPARENT_PEN, &oorbrush); - } - -#if DEBUG_PAINT - wxLogDebug("+++ finished painting"); -#endif -} - -void wxCalendarCtrl::RefreshDate(const wxDateTime& date) -{ - RecalcGeometry(); - - wxRect rect; - - // always refresh the whole row at once because our OnPaint() will draw - // the whole row anyhow - and this allows the small optimisation in - // OnClick() below to work - rect.x = wxMax( (GetSize().x - m_widthCol*7) /2 , 0 ); - - rect.y = (m_heightRow * GetWeek(date)) + m_rowOffset; - - rect.width = 7*m_widthCol; - rect.height = m_heightRow; - -#ifdef __WXMSW__ - // VZ: for some reason, the selected date seems to occupy more space under - // MSW - this is probably some bug in the font size calculations, but I - // don't know where exactly. This fix is ugly and leads to more - // refreshes than really needed, but without it the selected days - // leaves even more ugly underscores on screen. - rect.Inflate(0, 1); -#endif // MSW - -#if DEBUG_PAINT - wxLogDebug("*** refreshing week %d at (%d, %d)-(%d, %d)\n", - GetWeek(date), - rect.x, rect.y, - rect.x + rect.width, rect.y + rect.height); -#endif - - Refresh(true, &rect); -} - -void wxCalendarCtrl::HighlightRange(wxPaintDC* pDC, const wxDateTime& fromdate, const wxDateTime& todate, const wxPen* pPen, const wxBrush* pBrush) -{ - // Highlights the given range using pen and brush - // Does nothing if todate < fromdate - - -#if DEBUG_PAINT - wxLogDebug("+++ HighlightRange: (%s) - (%s) +++", fromdate.Format("%d %m %Y"), todate.Format("%d %m %Y")); -#endif - - if ( todate >= fromdate ) - { - // do stuff - // date-coordinates - int fd, fw; - int td, tw; - - // implicit: both dates must be currently shown - checked by GetDateCoord - if ( GetDateCoord(fromdate, &fd, &fw) && GetDateCoord(todate, &td, &tw) ) - { -#if DEBUG_PAINT - wxLogDebug("Highlight range: (%i, %i) - (%i, %i)", fd, fw, td, tw); -#endif - if ( ( (tw - fw) == 1 ) && ( td < fd ) ) - { - // special case: interval 7 days or less not in same week - // split in two separate intervals - wxDateTime tfd = fromdate + wxDateSpan::Days(7-fd); - wxDateTime ftd = tfd + wxDateSpan::Day(); -#if DEBUG_PAINT - wxLogDebug("Highlight: Separate segments"); -#endif - // draw separately - HighlightRange(pDC, fromdate, tfd, pPen, pBrush); - HighlightRange(pDC, ftd, todate, pPen, pBrush); - } - else - { - int numpoints; - wxPoint corners[8]; // potentially 8 corners in polygon - wxCoord x0 = wxMax( (GetSize().x - m_widthCol*7) /2 , 0 ); - - if ( fw == tw ) - { - // simple case: same week - numpoints = 4; - corners[0] = wxPoint(x0 + (fd - 1) * m_widthCol, (fw * m_heightRow) + m_rowOffset); - corners[1] = wxPoint(x0 + (fd - 1) * m_widthCol, ((fw + 1 ) * m_heightRow) + m_rowOffset); - corners[2] = wxPoint(x0 + td * m_widthCol, ((tw + 1) * m_heightRow) + m_rowOffset); - corners[3] = wxPoint(x0 + td * m_widthCol, (tw * m_heightRow) + m_rowOffset); - } - else - { - int cidx = 0; - // "complex" polygon - corners[cidx] = wxPoint(x0 + (fd - 1) * m_widthCol, (fw * m_heightRow) + m_rowOffset); cidx++; - - if ( fd > 1 ) - { - corners[cidx] = wxPoint(x0 + (fd - 1) * m_widthCol, ((fw + 1) * m_heightRow) + m_rowOffset); cidx++; - corners[cidx] = wxPoint(x0, ((fw + 1) * m_heightRow) + m_rowOffset); cidx++; - } - - corners[cidx] = wxPoint(x0, ((tw + 1) * m_heightRow) + m_rowOffset); cidx++; - corners[cidx] = wxPoint(x0 + td * m_widthCol, ((tw + 1) * m_heightRow) + m_rowOffset); cidx++; - - if ( td < 7 ) - { - corners[cidx] = wxPoint(x0 + td * m_widthCol, (tw * m_heightRow) + m_rowOffset); cidx++; - corners[cidx] = wxPoint(x0 + 7 * m_widthCol, (tw * m_heightRow) + m_rowOffset); cidx++; - } - - corners[cidx] = wxPoint(x0 + 7 * m_widthCol, (fw * m_heightRow) + m_rowOffset); cidx++; - - numpoints = cidx; - } - - // draw the polygon - pDC->SetBrush(*pBrush); - pDC->SetPen(*pPen); - pDC->DrawPolygon(numpoints, corners); - } - } - } - // else do nothing -#if DEBUG_PAINT - wxLogDebug("--- HighlightRange ---"); -#endif -} - -bool wxCalendarCtrl::GetDateCoord(const wxDateTime& date, int *day, int *week) const -{ - bool retval = true; - -#if DEBUG_PAINT - wxLogDebug("+++ GetDateCoord: (%s) +++", date.Format("%d %m %Y")); -#endif - - if ( IsDateShown(date) ) - { - bool startOnMonday = ( GetWindowStyle() & wxCAL_MONDAY_FIRST ) != 0; - - // Find day - *day = date.GetWeekDay(); - - if ( *day == 0 ) // sunday - { - *day = ( startOnMonday ) ? 7 : 1; - } - else - { - *day += ( startOnMonday ) ? 0 : 1; - } - - int targetmonth = date.GetMonth() + (12 * date.GetYear()); - int thismonth = m_date.GetMonth() + (12 * m_date.GetYear()); - - // Find week - if ( targetmonth == thismonth ) - { - *week = GetWeek(date); - } - else - { - if ( targetmonth < thismonth ) - { - *week = 1; // trivial - } - else // targetmonth > thismonth - { - wxDateTime ldcm; - int lastweek; - int lastday; - - // get the datecoord of the last day in the month currently shown -#if DEBUG_PAINT - wxLogDebug(" +++ LDOM +++"); -#endif - GetDateCoord(ldcm.SetToLastMonthDay(m_date.GetMonth(), m_date.GetYear()), &lastday, &lastweek); -#if DEBUG_PAINT - wxLogDebug(" --- LDOM ---"); -#endif - - wxTimeSpan span = date - ldcm; - - int daysfromlast = span.GetDays(); -#if DEBUG_PAINT - wxLogDebug("daysfromlast: %i", daysfromlast); -#endif - if ( daysfromlast + lastday > 7 ) // past week boundary - { - int wholeweeks = (daysfromlast / 7); - *week = wholeweeks + lastweek; - if ( (daysfromlast - (7 * wholeweeks) + lastday) > 7 ) - { - *week += 1; - } - } - else - { - *week = lastweek; - } - } - } - } - else - { - *day = -1; - *week = -1; - retval = false; - } - -#if DEBUG_PAINT - wxLogDebug("--- GetDateCoord: (%s) = (%i, %i) ---", date.Format("%d %m %Y"), *day, *week); -#endif - - return retval; -} - -// ---------------------------------------------------------------------------- -// mouse handling -// ---------------------------------------------------------------------------- - -void wxCalendarCtrl::OnDClick(wxMouseEvent& event) -{ - if ( HitTest(event.GetPosition()) != wxCAL_HITTEST_DAY ) - { - event.Skip(); - } - else - { - GenerateEvent(wxEVT_CALENDAR_DOUBLECLICKED); - } -} - -void wxCalendarCtrl::OnClick(wxMouseEvent& event) -{ - wxDateTime date; - wxDateTime::WeekDay wday; - switch ( HitTest(event.GetPosition(), &date, &wday) ) - { - case wxCAL_HITTEST_DAY: - if ( IsDateInRange(date) ) - { - ChangeDay(date); - - GenerateEvents(wxEVT_CALENDAR_DAY_CHANGED, - wxEVT_CALENDAR_SEL_CHANGED); - } - break; - - case wxCAL_HITTEST_HEADER: - { - wxCalendarEvent eventWd(this, wxEVT_CALENDAR_WEEKDAY_CLICKED); - eventWd.m_wday = wday; - (void)GetEventHandler()->ProcessEvent(eventWd); - } - break; - - case wxCAL_HITTEST_DECMONTH: - case wxCAL_HITTEST_INCMONTH: - case wxCAL_HITTEST_SURROUNDING_WEEK: - SetDateAndNotify(date); // we probably only want to refresh the control. No notification.. (maybe as an option?) - break; - - default: - wxFAIL_MSG(_T("unknown hittest code")); - // fall through - - case wxCAL_HITTEST_NOWHERE: - event.Skip(); - break; - } - - // as we don't (always) skip the message, we're not going to receive the - // focus on click by default if we don't do it ourselves - SetFocus(); -} - -wxCalendarHitTestResult wxCalendarCtrl::HitTest(const wxPoint& pos, - wxDateTime *date, - wxDateTime::WeekDay *wd) -{ - RecalcGeometry(); - - // the position where the calendar really begins - wxCoord x0 = wxMax((GetSize().x - m_widthCol*7)/2, 0); - - if ( HasFlag(wxCAL_SEQUENTIAL_MONTH_SELECTION) ) - { - // Header: month - - // we need to find out if the hit is on left arrow, on month or on right arrow - // left arrow? - if ( m_leftArrowRect.Contains(pos) ) - { - if ( date ) - { - if ( IsDateInRange(m_date - wxDateSpan::Month()) ) - { - *date = m_date - wxDateSpan::Month(); - } - else - { - *date = GetLowerDateLimit(); - } - } - - return wxCAL_HITTEST_DECMONTH; - } - - if ( m_rightArrowRect.Contains(pos) ) - { - if ( date ) - { - if ( IsDateInRange(m_date + wxDateSpan::Month()) ) - { - *date = m_date + wxDateSpan::Month(); - } - else - { - *date = GetUpperDateLimit(); - } - } - - return wxCAL_HITTEST_INCMONTH; - } - - } - - // header: week days - int wday = (pos.x - x0) / m_widthCol; - if ( pos.y < (m_heightRow + m_rowOffset) ) - { - if ( pos.y > m_rowOffset ) - { - if ( wd ) - { - if ( GetWindowStyle() & wxCAL_MONDAY_FIRST ) - { - wday = wday == 6 ? 0 : wday + 1; - } - - *wd = (wxDateTime::WeekDay)wday; - } - - return wxCAL_HITTEST_HEADER; - } - else - { - return wxCAL_HITTEST_NOWHERE; - } - } - - int week = (pos.y - (m_heightRow + m_rowOffset)) / m_heightRow; - if ( week >= 6 || wday >= 7 ) - { - return wxCAL_HITTEST_NOWHERE; - } - - wxDateTime dt = GetStartDate() + wxDateSpan::Days(7*week + wday); - - if ( IsDateShown(dt) ) - { - if ( date ) - *date = dt; - - if ( dt.GetMonth() == m_date.GetMonth() ) - { - - return wxCAL_HITTEST_DAY; - } - else - { - return wxCAL_HITTEST_SURROUNDING_WEEK; - } - } - else - { - return wxCAL_HITTEST_NOWHERE; - } -} - -// ---------------------------------------------------------------------------- -// subcontrols events handling -// ---------------------------------------------------------------------------- - -void wxCalendarCtrl::OnMonthChange(wxCommandEvent& event) -{ - wxDateTime::Tm tm = m_date.GetTm(); - - wxDateTime::Month mon = (wxDateTime::Month)event.GetInt(); - if ( tm.mday > wxDateTime::GetNumberOfDays(mon, tm.year) ) - { - tm.mday = wxDateTime::GetNumberOfDays(mon, tm.year); - } - - wxDateTime target = wxDateTime(tm.mday, mon, tm.year); - - ChangeMonth(&target); - SetDateAndNotify(target); -} - -void wxCalendarCtrl::OnYearChange(wxCommandEvent& event) -{ - int year = (int)event.GetInt(); - if ( year == INT_MIN ) - { - // invalid year in the spin control, ignore it - return; - } - - wxDateTime::Tm tm = m_date.GetTm(); - - if ( tm.mday > wxDateTime::GetNumberOfDays(tm.mon, year) ) - { - tm.mday = wxDateTime::GetNumberOfDays(tm.mon, year); - } - - wxDateTime target = wxDateTime(tm.mday, tm.mon, year); - - if ( ChangeYear(&target) ) - { - SetDateAndNotify(target); - } - else - { - // In this case we don't want to change the date. That would put us - // inside the same year but a strange number of months forward/back.. - m_spinYear->SetValue(target.GetYear()); - } -} - -void wxCalendarCtrl::OnYearTextChange(wxCommandEvent& event) -{ - SetUserChangedYear(); - OnYearChange(event); -} - -// Responds to colour changes, and passes event on to children. -void wxCalendarCtrl::OnSysColourChanged(wxSysColourChangedEvent& event) -{ - // reinit colours - InitColours(); - - // Propagate the event to the children - wxControl::OnSysColourChanged(event); - - // Redraw control area - SetBackgroundColour(m_colBackground); - Refresh(); -} - -// ---------------------------------------------------------------------------- -// keyboard interface -// ---------------------------------------------------------------------------- - -void wxCalendarCtrl::OnChar(wxKeyEvent& event) -{ - wxDateTime target; - switch ( event.GetKeyCode() ) - { - case _T('+'): - case WXK_ADD: - target = m_date + wxDateSpan::Year(); - if ( ChangeYear(&target) ) - { - SetDateAndNotify(target); - } - break; - - case _T('-'): - case WXK_SUBTRACT: - target = m_date - wxDateSpan::Year(); - if ( ChangeYear(&target) ) - { - SetDateAndNotify(target); - } - break; - - case WXK_PAGEUP: - target = m_date - wxDateSpan::Month(); - ChangeMonth(&target); - SetDateAndNotify(target); // always - break; - - case WXK_PAGEDOWN: - target = m_date + wxDateSpan::Month(); - ChangeMonth(&target); - SetDateAndNotify(target); // always - break; - - case WXK_RIGHT: - if ( event.ControlDown() ) - { - target = wxDateTime(m_date).SetToNextWeekDay( - GetWindowStyle() & wxCAL_MONDAY_FIRST - ? wxDateTime::Sun : wxDateTime::Sat); - if ( !IsDateInRange(target) ) - { - target = GetUpperDateLimit(); - } - SetDateAndNotify(target); - } - else - SetDateAndNotify(m_date + wxDateSpan::Day()); - break; - - case WXK_LEFT: - if ( event.ControlDown() ) - { - target = wxDateTime(m_date).SetToPrevWeekDay( - GetWindowStyle() & wxCAL_MONDAY_FIRST - ? wxDateTime::Mon : wxDateTime::Sun); - if ( !IsDateInRange(target) ) - { - target = GetLowerDateLimit(); - } - SetDateAndNotify(target); - } - else - SetDateAndNotify(m_date - wxDateSpan::Day()); - break; - - case WXK_UP: - SetDateAndNotify(m_date - wxDateSpan::Week()); - break; - - case WXK_DOWN: - SetDateAndNotify(m_date + wxDateSpan::Week()); - break; - - case WXK_HOME: - if ( event.ControlDown() ) - SetDateAndNotify(wxDateTime::Today()); - else - SetDateAndNotify(wxDateTime(1, m_date.GetMonth(), m_date.GetYear())); - break; - - case WXK_END: - SetDateAndNotify(wxDateTime(m_date).SetToLastMonthDay()); - break; - - case WXK_RETURN: - GenerateEvent(wxEVT_CALENDAR_DOUBLECLICKED); - break; - - default: - event.Skip(); - } -} - -// ---------------------------------------------------------------------------- -// holidays handling -// ---------------------------------------------------------------------------- - -void wxCalendarCtrl::EnableHolidayDisplay(bool display) -{ - long style = GetWindowStyle(); - if ( display ) - style |= wxCAL_SHOW_HOLIDAYS; - else - style &= ~wxCAL_SHOW_HOLIDAYS; - - SetWindowStyle(style); - - if ( display ) - SetHolidayAttrs(); - else - ResetHolidayAttrs(); - - Refresh(); -} - -void wxCalendarCtrl::SetHolidayAttrs() -{ - if ( GetWindowStyle() & wxCAL_SHOW_HOLIDAYS ) - { - ResetHolidayAttrs(); - - wxDateTime::Tm tm = m_date.GetTm(); - wxDateTime dtStart(1, tm.mon, tm.year), - dtEnd = dtStart.GetLastMonthDay(); - - wxDateTimeArray hol; - wxDateTimeHolidayAuthority::GetHolidaysInRange(dtStart, dtEnd, hol); - - size_t count = hol.GetCount(); - for ( size_t n = 0; n < count; n++ ) - { - SetHoliday(hol[n].GetDay()); - } - } -} - -void wxCalendarCtrl::SetHoliday(size_t day) -{ - wxCHECK_RET( day > 0 && day < 32, _T("invalid day in SetHoliday") ); - - wxCalendarDateAttr *attr = GetAttr(day); - if ( !attr ) - { - attr = new wxCalendarDateAttr; - } - - attr->SetHoliday(true); - - // can't use SetAttr() because it would delete this pointer - m_attrs[day - 1] = attr; -} - -void wxCalendarCtrl::ResetHolidayAttrs() -{ - for ( size_t day = 0; day < 31; day++ ) - { - if ( m_attrs[day] ) - { - m_attrs[day]->SetHoliday(false); - } - } -} - - -//static -wxVisualAttributes -wxCalendarCtrl::GetClassDefaultAttributes(wxWindowVariant variant) -{ - // Use the same color scheme as wxListBox - return wxListBox::GetClassDefaultAttributes(variant); -} - -#endif // wxUSE_CALENDARCTRL +/////////////////////////////////////////////////////////////////////////////// +// Name: src/generic/calctrl.cpp +// Purpose: implementation fo the generic wxCalendarCtrl +// Author: Vadim Zeitlin +// Modified by: +// Created: 29.12.99 +// RCS-ID: $Id: calctrl.cpp 53987 2008-06-05 15:48:55Z VZ $ +// Copyright: (c) 1999 Vadim Zeitlin +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#ifndef WX_PRECOMP + #include "wx/dcclient.h" + #include "wx/settings.h" + #include "wx/brush.h" + #include "wx/combobox.h" + #include "wx/listbox.h" + #include "wx/stattext.h" + #include "wx/textctrl.h" +#endif //WX_PRECOMP + +#if wxUSE_CALENDARCTRL + +#include "wx/spinctrl.h" + +// if wxDatePickerCtrl code doesn't define the date event, do it here as we +// need it as well +#if !wxUSE_DATEPICKCTRL + #define _WX_DEFINE_DATE_EVENTS_ +#endif + +#include "wx/calctrl.h" + +#define DEBUG_PAINT 0 + +// ---------------------------------------------------------------------------- +// wxWin macros +// ---------------------------------------------------------------------------- + +BEGIN_EVENT_TABLE(wxCalendarCtrl, wxControl) + EVT_PAINT(wxCalendarCtrl::OnPaint) + + EVT_CHAR(wxCalendarCtrl::OnChar) + + EVT_LEFT_DOWN(wxCalendarCtrl::OnClick) + EVT_LEFT_DCLICK(wxCalendarCtrl::OnDClick) + + EVT_SYS_COLOUR_CHANGED(wxCalendarCtrl::OnSysColourChanged) +END_EVENT_TABLE() + +#if wxUSE_EXTENDED_RTTI +WX_DEFINE_FLAGS( wxCalendarCtrlStyle ) + +wxBEGIN_FLAGS( wxCalendarCtrlStyle ) + // new style border flags, we put them first to + // use them for streaming out + wxFLAGS_MEMBER(wxBORDER_SIMPLE) + wxFLAGS_MEMBER(wxBORDER_SUNKEN) + wxFLAGS_MEMBER(wxBORDER_DOUBLE) + wxFLAGS_MEMBER(wxBORDER_RAISED) + wxFLAGS_MEMBER(wxBORDER_STATIC) + wxFLAGS_MEMBER(wxBORDER_NONE) + + // old style border flags + wxFLAGS_MEMBER(wxSIMPLE_BORDER) + wxFLAGS_MEMBER(wxSUNKEN_BORDER) + wxFLAGS_MEMBER(wxDOUBLE_BORDER) + wxFLAGS_MEMBER(wxRAISED_BORDER) + wxFLAGS_MEMBER(wxSTATIC_BORDER) + wxFLAGS_MEMBER(wxBORDER) + + // standard window styles + wxFLAGS_MEMBER(wxTAB_TRAVERSAL) + wxFLAGS_MEMBER(wxCLIP_CHILDREN) + wxFLAGS_MEMBER(wxTRANSPARENT_WINDOW) + wxFLAGS_MEMBER(wxWANTS_CHARS) + wxFLAGS_MEMBER(wxFULL_REPAINT_ON_RESIZE) + wxFLAGS_MEMBER(wxALWAYS_SHOW_SB ) + wxFLAGS_MEMBER(wxVSCROLL) + wxFLAGS_MEMBER(wxHSCROLL) + + wxFLAGS_MEMBER(wxCAL_SUNDAY_FIRST) + wxFLAGS_MEMBER(wxCAL_MONDAY_FIRST) + wxFLAGS_MEMBER(wxCAL_SHOW_HOLIDAYS) + wxFLAGS_MEMBER(wxCAL_NO_YEAR_CHANGE) + wxFLAGS_MEMBER(wxCAL_NO_MONTH_CHANGE) + wxFLAGS_MEMBER(wxCAL_SEQUENTIAL_MONTH_SELECTION) + wxFLAGS_MEMBER(wxCAL_SHOW_SURROUNDING_WEEKS) + +wxEND_FLAGS( wxCalendarCtrlStyle ) + +IMPLEMENT_DYNAMIC_CLASS_XTI(wxCalendarCtrl, wxControl,"wx/calctrl.h") + +wxBEGIN_PROPERTIES_TABLE(wxCalendarCtrl) + wxEVENT_RANGE_PROPERTY( Updated , wxEVT_CALENDAR_SEL_CHANGED , wxEVT_CALENDAR_WEEKDAY_CLICKED , wxCalendarEvent ) + wxHIDE_PROPERTY( Children ) + wxPROPERTY( Date,wxDateTime, SetDate , GetDate, , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) + wxPROPERTY_FLAGS( WindowStyle , wxCalendarCtrlStyle , long , SetWindowStyleFlag , GetWindowStyleFlag , , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // style +wxEND_PROPERTIES_TABLE() + +wxBEGIN_HANDLERS_TABLE(wxCalendarCtrl) +wxEND_HANDLERS_TABLE() + +wxCONSTRUCTOR_6( wxCalendarCtrl , wxWindow* , Parent , wxWindowID , Id , wxDateTime , Date , wxPoint , Position , wxSize , Size , long , WindowStyle ) +#else +IMPLEMENT_DYNAMIC_CLASS(wxCalendarCtrl, wxControl) +#endif +IMPLEMENT_DYNAMIC_CLASS(wxCalendarEvent, wxDateEvent) + +// ---------------------------------------------------------------------------- +// events +// ---------------------------------------------------------------------------- + +DEFINE_EVENT_TYPE(wxEVT_CALENDAR_SEL_CHANGED) +DEFINE_EVENT_TYPE(wxEVT_CALENDAR_DAY_CHANGED) +DEFINE_EVENT_TYPE(wxEVT_CALENDAR_MONTH_CHANGED) +DEFINE_EVENT_TYPE(wxEVT_CALENDAR_YEAR_CHANGED) +DEFINE_EVENT_TYPE(wxEVT_CALENDAR_DOUBLECLICKED) +DEFINE_EVENT_TYPE(wxEVT_CALENDAR_WEEKDAY_CLICKED) + +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// wxCalendarCtrl +// ---------------------------------------------------------------------------- + +wxCalendarCtrl::wxCalendarCtrl(wxWindow *parent, + wxWindowID id, + const wxDateTime& date, + const wxPoint& pos, + const wxSize& size, + long style, + const wxString& name) +{ + Init(); + + (void)Create(parent, id, date, pos, size, style, name); +} + +void wxCalendarCtrl::Init() +{ + m_comboMonth = NULL; + m_spinYear = NULL; + m_staticYear = NULL; + m_staticMonth = NULL; + + m_userChangedYear = false; + + m_widthCol = + m_heightRow = 0; + + wxDateTime::WeekDay wd; + for ( wd = wxDateTime::Sun; wd < wxDateTime::Inv_WeekDay; wxNextWDay(wd) ) + { + m_weekdays[wd] = wxDateTime::GetWeekDayName(wd, wxDateTime::Name_Abbr); + } + + for ( size_t n = 0; n < WXSIZEOF(m_attrs); n++ ) + { + m_attrs[n] = NULL; + } + + InitColours(); +} + +void wxCalendarCtrl::InitColours() +{ + m_colHighlightFg = wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT); + m_colHighlightBg = wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT); + m_colBackground = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW); + m_colSorrounding = wxSystemSettings::GetColour(wxSYS_COLOUR_GRAYTEXT); + + m_colHolidayFg = *wxRED; + // don't set m_colHolidayBg - by default, same as our bg colour + + m_colHeaderFg = *wxBLUE; + m_colHeaderBg = *wxLIGHT_GREY; +} + +bool wxCalendarCtrl::Create(wxWindow *parent, + wxWindowID id, + const wxDateTime& date, + const wxPoint& pos, + const wxSize& size, + long style, + const wxString& name) +{ + if ( !wxControl::Create(parent, id, pos, size, + style | wxCLIP_CHILDREN | wxWANTS_CHARS | wxFULL_REPAINT_ON_RESIZE, + wxDefaultValidator, name) ) + { + return false; + } + + // needed to get the arrow keys normally used for the dialog navigation + SetWindowStyle(style | wxWANTS_CHARS); + + m_date = date.IsValid() ? date : wxDateTime::Today(); + + m_lowdate = wxDefaultDateTime; + m_highdate = wxDefaultDateTime; + + if ( !HasFlag(wxCAL_SEQUENTIAL_MONTH_SELECTION) ) + { + CreateYearSpinCtrl(); + m_staticYear = new wxStaticText(GetParent(), wxID_ANY, m_date.Format(_T("%Y")), + wxDefaultPosition, wxDefaultSize, + wxALIGN_CENTRE); + + CreateMonthComboBox(); + m_staticMonth = new wxStaticText(GetParent(), wxID_ANY, m_date.Format(_T("%B")), + wxDefaultPosition, wxDefaultSize, + wxALIGN_CENTRE); + } + + ShowCurrentControls(); + + // we need to set the position as well because the main control position + // is not the same as the one specified in pos if we have the controls + // above it + SetInitialSize(size); + SetPosition(pos); + + // Since we don't paint the whole background make sure that the platform + // will use the right one. + SetBackgroundColour(m_colBackground); + + SetHolidayAttrs(); + + return true; +} + +wxCalendarCtrl::~wxCalendarCtrl() +{ + for ( size_t n = 0; n < WXSIZEOF(m_attrs); n++ ) + { + delete m_attrs[n]; + } + + if ( !HasFlag(wxCAL_SEQUENTIAL_MONTH_SELECTION) ) + { + delete m_comboMonth; + delete m_staticMonth; + delete m_spinYear; + delete m_staticYear; + } +} + +void wxCalendarCtrl::SetWindowStyleFlag(long style) +{ + // changing this style doesn't work because the controls are not + // created/shown/hidden accordingly + wxASSERT_MSG( (style & wxCAL_SEQUENTIAL_MONTH_SELECTION) == + (m_windowStyle & wxCAL_SEQUENTIAL_MONTH_SELECTION), + _T("wxCAL_SEQUENTIAL_MONTH_SELECTION can't be changed after creation") ); + + wxControl::SetWindowStyleFlag(style); +} + +// ---------------------------------------------------------------------------- +// Create the wxComboBox and wxSpinCtrl +// ---------------------------------------------------------------------------- + +void wxCalendarCtrl::CreateMonthComboBox() +{ + m_comboMonth = new wxComboBox(GetParent(), wxID_ANY, + wxEmptyString, + wxDefaultPosition, + wxDefaultSize, + 0, NULL, + wxCB_READONLY | wxCLIP_SIBLINGS); + + wxDateTime::Month m; + for ( m = wxDateTime::Jan; m < wxDateTime::Inv_Month; wxNextMonth(m) ) + { + m_comboMonth->Append(wxDateTime::GetMonthName(m)); + } + + m_comboMonth->SetSelection(GetDate().GetMonth()); + m_comboMonth->SetSize(wxDefaultCoord, + wxDefaultCoord, + wxDefaultCoord, + wxDefaultCoord, + wxSIZE_AUTO_WIDTH|wxSIZE_AUTO_HEIGHT); + + m_comboMonth->Connect(m_comboMonth->GetId(), wxEVT_COMMAND_COMBOBOX_SELECTED, + wxCommandEventHandler(wxCalendarCtrl::OnMonthChange), + NULL, this); +} + +void wxCalendarCtrl::CreateYearSpinCtrl() +{ + m_spinYear = new wxSpinCtrl(GetParent(), wxID_ANY, + GetDate().Format(_T("%Y")), + wxDefaultPosition, + wxDefaultSize, + wxSP_ARROW_KEYS | wxCLIP_SIBLINGS, + -4300, 10000, GetDate().GetYear()); + + m_spinYear->Connect(m_spinYear->GetId(), wxEVT_COMMAND_TEXT_UPDATED, + wxCommandEventHandler(wxCalendarCtrl::OnYearTextChange), + NULL, this); + + m_spinYear->Connect(m_spinYear->GetId(), wxEVT_COMMAND_SPINCTRL_UPDATED, + wxCommandEventHandler(wxCalendarCtrl::OnYearChange), + NULL, this); +} + +// ---------------------------------------------------------------------------- +// forward wxWin functions to subcontrols +// ---------------------------------------------------------------------------- + +bool wxCalendarCtrl::Destroy() +{ + if ( m_staticYear ) + m_staticYear->Destroy(); + if ( m_spinYear ) + m_spinYear->Destroy(); + if ( m_comboMonth ) + m_comboMonth->Destroy(); + if ( m_staticMonth ) + m_staticMonth->Destroy(); + + m_staticYear = NULL; + m_spinYear = NULL; + m_comboMonth = NULL; + m_staticMonth = NULL; + + return wxControl::Destroy(); +} + +bool wxCalendarCtrl::Show(bool show) +{ + if ( !wxControl::Show(show) ) + { + return false; + } + + if ( !(GetWindowStyle() & wxCAL_SEQUENTIAL_MONTH_SELECTION) ) + { + if ( GetMonthControl() ) + { + GetMonthControl()->Show(show); + GetYearControl()->Show(show); + } + } + + return true; +} + +bool wxCalendarCtrl::Enable(bool enable) +{ + if ( !wxControl::Enable(enable) ) + { + return false; + } + + if ( !(GetWindowStyle() & wxCAL_SEQUENTIAL_MONTH_SELECTION) ) + { + GetMonthControl()->Enable(enable); + GetYearControl()->Enable(enable); + } + + return true; +} + +// ---------------------------------------------------------------------------- +// enable/disable month/year controls +// ---------------------------------------------------------------------------- + +void wxCalendarCtrl::ShowCurrentControls() +{ + if ( !HasFlag(wxCAL_SEQUENTIAL_MONTH_SELECTION) ) + { + if ( AllowMonthChange() ) + { + m_comboMonth->Show(); + m_staticMonth->Hide(); + + if ( AllowYearChange() ) + { + m_spinYear->Show(); + m_staticYear->Hide(); + + // skip the rest + return; + } + } + else + { + m_comboMonth->Hide(); + m_staticMonth->Show(); + } + + // year change not allowed here + m_spinYear->Hide(); + m_staticYear->Show(); + } + //else: these controls are not even created, don't show/hide them +} + +wxControl *wxCalendarCtrl::GetMonthControl() const +{ + return AllowMonthChange() ? (wxControl *)m_comboMonth : (wxControl *)m_staticMonth; +} + +wxControl *wxCalendarCtrl::GetYearControl() const +{ + return AllowYearChange() ? (wxControl *)m_spinYear : (wxControl *)m_staticYear; +} + +void wxCalendarCtrl::EnableYearChange(bool enable) +{ + if ( enable != AllowYearChange() ) + { + long style = GetWindowStyle(); + if ( enable ) + style &= ~wxCAL_NO_YEAR_CHANGE; + else + style |= wxCAL_NO_YEAR_CHANGE; + SetWindowStyle(style); + + ShowCurrentControls(); + if ( GetWindowStyle() & wxCAL_SEQUENTIAL_MONTH_SELECTION ) + { + Refresh(); + } + } +} + +void wxCalendarCtrl::EnableMonthChange(bool enable) +{ + if ( enable != AllowMonthChange() ) + { + long style = GetWindowStyle(); + if ( enable ) + style &= ~wxCAL_NO_MONTH_CHANGE; + else + style |= wxCAL_NO_MONTH_CHANGE; + SetWindowStyle(style); + + ShowCurrentControls(); + if ( GetWindowStyle() & wxCAL_SEQUENTIAL_MONTH_SELECTION ) + { + Refresh(); + } + } +} + +// ---------------------------------------------------------------------------- +// changing date +// ---------------------------------------------------------------------------- + +bool wxCalendarCtrl::SetDate(const wxDateTime& date) +{ + bool retval = true; + + bool sameMonth = m_date.GetMonth() == date.GetMonth(), + sameYear = m_date.GetYear() == date.GetYear(); + + if ( IsDateInRange(date) ) + { + if ( sameMonth && sameYear ) + { + // just change the day + ChangeDay(date); + } + else + { + if ( AllowMonthChange() && (AllowYearChange() || sameYear) ) + { + // change everything + m_date = date; + + if ( !(GetWindowStyle() & wxCAL_SEQUENTIAL_MONTH_SELECTION) ) + { + // update the controls + m_comboMonth->SetSelection(m_date.GetMonth()); + + if ( AllowYearChange() ) + { + if ( !m_userChangedYear ) + m_spinYear->SetValue(m_date.Format(_T("%Y"))); + } + } + + // as the month changed, holidays did too + SetHolidayAttrs(); + + // update the calendar + Refresh(); + } + else + { + // forbidden + retval = false; + } + } + } + + m_userChangedYear = false; + + return retval; +} + +void wxCalendarCtrl::ChangeDay(const wxDateTime& date) +{ + if ( m_date != date ) + { + // we need to refresh the row containing the old date and the one + // containing the new one + wxDateTime dateOld = m_date; + m_date = date; + + RefreshDate(dateOld); + + // if the date is in the same row, it was already drawn correctly + if ( GetWeek(m_date) != GetWeek(dateOld) ) + { + RefreshDate(m_date); + } + } +} + +void wxCalendarCtrl::SetDateAndNotify(const wxDateTime& date) +{ + wxDateTime::Tm tm1 = m_date.GetTm(), + tm2 = date.GetTm(); + + wxEventType type; + if ( tm1.year != tm2.year ) + type = wxEVT_CALENDAR_YEAR_CHANGED; + else if ( tm1.mon != tm2.mon ) + type = wxEVT_CALENDAR_MONTH_CHANGED; + else if ( tm1.mday != tm2.mday ) + type = wxEVT_CALENDAR_DAY_CHANGED; + else + return; + + if ( SetDate(date) ) + { + GenerateEvents(type, wxEVT_CALENDAR_SEL_CHANGED); + } +} + +// ---------------------------------------------------------------------------- +// date range +// ---------------------------------------------------------------------------- + +bool wxCalendarCtrl::SetLowerDateLimit(const wxDateTime& date /* = wxDefaultDateTime */) +{ + bool retval = true; + + if ( !(date.IsValid()) || ( ( m_highdate.IsValid() ) ? ( date <= m_highdate ) : true ) ) + { + m_lowdate = date; + } + else + { + retval = false; + } + + return retval; +} + +bool wxCalendarCtrl::SetUpperDateLimit(const wxDateTime& date /* = wxDefaultDateTime */) +{ + bool retval = true; + + if ( !(date.IsValid()) || ( ( m_lowdate.IsValid() ) ? ( date >= m_lowdate ) : true ) ) + { + m_highdate = date; + } + else + { + retval = false; + } + + return retval; +} + +bool wxCalendarCtrl::SetDateRange(const wxDateTime& lowerdate /* = wxDefaultDateTime */, const wxDateTime& upperdate /* = wxDefaultDateTime */) +{ + bool retval = true; + + if ( + ( !( lowerdate.IsValid() ) || ( ( upperdate.IsValid() ) ? ( lowerdate <= upperdate ) : true ) ) && + ( !( upperdate.IsValid() ) || ( ( lowerdate.IsValid() ) ? ( upperdate >= lowerdate ) : true ) ) ) + { + m_lowdate = lowerdate; + m_highdate = upperdate; + } + else + { + retval = false; + } + + return retval; +} + +// ---------------------------------------------------------------------------- +// date helpers +// ---------------------------------------------------------------------------- + +wxDateTime wxCalendarCtrl::GetStartDate() const +{ + wxDateTime::Tm tm = m_date.GetTm(); + + wxDateTime date = wxDateTime(1, tm.mon, tm.year); + + // rewind back + date.SetToPrevWeekDay(GetWindowStyle() & wxCAL_MONDAY_FIRST + ? wxDateTime::Mon : wxDateTime::Sun); + + if ( GetWindowStyle() & wxCAL_SHOW_SURROUNDING_WEEKS ) + { + // We want to offset the calendar if we start on the first.. + if ( date.GetDay() == 1 ) + { + date -= wxDateSpan::Week(); + } + } + + return date; +} + +bool wxCalendarCtrl::IsDateShown(const wxDateTime& date) const +{ + if ( !(GetWindowStyle() & wxCAL_SHOW_SURROUNDING_WEEKS) ) + { + return date.GetMonth() == m_date.GetMonth(); + } + else + { + return true; + } +} + +bool wxCalendarCtrl::IsDateInRange(const wxDateTime& date) const +{ + // Check if the given date is in the range specified + return ( ( ( m_lowdate.IsValid() ) ? ( date >= m_lowdate ) : true ) + && ( ( m_highdate.IsValid() ) ? ( date <= m_highdate ) : true ) ); +} + +bool wxCalendarCtrl::ChangeYear(wxDateTime* target) const +{ + bool retval = false; + + if ( !(IsDateInRange(*target)) ) + { + if ( target->GetYear() < m_date.GetYear() ) + { + if ( target->GetYear() >= GetLowerDateLimit().GetYear() ) + { + *target = GetLowerDateLimit(); + retval = true; + } + else + { + *target = m_date; + } + } + else + { + if ( target->GetYear() <= GetUpperDateLimit().GetYear() ) + { + *target = GetUpperDateLimit(); + retval = true; + } + else + { + *target = m_date; + } + } + } + else + { + retval = true; + } + + return retval; +} + +bool wxCalendarCtrl::ChangeMonth(wxDateTime* target) const +{ + bool retval = true; + + if ( !(IsDateInRange(*target)) ) + { + retval = false; + + if ( target->GetMonth() < m_date.GetMonth() ) + { + *target = GetLowerDateLimit(); + } + else + { + *target = GetUpperDateLimit(); + } + } + + return retval; +} + +size_t wxCalendarCtrl::GetWeek(const wxDateTime& date) const +{ + size_t retval = date.GetWeekOfMonth(GetWindowStyle() & wxCAL_MONDAY_FIRST + ? wxDateTime::Monday_First + : wxDateTime::Sunday_First); + + if ( (GetWindowStyle() & wxCAL_SHOW_SURROUNDING_WEEKS) ) + { + // we need to offset an extra week if we "start" on the 1st of the month + wxDateTime::Tm tm = date.GetTm(); + + wxDateTime datetest = wxDateTime(1, tm.mon, tm.year); + + // rewind back + datetest.SetToPrevWeekDay(GetWindowStyle() & wxCAL_MONDAY_FIRST + ? wxDateTime::Mon : wxDateTime::Sun); + + if ( datetest.GetDay() == 1 ) + { + retval += 1; + } + } + + return retval; +} + +// ---------------------------------------------------------------------------- +// size management +// ---------------------------------------------------------------------------- + +// this is a composite control and it must arrange its parts each time its +// size or position changes: the combobox and spinctrl are along the top of +// the available area and the calendar takes up therest of the space + +// the static controls are supposed to be always smaller than combo/spin so we +// always use the latter for size calculations and position the static to take +// the same space + +// the constants used for the layout +#define VERT_MARGIN 5 // distance between combo and calendar +#ifdef __WXMAC__ +#define HORZ_MARGIN 5 // spin +#else +#define HORZ_MARGIN 15 // spin +#endif +wxSize wxCalendarCtrl::DoGetBestSize() const +{ + // calc the size of the calendar + ((wxCalendarCtrl *)this)->RecalcGeometry(); // const_cast + + wxCoord width = 7*m_widthCol, + height = 7*m_heightRow + m_rowOffset + VERT_MARGIN; + + if ( !HasFlag(wxCAL_SEQUENTIAL_MONTH_SELECTION) ) + { + // the combobox doesn't report its height correctly (it returns the + // height including the drop down list) so don't use it + height += m_spinYear->GetBestSize().y; + + + wxCoord w2 = m_comboMonth->GetBestSize().x + HORZ_MARGIN + GetCharWidth()*6; + if (width < w2) + width = w2; + } + + if ( !HasFlag(wxBORDER_NONE) ) + { + // the border would clip the last line otherwise + height += 6; + width += 4; + } + + wxSize best(width, height); + CacheBestSize(best); + return best; +} + +void wxCalendarCtrl::DoSetSize(int x, int y, + int width, int height, + int sizeFlags) +{ + wxControl::DoSetSize(x, y, width, height, sizeFlags); +} + +void wxCalendarCtrl::DoMoveWindow(int x, int y, int width, int height) +{ + int yDiff; + + if ( !HasFlag(wxCAL_SEQUENTIAL_MONTH_SELECTION) && m_staticMonth ) + { + wxSize sizeCombo = m_comboMonth->GetEffectiveMinSize(); + wxSize sizeStatic = m_staticMonth->GetSize(); + wxSize sizeSpin = m_spinYear->GetSize(); + + // wxMSW sometimes reports the wrong combo height, + // so on this platform we'll use the spin control + // height instead. +#ifdef __WXMSW__ + int maxHeight = sizeSpin.y; + int requiredSpinHeight = -1; +#else + int maxHeight = sizeCombo.y; + int requiredSpinHeight = sizeCombo.y; +#endif + int dy = (maxHeight - sizeStatic.y) / 2; + m_comboMonth->Move(x, y); + m_staticMonth->SetSize(x, y + dy, sizeCombo.x, -1, sizeStatic.y); + + int xDiff = sizeCombo.x + HORZ_MARGIN; + + m_spinYear->SetSize(x + xDiff, y, width - xDiff, requiredSpinHeight); + m_staticYear->SetSize(x + xDiff, y + dy, width - xDiff, sizeStatic.y); + + yDiff = wxMax(sizeSpin.y, maxHeight) + VERT_MARGIN; + } + else // no controls on the top + { + yDiff = 0; + } + + wxControl::DoMoveWindow(x, y + yDiff, width, height - yDiff); +} + +void wxCalendarCtrl::DoGetPosition(int *x, int *y) const +{ + wxControl::DoGetPosition(x, y); +#ifndef __WXPM__ + if ( !HasFlag(wxCAL_SEQUENTIAL_MONTH_SELECTION) && GetMonthControl() ) + { + // our real top corner is not in this position + if ( y ) + { + *y -= GetMonthControl()->GetSize().y + VERT_MARGIN; + } + } +#endif +} + +void wxCalendarCtrl::DoGetSize(int *width, int *height) const +{ + wxControl::DoGetSize(width, height); +#ifndef __WXPM__ + if ( !HasFlag(wxCAL_SEQUENTIAL_MONTH_SELECTION) ) + { + // our real height is bigger + if ( height && GetMonthControl()) + { + *height += GetMonthControl()->GetSize().y + VERT_MARGIN; + } + } +#endif +} + +void wxCalendarCtrl::RecalcGeometry() +{ + wxClientDC dc(this); + + dc.SetFont(GetFont()); + + // determine the column width (weekday names are not necessarily wider + // than the numbers (in some languages), so let's not assume that they are) + m_widthCol = 0; + for ( int day = 10; day <= 31; day++) + { + wxCoord width; + dc.GetTextExtent(wxString::Format(wxT("%d"), day), &width, &m_heightRow); + if ( width > m_widthCol ) + { + // 1.5 times the width gives nice margins even if the weekday + // names are short + m_widthCol = width+width/2; + } + } + wxDateTime::WeekDay wd; + for ( wd = wxDateTime::Sun; wd < wxDateTime::Inv_WeekDay; wxNextWDay(wd) ) + { + wxCoord width; + dc.GetTextExtent(m_weekdays[wd], &width, &m_heightRow); + if ( width > m_widthCol ) + { + m_widthCol = width; + } + } + + // leave some margins + m_widthCol += 2; + m_heightRow += 2; + + m_rowOffset = HasFlag(wxCAL_SEQUENTIAL_MONTH_SELECTION) ? m_heightRow : 0; // conditional in relation to style +} + +// ---------------------------------------------------------------------------- +// drawing +// ---------------------------------------------------------------------------- + +void wxCalendarCtrl::OnPaint(wxPaintEvent& WXUNUSED(event)) +{ + wxPaintDC dc(this); + + dc.SetFont(GetFont()); + + RecalcGeometry(); + +#if DEBUG_PAINT + wxLogDebug("--- starting to paint, selection: %s, week %u\n", + m_date.Format("%a %d-%m-%Y %H:%M:%S").c_str(), + GetWeek(m_date)); +#endif + + wxCoord y = 0; + wxCoord x0 = wxMax( (GetSize().x - m_widthCol*7) /2 , 0 ); + + if ( HasFlag(wxCAL_SEQUENTIAL_MONTH_SELECTION) ) + { + // draw the sequential month-selector + + dc.SetBackgroundMode(wxTRANSPARENT); + dc.SetTextForeground(*wxBLACK); + dc.SetBrush(wxBrush(m_colHeaderBg, wxSOLID)); + dc.SetPen(wxPen(m_colHeaderBg, 1, wxSOLID)); + dc.DrawRectangle(0, y, GetClientSize().x, m_heightRow); + + // Get extent of month-name + year + wxCoord monthw, monthh; + wxString headertext = m_date.Format(wxT("%B %Y")); + dc.GetTextExtent(headertext, &monthw, &monthh); + + // draw month-name centered above weekdays + wxCoord monthx = ((m_widthCol * 7) - monthw) / 2 + x0; + wxCoord monthy = ((m_heightRow - monthh) / 2) + y; + dc.DrawText(headertext, monthx, monthy); + + // calculate the "month-arrows" + wxPoint leftarrow[3]; + wxPoint rightarrow[3]; + + int arrowheight = monthh / 2; + + leftarrow[0] = wxPoint(0, arrowheight / 2); + leftarrow[1] = wxPoint(arrowheight / 2, 0); + leftarrow[2] = wxPoint(arrowheight / 2, arrowheight - 1); + + rightarrow[0] = wxPoint(0,0); + rightarrow[1] = wxPoint(arrowheight / 2, arrowheight / 2); + rightarrow[2] = wxPoint(0, arrowheight - 1); + + // draw the "month-arrows" + + wxCoord arrowy = (m_heightRow - arrowheight) / 2; + wxCoord larrowx = (m_widthCol - (arrowheight / 2)) / 2 + x0; + wxCoord rarrowx = ((m_widthCol - (arrowheight / 2)) / 2) + m_widthCol*6 + x0; + m_leftArrowRect = m_rightArrowRect = wxRect(0,0,0,0); + + if ( AllowMonthChange() ) + { + wxDateTime ldpm = wxDateTime(1,m_date.GetMonth(), m_date.GetYear()) - wxDateSpan::Day(); // last day prev month + // Check if range permits change + if ( IsDateInRange(ldpm) && ( ( ldpm.GetYear() == m_date.GetYear() ) ? true : AllowYearChange() ) ) + { + m_leftArrowRect = wxRect(larrowx - 3, arrowy - 3, (arrowheight / 2) + 8, (arrowheight + 6)); + dc.SetBrush(*wxBLACK_BRUSH); + dc.SetPen(*wxBLACK_PEN); + dc.DrawPolygon(3, leftarrow, larrowx , arrowy, wxWINDING_RULE); + dc.SetBrush(*wxTRANSPARENT_BRUSH); + dc.DrawRectangle(m_leftArrowRect); + } + wxDateTime fdnm = wxDateTime(1,m_date.GetMonth(), m_date.GetYear()) + wxDateSpan::Month(); // first day next month + if ( IsDateInRange(fdnm) && ( ( fdnm.GetYear() == m_date.GetYear() ) ? true : AllowYearChange() ) ) + { + m_rightArrowRect = wxRect(rarrowx - 4, arrowy - 3, (arrowheight / 2) + 8, (arrowheight + 6)); + dc.SetBrush(*wxBLACK_BRUSH); + dc.SetPen(*wxBLACK_PEN); + dc.DrawPolygon(3, rightarrow, rarrowx , arrowy, wxWINDING_RULE); + dc.SetBrush(*wxTRANSPARENT_BRUSH); + dc.DrawRectangle(m_rightArrowRect); + } + } + + y += m_heightRow; + } + + // first draw the week days + if ( IsExposed(x0, y, x0 + 7*m_widthCol, m_heightRow) ) + { +#if DEBUG_PAINT + wxLogDebug("painting the header"); +#endif + + dc.SetBackgroundMode(wxTRANSPARENT); + dc.SetTextForeground(m_colHeaderFg); + dc.SetBrush(wxBrush(m_colHeaderBg, wxSOLID)); + dc.SetPen(wxPen(m_colHeaderBg, 1, wxSOLID)); + dc.DrawRectangle(0, y, GetClientSize().x, m_heightRow); + + bool startOnMonday = (GetWindowStyle() & wxCAL_MONDAY_FIRST) != 0; + for ( int wd = 0; wd < 7; wd++ ) + { + size_t n; + if ( startOnMonday ) + n = wd == 6 ? 0 : wd + 1; + else + n = wd; + wxCoord dayw, dayh; + dc.GetTextExtent(m_weekdays[n], &dayw, &dayh); + dc.DrawText(m_weekdays[n], x0 + (wd*m_widthCol) + ((m_widthCol- dayw) / 2), y); // center the day-name + } + } + + // then the calendar itself + dc.SetTextForeground(*wxBLACK); + //dc.SetFont(*wxNORMAL_FONT); + + y += m_heightRow; + wxDateTime date = GetStartDate(); + +#if DEBUG_PAINT + wxLogDebug("starting calendar from %s\n", + date.Format("%a %d-%m-%Y %H:%M:%S").c_str()); +#endif + + dc.SetBackgroundMode(wxSOLID); + for ( size_t nWeek = 1; nWeek <= 6; nWeek++, y += m_heightRow ) + { + // if the update region doesn't intersect this row, don't paint it + if ( !IsExposed(x0, y, x0 + 7*m_widthCol, m_heightRow - 1) ) + { + date += wxDateSpan::Week(); + + continue; + } + +#if DEBUG_PAINT + wxLogDebug("painting week %d at y = %d\n", nWeek, y); +#endif + + for ( int wd = 0; wd < 7; wd++ ) + { + dc.SetTextBackground(m_colBackground); + if ( IsDateShown(date) ) + { + // don't use wxDate::Format() which prepends 0s + unsigned int day = date.GetDay(); + wxString dayStr = wxString::Format(_T("%u"), day); + wxCoord width; + dc.GetTextExtent(dayStr, &width, (wxCoord *)NULL); + + bool changedColours = false, + changedFont = false; + + bool isSel = false; + wxCalendarDateAttr *attr = NULL; + + if ( date.GetMonth() != m_date.GetMonth() || !IsDateInRange(date) ) + { + // surrounding week or out-of-range + // draw "disabled" + dc.SetTextForeground(m_colSorrounding); + changedColours = true; + } + else + { + isSel = date.IsSameDate(m_date); + attr = m_attrs[day - 1]; + + if ( isSel ) + { + dc.SetTextForeground(m_colHighlightFg); + dc.SetTextBackground(m_colHighlightBg); + + changedColours = true; + } + else if ( attr ) + { + wxColour colFg, colBg; + + if ( attr->IsHoliday() ) + { + colFg = m_colHolidayFg; + colBg = m_colHolidayBg; + } + else + { + colFg = attr->GetTextColour(); + colBg = attr->GetBackgroundColour(); + } + + if ( colFg.Ok() ) + { + dc.SetTextForeground(colFg); + changedColours = true; + } + + if ( colBg.Ok() ) + { + dc.SetTextBackground(colBg); + changedColours = true; + } + + if ( attr->HasFont() ) + { + dc.SetFont(attr->GetFont()); + changedFont = true; + } + } + } + + wxCoord x = wd*m_widthCol + (m_widthCol - width) / 2 + x0; + dc.DrawText(dayStr, x, y + 1); + + if ( !isSel && attr && attr->HasBorder() ) + { + wxColour colBorder; + if ( attr->HasBorderColour() ) + { + colBorder = attr->GetBorderColour(); + } + else + { + colBorder = GetForegroundColour(); + } + + wxPen pen(colBorder, 1, wxSOLID); + dc.SetPen(pen); + dc.SetBrush(*wxTRANSPARENT_BRUSH); + + switch ( attr->GetBorder() ) + { + case wxCAL_BORDER_SQUARE: + dc.DrawRectangle(x - 2, y, + width + 4, m_heightRow); + break; + + case wxCAL_BORDER_ROUND: + dc.DrawEllipse(x - 2, y, + width + 4, m_heightRow); + break; + + default: + wxFAIL_MSG(_T("unknown border type")); + } + } + + if ( changedColours ) + { + dc.SetTextForeground(GetForegroundColour()); + dc.SetTextBackground(GetBackgroundColour()); + } + + if ( changedFont ) + { + dc.SetFont(GetFont()); + } + } + //else: just don't draw it + + date += wxDateSpan::Day(); + } + } + + // Greying out out-of-range background + bool showSurrounding = (GetWindowStyle() & wxCAL_SHOW_SURROUNDING_WEEKS) != 0; + + date = ( showSurrounding ) ? GetStartDate() : wxDateTime(1, m_date.GetMonth(), m_date.GetYear()); + if ( !IsDateInRange(date) ) + { + wxDateTime firstOOR = GetLowerDateLimit() - wxDateSpan::Day(); // first out-of-range + + wxBrush oorbrush = *wxLIGHT_GREY_BRUSH; + oorbrush.SetStyle(wxFDIAGONAL_HATCH); + + HighlightRange(&dc, date, firstOOR, wxTRANSPARENT_PEN, &oorbrush); + } + + date = ( showSurrounding ) ? GetStartDate() + wxDateSpan::Weeks(6) - wxDateSpan::Day() : wxDateTime().SetToLastMonthDay(m_date.GetMonth(), m_date.GetYear()); + if ( !IsDateInRange(date) ) + { + wxDateTime firstOOR = GetUpperDateLimit() + wxDateSpan::Day(); // first out-of-range + + wxBrush oorbrush = *wxLIGHT_GREY_BRUSH; + oorbrush.SetStyle(wxFDIAGONAL_HATCH); + + HighlightRange(&dc, firstOOR, date, wxTRANSPARENT_PEN, &oorbrush); + } + +#if DEBUG_PAINT + wxLogDebug("+++ finished painting"); +#endif +} + +void wxCalendarCtrl::RefreshDate(const wxDateTime& date) +{ + RecalcGeometry(); + + wxRect rect; + + // always refresh the whole row at once because our OnPaint() will draw + // the whole row anyhow - and this allows the small optimisation in + // OnClick() below to work + rect.x = wxMax( (GetSize().x - m_widthCol*7) /2 , 0 ); + + rect.y = (m_heightRow * GetWeek(date)) + m_rowOffset; + + rect.width = 7*m_widthCol; + rect.height = m_heightRow; + +#ifdef __WXMSW__ + // VZ: for some reason, the selected date seems to occupy more space under + // MSW - this is probably some bug in the font size calculations, but I + // don't know where exactly. This fix is ugly and leads to more + // refreshes than really needed, but without it the selected days + // leaves even more ugly underscores on screen. + rect.Inflate(0, 1); +#endif // MSW + +#if DEBUG_PAINT + wxLogDebug("*** refreshing week %d at (%d, %d)-(%d, %d)\n", + GetWeek(date), + rect.x, rect.y, + rect.x + rect.width, rect.y + rect.height); +#endif + + Refresh(true, &rect); +} + +void wxCalendarCtrl::HighlightRange(wxPaintDC* pDC, const wxDateTime& fromdate, const wxDateTime& todate, const wxPen* pPen, const wxBrush* pBrush) +{ + // Highlights the given range using pen and brush + // Does nothing if todate < fromdate + + +#if DEBUG_PAINT + wxLogDebug("+++ HighlightRange: (%s) - (%s) +++", fromdate.Format("%d %m %Y"), todate.Format("%d %m %Y")); +#endif + + if ( todate >= fromdate ) + { + // do stuff + // date-coordinates + int fd, fw; + int td, tw; + + // implicit: both dates must be currently shown - checked by GetDateCoord + if ( GetDateCoord(fromdate, &fd, &fw) && GetDateCoord(todate, &td, &tw) ) + { +#if DEBUG_PAINT + wxLogDebug("Highlight range: (%i, %i) - (%i, %i)", fd, fw, td, tw); +#endif + if ( ( (tw - fw) == 1 ) && ( td < fd ) ) + { + // special case: interval 7 days or less not in same week + // split in two separate intervals + wxDateTime tfd = fromdate + wxDateSpan::Days(7-fd); + wxDateTime ftd = tfd + wxDateSpan::Day(); +#if DEBUG_PAINT + wxLogDebug("Highlight: Separate segments"); +#endif + // draw separately + HighlightRange(pDC, fromdate, tfd, pPen, pBrush); + HighlightRange(pDC, ftd, todate, pPen, pBrush); + } + else + { + int numpoints; + wxPoint corners[8]; // potentially 8 corners in polygon + wxCoord x0 = wxMax( (GetSize().x - m_widthCol*7) /2 , 0 ); + + if ( fw == tw ) + { + // simple case: same week + numpoints = 4; + corners[0] = wxPoint(x0 + (fd - 1) * m_widthCol, (fw * m_heightRow) + m_rowOffset); + corners[1] = wxPoint(x0 + (fd - 1) * m_widthCol, ((fw + 1 ) * m_heightRow) + m_rowOffset); + corners[2] = wxPoint(x0 + td * m_widthCol, ((tw + 1) * m_heightRow) + m_rowOffset); + corners[3] = wxPoint(x0 + td * m_widthCol, (tw * m_heightRow) + m_rowOffset); + } + else + { + int cidx = 0; + // "complex" polygon + corners[cidx] = wxPoint(x0 + (fd - 1) * m_widthCol, (fw * m_heightRow) + m_rowOffset); cidx++; + + if ( fd > 1 ) + { + corners[cidx] = wxPoint(x0 + (fd - 1) * m_widthCol, ((fw + 1) * m_heightRow) + m_rowOffset); cidx++; + corners[cidx] = wxPoint(x0, ((fw + 1) * m_heightRow) + m_rowOffset); cidx++; + } + + corners[cidx] = wxPoint(x0, ((tw + 1) * m_heightRow) + m_rowOffset); cidx++; + corners[cidx] = wxPoint(x0 + td * m_widthCol, ((tw + 1) * m_heightRow) + m_rowOffset); cidx++; + + if ( td < 7 ) + { + corners[cidx] = wxPoint(x0 + td * m_widthCol, (tw * m_heightRow) + m_rowOffset); cidx++; + corners[cidx] = wxPoint(x0 + 7 * m_widthCol, (tw * m_heightRow) + m_rowOffset); cidx++; + } + + corners[cidx] = wxPoint(x0 + 7 * m_widthCol, (fw * m_heightRow) + m_rowOffset); cidx++; + + numpoints = cidx; + } + + // draw the polygon + pDC->SetBrush(*pBrush); + pDC->SetPen(*pPen); + pDC->DrawPolygon(numpoints, corners); + } + } + } + // else do nothing +#if DEBUG_PAINT + wxLogDebug("--- HighlightRange ---"); +#endif +} + +bool wxCalendarCtrl::GetDateCoord(const wxDateTime& date, int *day, int *week) const +{ + bool retval = true; + +#if DEBUG_PAINT + wxLogDebug("+++ GetDateCoord: (%s) +++", date.Format("%d %m %Y")); +#endif + + if ( IsDateShown(date) ) + { + bool startOnMonday = ( GetWindowStyle() & wxCAL_MONDAY_FIRST ) != 0; + + // Find day + *day = date.GetWeekDay(); + + if ( *day == 0 ) // sunday + { + *day = ( startOnMonday ) ? 7 : 1; + } + else + { + *day += ( startOnMonday ) ? 0 : 1; + } + + int targetmonth = date.GetMonth() + (12 * date.GetYear()); + int thismonth = m_date.GetMonth() + (12 * m_date.GetYear()); + + // Find week + if ( targetmonth == thismonth ) + { + *week = GetWeek(date); + } + else + { + if ( targetmonth < thismonth ) + { + *week = 1; // trivial + } + else // targetmonth > thismonth + { + wxDateTime ldcm; + int lastweek; + int lastday; + + // get the datecoord of the last day in the month currently shown +#if DEBUG_PAINT + wxLogDebug(" +++ LDOM +++"); +#endif + GetDateCoord(ldcm.SetToLastMonthDay(m_date.GetMonth(), m_date.GetYear()), &lastday, &lastweek); +#if DEBUG_PAINT + wxLogDebug(" --- LDOM ---"); +#endif + + wxTimeSpan span = date - ldcm; + + int daysfromlast = span.GetDays(); +#if DEBUG_PAINT + wxLogDebug("daysfromlast: %i", daysfromlast); +#endif + if ( daysfromlast + lastday > 7 ) // past week boundary + { + int wholeweeks = (daysfromlast / 7); + *week = wholeweeks + lastweek; + if ( (daysfromlast - (7 * wholeweeks) + lastday) > 7 ) + { + *week += 1; + } + } + else + { + *week = lastweek; + } + } + } + } + else + { + *day = -1; + *week = -1; + retval = false; + } + +#if DEBUG_PAINT + wxLogDebug("--- GetDateCoord: (%s) = (%i, %i) ---", date.Format("%d %m %Y"), *day, *week); +#endif + + return retval; +} + +// ---------------------------------------------------------------------------- +// mouse handling +// ---------------------------------------------------------------------------- + +void wxCalendarCtrl::OnDClick(wxMouseEvent& event) +{ + if ( HitTest(event.GetPosition()) != wxCAL_HITTEST_DAY ) + { + event.Skip(); + } + else + { + GenerateEvent(wxEVT_CALENDAR_DOUBLECLICKED); + } +} + +void wxCalendarCtrl::OnClick(wxMouseEvent& event) +{ + wxDateTime date; + wxDateTime::WeekDay wday; + switch ( HitTest(event.GetPosition(), &date, &wday) ) + { + case wxCAL_HITTEST_DAY: + if ( IsDateInRange(date) ) + { + ChangeDay(date); + + GenerateEvents(wxEVT_CALENDAR_DAY_CHANGED, + wxEVT_CALENDAR_SEL_CHANGED); + } + break; + + case wxCAL_HITTEST_HEADER: + { + wxCalendarEvent eventWd(this, wxEVT_CALENDAR_WEEKDAY_CLICKED); + eventWd.m_wday = wday; + (void)GetEventHandler()->ProcessEvent(eventWd); + } + break; + + case wxCAL_HITTEST_DECMONTH: + case wxCAL_HITTEST_INCMONTH: + case wxCAL_HITTEST_SURROUNDING_WEEK: + SetDateAndNotify(date); // we probably only want to refresh the control. No notification.. (maybe as an option?) + break; + + default: + wxFAIL_MSG(_T("unknown hittest code")); + // fall through + + case wxCAL_HITTEST_NOWHERE: + event.Skip(); + break; + } + + // as we don't (always) skip the message, we're not going to receive the + // focus on click by default if we don't do it ourselves + SetFocus(); +} + +wxCalendarHitTestResult wxCalendarCtrl::HitTest(const wxPoint& pos, + wxDateTime *date, + wxDateTime::WeekDay *wd) +{ + RecalcGeometry(); + + // the position where the calendar really begins + wxCoord x0 = wxMax((GetSize().x - m_widthCol*7)/2, 0); + + if ( HasFlag(wxCAL_SEQUENTIAL_MONTH_SELECTION) ) + { + // Header: month + + // we need to find out if the hit is on left arrow, on month or on right arrow + // left arrow? + if ( m_leftArrowRect.Contains(pos) ) + { + if ( date ) + { + if ( IsDateInRange(m_date - wxDateSpan::Month()) ) + { + *date = m_date - wxDateSpan::Month(); + } + else + { + *date = GetLowerDateLimit(); + } + } + + return wxCAL_HITTEST_DECMONTH; + } + + if ( m_rightArrowRect.Contains(pos) ) + { + if ( date ) + { + if ( IsDateInRange(m_date + wxDateSpan::Month()) ) + { + *date = m_date + wxDateSpan::Month(); + } + else + { + *date = GetUpperDateLimit(); + } + } + + return wxCAL_HITTEST_INCMONTH; + } + + } + + // header: week days + int wday = (pos.x - x0) / m_widthCol; + if ( pos.y < (m_heightRow + m_rowOffset) ) + { + if ( pos.y > m_rowOffset ) + { + if ( wd ) + { + if ( GetWindowStyle() & wxCAL_MONDAY_FIRST ) + { + wday = wday == 6 ? 0 : wday + 1; + } + + *wd = (wxDateTime::WeekDay)wday; + } + + return wxCAL_HITTEST_HEADER; + } + else + { + return wxCAL_HITTEST_NOWHERE; + } + } + + int week = (pos.y - (m_heightRow + m_rowOffset)) / m_heightRow; + if ( week >= 6 || wday >= 7 ) + { + return wxCAL_HITTEST_NOWHERE; + } + + wxDateTime dt = GetStartDate() + wxDateSpan::Days(7*week + wday); + + if ( IsDateShown(dt) ) + { + if ( date ) + *date = dt; + + if ( dt.GetMonth() == m_date.GetMonth() ) + { + + return wxCAL_HITTEST_DAY; + } + else + { + return wxCAL_HITTEST_SURROUNDING_WEEK; + } + } + else + { + return wxCAL_HITTEST_NOWHERE; + } +} + +// ---------------------------------------------------------------------------- +// subcontrols events handling +// ---------------------------------------------------------------------------- + +void wxCalendarCtrl::OnMonthChange(wxCommandEvent& event) +{ + wxDateTime::Tm tm = m_date.GetTm(); + + wxDateTime::Month mon = (wxDateTime::Month)event.GetInt(); + if ( tm.mday > wxDateTime::GetNumberOfDays(mon, tm.year) ) + { + tm.mday = wxDateTime::GetNumberOfDays(mon, tm.year); + } + + wxDateTime target = wxDateTime(tm.mday, mon, tm.year); + + ChangeMonth(&target); + SetDateAndNotify(target); +} + +void wxCalendarCtrl::OnYearChange(wxCommandEvent& event) +{ + int year = (int)event.GetInt(); + if ( year == INT_MIN ) + { + // invalid year in the spin control, ignore it + return; + } + + wxDateTime::Tm tm = m_date.GetTm(); + + if ( tm.mday > wxDateTime::GetNumberOfDays(tm.mon, year) ) + { + tm.mday = wxDateTime::GetNumberOfDays(tm.mon, year); + } + + wxDateTime target = wxDateTime(tm.mday, tm.mon, year); + + if ( ChangeYear(&target) ) + { + SetDateAndNotify(target); + } + else + { + // In this case we don't want to change the date. That would put us + // inside the same year but a strange number of months forward/back.. + m_spinYear->SetValue(target.GetYear()); + } +} + +void wxCalendarCtrl::OnYearTextChange(wxCommandEvent& event) +{ + SetUserChangedYear(); + OnYearChange(event); +} + +// Responds to colour changes, and passes event on to children. +void wxCalendarCtrl::OnSysColourChanged(wxSysColourChangedEvent& event) +{ + // reinit colours + InitColours(); + + // Propagate the event to the children + wxControl::OnSysColourChanged(event); + + // Redraw control area + SetBackgroundColour(m_colBackground); + Refresh(); +} + +// ---------------------------------------------------------------------------- +// keyboard interface +// ---------------------------------------------------------------------------- + +void wxCalendarCtrl::OnChar(wxKeyEvent& event) +{ + wxDateTime target; + switch ( event.GetKeyCode() ) + { + case _T('+'): + case WXK_ADD: + target = m_date + wxDateSpan::Year(); + if ( ChangeYear(&target) ) + { + SetDateAndNotify(target); + } + break; + + case _T('-'): + case WXK_SUBTRACT: + target = m_date - wxDateSpan::Year(); + if ( ChangeYear(&target) ) + { + SetDateAndNotify(target); + } + break; + + case WXK_PAGEUP: + target = m_date - wxDateSpan::Month(); + ChangeMonth(&target); + SetDateAndNotify(target); // always + break; + + case WXK_PAGEDOWN: + target = m_date + wxDateSpan::Month(); + ChangeMonth(&target); + SetDateAndNotify(target); // always + break; + + case WXK_RIGHT: + if ( event.ControlDown() ) + { + target = wxDateTime(m_date).SetToNextWeekDay( + GetWindowStyle() & wxCAL_MONDAY_FIRST + ? wxDateTime::Sun : wxDateTime::Sat); + if ( !IsDateInRange(target) ) + { + target = GetUpperDateLimit(); + } + SetDateAndNotify(target); + } + else + SetDateAndNotify(m_date + wxDateSpan::Day()); + break; + + case WXK_LEFT: + if ( event.ControlDown() ) + { + target = wxDateTime(m_date).SetToPrevWeekDay( + GetWindowStyle() & wxCAL_MONDAY_FIRST + ? wxDateTime::Mon : wxDateTime::Sun); + if ( !IsDateInRange(target) ) + { + target = GetLowerDateLimit(); + } + SetDateAndNotify(target); + } + else + SetDateAndNotify(m_date - wxDateSpan::Day()); + break; + + case WXK_UP: + SetDateAndNotify(m_date - wxDateSpan::Week()); + break; + + case WXK_DOWN: + SetDateAndNotify(m_date + wxDateSpan::Week()); + break; + + case WXK_HOME: + if ( event.ControlDown() ) + SetDateAndNotify(wxDateTime::Today()); + else + SetDateAndNotify(wxDateTime(1, m_date.GetMonth(), m_date.GetYear())); + break; + + case WXK_END: + SetDateAndNotify(wxDateTime(m_date).SetToLastMonthDay()); + break; + + case WXK_RETURN: + GenerateEvent(wxEVT_CALENDAR_DOUBLECLICKED); + break; + + default: + event.Skip(); + } +} + +// ---------------------------------------------------------------------------- +// holidays handling +// ---------------------------------------------------------------------------- + +void wxCalendarCtrl::EnableHolidayDisplay(bool display) +{ + long style = GetWindowStyle(); + if ( display ) + style |= wxCAL_SHOW_HOLIDAYS; + else + style &= ~wxCAL_SHOW_HOLIDAYS; + + SetWindowStyle(style); + + if ( display ) + SetHolidayAttrs(); + else + ResetHolidayAttrs(); + + Refresh(); +} + +void wxCalendarCtrl::SetHolidayAttrs() +{ + if ( GetWindowStyle() & wxCAL_SHOW_HOLIDAYS ) + { + ResetHolidayAttrs(); + + wxDateTime::Tm tm = m_date.GetTm(); + wxDateTime dtStart(1, tm.mon, tm.year), + dtEnd = dtStart.GetLastMonthDay(); + + wxDateTimeArray hol; + wxDateTimeHolidayAuthority::GetHolidaysInRange(dtStart, dtEnd, hol); + + size_t count = hol.GetCount(); + for ( size_t n = 0; n < count; n++ ) + { + SetHoliday(hol[n].GetDay()); + } + } +} + +void wxCalendarCtrl::SetHoliday(size_t day) +{ + wxCHECK_RET( day > 0 && day < 32, _T("invalid day in SetHoliday") ); + + wxCalendarDateAttr *attr = GetAttr(day); + if ( !attr ) + { + attr = new wxCalendarDateAttr; + } + + attr->SetHoliday(true); + + // can't use SetAttr() because it would delete this pointer + m_attrs[day - 1] = attr; +} + +void wxCalendarCtrl::ResetHolidayAttrs() +{ + for ( size_t day = 0; day < 31; day++ ) + { + if ( m_attrs[day] ) + { + m_attrs[day]->SetHoliday(false); + } + } +} + + +//static +wxVisualAttributes +wxCalendarCtrl::GetClassDefaultAttributes(wxWindowVariant variant) +{ + // Use the same color scheme as wxListBox + return wxListBox::GetClassDefaultAttributes(variant); +} + +#endif // wxUSE_CALENDARCTRL diff --git a/Externals/wxWidgets/src/generic/caret.cpp b/Externals/wxWidgets/src/generic/caret.cpp index 23d25abcbb..f22308f8ff 100644 --- a/Externals/wxWidgets/src/generic/caret.cpp +++ b/Externals/wxWidgets/src/generic/caret.cpp @@ -1,283 +1,283 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: generic/caret.cpp -// Purpose: generic wxCaret class implementation -// Author: Vadim Zeitlin (original code by Robert Roebling) -// Modified by: -// Created: 25.05.99 -// RCS-ID: $Id: caret.cpp 42397 2006-10-25 12:12:56Z VS $ -// Copyright: (c) wxWidgets team -// Licence: wxWindows licence -/////////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_CARET - -#ifndef WX_PRECOMP - #include "wx/window.h" - #include "wx/dcclient.h" - #include "wx/dcmemory.h" -#endif //WX_PRECOMP - -#include "wx/caret.h" - -// ---------------------------------------------------------------------------- -// global variables for this module -// ---------------------------------------------------------------------------- - -// the blink time (common to all carets for MSW compatibility) -static int gs_blinkTime = 500; // in milliseconds - -// ============================================================================ -// implementation -// ============================================================================ - -// ---------------------------------------------------------------------------- -// timer stuff -// ---------------------------------------------------------------------------- - -wxCaretTimer::wxCaretTimer(wxCaret *caret) -{ - m_caret = caret; -} - -void wxCaretTimer::Notify() -{ - m_caret->OnTimer(); -} - -void wxCaret::OnTimer() -{ - // don't blink the caret when we don't have the focus - if ( m_hasFocus ) - Blink(); -} - -// ---------------------------------------------------------------------------- -// wxCaret static functions and data -// ---------------------------------------------------------------------------- - -int wxCaretBase::GetBlinkTime() -{ - return gs_blinkTime; -} - -void wxCaretBase::SetBlinkTime(int milliseconds) -{ - gs_blinkTime = milliseconds; -} - -// ---------------------------------------------------------------------------- -// initialization and destruction -// ---------------------------------------------------------------------------- - -void wxCaret::InitGeneric() -{ - m_hasFocus = true; - m_blinkedOut = true; -#ifndef wxHAS_CARET_USING_OVERLAYS - m_xOld = - m_yOld = -1; - m_bmpUnderCaret.Create(m_width, m_height); -#endif -} - -wxCaret::~wxCaret() -{ - if ( IsVisible() ) - { - // stop blinking - if ( m_timer.IsRunning() ) - m_timer.Stop(); - } -} - -// ---------------------------------------------------------------------------- -// showing/hiding/moving the caret (base class interface) -// ---------------------------------------------------------------------------- - -void wxCaret::DoShow() -{ - int blinkTime = GetBlinkTime(); - if ( blinkTime ) - m_timer.Start(blinkTime); - - if ( m_blinkedOut ) - Blink(); -} - -void wxCaret::DoHide() -{ - m_timer.Stop(); - - if ( !m_blinkedOut ) - { - Blink(); - } -} - -void wxCaret::DoMove() -{ -#ifdef wxHAS_CARET_USING_OVERLAYS - m_overlay.Reset(); -#endif - if ( IsVisible() ) - { - if ( !m_blinkedOut ) - { - // hide it right now and it will be shown the next time it blinks - Blink(); - - // but if the caret is not blinking, we should blink it back into - // visibility manually - if ( !m_timer.IsRunning() ) - Blink(); - } - } - //else: will be shown at the correct location when it is shown -} - -void wxCaret::DoSize() -{ - int countVisible = m_countVisible; - if (countVisible > 0) - { - m_countVisible = 0; - DoHide(); - } -#ifdef wxHAS_CARET_USING_OVERLAYS - m_overlay.Reset(); -#else - // Change bitmap size - m_bmpUnderCaret = wxBitmap(m_width, m_height); -#endif - if (countVisible > 0) - { - m_countVisible = countVisible; - DoShow(); - } -} - -// ---------------------------------------------------------------------------- -// handling the focus -// ---------------------------------------------------------------------------- - -void wxCaret::OnSetFocus() -{ - m_hasFocus = true; - - if ( IsVisible() ) - Refresh(); -} - -void wxCaret::OnKillFocus() -{ - m_hasFocus = false; - - if ( IsVisible() ) - { - // the caret must be shown - otherwise, if it is hidden now, it will - // stay so until the focus doesn't return because it won't blink any - // more - - // hide it first if it isn't hidden ... - if ( !m_blinkedOut ) - Blink(); - - // .. and show it in the new style - Blink(); - } -} - -// ---------------------------------------------------------------------------- -// drawing the caret -// ---------------------------------------------------------------------------- - -void wxCaret::Blink() -{ - m_blinkedOut = !m_blinkedOut; - - Refresh(); -} - -void wxCaret::Refresh() -{ - wxClientDC dcWin(GetWindow()); -// this is the new code, switch to 0 if this gives problems -#ifdef wxHAS_CARET_USING_OVERLAYS - wxDCOverlay dcOverlay( m_overlay, &dcWin, m_x, m_y, m_width , m_height ); - if ( m_blinkedOut ) - { - dcOverlay.Clear(); - } - else - { - DoDraw( &dcWin ); - } -#else - wxMemoryDC dcMem; - dcMem.SelectObject(m_bmpUnderCaret); - if ( m_blinkedOut ) - { - // restore the old image - dcWin.Blit(m_xOld, m_yOld, m_width, m_height, - &dcMem, 0, 0); - m_xOld = - m_yOld = -1; - } - else - { - if ( m_xOld == -1 && m_yOld == -1 ) - { - // save the part we're going to overdraw - - int x = m_x, - y = m_y; -#if defined(__WXGTK__) && !defined(__WX_DC_BLIT_FIXED__) - wxPoint pt = dcWin.GetDeviceOrigin(); - x += pt.x; - y += pt.y; -#endif // broken wxGTK wxDC::Blit - dcMem.Blit(0, 0, m_width, m_height, - &dcWin, x, y); - - m_xOld = m_x; - m_yOld = m_y; - } - //else: we already saved the image below the caret, don't do it any - // more - - // and draw the caret there - DoDraw(&dcWin); - } -#endif -} - -void wxCaret::DoDraw(wxDC *dc) -{ - dc->SetPen( *wxBLACK_PEN ); - - dc->SetBrush(*(m_hasFocus ? wxBLACK_BRUSH : wxTRANSPARENT_BRUSH)); - dc->SetPen(*wxBLACK_PEN); - - // VZ: unfortunately, the rectangle comes out a pixel smaller when this is - // done under wxGTK - no idea why - //dc->SetLogicalFunction(wxINVERT); - - dc->DrawRectangle(m_x, m_y, m_width, m_height); -} - -#endif // wxUSE_CARET +/////////////////////////////////////////////////////////////////////////////// +// Name: generic/caret.cpp +// Purpose: generic wxCaret class implementation +// Author: Vadim Zeitlin (original code by Robert Roebling) +// Modified by: +// Created: 25.05.99 +// RCS-ID: $Id: caret.cpp 42397 2006-10-25 12:12:56Z VS $ +// Copyright: (c) wxWidgets team +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_CARET + +#ifndef WX_PRECOMP + #include "wx/window.h" + #include "wx/dcclient.h" + #include "wx/dcmemory.h" +#endif //WX_PRECOMP + +#include "wx/caret.h" + +// ---------------------------------------------------------------------------- +// global variables for this module +// ---------------------------------------------------------------------------- + +// the blink time (common to all carets for MSW compatibility) +static int gs_blinkTime = 500; // in milliseconds + +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// timer stuff +// ---------------------------------------------------------------------------- + +wxCaretTimer::wxCaretTimer(wxCaret *caret) +{ + m_caret = caret; +} + +void wxCaretTimer::Notify() +{ + m_caret->OnTimer(); +} + +void wxCaret::OnTimer() +{ + // don't blink the caret when we don't have the focus + if ( m_hasFocus ) + Blink(); +} + +// ---------------------------------------------------------------------------- +// wxCaret static functions and data +// ---------------------------------------------------------------------------- + +int wxCaretBase::GetBlinkTime() +{ + return gs_blinkTime; +} + +void wxCaretBase::SetBlinkTime(int milliseconds) +{ + gs_blinkTime = milliseconds; +} + +// ---------------------------------------------------------------------------- +// initialization and destruction +// ---------------------------------------------------------------------------- + +void wxCaret::InitGeneric() +{ + m_hasFocus = true; + m_blinkedOut = true; +#ifndef wxHAS_CARET_USING_OVERLAYS + m_xOld = + m_yOld = -1; + m_bmpUnderCaret.Create(m_width, m_height); +#endif +} + +wxCaret::~wxCaret() +{ + if ( IsVisible() ) + { + // stop blinking + if ( m_timer.IsRunning() ) + m_timer.Stop(); + } +} + +// ---------------------------------------------------------------------------- +// showing/hiding/moving the caret (base class interface) +// ---------------------------------------------------------------------------- + +void wxCaret::DoShow() +{ + int blinkTime = GetBlinkTime(); + if ( blinkTime ) + m_timer.Start(blinkTime); + + if ( m_blinkedOut ) + Blink(); +} + +void wxCaret::DoHide() +{ + m_timer.Stop(); + + if ( !m_blinkedOut ) + { + Blink(); + } +} + +void wxCaret::DoMove() +{ +#ifdef wxHAS_CARET_USING_OVERLAYS + m_overlay.Reset(); +#endif + if ( IsVisible() ) + { + if ( !m_blinkedOut ) + { + // hide it right now and it will be shown the next time it blinks + Blink(); + + // but if the caret is not blinking, we should blink it back into + // visibility manually + if ( !m_timer.IsRunning() ) + Blink(); + } + } + //else: will be shown at the correct location when it is shown +} + +void wxCaret::DoSize() +{ + int countVisible = m_countVisible; + if (countVisible > 0) + { + m_countVisible = 0; + DoHide(); + } +#ifdef wxHAS_CARET_USING_OVERLAYS + m_overlay.Reset(); +#else + // Change bitmap size + m_bmpUnderCaret = wxBitmap(m_width, m_height); +#endif + if (countVisible > 0) + { + m_countVisible = countVisible; + DoShow(); + } +} + +// ---------------------------------------------------------------------------- +// handling the focus +// ---------------------------------------------------------------------------- + +void wxCaret::OnSetFocus() +{ + m_hasFocus = true; + + if ( IsVisible() ) + Refresh(); +} + +void wxCaret::OnKillFocus() +{ + m_hasFocus = false; + + if ( IsVisible() ) + { + // the caret must be shown - otherwise, if it is hidden now, it will + // stay so until the focus doesn't return because it won't blink any + // more + + // hide it first if it isn't hidden ... + if ( !m_blinkedOut ) + Blink(); + + // .. and show it in the new style + Blink(); + } +} + +// ---------------------------------------------------------------------------- +// drawing the caret +// ---------------------------------------------------------------------------- + +void wxCaret::Blink() +{ + m_blinkedOut = !m_blinkedOut; + + Refresh(); +} + +void wxCaret::Refresh() +{ + wxClientDC dcWin(GetWindow()); +// this is the new code, switch to 0 if this gives problems +#ifdef wxHAS_CARET_USING_OVERLAYS + wxDCOverlay dcOverlay( m_overlay, &dcWin, m_x, m_y, m_width , m_height ); + if ( m_blinkedOut ) + { + dcOverlay.Clear(); + } + else + { + DoDraw( &dcWin ); + } +#else + wxMemoryDC dcMem; + dcMem.SelectObject(m_bmpUnderCaret); + if ( m_blinkedOut ) + { + // restore the old image + dcWin.Blit(m_xOld, m_yOld, m_width, m_height, + &dcMem, 0, 0); + m_xOld = + m_yOld = -1; + } + else + { + if ( m_xOld == -1 && m_yOld == -1 ) + { + // save the part we're going to overdraw + + int x = m_x, + y = m_y; +#if defined(__WXGTK__) && !defined(__WX_DC_BLIT_FIXED__) + wxPoint pt = dcWin.GetDeviceOrigin(); + x += pt.x; + y += pt.y; +#endif // broken wxGTK wxDC::Blit + dcMem.Blit(0, 0, m_width, m_height, + &dcWin, x, y); + + m_xOld = m_x; + m_yOld = m_y; + } + //else: we already saved the image below the caret, don't do it any + // more + + // and draw the caret there + DoDraw(&dcWin); + } +#endif +} + +void wxCaret::DoDraw(wxDC *dc) +{ + dc->SetPen( *wxBLACK_PEN ); + + dc->SetBrush(*(m_hasFocus ? wxBLACK_BRUSH : wxTRANSPARENT_BRUSH)); + dc->SetPen(*wxBLACK_PEN); + + // VZ: unfortunately, the rectangle comes out a pixel smaller when this is + // done under wxGTK - no idea why + //dc->SetLogicalFunction(wxINVERT); + + dc->DrawRectangle(m_x, m_y, m_width, m_height); +} + +#endif // wxUSE_CARET diff --git a/Externals/wxWidgets/src/generic/choicbkg.cpp b/Externals/wxWidgets/src/generic/choicbkg.cpp index 4b64b8eec7..7d7c2f880a 100644 --- a/Externals/wxWidgets/src/generic/choicbkg.cpp +++ b/Externals/wxWidgets/src/generic/choicbkg.cpp @@ -1,328 +1,328 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: src/generic/choicbkg.cpp -// Purpose: generic implementation of wxChoicebook -// Author: Vadim Zeitlin -// Modified by: Wlodzimierz ABX Skiba from generic/listbkg.cpp -// Created: 15.09.04 -// RCS-ID: $Id: choicbkg.cpp 53045 2008-04-06 15:14:25Z VZ $ -// Copyright: (c) Vadim Zeitlin, Wlodzimierz Skiba -// Licence: wxWindows licence -/////////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_CHOICEBOOK - -#include "wx/choicebk.h" - -#ifndef WX_PRECOMP - #include "wx/settings.h" - #include "wx/choice.h" - #include "wx/sizer.h" -#endif - -#include "wx/imaglist.h" - -// ---------------------------------------------------------------------------- -// various wxWidgets macros -// ---------------------------------------------------------------------------- - -// check that the page index is valid -#define IS_VALID_PAGE(nPage) ((nPage) < GetPageCount()) - -// ---------------------------------------------------------------------------- -// event table -// ---------------------------------------------------------------------------- - -IMPLEMENT_DYNAMIC_CLASS(wxChoicebook, wxBookCtrlBase) -IMPLEMENT_DYNAMIC_CLASS(wxChoicebookEvent, wxNotifyEvent) - -#if !WXWIN_COMPATIBILITY_EVENT_TYPES -const wxEventType wxEVT_COMMAND_CHOICEBOOK_PAGE_CHANGING = wxNewEventType(); -const wxEventType wxEVT_COMMAND_CHOICEBOOK_PAGE_CHANGED = wxNewEventType(); -#endif - -BEGIN_EVENT_TABLE(wxChoicebook, wxBookCtrlBase) - EVT_CHOICE(wxID_ANY, wxChoicebook::OnChoiceSelected) -END_EVENT_TABLE() - -// ============================================================================ -// wxChoicebook implementation -// ============================================================================ - -// ---------------------------------------------------------------------------- -// wxChoicebook creation -// ---------------------------------------------------------------------------- - -void wxChoicebook::Init() -{ - m_selection = wxNOT_FOUND; -} - -bool -wxChoicebook::Create(wxWindow *parent, - wxWindowID id, - const wxPoint& pos, - const wxSize& size, - long style, - const wxString& name) -{ - if ( (style & wxBK_ALIGN_MASK) == wxBK_DEFAULT ) - { - style |= wxBK_TOP; - } - - // no border for this control, it doesn't look nice together with - // wxChoice border - style &= ~wxBORDER_MASK; - style |= wxBORDER_NONE; - - if ( !wxControl::Create(parent, id, pos, size, style, - wxDefaultValidator, name) ) - return false; - - m_bookctrl = new wxChoice - ( - this, - wxID_ANY, - wxDefaultPosition, - wxDefaultSize - ); - - wxSizer* mainSizer = new wxBoxSizer(IsVertical() ? wxVERTICAL : wxHORIZONTAL); - - if (style & wxBK_RIGHT || style & wxBK_BOTTOM) - mainSizer->Add(0, 0, 1, wxEXPAND, 0); - - m_controlSizer = new wxBoxSizer(IsVertical() ? wxHORIZONTAL : wxVERTICAL); - m_controlSizer->Add(m_bookctrl, 1, (IsVertical() ? wxALIGN_CENTRE_VERTICAL : wxALIGN_CENTRE) |wxGROW, 0); - mainSizer->Add(m_controlSizer, 0, (IsVertical() ? (int) wxGROW : (int) wxALIGN_CENTRE_VERTICAL)|wxALL, m_controlMargin); - SetSizer(mainSizer); - return true; -} - -// ---------------------------------------------------------------------------- -// wxChoicebook geometry management -// ---------------------------------------------------------------------------- - -wxSize wxChoicebook::GetControllerSize() const -{ - const wxSize sizeClient = GetClientSize(), - sizeChoice = m_controlSizer->CalcMin(); - - wxSize size; - if ( IsVertical() ) - { - size.x = sizeClient.x; - size.y = sizeChoice.y; - } - else // left/right aligned - { - size.x = sizeChoice.x; - size.y = sizeClient.y; - } - - return size; -} - -wxSize wxChoicebook::CalcSizeFromPage(const wxSize& sizePage) const -{ - // we need to add the size of the choice control and the border between - const wxSize sizeChoice = GetControllerSize(); - - wxSize size = sizePage; - if ( IsVertical() ) - { - size.y += sizeChoice.y + GetInternalBorder(); - } - else // left/right aligned - { - size.x += sizeChoice.x + GetInternalBorder(); - } - - return size; -} - - -// ---------------------------------------------------------------------------- -// accessing the pages -// ---------------------------------------------------------------------------- - -bool wxChoicebook::SetPageText(size_t n, const wxString& strText) -{ - GetChoiceCtrl()->SetString(n, strText); - - return true; -} - -wxString wxChoicebook::GetPageText(size_t n) const -{ - return GetChoiceCtrl()->GetString(n); -} - -int wxChoicebook::GetPageImage(size_t WXUNUSED(n)) const -{ - wxFAIL_MSG( _T("wxChoicebook::GetPageImage() not implemented") ); - - return wxNOT_FOUND; -} - -bool wxChoicebook::SetPageImage(size_t WXUNUSED(n), int WXUNUSED(imageId)) -{ - wxFAIL_MSG( _T("wxChoicebook::SetPageImage() not implemented") ); - - return false; -} - -// ---------------------------------------------------------------------------- -// image list stuff -// ---------------------------------------------------------------------------- - -void wxChoicebook::SetImageList(wxImageList *imageList) -{ - // TODO: can be implemented in form of static bitmap near choice control - - wxBookCtrlBase::SetImageList(imageList); -} - -// ---------------------------------------------------------------------------- -// selection -// ---------------------------------------------------------------------------- - -int wxChoicebook::GetSelection() const -{ - return m_selection; -} - -wxBookCtrlBaseEvent* wxChoicebook::CreatePageChangingEvent() const -{ - return new wxChoicebookEvent(wxEVT_COMMAND_CHOICEBOOK_PAGE_CHANGING, m_windowId); -} - -void wxChoicebook::MakeChangedEvent(wxBookCtrlBaseEvent &event) -{ - event.SetEventType(wxEVT_COMMAND_CHOICEBOOK_PAGE_CHANGED); -} - -// ---------------------------------------------------------------------------- -// adding/removing the pages -// ---------------------------------------------------------------------------- - -bool -wxChoicebook::InsertPage(size_t n, - wxWindow *page, - const wxString& text, - bool bSelect, - int imageId) -{ - if ( !wxBookCtrlBase::InsertPage(n, page, text, bSelect, imageId) ) - return false; - - GetChoiceCtrl()->Insert(text, n); - - // if the inserted page is before the selected one, we must update the - // index of the selected page - if ( int(n) <= m_selection ) - { - // one extra page added - m_selection++; - GetChoiceCtrl()->Select(m_selection); - } - - // some page should be selected: either this one or the first one if there - // is still no selection - int selNew = wxNOT_FOUND; - if ( bSelect ) - selNew = n; - else if ( m_selection == wxNOT_FOUND ) - selNew = 0; - - if ( selNew != m_selection ) - page->Hide(); - - if ( selNew != wxNOT_FOUND ) - SetSelection(selNew); - - return true; -} - -wxWindow *wxChoicebook::DoRemovePage(size_t page) -{ - const size_t page_count = GetPageCount(); - wxWindow *win = wxBookCtrlBase::DoRemovePage(page); - - if ( win ) - { - GetChoiceCtrl()->Delete(page); - - if (m_selection >= (int)page) - { - // force new sel valid if possible - int sel = m_selection - 1; - if (page_count == 1) - sel = wxNOT_FOUND; - else if ((page_count == 2) || (sel == -1)) - sel = 0; - - // force sel invalid if deleting current page - don't try to hide it - m_selection = (m_selection == (int)page) ? wxNOT_FOUND : m_selection - 1; - - if ((sel != wxNOT_FOUND) && (sel != m_selection)) - SetSelection(sel); - } - } - - return win; -} - - -bool wxChoicebook::DeleteAllPages() -{ - m_selection = wxNOT_FOUND; - GetChoiceCtrl()->Clear(); - return wxBookCtrlBase::DeleteAllPages(); -} - -// ---------------------------------------------------------------------------- -// wxChoicebook events -// ---------------------------------------------------------------------------- - -void wxChoicebook::OnChoiceSelected(wxCommandEvent& eventChoice) -{ - if ( eventChoice.GetEventObject() != m_bookctrl ) - { - eventChoice.Skip(); - return; - } - - const int selNew = eventChoice.GetSelection(); - - if ( selNew == m_selection ) - { - // this event can only come from our own Select(m_selection) below - // which we call when the page change is vetoed, so we should simply - // ignore it - return; - } - - SetSelection(selNew); - - // change wasn't allowed, return to previous state - if (m_selection != selNew) - GetChoiceCtrl()->Select(m_selection); -} - -#endif // wxUSE_CHOICEBOOK +/////////////////////////////////////////////////////////////////////////////// +// Name: src/generic/choicbkg.cpp +// Purpose: generic implementation of wxChoicebook +// Author: Vadim Zeitlin +// Modified by: Wlodzimierz ABX Skiba from generic/listbkg.cpp +// Created: 15.09.04 +// RCS-ID: $Id: choicbkg.cpp 53045 2008-04-06 15:14:25Z VZ $ +// Copyright: (c) Vadim Zeitlin, Wlodzimierz Skiba +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_CHOICEBOOK + +#include "wx/choicebk.h" + +#ifndef WX_PRECOMP + #include "wx/settings.h" + #include "wx/choice.h" + #include "wx/sizer.h" +#endif + +#include "wx/imaglist.h" + +// ---------------------------------------------------------------------------- +// various wxWidgets macros +// ---------------------------------------------------------------------------- + +// check that the page index is valid +#define IS_VALID_PAGE(nPage) ((nPage) < GetPageCount()) + +// ---------------------------------------------------------------------------- +// event table +// ---------------------------------------------------------------------------- + +IMPLEMENT_DYNAMIC_CLASS(wxChoicebook, wxBookCtrlBase) +IMPLEMENT_DYNAMIC_CLASS(wxChoicebookEvent, wxNotifyEvent) + +#if !WXWIN_COMPATIBILITY_EVENT_TYPES +const wxEventType wxEVT_COMMAND_CHOICEBOOK_PAGE_CHANGING = wxNewEventType(); +const wxEventType wxEVT_COMMAND_CHOICEBOOK_PAGE_CHANGED = wxNewEventType(); +#endif + +BEGIN_EVENT_TABLE(wxChoicebook, wxBookCtrlBase) + EVT_CHOICE(wxID_ANY, wxChoicebook::OnChoiceSelected) +END_EVENT_TABLE() + +// ============================================================================ +// wxChoicebook implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// wxChoicebook creation +// ---------------------------------------------------------------------------- + +void wxChoicebook::Init() +{ + m_selection = wxNOT_FOUND; +} + +bool +wxChoicebook::Create(wxWindow *parent, + wxWindowID id, + const wxPoint& pos, + const wxSize& size, + long style, + const wxString& name) +{ + if ( (style & wxBK_ALIGN_MASK) == wxBK_DEFAULT ) + { + style |= wxBK_TOP; + } + + // no border for this control, it doesn't look nice together with + // wxChoice border + style &= ~wxBORDER_MASK; + style |= wxBORDER_NONE; + + if ( !wxControl::Create(parent, id, pos, size, style, + wxDefaultValidator, name) ) + return false; + + m_bookctrl = new wxChoice + ( + this, + wxID_ANY, + wxDefaultPosition, + wxDefaultSize + ); + + wxSizer* mainSizer = new wxBoxSizer(IsVertical() ? wxVERTICAL : wxHORIZONTAL); + + if (style & wxBK_RIGHT || style & wxBK_BOTTOM) + mainSizer->Add(0, 0, 1, wxEXPAND, 0); + + m_controlSizer = new wxBoxSizer(IsVertical() ? wxHORIZONTAL : wxVERTICAL); + m_controlSizer->Add(m_bookctrl, 1, (IsVertical() ? wxALIGN_CENTRE_VERTICAL : wxALIGN_CENTRE) |wxGROW, 0); + mainSizer->Add(m_controlSizer, 0, (IsVertical() ? (int) wxGROW : (int) wxALIGN_CENTRE_VERTICAL)|wxALL, m_controlMargin); + SetSizer(mainSizer); + return true; +} + +// ---------------------------------------------------------------------------- +// wxChoicebook geometry management +// ---------------------------------------------------------------------------- + +wxSize wxChoicebook::GetControllerSize() const +{ + const wxSize sizeClient = GetClientSize(), + sizeChoice = m_controlSizer->CalcMin(); + + wxSize size; + if ( IsVertical() ) + { + size.x = sizeClient.x; + size.y = sizeChoice.y; + } + else // left/right aligned + { + size.x = sizeChoice.x; + size.y = sizeClient.y; + } + + return size; +} + +wxSize wxChoicebook::CalcSizeFromPage(const wxSize& sizePage) const +{ + // we need to add the size of the choice control and the border between + const wxSize sizeChoice = GetControllerSize(); + + wxSize size = sizePage; + if ( IsVertical() ) + { + size.y += sizeChoice.y + GetInternalBorder(); + } + else // left/right aligned + { + size.x += sizeChoice.x + GetInternalBorder(); + } + + return size; +} + + +// ---------------------------------------------------------------------------- +// accessing the pages +// ---------------------------------------------------------------------------- + +bool wxChoicebook::SetPageText(size_t n, const wxString& strText) +{ + GetChoiceCtrl()->SetString(n, strText); + + return true; +} + +wxString wxChoicebook::GetPageText(size_t n) const +{ + return GetChoiceCtrl()->GetString(n); +} + +int wxChoicebook::GetPageImage(size_t WXUNUSED(n)) const +{ + wxFAIL_MSG( _T("wxChoicebook::GetPageImage() not implemented") ); + + return wxNOT_FOUND; +} + +bool wxChoicebook::SetPageImage(size_t WXUNUSED(n), int WXUNUSED(imageId)) +{ + wxFAIL_MSG( _T("wxChoicebook::SetPageImage() not implemented") ); + + return false; +} + +// ---------------------------------------------------------------------------- +// image list stuff +// ---------------------------------------------------------------------------- + +void wxChoicebook::SetImageList(wxImageList *imageList) +{ + // TODO: can be implemented in form of static bitmap near choice control + + wxBookCtrlBase::SetImageList(imageList); +} + +// ---------------------------------------------------------------------------- +// selection +// ---------------------------------------------------------------------------- + +int wxChoicebook::GetSelection() const +{ + return m_selection; +} + +wxBookCtrlBaseEvent* wxChoicebook::CreatePageChangingEvent() const +{ + return new wxChoicebookEvent(wxEVT_COMMAND_CHOICEBOOK_PAGE_CHANGING, m_windowId); +} + +void wxChoicebook::MakeChangedEvent(wxBookCtrlBaseEvent &event) +{ + event.SetEventType(wxEVT_COMMAND_CHOICEBOOK_PAGE_CHANGED); +} + +// ---------------------------------------------------------------------------- +// adding/removing the pages +// ---------------------------------------------------------------------------- + +bool +wxChoicebook::InsertPage(size_t n, + wxWindow *page, + const wxString& text, + bool bSelect, + int imageId) +{ + if ( !wxBookCtrlBase::InsertPage(n, page, text, bSelect, imageId) ) + return false; + + GetChoiceCtrl()->Insert(text, n); + + // if the inserted page is before the selected one, we must update the + // index of the selected page + if ( int(n) <= m_selection ) + { + // one extra page added + m_selection++; + GetChoiceCtrl()->Select(m_selection); + } + + // some page should be selected: either this one or the first one if there + // is still no selection + int selNew = wxNOT_FOUND; + if ( bSelect ) + selNew = n; + else if ( m_selection == wxNOT_FOUND ) + selNew = 0; + + if ( selNew != m_selection ) + page->Hide(); + + if ( selNew != wxNOT_FOUND ) + SetSelection(selNew); + + return true; +} + +wxWindow *wxChoicebook::DoRemovePage(size_t page) +{ + const size_t page_count = GetPageCount(); + wxWindow *win = wxBookCtrlBase::DoRemovePage(page); + + if ( win ) + { + GetChoiceCtrl()->Delete(page); + + if (m_selection >= (int)page) + { + // force new sel valid if possible + int sel = m_selection - 1; + if (page_count == 1) + sel = wxNOT_FOUND; + else if ((page_count == 2) || (sel == -1)) + sel = 0; + + // force sel invalid if deleting current page - don't try to hide it + m_selection = (m_selection == (int)page) ? wxNOT_FOUND : m_selection - 1; + + if ((sel != wxNOT_FOUND) && (sel != m_selection)) + SetSelection(sel); + } + } + + return win; +} + + +bool wxChoicebook::DeleteAllPages() +{ + m_selection = wxNOT_FOUND; + GetChoiceCtrl()->Clear(); + return wxBookCtrlBase::DeleteAllPages(); +} + +// ---------------------------------------------------------------------------- +// wxChoicebook events +// ---------------------------------------------------------------------------- + +void wxChoicebook::OnChoiceSelected(wxCommandEvent& eventChoice) +{ + if ( eventChoice.GetEventObject() != m_bookctrl ) + { + eventChoice.Skip(); + return; + } + + const int selNew = eventChoice.GetSelection(); + + if ( selNew == m_selection ) + { + // this event can only come from our own Select(m_selection) below + // which we call when the page change is vetoed, so we should simply + // ignore it + return; + } + + SetSelection(selNew); + + // change wasn't allowed, return to previous state + if (m_selection != selNew) + GetChoiceCtrl()->Select(m_selection); +} + +#endif // wxUSE_CHOICEBOOK diff --git a/Externals/wxWidgets/src/generic/choicdgg.cpp b/Externals/wxWidgets/src/generic/choicdgg.cpp index 1caf90aa31..264b2288ed 100644 --- a/Externals/wxWidgets/src/generic/choicdgg.cpp +++ b/Externals/wxWidgets/src/generic/choicdgg.cpp @@ -1,556 +1,556 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/generic/choicdgg.cpp -// Purpose: Choice dialogs -// Author: Julian Smart -// Modified by: 03.11.00: VZ to add wxArrayString and multiple sel functions -// Created: 04/01/98 -// RCS-ID: $Id: choicdgg.cpp 44620 2007-03-06 09:56:43Z JS $ -// Copyright: (c) wxWidgets team -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_CHOICEDLG - -#ifndef WX_PRECOMP - #include - #include "wx/utils.h" - #include "wx/dialog.h" - #include "wx/button.h" - #include "wx/listbox.h" - #include "wx/checklst.h" - #include "wx/stattext.h" - #include "wx/intl.h" - #include "wx/sizer.h" - #include "wx/arrstr.h" -#endif - -#include "wx/statline.h" -#include "wx/settings.h" -#include "wx/generic/choicdgg.h" - -// ---------------------------------------------------------------------------- -// constants -// ---------------------------------------------------------------------------- - -#define wxID_LISTBOX 3000 - -// ---------------------------------------------------------------------------- -// private functions -// ---------------------------------------------------------------------------- - -// convert wxArrayString into a wxString[] which must be delete[]d by caller -static int ConvertWXArrayToC(const wxArrayString& aChoices, wxString **choices); - -// ============================================================================ -// implementation -// ============================================================================ - -// ---------------------------------------------------------------------------- -// helpers -// ---------------------------------------------------------------------------- - -int ConvertWXArrayToC(const wxArrayString& aChoices, wxString **choices) -{ - int n = aChoices.GetCount(); - *choices = new wxString[n]; - - for ( int i = 0; i < n; i++ ) - { - (*choices)[i] = aChoices[i]; - } - - return n; -} - -// ---------------------------------------------------------------------------- -// wrapper functions -// ---------------------------------------------------------------------------- - -wxString wxGetSingleChoice( const wxString& message, - const wxString& caption, - int n, const wxString *choices, - wxWindow *parent, - int WXUNUSED(x), int WXUNUSED(y), - bool WXUNUSED(centre), - int WXUNUSED(width), int WXUNUSED(height) ) -{ - wxSingleChoiceDialog dialog(parent, message, caption, n, choices); - wxString choice; - if ( dialog.ShowModal() == wxID_OK ) - choice = dialog.GetStringSelection(); - - return choice; -} - -wxString wxGetSingleChoice( const wxString& message, - const wxString& caption, - const wxArrayString& aChoices, - wxWindow *parent, - int x, int y, - bool centre, - int width, int height) -{ - wxString *choices; - int n = ConvertWXArrayToC(aChoices, &choices); - wxString res = wxGetSingleChoice(message, caption, n, choices, parent, - x, y, centre, width, height); - delete [] choices; - - return res; -} - -int wxGetSingleChoiceIndex( const wxString& message, - const wxString& caption, - int n, const wxString *choices, - wxWindow *parent, - int WXUNUSED(x), int WXUNUSED(y), - bool WXUNUSED(centre), - int WXUNUSED(width), int WXUNUSED(height) ) -{ - wxSingleChoiceDialog dialog(parent, message, caption, n, choices); - int choice; - if ( dialog.ShowModal() == wxID_OK ) - choice = dialog.GetSelection(); - else - choice = -1; - - return choice; -} - -int wxGetSingleChoiceIndex( const wxString& message, - const wxString& caption, - const wxArrayString& aChoices, - wxWindow *parent, - int x, int y, - bool centre, - int width, int height) -{ - wxString *choices; - int n = ConvertWXArrayToC(aChoices, &choices); - int res = wxGetSingleChoiceIndex(message, caption, n, choices, parent, - x, y, centre, width, height); - delete [] choices; - - return res; -} - -void *wxGetSingleChoiceData( const wxString& message, - const wxString& caption, - int n, const wxString *choices, - void **client_data, - wxWindow *parent, - int WXUNUSED(x), int WXUNUSED(y), - bool WXUNUSED(centre), - int WXUNUSED(width), int WXUNUSED(height) ) -{ - wxSingleChoiceDialog dialog(parent, message, caption, n, choices, - (char **)client_data); - void *data; - if ( dialog.ShowModal() == wxID_OK ) - data = dialog.GetSelectionClientData(); - else - data = NULL; - - return data; -} - -void *wxGetSingleChoiceData( const wxString& message, - const wxString& caption, - const wxArrayString& aChoices, - void **client_data, - wxWindow *parent, - int x, int y, - bool centre, - int width, int height) -{ - wxString *choices; - int n = ConvertWXArrayToC(aChoices, &choices); - void *res = wxGetSingleChoiceData(message, caption, n, choices, - client_data, parent, - x, y, centre, width, height); - delete [] choices; - - return res; -} - -size_t wxGetMultipleChoices(wxArrayInt& selections, - const wxString& message, - const wxString& caption, - int n, const wxString *choices, - wxWindow *parent, - int WXUNUSED(x), int WXUNUSED(y), - bool WXUNUSED(centre), - int WXUNUSED(width), int WXUNUSED(height)) -{ - wxMultiChoiceDialog dialog(parent, message, caption, n, choices); - - // call this even if selections array is empty and this then (correctly) - // deselects the first item which is selected by default - dialog.SetSelections(selections); - - if ( dialog.ShowModal() == wxID_OK ) - selections = dialog.GetSelections(); - else - selections.Empty(); - - return selections.GetCount(); -} - -size_t wxGetMultipleChoices(wxArrayInt& selections, - const wxString& message, - const wxString& caption, - const wxArrayString& aChoices, - wxWindow *parent, - int x, int y, - bool centre, - int width, int height) -{ - wxString *choices; - int n = ConvertWXArrayToC(aChoices, &choices); - size_t res = wxGetMultipleChoices(selections, message, caption, - n, choices, parent, - x, y, centre, width, height); - delete [] choices; - - return res; -} - -// ---------------------------------------------------------------------------- -// wxAnyChoiceDialog -// ---------------------------------------------------------------------------- - -bool wxAnyChoiceDialog::Create(wxWindow *parent, - const wxString& message, - const wxString& caption, - int n, const wxString *choices, - long styleDlg, - const wxPoint& pos, - long styleLbox) -{ -#ifdef __WXMAC__ - // FIXME: why?? - if ( !wxDialog::Create(parent, wxID_ANY, caption, pos, wxDefaultSize, styleDlg & (~wxCANCEL) ) ) - return false; -#else - if ( !wxDialog::Create(parent, wxID_ANY, caption, pos, wxDefaultSize, styleDlg) ) - return false; -#endif - - wxBoxSizer *topsizer = new wxBoxSizer( wxVERTICAL ); - - // 1) text message - topsizer-> - Add(CreateTextSizer(message), wxSizerFlags().Expand().TripleBorder()); - - // 2) list box - m_listbox = CreateList(n, choices, styleLbox); - - if ( n > 0 ) - m_listbox->SetSelection(0); - - topsizer-> - Add(m_listbox, wxSizerFlags().Expand().Proportion(1).TripleBorder(wxLEFT | wxRIGHT)); - - // 3) buttons if any - wxSizer * - buttonSizer = CreateSeparatedButtonSizer(styleDlg & ButtonSizerFlags); - if ( buttonSizer ) - { - topsizer->Add(buttonSizer, wxSizerFlags().Expand().DoubleBorder()); - } - - SetSizer( topsizer ); - - topsizer->SetSizeHints( this ); - topsizer->Fit( this ); - - if ( styleDlg & wxCENTRE ) - Centre(wxBOTH); - - m_listbox->SetFocus(); - - return true; -} - -bool wxAnyChoiceDialog::Create(wxWindow *parent, - const wxString& message, - const wxString& caption, - const wxArrayString& choices, - long styleDlg, - const wxPoint& pos, - long styleLbox) -{ - wxCArrayString chs(choices); - return Create(parent, message, caption, chs.GetCount(), chs.GetStrings(), - styleDlg, pos, styleLbox); -} - -wxListBoxBase *wxAnyChoiceDialog::CreateList(int n, const wxString *choices, long styleLbox) -{ - wxSize size = wxDefaultSize; - if (wxSystemSettings::GetScreenType() > wxSYS_SCREEN_PDA) - size = wxSize(300, 200); - return new wxListBox( this, wxID_LISTBOX, - wxDefaultPosition, size, - n, choices, - styleLbox ); -} - -// ---------------------------------------------------------------------------- -// wxSingleChoiceDialog -// ---------------------------------------------------------------------------- - -BEGIN_EVENT_TABLE(wxSingleChoiceDialog, wxDialog) - EVT_BUTTON(wxID_OK, wxSingleChoiceDialog::OnOK) -#ifndef __SMARTPHONE__ - EVT_LISTBOX_DCLICK(wxID_LISTBOX, wxSingleChoiceDialog::OnListBoxDClick) -#endif -#ifdef __WXWINCE__ - EVT_JOY_BUTTON_DOWN(wxSingleChoiceDialog::OnJoystickButtonDown) -#endif -END_EVENT_TABLE() - -IMPLEMENT_DYNAMIC_CLASS(wxSingleChoiceDialog, wxDialog) - -wxSingleChoiceDialog::wxSingleChoiceDialog(wxWindow *parent, - const wxString& message, - const wxString& caption, - int n, - const wxString *choices, - char **clientData, - long style, - const wxPoint& WXUNUSED(pos)) -{ - Create(parent, message, caption, n, choices, clientData, style); -} - -wxSingleChoiceDialog::wxSingleChoiceDialog(wxWindow *parent, - const wxString& message, - const wxString& caption, - const wxArrayString& choices, - char **clientData, - long style, - const wxPoint& WXUNUSED(pos)) -{ - Create(parent, message, caption, choices, clientData, style); -} - -bool wxSingleChoiceDialog::Create( wxWindow *parent, - const wxString& message, - const wxString& caption, - int n, - const wxString *choices, - char **clientData, - long style, - const wxPoint& pos ) -{ - if ( !wxAnyChoiceDialog::Create(parent, message, caption, - n, choices, - style, pos) ) - return false; - - m_selection = n > 0 ? 0 : -1; - - if (clientData) - { - for (int i = 0; i < n; i++) - m_listbox->SetClientData(i, clientData[i]); - } - - return true; -} - -bool wxSingleChoiceDialog::Create( wxWindow *parent, - const wxString& message, - const wxString& caption, - const wxArrayString& choices, - char **clientData, - long style, - const wxPoint& pos ) -{ - wxCArrayString chs(choices); - return Create( parent, message, caption, chs.GetCount(), chs.GetStrings(), - clientData, style, pos ); -} - -// Set the selection -void wxSingleChoiceDialog::SetSelection(int sel) -{ - m_listbox->SetSelection(sel); - m_selection = sel; -} - -void wxSingleChoiceDialog::OnOK(wxCommandEvent& WXUNUSED(event)) -{ - DoChoice(); -} - -#ifndef __SMARTPHONE__ -void wxSingleChoiceDialog::OnListBoxDClick(wxCommandEvent& WXUNUSED(event)) -{ - DoChoice(); -} -#endif - -#ifdef __WXWINCE__ -void wxSingleChoiceDialog::OnJoystickButtonDown(wxJoystickEvent& WXUNUSED(event)) -{ - DoChoice(); -} -#endif - -void wxSingleChoiceDialog::DoChoice() -{ - m_selection = m_listbox->GetSelection(); - m_stringSelection = m_listbox->GetStringSelection(); - - if ( m_listbox->HasClientUntypedData() ) - SetClientData(m_listbox->GetClientData(m_selection)); - - EndModal(wxID_OK); -} - -// ---------------------------------------------------------------------------- -// wxMultiChoiceDialog -// ---------------------------------------------------------------------------- - -IMPLEMENT_DYNAMIC_CLASS(wxMultiChoiceDialog, wxDialog) - -bool wxMultiChoiceDialog::Create( wxWindow *parent, - const wxString& message, - const wxString& caption, - int n, - const wxString *choices, - long style, - const wxPoint& pos ) -{ - long styleLbox; -#if wxUSE_CHECKLISTBOX - styleLbox = wxLB_ALWAYS_SB; -#else - styleLbox = wxLB_ALWAYS_SB | wxLB_EXTENDED; -#endif - - if ( !wxAnyChoiceDialog::Create(parent, message, caption, - n, choices, - style, pos, - styleLbox) ) - return false; - - return true; -} - -bool wxMultiChoiceDialog::Create( wxWindow *parent, - const wxString& message, - const wxString& caption, - const wxArrayString& choices, - long style, - const wxPoint& pos ) -{ - wxCArrayString chs(choices); - return Create( parent, message, caption, chs.GetCount(), - chs.GetStrings(), style, pos ); -} - -void wxMultiChoiceDialog::SetSelections(const wxArrayInt& selections) -{ -#if wxUSE_CHECKLISTBOX - wxCheckListBox* checkListBox = wxDynamicCast(m_listbox, wxCheckListBox); - if (checkListBox) - { - // first clear all currently selected items - size_t n, - count = checkListBox->GetCount(); - for ( n = 0; n < count; ++n ) - { - if (checkListBox->IsChecked(n)) - checkListBox->Check(n, false); - } - - // now select the ones which should be selected - count = selections.GetCount(); - for ( n = 0; n < count; n++ ) - { - checkListBox->Check(selections[n]); - } - - return; - } -#endif - - // first clear all currently selected items - size_t n, - count = m_listbox->GetCount(); - for ( n = 0; n < count; ++n ) - { - m_listbox->Deselect(n); - } - - // now select the ones which should be selected - count = selections.GetCount(); - for ( n = 0; n < count; n++ ) - { - m_listbox->Select(selections[n]); - } -} - -bool wxMultiChoiceDialog::TransferDataFromWindow() -{ - m_selections.Empty(); - -#if wxUSE_CHECKLISTBOX - wxCheckListBox* checkListBox = wxDynamicCast(m_listbox, wxCheckListBox); - if (checkListBox) - { - size_t count = checkListBox->GetCount(); - for ( size_t n = 0; n < count; n++ ) - { - if ( checkListBox->IsChecked(n) ) - m_selections.Add(n); - } - return true; - } -#endif - - size_t count = m_listbox->GetCount(); - for ( size_t n = 0; n < count; n++ ) - { - if ( m_listbox->IsSelected(n) ) - m_selections.Add(n); - } - - return true; -} - -#if wxUSE_CHECKLISTBOX - -wxListBoxBase *wxMultiChoiceDialog::CreateList(int n, const wxString *choices, long styleLbox) -{ - wxSize size = wxDefaultSize; - if (wxSystemSettings::GetScreenType() > wxSYS_SCREEN_PDA) - size = wxSize(300, 200); - - return new wxCheckListBox( this, wxID_LISTBOX, - wxDefaultPosition, size, - n, choices, - styleLbox ); -} - -#endif // wxUSE_CHECKLISTBOX - -#endif // wxUSE_CHOICEDLG +///////////////////////////////////////////////////////////////////////////// +// Name: src/generic/choicdgg.cpp +// Purpose: Choice dialogs +// Author: Julian Smart +// Modified by: 03.11.00: VZ to add wxArrayString and multiple sel functions +// Created: 04/01/98 +// RCS-ID: $Id: choicdgg.cpp 44620 2007-03-06 09:56:43Z JS $ +// Copyright: (c) wxWidgets team +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_CHOICEDLG + +#ifndef WX_PRECOMP + #include + #include "wx/utils.h" + #include "wx/dialog.h" + #include "wx/button.h" + #include "wx/listbox.h" + #include "wx/checklst.h" + #include "wx/stattext.h" + #include "wx/intl.h" + #include "wx/sizer.h" + #include "wx/arrstr.h" +#endif + +#include "wx/statline.h" +#include "wx/settings.h" +#include "wx/generic/choicdgg.h" + +// ---------------------------------------------------------------------------- +// constants +// ---------------------------------------------------------------------------- + +#define wxID_LISTBOX 3000 + +// ---------------------------------------------------------------------------- +// private functions +// ---------------------------------------------------------------------------- + +// convert wxArrayString into a wxString[] which must be delete[]d by caller +static int ConvertWXArrayToC(const wxArrayString& aChoices, wxString **choices); + +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// helpers +// ---------------------------------------------------------------------------- + +int ConvertWXArrayToC(const wxArrayString& aChoices, wxString **choices) +{ + int n = aChoices.GetCount(); + *choices = new wxString[n]; + + for ( int i = 0; i < n; i++ ) + { + (*choices)[i] = aChoices[i]; + } + + return n; +} + +// ---------------------------------------------------------------------------- +// wrapper functions +// ---------------------------------------------------------------------------- + +wxString wxGetSingleChoice( const wxString& message, + const wxString& caption, + int n, const wxString *choices, + wxWindow *parent, + int WXUNUSED(x), int WXUNUSED(y), + bool WXUNUSED(centre), + int WXUNUSED(width), int WXUNUSED(height) ) +{ + wxSingleChoiceDialog dialog(parent, message, caption, n, choices); + wxString choice; + if ( dialog.ShowModal() == wxID_OK ) + choice = dialog.GetStringSelection(); + + return choice; +} + +wxString wxGetSingleChoice( const wxString& message, + const wxString& caption, + const wxArrayString& aChoices, + wxWindow *parent, + int x, int y, + bool centre, + int width, int height) +{ + wxString *choices; + int n = ConvertWXArrayToC(aChoices, &choices); + wxString res = wxGetSingleChoice(message, caption, n, choices, parent, + x, y, centre, width, height); + delete [] choices; + + return res; +} + +int wxGetSingleChoiceIndex( const wxString& message, + const wxString& caption, + int n, const wxString *choices, + wxWindow *parent, + int WXUNUSED(x), int WXUNUSED(y), + bool WXUNUSED(centre), + int WXUNUSED(width), int WXUNUSED(height) ) +{ + wxSingleChoiceDialog dialog(parent, message, caption, n, choices); + int choice; + if ( dialog.ShowModal() == wxID_OK ) + choice = dialog.GetSelection(); + else + choice = -1; + + return choice; +} + +int wxGetSingleChoiceIndex( const wxString& message, + const wxString& caption, + const wxArrayString& aChoices, + wxWindow *parent, + int x, int y, + bool centre, + int width, int height) +{ + wxString *choices; + int n = ConvertWXArrayToC(aChoices, &choices); + int res = wxGetSingleChoiceIndex(message, caption, n, choices, parent, + x, y, centre, width, height); + delete [] choices; + + return res; +} + +void *wxGetSingleChoiceData( const wxString& message, + const wxString& caption, + int n, const wxString *choices, + void **client_data, + wxWindow *parent, + int WXUNUSED(x), int WXUNUSED(y), + bool WXUNUSED(centre), + int WXUNUSED(width), int WXUNUSED(height) ) +{ + wxSingleChoiceDialog dialog(parent, message, caption, n, choices, + (char **)client_data); + void *data; + if ( dialog.ShowModal() == wxID_OK ) + data = dialog.GetSelectionClientData(); + else + data = NULL; + + return data; +} + +void *wxGetSingleChoiceData( const wxString& message, + const wxString& caption, + const wxArrayString& aChoices, + void **client_data, + wxWindow *parent, + int x, int y, + bool centre, + int width, int height) +{ + wxString *choices; + int n = ConvertWXArrayToC(aChoices, &choices); + void *res = wxGetSingleChoiceData(message, caption, n, choices, + client_data, parent, + x, y, centre, width, height); + delete [] choices; + + return res; +} + +size_t wxGetMultipleChoices(wxArrayInt& selections, + const wxString& message, + const wxString& caption, + int n, const wxString *choices, + wxWindow *parent, + int WXUNUSED(x), int WXUNUSED(y), + bool WXUNUSED(centre), + int WXUNUSED(width), int WXUNUSED(height)) +{ + wxMultiChoiceDialog dialog(parent, message, caption, n, choices); + + // call this even if selections array is empty and this then (correctly) + // deselects the first item which is selected by default + dialog.SetSelections(selections); + + if ( dialog.ShowModal() == wxID_OK ) + selections = dialog.GetSelections(); + else + selections.Empty(); + + return selections.GetCount(); +} + +size_t wxGetMultipleChoices(wxArrayInt& selections, + const wxString& message, + const wxString& caption, + const wxArrayString& aChoices, + wxWindow *parent, + int x, int y, + bool centre, + int width, int height) +{ + wxString *choices; + int n = ConvertWXArrayToC(aChoices, &choices); + size_t res = wxGetMultipleChoices(selections, message, caption, + n, choices, parent, + x, y, centre, width, height); + delete [] choices; + + return res; +} + +// ---------------------------------------------------------------------------- +// wxAnyChoiceDialog +// ---------------------------------------------------------------------------- + +bool wxAnyChoiceDialog::Create(wxWindow *parent, + const wxString& message, + const wxString& caption, + int n, const wxString *choices, + long styleDlg, + const wxPoint& pos, + long styleLbox) +{ +#ifdef __WXMAC__ + // FIXME: why?? + if ( !wxDialog::Create(parent, wxID_ANY, caption, pos, wxDefaultSize, styleDlg & (~wxCANCEL) ) ) + return false; +#else + if ( !wxDialog::Create(parent, wxID_ANY, caption, pos, wxDefaultSize, styleDlg) ) + return false; +#endif + + wxBoxSizer *topsizer = new wxBoxSizer( wxVERTICAL ); + + // 1) text message + topsizer-> + Add(CreateTextSizer(message), wxSizerFlags().Expand().TripleBorder()); + + // 2) list box + m_listbox = CreateList(n, choices, styleLbox); + + if ( n > 0 ) + m_listbox->SetSelection(0); + + topsizer-> + Add(m_listbox, wxSizerFlags().Expand().Proportion(1).TripleBorder(wxLEFT | wxRIGHT)); + + // 3) buttons if any + wxSizer * + buttonSizer = CreateSeparatedButtonSizer(styleDlg & ButtonSizerFlags); + if ( buttonSizer ) + { + topsizer->Add(buttonSizer, wxSizerFlags().Expand().DoubleBorder()); + } + + SetSizer( topsizer ); + + topsizer->SetSizeHints( this ); + topsizer->Fit( this ); + + if ( styleDlg & wxCENTRE ) + Centre(wxBOTH); + + m_listbox->SetFocus(); + + return true; +} + +bool wxAnyChoiceDialog::Create(wxWindow *parent, + const wxString& message, + const wxString& caption, + const wxArrayString& choices, + long styleDlg, + const wxPoint& pos, + long styleLbox) +{ + wxCArrayString chs(choices); + return Create(parent, message, caption, chs.GetCount(), chs.GetStrings(), + styleDlg, pos, styleLbox); +} + +wxListBoxBase *wxAnyChoiceDialog::CreateList(int n, const wxString *choices, long styleLbox) +{ + wxSize size = wxDefaultSize; + if (wxSystemSettings::GetScreenType() > wxSYS_SCREEN_PDA) + size = wxSize(300, 200); + return new wxListBox( this, wxID_LISTBOX, + wxDefaultPosition, size, + n, choices, + styleLbox ); +} + +// ---------------------------------------------------------------------------- +// wxSingleChoiceDialog +// ---------------------------------------------------------------------------- + +BEGIN_EVENT_TABLE(wxSingleChoiceDialog, wxDialog) + EVT_BUTTON(wxID_OK, wxSingleChoiceDialog::OnOK) +#ifndef __SMARTPHONE__ + EVT_LISTBOX_DCLICK(wxID_LISTBOX, wxSingleChoiceDialog::OnListBoxDClick) +#endif +#ifdef __WXWINCE__ + EVT_JOY_BUTTON_DOWN(wxSingleChoiceDialog::OnJoystickButtonDown) +#endif +END_EVENT_TABLE() + +IMPLEMENT_DYNAMIC_CLASS(wxSingleChoiceDialog, wxDialog) + +wxSingleChoiceDialog::wxSingleChoiceDialog(wxWindow *parent, + const wxString& message, + const wxString& caption, + int n, + const wxString *choices, + char **clientData, + long style, + const wxPoint& WXUNUSED(pos)) +{ + Create(parent, message, caption, n, choices, clientData, style); +} + +wxSingleChoiceDialog::wxSingleChoiceDialog(wxWindow *parent, + const wxString& message, + const wxString& caption, + const wxArrayString& choices, + char **clientData, + long style, + const wxPoint& WXUNUSED(pos)) +{ + Create(parent, message, caption, choices, clientData, style); +} + +bool wxSingleChoiceDialog::Create( wxWindow *parent, + const wxString& message, + const wxString& caption, + int n, + const wxString *choices, + char **clientData, + long style, + const wxPoint& pos ) +{ + if ( !wxAnyChoiceDialog::Create(parent, message, caption, + n, choices, + style, pos) ) + return false; + + m_selection = n > 0 ? 0 : -1; + + if (clientData) + { + for (int i = 0; i < n; i++) + m_listbox->SetClientData(i, clientData[i]); + } + + return true; +} + +bool wxSingleChoiceDialog::Create( wxWindow *parent, + const wxString& message, + const wxString& caption, + const wxArrayString& choices, + char **clientData, + long style, + const wxPoint& pos ) +{ + wxCArrayString chs(choices); + return Create( parent, message, caption, chs.GetCount(), chs.GetStrings(), + clientData, style, pos ); +} + +// Set the selection +void wxSingleChoiceDialog::SetSelection(int sel) +{ + m_listbox->SetSelection(sel); + m_selection = sel; +} + +void wxSingleChoiceDialog::OnOK(wxCommandEvent& WXUNUSED(event)) +{ + DoChoice(); +} + +#ifndef __SMARTPHONE__ +void wxSingleChoiceDialog::OnListBoxDClick(wxCommandEvent& WXUNUSED(event)) +{ + DoChoice(); +} +#endif + +#ifdef __WXWINCE__ +void wxSingleChoiceDialog::OnJoystickButtonDown(wxJoystickEvent& WXUNUSED(event)) +{ + DoChoice(); +} +#endif + +void wxSingleChoiceDialog::DoChoice() +{ + m_selection = m_listbox->GetSelection(); + m_stringSelection = m_listbox->GetStringSelection(); + + if ( m_listbox->HasClientUntypedData() ) + SetClientData(m_listbox->GetClientData(m_selection)); + + EndModal(wxID_OK); +} + +// ---------------------------------------------------------------------------- +// wxMultiChoiceDialog +// ---------------------------------------------------------------------------- + +IMPLEMENT_DYNAMIC_CLASS(wxMultiChoiceDialog, wxDialog) + +bool wxMultiChoiceDialog::Create( wxWindow *parent, + const wxString& message, + const wxString& caption, + int n, + const wxString *choices, + long style, + const wxPoint& pos ) +{ + long styleLbox; +#if wxUSE_CHECKLISTBOX + styleLbox = wxLB_ALWAYS_SB; +#else + styleLbox = wxLB_ALWAYS_SB | wxLB_EXTENDED; +#endif + + if ( !wxAnyChoiceDialog::Create(parent, message, caption, + n, choices, + style, pos, + styleLbox) ) + return false; + + return true; +} + +bool wxMultiChoiceDialog::Create( wxWindow *parent, + const wxString& message, + const wxString& caption, + const wxArrayString& choices, + long style, + const wxPoint& pos ) +{ + wxCArrayString chs(choices); + return Create( parent, message, caption, chs.GetCount(), + chs.GetStrings(), style, pos ); +} + +void wxMultiChoiceDialog::SetSelections(const wxArrayInt& selections) +{ +#if wxUSE_CHECKLISTBOX + wxCheckListBox* checkListBox = wxDynamicCast(m_listbox, wxCheckListBox); + if (checkListBox) + { + // first clear all currently selected items + size_t n, + count = checkListBox->GetCount(); + for ( n = 0; n < count; ++n ) + { + if (checkListBox->IsChecked(n)) + checkListBox->Check(n, false); + } + + // now select the ones which should be selected + count = selections.GetCount(); + for ( n = 0; n < count; n++ ) + { + checkListBox->Check(selections[n]); + } + + return; + } +#endif + + // first clear all currently selected items + size_t n, + count = m_listbox->GetCount(); + for ( n = 0; n < count; ++n ) + { + m_listbox->Deselect(n); + } + + // now select the ones which should be selected + count = selections.GetCount(); + for ( n = 0; n < count; n++ ) + { + m_listbox->Select(selections[n]); + } +} + +bool wxMultiChoiceDialog::TransferDataFromWindow() +{ + m_selections.Empty(); + +#if wxUSE_CHECKLISTBOX + wxCheckListBox* checkListBox = wxDynamicCast(m_listbox, wxCheckListBox); + if (checkListBox) + { + size_t count = checkListBox->GetCount(); + for ( size_t n = 0; n < count; n++ ) + { + if ( checkListBox->IsChecked(n) ) + m_selections.Add(n); + } + return true; + } +#endif + + size_t count = m_listbox->GetCount(); + for ( size_t n = 0; n < count; n++ ) + { + if ( m_listbox->IsSelected(n) ) + m_selections.Add(n); + } + + return true; +} + +#if wxUSE_CHECKLISTBOX + +wxListBoxBase *wxMultiChoiceDialog::CreateList(int n, const wxString *choices, long styleLbox) +{ + wxSize size = wxDefaultSize; + if (wxSystemSettings::GetScreenType() > wxSYS_SCREEN_PDA) + size = wxSize(300, 200); + + return new wxCheckListBox( this, wxID_LISTBOX, + wxDefaultPosition, size, + n, choices, + styleLbox ); +} + +#endif // wxUSE_CHECKLISTBOX + +#endif // wxUSE_CHOICEDLG diff --git a/Externals/wxWidgets/src/generic/clrpickerg.cpp b/Externals/wxWidgets/src/generic/clrpickerg.cpp index 5d4eba0a9d..0a0a328c4a 100644 --- a/Externals/wxWidgets/src/generic/clrpickerg.cpp +++ b/Externals/wxWidgets/src/generic/clrpickerg.cpp @@ -1,132 +1,132 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: src/generic/clrpickerg.cpp -// Purpose: wxGenericColourButton class implementation -// Author: Francesco Montorsi (readapted code written by Vadim Zeitlin) -// Modified by: -// Created: 15/04/2006 -// RCS-ID: $Id: clrpickerg.cpp 52835 2008-03-26 15:49:08Z JS $ -// Copyright: (c) Vadim Zeitlin, Francesco Montorsi -// Licence: wxWindows licence -/////////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_COLOURPICKERCTRL - -#include "wx/clrpicker.h" - -#include "wx/colordlg.h" - - -// ============================================================================ -// implementation -// ============================================================================ - -wxColourData wxGenericColourButton::ms_data; -IMPLEMENT_DYNAMIC_CLASS(wxGenericColourButton, wxButton) - -// ---------------------------------------------------------------------------- -// wxGenericColourButton -// ---------------------------------------------------------------------------- - -bool wxGenericColourButton::Create( wxWindow *parent, wxWindowID id, - const wxColour &col, const wxPoint &pos, - const wxSize &size, long style, - const wxValidator& validator, const wxString &name) -{ - // create this button - if (!wxButton::Create( parent, id, wxEmptyString, pos, - size, style, validator, name )) - { - wxFAIL_MSG( wxT("wxGenericColourButton creation failed") ); - return false; - } - - // and handle user clicks on it - Connect(GetId(), wxEVT_COMMAND_BUTTON_CLICKED, - wxCommandEventHandler(wxGenericColourButton::OnButtonClick), - NULL, this); - - m_colour = col; - UpdateColour(); - InitColourData(); - - return true; -} - -void wxGenericColourButton::InitColourData() -{ - ms_data.SetChooseFull(true); - unsigned char grey = 0; - for (int i = 0; i < 16; i++, grey += 16) - { - // fill with grey tones the custom colors palette - wxColour colour(grey, grey, grey); - ms_data.SetCustomColour(i, colour); - } -} - -void wxGenericColourButton::OnButtonClick(wxCommandEvent& WXUNUSED(ev)) -{ - // update the wxColouData to be shown in the the dialog - ms_data.SetColour(m_colour); - - // create the colour dialog and display it - wxColourDialog dlg(this, &ms_data); - if (dlg.ShowModal() == wxID_OK) - { - ms_data = dlg.GetColourData(); - SetColour(ms_data.GetColour()); - - // fire an event - wxColourPickerEvent event(this, GetId(), m_colour); - GetEventHandler()->ProcessEvent(event); - } -} - -void wxGenericColourButton::UpdateColour() -{ - if ( !m_colour.Ok() ) - { - if ( HasFlag(wxCLRP_SHOW_LABEL) ) - SetLabel(wxEmptyString); - return; - } - - // some combinations of the fg/bg colours may be unreadable, so we invert - // the colour to make sure fg colour is different enough from m_colour - wxColour colFg(~m_colour.Red(), ~m_colour.Green(), ~m_colour.Blue()); - - SetForegroundColour(colFg); - SetBackgroundColour(m_colour); - - if ( HasFlag(wxCLRP_SHOW_LABEL) ) - SetLabel(m_colour.GetAsString(wxC2S_HTML_SYNTAX)); -} - -wxSize wxGenericColourButton::DoGetBestSize() const -{ - wxSize sz(wxButton::DoGetBestSize()); - if ( HasFlag(wxCLRP_SHOW_LABEL) ) - return sz; - - // if we have no label, then make this button a square - // (like e.g. native GTK version of this control) - sz.SetWidth(sz.GetHeight()); - return sz; -} - -#endif // wxUSE_COLOURPICKERCTRL +/////////////////////////////////////////////////////////////////////////////// +// Name: src/generic/clrpickerg.cpp +// Purpose: wxGenericColourButton class implementation +// Author: Francesco Montorsi (readapted code written by Vadim Zeitlin) +// Modified by: +// Created: 15/04/2006 +// RCS-ID: $Id: clrpickerg.cpp 52835 2008-03-26 15:49:08Z JS $ +// Copyright: (c) Vadim Zeitlin, Francesco Montorsi +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_COLOURPICKERCTRL + +#include "wx/clrpicker.h" + +#include "wx/colordlg.h" + + +// ============================================================================ +// implementation +// ============================================================================ + +wxColourData wxGenericColourButton::ms_data; +IMPLEMENT_DYNAMIC_CLASS(wxGenericColourButton, wxButton) + +// ---------------------------------------------------------------------------- +// wxGenericColourButton +// ---------------------------------------------------------------------------- + +bool wxGenericColourButton::Create( wxWindow *parent, wxWindowID id, + const wxColour &col, const wxPoint &pos, + const wxSize &size, long style, + const wxValidator& validator, const wxString &name) +{ + // create this button + if (!wxButton::Create( parent, id, wxEmptyString, pos, + size, style, validator, name )) + { + wxFAIL_MSG( wxT("wxGenericColourButton creation failed") ); + return false; + } + + // and handle user clicks on it + Connect(GetId(), wxEVT_COMMAND_BUTTON_CLICKED, + wxCommandEventHandler(wxGenericColourButton::OnButtonClick), + NULL, this); + + m_colour = col; + UpdateColour(); + InitColourData(); + + return true; +} + +void wxGenericColourButton::InitColourData() +{ + ms_data.SetChooseFull(true); + unsigned char grey = 0; + for (int i = 0; i < 16; i++, grey += 16) + { + // fill with grey tones the custom colors palette + wxColour colour(grey, grey, grey); + ms_data.SetCustomColour(i, colour); + } +} + +void wxGenericColourButton::OnButtonClick(wxCommandEvent& WXUNUSED(ev)) +{ + // update the wxColouData to be shown in the the dialog + ms_data.SetColour(m_colour); + + // create the colour dialog and display it + wxColourDialog dlg(this, &ms_data); + if (dlg.ShowModal() == wxID_OK) + { + ms_data = dlg.GetColourData(); + SetColour(ms_data.GetColour()); + + // fire an event + wxColourPickerEvent event(this, GetId(), m_colour); + GetEventHandler()->ProcessEvent(event); + } +} + +void wxGenericColourButton::UpdateColour() +{ + if ( !m_colour.Ok() ) + { + if ( HasFlag(wxCLRP_SHOW_LABEL) ) + SetLabel(wxEmptyString); + return; + } + + // some combinations of the fg/bg colours may be unreadable, so we invert + // the colour to make sure fg colour is different enough from m_colour + wxColour colFg(~m_colour.Red(), ~m_colour.Green(), ~m_colour.Blue()); + + SetForegroundColour(colFg); + SetBackgroundColour(m_colour); + + if ( HasFlag(wxCLRP_SHOW_LABEL) ) + SetLabel(m_colour.GetAsString(wxC2S_HTML_SYNTAX)); +} + +wxSize wxGenericColourButton::DoGetBestSize() const +{ + wxSize sz(wxButton::DoGetBestSize()); + if ( HasFlag(wxCLRP_SHOW_LABEL) ) + return sz; + + // if we have no label, then make this button a square + // (like e.g. native GTK version of this control) + sz.SetWidth(sz.GetHeight()); + return sz; +} + +#endif // wxUSE_COLOURPICKERCTRL diff --git a/Externals/wxWidgets/src/generic/collpaneg.cpp b/Externals/wxWidgets/src/generic/collpaneg.cpp index 7f8848f4b7..7dee8f18f0 100644 --- a/Externals/wxWidgets/src/generic/collpaneg.cpp +++ b/Externals/wxWidgets/src/generic/collpaneg.cpp @@ -1,307 +1,307 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/generic/collpaneg.cpp -// Purpose: wxGenericCollapsiblePane -// Author: Francesco Montorsi -// Modified By: -// Created: 8/10/2006 -// Id: $Id: collpaneg.cpp 43371 2006-11-12 21:38:49Z VZ $ -// Copyright: (c) Francesco Montorsi -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" -#include "wx/defs.h" - -#if wxUSE_COLLPANE && wxUSE_BUTTON && wxUSE_STATLINE - -#include "wx/collpane.h" - -#ifndef WX_PRECOMP - #include "wx/toplevel.h" - #include "wx/button.h" - #include "wx/sizer.h" - #include "wx/panel.h" -#endif // !WX_PRECOMP - -#include "wx/statline.h" - -// ---------------------------------------------------------------------------- -// constants -// ---------------------------------------------------------------------------- - -// ============================================================================ -// implementation -// ============================================================================ - -const wxChar wxCollapsiblePaneNameStr[] = wxT("collapsiblePane"); - -//----------------------------------------------------------------------------- -// wxGenericCollapsiblePane -//----------------------------------------------------------------------------- - -DEFINE_EVENT_TYPE(wxEVT_COMMAND_COLLPANE_CHANGED) -IMPLEMENT_DYNAMIC_CLASS(wxGenericCollapsiblePane, wxControl) -IMPLEMENT_DYNAMIC_CLASS(wxCollapsiblePaneEvent, wxCommandEvent) - -BEGIN_EVENT_TABLE(wxGenericCollapsiblePane, wxControl) - EVT_BUTTON(wxID_ANY, wxGenericCollapsiblePane::OnButton) - EVT_SIZE(wxGenericCollapsiblePane::OnSize) -END_EVENT_TABLE() - - -bool wxGenericCollapsiblePane::Create(wxWindow *parent, - wxWindowID id, - const wxString& label, - const wxPoint& pos, - const wxSize& size, - long style, - const wxValidator& val, - const wxString& name) -{ - if ( !wxControl::Create(parent, id, pos, size, style, val, name) ) - return false; - - m_strLabel = label; - - // create children and lay them out using a wxBoxSizer - // (so that we automatically get RTL features) - m_pButton = new wxButton(this, wxID_ANY, GetBtnLabel(), wxPoint(0, 0), - wxDefaultSize, wxBU_EXACTFIT); - m_pStaticLine = new wxStaticLine(this, wxID_ANY); -#ifdef __WXMAC__ - // on Mac we put the static libe above the button - m_sz = new wxBoxSizer(wxVERTICAL); - m_sz->Add(m_pStaticLine, 0, wxALL|wxGROW, GetBorder()); - m_sz->Add(m_pButton, 0, wxLEFT|wxRIGHT|wxBOTTOM, GetBorder()); -#else - // on other platforms we put the static line and the button horizontally - m_sz = new wxBoxSizer(wxHORIZONTAL); - m_sz->Add(m_pButton, 0, wxLEFT|wxTOP|wxBOTTOM, GetBorder()); - m_sz->Add(m_pStaticLine, 1, wxALIGN_CENTER|wxLEFT|wxRIGHT, GetBorder()); -#endif - - // FIXME: at least under wxCE and wxGTK1 the background is black if we don't do - // this, no idea why... -#if defined(__WXWINCE__) || (defined(__WXGTK__) && !defined(__WXGTK20__)) - SetBackgroundColour(parent->GetBackgroundColour()); -#endif - - // do not set sz as our sizers since we handle the pane window without using sizers - m_pPane = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, - wxTAB_TRAVERSAL|wxNO_BORDER); - - // start as collapsed: - m_pPane->Hide(); - - return true; -} - -wxGenericCollapsiblePane::~wxGenericCollapsiblePane() -{ - if (m_pButton && m_pStaticLine && m_sz) - { - m_pButton->SetContainingSizer(NULL); - m_pStaticLine->SetContainingSizer(NULL); - - // our sizer is not deleted automatically since we didn't use SetSizer()! - wxDELETE(m_sz); - } -} - -wxSize wxGenericCollapsiblePane::DoGetBestSize() const -{ - // NB: do not use GetSize() but rather GetMinSize() - wxSize sz = m_sz->GetMinSize(); - - // when expanded, we need more vertical space - if ( IsExpanded() ) - { - sz.SetWidth(wxMax( sz.GetWidth(), m_pPane->GetBestSize().x )); - sz.SetHeight(sz.y + GetBorder() + m_pPane->GetBestSize().y); - } - - return sz; -} - -wxString wxGenericCollapsiblePane::GetBtnLabel() const -{ - return m_strLabel + (IsCollapsed() ? wxT(" >>") : wxT(" <<")); -} - -void wxGenericCollapsiblePane::OnStateChange(const wxSize& sz) -{ - // minimal size has priority over the best size so set here our min size - SetMinSize(sz); - SetSize(sz); - - if (this->HasFlag(wxCP_NO_TLW_RESIZE)) - { - // the user asked to explicitely handle the resizing itself... - return; - } - - - // - // NB: the following block of code has been accurately designed to - // as much flicker-free as possible; be careful when modifying it! - // - - wxTopLevelWindow * - top = wxDynamicCast(wxGetTopLevelParent(this), wxTopLevelWindow); - if ( top ) - { - // NB: don't Layout() the 'top' window as its size has not been correctly - // updated yet and we don't want to do an initial Layout() with the old - // size immediately followed by a SetClientSize/Fit call for the new - // size; that would provoke flickering! - - if (top->GetSizer()) -#ifdef __WXGTK__ - // FIXME: the SetSizeHints() call would be required also for GTK+ for - // the expanded->collapsed transition. Unfortunately if we - // enable this line, then the GTK+ top window won't always be - // resized by the SetClientSize() call below! As a side effect - // of this dirty fix, the minimal size for the pane window is - // not set in GTK+ and the user can hide it shrinking the "top" - // window... - if (IsCollapsed()) -#endif - top->GetSizer()->SetSizeHints(top); - - - // we shouldn't attempt to resize a maximized window, whatever happens - if ( !top->IsMaximized() ) - { - if ( IsCollapsed() ) - { - // expanded -> collapsed transition - if (top->GetSizer()) - { - // we have just set the size hints... - wxSize sz = top->GetSizer()->CalcMin(); - - // use SetClientSize() and not SetSize() otherwise the size for - // e.g. a wxFrame with a menubar wouldn't be correctly set - top->SetClientSize(sz); - } - else - top->Layout(); - } - else - { - // collapsed -> expanded transition - - // force our parent to "fit", i.e. expand so that it can honour - // our minimal size - top->Fit(); - } - } - } -} - -void wxGenericCollapsiblePane::Collapse(bool collapse) -{ - // optimization - if ( IsCollapsed() == collapse ) - return; - - // update our state - m_pPane->Show(!collapse); - - // update button label - // NB: this must be done after updating our "state" - m_pButton->SetLabel(GetBtnLabel()); - - OnStateChange(GetBestSize()); -} - -void wxGenericCollapsiblePane::SetLabel(const wxString &label) -{ - m_strLabel = label; - m_pButton->SetLabel(GetBtnLabel()); - m_pButton->SetInitialSize(); - - Layout(); -} - -bool wxGenericCollapsiblePane::Layout() -{ - if (!m_pButton || !m_pStaticLine || !m_pPane || !m_sz) - return false; // we need to complete the creation first! - - wxSize oursz(GetSize()); - - // move & resize the button and the static line - m_sz->SetDimension(0, 0, oursz.GetWidth(), m_sz->GetMinSize().GetHeight()); - m_sz->Layout(); - - if ( IsExpanded() ) - { - // move & resize the container window - int yoffset = m_sz->GetSize().GetHeight() + GetBorder(); - m_pPane->SetSize(0, yoffset, - oursz.x, oursz.y - yoffset); - - // this is very important to make the pane window layout show correctly - m_pPane->Layout(); - } - - return true; -} - -int wxGenericCollapsiblePane::GetBorder() const -{ -#if defined( __WXMAC__ ) - return 6; -#elif defined(__WXGTK20__) - return 3; -#elif defined(__WXMSW__) - wxASSERT(m_pButton); - return m_pButton->ConvertDialogToPixels(wxSize(2, 0)).x; -#else - return 5; -#endif -} - - - -//----------------------------------------------------------------------------- -// wxGenericCollapsiblePane - event handlers -//----------------------------------------------------------------------------- - -void wxGenericCollapsiblePane::OnButton(wxCommandEvent& event) -{ - if ( event.GetEventObject() != m_pButton ) - { - event.Skip(); - return; - } - - Collapse(!IsCollapsed()); - - // this change was generated by the user - send the event - wxCollapsiblePaneEvent ev(this, GetId(), IsCollapsed()); - GetEventHandler()->ProcessEvent(ev); -} - -void wxGenericCollapsiblePane::OnSize(wxSizeEvent& WXUNUSED(event)) -{ -#if 0 // for debug only - wxClientDC dc(this); - dc.SetPen(*wxBLACK_PEN); - dc.SetBrush(*wxTRANSPARENT_BRUSH); - dc.DrawRectangle(wxPoint(0,0), GetSize()); - dc.SetPen(*wxRED_PEN); - dc.DrawRectangle(wxPoint(0,0), GetBestSize()); -#endif - - Layout(); -} - -#endif // wxUSE_COLLPANE && wxUSE_BUTTON && wxUSE_STATLINE +///////////////////////////////////////////////////////////////////////////// +// Name: src/generic/collpaneg.cpp +// Purpose: wxGenericCollapsiblePane +// Author: Francesco Montorsi +// Modified By: +// Created: 8/10/2006 +// Id: $Id: collpaneg.cpp 43371 2006-11-12 21:38:49Z VZ $ +// Copyright: (c) Francesco Montorsi +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" +#include "wx/defs.h" + +#if wxUSE_COLLPANE && wxUSE_BUTTON && wxUSE_STATLINE + +#include "wx/collpane.h" + +#ifndef WX_PRECOMP + #include "wx/toplevel.h" + #include "wx/button.h" + #include "wx/sizer.h" + #include "wx/panel.h" +#endif // !WX_PRECOMP + +#include "wx/statline.h" + +// ---------------------------------------------------------------------------- +// constants +// ---------------------------------------------------------------------------- + +// ============================================================================ +// implementation +// ============================================================================ + +const wxChar wxCollapsiblePaneNameStr[] = wxT("collapsiblePane"); + +//----------------------------------------------------------------------------- +// wxGenericCollapsiblePane +//----------------------------------------------------------------------------- + +DEFINE_EVENT_TYPE(wxEVT_COMMAND_COLLPANE_CHANGED) +IMPLEMENT_DYNAMIC_CLASS(wxGenericCollapsiblePane, wxControl) +IMPLEMENT_DYNAMIC_CLASS(wxCollapsiblePaneEvent, wxCommandEvent) + +BEGIN_EVENT_TABLE(wxGenericCollapsiblePane, wxControl) + EVT_BUTTON(wxID_ANY, wxGenericCollapsiblePane::OnButton) + EVT_SIZE(wxGenericCollapsiblePane::OnSize) +END_EVENT_TABLE() + + +bool wxGenericCollapsiblePane::Create(wxWindow *parent, + wxWindowID id, + const wxString& label, + const wxPoint& pos, + const wxSize& size, + long style, + const wxValidator& val, + const wxString& name) +{ + if ( !wxControl::Create(parent, id, pos, size, style, val, name) ) + return false; + + m_strLabel = label; + + // create children and lay them out using a wxBoxSizer + // (so that we automatically get RTL features) + m_pButton = new wxButton(this, wxID_ANY, GetBtnLabel(), wxPoint(0, 0), + wxDefaultSize, wxBU_EXACTFIT); + m_pStaticLine = new wxStaticLine(this, wxID_ANY); +#ifdef __WXMAC__ + // on Mac we put the static libe above the button + m_sz = new wxBoxSizer(wxVERTICAL); + m_sz->Add(m_pStaticLine, 0, wxALL|wxGROW, GetBorder()); + m_sz->Add(m_pButton, 0, wxLEFT|wxRIGHT|wxBOTTOM, GetBorder()); +#else + // on other platforms we put the static line and the button horizontally + m_sz = new wxBoxSizer(wxHORIZONTAL); + m_sz->Add(m_pButton, 0, wxLEFT|wxTOP|wxBOTTOM, GetBorder()); + m_sz->Add(m_pStaticLine, 1, wxALIGN_CENTER|wxLEFT|wxRIGHT, GetBorder()); +#endif + + // FIXME: at least under wxCE and wxGTK1 the background is black if we don't do + // this, no idea why... +#if defined(__WXWINCE__) || (defined(__WXGTK__) && !defined(__WXGTK20__)) + SetBackgroundColour(parent->GetBackgroundColour()); +#endif + + // do not set sz as our sizers since we handle the pane window without using sizers + m_pPane = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, + wxTAB_TRAVERSAL|wxNO_BORDER); + + // start as collapsed: + m_pPane->Hide(); + + return true; +} + +wxGenericCollapsiblePane::~wxGenericCollapsiblePane() +{ + if (m_pButton && m_pStaticLine && m_sz) + { + m_pButton->SetContainingSizer(NULL); + m_pStaticLine->SetContainingSizer(NULL); + + // our sizer is not deleted automatically since we didn't use SetSizer()! + wxDELETE(m_sz); + } +} + +wxSize wxGenericCollapsiblePane::DoGetBestSize() const +{ + // NB: do not use GetSize() but rather GetMinSize() + wxSize sz = m_sz->GetMinSize(); + + // when expanded, we need more vertical space + if ( IsExpanded() ) + { + sz.SetWidth(wxMax( sz.GetWidth(), m_pPane->GetBestSize().x )); + sz.SetHeight(sz.y + GetBorder() + m_pPane->GetBestSize().y); + } + + return sz; +} + +wxString wxGenericCollapsiblePane::GetBtnLabel() const +{ + return m_strLabel + (IsCollapsed() ? wxT(" >>") : wxT(" <<")); +} + +void wxGenericCollapsiblePane::OnStateChange(const wxSize& sz) +{ + // minimal size has priority over the best size so set here our min size + SetMinSize(sz); + SetSize(sz); + + if (this->HasFlag(wxCP_NO_TLW_RESIZE)) + { + // the user asked to explicitely handle the resizing itself... + return; + } + + + // + // NB: the following block of code has been accurately designed to + // as much flicker-free as possible; be careful when modifying it! + // + + wxTopLevelWindow * + top = wxDynamicCast(wxGetTopLevelParent(this), wxTopLevelWindow); + if ( top ) + { + // NB: don't Layout() the 'top' window as its size has not been correctly + // updated yet and we don't want to do an initial Layout() with the old + // size immediately followed by a SetClientSize/Fit call for the new + // size; that would provoke flickering! + + if (top->GetSizer()) +#ifdef __WXGTK__ + // FIXME: the SetSizeHints() call would be required also for GTK+ for + // the expanded->collapsed transition. Unfortunately if we + // enable this line, then the GTK+ top window won't always be + // resized by the SetClientSize() call below! As a side effect + // of this dirty fix, the minimal size for the pane window is + // not set in GTK+ and the user can hide it shrinking the "top" + // window... + if (IsCollapsed()) +#endif + top->GetSizer()->SetSizeHints(top); + + + // we shouldn't attempt to resize a maximized window, whatever happens + if ( !top->IsMaximized() ) + { + if ( IsCollapsed() ) + { + // expanded -> collapsed transition + if (top->GetSizer()) + { + // we have just set the size hints... + wxSize sz = top->GetSizer()->CalcMin(); + + // use SetClientSize() and not SetSize() otherwise the size for + // e.g. a wxFrame with a menubar wouldn't be correctly set + top->SetClientSize(sz); + } + else + top->Layout(); + } + else + { + // collapsed -> expanded transition + + // force our parent to "fit", i.e. expand so that it can honour + // our minimal size + top->Fit(); + } + } + } +} + +void wxGenericCollapsiblePane::Collapse(bool collapse) +{ + // optimization + if ( IsCollapsed() == collapse ) + return; + + // update our state + m_pPane->Show(!collapse); + + // update button label + // NB: this must be done after updating our "state" + m_pButton->SetLabel(GetBtnLabel()); + + OnStateChange(GetBestSize()); +} + +void wxGenericCollapsiblePane::SetLabel(const wxString &label) +{ + m_strLabel = label; + m_pButton->SetLabel(GetBtnLabel()); + m_pButton->SetInitialSize(); + + Layout(); +} + +bool wxGenericCollapsiblePane::Layout() +{ + if (!m_pButton || !m_pStaticLine || !m_pPane || !m_sz) + return false; // we need to complete the creation first! + + wxSize oursz(GetSize()); + + // move & resize the button and the static line + m_sz->SetDimension(0, 0, oursz.GetWidth(), m_sz->GetMinSize().GetHeight()); + m_sz->Layout(); + + if ( IsExpanded() ) + { + // move & resize the container window + int yoffset = m_sz->GetSize().GetHeight() + GetBorder(); + m_pPane->SetSize(0, yoffset, + oursz.x, oursz.y - yoffset); + + // this is very important to make the pane window layout show correctly + m_pPane->Layout(); + } + + return true; +} + +int wxGenericCollapsiblePane::GetBorder() const +{ +#if defined( __WXMAC__ ) + return 6; +#elif defined(__WXGTK20__) + return 3; +#elif defined(__WXMSW__) + wxASSERT(m_pButton); + return m_pButton->ConvertDialogToPixels(wxSize(2, 0)).x; +#else + return 5; +#endif +} + + + +//----------------------------------------------------------------------------- +// wxGenericCollapsiblePane - event handlers +//----------------------------------------------------------------------------- + +void wxGenericCollapsiblePane::OnButton(wxCommandEvent& event) +{ + if ( event.GetEventObject() != m_pButton ) + { + event.Skip(); + return; + } + + Collapse(!IsCollapsed()); + + // this change was generated by the user - send the event + wxCollapsiblePaneEvent ev(this, GetId(), IsCollapsed()); + GetEventHandler()->ProcessEvent(ev); +} + +void wxGenericCollapsiblePane::OnSize(wxSizeEvent& WXUNUSED(event)) +{ +#if 0 // for debug only + wxClientDC dc(this); + dc.SetPen(*wxBLACK_PEN); + dc.SetBrush(*wxTRANSPARENT_BRUSH); + dc.DrawRectangle(wxPoint(0,0), GetSize()); + dc.SetPen(*wxRED_PEN); + dc.DrawRectangle(wxPoint(0,0), GetBestSize()); +#endif + + Layout(); +} + +#endif // wxUSE_COLLPANE && wxUSE_BUTTON && wxUSE_STATLINE diff --git a/Externals/wxWidgets/src/generic/colour.cpp b/Externals/wxWidgets/src/generic/colour.cpp index c90a7a7a7a..85d67ceed7 100644 --- a/Externals/wxWidgets/src/generic/colour.cpp +++ b/Externals/wxWidgets/src/generic/colour.cpp @@ -1,72 +1,72 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/generic/colour.cpp -// Purpose: wxColour class -// Author: Julian Smart -// Modified by: -// Created: 01/02/97 -// RCS-ID: $Id: colour.cpp 41123 2006-09-10 02:00:24Z VZ $ -// Copyright: (c) Julian Smart -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#include "wx/colour.h" - -#ifndef WX_PRECOMP - #include "wx/gdicmn.h" -#endif - -IMPLEMENT_DYNAMIC_CLASS(wxColour, wxObject) - -// Colour - -void wxColour::Init() -{ - m_red = - m_blue = - m_green = 0; - m_alpha = wxALPHA_OPAQUE; - m_isInit = false; -} - -wxColour::wxColour() -{ - Init(); -} - -wxColour::wxColour(const wxColour& col) -{ - *this = col; -} - -wxColour& wxColour::operator=(const wxColour& col) -{ - m_red = col.m_red; - m_green = col.m_green; - m_blue = col.m_blue; - m_alpha = col.m_alpha; - m_isInit = col.m_isInit; - return *this; -} - -wxColour::~wxColour() -{ -} - -void wxColour::InitRGBA(unsigned char r, - unsigned char g, - unsigned char b, - unsigned char a) -{ - m_red = r; - m_green = g; - m_blue = b; - m_alpha = a; - m_isInit = true; -} +///////////////////////////////////////////////////////////////////////////// +// Name: src/generic/colour.cpp +// Purpose: wxColour class +// Author: Julian Smart +// Modified by: +// Created: 01/02/97 +// RCS-ID: $Id: colour.cpp 41123 2006-09-10 02:00:24Z VZ $ +// Copyright: (c) Julian Smart +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#include "wx/colour.h" + +#ifndef WX_PRECOMP + #include "wx/gdicmn.h" +#endif + +IMPLEMENT_DYNAMIC_CLASS(wxColour, wxObject) + +// Colour + +void wxColour::Init() +{ + m_red = + m_blue = + m_green = 0; + m_alpha = wxALPHA_OPAQUE; + m_isInit = false; +} + +wxColour::wxColour() +{ + Init(); +} + +wxColour::wxColour(const wxColour& col) +{ + *this = col; +} + +wxColour& wxColour::operator=(const wxColour& col) +{ + m_red = col.m_red; + m_green = col.m_green; + m_blue = col.m_blue; + m_alpha = col.m_alpha; + m_isInit = col.m_isInit; + return *this; +} + +wxColour::~wxColour() +{ +} + +void wxColour::InitRGBA(unsigned char r, + unsigned char g, + unsigned char b, + unsigned char a) +{ + m_red = r; + m_green = g; + m_blue = b; + m_alpha = a; + m_isInit = true; +} diff --git a/Externals/wxWidgets/src/generic/colrdlgg.cpp b/Externals/wxWidgets/src/generic/colrdlgg.cpp index c05fe38c3d..2474949358 100644 --- a/Externals/wxWidgets/src/generic/colrdlgg.cpp +++ b/Externals/wxWidgets/src/generic/colrdlgg.cpp @@ -1,586 +1,586 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/generic/colrdlgg.cpp -// Purpose: Choice dialogs -// Author: Julian Smart -// Modified by: -// Created: 04/01/98 -// RCS-ID: $Id: colrdlgg.cpp 41838 2006-10-09 21:08:45Z VZ $ -// Copyright: (c) Julian Smart -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_COLOURDLG && (!defined(__WXGTK20__) || defined(__WXUNIVERSAL__)) - -#ifndef WX_PRECOMP - #include "wx/utils.h" - #include "wx/intl.h" - #include "wx/dialog.h" - #include "wx/listbox.h" - #include "wx/button.h" - #include "wx/stattext.h" - #include "wx/layout.h" - #include "wx/dcclient.h" - #include "wx/sizer.h" - #include "wx/slider.h" -#endif - -#if wxUSE_STATLINE - #include "wx/statline.h" -#endif - -#include "wx/generic/colrdlgg.h" - -IMPLEMENT_DYNAMIC_CLASS(wxGenericColourDialog, wxDialog) - -BEGIN_EVENT_TABLE(wxGenericColourDialog, wxDialog) - EVT_BUTTON(wxID_ADD_CUSTOM, wxGenericColourDialog::OnAddCustom) -#if wxUSE_SLIDER - EVT_SLIDER(wxID_RED_SLIDER, wxGenericColourDialog::OnRedSlider) - EVT_SLIDER(wxID_GREEN_SLIDER, wxGenericColourDialog::OnGreenSlider) - EVT_SLIDER(wxID_BLUE_SLIDER, wxGenericColourDialog::OnBlueSlider) -#endif - EVT_PAINT(wxGenericColourDialog::OnPaint) - EVT_MOUSE_EVENTS(wxGenericColourDialog::OnMouseEvent) - EVT_CLOSE(wxGenericColourDialog::OnCloseWindow) -END_EVENT_TABLE() - - -/* - * Generic wxColourDialog - */ - -// don't change the number of elements (48) in this array, the code below is -// hardcoded to use it -static const wxChar *wxColourDialogNames[] = -{ - wxT("ORANGE"), - wxT("GOLDENROD"), - wxT("WHEAT"), - wxT("SPRING GREEN"), - wxT("SKY BLUE"), - wxT("SLATE BLUE"), - wxT("MEDIUM VIOLET RED"), - wxT("PURPLE"), - - wxT("RED"), - wxT("YELLOW"), - wxT("MEDIUM SPRING GREEN"), - wxT("PALE GREEN"), - wxT("CYAN"), - wxT("LIGHT STEEL BLUE"), - wxT("ORCHID"), - wxT("LIGHT MAGENTA"), - - wxT("BROWN"), - wxT("YELLOW"), - wxT("GREEN"), - wxT("CADET BLUE"), - wxT("MEDIUM BLUE"), - wxT("MAGENTA"), - wxT("MAROON"), - wxT("ORANGE RED"), - - wxT("FIREBRICK"), - wxT("CORAL"), - wxT("FOREST GREEN"), - wxT("AQUAMARINE"), - wxT("BLUE"), - wxT("NAVY"), - wxT("THISTLE"), - wxT("MEDIUM VIOLET RED"), - - wxT("INDIAN RED"), - wxT("GOLD"), - wxT("MEDIUM SEA GREEN"), - wxT("MEDIUM BLUE"), - wxT("MIDNIGHT BLUE"), - wxT("GREY"), - wxT("PURPLE"), - wxT("KHAKI"), - - wxT("BLACK"), - wxT("MEDIUM FOREST GREEN"), - wxT("KHAKI"), - wxT("DARK GREY"), - wxT("SEA GREEN"), - wxT("LIGHT GREY"), - wxT("MEDIUM SLATE BLUE"), - wxT("WHITE") -}; - -wxGenericColourDialog::wxGenericColourDialog() -{ - dialogParent = NULL; - whichKind = 1; - colourSelection = -1; -} - -wxGenericColourDialog::wxGenericColourDialog(wxWindow *parent, - wxColourData *data) -{ - whichKind = 1; - colourSelection = -1; - Create(parent, data); -} - -wxGenericColourDialog::~wxGenericColourDialog() -{ -} - -void wxGenericColourDialog::OnCloseWindow(wxCloseEvent& WXUNUSED(event)) -{ - EndModal(wxID_CANCEL); -} - -bool wxGenericColourDialog::Create(wxWindow *parent, wxColourData *data) -{ - if ( !wxDialog::Create(parent, wxID_ANY, _("Choose colour"), - wxPoint(0,0), wxSize(900, 900)) ) - return false; - - dialogParent = parent; - - if (data) - colourData = *data; - - InitializeColours(); - CalculateMeasurements(); - CreateWidgets(); - - return true; -} - -int wxGenericColourDialog::ShowModal() -{ - return wxDialog::ShowModal(); -} - - -// Internal functions -void wxGenericColourDialog::OnMouseEvent(wxMouseEvent& event) -{ - if (event.ButtonDown(1)) - { - int x = (int)event.GetX(); - int y = (int)event.GetY(); - -#ifdef __WXPM__ - // Handle OS/2's reverse coordinate system and account for the dialog title - int nClientHeight; - - GetClientSize(NULL, &nClientHeight); - y = (nClientHeight - y) + 20; -#endif - if ((x >= standardColoursRect.x && x <= (standardColoursRect.x + standardColoursRect.width)) && - (y >= standardColoursRect.y && y <= (standardColoursRect.y + standardColoursRect.height))) - { - int selX = (int)(x - standardColoursRect.x)/(smallRectangleSize.x + gridSpacing); - int selY = (int)(y - standardColoursRect.y)/(smallRectangleSize.y + gridSpacing); - int ptr = (int)(selX + selY*8); - OnBasicColourClick(ptr); - } - else if ((x >= customColoursRect.x && x <= (customColoursRect.x + customColoursRect.width)) && - (y >= customColoursRect.y && y <= (customColoursRect.y + customColoursRect.height))) - { - int selX = (int)(x - customColoursRect.x)/(smallRectangleSize.x + gridSpacing); - int selY = (int)(y - customColoursRect.y)/(smallRectangleSize.y + gridSpacing); - int ptr = (int)(selX + selY*8); - OnCustomColourClick(ptr); - } - else - event.Skip(); - } - else - event.Skip(); -} - -void wxGenericColourDialog::OnPaint(wxPaintEvent& event) -{ -#if !defined(__WXMOTIF__) && !defined(__WXPM__) && !defined(__WXCOCOA__) - wxDialog::OnPaint(event); -#else - wxUnusedVar(event); -#endif - - wxPaintDC dc(this); - - PaintBasicColours(dc); - PaintCustomColours(dc); - PaintCustomColour(dc); - PaintHighlight(dc, true); -} - -void wxGenericColourDialog::CalculateMeasurements() -{ - smallRectangleSize.x = 18; - smallRectangleSize.y = 14; - customRectangleSize.x = 40; - customRectangleSize.y = 40; - - gridSpacing = 6; - sectionSpacing = 15; - - standardColoursRect.x = 10; -#ifdef __WXPM__ - standardColoursRect.y = 15 + 20; /* OS/2 needs to account for dialog titlebar */ -#else - standardColoursRect.y = 15; -#endif - standardColoursRect.width = (8*smallRectangleSize.x) + (7*gridSpacing); - standardColoursRect.height = (6*smallRectangleSize.y) + (5*gridSpacing); - - customColoursRect.x = standardColoursRect.x; - customColoursRect.y = standardColoursRect.y + standardColoursRect.height + 20; - customColoursRect.width = (8*smallRectangleSize.x) + (7*gridSpacing); - customColoursRect.height = (2*smallRectangleSize.y) + (1*gridSpacing); - - singleCustomColourRect.x = customColoursRect.width + customColoursRect.x + sectionSpacing; - singleCustomColourRect.y = 80; - singleCustomColourRect.width = customRectangleSize.x; - singleCustomColourRect.height = customRectangleSize.y; - - okButtonX = 10; - customButtonX = singleCustomColourRect.x ; - buttonY = customColoursRect.y + customColoursRect.height + 10; -} - -void wxGenericColourDialog::CreateWidgets() -{ - wxBeginBusyCursor(); - - wxBoxSizer *topSizer = new wxBoxSizer( wxVERTICAL ); - - const int sliderHeight = 160; - - // first sliders -#if wxUSE_SLIDER - const int sliderX = singleCustomColourRect.x + singleCustomColourRect.width + sectionSpacing; - - redSlider = new wxSlider(this, wxID_RED_SLIDER, colourData.m_dataColour.Red(), 0, 255, - wxDefaultPosition, wxSize(wxDefaultCoord, sliderHeight), wxSL_VERTICAL|wxSL_LABELS|wxSL_INVERSE); - greenSlider = new wxSlider(this, wxID_GREEN_SLIDER, colourData.m_dataColour.Green(), 0, 255, - wxDefaultPosition, wxSize(wxDefaultCoord, sliderHeight), wxSL_VERTICAL|wxSL_LABELS|wxSL_INVERSE); - blueSlider = new wxSlider(this, wxID_BLUE_SLIDER, colourData.m_dataColour.Blue(), 0, 255, - wxDefaultPosition, wxSize(wxDefaultCoord, sliderHeight), wxSL_VERTICAL|wxSL_LABELS|wxSL_INVERSE); - - wxBoxSizer *sliderSizer = new wxBoxSizer( wxHORIZONTAL ); - - sliderSizer->Add(sliderX, sliderHeight ); - - wxSizerFlags flagsRight; - flagsRight.Align(wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL).DoubleBorder(); - - sliderSizer->Add(redSlider, flagsRight); - sliderSizer->Add(greenSlider,flagsRight); - sliderSizer->Add(blueSlider,flagsRight); - - topSizer->Add(sliderSizer, wxSizerFlags().Centre().DoubleBorder()); -#else - topSizer->Add(1, sliderHeight, wxSizerFlags(1).Centre().TripleBorder()); -#endif // wxUSE_SLIDER - - // then the custom button - topSizer->Add(new wxButton(this, wxID_ADD_CUSTOM, - _("Add to custom colours") ), - wxSizerFlags().DoubleHorzBorder()); - - // then the standard buttons - wxSizer *buttonsizer = CreateSeparatedButtonSizer(wxOK | wxCANCEL); - if ( buttonsizer ) - { - topSizer->Add(buttonsizer, wxSizerFlags().Expand().DoubleBorder()); - } - - SetAutoLayout( true ); - SetSizer( topSizer ); - - topSizer->SetSizeHints( this ); - topSizer->Fit( this ); - - Centre( wxBOTH ); - - wxEndBusyCursor(); -} - -void wxGenericColourDialog::InitializeColours(void) -{ - size_t i; - - for (i = 0; i < WXSIZEOF(wxColourDialogNames); i++) - { - wxColour col = wxTheColourDatabase->Find(wxColourDialogNames[i]); - if (col.Ok()) - standardColours[i].Set(col.Red(), col.Green(), col.Blue()); - else - standardColours[i].Set(0, 0, 0); - } - - for (i = 0; i < WXSIZEOF(customColours); i++) - { - wxColour c = colourData.GetCustomColour(i); - if (c.Ok()) - customColours[i] = colourData.GetCustomColour(i); - else - customColours[i] = wxColour(255, 255, 255); - } - - wxColour curr = colourData.GetColour(); - if ( curr.Ok() ) - { - bool initColourFound = false; - - for (i = 0; i < WXSIZEOF(wxColourDialogNames); i++) - { - if ( standardColours[i] == curr && !initColourFound ) - { - whichKind = 1; - colourSelection = i; - initColourFound = true; - break; - } - } - if ( !initColourFound ) - { - for ( i = 0; i < WXSIZEOF(customColours); i++ ) - { - if ( customColours[i] == curr ) - { - whichKind = 2; - colourSelection = i; - break; - } - } - } - colourData.m_dataColour.Set( curr.Red(), curr.Green(), curr.Blue() ); - } - else - { - whichKind = 1; - colourSelection = 0; - colourData.m_dataColour.Set( 0, 0, 0 ); - } -} - -void wxGenericColourDialog::PaintBasicColours(wxDC& dc) -{ - int i; - for (i = 0; i < 6; i++) - { - int j; - for (j = 0; j < 8; j++) - { - int ptr = i*8 + j; - - int x = (j*(smallRectangleSize.x+gridSpacing) + standardColoursRect.x); - int y = (i*(smallRectangleSize.y+gridSpacing) + standardColoursRect.y); - - dc.SetPen(*wxBLACK_PEN); - wxBrush brush(standardColours[ptr], wxSOLID); - dc.SetBrush(brush); - - dc.DrawRectangle( x, y, smallRectangleSize.x, smallRectangleSize.y); - } - } -} - -void wxGenericColourDialog::PaintCustomColours(wxDC& dc) -{ - int i; - for (i = 0; i < 2; i++) - { - int j; - for (j = 0; j < 8; j++) - { - int ptr = i*8 + j; - - int x = (j*(smallRectangleSize.x+gridSpacing)) + customColoursRect.x; - int y = (i*(smallRectangleSize.y+gridSpacing)) + customColoursRect.y; - - dc.SetPen(*wxBLACK_PEN); - - wxBrush brush(customColours[ptr], wxSOLID); - dc.SetBrush(brush); - - dc.DrawRectangle( x, y, smallRectangleSize.x, smallRectangleSize.y); - } - } -} - -void wxGenericColourDialog::PaintHighlight(wxDC& dc, bool draw) -{ - if ( colourSelection < 0 ) - return; - - // Number of pixels bigger than the standard rectangle size - // for drawing a highlight - int deltaX = 2; - int deltaY = 2; - - if (whichKind == 1) - { - // Standard colours - int y = (int)(colourSelection / 8); - int x = (int)(colourSelection - (y*8)); - - x = (x*(smallRectangleSize.x + gridSpacing) + standardColoursRect.x) - deltaX; - y = (y*(smallRectangleSize.y + gridSpacing) + standardColoursRect.y) - deltaY; - - if (draw) - dc.SetPen(*wxBLACK_PEN); - else - dc.SetPen(*wxLIGHT_GREY_PEN); - - dc.SetBrush(*wxTRANSPARENT_BRUSH); - dc.DrawRectangle( x, y, (smallRectangleSize.x + (2*deltaX)), (smallRectangleSize.y + (2*deltaY))); - } - else - { - // User-defined colours - int y = (int)(colourSelection / 8); - int x = (int)(colourSelection - (y*8)); - - x = (x*(smallRectangleSize.x + gridSpacing) + customColoursRect.x) - deltaX; - y = (y*(smallRectangleSize.y + gridSpacing) + customColoursRect.y) - deltaY; - - if (draw) - dc.SetPen(*wxBLACK_PEN); - else - dc.SetPen(*wxLIGHT_GREY_PEN); - - dc.SetBrush(*wxTRANSPARENT_BRUSH); - dc.DrawRectangle( x, y, (smallRectangleSize.x + (2*deltaX)), (smallRectangleSize.y + (2*deltaY))); - } -} - -void wxGenericColourDialog::PaintCustomColour(wxDC& dc) -{ - dc.SetPen(*wxBLACK_PEN); - - wxBrush *brush = new wxBrush(colourData.m_dataColour, wxSOLID); - dc.SetBrush(*brush); - - dc.DrawRectangle( singleCustomColourRect.x, singleCustomColourRect.y, - customRectangleSize.x, customRectangleSize.y); - - dc.SetBrush(wxNullBrush); - delete brush; -} - -void wxGenericColourDialog::OnBasicColourClick(int which) -{ - wxClientDC dc(this); - - PaintHighlight(dc, false); - whichKind = 1; - colourSelection = which; - -#if wxUSE_SLIDER - redSlider->SetValue( standardColours[colourSelection].Red() ); - greenSlider->SetValue( standardColours[colourSelection].Green() ); - blueSlider->SetValue( standardColours[colourSelection].Blue() ); -#endif // wxUSE_SLIDER - - colourData.m_dataColour.Set(standardColours[colourSelection].Red(), - standardColours[colourSelection].Green(), - standardColours[colourSelection].Blue()); - - PaintCustomColour(dc); - PaintHighlight(dc, true); -} - -void wxGenericColourDialog::OnCustomColourClick(int which) -{ - wxClientDC dc(this); - PaintHighlight(dc, false); - whichKind = 2; - colourSelection = which; - -#if wxUSE_SLIDER - redSlider->SetValue( customColours[colourSelection].Red() ); - greenSlider->SetValue( customColours[colourSelection].Green() ); - blueSlider->SetValue( customColours[colourSelection].Blue() ); -#endif // wxUSE_SLIDER - - colourData.m_dataColour.Set(customColours[colourSelection].Red(), - customColours[colourSelection].Green(), - customColours[colourSelection].Blue()); - - PaintCustomColour(dc); - PaintHighlight(dc, true); -} - -/* -void wxGenericColourDialog::OnOk(void) -{ - Show(false); -} - -void wxGenericColourDialog::OnCancel(void) -{ - colourDialogCancelled = true; - Show(false); -} -*/ - -void wxGenericColourDialog::OnAddCustom(wxCommandEvent& WXUNUSED(event)) -{ - wxClientDC dc(this); - if (whichKind != 2) - { - PaintHighlight(dc, false); - whichKind = 2; - colourSelection = 0; - PaintHighlight(dc, true); - } - - customColours[colourSelection].Set(colourData.m_dataColour.Red(), - colourData.m_dataColour.Green(), - colourData.m_dataColour.Blue()); - - colourData.SetCustomColour(colourSelection, customColours[colourSelection]); - - PaintCustomColours(dc); -} - -#if wxUSE_SLIDER - -void wxGenericColourDialog::OnRedSlider(wxCommandEvent& WXUNUSED(event)) -{ - if (!redSlider) - return; - - wxClientDC dc(this); - colourData.m_dataColour.Set((unsigned char)redSlider->GetValue(), colourData.m_dataColour.Green(), colourData.m_dataColour.Blue()); - PaintCustomColour(dc); -} - -void wxGenericColourDialog::OnGreenSlider(wxCommandEvent& WXUNUSED(event)) -{ - if (!greenSlider) - return; - - wxClientDC dc(this); - colourData.m_dataColour.Set(colourData.m_dataColour.Red(), (unsigned char)greenSlider->GetValue(), colourData.m_dataColour.Blue()); - PaintCustomColour(dc); -} - -void wxGenericColourDialog::OnBlueSlider(wxCommandEvent& WXUNUSED(event)) -{ - if (!blueSlider) - return; - - wxClientDC dc(this); - colourData.m_dataColour.Set(colourData.m_dataColour.Red(), colourData.m_dataColour.Green(), (unsigned char)blueSlider->GetValue()); - PaintCustomColour(dc); -} - -#endif // wxUSE_SLIDER - -#endif // wxUSE_COLOURDLG && !defined(__WXGTK20__) +///////////////////////////////////////////////////////////////////////////// +// Name: src/generic/colrdlgg.cpp +// Purpose: Choice dialogs +// Author: Julian Smart +// Modified by: +// Created: 04/01/98 +// RCS-ID: $Id: colrdlgg.cpp 41838 2006-10-09 21:08:45Z VZ $ +// Copyright: (c) Julian Smart +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_COLOURDLG && (!defined(__WXGTK20__) || defined(__WXUNIVERSAL__)) + +#ifndef WX_PRECOMP + #include "wx/utils.h" + #include "wx/intl.h" + #include "wx/dialog.h" + #include "wx/listbox.h" + #include "wx/button.h" + #include "wx/stattext.h" + #include "wx/layout.h" + #include "wx/dcclient.h" + #include "wx/sizer.h" + #include "wx/slider.h" +#endif + +#if wxUSE_STATLINE + #include "wx/statline.h" +#endif + +#include "wx/generic/colrdlgg.h" + +IMPLEMENT_DYNAMIC_CLASS(wxGenericColourDialog, wxDialog) + +BEGIN_EVENT_TABLE(wxGenericColourDialog, wxDialog) + EVT_BUTTON(wxID_ADD_CUSTOM, wxGenericColourDialog::OnAddCustom) +#if wxUSE_SLIDER + EVT_SLIDER(wxID_RED_SLIDER, wxGenericColourDialog::OnRedSlider) + EVT_SLIDER(wxID_GREEN_SLIDER, wxGenericColourDialog::OnGreenSlider) + EVT_SLIDER(wxID_BLUE_SLIDER, wxGenericColourDialog::OnBlueSlider) +#endif + EVT_PAINT(wxGenericColourDialog::OnPaint) + EVT_MOUSE_EVENTS(wxGenericColourDialog::OnMouseEvent) + EVT_CLOSE(wxGenericColourDialog::OnCloseWindow) +END_EVENT_TABLE() + + +/* + * Generic wxColourDialog + */ + +// don't change the number of elements (48) in this array, the code below is +// hardcoded to use it +static const wxChar *wxColourDialogNames[] = +{ + wxT("ORANGE"), + wxT("GOLDENROD"), + wxT("WHEAT"), + wxT("SPRING GREEN"), + wxT("SKY BLUE"), + wxT("SLATE BLUE"), + wxT("MEDIUM VIOLET RED"), + wxT("PURPLE"), + + wxT("RED"), + wxT("YELLOW"), + wxT("MEDIUM SPRING GREEN"), + wxT("PALE GREEN"), + wxT("CYAN"), + wxT("LIGHT STEEL BLUE"), + wxT("ORCHID"), + wxT("LIGHT MAGENTA"), + + wxT("BROWN"), + wxT("YELLOW"), + wxT("GREEN"), + wxT("CADET BLUE"), + wxT("MEDIUM BLUE"), + wxT("MAGENTA"), + wxT("MAROON"), + wxT("ORANGE RED"), + + wxT("FIREBRICK"), + wxT("CORAL"), + wxT("FOREST GREEN"), + wxT("AQUAMARINE"), + wxT("BLUE"), + wxT("NAVY"), + wxT("THISTLE"), + wxT("MEDIUM VIOLET RED"), + + wxT("INDIAN RED"), + wxT("GOLD"), + wxT("MEDIUM SEA GREEN"), + wxT("MEDIUM BLUE"), + wxT("MIDNIGHT BLUE"), + wxT("GREY"), + wxT("PURPLE"), + wxT("KHAKI"), + + wxT("BLACK"), + wxT("MEDIUM FOREST GREEN"), + wxT("KHAKI"), + wxT("DARK GREY"), + wxT("SEA GREEN"), + wxT("LIGHT GREY"), + wxT("MEDIUM SLATE BLUE"), + wxT("WHITE") +}; + +wxGenericColourDialog::wxGenericColourDialog() +{ + dialogParent = NULL; + whichKind = 1; + colourSelection = -1; +} + +wxGenericColourDialog::wxGenericColourDialog(wxWindow *parent, + wxColourData *data) +{ + whichKind = 1; + colourSelection = -1; + Create(parent, data); +} + +wxGenericColourDialog::~wxGenericColourDialog() +{ +} + +void wxGenericColourDialog::OnCloseWindow(wxCloseEvent& WXUNUSED(event)) +{ + EndModal(wxID_CANCEL); +} + +bool wxGenericColourDialog::Create(wxWindow *parent, wxColourData *data) +{ + if ( !wxDialog::Create(parent, wxID_ANY, _("Choose colour"), + wxPoint(0,0), wxSize(900, 900)) ) + return false; + + dialogParent = parent; + + if (data) + colourData = *data; + + InitializeColours(); + CalculateMeasurements(); + CreateWidgets(); + + return true; +} + +int wxGenericColourDialog::ShowModal() +{ + return wxDialog::ShowModal(); +} + + +// Internal functions +void wxGenericColourDialog::OnMouseEvent(wxMouseEvent& event) +{ + if (event.ButtonDown(1)) + { + int x = (int)event.GetX(); + int y = (int)event.GetY(); + +#ifdef __WXPM__ + // Handle OS/2's reverse coordinate system and account for the dialog title + int nClientHeight; + + GetClientSize(NULL, &nClientHeight); + y = (nClientHeight - y) + 20; +#endif + if ((x >= standardColoursRect.x && x <= (standardColoursRect.x + standardColoursRect.width)) && + (y >= standardColoursRect.y && y <= (standardColoursRect.y + standardColoursRect.height))) + { + int selX = (int)(x - standardColoursRect.x)/(smallRectangleSize.x + gridSpacing); + int selY = (int)(y - standardColoursRect.y)/(smallRectangleSize.y + gridSpacing); + int ptr = (int)(selX + selY*8); + OnBasicColourClick(ptr); + } + else if ((x >= customColoursRect.x && x <= (customColoursRect.x + customColoursRect.width)) && + (y >= customColoursRect.y && y <= (customColoursRect.y + customColoursRect.height))) + { + int selX = (int)(x - customColoursRect.x)/(smallRectangleSize.x + gridSpacing); + int selY = (int)(y - customColoursRect.y)/(smallRectangleSize.y + gridSpacing); + int ptr = (int)(selX + selY*8); + OnCustomColourClick(ptr); + } + else + event.Skip(); + } + else + event.Skip(); +} + +void wxGenericColourDialog::OnPaint(wxPaintEvent& event) +{ +#if !defined(__WXMOTIF__) && !defined(__WXPM__) && !defined(__WXCOCOA__) + wxDialog::OnPaint(event); +#else + wxUnusedVar(event); +#endif + + wxPaintDC dc(this); + + PaintBasicColours(dc); + PaintCustomColours(dc); + PaintCustomColour(dc); + PaintHighlight(dc, true); +} + +void wxGenericColourDialog::CalculateMeasurements() +{ + smallRectangleSize.x = 18; + smallRectangleSize.y = 14; + customRectangleSize.x = 40; + customRectangleSize.y = 40; + + gridSpacing = 6; + sectionSpacing = 15; + + standardColoursRect.x = 10; +#ifdef __WXPM__ + standardColoursRect.y = 15 + 20; /* OS/2 needs to account for dialog titlebar */ +#else + standardColoursRect.y = 15; +#endif + standardColoursRect.width = (8*smallRectangleSize.x) + (7*gridSpacing); + standardColoursRect.height = (6*smallRectangleSize.y) + (5*gridSpacing); + + customColoursRect.x = standardColoursRect.x; + customColoursRect.y = standardColoursRect.y + standardColoursRect.height + 20; + customColoursRect.width = (8*smallRectangleSize.x) + (7*gridSpacing); + customColoursRect.height = (2*smallRectangleSize.y) + (1*gridSpacing); + + singleCustomColourRect.x = customColoursRect.width + customColoursRect.x + sectionSpacing; + singleCustomColourRect.y = 80; + singleCustomColourRect.width = customRectangleSize.x; + singleCustomColourRect.height = customRectangleSize.y; + + okButtonX = 10; + customButtonX = singleCustomColourRect.x ; + buttonY = customColoursRect.y + customColoursRect.height + 10; +} + +void wxGenericColourDialog::CreateWidgets() +{ + wxBeginBusyCursor(); + + wxBoxSizer *topSizer = new wxBoxSizer( wxVERTICAL ); + + const int sliderHeight = 160; + + // first sliders +#if wxUSE_SLIDER + const int sliderX = singleCustomColourRect.x + singleCustomColourRect.width + sectionSpacing; + + redSlider = new wxSlider(this, wxID_RED_SLIDER, colourData.m_dataColour.Red(), 0, 255, + wxDefaultPosition, wxSize(wxDefaultCoord, sliderHeight), wxSL_VERTICAL|wxSL_LABELS|wxSL_INVERSE); + greenSlider = new wxSlider(this, wxID_GREEN_SLIDER, colourData.m_dataColour.Green(), 0, 255, + wxDefaultPosition, wxSize(wxDefaultCoord, sliderHeight), wxSL_VERTICAL|wxSL_LABELS|wxSL_INVERSE); + blueSlider = new wxSlider(this, wxID_BLUE_SLIDER, colourData.m_dataColour.Blue(), 0, 255, + wxDefaultPosition, wxSize(wxDefaultCoord, sliderHeight), wxSL_VERTICAL|wxSL_LABELS|wxSL_INVERSE); + + wxBoxSizer *sliderSizer = new wxBoxSizer( wxHORIZONTAL ); + + sliderSizer->Add(sliderX, sliderHeight ); + + wxSizerFlags flagsRight; + flagsRight.Align(wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL).DoubleBorder(); + + sliderSizer->Add(redSlider, flagsRight); + sliderSizer->Add(greenSlider,flagsRight); + sliderSizer->Add(blueSlider,flagsRight); + + topSizer->Add(sliderSizer, wxSizerFlags().Centre().DoubleBorder()); +#else + topSizer->Add(1, sliderHeight, wxSizerFlags(1).Centre().TripleBorder()); +#endif // wxUSE_SLIDER + + // then the custom button + topSizer->Add(new wxButton(this, wxID_ADD_CUSTOM, + _("Add to custom colours") ), + wxSizerFlags().DoubleHorzBorder()); + + // then the standard buttons + wxSizer *buttonsizer = CreateSeparatedButtonSizer(wxOK | wxCANCEL); + if ( buttonsizer ) + { + topSizer->Add(buttonsizer, wxSizerFlags().Expand().DoubleBorder()); + } + + SetAutoLayout( true ); + SetSizer( topSizer ); + + topSizer->SetSizeHints( this ); + topSizer->Fit( this ); + + Centre( wxBOTH ); + + wxEndBusyCursor(); +} + +void wxGenericColourDialog::InitializeColours(void) +{ + size_t i; + + for (i = 0; i < WXSIZEOF(wxColourDialogNames); i++) + { + wxColour col = wxTheColourDatabase->Find(wxColourDialogNames[i]); + if (col.Ok()) + standardColours[i].Set(col.Red(), col.Green(), col.Blue()); + else + standardColours[i].Set(0, 0, 0); + } + + for (i = 0; i < WXSIZEOF(customColours); i++) + { + wxColour c = colourData.GetCustomColour(i); + if (c.Ok()) + customColours[i] = colourData.GetCustomColour(i); + else + customColours[i] = wxColour(255, 255, 255); + } + + wxColour curr = colourData.GetColour(); + if ( curr.Ok() ) + { + bool initColourFound = false; + + for (i = 0; i < WXSIZEOF(wxColourDialogNames); i++) + { + if ( standardColours[i] == curr && !initColourFound ) + { + whichKind = 1; + colourSelection = i; + initColourFound = true; + break; + } + } + if ( !initColourFound ) + { + for ( i = 0; i < WXSIZEOF(customColours); i++ ) + { + if ( customColours[i] == curr ) + { + whichKind = 2; + colourSelection = i; + break; + } + } + } + colourData.m_dataColour.Set( curr.Red(), curr.Green(), curr.Blue() ); + } + else + { + whichKind = 1; + colourSelection = 0; + colourData.m_dataColour.Set( 0, 0, 0 ); + } +} + +void wxGenericColourDialog::PaintBasicColours(wxDC& dc) +{ + int i; + for (i = 0; i < 6; i++) + { + int j; + for (j = 0; j < 8; j++) + { + int ptr = i*8 + j; + + int x = (j*(smallRectangleSize.x+gridSpacing) + standardColoursRect.x); + int y = (i*(smallRectangleSize.y+gridSpacing) + standardColoursRect.y); + + dc.SetPen(*wxBLACK_PEN); + wxBrush brush(standardColours[ptr], wxSOLID); + dc.SetBrush(brush); + + dc.DrawRectangle( x, y, smallRectangleSize.x, smallRectangleSize.y); + } + } +} + +void wxGenericColourDialog::PaintCustomColours(wxDC& dc) +{ + int i; + for (i = 0; i < 2; i++) + { + int j; + for (j = 0; j < 8; j++) + { + int ptr = i*8 + j; + + int x = (j*(smallRectangleSize.x+gridSpacing)) + customColoursRect.x; + int y = (i*(smallRectangleSize.y+gridSpacing)) + customColoursRect.y; + + dc.SetPen(*wxBLACK_PEN); + + wxBrush brush(customColours[ptr], wxSOLID); + dc.SetBrush(brush); + + dc.DrawRectangle( x, y, smallRectangleSize.x, smallRectangleSize.y); + } + } +} + +void wxGenericColourDialog::PaintHighlight(wxDC& dc, bool draw) +{ + if ( colourSelection < 0 ) + return; + + // Number of pixels bigger than the standard rectangle size + // for drawing a highlight + int deltaX = 2; + int deltaY = 2; + + if (whichKind == 1) + { + // Standard colours + int y = (int)(colourSelection / 8); + int x = (int)(colourSelection - (y*8)); + + x = (x*(smallRectangleSize.x + gridSpacing) + standardColoursRect.x) - deltaX; + y = (y*(smallRectangleSize.y + gridSpacing) + standardColoursRect.y) - deltaY; + + if (draw) + dc.SetPen(*wxBLACK_PEN); + else + dc.SetPen(*wxLIGHT_GREY_PEN); + + dc.SetBrush(*wxTRANSPARENT_BRUSH); + dc.DrawRectangle( x, y, (smallRectangleSize.x + (2*deltaX)), (smallRectangleSize.y + (2*deltaY))); + } + else + { + // User-defined colours + int y = (int)(colourSelection / 8); + int x = (int)(colourSelection - (y*8)); + + x = (x*(smallRectangleSize.x + gridSpacing) + customColoursRect.x) - deltaX; + y = (y*(smallRectangleSize.y + gridSpacing) + customColoursRect.y) - deltaY; + + if (draw) + dc.SetPen(*wxBLACK_PEN); + else + dc.SetPen(*wxLIGHT_GREY_PEN); + + dc.SetBrush(*wxTRANSPARENT_BRUSH); + dc.DrawRectangle( x, y, (smallRectangleSize.x + (2*deltaX)), (smallRectangleSize.y + (2*deltaY))); + } +} + +void wxGenericColourDialog::PaintCustomColour(wxDC& dc) +{ + dc.SetPen(*wxBLACK_PEN); + + wxBrush *brush = new wxBrush(colourData.m_dataColour, wxSOLID); + dc.SetBrush(*brush); + + dc.DrawRectangle( singleCustomColourRect.x, singleCustomColourRect.y, + customRectangleSize.x, customRectangleSize.y); + + dc.SetBrush(wxNullBrush); + delete brush; +} + +void wxGenericColourDialog::OnBasicColourClick(int which) +{ + wxClientDC dc(this); + + PaintHighlight(dc, false); + whichKind = 1; + colourSelection = which; + +#if wxUSE_SLIDER + redSlider->SetValue( standardColours[colourSelection].Red() ); + greenSlider->SetValue( standardColours[colourSelection].Green() ); + blueSlider->SetValue( standardColours[colourSelection].Blue() ); +#endif // wxUSE_SLIDER + + colourData.m_dataColour.Set(standardColours[colourSelection].Red(), + standardColours[colourSelection].Green(), + standardColours[colourSelection].Blue()); + + PaintCustomColour(dc); + PaintHighlight(dc, true); +} + +void wxGenericColourDialog::OnCustomColourClick(int which) +{ + wxClientDC dc(this); + PaintHighlight(dc, false); + whichKind = 2; + colourSelection = which; + +#if wxUSE_SLIDER + redSlider->SetValue( customColours[colourSelection].Red() ); + greenSlider->SetValue( customColours[colourSelection].Green() ); + blueSlider->SetValue( customColours[colourSelection].Blue() ); +#endif // wxUSE_SLIDER + + colourData.m_dataColour.Set(customColours[colourSelection].Red(), + customColours[colourSelection].Green(), + customColours[colourSelection].Blue()); + + PaintCustomColour(dc); + PaintHighlight(dc, true); +} + +/* +void wxGenericColourDialog::OnOk(void) +{ + Show(false); +} + +void wxGenericColourDialog::OnCancel(void) +{ + colourDialogCancelled = true; + Show(false); +} +*/ + +void wxGenericColourDialog::OnAddCustom(wxCommandEvent& WXUNUSED(event)) +{ + wxClientDC dc(this); + if (whichKind != 2) + { + PaintHighlight(dc, false); + whichKind = 2; + colourSelection = 0; + PaintHighlight(dc, true); + } + + customColours[colourSelection].Set(colourData.m_dataColour.Red(), + colourData.m_dataColour.Green(), + colourData.m_dataColour.Blue()); + + colourData.SetCustomColour(colourSelection, customColours[colourSelection]); + + PaintCustomColours(dc); +} + +#if wxUSE_SLIDER + +void wxGenericColourDialog::OnRedSlider(wxCommandEvent& WXUNUSED(event)) +{ + if (!redSlider) + return; + + wxClientDC dc(this); + colourData.m_dataColour.Set((unsigned char)redSlider->GetValue(), colourData.m_dataColour.Green(), colourData.m_dataColour.Blue()); + PaintCustomColour(dc); +} + +void wxGenericColourDialog::OnGreenSlider(wxCommandEvent& WXUNUSED(event)) +{ + if (!greenSlider) + return; + + wxClientDC dc(this); + colourData.m_dataColour.Set(colourData.m_dataColour.Red(), (unsigned char)greenSlider->GetValue(), colourData.m_dataColour.Blue()); + PaintCustomColour(dc); +} + +void wxGenericColourDialog::OnBlueSlider(wxCommandEvent& WXUNUSED(event)) +{ + if (!blueSlider) + return; + + wxClientDC dc(this); + colourData.m_dataColour.Set(colourData.m_dataColour.Red(), colourData.m_dataColour.Green(), (unsigned char)blueSlider->GetValue()); + PaintCustomColour(dc); +} + +#endif // wxUSE_SLIDER + +#endif // wxUSE_COLOURDLG && !defined(__WXGTK20__) diff --git a/Externals/wxWidgets/src/generic/combog.cpp b/Externals/wxWidgets/src/generic/combog.cpp index 8f3fd9ef7a..6b7b1aa8b1 100644 --- a/Externals/wxWidgets/src/generic/combog.cpp +++ b/Externals/wxWidgets/src/generic/combog.cpp @@ -1,483 +1,483 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/generic/combog.cpp -// Purpose: Generic wxComboCtrl -// Author: Jaakko Salli -// Modified by: -// Created: Apr-30-2006 -// RCS-ID: $Id: combog.cpp 45232 2007-04-03 02:44:32Z PC $ -// Copyright: (c) 2005 Jaakko Salli -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_COMBOCTRL - -#include "wx/combo.h" - -#ifndef WX_PRECOMP - #include "wx/log.h" - #include "wx/combobox.h" - #include "wx/dcclient.h" - #include "wx/settings.h" -#endif - -#include "wx/dcbuffer.h" - -// ---------------------------------------------------------------------------- -// Some constant adjustments to make the generic more bearable - -#if defined(__WXUNIVERSAL__) - -#define TEXTCTRLXADJUST 0 // position adjustment for wxTextCtrl, with zero indent -#define TEXTCTRLYADJUST 0 -#define TEXTXADJUST 0 // how much is read-only text's x adjusted -#define DEFAULT_DROPBUTTON_WIDTH 19 - -#elif defined(__WXMSW__) - -#define TEXTCTRLXADJUST 2 // position adjustment for wxTextCtrl, with zero indent -#define TEXTCTRLYADJUST 3 -#define TEXTXADJUST 0 // how much is read-only text's x adjusted -#define DEFAULT_DROPBUTTON_WIDTH 17 - -#elif defined(__WXGTK__) - -#define TEXTCTRLXADJUST -1 // position adjustment for wxTextCtrl, with zero indent -#define TEXTCTRLYADJUST 0 -#define TEXTXADJUST 1 // how much is read-only text's x adjusted -#define DEFAULT_DROPBUTTON_WIDTH 23 - -#elif defined(__WXMAC__) - -#define TEXTCTRLXADJUST 0 // position adjustment for wxTextCtrl, with zero indent -#define TEXTCTRLYADJUST 0 -#define TEXTXADJUST 0 // how much is read-only text's x adjusted -#define DEFAULT_DROPBUTTON_WIDTH 22 - -#else - -#define TEXTCTRLXADJUST 0 // position adjustment for wxTextCtrl, with zero indent -#define TEXTCTRLYADJUST 0 -#define TEXTXADJUST 0 // how much is read-only text's x adjusted -#define DEFAULT_DROPBUTTON_WIDTH 19 - -#endif - - -// ============================================================================ -// implementation -// ============================================================================ - -// Only implement if no native or it wasn't fully featured -#ifndef wxCOMBOCONTROL_FULLY_FEATURED - - -// ---------------------------------------------------------------------------- -// wxGenericComboCtrl -// ---------------------------------------------------------------------------- - -BEGIN_EVENT_TABLE(wxGenericComboCtrl, wxComboCtrlBase) - EVT_PAINT(wxGenericComboCtrl::OnPaintEvent) - EVT_MOUSE_EVENTS(wxGenericComboCtrl::OnMouseEvent) -END_EVENT_TABLE() - - -IMPLEMENT_DYNAMIC_CLASS(wxGenericComboCtrl, wxComboCtrlBase) - -void wxGenericComboCtrl::Init() -{ -} - -bool wxGenericComboCtrl::Create(wxWindow *parent, - wxWindowID id, - const wxString& value, - const wxPoint& pos, - const wxSize& size, - long style, - const wxValidator& validator, - const wxString& name) -{ - // - // Note that technically we only support 'default' border and wxNO_BORDER. - long border = style & wxBORDER_MASK; - int tcBorder = wxNO_BORDER; - -#if defined(__WXUNIVERSAL__) - if ( !border ) - border = wxBORDER_SIMPLE; -#elif defined(__WXMSW__) - if ( !border ) - // For XP, have 1-width custom border, for older version use sunken - /*if ( wxUxThemeEngine::GetIfActive() ) - { - border = wxBORDER_NONE; - m_widthCustomBorder = 1; - } - else*/ - border = wxBORDER_SUNKEN; -#else - - // - // Generic version is optimized for wxGTK - // - - #define UNRELIABLE_TEXTCTRL_BORDER - - if ( !border ) - { - if ( style & wxCB_READONLY ) - { - m_widthCustomBorder = 1; - } - else - { - m_widthCustomBorder = 0; - tcBorder = 0; - } - } - else - { - // Have textctrl instead use the border given. - tcBorder = border; - } - - // Because we are going to have button outside the border, - // let's use wxBORDER_NONE for the whole control. - border = wxBORDER_NONE; - - Customize( wxCC_BUTTON_OUTSIDE_BORDER | - wxCC_NO_TEXT_AUTO_SELECT ); - -#endif - - style = (style & ~(wxBORDER_MASK)) | border; - if ( style & wxCC_STD_BUTTON ) - m_iFlags |= wxCC_POPUP_ON_MOUSE_UP; - - // create main window - if ( !wxComboCtrlBase::Create(parent, - id, - value, - pos, - size, - style | wxFULL_REPAINT_ON_RESIZE, - wxDefaultValidator, - name) ) - return false; - - // Create textctrl, if necessary - CreateTextCtrl( tcBorder, validator ); - - // Add keyboard input handlers for main control and textctrl - InstallInputHandlers(); - - // Set background - SetBackgroundStyle( wxBG_STYLE_CUSTOM ); // for double-buffering - - // SetInitialSize should be called last - SetInitialSize(size); - - return true; -} - -wxGenericComboCtrl::~wxGenericComboCtrl() -{ -} - -void wxGenericComboCtrl::OnResize() -{ - - // Recalculates button and textctrl areas - CalculateAreas(DEFAULT_DROPBUTTON_WIDTH); - -#if 0 - // Move separate button control, if any, to correct position - if ( m_btn ) - { - wxSize sz = GetClientSize(); - m_btn->SetSize( m_btnArea.x + m_btnSpacingX, - (sz.y-m_btnSize.y)/2, - m_btnSize.x, - m_btnSize.y ); - } -#endif - - // Move textctrl, if any, accordingly - PositionTextCtrl( TEXTCTRLXADJUST, TEXTCTRLYADJUST ); -} - -void wxGenericComboCtrl::OnPaintEvent( wxPaintEvent& WXUNUSED(event) ) -{ - wxSize sz = GetClientSize(); - wxAutoBufferedPaintDC dc(this); - - const wxRect& rectb = m_btnArea; - wxRect rect = m_tcArea; - - // artificial simple border - if ( m_widthCustomBorder ) - { - int customBorder = m_widthCustomBorder; - - // Set border colour - wxPen pen1( wxSystemSettings::GetColour(wxSYS_COLOUR_GRAYTEXT), - customBorder, - wxSOLID ); - dc.SetPen( pen1 ); - - // area around both controls - wxRect rect2(0,0,sz.x,sz.y); - if ( m_iFlags & wxCC_IFLAG_BUTTON_OUTSIDE ) - { - rect2 = m_tcArea; - if ( customBorder == 1 ) - { - rect2.Inflate(1); - } - else - { - #ifdef __WXGTK__ - rect2.x -= 1; - rect2.y -= 1; - #else - rect2.x -= customBorder; - rect2.y -= customBorder; - #endif - rect2.width += 1 + customBorder; - rect2.height += 1 + customBorder; - } - } - - dc.SetBrush( *wxTRANSPARENT_BRUSH ); - dc.DrawRectangle(rect2); - } - -#ifndef __WXMAC__ // see note in OnThemeChange - wxColour winCol = GetBackgroundColour(); -#else - wxColour winCol = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW); -#endif - dc.SetBrush(winCol); - dc.SetPen(winCol); - - //wxLogDebug(wxT("hei: %i tcy: %i tchei: %i"),GetClientSize().y,m_tcArea.y,m_tcArea.height); - //wxLogDebug(wxT("btnx: %i tcx: %i tcwid: %i"),m_btnArea.x,m_tcArea.x,m_tcArea.width); - - // clear main background - dc.DrawRectangle(rect); - - if ( !m_btn ) - { - // Standard button rendering - DrawButton(dc,rectb); - } - - // paint required portion on the control - if ( (!m_text || m_widthCustomPaint) ) - { - wxASSERT( m_widthCustomPaint >= 0 ); - - // this is intentionally here to allow drawed rectangle's - // right edge to be hidden - if ( m_text ) - rect.width = m_widthCustomPaint; - - dc.SetFont( GetFont() ); - - dc.SetClippingRegion(rect); - if ( m_popupInterface ) - m_popupInterface->PaintComboControl(dc,rect); - else - wxComboPopup::DefaultPaintComboControl(this,dc,rect); - } -} - -void wxGenericComboCtrl::OnMouseEvent( wxMouseEvent& event ) -{ - int mx = event.m_x; - bool isOnButtonArea = m_btnArea.Contains(mx,event.m_y); - int handlerFlags = isOnButtonArea ? wxCC_MF_ON_BUTTON : 0; - - if ( PreprocessMouseEvent(event,handlerFlags) ) - return; - - const bool ctrlIsButton = wxPlatformIs(wxOS_WINDOWS); - - if ( ctrlIsButton && - (m_windowStyle & (wxCC_SPECIAL_DCLICK|wxCB_READONLY)) == wxCB_READONLY ) - { - // if no textctrl and no special double-click, then the entire control acts - // as a button - handlerFlags |= wxCC_MF_ON_BUTTON; - if ( HandleButtonMouseEvent(event,handlerFlags) ) - return; - } - else - { - if ( isOnButtonArea || HasCapture() || - (m_widthCustomPaint && mx < (m_tcArea.x+m_widthCustomPaint)) ) - { - handlerFlags |= wxCC_MF_ON_CLICK_AREA; - - if ( HandleButtonMouseEvent(event,handlerFlags) ) - return; - } - else if ( m_btnState ) - { - // otherwise need to clear the hover status - m_btnState = 0; - RefreshRect(m_btnArea); - } - } - - // - // This will handle left_down and left_dclick events outside button in a Windows/GTK-like manner. - // See header file for further information on this method. - HandleNormalMouseEvent(event); - -} - -void wxGenericComboCtrl::SetCustomPaintWidth( int width ) -{ -#ifdef UNRELIABLE_TEXTCTRL_BORDER - // - // If starting/stopping to show an image in front - // of a writable text-field, then re-create textctrl - // with different kind of border (because we can't - // assume that textctrl fully supports wxNO_BORDER). - // - wxTextCtrl* tc = GetTextCtrl(); - - if ( tc && (m_iFlags & wxCC_BUTTON_OUTSIDE_BORDER) ) - { - int borderType = tc->GetWindowStyle() & wxBORDER_MASK; - int tcCreateStyle = -1; - - if ( width > 0 ) - { - // Re-create textctrl with no border - if ( borderType != wxNO_BORDER ) - { - m_widthCustomBorder = 1; - tcCreateStyle = wxNO_BORDER; - } - } - else if ( width == 0 ) - { - // Re-create textctrl with normal border - if ( borderType == wxNO_BORDER ) - { - m_widthCustomBorder = 0; - tcCreateStyle = 0; - } - } - - // Common textctrl re-creation code - if ( tcCreateStyle != -1 ) - { - tc->RemoveEventHandler(m_textEvtHandler); - delete m_textEvtHandler; - -#if wxUSE_VALIDATORS - wxValidator* pValidator = tc->GetValidator(); - if ( pValidator ) - { - pValidator = (wxValidator*) pValidator->Clone(); - CreateTextCtrl( tcCreateStyle, *pValidator ); - delete pValidator; - } - else -#endif - { - CreateTextCtrl( tcCreateStyle, wxDefaultValidator ); - } - - InstallInputHandlers(); - } - } -#endif // UNRELIABLE_TEXTCTRL_BORDER - - wxComboCtrlBase::SetCustomPaintWidth( width ); -} - -bool wxGenericComboCtrl::IsKeyPopupToggle(const wxKeyEvent& event) const -{ - int keycode = event.GetKeyCode(); - bool isPopupShown = IsPopupShown(); - - // This code is AFAIK appropriate for wxGTK. - - if ( isPopupShown ) - { - if ( keycode == WXK_ESCAPE || - ( keycode == WXK_UP && event.AltDown() ) ) - return true; - } - else - { - if ( keycode == WXK_DOWN && event.AltDown() ) - return true; - } - - return false; -} - -#ifdef __WXUNIVERSAL__ - -bool wxGenericComboCtrl::PerformAction(const wxControlAction& action, - long numArg, - const wxString& strArg) -{ - bool processed = false; - if ( action == wxACTION_COMBOBOX_POPUP ) - { - if ( !IsPopupShown() ) - { - ShowPopup(); - - processed = true; - } - } - else if ( action == wxACTION_COMBOBOX_DISMISS ) - { - if ( IsPopupShown() ) - { - HidePopup(); - - processed = true; - } - } - - if ( !processed ) - { - // pass along - return wxControl::PerformAction(action, numArg, strArg); - } - - return true; -} - -#endif // __WXUNIVERSAL__ - -// If native wxComboCtrl was not defined, then prepare a simple -// front-end so that wxRTTI works as expected. -#ifndef _WX_COMBOCONTROL_H_ -IMPLEMENT_DYNAMIC_CLASS(wxComboCtrl, wxGenericComboCtrl) -#endif - -#endif // !wxCOMBOCONTROL_FULLY_FEATURED - -#endif // wxUSE_COMBOCTRL +///////////////////////////////////////////////////////////////////////////// +// Name: src/generic/combog.cpp +// Purpose: Generic wxComboCtrl +// Author: Jaakko Salli +// Modified by: +// Created: Apr-30-2006 +// RCS-ID: $Id: combog.cpp 45232 2007-04-03 02:44:32Z PC $ +// Copyright: (c) 2005 Jaakko Salli +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_COMBOCTRL + +#include "wx/combo.h" + +#ifndef WX_PRECOMP + #include "wx/log.h" + #include "wx/combobox.h" + #include "wx/dcclient.h" + #include "wx/settings.h" +#endif + +#include "wx/dcbuffer.h" + +// ---------------------------------------------------------------------------- +// Some constant adjustments to make the generic more bearable + +#if defined(__WXUNIVERSAL__) + +#define TEXTCTRLXADJUST 0 // position adjustment for wxTextCtrl, with zero indent +#define TEXTCTRLYADJUST 0 +#define TEXTXADJUST 0 // how much is read-only text's x adjusted +#define DEFAULT_DROPBUTTON_WIDTH 19 + +#elif defined(__WXMSW__) + +#define TEXTCTRLXADJUST 2 // position adjustment for wxTextCtrl, with zero indent +#define TEXTCTRLYADJUST 3 +#define TEXTXADJUST 0 // how much is read-only text's x adjusted +#define DEFAULT_DROPBUTTON_WIDTH 17 + +#elif defined(__WXGTK__) + +#define TEXTCTRLXADJUST -1 // position adjustment for wxTextCtrl, with zero indent +#define TEXTCTRLYADJUST 0 +#define TEXTXADJUST 1 // how much is read-only text's x adjusted +#define DEFAULT_DROPBUTTON_WIDTH 23 + +#elif defined(__WXMAC__) + +#define TEXTCTRLXADJUST 0 // position adjustment for wxTextCtrl, with zero indent +#define TEXTCTRLYADJUST 0 +#define TEXTXADJUST 0 // how much is read-only text's x adjusted +#define DEFAULT_DROPBUTTON_WIDTH 22 + +#else + +#define TEXTCTRLXADJUST 0 // position adjustment for wxTextCtrl, with zero indent +#define TEXTCTRLYADJUST 0 +#define TEXTXADJUST 0 // how much is read-only text's x adjusted +#define DEFAULT_DROPBUTTON_WIDTH 19 + +#endif + + +// ============================================================================ +// implementation +// ============================================================================ + +// Only implement if no native or it wasn't fully featured +#ifndef wxCOMBOCONTROL_FULLY_FEATURED + + +// ---------------------------------------------------------------------------- +// wxGenericComboCtrl +// ---------------------------------------------------------------------------- + +BEGIN_EVENT_TABLE(wxGenericComboCtrl, wxComboCtrlBase) + EVT_PAINT(wxGenericComboCtrl::OnPaintEvent) + EVT_MOUSE_EVENTS(wxGenericComboCtrl::OnMouseEvent) +END_EVENT_TABLE() + + +IMPLEMENT_DYNAMIC_CLASS(wxGenericComboCtrl, wxComboCtrlBase) + +void wxGenericComboCtrl::Init() +{ +} + +bool wxGenericComboCtrl::Create(wxWindow *parent, + wxWindowID id, + const wxString& value, + const wxPoint& pos, + const wxSize& size, + long style, + const wxValidator& validator, + const wxString& name) +{ + // + // Note that technically we only support 'default' border and wxNO_BORDER. + long border = style & wxBORDER_MASK; + int tcBorder = wxNO_BORDER; + +#if defined(__WXUNIVERSAL__) + if ( !border ) + border = wxBORDER_SIMPLE; +#elif defined(__WXMSW__) + if ( !border ) + // For XP, have 1-width custom border, for older version use sunken + /*if ( wxUxThemeEngine::GetIfActive() ) + { + border = wxBORDER_NONE; + m_widthCustomBorder = 1; + } + else*/ + border = wxBORDER_SUNKEN; +#else + + // + // Generic version is optimized for wxGTK + // + + #define UNRELIABLE_TEXTCTRL_BORDER + + if ( !border ) + { + if ( style & wxCB_READONLY ) + { + m_widthCustomBorder = 1; + } + else + { + m_widthCustomBorder = 0; + tcBorder = 0; + } + } + else + { + // Have textctrl instead use the border given. + tcBorder = border; + } + + // Because we are going to have button outside the border, + // let's use wxBORDER_NONE for the whole control. + border = wxBORDER_NONE; + + Customize( wxCC_BUTTON_OUTSIDE_BORDER | + wxCC_NO_TEXT_AUTO_SELECT ); + +#endif + + style = (style & ~(wxBORDER_MASK)) | border; + if ( style & wxCC_STD_BUTTON ) + m_iFlags |= wxCC_POPUP_ON_MOUSE_UP; + + // create main window + if ( !wxComboCtrlBase::Create(parent, + id, + value, + pos, + size, + style | wxFULL_REPAINT_ON_RESIZE, + wxDefaultValidator, + name) ) + return false; + + // Create textctrl, if necessary + CreateTextCtrl( tcBorder, validator ); + + // Add keyboard input handlers for main control and textctrl + InstallInputHandlers(); + + // Set background + SetBackgroundStyle( wxBG_STYLE_CUSTOM ); // for double-buffering + + // SetInitialSize should be called last + SetInitialSize(size); + + return true; +} + +wxGenericComboCtrl::~wxGenericComboCtrl() +{ +} + +void wxGenericComboCtrl::OnResize() +{ + + // Recalculates button and textctrl areas + CalculateAreas(DEFAULT_DROPBUTTON_WIDTH); + +#if 0 + // Move separate button control, if any, to correct position + if ( m_btn ) + { + wxSize sz = GetClientSize(); + m_btn->SetSize( m_btnArea.x + m_btnSpacingX, + (sz.y-m_btnSize.y)/2, + m_btnSize.x, + m_btnSize.y ); + } +#endif + + // Move textctrl, if any, accordingly + PositionTextCtrl( TEXTCTRLXADJUST, TEXTCTRLYADJUST ); +} + +void wxGenericComboCtrl::OnPaintEvent( wxPaintEvent& WXUNUSED(event) ) +{ + wxSize sz = GetClientSize(); + wxAutoBufferedPaintDC dc(this); + + const wxRect& rectb = m_btnArea; + wxRect rect = m_tcArea; + + // artificial simple border + if ( m_widthCustomBorder ) + { + int customBorder = m_widthCustomBorder; + + // Set border colour + wxPen pen1( wxSystemSettings::GetColour(wxSYS_COLOUR_GRAYTEXT), + customBorder, + wxSOLID ); + dc.SetPen( pen1 ); + + // area around both controls + wxRect rect2(0,0,sz.x,sz.y); + if ( m_iFlags & wxCC_IFLAG_BUTTON_OUTSIDE ) + { + rect2 = m_tcArea; + if ( customBorder == 1 ) + { + rect2.Inflate(1); + } + else + { + #ifdef __WXGTK__ + rect2.x -= 1; + rect2.y -= 1; + #else + rect2.x -= customBorder; + rect2.y -= customBorder; + #endif + rect2.width += 1 + customBorder; + rect2.height += 1 + customBorder; + } + } + + dc.SetBrush( *wxTRANSPARENT_BRUSH ); + dc.DrawRectangle(rect2); + } + +#ifndef __WXMAC__ // see note in OnThemeChange + wxColour winCol = GetBackgroundColour(); +#else + wxColour winCol = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW); +#endif + dc.SetBrush(winCol); + dc.SetPen(winCol); + + //wxLogDebug(wxT("hei: %i tcy: %i tchei: %i"),GetClientSize().y,m_tcArea.y,m_tcArea.height); + //wxLogDebug(wxT("btnx: %i tcx: %i tcwid: %i"),m_btnArea.x,m_tcArea.x,m_tcArea.width); + + // clear main background + dc.DrawRectangle(rect); + + if ( !m_btn ) + { + // Standard button rendering + DrawButton(dc,rectb); + } + + // paint required portion on the control + if ( (!m_text || m_widthCustomPaint) ) + { + wxASSERT( m_widthCustomPaint >= 0 ); + + // this is intentionally here to allow drawed rectangle's + // right edge to be hidden + if ( m_text ) + rect.width = m_widthCustomPaint; + + dc.SetFont( GetFont() ); + + dc.SetClippingRegion(rect); + if ( m_popupInterface ) + m_popupInterface->PaintComboControl(dc,rect); + else + wxComboPopup::DefaultPaintComboControl(this,dc,rect); + } +} + +void wxGenericComboCtrl::OnMouseEvent( wxMouseEvent& event ) +{ + int mx = event.m_x; + bool isOnButtonArea = m_btnArea.Contains(mx,event.m_y); + int handlerFlags = isOnButtonArea ? wxCC_MF_ON_BUTTON : 0; + + if ( PreprocessMouseEvent(event,handlerFlags) ) + return; + + const bool ctrlIsButton = wxPlatformIs(wxOS_WINDOWS); + + if ( ctrlIsButton && + (m_windowStyle & (wxCC_SPECIAL_DCLICK|wxCB_READONLY)) == wxCB_READONLY ) + { + // if no textctrl and no special double-click, then the entire control acts + // as a button + handlerFlags |= wxCC_MF_ON_BUTTON; + if ( HandleButtonMouseEvent(event,handlerFlags) ) + return; + } + else + { + if ( isOnButtonArea || HasCapture() || + (m_widthCustomPaint && mx < (m_tcArea.x+m_widthCustomPaint)) ) + { + handlerFlags |= wxCC_MF_ON_CLICK_AREA; + + if ( HandleButtonMouseEvent(event,handlerFlags) ) + return; + } + else if ( m_btnState ) + { + // otherwise need to clear the hover status + m_btnState = 0; + RefreshRect(m_btnArea); + } + } + + // + // This will handle left_down and left_dclick events outside button in a Windows/GTK-like manner. + // See header file for further information on this method. + HandleNormalMouseEvent(event); + +} + +void wxGenericComboCtrl::SetCustomPaintWidth( int width ) +{ +#ifdef UNRELIABLE_TEXTCTRL_BORDER + // + // If starting/stopping to show an image in front + // of a writable text-field, then re-create textctrl + // with different kind of border (because we can't + // assume that textctrl fully supports wxNO_BORDER). + // + wxTextCtrl* tc = GetTextCtrl(); + + if ( tc && (m_iFlags & wxCC_BUTTON_OUTSIDE_BORDER) ) + { + int borderType = tc->GetWindowStyle() & wxBORDER_MASK; + int tcCreateStyle = -1; + + if ( width > 0 ) + { + // Re-create textctrl with no border + if ( borderType != wxNO_BORDER ) + { + m_widthCustomBorder = 1; + tcCreateStyle = wxNO_BORDER; + } + } + else if ( width == 0 ) + { + // Re-create textctrl with normal border + if ( borderType == wxNO_BORDER ) + { + m_widthCustomBorder = 0; + tcCreateStyle = 0; + } + } + + // Common textctrl re-creation code + if ( tcCreateStyle != -1 ) + { + tc->RemoveEventHandler(m_textEvtHandler); + delete m_textEvtHandler; + +#if wxUSE_VALIDATORS + wxValidator* pValidator = tc->GetValidator(); + if ( pValidator ) + { + pValidator = (wxValidator*) pValidator->Clone(); + CreateTextCtrl( tcCreateStyle, *pValidator ); + delete pValidator; + } + else +#endif + { + CreateTextCtrl( tcCreateStyle, wxDefaultValidator ); + } + + InstallInputHandlers(); + } + } +#endif // UNRELIABLE_TEXTCTRL_BORDER + + wxComboCtrlBase::SetCustomPaintWidth( width ); +} + +bool wxGenericComboCtrl::IsKeyPopupToggle(const wxKeyEvent& event) const +{ + int keycode = event.GetKeyCode(); + bool isPopupShown = IsPopupShown(); + + // This code is AFAIK appropriate for wxGTK. + + if ( isPopupShown ) + { + if ( keycode == WXK_ESCAPE || + ( keycode == WXK_UP && event.AltDown() ) ) + return true; + } + else + { + if ( keycode == WXK_DOWN && event.AltDown() ) + return true; + } + + return false; +} + +#ifdef __WXUNIVERSAL__ + +bool wxGenericComboCtrl::PerformAction(const wxControlAction& action, + long numArg, + const wxString& strArg) +{ + bool processed = false; + if ( action == wxACTION_COMBOBOX_POPUP ) + { + if ( !IsPopupShown() ) + { + ShowPopup(); + + processed = true; + } + } + else if ( action == wxACTION_COMBOBOX_DISMISS ) + { + if ( IsPopupShown() ) + { + HidePopup(); + + processed = true; + } + } + + if ( !processed ) + { + // pass along + return wxControl::PerformAction(action, numArg, strArg); + } + + return true; +} + +#endif // __WXUNIVERSAL__ + +// If native wxComboCtrl was not defined, then prepare a simple +// front-end so that wxRTTI works as expected. +#ifndef _WX_COMBOCONTROL_H_ +IMPLEMENT_DYNAMIC_CLASS(wxComboCtrl, wxGenericComboCtrl) +#endif + +#endif // !wxCOMBOCONTROL_FULLY_FEATURED + +#endif // wxUSE_COMBOCTRL diff --git a/Externals/wxWidgets/src/generic/datavgen.cpp b/Externals/wxWidgets/src/generic/datavgen.cpp index cabf70be82..1a009bb114 100644 --- a/Externals/wxWidgets/src/generic/datavgen.cpp +++ b/Externals/wxWidgets/src/generic/datavgen.cpp @@ -1,1911 +1,1911 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/generic/datavgen.cpp -// Purpose: wxDataViewCtrl generic implementation -// Author: Robert Roebling -// Id: $Id: datavgen.cpp 45498 2007-04-16 13:03:05Z VZ $ -// Copyright: (c) 1998 Robert Roebling -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_DATAVIEWCTRL - -#include "wx/dataview.h" - -#ifdef wxUSE_GENERICDATAVIEWCTRL - -#ifndef WX_PRECOMP - #ifdef __WXMSW__ - #include "wx/msw/wrapwin.h" - #endif - #include "wx/sizer.h" - #include "wx/log.h" - #include "wx/dcclient.h" - #include "wx/timer.h" - #include "wx/settings.h" - #include "wx/msgdlg.h" -#endif - -#include "wx/stockitem.h" -#include "wx/calctrl.h" -#include "wx/popupwin.h" -#include "wx/renderer.h" -#include "wx/dcbuffer.h" -#include "wx/icon.h" - -//----------------------------------------------------------------------------- -// classes -//----------------------------------------------------------------------------- - -class wxDataViewCtrl; - -//----------------------------------------------------------------------------- -// wxDataViewHeaderWindow -//----------------------------------------------------------------------------- - -class wxDataViewHeaderWindow: public wxWindow -{ -public: - wxDataViewHeaderWindow( wxDataViewCtrl *parent, - wxWindowID id, - const wxPoint &pos = wxDefaultPosition, - const wxSize &size = wxDefaultSize, - const wxString &name = wxT("wxdataviewctrlheaderwindow") ); - virtual ~wxDataViewHeaderWindow(); - - void SetOwner( wxDataViewCtrl* owner ) { m_owner = owner; } - wxDataViewCtrl *GetOwner() { return m_owner; } - - void OnPaint( wxPaintEvent &event ); - void OnMouse( wxMouseEvent &event ); - void OnSetFocus( wxFocusEvent &event ); - -private: - wxDataViewCtrl *m_owner; - wxCursor *m_resizeCursor; - -private: - DECLARE_DYNAMIC_CLASS(wxDataViewHeaderWindow) - DECLARE_EVENT_TABLE() -}; - -//----------------------------------------------------------------------------- -// wxDataViewRenameTimer -//----------------------------------------------------------------------------- - -class wxDataViewRenameTimer: public wxTimer -{ -private: - wxDataViewMainWindow *m_owner; - -public: - wxDataViewRenameTimer( wxDataViewMainWindow *owner ); - void Notify(); -}; - -//----------------------------------------------------------------------------- -// wxDataViewTextCtrlWrapper: wraps a wxTextCtrl for inline editing -//----------------------------------------------------------------------------- - -class wxDataViewTextCtrlWrapper : public wxEvtHandler -{ -public: - // NB: text must be a valid object but not Create()d yet - wxDataViewTextCtrlWrapper( wxDataViewMainWindow *owner, - wxTextCtrl *text, - wxDataViewListModel *model, - unsigned int col, unsigned int row, - wxRect cellLabel ); - - wxTextCtrl *GetText() const { return m_text; } - - void AcceptChangesAndFinish(); - -protected: - void OnChar( wxKeyEvent &event ); - void OnKeyUp( wxKeyEvent &event ); - void OnKillFocus( wxFocusEvent &event ); - - bool AcceptChanges(); - void Finish(); - -private: - wxDataViewMainWindow *m_owner; - wxTextCtrl *m_text; - wxString m_startValue; - wxDataViewListModel *m_model; - unsigned int m_col; - unsigned int m_row; - bool m_finished; - bool m_aboutToFinish; - - DECLARE_EVENT_TABLE() -}; - -//----------------------------------------------------------------------------- -// wxDataViewMainWindow -//----------------------------------------------------------------------------- - -WX_DEFINE_SORTED_USER_EXPORTED_ARRAY_SIZE_T(unsigned int, wxDataViewSelection, WXDLLIMPEXP_ADV); - -class wxDataViewMainWindow: public wxWindow -{ -public: - wxDataViewMainWindow( wxDataViewCtrl *parent, - wxWindowID id, - const wxPoint &pos = wxDefaultPosition, - const wxSize &size = wxDefaultSize, - const wxString &name = wxT("wxdataviewctrlmainwindow") ); - virtual ~wxDataViewMainWindow(); - - // notifications from wxDataViewListModel - bool RowAppended(); - bool RowPrepended(); - bool RowInserted( unsigned int before ); - bool RowDeleted( unsigned int row ); - bool RowChanged( unsigned int row ); - bool ValueChanged( unsigned int col, unsigned int row ); - bool RowsReordered( unsigned int *new_order ); - bool Cleared(); - - void SetOwner( wxDataViewCtrl* owner ) { m_owner = owner; } - wxDataViewCtrl *GetOwner() { return m_owner; } - - void OnPaint( wxPaintEvent &event ); - void OnArrowChar(unsigned int newCurrent, const wxKeyEvent& event); - void OnChar( wxKeyEvent &event ); - void OnMouse( wxMouseEvent &event ); - void OnSetFocus( wxFocusEvent &event ); - void OnKillFocus( wxFocusEvent &event ); - - void UpdateDisplay(); - void RecalculateDisplay(); - void OnInternalIdle(); - - void OnRenameTimer(); - void FinishEditing( wxTextCtrl *text ); - - void ScrollWindow( int dx, int dy, const wxRect *rect ); - - bool HasCurrentRow() { return m_currentRow != (unsigned int)-1; } - void ChangeCurrentRow( unsigned int row ); - - bool IsSingleSel() const { return !GetParent()->HasFlag(wxDV_MULTIPLE); } - bool IsEmpty() { return GetRowCount() == 0; } - - int GetCountPerPage(); - int GetEndOfLastCol(); - unsigned int GetFirstVisibleRow(); - unsigned int GetLastVisibleRow(); - unsigned int GetRowCount(); - - void SelectAllRows( bool on ); - void SelectRow( unsigned int row, bool on ); - void SelectRows( unsigned int from, unsigned int to, bool on ); - void ReverseRowSelection( unsigned int row ); - bool IsRowSelected( unsigned int row ); - - void RefreshRow( unsigned int row ); - void RefreshRows( unsigned int from, unsigned int to ); - void RefreshRowsAfter( unsigned int firstRow ); - -private: - wxDataViewCtrl *m_owner; - int m_lineHeight; - bool m_dirty; - - wxDataViewColumn *m_currentCol; - unsigned int m_currentRow; - wxDataViewSelection m_selection; - - wxDataViewRenameTimer *m_renameTimer; - wxDataViewTextCtrlWrapper *m_textctrlWrapper; - bool m_lastOnSame; - - bool m_hasFocus; - - int m_dragCount; - wxPoint m_dragStart; - - // for double click logic - unsigned int m_lineLastClicked, - m_lineBeforeLastClicked, - m_lineSelectSingleOnUp; - -private: - DECLARE_DYNAMIC_CLASS(wxDataViewMainWindow) - DECLARE_EVENT_TABLE() -}; - -// --------------------------------------------------------- -// wxGenericDataViewListModelNotifier -// --------------------------------------------------------- - -class wxGenericDataViewListModelNotifier: public wxDataViewListModelNotifier -{ -public: - wxGenericDataViewListModelNotifier( wxDataViewMainWindow *mainWindow ) - { m_mainWindow = mainWindow; } - - virtual bool RowAppended() - { return m_mainWindow->RowAppended(); } - virtual bool RowPrepended() - { return m_mainWindow->RowPrepended(); } - virtual bool RowInserted( unsigned int before ) - { return m_mainWindow->RowInserted( before ); } - virtual bool RowDeleted( unsigned int row ) - { return m_mainWindow->RowDeleted( row ); } - virtual bool RowChanged( unsigned int row ) - { return m_mainWindow->RowChanged( row ); } - virtual bool ValueChanged( unsigned int col, unsigned int row ) - { return m_mainWindow->ValueChanged( col, row ); } - virtual bool RowsReordered( unsigned int *new_order ) - { return m_mainWindow->RowsReordered( new_order ); } - virtual bool Cleared() - { return m_mainWindow->Cleared(); } - - wxDataViewMainWindow *m_mainWindow; -}; - -// --------------------------------------------------------- -// wxDataViewRenderer -// --------------------------------------------------------- - -IMPLEMENT_ABSTRACT_CLASS(wxDataViewRenderer, wxDataViewRendererBase) - -wxDataViewRenderer::wxDataViewRenderer( const wxString &varianttype, wxDataViewCellMode mode ) : - wxDataViewRendererBase( varianttype, mode ) -{ - m_dc = NULL; -} - -wxDataViewRenderer::~wxDataViewRenderer() -{ - if (m_dc) - delete m_dc; -} - -wxDC *wxDataViewRenderer::GetDC() -{ - if (m_dc == NULL) - { - if (GetOwner() == NULL) - return NULL; - if (GetOwner()->GetOwner() == NULL) - return NULL; - m_dc = new wxClientDC( GetOwner()->GetOwner() ); - } - - return m_dc; -} - -// --------------------------------------------------------- -// wxDataViewCustomRenderer -// --------------------------------------------------------- - -IMPLEMENT_ABSTRACT_CLASS(wxDataViewCustomRenderer, wxDataViewRenderer) - -wxDataViewCustomRenderer::wxDataViewCustomRenderer( const wxString &varianttype, - wxDataViewCellMode mode ) : - wxDataViewRenderer( varianttype, mode ) -{ -} - -// --------------------------------------------------------- -// wxDataViewTextRenderer -// --------------------------------------------------------- - -IMPLEMENT_CLASS(wxDataViewTextRenderer, wxDataViewCustomRenderer) - -wxDataViewTextRenderer::wxDataViewTextRenderer( const wxString &varianttype, wxDataViewCellMode mode ) : - wxDataViewCustomRenderer( varianttype, mode ) -{ -} - -bool wxDataViewTextRenderer::SetValue( const wxVariant &value ) -{ - m_text = value.GetString(); - - return true; -} - -bool wxDataViewTextRenderer::GetValue( wxVariant& WXUNUSED(value) ) -{ - return false; -} - -bool wxDataViewTextRenderer::Render( wxRect cell, wxDC *dc, int WXUNUSED(state) ) -{ - dc->DrawText( m_text, cell.x, cell.y ); - - return true; -} - -wxSize wxDataViewTextRenderer::GetSize() -{ - return wxSize(80,20); -} - -// --------------------------------------------------------- -// wxDataViewBitmapRenderer -// --------------------------------------------------------- - -IMPLEMENT_CLASS(wxDataViewBitmapRenderer, wxDataViewCustomRenderer) - -wxDataViewBitmapRenderer::wxDataViewBitmapRenderer( const wxString &varianttype, wxDataViewCellMode mode ) : - wxDataViewCustomRenderer( varianttype, mode ) -{ -} - -bool wxDataViewBitmapRenderer::SetValue( const wxVariant &value ) -{ - if (value.GetType() == wxT("wxBitmap")) - m_bitmap << value; - if (value.GetType() == wxT("wxIcon")) - m_icon << value; - - return true; -} - -bool wxDataViewBitmapRenderer::GetValue( wxVariant& WXUNUSED(value) ) -{ - return false; -} - -bool wxDataViewBitmapRenderer::Render( wxRect cell, wxDC *dc, int WXUNUSED(state) ) -{ - if (m_bitmap.Ok()) - dc->DrawBitmap( m_bitmap, cell.x, cell.y ); - else if (m_icon.Ok()) - dc->DrawIcon( m_icon, cell.x, cell.y ); - - return true; -} - -wxSize wxDataViewBitmapRenderer::GetSize() -{ - if (m_bitmap.Ok()) - return wxSize( m_bitmap.GetWidth(), m_bitmap.GetHeight() ); - else if (m_icon.Ok()) - return wxSize( m_icon.GetWidth(), m_icon.GetHeight() ); - - return wxSize(16,16); -} - -// --------------------------------------------------------- -// wxDataViewToggleRenderer -// --------------------------------------------------------- - -IMPLEMENT_ABSTRACT_CLASS(wxDataViewToggleRenderer, wxDataViewCustomRenderer) - -wxDataViewToggleRenderer::wxDataViewToggleRenderer( const wxString &varianttype, - wxDataViewCellMode mode ) : - wxDataViewCustomRenderer( varianttype, mode ) -{ - m_toggle = false; -} - -bool wxDataViewToggleRenderer::SetValue( const wxVariant &value ) -{ - m_toggle = value.GetBool(); - - return true; -} - -bool wxDataViewToggleRenderer::GetValue( wxVariant &WXUNUSED(value) ) -{ - return false; -} - -bool wxDataViewToggleRenderer::Render( wxRect cell, wxDC *dc, int WXUNUSED(state) ) -{ - // User wxRenderer here - - wxRect rect; - rect.x = cell.x + cell.width/2 - 10; - rect.width = 20; - rect.y = cell.y + cell.height/2 - 10; - rect.height = 20; - - int flags = 0; - if (m_toggle) - flags |= wxCONTROL_CHECKED; - if (GetMode() != wxDATAVIEW_CELL_ACTIVATABLE) - flags |= wxCONTROL_DISABLED; - - wxRendererNative::Get().DrawCheckBox( - GetOwner()->GetOwner(), - *dc, - rect, - flags ); - - return true; -} - -bool wxDataViewToggleRenderer::Activate( wxRect WXUNUSED(cell), wxDataViewListModel *model, unsigned int col, unsigned int row ) -{ - bool value = !m_toggle; - wxVariant variant = value; - model->SetValue( variant, col, row ); - model->ValueChanged( col, row ); - return true; -} - -wxSize wxDataViewToggleRenderer::GetSize() -{ - return wxSize(20,20); -} - -// --------------------------------------------------------- -// wxDataViewProgressRenderer -// --------------------------------------------------------- - -IMPLEMENT_ABSTRACT_CLASS(wxDataViewProgressRenderer, wxDataViewCustomRenderer) - -wxDataViewProgressRenderer::wxDataViewProgressRenderer( const wxString &label, - const wxString &varianttype, wxDataViewCellMode mode ) : - wxDataViewCustomRenderer( varianttype, mode ) -{ - m_label = label; - m_value = 0; -} - -wxDataViewProgressRenderer::~wxDataViewProgressRenderer() -{ -} - -bool wxDataViewProgressRenderer::SetValue( const wxVariant &value ) -{ - m_value = (long) value; - - if (m_value < 0) m_value = 0; - if (m_value > 100) m_value = 100; - - return true; -} - -bool wxDataViewProgressRenderer::Render( wxRect cell, wxDC *dc, int WXUNUSED(state) ) -{ - double pct = (double)m_value / 100.0; - wxRect bar = cell; - bar.width = (int)(cell.width * pct); - dc->SetPen( *wxTRANSPARENT_PEN ); - dc->SetBrush( *wxBLUE_BRUSH ); - dc->DrawRectangle( bar ); - - dc->SetBrush( *wxTRANSPARENT_BRUSH ); - dc->SetPen( *wxBLACK_PEN ); - dc->DrawRectangle( cell ); - - return true; -} - -wxSize wxDataViewProgressRenderer::GetSize() -{ - return wxSize(40,12); -} - -// --------------------------------------------------------- -// wxDataViewDateRenderer -// --------------------------------------------------------- - -#define wxUSE_DATE_RENDERER_POPUP (wxUSE_CALENDARCTRL && wxUSE_POPUPWIN) - -#if wxUSE_DATE_RENDERER_POPUP - -class wxDataViewDateRendererPopupTransient: public wxPopupTransientWindow -{ -public: - wxDataViewDateRendererPopupTransient( wxWindow* parent, wxDateTime *value, - wxDataViewListModel *model, unsigned int col, unsigned int row ) : - wxPopupTransientWindow( parent, wxBORDER_SIMPLE ) - { - m_model = model; - m_col = col; - m_row = row; - m_cal = new wxCalendarCtrl( this, wxID_ANY, *value ); - wxBoxSizer *sizer = new wxBoxSizer( wxHORIZONTAL ); - sizer->Add( m_cal, 1, wxGROW ); - SetSizer( sizer ); - sizer->Fit( this ); - } - - void OnCalendar( wxCalendarEvent &event ); - - wxCalendarCtrl *m_cal; - wxDataViewListModel *m_model; - unsigned int m_col; - unsigned int m_row; - -protected: - virtual void OnDismiss() - { - } - -private: - DECLARE_EVENT_TABLE() -}; - -BEGIN_EVENT_TABLE(wxDataViewDateRendererPopupTransient,wxPopupTransientWindow) - EVT_CALENDAR( wxID_ANY, wxDataViewDateRendererPopupTransient::OnCalendar ) -END_EVENT_TABLE() - -void wxDataViewDateRendererPopupTransient::OnCalendar( wxCalendarEvent &event ) -{ - wxDateTime date = event.GetDate(); - wxVariant value = date; - m_model->SetValue( value, m_col, m_row ); - m_model->ValueChanged( m_col, m_row ); - DismissAndNotify(); -} - -#endif // wxUSE_DATE_RENDERER_POPUP - -IMPLEMENT_ABSTRACT_CLASS(wxDataViewDateRenderer, wxDataViewCustomRenderer) - -wxDataViewDateRenderer::wxDataViewDateRenderer( const wxString &varianttype, - wxDataViewCellMode mode ) : - wxDataViewCustomRenderer( varianttype, mode ) -{ -} - -bool wxDataViewDateRenderer::SetValue( const wxVariant &value ) -{ - m_date = value.GetDateTime(); - - return true; -} - -bool wxDataViewDateRenderer::Render( wxRect cell, wxDC *dc, int WXUNUSED(state) ) -{ - dc->SetFont( GetOwner()->GetOwner()->GetFont() ); - wxString tmp = m_date.FormatDate(); - dc->DrawText( tmp, cell.x, cell.y ); - - return true; -} - -wxSize wxDataViewDateRenderer::GetSize() -{ - wxDataViewCtrl* view = GetOwner()->GetOwner(); - wxString tmp = m_date.FormatDate(); - wxCoord x,y,d; - view->GetTextExtent( tmp, &x, &y, &d ); - return wxSize(x,y+d); -} - -bool wxDataViewDateRenderer::Activate( wxRect WXUNUSED(cell), wxDataViewListModel *model, unsigned int col, unsigned int row ) -{ - wxVariant variant; - model->GetValue( variant, col, row ); - wxDateTime value = variant.GetDateTime(); - -#if wxUSE_DATE_RENDERER_POPUP - wxDataViewDateRendererPopupTransient *popup = new wxDataViewDateRendererPopupTransient( - GetOwner()->GetOwner()->GetParent(), &value, model, col, row ); - wxPoint pos = wxGetMousePosition(); - popup->Move( pos ); - popup->Layout(); - popup->Popup( popup->m_cal ); -#else // !wxUSE_DATE_RENDERER_POPUP - wxMessageBox(value.Format()); -#endif // wxUSE_DATE_RENDERER_POPUP/!wxUSE_DATE_RENDERER_POPUP - return true; -} - -// --------------------------------------------------------- -// wxDataViewColumn -// --------------------------------------------------------- - -IMPLEMENT_ABSTRACT_CLASS(wxDataViewColumn, wxDataViewColumnBase) - -wxDataViewColumn::wxDataViewColumn( const wxString &title, wxDataViewRenderer *cell, unsigned int model_column, - int width, int flags ) : - wxDataViewColumnBase( title, cell, model_column, width, flags ) -{ - m_width = width; - if (m_width < 0) - m_width = 80; -} - -wxDataViewColumn::wxDataViewColumn( const wxBitmap &bitmap, wxDataViewRenderer *cell, unsigned int model_column, - int width, int flags ) : - wxDataViewColumnBase( bitmap, cell, model_column, width, flags ) -{ - m_width = width; - if (m_width < 0) - m_width = 30; -} - -void wxDataViewColumn::SetAlignment( wxAlignment WXUNUSED(align) ) -{ - // TODO -} - -void wxDataViewColumn::SetSortable( bool WXUNUSED(sortable) ) -{ - // TODO -} - -bool wxDataViewColumn::GetSortable() -{ - // TODO - return false; -} - -void wxDataViewColumn::SetSortOrder( bool WXUNUSED(ascending) ) -{ - // TODO -} - -bool wxDataViewColumn::IsSortOrderAscending() -{ - // TODO - return true; -} - - -wxDataViewColumn::~wxDataViewColumn() -{ -} - -void wxDataViewColumn::SetTitle( const wxString &title ) -{ - wxDataViewColumnBase::SetTitle( title ); - -} - -void wxDataViewColumn::SetBitmap( const wxBitmap &bitmap ) -{ - wxDataViewColumnBase::SetBitmap( bitmap ); - -} - -int wxDataViewColumn::GetWidth() -{ - return m_width; -} - -//----------------------------------------------------------------------------- -// wxDataViewHeaderWindow -//----------------------------------------------------------------------------- - -IMPLEMENT_ABSTRACT_CLASS(wxDataViewHeaderWindow, wxWindow) - -BEGIN_EVENT_TABLE(wxDataViewHeaderWindow,wxWindow) - EVT_PAINT (wxDataViewHeaderWindow::OnPaint) - EVT_MOUSE_EVENTS (wxDataViewHeaderWindow::OnMouse) - EVT_SET_FOCUS (wxDataViewHeaderWindow::OnSetFocus) -END_EVENT_TABLE() - -wxDataViewHeaderWindow::wxDataViewHeaderWindow( wxDataViewCtrl *parent, wxWindowID id, - const wxPoint &pos, const wxSize &size, const wxString &name ) : - wxWindow( parent, id, pos, size, 0, name ) -{ - SetOwner( parent ); - - m_resizeCursor = new wxCursor( wxCURSOR_SIZEWE ); - - wxVisualAttributes attr = wxPanel::GetClassDefaultAttributes(); - SetBackgroundStyle( wxBG_STYLE_CUSTOM ); - SetOwnForegroundColour( attr.colFg ); - SetOwnBackgroundColour( attr.colBg ); - if (!m_hasFont) - SetOwnFont( attr.font ); -} - -wxDataViewHeaderWindow::~wxDataViewHeaderWindow() -{ - delete m_resizeCursor; -} - -void wxDataViewHeaderWindow::OnPaint( wxPaintEvent &WXUNUSED(event) ) -{ - int w, h; - GetClientSize( &w, &h ); - - wxAutoBufferedPaintDC dc( this ); - - dc.SetBackground(GetBackgroundColour()); - dc.Clear(); - - int xpix; - m_owner->GetScrollPixelsPerUnit( &xpix, NULL ); - - int x; - m_owner->GetViewStart( &x, NULL ); - - // account for the horz scrollbar offset - dc.SetDeviceOrigin( -x * xpix, 0 ); - - dc.SetFont( GetFont() ); - - unsigned int cols = GetOwner()->GetNumberOfColumns(); - unsigned int i; - int xpos = 0; - for (i = 0; i < cols; i++) - { - wxDataViewColumn *col = GetOwner()->GetColumn( i ); - int width = col->GetWidth(); - - int cw = width; - int ch = h; - - wxRendererNative::Get().DrawHeaderButton - ( - this, - dc, - wxRect(xpos, 0, cw, ch-1), - m_parent->IsEnabled() ? 0 - : (int)wxCONTROL_DISABLED - ); - - dc.DrawText( col->GetTitle(), xpos+3, 3 ); - - xpos += width; - } -} - -void wxDataViewHeaderWindow::OnMouse( wxMouseEvent &WXUNUSED(event) ) -{ -} - -void wxDataViewHeaderWindow::OnSetFocus( wxFocusEvent &event ) -{ - GetParent()->SetFocus(); - event.Skip(); -} - -//----------------------------------------------------------------------------- -// wxDataViewRenameTimer -//----------------------------------------------------------------------------- - -wxDataViewRenameTimer::wxDataViewRenameTimer( wxDataViewMainWindow *owner ) -{ - m_owner = owner; -} - -void wxDataViewRenameTimer::Notify() -{ - m_owner->OnRenameTimer(); -} - -//----------------------------------------------------------------------------- -// wxDataViewTextCtrlWrapper: wraps a wxTextCtrl for inline editing -//----------------------------------------------------------------------------- - -BEGIN_EVENT_TABLE(wxDataViewTextCtrlWrapper, wxEvtHandler) - EVT_CHAR (wxDataViewTextCtrlWrapper::OnChar) - EVT_KEY_UP (wxDataViewTextCtrlWrapper::OnKeyUp) - EVT_KILL_FOCUS (wxDataViewTextCtrlWrapper::OnKillFocus) -END_EVENT_TABLE() - -wxDataViewTextCtrlWrapper::wxDataViewTextCtrlWrapper( - wxDataViewMainWindow *owner, - wxTextCtrl *text, - wxDataViewListModel *model, - unsigned int col, unsigned int row, - wxRect rectLabel ) -{ - m_owner = owner; - m_model = model; - m_row = row; - m_col = col; - m_text = text; - - m_finished = false; - m_aboutToFinish = false; - - wxVariant value; - model->GetValue( value, col, row ); - m_startValue = value.GetString(); - - m_owner->GetOwner()->CalcScrolledPosition( - rectLabel.x, rectLabel.y, &rectLabel.x, &rectLabel.y ); - - m_text->Create( owner, wxID_ANY, m_startValue, - wxPoint(rectLabel.x-2,rectLabel.y-2), - wxSize(rectLabel.width+7,rectLabel.height+4) ); - m_text->SetFocus(); - - m_text->PushEventHandler(this); -} - -void wxDataViewTextCtrlWrapper::AcceptChangesAndFinish() -{ - m_aboutToFinish = true; - - // Notify the owner about the changes - AcceptChanges(); - - // Even if vetoed, close the control (consistent with MSW) - Finish(); -} - -void wxDataViewTextCtrlWrapper::OnChar( wxKeyEvent &event ) -{ - switch ( event.m_keyCode ) - { - case WXK_RETURN: - AcceptChangesAndFinish(); - break; - - case WXK_ESCAPE: - // m_owner->OnRenameCancelled( m_itemEdited ); - Finish(); - break; - - default: - event.Skip(); - } -} - -void wxDataViewTextCtrlWrapper::OnKeyUp( wxKeyEvent &event ) -{ - if (m_finished) - { - event.Skip(); - return; - } - - // auto-grow the textctrl - wxSize parentSize = m_owner->GetSize(); - wxPoint myPos = m_text->GetPosition(); - wxSize mySize = m_text->GetSize(); - int sx, sy; - m_text->GetTextExtent(m_text->GetValue() + _T("MM"), &sx, &sy); - if (myPos.x + sx > parentSize.x) - sx = parentSize.x - myPos.x; - if (mySize.x > sx) - sx = mySize.x; - m_text->SetSize(sx, wxDefaultCoord); - - event.Skip(); -} - -void wxDataViewTextCtrlWrapper::OnKillFocus( wxFocusEvent &event ) -{ - if ( !m_finished && !m_aboutToFinish ) - { - AcceptChanges(); - //if ( !AcceptChanges() ) - // m_owner->OnRenameCancelled( m_itemEdited ); - - Finish(); - } - - // We must let the native text control handle focus - event.Skip(); -} - -bool wxDataViewTextCtrlWrapper::AcceptChanges() -{ - const wxString value = m_text->GetValue(); - - if ( value == m_startValue ) - // nothing changed, always accept - return true; - -// if ( !m_owner->OnRenameAccept(m_itemEdited, value) ) - // vetoed by the user -// return false; - - // accepted, do rename the item - wxVariant variant; - variant = value; - m_model->SetValue( variant, m_col, m_row ); - m_model->ValueChanged( m_col, m_row ); - - return true; -} - -void wxDataViewTextCtrlWrapper::Finish() -{ - if ( !m_finished ) - { - m_finished = true; - - m_text->RemoveEventHandler(this); - m_owner->FinishEditing(m_text); - - // delete later - wxPendingDelete.Append( this ); - } -} - -//----------------------------------------------------------------------------- -// wxDataViewMainWindow -//----------------------------------------------------------------------------- - -int LINKAGEMODE wxDataViewSelectionCmp( unsigned int row1, unsigned int row2 ) -{ - if (row1 > row2) return 1; - if (row1 == row2) return 0; - return -1; -} - - -IMPLEMENT_ABSTRACT_CLASS(wxDataViewMainWindow, wxWindow) - -BEGIN_EVENT_TABLE(wxDataViewMainWindow,wxWindow) - EVT_PAINT (wxDataViewMainWindow::OnPaint) - EVT_MOUSE_EVENTS (wxDataViewMainWindow::OnMouse) - EVT_SET_FOCUS (wxDataViewMainWindow::OnSetFocus) - EVT_KILL_FOCUS (wxDataViewMainWindow::OnKillFocus) - EVT_CHAR (wxDataViewMainWindow::OnChar) -END_EVENT_TABLE() - -wxDataViewMainWindow::wxDataViewMainWindow( wxDataViewCtrl *parent, wxWindowID id, - const wxPoint &pos, const wxSize &size, const wxString &name ) : - wxWindow( parent, id, pos, size, wxWANTS_CHARS, name ), - m_selection( wxDataViewSelectionCmp ) - -{ - SetOwner( parent ); - - m_lastOnSame = false; - m_renameTimer = new wxDataViewRenameTimer( this ); - m_textctrlWrapper = NULL; - - // TODO: user better initial values/nothing selected - m_currentCol = NULL; - m_currentRow = 0; - - // TODO: we need to calculate this smartly - m_lineHeight = 20; - - m_dragCount = 0; - m_dragStart = wxPoint(0,0); - m_lineLastClicked = (unsigned int) -1; - m_lineBeforeLastClicked = (unsigned int) -1; - m_lineSelectSingleOnUp = (unsigned int) -1; - - m_hasFocus = false; - - SetBackgroundStyle( wxBG_STYLE_CUSTOM ); - SetBackgroundColour( *wxWHITE ); - - UpdateDisplay(); -} - -wxDataViewMainWindow::~wxDataViewMainWindow() -{ - delete m_renameTimer; -} - -void wxDataViewMainWindow::OnRenameTimer() -{ - // We have to call this here because changes may just have - // been made and no screen update taken place. - if ( m_dirty ) - wxSafeYield(); - - - int xpos = 0; - unsigned int cols = GetOwner()->GetNumberOfColumns(); - unsigned int i; - for (i = 0; i < cols; i++) - { - wxDataViewColumn *c = GetOwner()->GetColumn( i ); - if (c == m_currentCol) - break; - xpos += c->GetWidth(); - } - wxRect labelRect( xpos, m_currentRow * m_lineHeight, m_currentCol->GetWidth(), m_lineHeight ); - - wxClassInfo *textControlClass = CLASSINFO(wxTextCtrl); - - wxTextCtrl * const text = (wxTextCtrl *)textControlClass->CreateObject(); - m_textctrlWrapper = new wxDataViewTextCtrlWrapper(this, text, GetOwner()->GetModel(), - m_currentCol->GetModelColumn(), m_currentRow, labelRect ); -} - -void wxDataViewMainWindow::FinishEditing( wxTextCtrl *text ) -{ - delete text; - m_textctrlWrapper = NULL; - SetFocus(); - // SetFocusIgnoringChildren(); -} - -bool wxDataViewMainWindow::RowAppended() -{ - return false; -} - -bool wxDataViewMainWindow::RowPrepended() -{ - return false; -} - -bool wxDataViewMainWindow::RowInserted( unsigned int WXUNUSED(before) ) -{ - return false; -} - -bool wxDataViewMainWindow::RowDeleted( unsigned int WXUNUSED(row) ) -{ - return false; -} - -bool wxDataViewMainWindow::RowChanged( unsigned int WXUNUSED(row) ) -{ - return false; -} - -bool wxDataViewMainWindow::ValueChanged( unsigned int WXUNUSED(col), unsigned int row ) -{ - wxRect rect( 0, row*m_lineHeight, 10000, m_lineHeight ); - m_owner->CalcScrolledPosition( rect.x, rect.y, &rect.x, &rect.y ); - Refresh( true, &rect ); - - return true; -} - -bool wxDataViewMainWindow::RowsReordered( unsigned int *WXUNUSED(new_order) ) -{ - Refresh(); - - return true; -} - -bool wxDataViewMainWindow::Cleared() -{ - return false; -} - -void wxDataViewMainWindow::UpdateDisplay() -{ - m_dirty = true; -} - -void wxDataViewMainWindow::OnInternalIdle() -{ - wxWindow::OnInternalIdle(); - - if (m_dirty) - { - RecalculateDisplay(); - m_dirty = false; - } -} - -void wxDataViewMainWindow::RecalculateDisplay() -{ - wxDataViewListModel *model = GetOwner()->GetModel(); - if (!model) - { - Refresh(); - return; - } - - int width = 0; - unsigned int cols = GetOwner()->GetNumberOfColumns(); - unsigned int i; - for (i = 0; i < cols; i++) - { - wxDataViewColumn *col = GetOwner()->GetColumn( i ); - width += col->GetWidth(); - } - - int height = model->GetNumberOfRows() * m_lineHeight; - - SetVirtualSize( width, height ); - GetOwner()->SetScrollRate( 10, m_lineHeight ); - - Refresh(); -} - -void wxDataViewMainWindow::ScrollWindow( int dx, int dy, const wxRect *rect ) -{ - wxWindow::ScrollWindow( dx, dy, rect ); - GetOwner()->m_headerArea->ScrollWindow( dx, 0 ); -} - -void wxDataViewMainWindow::OnPaint( wxPaintEvent &WXUNUSED(event) ) -{ - wxAutoBufferedPaintDC dc( this ); - - dc.SetBackground(GetBackgroundColour()); - dc.Clear(); - - GetOwner()->PrepareDC( dc ); - - dc.SetFont( GetFont() ); - - wxRect update = GetUpdateRegion().GetBox(); - m_owner->CalcUnscrolledPosition( update.x, update.y, &update.x, &update.y ); - - wxDataViewListModel *model = GetOwner()->GetModel(); - - unsigned int item_start = wxMax( 0, (update.y / m_lineHeight) ); - unsigned int item_count = wxMin( (int)(((update.y + update.height) / m_lineHeight) - item_start + 1), - (int)(model->GetNumberOfRows()-item_start) ); - - - - unsigned int item; - for (item = item_start; item < item_start+item_count; item++) - { - if (m_selection.Index( item ) != wxNOT_FOUND) - { - int flags = wxCONTROL_SELECTED; - if (item == m_currentRow) - flags |= wxCONTROL_CURRENT; - if (m_hasFocus) - flags |= wxCONTROL_FOCUSED; - wxRect rect( 0, item*m_lineHeight+1, GetEndOfLastCol(), m_lineHeight-2 ); - wxRendererNative::Get().DrawItemSelectionRect - ( - this, - dc, - rect, - flags - ); - } - else - { - if (item == m_currentRow) - { - int flags = wxCONTROL_CURRENT; - if (m_hasFocus) - flags |= wxCONTROL_FOCUSED; // should have no effect - wxRect rect( 0, item*m_lineHeight+1, GetEndOfLastCol(), m_lineHeight-2 ); - wxRendererNative::Get().DrawItemSelectionRect - ( - this, - dc, - rect, - flags - ); - - } - } - } - - wxRect cell_rect; - cell_rect.x = 0; - cell_rect.height = m_lineHeight; - unsigned int cols = GetOwner()->GetNumberOfColumns(); - unsigned int i; - for (i = 0; i < cols; i++) - { - wxDataViewColumn *col = GetOwner()->GetColumn( i ); - wxDataViewRenderer *cell = col->GetRenderer(); - cell_rect.width = col->GetWidth(); - - for (item = item_start; item < item_start+item_count; item++) - { - cell_rect.y = item*m_lineHeight; - wxVariant value; - model->GetValue( value, col->GetModelColumn(), item ); - cell->SetValue( value ); - wxSize size = cell->GetSize(); - // cannot be bigger than allocated space - size.x = wxMin( size.x, cell_rect.width ); - size.y = wxMin( size.y, cell_rect.height ); - // TODO: check for left/right/centre alignment here - wxRect item_rect; - // for now: centre - item_rect.x = cell_rect.x + (cell_rect.width / 2) - (size.x / 2); - item_rect.y = cell_rect.y + (cell_rect.height / 2) - (size.y / 2); - - item_rect.width = size.x; - item_rect.height= size.y; - - int state = 0; - if (item == m_currentRow) - state |= wxDATAVIEW_CELL_SELECTED; - cell->Render( item_rect, &dc, state ); - } - - cell_rect.x += cell_rect.width; - } -} - -int wxDataViewMainWindow::GetCountPerPage() -{ - wxSize size = GetClientSize(); - return size.y / m_lineHeight; -} - -int wxDataViewMainWindow::GetEndOfLastCol() -{ - int width = 0; - unsigned int i; - for (i = 0; i < GetOwner()->GetNumberOfColumns(); i++) - { - wxDataViewColumn *c = GetOwner()->GetColumn( i ); - width += c->GetWidth(); - } - return width; -} - -unsigned int wxDataViewMainWindow::GetFirstVisibleRow() -{ - int x = 0; - int y = 0; - m_owner->CalcUnscrolledPosition( x, y, &x, &y ); - - return y / m_lineHeight; -} - -unsigned int wxDataViewMainWindow::GetLastVisibleRow() -{ - wxSize client_size = GetClientSize(); - m_owner->CalcUnscrolledPosition( client_size.x, client_size.y, &client_size.x, &client_size.y ); - - return wxMin( GetRowCount()-1, ((unsigned)client_size.y/m_lineHeight)+1 ); -} - -unsigned int wxDataViewMainWindow::GetRowCount() -{ - return GetOwner()->GetModel()->GetNumberOfRows(); -} - -void wxDataViewMainWindow::ChangeCurrentRow( unsigned int row ) -{ - m_currentRow = row; - - // send event -} - -void wxDataViewMainWindow::SelectAllRows( bool on ) -{ - if (IsEmpty()) - return; - - if (on) - { - m_selection.Clear(); - for (unsigned int i = 0; i < GetRowCount(); i++) - m_selection.Add( i ); - Refresh(); - } - else - { - unsigned int first_visible = GetFirstVisibleRow(); - unsigned int last_visible = GetLastVisibleRow(); - unsigned int i; - for (i = 0; i < m_selection.GetCount(); i++) - { - unsigned int row = m_selection[i]; - if ((row >= first_visible) && (row <= last_visible)) - RefreshRow( row ); - } - m_selection.Clear(); - } -} - -void wxDataViewMainWindow::SelectRow( unsigned int row, bool on ) -{ - if (m_selection.Index( row ) == wxNOT_FOUND) - { - if (on) - { - m_selection.Add( row ); - RefreshRow( row ); - } - } - else - { - if (!on) - { - m_selection.Remove( row ); - RefreshRow( row ); - } - } -} - -void wxDataViewMainWindow::SelectRows( unsigned int from, unsigned int to, bool on ) -{ - if (from > to) - { - unsigned int tmp = from; - from = to; - to = tmp; - } - - unsigned int i; - for (i = from; i <= to; i++) - { - if (m_selection.Index( i ) == wxNOT_FOUND) - { - if (on) - m_selection.Add( i ); - } - else - { - if (!on) - m_selection.Remove( i ); - } - } - RefreshRows( from, to ); -} - -void wxDataViewMainWindow::ReverseRowSelection( unsigned int row ) -{ - if (m_selection.Index( row ) == wxNOT_FOUND) - m_selection.Add( row ); - else - m_selection.Remove( row ); - RefreshRow( row ); -} - -bool wxDataViewMainWindow::IsRowSelected( unsigned int row ) -{ - return (m_selection.Index( row ) != wxNOT_FOUND); -} - -void wxDataViewMainWindow::RefreshRow( unsigned int row ) -{ - wxRect rect( 0, row*m_lineHeight, GetEndOfLastCol(), m_lineHeight ); - m_owner->CalcScrolledPosition( rect.x, rect.y, &rect.x, &rect.y ); - - wxSize client_size = GetClientSize(); - wxRect client_rect( 0, 0, client_size.x, client_size.y ); - wxRect intersect_rect = client_rect.Intersect( rect ); - if (intersect_rect.width > 0) - Refresh( true, &intersect_rect ); -} - -void wxDataViewMainWindow::RefreshRows( unsigned int from, unsigned int to ) -{ - if (from > to) - { - unsigned int tmp = to; - to = from; - from = tmp; - } - - wxRect rect( 0, from*m_lineHeight, GetEndOfLastCol(), (to-from+1) * m_lineHeight ); - m_owner->CalcScrolledPosition( rect.x, rect.y, &rect.x, &rect.y ); - - wxSize client_size = GetClientSize(); - wxRect client_rect( 0, 0, client_size.x, client_size.y ); - wxRect intersect_rect = client_rect.Intersect( rect ); - if (intersect_rect.width > 0) - Refresh( true, &intersect_rect ); -} - -void wxDataViewMainWindow::RefreshRowsAfter( unsigned int firstRow ) -{ - unsigned int count = GetRowCount(); - if (firstRow > count) - return; - - wxRect rect( 0, firstRow*m_lineHeight, GetEndOfLastCol(), count * m_lineHeight ); - m_owner->CalcScrolledPosition( rect.x, rect.y, &rect.x, &rect.y ); - - wxSize client_size = GetClientSize(); - wxRect client_rect( 0, 0, client_size.x, client_size.y ); - wxRect intersect_rect = client_rect.Intersect( rect ); - if (intersect_rect.width > 0) - Refresh( true, &intersect_rect ); -} - -void wxDataViewMainWindow::OnArrowChar(unsigned int newCurrent, const wxKeyEvent& event) -{ - wxCHECK_RET( newCurrent < GetRowCount(), - _T("invalid item index in OnArrowChar()") ); - - // if there is no selection, we cannot move it anywhere - if (!HasCurrentRow()) - return; - - unsigned int oldCurrent = m_currentRow; - - // in single selection we just ignore Shift as we can't select several - // items anyhow - if ( event.ShiftDown() && !IsSingleSel() ) - { - RefreshRow( oldCurrent ); - - ChangeCurrentRow( newCurrent ); - - // select all the items between the old and the new one - if ( oldCurrent > newCurrent ) - { - newCurrent = oldCurrent; - oldCurrent = m_currentRow; - } - - SelectRows( oldCurrent, newCurrent, true ); - } - else // !shift - { - RefreshRow( oldCurrent ); - - // all previously selected items are unselected unless ctrl is held - if ( !event.ControlDown() ) - SelectAllRows(false); - - ChangeCurrentRow( newCurrent ); - - if ( !event.ControlDown() ) - SelectRow( m_currentRow, true ); - else - RefreshRow( m_currentRow ); - } - - // MoveToFocus(); -} - -void wxDataViewMainWindow::OnChar( wxKeyEvent &event ) -{ - if (event.GetKeyCode() == WXK_TAB) - { - wxNavigationKeyEvent nevent; - nevent.SetWindowChange( event.ControlDown() ); - nevent.SetDirection( !event.ShiftDown() ); - nevent.SetEventObject( GetParent()->GetParent() ); - nevent.SetCurrentFocus( m_parent ); - if (GetParent()->GetParent()->GetEventHandler()->ProcessEvent( nevent )) - return; - } - - // no item -> nothing to do - if (!HasCurrentRow()) - { - event.Skip(); - return; - } - - // don't use m_linesPerPage directly as it might not be computed yet - const int pageSize = GetCountPerPage(); - wxCHECK_RET( pageSize, _T("should have non zero page size") ); - - switch ( event.GetKeyCode() ) - { - case WXK_UP: - if ( m_currentRow > 0 ) - OnArrowChar( m_currentRow - 1, event ); - break; - - case WXK_DOWN: - if ( m_currentRow < GetRowCount() - 1 ) - OnArrowChar( m_currentRow + 1, event ); - break; - - case WXK_END: - if (!IsEmpty()) - OnArrowChar( GetRowCount() - 1, event ); - break; - - case WXK_HOME: - if (!IsEmpty()) - OnArrowChar( 0, event ); - break; - - case WXK_PAGEUP: - { - int steps = pageSize - 1; - int index = m_currentRow - steps; - if (index < 0) - index = 0; - - OnArrowChar( index, event ); - } - break; - - case WXK_PAGEDOWN: - { - int steps = pageSize - 1; - unsigned int index = m_currentRow + steps; - unsigned int count = GetRowCount(); - if ( index >= count ) - index = count - 1; - - OnArrowChar( index, event ); - } - break; - - default: - event.Skip(); - } -} - -void wxDataViewMainWindow::OnMouse( wxMouseEvent &event ) -{ - if (event.GetEventType() == wxEVT_MOUSEWHEEL) - { - // let the base handle mouse wheel events. - event.Skip(); - return; - } - - int x = event.GetX(); - int y = event.GetY(); - m_owner->CalcUnscrolledPosition( x, y, &x, &y ); - - wxDataViewColumn *col = NULL; - - int xpos = 0; - unsigned int cols = GetOwner()->GetNumberOfColumns(); - unsigned int i; - for (i = 0; i < cols; i++) - { - wxDataViewColumn *c = GetOwner()->GetColumn( i ); - if (x < xpos + c->GetWidth()) - { - col = c; - break; - } - xpos += c->GetWidth(); - } - if (!col) - return; - wxDataViewRenderer *cell = col->GetRenderer(); - - unsigned int current = y / m_lineHeight; - - if ((current > GetRowCount()) || (x > GetEndOfLastCol())) - { - // Unselect all if below the last row ? - return; - } - - wxDataViewListModel *model = GetOwner()->GetModel(); - - if (event.Dragging()) - { - if (m_dragCount == 0) - { - // we have to report the raw, physical coords as we want to be - // able to call HitTest(event.m_pointDrag) from the user code to - // get the item being dragged - m_dragStart = event.GetPosition(); - } - - m_dragCount++; - - if (m_dragCount != 3) - return; - - if (event.LeftIsDown()) - { - // Notify cell about drag - } - return; - } - else - { - m_dragCount = 0; - } - - bool forceClick = false; - - if (event.ButtonDClick()) - { - m_renameTimer->Stop(); - m_lastOnSame = false; - } - - if (event.LeftDClick()) - { - if ( current == m_lineLastClicked ) - { - if (cell->GetMode() == wxDATAVIEW_CELL_ACTIVATABLE) - { - wxVariant value; - model->GetValue( value, col->GetModelColumn(), current ); - cell->SetValue( value ); - wxRect cell_rect( xpos, current * m_lineHeight, col->GetWidth(), m_lineHeight ); - cell->Activate( cell_rect, model, col->GetModelColumn(), current ); - } - return; - } - else - { - // The first click was on another item, so don't interpret this as - // a double click, but as a simple click instead - forceClick = true; - } - } - - if (event.LeftUp()) - { - if (m_lineSelectSingleOnUp != (unsigned int)-1) - { - // select single line - SelectAllRows( false ); - SelectRow( m_lineSelectSingleOnUp, true ); - } - - if (m_lastOnSame) - { - if ((col == m_currentCol) && (current == m_currentRow) && - (cell->GetMode() == wxDATAVIEW_CELL_EDITABLE) ) - { - m_renameTimer->Start( 100, true ); - } - } - - m_lastOnSame = false; - m_lineSelectSingleOnUp = (unsigned int)-1; - } - else - { - // This is necessary, because after a DnD operation in - // from and to ourself, the up event is swallowed by the - // DnD code. So on next non-up event (which means here and - // now) m_lineSelectSingleOnUp should be reset. - m_lineSelectSingleOnUp = (unsigned int)-1; - } - - if (event.RightDown()) - { - m_lineBeforeLastClicked = m_lineLastClicked; - m_lineLastClicked = current; - - // If the item is already selected, do not update the selection. - // Multi-selections should not be cleared if a selected item is clicked. - if (!IsRowSelected(current)) - { - SelectAllRows(false); - ChangeCurrentRow(current); - SelectRow(m_currentRow,true); - } - - // notify cell about right click - // cell->... - - // Allow generation of context menu event - event.Skip(); - } - else if (event.MiddleDown()) - { - // notify cell about middle click - // cell->... - } - if (event.LeftDown() || forceClick) - { -#ifdef __WXMSW__ - SetFocus(); -#endif - - m_lineBeforeLastClicked = m_lineLastClicked; - m_lineLastClicked = current; - - unsigned int oldCurrentRow = m_currentRow; - bool oldWasSelected = IsRowSelected(m_currentRow); - - bool cmdModifierDown = event.CmdDown(); - if ( IsSingleSel() || !(cmdModifierDown || event.ShiftDown()) ) - { - if ( IsSingleSel() || !IsRowSelected(current) ) - { - SelectAllRows( false ); - - ChangeCurrentRow(current); - - SelectRow(m_currentRow,true); - } - else // multi sel & current is highlighted & no mod keys - { - m_lineSelectSingleOnUp = current; - ChangeCurrentRow(current); // change focus - } - } - else // multi sel & either ctrl or shift is down - { - if (cmdModifierDown) - { - ChangeCurrentRow(current); - - ReverseRowSelection(m_currentRow); - } - else if (event.ShiftDown()) - { - ChangeCurrentRow(current); - - unsigned int lineFrom = oldCurrentRow, - lineTo = current; - - if ( lineTo < lineFrom ) - { - lineTo = lineFrom; - lineFrom = m_currentRow; - } - - SelectRows(lineFrom, lineTo, true); - } - else // !ctrl, !shift - { - // test in the enclosing if should make it impossible - wxFAIL_MSG( _T("how did we get here?") ); - } - } - - if (m_currentRow != oldCurrentRow) - RefreshRow( oldCurrentRow ); - - wxDataViewColumn *oldCurrentCol = m_currentCol; - - // Update selection here... - m_currentCol = col; - - m_lastOnSame = !forceClick && ((col == oldCurrentCol) && (current == oldCurrentRow)) && oldWasSelected; - } -} - -void wxDataViewMainWindow::OnSetFocus( wxFocusEvent &event ) -{ - m_hasFocus = true; - - if (HasCurrentRow()) - Refresh(); - - event.Skip(); -} - -void wxDataViewMainWindow::OnKillFocus( wxFocusEvent &event ) -{ - m_hasFocus = false; - - if (HasCurrentRow()) - Refresh(); - - event.Skip(); -} - -//----------------------------------------------------------------------------- -// wxDataViewCtrl -//----------------------------------------------------------------------------- - -IMPLEMENT_DYNAMIC_CLASS(wxDataViewCtrl, wxDataViewCtrlBase) - -BEGIN_EVENT_TABLE(wxDataViewCtrl, wxDataViewCtrlBase) - EVT_SIZE(wxDataViewCtrl::OnSize) -END_EVENT_TABLE() - -wxDataViewCtrl::~wxDataViewCtrl() -{ - if (m_notifier) - GetModel()->RemoveNotifier( m_notifier ); -} - -void wxDataViewCtrl::Init() -{ - m_notifier = NULL; -} - -bool wxDataViewCtrl::Create(wxWindow *parent, wxWindowID id, - const wxPoint& pos, const wxSize& size, - long style, const wxValidator& validator ) -{ - if (!wxControl::Create( parent, id, pos, size, style | wxScrolledWindowStyle|wxSUNKEN_BORDER, validator)) - return false; - - Init(); - -#ifdef __WXMAC__ - MacSetClipChildren( true ) ; -#endif - - m_clientArea = new wxDataViewMainWindow( this, wxID_ANY ); -#ifdef __WXMSW__ - m_headerArea = new wxDataViewHeaderWindow( this, wxID_ANY, wxDefaultPosition, wxSize(wxDefaultCoord,22) ); -#else - m_headerArea = new wxDataViewHeaderWindow( this, wxID_ANY, wxDefaultPosition, wxSize(wxDefaultCoord,25) ); -#endif - - SetTargetWindow( m_clientArea ); - - wxBoxSizer *sizer = new wxBoxSizer( wxVERTICAL ); - sizer->Add( m_headerArea, 0, wxGROW ); - sizer->Add( m_clientArea, 1, wxGROW ); - SetSizer( sizer ); - - return true; -} - -#ifdef __WXMSW__ -WXLRESULT wxDataViewCtrl::MSWWindowProc(WXUINT nMsg, - WXWPARAM wParam, - WXLPARAM lParam) -{ - WXLRESULT rc = wxDataViewCtrlBase::MSWWindowProc(nMsg, wParam, lParam); - -#ifndef __WXWINCE__ - // we need to process arrows ourselves for scrolling - if ( nMsg == WM_GETDLGCODE ) - { - rc |= DLGC_WANTARROWS; - } -#endif - - return rc; -} -#endif - -void wxDataViewCtrl::OnSize( wxSizeEvent &WXUNUSED(event) ) -{ - // We need to override OnSize so that our scrolled - // window a) does call Layout() to use sizers for - // positioning the controls but b) does not query - // the sizer for their size and use that for setting - // the scrollable area as set that ourselves by - // calling SetScrollbar() further down. - - Layout(); - - AdjustScrollbars(); -} - -bool wxDataViewCtrl::AssociateModel( wxDataViewListModel *model ) -{ - if (!wxDataViewCtrlBase::AssociateModel( model )) - return false; - - m_notifier = new wxGenericDataViewListModelNotifier( m_clientArea ); - - model->AddNotifier( m_notifier ); - - m_clientArea->UpdateDisplay(); - - return true; -} - -bool wxDataViewCtrl::AppendColumn( wxDataViewColumn *col ) -{ - if (!wxDataViewCtrlBase::AppendColumn(col)) - return false; - - m_clientArea->UpdateDisplay(); - - return true; -} - -void wxDataViewCtrl::SetSelection( int WXUNUSED(row) ) -{ - // FIXME - TODO -} - -void wxDataViewCtrl::SetSelectionRange( unsigned int WXUNUSED(from), unsigned int WXUNUSED(to) ) -{ - // FIXME - TODO -} - -void wxDataViewCtrl::SetSelections( const wxArrayInt& WXUNUSED(aSelections) ) -{ - // FIXME - TODO -} - -void wxDataViewCtrl::Unselect( unsigned int WXUNUSED(row) ) -{ - // FIXME - TODO -} - -bool wxDataViewCtrl::IsSelected( unsigned int WXUNUSED(row) ) const -{ - // FIXME - TODO - - return false; -} - -int wxDataViewCtrl::GetSelection() const -{ - // FIXME - TODO - - return -1; -} - -int wxDataViewCtrl::GetSelections(wxArrayInt& WXUNUSED(aSelections) ) const -{ - // FIXME - TODO - - return 0; -} - -#endif - // !wxUSE_GENERICDATAVIEWCTRL - -#endif - // wxUSE_DATAVIEWCTRL +///////////////////////////////////////////////////////////////////////////// +// Name: src/generic/datavgen.cpp +// Purpose: wxDataViewCtrl generic implementation +// Author: Robert Roebling +// Id: $Id: datavgen.cpp 45498 2007-04-16 13:03:05Z VZ $ +// Copyright: (c) 1998 Robert Roebling +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_DATAVIEWCTRL + +#include "wx/dataview.h" + +#ifdef wxUSE_GENERICDATAVIEWCTRL + +#ifndef WX_PRECOMP + #ifdef __WXMSW__ + #include "wx/msw/wrapwin.h" + #endif + #include "wx/sizer.h" + #include "wx/log.h" + #include "wx/dcclient.h" + #include "wx/timer.h" + #include "wx/settings.h" + #include "wx/msgdlg.h" +#endif + +#include "wx/stockitem.h" +#include "wx/calctrl.h" +#include "wx/popupwin.h" +#include "wx/renderer.h" +#include "wx/dcbuffer.h" +#include "wx/icon.h" + +//----------------------------------------------------------------------------- +// classes +//----------------------------------------------------------------------------- + +class wxDataViewCtrl; + +//----------------------------------------------------------------------------- +// wxDataViewHeaderWindow +//----------------------------------------------------------------------------- + +class wxDataViewHeaderWindow: public wxWindow +{ +public: + wxDataViewHeaderWindow( wxDataViewCtrl *parent, + wxWindowID id, + const wxPoint &pos = wxDefaultPosition, + const wxSize &size = wxDefaultSize, + const wxString &name = wxT("wxdataviewctrlheaderwindow") ); + virtual ~wxDataViewHeaderWindow(); + + void SetOwner( wxDataViewCtrl* owner ) { m_owner = owner; } + wxDataViewCtrl *GetOwner() { return m_owner; } + + void OnPaint( wxPaintEvent &event ); + void OnMouse( wxMouseEvent &event ); + void OnSetFocus( wxFocusEvent &event ); + +private: + wxDataViewCtrl *m_owner; + wxCursor *m_resizeCursor; + +private: + DECLARE_DYNAMIC_CLASS(wxDataViewHeaderWindow) + DECLARE_EVENT_TABLE() +}; + +//----------------------------------------------------------------------------- +// wxDataViewRenameTimer +//----------------------------------------------------------------------------- + +class wxDataViewRenameTimer: public wxTimer +{ +private: + wxDataViewMainWindow *m_owner; + +public: + wxDataViewRenameTimer( wxDataViewMainWindow *owner ); + void Notify(); +}; + +//----------------------------------------------------------------------------- +// wxDataViewTextCtrlWrapper: wraps a wxTextCtrl for inline editing +//----------------------------------------------------------------------------- + +class wxDataViewTextCtrlWrapper : public wxEvtHandler +{ +public: + // NB: text must be a valid object but not Create()d yet + wxDataViewTextCtrlWrapper( wxDataViewMainWindow *owner, + wxTextCtrl *text, + wxDataViewListModel *model, + unsigned int col, unsigned int row, + wxRect cellLabel ); + + wxTextCtrl *GetText() const { return m_text; } + + void AcceptChangesAndFinish(); + +protected: + void OnChar( wxKeyEvent &event ); + void OnKeyUp( wxKeyEvent &event ); + void OnKillFocus( wxFocusEvent &event ); + + bool AcceptChanges(); + void Finish(); + +private: + wxDataViewMainWindow *m_owner; + wxTextCtrl *m_text; + wxString m_startValue; + wxDataViewListModel *m_model; + unsigned int m_col; + unsigned int m_row; + bool m_finished; + bool m_aboutToFinish; + + DECLARE_EVENT_TABLE() +}; + +//----------------------------------------------------------------------------- +// wxDataViewMainWindow +//----------------------------------------------------------------------------- + +WX_DEFINE_SORTED_USER_EXPORTED_ARRAY_SIZE_T(unsigned int, wxDataViewSelection, WXDLLIMPEXP_ADV); + +class wxDataViewMainWindow: public wxWindow +{ +public: + wxDataViewMainWindow( wxDataViewCtrl *parent, + wxWindowID id, + const wxPoint &pos = wxDefaultPosition, + const wxSize &size = wxDefaultSize, + const wxString &name = wxT("wxdataviewctrlmainwindow") ); + virtual ~wxDataViewMainWindow(); + + // notifications from wxDataViewListModel + bool RowAppended(); + bool RowPrepended(); + bool RowInserted( unsigned int before ); + bool RowDeleted( unsigned int row ); + bool RowChanged( unsigned int row ); + bool ValueChanged( unsigned int col, unsigned int row ); + bool RowsReordered( unsigned int *new_order ); + bool Cleared(); + + void SetOwner( wxDataViewCtrl* owner ) { m_owner = owner; } + wxDataViewCtrl *GetOwner() { return m_owner; } + + void OnPaint( wxPaintEvent &event ); + void OnArrowChar(unsigned int newCurrent, const wxKeyEvent& event); + void OnChar( wxKeyEvent &event ); + void OnMouse( wxMouseEvent &event ); + void OnSetFocus( wxFocusEvent &event ); + void OnKillFocus( wxFocusEvent &event ); + + void UpdateDisplay(); + void RecalculateDisplay(); + void OnInternalIdle(); + + void OnRenameTimer(); + void FinishEditing( wxTextCtrl *text ); + + void ScrollWindow( int dx, int dy, const wxRect *rect ); + + bool HasCurrentRow() { return m_currentRow != (unsigned int)-1; } + void ChangeCurrentRow( unsigned int row ); + + bool IsSingleSel() const { return !GetParent()->HasFlag(wxDV_MULTIPLE); } + bool IsEmpty() { return GetRowCount() == 0; } + + int GetCountPerPage(); + int GetEndOfLastCol(); + unsigned int GetFirstVisibleRow(); + unsigned int GetLastVisibleRow(); + unsigned int GetRowCount(); + + void SelectAllRows( bool on ); + void SelectRow( unsigned int row, bool on ); + void SelectRows( unsigned int from, unsigned int to, bool on ); + void ReverseRowSelection( unsigned int row ); + bool IsRowSelected( unsigned int row ); + + void RefreshRow( unsigned int row ); + void RefreshRows( unsigned int from, unsigned int to ); + void RefreshRowsAfter( unsigned int firstRow ); + +private: + wxDataViewCtrl *m_owner; + int m_lineHeight; + bool m_dirty; + + wxDataViewColumn *m_currentCol; + unsigned int m_currentRow; + wxDataViewSelection m_selection; + + wxDataViewRenameTimer *m_renameTimer; + wxDataViewTextCtrlWrapper *m_textctrlWrapper; + bool m_lastOnSame; + + bool m_hasFocus; + + int m_dragCount; + wxPoint m_dragStart; + + // for double click logic + unsigned int m_lineLastClicked, + m_lineBeforeLastClicked, + m_lineSelectSingleOnUp; + +private: + DECLARE_DYNAMIC_CLASS(wxDataViewMainWindow) + DECLARE_EVENT_TABLE() +}; + +// --------------------------------------------------------- +// wxGenericDataViewListModelNotifier +// --------------------------------------------------------- + +class wxGenericDataViewListModelNotifier: public wxDataViewListModelNotifier +{ +public: + wxGenericDataViewListModelNotifier( wxDataViewMainWindow *mainWindow ) + { m_mainWindow = mainWindow; } + + virtual bool RowAppended() + { return m_mainWindow->RowAppended(); } + virtual bool RowPrepended() + { return m_mainWindow->RowPrepended(); } + virtual bool RowInserted( unsigned int before ) + { return m_mainWindow->RowInserted( before ); } + virtual bool RowDeleted( unsigned int row ) + { return m_mainWindow->RowDeleted( row ); } + virtual bool RowChanged( unsigned int row ) + { return m_mainWindow->RowChanged( row ); } + virtual bool ValueChanged( unsigned int col, unsigned int row ) + { return m_mainWindow->ValueChanged( col, row ); } + virtual bool RowsReordered( unsigned int *new_order ) + { return m_mainWindow->RowsReordered( new_order ); } + virtual bool Cleared() + { return m_mainWindow->Cleared(); } + + wxDataViewMainWindow *m_mainWindow; +}; + +// --------------------------------------------------------- +// wxDataViewRenderer +// --------------------------------------------------------- + +IMPLEMENT_ABSTRACT_CLASS(wxDataViewRenderer, wxDataViewRendererBase) + +wxDataViewRenderer::wxDataViewRenderer( const wxString &varianttype, wxDataViewCellMode mode ) : + wxDataViewRendererBase( varianttype, mode ) +{ + m_dc = NULL; +} + +wxDataViewRenderer::~wxDataViewRenderer() +{ + if (m_dc) + delete m_dc; +} + +wxDC *wxDataViewRenderer::GetDC() +{ + if (m_dc == NULL) + { + if (GetOwner() == NULL) + return NULL; + if (GetOwner()->GetOwner() == NULL) + return NULL; + m_dc = new wxClientDC( GetOwner()->GetOwner() ); + } + + return m_dc; +} + +// --------------------------------------------------------- +// wxDataViewCustomRenderer +// --------------------------------------------------------- + +IMPLEMENT_ABSTRACT_CLASS(wxDataViewCustomRenderer, wxDataViewRenderer) + +wxDataViewCustomRenderer::wxDataViewCustomRenderer( const wxString &varianttype, + wxDataViewCellMode mode ) : + wxDataViewRenderer( varianttype, mode ) +{ +} + +// --------------------------------------------------------- +// wxDataViewTextRenderer +// --------------------------------------------------------- + +IMPLEMENT_CLASS(wxDataViewTextRenderer, wxDataViewCustomRenderer) + +wxDataViewTextRenderer::wxDataViewTextRenderer( const wxString &varianttype, wxDataViewCellMode mode ) : + wxDataViewCustomRenderer( varianttype, mode ) +{ +} + +bool wxDataViewTextRenderer::SetValue( const wxVariant &value ) +{ + m_text = value.GetString(); + + return true; +} + +bool wxDataViewTextRenderer::GetValue( wxVariant& WXUNUSED(value) ) +{ + return false; +} + +bool wxDataViewTextRenderer::Render( wxRect cell, wxDC *dc, int WXUNUSED(state) ) +{ + dc->DrawText( m_text, cell.x, cell.y ); + + return true; +} + +wxSize wxDataViewTextRenderer::GetSize() +{ + return wxSize(80,20); +} + +// --------------------------------------------------------- +// wxDataViewBitmapRenderer +// --------------------------------------------------------- + +IMPLEMENT_CLASS(wxDataViewBitmapRenderer, wxDataViewCustomRenderer) + +wxDataViewBitmapRenderer::wxDataViewBitmapRenderer( const wxString &varianttype, wxDataViewCellMode mode ) : + wxDataViewCustomRenderer( varianttype, mode ) +{ +} + +bool wxDataViewBitmapRenderer::SetValue( const wxVariant &value ) +{ + if (value.GetType() == wxT("wxBitmap")) + m_bitmap << value; + if (value.GetType() == wxT("wxIcon")) + m_icon << value; + + return true; +} + +bool wxDataViewBitmapRenderer::GetValue( wxVariant& WXUNUSED(value) ) +{ + return false; +} + +bool wxDataViewBitmapRenderer::Render( wxRect cell, wxDC *dc, int WXUNUSED(state) ) +{ + if (m_bitmap.Ok()) + dc->DrawBitmap( m_bitmap, cell.x, cell.y ); + else if (m_icon.Ok()) + dc->DrawIcon( m_icon, cell.x, cell.y ); + + return true; +} + +wxSize wxDataViewBitmapRenderer::GetSize() +{ + if (m_bitmap.Ok()) + return wxSize( m_bitmap.GetWidth(), m_bitmap.GetHeight() ); + else if (m_icon.Ok()) + return wxSize( m_icon.GetWidth(), m_icon.GetHeight() ); + + return wxSize(16,16); +} + +// --------------------------------------------------------- +// wxDataViewToggleRenderer +// --------------------------------------------------------- + +IMPLEMENT_ABSTRACT_CLASS(wxDataViewToggleRenderer, wxDataViewCustomRenderer) + +wxDataViewToggleRenderer::wxDataViewToggleRenderer( const wxString &varianttype, + wxDataViewCellMode mode ) : + wxDataViewCustomRenderer( varianttype, mode ) +{ + m_toggle = false; +} + +bool wxDataViewToggleRenderer::SetValue( const wxVariant &value ) +{ + m_toggle = value.GetBool(); + + return true; +} + +bool wxDataViewToggleRenderer::GetValue( wxVariant &WXUNUSED(value) ) +{ + return false; +} + +bool wxDataViewToggleRenderer::Render( wxRect cell, wxDC *dc, int WXUNUSED(state) ) +{ + // User wxRenderer here + + wxRect rect; + rect.x = cell.x + cell.width/2 - 10; + rect.width = 20; + rect.y = cell.y + cell.height/2 - 10; + rect.height = 20; + + int flags = 0; + if (m_toggle) + flags |= wxCONTROL_CHECKED; + if (GetMode() != wxDATAVIEW_CELL_ACTIVATABLE) + flags |= wxCONTROL_DISABLED; + + wxRendererNative::Get().DrawCheckBox( + GetOwner()->GetOwner(), + *dc, + rect, + flags ); + + return true; +} + +bool wxDataViewToggleRenderer::Activate( wxRect WXUNUSED(cell), wxDataViewListModel *model, unsigned int col, unsigned int row ) +{ + bool value = !m_toggle; + wxVariant variant = value; + model->SetValue( variant, col, row ); + model->ValueChanged( col, row ); + return true; +} + +wxSize wxDataViewToggleRenderer::GetSize() +{ + return wxSize(20,20); +} + +// --------------------------------------------------------- +// wxDataViewProgressRenderer +// --------------------------------------------------------- + +IMPLEMENT_ABSTRACT_CLASS(wxDataViewProgressRenderer, wxDataViewCustomRenderer) + +wxDataViewProgressRenderer::wxDataViewProgressRenderer( const wxString &label, + const wxString &varianttype, wxDataViewCellMode mode ) : + wxDataViewCustomRenderer( varianttype, mode ) +{ + m_label = label; + m_value = 0; +} + +wxDataViewProgressRenderer::~wxDataViewProgressRenderer() +{ +} + +bool wxDataViewProgressRenderer::SetValue( const wxVariant &value ) +{ + m_value = (long) value; + + if (m_value < 0) m_value = 0; + if (m_value > 100) m_value = 100; + + return true; +} + +bool wxDataViewProgressRenderer::Render( wxRect cell, wxDC *dc, int WXUNUSED(state) ) +{ + double pct = (double)m_value / 100.0; + wxRect bar = cell; + bar.width = (int)(cell.width * pct); + dc->SetPen( *wxTRANSPARENT_PEN ); + dc->SetBrush( *wxBLUE_BRUSH ); + dc->DrawRectangle( bar ); + + dc->SetBrush( *wxTRANSPARENT_BRUSH ); + dc->SetPen( *wxBLACK_PEN ); + dc->DrawRectangle( cell ); + + return true; +} + +wxSize wxDataViewProgressRenderer::GetSize() +{ + return wxSize(40,12); +} + +// --------------------------------------------------------- +// wxDataViewDateRenderer +// --------------------------------------------------------- + +#define wxUSE_DATE_RENDERER_POPUP (wxUSE_CALENDARCTRL && wxUSE_POPUPWIN) + +#if wxUSE_DATE_RENDERER_POPUP + +class wxDataViewDateRendererPopupTransient: public wxPopupTransientWindow +{ +public: + wxDataViewDateRendererPopupTransient( wxWindow* parent, wxDateTime *value, + wxDataViewListModel *model, unsigned int col, unsigned int row ) : + wxPopupTransientWindow( parent, wxBORDER_SIMPLE ) + { + m_model = model; + m_col = col; + m_row = row; + m_cal = new wxCalendarCtrl( this, wxID_ANY, *value ); + wxBoxSizer *sizer = new wxBoxSizer( wxHORIZONTAL ); + sizer->Add( m_cal, 1, wxGROW ); + SetSizer( sizer ); + sizer->Fit( this ); + } + + void OnCalendar( wxCalendarEvent &event ); + + wxCalendarCtrl *m_cal; + wxDataViewListModel *m_model; + unsigned int m_col; + unsigned int m_row; + +protected: + virtual void OnDismiss() + { + } + +private: + DECLARE_EVENT_TABLE() +}; + +BEGIN_EVENT_TABLE(wxDataViewDateRendererPopupTransient,wxPopupTransientWindow) + EVT_CALENDAR( wxID_ANY, wxDataViewDateRendererPopupTransient::OnCalendar ) +END_EVENT_TABLE() + +void wxDataViewDateRendererPopupTransient::OnCalendar( wxCalendarEvent &event ) +{ + wxDateTime date = event.GetDate(); + wxVariant value = date; + m_model->SetValue( value, m_col, m_row ); + m_model->ValueChanged( m_col, m_row ); + DismissAndNotify(); +} + +#endif // wxUSE_DATE_RENDERER_POPUP + +IMPLEMENT_ABSTRACT_CLASS(wxDataViewDateRenderer, wxDataViewCustomRenderer) + +wxDataViewDateRenderer::wxDataViewDateRenderer( const wxString &varianttype, + wxDataViewCellMode mode ) : + wxDataViewCustomRenderer( varianttype, mode ) +{ +} + +bool wxDataViewDateRenderer::SetValue( const wxVariant &value ) +{ + m_date = value.GetDateTime(); + + return true; +} + +bool wxDataViewDateRenderer::Render( wxRect cell, wxDC *dc, int WXUNUSED(state) ) +{ + dc->SetFont( GetOwner()->GetOwner()->GetFont() ); + wxString tmp = m_date.FormatDate(); + dc->DrawText( tmp, cell.x, cell.y ); + + return true; +} + +wxSize wxDataViewDateRenderer::GetSize() +{ + wxDataViewCtrl* view = GetOwner()->GetOwner(); + wxString tmp = m_date.FormatDate(); + wxCoord x,y,d; + view->GetTextExtent( tmp, &x, &y, &d ); + return wxSize(x,y+d); +} + +bool wxDataViewDateRenderer::Activate( wxRect WXUNUSED(cell), wxDataViewListModel *model, unsigned int col, unsigned int row ) +{ + wxVariant variant; + model->GetValue( variant, col, row ); + wxDateTime value = variant.GetDateTime(); + +#if wxUSE_DATE_RENDERER_POPUP + wxDataViewDateRendererPopupTransient *popup = new wxDataViewDateRendererPopupTransient( + GetOwner()->GetOwner()->GetParent(), &value, model, col, row ); + wxPoint pos = wxGetMousePosition(); + popup->Move( pos ); + popup->Layout(); + popup->Popup( popup->m_cal ); +#else // !wxUSE_DATE_RENDERER_POPUP + wxMessageBox(value.Format()); +#endif // wxUSE_DATE_RENDERER_POPUP/!wxUSE_DATE_RENDERER_POPUP + return true; +} + +// --------------------------------------------------------- +// wxDataViewColumn +// --------------------------------------------------------- + +IMPLEMENT_ABSTRACT_CLASS(wxDataViewColumn, wxDataViewColumnBase) + +wxDataViewColumn::wxDataViewColumn( const wxString &title, wxDataViewRenderer *cell, unsigned int model_column, + int width, int flags ) : + wxDataViewColumnBase( title, cell, model_column, width, flags ) +{ + m_width = width; + if (m_width < 0) + m_width = 80; +} + +wxDataViewColumn::wxDataViewColumn( const wxBitmap &bitmap, wxDataViewRenderer *cell, unsigned int model_column, + int width, int flags ) : + wxDataViewColumnBase( bitmap, cell, model_column, width, flags ) +{ + m_width = width; + if (m_width < 0) + m_width = 30; +} + +void wxDataViewColumn::SetAlignment( wxAlignment WXUNUSED(align) ) +{ + // TODO +} + +void wxDataViewColumn::SetSortable( bool WXUNUSED(sortable) ) +{ + // TODO +} + +bool wxDataViewColumn::GetSortable() +{ + // TODO + return false; +} + +void wxDataViewColumn::SetSortOrder( bool WXUNUSED(ascending) ) +{ + // TODO +} + +bool wxDataViewColumn::IsSortOrderAscending() +{ + // TODO + return true; +} + + +wxDataViewColumn::~wxDataViewColumn() +{ +} + +void wxDataViewColumn::SetTitle( const wxString &title ) +{ + wxDataViewColumnBase::SetTitle( title ); + +} + +void wxDataViewColumn::SetBitmap( const wxBitmap &bitmap ) +{ + wxDataViewColumnBase::SetBitmap( bitmap ); + +} + +int wxDataViewColumn::GetWidth() +{ + return m_width; +} + +//----------------------------------------------------------------------------- +// wxDataViewHeaderWindow +//----------------------------------------------------------------------------- + +IMPLEMENT_ABSTRACT_CLASS(wxDataViewHeaderWindow, wxWindow) + +BEGIN_EVENT_TABLE(wxDataViewHeaderWindow,wxWindow) + EVT_PAINT (wxDataViewHeaderWindow::OnPaint) + EVT_MOUSE_EVENTS (wxDataViewHeaderWindow::OnMouse) + EVT_SET_FOCUS (wxDataViewHeaderWindow::OnSetFocus) +END_EVENT_TABLE() + +wxDataViewHeaderWindow::wxDataViewHeaderWindow( wxDataViewCtrl *parent, wxWindowID id, + const wxPoint &pos, const wxSize &size, const wxString &name ) : + wxWindow( parent, id, pos, size, 0, name ) +{ + SetOwner( parent ); + + m_resizeCursor = new wxCursor( wxCURSOR_SIZEWE ); + + wxVisualAttributes attr = wxPanel::GetClassDefaultAttributes(); + SetBackgroundStyle( wxBG_STYLE_CUSTOM ); + SetOwnForegroundColour( attr.colFg ); + SetOwnBackgroundColour( attr.colBg ); + if (!m_hasFont) + SetOwnFont( attr.font ); +} + +wxDataViewHeaderWindow::~wxDataViewHeaderWindow() +{ + delete m_resizeCursor; +} + +void wxDataViewHeaderWindow::OnPaint( wxPaintEvent &WXUNUSED(event) ) +{ + int w, h; + GetClientSize( &w, &h ); + + wxAutoBufferedPaintDC dc( this ); + + dc.SetBackground(GetBackgroundColour()); + dc.Clear(); + + int xpix; + m_owner->GetScrollPixelsPerUnit( &xpix, NULL ); + + int x; + m_owner->GetViewStart( &x, NULL ); + + // account for the horz scrollbar offset + dc.SetDeviceOrigin( -x * xpix, 0 ); + + dc.SetFont( GetFont() ); + + unsigned int cols = GetOwner()->GetNumberOfColumns(); + unsigned int i; + int xpos = 0; + for (i = 0; i < cols; i++) + { + wxDataViewColumn *col = GetOwner()->GetColumn( i ); + int width = col->GetWidth(); + + int cw = width; + int ch = h; + + wxRendererNative::Get().DrawHeaderButton + ( + this, + dc, + wxRect(xpos, 0, cw, ch-1), + m_parent->IsEnabled() ? 0 + : (int)wxCONTROL_DISABLED + ); + + dc.DrawText( col->GetTitle(), xpos+3, 3 ); + + xpos += width; + } +} + +void wxDataViewHeaderWindow::OnMouse( wxMouseEvent &WXUNUSED(event) ) +{ +} + +void wxDataViewHeaderWindow::OnSetFocus( wxFocusEvent &event ) +{ + GetParent()->SetFocus(); + event.Skip(); +} + +//----------------------------------------------------------------------------- +// wxDataViewRenameTimer +//----------------------------------------------------------------------------- + +wxDataViewRenameTimer::wxDataViewRenameTimer( wxDataViewMainWindow *owner ) +{ + m_owner = owner; +} + +void wxDataViewRenameTimer::Notify() +{ + m_owner->OnRenameTimer(); +} + +//----------------------------------------------------------------------------- +// wxDataViewTextCtrlWrapper: wraps a wxTextCtrl for inline editing +//----------------------------------------------------------------------------- + +BEGIN_EVENT_TABLE(wxDataViewTextCtrlWrapper, wxEvtHandler) + EVT_CHAR (wxDataViewTextCtrlWrapper::OnChar) + EVT_KEY_UP (wxDataViewTextCtrlWrapper::OnKeyUp) + EVT_KILL_FOCUS (wxDataViewTextCtrlWrapper::OnKillFocus) +END_EVENT_TABLE() + +wxDataViewTextCtrlWrapper::wxDataViewTextCtrlWrapper( + wxDataViewMainWindow *owner, + wxTextCtrl *text, + wxDataViewListModel *model, + unsigned int col, unsigned int row, + wxRect rectLabel ) +{ + m_owner = owner; + m_model = model; + m_row = row; + m_col = col; + m_text = text; + + m_finished = false; + m_aboutToFinish = false; + + wxVariant value; + model->GetValue( value, col, row ); + m_startValue = value.GetString(); + + m_owner->GetOwner()->CalcScrolledPosition( + rectLabel.x, rectLabel.y, &rectLabel.x, &rectLabel.y ); + + m_text->Create( owner, wxID_ANY, m_startValue, + wxPoint(rectLabel.x-2,rectLabel.y-2), + wxSize(rectLabel.width+7,rectLabel.height+4) ); + m_text->SetFocus(); + + m_text->PushEventHandler(this); +} + +void wxDataViewTextCtrlWrapper::AcceptChangesAndFinish() +{ + m_aboutToFinish = true; + + // Notify the owner about the changes + AcceptChanges(); + + // Even if vetoed, close the control (consistent with MSW) + Finish(); +} + +void wxDataViewTextCtrlWrapper::OnChar( wxKeyEvent &event ) +{ + switch ( event.m_keyCode ) + { + case WXK_RETURN: + AcceptChangesAndFinish(); + break; + + case WXK_ESCAPE: + // m_owner->OnRenameCancelled( m_itemEdited ); + Finish(); + break; + + default: + event.Skip(); + } +} + +void wxDataViewTextCtrlWrapper::OnKeyUp( wxKeyEvent &event ) +{ + if (m_finished) + { + event.Skip(); + return; + } + + // auto-grow the textctrl + wxSize parentSize = m_owner->GetSize(); + wxPoint myPos = m_text->GetPosition(); + wxSize mySize = m_text->GetSize(); + int sx, sy; + m_text->GetTextExtent(m_text->GetValue() + _T("MM"), &sx, &sy); + if (myPos.x + sx > parentSize.x) + sx = parentSize.x - myPos.x; + if (mySize.x > sx) + sx = mySize.x; + m_text->SetSize(sx, wxDefaultCoord); + + event.Skip(); +} + +void wxDataViewTextCtrlWrapper::OnKillFocus( wxFocusEvent &event ) +{ + if ( !m_finished && !m_aboutToFinish ) + { + AcceptChanges(); + //if ( !AcceptChanges() ) + // m_owner->OnRenameCancelled( m_itemEdited ); + + Finish(); + } + + // We must let the native text control handle focus + event.Skip(); +} + +bool wxDataViewTextCtrlWrapper::AcceptChanges() +{ + const wxString value = m_text->GetValue(); + + if ( value == m_startValue ) + // nothing changed, always accept + return true; + +// if ( !m_owner->OnRenameAccept(m_itemEdited, value) ) + // vetoed by the user +// return false; + + // accepted, do rename the item + wxVariant variant; + variant = value; + m_model->SetValue( variant, m_col, m_row ); + m_model->ValueChanged( m_col, m_row ); + + return true; +} + +void wxDataViewTextCtrlWrapper::Finish() +{ + if ( !m_finished ) + { + m_finished = true; + + m_text->RemoveEventHandler(this); + m_owner->FinishEditing(m_text); + + // delete later + wxPendingDelete.Append( this ); + } +} + +//----------------------------------------------------------------------------- +// wxDataViewMainWindow +//----------------------------------------------------------------------------- + +int LINKAGEMODE wxDataViewSelectionCmp( unsigned int row1, unsigned int row2 ) +{ + if (row1 > row2) return 1; + if (row1 == row2) return 0; + return -1; +} + + +IMPLEMENT_ABSTRACT_CLASS(wxDataViewMainWindow, wxWindow) + +BEGIN_EVENT_TABLE(wxDataViewMainWindow,wxWindow) + EVT_PAINT (wxDataViewMainWindow::OnPaint) + EVT_MOUSE_EVENTS (wxDataViewMainWindow::OnMouse) + EVT_SET_FOCUS (wxDataViewMainWindow::OnSetFocus) + EVT_KILL_FOCUS (wxDataViewMainWindow::OnKillFocus) + EVT_CHAR (wxDataViewMainWindow::OnChar) +END_EVENT_TABLE() + +wxDataViewMainWindow::wxDataViewMainWindow( wxDataViewCtrl *parent, wxWindowID id, + const wxPoint &pos, const wxSize &size, const wxString &name ) : + wxWindow( parent, id, pos, size, wxWANTS_CHARS, name ), + m_selection( wxDataViewSelectionCmp ) + +{ + SetOwner( parent ); + + m_lastOnSame = false; + m_renameTimer = new wxDataViewRenameTimer( this ); + m_textctrlWrapper = NULL; + + // TODO: user better initial values/nothing selected + m_currentCol = NULL; + m_currentRow = 0; + + // TODO: we need to calculate this smartly + m_lineHeight = 20; + + m_dragCount = 0; + m_dragStart = wxPoint(0,0); + m_lineLastClicked = (unsigned int) -1; + m_lineBeforeLastClicked = (unsigned int) -1; + m_lineSelectSingleOnUp = (unsigned int) -1; + + m_hasFocus = false; + + SetBackgroundStyle( wxBG_STYLE_CUSTOM ); + SetBackgroundColour( *wxWHITE ); + + UpdateDisplay(); +} + +wxDataViewMainWindow::~wxDataViewMainWindow() +{ + delete m_renameTimer; +} + +void wxDataViewMainWindow::OnRenameTimer() +{ + // We have to call this here because changes may just have + // been made and no screen update taken place. + if ( m_dirty ) + wxSafeYield(); + + + int xpos = 0; + unsigned int cols = GetOwner()->GetNumberOfColumns(); + unsigned int i; + for (i = 0; i < cols; i++) + { + wxDataViewColumn *c = GetOwner()->GetColumn( i ); + if (c == m_currentCol) + break; + xpos += c->GetWidth(); + } + wxRect labelRect( xpos, m_currentRow * m_lineHeight, m_currentCol->GetWidth(), m_lineHeight ); + + wxClassInfo *textControlClass = CLASSINFO(wxTextCtrl); + + wxTextCtrl * const text = (wxTextCtrl *)textControlClass->CreateObject(); + m_textctrlWrapper = new wxDataViewTextCtrlWrapper(this, text, GetOwner()->GetModel(), + m_currentCol->GetModelColumn(), m_currentRow, labelRect ); +} + +void wxDataViewMainWindow::FinishEditing( wxTextCtrl *text ) +{ + delete text; + m_textctrlWrapper = NULL; + SetFocus(); + // SetFocusIgnoringChildren(); +} + +bool wxDataViewMainWindow::RowAppended() +{ + return false; +} + +bool wxDataViewMainWindow::RowPrepended() +{ + return false; +} + +bool wxDataViewMainWindow::RowInserted( unsigned int WXUNUSED(before) ) +{ + return false; +} + +bool wxDataViewMainWindow::RowDeleted( unsigned int WXUNUSED(row) ) +{ + return false; +} + +bool wxDataViewMainWindow::RowChanged( unsigned int WXUNUSED(row) ) +{ + return false; +} + +bool wxDataViewMainWindow::ValueChanged( unsigned int WXUNUSED(col), unsigned int row ) +{ + wxRect rect( 0, row*m_lineHeight, 10000, m_lineHeight ); + m_owner->CalcScrolledPosition( rect.x, rect.y, &rect.x, &rect.y ); + Refresh( true, &rect ); + + return true; +} + +bool wxDataViewMainWindow::RowsReordered( unsigned int *WXUNUSED(new_order) ) +{ + Refresh(); + + return true; +} + +bool wxDataViewMainWindow::Cleared() +{ + return false; +} + +void wxDataViewMainWindow::UpdateDisplay() +{ + m_dirty = true; +} + +void wxDataViewMainWindow::OnInternalIdle() +{ + wxWindow::OnInternalIdle(); + + if (m_dirty) + { + RecalculateDisplay(); + m_dirty = false; + } +} + +void wxDataViewMainWindow::RecalculateDisplay() +{ + wxDataViewListModel *model = GetOwner()->GetModel(); + if (!model) + { + Refresh(); + return; + } + + int width = 0; + unsigned int cols = GetOwner()->GetNumberOfColumns(); + unsigned int i; + for (i = 0; i < cols; i++) + { + wxDataViewColumn *col = GetOwner()->GetColumn( i ); + width += col->GetWidth(); + } + + int height = model->GetNumberOfRows() * m_lineHeight; + + SetVirtualSize( width, height ); + GetOwner()->SetScrollRate( 10, m_lineHeight ); + + Refresh(); +} + +void wxDataViewMainWindow::ScrollWindow( int dx, int dy, const wxRect *rect ) +{ + wxWindow::ScrollWindow( dx, dy, rect ); + GetOwner()->m_headerArea->ScrollWindow( dx, 0 ); +} + +void wxDataViewMainWindow::OnPaint( wxPaintEvent &WXUNUSED(event) ) +{ + wxAutoBufferedPaintDC dc( this ); + + dc.SetBackground(GetBackgroundColour()); + dc.Clear(); + + GetOwner()->PrepareDC( dc ); + + dc.SetFont( GetFont() ); + + wxRect update = GetUpdateRegion().GetBox(); + m_owner->CalcUnscrolledPosition( update.x, update.y, &update.x, &update.y ); + + wxDataViewListModel *model = GetOwner()->GetModel(); + + unsigned int item_start = wxMax( 0, (update.y / m_lineHeight) ); + unsigned int item_count = wxMin( (int)(((update.y + update.height) / m_lineHeight) - item_start + 1), + (int)(model->GetNumberOfRows()-item_start) ); + + + + unsigned int item; + for (item = item_start; item < item_start+item_count; item++) + { + if (m_selection.Index( item ) != wxNOT_FOUND) + { + int flags = wxCONTROL_SELECTED; + if (item == m_currentRow) + flags |= wxCONTROL_CURRENT; + if (m_hasFocus) + flags |= wxCONTROL_FOCUSED; + wxRect rect( 0, item*m_lineHeight+1, GetEndOfLastCol(), m_lineHeight-2 ); + wxRendererNative::Get().DrawItemSelectionRect + ( + this, + dc, + rect, + flags + ); + } + else + { + if (item == m_currentRow) + { + int flags = wxCONTROL_CURRENT; + if (m_hasFocus) + flags |= wxCONTROL_FOCUSED; // should have no effect + wxRect rect( 0, item*m_lineHeight+1, GetEndOfLastCol(), m_lineHeight-2 ); + wxRendererNative::Get().DrawItemSelectionRect + ( + this, + dc, + rect, + flags + ); + + } + } + } + + wxRect cell_rect; + cell_rect.x = 0; + cell_rect.height = m_lineHeight; + unsigned int cols = GetOwner()->GetNumberOfColumns(); + unsigned int i; + for (i = 0; i < cols; i++) + { + wxDataViewColumn *col = GetOwner()->GetColumn( i ); + wxDataViewRenderer *cell = col->GetRenderer(); + cell_rect.width = col->GetWidth(); + + for (item = item_start; item < item_start+item_count; item++) + { + cell_rect.y = item*m_lineHeight; + wxVariant value; + model->GetValue( value, col->GetModelColumn(), item ); + cell->SetValue( value ); + wxSize size = cell->GetSize(); + // cannot be bigger than allocated space + size.x = wxMin( size.x, cell_rect.width ); + size.y = wxMin( size.y, cell_rect.height ); + // TODO: check for left/right/centre alignment here + wxRect item_rect; + // for now: centre + item_rect.x = cell_rect.x + (cell_rect.width / 2) - (size.x / 2); + item_rect.y = cell_rect.y + (cell_rect.height / 2) - (size.y / 2); + + item_rect.width = size.x; + item_rect.height= size.y; + + int state = 0; + if (item == m_currentRow) + state |= wxDATAVIEW_CELL_SELECTED; + cell->Render( item_rect, &dc, state ); + } + + cell_rect.x += cell_rect.width; + } +} + +int wxDataViewMainWindow::GetCountPerPage() +{ + wxSize size = GetClientSize(); + return size.y / m_lineHeight; +} + +int wxDataViewMainWindow::GetEndOfLastCol() +{ + int width = 0; + unsigned int i; + for (i = 0; i < GetOwner()->GetNumberOfColumns(); i++) + { + wxDataViewColumn *c = GetOwner()->GetColumn( i ); + width += c->GetWidth(); + } + return width; +} + +unsigned int wxDataViewMainWindow::GetFirstVisibleRow() +{ + int x = 0; + int y = 0; + m_owner->CalcUnscrolledPosition( x, y, &x, &y ); + + return y / m_lineHeight; +} + +unsigned int wxDataViewMainWindow::GetLastVisibleRow() +{ + wxSize client_size = GetClientSize(); + m_owner->CalcUnscrolledPosition( client_size.x, client_size.y, &client_size.x, &client_size.y ); + + return wxMin( GetRowCount()-1, ((unsigned)client_size.y/m_lineHeight)+1 ); +} + +unsigned int wxDataViewMainWindow::GetRowCount() +{ + return GetOwner()->GetModel()->GetNumberOfRows(); +} + +void wxDataViewMainWindow::ChangeCurrentRow( unsigned int row ) +{ + m_currentRow = row; + + // send event +} + +void wxDataViewMainWindow::SelectAllRows( bool on ) +{ + if (IsEmpty()) + return; + + if (on) + { + m_selection.Clear(); + for (unsigned int i = 0; i < GetRowCount(); i++) + m_selection.Add( i ); + Refresh(); + } + else + { + unsigned int first_visible = GetFirstVisibleRow(); + unsigned int last_visible = GetLastVisibleRow(); + unsigned int i; + for (i = 0; i < m_selection.GetCount(); i++) + { + unsigned int row = m_selection[i]; + if ((row >= first_visible) && (row <= last_visible)) + RefreshRow( row ); + } + m_selection.Clear(); + } +} + +void wxDataViewMainWindow::SelectRow( unsigned int row, bool on ) +{ + if (m_selection.Index( row ) == wxNOT_FOUND) + { + if (on) + { + m_selection.Add( row ); + RefreshRow( row ); + } + } + else + { + if (!on) + { + m_selection.Remove( row ); + RefreshRow( row ); + } + } +} + +void wxDataViewMainWindow::SelectRows( unsigned int from, unsigned int to, bool on ) +{ + if (from > to) + { + unsigned int tmp = from; + from = to; + to = tmp; + } + + unsigned int i; + for (i = from; i <= to; i++) + { + if (m_selection.Index( i ) == wxNOT_FOUND) + { + if (on) + m_selection.Add( i ); + } + else + { + if (!on) + m_selection.Remove( i ); + } + } + RefreshRows( from, to ); +} + +void wxDataViewMainWindow::ReverseRowSelection( unsigned int row ) +{ + if (m_selection.Index( row ) == wxNOT_FOUND) + m_selection.Add( row ); + else + m_selection.Remove( row ); + RefreshRow( row ); +} + +bool wxDataViewMainWindow::IsRowSelected( unsigned int row ) +{ + return (m_selection.Index( row ) != wxNOT_FOUND); +} + +void wxDataViewMainWindow::RefreshRow( unsigned int row ) +{ + wxRect rect( 0, row*m_lineHeight, GetEndOfLastCol(), m_lineHeight ); + m_owner->CalcScrolledPosition( rect.x, rect.y, &rect.x, &rect.y ); + + wxSize client_size = GetClientSize(); + wxRect client_rect( 0, 0, client_size.x, client_size.y ); + wxRect intersect_rect = client_rect.Intersect( rect ); + if (intersect_rect.width > 0) + Refresh( true, &intersect_rect ); +} + +void wxDataViewMainWindow::RefreshRows( unsigned int from, unsigned int to ) +{ + if (from > to) + { + unsigned int tmp = to; + to = from; + from = tmp; + } + + wxRect rect( 0, from*m_lineHeight, GetEndOfLastCol(), (to-from+1) * m_lineHeight ); + m_owner->CalcScrolledPosition( rect.x, rect.y, &rect.x, &rect.y ); + + wxSize client_size = GetClientSize(); + wxRect client_rect( 0, 0, client_size.x, client_size.y ); + wxRect intersect_rect = client_rect.Intersect( rect ); + if (intersect_rect.width > 0) + Refresh( true, &intersect_rect ); +} + +void wxDataViewMainWindow::RefreshRowsAfter( unsigned int firstRow ) +{ + unsigned int count = GetRowCount(); + if (firstRow > count) + return; + + wxRect rect( 0, firstRow*m_lineHeight, GetEndOfLastCol(), count * m_lineHeight ); + m_owner->CalcScrolledPosition( rect.x, rect.y, &rect.x, &rect.y ); + + wxSize client_size = GetClientSize(); + wxRect client_rect( 0, 0, client_size.x, client_size.y ); + wxRect intersect_rect = client_rect.Intersect( rect ); + if (intersect_rect.width > 0) + Refresh( true, &intersect_rect ); +} + +void wxDataViewMainWindow::OnArrowChar(unsigned int newCurrent, const wxKeyEvent& event) +{ + wxCHECK_RET( newCurrent < GetRowCount(), + _T("invalid item index in OnArrowChar()") ); + + // if there is no selection, we cannot move it anywhere + if (!HasCurrentRow()) + return; + + unsigned int oldCurrent = m_currentRow; + + // in single selection we just ignore Shift as we can't select several + // items anyhow + if ( event.ShiftDown() && !IsSingleSel() ) + { + RefreshRow( oldCurrent ); + + ChangeCurrentRow( newCurrent ); + + // select all the items between the old and the new one + if ( oldCurrent > newCurrent ) + { + newCurrent = oldCurrent; + oldCurrent = m_currentRow; + } + + SelectRows( oldCurrent, newCurrent, true ); + } + else // !shift + { + RefreshRow( oldCurrent ); + + // all previously selected items are unselected unless ctrl is held + if ( !event.ControlDown() ) + SelectAllRows(false); + + ChangeCurrentRow( newCurrent ); + + if ( !event.ControlDown() ) + SelectRow( m_currentRow, true ); + else + RefreshRow( m_currentRow ); + } + + // MoveToFocus(); +} + +void wxDataViewMainWindow::OnChar( wxKeyEvent &event ) +{ + if (event.GetKeyCode() == WXK_TAB) + { + wxNavigationKeyEvent nevent; + nevent.SetWindowChange( event.ControlDown() ); + nevent.SetDirection( !event.ShiftDown() ); + nevent.SetEventObject( GetParent()->GetParent() ); + nevent.SetCurrentFocus( m_parent ); + if (GetParent()->GetParent()->GetEventHandler()->ProcessEvent( nevent )) + return; + } + + // no item -> nothing to do + if (!HasCurrentRow()) + { + event.Skip(); + return; + } + + // don't use m_linesPerPage directly as it might not be computed yet + const int pageSize = GetCountPerPage(); + wxCHECK_RET( pageSize, _T("should have non zero page size") ); + + switch ( event.GetKeyCode() ) + { + case WXK_UP: + if ( m_currentRow > 0 ) + OnArrowChar( m_currentRow - 1, event ); + break; + + case WXK_DOWN: + if ( m_currentRow < GetRowCount() - 1 ) + OnArrowChar( m_currentRow + 1, event ); + break; + + case WXK_END: + if (!IsEmpty()) + OnArrowChar( GetRowCount() - 1, event ); + break; + + case WXK_HOME: + if (!IsEmpty()) + OnArrowChar( 0, event ); + break; + + case WXK_PAGEUP: + { + int steps = pageSize - 1; + int index = m_currentRow - steps; + if (index < 0) + index = 0; + + OnArrowChar( index, event ); + } + break; + + case WXK_PAGEDOWN: + { + int steps = pageSize - 1; + unsigned int index = m_currentRow + steps; + unsigned int count = GetRowCount(); + if ( index >= count ) + index = count - 1; + + OnArrowChar( index, event ); + } + break; + + default: + event.Skip(); + } +} + +void wxDataViewMainWindow::OnMouse( wxMouseEvent &event ) +{ + if (event.GetEventType() == wxEVT_MOUSEWHEEL) + { + // let the base handle mouse wheel events. + event.Skip(); + return; + } + + int x = event.GetX(); + int y = event.GetY(); + m_owner->CalcUnscrolledPosition( x, y, &x, &y ); + + wxDataViewColumn *col = NULL; + + int xpos = 0; + unsigned int cols = GetOwner()->GetNumberOfColumns(); + unsigned int i; + for (i = 0; i < cols; i++) + { + wxDataViewColumn *c = GetOwner()->GetColumn( i ); + if (x < xpos + c->GetWidth()) + { + col = c; + break; + } + xpos += c->GetWidth(); + } + if (!col) + return; + wxDataViewRenderer *cell = col->GetRenderer(); + + unsigned int current = y / m_lineHeight; + + if ((current > GetRowCount()) || (x > GetEndOfLastCol())) + { + // Unselect all if below the last row ? + return; + } + + wxDataViewListModel *model = GetOwner()->GetModel(); + + if (event.Dragging()) + { + if (m_dragCount == 0) + { + // we have to report the raw, physical coords as we want to be + // able to call HitTest(event.m_pointDrag) from the user code to + // get the item being dragged + m_dragStart = event.GetPosition(); + } + + m_dragCount++; + + if (m_dragCount != 3) + return; + + if (event.LeftIsDown()) + { + // Notify cell about drag + } + return; + } + else + { + m_dragCount = 0; + } + + bool forceClick = false; + + if (event.ButtonDClick()) + { + m_renameTimer->Stop(); + m_lastOnSame = false; + } + + if (event.LeftDClick()) + { + if ( current == m_lineLastClicked ) + { + if (cell->GetMode() == wxDATAVIEW_CELL_ACTIVATABLE) + { + wxVariant value; + model->GetValue( value, col->GetModelColumn(), current ); + cell->SetValue( value ); + wxRect cell_rect( xpos, current * m_lineHeight, col->GetWidth(), m_lineHeight ); + cell->Activate( cell_rect, model, col->GetModelColumn(), current ); + } + return; + } + else + { + // The first click was on another item, so don't interpret this as + // a double click, but as a simple click instead + forceClick = true; + } + } + + if (event.LeftUp()) + { + if (m_lineSelectSingleOnUp != (unsigned int)-1) + { + // select single line + SelectAllRows( false ); + SelectRow( m_lineSelectSingleOnUp, true ); + } + + if (m_lastOnSame) + { + if ((col == m_currentCol) && (current == m_currentRow) && + (cell->GetMode() == wxDATAVIEW_CELL_EDITABLE) ) + { + m_renameTimer->Start( 100, true ); + } + } + + m_lastOnSame = false; + m_lineSelectSingleOnUp = (unsigned int)-1; + } + else + { + // This is necessary, because after a DnD operation in + // from and to ourself, the up event is swallowed by the + // DnD code. So on next non-up event (which means here and + // now) m_lineSelectSingleOnUp should be reset. + m_lineSelectSingleOnUp = (unsigned int)-1; + } + + if (event.RightDown()) + { + m_lineBeforeLastClicked = m_lineLastClicked; + m_lineLastClicked = current; + + // If the item is already selected, do not update the selection. + // Multi-selections should not be cleared if a selected item is clicked. + if (!IsRowSelected(current)) + { + SelectAllRows(false); + ChangeCurrentRow(current); + SelectRow(m_currentRow,true); + } + + // notify cell about right click + // cell->... + + // Allow generation of context menu event + event.Skip(); + } + else if (event.MiddleDown()) + { + // notify cell about middle click + // cell->... + } + if (event.LeftDown() || forceClick) + { +#ifdef __WXMSW__ + SetFocus(); +#endif + + m_lineBeforeLastClicked = m_lineLastClicked; + m_lineLastClicked = current; + + unsigned int oldCurrentRow = m_currentRow; + bool oldWasSelected = IsRowSelected(m_currentRow); + + bool cmdModifierDown = event.CmdDown(); + if ( IsSingleSel() || !(cmdModifierDown || event.ShiftDown()) ) + { + if ( IsSingleSel() || !IsRowSelected(current) ) + { + SelectAllRows( false ); + + ChangeCurrentRow(current); + + SelectRow(m_currentRow,true); + } + else // multi sel & current is highlighted & no mod keys + { + m_lineSelectSingleOnUp = current; + ChangeCurrentRow(current); // change focus + } + } + else // multi sel & either ctrl or shift is down + { + if (cmdModifierDown) + { + ChangeCurrentRow(current); + + ReverseRowSelection(m_currentRow); + } + else if (event.ShiftDown()) + { + ChangeCurrentRow(current); + + unsigned int lineFrom = oldCurrentRow, + lineTo = current; + + if ( lineTo < lineFrom ) + { + lineTo = lineFrom; + lineFrom = m_currentRow; + } + + SelectRows(lineFrom, lineTo, true); + } + else // !ctrl, !shift + { + // test in the enclosing if should make it impossible + wxFAIL_MSG( _T("how did we get here?") ); + } + } + + if (m_currentRow != oldCurrentRow) + RefreshRow( oldCurrentRow ); + + wxDataViewColumn *oldCurrentCol = m_currentCol; + + // Update selection here... + m_currentCol = col; + + m_lastOnSame = !forceClick && ((col == oldCurrentCol) && (current == oldCurrentRow)) && oldWasSelected; + } +} + +void wxDataViewMainWindow::OnSetFocus( wxFocusEvent &event ) +{ + m_hasFocus = true; + + if (HasCurrentRow()) + Refresh(); + + event.Skip(); +} + +void wxDataViewMainWindow::OnKillFocus( wxFocusEvent &event ) +{ + m_hasFocus = false; + + if (HasCurrentRow()) + Refresh(); + + event.Skip(); +} + +//----------------------------------------------------------------------------- +// wxDataViewCtrl +//----------------------------------------------------------------------------- + +IMPLEMENT_DYNAMIC_CLASS(wxDataViewCtrl, wxDataViewCtrlBase) + +BEGIN_EVENT_TABLE(wxDataViewCtrl, wxDataViewCtrlBase) + EVT_SIZE(wxDataViewCtrl::OnSize) +END_EVENT_TABLE() + +wxDataViewCtrl::~wxDataViewCtrl() +{ + if (m_notifier) + GetModel()->RemoveNotifier( m_notifier ); +} + +void wxDataViewCtrl::Init() +{ + m_notifier = NULL; +} + +bool wxDataViewCtrl::Create(wxWindow *parent, wxWindowID id, + const wxPoint& pos, const wxSize& size, + long style, const wxValidator& validator ) +{ + if (!wxControl::Create( parent, id, pos, size, style | wxScrolledWindowStyle|wxSUNKEN_BORDER, validator)) + return false; + + Init(); + +#ifdef __WXMAC__ + MacSetClipChildren( true ) ; +#endif + + m_clientArea = new wxDataViewMainWindow( this, wxID_ANY ); +#ifdef __WXMSW__ + m_headerArea = new wxDataViewHeaderWindow( this, wxID_ANY, wxDefaultPosition, wxSize(wxDefaultCoord,22) ); +#else + m_headerArea = new wxDataViewHeaderWindow( this, wxID_ANY, wxDefaultPosition, wxSize(wxDefaultCoord,25) ); +#endif + + SetTargetWindow( m_clientArea ); + + wxBoxSizer *sizer = new wxBoxSizer( wxVERTICAL ); + sizer->Add( m_headerArea, 0, wxGROW ); + sizer->Add( m_clientArea, 1, wxGROW ); + SetSizer( sizer ); + + return true; +} + +#ifdef __WXMSW__ +WXLRESULT wxDataViewCtrl::MSWWindowProc(WXUINT nMsg, + WXWPARAM wParam, + WXLPARAM lParam) +{ + WXLRESULT rc = wxDataViewCtrlBase::MSWWindowProc(nMsg, wParam, lParam); + +#ifndef __WXWINCE__ + // we need to process arrows ourselves for scrolling + if ( nMsg == WM_GETDLGCODE ) + { + rc |= DLGC_WANTARROWS; + } +#endif + + return rc; +} +#endif + +void wxDataViewCtrl::OnSize( wxSizeEvent &WXUNUSED(event) ) +{ + // We need to override OnSize so that our scrolled + // window a) does call Layout() to use sizers for + // positioning the controls but b) does not query + // the sizer for their size and use that for setting + // the scrollable area as set that ourselves by + // calling SetScrollbar() further down. + + Layout(); + + AdjustScrollbars(); +} + +bool wxDataViewCtrl::AssociateModel( wxDataViewListModel *model ) +{ + if (!wxDataViewCtrlBase::AssociateModel( model )) + return false; + + m_notifier = new wxGenericDataViewListModelNotifier( m_clientArea ); + + model->AddNotifier( m_notifier ); + + m_clientArea->UpdateDisplay(); + + return true; +} + +bool wxDataViewCtrl::AppendColumn( wxDataViewColumn *col ) +{ + if (!wxDataViewCtrlBase::AppendColumn(col)) + return false; + + m_clientArea->UpdateDisplay(); + + return true; +} + +void wxDataViewCtrl::SetSelection( int WXUNUSED(row) ) +{ + // FIXME - TODO +} + +void wxDataViewCtrl::SetSelectionRange( unsigned int WXUNUSED(from), unsigned int WXUNUSED(to) ) +{ + // FIXME - TODO +} + +void wxDataViewCtrl::SetSelections( const wxArrayInt& WXUNUSED(aSelections) ) +{ + // FIXME - TODO +} + +void wxDataViewCtrl::Unselect( unsigned int WXUNUSED(row) ) +{ + // FIXME - TODO +} + +bool wxDataViewCtrl::IsSelected( unsigned int WXUNUSED(row) ) const +{ + // FIXME - TODO + + return false; +} + +int wxDataViewCtrl::GetSelection() const +{ + // FIXME - TODO + + return -1; +} + +int wxDataViewCtrl::GetSelections(wxArrayInt& WXUNUSED(aSelections) ) const +{ + // FIXME - TODO + + return 0; +} + +#endif + // !wxUSE_GENERICDATAVIEWCTRL + +#endif + // wxUSE_DATAVIEWCTRL diff --git a/Externals/wxWidgets/src/generic/datectlg.cpp b/Externals/wxWidgets/src/generic/datectlg.cpp index 11e45b677e..bf79d89085 100644 --- a/Externals/wxWidgets/src/generic/datectlg.cpp +++ b/Externals/wxWidgets/src/generic/datectlg.cpp @@ -1,538 +1,538 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/generic/datectlg.cpp -// Purpose: generic wxDatePickerCtrlGeneric implementation -// Author: Andreas Pflug -// Modified by: -// Created: 2005-01-19 -// RCS-ID: $Id: datectlg.cpp 53510 2008-05-09 22:15:55Z RD $ -// Copyright: (c) 2005 Andreas Pflug -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_DATEPICKCTRL - -#include "wx/datectrl.h" - -// use this version if we're explicitly requested to do it or if it's the only -// one we have -#if !defined(wxHAS_NATIVE_DATEPICKCTRL) || \ - (defined(wxUSE_DATEPICKCTRL_GENERIC) && wxUSE_DATEPICKCTRL_GENERIC) - -#ifndef WX_PRECOMP - #include "wx/dialog.h" - #include "wx/dcmemory.h" - #include "wx/panel.h" - #include "wx/textctrl.h" - #include "wx/valtext.h" -#endif - -#ifdef wxHAS_NATIVE_DATEPICKCTRL - // this header is not included from wx/datectrl.h if we have a native - // version, but we do need it here - #include "wx/generic/datectrl.h" -#else - // we need to define _WX_DEFINE_DATE_EVENTS_ before including wx/dateevt.h to - // define the event types we use if we're the only date picker control version - // being compiled -- otherwise it's defined in the native version implementation - #define _WX_DEFINE_DATE_EVENTS_ -#endif - -#include "wx/dateevt.h" - -#include "wx/calctrl.h" -#include "wx/combo.h" - -// ---------------------------------------------------------------------------- -// constants -// ---------------------------------------------------------------------------- - -#if defined(__WXMSW__) - #define CALBORDER 0 -#else - #define CALBORDER 4 -#endif - -// ---------------------------------------------------------------------------- -// global variables -// ---------------------------------------------------------------------------- - - -// ---------------------------------------------------------------------------- -// local classes -// ---------------------------------------------------------------------------- - -class wxCalendarComboPopup : public wxCalendarCtrl, - public wxComboPopup -{ -public: - - wxCalendarComboPopup() : wxCalendarCtrl(), - wxComboPopup() - { - } - - virtual void Init() - { - } - - // NB: Don't create lazily since it didn't work that way before - // wxComboCtrl was used, and changing behaviour would almost - // certainly introduce new bugs. - virtual bool Create(wxWindow* parent) - { - if ( !wxCalendarCtrl::Create(parent, wxID_ANY, wxDefaultDateTime, - wxPoint(0, 0), wxDefaultSize, - wxCAL_SHOW_HOLIDAYS | wxBORDER_SUNKEN) ) - return false; - - wxWindow *yearControl = wxCalendarCtrl::GetYearControl(); - - wxClientDC dc(yearControl); - dc.SetFont(yearControl->GetFont()); - wxCoord width, dummy; - dc.GetTextExtent(wxT("2000"), &width, &dummy); - width += ConvertDialogToPixels(wxSize(20, 0)).x; - - wxSize calSize = wxCalendarCtrl::GetBestSize(); - wxSize yearSize = yearControl->GetSize(); - yearSize.x = width; - - wxPoint yearPosition = yearControl->GetPosition(); - - SetFormat(wxT("%x")); - - width = yearPosition.x + yearSize.x+2+CALBORDER/2; - if (width < calSize.x-4) - width = calSize.x-4; - - int calPos = (width-calSize.x)/2; - if (calPos == -1) - { - calPos = 0; - width += 2; - } - wxCalendarCtrl::SetSize(calPos, 0, calSize.x, calSize.y); - yearControl->SetSize(width-yearSize.x-CALBORDER/2, yearPosition.y, - yearSize.x, yearSize.y); - wxCalendarCtrl::GetMonthControl()->Move(0, 0); - - m_useSize.x = width+CALBORDER/2; - m_useSize.y = calSize.y-2+CALBORDER; - - wxWindow* tx = m_combo->GetTextCtrl(); - if ( !tx ) - tx = m_combo; - - tx->Connect(wxEVT_KILL_FOCUS, - wxFocusEventHandler(wxCalendarComboPopup::OnKillTextFocus), - NULL, this); - - return true; - } - - virtual wxSize GetAdjustedSize(int WXUNUSED(minWidth), - int WXUNUSED(prefHeight), - int WXUNUSED(maxHeight)) - { - return m_useSize; - } - - virtual wxWindow *GetControl() { return this; } - - void SetDateValue(const wxDateTime& date) - { - if ( date.IsValid() ) - { - m_combo->SetText(date.Format(m_format)); - SetDate(date); - } - else // invalid date - { - wxASSERT_MSG( HasDPFlag(wxDP_ALLOWNONE), - _T("this control must have a valid date") ); - - m_combo->SetText(wxEmptyString); - } - } - - bool ParseDateTime(const wxString& s, wxDateTime* pDt) - { - wxASSERT(pDt); - - if ( !s.empty() ) - { - pDt->ParseFormat(s, m_format); - if ( !pDt->IsValid() ) - return false; - } - - return true; - } - - void SendDateEvent(const wxDateTime& dt) - { - // - // Sends both wxCalendarEvent and wxDateEvent - wxWindow* datePicker = m_combo->GetParent(); - - wxCalendarEvent cev((wxCalendarCtrl*) this, wxEVT_CALENDAR_SEL_CHANGED); - cev.SetEventObject(datePicker); - cev.SetId(datePicker->GetId()); - cev.SetDate(dt); - datePicker->GetEventHandler()->ProcessEvent(cev); - - wxDateEvent event(datePicker, dt, wxEVT_DATE_CHANGED); - datePicker->GetEventHandler()->ProcessEvent(event); - } - -private: - - void OnCalKey(wxKeyEvent & ev) - { - if (ev.GetKeyCode() == WXK_ESCAPE && !ev.HasModifiers()) - Dismiss(); - else - ev.Skip(); - } - - void OnSelChange(wxCalendarEvent &ev) - { - m_combo->SetText(GetDate().Format(m_format)); - - if ( ev.GetEventType() == wxEVT_CALENDAR_DOUBLECLICKED ) - { - Dismiss(); - } - - SendDateEvent(GetDate()); - } - - void OnKillTextFocus(wxFocusEvent &ev) - { - ev.Skip(); - - const wxDateTime& dtOld = GetDate(); - - wxDateTime dt; - wxString value = m_combo->GetValue(); - if ( !ParseDateTime(value, &dt) ) - { - if ( !HasDPFlag(wxDP_ALLOWNONE) ) - dt = dtOld; - } - - m_combo->SetText(GetStringValueFor(dt)); - - if ( !dt.IsValid() && HasDPFlag(wxDP_ALLOWNONE) ) - return; - - // notify that we had to change the date after validation - if ( (dt.IsValid() && (!dtOld.IsValid() || dt != dtOld)) || - (!dt.IsValid() && dtOld.IsValid()) ) - { - SetDate(dt); - SendDateEvent(dt); - } - } - - bool HasDPFlag(int flag) - { - return m_combo->GetParent()->HasFlag(flag); - } - - bool SetFormat(const wxChar *fmt) - { - m_format.clear(); - - wxDateTime dt; - dt.ParseFormat(wxT("2003-10-13"), wxT("%Y-%m-%d")); - wxString str(dt.Format(fmt)); - - const wxChar *p = str.c_str(); - while ( *p ) - { - int n=wxAtoi(p); - if (n == dt.GetDay()) - { - m_format.Append(wxT("%d")); - p += 2; - } - else if (n == (int)dt.GetMonth()+1) - { - m_format.Append(wxT("%m")); - p += 2; - } - else if (n == dt.GetYear()) - { - m_format.Append(wxT("%Y")); - p += 4; - } - else if (n == (dt.GetYear() % 100)) - { - if ( HasDPFlag(wxDP_SHOWCENTURY) ) - m_format.Append(wxT("%Y")); - else - m_format.Append(wxT("%y")); - p += 2; - } - else - m_format.Append(*p++); - } - - if ( m_combo ) - { - wxArrayString allowedChars; - for ( wxChar c = _T('0'); c <= _T('9'); c++ ) - allowedChars.Add(wxString(c, 1)); - - const wxChar *p2 = m_format.c_str(); - while ( *p2 ) - { - if ( *p2 == '%') - p2 += 2; - else - allowedChars.Add(wxString(*p2++, 1)); - } - - #if wxUSE_VALIDATORS - wxTextValidator tv(wxFILTER_INCLUDE_CHAR_LIST); - tv.SetIncludes(allowedChars); - m_combo->SetValidator(tv); - #endif - - if ( GetDate().IsValid() ) - m_combo->SetText(GetDate().Format(m_format)); - } - - return true; - } - - virtual void SetStringValue(const wxString& s) - { - wxDateTime dt; - if ( !s.empty() && ParseDateTime(s, &dt) ) - SetDate(dt); - //else: keep the old value - } - - virtual wxString GetStringValue() const - { - return GetStringValueFor(GetDate()); - } - -private: - // returns either the given date representation using the current format or - // an empty string if it's invalid - wxString GetStringValueFor(const wxDateTime& dt) const - { - wxString val; - if ( dt.IsValid() ) - val = dt.Format(m_format); - - return val; - } - - wxSize m_useSize; - wxString m_format; - - DECLARE_EVENT_TABLE() -}; - - -BEGIN_EVENT_TABLE(wxCalendarComboPopup, wxCalendarCtrl) - EVT_KEY_DOWN(wxCalendarComboPopup::OnCalKey) - EVT_CALENDAR_SEL_CHANGED(wxID_ANY, wxCalendarComboPopup::OnSelChange) - EVT_CALENDAR_DAY(wxID_ANY, wxCalendarComboPopup::OnSelChange) - EVT_CALENDAR_MONTH(wxID_ANY, wxCalendarComboPopup::OnSelChange) - EVT_CALENDAR_YEAR(wxID_ANY, wxCalendarComboPopup::OnSelChange) - EVT_CALENDAR(wxID_ANY, wxCalendarComboPopup::OnSelChange) -END_EVENT_TABLE() - - -// ============================================================================ -// wxDatePickerCtrlGeneric implementation -// ============================================================================ - -BEGIN_EVENT_TABLE(wxDatePickerCtrlGeneric, wxDatePickerCtrlBase) - EVT_TEXT(wxID_ANY, wxDatePickerCtrlGeneric::OnText) - EVT_SIZE(wxDatePickerCtrlGeneric::OnSize) - EVT_SET_FOCUS(wxDatePickerCtrlGeneric::OnFocus) -END_EVENT_TABLE() - -#ifndef wxHAS_NATIVE_DATEPICKCTRL - IMPLEMENT_DYNAMIC_CLASS(wxDatePickerCtrl, wxControl) -#endif - -// ---------------------------------------------------------------------------- -// creation -// ---------------------------------------------------------------------------- - -bool wxDatePickerCtrlGeneric::Create(wxWindow *parent, - wxWindowID id, - const wxDateTime& date, - const wxPoint& pos, - const wxSize& size, - long style, - const wxValidator& validator, - const wxString& name) -{ - wxASSERT_MSG( !(style & wxDP_SPIN), - _T("wxDP_SPIN style not supported, use wxDP_DEFAULT") ); - - if ( !wxControl::Create(parent, id, pos, size, - style | wxCLIP_CHILDREN | wxWANTS_CHARS | wxBORDER_NONE, - validator, name) ) - { - return false; - } - - InheritAttributes(); - - m_combo = new wxComboCtrl(this, -1, wxEmptyString, - wxDefaultPosition, wxDefaultSize); - - m_combo->SetCtrlMainWnd(this); - - m_popup = new wxCalendarComboPopup(); - m_cal = m_popup; - -#if defined(__WXMSW__) - // without this keyboard navigation in month control doesn't work - m_combo->UseAltPopupWindow(); -#endif - m_combo->SetPopupControl(m_popup); - - m_popup->SetDateValue(date.IsValid() ? date : wxDateTime::Today()); - - SetInitialSize(size); - - return true; -} - - -void wxDatePickerCtrlGeneric::Init() -{ - m_combo = NULL; - m_popup = NULL; - m_cal = NULL; -} - -wxDatePickerCtrlGeneric::~wxDatePickerCtrlGeneric() -{ -} - -bool wxDatePickerCtrlGeneric::Destroy() -{ - if ( m_combo ) - m_combo->Destroy(); - - m_combo = NULL; - m_popup = NULL; - m_cal = NULL; - - return wxControl::Destroy(); -} - -// ---------------------------------------------------------------------------- -// overridden base class methods -// ---------------------------------------------------------------------------- - -wxSize wxDatePickerCtrlGeneric::DoGetBestSize() const -{ - return m_combo->GetBestSize(); -} - -// ---------------------------------------------------------------------------- -// wxDatePickerCtrlGeneric API -// ---------------------------------------------------------------------------- - -bool -wxDatePickerCtrlGeneric::SetDateRange(const wxDateTime& lowerdate, - const wxDateTime& upperdate) -{ - return m_popup->SetDateRange(lowerdate, upperdate); -} - - -wxDateTime wxDatePickerCtrlGeneric::GetValue() const -{ - return m_popup->GetDate(); -} - - -void wxDatePickerCtrlGeneric::SetValue(const wxDateTime& date) -{ - m_popup->SetDateValue(date); -} - - -bool wxDatePickerCtrlGeneric::GetRange(wxDateTime *dt1, wxDateTime *dt2) const -{ - if (dt1) - *dt1 = m_popup->GetLowerDateLimit(); - if (dt2) - *dt2 = m_popup->GetUpperDateLimit(); - return true; -} - - -void -wxDatePickerCtrlGeneric::SetRange(const wxDateTime &dt1, const wxDateTime &dt2) -{ - m_popup->SetDateRange(dt1, dt2); -} - -// ---------------------------------------------------------------------------- -// event handlers -// ---------------------------------------------------------------------------- - - -void wxDatePickerCtrlGeneric::OnSize(wxSizeEvent& event) -{ - if ( m_combo ) - m_combo->SetSize(GetClientSize()); - - event.Skip(); -} - - -void wxDatePickerCtrlGeneric::OnText(wxCommandEvent &ev) -{ - ev.SetEventObject(this); - ev.SetId(GetId()); - GetParent()->ProcessEvent(ev); - - // We'll create an additional event if the date is valid. - // If the date isn't valid, the user's probably in the middle of typing - wxDateTime dt; - if ( !m_popup->ParseDateTime(m_combo->GetValue(), &dt) ) - return; - - m_popup->SendDateEvent(dt); -} - - -void wxDatePickerCtrlGeneric::OnFocus(wxFocusEvent& WXUNUSED(event)) -{ - m_combo->SetFocus(); -} - - -#endif // wxUSE_DATEPICKCTRL_GENERIC - -#endif // wxUSE_DATEPICKCTRL - +///////////////////////////////////////////////////////////////////////////// +// Name: src/generic/datectlg.cpp +// Purpose: generic wxDatePickerCtrlGeneric implementation +// Author: Andreas Pflug +// Modified by: +// Created: 2005-01-19 +// RCS-ID: $Id: datectlg.cpp 53510 2008-05-09 22:15:55Z RD $ +// Copyright: (c) 2005 Andreas Pflug +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_DATEPICKCTRL + +#include "wx/datectrl.h" + +// use this version if we're explicitly requested to do it or if it's the only +// one we have +#if !defined(wxHAS_NATIVE_DATEPICKCTRL) || \ + (defined(wxUSE_DATEPICKCTRL_GENERIC) && wxUSE_DATEPICKCTRL_GENERIC) + +#ifndef WX_PRECOMP + #include "wx/dialog.h" + #include "wx/dcmemory.h" + #include "wx/panel.h" + #include "wx/textctrl.h" + #include "wx/valtext.h" +#endif + +#ifdef wxHAS_NATIVE_DATEPICKCTRL + // this header is not included from wx/datectrl.h if we have a native + // version, but we do need it here + #include "wx/generic/datectrl.h" +#else + // we need to define _WX_DEFINE_DATE_EVENTS_ before including wx/dateevt.h to + // define the event types we use if we're the only date picker control version + // being compiled -- otherwise it's defined in the native version implementation + #define _WX_DEFINE_DATE_EVENTS_ +#endif + +#include "wx/dateevt.h" + +#include "wx/calctrl.h" +#include "wx/combo.h" + +// ---------------------------------------------------------------------------- +// constants +// ---------------------------------------------------------------------------- + +#if defined(__WXMSW__) + #define CALBORDER 0 +#else + #define CALBORDER 4 +#endif + +// ---------------------------------------------------------------------------- +// global variables +// ---------------------------------------------------------------------------- + + +// ---------------------------------------------------------------------------- +// local classes +// ---------------------------------------------------------------------------- + +class wxCalendarComboPopup : public wxCalendarCtrl, + public wxComboPopup +{ +public: + + wxCalendarComboPopup() : wxCalendarCtrl(), + wxComboPopup() + { + } + + virtual void Init() + { + } + + // NB: Don't create lazily since it didn't work that way before + // wxComboCtrl was used, and changing behaviour would almost + // certainly introduce new bugs. + virtual bool Create(wxWindow* parent) + { + if ( !wxCalendarCtrl::Create(parent, wxID_ANY, wxDefaultDateTime, + wxPoint(0, 0), wxDefaultSize, + wxCAL_SHOW_HOLIDAYS | wxBORDER_SUNKEN) ) + return false; + + wxWindow *yearControl = wxCalendarCtrl::GetYearControl(); + + wxClientDC dc(yearControl); + dc.SetFont(yearControl->GetFont()); + wxCoord width, dummy; + dc.GetTextExtent(wxT("2000"), &width, &dummy); + width += ConvertDialogToPixels(wxSize(20, 0)).x; + + wxSize calSize = wxCalendarCtrl::GetBestSize(); + wxSize yearSize = yearControl->GetSize(); + yearSize.x = width; + + wxPoint yearPosition = yearControl->GetPosition(); + + SetFormat(wxT("%x")); + + width = yearPosition.x + yearSize.x+2+CALBORDER/2; + if (width < calSize.x-4) + width = calSize.x-4; + + int calPos = (width-calSize.x)/2; + if (calPos == -1) + { + calPos = 0; + width += 2; + } + wxCalendarCtrl::SetSize(calPos, 0, calSize.x, calSize.y); + yearControl->SetSize(width-yearSize.x-CALBORDER/2, yearPosition.y, + yearSize.x, yearSize.y); + wxCalendarCtrl::GetMonthControl()->Move(0, 0); + + m_useSize.x = width+CALBORDER/2; + m_useSize.y = calSize.y-2+CALBORDER; + + wxWindow* tx = m_combo->GetTextCtrl(); + if ( !tx ) + tx = m_combo; + + tx->Connect(wxEVT_KILL_FOCUS, + wxFocusEventHandler(wxCalendarComboPopup::OnKillTextFocus), + NULL, this); + + return true; + } + + virtual wxSize GetAdjustedSize(int WXUNUSED(minWidth), + int WXUNUSED(prefHeight), + int WXUNUSED(maxHeight)) + { + return m_useSize; + } + + virtual wxWindow *GetControl() { return this; } + + void SetDateValue(const wxDateTime& date) + { + if ( date.IsValid() ) + { + m_combo->SetText(date.Format(m_format)); + SetDate(date); + } + else // invalid date + { + wxASSERT_MSG( HasDPFlag(wxDP_ALLOWNONE), + _T("this control must have a valid date") ); + + m_combo->SetText(wxEmptyString); + } + } + + bool ParseDateTime(const wxString& s, wxDateTime* pDt) + { + wxASSERT(pDt); + + if ( !s.empty() ) + { + pDt->ParseFormat(s, m_format); + if ( !pDt->IsValid() ) + return false; + } + + return true; + } + + void SendDateEvent(const wxDateTime& dt) + { + // + // Sends both wxCalendarEvent and wxDateEvent + wxWindow* datePicker = m_combo->GetParent(); + + wxCalendarEvent cev((wxCalendarCtrl*) this, wxEVT_CALENDAR_SEL_CHANGED); + cev.SetEventObject(datePicker); + cev.SetId(datePicker->GetId()); + cev.SetDate(dt); + datePicker->GetEventHandler()->ProcessEvent(cev); + + wxDateEvent event(datePicker, dt, wxEVT_DATE_CHANGED); + datePicker->GetEventHandler()->ProcessEvent(event); + } + +private: + + void OnCalKey(wxKeyEvent & ev) + { + if (ev.GetKeyCode() == WXK_ESCAPE && !ev.HasModifiers()) + Dismiss(); + else + ev.Skip(); + } + + void OnSelChange(wxCalendarEvent &ev) + { + m_combo->SetText(GetDate().Format(m_format)); + + if ( ev.GetEventType() == wxEVT_CALENDAR_DOUBLECLICKED ) + { + Dismiss(); + } + + SendDateEvent(GetDate()); + } + + void OnKillTextFocus(wxFocusEvent &ev) + { + ev.Skip(); + + const wxDateTime& dtOld = GetDate(); + + wxDateTime dt; + wxString value = m_combo->GetValue(); + if ( !ParseDateTime(value, &dt) ) + { + if ( !HasDPFlag(wxDP_ALLOWNONE) ) + dt = dtOld; + } + + m_combo->SetText(GetStringValueFor(dt)); + + if ( !dt.IsValid() && HasDPFlag(wxDP_ALLOWNONE) ) + return; + + // notify that we had to change the date after validation + if ( (dt.IsValid() && (!dtOld.IsValid() || dt != dtOld)) || + (!dt.IsValid() && dtOld.IsValid()) ) + { + SetDate(dt); + SendDateEvent(dt); + } + } + + bool HasDPFlag(int flag) + { + return m_combo->GetParent()->HasFlag(flag); + } + + bool SetFormat(const wxChar *fmt) + { + m_format.clear(); + + wxDateTime dt; + dt.ParseFormat(wxT("2003-10-13"), wxT("%Y-%m-%d")); + wxString str(dt.Format(fmt)); + + const wxChar *p = str.c_str(); + while ( *p ) + { + int n=wxAtoi(p); + if (n == dt.GetDay()) + { + m_format.Append(wxT("%d")); + p += 2; + } + else if (n == (int)dt.GetMonth()+1) + { + m_format.Append(wxT("%m")); + p += 2; + } + else if (n == dt.GetYear()) + { + m_format.Append(wxT("%Y")); + p += 4; + } + else if (n == (dt.GetYear() % 100)) + { + if ( HasDPFlag(wxDP_SHOWCENTURY) ) + m_format.Append(wxT("%Y")); + else + m_format.Append(wxT("%y")); + p += 2; + } + else + m_format.Append(*p++); + } + + if ( m_combo ) + { + wxArrayString allowedChars; + for ( wxChar c = _T('0'); c <= _T('9'); c++ ) + allowedChars.Add(wxString(c, 1)); + + const wxChar *p2 = m_format.c_str(); + while ( *p2 ) + { + if ( *p2 == '%') + p2 += 2; + else + allowedChars.Add(wxString(*p2++, 1)); + } + + #if wxUSE_VALIDATORS + wxTextValidator tv(wxFILTER_INCLUDE_CHAR_LIST); + tv.SetIncludes(allowedChars); + m_combo->SetValidator(tv); + #endif + + if ( GetDate().IsValid() ) + m_combo->SetText(GetDate().Format(m_format)); + } + + return true; + } + + virtual void SetStringValue(const wxString& s) + { + wxDateTime dt; + if ( !s.empty() && ParseDateTime(s, &dt) ) + SetDate(dt); + //else: keep the old value + } + + virtual wxString GetStringValue() const + { + return GetStringValueFor(GetDate()); + } + +private: + // returns either the given date representation using the current format or + // an empty string if it's invalid + wxString GetStringValueFor(const wxDateTime& dt) const + { + wxString val; + if ( dt.IsValid() ) + val = dt.Format(m_format); + + return val; + } + + wxSize m_useSize; + wxString m_format; + + DECLARE_EVENT_TABLE() +}; + + +BEGIN_EVENT_TABLE(wxCalendarComboPopup, wxCalendarCtrl) + EVT_KEY_DOWN(wxCalendarComboPopup::OnCalKey) + EVT_CALENDAR_SEL_CHANGED(wxID_ANY, wxCalendarComboPopup::OnSelChange) + EVT_CALENDAR_DAY(wxID_ANY, wxCalendarComboPopup::OnSelChange) + EVT_CALENDAR_MONTH(wxID_ANY, wxCalendarComboPopup::OnSelChange) + EVT_CALENDAR_YEAR(wxID_ANY, wxCalendarComboPopup::OnSelChange) + EVT_CALENDAR(wxID_ANY, wxCalendarComboPopup::OnSelChange) +END_EVENT_TABLE() + + +// ============================================================================ +// wxDatePickerCtrlGeneric implementation +// ============================================================================ + +BEGIN_EVENT_TABLE(wxDatePickerCtrlGeneric, wxDatePickerCtrlBase) + EVT_TEXT(wxID_ANY, wxDatePickerCtrlGeneric::OnText) + EVT_SIZE(wxDatePickerCtrlGeneric::OnSize) + EVT_SET_FOCUS(wxDatePickerCtrlGeneric::OnFocus) +END_EVENT_TABLE() + +#ifndef wxHAS_NATIVE_DATEPICKCTRL + IMPLEMENT_DYNAMIC_CLASS(wxDatePickerCtrl, wxControl) +#endif + +// ---------------------------------------------------------------------------- +// creation +// ---------------------------------------------------------------------------- + +bool wxDatePickerCtrlGeneric::Create(wxWindow *parent, + wxWindowID id, + const wxDateTime& date, + const wxPoint& pos, + const wxSize& size, + long style, + const wxValidator& validator, + const wxString& name) +{ + wxASSERT_MSG( !(style & wxDP_SPIN), + _T("wxDP_SPIN style not supported, use wxDP_DEFAULT") ); + + if ( !wxControl::Create(parent, id, pos, size, + style | wxCLIP_CHILDREN | wxWANTS_CHARS | wxBORDER_NONE, + validator, name) ) + { + return false; + } + + InheritAttributes(); + + m_combo = new wxComboCtrl(this, -1, wxEmptyString, + wxDefaultPosition, wxDefaultSize); + + m_combo->SetCtrlMainWnd(this); + + m_popup = new wxCalendarComboPopup(); + m_cal = m_popup; + +#if defined(__WXMSW__) + // without this keyboard navigation in month control doesn't work + m_combo->UseAltPopupWindow(); +#endif + m_combo->SetPopupControl(m_popup); + + m_popup->SetDateValue(date.IsValid() ? date : wxDateTime::Today()); + + SetInitialSize(size); + + return true; +} + + +void wxDatePickerCtrlGeneric::Init() +{ + m_combo = NULL; + m_popup = NULL; + m_cal = NULL; +} + +wxDatePickerCtrlGeneric::~wxDatePickerCtrlGeneric() +{ +} + +bool wxDatePickerCtrlGeneric::Destroy() +{ + if ( m_combo ) + m_combo->Destroy(); + + m_combo = NULL; + m_popup = NULL; + m_cal = NULL; + + return wxControl::Destroy(); +} + +// ---------------------------------------------------------------------------- +// overridden base class methods +// ---------------------------------------------------------------------------- + +wxSize wxDatePickerCtrlGeneric::DoGetBestSize() const +{ + return m_combo->GetBestSize(); +} + +// ---------------------------------------------------------------------------- +// wxDatePickerCtrlGeneric API +// ---------------------------------------------------------------------------- + +bool +wxDatePickerCtrlGeneric::SetDateRange(const wxDateTime& lowerdate, + const wxDateTime& upperdate) +{ + return m_popup->SetDateRange(lowerdate, upperdate); +} + + +wxDateTime wxDatePickerCtrlGeneric::GetValue() const +{ + return m_popup->GetDate(); +} + + +void wxDatePickerCtrlGeneric::SetValue(const wxDateTime& date) +{ + m_popup->SetDateValue(date); +} + + +bool wxDatePickerCtrlGeneric::GetRange(wxDateTime *dt1, wxDateTime *dt2) const +{ + if (dt1) + *dt1 = m_popup->GetLowerDateLimit(); + if (dt2) + *dt2 = m_popup->GetUpperDateLimit(); + return true; +} + + +void +wxDatePickerCtrlGeneric::SetRange(const wxDateTime &dt1, const wxDateTime &dt2) +{ + m_popup->SetDateRange(dt1, dt2); +} + +// ---------------------------------------------------------------------------- +// event handlers +// ---------------------------------------------------------------------------- + + +void wxDatePickerCtrlGeneric::OnSize(wxSizeEvent& event) +{ + if ( m_combo ) + m_combo->SetSize(GetClientSize()); + + event.Skip(); +} + + +void wxDatePickerCtrlGeneric::OnText(wxCommandEvent &ev) +{ + ev.SetEventObject(this); + ev.SetId(GetId()); + GetParent()->ProcessEvent(ev); + + // We'll create an additional event if the date is valid. + // If the date isn't valid, the user's probably in the middle of typing + wxDateTime dt; + if ( !m_popup->ParseDateTime(m_combo->GetValue(), &dt) ) + return; + + m_popup->SendDateEvent(dt); +} + + +void wxDatePickerCtrlGeneric::OnFocus(wxFocusEvent& WXUNUSED(event)) +{ + m_combo->SetFocus(); +} + + +#endif // wxUSE_DATEPICKCTRL_GENERIC + +#endif // wxUSE_DATEPICKCTRL + diff --git a/Externals/wxWidgets/src/generic/dbgrptg.cpp b/Externals/wxWidgets/src/generic/dbgrptg.cpp index b55ba61220..3f4139e54f 100644 --- a/Externals/wxWidgets/src/generic/dbgrptg.cpp +++ b/Externals/wxWidgets/src/generic/dbgrptg.cpp @@ -1,525 +1,525 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: src/generic/dbgrptg.cpp -// Purpose: implementation of wxDebugReportPreviewStd -// Author: Vadim Zeitlin, Andrej Putrin -// Modified by: -// Created: 2005-01-21 -// RCS-ID: $Id: dbgrptg.cpp 49242 2007-10-19 11:40:07Z JS $ -// Copyright: (c) 2005 Vadim Zeitlin -// License: wxWindows licence -/////////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_DEBUGREPORT && wxUSE_XML - -#include "wx/debugrpt.h" - -#ifndef WX_PRECOMP - #include "wx/sizer.h" - #include "wx/checklst.h" - #include "wx/textctrl.h" - #include "wx/intl.h" - #include "wx/stattext.h" - #include "wx/filedlg.h" - #include "wx/valtext.h" - #include "wx/button.h" -#endif // WX_PRECOMP - -#include "wx/filename.h" -#include "wx/ffile.h" -#include "wx/mimetype.h" - -#include "wx/statline.h" - -#ifdef __WXMSW__ - #include "wx/evtloop.h" // for SetCriticalWindow() -#endif // __WXMSW__ - -// ---------------------------------------------------------------------------- -// wxDumpPreviewDlg: simple class for showing ASCII preview of dump files -// ---------------------------------------------------------------------------- - -class wxDumpPreviewDlg : public wxDialog -{ -public: - wxDumpPreviewDlg(wxWindow *parent, - const wxString& title, - const wxString& text); - -private: - // the text we show - wxTextCtrl *m_text; - - DECLARE_NO_COPY_CLASS(wxDumpPreviewDlg) -}; - -wxDumpPreviewDlg::wxDumpPreviewDlg(wxWindow *parent, - const wxString& title, - const wxString& text) - : wxDialog(parent, wxID_ANY, title, - wxDefaultPosition, wxDefaultSize, - wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER) -{ - // create controls - // --------------- - - // use wxTE_RICH2 style to avoid 64kB limit under MSW and display big files - // faster than with wxTE_RICH - m_text = new wxTextCtrl(this, wxID_ANY, wxEmptyString, - wxPoint(0, 0), wxDefaultSize, - wxTE_MULTILINE | - wxTE_READONLY | - wxTE_NOHIDESEL | - wxTE_RICH2); - m_text->SetValue(text); - - // use fixed-width font - m_text->SetFont(wxFont(12, wxFONTFAMILY_TELETYPE, - wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL)); - - wxButton *btnClose = new wxButton(this, wxID_CANCEL, _("Close")); - - - // layout them - // ----------- - - wxSizer *sizerTop = new wxBoxSizer(wxVERTICAL), - *sizerBtns = new wxBoxSizer(wxHORIZONTAL); - - sizerBtns->Add(btnClose, 0, 0, 1); - - sizerTop->Add(m_text, 1, wxEXPAND); - sizerTop->Add(sizerBtns, 0, wxALIGN_RIGHT | wxTOP | wxBOTTOM | wxRIGHT, 1); - - // set the sizer &c - // ---------------- - - // make the text window bigger to show more contents of the file - sizerTop->SetItemMinSize(m_text, 600, 300); - SetSizer(sizerTop); - - Layout(); - Fit(); - - m_text->SetFocus(); -} - -// ---------------------------------------------------------------------------- -// wxDumpOpenExternalDlg: choose a command for opening the given file -// ---------------------------------------------------------------------------- - -class wxDumpOpenExternalDlg : public wxDialog -{ -public: - wxDumpOpenExternalDlg(wxWindow *parent, const wxFileName& filename); - - // return the command chosed by user to open this file - const wxString& GetCommand() const { return m_command; } - - wxString m_command; - -private: - -#if wxUSE_FILEDLG - void OnBrowse(wxCommandEvent& event); -#endif // wxUSE_FILEDLG - - DECLARE_EVENT_TABLE() - DECLARE_NO_COPY_CLASS(wxDumpOpenExternalDlg) -}; - -BEGIN_EVENT_TABLE(wxDumpOpenExternalDlg, wxDialog) - -#if wxUSE_FILEDLG - EVT_BUTTON(wxID_MORE, wxDumpOpenExternalDlg::OnBrowse) -#endif - -END_EVENT_TABLE() - - -wxDumpOpenExternalDlg::wxDumpOpenExternalDlg(wxWindow *parent, - const wxFileName& filename) - : wxDialog(parent, - wxID_ANY, - wxString::Format - ( - _("Open file \"%s\""), - filename.GetFullPath().c_str() - )) -{ - // create controls - // --------------- - - wxSizer *sizerTop = new wxBoxSizer(wxVERTICAL); - sizerTop->Add(new wxStaticText(this, wxID_ANY, - wxString::Format - ( - _("Enter command to open file \"%s\":"), - filename.GetFullName().c_str() - )), - wxSizerFlags().Border()); - - wxSizer *sizerH = new wxBoxSizer(wxHORIZONTAL); - - wxTextCtrl *command = new wxTextCtrl - ( - this, - wxID_ANY, - wxEmptyString, - wxDefaultPosition, - wxSize(250, wxDefaultCoord), - 0 -#if wxUSE_VALIDATORS - ,wxTextValidator(wxFILTER_NONE, &m_command) -#endif - ); - sizerH->Add(command, - wxSizerFlags(1).Align(wxALIGN_CENTER_VERTICAL)); - -#if wxUSE_FILEDLG - - wxButton *browse = new wxButton(this, wxID_MORE, wxT(">>"), - wxDefaultPosition, wxDefaultSize, - wxBU_EXACTFIT); - sizerH->Add(browse, - wxSizerFlags(0).Align(wxALIGN_CENTER_VERTICAL). Border(wxLEFT)); - -#endif // wxUSE_FILEDLG - - sizerTop->Add(sizerH, wxSizerFlags(0).Expand().Border()); - - sizerTop->Add(new wxStaticLine(this), wxSizerFlags().Expand().Border()); - - sizerTop->Add(CreateStdDialogButtonSizer(wxOK | wxCANCEL), - wxSizerFlags().Align(wxALIGN_RIGHT).Border()); - - // set the sizer &c - // ---------------- - - SetSizer(sizerTop); - - Layout(); - Fit(); - - command->SetFocus(); -} - -#if wxUSE_FILEDLG - -void wxDumpOpenExternalDlg::OnBrowse(wxCommandEvent& ) -{ - wxFileName fname(m_command); - wxFileDialog dlg(this, - wxFileSelectorPromptStr, - fname.GetPathWithSep(), - fname.GetFullName() -#ifdef __WXMSW__ - , _("Executable files (*.exe)|*.exe|All files (*.*)|*.*||") -#endif // __WXMSW__ - ); - if ( dlg.ShowModal() == wxID_OK ) - { - m_command = dlg.GetPath(); - TransferDataToWindow(); - } -} - -#endif // wxUSE_FILEDLG - -// ---------------------------------------------------------------------------- -// wxDebugReportDialog: class showing debug report to the user -// ---------------------------------------------------------------------------- - -class wxDebugReportDialog : public wxDialog -{ -public: - wxDebugReportDialog(wxDebugReport& dbgrpt); - - virtual bool TransferDataToWindow(); - virtual bool TransferDataFromWindow(); - -private: - void OnView(wxCommandEvent& ); - void OnViewUpdate(wxUpdateUIEvent& ); - void OnOpen(wxCommandEvent& ); - - - // small helper: add wxEXPAND and wxALL flags - static wxSizerFlags SizerFlags(int proportion) - { - return wxSizerFlags(proportion).Expand().Border(); - } - - - wxDebugReport& m_dbgrpt; - - wxCheckListBox *m_checklst; - wxTextCtrl *m_notes; - - wxArrayString m_files; - - DECLARE_EVENT_TABLE() - DECLARE_NO_COPY_CLASS(wxDebugReportDialog) -}; - -// ============================================================================ -// wxDebugReportDialog implementation -// ============================================================================ - -BEGIN_EVENT_TABLE(wxDebugReportDialog, wxDialog) - EVT_BUTTON(wxID_VIEW_DETAILS, wxDebugReportDialog::OnView) - EVT_UPDATE_UI(wxID_VIEW_DETAILS, wxDebugReportDialog::OnViewUpdate) - EVT_BUTTON(wxID_OPEN, wxDebugReportDialog::OnOpen) - EVT_UPDATE_UI(wxID_OPEN, wxDebugReportDialog::OnViewUpdate) -END_EVENT_TABLE() - - -// ---------------------------------------------------------------------------- -// construction -// ---------------------------------------------------------------------------- - -wxDebugReportDialog::wxDebugReportDialog(wxDebugReport& dbgrpt) - : wxDialog(NULL, wxID_ANY, - wxString::Format(_("Debug report \"%s\""), - dbgrpt.GetReportName().c_str()), - wxDefaultPosition, - wxDefaultSize, - wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER), - m_dbgrpt(dbgrpt) -{ - // upper part of the dialog: explanatory message - wxString msg; - wxString debugDir = dbgrpt.GetDirectory(); - - // The temporary directory can be the short form on Windows; - // normalize it for the benefit of users. -#ifdef __WXMSW__ - wxFileName debugDirFilename(debugDir, wxEmptyString); - debugDirFilename.Normalize(wxPATH_NORM_LONG); - debugDir = debugDirFilename.GetPath(); -#endif - msg << _("A debug report has been generated in the directory\n") - << _T('\n') - << _T(" \"") << debugDir << _T("\"\n") - << _T('\n') - << _("The report contains the files listed below. If any of these files contain private information,\nplease uncheck them and they will be removed from the report.\n") - << _T('\n') - << _("If you wish to suppress this debug report completely, please choose the \"Cancel\" button,\nbut be warned that it may hinder improving the program, so if\nat all possible please do continue with the report generation.\n") - << _T('\n') - << _(" Thank you and we're sorry for the inconvenience!\n") - << _T("\n\n"); // just some white space to separate from other stuff - - const wxSizerFlags flagsFixed(SizerFlags(0)); - const wxSizerFlags flagsExpand(SizerFlags(1)); - const wxSizerFlags flagsExpand2(SizerFlags(2)); - - wxSizer *sizerPreview = - new wxStaticBoxSizer(wxVERTICAL, this, _("&Debug report preview:")); - sizerPreview->Add(CreateTextSizer(msg), SizerFlags(0).Centre()); - - // ... and the list of files in this debug report with buttons to view them - wxSizer *sizerFileBtns = new wxBoxSizer(wxVERTICAL); - sizerFileBtns->AddStretchSpacer(1); - sizerFileBtns->Add(new wxButton(this, wxID_VIEW_DETAILS, _T("&View...")), - wxSizerFlags().Border(wxBOTTOM)); - sizerFileBtns->Add(new wxButton(this, wxID_OPEN, _T("&Open...")), - wxSizerFlags().Border(wxTOP)); - sizerFileBtns->AddStretchSpacer(1); - - m_checklst = new wxCheckListBox(this, wxID_ANY); - - wxSizer *sizerFiles = new wxBoxSizer(wxHORIZONTAL); - sizerFiles->Add(m_checklst, flagsExpand); - sizerFiles->Add(sizerFileBtns, flagsFixed); - - sizerPreview->Add(sizerFiles, flagsExpand2); - - - // lower part of the dialog: notes field - wxSizer *sizerNotes = new wxStaticBoxSizer(wxVERTICAL, this, _("&Notes:")); - - msg = _("If you have any additional information pertaining to this bug\nreport, please enter it here and it will be joined to it:"); - - m_notes = new wxTextCtrl(this, wxID_ANY, wxEmptyString, - wxDefaultPosition, wxDefaultSize, - wxTE_MULTILINE); - - sizerNotes->Add(CreateTextSizer(msg), flagsFixed); - sizerNotes->Add(m_notes, flagsExpand); - - - wxSizer *sizerTop = new wxBoxSizer(wxVERTICAL); - sizerTop->Add(sizerPreview, flagsExpand2); - sizerTop->AddSpacer(5); - sizerTop->Add(sizerNotes, flagsExpand); - sizerTop->Add(CreateStdDialogButtonSizer(wxOK | wxCANCEL), flagsFixed); - - SetSizerAndFit(sizerTop); - Layout(); - CentreOnScreen(); -} - -// ---------------------------------------------------------------------------- -// data exchange -// ---------------------------------------------------------------------------- - -bool wxDebugReportDialog::TransferDataToWindow() -{ - // all files are included in the report by default - const size_t count = m_dbgrpt.GetFilesCount(); - for ( size_t n = 0; n < count; n++ ) - { - wxString name, - desc; - if ( m_dbgrpt.GetFile(n, &name, &desc) ) - { - m_checklst->Append(name + _T(" (") + desc + _T(')')); - m_checklst->Check(n); - - m_files.Add(name); - } - } - - return true; -} - -bool wxDebugReportDialog::TransferDataFromWindow() -{ - // any unchecked files should be removed from the report - const size_t count = m_checklst->GetCount(); - for ( size_t n = 0; n < count; n++ ) - { - if ( !m_checklst->IsChecked(n) ) - { - m_dbgrpt.RemoveFile(m_files[n]); - } - } - - // if the user entered any notes, add them to the report - const wxString notes = m_notes->GetValue(); - if ( !notes.empty() ) - { - // for now filename fixed, could make it configurable in the future... - m_dbgrpt.AddText(_T("notes.txt"), notes, _T("user notes")); - } - - return true; -} - -// ---------------------------------------------------------------------------- -// event handlers -// ---------------------------------------------------------------------------- - -void wxDebugReportDialog::OnView(wxCommandEvent& ) -{ - const int sel = m_checklst->GetSelection(); - wxCHECK_RET( sel != wxNOT_FOUND, _T("invalid selection in OnView()") ); - - wxFileName fn(m_dbgrpt.GetDirectory(), m_files[sel]); - wxString str; - - wxFFile file(fn.GetFullPath()); - if ( file.IsOpened() && file.ReadAll(&str) ) - { - wxDumpPreviewDlg dlg(this, m_files[sel], str); - dlg.ShowModal(); - } -} - -void wxDebugReportDialog::OnOpen(wxCommandEvent& ) -{ - const int sel = m_checklst->GetSelection(); - wxCHECK_RET( sel != wxNOT_FOUND, _T("invalid selection in OnOpen()") ); - - wxFileName fn(m_dbgrpt.GetDirectory(), m_files[sel]); - - // try to get the command to open this kind of files ourselves - wxString command; -#if wxUSE_MIMETYPE - wxFileType * - ft = wxTheMimeTypesManager->GetFileTypeFromExtension(fn.GetExt()); - if ( ft ) - { - command = ft->GetOpenCommand(fn.GetFullPath()); - delete ft; - } -#endif // wxUSE_MIMETYPE - - // if we couldn't, ask the user - if ( command.empty() ) - { - wxDumpOpenExternalDlg dlg(this, fn); - if ( dlg.ShowModal() == wxID_OK ) - { - // get the command chosen by the user and append file name to it - - // if we don't have place marker for file name in the command... - wxString cmd = dlg.GetCommand(); - if ( !cmd.empty() ) - { -#if wxUSE_MIMETYPE - if ( cmd.find(_T('%')) != wxString::npos ) - { - command = wxFileType::ExpandCommand(cmd, fn.GetFullPath()); - } - else // no %s nor %1 -#endif // wxUSE_MIMETYPE - { - // append the file name to the end - command << cmd << _T(" \"") << fn.GetFullPath() << _T('"'); - } - } - } - } - - if ( !command.empty() ) - ::wxExecute(command); -} - -void wxDebugReportDialog::OnViewUpdate(wxUpdateUIEvent& event) -{ - int sel = m_checklst->GetSelection(); - if (sel >= 0) - { - wxFileName fn(m_dbgrpt.GetDirectory(), m_files[sel]); - event.Enable(fn.FileExists()); - } - else - event.Enable(false); -} - - -// ============================================================================ -// wxDebugReportPreviewStd implementation -// ============================================================================ - -bool wxDebugReportPreviewStd::Show(wxDebugReport& dbgrpt) const -{ - if ( !dbgrpt.GetFilesCount() ) - return false; - - wxDebugReportDialog dlg(dbgrpt); - -#ifdef __WXMSW__ - // before entering the event loop (from ShowModal()), block the event - // handling for all other windows as this could result in more crashes - wxEventLoop::SetCriticalWindow(&dlg); -#endif // __WXMSW__ - - return dlg.ShowModal() == wxID_OK && dbgrpt.GetFilesCount() != 0; -} - -#endif // wxUSE_DEBUGREPORT && wxUSE_XML +/////////////////////////////////////////////////////////////////////////////// +// Name: src/generic/dbgrptg.cpp +// Purpose: implementation of wxDebugReportPreviewStd +// Author: Vadim Zeitlin, Andrej Putrin +// Modified by: +// Created: 2005-01-21 +// RCS-ID: $Id: dbgrptg.cpp 49242 2007-10-19 11:40:07Z JS $ +// Copyright: (c) 2005 Vadim Zeitlin +// License: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_DEBUGREPORT && wxUSE_XML + +#include "wx/debugrpt.h" + +#ifndef WX_PRECOMP + #include "wx/sizer.h" + #include "wx/checklst.h" + #include "wx/textctrl.h" + #include "wx/intl.h" + #include "wx/stattext.h" + #include "wx/filedlg.h" + #include "wx/valtext.h" + #include "wx/button.h" +#endif // WX_PRECOMP + +#include "wx/filename.h" +#include "wx/ffile.h" +#include "wx/mimetype.h" + +#include "wx/statline.h" + +#ifdef __WXMSW__ + #include "wx/evtloop.h" // for SetCriticalWindow() +#endif // __WXMSW__ + +// ---------------------------------------------------------------------------- +// wxDumpPreviewDlg: simple class for showing ASCII preview of dump files +// ---------------------------------------------------------------------------- + +class wxDumpPreviewDlg : public wxDialog +{ +public: + wxDumpPreviewDlg(wxWindow *parent, + const wxString& title, + const wxString& text); + +private: + // the text we show + wxTextCtrl *m_text; + + DECLARE_NO_COPY_CLASS(wxDumpPreviewDlg) +}; + +wxDumpPreviewDlg::wxDumpPreviewDlg(wxWindow *parent, + const wxString& title, + const wxString& text) + : wxDialog(parent, wxID_ANY, title, + wxDefaultPosition, wxDefaultSize, + wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER) +{ + // create controls + // --------------- + + // use wxTE_RICH2 style to avoid 64kB limit under MSW and display big files + // faster than with wxTE_RICH + m_text = new wxTextCtrl(this, wxID_ANY, wxEmptyString, + wxPoint(0, 0), wxDefaultSize, + wxTE_MULTILINE | + wxTE_READONLY | + wxTE_NOHIDESEL | + wxTE_RICH2); + m_text->SetValue(text); + + // use fixed-width font + m_text->SetFont(wxFont(12, wxFONTFAMILY_TELETYPE, + wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL)); + + wxButton *btnClose = new wxButton(this, wxID_CANCEL, _("Close")); + + + // layout them + // ----------- + + wxSizer *sizerTop = new wxBoxSizer(wxVERTICAL), + *sizerBtns = new wxBoxSizer(wxHORIZONTAL); + + sizerBtns->Add(btnClose, 0, 0, 1); + + sizerTop->Add(m_text, 1, wxEXPAND); + sizerTop->Add(sizerBtns, 0, wxALIGN_RIGHT | wxTOP | wxBOTTOM | wxRIGHT, 1); + + // set the sizer &c + // ---------------- + + // make the text window bigger to show more contents of the file + sizerTop->SetItemMinSize(m_text, 600, 300); + SetSizer(sizerTop); + + Layout(); + Fit(); + + m_text->SetFocus(); +} + +// ---------------------------------------------------------------------------- +// wxDumpOpenExternalDlg: choose a command for opening the given file +// ---------------------------------------------------------------------------- + +class wxDumpOpenExternalDlg : public wxDialog +{ +public: + wxDumpOpenExternalDlg(wxWindow *parent, const wxFileName& filename); + + // return the command chosed by user to open this file + const wxString& GetCommand() const { return m_command; } + + wxString m_command; + +private: + +#if wxUSE_FILEDLG + void OnBrowse(wxCommandEvent& event); +#endif // wxUSE_FILEDLG + + DECLARE_EVENT_TABLE() + DECLARE_NO_COPY_CLASS(wxDumpOpenExternalDlg) +}; + +BEGIN_EVENT_TABLE(wxDumpOpenExternalDlg, wxDialog) + +#if wxUSE_FILEDLG + EVT_BUTTON(wxID_MORE, wxDumpOpenExternalDlg::OnBrowse) +#endif + +END_EVENT_TABLE() + + +wxDumpOpenExternalDlg::wxDumpOpenExternalDlg(wxWindow *parent, + const wxFileName& filename) + : wxDialog(parent, + wxID_ANY, + wxString::Format + ( + _("Open file \"%s\""), + filename.GetFullPath().c_str() + )) +{ + // create controls + // --------------- + + wxSizer *sizerTop = new wxBoxSizer(wxVERTICAL); + sizerTop->Add(new wxStaticText(this, wxID_ANY, + wxString::Format + ( + _("Enter command to open file \"%s\":"), + filename.GetFullName().c_str() + )), + wxSizerFlags().Border()); + + wxSizer *sizerH = new wxBoxSizer(wxHORIZONTAL); + + wxTextCtrl *command = new wxTextCtrl + ( + this, + wxID_ANY, + wxEmptyString, + wxDefaultPosition, + wxSize(250, wxDefaultCoord), + 0 +#if wxUSE_VALIDATORS + ,wxTextValidator(wxFILTER_NONE, &m_command) +#endif + ); + sizerH->Add(command, + wxSizerFlags(1).Align(wxALIGN_CENTER_VERTICAL)); + +#if wxUSE_FILEDLG + + wxButton *browse = new wxButton(this, wxID_MORE, wxT(">>"), + wxDefaultPosition, wxDefaultSize, + wxBU_EXACTFIT); + sizerH->Add(browse, + wxSizerFlags(0).Align(wxALIGN_CENTER_VERTICAL). Border(wxLEFT)); + +#endif // wxUSE_FILEDLG + + sizerTop->Add(sizerH, wxSizerFlags(0).Expand().Border()); + + sizerTop->Add(new wxStaticLine(this), wxSizerFlags().Expand().Border()); + + sizerTop->Add(CreateStdDialogButtonSizer(wxOK | wxCANCEL), + wxSizerFlags().Align(wxALIGN_RIGHT).Border()); + + // set the sizer &c + // ---------------- + + SetSizer(sizerTop); + + Layout(); + Fit(); + + command->SetFocus(); +} + +#if wxUSE_FILEDLG + +void wxDumpOpenExternalDlg::OnBrowse(wxCommandEvent& ) +{ + wxFileName fname(m_command); + wxFileDialog dlg(this, + wxFileSelectorPromptStr, + fname.GetPathWithSep(), + fname.GetFullName() +#ifdef __WXMSW__ + , _("Executable files (*.exe)|*.exe|All files (*.*)|*.*||") +#endif // __WXMSW__ + ); + if ( dlg.ShowModal() == wxID_OK ) + { + m_command = dlg.GetPath(); + TransferDataToWindow(); + } +} + +#endif // wxUSE_FILEDLG + +// ---------------------------------------------------------------------------- +// wxDebugReportDialog: class showing debug report to the user +// ---------------------------------------------------------------------------- + +class wxDebugReportDialog : public wxDialog +{ +public: + wxDebugReportDialog(wxDebugReport& dbgrpt); + + virtual bool TransferDataToWindow(); + virtual bool TransferDataFromWindow(); + +private: + void OnView(wxCommandEvent& ); + void OnViewUpdate(wxUpdateUIEvent& ); + void OnOpen(wxCommandEvent& ); + + + // small helper: add wxEXPAND and wxALL flags + static wxSizerFlags SizerFlags(int proportion) + { + return wxSizerFlags(proportion).Expand().Border(); + } + + + wxDebugReport& m_dbgrpt; + + wxCheckListBox *m_checklst; + wxTextCtrl *m_notes; + + wxArrayString m_files; + + DECLARE_EVENT_TABLE() + DECLARE_NO_COPY_CLASS(wxDebugReportDialog) +}; + +// ============================================================================ +// wxDebugReportDialog implementation +// ============================================================================ + +BEGIN_EVENT_TABLE(wxDebugReportDialog, wxDialog) + EVT_BUTTON(wxID_VIEW_DETAILS, wxDebugReportDialog::OnView) + EVT_UPDATE_UI(wxID_VIEW_DETAILS, wxDebugReportDialog::OnViewUpdate) + EVT_BUTTON(wxID_OPEN, wxDebugReportDialog::OnOpen) + EVT_UPDATE_UI(wxID_OPEN, wxDebugReportDialog::OnViewUpdate) +END_EVENT_TABLE() + + +// ---------------------------------------------------------------------------- +// construction +// ---------------------------------------------------------------------------- + +wxDebugReportDialog::wxDebugReportDialog(wxDebugReport& dbgrpt) + : wxDialog(NULL, wxID_ANY, + wxString::Format(_("Debug report \"%s\""), + dbgrpt.GetReportName().c_str()), + wxDefaultPosition, + wxDefaultSize, + wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER), + m_dbgrpt(dbgrpt) +{ + // upper part of the dialog: explanatory message + wxString msg; + wxString debugDir = dbgrpt.GetDirectory(); + + // The temporary directory can be the short form on Windows; + // normalize it for the benefit of users. +#ifdef __WXMSW__ + wxFileName debugDirFilename(debugDir, wxEmptyString); + debugDirFilename.Normalize(wxPATH_NORM_LONG); + debugDir = debugDirFilename.GetPath(); +#endif + msg << _("A debug report has been generated in the directory\n") + << _T('\n') + << _T(" \"") << debugDir << _T("\"\n") + << _T('\n') + << _("The report contains the files listed below. If any of these files contain private information,\nplease uncheck them and they will be removed from the report.\n") + << _T('\n') + << _("If you wish to suppress this debug report completely, please choose the \"Cancel\" button,\nbut be warned that it may hinder improving the program, so if\nat all possible please do continue with the report generation.\n") + << _T('\n') + << _(" Thank you and we're sorry for the inconvenience!\n") + << _T("\n\n"); // just some white space to separate from other stuff + + const wxSizerFlags flagsFixed(SizerFlags(0)); + const wxSizerFlags flagsExpand(SizerFlags(1)); + const wxSizerFlags flagsExpand2(SizerFlags(2)); + + wxSizer *sizerPreview = + new wxStaticBoxSizer(wxVERTICAL, this, _("&Debug report preview:")); + sizerPreview->Add(CreateTextSizer(msg), SizerFlags(0).Centre()); + + // ... and the list of files in this debug report with buttons to view them + wxSizer *sizerFileBtns = new wxBoxSizer(wxVERTICAL); + sizerFileBtns->AddStretchSpacer(1); + sizerFileBtns->Add(new wxButton(this, wxID_VIEW_DETAILS, _T("&View...")), + wxSizerFlags().Border(wxBOTTOM)); + sizerFileBtns->Add(new wxButton(this, wxID_OPEN, _T("&Open...")), + wxSizerFlags().Border(wxTOP)); + sizerFileBtns->AddStretchSpacer(1); + + m_checklst = new wxCheckListBox(this, wxID_ANY); + + wxSizer *sizerFiles = new wxBoxSizer(wxHORIZONTAL); + sizerFiles->Add(m_checklst, flagsExpand); + sizerFiles->Add(sizerFileBtns, flagsFixed); + + sizerPreview->Add(sizerFiles, flagsExpand2); + + + // lower part of the dialog: notes field + wxSizer *sizerNotes = new wxStaticBoxSizer(wxVERTICAL, this, _("&Notes:")); + + msg = _("If you have any additional information pertaining to this bug\nreport, please enter it here and it will be joined to it:"); + + m_notes = new wxTextCtrl(this, wxID_ANY, wxEmptyString, + wxDefaultPosition, wxDefaultSize, + wxTE_MULTILINE); + + sizerNotes->Add(CreateTextSizer(msg), flagsFixed); + sizerNotes->Add(m_notes, flagsExpand); + + + wxSizer *sizerTop = new wxBoxSizer(wxVERTICAL); + sizerTop->Add(sizerPreview, flagsExpand2); + sizerTop->AddSpacer(5); + sizerTop->Add(sizerNotes, flagsExpand); + sizerTop->Add(CreateStdDialogButtonSizer(wxOK | wxCANCEL), flagsFixed); + + SetSizerAndFit(sizerTop); + Layout(); + CentreOnScreen(); +} + +// ---------------------------------------------------------------------------- +// data exchange +// ---------------------------------------------------------------------------- + +bool wxDebugReportDialog::TransferDataToWindow() +{ + // all files are included in the report by default + const size_t count = m_dbgrpt.GetFilesCount(); + for ( size_t n = 0; n < count; n++ ) + { + wxString name, + desc; + if ( m_dbgrpt.GetFile(n, &name, &desc) ) + { + m_checklst->Append(name + _T(" (") + desc + _T(')')); + m_checklst->Check(n); + + m_files.Add(name); + } + } + + return true; +} + +bool wxDebugReportDialog::TransferDataFromWindow() +{ + // any unchecked files should be removed from the report + const size_t count = m_checklst->GetCount(); + for ( size_t n = 0; n < count; n++ ) + { + if ( !m_checklst->IsChecked(n) ) + { + m_dbgrpt.RemoveFile(m_files[n]); + } + } + + // if the user entered any notes, add them to the report + const wxString notes = m_notes->GetValue(); + if ( !notes.empty() ) + { + // for now filename fixed, could make it configurable in the future... + m_dbgrpt.AddText(_T("notes.txt"), notes, _T("user notes")); + } + + return true; +} + +// ---------------------------------------------------------------------------- +// event handlers +// ---------------------------------------------------------------------------- + +void wxDebugReportDialog::OnView(wxCommandEvent& ) +{ + const int sel = m_checklst->GetSelection(); + wxCHECK_RET( sel != wxNOT_FOUND, _T("invalid selection in OnView()") ); + + wxFileName fn(m_dbgrpt.GetDirectory(), m_files[sel]); + wxString str; + + wxFFile file(fn.GetFullPath()); + if ( file.IsOpened() && file.ReadAll(&str) ) + { + wxDumpPreviewDlg dlg(this, m_files[sel], str); + dlg.ShowModal(); + } +} + +void wxDebugReportDialog::OnOpen(wxCommandEvent& ) +{ + const int sel = m_checklst->GetSelection(); + wxCHECK_RET( sel != wxNOT_FOUND, _T("invalid selection in OnOpen()") ); + + wxFileName fn(m_dbgrpt.GetDirectory(), m_files[sel]); + + // try to get the command to open this kind of files ourselves + wxString command; +#if wxUSE_MIMETYPE + wxFileType * + ft = wxTheMimeTypesManager->GetFileTypeFromExtension(fn.GetExt()); + if ( ft ) + { + command = ft->GetOpenCommand(fn.GetFullPath()); + delete ft; + } +#endif // wxUSE_MIMETYPE + + // if we couldn't, ask the user + if ( command.empty() ) + { + wxDumpOpenExternalDlg dlg(this, fn); + if ( dlg.ShowModal() == wxID_OK ) + { + // get the command chosen by the user and append file name to it + + // if we don't have place marker for file name in the command... + wxString cmd = dlg.GetCommand(); + if ( !cmd.empty() ) + { +#if wxUSE_MIMETYPE + if ( cmd.find(_T('%')) != wxString::npos ) + { + command = wxFileType::ExpandCommand(cmd, fn.GetFullPath()); + } + else // no %s nor %1 +#endif // wxUSE_MIMETYPE + { + // append the file name to the end + command << cmd << _T(" \"") << fn.GetFullPath() << _T('"'); + } + } + } + } + + if ( !command.empty() ) + ::wxExecute(command); +} + +void wxDebugReportDialog::OnViewUpdate(wxUpdateUIEvent& event) +{ + int sel = m_checklst->GetSelection(); + if (sel >= 0) + { + wxFileName fn(m_dbgrpt.GetDirectory(), m_files[sel]); + event.Enable(fn.FileExists()); + } + else + event.Enable(false); +} + + +// ============================================================================ +// wxDebugReportPreviewStd implementation +// ============================================================================ + +bool wxDebugReportPreviewStd::Show(wxDebugReport& dbgrpt) const +{ + if ( !dbgrpt.GetFilesCount() ) + return false; + + wxDebugReportDialog dlg(dbgrpt); + +#ifdef __WXMSW__ + // before entering the event loop (from ShowModal()), block the event + // handling for all other windows as this could result in more crashes + wxEventLoop::SetCriticalWindow(&dlg); +#endif // __WXMSW__ + + return dlg.ShowModal() == wxID_OK && dbgrpt.GetFilesCount() != 0; +} + +#endif // wxUSE_DEBUGREPORT && wxUSE_XML diff --git a/Externals/wxWidgets/src/generic/dcpsg.cpp b/Externals/wxWidgets/src/generic/dcpsg.cpp index eb33a8908f..e23fe15214 100644 --- a/Externals/wxWidgets/src/generic/dcpsg.cpp +++ b/Externals/wxWidgets/src/generic/dcpsg.cpp @@ -1,2264 +1,2264 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/generic/dcpsg.cpp -// Purpose: Generic wxPostScriptDC implementation -// Author: Julian Smart, Robert Roebling, Markus Holzhem -// Modified by: -// Created: 04/01/98 -// RCS-ID: $Id: dcpsg.cpp 50711 2007-12-15 02:57:58Z VZ $ -// Copyright: (c) Julian Smart -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_PRINTING_ARCHITECTURE && wxUSE_POSTSCRIPT - -#include "wx/generic/dcpsg.h" - -#ifndef WX_PRECOMP - #include "wx/intl.h" - #include "wx/log.h" - #include "wx/utils.h" - #include "wx/dcmemory.h" - #include "wx/math.h" - #include "wx/image.h" - #include "wx/icon.h" -#endif // WX_PRECOMP - -#include "wx/prntbase.h" -#include "wx/generic/prntdlgg.h" -#include "wx/paper.h" -#include "wx/filefn.h" -#include "wx/stdpaths.h" - -WXDLLIMPEXP_DATA_CORE(int) wxPageNumber; - -#ifdef __WXMSW__ - -#ifdef DrawText -#undef DrawText -#endif - -#ifdef StartDoc -#undef StartDoc -#endif - -#ifdef GetCharWidth -#undef GetCharWidth -#endif - -#ifdef FindWindow -#undef FindWindow -#endif - -#endif - -//----------------------------------------------------------------------------- -// start and end of document/page -//----------------------------------------------------------------------------- - -static const char *wxPostScriptHeaderConicTo = "\ -/conicto {\n\ - /to_y exch def\n\ - /to_x exch def\n\ - /conic_cntrl_y exch def\n\ - /conic_cntrl_x exch def\n\ - currentpoint\n\ - /p0_y exch def\n\ - /p0_x exch def\n\ - /p1_x p0_x conic_cntrl_x p0_x sub 2 3 div mul add def\n\ - /p1_y p0_y conic_cntrl_y p0_y sub 2 3 div mul add def\n\ - /p2_x p1_x to_x p0_x sub 1 3 div mul add def\n\ - /p2_y p1_y to_y p0_y sub 1 3 div mul add def\n\ - p1_x p1_y p2_x p2_y to_x to_y curveto\n\ -} bind def\n\ -"; - -static const char *wxPostScriptHeaderEllipse = "\ -/ellipsedict 8 dict def\n\ -ellipsedict /mtrx matrix put\n\ -/ellipse {\n\ - ellipsedict begin\n\ - /endangle exch def\n\ - /startangle exch def\n\ - /yrad exch def\n\ - /xrad exch def\n\ - /y exch def\n\ - /x exch def\n\ - /savematrix mtrx currentmatrix def\n\ - x y translate\n\ - xrad yrad scale\n\ - 0 0 1 startangle endangle arc\n\ - savematrix setmatrix\n\ - end\n\ - } def\n\ -"; - -static const char *wxPostScriptHeaderEllipticArc= "\ -/ellipticarcdict 8 dict def\n\ -ellipticarcdict /mtrx matrix put\n\ -/ellipticarc\n\ -{ ellipticarcdict begin\n\ - /do_fill exch def\n\ - /endangle exch def\n\ - /startangle exch def\n\ - /yrad exch def\n\ - /xrad exch def \n\ - /y exch def\n\ - /x exch def\n\ - /savematrix mtrx currentmatrix def\n\ - x y translate\n\ - xrad yrad scale\n\ - do_fill { 0 0 moveto } if\n\ - 0 0 1 startangle endangle arc\n\ - savematrix setmatrix\n\ - do_fill { fill }{ stroke } ifelse\n\ - end\n\ -} def\n"; - -static const char *wxPostScriptHeaderSpline = "\ -/DrawSplineSection {\n\ - /y3 exch def\n\ - /x3 exch def\n\ - /y2 exch def\n\ - /x2 exch def\n\ - /y1 exch def\n\ - /x1 exch def\n\ - /xa x1 x2 x1 sub 0.666667 mul add def\n\ - /ya y1 y2 y1 sub 0.666667 mul add def\n\ - /xb x3 x2 x3 sub 0.666667 mul add def\n\ - /yb y3 y2 y3 sub 0.666667 mul add def\n\ - x1 y1 lineto\n\ - xa ya xb yb x3 y3 curveto\n\ - } def\n\ -"; - -static const char *wxPostScriptHeaderColourImage = "\ -% define 'colorimage' if it isn't defined\n\ -% ('colortogray' and 'mergeprocs' come from xwd2ps\n\ -% via xgrab)\n\ -/colorimage where % do we know about 'colorimage'?\n\ - { pop } % yes: pop off the 'dict' returned\n\ - { % no: define one\n\ - /colortogray { % define an RGB->I function\n\ - /rgbdata exch store % call input 'rgbdata'\n\ - rgbdata length 3 idiv\n\ - /npixls exch store\n\ - /rgbindx 0 store\n\ - 0 1 npixls 1 sub {\n\ - grays exch\n\ - rgbdata rgbindx get 20 mul % Red\n\ - rgbdata rgbindx 1 add get 32 mul % Green\n\ - rgbdata rgbindx 2 add get 12 mul % Blue\n\ - add add 64 idiv % I = .5G + .31R + .18B\n\ - put\n\ - /rgbindx rgbindx 3 add store\n\ - } for\n\ - grays 0 npixls getinterval\n\ - } bind def\n\ -\n\ - % Utility procedure for colorimage operator.\n\ - % This procedure takes two procedures off the\n\ - % stack and merges them into a single procedure.\n\ -\n\ - /mergeprocs { % def\n\ - dup length\n\ - 3 -1 roll\n\ - dup\n\ - length\n\ - dup\n\ - 5 1 roll\n\ - 3 -1 roll\n\ - add\n\ - array cvx\n\ - dup\n\ - 3 -1 roll\n\ - 0 exch\n\ - putinterval\n\ - dup\n\ - 4 2 roll\n\ - putinterval\n\ - } bind def\n\ -\n\ - /colorimage { % def\n\ - pop pop % remove 'false 3' operands\n\ - {colortogray} mergeprocs\n\ - image\n\ - } bind def\n\ - } ifelse % end of 'false' case\n\ -"; - -static char wxPostScriptHeaderReencodeISO1[] = - "\n/reencodeISO {\n" -"dup dup findfont dup length dict begin\n" -"{ 1 index /FID ne { def }{ pop pop } ifelse } forall\n" -"/Encoding ISOLatin1Encoding def\n" -"currentdict end definefont\n" -"} def\n" -"/ISOLatin1Encoding [\n" -"/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef\n" -"/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef\n" -"/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef\n" -"/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef\n" -"/space/exclam/quotedbl/numbersign/dollar/percent/ampersand/quoteright\n" -"/parenleft/parenright/asterisk/plus/comma/minus/period/slash\n" -"/zero/one/two/three/four/five/six/seven/eight/nine/colon/semicolon\n" -"/less/equal/greater/question/at/A/B/C/D/E/F/G/H/I/J/K/L/M/N\n" -"/O/P/Q/R/S/T/U/V/W/X/Y/Z/bracketleft/backslash/bracketright\n" -"/asciicircum/underscore/quoteleft/a/b/c/d/e/f/g/h/i/j/k/l/m\n" -"/n/o/p/q/r/s/t/u/v/w/x/y/z/braceleft/bar/braceright/asciitilde\n" -"/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef\n" -"/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef\n" -"/.notdef/dotlessi/grave/acute/circumflex/tilde/macron/breve\n" -"/dotaccent/dieresis/.notdef/ring/cedilla/.notdef/hungarumlaut\n"; - -static char wxPostScriptHeaderReencodeISO2[] = -"/ogonek/caron/space/exclamdown/cent/sterling/currency/yen/brokenbar\n" -"/section/dieresis/copyright/ordfeminine/guillemotleft/logicalnot\n" -"/hyphen/registered/macron/degree/plusminus/twosuperior/threesuperior\n" -"/acute/mu/paragraph/periodcentered/cedilla/onesuperior/ordmasculine\n" -"/guillemotright/onequarter/onehalf/threequarters/questiondown\n" -"/Agrave/Aacute/Acircumflex/Atilde/Adieresis/Aring/AE/Ccedilla\n" -"/Egrave/Eacute/Ecircumflex/Edieresis/Igrave/Iacute/Icircumflex\n" -"/Idieresis/Eth/Ntilde/Ograve/Oacute/Ocircumflex/Otilde/Odieresis\n" -"/multiply/Oslash/Ugrave/Uacute/Ucircumflex/Udieresis/Yacute\n" -"/Thorn/germandbls/agrave/aacute/acircumflex/atilde/adieresis\n" -"/aring/ae/ccedilla/egrave/eacute/ecircumflex/edieresis/igrave\n" -"/iacute/icircumflex/idieresis/eth/ntilde/ograve/oacute/ocircumflex\n" -"/otilde/odieresis/divide/oslash/ugrave/uacute/ucircumflex/udieresis\n" -"/yacute/thorn/ydieresis\n" - "] def\n\n"; - -//------------------------------------------------------------------------------- -// wxPostScriptDC -//------------------------------------------------------------------------------- - -IMPLEMENT_DYNAMIC_CLASS(wxPostScriptDC, wxDC) - -float wxPostScriptDC::ms_PSScaleFactor = 1.0; - -void wxPostScriptDC::SetResolution(int ppi) -{ - ms_PSScaleFactor = (float)ppi / 72.0; -} - -int wxPostScriptDC::GetResolution() -{ - return (int)(ms_PSScaleFactor * 72.0); -} - -//------------------------------------------------------------------------------- - -wxPostScriptDC::wxPostScriptDC () -{ - m_pstream = (FILE*) NULL; - - m_currentRed = 0; - m_currentGreen = 0; - m_currentBlue = 0; - - m_pageNumber = 0; - - m_clipping = false; - - m_underlinePosition = 0.0; - m_underlineThickness = 0.0; - - m_signX = 1; // default x-axis left to right - m_signY = -1; // default y-axis bottom up -> top down -} - -wxPostScriptDC::wxPostScriptDC (const wxPrintData& printData) -{ - m_pstream = (FILE*) NULL; - - m_currentRed = 0; - m_currentGreen = 0; - m_currentBlue = 0; - - m_pageNumber = 0; - - m_clipping = false; - - m_underlinePosition = 0.0; - m_underlineThickness = 0.0; - - m_signX = 1; // default x-axis left to right - m_signY = -1; // default y-axis bottom up -> top down - - m_printData = printData; - - m_ok = true; -} - -wxPostScriptDC::~wxPostScriptDC () -{ - if (m_pstream) - { - fclose( m_pstream ); - m_pstream = (FILE*) NULL; - } -} - -bool wxPostScriptDC::IsOk() const -{ - return m_ok; -} - -void wxPostScriptDC::DoSetClippingRegion (wxCoord x, wxCoord y, wxCoord w, wxCoord h) -{ - wxCHECK_RET( m_ok , wxT("invalid postscript dc") ); - - if (m_clipping) DestroyClippingRegion(); - - wxDC::DoSetClippingRegion(x, y, w, h); - - m_clipping = true; - - PsPrintf( wxT("gsave\n newpath\n") - wxT("%d %d moveto\n") - wxT("%d %d lineto\n") - wxT("%d %d lineto\n") - wxT("%d %d lineto\n") - wxT("closepath clip newpath\n"), - LogicalToDeviceX(x), LogicalToDeviceY(y), - LogicalToDeviceX(x+w), LogicalToDeviceY(y), - LogicalToDeviceX(x+w), LogicalToDeviceY(y+h), - LogicalToDeviceX(x), LogicalToDeviceY(y+h) ); -} - - -void wxPostScriptDC::DestroyClippingRegion() -{ - wxCHECK_RET( m_ok , wxT("invalid postscript dc") ); - - if (m_clipping) - { - m_clipping = false; - PsPrint( "grestore\n" ); - } - - wxDC::DestroyClippingRegion(); -} - -void wxPostScriptDC::Clear() -{ - // This should fail silently to avoid unnecessary - // asserts - // wxFAIL_MSG( wxT("wxPostScriptDC::Clear not implemented.") ); -} - -bool wxPostScriptDC::DoFloodFill (wxCoord WXUNUSED(x), wxCoord WXUNUSED(y), const wxColour &WXUNUSED(col), int WXUNUSED(style)) -{ - wxFAIL_MSG( wxT("wxPostScriptDC::FloodFill not implemented.") ); - return false; -} - -bool wxPostScriptDC::DoGetPixel (wxCoord WXUNUSED(x), wxCoord WXUNUSED(y), wxColour * WXUNUSED(col)) const -{ - wxFAIL_MSG( wxT("wxPostScriptDC::GetPixel not implemented.") ); - return false; -} - -void wxPostScriptDC::DoCrossHair (wxCoord WXUNUSED(x), wxCoord WXUNUSED(y)) -{ - wxFAIL_MSG( wxT("wxPostScriptDC::CrossHair not implemented.") ); -} - -void wxPostScriptDC::DoDrawLine (wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2) -{ - wxCHECK_RET( m_ok, wxT("invalid postscript dc") ); - - if (m_pen.GetStyle() == wxTRANSPARENT) return; - - SetPen( m_pen ); - - PsPrintf( wxT("newpath\n") - wxT("%d %d moveto\n") - wxT("%d %d lineto\n") - wxT("stroke\n"), - LogicalToDeviceX(x1), LogicalToDeviceY(y1), - LogicalToDeviceX(x2), LogicalToDeviceY (y2) ); - - CalcBoundingBox( x1, y1 ); - CalcBoundingBox( x2, y2 ); -} - -#define RAD2DEG 57.29577951308 - -void wxPostScriptDC::DoDrawArc (wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2, wxCoord xc, wxCoord yc) -{ - wxCHECK_RET( m_ok, wxT("invalid postscript dc") ); - - wxCoord dx = x1 - xc; - wxCoord dy = y1 - yc; - wxCoord radius = (wxCoord) sqrt( (double)(dx*dx+dy*dy) ); - double alpha1, alpha2; - - if (x1 == x2 && y1 == y2) - { - alpha1 = 0.0; - alpha2 = 360.0; - } - else if ( wxIsNullDouble(radius) ) - { - alpha1 = - alpha2 = 0.0; - } - else - { - alpha1 = (x1 - xc == 0) ? - (y1 - yc < 0) ? 90.0 : -90.0 : - -atan2(double(y1-yc), double(x1-xc)) * RAD2DEG; - alpha2 = (x2 - xc == 0) ? - (y2 - yc < 0) ? 90.0 : -90.0 : - -atan2(double(y2-yc), double(x2-xc)) * RAD2DEG; - } - while (alpha1 <= 0) alpha1 += 360; - while (alpha2 <= 0) alpha2 += 360; // adjust angles to be between - while (alpha1 > 360) alpha1 -= 360; // 0 and 360 degree - while (alpha2 > 360) alpha2 -= 360; - - if (m_brush.GetStyle() != wxTRANSPARENT) - { - SetBrush( m_brush ); - - PsPrintf( wxT("newpath\n") - wxT("%d %d %d %d %d %d ellipse\n") - wxT("%d %d lineto\n") - wxT("closepath\n") - wxT("fill\n"), - LogicalToDeviceX(xc), LogicalToDeviceY(yc), LogicalToDeviceXRel(radius), LogicalToDeviceYRel(radius), (wxCoord)alpha1, (wxCoord) alpha2, - LogicalToDeviceX(xc), LogicalToDeviceY(yc) ); - - CalcBoundingBox( xc-radius, yc-radius ); - CalcBoundingBox( xc+radius, yc+radius ); - } - - if (m_pen.GetStyle() != wxTRANSPARENT) - { - SetPen( m_pen ); - - PsPrintf( wxT("newpath\n") - wxT("%d %d %d %d %d %d ellipse\n") - wxT("%d %d lineto\n") - wxT("closepath\n") - wxT("stroke\n"), - LogicalToDeviceX(xc), LogicalToDeviceY(yc), LogicalToDeviceXRel(radius), LogicalToDeviceYRel(radius), (wxCoord)alpha1, (wxCoord) alpha2, - LogicalToDeviceX(xc), LogicalToDeviceY(yc) ); - - CalcBoundingBox( xc-radius, yc-radius ); - CalcBoundingBox( xc+radius, yc+radius ); - } -} - -void wxPostScriptDC::DoDrawEllipticArc(wxCoord x,wxCoord y,wxCoord w,wxCoord h,double sa,double ea) -{ - wxCHECK_RET( m_ok, wxT("invalid postscript dc") ); - - if ( sa >= 360 || sa <= -360 ) - sa -= int(sa/360)*360; - if ( ea >= 360 || ea <=- 360 ) - ea -= int(ea/360)*360; - if ( sa < 0 ) - sa += 360; - if ( ea < 0 ) - ea += 360; - - if ( wxIsSameDouble(sa, ea) ) - { - DrawEllipse(x,y,w,h); - return; - } - - if (m_brush.GetStyle () != wxTRANSPARENT) - { - SetBrush( m_brush ); - - PsPrintf( wxT("newpath\n") - wxT("%d %d %d %d %d %d true ellipticarc\n"), - LogicalToDeviceX(x+w/2), LogicalToDeviceY(y+h/2), - LogicalToDeviceXRel(w/2), LogicalToDeviceYRel(h/2), - (wxCoord)sa, (wxCoord)ea ); - - CalcBoundingBox( x ,y ); - CalcBoundingBox( x+w, y+h ); - } - - if (m_pen.GetStyle () != wxTRANSPARENT) - { - SetPen( m_pen ); - - PsPrintf( wxT("newpath\n") - wxT("%d %d %d %d %d %d false ellipticarc\n"), - LogicalToDeviceX(x+w/2), LogicalToDeviceY(y+h/2), - LogicalToDeviceXRel(w/2), LogicalToDeviceYRel(h/2), - (wxCoord)sa, (wxCoord)ea ); - - CalcBoundingBox( x ,y ); - CalcBoundingBox( x+w, y+h ); - } -} - -void wxPostScriptDC::DoDrawPoint (wxCoord x, wxCoord y) -{ - wxCHECK_RET( m_ok, wxT("invalid postscript dc") ); - - if (m_pen.GetStyle() == wxTRANSPARENT) return; - - SetPen (m_pen); - - PsPrintf( wxT("newpath\n") - wxT("%d %d moveto\n") - wxT("%d %d lineto\n") - wxT("stroke\n"), - LogicalToDeviceX(x), LogicalToDeviceY(y), - LogicalToDeviceX(x+1), LogicalToDeviceY(y) ); - - CalcBoundingBox( x, y ); -} - -void wxPostScriptDC::DoDrawPolygon (int n, wxPoint points[], wxCoord xoffset, wxCoord yoffset, int fillStyle) -{ - wxCHECK_RET( m_ok, wxT("invalid postscript dc") ); - - if (n <= 0) return; - - if (m_brush.GetStyle () != wxTRANSPARENT) - { - SetBrush( m_brush ); - - PsPrint( "newpath\n" ); - - wxCoord xx = LogicalToDeviceX(points[0].x + xoffset); - wxCoord yy = LogicalToDeviceY(points[0].y + yoffset); - - PsPrintf( wxT("%d %d moveto\n"), xx, yy ); - - CalcBoundingBox( points[0].x + xoffset, points[0].y + yoffset ); - - for (int i = 1; i < n; i++) - { - xx = LogicalToDeviceX(points[i].x + xoffset); - yy = LogicalToDeviceY(points[i].y + yoffset); - - PsPrintf( wxT("%d %d lineto\n"), xx, yy ); - - CalcBoundingBox( points[i].x + xoffset, points[i].y + yoffset); - } - - PsPrint( (fillStyle == wxODDEVEN_RULE ? "eofill\n" : "fill\n") ); - } - - if (m_pen.GetStyle () != wxTRANSPARENT) - { - SetPen( m_pen ); - - PsPrint( "newpath\n" ); - - wxCoord xx = LogicalToDeviceX(points[0].x + xoffset); - wxCoord yy = LogicalToDeviceY(points[0].y + yoffset); - - PsPrintf( wxT("%d %d moveto\n"), xx, yy ); - - CalcBoundingBox( points[0].x + xoffset, points[0].y + yoffset ); - - for (int i = 1; i < n; i++) - { - xx = LogicalToDeviceX(points[i].x + xoffset); - yy = LogicalToDeviceY(points[i].y + yoffset); - - PsPrintf( wxT("%d %d lineto\n"), xx, yy ); - - CalcBoundingBox( points[i].x + xoffset, points[i].y + yoffset); - } - - PsPrint( "closepath\n" ); - PsPrint( "stroke\n" ); - } -} - -void wxPostScriptDC::DoDrawPolyPolygon (int n, int count[], wxPoint points[], wxCoord xoffset, wxCoord yoffset, int fillStyle) -{ - wxCHECK_RET( m_ok, wxT("invalid postscript dc") ); - - if (n <= 0) return; - - if (m_brush.GetStyle () != wxTRANSPARENT) - { - SetBrush( m_brush ); - - PsPrint( "newpath\n" ); - - int ofs = 0; - for (int i = 0; i < n; ofs += count[i++]) - { - wxCoord xx = LogicalToDeviceX(points[ofs].x + xoffset); - wxCoord yy = LogicalToDeviceY(points[ofs].y + yoffset); - - PsPrintf( wxT("%d %d moveto\n"), xx, yy ); - - CalcBoundingBox( points[ofs].x + xoffset, points[ofs].y + yoffset ); - - for (int j = 1; j < count[i]; j++) - { - xx = LogicalToDeviceX(points[ofs+j].x + xoffset); - yy = LogicalToDeviceY(points[ofs+j].y + yoffset); - - PsPrintf( wxT("%d %d lineto\n"), xx, yy ); - - CalcBoundingBox( points[ofs+j].x + xoffset, points[ofs+j].y + yoffset); - } - } - PsPrint( (fillStyle == wxODDEVEN_RULE ? "eofill\n" : "fill\n") ); - } - - if (m_pen.GetStyle () != wxTRANSPARENT) - { - SetPen( m_pen ); - - PsPrint( "newpath\n" ); - - int ofs = 0; - for (int i = 0; i < n; ofs += count[i++]) - { - wxCoord xx = LogicalToDeviceX(points[ofs].x + xoffset); - wxCoord yy = LogicalToDeviceY(points[ofs].y + yoffset); - - PsPrintf( wxT("%d %d moveto\n"), xx, yy ); - - CalcBoundingBox( points[ofs].x + xoffset, points[ofs].y + yoffset ); - - for (int j = 1; j < count[i]; j++) - { - xx = LogicalToDeviceX(points[ofs+j].x + xoffset); - yy = LogicalToDeviceY(points[ofs+j].y + yoffset); - - PsPrintf( wxT("%d %d lineto\n"), xx, yy ); - - CalcBoundingBox( points[ofs+j].x + xoffset, points[ofs+j].y + yoffset); - } - } - PsPrint( "closepath\n" ); - PsPrint( "stroke\n" ); - } -} - -void wxPostScriptDC::DoDrawLines (int n, wxPoint points[], wxCoord xoffset, wxCoord yoffset) -{ - wxCHECK_RET( m_ok, wxT("invalid postscript dc") ); - - if (m_pen.GetStyle() == wxTRANSPARENT) return; - - if (n <= 0) return; - - SetPen (m_pen); - - int i; - for ( i =0; i= 128 ) - { - /* Cope with character codes > 127 */ - PsPrintf( wxT("\\%o"), c); - } - else - { - PsPrint(c); - } - } - - PsPrint( ") show\n" ); - - if (m_font.GetUnderlined()) - { - wxCoord uy = (wxCoord)(y + size - m_underlinePosition); - char buffer[100]; - - sprintf( buffer, - "gsave\n" - "%d %d moveto\n" - "%f setlinewidth\n" - "%d %d lineto\n" - "stroke\n" - "grestore\n", - LogicalToDeviceX(x), LogicalToDeviceY(uy), - m_underlineThickness, - LogicalToDeviceX(x + text_w), LogicalToDeviceY(uy) ); - for (i = 0; i < 100; i++) - if (buffer[i] == ',') buffer[i] = '.'; - PsPrint( buffer ); - } - - CalcBoundingBox( x, y ); - CalcBoundingBox( x + size * text.length() * 2/3 , y ); -} - -void wxPostScriptDC::DoDrawRotatedText( const wxString& text, wxCoord x, wxCoord y, double angle ) -{ - if ( wxIsNullDouble(angle) ) - { - DoDrawText(text, x, y); - return; - } - - wxCHECK_RET( m_ok, wxT("invalid postscript dc") ); - - SetFont( m_font ); - - if (m_textForegroundColour.Ok()) - { - unsigned char red = m_textForegroundColour.Red(); - unsigned char blue = m_textForegroundColour.Blue(); - unsigned char green = m_textForegroundColour.Green(); - - if (!m_colour) - { - // Anything not white is black - if (! (red == (unsigned char) 255 && - blue == (unsigned char) 255 && - green == (unsigned char) 255)) - { - red = (unsigned char) 0; - green = (unsigned char) 0; - blue = (unsigned char) 0; - } - } - - // maybe setgray here ? - if (!(red == m_currentRed && green == m_currentGreen && blue == m_currentBlue)) - { - double redPS = (double)(red) / 255.0; - double bluePS = (double)(blue) / 255.0; - double greenPS = (double)(green) / 255.0; - - char buffer[100]; - sprintf( buffer, - "%.8f %.8f %.8f setrgbcolor\n", - redPS, greenPS, bluePS ); - for (int i = 0; i < 100; i++) - if (buffer[i] == ',') buffer[i] = '.'; - PsPrint( buffer ); - - m_currentRed = red; - m_currentBlue = blue; - m_currentGreen = green; - } - } - - int size = m_font.GetPointSize(); - - PsPrintf( wxT("%d %d moveto\n"), - LogicalToDeviceX(x), LogicalToDeviceY(y)); - - char buffer[100]; - sprintf(buffer, "%.8f rotate\n", angle); - size_t i; - for (i = 0; i < 100; i++) - { - if (buffer[i] == ',') buffer[i] = '.'; - } - PsPrint( buffer); - - PsPrint( "(" ); - const wxWX2MBbuf textbuf = text.mb_str(); - size_t len = strlen(textbuf); - for (i = 0; i < len; i++) - { - int c = (unsigned char) textbuf[i]; - if (c == ')' || c == '(' || c == '\\') - { - /* Cope with special characters */ - PsPrint( "\\" ); - PsPrint(c); - } - else if ( c >= 128 ) - { - /* Cope with character codes > 127 */ - PsPrintf( wxT("\\%o"), c); - } - else - { - PsPrint(c); - } - } - - PsPrint( ") show\n" ); - - sprintf( buffer, "%.8f rotate\n", -angle ); - for (i = 0; i < 100; i++) - { - if (buffer[i] == ',') buffer[i] = '.'; - } - PsPrint( buffer ); - - if (m_font.GetUnderlined()) - { - wxCoord uy = (wxCoord)(y + size - m_underlinePosition); - wxCoord w, h; - GetTextExtent(text, &w, &h); - - sprintf( buffer, - "gsave\n" - "%d %d moveto\n" - "%f setlinewidth\n" - "%d %d lineto\n" - "stroke\n" - "grestore\n", - LogicalToDeviceX(x), LogicalToDeviceY(uy), - m_underlineThickness, - LogicalToDeviceX(x + w), LogicalToDeviceY(uy) ); - for (i = 0; i < 100; i++) - { - if (buffer[i] == ',') buffer[i] = '.'; - } - PsPrint( buffer ); - } - - CalcBoundingBox( x, y ); - CalcBoundingBox( x + size * text.length() * 2/3 , y ); -} - -void wxPostScriptDC::SetBackground (const wxBrush& brush) -{ - m_backgroundBrush = brush; -} - -void wxPostScriptDC::SetLogicalFunction (int WXUNUSED(function)) -{ - wxFAIL_MSG( wxT("wxPostScriptDC::SetLogicalFunction not implemented.") ); -} - -#if wxUSE_SPLINES -void wxPostScriptDC::DoDrawSpline( wxList *points ) -{ - wxCHECK_RET( m_ok, wxT("invalid postscript dc") ); - - SetPen( m_pen ); - - // a and b are not used - //double a, b; - double c, d, x1, y1, x2, y2, x3, y3; - wxPoint *p, *q; - - wxList::compatibility_iterator node = points->GetFirst(); - p = (wxPoint *)node->GetData(); - x1 = p->x; - y1 = p->y; - - node = node->GetNext(); - p = (wxPoint *)node->GetData(); - c = p->x; - d = p->y; - x3 = - #if 0 - a = - #endif - (double)(x1 + c) / 2; - y3 = - #if 0 - b = - #endif - (double)(y1 + d) / 2; - - PsPrintf( wxT("newpath\n") - wxT("%d %d moveto\n") - wxT("%d %d lineto\n"), - LogicalToDeviceX((wxCoord)x1), LogicalToDeviceY((wxCoord)y1), - LogicalToDeviceX((wxCoord)x3), LogicalToDeviceY((wxCoord)y3) ); - - CalcBoundingBox( (wxCoord)x1, (wxCoord)y1 ); - CalcBoundingBox( (wxCoord)x3, (wxCoord)y3 ); - - node = node->GetNext(); - while (node) - { - q = (wxPoint *)node->GetData(); - - x1 = x3; - y1 = y3; - x2 = c; - y2 = d; - c = q->x; - d = q->y; - x3 = (double)(x2 + c) / 2; - y3 = (double)(y2 + d) / 2; - - PsPrintf( wxT("%d %d %d %d %d %d DrawSplineSection\n"), - LogicalToDeviceX((wxCoord)x1), LogicalToDeviceY((wxCoord)y1), - LogicalToDeviceX((wxCoord)x2), LogicalToDeviceY((wxCoord)y2), - LogicalToDeviceX((wxCoord)x3), LogicalToDeviceY((wxCoord)y3) ); - - CalcBoundingBox( (wxCoord)x1, (wxCoord)y1 ); - CalcBoundingBox( (wxCoord)x3, (wxCoord)y3 ); - - node = node->GetNext(); - } - - /* - At this point, (x2,y2) and (c,d) are the position of the - next-to-last and last point respectively, in the point list - */ - - PsPrintf( wxT("%d %d lineto\n") - wxT("stroke\n"), - LogicalToDeviceX((wxCoord)c), LogicalToDeviceY((wxCoord)d) ); -} -#endif // wxUSE_SPLINES - -wxCoord wxPostScriptDC::GetCharWidth() const -{ - // Chris Breeze: reasonable approximation using wxMODERN/Courier - return (wxCoord) (GetCharHeight() * 72.0 / 120.0); -} - - -void wxPostScriptDC::SetAxisOrientation( bool xLeftRight, bool yBottomUp ) -{ - wxCHECK_RET( m_ok, wxT("invalid postscript dc") ); - - m_signX = (xLeftRight ? 1 : -1); - m_signY = (yBottomUp ? 1 : -1); - - ComputeScaleAndOrigin(); -} - -void wxPostScriptDC::SetDeviceOrigin( wxCoord x, wxCoord y ) -{ - wxCHECK_RET( m_ok, wxT("invalid postscript dc") ); - - int h = 0; - int w = 0; - GetSize( &w, &h ); - - wxDC::SetDeviceOrigin( x, h-y ); -} - -void wxPostScriptDC::DoGetSize(int* width, int* height) const -{ - wxPaperSize id = m_printData.GetPaperId(); - - wxPrintPaperType *paper = wxThePrintPaperDatabase->FindPaperType(id); - - if (!paper) paper = wxThePrintPaperDatabase->FindPaperType(wxPAPER_A4); - - int w = 595; - int h = 842; - if (paper) - { - w = paper->GetSizeDeviceUnits().x; - h = paper->GetSizeDeviceUnits().y; - } - - if (m_printData.GetOrientation() == wxLANDSCAPE) - { - int tmp = w; - w = h; - h = tmp; - } - - if (width) *width = (int)(w * ms_PSScaleFactor); - if (height) *height = (int)(h * ms_PSScaleFactor); -} - -void wxPostScriptDC::DoGetSizeMM(int *width, int *height) const -{ - wxPaperSize id = m_printData.GetPaperId(); - - wxPrintPaperType *paper = wxThePrintPaperDatabase->FindPaperType(id); - - if (!paper) paper = wxThePrintPaperDatabase->FindPaperType(wxPAPER_A4); - - int w = 210; - int h = 297; - if (paper) - { - w = paper->GetWidth() / 10; - h = paper->GetHeight() / 10; - } - - if (m_printData.GetOrientation() == wxLANDSCAPE) - { - int tmp = w; - w = h; - h = tmp; - } - - if (width) *width = w; - if (height) *height = h; -} - -// Resolution in pixels per logical inch -wxSize wxPostScriptDC::GetPPI(void) const -{ - return wxSize((int)(72 * ms_PSScaleFactor), - (int)(72 * ms_PSScaleFactor)); -} - - -bool wxPostScriptDC::StartDoc( const wxString& message ) -{ - wxCHECK_MSG( m_ok, false, wxT("invalid postscript dc") ); - - if (m_printData.GetPrintMode() != wxPRINT_MODE_STREAM ) - { - if (m_printData.GetFilename() == wxEmptyString) - { - wxString filename = wxGetTempFileName( wxT("ps") ); - m_printData.SetFilename(filename); - } - - m_pstream = wxFopen( m_printData.GetFilename(), wxT("w+") ); - - if (!m_pstream) - { - wxLogError( _("Cannot open file for PostScript printing!")); - m_ok = false; - return false; - } - } - - m_ok = true; - m_title = message; - - PsPrint( "%!PS-Adobe-2.0\n" ); - PsPrintf( wxT("%%%%Title: %s\n"), m_title.c_str() ); - PsPrint( "%%Creator: wxWidgets PostScript renderer\n" ); - PsPrintf( wxT("%%%%CreationDate: %s\n"), wxNow().c_str() ); - if (m_printData.GetOrientation() == wxLANDSCAPE) - PsPrint( "%%Orientation: Landscape\n" ); - else - PsPrint( "%%Orientation: Portrait\n" ); - - // PsPrintf( wxT("%%%%Pages: %d\n"), (wxPageNumber - 1) ); - - const wxChar *paper; - switch (m_printData.GetPaperId()) - { - case wxPAPER_LETTER: paper = wxT("Letter"); break; // Letter: paper ""; 8 1/2 by 11 inches - case wxPAPER_LEGAL: paper = wxT("Legal"); break; // Legal, 8 1/2 by 14 inches - case wxPAPER_A4: paper = wxT("A4"); break; // A4 Sheet, 210 by 297 millimeters - case wxPAPER_TABLOID: paper = wxT("Tabloid"); break; // Tabloid, 11 by 17 inches - case wxPAPER_LEDGER: paper = wxT("Ledger"); break; // Ledger, 17 by 11 inches - case wxPAPER_STATEMENT: paper = wxT("Statement"); break; // Statement, 5 1/2 by 8 1/2 inches - case wxPAPER_EXECUTIVE: paper = wxT("Executive"); break; // Executive, 7 1/4 by 10 1/2 inches - case wxPAPER_A3: paper = wxT("A3"); break; // A3 sheet, 297 by 420 millimeters - case wxPAPER_A5: paper = wxT("A5"); break; // A5 sheet, 148 by 210 millimeters - case wxPAPER_B4: paper = wxT("B4"); break; // B4 sheet, 250 by 354 millimeters - case wxPAPER_B5: paper = wxT("B5"); break; // B5 sheet, 182-by-257-millimeter paper - case wxPAPER_FOLIO: paper = wxT("Folio"); break; // Folio, 8-1/2-by-13-inch paper - case wxPAPER_QUARTO: paper = wxT("Quaro"); break; // Quarto, 215-by-275-millimeter paper - case wxPAPER_10X14: paper = wxT("10x14"); break; // 10-by-14-inch sheet - default: paper = wxT("A4"); - } - PsPrintf( wxT("%%%%DocumentPaperSizes: %s\n"), paper ); - PsPrint( "%%EndComments\n\n" ); - - PsPrint( "%%BeginProlog\n" ); - PsPrint( wxPostScriptHeaderConicTo ); - PsPrint( wxPostScriptHeaderEllipse ); - PsPrint( wxPostScriptHeaderEllipticArc ); - PsPrint( wxPostScriptHeaderColourImage ); - PsPrint( wxPostScriptHeaderReencodeISO1 ); - PsPrint( wxPostScriptHeaderReencodeISO2 ); - if (wxPostScriptHeaderSpline) - PsPrint( wxPostScriptHeaderSpline ); - PsPrint( "%%EndProlog\n" ); - - SetBrush( *wxBLACK_BRUSH ); - SetPen( *wxBLACK_PEN ); - SetBackground( *wxWHITE_BRUSH ); - SetTextForeground( *wxBLACK ); - - // set origin according to paper size - SetDeviceOrigin( 0,0 ); - - wxPageNumber = 1; - m_pageNumber = 1; - return true; -} - -void wxPostScriptDC::EndDoc () -{ - wxCHECK_RET( m_ok, wxT("invalid postscript dc") ); - - if (m_clipping) - { - m_clipping = false; - PsPrint( "grestore\n" ); - } - - if ( m_pstream ) { - fclose( m_pstream ); - m_pstream = (FILE *) NULL; - } - -#if 0 - // THE FOLLOWING HAS BEEN CONTRIBUTED BY Andy Fyfe - wxCoord wx_printer_translate_x, wx_printer_translate_y; - double wx_printer_scale_x, wx_printer_scale_y; - - wx_printer_translate_x = (wxCoord)m_printData.GetPrinterTranslateX(); - wx_printer_translate_y = (wxCoord)m_printData.GetPrinterTranslateY(); - - wx_printer_scale_x = m_printData.GetPrinterScaleX(); - wx_printer_scale_y = m_printData.GetPrinterScaleY(); - - // Compute the bounding box. Note that it is in the default user - // coordinate system, thus we have to convert the values. - wxCoord minX = (wxCoord) LogicalToDeviceX(m_minX); - wxCoord minY = (wxCoord) LogicalToDeviceY(m_minY); - wxCoord maxX = (wxCoord) LogicalToDeviceX(m_maxX); - wxCoord maxY = (wxCoord) LogicalToDeviceY(m_maxY); - - // LOG2DEV may have changed the minimum to maximum vice versa - if ( minX > maxX ) { wxCoord tmp = minX; minX = maxX; maxX = tmp; } - if ( minY > maxY ) { wxCoord tmp = minY; minY = maxY; maxY = tmp; } - - // account for used scaling (boundingbox is before scaling in ps-file) - double scale_x = m_printData.GetPrinterScaleX() / ms_PSScaleFactor; - double scale_y = m_printData.GetPrinterScaleY() / ms_PSScaleFactor; - - wxCoord llx, lly, urx, ury; - llx = (wxCoord) ((minX+wx_printer_translate_x)*scale_x); - lly = (wxCoord) ((minY+wx_printer_translate_y)*scale_y); - urx = (wxCoord) ((maxX+wx_printer_translate_x)*scale_x); - ury = (wxCoord) ((maxY+wx_printer_translate_y)*scale_y); - // (end of bounding box computation) - - - // If we're landscape, our sense of "x" and "y" is reversed. - if (m_printData.GetOrientation() == wxLANDSCAPE) - { - wxCoord tmp; - tmp = llx; llx = lly; lly = tmp; - tmp = urx; urx = ury; ury = tmp; - - // We need either the two lines that follow, or we need to subtract - // min_x from real_translate_y, which is commented out below. - llx = llx - (wxCoord)(m_minX*wx_printer_scale_y); - urx = urx - (wxCoord)(m_minX*wx_printer_scale_y); - } - - // The Adobe specifications call for integers; we round as to make - // the bounding larger. - PsPrintf( wxT("%%%%BoundingBox: %d %d %d %d\n"), - (wxCoord)floor((double)llx), (wxCoord)floor((double)lly), - (wxCoord)ceil((double)urx), (wxCoord)ceil((double)ury) ); - - // To check the correctness of the bounding box, postscript commands - // to draw a box corresponding to the bounding box are generated below. - // But since we typically don't want to print such a box, the postscript - // commands are generated within comments. These lines appear before any - // adjustment of scale, rotation, or translation, and hence are in the - // default user coordinates. - PsPrint( "% newpath\n" ); - PsPrintf( wxT("%% %d %d moveto\n"), llx, lly ); - PsPrintf( wxT("%% %d %d lineto\n"), urx, lly ); - PsPrintf( wxT("%% %d %d lineto\n"), urx, ury ); - PsPrintf( wxT("%% %d %d lineto closepath stroke\n"), llx, ury ); -#endif - -#ifndef __WXMSW__ - wxPostScriptPrintNativeData *data = - (wxPostScriptPrintNativeData *) m_printData.GetNativeData(); - - if (m_ok && (m_printData.GetPrintMode() == wxPRINT_MODE_PRINTER)) - { - wxString command; - command += data->GetPrinterCommand(); - command += wxT(" "); - command += data->GetPrinterOptions(); - command += wxT(" "); - command += m_printData.GetFilename(); - - wxExecute( command, true ); - wxRemoveFile( m_printData.GetFilename() ); - } -#endif -} - -void wxPostScriptDC::StartPage() -{ - wxCHECK_RET( m_ok, wxT("invalid postscript dc") ); - - PsPrintf( wxT("%%%%Page: %d\n"), wxPageNumber++ ); - - // What is this one supposed to do? RR. -// *m_pstream << "matrix currentmatrix\n"; - - // Added by Chris Breeze - - // Each page starts with an "initgraphics" which resets the - // transformation and so we need to reset the origin - // (and rotate the page for landscape printing) - - // Output scaling - wxCoord translate_x, translate_y; - double scale_x, scale_y; - - wxPostScriptPrintNativeData *data = - (wxPostScriptPrintNativeData *) m_printData.GetNativeData(); - - translate_x = (wxCoord)data->GetPrinterTranslateX(); - translate_y = (wxCoord)data->GetPrinterTranslateY(); - - scale_x = data->GetPrinterScaleX(); - scale_y = data->GetPrinterScaleY(); - - if (m_printData.GetOrientation() == wxLANDSCAPE) - { - int h; - GetSize( (int*) NULL, &h ); - translate_y -= h; - PsPrint( "90 rotate\n" ); - // I copied this one from a PostScript tutorial, but to no avail. RR. - // PsPrint( "90 rotate llx neg ury nef translate\n" ); - } - - char buffer[100]; - sprintf( buffer, "%.8f %.8f scale\n", scale_x / ms_PSScaleFactor, - scale_y / ms_PSScaleFactor); - for (int i = 0; i < 100; i++) - if (buffer[i] == ',') buffer[i] = '.'; - PsPrint( buffer ); - - PsPrintf( wxT("%d %d translate\n"), translate_x, translate_y ); -} - -void wxPostScriptDC::EndPage () -{ - wxCHECK_RET( m_ok , wxT("invalid postscript dc") ); - - PsPrint( "showpage\n" ); -} - -bool wxPostScriptDC::DoBlit( wxCoord xdest, wxCoord ydest, - wxCoord fwidth, wxCoord fheight, - wxDC *source, - wxCoord xsrc, wxCoord ysrc, - int rop, bool WXUNUSED(useMask), wxCoord WXUNUSED(xsrcMask), wxCoord WXUNUSED(ysrcMask) ) -{ - wxCHECK_MSG( m_ok, false, wxT("invalid postscript dc") ); - - wxCHECK_MSG( source, false, wxT("invalid source dc") ); - - /* blit into a bitmap */ - wxBitmap bitmap( (int)fwidth, (int)fheight ); - wxMemoryDC memDC; - memDC.SelectObject(bitmap); - memDC.Blit(0, 0, fwidth, fheight, source, xsrc, ysrc, rop); /* TODO: Blit transparently? */ - memDC.SelectObject(wxNullBitmap); - - /* draw bitmap. scaling and positioning is done there */ - DrawBitmap( bitmap, xdest, ydest ); - - return true; -} - -wxCoord wxPostScriptDC::GetCharHeight() const -{ - if (m_font.Ok()) - return m_font.GetPointSize(); - else - return 12; -} - -void wxPostScriptDC::DoGetTextExtent(const wxString& string, - wxCoord *x, wxCoord *y, - wxCoord *descent, wxCoord *externalLeading, - wxFont *theFont ) const -{ - wxFont *fontToUse = theFont; - - if (!fontToUse) fontToUse = (wxFont*) &m_font; - - wxCHECK_RET( fontToUse, wxT("GetTextExtent: no font defined") ); - - if (string.empty()) - { - if (x) (*x) = 0; - if (y) (*y) = 0; - if (descent) (*descent) = 0; - if (externalLeading) (*externalLeading) = 0; - return; - } - - // GTK 2.0 - - const wxWX2MBbuf strbuf = string.mb_str(); - -#if !wxUSE_AFM_FOR_POSTSCRIPT - /* Provide a VERY rough estimate (avoid using it). - * Produces accurate results for mono-spaced font - * such as Courier (aka wxMODERN) */ - - int height = 12; - if (fontToUse) - { - height = fontToUse->GetPointSize(); - } - if ( x ) - *x = strlen (strbuf) * height * 72 / 120; - if ( y ) - *y = (wxCoord) (height * 1.32); /* allow for descender */ - if (descent) *descent = 0; - if (externalLeading) *externalLeading = 0; -#else - - /* method for calculating string widths in postscript: - / read in the AFM (adobe font metrics) file for the - / actual font, parse it and extract the character widths - / and also the descender. this may be improved, but for now - / it works well. the AFM file is only read in if the - / font is changed. this may be chached in the future. - / calls to GetTextExtent with the font unchanged are rather - / efficient!!! - / - / for each font and style used there is an AFM file necessary. - / currently i have only files for the roman font family. - / I try to get files for the other ones! - / - / CAVE: the size of the string is currently always calculated - / in 'points' (1/72 of an inch). this should later on be - / changed to depend on the mapping mode. - / CAVE: the path to the AFM files must be set before calling this - / function. this is usually done by a call like the following: - / wxSetAFMPath("d:\\wxw161\\afm\\"); - / - / example: - / - / wxPostScriptDC dc(NULL, true); - / if (dc.Ok()){ - / wxSetAFMPath("d:\\wxw161\\afm\\"); - / dc.StartDoc("Test"); - / dc.StartPage(); - / wxCoord w,h; - / dc.SetFont(new wxFont(10, wxROMAN, wxNORMAL, wxNORMAL)); - / dc.GetTextExtent("Hallo",&w,&h); - / dc.EndPage(); - / dc.EndDoc(); - / } - / - / by steve (stefan.hammes@urz.uni-heidelberg.de) - / created: 10.09.94 - / updated: 14.05.95 */ - - /* these static vars are for storing the state between calls */ - static int lastFamily= INT_MIN; - static int lastSize= INT_MIN; - static int lastStyle= INT_MIN; - static int lastWeight= INT_MIN; - static int lastDescender = INT_MIN; - static int lastWidths[256]; /* widths of the characters */ - - double UnderlinePosition = 0.0; - double UnderlineThickness = 0.0; - - // Get actual parameters - int Family = fontToUse->GetFamily(); - int Size = fontToUse->GetPointSize(); - int Style = fontToUse->GetStyle(); - int Weight = fontToUse->GetWeight(); - - // If we have another font, read the font-metrics - if (Family!=lastFamily || Size!=lastSize || Style!=lastStyle || Weight!=lastWeight) - { - // Store actual values - lastFamily = Family; - lastSize = Size; - lastStyle = Style; - lastWeight = Weight; - - const wxChar *name; - - switch (Family) - { - case wxMODERN: - case wxTELETYPE: - { - if ((Style == wxITALIC) && (Weight == wxBOLD)) name = wxT("CourBoO.afm"); - else if ((Style != wxITALIC) && (Weight == wxBOLD)) name = wxT("CourBo.afm"); - else if ((Style == wxITALIC) && (Weight != wxBOLD)) name = wxT("CourO.afm"); - else name = wxT("Cour.afm"); - break; - } - case wxROMAN: - { - if ((Style == wxITALIC) && (Weight == wxBOLD)) name = wxT("TimesBoO.afm"); - else if ((Style != wxITALIC) && (Weight == wxBOLD)) name = wxT("TimesBo.afm"); - else if ((Style == wxITALIC) && (Weight != wxBOLD)) name = wxT("TimesO.afm"); - else name = wxT("TimesRo.afm"); - break; - } - case wxSCRIPT: - { - name = wxT("Zapf.afm"); - break; - } - case wxSWISS: - default: - { - if ((Style == wxITALIC) && (Weight == wxBOLD)) name = wxT("HelvBoO.afm"); - else if ((Style != wxITALIC) && (Weight == wxBOLD)) name = wxT("HelvBo.afm"); - else if ((Style == wxITALIC) && (Weight != wxBOLD)) name = wxT("HelvO.afm"); - else name = wxT("Helv.afm"); - break; - } - } - - FILE *afmFile = NULL; - - // Get the directory of the AFM files - wxString afmName; - - // VZ: I don't know if the cast always works under Unix but it clearly - // never does under Windows where the pointer is - // wxWindowsPrintNativeData and so calling GetFontMetricPath() on - // it just crashes -#ifndef __WIN32__ - wxPostScriptPrintNativeData *data = - wxDynamicCast(m_printData.GetNativeData(), wxPostScriptPrintNativeData); - - if (data && !data->GetFontMetricPath().empty()) - { - afmName = data->GetFontMetricPath(); - afmName << wxFILE_SEP_PATH << name; - } -#endif // __WIN32__ - - if ( !afmName.empty() ) - afmFile = wxFopen(afmName, wxT("r")); - - if ( !afmFile ) - { -#if defined(__UNIX__) && !defined(__VMS__) - afmName = wxGetDataDir(); -#else // !__UNIX__ - afmName = wxStandardPaths::Get().GetDataDir(); -#endif // __UNIX__/!__UNIX__ - - afmName << wxFILE_SEP_PATH -#if defined(__LINUX__) || defined(__FREEBSD__) - << wxT("gs_afm") << wxFILE_SEP_PATH -#else - << wxT("afm") << wxFILE_SEP_PATH -#endif - << name; - afmFile = wxFopen(afmName,wxT("r")); - } - - /* 2. open and process the file - / a short explanation of the AFM format: - / we have for each character a line, which gives its size - / e.g.: - / - / C 63 ; WX 444 ; N question ; B 49 -14 395 676 ; - / - / that means, we have a character with ascii code 63, and width - / (444/1000 * fontSize) points. - / the other data is ignored for now! - / - / when the font has changed, we read in the right AFM file and store the - / character widths in an array, which is processed below (see point 3.). */ - if (afmFile==NULL) - { - wxLogDebug( wxT("GetTextExtent: can't open AFM file '%s'"), afmName.c_str() ); - wxLogDebug( wxT(" using approximate values")); - for (int i=0; i<256; i++) lastWidths[i] = 500; /* an approximate value */ - lastDescender = -150; /* dito. */ - } - else - { - /* init the widths array */ - for(int i=0; i<256; i++) lastWidths[i] = INT_MIN; - /* some variables for holding parts of a line */ - char cString[10], semiString[10], WXString[10]; - char descString[20]; - char upString[30], utString[30]; - char encString[50]; - char line[256]; - int ascii,cWidth; - /* read in the file and parse it */ - while(fgets(line,sizeof(line),afmFile)!=NULL) - { - /* A.) check for descender definition */ - if (strncmp(line,"Descender",9)==0) - { - if ((sscanf(line,"%s%d",descString,&lastDescender)!=2) || - (strcmp(descString,"Descender")!=0)) - { - wxLogDebug( wxT("AFM-file '%s': line '%s' has error (bad descender)"), afmName.c_str(),line ); - } - } - /* JC 1.) check for UnderlinePosition */ - else if(strncmp(line,"UnderlinePosition",17)==0) - { - if ((sscanf(line,"%s%lf",upString,&UnderlinePosition)!=2) || - (strcmp(upString,"UnderlinePosition")!=0)) - { - wxLogDebug( wxT("AFM-file '%s': line '%s' has error (bad UnderlinePosition)"), afmName.c_str(), line ); - } - } - /* JC 2.) check for UnderlineThickness */ - else if(strncmp(line,"UnderlineThickness",18)==0) - { - if ((sscanf(line,"%s%lf",utString,&UnderlineThickness)!=2) || - (strcmp(utString,"UnderlineThickness")!=0)) - { - wxLogDebug( wxT("AFM-file '%s': line '%s' has error (bad UnderlineThickness)"), afmName.c_str(), line ); - } - } - /* JC 3.) check for EncodingScheme */ - else if(strncmp(line,"EncodingScheme",14)==0) - { - if ((sscanf(line,"%s%s",utString,encString)!=2) || - (strcmp(utString,"EncodingScheme")!=0)) - { - wxLogDebug( wxT("AFM-file '%s': line '%s' has error (bad EncodingScheme)"), afmName.c_str(), line ); - } - else if (strncmp(encString, "AdobeStandardEncoding", 21)) - { - wxLogDebug( wxT("AFM-file '%s': line '%s' has error (unsupported EncodingScheme %s)"), - afmName.c_str(),line, encString); - } - } - /* B.) check for char-width */ - else if(strncmp(line,"C ",2)==0) - { - if (sscanf(line,"%s%d%s%s%d",cString,&ascii,semiString,WXString,&cWidth)!=5) - { - wxLogDebug(wxT("AFM-file '%s': line '%s' has an error (bad character width)"),afmName.c_str(),line); - } - if(strcmp(cString,"C")!=0 || strcmp(semiString,";")!=0 || strcmp(WXString,"WX")!=0) - { - wxLogDebug(wxT("AFM-file '%s': line '%s' has a format error"),afmName.c_str(),line); - } - /* printf(" char '%c'=%d has width '%d'\n",ascii,ascii,cWidth); */ - if (ascii>=0 && ascii<256) - { - lastWidths[ascii] = cWidth; /* store width */ - } - else - { - /* MATTHEW: this happens a lot; don't print an error */ - /* wxLogDebug("AFM-file '%s': ASCII value %d out of range",afmName.c_str(),ascii); */ - } - } - /* C.) ignore other entries. */ - } - fclose(afmFile); - } - /* hack to compute correct values for german 'Umlaute' - / the correct way would be to map the character names - / like 'adieresis' to corresp. positions of ISOEnc and read - / these values from AFM files, too. Maybe later ... */ - - // NB: casts to int are needed to suppress gcc 3.3 warnings - lastWidths[196] = lastWidths[(int)'A']; // U+00C4 A Umlaute - lastWidths[228] = lastWidths[(int)'a']; // U+00E4 a Umlaute - lastWidths[214] = lastWidths[(int)'O']; // U+00D6 O Umlaute - lastWidths[246] = lastWidths[(int)'o']; // U+00F6 o Umlaute - lastWidths[220] = lastWidths[(int)'U']; // U+00DC U Umlaute - lastWidths[252] = lastWidths[(int)'u']; // U+00FC u Umlaute - lastWidths[223] = lastWidths[(int)251]; // U+00DF eszett (scharfes s) - - /* JC: calculate UnderlineThickness/UnderlinePosition */ - - // VS: dirty, but is there any better solution? - double *pt; - pt = (double*) &m_underlinePosition; - *pt = LogicalToDeviceYRel((wxCoord)(UnderlinePosition * fontToUse->GetPointSize())) / 1000.0f; - pt = (double*) &m_underlineThickness; - *pt = LogicalToDeviceYRel((wxCoord)(UnderlineThickness * fontToUse->GetPointSize())) / 1000.0f; - - } - - - /* 3. now the font metrics are read in, calc size this - / is done by adding the widths of the characters in the - / string. they are given in 1/1000 of the size! */ - - long sum=0; - wxCoord height=Size; /* by default */ - unsigned char *p; - for(p=(unsigned char *)wxMBSTRINGCAST strbuf; *p; p++) - { - if(lastWidths[*p]== INT_MIN) - { - wxLogDebug(wxT("GetTextExtent: undefined width for character '%c' (%d)"), *p,*p); - sum += lastWidths[(unsigned char)' ']; /* assume space */ - } - else - { - sum += lastWidths[*p]; - } - } - - double widthSum = sum; - widthSum *= Size; - widthSum /= 1000.0F; - - /* add descender to height (it is usually a negative value) */ - //if (lastDescender != INT_MIN) - //{ - // height += (wxCoord)(((-lastDescender)/1000.0F) * Size); /* MATTHEW: forgot scale */ - //} - // - commented by V. Slavik - height already contains descender in it - // (judging from few experiments) - - /* return size values */ - if ( x ) - *x = (wxCoord)widthSum; - if ( y ) - *y = height; - - /* return other parameters */ - if (descent) - { - if(lastDescender!=INT_MIN) - { - *descent = (wxCoord)(((-lastDescender)/1000.0F) * Size); /* MATTHEW: forgot scale */ - } - else - { - *descent = 0; - } - } - - /* currently no idea how to calculate this! */ - if (externalLeading) *externalLeading = 0; -#endif - // Use AFM -} - -// print postscript datas via required method (file, stream) -void wxPostScriptDC::PsPrintf( const wxChar* fmt, ... ) -{ - va_list argptr; - va_start(argptr, fmt); - - PsPrint( wxString::FormatV( fmt, argptr ).c_str() ); -} - -void wxPostScriptDC::PsPrint( const char* psdata ) -{ - wxPostScriptPrintNativeData *data = - (wxPostScriptPrintNativeData *) m_printData.GetNativeData(); - - switch (m_printData.GetPrintMode()) - { -#if wxUSE_STREAMS - // append to output stream - case wxPRINT_MODE_STREAM: - { - wxOutputStream* outputstream = data->GetOutputStream(); - wxCHECK_RET( outputstream, wxT("invalid outputstream") ); - outputstream->Write( psdata, strlen( psdata ) ); - } - break; -#endif // wxUSE_STREAMS - - // save data into file - default: - wxCHECK_RET( m_pstream, wxT("invalid postscript dc") ); - fwrite( psdata, 1, strlen( psdata ), m_pstream ); - } -} - -void wxPostScriptDC::PsPrint( int ch ) -{ - wxPostScriptPrintNativeData *data = - (wxPostScriptPrintNativeData *) m_printData.GetNativeData(); - - switch (m_printData.GetPrintMode()) - { -#if wxUSE_STREAMS - // append to output stream - case wxPRINT_MODE_STREAM: - { - wxOutputStream* outputstream = data->GetOutputStream(); - wxCHECK_RET( outputstream, wxT("invalid outputstream") ); - outputstream->PutC( (char)ch ); - } - break; -#endif // wxUSE_STREAMS - - // save data into file - default: - wxCHECK_RET( m_pstream, wxT("invalid postscript dc") ); - fputc( ch, m_pstream ); - } -} - -#endif // wxUSE_PRINTING_ARCHITECTURE && wxUSE_POSTSCRIPT - -// vi:sts=4:sw=4:et +///////////////////////////////////////////////////////////////////////////// +// Name: src/generic/dcpsg.cpp +// Purpose: Generic wxPostScriptDC implementation +// Author: Julian Smart, Robert Roebling, Markus Holzhem +// Modified by: +// Created: 04/01/98 +// RCS-ID: $Id: dcpsg.cpp 50711 2007-12-15 02:57:58Z VZ $ +// Copyright: (c) Julian Smart +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_PRINTING_ARCHITECTURE && wxUSE_POSTSCRIPT + +#include "wx/generic/dcpsg.h" + +#ifndef WX_PRECOMP + #include "wx/intl.h" + #include "wx/log.h" + #include "wx/utils.h" + #include "wx/dcmemory.h" + #include "wx/math.h" + #include "wx/image.h" + #include "wx/icon.h" +#endif // WX_PRECOMP + +#include "wx/prntbase.h" +#include "wx/generic/prntdlgg.h" +#include "wx/paper.h" +#include "wx/filefn.h" +#include "wx/stdpaths.h" + +WXDLLIMPEXP_DATA_CORE(int) wxPageNumber; + +#ifdef __WXMSW__ + +#ifdef DrawText +#undef DrawText +#endif + +#ifdef StartDoc +#undef StartDoc +#endif + +#ifdef GetCharWidth +#undef GetCharWidth +#endif + +#ifdef FindWindow +#undef FindWindow +#endif + +#endif + +//----------------------------------------------------------------------------- +// start and end of document/page +//----------------------------------------------------------------------------- + +static const char *wxPostScriptHeaderConicTo = "\ +/conicto {\n\ + /to_y exch def\n\ + /to_x exch def\n\ + /conic_cntrl_y exch def\n\ + /conic_cntrl_x exch def\n\ + currentpoint\n\ + /p0_y exch def\n\ + /p0_x exch def\n\ + /p1_x p0_x conic_cntrl_x p0_x sub 2 3 div mul add def\n\ + /p1_y p0_y conic_cntrl_y p0_y sub 2 3 div mul add def\n\ + /p2_x p1_x to_x p0_x sub 1 3 div mul add def\n\ + /p2_y p1_y to_y p0_y sub 1 3 div mul add def\n\ + p1_x p1_y p2_x p2_y to_x to_y curveto\n\ +} bind def\n\ +"; + +static const char *wxPostScriptHeaderEllipse = "\ +/ellipsedict 8 dict def\n\ +ellipsedict /mtrx matrix put\n\ +/ellipse {\n\ + ellipsedict begin\n\ + /endangle exch def\n\ + /startangle exch def\n\ + /yrad exch def\n\ + /xrad exch def\n\ + /y exch def\n\ + /x exch def\n\ + /savematrix mtrx currentmatrix def\n\ + x y translate\n\ + xrad yrad scale\n\ + 0 0 1 startangle endangle arc\n\ + savematrix setmatrix\n\ + end\n\ + } def\n\ +"; + +static const char *wxPostScriptHeaderEllipticArc= "\ +/ellipticarcdict 8 dict def\n\ +ellipticarcdict /mtrx matrix put\n\ +/ellipticarc\n\ +{ ellipticarcdict begin\n\ + /do_fill exch def\n\ + /endangle exch def\n\ + /startangle exch def\n\ + /yrad exch def\n\ + /xrad exch def \n\ + /y exch def\n\ + /x exch def\n\ + /savematrix mtrx currentmatrix def\n\ + x y translate\n\ + xrad yrad scale\n\ + do_fill { 0 0 moveto } if\n\ + 0 0 1 startangle endangle arc\n\ + savematrix setmatrix\n\ + do_fill { fill }{ stroke } ifelse\n\ + end\n\ +} def\n"; + +static const char *wxPostScriptHeaderSpline = "\ +/DrawSplineSection {\n\ + /y3 exch def\n\ + /x3 exch def\n\ + /y2 exch def\n\ + /x2 exch def\n\ + /y1 exch def\n\ + /x1 exch def\n\ + /xa x1 x2 x1 sub 0.666667 mul add def\n\ + /ya y1 y2 y1 sub 0.666667 mul add def\n\ + /xb x3 x2 x3 sub 0.666667 mul add def\n\ + /yb y3 y2 y3 sub 0.666667 mul add def\n\ + x1 y1 lineto\n\ + xa ya xb yb x3 y3 curveto\n\ + } def\n\ +"; + +static const char *wxPostScriptHeaderColourImage = "\ +% define 'colorimage' if it isn't defined\n\ +% ('colortogray' and 'mergeprocs' come from xwd2ps\n\ +% via xgrab)\n\ +/colorimage where % do we know about 'colorimage'?\n\ + { pop } % yes: pop off the 'dict' returned\n\ + { % no: define one\n\ + /colortogray { % define an RGB->I function\n\ + /rgbdata exch store % call input 'rgbdata'\n\ + rgbdata length 3 idiv\n\ + /npixls exch store\n\ + /rgbindx 0 store\n\ + 0 1 npixls 1 sub {\n\ + grays exch\n\ + rgbdata rgbindx get 20 mul % Red\n\ + rgbdata rgbindx 1 add get 32 mul % Green\n\ + rgbdata rgbindx 2 add get 12 mul % Blue\n\ + add add 64 idiv % I = .5G + .31R + .18B\n\ + put\n\ + /rgbindx rgbindx 3 add store\n\ + } for\n\ + grays 0 npixls getinterval\n\ + } bind def\n\ +\n\ + % Utility procedure for colorimage operator.\n\ + % This procedure takes two procedures off the\n\ + % stack and merges them into a single procedure.\n\ +\n\ + /mergeprocs { % def\n\ + dup length\n\ + 3 -1 roll\n\ + dup\n\ + length\n\ + dup\n\ + 5 1 roll\n\ + 3 -1 roll\n\ + add\n\ + array cvx\n\ + dup\n\ + 3 -1 roll\n\ + 0 exch\n\ + putinterval\n\ + dup\n\ + 4 2 roll\n\ + putinterval\n\ + } bind def\n\ +\n\ + /colorimage { % def\n\ + pop pop % remove 'false 3' operands\n\ + {colortogray} mergeprocs\n\ + image\n\ + } bind def\n\ + } ifelse % end of 'false' case\n\ +"; + +static char wxPostScriptHeaderReencodeISO1[] = + "\n/reencodeISO {\n" +"dup dup findfont dup length dict begin\n" +"{ 1 index /FID ne { def }{ pop pop } ifelse } forall\n" +"/Encoding ISOLatin1Encoding def\n" +"currentdict end definefont\n" +"} def\n" +"/ISOLatin1Encoding [\n" +"/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef\n" +"/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef\n" +"/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef\n" +"/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef\n" +"/space/exclam/quotedbl/numbersign/dollar/percent/ampersand/quoteright\n" +"/parenleft/parenright/asterisk/plus/comma/minus/period/slash\n" +"/zero/one/two/three/four/five/six/seven/eight/nine/colon/semicolon\n" +"/less/equal/greater/question/at/A/B/C/D/E/F/G/H/I/J/K/L/M/N\n" +"/O/P/Q/R/S/T/U/V/W/X/Y/Z/bracketleft/backslash/bracketright\n" +"/asciicircum/underscore/quoteleft/a/b/c/d/e/f/g/h/i/j/k/l/m\n" +"/n/o/p/q/r/s/t/u/v/w/x/y/z/braceleft/bar/braceright/asciitilde\n" +"/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef\n" +"/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef\n" +"/.notdef/dotlessi/grave/acute/circumflex/tilde/macron/breve\n" +"/dotaccent/dieresis/.notdef/ring/cedilla/.notdef/hungarumlaut\n"; + +static char wxPostScriptHeaderReencodeISO2[] = +"/ogonek/caron/space/exclamdown/cent/sterling/currency/yen/brokenbar\n" +"/section/dieresis/copyright/ordfeminine/guillemotleft/logicalnot\n" +"/hyphen/registered/macron/degree/plusminus/twosuperior/threesuperior\n" +"/acute/mu/paragraph/periodcentered/cedilla/onesuperior/ordmasculine\n" +"/guillemotright/onequarter/onehalf/threequarters/questiondown\n" +"/Agrave/Aacute/Acircumflex/Atilde/Adieresis/Aring/AE/Ccedilla\n" +"/Egrave/Eacute/Ecircumflex/Edieresis/Igrave/Iacute/Icircumflex\n" +"/Idieresis/Eth/Ntilde/Ograve/Oacute/Ocircumflex/Otilde/Odieresis\n" +"/multiply/Oslash/Ugrave/Uacute/Ucircumflex/Udieresis/Yacute\n" +"/Thorn/germandbls/agrave/aacute/acircumflex/atilde/adieresis\n" +"/aring/ae/ccedilla/egrave/eacute/ecircumflex/edieresis/igrave\n" +"/iacute/icircumflex/idieresis/eth/ntilde/ograve/oacute/ocircumflex\n" +"/otilde/odieresis/divide/oslash/ugrave/uacute/ucircumflex/udieresis\n" +"/yacute/thorn/ydieresis\n" + "] def\n\n"; + +//------------------------------------------------------------------------------- +// wxPostScriptDC +//------------------------------------------------------------------------------- + +IMPLEMENT_DYNAMIC_CLASS(wxPostScriptDC, wxDC) + +float wxPostScriptDC::ms_PSScaleFactor = 1.0; + +void wxPostScriptDC::SetResolution(int ppi) +{ + ms_PSScaleFactor = (float)ppi / 72.0; +} + +int wxPostScriptDC::GetResolution() +{ + return (int)(ms_PSScaleFactor * 72.0); +} + +//------------------------------------------------------------------------------- + +wxPostScriptDC::wxPostScriptDC () +{ + m_pstream = (FILE*) NULL; + + m_currentRed = 0; + m_currentGreen = 0; + m_currentBlue = 0; + + m_pageNumber = 0; + + m_clipping = false; + + m_underlinePosition = 0.0; + m_underlineThickness = 0.0; + + m_signX = 1; // default x-axis left to right + m_signY = -1; // default y-axis bottom up -> top down +} + +wxPostScriptDC::wxPostScriptDC (const wxPrintData& printData) +{ + m_pstream = (FILE*) NULL; + + m_currentRed = 0; + m_currentGreen = 0; + m_currentBlue = 0; + + m_pageNumber = 0; + + m_clipping = false; + + m_underlinePosition = 0.0; + m_underlineThickness = 0.0; + + m_signX = 1; // default x-axis left to right + m_signY = -1; // default y-axis bottom up -> top down + + m_printData = printData; + + m_ok = true; +} + +wxPostScriptDC::~wxPostScriptDC () +{ + if (m_pstream) + { + fclose( m_pstream ); + m_pstream = (FILE*) NULL; + } +} + +bool wxPostScriptDC::IsOk() const +{ + return m_ok; +} + +void wxPostScriptDC::DoSetClippingRegion (wxCoord x, wxCoord y, wxCoord w, wxCoord h) +{ + wxCHECK_RET( m_ok , wxT("invalid postscript dc") ); + + if (m_clipping) DestroyClippingRegion(); + + wxDC::DoSetClippingRegion(x, y, w, h); + + m_clipping = true; + + PsPrintf( wxT("gsave\n newpath\n") + wxT("%d %d moveto\n") + wxT("%d %d lineto\n") + wxT("%d %d lineto\n") + wxT("%d %d lineto\n") + wxT("closepath clip newpath\n"), + LogicalToDeviceX(x), LogicalToDeviceY(y), + LogicalToDeviceX(x+w), LogicalToDeviceY(y), + LogicalToDeviceX(x+w), LogicalToDeviceY(y+h), + LogicalToDeviceX(x), LogicalToDeviceY(y+h) ); +} + + +void wxPostScriptDC::DestroyClippingRegion() +{ + wxCHECK_RET( m_ok , wxT("invalid postscript dc") ); + + if (m_clipping) + { + m_clipping = false; + PsPrint( "grestore\n" ); + } + + wxDC::DestroyClippingRegion(); +} + +void wxPostScriptDC::Clear() +{ + // This should fail silently to avoid unnecessary + // asserts + // wxFAIL_MSG( wxT("wxPostScriptDC::Clear not implemented.") ); +} + +bool wxPostScriptDC::DoFloodFill (wxCoord WXUNUSED(x), wxCoord WXUNUSED(y), const wxColour &WXUNUSED(col), int WXUNUSED(style)) +{ + wxFAIL_MSG( wxT("wxPostScriptDC::FloodFill not implemented.") ); + return false; +} + +bool wxPostScriptDC::DoGetPixel (wxCoord WXUNUSED(x), wxCoord WXUNUSED(y), wxColour * WXUNUSED(col)) const +{ + wxFAIL_MSG( wxT("wxPostScriptDC::GetPixel not implemented.") ); + return false; +} + +void wxPostScriptDC::DoCrossHair (wxCoord WXUNUSED(x), wxCoord WXUNUSED(y)) +{ + wxFAIL_MSG( wxT("wxPostScriptDC::CrossHair not implemented.") ); +} + +void wxPostScriptDC::DoDrawLine (wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2) +{ + wxCHECK_RET( m_ok, wxT("invalid postscript dc") ); + + if (m_pen.GetStyle() == wxTRANSPARENT) return; + + SetPen( m_pen ); + + PsPrintf( wxT("newpath\n") + wxT("%d %d moveto\n") + wxT("%d %d lineto\n") + wxT("stroke\n"), + LogicalToDeviceX(x1), LogicalToDeviceY(y1), + LogicalToDeviceX(x2), LogicalToDeviceY (y2) ); + + CalcBoundingBox( x1, y1 ); + CalcBoundingBox( x2, y2 ); +} + +#define RAD2DEG 57.29577951308 + +void wxPostScriptDC::DoDrawArc (wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2, wxCoord xc, wxCoord yc) +{ + wxCHECK_RET( m_ok, wxT("invalid postscript dc") ); + + wxCoord dx = x1 - xc; + wxCoord dy = y1 - yc; + wxCoord radius = (wxCoord) sqrt( (double)(dx*dx+dy*dy) ); + double alpha1, alpha2; + + if (x1 == x2 && y1 == y2) + { + alpha1 = 0.0; + alpha2 = 360.0; + } + else if ( wxIsNullDouble(radius) ) + { + alpha1 = + alpha2 = 0.0; + } + else + { + alpha1 = (x1 - xc == 0) ? + (y1 - yc < 0) ? 90.0 : -90.0 : + -atan2(double(y1-yc), double(x1-xc)) * RAD2DEG; + alpha2 = (x2 - xc == 0) ? + (y2 - yc < 0) ? 90.0 : -90.0 : + -atan2(double(y2-yc), double(x2-xc)) * RAD2DEG; + } + while (alpha1 <= 0) alpha1 += 360; + while (alpha2 <= 0) alpha2 += 360; // adjust angles to be between + while (alpha1 > 360) alpha1 -= 360; // 0 and 360 degree + while (alpha2 > 360) alpha2 -= 360; + + if (m_brush.GetStyle() != wxTRANSPARENT) + { + SetBrush( m_brush ); + + PsPrintf( wxT("newpath\n") + wxT("%d %d %d %d %d %d ellipse\n") + wxT("%d %d lineto\n") + wxT("closepath\n") + wxT("fill\n"), + LogicalToDeviceX(xc), LogicalToDeviceY(yc), LogicalToDeviceXRel(radius), LogicalToDeviceYRel(radius), (wxCoord)alpha1, (wxCoord) alpha2, + LogicalToDeviceX(xc), LogicalToDeviceY(yc) ); + + CalcBoundingBox( xc-radius, yc-radius ); + CalcBoundingBox( xc+radius, yc+radius ); + } + + if (m_pen.GetStyle() != wxTRANSPARENT) + { + SetPen( m_pen ); + + PsPrintf( wxT("newpath\n") + wxT("%d %d %d %d %d %d ellipse\n") + wxT("%d %d lineto\n") + wxT("closepath\n") + wxT("stroke\n"), + LogicalToDeviceX(xc), LogicalToDeviceY(yc), LogicalToDeviceXRel(radius), LogicalToDeviceYRel(radius), (wxCoord)alpha1, (wxCoord) alpha2, + LogicalToDeviceX(xc), LogicalToDeviceY(yc) ); + + CalcBoundingBox( xc-radius, yc-radius ); + CalcBoundingBox( xc+radius, yc+radius ); + } +} + +void wxPostScriptDC::DoDrawEllipticArc(wxCoord x,wxCoord y,wxCoord w,wxCoord h,double sa,double ea) +{ + wxCHECK_RET( m_ok, wxT("invalid postscript dc") ); + + if ( sa >= 360 || sa <= -360 ) + sa -= int(sa/360)*360; + if ( ea >= 360 || ea <=- 360 ) + ea -= int(ea/360)*360; + if ( sa < 0 ) + sa += 360; + if ( ea < 0 ) + ea += 360; + + if ( wxIsSameDouble(sa, ea) ) + { + DrawEllipse(x,y,w,h); + return; + } + + if (m_brush.GetStyle () != wxTRANSPARENT) + { + SetBrush( m_brush ); + + PsPrintf( wxT("newpath\n") + wxT("%d %d %d %d %d %d true ellipticarc\n"), + LogicalToDeviceX(x+w/2), LogicalToDeviceY(y+h/2), + LogicalToDeviceXRel(w/2), LogicalToDeviceYRel(h/2), + (wxCoord)sa, (wxCoord)ea ); + + CalcBoundingBox( x ,y ); + CalcBoundingBox( x+w, y+h ); + } + + if (m_pen.GetStyle () != wxTRANSPARENT) + { + SetPen( m_pen ); + + PsPrintf( wxT("newpath\n") + wxT("%d %d %d %d %d %d false ellipticarc\n"), + LogicalToDeviceX(x+w/2), LogicalToDeviceY(y+h/2), + LogicalToDeviceXRel(w/2), LogicalToDeviceYRel(h/2), + (wxCoord)sa, (wxCoord)ea ); + + CalcBoundingBox( x ,y ); + CalcBoundingBox( x+w, y+h ); + } +} + +void wxPostScriptDC::DoDrawPoint (wxCoord x, wxCoord y) +{ + wxCHECK_RET( m_ok, wxT("invalid postscript dc") ); + + if (m_pen.GetStyle() == wxTRANSPARENT) return; + + SetPen (m_pen); + + PsPrintf( wxT("newpath\n") + wxT("%d %d moveto\n") + wxT("%d %d lineto\n") + wxT("stroke\n"), + LogicalToDeviceX(x), LogicalToDeviceY(y), + LogicalToDeviceX(x+1), LogicalToDeviceY(y) ); + + CalcBoundingBox( x, y ); +} + +void wxPostScriptDC::DoDrawPolygon (int n, wxPoint points[], wxCoord xoffset, wxCoord yoffset, int fillStyle) +{ + wxCHECK_RET( m_ok, wxT("invalid postscript dc") ); + + if (n <= 0) return; + + if (m_brush.GetStyle () != wxTRANSPARENT) + { + SetBrush( m_brush ); + + PsPrint( "newpath\n" ); + + wxCoord xx = LogicalToDeviceX(points[0].x + xoffset); + wxCoord yy = LogicalToDeviceY(points[0].y + yoffset); + + PsPrintf( wxT("%d %d moveto\n"), xx, yy ); + + CalcBoundingBox( points[0].x + xoffset, points[0].y + yoffset ); + + for (int i = 1; i < n; i++) + { + xx = LogicalToDeviceX(points[i].x + xoffset); + yy = LogicalToDeviceY(points[i].y + yoffset); + + PsPrintf( wxT("%d %d lineto\n"), xx, yy ); + + CalcBoundingBox( points[i].x + xoffset, points[i].y + yoffset); + } + + PsPrint( (fillStyle == wxODDEVEN_RULE ? "eofill\n" : "fill\n") ); + } + + if (m_pen.GetStyle () != wxTRANSPARENT) + { + SetPen( m_pen ); + + PsPrint( "newpath\n" ); + + wxCoord xx = LogicalToDeviceX(points[0].x + xoffset); + wxCoord yy = LogicalToDeviceY(points[0].y + yoffset); + + PsPrintf( wxT("%d %d moveto\n"), xx, yy ); + + CalcBoundingBox( points[0].x + xoffset, points[0].y + yoffset ); + + for (int i = 1; i < n; i++) + { + xx = LogicalToDeviceX(points[i].x + xoffset); + yy = LogicalToDeviceY(points[i].y + yoffset); + + PsPrintf( wxT("%d %d lineto\n"), xx, yy ); + + CalcBoundingBox( points[i].x + xoffset, points[i].y + yoffset); + } + + PsPrint( "closepath\n" ); + PsPrint( "stroke\n" ); + } +} + +void wxPostScriptDC::DoDrawPolyPolygon (int n, int count[], wxPoint points[], wxCoord xoffset, wxCoord yoffset, int fillStyle) +{ + wxCHECK_RET( m_ok, wxT("invalid postscript dc") ); + + if (n <= 0) return; + + if (m_brush.GetStyle () != wxTRANSPARENT) + { + SetBrush( m_brush ); + + PsPrint( "newpath\n" ); + + int ofs = 0; + for (int i = 0; i < n; ofs += count[i++]) + { + wxCoord xx = LogicalToDeviceX(points[ofs].x + xoffset); + wxCoord yy = LogicalToDeviceY(points[ofs].y + yoffset); + + PsPrintf( wxT("%d %d moveto\n"), xx, yy ); + + CalcBoundingBox( points[ofs].x + xoffset, points[ofs].y + yoffset ); + + for (int j = 1; j < count[i]; j++) + { + xx = LogicalToDeviceX(points[ofs+j].x + xoffset); + yy = LogicalToDeviceY(points[ofs+j].y + yoffset); + + PsPrintf( wxT("%d %d lineto\n"), xx, yy ); + + CalcBoundingBox( points[ofs+j].x + xoffset, points[ofs+j].y + yoffset); + } + } + PsPrint( (fillStyle == wxODDEVEN_RULE ? "eofill\n" : "fill\n") ); + } + + if (m_pen.GetStyle () != wxTRANSPARENT) + { + SetPen( m_pen ); + + PsPrint( "newpath\n" ); + + int ofs = 0; + for (int i = 0; i < n; ofs += count[i++]) + { + wxCoord xx = LogicalToDeviceX(points[ofs].x + xoffset); + wxCoord yy = LogicalToDeviceY(points[ofs].y + yoffset); + + PsPrintf( wxT("%d %d moveto\n"), xx, yy ); + + CalcBoundingBox( points[ofs].x + xoffset, points[ofs].y + yoffset ); + + for (int j = 1; j < count[i]; j++) + { + xx = LogicalToDeviceX(points[ofs+j].x + xoffset); + yy = LogicalToDeviceY(points[ofs+j].y + yoffset); + + PsPrintf( wxT("%d %d lineto\n"), xx, yy ); + + CalcBoundingBox( points[ofs+j].x + xoffset, points[ofs+j].y + yoffset); + } + } + PsPrint( "closepath\n" ); + PsPrint( "stroke\n" ); + } +} + +void wxPostScriptDC::DoDrawLines (int n, wxPoint points[], wxCoord xoffset, wxCoord yoffset) +{ + wxCHECK_RET( m_ok, wxT("invalid postscript dc") ); + + if (m_pen.GetStyle() == wxTRANSPARENT) return; + + if (n <= 0) return; + + SetPen (m_pen); + + int i; + for ( i =0; i= 128 ) + { + /* Cope with character codes > 127 */ + PsPrintf( wxT("\\%o"), c); + } + else + { + PsPrint(c); + } + } + + PsPrint( ") show\n" ); + + if (m_font.GetUnderlined()) + { + wxCoord uy = (wxCoord)(y + size - m_underlinePosition); + char buffer[100]; + + sprintf( buffer, + "gsave\n" + "%d %d moveto\n" + "%f setlinewidth\n" + "%d %d lineto\n" + "stroke\n" + "grestore\n", + LogicalToDeviceX(x), LogicalToDeviceY(uy), + m_underlineThickness, + LogicalToDeviceX(x + text_w), LogicalToDeviceY(uy) ); + for (i = 0; i < 100; i++) + if (buffer[i] == ',') buffer[i] = '.'; + PsPrint( buffer ); + } + + CalcBoundingBox( x, y ); + CalcBoundingBox( x + size * text.length() * 2/3 , y ); +} + +void wxPostScriptDC::DoDrawRotatedText( const wxString& text, wxCoord x, wxCoord y, double angle ) +{ + if ( wxIsNullDouble(angle) ) + { + DoDrawText(text, x, y); + return; + } + + wxCHECK_RET( m_ok, wxT("invalid postscript dc") ); + + SetFont( m_font ); + + if (m_textForegroundColour.Ok()) + { + unsigned char red = m_textForegroundColour.Red(); + unsigned char blue = m_textForegroundColour.Blue(); + unsigned char green = m_textForegroundColour.Green(); + + if (!m_colour) + { + // Anything not white is black + if (! (red == (unsigned char) 255 && + blue == (unsigned char) 255 && + green == (unsigned char) 255)) + { + red = (unsigned char) 0; + green = (unsigned char) 0; + blue = (unsigned char) 0; + } + } + + // maybe setgray here ? + if (!(red == m_currentRed && green == m_currentGreen && blue == m_currentBlue)) + { + double redPS = (double)(red) / 255.0; + double bluePS = (double)(blue) / 255.0; + double greenPS = (double)(green) / 255.0; + + char buffer[100]; + sprintf( buffer, + "%.8f %.8f %.8f setrgbcolor\n", + redPS, greenPS, bluePS ); + for (int i = 0; i < 100; i++) + if (buffer[i] == ',') buffer[i] = '.'; + PsPrint( buffer ); + + m_currentRed = red; + m_currentBlue = blue; + m_currentGreen = green; + } + } + + int size = m_font.GetPointSize(); + + PsPrintf( wxT("%d %d moveto\n"), + LogicalToDeviceX(x), LogicalToDeviceY(y)); + + char buffer[100]; + sprintf(buffer, "%.8f rotate\n", angle); + size_t i; + for (i = 0; i < 100; i++) + { + if (buffer[i] == ',') buffer[i] = '.'; + } + PsPrint( buffer); + + PsPrint( "(" ); + const wxWX2MBbuf textbuf = text.mb_str(); + size_t len = strlen(textbuf); + for (i = 0; i < len; i++) + { + int c = (unsigned char) textbuf[i]; + if (c == ')' || c == '(' || c == '\\') + { + /* Cope with special characters */ + PsPrint( "\\" ); + PsPrint(c); + } + else if ( c >= 128 ) + { + /* Cope with character codes > 127 */ + PsPrintf( wxT("\\%o"), c); + } + else + { + PsPrint(c); + } + } + + PsPrint( ") show\n" ); + + sprintf( buffer, "%.8f rotate\n", -angle ); + for (i = 0; i < 100; i++) + { + if (buffer[i] == ',') buffer[i] = '.'; + } + PsPrint( buffer ); + + if (m_font.GetUnderlined()) + { + wxCoord uy = (wxCoord)(y + size - m_underlinePosition); + wxCoord w, h; + GetTextExtent(text, &w, &h); + + sprintf( buffer, + "gsave\n" + "%d %d moveto\n" + "%f setlinewidth\n" + "%d %d lineto\n" + "stroke\n" + "grestore\n", + LogicalToDeviceX(x), LogicalToDeviceY(uy), + m_underlineThickness, + LogicalToDeviceX(x + w), LogicalToDeviceY(uy) ); + for (i = 0; i < 100; i++) + { + if (buffer[i] == ',') buffer[i] = '.'; + } + PsPrint( buffer ); + } + + CalcBoundingBox( x, y ); + CalcBoundingBox( x + size * text.length() * 2/3 , y ); +} + +void wxPostScriptDC::SetBackground (const wxBrush& brush) +{ + m_backgroundBrush = brush; +} + +void wxPostScriptDC::SetLogicalFunction (int WXUNUSED(function)) +{ + wxFAIL_MSG( wxT("wxPostScriptDC::SetLogicalFunction not implemented.") ); +} + +#if wxUSE_SPLINES +void wxPostScriptDC::DoDrawSpline( wxList *points ) +{ + wxCHECK_RET( m_ok, wxT("invalid postscript dc") ); + + SetPen( m_pen ); + + // a and b are not used + //double a, b; + double c, d, x1, y1, x2, y2, x3, y3; + wxPoint *p, *q; + + wxList::compatibility_iterator node = points->GetFirst(); + p = (wxPoint *)node->GetData(); + x1 = p->x; + y1 = p->y; + + node = node->GetNext(); + p = (wxPoint *)node->GetData(); + c = p->x; + d = p->y; + x3 = + #if 0 + a = + #endif + (double)(x1 + c) / 2; + y3 = + #if 0 + b = + #endif + (double)(y1 + d) / 2; + + PsPrintf( wxT("newpath\n") + wxT("%d %d moveto\n") + wxT("%d %d lineto\n"), + LogicalToDeviceX((wxCoord)x1), LogicalToDeviceY((wxCoord)y1), + LogicalToDeviceX((wxCoord)x3), LogicalToDeviceY((wxCoord)y3) ); + + CalcBoundingBox( (wxCoord)x1, (wxCoord)y1 ); + CalcBoundingBox( (wxCoord)x3, (wxCoord)y3 ); + + node = node->GetNext(); + while (node) + { + q = (wxPoint *)node->GetData(); + + x1 = x3; + y1 = y3; + x2 = c; + y2 = d; + c = q->x; + d = q->y; + x3 = (double)(x2 + c) / 2; + y3 = (double)(y2 + d) / 2; + + PsPrintf( wxT("%d %d %d %d %d %d DrawSplineSection\n"), + LogicalToDeviceX((wxCoord)x1), LogicalToDeviceY((wxCoord)y1), + LogicalToDeviceX((wxCoord)x2), LogicalToDeviceY((wxCoord)y2), + LogicalToDeviceX((wxCoord)x3), LogicalToDeviceY((wxCoord)y3) ); + + CalcBoundingBox( (wxCoord)x1, (wxCoord)y1 ); + CalcBoundingBox( (wxCoord)x3, (wxCoord)y3 ); + + node = node->GetNext(); + } + + /* + At this point, (x2,y2) and (c,d) are the position of the + next-to-last and last point respectively, in the point list + */ + + PsPrintf( wxT("%d %d lineto\n") + wxT("stroke\n"), + LogicalToDeviceX((wxCoord)c), LogicalToDeviceY((wxCoord)d) ); +} +#endif // wxUSE_SPLINES + +wxCoord wxPostScriptDC::GetCharWidth() const +{ + // Chris Breeze: reasonable approximation using wxMODERN/Courier + return (wxCoord) (GetCharHeight() * 72.0 / 120.0); +} + + +void wxPostScriptDC::SetAxisOrientation( bool xLeftRight, bool yBottomUp ) +{ + wxCHECK_RET( m_ok, wxT("invalid postscript dc") ); + + m_signX = (xLeftRight ? 1 : -1); + m_signY = (yBottomUp ? 1 : -1); + + ComputeScaleAndOrigin(); +} + +void wxPostScriptDC::SetDeviceOrigin( wxCoord x, wxCoord y ) +{ + wxCHECK_RET( m_ok, wxT("invalid postscript dc") ); + + int h = 0; + int w = 0; + GetSize( &w, &h ); + + wxDC::SetDeviceOrigin( x, h-y ); +} + +void wxPostScriptDC::DoGetSize(int* width, int* height) const +{ + wxPaperSize id = m_printData.GetPaperId(); + + wxPrintPaperType *paper = wxThePrintPaperDatabase->FindPaperType(id); + + if (!paper) paper = wxThePrintPaperDatabase->FindPaperType(wxPAPER_A4); + + int w = 595; + int h = 842; + if (paper) + { + w = paper->GetSizeDeviceUnits().x; + h = paper->GetSizeDeviceUnits().y; + } + + if (m_printData.GetOrientation() == wxLANDSCAPE) + { + int tmp = w; + w = h; + h = tmp; + } + + if (width) *width = (int)(w * ms_PSScaleFactor); + if (height) *height = (int)(h * ms_PSScaleFactor); +} + +void wxPostScriptDC::DoGetSizeMM(int *width, int *height) const +{ + wxPaperSize id = m_printData.GetPaperId(); + + wxPrintPaperType *paper = wxThePrintPaperDatabase->FindPaperType(id); + + if (!paper) paper = wxThePrintPaperDatabase->FindPaperType(wxPAPER_A4); + + int w = 210; + int h = 297; + if (paper) + { + w = paper->GetWidth() / 10; + h = paper->GetHeight() / 10; + } + + if (m_printData.GetOrientation() == wxLANDSCAPE) + { + int tmp = w; + w = h; + h = tmp; + } + + if (width) *width = w; + if (height) *height = h; +} + +// Resolution in pixels per logical inch +wxSize wxPostScriptDC::GetPPI(void) const +{ + return wxSize((int)(72 * ms_PSScaleFactor), + (int)(72 * ms_PSScaleFactor)); +} + + +bool wxPostScriptDC::StartDoc( const wxString& message ) +{ + wxCHECK_MSG( m_ok, false, wxT("invalid postscript dc") ); + + if (m_printData.GetPrintMode() != wxPRINT_MODE_STREAM ) + { + if (m_printData.GetFilename() == wxEmptyString) + { + wxString filename = wxGetTempFileName( wxT("ps") ); + m_printData.SetFilename(filename); + } + + m_pstream = wxFopen( m_printData.GetFilename(), wxT("w+") ); + + if (!m_pstream) + { + wxLogError( _("Cannot open file for PostScript printing!")); + m_ok = false; + return false; + } + } + + m_ok = true; + m_title = message; + + PsPrint( "%!PS-Adobe-2.0\n" ); + PsPrintf( wxT("%%%%Title: %s\n"), m_title.c_str() ); + PsPrint( "%%Creator: wxWidgets PostScript renderer\n" ); + PsPrintf( wxT("%%%%CreationDate: %s\n"), wxNow().c_str() ); + if (m_printData.GetOrientation() == wxLANDSCAPE) + PsPrint( "%%Orientation: Landscape\n" ); + else + PsPrint( "%%Orientation: Portrait\n" ); + + // PsPrintf( wxT("%%%%Pages: %d\n"), (wxPageNumber - 1) ); + + const wxChar *paper; + switch (m_printData.GetPaperId()) + { + case wxPAPER_LETTER: paper = wxT("Letter"); break; // Letter: paper ""; 8 1/2 by 11 inches + case wxPAPER_LEGAL: paper = wxT("Legal"); break; // Legal, 8 1/2 by 14 inches + case wxPAPER_A4: paper = wxT("A4"); break; // A4 Sheet, 210 by 297 millimeters + case wxPAPER_TABLOID: paper = wxT("Tabloid"); break; // Tabloid, 11 by 17 inches + case wxPAPER_LEDGER: paper = wxT("Ledger"); break; // Ledger, 17 by 11 inches + case wxPAPER_STATEMENT: paper = wxT("Statement"); break; // Statement, 5 1/2 by 8 1/2 inches + case wxPAPER_EXECUTIVE: paper = wxT("Executive"); break; // Executive, 7 1/4 by 10 1/2 inches + case wxPAPER_A3: paper = wxT("A3"); break; // A3 sheet, 297 by 420 millimeters + case wxPAPER_A5: paper = wxT("A5"); break; // A5 sheet, 148 by 210 millimeters + case wxPAPER_B4: paper = wxT("B4"); break; // B4 sheet, 250 by 354 millimeters + case wxPAPER_B5: paper = wxT("B5"); break; // B5 sheet, 182-by-257-millimeter paper + case wxPAPER_FOLIO: paper = wxT("Folio"); break; // Folio, 8-1/2-by-13-inch paper + case wxPAPER_QUARTO: paper = wxT("Quaro"); break; // Quarto, 215-by-275-millimeter paper + case wxPAPER_10X14: paper = wxT("10x14"); break; // 10-by-14-inch sheet + default: paper = wxT("A4"); + } + PsPrintf( wxT("%%%%DocumentPaperSizes: %s\n"), paper ); + PsPrint( "%%EndComments\n\n" ); + + PsPrint( "%%BeginProlog\n" ); + PsPrint( wxPostScriptHeaderConicTo ); + PsPrint( wxPostScriptHeaderEllipse ); + PsPrint( wxPostScriptHeaderEllipticArc ); + PsPrint( wxPostScriptHeaderColourImage ); + PsPrint( wxPostScriptHeaderReencodeISO1 ); + PsPrint( wxPostScriptHeaderReencodeISO2 ); + if (wxPostScriptHeaderSpline) + PsPrint( wxPostScriptHeaderSpline ); + PsPrint( "%%EndProlog\n" ); + + SetBrush( *wxBLACK_BRUSH ); + SetPen( *wxBLACK_PEN ); + SetBackground( *wxWHITE_BRUSH ); + SetTextForeground( *wxBLACK ); + + // set origin according to paper size + SetDeviceOrigin( 0,0 ); + + wxPageNumber = 1; + m_pageNumber = 1; + return true; +} + +void wxPostScriptDC::EndDoc () +{ + wxCHECK_RET( m_ok, wxT("invalid postscript dc") ); + + if (m_clipping) + { + m_clipping = false; + PsPrint( "grestore\n" ); + } + + if ( m_pstream ) { + fclose( m_pstream ); + m_pstream = (FILE *) NULL; + } + +#if 0 + // THE FOLLOWING HAS BEEN CONTRIBUTED BY Andy Fyfe + wxCoord wx_printer_translate_x, wx_printer_translate_y; + double wx_printer_scale_x, wx_printer_scale_y; + + wx_printer_translate_x = (wxCoord)m_printData.GetPrinterTranslateX(); + wx_printer_translate_y = (wxCoord)m_printData.GetPrinterTranslateY(); + + wx_printer_scale_x = m_printData.GetPrinterScaleX(); + wx_printer_scale_y = m_printData.GetPrinterScaleY(); + + // Compute the bounding box. Note that it is in the default user + // coordinate system, thus we have to convert the values. + wxCoord minX = (wxCoord) LogicalToDeviceX(m_minX); + wxCoord minY = (wxCoord) LogicalToDeviceY(m_minY); + wxCoord maxX = (wxCoord) LogicalToDeviceX(m_maxX); + wxCoord maxY = (wxCoord) LogicalToDeviceY(m_maxY); + + // LOG2DEV may have changed the minimum to maximum vice versa + if ( minX > maxX ) { wxCoord tmp = minX; minX = maxX; maxX = tmp; } + if ( minY > maxY ) { wxCoord tmp = minY; minY = maxY; maxY = tmp; } + + // account for used scaling (boundingbox is before scaling in ps-file) + double scale_x = m_printData.GetPrinterScaleX() / ms_PSScaleFactor; + double scale_y = m_printData.GetPrinterScaleY() / ms_PSScaleFactor; + + wxCoord llx, lly, urx, ury; + llx = (wxCoord) ((minX+wx_printer_translate_x)*scale_x); + lly = (wxCoord) ((minY+wx_printer_translate_y)*scale_y); + urx = (wxCoord) ((maxX+wx_printer_translate_x)*scale_x); + ury = (wxCoord) ((maxY+wx_printer_translate_y)*scale_y); + // (end of bounding box computation) + + + // If we're landscape, our sense of "x" and "y" is reversed. + if (m_printData.GetOrientation() == wxLANDSCAPE) + { + wxCoord tmp; + tmp = llx; llx = lly; lly = tmp; + tmp = urx; urx = ury; ury = tmp; + + // We need either the two lines that follow, or we need to subtract + // min_x from real_translate_y, which is commented out below. + llx = llx - (wxCoord)(m_minX*wx_printer_scale_y); + urx = urx - (wxCoord)(m_minX*wx_printer_scale_y); + } + + // The Adobe specifications call for integers; we round as to make + // the bounding larger. + PsPrintf( wxT("%%%%BoundingBox: %d %d %d %d\n"), + (wxCoord)floor((double)llx), (wxCoord)floor((double)lly), + (wxCoord)ceil((double)urx), (wxCoord)ceil((double)ury) ); + + // To check the correctness of the bounding box, postscript commands + // to draw a box corresponding to the bounding box are generated below. + // But since we typically don't want to print such a box, the postscript + // commands are generated within comments. These lines appear before any + // adjustment of scale, rotation, or translation, and hence are in the + // default user coordinates. + PsPrint( "% newpath\n" ); + PsPrintf( wxT("%% %d %d moveto\n"), llx, lly ); + PsPrintf( wxT("%% %d %d lineto\n"), urx, lly ); + PsPrintf( wxT("%% %d %d lineto\n"), urx, ury ); + PsPrintf( wxT("%% %d %d lineto closepath stroke\n"), llx, ury ); +#endif + +#ifndef __WXMSW__ + wxPostScriptPrintNativeData *data = + (wxPostScriptPrintNativeData *) m_printData.GetNativeData(); + + if (m_ok && (m_printData.GetPrintMode() == wxPRINT_MODE_PRINTER)) + { + wxString command; + command += data->GetPrinterCommand(); + command += wxT(" "); + command += data->GetPrinterOptions(); + command += wxT(" "); + command += m_printData.GetFilename(); + + wxExecute( command, true ); + wxRemoveFile( m_printData.GetFilename() ); + } +#endif +} + +void wxPostScriptDC::StartPage() +{ + wxCHECK_RET( m_ok, wxT("invalid postscript dc") ); + + PsPrintf( wxT("%%%%Page: %d\n"), wxPageNumber++ ); + + // What is this one supposed to do? RR. +// *m_pstream << "matrix currentmatrix\n"; + + // Added by Chris Breeze + + // Each page starts with an "initgraphics" which resets the + // transformation and so we need to reset the origin + // (and rotate the page for landscape printing) + + // Output scaling + wxCoord translate_x, translate_y; + double scale_x, scale_y; + + wxPostScriptPrintNativeData *data = + (wxPostScriptPrintNativeData *) m_printData.GetNativeData(); + + translate_x = (wxCoord)data->GetPrinterTranslateX(); + translate_y = (wxCoord)data->GetPrinterTranslateY(); + + scale_x = data->GetPrinterScaleX(); + scale_y = data->GetPrinterScaleY(); + + if (m_printData.GetOrientation() == wxLANDSCAPE) + { + int h; + GetSize( (int*) NULL, &h ); + translate_y -= h; + PsPrint( "90 rotate\n" ); + // I copied this one from a PostScript tutorial, but to no avail. RR. + // PsPrint( "90 rotate llx neg ury nef translate\n" ); + } + + char buffer[100]; + sprintf( buffer, "%.8f %.8f scale\n", scale_x / ms_PSScaleFactor, + scale_y / ms_PSScaleFactor); + for (int i = 0; i < 100; i++) + if (buffer[i] == ',') buffer[i] = '.'; + PsPrint( buffer ); + + PsPrintf( wxT("%d %d translate\n"), translate_x, translate_y ); +} + +void wxPostScriptDC::EndPage () +{ + wxCHECK_RET( m_ok , wxT("invalid postscript dc") ); + + PsPrint( "showpage\n" ); +} + +bool wxPostScriptDC::DoBlit( wxCoord xdest, wxCoord ydest, + wxCoord fwidth, wxCoord fheight, + wxDC *source, + wxCoord xsrc, wxCoord ysrc, + int rop, bool WXUNUSED(useMask), wxCoord WXUNUSED(xsrcMask), wxCoord WXUNUSED(ysrcMask) ) +{ + wxCHECK_MSG( m_ok, false, wxT("invalid postscript dc") ); + + wxCHECK_MSG( source, false, wxT("invalid source dc") ); + + /* blit into a bitmap */ + wxBitmap bitmap( (int)fwidth, (int)fheight ); + wxMemoryDC memDC; + memDC.SelectObject(bitmap); + memDC.Blit(0, 0, fwidth, fheight, source, xsrc, ysrc, rop); /* TODO: Blit transparently? */ + memDC.SelectObject(wxNullBitmap); + + /* draw bitmap. scaling and positioning is done there */ + DrawBitmap( bitmap, xdest, ydest ); + + return true; +} + +wxCoord wxPostScriptDC::GetCharHeight() const +{ + if (m_font.Ok()) + return m_font.GetPointSize(); + else + return 12; +} + +void wxPostScriptDC::DoGetTextExtent(const wxString& string, + wxCoord *x, wxCoord *y, + wxCoord *descent, wxCoord *externalLeading, + wxFont *theFont ) const +{ + wxFont *fontToUse = theFont; + + if (!fontToUse) fontToUse = (wxFont*) &m_font; + + wxCHECK_RET( fontToUse, wxT("GetTextExtent: no font defined") ); + + if (string.empty()) + { + if (x) (*x) = 0; + if (y) (*y) = 0; + if (descent) (*descent) = 0; + if (externalLeading) (*externalLeading) = 0; + return; + } + + // GTK 2.0 + + const wxWX2MBbuf strbuf = string.mb_str(); + +#if !wxUSE_AFM_FOR_POSTSCRIPT + /* Provide a VERY rough estimate (avoid using it). + * Produces accurate results for mono-spaced font + * such as Courier (aka wxMODERN) */ + + int height = 12; + if (fontToUse) + { + height = fontToUse->GetPointSize(); + } + if ( x ) + *x = strlen (strbuf) * height * 72 / 120; + if ( y ) + *y = (wxCoord) (height * 1.32); /* allow for descender */ + if (descent) *descent = 0; + if (externalLeading) *externalLeading = 0; +#else + + /* method for calculating string widths in postscript: + / read in the AFM (adobe font metrics) file for the + / actual font, parse it and extract the character widths + / and also the descender. this may be improved, but for now + / it works well. the AFM file is only read in if the + / font is changed. this may be chached in the future. + / calls to GetTextExtent with the font unchanged are rather + / efficient!!! + / + / for each font and style used there is an AFM file necessary. + / currently i have only files for the roman font family. + / I try to get files for the other ones! + / + / CAVE: the size of the string is currently always calculated + / in 'points' (1/72 of an inch). this should later on be + / changed to depend on the mapping mode. + / CAVE: the path to the AFM files must be set before calling this + / function. this is usually done by a call like the following: + / wxSetAFMPath("d:\\wxw161\\afm\\"); + / + / example: + / + / wxPostScriptDC dc(NULL, true); + / if (dc.Ok()){ + / wxSetAFMPath("d:\\wxw161\\afm\\"); + / dc.StartDoc("Test"); + / dc.StartPage(); + / wxCoord w,h; + / dc.SetFont(new wxFont(10, wxROMAN, wxNORMAL, wxNORMAL)); + / dc.GetTextExtent("Hallo",&w,&h); + / dc.EndPage(); + / dc.EndDoc(); + / } + / + / by steve (stefan.hammes@urz.uni-heidelberg.de) + / created: 10.09.94 + / updated: 14.05.95 */ + + /* these static vars are for storing the state between calls */ + static int lastFamily= INT_MIN; + static int lastSize= INT_MIN; + static int lastStyle= INT_MIN; + static int lastWeight= INT_MIN; + static int lastDescender = INT_MIN; + static int lastWidths[256]; /* widths of the characters */ + + double UnderlinePosition = 0.0; + double UnderlineThickness = 0.0; + + // Get actual parameters + int Family = fontToUse->GetFamily(); + int Size = fontToUse->GetPointSize(); + int Style = fontToUse->GetStyle(); + int Weight = fontToUse->GetWeight(); + + // If we have another font, read the font-metrics + if (Family!=lastFamily || Size!=lastSize || Style!=lastStyle || Weight!=lastWeight) + { + // Store actual values + lastFamily = Family; + lastSize = Size; + lastStyle = Style; + lastWeight = Weight; + + const wxChar *name; + + switch (Family) + { + case wxMODERN: + case wxTELETYPE: + { + if ((Style == wxITALIC) && (Weight == wxBOLD)) name = wxT("CourBoO.afm"); + else if ((Style != wxITALIC) && (Weight == wxBOLD)) name = wxT("CourBo.afm"); + else if ((Style == wxITALIC) && (Weight != wxBOLD)) name = wxT("CourO.afm"); + else name = wxT("Cour.afm"); + break; + } + case wxROMAN: + { + if ((Style == wxITALIC) && (Weight == wxBOLD)) name = wxT("TimesBoO.afm"); + else if ((Style != wxITALIC) && (Weight == wxBOLD)) name = wxT("TimesBo.afm"); + else if ((Style == wxITALIC) && (Weight != wxBOLD)) name = wxT("TimesO.afm"); + else name = wxT("TimesRo.afm"); + break; + } + case wxSCRIPT: + { + name = wxT("Zapf.afm"); + break; + } + case wxSWISS: + default: + { + if ((Style == wxITALIC) && (Weight == wxBOLD)) name = wxT("HelvBoO.afm"); + else if ((Style != wxITALIC) && (Weight == wxBOLD)) name = wxT("HelvBo.afm"); + else if ((Style == wxITALIC) && (Weight != wxBOLD)) name = wxT("HelvO.afm"); + else name = wxT("Helv.afm"); + break; + } + } + + FILE *afmFile = NULL; + + // Get the directory of the AFM files + wxString afmName; + + // VZ: I don't know if the cast always works under Unix but it clearly + // never does under Windows where the pointer is + // wxWindowsPrintNativeData and so calling GetFontMetricPath() on + // it just crashes +#ifndef __WIN32__ + wxPostScriptPrintNativeData *data = + wxDynamicCast(m_printData.GetNativeData(), wxPostScriptPrintNativeData); + + if (data && !data->GetFontMetricPath().empty()) + { + afmName = data->GetFontMetricPath(); + afmName << wxFILE_SEP_PATH << name; + } +#endif // __WIN32__ + + if ( !afmName.empty() ) + afmFile = wxFopen(afmName, wxT("r")); + + if ( !afmFile ) + { +#if defined(__UNIX__) && !defined(__VMS__) + afmName = wxGetDataDir(); +#else // !__UNIX__ + afmName = wxStandardPaths::Get().GetDataDir(); +#endif // __UNIX__/!__UNIX__ + + afmName << wxFILE_SEP_PATH +#if defined(__LINUX__) || defined(__FREEBSD__) + << wxT("gs_afm") << wxFILE_SEP_PATH +#else + << wxT("afm") << wxFILE_SEP_PATH +#endif + << name; + afmFile = wxFopen(afmName,wxT("r")); + } + + /* 2. open and process the file + / a short explanation of the AFM format: + / we have for each character a line, which gives its size + / e.g.: + / + / C 63 ; WX 444 ; N question ; B 49 -14 395 676 ; + / + / that means, we have a character with ascii code 63, and width + / (444/1000 * fontSize) points. + / the other data is ignored for now! + / + / when the font has changed, we read in the right AFM file and store the + / character widths in an array, which is processed below (see point 3.). */ + if (afmFile==NULL) + { + wxLogDebug( wxT("GetTextExtent: can't open AFM file '%s'"), afmName.c_str() ); + wxLogDebug( wxT(" using approximate values")); + for (int i=0; i<256; i++) lastWidths[i] = 500; /* an approximate value */ + lastDescender = -150; /* dito. */ + } + else + { + /* init the widths array */ + for(int i=0; i<256; i++) lastWidths[i] = INT_MIN; + /* some variables for holding parts of a line */ + char cString[10], semiString[10], WXString[10]; + char descString[20]; + char upString[30], utString[30]; + char encString[50]; + char line[256]; + int ascii,cWidth; + /* read in the file and parse it */ + while(fgets(line,sizeof(line),afmFile)!=NULL) + { + /* A.) check for descender definition */ + if (strncmp(line,"Descender",9)==0) + { + if ((sscanf(line,"%s%d",descString,&lastDescender)!=2) || + (strcmp(descString,"Descender")!=0)) + { + wxLogDebug( wxT("AFM-file '%s': line '%s' has error (bad descender)"), afmName.c_str(),line ); + } + } + /* JC 1.) check for UnderlinePosition */ + else if(strncmp(line,"UnderlinePosition",17)==0) + { + if ((sscanf(line,"%s%lf",upString,&UnderlinePosition)!=2) || + (strcmp(upString,"UnderlinePosition")!=0)) + { + wxLogDebug( wxT("AFM-file '%s': line '%s' has error (bad UnderlinePosition)"), afmName.c_str(), line ); + } + } + /* JC 2.) check for UnderlineThickness */ + else if(strncmp(line,"UnderlineThickness",18)==0) + { + if ((sscanf(line,"%s%lf",utString,&UnderlineThickness)!=2) || + (strcmp(utString,"UnderlineThickness")!=0)) + { + wxLogDebug( wxT("AFM-file '%s': line '%s' has error (bad UnderlineThickness)"), afmName.c_str(), line ); + } + } + /* JC 3.) check for EncodingScheme */ + else if(strncmp(line,"EncodingScheme",14)==0) + { + if ((sscanf(line,"%s%s",utString,encString)!=2) || + (strcmp(utString,"EncodingScheme")!=0)) + { + wxLogDebug( wxT("AFM-file '%s': line '%s' has error (bad EncodingScheme)"), afmName.c_str(), line ); + } + else if (strncmp(encString, "AdobeStandardEncoding", 21)) + { + wxLogDebug( wxT("AFM-file '%s': line '%s' has error (unsupported EncodingScheme %s)"), + afmName.c_str(),line, encString); + } + } + /* B.) check for char-width */ + else if(strncmp(line,"C ",2)==0) + { + if (sscanf(line,"%s%d%s%s%d",cString,&ascii,semiString,WXString,&cWidth)!=5) + { + wxLogDebug(wxT("AFM-file '%s': line '%s' has an error (bad character width)"),afmName.c_str(),line); + } + if(strcmp(cString,"C")!=0 || strcmp(semiString,";")!=0 || strcmp(WXString,"WX")!=0) + { + wxLogDebug(wxT("AFM-file '%s': line '%s' has a format error"),afmName.c_str(),line); + } + /* printf(" char '%c'=%d has width '%d'\n",ascii,ascii,cWidth); */ + if (ascii>=0 && ascii<256) + { + lastWidths[ascii] = cWidth; /* store width */ + } + else + { + /* MATTHEW: this happens a lot; don't print an error */ + /* wxLogDebug("AFM-file '%s': ASCII value %d out of range",afmName.c_str(),ascii); */ + } + } + /* C.) ignore other entries. */ + } + fclose(afmFile); + } + /* hack to compute correct values for german 'Umlaute' + / the correct way would be to map the character names + / like 'adieresis' to corresp. positions of ISOEnc and read + / these values from AFM files, too. Maybe later ... */ + + // NB: casts to int are needed to suppress gcc 3.3 warnings + lastWidths[196] = lastWidths[(int)'A']; // U+00C4 A Umlaute + lastWidths[228] = lastWidths[(int)'a']; // U+00E4 a Umlaute + lastWidths[214] = lastWidths[(int)'O']; // U+00D6 O Umlaute + lastWidths[246] = lastWidths[(int)'o']; // U+00F6 o Umlaute + lastWidths[220] = lastWidths[(int)'U']; // U+00DC U Umlaute + lastWidths[252] = lastWidths[(int)'u']; // U+00FC u Umlaute + lastWidths[223] = lastWidths[(int)251]; // U+00DF eszett (scharfes s) + + /* JC: calculate UnderlineThickness/UnderlinePosition */ + + // VS: dirty, but is there any better solution? + double *pt; + pt = (double*) &m_underlinePosition; + *pt = LogicalToDeviceYRel((wxCoord)(UnderlinePosition * fontToUse->GetPointSize())) / 1000.0f; + pt = (double*) &m_underlineThickness; + *pt = LogicalToDeviceYRel((wxCoord)(UnderlineThickness * fontToUse->GetPointSize())) / 1000.0f; + + } + + + /* 3. now the font metrics are read in, calc size this + / is done by adding the widths of the characters in the + / string. they are given in 1/1000 of the size! */ + + long sum=0; + wxCoord height=Size; /* by default */ + unsigned char *p; + for(p=(unsigned char *)wxMBSTRINGCAST strbuf; *p; p++) + { + if(lastWidths[*p]== INT_MIN) + { + wxLogDebug(wxT("GetTextExtent: undefined width for character '%c' (%d)"), *p,*p); + sum += lastWidths[(unsigned char)' ']; /* assume space */ + } + else + { + sum += lastWidths[*p]; + } + } + + double widthSum = sum; + widthSum *= Size; + widthSum /= 1000.0F; + + /* add descender to height (it is usually a negative value) */ + //if (lastDescender != INT_MIN) + //{ + // height += (wxCoord)(((-lastDescender)/1000.0F) * Size); /* MATTHEW: forgot scale */ + //} + // - commented by V. Slavik - height already contains descender in it + // (judging from few experiments) + + /* return size values */ + if ( x ) + *x = (wxCoord)widthSum; + if ( y ) + *y = height; + + /* return other parameters */ + if (descent) + { + if(lastDescender!=INT_MIN) + { + *descent = (wxCoord)(((-lastDescender)/1000.0F) * Size); /* MATTHEW: forgot scale */ + } + else + { + *descent = 0; + } + } + + /* currently no idea how to calculate this! */ + if (externalLeading) *externalLeading = 0; +#endif + // Use AFM +} + +// print postscript datas via required method (file, stream) +void wxPostScriptDC::PsPrintf( const wxChar* fmt, ... ) +{ + va_list argptr; + va_start(argptr, fmt); + + PsPrint( wxString::FormatV( fmt, argptr ).c_str() ); +} + +void wxPostScriptDC::PsPrint( const char* psdata ) +{ + wxPostScriptPrintNativeData *data = + (wxPostScriptPrintNativeData *) m_printData.GetNativeData(); + + switch (m_printData.GetPrintMode()) + { +#if wxUSE_STREAMS + // append to output stream + case wxPRINT_MODE_STREAM: + { + wxOutputStream* outputstream = data->GetOutputStream(); + wxCHECK_RET( outputstream, wxT("invalid outputstream") ); + outputstream->Write( psdata, strlen( psdata ) ); + } + break; +#endif // wxUSE_STREAMS + + // save data into file + default: + wxCHECK_RET( m_pstream, wxT("invalid postscript dc") ); + fwrite( psdata, 1, strlen( psdata ), m_pstream ); + } +} + +void wxPostScriptDC::PsPrint( int ch ) +{ + wxPostScriptPrintNativeData *data = + (wxPostScriptPrintNativeData *) m_printData.GetNativeData(); + + switch (m_printData.GetPrintMode()) + { +#if wxUSE_STREAMS + // append to output stream + case wxPRINT_MODE_STREAM: + { + wxOutputStream* outputstream = data->GetOutputStream(); + wxCHECK_RET( outputstream, wxT("invalid outputstream") ); + outputstream->PutC( (char)ch ); + } + break; +#endif // wxUSE_STREAMS + + // save data into file + default: + wxCHECK_RET( m_pstream, wxT("invalid postscript dc") ); + fputc( ch, m_pstream ); + } +} + +#endif // wxUSE_PRINTING_ARCHITECTURE && wxUSE_POSTSCRIPT + +// vi:sts=4:sw=4:et diff --git a/Externals/wxWidgets/src/generic/dirctrlg.cpp b/Externals/wxWidgets/src/generic/dirctrlg.cpp index e2e3af3ee2..3ebf23938c 100644 --- a/Externals/wxWidgets/src/generic/dirctrlg.cpp +++ b/Externals/wxWidgets/src/generic/dirctrlg.cpp @@ -1,1707 +1,1707 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/generic/dirctrlg.cpp -// Purpose: wxGenericDirCtrl -// Author: Harm van der Heijden, Robert Roebling, Julian Smart -// Modified by: -// Created: 12/12/98 -// RCS-ID: $Id: dirctrlg.cpp 46614 2007-06-22 12:12:10Z JS $ -// Copyright: (c) Harm van der Heijden, Robert Roebling and Julian Smart -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_DIRDLG || wxUSE_FILEDLG - -#include "wx/generic/dirctrlg.h" - -#ifndef WX_PRECOMP - #include "wx/hash.h" - #include "wx/intl.h" - #include "wx/log.h" - #include "wx/utils.h" - #include "wx/button.h" - #include "wx/icon.h" - #include "wx/settings.h" - #include "wx/msgdlg.h" - #include "wx/cmndata.h" - #include "wx/choice.h" - #include "wx/textctrl.h" - #include "wx/layout.h" - #include "wx/sizer.h" - #include "wx/textdlg.h" - #include "wx/gdicmn.h" - #include "wx/image.h" - #include "wx/module.h" -#endif - -#include "wx/filefn.h" -#include "wx/imaglist.h" -#include "wx/tokenzr.h" -#include "wx/dir.h" -#include "wx/artprov.h" -#include "wx/mimetype.h" - -#if wxUSE_STATLINE - #include "wx/statline.h" -#endif - -#if defined(__WXMAC__) - #include "wx/mac/private.h" // includes mac headers -#endif - -#ifdef __WXMSW__ -#include -#include "wx/msw/winundef.h" - -// FIXME - Mingw32 1.0 has both _getdrive() and _chdrive(). For now, let's assume -// older releases don't, but it should be verified and the checks modified -// accordingly. -#if !defined(__GNUWIN32__) || (defined(__MINGW32_MAJOR_VERSION) && __MINGW32_MAJOR_VERSION >= 1) -#if !defined(__WXWINCE__) - #include -#endif - #include - #include -#endif - -#endif - -#if defined(__OS2__) || defined(__DOS__) - #ifdef __OS2__ - #define INCL_BASE - #include - #ifndef __EMX__ - #include - #endif - #include - #include - #endif - extern bool wxIsDriveAvailable(const wxString& dirName); -#endif // __OS2__ - -#if defined(__WXMAC__) - #include "MoreFilesX.h" -#endif - -#ifdef __BORLANDC__ - #include "dos.h" -#endif - -// If compiled under Windows, this macro can cause problems -#ifdef GetFirstChild -#undef GetFirstChild -#endif - -// ---------------------------------------------------------------------------- -// wxGetAvailableDrives, for WINDOWS, DOS, OS2, MAC, UNIX (returns "/") -// ---------------------------------------------------------------------------- - -size_t wxGetAvailableDrives(wxArrayString &paths, wxArrayString &names, wxArrayInt &icon_ids) -{ -#if defined(__WINDOWS__) || defined(__DOS__) || defined(__OS2__) - -#ifdef __WXWINCE__ - // No logical drives; return "\" - paths.Add(wxT("\\")); - names.Add(wxT("\\")); - icon_ids.Add(wxFileIconsTable::computer); -#elif defined(__WIN32__) - wxChar driveBuffer[256]; - size_t n = (size_t) GetLogicalDriveStrings(255, driveBuffer); - size_t i = 0; - while (i < n) - { - wxString path, name; - path.Printf(wxT("%c:\\"), driveBuffer[i]); - name.Printf(wxT("%c:"), driveBuffer[i]); - - // Do not use GetVolumeInformation to further decorate the - // name, since it can cause severe delays on network drives. - - int imageId; - int driveType = ::GetDriveType(path); - switch (driveType) - { - case DRIVE_REMOVABLE: - if (path == wxT("a:\\") || path == wxT("b:\\")) - imageId = wxFileIconsTable::floppy; - else - imageId = wxFileIconsTable::removeable; - break; - case DRIVE_CDROM: - imageId = wxFileIconsTable::cdrom; - break; - case DRIVE_REMOTE: - case DRIVE_FIXED: - default: - imageId = wxFileIconsTable::drive; - break; - } - - paths.Add(path); - names.Add(name); - icon_ids.Add(imageId); - - while (driveBuffer[i] != wxT('\0')) - i ++; - i ++; - if (driveBuffer[i] == wxT('\0')) - break; - } -#elif defined(__OS2__) - APIRET rc; - ULONG ulDriveNum = 0; - ULONG ulDriveMap = 0; - rc = ::DosQueryCurrentDisk(&ulDriveNum, &ulDriveMap); - if ( rc == 0) - { - size_t i = 0; - while (i < 26) - { - if (ulDriveMap & ( 1 << i )) - { - wxString path, name; - path.Printf(wxT("%c:\\"), 'A' + i); - name.Printf(wxT("%c:"), 'A' + i); - - // Note: If _filesys is unsupported by some compilers, - // we can always replace it by DosQueryFSAttach - char filesysname[20]; -#ifdef __WATCOMC__ - ULONG cbBuffer = sizeof(filesysname); - PFSQBUFFER2 pfsqBuffer = (PFSQBUFFER2)filesysname; - APIRET rc = ::DosQueryFSAttach(name.fn_str(),0,FSAIL_QUERYNAME,pfsqBuffer,&cbBuffer); - if (rc != NO_ERROR) - { - filesysname[0] = '\0'; - } -#else - _filesys(name.fn_str(), filesysname, sizeof(filesysname)); -#endif - /* FAT, LAN, HPFS, CDFS, NFS */ - int imageId; - if (path == wxT("A:\\") || path == wxT("B:\\")) - imageId = wxFileIconsTable::floppy; - else if (!strcmp(filesysname, "CDFS")) - imageId = wxFileIconsTable::cdrom; - else if (!strcmp(filesysname, "LAN") || - !strcmp(filesysname, "NFS")) - imageId = wxFileIconsTable::drive; - else - imageId = wxFileIconsTable::drive; - paths.Add(path); - names.Add(name); - icon_ids.Add(imageId); - } - i ++; - } - } -#else // !__WIN32__, !__OS2__ - int drive; - - /* If we can switch to the drive, it exists. */ - for( drive = 1; drive <= 26; drive++ ) - { - wxString path, name; - path.Printf(wxT("%c:\\"), (char) (drive + 'a' - 1)); - name.Printf(wxT("%c:"), (char) (drive + 'A' - 1)); - - if (wxIsDriveAvailable(path)) - { - paths.Add(path); - names.Add(name); - icon_ids.Add((drive <= 2) ? wxFileIconsTable::floppy : wxFileIconsTable::drive); - } - } -#endif // __WIN32__/!__WIN32__ - -#elif defined(__WXMAC__) - - ItemCount volumeIndex = 1; - OSErr err = noErr ; - - while( noErr == err ) - { - HFSUniStr255 volumeName ; - FSRef fsRef ; - FSVolumeInfo volumeInfo ; - err = FSGetVolumeInfo(0, volumeIndex, NULL, kFSVolInfoFlags , &volumeInfo , &volumeName, &fsRef); - if( noErr == err ) - { - wxString path = wxMacFSRefToPath( &fsRef ) ; - wxString name = wxMacHFSUniStrToString( &volumeName ) ; - - if ( (volumeInfo.flags & kFSVolFlagSoftwareLockedMask) || (volumeInfo.flags & kFSVolFlagHardwareLockedMask) ) - { - icon_ids.Add(wxFileIconsTable::cdrom); - } - else - { - icon_ids.Add(wxFileIconsTable::drive); - } - // todo other removable - - paths.Add(path); - names.Add(name); - volumeIndex++ ; - } - } - -#elif defined(__UNIX__) - paths.Add(wxT("/")); - names.Add(wxT("/")); - icon_ids.Add(wxFileIconsTable::computer); -#else - #error "Unsupported platform in wxGenericDirCtrl!" -#endif - wxASSERT_MSG( (paths.GetCount() == names.GetCount()), wxT("The number of paths and their human readable names should be equal in number.")); - wxASSERT_MSG( (paths.GetCount() == icon_ids.GetCount()), wxT("Wrong number of icons for available drives.")); - return paths.GetCount(); -} - -// ---------------------------------------------------------------------------- -// wxIsDriveAvailable -// ---------------------------------------------------------------------------- - -#if defined(__DOS__) - -bool wxIsDriveAvailable(const wxString& dirName) -{ - // FIXME_MGL - this method leads to hang up under Watcom for some reason -#ifdef __WATCOMC__ - wxUnusedVar(dirName); -#else - if ( dirName.length() == 3 && dirName[1u] == wxT(':') ) - { - wxString dirNameLower(dirName.Lower()); - // VS: always return true for removable media, since Win95 doesn't - // like it when MS-DOS app accesses empty floppy drive - return (dirNameLower[0u] == wxT('a') || - dirNameLower[0u] == wxT('b') || - wxDirExists(dirNameLower)); - } - else -#endif - return true; -} - -#elif defined(__WINDOWS__) || defined(__OS2__) - -int setdrive(int WXUNUSED_IN_WINCE(drive)) -{ -#ifdef __WXWINCE__ - return 0; -#elif defined(__GNUWIN32__) && \ - (defined(__MINGW32_MAJOR_VERSION) && __MINGW32_MAJOR_VERSION >= 1) - return _chdrive(drive); -#else - wxChar newdrive[4]; - - if (drive < 1 || drive > 31) - return -1; - newdrive[0] = (wxChar)(wxT('A') + drive - 1); - newdrive[1] = wxT(':'); -#ifdef __OS2__ - newdrive[2] = wxT('\\'); - newdrive[3] = wxT('\0'); -#else - newdrive[2] = wxT('\0'); -#endif -#if defined(__WXMSW__) - if (::SetCurrentDirectory(newdrive)) -#else - // VA doesn't know what LPSTR is and has its own set - if (!DosSetCurrentDir((PSZ)newdrive)) -#endif - return 0; - else - return -1; -#endif // !GNUWIN32 -} - -bool wxIsDriveAvailable(const wxString& WXUNUSED_IN_WINCE(dirName)) -{ -#ifdef __WXWINCE__ - return false; -#else -#ifdef __WIN32__ - UINT errorMode = SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX); -#endif - bool success = true; - - // Check if this is a root directory and if so, - // whether the drive is available. - if (dirName.length() == 3 && dirName[(size_t)1] == wxT(':')) - { - wxString dirNameLower(dirName.Lower()); -#if defined(__GNUWIN32__) && !(defined(__MINGW32_MAJOR_VERSION) && __MINGW32_MAJOR_VERSION >= 1) - success = wxDirExists(dirNameLower); -#else - #if defined(__OS2__) - // Avoid changing to drive since no media may be inserted. - if (dirNameLower[(size_t)0] == 'a' || dirNameLower[(size_t)0] == 'b') - return success; - #endif - int currentDrive = _getdrive(); - int thisDrive = (int) (dirNameLower[(size_t)0] - 'a' + 1) ; - int err = setdrive( thisDrive ) ; - setdrive( currentDrive ); - - if (err == -1) - { - success = false; - } -#endif - } -#ifdef __WIN32__ - (void) SetErrorMode(errorMode); -#endif - - return success; -#endif -} -#endif // __WINDOWS__ || __OS2__ - -#endif // wxUSE_DIRDLG || wxUSE_FILEDLG - - - -#if wxUSE_DIRDLG - -// Function which is called by quick sort. We want to override the default wxArrayString behaviour, -// and sort regardless of case. -static int wxCMPFUNC_CONV wxDirCtrlStringCompareFunction(const wxString& strFirst, const wxString& strSecond) -{ - return strFirst.CmpNoCase(strSecond); -} - -//----------------------------------------------------------------------------- -// wxDirItemData -//----------------------------------------------------------------------------- - -wxDirItemData::wxDirItemData(const wxString& path, const wxString& name, - bool isDir) -{ - m_path = path; - m_name = name; - /* Insert logic to detect hidden files here - * In UnixLand we just check whether the first char is a dot - * For FileNameFromPath read LastDirNameInThisPath ;-) */ - // m_isHidden = (bool)(wxFileNameFromPath(*m_path)[0] == '.'); - m_isHidden = false; - m_isExpanded = false; - m_isDir = isDir; -} - -void wxDirItemData::SetNewDirName(const wxString& path) -{ - m_path = path; - m_name = wxFileNameFromPath(path); -} - -bool wxDirItemData::HasSubDirs() const -{ - if (m_path.empty()) - return false; - - wxDir dir; - { - wxLogNull nolog; - if ( !dir.Open(m_path) ) - return false; - } - - return dir.HasSubDirs(); -} - -bool wxDirItemData::HasFiles(const wxString& WXUNUSED(spec)) const -{ - if (m_path.empty()) - return false; - - wxDir dir; - { - wxLogNull nolog; - if ( !dir.Open(m_path) ) - return false; - } - - return dir.HasFiles(); -} - -//----------------------------------------------------------------------------- -// wxGenericDirCtrl -//----------------------------------------------------------------------------- - - -#if wxUSE_EXTENDED_RTTI -WX_DEFINE_FLAGS( wxGenericDirCtrlStyle ) - -wxBEGIN_FLAGS( wxGenericDirCtrlStyle ) - // new style border flags, we put them first to - // use them for streaming out - wxFLAGS_MEMBER(wxBORDER_SIMPLE) - wxFLAGS_MEMBER(wxBORDER_SUNKEN) - wxFLAGS_MEMBER(wxBORDER_DOUBLE) - wxFLAGS_MEMBER(wxBORDER_RAISED) - wxFLAGS_MEMBER(wxBORDER_STATIC) - wxFLAGS_MEMBER(wxBORDER_NONE) - - // old style border flags - wxFLAGS_MEMBER(wxSIMPLE_BORDER) - wxFLAGS_MEMBER(wxSUNKEN_BORDER) - wxFLAGS_MEMBER(wxDOUBLE_BORDER) - wxFLAGS_MEMBER(wxRAISED_BORDER) - wxFLAGS_MEMBER(wxSTATIC_BORDER) - wxFLAGS_MEMBER(wxBORDER) - - // standard window styles - wxFLAGS_MEMBER(wxTAB_TRAVERSAL) - wxFLAGS_MEMBER(wxCLIP_CHILDREN) - wxFLAGS_MEMBER(wxTRANSPARENT_WINDOW) - wxFLAGS_MEMBER(wxWANTS_CHARS) - wxFLAGS_MEMBER(wxFULL_REPAINT_ON_RESIZE) - wxFLAGS_MEMBER(wxALWAYS_SHOW_SB ) - wxFLAGS_MEMBER(wxVSCROLL) - wxFLAGS_MEMBER(wxHSCROLL) - - wxFLAGS_MEMBER(wxDIRCTRL_DIR_ONLY) - wxFLAGS_MEMBER(wxDIRCTRL_3D_INTERNAL) - wxFLAGS_MEMBER(wxDIRCTRL_SELECT_FIRST) - wxFLAGS_MEMBER(wxDIRCTRL_SHOW_FILTERS) - -wxEND_FLAGS( wxGenericDirCtrlStyle ) - -IMPLEMENT_DYNAMIC_CLASS_XTI(wxGenericDirCtrl, wxControl,"wx/dirctrl.h") - -wxBEGIN_PROPERTIES_TABLE(wxGenericDirCtrl) - wxHIDE_PROPERTY( Children ) - wxPROPERTY( DefaultPath , wxString , SetDefaultPath , GetDefaultPath , EMPTY_MACROVALUE , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) - wxPROPERTY( Filter , wxString , SetFilter , GetFilter , EMPTY_MACROVALUE , 0 /*flags*/ , wxT("Helpstring") , wxT("group") ) - wxPROPERTY( DefaultFilter , int , SetFilterIndex, GetFilterIndex, EMPTY_MACROVALUE , 0 /*flags*/ , wxT("Helpstring") , wxT("group") ) - wxPROPERTY_FLAGS( WindowStyle, wxGenericDirCtrlStyle, long, SetWindowStyleFlag, GetWindowStyleFlag, EMPTY_MACROVALUE , 0, wxT("Helpstring"), wxT("group") ) -wxEND_PROPERTIES_TABLE() - -wxBEGIN_HANDLERS_TABLE(wxGenericDirCtrl) -wxEND_HANDLERS_TABLE() - -wxCONSTRUCTOR_8( wxGenericDirCtrl , wxWindow* , Parent , wxWindowID , Id , wxString , DefaultPath , - wxPoint , Position , wxSize , Size , long , WindowStyle , wxString , Filter , int , DefaultFilter ) -#else -IMPLEMENT_DYNAMIC_CLASS(wxGenericDirCtrl, wxControl) -#endif - -BEGIN_EVENT_TABLE(wxGenericDirCtrl, wxControl) - EVT_TREE_ITEM_EXPANDING (wxID_TREECTRL, wxGenericDirCtrl::OnExpandItem) - EVT_TREE_ITEM_COLLAPSED (wxID_TREECTRL, wxGenericDirCtrl::OnCollapseItem) - EVT_TREE_BEGIN_LABEL_EDIT (wxID_TREECTRL, wxGenericDirCtrl::OnBeginEditItem) - EVT_TREE_END_LABEL_EDIT (wxID_TREECTRL, wxGenericDirCtrl::OnEndEditItem) - EVT_SIZE (wxGenericDirCtrl::OnSize) -END_EVENT_TABLE() - -wxGenericDirCtrl::wxGenericDirCtrl(void) -{ - Init(); -} - -void wxGenericDirCtrl::ExpandRoot() -{ - ExpandDir(m_rootId); // automatically expand first level - - // Expand and select the default path - if (!m_defaultPath.empty()) - { - ExpandPath(m_defaultPath); - } -#ifdef __UNIX__ - else - { - // On Unix, there's only one node under the (hidden) root node. It - // represents the / path, so the user would always have to expand it; - // let's do it ourselves - ExpandPath( wxT("/") ); - } -#endif -} - -bool wxGenericDirCtrl::Create(wxWindow *parent, - const wxWindowID id, - const wxString& dir, - const wxPoint& pos, - const wxSize& size, - long style, - const wxString& filter, - int defaultFilter, - const wxString& name) -{ - if (!wxControl::Create(parent, id, pos, size, style, wxDefaultValidator, name)) - return false; - - SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE)); - SetForegroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT)); - - Init(); - - long treeStyle = wxTR_HAS_BUTTONS; - - // On Windows CE, if you hide the root, you get a crash when - // attempting to access data for children of the root item. -#ifndef __WXWINCE__ - treeStyle |= wxTR_HIDE_ROOT; -#endif - -#ifdef __WXGTK20__ - treeStyle |= wxTR_NO_LINES; -#endif - - if (style & wxDIRCTRL_EDIT_LABELS) - treeStyle |= wxTR_EDIT_LABELS; - - if ((style & wxDIRCTRL_3D_INTERNAL) == 0) - treeStyle |= wxNO_BORDER; - else - treeStyle |= wxBORDER_SUNKEN; - - long filterStyle = 0; - if ((style & wxDIRCTRL_3D_INTERNAL) == 0) - filterStyle |= wxNO_BORDER; - else - filterStyle |= wxBORDER_SUNKEN; - - m_treeCtrl = CreateTreeCtrl(this, wxID_TREECTRL, - wxPoint(0,0), GetClientSize(), treeStyle); - - if (!filter.empty() && (style & wxDIRCTRL_SHOW_FILTERS)) - m_filterListCtrl = new wxDirFilterListCtrl(this, wxID_FILTERLISTCTRL, wxDefaultPosition, wxDefaultSize, filterStyle); - - m_defaultPath = dir; - m_filter = filter; - - if (m_filter.empty()) -#ifdef __UNIX__ - m_filter = wxT("*"); -#else - m_filter = wxT("*.*"); -#endif - - SetFilterIndex(defaultFilter); - - if (m_filterListCtrl) - m_filterListCtrl->FillFilterList(filter, defaultFilter); - - m_treeCtrl->SetImageList(wxTheFileIconsTable->GetSmallImageList()); - - m_showHidden = false; - wxDirItemData* rootData = new wxDirItemData(wxEmptyString, wxEmptyString, true); - - wxString rootName; - -#if defined(__WINDOWS__) || defined(__OS2__) || defined(__DOS__) - rootName = _("Computer"); -#else - rootName = _("Sections"); -#endif - - m_rootId = m_treeCtrl->AddRoot( rootName, 3, -1, rootData); - m_treeCtrl->SetItemHasChildren(m_rootId); - - ExpandRoot(); - - SetInitialSize(size); - DoResize(); - - return true; -} - -wxGenericDirCtrl::~wxGenericDirCtrl() -{ -} - -void wxGenericDirCtrl::Init() -{ - m_showHidden = false; - m_currentFilter = 0; - m_currentFilterStr = wxEmptyString; // Default: any file - m_treeCtrl = NULL; - m_filterListCtrl = NULL; -} - -wxTreeCtrl* wxGenericDirCtrl::CreateTreeCtrl(wxWindow *parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long treeStyle) -{ - return new wxTreeCtrl(parent, id, pos, size, treeStyle); -} - -void wxGenericDirCtrl::ShowHidden( bool show ) -{ - m_showHidden = show; - - wxString path = GetPath(); - ReCreateTree(); - SetPath(path); -} - -const wxTreeItemId -wxGenericDirCtrl::AddSection(const wxString& path, const wxString& name, int imageId) -{ - wxDirItemData *dir_item = new wxDirItemData(path,name,true); - - wxTreeItemId id = AppendItem( m_rootId, name, imageId, -1, dir_item); - - m_treeCtrl->SetItemHasChildren(id); - - return id; -} - -void wxGenericDirCtrl::SetupSections() -{ - wxArrayString paths, names; - wxArrayInt icons; - - size_t n, count = wxGetAvailableDrives(paths, names, icons); - -#ifdef __WXGTK20__ - wxString home = wxGetHomeDir(); - AddSection( home, _("Home directory"), 1); - home += wxT("/Desktop"); - AddSection( home, _("Desktop"), 1); -#endif - - for (n = 0; n < count; n++) - AddSection(paths[n], names[n], icons[n]); -} - -void wxGenericDirCtrl::OnBeginEditItem(wxTreeEvent &event) -{ - // don't rename the main entry "Sections" - if (event.GetItem() == m_rootId) - { - event.Veto(); - return; - } - - // don't rename the individual sections - if (m_treeCtrl->GetItemParent( event.GetItem() ) == m_rootId) - { - event.Veto(); - return; - } -} - -void wxGenericDirCtrl::OnEndEditItem(wxTreeEvent &event) -{ - if (event.IsEditCancelled()) - return; - - if ((event.GetLabel().empty()) || - (event.GetLabel() == wxT(".")) || - (event.GetLabel() == wxT("..")) || - (event.GetLabel().Find(wxT('/')) != wxNOT_FOUND) || - (event.GetLabel().Find(wxT('\\')) != wxNOT_FOUND) || - (event.GetLabel().Find(wxT('|')) != wxNOT_FOUND)) - { - wxMessageDialog dialog(this, _("Illegal directory name."), _("Error"), wxOK | wxICON_ERROR ); - dialog.ShowModal(); - event.Veto(); - return; - } - - wxTreeItemId id = event.GetItem(); - wxDirItemData *data = (wxDirItemData*)m_treeCtrl->GetItemData( id ); - wxASSERT( data ); - - wxString new_name( wxPathOnly( data->m_path ) ); - new_name += wxString(wxFILE_SEP_PATH); - new_name += event.GetLabel(); - - wxLogNull log; - - if (wxFileExists(new_name)) - { - wxMessageDialog dialog(this, _("File name exists already."), _("Error"), wxOK | wxICON_ERROR ); - dialog.ShowModal(); - event.Veto(); - } - - if (wxRenameFile(data->m_path,new_name)) - { - data->SetNewDirName( new_name ); - } - else - { - wxMessageDialog dialog(this, _("Operation not permitted."), _("Error"), wxOK | wxICON_ERROR ); - dialog.ShowModal(); - event.Veto(); - } -} - -void wxGenericDirCtrl::OnExpandItem(wxTreeEvent &event) -{ - wxTreeItemId parentId = event.GetItem(); - - // VS: this is needed because the event handler is called from wxTreeCtrl - // ctor when wxTR_HIDE_ROOT was specified - - if (!m_rootId.IsOk()) - - m_rootId = m_treeCtrl->GetRootItem(); - - ExpandDir(parentId); -} - -void wxGenericDirCtrl::OnCollapseItem(wxTreeEvent &event ) -{ - CollapseDir(event.GetItem()); -} - -void wxGenericDirCtrl::CollapseDir(wxTreeItemId parentId) -{ - wxTreeItemId child; - - wxDirItemData *data = (wxDirItemData *) m_treeCtrl->GetItemData(parentId); - if (!data->m_isExpanded) - return; - - data->m_isExpanded = false; - wxTreeItemIdValue cookie; - /* Workaround because DeleteChildren has disapeared (why?) and - * CollapseAndReset doesn't work as advertised (deletes parent too) */ - child = m_treeCtrl->GetFirstChild(parentId, cookie); - while (child.IsOk()) - { - m_treeCtrl->Delete(child); - /* Not GetNextChild below, because the cookie mechanism can't - * handle disappearing children! */ - child = m_treeCtrl->GetFirstChild(parentId, cookie); - } - if (parentId != m_treeCtrl->GetRootItem()) - m_treeCtrl->Collapse(parentId); -} - -void wxGenericDirCtrl::ExpandDir(wxTreeItemId parentId) -{ - wxDirItemData *data = (wxDirItemData *) m_treeCtrl->GetItemData(parentId); - - if (data->m_isExpanded) - return; - - data->m_isExpanded = true; - - if (parentId == m_treeCtrl->GetRootItem()) - { - SetupSections(); - return; - } - - wxASSERT(data); - - wxString search,path,filename; - - wxString dirName(data->m_path); - -#if (defined(__WINDOWS__) && !defined(__WXWINCE__)) || defined(__DOS__) || defined(__OS2__) - // Check if this is a root directory and if so, - // whether the drive is avaiable. - if (!wxIsDriveAvailable(dirName)) - { - data->m_isExpanded = false; - //wxMessageBox(wxT("Sorry, this drive is not available.")); - return; - } -#endif - - // This may take a longish time. Go to busy cursor - wxBusyCursor busy; - -#if defined(__WINDOWS__) || defined(__DOS__) || defined(__OS2__) - if (dirName.Last() == ':') - dirName += wxString(wxFILE_SEP_PATH); -#endif - - wxArrayString dirs; - wxArrayString filenames; - - wxDir d; - wxString eachFilename; - - wxLogNull log; - d.Open(dirName); - - if (d.IsOpened()) - { - int style = wxDIR_DIRS; - if (m_showHidden) style |= wxDIR_HIDDEN; - if (d.GetFirst(& eachFilename, wxEmptyString, style)) - { - do - { - if ((eachFilename != wxT(".")) && (eachFilename != wxT(".."))) - { - dirs.Add(eachFilename); - } - } - while (d.GetNext(&eachFilename)); - } - } - dirs.Sort(wxDirCtrlStringCompareFunction); - - // Now do the filenames -- but only if we're allowed to - if ((GetWindowStyle() & wxDIRCTRL_DIR_ONLY) == 0) - { - d.Open(dirName); - - if (d.IsOpened()) - { - int style = wxDIR_FILES; - if (m_showHidden) style |= wxDIR_HIDDEN; - // Process each filter (ex: "JPEG Files (*.jpg;*.jpeg)|*.jpg;*.jpeg") - wxStringTokenizer strTok; - wxString curFilter; - strTok.SetString(m_currentFilterStr,wxT(";")); - while(strTok.HasMoreTokens()) - { - curFilter = strTok.GetNextToken(); - if (d.GetFirst(& eachFilename, curFilter, style)) - { - do - { - if ((eachFilename != wxT(".")) && (eachFilename != wxT(".."))) - { - filenames.Add(eachFilename); - } - } - while (d.GetNext(& eachFilename)); - } - } - } - filenames.Sort(wxDirCtrlStringCompareFunction); - } - - // Add the sorted dirs - size_t i; - for (i = 0; i < dirs.Count(); i++) - { - eachFilename = dirs[i]; - path = dirName; - if (!wxEndsWithPathSeparator(path)) - path += wxString(wxFILE_SEP_PATH); - path += eachFilename; - - wxDirItemData *dir_item = new wxDirItemData(path,eachFilename,true); - wxTreeItemId id = AppendItem( parentId, eachFilename, - wxFileIconsTable::folder, -1, dir_item); - m_treeCtrl->SetItemImage( id, wxFileIconsTable::folder_open, - wxTreeItemIcon_Expanded ); - - // Has this got any children? If so, make it expandable. - // (There are two situations when a dir has children: either it - // has subdirectories or it contains files that weren't filtered - // out. The latter only applies to dirctrl with files.) - if ( dir_item->HasSubDirs() || - (((GetWindowStyle() & wxDIRCTRL_DIR_ONLY) == 0) && - dir_item->HasFiles(m_currentFilterStr)) ) - { - m_treeCtrl->SetItemHasChildren(id); - } - } - - // Add the sorted filenames - if ((GetWindowStyle() & wxDIRCTRL_DIR_ONLY) == 0) - { - for (i = 0; i < filenames.Count(); i++) - { - eachFilename = filenames[i]; - path = dirName; - if (!wxEndsWithPathSeparator(path)) - path += wxString(wxFILE_SEP_PATH); - path += eachFilename; - //path = dirName + wxString(wxT("/")) + eachFilename; - wxDirItemData *dir_item = new wxDirItemData(path,eachFilename,false); - int image_id = wxFileIconsTable::file; - if (eachFilename.Find(wxT('.')) != wxNOT_FOUND) - image_id = wxTheFileIconsTable->GetIconID(eachFilename.AfterLast(wxT('.'))); - (void) AppendItem( parentId, eachFilename, image_id, -1, dir_item); - } - } -} - -void wxGenericDirCtrl::ReCreateTree() -{ - CollapseDir(m_treeCtrl->GetRootItem()); - ExpandRoot(); -} - -void wxGenericDirCtrl::CollapseTree() -{ - wxTreeItemIdValue cookie; - wxTreeItemId child = m_treeCtrl->GetFirstChild(m_rootId, cookie); - while (child.IsOk()) - { - CollapseDir(child); - child = m_treeCtrl->GetNextChild(m_rootId, cookie); - } -} - -// Find the child that matches the first part of 'path'. -// E.g. if a child path is "/usr" and 'path' is "/usr/include" -// then the child for /usr is returned. -wxTreeItemId wxGenericDirCtrl::FindChild(wxTreeItemId parentId, const wxString& path, bool& done) -{ - wxString path2(path); - - // Make sure all separators are as per the current platform - path2.Replace(wxT("\\"), wxString(wxFILE_SEP_PATH)); - path2.Replace(wxT("/"), wxString(wxFILE_SEP_PATH)); - - // Append a separator to foil bogus substring matching - path2 += wxString(wxFILE_SEP_PATH); - - // In MSW or PM, case is not significant -#if defined(__WINDOWS__) || defined(__DOS__) || defined(__OS2__) - path2.MakeLower(); -#endif - - wxTreeItemIdValue cookie; - wxTreeItemId childId = m_treeCtrl->GetFirstChild(parentId, cookie); - while (childId.IsOk()) - { - wxDirItemData* data = (wxDirItemData*) m_treeCtrl->GetItemData(childId); - - if (data && !data->m_path.empty()) - { - wxString childPath(data->m_path); - if (!wxEndsWithPathSeparator(childPath)) - childPath += wxString(wxFILE_SEP_PATH); - - // In MSW and PM, case is not significant -#if defined(__WINDOWS__) || defined(__DOS__) || defined(__OS2__) - childPath.MakeLower(); -#endif - - if (childPath.length() <= path2.length()) - { - wxString path3 = path2.Mid(0, childPath.length()); - if (childPath == path3) - { - if (path3.length() == path2.length()) - done = true; - else - done = false; - return childId; - } - } - } - - childId = m_treeCtrl->GetNextChild(parentId, cookie); - } - wxTreeItemId invalid; - return invalid; -} - -// Try to expand as much of the given path as possible, -// and select the given tree item. -bool wxGenericDirCtrl::ExpandPath(const wxString& path) -{ - bool done = false; - wxTreeItemId id = FindChild(m_rootId, path, done); - wxTreeItemId lastId = id; // The last non-zero id - while (id.IsOk() && !done) - { - ExpandDir(id); - - id = FindChild(id, path, done); - if (id.IsOk()) - lastId = id; - } - if (!lastId.IsOk()) - return false; - - wxDirItemData *data = (wxDirItemData *) m_treeCtrl->GetItemData(lastId); - if (data->m_isDir) - { - m_treeCtrl->Expand(lastId); - } - if ((GetWindowStyle() & wxDIRCTRL_SELECT_FIRST) && data->m_isDir) - { - // Find the first file in this directory - wxTreeItemIdValue cookie; - wxTreeItemId childId = m_treeCtrl->GetFirstChild(lastId, cookie); - bool selectedChild = false; - while (childId.IsOk()) - { - data = (wxDirItemData*) m_treeCtrl->GetItemData(childId); - - if (data && data->m_path != wxEmptyString && !data->m_isDir) - { - m_treeCtrl->SelectItem(childId); - m_treeCtrl->EnsureVisible(childId); - selectedChild = true; - break; - } - childId = m_treeCtrl->GetNextChild(lastId, cookie); - } - if (!selectedChild) - { - m_treeCtrl->SelectItem(lastId); - m_treeCtrl->EnsureVisible(lastId); - } - } - else - { - m_treeCtrl->SelectItem(lastId); - m_treeCtrl->EnsureVisible(lastId); - } - - return true; -} - - -bool wxGenericDirCtrl::CollapsePath(const wxString& path) -{ - bool done = false; - wxTreeItemId id = FindChild(m_rootId, path, done); - wxTreeItemId lastId = id; // The last non-zero id - - while ( id.IsOk() && !done ) - { - CollapseDir(id); - - id = FindChild(id, path, done); - - if ( id.IsOk() ) - lastId = id; - } - - if ( !lastId.IsOk() ) - return false; - - m_treeCtrl->SelectItem(lastId); - m_treeCtrl->EnsureVisible(lastId); - - return true; -} - - -wxString wxGenericDirCtrl::GetPath() const -{ - wxTreeItemId id = m_treeCtrl->GetSelection(); - if (id) - { - wxDirItemData* data = (wxDirItemData*) m_treeCtrl->GetItemData(id); - return data->m_path; - } - else - return wxEmptyString; -} - -wxString wxGenericDirCtrl::GetFilePath() const -{ - wxTreeItemId id = m_treeCtrl->GetSelection(); - if (id) - { - wxDirItemData* data = (wxDirItemData*) m_treeCtrl->GetItemData(id); - if (data->m_isDir) - return wxEmptyString; - else - return data->m_path; - } - else - return wxEmptyString; -} - -void wxGenericDirCtrl::SetPath(const wxString& path) -{ - m_defaultPath = path; - if (m_rootId) - ExpandPath(path); -} - -// Not used -#if 0 -void wxGenericDirCtrl::FindChildFiles(wxTreeItemId id, int dirFlags, wxArrayString& filenames) -{ - wxDirItemData *data = (wxDirItemData *) m_treeCtrl->GetItemData(id); - - // This may take a longish time. Go to busy cursor - wxBusyCursor busy; - - wxASSERT(data); - - wxString search,path,filename; - - wxString dirName(data->m_path); - -#if defined(__WXMSW__) || defined(__OS2__) - if (dirName.Last() == ':') - dirName += wxString(wxFILE_SEP_PATH); -#endif - - wxDir d; - wxString eachFilename; - - wxLogNull log; - d.Open(dirName); - - if (d.IsOpened()) - { - if (d.GetFirst(& eachFilename, m_currentFilterStr, dirFlags)) - { - do - { - if ((eachFilename != wxT(".")) && (eachFilename != wxT(".."))) - { - filenames.Add(eachFilename); - } - } - while (d.GetNext(& eachFilename)) ; - } - } -} -#endif - -void wxGenericDirCtrl::SetFilterIndex(int n) -{ - m_currentFilter = n; - - wxString f, d; - if (ExtractWildcard(m_filter, n, f, d)) - m_currentFilterStr = f; - else -#ifdef __UNIX__ - m_currentFilterStr = wxT("*"); -#else - m_currentFilterStr = wxT("*.*"); -#endif -} - -void wxGenericDirCtrl::SetFilter(const wxString& filter) -{ - m_filter = filter; - - wxString f, d; - if (ExtractWildcard(m_filter, m_currentFilter, f, d)) - m_currentFilterStr = f; - else -#ifdef __UNIX__ - m_currentFilterStr = wxT("*"); -#else - m_currentFilterStr = wxT("*.*"); -#endif - - // current filter index is meaningless after filter change, set it to zero - SetFilterIndex(0); - if (m_filterListCtrl) - m_filterListCtrl->FillFilterList(m_filter, 0); -} - -// Extract description and actual filter from overall filter string -bool wxGenericDirCtrl::ExtractWildcard(const wxString& filterStr, int n, wxString& filter, wxString& description) -{ - wxArrayString filters, descriptions; - int count = wxParseCommonDialogsFilter(filterStr, descriptions, filters); - if (count > 0 && n < count) - { - filter = filters[n]; - description = descriptions[n]; - return true; - } - - return false; -} - -#if WXWIN_COMPATIBILITY_2_4 -// Parses the global filter, returning the number of filters. -// Returns 0 if none or if there's a problem. -// filterStr is in the form: "All files (*.*)|*.*|JPEG Files (*.jpeg)|*.jpg" -int wxGenericDirCtrl::ParseFilter(const wxString& filterStr, wxArrayString& filters, wxArrayString& descriptions) -{ - return wxParseCommonDialogsFilter(filterStr, descriptions, filters ); -} -#endif // WXWIN_COMPATIBILITY_2_4 - -void wxGenericDirCtrl::DoResize() -{ - wxSize sz = GetClientSize(); - int verticalSpacing = 3; - if (m_treeCtrl) - { - wxSize filterSz ; - if (m_filterListCtrl) - { - filterSz = m_filterListCtrl->GetSize(); - sz.y -= (filterSz.y + verticalSpacing); - } - m_treeCtrl->SetSize(0, 0, sz.x, sz.y); - if (m_filterListCtrl) - { - m_filterListCtrl->SetSize(0, sz.y + verticalSpacing, sz.x, filterSz.y); - // Don't know why, but this needs refreshing after a resize (wxMSW) - m_filterListCtrl->Refresh(); - } - } -} - - -void wxGenericDirCtrl::OnSize(wxSizeEvent& WXUNUSED(event)) -{ - DoResize(); -} - -wxTreeItemId wxGenericDirCtrl::AppendItem (const wxTreeItemId & parent, - const wxString & text, - int image, int selectedImage, - wxTreeItemData * data) -{ - wxTreeCtrl *treeCtrl = GetTreeCtrl (); - - wxASSERT (treeCtrl); - - if (treeCtrl) - { - return treeCtrl->AppendItem (parent, text, image, selectedImage, data); - } - else - { - return wxTreeItemId(); - } -} - - -//----------------------------------------------------------------------------- -// wxDirFilterListCtrl -//----------------------------------------------------------------------------- - -IMPLEMENT_CLASS(wxDirFilterListCtrl, wxChoice) - -BEGIN_EVENT_TABLE(wxDirFilterListCtrl, wxChoice) - EVT_CHOICE(wxID_ANY, wxDirFilterListCtrl::OnSelFilter) -END_EVENT_TABLE() - -bool wxDirFilterListCtrl::Create(wxGenericDirCtrl* parent, const wxWindowID id, - const wxPoint& pos, - const wxSize& size, - long style) -{ - m_dirCtrl = parent; - return wxChoice::Create(parent, id, pos, size, 0, NULL, style); -} - -void wxDirFilterListCtrl::Init() -{ - m_dirCtrl = NULL; -} - -void wxDirFilterListCtrl::OnSelFilter(wxCommandEvent& WXUNUSED(event)) -{ - int sel = GetSelection(); - - wxString currentPath = m_dirCtrl->GetPath(); - - m_dirCtrl->SetFilterIndex(sel); - - // If the filter has changed, the view is out of date, so - // collapse the tree. - m_dirCtrl->ReCreateTree(); - - // Try to restore the selection, or at least the directory - m_dirCtrl->ExpandPath(currentPath); -} - -void wxDirFilterListCtrl::FillFilterList(const wxString& filter, int defaultFilter) -{ - Clear(); - wxArrayString descriptions, filters; - size_t n = (size_t) wxParseCommonDialogsFilter(filter, descriptions, filters); - - if (n > 0 && defaultFilter < (int) n) - { - for (size_t i = 0; i < n; i++) - Append(descriptions[i]); - SetSelection(defaultFilter); - } -} -#endif // wxUSE_DIRDLG - -#if wxUSE_DIRDLG || wxUSE_FILEDLG - -// ---------------------------------------------------------------------------- -// wxFileIconsTable icons -// ---------------------------------------------------------------------------- - -#ifndef __WXGTK24__ -/* Computer (c) Julian Smart */ -static const char * file_icons_tbl_computer_xpm[] = { -/* columns rows colors chars-per-pixel */ -"16 16 42 1", -"r c #4E7FD0", -"$ c #7198D9", -"; c #DCE6F6", -"q c #FFFFFF", -"u c #4A7CCE", -"# c #779DDB", -"w c #95B2E3", -"y c #7FA2DD", -"f c #3263B4", -"= c #EAF0FA", -"< c #B1C7EB", -"% c #6992D7", -"9 c #D9E4F5", -"o c #9BB7E5", -"6 c #F7F9FD", -", c #BED0EE", -"3 c #F0F5FC", -"1 c #A8C0E8", -" c None", -"0 c #FDFEFF", -"4 c #C4D5F0", -"@ c #81A4DD", -"e c #4377CD", -"- c #E2EAF8", -"i c #9FB9E5", -"> c #CCDAF2", -"+ c #89A9DF", -"s c #5584D1", -"t c #5D89D3", -": c #D2DFF4", -"5 c #FAFCFE", -"2 c #F5F8FD", -"8 c #DFE8F7", -"& c #5E8AD4", -"X c #638ED5", -"a c #CEDCF2", -"p c #90AFE2", -"d c #2F5DA9", -"* c #5282D0", -"7 c #E5EDF9", -". c #A2BCE6", -"O c #8CACE0", -/* pixels */ -" ", -" .XXXXXXXXXXX ", -" oXO++@#$%&*X ", -" oX=-;:>,<1%X ", -" oX23=-;:4,$X ", -" oX5633789:@X ", -" oX05623=78+X ", -" oXqq05623=OX ", -" oX,,,,,<<<$X ", -" wXXXXXXXXXXe ", -" XrtX%$$y@+O,, ", -" uyiiiiiiiii@< ", -" ouiiiiiiiiiipAdd(wxArtProvider::GetBitmap(wxART_FOLDER, - wxART_CMN_DIALOG, - wxSize(16, 16))); - // folder_open - m_smallImageList->Add(wxArtProvider::GetBitmap(wxART_FOLDER_OPEN, - wxART_CMN_DIALOG, - wxSize(16, 16))); - // computer -#ifdef __WXGTK24__ - // GTK24 uses this icon in the file open dialog - m_smallImageList->Add(wxArtProvider::GetBitmap(wxART_HARDDISK, - wxART_CMN_DIALOG, - wxSize(16, 16))); -#else - m_smallImageList->Add(wxIcon(file_icons_tbl_computer_xpm)); -#endif - // drive - m_smallImageList->Add(wxArtProvider::GetBitmap(wxART_HARDDISK, - wxART_CMN_DIALOG, - wxSize(16, 16))); - // cdrom - m_smallImageList->Add(wxArtProvider::GetBitmap(wxART_CDROM, - wxART_CMN_DIALOG, - wxSize(16, 16))); - // floppy - m_smallImageList->Add(wxArtProvider::GetBitmap(wxART_FLOPPY, - wxART_CMN_DIALOG, - wxSize(16, 16))); - // removeable - m_smallImageList->Add(wxArtProvider::GetBitmap(wxART_REMOVABLE, - wxART_CMN_DIALOG, - wxSize(16, 16))); - // file - m_smallImageList->Add(wxArtProvider::GetBitmap(wxART_NORMAL_FILE, - wxART_CMN_DIALOG, - wxSize(16, 16))); - // executable - if (GetIconID(wxEmptyString, _T("application/x-executable")) == file) - { - m_smallImageList->Add(wxArtProvider::GetBitmap(wxART_EXECUTABLE_FILE, - wxART_CMN_DIALOG, - wxSize(16, 16))); - delete m_HashTable->Get(_T("exe")); - m_HashTable->Delete(_T("exe")); - m_HashTable->Put(_T("exe"), new wxFileIconEntry(executable)); - } - /* else put into list by GetIconID - (KDE defines application/x-executable for *.exe and has nice icon) - */ -} - -wxImageList *wxFileIconsTable::GetSmallImageList() -{ - if (!m_smallImageList) - Create(); - - return m_smallImageList; -} - -#if wxUSE_MIMETYPE && wxUSE_IMAGE && (!defined(__WXMSW__) || wxUSE_WXDIB) -// VS: we don't need this function w/o wxMimeTypesManager because we'll only have -// one icon and we won't resize it - -static wxBitmap CreateAntialiasedBitmap(const wxImage& img) -{ - const unsigned int size = 16; - - wxImage smallimg (size, size); - unsigned char *p1, *p2, *ps; - unsigned char mr = img.GetMaskRed(), - mg = img.GetMaskGreen(), - mb = img.GetMaskBlue(); - - unsigned x, y; - unsigned sr, sg, sb, smask; - - p1 = img.GetData(), p2 = img.GetData() + 3 * size*2, ps = smallimg.GetData(); - smallimg.SetMaskColour(mr, mr, mr); - - for (y = 0; y < size; y++) - { - for (x = 0; x < size; x++) - { - sr = sg = sb = smask = 0; - if (p1[0] != mr || p1[1] != mg || p1[2] != mb) - sr += p1[0], sg += p1[1], sb += p1[2]; - else smask++; - p1 += 3; - if (p1[0] != mr || p1[1] != mg || p1[2] != mb) - sr += p1[0], sg += p1[1], sb += p1[2]; - else smask++; - p1 += 3; - if (p2[0] != mr || p2[1] != mg || p2[2] != mb) - sr += p2[0], sg += p2[1], sb += p2[2]; - else smask++; - p2 += 3; - if (p2[0] != mr || p2[1] != mg || p2[2] != mb) - sr += p2[0], sg += p2[1], sb += p2[2]; - else smask++; - p2 += 3; - - if (smask > 2) - ps[0] = ps[1] = ps[2] = mr; - else - { - ps[0] = (unsigned char)(sr >> 2); - ps[1] = (unsigned char)(sg >> 2); - ps[2] = (unsigned char)(sb >> 2); - } - ps += 3; - } - p1 += size*2 * 3, p2 += size*2 * 3; - } - - return wxBitmap(smallimg); -} - -// This function is currently not unused anymore -#if 0 -// finds empty borders and return non-empty area of image: -static wxImage CutEmptyBorders(const wxImage& img) -{ - unsigned char mr = img.GetMaskRed(), - mg = img.GetMaskGreen(), - mb = img.GetMaskBlue(); - unsigned char *dt = img.GetData(), *dttmp; - unsigned w = img.GetWidth(), h = img.GetHeight(); - - unsigned top, bottom, left, right, i; - bool empt; - -#define MK_DTTMP(x,y) dttmp = dt + ((x + y * w) * 3) -#define NOEMPTY_PIX(empt) if (dttmp[0] != mr || dttmp[1] != mg || dttmp[2] != mb) {empt = false; break;} - - for (empt = true, top = 0; empt && top < h; top++) - { - MK_DTTMP(0, top); - for (i = 0; i < w; i++, dttmp+=3) - NOEMPTY_PIX(empt) - } - for (empt = true, bottom = h-1; empt && bottom > top; bottom--) - { - MK_DTTMP(0, bottom); - for (i = 0; i < w; i++, dttmp+=3) - NOEMPTY_PIX(empt) - } - for (empt = true, left = 0; empt && left < w; left++) - { - MK_DTTMP(left, 0); - for (i = 0; i < h; i++, dttmp+=3*w) - NOEMPTY_PIX(empt) - } - for (empt = true, right = w-1; empt && right > left; right--) - { - MK_DTTMP(right, 0); - for (i = 0; i < h; i++, dttmp+=3*w) - NOEMPTY_PIX(empt) - } - top--, left--, bottom++, right++; - - return img.GetSubImage(wxRect(left, top, right - left + 1, bottom - top + 1)); -} -#endif // #if 0 - -#endif // wxUSE_MIMETYPE - -int wxFileIconsTable::GetIconID(const wxString& extension, const wxString& mime) -{ - if (!m_smallImageList) - Create(); - -#if wxUSE_MIMETYPE - if (!extension.empty()) - { - wxFileIconEntry *entry = (wxFileIconEntry*) m_HashTable->Get(extension); - if (entry) return (entry -> id); - } - - wxFileType *ft = (mime.empty()) ? - wxTheMimeTypesManager -> GetFileTypeFromExtension(extension) : - wxTheMimeTypesManager -> GetFileTypeFromMimeType(mime); - - wxIconLocation iconLoc; - wxIcon ic; - - { - wxLogNull logNull; - if ( ft && ft->GetIcon(&iconLoc) ) - { - ic = wxIcon( iconLoc ); - } - } - - delete ft; - - if ( !ic.Ok() ) - { - int newid = file; - m_HashTable->Put(extension, new wxFileIconEntry(newid)); - return newid; - } - - wxBitmap bmp; - bmp.CopyFromIcon(ic); - - if ( !bmp.Ok() ) - { - int newid = file; - m_HashTable->Put(extension, new wxFileIconEntry(newid)); - return newid; - } - - const unsigned int size = 16; - - int id = m_smallImageList->GetImageCount(); - if ((bmp.GetWidth() == (int) size) && (bmp.GetHeight() == (int) size)) - { - m_smallImageList->Add(bmp); - } -#if wxUSE_IMAGE && (!defined(__WXMSW__) || wxUSE_WXDIB) - else - { - wxImage img = bmp.ConvertToImage(); - - if ((img.GetWidth() != size*2) || (img.GetHeight() != size*2)) -// m_smallImageList->Add(CreateAntialiasedBitmap(CutEmptyBorders(img).Rescale(size*2, size*2))); - m_smallImageList->Add(CreateAntialiasedBitmap(img.Rescale(size*2, size*2))); - else - m_smallImageList->Add(CreateAntialiasedBitmap(img)); - } -#endif // wxUSE_IMAGE - - m_HashTable->Put(extension, new wxFileIconEntry(id)); - return id; - -#else // !wxUSE_MIMETYPE - - wxUnusedVar(mime); - if (extension == wxT("exe")) - return executable; - else - return file; -#endif // wxUSE_MIMETYPE/!wxUSE_MIMETYPE -} - -#endif // wxUSE_DIRDLG || wxUSE_FILEDLG +///////////////////////////////////////////////////////////////////////////// +// Name: src/generic/dirctrlg.cpp +// Purpose: wxGenericDirCtrl +// Author: Harm van der Heijden, Robert Roebling, Julian Smart +// Modified by: +// Created: 12/12/98 +// RCS-ID: $Id: dirctrlg.cpp 46614 2007-06-22 12:12:10Z JS $ +// Copyright: (c) Harm van der Heijden, Robert Roebling and Julian Smart +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_DIRDLG || wxUSE_FILEDLG + +#include "wx/generic/dirctrlg.h" + +#ifndef WX_PRECOMP + #include "wx/hash.h" + #include "wx/intl.h" + #include "wx/log.h" + #include "wx/utils.h" + #include "wx/button.h" + #include "wx/icon.h" + #include "wx/settings.h" + #include "wx/msgdlg.h" + #include "wx/cmndata.h" + #include "wx/choice.h" + #include "wx/textctrl.h" + #include "wx/layout.h" + #include "wx/sizer.h" + #include "wx/textdlg.h" + #include "wx/gdicmn.h" + #include "wx/image.h" + #include "wx/module.h" +#endif + +#include "wx/filefn.h" +#include "wx/imaglist.h" +#include "wx/tokenzr.h" +#include "wx/dir.h" +#include "wx/artprov.h" +#include "wx/mimetype.h" + +#if wxUSE_STATLINE + #include "wx/statline.h" +#endif + +#if defined(__WXMAC__) + #include "wx/mac/private.h" // includes mac headers +#endif + +#ifdef __WXMSW__ +#include +#include "wx/msw/winundef.h" + +// FIXME - Mingw32 1.0 has both _getdrive() and _chdrive(). For now, let's assume +// older releases don't, but it should be verified and the checks modified +// accordingly. +#if !defined(__GNUWIN32__) || (defined(__MINGW32_MAJOR_VERSION) && __MINGW32_MAJOR_VERSION >= 1) +#if !defined(__WXWINCE__) + #include +#endif + #include + #include +#endif + +#endif + +#if defined(__OS2__) || defined(__DOS__) + #ifdef __OS2__ + #define INCL_BASE + #include + #ifndef __EMX__ + #include + #endif + #include + #include + #endif + extern bool wxIsDriveAvailable(const wxString& dirName); +#endif // __OS2__ + +#if defined(__WXMAC__) + #include "MoreFilesX.h" +#endif + +#ifdef __BORLANDC__ + #include "dos.h" +#endif + +// If compiled under Windows, this macro can cause problems +#ifdef GetFirstChild +#undef GetFirstChild +#endif + +// ---------------------------------------------------------------------------- +// wxGetAvailableDrives, for WINDOWS, DOS, OS2, MAC, UNIX (returns "/") +// ---------------------------------------------------------------------------- + +size_t wxGetAvailableDrives(wxArrayString &paths, wxArrayString &names, wxArrayInt &icon_ids) +{ +#if defined(__WINDOWS__) || defined(__DOS__) || defined(__OS2__) + +#ifdef __WXWINCE__ + // No logical drives; return "\" + paths.Add(wxT("\\")); + names.Add(wxT("\\")); + icon_ids.Add(wxFileIconsTable::computer); +#elif defined(__WIN32__) + wxChar driveBuffer[256]; + size_t n = (size_t) GetLogicalDriveStrings(255, driveBuffer); + size_t i = 0; + while (i < n) + { + wxString path, name; + path.Printf(wxT("%c:\\"), driveBuffer[i]); + name.Printf(wxT("%c:"), driveBuffer[i]); + + // Do not use GetVolumeInformation to further decorate the + // name, since it can cause severe delays on network drives. + + int imageId; + int driveType = ::GetDriveType(path); + switch (driveType) + { + case DRIVE_REMOVABLE: + if (path == wxT("a:\\") || path == wxT("b:\\")) + imageId = wxFileIconsTable::floppy; + else + imageId = wxFileIconsTable::removeable; + break; + case DRIVE_CDROM: + imageId = wxFileIconsTable::cdrom; + break; + case DRIVE_REMOTE: + case DRIVE_FIXED: + default: + imageId = wxFileIconsTable::drive; + break; + } + + paths.Add(path); + names.Add(name); + icon_ids.Add(imageId); + + while (driveBuffer[i] != wxT('\0')) + i ++; + i ++; + if (driveBuffer[i] == wxT('\0')) + break; + } +#elif defined(__OS2__) + APIRET rc; + ULONG ulDriveNum = 0; + ULONG ulDriveMap = 0; + rc = ::DosQueryCurrentDisk(&ulDriveNum, &ulDriveMap); + if ( rc == 0) + { + size_t i = 0; + while (i < 26) + { + if (ulDriveMap & ( 1 << i )) + { + wxString path, name; + path.Printf(wxT("%c:\\"), 'A' + i); + name.Printf(wxT("%c:"), 'A' + i); + + // Note: If _filesys is unsupported by some compilers, + // we can always replace it by DosQueryFSAttach + char filesysname[20]; +#ifdef __WATCOMC__ + ULONG cbBuffer = sizeof(filesysname); + PFSQBUFFER2 pfsqBuffer = (PFSQBUFFER2)filesysname; + APIRET rc = ::DosQueryFSAttach(name.fn_str(),0,FSAIL_QUERYNAME,pfsqBuffer,&cbBuffer); + if (rc != NO_ERROR) + { + filesysname[0] = '\0'; + } +#else + _filesys(name.fn_str(), filesysname, sizeof(filesysname)); +#endif + /* FAT, LAN, HPFS, CDFS, NFS */ + int imageId; + if (path == wxT("A:\\") || path == wxT("B:\\")) + imageId = wxFileIconsTable::floppy; + else if (!strcmp(filesysname, "CDFS")) + imageId = wxFileIconsTable::cdrom; + else if (!strcmp(filesysname, "LAN") || + !strcmp(filesysname, "NFS")) + imageId = wxFileIconsTable::drive; + else + imageId = wxFileIconsTable::drive; + paths.Add(path); + names.Add(name); + icon_ids.Add(imageId); + } + i ++; + } + } +#else // !__WIN32__, !__OS2__ + int drive; + + /* If we can switch to the drive, it exists. */ + for( drive = 1; drive <= 26; drive++ ) + { + wxString path, name; + path.Printf(wxT("%c:\\"), (char) (drive + 'a' - 1)); + name.Printf(wxT("%c:"), (char) (drive + 'A' - 1)); + + if (wxIsDriveAvailable(path)) + { + paths.Add(path); + names.Add(name); + icon_ids.Add((drive <= 2) ? wxFileIconsTable::floppy : wxFileIconsTable::drive); + } + } +#endif // __WIN32__/!__WIN32__ + +#elif defined(__WXMAC__) + + ItemCount volumeIndex = 1; + OSErr err = noErr ; + + while( noErr == err ) + { + HFSUniStr255 volumeName ; + FSRef fsRef ; + FSVolumeInfo volumeInfo ; + err = FSGetVolumeInfo(0, volumeIndex, NULL, kFSVolInfoFlags , &volumeInfo , &volumeName, &fsRef); + if( noErr == err ) + { + wxString path = wxMacFSRefToPath( &fsRef ) ; + wxString name = wxMacHFSUniStrToString( &volumeName ) ; + + if ( (volumeInfo.flags & kFSVolFlagSoftwareLockedMask) || (volumeInfo.flags & kFSVolFlagHardwareLockedMask) ) + { + icon_ids.Add(wxFileIconsTable::cdrom); + } + else + { + icon_ids.Add(wxFileIconsTable::drive); + } + // todo other removable + + paths.Add(path); + names.Add(name); + volumeIndex++ ; + } + } + +#elif defined(__UNIX__) + paths.Add(wxT("/")); + names.Add(wxT("/")); + icon_ids.Add(wxFileIconsTable::computer); +#else + #error "Unsupported platform in wxGenericDirCtrl!" +#endif + wxASSERT_MSG( (paths.GetCount() == names.GetCount()), wxT("The number of paths and their human readable names should be equal in number.")); + wxASSERT_MSG( (paths.GetCount() == icon_ids.GetCount()), wxT("Wrong number of icons for available drives.")); + return paths.GetCount(); +} + +// ---------------------------------------------------------------------------- +// wxIsDriveAvailable +// ---------------------------------------------------------------------------- + +#if defined(__DOS__) + +bool wxIsDriveAvailable(const wxString& dirName) +{ + // FIXME_MGL - this method leads to hang up under Watcom for some reason +#ifdef __WATCOMC__ + wxUnusedVar(dirName); +#else + if ( dirName.length() == 3 && dirName[1u] == wxT(':') ) + { + wxString dirNameLower(dirName.Lower()); + // VS: always return true for removable media, since Win95 doesn't + // like it when MS-DOS app accesses empty floppy drive + return (dirNameLower[0u] == wxT('a') || + dirNameLower[0u] == wxT('b') || + wxDirExists(dirNameLower)); + } + else +#endif + return true; +} + +#elif defined(__WINDOWS__) || defined(__OS2__) + +int setdrive(int WXUNUSED_IN_WINCE(drive)) +{ +#ifdef __WXWINCE__ + return 0; +#elif defined(__GNUWIN32__) && \ + (defined(__MINGW32_MAJOR_VERSION) && __MINGW32_MAJOR_VERSION >= 1) + return _chdrive(drive); +#else + wxChar newdrive[4]; + + if (drive < 1 || drive > 31) + return -1; + newdrive[0] = (wxChar)(wxT('A') + drive - 1); + newdrive[1] = wxT(':'); +#ifdef __OS2__ + newdrive[2] = wxT('\\'); + newdrive[3] = wxT('\0'); +#else + newdrive[2] = wxT('\0'); +#endif +#if defined(__WXMSW__) + if (::SetCurrentDirectory(newdrive)) +#else + // VA doesn't know what LPSTR is and has its own set + if (!DosSetCurrentDir((PSZ)newdrive)) +#endif + return 0; + else + return -1; +#endif // !GNUWIN32 +} + +bool wxIsDriveAvailable(const wxString& WXUNUSED_IN_WINCE(dirName)) +{ +#ifdef __WXWINCE__ + return false; +#else +#ifdef __WIN32__ + UINT errorMode = SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX); +#endif + bool success = true; + + // Check if this is a root directory and if so, + // whether the drive is available. + if (dirName.length() == 3 && dirName[(size_t)1] == wxT(':')) + { + wxString dirNameLower(dirName.Lower()); +#if defined(__GNUWIN32__) && !(defined(__MINGW32_MAJOR_VERSION) && __MINGW32_MAJOR_VERSION >= 1) + success = wxDirExists(dirNameLower); +#else + #if defined(__OS2__) + // Avoid changing to drive since no media may be inserted. + if (dirNameLower[(size_t)0] == 'a' || dirNameLower[(size_t)0] == 'b') + return success; + #endif + int currentDrive = _getdrive(); + int thisDrive = (int) (dirNameLower[(size_t)0] - 'a' + 1) ; + int err = setdrive( thisDrive ) ; + setdrive( currentDrive ); + + if (err == -1) + { + success = false; + } +#endif + } +#ifdef __WIN32__ + (void) SetErrorMode(errorMode); +#endif + + return success; +#endif +} +#endif // __WINDOWS__ || __OS2__ + +#endif // wxUSE_DIRDLG || wxUSE_FILEDLG + + + +#if wxUSE_DIRDLG + +// Function which is called by quick sort. We want to override the default wxArrayString behaviour, +// and sort regardless of case. +static int wxCMPFUNC_CONV wxDirCtrlStringCompareFunction(const wxString& strFirst, const wxString& strSecond) +{ + return strFirst.CmpNoCase(strSecond); +} + +//----------------------------------------------------------------------------- +// wxDirItemData +//----------------------------------------------------------------------------- + +wxDirItemData::wxDirItemData(const wxString& path, const wxString& name, + bool isDir) +{ + m_path = path; + m_name = name; + /* Insert logic to detect hidden files here + * In UnixLand we just check whether the first char is a dot + * For FileNameFromPath read LastDirNameInThisPath ;-) */ + // m_isHidden = (bool)(wxFileNameFromPath(*m_path)[0] == '.'); + m_isHidden = false; + m_isExpanded = false; + m_isDir = isDir; +} + +void wxDirItemData::SetNewDirName(const wxString& path) +{ + m_path = path; + m_name = wxFileNameFromPath(path); +} + +bool wxDirItemData::HasSubDirs() const +{ + if (m_path.empty()) + return false; + + wxDir dir; + { + wxLogNull nolog; + if ( !dir.Open(m_path) ) + return false; + } + + return dir.HasSubDirs(); +} + +bool wxDirItemData::HasFiles(const wxString& WXUNUSED(spec)) const +{ + if (m_path.empty()) + return false; + + wxDir dir; + { + wxLogNull nolog; + if ( !dir.Open(m_path) ) + return false; + } + + return dir.HasFiles(); +} + +//----------------------------------------------------------------------------- +// wxGenericDirCtrl +//----------------------------------------------------------------------------- + + +#if wxUSE_EXTENDED_RTTI +WX_DEFINE_FLAGS( wxGenericDirCtrlStyle ) + +wxBEGIN_FLAGS( wxGenericDirCtrlStyle ) + // new style border flags, we put them first to + // use them for streaming out + wxFLAGS_MEMBER(wxBORDER_SIMPLE) + wxFLAGS_MEMBER(wxBORDER_SUNKEN) + wxFLAGS_MEMBER(wxBORDER_DOUBLE) + wxFLAGS_MEMBER(wxBORDER_RAISED) + wxFLAGS_MEMBER(wxBORDER_STATIC) + wxFLAGS_MEMBER(wxBORDER_NONE) + + // old style border flags + wxFLAGS_MEMBER(wxSIMPLE_BORDER) + wxFLAGS_MEMBER(wxSUNKEN_BORDER) + wxFLAGS_MEMBER(wxDOUBLE_BORDER) + wxFLAGS_MEMBER(wxRAISED_BORDER) + wxFLAGS_MEMBER(wxSTATIC_BORDER) + wxFLAGS_MEMBER(wxBORDER) + + // standard window styles + wxFLAGS_MEMBER(wxTAB_TRAVERSAL) + wxFLAGS_MEMBER(wxCLIP_CHILDREN) + wxFLAGS_MEMBER(wxTRANSPARENT_WINDOW) + wxFLAGS_MEMBER(wxWANTS_CHARS) + wxFLAGS_MEMBER(wxFULL_REPAINT_ON_RESIZE) + wxFLAGS_MEMBER(wxALWAYS_SHOW_SB ) + wxFLAGS_MEMBER(wxVSCROLL) + wxFLAGS_MEMBER(wxHSCROLL) + + wxFLAGS_MEMBER(wxDIRCTRL_DIR_ONLY) + wxFLAGS_MEMBER(wxDIRCTRL_3D_INTERNAL) + wxFLAGS_MEMBER(wxDIRCTRL_SELECT_FIRST) + wxFLAGS_MEMBER(wxDIRCTRL_SHOW_FILTERS) + +wxEND_FLAGS( wxGenericDirCtrlStyle ) + +IMPLEMENT_DYNAMIC_CLASS_XTI(wxGenericDirCtrl, wxControl,"wx/dirctrl.h") + +wxBEGIN_PROPERTIES_TABLE(wxGenericDirCtrl) + wxHIDE_PROPERTY( Children ) + wxPROPERTY( DefaultPath , wxString , SetDefaultPath , GetDefaultPath , EMPTY_MACROVALUE , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) + wxPROPERTY( Filter , wxString , SetFilter , GetFilter , EMPTY_MACROVALUE , 0 /*flags*/ , wxT("Helpstring") , wxT("group") ) + wxPROPERTY( DefaultFilter , int , SetFilterIndex, GetFilterIndex, EMPTY_MACROVALUE , 0 /*flags*/ , wxT("Helpstring") , wxT("group") ) + wxPROPERTY_FLAGS( WindowStyle, wxGenericDirCtrlStyle, long, SetWindowStyleFlag, GetWindowStyleFlag, EMPTY_MACROVALUE , 0, wxT("Helpstring"), wxT("group") ) +wxEND_PROPERTIES_TABLE() + +wxBEGIN_HANDLERS_TABLE(wxGenericDirCtrl) +wxEND_HANDLERS_TABLE() + +wxCONSTRUCTOR_8( wxGenericDirCtrl , wxWindow* , Parent , wxWindowID , Id , wxString , DefaultPath , + wxPoint , Position , wxSize , Size , long , WindowStyle , wxString , Filter , int , DefaultFilter ) +#else +IMPLEMENT_DYNAMIC_CLASS(wxGenericDirCtrl, wxControl) +#endif + +BEGIN_EVENT_TABLE(wxGenericDirCtrl, wxControl) + EVT_TREE_ITEM_EXPANDING (wxID_TREECTRL, wxGenericDirCtrl::OnExpandItem) + EVT_TREE_ITEM_COLLAPSED (wxID_TREECTRL, wxGenericDirCtrl::OnCollapseItem) + EVT_TREE_BEGIN_LABEL_EDIT (wxID_TREECTRL, wxGenericDirCtrl::OnBeginEditItem) + EVT_TREE_END_LABEL_EDIT (wxID_TREECTRL, wxGenericDirCtrl::OnEndEditItem) + EVT_SIZE (wxGenericDirCtrl::OnSize) +END_EVENT_TABLE() + +wxGenericDirCtrl::wxGenericDirCtrl(void) +{ + Init(); +} + +void wxGenericDirCtrl::ExpandRoot() +{ + ExpandDir(m_rootId); // automatically expand first level + + // Expand and select the default path + if (!m_defaultPath.empty()) + { + ExpandPath(m_defaultPath); + } +#ifdef __UNIX__ + else + { + // On Unix, there's only one node under the (hidden) root node. It + // represents the / path, so the user would always have to expand it; + // let's do it ourselves + ExpandPath( wxT("/") ); + } +#endif +} + +bool wxGenericDirCtrl::Create(wxWindow *parent, + const wxWindowID id, + const wxString& dir, + const wxPoint& pos, + const wxSize& size, + long style, + const wxString& filter, + int defaultFilter, + const wxString& name) +{ + if (!wxControl::Create(parent, id, pos, size, style, wxDefaultValidator, name)) + return false; + + SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE)); + SetForegroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT)); + + Init(); + + long treeStyle = wxTR_HAS_BUTTONS; + + // On Windows CE, if you hide the root, you get a crash when + // attempting to access data for children of the root item. +#ifndef __WXWINCE__ + treeStyle |= wxTR_HIDE_ROOT; +#endif + +#ifdef __WXGTK20__ + treeStyle |= wxTR_NO_LINES; +#endif + + if (style & wxDIRCTRL_EDIT_LABELS) + treeStyle |= wxTR_EDIT_LABELS; + + if ((style & wxDIRCTRL_3D_INTERNAL) == 0) + treeStyle |= wxNO_BORDER; + else + treeStyle |= wxBORDER_SUNKEN; + + long filterStyle = 0; + if ((style & wxDIRCTRL_3D_INTERNAL) == 0) + filterStyle |= wxNO_BORDER; + else + filterStyle |= wxBORDER_SUNKEN; + + m_treeCtrl = CreateTreeCtrl(this, wxID_TREECTRL, + wxPoint(0,0), GetClientSize(), treeStyle); + + if (!filter.empty() && (style & wxDIRCTRL_SHOW_FILTERS)) + m_filterListCtrl = new wxDirFilterListCtrl(this, wxID_FILTERLISTCTRL, wxDefaultPosition, wxDefaultSize, filterStyle); + + m_defaultPath = dir; + m_filter = filter; + + if (m_filter.empty()) +#ifdef __UNIX__ + m_filter = wxT("*"); +#else + m_filter = wxT("*.*"); +#endif + + SetFilterIndex(defaultFilter); + + if (m_filterListCtrl) + m_filterListCtrl->FillFilterList(filter, defaultFilter); + + m_treeCtrl->SetImageList(wxTheFileIconsTable->GetSmallImageList()); + + m_showHidden = false; + wxDirItemData* rootData = new wxDirItemData(wxEmptyString, wxEmptyString, true); + + wxString rootName; + +#if defined(__WINDOWS__) || defined(__OS2__) || defined(__DOS__) + rootName = _("Computer"); +#else + rootName = _("Sections"); +#endif + + m_rootId = m_treeCtrl->AddRoot( rootName, 3, -1, rootData); + m_treeCtrl->SetItemHasChildren(m_rootId); + + ExpandRoot(); + + SetInitialSize(size); + DoResize(); + + return true; +} + +wxGenericDirCtrl::~wxGenericDirCtrl() +{ +} + +void wxGenericDirCtrl::Init() +{ + m_showHidden = false; + m_currentFilter = 0; + m_currentFilterStr = wxEmptyString; // Default: any file + m_treeCtrl = NULL; + m_filterListCtrl = NULL; +} + +wxTreeCtrl* wxGenericDirCtrl::CreateTreeCtrl(wxWindow *parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long treeStyle) +{ + return new wxTreeCtrl(parent, id, pos, size, treeStyle); +} + +void wxGenericDirCtrl::ShowHidden( bool show ) +{ + m_showHidden = show; + + wxString path = GetPath(); + ReCreateTree(); + SetPath(path); +} + +const wxTreeItemId +wxGenericDirCtrl::AddSection(const wxString& path, const wxString& name, int imageId) +{ + wxDirItemData *dir_item = new wxDirItemData(path,name,true); + + wxTreeItemId id = AppendItem( m_rootId, name, imageId, -1, dir_item); + + m_treeCtrl->SetItemHasChildren(id); + + return id; +} + +void wxGenericDirCtrl::SetupSections() +{ + wxArrayString paths, names; + wxArrayInt icons; + + size_t n, count = wxGetAvailableDrives(paths, names, icons); + +#ifdef __WXGTK20__ + wxString home = wxGetHomeDir(); + AddSection( home, _("Home directory"), 1); + home += wxT("/Desktop"); + AddSection( home, _("Desktop"), 1); +#endif + + for (n = 0; n < count; n++) + AddSection(paths[n], names[n], icons[n]); +} + +void wxGenericDirCtrl::OnBeginEditItem(wxTreeEvent &event) +{ + // don't rename the main entry "Sections" + if (event.GetItem() == m_rootId) + { + event.Veto(); + return; + } + + // don't rename the individual sections + if (m_treeCtrl->GetItemParent( event.GetItem() ) == m_rootId) + { + event.Veto(); + return; + } +} + +void wxGenericDirCtrl::OnEndEditItem(wxTreeEvent &event) +{ + if (event.IsEditCancelled()) + return; + + if ((event.GetLabel().empty()) || + (event.GetLabel() == wxT(".")) || + (event.GetLabel() == wxT("..")) || + (event.GetLabel().Find(wxT('/')) != wxNOT_FOUND) || + (event.GetLabel().Find(wxT('\\')) != wxNOT_FOUND) || + (event.GetLabel().Find(wxT('|')) != wxNOT_FOUND)) + { + wxMessageDialog dialog(this, _("Illegal directory name."), _("Error"), wxOK | wxICON_ERROR ); + dialog.ShowModal(); + event.Veto(); + return; + } + + wxTreeItemId id = event.GetItem(); + wxDirItemData *data = (wxDirItemData*)m_treeCtrl->GetItemData( id ); + wxASSERT( data ); + + wxString new_name( wxPathOnly( data->m_path ) ); + new_name += wxString(wxFILE_SEP_PATH); + new_name += event.GetLabel(); + + wxLogNull log; + + if (wxFileExists(new_name)) + { + wxMessageDialog dialog(this, _("File name exists already."), _("Error"), wxOK | wxICON_ERROR ); + dialog.ShowModal(); + event.Veto(); + } + + if (wxRenameFile(data->m_path,new_name)) + { + data->SetNewDirName( new_name ); + } + else + { + wxMessageDialog dialog(this, _("Operation not permitted."), _("Error"), wxOK | wxICON_ERROR ); + dialog.ShowModal(); + event.Veto(); + } +} + +void wxGenericDirCtrl::OnExpandItem(wxTreeEvent &event) +{ + wxTreeItemId parentId = event.GetItem(); + + // VS: this is needed because the event handler is called from wxTreeCtrl + // ctor when wxTR_HIDE_ROOT was specified + + if (!m_rootId.IsOk()) + + m_rootId = m_treeCtrl->GetRootItem(); + + ExpandDir(parentId); +} + +void wxGenericDirCtrl::OnCollapseItem(wxTreeEvent &event ) +{ + CollapseDir(event.GetItem()); +} + +void wxGenericDirCtrl::CollapseDir(wxTreeItemId parentId) +{ + wxTreeItemId child; + + wxDirItemData *data = (wxDirItemData *) m_treeCtrl->GetItemData(parentId); + if (!data->m_isExpanded) + return; + + data->m_isExpanded = false; + wxTreeItemIdValue cookie; + /* Workaround because DeleteChildren has disapeared (why?) and + * CollapseAndReset doesn't work as advertised (deletes parent too) */ + child = m_treeCtrl->GetFirstChild(parentId, cookie); + while (child.IsOk()) + { + m_treeCtrl->Delete(child); + /* Not GetNextChild below, because the cookie mechanism can't + * handle disappearing children! */ + child = m_treeCtrl->GetFirstChild(parentId, cookie); + } + if (parentId != m_treeCtrl->GetRootItem()) + m_treeCtrl->Collapse(parentId); +} + +void wxGenericDirCtrl::ExpandDir(wxTreeItemId parentId) +{ + wxDirItemData *data = (wxDirItemData *) m_treeCtrl->GetItemData(parentId); + + if (data->m_isExpanded) + return; + + data->m_isExpanded = true; + + if (parentId == m_treeCtrl->GetRootItem()) + { + SetupSections(); + return; + } + + wxASSERT(data); + + wxString search,path,filename; + + wxString dirName(data->m_path); + +#if (defined(__WINDOWS__) && !defined(__WXWINCE__)) || defined(__DOS__) || defined(__OS2__) + // Check if this is a root directory and if so, + // whether the drive is avaiable. + if (!wxIsDriveAvailable(dirName)) + { + data->m_isExpanded = false; + //wxMessageBox(wxT("Sorry, this drive is not available.")); + return; + } +#endif + + // This may take a longish time. Go to busy cursor + wxBusyCursor busy; + +#if defined(__WINDOWS__) || defined(__DOS__) || defined(__OS2__) + if (dirName.Last() == ':') + dirName += wxString(wxFILE_SEP_PATH); +#endif + + wxArrayString dirs; + wxArrayString filenames; + + wxDir d; + wxString eachFilename; + + wxLogNull log; + d.Open(dirName); + + if (d.IsOpened()) + { + int style = wxDIR_DIRS; + if (m_showHidden) style |= wxDIR_HIDDEN; + if (d.GetFirst(& eachFilename, wxEmptyString, style)) + { + do + { + if ((eachFilename != wxT(".")) && (eachFilename != wxT(".."))) + { + dirs.Add(eachFilename); + } + } + while (d.GetNext(&eachFilename)); + } + } + dirs.Sort(wxDirCtrlStringCompareFunction); + + // Now do the filenames -- but only if we're allowed to + if ((GetWindowStyle() & wxDIRCTRL_DIR_ONLY) == 0) + { + d.Open(dirName); + + if (d.IsOpened()) + { + int style = wxDIR_FILES; + if (m_showHidden) style |= wxDIR_HIDDEN; + // Process each filter (ex: "JPEG Files (*.jpg;*.jpeg)|*.jpg;*.jpeg") + wxStringTokenizer strTok; + wxString curFilter; + strTok.SetString(m_currentFilterStr,wxT(";")); + while(strTok.HasMoreTokens()) + { + curFilter = strTok.GetNextToken(); + if (d.GetFirst(& eachFilename, curFilter, style)) + { + do + { + if ((eachFilename != wxT(".")) && (eachFilename != wxT(".."))) + { + filenames.Add(eachFilename); + } + } + while (d.GetNext(& eachFilename)); + } + } + } + filenames.Sort(wxDirCtrlStringCompareFunction); + } + + // Add the sorted dirs + size_t i; + for (i = 0; i < dirs.Count(); i++) + { + eachFilename = dirs[i]; + path = dirName; + if (!wxEndsWithPathSeparator(path)) + path += wxString(wxFILE_SEP_PATH); + path += eachFilename; + + wxDirItemData *dir_item = new wxDirItemData(path,eachFilename,true); + wxTreeItemId id = AppendItem( parentId, eachFilename, + wxFileIconsTable::folder, -1, dir_item); + m_treeCtrl->SetItemImage( id, wxFileIconsTable::folder_open, + wxTreeItemIcon_Expanded ); + + // Has this got any children? If so, make it expandable. + // (There are two situations when a dir has children: either it + // has subdirectories or it contains files that weren't filtered + // out. The latter only applies to dirctrl with files.) + if ( dir_item->HasSubDirs() || + (((GetWindowStyle() & wxDIRCTRL_DIR_ONLY) == 0) && + dir_item->HasFiles(m_currentFilterStr)) ) + { + m_treeCtrl->SetItemHasChildren(id); + } + } + + // Add the sorted filenames + if ((GetWindowStyle() & wxDIRCTRL_DIR_ONLY) == 0) + { + for (i = 0; i < filenames.Count(); i++) + { + eachFilename = filenames[i]; + path = dirName; + if (!wxEndsWithPathSeparator(path)) + path += wxString(wxFILE_SEP_PATH); + path += eachFilename; + //path = dirName + wxString(wxT("/")) + eachFilename; + wxDirItemData *dir_item = new wxDirItemData(path,eachFilename,false); + int image_id = wxFileIconsTable::file; + if (eachFilename.Find(wxT('.')) != wxNOT_FOUND) + image_id = wxTheFileIconsTable->GetIconID(eachFilename.AfterLast(wxT('.'))); + (void) AppendItem( parentId, eachFilename, image_id, -1, dir_item); + } + } +} + +void wxGenericDirCtrl::ReCreateTree() +{ + CollapseDir(m_treeCtrl->GetRootItem()); + ExpandRoot(); +} + +void wxGenericDirCtrl::CollapseTree() +{ + wxTreeItemIdValue cookie; + wxTreeItemId child = m_treeCtrl->GetFirstChild(m_rootId, cookie); + while (child.IsOk()) + { + CollapseDir(child); + child = m_treeCtrl->GetNextChild(m_rootId, cookie); + } +} + +// Find the child that matches the first part of 'path'. +// E.g. if a child path is "/usr" and 'path' is "/usr/include" +// then the child for /usr is returned. +wxTreeItemId wxGenericDirCtrl::FindChild(wxTreeItemId parentId, const wxString& path, bool& done) +{ + wxString path2(path); + + // Make sure all separators are as per the current platform + path2.Replace(wxT("\\"), wxString(wxFILE_SEP_PATH)); + path2.Replace(wxT("/"), wxString(wxFILE_SEP_PATH)); + + // Append a separator to foil bogus substring matching + path2 += wxString(wxFILE_SEP_PATH); + + // In MSW or PM, case is not significant +#if defined(__WINDOWS__) || defined(__DOS__) || defined(__OS2__) + path2.MakeLower(); +#endif + + wxTreeItemIdValue cookie; + wxTreeItemId childId = m_treeCtrl->GetFirstChild(parentId, cookie); + while (childId.IsOk()) + { + wxDirItemData* data = (wxDirItemData*) m_treeCtrl->GetItemData(childId); + + if (data && !data->m_path.empty()) + { + wxString childPath(data->m_path); + if (!wxEndsWithPathSeparator(childPath)) + childPath += wxString(wxFILE_SEP_PATH); + + // In MSW and PM, case is not significant +#if defined(__WINDOWS__) || defined(__DOS__) || defined(__OS2__) + childPath.MakeLower(); +#endif + + if (childPath.length() <= path2.length()) + { + wxString path3 = path2.Mid(0, childPath.length()); + if (childPath == path3) + { + if (path3.length() == path2.length()) + done = true; + else + done = false; + return childId; + } + } + } + + childId = m_treeCtrl->GetNextChild(parentId, cookie); + } + wxTreeItemId invalid; + return invalid; +} + +// Try to expand as much of the given path as possible, +// and select the given tree item. +bool wxGenericDirCtrl::ExpandPath(const wxString& path) +{ + bool done = false; + wxTreeItemId id = FindChild(m_rootId, path, done); + wxTreeItemId lastId = id; // The last non-zero id + while (id.IsOk() && !done) + { + ExpandDir(id); + + id = FindChild(id, path, done); + if (id.IsOk()) + lastId = id; + } + if (!lastId.IsOk()) + return false; + + wxDirItemData *data = (wxDirItemData *) m_treeCtrl->GetItemData(lastId); + if (data->m_isDir) + { + m_treeCtrl->Expand(lastId); + } + if ((GetWindowStyle() & wxDIRCTRL_SELECT_FIRST) && data->m_isDir) + { + // Find the first file in this directory + wxTreeItemIdValue cookie; + wxTreeItemId childId = m_treeCtrl->GetFirstChild(lastId, cookie); + bool selectedChild = false; + while (childId.IsOk()) + { + data = (wxDirItemData*) m_treeCtrl->GetItemData(childId); + + if (data && data->m_path != wxEmptyString && !data->m_isDir) + { + m_treeCtrl->SelectItem(childId); + m_treeCtrl->EnsureVisible(childId); + selectedChild = true; + break; + } + childId = m_treeCtrl->GetNextChild(lastId, cookie); + } + if (!selectedChild) + { + m_treeCtrl->SelectItem(lastId); + m_treeCtrl->EnsureVisible(lastId); + } + } + else + { + m_treeCtrl->SelectItem(lastId); + m_treeCtrl->EnsureVisible(lastId); + } + + return true; +} + + +bool wxGenericDirCtrl::CollapsePath(const wxString& path) +{ + bool done = false; + wxTreeItemId id = FindChild(m_rootId, path, done); + wxTreeItemId lastId = id; // The last non-zero id + + while ( id.IsOk() && !done ) + { + CollapseDir(id); + + id = FindChild(id, path, done); + + if ( id.IsOk() ) + lastId = id; + } + + if ( !lastId.IsOk() ) + return false; + + m_treeCtrl->SelectItem(lastId); + m_treeCtrl->EnsureVisible(lastId); + + return true; +} + + +wxString wxGenericDirCtrl::GetPath() const +{ + wxTreeItemId id = m_treeCtrl->GetSelection(); + if (id) + { + wxDirItemData* data = (wxDirItemData*) m_treeCtrl->GetItemData(id); + return data->m_path; + } + else + return wxEmptyString; +} + +wxString wxGenericDirCtrl::GetFilePath() const +{ + wxTreeItemId id = m_treeCtrl->GetSelection(); + if (id) + { + wxDirItemData* data = (wxDirItemData*) m_treeCtrl->GetItemData(id); + if (data->m_isDir) + return wxEmptyString; + else + return data->m_path; + } + else + return wxEmptyString; +} + +void wxGenericDirCtrl::SetPath(const wxString& path) +{ + m_defaultPath = path; + if (m_rootId) + ExpandPath(path); +} + +// Not used +#if 0 +void wxGenericDirCtrl::FindChildFiles(wxTreeItemId id, int dirFlags, wxArrayString& filenames) +{ + wxDirItemData *data = (wxDirItemData *) m_treeCtrl->GetItemData(id); + + // This may take a longish time. Go to busy cursor + wxBusyCursor busy; + + wxASSERT(data); + + wxString search,path,filename; + + wxString dirName(data->m_path); + +#if defined(__WXMSW__) || defined(__OS2__) + if (dirName.Last() == ':') + dirName += wxString(wxFILE_SEP_PATH); +#endif + + wxDir d; + wxString eachFilename; + + wxLogNull log; + d.Open(dirName); + + if (d.IsOpened()) + { + if (d.GetFirst(& eachFilename, m_currentFilterStr, dirFlags)) + { + do + { + if ((eachFilename != wxT(".")) && (eachFilename != wxT(".."))) + { + filenames.Add(eachFilename); + } + } + while (d.GetNext(& eachFilename)) ; + } + } +} +#endif + +void wxGenericDirCtrl::SetFilterIndex(int n) +{ + m_currentFilter = n; + + wxString f, d; + if (ExtractWildcard(m_filter, n, f, d)) + m_currentFilterStr = f; + else +#ifdef __UNIX__ + m_currentFilterStr = wxT("*"); +#else + m_currentFilterStr = wxT("*.*"); +#endif +} + +void wxGenericDirCtrl::SetFilter(const wxString& filter) +{ + m_filter = filter; + + wxString f, d; + if (ExtractWildcard(m_filter, m_currentFilter, f, d)) + m_currentFilterStr = f; + else +#ifdef __UNIX__ + m_currentFilterStr = wxT("*"); +#else + m_currentFilterStr = wxT("*.*"); +#endif + + // current filter index is meaningless after filter change, set it to zero + SetFilterIndex(0); + if (m_filterListCtrl) + m_filterListCtrl->FillFilterList(m_filter, 0); +} + +// Extract description and actual filter from overall filter string +bool wxGenericDirCtrl::ExtractWildcard(const wxString& filterStr, int n, wxString& filter, wxString& description) +{ + wxArrayString filters, descriptions; + int count = wxParseCommonDialogsFilter(filterStr, descriptions, filters); + if (count > 0 && n < count) + { + filter = filters[n]; + description = descriptions[n]; + return true; + } + + return false; +} + +#if WXWIN_COMPATIBILITY_2_4 +// Parses the global filter, returning the number of filters. +// Returns 0 if none or if there's a problem. +// filterStr is in the form: "All files (*.*)|*.*|JPEG Files (*.jpeg)|*.jpg" +int wxGenericDirCtrl::ParseFilter(const wxString& filterStr, wxArrayString& filters, wxArrayString& descriptions) +{ + return wxParseCommonDialogsFilter(filterStr, descriptions, filters ); +} +#endif // WXWIN_COMPATIBILITY_2_4 + +void wxGenericDirCtrl::DoResize() +{ + wxSize sz = GetClientSize(); + int verticalSpacing = 3; + if (m_treeCtrl) + { + wxSize filterSz ; + if (m_filterListCtrl) + { + filterSz = m_filterListCtrl->GetSize(); + sz.y -= (filterSz.y + verticalSpacing); + } + m_treeCtrl->SetSize(0, 0, sz.x, sz.y); + if (m_filterListCtrl) + { + m_filterListCtrl->SetSize(0, sz.y + verticalSpacing, sz.x, filterSz.y); + // Don't know why, but this needs refreshing after a resize (wxMSW) + m_filterListCtrl->Refresh(); + } + } +} + + +void wxGenericDirCtrl::OnSize(wxSizeEvent& WXUNUSED(event)) +{ + DoResize(); +} + +wxTreeItemId wxGenericDirCtrl::AppendItem (const wxTreeItemId & parent, + const wxString & text, + int image, int selectedImage, + wxTreeItemData * data) +{ + wxTreeCtrl *treeCtrl = GetTreeCtrl (); + + wxASSERT (treeCtrl); + + if (treeCtrl) + { + return treeCtrl->AppendItem (parent, text, image, selectedImage, data); + } + else + { + return wxTreeItemId(); + } +} + + +//----------------------------------------------------------------------------- +// wxDirFilterListCtrl +//----------------------------------------------------------------------------- + +IMPLEMENT_CLASS(wxDirFilterListCtrl, wxChoice) + +BEGIN_EVENT_TABLE(wxDirFilterListCtrl, wxChoice) + EVT_CHOICE(wxID_ANY, wxDirFilterListCtrl::OnSelFilter) +END_EVENT_TABLE() + +bool wxDirFilterListCtrl::Create(wxGenericDirCtrl* parent, const wxWindowID id, + const wxPoint& pos, + const wxSize& size, + long style) +{ + m_dirCtrl = parent; + return wxChoice::Create(parent, id, pos, size, 0, NULL, style); +} + +void wxDirFilterListCtrl::Init() +{ + m_dirCtrl = NULL; +} + +void wxDirFilterListCtrl::OnSelFilter(wxCommandEvent& WXUNUSED(event)) +{ + int sel = GetSelection(); + + wxString currentPath = m_dirCtrl->GetPath(); + + m_dirCtrl->SetFilterIndex(sel); + + // If the filter has changed, the view is out of date, so + // collapse the tree. + m_dirCtrl->ReCreateTree(); + + // Try to restore the selection, or at least the directory + m_dirCtrl->ExpandPath(currentPath); +} + +void wxDirFilterListCtrl::FillFilterList(const wxString& filter, int defaultFilter) +{ + Clear(); + wxArrayString descriptions, filters; + size_t n = (size_t) wxParseCommonDialogsFilter(filter, descriptions, filters); + + if (n > 0 && defaultFilter < (int) n) + { + for (size_t i = 0; i < n; i++) + Append(descriptions[i]); + SetSelection(defaultFilter); + } +} +#endif // wxUSE_DIRDLG + +#if wxUSE_DIRDLG || wxUSE_FILEDLG + +// ---------------------------------------------------------------------------- +// wxFileIconsTable icons +// ---------------------------------------------------------------------------- + +#ifndef __WXGTK24__ +/* Computer (c) Julian Smart */ +static const char * file_icons_tbl_computer_xpm[] = { +/* columns rows colors chars-per-pixel */ +"16 16 42 1", +"r c #4E7FD0", +"$ c #7198D9", +"; c #DCE6F6", +"q c #FFFFFF", +"u c #4A7CCE", +"# c #779DDB", +"w c #95B2E3", +"y c #7FA2DD", +"f c #3263B4", +"= c #EAF0FA", +"< c #B1C7EB", +"% c #6992D7", +"9 c #D9E4F5", +"o c #9BB7E5", +"6 c #F7F9FD", +", c #BED0EE", +"3 c #F0F5FC", +"1 c #A8C0E8", +" c None", +"0 c #FDFEFF", +"4 c #C4D5F0", +"@ c #81A4DD", +"e c #4377CD", +"- c #E2EAF8", +"i c #9FB9E5", +"> c #CCDAF2", +"+ c #89A9DF", +"s c #5584D1", +"t c #5D89D3", +": c #D2DFF4", +"5 c #FAFCFE", +"2 c #F5F8FD", +"8 c #DFE8F7", +"& c #5E8AD4", +"X c #638ED5", +"a c #CEDCF2", +"p c #90AFE2", +"d c #2F5DA9", +"* c #5282D0", +"7 c #E5EDF9", +". c #A2BCE6", +"O c #8CACE0", +/* pixels */ +" ", +" .XXXXXXXXXXX ", +" oXO++@#$%&*X ", +" oX=-;:>,<1%X ", +" oX23=-;:4,$X ", +" oX5633789:@X ", +" oX05623=78+X ", +" oXqq05623=OX ", +" oX,,,,,<<<$X ", +" wXXXXXXXXXXe ", +" XrtX%$$y@+O,, ", +" uyiiiiiiiii@< ", +" ouiiiiiiiiiipAdd(wxArtProvider::GetBitmap(wxART_FOLDER, + wxART_CMN_DIALOG, + wxSize(16, 16))); + // folder_open + m_smallImageList->Add(wxArtProvider::GetBitmap(wxART_FOLDER_OPEN, + wxART_CMN_DIALOG, + wxSize(16, 16))); + // computer +#ifdef __WXGTK24__ + // GTK24 uses this icon in the file open dialog + m_smallImageList->Add(wxArtProvider::GetBitmap(wxART_HARDDISK, + wxART_CMN_DIALOG, + wxSize(16, 16))); +#else + m_smallImageList->Add(wxIcon(file_icons_tbl_computer_xpm)); +#endif + // drive + m_smallImageList->Add(wxArtProvider::GetBitmap(wxART_HARDDISK, + wxART_CMN_DIALOG, + wxSize(16, 16))); + // cdrom + m_smallImageList->Add(wxArtProvider::GetBitmap(wxART_CDROM, + wxART_CMN_DIALOG, + wxSize(16, 16))); + // floppy + m_smallImageList->Add(wxArtProvider::GetBitmap(wxART_FLOPPY, + wxART_CMN_DIALOG, + wxSize(16, 16))); + // removeable + m_smallImageList->Add(wxArtProvider::GetBitmap(wxART_REMOVABLE, + wxART_CMN_DIALOG, + wxSize(16, 16))); + // file + m_smallImageList->Add(wxArtProvider::GetBitmap(wxART_NORMAL_FILE, + wxART_CMN_DIALOG, + wxSize(16, 16))); + // executable + if (GetIconID(wxEmptyString, _T("application/x-executable")) == file) + { + m_smallImageList->Add(wxArtProvider::GetBitmap(wxART_EXECUTABLE_FILE, + wxART_CMN_DIALOG, + wxSize(16, 16))); + delete m_HashTable->Get(_T("exe")); + m_HashTable->Delete(_T("exe")); + m_HashTable->Put(_T("exe"), new wxFileIconEntry(executable)); + } + /* else put into list by GetIconID + (KDE defines application/x-executable for *.exe and has nice icon) + */ +} + +wxImageList *wxFileIconsTable::GetSmallImageList() +{ + if (!m_smallImageList) + Create(); + + return m_smallImageList; +} + +#if wxUSE_MIMETYPE && wxUSE_IMAGE && (!defined(__WXMSW__) || wxUSE_WXDIB) +// VS: we don't need this function w/o wxMimeTypesManager because we'll only have +// one icon and we won't resize it + +static wxBitmap CreateAntialiasedBitmap(const wxImage& img) +{ + const unsigned int size = 16; + + wxImage smallimg (size, size); + unsigned char *p1, *p2, *ps; + unsigned char mr = img.GetMaskRed(), + mg = img.GetMaskGreen(), + mb = img.GetMaskBlue(); + + unsigned x, y; + unsigned sr, sg, sb, smask; + + p1 = img.GetData(), p2 = img.GetData() + 3 * size*2, ps = smallimg.GetData(); + smallimg.SetMaskColour(mr, mr, mr); + + for (y = 0; y < size; y++) + { + for (x = 0; x < size; x++) + { + sr = sg = sb = smask = 0; + if (p1[0] != mr || p1[1] != mg || p1[2] != mb) + sr += p1[0], sg += p1[1], sb += p1[2]; + else smask++; + p1 += 3; + if (p1[0] != mr || p1[1] != mg || p1[2] != mb) + sr += p1[0], sg += p1[1], sb += p1[2]; + else smask++; + p1 += 3; + if (p2[0] != mr || p2[1] != mg || p2[2] != mb) + sr += p2[0], sg += p2[1], sb += p2[2]; + else smask++; + p2 += 3; + if (p2[0] != mr || p2[1] != mg || p2[2] != mb) + sr += p2[0], sg += p2[1], sb += p2[2]; + else smask++; + p2 += 3; + + if (smask > 2) + ps[0] = ps[1] = ps[2] = mr; + else + { + ps[0] = (unsigned char)(sr >> 2); + ps[1] = (unsigned char)(sg >> 2); + ps[2] = (unsigned char)(sb >> 2); + } + ps += 3; + } + p1 += size*2 * 3, p2 += size*2 * 3; + } + + return wxBitmap(smallimg); +} + +// This function is currently not unused anymore +#if 0 +// finds empty borders and return non-empty area of image: +static wxImage CutEmptyBorders(const wxImage& img) +{ + unsigned char mr = img.GetMaskRed(), + mg = img.GetMaskGreen(), + mb = img.GetMaskBlue(); + unsigned char *dt = img.GetData(), *dttmp; + unsigned w = img.GetWidth(), h = img.GetHeight(); + + unsigned top, bottom, left, right, i; + bool empt; + +#define MK_DTTMP(x,y) dttmp = dt + ((x + y * w) * 3) +#define NOEMPTY_PIX(empt) if (dttmp[0] != mr || dttmp[1] != mg || dttmp[2] != mb) {empt = false; break;} + + for (empt = true, top = 0; empt && top < h; top++) + { + MK_DTTMP(0, top); + for (i = 0; i < w; i++, dttmp+=3) + NOEMPTY_PIX(empt) + } + for (empt = true, bottom = h-1; empt && bottom > top; bottom--) + { + MK_DTTMP(0, bottom); + for (i = 0; i < w; i++, dttmp+=3) + NOEMPTY_PIX(empt) + } + for (empt = true, left = 0; empt && left < w; left++) + { + MK_DTTMP(left, 0); + for (i = 0; i < h; i++, dttmp+=3*w) + NOEMPTY_PIX(empt) + } + for (empt = true, right = w-1; empt && right > left; right--) + { + MK_DTTMP(right, 0); + for (i = 0; i < h; i++, dttmp+=3*w) + NOEMPTY_PIX(empt) + } + top--, left--, bottom++, right++; + + return img.GetSubImage(wxRect(left, top, right - left + 1, bottom - top + 1)); +} +#endif // #if 0 + +#endif // wxUSE_MIMETYPE + +int wxFileIconsTable::GetIconID(const wxString& extension, const wxString& mime) +{ + if (!m_smallImageList) + Create(); + +#if wxUSE_MIMETYPE + if (!extension.empty()) + { + wxFileIconEntry *entry = (wxFileIconEntry*) m_HashTable->Get(extension); + if (entry) return (entry -> id); + } + + wxFileType *ft = (mime.empty()) ? + wxTheMimeTypesManager -> GetFileTypeFromExtension(extension) : + wxTheMimeTypesManager -> GetFileTypeFromMimeType(mime); + + wxIconLocation iconLoc; + wxIcon ic; + + { + wxLogNull logNull; + if ( ft && ft->GetIcon(&iconLoc) ) + { + ic = wxIcon( iconLoc ); + } + } + + delete ft; + + if ( !ic.Ok() ) + { + int newid = file; + m_HashTable->Put(extension, new wxFileIconEntry(newid)); + return newid; + } + + wxBitmap bmp; + bmp.CopyFromIcon(ic); + + if ( !bmp.Ok() ) + { + int newid = file; + m_HashTable->Put(extension, new wxFileIconEntry(newid)); + return newid; + } + + const unsigned int size = 16; + + int id = m_smallImageList->GetImageCount(); + if ((bmp.GetWidth() == (int) size) && (bmp.GetHeight() == (int) size)) + { + m_smallImageList->Add(bmp); + } +#if wxUSE_IMAGE && (!defined(__WXMSW__) || wxUSE_WXDIB) + else + { + wxImage img = bmp.ConvertToImage(); + + if ((img.GetWidth() != size*2) || (img.GetHeight() != size*2)) +// m_smallImageList->Add(CreateAntialiasedBitmap(CutEmptyBorders(img).Rescale(size*2, size*2))); + m_smallImageList->Add(CreateAntialiasedBitmap(img.Rescale(size*2, size*2))); + else + m_smallImageList->Add(CreateAntialiasedBitmap(img)); + } +#endif // wxUSE_IMAGE + + m_HashTable->Put(extension, new wxFileIconEntry(id)); + return id; + +#else // !wxUSE_MIMETYPE + + wxUnusedVar(mime); + if (extension == wxT("exe")) + return executable; + else + return file; +#endif // wxUSE_MIMETYPE/!wxUSE_MIMETYPE +} + +#endif // wxUSE_DIRDLG || wxUSE_FILEDLG diff --git a/Externals/wxWidgets/src/generic/dirdlgg.cpp b/Externals/wxWidgets/src/generic/dirdlgg.cpp index 103f341e4c..49fb67f9ca 100644 --- a/Externals/wxWidgets/src/generic/dirdlgg.cpp +++ b/Externals/wxWidgets/src/generic/dirdlgg.cpp @@ -1,369 +1,369 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/generic/dirdlg.cpp -// Purpose: wxDirDialog -// Author: Harm van der Heijden, Robert Roebling & Julian Smart -// Modified by: -// Created: 12/12/98 -// RCS-ID: $Id: dirdlgg.cpp 41838 2006-10-09 21:08:45Z VZ $ -// Copyright: (c) Harm van der Heijden, Robert Roebling, Julian Smart -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_DIRDLG - -#ifndef WX_PRECOMP - #include "wx/textctrl.h" - #include "wx/button.h" - #include "wx/checkbox.h" - #include "wx/sizer.h" - #include "wx/intl.h" - #include "wx/log.h" - #include "wx/msgdlg.h" - #include "wx/bmpbuttn.h" -#endif - -#include "wx/statline.h" -#include "wx/dirctrl.h" -#include "wx/generic/dirdlgg.h" -#include "wx/artprov.h" - -// ---------------------------------------------------------------------------- -// constants -// ---------------------------------------------------------------------------- - -static const int ID_DIRCTRL = 1000; -static const int ID_TEXTCTRL = 1001; -static const int ID_NEW = 1004; -static const int ID_SHOW_HIDDEN = 1005; -static const int ID_GO_HOME = 1006; - -//----------------------------------------------------------------------------- -// wxGenericDirDialog -//----------------------------------------------------------------------------- - -IMPLEMENT_DYNAMIC_CLASS(wxGenericDirDialog, wxDialog) - -BEGIN_EVENT_TABLE(wxGenericDirDialog, wxDialog) - EVT_CLOSE (wxGenericDirDialog::OnCloseWindow) - EVT_BUTTON (wxID_OK, wxGenericDirDialog::OnOK) - EVT_BUTTON (ID_NEW, wxGenericDirDialog::OnNew) - EVT_BUTTON (ID_GO_HOME, wxGenericDirDialog::OnGoHome) - EVT_TREE_KEY_DOWN (wxID_ANY, wxGenericDirDialog::OnTreeKeyDown) - EVT_TREE_SEL_CHANGED (wxID_ANY, wxGenericDirDialog::OnTreeSelected) - EVT_TEXT_ENTER (ID_TEXTCTRL, wxGenericDirDialog::OnOK) - EVT_CHECKBOX (ID_SHOW_HIDDEN, wxGenericDirDialog::OnShowHidden) -END_EVENT_TABLE() - -wxGenericDirDialog::wxGenericDirDialog(wxWindow* parent, const wxString& title, - const wxString& defaultPath, long style, - const wxPoint& pos, const wxSize& sz, - const wxString& name) -{ - Create(parent, title, defaultPath, style, pos, sz, name); -} - -bool wxGenericDirDialog::Create(wxWindow* parent, - const wxString& title, - const wxString& defaultPath, long style, - const wxPoint& pos, - const wxSize& sz, - const wxString& name) -{ - wxBusyCursor cursor; - - if (!wxDirDialogBase::Create(parent, title, defaultPath, style, pos, sz, name)) - return false; - - m_path = defaultPath; - if (m_path == wxT("~")) - wxGetHomeDir(&m_path); - if (m_path == wxT(".")) - m_path = wxGetCwd(); - - wxBoxSizer *topsizer = new wxBoxSizer( wxVERTICAL ); - - // smartphones does not support or do not waste space for wxButtons -#if defined(__SMARTPHONE__) - - wxMenu *dirMenu = new wxMenu; - dirMenu->Append(ID_GO_HOME, _("Home")); - - if (!HasFlag(wxDD_DIR_MUST_EXIST)) - { - dirMenu->Append(ID_NEW, _("New directory")); - } - - dirMenu->AppendCheckItem(ID_SHOW_HIDDEN, _("Show hidden directories")); - dirMenu->AppendSeparator(); - dirMenu->Append(wxID_CANCEL, _("Cancel")); - -#else - - // 0) 'New' and 'Home' Buttons - wxSizer* buttonsizer = new wxBoxSizer( wxHORIZONTAL ); - - // VS: 'Home directory' concept is unknown to MS-DOS -#if !defined(__DOS__) - wxBitmapButton* homeButton = - new wxBitmapButton(this, ID_GO_HOME, - wxArtProvider::GetBitmap(wxART_GO_HOME, wxART_BUTTON)); - buttonsizer->Add( homeButton, 0, wxLEFT|wxRIGHT, 10 ); -#endif - - // I'm not convinced we need a New button, and we tend to get annoying - // accidental-editing with label editing enabled. - if (!HasFlag(wxDD_DIR_MUST_EXIST)) - { - wxBitmapButton* newButton = - new wxBitmapButton(this, ID_NEW, - wxArtProvider::GetBitmap(wxART_NEW_DIR, wxART_BUTTON)); - buttonsizer->Add( newButton, 0, wxRIGHT, 10 ); -#if wxUSE_TOOLTIPS - newButton->SetToolTip(_("Create new directory")); -#endif - } - -#if wxUSE_TOOLTIPS - homeButton->SetToolTip(_("Go to home directory")); -#endif - - topsizer->Add( buttonsizer, 0, wxTOP | wxALIGN_RIGHT, 10 ); - -#endif // __SMARTPHONE__/!__SMARTPHONE__ - - // 1) dir ctrl - m_dirCtrl = NULL; // this is necessary, event handler called from - // wxGenericDirCtrl would crash otherwise! - long dirStyle = wxDIRCTRL_DIR_ONLY | wxDEFAULT_CONTROL_BORDER; - -#ifdef __WXMSW__ - if (!HasFlag(wxDD_DIR_MUST_EXIST)) - { - // Only under Windows do we need the wxTR_EDIT_LABEL tree control style - // before we can call EditLabel (required for "New directory") - dirStyle |= wxDIRCTRL_EDIT_LABELS; - } -#endif - - m_dirCtrl = new wxGenericDirCtrl(this, ID_DIRCTRL, - m_path, wxDefaultPosition, - wxSize(300, 200), - dirStyle); - - wxSizerFlags flagsBorder2; - flagsBorder2.DoubleBorder(wxTOP | wxLEFT | wxRIGHT); - - topsizer->Add(m_dirCtrl, wxSizerFlags(flagsBorder2).Proportion(1).Expand()); - -#ifndef __SMARTPHONE__ - // Make the an option depending on a flag? - wxCheckBox * - check = new wxCheckBox(this, ID_SHOW_HIDDEN, _("Show &hidden directories")); - topsizer->Add(check, wxSizerFlags(flagsBorder2).Right()); -#endif // !__SMARTPHONE__ - - // 2) text ctrl - m_input = new wxTextCtrl( this, ID_TEXTCTRL, m_path, wxDefaultPosition ); - topsizer->Add(m_input, wxSizerFlags(flagsBorder2).Expand()); - - // 3) buttons if any - wxSizer *buttonSizer = CreateSeparatedButtonSizer(wxOK | wxCANCEL); - if ( buttonSizer ) - { - topsizer->Add(buttonSizer, wxSizerFlags().Expand().DoubleBorder()); - } - -#ifdef __SMARTPHONE__ - // overwrite menu set by CreateSeparatedButtonSizer() call above - SetRightMenu(wxID_ANY, _("Options"), dirMenu); -#endif - - m_input->SetFocus(); - - SetAutoLayout( true ); - SetSizer( topsizer ); - - topsizer->SetSizeHints( this ); - topsizer->Fit( this ); - - Centre( wxBOTH ); - - return true; -} - -void wxGenericDirDialog::EndModal(int retCode) -{ - // before proceeding, change the current working directory if user asked so - if (retCode == wxID_OK && HasFlag(wxDD_CHANGE_DIR)) - wxSetWorkingDirectory(m_path); - - wxDialog::EndModal(retCode); -} - -void wxGenericDirDialog::OnCloseWindow(wxCloseEvent& WXUNUSED(event)) -{ - EndModal(wxID_CANCEL); -} - -void wxGenericDirDialog::OnOK(wxCommandEvent& WXUNUSED(event)) -{ - m_path = m_input->GetValue(); - - // Does the path exist? (User may have typed anything in m_input) - if (wxDirExists(m_path)) - { - // OK, path exists, we're done. - EndModal(wxID_OK); - return; - } - - // Interact with user, find out if the dir is a typo or to be created - wxString msg; - msg.Printf(_("The directory '%s' does not exist\nCreate it now?"), - m_path.c_str()); - wxMessageDialog dialog(this, msg, _("Directory does not exist"), - wxYES_NO | wxICON_WARNING); - - if ( dialog.ShowModal() == wxID_YES ) - { - // Okay, let's make it - wxLogNull log; - if (wxMkdir(m_path)) - { - // The new dir was created okay. - EndModal(wxID_OK); - return; - } - else - { - // Trouble... - msg.Printf(_("Failed to create directory '%s'\n(Do you have the required permissions?)"), - m_path.c_str()); - wxMessageDialog errmsg(this, msg, _("Error creating directory"), wxOK | wxICON_ERROR); - errmsg.ShowModal(); - // We still don't have a valid dir. Back to the main dialog. - } - } - // User has answered NO to create dir. -} - -void wxGenericDirDialog::SetPath(const wxString& path) -{ - m_dirCtrl->SetPath(path); - m_path = path; -} - -wxString wxGenericDirDialog::GetPath(void) const -{ - return m_path; -} - -int wxGenericDirDialog::ShowModal() -{ - m_input->SetValue( m_path ); - return wxDialog::ShowModal(); -} - -void wxGenericDirDialog::OnTreeSelected( wxTreeEvent &event ) -{ - if (!m_dirCtrl) - return; - - wxTreeItemId item = event.GetItem(); - - wxDirItemData *data = NULL; - - if(item.IsOk()) - data = (wxDirItemData*)m_dirCtrl->GetTreeCtrl()->GetItemData(item); - - if (data) - m_input->SetValue( data->m_path ); -} - -void wxGenericDirDialog::OnTreeKeyDown( wxTreeEvent &WXUNUSED(event) ) -{ - if (!m_dirCtrl) - return; - - wxDirItemData *data = (wxDirItemData*)m_dirCtrl->GetTreeCtrl()->GetItemData(m_dirCtrl->GetTreeCtrl()->GetSelection()); - if (data) - m_input->SetValue( data->m_path ); -} - -void wxGenericDirDialog::OnShowHidden( wxCommandEvent& event ) -{ - if (!m_dirCtrl) - return; - - m_dirCtrl->ShowHidden( event.GetInt() != 0 ); -} - -void wxGenericDirDialog::OnNew( wxCommandEvent& WXUNUSED(event) ) -{ - wxTreeItemId id = m_dirCtrl->GetTreeCtrl()->GetSelection(); - if ((id == m_dirCtrl->GetTreeCtrl()->GetRootItem()) || - (m_dirCtrl->GetTreeCtrl()->GetItemParent(id) == m_dirCtrl->GetTreeCtrl()->GetRootItem())) - { - wxMessageDialog msg(this, _("You cannot add a new directory to this section."), - _("Create directory"), wxOK | wxICON_INFORMATION ); - msg.ShowModal(); - return; - } - - wxTreeItemId parent = id ; // m_dirCtrl->GetTreeCtrl()->GetItemParent( id ); - wxDirItemData *data = (wxDirItemData*)m_dirCtrl->GetTreeCtrl()->GetItemData( parent ); - wxASSERT( data ); - - wxString new_name( _("NewName") ); - wxString path( data->m_path ); - if (!wxEndsWithPathSeparator(path)) - path += wxFILE_SEP_PATH; - path += new_name; - if (wxDirExists(path)) - { - // try NewName0, NewName1 etc. - int i = 0; - do { - new_name = _("NewName"); - wxString num; - num.Printf( wxT("%d"), i ); - new_name += num; - - path = data->m_path; - if (!wxEndsWithPathSeparator(path)) - path += wxFILE_SEP_PATH; - path += new_name; - i++; - } while (wxDirExists(path)); - } - - wxLogNull log; - if (!wxMkdir(path)) - { - wxMessageDialog dialog(this, _("Operation not permitted."), _("Error"), wxOK | wxICON_ERROR ); - dialog.ShowModal(); - return; - } - - wxDirItemData *new_data = new wxDirItemData( path, new_name, true ); - - // TODO: THIS CODE DOESN'T WORK YET. We need to avoid duplication of the first child - // of the parent. - wxTreeItemId new_id = m_dirCtrl->GetTreeCtrl()->AppendItem( parent, new_name, 0, 0, new_data ); - m_dirCtrl->GetTreeCtrl()->EnsureVisible( new_id ); - m_dirCtrl->GetTreeCtrl()->EditLabel( new_id ); -} - -void wxGenericDirDialog::OnGoHome(wxCommandEvent& WXUNUSED(event)) -{ - SetPath(wxGetUserHome()); -} - -#endif // wxUSE_DIRDLG +///////////////////////////////////////////////////////////////////////////// +// Name: src/generic/dirdlg.cpp +// Purpose: wxDirDialog +// Author: Harm van der Heijden, Robert Roebling & Julian Smart +// Modified by: +// Created: 12/12/98 +// RCS-ID: $Id: dirdlgg.cpp 41838 2006-10-09 21:08:45Z VZ $ +// Copyright: (c) Harm van der Heijden, Robert Roebling, Julian Smart +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_DIRDLG + +#ifndef WX_PRECOMP + #include "wx/textctrl.h" + #include "wx/button.h" + #include "wx/checkbox.h" + #include "wx/sizer.h" + #include "wx/intl.h" + #include "wx/log.h" + #include "wx/msgdlg.h" + #include "wx/bmpbuttn.h" +#endif + +#include "wx/statline.h" +#include "wx/dirctrl.h" +#include "wx/generic/dirdlgg.h" +#include "wx/artprov.h" + +// ---------------------------------------------------------------------------- +// constants +// ---------------------------------------------------------------------------- + +static const int ID_DIRCTRL = 1000; +static const int ID_TEXTCTRL = 1001; +static const int ID_NEW = 1004; +static const int ID_SHOW_HIDDEN = 1005; +static const int ID_GO_HOME = 1006; + +//----------------------------------------------------------------------------- +// wxGenericDirDialog +//----------------------------------------------------------------------------- + +IMPLEMENT_DYNAMIC_CLASS(wxGenericDirDialog, wxDialog) + +BEGIN_EVENT_TABLE(wxGenericDirDialog, wxDialog) + EVT_CLOSE (wxGenericDirDialog::OnCloseWindow) + EVT_BUTTON (wxID_OK, wxGenericDirDialog::OnOK) + EVT_BUTTON (ID_NEW, wxGenericDirDialog::OnNew) + EVT_BUTTON (ID_GO_HOME, wxGenericDirDialog::OnGoHome) + EVT_TREE_KEY_DOWN (wxID_ANY, wxGenericDirDialog::OnTreeKeyDown) + EVT_TREE_SEL_CHANGED (wxID_ANY, wxGenericDirDialog::OnTreeSelected) + EVT_TEXT_ENTER (ID_TEXTCTRL, wxGenericDirDialog::OnOK) + EVT_CHECKBOX (ID_SHOW_HIDDEN, wxGenericDirDialog::OnShowHidden) +END_EVENT_TABLE() + +wxGenericDirDialog::wxGenericDirDialog(wxWindow* parent, const wxString& title, + const wxString& defaultPath, long style, + const wxPoint& pos, const wxSize& sz, + const wxString& name) +{ + Create(parent, title, defaultPath, style, pos, sz, name); +} + +bool wxGenericDirDialog::Create(wxWindow* parent, + const wxString& title, + const wxString& defaultPath, long style, + const wxPoint& pos, + const wxSize& sz, + const wxString& name) +{ + wxBusyCursor cursor; + + if (!wxDirDialogBase::Create(parent, title, defaultPath, style, pos, sz, name)) + return false; + + m_path = defaultPath; + if (m_path == wxT("~")) + wxGetHomeDir(&m_path); + if (m_path == wxT(".")) + m_path = wxGetCwd(); + + wxBoxSizer *topsizer = new wxBoxSizer( wxVERTICAL ); + + // smartphones does not support or do not waste space for wxButtons +#if defined(__SMARTPHONE__) + + wxMenu *dirMenu = new wxMenu; + dirMenu->Append(ID_GO_HOME, _("Home")); + + if (!HasFlag(wxDD_DIR_MUST_EXIST)) + { + dirMenu->Append(ID_NEW, _("New directory")); + } + + dirMenu->AppendCheckItem(ID_SHOW_HIDDEN, _("Show hidden directories")); + dirMenu->AppendSeparator(); + dirMenu->Append(wxID_CANCEL, _("Cancel")); + +#else + + // 0) 'New' and 'Home' Buttons + wxSizer* buttonsizer = new wxBoxSizer( wxHORIZONTAL ); + + // VS: 'Home directory' concept is unknown to MS-DOS +#if !defined(__DOS__) + wxBitmapButton* homeButton = + new wxBitmapButton(this, ID_GO_HOME, + wxArtProvider::GetBitmap(wxART_GO_HOME, wxART_BUTTON)); + buttonsizer->Add( homeButton, 0, wxLEFT|wxRIGHT, 10 ); +#endif + + // I'm not convinced we need a New button, and we tend to get annoying + // accidental-editing with label editing enabled. + if (!HasFlag(wxDD_DIR_MUST_EXIST)) + { + wxBitmapButton* newButton = + new wxBitmapButton(this, ID_NEW, + wxArtProvider::GetBitmap(wxART_NEW_DIR, wxART_BUTTON)); + buttonsizer->Add( newButton, 0, wxRIGHT, 10 ); +#if wxUSE_TOOLTIPS + newButton->SetToolTip(_("Create new directory")); +#endif + } + +#if wxUSE_TOOLTIPS + homeButton->SetToolTip(_("Go to home directory")); +#endif + + topsizer->Add( buttonsizer, 0, wxTOP | wxALIGN_RIGHT, 10 ); + +#endif // __SMARTPHONE__/!__SMARTPHONE__ + + // 1) dir ctrl + m_dirCtrl = NULL; // this is necessary, event handler called from + // wxGenericDirCtrl would crash otherwise! + long dirStyle = wxDIRCTRL_DIR_ONLY | wxDEFAULT_CONTROL_BORDER; + +#ifdef __WXMSW__ + if (!HasFlag(wxDD_DIR_MUST_EXIST)) + { + // Only under Windows do we need the wxTR_EDIT_LABEL tree control style + // before we can call EditLabel (required for "New directory") + dirStyle |= wxDIRCTRL_EDIT_LABELS; + } +#endif + + m_dirCtrl = new wxGenericDirCtrl(this, ID_DIRCTRL, + m_path, wxDefaultPosition, + wxSize(300, 200), + dirStyle); + + wxSizerFlags flagsBorder2; + flagsBorder2.DoubleBorder(wxTOP | wxLEFT | wxRIGHT); + + topsizer->Add(m_dirCtrl, wxSizerFlags(flagsBorder2).Proportion(1).Expand()); + +#ifndef __SMARTPHONE__ + // Make the an option depending on a flag? + wxCheckBox * + check = new wxCheckBox(this, ID_SHOW_HIDDEN, _("Show &hidden directories")); + topsizer->Add(check, wxSizerFlags(flagsBorder2).Right()); +#endif // !__SMARTPHONE__ + + // 2) text ctrl + m_input = new wxTextCtrl( this, ID_TEXTCTRL, m_path, wxDefaultPosition ); + topsizer->Add(m_input, wxSizerFlags(flagsBorder2).Expand()); + + // 3) buttons if any + wxSizer *buttonSizer = CreateSeparatedButtonSizer(wxOK | wxCANCEL); + if ( buttonSizer ) + { + topsizer->Add(buttonSizer, wxSizerFlags().Expand().DoubleBorder()); + } + +#ifdef __SMARTPHONE__ + // overwrite menu set by CreateSeparatedButtonSizer() call above + SetRightMenu(wxID_ANY, _("Options"), dirMenu); +#endif + + m_input->SetFocus(); + + SetAutoLayout( true ); + SetSizer( topsizer ); + + topsizer->SetSizeHints( this ); + topsizer->Fit( this ); + + Centre( wxBOTH ); + + return true; +} + +void wxGenericDirDialog::EndModal(int retCode) +{ + // before proceeding, change the current working directory if user asked so + if (retCode == wxID_OK && HasFlag(wxDD_CHANGE_DIR)) + wxSetWorkingDirectory(m_path); + + wxDialog::EndModal(retCode); +} + +void wxGenericDirDialog::OnCloseWindow(wxCloseEvent& WXUNUSED(event)) +{ + EndModal(wxID_CANCEL); +} + +void wxGenericDirDialog::OnOK(wxCommandEvent& WXUNUSED(event)) +{ + m_path = m_input->GetValue(); + + // Does the path exist? (User may have typed anything in m_input) + if (wxDirExists(m_path)) + { + // OK, path exists, we're done. + EndModal(wxID_OK); + return; + } + + // Interact with user, find out if the dir is a typo or to be created + wxString msg; + msg.Printf(_("The directory '%s' does not exist\nCreate it now?"), + m_path.c_str()); + wxMessageDialog dialog(this, msg, _("Directory does not exist"), + wxYES_NO | wxICON_WARNING); + + if ( dialog.ShowModal() == wxID_YES ) + { + // Okay, let's make it + wxLogNull log; + if (wxMkdir(m_path)) + { + // The new dir was created okay. + EndModal(wxID_OK); + return; + } + else + { + // Trouble... + msg.Printf(_("Failed to create directory '%s'\n(Do you have the required permissions?)"), + m_path.c_str()); + wxMessageDialog errmsg(this, msg, _("Error creating directory"), wxOK | wxICON_ERROR); + errmsg.ShowModal(); + // We still don't have a valid dir. Back to the main dialog. + } + } + // User has answered NO to create dir. +} + +void wxGenericDirDialog::SetPath(const wxString& path) +{ + m_dirCtrl->SetPath(path); + m_path = path; +} + +wxString wxGenericDirDialog::GetPath(void) const +{ + return m_path; +} + +int wxGenericDirDialog::ShowModal() +{ + m_input->SetValue( m_path ); + return wxDialog::ShowModal(); +} + +void wxGenericDirDialog::OnTreeSelected( wxTreeEvent &event ) +{ + if (!m_dirCtrl) + return; + + wxTreeItemId item = event.GetItem(); + + wxDirItemData *data = NULL; + + if(item.IsOk()) + data = (wxDirItemData*)m_dirCtrl->GetTreeCtrl()->GetItemData(item); + + if (data) + m_input->SetValue( data->m_path ); +} + +void wxGenericDirDialog::OnTreeKeyDown( wxTreeEvent &WXUNUSED(event) ) +{ + if (!m_dirCtrl) + return; + + wxDirItemData *data = (wxDirItemData*)m_dirCtrl->GetTreeCtrl()->GetItemData(m_dirCtrl->GetTreeCtrl()->GetSelection()); + if (data) + m_input->SetValue( data->m_path ); +} + +void wxGenericDirDialog::OnShowHidden( wxCommandEvent& event ) +{ + if (!m_dirCtrl) + return; + + m_dirCtrl->ShowHidden( event.GetInt() != 0 ); +} + +void wxGenericDirDialog::OnNew( wxCommandEvent& WXUNUSED(event) ) +{ + wxTreeItemId id = m_dirCtrl->GetTreeCtrl()->GetSelection(); + if ((id == m_dirCtrl->GetTreeCtrl()->GetRootItem()) || + (m_dirCtrl->GetTreeCtrl()->GetItemParent(id) == m_dirCtrl->GetTreeCtrl()->GetRootItem())) + { + wxMessageDialog msg(this, _("You cannot add a new directory to this section."), + _("Create directory"), wxOK | wxICON_INFORMATION ); + msg.ShowModal(); + return; + } + + wxTreeItemId parent = id ; // m_dirCtrl->GetTreeCtrl()->GetItemParent( id ); + wxDirItemData *data = (wxDirItemData*)m_dirCtrl->GetTreeCtrl()->GetItemData( parent ); + wxASSERT( data ); + + wxString new_name( _("NewName") ); + wxString path( data->m_path ); + if (!wxEndsWithPathSeparator(path)) + path += wxFILE_SEP_PATH; + path += new_name; + if (wxDirExists(path)) + { + // try NewName0, NewName1 etc. + int i = 0; + do { + new_name = _("NewName"); + wxString num; + num.Printf( wxT("%d"), i ); + new_name += num; + + path = data->m_path; + if (!wxEndsWithPathSeparator(path)) + path += wxFILE_SEP_PATH; + path += new_name; + i++; + } while (wxDirExists(path)); + } + + wxLogNull log; + if (!wxMkdir(path)) + { + wxMessageDialog dialog(this, _("Operation not permitted."), _("Error"), wxOK | wxICON_ERROR ); + dialog.ShowModal(); + return; + } + + wxDirItemData *new_data = new wxDirItemData( path, new_name, true ); + + // TODO: THIS CODE DOESN'T WORK YET. We need to avoid duplication of the first child + // of the parent. + wxTreeItemId new_id = m_dirCtrl->GetTreeCtrl()->AppendItem( parent, new_name, 0, 0, new_data ); + m_dirCtrl->GetTreeCtrl()->EnsureVisible( new_id ); + m_dirCtrl->GetTreeCtrl()->EditLabel( new_id ); +} + +void wxGenericDirDialog::OnGoHome(wxCommandEvent& WXUNUSED(event)) +{ + SetPath(wxGetUserHome()); +} + +#endif // wxUSE_DIRDLG diff --git a/Externals/wxWidgets/src/generic/dragimgg.cpp b/Externals/wxWidgets/src/generic/dragimgg.cpp index d3c8ac474a..b915c1bd2f 100644 --- a/Externals/wxWidgets/src/generic/dragimgg.cpp +++ b/Externals/wxWidgets/src/generic/dragimgg.cpp @@ -1,574 +1,574 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/generic/dragimgg.cpp -// Purpose: Generic wxDragImage implementation -// Author: Julian Smart -// Modified by: -// Created: 29/2/2000 -// RCS-ID: $Id: dragimgg.cpp 42397 2006-10-25 12:12:56Z VS $ -// Copyright: (c) Julian Smart -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_DRAGIMAGE - -#ifndef WX_PRECOMP - #include - #include "wx/window.h" - #include "wx/frame.h" - #include "wx/dcclient.h" - #include "wx/dcscreen.h" - #include "wx/dcmemory.h" - #include "wx/settings.h" - #include "wx/intl.h" - #include "wx/log.h" - #include "wx/image.h" -#endif - -#define wxUSE_IMAGE_IN_DRAGIMAGE 1 - -#include "wx/generic/dragimgg.h" - -// ---------------------------------------------------------------------------- -// macros -// ---------------------------------------------------------------------------- - -IMPLEMENT_DYNAMIC_CLASS(wxGenericDragImage, wxObject) - -// ============================================================================ -// implementation -// ============================================================================ - -// ---------------------------------------------------------------------------- -// wxGenericDragImage ctors/dtor -// ---------------------------------------------------------------------------- - -wxGenericDragImage::~wxGenericDragImage() -{ - if (m_windowDC) - { - delete m_windowDC; - } -} - -void wxGenericDragImage::Init() -{ - m_isDirty = false; - m_isShown = false; - m_windowDC = (wxDC*) NULL; - m_window = (wxWindow*) NULL; - m_fullScreen = false; -#ifdef wxHAS_NATIVE_OVERLAY - m_dcOverlay = NULL; -#else - m_pBackingBitmap = (wxBitmap*) NULL; -#endif -} - -#if WXWIN_COMPATIBILITY_2_6 -wxGenericDragImage::wxGenericDragImage(const wxCursor& cursor, const wxPoint& WXUNUSED(cursorHotspot)) -{ - Init(); - Create(cursor); -} - -wxGenericDragImage::wxGenericDragImage(const wxBitmap& image, const wxCursor& cursor, const wxPoint& WXUNUSED(cursorHotspot)) -{ - Init(); - - Create(image, cursor); -} - -wxGenericDragImage::wxGenericDragImage(const wxIcon& image, const wxCursor& cursor, const wxPoint& WXUNUSED(cursorHotspot)) -{ - Init(); - - Create(image, cursor); -} - -wxGenericDragImage::wxGenericDragImage(const wxString& str, const wxCursor& cursor, const wxPoint& WXUNUSED(cursorHotspot)) -{ - Init(); - - Create(str, cursor); -} - -bool wxGenericDragImage::Create(const wxCursor& cursor, const wxPoint& WXUNUSED(cursorHotspot)) -{ - return Create(cursor); -} - -bool wxGenericDragImage::Create(const wxBitmap& image, const wxCursor& cursor, const wxPoint& WXUNUSED(cursorHotspot)) -{ - return Create(image, cursor); -} - -bool wxGenericDragImage::Create(const wxIcon& image, const wxCursor& cursor, const wxPoint& WXUNUSED(cursorHotspot)) -{ - return Create(image, cursor); -} - -bool wxGenericDragImage::Create(const wxString& str, const wxCursor& cursor, const wxPoint& WXUNUSED(cursorHotspot)) -{ - return Create(str, cursor); -} -#endif // WXWIN_COMPATIBILITY_2_6 - -// Attributes -//////////////////////////////////////////////////////////////////////////// - - -// Operations -//////////////////////////////////////////////////////////////////////////// - -// Create a drag image with a virtual image (need to override DoDrawImage, GetImageRect) -bool wxGenericDragImage::Create(const wxCursor& cursor) -{ - m_cursor = cursor; - - return true; -} - -// Create a drag image from a bitmap and optional cursor -bool wxGenericDragImage::Create(const wxBitmap& image, const wxCursor& cursor) -{ - // We don't have to combine the cursor explicitly since we simply show the cursor - // as we drag. This currently will only work within one window. - - m_cursor = cursor; - m_bitmap = image; - - return true ; -} - -// Create a drag image from an icon and optional cursor -bool wxGenericDragImage::Create(const wxIcon& image, const wxCursor& cursor) -{ - // We don't have to combine the cursor explicitly since we simply show the cursor - // as we drag. This currently will only work within one window. - - m_cursor = cursor; - m_icon = image; - - return true ; -} - -// Create a drag image from a string and optional cursor -bool wxGenericDragImage::Create(const wxString& str, const wxCursor& cursor) -{ - wxFont font(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT)); - - long w = 0, h = 0; - wxScreenDC dc; - dc.SetFont(font); - dc.GetTextExtent(str, & w, & h); - dc.SetFont(wxNullFont); - - wxMemoryDC dc2; - - // Sometimes GetTextExtent isn't accurate enough, so make it longer - wxBitmap bitmap((int) ((w+2) * 1.5), (int) h+2); - dc2.SelectObject(bitmap); - - dc2.SetFont(font); - dc2.SetBackground(* wxWHITE_BRUSH); - dc2.Clear(); - dc2.SetBackgroundMode(wxTRANSPARENT); - dc2.SetTextForeground(* wxLIGHT_GREY); - dc2.DrawText(str, 0, 0); - dc2.DrawText(str, 1, 0); - dc2.DrawText(str, 2, 0); - dc2.DrawText(str, 1, 1); - dc2.DrawText(str, 2, 1); - dc2.DrawText(str, 1, 2); - dc2.DrawText(str, 2, 2); - - dc2.SetTextForeground(* wxBLACK); - dc2.DrawText(str, 1, 1); - - dc2.SelectObject(wxNullBitmap); - -#if wxUSE_IMAGE_IN_DRAGIMAGE && (!defined(__WXMSW__) || wxUSE_WXDIB) - // Make the bitmap masked - wxImage image = bitmap.ConvertToImage(); - image.SetMaskColour(255, 255, 255); - bitmap = wxBitmap(image); -#endif - - return Create(bitmap, cursor); -} - -#if wxUSE_TREECTRL -// Create a drag image for the given tree control item -bool wxGenericDragImage::Create(const wxTreeCtrl& treeCtrl, wxTreeItemId& id) -{ - wxString str = treeCtrl.GetItemText(id); - return Create(str); -} -#endif - -#if wxUSE_LISTCTRL -// Create a drag image for the given list control item -bool wxGenericDragImage::Create(const wxListCtrl& listCtrl, long id) -{ - wxString str = listCtrl.GetItemText(id); - return Create(str); -} -#endif - -// Begin drag -bool wxGenericDragImage::BeginDrag(const wxPoint& hotspot, - wxWindow* window, - bool fullScreen, - wxRect* rect) -{ - wxASSERT_MSG( (window != 0), wxT("Window must not be null in BeginDrag.")); - - // The image should be offset by this amount - m_offset = hotspot; - m_window = window; - m_fullScreen = fullScreen; - - if (rect) - m_boundingRect = * rect; - - m_isDirty = false; - m_isDirty = false; - - if (window) - { - window->CaptureMouse(); - - if (m_cursor.Ok()) - { - m_oldCursor = window->GetCursor(); - window->SetCursor(m_cursor); - } - } - - // Make a copy of the window so we can repair damage done as the image is - // dragged. - - wxSize clientSize; - wxPoint pt; - if (!m_fullScreen) - { - clientSize = window->GetClientSize(); - m_boundingRect.x = 0; m_boundingRect.y = 0; - m_boundingRect.width = clientSize.x; m_boundingRect.height = clientSize.y; - } - else - { - int w, h; - wxDisplaySize(& w, & h); - clientSize.x = w; clientSize.y = h; - if (rect) - { - pt.x = m_boundingRect.x; pt.y = m_boundingRect.y; - clientSize.x = m_boundingRect.width; clientSize.y = m_boundingRect.height; - } - else - { - m_boundingRect.x = 0; m_boundingRect.y = 0; - m_boundingRect.width = w; m_boundingRect.height = h; - } - } - -#ifndef wxHAS_NATIVE_OVERLAY - wxBitmap* backing = (m_pBackingBitmap ? m_pBackingBitmap : (wxBitmap*) & m_backingBitmap); - - if (!backing->Ok() || (backing->GetWidth() < clientSize.x || backing->GetHeight() < clientSize.y)) - (*backing) = wxBitmap(clientSize.x, clientSize.y); -#endif // !wxHAS_NATIVE_OVERLAY - - if (!m_fullScreen) - { - m_windowDC = new wxClientDC(window); - } - else - { - m_windowDC = new wxScreenDC; - -#if 0 - // Use m_boundingRect to limit the area considered. - ((wxScreenDC*) m_windowDC)->StartDrawingOnTop(rect); -#endif - - m_windowDC->SetClippingRegion(m_boundingRect.x, m_boundingRect.y, - m_boundingRect.width, m_boundingRect.height); - } - - return true; -} - -// Begin drag. hotspot is the location of the drag position relative to the upper-left -// corner of the image. This is full screen only. fullScreenRect gives the -// position of the window on the screen, to restrict the drag to. -bool wxGenericDragImage::BeginDrag(const wxPoint& hotspot, wxWindow* window, wxWindow* fullScreenRect) -{ - wxRect rect; - - int x = fullScreenRect->GetPosition().x; - int y = fullScreenRect->GetPosition().y; - - wxSize sz = fullScreenRect->GetSize(); - - if (fullScreenRect->GetParent() && !fullScreenRect->IsKindOf(CLASSINFO(wxFrame))) - fullScreenRect->GetParent()->ClientToScreen(& x, & y); - - rect.x = x; rect.y = y; - rect.width = sz.x; rect.height = sz.y; - - return BeginDrag(hotspot, window, true, & rect); -} - -// End drag -bool wxGenericDragImage::EndDrag() -{ - if (m_window) - { -#ifdef __WXMSW__ - // Under Windows we can be pretty sure this test will give - // the correct results - if (wxWindow::GetCapture() == m_window) -#endif - m_window->ReleaseMouse(); - - if (m_cursor.Ok() && m_oldCursor.Ok()) - { - m_window->SetCursor(m_oldCursor); - } - } - - if (m_windowDC) - { -#ifdef wxHAS_NATIVE_OVERLAY - m_overlay.Reset(); -#else - m_windowDC->DestroyClippingRegion(); -#endif - delete m_windowDC; - m_windowDC = (wxDC*) NULL; - } - -#ifndef wxHAS_NATIVE_OVERLAY - m_repairBitmap = wxNullBitmap; -#endif - - return true; -} - -// Move the image: call from OnMouseMove. Pt is in window client coordinates if window -// is non-NULL, or in screen coordinates if NULL. -bool wxGenericDragImage::Move(const wxPoint& pt) -{ - wxASSERT_MSG( (m_windowDC != (wxDC*) NULL), wxT("No window DC in wxGenericDragImage::Move()") ); - - wxPoint pt2(pt); - if (m_fullScreen) - pt2 = m_window->ClientToScreen(pt); - - // Erase at old position, then show at the current position - wxPoint oldPos = m_position; - - bool eraseOldImage = (m_isDirty && m_isShown); - - if (m_isShown) - RedrawImage(oldPos - m_offset, pt2 - m_offset, eraseOldImage, true); - - m_position = pt2; - - if (m_isShown) - m_isDirty = true; - - return true; -} - -bool wxGenericDragImage::Show() -{ - wxASSERT_MSG( (m_windowDC != (wxDC*) NULL), wxT("No window DC in wxGenericDragImage::Show()") ); - - // Show at the current position - - if (!m_isShown) - { - // This is where we restore the backing bitmap, in case - // something has changed on the window. - -#ifndef wxHAS_NATIVE_OVERLAY - wxBitmap* backing = (m_pBackingBitmap ? m_pBackingBitmap : (wxBitmap*) & m_backingBitmap); - wxMemoryDC memDC; - memDC.SelectObject(* backing); - - UpdateBackingFromWindow(* m_windowDC, memDC, m_boundingRect, wxRect(0, 0, m_boundingRect.width, m_boundingRect.height)); - - //memDC.Blit(0, 0, m_boundingRect.width, m_boundingRect.height, m_windowDC, m_boundingRect.x, m_boundingRect.y); - memDC.SelectObject(wxNullBitmap); -#endif // !wxHAS_NATIVE_OVERLAY - - RedrawImage(m_position - m_offset, m_position - m_offset, false, true); - } - - m_isShown = true; - m_isDirty = true; - - return true; -} - -bool wxGenericDragImage::UpdateBackingFromWindow(wxDC& windowDC, wxMemoryDC& destDC, - const wxRect& sourceRect, const wxRect& destRect) const -{ - return destDC.Blit(destRect.x, destRect.y, destRect.width, destRect.height, & windowDC, - sourceRect.x, sourceRect.y); -} - -bool wxGenericDragImage::Hide() -{ - wxASSERT_MSG( (m_windowDC != (wxDC*) NULL), wxT("No window DC in wxGenericDragImage::Hide()") ); - - // Repair the old position - - if (m_isShown && m_isDirty) - { - RedrawImage(m_position - m_offset, m_position - m_offset, true, false); - } - - m_isShown = false; - m_isDirty = false; - - return true; -} - -// More efficient: erase and redraw simultaneously if possible -bool wxGenericDragImage::RedrawImage(const wxPoint& oldPos, const wxPoint& newPos, - bool eraseOld, bool drawNew) -{ - if (!m_windowDC) - return false; - -#ifdef wxHAS_NATIVE_OVERLAY - wxDCOverlay dcoverlay( m_overlay, (wxWindowDC*) m_windowDC ) ; - if ( eraseOld ) - dcoverlay.Clear() ; - if (drawNew) - DoDrawImage(*m_windowDC, newPos); -#else // !wxHAS_NATIVE_OVERLAY - wxBitmap* backing = (m_pBackingBitmap ? m_pBackingBitmap : (wxBitmap*) & m_backingBitmap); - if (!backing->Ok()) - return false; - - wxRect oldRect(GetImageRect(oldPos)); - wxRect newRect(GetImageRect(newPos)); - - wxRect fullRect; - - // Full rect: the combination of both rects - if (eraseOld && drawNew) - { - int oldRight = oldRect.GetRight(); - int oldBottom = oldRect.GetBottom(); - int newRight = newRect.GetRight(); - int newBottom = newRect.GetBottom(); - - wxPoint topLeft = wxPoint(wxMin(oldPos.x, newPos.x), wxMin(oldPos.y, newPos.y)); - wxPoint bottomRight = wxPoint(wxMax(oldRight, newRight), wxMax(oldBottom, newBottom)); - - fullRect.x = topLeft.x; fullRect.y = topLeft.y; - fullRect.SetRight(bottomRight.x); - fullRect.SetBottom(bottomRight.y); - } - else if (eraseOld) - fullRect = oldRect; - else if (drawNew) - fullRect = newRect; - - // Make the bitmap bigger than it need be, so we don't - // keep reallocating all the time. - int excess = 50; - - if (!m_repairBitmap.Ok() || (m_repairBitmap.GetWidth() < fullRect.GetWidth() || m_repairBitmap.GetHeight() < fullRect.GetHeight())) - { - m_repairBitmap = wxBitmap(fullRect.GetWidth() + excess, fullRect.GetHeight() + excess); - } - - wxMemoryDC memDC; - memDC.SelectObject(* backing); - - wxMemoryDC memDCTemp; - memDCTemp.SelectObject(m_repairBitmap); - - // Draw the backing bitmap onto the repair bitmap. - // If full-screen, we may have specified the rect on the - // screen that we're using for our backing bitmap. - // So subtract this when we're blitting from the backing bitmap - // (translate from screen to backing-bitmap coords). - - memDCTemp.Blit(0, 0, fullRect.GetWidth(), fullRect.GetHeight(), & memDC, fullRect.x - m_boundingRect.x, fullRect.y - m_boundingRect.y); - - // If drawing, draw the image onto the mem DC - if (drawNew) - { - wxPoint pos(newPos.x - fullRect.x, newPos.y - fullRect.y) ; - DoDrawImage(memDCTemp, pos); - } - - // Now blit to the window - // Finally, blit the temp mem DC to the window. - m_windowDC->Blit(fullRect.x, fullRect.y, fullRect.width, fullRect.height, & memDCTemp, 0, 0); - - memDCTemp.SelectObject(wxNullBitmap); - memDC.SelectObject(wxNullBitmap); -#endif // wxHAS_NATIVE_OVERLAY/!wxHAS_NATIVE_OVERLAY - - return true; -} - -// Override this if you are using a virtual image (drawing your own image) -bool wxGenericDragImage::DoDrawImage(wxDC& dc, const wxPoint& pos) const -{ - if (m_bitmap.Ok()) - { - dc.DrawBitmap(m_bitmap, pos.x, pos.y, (m_bitmap.GetMask() != 0)); - return true; - } - else if (m_icon.Ok()) - { - dc.DrawIcon(m_icon, pos.x, pos.y); - return true; - } - else - return false; -} - -// Override this if you are using a virtual image (drawing your own image) -wxRect wxGenericDragImage::GetImageRect(const wxPoint& pos) const -{ - if (m_bitmap.Ok()) - { - return wxRect(pos.x, pos.y, m_bitmap.GetWidth(), m_bitmap.GetHeight()); - } - else if (m_icon.Ok()) - { - return wxRect(pos.x, pos.y, m_icon.GetWidth(), m_icon.GetHeight()); - } - else - { - return wxRect(pos.x, pos.y, 0, 0); - } -} - -#endif // wxUSE_DRAGIMAGE +///////////////////////////////////////////////////////////////////////////// +// Name: src/generic/dragimgg.cpp +// Purpose: Generic wxDragImage implementation +// Author: Julian Smart +// Modified by: +// Created: 29/2/2000 +// RCS-ID: $Id: dragimgg.cpp 42397 2006-10-25 12:12:56Z VS $ +// Copyright: (c) Julian Smart +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_DRAGIMAGE + +#ifndef WX_PRECOMP + #include + #include "wx/window.h" + #include "wx/frame.h" + #include "wx/dcclient.h" + #include "wx/dcscreen.h" + #include "wx/dcmemory.h" + #include "wx/settings.h" + #include "wx/intl.h" + #include "wx/log.h" + #include "wx/image.h" +#endif + +#define wxUSE_IMAGE_IN_DRAGIMAGE 1 + +#include "wx/generic/dragimgg.h" + +// ---------------------------------------------------------------------------- +// macros +// ---------------------------------------------------------------------------- + +IMPLEMENT_DYNAMIC_CLASS(wxGenericDragImage, wxObject) + +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// wxGenericDragImage ctors/dtor +// ---------------------------------------------------------------------------- + +wxGenericDragImage::~wxGenericDragImage() +{ + if (m_windowDC) + { + delete m_windowDC; + } +} + +void wxGenericDragImage::Init() +{ + m_isDirty = false; + m_isShown = false; + m_windowDC = (wxDC*) NULL; + m_window = (wxWindow*) NULL; + m_fullScreen = false; +#ifdef wxHAS_NATIVE_OVERLAY + m_dcOverlay = NULL; +#else + m_pBackingBitmap = (wxBitmap*) NULL; +#endif +} + +#if WXWIN_COMPATIBILITY_2_6 +wxGenericDragImage::wxGenericDragImage(const wxCursor& cursor, const wxPoint& WXUNUSED(cursorHotspot)) +{ + Init(); + Create(cursor); +} + +wxGenericDragImage::wxGenericDragImage(const wxBitmap& image, const wxCursor& cursor, const wxPoint& WXUNUSED(cursorHotspot)) +{ + Init(); + + Create(image, cursor); +} + +wxGenericDragImage::wxGenericDragImage(const wxIcon& image, const wxCursor& cursor, const wxPoint& WXUNUSED(cursorHotspot)) +{ + Init(); + + Create(image, cursor); +} + +wxGenericDragImage::wxGenericDragImage(const wxString& str, const wxCursor& cursor, const wxPoint& WXUNUSED(cursorHotspot)) +{ + Init(); + + Create(str, cursor); +} + +bool wxGenericDragImage::Create(const wxCursor& cursor, const wxPoint& WXUNUSED(cursorHotspot)) +{ + return Create(cursor); +} + +bool wxGenericDragImage::Create(const wxBitmap& image, const wxCursor& cursor, const wxPoint& WXUNUSED(cursorHotspot)) +{ + return Create(image, cursor); +} + +bool wxGenericDragImage::Create(const wxIcon& image, const wxCursor& cursor, const wxPoint& WXUNUSED(cursorHotspot)) +{ + return Create(image, cursor); +} + +bool wxGenericDragImage::Create(const wxString& str, const wxCursor& cursor, const wxPoint& WXUNUSED(cursorHotspot)) +{ + return Create(str, cursor); +} +#endif // WXWIN_COMPATIBILITY_2_6 + +// Attributes +//////////////////////////////////////////////////////////////////////////// + + +// Operations +//////////////////////////////////////////////////////////////////////////// + +// Create a drag image with a virtual image (need to override DoDrawImage, GetImageRect) +bool wxGenericDragImage::Create(const wxCursor& cursor) +{ + m_cursor = cursor; + + return true; +} + +// Create a drag image from a bitmap and optional cursor +bool wxGenericDragImage::Create(const wxBitmap& image, const wxCursor& cursor) +{ + // We don't have to combine the cursor explicitly since we simply show the cursor + // as we drag. This currently will only work within one window. + + m_cursor = cursor; + m_bitmap = image; + + return true ; +} + +// Create a drag image from an icon and optional cursor +bool wxGenericDragImage::Create(const wxIcon& image, const wxCursor& cursor) +{ + // We don't have to combine the cursor explicitly since we simply show the cursor + // as we drag. This currently will only work within one window. + + m_cursor = cursor; + m_icon = image; + + return true ; +} + +// Create a drag image from a string and optional cursor +bool wxGenericDragImage::Create(const wxString& str, const wxCursor& cursor) +{ + wxFont font(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT)); + + long w = 0, h = 0; + wxScreenDC dc; + dc.SetFont(font); + dc.GetTextExtent(str, & w, & h); + dc.SetFont(wxNullFont); + + wxMemoryDC dc2; + + // Sometimes GetTextExtent isn't accurate enough, so make it longer + wxBitmap bitmap((int) ((w+2) * 1.5), (int) h+2); + dc2.SelectObject(bitmap); + + dc2.SetFont(font); + dc2.SetBackground(* wxWHITE_BRUSH); + dc2.Clear(); + dc2.SetBackgroundMode(wxTRANSPARENT); + dc2.SetTextForeground(* wxLIGHT_GREY); + dc2.DrawText(str, 0, 0); + dc2.DrawText(str, 1, 0); + dc2.DrawText(str, 2, 0); + dc2.DrawText(str, 1, 1); + dc2.DrawText(str, 2, 1); + dc2.DrawText(str, 1, 2); + dc2.DrawText(str, 2, 2); + + dc2.SetTextForeground(* wxBLACK); + dc2.DrawText(str, 1, 1); + + dc2.SelectObject(wxNullBitmap); + +#if wxUSE_IMAGE_IN_DRAGIMAGE && (!defined(__WXMSW__) || wxUSE_WXDIB) + // Make the bitmap masked + wxImage image = bitmap.ConvertToImage(); + image.SetMaskColour(255, 255, 255); + bitmap = wxBitmap(image); +#endif + + return Create(bitmap, cursor); +} + +#if wxUSE_TREECTRL +// Create a drag image for the given tree control item +bool wxGenericDragImage::Create(const wxTreeCtrl& treeCtrl, wxTreeItemId& id) +{ + wxString str = treeCtrl.GetItemText(id); + return Create(str); +} +#endif + +#if wxUSE_LISTCTRL +// Create a drag image for the given list control item +bool wxGenericDragImage::Create(const wxListCtrl& listCtrl, long id) +{ + wxString str = listCtrl.GetItemText(id); + return Create(str); +} +#endif + +// Begin drag +bool wxGenericDragImage::BeginDrag(const wxPoint& hotspot, + wxWindow* window, + bool fullScreen, + wxRect* rect) +{ + wxASSERT_MSG( (window != 0), wxT("Window must not be null in BeginDrag.")); + + // The image should be offset by this amount + m_offset = hotspot; + m_window = window; + m_fullScreen = fullScreen; + + if (rect) + m_boundingRect = * rect; + + m_isDirty = false; + m_isDirty = false; + + if (window) + { + window->CaptureMouse(); + + if (m_cursor.Ok()) + { + m_oldCursor = window->GetCursor(); + window->SetCursor(m_cursor); + } + } + + // Make a copy of the window so we can repair damage done as the image is + // dragged. + + wxSize clientSize; + wxPoint pt; + if (!m_fullScreen) + { + clientSize = window->GetClientSize(); + m_boundingRect.x = 0; m_boundingRect.y = 0; + m_boundingRect.width = clientSize.x; m_boundingRect.height = clientSize.y; + } + else + { + int w, h; + wxDisplaySize(& w, & h); + clientSize.x = w; clientSize.y = h; + if (rect) + { + pt.x = m_boundingRect.x; pt.y = m_boundingRect.y; + clientSize.x = m_boundingRect.width; clientSize.y = m_boundingRect.height; + } + else + { + m_boundingRect.x = 0; m_boundingRect.y = 0; + m_boundingRect.width = w; m_boundingRect.height = h; + } + } + +#ifndef wxHAS_NATIVE_OVERLAY + wxBitmap* backing = (m_pBackingBitmap ? m_pBackingBitmap : (wxBitmap*) & m_backingBitmap); + + if (!backing->Ok() || (backing->GetWidth() < clientSize.x || backing->GetHeight() < clientSize.y)) + (*backing) = wxBitmap(clientSize.x, clientSize.y); +#endif // !wxHAS_NATIVE_OVERLAY + + if (!m_fullScreen) + { + m_windowDC = new wxClientDC(window); + } + else + { + m_windowDC = new wxScreenDC; + +#if 0 + // Use m_boundingRect to limit the area considered. + ((wxScreenDC*) m_windowDC)->StartDrawingOnTop(rect); +#endif + + m_windowDC->SetClippingRegion(m_boundingRect.x, m_boundingRect.y, + m_boundingRect.width, m_boundingRect.height); + } + + return true; +} + +// Begin drag. hotspot is the location of the drag position relative to the upper-left +// corner of the image. This is full screen only. fullScreenRect gives the +// position of the window on the screen, to restrict the drag to. +bool wxGenericDragImage::BeginDrag(const wxPoint& hotspot, wxWindow* window, wxWindow* fullScreenRect) +{ + wxRect rect; + + int x = fullScreenRect->GetPosition().x; + int y = fullScreenRect->GetPosition().y; + + wxSize sz = fullScreenRect->GetSize(); + + if (fullScreenRect->GetParent() && !fullScreenRect->IsKindOf(CLASSINFO(wxFrame))) + fullScreenRect->GetParent()->ClientToScreen(& x, & y); + + rect.x = x; rect.y = y; + rect.width = sz.x; rect.height = sz.y; + + return BeginDrag(hotspot, window, true, & rect); +} + +// End drag +bool wxGenericDragImage::EndDrag() +{ + if (m_window) + { +#ifdef __WXMSW__ + // Under Windows we can be pretty sure this test will give + // the correct results + if (wxWindow::GetCapture() == m_window) +#endif + m_window->ReleaseMouse(); + + if (m_cursor.Ok() && m_oldCursor.Ok()) + { + m_window->SetCursor(m_oldCursor); + } + } + + if (m_windowDC) + { +#ifdef wxHAS_NATIVE_OVERLAY + m_overlay.Reset(); +#else + m_windowDC->DestroyClippingRegion(); +#endif + delete m_windowDC; + m_windowDC = (wxDC*) NULL; + } + +#ifndef wxHAS_NATIVE_OVERLAY + m_repairBitmap = wxNullBitmap; +#endif + + return true; +} + +// Move the image: call from OnMouseMove. Pt is in window client coordinates if window +// is non-NULL, or in screen coordinates if NULL. +bool wxGenericDragImage::Move(const wxPoint& pt) +{ + wxASSERT_MSG( (m_windowDC != (wxDC*) NULL), wxT("No window DC in wxGenericDragImage::Move()") ); + + wxPoint pt2(pt); + if (m_fullScreen) + pt2 = m_window->ClientToScreen(pt); + + // Erase at old position, then show at the current position + wxPoint oldPos = m_position; + + bool eraseOldImage = (m_isDirty && m_isShown); + + if (m_isShown) + RedrawImage(oldPos - m_offset, pt2 - m_offset, eraseOldImage, true); + + m_position = pt2; + + if (m_isShown) + m_isDirty = true; + + return true; +} + +bool wxGenericDragImage::Show() +{ + wxASSERT_MSG( (m_windowDC != (wxDC*) NULL), wxT("No window DC in wxGenericDragImage::Show()") ); + + // Show at the current position + + if (!m_isShown) + { + // This is where we restore the backing bitmap, in case + // something has changed on the window. + +#ifndef wxHAS_NATIVE_OVERLAY + wxBitmap* backing = (m_pBackingBitmap ? m_pBackingBitmap : (wxBitmap*) & m_backingBitmap); + wxMemoryDC memDC; + memDC.SelectObject(* backing); + + UpdateBackingFromWindow(* m_windowDC, memDC, m_boundingRect, wxRect(0, 0, m_boundingRect.width, m_boundingRect.height)); + + //memDC.Blit(0, 0, m_boundingRect.width, m_boundingRect.height, m_windowDC, m_boundingRect.x, m_boundingRect.y); + memDC.SelectObject(wxNullBitmap); +#endif // !wxHAS_NATIVE_OVERLAY + + RedrawImage(m_position - m_offset, m_position - m_offset, false, true); + } + + m_isShown = true; + m_isDirty = true; + + return true; +} + +bool wxGenericDragImage::UpdateBackingFromWindow(wxDC& windowDC, wxMemoryDC& destDC, + const wxRect& sourceRect, const wxRect& destRect) const +{ + return destDC.Blit(destRect.x, destRect.y, destRect.width, destRect.height, & windowDC, + sourceRect.x, sourceRect.y); +} + +bool wxGenericDragImage::Hide() +{ + wxASSERT_MSG( (m_windowDC != (wxDC*) NULL), wxT("No window DC in wxGenericDragImage::Hide()") ); + + // Repair the old position + + if (m_isShown && m_isDirty) + { + RedrawImage(m_position - m_offset, m_position - m_offset, true, false); + } + + m_isShown = false; + m_isDirty = false; + + return true; +} + +// More efficient: erase and redraw simultaneously if possible +bool wxGenericDragImage::RedrawImage(const wxPoint& oldPos, const wxPoint& newPos, + bool eraseOld, bool drawNew) +{ + if (!m_windowDC) + return false; + +#ifdef wxHAS_NATIVE_OVERLAY + wxDCOverlay dcoverlay( m_overlay, (wxWindowDC*) m_windowDC ) ; + if ( eraseOld ) + dcoverlay.Clear() ; + if (drawNew) + DoDrawImage(*m_windowDC, newPos); +#else // !wxHAS_NATIVE_OVERLAY + wxBitmap* backing = (m_pBackingBitmap ? m_pBackingBitmap : (wxBitmap*) & m_backingBitmap); + if (!backing->Ok()) + return false; + + wxRect oldRect(GetImageRect(oldPos)); + wxRect newRect(GetImageRect(newPos)); + + wxRect fullRect; + + // Full rect: the combination of both rects + if (eraseOld && drawNew) + { + int oldRight = oldRect.GetRight(); + int oldBottom = oldRect.GetBottom(); + int newRight = newRect.GetRight(); + int newBottom = newRect.GetBottom(); + + wxPoint topLeft = wxPoint(wxMin(oldPos.x, newPos.x), wxMin(oldPos.y, newPos.y)); + wxPoint bottomRight = wxPoint(wxMax(oldRight, newRight), wxMax(oldBottom, newBottom)); + + fullRect.x = topLeft.x; fullRect.y = topLeft.y; + fullRect.SetRight(bottomRight.x); + fullRect.SetBottom(bottomRight.y); + } + else if (eraseOld) + fullRect = oldRect; + else if (drawNew) + fullRect = newRect; + + // Make the bitmap bigger than it need be, so we don't + // keep reallocating all the time. + int excess = 50; + + if (!m_repairBitmap.Ok() || (m_repairBitmap.GetWidth() < fullRect.GetWidth() || m_repairBitmap.GetHeight() < fullRect.GetHeight())) + { + m_repairBitmap = wxBitmap(fullRect.GetWidth() + excess, fullRect.GetHeight() + excess); + } + + wxMemoryDC memDC; + memDC.SelectObject(* backing); + + wxMemoryDC memDCTemp; + memDCTemp.SelectObject(m_repairBitmap); + + // Draw the backing bitmap onto the repair bitmap. + // If full-screen, we may have specified the rect on the + // screen that we're using for our backing bitmap. + // So subtract this when we're blitting from the backing bitmap + // (translate from screen to backing-bitmap coords). + + memDCTemp.Blit(0, 0, fullRect.GetWidth(), fullRect.GetHeight(), & memDC, fullRect.x - m_boundingRect.x, fullRect.y - m_boundingRect.y); + + // If drawing, draw the image onto the mem DC + if (drawNew) + { + wxPoint pos(newPos.x - fullRect.x, newPos.y - fullRect.y) ; + DoDrawImage(memDCTemp, pos); + } + + // Now blit to the window + // Finally, blit the temp mem DC to the window. + m_windowDC->Blit(fullRect.x, fullRect.y, fullRect.width, fullRect.height, & memDCTemp, 0, 0); + + memDCTemp.SelectObject(wxNullBitmap); + memDC.SelectObject(wxNullBitmap); +#endif // wxHAS_NATIVE_OVERLAY/!wxHAS_NATIVE_OVERLAY + + return true; +} + +// Override this if you are using a virtual image (drawing your own image) +bool wxGenericDragImage::DoDrawImage(wxDC& dc, const wxPoint& pos) const +{ + if (m_bitmap.Ok()) + { + dc.DrawBitmap(m_bitmap, pos.x, pos.y, (m_bitmap.GetMask() != 0)); + return true; + } + else if (m_icon.Ok()) + { + dc.DrawIcon(m_icon, pos.x, pos.y); + return true; + } + else + return false; +} + +// Override this if you are using a virtual image (drawing your own image) +wxRect wxGenericDragImage::GetImageRect(const wxPoint& pos) const +{ + if (m_bitmap.Ok()) + { + return wxRect(pos.x, pos.y, m_bitmap.GetWidth(), m_bitmap.GetHeight()); + } + else if (m_icon.Ok()) + { + return wxRect(pos.x, pos.y, m_icon.GetWidth(), m_icon.GetHeight()); + } + else + { + return wxRect(pos.x, pos.y, 0, 0); + } +} + +#endif // wxUSE_DRAGIMAGE diff --git a/Externals/wxWidgets/src/generic/fdrepdlg.cpp b/Externals/wxWidgets/src/generic/fdrepdlg.cpp index cadfbd0ced..797ac68cbb 100644 --- a/Externals/wxWidgets/src/generic/fdrepdlg.cpp +++ b/Externals/wxWidgets/src/generic/fdrepdlg.cpp @@ -1,291 +1,291 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/generic/fdrepgg.cpp -// Purpose: Find/Replace dialogs -// Author: Markus Greither and Vadim Zeitlin -// Modified by: -// Created: 05/25/01 -// RCS-ID: -// Copyright: (c) wxWidgets team -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_FINDREPLDLG - -#ifndef WX_PRECOMP - #include "wx/intl.h" - #include "wx/log.h" - - #include "wx/sizer.h" - - #include "wx/button.h" - #include "wx/checkbox.h" - #include "wx/radiobox.h" - #include "wx/stattext.h" - #include "wx/textctrl.h" - #include "wx/settings.h" -#endif - -#include "wx/fdrepdlg.h" - -// ---------------------------------------------------------------------------- -// constants -// ---------------------------------------------------------------------------- - -// ============================================================================ -// implementation -// ============================================================================ - -IMPLEMENT_DYNAMIC_CLASS(wxGenericFindReplaceDialog, wxDialog) - -BEGIN_EVENT_TABLE(wxGenericFindReplaceDialog, wxDialog) - EVT_BUTTON(wxID_FIND, wxGenericFindReplaceDialog::OnFind) - EVT_BUTTON(wxID_REPLACE, wxGenericFindReplaceDialog::OnReplace) - EVT_BUTTON(wxID_REPLACE_ALL, wxGenericFindReplaceDialog::OnReplaceAll) - EVT_BUTTON(wxID_CANCEL, wxGenericFindReplaceDialog::OnCancel) - - EVT_UPDATE_UI(wxID_FIND, wxGenericFindReplaceDialog::OnUpdateFindUI) - EVT_UPDATE_UI(wxID_REPLACE, wxGenericFindReplaceDialog::OnUpdateFindUI) - EVT_UPDATE_UI(wxID_REPLACE_ALL, wxGenericFindReplaceDialog::OnUpdateFindUI) - - EVT_CLOSE(wxGenericFindReplaceDialog::OnCloseWindow) -END_EVENT_TABLE() - -// ---------------------------------------------------------------------------- -// wxGenericFindReplaceDialog -// ---------------------------------------------------------------------------- - -void wxGenericFindReplaceDialog::Init() -{ - m_FindReplaceData = NULL; - - m_chkWord = - m_chkCase = NULL; - - m_radioDir = NULL; - - m_textFind = - m_textRepl = NULL; -} - -bool wxGenericFindReplaceDialog::Create(wxWindow *parent, - wxFindReplaceData *data, - const wxString& title, - int style) -{ - if ( !wxDialog::Create(parent, wxID_ANY, title, - wxDefaultPosition, wxDefaultSize, - wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER - | style) ) - { - return false; - } - - SetData(data); - - wxCHECK_MSG( m_FindReplaceData, false, - _T("can't create dialog without data") ); - - bool isPda = (wxSystemSettings::GetScreenType() <= wxSYS_SCREEN_PDA); - - wxBoxSizer *leftsizer = new wxBoxSizer( wxVERTICAL ); - - // 3 columns because there is a spacer in the middle - wxFlexGridSizer *sizer2Col = new wxFlexGridSizer(3); - sizer2Col->AddGrowableCol(2); - - sizer2Col->Add(new wxStaticText(this, wxID_ANY, _("Search for:"), - wxDefaultPosition, wxSize(80, wxDefaultCoord)), - 0, - wxALIGN_CENTRE_VERTICAL | wxALIGN_RIGHT); - - sizer2Col->Add(10, 0); - - m_textFind = new wxTextCtrl(this, wxID_ANY, m_FindReplaceData->GetFindString()); - sizer2Col->Add(m_textFind, 1, wxALIGN_CENTRE_VERTICAL | wxEXPAND); - - if ( style & wxFR_REPLACEDIALOG ) - { - sizer2Col->Add(new wxStaticText(this, wxID_ANY, _("Replace with:"), - wxDefaultPosition, wxSize(80, wxDefaultCoord)), - 0, - wxALIGN_CENTRE_VERTICAL | - wxALIGN_RIGHT | wxTOP, 5); - - sizer2Col->Add(isPda ? 2 : 10, 0); - - m_textRepl = new wxTextCtrl(this, wxID_ANY, - m_FindReplaceData->GetReplaceString()); - sizer2Col->Add(m_textRepl, 1, - wxALIGN_CENTRE_VERTICAL | wxEXPAND | wxTOP, 5); - } - - leftsizer->Add(sizer2Col, 0, wxEXPAND | wxALL, 5); - - wxBoxSizer *optsizer = new wxBoxSizer( isPda ? wxVERTICAL : wxHORIZONTAL ); - - wxBoxSizer *chksizer = new wxBoxSizer( wxVERTICAL); - - m_chkWord = new wxCheckBox(this, wxID_ANY, _("Whole word")); - chksizer->Add(m_chkWord, 0, wxALL, 3); - - m_chkCase = new wxCheckBox(this, wxID_ANY, _("Match case")); - chksizer->Add(m_chkCase, 0, wxALL, 3); - - optsizer->Add(chksizer, 0, wxALL, 10); - - static const wxString searchDirections[] = {_("Up"), _("Down")}; - int majorDimension = 0; - int rbStyle ; - if (isPda) - rbStyle = wxRA_SPECIFY_ROWS; - else - rbStyle = wxRA_SPECIFY_COLS; - - m_radioDir = new wxRadioBox(this, wxID_ANY, _("Search direction"), - wxDefaultPosition, wxDefaultSize, - WXSIZEOF(searchDirections), searchDirections, - majorDimension, rbStyle); - - optsizer->Add(m_radioDir, 0, wxALL, isPda ? 5 : 10); - - leftsizer->Add(optsizer); - - wxBoxSizer *bttnsizer = new wxBoxSizer(wxVERTICAL); - - wxButton* btn = new wxButton(this, wxID_FIND); - btn->SetDefault(); - bttnsizer->Add(btn, 0, wxALL, 3); - - bttnsizer->Add(new wxButton(this, wxID_CANCEL), 0, wxALL, 3); - - if ( style & wxFR_REPLACEDIALOG ) - { - bttnsizer->Add(new wxButton(this, wxID_REPLACE, _("&Replace")), - 0, wxALL, 3); - - bttnsizer->Add(new wxButton(this, wxID_REPLACE_ALL, _("Replace &all")), - 0, wxALL, 3); - } - - wxBoxSizer *topsizer = new wxBoxSizer( wxHORIZONTAL ); - - topsizer->Add(leftsizer, 1, wxALL, isPda ? 0 : 5); - topsizer->Add(bttnsizer, 0, wxALL, isPda ? 0 : 5); - - int flags = m_FindReplaceData->GetFlags(); - - if ( flags & wxFR_MATCHCASE ) - m_chkCase->SetValue(true); - - if ( flags & wxFR_WHOLEWORD ) - m_chkWord->SetValue(true); - - m_radioDir->SetSelection( flags & wxFR_DOWN ); - - if ( style & wxFR_NOMATCHCASE ) - m_chkCase->Enable(false); - - if ( style & wxFR_NOWHOLEWORD ) - m_chkWord->Enable(false); - - if ( style & wxFR_NOUPDOWN) - m_radioDir->Enable(false); - - SetAutoLayout( true ); - SetSizer( topsizer ); - - topsizer->SetSizeHints( this ); - topsizer->Fit( this ); - - Centre( wxBOTH ); - - m_textFind->SetFocus(); - - return true; -} - -// ---------------------------------------------------------------------------- -// send the notification event -// ---------------------------------------------------------------------------- - -void wxGenericFindReplaceDialog::SendEvent(const wxEventType& evtType) -{ - wxFindDialogEvent event(evtType, GetId()); - event.SetEventObject(this); - event.SetFindString(m_textFind->GetValue()); - if ( HasFlag(wxFR_REPLACEDIALOG) ) - { - event.SetReplaceString(m_textRepl->GetValue()); - } - - int flags = 0; - - if ( m_chkCase->GetValue() ) - flags |= wxFR_MATCHCASE; - - if ( m_chkWord->GetValue() ) - flags |= wxFR_WHOLEWORD; - - if ( !m_radioDir || m_radioDir->GetSelection() == 1 ) - { - flags |= wxFR_DOWN; - } - - event.SetFlags(flags); - - wxFindReplaceDialogBase::Send(event); -} - -// ---------------------------------------------------------------------------- -// event handlers -// ---------------------------------------------------------------------------- - -void wxGenericFindReplaceDialog::OnFind(wxCommandEvent& WXUNUSED(event)) -{ - SendEvent(wxEVT_COMMAND_FIND_NEXT); -} - -void wxGenericFindReplaceDialog::OnReplace(wxCommandEvent& WXUNUSED(event)) -{ - SendEvent(wxEVT_COMMAND_FIND_REPLACE); -} - -void wxGenericFindReplaceDialog::OnReplaceAll(wxCommandEvent& WXUNUSED(event)) -{ - SendEvent(wxEVT_COMMAND_FIND_REPLACE_ALL); -} - -void wxGenericFindReplaceDialog::OnCancel(wxCommandEvent& WXUNUSED(event)) -{ - SendEvent(wxEVT_COMMAND_FIND_CLOSE); - - Show(false); -} - -void wxGenericFindReplaceDialog::OnUpdateFindUI(wxUpdateUIEvent &event) -{ - // we can't search for empty strings - event.Enable( !m_textFind->GetValue().empty() ); -} - -void wxGenericFindReplaceDialog::OnCloseWindow(wxCloseEvent &) -{ - SendEvent(wxEVT_COMMAND_FIND_CLOSE); -} - -#endif // wxUSE_FINDREPLDLG +///////////////////////////////////////////////////////////////////////////// +// Name: src/generic/fdrepgg.cpp +// Purpose: Find/Replace dialogs +// Author: Markus Greither and Vadim Zeitlin +// Modified by: +// Created: 05/25/01 +// RCS-ID: +// Copyright: (c) wxWidgets team +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_FINDREPLDLG + +#ifndef WX_PRECOMP + #include "wx/intl.h" + #include "wx/log.h" + + #include "wx/sizer.h" + + #include "wx/button.h" + #include "wx/checkbox.h" + #include "wx/radiobox.h" + #include "wx/stattext.h" + #include "wx/textctrl.h" + #include "wx/settings.h" +#endif + +#include "wx/fdrepdlg.h" + +// ---------------------------------------------------------------------------- +// constants +// ---------------------------------------------------------------------------- + +// ============================================================================ +// implementation +// ============================================================================ + +IMPLEMENT_DYNAMIC_CLASS(wxGenericFindReplaceDialog, wxDialog) + +BEGIN_EVENT_TABLE(wxGenericFindReplaceDialog, wxDialog) + EVT_BUTTON(wxID_FIND, wxGenericFindReplaceDialog::OnFind) + EVT_BUTTON(wxID_REPLACE, wxGenericFindReplaceDialog::OnReplace) + EVT_BUTTON(wxID_REPLACE_ALL, wxGenericFindReplaceDialog::OnReplaceAll) + EVT_BUTTON(wxID_CANCEL, wxGenericFindReplaceDialog::OnCancel) + + EVT_UPDATE_UI(wxID_FIND, wxGenericFindReplaceDialog::OnUpdateFindUI) + EVT_UPDATE_UI(wxID_REPLACE, wxGenericFindReplaceDialog::OnUpdateFindUI) + EVT_UPDATE_UI(wxID_REPLACE_ALL, wxGenericFindReplaceDialog::OnUpdateFindUI) + + EVT_CLOSE(wxGenericFindReplaceDialog::OnCloseWindow) +END_EVENT_TABLE() + +// ---------------------------------------------------------------------------- +// wxGenericFindReplaceDialog +// ---------------------------------------------------------------------------- + +void wxGenericFindReplaceDialog::Init() +{ + m_FindReplaceData = NULL; + + m_chkWord = + m_chkCase = NULL; + + m_radioDir = NULL; + + m_textFind = + m_textRepl = NULL; +} + +bool wxGenericFindReplaceDialog::Create(wxWindow *parent, + wxFindReplaceData *data, + const wxString& title, + int style) +{ + if ( !wxDialog::Create(parent, wxID_ANY, title, + wxDefaultPosition, wxDefaultSize, + wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER + | style) ) + { + return false; + } + + SetData(data); + + wxCHECK_MSG( m_FindReplaceData, false, + _T("can't create dialog without data") ); + + bool isPda = (wxSystemSettings::GetScreenType() <= wxSYS_SCREEN_PDA); + + wxBoxSizer *leftsizer = new wxBoxSizer( wxVERTICAL ); + + // 3 columns because there is a spacer in the middle + wxFlexGridSizer *sizer2Col = new wxFlexGridSizer(3); + sizer2Col->AddGrowableCol(2); + + sizer2Col->Add(new wxStaticText(this, wxID_ANY, _("Search for:"), + wxDefaultPosition, wxSize(80, wxDefaultCoord)), + 0, + wxALIGN_CENTRE_VERTICAL | wxALIGN_RIGHT); + + sizer2Col->Add(10, 0); + + m_textFind = new wxTextCtrl(this, wxID_ANY, m_FindReplaceData->GetFindString()); + sizer2Col->Add(m_textFind, 1, wxALIGN_CENTRE_VERTICAL | wxEXPAND); + + if ( style & wxFR_REPLACEDIALOG ) + { + sizer2Col->Add(new wxStaticText(this, wxID_ANY, _("Replace with:"), + wxDefaultPosition, wxSize(80, wxDefaultCoord)), + 0, + wxALIGN_CENTRE_VERTICAL | + wxALIGN_RIGHT | wxTOP, 5); + + sizer2Col->Add(isPda ? 2 : 10, 0); + + m_textRepl = new wxTextCtrl(this, wxID_ANY, + m_FindReplaceData->GetReplaceString()); + sizer2Col->Add(m_textRepl, 1, + wxALIGN_CENTRE_VERTICAL | wxEXPAND | wxTOP, 5); + } + + leftsizer->Add(sizer2Col, 0, wxEXPAND | wxALL, 5); + + wxBoxSizer *optsizer = new wxBoxSizer( isPda ? wxVERTICAL : wxHORIZONTAL ); + + wxBoxSizer *chksizer = new wxBoxSizer( wxVERTICAL); + + m_chkWord = new wxCheckBox(this, wxID_ANY, _("Whole word")); + chksizer->Add(m_chkWord, 0, wxALL, 3); + + m_chkCase = new wxCheckBox(this, wxID_ANY, _("Match case")); + chksizer->Add(m_chkCase, 0, wxALL, 3); + + optsizer->Add(chksizer, 0, wxALL, 10); + + static const wxString searchDirections[] = {_("Up"), _("Down")}; + int majorDimension = 0; + int rbStyle ; + if (isPda) + rbStyle = wxRA_SPECIFY_ROWS; + else + rbStyle = wxRA_SPECIFY_COLS; + + m_radioDir = new wxRadioBox(this, wxID_ANY, _("Search direction"), + wxDefaultPosition, wxDefaultSize, + WXSIZEOF(searchDirections), searchDirections, + majorDimension, rbStyle); + + optsizer->Add(m_radioDir, 0, wxALL, isPda ? 5 : 10); + + leftsizer->Add(optsizer); + + wxBoxSizer *bttnsizer = new wxBoxSizer(wxVERTICAL); + + wxButton* btn = new wxButton(this, wxID_FIND); + btn->SetDefault(); + bttnsizer->Add(btn, 0, wxALL, 3); + + bttnsizer->Add(new wxButton(this, wxID_CANCEL), 0, wxALL, 3); + + if ( style & wxFR_REPLACEDIALOG ) + { + bttnsizer->Add(new wxButton(this, wxID_REPLACE, _("&Replace")), + 0, wxALL, 3); + + bttnsizer->Add(new wxButton(this, wxID_REPLACE_ALL, _("Replace &all")), + 0, wxALL, 3); + } + + wxBoxSizer *topsizer = new wxBoxSizer( wxHORIZONTAL ); + + topsizer->Add(leftsizer, 1, wxALL, isPda ? 0 : 5); + topsizer->Add(bttnsizer, 0, wxALL, isPda ? 0 : 5); + + int flags = m_FindReplaceData->GetFlags(); + + if ( flags & wxFR_MATCHCASE ) + m_chkCase->SetValue(true); + + if ( flags & wxFR_WHOLEWORD ) + m_chkWord->SetValue(true); + + m_radioDir->SetSelection( flags & wxFR_DOWN ); + + if ( style & wxFR_NOMATCHCASE ) + m_chkCase->Enable(false); + + if ( style & wxFR_NOWHOLEWORD ) + m_chkWord->Enable(false); + + if ( style & wxFR_NOUPDOWN) + m_radioDir->Enable(false); + + SetAutoLayout( true ); + SetSizer( topsizer ); + + topsizer->SetSizeHints( this ); + topsizer->Fit( this ); + + Centre( wxBOTH ); + + m_textFind->SetFocus(); + + return true; +} + +// ---------------------------------------------------------------------------- +// send the notification event +// ---------------------------------------------------------------------------- + +void wxGenericFindReplaceDialog::SendEvent(const wxEventType& evtType) +{ + wxFindDialogEvent event(evtType, GetId()); + event.SetEventObject(this); + event.SetFindString(m_textFind->GetValue()); + if ( HasFlag(wxFR_REPLACEDIALOG) ) + { + event.SetReplaceString(m_textRepl->GetValue()); + } + + int flags = 0; + + if ( m_chkCase->GetValue() ) + flags |= wxFR_MATCHCASE; + + if ( m_chkWord->GetValue() ) + flags |= wxFR_WHOLEWORD; + + if ( !m_radioDir || m_radioDir->GetSelection() == 1 ) + { + flags |= wxFR_DOWN; + } + + event.SetFlags(flags); + + wxFindReplaceDialogBase::Send(event); +} + +// ---------------------------------------------------------------------------- +// event handlers +// ---------------------------------------------------------------------------- + +void wxGenericFindReplaceDialog::OnFind(wxCommandEvent& WXUNUSED(event)) +{ + SendEvent(wxEVT_COMMAND_FIND_NEXT); +} + +void wxGenericFindReplaceDialog::OnReplace(wxCommandEvent& WXUNUSED(event)) +{ + SendEvent(wxEVT_COMMAND_FIND_REPLACE); +} + +void wxGenericFindReplaceDialog::OnReplaceAll(wxCommandEvent& WXUNUSED(event)) +{ + SendEvent(wxEVT_COMMAND_FIND_REPLACE_ALL); +} + +void wxGenericFindReplaceDialog::OnCancel(wxCommandEvent& WXUNUSED(event)) +{ + SendEvent(wxEVT_COMMAND_FIND_CLOSE); + + Show(false); +} + +void wxGenericFindReplaceDialog::OnUpdateFindUI(wxUpdateUIEvent &event) +{ + // we can't search for empty strings + event.Enable( !m_textFind->GetValue().empty() ); +} + +void wxGenericFindReplaceDialog::OnCloseWindow(wxCloseEvent &) +{ + SendEvent(wxEVT_COMMAND_FIND_CLOSE); +} + +#endif // wxUSE_FINDREPLDLG diff --git a/Externals/wxWidgets/src/generic/filedlgg.cpp b/Externals/wxWidgets/src/generic/filedlgg.cpp index 71bb8c12b9..3b4b8a28f4 100644 --- a/Externals/wxWidgets/src/generic/filedlgg.cpp +++ b/Externals/wxWidgets/src/generic/filedlgg.cpp @@ -1,1645 +1,1645 @@ -////////////////////////////////////////////////////////////////////////////// -// Name: src/generic/filedlgg.cpp -// Purpose: wxGenericFileDialog -// Author: Robert Roebling -// Modified by: -// Created: 12/12/98 -// RCS-ID: $Id: filedlgg.cpp 45836 2007-05-05 17:13:30Z PC $ -// Copyright: (c) Robert Roebling -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_FILEDLG - -// NOTE : it probably also supports MAC, untested -#if !defined(__UNIX__) && !defined(__DOS__) && !defined(__WIN32__) && !defined(__OS2__) -#error wxGenericFileDialog currently only supports Unix, win32 and DOS -#endif - -#ifndef WX_PRECOMP - #ifdef __WXMSW__ - #include "wx/msw/wrapwin.h" - #endif - #include "wx/hash.h" - #include "wx/intl.h" - #include "wx/settings.h" - #include "wx/log.h" - #include "wx/msgdlg.h" - #include "wx/bmpbuttn.h" - #include "wx/checkbox.h" - #include "wx/choice.h" - #include "wx/stattext.h" - #include "wx/textctrl.h" - #include "wx/sizer.h" - #include "wx/filedlg.h" // wxFD_OPEN, wxFD_SAVE... -#endif - -#include "wx/longlong.h" -#include "wx/tokenzr.h" -#include "wx/config.h" -#include "wx/imaglist.h" -#include "wx/dir.h" -#include "wx/artprov.h" -#include "wx/filefn.h" -#include "wx/file.h" // for wxS_IXXX constants only -#include "wx/generic/filedlgg.h" -#include "wx/generic/dirctrlg.h" // for wxFileIconsTable - -#if wxUSE_TOOLTIPS - #include "wx/tooltip.h" -#endif - -#ifndef __WXWINCE__ - #include - #include -#endif - -#ifdef __UNIX__ - #include - #include - #ifndef __VMS - # include - #endif -#endif - -#ifdef __WINDOWS__ - #include "wx/msw/mslu.h" -#endif - -#ifdef __WATCOMC__ - #include -#endif - -#ifndef __WXWINCE__ -#include -#endif - -#if defined(__UNIX__) || defined(__DOS__) -#include -#endif - -// ---------------------------------------------------------------------------- -// private functions -// ---------------------------------------------------------------------------- - -static -int wxCALLBACK wxFileDataNameCompare( long data1, long data2, long sortOrder) -{ - wxFileData *fd1 = (wxFileData *)wxUIntToPtr(data1); - wxFileData *fd2 = (wxFileData *)wxUIntToPtr(data2); - - if (fd1->GetFileName() == wxT("..")) - return -sortOrder; - if (fd2->GetFileName() == wxT("..")) - return sortOrder; - if (fd1->IsDir() && !fd2->IsDir()) - return -sortOrder; - if (fd2->IsDir() && !fd1->IsDir()) - return sortOrder; - - return sortOrder*wxStrcmp( fd1->GetFileName(), fd2->GetFileName() ); -} - -static -int wxCALLBACK wxFileDataSizeCompare(long data1, long data2, long sortOrder) -{ - wxFileData *fd1 = (wxFileData *)wxUIntToPtr(data1); - wxFileData *fd2 = (wxFileData *)wxUIntToPtr(data2); - - if (fd1->GetFileName() == wxT("..")) - return -sortOrder; - if (fd2->GetFileName() == wxT("..")) - return sortOrder; - if (fd1->IsDir() && !fd2->IsDir()) - return -sortOrder; - if (fd2->IsDir() && !fd1->IsDir()) - return sortOrder; - if (fd1->IsLink() && !fd2->IsLink()) - return -sortOrder; - if (fd2->IsLink() && !fd1->IsLink()) - return sortOrder; - - return fd1->GetSize() > fd2->GetSize() ? sortOrder : -sortOrder; -} - -static -int wxCALLBACK wxFileDataTypeCompare(long data1, long data2, long sortOrder) -{ - wxFileData *fd1 = (wxFileData *)wxUIntToPtr(data1); - wxFileData *fd2 = (wxFileData *)wxUIntToPtr(data2); - - if (fd1->GetFileName() == wxT("..")) - return -sortOrder; - if (fd2->GetFileName() == wxT("..")) - return sortOrder; - if (fd1->IsDir() && !fd2->IsDir()) - return -sortOrder; - if (fd2->IsDir() && !fd1->IsDir()) - return sortOrder; - if (fd1->IsLink() && !fd2->IsLink()) - return -sortOrder; - if (fd2->IsLink() && !fd1->IsLink()) - return sortOrder; - - return sortOrder*wxStrcmp( fd1->GetFileType(), fd2->GetFileType() ); -} - -static -int wxCALLBACK wxFileDataTimeCompare(long data1, long data2, long sortOrder) -{ - wxFileData *fd1 = (wxFileData *)wxUIntToPtr(data1); - wxFileData *fd2 = (wxFileData *)wxUIntToPtr(data2); - - if (fd1->GetFileName() == wxT("..")) - return -sortOrder; - if (fd2->GetFileName() == wxT("..")) - return sortOrder; - if (fd1->IsDir() && !fd2->IsDir()) - return -sortOrder; - if (fd2->IsDir() && !fd1->IsDir()) - return sortOrder; - - return fd1->GetDateTime().IsLaterThan(fd2->GetDateTime()) ? sortOrder : -sortOrder; -} - -#if defined(__WXWINCE__) -#define IsTopMostDir(dir) (dir == wxT("\\") || dir == wxT("/")) -#elif (defined(__DOS__) || defined(__WINDOWS__) || defined (__OS2__)) -#define IsTopMostDir(dir) (dir.empty()) -#else -#define IsTopMostDir(dir) (dir == wxT("/")) -#endif - -// defined in src/generic/dirctrlg.cpp -extern size_t wxGetAvailableDrives(wxArrayString &paths, wxArrayString &names, wxArrayInt &icon_ids); - -//----------------------------------------------------------------------------- -// wxFileData -//----------------------------------------------------------------------------- - -wxFileData::wxFileData( const wxString &filePath, const wxString &fileName, fileType type, int image_id ) -{ - Init(); - m_fileName = fileName; - m_filePath = filePath; - m_type = type; - m_image = image_id; - - ReadData(); -} - -void wxFileData::Init() -{ - m_size = 0; - m_type = wxFileData::is_file; - m_image = wxFileIconsTable::file; -} - -void wxFileData::Copy( const wxFileData& fileData ) -{ - m_fileName = fileData.GetFileName(); - m_filePath = fileData.GetFilePath(); - m_size = fileData.GetSize(); - m_dateTime = fileData.GetDateTime(); - m_permissions = fileData.GetPermissions(); - m_type = fileData.GetType(); - m_image = fileData.GetImageId(); -} - -void wxFileData::ReadData() -{ - if (IsDrive()) - { - m_size = 0; - return; - } - -#if defined(__DOS__) || (defined(__WINDOWS__) && !defined(__WXWINCE__)) || defined(__OS2__) - // c:\.. is a drive don't stat it - if ((m_fileName == wxT("..")) && (m_filePath.length() <= 5)) - { - m_type = is_drive; - m_size = 0; - return; - } -#endif // __DOS__ || __WINDOWS__ - -#ifdef __WXWINCE__ - - // WinCE - - DWORD fileAttribs = GetFileAttributes(m_filePath.fn_str()); - m_type |= (fileAttribs & FILE_ATTRIBUTE_DIRECTORY) != 0 ? is_dir : 0; - - wxString p, f, ext; - wxSplitPath(m_filePath, & p, & f, & ext); - if (wxStricmp(ext, wxT("exe")) == 0) - m_type |= is_exe; - - // Find out size - m_size = 0; - HANDLE fileHandle = CreateFile(m_filePath.fn_str(), - GENERIC_READ, - FILE_SHARE_READ, - NULL, - OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL, - NULL); - - if (fileHandle != INVALID_HANDLE_VALUE) - { - m_size = GetFileSize(fileHandle, 0); - CloseHandle(fileHandle); - } - - m_dateTime = wxFileModificationTime(m_filePath); - -#else - - // OTHER PLATFORMS - - wxStructStat buff; - -#if defined(__UNIX__) && (!defined( __OS2__ ) && !defined(__VMS)) - lstat( m_filePath.fn_str(), &buff ); - m_type |= S_ISLNK( buff.st_mode ) != 0 ? is_link : 0; -#else // no lstat() - // only translate to file charset if we don't go by our - // wxStat implementation -#ifndef wxNEED_WX_UNISTD_H - wxStat( m_filePath.fn_str() , &buff ); -#else - wxStat( m_filePath, &buff ); -#endif -#endif - - m_type |= (buff.st_mode & S_IFDIR) != 0 ? is_dir : 0; - m_type |= (buff.st_mode & wxS_IXUSR) != 0 ? is_exe : 0; - - m_size = buff.st_size; - - m_dateTime = buff.st_mtime; -#endif - // __WXWINCE__ - -#if defined(__UNIX__) - m_permissions.Printf(_T("%c%c%c%c%c%c%c%c%c"), - buff.st_mode & wxS_IRUSR ? _T('r') : _T('-'), - buff.st_mode & wxS_IWUSR ? _T('w') : _T('-'), - buff.st_mode & wxS_IXUSR ? _T('x') : _T('-'), - buff.st_mode & wxS_IRGRP ? _T('r') : _T('-'), - buff.st_mode & wxS_IWGRP ? _T('w') : _T('-'), - buff.st_mode & wxS_IXGRP ? _T('x') : _T('-'), - buff.st_mode & wxS_IROTH ? _T('r') : _T('-'), - buff.st_mode & wxS_IWOTH ? _T('w') : _T('-'), - buff.st_mode & wxS_IXOTH ? _T('x') : _T('-')); -#elif defined(__WIN32__) - DWORD attribs = ::GetFileAttributes(m_filePath.c_str()); - if (attribs != (DWORD)-1) - { - m_permissions.Printf(_T("%c%c%c%c"), - attribs & FILE_ATTRIBUTE_ARCHIVE ? _T('A') : _T(' '), - attribs & FILE_ATTRIBUTE_READONLY ? _T('R') : _T(' '), - attribs & FILE_ATTRIBUTE_HIDDEN ? _T('H') : _T(' '), - attribs & FILE_ATTRIBUTE_SYSTEM ? _T('S') : _T(' ')); - } -#endif - - // try to get a better icon - if (m_image == wxFileIconsTable::file) - { - if (m_fileName.Find(wxT('.'), true) != wxNOT_FOUND) - { - m_image = wxTheFileIconsTable->GetIconID( m_fileName.AfterLast(wxT('.'))); - } else if (IsExe()) - { - m_image = wxFileIconsTable::executable; - } - } -} - -wxString wxFileData::GetFileType() const -{ - if (IsDir()) - return _(""); - else if (IsLink()) - return _(""); - else if (IsDrive()) - return _(""); - else if (m_fileName.Find(wxT('.'), true) != wxNOT_FOUND) - return m_fileName.AfterLast(wxT('.')); - - return wxEmptyString; -} - -wxString wxFileData::GetModificationTime() const -{ - // want time as 01:02 so they line up nicely, no %r in WIN32 - return m_dateTime.FormatDate() + wxT(" ") + m_dateTime.Format(wxT("%I:%M:%S %p")); -} - -wxString wxFileData::GetHint() const -{ - wxString s = m_filePath; - s += wxT(" "); - - if (IsDir()) - s += _(""); - else if (IsLink()) - s += _(""); - else if (IsDrive()) - s += _(""); - else // plain file - s += wxString::Format(wxPLURAL("%ld byte", "%ld bytes", m_size), - wxLongLong(m_size).ToString().c_str()); - - s += wxT(' '); - - if ( !IsDrive() ) - { - s << GetModificationTime() - << wxT(" ") - << m_permissions; - } - - return s; -} - -wxString wxFileData::GetEntry( fileListFieldType num ) const -{ - wxString s; - switch ( num ) - { - case FileList_Name: - s = m_fileName; - break; - - case FileList_Size: - if (!IsDir() && !IsLink() && !IsDrive()) - s = wxLongLong(m_size).ToString(); - break; - - case FileList_Type: - s = GetFileType(); - break; - - case FileList_Time: - if (!IsDrive()) - s = GetModificationTime(); - break; - -#if defined(__UNIX__) || defined(__WIN32__) - case FileList_Perm: - s = m_permissions; - break; -#endif // defined(__UNIX__) || defined(__WIN32__) - - default: - wxFAIL_MSG( _T("unexpected field in wxFileData::GetEntry()") ); - } - - return s; -} - -void wxFileData::SetNewName( const wxString &filePath, const wxString &fileName ) -{ - m_fileName = fileName; - m_filePath = filePath; -} - -void wxFileData::MakeItem( wxListItem &item ) -{ - item.m_text = m_fileName; - item.ClearAttributes(); - if (IsExe()) - item.SetTextColour(*wxRED); - if (IsDir()) - item.SetTextColour(*wxBLUE); - - item.m_image = m_image; - - if (IsLink()) - { - wxColour dg = wxTheColourDatabase->Find( _T("MEDIUM GREY") ); - if ( dg.Ok() ) - item.SetTextColour(dg); - } - item.m_data = wxPtrToUInt(this); -} - -//----------------------------------------------------------------------------- -// wxFileCtrl -//----------------------------------------------------------------------------- - -static bool ignoreChanges = false; - -IMPLEMENT_DYNAMIC_CLASS(wxFileCtrl,wxListCtrl) - -BEGIN_EVENT_TABLE(wxFileCtrl,wxListCtrl) - EVT_LIST_DELETE_ITEM(wxID_ANY, wxFileCtrl::OnListDeleteItem) - EVT_LIST_DELETE_ALL_ITEMS(wxID_ANY, wxFileCtrl::OnListDeleteAllItems) - EVT_LIST_END_LABEL_EDIT(wxID_ANY, wxFileCtrl::OnListEndLabelEdit) - EVT_LIST_COL_CLICK(wxID_ANY, wxFileCtrl::OnListColClick) -END_EVENT_TABLE() - - -wxFileCtrl::wxFileCtrl() -{ - m_showHidden = false; - m_sort_foward = 1; - m_sort_field = wxFileData::FileList_Name; -} - -wxFileCtrl::wxFileCtrl(wxWindow *win, - wxWindowID id, - const wxString& wild, - bool showHidden, - const wxPoint& pos, - const wxSize& size, - long style, - const wxValidator &validator, - const wxString &name) - : wxListCtrl(win, id, pos, size, style, validator, name), - m_wild(wild) -{ - wxImageList *imageList = wxTheFileIconsTable->GetSmallImageList(); - - SetImageList( imageList, wxIMAGE_LIST_SMALL ); - - m_showHidden = showHidden; - - m_sort_foward = 1; - m_sort_field = wxFileData::FileList_Name; - - m_dirName = wxT("*"); - - if (style & wxLC_REPORT) - ChangeToReportMode(); -} - -void wxFileCtrl::ChangeToListMode() -{ - ClearAll(); - SetSingleStyle( wxLC_LIST ); - UpdateFiles(); -} - -void wxFileCtrl::ChangeToReportMode() -{ - ClearAll(); - SetSingleStyle( wxLC_REPORT ); - - // do this since WIN32 does mm/dd/yy UNIX does mm/dd/yyyy - // don't hardcode since mm/dd is dd/mm elsewhere - int w, h; - wxDateTime dt(22, wxDateTime::Dec, 2002, 22, 22, 22); - wxString txt = dt.FormatDate() + wxT("22") + dt.Format(wxT("%I:%M:%S %p")); - GetTextExtent(txt, &w, &h); - - InsertColumn( 0, _("Name"), wxLIST_FORMAT_LEFT, w ); - InsertColumn( 1, _("Size"), wxLIST_FORMAT_LEFT, w/2 ); - InsertColumn( 2, _("Type"), wxLIST_FORMAT_LEFT, w/2 ); - InsertColumn( 3, _("Modified"), wxLIST_FORMAT_LEFT, w ); -#if defined(__UNIX__) - GetTextExtent(wxT("Permissions 2"), &w, &h); - InsertColumn( 4, _("Permissions"), wxLIST_FORMAT_LEFT, w ); -#elif defined(__WIN32__) - GetTextExtent(wxT("Attributes 2"), &w, &h); - InsertColumn( 4, _("Attributes"), wxLIST_FORMAT_LEFT, w ); -#endif - - UpdateFiles(); -} - -void wxFileCtrl::ChangeToSmallIconMode() -{ - ClearAll(); - SetSingleStyle( wxLC_SMALL_ICON ); - UpdateFiles(); -} - -void wxFileCtrl::ShowHidden( bool show ) -{ - m_showHidden = show; - UpdateFiles(); -} - -long wxFileCtrl::Add( wxFileData *fd, wxListItem &item ) -{ - long ret = -1; - item.m_mask = wxLIST_MASK_TEXT + wxLIST_MASK_DATA + wxLIST_MASK_IMAGE; - fd->MakeItem( item ); - long my_style = GetWindowStyleFlag(); - if (my_style & wxLC_REPORT) - { - ret = InsertItem( item ); - for (int i = 1; i < wxFileData::FileList_Max; i++) - SetItem( item.m_itemId, i, fd->GetEntry((wxFileData::fileListFieldType)i) ); - } - else if ((my_style & wxLC_LIST) || (my_style & wxLC_SMALL_ICON)) - { - ret = InsertItem( item ); - } - return ret; -} - -void wxFileCtrl::UpdateItem(const wxListItem &item) -{ - wxFileData *fd = (wxFileData*)GetItemData(item); - wxCHECK_RET(fd, wxT("invalid filedata")); - - fd->ReadData(); - - SetItemText(item, fd->GetFileName()); - SetItemImage(item, fd->GetImageId()); - - if (GetWindowStyleFlag() & wxLC_REPORT) - { - for (int i = 1; i < wxFileData::FileList_Max; i++) - SetItem( item.m_itemId, i, fd->GetEntry((wxFileData::fileListFieldType)i) ); - } -} - -void wxFileCtrl::UpdateFiles() -{ - // don't do anything before ShowModal() call which sets m_dirName - if ( m_dirName == wxT("*") ) - return; - - wxBusyCursor bcur; // this may take a while... - - DeleteAllItems(); - - wxListItem item; - item.m_itemId = 0; - item.m_col = 0; - -#if (defined(__WINDOWS__) || defined(__DOS__) || defined(__WXMAC__) || defined(__OS2__)) && !defined(__WXWINCE__) - if ( IsTopMostDir(m_dirName) ) - { - wxArrayString names, paths; - wxArrayInt icons; - size_t n, count = wxGetAvailableDrives(paths, names, icons); - - for (n=0; nGetFilePath() ) ); - new_name += wxFILE_SEP_PATH; - new_name += event.GetLabel(); - - wxLogNull log; - - if (wxFileExists(new_name)) - { - wxMessageDialog dialog(this, _("File name exists already."), _("Error"), wxOK | wxICON_ERROR ); - dialog.ShowModal(); - event.Veto(); - } - - if (wxRenameFile(fd->GetFilePath(),new_name)) - { - fd->SetNewName( new_name, event.GetLabel() ); - - ignoreChanges = true; - SetItemState( event.GetItem(), wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED ); - ignoreChanges = false; - - UpdateItem( event.GetItem() ); - EnsureVisible( event.GetItem() ); - } - else - { - wxMessageDialog dialog(this, _("Operation not permitted."), _("Error"), wxOK | wxICON_ERROR ); - dialog.ShowModal(); - event.Veto(); - } -} - -void wxFileCtrl::OnListColClick( wxListEvent &event ) -{ - int col = event.GetColumn(); - - switch (col) - { - case wxFileData::FileList_Name : - case wxFileData::FileList_Size : - case wxFileData::FileList_Type : - case wxFileData::FileList_Time : break; - default : return; - } - - if ((wxFileData::fileListFieldType)col == m_sort_field) - m_sort_foward = !m_sort_foward; - else - m_sort_field = (wxFileData::fileListFieldType)col; - - SortItems(m_sort_field, m_sort_foward); -} - -void wxFileCtrl::SortItems(wxFileData::fileListFieldType field, bool forward) -{ - m_sort_field = field; - m_sort_foward = forward; - const long sort_dir = forward ? 1 : -1; - - switch (m_sort_field) - { - case wxFileData::FileList_Size : - wxListCtrl::SortItems(wxFileDataSizeCompare, sort_dir); - break; - - case wxFileData::FileList_Type : - wxListCtrl::SortItems(wxFileDataTypeCompare, sort_dir); - break; - - case wxFileData::FileList_Time : - wxListCtrl::SortItems(wxFileDataTimeCompare, sort_dir); - break; - - case wxFileData::FileList_Name : - default : - wxListCtrl::SortItems(wxFileDataNameCompare, sort_dir); - break; - } -} - -wxFileCtrl::~wxFileCtrl() -{ - // Normally the data are freed via an EVT_LIST_DELETE_ALL_ITEMS event and - // wxFileCtrl::OnListDeleteAllItems. But if the event is generated after - // the destruction of the wxFileCtrl we need to free any data here: - FreeAllItemsData(); -} - -//----------------------------------------------------------------------------- -// wxGenericFileDialog -//----------------------------------------------------------------------------- - -#define ID_LIST_MODE (wxID_FILEDLGG ) -#define ID_REPORT_MODE (wxID_FILEDLGG + 1) -#define ID_UP_DIR (wxID_FILEDLGG + 5) -#define ID_PARENT_DIR (wxID_FILEDLGG + 6) -#define ID_NEW_DIR (wxID_FILEDLGG + 7) -#define ID_CHOICE (wxID_FILEDLGG + 8) -#define ID_TEXT (wxID_FILEDLGG + 9) -#define ID_LIST_CTRL (wxID_FILEDLGG + 10) -#define ID_CHECK (wxID_FILEDLGG + 12) - -IMPLEMENT_DYNAMIC_CLASS(wxGenericFileDialog, wxFileDialogBase) - -BEGIN_EVENT_TABLE(wxGenericFileDialog,wxDialog) - EVT_BUTTON(ID_LIST_MODE, wxGenericFileDialog::OnList) - EVT_BUTTON(ID_REPORT_MODE, wxGenericFileDialog::OnReport) - EVT_BUTTON(ID_UP_DIR, wxGenericFileDialog::OnUp) - EVT_BUTTON(ID_PARENT_DIR, wxGenericFileDialog::OnHome) - EVT_BUTTON(ID_NEW_DIR, wxGenericFileDialog::OnNew) - EVT_BUTTON(wxID_OK, wxGenericFileDialog::OnListOk) - EVT_LIST_ITEM_SELECTED(ID_LIST_CTRL, wxGenericFileDialog::OnSelected) - EVT_LIST_ITEM_ACTIVATED(ID_LIST_CTRL, wxGenericFileDialog::OnActivated) - EVT_CHOICE(ID_CHOICE,wxGenericFileDialog::OnChoiceFilter) - EVT_TEXT_ENTER(ID_TEXT,wxGenericFileDialog::OnTextEnter) - EVT_TEXT(ID_TEXT,wxGenericFileDialog::OnTextChange) - EVT_CHECKBOX(ID_CHECK,wxGenericFileDialog::OnCheck) -END_EVENT_TABLE() - -long wxGenericFileDialog::ms_lastViewStyle = wxLC_LIST; -bool wxGenericFileDialog::ms_lastShowHidden = false; - -void wxGenericFileDialog::Init() -{ - m_bypassGenericImpl = false; - - m_choice = NULL; - m_text = NULL; - m_list = NULL; - m_check = NULL; - m_static = NULL; - m_upDirButton = NULL; - m_newDirButton = NULL; -} - -wxGenericFileDialog::wxGenericFileDialog(wxWindow *parent, - const wxString& message, - const wxString& defaultDir, - const wxString& defaultFile, - const wxString& wildCard, - long style, - const wxPoint& pos, - const wxSize& sz, - const wxString& name, - bool bypassGenericImpl ) : wxFileDialogBase() -{ - Init(); - Create( parent, message, defaultDir, defaultFile, wildCard, style, pos, sz, name, bypassGenericImpl ); -} - -bool wxGenericFileDialog::Create( wxWindow *parent, - const wxString& message, - const wxString& defaultDir, - const wxString& defaultFile, - const wxString& wildCard, - long style, - const wxPoint& pos, - const wxSize& sz, - const wxString& name, - bool bypassGenericImpl ) -{ - m_bypassGenericImpl = bypassGenericImpl; - - if (!wxFileDialogBase::Create(parent, message, defaultDir, defaultFile, - wildCard, style, pos, sz, name)) - { - return false; - } - - if (m_bypassGenericImpl) - return true; - - if (!wxDialog::Create( parent, wxID_ANY, message, pos, sz, - wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER | style, name - )) - { - return false; - } - - ignoreChanges = true; - -#if wxUSE_CONFIG - if (wxConfig::Get(false)) - { - wxConfig::Get()->Read(wxT("/wxWindows/wxFileDialog/ViewStyle"), - &ms_lastViewStyle); - wxConfig::Get()->Read(wxT("/wxWindows/wxFileDialog/ShowHidden"), - &ms_lastShowHidden); - } -#endif - - if ((m_dir.empty()) || (m_dir == wxT("."))) - { - m_dir = wxGetCwd(); - if (m_dir.empty()) - m_dir = wxFILE_SEP_PATH; - } - - size_t len = m_dir.length(); - if ((len > 1) && (wxEndsWithPathSeparator(m_dir))) - m_dir.Remove( len-1, 1 ); - - m_path = m_dir; - m_path += wxFILE_SEP_PATH; - m_path += defaultFile; - m_filterExtension = wxEmptyString; - - // layout - - bool is_pda = (wxSystemSettings::GetScreenType() <= wxSYS_SCREEN_PDA); - - wxBoxSizer *mainsizer = new wxBoxSizer( wxVERTICAL ); - - wxBoxSizer *buttonsizer = new wxBoxSizer( wxHORIZONTAL ); - - wxBitmapButton *but; - - but = new wxBitmapButton(this, ID_LIST_MODE, - wxArtProvider::GetBitmap(wxART_LIST_VIEW, wxART_BUTTON)); -#if wxUSE_TOOLTIPS - but->SetToolTip( _("View files as a list view") ); -#endif - buttonsizer->Add( but, 0, wxALL, 5 ); - - but = new wxBitmapButton(this, ID_REPORT_MODE, - wxArtProvider::GetBitmap(wxART_REPORT_VIEW, wxART_BUTTON)); -#if wxUSE_TOOLTIPS - but->SetToolTip( _("View files as a detailed view") ); -#endif - buttonsizer->Add( but, 0, wxALL, 5 ); - - buttonsizer->Add( 30, 5, 1 ); - - m_upDirButton = new wxBitmapButton(this, ID_UP_DIR, - wxArtProvider::GetBitmap(wxART_GO_DIR_UP, wxART_BUTTON)); -#if wxUSE_TOOLTIPS - m_upDirButton->SetToolTip( _("Go to parent directory") ); -#endif - buttonsizer->Add( m_upDirButton, 0, wxALL, 5 ); - -#ifndef __DOS__ // VS: Home directory is meaningless in MS-DOS... - but = new wxBitmapButton(this, ID_PARENT_DIR, - wxArtProvider::GetBitmap(wxART_GO_HOME, wxART_BUTTON)); -#if wxUSE_TOOLTIPS - but->SetToolTip( _("Go to home directory") ); -#endif - buttonsizer->Add( but, 0, wxALL, 5); - - buttonsizer->Add( 20, 20 ); -#endif //!__DOS__ - - m_newDirButton = new wxBitmapButton(this, ID_NEW_DIR, - wxArtProvider::GetBitmap(wxART_NEW_DIR, wxART_BUTTON)); -#if wxUSE_TOOLTIPS - m_newDirButton->SetToolTip( _("Create new directory") ); -#endif - buttonsizer->Add( m_newDirButton, 0, wxALL, 5 ); - - if (is_pda) - mainsizer->Add( buttonsizer, 0, wxALL | wxEXPAND, 0 ); - else - mainsizer->Add( buttonsizer, 0, wxALL | wxEXPAND, 5 ); - - wxBoxSizer *staticsizer = new wxBoxSizer( wxHORIZONTAL ); - if (is_pda) - staticsizer->Add( new wxStaticText( this, wxID_ANY, _("Current directory:") ), 0, wxRIGHT, 10 ); - m_static = new wxStaticText( this, wxID_ANY, m_dir ); - staticsizer->Add( m_static, 1 ); - mainsizer->Add( staticsizer, 0, wxEXPAND | wxLEFT|wxRIGHT|wxBOTTOM, 10 ); - - long style2 = ms_lastViewStyle; - if ( !HasFdFlag(wxFD_MULTIPLE) ) - style2 |= wxLC_SINGLE_SEL; - -#ifdef __WXWINCE__ - style2 |= wxSIMPLE_BORDER; -#else - style2 |= wxSUNKEN_BORDER; -#endif - - m_list = new wxFileCtrl( this, ID_LIST_CTRL, - wxEmptyString, ms_lastShowHidden, - wxDefaultPosition, wxSize(540,200), - style2); - - m_text = new wxTextCtrl(this, ID_TEXT, m_fileName, - wxDefaultPosition, wxDefaultSize, - wxTE_PROCESS_ENTER); - m_choice = new wxChoice(this, ID_CHOICE); - - if (is_pda) - { - // PDAs have a different screen layout - mainsizer->Add(m_list, wxSizerFlags(1).Expand().HorzBorder()); - - wxBoxSizer *textsizer = new wxBoxSizer(wxHORIZONTAL); - textsizer->Add(m_text, wxSizerFlags(1).Centre().Border()); - mainsizer->Add(textsizer, wxSizerFlags().Expand()); - - m_check = NULL; - textsizer->Add(m_choice, wxSizerFlags(1).Centre().Border()); - - wxSizer *bsizer = CreateButtonSizer(wxOK | wxCANCEL); - if ( bsizer ) - mainsizer->Add(bsizer, wxSizerFlags().Expand().Border()); - } - else // !is_pda - { - mainsizer->Add(m_list, wxSizerFlags(1).Expand().DoubleHorzBorder()); - - wxBoxSizer *textsizer = new wxBoxSizer(wxHORIZONTAL); - textsizer->Add(m_text, wxSizerFlags(1).Centre(). - DoubleBorder(wxLEFT | wxRIGHT | wxTOP)); - textsizer->Add(new wxButton(this, wxID_OK), wxSizerFlags().Centre(). - DoubleBorder(wxLEFT | wxRIGHT | wxTOP)); - mainsizer->Add(textsizer, wxSizerFlags().Expand()); - - wxSizerFlags flagsCentre; - flagsCentre.Centre().DoubleBorder(); - - wxBoxSizer *choicesizer = new wxBoxSizer(wxHORIZONTAL); - choicesizer->Add(m_choice, wxSizerFlags(flagsCentre).Proportion(1)); - - m_check = new wxCheckBox(this, ID_CHECK, _("Show &hidden files")); - m_check->SetValue(ms_lastShowHidden); - - choicesizer->Add(m_check, flagsCentre); - choicesizer->Add(new wxButton(this, wxID_CANCEL), flagsCentre); - mainsizer->Add(choicesizer, wxSizerFlags().Expand()); - } - - SetWildcard(wildCard); - - SetAutoLayout( true ); - SetSizer( mainsizer ); - - if (!is_pda) - { - mainsizer->Fit( this ); - mainsizer->SetSizeHints( this ); - - Centre( wxBOTH ); - } - - m_text->SetFocus(); - - ignoreChanges = false; - - return true; -} - -wxGenericFileDialog::~wxGenericFileDialog() -{ - ignoreChanges = true; - - if (!m_bypassGenericImpl) - { -#if wxUSE_CONFIG - if (wxConfig::Get(false)) - { - wxConfig::Get()->Write(wxT("/wxWindows/wxFileDialog/ViewStyle"), - ms_lastViewStyle); - wxConfig::Get()->Write(wxT("/wxWindows/wxFileDialog/ShowHidden"), - ms_lastShowHidden); - } -#endif - - const int count = m_choice->GetCount(); - for ( int i = 0; i < count; i++ ) - { - delete (wxString *)m_choice->GetClientData(i); - } - } -} - -int wxGenericFileDialog::ShowModal() -{ - ignoreChanges = true; - - m_list->GoToDir(m_dir); - UpdateControls(); - m_text->SetValue(m_fileName); - - ignoreChanges = false; - - return wxDialog::ShowModal(); -} - -bool wxGenericFileDialog::Show( bool show ) -{ - // Called by ShowModal, so don't repeate the update -#ifndef __WIN32__ - if (show) - { - m_list->GoToDir(m_dir); - UpdateControls(); - m_text->SetValue(m_fileName); - } -#endif - - return wxDialog::Show( show ); -} - -void wxGenericFileDialog::DoSetFilterIndex(int filterindex) -{ - wxString *str = (wxString*) m_choice->GetClientData( filterindex ); - m_list->SetWild( *str ); - m_filterIndex = filterindex; - if ( str->Left(2) == wxT("*.") ) - { - m_filterExtension = str->Mid(1); - if (m_filterExtension == _T(".*")) - m_filterExtension.clear(); - } - else - { - m_filterExtension.clear(); - } -} - -void wxGenericFileDialog::SetWildcard(const wxString& wildCard) -{ - wxFileDialogBase::SetWildcard(wildCard); - - wxArrayString wildDescriptions, wildFilters; - const size_t count = wxParseCommonDialogsFilter(m_wildCard, - wildDescriptions, - wildFilters); - wxCHECK_RET( count, wxT("wxFileDialog: bad wildcard string") ); - - const size_t countOld = m_choice->GetCount(); - size_t n; - for ( n = 0; n < countOld; n++ ) - { - delete (wxString *)m_choice->GetClientData(n); - } - - for ( n = 0; n < count; n++ ) - { - m_choice->Append( wildDescriptions[n], new wxString( wildFilters[n] ) ); - } - - SetFilterIndex( 0 ); -} - -void wxGenericFileDialog::SetFilterIndex( int filterindex ) -{ - m_choice->SetSelection( filterindex ); - - DoSetFilterIndex(filterindex); -} - -void wxGenericFileDialog::OnChoiceFilter( wxCommandEvent &event ) -{ - DoSetFilterIndex((int)event.GetInt()); -} - -void wxGenericFileDialog::OnCheck( wxCommandEvent &event ) -{ - m_list->ShowHidden( (ms_lastShowHidden = event.GetInt() != 0) ); -} - -void wxGenericFileDialog::OnActivated( wxListEvent &event ) -{ - HandleAction( event.m_item.m_text ); -} - -void wxGenericFileDialog::OnTextEnter( wxCommandEvent &WXUNUSED(event) ) -{ - HandleAction( m_text->GetValue() ); -} - -void wxGenericFileDialog::OnTextChange( wxCommandEvent &WXUNUSED(event) ) -{ - if (!ignoreChanges) - { - // Clear selections. Otherwise when the user types in a value they may - // not get the file whose name they typed. - if (m_list->GetSelectedItemCount() > 0) - { - long item = m_list->GetNextItem(-1, wxLIST_NEXT_ALL, - wxLIST_STATE_SELECTED); - while ( item != -1 ) - { - m_list->SetItemState(item,0, wxLIST_STATE_SELECTED); - item = m_list->GetNextItem(item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED); - } - } - } -} - -void wxGenericFileDialog::OnSelected( wxListEvent &event ) -{ - static bool inSelected = false; - - if (inSelected) - return; - - inSelected = true; - wxString filename( event.m_item.m_text ); - -#ifdef __WXWINCE__ - // No double-click on most WinCE devices, so do action immediately. - HandleAction( filename ); -#else - if (filename == wxT("..")) - { - inSelected = false; - return; - } - - wxString dir = m_list->GetDir(); - if (!IsTopMostDir(dir)) - dir += wxFILE_SEP_PATH; - dir += filename; - if (wxDirExists(dir)) - { - inSelected = false; - return; - } - - ignoreChanges = true; - m_text->SetValue( filename ); - ignoreChanges = false; -#endif - inSelected = false; -} - -void wxGenericFileDialog::HandleAction( const wxString &fn ) -{ - if (ignoreChanges) - return; - - wxString filename( fn ); - if (filename.empty()) - { -#ifdef __WXWINCE__ - EndModal(wxID_CANCEL); -#endif - return; - } - if (filename == wxT(".")) return; - - wxString dir = m_list->GetDir(); - - // "some/place/" means they want to chdir not try to load "place" - bool want_dir = filename.Last() == wxFILE_SEP_PATH; - if (want_dir) - filename = filename.RemoveLast(); - - if (filename == wxT("..")) - { - ignoreChanges = true; - m_list->GoToParentDir(); - m_list->SetFocus(); - UpdateControls(); - ignoreChanges = false; - return; - } - -#ifdef __UNIX__ - if (filename == wxT("~")) - { - ignoreChanges = true; - m_list->GoToHomeDir(); - m_list->SetFocus(); - UpdateControls(); - ignoreChanges = false; - return; - } - - if (filename.BeforeFirst(wxT('/')) == wxT("~")) - { - filename = wxString(wxGetUserHome()) + filename.Remove(0, 1); - } -#endif // __UNIX__ - - if (!HasFdFlag(wxFD_SAVE)) - { - if ((filename.Find(wxT('*')) != wxNOT_FOUND) || - (filename.Find(wxT('?')) != wxNOT_FOUND)) - { - if (filename.Find(wxFILE_SEP_PATH) != wxNOT_FOUND) - { - wxMessageBox(_("Illegal file specification."), _("Error"), wxOK | wxICON_ERROR ); - return; - } - m_list->SetWild( filename ); - return; - } - } - - if (!IsTopMostDir(dir)) - dir += wxFILE_SEP_PATH; - if (!wxIsAbsolutePath(filename)) - { - dir += filename; - filename = dir; - } - - if (wxDirExists(filename)) - { - ignoreChanges = true; - m_list->GoToDir( filename ); - UpdateControls(); - ignoreChanges = false; - return; - } - - // they really wanted a dir, but it doesn't exist - if (want_dir) - { - wxMessageBox(_("Directory doesn't exist."), _("Error"), - wxOK | wxICON_ERROR ); - return; - } - - // append the default extension to the filename if it doesn't have any - // - // VZ: the logic of testing for !wxFileExists() only for the open file - // dialog is not entirely clear to me, why don't we allow saving to a - // file without extension as well? - if ( !HasFdFlag(wxFD_OPEN) || !wxFileExists(filename) ) - { - filename = AppendExtension(filename, m_filterExtension); - } - - // check that the file [doesn't] exist if necessary - if ( HasFdFlag(wxFD_SAVE) && HasFdFlag(wxFD_OVERWRITE_PROMPT) && - wxFileExists( filename ) ) - { - wxString msg; - msg.Printf( _("File '%s' already exists, do you really want to overwrite it?"), filename.c_str() ); - - if (wxMessageBox(msg, _("Confirm"), wxYES_NO) != wxYES) - return; - } - else if ( HasFdFlag(wxFD_OPEN) && HasFdFlag(wxFD_FILE_MUST_EXIST) && - !wxFileExists(filename) ) - { - wxMessageBox(_("Please choose an existing file."), _("Error"), - wxOK | wxICON_ERROR ); - return; - } - - SetPath( filename ); - - // change to the directory where the user went if asked - if ( HasFdFlag(wxFD_CHANGE_DIR) ) - { - wxString cwd; - wxSplitPath(filename, &cwd, NULL, NULL); - - if ( cwd != wxGetCwd() ) - { - wxSetWorkingDirectory(cwd); - } - } - - EndModal(wxID_OK); -} - -void wxGenericFileDialog::OnListOk( wxCommandEvent &WXUNUSED(event) ) -{ - HandleAction( m_text->GetValue() ); -} - -void wxGenericFileDialog::OnList( wxCommandEvent &WXUNUSED(event) ) -{ - ignoreChanges = true; - m_list->ChangeToListMode(); - ms_lastViewStyle = wxLC_LIST; - m_list->SetFocus(); - ignoreChanges = false; -} - -void wxGenericFileDialog::OnReport( wxCommandEvent &WXUNUSED(event) ) -{ - ignoreChanges = true; - m_list->ChangeToReportMode(); - ms_lastViewStyle = wxLC_REPORT; - m_list->SetFocus(); - ignoreChanges = false; -} - -void wxGenericFileDialog::OnUp( wxCommandEvent &WXUNUSED(event) ) -{ - ignoreChanges = true; - m_list->GoToParentDir(); - m_list->SetFocus(); - UpdateControls(); - ignoreChanges = false; -} - -void wxGenericFileDialog::OnHome( wxCommandEvent &WXUNUSED(event) ) -{ - ignoreChanges = true; - m_list->GoToHomeDir(); - m_list->SetFocus(); - UpdateControls(); - ignoreChanges = false; -} - -void wxGenericFileDialog::OnNew( wxCommandEvent &WXUNUSED(event) ) -{ - ignoreChanges = true; - - m_list->MakeDir(); - - ignoreChanges = false; -} - -void wxGenericFileDialog::SetPath( const wxString& path ) -{ - // not only set the full path but also update filename and dir - m_path = path; - -#ifdef __WXWINCE__ - if (m_path.empty()) - m_path = wxFILE_SEP_PATH; -#endif - - if ( !path.empty() ) - { - wxString ext; - wxSplitPath(path, &m_dir, &m_fileName, &ext); - if (!ext.empty()) - { - m_fileName += wxT("."); - m_fileName += ext; - } - } -} - -void wxGenericFileDialog::GetPaths( wxArrayString& paths ) const -{ - paths.Empty(); - if (m_list->GetSelectedItemCount() == 0) - { - paths.Add( GetPath() ); - return; - } - - paths.Alloc( m_list->GetSelectedItemCount() ); - - wxString dir = m_list->GetDir(); -#ifdef __UNIX__ - if (dir != wxT("/")) -#endif -#ifdef __WXWINCE__ - if (dir != wxT("/") && dir != wxT("\\")) -#endif - dir += wxFILE_SEP_PATH; - - wxListItem item; - item.m_mask = wxLIST_MASK_TEXT; - - item.m_itemId = m_list->GetNextItem( -1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED ); - while ( item.m_itemId != -1 ) - { - m_list->GetItem( item ); - paths.Add( dir + item.m_text ); - item.m_itemId = m_list->GetNextItem( item.m_itemId, - wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED ); - } -} - -void wxGenericFileDialog::GetFilenames(wxArrayString& files) const -{ - files.Empty(); - if (m_list->GetSelectedItemCount() == 0) - { - files.Add( GetFilename() ); - return; - } - files.Alloc( m_list->GetSelectedItemCount() ); - - wxListItem item; - item.m_mask = wxLIST_MASK_TEXT; - - item.m_itemId = m_list->GetNextItem( -1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED ); - while ( item.m_itemId != -1 ) - { - m_list->GetItem( item ); - files.Add( item.m_text ); - item.m_itemId = m_list->GetNextItem( item.m_itemId, - wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED ); - } -} - -void wxGenericFileDialog::UpdateControls() -{ - wxString dir = m_list->GetDir(); - m_static->SetLabel(dir); - - bool enable = !IsTopMostDir(dir); - m_upDirButton->Enable(enable); - -#if defined(__DOS__) || defined(__WINDOWS__) || defined(__OS2__) - m_newDirButton->Enable(enable); -#endif // defined(__DOS__) || defined(__WINDOWS__) || defined(__OS2__) -} - -#ifdef wxUSE_GENERIC_FILEDIALOG - -IMPLEMENT_DYNAMIC_CLASS(wxFileDialog, wxGenericFileDialog) - -#endif // wxUSE_GENERIC_FILEDIALOG - -#endif // wxUSE_FILEDLG +////////////////////////////////////////////////////////////////////////////// +// Name: src/generic/filedlgg.cpp +// Purpose: wxGenericFileDialog +// Author: Robert Roebling +// Modified by: +// Created: 12/12/98 +// RCS-ID: $Id: filedlgg.cpp 45836 2007-05-05 17:13:30Z PC $ +// Copyright: (c) Robert Roebling +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_FILEDLG + +// NOTE : it probably also supports MAC, untested +#if !defined(__UNIX__) && !defined(__DOS__) && !defined(__WIN32__) && !defined(__OS2__) +#error wxGenericFileDialog currently only supports Unix, win32 and DOS +#endif + +#ifndef WX_PRECOMP + #ifdef __WXMSW__ + #include "wx/msw/wrapwin.h" + #endif + #include "wx/hash.h" + #include "wx/intl.h" + #include "wx/settings.h" + #include "wx/log.h" + #include "wx/msgdlg.h" + #include "wx/bmpbuttn.h" + #include "wx/checkbox.h" + #include "wx/choice.h" + #include "wx/stattext.h" + #include "wx/textctrl.h" + #include "wx/sizer.h" + #include "wx/filedlg.h" // wxFD_OPEN, wxFD_SAVE... +#endif + +#include "wx/longlong.h" +#include "wx/tokenzr.h" +#include "wx/config.h" +#include "wx/imaglist.h" +#include "wx/dir.h" +#include "wx/artprov.h" +#include "wx/filefn.h" +#include "wx/file.h" // for wxS_IXXX constants only +#include "wx/generic/filedlgg.h" +#include "wx/generic/dirctrlg.h" // for wxFileIconsTable + +#if wxUSE_TOOLTIPS + #include "wx/tooltip.h" +#endif + +#ifndef __WXWINCE__ + #include + #include +#endif + +#ifdef __UNIX__ + #include + #include + #ifndef __VMS + # include + #endif +#endif + +#ifdef __WINDOWS__ + #include "wx/msw/mslu.h" +#endif + +#ifdef __WATCOMC__ + #include +#endif + +#ifndef __WXWINCE__ +#include +#endif + +#if defined(__UNIX__) || defined(__DOS__) +#include +#endif + +// ---------------------------------------------------------------------------- +// private functions +// ---------------------------------------------------------------------------- + +static +int wxCALLBACK wxFileDataNameCompare( long data1, long data2, long sortOrder) +{ + wxFileData *fd1 = (wxFileData *)wxUIntToPtr(data1); + wxFileData *fd2 = (wxFileData *)wxUIntToPtr(data2); + + if (fd1->GetFileName() == wxT("..")) + return -sortOrder; + if (fd2->GetFileName() == wxT("..")) + return sortOrder; + if (fd1->IsDir() && !fd2->IsDir()) + return -sortOrder; + if (fd2->IsDir() && !fd1->IsDir()) + return sortOrder; + + return sortOrder*wxStrcmp( fd1->GetFileName(), fd2->GetFileName() ); +} + +static +int wxCALLBACK wxFileDataSizeCompare(long data1, long data2, long sortOrder) +{ + wxFileData *fd1 = (wxFileData *)wxUIntToPtr(data1); + wxFileData *fd2 = (wxFileData *)wxUIntToPtr(data2); + + if (fd1->GetFileName() == wxT("..")) + return -sortOrder; + if (fd2->GetFileName() == wxT("..")) + return sortOrder; + if (fd1->IsDir() && !fd2->IsDir()) + return -sortOrder; + if (fd2->IsDir() && !fd1->IsDir()) + return sortOrder; + if (fd1->IsLink() && !fd2->IsLink()) + return -sortOrder; + if (fd2->IsLink() && !fd1->IsLink()) + return sortOrder; + + return fd1->GetSize() > fd2->GetSize() ? sortOrder : -sortOrder; +} + +static +int wxCALLBACK wxFileDataTypeCompare(long data1, long data2, long sortOrder) +{ + wxFileData *fd1 = (wxFileData *)wxUIntToPtr(data1); + wxFileData *fd2 = (wxFileData *)wxUIntToPtr(data2); + + if (fd1->GetFileName() == wxT("..")) + return -sortOrder; + if (fd2->GetFileName() == wxT("..")) + return sortOrder; + if (fd1->IsDir() && !fd2->IsDir()) + return -sortOrder; + if (fd2->IsDir() && !fd1->IsDir()) + return sortOrder; + if (fd1->IsLink() && !fd2->IsLink()) + return -sortOrder; + if (fd2->IsLink() && !fd1->IsLink()) + return sortOrder; + + return sortOrder*wxStrcmp( fd1->GetFileType(), fd2->GetFileType() ); +} + +static +int wxCALLBACK wxFileDataTimeCompare(long data1, long data2, long sortOrder) +{ + wxFileData *fd1 = (wxFileData *)wxUIntToPtr(data1); + wxFileData *fd2 = (wxFileData *)wxUIntToPtr(data2); + + if (fd1->GetFileName() == wxT("..")) + return -sortOrder; + if (fd2->GetFileName() == wxT("..")) + return sortOrder; + if (fd1->IsDir() && !fd2->IsDir()) + return -sortOrder; + if (fd2->IsDir() && !fd1->IsDir()) + return sortOrder; + + return fd1->GetDateTime().IsLaterThan(fd2->GetDateTime()) ? sortOrder : -sortOrder; +} + +#if defined(__WXWINCE__) +#define IsTopMostDir(dir) (dir == wxT("\\") || dir == wxT("/")) +#elif (defined(__DOS__) || defined(__WINDOWS__) || defined (__OS2__)) +#define IsTopMostDir(dir) (dir.empty()) +#else +#define IsTopMostDir(dir) (dir == wxT("/")) +#endif + +// defined in src/generic/dirctrlg.cpp +extern size_t wxGetAvailableDrives(wxArrayString &paths, wxArrayString &names, wxArrayInt &icon_ids); + +//----------------------------------------------------------------------------- +// wxFileData +//----------------------------------------------------------------------------- + +wxFileData::wxFileData( const wxString &filePath, const wxString &fileName, fileType type, int image_id ) +{ + Init(); + m_fileName = fileName; + m_filePath = filePath; + m_type = type; + m_image = image_id; + + ReadData(); +} + +void wxFileData::Init() +{ + m_size = 0; + m_type = wxFileData::is_file; + m_image = wxFileIconsTable::file; +} + +void wxFileData::Copy( const wxFileData& fileData ) +{ + m_fileName = fileData.GetFileName(); + m_filePath = fileData.GetFilePath(); + m_size = fileData.GetSize(); + m_dateTime = fileData.GetDateTime(); + m_permissions = fileData.GetPermissions(); + m_type = fileData.GetType(); + m_image = fileData.GetImageId(); +} + +void wxFileData::ReadData() +{ + if (IsDrive()) + { + m_size = 0; + return; + } + +#if defined(__DOS__) || (defined(__WINDOWS__) && !defined(__WXWINCE__)) || defined(__OS2__) + // c:\.. is a drive don't stat it + if ((m_fileName == wxT("..")) && (m_filePath.length() <= 5)) + { + m_type = is_drive; + m_size = 0; + return; + } +#endif // __DOS__ || __WINDOWS__ + +#ifdef __WXWINCE__ + + // WinCE + + DWORD fileAttribs = GetFileAttributes(m_filePath.fn_str()); + m_type |= (fileAttribs & FILE_ATTRIBUTE_DIRECTORY) != 0 ? is_dir : 0; + + wxString p, f, ext; + wxSplitPath(m_filePath, & p, & f, & ext); + if (wxStricmp(ext, wxT("exe")) == 0) + m_type |= is_exe; + + // Find out size + m_size = 0; + HANDLE fileHandle = CreateFile(m_filePath.fn_str(), + GENERIC_READ, + FILE_SHARE_READ, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL); + + if (fileHandle != INVALID_HANDLE_VALUE) + { + m_size = GetFileSize(fileHandle, 0); + CloseHandle(fileHandle); + } + + m_dateTime = wxFileModificationTime(m_filePath); + +#else + + // OTHER PLATFORMS + + wxStructStat buff; + +#if defined(__UNIX__) && (!defined( __OS2__ ) && !defined(__VMS)) + lstat( m_filePath.fn_str(), &buff ); + m_type |= S_ISLNK( buff.st_mode ) != 0 ? is_link : 0; +#else // no lstat() + // only translate to file charset if we don't go by our + // wxStat implementation +#ifndef wxNEED_WX_UNISTD_H + wxStat( m_filePath.fn_str() , &buff ); +#else + wxStat( m_filePath, &buff ); +#endif +#endif + + m_type |= (buff.st_mode & S_IFDIR) != 0 ? is_dir : 0; + m_type |= (buff.st_mode & wxS_IXUSR) != 0 ? is_exe : 0; + + m_size = buff.st_size; + + m_dateTime = buff.st_mtime; +#endif + // __WXWINCE__ + +#if defined(__UNIX__) + m_permissions.Printf(_T("%c%c%c%c%c%c%c%c%c"), + buff.st_mode & wxS_IRUSR ? _T('r') : _T('-'), + buff.st_mode & wxS_IWUSR ? _T('w') : _T('-'), + buff.st_mode & wxS_IXUSR ? _T('x') : _T('-'), + buff.st_mode & wxS_IRGRP ? _T('r') : _T('-'), + buff.st_mode & wxS_IWGRP ? _T('w') : _T('-'), + buff.st_mode & wxS_IXGRP ? _T('x') : _T('-'), + buff.st_mode & wxS_IROTH ? _T('r') : _T('-'), + buff.st_mode & wxS_IWOTH ? _T('w') : _T('-'), + buff.st_mode & wxS_IXOTH ? _T('x') : _T('-')); +#elif defined(__WIN32__) + DWORD attribs = ::GetFileAttributes(m_filePath.c_str()); + if (attribs != (DWORD)-1) + { + m_permissions.Printf(_T("%c%c%c%c"), + attribs & FILE_ATTRIBUTE_ARCHIVE ? _T('A') : _T(' '), + attribs & FILE_ATTRIBUTE_READONLY ? _T('R') : _T(' '), + attribs & FILE_ATTRIBUTE_HIDDEN ? _T('H') : _T(' '), + attribs & FILE_ATTRIBUTE_SYSTEM ? _T('S') : _T(' ')); + } +#endif + + // try to get a better icon + if (m_image == wxFileIconsTable::file) + { + if (m_fileName.Find(wxT('.'), true) != wxNOT_FOUND) + { + m_image = wxTheFileIconsTable->GetIconID( m_fileName.AfterLast(wxT('.'))); + } else if (IsExe()) + { + m_image = wxFileIconsTable::executable; + } + } +} + +wxString wxFileData::GetFileType() const +{ + if (IsDir()) + return _(""); + else if (IsLink()) + return _(""); + else if (IsDrive()) + return _(""); + else if (m_fileName.Find(wxT('.'), true) != wxNOT_FOUND) + return m_fileName.AfterLast(wxT('.')); + + return wxEmptyString; +} + +wxString wxFileData::GetModificationTime() const +{ + // want time as 01:02 so they line up nicely, no %r in WIN32 + return m_dateTime.FormatDate() + wxT(" ") + m_dateTime.Format(wxT("%I:%M:%S %p")); +} + +wxString wxFileData::GetHint() const +{ + wxString s = m_filePath; + s += wxT(" "); + + if (IsDir()) + s += _(""); + else if (IsLink()) + s += _(""); + else if (IsDrive()) + s += _(""); + else // plain file + s += wxString::Format(wxPLURAL("%ld byte", "%ld bytes", m_size), + wxLongLong(m_size).ToString().c_str()); + + s += wxT(' '); + + if ( !IsDrive() ) + { + s << GetModificationTime() + << wxT(" ") + << m_permissions; + } + + return s; +} + +wxString wxFileData::GetEntry( fileListFieldType num ) const +{ + wxString s; + switch ( num ) + { + case FileList_Name: + s = m_fileName; + break; + + case FileList_Size: + if (!IsDir() && !IsLink() && !IsDrive()) + s = wxLongLong(m_size).ToString(); + break; + + case FileList_Type: + s = GetFileType(); + break; + + case FileList_Time: + if (!IsDrive()) + s = GetModificationTime(); + break; + +#if defined(__UNIX__) || defined(__WIN32__) + case FileList_Perm: + s = m_permissions; + break; +#endif // defined(__UNIX__) || defined(__WIN32__) + + default: + wxFAIL_MSG( _T("unexpected field in wxFileData::GetEntry()") ); + } + + return s; +} + +void wxFileData::SetNewName( const wxString &filePath, const wxString &fileName ) +{ + m_fileName = fileName; + m_filePath = filePath; +} + +void wxFileData::MakeItem( wxListItem &item ) +{ + item.m_text = m_fileName; + item.ClearAttributes(); + if (IsExe()) + item.SetTextColour(*wxRED); + if (IsDir()) + item.SetTextColour(*wxBLUE); + + item.m_image = m_image; + + if (IsLink()) + { + wxColour dg = wxTheColourDatabase->Find( _T("MEDIUM GREY") ); + if ( dg.Ok() ) + item.SetTextColour(dg); + } + item.m_data = wxPtrToUInt(this); +} + +//----------------------------------------------------------------------------- +// wxFileCtrl +//----------------------------------------------------------------------------- + +static bool ignoreChanges = false; + +IMPLEMENT_DYNAMIC_CLASS(wxFileCtrl,wxListCtrl) + +BEGIN_EVENT_TABLE(wxFileCtrl,wxListCtrl) + EVT_LIST_DELETE_ITEM(wxID_ANY, wxFileCtrl::OnListDeleteItem) + EVT_LIST_DELETE_ALL_ITEMS(wxID_ANY, wxFileCtrl::OnListDeleteAllItems) + EVT_LIST_END_LABEL_EDIT(wxID_ANY, wxFileCtrl::OnListEndLabelEdit) + EVT_LIST_COL_CLICK(wxID_ANY, wxFileCtrl::OnListColClick) +END_EVENT_TABLE() + + +wxFileCtrl::wxFileCtrl() +{ + m_showHidden = false; + m_sort_foward = 1; + m_sort_field = wxFileData::FileList_Name; +} + +wxFileCtrl::wxFileCtrl(wxWindow *win, + wxWindowID id, + const wxString& wild, + bool showHidden, + const wxPoint& pos, + const wxSize& size, + long style, + const wxValidator &validator, + const wxString &name) + : wxListCtrl(win, id, pos, size, style, validator, name), + m_wild(wild) +{ + wxImageList *imageList = wxTheFileIconsTable->GetSmallImageList(); + + SetImageList( imageList, wxIMAGE_LIST_SMALL ); + + m_showHidden = showHidden; + + m_sort_foward = 1; + m_sort_field = wxFileData::FileList_Name; + + m_dirName = wxT("*"); + + if (style & wxLC_REPORT) + ChangeToReportMode(); +} + +void wxFileCtrl::ChangeToListMode() +{ + ClearAll(); + SetSingleStyle( wxLC_LIST ); + UpdateFiles(); +} + +void wxFileCtrl::ChangeToReportMode() +{ + ClearAll(); + SetSingleStyle( wxLC_REPORT ); + + // do this since WIN32 does mm/dd/yy UNIX does mm/dd/yyyy + // don't hardcode since mm/dd is dd/mm elsewhere + int w, h; + wxDateTime dt(22, wxDateTime::Dec, 2002, 22, 22, 22); + wxString txt = dt.FormatDate() + wxT("22") + dt.Format(wxT("%I:%M:%S %p")); + GetTextExtent(txt, &w, &h); + + InsertColumn( 0, _("Name"), wxLIST_FORMAT_LEFT, w ); + InsertColumn( 1, _("Size"), wxLIST_FORMAT_LEFT, w/2 ); + InsertColumn( 2, _("Type"), wxLIST_FORMAT_LEFT, w/2 ); + InsertColumn( 3, _("Modified"), wxLIST_FORMAT_LEFT, w ); +#if defined(__UNIX__) + GetTextExtent(wxT("Permissions 2"), &w, &h); + InsertColumn( 4, _("Permissions"), wxLIST_FORMAT_LEFT, w ); +#elif defined(__WIN32__) + GetTextExtent(wxT("Attributes 2"), &w, &h); + InsertColumn( 4, _("Attributes"), wxLIST_FORMAT_LEFT, w ); +#endif + + UpdateFiles(); +} + +void wxFileCtrl::ChangeToSmallIconMode() +{ + ClearAll(); + SetSingleStyle( wxLC_SMALL_ICON ); + UpdateFiles(); +} + +void wxFileCtrl::ShowHidden( bool show ) +{ + m_showHidden = show; + UpdateFiles(); +} + +long wxFileCtrl::Add( wxFileData *fd, wxListItem &item ) +{ + long ret = -1; + item.m_mask = wxLIST_MASK_TEXT + wxLIST_MASK_DATA + wxLIST_MASK_IMAGE; + fd->MakeItem( item ); + long my_style = GetWindowStyleFlag(); + if (my_style & wxLC_REPORT) + { + ret = InsertItem( item ); + for (int i = 1; i < wxFileData::FileList_Max; i++) + SetItem( item.m_itemId, i, fd->GetEntry((wxFileData::fileListFieldType)i) ); + } + else if ((my_style & wxLC_LIST) || (my_style & wxLC_SMALL_ICON)) + { + ret = InsertItem( item ); + } + return ret; +} + +void wxFileCtrl::UpdateItem(const wxListItem &item) +{ + wxFileData *fd = (wxFileData*)GetItemData(item); + wxCHECK_RET(fd, wxT("invalid filedata")); + + fd->ReadData(); + + SetItemText(item, fd->GetFileName()); + SetItemImage(item, fd->GetImageId()); + + if (GetWindowStyleFlag() & wxLC_REPORT) + { + for (int i = 1; i < wxFileData::FileList_Max; i++) + SetItem( item.m_itemId, i, fd->GetEntry((wxFileData::fileListFieldType)i) ); + } +} + +void wxFileCtrl::UpdateFiles() +{ + // don't do anything before ShowModal() call which sets m_dirName + if ( m_dirName == wxT("*") ) + return; + + wxBusyCursor bcur; // this may take a while... + + DeleteAllItems(); + + wxListItem item; + item.m_itemId = 0; + item.m_col = 0; + +#if (defined(__WINDOWS__) || defined(__DOS__) || defined(__WXMAC__) || defined(__OS2__)) && !defined(__WXWINCE__) + if ( IsTopMostDir(m_dirName) ) + { + wxArrayString names, paths; + wxArrayInt icons; + size_t n, count = wxGetAvailableDrives(paths, names, icons); + + for (n=0; nGetFilePath() ) ); + new_name += wxFILE_SEP_PATH; + new_name += event.GetLabel(); + + wxLogNull log; + + if (wxFileExists(new_name)) + { + wxMessageDialog dialog(this, _("File name exists already."), _("Error"), wxOK | wxICON_ERROR ); + dialog.ShowModal(); + event.Veto(); + } + + if (wxRenameFile(fd->GetFilePath(),new_name)) + { + fd->SetNewName( new_name, event.GetLabel() ); + + ignoreChanges = true; + SetItemState( event.GetItem(), wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED ); + ignoreChanges = false; + + UpdateItem( event.GetItem() ); + EnsureVisible( event.GetItem() ); + } + else + { + wxMessageDialog dialog(this, _("Operation not permitted."), _("Error"), wxOK | wxICON_ERROR ); + dialog.ShowModal(); + event.Veto(); + } +} + +void wxFileCtrl::OnListColClick( wxListEvent &event ) +{ + int col = event.GetColumn(); + + switch (col) + { + case wxFileData::FileList_Name : + case wxFileData::FileList_Size : + case wxFileData::FileList_Type : + case wxFileData::FileList_Time : break; + default : return; + } + + if ((wxFileData::fileListFieldType)col == m_sort_field) + m_sort_foward = !m_sort_foward; + else + m_sort_field = (wxFileData::fileListFieldType)col; + + SortItems(m_sort_field, m_sort_foward); +} + +void wxFileCtrl::SortItems(wxFileData::fileListFieldType field, bool forward) +{ + m_sort_field = field; + m_sort_foward = forward; + const long sort_dir = forward ? 1 : -1; + + switch (m_sort_field) + { + case wxFileData::FileList_Size : + wxListCtrl::SortItems(wxFileDataSizeCompare, sort_dir); + break; + + case wxFileData::FileList_Type : + wxListCtrl::SortItems(wxFileDataTypeCompare, sort_dir); + break; + + case wxFileData::FileList_Time : + wxListCtrl::SortItems(wxFileDataTimeCompare, sort_dir); + break; + + case wxFileData::FileList_Name : + default : + wxListCtrl::SortItems(wxFileDataNameCompare, sort_dir); + break; + } +} + +wxFileCtrl::~wxFileCtrl() +{ + // Normally the data are freed via an EVT_LIST_DELETE_ALL_ITEMS event and + // wxFileCtrl::OnListDeleteAllItems. But if the event is generated after + // the destruction of the wxFileCtrl we need to free any data here: + FreeAllItemsData(); +} + +//----------------------------------------------------------------------------- +// wxGenericFileDialog +//----------------------------------------------------------------------------- + +#define ID_LIST_MODE (wxID_FILEDLGG ) +#define ID_REPORT_MODE (wxID_FILEDLGG + 1) +#define ID_UP_DIR (wxID_FILEDLGG + 5) +#define ID_PARENT_DIR (wxID_FILEDLGG + 6) +#define ID_NEW_DIR (wxID_FILEDLGG + 7) +#define ID_CHOICE (wxID_FILEDLGG + 8) +#define ID_TEXT (wxID_FILEDLGG + 9) +#define ID_LIST_CTRL (wxID_FILEDLGG + 10) +#define ID_CHECK (wxID_FILEDLGG + 12) + +IMPLEMENT_DYNAMIC_CLASS(wxGenericFileDialog, wxFileDialogBase) + +BEGIN_EVENT_TABLE(wxGenericFileDialog,wxDialog) + EVT_BUTTON(ID_LIST_MODE, wxGenericFileDialog::OnList) + EVT_BUTTON(ID_REPORT_MODE, wxGenericFileDialog::OnReport) + EVT_BUTTON(ID_UP_DIR, wxGenericFileDialog::OnUp) + EVT_BUTTON(ID_PARENT_DIR, wxGenericFileDialog::OnHome) + EVT_BUTTON(ID_NEW_DIR, wxGenericFileDialog::OnNew) + EVT_BUTTON(wxID_OK, wxGenericFileDialog::OnListOk) + EVT_LIST_ITEM_SELECTED(ID_LIST_CTRL, wxGenericFileDialog::OnSelected) + EVT_LIST_ITEM_ACTIVATED(ID_LIST_CTRL, wxGenericFileDialog::OnActivated) + EVT_CHOICE(ID_CHOICE,wxGenericFileDialog::OnChoiceFilter) + EVT_TEXT_ENTER(ID_TEXT,wxGenericFileDialog::OnTextEnter) + EVT_TEXT(ID_TEXT,wxGenericFileDialog::OnTextChange) + EVT_CHECKBOX(ID_CHECK,wxGenericFileDialog::OnCheck) +END_EVENT_TABLE() + +long wxGenericFileDialog::ms_lastViewStyle = wxLC_LIST; +bool wxGenericFileDialog::ms_lastShowHidden = false; + +void wxGenericFileDialog::Init() +{ + m_bypassGenericImpl = false; + + m_choice = NULL; + m_text = NULL; + m_list = NULL; + m_check = NULL; + m_static = NULL; + m_upDirButton = NULL; + m_newDirButton = NULL; +} + +wxGenericFileDialog::wxGenericFileDialog(wxWindow *parent, + const wxString& message, + const wxString& defaultDir, + const wxString& defaultFile, + const wxString& wildCard, + long style, + const wxPoint& pos, + const wxSize& sz, + const wxString& name, + bool bypassGenericImpl ) : wxFileDialogBase() +{ + Init(); + Create( parent, message, defaultDir, defaultFile, wildCard, style, pos, sz, name, bypassGenericImpl ); +} + +bool wxGenericFileDialog::Create( wxWindow *parent, + const wxString& message, + const wxString& defaultDir, + const wxString& defaultFile, + const wxString& wildCard, + long style, + const wxPoint& pos, + const wxSize& sz, + const wxString& name, + bool bypassGenericImpl ) +{ + m_bypassGenericImpl = bypassGenericImpl; + + if (!wxFileDialogBase::Create(parent, message, defaultDir, defaultFile, + wildCard, style, pos, sz, name)) + { + return false; + } + + if (m_bypassGenericImpl) + return true; + + if (!wxDialog::Create( parent, wxID_ANY, message, pos, sz, + wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER | style, name + )) + { + return false; + } + + ignoreChanges = true; + +#if wxUSE_CONFIG + if (wxConfig::Get(false)) + { + wxConfig::Get()->Read(wxT("/wxWindows/wxFileDialog/ViewStyle"), + &ms_lastViewStyle); + wxConfig::Get()->Read(wxT("/wxWindows/wxFileDialog/ShowHidden"), + &ms_lastShowHidden); + } +#endif + + if ((m_dir.empty()) || (m_dir == wxT("."))) + { + m_dir = wxGetCwd(); + if (m_dir.empty()) + m_dir = wxFILE_SEP_PATH; + } + + size_t len = m_dir.length(); + if ((len > 1) && (wxEndsWithPathSeparator(m_dir))) + m_dir.Remove( len-1, 1 ); + + m_path = m_dir; + m_path += wxFILE_SEP_PATH; + m_path += defaultFile; + m_filterExtension = wxEmptyString; + + // layout + + bool is_pda = (wxSystemSettings::GetScreenType() <= wxSYS_SCREEN_PDA); + + wxBoxSizer *mainsizer = new wxBoxSizer( wxVERTICAL ); + + wxBoxSizer *buttonsizer = new wxBoxSizer( wxHORIZONTAL ); + + wxBitmapButton *but; + + but = new wxBitmapButton(this, ID_LIST_MODE, + wxArtProvider::GetBitmap(wxART_LIST_VIEW, wxART_BUTTON)); +#if wxUSE_TOOLTIPS + but->SetToolTip( _("View files as a list view") ); +#endif + buttonsizer->Add( but, 0, wxALL, 5 ); + + but = new wxBitmapButton(this, ID_REPORT_MODE, + wxArtProvider::GetBitmap(wxART_REPORT_VIEW, wxART_BUTTON)); +#if wxUSE_TOOLTIPS + but->SetToolTip( _("View files as a detailed view") ); +#endif + buttonsizer->Add( but, 0, wxALL, 5 ); + + buttonsizer->Add( 30, 5, 1 ); + + m_upDirButton = new wxBitmapButton(this, ID_UP_DIR, + wxArtProvider::GetBitmap(wxART_GO_DIR_UP, wxART_BUTTON)); +#if wxUSE_TOOLTIPS + m_upDirButton->SetToolTip( _("Go to parent directory") ); +#endif + buttonsizer->Add( m_upDirButton, 0, wxALL, 5 ); + +#ifndef __DOS__ // VS: Home directory is meaningless in MS-DOS... + but = new wxBitmapButton(this, ID_PARENT_DIR, + wxArtProvider::GetBitmap(wxART_GO_HOME, wxART_BUTTON)); +#if wxUSE_TOOLTIPS + but->SetToolTip( _("Go to home directory") ); +#endif + buttonsizer->Add( but, 0, wxALL, 5); + + buttonsizer->Add( 20, 20 ); +#endif //!__DOS__ + + m_newDirButton = new wxBitmapButton(this, ID_NEW_DIR, + wxArtProvider::GetBitmap(wxART_NEW_DIR, wxART_BUTTON)); +#if wxUSE_TOOLTIPS + m_newDirButton->SetToolTip( _("Create new directory") ); +#endif + buttonsizer->Add( m_newDirButton, 0, wxALL, 5 ); + + if (is_pda) + mainsizer->Add( buttonsizer, 0, wxALL | wxEXPAND, 0 ); + else + mainsizer->Add( buttonsizer, 0, wxALL | wxEXPAND, 5 ); + + wxBoxSizer *staticsizer = new wxBoxSizer( wxHORIZONTAL ); + if (is_pda) + staticsizer->Add( new wxStaticText( this, wxID_ANY, _("Current directory:") ), 0, wxRIGHT, 10 ); + m_static = new wxStaticText( this, wxID_ANY, m_dir ); + staticsizer->Add( m_static, 1 ); + mainsizer->Add( staticsizer, 0, wxEXPAND | wxLEFT|wxRIGHT|wxBOTTOM, 10 ); + + long style2 = ms_lastViewStyle; + if ( !HasFdFlag(wxFD_MULTIPLE) ) + style2 |= wxLC_SINGLE_SEL; + +#ifdef __WXWINCE__ + style2 |= wxSIMPLE_BORDER; +#else + style2 |= wxSUNKEN_BORDER; +#endif + + m_list = new wxFileCtrl( this, ID_LIST_CTRL, + wxEmptyString, ms_lastShowHidden, + wxDefaultPosition, wxSize(540,200), + style2); + + m_text = new wxTextCtrl(this, ID_TEXT, m_fileName, + wxDefaultPosition, wxDefaultSize, + wxTE_PROCESS_ENTER); + m_choice = new wxChoice(this, ID_CHOICE); + + if (is_pda) + { + // PDAs have a different screen layout + mainsizer->Add(m_list, wxSizerFlags(1).Expand().HorzBorder()); + + wxBoxSizer *textsizer = new wxBoxSizer(wxHORIZONTAL); + textsizer->Add(m_text, wxSizerFlags(1).Centre().Border()); + mainsizer->Add(textsizer, wxSizerFlags().Expand()); + + m_check = NULL; + textsizer->Add(m_choice, wxSizerFlags(1).Centre().Border()); + + wxSizer *bsizer = CreateButtonSizer(wxOK | wxCANCEL); + if ( bsizer ) + mainsizer->Add(bsizer, wxSizerFlags().Expand().Border()); + } + else // !is_pda + { + mainsizer->Add(m_list, wxSizerFlags(1).Expand().DoubleHorzBorder()); + + wxBoxSizer *textsizer = new wxBoxSizer(wxHORIZONTAL); + textsizer->Add(m_text, wxSizerFlags(1).Centre(). + DoubleBorder(wxLEFT | wxRIGHT | wxTOP)); + textsizer->Add(new wxButton(this, wxID_OK), wxSizerFlags().Centre(). + DoubleBorder(wxLEFT | wxRIGHT | wxTOP)); + mainsizer->Add(textsizer, wxSizerFlags().Expand()); + + wxSizerFlags flagsCentre; + flagsCentre.Centre().DoubleBorder(); + + wxBoxSizer *choicesizer = new wxBoxSizer(wxHORIZONTAL); + choicesizer->Add(m_choice, wxSizerFlags(flagsCentre).Proportion(1)); + + m_check = new wxCheckBox(this, ID_CHECK, _("Show &hidden files")); + m_check->SetValue(ms_lastShowHidden); + + choicesizer->Add(m_check, flagsCentre); + choicesizer->Add(new wxButton(this, wxID_CANCEL), flagsCentre); + mainsizer->Add(choicesizer, wxSizerFlags().Expand()); + } + + SetWildcard(wildCard); + + SetAutoLayout( true ); + SetSizer( mainsizer ); + + if (!is_pda) + { + mainsizer->Fit( this ); + mainsizer->SetSizeHints( this ); + + Centre( wxBOTH ); + } + + m_text->SetFocus(); + + ignoreChanges = false; + + return true; +} + +wxGenericFileDialog::~wxGenericFileDialog() +{ + ignoreChanges = true; + + if (!m_bypassGenericImpl) + { +#if wxUSE_CONFIG + if (wxConfig::Get(false)) + { + wxConfig::Get()->Write(wxT("/wxWindows/wxFileDialog/ViewStyle"), + ms_lastViewStyle); + wxConfig::Get()->Write(wxT("/wxWindows/wxFileDialog/ShowHidden"), + ms_lastShowHidden); + } +#endif + + const int count = m_choice->GetCount(); + for ( int i = 0; i < count; i++ ) + { + delete (wxString *)m_choice->GetClientData(i); + } + } +} + +int wxGenericFileDialog::ShowModal() +{ + ignoreChanges = true; + + m_list->GoToDir(m_dir); + UpdateControls(); + m_text->SetValue(m_fileName); + + ignoreChanges = false; + + return wxDialog::ShowModal(); +} + +bool wxGenericFileDialog::Show( bool show ) +{ + // Called by ShowModal, so don't repeate the update +#ifndef __WIN32__ + if (show) + { + m_list->GoToDir(m_dir); + UpdateControls(); + m_text->SetValue(m_fileName); + } +#endif + + return wxDialog::Show( show ); +} + +void wxGenericFileDialog::DoSetFilterIndex(int filterindex) +{ + wxString *str = (wxString*) m_choice->GetClientData( filterindex ); + m_list->SetWild( *str ); + m_filterIndex = filterindex; + if ( str->Left(2) == wxT("*.") ) + { + m_filterExtension = str->Mid(1); + if (m_filterExtension == _T(".*")) + m_filterExtension.clear(); + } + else + { + m_filterExtension.clear(); + } +} + +void wxGenericFileDialog::SetWildcard(const wxString& wildCard) +{ + wxFileDialogBase::SetWildcard(wildCard); + + wxArrayString wildDescriptions, wildFilters; + const size_t count = wxParseCommonDialogsFilter(m_wildCard, + wildDescriptions, + wildFilters); + wxCHECK_RET( count, wxT("wxFileDialog: bad wildcard string") ); + + const size_t countOld = m_choice->GetCount(); + size_t n; + for ( n = 0; n < countOld; n++ ) + { + delete (wxString *)m_choice->GetClientData(n); + } + + for ( n = 0; n < count; n++ ) + { + m_choice->Append( wildDescriptions[n], new wxString( wildFilters[n] ) ); + } + + SetFilterIndex( 0 ); +} + +void wxGenericFileDialog::SetFilterIndex( int filterindex ) +{ + m_choice->SetSelection( filterindex ); + + DoSetFilterIndex(filterindex); +} + +void wxGenericFileDialog::OnChoiceFilter( wxCommandEvent &event ) +{ + DoSetFilterIndex((int)event.GetInt()); +} + +void wxGenericFileDialog::OnCheck( wxCommandEvent &event ) +{ + m_list->ShowHidden( (ms_lastShowHidden = event.GetInt() != 0) ); +} + +void wxGenericFileDialog::OnActivated( wxListEvent &event ) +{ + HandleAction( event.m_item.m_text ); +} + +void wxGenericFileDialog::OnTextEnter( wxCommandEvent &WXUNUSED(event) ) +{ + HandleAction( m_text->GetValue() ); +} + +void wxGenericFileDialog::OnTextChange( wxCommandEvent &WXUNUSED(event) ) +{ + if (!ignoreChanges) + { + // Clear selections. Otherwise when the user types in a value they may + // not get the file whose name they typed. + if (m_list->GetSelectedItemCount() > 0) + { + long item = m_list->GetNextItem(-1, wxLIST_NEXT_ALL, + wxLIST_STATE_SELECTED); + while ( item != -1 ) + { + m_list->SetItemState(item,0, wxLIST_STATE_SELECTED); + item = m_list->GetNextItem(item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED); + } + } + } +} + +void wxGenericFileDialog::OnSelected( wxListEvent &event ) +{ + static bool inSelected = false; + + if (inSelected) + return; + + inSelected = true; + wxString filename( event.m_item.m_text ); + +#ifdef __WXWINCE__ + // No double-click on most WinCE devices, so do action immediately. + HandleAction( filename ); +#else + if (filename == wxT("..")) + { + inSelected = false; + return; + } + + wxString dir = m_list->GetDir(); + if (!IsTopMostDir(dir)) + dir += wxFILE_SEP_PATH; + dir += filename; + if (wxDirExists(dir)) + { + inSelected = false; + return; + } + + ignoreChanges = true; + m_text->SetValue( filename ); + ignoreChanges = false; +#endif + inSelected = false; +} + +void wxGenericFileDialog::HandleAction( const wxString &fn ) +{ + if (ignoreChanges) + return; + + wxString filename( fn ); + if (filename.empty()) + { +#ifdef __WXWINCE__ + EndModal(wxID_CANCEL); +#endif + return; + } + if (filename == wxT(".")) return; + + wxString dir = m_list->GetDir(); + + // "some/place/" means they want to chdir not try to load "place" + bool want_dir = filename.Last() == wxFILE_SEP_PATH; + if (want_dir) + filename = filename.RemoveLast(); + + if (filename == wxT("..")) + { + ignoreChanges = true; + m_list->GoToParentDir(); + m_list->SetFocus(); + UpdateControls(); + ignoreChanges = false; + return; + } + +#ifdef __UNIX__ + if (filename == wxT("~")) + { + ignoreChanges = true; + m_list->GoToHomeDir(); + m_list->SetFocus(); + UpdateControls(); + ignoreChanges = false; + return; + } + + if (filename.BeforeFirst(wxT('/')) == wxT("~")) + { + filename = wxString(wxGetUserHome()) + filename.Remove(0, 1); + } +#endif // __UNIX__ + + if (!HasFdFlag(wxFD_SAVE)) + { + if ((filename.Find(wxT('*')) != wxNOT_FOUND) || + (filename.Find(wxT('?')) != wxNOT_FOUND)) + { + if (filename.Find(wxFILE_SEP_PATH) != wxNOT_FOUND) + { + wxMessageBox(_("Illegal file specification."), _("Error"), wxOK | wxICON_ERROR ); + return; + } + m_list->SetWild( filename ); + return; + } + } + + if (!IsTopMostDir(dir)) + dir += wxFILE_SEP_PATH; + if (!wxIsAbsolutePath(filename)) + { + dir += filename; + filename = dir; + } + + if (wxDirExists(filename)) + { + ignoreChanges = true; + m_list->GoToDir( filename ); + UpdateControls(); + ignoreChanges = false; + return; + } + + // they really wanted a dir, but it doesn't exist + if (want_dir) + { + wxMessageBox(_("Directory doesn't exist."), _("Error"), + wxOK | wxICON_ERROR ); + return; + } + + // append the default extension to the filename if it doesn't have any + // + // VZ: the logic of testing for !wxFileExists() only for the open file + // dialog is not entirely clear to me, why don't we allow saving to a + // file without extension as well? + if ( !HasFdFlag(wxFD_OPEN) || !wxFileExists(filename) ) + { + filename = AppendExtension(filename, m_filterExtension); + } + + // check that the file [doesn't] exist if necessary + if ( HasFdFlag(wxFD_SAVE) && HasFdFlag(wxFD_OVERWRITE_PROMPT) && + wxFileExists( filename ) ) + { + wxString msg; + msg.Printf( _("File '%s' already exists, do you really want to overwrite it?"), filename.c_str() ); + + if (wxMessageBox(msg, _("Confirm"), wxYES_NO) != wxYES) + return; + } + else if ( HasFdFlag(wxFD_OPEN) && HasFdFlag(wxFD_FILE_MUST_EXIST) && + !wxFileExists(filename) ) + { + wxMessageBox(_("Please choose an existing file."), _("Error"), + wxOK | wxICON_ERROR ); + return; + } + + SetPath( filename ); + + // change to the directory where the user went if asked + if ( HasFdFlag(wxFD_CHANGE_DIR) ) + { + wxString cwd; + wxSplitPath(filename, &cwd, NULL, NULL); + + if ( cwd != wxGetCwd() ) + { + wxSetWorkingDirectory(cwd); + } + } + + EndModal(wxID_OK); +} + +void wxGenericFileDialog::OnListOk( wxCommandEvent &WXUNUSED(event) ) +{ + HandleAction( m_text->GetValue() ); +} + +void wxGenericFileDialog::OnList( wxCommandEvent &WXUNUSED(event) ) +{ + ignoreChanges = true; + m_list->ChangeToListMode(); + ms_lastViewStyle = wxLC_LIST; + m_list->SetFocus(); + ignoreChanges = false; +} + +void wxGenericFileDialog::OnReport( wxCommandEvent &WXUNUSED(event) ) +{ + ignoreChanges = true; + m_list->ChangeToReportMode(); + ms_lastViewStyle = wxLC_REPORT; + m_list->SetFocus(); + ignoreChanges = false; +} + +void wxGenericFileDialog::OnUp( wxCommandEvent &WXUNUSED(event) ) +{ + ignoreChanges = true; + m_list->GoToParentDir(); + m_list->SetFocus(); + UpdateControls(); + ignoreChanges = false; +} + +void wxGenericFileDialog::OnHome( wxCommandEvent &WXUNUSED(event) ) +{ + ignoreChanges = true; + m_list->GoToHomeDir(); + m_list->SetFocus(); + UpdateControls(); + ignoreChanges = false; +} + +void wxGenericFileDialog::OnNew( wxCommandEvent &WXUNUSED(event) ) +{ + ignoreChanges = true; + + m_list->MakeDir(); + + ignoreChanges = false; +} + +void wxGenericFileDialog::SetPath( const wxString& path ) +{ + // not only set the full path but also update filename and dir + m_path = path; + +#ifdef __WXWINCE__ + if (m_path.empty()) + m_path = wxFILE_SEP_PATH; +#endif + + if ( !path.empty() ) + { + wxString ext; + wxSplitPath(path, &m_dir, &m_fileName, &ext); + if (!ext.empty()) + { + m_fileName += wxT("."); + m_fileName += ext; + } + } +} + +void wxGenericFileDialog::GetPaths( wxArrayString& paths ) const +{ + paths.Empty(); + if (m_list->GetSelectedItemCount() == 0) + { + paths.Add( GetPath() ); + return; + } + + paths.Alloc( m_list->GetSelectedItemCount() ); + + wxString dir = m_list->GetDir(); +#ifdef __UNIX__ + if (dir != wxT("/")) +#endif +#ifdef __WXWINCE__ + if (dir != wxT("/") && dir != wxT("\\")) +#endif + dir += wxFILE_SEP_PATH; + + wxListItem item; + item.m_mask = wxLIST_MASK_TEXT; + + item.m_itemId = m_list->GetNextItem( -1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED ); + while ( item.m_itemId != -1 ) + { + m_list->GetItem( item ); + paths.Add( dir + item.m_text ); + item.m_itemId = m_list->GetNextItem( item.m_itemId, + wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED ); + } +} + +void wxGenericFileDialog::GetFilenames(wxArrayString& files) const +{ + files.Empty(); + if (m_list->GetSelectedItemCount() == 0) + { + files.Add( GetFilename() ); + return; + } + files.Alloc( m_list->GetSelectedItemCount() ); + + wxListItem item; + item.m_mask = wxLIST_MASK_TEXT; + + item.m_itemId = m_list->GetNextItem( -1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED ); + while ( item.m_itemId != -1 ) + { + m_list->GetItem( item ); + files.Add( item.m_text ); + item.m_itemId = m_list->GetNextItem( item.m_itemId, + wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED ); + } +} + +void wxGenericFileDialog::UpdateControls() +{ + wxString dir = m_list->GetDir(); + m_static->SetLabel(dir); + + bool enable = !IsTopMostDir(dir); + m_upDirButton->Enable(enable); + +#if defined(__DOS__) || defined(__WINDOWS__) || defined(__OS2__) + m_newDirButton->Enable(enable); +#endif // defined(__DOS__) || defined(__WINDOWS__) || defined(__OS2__) +} + +#ifdef wxUSE_GENERIC_FILEDIALOG + +IMPLEMENT_DYNAMIC_CLASS(wxFileDialog, wxGenericFileDialog) + +#endif // wxUSE_GENERIC_FILEDIALOG + +#endif // wxUSE_FILEDLG diff --git a/Externals/wxWidgets/src/generic/filepickerg.cpp b/Externals/wxWidgets/src/generic/filepickerg.cpp index 96eb79916a..cfac7f4760 100644 --- a/Externals/wxWidgets/src/generic/filepickerg.cpp +++ b/Externals/wxWidgets/src/generic/filepickerg.cpp @@ -1,86 +1,86 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: src/generic/filepickerg.cpp -// Purpose: wxGenericFileDirButton class implementation -// Author: Francesco Montorsi -// Modified by: -// Created: 15/04/2006 -// RCS-ID: $Id: filepickerg.cpp 52835 2008-03-26 15:49:08Z JS $ -// Copyright: (c) Francesco Montorsi -// Licence: wxWindows licence -/////////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_FILEPICKERCTRL || wxUSE_DIRPICKERCTRL - -#include "wx/filepicker.h" - - -// ============================================================================ -// implementation -// ============================================================================ - -IMPLEMENT_DYNAMIC_CLASS(wxGenericFileButton, wxButton) -IMPLEMENT_DYNAMIC_CLASS(wxGenericDirButton, wxButton) - -// ---------------------------------------------------------------------------- -// wxGenericFileButton -// ---------------------------------------------------------------------------- - -bool wxGenericFileDirButton::Create( wxWindow *parent, wxWindowID id, - const wxString &label, const wxString &path, - const wxString &message, const wxString &wildcard, - const wxPoint &pos, const wxSize &size, long style, - const wxValidator& validator, const wxString &name) -{ - // create this button - if (!wxButton::Create(parent, id, label, pos, size, style, - validator, name)) - { - wxFAIL_MSG( wxT("wxGenericFileButton creation failed") ); - return false; - } - - // and handle user clicks on it - Connect(GetId(), wxEVT_COMMAND_BUTTON_CLICKED, - wxCommandEventHandler(wxGenericFileDirButton::OnButtonClick), - NULL, this); - - // create the dialog associated with this button - m_path = path; - m_message = message; - m_wildcard = wildcard; - - return true; -} - -void wxGenericFileDirButton::OnButtonClick(wxCommandEvent& WXUNUSED(ev)) -{ - wxDialog *p = CreateDialog(); - if (p->ShowModal() == wxID_OK) - { - // save updated path in m_path - UpdatePathFromDialog(p); - - // fire an event - wxFileDirPickerEvent event(GetEventType(), this, GetId(), m_path); - GetEventHandler()->ProcessEvent(event); - } - - wxDELETE(p); -} - -#endif // wxUSE_FILEPICKERCTRL || wxUSE_DIRPICKERCTRL +/////////////////////////////////////////////////////////////////////////////// +// Name: src/generic/filepickerg.cpp +// Purpose: wxGenericFileDirButton class implementation +// Author: Francesco Montorsi +// Modified by: +// Created: 15/04/2006 +// RCS-ID: $Id: filepickerg.cpp 52835 2008-03-26 15:49:08Z JS $ +// Copyright: (c) Francesco Montorsi +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_FILEPICKERCTRL || wxUSE_DIRPICKERCTRL + +#include "wx/filepicker.h" + + +// ============================================================================ +// implementation +// ============================================================================ + +IMPLEMENT_DYNAMIC_CLASS(wxGenericFileButton, wxButton) +IMPLEMENT_DYNAMIC_CLASS(wxGenericDirButton, wxButton) + +// ---------------------------------------------------------------------------- +// wxGenericFileButton +// ---------------------------------------------------------------------------- + +bool wxGenericFileDirButton::Create( wxWindow *parent, wxWindowID id, + const wxString &label, const wxString &path, + const wxString &message, const wxString &wildcard, + const wxPoint &pos, const wxSize &size, long style, + const wxValidator& validator, const wxString &name) +{ + // create this button + if (!wxButton::Create(parent, id, label, pos, size, style, + validator, name)) + { + wxFAIL_MSG( wxT("wxGenericFileButton creation failed") ); + return false; + } + + // and handle user clicks on it + Connect(GetId(), wxEVT_COMMAND_BUTTON_CLICKED, + wxCommandEventHandler(wxGenericFileDirButton::OnButtonClick), + NULL, this); + + // create the dialog associated with this button + m_path = path; + m_message = message; + m_wildcard = wildcard; + + return true; +} + +void wxGenericFileDirButton::OnButtonClick(wxCommandEvent& WXUNUSED(ev)) +{ + wxDialog *p = CreateDialog(); + if (p->ShowModal() == wxID_OK) + { + // save updated path in m_path + UpdatePathFromDialog(p); + + // fire an event + wxFileDirPickerEvent event(GetEventType(), this, GetId(), m_path); + GetEventHandler()->ProcessEvent(event); + } + + wxDELETE(p); +} + +#endif // wxUSE_FILEPICKERCTRL || wxUSE_DIRPICKERCTRL diff --git a/Externals/wxWidgets/src/generic/fontdlgg.cpp b/Externals/wxWidgets/src/generic/fontdlgg.cpp index 0151c14f1d..fddcbbf7e6 100644 --- a/Externals/wxWidgets/src/generic/fontdlgg.cpp +++ b/Externals/wxWidgets/src/generic/fontdlgg.cpp @@ -1,623 +1,623 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/generic/fontdlgg.cpp -// Purpose: Generic font dialog -// Author: Julian Smart -// Modified by: -// Created: 04/01/98 -// RCS-ID: $Id: fontdlgg.cpp 39627 2006-06-08 06:57:39Z ABX $ -// Copyright: (c) Julian Smart -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ -#pragma hdrstop -#endif - -#if wxUSE_FONTDLG && (!defined(__WXGTK__) || defined(__WXGPE__) || defined(__WXUNIVERSAL__)) - -#ifndef WX_PRECOMP - #include - #include "wx/utils.h" - #include "wx/dialog.h" - #include "wx/listbox.h" - #include "wx/button.h" - #include "wx/stattext.h" - #include "wx/layout.h" - #include "wx/dcclient.h" - #include "wx/choice.h" - #include "wx/checkbox.h" - #include "wx/intl.h" - #include "wx/settings.h" - #include "wx/cmndata.h" - #include "wx/sizer.h" -#endif - -#include -#include - -#include "wx/fontdlg.h" -#include "wx/generic/fontdlgg.h" - -#if USE_SPINCTRL_FOR_POINT_SIZE -#include "wx/spinctrl.h" -#endif - -//----------------------------------------------------------------------------- -// helper class - wxFontPreviewer -//----------------------------------------------------------------------------- - -class WXDLLEXPORT wxFontPreviewer : public wxWindow -{ -public: - wxFontPreviewer(wxWindow *parent, const wxSize& sz = wxDefaultSize) : wxWindow(parent, wxID_ANY, wxDefaultPosition, sz) - { - } - -private: - void OnPaint(wxPaintEvent& event); - DECLARE_EVENT_TABLE() -}; - -BEGIN_EVENT_TABLE(wxFontPreviewer, wxWindow) - EVT_PAINT(wxFontPreviewer::OnPaint) -END_EVENT_TABLE() - -void wxFontPreviewer::OnPaint(wxPaintEvent& WXUNUSED(event)) -{ - wxPaintDC dc(this); - - wxSize size = GetSize(); - wxFont font = GetFont(); - - dc.SetPen(*wxBLACK_PEN); - dc.SetBrush(*wxWHITE_BRUSH); - dc.DrawRectangle(0, 0, size.x, size.y); - - if ( font.Ok() ) - { - dc.SetFont(font); - // Calculate vertical centre - long w = 0, h = 0; - dc.GetTextExtent( wxT("X"), &w, &h); - dc.SetTextForeground(GetForegroundColour()); - dc.SetClippingRegion(2, 2, size.x-4, size.y-4); - dc.DrawText(_("ABCDEFGabcdefg12345"), - 10, size.y/2 - h/2); - dc.DestroyClippingRegion(); - } -} - -//----------------------------------------------------------------------------- -// wxGenericFontDialog -//----------------------------------------------------------------------------- - -IMPLEMENT_DYNAMIC_CLASS(wxGenericFontDialog, wxDialog) - -BEGIN_EVENT_TABLE(wxGenericFontDialog, wxDialog) - EVT_CHECKBOX(wxID_FONT_UNDERLINE, wxGenericFontDialog::OnChangeFont) - EVT_CHOICE(wxID_FONT_STYLE, wxGenericFontDialog::OnChangeFont) - EVT_CHOICE(wxID_FONT_WEIGHT, wxGenericFontDialog::OnChangeFont) - EVT_CHOICE(wxID_FONT_FAMILY, wxGenericFontDialog::OnChangeFont) - EVT_CHOICE(wxID_FONT_COLOUR, wxGenericFontDialog::OnChangeFont) -#if USE_SPINCTRL_FOR_POINT_SIZE - EVT_SPINCTRL(wxID_FONT_SIZE, wxGenericFontDialog::OnChangeSize) - EVT_TEXT(wxID_FONT_SIZE, wxGenericFontDialog::OnChangeFont) -#else - EVT_CHOICE(wxID_FONT_SIZE, wxGenericFontDialog::OnChangeFont) -#endif - EVT_CLOSE(wxGenericFontDialog::OnCloseWindow) -END_EVENT_TABLE() - - -#define NUM_COLS 48 -static wxString wxColourDialogNames[NUM_COLS]={wxT("ORANGE"), - wxT("GOLDENROD"), - wxT("WHEAT"), - wxT("SPRING GREEN"), - wxT("SKY BLUE"), - wxT("SLATE BLUE"), - wxT("MEDIUM VIOLET RED"), - wxT("PURPLE"), - - wxT("RED"), - wxT("YELLOW"), - wxT("MEDIUM SPRING GREEN"), - wxT("PALE GREEN"), - wxT("CYAN"), - wxT("LIGHT STEEL BLUE"), - wxT("ORCHID"), - wxT("LIGHT MAGENTA"), - - wxT("BROWN"), - wxT("YELLOW"), - wxT("GREEN"), - wxT("CADET BLUE"), - wxT("MEDIUM BLUE"), - wxT("MAGENTA"), - wxT("MAROON"), - wxT("ORANGE RED"), - - wxT("FIREBRICK"), - wxT("CORAL"), - wxT("FOREST GREEN"), - wxT("AQUARAMINE"), - wxT("BLUE"), - wxT("NAVY"), - wxT("THISTLE"), - wxT("MEDIUM VIOLET RED"), - - wxT("INDIAN RED"), - wxT("GOLD"), - wxT("MEDIUM SEA GREEN"), - wxT("MEDIUM BLUE"), - wxT("MIDNIGHT BLUE"), - wxT("GREY"), - wxT("PURPLE"), - wxT("KHAKI"), - - wxT("BLACK"), - wxT("MEDIUM FOREST GREEN"), - wxT("KHAKI"), - wxT("DARK GREY"), - wxT("SEA GREEN"), - wxT("LIGHT GREY"), - wxT("MEDIUM SLATE BLUE"), - wxT("WHITE") - }; - -/* - * Generic wxFontDialog - */ - -void wxGenericFontDialog::Init() -{ - m_useEvents = false; - m_previewer = NULL; - Create( m_parent ) ; -} - -wxGenericFontDialog::~wxGenericFontDialog() -{ -} - -void wxGenericFontDialog::OnCloseWindow(wxCloseEvent& WXUNUSED(event)) -{ - EndModal(wxID_CANCEL); -} - -bool wxGenericFontDialog::DoCreate(wxWindow *parent) -{ - if ( !wxDialog::Create( parent , wxID_ANY , _T("Choose Font") , wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE, - _T("fontdialog") ) ) - { - wxFAIL_MSG( wxT("wxFontDialog creation failed") ); - return false; - } - - InitializeFont(); - CreateWidgets(); - - // sets initial font in preview area - DoChangeFont(); - - return true; -} - -int wxGenericFontDialog::ShowModal() -{ - int ret = wxDialog::ShowModal(); - - if (ret != wxID_CANCEL) - { - m_fontData.m_chosenFont = m_dialogFont; - } - - return ret; -} - -// This should be application-settable -static bool ShowToolTips() { return false; } - -void wxGenericFontDialog::CreateWidgets() -{ - wxString *families = new wxString[6], - *styles = new wxString[3], - *weights = new wxString[3]; - families[0] = _("Roman"); - families[1] = _("Decorative"); - families[2] = _("Modern"); - families[3] = _("Script"); - families[4] = _("Swiss" ); - families[5] = _("Teletype" ); - styles[0] = _("Normal"); - styles[1] = _("Italic"); - styles[2] = _("Slant"); - weights[0] = _("Normal"); - weights[1] = _("Light"); - weights[2] = _("Bold"); - -#if !USE_SPINCTRL_FOR_POINT_SIZE - wxString *pointSizes = new wxString[40]; - int i; - for ( i = 0; i < 40; i++) - { - wxChar buf[5]; - wxSprintf(buf, wxT("%d"), i + 1); - pointSizes[i] = buf; - } -#endif - - // layout - - bool is_pda = (wxSystemSettings::GetScreenType() <= wxSYS_SCREEN_PDA); - int noCols, noRows; - if (is_pda) - { - noCols = 2; noRows = 3; - } - else - { - noCols = 3; noRows = 2; - } - - wxBoxSizer* itemBoxSizer2 = new wxBoxSizer(wxVERTICAL); - this->SetSizer(itemBoxSizer2); - this->SetAutoLayout(true); - - wxBoxSizer* itemBoxSizer3 = new wxBoxSizer(wxVERTICAL); - itemBoxSizer2->Add(itemBoxSizer3, 1, wxGROW|wxALL, 5); - - wxFlexGridSizer* itemGridSizer4 = new wxFlexGridSizer(noRows, noCols, 0, 0); - itemBoxSizer3->Add(itemGridSizer4, 0, wxGROW, 5); - - wxBoxSizer* itemBoxSizer5 = new wxBoxSizer(wxVERTICAL); - itemGridSizer4->Add(itemBoxSizer5, 0, wxALIGN_CENTER_HORIZONTAL|wxGROW, 5); - wxStaticText* itemStaticText6 = new wxStaticText( this, wxID_STATIC, _("&Font family:"), wxDefaultPosition, wxDefaultSize, 0 ); - itemBoxSizer5->Add(itemStaticText6, 0, wxALIGN_LEFT|wxLEFT|wxRIGHT|wxTOP|wxADJUST_MINSIZE, 5); - - wxChoice* itemChoice7 = new wxChoice( this, wxID_FONT_FAMILY, wxDefaultPosition, wxDefaultSize, 5, families, 0 ); - itemChoice7->SetHelpText(_("The font family.")); - if (ShowToolTips()) - itemChoice7->SetToolTip(_("The font family.")); - itemBoxSizer5->Add(itemChoice7, 0, wxALIGN_LEFT|wxALL, 5); - - wxBoxSizer* itemBoxSizer8 = new wxBoxSizer(wxVERTICAL); - itemGridSizer4->Add(itemBoxSizer8, 0, wxALIGN_CENTER_HORIZONTAL|wxGROW, 5); - wxStaticText* itemStaticText9 = new wxStaticText( this, wxID_STATIC, _("&Style:"), wxDefaultPosition, wxDefaultSize, 0 ); - itemBoxSizer8->Add(itemStaticText9, 0, wxALIGN_LEFT|wxLEFT|wxRIGHT|wxTOP|wxADJUST_MINSIZE, 5); - - wxChoice* itemChoice10 = new wxChoice( this, wxID_FONT_STYLE, wxDefaultPosition, wxDefaultSize, 3, styles, 0 ); - itemChoice10->SetHelpText(_("The font style.")); - if (ShowToolTips()) - itemChoice10->SetToolTip(_("The font style.")); - itemBoxSizer8->Add(itemChoice10, 0, wxALIGN_LEFT|wxALL, 5); - - wxBoxSizer* itemBoxSizer11 = new wxBoxSizer(wxVERTICAL); - itemGridSizer4->Add(itemBoxSizer11, 0, wxALIGN_CENTER_HORIZONTAL|wxGROW, 5); - wxStaticText* itemStaticText12 = new wxStaticText( this, wxID_STATIC, _("&Weight:"), wxDefaultPosition, wxDefaultSize, 0 ); - itemBoxSizer11->Add(itemStaticText12, 0, wxALIGN_LEFT|wxLEFT|wxRIGHT|wxTOP|wxADJUST_MINSIZE, 5); - - wxChoice* itemChoice13 = new wxChoice( this, wxID_FONT_WEIGHT, wxDefaultPosition, wxDefaultSize, 3, weights, 0 ); - itemChoice13->SetHelpText(_("The font weight.")); - if (ShowToolTips()) - itemChoice13->SetToolTip(_("The font weight.")); - itemBoxSizer11->Add(itemChoice13, 0, wxALIGN_LEFT|wxALL, 5); - - wxBoxSizer* itemBoxSizer14 = new wxBoxSizer(wxVERTICAL); - itemGridSizer4->Add(itemBoxSizer14, 0, wxALIGN_CENTER_HORIZONTAL|wxGROW, 5); - if (m_fontData.GetEnableEffects()) - { - wxStaticText* itemStaticText15 = new wxStaticText( this, wxID_STATIC, _("C&olour:"), wxDefaultPosition, wxDefaultSize, 0 ); - itemBoxSizer14->Add(itemStaticText15, 0, wxALIGN_LEFT|wxLEFT|wxRIGHT|wxTOP|wxADJUST_MINSIZE, 5); - - wxSize colourSize = wxDefaultSize; - if (is_pda) - colourSize.x = 100; - - wxChoice* itemChoice16 = new wxChoice( this, wxID_FONT_COLOUR, wxDefaultPosition, colourSize, NUM_COLS, wxColourDialogNames, 0 ); - itemChoice16->SetHelpText(_("The font colour.")); - if (ShowToolTips()) - itemChoice16->SetToolTip(_("The font colour.")); - itemBoxSizer14->Add(itemChoice16, 0, wxALIGN_LEFT|wxALL, 5); - } - - wxBoxSizer* itemBoxSizer17 = new wxBoxSizer(wxVERTICAL); - itemGridSizer4->Add(itemBoxSizer17, 0, wxALIGN_CENTER_HORIZONTAL|wxGROW, 5); - wxStaticText* itemStaticText18 = new wxStaticText( this, wxID_STATIC, _("&Point size:"), wxDefaultPosition, wxDefaultSize, 0 ); - itemBoxSizer17->Add(itemStaticText18, 0, wxALIGN_LEFT|wxLEFT|wxRIGHT|wxTOP|wxADJUST_MINSIZE, 5); - -#if USE_SPINCTRL_FOR_POINT_SIZE - wxSpinCtrl* spinCtrl = new wxSpinCtrl(this, wxID_FONT_SIZE, wxT("12"), wxDefaultPosition, wxSize(80, wxDefaultCoord), wxSP_ARROW_KEYS, 1, 500, 12); - spinCtrl->SetHelpText(_("The font point size.")); - if (ShowToolTips()) - spinCtrl->SetToolTip(_("The font point size.")); - - itemBoxSizer17->Add(spinCtrl, 0, wxALIGN_LEFT|wxALL, 5); -#else - wxChoice* itemChoice19 = new wxChoice( this, wxID_FONT_SIZE, wxDefaultPosition, wxDefaultSize, 40, pointSizes, 0 ); - itemChoice19->SetHelpText(_("The font point size.")); - if (ShowToolTips()) - itemChoice19->SetToolTip(_("The font point size.")); - itemBoxSizer17->Add(itemChoice19, 0, wxALIGN_LEFT|wxALL, 5); -#endif - - if (m_fontData.GetEnableEffects()) - { - wxBoxSizer* itemBoxSizer20 = new wxBoxSizer(wxVERTICAL); - itemGridSizer4->Add(itemBoxSizer20, 0, wxALIGN_LEFT|wxALIGN_CENTER_VERTICAL, 5); - wxCheckBox* itemCheckBox21 = new wxCheckBox( this, wxID_FONT_UNDERLINE, _("&Underline"), wxDefaultPosition, wxDefaultSize, 0 ); - itemCheckBox21->SetValue(false); - itemCheckBox21->SetHelpText(_("Whether the font is underlined.")); - if (ShowToolTips()) - itemCheckBox21->SetToolTip(_("Whether the font is underlined.")); - itemBoxSizer20->Add(itemCheckBox21, 0, wxALIGN_LEFT|wxALL, 5); - } - - if (!is_pda) - itemBoxSizer3->Add(5, 5, 0, wxALIGN_CENTER_HORIZONTAL|wxALL, 5); - - wxStaticText* itemStaticText23 = new wxStaticText( this, wxID_STATIC, _("Preview:"), wxDefaultPosition, wxDefaultSize, 0 ); - itemBoxSizer3->Add(itemStaticText23, 0, wxALIGN_LEFT|wxLEFT|wxRIGHT|wxTOP|wxADJUST_MINSIZE, 5); - - wxFontPreviewer* itemWindow24 = new wxFontPreviewer( this ); - m_previewer = itemWindow24; - itemWindow24->SetHelpText(_("Shows the font preview.")); - if (ShowToolTips()) - itemWindow24->SetToolTip(_("Shows the font preview.")); - itemBoxSizer3->Add(itemWindow24, 1, wxGROW|wxALL, 5); - - wxBoxSizer* itemBoxSizer25 = new wxBoxSizer(wxHORIZONTAL); - itemBoxSizer3->Add(itemBoxSizer25, 0, wxGROW, 5); - itemBoxSizer25->Add(5, 5, 1, wxGROW|wxALL, 5); - -#ifdef __WXMAC__ - wxButton* itemButton28 = new wxButton( this, wxID_CANCEL, _("&Cancel"), wxDefaultPosition, wxDefaultSize, 0 ); - if (ShowToolTips()) - itemButton28->SetToolTip(_("Click to cancel the font selection.")); - itemBoxSizer25->Add(itemButton28, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5); - - wxButton* itemButton27 = new wxButton( this, wxID_OK, _("&OK"), wxDefaultPosition, wxDefaultSize, 0 ); - itemButton27->SetDefault(); - itemButton27->SetHelpText(_("Click to confirm the font selection.")); - if (ShowToolTips()) - itemButton27->SetToolTip(_("Click to confirm the font selection.")); - itemBoxSizer25->Add(itemButton27, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5); -#else - wxButton* itemButton27 = new wxButton( this, wxID_OK, _("&OK"), wxDefaultPosition, wxDefaultSize, 0 ); - itemButton27->SetDefault(); - itemButton27->SetHelpText(_("Click to confirm the font selection.")); - if (ShowToolTips()) - itemButton27->SetToolTip(_("Click to confirm the font selection.")); - itemBoxSizer25->Add(itemButton27, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5); - - wxButton* itemButton28 = new wxButton( this, wxID_CANCEL, _("&Cancel"), wxDefaultPosition, wxDefaultSize, 0 ); - if (ShowToolTips()) - itemButton28->SetToolTip(_("Click to cancel the font selection.")); - itemBoxSizer25->Add(itemButton28, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5); -#endif - - m_familyChoice = (wxChoice*) FindWindow(wxID_FONT_FAMILY); - m_styleChoice = (wxChoice*) FindWindow(wxID_FONT_STYLE); - m_weightChoice = (wxChoice*) FindWindow(wxID_FONT_WEIGHT); - m_colourChoice = (wxChoice*) FindWindow(wxID_FONT_COLOUR); - m_underLineCheckBox = (wxCheckBox*) FindWindow(wxID_FONT_UNDERLINE); - - m_familyChoice->SetStringSelection( wxFontFamilyIntToString(m_dialogFont.GetFamily()) ); - m_styleChoice->SetStringSelection(wxFontStyleIntToString(m_dialogFont.GetStyle())); - m_weightChoice->SetStringSelection(wxFontWeightIntToString(m_dialogFont.GetWeight())); - - if (m_colourChoice) - { - wxString name(wxTheColourDatabase->FindName(m_fontData.GetColour())); - if (name.length()) - m_colourChoice->SetStringSelection(name); - else - m_colourChoice->SetStringSelection(wxT("BLACK")); - } - - if (m_underLineCheckBox) - { - m_underLineCheckBox->SetValue(m_dialogFont.GetUnderlined()); - } - -#if USE_SPINCTRL_FOR_POINT_SIZE - spinCtrl->SetValue(m_dialogFont.GetPointSize()); -#else - m_pointSizeChoice = (wxChoice*) FindWindow(wxID_FONT_SIZE); - m_pointSizeChoice->SetSelection(m_dialogFont.GetPointSize()-1); -#endif - - GetSizer()->SetItemMinSize(m_previewer, is_pda ? 100 : 430, is_pda ? 40 : 100); - GetSizer()->SetSizeHints(this); - GetSizer()->Fit(this); - - Centre(wxBOTH); - - delete[] families; - delete[] styles; - delete[] weights; -#if !USE_SPINCTRL_FOR_POINT_SIZE - delete[] pointSizes; -#endif - - // Don't block events any more - m_useEvents = true; - -} - -void wxGenericFontDialog::InitializeFont() -{ - int fontFamily = wxSWISS; - int fontWeight = wxNORMAL; - int fontStyle = wxNORMAL; - int fontSize = 12; - bool fontUnderline = false; - - if (m_fontData.m_initialFont.Ok()) - { - fontFamily = m_fontData.m_initialFont.GetFamily(); - fontWeight = m_fontData.m_initialFont.GetWeight(); - fontStyle = m_fontData.m_initialFont.GetStyle(); - fontSize = m_fontData.m_initialFont.GetPointSize(); - fontUnderline = m_fontData.m_initialFont.GetUnderlined(); - } - - m_dialogFont = wxFont(fontSize, fontFamily, fontStyle, - fontWeight, fontUnderline); - - if (m_previewer) - m_previewer->SetFont(m_dialogFont); -} - -void wxGenericFontDialog::OnChangeFont(wxCommandEvent& WXUNUSED(event)) -{ - DoChangeFont(); -} - -void wxGenericFontDialog::DoChangeFont() -{ - if (!m_useEvents) return; - - int fontFamily = wxFontFamilyStringToInt(WXSTRINGCAST m_familyChoice->GetStringSelection()); - int fontWeight = wxFontWeightStringToInt(WXSTRINGCAST m_weightChoice->GetStringSelection()); - int fontStyle = wxFontStyleStringToInt(WXSTRINGCAST m_styleChoice->GetStringSelection()); -#if USE_SPINCTRL_FOR_POINT_SIZE - wxSpinCtrl* fontSizeCtrl = wxDynamicCast(FindWindow(wxID_FONT_SIZE), wxSpinCtrl); - int fontSize = fontSizeCtrl->GetValue(); -#else - int fontSize = wxAtoi(m_pointSizeChoice->GetStringSelection()); -#endif - - // Start with previous underline setting, we want to retain it even if we can't edit it - // m_dialogFont is always initialized because of the call to InitializeFont - int fontUnderline = m_dialogFont.GetUnderlined(); - - if (m_underLineCheckBox) - { - fontUnderline = m_underLineCheckBox->GetValue(); - } - - m_dialogFont = wxFont(fontSize, fontFamily, fontStyle, fontWeight, (fontUnderline != 0)); - m_previewer->SetFont(m_dialogFont); - - if ( m_colourChoice ) - { - if ( !m_colourChoice->GetStringSelection().empty() ) - { - wxColour col = wxTheColourDatabase->Find(m_colourChoice->GetStringSelection()); - if (col.Ok()) - { - m_fontData.m_fontColour = col; - } - } - } - // Update color here so that we can also use the color originally passed in - // (EnableEffects may be false) - if (m_fontData.m_fontColour.Ok()) - m_previewer->SetForegroundColour(m_fontData.m_fontColour); - - m_previewer->Refresh(); -} - -#if USE_SPINCTRL_FOR_POINT_SIZE -void wxGenericFontDialog::OnChangeSize(wxSpinEvent& WXUNUSED(event)) -{ - DoChangeFont(); -} -#endif - -const wxChar *wxFontWeightIntToString(int weight) -{ - switch (weight) - { - case wxLIGHT: - return wxT("Light"); - case wxBOLD: - return wxT("Bold"); - case wxNORMAL: - default: - return wxT("Normal"); - } -} - -const wxChar *wxFontStyleIntToString(int style) -{ - switch (style) - { - case wxITALIC: - return wxT("Italic"); - case wxSLANT: - return wxT("Slant"); - case wxNORMAL: - default: - return wxT("Normal"); - } -} - -const wxChar *wxFontFamilyIntToString(int family) -{ - switch (family) - { - case wxROMAN: - return wxT("Roman"); - case wxDECORATIVE: - return wxT("Decorative"); - case wxMODERN: - return wxT("Modern"); - case wxSCRIPT: - return wxT("Script"); - case wxTELETYPE: - return wxT("Teletype"); - case wxSWISS: - default: - return wxT("Swiss"); - } -} - -int wxFontFamilyStringToInt(wxChar *family) -{ - if (!family) - return wxSWISS; - - if (wxStrcmp(family, wxT("Roman")) == 0) - return wxROMAN; - else if (wxStrcmp(family, wxT("Decorative")) == 0) - return wxDECORATIVE; - else if (wxStrcmp(family, wxT("Modern")) == 0) - return wxMODERN; - else if (wxStrcmp(family, wxT("Script")) == 0) - return wxSCRIPT; - else if (wxStrcmp(family, wxT("Teletype")) == 0) - return wxTELETYPE; - else return wxSWISS; -} - -int wxFontStyleStringToInt(wxChar *style) -{ - if (!style) - return wxNORMAL; - if (wxStrcmp(style, wxT("Italic")) == 0) - return wxITALIC; - else if (wxStrcmp(style, wxT("Slant")) == 0) - return wxSLANT; - else - return wxNORMAL; -} - -int wxFontWeightStringToInt(wxChar *weight) -{ - if (!weight) - return wxNORMAL; - if (wxStrcmp(weight, wxT("Bold")) == 0) - return wxBOLD; - else if (wxStrcmp(weight, wxT("Light")) == 0) - return wxLIGHT; - else - return wxNORMAL; -} - -#endif - // wxUSE_FONTDLG +///////////////////////////////////////////////////////////////////////////// +// Name: src/generic/fontdlgg.cpp +// Purpose: Generic font dialog +// Author: Julian Smart +// Modified by: +// Created: 04/01/98 +// RCS-ID: $Id: fontdlgg.cpp 39627 2006-06-08 06:57:39Z ABX $ +// Copyright: (c) Julian Smart +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ +#pragma hdrstop +#endif + +#if wxUSE_FONTDLG && (!defined(__WXGTK__) || defined(__WXGPE__) || defined(__WXUNIVERSAL__)) + +#ifndef WX_PRECOMP + #include + #include "wx/utils.h" + #include "wx/dialog.h" + #include "wx/listbox.h" + #include "wx/button.h" + #include "wx/stattext.h" + #include "wx/layout.h" + #include "wx/dcclient.h" + #include "wx/choice.h" + #include "wx/checkbox.h" + #include "wx/intl.h" + #include "wx/settings.h" + #include "wx/cmndata.h" + #include "wx/sizer.h" +#endif + +#include +#include + +#include "wx/fontdlg.h" +#include "wx/generic/fontdlgg.h" + +#if USE_SPINCTRL_FOR_POINT_SIZE +#include "wx/spinctrl.h" +#endif + +//----------------------------------------------------------------------------- +// helper class - wxFontPreviewer +//----------------------------------------------------------------------------- + +class WXDLLEXPORT wxFontPreviewer : public wxWindow +{ +public: + wxFontPreviewer(wxWindow *parent, const wxSize& sz = wxDefaultSize) : wxWindow(parent, wxID_ANY, wxDefaultPosition, sz) + { + } + +private: + void OnPaint(wxPaintEvent& event); + DECLARE_EVENT_TABLE() +}; + +BEGIN_EVENT_TABLE(wxFontPreviewer, wxWindow) + EVT_PAINT(wxFontPreviewer::OnPaint) +END_EVENT_TABLE() + +void wxFontPreviewer::OnPaint(wxPaintEvent& WXUNUSED(event)) +{ + wxPaintDC dc(this); + + wxSize size = GetSize(); + wxFont font = GetFont(); + + dc.SetPen(*wxBLACK_PEN); + dc.SetBrush(*wxWHITE_BRUSH); + dc.DrawRectangle(0, 0, size.x, size.y); + + if ( font.Ok() ) + { + dc.SetFont(font); + // Calculate vertical centre + long w = 0, h = 0; + dc.GetTextExtent( wxT("X"), &w, &h); + dc.SetTextForeground(GetForegroundColour()); + dc.SetClippingRegion(2, 2, size.x-4, size.y-4); + dc.DrawText(_("ABCDEFGabcdefg12345"), + 10, size.y/2 - h/2); + dc.DestroyClippingRegion(); + } +} + +//----------------------------------------------------------------------------- +// wxGenericFontDialog +//----------------------------------------------------------------------------- + +IMPLEMENT_DYNAMIC_CLASS(wxGenericFontDialog, wxDialog) + +BEGIN_EVENT_TABLE(wxGenericFontDialog, wxDialog) + EVT_CHECKBOX(wxID_FONT_UNDERLINE, wxGenericFontDialog::OnChangeFont) + EVT_CHOICE(wxID_FONT_STYLE, wxGenericFontDialog::OnChangeFont) + EVT_CHOICE(wxID_FONT_WEIGHT, wxGenericFontDialog::OnChangeFont) + EVT_CHOICE(wxID_FONT_FAMILY, wxGenericFontDialog::OnChangeFont) + EVT_CHOICE(wxID_FONT_COLOUR, wxGenericFontDialog::OnChangeFont) +#if USE_SPINCTRL_FOR_POINT_SIZE + EVT_SPINCTRL(wxID_FONT_SIZE, wxGenericFontDialog::OnChangeSize) + EVT_TEXT(wxID_FONT_SIZE, wxGenericFontDialog::OnChangeFont) +#else + EVT_CHOICE(wxID_FONT_SIZE, wxGenericFontDialog::OnChangeFont) +#endif + EVT_CLOSE(wxGenericFontDialog::OnCloseWindow) +END_EVENT_TABLE() + + +#define NUM_COLS 48 +static wxString wxColourDialogNames[NUM_COLS]={wxT("ORANGE"), + wxT("GOLDENROD"), + wxT("WHEAT"), + wxT("SPRING GREEN"), + wxT("SKY BLUE"), + wxT("SLATE BLUE"), + wxT("MEDIUM VIOLET RED"), + wxT("PURPLE"), + + wxT("RED"), + wxT("YELLOW"), + wxT("MEDIUM SPRING GREEN"), + wxT("PALE GREEN"), + wxT("CYAN"), + wxT("LIGHT STEEL BLUE"), + wxT("ORCHID"), + wxT("LIGHT MAGENTA"), + + wxT("BROWN"), + wxT("YELLOW"), + wxT("GREEN"), + wxT("CADET BLUE"), + wxT("MEDIUM BLUE"), + wxT("MAGENTA"), + wxT("MAROON"), + wxT("ORANGE RED"), + + wxT("FIREBRICK"), + wxT("CORAL"), + wxT("FOREST GREEN"), + wxT("AQUARAMINE"), + wxT("BLUE"), + wxT("NAVY"), + wxT("THISTLE"), + wxT("MEDIUM VIOLET RED"), + + wxT("INDIAN RED"), + wxT("GOLD"), + wxT("MEDIUM SEA GREEN"), + wxT("MEDIUM BLUE"), + wxT("MIDNIGHT BLUE"), + wxT("GREY"), + wxT("PURPLE"), + wxT("KHAKI"), + + wxT("BLACK"), + wxT("MEDIUM FOREST GREEN"), + wxT("KHAKI"), + wxT("DARK GREY"), + wxT("SEA GREEN"), + wxT("LIGHT GREY"), + wxT("MEDIUM SLATE BLUE"), + wxT("WHITE") + }; + +/* + * Generic wxFontDialog + */ + +void wxGenericFontDialog::Init() +{ + m_useEvents = false; + m_previewer = NULL; + Create( m_parent ) ; +} + +wxGenericFontDialog::~wxGenericFontDialog() +{ +} + +void wxGenericFontDialog::OnCloseWindow(wxCloseEvent& WXUNUSED(event)) +{ + EndModal(wxID_CANCEL); +} + +bool wxGenericFontDialog::DoCreate(wxWindow *parent) +{ + if ( !wxDialog::Create( parent , wxID_ANY , _T("Choose Font") , wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE, + _T("fontdialog") ) ) + { + wxFAIL_MSG( wxT("wxFontDialog creation failed") ); + return false; + } + + InitializeFont(); + CreateWidgets(); + + // sets initial font in preview area + DoChangeFont(); + + return true; +} + +int wxGenericFontDialog::ShowModal() +{ + int ret = wxDialog::ShowModal(); + + if (ret != wxID_CANCEL) + { + m_fontData.m_chosenFont = m_dialogFont; + } + + return ret; +} + +// This should be application-settable +static bool ShowToolTips() { return false; } + +void wxGenericFontDialog::CreateWidgets() +{ + wxString *families = new wxString[6], + *styles = new wxString[3], + *weights = new wxString[3]; + families[0] = _("Roman"); + families[1] = _("Decorative"); + families[2] = _("Modern"); + families[3] = _("Script"); + families[4] = _("Swiss" ); + families[5] = _("Teletype" ); + styles[0] = _("Normal"); + styles[1] = _("Italic"); + styles[2] = _("Slant"); + weights[0] = _("Normal"); + weights[1] = _("Light"); + weights[2] = _("Bold"); + +#if !USE_SPINCTRL_FOR_POINT_SIZE + wxString *pointSizes = new wxString[40]; + int i; + for ( i = 0; i < 40; i++) + { + wxChar buf[5]; + wxSprintf(buf, wxT("%d"), i + 1); + pointSizes[i] = buf; + } +#endif + + // layout + + bool is_pda = (wxSystemSettings::GetScreenType() <= wxSYS_SCREEN_PDA); + int noCols, noRows; + if (is_pda) + { + noCols = 2; noRows = 3; + } + else + { + noCols = 3; noRows = 2; + } + + wxBoxSizer* itemBoxSizer2 = new wxBoxSizer(wxVERTICAL); + this->SetSizer(itemBoxSizer2); + this->SetAutoLayout(true); + + wxBoxSizer* itemBoxSizer3 = new wxBoxSizer(wxVERTICAL); + itemBoxSizer2->Add(itemBoxSizer3, 1, wxGROW|wxALL, 5); + + wxFlexGridSizer* itemGridSizer4 = new wxFlexGridSizer(noRows, noCols, 0, 0); + itemBoxSizer3->Add(itemGridSizer4, 0, wxGROW, 5); + + wxBoxSizer* itemBoxSizer5 = new wxBoxSizer(wxVERTICAL); + itemGridSizer4->Add(itemBoxSizer5, 0, wxALIGN_CENTER_HORIZONTAL|wxGROW, 5); + wxStaticText* itemStaticText6 = new wxStaticText( this, wxID_STATIC, _("&Font family:"), wxDefaultPosition, wxDefaultSize, 0 ); + itemBoxSizer5->Add(itemStaticText6, 0, wxALIGN_LEFT|wxLEFT|wxRIGHT|wxTOP|wxADJUST_MINSIZE, 5); + + wxChoice* itemChoice7 = new wxChoice( this, wxID_FONT_FAMILY, wxDefaultPosition, wxDefaultSize, 5, families, 0 ); + itemChoice7->SetHelpText(_("The font family.")); + if (ShowToolTips()) + itemChoice7->SetToolTip(_("The font family.")); + itemBoxSizer5->Add(itemChoice7, 0, wxALIGN_LEFT|wxALL, 5); + + wxBoxSizer* itemBoxSizer8 = new wxBoxSizer(wxVERTICAL); + itemGridSizer4->Add(itemBoxSizer8, 0, wxALIGN_CENTER_HORIZONTAL|wxGROW, 5); + wxStaticText* itemStaticText9 = new wxStaticText( this, wxID_STATIC, _("&Style:"), wxDefaultPosition, wxDefaultSize, 0 ); + itemBoxSizer8->Add(itemStaticText9, 0, wxALIGN_LEFT|wxLEFT|wxRIGHT|wxTOP|wxADJUST_MINSIZE, 5); + + wxChoice* itemChoice10 = new wxChoice( this, wxID_FONT_STYLE, wxDefaultPosition, wxDefaultSize, 3, styles, 0 ); + itemChoice10->SetHelpText(_("The font style.")); + if (ShowToolTips()) + itemChoice10->SetToolTip(_("The font style.")); + itemBoxSizer8->Add(itemChoice10, 0, wxALIGN_LEFT|wxALL, 5); + + wxBoxSizer* itemBoxSizer11 = new wxBoxSizer(wxVERTICAL); + itemGridSizer4->Add(itemBoxSizer11, 0, wxALIGN_CENTER_HORIZONTAL|wxGROW, 5); + wxStaticText* itemStaticText12 = new wxStaticText( this, wxID_STATIC, _("&Weight:"), wxDefaultPosition, wxDefaultSize, 0 ); + itemBoxSizer11->Add(itemStaticText12, 0, wxALIGN_LEFT|wxLEFT|wxRIGHT|wxTOP|wxADJUST_MINSIZE, 5); + + wxChoice* itemChoice13 = new wxChoice( this, wxID_FONT_WEIGHT, wxDefaultPosition, wxDefaultSize, 3, weights, 0 ); + itemChoice13->SetHelpText(_("The font weight.")); + if (ShowToolTips()) + itemChoice13->SetToolTip(_("The font weight.")); + itemBoxSizer11->Add(itemChoice13, 0, wxALIGN_LEFT|wxALL, 5); + + wxBoxSizer* itemBoxSizer14 = new wxBoxSizer(wxVERTICAL); + itemGridSizer4->Add(itemBoxSizer14, 0, wxALIGN_CENTER_HORIZONTAL|wxGROW, 5); + if (m_fontData.GetEnableEffects()) + { + wxStaticText* itemStaticText15 = new wxStaticText( this, wxID_STATIC, _("C&olour:"), wxDefaultPosition, wxDefaultSize, 0 ); + itemBoxSizer14->Add(itemStaticText15, 0, wxALIGN_LEFT|wxLEFT|wxRIGHT|wxTOP|wxADJUST_MINSIZE, 5); + + wxSize colourSize = wxDefaultSize; + if (is_pda) + colourSize.x = 100; + + wxChoice* itemChoice16 = new wxChoice( this, wxID_FONT_COLOUR, wxDefaultPosition, colourSize, NUM_COLS, wxColourDialogNames, 0 ); + itemChoice16->SetHelpText(_("The font colour.")); + if (ShowToolTips()) + itemChoice16->SetToolTip(_("The font colour.")); + itemBoxSizer14->Add(itemChoice16, 0, wxALIGN_LEFT|wxALL, 5); + } + + wxBoxSizer* itemBoxSizer17 = new wxBoxSizer(wxVERTICAL); + itemGridSizer4->Add(itemBoxSizer17, 0, wxALIGN_CENTER_HORIZONTAL|wxGROW, 5); + wxStaticText* itemStaticText18 = new wxStaticText( this, wxID_STATIC, _("&Point size:"), wxDefaultPosition, wxDefaultSize, 0 ); + itemBoxSizer17->Add(itemStaticText18, 0, wxALIGN_LEFT|wxLEFT|wxRIGHT|wxTOP|wxADJUST_MINSIZE, 5); + +#if USE_SPINCTRL_FOR_POINT_SIZE + wxSpinCtrl* spinCtrl = new wxSpinCtrl(this, wxID_FONT_SIZE, wxT("12"), wxDefaultPosition, wxSize(80, wxDefaultCoord), wxSP_ARROW_KEYS, 1, 500, 12); + spinCtrl->SetHelpText(_("The font point size.")); + if (ShowToolTips()) + spinCtrl->SetToolTip(_("The font point size.")); + + itemBoxSizer17->Add(spinCtrl, 0, wxALIGN_LEFT|wxALL, 5); +#else + wxChoice* itemChoice19 = new wxChoice( this, wxID_FONT_SIZE, wxDefaultPosition, wxDefaultSize, 40, pointSizes, 0 ); + itemChoice19->SetHelpText(_("The font point size.")); + if (ShowToolTips()) + itemChoice19->SetToolTip(_("The font point size.")); + itemBoxSizer17->Add(itemChoice19, 0, wxALIGN_LEFT|wxALL, 5); +#endif + + if (m_fontData.GetEnableEffects()) + { + wxBoxSizer* itemBoxSizer20 = new wxBoxSizer(wxVERTICAL); + itemGridSizer4->Add(itemBoxSizer20, 0, wxALIGN_LEFT|wxALIGN_CENTER_VERTICAL, 5); + wxCheckBox* itemCheckBox21 = new wxCheckBox( this, wxID_FONT_UNDERLINE, _("&Underline"), wxDefaultPosition, wxDefaultSize, 0 ); + itemCheckBox21->SetValue(false); + itemCheckBox21->SetHelpText(_("Whether the font is underlined.")); + if (ShowToolTips()) + itemCheckBox21->SetToolTip(_("Whether the font is underlined.")); + itemBoxSizer20->Add(itemCheckBox21, 0, wxALIGN_LEFT|wxALL, 5); + } + + if (!is_pda) + itemBoxSizer3->Add(5, 5, 0, wxALIGN_CENTER_HORIZONTAL|wxALL, 5); + + wxStaticText* itemStaticText23 = new wxStaticText( this, wxID_STATIC, _("Preview:"), wxDefaultPosition, wxDefaultSize, 0 ); + itemBoxSizer3->Add(itemStaticText23, 0, wxALIGN_LEFT|wxLEFT|wxRIGHT|wxTOP|wxADJUST_MINSIZE, 5); + + wxFontPreviewer* itemWindow24 = new wxFontPreviewer( this ); + m_previewer = itemWindow24; + itemWindow24->SetHelpText(_("Shows the font preview.")); + if (ShowToolTips()) + itemWindow24->SetToolTip(_("Shows the font preview.")); + itemBoxSizer3->Add(itemWindow24, 1, wxGROW|wxALL, 5); + + wxBoxSizer* itemBoxSizer25 = new wxBoxSizer(wxHORIZONTAL); + itemBoxSizer3->Add(itemBoxSizer25, 0, wxGROW, 5); + itemBoxSizer25->Add(5, 5, 1, wxGROW|wxALL, 5); + +#ifdef __WXMAC__ + wxButton* itemButton28 = new wxButton( this, wxID_CANCEL, _("&Cancel"), wxDefaultPosition, wxDefaultSize, 0 ); + if (ShowToolTips()) + itemButton28->SetToolTip(_("Click to cancel the font selection.")); + itemBoxSizer25->Add(itemButton28, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5); + + wxButton* itemButton27 = new wxButton( this, wxID_OK, _("&OK"), wxDefaultPosition, wxDefaultSize, 0 ); + itemButton27->SetDefault(); + itemButton27->SetHelpText(_("Click to confirm the font selection.")); + if (ShowToolTips()) + itemButton27->SetToolTip(_("Click to confirm the font selection.")); + itemBoxSizer25->Add(itemButton27, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5); +#else + wxButton* itemButton27 = new wxButton( this, wxID_OK, _("&OK"), wxDefaultPosition, wxDefaultSize, 0 ); + itemButton27->SetDefault(); + itemButton27->SetHelpText(_("Click to confirm the font selection.")); + if (ShowToolTips()) + itemButton27->SetToolTip(_("Click to confirm the font selection.")); + itemBoxSizer25->Add(itemButton27, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5); + + wxButton* itemButton28 = new wxButton( this, wxID_CANCEL, _("&Cancel"), wxDefaultPosition, wxDefaultSize, 0 ); + if (ShowToolTips()) + itemButton28->SetToolTip(_("Click to cancel the font selection.")); + itemBoxSizer25->Add(itemButton28, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5); +#endif + + m_familyChoice = (wxChoice*) FindWindow(wxID_FONT_FAMILY); + m_styleChoice = (wxChoice*) FindWindow(wxID_FONT_STYLE); + m_weightChoice = (wxChoice*) FindWindow(wxID_FONT_WEIGHT); + m_colourChoice = (wxChoice*) FindWindow(wxID_FONT_COLOUR); + m_underLineCheckBox = (wxCheckBox*) FindWindow(wxID_FONT_UNDERLINE); + + m_familyChoice->SetStringSelection( wxFontFamilyIntToString(m_dialogFont.GetFamily()) ); + m_styleChoice->SetStringSelection(wxFontStyleIntToString(m_dialogFont.GetStyle())); + m_weightChoice->SetStringSelection(wxFontWeightIntToString(m_dialogFont.GetWeight())); + + if (m_colourChoice) + { + wxString name(wxTheColourDatabase->FindName(m_fontData.GetColour())); + if (name.length()) + m_colourChoice->SetStringSelection(name); + else + m_colourChoice->SetStringSelection(wxT("BLACK")); + } + + if (m_underLineCheckBox) + { + m_underLineCheckBox->SetValue(m_dialogFont.GetUnderlined()); + } + +#if USE_SPINCTRL_FOR_POINT_SIZE + spinCtrl->SetValue(m_dialogFont.GetPointSize()); +#else + m_pointSizeChoice = (wxChoice*) FindWindow(wxID_FONT_SIZE); + m_pointSizeChoice->SetSelection(m_dialogFont.GetPointSize()-1); +#endif + + GetSizer()->SetItemMinSize(m_previewer, is_pda ? 100 : 430, is_pda ? 40 : 100); + GetSizer()->SetSizeHints(this); + GetSizer()->Fit(this); + + Centre(wxBOTH); + + delete[] families; + delete[] styles; + delete[] weights; +#if !USE_SPINCTRL_FOR_POINT_SIZE + delete[] pointSizes; +#endif + + // Don't block events any more + m_useEvents = true; + +} + +void wxGenericFontDialog::InitializeFont() +{ + int fontFamily = wxSWISS; + int fontWeight = wxNORMAL; + int fontStyle = wxNORMAL; + int fontSize = 12; + bool fontUnderline = false; + + if (m_fontData.m_initialFont.Ok()) + { + fontFamily = m_fontData.m_initialFont.GetFamily(); + fontWeight = m_fontData.m_initialFont.GetWeight(); + fontStyle = m_fontData.m_initialFont.GetStyle(); + fontSize = m_fontData.m_initialFont.GetPointSize(); + fontUnderline = m_fontData.m_initialFont.GetUnderlined(); + } + + m_dialogFont = wxFont(fontSize, fontFamily, fontStyle, + fontWeight, fontUnderline); + + if (m_previewer) + m_previewer->SetFont(m_dialogFont); +} + +void wxGenericFontDialog::OnChangeFont(wxCommandEvent& WXUNUSED(event)) +{ + DoChangeFont(); +} + +void wxGenericFontDialog::DoChangeFont() +{ + if (!m_useEvents) return; + + int fontFamily = wxFontFamilyStringToInt(WXSTRINGCAST m_familyChoice->GetStringSelection()); + int fontWeight = wxFontWeightStringToInt(WXSTRINGCAST m_weightChoice->GetStringSelection()); + int fontStyle = wxFontStyleStringToInt(WXSTRINGCAST m_styleChoice->GetStringSelection()); +#if USE_SPINCTRL_FOR_POINT_SIZE + wxSpinCtrl* fontSizeCtrl = wxDynamicCast(FindWindow(wxID_FONT_SIZE), wxSpinCtrl); + int fontSize = fontSizeCtrl->GetValue(); +#else + int fontSize = wxAtoi(m_pointSizeChoice->GetStringSelection()); +#endif + + // Start with previous underline setting, we want to retain it even if we can't edit it + // m_dialogFont is always initialized because of the call to InitializeFont + int fontUnderline = m_dialogFont.GetUnderlined(); + + if (m_underLineCheckBox) + { + fontUnderline = m_underLineCheckBox->GetValue(); + } + + m_dialogFont = wxFont(fontSize, fontFamily, fontStyle, fontWeight, (fontUnderline != 0)); + m_previewer->SetFont(m_dialogFont); + + if ( m_colourChoice ) + { + if ( !m_colourChoice->GetStringSelection().empty() ) + { + wxColour col = wxTheColourDatabase->Find(m_colourChoice->GetStringSelection()); + if (col.Ok()) + { + m_fontData.m_fontColour = col; + } + } + } + // Update color here so that we can also use the color originally passed in + // (EnableEffects may be false) + if (m_fontData.m_fontColour.Ok()) + m_previewer->SetForegroundColour(m_fontData.m_fontColour); + + m_previewer->Refresh(); +} + +#if USE_SPINCTRL_FOR_POINT_SIZE +void wxGenericFontDialog::OnChangeSize(wxSpinEvent& WXUNUSED(event)) +{ + DoChangeFont(); +} +#endif + +const wxChar *wxFontWeightIntToString(int weight) +{ + switch (weight) + { + case wxLIGHT: + return wxT("Light"); + case wxBOLD: + return wxT("Bold"); + case wxNORMAL: + default: + return wxT("Normal"); + } +} + +const wxChar *wxFontStyleIntToString(int style) +{ + switch (style) + { + case wxITALIC: + return wxT("Italic"); + case wxSLANT: + return wxT("Slant"); + case wxNORMAL: + default: + return wxT("Normal"); + } +} + +const wxChar *wxFontFamilyIntToString(int family) +{ + switch (family) + { + case wxROMAN: + return wxT("Roman"); + case wxDECORATIVE: + return wxT("Decorative"); + case wxMODERN: + return wxT("Modern"); + case wxSCRIPT: + return wxT("Script"); + case wxTELETYPE: + return wxT("Teletype"); + case wxSWISS: + default: + return wxT("Swiss"); + } +} + +int wxFontFamilyStringToInt(wxChar *family) +{ + if (!family) + return wxSWISS; + + if (wxStrcmp(family, wxT("Roman")) == 0) + return wxROMAN; + else if (wxStrcmp(family, wxT("Decorative")) == 0) + return wxDECORATIVE; + else if (wxStrcmp(family, wxT("Modern")) == 0) + return wxMODERN; + else if (wxStrcmp(family, wxT("Script")) == 0) + return wxSCRIPT; + else if (wxStrcmp(family, wxT("Teletype")) == 0) + return wxTELETYPE; + else return wxSWISS; +} + +int wxFontStyleStringToInt(wxChar *style) +{ + if (!style) + return wxNORMAL; + if (wxStrcmp(style, wxT("Italic")) == 0) + return wxITALIC; + else if (wxStrcmp(style, wxT("Slant")) == 0) + return wxSLANT; + else + return wxNORMAL; +} + +int wxFontWeightStringToInt(wxChar *weight) +{ + if (!weight) + return wxNORMAL; + if (wxStrcmp(weight, wxT("Bold")) == 0) + return wxBOLD; + else if (wxStrcmp(weight, wxT("Light")) == 0) + return wxLIGHT; + else + return wxNORMAL; +} + +#endif + // wxUSE_FONTDLG diff --git a/Externals/wxWidgets/src/generic/fontpickerg.cpp b/Externals/wxWidgets/src/generic/fontpickerg.cpp index e01bcd544e..7c42f54657 100644 --- a/Externals/wxWidgets/src/generic/fontpickerg.cpp +++ b/Externals/wxWidgets/src/generic/fontpickerg.cpp @@ -1,120 +1,120 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: src/generic/fontpickerg.cpp -// Purpose: wxGenericFontButton class implementation -// Author: Francesco Montorsi -// Modified by: -// Created: 15/04/2006 -// RCS-ID: $Id: fontpickerg.cpp 52835 2008-03-26 15:49:08Z JS $ -// Copyright: (c) Francesco Montorsi -// Licence: wxWindows licence -/////////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_FONTPICKERCTRL - -#include "wx/fontpicker.h" - -#include "wx/fontdlg.h" - - -// ============================================================================ -// implementation -// ============================================================================ - -wxFontData wxGenericFontButton::ms_data; -IMPLEMENT_DYNAMIC_CLASS(wxGenericFontButton, wxButton) - -// ---------------------------------------------------------------------------- -// wxGenericFontButton -// ---------------------------------------------------------------------------- - -bool wxGenericFontButton::Create( wxWindow *parent, wxWindowID id, - const wxFont &initial, const wxPoint &pos, - const wxSize &size, long style, - const wxValidator& validator, const wxString &name) -{ - wxString label = (style & wxFNTP_FONTDESC_AS_LABEL) ? - wxEmptyString : // label will be updated by UpdateFont - wxT("Choose font"); - - // create this button - if (!wxButton::Create( parent, id, label, pos, - size, style, validator, name )) - { - wxFAIL_MSG( wxT("wxGenericFontButton creation failed") ); - return false; - } - - // and handle user clicks on it - Connect(GetId(), wxEVT_COMMAND_BUTTON_CLICKED, - wxCommandEventHandler(wxGenericFontButton::OnButtonClick), - NULL, this); - - m_selectedFont = initial.IsOk() ? initial : *wxNORMAL_FONT; - UpdateFont(); - InitFontData(); - - return true; -} - -void wxGenericFontButton::InitFontData() -{ - ms_data.SetAllowSymbols(true); - ms_data.SetColour(*wxBLACK); - ms_data.EnableEffects(true); -} - -void wxGenericFontButton::OnButtonClick(wxCommandEvent& WXUNUSED(ev)) -{ - // update the wxFontData to be shown in the the dialog - ms_data.SetInitialFont(m_selectedFont); - - // create the font dialog and display it - wxFontDialog dlg(this, ms_data); - if (dlg.ShowModal() == wxID_OK) - { - ms_data = dlg.GetFontData(); - SetSelectedFont(ms_data.GetChosenFont()); - - // fire an event - wxFontPickerEvent event(this, GetId(), m_selectedFont); - GetEventHandler()->ProcessEvent(event); - } -} - -void wxGenericFontButton::UpdateFont() -{ - if ( !m_selectedFont.Ok() ) - return; - - SetForegroundColour(ms_data.GetColour()); - - if (HasFlag(wxFNTP_USEFONT_FOR_LABEL)) - { - // use currently selected font for the label... - wxButton::SetFont(m_selectedFont); - } - - if (HasFlag(wxFNTP_FONTDESC_AS_LABEL)) - { - SetLabel(wxString::Format(wxT("%s, %d"), - m_selectedFont.GetFaceName().c_str(), - m_selectedFont.GetPointSize())); - } -} - -#endif // wxUSE_FONTPICKERCTRL +/////////////////////////////////////////////////////////////////////////////// +// Name: src/generic/fontpickerg.cpp +// Purpose: wxGenericFontButton class implementation +// Author: Francesco Montorsi +// Modified by: +// Created: 15/04/2006 +// RCS-ID: $Id: fontpickerg.cpp 52835 2008-03-26 15:49:08Z JS $ +// Copyright: (c) Francesco Montorsi +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_FONTPICKERCTRL + +#include "wx/fontpicker.h" + +#include "wx/fontdlg.h" + + +// ============================================================================ +// implementation +// ============================================================================ + +wxFontData wxGenericFontButton::ms_data; +IMPLEMENT_DYNAMIC_CLASS(wxGenericFontButton, wxButton) + +// ---------------------------------------------------------------------------- +// wxGenericFontButton +// ---------------------------------------------------------------------------- + +bool wxGenericFontButton::Create( wxWindow *parent, wxWindowID id, + const wxFont &initial, const wxPoint &pos, + const wxSize &size, long style, + const wxValidator& validator, const wxString &name) +{ + wxString label = (style & wxFNTP_FONTDESC_AS_LABEL) ? + wxEmptyString : // label will be updated by UpdateFont + wxT("Choose font"); + + // create this button + if (!wxButton::Create( parent, id, label, pos, + size, style, validator, name )) + { + wxFAIL_MSG( wxT("wxGenericFontButton creation failed") ); + return false; + } + + // and handle user clicks on it + Connect(GetId(), wxEVT_COMMAND_BUTTON_CLICKED, + wxCommandEventHandler(wxGenericFontButton::OnButtonClick), + NULL, this); + + m_selectedFont = initial.IsOk() ? initial : *wxNORMAL_FONT; + UpdateFont(); + InitFontData(); + + return true; +} + +void wxGenericFontButton::InitFontData() +{ + ms_data.SetAllowSymbols(true); + ms_data.SetColour(*wxBLACK); + ms_data.EnableEffects(true); +} + +void wxGenericFontButton::OnButtonClick(wxCommandEvent& WXUNUSED(ev)) +{ + // update the wxFontData to be shown in the the dialog + ms_data.SetInitialFont(m_selectedFont); + + // create the font dialog and display it + wxFontDialog dlg(this, ms_data); + if (dlg.ShowModal() == wxID_OK) + { + ms_data = dlg.GetFontData(); + SetSelectedFont(ms_data.GetChosenFont()); + + // fire an event + wxFontPickerEvent event(this, GetId(), m_selectedFont); + GetEventHandler()->ProcessEvent(event); + } +} + +void wxGenericFontButton::UpdateFont() +{ + if ( !m_selectedFont.Ok() ) + return; + + SetForegroundColour(ms_data.GetColour()); + + if (HasFlag(wxFNTP_USEFONT_FOR_LABEL)) + { + // use currently selected font for the label... + wxButton::SetFont(m_selectedFont); + } + + if (HasFlag(wxFNTP_FONTDESC_AS_LABEL)) + { + SetLabel(wxString::Format(wxT("%s, %d"), + m_selectedFont.GetFaceName().c_str(), + m_selectedFont.GetPointSize())); + } +} + +#endif // wxUSE_FONTPICKERCTRL diff --git a/Externals/wxWidgets/src/generic/graphicc.cpp b/Externals/wxWidgets/src/generic/graphicc.cpp index 53b4fa881e..4ba4e04083 100644 --- a/Externals/wxWidgets/src/generic/graphicc.cpp +++ b/Externals/wxWidgets/src/generic/graphicc.cpp @@ -1,1510 +1,1510 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/generic/graphicc.cpp -// Purpose: cairo device context class -// Author: Stefan Csomor -// Modified by: -// Created: 2006-10-03 -// RCS-ID: $Id: graphicc.cpp 51312 2008-01-21 16:30:13Z VS $ -// Copyright: (c) 2006 Stefan Csomor -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -#include "wx/wxprec.h" - -#include "wx/dc.h" - -#ifdef __BORLANDC__ -#pragma hdrstop -#endif - -#ifndef WX_PRECOMP -#include "wx/image.h" -#include "wx/window.h" -#include "wx/dc.h" -#include "wx/utils.h" -#include "wx/dialog.h" -#include "wx/app.h" -#include "wx/bitmap.h" -#include "wx/dcmemory.h" -#include "wx/log.h" -#include "wx/icon.h" -#include "wx/dcprint.h" -#include "wx/module.h" -#endif - -#ifdef __WXGTK__ -#include "wx/gtk/win_gtk.h" -#endif - -#include "wx/graphics.h" -#include "wx/rawbmp.h" - -#if wxUSE_GRAPHICS_CONTEXT - -#include - -using namespace std; - -//----------------------------------------------------------------------------- -// constants -//----------------------------------------------------------------------------- - -const double RAD2DEG = 180.0 / M_PI; - -//----------------------------------------------------------------------------- -// Local functions -//----------------------------------------------------------------------------- - -static inline double dmin(double a, double b) -{ - return a < b ? a : b; -} -static inline double dmax(double a, double b) -{ - return a > b ? a : b; -} - -static inline double DegToRad(double deg) -{ - return (deg * M_PI) / 180.0; -} -static inline double RadToDeg(double deg) -{ - return (deg * 180.0) / M_PI; -} - -//----------------------------------------------------------------------------- -// device context implementation -// -// more and more of the dc functionality should be implemented by calling -// the appropricate wxCairoContext, but we will have to do that step by step -// also coordinate conversions should be moved to native matrix ops -//----------------------------------------------------------------------------- - -// we always stock two context states, one at entry, to be able to preserve the -// state we were called with, the other one after changing to HI Graphics orientation -// (this one is used for getting back clippings etc) - -//----------------------------------------------------------------------------- -// wxGraphicsPath implementation -//----------------------------------------------------------------------------- - -// TODO remove this dependency (gdiplus needs the macros) - -#ifndef max -#define max(a,b) (((a) > (b)) ? (a) : (b)) -#endif - -#ifndef min -#define min(a,b) (((a) < (b)) ? (a) : (b)) -#endif - -#include -#ifdef __WXGTK__ -#include -#endif - -class WXDLLIMPEXP_CORE wxCairoPathData : public wxGraphicsPathData -{ -public : - wxCairoPathData(wxGraphicsRenderer* renderer, cairo_t* path = NULL); - ~wxCairoPathData(); - - virtual wxGraphicsObjectRefData *Clone() const; - - // - // These are the path primitives from which everything else can be constructed - // - - // begins a new subpath at (x,y) - virtual void MoveToPoint( wxDouble x, wxDouble y ); - - // adds a straight line from the current point to (x,y) - virtual void AddLineToPoint( wxDouble x, wxDouble y ); - - // adds a cubic Bezier curve from the current point, using two control points and an end point - virtual void AddCurveToPoint( wxDouble cx1, wxDouble cy1, wxDouble cx2, wxDouble cy2, wxDouble x, wxDouble y ); - - - // adds an arc of a circle centering at (x,y) with radius (r) from startAngle to endAngle - virtual void AddArc( wxDouble x, wxDouble y, wxDouble r, wxDouble startAngle, wxDouble endAngle, bool clockwise ) ; - - // gets the last point of the current path, (0,0) if not yet set - virtual void GetCurrentPoint( wxDouble* x, wxDouble* y) const; - - // adds another path - virtual void AddPath( const wxGraphicsPathData* path ); - - // closes the current sub-path - virtual void CloseSubpath(); - - // - // These are convenience functions which - if not available natively will be assembled - // using the primitives from above - // - - /* - - // appends a rectangle as a new closed subpath - virtual void AddRectangle( wxDouble x, wxDouble y, wxDouble w, wxDouble h ) ; - // appends an ellipsis as a new closed subpath fitting the passed rectangle - virtual void AddEllipsis( wxDouble x, wxDouble y, wxDouble w , wxDouble h ) ; - - // draws a an arc to two tangents connecting (current) to (x1,y1) and (x1,y1) to (x2,y2), also a straight line from (current) to (x1,y1) - virtual void AddArcToPoint( wxDouble x1, wxDouble y1 , wxDouble x2, wxDouble y2, wxDouble r ) ; - */ - - // returns the native path - virtual void * GetNativePath() const ; - - // give the native path returned by GetNativePath() back (there might be some deallocations necessary) - virtual void UnGetNativePath(void *p) const; - - // transforms each point of this path by the matrix - virtual void Transform( const wxGraphicsMatrixData* matrix ) ; - - // gets the bounding box enclosing all points (possibly including control points) - virtual void GetBox(wxDouble *x, wxDouble *y, wxDouble *w, wxDouble *h) const; - - virtual bool Contains( wxDouble x, wxDouble y, int fillStyle = wxWINDING_RULE) const; - -private : - cairo_t* m_pathContext; -}; - -class WXDLLIMPEXP_CORE wxCairoMatrixData : public wxGraphicsMatrixData -{ -public : - wxCairoMatrixData(wxGraphicsRenderer* renderer, const cairo_matrix_t* matrix = NULL ) ; - virtual ~wxCairoMatrixData() ; - - virtual wxGraphicsObjectRefData *Clone() const ; - - // concatenates the matrix - virtual void Concat( const wxGraphicsMatrixData *t ); - - // sets the matrix to the respective values - virtual void Set(wxDouble a=1.0, wxDouble b=0.0, wxDouble c=0.0, wxDouble d=1.0, - wxDouble tx=0.0, wxDouble ty=0.0); - - // gets the component valuess of the matrix - virtual void Get(wxDouble* a=NULL, wxDouble* b=NULL, wxDouble* c=NULL, - wxDouble* d=NULL, wxDouble* tx=NULL, wxDouble* ty=NULL) const; - - // makes this the inverse matrix - virtual void Invert(); - - // returns true if the elements of the transformation matrix are equal ? - virtual bool IsEqual( const wxGraphicsMatrixData* t) const ; - - // return true if this is the identity matrix - virtual bool IsIdentity() const; - - // - // transformation - // - - // add the translation to this matrix - virtual void Translate( wxDouble dx , wxDouble dy ); - - // add the scale to this matrix - virtual void Scale( wxDouble xScale , wxDouble yScale ); - - // add the rotation to this matrix (radians) - virtual void Rotate( wxDouble angle ); - - // - // apply the transforms - // - - // applies that matrix to the point - virtual void TransformPoint( wxDouble *x, wxDouble *y ) const; - - // applies the matrix except for translations - virtual void TransformDistance( wxDouble *dx, wxDouble *dy ) const; - - // returns the native representation - virtual void * GetNativeMatrix() const; -private: - cairo_matrix_t m_matrix ; -} ; - -class WXDLLIMPEXP_CORE wxCairoPenData : public wxGraphicsObjectRefData -{ -public: - wxCairoPenData( wxGraphicsRenderer* renderer, const wxPen &pen ); - ~wxCairoPenData(); - - void Init(); - - virtual void Apply( wxGraphicsContext* context ); - virtual wxDouble GetWidth() { return m_width; } - -private : - double m_width; - - double m_red; - double m_green; - double m_blue; - double m_alpha; - - cairo_line_cap_t m_cap; - cairo_line_join_t m_join; - - int m_count; - const double *m_lengths; - double *m_userLengths; - - wxPen m_pen; -}; - -class WXDLLIMPEXP_CORE wxCairoBrushData : public wxGraphicsObjectRefData -{ -public: - wxCairoBrushData( wxGraphicsRenderer* renderer ); - wxCairoBrushData( wxGraphicsRenderer* renderer, const wxBrush &brush ); - ~wxCairoBrushData (); - - virtual void Apply( wxGraphicsContext* context ); - void CreateLinearGradientBrush( wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2, - const wxColour&c1, const wxColour&c2 ); - void CreateRadialGradientBrush( wxDouble xo, wxDouble yo, wxDouble xc, wxDouble yc, wxDouble radius, - const wxColour &oColor, const wxColour &cColor ); - -protected: - virtual void Init(); - -private : - double m_red; - double m_green; - double m_blue; - double m_alpha; - - cairo_pattern_t* m_brushPattern; -}; - -class wxCairoFontData : public wxGraphicsObjectRefData -{ -public: - wxCairoFontData( wxGraphicsRenderer* renderer, const wxFont &font, const wxColour& col ); - ~wxCairoFontData(); - - virtual void Apply( wxGraphicsContext* context ); -private : - wxCharBuffer m_fontName; - double m_size; - cairo_font_slant_t m_slant; - cairo_font_weight_t m_weight; - double m_red; - double m_green; - double m_blue; - double m_alpha; -}; - -class WXDLLIMPEXP_CORE wxCairoContext : public wxGraphicsContext -{ - DECLARE_NO_COPY_CLASS(wxCairoContext) - -public: - wxCairoContext( wxGraphicsRenderer* renderer, const wxWindowDC& dc ); -#ifdef __WXGTK__ - wxCairoContext( wxGraphicsRenderer* renderer, GdkDrawable *drawable ); -#endif - wxCairoContext( wxGraphicsRenderer* renderer, cairo_t *context ); - wxCairoContext( wxGraphicsRenderer* renderer, wxWindow *window); - wxCairoContext(); - virtual ~wxCairoContext(); - - virtual void Clip( const wxRegion ®ion ); - - // clips drawings to the rect - virtual void Clip( wxDouble x, wxDouble y, wxDouble w, wxDouble h ); - - // resets the clipping to original extent - virtual void ResetClip(); - - virtual void * GetNativeContext(); - - virtual void StrokePath( const wxGraphicsPath& p ); - virtual void FillPath( const wxGraphicsPath& p , int fillStyle = wxWINDING_RULE ); - - virtual void Translate( wxDouble dx , wxDouble dy ); - virtual void Scale( wxDouble xScale , wxDouble yScale ); - virtual void Rotate( wxDouble angle ); - - // concatenates this transform with the current transform of this context - virtual void ConcatTransform( const wxGraphicsMatrix& matrix ); - - // sets the transform of this context - virtual void SetTransform( const wxGraphicsMatrix& matrix ); - - // gets the matrix of this context - virtual wxGraphicsMatrix GetTransform() const; - - virtual void DrawBitmap( const wxBitmap &bmp, wxDouble x, wxDouble y, wxDouble w, wxDouble h ); - virtual void DrawIcon( const wxIcon &icon, wxDouble x, wxDouble y, wxDouble w, wxDouble h ); - virtual void PushState(); - virtual void PopState(); - - virtual void DrawText( const wxString &str, wxDouble x, wxDouble y); - virtual void GetTextExtent( const wxString &str, wxDouble *width, wxDouble *height, - wxDouble *descent, wxDouble *externalLeading ) const; - virtual void GetPartialTextExtents(const wxString& text, wxArrayDouble& widths) const; - -private: - cairo_t* m_context; -}; - -//----------------------------------------------------------------------------- -// wxCairoPenData implementation -//----------------------------------------------------------------------------- - -wxCairoPenData::~wxCairoPenData() -{ - delete[] m_userLengths; -} - -void wxCairoPenData::Init() -{ - m_lengths = NULL; - m_userLengths = NULL; - m_width = 0; - m_count = 0; -} - -wxCairoPenData::wxCairoPenData( wxGraphicsRenderer* renderer, const wxPen &pen ) -: wxGraphicsObjectRefData(renderer) -{ - Init(); - m_pen = pen; - m_width = m_pen.GetWidth(); - if (m_width <= 0.0) - m_width = 0.1; - - m_red = m_pen.GetColour().Red()/255.0; - m_green = m_pen.GetColour().Green()/255.0; - m_blue = m_pen.GetColour().Blue()/255.0; - m_alpha = m_pen.GetColour().Alpha()/255.0; - - switch ( m_pen.GetCap() ) - { - case wxCAP_ROUND : - m_cap = CAIRO_LINE_CAP_ROUND; - break; - - case wxCAP_PROJECTING : - m_cap = CAIRO_LINE_CAP_SQUARE; - break; - - case wxCAP_BUTT : - m_cap = CAIRO_LINE_CAP_BUTT; - break; - - default : - m_cap = CAIRO_LINE_CAP_BUTT; - break; - } - - switch ( m_pen.GetJoin() ) - { - case wxJOIN_BEVEL : - m_join = CAIRO_LINE_JOIN_BEVEL; - break; - - case wxJOIN_MITER : - m_join = CAIRO_LINE_JOIN_MITER; - break; - - case wxJOIN_ROUND : - m_join = CAIRO_LINE_JOIN_ROUND; - break; - - default : - m_join = CAIRO_LINE_JOIN_MITER; - break; - } - - const double dashUnit = m_width < 1.0 ? 1.0 : m_width; - const double dotted[] = - { - dashUnit , dashUnit + 2.0 - }; - static const double short_dashed[] = - { - 9.0 , 6.0 - }; - static const double dashed[] = - { - 19.0 , 9.0 - }; - static const double dotted_dashed[] = - { - 9.0 , 6.0 , 3.0 , 3.0 - }; - - switch ( m_pen.GetStyle() ) - { - case wxSOLID : - break; - - case wxDOT : - m_count = WXSIZEOF(dotted); - m_userLengths = new double[ m_count ] ; - memcpy( m_userLengths, dotted, sizeof(dotted) ); - m_lengths = m_userLengths; - break; - - case wxLONG_DASH : - m_lengths = dotted ; - m_count = WXSIZEOF(dashed); - break; - - case wxSHORT_DASH : - m_lengths = dotted ; - m_count = WXSIZEOF(short_dashed); - break; - - case wxDOT_DASH : - m_lengths = dotted ; - m_count = WXSIZEOF(dotted_dashed); - break; - - case wxUSER_DASH : - { - wxDash *wxdashes ; - m_count = m_pen.GetDashes( &wxdashes ) ; - if ((wxdashes != NULL) && (m_count > 0)) - { - m_userLengths = new double[m_count] ; - for ( int i = 0 ; i < m_count ; ++i ) - { - m_userLengths[i] = wxdashes[i] * dashUnit ; - - if ( i % 2 == 1 && m_userLengths[i] < dashUnit + 2.0 ) - m_userLengths[i] = dashUnit + 2.0 ; - else if ( i % 2 == 0 && m_userLengths[i] < dashUnit ) - m_userLengths[i] = dashUnit ; - } - } - m_lengths = m_userLengths ; - } - break; - case wxSTIPPLE : - { - /* - wxBitmap* bmp = pen.GetStipple(); - if ( bmp && bmp->Ok() ) - { - wxDELETE( m_penImage ); - wxDELETE( m_penBrush ); - m_penImage = Bitmap::FromHBITMAP((HBITMAP)bmp->GetHBITMAP(),(HPALETTE)bmp->GetPalette()->GetHPALETTE()); - m_penBrush = new TextureBrush(m_penImage); - m_pen->SetBrush( m_penBrush ); - } - */ - } - break; - default : - if ( m_pen.GetStyle() >= wxFIRST_HATCH && m_pen.GetStyle() <= wxLAST_HATCH ) - { - /* - wxDELETE( m_penBrush ); - HatchStyle style = HatchStyleHorizontal; - switch( pen.GetStyle() ) - { - case wxBDIAGONAL_HATCH : - style = HatchStyleBackwardDiagonal; - break ; - case wxCROSSDIAG_HATCH : - style = HatchStyleDiagonalCross; - break ; - case wxFDIAGONAL_HATCH : - style = HatchStyleForwardDiagonal; - break ; - case wxCROSS_HATCH : - style = HatchStyleCross; - break ; - case wxHORIZONTAL_HATCH : - style = HatchStyleHorizontal; - break ; - case wxVERTICAL_HATCH : - style = HatchStyleVertical; - break ; - - } - m_penBrush = new HatchBrush(style,Color( pen.GetColour().Alpha() , pen.GetColour().Red() , - pen.GetColour().Green() , pen.GetColour().Blue() ), Color.Transparent ); - m_pen->SetBrush( m_penBrush ) - */ - } - break; - } -} - -void wxCairoPenData::Apply( wxGraphicsContext* context ) -{ - cairo_t * ctext = (cairo_t*) context->GetNativeContext(); - cairo_set_line_width(ctext,m_width); - cairo_set_source_rgba(ctext,m_red,m_green, m_blue,m_alpha); - cairo_set_line_cap(ctext,m_cap); - cairo_set_line_join(ctext,m_join); - cairo_set_dash(ctext,(double*)m_lengths,m_count,0.0); -} - -//----------------------------------------------------------------------------- -// wxCairoBrushData implementation -//----------------------------------------------------------------------------- - -wxCairoBrushData::wxCairoBrushData( wxGraphicsRenderer* renderer ) - : wxGraphicsObjectRefData( renderer ) -{ - Init(); -} - -wxCairoBrushData::wxCairoBrushData( wxGraphicsRenderer* renderer, const wxBrush &brush ) - : wxGraphicsObjectRefData(renderer) -{ - Init(); - - m_red = brush.GetColour().Red()/255.0; - m_green = brush.GetColour().Green()/255.0; - m_blue = brush.GetColour().Blue()/255.0; - m_alpha = brush.GetColour().Alpha()/255.0; - /* - if ( brush.GetStyle() == wxSOLID) - { - m_brush = new SolidBrush( Color( brush.GetColour().Alpha() , brush.GetColour().Red() , - brush.GetColour().Green() , brush.GetColour().Blue() ) ); - } - else if ( brush.IsHatch() ) - { - HatchStyle style = HatchStyleHorizontal; - switch( brush.GetStyle() ) - { - case wxBDIAGONAL_HATCH : - style = HatchStyleBackwardDiagonal; - break ; - case wxCROSSDIAG_HATCH : - style = HatchStyleDiagonalCross; - break ; - case wxFDIAGONAL_HATCH : - style = HatchStyleForwardDiagonal; - break ; - case wxCROSS_HATCH : - style = HatchStyleCross; - break ; - case wxHORIZONTAL_HATCH : - style = HatchStyleHorizontal; - break ; - case wxVERTICAL_HATCH : - style = HatchStyleVertical; - break ; - - } - m_brush = new HatchBrush(style,Color( brush.GetColour().Alpha() , brush.GetColour().Red() , - brush.GetColour().Green() , brush.GetColour().Blue() ), Color.Transparent ); - } - else - { - wxBitmap* bmp = brush.GetStipple(); - if ( bmp && bmp->Ok() ) - { - wxDELETE( m_brushImage ); - m_brushImage = Bitmap::FromHBITMAP((HBITMAP)bmp->GetHBITMAP(),(HPALETTE)bmp->GetPalette()->GetHPALETTE()); - m_brush = new TextureBrush(m_brushImage); - } - } - */ -} - -wxCairoBrushData::~wxCairoBrushData () -{ - if (m_brushPattern) - cairo_pattern_destroy(m_brushPattern); -} - -void wxCairoBrushData::Apply( wxGraphicsContext* context ) -{ - cairo_t * ctext = (cairo_t*) context->GetNativeContext(); - if ( m_brushPattern ) - { - cairo_set_source(ctext,m_brushPattern); - } - else - { - cairo_set_source_rgba(ctext,m_red,m_green, m_blue,m_alpha); - } -} - -void wxCairoBrushData::CreateLinearGradientBrush( wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2, - const wxColour&c1, const wxColour&c2 ) -{ - m_brushPattern = cairo_pattern_create_linear(x1,y1,x2,y2); - cairo_pattern_add_color_stop_rgba(m_brushPattern,0.0,c1.Red()/255.0, - c1.Green()/255.0, c1.Blue()/255.0,c1.Alpha()/255.0); - cairo_pattern_add_color_stop_rgba(m_brushPattern,1.0,c2.Red()/255.0, - c2.Green()/255.0, c2.Blue()/255.0,c2.Alpha()/255.0); - wxASSERT_MSG(cairo_pattern_status(m_brushPattern) == CAIRO_STATUS_SUCCESS, wxT("Couldn't create cairo pattern")); -} - -void wxCairoBrushData::CreateRadialGradientBrush( wxDouble xo, wxDouble yo, wxDouble xc, wxDouble yc, wxDouble radius, - const wxColour &oColor, const wxColour &cColor ) -{ - m_brushPattern = cairo_pattern_create_radial(xo,yo,0.0,xc,yc,radius); - cairo_pattern_add_color_stop_rgba(m_brushPattern,0.0,oColor.Red()/255.0, - oColor.Green()/255.0, oColor.Blue()/255.0,oColor.Alpha()/255.0); - cairo_pattern_add_color_stop_rgba(m_brushPattern,1.0,cColor.Red()/255.0, - cColor.Green()/255.0, cColor.Blue()/255.0,cColor.Alpha()/255.0); - wxASSERT_MSG(cairo_pattern_status(m_brushPattern) == CAIRO_STATUS_SUCCESS, wxT("Couldn't create cairo pattern")); -} - -void wxCairoBrushData::Init() -{ - m_brushPattern = NULL; -} - -//----------------------------------------------------------------------------- -// wxCairoFontData implementation -//----------------------------------------------------------------------------- - -wxCairoFontData::wxCairoFontData( wxGraphicsRenderer* renderer, const wxFont &font, - const wxColour& col ) : wxGraphicsObjectRefData(renderer) -{ - m_red = col.Red()/255.0; - m_green = col.Green()/255.0; - m_blue = col.Blue()/255.0; - m_alpha = col.Alpha()/255.0; - - m_size = font.GetPointSize(); - m_fontName = font.GetFaceName().mb_str(wxConvUTF8); - m_slant = font.GetStyle() == wxFONTSTYLE_ITALIC ? CAIRO_FONT_SLANT_ITALIC:CAIRO_FONT_SLANT_NORMAL; - m_weight = font.GetWeight() == wxFONTWEIGHT_BOLD ? CAIRO_FONT_WEIGHT_BOLD:CAIRO_FONT_WEIGHT_NORMAL; -} - -wxCairoFontData::~wxCairoFontData() -{ -} - -void wxCairoFontData::Apply( wxGraphicsContext* context ) -{ - cairo_t * ctext = (cairo_t*) context->GetNativeContext(); - cairo_set_source_rgba(ctext,m_red,m_green, m_blue,m_alpha); - cairo_select_font_face(ctext,m_fontName,m_slant,m_weight); - cairo_set_font_size(ctext,m_size); - // TODO UNDERLINE - // TODO FIX SIZE -} - -//----------------------------------------------------------------------------- -// wxCairoPathData implementation -//----------------------------------------------------------------------------- - -wxCairoPathData::wxCairoPathData( wxGraphicsRenderer* renderer, cairo_t* pathcontext) - : wxGraphicsPathData(renderer) -{ - if (pathcontext) - { - m_pathContext = pathcontext; - } - else - { - cairo_surface_t* surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,1,1); - m_pathContext = cairo_create(surface); - cairo_surface_destroy (surface); - } -} - -wxCairoPathData::~wxCairoPathData() -{ - cairo_destroy(m_pathContext); -} - -wxGraphicsObjectRefData *wxCairoPathData::Clone() const -{ - cairo_surface_t* surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,1,1); - cairo_t* pathcontext = cairo_create(surface); - cairo_surface_destroy (surface); - - cairo_path_t* path = cairo_copy_path(m_pathContext); - cairo_append_path(pathcontext, path); - cairo_path_destroy(path); - return new wxCairoPathData( GetRenderer() ,pathcontext); -} - - -void* wxCairoPathData::GetNativePath() const -{ - return cairo_copy_path(m_pathContext) ; -} - -void wxCairoPathData::UnGetNativePath(void *p) const -{ - cairo_path_destroy((cairo_path_t*)p); -} - -// -// The Primitives -// - -void wxCairoPathData::MoveToPoint( wxDouble x , wxDouble y ) -{ - cairo_move_to(m_pathContext,x,y); -} - -void wxCairoPathData::AddLineToPoint( wxDouble x , wxDouble y ) -{ - cairo_line_to(m_pathContext,x,y); -} - -void wxCairoPathData::AddPath( const wxGraphicsPathData* path ) -{ - cairo_path_t* p = (cairo_path_t*)path->GetNativePath(); - cairo_append_path(m_pathContext, p); - UnGetNativePath(p); -} - -void wxCairoPathData::CloseSubpath() -{ - cairo_close_path(m_pathContext); -} - -void wxCairoPathData::AddCurveToPoint( wxDouble cx1, wxDouble cy1, wxDouble cx2, wxDouble cy2, wxDouble x, wxDouble y ) -{ - cairo_curve_to(m_pathContext,cx1,cy1,cx2,cy2,x,y); -} - -// gets the last point of the current path, (0,0) if not yet set -void wxCairoPathData::GetCurrentPoint( wxDouble* x, wxDouble* y) const -{ - double dx,dy; - cairo_get_current_point(m_pathContext,&dx,&dy); - if (x) - *x = dx; - if (y) - *y = dy; -} - -void wxCairoPathData::AddArc( wxDouble x, wxDouble y, wxDouble r, double startAngle, double endAngle, bool clockwise ) -{ - // as clockwise means positive in our system (y pointing downwards) - // TODO make this interpretation dependent of the - // real device trans - if ( clockwise||(endAngle-startAngle)>=2*M_PI) - cairo_arc(m_pathContext,x,y,r,startAngle,endAngle); - else - cairo_arc_negative(m_pathContext,x,y,r,startAngle,endAngle); -} - -// transforms each point of this path by the matrix -void wxCairoPathData::Transform( const wxGraphicsMatrixData* matrix ) -{ - // as we don't have a true path object, we have to apply the inverse - // matrix to the context - cairo_matrix_t m = *((cairo_matrix_t*) matrix->GetNativeMatrix()); - cairo_matrix_invert( &m ); - cairo_transform(m_pathContext,&m); -} - -// gets the bounding box enclosing all points (possibly including control points) -void wxCairoPathData::GetBox(wxDouble *x, wxDouble *y, wxDouble *w, wxDouble *h) const -{ - double x1,y1,x2,y2; - - cairo_stroke_extents( m_pathContext, &x1, &y1, &x2, &y2 ); - if ( x2 < x1 ) - { - *x = x2; - *w = x1-x2; - } - else - { - *x = x1; - *w = x2-x1; - } - - if( y2 < y1 ) - { - *y = y2; - *h = y1-y2; - } - else - { - *y = y1; - *h = y2-y1; - } -} - -bool wxCairoPathData::Contains( wxDouble x, wxDouble y, int fillStyle ) const -{ - return cairo_in_stroke( m_pathContext, x, y) != 0; -} - -//----------------------------------------------------------------------------- -// wxCairoMatrixData implementation -//----------------------------------------------------------------------------- - -wxCairoMatrixData::wxCairoMatrixData(wxGraphicsRenderer* renderer, const cairo_matrix_t* matrix ) - : wxGraphicsMatrixData(renderer) -{ - if ( matrix ) - m_matrix = *matrix; -} - -wxCairoMatrixData::~wxCairoMatrixData() -{ - // nothing to do -} - -wxGraphicsObjectRefData *wxCairoMatrixData::Clone() const -{ - return new wxCairoMatrixData(GetRenderer(),&m_matrix); -} - -// concatenates the matrix -void wxCairoMatrixData::Concat( const wxGraphicsMatrixData *t ) -{ - cairo_matrix_multiply( &m_matrix, &m_matrix, (cairo_matrix_t*) t->GetNativeMatrix()); -} - -// sets the matrix to the respective values -void wxCairoMatrixData::Set(wxDouble a, wxDouble b, wxDouble c, wxDouble d, - wxDouble tx, wxDouble ty) -{ - cairo_matrix_init( &m_matrix, a, b, c, d, tx, ty); -} - -// gets the component valuess of the matrix -void wxCairoMatrixData::Get(wxDouble* a, wxDouble* b, wxDouble* c, - wxDouble* d, wxDouble* tx, wxDouble* ty) const -{ - if (a) *a = m_matrix.xx; - if (b) *b = m_matrix.yx; - if (c) *c = m_matrix.xy; - if (d) *d = m_matrix.yy; - if (tx) *tx= m_matrix.x0; - if (ty) *ty= m_matrix.y0; -} - -// makes this the inverse matrix -void wxCairoMatrixData::Invert() -{ - cairo_matrix_invert( &m_matrix ); -} - -// returns true if the elements of the transformation matrix are equal ? -bool wxCairoMatrixData::IsEqual( const wxGraphicsMatrixData* t) const -{ - const cairo_matrix_t* tm = (cairo_matrix_t*) t->GetNativeMatrix(); - return ( - m_matrix.xx == tm->xx && - m_matrix.yx == tm->yx && - m_matrix.xy == tm->xy && - m_matrix.yy == tm->yy && - m_matrix.x0 == tm->x0 && - m_matrix.y0 == tm->y0 ) ; -} - -// return true if this is the identity matrix -bool wxCairoMatrixData::IsIdentity() const -{ - return ( m_matrix.xx == 1 && m_matrix.yy == 1 && - m_matrix.yx == 0 && m_matrix.xy == 0 && m_matrix.x0 == 0 && m_matrix.y0 == 0); -} - -// -// transformation -// - -// add the translation to this matrix -void wxCairoMatrixData::Translate( wxDouble dx , wxDouble dy ) -{ - cairo_matrix_translate( &m_matrix, dx, dy) ; -} - -// add the scale to this matrix -void wxCairoMatrixData::Scale( wxDouble xScale , wxDouble yScale ) -{ - cairo_matrix_scale( &m_matrix, xScale, yScale) ; -} - -// add the rotation to this matrix (radians) -void wxCairoMatrixData::Rotate( wxDouble angle ) -{ - cairo_matrix_rotate( &m_matrix, angle) ; -} - -// -// apply the transforms -// - -// applies that matrix to the point -void wxCairoMatrixData::TransformPoint( wxDouble *x, wxDouble *y ) const -{ - double lx = *x, ly = *y ; - cairo_matrix_transform_point( &m_matrix, &lx, &ly); - *x = lx; - *y = ly; -} - -// applies the matrix except for translations -void wxCairoMatrixData::TransformDistance( wxDouble *dx, wxDouble *dy ) const -{ - double lx = *dx, ly = *dy ; - cairo_matrix_transform_distance( &m_matrix, &lx, &ly); - *dx = lx; - *dy = ly; -} - -// returns the native representation -void * wxCairoMatrixData::GetNativeMatrix() const -{ - return (void*) &m_matrix; -} - -//----------------------------------------------------------------------------- -// wxCairoContext implementation -//----------------------------------------------------------------------------- - -wxCairoContext::wxCairoContext( wxGraphicsRenderer* renderer, const wxWindowDC& dc ) -: wxGraphicsContext(renderer) -{ -#ifdef __WXGTK__ - m_context = gdk_cairo_create( dc.m_window ) ; -#endif - PushState(); - PushState(); -} - -#ifdef __WXGTK__ -wxCairoContext::wxCairoContext( wxGraphicsRenderer* renderer, GdkDrawable *drawable ) -: wxGraphicsContext(renderer) -{ - m_context = gdk_cairo_create( drawable ) ; - PushState(); - PushState(); -} -#endif - -wxCairoContext::wxCairoContext( wxGraphicsRenderer* renderer, cairo_t *context ) -: wxGraphicsContext(renderer) -{ - m_context = context ; - PushState(); - PushState(); -} - -wxCairoContext::wxCairoContext( wxGraphicsRenderer* renderer, wxWindow *window) -: wxGraphicsContext(renderer) -{ -#ifdef __WXGTK__ - // something along these lines (copied from dcclient) - - GtkWidget *widget = window->m_wxwindow; - - // Some controls don't have m_wxwindow - like wxStaticBox, but the user - // code should still be able to create wxClientDCs for them, so we will - // use the parent window here then. - if ( !widget ) - { - window = window->GetParent(); - widget = window->m_wxwindow; - } - - wxASSERT_MSG( widget, wxT("wxCairoContext needs a widget") ); - - GtkPizza *pizza = GTK_PIZZA( widget ); - GdkDrawable* drawable = pizza->bin_window; - m_context = gdk_cairo_create( drawable ) ; -#endif - PushState(); - PushState(); -} - -wxCairoContext::~wxCairoContext() -{ - if ( m_context ) - { - PopState(); - PopState(); - cairo_destroy(m_context); - } -} - - -void wxCairoContext::Clip( const wxRegion& region ) -{ - // Create a path with all the rectangles in the region - wxGraphicsPath path = GetRenderer()->CreatePath(); - wxRegionIterator ri(region); - while (ri) - { - path.AddRectangle(ri.GetX(), ri.GetY(), ri.GetW(), ri.GetH()); - ri++; - } - - // Put it in the context - cairo_path_t* cp = (cairo_path_t*) path.GetNativePath() ; - cairo_append_path(m_context, cp); - - // clip to that path - cairo_clip(m_context); - path.UnGetNativePath(cp); -} - -void wxCairoContext::Clip( wxDouble x, wxDouble y, wxDouble w, wxDouble h ) -{ - // Create a path with this rectangle - wxGraphicsPath path = GetRenderer()->CreatePath(); - path.AddRectangle(x,y,w,h); - - // Put it in the context - cairo_path_t* cp = (cairo_path_t*) path.GetNativePath() ; - cairo_append_path(m_context, cp); - - // clip to that path - cairo_clip(m_context); - path.UnGetNativePath(cp); -} - -void wxCairoContext::ResetClip() -{ - cairo_reset_clip(m_context); -} - - -void wxCairoContext::StrokePath( const wxGraphicsPath& path ) -{ - if ( !m_pen.IsNull() ) - { - cairo_path_t* cp = (cairo_path_t*) path.GetNativePath() ; - cairo_append_path(m_context,cp); - ((wxCairoPenData*)m_pen.GetRefData())->Apply(this); - cairo_stroke(m_context); - path.UnGetNativePath(cp); - } -} - -void wxCairoContext::FillPath( const wxGraphicsPath& path , int fillStyle ) -{ - if ( !m_brush.IsNull() ) - { - cairo_path_t* cp = (cairo_path_t*) path.GetNativePath() ; - cairo_append_path(m_context,cp); - ((wxCairoBrushData*)m_brush.GetRefData())->Apply(this); - cairo_set_fill_rule(m_context,fillStyle==wxODDEVEN_RULE ? CAIRO_FILL_RULE_EVEN_ODD : CAIRO_FILL_RULE_WINDING); - cairo_fill(m_context); - path.UnGetNativePath(cp); - } -} - -void wxCairoContext::Rotate( wxDouble angle ) -{ - cairo_rotate(m_context,angle); -} - -void wxCairoContext::Translate( wxDouble dx , wxDouble dy ) -{ - cairo_translate(m_context,dx,dy); -} - -void wxCairoContext::Scale( wxDouble xScale , wxDouble yScale ) -{ - cairo_scale(m_context,xScale,yScale); -} - -// concatenates this transform with the current transform of this context -void wxCairoContext::ConcatTransform( const wxGraphicsMatrix& matrix ) -{ - cairo_transform(m_context,(const cairo_matrix_t *) matrix.GetNativeMatrix()); -} - -// sets the transform of this context -void wxCairoContext::SetTransform( const wxGraphicsMatrix& matrix ) -{ - cairo_set_matrix(m_context,(const cairo_matrix_t*) matrix.GetNativeMatrix()); -} - -// gets the matrix of this context -wxGraphicsMatrix wxCairoContext::GetTransform() const -{ - wxGraphicsMatrix matrix = CreateMatrix(); - cairo_get_matrix(m_context,(cairo_matrix_t*) matrix.GetNativeMatrix()); - return matrix; -} - - - -void wxCairoContext::PushState() -{ - cairo_save(m_context); -} - -void wxCairoContext::PopState() -{ - cairo_restore(m_context); -} - -void wxCairoContext::DrawBitmap( const wxBitmap &bmp, wxDouble x, wxDouble y, wxDouble w, wxDouble h ) -{ - wxCHECK_RET( bmp.IsOk(), wxT("Invalid bitmap in wxCairoContext::DrawBitmap")); - - cairo_surface_t* surface; - int bw = bmp.GetWidth(); - int bh = bmp.GetHeight(); - wxBitmap bmpSource = bmp; // we need a non-const instance - unsigned char* buffer = new unsigned char[bw*bh*4]; - wxUint32* data = (wxUint32*)buffer; - - // Create a surface object and copy the bitmap pixel data to it. if the - // image has alpha (or a mask represented as alpha) then we'll use a - // different format and iterator than if it doesn't... - if (bmpSource.HasAlpha() || bmpSource.GetMask()) - { - surface = cairo_image_surface_create_for_data( - buffer, CAIRO_FORMAT_ARGB32, bw, bh, bw*4); - wxAlphaPixelData pixData(bmpSource, wxPoint(0,0), wxSize(bw, bh)); - wxCHECK_RET( pixData, wxT("Failed to gain raw access to bitmap data.")); - - wxAlphaPixelData::Iterator p(pixData); - for (int y=0; yApply(this); - - // Cairo's x,y for drawing text is at the baseline, so we need to adjust - // the position we move to by the ascent. - cairo_font_extents_t fe; - cairo_font_extents(m_context, &fe); - cairo_move_to(m_context, x, y+fe.ascent); - - const wxWX2MBbuf buf(str.mb_str(wxConvUTF8)); - cairo_show_text(m_context,buf); -} - -void wxCairoContext::GetTextExtent( const wxString &str, wxDouble *width, wxDouble *height, - wxDouble *descent, wxDouble *externalLeading ) const -{ - if ( m_font.IsNull() || str.empty()) - return; - - ((wxCairoFontData*)m_font.GetRefData())->Apply((wxCairoContext*)this); - - if (width) - { - const wxWX2MBbuf buf(str.mb_str(wxConvUTF8)); - cairo_text_extents_t te; - cairo_text_extents(m_context, buf, &te); - *width = te.width; - } - - if (height || descent || externalLeading) - { - cairo_font_extents_t fe; - cairo_font_extents(m_context, &fe); - - if (height) - *height = fe.height; - if ( descent ) - *descent = fe.descent; - if ( externalLeading ) - *externalLeading = wxMax(0, fe.height - (fe.ascent + fe.descent)); - } -} - -void wxCairoContext::GetPartialTextExtents(const wxString& text, wxArrayDouble& widths) const -{ - widths.Empty(); - widths.Add(0, text.length()); - - if (text.empty()) - return; - - // TODO -} - -void * wxCairoContext::GetNativeContext() -{ - return m_context; -} - -//----------------------------------------------------------------------------- -// wxCairoRenderer declaration -//----------------------------------------------------------------------------- - -class WXDLLIMPEXP_CORE wxCairoRenderer : public wxGraphicsRenderer -{ -public : - wxCairoRenderer() {} - - virtual ~wxCairoRenderer() {} - - // Context - - virtual wxGraphicsContext * CreateContext( const wxWindowDC& dc); - -#ifdef __WXMSW__ - virtual wxGraphicsContext * CreateContext( const wxMemoryDC& dc); -#endif - - virtual wxGraphicsContext * CreateContextFromNativeContext( void * context ); - - virtual wxGraphicsContext * CreateContextFromNativeWindow( void * window ); - - virtual wxGraphicsContext * CreateContext( wxWindow* window ); - - virtual wxGraphicsContext * CreateMeasuringContext(); - - // Path - - virtual wxGraphicsPath CreatePath(); - - // Matrix - - virtual wxGraphicsMatrix CreateMatrix( wxDouble a=1.0, wxDouble b=0.0, wxDouble c=0.0, wxDouble d=1.0, - wxDouble tx=0.0, wxDouble ty=0.0); - - - virtual wxGraphicsPen CreatePen(const wxPen& pen) ; - - virtual wxGraphicsBrush CreateBrush(const wxBrush& brush ) ; - - // sets the brush to a linear gradient, starting at (x1,y1) with color c1 to (x2,y2) with color c2 - virtual wxGraphicsBrush CreateLinearGradientBrush( wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2, - const wxColour&c1, const wxColour&c2) ; - - // sets the brush to a radial gradient originating at (xo,yc) with color oColor and ends on a circle around (xc,yc) - // with radius r and color cColor - virtual wxGraphicsBrush CreateRadialGradientBrush( wxDouble xo, wxDouble yo, wxDouble xc, wxDouble yc, wxDouble radius, - const wxColour &oColor, const wxColour &cColor) ; - - // sets the font - virtual wxGraphicsFont CreateFont( const wxFont &font , const wxColour &col = *wxBLACK ) ; - -private : - DECLARE_DYNAMIC_CLASS_NO_COPY(wxCairoRenderer) -} ; - -//----------------------------------------------------------------------------- -// wxCairoRenderer implementation -//----------------------------------------------------------------------------- - -IMPLEMENT_DYNAMIC_CLASS(wxCairoRenderer,wxGraphicsRenderer) - -static wxCairoRenderer gs_cairoGraphicsRenderer; - -#ifdef __WXGTK__ -wxGraphicsRenderer* wxGraphicsRenderer::GetDefaultRenderer() -{ - return &gs_cairoGraphicsRenderer; -} -#endif - -wxGraphicsContext * wxCairoRenderer::CreateContext( const wxWindowDC& dc) -{ - return new wxCairoContext(this,dc); -} - -#ifdef __WXMSW__ -wxGraphicsContext * wxCairoRenderer::CreateContext( const wxMemoryDC& dc) -{ - return NULL; -} -#endif - -wxGraphicsContext * wxCairoRenderer::CreateContextFromNativeContext( void * context ) -{ - return new wxCairoContext(this,(cairo_t*)context); -} - - -wxGraphicsContext * wxCairoRenderer::CreateContextFromNativeWindow( void * window ) -{ -#ifdef __WXGTK__ - return new wxCairoContext(this,(GdkDrawable*)window); -#else - return NULL; -#endif -} - -wxGraphicsContext * wxCairoRenderer::CreateMeasuringContext() -{ - return NULL; - // TODO -} - -wxGraphicsContext * wxCairoRenderer::CreateContext( wxWindow* window ) -{ - return new wxCairoContext(this, window ); -} - -// Path - -wxGraphicsPath wxCairoRenderer::CreatePath() -{ - wxGraphicsPath path; - path.SetRefData( new wxCairoPathData(this) ); - return path; -} - - -// Matrix - -wxGraphicsMatrix wxCairoRenderer::CreateMatrix( wxDouble a, wxDouble b, wxDouble c, wxDouble d, - wxDouble tx, wxDouble ty) - -{ - wxGraphicsMatrix m; - wxCairoMatrixData* data = new wxCairoMatrixData( this ); - data->Set( a,b,c,d,tx,ty ) ; - m.SetRefData(data); - return m; -} - -wxGraphicsPen wxCairoRenderer::CreatePen(const wxPen& pen) -{ - if ( !pen.Ok() || pen.GetStyle() == wxTRANSPARENT ) - return wxNullGraphicsPen; - else - { - wxGraphicsPen p; - p.SetRefData(new wxCairoPenData( this, pen )); - return p; - } -} - -wxGraphicsBrush wxCairoRenderer::CreateBrush(const wxBrush& brush ) -{ - if ( !brush.Ok() || brush.GetStyle() == wxTRANSPARENT ) - return wxNullGraphicsBrush; - else - { - wxGraphicsBrush p; - p.SetRefData(new wxCairoBrushData( this, brush )); - return p; - } -} - -// sets the brush to a linear gradient, starting at (x1,y1) with color c1 to (x2,y2) with color c2 -wxGraphicsBrush wxCairoRenderer::CreateLinearGradientBrush( wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2, - const wxColour&c1, const wxColour&c2) -{ - wxGraphicsBrush p; - wxCairoBrushData* d = new wxCairoBrushData( this ); - d->CreateLinearGradientBrush(x1, y1, x2, y2, c1, c2); - p.SetRefData(d); - return p; -} - -// sets the brush to a radial gradient originating at (xo,yc) with color oColor and ends on a circle around (xc,yc) -// with radius r and color cColor -wxGraphicsBrush wxCairoRenderer::CreateRadialGradientBrush( wxDouble xo, wxDouble yo, wxDouble xc, wxDouble yc, wxDouble radius, - const wxColour &oColor, const wxColour &cColor) -{ - wxGraphicsBrush p; - wxCairoBrushData* d = new wxCairoBrushData( this ); - d->CreateRadialGradientBrush(xo,yo,xc,yc,radius,oColor,cColor); - p.SetRefData(d); - return p; -} - -// sets the font -wxGraphicsFont wxCairoRenderer::CreateFont( const wxFont &font , const wxColour &col ) -{ - if ( font.Ok() ) - { - wxGraphicsFont p; - p.SetRefData(new wxCairoFontData( this , font, col )); - return p; - } - else - return wxNullGraphicsFont; -} - -#endif // wxUSE_GRAPHICS_CONTEXT +///////////////////////////////////////////////////////////////////////////// +// Name: src/generic/graphicc.cpp +// Purpose: cairo device context class +// Author: Stefan Csomor +// Modified by: +// Created: 2006-10-03 +// RCS-ID: $Id: graphicc.cpp 51312 2008-01-21 16:30:13Z VS $ +// Copyright: (c) 2006 Stefan Csomor +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#include "wx/wxprec.h" + +#include "wx/dc.h" + +#ifdef __BORLANDC__ +#pragma hdrstop +#endif + +#ifndef WX_PRECOMP +#include "wx/image.h" +#include "wx/window.h" +#include "wx/dc.h" +#include "wx/utils.h" +#include "wx/dialog.h" +#include "wx/app.h" +#include "wx/bitmap.h" +#include "wx/dcmemory.h" +#include "wx/log.h" +#include "wx/icon.h" +#include "wx/dcprint.h" +#include "wx/module.h" +#endif + +#ifdef __WXGTK__ +#include "wx/gtk/win_gtk.h" +#endif + +#include "wx/graphics.h" +#include "wx/rawbmp.h" + +#if wxUSE_GRAPHICS_CONTEXT + +#include + +using namespace std; + +//----------------------------------------------------------------------------- +// constants +//----------------------------------------------------------------------------- + +const double RAD2DEG = 180.0 / M_PI; + +//----------------------------------------------------------------------------- +// Local functions +//----------------------------------------------------------------------------- + +static inline double dmin(double a, double b) +{ + return a < b ? a : b; +} +static inline double dmax(double a, double b) +{ + return a > b ? a : b; +} + +static inline double DegToRad(double deg) +{ + return (deg * M_PI) / 180.0; +} +static inline double RadToDeg(double deg) +{ + return (deg * 180.0) / M_PI; +} + +//----------------------------------------------------------------------------- +// device context implementation +// +// more and more of the dc functionality should be implemented by calling +// the appropricate wxCairoContext, but we will have to do that step by step +// also coordinate conversions should be moved to native matrix ops +//----------------------------------------------------------------------------- + +// we always stock two context states, one at entry, to be able to preserve the +// state we were called with, the other one after changing to HI Graphics orientation +// (this one is used for getting back clippings etc) + +//----------------------------------------------------------------------------- +// wxGraphicsPath implementation +//----------------------------------------------------------------------------- + +// TODO remove this dependency (gdiplus needs the macros) + +#ifndef max +#define max(a,b) (((a) > (b)) ? (a) : (b)) +#endif + +#ifndef min +#define min(a,b) (((a) < (b)) ? (a) : (b)) +#endif + +#include +#ifdef __WXGTK__ +#include +#endif + +class WXDLLIMPEXP_CORE wxCairoPathData : public wxGraphicsPathData +{ +public : + wxCairoPathData(wxGraphicsRenderer* renderer, cairo_t* path = NULL); + ~wxCairoPathData(); + + virtual wxGraphicsObjectRefData *Clone() const; + + // + // These are the path primitives from which everything else can be constructed + // + + // begins a new subpath at (x,y) + virtual void MoveToPoint( wxDouble x, wxDouble y ); + + // adds a straight line from the current point to (x,y) + virtual void AddLineToPoint( wxDouble x, wxDouble y ); + + // adds a cubic Bezier curve from the current point, using two control points and an end point + virtual void AddCurveToPoint( wxDouble cx1, wxDouble cy1, wxDouble cx2, wxDouble cy2, wxDouble x, wxDouble y ); + + + // adds an arc of a circle centering at (x,y) with radius (r) from startAngle to endAngle + virtual void AddArc( wxDouble x, wxDouble y, wxDouble r, wxDouble startAngle, wxDouble endAngle, bool clockwise ) ; + + // gets the last point of the current path, (0,0) if not yet set + virtual void GetCurrentPoint( wxDouble* x, wxDouble* y) const; + + // adds another path + virtual void AddPath( const wxGraphicsPathData* path ); + + // closes the current sub-path + virtual void CloseSubpath(); + + // + // These are convenience functions which - if not available natively will be assembled + // using the primitives from above + // + + /* + + // appends a rectangle as a new closed subpath + virtual void AddRectangle( wxDouble x, wxDouble y, wxDouble w, wxDouble h ) ; + // appends an ellipsis as a new closed subpath fitting the passed rectangle + virtual void AddEllipsis( wxDouble x, wxDouble y, wxDouble w , wxDouble h ) ; + + // draws a an arc to two tangents connecting (current) to (x1,y1) and (x1,y1) to (x2,y2), also a straight line from (current) to (x1,y1) + virtual void AddArcToPoint( wxDouble x1, wxDouble y1 , wxDouble x2, wxDouble y2, wxDouble r ) ; + */ + + // returns the native path + virtual void * GetNativePath() const ; + + // give the native path returned by GetNativePath() back (there might be some deallocations necessary) + virtual void UnGetNativePath(void *p) const; + + // transforms each point of this path by the matrix + virtual void Transform( const wxGraphicsMatrixData* matrix ) ; + + // gets the bounding box enclosing all points (possibly including control points) + virtual void GetBox(wxDouble *x, wxDouble *y, wxDouble *w, wxDouble *h) const; + + virtual bool Contains( wxDouble x, wxDouble y, int fillStyle = wxWINDING_RULE) const; + +private : + cairo_t* m_pathContext; +}; + +class WXDLLIMPEXP_CORE wxCairoMatrixData : public wxGraphicsMatrixData +{ +public : + wxCairoMatrixData(wxGraphicsRenderer* renderer, const cairo_matrix_t* matrix = NULL ) ; + virtual ~wxCairoMatrixData() ; + + virtual wxGraphicsObjectRefData *Clone() const ; + + // concatenates the matrix + virtual void Concat( const wxGraphicsMatrixData *t ); + + // sets the matrix to the respective values + virtual void Set(wxDouble a=1.0, wxDouble b=0.0, wxDouble c=0.0, wxDouble d=1.0, + wxDouble tx=0.0, wxDouble ty=0.0); + + // gets the component valuess of the matrix + virtual void Get(wxDouble* a=NULL, wxDouble* b=NULL, wxDouble* c=NULL, + wxDouble* d=NULL, wxDouble* tx=NULL, wxDouble* ty=NULL) const; + + // makes this the inverse matrix + virtual void Invert(); + + // returns true if the elements of the transformation matrix are equal ? + virtual bool IsEqual( const wxGraphicsMatrixData* t) const ; + + // return true if this is the identity matrix + virtual bool IsIdentity() const; + + // + // transformation + // + + // add the translation to this matrix + virtual void Translate( wxDouble dx , wxDouble dy ); + + // add the scale to this matrix + virtual void Scale( wxDouble xScale , wxDouble yScale ); + + // add the rotation to this matrix (radians) + virtual void Rotate( wxDouble angle ); + + // + // apply the transforms + // + + // applies that matrix to the point + virtual void TransformPoint( wxDouble *x, wxDouble *y ) const; + + // applies the matrix except for translations + virtual void TransformDistance( wxDouble *dx, wxDouble *dy ) const; + + // returns the native representation + virtual void * GetNativeMatrix() const; +private: + cairo_matrix_t m_matrix ; +} ; + +class WXDLLIMPEXP_CORE wxCairoPenData : public wxGraphicsObjectRefData +{ +public: + wxCairoPenData( wxGraphicsRenderer* renderer, const wxPen &pen ); + ~wxCairoPenData(); + + void Init(); + + virtual void Apply( wxGraphicsContext* context ); + virtual wxDouble GetWidth() { return m_width; } + +private : + double m_width; + + double m_red; + double m_green; + double m_blue; + double m_alpha; + + cairo_line_cap_t m_cap; + cairo_line_join_t m_join; + + int m_count; + const double *m_lengths; + double *m_userLengths; + + wxPen m_pen; +}; + +class WXDLLIMPEXP_CORE wxCairoBrushData : public wxGraphicsObjectRefData +{ +public: + wxCairoBrushData( wxGraphicsRenderer* renderer ); + wxCairoBrushData( wxGraphicsRenderer* renderer, const wxBrush &brush ); + ~wxCairoBrushData (); + + virtual void Apply( wxGraphicsContext* context ); + void CreateLinearGradientBrush( wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2, + const wxColour&c1, const wxColour&c2 ); + void CreateRadialGradientBrush( wxDouble xo, wxDouble yo, wxDouble xc, wxDouble yc, wxDouble radius, + const wxColour &oColor, const wxColour &cColor ); + +protected: + virtual void Init(); + +private : + double m_red; + double m_green; + double m_blue; + double m_alpha; + + cairo_pattern_t* m_brushPattern; +}; + +class wxCairoFontData : public wxGraphicsObjectRefData +{ +public: + wxCairoFontData( wxGraphicsRenderer* renderer, const wxFont &font, const wxColour& col ); + ~wxCairoFontData(); + + virtual void Apply( wxGraphicsContext* context ); +private : + wxCharBuffer m_fontName; + double m_size; + cairo_font_slant_t m_slant; + cairo_font_weight_t m_weight; + double m_red; + double m_green; + double m_blue; + double m_alpha; +}; + +class WXDLLIMPEXP_CORE wxCairoContext : public wxGraphicsContext +{ + DECLARE_NO_COPY_CLASS(wxCairoContext) + +public: + wxCairoContext( wxGraphicsRenderer* renderer, const wxWindowDC& dc ); +#ifdef __WXGTK__ + wxCairoContext( wxGraphicsRenderer* renderer, GdkDrawable *drawable ); +#endif + wxCairoContext( wxGraphicsRenderer* renderer, cairo_t *context ); + wxCairoContext( wxGraphicsRenderer* renderer, wxWindow *window); + wxCairoContext(); + virtual ~wxCairoContext(); + + virtual void Clip( const wxRegion ®ion ); + + // clips drawings to the rect + virtual void Clip( wxDouble x, wxDouble y, wxDouble w, wxDouble h ); + + // resets the clipping to original extent + virtual void ResetClip(); + + virtual void * GetNativeContext(); + + virtual void StrokePath( const wxGraphicsPath& p ); + virtual void FillPath( const wxGraphicsPath& p , int fillStyle = wxWINDING_RULE ); + + virtual void Translate( wxDouble dx , wxDouble dy ); + virtual void Scale( wxDouble xScale , wxDouble yScale ); + virtual void Rotate( wxDouble angle ); + + // concatenates this transform with the current transform of this context + virtual void ConcatTransform( const wxGraphicsMatrix& matrix ); + + // sets the transform of this context + virtual void SetTransform( const wxGraphicsMatrix& matrix ); + + // gets the matrix of this context + virtual wxGraphicsMatrix GetTransform() const; + + virtual void DrawBitmap( const wxBitmap &bmp, wxDouble x, wxDouble y, wxDouble w, wxDouble h ); + virtual void DrawIcon( const wxIcon &icon, wxDouble x, wxDouble y, wxDouble w, wxDouble h ); + virtual void PushState(); + virtual void PopState(); + + virtual void DrawText( const wxString &str, wxDouble x, wxDouble y); + virtual void GetTextExtent( const wxString &str, wxDouble *width, wxDouble *height, + wxDouble *descent, wxDouble *externalLeading ) const; + virtual void GetPartialTextExtents(const wxString& text, wxArrayDouble& widths) const; + +private: + cairo_t* m_context; +}; + +//----------------------------------------------------------------------------- +// wxCairoPenData implementation +//----------------------------------------------------------------------------- + +wxCairoPenData::~wxCairoPenData() +{ + delete[] m_userLengths; +} + +void wxCairoPenData::Init() +{ + m_lengths = NULL; + m_userLengths = NULL; + m_width = 0; + m_count = 0; +} + +wxCairoPenData::wxCairoPenData( wxGraphicsRenderer* renderer, const wxPen &pen ) +: wxGraphicsObjectRefData(renderer) +{ + Init(); + m_pen = pen; + m_width = m_pen.GetWidth(); + if (m_width <= 0.0) + m_width = 0.1; + + m_red = m_pen.GetColour().Red()/255.0; + m_green = m_pen.GetColour().Green()/255.0; + m_blue = m_pen.GetColour().Blue()/255.0; + m_alpha = m_pen.GetColour().Alpha()/255.0; + + switch ( m_pen.GetCap() ) + { + case wxCAP_ROUND : + m_cap = CAIRO_LINE_CAP_ROUND; + break; + + case wxCAP_PROJECTING : + m_cap = CAIRO_LINE_CAP_SQUARE; + break; + + case wxCAP_BUTT : + m_cap = CAIRO_LINE_CAP_BUTT; + break; + + default : + m_cap = CAIRO_LINE_CAP_BUTT; + break; + } + + switch ( m_pen.GetJoin() ) + { + case wxJOIN_BEVEL : + m_join = CAIRO_LINE_JOIN_BEVEL; + break; + + case wxJOIN_MITER : + m_join = CAIRO_LINE_JOIN_MITER; + break; + + case wxJOIN_ROUND : + m_join = CAIRO_LINE_JOIN_ROUND; + break; + + default : + m_join = CAIRO_LINE_JOIN_MITER; + break; + } + + const double dashUnit = m_width < 1.0 ? 1.0 : m_width; + const double dotted[] = + { + dashUnit , dashUnit + 2.0 + }; + static const double short_dashed[] = + { + 9.0 , 6.0 + }; + static const double dashed[] = + { + 19.0 , 9.0 + }; + static const double dotted_dashed[] = + { + 9.0 , 6.0 , 3.0 , 3.0 + }; + + switch ( m_pen.GetStyle() ) + { + case wxSOLID : + break; + + case wxDOT : + m_count = WXSIZEOF(dotted); + m_userLengths = new double[ m_count ] ; + memcpy( m_userLengths, dotted, sizeof(dotted) ); + m_lengths = m_userLengths; + break; + + case wxLONG_DASH : + m_lengths = dotted ; + m_count = WXSIZEOF(dashed); + break; + + case wxSHORT_DASH : + m_lengths = dotted ; + m_count = WXSIZEOF(short_dashed); + break; + + case wxDOT_DASH : + m_lengths = dotted ; + m_count = WXSIZEOF(dotted_dashed); + break; + + case wxUSER_DASH : + { + wxDash *wxdashes ; + m_count = m_pen.GetDashes( &wxdashes ) ; + if ((wxdashes != NULL) && (m_count > 0)) + { + m_userLengths = new double[m_count] ; + for ( int i = 0 ; i < m_count ; ++i ) + { + m_userLengths[i] = wxdashes[i] * dashUnit ; + + if ( i % 2 == 1 && m_userLengths[i] < dashUnit + 2.0 ) + m_userLengths[i] = dashUnit + 2.0 ; + else if ( i % 2 == 0 && m_userLengths[i] < dashUnit ) + m_userLengths[i] = dashUnit ; + } + } + m_lengths = m_userLengths ; + } + break; + case wxSTIPPLE : + { + /* + wxBitmap* bmp = pen.GetStipple(); + if ( bmp && bmp->Ok() ) + { + wxDELETE( m_penImage ); + wxDELETE( m_penBrush ); + m_penImage = Bitmap::FromHBITMAP((HBITMAP)bmp->GetHBITMAP(),(HPALETTE)bmp->GetPalette()->GetHPALETTE()); + m_penBrush = new TextureBrush(m_penImage); + m_pen->SetBrush( m_penBrush ); + } + */ + } + break; + default : + if ( m_pen.GetStyle() >= wxFIRST_HATCH && m_pen.GetStyle() <= wxLAST_HATCH ) + { + /* + wxDELETE( m_penBrush ); + HatchStyle style = HatchStyleHorizontal; + switch( pen.GetStyle() ) + { + case wxBDIAGONAL_HATCH : + style = HatchStyleBackwardDiagonal; + break ; + case wxCROSSDIAG_HATCH : + style = HatchStyleDiagonalCross; + break ; + case wxFDIAGONAL_HATCH : + style = HatchStyleForwardDiagonal; + break ; + case wxCROSS_HATCH : + style = HatchStyleCross; + break ; + case wxHORIZONTAL_HATCH : + style = HatchStyleHorizontal; + break ; + case wxVERTICAL_HATCH : + style = HatchStyleVertical; + break ; + + } + m_penBrush = new HatchBrush(style,Color( pen.GetColour().Alpha() , pen.GetColour().Red() , + pen.GetColour().Green() , pen.GetColour().Blue() ), Color.Transparent ); + m_pen->SetBrush( m_penBrush ) + */ + } + break; + } +} + +void wxCairoPenData::Apply( wxGraphicsContext* context ) +{ + cairo_t * ctext = (cairo_t*) context->GetNativeContext(); + cairo_set_line_width(ctext,m_width); + cairo_set_source_rgba(ctext,m_red,m_green, m_blue,m_alpha); + cairo_set_line_cap(ctext,m_cap); + cairo_set_line_join(ctext,m_join); + cairo_set_dash(ctext,(double*)m_lengths,m_count,0.0); +} + +//----------------------------------------------------------------------------- +// wxCairoBrushData implementation +//----------------------------------------------------------------------------- + +wxCairoBrushData::wxCairoBrushData( wxGraphicsRenderer* renderer ) + : wxGraphicsObjectRefData( renderer ) +{ + Init(); +} + +wxCairoBrushData::wxCairoBrushData( wxGraphicsRenderer* renderer, const wxBrush &brush ) + : wxGraphicsObjectRefData(renderer) +{ + Init(); + + m_red = brush.GetColour().Red()/255.0; + m_green = brush.GetColour().Green()/255.0; + m_blue = brush.GetColour().Blue()/255.0; + m_alpha = brush.GetColour().Alpha()/255.0; + /* + if ( brush.GetStyle() == wxSOLID) + { + m_brush = new SolidBrush( Color( brush.GetColour().Alpha() , brush.GetColour().Red() , + brush.GetColour().Green() , brush.GetColour().Blue() ) ); + } + else if ( brush.IsHatch() ) + { + HatchStyle style = HatchStyleHorizontal; + switch( brush.GetStyle() ) + { + case wxBDIAGONAL_HATCH : + style = HatchStyleBackwardDiagonal; + break ; + case wxCROSSDIAG_HATCH : + style = HatchStyleDiagonalCross; + break ; + case wxFDIAGONAL_HATCH : + style = HatchStyleForwardDiagonal; + break ; + case wxCROSS_HATCH : + style = HatchStyleCross; + break ; + case wxHORIZONTAL_HATCH : + style = HatchStyleHorizontal; + break ; + case wxVERTICAL_HATCH : + style = HatchStyleVertical; + break ; + + } + m_brush = new HatchBrush(style,Color( brush.GetColour().Alpha() , brush.GetColour().Red() , + brush.GetColour().Green() , brush.GetColour().Blue() ), Color.Transparent ); + } + else + { + wxBitmap* bmp = brush.GetStipple(); + if ( bmp && bmp->Ok() ) + { + wxDELETE( m_brushImage ); + m_brushImage = Bitmap::FromHBITMAP((HBITMAP)bmp->GetHBITMAP(),(HPALETTE)bmp->GetPalette()->GetHPALETTE()); + m_brush = new TextureBrush(m_brushImage); + } + } + */ +} + +wxCairoBrushData::~wxCairoBrushData () +{ + if (m_brushPattern) + cairo_pattern_destroy(m_brushPattern); +} + +void wxCairoBrushData::Apply( wxGraphicsContext* context ) +{ + cairo_t * ctext = (cairo_t*) context->GetNativeContext(); + if ( m_brushPattern ) + { + cairo_set_source(ctext,m_brushPattern); + } + else + { + cairo_set_source_rgba(ctext,m_red,m_green, m_blue,m_alpha); + } +} + +void wxCairoBrushData::CreateLinearGradientBrush( wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2, + const wxColour&c1, const wxColour&c2 ) +{ + m_brushPattern = cairo_pattern_create_linear(x1,y1,x2,y2); + cairo_pattern_add_color_stop_rgba(m_brushPattern,0.0,c1.Red()/255.0, + c1.Green()/255.0, c1.Blue()/255.0,c1.Alpha()/255.0); + cairo_pattern_add_color_stop_rgba(m_brushPattern,1.0,c2.Red()/255.0, + c2.Green()/255.0, c2.Blue()/255.0,c2.Alpha()/255.0); + wxASSERT_MSG(cairo_pattern_status(m_brushPattern) == CAIRO_STATUS_SUCCESS, wxT("Couldn't create cairo pattern")); +} + +void wxCairoBrushData::CreateRadialGradientBrush( wxDouble xo, wxDouble yo, wxDouble xc, wxDouble yc, wxDouble radius, + const wxColour &oColor, const wxColour &cColor ) +{ + m_brushPattern = cairo_pattern_create_radial(xo,yo,0.0,xc,yc,radius); + cairo_pattern_add_color_stop_rgba(m_brushPattern,0.0,oColor.Red()/255.0, + oColor.Green()/255.0, oColor.Blue()/255.0,oColor.Alpha()/255.0); + cairo_pattern_add_color_stop_rgba(m_brushPattern,1.0,cColor.Red()/255.0, + cColor.Green()/255.0, cColor.Blue()/255.0,cColor.Alpha()/255.0); + wxASSERT_MSG(cairo_pattern_status(m_brushPattern) == CAIRO_STATUS_SUCCESS, wxT("Couldn't create cairo pattern")); +} + +void wxCairoBrushData::Init() +{ + m_brushPattern = NULL; +} + +//----------------------------------------------------------------------------- +// wxCairoFontData implementation +//----------------------------------------------------------------------------- + +wxCairoFontData::wxCairoFontData( wxGraphicsRenderer* renderer, const wxFont &font, + const wxColour& col ) : wxGraphicsObjectRefData(renderer) +{ + m_red = col.Red()/255.0; + m_green = col.Green()/255.0; + m_blue = col.Blue()/255.0; + m_alpha = col.Alpha()/255.0; + + m_size = font.GetPointSize(); + m_fontName = font.GetFaceName().mb_str(wxConvUTF8); + m_slant = font.GetStyle() == wxFONTSTYLE_ITALIC ? CAIRO_FONT_SLANT_ITALIC:CAIRO_FONT_SLANT_NORMAL; + m_weight = font.GetWeight() == wxFONTWEIGHT_BOLD ? CAIRO_FONT_WEIGHT_BOLD:CAIRO_FONT_WEIGHT_NORMAL; +} + +wxCairoFontData::~wxCairoFontData() +{ +} + +void wxCairoFontData::Apply( wxGraphicsContext* context ) +{ + cairo_t * ctext = (cairo_t*) context->GetNativeContext(); + cairo_set_source_rgba(ctext,m_red,m_green, m_blue,m_alpha); + cairo_select_font_face(ctext,m_fontName,m_slant,m_weight); + cairo_set_font_size(ctext,m_size); + // TODO UNDERLINE + // TODO FIX SIZE +} + +//----------------------------------------------------------------------------- +// wxCairoPathData implementation +//----------------------------------------------------------------------------- + +wxCairoPathData::wxCairoPathData( wxGraphicsRenderer* renderer, cairo_t* pathcontext) + : wxGraphicsPathData(renderer) +{ + if (pathcontext) + { + m_pathContext = pathcontext; + } + else + { + cairo_surface_t* surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,1,1); + m_pathContext = cairo_create(surface); + cairo_surface_destroy (surface); + } +} + +wxCairoPathData::~wxCairoPathData() +{ + cairo_destroy(m_pathContext); +} + +wxGraphicsObjectRefData *wxCairoPathData::Clone() const +{ + cairo_surface_t* surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,1,1); + cairo_t* pathcontext = cairo_create(surface); + cairo_surface_destroy (surface); + + cairo_path_t* path = cairo_copy_path(m_pathContext); + cairo_append_path(pathcontext, path); + cairo_path_destroy(path); + return new wxCairoPathData( GetRenderer() ,pathcontext); +} + + +void* wxCairoPathData::GetNativePath() const +{ + return cairo_copy_path(m_pathContext) ; +} + +void wxCairoPathData::UnGetNativePath(void *p) const +{ + cairo_path_destroy((cairo_path_t*)p); +} + +// +// The Primitives +// + +void wxCairoPathData::MoveToPoint( wxDouble x , wxDouble y ) +{ + cairo_move_to(m_pathContext,x,y); +} + +void wxCairoPathData::AddLineToPoint( wxDouble x , wxDouble y ) +{ + cairo_line_to(m_pathContext,x,y); +} + +void wxCairoPathData::AddPath( const wxGraphicsPathData* path ) +{ + cairo_path_t* p = (cairo_path_t*)path->GetNativePath(); + cairo_append_path(m_pathContext, p); + UnGetNativePath(p); +} + +void wxCairoPathData::CloseSubpath() +{ + cairo_close_path(m_pathContext); +} + +void wxCairoPathData::AddCurveToPoint( wxDouble cx1, wxDouble cy1, wxDouble cx2, wxDouble cy2, wxDouble x, wxDouble y ) +{ + cairo_curve_to(m_pathContext,cx1,cy1,cx2,cy2,x,y); +} + +// gets the last point of the current path, (0,0) if not yet set +void wxCairoPathData::GetCurrentPoint( wxDouble* x, wxDouble* y) const +{ + double dx,dy; + cairo_get_current_point(m_pathContext,&dx,&dy); + if (x) + *x = dx; + if (y) + *y = dy; +} + +void wxCairoPathData::AddArc( wxDouble x, wxDouble y, wxDouble r, double startAngle, double endAngle, bool clockwise ) +{ + // as clockwise means positive in our system (y pointing downwards) + // TODO make this interpretation dependent of the + // real device trans + if ( clockwise||(endAngle-startAngle)>=2*M_PI) + cairo_arc(m_pathContext,x,y,r,startAngle,endAngle); + else + cairo_arc_negative(m_pathContext,x,y,r,startAngle,endAngle); +} + +// transforms each point of this path by the matrix +void wxCairoPathData::Transform( const wxGraphicsMatrixData* matrix ) +{ + // as we don't have a true path object, we have to apply the inverse + // matrix to the context + cairo_matrix_t m = *((cairo_matrix_t*) matrix->GetNativeMatrix()); + cairo_matrix_invert( &m ); + cairo_transform(m_pathContext,&m); +} + +// gets the bounding box enclosing all points (possibly including control points) +void wxCairoPathData::GetBox(wxDouble *x, wxDouble *y, wxDouble *w, wxDouble *h) const +{ + double x1,y1,x2,y2; + + cairo_stroke_extents( m_pathContext, &x1, &y1, &x2, &y2 ); + if ( x2 < x1 ) + { + *x = x2; + *w = x1-x2; + } + else + { + *x = x1; + *w = x2-x1; + } + + if( y2 < y1 ) + { + *y = y2; + *h = y1-y2; + } + else + { + *y = y1; + *h = y2-y1; + } +} + +bool wxCairoPathData::Contains( wxDouble x, wxDouble y, int fillStyle ) const +{ + return cairo_in_stroke( m_pathContext, x, y) != 0; +} + +//----------------------------------------------------------------------------- +// wxCairoMatrixData implementation +//----------------------------------------------------------------------------- + +wxCairoMatrixData::wxCairoMatrixData(wxGraphicsRenderer* renderer, const cairo_matrix_t* matrix ) + : wxGraphicsMatrixData(renderer) +{ + if ( matrix ) + m_matrix = *matrix; +} + +wxCairoMatrixData::~wxCairoMatrixData() +{ + // nothing to do +} + +wxGraphicsObjectRefData *wxCairoMatrixData::Clone() const +{ + return new wxCairoMatrixData(GetRenderer(),&m_matrix); +} + +// concatenates the matrix +void wxCairoMatrixData::Concat( const wxGraphicsMatrixData *t ) +{ + cairo_matrix_multiply( &m_matrix, &m_matrix, (cairo_matrix_t*) t->GetNativeMatrix()); +} + +// sets the matrix to the respective values +void wxCairoMatrixData::Set(wxDouble a, wxDouble b, wxDouble c, wxDouble d, + wxDouble tx, wxDouble ty) +{ + cairo_matrix_init( &m_matrix, a, b, c, d, tx, ty); +} + +// gets the component valuess of the matrix +void wxCairoMatrixData::Get(wxDouble* a, wxDouble* b, wxDouble* c, + wxDouble* d, wxDouble* tx, wxDouble* ty) const +{ + if (a) *a = m_matrix.xx; + if (b) *b = m_matrix.yx; + if (c) *c = m_matrix.xy; + if (d) *d = m_matrix.yy; + if (tx) *tx= m_matrix.x0; + if (ty) *ty= m_matrix.y0; +} + +// makes this the inverse matrix +void wxCairoMatrixData::Invert() +{ + cairo_matrix_invert( &m_matrix ); +} + +// returns true if the elements of the transformation matrix are equal ? +bool wxCairoMatrixData::IsEqual( const wxGraphicsMatrixData* t) const +{ + const cairo_matrix_t* tm = (cairo_matrix_t*) t->GetNativeMatrix(); + return ( + m_matrix.xx == tm->xx && + m_matrix.yx == tm->yx && + m_matrix.xy == tm->xy && + m_matrix.yy == tm->yy && + m_matrix.x0 == tm->x0 && + m_matrix.y0 == tm->y0 ) ; +} + +// return true if this is the identity matrix +bool wxCairoMatrixData::IsIdentity() const +{ + return ( m_matrix.xx == 1 && m_matrix.yy == 1 && + m_matrix.yx == 0 && m_matrix.xy == 0 && m_matrix.x0 == 0 && m_matrix.y0 == 0); +} + +// +// transformation +// + +// add the translation to this matrix +void wxCairoMatrixData::Translate( wxDouble dx , wxDouble dy ) +{ + cairo_matrix_translate( &m_matrix, dx, dy) ; +} + +// add the scale to this matrix +void wxCairoMatrixData::Scale( wxDouble xScale , wxDouble yScale ) +{ + cairo_matrix_scale( &m_matrix, xScale, yScale) ; +} + +// add the rotation to this matrix (radians) +void wxCairoMatrixData::Rotate( wxDouble angle ) +{ + cairo_matrix_rotate( &m_matrix, angle) ; +} + +// +// apply the transforms +// + +// applies that matrix to the point +void wxCairoMatrixData::TransformPoint( wxDouble *x, wxDouble *y ) const +{ + double lx = *x, ly = *y ; + cairo_matrix_transform_point( &m_matrix, &lx, &ly); + *x = lx; + *y = ly; +} + +// applies the matrix except for translations +void wxCairoMatrixData::TransformDistance( wxDouble *dx, wxDouble *dy ) const +{ + double lx = *dx, ly = *dy ; + cairo_matrix_transform_distance( &m_matrix, &lx, &ly); + *dx = lx; + *dy = ly; +} + +// returns the native representation +void * wxCairoMatrixData::GetNativeMatrix() const +{ + return (void*) &m_matrix; +} + +//----------------------------------------------------------------------------- +// wxCairoContext implementation +//----------------------------------------------------------------------------- + +wxCairoContext::wxCairoContext( wxGraphicsRenderer* renderer, const wxWindowDC& dc ) +: wxGraphicsContext(renderer) +{ +#ifdef __WXGTK__ + m_context = gdk_cairo_create( dc.m_window ) ; +#endif + PushState(); + PushState(); +} + +#ifdef __WXGTK__ +wxCairoContext::wxCairoContext( wxGraphicsRenderer* renderer, GdkDrawable *drawable ) +: wxGraphicsContext(renderer) +{ + m_context = gdk_cairo_create( drawable ) ; + PushState(); + PushState(); +} +#endif + +wxCairoContext::wxCairoContext( wxGraphicsRenderer* renderer, cairo_t *context ) +: wxGraphicsContext(renderer) +{ + m_context = context ; + PushState(); + PushState(); +} + +wxCairoContext::wxCairoContext( wxGraphicsRenderer* renderer, wxWindow *window) +: wxGraphicsContext(renderer) +{ +#ifdef __WXGTK__ + // something along these lines (copied from dcclient) + + GtkWidget *widget = window->m_wxwindow; + + // Some controls don't have m_wxwindow - like wxStaticBox, but the user + // code should still be able to create wxClientDCs for them, so we will + // use the parent window here then. + if ( !widget ) + { + window = window->GetParent(); + widget = window->m_wxwindow; + } + + wxASSERT_MSG( widget, wxT("wxCairoContext needs a widget") ); + + GtkPizza *pizza = GTK_PIZZA( widget ); + GdkDrawable* drawable = pizza->bin_window; + m_context = gdk_cairo_create( drawable ) ; +#endif + PushState(); + PushState(); +} + +wxCairoContext::~wxCairoContext() +{ + if ( m_context ) + { + PopState(); + PopState(); + cairo_destroy(m_context); + } +} + + +void wxCairoContext::Clip( const wxRegion& region ) +{ + // Create a path with all the rectangles in the region + wxGraphicsPath path = GetRenderer()->CreatePath(); + wxRegionIterator ri(region); + while (ri) + { + path.AddRectangle(ri.GetX(), ri.GetY(), ri.GetW(), ri.GetH()); + ri++; + } + + // Put it in the context + cairo_path_t* cp = (cairo_path_t*) path.GetNativePath() ; + cairo_append_path(m_context, cp); + + // clip to that path + cairo_clip(m_context); + path.UnGetNativePath(cp); +} + +void wxCairoContext::Clip( wxDouble x, wxDouble y, wxDouble w, wxDouble h ) +{ + // Create a path with this rectangle + wxGraphicsPath path = GetRenderer()->CreatePath(); + path.AddRectangle(x,y,w,h); + + // Put it in the context + cairo_path_t* cp = (cairo_path_t*) path.GetNativePath() ; + cairo_append_path(m_context, cp); + + // clip to that path + cairo_clip(m_context); + path.UnGetNativePath(cp); +} + +void wxCairoContext::ResetClip() +{ + cairo_reset_clip(m_context); +} + + +void wxCairoContext::StrokePath( const wxGraphicsPath& path ) +{ + if ( !m_pen.IsNull() ) + { + cairo_path_t* cp = (cairo_path_t*) path.GetNativePath() ; + cairo_append_path(m_context,cp); + ((wxCairoPenData*)m_pen.GetRefData())->Apply(this); + cairo_stroke(m_context); + path.UnGetNativePath(cp); + } +} + +void wxCairoContext::FillPath( const wxGraphicsPath& path , int fillStyle ) +{ + if ( !m_brush.IsNull() ) + { + cairo_path_t* cp = (cairo_path_t*) path.GetNativePath() ; + cairo_append_path(m_context,cp); + ((wxCairoBrushData*)m_brush.GetRefData())->Apply(this); + cairo_set_fill_rule(m_context,fillStyle==wxODDEVEN_RULE ? CAIRO_FILL_RULE_EVEN_ODD : CAIRO_FILL_RULE_WINDING); + cairo_fill(m_context); + path.UnGetNativePath(cp); + } +} + +void wxCairoContext::Rotate( wxDouble angle ) +{ + cairo_rotate(m_context,angle); +} + +void wxCairoContext::Translate( wxDouble dx , wxDouble dy ) +{ + cairo_translate(m_context,dx,dy); +} + +void wxCairoContext::Scale( wxDouble xScale , wxDouble yScale ) +{ + cairo_scale(m_context,xScale,yScale); +} + +// concatenates this transform with the current transform of this context +void wxCairoContext::ConcatTransform( const wxGraphicsMatrix& matrix ) +{ + cairo_transform(m_context,(const cairo_matrix_t *) matrix.GetNativeMatrix()); +} + +// sets the transform of this context +void wxCairoContext::SetTransform( const wxGraphicsMatrix& matrix ) +{ + cairo_set_matrix(m_context,(const cairo_matrix_t*) matrix.GetNativeMatrix()); +} + +// gets the matrix of this context +wxGraphicsMatrix wxCairoContext::GetTransform() const +{ + wxGraphicsMatrix matrix = CreateMatrix(); + cairo_get_matrix(m_context,(cairo_matrix_t*) matrix.GetNativeMatrix()); + return matrix; +} + + + +void wxCairoContext::PushState() +{ + cairo_save(m_context); +} + +void wxCairoContext::PopState() +{ + cairo_restore(m_context); +} + +void wxCairoContext::DrawBitmap( const wxBitmap &bmp, wxDouble x, wxDouble y, wxDouble w, wxDouble h ) +{ + wxCHECK_RET( bmp.IsOk(), wxT("Invalid bitmap in wxCairoContext::DrawBitmap")); + + cairo_surface_t* surface; + int bw = bmp.GetWidth(); + int bh = bmp.GetHeight(); + wxBitmap bmpSource = bmp; // we need a non-const instance + unsigned char* buffer = new unsigned char[bw*bh*4]; + wxUint32* data = (wxUint32*)buffer; + + // Create a surface object and copy the bitmap pixel data to it. if the + // image has alpha (or a mask represented as alpha) then we'll use a + // different format and iterator than if it doesn't... + if (bmpSource.HasAlpha() || bmpSource.GetMask()) + { + surface = cairo_image_surface_create_for_data( + buffer, CAIRO_FORMAT_ARGB32, bw, bh, bw*4); + wxAlphaPixelData pixData(bmpSource, wxPoint(0,0), wxSize(bw, bh)); + wxCHECK_RET( pixData, wxT("Failed to gain raw access to bitmap data.")); + + wxAlphaPixelData::Iterator p(pixData); + for (int y=0; yApply(this); + + // Cairo's x,y for drawing text is at the baseline, so we need to adjust + // the position we move to by the ascent. + cairo_font_extents_t fe; + cairo_font_extents(m_context, &fe); + cairo_move_to(m_context, x, y+fe.ascent); + + const wxWX2MBbuf buf(str.mb_str(wxConvUTF8)); + cairo_show_text(m_context,buf); +} + +void wxCairoContext::GetTextExtent( const wxString &str, wxDouble *width, wxDouble *height, + wxDouble *descent, wxDouble *externalLeading ) const +{ + if ( m_font.IsNull() || str.empty()) + return; + + ((wxCairoFontData*)m_font.GetRefData())->Apply((wxCairoContext*)this); + + if (width) + { + const wxWX2MBbuf buf(str.mb_str(wxConvUTF8)); + cairo_text_extents_t te; + cairo_text_extents(m_context, buf, &te); + *width = te.width; + } + + if (height || descent || externalLeading) + { + cairo_font_extents_t fe; + cairo_font_extents(m_context, &fe); + + if (height) + *height = fe.height; + if ( descent ) + *descent = fe.descent; + if ( externalLeading ) + *externalLeading = wxMax(0, fe.height - (fe.ascent + fe.descent)); + } +} + +void wxCairoContext::GetPartialTextExtents(const wxString& text, wxArrayDouble& widths) const +{ + widths.Empty(); + widths.Add(0, text.length()); + + if (text.empty()) + return; + + // TODO +} + +void * wxCairoContext::GetNativeContext() +{ + return m_context; +} + +//----------------------------------------------------------------------------- +// wxCairoRenderer declaration +//----------------------------------------------------------------------------- + +class WXDLLIMPEXP_CORE wxCairoRenderer : public wxGraphicsRenderer +{ +public : + wxCairoRenderer() {} + + virtual ~wxCairoRenderer() {} + + // Context + + virtual wxGraphicsContext * CreateContext( const wxWindowDC& dc); + +#ifdef __WXMSW__ + virtual wxGraphicsContext * CreateContext( const wxMemoryDC& dc); +#endif + + virtual wxGraphicsContext * CreateContextFromNativeContext( void * context ); + + virtual wxGraphicsContext * CreateContextFromNativeWindow( void * window ); + + virtual wxGraphicsContext * CreateContext( wxWindow* window ); + + virtual wxGraphicsContext * CreateMeasuringContext(); + + // Path + + virtual wxGraphicsPath CreatePath(); + + // Matrix + + virtual wxGraphicsMatrix CreateMatrix( wxDouble a=1.0, wxDouble b=0.0, wxDouble c=0.0, wxDouble d=1.0, + wxDouble tx=0.0, wxDouble ty=0.0); + + + virtual wxGraphicsPen CreatePen(const wxPen& pen) ; + + virtual wxGraphicsBrush CreateBrush(const wxBrush& brush ) ; + + // sets the brush to a linear gradient, starting at (x1,y1) with color c1 to (x2,y2) with color c2 + virtual wxGraphicsBrush CreateLinearGradientBrush( wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2, + const wxColour&c1, const wxColour&c2) ; + + // sets the brush to a radial gradient originating at (xo,yc) with color oColor and ends on a circle around (xc,yc) + // with radius r and color cColor + virtual wxGraphicsBrush CreateRadialGradientBrush( wxDouble xo, wxDouble yo, wxDouble xc, wxDouble yc, wxDouble radius, + const wxColour &oColor, const wxColour &cColor) ; + + // sets the font + virtual wxGraphicsFont CreateFont( const wxFont &font , const wxColour &col = *wxBLACK ) ; + +private : + DECLARE_DYNAMIC_CLASS_NO_COPY(wxCairoRenderer) +} ; + +//----------------------------------------------------------------------------- +// wxCairoRenderer implementation +//----------------------------------------------------------------------------- + +IMPLEMENT_DYNAMIC_CLASS(wxCairoRenderer,wxGraphicsRenderer) + +static wxCairoRenderer gs_cairoGraphicsRenderer; + +#ifdef __WXGTK__ +wxGraphicsRenderer* wxGraphicsRenderer::GetDefaultRenderer() +{ + return &gs_cairoGraphicsRenderer; +} +#endif + +wxGraphicsContext * wxCairoRenderer::CreateContext( const wxWindowDC& dc) +{ + return new wxCairoContext(this,dc); +} + +#ifdef __WXMSW__ +wxGraphicsContext * wxCairoRenderer::CreateContext( const wxMemoryDC& dc) +{ + return NULL; +} +#endif + +wxGraphicsContext * wxCairoRenderer::CreateContextFromNativeContext( void * context ) +{ + return new wxCairoContext(this,(cairo_t*)context); +} + + +wxGraphicsContext * wxCairoRenderer::CreateContextFromNativeWindow( void * window ) +{ +#ifdef __WXGTK__ + return new wxCairoContext(this,(GdkDrawable*)window); +#else + return NULL; +#endif +} + +wxGraphicsContext * wxCairoRenderer::CreateMeasuringContext() +{ + return NULL; + // TODO +} + +wxGraphicsContext * wxCairoRenderer::CreateContext( wxWindow* window ) +{ + return new wxCairoContext(this, window ); +} + +// Path + +wxGraphicsPath wxCairoRenderer::CreatePath() +{ + wxGraphicsPath path; + path.SetRefData( new wxCairoPathData(this) ); + return path; +} + + +// Matrix + +wxGraphicsMatrix wxCairoRenderer::CreateMatrix( wxDouble a, wxDouble b, wxDouble c, wxDouble d, + wxDouble tx, wxDouble ty) + +{ + wxGraphicsMatrix m; + wxCairoMatrixData* data = new wxCairoMatrixData( this ); + data->Set( a,b,c,d,tx,ty ) ; + m.SetRefData(data); + return m; +} + +wxGraphicsPen wxCairoRenderer::CreatePen(const wxPen& pen) +{ + if ( !pen.Ok() || pen.GetStyle() == wxTRANSPARENT ) + return wxNullGraphicsPen; + else + { + wxGraphicsPen p; + p.SetRefData(new wxCairoPenData( this, pen )); + return p; + } +} + +wxGraphicsBrush wxCairoRenderer::CreateBrush(const wxBrush& brush ) +{ + if ( !brush.Ok() || brush.GetStyle() == wxTRANSPARENT ) + return wxNullGraphicsBrush; + else + { + wxGraphicsBrush p; + p.SetRefData(new wxCairoBrushData( this, brush )); + return p; + } +} + +// sets the brush to a linear gradient, starting at (x1,y1) with color c1 to (x2,y2) with color c2 +wxGraphicsBrush wxCairoRenderer::CreateLinearGradientBrush( wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2, + const wxColour&c1, const wxColour&c2) +{ + wxGraphicsBrush p; + wxCairoBrushData* d = new wxCairoBrushData( this ); + d->CreateLinearGradientBrush(x1, y1, x2, y2, c1, c2); + p.SetRefData(d); + return p; +} + +// sets the brush to a radial gradient originating at (xo,yc) with color oColor and ends on a circle around (xc,yc) +// with radius r and color cColor +wxGraphicsBrush wxCairoRenderer::CreateRadialGradientBrush( wxDouble xo, wxDouble yo, wxDouble xc, wxDouble yc, wxDouble radius, + const wxColour &oColor, const wxColour &cColor) +{ + wxGraphicsBrush p; + wxCairoBrushData* d = new wxCairoBrushData( this ); + d->CreateRadialGradientBrush(xo,yo,xc,yc,radius,oColor,cColor); + p.SetRefData(d); + return p; +} + +// sets the font +wxGraphicsFont wxCairoRenderer::CreateFont( const wxFont &font , const wxColour &col ) +{ + if ( font.Ok() ) + { + wxGraphicsFont p; + p.SetRefData(new wxCairoFontData( this , font, col )); + return p; + } + else + return wxNullGraphicsFont; +} + +#endif // wxUSE_GRAPHICS_CONTEXT diff --git a/Externals/wxWidgets/src/generic/grid.cpp b/Externals/wxWidgets/src/generic/grid.cpp index 99493008f3..08962d6434 100644 --- a/Externals/wxWidgets/src/generic/grid.cpp +++ b/Externals/wxWidgets/src/generic/grid.cpp @@ -1,11322 +1,11322 @@ -/////////////////////////////////////////////////////////////////////////// -// Name: src/generic/grid.cpp -// Purpose: wxGrid and related classes -// Author: Michael Bedward (based on code by Julian Smart, Robin Dunn) -// Modified by: Robin Dunn, Vadim Zeitlin, Santiago Palacios -// Created: 1/08/1999 -// RCS-ID: $Id: grid.cpp 54276 2008-06-18 11:21:57Z SN $ -// Copyright: (c) Michael Bedward (mbedward@ozemail.com.au) -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx/wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_GRID - -#include "wx/grid.h" - -#ifndef WX_PRECOMP - #include "wx/utils.h" - #include "wx/dcclient.h" - #include "wx/settings.h" - #include "wx/log.h" - #include "wx/textctrl.h" - #include "wx/checkbox.h" - #include "wx/combobox.h" - #include "wx/valtext.h" - #include "wx/intl.h" - #include "wx/math.h" - #include "wx/listbox.h" -#endif - -#include "wx/textfile.h" -#include "wx/spinctrl.h" -#include "wx/tokenzr.h" -#include "wx/renderer.h" - -#include "wx/generic/gridsel.h" - -const wxChar wxGridNameStr[] = wxT("grid"); - -#if defined(__WXMOTIF__) - #define WXUNUSED_MOTIF(identifier) WXUNUSED(identifier) -#else - #define WXUNUSED_MOTIF(identifier) identifier -#endif - -#if defined(__WXGTK__) - #define WXUNUSED_GTK(identifier) WXUNUSED(identifier) -#else - #define WXUNUSED_GTK(identifier) identifier -#endif - -// Required for wxIs... functions -#include - -// ---------------------------------------------------------------------------- -// array classes -// ---------------------------------------------------------------------------- - -WX_DEFINE_ARRAY_WITH_DECL_PTR(wxGridCellAttr *, wxArrayAttrs, - class WXDLLIMPEXP_ADV); - -struct wxGridCellWithAttr -{ - wxGridCellWithAttr(int row, int col, wxGridCellAttr *attr_) - : coords(row, col), attr(attr_) - { - wxASSERT( attr ); - } - - wxGridCellWithAttr(const wxGridCellWithAttr& other) - : coords(other.coords), - attr(other.attr) - { - attr->IncRef(); - } - - wxGridCellWithAttr& operator=(const wxGridCellWithAttr& other) - { - coords = other.coords; - if (attr != other.attr) - { - attr->DecRef(); - attr = other.attr; - attr->IncRef(); - } - return *this; - } - - void ChangeAttr(wxGridCellAttr * new_attr) - { - if (attr != new_attr) - { - // "Delete" (i.e. DecRef) the old attribute. - attr->DecRef(); - attr = new_attr; - // Take ownership of the new attribute, i.e. no IncRef. - } - } - - ~wxGridCellWithAttr() - { - attr->DecRef(); - } - - wxGridCellCoords coords; - wxGridCellAttr *attr; -}; - -WX_DECLARE_OBJARRAY_WITH_DECL(wxGridCellWithAttr, wxGridCellWithAttrArray, - class WXDLLIMPEXP_ADV); - -#include "wx/arrimpl.cpp" - -WX_DEFINE_OBJARRAY(wxGridCellCoordsArray) -WX_DEFINE_OBJARRAY(wxGridCellWithAttrArray) - -// ---------------------------------------------------------------------------- -// events -// ---------------------------------------------------------------------------- - -DEFINE_EVENT_TYPE(wxEVT_GRID_CELL_LEFT_CLICK) -DEFINE_EVENT_TYPE(wxEVT_GRID_CELL_RIGHT_CLICK) -DEFINE_EVENT_TYPE(wxEVT_GRID_CELL_LEFT_DCLICK) -DEFINE_EVENT_TYPE(wxEVT_GRID_CELL_RIGHT_DCLICK) -DEFINE_EVENT_TYPE(wxEVT_GRID_CELL_BEGIN_DRAG) -DEFINE_EVENT_TYPE(wxEVT_GRID_LABEL_LEFT_CLICK) -DEFINE_EVENT_TYPE(wxEVT_GRID_LABEL_RIGHT_CLICK) -DEFINE_EVENT_TYPE(wxEVT_GRID_LABEL_LEFT_DCLICK) -DEFINE_EVENT_TYPE(wxEVT_GRID_LABEL_RIGHT_DCLICK) -DEFINE_EVENT_TYPE(wxEVT_GRID_ROW_SIZE) -DEFINE_EVENT_TYPE(wxEVT_GRID_COL_SIZE) -DEFINE_EVENT_TYPE(wxEVT_GRID_COL_MOVE) -DEFINE_EVENT_TYPE(wxEVT_GRID_RANGE_SELECT) -DEFINE_EVENT_TYPE(wxEVT_GRID_CELL_CHANGE) -DEFINE_EVENT_TYPE(wxEVT_GRID_SELECT_CELL) -DEFINE_EVENT_TYPE(wxEVT_GRID_EDITOR_SHOWN) -DEFINE_EVENT_TYPE(wxEVT_GRID_EDITOR_HIDDEN) -DEFINE_EVENT_TYPE(wxEVT_GRID_EDITOR_CREATED) - -// ---------------------------------------------------------------------------- -// private classes -// ---------------------------------------------------------------------------- - -class WXDLLIMPEXP_ADV wxGridRowLabelWindow : public wxWindow -{ -public: - wxGridRowLabelWindow() { m_owner = (wxGrid *)NULL; } - wxGridRowLabelWindow( wxGrid *parent, wxWindowID id, - const wxPoint &pos, const wxSize &size ); - - virtual bool AcceptsFocus() const { return false; } - -private: - wxGrid *m_owner; - - void OnPaint( wxPaintEvent& event ); - void OnMouseEvent( wxMouseEvent& event ); - void OnMouseWheel( wxMouseEvent& event ); - void OnKeyDown( wxKeyEvent& event ); - void OnKeyUp( wxKeyEvent& ); - void OnChar( wxKeyEvent& ); - - DECLARE_DYNAMIC_CLASS(wxGridRowLabelWindow) - DECLARE_EVENT_TABLE() - DECLARE_NO_COPY_CLASS(wxGridRowLabelWindow) -}; - - -class WXDLLIMPEXP_ADV wxGridColLabelWindow : public wxWindow -{ -public: - wxGridColLabelWindow() { m_owner = (wxGrid *)NULL; } - wxGridColLabelWindow( wxGrid *parent, wxWindowID id, - const wxPoint &pos, const wxSize &size ); - - virtual bool AcceptsFocus() const { return false; } - -private: - wxGrid *m_owner; - - void OnPaint( wxPaintEvent& event ); - void OnMouseEvent( wxMouseEvent& event ); - void OnMouseWheel( wxMouseEvent& event ); - void OnKeyDown( wxKeyEvent& event ); - void OnKeyUp( wxKeyEvent& ); - void OnChar( wxKeyEvent& ); - - DECLARE_DYNAMIC_CLASS(wxGridColLabelWindow) - DECLARE_EVENT_TABLE() - DECLARE_NO_COPY_CLASS(wxGridColLabelWindow) -}; - - -class WXDLLIMPEXP_ADV wxGridCornerLabelWindow : public wxWindow -{ -public: - wxGridCornerLabelWindow() { m_owner = (wxGrid *)NULL; } - wxGridCornerLabelWindow( wxGrid *parent, wxWindowID id, - const wxPoint &pos, const wxSize &size ); - - virtual bool AcceptsFocus() const { return false; } - -private: - wxGrid *m_owner; - - void OnMouseEvent( wxMouseEvent& event ); - void OnMouseWheel( wxMouseEvent& event ); - void OnKeyDown( wxKeyEvent& event ); - void OnKeyUp( wxKeyEvent& ); - void OnChar( wxKeyEvent& ); - void OnPaint( wxPaintEvent& event ); - - DECLARE_DYNAMIC_CLASS(wxGridCornerLabelWindow) - DECLARE_EVENT_TABLE() - DECLARE_NO_COPY_CLASS(wxGridCornerLabelWindow) -}; - -class WXDLLIMPEXP_ADV wxGridWindow : public wxWindow -{ -public: - wxGridWindow() - { - m_owner = NULL; - m_rowLabelWin = NULL; - m_colLabelWin = NULL; - } - - wxGridWindow( wxGrid *parent, - wxGridRowLabelWindow *rowLblWin, - wxGridColLabelWindow *colLblWin, - wxWindowID id, const wxPoint &pos, const wxSize &size ); - virtual ~wxGridWindow() {} - - void ScrollWindow( int dx, int dy, const wxRect *rect ); - - wxGrid* GetOwner() { return m_owner; } - -private: - wxGrid *m_owner; - wxGridRowLabelWindow *m_rowLabelWin; - wxGridColLabelWindow *m_colLabelWin; - - void OnPaint( wxPaintEvent &event ); - void OnMouseWheel( wxMouseEvent& event ); - void OnMouseEvent( wxMouseEvent& event ); - void OnKeyDown( wxKeyEvent& ); - void OnKeyUp( wxKeyEvent& ); - void OnChar( wxKeyEvent& ); - void OnEraseBackground( wxEraseEvent& ); - void OnFocus( wxFocusEvent& ); - - DECLARE_DYNAMIC_CLASS(wxGridWindow) - DECLARE_EVENT_TABLE() - DECLARE_NO_COPY_CLASS(wxGridWindow) -}; - - -class wxGridCellEditorEvtHandler : public wxEvtHandler -{ -public: - wxGridCellEditorEvtHandler(wxGrid* grid, wxGridCellEditor* editor) - : m_grid(grid), - m_editor(editor), - m_inSetFocus(false) - { - } - - void OnKillFocus(wxFocusEvent& event); - void OnKeyDown(wxKeyEvent& event); - void OnChar(wxKeyEvent& event); - - void SetInSetFocus(bool inSetFocus) { m_inSetFocus = inSetFocus; } - -private: - wxGrid *m_grid; - wxGridCellEditor *m_editor; - - // Work around the fact that a focus kill event can be sent to - // a combobox within a set focus event. - bool m_inSetFocus; - - DECLARE_EVENT_TABLE() - DECLARE_DYNAMIC_CLASS(wxGridCellEditorEvtHandler) - DECLARE_NO_COPY_CLASS(wxGridCellEditorEvtHandler) -}; - - -IMPLEMENT_ABSTRACT_CLASS(wxGridCellEditorEvtHandler, wxEvtHandler) - -BEGIN_EVENT_TABLE( wxGridCellEditorEvtHandler, wxEvtHandler ) - EVT_KILL_FOCUS( wxGridCellEditorEvtHandler::OnKillFocus ) - EVT_KEY_DOWN( wxGridCellEditorEvtHandler::OnKeyDown ) - EVT_CHAR( wxGridCellEditorEvtHandler::OnChar ) -END_EVENT_TABLE() - - -// ---------------------------------------------------------------------------- -// the internal data representation used by wxGridCellAttrProvider -// ---------------------------------------------------------------------------- - -// this class stores attributes set for cells -class WXDLLIMPEXP_ADV wxGridCellAttrData -{ -public: - void SetAttr(wxGridCellAttr *attr, int row, int col); - wxGridCellAttr *GetAttr(int row, int col) const; - void UpdateAttrRows( size_t pos, int numRows ); - void UpdateAttrCols( size_t pos, int numCols ); - -private: - // searches for the attr for given cell, returns wxNOT_FOUND if not found - int FindIndex(int row, int col) const; - - wxGridCellWithAttrArray m_attrs; -}; - -// this class stores attributes set for rows or columns -class WXDLLIMPEXP_ADV wxGridRowOrColAttrData -{ -public: - // empty ctor to suppress warnings - wxGridRowOrColAttrData() {} - ~wxGridRowOrColAttrData(); - - void SetAttr(wxGridCellAttr *attr, int rowOrCol); - wxGridCellAttr *GetAttr(int rowOrCol) const; - void UpdateAttrRowsOrCols( size_t pos, int numRowsOrCols ); - -private: - wxArrayInt m_rowsOrCols; - wxArrayAttrs m_attrs; -}; - -// NB: this is just a wrapper around 3 objects: one which stores cell -// attributes, and 2 others for row/col ones -class WXDLLIMPEXP_ADV wxGridCellAttrProviderData -{ -public: - wxGridCellAttrData m_cellAttrs; - wxGridRowOrColAttrData m_rowAttrs, - m_colAttrs; -}; - - -// ---------------------------------------------------------------------------- -// data structures used for the data type registry -// ---------------------------------------------------------------------------- - -struct wxGridDataTypeInfo -{ - wxGridDataTypeInfo(const wxString& typeName, - wxGridCellRenderer* renderer, - wxGridCellEditor* editor) - : m_typeName(typeName), m_renderer(renderer), m_editor(editor) - {} - - ~wxGridDataTypeInfo() - { - wxSafeDecRef(m_renderer); - wxSafeDecRef(m_editor); - } - - wxString m_typeName; - wxGridCellRenderer* m_renderer; - wxGridCellEditor* m_editor; - - DECLARE_NO_COPY_CLASS(wxGridDataTypeInfo) -}; - - -WX_DEFINE_ARRAY_WITH_DECL_PTR(wxGridDataTypeInfo*, wxGridDataTypeInfoArray, - class WXDLLIMPEXP_ADV); - - -class WXDLLIMPEXP_ADV wxGridTypeRegistry -{ -public: - wxGridTypeRegistry() {} - ~wxGridTypeRegistry(); - - void RegisterDataType(const wxString& typeName, - wxGridCellRenderer* renderer, - wxGridCellEditor* editor); - - // find one of already registered data types - int FindRegisteredDataType(const wxString& typeName); - - // try to FindRegisteredDataType(), if this fails and typeName is one of - // standard typenames, register it and return its index - int FindDataType(const wxString& typeName); - - // try to FindDataType(), if it fails see if it is not one of already - // registered data types with some params in which case clone the - // registered data type and set params for it - int FindOrCloneDataType(const wxString& typeName); - - wxGridCellRenderer* GetRenderer(int index); - wxGridCellEditor* GetEditor(int index); - -private: - wxGridDataTypeInfoArray m_typeinfo; -}; - - -// ---------------------------------------------------------------------------- -// conditional compilation -// ---------------------------------------------------------------------------- - -#ifndef WXGRID_DRAW_LINES -#define WXGRID_DRAW_LINES 1 -#endif - -// ---------------------------------------------------------------------------- -// globals -// ---------------------------------------------------------------------------- - -//#define DEBUG_ATTR_CACHE -#ifdef DEBUG_ATTR_CACHE - static size_t gs_nAttrCacheHits = 0; - static size_t gs_nAttrCacheMisses = 0; -#endif - -// ---------------------------------------------------------------------------- -// constants -// ---------------------------------------------------------------------------- - -wxGridCellCoords wxGridNoCellCoords( -1, -1 ); -wxRect wxGridNoCellRect( -1, -1, -1, -1 ); - -// scroll line size -// TODO: this doesn't work at all, grid cells have different sizes and approx -// calculations don't work as because of the size mismatch scrollbars -// sometimes fail to be shown when they should be or vice versa -// -// The scroll bars may be a little flakey once in a while, but that is -// surely much less horrible than having scroll lines of only 1!!! -// -- Robin -// -// Well, it's still seriously broken so it might be better but needs -// fixing anyhow -// -- Vadim -static const size_t GRID_SCROLL_LINE_X = 15; // 1; -static const size_t GRID_SCROLL_LINE_Y = GRID_SCROLL_LINE_X; - -// the size of hash tables used a bit everywhere (the max number of elements -// in these hash tables is the number of rows/columns) -static const int GRID_HASH_SIZE = 100; - -#if 0 -// ---------------------------------------------------------------------------- -// private functions -// ---------------------------------------------------------------------------- - -static inline int GetScrollX(int x) -{ - return (x + GRID_SCROLL_LINE_X - 1) / GRID_SCROLL_LINE_X; -} - -static inline int GetScrollY(int y) -{ - return (y + GRID_SCROLL_LINE_Y - 1) / GRID_SCROLL_LINE_Y; -} -#endif - -// ============================================================================ -// implementation -// ============================================================================ - -// ---------------------------------------------------------------------------- -// wxGridCellEditor -// ---------------------------------------------------------------------------- - -wxGridCellEditor::wxGridCellEditor() -{ - m_control = NULL; - m_attr = NULL; -} - -wxGridCellEditor::~wxGridCellEditor() -{ - Destroy(); -} - -void wxGridCellEditor::Create(wxWindow* WXUNUSED(parent), - wxWindowID WXUNUSED(id), - wxEvtHandler* evtHandler) -{ - if ( evtHandler ) - m_control->PushEventHandler(evtHandler); -} - -void wxGridCellEditor::PaintBackground(const wxRect& rectCell, - wxGridCellAttr *attr) -{ - // erase the background because we might not fill the cell - wxClientDC dc(m_control->GetParent()); - wxGridWindow* gridWindow = wxDynamicCast(m_control->GetParent(), wxGridWindow); - if (gridWindow) - gridWindow->GetOwner()->PrepareDC(dc); - - dc.SetPen(*wxTRANSPARENT_PEN); - dc.SetBrush(wxBrush(attr->GetBackgroundColour(), wxSOLID)); - dc.DrawRectangle(rectCell); - - // redraw the control we just painted over - m_control->Refresh(); -} - -void wxGridCellEditor::Destroy() -{ - if (m_control) - { - m_control->PopEventHandler( true /* delete it*/ ); - - m_control->Destroy(); - m_control = NULL; - } -} - -void wxGridCellEditor::Show(bool show, wxGridCellAttr *attr) -{ - wxASSERT_MSG(m_control, wxT("The wxGridCellEditor must be created first!")); - - m_control->Show(show); - - if ( show ) - { - // set the colours/fonts if we have any - if ( attr ) - { - m_colFgOld = m_control->GetForegroundColour(); - m_control->SetForegroundColour(attr->GetTextColour()); - - m_colBgOld = m_control->GetBackgroundColour(); - m_control->SetBackgroundColour(attr->GetBackgroundColour()); - -// Workaround for GTK+1 font setting problem on some platforms -#if !defined(__WXGTK__) || defined(__WXGTK20__) - m_fontOld = m_control->GetFont(); - m_control->SetFont(attr->GetFont()); -#endif - - // can't do anything more in the base class version, the other - // attributes may only be used by the derived classes - } - } - else - { - // restore the standard colours fonts - if ( m_colFgOld.Ok() ) - { - m_control->SetForegroundColour(m_colFgOld); - m_colFgOld = wxNullColour; - } - - if ( m_colBgOld.Ok() ) - { - m_control->SetBackgroundColour(m_colBgOld); - m_colBgOld = wxNullColour; - } - -// Workaround for GTK+1 font setting problem on some platforms -#if !defined(__WXGTK__) || defined(__WXGTK20__) - if ( m_fontOld.Ok() ) - { - m_control->SetFont(m_fontOld); - m_fontOld = wxNullFont; - } -#endif - } -} - -void wxGridCellEditor::SetSize(const wxRect& rect) -{ - wxASSERT_MSG(m_control, wxT("The wxGridCellEditor must be created first!")); - - m_control->SetSize(rect, wxSIZE_ALLOW_MINUS_ONE); -} - -void wxGridCellEditor::HandleReturn(wxKeyEvent& event) -{ - event.Skip(); -} - -bool wxGridCellEditor::IsAcceptedKey(wxKeyEvent& event) -{ - bool ctrl = event.ControlDown(); - bool alt = event.AltDown(); - -#ifdef __WXMAC__ - // On the Mac the Alt key is more like shift and is used for entry of - // valid characters, so check for Ctrl and Meta instead. - alt = event.MetaDown(); -#endif - - // Assume it's not a valid char if ctrl or alt is down, but if both are - // down then it may be because of an AltGr key combination, so let them - // through in that case. - if ((ctrl || alt) && !(ctrl && alt)) - return false; - - int key = 0; - bool keyOk = true; - -#ifdef __WXGTK20__ - // If it's a F-Key or other special key then it shouldn't start the - // editor. - if (event.GetKeyCode() >= WXK_START) - return false; -#endif -#if wxUSE_UNICODE - // if the unicode key code is not really a unicode character (it may - // be a function key or etc., the platforms appear to always give us a - // small value in this case) then fallback to the ASCII key code but - // don't do anything for function keys or etc. - key = event.GetUnicodeKey(); - if (key <= 127) - { - key = event.GetKeyCode(); - keyOk = (key <= 127); - } -#else - key = event.GetKeyCode(); - keyOk = (key <= 255); -#endif - - return keyOk; -} - -void wxGridCellEditor::StartingKey(wxKeyEvent& event) -{ - event.Skip(); -} - -void wxGridCellEditor::StartingClick() -{ -} - -#if wxUSE_TEXTCTRL - -// ---------------------------------------------------------------------------- -// wxGridCellTextEditor -// ---------------------------------------------------------------------------- - -wxGridCellTextEditor::wxGridCellTextEditor() -{ - m_maxChars = 0; -} - -void wxGridCellTextEditor::Create(wxWindow* parent, - wxWindowID id, - wxEvtHandler* evtHandler) -{ - m_control = new wxTextCtrl(parent, id, wxEmptyString, - wxDefaultPosition, wxDefaultSize -#if defined(__WXMSW__) - , - wxTE_PROCESS_ENTER | - wxTE_PROCESS_TAB | - wxTE_AUTO_SCROLL | - wxNO_BORDER -#endif - ); - - // set max length allowed in the textctrl, if the parameter was set - if (m_maxChars != 0) - { - ((wxTextCtrl*)m_control)->SetMaxLength(m_maxChars); - } - - wxGridCellEditor::Create(parent, id, evtHandler); -} - -void wxGridCellTextEditor::PaintBackground(const wxRect& WXUNUSED(rectCell), - wxGridCellAttr * WXUNUSED(attr)) -{ - // as we fill the entire client area, - // don't do anything here to minimize flicker -} - -void wxGridCellTextEditor::SetSize(const wxRect& rectOrig) -{ - wxRect rect(rectOrig); - - // Make the edit control large enough to allow for internal margins - // - // TODO: remove this if the text ctrl sizing is improved esp. for unix - // -#if defined(__WXGTK__) - if (rect.x != 0) - { - rect.x += 1; - rect.y += 1; - rect.width -= 1; - rect.height -= 1; - } -#elif defined(__WXMSW__) - if ( rect.x == 0 ) - rect.x += 2; - else - rect.x += 3; - - if ( rect.y == 0 ) - rect.y += 2; - else - rect.y += 3; - - rect.width -= 2; - rect.height -= 2; -#else - int extra_x = ( rect.x > 2 ) ? 2 : 1; - int extra_y = ( rect.y > 2 ) ? 2 : 1; - - #if defined(__WXMOTIF__) - extra_x *= 2; - extra_y *= 2; - #endif - - rect.SetLeft( wxMax(0, rect.x - extra_x) ); - rect.SetTop( wxMax(0, rect.y - extra_y) ); - rect.SetRight( rect.GetRight() + 2 * extra_x ); - rect.SetBottom( rect.GetBottom() + 2 * extra_y ); -#endif - - wxGridCellEditor::SetSize(rect); -} - -void wxGridCellTextEditor::BeginEdit(int row, int col, wxGrid* grid) -{ - wxASSERT_MSG(m_control, wxT("The wxGridCellEditor must be created first!")); - - m_startValue = grid->GetTable()->GetValue(row, col); - - DoBeginEdit(m_startValue); -} - -void wxGridCellTextEditor::DoBeginEdit(const wxString& startValue) -{ - Text()->SetValue(startValue); - Text()->SetInsertionPointEnd(); - Text()->SetSelection(-1, -1); - Text()->SetFocus(); -} - -bool wxGridCellTextEditor::EndEdit(int row, int col, wxGrid* grid) -{ - wxASSERT_MSG(m_control, wxT("The wxGridCellEditor must be created first!")); - - bool changed = false; - wxString value = Text()->GetValue(); - if (value != m_startValue) - changed = true; - - if (changed) - grid->GetTable()->SetValue(row, col, value); - - m_startValue = wxEmptyString; - - // No point in setting the text of the hidden control - //Text()->SetValue(m_startValue); - - return changed; -} - -void wxGridCellTextEditor::Reset() -{ - wxASSERT_MSG(m_control, wxT("The wxGridCellEditor must be created first!")); - - DoReset(m_startValue); -} - -void wxGridCellTextEditor::DoReset(const wxString& startValue) -{ - Text()->SetValue(startValue); - Text()->SetInsertionPointEnd(); -} - -bool wxGridCellTextEditor::IsAcceptedKey(wxKeyEvent& event) -{ - return wxGridCellEditor::IsAcceptedKey(event); -} - -void wxGridCellTextEditor::StartingKey(wxKeyEvent& event) -{ - // Since this is now happening in the EVT_CHAR event EmulateKeyPress is no - // longer an appropriate way to get the character into the text control. - // Do it ourselves instead. We know that if we get this far that we have - // a valid character, so not a whole lot of testing needs to be done. - - wxTextCtrl* tc = Text(); - wxChar ch; - long pos; - -#if wxUSE_UNICODE - ch = event.GetUnicodeKey(); - if (ch <= 127) - ch = (wxChar)event.GetKeyCode(); -#else - ch = (wxChar)event.GetKeyCode(); -#endif - - switch (ch) - { - case WXK_DELETE: - // delete the character at the cursor - pos = tc->GetInsertionPoint(); - if (pos < tc->GetLastPosition()) - tc->Remove(pos, pos + 1); - break; - - case WXK_BACK: - // delete the character before the cursor - pos = tc->GetInsertionPoint(); - if (pos > 0) - tc->Remove(pos - 1, pos); - break; - - default: - tc->WriteText(ch); - break; - } -} - -void wxGridCellTextEditor::HandleReturn( wxKeyEvent& - WXUNUSED_GTK(WXUNUSED_MOTIF(event)) ) -{ -#if defined(__WXMOTIF__) || defined(__WXGTK__) - // wxMotif needs a little extra help... - size_t pos = (size_t)( Text()->GetInsertionPoint() ); - wxString s( Text()->GetValue() ); - s = s.Left(pos) + wxT("\n") + s.Mid(pos); - Text()->SetValue(s); - Text()->SetInsertionPoint( pos ); -#else - // the other ports can handle a Return key press - // - event.Skip(); -#endif -} - -void wxGridCellTextEditor::SetParameters(const wxString& params) -{ - if ( !params ) - { - // reset to default - m_maxChars = 0; - } - else - { - long tmp; - if ( params.ToLong(&tmp) ) - { - m_maxChars = (size_t)tmp; - } - else - { - wxLogDebug( _T("Invalid wxGridCellTextEditor parameter string '%s' ignored"), params.c_str() ); - } - } -} - -// return the value in the text control -wxString wxGridCellTextEditor::GetValue() const -{ - return Text()->GetValue(); -} - -// ---------------------------------------------------------------------------- -// wxGridCellNumberEditor -// ---------------------------------------------------------------------------- - -wxGridCellNumberEditor::wxGridCellNumberEditor(int min, int max) -{ - m_min = min; - m_max = max; -} - -void wxGridCellNumberEditor::Create(wxWindow* parent, - wxWindowID id, - wxEvtHandler* evtHandler) -{ -#if wxUSE_SPINCTRL - if ( HasRange() ) - { - // create a spin ctrl - m_control = new wxSpinCtrl(parent, wxID_ANY, wxEmptyString, - wxDefaultPosition, wxDefaultSize, - wxSP_ARROW_KEYS, - m_min, m_max); - - wxGridCellEditor::Create(parent, id, evtHandler); - } - else -#endif - { - // just a text control - wxGridCellTextEditor::Create(parent, id, evtHandler); - -#if wxUSE_VALIDATORS - Text()->SetValidator(wxTextValidator(wxFILTER_NUMERIC)); -#endif - } -} - -void wxGridCellNumberEditor::BeginEdit(int row, int col, wxGrid* grid) -{ - // first get the value - wxGridTableBase *table = grid->GetTable(); - if ( table->CanGetValueAs(row, col, wxGRID_VALUE_NUMBER) ) - { - m_valueOld = table->GetValueAsLong(row, col); - } - else - { - m_valueOld = 0; - wxString sValue = table->GetValue(row, col); - if (! sValue.ToLong(&m_valueOld) && ! sValue.empty()) - { - wxFAIL_MSG( _T("this cell doesn't have numeric value") ); - return; - } - } - -#if wxUSE_SPINCTRL - if ( HasRange() ) - { - Spin()->SetValue((int)m_valueOld); - Spin()->SetFocus(); - } - else -#endif - { - DoBeginEdit(GetString()); - } -} - -bool wxGridCellNumberEditor::EndEdit(int row, int col, - wxGrid* grid) -{ - bool changed; - long value = 0; - wxString text; - -#if wxUSE_SPINCTRL - if ( HasRange() ) - { - value = Spin()->GetValue(); - changed = value != m_valueOld; - if (changed) - text = wxString::Format(wxT("%ld"), value); - } - else -#endif - { - text = Text()->GetValue(); - changed = (text.empty() || text.ToLong(&value)) && (value != m_valueOld); - } - - if ( changed ) - { - if (grid->GetTable()->CanSetValueAs(row, col, wxGRID_VALUE_NUMBER)) - grid->GetTable()->SetValueAsLong(row, col, value); - else - grid->GetTable()->SetValue(row, col, text); - } - - return changed; -} - -void wxGridCellNumberEditor::Reset() -{ -#if wxUSE_SPINCTRL - if ( HasRange() ) - { - Spin()->SetValue((int)m_valueOld); - } - else -#endif - { - DoReset(GetString()); - } -} - -bool wxGridCellNumberEditor::IsAcceptedKey(wxKeyEvent& event) -{ - if ( wxGridCellEditor::IsAcceptedKey(event) ) - { - int keycode = event.GetKeyCode(); - if ( (keycode < 128) && - (wxIsdigit(keycode) || keycode == '+' || keycode == '-')) - { - return true; - } - } - - return false; -} - -void wxGridCellNumberEditor::StartingKey(wxKeyEvent& event) -{ - int keycode = event.GetKeyCode(); - if ( !HasRange() ) - { - if ( wxIsdigit(keycode) || keycode == '+' || keycode == '-') - { - wxGridCellTextEditor::StartingKey(event); - - // skip Skip() below - return; - } - } -#if wxUSE_SPINCTRL - else - { - if ( wxIsdigit(keycode) ) - { - wxSpinCtrl* spin = (wxSpinCtrl*)m_control; - spin->SetValue(keycode - '0'); - spin->SetSelection(1,1); - return; - } - } -#endif - - event.Skip(); -} - -void wxGridCellNumberEditor::SetParameters(const wxString& params) -{ - if ( !params ) - { - // reset to default - m_min = - m_max = -1; - } - else - { - long tmp; - if ( params.BeforeFirst(_T(',')).ToLong(&tmp) ) - { - m_min = (int)tmp; - - if ( params.AfterFirst(_T(',')).ToLong(&tmp) ) - { - m_max = (int)tmp; - - // skip the error message below - return; - } - } - - wxLogDebug(_T("Invalid wxGridCellNumberEditor parameter string '%s' ignored"), params.c_str()); - } -} - -// return the value in the spin control if it is there (the text control otherwise) -wxString wxGridCellNumberEditor::GetValue() const -{ - wxString s; - -#if wxUSE_SPINCTRL - if ( HasRange() ) - { - long value = Spin()->GetValue(); - s.Printf(wxT("%ld"), value); - } - else -#endif - { - s = Text()->GetValue(); - } - - return s; -} - -// ---------------------------------------------------------------------------- -// wxGridCellFloatEditor -// ---------------------------------------------------------------------------- - -wxGridCellFloatEditor::wxGridCellFloatEditor(int width, int precision) -{ - m_width = width; - m_precision = precision; -} - -void wxGridCellFloatEditor::Create(wxWindow* parent, - wxWindowID id, - wxEvtHandler* evtHandler) -{ - wxGridCellTextEditor::Create(parent, id, evtHandler); - -#if wxUSE_VALIDATORS - Text()->SetValidator(wxTextValidator(wxFILTER_NUMERIC)); -#endif -} - -void wxGridCellFloatEditor::BeginEdit(int row, int col, wxGrid* grid) -{ - // first get the value - wxGridTableBase *table = grid->GetTable(); - if ( table->CanGetValueAs(row, col, wxGRID_VALUE_FLOAT) ) - { - m_valueOld = table->GetValueAsDouble(row, col); - } - else - { - m_valueOld = 0.0; - wxString sValue = table->GetValue(row, col); - if (! sValue.ToDouble(&m_valueOld) && ! sValue.empty()) - { - wxFAIL_MSG( _T("this cell doesn't have float value") ); - return; - } - } - - DoBeginEdit(GetString()); -} - -bool wxGridCellFloatEditor::EndEdit(int row, int col, - wxGrid* grid) -{ - double value = 0.0; - wxString text(Text()->GetValue()); - - if ( (text.empty() || text.ToDouble(&value)) && - !wxIsSameDouble(value, m_valueOld) ) - { - if (grid->GetTable()->CanSetValueAs(row, col, wxGRID_VALUE_FLOAT)) - grid->GetTable()->SetValueAsDouble(row, col, value); - else - grid->GetTable()->SetValue(row, col, text); - - return true; - } - - return false; -} - -void wxGridCellFloatEditor::Reset() -{ - DoReset(GetString()); -} - -void wxGridCellFloatEditor::StartingKey(wxKeyEvent& event) -{ - int keycode = event.GetKeyCode(); - char tmpbuf[2]; - tmpbuf[0] = (char) keycode; - tmpbuf[1] = '\0'; - wxString strbuf(tmpbuf, *wxConvCurrent); - -#if wxUSE_INTL - bool is_decimal_point = ( strbuf == - wxLocale::GetInfo(wxLOCALE_DECIMAL_POINT, wxLOCALE_CAT_NUMBER) ); -#else - bool is_decimal_point = ( strbuf == _T(".") ); -#endif - - if ( wxIsdigit(keycode) || keycode == '+' || keycode == '-' - || is_decimal_point ) - { - wxGridCellTextEditor::StartingKey(event); - - // skip Skip() below - return; - } - - event.Skip(); -} - -void wxGridCellFloatEditor::SetParameters(const wxString& params) -{ - if ( !params ) - { - // reset to default - m_width = - m_precision = -1; - } - else - { - long tmp; - if ( params.BeforeFirst(_T(',')).ToLong(&tmp) ) - { - m_width = (int)tmp; - - if ( params.AfterFirst(_T(',')).ToLong(&tmp) ) - { - m_precision = (int)tmp; - - // skip the error message below - return; - } - } - - wxLogDebug(_T("Invalid wxGridCellFloatEditor parameter string '%s' ignored"), params.c_str()); - } -} - -wxString wxGridCellFloatEditor::GetString() const -{ - wxString fmt; - if ( m_precision == -1 && m_width != -1) - { - // default precision - fmt.Printf(_T("%%%d.f"), m_width); - } - else if ( m_precision != -1 && m_width == -1) - { - // default width - fmt.Printf(_T("%%.%df"), m_precision); - } - else if ( m_precision != -1 && m_width != -1 ) - { - fmt.Printf(_T("%%%d.%df"), m_width, m_precision); - } - else - { - // default width/precision - fmt = _T("%f"); - } - - return wxString::Format(fmt, m_valueOld); -} - -bool wxGridCellFloatEditor::IsAcceptedKey(wxKeyEvent& event) -{ - if ( wxGridCellEditor::IsAcceptedKey(event) ) - { - const int keycode = event.GetKeyCode(); - if ( isascii(keycode) ) - { - char tmpbuf[2]; - tmpbuf[0] = (char) keycode; - tmpbuf[1] = '\0'; - wxString strbuf(tmpbuf, *wxConvCurrent); - -#if wxUSE_INTL - const wxString decimalPoint = - wxLocale::GetInfo(wxLOCALE_DECIMAL_POINT, wxLOCALE_CAT_NUMBER); -#else - const wxString decimalPoint(_T('.')); -#endif - - // accept digits, 'e' as in '1e+6', also '-', '+', and '.' - if ( wxIsdigit(keycode) || - tolower(keycode) == 'e' || - keycode == decimalPoint || - keycode == '+' || - keycode == '-' ) - { - return true; - } - } - } - - return false; -} - -#endif // wxUSE_TEXTCTRL - -#if wxUSE_CHECKBOX - -// ---------------------------------------------------------------------------- -// wxGridCellBoolEditor -// ---------------------------------------------------------------------------- - -// the default values for GetValue() -wxString wxGridCellBoolEditor::ms_stringValues[2] = { _T(""), _T("1") }; - -void wxGridCellBoolEditor::Create(wxWindow* parent, - wxWindowID id, - wxEvtHandler* evtHandler) -{ - m_control = new wxCheckBox(parent, id, wxEmptyString, - wxDefaultPosition, wxDefaultSize, - wxNO_BORDER); - - wxGridCellEditor::Create(parent, id, evtHandler); -} - -void wxGridCellBoolEditor::SetSize(const wxRect& r) -{ - bool resize = false; - wxSize size = m_control->GetSize(); - wxCoord minSize = wxMin(r.width, r.height); - - // check if the checkbox is not too big/small for this cell - wxSize sizeBest = m_control->GetBestSize(); - if ( !(size == sizeBest) ) - { - // reset to default size if it had been made smaller - size = sizeBest; - - resize = true; - } - - if ( size.x >= minSize || size.y >= minSize ) - { - // leave 1 pixel margin - size.x = size.y = minSize - 2; - - resize = true; - } - - if ( resize ) - { - m_control->SetSize(size); - } - - // position it in the centre of the rectangle (TODO: support alignment?) - -#if defined(__WXGTK__) || defined (__WXMOTIF__) - // the checkbox without label still has some space to the right in wxGTK, - // so shift it to the right - size.x -= 8; -#elif defined(__WXMSW__) - // here too, but in other way - size.x += 1; - size.y -= 2; -#endif - - int hAlign = wxALIGN_CENTRE; - int vAlign = wxALIGN_CENTRE; - if (GetCellAttr()) - GetCellAttr()->GetAlignment(& hAlign, & vAlign); - - int x = 0, y = 0; - if (hAlign == wxALIGN_LEFT) - { - x = r.x + 2; - -#ifdef __WXMSW__ - x += 2; -#endif - - y = r.y + r.height / 2 - size.y / 2; - } - else if (hAlign == wxALIGN_RIGHT) - { - x = r.x + r.width - size.x - 2; - y = r.y + r.height / 2 - size.y / 2; - } - else if (hAlign == wxALIGN_CENTRE) - { - x = r.x + r.width / 2 - size.x / 2; - y = r.y + r.height / 2 - size.y / 2; - } - - m_control->Move(x, y); -} - -void wxGridCellBoolEditor::Show(bool show, wxGridCellAttr *attr) -{ - m_control->Show(show); - - if ( show ) - { - wxColour colBg = attr ? attr->GetBackgroundColour() : *wxLIGHT_GREY; - CBox()->SetBackgroundColour(colBg); - } -} - -void wxGridCellBoolEditor::BeginEdit(int row, int col, wxGrid* grid) -{ - wxASSERT_MSG(m_control, - wxT("The wxGridCellEditor must be created first!")); - - if (grid->GetTable()->CanGetValueAs(row, col, wxGRID_VALUE_BOOL)) - { - m_startValue = grid->GetTable()->GetValueAsBool(row, col); - } - else - { - wxString cellval( grid->GetTable()->GetValue(row, col) ); - - if ( cellval == ms_stringValues[false] ) - m_startValue = false; - else if ( cellval == ms_stringValues[true] ) - m_startValue = true; - else - { - // do not try to be smart here and convert it to true or false - // because we'll still overwrite it with something different and - // this risks to be very surprising for the user code, let them - // know about it - wxFAIL_MSG( _T("invalid value for a cell with bool editor!") ); - } - } - - CBox()->SetValue(m_startValue); - CBox()->SetFocus(); -} - -bool wxGridCellBoolEditor::EndEdit(int row, int col, - wxGrid* grid) -{ - wxASSERT_MSG(m_control, - wxT("The wxGridCellEditor must be created first!")); - - bool changed = false; - bool value = CBox()->GetValue(); - if ( value != m_startValue ) - changed = true; - - if ( changed ) - { - wxGridTableBase * const table = grid->GetTable(); - if ( table->CanGetValueAs(row, col, wxGRID_VALUE_BOOL) ) - table->SetValueAsBool(row, col, value); - else - table->SetValue(row, col, GetValue()); - } - - return changed; -} - -void wxGridCellBoolEditor::Reset() -{ - wxASSERT_MSG(m_control, - wxT("The wxGridCellEditor must be created first!")); - - CBox()->SetValue(m_startValue); -} - -void wxGridCellBoolEditor::StartingClick() -{ - CBox()->SetValue(!CBox()->GetValue()); -} - -bool wxGridCellBoolEditor::IsAcceptedKey(wxKeyEvent& event) -{ - if ( wxGridCellEditor::IsAcceptedKey(event) ) - { - int keycode = event.GetKeyCode(); - switch ( keycode ) - { - case WXK_SPACE: - case '+': - case '-': - return true; - } - } - - return false; -} - -void wxGridCellBoolEditor::StartingKey(wxKeyEvent& event) -{ - int keycode = event.GetKeyCode(); - switch ( keycode ) - { - case WXK_SPACE: - CBox()->SetValue(!CBox()->GetValue()); - break; - - case '+': - CBox()->SetValue(true); - break; - - case '-': - CBox()->SetValue(false); - break; - } -} - -wxString wxGridCellBoolEditor::GetValue() const -{ - return ms_stringValues[CBox()->GetValue()]; -} - -/* static */ void -wxGridCellBoolEditor::UseStringValues(const wxString& valueTrue, - const wxString& valueFalse) -{ - ms_stringValues[false] = valueFalse; - ms_stringValues[true] = valueTrue; -} - -/* static */ bool -wxGridCellBoolEditor::IsTrueValue(const wxString& value) -{ - return value == ms_stringValues[true]; -} - -#endif // wxUSE_CHECKBOX - -#if wxUSE_COMBOBOX - -// ---------------------------------------------------------------------------- -// wxGridCellChoiceEditor -// ---------------------------------------------------------------------------- - -wxGridCellChoiceEditor::wxGridCellChoiceEditor(const wxArrayString& choices, - bool allowOthers) - : m_choices(choices), - m_allowOthers(allowOthers) { } - -wxGridCellChoiceEditor::wxGridCellChoiceEditor(size_t count, - const wxString choices[], - bool allowOthers) - : m_allowOthers(allowOthers) -{ - if ( count ) - { - m_choices.Alloc(count); - for ( size_t n = 0; n < count; n++ ) - { - m_choices.Add(choices[n]); - } - } -} - -wxGridCellEditor *wxGridCellChoiceEditor::Clone() const -{ - wxGridCellChoiceEditor *editor = new wxGridCellChoiceEditor; - editor->m_allowOthers = m_allowOthers; - editor->m_choices = m_choices; - - return editor; -} - -void wxGridCellChoiceEditor::Create(wxWindow* parent, - wxWindowID id, - wxEvtHandler* evtHandler) -{ - int style = wxTE_PROCESS_ENTER | - wxTE_PROCESS_TAB | - wxBORDER_NONE; - - if ( !m_allowOthers ) - style |= wxCB_READONLY; - - m_control = new wxComboBox(parent, id, wxEmptyString, - wxDefaultPosition, wxDefaultSize, - m_choices, - style); - - wxGridCellEditor::Create(parent, id, evtHandler); -} - -void wxGridCellChoiceEditor::PaintBackground(const wxRect& rectCell, - wxGridCellAttr * attr) -{ - // as we fill the entire client area, don't do anything here to minimize - // flicker - - // TODO: It doesn't actually fill the client area since the height of a - // combo always defaults to the standard. Until someone has time to - // figure out the right rectangle to paint, just do it the normal way. - wxGridCellEditor::PaintBackground(rectCell, attr); -} - -void wxGridCellChoiceEditor::BeginEdit(int row, int col, wxGrid* grid) -{ - wxASSERT_MSG(m_control, - wxT("The wxGridCellEditor must be created first!")); - - wxGridCellEditorEvtHandler* evtHandler = NULL; - if (m_control) - evtHandler = wxDynamicCast(m_control->GetEventHandler(), wxGridCellEditorEvtHandler); - - // Don't immediately end if we get a kill focus event within BeginEdit - if (evtHandler) - evtHandler->SetInSetFocus(true); - - m_startValue = grid->GetTable()->GetValue(row, col); - - if (m_allowOthers) - { - Combo()->SetValue(m_startValue); - } - else - { - // find the right position, or default to the first if not found - int pos = Combo()->FindString(m_startValue); - if (pos == wxNOT_FOUND) - pos = 0; - Combo()->SetSelection(pos); - } - - Combo()->SetInsertionPointEnd(); - Combo()->SetFocus(); - - if (evtHandler) - { - // When dropping down the menu, a kill focus event - // happens after this point, so we can't reset the flag yet. -#if !defined(__WXGTK20__) - evtHandler->SetInSetFocus(false); -#endif - } -} - -bool wxGridCellChoiceEditor::EndEdit(int row, int col, - wxGrid* grid) -{ - wxString value = Combo()->GetValue(); - if ( value == m_startValue ) - return false; - - grid->GetTable()->SetValue(row, col, value); - - return true; -} - -void wxGridCellChoiceEditor::Reset() -{ - Combo()->SetValue(m_startValue); - Combo()->SetInsertionPointEnd(); -} - -void wxGridCellChoiceEditor::SetParameters(const wxString& params) -{ - if ( !params ) - { - // what can we do? - return; - } - - m_choices.Empty(); - - wxStringTokenizer tk(params, _T(',')); - while ( tk.HasMoreTokens() ) - { - m_choices.Add(tk.GetNextToken()); - } -} - -// return the value in the text control -wxString wxGridCellChoiceEditor::GetValue() const -{ - return Combo()->GetValue(); -} - -#endif // wxUSE_COMBOBOX - -// ---------------------------------------------------------------------------- -// wxGridCellEditorEvtHandler -// ---------------------------------------------------------------------------- - -void wxGridCellEditorEvtHandler::OnKillFocus(wxFocusEvent& event) -{ - // Don't disable the cell if we're just starting to edit it - if (m_inSetFocus) - return; - - // accept changes - m_grid->DisableCellEditControl(); - - event.Skip(); -} - -void wxGridCellEditorEvtHandler::OnKeyDown(wxKeyEvent& event) -{ - switch ( event.GetKeyCode() ) - { - case WXK_ESCAPE: - m_editor->Reset(); - m_grid->DisableCellEditControl(); - break; - - case WXK_TAB: - m_grid->GetEventHandler()->ProcessEvent( event ); - break; - - case WXK_RETURN: - case WXK_NUMPAD_ENTER: - if (!m_grid->GetEventHandler()->ProcessEvent(event)) - m_editor->HandleReturn(event); - break; - - default: - event.Skip(); - break; - } -} - -void wxGridCellEditorEvtHandler::OnChar(wxKeyEvent& event) -{ - int row = m_grid->GetGridCursorRow(); - int col = m_grid->GetGridCursorCol(); - wxRect rect = m_grid->CellToRect( row, col ); - int cw, ch; - m_grid->GetGridWindow()->GetClientSize( &cw, &ch ); - - // if cell width is smaller than grid client area, cell is wholly visible - bool wholeCellVisible = (rect.GetWidth() < cw); - - switch ( event.GetKeyCode() ) - { - case WXK_ESCAPE: - case WXK_TAB: - case WXK_RETURN: - case WXK_NUMPAD_ENTER: - break; - - case WXK_HOME: - { - if ( wholeCellVisible ) - { - // no special processing needed... - event.Skip(); - break; - } - - // do special processing for partly visible cell... - - // get the widths of all cells previous to this one - int colXPos = 0; - for ( int i = 0; i < col; i++ ) - { - colXPos += m_grid->GetColSize(i); - } - - int xUnit = 1, yUnit = 1; - m_grid->GetScrollPixelsPerUnit(&xUnit, &yUnit); - if (col != 0) - { - m_grid->Scroll(colXPos / xUnit - 1, m_grid->GetScrollPos(wxVERTICAL)); - } - else - { - m_grid->Scroll(colXPos / xUnit, m_grid->GetScrollPos(wxVERTICAL)); - } - event.Skip(); - break; - } - - case WXK_END: - { - if ( wholeCellVisible ) - { - // no special processing needed... - event.Skip(); - break; - } - - // do special processing for partly visible cell... - - int textWidth = 0; - wxString value = m_grid->GetCellValue(row, col); - if ( wxEmptyString != value ) - { - // get width of cell CONTENTS (text) - int y; - wxFont font = m_grid->GetCellFont(row, col); - m_grid->GetTextExtent(value, &textWidth, &y, NULL, NULL, &font); - - // try to RIGHT align the text by scrolling - int client_right = m_grid->GetGridWindow()->GetClientSize().GetWidth(); - - // (m_grid->GetScrollLineX()*2) is a factor for not scrolling to far, - // otherwise the last part of the cell content might be hidden below the scroll bar - // FIXME: maybe there is a more suitable correction? - textWidth -= (client_right - (m_grid->GetScrollLineX() * 2)); - if ( textWidth < 0 ) - { - textWidth = 0; - } - } - - // get the widths of all cells previous to this one - int colXPos = 0; - for ( int i = 0; i < col; i++ ) - { - colXPos += m_grid->GetColSize(i); - } - - // and add the (modified) text width of the cell contents - // as we'd like to see the last part of the cell contents - colXPos += textWidth; - - int xUnit = 1, yUnit = 1; - m_grid->GetScrollPixelsPerUnit(&xUnit, &yUnit); - m_grid->Scroll(colXPos / xUnit - 1, m_grid->GetScrollPos(wxVERTICAL)); - event.Skip(); - break; - } - - default: - event.Skip(); - break; - } -} - -// ---------------------------------------------------------------------------- -// wxGridCellWorker is an (almost) empty common base class for -// wxGridCellRenderer and wxGridCellEditor managing ref counting -// ---------------------------------------------------------------------------- - -void wxGridCellWorker::SetParameters(const wxString& WXUNUSED(params)) -{ - // nothing to do -} - -wxGridCellWorker::~wxGridCellWorker() -{ -} - -// ============================================================================ -// renderer classes -// ============================================================================ - -// ---------------------------------------------------------------------------- -// wxGridCellRenderer -// ---------------------------------------------------------------------------- - -void wxGridCellRenderer::Draw(wxGrid& grid, - wxGridCellAttr& attr, - wxDC& dc, - const wxRect& rect, - int WXUNUSED(row), int WXUNUSED(col), - bool isSelected) -{ - dc.SetBackgroundMode( wxSOLID ); - - // grey out fields if the grid is disabled - if ( grid.IsEnabled() ) - { - if ( isSelected ) - { - wxColour clr; - if ( wxWindow::FindFocus() == grid.GetGridWindow() ) - clr = grid.GetSelectionBackground(); - else - clr = wxSystemSettings::GetColour(wxSYS_COLOUR_BTNSHADOW); - dc.SetBrush( wxBrush(clr, wxSOLID) ); - } - else - { - dc.SetBrush( wxBrush(attr.GetBackgroundColour(), wxSOLID) ); - } - } - else - { - dc.SetBrush(wxBrush(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE), wxSOLID)); - } - - dc.SetPen( *wxTRANSPARENT_PEN ); - dc.DrawRectangle(rect); -} - -// ---------------------------------------------------------------------------- -// wxGridCellStringRenderer -// ---------------------------------------------------------------------------- - -void wxGridCellStringRenderer::SetTextColoursAndFont(const wxGrid& grid, - const wxGridCellAttr& attr, - wxDC& dc, - bool isSelected) -{ - dc.SetBackgroundMode( wxTRANSPARENT ); - - // TODO some special colours for attr.IsReadOnly() case? - - // different coloured text when the grid is disabled - if ( grid.IsEnabled() ) - { - if ( isSelected ) - { - wxColour clr; - if ( wxWindow::FindFocus() == - wx_const_cast(wxGrid&, grid).GetGridWindow() ) - clr = grid.GetSelectionBackground(); - else - clr = wxSystemSettings::GetColour(wxSYS_COLOUR_BTNSHADOW); - dc.SetTextBackground( clr ); - dc.SetTextForeground( grid.GetSelectionForeground() ); - } - else - { - dc.SetTextBackground( attr.GetBackgroundColour() ); - dc.SetTextForeground( attr.GetTextColour() ); - } - } - else - { - dc.SetTextBackground(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE)); - dc.SetTextForeground(wxSystemSettings::GetColour(wxSYS_COLOUR_GRAYTEXT)); - } - - dc.SetFont( attr.GetFont() ); -} - -wxSize wxGridCellStringRenderer::DoGetBestSize(const wxGridCellAttr& attr, - wxDC& dc, - const wxString& text) -{ - wxCoord x = 0, y = 0, max_x = 0; - dc.SetFont(attr.GetFont()); - wxStringTokenizer tk(text, _T('\n')); - while ( tk.HasMoreTokens() ) - { - dc.GetTextExtent(tk.GetNextToken(), &x, &y); - max_x = wxMax(max_x, x); - } - - y *= 1 + text.Freq(wxT('\n')); // multiply by the number of lines. - - return wxSize(max_x, y); -} - -wxSize wxGridCellStringRenderer::GetBestSize(wxGrid& grid, - wxGridCellAttr& attr, - wxDC& dc, - int row, int col) -{ - return DoGetBestSize(attr, dc, grid.GetCellValue(row, col)); -} - -void wxGridCellStringRenderer::Draw(wxGrid& grid, - wxGridCellAttr& attr, - wxDC& dc, - const wxRect& rectCell, - int row, int col, - bool isSelected) -{ - wxRect rect = rectCell; - rect.Inflate(-1); - - // erase only this cells background, overflow cells should have been erased - wxGridCellRenderer::Draw(grid, attr, dc, rectCell, row, col, isSelected); - - int hAlign, vAlign; - attr.GetAlignment(&hAlign, &vAlign); - - int overflowCols = 0; - - if (attr.GetOverflow()) - { - int cols = grid.GetNumberCols(); - int best_width = GetBestSize(grid,attr,dc,row,col).GetWidth(); - int cell_rows, cell_cols; - attr.GetSize( &cell_rows, &cell_cols ); // shouldn't get here if <= 0 - if ((best_width > rectCell.width) && (col < cols) && grid.GetTable()) - { - int i, c_cols, c_rows; - for (i = col+cell_cols; i < cols; i++) - { - bool is_empty = true; - for (int j=row; j < row + cell_rows; j++) - { - // check w/ anchor cell for multicell block - grid.GetCellSize(j, i, &c_rows, &c_cols); - if (c_rows > 0) - c_rows = 0; - if (!grid.GetTable()->IsEmptyCell(j + c_rows, i)) - { - is_empty = false; - break; - } - } - - if (is_empty) - { - rect.width += grid.GetColSize(i); - } - else - { - i--; - break; - } - - if (rect.width >= best_width) - break; - } - - overflowCols = i - col - cell_cols + 1; - if (overflowCols >= cols) - overflowCols = cols - 1; - } - - if (overflowCols > 0) // redraw overflow cells w/ proper hilight - { - hAlign = wxALIGN_LEFT; // if oveflowed then it's left aligned - wxRect clip = rect; - clip.x += rectCell.width; - // draw each overflow cell individually - int col_end = col + cell_cols + overflowCols; - if (col_end >= grid.GetNumberCols()) - col_end = grid.GetNumberCols() - 1; - for (int i = col + cell_cols; i <= col_end; i++) - { - clip.width = grid.GetColSize(i) - 1; - dc.DestroyClippingRegion(); - dc.SetClippingRegion(clip); - - SetTextColoursAndFont(grid, attr, dc, - grid.IsInSelection(row,i)); - - grid.DrawTextRectangle(dc, grid.GetCellValue(row, col), - rect, hAlign, vAlign); - clip.x += grid.GetColSize(i) - 1; - } - - rect = rectCell; - rect.Inflate(-1); - rect.width++; - dc.DestroyClippingRegion(); - } - } - - // now we only have to draw the text - SetTextColoursAndFont(grid, attr, dc, isSelected); - - grid.DrawTextRectangle(dc, grid.GetCellValue(row, col), - rect, hAlign, vAlign); -} - -// ---------------------------------------------------------------------------- -// wxGridCellNumberRenderer -// ---------------------------------------------------------------------------- - -wxString wxGridCellNumberRenderer::GetString(const wxGrid& grid, int row, int col) -{ - wxGridTableBase *table = grid.GetTable(); - wxString text; - if ( table->CanGetValueAs(row, col, wxGRID_VALUE_NUMBER) ) - { - text.Printf(_T("%ld"), table->GetValueAsLong(row, col)); - } - else - { - text = table->GetValue(row, col); - } - - return text; -} - -void wxGridCellNumberRenderer::Draw(wxGrid& grid, - wxGridCellAttr& attr, - wxDC& dc, - const wxRect& rectCell, - int row, int col, - bool isSelected) -{ - wxGridCellRenderer::Draw(grid, attr, dc, rectCell, row, col, isSelected); - - SetTextColoursAndFont(grid, attr, dc, isSelected); - - // draw the text right aligned by default - int hAlign, vAlign; - attr.GetAlignment(&hAlign, &vAlign); - hAlign = wxALIGN_RIGHT; - - wxRect rect = rectCell; - rect.Inflate(-1); - - grid.DrawTextRectangle(dc, GetString(grid, row, col), rect, hAlign, vAlign); -} - -wxSize wxGridCellNumberRenderer::GetBestSize(wxGrid& grid, - wxGridCellAttr& attr, - wxDC& dc, - int row, int col) -{ - return DoGetBestSize(attr, dc, GetString(grid, row, col)); -} - -// ---------------------------------------------------------------------------- -// wxGridCellFloatRenderer -// ---------------------------------------------------------------------------- - -wxGridCellFloatRenderer::wxGridCellFloatRenderer(int width, int precision) -{ - SetWidth(width); - SetPrecision(precision); -} - -wxGridCellRenderer *wxGridCellFloatRenderer::Clone() const -{ - wxGridCellFloatRenderer *renderer = new wxGridCellFloatRenderer; - renderer->m_width = m_width; - renderer->m_precision = m_precision; - renderer->m_format = m_format; - - return renderer; -} - -wxString wxGridCellFloatRenderer::GetString(const wxGrid& grid, int row, int col) -{ - wxGridTableBase *table = grid.GetTable(); - - bool hasDouble; - double val; - wxString text; - if ( table->CanGetValueAs(row, col, wxGRID_VALUE_FLOAT) ) - { - val = table->GetValueAsDouble(row, col); - hasDouble = true; - } - else - { - text = table->GetValue(row, col); - hasDouble = text.ToDouble(&val); - } - - if ( hasDouble ) - { - if ( !m_format ) - { - if ( m_width == -1 ) - { - if ( m_precision == -1 ) - { - // default width/precision - m_format = _T("%f"); - } - else - { - m_format.Printf(_T("%%.%df"), m_precision); - } - } - else if ( m_precision == -1 ) - { - // default precision - m_format.Printf(_T("%%%d.f"), m_width); - } - else - { - m_format.Printf(_T("%%%d.%df"), m_width, m_precision); - } - } - - text.Printf(m_format, val); - - } - //else: text already contains the string - - return text; -} - -void wxGridCellFloatRenderer::Draw(wxGrid& grid, - wxGridCellAttr& attr, - wxDC& dc, - const wxRect& rectCell, - int row, int col, - bool isSelected) -{ - wxGridCellRenderer::Draw(grid, attr, dc, rectCell, row, col, isSelected); - - SetTextColoursAndFont(grid, attr, dc, isSelected); - - // draw the text right aligned by default - int hAlign, vAlign; - attr.GetAlignment(&hAlign, &vAlign); - hAlign = wxALIGN_RIGHT; - - wxRect rect = rectCell; - rect.Inflate(-1); - - grid.DrawTextRectangle(dc, GetString(grid, row, col), rect, hAlign, vAlign); -} - -wxSize wxGridCellFloatRenderer::GetBestSize(wxGrid& grid, - wxGridCellAttr& attr, - wxDC& dc, - int row, int col) -{ - return DoGetBestSize(attr, dc, GetString(grid, row, col)); -} - -void wxGridCellFloatRenderer::SetParameters(const wxString& params) -{ - if ( !params ) - { - // reset to defaults - SetWidth(-1); - SetPrecision(-1); - } - else - { - wxString tmp = params.BeforeFirst(_T(',')); - if ( !tmp.empty() ) - { - long width; - if ( tmp.ToLong(&width) ) - { - SetWidth((int)width); - } - else - { - wxLogDebug(_T("Invalid wxGridCellFloatRenderer width parameter string '%s ignored"), params.c_str()); - } - } - - tmp = params.AfterFirst(_T(',')); - if ( !tmp.empty() ) - { - long precision; - if ( tmp.ToLong(&precision) ) - { - SetPrecision((int)precision); - } - else - { - wxLogDebug(_T("Invalid wxGridCellFloatRenderer precision parameter string '%s ignored"), params.c_str()); - } - } - } -} - -// ---------------------------------------------------------------------------- -// wxGridCellBoolRenderer -// ---------------------------------------------------------------------------- - -wxSize wxGridCellBoolRenderer::ms_sizeCheckMark; - -// FIXME these checkbox size calculations are really ugly... - -// between checkmark and box -static const wxCoord wxGRID_CHECKMARK_MARGIN = 2; - -wxSize wxGridCellBoolRenderer::GetBestSize(wxGrid& grid, - wxGridCellAttr& WXUNUSED(attr), - wxDC& WXUNUSED(dc), - int WXUNUSED(row), - int WXUNUSED(col)) -{ - // compute it only once (no locks for MT safeness in GUI thread...) - if ( !ms_sizeCheckMark.x ) - { - // get checkbox size - wxCheckBox *checkbox = new wxCheckBox(&grid, wxID_ANY, wxEmptyString); - wxSize size = checkbox->GetBestSize(); - wxCoord checkSize = size.y + 2 * wxGRID_CHECKMARK_MARGIN; - - // FIXME wxGTK::wxCheckBox::GetBestSize() gives "wrong" result -#if defined(__WXGTK__) || defined(__WXMOTIF__) - checkSize -= size.y / 2; -#endif - - delete checkbox; - - ms_sizeCheckMark.x = ms_sizeCheckMark.y = checkSize; - } - - return ms_sizeCheckMark; -} - -void wxGridCellBoolRenderer::Draw(wxGrid& grid, - wxGridCellAttr& attr, - wxDC& dc, - const wxRect& rect, - int row, int col, - bool isSelected) -{ - wxGridCellRenderer::Draw(grid, attr, dc, rect, row, col, isSelected); - - // draw a check mark in the centre (ignoring alignment - TODO) - wxSize size = GetBestSize(grid, attr, dc, row, col); - - // don't draw outside the cell - wxCoord minSize = wxMin(rect.width, rect.height); - if ( size.x >= minSize || size.y >= minSize ) - { - // and even leave (at least) 1 pixel margin - size.x = size.y = minSize - 2; - } - - // draw a border around checkmark - int vAlign, hAlign; - attr.GetAlignment(&hAlign, &vAlign); - - wxRect rectBorder; - if (hAlign == wxALIGN_CENTRE) - { - rectBorder.x = rect.x + rect.width / 2 - size.x / 2; - rectBorder.y = rect.y + rect.height / 2 - size.y / 2; - rectBorder.width = size.x; - rectBorder.height = size.y; - } - else if (hAlign == wxALIGN_LEFT) - { - rectBorder.x = rect.x + 2; - rectBorder.y = rect.y + rect.height / 2 - size.y / 2; - rectBorder.width = size.x; - rectBorder.height = size.y; - } - else if (hAlign == wxALIGN_RIGHT) - { - rectBorder.x = rect.x + rect.width - size.x - 2; - rectBorder.y = rect.y + rect.height / 2 - size.y / 2; - rectBorder.width = size.x; - rectBorder.height = size.y; - } - - bool value; - if ( grid.GetTable()->CanGetValueAs(row, col, wxGRID_VALUE_BOOL) ) - { - value = grid.GetTable()->GetValueAsBool(row, col); - } - else - { - wxString cellval( grid.GetTable()->GetValue(row, col) ); - value = wxGridCellBoolEditor::IsTrueValue(cellval); - } - - if ( value ) - { - wxRect rectMark = rectBorder; - -#ifdef __WXMSW__ - // MSW DrawCheckMark() is weird (and should probably be changed...) - rectMark.Inflate(-wxGRID_CHECKMARK_MARGIN / 2); - rectMark.x++; - rectMark.y++; -#else - rectMark.Inflate(-wxGRID_CHECKMARK_MARGIN); -#endif - - dc.SetTextForeground(attr.GetTextColour()); - dc.DrawCheckMark(rectMark); - } - - dc.SetBrush(*wxTRANSPARENT_BRUSH); - dc.SetPen(wxPen(attr.GetTextColour(), 1, wxSOLID)); - dc.DrawRectangle(rectBorder); -} - -// ---------------------------------------------------------------------------- -// wxGridCellAttr -// ---------------------------------------------------------------------------- - -void wxGridCellAttr::Init(wxGridCellAttr *attrDefault) -{ - m_nRef = 1; - - m_isReadOnly = Unset; - - m_renderer = NULL; - m_editor = NULL; - - m_attrkind = wxGridCellAttr::Cell; - - m_sizeRows = m_sizeCols = 1; - m_overflow = UnsetOverflow; - - SetDefAttr(attrDefault); -} - -wxGridCellAttr *wxGridCellAttr::Clone() const -{ - wxGridCellAttr *attr = new wxGridCellAttr(m_defGridAttr); - - if ( HasTextColour() ) - attr->SetTextColour(GetTextColour()); - if ( HasBackgroundColour() ) - attr->SetBackgroundColour(GetBackgroundColour()); - if ( HasFont() ) - attr->SetFont(GetFont()); - if ( HasAlignment() ) - attr->SetAlignment(m_hAlign, m_vAlign); - - attr->SetSize( m_sizeRows, m_sizeCols ); - - if ( m_renderer ) - { - attr->SetRenderer(m_renderer); - m_renderer->IncRef(); - } - if ( m_editor ) - { - attr->SetEditor(m_editor); - m_editor->IncRef(); - } - - if ( IsReadOnly() ) - attr->SetReadOnly(); - - attr->SetOverflow( m_overflow == Overflow ); - attr->SetKind( m_attrkind ); - - return attr; -} - -void wxGridCellAttr::MergeWith(wxGridCellAttr *mergefrom) -{ - if ( !HasTextColour() && mergefrom->HasTextColour() ) - SetTextColour(mergefrom->GetTextColour()); - if ( !HasBackgroundColour() && mergefrom->HasBackgroundColour() ) - SetBackgroundColour(mergefrom->GetBackgroundColour()); - if ( !HasFont() && mergefrom->HasFont() ) - SetFont(mergefrom->GetFont()); - if ( !HasAlignment() && mergefrom->HasAlignment() ) - { - int hAlign, vAlign; - mergefrom->GetAlignment( &hAlign, &vAlign); - SetAlignment(hAlign, vAlign); - } - if ( !HasSize() && mergefrom->HasSize() ) - mergefrom->GetSize( &m_sizeRows, &m_sizeCols ); - - // Directly access member functions as GetRender/Editor don't just return - // m_renderer/m_editor - // - // Maybe add support for merge of Render and Editor? - if (!HasRenderer() && mergefrom->HasRenderer() ) - { - m_renderer = mergefrom->m_renderer; - m_renderer->IncRef(); - } - if ( !HasEditor() && mergefrom->HasEditor() ) - { - m_editor = mergefrom->m_editor; - m_editor->IncRef(); - } - if ( !HasReadWriteMode() && mergefrom->HasReadWriteMode() ) - SetReadOnly(mergefrom->IsReadOnly()); - - if (!HasOverflowMode() && mergefrom->HasOverflowMode() ) - SetOverflow(mergefrom->GetOverflow()); - - SetDefAttr(mergefrom->m_defGridAttr); -} - -void wxGridCellAttr::SetSize(int num_rows, int num_cols) -{ - // The size of a cell is normally 1,1 - - // If this cell is larger (2,2) then this is the top left cell - // the other cells that will be covered (lower right cells) must be - // set to negative or zero values such that - // row + num_rows of the covered cell points to the larger cell (this cell) - // same goes for the col + num_cols. - - // Size of 0,0 is NOT valid, neither is <=0 and any positive value - - wxASSERT_MSG( (!((num_rows > 0) && (num_cols <= 0)) || - !((num_rows <= 0) && (num_cols > 0)) || - !((num_rows == 0) && (num_cols == 0))), - wxT("wxGridCellAttr::SetSize only takes two postive values or negative/zero values")); - - m_sizeRows = num_rows; - m_sizeCols = num_cols; -} - -const wxColour& wxGridCellAttr::GetTextColour() const -{ - if (HasTextColour()) - { - return m_colText; - } - else if (m_defGridAttr && m_defGridAttr != this) - { - return m_defGridAttr->GetTextColour(); - } - else - { - wxFAIL_MSG(wxT("Missing default cell attribute")); - return wxNullColour; - } -} - -const wxColour& wxGridCellAttr::GetBackgroundColour() const -{ - if (HasBackgroundColour()) - { - return m_colBack; - } - else if (m_defGridAttr && m_defGridAttr != this) - { - return m_defGridAttr->GetBackgroundColour(); - } - else - { - wxFAIL_MSG(wxT("Missing default cell attribute")); - return wxNullColour; - } -} - -const wxFont& wxGridCellAttr::GetFont() const -{ - if (HasFont()) - { - return m_font; - } - else if (m_defGridAttr && m_defGridAttr != this) - { - return m_defGridAttr->GetFont(); - } - else - { - wxFAIL_MSG(wxT("Missing default cell attribute")); - return wxNullFont; - } -} - -void wxGridCellAttr::GetAlignment(int *hAlign, int *vAlign) const -{ - if (HasAlignment()) - { - if ( hAlign ) - *hAlign = m_hAlign; - if ( vAlign ) - *vAlign = m_vAlign; - } - else if (m_defGridAttr && m_defGridAttr != this) - { - m_defGridAttr->GetAlignment(hAlign, vAlign); - } - else - { - wxFAIL_MSG(wxT("Missing default cell attribute")); - } -} - -void wxGridCellAttr::GetSize( int *num_rows, int *num_cols ) const -{ - if ( num_rows ) - *num_rows = m_sizeRows; - if ( num_cols ) - *num_cols = m_sizeCols; -} - -// GetRenderer and GetEditor use a slightly different decision path about -// which attribute to use. If a non-default attr object has one then it is -// used, otherwise the default editor or renderer is fetched from the grid and -// used. It should be the default for the data type of the cell. If it is -// NULL (because the table has a type that the grid does not have in its -// registry), then the grid's default editor or renderer is used. - -wxGridCellRenderer* wxGridCellAttr::GetRenderer(wxGrid* grid, int row, int col) const -{ - wxGridCellRenderer *renderer = NULL; - - if ( m_renderer && this != m_defGridAttr ) - { - // use the cells renderer if it has one - renderer = m_renderer; - renderer->IncRef(); - } - else // no non-default cell renderer - { - // get default renderer for the data type - if ( grid ) - { - // GetDefaultRendererForCell() will do IncRef() for us - renderer = grid->GetDefaultRendererForCell(row, col); - } - - if ( renderer == NULL ) - { - if ( (m_defGridAttr != NULL) && (m_defGridAttr != this) ) - { - // if we still don't have one then use the grid default - // (no need for IncRef() here neither) - renderer = m_defGridAttr->GetRenderer(NULL, 0, 0); - } - else // default grid attr - { - // use m_renderer which we had decided not to use initially - renderer = m_renderer; - if ( renderer ) - renderer->IncRef(); - } - } - } - - // we're supposed to always find something - wxASSERT_MSG(renderer, wxT("Missing default cell renderer")); - - return renderer; -} - -// same as above, except for s/renderer/editor/g -wxGridCellEditor* wxGridCellAttr::GetEditor(wxGrid* grid, int row, int col) const -{ - wxGridCellEditor *editor = NULL; - - if ( m_editor && this != m_defGridAttr ) - { - // use the cells editor if it has one - editor = m_editor; - editor->IncRef(); - } - else // no non default cell editor - { - // get default editor for the data type - if ( grid ) - { - // GetDefaultEditorForCell() will do IncRef() for us - editor = grid->GetDefaultEditorForCell(row, col); - } - - if ( editor == NULL ) - { - if ( (m_defGridAttr != NULL) && (m_defGridAttr != this) ) - { - // if we still don't have one then use the grid default - // (no need for IncRef() here neither) - editor = m_defGridAttr->GetEditor(NULL, 0, 0); - } - else // default grid attr - { - // use m_editor which we had decided not to use initially - editor = m_editor; - if ( editor ) - editor->IncRef(); - } - } - } - - // we're supposed to always find something - wxASSERT_MSG(editor, wxT("Missing default cell editor")); - - return editor; -} - -// ---------------------------------------------------------------------------- -// wxGridCellAttrData -// ---------------------------------------------------------------------------- - -void wxGridCellAttrData::SetAttr(wxGridCellAttr *attr, int row, int col) -{ - // Note: contrary to wxGridRowOrColAttrData::SetAttr, we must not - // touch attribute's reference counting explicitly, since this - // is managed by class wxGridCellWithAttr - int n = FindIndex(row, col); - if ( n == wxNOT_FOUND ) - { - if ( attr ) - { - // add the attribute - m_attrs.Add(new wxGridCellWithAttr(row, col, attr)); - } - //else: nothing to do - } - else // we already have an attribute for this cell - { - if ( attr ) - { - // change the attribute - m_attrs[(size_t)n].ChangeAttr(attr); - } - else - { - // remove this attribute - m_attrs.RemoveAt((size_t)n); - } - } -} - -wxGridCellAttr *wxGridCellAttrData::GetAttr(int row, int col) const -{ - wxGridCellAttr *attr = (wxGridCellAttr *)NULL; - - int n = FindIndex(row, col); - if ( n != wxNOT_FOUND ) - { - attr = m_attrs[(size_t)n].attr; - attr->IncRef(); - } - - return attr; -} - -void wxGridCellAttrData::UpdateAttrRows( size_t pos, int numRows ) -{ - size_t count = m_attrs.GetCount(); - for ( size_t n = 0; n < count; n++ ) - { - wxGridCellCoords& coords = m_attrs[n].coords; - wxCoord row = coords.GetRow(); - if ((size_t)row >= pos) - { - if (numRows > 0) - { - // If rows inserted, include row counter where necessary - coords.SetRow(row + numRows); - } - else if (numRows < 0) - { - // If rows deleted ... - if ((size_t)row >= pos - numRows) - { - // ...either decrement row counter (if row still exists)... - coords.SetRow(row + numRows); - } - else - { - // ...or remove the attribute - m_attrs.RemoveAt(n); - n--; - count--; - } - } - } - } -} - -void wxGridCellAttrData::UpdateAttrCols( size_t pos, int numCols ) -{ - size_t count = m_attrs.GetCount(); - for ( size_t n = 0; n < count; n++ ) - { - wxGridCellCoords& coords = m_attrs[n].coords; - wxCoord col = coords.GetCol(); - if ( (size_t)col >= pos ) - { - if ( numCols > 0 ) - { - // If rows inserted, include row counter where necessary - coords.SetCol(col + numCols); - } - else if (numCols < 0) - { - // If rows deleted ... - if ((size_t)col >= pos - numCols) - { - // ...either decrement row counter (if row still exists)... - coords.SetCol(col + numCols); - } - else - { - // ...or remove the attribute - m_attrs.RemoveAt(n); - n--; - count--; - } - } - } - } -} - -int wxGridCellAttrData::FindIndex(int row, int col) const -{ - size_t count = m_attrs.GetCount(); - for ( size_t n = 0; n < count; n++ ) - { - const wxGridCellCoords& coords = m_attrs[n].coords; - if ( (coords.GetRow() == row) && (coords.GetCol() == col) ) - { - return n; - } - } - - return wxNOT_FOUND; -} - -// ---------------------------------------------------------------------------- -// wxGridRowOrColAttrData -// ---------------------------------------------------------------------------- - -wxGridRowOrColAttrData::~wxGridRowOrColAttrData() -{ - size_t count = m_attrs.Count(); - for ( size_t n = 0; n < count; n++ ) - { - m_attrs[n]->DecRef(); - } -} - -wxGridCellAttr *wxGridRowOrColAttrData::GetAttr(int rowOrCol) const -{ - wxGridCellAttr *attr = (wxGridCellAttr *)NULL; - - int n = m_rowsOrCols.Index(rowOrCol); - if ( n != wxNOT_FOUND ) - { - attr = m_attrs[(size_t)n]; - attr->IncRef(); - } - - return attr; -} - -void wxGridRowOrColAttrData::SetAttr(wxGridCellAttr *attr, int rowOrCol) -{ - int i = m_rowsOrCols.Index(rowOrCol); - if ( i == wxNOT_FOUND ) - { - if ( attr ) - { - // add the attribute - no need to do anything to reference count - // since we take ownership of the attribute. - m_rowsOrCols.Add(rowOrCol); - m_attrs.Add(attr); - } - // nothing to remove - } - else - { - size_t n = (size_t)i; - if ( m_attrs[n] == attr ) - // nothing to do - return; - if ( attr ) - { - // change the attribute, handling reference count manually, - // taking ownership of the new attribute. - m_attrs[n]->DecRef(); - m_attrs[n] = attr; - } - else - { - // remove this attribute, handling reference count manually - m_attrs[n]->DecRef(); - m_rowsOrCols.RemoveAt(n); - m_attrs.RemoveAt(n); - } - } -} - -void wxGridRowOrColAttrData::UpdateAttrRowsOrCols( size_t pos, int numRowsOrCols ) -{ - size_t count = m_attrs.GetCount(); - for ( size_t n = 0; n < count; n++ ) - { - int & rowOrCol = m_rowsOrCols[n]; - if ( (size_t)rowOrCol >= pos ) - { - if ( numRowsOrCols > 0 ) - { - // If rows inserted, include row counter where necessary - rowOrCol += numRowsOrCols; - } - else if ( numRowsOrCols < 0) - { - // If rows deleted, either decrement row counter (if row still exists) - if ((size_t)rowOrCol >= pos - numRowsOrCols) - rowOrCol += numRowsOrCols; - else - { - m_rowsOrCols.RemoveAt(n); - m_attrs[n]->DecRef(); - m_attrs.RemoveAt(n); - n--; - count--; - } - } - } - } -} - -// ---------------------------------------------------------------------------- -// wxGridCellAttrProvider -// ---------------------------------------------------------------------------- - -wxGridCellAttrProvider::wxGridCellAttrProvider() -{ - m_data = (wxGridCellAttrProviderData *)NULL; -} - -wxGridCellAttrProvider::~wxGridCellAttrProvider() -{ - delete m_data; -} - -void wxGridCellAttrProvider::InitData() -{ - m_data = new wxGridCellAttrProviderData; -} - -wxGridCellAttr *wxGridCellAttrProvider::GetAttr(int row, int col, - wxGridCellAttr::wxAttrKind kind ) const -{ - wxGridCellAttr *attr = (wxGridCellAttr *)NULL; - if ( m_data ) - { - switch (kind) - { - case (wxGridCellAttr::Any): - // Get cached merge attributes. - // Currently not used as no cache implemented as not mutable - // attr = m_data->m_mergeAttr.GetAttr(row, col); - if (!attr) - { - // Basically implement old version. - // Also check merge cache, so we don't have to re-merge every time.. - wxGridCellAttr *attrcell = m_data->m_cellAttrs.GetAttr(row, col); - wxGridCellAttr *attrrow = m_data->m_rowAttrs.GetAttr(row); - wxGridCellAttr *attrcol = m_data->m_colAttrs.GetAttr(col); - - if ((attrcell != attrrow) && (attrrow != attrcol) && (attrcell != attrcol)) - { - // Two or more are non NULL - attr = new wxGridCellAttr; - attr->SetKind(wxGridCellAttr::Merged); - - // Order is important.. - if (attrcell) - { - attr->MergeWith(attrcell); - attrcell->DecRef(); - } - if (attrcol) - { - attr->MergeWith(attrcol); - attrcol->DecRef(); - } - if (attrrow) - { - attr->MergeWith(attrrow); - attrrow->DecRef(); - } - - // store merge attr if cache implemented - //attr->IncRef(); - //m_data->m_mergeAttr.SetAttr(attr, row, col); - } - else - { - // one or none is non null return it or null. - if (attrrow) - attr = attrrow; - if (attrcol) - { - if (attr) - attr->DecRef(); - attr = attrcol; - } - if (attrcell) - { - if (attr) - attr->DecRef(); - attr = attrcell; - } - } - } - break; - - case (wxGridCellAttr::Cell): - attr = m_data->m_cellAttrs.GetAttr(row, col); - break; - - case (wxGridCellAttr::Col): - attr = m_data->m_colAttrs.GetAttr(col); - break; - - case (wxGridCellAttr::Row): - attr = m_data->m_rowAttrs.GetAttr(row); - break; - - default: - // unused as yet... - // (wxGridCellAttr::Default): - // (wxGridCellAttr::Merged): - break; - } - } - - return attr; -} - -void wxGridCellAttrProvider::SetAttr(wxGridCellAttr *attr, - int row, int col) -{ - if ( !m_data ) - InitData(); - - m_data->m_cellAttrs.SetAttr(attr, row, col); -} - -void wxGridCellAttrProvider::SetRowAttr(wxGridCellAttr *attr, int row) -{ - if ( !m_data ) - InitData(); - - m_data->m_rowAttrs.SetAttr(attr, row); -} - -void wxGridCellAttrProvider::SetColAttr(wxGridCellAttr *attr, int col) -{ - if ( !m_data ) - InitData(); - - m_data->m_colAttrs.SetAttr(attr, col); -} - -void wxGridCellAttrProvider::UpdateAttrRows( size_t pos, int numRows ) -{ - if ( m_data ) - { - m_data->m_cellAttrs.UpdateAttrRows( pos, numRows ); - - m_data->m_rowAttrs.UpdateAttrRowsOrCols( pos, numRows ); - } -} - -void wxGridCellAttrProvider::UpdateAttrCols( size_t pos, int numCols ) -{ - if ( m_data ) - { - m_data->m_cellAttrs.UpdateAttrCols( pos, numCols ); - - m_data->m_colAttrs.UpdateAttrRowsOrCols( pos, numCols ); - } -} - -// ---------------------------------------------------------------------------- -// wxGridTypeRegistry -// ---------------------------------------------------------------------------- - -wxGridTypeRegistry::~wxGridTypeRegistry() -{ - size_t count = m_typeinfo.Count(); - for ( size_t i = 0; i < count; i++ ) - delete m_typeinfo[i]; -} - -void wxGridTypeRegistry::RegisterDataType(const wxString& typeName, - wxGridCellRenderer* renderer, - wxGridCellEditor* editor) -{ - wxGridDataTypeInfo* info = new wxGridDataTypeInfo(typeName, renderer, editor); - - // is it already registered? - int loc = FindRegisteredDataType(typeName); - if ( loc != wxNOT_FOUND ) - { - delete m_typeinfo[loc]; - m_typeinfo[loc] = info; - } - else - { - m_typeinfo.Add(info); - } -} - -int wxGridTypeRegistry::FindRegisteredDataType(const wxString& typeName) -{ - size_t count = m_typeinfo.GetCount(); - for ( size_t i = 0; i < count; i++ ) - { - if ( typeName == m_typeinfo[i]->m_typeName ) - { - return i; - } - } - - return wxNOT_FOUND; -} - -int wxGridTypeRegistry::FindDataType(const wxString& typeName) -{ - int index = FindRegisteredDataType(typeName); - if ( index == wxNOT_FOUND ) - { - // check whether this is one of the standard ones, in which case - // register it "on the fly" -#if wxUSE_TEXTCTRL - if ( typeName == wxGRID_VALUE_STRING ) - { - RegisterDataType(wxGRID_VALUE_STRING, - new wxGridCellStringRenderer, - new wxGridCellTextEditor); - } - else -#endif // wxUSE_TEXTCTRL -#if wxUSE_CHECKBOX - if ( typeName == wxGRID_VALUE_BOOL ) - { - RegisterDataType(wxGRID_VALUE_BOOL, - new wxGridCellBoolRenderer, - new wxGridCellBoolEditor); - } - else -#endif // wxUSE_CHECKBOX -#if wxUSE_TEXTCTRL - if ( typeName == wxGRID_VALUE_NUMBER ) - { - RegisterDataType(wxGRID_VALUE_NUMBER, - new wxGridCellNumberRenderer, - new wxGridCellNumberEditor); - } - else if ( typeName == wxGRID_VALUE_FLOAT ) - { - RegisterDataType(wxGRID_VALUE_FLOAT, - new wxGridCellFloatRenderer, - new wxGridCellFloatEditor); - } - else -#endif // wxUSE_TEXTCTRL -#if wxUSE_COMBOBOX - if ( typeName == wxGRID_VALUE_CHOICE ) - { - RegisterDataType(wxGRID_VALUE_CHOICE, - new wxGridCellStringRenderer, - new wxGridCellChoiceEditor); - } - else -#endif // wxUSE_COMBOBOX - { - return wxNOT_FOUND; - } - - // we get here only if just added the entry for this type, so return - // the last index - index = m_typeinfo.GetCount() - 1; - } - - return index; -} - -int wxGridTypeRegistry::FindOrCloneDataType(const wxString& typeName) -{ - int index = FindDataType(typeName); - if ( index == wxNOT_FOUND ) - { - // the first part of the typename is the "real" type, anything after ':' - // are the parameters for the renderer - index = FindDataType(typeName.BeforeFirst(_T(':'))); - if ( index == wxNOT_FOUND ) - { - return wxNOT_FOUND; - } - - wxGridCellRenderer *renderer = GetRenderer(index); - wxGridCellRenderer *rendererOld = renderer; - renderer = renderer->Clone(); - rendererOld->DecRef(); - - wxGridCellEditor *editor = GetEditor(index); - wxGridCellEditor *editorOld = editor; - editor = editor->Clone(); - editorOld->DecRef(); - - // do it even if there are no parameters to reset them to defaults - wxString params = typeName.AfterFirst(_T(':')); - renderer->SetParameters(params); - editor->SetParameters(params); - - // register the new typename - RegisterDataType(typeName, renderer, editor); - - // we just registered it, it's the last one - index = m_typeinfo.GetCount() - 1; - } - - return index; -} - -wxGridCellRenderer* wxGridTypeRegistry::GetRenderer(int index) -{ - wxGridCellRenderer* renderer = m_typeinfo[index]->m_renderer; - if (renderer) - renderer->IncRef(); - - return renderer; -} - -wxGridCellEditor* wxGridTypeRegistry::GetEditor(int index) -{ - wxGridCellEditor* editor = m_typeinfo[index]->m_editor; - if (editor) - editor->IncRef(); - - return editor; -} - -// ---------------------------------------------------------------------------- -// wxGridTableBase -// ---------------------------------------------------------------------------- - -IMPLEMENT_ABSTRACT_CLASS( wxGridTableBase, wxObject ) - -wxGridTableBase::wxGridTableBase() -{ - m_view = (wxGrid *) NULL; - m_attrProvider = (wxGridCellAttrProvider *) NULL; -} - -wxGridTableBase::~wxGridTableBase() -{ - delete m_attrProvider; -} - -void wxGridTableBase::SetAttrProvider(wxGridCellAttrProvider *attrProvider) -{ - delete m_attrProvider; - m_attrProvider = attrProvider; -} - -bool wxGridTableBase::CanHaveAttributes() -{ - if ( ! GetAttrProvider() ) - { - // use the default attr provider by default - SetAttrProvider(new wxGridCellAttrProvider); - } - - return true; -} - -wxGridCellAttr *wxGridTableBase::GetAttr(int row, int col, wxGridCellAttr::wxAttrKind kind) -{ - if ( m_attrProvider ) - return m_attrProvider->GetAttr(row, col, kind); - else - return (wxGridCellAttr *)NULL; -} - -void wxGridTableBase::SetAttr(wxGridCellAttr* attr, int row, int col) -{ - if ( m_attrProvider ) - { - if ( attr ) - attr->SetKind(wxGridCellAttr::Cell); - m_attrProvider->SetAttr(attr, row, col); - } - else - { - // as we take ownership of the pointer and don't store it, we must - // free it now - wxSafeDecRef(attr); - } -} - -void wxGridTableBase::SetRowAttr(wxGridCellAttr *attr, int row) -{ - if ( m_attrProvider ) - { - attr->SetKind(wxGridCellAttr::Row); - m_attrProvider->SetRowAttr(attr, row); - } - else - { - // as we take ownership of the pointer and don't store it, we must - // free it now - wxSafeDecRef(attr); - } -} - -void wxGridTableBase::SetColAttr(wxGridCellAttr *attr, int col) -{ - if ( m_attrProvider ) - { - attr->SetKind(wxGridCellAttr::Col); - m_attrProvider->SetColAttr(attr, col); - } - else - { - // as we take ownership of the pointer and don't store it, we must - // free it now - wxSafeDecRef(attr); - } -} - -bool wxGridTableBase::InsertRows( size_t WXUNUSED(pos), - size_t WXUNUSED(numRows) ) -{ - wxFAIL_MSG( wxT("Called grid table class function InsertRows\nbut your derived table class does not override this function") ); - - return false; -} - -bool wxGridTableBase::AppendRows( size_t WXUNUSED(numRows) ) -{ - wxFAIL_MSG( wxT("Called grid table class function AppendRows\nbut your derived table class does not override this function")); - - return false; -} - -bool wxGridTableBase::DeleteRows( size_t WXUNUSED(pos), - size_t WXUNUSED(numRows) ) -{ - wxFAIL_MSG( wxT("Called grid table class function DeleteRows\nbut your derived table class does not override this function")); - - return false; -} - -bool wxGridTableBase::InsertCols( size_t WXUNUSED(pos), - size_t WXUNUSED(numCols) ) -{ - wxFAIL_MSG( wxT("Called grid table class function InsertCols\nbut your derived table class does not override this function")); - - return false; -} - -bool wxGridTableBase::AppendCols( size_t WXUNUSED(numCols) ) -{ - wxFAIL_MSG(wxT("Called grid table class function AppendCols\nbut your derived table class does not override this function")); - - return false; -} - -bool wxGridTableBase::DeleteCols( size_t WXUNUSED(pos), - size_t WXUNUSED(numCols) ) -{ - wxFAIL_MSG( wxT("Called grid table class function DeleteCols\nbut your derived table class does not override this function")); - - return false; -} - -wxString wxGridTableBase::GetRowLabelValue( int row ) -{ - wxString s; - - // RD: Starting the rows at zero confuses users, - // no matter how much it makes sense to us geeks. - s << row + 1; - - return s; -} - -wxString wxGridTableBase::GetColLabelValue( int col ) -{ - // default col labels are: - // cols 0 to 25 : A-Z - // cols 26 to 675 : AA-ZZ - // etc. - - wxString s; - unsigned int i, n; - for ( n = 1; ; n++ ) - { - s += (wxChar) (_T('A') + (wxChar)(col % 26)); - col = col / 26 - 1; - if ( col < 0 ) - break; - } - - // reverse the string... - wxString s2; - for ( i = 0; i < n; i++ ) - { - s2 += s[n - i - 1]; - } - - return s2; -} - -wxString wxGridTableBase::GetTypeName( int WXUNUSED(row), int WXUNUSED(col) ) -{ - return wxGRID_VALUE_STRING; -} - -bool wxGridTableBase::CanGetValueAs( int WXUNUSED(row), int WXUNUSED(col), - const wxString& typeName ) -{ - return typeName == wxGRID_VALUE_STRING; -} - -bool wxGridTableBase::CanSetValueAs( int row, int col, const wxString& typeName ) -{ - return CanGetValueAs(row, col, typeName); -} - -long wxGridTableBase::GetValueAsLong( int WXUNUSED(row), int WXUNUSED(col) ) -{ - return 0; -} - -double wxGridTableBase::GetValueAsDouble( int WXUNUSED(row), int WXUNUSED(col) ) -{ - return 0.0; -} - -bool wxGridTableBase::GetValueAsBool( int WXUNUSED(row), int WXUNUSED(col) ) -{ - return false; -} - -void wxGridTableBase::SetValueAsLong( int WXUNUSED(row), int WXUNUSED(col), - long WXUNUSED(value) ) -{ -} - -void wxGridTableBase::SetValueAsDouble( int WXUNUSED(row), int WXUNUSED(col), - double WXUNUSED(value) ) -{ -} - -void wxGridTableBase::SetValueAsBool( int WXUNUSED(row), int WXUNUSED(col), - bool WXUNUSED(value) ) -{ -} - -void* wxGridTableBase::GetValueAsCustom( int WXUNUSED(row), int WXUNUSED(col), - const wxString& WXUNUSED(typeName) ) -{ - return NULL; -} - -void wxGridTableBase::SetValueAsCustom( int WXUNUSED(row), int WXUNUSED(col), - const wxString& WXUNUSED(typeName), - void* WXUNUSED(value) ) -{ -} - -////////////////////////////////////////////////////////////////////// -// -// Message class for the grid table to send requests and notifications -// to the grid view -// - -wxGridTableMessage::wxGridTableMessage() -{ - m_table = (wxGridTableBase *) NULL; - m_id = -1; - m_comInt1 = -1; - m_comInt2 = -1; -} - -wxGridTableMessage::wxGridTableMessage( wxGridTableBase *table, int id, - int commandInt1, int commandInt2 ) -{ - m_table = table; - m_id = id; - m_comInt1 = commandInt1; - m_comInt2 = commandInt2; -} - -////////////////////////////////////////////////////////////////////// -// -// A basic grid table for string data. An object of this class will -// created by wxGrid if you don't specify an alternative table class. -// - -WX_DEFINE_OBJARRAY(wxGridStringArray) - -IMPLEMENT_DYNAMIC_CLASS( wxGridStringTable, wxGridTableBase ) - -wxGridStringTable::wxGridStringTable() - : wxGridTableBase() -{ -} - -wxGridStringTable::wxGridStringTable( int numRows, int numCols ) - : wxGridTableBase() -{ - m_data.Alloc( numRows ); - - wxArrayString sa; - sa.Alloc( numCols ); - sa.Add( wxEmptyString, numCols ); - - m_data.Add( sa, numRows ); -} - -wxGridStringTable::~wxGridStringTable() -{ -} - -int wxGridStringTable::GetNumberRows() -{ - return m_data.GetCount(); -} - -int wxGridStringTable::GetNumberCols() -{ - if ( m_data.GetCount() > 0 ) - return m_data[0].GetCount(); - else - return 0; -} - -wxString wxGridStringTable::GetValue( int row, int col ) -{ - wxCHECK_MSG( (row < GetNumberRows()) && (col < GetNumberCols()), - wxEmptyString, - _T("invalid row or column index in wxGridStringTable") ); - - return m_data[row][col]; -} - -void wxGridStringTable::SetValue( int row, int col, const wxString& value ) -{ - wxCHECK_RET( (row < GetNumberRows()) && (col < GetNumberCols()), - _T("invalid row or column index in wxGridStringTable") ); - - m_data[row][col] = value; -} - -bool wxGridStringTable::IsEmptyCell( int row, int col ) -{ - wxCHECK_MSG( (row < GetNumberRows()) && (col < GetNumberCols()), - true, - _T("invalid row or column index in wxGridStringTable") ); - - return (m_data[row][col] == wxEmptyString); -} - -void wxGridStringTable::Clear() -{ - int row, col; - int numRows, numCols; - - numRows = m_data.GetCount(); - if ( numRows > 0 ) - { - numCols = m_data[0].GetCount(); - - for ( row = 0; row < numRows; row++ ) - { - for ( col = 0; col < numCols; col++ ) - { - m_data[row][col] = wxEmptyString; - } - } - } -} - -bool wxGridStringTable::InsertRows( size_t pos, size_t numRows ) -{ - size_t curNumRows = m_data.GetCount(); - size_t curNumCols = ( curNumRows > 0 ? m_data[0].GetCount() : - ( GetView() ? GetView()->GetNumberCols() : 0 ) ); - - if ( pos >= curNumRows ) - { - return AppendRows( numRows ); - } - - wxArrayString sa; - sa.Alloc( curNumCols ); - sa.Add( wxEmptyString, curNumCols ); - m_data.Insert( sa, pos, numRows ); - - if ( GetView() ) - { - wxGridTableMessage msg( this, - wxGRIDTABLE_NOTIFY_ROWS_INSERTED, - pos, - numRows ); - - GetView()->ProcessTableMessage( msg ); - } - - return true; -} - -bool wxGridStringTable::AppendRows( size_t numRows ) -{ - size_t curNumRows = m_data.GetCount(); - size_t curNumCols = ( curNumRows > 0 - ? m_data[0].GetCount() - : ( GetView() ? GetView()->GetNumberCols() : 0 ) ); - - wxArrayString sa; - if ( curNumCols > 0 ) - { - sa.Alloc( curNumCols ); - sa.Add( wxEmptyString, curNumCols ); - } - - m_data.Add( sa, numRows ); - - if ( GetView() ) - { - wxGridTableMessage msg( this, - wxGRIDTABLE_NOTIFY_ROWS_APPENDED, - numRows ); - - GetView()->ProcessTableMessage( msg ); - } - - return true; -} - -bool wxGridStringTable::DeleteRows( size_t pos, size_t numRows ) -{ - size_t curNumRows = m_data.GetCount(); - - if ( pos >= curNumRows ) - { - wxFAIL_MSG( wxString::Format - ( - wxT("Called wxGridStringTable::DeleteRows(pos=%lu, N=%lu)\nPos value is invalid for present table with %lu rows"), - (unsigned long)pos, - (unsigned long)numRows, - (unsigned long)curNumRows - ) ); - - return false; - } - - if ( numRows > curNumRows - pos ) - { - numRows = curNumRows - pos; - } - - if ( numRows >= curNumRows ) - { - m_data.Clear(); - } - else - { - m_data.RemoveAt( pos, numRows ); - } - - if ( GetView() ) - { - wxGridTableMessage msg( this, - wxGRIDTABLE_NOTIFY_ROWS_DELETED, - pos, - numRows ); - - GetView()->ProcessTableMessage( msg ); - } - - return true; -} - -bool wxGridStringTable::InsertCols( size_t pos, size_t numCols ) -{ - size_t row, col; - - size_t curNumRows = m_data.GetCount(); - size_t curNumCols = ( curNumRows > 0 - ? m_data[0].GetCount() - : ( GetView() ? GetView()->GetNumberCols() : 0 ) ); - - if ( pos >= curNumCols ) - { - return AppendCols( numCols ); - } - - if ( !m_colLabels.IsEmpty() ) - { - m_colLabels.Insert( wxEmptyString, pos, numCols ); - - size_t i; - for ( i = pos; i < pos + numCols; i++ ) - m_colLabels[i] = wxGridTableBase::GetColLabelValue( i ); - } - - for ( row = 0; row < curNumRows; row++ ) - { - for ( col = pos; col < pos + numCols; col++ ) - { - m_data[row].Insert( wxEmptyString, col ); - } - } - - if ( GetView() ) - { - wxGridTableMessage msg( this, - wxGRIDTABLE_NOTIFY_COLS_INSERTED, - pos, - numCols ); - - GetView()->ProcessTableMessage( msg ); - } - - return true; -} - -bool wxGridStringTable::AppendCols( size_t numCols ) -{ - size_t row; - - size_t curNumRows = m_data.GetCount(); - -#if 0 - if ( !curNumRows ) - { - // TODO: something better than this ? - // - wxFAIL_MSG( wxT("Unable to append cols to a grid table with no rows.\nCall AppendRows() first") ); - return false; - } -#endif - - for ( row = 0; row < curNumRows; row++ ) - { - m_data[row].Add( wxEmptyString, numCols ); - } - - if ( GetView() ) - { - wxGridTableMessage msg( this, - wxGRIDTABLE_NOTIFY_COLS_APPENDED, - numCols ); - - GetView()->ProcessTableMessage( msg ); - } - - return true; -} - -bool wxGridStringTable::DeleteCols( size_t pos, size_t numCols ) -{ - size_t row; - - size_t curNumRows = m_data.GetCount(); - size_t curNumCols = ( curNumRows > 0 ? m_data[0].GetCount() : - ( GetView() ? GetView()->GetNumberCols() : 0 ) ); - - if ( pos >= curNumCols ) - { - wxFAIL_MSG( wxString::Format - ( - wxT("Called wxGridStringTable::DeleteCols(pos=%lu, N=%lu)\nPos value is invalid for present table with %lu cols"), - (unsigned long)pos, - (unsigned long)numCols, - (unsigned long)curNumCols - ) ); - return false; - } - - int colID; - if ( GetView() ) - colID = GetView()->GetColAt( pos ); - else - colID = pos; - - if ( numCols > curNumCols - colID ) - { - numCols = curNumCols - colID; - } - - if ( !m_colLabels.IsEmpty() ) - { - // m_colLabels stores just as many elements as it needs, e.g. if only - // the label of the first column had been set it would have only one - // element and not numCols, so account for it - int nToRm = m_colLabels.size() - colID; - if ( nToRm > 0 ) - m_colLabels.RemoveAt( colID, nToRm ); - } - - for ( row = 0; row < curNumRows; row++ ) - { - if ( numCols >= curNumCols ) - { - m_data[row].Clear(); - } - else - { - m_data[row].RemoveAt( colID, numCols ); - } - } - - if ( GetView() ) - { - wxGridTableMessage msg( this, - wxGRIDTABLE_NOTIFY_COLS_DELETED, - pos, - numCols ); - - GetView()->ProcessTableMessage( msg ); - } - - return true; -} - -wxString wxGridStringTable::GetRowLabelValue( int row ) -{ - if ( row > (int)(m_rowLabels.GetCount()) - 1 ) - { - // using default label - // - return wxGridTableBase::GetRowLabelValue( row ); - } - else - { - return m_rowLabels[row]; - } -} - -wxString wxGridStringTable::GetColLabelValue( int col ) -{ - if ( col > (int)(m_colLabels.GetCount()) - 1 ) - { - // using default label - // - return wxGridTableBase::GetColLabelValue( col ); - } - else - { - return m_colLabels[col]; - } -} - -void wxGridStringTable::SetRowLabelValue( int row, const wxString& value ) -{ - if ( row > (int)(m_rowLabels.GetCount()) - 1 ) - { - int n = m_rowLabels.GetCount(); - int i; - - for ( i = n; i <= row; i++ ) - { - m_rowLabels.Add( wxGridTableBase::GetRowLabelValue(i) ); - } - } - - m_rowLabels[row] = value; -} - -void wxGridStringTable::SetColLabelValue( int col, const wxString& value ) -{ - if ( col > (int)(m_colLabels.GetCount()) - 1 ) - { - int n = m_colLabels.GetCount(); - int i; - - for ( i = n; i <= col; i++ ) - { - m_colLabels.Add( wxGridTableBase::GetColLabelValue(i) ); - } - } - - m_colLabels[col] = value; -} - - -////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////// - -IMPLEMENT_DYNAMIC_CLASS( wxGridRowLabelWindow, wxWindow ) - -BEGIN_EVENT_TABLE( wxGridRowLabelWindow, wxWindow ) - EVT_PAINT( wxGridRowLabelWindow::OnPaint ) - EVT_MOUSEWHEEL( wxGridRowLabelWindow::OnMouseWheel ) - EVT_MOUSE_EVENTS( wxGridRowLabelWindow::OnMouseEvent ) - EVT_KEY_DOWN( wxGridRowLabelWindow::OnKeyDown ) - EVT_KEY_UP( wxGridRowLabelWindow::OnKeyUp ) - EVT_CHAR( wxGridRowLabelWindow::OnChar ) -END_EVENT_TABLE() - -wxGridRowLabelWindow::wxGridRowLabelWindow( wxGrid *parent, - wxWindowID id, - const wxPoint &pos, const wxSize &size ) - : wxWindow( parent, id, pos, size, wxWANTS_CHARS | wxBORDER_NONE | wxFULL_REPAINT_ON_RESIZE ) -{ - m_owner = parent; -} - -void wxGridRowLabelWindow::OnPaint( wxPaintEvent& WXUNUSED(event) ) -{ - wxPaintDC dc(this); - - // NO - don't do this because it will set both the x and y origin - // coords to match the parent scrolled window and we just want to - // set the y coord - MB - // - // m_owner->PrepareDC( dc ); - - int x, y; - m_owner->CalcUnscrolledPosition( 0, 0, &x, &y ); - wxPoint pt = dc.GetDeviceOrigin(); - dc.SetDeviceOrigin( pt.x, pt.y-y ); - - wxArrayInt rows = m_owner->CalcRowLabelsExposed( GetUpdateRegion() ); - m_owner->DrawRowLabels( dc, rows ); -} - -void wxGridRowLabelWindow::OnMouseEvent( wxMouseEvent& event ) -{ - m_owner->ProcessRowLabelMouseEvent( event ); -} - -void wxGridRowLabelWindow::OnMouseWheel( wxMouseEvent& event ) -{ - m_owner->GetEventHandler()->ProcessEvent( event ); -} - -// This seems to be required for wxMotif otherwise the mouse -// cursor must be in the cell edit control to get key events -// -void wxGridRowLabelWindow::OnKeyDown( wxKeyEvent& event ) -{ - if ( !m_owner->GetEventHandler()->ProcessEvent( event ) ) - event.Skip(); -} - -void wxGridRowLabelWindow::OnKeyUp( wxKeyEvent& event ) -{ - if ( !m_owner->GetEventHandler()->ProcessEvent( event ) ) - event.Skip(); -} - -void wxGridRowLabelWindow::OnChar( wxKeyEvent& event ) -{ - if ( !m_owner->GetEventHandler()->ProcessEvent( event ) ) - event.Skip(); -} - -////////////////////////////////////////////////////////////////////// - -IMPLEMENT_DYNAMIC_CLASS( wxGridColLabelWindow, wxWindow ) - -BEGIN_EVENT_TABLE( wxGridColLabelWindow, wxWindow ) - EVT_PAINT( wxGridColLabelWindow::OnPaint ) - EVT_MOUSEWHEEL( wxGridColLabelWindow::OnMouseWheel ) - EVT_MOUSE_EVENTS( wxGridColLabelWindow::OnMouseEvent ) - EVT_KEY_DOWN( wxGridColLabelWindow::OnKeyDown ) - EVT_KEY_UP( wxGridColLabelWindow::OnKeyUp ) - EVT_CHAR( wxGridColLabelWindow::OnChar ) -END_EVENT_TABLE() - -wxGridColLabelWindow::wxGridColLabelWindow( wxGrid *parent, - wxWindowID id, - const wxPoint &pos, const wxSize &size ) - : wxWindow( parent, id, pos, size, wxWANTS_CHARS | wxBORDER_NONE | wxFULL_REPAINT_ON_RESIZE ) -{ - m_owner = parent; -} - -void wxGridColLabelWindow::OnPaint( wxPaintEvent& WXUNUSED(event) ) -{ - wxPaintDC dc(this); - - // NO - don't do this because it will set both the x and y origin - // coords to match the parent scrolled window and we just want to - // set the x coord - MB - // - // m_owner->PrepareDC( dc ); - - int x, y; - m_owner->CalcUnscrolledPosition( 0, 0, &x, &y ); - wxPoint pt = dc.GetDeviceOrigin(); - if (GetLayoutDirection() == wxLayout_RightToLeft) - dc.SetDeviceOrigin( pt.x+x, pt.y ); - else - dc.SetDeviceOrigin( pt.x-x, pt.y ); - - wxArrayInt cols = m_owner->CalcColLabelsExposed( GetUpdateRegion() ); - m_owner->DrawColLabels( dc, cols ); -} - -void wxGridColLabelWindow::OnMouseEvent( wxMouseEvent& event ) -{ - m_owner->ProcessColLabelMouseEvent( event ); -} - -void wxGridColLabelWindow::OnMouseWheel( wxMouseEvent& event ) -{ - m_owner->GetEventHandler()->ProcessEvent( event ); -} - -// This seems to be required for wxMotif otherwise the mouse -// cursor must be in the cell edit control to get key events -// -void wxGridColLabelWindow::OnKeyDown( wxKeyEvent& event ) -{ - if ( !m_owner->GetEventHandler()->ProcessEvent( event ) ) - event.Skip(); -} - -void wxGridColLabelWindow::OnKeyUp( wxKeyEvent& event ) -{ - if ( !m_owner->GetEventHandler()->ProcessEvent( event ) ) - event.Skip(); -} - -void wxGridColLabelWindow::OnChar( wxKeyEvent& event ) -{ - if ( !m_owner->GetEventHandler()->ProcessEvent( event ) ) - event.Skip(); -} - -////////////////////////////////////////////////////////////////////// - -IMPLEMENT_DYNAMIC_CLASS( wxGridCornerLabelWindow, wxWindow ) - -BEGIN_EVENT_TABLE( wxGridCornerLabelWindow, wxWindow ) - EVT_MOUSEWHEEL( wxGridCornerLabelWindow::OnMouseWheel ) - EVT_MOUSE_EVENTS( wxGridCornerLabelWindow::OnMouseEvent ) - EVT_PAINT( wxGridCornerLabelWindow::OnPaint ) - EVT_KEY_DOWN( wxGridCornerLabelWindow::OnKeyDown ) - EVT_KEY_UP( wxGridCornerLabelWindow::OnKeyUp ) - EVT_CHAR( wxGridCornerLabelWindow::OnChar ) -END_EVENT_TABLE() - -wxGridCornerLabelWindow::wxGridCornerLabelWindow( wxGrid *parent, - wxWindowID id, - const wxPoint &pos, const wxSize &size ) - : wxWindow( parent, id, pos, size, wxWANTS_CHARS | wxBORDER_NONE | wxFULL_REPAINT_ON_RESIZE ) -{ - m_owner = parent; -} - -void wxGridCornerLabelWindow::OnPaint( wxPaintEvent& WXUNUSED(event) ) -{ - wxPaintDC dc(this); - - int client_height = 0; - int client_width = 0; - GetClientSize( &client_width, &client_height ); - - // VZ: any reason for this ifdef? (FIXME) -#if 0 -def __WXGTK__ - wxRect rect; - rect.SetX( 1 ); - rect.SetY( 1 ); - rect.SetWidth( client_width - 2 ); - rect.SetHeight( client_height - 2 ); - - wxRendererNative::Get().DrawHeaderButton( this, dc, rect, 0 ); -#else // !__WXGTK__ - dc.SetPen( wxPen(wxSystemSettings::GetColour(wxSYS_COLOUR_3DSHADOW), 1, wxSOLID) ); - dc.DrawLine( client_width - 1, client_height - 1, client_width - 1, 0 ); - dc.DrawLine( client_width - 1, client_height - 1, 0, client_height - 1 ); - dc.DrawLine( 0, 0, client_width, 0 ); - dc.DrawLine( 0, 0, 0, client_height ); - - dc.SetPen( *wxWHITE_PEN ); - dc.DrawLine( 1, 1, client_width - 1, 1 ); - dc.DrawLine( 1, 1, 1, client_height - 1 ); -#endif -} - -void wxGridCornerLabelWindow::OnMouseEvent( wxMouseEvent& event ) -{ - m_owner->ProcessCornerLabelMouseEvent( event ); -} - -void wxGridCornerLabelWindow::OnMouseWheel( wxMouseEvent& event ) -{ - m_owner->GetEventHandler()->ProcessEvent(event); -} - -// This seems to be required for wxMotif otherwise the mouse -// cursor must be in the cell edit control to get key events -// -void wxGridCornerLabelWindow::OnKeyDown( wxKeyEvent& event ) -{ - if ( !m_owner->GetEventHandler()->ProcessEvent( event ) ) - event.Skip(); -} - -void wxGridCornerLabelWindow::OnKeyUp( wxKeyEvent& event ) -{ - if ( !m_owner->GetEventHandler()->ProcessEvent( event ) ) - event.Skip(); -} - -void wxGridCornerLabelWindow::OnChar( wxKeyEvent& event ) -{ - if ( !m_owner->GetEventHandler()->ProcessEvent( event ) ) - event.Skip(); -} - -////////////////////////////////////////////////////////////////////// - -IMPLEMENT_DYNAMIC_CLASS( wxGridWindow, wxWindow ) - -BEGIN_EVENT_TABLE( wxGridWindow, wxWindow ) - EVT_PAINT( wxGridWindow::OnPaint ) - EVT_MOUSEWHEEL( wxGridWindow::OnMouseWheel ) - EVT_MOUSE_EVENTS( wxGridWindow::OnMouseEvent ) - EVT_KEY_DOWN( wxGridWindow::OnKeyDown ) - EVT_KEY_UP( wxGridWindow::OnKeyUp ) - EVT_CHAR( wxGridWindow::OnChar ) - EVT_SET_FOCUS( wxGridWindow::OnFocus ) - EVT_KILL_FOCUS( wxGridWindow::OnFocus ) - EVT_ERASE_BACKGROUND( wxGridWindow::OnEraseBackground ) -END_EVENT_TABLE() - -wxGridWindow::wxGridWindow( wxGrid *parent, - wxGridRowLabelWindow *rowLblWin, - wxGridColLabelWindow *colLblWin, - wxWindowID id, - const wxPoint &pos, - const wxSize &size ) - : wxWindow( - parent, id, pos, size, - wxWANTS_CHARS | wxBORDER_NONE | wxCLIP_CHILDREN | wxFULL_REPAINT_ON_RESIZE, - wxT("grid window") ) -{ - m_owner = parent; - m_rowLabelWin = rowLblWin; - m_colLabelWin = colLblWin; -} - -void wxGridWindow::OnPaint( wxPaintEvent &WXUNUSED(event) ) -{ - wxPaintDC dc( this ); - m_owner->PrepareDC( dc ); - wxRegion reg = GetUpdateRegion(); - wxGridCellCoordsArray dirtyCells = m_owner->CalcCellsExposed( reg ); - m_owner->DrawGridCellArea( dc, dirtyCells ); - -#if WXGRID_DRAW_LINES - m_owner->DrawAllGridLines( dc, reg ); -#endif - - m_owner->DrawGridSpace( dc ); - m_owner->DrawHighlight( dc, dirtyCells ); -} - -void wxGridWindow::ScrollWindow( int dx, int dy, const wxRect *rect ) -{ - wxWindow::ScrollWindow( dx, dy, rect ); - m_rowLabelWin->ScrollWindow( 0, dy, rect ); - m_colLabelWin->ScrollWindow( dx, 0, rect ); -} - -void wxGridWindow::OnMouseEvent( wxMouseEvent& event ) -{ - if (event.ButtonDown(wxMOUSE_BTN_LEFT) && FindFocus() != this) - SetFocus(); - - m_owner->ProcessGridCellMouseEvent( event ); -} - -void wxGridWindow::OnMouseWheel( wxMouseEvent& event ) -{ - m_owner->GetEventHandler()->ProcessEvent( event ); -} - -// This seems to be required for wxMotif/wxGTK otherwise the mouse -// cursor must be in the cell edit control to get key events -// -void wxGridWindow::OnKeyDown( wxKeyEvent& event ) -{ - if ( !m_owner->GetEventHandler()->ProcessEvent( event ) ) - event.Skip(); -} - -void wxGridWindow::OnKeyUp( wxKeyEvent& event ) -{ - if ( !m_owner->GetEventHandler()->ProcessEvent( event ) ) - event.Skip(); -} - -void wxGridWindow::OnChar( wxKeyEvent& event ) -{ - if ( !m_owner->GetEventHandler()->ProcessEvent( event ) ) - event.Skip(); -} - -void wxGridWindow::OnEraseBackground( wxEraseEvent& WXUNUSED(event) ) -{ -} - -void wxGridWindow::OnFocus(wxFocusEvent& event) -{ - // current cell cursor {dis,re}appears on focus change: - wxRect cursor = m_owner->CellToRect(m_owner->GetGridCursorRow(), - m_owner->GetGridCursorCol()); - Refresh(true, &cursor); - - // and if we have any selection, it has to be repainted, because it - // uses different colour when the grid is not focused: - if ( m_owner->IsSelection() ) - { - Refresh(); - } - else - { - // NB: Note that this code is in "else" branch only because the other - // branch refreshes everything and so there's no point in calling - // Refresh() again, *not* because it should only be done if - // !IsSelection(). If the above code is ever optimized to refresh - // only selected area, this needs to be moved out of the "else" - // branch so that it's always executed. - - // current cell cursor {dis,re}appears on focus change: - const wxGridCellCoords cursorCoords(m_owner->GetGridCursorRow(), - m_owner->GetGridCursorCol()); - const wxRect cursor = - m_owner->BlockToDeviceRect(cursorCoords, cursorCoords); - Refresh(true, &cursor); - } - - if ( !m_owner->GetEventHandler()->ProcessEvent( event ) ) - event.Skip(); -} - -////////////////////////////////////////////////////////////////////// - -// Internal Helper function for computing row or column from some -// (unscrolled) coordinate value, using either -// m_defaultRowHeight/m_defaultColWidth or binary search on array -// of m_rowBottoms/m_ColRights to speed up the search! - -// Internal helper macros for simpler use of that function - -static int CoordToRowOrCol(int coord, int defaultDist, int minDist, - const wxArrayInt& BorderArray, int nMax, - bool clipToMinMax); - -#define internalXToCol(x) XToCol(x, true) -#define internalYToRow(y) CoordToRowOrCol(y, m_defaultRowHeight, \ - m_minAcceptableRowHeight, \ - m_rowBottoms, m_numRows, true) - -///////////////////////////////////////////////////////////////////// - -#if wxUSE_EXTENDED_RTTI -WX_DEFINE_FLAGS( wxGridStyle ) - -wxBEGIN_FLAGS( wxGridStyle ) - // new style border flags, we put them first to - // use them for streaming out - wxFLAGS_MEMBER(wxBORDER_SIMPLE) - wxFLAGS_MEMBER(wxBORDER_SUNKEN) - wxFLAGS_MEMBER(wxBORDER_DOUBLE) - wxFLAGS_MEMBER(wxBORDER_RAISED) - wxFLAGS_MEMBER(wxBORDER_STATIC) - wxFLAGS_MEMBER(wxBORDER_NONE) - - // old style border flags - wxFLAGS_MEMBER(wxSIMPLE_BORDER) - wxFLAGS_MEMBER(wxSUNKEN_BORDER) - wxFLAGS_MEMBER(wxDOUBLE_BORDER) - wxFLAGS_MEMBER(wxRAISED_BORDER) - wxFLAGS_MEMBER(wxSTATIC_BORDER) - wxFLAGS_MEMBER(wxBORDER) - - // standard window styles - wxFLAGS_MEMBER(wxTAB_TRAVERSAL) - wxFLAGS_MEMBER(wxCLIP_CHILDREN) - wxFLAGS_MEMBER(wxTRANSPARENT_WINDOW) - wxFLAGS_MEMBER(wxWANTS_CHARS) - wxFLAGS_MEMBER(wxFULL_REPAINT_ON_RESIZE) - wxFLAGS_MEMBER(wxALWAYS_SHOW_SB) - wxFLAGS_MEMBER(wxVSCROLL) - wxFLAGS_MEMBER(wxHSCROLL) - -wxEND_FLAGS( wxGridStyle ) - -IMPLEMENT_DYNAMIC_CLASS_XTI(wxGrid, wxScrolledWindow,"wx/grid.h") - -wxBEGIN_PROPERTIES_TABLE(wxGrid) - wxHIDE_PROPERTY( Children ) - wxPROPERTY_FLAGS( WindowStyle , wxGridStyle , long , SetWindowStyleFlag , GetWindowStyleFlag , EMPTY_MACROVALUE, 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // style -wxEND_PROPERTIES_TABLE() - -wxBEGIN_HANDLERS_TABLE(wxGrid) -wxEND_HANDLERS_TABLE() - -wxCONSTRUCTOR_5( wxGrid , wxWindow* , Parent , wxWindowID , Id , wxPoint , Position , wxSize , Size , long , WindowStyle ) - -/* - TODO : Expose more information of a list's layout, etc. via appropriate objects (e.g., NotebookPageInfo) -*/ -#else -IMPLEMENT_DYNAMIC_CLASS( wxGrid, wxScrolledWindow ) -#endif - -BEGIN_EVENT_TABLE( wxGrid, wxScrolledWindow ) - EVT_PAINT( wxGrid::OnPaint ) - EVT_SIZE( wxGrid::OnSize ) - EVT_KEY_DOWN( wxGrid::OnKeyDown ) - EVT_KEY_UP( wxGrid::OnKeyUp ) - EVT_CHAR ( wxGrid::OnChar ) - EVT_ERASE_BACKGROUND( wxGrid::OnEraseBackground ) -END_EVENT_TABLE() - -wxGrid::wxGrid() -{ - // in order to make sure that a size event is not - // trigerred in a unfinished state - m_cornerLabelWin = NULL; - m_rowLabelWin = NULL; - m_colLabelWin = NULL; - m_gridWin = NULL; -} - -wxGrid::wxGrid( wxWindow *parent, - wxWindowID id, - const wxPoint& pos, - const wxSize& size, - long style, - const wxString& name ) - : wxScrolledWindow( parent, id, pos, size, (style | wxWANTS_CHARS), name ), - m_colMinWidths(GRID_HASH_SIZE), - m_rowMinHeights(GRID_HASH_SIZE) -{ - Create(); - SetInitialSize(size); -} - -bool wxGrid::Create(wxWindow *parent, wxWindowID id, - const wxPoint& pos, const wxSize& size, - long style, const wxString& name) -{ - if (!wxScrolledWindow::Create(parent, id, pos, size, - style | wxWANTS_CHARS, name)) - return false; - - m_colMinWidths = wxLongToLongHashMap(GRID_HASH_SIZE); - m_rowMinHeights = wxLongToLongHashMap(GRID_HASH_SIZE); - - Create(); - SetInitialSize(size); - CalcDimensions(); - - return true; -} - -wxGrid::~wxGrid() -{ - // Must do this or ~wxScrollHelper will pop the wrong event handler - SetTargetWindow(this); - ClearAttrCache(); - wxSafeDecRef(m_defaultCellAttr); - -#ifdef DEBUG_ATTR_CACHE - size_t total = gs_nAttrCacheHits + gs_nAttrCacheMisses; - wxPrintf(_T("wxGrid attribute cache statistics: " - "total: %u, hits: %u (%u%%)\n"), - total, gs_nAttrCacheHits, - total ? (gs_nAttrCacheHits*100) / total : 0); -#endif - - // if we own the table, just delete it, otherwise at least don't leave it - // with dangling view pointer - if ( m_ownTable ) - delete m_table; - else if ( m_table && m_table->GetView() == this ) - m_table->SetView(NULL); - - delete m_typeRegistry; - delete m_selection; -} - -// -// ----- internal init and update functions -// - -// NOTE: If using the default visual attributes works everywhere then this can -// be removed as well as the #else cases below. -#define _USE_VISATTR 0 - -void wxGrid::Create() -{ - // set to true by CreateGrid - m_created = false; - - // create the type registry - m_typeRegistry = new wxGridTypeRegistry; - m_selection = NULL; - - m_table = (wxGridTableBase *) NULL; - m_ownTable = false; - - m_cellEditCtrlEnabled = false; - - m_defaultCellAttr = new wxGridCellAttr(); - - // Set default cell attributes - m_defaultCellAttr->SetDefAttr(m_defaultCellAttr); - m_defaultCellAttr->SetKind(wxGridCellAttr::Default); - m_defaultCellAttr->SetFont(GetFont()); - m_defaultCellAttr->SetAlignment(wxALIGN_LEFT, wxALIGN_TOP); - m_defaultCellAttr->SetRenderer(new wxGridCellStringRenderer); - m_defaultCellAttr->SetEditor(new wxGridCellTextEditor); - -#if _USE_VISATTR - wxVisualAttributes gva = wxListBox::GetClassDefaultAttributes(); - wxVisualAttributes lva = wxPanel::GetClassDefaultAttributes(); - - m_defaultCellAttr->SetTextColour(gva.colFg); - m_defaultCellAttr->SetBackgroundColour(gva.colBg); - -#else - m_defaultCellAttr->SetTextColour( - wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT)); - m_defaultCellAttr->SetBackgroundColour( - wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW)); -#endif - - m_numRows = 0; - m_numCols = 0; - m_currentCellCoords = wxGridNoCellCoords; - - m_rowLabelWidth = WXGRID_DEFAULT_ROW_LABEL_WIDTH; - m_colLabelHeight = WXGRID_DEFAULT_COL_LABEL_HEIGHT; - - // subwindow components that make up the wxGrid - m_rowLabelWin = new wxGridRowLabelWindow( this, - wxID_ANY, - wxDefaultPosition, - wxDefaultSize ); - - m_colLabelWin = new wxGridColLabelWindow( this, - wxID_ANY, - wxDefaultPosition, - wxDefaultSize ); - - m_cornerLabelWin = new wxGridCornerLabelWindow( this, - wxID_ANY, - wxDefaultPosition, - wxDefaultSize ); - - m_gridWin = new wxGridWindow( this, - m_rowLabelWin, - m_colLabelWin, - wxID_ANY, - wxDefaultPosition, - wxDefaultSize ); - - SetTargetWindow( m_gridWin ); - -#if _USE_VISATTR - wxColour gfg = gva.colFg; - wxColour gbg = gva.colBg; - wxColour lfg = lva.colFg; - wxColour lbg = lva.colBg; -#else - wxColour gfg = wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOWTEXT ); - wxColour gbg = wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOW ); - wxColour lfg = wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOWTEXT ); - wxColour lbg = wxSystemSettings::GetColour( wxSYS_COLOUR_BTNFACE ); -#endif - - m_cornerLabelWin->SetOwnForegroundColour(lfg); - m_cornerLabelWin->SetOwnBackgroundColour(lbg); - m_rowLabelWin->SetOwnForegroundColour(lfg); - m_rowLabelWin->SetOwnBackgroundColour(lbg); - m_colLabelWin->SetOwnForegroundColour(lfg); - m_colLabelWin->SetOwnBackgroundColour(lbg); - - m_gridWin->SetOwnForegroundColour(gfg); - m_gridWin->SetOwnBackgroundColour(gbg); - - Init(); -} - -bool wxGrid::CreateGrid( int numRows, int numCols, - wxGrid::wxGridSelectionModes selmode ) -{ - wxCHECK_MSG( !m_created, - false, - wxT("wxGrid::CreateGrid or wxGrid::SetTable called more than once") ); - - m_numRows = numRows; - m_numCols = numCols; - - m_table = new wxGridStringTable( m_numRows, m_numCols ); - m_table->SetView( this ); - m_ownTable = true; - m_selection = new wxGridSelection( this, selmode ); - - CalcDimensions(); - - m_created = true; - - return m_created; -} - -void wxGrid::SetSelectionMode(wxGrid::wxGridSelectionModes selmode) -{ - wxCHECK_RET( m_created, - wxT("Called wxGrid::SetSelectionMode() before calling CreateGrid()") ); - - m_selection->SetSelectionMode( selmode ); -} - -wxGrid::wxGridSelectionModes wxGrid::GetSelectionMode() const -{ - wxCHECK_MSG( m_created, wxGrid::wxGridSelectCells, - wxT("Called wxGrid::GetSelectionMode() before calling CreateGrid()") ); - - return m_selection->GetSelectionMode(); -} - -bool wxGrid::SetTable( wxGridTableBase *table, bool takeOwnership, - wxGrid::wxGridSelectionModes selmode ) -{ - bool checkSelection = false; - if ( m_created ) - { - // stop all processing - m_created = false; - - if (m_table) - { - m_table->SetView(0); - if( m_ownTable ) - delete m_table; - m_table = NULL; - } - - delete m_selection; - m_selection = NULL; - - m_ownTable = false; - m_numRows = 0; - m_numCols = 0; - checkSelection = true; - - // kill row and column size arrays - m_colWidths.Empty(); - m_colRights.Empty(); - m_rowHeights.Empty(); - m_rowBottoms.Empty(); - } - - if (table) - { - m_numRows = table->GetNumberRows(); - m_numCols = table->GetNumberCols(); - - m_table = table; - m_table->SetView( this ); - m_ownTable = takeOwnership; - m_selection = new wxGridSelection( this, selmode ); - if (checkSelection) - { - // If the newly set table is smaller than the - // original one current cell and selection regions - // might be invalid, - m_selectingKeyboard = wxGridNoCellCoords; - m_currentCellCoords = - wxGridCellCoords(wxMin(m_numRows, m_currentCellCoords.GetRow()), - wxMin(m_numCols, m_currentCellCoords.GetCol())); - if (m_selectingTopLeft.GetRow() >= m_numRows || - m_selectingTopLeft.GetCol() >= m_numCols) - { - m_selectingTopLeft = wxGridNoCellCoords; - m_selectingBottomRight = wxGridNoCellCoords; - } - else - m_selectingBottomRight = - wxGridCellCoords(wxMin(m_numRows, - m_selectingBottomRight.GetRow()), - wxMin(m_numCols, - m_selectingBottomRight.GetCol())); - } - CalcDimensions(); - - m_created = true; - } - - return m_created; -} - -void wxGrid::Init() -{ - m_rowLabelWidth = WXGRID_DEFAULT_ROW_LABEL_WIDTH; - m_colLabelHeight = WXGRID_DEFAULT_COL_LABEL_HEIGHT; - - if ( m_rowLabelWin ) - { - m_labelBackgroundColour = m_rowLabelWin->GetBackgroundColour(); - } - else - { - m_labelBackgroundColour = *wxWHITE; - } - - m_labelTextColour = *wxBLACK; - - // init attr cache - m_attrCache.row = -1; - m_attrCache.col = -1; - m_attrCache.attr = NULL; - - // TODO: something better than this ? - // - m_labelFont = this->GetFont(); - m_labelFont.SetWeight( wxBOLD ); - - m_rowLabelHorizAlign = wxALIGN_CENTRE; - m_rowLabelVertAlign = wxALIGN_CENTRE; - - m_colLabelHorizAlign = wxALIGN_CENTRE; - m_colLabelVertAlign = wxALIGN_CENTRE; - m_colLabelTextOrientation = wxHORIZONTAL; - - m_defaultColWidth = WXGRID_DEFAULT_COL_WIDTH; - m_defaultRowHeight = m_gridWin->GetCharHeight(); - - m_minAcceptableColWidth = WXGRID_MIN_COL_WIDTH; - m_minAcceptableRowHeight = WXGRID_MIN_ROW_HEIGHT; - -#if defined(__WXMOTIF__) || defined(__WXGTK__) // see also text ctrl sizing in ShowCellEditControl() - m_defaultRowHeight += 8; -#else - m_defaultRowHeight += 4; -#endif - - m_gridLineColour = wxColour( 192,192,192 ); - m_gridLinesEnabled = true; - m_cellHighlightColour = *wxBLACK; - m_cellHighlightPenWidth = 2; - m_cellHighlightROPenWidth = 1; - - m_canDragColMove = false; - - m_cursorMode = WXGRID_CURSOR_SELECT_CELL; - m_winCapture = (wxWindow *)NULL; - m_canDragRowSize = true; - m_canDragColSize = true; - m_canDragGridSize = true; - m_canDragCell = false; - m_dragLastPos = -1; - m_dragRowOrCol = -1; - m_isDragging = false; - m_startDragPos = wxDefaultPosition; - - m_waitForSlowClick = false; - - m_rowResizeCursor = wxCursor( wxCURSOR_SIZENS ); - m_colResizeCursor = wxCursor( wxCURSOR_SIZEWE ); - - m_currentCellCoords = wxGridNoCellCoords; - - ClearSelection(); - - m_selectionBackground = wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT); - m_selectionForeground = wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT); - - m_editable = true; // default for whole grid - - m_inOnKeyDown = false; - m_batchCount = 0; - - m_extraWidth = - m_extraHeight = 0; - - m_scrollLineX = GRID_SCROLL_LINE_X; - m_scrollLineY = GRID_SCROLL_LINE_Y; -} - -// ---------------------------------------------------------------------------- -// the idea is to call these functions only when necessary because they create -// quite big arrays which eat memory mostly unnecessary - in particular, if -// default widths/heights are used for all rows/columns, we may not use these -// arrays at all -// -// with some extra code, it should be possible to only store the widths/heights -// different from default ones (resulting in space savings for huge grids) but -// this is not done currently -// ---------------------------------------------------------------------------- - -void wxGrid::InitRowHeights() -{ - m_rowHeights.Empty(); - m_rowBottoms.Empty(); - - m_rowHeights.Alloc( m_numRows ); - m_rowBottoms.Alloc( m_numRows ); - - m_rowHeights.Add( m_defaultRowHeight, m_numRows ); - - int rowBottom = 0; - for ( int i = 0; i < m_numRows; i++ ) - { - rowBottom += m_defaultRowHeight; - m_rowBottoms.Add( rowBottom ); - } -} - -void wxGrid::InitColWidths() -{ - m_colWidths.Empty(); - m_colRights.Empty(); - - m_colWidths.Alloc( m_numCols ); - m_colRights.Alloc( m_numCols ); - - m_colWidths.Add( m_defaultColWidth, m_numCols ); - - int colRight = 0; - for ( int i = 0; i < m_numCols; i++ ) - { - colRight = ( GetColPos( i ) + 1 ) * m_defaultColWidth; - m_colRights.Add( colRight ); - } -} - -int wxGrid::GetColWidth(int col) const -{ - return m_colWidths.IsEmpty() ? m_defaultColWidth : m_colWidths[col]; -} - -int wxGrid::GetColLeft(int col) const -{ - return m_colRights.IsEmpty() ? GetColPos( col ) * m_defaultColWidth - : m_colRights[col] - m_colWidths[col]; -} - -int wxGrid::GetColRight(int col) const -{ - return m_colRights.IsEmpty() ? (GetColPos( col ) + 1) * m_defaultColWidth - : m_colRights[col]; -} - -int wxGrid::GetRowHeight(int row) const -{ - return m_rowHeights.IsEmpty() ? m_defaultRowHeight : m_rowHeights[row]; -} - -int wxGrid::GetRowTop(int row) const -{ - return m_rowBottoms.IsEmpty() ? row * m_defaultRowHeight - : m_rowBottoms[row] - m_rowHeights[row]; -} - -int wxGrid::GetRowBottom(int row) const -{ - return m_rowBottoms.IsEmpty() ? (row + 1) * m_defaultRowHeight - : m_rowBottoms[row]; -} - -void wxGrid::CalcDimensions() -{ - // compute the size of the scrollable area - int w = m_numCols > 0 ? GetColRight(GetColAt(m_numCols - 1)) : 0; - int h = m_numRows > 0 ? GetRowBottom(m_numRows - 1) : 0; - - w += m_extraWidth; - h += m_extraHeight; - - // take into account editor if shown - if ( IsCellEditControlShown() ) - { - int w2, h2; - int r = m_currentCellCoords.GetRow(); - int c = m_currentCellCoords.GetCol(); - int x = GetColLeft(c); - int y = GetRowTop(r); - - // how big is the editor - wxGridCellAttr* attr = GetCellAttr(r, c); - wxGridCellEditor* editor = attr->GetEditor(this, r, c); - editor->GetControl()->GetSize(&w2, &h2); - w2 += x; - h2 += y; - if ( w2 > w ) - w = w2; - if ( h2 > h ) - h = h2; - editor->DecRef(); - attr->DecRef(); - } - - // preserve (more or less) the previous position - int x, y; - GetViewStart( &x, &y ); - - // ensure the position is valid for the new scroll ranges - if ( x >= w ) - x = wxMax( w - 1, 0 ); - if ( y >= h ) - y = wxMax( h - 1, 0 ); - - // do set scrollbar parameters - SetScrollbars( m_scrollLineX, m_scrollLineY, - GetScrollX(w), GetScrollY(h), - x, y, - GetBatchCount() != 0); - - // if our OnSize() hadn't been called (it would if we have scrollbars), we - // still must reposition the children - CalcWindowSizes(); -} - -void wxGrid::CalcWindowSizes() -{ - // escape if the window is has not been fully created yet - - if ( m_cornerLabelWin == NULL ) - return; - - int cw, ch; - GetClientSize( &cw, &ch ); - - // this block of code tries to work around the following problem: the grid - // could have been just resized to have enough space to show the full grid - // window contents without the scrollbars, but its client size could be - // not big enough because the grid has the scrollbars right now and so the - // scrollbars would remain even though we don't need them any more - // - // to prevent this from happening, check if we have enough space for - // everything without the scrollbars and explicitly disable them then - wxSize size = GetSize() - GetWindowBorderSize(); - if ( size != wxSize(cw, ch) ) - { - // check if we have enough space for grid window after accounting for - // the fixed size elements - size.x -= m_rowLabelWidth; - size.y -= m_colLabelHeight; - - const wxSize vsize = m_gridWin->GetVirtualSize(); - - if ( size.x >= vsize.x && size.y >= vsize.y ) - { - // yes, we do, so remove the scrollbars and use the new client size - // (which should be the same as full window size - borders now) - SetScrollbars(0, 0, 0, 0); - GetClientSize(&cw, &ch); - } - } - - // the grid may be too small to have enough space for the labels yet, don't - // size the windows to negative sizes in this case - int gw = cw - m_rowLabelWidth; - int gh = ch - m_colLabelHeight; - if (gw < 0) - gw = 0; - if (gh < 0) - gh = 0; - - if ( m_cornerLabelWin && m_cornerLabelWin->IsShown() ) - m_cornerLabelWin->SetSize( 0, 0, m_rowLabelWidth, m_colLabelHeight ); - - if ( m_colLabelWin && m_colLabelWin->IsShown() ) - m_colLabelWin->SetSize( m_rowLabelWidth, 0, gw, m_colLabelHeight ); - - if ( m_rowLabelWin && m_rowLabelWin->IsShown() ) - m_rowLabelWin->SetSize( 0, m_colLabelHeight, m_rowLabelWidth, gh ); - - if ( m_gridWin && m_gridWin->IsShown() ) - m_gridWin->SetSize( m_rowLabelWidth, m_colLabelHeight, gw, gh ); -} - -// this is called when the grid table sends a message -// to indicate that it has been redimensioned -// -bool wxGrid::Redimension( wxGridTableMessage& msg ) -{ - int i; - bool result = false; - - // Clear the attribute cache as the attribute might refer to a different - // cell than stored in the cache after adding/removing rows/columns. - ClearAttrCache(); - - // By the same reasoning, the editor should be dismissed if columns are - // added or removed. And for consistency, it should IMHO always be - // removed, not only if the cell "underneath" it actually changes. - // For now, I intentionally do not save the editor's content as the - // cell it might want to save that stuff to might no longer exist. - HideCellEditControl(); - -#if 0 - // if we were using the default widths/heights so far, we must change them - // now - if ( m_colWidths.IsEmpty() ) - { - InitColWidths(); - } - - if ( m_rowHeights.IsEmpty() ) - { - InitRowHeights(); - } -#endif - - switch ( msg.GetId() ) - { - case wxGRIDTABLE_NOTIFY_ROWS_INSERTED: - { - size_t pos = msg.GetCommandInt(); - int numRows = msg.GetCommandInt2(); - - m_numRows += numRows; - - if ( !m_rowHeights.IsEmpty() ) - { - m_rowHeights.Insert( m_defaultRowHeight, pos, numRows ); - m_rowBottoms.Insert( 0, pos, numRows ); - - int bottom = 0; - if ( pos > 0 ) - bottom = m_rowBottoms[pos - 1]; - - for ( i = pos; i < m_numRows; i++ ) - { - bottom += m_rowHeights[i]; - m_rowBottoms[i] = bottom; - } - } - - if ( m_currentCellCoords == wxGridNoCellCoords ) - { - // if we have just inserted cols into an empty grid the current - // cell will be undefined... - // - SetCurrentCell( 0, 0 ); - } - - if ( m_selection ) - m_selection->UpdateRows( pos, numRows ); - wxGridCellAttrProvider * attrProvider = m_table->GetAttrProvider(); - if (attrProvider) - attrProvider->UpdateAttrRows( pos, numRows ); - - if ( !GetBatchCount() ) - { - CalcDimensions(); - m_rowLabelWin->Refresh(); - } - } - result = true; - break; - - case wxGRIDTABLE_NOTIFY_ROWS_APPENDED: - { - int numRows = msg.GetCommandInt(); - int oldNumRows = m_numRows; - m_numRows += numRows; - - if ( !m_rowHeights.IsEmpty() ) - { - m_rowHeights.Add( m_defaultRowHeight, numRows ); - m_rowBottoms.Add( 0, numRows ); - - int bottom = 0; - if ( oldNumRows > 0 ) - bottom = m_rowBottoms[oldNumRows - 1]; - - for ( i = oldNumRows; i < m_numRows; i++ ) - { - bottom += m_rowHeights[i]; - m_rowBottoms[i] = bottom; - } - } - - if ( m_currentCellCoords == wxGridNoCellCoords ) - { - // if we have just inserted cols into an empty grid the current - // cell will be undefined... - // - SetCurrentCell( 0, 0 ); - } - - if ( !GetBatchCount() ) - { - CalcDimensions(); - m_rowLabelWin->Refresh(); - } - } - result = true; - break; - - case wxGRIDTABLE_NOTIFY_ROWS_DELETED: - { - size_t pos = msg.GetCommandInt(); - int numRows = msg.GetCommandInt2(); - m_numRows -= numRows; - - if ( !m_rowHeights.IsEmpty() ) - { - m_rowHeights.RemoveAt( pos, numRows ); - m_rowBottoms.RemoveAt( pos, numRows ); - - int h = 0; - for ( i = 0; i < m_numRows; i++ ) - { - h += m_rowHeights[i]; - m_rowBottoms[i] = h; - } - } - - if ( !m_numRows ) - { - m_currentCellCoords = wxGridNoCellCoords; - } - else - { - if ( m_currentCellCoords.GetRow() >= m_numRows ) - m_currentCellCoords.Set( 0, 0 ); - } - - if ( m_selection ) - m_selection->UpdateRows( pos, -((int)numRows) ); - wxGridCellAttrProvider * attrProvider = m_table->GetAttrProvider(); - if (attrProvider) - { - attrProvider->UpdateAttrRows( pos, -((int)numRows) ); - -// ifdef'd out following patch from Paul Gammans -#if 0 - // No need to touch column attributes, unless we - // removed _all_ rows, in this case, we remove - // all column attributes. - // I hate to do this here, but the - // needed data is not available inside UpdateAttrRows. - if ( !GetNumberRows() ) - attrProvider->UpdateAttrCols( 0, -GetNumberCols() ); -#endif - } - - if ( !GetBatchCount() ) - { - CalcDimensions(); - m_rowLabelWin->Refresh(); - } - } - result = true; - break; - - case wxGRIDTABLE_NOTIFY_COLS_INSERTED: - { - size_t pos = msg.GetCommandInt(); - int numCols = msg.GetCommandInt2(); - m_numCols += numCols; - - if ( !m_colAt.IsEmpty() ) - { - //Shift the column IDs - int i; - for ( i = 0; i < m_numCols - numCols; i++ ) - { - if ( m_colAt[i] >= (int)pos ) - m_colAt[i] += numCols; - } - - m_colAt.Insert( pos, pos, numCols ); - - //Set the new columns' positions - for ( i = pos + 1; i < (int)pos + numCols; i++ ) - { - m_colAt[i] = i; - } - } - - if ( !m_colWidths.IsEmpty() ) - { - m_colWidths.Insert( m_defaultColWidth, pos, numCols ); - m_colRights.Insert( 0, pos, numCols ); - - int right = 0; - if ( pos > 0 ) - right = m_colRights[GetColAt( pos - 1 )]; - - int colPos; - for ( colPos = pos; colPos < m_numCols; colPos++ ) - { - i = GetColAt( colPos ); - - right += m_colWidths[i]; - m_colRights[i] = right; - } - } - - if ( m_currentCellCoords == wxGridNoCellCoords ) - { - // if we have just inserted cols into an empty grid the current - // cell will be undefined... - // - SetCurrentCell( 0, 0 ); - } - - if ( m_selection ) - m_selection->UpdateCols( pos, numCols ); - wxGridCellAttrProvider * attrProvider = m_table->GetAttrProvider(); - if (attrProvider) - attrProvider->UpdateAttrCols( pos, numCols ); - if ( !GetBatchCount() ) - { - CalcDimensions(); - m_colLabelWin->Refresh(); - } - } - result = true; - break; - - case wxGRIDTABLE_NOTIFY_COLS_APPENDED: - { - int numCols = msg.GetCommandInt(); - int oldNumCols = m_numCols; - m_numCols += numCols; - - if ( !m_colAt.IsEmpty() ) - { - m_colAt.Add( 0, numCols ); - - //Set the new columns' positions - int i; - for ( i = oldNumCols; i < m_numCols; i++ ) - { - m_colAt[i] = i; - } - } - - if ( !m_colWidths.IsEmpty() ) - { - m_colWidths.Add( m_defaultColWidth, numCols ); - m_colRights.Add( 0, numCols ); - - int right = 0; - if ( oldNumCols > 0 ) - right = m_colRights[GetColAt( oldNumCols - 1 )]; - - int colPos; - for ( colPos = oldNumCols; colPos < m_numCols; colPos++ ) - { - i = GetColAt( colPos ); - - right += m_colWidths[i]; - m_colRights[i] = right; - } - } - - if ( m_currentCellCoords == wxGridNoCellCoords ) - { - // if we have just inserted cols into an empty grid the current - // cell will be undefined... - // - SetCurrentCell( 0, 0 ); - } - if ( !GetBatchCount() ) - { - CalcDimensions(); - m_colLabelWin->Refresh(); - } - } - result = true; - break; - - case wxGRIDTABLE_NOTIFY_COLS_DELETED: - { - size_t pos = msg.GetCommandInt(); - int numCols = msg.GetCommandInt2(); - m_numCols -= numCols; - - if ( !m_colAt.IsEmpty() ) - { - int colID = GetColAt( pos ); - - m_colAt.RemoveAt( pos, numCols ); - - //Shift the column IDs - int colPos; - for ( colPos = 0; colPos < m_numCols; colPos++ ) - { - if ( m_colAt[colPos] > colID ) - m_colAt[colPos] -= numCols; - } - } - - if ( !m_colWidths.IsEmpty() ) - { - m_colWidths.RemoveAt( pos, numCols ); - m_colRights.RemoveAt( pos, numCols ); - - int w = 0; - int colPos; - for ( colPos = 0; colPos < m_numCols; colPos++ ) - { - i = GetColAt( colPos ); - - w += m_colWidths[i]; - m_colRights[i] = w; - } - } - - if ( !m_numCols ) - { - m_currentCellCoords = wxGridNoCellCoords; - } - else - { - if ( m_currentCellCoords.GetCol() >= m_numCols ) - m_currentCellCoords.Set( 0, 0 ); - } - - if ( m_selection ) - m_selection->UpdateCols( pos, -((int)numCols) ); - wxGridCellAttrProvider * attrProvider = m_table->GetAttrProvider(); - if (attrProvider) - { - attrProvider->UpdateAttrCols( pos, -((int)numCols) ); - -// ifdef'd out following patch from Paul Gammans -#if 0 - // No need to touch row attributes, unless we - // removed _all_ columns, in this case, we remove - // all row attributes. - // I hate to do this here, but the - // needed data is not available inside UpdateAttrCols. - if ( !GetNumberCols() ) - attrProvider->UpdateAttrRows( 0, -GetNumberRows() ); -#endif - } - - if ( !GetBatchCount() ) - { - CalcDimensions(); - m_colLabelWin->Refresh(); - } - } - result = true; - break; - } - - if (result && !GetBatchCount() ) - m_gridWin->Refresh(); - - return result; -} - -wxArrayInt wxGrid::CalcRowLabelsExposed( const wxRegion& reg ) -{ - wxRegionIterator iter( reg ); - wxRect r; - - wxArrayInt rowlabels; - - int top, bottom; - while ( iter ) - { - r = iter.GetRect(); - - // TODO: remove this when we can... - // There is a bug in wxMotif that gives garbage update - // rectangles if you jump-scroll a long way by clicking the - // scrollbar with middle button. This is a work-around - // -#if defined(__WXMOTIF__) - int cw, ch; - m_gridWin->GetClientSize( &cw, &ch ); - if ( r.GetTop() > ch ) - r.SetTop( 0 ); - r.SetBottom( wxMin( r.GetBottom(), ch ) ); -#endif - - // logical bounds of update region - // - int dummy; - CalcUnscrolledPosition( 0, r.GetTop(), &dummy, &top ); - CalcUnscrolledPosition( 0, r.GetBottom(), &dummy, &bottom ); - - // find the row labels within these bounds - // - int row; - for ( row = internalYToRow(top); row < m_numRows; row++ ) - { - if ( GetRowBottom(row) < top ) - continue; - - if ( GetRowTop(row) > bottom ) - break; - - rowlabels.Add( row ); - } - - ++iter; - } - - return rowlabels; -} - -wxArrayInt wxGrid::CalcColLabelsExposed( const wxRegion& reg ) -{ - wxRegionIterator iter( reg ); - wxRect r; - - wxArrayInt colLabels; - - int left, right; - while ( iter ) - { - r = iter.GetRect(); - - // TODO: remove this when we can... - // There is a bug in wxMotif that gives garbage update - // rectangles if you jump-scroll a long way by clicking the - // scrollbar with middle button. This is a work-around - // -#if defined(__WXMOTIF__) - int cw, ch; - m_gridWin->GetClientSize( &cw, &ch ); - if ( r.GetLeft() > cw ) - r.SetLeft( 0 ); - r.SetRight( wxMin( r.GetRight(), cw ) ); -#endif - - // logical bounds of update region - // - int dummy; - CalcUnscrolledPosition( r.GetLeft(), 0, &left, &dummy ); - CalcUnscrolledPosition( r.GetRight(), 0, &right, &dummy ); - - // find the cells within these bounds - // - int col; - int colPos; - for ( colPos = GetColPos( internalXToCol(left) ); colPos < m_numCols; colPos++ ) - { - col = GetColAt( colPos ); - - if ( GetColRight(col) < left ) - continue; - - if ( GetColLeft(col) > right ) - break; - - colLabels.Add( col ); - } - - ++iter; - } - - return colLabels; -} - -wxGridCellCoordsArray wxGrid::CalcCellsExposed( const wxRegion& reg ) -{ - wxRegionIterator iter( reg ); - wxRect r; - - wxGridCellCoordsArray cellsExposed; - - int left, top, right, bottom; - while ( iter ) - { - r = iter.GetRect(); - - // TODO: remove this when we can... - // There is a bug in wxMotif that gives garbage update - // rectangles if you jump-scroll a long way by clicking the - // scrollbar with middle button. This is a work-around - // -#if defined(__WXMOTIF__) - int cw, ch; - m_gridWin->GetClientSize( &cw, &ch ); - if ( r.GetTop() > ch ) r.SetTop( 0 ); - if ( r.GetLeft() > cw ) r.SetLeft( 0 ); - r.SetRight( wxMin( r.GetRight(), cw ) ); - r.SetBottom( wxMin( r.GetBottom(), ch ) ); -#endif - - // logical bounds of update region - // - CalcUnscrolledPosition( r.GetLeft(), r.GetTop(), &left, &top ); - CalcUnscrolledPosition( r.GetRight(), r.GetBottom(), &right, &bottom ); - - // find the cells within these bounds - // - int row, col; - for ( row = internalYToRow(top); row < m_numRows; row++ ) - { - if ( GetRowBottom(row) <= top ) - continue; - - if ( GetRowTop(row) > bottom ) - break; - - int colPos; - for ( colPos = GetColPos( internalXToCol(left) ); colPos < m_numCols; colPos++ ) - { - col = GetColAt( colPos ); - - if ( GetColRight(col) <= left ) - continue; - - if ( GetColLeft(col) > right ) - break; - - cellsExposed.Add( wxGridCellCoords( row, col ) ); - } - } - - ++iter; - } - - return cellsExposed; -} - - -void wxGrid::ProcessRowLabelMouseEvent( wxMouseEvent& event ) -{ - int x, y, row; - wxPoint pos( event.GetPosition() ); - CalcUnscrolledPosition( pos.x, pos.y, &x, &y ); - - if ( event.Dragging() ) - { - if (!m_isDragging) - { - m_isDragging = true; - m_rowLabelWin->CaptureMouse(); - } - - if ( event.LeftIsDown() ) - { - switch ( m_cursorMode ) - { - case WXGRID_CURSOR_RESIZE_ROW: - { - int cw, ch, left, dummy; - m_gridWin->GetClientSize( &cw, &ch ); - CalcUnscrolledPosition( 0, 0, &left, &dummy ); - - wxClientDC dc( m_gridWin ); - PrepareDC( dc ); - y = wxMax( y, - GetRowTop(m_dragRowOrCol) + - GetRowMinimalHeight(m_dragRowOrCol) ); - dc.SetLogicalFunction(wxINVERT); - if ( m_dragLastPos >= 0 ) - { - dc.DrawLine( left, m_dragLastPos, left+cw, m_dragLastPos ); - } - dc.DrawLine( left, y, left+cw, y ); - m_dragLastPos = y; - } - break; - - case WXGRID_CURSOR_SELECT_ROW: - { - if ( (row = YToRow( y )) >= 0 ) - { - if ( m_selection ) - { - m_selection->SelectRow( row, - event.ControlDown(), - event.ShiftDown(), - event.AltDown(), - event.MetaDown() ); - } - } - } - break; - - // default label to suppress warnings about "enumeration value - // 'xxx' not handled in switch - default: - break; - } - } - return; - } - - if ( m_isDragging && (event.Entering() || event.Leaving()) ) - return; - - if (m_isDragging) - { - if (m_rowLabelWin->HasCapture()) - m_rowLabelWin->ReleaseMouse(); - m_isDragging = false; - } - - // ------------ Entering or leaving the window - // - if ( event.Entering() || event.Leaving() ) - { - ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL, m_rowLabelWin); - } - - // ------------ Left button pressed - // - else if ( event.LeftDown() ) - { - // don't send a label click event for a hit on the - // edge of the row label - this is probably the user - // wanting to resize the row - // - if ( YToEdgeOfRow(y) < 0 ) - { - row = YToRow(y); - if ( row >= 0 && - !SendEvent( wxEVT_GRID_LABEL_LEFT_CLICK, row, -1, event ) ) - { - if ( !event.ShiftDown() && !event.CmdDown() ) - ClearSelection(); - if ( m_selection ) - { - if ( event.ShiftDown() ) - { - m_selection->SelectBlock( m_currentCellCoords.GetRow(), - 0, - row, - GetNumberCols() - 1, - event.ControlDown(), - event.ShiftDown(), - event.AltDown(), - event.MetaDown() ); - } - else - { - m_selection->SelectRow( row, - event.ControlDown(), - event.ShiftDown(), - event.AltDown(), - event.MetaDown() ); - } - } - - ChangeCursorMode(WXGRID_CURSOR_SELECT_ROW, m_rowLabelWin); - } - } - else - { - // starting to drag-resize a row - if ( CanDragRowSize() ) - ChangeCursorMode(WXGRID_CURSOR_RESIZE_ROW, m_rowLabelWin); - } - } - - // ------------ Left double click - // - else if (event.LeftDClick() ) - { - row = YToEdgeOfRow(y); - if ( row < 0 ) - { - row = YToRow(y); - if ( row >=0 && - !SendEvent( wxEVT_GRID_LABEL_LEFT_DCLICK, row, -1, event ) ) - { - // no default action at the moment - } - } - else - { - // adjust row height depending on label text - AutoSizeRowLabelSize( row ); - - ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL, m_colLabelWin); - m_dragLastPos = -1; - } - } - - // ------------ Left button released - // - else if ( event.LeftUp() ) - { - if ( m_cursorMode == WXGRID_CURSOR_RESIZE_ROW ) - { - DoEndDragResizeRow(); - - // Note: we are ending the event *after* doing - // default processing in this case - // - SendEvent( wxEVT_GRID_ROW_SIZE, m_dragRowOrCol, -1, event ); - } - - ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL, m_rowLabelWin); - m_dragLastPos = -1; - } - - // ------------ Right button down - // - else if ( event.RightDown() ) - { - row = YToRow(y); - if ( row >=0 && - !SendEvent( wxEVT_GRID_LABEL_RIGHT_CLICK, row, -1, event ) ) - { - // no default action at the moment - } - } - - // ------------ Right double click - // - else if ( event.RightDClick() ) - { - row = YToRow(y); - if ( row >= 0 && - !SendEvent( wxEVT_GRID_LABEL_RIGHT_DCLICK, row, -1, event ) ) - { - // no default action at the moment - } - } - - // ------------ No buttons down and mouse moving - // - else if ( event.Moving() ) - { - m_dragRowOrCol = YToEdgeOfRow( y ); - if ( m_dragRowOrCol >= 0 ) - { - if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL ) - { - // don't capture the mouse yet - if ( CanDragRowSize() ) - ChangeCursorMode(WXGRID_CURSOR_RESIZE_ROW, m_rowLabelWin, false); - } - } - else if ( m_cursorMode != WXGRID_CURSOR_SELECT_CELL ) - { - ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL, m_rowLabelWin, false); - } - } -} - -void wxGrid::ProcessColLabelMouseEvent( wxMouseEvent& event ) -{ - int x, y, col; - wxPoint pos( event.GetPosition() ); - CalcUnscrolledPosition( pos.x, pos.y, &x, &y ); - - if ( event.Dragging() ) - { - if (!m_isDragging) - { - m_isDragging = true; - m_colLabelWin->CaptureMouse(); - - if ( m_cursorMode == WXGRID_CURSOR_MOVE_COL ) - m_dragRowOrCol = XToCol( x ); - } - - if ( event.LeftIsDown() ) - { - switch ( m_cursorMode ) - { - case WXGRID_CURSOR_RESIZE_COL: - { - int cw, ch, dummy, top; - m_gridWin->GetClientSize( &cw, &ch ); - CalcUnscrolledPosition( 0, 0, &dummy, &top ); - - wxClientDC dc( m_gridWin ); - PrepareDC( dc ); - - x = wxMax( x, GetColLeft(m_dragRowOrCol) + - GetColMinimalWidth(m_dragRowOrCol)); - dc.SetLogicalFunction(wxINVERT); - if ( m_dragLastPos >= 0 ) - { - dc.DrawLine( m_dragLastPos, top, m_dragLastPos, top + ch ); - } - dc.DrawLine( x, top, x, top + ch ); - m_dragLastPos = x; - } - break; - - case WXGRID_CURSOR_SELECT_COL: - { - if ( (col = XToCol( x )) >= 0 ) - { - if ( m_selection ) - { - m_selection->SelectCol( col, - event.ControlDown(), - event.ShiftDown(), - event.AltDown(), - event.MetaDown() ); - } - } - } - break; - - case WXGRID_CURSOR_MOVE_COL: - { - if ( x < 0 ) - m_moveToCol = GetColAt( 0 ); - else - m_moveToCol = XToCol( x ); - - int markerX; - - if ( m_moveToCol < 0 ) - markerX = GetColRight( GetColAt( m_numCols - 1 ) ); - else - markerX = GetColLeft( m_moveToCol ); - - if ( markerX != m_dragLastPos ) - { - wxClientDC dc( m_colLabelWin ); - - int cw, ch; - m_colLabelWin->GetClientSize( &cw, &ch ); - - markerX++; - - //Clean up the last indicator - if ( m_dragLastPos >= 0 ) - { - wxPen pen( m_colLabelWin->GetBackgroundColour(), 2 ); - dc.SetPen(pen); - dc.DrawLine( m_dragLastPos + 1, 0, m_dragLastPos + 1, ch ); - dc.SetPen(wxNullPen); - - if ( XToCol( m_dragLastPos ) != -1 ) - DrawColLabel( dc, XToCol( m_dragLastPos ) ); - } - - //Moving to the same place? Don't draw a marker - if ( (m_moveToCol == m_dragRowOrCol) - || (GetColPos( m_moveToCol ) == GetColPos( m_dragRowOrCol ) + 1) - || (m_moveToCol < 0 && m_dragRowOrCol == GetColAt( m_numCols - 1 ))) - { - m_dragLastPos = -1; - return; - } - - //Draw the marker - wxPen pen( *wxBLUE, 2 ); - dc.SetPen(pen); - - dc.DrawLine( markerX, 0, markerX, ch ); - - dc.SetPen(wxNullPen); - - m_dragLastPos = markerX - 1; - } - } - break; - - // default label to suppress warnings about "enumeration value - // 'xxx' not handled in switch - default: - break; - } - } - return; - } - - if ( m_isDragging && (event.Entering() || event.Leaving()) ) - return; - - if (m_isDragging) - { - if (m_colLabelWin->HasCapture()) - m_colLabelWin->ReleaseMouse(); - m_isDragging = false; - } - - // ------------ Entering or leaving the window - // - if ( event.Entering() || event.Leaving() ) - { - ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL, m_colLabelWin); - } - - // ------------ Left button pressed - // - else if ( event.LeftDown() ) - { - // don't send a label click event for a hit on the - // edge of the col label - this is probably the user - // wanting to resize the col - // - if ( XToEdgeOfCol(x) < 0 ) - { - col = XToCol(x); - if ( col >= 0 && - !SendEvent( wxEVT_GRID_LABEL_LEFT_CLICK, -1, col, event ) ) - { - if ( m_canDragColMove ) - { - //Show button as pressed - wxClientDC dc( m_colLabelWin ); - int colLeft = GetColLeft( col ); - int colRight = GetColRight( col ) - 1; - dc.SetPen( wxPen( m_colLabelWin->GetBackgroundColour(), 1 ) ); - dc.DrawLine( colLeft, 1, colLeft, m_colLabelHeight-1 ); - dc.DrawLine( colLeft, 1, colRight, 1 ); - - ChangeCursorMode(WXGRID_CURSOR_MOVE_COL, m_colLabelWin); - } - else - { - if ( !event.ShiftDown() && !event.CmdDown() ) - ClearSelection(); - if ( m_selection ) - { - if ( event.ShiftDown() ) - { - m_selection->SelectBlock( 0, - m_currentCellCoords.GetCol(), - GetNumberRows() - 1, col, - event.ControlDown(), - event.ShiftDown(), - event.AltDown(), - event.MetaDown() ); - } - else - { - m_selection->SelectCol( col, - event.ControlDown(), - event.ShiftDown(), - event.AltDown(), - event.MetaDown() ); - } - } - - ChangeCursorMode(WXGRID_CURSOR_SELECT_COL, m_colLabelWin); - } - } - } - else - { - // starting to drag-resize a col - // - if ( CanDragColSize() ) - ChangeCursorMode(WXGRID_CURSOR_RESIZE_COL, m_colLabelWin); - } - } - - // ------------ Left double click - // - if ( event.LeftDClick() ) - { - col = XToEdgeOfCol(x); - if ( col < 0 ) - { - col = XToCol(x); - if ( col >= 0 && - ! SendEvent( wxEVT_GRID_LABEL_LEFT_DCLICK, -1, col, event ) ) - { - // no default action at the moment - } - } - else - { - // adjust column width depending on label text - AutoSizeColLabelSize( col ); - - ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL, m_colLabelWin); - m_dragLastPos = -1; - } - } - - // ------------ Left button released - // - else if ( event.LeftUp() ) - { - switch ( m_cursorMode ) - { - case WXGRID_CURSOR_RESIZE_COL: - DoEndDragResizeCol(); - - // Note: we are ending the event *after* doing - // default processing in this case - // - SendEvent( wxEVT_GRID_COL_SIZE, -1, m_dragRowOrCol, event ); - break; - - case WXGRID_CURSOR_MOVE_COL: - DoEndDragMoveCol(); - - SendEvent( wxEVT_GRID_COL_MOVE, -1, m_dragRowOrCol, event ); - break; - - case WXGRID_CURSOR_SELECT_COL: - case WXGRID_CURSOR_SELECT_CELL: - case WXGRID_CURSOR_RESIZE_ROW: - case WXGRID_CURSOR_SELECT_ROW: - // nothing to do (?) - break; - } - - ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL, m_colLabelWin); - m_dragLastPos = -1; - } - - // ------------ Right button down - // - else if ( event.RightDown() ) - { - col = XToCol(x); - if ( col >= 0 && - !SendEvent( wxEVT_GRID_LABEL_RIGHT_CLICK, -1, col, event ) ) - { - // no default action at the moment - } - } - - // ------------ Right double click - // - else if ( event.RightDClick() ) - { - col = XToCol(x); - if ( col >= 0 && - !SendEvent( wxEVT_GRID_LABEL_RIGHT_DCLICK, -1, col, event ) ) - { - // no default action at the moment - } - } - - // ------------ No buttons down and mouse moving - // - else if ( event.Moving() ) - { - m_dragRowOrCol = XToEdgeOfCol( x ); - if ( m_dragRowOrCol >= 0 ) - { - if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL ) - { - // don't capture the cursor yet - if ( CanDragColSize() ) - ChangeCursorMode(WXGRID_CURSOR_RESIZE_COL, m_colLabelWin, false); - } - } - else if ( m_cursorMode != WXGRID_CURSOR_SELECT_CELL ) - { - ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL, m_colLabelWin, false); - } - } -} - -void wxGrid::ProcessCornerLabelMouseEvent( wxMouseEvent& event ) -{ - if ( event.LeftDown() ) - { - // indicate corner label by having both row and - // col args == -1 - // - if ( !SendEvent( wxEVT_GRID_LABEL_LEFT_CLICK, -1, -1, event ) ) - { - SelectAll(); - } - } - else if ( event.LeftDClick() ) - { - SendEvent( wxEVT_GRID_LABEL_LEFT_DCLICK, -1, -1, event ); - } - else if ( event.RightDown() ) - { - if ( !SendEvent( wxEVT_GRID_LABEL_RIGHT_CLICK, -1, -1, event ) ) - { - // no default action at the moment - } - } - else if ( event.RightDClick() ) - { - if ( !SendEvent( wxEVT_GRID_LABEL_RIGHT_DCLICK, -1, -1, event ) ) - { - // no default action at the moment - } - } -} - -void wxGrid::ChangeCursorMode(CursorMode mode, - wxWindow *win, - bool captureMouse) -{ -#ifdef __WXDEBUG__ - static const wxChar *cursorModes[] = - { - _T("SELECT_CELL"), - _T("RESIZE_ROW"), - _T("RESIZE_COL"), - _T("SELECT_ROW"), - _T("SELECT_COL"), - _T("MOVE_COL"), - }; - - wxLogTrace(_T("grid"), - _T("wxGrid cursor mode (mouse capture for %s): %s -> %s"), - win == m_colLabelWin ? _T("colLabelWin") - : win ? _T("rowLabelWin") - : _T("gridWin"), - cursorModes[m_cursorMode], cursorModes[mode]); -#endif - - if ( mode == m_cursorMode && - win == m_winCapture && - captureMouse == (m_winCapture != NULL)) - return; - - if ( !win ) - { - // by default use the grid itself - win = m_gridWin; - } - - if ( m_winCapture ) - { - if (m_winCapture->HasCapture()) - m_winCapture->ReleaseMouse(); - m_winCapture = (wxWindow *)NULL; - } - - m_cursorMode = mode; - - switch ( m_cursorMode ) - { - case WXGRID_CURSOR_RESIZE_ROW: - win->SetCursor( m_rowResizeCursor ); - break; - - case WXGRID_CURSOR_RESIZE_COL: - win->SetCursor( m_colResizeCursor ); - break; - - case WXGRID_CURSOR_MOVE_COL: - win->SetCursor( wxCursor(wxCURSOR_HAND) ); - break; - - default: - win->SetCursor( *wxSTANDARD_CURSOR ); - break; - } - - // we need to capture mouse when resizing - bool resize = m_cursorMode == WXGRID_CURSOR_RESIZE_ROW || - m_cursorMode == WXGRID_CURSOR_RESIZE_COL; - - if ( captureMouse && resize ) - { - win->CaptureMouse(); - m_winCapture = win; - } -} - -void wxGrid::ProcessGridCellMouseEvent( wxMouseEvent& event ) -{ - int x, y; - wxPoint pos( event.GetPosition() ); - CalcUnscrolledPosition( pos.x, pos.y, &x, &y ); - - wxGridCellCoords coords; - XYToCell( x, y, coords ); - - int cell_rows, cell_cols; - bool isFirstDrag = !m_isDragging; - GetCellSize( coords.GetRow(), coords.GetCol(), &cell_rows, &cell_cols ); - if ((cell_rows < 0) || (cell_cols < 0)) - { - coords.SetRow(coords.GetRow() + cell_rows); - coords.SetCol(coords.GetCol() + cell_cols); - } - - if ( event.Dragging() ) - { - //wxLogDebug("pos(%d, %d) coords(%d, %d)", pos.x, pos.y, coords.GetRow(), coords.GetCol()); - - // Don't start doing anything until the mouse has been dragged at - // least 3 pixels in any direction... - if (! m_isDragging) - { - if (m_startDragPos == wxDefaultPosition) - { - m_startDragPos = pos; - return; - } - if (abs(m_startDragPos.x - pos.x) < 4 && abs(m_startDragPos.y - pos.y) < 4) - return; - } - - m_isDragging = true; - if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL ) - { - // Hide the edit control, so it - // won't interfere with drag-shrinking. - if ( IsCellEditControlShown() ) - { - HideCellEditControl(); - SaveEditControlValue(); - } - - if ( coords != wxGridNoCellCoords ) - { - if ( event.CmdDown() ) - { - if ( m_selectingKeyboard == wxGridNoCellCoords) - m_selectingKeyboard = coords; - HighlightBlock( m_selectingKeyboard, coords ); - } - else if ( CanDragCell() ) - { - if ( isFirstDrag ) - { - if ( m_selectingKeyboard == wxGridNoCellCoords) - m_selectingKeyboard = coords; - - SendEvent( wxEVT_GRID_CELL_BEGIN_DRAG, - coords.GetRow(), - coords.GetCol(), - event ); - return; - } - } - else - { - if ( !IsSelection() ) - { - HighlightBlock( coords, coords ); - } - else - { - HighlightBlock( m_currentCellCoords, coords ); - } - } - - if (! IsVisible(coords)) - { - MakeCellVisible(coords); - // TODO: need to introduce a delay or something here. The - // scrolling is way to fast, at least on MSW - also on GTK. - } - } - // Have we captured the mouse yet? - if (! m_winCapture) - { - m_winCapture = m_gridWin; - m_winCapture->CaptureMouse(); - } - - - } - else if ( m_cursorMode == WXGRID_CURSOR_RESIZE_ROW ) - { - int cw, ch, left, dummy; - m_gridWin->GetClientSize( &cw, &ch ); - CalcUnscrolledPosition( 0, 0, &left, &dummy ); - - wxClientDC dc( m_gridWin ); - PrepareDC( dc ); - y = wxMax( y, GetRowTop(m_dragRowOrCol) + - GetRowMinimalHeight(m_dragRowOrCol) ); - dc.SetLogicalFunction(wxINVERT); - if ( m_dragLastPos >= 0 ) - { - dc.DrawLine( left, m_dragLastPos, left+cw, m_dragLastPos ); - } - dc.DrawLine( left, y, left+cw, y ); - m_dragLastPos = y; - } - else if ( m_cursorMode == WXGRID_CURSOR_RESIZE_COL ) - { - int cw, ch, dummy, top; - m_gridWin->GetClientSize( &cw, &ch ); - CalcUnscrolledPosition( 0, 0, &dummy, &top ); - - wxClientDC dc( m_gridWin ); - PrepareDC( dc ); - x = wxMax( x, GetColLeft(m_dragRowOrCol) + - GetColMinimalWidth(m_dragRowOrCol) ); - dc.SetLogicalFunction(wxINVERT); - if ( m_dragLastPos >= 0 ) - { - dc.DrawLine( m_dragLastPos, top, m_dragLastPos, top + ch ); - } - dc.DrawLine( x, top, x, top + ch ); - m_dragLastPos = x; - } - - return; - } - - m_isDragging = false; - m_startDragPos = wxDefaultPosition; - - // VZ: if we do this, the mode is reset to WXGRID_CURSOR_SELECT_CELL - // immediately after it becomes WXGRID_CURSOR_RESIZE_ROW/COL under - // wxGTK -#if 0 - if ( event.Entering() || event.Leaving() ) - { - ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL); - m_gridWin->SetCursor( *wxSTANDARD_CURSOR ); - } - else -#endif // 0 - - // ------------ Left button pressed - // - if ( event.LeftDown() && coords != wxGridNoCellCoords ) - { - if ( !SendEvent( wxEVT_GRID_CELL_LEFT_CLICK, - coords.GetRow(), - coords.GetCol(), - event ) ) - { - if ( !event.CmdDown() ) - ClearSelection(); - if ( event.ShiftDown() ) - { - if ( m_selection ) - { - m_selection->SelectBlock( m_currentCellCoords.GetRow(), - m_currentCellCoords.GetCol(), - coords.GetRow(), - coords.GetCol(), - event.ControlDown(), - event.ShiftDown(), - event.AltDown(), - event.MetaDown() ); - } - } - else if ( XToEdgeOfCol(x) < 0 && - YToEdgeOfRow(y) < 0 ) - { - DisableCellEditControl(); - MakeCellVisible( coords ); - - if ( event.CmdDown() ) - { - if ( m_selection ) - { - m_selection->ToggleCellSelection( coords.GetRow(), - coords.GetCol(), - event.ControlDown(), - event.ShiftDown(), - event.AltDown(), - event.MetaDown() ); - } - m_selectingTopLeft = wxGridNoCellCoords; - m_selectingBottomRight = wxGridNoCellCoords; - m_selectingKeyboard = coords; - } - else - { - m_waitForSlowClick = m_currentCellCoords == coords && coords != wxGridNoCellCoords; - SetCurrentCell( coords ); - if ( m_selection ) - { - if ( m_selection->GetSelectionMode() != - wxGrid::wxGridSelectCells ) - { - HighlightBlock( coords, coords ); - } - } - } - } - } - } - - // ------------ Left double click - // - else if ( event.LeftDClick() && coords != wxGridNoCellCoords ) - { - DisableCellEditControl(); - - if ( XToEdgeOfCol(x) < 0 && YToEdgeOfRow(y) < 0 ) - { - if ( !SendEvent( wxEVT_GRID_CELL_LEFT_DCLICK, - coords.GetRow(), - coords.GetCol(), - event ) ) - { - // we want double click to select a cell and start editing - // (i.e. to behave in same way as sequence of two slow clicks): - m_waitForSlowClick = true; - } - } - } - - // ------------ Left button released - // - else if ( event.LeftUp() ) - { - if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL ) - { - if (m_winCapture) - { - if (m_winCapture->HasCapture()) - m_winCapture->ReleaseMouse(); - m_winCapture = NULL; - } - - if ( coords == m_currentCellCoords && m_waitForSlowClick && CanEnableCellControl() ) - { - ClearSelection(); - EnableCellEditControl(); - - wxGridCellAttr *attr = GetCellAttr(coords); - wxGridCellEditor *editor = attr->GetEditor(this, coords.GetRow(), coords.GetCol()); - editor->StartingClick(); - editor->DecRef(); - attr->DecRef(); - - m_waitForSlowClick = false; - } - else if ( m_selectingTopLeft != wxGridNoCellCoords && - m_selectingBottomRight != wxGridNoCellCoords ) - { - if ( m_selection ) - { - m_selection->SelectBlock( m_selectingTopLeft.GetRow(), - m_selectingTopLeft.GetCol(), - m_selectingBottomRight.GetRow(), - m_selectingBottomRight.GetCol(), - event.ControlDown(), - event.ShiftDown(), - event.AltDown(), - event.MetaDown() ); - } - - m_selectingTopLeft = wxGridNoCellCoords; - m_selectingBottomRight = wxGridNoCellCoords; - - // Show the edit control, if it has been hidden for - // drag-shrinking. - ShowCellEditControl(); - } - } - else if ( m_cursorMode == WXGRID_CURSOR_RESIZE_ROW ) - { - ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL); - DoEndDragResizeRow(); - - // Note: we are ending the event *after* doing - // default processing in this case - // - SendEvent( wxEVT_GRID_ROW_SIZE, m_dragRowOrCol, -1, event ); - } - else if ( m_cursorMode == WXGRID_CURSOR_RESIZE_COL ) - { - ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL); - DoEndDragResizeCol(); - - // Note: we are ending the event *after* doing - // default processing in this case - // - SendEvent( wxEVT_GRID_COL_SIZE, -1, m_dragRowOrCol, event ); - } - - m_dragLastPos = -1; - } - - // ------------ Right button down - // - else if ( event.RightDown() && coords != wxGridNoCellCoords ) - { - DisableCellEditControl(); - if ( !SendEvent( wxEVT_GRID_CELL_RIGHT_CLICK, - coords.GetRow(), - coords.GetCol(), - event ) ) - { - // no default action at the moment - } - } - - // ------------ Right double click - // - else if ( event.RightDClick() && coords != wxGridNoCellCoords ) - { - DisableCellEditControl(); - if ( !SendEvent( wxEVT_GRID_CELL_RIGHT_DCLICK, - coords.GetRow(), - coords.GetCol(), - event ) ) - { - // no default action at the moment - } - } - - // ------------ Moving and no button action - // - else if ( event.Moving() && !event.IsButton() ) - { - if ( coords.GetRow() < 0 || coords.GetCol() < 0 ) - { - // out of grid cell area - ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL); - return; - } - - int dragRow = YToEdgeOfRow( y ); - int dragCol = XToEdgeOfCol( x ); - - // Dragging on the corner of a cell to resize in both - // directions is not implemented yet... - // - if ( dragRow >= 0 && dragCol >= 0 ) - { - ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL); - return; - } - - if ( dragRow >= 0 ) - { - m_dragRowOrCol = dragRow; - - if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL ) - { - if ( CanDragRowSize() && CanDragGridSize() ) - ChangeCursorMode(WXGRID_CURSOR_RESIZE_ROW, NULL, false); - } - } - else if ( dragCol >= 0 ) - { - m_dragRowOrCol = dragCol; - - if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL ) - { - if ( CanDragColSize() && CanDragGridSize() ) - ChangeCursorMode(WXGRID_CURSOR_RESIZE_COL, NULL, false); - } - } - else // Neither on a row or col edge - { - if ( m_cursorMode != WXGRID_CURSOR_SELECT_CELL ) - { - ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL); - } - } - } -} - -void wxGrid::DoEndDragResizeRow() -{ - if ( m_dragLastPos >= 0 ) - { - // erase the last line and resize the row - // - int cw, ch, left, dummy; - m_gridWin->GetClientSize( &cw, &ch ); - CalcUnscrolledPosition( 0, 0, &left, &dummy ); - - wxClientDC dc( m_gridWin ); - PrepareDC( dc ); - dc.SetLogicalFunction( wxINVERT ); - dc.DrawLine( left, m_dragLastPos, left + cw, m_dragLastPos ); - HideCellEditControl(); - SaveEditControlValue(); - - int rowTop = GetRowTop(m_dragRowOrCol); - SetRowSize( m_dragRowOrCol, - wxMax( m_dragLastPos - rowTop, m_minAcceptableRowHeight ) ); - - if ( !GetBatchCount() ) - { - // Only needed to get the correct rect.y: - wxRect rect ( CellToRect( m_dragRowOrCol, 0 ) ); - rect.x = 0; - CalcScrolledPosition(0, rect.y, &dummy, &rect.y); - rect.width = m_rowLabelWidth; - rect.height = ch - rect.y; - m_rowLabelWin->Refresh( true, &rect ); - rect.width = cw; - - // if there is a multicell block, paint all of it - if (m_table) - { - int i, cell_rows, cell_cols, subtract_rows = 0; - int leftCol = XToCol(left); - int rightCol = internalXToCol(left + cw); - if (leftCol >= 0) - { - for (i=leftCol; iRefresh( false, &rect ); - } - - ShowCellEditControl(); - } -} - - -void wxGrid::DoEndDragResizeCol() -{ - if ( m_dragLastPos >= 0 ) - { - // erase the last line and resize the col - // - int cw, ch, dummy, top; - m_gridWin->GetClientSize( &cw, &ch ); - CalcUnscrolledPosition( 0, 0, &dummy, &top ); - - wxClientDC dc( m_gridWin ); - PrepareDC( dc ); - dc.SetLogicalFunction( wxINVERT ); - dc.DrawLine( m_dragLastPos, top, m_dragLastPos, top + ch ); - HideCellEditControl(); - SaveEditControlValue(); - - int colLeft = GetColLeft(m_dragRowOrCol); - SetColSize( m_dragRowOrCol, - wxMax( m_dragLastPos - colLeft, - GetColMinimalWidth(m_dragRowOrCol) ) ); - - if ( !GetBatchCount() ) - { - // Only needed to get the correct rect.x: - wxRect rect ( CellToRect( 0, m_dragRowOrCol ) ); - rect.y = 0; - CalcScrolledPosition(rect.x, 0, &rect.x, &dummy); - rect.width = cw - rect.x; - rect.height = m_colLabelHeight; - m_colLabelWin->Refresh( true, &rect ); - rect.height = ch; - - // if there is a multicell block, paint all of it - if (m_table) - { - int i, cell_rows, cell_cols, subtract_cols = 0; - int topRow = YToRow(top); - int bottomRow = internalYToRow(top + cw); - if (topRow >= 0) - { - for (i=topRow; iRefresh( false, &rect ); - } - - ShowCellEditControl(); - } -} - -void wxGrid::DoEndDragMoveCol() -{ - //The user clicked on the column but didn't actually drag - if ( m_dragLastPos < 0 ) - { - m_colLabelWin->Refresh(); //Do this to "unpress" the column - return; - } - - int newPos; - if ( m_moveToCol == -1 ) - newPos = m_numCols - 1; - else - { - newPos = GetColPos( m_moveToCol ); - if ( newPos > GetColPos( m_dragRowOrCol ) ) - newPos--; - } - - SetColPos( m_dragRowOrCol, newPos ); -} - -void wxGrid::SetColPos( int colID, int newPos ) -{ - if ( m_colAt.IsEmpty() ) - { - m_colAt.Alloc( m_numCols ); - - int i; - for ( i = 0; i < m_numCols; i++ ) - { - m_colAt.Add( i ); - } - } - - int oldPos = GetColPos( colID ); - - //Reshuffle the m_colAt array - if ( newPos > oldPos ) - { - int i; - for ( i = oldPos; i < newPos; i++ ) - { - m_colAt[i] = m_colAt[i+1]; - } - } - else - { - int i; - for ( i = oldPos; i > newPos; i-- ) - { - m_colAt[i] = m_colAt[i-1]; - } - } - - m_colAt[newPos] = colID; - - //Recalculate the column rights - if ( !m_colWidths.IsEmpty() ) - { - int colRight = 0; - int colPos; - for ( colPos = 0; colPos < m_numCols; colPos++ ) - { - int colID = GetColAt( colPos ); - - colRight += m_colWidths[colID]; - m_colRights[colID] = colRight; - } - } - - m_colLabelWin->Refresh(); - m_gridWin->Refresh(); -} - - - -void wxGrid::EnableDragColMove( bool enable ) -{ - if ( m_canDragColMove == enable ) - return; - - m_canDragColMove = enable; - - if ( !m_canDragColMove ) - { - m_colAt.Clear(); - - //Recalculate the column rights - if ( !m_colWidths.IsEmpty() ) - { - int colRight = 0; - int colPos; - for ( colPos = 0; colPos < m_numCols; colPos++ ) - { - colRight += m_colWidths[colPos]; - m_colRights[colPos] = colRight; - } - } - - m_colLabelWin->Refresh(); - m_gridWin->Refresh(); - } -} - - -// -// ------ interaction with data model -// -bool wxGrid::ProcessTableMessage( wxGridTableMessage& msg ) -{ - switch ( msg.GetId() ) - { - case wxGRIDTABLE_REQUEST_VIEW_GET_VALUES: - return GetModelValues(); - - case wxGRIDTABLE_REQUEST_VIEW_SEND_VALUES: - return SetModelValues(); - - case wxGRIDTABLE_NOTIFY_ROWS_INSERTED: - case wxGRIDTABLE_NOTIFY_ROWS_APPENDED: - case wxGRIDTABLE_NOTIFY_ROWS_DELETED: - case wxGRIDTABLE_NOTIFY_COLS_INSERTED: - case wxGRIDTABLE_NOTIFY_COLS_APPENDED: - case wxGRIDTABLE_NOTIFY_COLS_DELETED: - return Redimension( msg ); - - default: - return false; - } -} - -// The behaviour of this function depends on the grid table class -// Clear() function. For the default wxGridStringTable class the -// behavious is to replace all cell contents with wxEmptyString but -// not to change the number of rows or cols. -// -void wxGrid::ClearGrid() -{ - if ( m_table ) - { - if (IsCellEditControlEnabled()) - DisableCellEditControl(); - - m_table->Clear(); - if (!GetBatchCount()) - m_gridWin->Refresh(); - } -} - -bool wxGrid::InsertRows( int pos, int numRows, bool WXUNUSED(updateLabels) ) -{ - // TODO: something with updateLabels flag - - if ( !m_created ) - { - wxFAIL_MSG( wxT("Called wxGrid::InsertRows() before calling CreateGrid()") ); - return false; - } - - if ( m_table ) - { - if (IsCellEditControlEnabled()) - DisableCellEditControl(); - - bool done = m_table->InsertRows( pos, numRows ); - return done; - - // the table will have sent the results of the insert row - // operation to this view object as a grid table message - } - - return false; -} - -bool wxGrid::AppendRows( int numRows, bool WXUNUSED(updateLabels) ) -{ - // TODO: something with updateLabels flag - - if ( !m_created ) - { - wxFAIL_MSG( wxT("Called wxGrid::AppendRows() before calling CreateGrid()") ); - return false; - } - - if ( m_table ) - { - bool done = m_table && m_table->AppendRows( numRows ); - return done; - - // the table will have sent the results of the append row - // operation to this view object as a grid table message - } - - return false; -} - -bool wxGrid::DeleteRows( int pos, int numRows, bool WXUNUSED(updateLabels) ) -{ - // TODO: something with updateLabels flag - - if ( !m_created ) - { - wxFAIL_MSG( wxT("Called wxGrid::DeleteRows() before calling CreateGrid()") ); - return false; - } - - if ( m_table ) - { - if (IsCellEditControlEnabled()) - DisableCellEditControl(); - - bool done = m_table->DeleteRows( pos, numRows ); - return done; - // the table will have sent the results of the delete row - // operation to this view object as a grid table message - } - - return false; -} - -bool wxGrid::InsertCols( int pos, int numCols, bool WXUNUSED(updateLabels) ) -{ - // TODO: something with updateLabels flag - - if ( !m_created ) - { - wxFAIL_MSG( wxT("Called wxGrid::InsertCols() before calling CreateGrid()") ); - return false; - } - - if ( m_table ) - { - if (IsCellEditControlEnabled()) - DisableCellEditControl(); - - bool done = m_table->InsertCols( pos, numCols ); - return done; - // the table will have sent the results of the insert col - // operation to this view object as a grid table message - } - - return false; -} - -bool wxGrid::AppendCols( int numCols, bool WXUNUSED(updateLabels) ) -{ - // TODO: something with updateLabels flag - - if ( !m_created ) - { - wxFAIL_MSG( wxT("Called wxGrid::AppendCols() before calling CreateGrid()") ); - return false; - } - - if ( m_table ) - { - bool done = m_table->AppendCols( numCols ); - return done; - // the table will have sent the results of the append col - // operation to this view object as a grid table message - } - - return false; -} - -bool wxGrid::DeleteCols( int pos, int numCols, bool WXUNUSED(updateLabels) ) -{ - // TODO: something with updateLabels flag - - if ( !m_created ) - { - wxFAIL_MSG( wxT("Called wxGrid::DeleteCols() before calling CreateGrid()") ); - return false; - } - - if ( m_table ) - { - if (IsCellEditControlEnabled()) - DisableCellEditControl(); - - bool done = m_table->DeleteCols( pos, numCols ); - return done; - // the table will have sent the results of the delete col - // operation to this view object as a grid table message - } - - return false; -} - -// -// ----- event handlers -// - -// Generate a grid event based on a mouse event and -// return the result of ProcessEvent() -// -int wxGrid::SendEvent( const wxEventType type, - int row, int col, - wxMouseEvent& mouseEv ) -{ - bool claimed, vetoed; - - if ( type == wxEVT_GRID_ROW_SIZE || type == wxEVT_GRID_COL_SIZE ) - { - int rowOrCol = (row == -1 ? col : row); - - wxGridSizeEvent gridEvt( GetId(), - type, - this, - rowOrCol, - mouseEv.GetX() + GetRowLabelSize(), - mouseEv.GetY() + GetColLabelSize(), - mouseEv.ControlDown(), - mouseEv.ShiftDown(), - mouseEv.AltDown(), - mouseEv.MetaDown() ); - - claimed = GetEventHandler()->ProcessEvent(gridEvt); - vetoed = !gridEvt.IsAllowed(); - } - else if ( type == wxEVT_GRID_RANGE_SELECT ) - { - // Right now, it should _never_ end up here! - wxGridRangeSelectEvent gridEvt( GetId(), - type, - this, - m_selectingTopLeft, - m_selectingBottomRight, - true, - mouseEv.ControlDown(), - mouseEv.ShiftDown(), - mouseEv.AltDown(), - mouseEv.MetaDown() ); - - claimed = GetEventHandler()->ProcessEvent(gridEvt); - vetoed = !gridEvt.IsAllowed(); - } - else if ( type == wxEVT_GRID_LABEL_LEFT_CLICK || - type == wxEVT_GRID_LABEL_LEFT_DCLICK || - type == wxEVT_GRID_LABEL_RIGHT_CLICK || - type == wxEVT_GRID_LABEL_RIGHT_DCLICK ) - { - wxPoint pos = mouseEv.GetPosition(); - - if ( mouseEv.GetEventObject() == GetGridRowLabelWindow() ) - pos.y += GetColLabelSize(); - if ( mouseEv.GetEventObject() == GetGridColLabelWindow() ) - pos.x += GetRowLabelSize(); - - wxGridEvent gridEvt( GetId(), - type, - this, - row, col, - pos.x, - pos.y, - false, - mouseEv.ControlDown(), - mouseEv.ShiftDown(), - mouseEv.AltDown(), - mouseEv.MetaDown() ); - claimed = GetEventHandler()->ProcessEvent(gridEvt); - vetoed = !gridEvt.IsAllowed(); - } - else - { - wxGridEvent gridEvt( GetId(), - type, - this, - row, col, - mouseEv.GetX() + GetRowLabelSize(), - mouseEv.GetY() + GetColLabelSize(), - false, - mouseEv.ControlDown(), - mouseEv.ShiftDown(), - mouseEv.AltDown(), - mouseEv.MetaDown() ); - claimed = GetEventHandler()->ProcessEvent(gridEvt); - vetoed = !gridEvt.IsAllowed(); - } - - // A Veto'd event may not be `claimed' so test this first - if (vetoed) - return -1; - - return claimed ? 1 : 0; -} - -// Generate a grid event of specified type and return the result -// of ProcessEvent(). -// -int wxGrid::SendEvent( const wxEventType type, - int row, int col ) -{ - bool claimed, vetoed; - - if ( type == wxEVT_GRID_ROW_SIZE || type == wxEVT_GRID_COL_SIZE ) - { - int rowOrCol = (row == -1 ? col : row); - - wxGridSizeEvent gridEvt( GetId(), type, this, rowOrCol ); - - claimed = GetEventHandler()->ProcessEvent(gridEvt); - vetoed = !gridEvt.IsAllowed(); - } - else - { - wxGridEvent gridEvt( GetId(), type, this, row, col ); - - claimed = GetEventHandler()->ProcessEvent(gridEvt); - vetoed = !gridEvt.IsAllowed(); - } - - // A Veto'd event may not be `claimed' so test this first - if (vetoed) - return -1; - - return claimed ? 1 : 0; -} - -void wxGrid::OnPaint( wxPaintEvent& WXUNUSED(event) ) -{ - // needed to prevent zillions of paint events on MSW - wxPaintDC dc(this); -} - -void wxGrid::Refresh(bool eraseb, const wxRect* rect) -{ - // Don't do anything if between Begin/EndBatch... - // EndBatch() will do all this on the last nested one anyway. - if (! GetBatchCount()) - { - // Refresh to get correct scrolled position: - wxScrolledWindow::Refresh(eraseb, rect); - - if (rect) - { - int rect_x, rect_y, rectWidth, rectHeight; - int width_label, width_cell, height_label, height_cell; - int x, y; - - // Copy rectangle can get scroll offsets.. - rect_x = rect->GetX(); - rect_y = rect->GetY(); - rectWidth = rect->GetWidth(); - rectHeight = rect->GetHeight(); - - width_label = m_rowLabelWidth - rect_x; - if (width_label > rectWidth) - width_label = rectWidth; - - height_label = m_colLabelHeight - rect_y; - if (height_label > rectHeight) - height_label = rectHeight; - - if (rect_x > m_rowLabelWidth) - { - x = rect_x - m_rowLabelWidth; - width_cell = rectWidth; - } - else - { - x = 0; - width_cell = rectWidth - (m_rowLabelWidth - rect_x); - } - - if (rect_y > m_colLabelHeight) - { - y = rect_y - m_colLabelHeight; - height_cell = rectHeight; - } - else - { - y = 0; - height_cell = rectHeight - (m_colLabelHeight - rect_y); - } - - // Paint corner label part intersecting rect. - if ( width_label > 0 && height_label > 0 ) - { - wxRect anotherrect(rect_x, rect_y, width_label, height_label); - m_cornerLabelWin->Refresh(eraseb, &anotherrect); - } - - // Paint col labels part intersecting rect. - if ( width_cell > 0 && height_label > 0 ) - { - wxRect anotherrect(x, rect_y, width_cell, height_label); - m_colLabelWin->Refresh(eraseb, &anotherrect); - } - - // Paint row labels part intersecting rect. - if ( width_label > 0 && height_cell > 0 ) - { - wxRect anotherrect(rect_x, y, width_label, height_cell); - m_rowLabelWin->Refresh(eraseb, &anotherrect); - } - - // Paint cell area part intersecting rect. - if ( width_cell > 0 && height_cell > 0 ) - { - wxRect anotherrect(x, y, width_cell, height_cell); - m_gridWin->Refresh(eraseb, &anotherrect); - } - } - else - { - m_cornerLabelWin->Refresh(eraseb, NULL); - m_colLabelWin->Refresh(eraseb, NULL); - m_rowLabelWin->Refresh(eraseb, NULL); - m_gridWin->Refresh(eraseb, NULL); - } - } -} - -void wxGrid::OnSize( wxSizeEvent& WXUNUSED(event) ) -{ - if (m_targetWindow != this) // check whether initialisation has been done - { - // update our children window positions and scrollbars - CalcDimensions(); - } -} - -void wxGrid::OnKeyDown( wxKeyEvent& event ) -{ - if ( m_inOnKeyDown ) - { - // shouldn't be here - we are going round in circles... - // - wxFAIL_MSG( wxT("wxGrid::OnKeyDown called while already active") ); - } - - m_inOnKeyDown = true; - - // propagate the event up and see if it gets processed - wxWindow *parent = GetParent(); - wxKeyEvent keyEvt( event ); - keyEvt.SetEventObject( parent ); - - if ( !parent->GetEventHandler()->ProcessEvent( keyEvt ) ) - { - if (GetLayoutDirection() == wxLayout_RightToLeft) - { - if (event.GetKeyCode() == WXK_RIGHT) - event.m_keyCode = WXK_LEFT; - else if (event.GetKeyCode() == WXK_LEFT) - event.m_keyCode = WXK_RIGHT; - } - - // try local handlers - switch ( event.GetKeyCode() ) - { - case WXK_UP: - if ( event.ControlDown() ) - MoveCursorUpBlock( event.ShiftDown() ); - else - MoveCursorUp( event.ShiftDown() ); - break; - - case WXK_DOWN: - if ( event.ControlDown() ) - MoveCursorDownBlock( event.ShiftDown() ); - else - MoveCursorDown( event.ShiftDown() ); - break; - - case WXK_LEFT: - if ( event.ControlDown() ) - MoveCursorLeftBlock( event.ShiftDown() ); - else - MoveCursorLeft( event.ShiftDown() ); - break; - - case WXK_RIGHT: - if ( event.ControlDown() ) - MoveCursorRightBlock( event.ShiftDown() ); - else - MoveCursorRight( event.ShiftDown() ); - break; - - case WXK_RETURN: - case WXK_NUMPAD_ENTER: - if ( event.ControlDown() ) - { - event.Skip(); // to let the edit control have the return - } - else - { - if ( GetGridCursorRow() < GetNumberRows()-1 ) - { - MoveCursorDown( event.ShiftDown() ); - } - else - { - // at the bottom of a column - DisableCellEditControl(); - } - } - break; - - case WXK_ESCAPE: - ClearSelection(); - break; - - case WXK_TAB: - if (event.ShiftDown()) - { - if ( GetGridCursorCol() > 0 ) - { - MoveCursorLeft( false ); - } - else - { - // at left of grid - DisableCellEditControl(); - } - } - else - { - if ( GetGridCursorCol() < GetNumberCols() - 1 ) - { - MoveCursorRight( false ); - } - else - { - // at right of grid - DisableCellEditControl(); - } - } - break; - - case WXK_HOME: - if ( event.ControlDown() ) - { - MakeCellVisible( 0, 0 ); - SetCurrentCell( 0, 0 ); - } - else - { - event.Skip(); - } - break; - - case WXK_END: - if ( event.ControlDown() ) - { - MakeCellVisible( m_numRows - 1, m_numCols - 1 ); - SetCurrentCell( m_numRows - 1, m_numCols - 1 ); - } - else - { - event.Skip(); - } - break; - - case WXK_PAGEUP: - MovePageUp(); - break; - - case WXK_PAGEDOWN: - MovePageDown(); - break; - - case WXK_SPACE: - if ( event.ControlDown() ) - { - if ( m_selection ) - { - m_selection->ToggleCellSelection( - m_currentCellCoords.GetRow(), - m_currentCellCoords.GetCol(), - event.ControlDown(), - event.ShiftDown(), - event.AltDown(), - event.MetaDown() ); - } - break; - } - - if ( !IsEditable() ) - MoveCursorRight( false ); - else - event.Skip(); - break; - - default: - event.Skip(); - break; - } - } - - m_inOnKeyDown = false; -} - -void wxGrid::OnKeyUp( wxKeyEvent& event ) -{ - // try local handlers - // - if ( event.GetKeyCode() == WXK_SHIFT ) - { - if ( m_selectingTopLeft != wxGridNoCellCoords && - m_selectingBottomRight != wxGridNoCellCoords ) - { - if ( m_selection ) - { - m_selection->SelectBlock( - m_selectingTopLeft.GetRow(), - m_selectingTopLeft.GetCol(), - m_selectingBottomRight.GetRow(), - m_selectingBottomRight.GetCol(), - event.ControlDown(), - true, - event.AltDown(), - event.MetaDown() ); - } - } - - m_selectingTopLeft = wxGridNoCellCoords; - m_selectingBottomRight = wxGridNoCellCoords; - m_selectingKeyboard = wxGridNoCellCoords; - } -} - -void wxGrid::OnChar( wxKeyEvent& event ) -{ - // is it possible to edit the current cell at all? - if ( !IsCellEditControlEnabled() && CanEnableCellControl() ) - { - // yes, now check whether the cells editor accepts the key - int row = m_currentCellCoords.GetRow(); - int col = m_currentCellCoords.GetCol(); - wxGridCellAttr *attr = GetCellAttr(row, col); - wxGridCellEditor *editor = attr->GetEditor(this, row, col); - - // is special and will always start editing, for - // other keys - ask the editor itself - if ( (event.GetKeyCode() == WXK_F2 && !event.HasModifiers()) - || editor->IsAcceptedKey(event) ) - { - // ensure cell is visble - MakeCellVisible(row, col); - EnableCellEditControl(); - - // a problem can arise if the cell is not completely - // visible (even after calling MakeCellVisible the - // control is not created and calling StartingKey will - // crash the app - if ( event.GetKeyCode() != WXK_F2 && editor->IsCreated() && m_cellEditCtrlEnabled ) - editor->StartingKey(event); - } - else - { - event.Skip(); - } - - editor->DecRef(); - attr->DecRef(); - } - else - { - event.Skip(); - } -} - -void wxGrid::OnEraseBackground(wxEraseEvent&) -{ -} - -void wxGrid::SetCurrentCell( const wxGridCellCoords& coords ) -{ - if ( SendEvent( wxEVT_GRID_SELECT_CELL, coords.GetRow(), coords.GetCol() ) ) - { - // the event has been intercepted - do nothing - return; - } - -#if !(defined(__WXMAC__) && wxMAC_USE_CORE_GRAPHICS) - wxClientDC dc( m_gridWin ); - PrepareDC( dc ); -#endif - - if ( m_currentCellCoords != wxGridNoCellCoords ) - { - DisableCellEditControl(); - - if ( IsVisible( m_currentCellCoords, false ) ) - { - wxRect r; - r = BlockToDeviceRect( m_currentCellCoords, m_currentCellCoords ); - if ( !m_gridLinesEnabled ) - { - r.x--; - r.y--; - r.width++; - r.height++; - } - - wxGridCellCoordsArray cells = CalcCellsExposed( r ); - - // Otherwise refresh redraws the highlight! - m_currentCellCoords = coords; - -#if defined(__WXMAC__) && wxMAC_USE_CORE_GRAPHICS - m_gridWin->Refresh(true /*, & r */); -#else - DrawGridCellArea( dc, cells ); - DrawAllGridLines( dc, r ); -#endif - } - } - - m_currentCellCoords = coords; - - wxGridCellAttr *attr = GetCellAttr( coords ); -#if !(defined(__WXMAC__) && wxMAC_USE_CORE_GRAPHICS) - DrawCellHighlight( dc, attr ); -#endif - attr->DecRef(); -} - -void wxGrid::HighlightBlock( int topRow, int leftCol, int bottomRow, int rightCol ) -{ - int temp; - wxGridCellCoords updateTopLeft, updateBottomRight; - - if ( m_selection ) - { - if ( m_selection->GetSelectionMode() == wxGrid::wxGridSelectRows ) - { - leftCol = 0; - rightCol = GetNumberCols() - 1; - } - else if ( m_selection->GetSelectionMode() == wxGrid::wxGridSelectColumns ) - { - topRow = 0; - bottomRow = GetNumberRows() - 1; - } - } - - if ( topRow > bottomRow ) - { - temp = topRow; - topRow = bottomRow; - bottomRow = temp; - } - - if ( leftCol > rightCol ) - { - temp = leftCol; - leftCol = rightCol; - rightCol = temp; - } - - updateTopLeft = wxGridCellCoords( topRow, leftCol ); - updateBottomRight = wxGridCellCoords( bottomRow, rightCol ); - - // First the case that we selected a completely new area - if ( m_selectingTopLeft == wxGridNoCellCoords || - m_selectingBottomRight == wxGridNoCellCoords ) - { - wxRect rect; - rect = BlockToDeviceRect( wxGridCellCoords ( topRow, leftCol ), - wxGridCellCoords ( bottomRow, rightCol ) ); - m_gridWin->Refresh( false, &rect ); - } - - // Now handle changing an existing selection area. - else if ( m_selectingTopLeft != updateTopLeft || - m_selectingBottomRight != updateBottomRight ) - { - // Compute two optimal update rectangles: - // Either one rectangle is a real subset of the - // other, or they are (almost) disjoint! - wxRect rect[4]; - bool need_refresh[4]; - need_refresh[0] = - need_refresh[1] = - need_refresh[2] = - need_refresh[3] = false; - int i; - - // Store intermediate values - wxCoord oldLeft = m_selectingTopLeft.GetCol(); - wxCoord oldTop = m_selectingTopLeft.GetRow(); - wxCoord oldRight = m_selectingBottomRight.GetCol(); - wxCoord oldBottom = m_selectingBottomRight.GetRow(); - - // Determine the outer/inner coordinates. - if (oldLeft > leftCol) - { - temp = oldLeft; - oldLeft = leftCol; - leftCol = temp; - } - if (oldTop > topRow ) - { - temp = oldTop; - oldTop = topRow; - topRow = temp; - } - if (oldRight < rightCol ) - { - temp = oldRight; - oldRight = rightCol; - rightCol = temp; - } - if (oldBottom < bottomRow) - { - temp = oldBottom; - oldBottom = bottomRow; - bottomRow = temp; - } - - // Now, either the stuff marked old is the outer - // rectangle or we don't have a situation where one - // is contained in the other. - - if ( oldLeft < leftCol ) - { - // Refresh the newly selected or deselected - // area to the left of the old or new selection. - need_refresh[0] = true; - rect[0] = BlockToDeviceRect( - wxGridCellCoords( oldTop, oldLeft ), - wxGridCellCoords( oldBottom, leftCol - 1 ) ); - } - - if ( oldTop < topRow ) - { - // Refresh the newly selected or deselected - // area above the old or new selection. - need_refresh[1] = true; - rect[1] = BlockToDeviceRect( - wxGridCellCoords( oldTop, leftCol ), - wxGridCellCoords( topRow - 1, rightCol ) ); - } - - if ( oldRight > rightCol ) - { - // Refresh the newly selected or deselected - // area to the right of the old or new selection. - need_refresh[2] = true; - rect[2] = BlockToDeviceRect( - wxGridCellCoords( oldTop, rightCol + 1 ), - wxGridCellCoords( oldBottom, oldRight ) ); - } - - if ( oldBottom > bottomRow ) - { - // Refresh the newly selected or deselected - // area below the old or new selection. - need_refresh[3] = true; - rect[3] = BlockToDeviceRect( - wxGridCellCoords( bottomRow + 1, leftCol ), - wxGridCellCoords( oldBottom, rightCol ) ); - } - - // various Refresh() calls - for (i = 0; i < 4; i++ ) - if ( need_refresh[i] && rect[i] != wxGridNoCellRect ) - m_gridWin->Refresh( false, &(rect[i]) ); - } - - // change selection - m_selectingTopLeft = updateTopLeft; - m_selectingBottomRight = updateBottomRight; -} - -// -// ------ functions to get/send data (see also public functions) -// - -bool wxGrid::GetModelValues() -{ - // Hide the editor, so it won't hide a changed value. - HideCellEditControl(); - - if ( m_table ) - { - // all we need to do is repaint the grid - // - m_gridWin->Refresh(); - return true; - } - - return false; -} - -bool wxGrid::SetModelValues() -{ - int row, col; - - // Disable the editor, so it won't hide a changed value. - // Do we also want to save the current value of the editor first? - // I think so ... - DisableCellEditControl(); - - if ( m_table ) - { - for ( row = 0; row < m_numRows; row++ ) - { - for ( col = 0; col < m_numCols; col++ ) - { - m_table->SetValue( row, col, GetCellValue(row, col) ); - } - } - - return true; - } - - return false; -} - -// Note - this function only draws cells that are in the list of -// exposed cells (usually set from the update region by -// CalcExposedCells) -// -void wxGrid::DrawGridCellArea( wxDC& dc, const wxGridCellCoordsArray& cells ) -{ - if ( !m_numRows || !m_numCols ) - return; - - int i, numCells = cells.GetCount(); - int row, col, cell_rows, cell_cols; - wxGridCellCoordsArray redrawCells; - - for ( i = numCells - 1; i >= 0; i-- ) - { - row = cells[i].GetRow(); - col = cells[i].GetCol(); - GetCellSize( row, col, &cell_rows, &cell_cols ); - - // If this cell is part of a multicell block, find owner for repaint - if ( cell_rows <= 0 || cell_cols <= 0 ) - { - wxGridCellCoords cell( row + cell_rows, col + cell_cols ); - bool marked = false; - for ( int j = 0; j < numCells; j++ ) - { - if ( cell == cells[j] ) - { - marked = true; - break; - } - } - - if (!marked) - { - int count = redrawCells.GetCount(); - for (int j = 0; j < count; j++) - { - if ( cell == redrawCells[j] ) - { - marked = true; - break; - } - } - - if (!marked) - redrawCells.Add( cell ); - } - - // don't bother drawing this cell - continue; - } - - // If this cell is empty, find cell to left that might want to overflow - if (m_table && m_table->IsEmptyCell(row, col)) - { - for ( int l = 0; l < cell_rows; l++ ) - { - // find a cell in this row to leave already marked for repaint - int left = col; - for (int k = 0; k < int(redrawCells.GetCount()); k++) - if ((redrawCells[k].GetCol() < left) && - (redrawCells[k].GetRow() == row)) - { - left = redrawCells[k].GetCol(); - } - - if (left == col) - left = 0; // oh well - - for (int j = col - 1; j >= left; j--) - { - if (!m_table->IsEmptyCell(row + l, j)) - { - if (GetCellOverflow(row + l, j)) - { - wxGridCellCoords cell(row + l, j); - bool marked = false; - - for (int k = 0; k < numCells; k++) - { - if ( cell == cells[k] ) - { - marked = true; - break; - } - } - - if (!marked) - { - int count = redrawCells.GetCount(); - for (int k = 0; k < count; k++) - { - if ( cell == redrawCells[k] ) - { - marked = true; - break; - } - } - if (!marked) - redrawCells.Add( cell ); - } - } - break; - } - } - } - } - - DrawCell( dc, cells[i] ); - } - - numCells = redrawCells.GetCount(); - - for ( i = numCells - 1; i >= 0; i-- ) - { - DrawCell( dc, redrawCells[i] ); - } -} - -void wxGrid::DrawGridSpace( wxDC& dc ) -{ - int cw, ch; - m_gridWin->GetClientSize( &cw, &ch ); - - int right, bottom; - CalcUnscrolledPosition( cw, ch, &right, &bottom ); - - int rightCol = m_numCols > 0 ? GetColRight(GetColAt( m_numCols - 1 )) : 0; - int bottomRow = m_numRows > 0 ? GetRowBottom(m_numRows - 1) : 0; - - if ( right > rightCol || bottom > bottomRow ) - { - int left, top; - CalcUnscrolledPosition( 0, 0, &left, &top ); - - dc.SetBrush( wxBrush(GetDefaultCellBackgroundColour(), wxSOLID) ); - dc.SetPen( *wxTRANSPARENT_PEN ); - - if ( right > rightCol ) - { - dc.DrawRectangle( rightCol, top, right - rightCol, ch ); - } - - if ( bottom > bottomRow ) - { - dc.DrawRectangle( left, bottomRow, cw, bottom - bottomRow ); - } - } -} - -void wxGrid::DrawCell( wxDC& dc, const wxGridCellCoords& coords ) -{ - int row = coords.GetRow(); - int col = coords.GetCol(); - - if ( GetColWidth(col) <= 0 || GetRowHeight(row) <= 0 ) - return; - - // we draw the cell border ourselves -#if !WXGRID_DRAW_LINES - if ( m_gridLinesEnabled ) - DrawCellBorder( dc, coords ); -#endif - - wxGridCellAttr* attr = GetCellAttr(row, col); - - bool isCurrent = coords == m_currentCellCoords; - - wxRect rect = CellToRect( row, col ); - - // if the editor is shown, we should use it and not the renderer - // Note: However, only if it is really _shown_, i.e. not hidden! - if ( isCurrent && IsCellEditControlShown() ) - { - // NB: this "#if..." is temporary and fixes a problem where the - // edit control is erased by this code after being rendered. - // On wxMac (QD build only), the cell editor is a wxTextCntl and is rendered - // implicitly, causing this out-of order render. -#if !defined(__WXMAC__) - wxGridCellEditor *editor = attr->GetEditor(this, row, col); - editor->PaintBackground(rect, attr); - editor->DecRef(); -#endif - } - else - { - // but all the rest is drawn by the cell renderer and hence may be customized - wxGridCellRenderer *renderer = attr->GetRenderer(this, row, col); - renderer->Draw(*this, *attr, dc, rect, row, col, IsInSelection(coords)); - renderer->DecRef(); - } - - attr->DecRef(); -} - -void wxGrid::DrawCellHighlight( wxDC& dc, const wxGridCellAttr *attr ) -{ - // don't show highlight when the grid doesn't have focus - if ( wxWindow::FindFocus() != m_gridWin ) - return; - - int row = m_currentCellCoords.GetRow(); - int col = m_currentCellCoords.GetCol(); - - if ( GetColWidth(col) <= 0 || GetRowHeight(row) <= 0 ) - return; - - wxRect rect = CellToRect(row, col); - - // hmmm... what could we do here to show that the cell is disabled? - // for now, I just draw a thinner border than for the other ones, but - // it doesn't look really good - - int penWidth = attr->IsReadOnly() ? m_cellHighlightROPenWidth : m_cellHighlightPenWidth; - - if (penWidth > 0) - { - // The center of the drawn line is where the position/width/height of - // the rectangle is actually at (on wxMSW at least), so the - // size of the rectangle is reduced to compensate for the thickness of - // the line. If this is too strange on non-wxMSW platforms then - // please #ifdef this appropriately. - rect.x += penWidth / 2; - rect.y += penWidth / 2; - rect.width -= penWidth - 1; - rect.height -= penWidth - 1; - - // Now draw the rectangle - // use the cellHighlightColour if the cell is inside a selection, this - // will ensure the cell is always visible. - dc.SetPen(wxPen(IsInSelection(row,col) ? m_selectionForeground : m_cellHighlightColour, penWidth, wxSOLID)); - dc.SetBrush(*wxTRANSPARENT_BRUSH); - dc.DrawRectangle(rect); - } - -#if 0 - // VZ: my experiments with 3D borders... - - // how to properly set colours for arbitrary bg? - wxCoord x1 = rect.x, - y1 = rect.y, - x2 = rect.x + rect.width - 1, - y2 = rect.y + rect.height - 1; - - dc.SetPen(*wxWHITE_PEN); - dc.DrawLine(x1, y1, x2, y1); - dc.DrawLine(x1, y1, x1, y2); - - dc.DrawLine(x1 + 1, y2 - 1, x2 - 1, y2 - 1); - dc.DrawLine(x2 - 1, y1 + 1, x2 - 1, y2); - - dc.SetPen(*wxBLACK_PEN); - dc.DrawLine(x1, y2, x2, y2); - dc.DrawLine(x2, y1, x2, y2 + 1); -#endif -} - -wxPen wxGrid::GetDefaultGridLinePen() -{ - return wxPen(GetGridLineColour(), 1, wxSOLID); -} - -wxPen wxGrid::GetRowGridLinePen(int WXUNUSED(row)) -{ - return GetDefaultGridLinePen(); -} - -wxPen wxGrid::GetColGridLinePen(int WXUNUSED(col)) -{ - return GetDefaultGridLinePen(); -} - -void wxGrid::DrawCellBorder( wxDC& dc, const wxGridCellCoords& coords ) -{ - int row = coords.GetRow(); - int col = coords.GetCol(); - if ( GetColWidth(col) <= 0 || GetRowHeight(row) <= 0 ) - return; - - - wxRect rect = CellToRect( row, col ); - - // right hand border - dc.SetPen( GetColGridLinePen(col) ); - dc.DrawLine( rect.x + rect.width, rect.y, - rect.x + rect.width, rect.y + rect.height + 1 ); - - // bottom border - dc.SetPen( GetRowGridLinePen(row) ); - dc.DrawLine( rect.x, rect.y + rect.height, - rect.x + rect.width, rect.y + rect.height); -} - -void wxGrid::DrawHighlight(wxDC& dc, const wxGridCellCoordsArray& cells) -{ - // This if block was previously in wxGrid::OnPaint but that doesn't - // seem to get called under wxGTK - MB - // - if ( m_currentCellCoords == wxGridNoCellCoords && - m_numRows && m_numCols ) - { - m_currentCellCoords.Set(0, 0); - } - - if ( IsCellEditControlShown() ) - { - // don't show highlight when the edit control is shown - return; - } - - // if the active cell was repainted, repaint its highlight too because it - // might have been damaged by the grid lines - size_t count = cells.GetCount(); - for ( size_t n = 0; n < count; n++ ) - { - if ( cells[n] == m_currentCellCoords ) - { - wxGridCellAttr* attr = GetCellAttr(m_currentCellCoords); - DrawCellHighlight(dc, attr); - attr->DecRef(); - - break; - } - } -} - -// TODO: remove this ??? -// This is used to redraw all grid lines e.g. when the grid line colour -// has been changed -// -void wxGrid::DrawAllGridLines( wxDC& dc, const wxRegion & WXUNUSED(reg) ) -{ -#if !WXGRID_DRAW_LINES - return; -#endif - - if ( !m_gridLinesEnabled || !m_numRows || !m_numCols ) - return; - - int top, bottom, left, right; - -#if 0 //#ifndef __WXGTK__ - if (reg.IsEmpty()) - { - int cw, ch; - m_gridWin->GetClientSize(&cw, &ch); - - // virtual coords of visible area - // - CalcUnscrolledPosition( 0, 0, &left, &top ); - CalcUnscrolledPosition( cw, ch, &right, &bottom ); - } - else - { - wxCoord x, y, w, h; - reg.GetBox(x, y, w, h); - CalcUnscrolledPosition( x, y, &left, &top ); - CalcUnscrolledPosition( x + w, y + h, &right, &bottom ); - } -#else - int cw, ch; - m_gridWin->GetClientSize(&cw, &ch); - CalcUnscrolledPosition( 0, 0, &left, &top ); - CalcUnscrolledPosition( cw, ch, &right, &bottom ); -#endif - - // avoid drawing grid lines past the last row and col - // - right = wxMin( right, GetColRight(GetColAt( m_numCols - 1 )) ); - bottom = wxMin( bottom, GetRowBottom(m_numRows - 1) ); - - // no gridlines inside multicells, clip them out - int leftCol = GetColPos( internalXToCol(left) ); - int topRow = internalYToRow(top); - int rightCol = GetColPos( internalXToCol(right) ); - int bottomRow = internalYToRow(bottom); - -#if !defined(__WXMAC__) || wxMAC_USE_CORE_GRAPHICS - wxRegion clippedcells(0, 0, cw, ch); - - int i, j, cell_rows, cell_cols; - wxRect rect; - - for (j=topRow; j<=bottomRow; j++) - { - int colPos; - for (colPos=leftCol; colPos<=rightCol; colPos++) - { - i = GetColAt( colPos ); - - GetCellSize( j, i, &cell_rows, &cell_cols ); - if ((cell_rows > 1) || (cell_cols > 1)) - { - rect = CellToRect(j,i); - CalcScrolledPosition( rect.x, rect.y, &rect.x, &rect.y ); - clippedcells.Subtract(rect); - } - else if ((cell_rows < 0) || (cell_cols < 0)) - { - rect = CellToRect(j + cell_rows, i + cell_cols); - CalcScrolledPosition( rect.x, rect.y, &rect.x, &rect.y ); - clippedcells.Subtract(rect); - } - } - } -#else - wxRegion clippedcells( left, top, right - left, bottom - top ); - - int i, j, cell_rows, cell_cols; - wxRect rect; - - for (j=topRow; j<=bottomRow; j++) - { - for (i=leftCol; i<=rightCol; i++) - { - GetCellSize( j, i, &cell_rows, &cell_cols ); - if ((cell_rows > 1) || (cell_cols > 1)) - { - rect = CellToRect(j, i); - clippedcells.Subtract(rect); - } - else if ((cell_rows < 0) || (cell_cols < 0)) - { - rect = CellToRect(j + cell_rows, i + cell_cols); - clippedcells.Subtract(rect); - } - } - } -#endif - - dc.SetClippingRegion( clippedcells ); - - - // horizontal grid lines - // - // already declared above - int i; - for ( i = internalYToRow(top); i < m_numRows; i++ ) - { - int bot = GetRowBottom(i) - 1; - - if ( bot > bottom ) - { - break; - } - - if ( bot >= top ) - { - dc.SetPen( GetRowGridLinePen(i) ); - dc.DrawLine( left, bot, right, bot ); - } - } - - // vertical grid lines - // - int colPos; - for ( colPos = leftCol; colPos < m_numCols; colPos++ ) - { - i = GetColAt( colPos ); - - int colRight = GetColRight(i); -#ifdef __WXGTK__ - if (GetLayoutDirection() != wxLayout_RightToLeft) -#endif - colRight--; - - if ( colRight > right ) - { - break; - } - - if ( colRight >= left ) - { - dc.SetPen( GetColGridLinePen(i) ); - dc.DrawLine( colRight, top, colRight, bottom ); - } - } - - dc.DestroyClippingRegion(); -} - -void wxGrid::DrawRowLabels( wxDC& dc, const wxArrayInt& rows) -{ - if ( !m_numRows ) - return; - - size_t i; - size_t numLabels = rows.GetCount(); - - for ( i = 0; i < numLabels; i++ ) - { - DrawRowLabel( dc, rows[i] ); - } -} - -void wxGrid::DrawRowLabel( wxDC& dc, int row ) -{ - if ( GetRowHeight(row) <= 0 || m_rowLabelWidth <= 0 ) - return; - - wxRect rect; - -#if 0 -def __WXGTK20__ - rect.SetX( 1 ); - rect.SetY( GetRowTop(row) + 1 ); - rect.SetWidth( m_rowLabelWidth - 2 ); - rect.SetHeight( GetRowHeight(row) - 2 ); - - CalcScrolledPosition( 0, rect.y, NULL, &rect.y ); - - wxWindowDC *win_dc = (wxWindowDC*) &dc; - - wxRendererNative::Get().DrawHeaderButton( win_dc->m_owner, dc, rect, 0 ); -#else - int rowTop = GetRowTop(row), - rowBottom = GetRowBottom(row) - 1; - - dc.SetPen( wxPen(wxSystemSettings::GetColour(wxSYS_COLOUR_3DSHADOW), 1, wxSOLID) ); - dc.DrawLine( m_rowLabelWidth - 1, rowTop, m_rowLabelWidth - 1, rowBottom ); - dc.DrawLine( 0, rowTop, 0, rowBottom ); - dc.DrawLine( 0, rowBottom, m_rowLabelWidth, rowBottom ); - - dc.SetPen( *wxWHITE_PEN ); - dc.DrawLine( 1, rowTop, 1, rowBottom ); - dc.DrawLine( 1, rowTop, m_rowLabelWidth - 1, rowTop ); -#endif - - dc.SetBackgroundMode( wxTRANSPARENT ); - dc.SetTextForeground( GetLabelTextColour() ); - dc.SetFont( GetLabelFont() ); - - int hAlign, vAlign; - GetRowLabelAlignment( &hAlign, &vAlign ); - - rect.SetX( 2 ); - rect.SetY( GetRowTop(row) + 2 ); - rect.SetWidth( m_rowLabelWidth - 4 ); - rect.SetHeight( GetRowHeight(row) - 4 ); - DrawTextRectangle( dc, GetRowLabelValue( row ), rect, hAlign, vAlign ); -} - -void wxGrid::DrawColLabels( wxDC& dc,const wxArrayInt& cols ) -{ - if ( !m_numCols ) - return; - - size_t i; - size_t numLabels = cols.GetCount(); - - for ( i = 0; i < numLabels; i++ ) - { - DrawColLabel( dc, cols[i] ); - } -} - -void wxGrid::DrawColLabel( wxDC& dc, int col ) -{ - if ( GetColWidth(col) <= 0 || m_colLabelHeight <= 0 ) - return; - - int colLeft = GetColLeft(col); - - wxRect rect; - -#if 0 -def __WXGTK20__ - rect.SetX( colLeft + 1 ); - rect.SetY( 1 ); - rect.SetWidth( GetColWidth(col) - 2 ); - rect.SetHeight( m_colLabelHeight - 2 ); - - wxWindowDC *win_dc = (wxWindowDC*) &dc; - - wxRendererNative::Get().DrawHeaderButton( win_dc->m_owner, dc, rect, 0 ); -#else - int colRight = GetColRight(col) - 1; - - dc.SetPen( wxPen(wxSystemSettings::GetColour(wxSYS_COLOUR_3DSHADOW), 1, wxSOLID) ); - dc.DrawLine( colRight, 0, colRight, m_colLabelHeight - 1 ); - dc.DrawLine( colLeft, 0, colRight, 0 ); - dc.DrawLine( colLeft, m_colLabelHeight - 1, - colRight + 1, m_colLabelHeight - 1 ); - - dc.SetPen( *wxWHITE_PEN ); - dc.DrawLine( colLeft, 1, colLeft, m_colLabelHeight - 1 ); - dc.DrawLine( colLeft, 1, colRight, 1 ); -#endif - - dc.SetBackgroundMode( wxTRANSPARENT ); - dc.SetTextForeground( GetLabelTextColour() ); - dc.SetFont( GetLabelFont() ); - - int hAlign, vAlign, orient; - GetColLabelAlignment( &hAlign, &vAlign ); - orient = GetColLabelTextOrientation(); - - rect.SetX( colLeft + 2 ); - rect.SetY( 2 ); - rect.SetWidth( GetColWidth(col) - 4 ); - rect.SetHeight( m_colLabelHeight - 4 ); - DrawTextRectangle( dc, GetColLabelValue( col ), rect, hAlign, vAlign, orient ); -} - -void wxGrid::DrawTextRectangle( wxDC& dc, - const wxString& value, - const wxRect& rect, - int horizAlign, - int vertAlign, - int textOrientation ) -{ - wxArrayString lines; - - StringToLines( value, lines ); - - // Forward to new API. - DrawTextRectangle( dc, - lines, - rect, - horizAlign, - vertAlign, - textOrientation ); -} - -// VZ: this should be replaced with wxDC::DrawLabel() to which we just have to -// add textOrientation support -void wxGrid::DrawTextRectangle(wxDC& dc, - const wxArrayString& lines, - const wxRect& rect, - int horizAlign, - int vertAlign, - int textOrientation) -{ - if ( lines.empty() ) - return; - - wxDCClipper clip(dc, rect); - - long textWidth, - textHeight; - - if ( textOrientation == wxHORIZONTAL ) - GetTextBoxSize( dc, lines, &textWidth, &textHeight ); - else - GetTextBoxSize( dc, lines, &textHeight, &textWidth ); - - int x = 0, - y = 0; - switch ( vertAlign ) - { - case wxALIGN_BOTTOM: - if ( textOrientation == wxHORIZONTAL ) - y = rect.y + (rect.height - textHeight - 1); - else - x = rect.x + rect.width - textWidth; - break; - - case wxALIGN_CENTRE: - if ( textOrientation == wxHORIZONTAL ) - y = rect.y + ((rect.height - textHeight) / 2); - else - x = rect.x + ((rect.width - textWidth) / 2); - break; - - case wxALIGN_TOP: - default: - if ( textOrientation == wxHORIZONTAL ) - y = rect.y + 1; - else - x = rect.x + 1; - break; - } - - // Align each line of a multi-line label - size_t nLines = lines.GetCount(); - for ( size_t l = 0; l < nLines; l++ ) - { - const wxString& line = lines[l]; - - if ( line.empty() ) - { - *(textOrientation == wxHORIZONTAL ? &y : &x) += dc.GetCharHeight(); - continue; - } - - long lineWidth = 0, - lineHeight = 0; - dc.GetTextExtent(line, &lineWidth, &lineHeight); - - switch ( horizAlign ) - { - case wxALIGN_RIGHT: - if ( textOrientation == wxHORIZONTAL ) - x = rect.x + (rect.width - lineWidth - 1); - else - y = rect.y + lineWidth + 1; - break; - - case wxALIGN_CENTRE: - if ( textOrientation == wxHORIZONTAL ) - x = rect.x + ((rect.width - lineWidth) / 2); - else - y = rect.y + rect.height - ((rect.height - lineWidth) / 2); - break; - - case wxALIGN_LEFT: - default: - if ( textOrientation == wxHORIZONTAL ) - x = rect.x + 1; - else - y = rect.y + rect.height - 1; - break; - } - - if ( textOrientation == wxHORIZONTAL ) - { - dc.DrawText( line, x, y ); - y += lineHeight; - } - else - { - dc.DrawRotatedText( line, x, y, 90.0 ); - x += lineHeight; - } - } -} - -// Split multi-line text up into an array of strings. -// Any existing contents of the string array are preserved. -// -void wxGrid::StringToLines( const wxString& value, wxArrayString& lines ) -{ - int startPos = 0; - int pos; - wxString eol = wxTextFile::GetEOL( wxTextFileType_Unix ); - wxString tVal = wxTextFile::Translate( value, wxTextFileType_Unix ); - - while ( startPos < (int)tVal.length() ) - { - pos = tVal.Mid(startPos).Find( eol ); - if ( pos < 0 ) - { - break; - } - else if ( pos == 0 ) - { - lines.Add( wxEmptyString ); - } - else - { - lines.Add( tVal.Mid(startPos, pos) ); - } - - startPos += pos + 1; - } - - if ( startPos < (int)tVal.length() ) - { - lines.Add( tVal.Mid( startPos ) ); - } -} - -void wxGrid::GetTextBoxSize( const wxDC& dc, - const wxArrayString& lines, - long *width, long *height ) -{ - long w = 0; - long h = 0; - long lineW = 0, lineH = 0; - - size_t i; - for ( i = 0; i < lines.GetCount(); i++ ) - { - dc.GetTextExtent( lines[i], &lineW, &lineH ); - w = wxMax( w, lineW ); - h += lineH; - } - - *width = w; - *height = h; -} - -// -// ------ Batch processing. -// -void wxGrid::EndBatch() -{ - if ( m_batchCount > 0 ) - { - m_batchCount--; - if ( !m_batchCount ) - { - CalcDimensions(); - m_rowLabelWin->Refresh(); - m_colLabelWin->Refresh(); - m_cornerLabelWin->Refresh(); - m_gridWin->Refresh(); - } - } -} - -// Use this, rather than wxWindow::Refresh(), to force an immediate -// repainting of the grid. Has no effect if you are already inside a -// BeginBatch / EndBatch block. -// -void wxGrid::ForceRefresh() -{ - BeginBatch(); - EndBatch(); -} - -bool wxGrid::Enable(bool enable) -{ - if ( !wxScrolledWindow::Enable(enable) ) - return false; - - // redraw in the new state - m_gridWin->Refresh(); - - return true; -} - -// -// ------ Edit control functions -// - -void wxGrid::EnableEditing( bool edit ) -{ - // TODO: improve this ? - // - if ( edit != m_editable ) - { - if (!edit) - EnableCellEditControl(edit); - m_editable = edit; - } -} - -void wxGrid::EnableCellEditControl( bool enable ) -{ - if (! m_editable) - return; - - if ( enable != m_cellEditCtrlEnabled ) - { - if ( enable ) - { - if (SendEvent( wxEVT_GRID_EDITOR_SHOWN) <0) - return; - - // this should be checked by the caller! - wxASSERT_MSG( CanEnableCellControl(), _T("can't enable editing for this cell!") ); - - // do it before ShowCellEditControl() - m_cellEditCtrlEnabled = enable; - - ShowCellEditControl(); - } - else - { - //FIXME:add veto support - SendEvent( wxEVT_GRID_EDITOR_HIDDEN ); - - HideCellEditControl(); - SaveEditControlValue(); - - // do it after HideCellEditControl() - m_cellEditCtrlEnabled = enable; - } - } -} - -bool wxGrid::IsCurrentCellReadOnly() const -{ - // const_cast - wxGridCellAttr* attr = ((wxGrid *)this)->GetCellAttr(m_currentCellCoords); - bool readonly = attr->IsReadOnly(); - attr->DecRef(); - - return readonly; -} - -bool wxGrid::CanEnableCellControl() const -{ - return m_editable && (m_currentCellCoords != wxGridNoCellCoords) && - !IsCurrentCellReadOnly(); -} - -bool wxGrid::IsCellEditControlEnabled() const -{ - // the cell edit control might be disable for all cells or just for the - // current one if it's read only - return m_cellEditCtrlEnabled ? !IsCurrentCellReadOnly() : false; -} - -bool wxGrid::IsCellEditControlShown() const -{ - bool isShown = false; - - if ( m_cellEditCtrlEnabled ) - { - int row = m_currentCellCoords.GetRow(); - int col = m_currentCellCoords.GetCol(); - wxGridCellAttr* attr = GetCellAttr(row, col); - wxGridCellEditor* editor = attr->GetEditor((wxGrid*) this, row, col); - attr->DecRef(); - - if ( editor ) - { - if ( editor->IsCreated() ) - { - isShown = editor->GetControl()->IsShown(); - } - - editor->DecRef(); - } - } - - return isShown; -} - -void wxGrid::ShowCellEditControl() -{ - if ( IsCellEditControlEnabled() ) - { - if ( !IsVisible( m_currentCellCoords, false ) ) - { - m_cellEditCtrlEnabled = false; - return; - } - else - { - wxRect rect = CellToRect( m_currentCellCoords ); - int row = m_currentCellCoords.GetRow(); - int col = m_currentCellCoords.GetCol(); - - // if this is part of a multicell, find owner (topleft) - int cell_rows, cell_cols; - GetCellSize( row, col, &cell_rows, &cell_cols ); - if ( cell_rows <= 0 || cell_cols <= 0 ) - { - row += cell_rows; - col += cell_cols; - m_currentCellCoords.SetRow( row ); - m_currentCellCoords.SetCol( col ); - } - - // erase the highlight and the cell contents because the editor - // might not cover the entire cell - wxClientDC dc( m_gridWin ); - PrepareDC( dc ); - wxGridCellAttr* attr = GetCellAttr(row, col); - dc.SetBrush(wxBrush(attr->GetBackgroundColour(), wxSOLID)); - dc.SetPen(*wxTRANSPARENT_PEN); - dc.DrawRectangle(rect); - - // convert to scrolled coords - CalcScrolledPosition( rect.x, rect.y, &rect.x, &rect.y ); - - int nXMove = 0; - if (rect.x < 0) - nXMove = rect.x; - - // cell is shifted by one pixel - // However, don't allow x or y to become negative - // since the SetSize() method interprets that as - // "don't change." - if (rect.x > 0) - rect.x--; - if (rect.y > 0) - rect.y--; - - wxGridCellEditor* editor = attr->GetEditor(this, row, col); - if ( !editor->IsCreated() ) - { - editor->Create(m_gridWin, wxID_ANY, - new wxGridCellEditorEvtHandler(this, editor)); - - wxGridEditorCreatedEvent evt(GetId(), - wxEVT_GRID_EDITOR_CREATED, - this, - row, - col, - editor->GetControl()); - GetEventHandler()->ProcessEvent(evt); - } - - // resize editor to overflow into righthand cells if allowed - int maxWidth = rect.width; - wxString value = GetCellValue(row, col); - if ( (value != wxEmptyString) && (attr->GetOverflow()) ) - { - int y; - GetTextExtent(value, &maxWidth, &y, NULL, NULL, &attr->GetFont()); - if (maxWidth < rect.width) - maxWidth = rect.width; - } - - int client_right = m_gridWin->GetClientSize().GetWidth(); - if (rect.x + maxWidth > client_right) - maxWidth = client_right - rect.x; - - if ((maxWidth > rect.width) && (col < m_numCols) && m_table) - { - GetCellSize( row, col, &cell_rows, &cell_cols ); - // may have changed earlier - for (int i = col + cell_cols; i < m_numCols; i++) - { - int c_rows, c_cols; - GetCellSize( row, i, &c_rows, &c_cols ); - - // looks weird going over a multicell - if (m_table->IsEmptyCell( row, i ) && - (rect.width < maxWidth) && (c_rows == 1)) - { - rect.width += GetColWidth( i ); - } - else - break; - } - - if (rect.GetRight() > client_right) - rect.SetRight( client_right - 1 ); - } - - editor->SetCellAttr( attr ); - editor->SetSize( rect ); - if (nXMove != 0) - editor->GetControl()->Move( - editor->GetControl()->GetPosition().x + nXMove, - editor->GetControl()->GetPosition().y ); - editor->Show( true, attr ); - - // recalc dimensions in case we need to - // expand the scrolled window to account for editor - CalcDimensions(); - - editor->BeginEdit(row, col, this); - editor->SetCellAttr(NULL); - - editor->DecRef(); - attr->DecRef(); - } - } -} - -void wxGrid::HideCellEditControl() -{ - if ( IsCellEditControlEnabled() ) - { - int row = m_currentCellCoords.GetRow(); - int col = m_currentCellCoords.GetCol(); - - wxGridCellAttr *attr = GetCellAttr(row, col); - wxGridCellEditor *editor = attr->GetEditor(this, row, col); - editor->Show( false ); - editor->DecRef(); - attr->DecRef(); - - m_gridWin->SetFocus(); - - // refresh whole row to the right - wxRect rect( CellToRect(row, col) ); - CalcScrolledPosition(rect.x, rect.y, &rect.x, &rect.y ); - rect.width = m_gridWin->GetClientSize().GetWidth() - rect.x; - -#ifdef __WXMAC__ - // ensure that the pixels under the focus ring get refreshed as well - rect.Inflate(10, 10); -#endif - - m_gridWin->Refresh( false, &rect ); - } -} - -void wxGrid::SaveEditControlValue() -{ - if ( IsCellEditControlEnabled() ) - { - int row = m_currentCellCoords.GetRow(); - int col = m_currentCellCoords.GetCol(); - - wxString oldval = GetCellValue(row, col); - - wxGridCellAttr* attr = GetCellAttr(row, col); - wxGridCellEditor* editor = attr->GetEditor(this, row, col); - bool changed = editor->EndEdit(row, col, this); - - editor->DecRef(); - attr->DecRef(); - - if (changed) - { - if ( SendEvent( wxEVT_GRID_CELL_CHANGE, - m_currentCellCoords.GetRow(), - m_currentCellCoords.GetCol() ) < 0 ) - { - // Event has been vetoed, set the data back. - SetCellValue(row, col, oldval); - } - } - } -} - -// -// ------ Grid location functions -// Note that all of these functions work with the logical coordinates of -// grid cells and labels so you will need to convert from device -// coordinates for mouse events etc. -// - -void wxGrid::XYToCell( int x, int y, wxGridCellCoords& coords ) -{ - int row = YToRow(y); - int col = XToCol(x); - - if ( row == -1 || col == -1 ) - { - coords = wxGridNoCellCoords; - } - else - { - coords.Set( row, col ); - } -} - -// Internal Helper function for computing row or column from some -// (unscrolled) coordinate value, using either -// m_defaultRowHeight/m_defaultColWidth or binary search on array -// of m_rowBottoms/m_ColRights to speed up the search! - -static int CoordToRowOrCol(int coord, int defaultDist, int minDist, - const wxArrayInt& BorderArray, int nMax, - bool clipToMinMax) -{ - if (coord < 0) - return clipToMinMax && (nMax > 0) ? 0 : -1; - - if (!defaultDist) - defaultDist = 1; - - size_t i_max = coord / defaultDist, - i_min = 0; - - if (BorderArray.IsEmpty()) - { - if ((int) i_max < nMax) - return i_max; - return clipToMinMax ? nMax - 1 : -1; - } - - if ( i_max >= BorderArray.GetCount()) - { - i_max = BorderArray.GetCount() - 1; - } - else - { - if ( coord >= BorderArray[i_max]) - { - i_min = i_max; - if (minDist) - i_max = coord / minDist; - else - i_max = BorderArray.GetCount() - 1; - } - - if ( i_max >= BorderArray.GetCount()) - i_max = BorderArray.GetCount() - 1; - } - - if ( coord >= BorderArray[i_max]) - return clipToMinMax ? (int)i_max : -1; - if ( coord < BorderArray[0] ) - return 0; - - while ( i_max - i_min > 0 ) - { - wxCHECK_MSG(BorderArray[i_min] <= coord && coord < BorderArray[i_max], - 0, _T("wxGrid: internal error in CoordToRowOrCol")); - if (coord >= BorderArray[ i_max - 1]) - return i_max; - else - i_max--; - int median = i_min + (i_max - i_min + 1) / 2; - if (coord < BorderArray[median]) - i_max = median; - else - i_min = median; - } - - return i_max; -} - -int wxGrid::YToRow( int y ) -{ - return CoordToRowOrCol(y, m_defaultRowHeight, - m_minAcceptableRowHeight, m_rowBottoms, m_numRows, false); -} - -int wxGrid::XToCol( int x, bool clipToMinMax ) -{ - if (x < 0) - return clipToMinMax && (m_numCols > 0) ? GetColAt( 0 ) : -1; - - if (!m_defaultColWidth) - m_defaultColWidth = 1; - - int maxPos = x / m_defaultColWidth; - int minPos = 0; - - if (m_colRights.IsEmpty()) - { - if(maxPos < m_numCols) - return GetColAt( maxPos ); - return clipToMinMax ? GetColAt( m_numCols - 1 ) : -1; - } - - if ( maxPos >= m_numCols) - maxPos = m_numCols - 1; - else - { - if ( x >= m_colRights[GetColAt( maxPos )]) - { - minPos = maxPos; - if (m_minAcceptableColWidth) - maxPos = x / m_minAcceptableColWidth; - else - maxPos = m_numCols - 1; - } - if ( maxPos >= m_numCols) - maxPos = m_numCols - 1; - } - - //X is beyond the last column - if ( x >= m_colRights[GetColAt( maxPos )]) - return clipToMinMax ? GetColAt( maxPos ) : -1; - - //X is before the first column - if ( x < m_colRights[GetColAt( 0 )] ) - return GetColAt( 0 ); - - //Perform a binary search - while ( maxPos - minPos > 0 ) - { - wxCHECK_MSG(m_colRights[GetColAt( minPos )] <= x && x < m_colRights[GetColAt( maxPos )], - 0, _T("wxGrid: internal error in XToCol")); - - if (x >= m_colRights[GetColAt( maxPos - 1 )]) - return GetColAt( maxPos ); - else - maxPos--; - int median = minPos + (maxPos - minPos + 1) / 2; - if (x < m_colRights[GetColAt( median )]) - maxPos = median; - else - minPos = median; - } - return GetColAt( maxPos ); -} - -// return the row number that that the y coord is near -// the edge of, or -1 if not near an edge. -// coords can only possibly be near an edge if -// (a) the row/column is large enough to still allow for an "inner" area -// that is _not_ nead the edge (i.e., if the height/width is smaller -// than WXGRID_LABEL_EDGE_ZONE, coords are _never_ considered to be -// near the edge). -// and -// (b) resizing rows/columns (the thing for which edge detection is -// relevant at all) is enabled. -// -int wxGrid::YToEdgeOfRow( int y ) -{ - int i; - i = internalYToRow(y); - - if ( GetRowHeight(i) > WXGRID_LABEL_EDGE_ZONE && CanDragRowSize() ) - { - // We know that we are in row i, test whether we are - // close enough to lower or upper border, respectively. - if ( abs(GetRowBottom(i) - y) < WXGRID_LABEL_EDGE_ZONE ) - return i; - else if ( i > 0 && y - GetRowTop(i) < WXGRID_LABEL_EDGE_ZONE ) - return i - 1; - } - - return -1; -} - -// return the col number that that the x coord is near the edge of, or -// -1 if not near an edge -// See comment at YToEdgeOfRow for conditions on edge detection. -// -int wxGrid::XToEdgeOfCol( int x ) -{ - int i; - i = internalXToCol(x); - - if ( GetColWidth(i) > WXGRID_LABEL_EDGE_ZONE && CanDragColSize() ) - { - // We know that we are in column i; test whether we are - // close enough to right or left border, respectively. - if ( abs(GetColRight(i) - x) < WXGRID_LABEL_EDGE_ZONE ) - return i; - else if ( i > 0 && x - GetColLeft(i) < WXGRID_LABEL_EDGE_ZONE ) - return i - 1; - } - - return -1; -} - -wxRect wxGrid::CellToRect( int row, int col ) -{ - wxRect rect( -1, -1, -1, -1 ); - - if ( row >= 0 && row < m_numRows && - col >= 0 && col < m_numCols ) - { - int i, cell_rows, cell_cols; - rect.width = rect.height = 0; - GetCellSize( row, col, &cell_rows, &cell_cols ); - // if negative then find multicell owner - if (cell_rows < 0) - row += cell_rows; - if (cell_cols < 0) - col += cell_cols; - GetCellSize( row, col, &cell_rows, &cell_cols ); - - rect.x = GetColLeft(col); - rect.y = GetRowTop(row); - for (i=col; i < col + cell_cols; i++) - rect.width += GetColWidth(i); - for (i=row; i < row + cell_rows; i++) - rect.height += GetRowHeight(i); - } - - // if grid lines are enabled, then the area of the cell is a bit smaller - if (m_gridLinesEnabled) - { - rect.width -= 1; - rect.height -= 1; - } - - return rect; -} - -bool wxGrid::IsVisible( int row, int col, bool wholeCellVisible ) -{ - // get the cell rectangle in logical coords - // - wxRect r( CellToRect( row, col ) ); - - // convert to device coords - // - int left, top, right, bottom; - CalcScrolledPosition( r.GetLeft(), r.GetTop(), &left, &top ); - CalcScrolledPosition( r.GetRight(), r.GetBottom(), &right, &bottom ); - - // check against the client area of the grid window - int cw, ch; - m_gridWin->GetClientSize( &cw, &ch ); - - if ( wholeCellVisible ) - { - // is the cell wholly visible ? - return ( left >= 0 && right <= cw && - top >= 0 && bottom <= ch ); - } - else - { - // is the cell partly visible ? - // - return ( ((left >= 0 && left < cw) || (right > 0 && right <= cw)) && - ((top >= 0 && top < ch) || (bottom > 0 && bottom <= ch)) ); - } -} - -// make the specified cell location visible by doing a minimal amount -// of scrolling -// -void wxGrid::MakeCellVisible( int row, int col ) -{ - int i; - int xpos = -1, ypos = -1; - - if ( row >= 0 && row < m_numRows && - col >= 0 && col < m_numCols ) - { - // get the cell rectangle in logical coords - wxRect r( CellToRect( row, col ) ); - - // convert to device coords - int left, top, right, bottom; - CalcScrolledPosition( r.GetLeft(), r.GetTop(), &left, &top ); - CalcScrolledPosition( r.GetRight(), r.GetBottom(), &right, &bottom ); - - int cw, ch; - m_gridWin->GetClientSize( &cw, &ch ); - - if ( top < 0 ) - { - ypos = r.GetTop(); - } - else if ( bottom > ch ) - { - int h = r.GetHeight(); - ypos = r.GetTop(); - for ( i = row - 1; i >= 0; i-- ) - { - int rowHeight = GetRowHeight(i); - if ( h + rowHeight > ch ) - break; - - h += rowHeight; - ypos -= rowHeight; - } - - // we divide it later by GRID_SCROLL_LINE, make sure that we don't - // have rounding errors (this is important, because if we do, - // we might not scroll at all and some cells won't be redrawn) - // - // Sometimes GRID_SCROLL_LINE / 2 is not enough, - // so just add a full scroll unit... - ypos += m_scrollLineY; - } - - // special handling for wide cells - show always left part of the cell! - // Otherwise, e.g. when stepping from row to row, it would jump between - // left and right part of the cell on every step! -// if ( left < 0 ) - if ( left < 0 || (right - left) >= cw ) - { - xpos = r.GetLeft(); - } - else if ( right > cw ) - { - // position the view so that the cell is on the right - int x0, y0; - CalcUnscrolledPosition(0, 0, &x0, &y0); - xpos = x0 + (right - cw); - - // see comment for ypos above - xpos += m_scrollLineX; - } - - if ( xpos != -1 || ypos != -1 ) - { - if ( xpos != -1 ) - xpos /= m_scrollLineX; - if ( ypos != -1 ) - ypos /= m_scrollLineY; - Scroll( xpos, ypos ); - AdjustScrollbars(); - } - } -} - -// -// ------ Grid cursor movement functions -// - -bool wxGrid::MoveCursorUp( bool expandSelection ) -{ - if ( m_currentCellCoords != wxGridNoCellCoords && - m_currentCellCoords.GetRow() >= 0 ) - { - if ( expandSelection ) - { - if ( m_selectingKeyboard == wxGridNoCellCoords ) - m_selectingKeyboard = m_currentCellCoords; - if ( m_selectingKeyboard.GetRow() > 0 ) - { - m_selectingKeyboard.SetRow( m_selectingKeyboard.GetRow() - 1 ); - MakeCellVisible( m_selectingKeyboard.GetRow(), - m_selectingKeyboard.GetCol() ); - HighlightBlock( m_currentCellCoords, m_selectingKeyboard ); - } - } - else if ( m_currentCellCoords.GetRow() > 0 ) - { - int row = m_currentCellCoords.GetRow() - 1; - int col = m_currentCellCoords.GetCol(); - ClearSelection(); - MakeCellVisible( row, col ); - SetCurrentCell( row, col ); - } - else - return false; - - return true; - } - - return false; -} - -bool wxGrid::MoveCursorDown( bool expandSelection ) -{ - if ( m_currentCellCoords != wxGridNoCellCoords && - m_currentCellCoords.GetRow() < m_numRows ) - { - if ( expandSelection ) - { - if ( m_selectingKeyboard == wxGridNoCellCoords ) - m_selectingKeyboard = m_currentCellCoords; - if ( m_selectingKeyboard.GetRow() < m_numRows - 1 ) - { - m_selectingKeyboard.SetRow( m_selectingKeyboard.GetRow() + 1 ); - MakeCellVisible( m_selectingKeyboard.GetRow(), - m_selectingKeyboard.GetCol() ); - HighlightBlock( m_currentCellCoords, m_selectingKeyboard ); - } - } - else if ( m_currentCellCoords.GetRow() < m_numRows - 1 ) - { - int row = m_currentCellCoords.GetRow() + 1; - int col = m_currentCellCoords.GetCol(); - ClearSelection(); - MakeCellVisible( row, col ); - SetCurrentCell( row, col ); - } - else - return false; - - return true; - } - - return false; -} - -bool wxGrid::MoveCursorLeft( bool expandSelection ) -{ - if ( m_currentCellCoords != wxGridNoCellCoords && - m_currentCellCoords.GetCol() >= 0 ) - { - if ( expandSelection ) - { - if ( m_selectingKeyboard == wxGridNoCellCoords ) - m_selectingKeyboard = m_currentCellCoords; - if ( m_selectingKeyboard.GetCol() > 0 ) - { - m_selectingKeyboard.SetCol( m_selectingKeyboard.GetCol() - 1 ); - MakeCellVisible( m_selectingKeyboard.GetRow(), - m_selectingKeyboard.GetCol() ); - HighlightBlock( m_currentCellCoords, m_selectingKeyboard ); - } - } - else if ( GetColPos( m_currentCellCoords.GetCol() ) > 0 ) - { - int row = m_currentCellCoords.GetRow(); - int col = GetColAt( GetColPos( m_currentCellCoords.GetCol() ) - 1 ); - ClearSelection(); - - MakeCellVisible( row, col ); - SetCurrentCell( row, col ); - } - else - return false; - - return true; - } - - return false; -} - -bool wxGrid::MoveCursorRight( bool expandSelection ) -{ - if ( m_currentCellCoords != wxGridNoCellCoords && - m_currentCellCoords.GetCol() < m_numCols ) - { - if ( expandSelection ) - { - if ( m_selectingKeyboard == wxGridNoCellCoords ) - m_selectingKeyboard = m_currentCellCoords; - if ( m_selectingKeyboard.GetCol() < m_numCols - 1 ) - { - m_selectingKeyboard.SetCol( m_selectingKeyboard.GetCol() + 1 ); - MakeCellVisible( m_selectingKeyboard.GetRow(), - m_selectingKeyboard.GetCol() ); - HighlightBlock( m_currentCellCoords, m_selectingKeyboard ); - } - } - else if ( GetColPos( m_currentCellCoords.GetCol() ) < m_numCols - 1 ) - { - int row = m_currentCellCoords.GetRow(); - int col = GetColAt( GetColPos( m_currentCellCoords.GetCol() ) + 1 ); - ClearSelection(); - - MakeCellVisible( row, col ); - SetCurrentCell( row, col ); - } - else - return false; - - return true; - } - - return false; -} - -bool wxGrid::MovePageUp() -{ - if ( m_currentCellCoords == wxGridNoCellCoords ) - return false; - - int row = m_currentCellCoords.GetRow(); - if ( row > 0 ) - { - int cw, ch; - m_gridWin->GetClientSize( &cw, &ch ); - - int y = GetRowTop(row); - int newRow = internalYToRow( y - ch + 1 ); - - if ( newRow == row ) - { - // row > 0, so newRow can never be less than 0 here. - newRow = row - 1; - } - - MakeCellVisible( newRow, m_currentCellCoords.GetCol() ); - SetCurrentCell( newRow, m_currentCellCoords.GetCol() ); - - return true; - } - - return false; -} - -bool wxGrid::MovePageDown() -{ - if ( m_currentCellCoords == wxGridNoCellCoords ) - return false; - - int row = m_currentCellCoords.GetRow(); - if ( (row + 1) < m_numRows ) - { - int cw, ch; - m_gridWin->GetClientSize( &cw, &ch ); - - int y = GetRowTop(row); - int newRow = internalYToRow( y + ch ); - if ( newRow == row ) - { - // row < m_numRows, so newRow can't overflow here. - newRow = row + 1; - } - - MakeCellVisible( newRow, m_currentCellCoords.GetCol() ); - SetCurrentCell( newRow, m_currentCellCoords.GetCol() ); - - return true; - } - - return false; -} - -bool wxGrid::MoveCursorUpBlock( bool expandSelection ) -{ - if ( m_table && - m_currentCellCoords != wxGridNoCellCoords && - m_currentCellCoords.GetRow() > 0 ) - { - int row = m_currentCellCoords.GetRow(); - int col = m_currentCellCoords.GetCol(); - - if ( m_table->IsEmptyCell(row, col) ) - { - // starting in an empty cell: find the next block of - // non-empty cells - // - while ( row > 0 ) - { - row--; - if ( !(m_table->IsEmptyCell(row, col)) ) - break; - } - } - else if ( m_table->IsEmptyCell(row - 1, col) ) - { - // starting at the top of a block: find the next block - // - row--; - while ( row > 0 ) - { - row--; - if ( !(m_table->IsEmptyCell(row, col)) ) - break; - } - } - else - { - // starting within a block: find the top of the block - // - while ( row > 0 ) - { - row--; - if ( m_table->IsEmptyCell(row, col) ) - { - row++; - break; - } - } - } - - MakeCellVisible( row, col ); - if ( expandSelection ) - { - m_selectingKeyboard = wxGridCellCoords( row, col ); - HighlightBlock( m_currentCellCoords, m_selectingKeyboard ); - } - else - { - ClearSelection(); - SetCurrentCell( row, col ); - } - - return true; - } - - return false; -} - -bool wxGrid::MoveCursorDownBlock( bool expandSelection ) -{ - if ( m_table && - m_currentCellCoords != wxGridNoCellCoords && - m_currentCellCoords.GetRow() < m_numRows - 1 ) - { - int row = m_currentCellCoords.GetRow(); - int col = m_currentCellCoords.GetCol(); - - if ( m_table->IsEmptyCell(row, col) ) - { - // starting in an empty cell: find the next block of - // non-empty cells - // - while ( row < m_numRows - 1 ) - { - row++; - if ( !(m_table->IsEmptyCell(row, col)) ) - break; - } - } - else if ( m_table->IsEmptyCell(row + 1, col) ) - { - // starting at the bottom of a block: find the next block - // - row++; - while ( row < m_numRows - 1 ) - { - row++; - if ( !(m_table->IsEmptyCell(row, col)) ) - break; - } - } - else - { - // starting within a block: find the bottom of the block - // - while ( row < m_numRows - 1 ) - { - row++; - if ( m_table->IsEmptyCell(row, col) ) - { - row--; - break; - } - } - } - - MakeCellVisible( row, col ); - if ( expandSelection ) - { - m_selectingKeyboard = wxGridCellCoords( row, col ); - HighlightBlock( m_currentCellCoords, m_selectingKeyboard ); - } - else - { - ClearSelection(); - SetCurrentCell( row, col ); - } - - return true; - } - - return false; -} - -bool wxGrid::MoveCursorLeftBlock( bool expandSelection ) -{ - if ( m_table && - m_currentCellCoords != wxGridNoCellCoords && - m_currentCellCoords.GetCol() > 0 ) - { - int row = m_currentCellCoords.GetRow(); - int col = m_currentCellCoords.GetCol(); - - if ( m_table->IsEmptyCell(row, col) ) - { - // starting in an empty cell: find the next block of - // non-empty cells - // - while ( col > 0 ) - { - col--; - if ( !(m_table->IsEmptyCell(row, col)) ) - break; - } - } - else if ( m_table->IsEmptyCell(row, col - 1) ) - { - // starting at the left of a block: find the next block - // - col--; - while ( col > 0 ) - { - col--; - if ( !(m_table->IsEmptyCell(row, col)) ) - break; - } - } - else - { - // starting within a block: find the left of the block - // - while ( col > 0 ) - { - col--; - if ( m_table->IsEmptyCell(row, col) ) - { - col++; - break; - } - } - } - - MakeCellVisible( row, col ); - if ( expandSelection ) - { - m_selectingKeyboard = wxGridCellCoords( row, col ); - HighlightBlock( m_currentCellCoords, m_selectingKeyboard ); - } - else - { - ClearSelection(); - SetCurrentCell( row, col ); - } - - return true; - } - - return false; -} - -bool wxGrid::MoveCursorRightBlock( bool expandSelection ) -{ - if ( m_table && - m_currentCellCoords != wxGridNoCellCoords && - m_currentCellCoords.GetCol() < m_numCols - 1 ) - { - int row = m_currentCellCoords.GetRow(); - int col = m_currentCellCoords.GetCol(); - - if ( m_table->IsEmptyCell(row, col) ) - { - // starting in an empty cell: find the next block of - // non-empty cells - // - while ( col < m_numCols - 1 ) - { - col++; - if ( !(m_table->IsEmptyCell(row, col)) ) - break; - } - } - else if ( m_table->IsEmptyCell(row, col + 1) ) - { - // starting at the right of a block: find the next block - // - col++; - while ( col < m_numCols - 1 ) - { - col++; - if ( !(m_table->IsEmptyCell(row, col)) ) - break; - } - } - else - { - // starting within a block: find the right of the block - // - while ( col < m_numCols - 1 ) - { - col++; - if ( m_table->IsEmptyCell(row, col) ) - { - col--; - break; - } - } - } - - MakeCellVisible( row, col ); - if ( expandSelection ) - { - m_selectingKeyboard = wxGridCellCoords( row, col ); - HighlightBlock( m_currentCellCoords, m_selectingKeyboard ); - } - else - { - ClearSelection(); - SetCurrentCell( row, col ); - } - - return true; - } - - return false; -} - -// -// ------ Label values and formatting -// - -void wxGrid::GetRowLabelAlignment( int *horiz, int *vert ) -{ - if ( horiz ) - *horiz = m_rowLabelHorizAlign; - if ( vert ) - *vert = m_rowLabelVertAlign; -} - -void wxGrid::GetColLabelAlignment( int *horiz, int *vert ) -{ - if ( horiz ) - *horiz = m_colLabelHorizAlign; - if ( vert ) - *vert = m_colLabelVertAlign; -} - -int wxGrid::GetColLabelTextOrientation() -{ - return m_colLabelTextOrientation; -} - -wxString wxGrid::GetRowLabelValue( int row ) -{ - if ( m_table ) - { - return m_table->GetRowLabelValue( row ); - } - else - { - wxString s; - s << row; - return s; - } -} - -wxString wxGrid::GetColLabelValue( int col ) -{ - if ( m_table ) - { - return m_table->GetColLabelValue( col ); - } - else - { - wxString s; - s << col; - return s; - } -} - -void wxGrid::SetRowLabelSize( int width ) -{ - wxASSERT( width >= 0 || width == wxGRID_AUTOSIZE ); - - if ( width == wxGRID_AUTOSIZE ) - { - width = CalcColOrRowLabelAreaMinSize(false/*row*/); - } - - if ( width != m_rowLabelWidth ) - { - if ( width == 0 ) - { - m_rowLabelWin->Show( false ); - m_cornerLabelWin->Show( false ); - } - else if ( m_rowLabelWidth == 0 ) - { - m_rowLabelWin->Show( true ); - if ( m_colLabelHeight > 0 ) - m_cornerLabelWin->Show( true ); - } - - m_rowLabelWidth = width; - CalcWindowSizes(); - wxScrolledWindow::Refresh( true ); - } -} - -void wxGrid::SetColLabelSize( int height ) -{ - wxASSERT( height >=0 || height == wxGRID_AUTOSIZE ); - - if ( height == wxGRID_AUTOSIZE ) - { - height = CalcColOrRowLabelAreaMinSize(true/*column*/); - } - - if ( height != m_colLabelHeight ) - { - if ( height == 0 ) - { - m_colLabelWin->Show( false ); - m_cornerLabelWin->Show( false ); - } - else if ( m_colLabelHeight == 0 ) - { - m_colLabelWin->Show( true ); - if ( m_rowLabelWidth > 0 ) - m_cornerLabelWin->Show( true ); - } - - m_colLabelHeight = height; - CalcWindowSizes(); - wxScrolledWindow::Refresh( true ); - } -} - -void wxGrid::SetLabelBackgroundColour( const wxColour& colour ) -{ - if ( m_labelBackgroundColour != colour ) - { - m_labelBackgroundColour = colour; - m_rowLabelWin->SetBackgroundColour( colour ); - m_colLabelWin->SetBackgroundColour( colour ); - m_cornerLabelWin->SetBackgroundColour( colour ); - - if ( !GetBatchCount() ) - { - m_rowLabelWin->Refresh(); - m_colLabelWin->Refresh(); - m_cornerLabelWin->Refresh(); - } - } -} - -void wxGrid::SetLabelTextColour( const wxColour& colour ) -{ - if ( m_labelTextColour != colour ) - { - m_labelTextColour = colour; - if ( !GetBatchCount() ) - { - m_rowLabelWin->Refresh(); - m_colLabelWin->Refresh(); - } - } -} - -void wxGrid::SetLabelFont( const wxFont& font ) -{ - m_labelFont = font; - if ( !GetBatchCount() ) - { - m_rowLabelWin->Refresh(); - m_colLabelWin->Refresh(); - } -} - -void wxGrid::SetRowLabelAlignment( int horiz, int vert ) -{ - // allow old (incorrect) defs to be used - switch ( horiz ) - { - case wxLEFT: horiz = wxALIGN_LEFT; break; - case wxRIGHT: horiz = wxALIGN_RIGHT; break; - case wxCENTRE: horiz = wxALIGN_CENTRE; break; - } - - switch ( vert ) - { - case wxTOP: vert = wxALIGN_TOP; break; - case wxBOTTOM: vert = wxALIGN_BOTTOM; break; - case wxCENTRE: vert = wxALIGN_CENTRE; break; - } - - if ( horiz == wxALIGN_LEFT || horiz == wxALIGN_CENTRE || horiz == wxALIGN_RIGHT ) - { - m_rowLabelHorizAlign = horiz; - } - - if ( vert == wxALIGN_TOP || vert == wxALIGN_CENTRE || vert == wxALIGN_BOTTOM ) - { - m_rowLabelVertAlign = vert; - } - - if ( !GetBatchCount() ) - { - m_rowLabelWin->Refresh(); - } -} - -void wxGrid::SetColLabelAlignment( int horiz, int vert ) -{ - // allow old (incorrect) defs to be used - switch ( horiz ) - { - case wxLEFT: horiz = wxALIGN_LEFT; break; - case wxRIGHT: horiz = wxALIGN_RIGHT; break; - case wxCENTRE: horiz = wxALIGN_CENTRE; break; - } - - switch ( vert ) - { - case wxTOP: vert = wxALIGN_TOP; break; - case wxBOTTOM: vert = wxALIGN_BOTTOM; break; - case wxCENTRE: vert = wxALIGN_CENTRE; break; - } - - if ( horiz == wxALIGN_LEFT || horiz == wxALIGN_CENTRE || horiz == wxALIGN_RIGHT ) - { - m_colLabelHorizAlign = horiz; - } - - if ( vert == wxALIGN_TOP || vert == wxALIGN_CENTRE || vert == wxALIGN_BOTTOM ) - { - m_colLabelVertAlign = vert; - } - - if ( !GetBatchCount() ) - { - m_colLabelWin->Refresh(); - } -} - -// Note: under MSW, the default column label font must be changed because it -// does not support vertical printing -// -// Example: wxFont font(9, wxSWISS, wxNORMAL, wxBOLD); -// pGrid->SetLabelFont(font); -// pGrid->SetColLabelTextOrientation(wxVERTICAL); -// -void wxGrid::SetColLabelTextOrientation( int textOrientation ) -{ - if ( textOrientation == wxHORIZONTAL || textOrientation == wxVERTICAL ) - m_colLabelTextOrientation = textOrientation; - - if ( !GetBatchCount() ) - m_colLabelWin->Refresh(); -} - -void wxGrid::SetRowLabelValue( int row, const wxString& s ) -{ - if ( m_table ) - { - m_table->SetRowLabelValue( row, s ); - if ( !GetBatchCount() ) - { - wxRect rect = CellToRect( row, 0 ); - if ( rect.height > 0 ) - { - CalcScrolledPosition(0, rect.y, &rect.x, &rect.y); - rect.x = 0; - rect.width = m_rowLabelWidth; - m_rowLabelWin->Refresh( true, &rect ); - } - } - } -} - -void wxGrid::SetColLabelValue( int col, const wxString& s ) -{ - if ( m_table ) - { - m_table->SetColLabelValue( col, s ); - if ( !GetBatchCount() ) - { - wxRect rect = CellToRect( 0, col ); - if ( rect.width > 0 ) - { - CalcScrolledPosition(rect.x, 0, &rect.x, &rect.y); - rect.y = 0; - rect.height = m_colLabelHeight; - m_colLabelWin->Refresh( true, &rect ); - } - } - } -} - -void wxGrid::SetGridLineColour( const wxColour& colour ) -{ - if ( m_gridLineColour != colour ) - { - m_gridLineColour = colour; - - wxClientDC dc( m_gridWin ); - PrepareDC( dc ); - DrawAllGridLines( dc, wxRegion() ); - } -} - -void wxGrid::SetCellHighlightColour( const wxColour& colour ) -{ - if ( m_cellHighlightColour != colour ) - { - m_cellHighlightColour = colour; - - wxClientDC dc( m_gridWin ); - PrepareDC( dc ); - wxGridCellAttr* attr = GetCellAttr(m_currentCellCoords); - DrawCellHighlight(dc, attr); - attr->DecRef(); - } -} - -void wxGrid::SetCellHighlightPenWidth(int width) -{ - if (m_cellHighlightPenWidth != width) - { - m_cellHighlightPenWidth = width; - - // Just redrawing the cell highlight is not enough since that won't - // make any visible change if the the thickness is getting smaller. - int row = m_currentCellCoords.GetRow(); - int col = m_currentCellCoords.GetCol(); - if ( row == -1 || col == -1 || GetColWidth(col) <= 0 || GetRowHeight(row) <= 0 ) - return; - - wxRect rect = CellToRect(row, col); - m_gridWin->Refresh(true, &rect); - } -} - -void wxGrid::SetCellHighlightROPenWidth(int width) -{ - if (m_cellHighlightROPenWidth != width) - { - m_cellHighlightROPenWidth = width; - - // Just redrawing the cell highlight is not enough since that won't - // make any visible change if the the thickness is getting smaller. - int row = m_currentCellCoords.GetRow(); - int col = m_currentCellCoords.GetCol(); - if ( row == -1 || col == -1 || - GetColWidth(col) <= 0 || GetRowHeight(row) <= 0 ) - return; - - wxRect rect = CellToRect(row, col); - m_gridWin->Refresh(true, &rect); - } -} - -void wxGrid::EnableGridLines( bool enable ) -{ - if ( enable != m_gridLinesEnabled ) - { - m_gridLinesEnabled = enable; - - if ( !GetBatchCount() ) - { - if ( enable ) - { - wxClientDC dc( m_gridWin ); - PrepareDC( dc ); - DrawAllGridLines( dc, wxRegion() ); - } - else - { - m_gridWin->Refresh(); - } - } - } -} - -int wxGrid::GetDefaultRowSize() -{ - return m_defaultRowHeight; -} - -int wxGrid::GetRowSize( int row ) -{ - wxCHECK_MSG( row >= 0 && row < m_numRows, 0, _T("invalid row index") ); - - return GetRowHeight(row); -} - -int wxGrid::GetDefaultColSize() -{ - return m_defaultColWidth; -} - -int wxGrid::GetColSize( int col ) -{ - wxCHECK_MSG( col >= 0 && col < m_numCols, 0, _T("invalid column index") ); - - return GetColWidth(col); -} - -// ============================================================================ -// access to the grid attributes: each of them has a default value in the grid -// itself and may be overidden on a per-cell basis -// ============================================================================ - -// ---------------------------------------------------------------------------- -// setting default attributes -// ---------------------------------------------------------------------------- - -void wxGrid::SetDefaultCellBackgroundColour( const wxColour& col ) -{ - m_defaultCellAttr->SetBackgroundColour(col); -#ifdef __WXGTK__ - m_gridWin->SetBackgroundColour(col); -#endif -} - -void wxGrid::SetDefaultCellTextColour( const wxColour& col ) -{ - m_defaultCellAttr->SetTextColour(col); -} - -void wxGrid::SetDefaultCellAlignment( int horiz, int vert ) -{ - m_defaultCellAttr->SetAlignment(horiz, vert); -} - -void wxGrid::SetDefaultCellOverflow( bool allow ) -{ - m_defaultCellAttr->SetOverflow(allow); -} - -void wxGrid::SetDefaultCellFont( const wxFont& font ) -{ - m_defaultCellAttr->SetFont(font); -} - -// For editors and renderers the type registry takes precedence over the -// default attr, so we need to register the new editor/renderer for the string -// data type in order to make setting a default editor/renderer appear to -// work correctly. - -void wxGrid::SetDefaultRenderer(wxGridCellRenderer *renderer) -{ - RegisterDataType(wxGRID_VALUE_STRING, - renderer, - GetDefaultEditorForType(wxGRID_VALUE_STRING)); -} - -void wxGrid::SetDefaultEditor(wxGridCellEditor *editor) -{ - RegisterDataType(wxGRID_VALUE_STRING, - GetDefaultRendererForType(wxGRID_VALUE_STRING), - editor); -} - -// ---------------------------------------------------------------------------- -// access to the default attrbiutes -// ---------------------------------------------------------------------------- - -wxColour wxGrid::GetDefaultCellBackgroundColour() -{ - return m_defaultCellAttr->GetBackgroundColour(); -} - -wxColour wxGrid::GetDefaultCellTextColour() -{ - return m_defaultCellAttr->GetTextColour(); -} - -wxFont wxGrid::GetDefaultCellFont() -{ - return m_defaultCellAttr->GetFont(); -} - -void wxGrid::GetDefaultCellAlignment( int *horiz, int *vert ) -{ - m_defaultCellAttr->GetAlignment(horiz, vert); -} - -bool wxGrid::GetDefaultCellOverflow() -{ - return m_defaultCellAttr->GetOverflow(); -} - -wxGridCellRenderer *wxGrid::GetDefaultRenderer() const -{ - return m_defaultCellAttr->GetRenderer(NULL, 0, 0); -} - -wxGridCellEditor *wxGrid::GetDefaultEditor() const -{ - return m_defaultCellAttr->GetEditor(NULL, 0, 0); -} - -// ---------------------------------------------------------------------------- -// access to cell attributes -// ---------------------------------------------------------------------------- - -wxColour wxGrid::GetCellBackgroundColour(int row, int col) -{ - wxGridCellAttr *attr = GetCellAttr(row, col); - wxColour colour = attr->GetBackgroundColour(); - attr->DecRef(); - - return colour; -} - -wxColour wxGrid::GetCellTextColour( int row, int col ) -{ - wxGridCellAttr *attr = GetCellAttr(row, col); - wxColour colour = attr->GetTextColour(); - attr->DecRef(); - - return colour; -} - -wxFont wxGrid::GetCellFont( int row, int col ) -{ - wxGridCellAttr *attr = GetCellAttr(row, col); - wxFont font = attr->GetFont(); - attr->DecRef(); - - return font; -} - -void wxGrid::GetCellAlignment( int row, int col, int *horiz, int *vert ) -{ - wxGridCellAttr *attr = GetCellAttr(row, col); - attr->GetAlignment(horiz, vert); - attr->DecRef(); -} - -bool wxGrid::GetCellOverflow( int row, int col ) -{ - wxGridCellAttr *attr = GetCellAttr(row, col); - bool allow = attr->GetOverflow(); - attr->DecRef(); - - return allow; -} - -void wxGrid::GetCellSize( int row, int col, int *num_rows, int *num_cols ) -{ - wxGridCellAttr *attr = GetCellAttr(row, col); - attr->GetSize( num_rows, num_cols ); - attr->DecRef(); -} - -wxGridCellRenderer* wxGrid::GetCellRenderer(int row, int col) -{ - wxGridCellAttr* attr = GetCellAttr(row, col); - wxGridCellRenderer* renderer = attr->GetRenderer(this, row, col); - attr->DecRef(); - - return renderer; -} - -wxGridCellEditor* wxGrid::GetCellEditor(int row, int col) -{ - wxGridCellAttr* attr = GetCellAttr(row, col); - wxGridCellEditor* editor = attr->GetEditor(this, row, col); - attr->DecRef(); - - return editor; -} - -bool wxGrid::IsReadOnly(int row, int col) const -{ - wxGridCellAttr* attr = GetCellAttr(row, col); - bool isReadOnly = attr->IsReadOnly(); - attr->DecRef(); - - return isReadOnly; -} - -// ---------------------------------------------------------------------------- -// attribute support: cache, automatic provider creation, ... -// ---------------------------------------------------------------------------- - -bool wxGrid::CanHaveAttributes() -{ - if ( !m_table ) - { - return false; - } - - return m_table->CanHaveAttributes(); -} - -void wxGrid::ClearAttrCache() -{ - if ( m_attrCache.row != -1 ) - { - wxSafeDecRef(m_attrCache.attr); - m_attrCache.attr = NULL; - m_attrCache.row = -1; - } -} - -void wxGrid::CacheAttr(int row, int col, wxGridCellAttr *attr) const -{ - if ( attr != NULL ) - { - wxGrid *self = (wxGrid *)this; // const_cast - - self->ClearAttrCache(); - self->m_attrCache.row = row; - self->m_attrCache.col = col; - self->m_attrCache.attr = attr; - wxSafeIncRef(attr); - } -} - -bool wxGrid::LookupAttr(int row, int col, wxGridCellAttr **attr) const -{ - if ( row == m_attrCache.row && col == m_attrCache.col ) - { - *attr = m_attrCache.attr; - wxSafeIncRef(m_attrCache.attr); - -#ifdef DEBUG_ATTR_CACHE - gs_nAttrCacheHits++; -#endif - - return true; - } - else - { -#ifdef DEBUG_ATTR_CACHE - gs_nAttrCacheMisses++; -#endif - - return false; - } -} - -wxGridCellAttr *wxGrid::GetCellAttr(int row, int col) const -{ - wxGridCellAttr *attr = NULL; - // Additional test to avoid looking at the cache e.g. for - // wxNoCellCoords, as this will confuse memory management. - if ( row >= 0 ) - { - if ( !LookupAttr(row, col, &attr) ) - { - attr = m_table ? m_table->GetAttr(row, col, wxGridCellAttr::Any) - : (wxGridCellAttr *)NULL; - CacheAttr(row, col, attr); - } - } - - if (attr) - { - attr->SetDefAttr(m_defaultCellAttr); - } - else - { - attr = m_defaultCellAttr; - attr->IncRef(); - } - - return attr; -} - -wxGridCellAttr *wxGrid::GetOrCreateCellAttr(int row, int col) const -{ - wxGridCellAttr *attr = (wxGridCellAttr *)NULL; - bool canHave = ((wxGrid*)this)->CanHaveAttributes(); - - wxCHECK_MSG( canHave, attr, _T("Cell attributes not allowed")); - wxCHECK_MSG( m_table, attr, _T("must have a table") ); - - attr = m_table->GetAttr(row, col, wxGridCellAttr::Cell); - if ( !attr ) - { - attr = new wxGridCellAttr(m_defaultCellAttr); - - // artificially inc the ref count to match DecRef() in caller - attr->IncRef(); - m_table->SetAttr(attr, row, col); - } - - return attr; -} - -// ---------------------------------------------------------------------------- -// setting column attributes (wrappers around SetColAttr) -// ---------------------------------------------------------------------------- - -void wxGrid::SetColFormatBool(int col) -{ - SetColFormatCustom(col, wxGRID_VALUE_BOOL); -} - -void wxGrid::SetColFormatNumber(int col) -{ - SetColFormatCustom(col, wxGRID_VALUE_NUMBER); -} - -void wxGrid::SetColFormatFloat(int col, int width, int precision) -{ - wxString typeName = wxGRID_VALUE_FLOAT; - if ( (width != -1) || (precision != -1) ) - { - typeName << _T(':') << width << _T(',') << precision; - } - - SetColFormatCustom(col, typeName); -} - -void wxGrid::SetColFormatCustom(int col, const wxString& typeName) -{ - wxGridCellAttr *attr = m_table->GetAttr(-1, col, wxGridCellAttr::Col ); - if (!attr) - attr = new wxGridCellAttr; - wxGridCellRenderer *renderer = GetDefaultRendererForType(typeName); - attr->SetRenderer(renderer); - - SetColAttr(col, attr); - -} - -// ---------------------------------------------------------------------------- -// setting cell attributes: this is forwarded to the table -// ---------------------------------------------------------------------------- - -void wxGrid::SetAttr(int row, int col, wxGridCellAttr *attr) -{ - if ( CanHaveAttributes() ) - { - m_table->SetAttr(attr, row, col); - ClearAttrCache(); - } - else - { - wxSafeDecRef(attr); - } -} - -void wxGrid::SetRowAttr(int row, wxGridCellAttr *attr) -{ - if ( CanHaveAttributes() ) - { - m_table->SetRowAttr(attr, row); - ClearAttrCache(); - } - else - { - wxSafeDecRef(attr); - } -} - -void wxGrid::SetColAttr(int col, wxGridCellAttr *attr) -{ - if ( CanHaveAttributes() ) - { - m_table->SetColAttr(attr, col); - ClearAttrCache(); - } - else - { - wxSafeDecRef(attr); - } -} - -void wxGrid::SetCellBackgroundColour( int row, int col, const wxColour& colour ) -{ - if ( CanHaveAttributes() ) - { - wxGridCellAttr *attr = GetOrCreateCellAttr(row, col); - attr->SetBackgroundColour(colour); - attr->DecRef(); - } -} - -void wxGrid::SetCellTextColour( int row, int col, const wxColour& colour ) -{ - if ( CanHaveAttributes() ) - { - wxGridCellAttr *attr = GetOrCreateCellAttr(row, col); - attr->SetTextColour(colour); - attr->DecRef(); - } -} - -void wxGrid::SetCellFont( int row, int col, const wxFont& font ) -{ - if ( CanHaveAttributes() ) - { - wxGridCellAttr *attr = GetOrCreateCellAttr(row, col); - attr->SetFont(font); - attr->DecRef(); - } -} - -void wxGrid::SetCellAlignment( int row, int col, int horiz, int vert ) -{ - if ( CanHaveAttributes() ) - { - wxGridCellAttr *attr = GetOrCreateCellAttr(row, col); - attr->SetAlignment(horiz, vert); - attr->DecRef(); - } -} - -void wxGrid::SetCellOverflow( int row, int col, bool allow ) -{ - if ( CanHaveAttributes() ) - { - wxGridCellAttr *attr = GetOrCreateCellAttr(row, col); - attr->SetOverflow(allow); - attr->DecRef(); - } -} - -void wxGrid::SetCellSize( int row, int col, int num_rows, int num_cols ) -{ - if ( CanHaveAttributes() ) - { - int cell_rows, cell_cols; - - wxGridCellAttr *attr = GetOrCreateCellAttr(row, col); - attr->GetSize(&cell_rows, &cell_cols); - attr->SetSize(num_rows, num_cols); - attr->DecRef(); - - // Cannot set the size of a cell to 0 or negative values - // While it is perfectly legal to do that, this function cannot - // handle all the possibilies, do it by hand by getting the CellAttr. - // You can only set the size of a cell to 1,1 or greater with this fn - wxASSERT_MSG( !((cell_rows < 1) || (cell_cols < 1)), - wxT("wxGrid::SetCellSize setting cell size that is already part of another cell")); - wxASSERT_MSG( !((num_rows < 1) || (num_cols < 1)), - wxT("wxGrid::SetCellSize setting cell size to < 1")); - - // if this was already a multicell then "turn off" the other cells first - if ((cell_rows > 1) || (cell_rows > 1)) - { - int i, j; - for (j=row; j < row + cell_rows; j++) - { - for (i=col; i < col + cell_cols; i++) - { - if ((i != col) || (j != row)) - { - wxGridCellAttr *attr_stub = GetOrCreateCellAttr(j, i); - attr_stub->SetSize( 1, 1 ); - attr_stub->DecRef(); - } - } - } - } - - // mark the cells that will be covered by this cell to - // negative or zero values to point back at this cell - if (((num_rows > 1) || (num_cols > 1)) && (num_rows >= 1) && (num_cols >= 1)) - { - int i, j; - for (j=row; j < row + num_rows; j++) - { - for (i=col; i < col + num_cols; i++) - { - if ((i != col) || (j != row)) - { - wxGridCellAttr *attr_stub = GetOrCreateCellAttr(j, i); - attr_stub->SetSize( row - j, col - i ); - attr_stub->DecRef(); - } - } - } - } - } -} - -void wxGrid::SetCellRenderer(int row, int col, wxGridCellRenderer *renderer) -{ - if ( CanHaveAttributes() ) - { - wxGridCellAttr *attr = GetOrCreateCellAttr(row, col); - attr->SetRenderer(renderer); - attr->DecRef(); - } -} - -void wxGrid::SetCellEditor(int row, int col, wxGridCellEditor* editor) -{ - if ( CanHaveAttributes() ) - { - wxGridCellAttr *attr = GetOrCreateCellAttr(row, col); - attr->SetEditor(editor); - attr->DecRef(); - } -} - -void wxGrid::SetReadOnly(int row, int col, bool isReadOnly) -{ - if ( CanHaveAttributes() ) - { - wxGridCellAttr *attr = GetOrCreateCellAttr(row, col); - attr->SetReadOnly(isReadOnly); - attr->DecRef(); - } -} - -// ---------------------------------------------------------------------------- -// Data type registration -// ---------------------------------------------------------------------------- - -void wxGrid::RegisterDataType(const wxString& typeName, - wxGridCellRenderer* renderer, - wxGridCellEditor* editor) -{ - m_typeRegistry->RegisterDataType(typeName, renderer, editor); -} - - -wxGridCellEditor * wxGrid::GetDefaultEditorForCell(int row, int col) const -{ - wxString typeName = m_table->GetTypeName(row, col); - return GetDefaultEditorForType(typeName); -} - -wxGridCellRenderer * wxGrid::GetDefaultRendererForCell(int row, int col) const -{ - wxString typeName = m_table->GetTypeName(row, col); - return GetDefaultRendererForType(typeName); -} - -wxGridCellEditor * wxGrid::GetDefaultEditorForType(const wxString& typeName) const -{ - int index = m_typeRegistry->FindOrCloneDataType(typeName); - if ( index == wxNOT_FOUND ) - { - wxString errStr; - - errStr.Printf(wxT("Unknown data type name [%s]"), typeName.c_str()); - wxFAIL_MSG(errStr.c_str()); - - return NULL; - } - - return m_typeRegistry->GetEditor(index); -} - -wxGridCellRenderer * wxGrid::GetDefaultRendererForType(const wxString& typeName) const -{ - int index = m_typeRegistry->FindOrCloneDataType(typeName); - if ( index == wxNOT_FOUND ) - { - wxString errStr; - - errStr.Printf(wxT("Unknown data type name [%s]"), typeName.c_str()); - wxFAIL_MSG(errStr.c_str()); - - return NULL; - } - - return m_typeRegistry->GetRenderer(index); -} - -// ---------------------------------------------------------------------------- -// row/col size -// ---------------------------------------------------------------------------- - -void wxGrid::EnableDragRowSize( bool enable ) -{ - m_canDragRowSize = enable; -} - -void wxGrid::EnableDragColSize( bool enable ) -{ - m_canDragColSize = enable; -} - -void wxGrid::EnableDragGridSize( bool enable ) -{ - m_canDragGridSize = enable; -} - -void wxGrid::EnableDragCell( bool enable ) -{ - m_canDragCell = enable; -} - -void wxGrid::SetDefaultRowSize( int height, bool resizeExistingRows ) -{ - m_defaultRowHeight = wxMax( height, m_minAcceptableRowHeight ); - - if ( resizeExistingRows ) - { - // since we are resizing all rows to the default row size, - // we can simply clear the row heights and row bottoms - // arrays (which also allows us to take advantage of - // some speed optimisations) - m_rowHeights.Empty(); - m_rowBottoms.Empty(); - if ( !GetBatchCount() ) - CalcDimensions(); - } -} - -void wxGrid::SetRowSize( int row, int height ) -{ - wxCHECK_RET( row >= 0 && row < m_numRows, _T("invalid row index") ); - - // See comment in SetColSize - if ( height < GetRowMinimalAcceptableHeight()) - return; - - if ( m_rowHeights.IsEmpty() ) - { - // need to really create the array - InitRowHeights(); - } - - int h = wxMax( 0, height ); - int diff = h - m_rowHeights[row]; - - m_rowHeights[row] = h; - for ( int i = row; i < m_numRows; i++ ) - { - m_rowBottoms[i] += diff; - } - - if ( !GetBatchCount() ) - CalcDimensions(); -} - -void wxGrid::SetDefaultColSize( int width, bool resizeExistingCols ) -{ - m_defaultColWidth = wxMax( width, m_minAcceptableColWidth ); - - if ( resizeExistingCols ) - { - // since we are resizing all columns to the default column size, - // we can simply clear the col widths and col rights - // arrays (which also allows us to take advantage of - // some speed optimisations) - m_colWidths.Empty(); - m_colRights.Empty(); - if ( !GetBatchCount() ) - CalcDimensions(); - } -} - -void wxGrid::SetColSize( int col, int width ) -{ - wxCHECK_RET( col >= 0 && col < m_numCols, _T("invalid column index") ); - - // should we check that it's bigger than GetColMinimalWidth(col) here? - // (VZ) - // No, because it is reasonable to assume the library user know's - // what he is doing. However we should test against the weaker - // constraint of minimalAcceptableWidth, as this breaks rendering - // - // This test then fixes sf.net bug #645734 - - if ( width < GetColMinimalAcceptableWidth() ) - return; - - if ( m_colWidths.IsEmpty() ) - { - // need to really create the array - InitColWidths(); - } - - // if < 0 then calculate new width from label - if ( width < 0 ) - { - long w, h; - wxArrayString lines; - wxClientDC dc(m_colLabelWin); - dc.SetFont(GetLabelFont()); - StringToLines(GetColLabelValue(col), lines); - GetTextBoxSize(dc, lines, &w, &h); - width = w + 6; - } - - int w = wxMax( 0, width ); - int diff = w - m_colWidths[col]; - m_colWidths[col] = w; - - for ( int colPos = GetColPos(col); colPos < m_numCols; colPos++ ) - { - m_colRights[GetColAt(colPos)] += diff; - } - - if ( !GetBatchCount() ) - CalcDimensions(); -} - -void wxGrid::SetColMinimalWidth( int col, int width ) -{ - if (width > GetColMinimalAcceptableWidth()) - { - wxLongToLongHashMap::key_type key = (wxLongToLongHashMap::key_type)col; - m_colMinWidths[key] = width; - } -} - -void wxGrid::SetRowMinimalHeight( int row, int width ) -{ - if (width > GetRowMinimalAcceptableHeight()) - { - wxLongToLongHashMap::key_type key = (wxLongToLongHashMap::key_type)row; - m_rowMinHeights[key] = width; - } -} - -int wxGrid::GetColMinimalWidth(int col) const -{ - wxLongToLongHashMap::key_type key = (wxLongToLongHashMap::key_type)col; - wxLongToLongHashMap::const_iterator it = m_colMinWidths.find(key); - - return it != m_colMinWidths.end() ? (int)it->second : m_minAcceptableColWidth; -} - -int wxGrid::GetRowMinimalHeight(int row) const -{ - wxLongToLongHashMap::key_type key = (wxLongToLongHashMap::key_type)row; - wxLongToLongHashMap::const_iterator it = m_rowMinHeights.find(key); - - return it != m_rowMinHeights.end() ? (int)it->second : m_minAcceptableRowHeight; -} - -void wxGrid::SetColMinimalAcceptableWidth( int width ) -{ - // We do allow a width of 0 since this gives us - // an easy way to temporarily hiding columns. - if ( width >= 0 ) - m_minAcceptableColWidth = width; -} - -void wxGrid::SetRowMinimalAcceptableHeight( int height ) -{ - // We do allow a height of 0 since this gives us - // an easy way to temporarily hiding rows. - if ( height >= 0 ) - m_minAcceptableRowHeight = height; -} - -int wxGrid::GetColMinimalAcceptableWidth() const -{ - return m_minAcceptableColWidth; -} - -int wxGrid::GetRowMinimalAcceptableHeight() const -{ - return m_minAcceptableRowHeight; -} - -// ---------------------------------------------------------------------------- -// auto sizing -// ---------------------------------------------------------------------------- - -void wxGrid::AutoSizeColOrRow( int colOrRow, bool setAsMin, bool column ) -{ - wxClientDC dc(m_gridWin); - - // cancel editing of cell - HideCellEditControl(); - SaveEditControlValue(); - - // init both of them to avoid compiler warnings, even if we only need one - int row = -1, - col = -1; - if ( column ) - col = colOrRow; - else - row = colOrRow; - - wxCoord extent, extentMax = 0; - int max = column ? m_numRows : m_numCols; - for ( int rowOrCol = 0; rowOrCol < max; rowOrCol++ ) - { - if ( column ) - row = rowOrCol; - else - col = rowOrCol; - - wxGridCellAttr *attr = GetCellAttr(row, col); - wxGridCellRenderer *renderer = attr->GetRenderer(this, row, col); - if ( renderer ) - { - wxSize size = renderer->GetBestSize(*this, *attr, dc, row, col); - extent = column ? size.x : size.y; - if ( extent > extentMax ) - extentMax = extent; - - renderer->DecRef(); - } - - attr->DecRef(); - } - - // now also compare with the column label extent - wxCoord w, h; - dc.SetFont( GetLabelFont() ); - - if ( column ) - { - dc.GetMultiLineTextExtent( GetColLabelValue(col), &w, &h ); - if ( GetColLabelTextOrientation() == wxVERTICAL ) - w = h; - } - else - dc.GetMultiLineTextExtent( GetRowLabelValue(row), &w, &h ); - - extent = column ? w : h; - if ( extent > extentMax ) - extentMax = extent; - - if ( !extentMax ) - { - // empty column - give default extent (notice that if extentMax is less - // than default extent but != 0, it's OK) - extentMax = column ? m_defaultColWidth : m_defaultRowHeight; - } - else - { - if ( column ) - // leave some space around text - extentMax += 10; - else - extentMax += 6; - } - - if ( column ) - { - // Ensure automatic width is not less than minimal width. See the - // comment in SetColSize() for explanation of why this isn't done - // in SetColSize(). - if ( !setAsMin ) - extentMax = wxMax(extentMax, GetColMinimalWidth(col)); - - SetColSize( col, extentMax ); - if ( !GetBatchCount() ) - { - int cw, ch, dummy; - m_gridWin->GetClientSize( &cw, &ch ); - wxRect rect ( CellToRect( 0, col ) ); - rect.y = 0; - CalcScrolledPosition(rect.x, 0, &rect.x, &dummy); - rect.width = cw - rect.x; - rect.height = m_colLabelHeight; - m_colLabelWin->Refresh( true, &rect ); - } - } - else - { - // Ensure automatic width is not less than minimal height. See the - // comment in SetColSize() for explanation of why this isn't done - // in SetRowSize(). - if ( !setAsMin ) - extentMax = wxMax(extentMax, GetRowMinimalHeight(row)); - - SetRowSize(row, extentMax); - if ( !GetBatchCount() ) - { - int cw, ch, dummy; - m_gridWin->GetClientSize( &cw, &ch ); - wxRect rect( CellToRect( row, 0 ) ); - rect.x = 0; - CalcScrolledPosition(0, rect.y, &dummy, &rect.y); - rect.width = m_rowLabelWidth; - rect.height = ch - rect.y; - m_rowLabelWin->Refresh( true, &rect ); - } - } - - if ( setAsMin ) - { - if ( column ) - SetColMinimalWidth(col, extentMax); - else - SetRowMinimalHeight(row, extentMax); - } -} - -wxCoord wxGrid::CalcColOrRowLabelAreaMinSize(bool column) -{ - // calculate size for the rows or columns? - const bool calcRows = !column; - - wxClientDC dc(calcRows ? GetGridRowLabelWindow() - : GetGridColLabelWindow()); - dc.SetFont(GetLabelFont()); - - // which dimension should we take into account for calculations? - // - // for columns, the text can be only horizontal so it's easy but for rows - // we also have to take into account the text orientation - const bool - useWidth = calcRows || (GetColLabelTextOrientation() == wxVERTICAL); - - wxArrayString lines; - wxCoord extentMax = 0; - - const int numRowsOrCols = calcRows ? m_numRows : m_numCols; - for ( int rowOrCol = 0; rowOrCol < numRowsOrCols; rowOrCol++ ) - { - lines.Clear(); - // NB: extra parentheses needed to avoid bcc 5.82 compilation errors - StringToLines((calcRows ? GetRowLabelValue(rowOrCol) - : GetColLabelValue(rowOrCol)), - lines); - - long w, h; - GetTextBoxSize(dc, lines, &w, &h); - - const wxCoord extent = useWidth ? w : h; - if ( extent > extentMax ) - extentMax = extent; - } - - if ( !extentMax ) - { - // empty column - give default extent (notice that if extentMax is less - // than default extent but != 0, it's OK) - extentMax = calcRows ? GetDefaultRowLabelSize() - : GetDefaultColLabelSize(); - } - - // leave some space around text (taken from AutoSizeColOrRow) - if ( calcRows ) - extentMax += 10; - else - extentMax += 6; - - return extentMax; -} - -int wxGrid::SetOrCalcColumnSizes(bool calcOnly, bool setAsMin) -{ - int width = m_rowLabelWidth; - - if ( !calcOnly ) - BeginBatch(); - - for ( int col = 0; col < m_numCols; col++ ) - { - if ( !calcOnly ) - AutoSizeColumn(col, setAsMin); - - width += GetColWidth(col); - } - - if ( !calcOnly ) - EndBatch(); - - return width; -} - -int wxGrid::SetOrCalcRowSizes(bool calcOnly, bool setAsMin) -{ - int height = m_colLabelHeight; - - if ( !calcOnly ) - BeginBatch(); - - for ( int row = 0; row < m_numRows; row++ ) - { - if ( !calcOnly ) - AutoSizeRow(row, setAsMin); - - height += GetRowHeight(row); - } - - if ( !calcOnly ) - EndBatch(); - - return height; -} - -void wxGrid::AutoSize() -{ - BeginBatch(); - - // we need to round up the size of the scrollable area to a multiple of - // scroll step to ensure that we don't get the scrollbars when we're sized - // exactly to fit our contents - wxSize size(SetOrCalcColumnSizes(false) - m_rowLabelWidth + m_extraWidth, - SetOrCalcRowSizes(false) - m_colLabelHeight + m_extraHeight); - wxSize sizeFit(GetScrollX(size.x) * GetScrollLineX(), - GetScrollY(size.y) * GetScrollLineY()); - - // distribute the extra space between the columns/rows to avoid having - // extra white space - wxCoord diff = sizeFit.x - size.x; - if ( diff && m_numCols ) - { - // try to resize the columns uniformly - wxCoord diffPerCol = diff / m_numCols; - if ( diffPerCol ) - { - for ( int col = 0; col < m_numCols; col++ ) - { - SetColSize(col, GetColWidth(col) + diffPerCol); - } - } - - // add remaining amount to the last columns - diff -= diffPerCol * m_numCols; - if ( diff ) - { - for ( int col = m_numCols - 1; col >= m_numCols - diff; col-- ) - { - SetColSize(col, GetColWidth(col) + 1); - } - } - } - - // same for rows - diff = sizeFit.y - size.y; - if ( diff && m_numRows ) - { - // try to resize the columns uniformly - wxCoord diffPerRow = diff / m_numRows; - if ( diffPerRow ) - { - for ( int row = 0; row < m_numRows; row++ ) - { - SetRowSize(row, GetRowHeight(row) + diffPerRow); - } - } - - // add remaining amount to the last rows - diff -= diffPerRow * m_numRows; - if ( diff ) - { - for ( int row = m_numRows - 1; row >= m_numRows - diff; row-- ) - { - SetRowSize(row, GetRowHeight(row) + 1); - } - } - } - - // we know that we're not going to have scrollbars so disable them now to - // avoid trouble in SetClientSize() which can otherwise set the correct - // client size but also leave space for (not needed any more) scrollbars - SetScrollbars(0, 0, 0, 0, 0, 0, true); - SetClientSize(sizeFit.x + m_rowLabelWidth, sizeFit.y + m_colLabelHeight); - - EndBatch(); -} - -void wxGrid::AutoSizeRowLabelSize( int row ) -{ - wxArrayString lines; - long w, h; - - // Hide the edit control, so it - // won't interfere with drag-shrinking. - if ( IsCellEditControlShown() ) - { - HideCellEditControl(); - SaveEditControlValue(); - } - - // autosize row height depending on label text - StringToLines( GetRowLabelValue( row ), lines ); - wxClientDC dc( m_rowLabelWin ); - GetTextBoxSize( dc, lines, &w, &h ); - if ( h < m_defaultRowHeight ) - h = m_defaultRowHeight; - SetRowSize(row, h); - ForceRefresh(); -} - -void wxGrid::AutoSizeColLabelSize( int col ) -{ - wxArrayString lines; - long w, h; - - // Hide the edit control, so it - // won't interfere with drag-shrinking. - if ( IsCellEditControlShown() ) - { - HideCellEditControl(); - SaveEditControlValue(); - } - - // autosize column width depending on label text - StringToLines( GetColLabelValue( col ), lines ); - wxClientDC dc( m_colLabelWin ); - if ( GetColLabelTextOrientation() == wxHORIZONTAL ) - GetTextBoxSize( dc, lines, &w, &h ); - else - GetTextBoxSize( dc, lines, &h, &w ); - if ( w < m_defaultColWidth ) - w = m_defaultColWidth; - SetColSize(col, w); - ForceRefresh(); -} - -wxSize wxGrid::DoGetBestSize() const -{ - wxGrid *self = (wxGrid *)this; // const_cast - - // we do the same as in AutoSize() here with the exception that we don't - // change the column/row sizes, only calculate them - wxSize size(self->SetOrCalcColumnSizes(true) - m_rowLabelWidth + m_extraWidth, - self->SetOrCalcRowSizes(true) - m_colLabelHeight + m_extraHeight); - wxSize sizeFit(GetScrollX(size.x) * GetScrollLineX(), - GetScrollY(size.y) * GetScrollLineY()); - - // NOTE: This size should be cached, but first we need to add calls to - // InvalidateBestSize everywhere that could change the results of this - // calculation. - // CacheBestSize(size); - - return wxSize(sizeFit.x + m_rowLabelWidth, sizeFit.y + m_colLabelHeight) - + GetWindowBorderSize(); -} - -void wxGrid::Fit() -{ - AutoSize(); -} - -wxPen& wxGrid::GetDividerPen() const -{ - return wxNullPen; -} - -// ---------------------------------------------------------------------------- -// cell value accessor functions -// ---------------------------------------------------------------------------- - -void wxGrid::SetCellValue( int row, int col, const wxString& s ) -{ - if ( m_table ) - { - m_table->SetValue( row, col, s ); - if ( !GetBatchCount() ) - { - int dummy; - wxRect rect( CellToRect( row, col ) ); - rect.x = 0; - rect.width = m_gridWin->GetClientSize().GetWidth(); - CalcScrolledPosition(0, rect.y, &dummy, &rect.y); - m_gridWin->Refresh( false, &rect ); - } - - if ( m_currentCellCoords.GetRow() == row && - m_currentCellCoords.GetCol() == col && - IsCellEditControlShown()) - // Note: If we are using IsCellEditControlEnabled, - // this interacts badly with calling SetCellValue from - // an EVT_GRID_CELL_CHANGE handler. - { - HideCellEditControl(); - ShowCellEditControl(); // will reread data from table - } - } -} - -// ---------------------------------------------------------------------------- -// block, row and column selection -// ---------------------------------------------------------------------------- - -void wxGrid::SelectRow( int row, bool addToSelected ) -{ - if ( IsSelection() && !addToSelected ) - ClearSelection(); - - if ( m_selection ) - m_selection->SelectRow( row, false, addToSelected ); -} - -void wxGrid::SelectCol( int col, bool addToSelected ) -{ - if ( IsSelection() && !addToSelected ) - ClearSelection(); - - if ( m_selection ) - m_selection->SelectCol( col, false, addToSelected ); -} - -void wxGrid::SelectBlock( int topRow, int leftCol, int bottomRow, int rightCol, - bool addToSelected ) -{ - if ( IsSelection() && !addToSelected ) - ClearSelection(); - - if ( m_selection ) - m_selection->SelectBlock( topRow, leftCol, bottomRow, rightCol, - false, addToSelected ); -} - -void wxGrid::SelectAll() -{ - if ( m_numRows > 0 && m_numCols > 0 ) - { - if ( m_selection ) - m_selection->SelectBlock( 0, 0, m_numRows - 1, m_numCols - 1 ); - } -} - -// ---------------------------------------------------------------------------- -// cell, row and col deselection -// ---------------------------------------------------------------------------- - -void wxGrid::DeselectRow( int row ) -{ - if ( !m_selection ) - return; - - if ( m_selection->GetSelectionMode() == wxGrid::wxGridSelectRows ) - { - if ( m_selection->IsInSelection(row, 0 ) ) - m_selection->ToggleCellSelection(row, 0); - } - else - { - int nCols = GetNumberCols(); - for ( int i = 0; i < nCols; i++ ) - { - if ( m_selection->IsInSelection(row, i ) ) - m_selection->ToggleCellSelection(row, i); - } - } -} - -void wxGrid::DeselectCol( int col ) -{ - if ( !m_selection ) - return; - - if ( m_selection->GetSelectionMode() == wxGrid::wxGridSelectColumns ) - { - if ( m_selection->IsInSelection(0, col ) ) - m_selection->ToggleCellSelection(0, col); - } - else - { - int nRows = GetNumberRows(); - for ( int i = 0; i < nRows; i++ ) - { - if ( m_selection->IsInSelection(i, col ) ) - m_selection->ToggleCellSelection(i, col); - } - } -} - -void wxGrid::DeselectCell( int row, int col ) -{ - if ( m_selection && m_selection->IsInSelection(row, col) ) - m_selection->ToggleCellSelection(row, col); -} - -bool wxGrid::IsSelection() -{ - return ( m_selection && (m_selection->IsSelection() || - ( m_selectingTopLeft != wxGridNoCellCoords && - m_selectingBottomRight != wxGridNoCellCoords) ) ); -} - -bool wxGrid::IsInSelection( int row, int col ) const -{ - return ( m_selection && (m_selection->IsInSelection( row, col ) || - ( row >= m_selectingTopLeft.GetRow() && - col >= m_selectingTopLeft.GetCol() && - row <= m_selectingBottomRight.GetRow() && - col <= m_selectingBottomRight.GetCol() )) ); -} - -wxGridCellCoordsArray wxGrid::GetSelectedCells() const -{ - if (!m_selection) - { - wxGridCellCoordsArray a; - return a; - } - - return m_selection->m_cellSelection; -} - -wxGridCellCoordsArray wxGrid::GetSelectionBlockTopLeft() const -{ - if (!m_selection) - { - wxGridCellCoordsArray a; - return a; - } - - return m_selection->m_blockSelectionTopLeft; -} - -wxGridCellCoordsArray wxGrid::GetSelectionBlockBottomRight() const -{ - if (!m_selection) - { - wxGridCellCoordsArray a; - return a; - } - - return m_selection->m_blockSelectionBottomRight; -} - -wxArrayInt wxGrid::GetSelectedRows() const -{ - if (!m_selection) - { - wxArrayInt a; - return a; - } - - return m_selection->m_rowSelection; -} - -wxArrayInt wxGrid::GetSelectedCols() const -{ - if (!m_selection) - { - wxArrayInt a; - return a; - } - - return m_selection->m_colSelection; -} - -void wxGrid::ClearSelection() -{ - wxRect r1 = BlockToDeviceRect( m_selectingTopLeft, m_selectingBottomRight); - wxRect r2 = BlockToDeviceRect( m_currentCellCoords, m_selectingKeyboard ); - m_selectingTopLeft = - m_selectingBottomRight = - m_selectingKeyboard = wxGridNoCellCoords; - Refresh( false, &r1 ); - Refresh( false, &r2 ); - if ( m_selection ) - m_selection->ClearSelection(); -} - -// This function returns the rectangle that encloses the given block -// in device coords clipped to the client size of the grid window. -// -wxRect wxGrid::BlockToDeviceRect( const wxGridCellCoords &topLeft, - const wxGridCellCoords &bottomRight ) -{ - wxRect rect( wxGridNoCellRect ); - wxRect cellRect; - - cellRect = CellToRect( topLeft ); - if ( cellRect != wxGridNoCellRect ) - { - rect = cellRect; - } - else - { - rect = wxRect(0, 0, 0, 0); - } - - cellRect = CellToRect( bottomRight ); - if ( cellRect != wxGridNoCellRect ) - { - rect += cellRect; - } - else - { - return wxGridNoCellRect; - } - - int i, j; - int left = rect.GetLeft(); - int top = rect.GetTop(); - int right = rect.GetRight(); - int bottom = rect.GetBottom(); - - int leftCol = topLeft.GetCol(); - int topRow = topLeft.GetRow(); - int rightCol = bottomRight.GetCol(); - int bottomRow = bottomRight.GetRow(); - - if (left > right) - { - i = left; - left = right; - right = i; - i = leftCol; - leftCol = rightCol; - rightCol = i; - } - - if (top > bottom) - { - i = top; - top = bottom; - bottom = i; - i = topRow; - topRow = bottomRow; - bottomRow = i; - } - - for ( j = topRow; j <= bottomRow; j++ ) - { - for ( i = leftCol; i <= rightCol; i++ ) - { - if ((j == topRow) || (j == bottomRow) || (i == leftCol) || (i == rightCol)) - { - cellRect = CellToRect( j, i ); - - if (cellRect.x < left) - left = cellRect.x; - if (cellRect.y < top) - top = cellRect.y; - if (cellRect.x + cellRect.width > right) - right = cellRect.x + cellRect.width; - if (cellRect.y + cellRect.height > bottom) - bottom = cellRect.y + cellRect.height; - } - else - { - i = rightCol; // jump over inner cells. - } - } - } - - // convert to scrolled coords - // - CalcScrolledPosition( left, top, &left, &top ); - CalcScrolledPosition( right, bottom, &right, &bottom ); - - int cw, ch; - m_gridWin->GetClientSize( &cw, &ch ); - - if (right < 0 || bottom < 0 || left > cw || top > ch) - return wxRect(0,0,0,0); - - rect.SetLeft( wxMax(0, left) ); - rect.SetTop( wxMax(0, top) ); - rect.SetRight( wxMin(cw, right) ); - rect.SetBottom( wxMin(ch, bottom) ); - - return rect; -} - -// ---------------------------------------------------------------------------- -// grid event classes -// ---------------------------------------------------------------------------- - -IMPLEMENT_DYNAMIC_CLASS( wxGridEvent, wxNotifyEvent ) - -wxGridEvent::wxGridEvent( int id, wxEventType type, wxObject* obj, - int row, int col, int x, int y, bool sel, - bool control, bool shift, bool alt, bool meta ) - : wxNotifyEvent( type, id ) -{ - m_row = row; - m_col = col; - m_x = x; - m_y = y; - m_selecting = sel; - m_control = control; - m_shift = shift; - m_alt = alt; - m_meta = meta; - - SetEventObject(obj); -} - - -IMPLEMENT_DYNAMIC_CLASS( wxGridSizeEvent, wxNotifyEvent ) - -wxGridSizeEvent::wxGridSizeEvent( int id, wxEventType type, wxObject* obj, - int rowOrCol, int x, int y, - bool control, bool shift, bool alt, bool meta ) - : wxNotifyEvent( type, id ) -{ - m_rowOrCol = rowOrCol; - m_x = x; - m_y = y; - m_control = control; - m_shift = shift; - m_alt = alt; - m_meta = meta; - - SetEventObject(obj); -} - - -IMPLEMENT_DYNAMIC_CLASS( wxGridRangeSelectEvent, wxNotifyEvent ) - -wxGridRangeSelectEvent::wxGridRangeSelectEvent(int id, wxEventType type, wxObject* obj, - const wxGridCellCoords& topLeft, - const wxGridCellCoords& bottomRight, - bool sel, bool control, - bool shift, bool alt, bool meta ) - : wxNotifyEvent( type, id ) -{ - m_topLeft = topLeft; - m_bottomRight = bottomRight; - m_selecting = sel; - m_control = control; - m_shift = shift; - m_alt = alt; - m_meta = meta; - - SetEventObject(obj); -} - - -IMPLEMENT_DYNAMIC_CLASS(wxGridEditorCreatedEvent, wxCommandEvent) - -wxGridEditorCreatedEvent::wxGridEditorCreatedEvent(int id, wxEventType type, - wxObject* obj, int row, - int col, wxControl* ctrl) - : wxCommandEvent(type, id) -{ - SetEventObject(obj); - m_row = row; - m_col = col; - m_ctrl = ctrl; -} - -#endif // wxUSE_GRID +/////////////////////////////////////////////////////////////////////////// +// Name: src/generic/grid.cpp +// Purpose: wxGrid and related classes +// Author: Michael Bedward (based on code by Julian Smart, Robin Dunn) +// Modified by: Robin Dunn, Vadim Zeitlin, Santiago Palacios +// Created: 1/08/1999 +// RCS-ID: $Id: grid.cpp 54276 2008-06-18 11:21:57Z SN $ +// Copyright: (c) Michael Bedward (mbedward@ozemail.com.au) +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx/wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_GRID + +#include "wx/grid.h" + +#ifndef WX_PRECOMP + #include "wx/utils.h" + #include "wx/dcclient.h" + #include "wx/settings.h" + #include "wx/log.h" + #include "wx/textctrl.h" + #include "wx/checkbox.h" + #include "wx/combobox.h" + #include "wx/valtext.h" + #include "wx/intl.h" + #include "wx/math.h" + #include "wx/listbox.h" +#endif + +#include "wx/textfile.h" +#include "wx/spinctrl.h" +#include "wx/tokenzr.h" +#include "wx/renderer.h" + +#include "wx/generic/gridsel.h" + +const wxChar wxGridNameStr[] = wxT("grid"); + +#if defined(__WXMOTIF__) + #define WXUNUSED_MOTIF(identifier) WXUNUSED(identifier) +#else + #define WXUNUSED_MOTIF(identifier) identifier +#endif + +#if defined(__WXGTK__) + #define WXUNUSED_GTK(identifier) WXUNUSED(identifier) +#else + #define WXUNUSED_GTK(identifier) identifier +#endif + +// Required for wxIs... functions +#include + +// ---------------------------------------------------------------------------- +// array classes +// ---------------------------------------------------------------------------- + +WX_DEFINE_ARRAY_WITH_DECL_PTR(wxGridCellAttr *, wxArrayAttrs, + class WXDLLIMPEXP_ADV); + +struct wxGridCellWithAttr +{ + wxGridCellWithAttr(int row, int col, wxGridCellAttr *attr_) + : coords(row, col), attr(attr_) + { + wxASSERT( attr ); + } + + wxGridCellWithAttr(const wxGridCellWithAttr& other) + : coords(other.coords), + attr(other.attr) + { + attr->IncRef(); + } + + wxGridCellWithAttr& operator=(const wxGridCellWithAttr& other) + { + coords = other.coords; + if (attr != other.attr) + { + attr->DecRef(); + attr = other.attr; + attr->IncRef(); + } + return *this; + } + + void ChangeAttr(wxGridCellAttr * new_attr) + { + if (attr != new_attr) + { + // "Delete" (i.e. DecRef) the old attribute. + attr->DecRef(); + attr = new_attr; + // Take ownership of the new attribute, i.e. no IncRef. + } + } + + ~wxGridCellWithAttr() + { + attr->DecRef(); + } + + wxGridCellCoords coords; + wxGridCellAttr *attr; +}; + +WX_DECLARE_OBJARRAY_WITH_DECL(wxGridCellWithAttr, wxGridCellWithAttrArray, + class WXDLLIMPEXP_ADV); + +#include "wx/arrimpl.cpp" + +WX_DEFINE_OBJARRAY(wxGridCellCoordsArray) +WX_DEFINE_OBJARRAY(wxGridCellWithAttrArray) + +// ---------------------------------------------------------------------------- +// events +// ---------------------------------------------------------------------------- + +DEFINE_EVENT_TYPE(wxEVT_GRID_CELL_LEFT_CLICK) +DEFINE_EVENT_TYPE(wxEVT_GRID_CELL_RIGHT_CLICK) +DEFINE_EVENT_TYPE(wxEVT_GRID_CELL_LEFT_DCLICK) +DEFINE_EVENT_TYPE(wxEVT_GRID_CELL_RIGHT_DCLICK) +DEFINE_EVENT_TYPE(wxEVT_GRID_CELL_BEGIN_DRAG) +DEFINE_EVENT_TYPE(wxEVT_GRID_LABEL_LEFT_CLICK) +DEFINE_EVENT_TYPE(wxEVT_GRID_LABEL_RIGHT_CLICK) +DEFINE_EVENT_TYPE(wxEVT_GRID_LABEL_LEFT_DCLICK) +DEFINE_EVENT_TYPE(wxEVT_GRID_LABEL_RIGHT_DCLICK) +DEFINE_EVENT_TYPE(wxEVT_GRID_ROW_SIZE) +DEFINE_EVENT_TYPE(wxEVT_GRID_COL_SIZE) +DEFINE_EVENT_TYPE(wxEVT_GRID_COL_MOVE) +DEFINE_EVENT_TYPE(wxEVT_GRID_RANGE_SELECT) +DEFINE_EVENT_TYPE(wxEVT_GRID_CELL_CHANGE) +DEFINE_EVENT_TYPE(wxEVT_GRID_SELECT_CELL) +DEFINE_EVENT_TYPE(wxEVT_GRID_EDITOR_SHOWN) +DEFINE_EVENT_TYPE(wxEVT_GRID_EDITOR_HIDDEN) +DEFINE_EVENT_TYPE(wxEVT_GRID_EDITOR_CREATED) + +// ---------------------------------------------------------------------------- +// private classes +// ---------------------------------------------------------------------------- + +class WXDLLIMPEXP_ADV wxGridRowLabelWindow : public wxWindow +{ +public: + wxGridRowLabelWindow() { m_owner = (wxGrid *)NULL; } + wxGridRowLabelWindow( wxGrid *parent, wxWindowID id, + const wxPoint &pos, const wxSize &size ); + + virtual bool AcceptsFocus() const { return false; } + +private: + wxGrid *m_owner; + + void OnPaint( wxPaintEvent& event ); + void OnMouseEvent( wxMouseEvent& event ); + void OnMouseWheel( wxMouseEvent& event ); + void OnKeyDown( wxKeyEvent& event ); + void OnKeyUp( wxKeyEvent& ); + void OnChar( wxKeyEvent& ); + + DECLARE_DYNAMIC_CLASS(wxGridRowLabelWindow) + DECLARE_EVENT_TABLE() + DECLARE_NO_COPY_CLASS(wxGridRowLabelWindow) +}; + + +class WXDLLIMPEXP_ADV wxGridColLabelWindow : public wxWindow +{ +public: + wxGridColLabelWindow() { m_owner = (wxGrid *)NULL; } + wxGridColLabelWindow( wxGrid *parent, wxWindowID id, + const wxPoint &pos, const wxSize &size ); + + virtual bool AcceptsFocus() const { return false; } + +private: + wxGrid *m_owner; + + void OnPaint( wxPaintEvent& event ); + void OnMouseEvent( wxMouseEvent& event ); + void OnMouseWheel( wxMouseEvent& event ); + void OnKeyDown( wxKeyEvent& event ); + void OnKeyUp( wxKeyEvent& ); + void OnChar( wxKeyEvent& ); + + DECLARE_DYNAMIC_CLASS(wxGridColLabelWindow) + DECLARE_EVENT_TABLE() + DECLARE_NO_COPY_CLASS(wxGridColLabelWindow) +}; + + +class WXDLLIMPEXP_ADV wxGridCornerLabelWindow : public wxWindow +{ +public: + wxGridCornerLabelWindow() { m_owner = (wxGrid *)NULL; } + wxGridCornerLabelWindow( wxGrid *parent, wxWindowID id, + const wxPoint &pos, const wxSize &size ); + + virtual bool AcceptsFocus() const { return false; } + +private: + wxGrid *m_owner; + + void OnMouseEvent( wxMouseEvent& event ); + void OnMouseWheel( wxMouseEvent& event ); + void OnKeyDown( wxKeyEvent& event ); + void OnKeyUp( wxKeyEvent& ); + void OnChar( wxKeyEvent& ); + void OnPaint( wxPaintEvent& event ); + + DECLARE_DYNAMIC_CLASS(wxGridCornerLabelWindow) + DECLARE_EVENT_TABLE() + DECLARE_NO_COPY_CLASS(wxGridCornerLabelWindow) +}; + +class WXDLLIMPEXP_ADV wxGridWindow : public wxWindow +{ +public: + wxGridWindow() + { + m_owner = NULL; + m_rowLabelWin = NULL; + m_colLabelWin = NULL; + } + + wxGridWindow( wxGrid *parent, + wxGridRowLabelWindow *rowLblWin, + wxGridColLabelWindow *colLblWin, + wxWindowID id, const wxPoint &pos, const wxSize &size ); + virtual ~wxGridWindow() {} + + void ScrollWindow( int dx, int dy, const wxRect *rect ); + + wxGrid* GetOwner() { return m_owner; } + +private: + wxGrid *m_owner; + wxGridRowLabelWindow *m_rowLabelWin; + wxGridColLabelWindow *m_colLabelWin; + + void OnPaint( wxPaintEvent &event ); + void OnMouseWheel( wxMouseEvent& event ); + void OnMouseEvent( wxMouseEvent& event ); + void OnKeyDown( wxKeyEvent& ); + void OnKeyUp( wxKeyEvent& ); + void OnChar( wxKeyEvent& ); + void OnEraseBackground( wxEraseEvent& ); + void OnFocus( wxFocusEvent& ); + + DECLARE_DYNAMIC_CLASS(wxGridWindow) + DECLARE_EVENT_TABLE() + DECLARE_NO_COPY_CLASS(wxGridWindow) +}; + + +class wxGridCellEditorEvtHandler : public wxEvtHandler +{ +public: + wxGridCellEditorEvtHandler(wxGrid* grid, wxGridCellEditor* editor) + : m_grid(grid), + m_editor(editor), + m_inSetFocus(false) + { + } + + void OnKillFocus(wxFocusEvent& event); + void OnKeyDown(wxKeyEvent& event); + void OnChar(wxKeyEvent& event); + + void SetInSetFocus(bool inSetFocus) { m_inSetFocus = inSetFocus; } + +private: + wxGrid *m_grid; + wxGridCellEditor *m_editor; + + // Work around the fact that a focus kill event can be sent to + // a combobox within a set focus event. + bool m_inSetFocus; + + DECLARE_EVENT_TABLE() + DECLARE_DYNAMIC_CLASS(wxGridCellEditorEvtHandler) + DECLARE_NO_COPY_CLASS(wxGridCellEditorEvtHandler) +}; + + +IMPLEMENT_ABSTRACT_CLASS(wxGridCellEditorEvtHandler, wxEvtHandler) + +BEGIN_EVENT_TABLE( wxGridCellEditorEvtHandler, wxEvtHandler ) + EVT_KILL_FOCUS( wxGridCellEditorEvtHandler::OnKillFocus ) + EVT_KEY_DOWN( wxGridCellEditorEvtHandler::OnKeyDown ) + EVT_CHAR( wxGridCellEditorEvtHandler::OnChar ) +END_EVENT_TABLE() + + +// ---------------------------------------------------------------------------- +// the internal data representation used by wxGridCellAttrProvider +// ---------------------------------------------------------------------------- + +// this class stores attributes set for cells +class WXDLLIMPEXP_ADV wxGridCellAttrData +{ +public: + void SetAttr(wxGridCellAttr *attr, int row, int col); + wxGridCellAttr *GetAttr(int row, int col) const; + void UpdateAttrRows( size_t pos, int numRows ); + void UpdateAttrCols( size_t pos, int numCols ); + +private: + // searches for the attr for given cell, returns wxNOT_FOUND if not found + int FindIndex(int row, int col) const; + + wxGridCellWithAttrArray m_attrs; +}; + +// this class stores attributes set for rows or columns +class WXDLLIMPEXP_ADV wxGridRowOrColAttrData +{ +public: + // empty ctor to suppress warnings + wxGridRowOrColAttrData() {} + ~wxGridRowOrColAttrData(); + + void SetAttr(wxGridCellAttr *attr, int rowOrCol); + wxGridCellAttr *GetAttr(int rowOrCol) const; + void UpdateAttrRowsOrCols( size_t pos, int numRowsOrCols ); + +private: + wxArrayInt m_rowsOrCols; + wxArrayAttrs m_attrs; +}; + +// NB: this is just a wrapper around 3 objects: one which stores cell +// attributes, and 2 others for row/col ones +class WXDLLIMPEXP_ADV wxGridCellAttrProviderData +{ +public: + wxGridCellAttrData m_cellAttrs; + wxGridRowOrColAttrData m_rowAttrs, + m_colAttrs; +}; + + +// ---------------------------------------------------------------------------- +// data structures used for the data type registry +// ---------------------------------------------------------------------------- + +struct wxGridDataTypeInfo +{ + wxGridDataTypeInfo(const wxString& typeName, + wxGridCellRenderer* renderer, + wxGridCellEditor* editor) + : m_typeName(typeName), m_renderer(renderer), m_editor(editor) + {} + + ~wxGridDataTypeInfo() + { + wxSafeDecRef(m_renderer); + wxSafeDecRef(m_editor); + } + + wxString m_typeName; + wxGridCellRenderer* m_renderer; + wxGridCellEditor* m_editor; + + DECLARE_NO_COPY_CLASS(wxGridDataTypeInfo) +}; + + +WX_DEFINE_ARRAY_WITH_DECL_PTR(wxGridDataTypeInfo*, wxGridDataTypeInfoArray, + class WXDLLIMPEXP_ADV); + + +class WXDLLIMPEXP_ADV wxGridTypeRegistry +{ +public: + wxGridTypeRegistry() {} + ~wxGridTypeRegistry(); + + void RegisterDataType(const wxString& typeName, + wxGridCellRenderer* renderer, + wxGridCellEditor* editor); + + // find one of already registered data types + int FindRegisteredDataType(const wxString& typeName); + + // try to FindRegisteredDataType(), if this fails and typeName is one of + // standard typenames, register it and return its index + int FindDataType(const wxString& typeName); + + // try to FindDataType(), if it fails see if it is not one of already + // registered data types with some params in which case clone the + // registered data type and set params for it + int FindOrCloneDataType(const wxString& typeName); + + wxGridCellRenderer* GetRenderer(int index); + wxGridCellEditor* GetEditor(int index); + +private: + wxGridDataTypeInfoArray m_typeinfo; +}; + + +// ---------------------------------------------------------------------------- +// conditional compilation +// ---------------------------------------------------------------------------- + +#ifndef WXGRID_DRAW_LINES +#define WXGRID_DRAW_LINES 1 +#endif + +// ---------------------------------------------------------------------------- +// globals +// ---------------------------------------------------------------------------- + +//#define DEBUG_ATTR_CACHE +#ifdef DEBUG_ATTR_CACHE + static size_t gs_nAttrCacheHits = 0; + static size_t gs_nAttrCacheMisses = 0; +#endif + +// ---------------------------------------------------------------------------- +// constants +// ---------------------------------------------------------------------------- + +wxGridCellCoords wxGridNoCellCoords( -1, -1 ); +wxRect wxGridNoCellRect( -1, -1, -1, -1 ); + +// scroll line size +// TODO: this doesn't work at all, grid cells have different sizes and approx +// calculations don't work as because of the size mismatch scrollbars +// sometimes fail to be shown when they should be or vice versa +// +// The scroll bars may be a little flakey once in a while, but that is +// surely much less horrible than having scroll lines of only 1!!! +// -- Robin +// +// Well, it's still seriously broken so it might be better but needs +// fixing anyhow +// -- Vadim +static const size_t GRID_SCROLL_LINE_X = 15; // 1; +static const size_t GRID_SCROLL_LINE_Y = GRID_SCROLL_LINE_X; + +// the size of hash tables used a bit everywhere (the max number of elements +// in these hash tables is the number of rows/columns) +static const int GRID_HASH_SIZE = 100; + +#if 0 +// ---------------------------------------------------------------------------- +// private functions +// ---------------------------------------------------------------------------- + +static inline int GetScrollX(int x) +{ + return (x + GRID_SCROLL_LINE_X - 1) / GRID_SCROLL_LINE_X; +} + +static inline int GetScrollY(int y) +{ + return (y + GRID_SCROLL_LINE_Y - 1) / GRID_SCROLL_LINE_Y; +} +#endif + +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// wxGridCellEditor +// ---------------------------------------------------------------------------- + +wxGridCellEditor::wxGridCellEditor() +{ + m_control = NULL; + m_attr = NULL; +} + +wxGridCellEditor::~wxGridCellEditor() +{ + Destroy(); +} + +void wxGridCellEditor::Create(wxWindow* WXUNUSED(parent), + wxWindowID WXUNUSED(id), + wxEvtHandler* evtHandler) +{ + if ( evtHandler ) + m_control->PushEventHandler(evtHandler); +} + +void wxGridCellEditor::PaintBackground(const wxRect& rectCell, + wxGridCellAttr *attr) +{ + // erase the background because we might not fill the cell + wxClientDC dc(m_control->GetParent()); + wxGridWindow* gridWindow = wxDynamicCast(m_control->GetParent(), wxGridWindow); + if (gridWindow) + gridWindow->GetOwner()->PrepareDC(dc); + + dc.SetPen(*wxTRANSPARENT_PEN); + dc.SetBrush(wxBrush(attr->GetBackgroundColour(), wxSOLID)); + dc.DrawRectangle(rectCell); + + // redraw the control we just painted over + m_control->Refresh(); +} + +void wxGridCellEditor::Destroy() +{ + if (m_control) + { + m_control->PopEventHandler( true /* delete it*/ ); + + m_control->Destroy(); + m_control = NULL; + } +} + +void wxGridCellEditor::Show(bool show, wxGridCellAttr *attr) +{ + wxASSERT_MSG(m_control, wxT("The wxGridCellEditor must be created first!")); + + m_control->Show(show); + + if ( show ) + { + // set the colours/fonts if we have any + if ( attr ) + { + m_colFgOld = m_control->GetForegroundColour(); + m_control->SetForegroundColour(attr->GetTextColour()); + + m_colBgOld = m_control->GetBackgroundColour(); + m_control->SetBackgroundColour(attr->GetBackgroundColour()); + +// Workaround for GTK+1 font setting problem on some platforms +#if !defined(__WXGTK__) || defined(__WXGTK20__) + m_fontOld = m_control->GetFont(); + m_control->SetFont(attr->GetFont()); +#endif + + // can't do anything more in the base class version, the other + // attributes may only be used by the derived classes + } + } + else + { + // restore the standard colours fonts + if ( m_colFgOld.Ok() ) + { + m_control->SetForegroundColour(m_colFgOld); + m_colFgOld = wxNullColour; + } + + if ( m_colBgOld.Ok() ) + { + m_control->SetBackgroundColour(m_colBgOld); + m_colBgOld = wxNullColour; + } + +// Workaround for GTK+1 font setting problem on some platforms +#if !defined(__WXGTK__) || defined(__WXGTK20__) + if ( m_fontOld.Ok() ) + { + m_control->SetFont(m_fontOld); + m_fontOld = wxNullFont; + } +#endif + } +} + +void wxGridCellEditor::SetSize(const wxRect& rect) +{ + wxASSERT_MSG(m_control, wxT("The wxGridCellEditor must be created first!")); + + m_control->SetSize(rect, wxSIZE_ALLOW_MINUS_ONE); +} + +void wxGridCellEditor::HandleReturn(wxKeyEvent& event) +{ + event.Skip(); +} + +bool wxGridCellEditor::IsAcceptedKey(wxKeyEvent& event) +{ + bool ctrl = event.ControlDown(); + bool alt = event.AltDown(); + +#ifdef __WXMAC__ + // On the Mac the Alt key is more like shift and is used for entry of + // valid characters, so check for Ctrl and Meta instead. + alt = event.MetaDown(); +#endif + + // Assume it's not a valid char if ctrl or alt is down, but if both are + // down then it may be because of an AltGr key combination, so let them + // through in that case. + if ((ctrl || alt) && !(ctrl && alt)) + return false; + + int key = 0; + bool keyOk = true; + +#ifdef __WXGTK20__ + // If it's a F-Key or other special key then it shouldn't start the + // editor. + if (event.GetKeyCode() >= WXK_START) + return false; +#endif +#if wxUSE_UNICODE + // if the unicode key code is not really a unicode character (it may + // be a function key or etc., the platforms appear to always give us a + // small value in this case) then fallback to the ASCII key code but + // don't do anything for function keys or etc. + key = event.GetUnicodeKey(); + if (key <= 127) + { + key = event.GetKeyCode(); + keyOk = (key <= 127); + } +#else + key = event.GetKeyCode(); + keyOk = (key <= 255); +#endif + + return keyOk; +} + +void wxGridCellEditor::StartingKey(wxKeyEvent& event) +{ + event.Skip(); +} + +void wxGridCellEditor::StartingClick() +{ +} + +#if wxUSE_TEXTCTRL + +// ---------------------------------------------------------------------------- +// wxGridCellTextEditor +// ---------------------------------------------------------------------------- + +wxGridCellTextEditor::wxGridCellTextEditor() +{ + m_maxChars = 0; +} + +void wxGridCellTextEditor::Create(wxWindow* parent, + wxWindowID id, + wxEvtHandler* evtHandler) +{ + m_control = new wxTextCtrl(parent, id, wxEmptyString, + wxDefaultPosition, wxDefaultSize +#if defined(__WXMSW__) + , + wxTE_PROCESS_ENTER | + wxTE_PROCESS_TAB | + wxTE_AUTO_SCROLL | + wxNO_BORDER +#endif + ); + + // set max length allowed in the textctrl, if the parameter was set + if (m_maxChars != 0) + { + ((wxTextCtrl*)m_control)->SetMaxLength(m_maxChars); + } + + wxGridCellEditor::Create(parent, id, evtHandler); +} + +void wxGridCellTextEditor::PaintBackground(const wxRect& WXUNUSED(rectCell), + wxGridCellAttr * WXUNUSED(attr)) +{ + // as we fill the entire client area, + // don't do anything here to minimize flicker +} + +void wxGridCellTextEditor::SetSize(const wxRect& rectOrig) +{ + wxRect rect(rectOrig); + + // Make the edit control large enough to allow for internal margins + // + // TODO: remove this if the text ctrl sizing is improved esp. for unix + // +#if defined(__WXGTK__) + if (rect.x != 0) + { + rect.x += 1; + rect.y += 1; + rect.width -= 1; + rect.height -= 1; + } +#elif defined(__WXMSW__) + if ( rect.x == 0 ) + rect.x += 2; + else + rect.x += 3; + + if ( rect.y == 0 ) + rect.y += 2; + else + rect.y += 3; + + rect.width -= 2; + rect.height -= 2; +#else + int extra_x = ( rect.x > 2 ) ? 2 : 1; + int extra_y = ( rect.y > 2 ) ? 2 : 1; + + #if defined(__WXMOTIF__) + extra_x *= 2; + extra_y *= 2; + #endif + + rect.SetLeft( wxMax(0, rect.x - extra_x) ); + rect.SetTop( wxMax(0, rect.y - extra_y) ); + rect.SetRight( rect.GetRight() + 2 * extra_x ); + rect.SetBottom( rect.GetBottom() + 2 * extra_y ); +#endif + + wxGridCellEditor::SetSize(rect); +} + +void wxGridCellTextEditor::BeginEdit(int row, int col, wxGrid* grid) +{ + wxASSERT_MSG(m_control, wxT("The wxGridCellEditor must be created first!")); + + m_startValue = grid->GetTable()->GetValue(row, col); + + DoBeginEdit(m_startValue); +} + +void wxGridCellTextEditor::DoBeginEdit(const wxString& startValue) +{ + Text()->SetValue(startValue); + Text()->SetInsertionPointEnd(); + Text()->SetSelection(-1, -1); + Text()->SetFocus(); +} + +bool wxGridCellTextEditor::EndEdit(int row, int col, wxGrid* grid) +{ + wxASSERT_MSG(m_control, wxT("The wxGridCellEditor must be created first!")); + + bool changed = false; + wxString value = Text()->GetValue(); + if (value != m_startValue) + changed = true; + + if (changed) + grid->GetTable()->SetValue(row, col, value); + + m_startValue = wxEmptyString; + + // No point in setting the text of the hidden control + //Text()->SetValue(m_startValue); + + return changed; +} + +void wxGridCellTextEditor::Reset() +{ + wxASSERT_MSG(m_control, wxT("The wxGridCellEditor must be created first!")); + + DoReset(m_startValue); +} + +void wxGridCellTextEditor::DoReset(const wxString& startValue) +{ + Text()->SetValue(startValue); + Text()->SetInsertionPointEnd(); +} + +bool wxGridCellTextEditor::IsAcceptedKey(wxKeyEvent& event) +{ + return wxGridCellEditor::IsAcceptedKey(event); +} + +void wxGridCellTextEditor::StartingKey(wxKeyEvent& event) +{ + // Since this is now happening in the EVT_CHAR event EmulateKeyPress is no + // longer an appropriate way to get the character into the text control. + // Do it ourselves instead. We know that if we get this far that we have + // a valid character, so not a whole lot of testing needs to be done. + + wxTextCtrl* tc = Text(); + wxChar ch; + long pos; + +#if wxUSE_UNICODE + ch = event.GetUnicodeKey(); + if (ch <= 127) + ch = (wxChar)event.GetKeyCode(); +#else + ch = (wxChar)event.GetKeyCode(); +#endif + + switch (ch) + { + case WXK_DELETE: + // delete the character at the cursor + pos = tc->GetInsertionPoint(); + if (pos < tc->GetLastPosition()) + tc->Remove(pos, pos + 1); + break; + + case WXK_BACK: + // delete the character before the cursor + pos = tc->GetInsertionPoint(); + if (pos > 0) + tc->Remove(pos - 1, pos); + break; + + default: + tc->WriteText(ch); + break; + } +} + +void wxGridCellTextEditor::HandleReturn( wxKeyEvent& + WXUNUSED_GTK(WXUNUSED_MOTIF(event)) ) +{ +#if defined(__WXMOTIF__) || defined(__WXGTK__) + // wxMotif needs a little extra help... + size_t pos = (size_t)( Text()->GetInsertionPoint() ); + wxString s( Text()->GetValue() ); + s = s.Left(pos) + wxT("\n") + s.Mid(pos); + Text()->SetValue(s); + Text()->SetInsertionPoint( pos ); +#else + // the other ports can handle a Return key press + // + event.Skip(); +#endif +} + +void wxGridCellTextEditor::SetParameters(const wxString& params) +{ + if ( !params ) + { + // reset to default + m_maxChars = 0; + } + else + { + long tmp; + if ( params.ToLong(&tmp) ) + { + m_maxChars = (size_t)tmp; + } + else + { + wxLogDebug( _T("Invalid wxGridCellTextEditor parameter string '%s' ignored"), params.c_str() ); + } + } +} + +// return the value in the text control +wxString wxGridCellTextEditor::GetValue() const +{ + return Text()->GetValue(); +} + +// ---------------------------------------------------------------------------- +// wxGridCellNumberEditor +// ---------------------------------------------------------------------------- + +wxGridCellNumberEditor::wxGridCellNumberEditor(int min, int max) +{ + m_min = min; + m_max = max; +} + +void wxGridCellNumberEditor::Create(wxWindow* parent, + wxWindowID id, + wxEvtHandler* evtHandler) +{ +#if wxUSE_SPINCTRL + if ( HasRange() ) + { + // create a spin ctrl + m_control = new wxSpinCtrl(parent, wxID_ANY, wxEmptyString, + wxDefaultPosition, wxDefaultSize, + wxSP_ARROW_KEYS, + m_min, m_max); + + wxGridCellEditor::Create(parent, id, evtHandler); + } + else +#endif + { + // just a text control + wxGridCellTextEditor::Create(parent, id, evtHandler); + +#if wxUSE_VALIDATORS + Text()->SetValidator(wxTextValidator(wxFILTER_NUMERIC)); +#endif + } +} + +void wxGridCellNumberEditor::BeginEdit(int row, int col, wxGrid* grid) +{ + // first get the value + wxGridTableBase *table = grid->GetTable(); + if ( table->CanGetValueAs(row, col, wxGRID_VALUE_NUMBER) ) + { + m_valueOld = table->GetValueAsLong(row, col); + } + else + { + m_valueOld = 0; + wxString sValue = table->GetValue(row, col); + if (! sValue.ToLong(&m_valueOld) && ! sValue.empty()) + { + wxFAIL_MSG( _T("this cell doesn't have numeric value") ); + return; + } + } + +#if wxUSE_SPINCTRL + if ( HasRange() ) + { + Spin()->SetValue((int)m_valueOld); + Spin()->SetFocus(); + } + else +#endif + { + DoBeginEdit(GetString()); + } +} + +bool wxGridCellNumberEditor::EndEdit(int row, int col, + wxGrid* grid) +{ + bool changed; + long value = 0; + wxString text; + +#if wxUSE_SPINCTRL + if ( HasRange() ) + { + value = Spin()->GetValue(); + changed = value != m_valueOld; + if (changed) + text = wxString::Format(wxT("%ld"), value); + } + else +#endif + { + text = Text()->GetValue(); + changed = (text.empty() || text.ToLong(&value)) && (value != m_valueOld); + } + + if ( changed ) + { + if (grid->GetTable()->CanSetValueAs(row, col, wxGRID_VALUE_NUMBER)) + grid->GetTable()->SetValueAsLong(row, col, value); + else + grid->GetTable()->SetValue(row, col, text); + } + + return changed; +} + +void wxGridCellNumberEditor::Reset() +{ +#if wxUSE_SPINCTRL + if ( HasRange() ) + { + Spin()->SetValue((int)m_valueOld); + } + else +#endif + { + DoReset(GetString()); + } +} + +bool wxGridCellNumberEditor::IsAcceptedKey(wxKeyEvent& event) +{ + if ( wxGridCellEditor::IsAcceptedKey(event) ) + { + int keycode = event.GetKeyCode(); + if ( (keycode < 128) && + (wxIsdigit(keycode) || keycode == '+' || keycode == '-')) + { + return true; + } + } + + return false; +} + +void wxGridCellNumberEditor::StartingKey(wxKeyEvent& event) +{ + int keycode = event.GetKeyCode(); + if ( !HasRange() ) + { + if ( wxIsdigit(keycode) || keycode == '+' || keycode == '-') + { + wxGridCellTextEditor::StartingKey(event); + + // skip Skip() below + return; + } + } +#if wxUSE_SPINCTRL + else + { + if ( wxIsdigit(keycode) ) + { + wxSpinCtrl* spin = (wxSpinCtrl*)m_control; + spin->SetValue(keycode - '0'); + spin->SetSelection(1,1); + return; + } + } +#endif + + event.Skip(); +} + +void wxGridCellNumberEditor::SetParameters(const wxString& params) +{ + if ( !params ) + { + // reset to default + m_min = + m_max = -1; + } + else + { + long tmp; + if ( params.BeforeFirst(_T(',')).ToLong(&tmp) ) + { + m_min = (int)tmp; + + if ( params.AfterFirst(_T(',')).ToLong(&tmp) ) + { + m_max = (int)tmp; + + // skip the error message below + return; + } + } + + wxLogDebug(_T("Invalid wxGridCellNumberEditor parameter string '%s' ignored"), params.c_str()); + } +} + +// return the value in the spin control if it is there (the text control otherwise) +wxString wxGridCellNumberEditor::GetValue() const +{ + wxString s; + +#if wxUSE_SPINCTRL + if ( HasRange() ) + { + long value = Spin()->GetValue(); + s.Printf(wxT("%ld"), value); + } + else +#endif + { + s = Text()->GetValue(); + } + + return s; +} + +// ---------------------------------------------------------------------------- +// wxGridCellFloatEditor +// ---------------------------------------------------------------------------- + +wxGridCellFloatEditor::wxGridCellFloatEditor(int width, int precision) +{ + m_width = width; + m_precision = precision; +} + +void wxGridCellFloatEditor::Create(wxWindow* parent, + wxWindowID id, + wxEvtHandler* evtHandler) +{ + wxGridCellTextEditor::Create(parent, id, evtHandler); + +#if wxUSE_VALIDATORS + Text()->SetValidator(wxTextValidator(wxFILTER_NUMERIC)); +#endif +} + +void wxGridCellFloatEditor::BeginEdit(int row, int col, wxGrid* grid) +{ + // first get the value + wxGridTableBase *table = grid->GetTable(); + if ( table->CanGetValueAs(row, col, wxGRID_VALUE_FLOAT) ) + { + m_valueOld = table->GetValueAsDouble(row, col); + } + else + { + m_valueOld = 0.0; + wxString sValue = table->GetValue(row, col); + if (! sValue.ToDouble(&m_valueOld) && ! sValue.empty()) + { + wxFAIL_MSG( _T("this cell doesn't have float value") ); + return; + } + } + + DoBeginEdit(GetString()); +} + +bool wxGridCellFloatEditor::EndEdit(int row, int col, + wxGrid* grid) +{ + double value = 0.0; + wxString text(Text()->GetValue()); + + if ( (text.empty() || text.ToDouble(&value)) && + !wxIsSameDouble(value, m_valueOld) ) + { + if (grid->GetTable()->CanSetValueAs(row, col, wxGRID_VALUE_FLOAT)) + grid->GetTable()->SetValueAsDouble(row, col, value); + else + grid->GetTable()->SetValue(row, col, text); + + return true; + } + + return false; +} + +void wxGridCellFloatEditor::Reset() +{ + DoReset(GetString()); +} + +void wxGridCellFloatEditor::StartingKey(wxKeyEvent& event) +{ + int keycode = event.GetKeyCode(); + char tmpbuf[2]; + tmpbuf[0] = (char) keycode; + tmpbuf[1] = '\0'; + wxString strbuf(tmpbuf, *wxConvCurrent); + +#if wxUSE_INTL + bool is_decimal_point = ( strbuf == + wxLocale::GetInfo(wxLOCALE_DECIMAL_POINT, wxLOCALE_CAT_NUMBER) ); +#else + bool is_decimal_point = ( strbuf == _T(".") ); +#endif + + if ( wxIsdigit(keycode) || keycode == '+' || keycode == '-' + || is_decimal_point ) + { + wxGridCellTextEditor::StartingKey(event); + + // skip Skip() below + return; + } + + event.Skip(); +} + +void wxGridCellFloatEditor::SetParameters(const wxString& params) +{ + if ( !params ) + { + // reset to default + m_width = + m_precision = -1; + } + else + { + long tmp; + if ( params.BeforeFirst(_T(',')).ToLong(&tmp) ) + { + m_width = (int)tmp; + + if ( params.AfterFirst(_T(',')).ToLong(&tmp) ) + { + m_precision = (int)tmp; + + // skip the error message below + return; + } + } + + wxLogDebug(_T("Invalid wxGridCellFloatEditor parameter string '%s' ignored"), params.c_str()); + } +} + +wxString wxGridCellFloatEditor::GetString() const +{ + wxString fmt; + if ( m_precision == -1 && m_width != -1) + { + // default precision + fmt.Printf(_T("%%%d.f"), m_width); + } + else if ( m_precision != -1 && m_width == -1) + { + // default width + fmt.Printf(_T("%%.%df"), m_precision); + } + else if ( m_precision != -1 && m_width != -1 ) + { + fmt.Printf(_T("%%%d.%df"), m_width, m_precision); + } + else + { + // default width/precision + fmt = _T("%f"); + } + + return wxString::Format(fmt, m_valueOld); +} + +bool wxGridCellFloatEditor::IsAcceptedKey(wxKeyEvent& event) +{ + if ( wxGridCellEditor::IsAcceptedKey(event) ) + { + const int keycode = event.GetKeyCode(); + if ( isascii(keycode) ) + { + char tmpbuf[2]; + tmpbuf[0] = (char) keycode; + tmpbuf[1] = '\0'; + wxString strbuf(tmpbuf, *wxConvCurrent); + +#if wxUSE_INTL + const wxString decimalPoint = + wxLocale::GetInfo(wxLOCALE_DECIMAL_POINT, wxLOCALE_CAT_NUMBER); +#else + const wxString decimalPoint(_T('.')); +#endif + + // accept digits, 'e' as in '1e+6', also '-', '+', and '.' + if ( wxIsdigit(keycode) || + tolower(keycode) == 'e' || + keycode == decimalPoint || + keycode == '+' || + keycode == '-' ) + { + return true; + } + } + } + + return false; +} + +#endif // wxUSE_TEXTCTRL + +#if wxUSE_CHECKBOX + +// ---------------------------------------------------------------------------- +// wxGridCellBoolEditor +// ---------------------------------------------------------------------------- + +// the default values for GetValue() +wxString wxGridCellBoolEditor::ms_stringValues[2] = { _T(""), _T("1") }; + +void wxGridCellBoolEditor::Create(wxWindow* parent, + wxWindowID id, + wxEvtHandler* evtHandler) +{ + m_control = new wxCheckBox(parent, id, wxEmptyString, + wxDefaultPosition, wxDefaultSize, + wxNO_BORDER); + + wxGridCellEditor::Create(parent, id, evtHandler); +} + +void wxGridCellBoolEditor::SetSize(const wxRect& r) +{ + bool resize = false; + wxSize size = m_control->GetSize(); + wxCoord minSize = wxMin(r.width, r.height); + + // check if the checkbox is not too big/small for this cell + wxSize sizeBest = m_control->GetBestSize(); + if ( !(size == sizeBest) ) + { + // reset to default size if it had been made smaller + size = sizeBest; + + resize = true; + } + + if ( size.x >= minSize || size.y >= minSize ) + { + // leave 1 pixel margin + size.x = size.y = minSize - 2; + + resize = true; + } + + if ( resize ) + { + m_control->SetSize(size); + } + + // position it in the centre of the rectangle (TODO: support alignment?) + +#if defined(__WXGTK__) || defined (__WXMOTIF__) + // the checkbox without label still has some space to the right in wxGTK, + // so shift it to the right + size.x -= 8; +#elif defined(__WXMSW__) + // here too, but in other way + size.x += 1; + size.y -= 2; +#endif + + int hAlign = wxALIGN_CENTRE; + int vAlign = wxALIGN_CENTRE; + if (GetCellAttr()) + GetCellAttr()->GetAlignment(& hAlign, & vAlign); + + int x = 0, y = 0; + if (hAlign == wxALIGN_LEFT) + { + x = r.x + 2; + +#ifdef __WXMSW__ + x += 2; +#endif + + y = r.y + r.height / 2 - size.y / 2; + } + else if (hAlign == wxALIGN_RIGHT) + { + x = r.x + r.width - size.x - 2; + y = r.y + r.height / 2 - size.y / 2; + } + else if (hAlign == wxALIGN_CENTRE) + { + x = r.x + r.width / 2 - size.x / 2; + y = r.y + r.height / 2 - size.y / 2; + } + + m_control->Move(x, y); +} + +void wxGridCellBoolEditor::Show(bool show, wxGridCellAttr *attr) +{ + m_control->Show(show); + + if ( show ) + { + wxColour colBg = attr ? attr->GetBackgroundColour() : *wxLIGHT_GREY; + CBox()->SetBackgroundColour(colBg); + } +} + +void wxGridCellBoolEditor::BeginEdit(int row, int col, wxGrid* grid) +{ + wxASSERT_MSG(m_control, + wxT("The wxGridCellEditor must be created first!")); + + if (grid->GetTable()->CanGetValueAs(row, col, wxGRID_VALUE_BOOL)) + { + m_startValue = grid->GetTable()->GetValueAsBool(row, col); + } + else + { + wxString cellval( grid->GetTable()->GetValue(row, col) ); + + if ( cellval == ms_stringValues[false] ) + m_startValue = false; + else if ( cellval == ms_stringValues[true] ) + m_startValue = true; + else + { + // do not try to be smart here and convert it to true or false + // because we'll still overwrite it with something different and + // this risks to be very surprising for the user code, let them + // know about it + wxFAIL_MSG( _T("invalid value for a cell with bool editor!") ); + } + } + + CBox()->SetValue(m_startValue); + CBox()->SetFocus(); +} + +bool wxGridCellBoolEditor::EndEdit(int row, int col, + wxGrid* grid) +{ + wxASSERT_MSG(m_control, + wxT("The wxGridCellEditor must be created first!")); + + bool changed = false; + bool value = CBox()->GetValue(); + if ( value != m_startValue ) + changed = true; + + if ( changed ) + { + wxGridTableBase * const table = grid->GetTable(); + if ( table->CanGetValueAs(row, col, wxGRID_VALUE_BOOL) ) + table->SetValueAsBool(row, col, value); + else + table->SetValue(row, col, GetValue()); + } + + return changed; +} + +void wxGridCellBoolEditor::Reset() +{ + wxASSERT_MSG(m_control, + wxT("The wxGridCellEditor must be created first!")); + + CBox()->SetValue(m_startValue); +} + +void wxGridCellBoolEditor::StartingClick() +{ + CBox()->SetValue(!CBox()->GetValue()); +} + +bool wxGridCellBoolEditor::IsAcceptedKey(wxKeyEvent& event) +{ + if ( wxGridCellEditor::IsAcceptedKey(event) ) + { + int keycode = event.GetKeyCode(); + switch ( keycode ) + { + case WXK_SPACE: + case '+': + case '-': + return true; + } + } + + return false; +} + +void wxGridCellBoolEditor::StartingKey(wxKeyEvent& event) +{ + int keycode = event.GetKeyCode(); + switch ( keycode ) + { + case WXK_SPACE: + CBox()->SetValue(!CBox()->GetValue()); + break; + + case '+': + CBox()->SetValue(true); + break; + + case '-': + CBox()->SetValue(false); + break; + } +} + +wxString wxGridCellBoolEditor::GetValue() const +{ + return ms_stringValues[CBox()->GetValue()]; +} + +/* static */ void +wxGridCellBoolEditor::UseStringValues(const wxString& valueTrue, + const wxString& valueFalse) +{ + ms_stringValues[false] = valueFalse; + ms_stringValues[true] = valueTrue; +} + +/* static */ bool +wxGridCellBoolEditor::IsTrueValue(const wxString& value) +{ + return value == ms_stringValues[true]; +} + +#endif // wxUSE_CHECKBOX + +#if wxUSE_COMBOBOX + +// ---------------------------------------------------------------------------- +// wxGridCellChoiceEditor +// ---------------------------------------------------------------------------- + +wxGridCellChoiceEditor::wxGridCellChoiceEditor(const wxArrayString& choices, + bool allowOthers) + : m_choices(choices), + m_allowOthers(allowOthers) { } + +wxGridCellChoiceEditor::wxGridCellChoiceEditor(size_t count, + const wxString choices[], + bool allowOthers) + : m_allowOthers(allowOthers) +{ + if ( count ) + { + m_choices.Alloc(count); + for ( size_t n = 0; n < count; n++ ) + { + m_choices.Add(choices[n]); + } + } +} + +wxGridCellEditor *wxGridCellChoiceEditor::Clone() const +{ + wxGridCellChoiceEditor *editor = new wxGridCellChoiceEditor; + editor->m_allowOthers = m_allowOthers; + editor->m_choices = m_choices; + + return editor; +} + +void wxGridCellChoiceEditor::Create(wxWindow* parent, + wxWindowID id, + wxEvtHandler* evtHandler) +{ + int style = wxTE_PROCESS_ENTER | + wxTE_PROCESS_TAB | + wxBORDER_NONE; + + if ( !m_allowOthers ) + style |= wxCB_READONLY; + + m_control = new wxComboBox(parent, id, wxEmptyString, + wxDefaultPosition, wxDefaultSize, + m_choices, + style); + + wxGridCellEditor::Create(parent, id, evtHandler); +} + +void wxGridCellChoiceEditor::PaintBackground(const wxRect& rectCell, + wxGridCellAttr * attr) +{ + // as we fill the entire client area, don't do anything here to minimize + // flicker + + // TODO: It doesn't actually fill the client area since the height of a + // combo always defaults to the standard. Until someone has time to + // figure out the right rectangle to paint, just do it the normal way. + wxGridCellEditor::PaintBackground(rectCell, attr); +} + +void wxGridCellChoiceEditor::BeginEdit(int row, int col, wxGrid* grid) +{ + wxASSERT_MSG(m_control, + wxT("The wxGridCellEditor must be created first!")); + + wxGridCellEditorEvtHandler* evtHandler = NULL; + if (m_control) + evtHandler = wxDynamicCast(m_control->GetEventHandler(), wxGridCellEditorEvtHandler); + + // Don't immediately end if we get a kill focus event within BeginEdit + if (evtHandler) + evtHandler->SetInSetFocus(true); + + m_startValue = grid->GetTable()->GetValue(row, col); + + if (m_allowOthers) + { + Combo()->SetValue(m_startValue); + } + else + { + // find the right position, or default to the first if not found + int pos = Combo()->FindString(m_startValue); + if (pos == wxNOT_FOUND) + pos = 0; + Combo()->SetSelection(pos); + } + + Combo()->SetInsertionPointEnd(); + Combo()->SetFocus(); + + if (evtHandler) + { + // When dropping down the menu, a kill focus event + // happens after this point, so we can't reset the flag yet. +#if !defined(__WXGTK20__) + evtHandler->SetInSetFocus(false); +#endif + } +} + +bool wxGridCellChoiceEditor::EndEdit(int row, int col, + wxGrid* grid) +{ + wxString value = Combo()->GetValue(); + if ( value == m_startValue ) + return false; + + grid->GetTable()->SetValue(row, col, value); + + return true; +} + +void wxGridCellChoiceEditor::Reset() +{ + Combo()->SetValue(m_startValue); + Combo()->SetInsertionPointEnd(); +} + +void wxGridCellChoiceEditor::SetParameters(const wxString& params) +{ + if ( !params ) + { + // what can we do? + return; + } + + m_choices.Empty(); + + wxStringTokenizer tk(params, _T(',')); + while ( tk.HasMoreTokens() ) + { + m_choices.Add(tk.GetNextToken()); + } +} + +// return the value in the text control +wxString wxGridCellChoiceEditor::GetValue() const +{ + return Combo()->GetValue(); +} + +#endif // wxUSE_COMBOBOX + +// ---------------------------------------------------------------------------- +// wxGridCellEditorEvtHandler +// ---------------------------------------------------------------------------- + +void wxGridCellEditorEvtHandler::OnKillFocus(wxFocusEvent& event) +{ + // Don't disable the cell if we're just starting to edit it + if (m_inSetFocus) + return; + + // accept changes + m_grid->DisableCellEditControl(); + + event.Skip(); +} + +void wxGridCellEditorEvtHandler::OnKeyDown(wxKeyEvent& event) +{ + switch ( event.GetKeyCode() ) + { + case WXK_ESCAPE: + m_editor->Reset(); + m_grid->DisableCellEditControl(); + break; + + case WXK_TAB: + m_grid->GetEventHandler()->ProcessEvent( event ); + break; + + case WXK_RETURN: + case WXK_NUMPAD_ENTER: + if (!m_grid->GetEventHandler()->ProcessEvent(event)) + m_editor->HandleReturn(event); + break; + + default: + event.Skip(); + break; + } +} + +void wxGridCellEditorEvtHandler::OnChar(wxKeyEvent& event) +{ + int row = m_grid->GetGridCursorRow(); + int col = m_grid->GetGridCursorCol(); + wxRect rect = m_grid->CellToRect( row, col ); + int cw, ch; + m_grid->GetGridWindow()->GetClientSize( &cw, &ch ); + + // if cell width is smaller than grid client area, cell is wholly visible + bool wholeCellVisible = (rect.GetWidth() < cw); + + switch ( event.GetKeyCode() ) + { + case WXK_ESCAPE: + case WXK_TAB: + case WXK_RETURN: + case WXK_NUMPAD_ENTER: + break; + + case WXK_HOME: + { + if ( wholeCellVisible ) + { + // no special processing needed... + event.Skip(); + break; + } + + // do special processing for partly visible cell... + + // get the widths of all cells previous to this one + int colXPos = 0; + for ( int i = 0; i < col; i++ ) + { + colXPos += m_grid->GetColSize(i); + } + + int xUnit = 1, yUnit = 1; + m_grid->GetScrollPixelsPerUnit(&xUnit, &yUnit); + if (col != 0) + { + m_grid->Scroll(colXPos / xUnit - 1, m_grid->GetScrollPos(wxVERTICAL)); + } + else + { + m_grid->Scroll(colXPos / xUnit, m_grid->GetScrollPos(wxVERTICAL)); + } + event.Skip(); + break; + } + + case WXK_END: + { + if ( wholeCellVisible ) + { + // no special processing needed... + event.Skip(); + break; + } + + // do special processing for partly visible cell... + + int textWidth = 0; + wxString value = m_grid->GetCellValue(row, col); + if ( wxEmptyString != value ) + { + // get width of cell CONTENTS (text) + int y; + wxFont font = m_grid->GetCellFont(row, col); + m_grid->GetTextExtent(value, &textWidth, &y, NULL, NULL, &font); + + // try to RIGHT align the text by scrolling + int client_right = m_grid->GetGridWindow()->GetClientSize().GetWidth(); + + // (m_grid->GetScrollLineX()*2) is a factor for not scrolling to far, + // otherwise the last part of the cell content might be hidden below the scroll bar + // FIXME: maybe there is a more suitable correction? + textWidth -= (client_right - (m_grid->GetScrollLineX() * 2)); + if ( textWidth < 0 ) + { + textWidth = 0; + } + } + + // get the widths of all cells previous to this one + int colXPos = 0; + for ( int i = 0; i < col; i++ ) + { + colXPos += m_grid->GetColSize(i); + } + + // and add the (modified) text width of the cell contents + // as we'd like to see the last part of the cell contents + colXPos += textWidth; + + int xUnit = 1, yUnit = 1; + m_grid->GetScrollPixelsPerUnit(&xUnit, &yUnit); + m_grid->Scroll(colXPos / xUnit - 1, m_grid->GetScrollPos(wxVERTICAL)); + event.Skip(); + break; + } + + default: + event.Skip(); + break; + } +} + +// ---------------------------------------------------------------------------- +// wxGridCellWorker is an (almost) empty common base class for +// wxGridCellRenderer and wxGridCellEditor managing ref counting +// ---------------------------------------------------------------------------- + +void wxGridCellWorker::SetParameters(const wxString& WXUNUSED(params)) +{ + // nothing to do +} + +wxGridCellWorker::~wxGridCellWorker() +{ +} + +// ============================================================================ +// renderer classes +// ============================================================================ + +// ---------------------------------------------------------------------------- +// wxGridCellRenderer +// ---------------------------------------------------------------------------- + +void wxGridCellRenderer::Draw(wxGrid& grid, + wxGridCellAttr& attr, + wxDC& dc, + const wxRect& rect, + int WXUNUSED(row), int WXUNUSED(col), + bool isSelected) +{ + dc.SetBackgroundMode( wxSOLID ); + + // grey out fields if the grid is disabled + if ( grid.IsEnabled() ) + { + if ( isSelected ) + { + wxColour clr; + if ( wxWindow::FindFocus() == grid.GetGridWindow() ) + clr = grid.GetSelectionBackground(); + else + clr = wxSystemSettings::GetColour(wxSYS_COLOUR_BTNSHADOW); + dc.SetBrush( wxBrush(clr, wxSOLID) ); + } + else + { + dc.SetBrush( wxBrush(attr.GetBackgroundColour(), wxSOLID) ); + } + } + else + { + dc.SetBrush(wxBrush(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE), wxSOLID)); + } + + dc.SetPen( *wxTRANSPARENT_PEN ); + dc.DrawRectangle(rect); +} + +// ---------------------------------------------------------------------------- +// wxGridCellStringRenderer +// ---------------------------------------------------------------------------- + +void wxGridCellStringRenderer::SetTextColoursAndFont(const wxGrid& grid, + const wxGridCellAttr& attr, + wxDC& dc, + bool isSelected) +{ + dc.SetBackgroundMode( wxTRANSPARENT ); + + // TODO some special colours for attr.IsReadOnly() case? + + // different coloured text when the grid is disabled + if ( grid.IsEnabled() ) + { + if ( isSelected ) + { + wxColour clr; + if ( wxWindow::FindFocus() == + wx_const_cast(wxGrid&, grid).GetGridWindow() ) + clr = grid.GetSelectionBackground(); + else + clr = wxSystemSettings::GetColour(wxSYS_COLOUR_BTNSHADOW); + dc.SetTextBackground( clr ); + dc.SetTextForeground( grid.GetSelectionForeground() ); + } + else + { + dc.SetTextBackground( attr.GetBackgroundColour() ); + dc.SetTextForeground( attr.GetTextColour() ); + } + } + else + { + dc.SetTextBackground(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE)); + dc.SetTextForeground(wxSystemSettings::GetColour(wxSYS_COLOUR_GRAYTEXT)); + } + + dc.SetFont( attr.GetFont() ); +} + +wxSize wxGridCellStringRenderer::DoGetBestSize(const wxGridCellAttr& attr, + wxDC& dc, + const wxString& text) +{ + wxCoord x = 0, y = 0, max_x = 0; + dc.SetFont(attr.GetFont()); + wxStringTokenizer tk(text, _T('\n')); + while ( tk.HasMoreTokens() ) + { + dc.GetTextExtent(tk.GetNextToken(), &x, &y); + max_x = wxMax(max_x, x); + } + + y *= 1 + text.Freq(wxT('\n')); // multiply by the number of lines. + + return wxSize(max_x, y); +} + +wxSize wxGridCellStringRenderer::GetBestSize(wxGrid& grid, + wxGridCellAttr& attr, + wxDC& dc, + int row, int col) +{ + return DoGetBestSize(attr, dc, grid.GetCellValue(row, col)); +} + +void wxGridCellStringRenderer::Draw(wxGrid& grid, + wxGridCellAttr& attr, + wxDC& dc, + const wxRect& rectCell, + int row, int col, + bool isSelected) +{ + wxRect rect = rectCell; + rect.Inflate(-1); + + // erase only this cells background, overflow cells should have been erased + wxGridCellRenderer::Draw(grid, attr, dc, rectCell, row, col, isSelected); + + int hAlign, vAlign; + attr.GetAlignment(&hAlign, &vAlign); + + int overflowCols = 0; + + if (attr.GetOverflow()) + { + int cols = grid.GetNumberCols(); + int best_width = GetBestSize(grid,attr,dc,row,col).GetWidth(); + int cell_rows, cell_cols; + attr.GetSize( &cell_rows, &cell_cols ); // shouldn't get here if <= 0 + if ((best_width > rectCell.width) && (col < cols) && grid.GetTable()) + { + int i, c_cols, c_rows; + for (i = col+cell_cols; i < cols; i++) + { + bool is_empty = true; + for (int j=row; j < row + cell_rows; j++) + { + // check w/ anchor cell for multicell block + grid.GetCellSize(j, i, &c_rows, &c_cols); + if (c_rows > 0) + c_rows = 0; + if (!grid.GetTable()->IsEmptyCell(j + c_rows, i)) + { + is_empty = false; + break; + } + } + + if (is_empty) + { + rect.width += grid.GetColSize(i); + } + else + { + i--; + break; + } + + if (rect.width >= best_width) + break; + } + + overflowCols = i - col - cell_cols + 1; + if (overflowCols >= cols) + overflowCols = cols - 1; + } + + if (overflowCols > 0) // redraw overflow cells w/ proper hilight + { + hAlign = wxALIGN_LEFT; // if oveflowed then it's left aligned + wxRect clip = rect; + clip.x += rectCell.width; + // draw each overflow cell individually + int col_end = col + cell_cols + overflowCols; + if (col_end >= grid.GetNumberCols()) + col_end = grid.GetNumberCols() - 1; + for (int i = col + cell_cols; i <= col_end; i++) + { + clip.width = grid.GetColSize(i) - 1; + dc.DestroyClippingRegion(); + dc.SetClippingRegion(clip); + + SetTextColoursAndFont(grid, attr, dc, + grid.IsInSelection(row,i)); + + grid.DrawTextRectangle(dc, grid.GetCellValue(row, col), + rect, hAlign, vAlign); + clip.x += grid.GetColSize(i) - 1; + } + + rect = rectCell; + rect.Inflate(-1); + rect.width++; + dc.DestroyClippingRegion(); + } + } + + // now we only have to draw the text + SetTextColoursAndFont(grid, attr, dc, isSelected); + + grid.DrawTextRectangle(dc, grid.GetCellValue(row, col), + rect, hAlign, vAlign); +} + +// ---------------------------------------------------------------------------- +// wxGridCellNumberRenderer +// ---------------------------------------------------------------------------- + +wxString wxGridCellNumberRenderer::GetString(const wxGrid& grid, int row, int col) +{ + wxGridTableBase *table = grid.GetTable(); + wxString text; + if ( table->CanGetValueAs(row, col, wxGRID_VALUE_NUMBER) ) + { + text.Printf(_T("%ld"), table->GetValueAsLong(row, col)); + } + else + { + text = table->GetValue(row, col); + } + + return text; +} + +void wxGridCellNumberRenderer::Draw(wxGrid& grid, + wxGridCellAttr& attr, + wxDC& dc, + const wxRect& rectCell, + int row, int col, + bool isSelected) +{ + wxGridCellRenderer::Draw(grid, attr, dc, rectCell, row, col, isSelected); + + SetTextColoursAndFont(grid, attr, dc, isSelected); + + // draw the text right aligned by default + int hAlign, vAlign; + attr.GetAlignment(&hAlign, &vAlign); + hAlign = wxALIGN_RIGHT; + + wxRect rect = rectCell; + rect.Inflate(-1); + + grid.DrawTextRectangle(dc, GetString(grid, row, col), rect, hAlign, vAlign); +} + +wxSize wxGridCellNumberRenderer::GetBestSize(wxGrid& grid, + wxGridCellAttr& attr, + wxDC& dc, + int row, int col) +{ + return DoGetBestSize(attr, dc, GetString(grid, row, col)); +} + +// ---------------------------------------------------------------------------- +// wxGridCellFloatRenderer +// ---------------------------------------------------------------------------- + +wxGridCellFloatRenderer::wxGridCellFloatRenderer(int width, int precision) +{ + SetWidth(width); + SetPrecision(precision); +} + +wxGridCellRenderer *wxGridCellFloatRenderer::Clone() const +{ + wxGridCellFloatRenderer *renderer = new wxGridCellFloatRenderer; + renderer->m_width = m_width; + renderer->m_precision = m_precision; + renderer->m_format = m_format; + + return renderer; +} + +wxString wxGridCellFloatRenderer::GetString(const wxGrid& grid, int row, int col) +{ + wxGridTableBase *table = grid.GetTable(); + + bool hasDouble; + double val; + wxString text; + if ( table->CanGetValueAs(row, col, wxGRID_VALUE_FLOAT) ) + { + val = table->GetValueAsDouble(row, col); + hasDouble = true; + } + else + { + text = table->GetValue(row, col); + hasDouble = text.ToDouble(&val); + } + + if ( hasDouble ) + { + if ( !m_format ) + { + if ( m_width == -1 ) + { + if ( m_precision == -1 ) + { + // default width/precision + m_format = _T("%f"); + } + else + { + m_format.Printf(_T("%%.%df"), m_precision); + } + } + else if ( m_precision == -1 ) + { + // default precision + m_format.Printf(_T("%%%d.f"), m_width); + } + else + { + m_format.Printf(_T("%%%d.%df"), m_width, m_precision); + } + } + + text.Printf(m_format, val); + + } + //else: text already contains the string + + return text; +} + +void wxGridCellFloatRenderer::Draw(wxGrid& grid, + wxGridCellAttr& attr, + wxDC& dc, + const wxRect& rectCell, + int row, int col, + bool isSelected) +{ + wxGridCellRenderer::Draw(grid, attr, dc, rectCell, row, col, isSelected); + + SetTextColoursAndFont(grid, attr, dc, isSelected); + + // draw the text right aligned by default + int hAlign, vAlign; + attr.GetAlignment(&hAlign, &vAlign); + hAlign = wxALIGN_RIGHT; + + wxRect rect = rectCell; + rect.Inflate(-1); + + grid.DrawTextRectangle(dc, GetString(grid, row, col), rect, hAlign, vAlign); +} + +wxSize wxGridCellFloatRenderer::GetBestSize(wxGrid& grid, + wxGridCellAttr& attr, + wxDC& dc, + int row, int col) +{ + return DoGetBestSize(attr, dc, GetString(grid, row, col)); +} + +void wxGridCellFloatRenderer::SetParameters(const wxString& params) +{ + if ( !params ) + { + // reset to defaults + SetWidth(-1); + SetPrecision(-1); + } + else + { + wxString tmp = params.BeforeFirst(_T(',')); + if ( !tmp.empty() ) + { + long width; + if ( tmp.ToLong(&width) ) + { + SetWidth((int)width); + } + else + { + wxLogDebug(_T("Invalid wxGridCellFloatRenderer width parameter string '%s ignored"), params.c_str()); + } + } + + tmp = params.AfterFirst(_T(',')); + if ( !tmp.empty() ) + { + long precision; + if ( tmp.ToLong(&precision) ) + { + SetPrecision((int)precision); + } + else + { + wxLogDebug(_T("Invalid wxGridCellFloatRenderer precision parameter string '%s ignored"), params.c_str()); + } + } + } +} + +// ---------------------------------------------------------------------------- +// wxGridCellBoolRenderer +// ---------------------------------------------------------------------------- + +wxSize wxGridCellBoolRenderer::ms_sizeCheckMark; + +// FIXME these checkbox size calculations are really ugly... + +// between checkmark and box +static const wxCoord wxGRID_CHECKMARK_MARGIN = 2; + +wxSize wxGridCellBoolRenderer::GetBestSize(wxGrid& grid, + wxGridCellAttr& WXUNUSED(attr), + wxDC& WXUNUSED(dc), + int WXUNUSED(row), + int WXUNUSED(col)) +{ + // compute it only once (no locks for MT safeness in GUI thread...) + if ( !ms_sizeCheckMark.x ) + { + // get checkbox size + wxCheckBox *checkbox = new wxCheckBox(&grid, wxID_ANY, wxEmptyString); + wxSize size = checkbox->GetBestSize(); + wxCoord checkSize = size.y + 2 * wxGRID_CHECKMARK_MARGIN; + + // FIXME wxGTK::wxCheckBox::GetBestSize() gives "wrong" result +#if defined(__WXGTK__) || defined(__WXMOTIF__) + checkSize -= size.y / 2; +#endif + + delete checkbox; + + ms_sizeCheckMark.x = ms_sizeCheckMark.y = checkSize; + } + + return ms_sizeCheckMark; +} + +void wxGridCellBoolRenderer::Draw(wxGrid& grid, + wxGridCellAttr& attr, + wxDC& dc, + const wxRect& rect, + int row, int col, + bool isSelected) +{ + wxGridCellRenderer::Draw(grid, attr, dc, rect, row, col, isSelected); + + // draw a check mark in the centre (ignoring alignment - TODO) + wxSize size = GetBestSize(grid, attr, dc, row, col); + + // don't draw outside the cell + wxCoord minSize = wxMin(rect.width, rect.height); + if ( size.x >= minSize || size.y >= minSize ) + { + // and even leave (at least) 1 pixel margin + size.x = size.y = minSize - 2; + } + + // draw a border around checkmark + int vAlign, hAlign; + attr.GetAlignment(&hAlign, &vAlign); + + wxRect rectBorder; + if (hAlign == wxALIGN_CENTRE) + { + rectBorder.x = rect.x + rect.width / 2 - size.x / 2; + rectBorder.y = rect.y + rect.height / 2 - size.y / 2; + rectBorder.width = size.x; + rectBorder.height = size.y; + } + else if (hAlign == wxALIGN_LEFT) + { + rectBorder.x = rect.x + 2; + rectBorder.y = rect.y + rect.height / 2 - size.y / 2; + rectBorder.width = size.x; + rectBorder.height = size.y; + } + else if (hAlign == wxALIGN_RIGHT) + { + rectBorder.x = rect.x + rect.width - size.x - 2; + rectBorder.y = rect.y + rect.height / 2 - size.y / 2; + rectBorder.width = size.x; + rectBorder.height = size.y; + } + + bool value; + if ( grid.GetTable()->CanGetValueAs(row, col, wxGRID_VALUE_BOOL) ) + { + value = grid.GetTable()->GetValueAsBool(row, col); + } + else + { + wxString cellval( grid.GetTable()->GetValue(row, col) ); + value = wxGridCellBoolEditor::IsTrueValue(cellval); + } + + if ( value ) + { + wxRect rectMark = rectBorder; + +#ifdef __WXMSW__ + // MSW DrawCheckMark() is weird (and should probably be changed...) + rectMark.Inflate(-wxGRID_CHECKMARK_MARGIN / 2); + rectMark.x++; + rectMark.y++; +#else + rectMark.Inflate(-wxGRID_CHECKMARK_MARGIN); +#endif + + dc.SetTextForeground(attr.GetTextColour()); + dc.DrawCheckMark(rectMark); + } + + dc.SetBrush(*wxTRANSPARENT_BRUSH); + dc.SetPen(wxPen(attr.GetTextColour(), 1, wxSOLID)); + dc.DrawRectangle(rectBorder); +} + +// ---------------------------------------------------------------------------- +// wxGridCellAttr +// ---------------------------------------------------------------------------- + +void wxGridCellAttr::Init(wxGridCellAttr *attrDefault) +{ + m_nRef = 1; + + m_isReadOnly = Unset; + + m_renderer = NULL; + m_editor = NULL; + + m_attrkind = wxGridCellAttr::Cell; + + m_sizeRows = m_sizeCols = 1; + m_overflow = UnsetOverflow; + + SetDefAttr(attrDefault); +} + +wxGridCellAttr *wxGridCellAttr::Clone() const +{ + wxGridCellAttr *attr = new wxGridCellAttr(m_defGridAttr); + + if ( HasTextColour() ) + attr->SetTextColour(GetTextColour()); + if ( HasBackgroundColour() ) + attr->SetBackgroundColour(GetBackgroundColour()); + if ( HasFont() ) + attr->SetFont(GetFont()); + if ( HasAlignment() ) + attr->SetAlignment(m_hAlign, m_vAlign); + + attr->SetSize( m_sizeRows, m_sizeCols ); + + if ( m_renderer ) + { + attr->SetRenderer(m_renderer); + m_renderer->IncRef(); + } + if ( m_editor ) + { + attr->SetEditor(m_editor); + m_editor->IncRef(); + } + + if ( IsReadOnly() ) + attr->SetReadOnly(); + + attr->SetOverflow( m_overflow == Overflow ); + attr->SetKind( m_attrkind ); + + return attr; +} + +void wxGridCellAttr::MergeWith(wxGridCellAttr *mergefrom) +{ + if ( !HasTextColour() && mergefrom->HasTextColour() ) + SetTextColour(mergefrom->GetTextColour()); + if ( !HasBackgroundColour() && mergefrom->HasBackgroundColour() ) + SetBackgroundColour(mergefrom->GetBackgroundColour()); + if ( !HasFont() && mergefrom->HasFont() ) + SetFont(mergefrom->GetFont()); + if ( !HasAlignment() && mergefrom->HasAlignment() ) + { + int hAlign, vAlign; + mergefrom->GetAlignment( &hAlign, &vAlign); + SetAlignment(hAlign, vAlign); + } + if ( !HasSize() && mergefrom->HasSize() ) + mergefrom->GetSize( &m_sizeRows, &m_sizeCols ); + + // Directly access member functions as GetRender/Editor don't just return + // m_renderer/m_editor + // + // Maybe add support for merge of Render and Editor? + if (!HasRenderer() && mergefrom->HasRenderer() ) + { + m_renderer = mergefrom->m_renderer; + m_renderer->IncRef(); + } + if ( !HasEditor() && mergefrom->HasEditor() ) + { + m_editor = mergefrom->m_editor; + m_editor->IncRef(); + } + if ( !HasReadWriteMode() && mergefrom->HasReadWriteMode() ) + SetReadOnly(mergefrom->IsReadOnly()); + + if (!HasOverflowMode() && mergefrom->HasOverflowMode() ) + SetOverflow(mergefrom->GetOverflow()); + + SetDefAttr(mergefrom->m_defGridAttr); +} + +void wxGridCellAttr::SetSize(int num_rows, int num_cols) +{ + // The size of a cell is normally 1,1 + + // If this cell is larger (2,2) then this is the top left cell + // the other cells that will be covered (lower right cells) must be + // set to negative or zero values such that + // row + num_rows of the covered cell points to the larger cell (this cell) + // same goes for the col + num_cols. + + // Size of 0,0 is NOT valid, neither is <=0 and any positive value + + wxASSERT_MSG( (!((num_rows > 0) && (num_cols <= 0)) || + !((num_rows <= 0) && (num_cols > 0)) || + !((num_rows == 0) && (num_cols == 0))), + wxT("wxGridCellAttr::SetSize only takes two postive values or negative/zero values")); + + m_sizeRows = num_rows; + m_sizeCols = num_cols; +} + +const wxColour& wxGridCellAttr::GetTextColour() const +{ + if (HasTextColour()) + { + return m_colText; + } + else if (m_defGridAttr && m_defGridAttr != this) + { + return m_defGridAttr->GetTextColour(); + } + else + { + wxFAIL_MSG(wxT("Missing default cell attribute")); + return wxNullColour; + } +} + +const wxColour& wxGridCellAttr::GetBackgroundColour() const +{ + if (HasBackgroundColour()) + { + return m_colBack; + } + else if (m_defGridAttr && m_defGridAttr != this) + { + return m_defGridAttr->GetBackgroundColour(); + } + else + { + wxFAIL_MSG(wxT("Missing default cell attribute")); + return wxNullColour; + } +} + +const wxFont& wxGridCellAttr::GetFont() const +{ + if (HasFont()) + { + return m_font; + } + else if (m_defGridAttr && m_defGridAttr != this) + { + return m_defGridAttr->GetFont(); + } + else + { + wxFAIL_MSG(wxT("Missing default cell attribute")); + return wxNullFont; + } +} + +void wxGridCellAttr::GetAlignment(int *hAlign, int *vAlign) const +{ + if (HasAlignment()) + { + if ( hAlign ) + *hAlign = m_hAlign; + if ( vAlign ) + *vAlign = m_vAlign; + } + else if (m_defGridAttr && m_defGridAttr != this) + { + m_defGridAttr->GetAlignment(hAlign, vAlign); + } + else + { + wxFAIL_MSG(wxT("Missing default cell attribute")); + } +} + +void wxGridCellAttr::GetSize( int *num_rows, int *num_cols ) const +{ + if ( num_rows ) + *num_rows = m_sizeRows; + if ( num_cols ) + *num_cols = m_sizeCols; +} + +// GetRenderer and GetEditor use a slightly different decision path about +// which attribute to use. If a non-default attr object has one then it is +// used, otherwise the default editor or renderer is fetched from the grid and +// used. It should be the default for the data type of the cell. If it is +// NULL (because the table has a type that the grid does not have in its +// registry), then the grid's default editor or renderer is used. + +wxGridCellRenderer* wxGridCellAttr::GetRenderer(wxGrid* grid, int row, int col) const +{ + wxGridCellRenderer *renderer = NULL; + + if ( m_renderer && this != m_defGridAttr ) + { + // use the cells renderer if it has one + renderer = m_renderer; + renderer->IncRef(); + } + else // no non-default cell renderer + { + // get default renderer for the data type + if ( grid ) + { + // GetDefaultRendererForCell() will do IncRef() for us + renderer = grid->GetDefaultRendererForCell(row, col); + } + + if ( renderer == NULL ) + { + if ( (m_defGridAttr != NULL) && (m_defGridAttr != this) ) + { + // if we still don't have one then use the grid default + // (no need for IncRef() here neither) + renderer = m_defGridAttr->GetRenderer(NULL, 0, 0); + } + else // default grid attr + { + // use m_renderer which we had decided not to use initially + renderer = m_renderer; + if ( renderer ) + renderer->IncRef(); + } + } + } + + // we're supposed to always find something + wxASSERT_MSG(renderer, wxT("Missing default cell renderer")); + + return renderer; +} + +// same as above, except for s/renderer/editor/g +wxGridCellEditor* wxGridCellAttr::GetEditor(wxGrid* grid, int row, int col) const +{ + wxGridCellEditor *editor = NULL; + + if ( m_editor && this != m_defGridAttr ) + { + // use the cells editor if it has one + editor = m_editor; + editor->IncRef(); + } + else // no non default cell editor + { + // get default editor for the data type + if ( grid ) + { + // GetDefaultEditorForCell() will do IncRef() for us + editor = grid->GetDefaultEditorForCell(row, col); + } + + if ( editor == NULL ) + { + if ( (m_defGridAttr != NULL) && (m_defGridAttr != this) ) + { + // if we still don't have one then use the grid default + // (no need for IncRef() here neither) + editor = m_defGridAttr->GetEditor(NULL, 0, 0); + } + else // default grid attr + { + // use m_editor which we had decided not to use initially + editor = m_editor; + if ( editor ) + editor->IncRef(); + } + } + } + + // we're supposed to always find something + wxASSERT_MSG(editor, wxT("Missing default cell editor")); + + return editor; +} + +// ---------------------------------------------------------------------------- +// wxGridCellAttrData +// ---------------------------------------------------------------------------- + +void wxGridCellAttrData::SetAttr(wxGridCellAttr *attr, int row, int col) +{ + // Note: contrary to wxGridRowOrColAttrData::SetAttr, we must not + // touch attribute's reference counting explicitly, since this + // is managed by class wxGridCellWithAttr + int n = FindIndex(row, col); + if ( n == wxNOT_FOUND ) + { + if ( attr ) + { + // add the attribute + m_attrs.Add(new wxGridCellWithAttr(row, col, attr)); + } + //else: nothing to do + } + else // we already have an attribute for this cell + { + if ( attr ) + { + // change the attribute + m_attrs[(size_t)n].ChangeAttr(attr); + } + else + { + // remove this attribute + m_attrs.RemoveAt((size_t)n); + } + } +} + +wxGridCellAttr *wxGridCellAttrData::GetAttr(int row, int col) const +{ + wxGridCellAttr *attr = (wxGridCellAttr *)NULL; + + int n = FindIndex(row, col); + if ( n != wxNOT_FOUND ) + { + attr = m_attrs[(size_t)n].attr; + attr->IncRef(); + } + + return attr; +} + +void wxGridCellAttrData::UpdateAttrRows( size_t pos, int numRows ) +{ + size_t count = m_attrs.GetCount(); + for ( size_t n = 0; n < count; n++ ) + { + wxGridCellCoords& coords = m_attrs[n].coords; + wxCoord row = coords.GetRow(); + if ((size_t)row >= pos) + { + if (numRows > 0) + { + // If rows inserted, include row counter where necessary + coords.SetRow(row + numRows); + } + else if (numRows < 0) + { + // If rows deleted ... + if ((size_t)row >= pos - numRows) + { + // ...either decrement row counter (if row still exists)... + coords.SetRow(row + numRows); + } + else + { + // ...or remove the attribute + m_attrs.RemoveAt(n); + n--; + count--; + } + } + } + } +} + +void wxGridCellAttrData::UpdateAttrCols( size_t pos, int numCols ) +{ + size_t count = m_attrs.GetCount(); + for ( size_t n = 0; n < count; n++ ) + { + wxGridCellCoords& coords = m_attrs[n].coords; + wxCoord col = coords.GetCol(); + if ( (size_t)col >= pos ) + { + if ( numCols > 0 ) + { + // If rows inserted, include row counter where necessary + coords.SetCol(col + numCols); + } + else if (numCols < 0) + { + // If rows deleted ... + if ((size_t)col >= pos - numCols) + { + // ...either decrement row counter (if row still exists)... + coords.SetCol(col + numCols); + } + else + { + // ...or remove the attribute + m_attrs.RemoveAt(n); + n--; + count--; + } + } + } + } +} + +int wxGridCellAttrData::FindIndex(int row, int col) const +{ + size_t count = m_attrs.GetCount(); + for ( size_t n = 0; n < count; n++ ) + { + const wxGridCellCoords& coords = m_attrs[n].coords; + if ( (coords.GetRow() == row) && (coords.GetCol() == col) ) + { + return n; + } + } + + return wxNOT_FOUND; +} + +// ---------------------------------------------------------------------------- +// wxGridRowOrColAttrData +// ---------------------------------------------------------------------------- + +wxGridRowOrColAttrData::~wxGridRowOrColAttrData() +{ + size_t count = m_attrs.Count(); + for ( size_t n = 0; n < count; n++ ) + { + m_attrs[n]->DecRef(); + } +} + +wxGridCellAttr *wxGridRowOrColAttrData::GetAttr(int rowOrCol) const +{ + wxGridCellAttr *attr = (wxGridCellAttr *)NULL; + + int n = m_rowsOrCols.Index(rowOrCol); + if ( n != wxNOT_FOUND ) + { + attr = m_attrs[(size_t)n]; + attr->IncRef(); + } + + return attr; +} + +void wxGridRowOrColAttrData::SetAttr(wxGridCellAttr *attr, int rowOrCol) +{ + int i = m_rowsOrCols.Index(rowOrCol); + if ( i == wxNOT_FOUND ) + { + if ( attr ) + { + // add the attribute - no need to do anything to reference count + // since we take ownership of the attribute. + m_rowsOrCols.Add(rowOrCol); + m_attrs.Add(attr); + } + // nothing to remove + } + else + { + size_t n = (size_t)i; + if ( m_attrs[n] == attr ) + // nothing to do + return; + if ( attr ) + { + // change the attribute, handling reference count manually, + // taking ownership of the new attribute. + m_attrs[n]->DecRef(); + m_attrs[n] = attr; + } + else + { + // remove this attribute, handling reference count manually + m_attrs[n]->DecRef(); + m_rowsOrCols.RemoveAt(n); + m_attrs.RemoveAt(n); + } + } +} + +void wxGridRowOrColAttrData::UpdateAttrRowsOrCols( size_t pos, int numRowsOrCols ) +{ + size_t count = m_attrs.GetCount(); + for ( size_t n = 0; n < count; n++ ) + { + int & rowOrCol = m_rowsOrCols[n]; + if ( (size_t)rowOrCol >= pos ) + { + if ( numRowsOrCols > 0 ) + { + // If rows inserted, include row counter where necessary + rowOrCol += numRowsOrCols; + } + else if ( numRowsOrCols < 0) + { + // If rows deleted, either decrement row counter (if row still exists) + if ((size_t)rowOrCol >= pos - numRowsOrCols) + rowOrCol += numRowsOrCols; + else + { + m_rowsOrCols.RemoveAt(n); + m_attrs[n]->DecRef(); + m_attrs.RemoveAt(n); + n--; + count--; + } + } + } + } +} + +// ---------------------------------------------------------------------------- +// wxGridCellAttrProvider +// ---------------------------------------------------------------------------- + +wxGridCellAttrProvider::wxGridCellAttrProvider() +{ + m_data = (wxGridCellAttrProviderData *)NULL; +} + +wxGridCellAttrProvider::~wxGridCellAttrProvider() +{ + delete m_data; +} + +void wxGridCellAttrProvider::InitData() +{ + m_data = new wxGridCellAttrProviderData; +} + +wxGridCellAttr *wxGridCellAttrProvider::GetAttr(int row, int col, + wxGridCellAttr::wxAttrKind kind ) const +{ + wxGridCellAttr *attr = (wxGridCellAttr *)NULL; + if ( m_data ) + { + switch (kind) + { + case (wxGridCellAttr::Any): + // Get cached merge attributes. + // Currently not used as no cache implemented as not mutable + // attr = m_data->m_mergeAttr.GetAttr(row, col); + if (!attr) + { + // Basically implement old version. + // Also check merge cache, so we don't have to re-merge every time.. + wxGridCellAttr *attrcell = m_data->m_cellAttrs.GetAttr(row, col); + wxGridCellAttr *attrrow = m_data->m_rowAttrs.GetAttr(row); + wxGridCellAttr *attrcol = m_data->m_colAttrs.GetAttr(col); + + if ((attrcell != attrrow) && (attrrow != attrcol) && (attrcell != attrcol)) + { + // Two or more are non NULL + attr = new wxGridCellAttr; + attr->SetKind(wxGridCellAttr::Merged); + + // Order is important.. + if (attrcell) + { + attr->MergeWith(attrcell); + attrcell->DecRef(); + } + if (attrcol) + { + attr->MergeWith(attrcol); + attrcol->DecRef(); + } + if (attrrow) + { + attr->MergeWith(attrrow); + attrrow->DecRef(); + } + + // store merge attr if cache implemented + //attr->IncRef(); + //m_data->m_mergeAttr.SetAttr(attr, row, col); + } + else + { + // one or none is non null return it or null. + if (attrrow) + attr = attrrow; + if (attrcol) + { + if (attr) + attr->DecRef(); + attr = attrcol; + } + if (attrcell) + { + if (attr) + attr->DecRef(); + attr = attrcell; + } + } + } + break; + + case (wxGridCellAttr::Cell): + attr = m_data->m_cellAttrs.GetAttr(row, col); + break; + + case (wxGridCellAttr::Col): + attr = m_data->m_colAttrs.GetAttr(col); + break; + + case (wxGridCellAttr::Row): + attr = m_data->m_rowAttrs.GetAttr(row); + break; + + default: + // unused as yet... + // (wxGridCellAttr::Default): + // (wxGridCellAttr::Merged): + break; + } + } + + return attr; +} + +void wxGridCellAttrProvider::SetAttr(wxGridCellAttr *attr, + int row, int col) +{ + if ( !m_data ) + InitData(); + + m_data->m_cellAttrs.SetAttr(attr, row, col); +} + +void wxGridCellAttrProvider::SetRowAttr(wxGridCellAttr *attr, int row) +{ + if ( !m_data ) + InitData(); + + m_data->m_rowAttrs.SetAttr(attr, row); +} + +void wxGridCellAttrProvider::SetColAttr(wxGridCellAttr *attr, int col) +{ + if ( !m_data ) + InitData(); + + m_data->m_colAttrs.SetAttr(attr, col); +} + +void wxGridCellAttrProvider::UpdateAttrRows( size_t pos, int numRows ) +{ + if ( m_data ) + { + m_data->m_cellAttrs.UpdateAttrRows( pos, numRows ); + + m_data->m_rowAttrs.UpdateAttrRowsOrCols( pos, numRows ); + } +} + +void wxGridCellAttrProvider::UpdateAttrCols( size_t pos, int numCols ) +{ + if ( m_data ) + { + m_data->m_cellAttrs.UpdateAttrCols( pos, numCols ); + + m_data->m_colAttrs.UpdateAttrRowsOrCols( pos, numCols ); + } +} + +// ---------------------------------------------------------------------------- +// wxGridTypeRegistry +// ---------------------------------------------------------------------------- + +wxGridTypeRegistry::~wxGridTypeRegistry() +{ + size_t count = m_typeinfo.Count(); + for ( size_t i = 0; i < count; i++ ) + delete m_typeinfo[i]; +} + +void wxGridTypeRegistry::RegisterDataType(const wxString& typeName, + wxGridCellRenderer* renderer, + wxGridCellEditor* editor) +{ + wxGridDataTypeInfo* info = new wxGridDataTypeInfo(typeName, renderer, editor); + + // is it already registered? + int loc = FindRegisteredDataType(typeName); + if ( loc != wxNOT_FOUND ) + { + delete m_typeinfo[loc]; + m_typeinfo[loc] = info; + } + else + { + m_typeinfo.Add(info); + } +} + +int wxGridTypeRegistry::FindRegisteredDataType(const wxString& typeName) +{ + size_t count = m_typeinfo.GetCount(); + for ( size_t i = 0; i < count; i++ ) + { + if ( typeName == m_typeinfo[i]->m_typeName ) + { + return i; + } + } + + return wxNOT_FOUND; +} + +int wxGridTypeRegistry::FindDataType(const wxString& typeName) +{ + int index = FindRegisteredDataType(typeName); + if ( index == wxNOT_FOUND ) + { + // check whether this is one of the standard ones, in which case + // register it "on the fly" +#if wxUSE_TEXTCTRL + if ( typeName == wxGRID_VALUE_STRING ) + { + RegisterDataType(wxGRID_VALUE_STRING, + new wxGridCellStringRenderer, + new wxGridCellTextEditor); + } + else +#endif // wxUSE_TEXTCTRL +#if wxUSE_CHECKBOX + if ( typeName == wxGRID_VALUE_BOOL ) + { + RegisterDataType(wxGRID_VALUE_BOOL, + new wxGridCellBoolRenderer, + new wxGridCellBoolEditor); + } + else +#endif // wxUSE_CHECKBOX +#if wxUSE_TEXTCTRL + if ( typeName == wxGRID_VALUE_NUMBER ) + { + RegisterDataType(wxGRID_VALUE_NUMBER, + new wxGridCellNumberRenderer, + new wxGridCellNumberEditor); + } + else if ( typeName == wxGRID_VALUE_FLOAT ) + { + RegisterDataType(wxGRID_VALUE_FLOAT, + new wxGridCellFloatRenderer, + new wxGridCellFloatEditor); + } + else +#endif // wxUSE_TEXTCTRL +#if wxUSE_COMBOBOX + if ( typeName == wxGRID_VALUE_CHOICE ) + { + RegisterDataType(wxGRID_VALUE_CHOICE, + new wxGridCellStringRenderer, + new wxGridCellChoiceEditor); + } + else +#endif // wxUSE_COMBOBOX + { + return wxNOT_FOUND; + } + + // we get here only if just added the entry for this type, so return + // the last index + index = m_typeinfo.GetCount() - 1; + } + + return index; +} + +int wxGridTypeRegistry::FindOrCloneDataType(const wxString& typeName) +{ + int index = FindDataType(typeName); + if ( index == wxNOT_FOUND ) + { + // the first part of the typename is the "real" type, anything after ':' + // are the parameters for the renderer + index = FindDataType(typeName.BeforeFirst(_T(':'))); + if ( index == wxNOT_FOUND ) + { + return wxNOT_FOUND; + } + + wxGridCellRenderer *renderer = GetRenderer(index); + wxGridCellRenderer *rendererOld = renderer; + renderer = renderer->Clone(); + rendererOld->DecRef(); + + wxGridCellEditor *editor = GetEditor(index); + wxGridCellEditor *editorOld = editor; + editor = editor->Clone(); + editorOld->DecRef(); + + // do it even if there are no parameters to reset them to defaults + wxString params = typeName.AfterFirst(_T(':')); + renderer->SetParameters(params); + editor->SetParameters(params); + + // register the new typename + RegisterDataType(typeName, renderer, editor); + + // we just registered it, it's the last one + index = m_typeinfo.GetCount() - 1; + } + + return index; +} + +wxGridCellRenderer* wxGridTypeRegistry::GetRenderer(int index) +{ + wxGridCellRenderer* renderer = m_typeinfo[index]->m_renderer; + if (renderer) + renderer->IncRef(); + + return renderer; +} + +wxGridCellEditor* wxGridTypeRegistry::GetEditor(int index) +{ + wxGridCellEditor* editor = m_typeinfo[index]->m_editor; + if (editor) + editor->IncRef(); + + return editor; +} + +// ---------------------------------------------------------------------------- +// wxGridTableBase +// ---------------------------------------------------------------------------- + +IMPLEMENT_ABSTRACT_CLASS( wxGridTableBase, wxObject ) + +wxGridTableBase::wxGridTableBase() +{ + m_view = (wxGrid *) NULL; + m_attrProvider = (wxGridCellAttrProvider *) NULL; +} + +wxGridTableBase::~wxGridTableBase() +{ + delete m_attrProvider; +} + +void wxGridTableBase::SetAttrProvider(wxGridCellAttrProvider *attrProvider) +{ + delete m_attrProvider; + m_attrProvider = attrProvider; +} + +bool wxGridTableBase::CanHaveAttributes() +{ + if ( ! GetAttrProvider() ) + { + // use the default attr provider by default + SetAttrProvider(new wxGridCellAttrProvider); + } + + return true; +} + +wxGridCellAttr *wxGridTableBase::GetAttr(int row, int col, wxGridCellAttr::wxAttrKind kind) +{ + if ( m_attrProvider ) + return m_attrProvider->GetAttr(row, col, kind); + else + return (wxGridCellAttr *)NULL; +} + +void wxGridTableBase::SetAttr(wxGridCellAttr* attr, int row, int col) +{ + if ( m_attrProvider ) + { + if ( attr ) + attr->SetKind(wxGridCellAttr::Cell); + m_attrProvider->SetAttr(attr, row, col); + } + else + { + // as we take ownership of the pointer and don't store it, we must + // free it now + wxSafeDecRef(attr); + } +} + +void wxGridTableBase::SetRowAttr(wxGridCellAttr *attr, int row) +{ + if ( m_attrProvider ) + { + attr->SetKind(wxGridCellAttr::Row); + m_attrProvider->SetRowAttr(attr, row); + } + else + { + // as we take ownership of the pointer and don't store it, we must + // free it now + wxSafeDecRef(attr); + } +} + +void wxGridTableBase::SetColAttr(wxGridCellAttr *attr, int col) +{ + if ( m_attrProvider ) + { + attr->SetKind(wxGridCellAttr::Col); + m_attrProvider->SetColAttr(attr, col); + } + else + { + // as we take ownership of the pointer and don't store it, we must + // free it now + wxSafeDecRef(attr); + } +} + +bool wxGridTableBase::InsertRows( size_t WXUNUSED(pos), + size_t WXUNUSED(numRows) ) +{ + wxFAIL_MSG( wxT("Called grid table class function InsertRows\nbut your derived table class does not override this function") ); + + return false; +} + +bool wxGridTableBase::AppendRows( size_t WXUNUSED(numRows) ) +{ + wxFAIL_MSG( wxT("Called grid table class function AppendRows\nbut your derived table class does not override this function")); + + return false; +} + +bool wxGridTableBase::DeleteRows( size_t WXUNUSED(pos), + size_t WXUNUSED(numRows) ) +{ + wxFAIL_MSG( wxT("Called grid table class function DeleteRows\nbut your derived table class does not override this function")); + + return false; +} + +bool wxGridTableBase::InsertCols( size_t WXUNUSED(pos), + size_t WXUNUSED(numCols) ) +{ + wxFAIL_MSG( wxT("Called grid table class function InsertCols\nbut your derived table class does not override this function")); + + return false; +} + +bool wxGridTableBase::AppendCols( size_t WXUNUSED(numCols) ) +{ + wxFAIL_MSG(wxT("Called grid table class function AppendCols\nbut your derived table class does not override this function")); + + return false; +} + +bool wxGridTableBase::DeleteCols( size_t WXUNUSED(pos), + size_t WXUNUSED(numCols) ) +{ + wxFAIL_MSG( wxT("Called grid table class function DeleteCols\nbut your derived table class does not override this function")); + + return false; +} + +wxString wxGridTableBase::GetRowLabelValue( int row ) +{ + wxString s; + + // RD: Starting the rows at zero confuses users, + // no matter how much it makes sense to us geeks. + s << row + 1; + + return s; +} + +wxString wxGridTableBase::GetColLabelValue( int col ) +{ + // default col labels are: + // cols 0 to 25 : A-Z + // cols 26 to 675 : AA-ZZ + // etc. + + wxString s; + unsigned int i, n; + for ( n = 1; ; n++ ) + { + s += (wxChar) (_T('A') + (wxChar)(col % 26)); + col = col / 26 - 1; + if ( col < 0 ) + break; + } + + // reverse the string... + wxString s2; + for ( i = 0; i < n; i++ ) + { + s2 += s[n - i - 1]; + } + + return s2; +} + +wxString wxGridTableBase::GetTypeName( int WXUNUSED(row), int WXUNUSED(col) ) +{ + return wxGRID_VALUE_STRING; +} + +bool wxGridTableBase::CanGetValueAs( int WXUNUSED(row), int WXUNUSED(col), + const wxString& typeName ) +{ + return typeName == wxGRID_VALUE_STRING; +} + +bool wxGridTableBase::CanSetValueAs( int row, int col, const wxString& typeName ) +{ + return CanGetValueAs(row, col, typeName); +} + +long wxGridTableBase::GetValueAsLong( int WXUNUSED(row), int WXUNUSED(col) ) +{ + return 0; +} + +double wxGridTableBase::GetValueAsDouble( int WXUNUSED(row), int WXUNUSED(col) ) +{ + return 0.0; +} + +bool wxGridTableBase::GetValueAsBool( int WXUNUSED(row), int WXUNUSED(col) ) +{ + return false; +} + +void wxGridTableBase::SetValueAsLong( int WXUNUSED(row), int WXUNUSED(col), + long WXUNUSED(value) ) +{ +} + +void wxGridTableBase::SetValueAsDouble( int WXUNUSED(row), int WXUNUSED(col), + double WXUNUSED(value) ) +{ +} + +void wxGridTableBase::SetValueAsBool( int WXUNUSED(row), int WXUNUSED(col), + bool WXUNUSED(value) ) +{ +} + +void* wxGridTableBase::GetValueAsCustom( int WXUNUSED(row), int WXUNUSED(col), + const wxString& WXUNUSED(typeName) ) +{ + return NULL; +} + +void wxGridTableBase::SetValueAsCustom( int WXUNUSED(row), int WXUNUSED(col), + const wxString& WXUNUSED(typeName), + void* WXUNUSED(value) ) +{ +} + +////////////////////////////////////////////////////////////////////// +// +// Message class for the grid table to send requests and notifications +// to the grid view +// + +wxGridTableMessage::wxGridTableMessage() +{ + m_table = (wxGridTableBase *) NULL; + m_id = -1; + m_comInt1 = -1; + m_comInt2 = -1; +} + +wxGridTableMessage::wxGridTableMessage( wxGridTableBase *table, int id, + int commandInt1, int commandInt2 ) +{ + m_table = table; + m_id = id; + m_comInt1 = commandInt1; + m_comInt2 = commandInt2; +} + +////////////////////////////////////////////////////////////////////// +// +// A basic grid table for string data. An object of this class will +// created by wxGrid if you don't specify an alternative table class. +// + +WX_DEFINE_OBJARRAY(wxGridStringArray) + +IMPLEMENT_DYNAMIC_CLASS( wxGridStringTable, wxGridTableBase ) + +wxGridStringTable::wxGridStringTable() + : wxGridTableBase() +{ +} + +wxGridStringTable::wxGridStringTable( int numRows, int numCols ) + : wxGridTableBase() +{ + m_data.Alloc( numRows ); + + wxArrayString sa; + sa.Alloc( numCols ); + sa.Add( wxEmptyString, numCols ); + + m_data.Add( sa, numRows ); +} + +wxGridStringTable::~wxGridStringTable() +{ +} + +int wxGridStringTable::GetNumberRows() +{ + return m_data.GetCount(); +} + +int wxGridStringTable::GetNumberCols() +{ + if ( m_data.GetCount() > 0 ) + return m_data[0].GetCount(); + else + return 0; +} + +wxString wxGridStringTable::GetValue( int row, int col ) +{ + wxCHECK_MSG( (row < GetNumberRows()) && (col < GetNumberCols()), + wxEmptyString, + _T("invalid row or column index in wxGridStringTable") ); + + return m_data[row][col]; +} + +void wxGridStringTable::SetValue( int row, int col, const wxString& value ) +{ + wxCHECK_RET( (row < GetNumberRows()) && (col < GetNumberCols()), + _T("invalid row or column index in wxGridStringTable") ); + + m_data[row][col] = value; +} + +bool wxGridStringTable::IsEmptyCell( int row, int col ) +{ + wxCHECK_MSG( (row < GetNumberRows()) && (col < GetNumberCols()), + true, + _T("invalid row or column index in wxGridStringTable") ); + + return (m_data[row][col] == wxEmptyString); +} + +void wxGridStringTable::Clear() +{ + int row, col; + int numRows, numCols; + + numRows = m_data.GetCount(); + if ( numRows > 0 ) + { + numCols = m_data[0].GetCount(); + + for ( row = 0; row < numRows; row++ ) + { + for ( col = 0; col < numCols; col++ ) + { + m_data[row][col] = wxEmptyString; + } + } + } +} + +bool wxGridStringTable::InsertRows( size_t pos, size_t numRows ) +{ + size_t curNumRows = m_data.GetCount(); + size_t curNumCols = ( curNumRows > 0 ? m_data[0].GetCount() : + ( GetView() ? GetView()->GetNumberCols() : 0 ) ); + + if ( pos >= curNumRows ) + { + return AppendRows( numRows ); + } + + wxArrayString sa; + sa.Alloc( curNumCols ); + sa.Add( wxEmptyString, curNumCols ); + m_data.Insert( sa, pos, numRows ); + + if ( GetView() ) + { + wxGridTableMessage msg( this, + wxGRIDTABLE_NOTIFY_ROWS_INSERTED, + pos, + numRows ); + + GetView()->ProcessTableMessage( msg ); + } + + return true; +} + +bool wxGridStringTable::AppendRows( size_t numRows ) +{ + size_t curNumRows = m_data.GetCount(); + size_t curNumCols = ( curNumRows > 0 + ? m_data[0].GetCount() + : ( GetView() ? GetView()->GetNumberCols() : 0 ) ); + + wxArrayString sa; + if ( curNumCols > 0 ) + { + sa.Alloc( curNumCols ); + sa.Add( wxEmptyString, curNumCols ); + } + + m_data.Add( sa, numRows ); + + if ( GetView() ) + { + wxGridTableMessage msg( this, + wxGRIDTABLE_NOTIFY_ROWS_APPENDED, + numRows ); + + GetView()->ProcessTableMessage( msg ); + } + + return true; +} + +bool wxGridStringTable::DeleteRows( size_t pos, size_t numRows ) +{ + size_t curNumRows = m_data.GetCount(); + + if ( pos >= curNumRows ) + { + wxFAIL_MSG( wxString::Format + ( + wxT("Called wxGridStringTable::DeleteRows(pos=%lu, N=%lu)\nPos value is invalid for present table with %lu rows"), + (unsigned long)pos, + (unsigned long)numRows, + (unsigned long)curNumRows + ) ); + + return false; + } + + if ( numRows > curNumRows - pos ) + { + numRows = curNumRows - pos; + } + + if ( numRows >= curNumRows ) + { + m_data.Clear(); + } + else + { + m_data.RemoveAt( pos, numRows ); + } + + if ( GetView() ) + { + wxGridTableMessage msg( this, + wxGRIDTABLE_NOTIFY_ROWS_DELETED, + pos, + numRows ); + + GetView()->ProcessTableMessage( msg ); + } + + return true; +} + +bool wxGridStringTable::InsertCols( size_t pos, size_t numCols ) +{ + size_t row, col; + + size_t curNumRows = m_data.GetCount(); + size_t curNumCols = ( curNumRows > 0 + ? m_data[0].GetCount() + : ( GetView() ? GetView()->GetNumberCols() : 0 ) ); + + if ( pos >= curNumCols ) + { + return AppendCols( numCols ); + } + + if ( !m_colLabels.IsEmpty() ) + { + m_colLabels.Insert( wxEmptyString, pos, numCols ); + + size_t i; + for ( i = pos; i < pos + numCols; i++ ) + m_colLabels[i] = wxGridTableBase::GetColLabelValue( i ); + } + + for ( row = 0; row < curNumRows; row++ ) + { + for ( col = pos; col < pos + numCols; col++ ) + { + m_data[row].Insert( wxEmptyString, col ); + } + } + + if ( GetView() ) + { + wxGridTableMessage msg( this, + wxGRIDTABLE_NOTIFY_COLS_INSERTED, + pos, + numCols ); + + GetView()->ProcessTableMessage( msg ); + } + + return true; +} + +bool wxGridStringTable::AppendCols( size_t numCols ) +{ + size_t row; + + size_t curNumRows = m_data.GetCount(); + +#if 0 + if ( !curNumRows ) + { + // TODO: something better than this ? + // + wxFAIL_MSG( wxT("Unable to append cols to a grid table with no rows.\nCall AppendRows() first") ); + return false; + } +#endif + + for ( row = 0; row < curNumRows; row++ ) + { + m_data[row].Add( wxEmptyString, numCols ); + } + + if ( GetView() ) + { + wxGridTableMessage msg( this, + wxGRIDTABLE_NOTIFY_COLS_APPENDED, + numCols ); + + GetView()->ProcessTableMessage( msg ); + } + + return true; +} + +bool wxGridStringTable::DeleteCols( size_t pos, size_t numCols ) +{ + size_t row; + + size_t curNumRows = m_data.GetCount(); + size_t curNumCols = ( curNumRows > 0 ? m_data[0].GetCount() : + ( GetView() ? GetView()->GetNumberCols() : 0 ) ); + + if ( pos >= curNumCols ) + { + wxFAIL_MSG( wxString::Format + ( + wxT("Called wxGridStringTable::DeleteCols(pos=%lu, N=%lu)\nPos value is invalid for present table with %lu cols"), + (unsigned long)pos, + (unsigned long)numCols, + (unsigned long)curNumCols + ) ); + return false; + } + + int colID; + if ( GetView() ) + colID = GetView()->GetColAt( pos ); + else + colID = pos; + + if ( numCols > curNumCols - colID ) + { + numCols = curNumCols - colID; + } + + if ( !m_colLabels.IsEmpty() ) + { + // m_colLabels stores just as many elements as it needs, e.g. if only + // the label of the first column had been set it would have only one + // element and not numCols, so account for it + int nToRm = m_colLabels.size() - colID; + if ( nToRm > 0 ) + m_colLabels.RemoveAt( colID, nToRm ); + } + + for ( row = 0; row < curNumRows; row++ ) + { + if ( numCols >= curNumCols ) + { + m_data[row].Clear(); + } + else + { + m_data[row].RemoveAt( colID, numCols ); + } + } + + if ( GetView() ) + { + wxGridTableMessage msg( this, + wxGRIDTABLE_NOTIFY_COLS_DELETED, + pos, + numCols ); + + GetView()->ProcessTableMessage( msg ); + } + + return true; +} + +wxString wxGridStringTable::GetRowLabelValue( int row ) +{ + if ( row > (int)(m_rowLabels.GetCount()) - 1 ) + { + // using default label + // + return wxGridTableBase::GetRowLabelValue( row ); + } + else + { + return m_rowLabels[row]; + } +} + +wxString wxGridStringTable::GetColLabelValue( int col ) +{ + if ( col > (int)(m_colLabels.GetCount()) - 1 ) + { + // using default label + // + return wxGridTableBase::GetColLabelValue( col ); + } + else + { + return m_colLabels[col]; + } +} + +void wxGridStringTable::SetRowLabelValue( int row, const wxString& value ) +{ + if ( row > (int)(m_rowLabels.GetCount()) - 1 ) + { + int n = m_rowLabels.GetCount(); + int i; + + for ( i = n; i <= row; i++ ) + { + m_rowLabels.Add( wxGridTableBase::GetRowLabelValue(i) ); + } + } + + m_rowLabels[row] = value; +} + +void wxGridStringTable::SetColLabelValue( int col, const wxString& value ) +{ + if ( col > (int)(m_colLabels.GetCount()) - 1 ) + { + int n = m_colLabels.GetCount(); + int i; + + for ( i = n; i <= col; i++ ) + { + m_colLabels.Add( wxGridTableBase::GetColLabelValue(i) ); + } + } + + m_colLabels[col] = value; +} + + +////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////// + +IMPLEMENT_DYNAMIC_CLASS( wxGridRowLabelWindow, wxWindow ) + +BEGIN_EVENT_TABLE( wxGridRowLabelWindow, wxWindow ) + EVT_PAINT( wxGridRowLabelWindow::OnPaint ) + EVT_MOUSEWHEEL( wxGridRowLabelWindow::OnMouseWheel ) + EVT_MOUSE_EVENTS( wxGridRowLabelWindow::OnMouseEvent ) + EVT_KEY_DOWN( wxGridRowLabelWindow::OnKeyDown ) + EVT_KEY_UP( wxGridRowLabelWindow::OnKeyUp ) + EVT_CHAR( wxGridRowLabelWindow::OnChar ) +END_EVENT_TABLE() + +wxGridRowLabelWindow::wxGridRowLabelWindow( wxGrid *parent, + wxWindowID id, + const wxPoint &pos, const wxSize &size ) + : wxWindow( parent, id, pos, size, wxWANTS_CHARS | wxBORDER_NONE | wxFULL_REPAINT_ON_RESIZE ) +{ + m_owner = parent; +} + +void wxGridRowLabelWindow::OnPaint( wxPaintEvent& WXUNUSED(event) ) +{ + wxPaintDC dc(this); + + // NO - don't do this because it will set both the x and y origin + // coords to match the parent scrolled window and we just want to + // set the y coord - MB + // + // m_owner->PrepareDC( dc ); + + int x, y; + m_owner->CalcUnscrolledPosition( 0, 0, &x, &y ); + wxPoint pt = dc.GetDeviceOrigin(); + dc.SetDeviceOrigin( pt.x, pt.y-y ); + + wxArrayInt rows = m_owner->CalcRowLabelsExposed( GetUpdateRegion() ); + m_owner->DrawRowLabels( dc, rows ); +} + +void wxGridRowLabelWindow::OnMouseEvent( wxMouseEvent& event ) +{ + m_owner->ProcessRowLabelMouseEvent( event ); +} + +void wxGridRowLabelWindow::OnMouseWheel( wxMouseEvent& event ) +{ + m_owner->GetEventHandler()->ProcessEvent( event ); +} + +// This seems to be required for wxMotif otherwise the mouse +// cursor must be in the cell edit control to get key events +// +void wxGridRowLabelWindow::OnKeyDown( wxKeyEvent& event ) +{ + if ( !m_owner->GetEventHandler()->ProcessEvent( event ) ) + event.Skip(); +} + +void wxGridRowLabelWindow::OnKeyUp( wxKeyEvent& event ) +{ + if ( !m_owner->GetEventHandler()->ProcessEvent( event ) ) + event.Skip(); +} + +void wxGridRowLabelWindow::OnChar( wxKeyEvent& event ) +{ + if ( !m_owner->GetEventHandler()->ProcessEvent( event ) ) + event.Skip(); +} + +////////////////////////////////////////////////////////////////////// + +IMPLEMENT_DYNAMIC_CLASS( wxGridColLabelWindow, wxWindow ) + +BEGIN_EVENT_TABLE( wxGridColLabelWindow, wxWindow ) + EVT_PAINT( wxGridColLabelWindow::OnPaint ) + EVT_MOUSEWHEEL( wxGridColLabelWindow::OnMouseWheel ) + EVT_MOUSE_EVENTS( wxGridColLabelWindow::OnMouseEvent ) + EVT_KEY_DOWN( wxGridColLabelWindow::OnKeyDown ) + EVT_KEY_UP( wxGridColLabelWindow::OnKeyUp ) + EVT_CHAR( wxGridColLabelWindow::OnChar ) +END_EVENT_TABLE() + +wxGridColLabelWindow::wxGridColLabelWindow( wxGrid *parent, + wxWindowID id, + const wxPoint &pos, const wxSize &size ) + : wxWindow( parent, id, pos, size, wxWANTS_CHARS | wxBORDER_NONE | wxFULL_REPAINT_ON_RESIZE ) +{ + m_owner = parent; +} + +void wxGridColLabelWindow::OnPaint( wxPaintEvent& WXUNUSED(event) ) +{ + wxPaintDC dc(this); + + // NO - don't do this because it will set both the x and y origin + // coords to match the parent scrolled window and we just want to + // set the x coord - MB + // + // m_owner->PrepareDC( dc ); + + int x, y; + m_owner->CalcUnscrolledPosition( 0, 0, &x, &y ); + wxPoint pt = dc.GetDeviceOrigin(); + if (GetLayoutDirection() == wxLayout_RightToLeft) + dc.SetDeviceOrigin( pt.x+x, pt.y ); + else + dc.SetDeviceOrigin( pt.x-x, pt.y ); + + wxArrayInt cols = m_owner->CalcColLabelsExposed( GetUpdateRegion() ); + m_owner->DrawColLabels( dc, cols ); +} + +void wxGridColLabelWindow::OnMouseEvent( wxMouseEvent& event ) +{ + m_owner->ProcessColLabelMouseEvent( event ); +} + +void wxGridColLabelWindow::OnMouseWheel( wxMouseEvent& event ) +{ + m_owner->GetEventHandler()->ProcessEvent( event ); +} + +// This seems to be required for wxMotif otherwise the mouse +// cursor must be in the cell edit control to get key events +// +void wxGridColLabelWindow::OnKeyDown( wxKeyEvent& event ) +{ + if ( !m_owner->GetEventHandler()->ProcessEvent( event ) ) + event.Skip(); +} + +void wxGridColLabelWindow::OnKeyUp( wxKeyEvent& event ) +{ + if ( !m_owner->GetEventHandler()->ProcessEvent( event ) ) + event.Skip(); +} + +void wxGridColLabelWindow::OnChar( wxKeyEvent& event ) +{ + if ( !m_owner->GetEventHandler()->ProcessEvent( event ) ) + event.Skip(); +} + +////////////////////////////////////////////////////////////////////// + +IMPLEMENT_DYNAMIC_CLASS( wxGridCornerLabelWindow, wxWindow ) + +BEGIN_EVENT_TABLE( wxGridCornerLabelWindow, wxWindow ) + EVT_MOUSEWHEEL( wxGridCornerLabelWindow::OnMouseWheel ) + EVT_MOUSE_EVENTS( wxGridCornerLabelWindow::OnMouseEvent ) + EVT_PAINT( wxGridCornerLabelWindow::OnPaint ) + EVT_KEY_DOWN( wxGridCornerLabelWindow::OnKeyDown ) + EVT_KEY_UP( wxGridCornerLabelWindow::OnKeyUp ) + EVT_CHAR( wxGridCornerLabelWindow::OnChar ) +END_EVENT_TABLE() + +wxGridCornerLabelWindow::wxGridCornerLabelWindow( wxGrid *parent, + wxWindowID id, + const wxPoint &pos, const wxSize &size ) + : wxWindow( parent, id, pos, size, wxWANTS_CHARS | wxBORDER_NONE | wxFULL_REPAINT_ON_RESIZE ) +{ + m_owner = parent; +} + +void wxGridCornerLabelWindow::OnPaint( wxPaintEvent& WXUNUSED(event) ) +{ + wxPaintDC dc(this); + + int client_height = 0; + int client_width = 0; + GetClientSize( &client_width, &client_height ); + + // VZ: any reason for this ifdef? (FIXME) +#if 0 +def __WXGTK__ + wxRect rect; + rect.SetX( 1 ); + rect.SetY( 1 ); + rect.SetWidth( client_width - 2 ); + rect.SetHeight( client_height - 2 ); + + wxRendererNative::Get().DrawHeaderButton( this, dc, rect, 0 ); +#else // !__WXGTK__ + dc.SetPen( wxPen(wxSystemSettings::GetColour(wxSYS_COLOUR_3DSHADOW), 1, wxSOLID) ); + dc.DrawLine( client_width - 1, client_height - 1, client_width - 1, 0 ); + dc.DrawLine( client_width - 1, client_height - 1, 0, client_height - 1 ); + dc.DrawLine( 0, 0, client_width, 0 ); + dc.DrawLine( 0, 0, 0, client_height ); + + dc.SetPen( *wxWHITE_PEN ); + dc.DrawLine( 1, 1, client_width - 1, 1 ); + dc.DrawLine( 1, 1, 1, client_height - 1 ); +#endif +} + +void wxGridCornerLabelWindow::OnMouseEvent( wxMouseEvent& event ) +{ + m_owner->ProcessCornerLabelMouseEvent( event ); +} + +void wxGridCornerLabelWindow::OnMouseWheel( wxMouseEvent& event ) +{ + m_owner->GetEventHandler()->ProcessEvent(event); +} + +// This seems to be required for wxMotif otherwise the mouse +// cursor must be in the cell edit control to get key events +// +void wxGridCornerLabelWindow::OnKeyDown( wxKeyEvent& event ) +{ + if ( !m_owner->GetEventHandler()->ProcessEvent( event ) ) + event.Skip(); +} + +void wxGridCornerLabelWindow::OnKeyUp( wxKeyEvent& event ) +{ + if ( !m_owner->GetEventHandler()->ProcessEvent( event ) ) + event.Skip(); +} + +void wxGridCornerLabelWindow::OnChar( wxKeyEvent& event ) +{ + if ( !m_owner->GetEventHandler()->ProcessEvent( event ) ) + event.Skip(); +} + +////////////////////////////////////////////////////////////////////// + +IMPLEMENT_DYNAMIC_CLASS( wxGridWindow, wxWindow ) + +BEGIN_EVENT_TABLE( wxGridWindow, wxWindow ) + EVT_PAINT( wxGridWindow::OnPaint ) + EVT_MOUSEWHEEL( wxGridWindow::OnMouseWheel ) + EVT_MOUSE_EVENTS( wxGridWindow::OnMouseEvent ) + EVT_KEY_DOWN( wxGridWindow::OnKeyDown ) + EVT_KEY_UP( wxGridWindow::OnKeyUp ) + EVT_CHAR( wxGridWindow::OnChar ) + EVT_SET_FOCUS( wxGridWindow::OnFocus ) + EVT_KILL_FOCUS( wxGridWindow::OnFocus ) + EVT_ERASE_BACKGROUND( wxGridWindow::OnEraseBackground ) +END_EVENT_TABLE() + +wxGridWindow::wxGridWindow( wxGrid *parent, + wxGridRowLabelWindow *rowLblWin, + wxGridColLabelWindow *colLblWin, + wxWindowID id, + const wxPoint &pos, + const wxSize &size ) + : wxWindow( + parent, id, pos, size, + wxWANTS_CHARS | wxBORDER_NONE | wxCLIP_CHILDREN | wxFULL_REPAINT_ON_RESIZE, + wxT("grid window") ) +{ + m_owner = parent; + m_rowLabelWin = rowLblWin; + m_colLabelWin = colLblWin; +} + +void wxGridWindow::OnPaint( wxPaintEvent &WXUNUSED(event) ) +{ + wxPaintDC dc( this ); + m_owner->PrepareDC( dc ); + wxRegion reg = GetUpdateRegion(); + wxGridCellCoordsArray dirtyCells = m_owner->CalcCellsExposed( reg ); + m_owner->DrawGridCellArea( dc, dirtyCells ); + +#if WXGRID_DRAW_LINES + m_owner->DrawAllGridLines( dc, reg ); +#endif + + m_owner->DrawGridSpace( dc ); + m_owner->DrawHighlight( dc, dirtyCells ); +} + +void wxGridWindow::ScrollWindow( int dx, int dy, const wxRect *rect ) +{ + wxWindow::ScrollWindow( dx, dy, rect ); + m_rowLabelWin->ScrollWindow( 0, dy, rect ); + m_colLabelWin->ScrollWindow( dx, 0, rect ); +} + +void wxGridWindow::OnMouseEvent( wxMouseEvent& event ) +{ + if (event.ButtonDown(wxMOUSE_BTN_LEFT) && FindFocus() != this) + SetFocus(); + + m_owner->ProcessGridCellMouseEvent( event ); +} + +void wxGridWindow::OnMouseWheel( wxMouseEvent& event ) +{ + m_owner->GetEventHandler()->ProcessEvent( event ); +} + +// This seems to be required for wxMotif/wxGTK otherwise the mouse +// cursor must be in the cell edit control to get key events +// +void wxGridWindow::OnKeyDown( wxKeyEvent& event ) +{ + if ( !m_owner->GetEventHandler()->ProcessEvent( event ) ) + event.Skip(); +} + +void wxGridWindow::OnKeyUp( wxKeyEvent& event ) +{ + if ( !m_owner->GetEventHandler()->ProcessEvent( event ) ) + event.Skip(); +} + +void wxGridWindow::OnChar( wxKeyEvent& event ) +{ + if ( !m_owner->GetEventHandler()->ProcessEvent( event ) ) + event.Skip(); +} + +void wxGridWindow::OnEraseBackground( wxEraseEvent& WXUNUSED(event) ) +{ +} + +void wxGridWindow::OnFocus(wxFocusEvent& event) +{ + // current cell cursor {dis,re}appears on focus change: + wxRect cursor = m_owner->CellToRect(m_owner->GetGridCursorRow(), + m_owner->GetGridCursorCol()); + Refresh(true, &cursor); + + // and if we have any selection, it has to be repainted, because it + // uses different colour when the grid is not focused: + if ( m_owner->IsSelection() ) + { + Refresh(); + } + else + { + // NB: Note that this code is in "else" branch only because the other + // branch refreshes everything and so there's no point in calling + // Refresh() again, *not* because it should only be done if + // !IsSelection(). If the above code is ever optimized to refresh + // only selected area, this needs to be moved out of the "else" + // branch so that it's always executed. + + // current cell cursor {dis,re}appears on focus change: + const wxGridCellCoords cursorCoords(m_owner->GetGridCursorRow(), + m_owner->GetGridCursorCol()); + const wxRect cursor = + m_owner->BlockToDeviceRect(cursorCoords, cursorCoords); + Refresh(true, &cursor); + } + + if ( !m_owner->GetEventHandler()->ProcessEvent( event ) ) + event.Skip(); +} + +////////////////////////////////////////////////////////////////////// + +// Internal Helper function for computing row or column from some +// (unscrolled) coordinate value, using either +// m_defaultRowHeight/m_defaultColWidth or binary search on array +// of m_rowBottoms/m_ColRights to speed up the search! + +// Internal helper macros for simpler use of that function + +static int CoordToRowOrCol(int coord, int defaultDist, int minDist, + const wxArrayInt& BorderArray, int nMax, + bool clipToMinMax); + +#define internalXToCol(x) XToCol(x, true) +#define internalYToRow(y) CoordToRowOrCol(y, m_defaultRowHeight, \ + m_minAcceptableRowHeight, \ + m_rowBottoms, m_numRows, true) + +///////////////////////////////////////////////////////////////////// + +#if wxUSE_EXTENDED_RTTI +WX_DEFINE_FLAGS( wxGridStyle ) + +wxBEGIN_FLAGS( wxGridStyle ) + // new style border flags, we put them first to + // use them for streaming out + wxFLAGS_MEMBER(wxBORDER_SIMPLE) + wxFLAGS_MEMBER(wxBORDER_SUNKEN) + wxFLAGS_MEMBER(wxBORDER_DOUBLE) + wxFLAGS_MEMBER(wxBORDER_RAISED) + wxFLAGS_MEMBER(wxBORDER_STATIC) + wxFLAGS_MEMBER(wxBORDER_NONE) + + // old style border flags + wxFLAGS_MEMBER(wxSIMPLE_BORDER) + wxFLAGS_MEMBER(wxSUNKEN_BORDER) + wxFLAGS_MEMBER(wxDOUBLE_BORDER) + wxFLAGS_MEMBER(wxRAISED_BORDER) + wxFLAGS_MEMBER(wxSTATIC_BORDER) + wxFLAGS_MEMBER(wxBORDER) + + // standard window styles + wxFLAGS_MEMBER(wxTAB_TRAVERSAL) + wxFLAGS_MEMBER(wxCLIP_CHILDREN) + wxFLAGS_MEMBER(wxTRANSPARENT_WINDOW) + wxFLAGS_MEMBER(wxWANTS_CHARS) + wxFLAGS_MEMBER(wxFULL_REPAINT_ON_RESIZE) + wxFLAGS_MEMBER(wxALWAYS_SHOW_SB) + wxFLAGS_MEMBER(wxVSCROLL) + wxFLAGS_MEMBER(wxHSCROLL) + +wxEND_FLAGS( wxGridStyle ) + +IMPLEMENT_DYNAMIC_CLASS_XTI(wxGrid, wxScrolledWindow,"wx/grid.h") + +wxBEGIN_PROPERTIES_TABLE(wxGrid) + wxHIDE_PROPERTY( Children ) + wxPROPERTY_FLAGS( WindowStyle , wxGridStyle , long , SetWindowStyleFlag , GetWindowStyleFlag , EMPTY_MACROVALUE, 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // style +wxEND_PROPERTIES_TABLE() + +wxBEGIN_HANDLERS_TABLE(wxGrid) +wxEND_HANDLERS_TABLE() + +wxCONSTRUCTOR_5( wxGrid , wxWindow* , Parent , wxWindowID , Id , wxPoint , Position , wxSize , Size , long , WindowStyle ) + +/* + TODO : Expose more information of a list's layout, etc. via appropriate objects (e.g., NotebookPageInfo) +*/ +#else +IMPLEMENT_DYNAMIC_CLASS( wxGrid, wxScrolledWindow ) +#endif + +BEGIN_EVENT_TABLE( wxGrid, wxScrolledWindow ) + EVT_PAINT( wxGrid::OnPaint ) + EVT_SIZE( wxGrid::OnSize ) + EVT_KEY_DOWN( wxGrid::OnKeyDown ) + EVT_KEY_UP( wxGrid::OnKeyUp ) + EVT_CHAR ( wxGrid::OnChar ) + EVT_ERASE_BACKGROUND( wxGrid::OnEraseBackground ) +END_EVENT_TABLE() + +wxGrid::wxGrid() +{ + // in order to make sure that a size event is not + // trigerred in a unfinished state + m_cornerLabelWin = NULL; + m_rowLabelWin = NULL; + m_colLabelWin = NULL; + m_gridWin = NULL; +} + +wxGrid::wxGrid( wxWindow *parent, + wxWindowID id, + const wxPoint& pos, + const wxSize& size, + long style, + const wxString& name ) + : wxScrolledWindow( parent, id, pos, size, (style | wxWANTS_CHARS), name ), + m_colMinWidths(GRID_HASH_SIZE), + m_rowMinHeights(GRID_HASH_SIZE) +{ + Create(); + SetInitialSize(size); +} + +bool wxGrid::Create(wxWindow *parent, wxWindowID id, + const wxPoint& pos, const wxSize& size, + long style, const wxString& name) +{ + if (!wxScrolledWindow::Create(parent, id, pos, size, + style | wxWANTS_CHARS, name)) + return false; + + m_colMinWidths = wxLongToLongHashMap(GRID_HASH_SIZE); + m_rowMinHeights = wxLongToLongHashMap(GRID_HASH_SIZE); + + Create(); + SetInitialSize(size); + CalcDimensions(); + + return true; +} + +wxGrid::~wxGrid() +{ + // Must do this or ~wxScrollHelper will pop the wrong event handler + SetTargetWindow(this); + ClearAttrCache(); + wxSafeDecRef(m_defaultCellAttr); + +#ifdef DEBUG_ATTR_CACHE + size_t total = gs_nAttrCacheHits + gs_nAttrCacheMisses; + wxPrintf(_T("wxGrid attribute cache statistics: " + "total: %u, hits: %u (%u%%)\n"), + total, gs_nAttrCacheHits, + total ? (gs_nAttrCacheHits*100) / total : 0); +#endif + + // if we own the table, just delete it, otherwise at least don't leave it + // with dangling view pointer + if ( m_ownTable ) + delete m_table; + else if ( m_table && m_table->GetView() == this ) + m_table->SetView(NULL); + + delete m_typeRegistry; + delete m_selection; +} + +// +// ----- internal init and update functions +// + +// NOTE: If using the default visual attributes works everywhere then this can +// be removed as well as the #else cases below. +#define _USE_VISATTR 0 + +void wxGrid::Create() +{ + // set to true by CreateGrid + m_created = false; + + // create the type registry + m_typeRegistry = new wxGridTypeRegistry; + m_selection = NULL; + + m_table = (wxGridTableBase *) NULL; + m_ownTable = false; + + m_cellEditCtrlEnabled = false; + + m_defaultCellAttr = new wxGridCellAttr(); + + // Set default cell attributes + m_defaultCellAttr->SetDefAttr(m_defaultCellAttr); + m_defaultCellAttr->SetKind(wxGridCellAttr::Default); + m_defaultCellAttr->SetFont(GetFont()); + m_defaultCellAttr->SetAlignment(wxALIGN_LEFT, wxALIGN_TOP); + m_defaultCellAttr->SetRenderer(new wxGridCellStringRenderer); + m_defaultCellAttr->SetEditor(new wxGridCellTextEditor); + +#if _USE_VISATTR + wxVisualAttributes gva = wxListBox::GetClassDefaultAttributes(); + wxVisualAttributes lva = wxPanel::GetClassDefaultAttributes(); + + m_defaultCellAttr->SetTextColour(gva.colFg); + m_defaultCellAttr->SetBackgroundColour(gva.colBg); + +#else + m_defaultCellAttr->SetTextColour( + wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT)); + m_defaultCellAttr->SetBackgroundColour( + wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW)); +#endif + + m_numRows = 0; + m_numCols = 0; + m_currentCellCoords = wxGridNoCellCoords; + + m_rowLabelWidth = WXGRID_DEFAULT_ROW_LABEL_WIDTH; + m_colLabelHeight = WXGRID_DEFAULT_COL_LABEL_HEIGHT; + + // subwindow components that make up the wxGrid + m_rowLabelWin = new wxGridRowLabelWindow( this, + wxID_ANY, + wxDefaultPosition, + wxDefaultSize ); + + m_colLabelWin = new wxGridColLabelWindow( this, + wxID_ANY, + wxDefaultPosition, + wxDefaultSize ); + + m_cornerLabelWin = new wxGridCornerLabelWindow( this, + wxID_ANY, + wxDefaultPosition, + wxDefaultSize ); + + m_gridWin = new wxGridWindow( this, + m_rowLabelWin, + m_colLabelWin, + wxID_ANY, + wxDefaultPosition, + wxDefaultSize ); + + SetTargetWindow( m_gridWin ); + +#if _USE_VISATTR + wxColour gfg = gva.colFg; + wxColour gbg = gva.colBg; + wxColour lfg = lva.colFg; + wxColour lbg = lva.colBg; +#else + wxColour gfg = wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOWTEXT ); + wxColour gbg = wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOW ); + wxColour lfg = wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOWTEXT ); + wxColour lbg = wxSystemSettings::GetColour( wxSYS_COLOUR_BTNFACE ); +#endif + + m_cornerLabelWin->SetOwnForegroundColour(lfg); + m_cornerLabelWin->SetOwnBackgroundColour(lbg); + m_rowLabelWin->SetOwnForegroundColour(lfg); + m_rowLabelWin->SetOwnBackgroundColour(lbg); + m_colLabelWin->SetOwnForegroundColour(lfg); + m_colLabelWin->SetOwnBackgroundColour(lbg); + + m_gridWin->SetOwnForegroundColour(gfg); + m_gridWin->SetOwnBackgroundColour(gbg); + + Init(); +} + +bool wxGrid::CreateGrid( int numRows, int numCols, + wxGrid::wxGridSelectionModes selmode ) +{ + wxCHECK_MSG( !m_created, + false, + wxT("wxGrid::CreateGrid or wxGrid::SetTable called more than once") ); + + m_numRows = numRows; + m_numCols = numCols; + + m_table = new wxGridStringTable( m_numRows, m_numCols ); + m_table->SetView( this ); + m_ownTable = true; + m_selection = new wxGridSelection( this, selmode ); + + CalcDimensions(); + + m_created = true; + + return m_created; +} + +void wxGrid::SetSelectionMode(wxGrid::wxGridSelectionModes selmode) +{ + wxCHECK_RET( m_created, + wxT("Called wxGrid::SetSelectionMode() before calling CreateGrid()") ); + + m_selection->SetSelectionMode( selmode ); +} + +wxGrid::wxGridSelectionModes wxGrid::GetSelectionMode() const +{ + wxCHECK_MSG( m_created, wxGrid::wxGridSelectCells, + wxT("Called wxGrid::GetSelectionMode() before calling CreateGrid()") ); + + return m_selection->GetSelectionMode(); +} + +bool wxGrid::SetTable( wxGridTableBase *table, bool takeOwnership, + wxGrid::wxGridSelectionModes selmode ) +{ + bool checkSelection = false; + if ( m_created ) + { + // stop all processing + m_created = false; + + if (m_table) + { + m_table->SetView(0); + if( m_ownTable ) + delete m_table; + m_table = NULL; + } + + delete m_selection; + m_selection = NULL; + + m_ownTable = false; + m_numRows = 0; + m_numCols = 0; + checkSelection = true; + + // kill row and column size arrays + m_colWidths.Empty(); + m_colRights.Empty(); + m_rowHeights.Empty(); + m_rowBottoms.Empty(); + } + + if (table) + { + m_numRows = table->GetNumberRows(); + m_numCols = table->GetNumberCols(); + + m_table = table; + m_table->SetView( this ); + m_ownTable = takeOwnership; + m_selection = new wxGridSelection( this, selmode ); + if (checkSelection) + { + // If the newly set table is smaller than the + // original one current cell and selection regions + // might be invalid, + m_selectingKeyboard = wxGridNoCellCoords; + m_currentCellCoords = + wxGridCellCoords(wxMin(m_numRows, m_currentCellCoords.GetRow()), + wxMin(m_numCols, m_currentCellCoords.GetCol())); + if (m_selectingTopLeft.GetRow() >= m_numRows || + m_selectingTopLeft.GetCol() >= m_numCols) + { + m_selectingTopLeft = wxGridNoCellCoords; + m_selectingBottomRight = wxGridNoCellCoords; + } + else + m_selectingBottomRight = + wxGridCellCoords(wxMin(m_numRows, + m_selectingBottomRight.GetRow()), + wxMin(m_numCols, + m_selectingBottomRight.GetCol())); + } + CalcDimensions(); + + m_created = true; + } + + return m_created; +} + +void wxGrid::Init() +{ + m_rowLabelWidth = WXGRID_DEFAULT_ROW_LABEL_WIDTH; + m_colLabelHeight = WXGRID_DEFAULT_COL_LABEL_HEIGHT; + + if ( m_rowLabelWin ) + { + m_labelBackgroundColour = m_rowLabelWin->GetBackgroundColour(); + } + else + { + m_labelBackgroundColour = *wxWHITE; + } + + m_labelTextColour = *wxBLACK; + + // init attr cache + m_attrCache.row = -1; + m_attrCache.col = -1; + m_attrCache.attr = NULL; + + // TODO: something better than this ? + // + m_labelFont = this->GetFont(); + m_labelFont.SetWeight( wxBOLD ); + + m_rowLabelHorizAlign = wxALIGN_CENTRE; + m_rowLabelVertAlign = wxALIGN_CENTRE; + + m_colLabelHorizAlign = wxALIGN_CENTRE; + m_colLabelVertAlign = wxALIGN_CENTRE; + m_colLabelTextOrientation = wxHORIZONTAL; + + m_defaultColWidth = WXGRID_DEFAULT_COL_WIDTH; + m_defaultRowHeight = m_gridWin->GetCharHeight(); + + m_minAcceptableColWidth = WXGRID_MIN_COL_WIDTH; + m_minAcceptableRowHeight = WXGRID_MIN_ROW_HEIGHT; + +#if defined(__WXMOTIF__) || defined(__WXGTK__) // see also text ctrl sizing in ShowCellEditControl() + m_defaultRowHeight += 8; +#else + m_defaultRowHeight += 4; +#endif + + m_gridLineColour = wxColour( 192,192,192 ); + m_gridLinesEnabled = true; + m_cellHighlightColour = *wxBLACK; + m_cellHighlightPenWidth = 2; + m_cellHighlightROPenWidth = 1; + + m_canDragColMove = false; + + m_cursorMode = WXGRID_CURSOR_SELECT_CELL; + m_winCapture = (wxWindow *)NULL; + m_canDragRowSize = true; + m_canDragColSize = true; + m_canDragGridSize = true; + m_canDragCell = false; + m_dragLastPos = -1; + m_dragRowOrCol = -1; + m_isDragging = false; + m_startDragPos = wxDefaultPosition; + + m_waitForSlowClick = false; + + m_rowResizeCursor = wxCursor( wxCURSOR_SIZENS ); + m_colResizeCursor = wxCursor( wxCURSOR_SIZEWE ); + + m_currentCellCoords = wxGridNoCellCoords; + + ClearSelection(); + + m_selectionBackground = wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT); + m_selectionForeground = wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT); + + m_editable = true; // default for whole grid + + m_inOnKeyDown = false; + m_batchCount = 0; + + m_extraWidth = + m_extraHeight = 0; + + m_scrollLineX = GRID_SCROLL_LINE_X; + m_scrollLineY = GRID_SCROLL_LINE_Y; +} + +// ---------------------------------------------------------------------------- +// the idea is to call these functions only when necessary because they create +// quite big arrays which eat memory mostly unnecessary - in particular, if +// default widths/heights are used for all rows/columns, we may not use these +// arrays at all +// +// with some extra code, it should be possible to only store the widths/heights +// different from default ones (resulting in space savings for huge grids) but +// this is not done currently +// ---------------------------------------------------------------------------- + +void wxGrid::InitRowHeights() +{ + m_rowHeights.Empty(); + m_rowBottoms.Empty(); + + m_rowHeights.Alloc( m_numRows ); + m_rowBottoms.Alloc( m_numRows ); + + m_rowHeights.Add( m_defaultRowHeight, m_numRows ); + + int rowBottom = 0; + for ( int i = 0; i < m_numRows; i++ ) + { + rowBottom += m_defaultRowHeight; + m_rowBottoms.Add( rowBottom ); + } +} + +void wxGrid::InitColWidths() +{ + m_colWidths.Empty(); + m_colRights.Empty(); + + m_colWidths.Alloc( m_numCols ); + m_colRights.Alloc( m_numCols ); + + m_colWidths.Add( m_defaultColWidth, m_numCols ); + + int colRight = 0; + for ( int i = 0; i < m_numCols; i++ ) + { + colRight = ( GetColPos( i ) + 1 ) * m_defaultColWidth; + m_colRights.Add( colRight ); + } +} + +int wxGrid::GetColWidth(int col) const +{ + return m_colWidths.IsEmpty() ? m_defaultColWidth : m_colWidths[col]; +} + +int wxGrid::GetColLeft(int col) const +{ + return m_colRights.IsEmpty() ? GetColPos( col ) * m_defaultColWidth + : m_colRights[col] - m_colWidths[col]; +} + +int wxGrid::GetColRight(int col) const +{ + return m_colRights.IsEmpty() ? (GetColPos( col ) + 1) * m_defaultColWidth + : m_colRights[col]; +} + +int wxGrid::GetRowHeight(int row) const +{ + return m_rowHeights.IsEmpty() ? m_defaultRowHeight : m_rowHeights[row]; +} + +int wxGrid::GetRowTop(int row) const +{ + return m_rowBottoms.IsEmpty() ? row * m_defaultRowHeight + : m_rowBottoms[row] - m_rowHeights[row]; +} + +int wxGrid::GetRowBottom(int row) const +{ + return m_rowBottoms.IsEmpty() ? (row + 1) * m_defaultRowHeight + : m_rowBottoms[row]; +} + +void wxGrid::CalcDimensions() +{ + // compute the size of the scrollable area + int w = m_numCols > 0 ? GetColRight(GetColAt(m_numCols - 1)) : 0; + int h = m_numRows > 0 ? GetRowBottom(m_numRows - 1) : 0; + + w += m_extraWidth; + h += m_extraHeight; + + // take into account editor if shown + if ( IsCellEditControlShown() ) + { + int w2, h2; + int r = m_currentCellCoords.GetRow(); + int c = m_currentCellCoords.GetCol(); + int x = GetColLeft(c); + int y = GetRowTop(r); + + // how big is the editor + wxGridCellAttr* attr = GetCellAttr(r, c); + wxGridCellEditor* editor = attr->GetEditor(this, r, c); + editor->GetControl()->GetSize(&w2, &h2); + w2 += x; + h2 += y; + if ( w2 > w ) + w = w2; + if ( h2 > h ) + h = h2; + editor->DecRef(); + attr->DecRef(); + } + + // preserve (more or less) the previous position + int x, y; + GetViewStart( &x, &y ); + + // ensure the position is valid for the new scroll ranges + if ( x >= w ) + x = wxMax( w - 1, 0 ); + if ( y >= h ) + y = wxMax( h - 1, 0 ); + + // do set scrollbar parameters + SetScrollbars( m_scrollLineX, m_scrollLineY, + GetScrollX(w), GetScrollY(h), + x, y, + GetBatchCount() != 0); + + // if our OnSize() hadn't been called (it would if we have scrollbars), we + // still must reposition the children + CalcWindowSizes(); +} + +void wxGrid::CalcWindowSizes() +{ + // escape if the window is has not been fully created yet + + if ( m_cornerLabelWin == NULL ) + return; + + int cw, ch; + GetClientSize( &cw, &ch ); + + // this block of code tries to work around the following problem: the grid + // could have been just resized to have enough space to show the full grid + // window contents without the scrollbars, but its client size could be + // not big enough because the grid has the scrollbars right now and so the + // scrollbars would remain even though we don't need them any more + // + // to prevent this from happening, check if we have enough space for + // everything without the scrollbars and explicitly disable them then + wxSize size = GetSize() - GetWindowBorderSize(); + if ( size != wxSize(cw, ch) ) + { + // check if we have enough space for grid window after accounting for + // the fixed size elements + size.x -= m_rowLabelWidth; + size.y -= m_colLabelHeight; + + const wxSize vsize = m_gridWin->GetVirtualSize(); + + if ( size.x >= vsize.x && size.y >= vsize.y ) + { + // yes, we do, so remove the scrollbars and use the new client size + // (which should be the same as full window size - borders now) + SetScrollbars(0, 0, 0, 0); + GetClientSize(&cw, &ch); + } + } + + // the grid may be too small to have enough space for the labels yet, don't + // size the windows to negative sizes in this case + int gw = cw - m_rowLabelWidth; + int gh = ch - m_colLabelHeight; + if (gw < 0) + gw = 0; + if (gh < 0) + gh = 0; + + if ( m_cornerLabelWin && m_cornerLabelWin->IsShown() ) + m_cornerLabelWin->SetSize( 0, 0, m_rowLabelWidth, m_colLabelHeight ); + + if ( m_colLabelWin && m_colLabelWin->IsShown() ) + m_colLabelWin->SetSize( m_rowLabelWidth, 0, gw, m_colLabelHeight ); + + if ( m_rowLabelWin && m_rowLabelWin->IsShown() ) + m_rowLabelWin->SetSize( 0, m_colLabelHeight, m_rowLabelWidth, gh ); + + if ( m_gridWin && m_gridWin->IsShown() ) + m_gridWin->SetSize( m_rowLabelWidth, m_colLabelHeight, gw, gh ); +} + +// this is called when the grid table sends a message +// to indicate that it has been redimensioned +// +bool wxGrid::Redimension( wxGridTableMessage& msg ) +{ + int i; + bool result = false; + + // Clear the attribute cache as the attribute might refer to a different + // cell than stored in the cache after adding/removing rows/columns. + ClearAttrCache(); + + // By the same reasoning, the editor should be dismissed if columns are + // added or removed. And for consistency, it should IMHO always be + // removed, not only if the cell "underneath" it actually changes. + // For now, I intentionally do not save the editor's content as the + // cell it might want to save that stuff to might no longer exist. + HideCellEditControl(); + +#if 0 + // if we were using the default widths/heights so far, we must change them + // now + if ( m_colWidths.IsEmpty() ) + { + InitColWidths(); + } + + if ( m_rowHeights.IsEmpty() ) + { + InitRowHeights(); + } +#endif + + switch ( msg.GetId() ) + { + case wxGRIDTABLE_NOTIFY_ROWS_INSERTED: + { + size_t pos = msg.GetCommandInt(); + int numRows = msg.GetCommandInt2(); + + m_numRows += numRows; + + if ( !m_rowHeights.IsEmpty() ) + { + m_rowHeights.Insert( m_defaultRowHeight, pos, numRows ); + m_rowBottoms.Insert( 0, pos, numRows ); + + int bottom = 0; + if ( pos > 0 ) + bottom = m_rowBottoms[pos - 1]; + + for ( i = pos; i < m_numRows; i++ ) + { + bottom += m_rowHeights[i]; + m_rowBottoms[i] = bottom; + } + } + + if ( m_currentCellCoords == wxGridNoCellCoords ) + { + // if we have just inserted cols into an empty grid the current + // cell will be undefined... + // + SetCurrentCell( 0, 0 ); + } + + if ( m_selection ) + m_selection->UpdateRows( pos, numRows ); + wxGridCellAttrProvider * attrProvider = m_table->GetAttrProvider(); + if (attrProvider) + attrProvider->UpdateAttrRows( pos, numRows ); + + if ( !GetBatchCount() ) + { + CalcDimensions(); + m_rowLabelWin->Refresh(); + } + } + result = true; + break; + + case wxGRIDTABLE_NOTIFY_ROWS_APPENDED: + { + int numRows = msg.GetCommandInt(); + int oldNumRows = m_numRows; + m_numRows += numRows; + + if ( !m_rowHeights.IsEmpty() ) + { + m_rowHeights.Add( m_defaultRowHeight, numRows ); + m_rowBottoms.Add( 0, numRows ); + + int bottom = 0; + if ( oldNumRows > 0 ) + bottom = m_rowBottoms[oldNumRows - 1]; + + for ( i = oldNumRows; i < m_numRows; i++ ) + { + bottom += m_rowHeights[i]; + m_rowBottoms[i] = bottom; + } + } + + if ( m_currentCellCoords == wxGridNoCellCoords ) + { + // if we have just inserted cols into an empty grid the current + // cell will be undefined... + // + SetCurrentCell( 0, 0 ); + } + + if ( !GetBatchCount() ) + { + CalcDimensions(); + m_rowLabelWin->Refresh(); + } + } + result = true; + break; + + case wxGRIDTABLE_NOTIFY_ROWS_DELETED: + { + size_t pos = msg.GetCommandInt(); + int numRows = msg.GetCommandInt2(); + m_numRows -= numRows; + + if ( !m_rowHeights.IsEmpty() ) + { + m_rowHeights.RemoveAt( pos, numRows ); + m_rowBottoms.RemoveAt( pos, numRows ); + + int h = 0; + for ( i = 0; i < m_numRows; i++ ) + { + h += m_rowHeights[i]; + m_rowBottoms[i] = h; + } + } + + if ( !m_numRows ) + { + m_currentCellCoords = wxGridNoCellCoords; + } + else + { + if ( m_currentCellCoords.GetRow() >= m_numRows ) + m_currentCellCoords.Set( 0, 0 ); + } + + if ( m_selection ) + m_selection->UpdateRows( pos, -((int)numRows) ); + wxGridCellAttrProvider * attrProvider = m_table->GetAttrProvider(); + if (attrProvider) + { + attrProvider->UpdateAttrRows( pos, -((int)numRows) ); + +// ifdef'd out following patch from Paul Gammans +#if 0 + // No need to touch column attributes, unless we + // removed _all_ rows, in this case, we remove + // all column attributes. + // I hate to do this here, but the + // needed data is not available inside UpdateAttrRows. + if ( !GetNumberRows() ) + attrProvider->UpdateAttrCols( 0, -GetNumberCols() ); +#endif + } + + if ( !GetBatchCount() ) + { + CalcDimensions(); + m_rowLabelWin->Refresh(); + } + } + result = true; + break; + + case wxGRIDTABLE_NOTIFY_COLS_INSERTED: + { + size_t pos = msg.GetCommandInt(); + int numCols = msg.GetCommandInt2(); + m_numCols += numCols; + + if ( !m_colAt.IsEmpty() ) + { + //Shift the column IDs + int i; + for ( i = 0; i < m_numCols - numCols; i++ ) + { + if ( m_colAt[i] >= (int)pos ) + m_colAt[i] += numCols; + } + + m_colAt.Insert( pos, pos, numCols ); + + //Set the new columns' positions + for ( i = pos + 1; i < (int)pos + numCols; i++ ) + { + m_colAt[i] = i; + } + } + + if ( !m_colWidths.IsEmpty() ) + { + m_colWidths.Insert( m_defaultColWidth, pos, numCols ); + m_colRights.Insert( 0, pos, numCols ); + + int right = 0; + if ( pos > 0 ) + right = m_colRights[GetColAt( pos - 1 )]; + + int colPos; + for ( colPos = pos; colPos < m_numCols; colPos++ ) + { + i = GetColAt( colPos ); + + right += m_colWidths[i]; + m_colRights[i] = right; + } + } + + if ( m_currentCellCoords == wxGridNoCellCoords ) + { + // if we have just inserted cols into an empty grid the current + // cell will be undefined... + // + SetCurrentCell( 0, 0 ); + } + + if ( m_selection ) + m_selection->UpdateCols( pos, numCols ); + wxGridCellAttrProvider * attrProvider = m_table->GetAttrProvider(); + if (attrProvider) + attrProvider->UpdateAttrCols( pos, numCols ); + if ( !GetBatchCount() ) + { + CalcDimensions(); + m_colLabelWin->Refresh(); + } + } + result = true; + break; + + case wxGRIDTABLE_NOTIFY_COLS_APPENDED: + { + int numCols = msg.GetCommandInt(); + int oldNumCols = m_numCols; + m_numCols += numCols; + + if ( !m_colAt.IsEmpty() ) + { + m_colAt.Add( 0, numCols ); + + //Set the new columns' positions + int i; + for ( i = oldNumCols; i < m_numCols; i++ ) + { + m_colAt[i] = i; + } + } + + if ( !m_colWidths.IsEmpty() ) + { + m_colWidths.Add( m_defaultColWidth, numCols ); + m_colRights.Add( 0, numCols ); + + int right = 0; + if ( oldNumCols > 0 ) + right = m_colRights[GetColAt( oldNumCols - 1 )]; + + int colPos; + for ( colPos = oldNumCols; colPos < m_numCols; colPos++ ) + { + i = GetColAt( colPos ); + + right += m_colWidths[i]; + m_colRights[i] = right; + } + } + + if ( m_currentCellCoords == wxGridNoCellCoords ) + { + // if we have just inserted cols into an empty grid the current + // cell will be undefined... + // + SetCurrentCell( 0, 0 ); + } + if ( !GetBatchCount() ) + { + CalcDimensions(); + m_colLabelWin->Refresh(); + } + } + result = true; + break; + + case wxGRIDTABLE_NOTIFY_COLS_DELETED: + { + size_t pos = msg.GetCommandInt(); + int numCols = msg.GetCommandInt2(); + m_numCols -= numCols; + + if ( !m_colAt.IsEmpty() ) + { + int colID = GetColAt( pos ); + + m_colAt.RemoveAt( pos, numCols ); + + //Shift the column IDs + int colPos; + for ( colPos = 0; colPos < m_numCols; colPos++ ) + { + if ( m_colAt[colPos] > colID ) + m_colAt[colPos] -= numCols; + } + } + + if ( !m_colWidths.IsEmpty() ) + { + m_colWidths.RemoveAt( pos, numCols ); + m_colRights.RemoveAt( pos, numCols ); + + int w = 0; + int colPos; + for ( colPos = 0; colPos < m_numCols; colPos++ ) + { + i = GetColAt( colPos ); + + w += m_colWidths[i]; + m_colRights[i] = w; + } + } + + if ( !m_numCols ) + { + m_currentCellCoords = wxGridNoCellCoords; + } + else + { + if ( m_currentCellCoords.GetCol() >= m_numCols ) + m_currentCellCoords.Set( 0, 0 ); + } + + if ( m_selection ) + m_selection->UpdateCols( pos, -((int)numCols) ); + wxGridCellAttrProvider * attrProvider = m_table->GetAttrProvider(); + if (attrProvider) + { + attrProvider->UpdateAttrCols( pos, -((int)numCols) ); + +// ifdef'd out following patch from Paul Gammans +#if 0 + // No need to touch row attributes, unless we + // removed _all_ columns, in this case, we remove + // all row attributes. + // I hate to do this here, but the + // needed data is not available inside UpdateAttrCols. + if ( !GetNumberCols() ) + attrProvider->UpdateAttrRows( 0, -GetNumberRows() ); +#endif + } + + if ( !GetBatchCount() ) + { + CalcDimensions(); + m_colLabelWin->Refresh(); + } + } + result = true; + break; + } + + if (result && !GetBatchCount() ) + m_gridWin->Refresh(); + + return result; +} + +wxArrayInt wxGrid::CalcRowLabelsExposed( const wxRegion& reg ) +{ + wxRegionIterator iter( reg ); + wxRect r; + + wxArrayInt rowlabels; + + int top, bottom; + while ( iter ) + { + r = iter.GetRect(); + + // TODO: remove this when we can... + // There is a bug in wxMotif that gives garbage update + // rectangles if you jump-scroll a long way by clicking the + // scrollbar with middle button. This is a work-around + // +#if defined(__WXMOTIF__) + int cw, ch; + m_gridWin->GetClientSize( &cw, &ch ); + if ( r.GetTop() > ch ) + r.SetTop( 0 ); + r.SetBottom( wxMin( r.GetBottom(), ch ) ); +#endif + + // logical bounds of update region + // + int dummy; + CalcUnscrolledPosition( 0, r.GetTop(), &dummy, &top ); + CalcUnscrolledPosition( 0, r.GetBottom(), &dummy, &bottom ); + + // find the row labels within these bounds + // + int row; + for ( row = internalYToRow(top); row < m_numRows; row++ ) + { + if ( GetRowBottom(row) < top ) + continue; + + if ( GetRowTop(row) > bottom ) + break; + + rowlabels.Add( row ); + } + + ++iter; + } + + return rowlabels; +} + +wxArrayInt wxGrid::CalcColLabelsExposed( const wxRegion& reg ) +{ + wxRegionIterator iter( reg ); + wxRect r; + + wxArrayInt colLabels; + + int left, right; + while ( iter ) + { + r = iter.GetRect(); + + // TODO: remove this when we can... + // There is a bug in wxMotif that gives garbage update + // rectangles if you jump-scroll a long way by clicking the + // scrollbar with middle button. This is a work-around + // +#if defined(__WXMOTIF__) + int cw, ch; + m_gridWin->GetClientSize( &cw, &ch ); + if ( r.GetLeft() > cw ) + r.SetLeft( 0 ); + r.SetRight( wxMin( r.GetRight(), cw ) ); +#endif + + // logical bounds of update region + // + int dummy; + CalcUnscrolledPosition( r.GetLeft(), 0, &left, &dummy ); + CalcUnscrolledPosition( r.GetRight(), 0, &right, &dummy ); + + // find the cells within these bounds + // + int col; + int colPos; + for ( colPos = GetColPos( internalXToCol(left) ); colPos < m_numCols; colPos++ ) + { + col = GetColAt( colPos ); + + if ( GetColRight(col) < left ) + continue; + + if ( GetColLeft(col) > right ) + break; + + colLabels.Add( col ); + } + + ++iter; + } + + return colLabels; +} + +wxGridCellCoordsArray wxGrid::CalcCellsExposed( const wxRegion& reg ) +{ + wxRegionIterator iter( reg ); + wxRect r; + + wxGridCellCoordsArray cellsExposed; + + int left, top, right, bottom; + while ( iter ) + { + r = iter.GetRect(); + + // TODO: remove this when we can... + // There is a bug in wxMotif that gives garbage update + // rectangles if you jump-scroll a long way by clicking the + // scrollbar with middle button. This is a work-around + // +#if defined(__WXMOTIF__) + int cw, ch; + m_gridWin->GetClientSize( &cw, &ch ); + if ( r.GetTop() > ch ) r.SetTop( 0 ); + if ( r.GetLeft() > cw ) r.SetLeft( 0 ); + r.SetRight( wxMin( r.GetRight(), cw ) ); + r.SetBottom( wxMin( r.GetBottom(), ch ) ); +#endif + + // logical bounds of update region + // + CalcUnscrolledPosition( r.GetLeft(), r.GetTop(), &left, &top ); + CalcUnscrolledPosition( r.GetRight(), r.GetBottom(), &right, &bottom ); + + // find the cells within these bounds + // + int row, col; + for ( row = internalYToRow(top); row < m_numRows; row++ ) + { + if ( GetRowBottom(row) <= top ) + continue; + + if ( GetRowTop(row) > bottom ) + break; + + int colPos; + for ( colPos = GetColPos( internalXToCol(left) ); colPos < m_numCols; colPos++ ) + { + col = GetColAt( colPos ); + + if ( GetColRight(col) <= left ) + continue; + + if ( GetColLeft(col) > right ) + break; + + cellsExposed.Add( wxGridCellCoords( row, col ) ); + } + } + + ++iter; + } + + return cellsExposed; +} + + +void wxGrid::ProcessRowLabelMouseEvent( wxMouseEvent& event ) +{ + int x, y, row; + wxPoint pos( event.GetPosition() ); + CalcUnscrolledPosition( pos.x, pos.y, &x, &y ); + + if ( event.Dragging() ) + { + if (!m_isDragging) + { + m_isDragging = true; + m_rowLabelWin->CaptureMouse(); + } + + if ( event.LeftIsDown() ) + { + switch ( m_cursorMode ) + { + case WXGRID_CURSOR_RESIZE_ROW: + { + int cw, ch, left, dummy; + m_gridWin->GetClientSize( &cw, &ch ); + CalcUnscrolledPosition( 0, 0, &left, &dummy ); + + wxClientDC dc( m_gridWin ); + PrepareDC( dc ); + y = wxMax( y, + GetRowTop(m_dragRowOrCol) + + GetRowMinimalHeight(m_dragRowOrCol) ); + dc.SetLogicalFunction(wxINVERT); + if ( m_dragLastPos >= 0 ) + { + dc.DrawLine( left, m_dragLastPos, left+cw, m_dragLastPos ); + } + dc.DrawLine( left, y, left+cw, y ); + m_dragLastPos = y; + } + break; + + case WXGRID_CURSOR_SELECT_ROW: + { + if ( (row = YToRow( y )) >= 0 ) + { + if ( m_selection ) + { + m_selection->SelectRow( row, + event.ControlDown(), + event.ShiftDown(), + event.AltDown(), + event.MetaDown() ); + } + } + } + break; + + // default label to suppress warnings about "enumeration value + // 'xxx' not handled in switch + default: + break; + } + } + return; + } + + if ( m_isDragging && (event.Entering() || event.Leaving()) ) + return; + + if (m_isDragging) + { + if (m_rowLabelWin->HasCapture()) + m_rowLabelWin->ReleaseMouse(); + m_isDragging = false; + } + + // ------------ Entering or leaving the window + // + if ( event.Entering() || event.Leaving() ) + { + ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL, m_rowLabelWin); + } + + // ------------ Left button pressed + // + else if ( event.LeftDown() ) + { + // don't send a label click event for a hit on the + // edge of the row label - this is probably the user + // wanting to resize the row + // + if ( YToEdgeOfRow(y) < 0 ) + { + row = YToRow(y); + if ( row >= 0 && + !SendEvent( wxEVT_GRID_LABEL_LEFT_CLICK, row, -1, event ) ) + { + if ( !event.ShiftDown() && !event.CmdDown() ) + ClearSelection(); + if ( m_selection ) + { + if ( event.ShiftDown() ) + { + m_selection->SelectBlock( m_currentCellCoords.GetRow(), + 0, + row, + GetNumberCols() - 1, + event.ControlDown(), + event.ShiftDown(), + event.AltDown(), + event.MetaDown() ); + } + else + { + m_selection->SelectRow( row, + event.ControlDown(), + event.ShiftDown(), + event.AltDown(), + event.MetaDown() ); + } + } + + ChangeCursorMode(WXGRID_CURSOR_SELECT_ROW, m_rowLabelWin); + } + } + else + { + // starting to drag-resize a row + if ( CanDragRowSize() ) + ChangeCursorMode(WXGRID_CURSOR_RESIZE_ROW, m_rowLabelWin); + } + } + + // ------------ Left double click + // + else if (event.LeftDClick() ) + { + row = YToEdgeOfRow(y); + if ( row < 0 ) + { + row = YToRow(y); + if ( row >=0 && + !SendEvent( wxEVT_GRID_LABEL_LEFT_DCLICK, row, -1, event ) ) + { + // no default action at the moment + } + } + else + { + // adjust row height depending on label text + AutoSizeRowLabelSize( row ); + + ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL, m_colLabelWin); + m_dragLastPos = -1; + } + } + + // ------------ Left button released + // + else if ( event.LeftUp() ) + { + if ( m_cursorMode == WXGRID_CURSOR_RESIZE_ROW ) + { + DoEndDragResizeRow(); + + // Note: we are ending the event *after* doing + // default processing in this case + // + SendEvent( wxEVT_GRID_ROW_SIZE, m_dragRowOrCol, -1, event ); + } + + ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL, m_rowLabelWin); + m_dragLastPos = -1; + } + + // ------------ Right button down + // + else if ( event.RightDown() ) + { + row = YToRow(y); + if ( row >=0 && + !SendEvent( wxEVT_GRID_LABEL_RIGHT_CLICK, row, -1, event ) ) + { + // no default action at the moment + } + } + + // ------------ Right double click + // + else if ( event.RightDClick() ) + { + row = YToRow(y); + if ( row >= 0 && + !SendEvent( wxEVT_GRID_LABEL_RIGHT_DCLICK, row, -1, event ) ) + { + // no default action at the moment + } + } + + // ------------ No buttons down and mouse moving + // + else if ( event.Moving() ) + { + m_dragRowOrCol = YToEdgeOfRow( y ); + if ( m_dragRowOrCol >= 0 ) + { + if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL ) + { + // don't capture the mouse yet + if ( CanDragRowSize() ) + ChangeCursorMode(WXGRID_CURSOR_RESIZE_ROW, m_rowLabelWin, false); + } + } + else if ( m_cursorMode != WXGRID_CURSOR_SELECT_CELL ) + { + ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL, m_rowLabelWin, false); + } + } +} + +void wxGrid::ProcessColLabelMouseEvent( wxMouseEvent& event ) +{ + int x, y, col; + wxPoint pos( event.GetPosition() ); + CalcUnscrolledPosition( pos.x, pos.y, &x, &y ); + + if ( event.Dragging() ) + { + if (!m_isDragging) + { + m_isDragging = true; + m_colLabelWin->CaptureMouse(); + + if ( m_cursorMode == WXGRID_CURSOR_MOVE_COL ) + m_dragRowOrCol = XToCol( x ); + } + + if ( event.LeftIsDown() ) + { + switch ( m_cursorMode ) + { + case WXGRID_CURSOR_RESIZE_COL: + { + int cw, ch, dummy, top; + m_gridWin->GetClientSize( &cw, &ch ); + CalcUnscrolledPosition( 0, 0, &dummy, &top ); + + wxClientDC dc( m_gridWin ); + PrepareDC( dc ); + + x = wxMax( x, GetColLeft(m_dragRowOrCol) + + GetColMinimalWidth(m_dragRowOrCol)); + dc.SetLogicalFunction(wxINVERT); + if ( m_dragLastPos >= 0 ) + { + dc.DrawLine( m_dragLastPos, top, m_dragLastPos, top + ch ); + } + dc.DrawLine( x, top, x, top + ch ); + m_dragLastPos = x; + } + break; + + case WXGRID_CURSOR_SELECT_COL: + { + if ( (col = XToCol( x )) >= 0 ) + { + if ( m_selection ) + { + m_selection->SelectCol( col, + event.ControlDown(), + event.ShiftDown(), + event.AltDown(), + event.MetaDown() ); + } + } + } + break; + + case WXGRID_CURSOR_MOVE_COL: + { + if ( x < 0 ) + m_moveToCol = GetColAt( 0 ); + else + m_moveToCol = XToCol( x ); + + int markerX; + + if ( m_moveToCol < 0 ) + markerX = GetColRight( GetColAt( m_numCols - 1 ) ); + else + markerX = GetColLeft( m_moveToCol ); + + if ( markerX != m_dragLastPos ) + { + wxClientDC dc( m_colLabelWin ); + + int cw, ch; + m_colLabelWin->GetClientSize( &cw, &ch ); + + markerX++; + + //Clean up the last indicator + if ( m_dragLastPos >= 0 ) + { + wxPen pen( m_colLabelWin->GetBackgroundColour(), 2 ); + dc.SetPen(pen); + dc.DrawLine( m_dragLastPos + 1, 0, m_dragLastPos + 1, ch ); + dc.SetPen(wxNullPen); + + if ( XToCol( m_dragLastPos ) != -1 ) + DrawColLabel( dc, XToCol( m_dragLastPos ) ); + } + + //Moving to the same place? Don't draw a marker + if ( (m_moveToCol == m_dragRowOrCol) + || (GetColPos( m_moveToCol ) == GetColPos( m_dragRowOrCol ) + 1) + || (m_moveToCol < 0 && m_dragRowOrCol == GetColAt( m_numCols - 1 ))) + { + m_dragLastPos = -1; + return; + } + + //Draw the marker + wxPen pen( *wxBLUE, 2 ); + dc.SetPen(pen); + + dc.DrawLine( markerX, 0, markerX, ch ); + + dc.SetPen(wxNullPen); + + m_dragLastPos = markerX - 1; + } + } + break; + + // default label to suppress warnings about "enumeration value + // 'xxx' not handled in switch + default: + break; + } + } + return; + } + + if ( m_isDragging && (event.Entering() || event.Leaving()) ) + return; + + if (m_isDragging) + { + if (m_colLabelWin->HasCapture()) + m_colLabelWin->ReleaseMouse(); + m_isDragging = false; + } + + // ------------ Entering or leaving the window + // + if ( event.Entering() || event.Leaving() ) + { + ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL, m_colLabelWin); + } + + // ------------ Left button pressed + // + else if ( event.LeftDown() ) + { + // don't send a label click event for a hit on the + // edge of the col label - this is probably the user + // wanting to resize the col + // + if ( XToEdgeOfCol(x) < 0 ) + { + col = XToCol(x); + if ( col >= 0 && + !SendEvent( wxEVT_GRID_LABEL_LEFT_CLICK, -1, col, event ) ) + { + if ( m_canDragColMove ) + { + //Show button as pressed + wxClientDC dc( m_colLabelWin ); + int colLeft = GetColLeft( col ); + int colRight = GetColRight( col ) - 1; + dc.SetPen( wxPen( m_colLabelWin->GetBackgroundColour(), 1 ) ); + dc.DrawLine( colLeft, 1, colLeft, m_colLabelHeight-1 ); + dc.DrawLine( colLeft, 1, colRight, 1 ); + + ChangeCursorMode(WXGRID_CURSOR_MOVE_COL, m_colLabelWin); + } + else + { + if ( !event.ShiftDown() && !event.CmdDown() ) + ClearSelection(); + if ( m_selection ) + { + if ( event.ShiftDown() ) + { + m_selection->SelectBlock( 0, + m_currentCellCoords.GetCol(), + GetNumberRows() - 1, col, + event.ControlDown(), + event.ShiftDown(), + event.AltDown(), + event.MetaDown() ); + } + else + { + m_selection->SelectCol( col, + event.ControlDown(), + event.ShiftDown(), + event.AltDown(), + event.MetaDown() ); + } + } + + ChangeCursorMode(WXGRID_CURSOR_SELECT_COL, m_colLabelWin); + } + } + } + else + { + // starting to drag-resize a col + // + if ( CanDragColSize() ) + ChangeCursorMode(WXGRID_CURSOR_RESIZE_COL, m_colLabelWin); + } + } + + // ------------ Left double click + // + if ( event.LeftDClick() ) + { + col = XToEdgeOfCol(x); + if ( col < 0 ) + { + col = XToCol(x); + if ( col >= 0 && + ! SendEvent( wxEVT_GRID_LABEL_LEFT_DCLICK, -1, col, event ) ) + { + // no default action at the moment + } + } + else + { + // adjust column width depending on label text + AutoSizeColLabelSize( col ); + + ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL, m_colLabelWin); + m_dragLastPos = -1; + } + } + + // ------------ Left button released + // + else if ( event.LeftUp() ) + { + switch ( m_cursorMode ) + { + case WXGRID_CURSOR_RESIZE_COL: + DoEndDragResizeCol(); + + // Note: we are ending the event *after* doing + // default processing in this case + // + SendEvent( wxEVT_GRID_COL_SIZE, -1, m_dragRowOrCol, event ); + break; + + case WXGRID_CURSOR_MOVE_COL: + DoEndDragMoveCol(); + + SendEvent( wxEVT_GRID_COL_MOVE, -1, m_dragRowOrCol, event ); + break; + + case WXGRID_CURSOR_SELECT_COL: + case WXGRID_CURSOR_SELECT_CELL: + case WXGRID_CURSOR_RESIZE_ROW: + case WXGRID_CURSOR_SELECT_ROW: + // nothing to do (?) + break; + } + + ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL, m_colLabelWin); + m_dragLastPos = -1; + } + + // ------------ Right button down + // + else if ( event.RightDown() ) + { + col = XToCol(x); + if ( col >= 0 && + !SendEvent( wxEVT_GRID_LABEL_RIGHT_CLICK, -1, col, event ) ) + { + // no default action at the moment + } + } + + // ------------ Right double click + // + else if ( event.RightDClick() ) + { + col = XToCol(x); + if ( col >= 0 && + !SendEvent( wxEVT_GRID_LABEL_RIGHT_DCLICK, -1, col, event ) ) + { + // no default action at the moment + } + } + + // ------------ No buttons down and mouse moving + // + else if ( event.Moving() ) + { + m_dragRowOrCol = XToEdgeOfCol( x ); + if ( m_dragRowOrCol >= 0 ) + { + if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL ) + { + // don't capture the cursor yet + if ( CanDragColSize() ) + ChangeCursorMode(WXGRID_CURSOR_RESIZE_COL, m_colLabelWin, false); + } + } + else if ( m_cursorMode != WXGRID_CURSOR_SELECT_CELL ) + { + ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL, m_colLabelWin, false); + } + } +} + +void wxGrid::ProcessCornerLabelMouseEvent( wxMouseEvent& event ) +{ + if ( event.LeftDown() ) + { + // indicate corner label by having both row and + // col args == -1 + // + if ( !SendEvent( wxEVT_GRID_LABEL_LEFT_CLICK, -1, -1, event ) ) + { + SelectAll(); + } + } + else if ( event.LeftDClick() ) + { + SendEvent( wxEVT_GRID_LABEL_LEFT_DCLICK, -1, -1, event ); + } + else if ( event.RightDown() ) + { + if ( !SendEvent( wxEVT_GRID_LABEL_RIGHT_CLICK, -1, -1, event ) ) + { + // no default action at the moment + } + } + else if ( event.RightDClick() ) + { + if ( !SendEvent( wxEVT_GRID_LABEL_RIGHT_DCLICK, -1, -1, event ) ) + { + // no default action at the moment + } + } +} + +void wxGrid::ChangeCursorMode(CursorMode mode, + wxWindow *win, + bool captureMouse) +{ +#ifdef __WXDEBUG__ + static const wxChar *cursorModes[] = + { + _T("SELECT_CELL"), + _T("RESIZE_ROW"), + _T("RESIZE_COL"), + _T("SELECT_ROW"), + _T("SELECT_COL"), + _T("MOVE_COL"), + }; + + wxLogTrace(_T("grid"), + _T("wxGrid cursor mode (mouse capture for %s): %s -> %s"), + win == m_colLabelWin ? _T("colLabelWin") + : win ? _T("rowLabelWin") + : _T("gridWin"), + cursorModes[m_cursorMode], cursorModes[mode]); +#endif + + if ( mode == m_cursorMode && + win == m_winCapture && + captureMouse == (m_winCapture != NULL)) + return; + + if ( !win ) + { + // by default use the grid itself + win = m_gridWin; + } + + if ( m_winCapture ) + { + if (m_winCapture->HasCapture()) + m_winCapture->ReleaseMouse(); + m_winCapture = (wxWindow *)NULL; + } + + m_cursorMode = mode; + + switch ( m_cursorMode ) + { + case WXGRID_CURSOR_RESIZE_ROW: + win->SetCursor( m_rowResizeCursor ); + break; + + case WXGRID_CURSOR_RESIZE_COL: + win->SetCursor( m_colResizeCursor ); + break; + + case WXGRID_CURSOR_MOVE_COL: + win->SetCursor( wxCursor(wxCURSOR_HAND) ); + break; + + default: + win->SetCursor( *wxSTANDARD_CURSOR ); + break; + } + + // we need to capture mouse when resizing + bool resize = m_cursorMode == WXGRID_CURSOR_RESIZE_ROW || + m_cursorMode == WXGRID_CURSOR_RESIZE_COL; + + if ( captureMouse && resize ) + { + win->CaptureMouse(); + m_winCapture = win; + } +} + +void wxGrid::ProcessGridCellMouseEvent( wxMouseEvent& event ) +{ + int x, y; + wxPoint pos( event.GetPosition() ); + CalcUnscrolledPosition( pos.x, pos.y, &x, &y ); + + wxGridCellCoords coords; + XYToCell( x, y, coords ); + + int cell_rows, cell_cols; + bool isFirstDrag = !m_isDragging; + GetCellSize( coords.GetRow(), coords.GetCol(), &cell_rows, &cell_cols ); + if ((cell_rows < 0) || (cell_cols < 0)) + { + coords.SetRow(coords.GetRow() + cell_rows); + coords.SetCol(coords.GetCol() + cell_cols); + } + + if ( event.Dragging() ) + { + //wxLogDebug("pos(%d, %d) coords(%d, %d)", pos.x, pos.y, coords.GetRow(), coords.GetCol()); + + // Don't start doing anything until the mouse has been dragged at + // least 3 pixels in any direction... + if (! m_isDragging) + { + if (m_startDragPos == wxDefaultPosition) + { + m_startDragPos = pos; + return; + } + if (abs(m_startDragPos.x - pos.x) < 4 && abs(m_startDragPos.y - pos.y) < 4) + return; + } + + m_isDragging = true; + if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL ) + { + // Hide the edit control, so it + // won't interfere with drag-shrinking. + if ( IsCellEditControlShown() ) + { + HideCellEditControl(); + SaveEditControlValue(); + } + + if ( coords != wxGridNoCellCoords ) + { + if ( event.CmdDown() ) + { + if ( m_selectingKeyboard == wxGridNoCellCoords) + m_selectingKeyboard = coords; + HighlightBlock( m_selectingKeyboard, coords ); + } + else if ( CanDragCell() ) + { + if ( isFirstDrag ) + { + if ( m_selectingKeyboard == wxGridNoCellCoords) + m_selectingKeyboard = coords; + + SendEvent( wxEVT_GRID_CELL_BEGIN_DRAG, + coords.GetRow(), + coords.GetCol(), + event ); + return; + } + } + else + { + if ( !IsSelection() ) + { + HighlightBlock( coords, coords ); + } + else + { + HighlightBlock( m_currentCellCoords, coords ); + } + } + + if (! IsVisible(coords)) + { + MakeCellVisible(coords); + // TODO: need to introduce a delay or something here. The + // scrolling is way to fast, at least on MSW - also on GTK. + } + } + // Have we captured the mouse yet? + if (! m_winCapture) + { + m_winCapture = m_gridWin; + m_winCapture->CaptureMouse(); + } + + + } + else if ( m_cursorMode == WXGRID_CURSOR_RESIZE_ROW ) + { + int cw, ch, left, dummy; + m_gridWin->GetClientSize( &cw, &ch ); + CalcUnscrolledPosition( 0, 0, &left, &dummy ); + + wxClientDC dc( m_gridWin ); + PrepareDC( dc ); + y = wxMax( y, GetRowTop(m_dragRowOrCol) + + GetRowMinimalHeight(m_dragRowOrCol) ); + dc.SetLogicalFunction(wxINVERT); + if ( m_dragLastPos >= 0 ) + { + dc.DrawLine( left, m_dragLastPos, left+cw, m_dragLastPos ); + } + dc.DrawLine( left, y, left+cw, y ); + m_dragLastPos = y; + } + else if ( m_cursorMode == WXGRID_CURSOR_RESIZE_COL ) + { + int cw, ch, dummy, top; + m_gridWin->GetClientSize( &cw, &ch ); + CalcUnscrolledPosition( 0, 0, &dummy, &top ); + + wxClientDC dc( m_gridWin ); + PrepareDC( dc ); + x = wxMax( x, GetColLeft(m_dragRowOrCol) + + GetColMinimalWidth(m_dragRowOrCol) ); + dc.SetLogicalFunction(wxINVERT); + if ( m_dragLastPos >= 0 ) + { + dc.DrawLine( m_dragLastPos, top, m_dragLastPos, top + ch ); + } + dc.DrawLine( x, top, x, top + ch ); + m_dragLastPos = x; + } + + return; + } + + m_isDragging = false; + m_startDragPos = wxDefaultPosition; + + // VZ: if we do this, the mode is reset to WXGRID_CURSOR_SELECT_CELL + // immediately after it becomes WXGRID_CURSOR_RESIZE_ROW/COL under + // wxGTK +#if 0 + if ( event.Entering() || event.Leaving() ) + { + ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL); + m_gridWin->SetCursor( *wxSTANDARD_CURSOR ); + } + else +#endif // 0 + + // ------------ Left button pressed + // + if ( event.LeftDown() && coords != wxGridNoCellCoords ) + { + if ( !SendEvent( wxEVT_GRID_CELL_LEFT_CLICK, + coords.GetRow(), + coords.GetCol(), + event ) ) + { + if ( !event.CmdDown() ) + ClearSelection(); + if ( event.ShiftDown() ) + { + if ( m_selection ) + { + m_selection->SelectBlock( m_currentCellCoords.GetRow(), + m_currentCellCoords.GetCol(), + coords.GetRow(), + coords.GetCol(), + event.ControlDown(), + event.ShiftDown(), + event.AltDown(), + event.MetaDown() ); + } + } + else if ( XToEdgeOfCol(x) < 0 && + YToEdgeOfRow(y) < 0 ) + { + DisableCellEditControl(); + MakeCellVisible( coords ); + + if ( event.CmdDown() ) + { + if ( m_selection ) + { + m_selection->ToggleCellSelection( coords.GetRow(), + coords.GetCol(), + event.ControlDown(), + event.ShiftDown(), + event.AltDown(), + event.MetaDown() ); + } + m_selectingTopLeft = wxGridNoCellCoords; + m_selectingBottomRight = wxGridNoCellCoords; + m_selectingKeyboard = coords; + } + else + { + m_waitForSlowClick = m_currentCellCoords == coords && coords != wxGridNoCellCoords; + SetCurrentCell( coords ); + if ( m_selection ) + { + if ( m_selection->GetSelectionMode() != + wxGrid::wxGridSelectCells ) + { + HighlightBlock( coords, coords ); + } + } + } + } + } + } + + // ------------ Left double click + // + else if ( event.LeftDClick() && coords != wxGridNoCellCoords ) + { + DisableCellEditControl(); + + if ( XToEdgeOfCol(x) < 0 && YToEdgeOfRow(y) < 0 ) + { + if ( !SendEvent( wxEVT_GRID_CELL_LEFT_DCLICK, + coords.GetRow(), + coords.GetCol(), + event ) ) + { + // we want double click to select a cell and start editing + // (i.e. to behave in same way as sequence of two slow clicks): + m_waitForSlowClick = true; + } + } + } + + // ------------ Left button released + // + else if ( event.LeftUp() ) + { + if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL ) + { + if (m_winCapture) + { + if (m_winCapture->HasCapture()) + m_winCapture->ReleaseMouse(); + m_winCapture = NULL; + } + + if ( coords == m_currentCellCoords && m_waitForSlowClick && CanEnableCellControl() ) + { + ClearSelection(); + EnableCellEditControl(); + + wxGridCellAttr *attr = GetCellAttr(coords); + wxGridCellEditor *editor = attr->GetEditor(this, coords.GetRow(), coords.GetCol()); + editor->StartingClick(); + editor->DecRef(); + attr->DecRef(); + + m_waitForSlowClick = false; + } + else if ( m_selectingTopLeft != wxGridNoCellCoords && + m_selectingBottomRight != wxGridNoCellCoords ) + { + if ( m_selection ) + { + m_selection->SelectBlock( m_selectingTopLeft.GetRow(), + m_selectingTopLeft.GetCol(), + m_selectingBottomRight.GetRow(), + m_selectingBottomRight.GetCol(), + event.ControlDown(), + event.ShiftDown(), + event.AltDown(), + event.MetaDown() ); + } + + m_selectingTopLeft = wxGridNoCellCoords; + m_selectingBottomRight = wxGridNoCellCoords; + + // Show the edit control, if it has been hidden for + // drag-shrinking. + ShowCellEditControl(); + } + } + else if ( m_cursorMode == WXGRID_CURSOR_RESIZE_ROW ) + { + ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL); + DoEndDragResizeRow(); + + // Note: we are ending the event *after* doing + // default processing in this case + // + SendEvent( wxEVT_GRID_ROW_SIZE, m_dragRowOrCol, -1, event ); + } + else if ( m_cursorMode == WXGRID_CURSOR_RESIZE_COL ) + { + ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL); + DoEndDragResizeCol(); + + // Note: we are ending the event *after* doing + // default processing in this case + // + SendEvent( wxEVT_GRID_COL_SIZE, -1, m_dragRowOrCol, event ); + } + + m_dragLastPos = -1; + } + + // ------------ Right button down + // + else if ( event.RightDown() && coords != wxGridNoCellCoords ) + { + DisableCellEditControl(); + if ( !SendEvent( wxEVT_GRID_CELL_RIGHT_CLICK, + coords.GetRow(), + coords.GetCol(), + event ) ) + { + // no default action at the moment + } + } + + // ------------ Right double click + // + else if ( event.RightDClick() && coords != wxGridNoCellCoords ) + { + DisableCellEditControl(); + if ( !SendEvent( wxEVT_GRID_CELL_RIGHT_DCLICK, + coords.GetRow(), + coords.GetCol(), + event ) ) + { + // no default action at the moment + } + } + + // ------------ Moving and no button action + // + else if ( event.Moving() && !event.IsButton() ) + { + if ( coords.GetRow() < 0 || coords.GetCol() < 0 ) + { + // out of grid cell area + ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL); + return; + } + + int dragRow = YToEdgeOfRow( y ); + int dragCol = XToEdgeOfCol( x ); + + // Dragging on the corner of a cell to resize in both + // directions is not implemented yet... + // + if ( dragRow >= 0 && dragCol >= 0 ) + { + ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL); + return; + } + + if ( dragRow >= 0 ) + { + m_dragRowOrCol = dragRow; + + if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL ) + { + if ( CanDragRowSize() && CanDragGridSize() ) + ChangeCursorMode(WXGRID_CURSOR_RESIZE_ROW, NULL, false); + } + } + else if ( dragCol >= 0 ) + { + m_dragRowOrCol = dragCol; + + if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL ) + { + if ( CanDragColSize() && CanDragGridSize() ) + ChangeCursorMode(WXGRID_CURSOR_RESIZE_COL, NULL, false); + } + } + else // Neither on a row or col edge + { + if ( m_cursorMode != WXGRID_CURSOR_SELECT_CELL ) + { + ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL); + } + } + } +} + +void wxGrid::DoEndDragResizeRow() +{ + if ( m_dragLastPos >= 0 ) + { + // erase the last line and resize the row + // + int cw, ch, left, dummy; + m_gridWin->GetClientSize( &cw, &ch ); + CalcUnscrolledPosition( 0, 0, &left, &dummy ); + + wxClientDC dc( m_gridWin ); + PrepareDC( dc ); + dc.SetLogicalFunction( wxINVERT ); + dc.DrawLine( left, m_dragLastPos, left + cw, m_dragLastPos ); + HideCellEditControl(); + SaveEditControlValue(); + + int rowTop = GetRowTop(m_dragRowOrCol); + SetRowSize( m_dragRowOrCol, + wxMax( m_dragLastPos - rowTop, m_minAcceptableRowHeight ) ); + + if ( !GetBatchCount() ) + { + // Only needed to get the correct rect.y: + wxRect rect ( CellToRect( m_dragRowOrCol, 0 ) ); + rect.x = 0; + CalcScrolledPosition(0, rect.y, &dummy, &rect.y); + rect.width = m_rowLabelWidth; + rect.height = ch - rect.y; + m_rowLabelWin->Refresh( true, &rect ); + rect.width = cw; + + // if there is a multicell block, paint all of it + if (m_table) + { + int i, cell_rows, cell_cols, subtract_rows = 0; + int leftCol = XToCol(left); + int rightCol = internalXToCol(left + cw); + if (leftCol >= 0) + { + for (i=leftCol; iRefresh( false, &rect ); + } + + ShowCellEditControl(); + } +} + + +void wxGrid::DoEndDragResizeCol() +{ + if ( m_dragLastPos >= 0 ) + { + // erase the last line and resize the col + // + int cw, ch, dummy, top; + m_gridWin->GetClientSize( &cw, &ch ); + CalcUnscrolledPosition( 0, 0, &dummy, &top ); + + wxClientDC dc( m_gridWin ); + PrepareDC( dc ); + dc.SetLogicalFunction( wxINVERT ); + dc.DrawLine( m_dragLastPos, top, m_dragLastPos, top + ch ); + HideCellEditControl(); + SaveEditControlValue(); + + int colLeft = GetColLeft(m_dragRowOrCol); + SetColSize( m_dragRowOrCol, + wxMax( m_dragLastPos - colLeft, + GetColMinimalWidth(m_dragRowOrCol) ) ); + + if ( !GetBatchCount() ) + { + // Only needed to get the correct rect.x: + wxRect rect ( CellToRect( 0, m_dragRowOrCol ) ); + rect.y = 0; + CalcScrolledPosition(rect.x, 0, &rect.x, &dummy); + rect.width = cw - rect.x; + rect.height = m_colLabelHeight; + m_colLabelWin->Refresh( true, &rect ); + rect.height = ch; + + // if there is a multicell block, paint all of it + if (m_table) + { + int i, cell_rows, cell_cols, subtract_cols = 0; + int topRow = YToRow(top); + int bottomRow = internalYToRow(top + cw); + if (topRow >= 0) + { + for (i=topRow; iRefresh( false, &rect ); + } + + ShowCellEditControl(); + } +} + +void wxGrid::DoEndDragMoveCol() +{ + //The user clicked on the column but didn't actually drag + if ( m_dragLastPos < 0 ) + { + m_colLabelWin->Refresh(); //Do this to "unpress" the column + return; + } + + int newPos; + if ( m_moveToCol == -1 ) + newPos = m_numCols - 1; + else + { + newPos = GetColPos( m_moveToCol ); + if ( newPos > GetColPos( m_dragRowOrCol ) ) + newPos--; + } + + SetColPos( m_dragRowOrCol, newPos ); +} + +void wxGrid::SetColPos( int colID, int newPos ) +{ + if ( m_colAt.IsEmpty() ) + { + m_colAt.Alloc( m_numCols ); + + int i; + for ( i = 0; i < m_numCols; i++ ) + { + m_colAt.Add( i ); + } + } + + int oldPos = GetColPos( colID ); + + //Reshuffle the m_colAt array + if ( newPos > oldPos ) + { + int i; + for ( i = oldPos; i < newPos; i++ ) + { + m_colAt[i] = m_colAt[i+1]; + } + } + else + { + int i; + for ( i = oldPos; i > newPos; i-- ) + { + m_colAt[i] = m_colAt[i-1]; + } + } + + m_colAt[newPos] = colID; + + //Recalculate the column rights + if ( !m_colWidths.IsEmpty() ) + { + int colRight = 0; + int colPos; + for ( colPos = 0; colPos < m_numCols; colPos++ ) + { + int colID = GetColAt( colPos ); + + colRight += m_colWidths[colID]; + m_colRights[colID] = colRight; + } + } + + m_colLabelWin->Refresh(); + m_gridWin->Refresh(); +} + + + +void wxGrid::EnableDragColMove( bool enable ) +{ + if ( m_canDragColMove == enable ) + return; + + m_canDragColMove = enable; + + if ( !m_canDragColMove ) + { + m_colAt.Clear(); + + //Recalculate the column rights + if ( !m_colWidths.IsEmpty() ) + { + int colRight = 0; + int colPos; + for ( colPos = 0; colPos < m_numCols; colPos++ ) + { + colRight += m_colWidths[colPos]; + m_colRights[colPos] = colRight; + } + } + + m_colLabelWin->Refresh(); + m_gridWin->Refresh(); + } +} + + +// +// ------ interaction with data model +// +bool wxGrid::ProcessTableMessage( wxGridTableMessage& msg ) +{ + switch ( msg.GetId() ) + { + case wxGRIDTABLE_REQUEST_VIEW_GET_VALUES: + return GetModelValues(); + + case wxGRIDTABLE_REQUEST_VIEW_SEND_VALUES: + return SetModelValues(); + + case wxGRIDTABLE_NOTIFY_ROWS_INSERTED: + case wxGRIDTABLE_NOTIFY_ROWS_APPENDED: + case wxGRIDTABLE_NOTIFY_ROWS_DELETED: + case wxGRIDTABLE_NOTIFY_COLS_INSERTED: + case wxGRIDTABLE_NOTIFY_COLS_APPENDED: + case wxGRIDTABLE_NOTIFY_COLS_DELETED: + return Redimension( msg ); + + default: + return false; + } +} + +// The behaviour of this function depends on the grid table class +// Clear() function. For the default wxGridStringTable class the +// behavious is to replace all cell contents with wxEmptyString but +// not to change the number of rows or cols. +// +void wxGrid::ClearGrid() +{ + if ( m_table ) + { + if (IsCellEditControlEnabled()) + DisableCellEditControl(); + + m_table->Clear(); + if (!GetBatchCount()) + m_gridWin->Refresh(); + } +} + +bool wxGrid::InsertRows( int pos, int numRows, bool WXUNUSED(updateLabels) ) +{ + // TODO: something with updateLabels flag + + if ( !m_created ) + { + wxFAIL_MSG( wxT("Called wxGrid::InsertRows() before calling CreateGrid()") ); + return false; + } + + if ( m_table ) + { + if (IsCellEditControlEnabled()) + DisableCellEditControl(); + + bool done = m_table->InsertRows( pos, numRows ); + return done; + + // the table will have sent the results of the insert row + // operation to this view object as a grid table message + } + + return false; +} + +bool wxGrid::AppendRows( int numRows, bool WXUNUSED(updateLabels) ) +{ + // TODO: something with updateLabels flag + + if ( !m_created ) + { + wxFAIL_MSG( wxT("Called wxGrid::AppendRows() before calling CreateGrid()") ); + return false; + } + + if ( m_table ) + { + bool done = m_table && m_table->AppendRows( numRows ); + return done; + + // the table will have sent the results of the append row + // operation to this view object as a grid table message + } + + return false; +} + +bool wxGrid::DeleteRows( int pos, int numRows, bool WXUNUSED(updateLabels) ) +{ + // TODO: something with updateLabels flag + + if ( !m_created ) + { + wxFAIL_MSG( wxT("Called wxGrid::DeleteRows() before calling CreateGrid()") ); + return false; + } + + if ( m_table ) + { + if (IsCellEditControlEnabled()) + DisableCellEditControl(); + + bool done = m_table->DeleteRows( pos, numRows ); + return done; + // the table will have sent the results of the delete row + // operation to this view object as a grid table message + } + + return false; +} + +bool wxGrid::InsertCols( int pos, int numCols, bool WXUNUSED(updateLabels) ) +{ + // TODO: something with updateLabels flag + + if ( !m_created ) + { + wxFAIL_MSG( wxT("Called wxGrid::InsertCols() before calling CreateGrid()") ); + return false; + } + + if ( m_table ) + { + if (IsCellEditControlEnabled()) + DisableCellEditControl(); + + bool done = m_table->InsertCols( pos, numCols ); + return done; + // the table will have sent the results of the insert col + // operation to this view object as a grid table message + } + + return false; +} + +bool wxGrid::AppendCols( int numCols, bool WXUNUSED(updateLabels) ) +{ + // TODO: something with updateLabels flag + + if ( !m_created ) + { + wxFAIL_MSG( wxT("Called wxGrid::AppendCols() before calling CreateGrid()") ); + return false; + } + + if ( m_table ) + { + bool done = m_table->AppendCols( numCols ); + return done; + // the table will have sent the results of the append col + // operation to this view object as a grid table message + } + + return false; +} + +bool wxGrid::DeleteCols( int pos, int numCols, bool WXUNUSED(updateLabels) ) +{ + // TODO: something with updateLabels flag + + if ( !m_created ) + { + wxFAIL_MSG( wxT("Called wxGrid::DeleteCols() before calling CreateGrid()") ); + return false; + } + + if ( m_table ) + { + if (IsCellEditControlEnabled()) + DisableCellEditControl(); + + bool done = m_table->DeleteCols( pos, numCols ); + return done; + // the table will have sent the results of the delete col + // operation to this view object as a grid table message + } + + return false; +} + +// +// ----- event handlers +// + +// Generate a grid event based on a mouse event and +// return the result of ProcessEvent() +// +int wxGrid::SendEvent( const wxEventType type, + int row, int col, + wxMouseEvent& mouseEv ) +{ + bool claimed, vetoed; + + if ( type == wxEVT_GRID_ROW_SIZE || type == wxEVT_GRID_COL_SIZE ) + { + int rowOrCol = (row == -1 ? col : row); + + wxGridSizeEvent gridEvt( GetId(), + type, + this, + rowOrCol, + mouseEv.GetX() + GetRowLabelSize(), + mouseEv.GetY() + GetColLabelSize(), + mouseEv.ControlDown(), + mouseEv.ShiftDown(), + mouseEv.AltDown(), + mouseEv.MetaDown() ); + + claimed = GetEventHandler()->ProcessEvent(gridEvt); + vetoed = !gridEvt.IsAllowed(); + } + else if ( type == wxEVT_GRID_RANGE_SELECT ) + { + // Right now, it should _never_ end up here! + wxGridRangeSelectEvent gridEvt( GetId(), + type, + this, + m_selectingTopLeft, + m_selectingBottomRight, + true, + mouseEv.ControlDown(), + mouseEv.ShiftDown(), + mouseEv.AltDown(), + mouseEv.MetaDown() ); + + claimed = GetEventHandler()->ProcessEvent(gridEvt); + vetoed = !gridEvt.IsAllowed(); + } + else if ( type == wxEVT_GRID_LABEL_LEFT_CLICK || + type == wxEVT_GRID_LABEL_LEFT_DCLICK || + type == wxEVT_GRID_LABEL_RIGHT_CLICK || + type == wxEVT_GRID_LABEL_RIGHT_DCLICK ) + { + wxPoint pos = mouseEv.GetPosition(); + + if ( mouseEv.GetEventObject() == GetGridRowLabelWindow() ) + pos.y += GetColLabelSize(); + if ( mouseEv.GetEventObject() == GetGridColLabelWindow() ) + pos.x += GetRowLabelSize(); + + wxGridEvent gridEvt( GetId(), + type, + this, + row, col, + pos.x, + pos.y, + false, + mouseEv.ControlDown(), + mouseEv.ShiftDown(), + mouseEv.AltDown(), + mouseEv.MetaDown() ); + claimed = GetEventHandler()->ProcessEvent(gridEvt); + vetoed = !gridEvt.IsAllowed(); + } + else + { + wxGridEvent gridEvt( GetId(), + type, + this, + row, col, + mouseEv.GetX() + GetRowLabelSize(), + mouseEv.GetY() + GetColLabelSize(), + false, + mouseEv.ControlDown(), + mouseEv.ShiftDown(), + mouseEv.AltDown(), + mouseEv.MetaDown() ); + claimed = GetEventHandler()->ProcessEvent(gridEvt); + vetoed = !gridEvt.IsAllowed(); + } + + // A Veto'd event may not be `claimed' so test this first + if (vetoed) + return -1; + + return claimed ? 1 : 0; +} + +// Generate a grid event of specified type and return the result +// of ProcessEvent(). +// +int wxGrid::SendEvent( const wxEventType type, + int row, int col ) +{ + bool claimed, vetoed; + + if ( type == wxEVT_GRID_ROW_SIZE || type == wxEVT_GRID_COL_SIZE ) + { + int rowOrCol = (row == -1 ? col : row); + + wxGridSizeEvent gridEvt( GetId(), type, this, rowOrCol ); + + claimed = GetEventHandler()->ProcessEvent(gridEvt); + vetoed = !gridEvt.IsAllowed(); + } + else + { + wxGridEvent gridEvt( GetId(), type, this, row, col ); + + claimed = GetEventHandler()->ProcessEvent(gridEvt); + vetoed = !gridEvt.IsAllowed(); + } + + // A Veto'd event may not be `claimed' so test this first + if (vetoed) + return -1; + + return claimed ? 1 : 0; +} + +void wxGrid::OnPaint( wxPaintEvent& WXUNUSED(event) ) +{ + // needed to prevent zillions of paint events on MSW + wxPaintDC dc(this); +} + +void wxGrid::Refresh(bool eraseb, const wxRect* rect) +{ + // Don't do anything if between Begin/EndBatch... + // EndBatch() will do all this on the last nested one anyway. + if (! GetBatchCount()) + { + // Refresh to get correct scrolled position: + wxScrolledWindow::Refresh(eraseb, rect); + + if (rect) + { + int rect_x, rect_y, rectWidth, rectHeight; + int width_label, width_cell, height_label, height_cell; + int x, y; + + // Copy rectangle can get scroll offsets.. + rect_x = rect->GetX(); + rect_y = rect->GetY(); + rectWidth = rect->GetWidth(); + rectHeight = rect->GetHeight(); + + width_label = m_rowLabelWidth - rect_x; + if (width_label > rectWidth) + width_label = rectWidth; + + height_label = m_colLabelHeight - rect_y; + if (height_label > rectHeight) + height_label = rectHeight; + + if (rect_x > m_rowLabelWidth) + { + x = rect_x - m_rowLabelWidth; + width_cell = rectWidth; + } + else + { + x = 0; + width_cell = rectWidth - (m_rowLabelWidth - rect_x); + } + + if (rect_y > m_colLabelHeight) + { + y = rect_y - m_colLabelHeight; + height_cell = rectHeight; + } + else + { + y = 0; + height_cell = rectHeight - (m_colLabelHeight - rect_y); + } + + // Paint corner label part intersecting rect. + if ( width_label > 0 && height_label > 0 ) + { + wxRect anotherrect(rect_x, rect_y, width_label, height_label); + m_cornerLabelWin->Refresh(eraseb, &anotherrect); + } + + // Paint col labels part intersecting rect. + if ( width_cell > 0 && height_label > 0 ) + { + wxRect anotherrect(x, rect_y, width_cell, height_label); + m_colLabelWin->Refresh(eraseb, &anotherrect); + } + + // Paint row labels part intersecting rect. + if ( width_label > 0 && height_cell > 0 ) + { + wxRect anotherrect(rect_x, y, width_label, height_cell); + m_rowLabelWin->Refresh(eraseb, &anotherrect); + } + + // Paint cell area part intersecting rect. + if ( width_cell > 0 && height_cell > 0 ) + { + wxRect anotherrect(x, y, width_cell, height_cell); + m_gridWin->Refresh(eraseb, &anotherrect); + } + } + else + { + m_cornerLabelWin->Refresh(eraseb, NULL); + m_colLabelWin->Refresh(eraseb, NULL); + m_rowLabelWin->Refresh(eraseb, NULL); + m_gridWin->Refresh(eraseb, NULL); + } + } +} + +void wxGrid::OnSize( wxSizeEvent& WXUNUSED(event) ) +{ + if (m_targetWindow != this) // check whether initialisation has been done + { + // update our children window positions and scrollbars + CalcDimensions(); + } +} + +void wxGrid::OnKeyDown( wxKeyEvent& event ) +{ + if ( m_inOnKeyDown ) + { + // shouldn't be here - we are going round in circles... + // + wxFAIL_MSG( wxT("wxGrid::OnKeyDown called while already active") ); + } + + m_inOnKeyDown = true; + + // propagate the event up and see if it gets processed + wxWindow *parent = GetParent(); + wxKeyEvent keyEvt( event ); + keyEvt.SetEventObject( parent ); + + if ( !parent->GetEventHandler()->ProcessEvent( keyEvt ) ) + { + if (GetLayoutDirection() == wxLayout_RightToLeft) + { + if (event.GetKeyCode() == WXK_RIGHT) + event.m_keyCode = WXK_LEFT; + else if (event.GetKeyCode() == WXK_LEFT) + event.m_keyCode = WXK_RIGHT; + } + + // try local handlers + switch ( event.GetKeyCode() ) + { + case WXK_UP: + if ( event.ControlDown() ) + MoveCursorUpBlock( event.ShiftDown() ); + else + MoveCursorUp( event.ShiftDown() ); + break; + + case WXK_DOWN: + if ( event.ControlDown() ) + MoveCursorDownBlock( event.ShiftDown() ); + else + MoveCursorDown( event.ShiftDown() ); + break; + + case WXK_LEFT: + if ( event.ControlDown() ) + MoveCursorLeftBlock( event.ShiftDown() ); + else + MoveCursorLeft( event.ShiftDown() ); + break; + + case WXK_RIGHT: + if ( event.ControlDown() ) + MoveCursorRightBlock( event.ShiftDown() ); + else + MoveCursorRight( event.ShiftDown() ); + break; + + case WXK_RETURN: + case WXK_NUMPAD_ENTER: + if ( event.ControlDown() ) + { + event.Skip(); // to let the edit control have the return + } + else + { + if ( GetGridCursorRow() < GetNumberRows()-1 ) + { + MoveCursorDown( event.ShiftDown() ); + } + else + { + // at the bottom of a column + DisableCellEditControl(); + } + } + break; + + case WXK_ESCAPE: + ClearSelection(); + break; + + case WXK_TAB: + if (event.ShiftDown()) + { + if ( GetGridCursorCol() > 0 ) + { + MoveCursorLeft( false ); + } + else + { + // at left of grid + DisableCellEditControl(); + } + } + else + { + if ( GetGridCursorCol() < GetNumberCols() - 1 ) + { + MoveCursorRight( false ); + } + else + { + // at right of grid + DisableCellEditControl(); + } + } + break; + + case WXK_HOME: + if ( event.ControlDown() ) + { + MakeCellVisible( 0, 0 ); + SetCurrentCell( 0, 0 ); + } + else + { + event.Skip(); + } + break; + + case WXK_END: + if ( event.ControlDown() ) + { + MakeCellVisible( m_numRows - 1, m_numCols - 1 ); + SetCurrentCell( m_numRows - 1, m_numCols - 1 ); + } + else + { + event.Skip(); + } + break; + + case WXK_PAGEUP: + MovePageUp(); + break; + + case WXK_PAGEDOWN: + MovePageDown(); + break; + + case WXK_SPACE: + if ( event.ControlDown() ) + { + if ( m_selection ) + { + m_selection->ToggleCellSelection( + m_currentCellCoords.GetRow(), + m_currentCellCoords.GetCol(), + event.ControlDown(), + event.ShiftDown(), + event.AltDown(), + event.MetaDown() ); + } + break; + } + + if ( !IsEditable() ) + MoveCursorRight( false ); + else + event.Skip(); + break; + + default: + event.Skip(); + break; + } + } + + m_inOnKeyDown = false; +} + +void wxGrid::OnKeyUp( wxKeyEvent& event ) +{ + // try local handlers + // + if ( event.GetKeyCode() == WXK_SHIFT ) + { + if ( m_selectingTopLeft != wxGridNoCellCoords && + m_selectingBottomRight != wxGridNoCellCoords ) + { + if ( m_selection ) + { + m_selection->SelectBlock( + m_selectingTopLeft.GetRow(), + m_selectingTopLeft.GetCol(), + m_selectingBottomRight.GetRow(), + m_selectingBottomRight.GetCol(), + event.ControlDown(), + true, + event.AltDown(), + event.MetaDown() ); + } + } + + m_selectingTopLeft = wxGridNoCellCoords; + m_selectingBottomRight = wxGridNoCellCoords; + m_selectingKeyboard = wxGridNoCellCoords; + } +} + +void wxGrid::OnChar( wxKeyEvent& event ) +{ + // is it possible to edit the current cell at all? + if ( !IsCellEditControlEnabled() && CanEnableCellControl() ) + { + // yes, now check whether the cells editor accepts the key + int row = m_currentCellCoords.GetRow(); + int col = m_currentCellCoords.GetCol(); + wxGridCellAttr *attr = GetCellAttr(row, col); + wxGridCellEditor *editor = attr->GetEditor(this, row, col); + + // is special and will always start editing, for + // other keys - ask the editor itself + if ( (event.GetKeyCode() == WXK_F2 && !event.HasModifiers()) + || editor->IsAcceptedKey(event) ) + { + // ensure cell is visble + MakeCellVisible(row, col); + EnableCellEditControl(); + + // a problem can arise if the cell is not completely + // visible (even after calling MakeCellVisible the + // control is not created and calling StartingKey will + // crash the app + if ( event.GetKeyCode() != WXK_F2 && editor->IsCreated() && m_cellEditCtrlEnabled ) + editor->StartingKey(event); + } + else + { + event.Skip(); + } + + editor->DecRef(); + attr->DecRef(); + } + else + { + event.Skip(); + } +} + +void wxGrid::OnEraseBackground(wxEraseEvent&) +{ +} + +void wxGrid::SetCurrentCell( const wxGridCellCoords& coords ) +{ + if ( SendEvent( wxEVT_GRID_SELECT_CELL, coords.GetRow(), coords.GetCol() ) ) + { + // the event has been intercepted - do nothing + return; + } + +#if !(defined(__WXMAC__) && wxMAC_USE_CORE_GRAPHICS) + wxClientDC dc( m_gridWin ); + PrepareDC( dc ); +#endif + + if ( m_currentCellCoords != wxGridNoCellCoords ) + { + DisableCellEditControl(); + + if ( IsVisible( m_currentCellCoords, false ) ) + { + wxRect r; + r = BlockToDeviceRect( m_currentCellCoords, m_currentCellCoords ); + if ( !m_gridLinesEnabled ) + { + r.x--; + r.y--; + r.width++; + r.height++; + } + + wxGridCellCoordsArray cells = CalcCellsExposed( r ); + + // Otherwise refresh redraws the highlight! + m_currentCellCoords = coords; + +#if defined(__WXMAC__) && wxMAC_USE_CORE_GRAPHICS + m_gridWin->Refresh(true /*, & r */); +#else + DrawGridCellArea( dc, cells ); + DrawAllGridLines( dc, r ); +#endif + } + } + + m_currentCellCoords = coords; + + wxGridCellAttr *attr = GetCellAttr( coords ); +#if !(defined(__WXMAC__) && wxMAC_USE_CORE_GRAPHICS) + DrawCellHighlight( dc, attr ); +#endif + attr->DecRef(); +} + +void wxGrid::HighlightBlock( int topRow, int leftCol, int bottomRow, int rightCol ) +{ + int temp; + wxGridCellCoords updateTopLeft, updateBottomRight; + + if ( m_selection ) + { + if ( m_selection->GetSelectionMode() == wxGrid::wxGridSelectRows ) + { + leftCol = 0; + rightCol = GetNumberCols() - 1; + } + else if ( m_selection->GetSelectionMode() == wxGrid::wxGridSelectColumns ) + { + topRow = 0; + bottomRow = GetNumberRows() - 1; + } + } + + if ( topRow > bottomRow ) + { + temp = topRow; + topRow = bottomRow; + bottomRow = temp; + } + + if ( leftCol > rightCol ) + { + temp = leftCol; + leftCol = rightCol; + rightCol = temp; + } + + updateTopLeft = wxGridCellCoords( topRow, leftCol ); + updateBottomRight = wxGridCellCoords( bottomRow, rightCol ); + + // First the case that we selected a completely new area + if ( m_selectingTopLeft == wxGridNoCellCoords || + m_selectingBottomRight == wxGridNoCellCoords ) + { + wxRect rect; + rect = BlockToDeviceRect( wxGridCellCoords ( topRow, leftCol ), + wxGridCellCoords ( bottomRow, rightCol ) ); + m_gridWin->Refresh( false, &rect ); + } + + // Now handle changing an existing selection area. + else if ( m_selectingTopLeft != updateTopLeft || + m_selectingBottomRight != updateBottomRight ) + { + // Compute two optimal update rectangles: + // Either one rectangle is a real subset of the + // other, or they are (almost) disjoint! + wxRect rect[4]; + bool need_refresh[4]; + need_refresh[0] = + need_refresh[1] = + need_refresh[2] = + need_refresh[3] = false; + int i; + + // Store intermediate values + wxCoord oldLeft = m_selectingTopLeft.GetCol(); + wxCoord oldTop = m_selectingTopLeft.GetRow(); + wxCoord oldRight = m_selectingBottomRight.GetCol(); + wxCoord oldBottom = m_selectingBottomRight.GetRow(); + + // Determine the outer/inner coordinates. + if (oldLeft > leftCol) + { + temp = oldLeft; + oldLeft = leftCol; + leftCol = temp; + } + if (oldTop > topRow ) + { + temp = oldTop; + oldTop = topRow; + topRow = temp; + } + if (oldRight < rightCol ) + { + temp = oldRight; + oldRight = rightCol; + rightCol = temp; + } + if (oldBottom < bottomRow) + { + temp = oldBottom; + oldBottom = bottomRow; + bottomRow = temp; + } + + // Now, either the stuff marked old is the outer + // rectangle or we don't have a situation where one + // is contained in the other. + + if ( oldLeft < leftCol ) + { + // Refresh the newly selected or deselected + // area to the left of the old or new selection. + need_refresh[0] = true; + rect[0] = BlockToDeviceRect( + wxGridCellCoords( oldTop, oldLeft ), + wxGridCellCoords( oldBottom, leftCol - 1 ) ); + } + + if ( oldTop < topRow ) + { + // Refresh the newly selected or deselected + // area above the old or new selection. + need_refresh[1] = true; + rect[1] = BlockToDeviceRect( + wxGridCellCoords( oldTop, leftCol ), + wxGridCellCoords( topRow - 1, rightCol ) ); + } + + if ( oldRight > rightCol ) + { + // Refresh the newly selected or deselected + // area to the right of the old or new selection. + need_refresh[2] = true; + rect[2] = BlockToDeviceRect( + wxGridCellCoords( oldTop, rightCol + 1 ), + wxGridCellCoords( oldBottom, oldRight ) ); + } + + if ( oldBottom > bottomRow ) + { + // Refresh the newly selected or deselected + // area below the old or new selection. + need_refresh[3] = true; + rect[3] = BlockToDeviceRect( + wxGridCellCoords( bottomRow + 1, leftCol ), + wxGridCellCoords( oldBottom, rightCol ) ); + } + + // various Refresh() calls + for (i = 0; i < 4; i++ ) + if ( need_refresh[i] && rect[i] != wxGridNoCellRect ) + m_gridWin->Refresh( false, &(rect[i]) ); + } + + // change selection + m_selectingTopLeft = updateTopLeft; + m_selectingBottomRight = updateBottomRight; +} + +// +// ------ functions to get/send data (see also public functions) +// + +bool wxGrid::GetModelValues() +{ + // Hide the editor, so it won't hide a changed value. + HideCellEditControl(); + + if ( m_table ) + { + // all we need to do is repaint the grid + // + m_gridWin->Refresh(); + return true; + } + + return false; +} + +bool wxGrid::SetModelValues() +{ + int row, col; + + // Disable the editor, so it won't hide a changed value. + // Do we also want to save the current value of the editor first? + // I think so ... + DisableCellEditControl(); + + if ( m_table ) + { + for ( row = 0; row < m_numRows; row++ ) + { + for ( col = 0; col < m_numCols; col++ ) + { + m_table->SetValue( row, col, GetCellValue(row, col) ); + } + } + + return true; + } + + return false; +} + +// Note - this function only draws cells that are in the list of +// exposed cells (usually set from the update region by +// CalcExposedCells) +// +void wxGrid::DrawGridCellArea( wxDC& dc, const wxGridCellCoordsArray& cells ) +{ + if ( !m_numRows || !m_numCols ) + return; + + int i, numCells = cells.GetCount(); + int row, col, cell_rows, cell_cols; + wxGridCellCoordsArray redrawCells; + + for ( i = numCells - 1; i >= 0; i-- ) + { + row = cells[i].GetRow(); + col = cells[i].GetCol(); + GetCellSize( row, col, &cell_rows, &cell_cols ); + + // If this cell is part of a multicell block, find owner for repaint + if ( cell_rows <= 0 || cell_cols <= 0 ) + { + wxGridCellCoords cell( row + cell_rows, col + cell_cols ); + bool marked = false; + for ( int j = 0; j < numCells; j++ ) + { + if ( cell == cells[j] ) + { + marked = true; + break; + } + } + + if (!marked) + { + int count = redrawCells.GetCount(); + for (int j = 0; j < count; j++) + { + if ( cell == redrawCells[j] ) + { + marked = true; + break; + } + } + + if (!marked) + redrawCells.Add( cell ); + } + + // don't bother drawing this cell + continue; + } + + // If this cell is empty, find cell to left that might want to overflow + if (m_table && m_table->IsEmptyCell(row, col)) + { + for ( int l = 0; l < cell_rows; l++ ) + { + // find a cell in this row to leave already marked for repaint + int left = col; + for (int k = 0; k < int(redrawCells.GetCount()); k++) + if ((redrawCells[k].GetCol() < left) && + (redrawCells[k].GetRow() == row)) + { + left = redrawCells[k].GetCol(); + } + + if (left == col) + left = 0; // oh well + + for (int j = col - 1; j >= left; j--) + { + if (!m_table->IsEmptyCell(row + l, j)) + { + if (GetCellOverflow(row + l, j)) + { + wxGridCellCoords cell(row + l, j); + bool marked = false; + + for (int k = 0; k < numCells; k++) + { + if ( cell == cells[k] ) + { + marked = true; + break; + } + } + + if (!marked) + { + int count = redrawCells.GetCount(); + for (int k = 0; k < count; k++) + { + if ( cell == redrawCells[k] ) + { + marked = true; + break; + } + } + if (!marked) + redrawCells.Add( cell ); + } + } + break; + } + } + } + } + + DrawCell( dc, cells[i] ); + } + + numCells = redrawCells.GetCount(); + + for ( i = numCells - 1; i >= 0; i-- ) + { + DrawCell( dc, redrawCells[i] ); + } +} + +void wxGrid::DrawGridSpace( wxDC& dc ) +{ + int cw, ch; + m_gridWin->GetClientSize( &cw, &ch ); + + int right, bottom; + CalcUnscrolledPosition( cw, ch, &right, &bottom ); + + int rightCol = m_numCols > 0 ? GetColRight(GetColAt( m_numCols - 1 )) : 0; + int bottomRow = m_numRows > 0 ? GetRowBottom(m_numRows - 1) : 0; + + if ( right > rightCol || bottom > bottomRow ) + { + int left, top; + CalcUnscrolledPosition( 0, 0, &left, &top ); + + dc.SetBrush( wxBrush(GetDefaultCellBackgroundColour(), wxSOLID) ); + dc.SetPen( *wxTRANSPARENT_PEN ); + + if ( right > rightCol ) + { + dc.DrawRectangle( rightCol, top, right - rightCol, ch ); + } + + if ( bottom > bottomRow ) + { + dc.DrawRectangle( left, bottomRow, cw, bottom - bottomRow ); + } + } +} + +void wxGrid::DrawCell( wxDC& dc, const wxGridCellCoords& coords ) +{ + int row = coords.GetRow(); + int col = coords.GetCol(); + + if ( GetColWidth(col) <= 0 || GetRowHeight(row) <= 0 ) + return; + + // we draw the cell border ourselves +#if !WXGRID_DRAW_LINES + if ( m_gridLinesEnabled ) + DrawCellBorder( dc, coords ); +#endif + + wxGridCellAttr* attr = GetCellAttr(row, col); + + bool isCurrent = coords == m_currentCellCoords; + + wxRect rect = CellToRect( row, col ); + + // if the editor is shown, we should use it and not the renderer + // Note: However, only if it is really _shown_, i.e. not hidden! + if ( isCurrent && IsCellEditControlShown() ) + { + // NB: this "#if..." is temporary and fixes a problem where the + // edit control is erased by this code after being rendered. + // On wxMac (QD build only), the cell editor is a wxTextCntl and is rendered + // implicitly, causing this out-of order render. +#if !defined(__WXMAC__) + wxGridCellEditor *editor = attr->GetEditor(this, row, col); + editor->PaintBackground(rect, attr); + editor->DecRef(); +#endif + } + else + { + // but all the rest is drawn by the cell renderer and hence may be customized + wxGridCellRenderer *renderer = attr->GetRenderer(this, row, col); + renderer->Draw(*this, *attr, dc, rect, row, col, IsInSelection(coords)); + renderer->DecRef(); + } + + attr->DecRef(); +} + +void wxGrid::DrawCellHighlight( wxDC& dc, const wxGridCellAttr *attr ) +{ + // don't show highlight when the grid doesn't have focus + if ( wxWindow::FindFocus() != m_gridWin ) + return; + + int row = m_currentCellCoords.GetRow(); + int col = m_currentCellCoords.GetCol(); + + if ( GetColWidth(col) <= 0 || GetRowHeight(row) <= 0 ) + return; + + wxRect rect = CellToRect(row, col); + + // hmmm... what could we do here to show that the cell is disabled? + // for now, I just draw a thinner border than for the other ones, but + // it doesn't look really good + + int penWidth = attr->IsReadOnly() ? m_cellHighlightROPenWidth : m_cellHighlightPenWidth; + + if (penWidth > 0) + { + // The center of the drawn line is where the position/width/height of + // the rectangle is actually at (on wxMSW at least), so the + // size of the rectangle is reduced to compensate for the thickness of + // the line. If this is too strange on non-wxMSW platforms then + // please #ifdef this appropriately. + rect.x += penWidth / 2; + rect.y += penWidth / 2; + rect.width -= penWidth - 1; + rect.height -= penWidth - 1; + + // Now draw the rectangle + // use the cellHighlightColour if the cell is inside a selection, this + // will ensure the cell is always visible. + dc.SetPen(wxPen(IsInSelection(row,col) ? m_selectionForeground : m_cellHighlightColour, penWidth, wxSOLID)); + dc.SetBrush(*wxTRANSPARENT_BRUSH); + dc.DrawRectangle(rect); + } + +#if 0 + // VZ: my experiments with 3D borders... + + // how to properly set colours for arbitrary bg? + wxCoord x1 = rect.x, + y1 = rect.y, + x2 = rect.x + rect.width - 1, + y2 = rect.y + rect.height - 1; + + dc.SetPen(*wxWHITE_PEN); + dc.DrawLine(x1, y1, x2, y1); + dc.DrawLine(x1, y1, x1, y2); + + dc.DrawLine(x1 + 1, y2 - 1, x2 - 1, y2 - 1); + dc.DrawLine(x2 - 1, y1 + 1, x2 - 1, y2); + + dc.SetPen(*wxBLACK_PEN); + dc.DrawLine(x1, y2, x2, y2); + dc.DrawLine(x2, y1, x2, y2 + 1); +#endif +} + +wxPen wxGrid::GetDefaultGridLinePen() +{ + return wxPen(GetGridLineColour(), 1, wxSOLID); +} + +wxPen wxGrid::GetRowGridLinePen(int WXUNUSED(row)) +{ + return GetDefaultGridLinePen(); +} + +wxPen wxGrid::GetColGridLinePen(int WXUNUSED(col)) +{ + return GetDefaultGridLinePen(); +} + +void wxGrid::DrawCellBorder( wxDC& dc, const wxGridCellCoords& coords ) +{ + int row = coords.GetRow(); + int col = coords.GetCol(); + if ( GetColWidth(col) <= 0 || GetRowHeight(row) <= 0 ) + return; + + + wxRect rect = CellToRect( row, col ); + + // right hand border + dc.SetPen( GetColGridLinePen(col) ); + dc.DrawLine( rect.x + rect.width, rect.y, + rect.x + rect.width, rect.y + rect.height + 1 ); + + // bottom border + dc.SetPen( GetRowGridLinePen(row) ); + dc.DrawLine( rect.x, rect.y + rect.height, + rect.x + rect.width, rect.y + rect.height); +} + +void wxGrid::DrawHighlight(wxDC& dc, const wxGridCellCoordsArray& cells) +{ + // This if block was previously in wxGrid::OnPaint but that doesn't + // seem to get called under wxGTK - MB + // + if ( m_currentCellCoords == wxGridNoCellCoords && + m_numRows && m_numCols ) + { + m_currentCellCoords.Set(0, 0); + } + + if ( IsCellEditControlShown() ) + { + // don't show highlight when the edit control is shown + return; + } + + // if the active cell was repainted, repaint its highlight too because it + // might have been damaged by the grid lines + size_t count = cells.GetCount(); + for ( size_t n = 0; n < count; n++ ) + { + if ( cells[n] == m_currentCellCoords ) + { + wxGridCellAttr* attr = GetCellAttr(m_currentCellCoords); + DrawCellHighlight(dc, attr); + attr->DecRef(); + + break; + } + } +} + +// TODO: remove this ??? +// This is used to redraw all grid lines e.g. when the grid line colour +// has been changed +// +void wxGrid::DrawAllGridLines( wxDC& dc, const wxRegion & WXUNUSED(reg) ) +{ +#if !WXGRID_DRAW_LINES + return; +#endif + + if ( !m_gridLinesEnabled || !m_numRows || !m_numCols ) + return; + + int top, bottom, left, right; + +#if 0 //#ifndef __WXGTK__ + if (reg.IsEmpty()) + { + int cw, ch; + m_gridWin->GetClientSize(&cw, &ch); + + // virtual coords of visible area + // + CalcUnscrolledPosition( 0, 0, &left, &top ); + CalcUnscrolledPosition( cw, ch, &right, &bottom ); + } + else + { + wxCoord x, y, w, h; + reg.GetBox(x, y, w, h); + CalcUnscrolledPosition( x, y, &left, &top ); + CalcUnscrolledPosition( x + w, y + h, &right, &bottom ); + } +#else + int cw, ch; + m_gridWin->GetClientSize(&cw, &ch); + CalcUnscrolledPosition( 0, 0, &left, &top ); + CalcUnscrolledPosition( cw, ch, &right, &bottom ); +#endif + + // avoid drawing grid lines past the last row and col + // + right = wxMin( right, GetColRight(GetColAt( m_numCols - 1 )) ); + bottom = wxMin( bottom, GetRowBottom(m_numRows - 1) ); + + // no gridlines inside multicells, clip them out + int leftCol = GetColPos( internalXToCol(left) ); + int topRow = internalYToRow(top); + int rightCol = GetColPos( internalXToCol(right) ); + int bottomRow = internalYToRow(bottom); + +#if !defined(__WXMAC__) || wxMAC_USE_CORE_GRAPHICS + wxRegion clippedcells(0, 0, cw, ch); + + int i, j, cell_rows, cell_cols; + wxRect rect; + + for (j=topRow; j<=bottomRow; j++) + { + int colPos; + for (colPos=leftCol; colPos<=rightCol; colPos++) + { + i = GetColAt( colPos ); + + GetCellSize( j, i, &cell_rows, &cell_cols ); + if ((cell_rows > 1) || (cell_cols > 1)) + { + rect = CellToRect(j,i); + CalcScrolledPosition( rect.x, rect.y, &rect.x, &rect.y ); + clippedcells.Subtract(rect); + } + else if ((cell_rows < 0) || (cell_cols < 0)) + { + rect = CellToRect(j + cell_rows, i + cell_cols); + CalcScrolledPosition( rect.x, rect.y, &rect.x, &rect.y ); + clippedcells.Subtract(rect); + } + } + } +#else + wxRegion clippedcells( left, top, right - left, bottom - top ); + + int i, j, cell_rows, cell_cols; + wxRect rect; + + for (j=topRow; j<=bottomRow; j++) + { + for (i=leftCol; i<=rightCol; i++) + { + GetCellSize( j, i, &cell_rows, &cell_cols ); + if ((cell_rows > 1) || (cell_cols > 1)) + { + rect = CellToRect(j, i); + clippedcells.Subtract(rect); + } + else if ((cell_rows < 0) || (cell_cols < 0)) + { + rect = CellToRect(j + cell_rows, i + cell_cols); + clippedcells.Subtract(rect); + } + } + } +#endif + + dc.SetClippingRegion( clippedcells ); + + + // horizontal grid lines + // + // already declared above - int i; + for ( i = internalYToRow(top); i < m_numRows; i++ ) + { + int bot = GetRowBottom(i) - 1; + + if ( bot > bottom ) + { + break; + } + + if ( bot >= top ) + { + dc.SetPen( GetRowGridLinePen(i) ); + dc.DrawLine( left, bot, right, bot ); + } + } + + // vertical grid lines + // + int colPos; + for ( colPos = leftCol; colPos < m_numCols; colPos++ ) + { + i = GetColAt( colPos ); + + int colRight = GetColRight(i); +#ifdef __WXGTK__ + if (GetLayoutDirection() != wxLayout_RightToLeft) +#endif + colRight--; + + if ( colRight > right ) + { + break; + } + + if ( colRight >= left ) + { + dc.SetPen( GetColGridLinePen(i) ); + dc.DrawLine( colRight, top, colRight, bottom ); + } + } + + dc.DestroyClippingRegion(); +} + +void wxGrid::DrawRowLabels( wxDC& dc, const wxArrayInt& rows) +{ + if ( !m_numRows ) + return; + + size_t i; + size_t numLabels = rows.GetCount(); + + for ( i = 0; i < numLabels; i++ ) + { + DrawRowLabel( dc, rows[i] ); + } +} + +void wxGrid::DrawRowLabel( wxDC& dc, int row ) +{ + if ( GetRowHeight(row) <= 0 || m_rowLabelWidth <= 0 ) + return; + + wxRect rect; + +#if 0 +def __WXGTK20__ + rect.SetX( 1 ); + rect.SetY( GetRowTop(row) + 1 ); + rect.SetWidth( m_rowLabelWidth - 2 ); + rect.SetHeight( GetRowHeight(row) - 2 ); + + CalcScrolledPosition( 0, rect.y, NULL, &rect.y ); + + wxWindowDC *win_dc = (wxWindowDC*) &dc; + + wxRendererNative::Get().DrawHeaderButton( win_dc->m_owner, dc, rect, 0 ); +#else + int rowTop = GetRowTop(row), + rowBottom = GetRowBottom(row) - 1; + + dc.SetPen( wxPen(wxSystemSettings::GetColour(wxSYS_COLOUR_3DSHADOW), 1, wxSOLID) ); + dc.DrawLine( m_rowLabelWidth - 1, rowTop, m_rowLabelWidth - 1, rowBottom ); + dc.DrawLine( 0, rowTop, 0, rowBottom ); + dc.DrawLine( 0, rowBottom, m_rowLabelWidth, rowBottom ); + + dc.SetPen( *wxWHITE_PEN ); + dc.DrawLine( 1, rowTop, 1, rowBottom ); + dc.DrawLine( 1, rowTop, m_rowLabelWidth - 1, rowTop ); +#endif + + dc.SetBackgroundMode( wxTRANSPARENT ); + dc.SetTextForeground( GetLabelTextColour() ); + dc.SetFont( GetLabelFont() ); + + int hAlign, vAlign; + GetRowLabelAlignment( &hAlign, &vAlign ); + + rect.SetX( 2 ); + rect.SetY( GetRowTop(row) + 2 ); + rect.SetWidth( m_rowLabelWidth - 4 ); + rect.SetHeight( GetRowHeight(row) - 4 ); + DrawTextRectangle( dc, GetRowLabelValue( row ), rect, hAlign, vAlign ); +} + +void wxGrid::DrawColLabels( wxDC& dc,const wxArrayInt& cols ) +{ + if ( !m_numCols ) + return; + + size_t i; + size_t numLabels = cols.GetCount(); + + for ( i = 0; i < numLabels; i++ ) + { + DrawColLabel( dc, cols[i] ); + } +} + +void wxGrid::DrawColLabel( wxDC& dc, int col ) +{ + if ( GetColWidth(col) <= 0 || m_colLabelHeight <= 0 ) + return; + + int colLeft = GetColLeft(col); + + wxRect rect; + +#if 0 +def __WXGTK20__ + rect.SetX( colLeft + 1 ); + rect.SetY( 1 ); + rect.SetWidth( GetColWidth(col) - 2 ); + rect.SetHeight( m_colLabelHeight - 2 ); + + wxWindowDC *win_dc = (wxWindowDC*) &dc; + + wxRendererNative::Get().DrawHeaderButton( win_dc->m_owner, dc, rect, 0 ); +#else + int colRight = GetColRight(col) - 1; + + dc.SetPen( wxPen(wxSystemSettings::GetColour(wxSYS_COLOUR_3DSHADOW), 1, wxSOLID) ); + dc.DrawLine( colRight, 0, colRight, m_colLabelHeight - 1 ); + dc.DrawLine( colLeft, 0, colRight, 0 ); + dc.DrawLine( colLeft, m_colLabelHeight - 1, + colRight + 1, m_colLabelHeight - 1 ); + + dc.SetPen( *wxWHITE_PEN ); + dc.DrawLine( colLeft, 1, colLeft, m_colLabelHeight - 1 ); + dc.DrawLine( colLeft, 1, colRight, 1 ); +#endif + + dc.SetBackgroundMode( wxTRANSPARENT ); + dc.SetTextForeground( GetLabelTextColour() ); + dc.SetFont( GetLabelFont() ); + + int hAlign, vAlign, orient; + GetColLabelAlignment( &hAlign, &vAlign ); + orient = GetColLabelTextOrientation(); + + rect.SetX( colLeft + 2 ); + rect.SetY( 2 ); + rect.SetWidth( GetColWidth(col) - 4 ); + rect.SetHeight( m_colLabelHeight - 4 ); + DrawTextRectangle( dc, GetColLabelValue( col ), rect, hAlign, vAlign, orient ); +} + +void wxGrid::DrawTextRectangle( wxDC& dc, + const wxString& value, + const wxRect& rect, + int horizAlign, + int vertAlign, + int textOrientation ) +{ + wxArrayString lines; + + StringToLines( value, lines ); + + // Forward to new API. + DrawTextRectangle( dc, + lines, + rect, + horizAlign, + vertAlign, + textOrientation ); +} + +// VZ: this should be replaced with wxDC::DrawLabel() to which we just have to +// add textOrientation support +void wxGrid::DrawTextRectangle(wxDC& dc, + const wxArrayString& lines, + const wxRect& rect, + int horizAlign, + int vertAlign, + int textOrientation) +{ + if ( lines.empty() ) + return; + + wxDCClipper clip(dc, rect); + + long textWidth, + textHeight; + + if ( textOrientation == wxHORIZONTAL ) + GetTextBoxSize( dc, lines, &textWidth, &textHeight ); + else + GetTextBoxSize( dc, lines, &textHeight, &textWidth ); + + int x = 0, + y = 0; + switch ( vertAlign ) + { + case wxALIGN_BOTTOM: + if ( textOrientation == wxHORIZONTAL ) + y = rect.y + (rect.height - textHeight - 1); + else + x = rect.x + rect.width - textWidth; + break; + + case wxALIGN_CENTRE: + if ( textOrientation == wxHORIZONTAL ) + y = rect.y + ((rect.height - textHeight) / 2); + else + x = rect.x + ((rect.width - textWidth) / 2); + break; + + case wxALIGN_TOP: + default: + if ( textOrientation == wxHORIZONTAL ) + y = rect.y + 1; + else + x = rect.x + 1; + break; + } + + // Align each line of a multi-line label + size_t nLines = lines.GetCount(); + for ( size_t l = 0; l < nLines; l++ ) + { + const wxString& line = lines[l]; + + if ( line.empty() ) + { + *(textOrientation == wxHORIZONTAL ? &y : &x) += dc.GetCharHeight(); + continue; + } + + long lineWidth = 0, + lineHeight = 0; + dc.GetTextExtent(line, &lineWidth, &lineHeight); + + switch ( horizAlign ) + { + case wxALIGN_RIGHT: + if ( textOrientation == wxHORIZONTAL ) + x = rect.x + (rect.width - lineWidth - 1); + else + y = rect.y + lineWidth + 1; + break; + + case wxALIGN_CENTRE: + if ( textOrientation == wxHORIZONTAL ) + x = rect.x + ((rect.width - lineWidth) / 2); + else + y = rect.y + rect.height - ((rect.height - lineWidth) / 2); + break; + + case wxALIGN_LEFT: + default: + if ( textOrientation == wxHORIZONTAL ) + x = rect.x + 1; + else + y = rect.y + rect.height - 1; + break; + } + + if ( textOrientation == wxHORIZONTAL ) + { + dc.DrawText( line, x, y ); + y += lineHeight; + } + else + { + dc.DrawRotatedText( line, x, y, 90.0 ); + x += lineHeight; + } + } +} + +// Split multi-line text up into an array of strings. +// Any existing contents of the string array are preserved. +// +void wxGrid::StringToLines( const wxString& value, wxArrayString& lines ) +{ + int startPos = 0; + int pos; + wxString eol = wxTextFile::GetEOL( wxTextFileType_Unix ); + wxString tVal = wxTextFile::Translate( value, wxTextFileType_Unix ); + + while ( startPos < (int)tVal.length() ) + { + pos = tVal.Mid(startPos).Find( eol ); + if ( pos < 0 ) + { + break; + } + else if ( pos == 0 ) + { + lines.Add( wxEmptyString ); + } + else + { + lines.Add( tVal.Mid(startPos, pos) ); + } + + startPos += pos + 1; + } + + if ( startPos < (int)tVal.length() ) + { + lines.Add( tVal.Mid( startPos ) ); + } +} + +void wxGrid::GetTextBoxSize( const wxDC& dc, + const wxArrayString& lines, + long *width, long *height ) +{ + long w = 0; + long h = 0; + long lineW = 0, lineH = 0; + + size_t i; + for ( i = 0; i < lines.GetCount(); i++ ) + { + dc.GetTextExtent( lines[i], &lineW, &lineH ); + w = wxMax( w, lineW ); + h += lineH; + } + + *width = w; + *height = h; +} + +// +// ------ Batch processing. +// +void wxGrid::EndBatch() +{ + if ( m_batchCount > 0 ) + { + m_batchCount--; + if ( !m_batchCount ) + { + CalcDimensions(); + m_rowLabelWin->Refresh(); + m_colLabelWin->Refresh(); + m_cornerLabelWin->Refresh(); + m_gridWin->Refresh(); + } + } +} + +// Use this, rather than wxWindow::Refresh(), to force an immediate +// repainting of the grid. Has no effect if you are already inside a +// BeginBatch / EndBatch block. +// +void wxGrid::ForceRefresh() +{ + BeginBatch(); + EndBatch(); +} + +bool wxGrid::Enable(bool enable) +{ + if ( !wxScrolledWindow::Enable(enable) ) + return false; + + // redraw in the new state + m_gridWin->Refresh(); + + return true; +} + +// +// ------ Edit control functions +// + +void wxGrid::EnableEditing( bool edit ) +{ + // TODO: improve this ? + // + if ( edit != m_editable ) + { + if (!edit) + EnableCellEditControl(edit); + m_editable = edit; + } +} + +void wxGrid::EnableCellEditControl( bool enable ) +{ + if (! m_editable) + return; + + if ( enable != m_cellEditCtrlEnabled ) + { + if ( enable ) + { + if (SendEvent( wxEVT_GRID_EDITOR_SHOWN) <0) + return; + + // this should be checked by the caller! + wxASSERT_MSG( CanEnableCellControl(), _T("can't enable editing for this cell!") ); + + // do it before ShowCellEditControl() + m_cellEditCtrlEnabled = enable; + + ShowCellEditControl(); + } + else + { + //FIXME:add veto support + SendEvent( wxEVT_GRID_EDITOR_HIDDEN ); + + HideCellEditControl(); + SaveEditControlValue(); + + // do it after HideCellEditControl() + m_cellEditCtrlEnabled = enable; + } + } +} + +bool wxGrid::IsCurrentCellReadOnly() const +{ + // const_cast + wxGridCellAttr* attr = ((wxGrid *)this)->GetCellAttr(m_currentCellCoords); + bool readonly = attr->IsReadOnly(); + attr->DecRef(); + + return readonly; +} + +bool wxGrid::CanEnableCellControl() const +{ + return m_editable && (m_currentCellCoords != wxGridNoCellCoords) && + !IsCurrentCellReadOnly(); +} + +bool wxGrid::IsCellEditControlEnabled() const +{ + // the cell edit control might be disable for all cells or just for the + // current one if it's read only + return m_cellEditCtrlEnabled ? !IsCurrentCellReadOnly() : false; +} + +bool wxGrid::IsCellEditControlShown() const +{ + bool isShown = false; + + if ( m_cellEditCtrlEnabled ) + { + int row = m_currentCellCoords.GetRow(); + int col = m_currentCellCoords.GetCol(); + wxGridCellAttr* attr = GetCellAttr(row, col); + wxGridCellEditor* editor = attr->GetEditor((wxGrid*) this, row, col); + attr->DecRef(); + + if ( editor ) + { + if ( editor->IsCreated() ) + { + isShown = editor->GetControl()->IsShown(); + } + + editor->DecRef(); + } + } + + return isShown; +} + +void wxGrid::ShowCellEditControl() +{ + if ( IsCellEditControlEnabled() ) + { + if ( !IsVisible( m_currentCellCoords, false ) ) + { + m_cellEditCtrlEnabled = false; + return; + } + else + { + wxRect rect = CellToRect( m_currentCellCoords ); + int row = m_currentCellCoords.GetRow(); + int col = m_currentCellCoords.GetCol(); + + // if this is part of a multicell, find owner (topleft) + int cell_rows, cell_cols; + GetCellSize( row, col, &cell_rows, &cell_cols ); + if ( cell_rows <= 0 || cell_cols <= 0 ) + { + row += cell_rows; + col += cell_cols; + m_currentCellCoords.SetRow( row ); + m_currentCellCoords.SetCol( col ); + } + + // erase the highlight and the cell contents because the editor + // might not cover the entire cell + wxClientDC dc( m_gridWin ); + PrepareDC( dc ); + wxGridCellAttr* attr = GetCellAttr(row, col); + dc.SetBrush(wxBrush(attr->GetBackgroundColour(), wxSOLID)); + dc.SetPen(*wxTRANSPARENT_PEN); + dc.DrawRectangle(rect); + + // convert to scrolled coords + CalcScrolledPosition( rect.x, rect.y, &rect.x, &rect.y ); + + int nXMove = 0; + if (rect.x < 0) + nXMove = rect.x; + + // cell is shifted by one pixel + // However, don't allow x or y to become negative + // since the SetSize() method interprets that as + // "don't change." + if (rect.x > 0) + rect.x--; + if (rect.y > 0) + rect.y--; + + wxGridCellEditor* editor = attr->GetEditor(this, row, col); + if ( !editor->IsCreated() ) + { + editor->Create(m_gridWin, wxID_ANY, + new wxGridCellEditorEvtHandler(this, editor)); + + wxGridEditorCreatedEvent evt(GetId(), + wxEVT_GRID_EDITOR_CREATED, + this, + row, + col, + editor->GetControl()); + GetEventHandler()->ProcessEvent(evt); + } + + // resize editor to overflow into righthand cells if allowed + int maxWidth = rect.width; + wxString value = GetCellValue(row, col); + if ( (value != wxEmptyString) && (attr->GetOverflow()) ) + { + int y; + GetTextExtent(value, &maxWidth, &y, NULL, NULL, &attr->GetFont()); + if (maxWidth < rect.width) + maxWidth = rect.width; + } + + int client_right = m_gridWin->GetClientSize().GetWidth(); + if (rect.x + maxWidth > client_right) + maxWidth = client_right - rect.x; + + if ((maxWidth > rect.width) && (col < m_numCols) && m_table) + { + GetCellSize( row, col, &cell_rows, &cell_cols ); + // may have changed earlier + for (int i = col + cell_cols; i < m_numCols; i++) + { + int c_rows, c_cols; + GetCellSize( row, i, &c_rows, &c_cols ); + + // looks weird going over a multicell + if (m_table->IsEmptyCell( row, i ) && + (rect.width < maxWidth) && (c_rows == 1)) + { + rect.width += GetColWidth( i ); + } + else + break; + } + + if (rect.GetRight() > client_right) + rect.SetRight( client_right - 1 ); + } + + editor->SetCellAttr( attr ); + editor->SetSize( rect ); + if (nXMove != 0) + editor->GetControl()->Move( + editor->GetControl()->GetPosition().x + nXMove, + editor->GetControl()->GetPosition().y ); + editor->Show( true, attr ); + + // recalc dimensions in case we need to + // expand the scrolled window to account for editor + CalcDimensions(); + + editor->BeginEdit(row, col, this); + editor->SetCellAttr(NULL); + + editor->DecRef(); + attr->DecRef(); + } + } +} + +void wxGrid::HideCellEditControl() +{ + if ( IsCellEditControlEnabled() ) + { + int row = m_currentCellCoords.GetRow(); + int col = m_currentCellCoords.GetCol(); + + wxGridCellAttr *attr = GetCellAttr(row, col); + wxGridCellEditor *editor = attr->GetEditor(this, row, col); + editor->Show( false ); + editor->DecRef(); + attr->DecRef(); + + m_gridWin->SetFocus(); + + // refresh whole row to the right + wxRect rect( CellToRect(row, col) ); + CalcScrolledPosition(rect.x, rect.y, &rect.x, &rect.y ); + rect.width = m_gridWin->GetClientSize().GetWidth() - rect.x; + +#ifdef __WXMAC__ + // ensure that the pixels under the focus ring get refreshed as well + rect.Inflate(10, 10); +#endif + + m_gridWin->Refresh( false, &rect ); + } +} + +void wxGrid::SaveEditControlValue() +{ + if ( IsCellEditControlEnabled() ) + { + int row = m_currentCellCoords.GetRow(); + int col = m_currentCellCoords.GetCol(); + + wxString oldval = GetCellValue(row, col); + + wxGridCellAttr* attr = GetCellAttr(row, col); + wxGridCellEditor* editor = attr->GetEditor(this, row, col); + bool changed = editor->EndEdit(row, col, this); + + editor->DecRef(); + attr->DecRef(); + + if (changed) + { + if ( SendEvent( wxEVT_GRID_CELL_CHANGE, + m_currentCellCoords.GetRow(), + m_currentCellCoords.GetCol() ) < 0 ) + { + // Event has been vetoed, set the data back. + SetCellValue(row, col, oldval); + } + } + } +} + +// +// ------ Grid location functions +// Note that all of these functions work with the logical coordinates of +// grid cells and labels so you will need to convert from device +// coordinates for mouse events etc. +// + +void wxGrid::XYToCell( int x, int y, wxGridCellCoords& coords ) +{ + int row = YToRow(y); + int col = XToCol(x); + + if ( row == -1 || col == -1 ) + { + coords = wxGridNoCellCoords; + } + else + { + coords.Set( row, col ); + } +} + +// Internal Helper function for computing row or column from some +// (unscrolled) coordinate value, using either +// m_defaultRowHeight/m_defaultColWidth or binary search on array +// of m_rowBottoms/m_ColRights to speed up the search! + +static int CoordToRowOrCol(int coord, int defaultDist, int minDist, + const wxArrayInt& BorderArray, int nMax, + bool clipToMinMax) +{ + if (coord < 0) + return clipToMinMax && (nMax > 0) ? 0 : -1; + + if (!defaultDist) + defaultDist = 1; + + size_t i_max = coord / defaultDist, + i_min = 0; + + if (BorderArray.IsEmpty()) + { + if ((int) i_max < nMax) + return i_max; + return clipToMinMax ? nMax - 1 : -1; + } + + if ( i_max >= BorderArray.GetCount()) + { + i_max = BorderArray.GetCount() - 1; + } + else + { + if ( coord >= BorderArray[i_max]) + { + i_min = i_max; + if (minDist) + i_max = coord / minDist; + else + i_max = BorderArray.GetCount() - 1; + } + + if ( i_max >= BorderArray.GetCount()) + i_max = BorderArray.GetCount() - 1; + } + + if ( coord >= BorderArray[i_max]) + return clipToMinMax ? (int)i_max : -1; + if ( coord < BorderArray[0] ) + return 0; + + while ( i_max - i_min > 0 ) + { + wxCHECK_MSG(BorderArray[i_min] <= coord && coord < BorderArray[i_max], + 0, _T("wxGrid: internal error in CoordToRowOrCol")); + if (coord >= BorderArray[ i_max - 1]) + return i_max; + else + i_max--; + int median = i_min + (i_max - i_min + 1) / 2; + if (coord < BorderArray[median]) + i_max = median; + else + i_min = median; + } + + return i_max; +} + +int wxGrid::YToRow( int y ) +{ + return CoordToRowOrCol(y, m_defaultRowHeight, + m_minAcceptableRowHeight, m_rowBottoms, m_numRows, false); +} + +int wxGrid::XToCol( int x, bool clipToMinMax ) +{ + if (x < 0) + return clipToMinMax && (m_numCols > 0) ? GetColAt( 0 ) : -1; + + if (!m_defaultColWidth) + m_defaultColWidth = 1; + + int maxPos = x / m_defaultColWidth; + int minPos = 0; + + if (m_colRights.IsEmpty()) + { + if(maxPos < m_numCols) + return GetColAt( maxPos ); + return clipToMinMax ? GetColAt( m_numCols - 1 ) : -1; + } + + if ( maxPos >= m_numCols) + maxPos = m_numCols - 1; + else + { + if ( x >= m_colRights[GetColAt( maxPos )]) + { + minPos = maxPos; + if (m_minAcceptableColWidth) + maxPos = x / m_minAcceptableColWidth; + else + maxPos = m_numCols - 1; + } + if ( maxPos >= m_numCols) + maxPos = m_numCols - 1; + } + + //X is beyond the last column + if ( x >= m_colRights[GetColAt( maxPos )]) + return clipToMinMax ? GetColAt( maxPos ) : -1; + + //X is before the first column + if ( x < m_colRights[GetColAt( 0 )] ) + return GetColAt( 0 ); + + //Perform a binary search + while ( maxPos - minPos > 0 ) + { + wxCHECK_MSG(m_colRights[GetColAt( minPos )] <= x && x < m_colRights[GetColAt( maxPos )], + 0, _T("wxGrid: internal error in XToCol")); + + if (x >= m_colRights[GetColAt( maxPos - 1 )]) + return GetColAt( maxPos ); + else + maxPos--; + int median = minPos + (maxPos - minPos + 1) / 2; + if (x < m_colRights[GetColAt( median )]) + maxPos = median; + else + minPos = median; + } + return GetColAt( maxPos ); +} + +// return the row number that that the y coord is near +// the edge of, or -1 if not near an edge. +// coords can only possibly be near an edge if +// (a) the row/column is large enough to still allow for an "inner" area +// that is _not_ nead the edge (i.e., if the height/width is smaller +// than WXGRID_LABEL_EDGE_ZONE, coords are _never_ considered to be +// near the edge). +// and +// (b) resizing rows/columns (the thing for which edge detection is +// relevant at all) is enabled. +// +int wxGrid::YToEdgeOfRow( int y ) +{ + int i; + i = internalYToRow(y); + + if ( GetRowHeight(i) > WXGRID_LABEL_EDGE_ZONE && CanDragRowSize() ) + { + // We know that we are in row i, test whether we are + // close enough to lower or upper border, respectively. + if ( abs(GetRowBottom(i) - y) < WXGRID_LABEL_EDGE_ZONE ) + return i; + else if ( i > 0 && y - GetRowTop(i) < WXGRID_LABEL_EDGE_ZONE ) + return i - 1; + } + + return -1; +} + +// return the col number that that the x coord is near the edge of, or +// -1 if not near an edge +// See comment at YToEdgeOfRow for conditions on edge detection. +// +int wxGrid::XToEdgeOfCol( int x ) +{ + int i; + i = internalXToCol(x); + + if ( GetColWidth(i) > WXGRID_LABEL_EDGE_ZONE && CanDragColSize() ) + { + // We know that we are in column i; test whether we are + // close enough to right or left border, respectively. + if ( abs(GetColRight(i) - x) < WXGRID_LABEL_EDGE_ZONE ) + return i; + else if ( i > 0 && x - GetColLeft(i) < WXGRID_LABEL_EDGE_ZONE ) + return i - 1; + } + + return -1; +} + +wxRect wxGrid::CellToRect( int row, int col ) +{ + wxRect rect( -1, -1, -1, -1 ); + + if ( row >= 0 && row < m_numRows && + col >= 0 && col < m_numCols ) + { + int i, cell_rows, cell_cols; + rect.width = rect.height = 0; + GetCellSize( row, col, &cell_rows, &cell_cols ); + // if negative then find multicell owner + if (cell_rows < 0) + row += cell_rows; + if (cell_cols < 0) + col += cell_cols; + GetCellSize( row, col, &cell_rows, &cell_cols ); + + rect.x = GetColLeft(col); + rect.y = GetRowTop(row); + for (i=col; i < col + cell_cols; i++) + rect.width += GetColWidth(i); + for (i=row; i < row + cell_rows; i++) + rect.height += GetRowHeight(i); + } + + // if grid lines are enabled, then the area of the cell is a bit smaller + if (m_gridLinesEnabled) + { + rect.width -= 1; + rect.height -= 1; + } + + return rect; +} + +bool wxGrid::IsVisible( int row, int col, bool wholeCellVisible ) +{ + // get the cell rectangle in logical coords + // + wxRect r( CellToRect( row, col ) ); + + // convert to device coords + // + int left, top, right, bottom; + CalcScrolledPosition( r.GetLeft(), r.GetTop(), &left, &top ); + CalcScrolledPosition( r.GetRight(), r.GetBottom(), &right, &bottom ); + + // check against the client area of the grid window + int cw, ch; + m_gridWin->GetClientSize( &cw, &ch ); + + if ( wholeCellVisible ) + { + // is the cell wholly visible ? + return ( left >= 0 && right <= cw && + top >= 0 && bottom <= ch ); + } + else + { + // is the cell partly visible ? + // + return ( ((left >= 0 && left < cw) || (right > 0 && right <= cw)) && + ((top >= 0 && top < ch) || (bottom > 0 && bottom <= ch)) ); + } +} + +// make the specified cell location visible by doing a minimal amount +// of scrolling +// +void wxGrid::MakeCellVisible( int row, int col ) +{ + int i; + int xpos = -1, ypos = -1; + + if ( row >= 0 && row < m_numRows && + col >= 0 && col < m_numCols ) + { + // get the cell rectangle in logical coords + wxRect r( CellToRect( row, col ) ); + + // convert to device coords + int left, top, right, bottom; + CalcScrolledPosition( r.GetLeft(), r.GetTop(), &left, &top ); + CalcScrolledPosition( r.GetRight(), r.GetBottom(), &right, &bottom ); + + int cw, ch; + m_gridWin->GetClientSize( &cw, &ch ); + + if ( top < 0 ) + { + ypos = r.GetTop(); + } + else if ( bottom > ch ) + { + int h = r.GetHeight(); + ypos = r.GetTop(); + for ( i = row - 1; i >= 0; i-- ) + { + int rowHeight = GetRowHeight(i); + if ( h + rowHeight > ch ) + break; + + h += rowHeight; + ypos -= rowHeight; + } + + // we divide it later by GRID_SCROLL_LINE, make sure that we don't + // have rounding errors (this is important, because if we do, + // we might not scroll at all and some cells won't be redrawn) + // + // Sometimes GRID_SCROLL_LINE / 2 is not enough, + // so just add a full scroll unit... + ypos += m_scrollLineY; + } + + // special handling for wide cells - show always left part of the cell! + // Otherwise, e.g. when stepping from row to row, it would jump between + // left and right part of the cell on every step! +// if ( left < 0 ) + if ( left < 0 || (right - left) >= cw ) + { + xpos = r.GetLeft(); + } + else if ( right > cw ) + { + // position the view so that the cell is on the right + int x0, y0; + CalcUnscrolledPosition(0, 0, &x0, &y0); + xpos = x0 + (right - cw); + + // see comment for ypos above + xpos += m_scrollLineX; + } + + if ( xpos != -1 || ypos != -1 ) + { + if ( xpos != -1 ) + xpos /= m_scrollLineX; + if ( ypos != -1 ) + ypos /= m_scrollLineY; + Scroll( xpos, ypos ); + AdjustScrollbars(); + } + } +} + +// +// ------ Grid cursor movement functions +// + +bool wxGrid::MoveCursorUp( bool expandSelection ) +{ + if ( m_currentCellCoords != wxGridNoCellCoords && + m_currentCellCoords.GetRow() >= 0 ) + { + if ( expandSelection ) + { + if ( m_selectingKeyboard == wxGridNoCellCoords ) + m_selectingKeyboard = m_currentCellCoords; + if ( m_selectingKeyboard.GetRow() > 0 ) + { + m_selectingKeyboard.SetRow( m_selectingKeyboard.GetRow() - 1 ); + MakeCellVisible( m_selectingKeyboard.GetRow(), + m_selectingKeyboard.GetCol() ); + HighlightBlock( m_currentCellCoords, m_selectingKeyboard ); + } + } + else if ( m_currentCellCoords.GetRow() > 0 ) + { + int row = m_currentCellCoords.GetRow() - 1; + int col = m_currentCellCoords.GetCol(); + ClearSelection(); + MakeCellVisible( row, col ); + SetCurrentCell( row, col ); + } + else + return false; + + return true; + } + + return false; +} + +bool wxGrid::MoveCursorDown( bool expandSelection ) +{ + if ( m_currentCellCoords != wxGridNoCellCoords && + m_currentCellCoords.GetRow() < m_numRows ) + { + if ( expandSelection ) + { + if ( m_selectingKeyboard == wxGridNoCellCoords ) + m_selectingKeyboard = m_currentCellCoords; + if ( m_selectingKeyboard.GetRow() < m_numRows - 1 ) + { + m_selectingKeyboard.SetRow( m_selectingKeyboard.GetRow() + 1 ); + MakeCellVisible( m_selectingKeyboard.GetRow(), + m_selectingKeyboard.GetCol() ); + HighlightBlock( m_currentCellCoords, m_selectingKeyboard ); + } + } + else if ( m_currentCellCoords.GetRow() < m_numRows - 1 ) + { + int row = m_currentCellCoords.GetRow() + 1; + int col = m_currentCellCoords.GetCol(); + ClearSelection(); + MakeCellVisible( row, col ); + SetCurrentCell( row, col ); + } + else + return false; + + return true; + } + + return false; +} + +bool wxGrid::MoveCursorLeft( bool expandSelection ) +{ + if ( m_currentCellCoords != wxGridNoCellCoords && + m_currentCellCoords.GetCol() >= 0 ) + { + if ( expandSelection ) + { + if ( m_selectingKeyboard == wxGridNoCellCoords ) + m_selectingKeyboard = m_currentCellCoords; + if ( m_selectingKeyboard.GetCol() > 0 ) + { + m_selectingKeyboard.SetCol( m_selectingKeyboard.GetCol() - 1 ); + MakeCellVisible( m_selectingKeyboard.GetRow(), + m_selectingKeyboard.GetCol() ); + HighlightBlock( m_currentCellCoords, m_selectingKeyboard ); + } + } + else if ( GetColPos( m_currentCellCoords.GetCol() ) > 0 ) + { + int row = m_currentCellCoords.GetRow(); + int col = GetColAt( GetColPos( m_currentCellCoords.GetCol() ) - 1 ); + ClearSelection(); + + MakeCellVisible( row, col ); + SetCurrentCell( row, col ); + } + else + return false; + + return true; + } + + return false; +} + +bool wxGrid::MoveCursorRight( bool expandSelection ) +{ + if ( m_currentCellCoords != wxGridNoCellCoords && + m_currentCellCoords.GetCol() < m_numCols ) + { + if ( expandSelection ) + { + if ( m_selectingKeyboard == wxGridNoCellCoords ) + m_selectingKeyboard = m_currentCellCoords; + if ( m_selectingKeyboard.GetCol() < m_numCols - 1 ) + { + m_selectingKeyboard.SetCol( m_selectingKeyboard.GetCol() + 1 ); + MakeCellVisible( m_selectingKeyboard.GetRow(), + m_selectingKeyboard.GetCol() ); + HighlightBlock( m_currentCellCoords, m_selectingKeyboard ); + } + } + else if ( GetColPos( m_currentCellCoords.GetCol() ) < m_numCols - 1 ) + { + int row = m_currentCellCoords.GetRow(); + int col = GetColAt( GetColPos( m_currentCellCoords.GetCol() ) + 1 ); + ClearSelection(); + + MakeCellVisible( row, col ); + SetCurrentCell( row, col ); + } + else + return false; + + return true; + } + + return false; +} + +bool wxGrid::MovePageUp() +{ + if ( m_currentCellCoords == wxGridNoCellCoords ) + return false; + + int row = m_currentCellCoords.GetRow(); + if ( row > 0 ) + { + int cw, ch; + m_gridWin->GetClientSize( &cw, &ch ); + + int y = GetRowTop(row); + int newRow = internalYToRow( y - ch + 1 ); + + if ( newRow == row ) + { + // row > 0, so newRow can never be less than 0 here. + newRow = row - 1; + } + + MakeCellVisible( newRow, m_currentCellCoords.GetCol() ); + SetCurrentCell( newRow, m_currentCellCoords.GetCol() ); + + return true; + } + + return false; +} + +bool wxGrid::MovePageDown() +{ + if ( m_currentCellCoords == wxGridNoCellCoords ) + return false; + + int row = m_currentCellCoords.GetRow(); + if ( (row + 1) < m_numRows ) + { + int cw, ch; + m_gridWin->GetClientSize( &cw, &ch ); + + int y = GetRowTop(row); + int newRow = internalYToRow( y + ch ); + if ( newRow == row ) + { + // row < m_numRows, so newRow can't overflow here. + newRow = row + 1; + } + + MakeCellVisible( newRow, m_currentCellCoords.GetCol() ); + SetCurrentCell( newRow, m_currentCellCoords.GetCol() ); + + return true; + } + + return false; +} + +bool wxGrid::MoveCursorUpBlock( bool expandSelection ) +{ + if ( m_table && + m_currentCellCoords != wxGridNoCellCoords && + m_currentCellCoords.GetRow() > 0 ) + { + int row = m_currentCellCoords.GetRow(); + int col = m_currentCellCoords.GetCol(); + + if ( m_table->IsEmptyCell(row, col) ) + { + // starting in an empty cell: find the next block of + // non-empty cells + // + while ( row > 0 ) + { + row--; + if ( !(m_table->IsEmptyCell(row, col)) ) + break; + } + } + else if ( m_table->IsEmptyCell(row - 1, col) ) + { + // starting at the top of a block: find the next block + // + row--; + while ( row > 0 ) + { + row--; + if ( !(m_table->IsEmptyCell(row, col)) ) + break; + } + } + else + { + // starting within a block: find the top of the block + // + while ( row > 0 ) + { + row--; + if ( m_table->IsEmptyCell(row, col) ) + { + row++; + break; + } + } + } + + MakeCellVisible( row, col ); + if ( expandSelection ) + { + m_selectingKeyboard = wxGridCellCoords( row, col ); + HighlightBlock( m_currentCellCoords, m_selectingKeyboard ); + } + else + { + ClearSelection(); + SetCurrentCell( row, col ); + } + + return true; + } + + return false; +} + +bool wxGrid::MoveCursorDownBlock( bool expandSelection ) +{ + if ( m_table && + m_currentCellCoords != wxGridNoCellCoords && + m_currentCellCoords.GetRow() < m_numRows - 1 ) + { + int row = m_currentCellCoords.GetRow(); + int col = m_currentCellCoords.GetCol(); + + if ( m_table->IsEmptyCell(row, col) ) + { + // starting in an empty cell: find the next block of + // non-empty cells + // + while ( row < m_numRows - 1 ) + { + row++; + if ( !(m_table->IsEmptyCell(row, col)) ) + break; + } + } + else if ( m_table->IsEmptyCell(row + 1, col) ) + { + // starting at the bottom of a block: find the next block + // + row++; + while ( row < m_numRows - 1 ) + { + row++; + if ( !(m_table->IsEmptyCell(row, col)) ) + break; + } + } + else + { + // starting within a block: find the bottom of the block + // + while ( row < m_numRows - 1 ) + { + row++; + if ( m_table->IsEmptyCell(row, col) ) + { + row--; + break; + } + } + } + + MakeCellVisible( row, col ); + if ( expandSelection ) + { + m_selectingKeyboard = wxGridCellCoords( row, col ); + HighlightBlock( m_currentCellCoords, m_selectingKeyboard ); + } + else + { + ClearSelection(); + SetCurrentCell( row, col ); + } + + return true; + } + + return false; +} + +bool wxGrid::MoveCursorLeftBlock( bool expandSelection ) +{ + if ( m_table && + m_currentCellCoords != wxGridNoCellCoords && + m_currentCellCoords.GetCol() > 0 ) + { + int row = m_currentCellCoords.GetRow(); + int col = m_currentCellCoords.GetCol(); + + if ( m_table->IsEmptyCell(row, col) ) + { + // starting in an empty cell: find the next block of + // non-empty cells + // + while ( col > 0 ) + { + col--; + if ( !(m_table->IsEmptyCell(row, col)) ) + break; + } + } + else if ( m_table->IsEmptyCell(row, col - 1) ) + { + // starting at the left of a block: find the next block + // + col--; + while ( col > 0 ) + { + col--; + if ( !(m_table->IsEmptyCell(row, col)) ) + break; + } + } + else + { + // starting within a block: find the left of the block + // + while ( col > 0 ) + { + col--; + if ( m_table->IsEmptyCell(row, col) ) + { + col++; + break; + } + } + } + + MakeCellVisible( row, col ); + if ( expandSelection ) + { + m_selectingKeyboard = wxGridCellCoords( row, col ); + HighlightBlock( m_currentCellCoords, m_selectingKeyboard ); + } + else + { + ClearSelection(); + SetCurrentCell( row, col ); + } + + return true; + } + + return false; +} + +bool wxGrid::MoveCursorRightBlock( bool expandSelection ) +{ + if ( m_table && + m_currentCellCoords != wxGridNoCellCoords && + m_currentCellCoords.GetCol() < m_numCols - 1 ) + { + int row = m_currentCellCoords.GetRow(); + int col = m_currentCellCoords.GetCol(); + + if ( m_table->IsEmptyCell(row, col) ) + { + // starting in an empty cell: find the next block of + // non-empty cells + // + while ( col < m_numCols - 1 ) + { + col++; + if ( !(m_table->IsEmptyCell(row, col)) ) + break; + } + } + else if ( m_table->IsEmptyCell(row, col + 1) ) + { + // starting at the right of a block: find the next block + // + col++; + while ( col < m_numCols - 1 ) + { + col++; + if ( !(m_table->IsEmptyCell(row, col)) ) + break; + } + } + else + { + // starting within a block: find the right of the block + // + while ( col < m_numCols - 1 ) + { + col++; + if ( m_table->IsEmptyCell(row, col) ) + { + col--; + break; + } + } + } + + MakeCellVisible( row, col ); + if ( expandSelection ) + { + m_selectingKeyboard = wxGridCellCoords( row, col ); + HighlightBlock( m_currentCellCoords, m_selectingKeyboard ); + } + else + { + ClearSelection(); + SetCurrentCell( row, col ); + } + + return true; + } + + return false; +} + +// +// ------ Label values and formatting +// + +void wxGrid::GetRowLabelAlignment( int *horiz, int *vert ) +{ + if ( horiz ) + *horiz = m_rowLabelHorizAlign; + if ( vert ) + *vert = m_rowLabelVertAlign; +} + +void wxGrid::GetColLabelAlignment( int *horiz, int *vert ) +{ + if ( horiz ) + *horiz = m_colLabelHorizAlign; + if ( vert ) + *vert = m_colLabelVertAlign; +} + +int wxGrid::GetColLabelTextOrientation() +{ + return m_colLabelTextOrientation; +} + +wxString wxGrid::GetRowLabelValue( int row ) +{ + if ( m_table ) + { + return m_table->GetRowLabelValue( row ); + } + else + { + wxString s; + s << row; + return s; + } +} + +wxString wxGrid::GetColLabelValue( int col ) +{ + if ( m_table ) + { + return m_table->GetColLabelValue( col ); + } + else + { + wxString s; + s << col; + return s; + } +} + +void wxGrid::SetRowLabelSize( int width ) +{ + wxASSERT( width >= 0 || width == wxGRID_AUTOSIZE ); + + if ( width == wxGRID_AUTOSIZE ) + { + width = CalcColOrRowLabelAreaMinSize(false/*row*/); + } + + if ( width != m_rowLabelWidth ) + { + if ( width == 0 ) + { + m_rowLabelWin->Show( false ); + m_cornerLabelWin->Show( false ); + } + else if ( m_rowLabelWidth == 0 ) + { + m_rowLabelWin->Show( true ); + if ( m_colLabelHeight > 0 ) + m_cornerLabelWin->Show( true ); + } + + m_rowLabelWidth = width; + CalcWindowSizes(); + wxScrolledWindow::Refresh( true ); + } +} + +void wxGrid::SetColLabelSize( int height ) +{ + wxASSERT( height >=0 || height == wxGRID_AUTOSIZE ); + + if ( height == wxGRID_AUTOSIZE ) + { + height = CalcColOrRowLabelAreaMinSize(true/*column*/); + } + + if ( height != m_colLabelHeight ) + { + if ( height == 0 ) + { + m_colLabelWin->Show( false ); + m_cornerLabelWin->Show( false ); + } + else if ( m_colLabelHeight == 0 ) + { + m_colLabelWin->Show( true ); + if ( m_rowLabelWidth > 0 ) + m_cornerLabelWin->Show( true ); + } + + m_colLabelHeight = height; + CalcWindowSizes(); + wxScrolledWindow::Refresh( true ); + } +} + +void wxGrid::SetLabelBackgroundColour( const wxColour& colour ) +{ + if ( m_labelBackgroundColour != colour ) + { + m_labelBackgroundColour = colour; + m_rowLabelWin->SetBackgroundColour( colour ); + m_colLabelWin->SetBackgroundColour( colour ); + m_cornerLabelWin->SetBackgroundColour( colour ); + + if ( !GetBatchCount() ) + { + m_rowLabelWin->Refresh(); + m_colLabelWin->Refresh(); + m_cornerLabelWin->Refresh(); + } + } +} + +void wxGrid::SetLabelTextColour( const wxColour& colour ) +{ + if ( m_labelTextColour != colour ) + { + m_labelTextColour = colour; + if ( !GetBatchCount() ) + { + m_rowLabelWin->Refresh(); + m_colLabelWin->Refresh(); + } + } +} + +void wxGrid::SetLabelFont( const wxFont& font ) +{ + m_labelFont = font; + if ( !GetBatchCount() ) + { + m_rowLabelWin->Refresh(); + m_colLabelWin->Refresh(); + } +} + +void wxGrid::SetRowLabelAlignment( int horiz, int vert ) +{ + // allow old (incorrect) defs to be used + switch ( horiz ) + { + case wxLEFT: horiz = wxALIGN_LEFT; break; + case wxRIGHT: horiz = wxALIGN_RIGHT; break; + case wxCENTRE: horiz = wxALIGN_CENTRE; break; + } + + switch ( vert ) + { + case wxTOP: vert = wxALIGN_TOP; break; + case wxBOTTOM: vert = wxALIGN_BOTTOM; break; + case wxCENTRE: vert = wxALIGN_CENTRE; break; + } + + if ( horiz == wxALIGN_LEFT || horiz == wxALIGN_CENTRE || horiz == wxALIGN_RIGHT ) + { + m_rowLabelHorizAlign = horiz; + } + + if ( vert == wxALIGN_TOP || vert == wxALIGN_CENTRE || vert == wxALIGN_BOTTOM ) + { + m_rowLabelVertAlign = vert; + } + + if ( !GetBatchCount() ) + { + m_rowLabelWin->Refresh(); + } +} + +void wxGrid::SetColLabelAlignment( int horiz, int vert ) +{ + // allow old (incorrect) defs to be used + switch ( horiz ) + { + case wxLEFT: horiz = wxALIGN_LEFT; break; + case wxRIGHT: horiz = wxALIGN_RIGHT; break; + case wxCENTRE: horiz = wxALIGN_CENTRE; break; + } + + switch ( vert ) + { + case wxTOP: vert = wxALIGN_TOP; break; + case wxBOTTOM: vert = wxALIGN_BOTTOM; break; + case wxCENTRE: vert = wxALIGN_CENTRE; break; + } + + if ( horiz == wxALIGN_LEFT || horiz == wxALIGN_CENTRE || horiz == wxALIGN_RIGHT ) + { + m_colLabelHorizAlign = horiz; + } + + if ( vert == wxALIGN_TOP || vert == wxALIGN_CENTRE || vert == wxALIGN_BOTTOM ) + { + m_colLabelVertAlign = vert; + } + + if ( !GetBatchCount() ) + { + m_colLabelWin->Refresh(); + } +} + +// Note: under MSW, the default column label font must be changed because it +// does not support vertical printing +// +// Example: wxFont font(9, wxSWISS, wxNORMAL, wxBOLD); +// pGrid->SetLabelFont(font); +// pGrid->SetColLabelTextOrientation(wxVERTICAL); +// +void wxGrid::SetColLabelTextOrientation( int textOrientation ) +{ + if ( textOrientation == wxHORIZONTAL || textOrientation == wxVERTICAL ) + m_colLabelTextOrientation = textOrientation; + + if ( !GetBatchCount() ) + m_colLabelWin->Refresh(); +} + +void wxGrid::SetRowLabelValue( int row, const wxString& s ) +{ + if ( m_table ) + { + m_table->SetRowLabelValue( row, s ); + if ( !GetBatchCount() ) + { + wxRect rect = CellToRect( row, 0 ); + if ( rect.height > 0 ) + { + CalcScrolledPosition(0, rect.y, &rect.x, &rect.y); + rect.x = 0; + rect.width = m_rowLabelWidth; + m_rowLabelWin->Refresh( true, &rect ); + } + } + } +} + +void wxGrid::SetColLabelValue( int col, const wxString& s ) +{ + if ( m_table ) + { + m_table->SetColLabelValue( col, s ); + if ( !GetBatchCount() ) + { + wxRect rect = CellToRect( 0, col ); + if ( rect.width > 0 ) + { + CalcScrolledPosition(rect.x, 0, &rect.x, &rect.y); + rect.y = 0; + rect.height = m_colLabelHeight; + m_colLabelWin->Refresh( true, &rect ); + } + } + } +} + +void wxGrid::SetGridLineColour( const wxColour& colour ) +{ + if ( m_gridLineColour != colour ) + { + m_gridLineColour = colour; + + wxClientDC dc( m_gridWin ); + PrepareDC( dc ); + DrawAllGridLines( dc, wxRegion() ); + } +} + +void wxGrid::SetCellHighlightColour( const wxColour& colour ) +{ + if ( m_cellHighlightColour != colour ) + { + m_cellHighlightColour = colour; + + wxClientDC dc( m_gridWin ); + PrepareDC( dc ); + wxGridCellAttr* attr = GetCellAttr(m_currentCellCoords); + DrawCellHighlight(dc, attr); + attr->DecRef(); + } +} + +void wxGrid::SetCellHighlightPenWidth(int width) +{ + if (m_cellHighlightPenWidth != width) + { + m_cellHighlightPenWidth = width; + + // Just redrawing the cell highlight is not enough since that won't + // make any visible change if the the thickness is getting smaller. + int row = m_currentCellCoords.GetRow(); + int col = m_currentCellCoords.GetCol(); + if ( row == -1 || col == -1 || GetColWidth(col) <= 0 || GetRowHeight(row) <= 0 ) + return; + + wxRect rect = CellToRect(row, col); + m_gridWin->Refresh(true, &rect); + } +} + +void wxGrid::SetCellHighlightROPenWidth(int width) +{ + if (m_cellHighlightROPenWidth != width) + { + m_cellHighlightROPenWidth = width; + + // Just redrawing the cell highlight is not enough since that won't + // make any visible change if the the thickness is getting smaller. + int row = m_currentCellCoords.GetRow(); + int col = m_currentCellCoords.GetCol(); + if ( row == -1 || col == -1 || + GetColWidth(col) <= 0 || GetRowHeight(row) <= 0 ) + return; + + wxRect rect = CellToRect(row, col); + m_gridWin->Refresh(true, &rect); + } +} + +void wxGrid::EnableGridLines( bool enable ) +{ + if ( enable != m_gridLinesEnabled ) + { + m_gridLinesEnabled = enable; + + if ( !GetBatchCount() ) + { + if ( enable ) + { + wxClientDC dc( m_gridWin ); + PrepareDC( dc ); + DrawAllGridLines( dc, wxRegion() ); + } + else + { + m_gridWin->Refresh(); + } + } + } +} + +int wxGrid::GetDefaultRowSize() +{ + return m_defaultRowHeight; +} + +int wxGrid::GetRowSize( int row ) +{ + wxCHECK_MSG( row >= 0 && row < m_numRows, 0, _T("invalid row index") ); + + return GetRowHeight(row); +} + +int wxGrid::GetDefaultColSize() +{ + return m_defaultColWidth; +} + +int wxGrid::GetColSize( int col ) +{ + wxCHECK_MSG( col >= 0 && col < m_numCols, 0, _T("invalid column index") ); + + return GetColWidth(col); +} + +// ============================================================================ +// access to the grid attributes: each of them has a default value in the grid +// itself and may be overidden on a per-cell basis +// ============================================================================ + +// ---------------------------------------------------------------------------- +// setting default attributes +// ---------------------------------------------------------------------------- + +void wxGrid::SetDefaultCellBackgroundColour( const wxColour& col ) +{ + m_defaultCellAttr->SetBackgroundColour(col); +#ifdef __WXGTK__ + m_gridWin->SetBackgroundColour(col); +#endif +} + +void wxGrid::SetDefaultCellTextColour( const wxColour& col ) +{ + m_defaultCellAttr->SetTextColour(col); +} + +void wxGrid::SetDefaultCellAlignment( int horiz, int vert ) +{ + m_defaultCellAttr->SetAlignment(horiz, vert); +} + +void wxGrid::SetDefaultCellOverflow( bool allow ) +{ + m_defaultCellAttr->SetOverflow(allow); +} + +void wxGrid::SetDefaultCellFont( const wxFont& font ) +{ + m_defaultCellAttr->SetFont(font); +} + +// For editors and renderers the type registry takes precedence over the +// default attr, so we need to register the new editor/renderer for the string +// data type in order to make setting a default editor/renderer appear to +// work correctly. + +void wxGrid::SetDefaultRenderer(wxGridCellRenderer *renderer) +{ + RegisterDataType(wxGRID_VALUE_STRING, + renderer, + GetDefaultEditorForType(wxGRID_VALUE_STRING)); +} + +void wxGrid::SetDefaultEditor(wxGridCellEditor *editor) +{ + RegisterDataType(wxGRID_VALUE_STRING, + GetDefaultRendererForType(wxGRID_VALUE_STRING), + editor); +} + +// ---------------------------------------------------------------------------- +// access to the default attrbiutes +// ---------------------------------------------------------------------------- + +wxColour wxGrid::GetDefaultCellBackgroundColour() +{ + return m_defaultCellAttr->GetBackgroundColour(); +} + +wxColour wxGrid::GetDefaultCellTextColour() +{ + return m_defaultCellAttr->GetTextColour(); +} + +wxFont wxGrid::GetDefaultCellFont() +{ + return m_defaultCellAttr->GetFont(); +} + +void wxGrid::GetDefaultCellAlignment( int *horiz, int *vert ) +{ + m_defaultCellAttr->GetAlignment(horiz, vert); +} + +bool wxGrid::GetDefaultCellOverflow() +{ + return m_defaultCellAttr->GetOverflow(); +} + +wxGridCellRenderer *wxGrid::GetDefaultRenderer() const +{ + return m_defaultCellAttr->GetRenderer(NULL, 0, 0); +} + +wxGridCellEditor *wxGrid::GetDefaultEditor() const +{ + return m_defaultCellAttr->GetEditor(NULL, 0, 0); +} + +// ---------------------------------------------------------------------------- +// access to cell attributes +// ---------------------------------------------------------------------------- + +wxColour wxGrid::GetCellBackgroundColour(int row, int col) +{ + wxGridCellAttr *attr = GetCellAttr(row, col); + wxColour colour = attr->GetBackgroundColour(); + attr->DecRef(); + + return colour; +} + +wxColour wxGrid::GetCellTextColour( int row, int col ) +{ + wxGridCellAttr *attr = GetCellAttr(row, col); + wxColour colour = attr->GetTextColour(); + attr->DecRef(); + + return colour; +} + +wxFont wxGrid::GetCellFont( int row, int col ) +{ + wxGridCellAttr *attr = GetCellAttr(row, col); + wxFont font = attr->GetFont(); + attr->DecRef(); + + return font; +} + +void wxGrid::GetCellAlignment( int row, int col, int *horiz, int *vert ) +{ + wxGridCellAttr *attr = GetCellAttr(row, col); + attr->GetAlignment(horiz, vert); + attr->DecRef(); +} + +bool wxGrid::GetCellOverflow( int row, int col ) +{ + wxGridCellAttr *attr = GetCellAttr(row, col); + bool allow = attr->GetOverflow(); + attr->DecRef(); + + return allow; +} + +void wxGrid::GetCellSize( int row, int col, int *num_rows, int *num_cols ) +{ + wxGridCellAttr *attr = GetCellAttr(row, col); + attr->GetSize( num_rows, num_cols ); + attr->DecRef(); +} + +wxGridCellRenderer* wxGrid::GetCellRenderer(int row, int col) +{ + wxGridCellAttr* attr = GetCellAttr(row, col); + wxGridCellRenderer* renderer = attr->GetRenderer(this, row, col); + attr->DecRef(); + + return renderer; +} + +wxGridCellEditor* wxGrid::GetCellEditor(int row, int col) +{ + wxGridCellAttr* attr = GetCellAttr(row, col); + wxGridCellEditor* editor = attr->GetEditor(this, row, col); + attr->DecRef(); + + return editor; +} + +bool wxGrid::IsReadOnly(int row, int col) const +{ + wxGridCellAttr* attr = GetCellAttr(row, col); + bool isReadOnly = attr->IsReadOnly(); + attr->DecRef(); + + return isReadOnly; +} + +// ---------------------------------------------------------------------------- +// attribute support: cache, automatic provider creation, ... +// ---------------------------------------------------------------------------- + +bool wxGrid::CanHaveAttributes() +{ + if ( !m_table ) + { + return false; + } + + return m_table->CanHaveAttributes(); +} + +void wxGrid::ClearAttrCache() +{ + if ( m_attrCache.row != -1 ) + { + wxSafeDecRef(m_attrCache.attr); + m_attrCache.attr = NULL; + m_attrCache.row = -1; + } +} + +void wxGrid::CacheAttr(int row, int col, wxGridCellAttr *attr) const +{ + if ( attr != NULL ) + { + wxGrid *self = (wxGrid *)this; // const_cast + + self->ClearAttrCache(); + self->m_attrCache.row = row; + self->m_attrCache.col = col; + self->m_attrCache.attr = attr; + wxSafeIncRef(attr); + } +} + +bool wxGrid::LookupAttr(int row, int col, wxGridCellAttr **attr) const +{ + if ( row == m_attrCache.row && col == m_attrCache.col ) + { + *attr = m_attrCache.attr; + wxSafeIncRef(m_attrCache.attr); + +#ifdef DEBUG_ATTR_CACHE + gs_nAttrCacheHits++; +#endif + + return true; + } + else + { +#ifdef DEBUG_ATTR_CACHE + gs_nAttrCacheMisses++; +#endif + + return false; + } +} + +wxGridCellAttr *wxGrid::GetCellAttr(int row, int col) const +{ + wxGridCellAttr *attr = NULL; + // Additional test to avoid looking at the cache e.g. for + // wxNoCellCoords, as this will confuse memory management. + if ( row >= 0 ) + { + if ( !LookupAttr(row, col, &attr) ) + { + attr = m_table ? m_table->GetAttr(row, col, wxGridCellAttr::Any) + : (wxGridCellAttr *)NULL; + CacheAttr(row, col, attr); + } + } + + if (attr) + { + attr->SetDefAttr(m_defaultCellAttr); + } + else + { + attr = m_defaultCellAttr; + attr->IncRef(); + } + + return attr; +} + +wxGridCellAttr *wxGrid::GetOrCreateCellAttr(int row, int col) const +{ + wxGridCellAttr *attr = (wxGridCellAttr *)NULL; + bool canHave = ((wxGrid*)this)->CanHaveAttributes(); + + wxCHECK_MSG( canHave, attr, _T("Cell attributes not allowed")); + wxCHECK_MSG( m_table, attr, _T("must have a table") ); + + attr = m_table->GetAttr(row, col, wxGridCellAttr::Cell); + if ( !attr ) + { + attr = new wxGridCellAttr(m_defaultCellAttr); + + // artificially inc the ref count to match DecRef() in caller + attr->IncRef(); + m_table->SetAttr(attr, row, col); + } + + return attr; +} + +// ---------------------------------------------------------------------------- +// setting column attributes (wrappers around SetColAttr) +// ---------------------------------------------------------------------------- + +void wxGrid::SetColFormatBool(int col) +{ + SetColFormatCustom(col, wxGRID_VALUE_BOOL); +} + +void wxGrid::SetColFormatNumber(int col) +{ + SetColFormatCustom(col, wxGRID_VALUE_NUMBER); +} + +void wxGrid::SetColFormatFloat(int col, int width, int precision) +{ + wxString typeName = wxGRID_VALUE_FLOAT; + if ( (width != -1) || (precision != -1) ) + { + typeName << _T(':') << width << _T(',') << precision; + } + + SetColFormatCustom(col, typeName); +} + +void wxGrid::SetColFormatCustom(int col, const wxString& typeName) +{ + wxGridCellAttr *attr = m_table->GetAttr(-1, col, wxGridCellAttr::Col ); + if (!attr) + attr = new wxGridCellAttr; + wxGridCellRenderer *renderer = GetDefaultRendererForType(typeName); + attr->SetRenderer(renderer); + + SetColAttr(col, attr); + +} + +// ---------------------------------------------------------------------------- +// setting cell attributes: this is forwarded to the table +// ---------------------------------------------------------------------------- + +void wxGrid::SetAttr(int row, int col, wxGridCellAttr *attr) +{ + if ( CanHaveAttributes() ) + { + m_table->SetAttr(attr, row, col); + ClearAttrCache(); + } + else + { + wxSafeDecRef(attr); + } +} + +void wxGrid::SetRowAttr(int row, wxGridCellAttr *attr) +{ + if ( CanHaveAttributes() ) + { + m_table->SetRowAttr(attr, row); + ClearAttrCache(); + } + else + { + wxSafeDecRef(attr); + } +} + +void wxGrid::SetColAttr(int col, wxGridCellAttr *attr) +{ + if ( CanHaveAttributes() ) + { + m_table->SetColAttr(attr, col); + ClearAttrCache(); + } + else + { + wxSafeDecRef(attr); + } +} + +void wxGrid::SetCellBackgroundColour( int row, int col, const wxColour& colour ) +{ + if ( CanHaveAttributes() ) + { + wxGridCellAttr *attr = GetOrCreateCellAttr(row, col); + attr->SetBackgroundColour(colour); + attr->DecRef(); + } +} + +void wxGrid::SetCellTextColour( int row, int col, const wxColour& colour ) +{ + if ( CanHaveAttributes() ) + { + wxGridCellAttr *attr = GetOrCreateCellAttr(row, col); + attr->SetTextColour(colour); + attr->DecRef(); + } +} + +void wxGrid::SetCellFont( int row, int col, const wxFont& font ) +{ + if ( CanHaveAttributes() ) + { + wxGridCellAttr *attr = GetOrCreateCellAttr(row, col); + attr->SetFont(font); + attr->DecRef(); + } +} + +void wxGrid::SetCellAlignment( int row, int col, int horiz, int vert ) +{ + if ( CanHaveAttributes() ) + { + wxGridCellAttr *attr = GetOrCreateCellAttr(row, col); + attr->SetAlignment(horiz, vert); + attr->DecRef(); + } +} + +void wxGrid::SetCellOverflow( int row, int col, bool allow ) +{ + if ( CanHaveAttributes() ) + { + wxGridCellAttr *attr = GetOrCreateCellAttr(row, col); + attr->SetOverflow(allow); + attr->DecRef(); + } +} + +void wxGrid::SetCellSize( int row, int col, int num_rows, int num_cols ) +{ + if ( CanHaveAttributes() ) + { + int cell_rows, cell_cols; + + wxGridCellAttr *attr = GetOrCreateCellAttr(row, col); + attr->GetSize(&cell_rows, &cell_cols); + attr->SetSize(num_rows, num_cols); + attr->DecRef(); + + // Cannot set the size of a cell to 0 or negative values + // While it is perfectly legal to do that, this function cannot + // handle all the possibilies, do it by hand by getting the CellAttr. + // You can only set the size of a cell to 1,1 or greater with this fn + wxASSERT_MSG( !((cell_rows < 1) || (cell_cols < 1)), + wxT("wxGrid::SetCellSize setting cell size that is already part of another cell")); + wxASSERT_MSG( !((num_rows < 1) || (num_cols < 1)), + wxT("wxGrid::SetCellSize setting cell size to < 1")); + + // if this was already a multicell then "turn off" the other cells first + if ((cell_rows > 1) || (cell_rows > 1)) + { + int i, j; + for (j=row; j < row + cell_rows; j++) + { + for (i=col; i < col + cell_cols; i++) + { + if ((i != col) || (j != row)) + { + wxGridCellAttr *attr_stub = GetOrCreateCellAttr(j, i); + attr_stub->SetSize( 1, 1 ); + attr_stub->DecRef(); + } + } + } + } + + // mark the cells that will be covered by this cell to + // negative or zero values to point back at this cell + if (((num_rows > 1) || (num_cols > 1)) && (num_rows >= 1) && (num_cols >= 1)) + { + int i, j; + for (j=row; j < row + num_rows; j++) + { + for (i=col; i < col + num_cols; i++) + { + if ((i != col) || (j != row)) + { + wxGridCellAttr *attr_stub = GetOrCreateCellAttr(j, i); + attr_stub->SetSize( row - j, col - i ); + attr_stub->DecRef(); + } + } + } + } + } +} + +void wxGrid::SetCellRenderer(int row, int col, wxGridCellRenderer *renderer) +{ + if ( CanHaveAttributes() ) + { + wxGridCellAttr *attr = GetOrCreateCellAttr(row, col); + attr->SetRenderer(renderer); + attr->DecRef(); + } +} + +void wxGrid::SetCellEditor(int row, int col, wxGridCellEditor* editor) +{ + if ( CanHaveAttributes() ) + { + wxGridCellAttr *attr = GetOrCreateCellAttr(row, col); + attr->SetEditor(editor); + attr->DecRef(); + } +} + +void wxGrid::SetReadOnly(int row, int col, bool isReadOnly) +{ + if ( CanHaveAttributes() ) + { + wxGridCellAttr *attr = GetOrCreateCellAttr(row, col); + attr->SetReadOnly(isReadOnly); + attr->DecRef(); + } +} + +// ---------------------------------------------------------------------------- +// Data type registration +// ---------------------------------------------------------------------------- + +void wxGrid::RegisterDataType(const wxString& typeName, + wxGridCellRenderer* renderer, + wxGridCellEditor* editor) +{ + m_typeRegistry->RegisterDataType(typeName, renderer, editor); +} + + +wxGridCellEditor * wxGrid::GetDefaultEditorForCell(int row, int col) const +{ + wxString typeName = m_table->GetTypeName(row, col); + return GetDefaultEditorForType(typeName); +} + +wxGridCellRenderer * wxGrid::GetDefaultRendererForCell(int row, int col) const +{ + wxString typeName = m_table->GetTypeName(row, col); + return GetDefaultRendererForType(typeName); +} + +wxGridCellEditor * wxGrid::GetDefaultEditorForType(const wxString& typeName) const +{ + int index = m_typeRegistry->FindOrCloneDataType(typeName); + if ( index == wxNOT_FOUND ) + { + wxString errStr; + + errStr.Printf(wxT("Unknown data type name [%s]"), typeName.c_str()); + wxFAIL_MSG(errStr.c_str()); + + return NULL; + } + + return m_typeRegistry->GetEditor(index); +} + +wxGridCellRenderer * wxGrid::GetDefaultRendererForType(const wxString& typeName) const +{ + int index = m_typeRegistry->FindOrCloneDataType(typeName); + if ( index == wxNOT_FOUND ) + { + wxString errStr; + + errStr.Printf(wxT("Unknown data type name [%s]"), typeName.c_str()); + wxFAIL_MSG(errStr.c_str()); + + return NULL; + } + + return m_typeRegistry->GetRenderer(index); +} + +// ---------------------------------------------------------------------------- +// row/col size +// ---------------------------------------------------------------------------- + +void wxGrid::EnableDragRowSize( bool enable ) +{ + m_canDragRowSize = enable; +} + +void wxGrid::EnableDragColSize( bool enable ) +{ + m_canDragColSize = enable; +} + +void wxGrid::EnableDragGridSize( bool enable ) +{ + m_canDragGridSize = enable; +} + +void wxGrid::EnableDragCell( bool enable ) +{ + m_canDragCell = enable; +} + +void wxGrid::SetDefaultRowSize( int height, bool resizeExistingRows ) +{ + m_defaultRowHeight = wxMax( height, m_minAcceptableRowHeight ); + + if ( resizeExistingRows ) + { + // since we are resizing all rows to the default row size, + // we can simply clear the row heights and row bottoms + // arrays (which also allows us to take advantage of + // some speed optimisations) + m_rowHeights.Empty(); + m_rowBottoms.Empty(); + if ( !GetBatchCount() ) + CalcDimensions(); + } +} + +void wxGrid::SetRowSize( int row, int height ) +{ + wxCHECK_RET( row >= 0 && row < m_numRows, _T("invalid row index") ); + + // See comment in SetColSize + if ( height < GetRowMinimalAcceptableHeight()) + return; + + if ( m_rowHeights.IsEmpty() ) + { + // need to really create the array + InitRowHeights(); + } + + int h = wxMax( 0, height ); + int diff = h - m_rowHeights[row]; + + m_rowHeights[row] = h; + for ( int i = row; i < m_numRows; i++ ) + { + m_rowBottoms[i] += diff; + } + + if ( !GetBatchCount() ) + CalcDimensions(); +} + +void wxGrid::SetDefaultColSize( int width, bool resizeExistingCols ) +{ + m_defaultColWidth = wxMax( width, m_minAcceptableColWidth ); + + if ( resizeExistingCols ) + { + // since we are resizing all columns to the default column size, + // we can simply clear the col widths and col rights + // arrays (which also allows us to take advantage of + // some speed optimisations) + m_colWidths.Empty(); + m_colRights.Empty(); + if ( !GetBatchCount() ) + CalcDimensions(); + } +} + +void wxGrid::SetColSize( int col, int width ) +{ + wxCHECK_RET( col >= 0 && col < m_numCols, _T("invalid column index") ); + + // should we check that it's bigger than GetColMinimalWidth(col) here? + // (VZ) + // No, because it is reasonable to assume the library user know's + // what he is doing. However we should test against the weaker + // constraint of minimalAcceptableWidth, as this breaks rendering + // + // This test then fixes sf.net bug #645734 + + if ( width < GetColMinimalAcceptableWidth() ) + return; + + if ( m_colWidths.IsEmpty() ) + { + // need to really create the array + InitColWidths(); + } + + // if < 0 then calculate new width from label + if ( width < 0 ) + { + long w, h; + wxArrayString lines; + wxClientDC dc(m_colLabelWin); + dc.SetFont(GetLabelFont()); + StringToLines(GetColLabelValue(col), lines); + GetTextBoxSize(dc, lines, &w, &h); + width = w + 6; + } + + int w = wxMax( 0, width ); + int diff = w - m_colWidths[col]; + m_colWidths[col] = w; + + for ( int colPos = GetColPos(col); colPos < m_numCols; colPos++ ) + { + m_colRights[GetColAt(colPos)] += diff; + } + + if ( !GetBatchCount() ) + CalcDimensions(); +} + +void wxGrid::SetColMinimalWidth( int col, int width ) +{ + if (width > GetColMinimalAcceptableWidth()) + { + wxLongToLongHashMap::key_type key = (wxLongToLongHashMap::key_type)col; + m_colMinWidths[key] = width; + } +} + +void wxGrid::SetRowMinimalHeight( int row, int width ) +{ + if (width > GetRowMinimalAcceptableHeight()) + { + wxLongToLongHashMap::key_type key = (wxLongToLongHashMap::key_type)row; + m_rowMinHeights[key] = width; + } +} + +int wxGrid::GetColMinimalWidth(int col) const +{ + wxLongToLongHashMap::key_type key = (wxLongToLongHashMap::key_type)col; + wxLongToLongHashMap::const_iterator it = m_colMinWidths.find(key); + + return it != m_colMinWidths.end() ? (int)it->second : m_minAcceptableColWidth; +} + +int wxGrid::GetRowMinimalHeight(int row) const +{ + wxLongToLongHashMap::key_type key = (wxLongToLongHashMap::key_type)row; + wxLongToLongHashMap::const_iterator it = m_rowMinHeights.find(key); + + return it != m_rowMinHeights.end() ? (int)it->second : m_minAcceptableRowHeight; +} + +void wxGrid::SetColMinimalAcceptableWidth( int width ) +{ + // We do allow a width of 0 since this gives us + // an easy way to temporarily hiding columns. + if ( width >= 0 ) + m_minAcceptableColWidth = width; +} + +void wxGrid::SetRowMinimalAcceptableHeight( int height ) +{ + // We do allow a height of 0 since this gives us + // an easy way to temporarily hiding rows. + if ( height >= 0 ) + m_minAcceptableRowHeight = height; +} + +int wxGrid::GetColMinimalAcceptableWidth() const +{ + return m_minAcceptableColWidth; +} + +int wxGrid::GetRowMinimalAcceptableHeight() const +{ + return m_minAcceptableRowHeight; +} + +// ---------------------------------------------------------------------------- +// auto sizing +// ---------------------------------------------------------------------------- + +void wxGrid::AutoSizeColOrRow( int colOrRow, bool setAsMin, bool column ) +{ + wxClientDC dc(m_gridWin); + + // cancel editing of cell + HideCellEditControl(); + SaveEditControlValue(); + + // init both of them to avoid compiler warnings, even if we only need one + int row = -1, + col = -1; + if ( column ) + col = colOrRow; + else + row = colOrRow; + + wxCoord extent, extentMax = 0; + int max = column ? m_numRows : m_numCols; + for ( int rowOrCol = 0; rowOrCol < max; rowOrCol++ ) + { + if ( column ) + row = rowOrCol; + else + col = rowOrCol; + + wxGridCellAttr *attr = GetCellAttr(row, col); + wxGridCellRenderer *renderer = attr->GetRenderer(this, row, col); + if ( renderer ) + { + wxSize size = renderer->GetBestSize(*this, *attr, dc, row, col); + extent = column ? size.x : size.y; + if ( extent > extentMax ) + extentMax = extent; + + renderer->DecRef(); + } + + attr->DecRef(); + } + + // now also compare with the column label extent + wxCoord w, h; + dc.SetFont( GetLabelFont() ); + + if ( column ) + { + dc.GetMultiLineTextExtent( GetColLabelValue(col), &w, &h ); + if ( GetColLabelTextOrientation() == wxVERTICAL ) + w = h; + } + else + dc.GetMultiLineTextExtent( GetRowLabelValue(row), &w, &h ); + + extent = column ? w : h; + if ( extent > extentMax ) + extentMax = extent; + + if ( !extentMax ) + { + // empty column - give default extent (notice that if extentMax is less + // than default extent but != 0, it's OK) + extentMax = column ? m_defaultColWidth : m_defaultRowHeight; + } + else + { + if ( column ) + // leave some space around text + extentMax += 10; + else + extentMax += 6; + } + + if ( column ) + { + // Ensure automatic width is not less than minimal width. See the + // comment in SetColSize() for explanation of why this isn't done + // in SetColSize(). + if ( !setAsMin ) + extentMax = wxMax(extentMax, GetColMinimalWidth(col)); + + SetColSize( col, extentMax ); + if ( !GetBatchCount() ) + { + int cw, ch, dummy; + m_gridWin->GetClientSize( &cw, &ch ); + wxRect rect ( CellToRect( 0, col ) ); + rect.y = 0; + CalcScrolledPosition(rect.x, 0, &rect.x, &dummy); + rect.width = cw - rect.x; + rect.height = m_colLabelHeight; + m_colLabelWin->Refresh( true, &rect ); + } + } + else + { + // Ensure automatic width is not less than minimal height. See the + // comment in SetColSize() for explanation of why this isn't done + // in SetRowSize(). + if ( !setAsMin ) + extentMax = wxMax(extentMax, GetRowMinimalHeight(row)); + + SetRowSize(row, extentMax); + if ( !GetBatchCount() ) + { + int cw, ch, dummy; + m_gridWin->GetClientSize( &cw, &ch ); + wxRect rect( CellToRect( row, 0 ) ); + rect.x = 0; + CalcScrolledPosition(0, rect.y, &dummy, &rect.y); + rect.width = m_rowLabelWidth; + rect.height = ch - rect.y; + m_rowLabelWin->Refresh( true, &rect ); + } + } + + if ( setAsMin ) + { + if ( column ) + SetColMinimalWidth(col, extentMax); + else + SetRowMinimalHeight(row, extentMax); + } +} + +wxCoord wxGrid::CalcColOrRowLabelAreaMinSize(bool column) +{ + // calculate size for the rows or columns? + const bool calcRows = !column; + + wxClientDC dc(calcRows ? GetGridRowLabelWindow() + : GetGridColLabelWindow()); + dc.SetFont(GetLabelFont()); + + // which dimension should we take into account for calculations? + // + // for columns, the text can be only horizontal so it's easy but for rows + // we also have to take into account the text orientation + const bool + useWidth = calcRows || (GetColLabelTextOrientation() == wxVERTICAL); + + wxArrayString lines; + wxCoord extentMax = 0; + + const int numRowsOrCols = calcRows ? m_numRows : m_numCols; + for ( int rowOrCol = 0; rowOrCol < numRowsOrCols; rowOrCol++ ) + { + lines.Clear(); + // NB: extra parentheses needed to avoid bcc 5.82 compilation errors + StringToLines((calcRows ? GetRowLabelValue(rowOrCol) + : GetColLabelValue(rowOrCol)), + lines); + + long w, h; + GetTextBoxSize(dc, lines, &w, &h); + + const wxCoord extent = useWidth ? w : h; + if ( extent > extentMax ) + extentMax = extent; + } + + if ( !extentMax ) + { + // empty column - give default extent (notice that if extentMax is less + // than default extent but != 0, it's OK) + extentMax = calcRows ? GetDefaultRowLabelSize() + : GetDefaultColLabelSize(); + } + + // leave some space around text (taken from AutoSizeColOrRow) + if ( calcRows ) + extentMax += 10; + else + extentMax += 6; + + return extentMax; +} + +int wxGrid::SetOrCalcColumnSizes(bool calcOnly, bool setAsMin) +{ + int width = m_rowLabelWidth; + + if ( !calcOnly ) + BeginBatch(); + + for ( int col = 0; col < m_numCols; col++ ) + { + if ( !calcOnly ) + AutoSizeColumn(col, setAsMin); + + width += GetColWidth(col); + } + + if ( !calcOnly ) + EndBatch(); + + return width; +} + +int wxGrid::SetOrCalcRowSizes(bool calcOnly, bool setAsMin) +{ + int height = m_colLabelHeight; + + if ( !calcOnly ) + BeginBatch(); + + for ( int row = 0; row < m_numRows; row++ ) + { + if ( !calcOnly ) + AutoSizeRow(row, setAsMin); + + height += GetRowHeight(row); + } + + if ( !calcOnly ) + EndBatch(); + + return height; +} + +void wxGrid::AutoSize() +{ + BeginBatch(); + + // we need to round up the size of the scrollable area to a multiple of + // scroll step to ensure that we don't get the scrollbars when we're sized + // exactly to fit our contents + wxSize size(SetOrCalcColumnSizes(false) - m_rowLabelWidth + m_extraWidth, + SetOrCalcRowSizes(false) - m_colLabelHeight + m_extraHeight); + wxSize sizeFit(GetScrollX(size.x) * GetScrollLineX(), + GetScrollY(size.y) * GetScrollLineY()); + + // distribute the extra space between the columns/rows to avoid having + // extra white space + wxCoord diff = sizeFit.x - size.x; + if ( diff && m_numCols ) + { + // try to resize the columns uniformly + wxCoord diffPerCol = diff / m_numCols; + if ( diffPerCol ) + { + for ( int col = 0; col < m_numCols; col++ ) + { + SetColSize(col, GetColWidth(col) + diffPerCol); + } + } + + // add remaining amount to the last columns + diff -= diffPerCol * m_numCols; + if ( diff ) + { + for ( int col = m_numCols - 1; col >= m_numCols - diff; col-- ) + { + SetColSize(col, GetColWidth(col) + 1); + } + } + } + + // same for rows + diff = sizeFit.y - size.y; + if ( diff && m_numRows ) + { + // try to resize the columns uniformly + wxCoord diffPerRow = diff / m_numRows; + if ( diffPerRow ) + { + for ( int row = 0; row < m_numRows; row++ ) + { + SetRowSize(row, GetRowHeight(row) + diffPerRow); + } + } + + // add remaining amount to the last rows + diff -= diffPerRow * m_numRows; + if ( diff ) + { + for ( int row = m_numRows - 1; row >= m_numRows - diff; row-- ) + { + SetRowSize(row, GetRowHeight(row) + 1); + } + } + } + + // we know that we're not going to have scrollbars so disable them now to + // avoid trouble in SetClientSize() which can otherwise set the correct + // client size but also leave space for (not needed any more) scrollbars + SetScrollbars(0, 0, 0, 0, 0, 0, true); + SetClientSize(sizeFit.x + m_rowLabelWidth, sizeFit.y + m_colLabelHeight); + + EndBatch(); +} + +void wxGrid::AutoSizeRowLabelSize( int row ) +{ + wxArrayString lines; + long w, h; + + // Hide the edit control, so it + // won't interfere with drag-shrinking. + if ( IsCellEditControlShown() ) + { + HideCellEditControl(); + SaveEditControlValue(); + } + + // autosize row height depending on label text + StringToLines( GetRowLabelValue( row ), lines ); + wxClientDC dc( m_rowLabelWin ); + GetTextBoxSize( dc, lines, &w, &h ); + if ( h < m_defaultRowHeight ) + h = m_defaultRowHeight; + SetRowSize(row, h); + ForceRefresh(); +} + +void wxGrid::AutoSizeColLabelSize( int col ) +{ + wxArrayString lines; + long w, h; + + // Hide the edit control, so it + // won't interfere with drag-shrinking. + if ( IsCellEditControlShown() ) + { + HideCellEditControl(); + SaveEditControlValue(); + } + + // autosize column width depending on label text + StringToLines( GetColLabelValue( col ), lines ); + wxClientDC dc( m_colLabelWin ); + if ( GetColLabelTextOrientation() == wxHORIZONTAL ) + GetTextBoxSize( dc, lines, &w, &h ); + else + GetTextBoxSize( dc, lines, &h, &w ); + if ( w < m_defaultColWidth ) + w = m_defaultColWidth; + SetColSize(col, w); + ForceRefresh(); +} + +wxSize wxGrid::DoGetBestSize() const +{ + wxGrid *self = (wxGrid *)this; // const_cast + + // we do the same as in AutoSize() here with the exception that we don't + // change the column/row sizes, only calculate them + wxSize size(self->SetOrCalcColumnSizes(true) - m_rowLabelWidth + m_extraWidth, + self->SetOrCalcRowSizes(true) - m_colLabelHeight + m_extraHeight); + wxSize sizeFit(GetScrollX(size.x) * GetScrollLineX(), + GetScrollY(size.y) * GetScrollLineY()); + + // NOTE: This size should be cached, but first we need to add calls to + // InvalidateBestSize everywhere that could change the results of this + // calculation. + // CacheBestSize(size); + + return wxSize(sizeFit.x + m_rowLabelWidth, sizeFit.y + m_colLabelHeight) + + GetWindowBorderSize(); +} + +void wxGrid::Fit() +{ + AutoSize(); +} + +wxPen& wxGrid::GetDividerPen() const +{ + return wxNullPen; +} + +// ---------------------------------------------------------------------------- +// cell value accessor functions +// ---------------------------------------------------------------------------- + +void wxGrid::SetCellValue( int row, int col, const wxString& s ) +{ + if ( m_table ) + { + m_table->SetValue( row, col, s ); + if ( !GetBatchCount() ) + { + int dummy; + wxRect rect( CellToRect( row, col ) ); + rect.x = 0; + rect.width = m_gridWin->GetClientSize().GetWidth(); + CalcScrolledPosition(0, rect.y, &dummy, &rect.y); + m_gridWin->Refresh( false, &rect ); + } + + if ( m_currentCellCoords.GetRow() == row && + m_currentCellCoords.GetCol() == col && + IsCellEditControlShown()) + // Note: If we are using IsCellEditControlEnabled, + // this interacts badly with calling SetCellValue from + // an EVT_GRID_CELL_CHANGE handler. + { + HideCellEditControl(); + ShowCellEditControl(); // will reread data from table + } + } +} + +// ---------------------------------------------------------------------------- +// block, row and column selection +// ---------------------------------------------------------------------------- + +void wxGrid::SelectRow( int row, bool addToSelected ) +{ + if ( IsSelection() && !addToSelected ) + ClearSelection(); + + if ( m_selection ) + m_selection->SelectRow( row, false, addToSelected ); +} + +void wxGrid::SelectCol( int col, bool addToSelected ) +{ + if ( IsSelection() && !addToSelected ) + ClearSelection(); + + if ( m_selection ) + m_selection->SelectCol( col, false, addToSelected ); +} + +void wxGrid::SelectBlock( int topRow, int leftCol, int bottomRow, int rightCol, + bool addToSelected ) +{ + if ( IsSelection() && !addToSelected ) + ClearSelection(); + + if ( m_selection ) + m_selection->SelectBlock( topRow, leftCol, bottomRow, rightCol, + false, addToSelected ); +} + +void wxGrid::SelectAll() +{ + if ( m_numRows > 0 && m_numCols > 0 ) + { + if ( m_selection ) + m_selection->SelectBlock( 0, 0, m_numRows - 1, m_numCols - 1 ); + } +} + +// ---------------------------------------------------------------------------- +// cell, row and col deselection +// ---------------------------------------------------------------------------- + +void wxGrid::DeselectRow( int row ) +{ + if ( !m_selection ) + return; + + if ( m_selection->GetSelectionMode() == wxGrid::wxGridSelectRows ) + { + if ( m_selection->IsInSelection(row, 0 ) ) + m_selection->ToggleCellSelection(row, 0); + } + else + { + int nCols = GetNumberCols(); + for ( int i = 0; i < nCols; i++ ) + { + if ( m_selection->IsInSelection(row, i ) ) + m_selection->ToggleCellSelection(row, i); + } + } +} + +void wxGrid::DeselectCol( int col ) +{ + if ( !m_selection ) + return; + + if ( m_selection->GetSelectionMode() == wxGrid::wxGridSelectColumns ) + { + if ( m_selection->IsInSelection(0, col ) ) + m_selection->ToggleCellSelection(0, col); + } + else + { + int nRows = GetNumberRows(); + for ( int i = 0; i < nRows; i++ ) + { + if ( m_selection->IsInSelection(i, col ) ) + m_selection->ToggleCellSelection(i, col); + } + } +} + +void wxGrid::DeselectCell( int row, int col ) +{ + if ( m_selection && m_selection->IsInSelection(row, col) ) + m_selection->ToggleCellSelection(row, col); +} + +bool wxGrid::IsSelection() +{ + return ( m_selection && (m_selection->IsSelection() || + ( m_selectingTopLeft != wxGridNoCellCoords && + m_selectingBottomRight != wxGridNoCellCoords) ) ); +} + +bool wxGrid::IsInSelection( int row, int col ) const +{ + return ( m_selection && (m_selection->IsInSelection( row, col ) || + ( row >= m_selectingTopLeft.GetRow() && + col >= m_selectingTopLeft.GetCol() && + row <= m_selectingBottomRight.GetRow() && + col <= m_selectingBottomRight.GetCol() )) ); +} + +wxGridCellCoordsArray wxGrid::GetSelectedCells() const +{ + if (!m_selection) + { + wxGridCellCoordsArray a; + return a; + } + + return m_selection->m_cellSelection; +} + +wxGridCellCoordsArray wxGrid::GetSelectionBlockTopLeft() const +{ + if (!m_selection) + { + wxGridCellCoordsArray a; + return a; + } + + return m_selection->m_blockSelectionTopLeft; +} + +wxGridCellCoordsArray wxGrid::GetSelectionBlockBottomRight() const +{ + if (!m_selection) + { + wxGridCellCoordsArray a; + return a; + } + + return m_selection->m_blockSelectionBottomRight; +} + +wxArrayInt wxGrid::GetSelectedRows() const +{ + if (!m_selection) + { + wxArrayInt a; + return a; + } + + return m_selection->m_rowSelection; +} + +wxArrayInt wxGrid::GetSelectedCols() const +{ + if (!m_selection) + { + wxArrayInt a; + return a; + } + + return m_selection->m_colSelection; +} + +void wxGrid::ClearSelection() +{ + wxRect r1 = BlockToDeviceRect( m_selectingTopLeft, m_selectingBottomRight); + wxRect r2 = BlockToDeviceRect( m_currentCellCoords, m_selectingKeyboard ); + m_selectingTopLeft = + m_selectingBottomRight = + m_selectingKeyboard = wxGridNoCellCoords; + Refresh( false, &r1 ); + Refresh( false, &r2 ); + if ( m_selection ) + m_selection->ClearSelection(); +} + +// This function returns the rectangle that encloses the given block +// in device coords clipped to the client size of the grid window. +// +wxRect wxGrid::BlockToDeviceRect( const wxGridCellCoords &topLeft, + const wxGridCellCoords &bottomRight ) +{ + wxRect rect( wxGridNoCellRect ); + wxRect cellRect; + + cellRect = CellToRect( topLeft ); + if ( cellRect != wxGridNoCellRect ) + { + rect = cellRect; + } + else + { + rect = wxRect(0, 0, 0, 0); + } + + cellRect = CellToRect( bottomRight ); + if ( cellRect != wxGridNoCellRect ) + { + rect += cellRect; + } + else + { + return wxGridNoCellRect; + } + + int i, j; + int left = rect.GetLeft(); + int top = rect.GetTop(); + int right = rect.GetRight(); + int bottom = rect.GetBottom(); + + int leftCol = topLeft.GetCol(); + int topRow = topLeft.GetRow(); + int rightCol = bottomRight.GetCol(); + int bottomRow = bottomRight.GetRow(); + + if (left > right) + { + i = left; + left = right; + right = i; + i = leftCol; + leftCol = rightCol; + rightCol = i; + } + + if (top > bottom) + { + i = top; + top = bottom; + bottom = i; + i = topRow; + topRow = bottomRow; + bottomRow = i; + } + + for ( j = topRow; j <= bottomRow; j++ ) + { + for ( i = leftCol; i <= rightCol; i++ ) + { + if ((j == topRow) || (j == bottomRow) || (i == leftCol) || (i == rightCol)) + { + cellRect = CellToRect( j, i ); + + if (cellRect.x < left) + left = cellRect.x; + if (cellRect.y < top) + top = cellRect.y; + if (cellRect.x + cellRect.width > right) + right = cellRect.x + cellRect.width; + if (cellRect.y + cellRect.height > bottom) + bottom = cellRect.y + cellRect.height; + } + else + { + i = rightCol; // jump over inner cells. + } + } + } + + // convert to scrolled coords + // + CalcScrolledPosition( left, top, &left, &top ); + CalcScrolledPosition( right, bottom, &right, &bottom ); + + int cw, ch; + m_gridWin->GetClientSize( &cw, &ch ); + + if (right < 0 || bottom < 0 || left > cw || top > ch) + return wxRect(0,0,0,0); + + rect.SetLeft( wxMax(0, left) ); + rect.SetTop( wxMax(0, top) ); + rect.SetRight( wxMin(cw, right) ); + rect.SetBottom( wxMin(ch, bottom) ); + + return rect; +} + +// ---------------------------------------------------------------------------- +// grid event classes +// ---------------------------------------------------------------------------- + +IMPLEMENT_DYNAMIC_CLASS( wxGridEvent, wxNotifyEvent ) + +wxGridEvent::wxGridEvent( int id, wxEventType type, wxObject* obj, + int row, int col, int x, int y, bool sel, + bool control, bool shift, bool alt, bool meta ) + : wxNotifyEvent( type, id ) +{ + m_row = row; + m_col = col; + m_x = x; + m_y = y; + m_selecting = sel; + m_control = control; + m_shift = shift; + m_alt = alt; + m_meta = meta; + + SetEventObject(obj); +} + + +IMPLEMENT_DYNAMIC_CLASS( wxGridSizeEvent, wxNotifyEvent ) + +wxGridSizeEvent::wxGridSizeEvent( int id, wxEventType type, wxObject* obj, + int rowOrCol, int x, int y, + bool control, bool shift, bool alt, bool meta ) + : wxNotifyEvent( type, id ) +{ + m_rowOrCol = rowOrCol; + m_x = x; + m_y = y; + m_control = control; + m_shift = shift; + m_alt = alt; + m_meta = meta; + + SetEventObject(obj); +} + + +IMPLEMENT_DYNAMIC_CLASS( wxGridRangeSelectEvent, wxNotifyEvent ) + +wxGridRangeSelectEvent::wxGridRangeSelectEvent(int id, wxEventType type, wxObject* obj, + const wxGridCellCoords& topLeft, + const wxGridCellCoords& bottomRight, + bool sel, bool control, + bool shift, bool alt, bool meta ) + : wxNotifyEvent( type, id ) +{ + m_topLeft = topLeft; + m_bottomRight = bottomRight; + m_selecting = sel; + m_control = control; + m_shift = shift; + m_alt = alt; + m_meta = meta; + + SetEventObject(obj); +} + + +IMPLEMENT_DYNAMIC_CLASS(wxGridEditorCreatedEvent, wxCommandEvent) + +wxGridEditorCreatedEvent::wxGridEditorCreatedEvent(int id, wxEventType type, + wxObject* obj, int row, + int col, wxControl* ctrl) + : wxCommandEvent(type, id) +{ + SetEventObject(obj); + m_row = row; + m_col = col; + m_ctrl = ctrl; +} + +#endif // wxUSE_GRID diff --git a/Externals/wxWidgets/src/generic/gridctrl.cpp b/Externals/wxWidgets/src/generic/gridctrl.cpp index e847fb9673..24eb4ae79a 100644 --- a/Externals/wxWidgets/src/generic/gridctrl.cpp +++ b/Externals/wxWidgets/src/generic/gridctrl.cpp @@ -1,405 +1,405 @@ -/////////////////////////////////////////////////////////////////////////// -// Name: generic/gridctrl.cpp -// Purpose: wxGrid controls -// Author: Paul Gammans, Roger Gammans -// Modified by: -// Created: 11/04/2001 -// RCS-ID: $Id: gridctrl.cpp 41587 2006-10-03 14:28:36Z PC $ -// Copyright: (c) The Computer Surgery (paul@compsurg.co.uk) -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_GRID - -#include "wx/generic/gridctrl.h" - -#ifndef WX_PRECOMP - #include "wx/textctrl.h" - #include "wx/dc.h" - #include "wx/combobox.h" -#endif // WX_PRECOMP - -#include "wx/tokenzr.h" - -// ---------------------------------------------------------------------------- -// wxGridCellDateTimeRenderer -// ---------------------------------------------------------------------------- - -#if wxUSE_DATETIME - -// Enables a grid cell to display a formatted date and or time - -wxGridCellDateTimeRenderer::wxGridCellDateTimeRenderer(const wxString& outformat, const wxString& informat) -{ - m_iformat = informat; - m_oformat = outformat; - m_tz = wxDateTime::Local; - m_dateDef = wxDefaultDateTime; -} - -wxGridCellRenderer *wxGridCellDateTimeRenderer::Clone() const -{ - wxGridCellDateTimeRenderer *renderer = new wxGridCellDateTimeRenderer; - renderer->m_iformat = m_iformat; - renderer->m_oformat = m_oformat; - renderer->m_dateDef = m_dateDef; - renderer->m_tz = m_tz; - - return renderer; -} - -wxString wxGridCellDateTimeRenderer::GetString(const wxGrid& grid, int row, int col) -{ - wxGridTableBase *table = grid.GetTable(); - - bool hasDatetime = false; - wxDateTime val; - wxString text; - if ( table->CanGetValueAs(row, col, wxGRID_VALUE_DATETIME) ) - { - void * tempval = table->GetValueAsCustom(row, col,wxGRID_VALUE_DATETIME); - - if (tempval){ - val = *((wxDateTime *)tempval); - hasDatetime = true; - delete (wxDateTime *)tempval; - } - - } - - if (!hasDatetime ) - { - text = table->GetValue(row, col); - hasDatetime = (val.ParseFormat( text, m_iformat, m_dateDef ) != (wxChar *)NULL) ; - } - - if ( hasDatetime ) - text = val.Format(m_oformat, m_tz ); - - //If we faild to parse string just show what we where given? - return text; -} - -void wxGridCellDateTimeRenderer::Draw(wxGrid& grid, - wxGridCellAttr& attr, - wxDC& dc, - const wxRect& rectCell, - int row, int col, - bool isSelected) -{ - wxGridCellRenderer::Draw(grid, attr, dc, rectCell, row, col, isSelected); - - SetTextColoursAndFont(grid, attr, dc, isSelected); - - // draw the text right aligned by default - int hAlign, vAlign; - attr.GetAlignment(&hAlign, &vAlign); - hAlign = wxRIGHT; - - wxRect rect = rectCell; - rect.Inflate(-1); - - grid.DrawTextRectangle(dc, GetString(grid, row, col), rect, hAlign, vAlign); -} - -wxSize wxGridCellDateTimeRenderer::GetBestSize(wxGrid& grid, - wxGridCellAttr& attr, - wxDC& dc, - int row, int col) -{ - return DoGetBestSize(attr, dc, GetString(grid, row, col)); -} - -void wxGridCellDateTimeRenderer::SetParameters(const wxString& params) -{ - if (!params.empty()) - m_oformat=params; -} - -#endif // wxUSE_DATETIME - -// ---------------------------------------------------------------------------- -// wxGridCellChoiceNumberRenderer -// ---------------------------------------------------------------------------- -// Renders a number as a textual equivalent. -// eg data in cell is 0,1,2 ... n the cell could be rendered as "John","Fred"..."Bob" - - -wxGridCellEnumRenderer::wxGridCellEnumRenderer(const wxString& choices) -{ - if (!choices.empty()) - SetParameters(choices); -} - -wxGridCellRenderer *wxGridCellEnumRenderer::Clone() const -{ - wxGridCellEnumRenderer *renderer = new wxGridCellEnumRenderer; - renderer->m_choices = m_choices; - return renderer; -} - -wxString wxGridCellEnumRenderer::GetString(const wxGrid& grid, int row, int col) -{ - wxGridTableBase *table = grid.GetTable(); - wxString text; - if ( table->CanGetValueAs(row, col, wxGRID_VALUE_NUMBER) ) - { - int choiceno = table->GetValueAsLong(row, col); - text.Printf(_T("%s"), m_choices[ choiceno ].c_str() ); - } - else - { - text = table->GetValue(row, col); - } - - - //If we faild to parse string just show what we where given? - return text; -} - -void wxGridCellEnumRenderer::Draw(wxGrid& grid, - wxGridCellAttr& attr, - wxDC& dc, - const wxRect& rectCell, - int row, int col, - bool isSelected) -{ - wxGridCellRenderer::Draw(grid, attr, dc, rectCell, row, col, isSelected); - - SetTextColoursAndFont(grid, attr, dc, isSelected); - - // draw the text right aligned by default - int hAlign, vAlign; - attr.GetAlignment(&hAlign, &vAlign); - hAlign = wxRIGHT; - - wxRect rect = rectCell; - rect.Inflate(-1); - - grid.DrawTextRectangle(dc, GetString(grid, row, col), rect, hAlign, vAlign); -} - -wxSize wxGridCellEnumRenderer::GetBestSize(wxGrid& grid, - wxGridCellAttr& attr, - wxDC& dc, - int row, int col) -{ - return DoGetBestSize(attr, dc, GetString(grid, row, col)); -} - -void wxGridCellEnumRenderer::SetParameters(const wxString& params) -{ - if ( !params ) - { - // what can we do? - return; - } - - m_choices.Empty(); - - wxStringTokenizer tk(params, _T(',')); - while ( tk.HasMoreTokens() ) - { - m_choices.Add(tk.GetNextToken()); - } -} - -#if wxUSE_COMBOBOX - -// ---------------------------------------------------------------------------- -// wxGridCellEnumEditor -// ---------------------------------------------------------------------------- - -// A cell editor which displays an enum number as a textual equivalent. eg -// data in cell is 0,1,2 ... n the cell could be displayed as -// "John","Fred"..."Bob" in the combo choice box - -wxGridCellEnumEditor::wxGridCellEnumEditor(const wxString& choices) - :wxGridCellChoiceEditor() -{ - m_startint = -1; - - if (!choices.empty()) - SetParameters(choices); -} - -wxGridCellEditor *wxGridCellEnumEditor::Clone() const -{ - wxGridCellEnumEditor *editor = new wxGridCellEnumEditor(); - editor->m_startint = m_startint; - return editor; -} - -void wxGridCellEnumEditor::BeginEdit(int row, int col, wxGrid* grid) -{ - wxASSERT_MSG(m_control, - wxT("The wxGridCellEnumEditor must be Created first!")); - - wxGridTableBase *table = grid->GetTable(); - - if ( table->CanGetValueAs(row, col, wxGRID_VALUE_NUMBER) ) - { - m_startint = table->GetValueAsLong(row, col); - } - else - { - wxString startValue = table->GetValue(row, col); - if (startValue.IsNumber() && !startValue.empty()) - { - startValue.ToLong(&m_startint); - } - else - { - m_startint=-1; - } - } - - Combo()->SetSelection(m_startint); - Combo()->SetInsertionPointEnd(); - Combo()->SetFocus(); - -} - -bool wxGridCellEnumEditor::EndEdit(int row, int col, wxGrid* grid) -{ - int pos = Combo()->GetSelection(); - bool changed = (pos != m_startint); - if (changed) - { - if (grid->GetTable()->CanSetValueAs(row, col, wxGRID_VALUE_NUMBER)) - grid->GetTable()->SetValueAsLong(row, col, pos); - else - grid->GetTable()->SetValue(row, col,wxString::Format(wxT("%i"),pos)); - } - - return changed; -} - -#endif // wxUSE_COMBOBOX - -// ---------------------------------------------------------------------------- -// wxGridCellAutoWrapStringEditor -// ---------------------------------------------------------------------------- - -void -wxGridCellAutoWrapStringEditor::Create(wxWindow* parent, - wxWindowID id, - wxEvtHandler* evtHandler) -{ - m_control = new wxTextCtrl(parent, id, wxEmptyString, - wxDefaultPosition, wxDefaultSize, - wxTE_MULTILINE | wxTE_RICH); - - - wxGridCellEditor::Create(parent, id, evtHandler); -} - -void -wxGridCellAutoWrapStringRenderer::Draw(wxGrid& grid, - wxGridCellAttr& attr, - wxDC& dc, - const wxRect& rectCell, - int row, int col, - bool isSelected) { - - - wxGridCellRenderer::Draw(grid, attr, dc, rectCell, row, col, isSelected); - - // now we only have to draw the text - SetTextColoursAndFont(grid, attr, dc, isSelected); - - int horizAlign, vertAlign; - attr.GetAlignment(&horizAlign, &vertAlign); - - wxRect rect = rectCell; - rect.Inflate(-1); - - grid.DrawTextRectangle(dc, GetTextLines(grid,dc,attr,rect,row,col), - rect, horizAlign, vertAlign); -} - - -wxArrayString -wxGridCellAutoWrapStringRenderer::GetTextLines(wxGrid& grid, - wxDC& dc, - const wxGridCellAttr& attr, - const wxRect& rect, - int row, int col) -{ - wxString data = grid.GetCellValue(row, col); - - wxArrayString lines; - dc.SetFont(attr.GetFont()); - - //Taken from wxGrid again! - wxCoord x = 0, y = 0, curr_x = 0; - wxCoord max_x = rect.GetWidth(); - - dc.SetFont(attr.GetFont()); - wxStringTokenizer tk(data , _T(" \n\t\r")); - wxString thisline = wxEmptyString; - - while ( tk.HasMoreTokens() ) - { - wxString tok = tk.GetNextToken(); - //FIXME: this causes us to print an extra unnecesary - // space at the end of the line. But it - // is invisible , simplifies the size calculation - // and ensures tokens are separated in the display - tok += _T(" "); - - dc.GetTextExtent(tok, &x, &y); - if ( curr_x + x > max_x) - { - lines.Add( wxString(thisline) ); - thisline = tok; - curr_x=x; - } - else - { - thisline+= tok; - curr_x += x; - } - } - //Add last line - lines.Add( wxString(thisline) ); - - return lines; -} - - -wxSize -wxGridCellAutoWrapStringRenderer::GetBestSize(wxGrid& grid, - wxGridCellAttr& attr, - wxDC& dc, - int row, int col) -{ - wxCoord x,y, height , width = grid.GetColSize(col) -10; - int count = 250; //Limit iterations.. - - wxRect rect(0,0,width,10); - - // M is a nice large character 'y' gives descender!. - dc.GetTextExtent(wxT("My"), &x, &y); - - do - { - width+=10; - rect.SetWidth(width); - height = y * (wx_truncate_cast(wxCoord, GetTextLines(grid,dc,attr,rect,row,col).GetCount())); - count--; - // Search for a shape no taller than the golden ratio. - } while (count && (width < (height*1.68)) ); - - - return wxSize(width,height); -} - -#endif // wxUSE_GRID - +/////////////////////////////////////////////////////////////////////////// +// Name: generic/gridctrl.cpp +// Purpose: wxGrid controls +// Author: Paul Gammans, Roger Gammans +// Modified by: +// Created: 11/04/2001 +// RCS-ID: $Id: gridctrl.cpp 41587 2006-10-03 14:28:36Z PC $ +// Copyright: (c) The Computer Surgery (paul@compsurg.co.uk) +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_GRID + +#include "wx/generic/gridctrl.h" + +#ifndef WX_PRECOMP + #include "wx/textctrl.h" + #include "wx/dc.h" + #include "wx/combobox.h" +#endif // WX_PRECOMP + +#include "wx/tokenzr.h" + +// ---------------------------------------------------------------------------- +// wxGridCellDateTimeRenderer +// ---------------------------------------------------------------------------- + +#if wxUSE_DATETIME + +// Enables a grid cell to display a formatted date and or time + +wxGridCellDateTimeRenderer::wxGridCellDateTimeRenderer(const wxString& outformat, const wxString& informat) +{ + m_iformat = informat; + m_oformat = outformat; + m_tz = wxDateTime::Local; + m_dateDef = wxDefaultDateTime; +} + +wxGridCellRenderer *wxGridCellDateTimeRenderer::Clone() const +{ + wxGridCellDateTimeRenderer *renderer = new wxGridCellDateTimeRenderer; + renderer->m_iformat = m_iformat; + renderer->m_oformat = m_oformat; + renderer->m_dateDef = m_dateDef; + renderer->m_tz = m_tz; + + return renderer; +} + +wxString wxGridCellDateTimeRenderer::GetString(const wxGrid& grid, int row, int col) +{ + wxGridTableBase *table = grid.GetTable(); + + bool hasDatetime = false; + wxDateTime val; + wxString text; + if ( table->CanGetValueAs(row, col, wxGRID_VALUE_DATETIME) ) + { + void * tempval = table->GetValueAsCustom(row, col,wxGRID_VALUE_DATETIME); + + if (tempval){ + val = *((wxDateTime *)tempval); + hasDatetime = true; + delete (wxDateTime *)tempval; + } + + } + + if (!hasDatetime ) + { + text = table->GetValue(row, col); + hasDatetime = (val.ParseFormat( text, m_iformat, m_dateDef ) != (wxChar *)NULL) ; + } + + if ( hasDatetime ) + text = val.Format(m_oformat, m_tz ); + + //If we faild to parse string just show what we where given? + return text; +} + +void wxGridCellDateTimeRenderer::Draw(wxGrid& grid, + wxGridCellAttr& attr, + wxDC& dc, + const wxRect& rectCell, + int row, int col, + bool isSelected) +{ + wxGridCellRenderer::Draw(grid, attr, dc, rectCell, row, col, isSelected); + + SetTextColoursAndFont(grid, attr, dc, isSelected); + + // draw the text right aligned by default + int hAlign, vAlign; + attr.GetAlignment(&hAlign, &vAlign); + hAlign = wxRIGHT; + + wxRect rect = rectCell; + rect.Inflate(-1); + + grid.DrawTextRectangle(dc, GetString(grid, row, col), rect, hAlign, vAlign); +} + +wxSize wxGridCellDateTimeRenderer::GetBestSize(wxGrid& grid, + wxGridCellAttr& attr, + wxDC& dc, + int row, int col) +{ + return DoGetBestSize(attr, dc, GetString(grid, row, col)); +} + +void wxGridCellDateTimeRenderer::SetParameters(const wxString& params) +{ + if (!params.empty()) + m_oformat=params; +} + +#endif // wxUSE_DATETIME + +// ---------------------------------------------------------------------------- +// wxGridCellChoiceNumberRenderer +// ---------------------------------------------------------------------------- +// Renders a number as a textual equivalent. +// eg data in cell is 0,1,2 ... n the cell could be rendered as "John","Fred"..."Bob" + + +wxGridCellEnumRenderer::wxGridCellEnumRenderer(const wxString& choices) +{ + if (!choices.empty()) + SetParameters(choices); +} + +wxGridCellRenderer *wxGridCellEnumRenderer::Clone() const +{ + wxGridCellEnumRenderer *renderer = new wxGridCellEnumRenderer; + renderer->m_choices = m_choices; + return renderer; +} + +wxString wxGridCellEnumRenderer::GetString(const wxGrid& grid, int row, int col) +{ + wxGridTableBase *table = grid.GetTable(); + wxString text; + if ( table->CanGetValueAs(row, col, wxGRID_VALUE_NUMBER) ) + { + int choiceno = table->GetValueAsLong(row, col); + text.Printf(_T("%s"), m_choices[ choiceno ].c_str() ); + } + else + { + text = table->GetValue(row, col); + } + + + //If we faild to parse string just show what we where given? + return text; +} + +void wxGridCellEnumRenderer::Draw(wxGrid& grid, + wxGridCellAttr& attr, + wxDC& dc, + const wxRect& rectCell, + int row, int col, + bool isSelected) +{ + wxGridCellRenderer::Draw(grid, attr, dc, rectCell, row, col, isSelected); + + SetTextColoursAndFont(grid, attr, dc, isSelected); + + // draw the text right aligned by default + int hAlign, vAlign; + attr.GetAlignment(&hAlign, &vAlign); + hAlign = wxRIGHT; + + wxRect rect = rectCell; + rect.Inflate(-1); + + grid.DrawTextRectangle(dc, GetString(grid, row, col), rect, hAlign, vAlign); +} + +wxSize wxGridCellEnumRenderer::GetBestSize(wxGrid& grid, + wxGridCellAttr& attr, + wxDC& dc, + int row, int col) +{ + return DoGetBestSize(attr, dc, GetString(grid, row, col)); +} + +void wxGridCellEnumRenderer::SetParameters(const wxString& params) +{ + if ( !params ) + { + // what can we do? + return; + } + + m_choices.Empty(); + + wxStringTokenizer tk(params, _T(',')); + while ( tk.HasMoreTokens() ) + { + m_choices.Add(tk.GetNextToken()); + } +} + +#if wxUSE_COMBOBOX + +// ---------------------------------------------------------------------------- +// wxGridCellEnumEditor +// ---------------------------------------------------------------------------- + +// A cell editor which displays an enum number as a textual equivalent. eg +// data in cell is 0,1,2 ... n the cell could be displayed as +// "John","Fred"..."Bob" in the combo choice box + +wxGridCellEnumEditor::wxGridCellEnumEditor(const wxString& choices) + :wxGridCellChoiceEditor() +{ + m_startint = -1; + + if (!choices.empty()) + SetParameters(choices); +} + +wxGridCellEditor *wxGridCellEnumEditor::Clone() const +{ + wxGridCellEnumEditor *editor = new wxGridCellEnumEditor(); + editor->m_startint = m_startint; + return editor; +} + +void wxGridCellEnumEditor::BeginEdit(int row, int col, wxGrid* grid) +{ + wxASSERT_MSG(m_control, + wxT("The wxGridCellEnumEditor must be Created first!")); + + wxGridTableBase *table = grid->GetTable(); + + if ( table->CanGetValueAs(row, col, wxGRID_VALUE_NUMBER) ) + { + m_startint = table->GetValueAsLong(row, col); + } + else + { + wxString startValue = table->GetValue(row, col); + if (startValue.IsNumber() && !startValue.empty()) + { + startValue.ToLong(&m_startint); + } + else + { + m_startint=-1; + } + } + + Combo()->SetSelection(m_startint); + Combo()->SetInsertionPointEnd(); + Combo()->SetFocus(); + +} + +bool wxGridCellEnumEditor::EndEdit(int row, int col, wxGrid* grid) +{ + int pos = Combo()->GetSelection(); + bool changed = (pos != m_startint); + if (changed) + { + if (grid->GetTable()->CanSetValueAs(row, col, wxGRID_VALUE_NUMBER)) + grid->GetTable()->SetValueAsLong(row, col, pos); + else + grid->GetTable()->SetValue(row, col,wxString::Format(wxT("%i"),pos)); + } + + return changed; +} + +#endif // wxUSE_COMBOBOX + +// ---------------------------------------------------------------------------- +// wxGridCellAutoWrapStringEditor +// ---------------------------------------------------------------------------- + +void +wxGridCellAutoWrapStringEditor::Create(wxWindow* parent, + wxWindowID id, + wxEvtHandler* evtHandler) +{ + m_control = new wxTextCtrl(parent, id, wxEmptyString, + wxDefaultPosition, wxDefaultSize, + wxTE_MULTILINE | wxTE_RICH); + + + wxGridCellEditor::Create(parent, id, evtHandler); +} + +void +wxGridCellAutoWrapStringRenderer::Draw(wxGrid& grid, + wxGridCellAttr& attr, + wxDC& dc, + const wxRect& rectCell, + int row, int col, + bool isSelected) { + + + wxGridCellRenderer::Draw(grid, attr, dc, rectCell, row, col, isSelected); + + // now we only have to draw the text + SetTextColoursAndFont(grid, attr, dc, isSelected); + + int horizAlign, vertAlign; + attr.GetAlignment(&horizAlign, &vertAlign); + + wxRect rect = rectCell; + rect.Inflate(-1); + + grid.DrawTextRectangle(dc, GetTextLines(grid,dc,attr,rect,row,col), + rect, horizAlign, vertAlign); +} + + +wxArrayString +wxGridCellAutoWrapStringRenderer::GetTextLines(wxGrid& grid, + wxDC& dc, + const wxGridCellAttr& attr, + const wxRect& rect, + int row, int col) +{ + wxString data = grid.GetCellValue(row, col); + + wxArrayString lines; + dc.SetFont(attr.GetFont()); + + //Taken from wxGrid again! + wxCoord x = 0, y = 0, curr_x = 0; + wxCoord max_x = rect.GetWidth(); + + dc.SetFont(attr.GetFont()); + wxStringTokenizer tk(data , _T(" \n\t\r")); + wxString thisline = wxEmptyString; + + while ( tk.HasMoreTokens() ) + { + wxString tok = tk.GetNextToken(); + //FIXME: this causes us to print an extra unnecesary + // space at the end of the line. But it + // is invisible , simplifies the size calculation + // and ensures tokens are separated in the display + tok += _T(" "); + + dc.GetTextExtent(tok, &x, &y); + if ( curr_x + x > max_x) + { + lines.Add( wxString(thisline) ); + thisline = tok; + curr_x=x; + } + else + { + thisline+= tok; + curr_x += x; + } + } + //Add last line + lines.Add( wxString(thisline) ); + + return lines; +} + + +wxSize +wxGridCellAutoWrapStringRenderer::GetBestSize(wxGrid& grid, + wxGridCellAttr& attr, + wxDC& dc, + int row, int col) +{ + wxCoord x,y, height , width = grid.GetColSize(col) -10; + int count = 250; //Limit iterations.. + + wxRect rect(0,0,width,10); + + // M is a nice large character 'y' gives descender!. + dc.GetTextExtent(wxT("My"), &x, &y); + + do + { + width+=10; + rect.SetWidth(width); + height = y * (wx_truncate_cast(wxCoord, GetTextLines(grid,dc,attr,rect,row,col).GetCount())); + count--; + // Search for a shape no taller than the golden ratio. + } while (count && (width < (height*1.68)) ); + + + return wxSize(width,height); +} + +#endif // wxUSE_GRID + diff --git a/Externals/wxWidgets/src/generic/gridsel.cpp b/Externals/wxWidgets/src/generic/gridsel.cpp index 7385a0e5f3..13ee80a6c7 100644 --- a/Externals/wxWidgets/src/generic/gridsel.cpp +++ b/Externals/wxWidgets/src/generic/gridsel.cpp @@ -1,1177 +1,1177 @@ -/////////////////////////////////////////////////////////////////////////// -// Name: src/generic/gridsel.cpp -// Purpose: wxGridSelection -// Author: Stefan Neis -// Modified by: -// Created: 20/02/1999 -// RCS-ID: $Id: gridsel.cpp 38788 2006-04-18 08:11:26Z ABX $ -// Copyright: (c) Stefan Neis (Stefan.Neis@t-online.de) -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx/wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -#if wxUSE_GRID - -#include "wx/generic/gridsel.h" - - -// Some explanation for the members of the class: -// m_cellSelection stores individual selected cells -// -- this is only used if m_selectionMode == wxGridSelectCells -// m_blockSelectionTopLeft and m_blockSelectionBottomRight -// store the upper left and lower right corner of selected Blocks -// m_rowSelection and m_colSelection store individual selected -// rows and columns; maybe those are superfluous and should be -// treated as blocks? - -wxGridSelection::wxGridSelection( wxGrid * grid, - wxGrid::wxGridSelectionModes sel ) -{ - m_grid = grid; - m_selectionMode = sel; -} - -bool wxGridSelection::IsSelection() -{ - return ( m_cellSelection.GetCount() || m_blockSelectionTopLeft.GetCount() || - m_rowSelection.GetCount() || m_colSelection.GetCount() ); -} - -bool wxGridSelection::IsInSelection( int row, int col ) -{ - size_t count; - - // First check whether the given cell is individually selected - // (if m_selectionMode is wxGridSelectCells). - if ( m_selectionMode == wxGrid::wxGridSelectCells ) - { - count = m_cellSelection.GetCount(); - for ( size_t n = 0; n < count; n++ ) - { - wxGridCellCoords& coords = m_cellSelection[n]; - if ( row == coords.GetRow() && col == coords.GetCol() ) - return true; - } - } - - // Now check whether the given cell is - // contained in one of the selected blocks. - count = m_blockSelectionTopLeft.GetCount(); - for ( size_t n = 0; n < count; n++ ) - { - wxGridCellCoords& coords1 = m_blockSelectionTopLeft[n]; - wxGridCellCoords& coords2 = m_blockSelectionBottomRight[n]; - if ( BlockContainsCell(coords1.GetRow(), coords1.GetCol(), - coords2.GetRow(), coords2.GetCol(), - row, col ) ) - return true; - } - - // Now check whether the given cell is - // contained in one of the selected rows - // (unless we are in column selection mode). - if ( m_selectionMode != wxGrid::wxGridSelectColumns ) - { - count = m_rowSelection.GetCount(); - for ( size_t n = 0; n < count; n++ ) - { - if ( row == m_rowSelection[n] ) - return true; - } - } - - // Now check whether the given cell is - // contained in one of the selected columns - // (unless we are in row selection mode). - if ( m_selectionMode != wxGrid::wxGridSelectRows ) - { - count = m_colSelection.GetCount(); - for ( size_t n = 0; n < count; n++ ) - { - if ( col == m_colSelection[n] ) - return true; - } - } - - return false; -} - -// Change the selection mode -void wxGridSelection::SetSelectionMode( wxGrid::wxGridSelectionModes selmode ) -{ - // if selection mode is unchanged return immediately - if (selmode == m_selectionMode) - return; - - if ( m_selectionMode != wxGrid::wxGridSelectCells ) - { - // if changing form row to column selection - // or vice versa, clear the selection. - if ( selmode != wxGrid::wxGridSelectCells ) - ClearSelection(); - - m_selectionMode = selmode; - } - else - { - // if changing from cell selection to something else, - // promote selected cells/blocks to whole rows/columns. - size_t n; - while ( ( n = m_cellSelection.GetCount() ) > 0 ) - { - n--; - wxGridCellCoords& coords = m_cellSelection[n]; - int row = coords.GetRow(); - int col = coords.GetCol(); - m_cellSelection.RemoveAt(n); - if (selmode == wxGrid::wxGridSelectRows) - SelectRow( row ); - else // selmode == wxGridSelectColumns) - SelectCol( col ); - } - - // Note that m_blockSelectionTopLeft's size may be changing! - for (n = 0; n < m_blockSelectionTopLeft.GetCount(); n++) - { - wxGridCellCoords& coords = m_blockSelectionTopLeft[n]; - int topRow = coords.GetRow(); - int leftCol = coords.GetCol(); - coords = m_blockSelectionBottomRight[n]; - int bottomRow = coords.GetRow(); - int rightCol = coords.GetCol(); - - if (selmode == wxGrid::wxGridSelectRows) - { - if (leftCol != 0 || rightCol != m_grid->GetNumberCols() - 1 ) - { - m_blockSelectionTopLeft.RemoveAt(n); - m_blockSelectionBottomRight.RemoveAt(n); - SelectBlock( topRow, 0, - bottomRow, m_grid->GetNumberCols() - 1, - false, false, false, false, false ); - } - } - else // selmode == wxGridSelectColumns) - { - if (topRow != 0 || bottomRow != m_grid->GetNumberRows() - 1 ) - { - m_blockSelectionTopLeft.RemoveAt(n); - m_blockSelectionBottomRight.RemoveAt(n); - SelectBlock( 0, leftCol, - m_grid->GetNumberRows() - 1, rightCol, - false, false, false, false, false ); - } - } - } - - m_selectionMode = selmode; - } -} - -void wxGridSelection::SelectRow( int row, - bool ControlDown, bool ShiftDown, - bool AltDown, bool MetaDown ) -{ - if ( m_selectionMode == wxGrid::wxGridSelectColumns ) - return; - - size_t count, n; - - // Remove single cells contained in newly selected block. - if ( m_selectionMode == wxGrid::wxGridSelectCells ) - { - count = m_cellSelection.GetCount(); - for ( n = 0; n < count; n++ ) - { - wxGridCellCoords& coords = m_cellSelection[n]; - if ( BlockContainsCell( row, 0, row, m_grid->GetNumberCols() - 1, - coords.GetRow(), coords.GetCol() ) ) - { - m_cellSelection.RemoveAt(n); - n--; - count--; - } - } - } - - // Simplify list of selected blocks (if possible) - count = m_blockSelectionTopLeft.GetCount(); - bool done = false; - - for ( n = 0; n < count; n++ ) - { - wxGridCellCoords& coords1 = m_blockSelectionTopLeft[n]; - wxGridCellCoords& coords2 = m_blockSelectionBottomRight[n]; - - // Remove block if it is a subset of the row - if ( coords1.GetRow() == row && row == coords2.GetRow() ) - { - m_blockSelectionTopLeft.RemoveAt(n); - m_blockSelectionBottomRight.RemoveAt(n); - n--; - count--; - } - else if ( coords1.GetCol() == 0 && - coords2.GetCol() == m_grid->GetNumberCols() - 1 ) - { - // silently return, if row is contained in block - if ( coords1.GetRow() <= row && row <= coords2.GetRow() ) - return; - // expand block, if it touched row - else if ( coords1.GetRow() == row + 1) - { - coords1.SetRow(row); - done = true; - } - else if ( coords2.GetRow() == row - 1) - { - coords2.SetRow(row); - done = true; - } - } - } - - // Unless we successfully handled the row, - // check whether row is already selected. - if ( !done ) - { - count = m_rowSelection.GetCount(); - for ( n = 0; n < count; n++ ) - { - if ( row == m_rowSelection[n] ) - return; - } - - // Add row to selection - m_rowSelection.Add(row); - } - - // Update View: - if ( !m_grid->GetBatchCount() ) - { - wxRect r = m_grid->BlockToDeviceRect( wxGridCellCoords( row, 0 ), - wxGridCellCoords( row, m_grid->GetNumberCols() - 1 ) ); - ((wxWindow *)m_grid->m_gridWin)->Refresh( false, &r ); - } - - // Send Event - wxGridRangeSelectEvent gridEvt( m_grid->GetId(), - wxEVT_GRID_RANGE_SELECT, - m_grid, - wxGridCellCoords( row, 0 ), - wxGridCellCoords( row, m_grid->GetNumberCols() - 1 ), - true, - ControlDown, ShiftDown, - AltDown, MetaDown ); - - m_grid->GetEventHandler()->ProcessEvent( gridEvt ); -} - -void wxGridSelection::SelectCol( int col, - bool ControlDown, bool ShiftDown, - bool AltDown, bool MetaDown ) -{ - if ( m_selectionMode == wxGrid::wxGridSelectRows ) - return; - size_t count, n; - - // Remove single cells contained in newly selected block. - if ( m_selectionMode == wxGrid::wxGridSelectCells ) - { - count = m_cellSelection.GetCount(); - for ( n = 0; n < count; n++ ) - { - wxGridCellCoords& coords = m_cellSelection[n]; - if ( BlockContainsCell( 0, col, m_grid->GetNumberRows() - 1, col, - coords.GetRow(), coords.GetCol() ) ) - { - m_cellSelection.RemoveAt(n); - n--; - count--; - } - } - } - - // Simplify list of selected blocks (if possible) - count = m_blockSelectionTopLeft.GetCount(); - bool done = false; - for ( n = 0; n < count; n++ ) - { - wxGridCellCoords& coords1 = m_blockSelectionTopLeft[n]; - wxGridCellCoords& coords2 = m_blockSelectionBottomRight[n]; - - // Remove block if it is a subset of the column - if ( coords1.GetCol() == col && col == coords2.GetCol() ) - { - m_blockSelectionTopLeft.RemoveAt(n); - m_blockSelectionBottomRight.RemoveAt(n); - n--; - count--; - } - else if ( coords1.GetRow() == 0 && - coords2.GetRow() == m_grid->GetNumberRows() - 1 ) - { - // silently return, if row is contained in block - if ( coords1.GetCol() <= col && col <= coords2.GetCol() ) - return; - // expand block, if it touched col - else if ( coords1.GetCol() == col + 1) - { - coords1.SetCol(col); - done = true; - } - else if ( coords2.GetCol() == col - 1) - { - coords2.SetCol(col); - done = true; - } - } - } - - // Unless we successfully handled the column, - // Check whether col is already selected. - if ( !done ) - { - count = m_colSelection.GetCount(); - for ( n = 0; n < count; n++ ) - { - if ( col == m_colSelection[n] ) - return; - } - - // Add col to selection - m_colSelection.Add(col); - } - - // Update View: - if ( !m_grid->GetBatchCount() ) - { - wxRect r = m_grid->BlockToDeviceRect( wxGridCellCoords( 0, col ), - wxGridCellCoords( m_grid->GetNumberRows() - 1, col ) ); - ((wxWindow *)m_grid->m_gridWin)->Refresh( false, &r ); - } - - // Send Event - wxGridRangeSelectEvent gridEvt( m_grid->GetId(), - wxEVT_GRID_RANGE_SELECT, - m_grid, - wxGridCellCoords( 0, col ), - wxGridCellCoords( m_grid->GetNumberRows() - 1, col ), - true, - ControlDown, ShiftDown, - AltDown, MetaDown ); - - m_grid->GetEventHandler()->ProcessEvent( gridEvt ); -} - -void wxGridSelection::SelectBlock( int topRow, int leftCol, - int bottomRow, int rightCol, - bool ControlDown, bool ShiftDown, - bool AltDown, bool MetaDown, - bool sendEvent ) -{ - // Fix the coordinates of the block if needed. - if ( m_selectionMode == wxGrid::wxGridSelectRows ) - { - leftCol = 0; - rightCol = m_grid->GetNumberCols() - 1; - } - else if ( m_selectionMode == wxGrid::wxGridSelectColumns ) - { - topRow = 0; - bottomRow = m_grid->GetNumberRows() - 1; - } - - if ( topRow > bottomRow ) - { - int temp = topRow; - topRow = bottomRow; - bottomRow = temp; - } - - if ( leftCol > rightCol ) - { - int temp = leftCol; - leftCol = rightCol; - rightCol = temp; - } - - // Handle single cell selection in SelectCell. - // (MB: added check for selection mode here to prevent - // crashes if, for example, we are select rows and the - // grid only has 1 col) - if ( m_selectionMode == wxGrid::wxGridSelectCells && - topRow == bottomRow && leftCol == rightCol ) - { - SelectCell( topRow, leftCol, ControlDown, ShiftDown, - AltDown, MetaDown, sendEvent ); - } - - size_t count, n; - - // Remove single cells contained in newly selected block. - if ( m_selectionMode == wxGrid::wxGridSelectCells ) - { - count = m_cellSelection.GetCount(); - for ( n = 0; n < count; n++ ) - { - wxGridCellCoords& coords = m_cellSelection[n]; - if ( BlockContainsCell( topRow, leftCol, bottomRow, rightCol, - coords.GetRow(), coords.GetCol() ) ) - { - m_cellSelection.RemoveAt(n); - n--; - count--; - } - } - } - - // If a block containing the selection is already selected, return, - // if a block contained in the selection is found, remove it. - - count = m_blockSelectionTopLeft.GetCount(); - for ( n = 0; n < count; n++ ) - { - wxGridCellCoords& coords1 = m_blockSelectionTopLeft[n]; - wxGridCellCoords& coords2 = m_blockSelectionBottomRight[n]; - - switch ( BlockContain( coords1.GetRow(), coords1.GetCol(), - coords2.GetRow(), coords2.GetCol(), - topRow, leftCol, bottomRow, rightCol ) ) - { - case 1: - return; - - case -1: - m_blockSelectionTopLeft.RemoveAt(n); - m_blockSelectionBottomRight.RemoveAt(n); - n--; - count--; - break; - - default: - break; - } - } - - // If a row containing the selection is already selected, return, - // if a row contained in newly selected block is found, remove it. - if ( m_selectionMode != wxGrid::wxGridSelectColumns ) - { - count = m_rowSelection.GetCount(); - for ( n = 0; n < count; n++ ) - { - switch ( BlockContain( m_rowSelection[n], 0, - m_rowSelection[n], m_grid->GetNumberCols() - 1, - topRow, leftCol, bottomRow, rightCol ) ) - { - case 1: - return; - - case -1: - m_rowSelection.RemoveAt(n); - n--; - count--; - break; - - default: - break; - } - } - } - - if ( m_selectionMode != wxGrid::wxGridSelectRows ) - { - count = m_colSelection.GetCount(); - for ( n = 0; n < count; n++ ) - { - switch ( BlockContain( 0, m_colSelection[n], - m_grid->GetNumberRows() - 1, m_colSelection[n], - topRow, leftCol, bottomRow, rightCol ) ) - { - case 1: - return; - - case -1: - m_colSelection.RemoveAt(n); - n--; - count--; - break; - - default: - break; - } - } - } - - m_blockSelectionTopLeft.Add( wxGridCellCoords( topRow, leftCol ) ); - m_blockSelectionBottomRight.Add( wxGridCellCoords( bottomRow, rightCol ) ); - - // Update View: - if ( !m_grid->GetBatchCount() ) - { - wxRect r = m_grid->BlockToDeviceRect( wxGridCellCoords( topRow, leftCol ), - wxGridCellCoords( bottomRow, rightCol ) ); - ((wxWindow *)m_grid->m_gridWin)->Refresh( false, &r ); - } - - // Send Event, if not disabled. - if ( sendEvent ) - { - wxGridRangeSelectEvent gridEvt( m_grid->GetId(), - wxEVT_GRID_RANGE_SELECT, - m_grid, - wxGridCellCoords( topRow, leftCol ), - wxGridCellCoords( bottomRow, rightCol ), - true, - ControlDown, ShiftDown, - AltDown, MetaDown ); - m_grid->GetEventHandler()->ProcessEvent( gridEvt ); - } -} - -void wxGridSelection::SelectCell( int row, int col, - bool ControlDown, bool ShiftDown, - bool AltDown, bool MetaDown, - bool sendEvent ) -{ - if ( m_selectionMode == wxGrid::wxGridSelectRows ) - { - SelectBlock(row, 0, row, m_grid->GetNumberCols() - 1, - ControlDown, ShiftDown, AltDown, MetaDown, sendEvent); - - return; - } - else if ( m_selectionMode == wxGrid::wxGridSelectColumns ) - { - SelectBlock(0, col, m_grid->GetNumberRows() - 1, col, - ControlDown, ShiftDown, AltDown, MetaDown, sendEvent); - - return; - } - else if ( IsInSelection ( row, col ) ) - return; - - m_cellSelection.Add( wxGridCellCoords( row, col ) ); - - // Update View: - if ( !m_grid->GetBatchCount() ) - { - wxRect r = m_grid->BlockToDeviceRect( - wxGridCellCoords( row, col ), - wxGridCellCoords( row, col ) ); - ((wxWindow *)m_grid->m_gridWin)->Refresh( false, &r ); - } - - // Send event - if (sendEvent) - { - wxGridRangeSelectEvent gridEvt( m_grid->GetId(), - wxEVT_GRID_RANGE_SELECT, - m_grid, - wxGridCellCoords( row, col ), - wxGridCellCoords( row, col ), - true, - ControlDown, ShiftDown, - AltDown, MetaDown ); - m_grid->GetEventHandler()->ProcessEvent( gridEvt ); - } -} - -void wxGridSelection::ToggleCellSelection( int row, int col, - bool ControlDown, bool ShiftDown, - bool AltDown, bool MetaDown ) -{ - // if the cell is not selected, select it - if ( !IsInSelection ( row, col ) ) - { - SelectCell( row, col, ControlDown, ShiftDown, AltDown, MetaDown ); - - return; - } - - // otherwise deselect it. This can be simple or more or - // less difficult, depending on how the cell is selected. - size_t count, n; - - // The simplest case: The cell is contained in m_cellSelection - // Then it can't be contained in rows/cols/block (since those - // would remove the cell from m_cellSelection on creation), so - // we just have to remove it from m_cellSelection. - - if ( m_selectionMode == wxGrid::wxGridSelectCells ) - { - count = m_cellSelection.GetCount(); - for ( n = 0; n < count; n++ ) - { - const wxGridCellCoords& sel = m_cellSelection[n]; - if ( row == sel.GetRow() && col == sel.GetCol() ) - { - wxGridCellCoords coords = m_cellSelection[n]; - m_cellSelection.RemoveAt(n); - if ( !m_grid->GetBatchCount() ) - { - wxRect r = m_grid->BlockToDeviceRect( coords, coords ); - ((wxWindow *)m_grid->m_gridWin)->Refresh( false, &r ); - } - - // Send event - wxGridRangeSelectEvent gridEvt( m_grid->GetId(), - wxEVT_GRID_RANGE_SELECT, - m_grid, - wxGridCellCoords( row, col ), - wxGridCellCoords( row, col ), - false, - ControlDown, ShiftDown, - AltDown, MetaDown ); - m_grid->GetEventHandler()->ProcessEvent( gridEvt ); - - return; - } - } - } - - // The most difficult case: The cell is member of one or even several - // blocks. Split each such block in up to 4 new parts, that don't - // contain the cell to be selected, like this: - // |---------------------------| - // | | - // | part 1 | - // | | - // |---------------------------| - // | part 3 |x| part 4 | - // |---------------------------| - // | | - // | part 2 | - // | | - // |---------------------------| - // (The x marks the newly deselected cell). - // Note: in row selection mode, we only need part1 and part2; - // in column selection mode, we only need part 3 and part4, - // which are expanded to whole columns automatically! - - count = m_blockSelectionTopLeft.GetCount(); - for ( n = 0; n < count; n++ ) - { - wxGridCellCoords& coords1 = m_blockSelectionTopLeft[n]; - wxGridCellCoords& coords2 = m_blockSelectionBottomRight[n]; - int topRow = coords1.GetRow(); - int leftCol = coords1.GetCol(); - int bottomRow = coords2.GetRow(); - int rightCol = coords2.GetCol(); - - if ( BlockContainsCell( topRow, leftCol, bottomRow, rightCol, row, col ) ) - { - // remove the block - m_blockSelectionTopLeft.RemoveAt(n); - m_blockSelectionBottomRight.RemoveAt(n); - n--; - count--; - - // add up to 4 smaller blocks and set update region - if ( m_selectionMode != wxGrid::wxGridSelectColumns ) - { - if ( topRow < row ) - SelectBlock( topRow, leftCol, row - 1, rightCol, - false, false, false, false, false ); - if ( bottomRow > row ) - SelectBlock( row + 1, leftCol, bottomRow, rightCol, - false, false, false, false, false ); - } - - if ( m_selectionMode != wxGrid::wxGridSelectRows ) - { - if ( leftCol < col ) - SelectBlock( row, leftCol, row, col - 1, - false, false, false, false, false ); - if ( rightCol > col ) - SelectBlock( row, col + 1, row, rightCol, - false, false, false, false, false ); - } - } - } - - // remove a cell from a row, adding up to two new blocks - if ( m_selectionMode != wxGrid::wxGridSelectColumns ) - { - count = m_rowSelection.GetCount(); - for ( n = 0; n < count; n++ ) - { - if ( m_rowSelection[n] == row ) - { - m_rowSelection.RemoveAt(n); - n--; - count--; - - if (m_selectionMode == wxGrid::wxGridSelectCells) - { - if ( col > 0 ) - SelectBlock( row, 0, row, col - 1, - false, false, false, false, false ); - if ( col < m_grid->GetNumberCols() - 1 ) - SelectBlock( row, col + 1, - row, m_grid->GetNumberCols() - 1, - false, false, false, false, false ); - } - } - } - } - - // remove a cell from a column, adding up to two new blocks - if ( m_selectionMode != wxGrid::wxGridSelectRows ) - { - count = m_colSelection.GetCount(); - for ( n = 0; n < count; n++ ) - { - if ( m_colSelection[n] == col ) - { - m_colSelection.RemoveAt(n); - n--; - count--; - - if (m_selectionMode == wxGrid::wxGridSelectCells) - { - if ( row > 0 ) - SelectBlock( 0, col, row - 1, col, - false, false, false, false, false ); - if ( row < m_grid->GetNumberRows() - 1 ) - SelectBlock( row + 1, col, - m_grid->GetNumberRows() - 1, col, - false, false, false, false, false ); - } - } - } - } - - // Refresh the screen and send the event; according to m_selectionMode, - // we need to either update only the cell, or the whole row/column. - wxRect r; - switch (m_selectionMode) - { - case wxGrid::wxGridSelectCells: - { - if ( !m_grid->GetBatchCount() ) - { - r = m_grid->BlockToDeviceRect( - wxGridCellCoords( row, col ), - wxGridCellCoords( row, col ) ); - ((wxWindow *)m_grid->m_gridWin)->Refresh( false, &r ); - } - - wxGridRangeSelectEvent gridEvt( m_grid->GetId(), - wxEVT_GRID_RANGE_SELECT, - m_grid, - wxGridCellCoords( row, col ), - wxGridCellCoords( row, col ), - false, - ControlDown, ShiftDown, - AltDown, MetaDown ); - m_grid->GetEventHandler()->ProcessEvent( gridEvt ); - } - break; - - case wxGrid::wxGridSelectRows: - { - if ( !m_grid->GetBatchCount() ) - { - r = m_grid->BlockToDeviceRect( - wxGridCellCoords( row, 0 ), - wxGridCellCoords( row, m_grid->GetNumberCols() - 1 ) ); - ((wxWindow *)m_grid->m_gridWin)->Refresh( false, &r ); - } - - wxGridRangeSelectEvent gridEvt( m_grid->GetId(), - wxEVT_GRID_RANGE_SELECT, - m_grid, - wxGridCellCoords( row, 0 ), - wxGridCellCoords( row, m_grid->GetNumberCols() - 1 ), - false, - ControlDown, ShiftDown, - AltDown, MetaDown ); - m_grid->GetEventHandler()->ProcessEvent( gridEvt ); - } - break; - - case wxGrid::wxGridSelectColumns: - { - if ( !m_grid->GetBatchCount() ) - { - r = m_grid->BlockToDeviceRect( - wxGridCellCoords( 0, col ), - wxGridCellCoords( m_grid->GetNumberRows() - 1, col ) ); - ((wxWindow *)m_grid->m_gridWin)->Refresh( false, &r ); - } - - wxGridRangeSelectEvent gridEvt( m_grid->GetId(), - wxEVT_GRID_RANGE_SELECT, - m_grid, - wxGridCellCoords( 0, col ), - wxGridCellCoords( m_grid->GetNumberRows() - 1, col ), - false, - ControlDown, ShiftDown, - AltDown, MetaDown ); - m_grid->GetEventHandler()->ProcessEvent( gridEvt ); - } - break; - - default: - break; - } -} - -void wxGridSelection::ClearSelection() -{ - size_t n; - wxRect r; - wxGridCellCoords coords1, coords2; - - // deselect all individual cells and update the screen - if ( m_selectionMode == wxGrid::wxGridSelectCells ) - { - while ( ( n = m_cellSelection.GetCount() ) > 0) - { - n--; - coords1 = m_cellSelection[n]; - m_cellSelection.RemoveAt(n); - if ( !m_grid->GetBatchCount() ) - { - r = m_grid->BlockToDeviceRect( coords1, coords1 ); - ((wxWindow *)m_grid->m_gridWin)->Refresh( false, &r ); - -#ifdef __WXMAC__ - ((wxWindow *)m_grid->m_gridWin)->Update(); -#endif - } - } - } - - // deselect all blocks and update the screen - while ( ( n = m_blockSelectionTopLeft.GetCount() ) > 0) - { - n--; - coords1 = m_blockSelectionTopLeft[n]; - coords2 = m_blockSelectionBottomRight[n]; - m_blockSelectionTopLeft.RemoveAt(n); - m_blockSelectionBottomRight.RemoveAt(n); - if ( !m_grid->GetBatchCount() ) - { - r = m_grid->BlockToDeviceRect( coords1, coords2 ); - ((wxWindow *)m_grid->m_gridWin)->Refresh( false, &r ); - -#ifdef __WXMAC__ - ((wxWindow *)m_grid->m_gridWin)->Update(); -#endif - } - } - - // deselect all rows and update the screen - if ( m_selectionMode != wxGrid::wxGridSelectColumns ) - { - while ( ( n = m_rowSelection.GetCount() ) > 0) - { - n--; - int row = m_rowSelection[n]; - m_rowSelection.RemoveAt(n); - if ( !m_grid->GetBatchCount() ) - { - r = m_grid->BlockToDeviceRect( wxGridCellCoords( row, 0 ), - wxGridCellCoords( row, m_grid->GetNumberCols() - 1 ) ); - ((wxWindow *)m_grid->m_gridWin)->Refresh( false, &r ); - -#ifdef __WXMAC__ - ((wxWindow *)m_grid->m_gridWin)->Update(); -#endif - } - } - } - - // deselect all columns and update the screen - if ( m_selectionMode != wxGrid::wxGridSelectRows ) - { - while ( ( n = m_colSelection.GetCount() ) > 0) - { - n--; - int col = m_colSelection[n]; - m_colSelection.RemoveAt(n); - if ( !m_grid->GetBatchCount() ) - { - r = m_grid->BlockToDeviceRect( wxGridCellCoords( 0, col ), - wxGridCellCoords( m_grid->GetNumberRows() - 1, col ) ); - ((wxWindow *)m_grid->m_gridWin)->Refresh( false, &r ); - -#ifdef __WXMAC__ - ((wxWindow *)m_grid->m_gridWin)->Update(); -#endif - } - } - } - - // One deselection event, indicating deselection of _all_ cells. - // (No finer grained events for each of the smaller regions - // deselected above!) - wxGridRangeSelectEvent gridEvt( m_grid->GetId(), - wxEVT_GRID_RANGE_SELECT, - m_grid, - wxGridCellCoords( 0, 0 ), - wxGridCellCoords( - m_grid->GetNumberRows() - 1, - m_grid->GetNumberCols() - 1 ), - false ); - - m_grid->GetEventHandler()->ProcessEvent(gridEvt); -} - - -void wxGridSelection::UpdateRows( size_t pos, int numRows ) -{ - size_t count = m_cellSelection.GetCount(); - size_t n; - for ( n = 0; n < count; n++ ) - { - wxGridCellCoords& coords = m_cellSelection[n]; - wxCoord row = coords.GetRow(); - if ((size_t)row >= pos) - { - if (numRows > 0) - { - // If rows inserted, increase row counter where necessary - coords.SetRow(row + numRows); - } - else if (numRows < 0) - { - // If rows deleted ... - if ((size_t)row >= pos - numRows) - { - // ...either decrement row counter (if row still exists)... - coords.SetRow(row + numRows); - } - else - { - // ...or remove the attribute - m_cellSelection.RemoveAt(n); - n--; - count--; - } - } - } - } - - count = m_blockSelectionTopLeft.GetCount(); - for ( n = 0; n < count; n++ ) - { - wxGridCellCoords& coords1 = m_blockSelectionTopLeft[n]; - wxGridCellCoords& coords2 = m_blockSelectionBottomRight[n]; - wxCoord row1 = coords1.GetRow(); - wxCoord row2 = coords2.GetRow(); - - if ((size_t)row2 >= pos) - { - if (numRows > 0) - { - // If rows inserted, increase row counter where necessary - coords2.SetRow( row2 + numRows ); - if ((size_t)row1 >= pos) - coords1.SetRow( row1 + numRows ); - } - else if (numRows < 0) - { - // If rows deleted ... - if ((size_t)row2 >= pos - numRows) - { - // ...either decrement row counter (if row still exists)... - coords2.SetRow( row2 + numRows ); - if ((size_t)row1 >= pos) - coords1.SetRow( wxMax(row1 + numRows, (int)pos) ); - - } - else - { - if ((size_t)row1 >= pos) - { - // ...or remove the attribute - m_blockSelectionTopLeft.RemoveAt(n); - m_blockSelectionBottomRight.RemoveAt(n); - n--; - count--; - } - else - coords2.SetRow( pos ); - } - } - } - } - - count = m_rowSelection.GetCount(); - for ( n = 0; n < count; n++ ) - { - int rowOrCol_ = m_rowSelection[n]; - - if ((size_t) rowOrCol_ >= pos) - { - if ( numRows > 0 ) - { - m_rowSelection[n] += numRows; - } - else if ( numRows < 0 ) - { - if ((size_t)rowOrCol_ >= (pos - numRows)) - m_rowSelection[n] += numRows; - else - { - m_rowSelection.RemoveAt( n ); - n--; - count--; - } - } - } - } - // No need to touch selected columns, unless we removed _all_ - // rows, in this case, we remove all columns from the selection. - - if ( !m_grid->GetNumberRows() ) - m_colSelection.Clear(); -} - - -void wxGridSelection::UpdateCols( size_t pos, int numCols ) -{ - size_t count = m_cellSelection.GetCount(); - size_t n; - - for ( n = 0; n < count; n++ ) - { - wxGridCellCoords& coords = m_cellSelection[n]; - wxCoord col = coords.GetCol(); - if ((size_t)col >= pos) - { - if (numCols > 0) - { - // If rows inserted, increase row counter where necessary - coords.SetCol(col + numCols); - } - else if (numCols < 0) - { - // If rows deleted ... - if ((size_t)col >= pos - numCols) - { - // ...either decrement row counter (if row still exists)... - coords.SetCol(col + numCols); - } - else - { - // ...or remove the attribute - m_cellSelection.RemoveAt(n); - n--; - count--; - } - } - } - } - - count = m_blockSelectionTopLeft.GetCount(); - for ( n = 0; n < count; n++ ) - { - wxGridCellCoords& coords1 = m_blockSelectionTopLeft[n]; - wxGridCellCoords& coords2 = m_blockSelectionBottomRight[n]; - wxCoord col1 = coords1.GetCol(); - wxCoord col2 = coords2.GetCol(); - - if ((size_t)col2 >= pos) - { - if (numCols > 0) - { - // If rows inserted, increase row counter where necessary - coords2.SetCol(col2 + numCols); - if ((size_t)col1 >= pos) - coords1.SetCol(col1 + numCols); - } - else if (numCols < 0) - { - // If cols deleted ... - if ((size_t)col2 >= pos - numCols) - { - // ...either decrement col counter (if col still exists)... - coords2.SetCol(col2 + numCols); - if ( (size_t) col1 >= pos) - coords1.SetCol( wxMax(col1 + numCols, (int)pos) ); - - } - else - { - if ((size_t)col1 >= pos) - { - // ...or remove the attribute - m_blockSelectionTopLeft.RemoveAt(n); - m_blockSelectionBottomRight.RemoveAt(n); - n--; - count--; - } - else - coords2.SetCol(pos); - } - } - } - } - - count = m_colSelection.GetCount(); - for ( n = 0; n < count; n++ ) - { - int rowOrCol = m_colSelection[n]; - - if ((size_t)rowOrCol >= pos) - { - if ( numCols > 0 ) - m_colSelection[n] += numCols; - else if ( numCols < 0 ) - { - if ((size_t)rowOrCol >= (pos - numCols)) - m_colSelection[n] += numCols; - else - { - m_colSelection.RemoveAt( n ); - n--; - count--; - } - } - } - } - - // No need to touch selected rows, unless we removed _all_ - // columns, in this case, we remove all rows from the selection. - if ( !m_grid->GetNumberCols() ) - m_rowSelection.Clear(); -} - -int wxGridSelection::BlockContain( int topRow1, int leftCol1, - int bottomRow1, int rightCol1, - int topRow2, int leftCol2, - int bottomRow2, int rightCol2 ) -// returns 1, if Block1 contains Block2, -// -1, if Block2 contains Block1, -// 0, otherwise -{ - if ( topRow1 <= topRow2 && bottomRow2 <= bottomRow1 && - leftCol1 <= leftCol2 && rightCol2 <= rightCol1 ) - return 1; - else if ( topRow2 <= topRow1 && bottomRow1 <= bottomRow2 && - leftCol2 <= leftCol1 && rightCol1 <= rightCol2 ) - return -1; - - return 0; -} - -#endif +/////////////////////////////////////////////////////////////////////////// +// Name: src/generic/gridsel.cpp +// Purpose: wxGridSelection +// Author: Stefan Neis +// Modified by: +// Created: 20/02/1999 +// RCS-ID: $Id: gridsel.cpp 38788 2006-04-18 08:11:26Z ABX $ +// Copyright: (c) Stefan Neis (Stefan.Neis@t-online.de) +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx/wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +#if wxUSE_GRID + +#include "wx/generic/gridsel.h" + + +// Some explanation for the members of the class: +// m_cellSelection stores individual selected cells +// -- this is only used if m_selectionMode == wxGridSelectCells +// m_blockSelectionTopLeft and m_blockSelectionBottomRight +// store the upper left and lower right corner of selected Blocks +// m_rowSelection and m_colSelection store individual selected +// rows and columns; maybe those are superfluous and should be +// treated as blocks? + +wxGridSelection::wxGridSelection( wxGrid * grid, + wxGrid::wxGridSelectionModes sel ) +{ + m_grid = grid; + m_selectionMode = sel; +} + +bool wxGridSelection::IsSelection() +{ + return ( m_cellSelection.GetCount() || m_blockSelectionTopLeft.GetCount() || + m_rowSelection.GetCount() || m_colSelection.GetCount() ); +} + +bool wxGridSelection::IsInSelection( int row, int col ) +{ + size_t count; + + // First check whether the given cell is individually selected + // (if m_selectionMode is wxGridSelectCells). + if ( m_selectionMode == wxGrid::wxGridSelectCells ) + { + count = m_cellSelection.GetCount(); + for ( size_t n = 0; n < count; n++ ) + { + wxGridCellCoords& coords = m_cellSelection[n]; + if ( row == coords.GetRow() && col == coords.GetCol() ) + return true; + } + } + + // Now check whether the given cell is + // contained in one of the selected blocks. + count = m_blockSelectionTopLeft.GetCount(); + for ( size_t n = 0; n < count; n++ ) + { + wxGridCellCoords& coords1 = m_blockSelectionTopLeft[n]; + wxGridCellCoords& coords2 = m_blockSelectionBottomRight[n]; + if ( BlockContainsCell(coords1.GetRow(), coords1.GetCol(), + coords2.GetRow(), coords2.GetCol(), + row, col ) ) + return true; + } + + // Now check whether the given cell is + // contained in one of the selected rows + // (unless we are in column selection mode). + if ( m_selectionMode != wxGrid::wxGridSelectColumns ) + { + count = m_rowSelection.GetCount(); + for ( size_t n = 0; n < count; n++ ) + { + if ( row == m_rowSelection[n] ) + return true; + } + } + + // Now check whether the given cell is + // contained in one of the selected columns + // (unless we are in row selection mode). + if ( m_selectionMode != wxGrid::wxGridSelectRows ) + { + count = m_colSelection.GetCount(); + for ( size_t n = 0; n < count; n++ ) + { + if ( col == m_colSelection[n] ) + return true; + } + } + + return false; +} + +// Change the selection mode +void wxGridSelection::SetSelectionMode( wxGrid::wxGridSelectionModes selmode ) +{ + // if selection mode is unchanged return immediately + if (selmode == m_selectionMode) + return; + + if ( m_selectionMode != wxGrid::wxGridSelectCells ) + { + // if changing form row to column selection + // or vice versa, clear the selection. + if ( selmode != wxGrid::wxGridSelectCells ) + ClearSelection(); + + m_selectionMode = selmode; + } + else + { + // if changing from cell selection to something else, + // promote selected cells/blocks to whole rows/columns. + size_t n; + while ( ( n = m_cellSelection.GetCount() ) > 0 ) + { + n--; + wxGridCellCoords& coords = m_cellSelection[n]; + int row = coords.GetRow(); + int col = coords.GetCol(); + m_cellSelection.RemoveAt(n); + if (selmode == wxGrid::wxGridSelectRows) + SelectRow( row ); + else // selmode == wxGridSelectColumns) + SelectCol( col ); + } + + // Note that m_blockSelectionTopLeft's size may be changing! + for (n = 0; n < m_blockSelectionTopLeft.GetCount(); n++) + { + wxGridCellCoords& coords = m_blockSelectionTopLeft[n]; + int topRow = coords.GetRow(); + int leftCol = coords.GetCol(); + coords = m_blockSelectionBottomRight[n]; + int bottomRow = coords.GetRow(); + int rightCol = coords.GetCol(); + + if (selmode == wxGrid::wxGridSelectRows) + { + if (leftCol != 0 || rightCol != m_grid->GetNumberCols() - 1 ) + { + m_blockSelectionTopLeft.RemoveAt(n); + m_blockSelectionBottomRight.RemoveAt(n); + SelectBlock( topRow, 0, + bottomRow, m_grid->GetNumberCols() - 1, + false, false, false, false, false ); + } + } + else // selmode == wxGridSelectColumns) + { + if (topRow != 0 || bottomRow != m_grid->GetNumberRows() - 1 ) + { + m_blockSelectionTopLeft.RemoveAt(n); + m_blockSelectionBottomRight.RemoveAt(n); + SelectBlock( 0, leftCol, + m_grid->GetNumberRows() - 1, rightCol, + false, false, false, false, false ); + } + } + } + + m_selectionMode = selmode; + } +} + +void wxGridSelection::SelectRow( int row, + bool ControlDown, bool ShiftDown, + bool AltDown, bool MetaDown ) +{ + if ( m_selectionMode == wxGrid::wxGridSelectColumns ) + return; + + size_t count, n; + + // Remove single cells contained in newly selected block. + if ( m_selectionMode == wxGrid::wxGridSelectCells ) + { + count = m_cellSelection.GetCount(); + for ( n = 0; n < count; n++ ) + { + wxGridCellCoords& coords = m_cellSelection[n]; + if ( BlockContainsCell( row, 0, row, m_grid->GetNumberCols() - 1, + coords.GetRow(), coords.GetCol() ) ) + { + m_cellSelection.RemoveAt(n); + n--; + count--; + } + } + } + + // Simplify list of selected blocks (if possible) + count = m_blockSelectionTopLeft.GetCount(); + bool done = false; + + for ( n = 0; n < count; n++ ) + { + wxGridCellCoords& coords1 = m_blockSelectionTopLeft[n]; + wxGridCellCoords& coords2 = m_blockSelectionBottomRight[n]; + + // Remove block if it is a subset of the row + if ( coords1.GetRow() == row && row == coords2.GetRow() ) + { + m_blockSelectionTopLeft.RemoveAt(n); + m_blockSelectionBottomRight.RemoveAt(n); + n--; + count--; + } + else if ( coords1.GetCol() == 0 && + coords2.GetCol() == m_grid->GetNumberCols() - 1 ) + { + // silently return, if row is contained in block + if ( coords1.GetRow() <= row && row <= coords2.GetRow() ) + return; + // expand block, if it touched row + else if ( coords1.GetRow() == row + 1) + { + coords1.SetRow(row); + done = true; + } + else if ( coords2.GetRow() == row - 1) + { + coords2.SetRow(row); + done = true; + } + } + } + + // Unless we successfully handled the row, + // check whether row is already selected. + if ( !done ) + { + count = m_rowSelection.GetCount(); + for ( n = 0; n < count; n++ ) + { + if ( row == m_rowSelection[n] ) + return; + } + + // Add row to selection + m_rowSelection.Add(row); + } + + // Update View: + if ( !m_grid->GetBatchCount() ) + { + wxRect r = m_grid->BlockToDeviceRect( wxGridCellCoords( row, 0 ), + wxGridCellCoords( row, m_grid->GetNumberCols() - 1 ) ); + ((wxWindow *)m_grid->m_gridWin)->Refresh( false, &r ); + } + + // Send Event + wxGridRangeSelectEvent gridEvt( m_grid->GetId(), + wxEVT_GRID_RANGE_SELECT, + m_grid, + wxGridCellCoords( row, 0 ), + wxGridCellCoords( row, m_grid->GetNumberCols() - 1 ), + true, + ControlDown, ShiftDown, + AltDown, MetaDown ); + + m_grid->GetEventHandler()->ProcessEvent( gridEvt ); +} + +void wxGridSelection::SelectCol( int col, + bool ControlDown, bool ShiftDown, + bool AltDown, bool MetaDown ) +{ + if ( m_selectionMode == wxGrid::wxGridSelectRows ) + return; + size_t count, n; + + // Remove single cells contained in newly selected block. + if ( m_selectionMode == wxGrid::wxGridSelectCells ) + { + count = m_cellSelection.GetCount(); + for ( n = 0; n < count; n++ ) + { + wxGridCellCoords& coords = m_cellSelection[n]; + if ( BlockContainsCell( 0, col, m_grid->GetNumberRows() - 1, col, + coords.GetRow(), coords.GetCol() ) ) + { + m_cellSelection.RemoveAt(n); + n--; + count--; + } + } + } + + // Simplify list of selected blocks (if possible) + count = m_blockSelectionTopLeft.GetCount(); + bool done = false; + for ( n = 0; n < count; n++ ) + { + wxGridCellCoords& coords1 = m_blockSelectionTopLeft[n]; + wxGridCellCoords& coords2 = m_blockSelectionBottomRight[n]; + + // Remove block if it is a subset of the column + if ( coords1.GetCol() == col && col == coords2.GetCol() ) + { + m_blockSelectionTopLeft.RemoveAt(n); + m_blockSelectionBottomRight.RemoveAt(n); + n--; + count--; + } + else if ( coords1.GetRow() == 0 && + coords2.GetRow() == m_grid->GetNumberRows() - 1 ) + { + // silently return, if row is contained in block + if ( coords1.GetCol() <= col && col <= coords2.GetCol() ) + return; + // expand block, if it touched col + else if ( coords1.GetCol() == col + 1) + { + coords1.SetCol(col); + done = true; + } + else if ( coords2.GetCol() == col - 1) + { + coords2.SetCol(col); + done = true; + } + } + } + + // Unless we successfully handled the column, + // Check whether col is already selected. + if ( !done ) + { + count = m_colSelection.GetCount(); + for ( n = 0; n < count; n++ ) + { + if ( col == m_colSelection[n] ) + return; + } + + // Add col to selection + m_colSelection.Add(col); + } + + // Update View: + if ( !m_grid->GetBatchCount() ) + { + wxRect r = m_grid->BlockToDeviceRect( wxGridCellCoords( 0, col ), + wxGridCellCoords( m_grid->GetNumberRows() - 1, col ) ); + ((wxWindow *)m_grid->m_gridWin)->Refresh( false, &r ); + } + + // Send Event + wxGridRangeSelectEvent gridEvt( m_grid->GetId(), + wxEVT_GRID_RANGE_SELECT, + m_grid, + wxGridCellCoords( 0, col ), + wxGridCellCoords( m_grid->GetNumberRows() - 1, col ), + true, + ControlDown, ShiftDown, + AltDown, MetaDown ); + + m_grid->GetEventHandler()->ProcessEvent( gridEvt ); +} + +void wxGridSelection::SelectBlock( int topRow, int leftCol, + int bottomRow, int rightCol, + bool ControlDown, bool ShiftDown, + bool AltDown, bool MetaDown, + bool sendEvent ) +{ + // Fix the coordinates of the block if needed. + if ( m_selectionMode == wxGrid::wxGridSelectRows ) + { + leftCol = 0; + rightCol = m_grid->GetNumberCols() - 1; + } + else if ( m_selectionMode == wxGrid::wxGridSelectColumns ) + { + topRow = 0; + bottomRow = m_grid->GetNumberRows() - 1; + } + + if ( topRow > bottomRow ) + { + int temp = topRow; + topRow = bottomRow; + bottomRow = temp; + } + + if ( leftCol > rightCol ) + { + int temp = leftCol; + leftCol = rightCol; + rightCol = temp; + } + + // Handle single cell selection in SelectCell. + // (MB: added check for selection mode here to prevent + // crashes if, for example, we are select rows and the + // grid only has 1 col) + if ( m_selectionMode == wxGrid::wxGridSelectCells && + topRow == bottomRow && leftCol == rightCol ) + { + SelectCell( topRow, leftCol, ControlDown, ShiftDown, + AltDown, MetaDown, sendEvent ); + } + + size_t count, n; + + // Remove single cells contained in newly selected block. + if ( m_selectionMode == wxGrid::wxGridSelectCells ) + { + count = m_cellSelection.GetCount(); + for ( n = 0; n < count; n++ ) + { + wxGridCellCoords& coords = m_cellSelection[n]; + if ( BlockContainsCell( topRow, leftCol, bottomRow, rightCol, + coords.GetRow(), coords.GetCol() ) ) + { + m_cellSelection.RemoveAt(n); + n--; + count--; + } + } + } + + // If a block containing the selection is already selected, return, + // if a block contained in the selection is found, remove it. + + count = m_blockSelectionTopLeft.GetCount(); + for ( n = 0; n < count; n++ ) + { + wxGridCellCoords& coords1 = m_blockSelectionTopLeft[n]; + wxGridCellCoords& coords2 = m_blockSelectionBottomRight[n]; + + switch ( BlockContain( coords1.GetRow(), coords1.GetCol(), + coords2.GetRow(), coords2.GetCol(), + topRow, leftCol, bottomRow, rightCol ) ) + { + case 1: + return; + + case -1: + m_blockSelectionTopLeft.RemoveAt(n); + m_blockSelectionBottomRight.RemoveAt(n); + n--; + count--; + break; + + default: + break; + } + } + + // If a row containing the selection is already selected, return, + // if a row contained in newly selected block is found, remove it. + if ( m_selectionMode != wxGrid::wxGridSelectColumns ) + { + count = m_rowSelection.GetCount(); + for ( n = 0; n < count; n++ ) + { + switch ( BlockContain( m_rowSelection[n], 0, + m_rowSelection[n], m_grid->GetNumberCols() - 1, + topRow, leftCol, bottomRow, rightCol ) ) + { + case 1: + return; + + case -1: + m_rowSelection.RemoveAt(n); + n--; + count--; + break; + + default: + break; + } + } + } + + if ( m_selectionMode != wxGrid::wxGridSelectRows ) + { + count = m_colSelection.GetCount(); + for ( n = 0; n < count; n++ ) + { + switch ( BlockContain( 0, m_colSelection[n], + m_grid->GetNumberRows() - 1, m_colSelection[n], + topRow, leftCol, bottomRow, rightCol ) ) + { + case 1: + return; + + case -1: + m_colSelection.RemoveAt(n); + n--; + count--; + break; + + default: + break; + } + } + } + + m_blockSelectionTopLeft.Add( wxGridCellCoords( topRow, leftCol ) ); + m_blockSelectionBottomRight.Add( wxGridCellCoords( bottomRow, rightCol ) ); + + // Update View: + if ( !m_grid->GetBatchCount() ) + { + wxRect r = m_grid->BlockToDeviceRect( wxGridCellCoords( topRow, leftCol ), + wxGridCellCoords( bottomRow, rightCol ) ); + ((wxWindow *)m_grid->m_gridWin)->Refresh( false, &r ); + } + + // Send Event, if not disabled. + if ( sendEvent ) + { + wxGridRangeSelectEvent gridEvt( m_grid->GetId(), + wxEVT_GRID_RANGE_SELECT, + m_grid, + wxGridCellCoords( topRow, leftCol ), + wxGridCellCoords( bottomRow, rightCol ), + true, + ControlDown, ShiftDown, + AltDown, MetaDown ); + m_grid->GetEventHandler()->ProcessEvent( gridEvt ); + } +} + +void wxGridSelection::SelectCell( int row, int col, + bool ControlDown, bool ShiftDown, + bool AltDown, bool MetaDown, + bool sendEvent ) +{ + if ( m_selectionMode == wxGrid::wxGridSelectRows ) + { + SelectBlock(row, 0, row, m_grid->GetNumberCols() - 1, + ControlDown, ShiftDown, AltDown, MetaDown, sendEvent); + + return; + } + else if ( m_selectionMode == wxGrid::wxGridSelectColumns ) + { + SelectBlock(0, col, m_grid->GetNumberRows() - 1, col, + ControlDown, ShiftDown, AltDown, MetaDown, sendEvent); + + return; + } + else if ( IsInSelection ( row, col ) ) + return; + + m_cellSelection.Add( wxGridCellCoords( row, col ) ); + + // Update View: + if ( !m_grid->GetBatchCount() ) + { + wxRect r = m_grid->BlockToDeviceRect( + wxGridCellCoords( row, col ), + wxGridCellCoords( row, col ) ); + ((wxWindow *)m_grid->m_gridWin)->Refresh( false, &r ); + } + + // Send event + if (sendEvent) + { + wxGridRangeSelectEvent gridEvt( m_grid->GetId(), + wxEVT_GRID_RANGE_SELECT, + m_grid, + wxGridCellCoords( row, col ), + wxGridCellCoords( row, col ), + true, + ControlDown, ShiftDown, + AltDown, MetaDown ); + m_grid->GetEventHandler()->ProcessEvent( gridEvt ); + } +} + +void wxGridSelection::ToggleCellSelection( int row, int col, + bool ControlDown, bool ShiftDown, + bool AltDown, bool MetaDown ) +{ + // if the cell is not selected, select it + if ( !IsInSelection ( row, col ) ) + { + SelectCell( row, col, ControlDown, ShiftDown, AltDown, MetaDown ); + + return; + } + + // otherwise deselect it. This can be simple or more or + // less difficult, depending on how the cell is selected. + size_t count, n; + + // The simplest case: The cell is contained in m_cellSelection + // Then it can't be contained in rows/cols/block (since those + // would remove the cell from m_cellSelection on creation), so + // we just have to remove it from m_cellSelection. + + if ( m_selectionMode == wxGrid::wxGridSelectCells ) + { + count = m_cellSelection.GetCount(); + for ( n = 0; n < count; n++ ) + { + const wxGridCellCoords& sel = m_cellSelection[n]; + if ( row == sel.GetRow() && col == sel.GetCol() ) + { + wxGridCellCoords coords = m_cellSelection[n]; + m_cellSelection.RemoveAt(n); + if ( !m_grid->GetBatchCount() ) + { + wxRect r = m_grid->BlockToDeviceRect( coords, coords ); + ((wxWindow *)m_grid->m_gridWin)->Refresh( false, &r ); + } + + // Send event + wxGridRangeSelectEvent gridEvt( m_grid->GetId(), + wxEVT_GRID_RANGE_SELECT, + m_grid, + wxGridCellCoords( row, col ), + wxGridCellCoords( row, col ), + false, + ControlDown, ShiftDown, + AltDown, MetaDown ); + m_grid->GetEventHandler()->ProcessEvent( gridEvt ); + + return; + } + } + } + + // The most difficult case: The cell is member of one or even several + // blocks. Split each such block in up to 4 new parts, that don't + // contain the cell to be selected, like this: + // |---------------------------| + // | | + // | part 1 | + // | | + // |---------------------------| + // | part 3 |x| part 4 | + // |---------------------------| + // | | + // | part 2 | + // | | + // |---------------------------| + // (The x marks the newly deselected cell). + // Note: in row selection mode, we only need part1 and part2; + // in column selection mode, we only need part 3 and part4, + // which are expanded to whole columns automatically! + + count = m_blockSelectionTopLeft.GetCount(); + for ( n = 0; n < count; n++ ) + { + wxGridCellCoords& coords1 = m_blockSelectionTopLeft[n]; + wxGridCellCoords& coords2 = m_blockSelectionBottomRight[n]; + int topRow = coords1.GetRow(); + int leftCol = coords1.GetCol(); + int bottomRow = coords2.GetRow(); + int rightCol = coords2.GetCol(); + + if ( BlockContainsCell( topRow, leftCol, bottomRow, rightCol, row, col ) ) + { + // remove the block + m_blockSelectionTopLeft.RemoveAt(n); + m_blockSelectionBottomRight.RemoveAt(n); + n--; + count--; + + // add up to 4 smaller blocks and set update region + if ( m_selectionMode != wxGrid::wxGridSelectColumns ) + { + if ( topRow < row ) + SelectBlock( topRow, leftCol, row - 1, rightCol, + false, false, false, false, false ); + if ( bottomRow > row ) + SelectBlock( row + 1, leftCol, bottomRow, rightCol, + false, false, false, false, false ); + } + + if ( m_selectionMode != wxGrid::wxGridSelectRows ) + { + if ( leftCol < col ) + SelectBlock( row, leftCol, row, col - 1, + false, false, false, false, false ); + if ( rightCol > col ) + SelectBlock( row, col + 1, row, rightCol, + false, false, false, false, false ); + } + } + } + + // remove a cell from a row, adding up to two new blocks + if ( m_selectionMode != wxGrid::wxGridSelectColumns ) + { + count = m_rowSelection.GetCount(); + for ( n = 0; n < count; n++ ) + { + if ( m_rowSelection[n] == row ) + { + m_rowSelection.RemoveAt(n); + n--; + count--; + + if (m_selectionMode == wxGrid::wxGridSelectCells) + { + if ( col > 0 ) + SelectBlock( row, 0, row, col - 1, + false, false, false, false, false ); + if ( col < m_grid->GetNumberCols() - 1 ) + SelectBlock( row, col + 1, + row, m_grid->GetNumberCols() - 1, + false, false, false, false, false ); + } + } + } + } + + // remove a cell from a column, adding up to two new blocks + if ( m_selectionMode != wxGrid::wxGridSelectRows ) + { + count = m_colSelection.GetCount(); + for ( n = 0; n < count; n++ ) + { + if ( m_colSelection[n] == col ) + { + m_colSelection.RemoveAt(n); + n--; + count--; + + if (m_selectionMode == wxGrid::wxGridSelectCells) + { + if ( row > 0 ) + SelectBlock( 0, col, row - 1, col, + false, false, false, false, false ); + if ( row < m_grid->GetNumberRows() - 1 ) + SelectBlock( row + 1, col, + m_grid->GetNumberRows() - 1, col, + false, false, false, false, false ); + } + } + } + } + + // Refresh the screen and send the event; according to m_selectionMode, + // we need to either update only the cell, or the whole row/column. + wxRect r; + switch (m_selectionMode) + { + case wxGrid::wxGridSelectCells: + { + if ( !m_grid->GetBatchCount() ) + { + r = m_grid->BlockToDeviceRect( + wxGridCellCoords( row, col ), + wxGridCellCoords( row, col ) ); + ((wxWindow *)m_grid->m_gridWin)->Refresh( false, &r ); + } + + wxGridRangeSelectEvent gridEvt( m_grid->GetId(), + wxEVT_GRID_RANGE_SELECT, + m_grid, + wxGridCellCoords( row, col ), + wxGridCellCoords( row, col ), + false, + ControlDown, ShiftDown, + AltDown, MetaDown ); + m_grid->GetEventHandler()->ProcessEvent( gridEvt ); + } + break; + + case wxGrid::wxGridSelectRows: + { + if ( !m_grid->GetBatchCount() ) + { + r = m_grid->BlockToDeviceRect( + wxGridCellCoords( row, 0 ), + wxGridCellCoords( row, m_grid->GetNumberCols() - 1 ) ); + ((wxWindow *)m_grid->m_gridWin)->Refresh( false, &r ); + } + + wxGridRangeSelectEvent gridEvt( m_grid->GetId(), + wxEVT_GRID_RANGE_SELECT, + m_grid, + wxGridCellCoords( row, 0 ), + wxGridCellCoords( row, m_grid->GetNumberCols() - 1 ), + false, + ControlDown, ShiftDown, + AltDown, MetaDown ); + m_grid->GetEventHandler()->ProcessEvent( gridEvt ); + } + break; + + case wxGrid::wxGridSelectColumns: + { + if ( !m_grid->GetBatchCount() ) + { + r = m_grid->BlockToDeviceRect( + wxGridCellCoords( 0, col ), + wxGridCellCoords( m_grid->GetNumberRows() - 1, col ) ); + ((wxWindow *)m_grid->m_gridWin)->Refresh( false, &r ); + } + + wxGridRangeSelectEvent gridEvt( m_grid->GetId(), + wxEVT_GRID_RANGE_SELECT, + m_grid, + wxGridCellCoords( 0, col ), + wxGridCellCoords( m_grid->GetNumberRows() - 1, col ), + false, + ControlDown, ShiftDown, + AltDown, MetaDown ); + m_grid->GetEventHandler()->ProcessEvent( gridEvt ); + } + break; + + default: + break; + } +} + +void wxGridSelection::ClearSelection() +{ + size_t n; + wxRect r; + wxGridCellCoords coords1, coords2; + + // deselect all individual cells and update the screen + if ( m_selectionMode == wxGrid::wxGridSelectCells ) + { + while ( ( n = m_cellSelection.GetCount() ) > 0) + { + n--; + coords1 = m_cellSelection[n]; + m_cellSelection.RemoveAt(n); + if ( !m_grid->GetBatchCount() ) + { + r = m_grid->BlockToDeviceRect( coords1, coords1 ); + ((wxWindow *)m_grid->m_gridWin)->Refresh( false, &r ); + +#ifdef __WXMAC__ + ((wxWindow *)m_grid->m_gridWin)->Update(); +#endif + } + } + } + + // deselect all blocks and update the screen + while ( ( n = m_blockSelectionTopLeft.GetCount() ) > 0) + { + n--; + coords1 = m_blockSelectionTopLeft[n]; + coords2 = m_blockSelectionBottomRight[n]; + m_blockSelectionTopLeft.RemoveAt(n); + m_blockSelectionBottomRight.RemoveAt(n); + if ( !m_grid->GetBatchCount() ) + { + r = m_grid->BlockToDeviceRect( coords1, coords2 ); + ((wxWindow *)m_grid->m_gridWin)->Refresh( false, &r ); + +#ifdef __WXMAC__ + ((wxWindow *)m_grid->m_gridWin)->Update(); +#endif + } + } + + // deselect all rows and update the screen + if ( m_selectionMode != wxGrid::wxGridSelectColumns ) + { + while ( ( n = m_rowSelection.GetCount() ) > 0) + { + n--; + int row = m_rowSelection[n]; + m_rowSelection.RemoveAt(n); + if ( !m_grid->GetBatchCount() ) + { + r = m_grid->BlockToDeviceRect( wxGridCellCoords( row, 0 ), + wxGridCellCoords( row, m_grid->GetNumberCols() - 1 ) ); + ((wxWindow *)m_grid->m_gridWin)->Refresh( false, &r ); + +#ifdef __WXMAC__ + ((wxWindow *)m_grid->m_gridWin)->Update(); +#endif + } + } + } + + // deselect all columns and update the screen + if ( m_selectionMode != wxGrid::wxGridSelectRows ) + { + while ( ( n = m_colSelection.GetCount() ) > 0) + { + n--; + int col = m_colSelection[n]; + m_colSelection.RemoveAt(n); + if ( !m_grid->GetBatchCount() ) + { + r = m_grid->BlockToDeviceRect( wxGridCellCoords( 0, col ), + wxGridCellCoords( m_grid->GetNumberRows() - 1, col ) ); + ((wxWindow *)m_grid->m_gridWin)->Refresh( false, &r ); + +#ifdef __WXMAC__ + ((wxWindow *)m_grid->m_gridWin)->Update(); +#endif + } + } + } + + // One deselection event, indicating deselection of _all_ cells. + // (No finer grained events for each of the smaller regions + // deselected above!) + wxGridRangeSelectEvent gridEvt( m_grid->GetId(), + wxEVT_GRID_RANGE_SELECT, + m_grid, + wxGridCellCoords( 0, 0 ), + wxGridCellCoords( + m_grid->GetNumberRows() - 1, + m_grid->GetNumberCols() - 1 ), + false ); + + m_grid->GetEventHandler()->ProcessEvent(gridEvt); +} + + +void wxGridSelection::UpdateRows( size_t pos, int numRows ) +{ + size_t count = m_cellSelection.GetCount(); + size_t n; + for ( n = 0; n < count; n++ ) + { + wxGridCellCoords& coords = m_cellSelection[n]; + wxCoord row = coords.GetRow(); + if ((size_t)row >= pos) + { + if (numRows > 0) + { + // If rows inserted, increase row counter where necessary + coords.SetRow(row + numRows); + } + else if (numRows < 0) + { + // If rows deleted ... + if ((size_t)row >= pos - numRows) + { + // ...either decrement row counter (if row still exists)... + coords.SetRow(row + numRows); + } + else + { + // ...or remove the attribute + m_cellSelection.RemoveAt(n); + n--; + count--; + } + } + } + } + + count = m_blockSelectionTopLeft.GetCount(); + for ( n = 0; n < count; n++ ) + { + wxGridCellCoords& coords1 = m_blockSelectionTopLeft[n]; + wxGridCellCoords& coords2 = m_blockSelectionBottomRight[n]; + wxCoord row1 = coords1.GetRow(); + wxCoord row2 = coords2.GetRow(); + + if ((size_t)row2 >= pos) + { + if (numRows > 0) + { + // If rows inserted, increase row counter where necessary + coords2.SetRow( row2 + numRows ); + if ((size_t)row1 >= pos) + coords1.SetRow( row1 + numRows ); + } + else if (numRows < 0) + { + // If rows deleted ... + if ((size_t)row2 >= pos - numRows) + { + // ...either decrement row counter (if row still exists)... + coords2.SetRow( row2 + numRows ); + if ((size_t)row1 >= pos) + coords1.SetRow( wxMax(row1 + numRows, (int)pos) ); + + } + else + { + if ((size_t)row1 >= pos) + { + // ...or remove the attribute + m_blockSelectionTopLeft.RemoveAt(n); + m_blockSelectionBottomRight.RemoveAt(n); + n--; + count--; + } + else + coords2.SetRow( pos ); + } + } + } + } + + count = m_rowSelection.GetCount(); + for ( n = 0; n < count; n++ ) + { + int rowOrCol_ = m_rowSelection[n]; + + if ((size_t) rowOrCol_ >= pos) + { + if ( numRows > 0 ) + { + m_rowSelection[n] += numRows; + } + else if ( numRows < 0 ) + { + if ((size_t)rowOrCol_ >= (pos - numRows)) + m_rowSelection[n] += numRows; + else + { + m_rowSelection.RemoveAt( n ); + n--; + count--; + } + } + } + } + // No need to touch selected columns, unless we removed _all_ + // rows, in this case, we remove all columns from the selection. + + if ( !m_grid->GetNumberRows() ) + m_colSelection.Clear(); +} + + +void wxGridSelection::UpdateCols( size_t pos, int numCols ) +{ + size_t count = m_cellSelection.GetCount(); + size_t n; + + for ( n = 0; n < count; n++ ) + { + wxGridCellCoords& coords = m_cellSelection[n]; + wxCoord col = coords.GetCol(); + if ((size_t)col >= pos) + { + if (numCols > 0) + { + // If rows inserted, increase row counter where necessary + coords.SetCol(col + numCols); + } + else if (numCols < 0) + { + // If rows deleted ... + if ((size_t)col >= pos - numCols) + { + // ...either decrement row counter (if row still exists)... + coords.SetCol(col + numCols); + } + else + { + // ...or remove the attribute + m_cellSelection.RemoveAt(n); + n--; + count--; + } + } + } + } + + count = m_blockSelectionTopLeft.GetCount(); + for ( n = 0; n < count; n++ ) + { + wxGridCellCoords& coords1 = m_blockSelectionTopLeft[n]; + wxGridCellCoords& coords2 = m_blockSelectionBottomRight[n]; + wxCoord col1 = coords1.GetCol(); + wxCoord col2 = coords2.GetCol(); + + if ((size_t)col2 >= pos) + { + if (numCols > 0) + { + // If rows inserted, increase row counter where necessary + coords2.SetCol(col2 + numCols); + if ((size_t)col1 >= pos) + coords1.SetCol(col1 + numCols); + } + else if (numCols < 0) + { + // If cols deleted ... + if ((size_t)col2 >= pos - numCols) + { + // ...either decrement col counter (if col still exists)... + coords2.SetCol(col2 + numCols); + if ( (size_t) col1 >= pos) + coords1.SetCol( wxMax(col1 + numCols, (int)pos) ); + + } + else + { + if ((size_t)col1 >= pos) + { + // ...or remove the attribute + m_blockSelectionTopLeft.RemoveAt(n); + m_blockSelectionBottomRight.RemoveAt(n); + n--; + count--; + } + else + coords2.SetCol(pos); + } + } + } + } + + count = m_colSelection.GetCount(); + for ( n = 0; n < count; n++ ) + { + int rowOrCol = m_colSelection[n]; + + if ((size_t)rowOrCol >= pos) + { + if ( numCols > 0 ) + m_colSelection[n] += numCols; + else if ( numCols < 0 ) + { + if ((size_t)rowOrCol >= (pos - numCols)) + m_colSelection[n] += numCols; + else + { + m_colSelection.RemoveAt( n ); + n--; + count--; + } + } + } + } + + // No need to touch selected rows, unless we removed _all_ + // columns, in this case, we remove all rows from the selection. + if ( !m_grid->GetNumberCols() ) + m_rowSelection.Clear(); +} + +int wxGridSelection::BlockContain( int topRow1, int leftCol1, + int bottomRow1, int rightCol1, + int topRow2, int leftCol2, + int bottomRow2, int rightCol2 ) +// returns 1, if Block1 contains Block2, +// -1, if Block2 contains Block1, +// 0, otherwise +{ + if ( topRow1 <= topRow2 && bottomRow2 <= bottomRow1 && + leftCol1 <= leftCol2 && rightCol2 <= rightCol1 ) + return 1; + else if ( topRow2 <= topRow1 && bottomRow1 <= bottomRow2 && + leftCol2 <= leftCol1 && rightCol1 <= rightCol2 ) + return -1; + + return 0; +} + +#endif diff --git a/Externals/wxWidgets/src/generic/helpext.cpp b/Externals/wxWidgets/src/generic/helpext.cpp index 97100ed3ca..f01de9073d 100644 --- a/Externals/wxWidgets/src/generic/helpext.cpp +++ b/Externals/wxWidgets/src/generic/helpext.cpp @@ -1,485 +1,485 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/generic/helpext.cpp -// Purpose: an external help controller for wxWidgets -// Author: Karsten Ballueder -// Modified by: -// Created: 04/01/98 -// RCS-ID: $Id: helpext.cpp 38857 2006-04-20 07:31:44Z ABX $ -// Copyright: (c) Karsten Ballueder -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_HELP && !defined(__WXWINCE__) && (!defined(__WXMAC__) || defined(__WXMAC_OSX__)) - -#ifndef WX_PRECOMP - #include "wx/list.h" - #include "wx/string.h" - #include "wx/utils.h" - #include "wx/intl.h" - #include "wx/msgdlg.h" - #include "wx/choicdlg.h" - #include "wx/log.h" -#endif - -#include "wx/filename.h" -#include "wx/textfile.h" -#include "wx/generic/helpext.h" - -#include -#include -#include - -#if !defined(__WINDOWS__) && !defined(__OS2__) - #include -#endif - -#ifdef __WINDOWS__ -#include "wx/msw/mslu.h" -#endif - -#ifdef __WXMSW__ -#include -#include "wx/msw/winundef.h" -#endif - -// ---------------------------------------------------------------------------- -// constants -// ---------------------------------------------------------------------------- - -/// Name for map file. -#define WXEXTHELP_MAPFILE _T("wxhelp.map") - -/// Character introducing comments/documentation field in map file. -#define WXEXTHELP_COMMENTCHAR ';' - -#define CONTENTS_ID 0 - -IMPLEMENT_CLASS(wxExtHelpController, wxHelpControllerBase) - -/// Name of environment variable to set help browser. -#define WXEXTHELP_ENVVAR_BROWSER wxT("WX_HELPBROWSER") -/// Is browser a netscape browser? -#define WXEXTHELP_ENVVAR_BROWSERISNETSCAPE wxT("WX_HELPBROWSER_NS") - -/** - This class implements help via an external browser. - It requires the name of a directory containing the documentation - and a file mapping numerical Section numbers to relative URLS. -*/ - -wxExtHelpController::wxExtHelpController(wxWindow* parentWindow) - : wxHelpControllerBase(parentWindow) -{ - m_MapList = NULL; - m_NumOfEntries = 0; - m_BrowserIsNetscape = false; - - wxChar *browser = wxGetenv(WXEXTHELP_ENVVAR_BROWSER); - if (browser) - { - m_BrowserName = browser; - browser = wxGetenv(WXEXTHELP_ENVVAR_BROWSERISNETSCAPE); - m_BrowserIsNetscape = browser && (wxAtoi(browser) != 0); - } -} - -wxExtHelpController::~wxExtHelpController() -{ - DeleteList(); -} - -void wxExtHelpController::SetBrowser(const wxString& browsername, bool isNetscape) -{ - m_BrowserName = browsername; - m_BrowserIsNetscape = isNetscape; -} - -// Set viewer: new, generic name for SetBrowser -void wxExtHelpController::SetViewer(const wxString& viewer, long flags) -{ - SetBrowser(viewer, (flags & wxHELP_NETSCAPE) != 0); -} - -bool wxExtHelpController::DisplayHelp(const wxString &relativeURL) -{ - // construct hte URL to open -- it's just a file - wxString url(_T("file://") + m_helpDir); - url << wxFILE_SEP_PATH << relativeURL; - - // use the explicit browser program if specified - if ( !m_BrowserName.empty() ) - { - if ( m_BrowserIsNetscape ) - { - wxString command; - command << m_BrowserName - << wxT(" -remote openURL(") << url << wxT(')'); - if ( wxExecute(command, wxEXEC_SYNC) != -1 ) - return true; - } - - if ( wxExecute(m_BrowserName + _T(' ') + url, wxEXEC_SYNC) != -1 ) - return true; - } - //else: either no browser explicitly specified or we failed to open it - - // just use default browser - return wxLaunchDefaultBrowser(url); -} - -class wxExtHelpMapEntry : public wxObject -{ -public: - int id; - wxString url; - wxString doc; - wxExtHelpMapEntry(int iid, wxString const &iurl, wxString const &idoc) - { id = iid; url = iurl; doc = idoc; } -}; - -void wxExtHelpController::DeleteList() -{ - if (m_MapList) - { - wxList::compatibility_iterator node = m_MapList->GetFirst(); - while (node) - { - delete (wxExtHelpMapEntry *)node->GetData(); - m_MapList->Erase(node); - node = m_MapList->GetFirst(); - } - - delete m_MapList; - m_MapList = (wxList*) NULL; - } -} - -// This must be called to tell the controller where to find the documentation. -// @param file - NOT a filename, but a directory name. -// @return true on success -bool wxExtHelpController::Initialize(const wxString& file) -{ - return LoadFile(file); -} - -bool wxExtHelpController::ParseMapFileLine(const wxString& line) -{ - const wxChar *p = line.c_str(); - - // skip whitespace - while ( isascii(*p) && isspace(*p) ) - p++; - - // skip empty lines and comments - if ( *p == _T('\0') || *p == WXEXTHELP_COMMENTCHAR ) - return true; - - // the line is of the form "num url" so we must have an integer now - wxChar *end; - const unsigned long id = wxStrtoul(p, &end, 0); - - if ( end == p ) - return false; - - p = end; - while ( isascii(*p) && isspace(*p) ) - p++; - - // next should be the URL - wxString url; - url.reserve(line.length()); - while ( isascii(*p) && !isspace(*p) ) - url += *p++; - - while ( isascii(*p) && isspace(*p) ) - p++; - - // and finally the optional description of the entry after comment - wxString doc; - if ( *p == WXEXTHELP_COMMENTCHAR ) - { - p++; - while ( isascii(*p) && isspace(*p) ) - p++; - doc = p; - } - - m_MapList->Append(new wxExtHelpMapEntry(id, url, doc)); - m_NumOfEntries++; - - return true; -} - -// file is a misnomer as it's the name of the base help directory -bool wxExtHelpController::LoadFile(const wxString& file) -{ - wxFileName helpDir(wxFileName::DirName(file)); - helpDir.MakeAbsolute(); - - bool dirExists = false; - -#if wxUSE_INTL - // If a locale is set, look in file/localename, i.e. If passed - // "/usr/local/myapp/help" and the current wxLocale is set to be "de", then - // look in "/usr/local/myapp/help/de/" first and fall back to - // "/usr/local/myapp/help" if that doesn't exist. - const wxLocale * const loc = wxGetLocale(); - if ( loc ) - { - wxString locName = loc->GetName(); - - // the locale is in general of the form xx_YY.zzzz, try the full firm - // first and then also more general ones - wxFileName helpDirLoc(helpDir); - helpDirLoc.AppendDir(locName); - dirExists = helpDirLoc.DirExists(); - - if ( ! dirExists ) - { - // try without encoding - const wxString locNameWithoutEncoding = locName.BeforeLast(_T('.')); - if ( !locNameWithoutEncoding.empty() ) - { - helpDirLoc = helpDir; - helpDirLoc.AppendDir(locNameWithoutEncoding); - dirExists = helpDirLoc.DirExists(); - } - } - - if ( !dirExists ) - { - // try without country part - wxString locNameWithoutCountry = locName.BeforeLast(_T('_')); - if ( !locNameWithoutCountry.empty() ) - { - helpDirLoc = helpDir; - helpDirLoc.AppendDir(locNameWithoutCountry); - dirExists = helpDirLoc.DirExists(); - } - } - - if ( dirExists ) - helpDir = helpDirLoc; - } -#endif // wxUSE_INTL - - if ( ! dirExists && !helpDir.DirExists() ) - { - wxLogError(_("Help directory \"%s\" not found."), - helpDir.GetFullPath().c_str()); - return false; - } - - const wxFileName mapFile(helpDir.GetFullPath(), WXEXTHELP_MAPFILE); - if ( ! mapFile.FileExists() ) - { - wxLogError(_("Help file \"%s\" not found."), - mapFile.GetFullPath().c_str()); - return false; - } - - DeleteList(); - m_MapList = new wxList; - m_NumOfEntries = 0; - - wxTextFile input; - if ( !input.Open(mapFile.GetFullPath()) ) - return false; - - for ( wxString& line = input.GetFirstLine(); - !input.Eof(); - line = input.GetNextLine() ) - { - if ( !ParseMapFileLine(line) ) - { - wxLogWarning(_("Line %lu of map file \"%s\" has invalid syntax, skipped."), - (unsigned long)input.GetCurrentLine(), - mapFile.GetFullPath().c_str()); - } - } - - if ( !m_NumOfEntries ) - { - wxLogError(_("No valid mappings found in the file \"%s\"."), - mapFile.GetFullPath().c_str()); - return false; - } - - m_helpDir = helpDir.GetFullPath(); // now it's valid - return true; -} - - -bool wxExtHelpController::DisplayContents() -{ - if (! m_NumOfEntries) - return false; - - wxString contents; - wxList::compatibility_iterator node = m_MapList->GetFirst(); - wxExtHelpMapEntry *entry; - while (node) - { - entry = (wxExtHelpMapEntry *)node->GetData(); - if (entry->id == CONTENTS_ID) - { - contents = entry->url; - break; - } - - node = node->GetNext(); - } - - bool rc = false; - wxString file; - file << m_helpDir << wxFILE_SEP_PATH << contents; - if (file.Contains(wxT('#'))) - file = file.BeforeLast(wxT('#')); - if (contents.length() && wxFileExists(file)) - rc = DisplaySection(CONTENTS_ID); - - // if not found, open homemade toc: - return rc ? true : KeywordSearch(wxEmptyString); -} - -bool wxExtHelpController::DisplaySection(int sectionNo) -{ - if (! m_NumOfEntries) - return false; - - wxBusyCursor b; // display a busy cursor - wxList::compatibility_iterator node = m_MapList->GetFirst(); - wxExtHelpMapEntry *entry; - while (node) - { - entry = (wxExtHelpMapEntry *)node->GetData(); - if (entry->id == sectionNo) - return DisplayHelp(entry->url); - node = node->GetNext(); - } - - return false; -} - -bool wxExtHelpController::DisplaySection(const wxString& section) -{ - bool isFilename = (section.Find(wxT(".htm")) != -1); - - if (isFilename) - return DisplayHelp(section); - else - return KeywordSearch(section); -} - -bool wxExtHelpController::DisplayBlock(long blockNo) -{ - return DisplaySection((int)blockNo); -} - -bool wxExtHelpController::KeywordSearch(const wxString& k, - wxHelpSearchMode WXUNUSED(mode)) -{ - if (! m_NumOfEntries) - return false; - - wxString *choices = new wxString[m_NumOfEntries]; - wxString *urls = new wxString[m_NumOfEntries]; - - int idx = 0; - bool rc = false; - bool showAll = k.empty(); - - wxList::compatibility_iterator node = m_MapList->GetFirst(); - - { - // display a busy cursor - wxBusyCursor b; - wxString compA, compB; - wxExtHelpMapEntry *entry; - - // we compare case insensitive - if (! showAll) - { - compA = k; - compA.LowerCase(); - } - - while (node) - { - entry = (wxExtHelpMapEntry *)node->GetData(); - compB = entry->doc; - - bool testTarget = ! compB.empty(); - if (testTarget && ! showAll) - { - compB.LowerCase(); - testTarget = compB.Contains(compA); - } - - if (testTarget) - { - urls[idx] = entry->url; - // doesn't work: - // choices[idx] = (**i).doc.Contains((**i).doc.Before(WXEXTHELP_COMMENTCHAR)); - //if (choices[idx].empty()) // didn't contain the ';' - // choices[idx] = (**i).doc; - choices[idx] = wxEmptyString; - for (int j=0; ; j++) - { - wxChar targetChar = entry->doc.c_str()[j]; - if ((targetChar == 0) || (targetChar == WXEXTHELP_COMMENTCHAR)) - break; - - choices[idx] << targetChar; - } - - idx++; - } - - node = node->GetNext(); - } - } - - switch (idx) - { - case 0: - wxMessageBox(_("No entries found.")); - break; - - case 1: - rc = DisplayHelp(urls[0]); - break; - - default: - idx = wxGetSingleChoiceIndex( - showAll ? _("Help Index") : _("Relevant entries:"), - showAll ? _("Help Index") : _("Entries found"), - idx, choices); - if (idx >= 0) - rc = DisplayHelp(urls[idx]); - break; - } - - delete [] urls; - delete [] choices; - - return rc; -} - - -bool wxExtHelpController::Quit() -{ - return true; -} - -void wxExtHelpController::OnQuit() -{ -} - -#endif // wxUSE_HELP +///////////////////////////////////////////////////////////////////////////// +// Name: src/generic/helpext.cpp +// Purpose: an external help controller for wxWidgets +// Author: Karsten Ballueder +// Modified by: +// Created: 04/01/98 +// RCS-ID: $Id: helpext.cpp 38857 2006-04-20 07:31:44Z ABX $ +// Copyright: (c) Karsten Ballueder +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_HELP && !defined(__WXWINCE__) && (!defined(__WXMAC__) || defined(__WXMAC_OSX__)) + +#ifndef WX_PRECOMP + #include "wx/list.h" + #include "wx/string.h" + #include "wx/utils.h" + #include "wx/intl.h" + #include "wx/msgdlg.h" + #include "wx/choicdlg.h" + #include "wx/log.h" +#endif + +#include "wx/filename.h" +#include "wx/textfile.h" +#include "wx/generic/helpext.h" + +#include +#include +#include + +#if !defined(__WINDOWS__) && !defined(__OS2__) + #include +#endif + +#ifdef __WINDOWS__ +#include "wx/msw/mslu.h" +#endif + +#ifdef __WXMSW__ +#include +#include "wx/msw/winundef.h" +#endif + +// ---------------------------------------------------------------------------- +// constants +// ---------------------------------------------------------------------------- + +/// Name for map file. +#define WXEXTHELP_MAPFILE _T("wxhelp.map") + +/// Character introducing comments/documentation field in map file. +#define WXEXTHELP_COMMENTCHAR ';' + +#define CONTENTS_ID 0 + +IMPLEMENT_CLASS(wxExtHelpController, wxHelpControllerBase) + +/// Name of environment variable to set help browser. +#define WXEXTHELP_ENVVAR_BROWSER wxT("WX_HELPBROWSER") +/// Is browser a netscape browser? +#define WXEXTHELP_ENVVAR_BROWSERISNETSCAPE wxT("WX_HELPBROWSER_NS") + +/** + This class implements help via an external browser. + It requires the name of a directory containing the documentation + and a file mapping numerical Section numbers to relative URLS. +*/ + +wxExtHelpController::wxExtHelpController(wxWindow* parentWindow) + : wxHelpControllerBase(parentWindow) +{ + m_MapList = NULL; + m_NumOfEntries = 0; + m_BrowserIsNetscape = false; + + wxChar *browser = wxGetenv(WXEXTHELP_ENVVAR_BROWSER); + if (browser) + { + m_BrowserName = browser; + browser = wxGetenv(WXEXTHELP_ENVVAR_BROWSERISNETSCAPE); + m_BrowserIsNetscape = browser && (wxAtoi(browser) != 0); + } +} + +wxExtHelpController::~wxExtHelpController() +{ + DeleteList(); +} + +void wxExtHelpController::SetBrowser(const wxString& browsername, bool isNetscape) +{ + m_BrowserName = browsername; + m_BrowserIsNetscape = isNetscape; +} + +// Set viewer: new, generic name for SetBrowser +void wxExtHelpController::SetViewer(const wxString& viewer, long flags) +{ + SetBrowser(viewer, (flags & wxHELP_NETSCAPE) != 0); +} + +bool wxExtHelpController::DisplayHelp(const wxString &relativeURL) +{ + // construct hte URL to open -- it's just a file + wxString url(_T("file://") + m_helpDir); + url << wxFILE_SEP_PATH << relativeURL; + + // use the explicit browser program if specified + if ( !m_BrowserName.empty() ) + { + if ( m_BrowserIsNetscape ) + { + wxString command; + command << m_BrowserName + << wxT(" -remote openURL(") << url << wxT(')'); + if ( wxExecute(command, wxEXEC_SYNC) != -1 ) + return true; + } + + if ( wxExecute(m_BrowserName + _T(' ') + url, wxEXEC_SYNC) != -1 ) + return true; + } + //else: either no browser explicitly specified or we failed to open it + + // just use default browser + return wxLaunchDefaultBrowser(url); +} + +class wxExtHelpMapEntry : public wxObject +{ +public: + int id; + wxString url; + wxString doc; + wxExtHelpMapEntry(int iid, wxString const &iurl, wxString const &idoc) + { id = iid; url = iurl; doc = idoc; } +}; + +void wxExtHelpController::DeleteList() +{ + if (m_MapList) + { + wxList::compatibility_iterator node = m_MapList->GetFirst(); + while (node) + { + delete (wxExtHelpMapEntry *)node->GetData(); + m_MapList->Erase(node); + node = m_MapList->GetFirst(); + } + + delete m_MapList; + m_MapList = (wxList*) NULL; + } +} + +// This must be called to tell the controller where to find the documentation. +// @param file - NOT a filename, but a directory name. +// @return true on success +bool wxExtHelpController::Initialize(const wxString& file) +{ + return LoadFile(file); +} + +bool wxExtHelpController::ParseMapFileLine(const wxString& line) +{ + const wxChar *p = line.c_str(); + + // skip whitespace + while ( isascii(*p) && isspace(*p) ) + p++; + + // skip empty lines and comments + if ( *p == _T('\0') || *p == WXEXTHELP_COMMENTCHAR ) + return true; + + // the line is of the form "num url" so we must have an integer now + wxChar *end; + const unsigned long id = wxStrtoul(p, &end, 0); + + if ( end == p ) + return false; + + p = end; + while ( isascii(*p) && isspace(*p) ) + p++; + + // next should be the URL + wxString url; + url.reserve(line.length()); + while ( isascii(*p) && !isspace(*p) ) + url += *p++; + + while ( isascii(*p) && isspace(*p) ) + p++; + + // and finally the optional description of the entry after comment + wxString doc; + if ( *p == WXEXTHELP_COMMENTCHAR ) + { + p++; + while ( isascii(*p) && isspace(*p) ) + p++; + doc = p; + } + + m_MapList->Append(new wxExtHelpMapEntry(id, url, doc)); + m_NumOfEntries++; + + return true; +} + +// file is a misnomer as it's the name of the base help directory +bool wxExtHelpController::LoadFile(const wxString& file) +{ + wxFileName helpDir(wxFileName::DirName(file)); + helpDir.MakeAbsolute(); + + bool dirExists = false; + +#if wxUSE_INTL + // If a locale is set, look in file/localename, i.e. If passed + // "/usr/local/myapp/help" and the current wxLocale is set to be "de", then + // look in "/usr/local/myapp/help/de/" first and fall back to + // "/usr/local/myapp/help" if that doesn't exist. + const wxLocale * const loc = wxGetLocale(); + if ( loc ) + { + wxString locName = loc->GetName(); + + // the locale is in general of the form xx_YY.zzzz, try the full firm + // first and then also more general ones + wxFileName helpDirLoc(helpDir); + helpDirLoc.AppendDir(locName); + dirExists = helpDirLoc.DirExists(); + + if ( ! dirExists ) + { + // try without encoding + const wxString locNameWithoutEncoding = locName.BeforeLast(_T('.')); + if ( !locNameWithoutEncoding.empty() ) + { + helpDirLoc = helpDir; + helpDirLoc.AppendDir(locNameWithoutEncoding); + dirExists = helpDirLoc.DirExists(); + } + } + + if ( !dirExists ) + { + // try without country part + wxString locNameWithoutCountry = locName.BeforeLast(_T('_')); + if ( !locNameWithoutCountry.empty() ) + { + helpDirLoc = helpDir; + helpDirLoc.AppendDir(locNameWithoutCountry); + dirExists = helpDirLoc.DirExists(); + } + } + + if ( dirExists ) + helpDir = helpDirLoc; + } +#endif // wxUSE_INTL + + if ( ! dirExists && !helpDir.DirExists() ) + { + wxLogError(_("Help directory \"%s\" not found."), + helpDir.GetFullPath().c_str()); + return false; + } + + const wxFileName mapFile(helpDir.GetFullPath(), WXEXTHELP_MAPFILE); + if ( ! mapFile.FileExists() ) + { + wxLogError(_("Help file \"%s\" not found."), + mapFile.GetFullPath().c_str()); + return false; + } + + DeleteList(); + m_MapList = new wxList; + m_NumOfEntries = 0; + + wxTextFile input; + if ( !input.Open(mapFile.GetFullPath()) ) + return false; + + for ( wxString& line = input.GetFirstLine(); + !input.Eof(); + line = input.GetNextLine() ) + { + if ( !ParseMapFileLine(line) ) + { + wxLogWarning(_("Line %lu of map file \"%s\" has invalid syntax, skipped."), + (unsigned long)input.GetCurrentLine(), + mapFile.GetFullPath().c_str()); + } + } + + if ( !m_NumOfEntries ) + { + wxLogError(_("No valid mappings found in the file \"%s\"."), + mapFile.GetFullPath().c_str()); + return false; + } + + m_helpDir = helpDir.GetFullPath(); // now it's valid + return true; +} + + +bool wxExtHelpController::DisplayContents() +{ + if (! m_NumOfEntries) + return false; + + wxString contents; + wxList::compatibility_iterator node = m_MapList->GetFirst(); + wxExtHelpMapEntry *entry; + while (node) + { + entry = (wxExtHelpMapEntry *)node->GetData(); + if (entry->id == CONTENTS_ID) + { + contents = entry->url; + break; + } + + node = node->GetNext(); + } + + bool rc = false; + wxString file; + file << m_helpDir << wxFILE_SEP_PATH << contents; + if (file.Contains(wxT('#'))) + file = file.BeforeLast(wxT('#')); + if (contents.length() && wxFileExists(file)) + rc = DisplaySection(CONTENTS_ID); + + // if not found, open homemade toc: + return rc ? true : KeywordSearch(wxEmptyString); +} + +bool wxExtHelpController::DisplaySection(int sectionNo) +{ + if (! m_NumOfEntries) + return false; + + wxBusyCursor b; // display a busy cursor + wxList::compatibility_iterator node = m_MapList->GetFirst(); + wxExtHelpMapEntry *entry; + while (node) + { + entry = (wxExtHelpMapEntry *)node->GetData(); + if (entry->id == sectionNo) + return DisplayHelp(entry->url); + node = node->GetNext(); + } + + return false; +} + +bool wxExtHelpController::DisplaySection(const wxString& section) +{ + bool isFilename = (section.Find(wxT(".htm")) != -1); + + if (isFilename) + return DisplayHelp(section); + else + return KeywordSearch(section); +} + +bool wxExtHelpController::DisplayBlock(long blockNo) +{ + return DisplaySection((int)blockNo); +} + +bool wxExtHelpController::KeywordSearch(const wxString& k, + wxHelpSearchMode WXUNUSED(mode)) +{ + if (! m_NumOfEntries) + return false; + + wxString *choices = new wxString[m_NumOfEntries]; + wxString *urls = new wxString[m_NumOfEntries]; + + int idx = 0; + bool rc = false; + bool showAll = k.empty(); + + wxList::compatibility_iterator node = m_MapList->GetFirst(); + + { + // display a busy cursor + wxBusyCursor b; + wxString compA, compB; + wxExtHelpMapEntry *entry; + + // we compare case insensitive + if (! showAll) + { + compA = k; + compA.LowerCase(); + } + + while (node) + { + entry = (wxExtHelpMapEntry *)node->GetData(); + compB = entry->doc; + + bool testTarget = ! compB.empty(); + if (testTarget && ! showAll) + { + compB.LowerCase(); + testTarget = compB.Contains(compA); + } + + if (testTarget) + { + urls[idx] = entry->url; + // doesn't work: + // choices[idx] = (**i).doc.Contains((**i).doc.Before(WXEXTHELP_COMMENTCHAR)); + //if (choices[idx].empty()) // didn't contain the ';' + // choices[idx] = (**i).doc; + choices[idx] = wxEmptyString; + for (int j=0; ; j++) + { + wxChar targetChar = entry->doc.c_str()[j]; + if ((targetChar == 0) || (targetChar == WXEXTHELP_COMMENTCHAR)) + break; + + choices[idx] << targetChar; + } + + idx++; + } + + node = node->GetNext(); + } + } + + switch (idx) + { + case 0: + wxMessageBox(_("No entries found.")); + break; + + case 1: + rc = DisplayHelp(urls[0]); + break; + + default: + idx = wxGetSingleChoiceIndex( + showAll ? _("Help Index") : _("Relevant entries:"), + showAll ? _("Help Index") : _("Entries found"), + idx, choices); + if (idx >= 0) + rc = DisplayHelp(urls[idx]); + break; + } + + delete [] urls; + delete [] choices; + + return rc; +} + + +bool wxExtHelpController::Quit() +{ + return true; +} + +void wxExtHelpController::OnQuit() +{ +} + +#endif // wxUSE_HELP diff --git a/Externals/wxWidgets/src/generic/htmllbox.cpp b/Externals/wxWidgets/src/generic/htmllbox.cpp index a560d4ffc3..0ffc71eea2 100644 --- a/Externals/wxWidgets/src/generic/htmllbox.cpp +++ b/Externals/wxWidgets/src/generic/htmllbox.cpp @@ -1,682 +1,682 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: generic/htmllbox.cpp -// Purpose: implementation of wxHtmlListBox -// Author: Vadim Zeitlin -// Modified by: -// Created: 31.05.03 -// RCS-ID: $Id: htmllbox.cpp 44026 2006-12-21 18:24:27Z VS $ -// Copyright: (c) 2003 Vadim Zeitlin -// License: wxWindows license -/////////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#ifndef WX_PRECOMP - #include "wx/dcclient.h" -#endif //WX_PRECOMP - -#if wxUSE_HTML - -#include "wx/htmllbox.h" - -#include "wx/html/htmlcell.h" -#include "wx/html/winpars.h" - -// this hack forces the linker to always link in m_* files -#include "wx/html/forcelnk.h" -FORCE_WXHTML_MODULES() - -// ---------------------------------------------------------------------------- -// constants -// ---------------------------------------------------------------------------- - -// small border always added to the cells: -static const wxCoord CELL_BORDER = 2; - -const wxChar wxHtmlListBoxNameStr[] = wxT("htmlListBox"); -const wxChar wxSimpleHtmlListBoxNameStr[] = wxT("simpleHtmlListBox"); - -// ============================================================================ -// private classes -// ============================================================================ - -// ---------------------------------------------------------------------------- -// wxHtmlListBoxCache -// ---------------------------------------------------------------------------- - -// this class is used by wxHtmlListBox to cache the parsed representation of -// the items to avoid doing it anew each time an item must be drawn -class wxHtmlListBoxCache -{ -private: - // invalidate a single item, used by Clear() and InvalidateRange() - void InvalidateItem(size_t n) - { - m_items[n] = (size_t)-1; - delete m_cells[n]; - m_cells[n] = NULL; - } - -public: - wxHtmlListBoxCache() - { - for ( size_t n = 0; n < SIZE; n++ ) - { - m_items[n] = (size_t)-1; - m_cells[n] = NULL; - } - - m_next = 0; - } - - ~wxHtmlListBoxCache() - { - for ( size_t n = 0; n < SIZE; n++ ) - { - delete m_cells[n]; - } - } - - // completely invalidate the cache - void Clear() - { - for ( size_t n = 0; n < SIZE; n++ ) - { - InvalidateItem(n); - } - } - - // return the cached cell for this index or NULL if none - wxHtmlCell *Get(size_t item) const - { - for ( size_t n = 0; n < SIZE; n++ ) - { - if ( m_items[n] == item ) - return m_cells[n]; - } - - return NULL; - } - - // returns true if we already have this item cached - bool Has(size_t item) const { return Get(item) != NULL; } - - // ensure that the item is cached - void Store(size_t item, wxHtmlCell *cell) - { - delete m_cells[m_next]; - m_cells[m_next] = cell; - m_items[m_next] = item; - - // advance to the next item wrapping around if there are no more - if ( ++m_next == SIZE ) - m_next = 0; - } - - // forget the cached value of the item(s) between the given ones (inclusive) - void InvalidateRange(size_t from, size_t to) - { - for ( size_t n = 0; n < SIZE; n++ ) - { - if ( m_items[n] >= from && m_items[n] <= to ) - { - InvalidateItem(n); - } - } - } - -private: - // the max number of the items we cache - enum { SIZE = 50 }; - - // the index of the LRU (oldest) cell - size_t m_next; - - // the parsed representation of the cached item or NULL - wxHtmlCell *m_cells[SIZE]; - - // the index of the currently cached item (only valid if m_cells != NULL) - size_t m_items[SIZE]; -}; - -// ---------------------------------------------------------------------------- -// wxHtmlListBoxStyle -// ---------------------------------------------------------------------------- - -// just forward wxDefaultHtmlRenderingStyle callbacks to the main class so that -// they could be overridden by the user code -class wxHtmlListBoxStyle : public wxDefaultHtmlRenderingStyle -{ -public: - wxHtmlListBoxStyle(const wxHtmlListBox& hlbox) : m_hlbox(hlbox) { } - - virtual wxColour GetSelectedTextColour(const wxColour& colFg) - { - return m_hlbox.GetSelectedTextColour(colFg); - } - - virtual wxColour GetSelectedTextBgColour(const wxColour& colBg) - { - return m_hlbox.GetSelectedTextBgColour(colBg); - } - -private: - const wxHtmlListBox& m_hlbox; - - DECLARE_NO_COPY_CLASS(wxHtmlListBoxStyle) -}; - -// ---------------------------------------------------------------------------- -// event tables -// ---------------------------------------------------------------------------- - -BEGIN_EVENT_TABLE(wxHtmlListBox, wxVListBox) - EVT_SIZE(wxHtmlListBox::OnSize) - EVT_MOTION(wxHtmlListBox::OnMouseMove) - EVT_LEFT_DOWN(wxHtmlListBox::OnLeftDown) -END_EVENT_TABLE() - -// ============================================================================ -// implementation -// ============================================================================ - -IMPLEMENT_ABSTRACT_CLASS(wxHtmlListBox, wxVListBox) - - -// ---------------------------------------------------------------------------- -// wxHtmlListBox creation -// ---------------------------------------------------------------------------- - -wxHtmlListBox::wxHtmlListBox() - : wxHtmlWindowMouseHelper(this) -{ - Init(); -} - -// normal constructor which calls Create() internally -wxHtmlListBox::wxHtmlListBox(wxWindow *parent, - wxWindowID id, - const wxPoint& pos, - const wxSize& size, - long style, - const wxString& name) - : wxHtmlWindowMouseHelper(this) -{ - Init(); - - (void)Create(parent, id, pos, size, style, name); -} - -void wxHtmlListBox::Init() -{ - m_htmlParser = NULL; - m_htmlRendStyle = new wxHtmlListBoxStyle(*this); - m_cache = new wxHtmlListBoxCache; -} - -bool wxHtmlListBox::Create(wxWindow *parent, - wxWindowID id, - const wxPoint& pos, - const wxSize& size, - long style, - const wxString& name) -{ - return wxVListBox::Create(parent, id, pos, size, style, name); -} - -wxHtmlListBox::~wxHtmlListBox() -{ - delete m_cache; - - if ( m_htmlParser ) - { - delete m_htmlParser->GetDC(); - delete m_htmlParser; - } - - delete m_htmlRendStyle; -} - -// ---------------------------------------------------------------------------- -// wxHtmlListBox appearance -// ---------------------------------------------------------------------------- - -wxColour wxHtmlListBox::GetSelectedTextColour(const wxColour& colFg) const -{ - return m_htmlRendStyle-> - wxDefaultHtmlRenderingStyle::GetSelectedTextColour(colFg); -} - -wxColour -wxHtmlListBox::GetSelectedTextBgColour(const wxColour& WXUNUSED(colBg)) const -{ - return GetSelectionBackground(); -} - -// ---------------------------------------------------------------------------- -// wxHtmlListBox items markup -// ---------------------------------------------------------------------------- - -wxString wxHtmlListBox::OnGetItemMarkup(size_t n) const -{ - // we don't even need to wrap the value returned by OnGetItem() inside - // "" and "" because wxHTML can parse it even - // without these tags - return OnGetItem(n); -} - -// ---------------------------------------------------------------------------- -// wxHtmlListBox cache handling -// ---------------------------------------------------------------------------- - -void wxHtmlListBox::CacheItem(size_t n) const -{ - if ( !m_cache->Has(n) ) - { - if ( !m_htmlParser ) - { - wxHtmlListBox *self = wxConstCast(this, wxHtmlListBox); - - self->m_htmlParser = new wxHtmlWinParser(self); - m_htmlParser->SetDC(new wxClientDC(self)); - m_htmlParser->SetFS(&self->m_filesystem); -#if !wxUSE_UNICODE - if (GetFont().Ok()) - m_htmlParser->SetInputEncoding(GetFont().GetEncoding()); -#endif - // use system's default GUI font by default: - m_htmlParser->SetStandardFonts(); - } - - wxHtmlContainerCell *cell = (wxHtmlContainerCell *)m_htmlParser-> - Parse(OnGetItemMarkup(n)); - wxCHECK_RET( cell, _T("wxHtmlParser::Parse() returned NULL?") ); - - // set the cell's ID to item's index so that CellCoordsToPhysical() - // can quickly find the item: - cell->SetId(wxString::Format(_T("%lu"), (unsigned long)n)); - - cell->Layout(GetClientSize().x - 2*GetMargins().x); - - m_cache->Store(n, cell); - } -} - -void wxHtmlListBox::OnSize(wxSizeEvent& event) -{ - // we need to relayout all the cached cells - m_cache->Clear(); - - event.Skip(); -} - -void wxHtmlListBox::RefreshLine(size_t line) -{ - m_cache->InvalidateRange(line, line); - - wxVListBox::RefreshLine(line); -} - -void wxHtmlListBox::RefreshLines(size_t from, size_t to) -{ - m_cache->InvalidateRange(from, to); - - wxVListBox::RefreshLines(from, to); -} - -void wxHtmlListBox::RefreshAll() -{ - m_cache->Clear(); - - wxVListBox::RefreshAll(); -} - -void wxHtmlListBox::SetItemCount(size_t count) -{ - // the items are going to change, forget the old ones - m_cache->Clear(); - - wxVListBox::SetItemCount(count); -} - -// ---------------------------------------------------------------------------- -// wxHtmlListBox implementation of wxVListBox pure virtuals -// ---------------------------------------------------------------------------- - -void wxHtmlListBox::OnDrawItem(wxDC& dc, const wxRect& rect, size_t n) const -{ - CacheItem(n); - - wxHtmlCell *cell = m_cache->Get(n); - wxCHECK_RET( cell, _T("this cell should be cached!") ); - - wxHtmlRenderingInfo htmlRendInfo; - - // draw the selected cell in selected state - if ( IsSelected(n) ) - { - wxHtmlSelection htmlSel; - htmlSel.Set(wxPoint(0,0), cell, wxPoint(INT_MAX, INT_MAX), cell); - htmlRendInfo.SetSelection(&htmlSel); - if ( m_htmlRendStyle ) - htmlRendInfo.SetStyle(m_htmlRendStyle); - htmlRendInfo.GetState().SetSelectionState(wxHTML_SEL_IN); - } - - // note that we can't stop drawing exactly at the window boundary as then - // even the visible cells part could be not drawn, so always draw the - // entire cell - cell->Draw(dc, - rect.x + CELL_BORDER, rect.y + CELL_BORDER, - 0, INT_MAX, htmlRendInfo); -} - -wxCoord wxHtmlListBox::OnMeasureItem(size_t n) const -{ - CacheItem(n); - - wxHtmlCell *cell = m_cache->Get(n); - wxCHECK_MSG( cell, 0, _T("this cell should be cached!") ); - - return cell->GetHeight() + cell->GetDescent() + 4; -} - -// ---------------------------------------------------------------------------- -// wxHtmlListBox implementation of wxHtmlListBoxWinInterface -// ---------------------------------------------------------------------------- - -void wxHtmlListBox::SetHTMLWindowTitle(const wxString& WXUNUSED(title)) -{ - // nothing to do -} - -void wxHtmlListBox::OnHTMLLinkClicked(const wxHtmlLinkInfo& link) -{ - OnLinkClicked(GetItemForCell(link.GetHtmlCell()), link); -} - -void wxHtmlListBox::OnLinkClicked(size_t WXUNUSED(n), - const wxHtmlLinkInfo& link) -{ - wxHtmlLinkEvent event(GetId(), link); - GetEventHandler()->ProcessEvent(event); -} - -wxHtmlOpeningStatus -wxHtmlListBox::OnHTMLOpeningURL(wxHtmlURLType WXUNUSED(type), - const wxString& WXUNUSED(url), - wxString *WXUNUSED(redirect)) const -{ - return wxHTML_OPEN; -} - -wxPoint wxHtmlListBox::HTMLCoordsToWindow(wxHtmlCell *cell, - const wxPoint& pos) const -{ - return CellCoordsToPhysical(pos, cell); -} - -wxWindow* wxHtmlListBox::GetHTMLWindow() { return this; } - -wxColour wxHtmlListBox::GetHTMLBackgroundColour() const -{ - return GetBackgroundColour(); -} - -void wxHtmlListBox::SetHTMLBackgroundColour(const wxColour& WXUNUSED(clr)) -{ - // nothing to do -} - -void wxHtmlListBox::SetHTMLBackgroundImage(const wxBitmap& WXUNUSED(bmpBg)) -{ - // nothing to do -} - -void wxHtmlListBox::SetHTMLStatusText(const wxString& WXUNUSED(text)) -{ - // nothing to do -} - -wxCursor wxHtmlListBox::GetHTMLCursor(HTMLCursor type) const -{ - // we don't want to show text selection cursor in listboxes - if (type == HTMLCursor_Text) - return wxHtmlWindow::GetDefaultHTMLCursor(HTMLCursor_Default); - - // in all other cases, use the same cursor as wxHtmlWindow: - return wxHtmlWindow::GetDefaultHTMLCursor(type); -} - -// ---------------------------------------------------------------------------- -// wxHtmlListBox handling of HTML links -// ---------------------------------------------------------------------------- - -wxPoint wxHtmlListBox::GetRootCellCoords(size_t n) const -{ - wxPoint pos(CELL_BORDER, CELL_BORDER); - pos += GetMargins(); - pos.y += GetLinesHeight(GetFirstVisibleLine(), n); - return pos; -} - -bool wxHtmlListBox::PhysicalCoordsToCell(wxPoint& pos, wxHtmlCell*& cell) const -{ - int n = HitTest(pos); - if ( n == wxNOT_FOUND ) - return false; - - // convert mouse coordinates to coords relative to item's wxHtmlCell: - pos -= GetRootCellCoords(n); - - CacheItem(n); - cell = m_cache->Get(n); - - return true; -} - -size_t wxHtmlListBox::GetItemForCell(const wxHtmlCell *cell) const -{ - wxCHECK_MSG( cell, 0, _T("no cell") ); - - cell = cell->GetRootCell(); - - wxCHECK_MSG( cell, 0, _T("no root cell") ); - - // the cell's ID contains item index, see CacheItem(): - unsigned long n; - if ( !cell->GetId().ToULong(&n) ) - { - wxFAIL_MSG( _T("unexpected root cell's ID") ); - return 0; - } - - return n; -} - -wxPoint -wxHtmlListBox::CellCoordsToPhysical(const wxPoint& pos, wxHtmlCell *cell) const -{ - return pos + GetRootCellCoords(GetItemForCell(cell)); -} - -void wxHtmlListBox::OnInternalIdle() -{ - wxVListBox::OnInternalIdle(); - - if ( wxHtmlWindowMouseHelper::DidMouseMove() ) - { - wxPoint pos = ScreenToClient(wxGetMousePosition()); - wxHtmlCell *cell; - - if ( !PhysicalCoordsToCell(pos, cell) ) - return; - - wxHtmlWindowMouseHelper::HandleIdle(cell, pos); - } -} - -void wxHtmlListBox::OnMouseMove(wxMouseEvent& event) -{ - wxHtmlWindowMouseHelper::HandleMouseMoved(); - event.Skip(); -} - -void wxHtmlListBox::OnLeftDown(wxMouseEvent& event) -{ - wxPoint pos = event.GetPosition(); - wxHtmlCell *cell; - - if ( !PhysicalCoordsToCell(pos, cell) ) - { - event.Skip(); - return; - } - - if ( !wxHtmlWindowMouseHelper::HandleMouseClick(cell, pos, event) ) - { - // no link was clicked, so let the listbox code handle the click (e.g. - // by selecting another item in the list): - event.Skip(); - } -} - - -// ---------------------------------------------------------------------------- -// wxSimpleHtmlListBox -// ---------------------------------------------------------------------------- - -bool wxSimpleHtmlListBox::Create(wxWindow *parent, wxWindowID id, - const wxPoint& pos, - const wxSize& size, - int n, const wxString choices[], - long style, - const wxValidator& validator, - const wxString& name) -{ - if (!wxHtmlListBox::Create(parent, id, pos, size, style, name)) - return false; - -#if wxUSE_VALIDATORS - SetValidator(validator); -#endif - for (int i=0; iIsFrozen()) - RefreshAll(); -} - -#endif // wxUSE_HTML +/////////////////////////////////////////////////////////////////////////////// +// Name: generic/htmllbox.cpp +// Purpose: implementation of wxHtmlListBox +// Author: Vadim Zeitlin +// Modified by: +// Created: 31.05.03 +// RCS-ID: $Id: htmllbox.cpp 44026 2006-12-21 18:24:27Z VS $ +// Copyright: (c) 2003 Vadim Zeitlin +// License: wxWindows license +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#ifndef WX_PRECOMP + #include "wx/dcclient.h" +#endif //WX_PRECOMP + +#if wxUSE_HTML + +#include "wx/htmllbox.h" + +#include "wx/html/htmlcell.h" +#include "wx/html/winpars.h" + +// this hack forces the linker to always link in m_* files +#include "wx/html/forcelnk.h" +FORCE_WXHTML_MODULES() + +// ---------------------------------------------------------------------------- +// constants +// ---------------------------------------------------------------------------- + +// small border always added to the cells: +static const wxCoord CELL_BORDER = 2; + +const wxChar wxHtmlListBoxNameStr[] = wxT("htmlListBox"); +const wxChar wxSimpleHtmlListBoxNameStr[] = wxT("simpleHtmlListBox"); + +// ============================================================================ +// private classes +// ============================================================================ + +// ---------------------------------------------------------------------------- +// wxHtmlListBoxCache +// ---------------------------------------------------------------------------- + +// this class is used by wxHtmlListBox to cache the parsed representation of +// the items to avoid doing it anew each time an item must be drawn +class wxHtmlListBoxCache +{ +private: + // invalidate a single item, used by Clear() and InvalidateRange() + void InvalidateItem(size_t n) + { + m_items[n] = (size_t)-1; + delete m_cells[n]; + m_cells[n] = NULL; + } + +public: + wxHtmlListBoxCache() + { + for ( size_t n = 0; n < SIZE; n++ ) + { + m_items[n] = (size_t)-1; + m_cells[n] = NULL; + } + + m_next = 0; + } + + ~wxHtmlListBoxCache() + { + for ( size_t n = 0; n < SIZE; n++ ) + { + delete m_cells[n]; + } + } + + // completely invalidate the cache + void Clear() + { + for ( size_t n = 0; n < SIZE; n++ ) + { + InvalidateItem(n); + } + } + + // return the cached cell for this index or NULL if none + wxHtmlCell *Get(size_t item) const + { + for ( size_t n = 0; n < SIZE; n++ ) + { + if ( m_items[n] == item ) + return m_cells[n]; + } + + return NULL; + } + + // returns true if we already have this item cached + bool Has(size_t item) const { return Get(item) != NULL; } + + // ensure that the item is cached + void Store(size_t item, wxHtmlCell *cell) + { + delete m_cells[m_next]; + m_cells[m_next] = cell; + m_items[m_next] = item; + + // advance to the next item wrapping around if there are no more + if ( ++m_next == SIZE ) + m_next = 0; + } + + // forget the cached value of the item(s) between the given ones (inclusive) + void InvalidateRange(size_t from, size_t to) + { + for ( size_t n = 0; n < SIZE; n++ ) + { + if ( m_items[n] >= from && m_items[n] <= to ) + { + InvalidateItem(n); + } + } + } + +private: + // the max number of the items we cache + enum { SIZE = 50 }; + + // the index of the LRU (oldest) cell + size_t m_next; + + // the parsed representation of the cached item or NULL + wxHtmlCell *m_cells[SIZE]; + + // the index of the currently cached item (only valid if m_cells != NULL) + size_t m_items[SIZE]; +}; + +// ---------------------------------------------------------------------------- +// wxHtmlListBoxStyle +// ---------------------------------------------------------------------------- + +// just forward wxDefaultHtmlRenderingStyle callbacks to the main class so that +// they could be overridden by the user code +class wxHtmlListBoxStyle : public wxDefaultHtmlRenderingStyle +{ +public: + wxHtmlListBoxStyle(const wxHtmlListBox& hlbox) : m_hlbox(hlbox) { } + + virtual wxColour GetSelectedTextColour(const wxColour& colFg) + { + return m_hlbox.GetSelectedTextColour(colFg); + } + + virtual wxColour GetSelectedTextBgColour(const wxColour& colBg) + { + return m_hlbox.GetSelectedTextBgColour(colBg); + } + +private: + const wxHtmlListBox& m_hlbox; + + DECLARE_NO_COPY_CLASS(wxHtmlListBoxStyle) +}; + +// ---------------------------------------------------------------------------- +// event tables +// ---------------------------------------------------------------------------- + +BEGIN_EVENT_TABLE(wxHtmlListBox, wxVListBox) + EVT_SIZE(wxHtmlListBox::OnSize) + EVT_MOTION(wxHtmlListBox::OnMouseMove) + EVT_LEFT_DOWN(wxHtmlListBox::OnLeftDown) +END_EVENT_TABLE() + +// ============================================================================ +// implementation +// ============================================================================ + +IMPLEMENT_ABSTRACT_CLASS(wxHtmlListBox, wxVListBox) + + +// ---------------------------------------------------------------------------- +// wxHtmlListBox creation +// ---------------------------------------------------------------------------- + +wxHtmlListBox::wxHtmlListBox() + : wxHtmlWindowMouseHelper(this) +{ + Init(); +} + +// normal constructor which calls Create() internally +wxHtmlListBox::wxHtmlListBox(wxWindow *parent, + wxWindowID id, + const wxPoint& pos, + const wxSize& size, + long style, + const wxString& name) + : wxHtmlWindowMouseHelper(this) +{ + Init(); + + (void)Create(parent, id, pos, size, style, name); +} + +void wxHtmlListBox::Init() +{ + m_htmlParser = NULL; + m_htmlRendStyle = new wxHtmlListBoxStyle(*this); + m_cache = new wxHtmlListBoxCache; +} + +bool wxHtmlListBox::Create(wxWindow *parent, + wxWindowID id, + const wxPoint& pos, + const wxSize& size, + long style, + const wxString& name) +{ + return wxVListBox::Create(parent, id, pos, size, style, name); +} + +wxHtmlListBox::~wxHtmlListBox() +{ + delete m_cache; + + if ( m_htmlParser ) + { + delete m_htmlParser->GetDC(); + delete m_htmlParser; + } + + delete m_htmlRendStyle; +} + +// ---------------------------------------------------------------------------- +// wxHtmlListBox appearance +// ---------------------------------------------------------------------------- + +wxColour wxHtmlListBox::GetSelectedTextColour(const wxColour& colFg) const +{ + return m_htmlRendStyle-> + wxDefaultHtmlRenderingStyle::GetSelectedTextColour(colFg); +} + +wxColour +wxHtmlListBox::GetSelectedTextBgColour(const wxColour& WXUNUSED(colBg)) const +{ + return GetSelectionBackground(); +} + +// ---------------------------------------------------------------------------- +// wxHtmlListBox items markup +// ---------------------------------------------------------------------------- + +wxString wxHtmlListBox::OnGetItemMarkup(size_t n) const +{ + // we don't even need to wrap the value returned by OnGetItem() inside + // "" and "" because wxHTML can parse it even + // without these tags + return OnGetItem(n); +} + +// ---------------------------------------------------------------------------- +// wxHtmlListBox cache handling +// ---------------------------------------------------------------------------- + +void wxHtmlListBox::CacheItem(size_t n) const +{ + if ( !m_cache->Has(n) ) + { + if ( !m_htmlParser ) + { + wxHtmlListBox *self = wxConstCast(this, wxHtmlListBox); + + self->m_htmlParser = new wxHtmlWinParser(self); + m_htmlParser->SetDC(new wxClientDC(self)); + m_htmlParser->SetFS(&self->m_filesystem); +#if !wxUSE_UNICODE + if (GetFont().Ok()) + m_htmlParser->SetInputEncoding(GetFont().GetEncoding()); +#endif + // use system's default GUI font by default: + m_htmlParser->SetStandardFonts(); + } + + wxHtmlContainerCell *cell = (wxHtmlContainerCell *)m_htmlParser-> + Parse(OnGetItemMarkup(n)); + wxCHECK_RET( cell, _T("wxHtmlParser::Parse() returned NULL?") ); + + // set the cell's ID to item's index so that CellCoordsToPhysical() + // can quickly find the item: + cell->SetId(wxString::Format(_T("%lu"), (unsigned long)n)); + + cell->Layout(GetClientSize().x - 2*GetMargins().x); + + m_cache->Store(n, cell); + } +} + +void wxHtmlListBox::OnSize(wxSizeEvent& event) +{ + // we need to relayout all the cached cells + m_cache->Clear(); + + event.Skip(); +} + +void wxHtmlListBox::RefreshLine(size_t line) +{ + m_cache->InvalidateRange(line, line); + + wxVListBox::RefreshLine(line); +} + +void wxHtmlListBox::RefreshLines(size_t from, size_t to) +{ + m_cache->InvalidateRange(from, to); + + wxVListBox::RefreshLines(from, to); +} + +void wxHtmlListBox::RefreshAll() +{ + m_cache->Clear(); + + wxVListBox::RefreshAll(); +} + +void wxHtmlListBox::SetItemCount(size_t count) +{ + // the items are going to change, forget the old ones + m_cache->Clear(); + + wxVListBox::SetItemCount(count); +} + +// ---------------------------------------------------------------------------- +// wxHtmlListBox implementation of wxVListBox pure virtuals +// ---------------------------------------------------------------------------- + +void wxHtmlListBox::OnDrawItem(wxDC& dc, const wxRect& rect, size_t n) const +{ + CacheItem(n); + + wxHtmlCell *cell = m_cache->Get(n); + wxCHECK_RET( cell, _T("this cell should be cached!") ); + + wxHtmlRenderingInfo htmlRendInfo; + + // draw the selected cell in selected state + if ( IsSelected(n) ) + { + wxHtmlSelection htmlSel; + htmlSel.Set(wxPoint(0,0), cell, wxPoint(INT_MAX, INT_MAX), cell); + htmlRendInfo.SetSelection(&htmlSel); + if ( m_htmlRendStyle ) + htmlRendInfo.SetStyle(m_htmlRendStyle); + htmlRendInfo.GetState().SetSelectionState(wxHTML_SEL_IN); + } + + // note that we can't stop drawing exactly at the window boundary as then + // even the visible cells part could be not drawn, so always draw the + // entire cell + cell->Draw(dc, + rect.x + CELL_BORDER, rect.y + CELL_BORDER, + 0, INT_MAX, htmlRendInfo); +} + +wxCoord wxHtmlListBox::OnMeasureItem(size_t n) const +{ + CacheItem(n); + + wxHtmlCell *cell = m_cache->Get(n); + wxCHECK_MSG( cell, 0, _T("this cell should be cached!") ); + + return cell->GetHeight() + cell->GetDescent() + 4; +} + +// ---------------------------------------------------------------------------- +// wxHtmlListBox implementation of wxHtmlListBoxWinInterface +// ---------------------------------------------------------------------------- + +void wxHtmlListBox::SetHTMLWindowTitle(const wxString& WXUNUSED(title)) +{ + // nothing to do +} + +void wxHtmlListBox::OnHTMLLinkClicked(const wxHtmlLinkInfo& link) +{ + OnLinkClicked(GetItemForCell(link.GetHtmlCell()), link); +} + +void wxHtmlListBox::OnLinkClicked(size_t WXUNUSED(n), + const wxHtmlLinkInfo& link) +{ + wxHtmlLinkEvent event(GetId(), link); + GetEventHandler()->ProcessEvent(event); +} + +wxHtmlOpeningStatus +wxHtmlListBox::OnHTMLOpeningURL(wxHtmlURLType WXUNUSED(type), + const wxString& WXUNUSED(url), + wxString *WXUNUSED(redirect)) const +{ + return wxHTML_OPEN; +} + +wxPoint wxHtmlListBox::HTMLCoordsToWindow(wxHtmlCell *cell, + const wxPoint& pos) const +{ + return CellCoordsToPhysical(pos, cell); +} + +wxWindow* wxHtmlListBox::GetHTMLWindow() { return this; } + +wxColour wxHtmlListBox::GetHTMLBackgroundColour() const +{ + return GetBackgroundColour(); +} + +void wxHtmlListBox::SetHTMLBackgroundColour(const wxColour& WXUNUSED(clr)) +{ + // nothing to do +} + +void wxHtmlListBox::SetHTMLBackgroundImage(const wxBitmap& WXUNUSED(bmpBg)) +{ + // nothing to do +} + +void wxHtmlListBox::SetHTMLStatusText(const wxString& WXUNUSED(text)) +{ + // nothing to do +} + +wxCursor wxHtmlListBox::GetHTMLCursor(HTMLCursor type) const +{ + // we don't want to show text selection cursor in listboxes + if (type == HTMLCursor_Text) + return wxHtmlWindow::GetDefaultHTMLCursor(HTMLCursor_Default); + + // in all other cases, use the same cursor as wxHtmlWindow: + return wxHtmlWindow::GetDefaultHTMLCursor(type); +} + +// ---------------------------------------------------------------------------- +// wxHtmlListBox handling of HTML links +// ---------------------------------------------------------------------------- + +wxPoint wxHtmlListBox::GetRootCellCoords(size_t n) const +{ + wxPoint pos(CELL_BORDER, CELL_BORDER); + pos += GetMargins(); + pos.y += GetLinesHeight(GetFirstVisibleLine(), n); + return pos; +} + +bool wxHtmlListBox::PhysicalCoordsToCell(wxPoint& pos, wxHtmlCell*& cell) const +{ + int n = HitTest(pos); + if ( n == wxNOT_FOUND ) + return false; + + // convert mouse coordinates to coords relative to item's wxHtmlCell: + pos -= GetRootCellCoords(n); + + CacheItem(n); + cell = m_cache->Get(n); + + return true; +} + +size_t wxHtmlListBox::GetItemForCell(const wxHtmlCell *cell) const +{ + wxCHECK_MSG( cell, 0, _T("no cell") ); + + cell = cell->GetRootCell(); + + wxCHECK_MSG( cell, 0, _T("no root cell") ); + + // the cell's ID contains item index, see CacheItem(): + unsigned long n; + if ( !cell->GetId().ToULong(&n) ) + { + wxFAIL_MSG( _T("unexpected root cell's ID") ); + return 0; + } + + return n; +} + +wxPoint +wxHtmlListBox::CellCoordsToPhysical(const wxPoint& pos, wxHtmlCell *cell) const +{ + return pos + GetRootCellCoords(GetItemForCell(cell)); +} + +void wxHtmlListBox::OnInternalIdle() +{ + wxVListBox::OnInternalIdle(); + + if ( wxHtmlWindowMouseHelper::DidMouseMove() ) + { + wxPoint pos = ScreenToClient(wxGetMousePosition()); + wxHtmlCell *cell; + + if ( !PhysicalCoordsToCell(pos, cell) ) + return; + + wxHtmlWindowMouseHelper::HandleIdle(cell, pos); + } +} + +void wxHtmlListBox::OnMouseMove(wxMouseEvent& event) +{ + wxHtmlWindowMouseHelper::HandleMouseMoved(); + event.Skip(); +} + +void wxHtmlListBox::OnLeftDown(wxMouseEvent& event) +{ + wxPoint pos = event.GetPosition(); + wxHtmlCell *cell; + + if ( !PhysicalCoordsToCell(pos, cell) ) + { + event.Skip(); + return; + } + + if ( !wxHtmlWindowMouseHelper::HandleMouseClick(cell, pos, event) ) + { + // no link was clicked, so let the listbox code handle the click (e.g. + // by selecting another item in the list): + event.Skip(); + } +} + + +// ---------------------------------------------------------------------------- +// wxSimpleHtmlListBox +// ---------------------------------------------------------------------------- + +bool wxSimpleHtmlListBox::Create(wxWindow *parent, wxWindowID id, + const wxPoint& pos, + const wxSize& size, + int n, const wxString choices[], + long style, + const wxValidator& validator, + const wxString& name) +{ + if (!wxHtmlListBox::Create(parent, id, pos, size, style, name)) + return false; + +#if wxUSE_VALIDATORS + SetValidator(validator); +#endif + for (int i=0; iIsFrozen()) + RefreshAll(); +} + +#endif // wxUSE_HTML diff --git a/Externals/wxWidgets/src/generic/hyperlink.cpp b/Externals/wxWidgets/src/generic/hyperlink.cpp index 7ee1ad3905..e2416bcc09 100644 --- a/Externals/wxWidgets/src/generic/hyperlink.cpp +++ b/Externals/wxWidgets/src/generic/hyperlink.cpp @@ -1,284 +1,284 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/generic/hyperlink.cpp -// Purpose: Hyperlink control -// Author: David Norris , Otto Wyss -// Modified by: Ryan Norton, Francesco Montorsi -// Created: 04/02/2005 -// RCS-ID: $Id: hyperlink.cpp 52131 2008-02-27 02:18:42Z VZ $ -// Copyright: (c) 2005 David Norris -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -//--------------------------------------------------------------------------- -// Pre-compiled header stuff -//--------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_HYPERLINKCTRL - -//--------------------------------------------------------------------------- -// Includes -//--------------------------------------------------------------------------- - -#include "wx/hyperlink.h" - -#ifndef WX_PRECOMP - #include "wx/utils.h" // for wxLaunchDefaultBrowser - #include "wx/dcclient.h" - #include "wx/menu.h" - #include "wx/log.h" - #include "wx/dataobj.h" -#endif - -#include "wx/clipbrd.h" - -// ============================================================================ -// implementation -// ============================================================================ - -IMPLEMENT_DYNAMIC_CLASS(wxHyperlinkCtrl, wxControl) -IMPLEMENT_DYNAMIC_CLASS(wxHyperlinkEvent, wxCommandEvent) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_HYPERLINK) - -// reserved for internal use only -#define wxHYPERLINKCTRL_POPUP_COPY_ID 16384 - -const wxChar wxHyperlinkCtrlNameStr[] = wxT("hyperlink"); - -// ---------------------------------------------------------------------------- -// wxHyperlinkCtrl -// ---------------------------------------------------------------------------- - -BEGIN_EVENT_TABLE(wxHyperlinkCtrl, wxControl) - EVT_PAINT(wxHyperlinkCtrl::OnPaint) - EVT_LEFT_DOWN(wxHyperlinkCtrl::OnLeftDown) - EVT_LEFT_UP(wxHyperlinkCtrl::OnLeftUp) - EVT_RIGHT_UP(wxHyperlinkCtrl::OnRightUp) - EVT_MOTION(wxHyperlinkCtrl::OnMotion) - EVT_LEAVE_WINDOW(wxHyperlinkCtrl::OnLeaveWindow) - EVT_SIZE(wxHyperlinkCtrl::OnSize) - - // for the context menu - EVT_MENU(wxHYPERLINKCTRL_POPUP_COPY_ID, wxHyperlinkCtrl::OnPopUpCopy) -END_EVENT_TABLE() - -bool wxHyperlinkCtrl::Create(wxWindow *parent, wxWindowID id, - const wxString& label, const wxString& url, const wxPoint& pos, - const wxSize& size, long style, const wxString& name) -{ - wxASSERT_MSG(!url.empty() || !label.empty(), - wxT("Both URL and label are empty ?")); - -#ifdef __WXDEBUG__ - int alignment = (int)((style & wxHL_ALIGN_LEFT) != 0) + - (int)((style & wxHL_ALIGN_CENTRE) != 0) + - (int)((style & wxHL_ALIGN_RIGHT) != 0); - wxASSERT_MSG(alignment == 1, - wxT("Specify exactly one align flag!")); -#endif - - if (!wxControl::Create(parent, id, pos, size, style, wxDefaultValidator, name)) - return false; - - // set to non empty strings both the url and the label - if(url.empty()) - SetURL(label); - else - SetURL(url); - - if(label.empty()) - SetLabel(url); - else - SetLabel(label); - - m_rollover = false; - m_clicking = false; - m_visited = false; - - // colours - m_normalColour = *wxBLUE; - m_hoverColour = *wxRED; - SetForegroundColour(m_normalColour); - - // by default the font of an hyperlink control is underlined - wxFont f = GetFont(); - f.SetUnderlined(true); - SetFont(f); - - SetInitialSize(size); - - return true; -} - -wxSize wxHyperlinkCtrl::DoGetBestSize() const -{ - int w, h; - - wxClientDC dc((wxWindow *)this); - dc.SetFont(GetFont()); - dc.GetTextExtent(GetLabel(), &w, &h); - - wxSize best(w, h); - CacheBestSize(best); - return best; -} - - -void wxHyperlinkCtrl::SetNormalColour(const wxColour &colour) -{ - m_normalColour = colour; - if (!m_visited) - { - SetForegroundColour(m_normalColour); - Refresh(); - } -} - -void wxHyperlinkCtrl::SetVisitedColour(const wxColour &colour) -{ - m_visitedColour = colour; - if (m_visited) - { - SetForegroundColour(m_visitedColour); - Refresh(); - } -} - -void wxHyperlinkCtrl::DoContextMenu(const wxPoint &pos) -{ - wxMenu *menuPopUp = new wxMenu(wxEmptyString, wxMENU_TEAROFF); - menuPopUp->Append(wxHYPERLINKCTRL_POPUP_COPY_ID, _("&Copy URL")); - PopupMenu( menuPopUp, pos ); - delete menuPopUp; -} - -wxRect wxHyperlinkCtrl::GetLabelRect() const -{ - // our best size is always the size of the label without borders - wxSize c(GetClientSize()), b(GetBestSize()); - wxPoint offset; - - // the label is always centered vertically - offset.y = (c.GetHeight()-b.GetHeight())/2; - - if (HasFlag(wxHL_ALIGN_CENTRE)) - offset.x = (c.GetWidth()-b.GetWidth())/2; - else if (HasFlag(wxHL_ALIGN_RIGHT)) - offset.x = c.GetWidth()-b.GetWidth(); - else if (HasFlag(wxHL_ALIGN_LEFT)) - offset.x = 0; - return wxRect(offset, b); -} - - - -// ---------------------------------------------------------------------------- -// wxHyperlinkCtrl - event handlers -// ---------------------------------------------------------------------------- - -void wxHyperlinkCtrl::OnPaint(wxPaintEvent& WXUNUSED(event)) -{ - wxPaintDC dc(this); - dc.SetFont(GetFont()); - dc.SetTextForeground(GetForegroundColour()); - dc.SetTextBackground(GetBackgroundColour()); - - dc.DrawText(GetLabel(), GetLabelRect().GetTopLeft()); -} - -void wxHyperlinkCtrl::OnLeftDown(wxMouseEvent& event) -{ - // the left click must start from the hyperlink rect - m_clicking = GetLabelRect().Contains(event.GetPosition()); -} - -void wxHyperlinkCtrl::OnLeftUp(wxMouseEvent& event) -{ - // the click must be started and ended in the hyperlink rect - if (!m_clicking || !GetLabelRect().Contains(event.GetPosition())) - return; - - SetForegroundColour(m_visitedColour); - m_visited = true; - m_clicking = false; - - // send the event - wxHyperlinkEvent linkEvent(this, GetId(), m_url); - if (!GetEventHandler()->ProcessEvent(linkEvent)) // was the event skipped ? - if (!wxLaunchDefaultBrowser(m_url)) - wxLogWarning(wxT("Could not launch the default browser with url '%s' !"), m_url.c_str()); -} - -void wxHyperlinkCtrl::OnRightUp(wxMouseEvent& event) -{ - if( GetWindowStyle() & wxHL_CONTEXTMENU ) - if ( GetLabelRect().Contains(event.GetPosition()) ) - DoContextMenu(wxPoint(event.m_x, event.m_y)); -} - -void wxHyperlinkCtrl::OnMotion(wxMouseEvent& event) -{ - wxRect textrc = GetLabelRect(); - - if (textrc.Contains(event.GetPosition())) - { - SetCursor(wxCursor(wxCURSOR_HAND)); - SetForegroundColour(m_hoverColour); - m_rollover = true; - Refresh(); - } - else if (m_rollover) - { - SetCursor(*wxSTANDARD_CURSOR); - SetForegroundColour(!m_visited ? m_normalColour : m_visitedColour); - m_rollover = false; - Refresh(); - } -} - -void wxHyperlinkCtrl::OnLeaveWindow(wxMouseEvent& WXUNUSED(event) ) -{ - // NB: when the label rect and the client size rect have the same - // height this function is indispensable to remove the "rollover" - // effect as the OnMotion() event handler could not be called - // in that case moving the mouse out of the label vertically... - - if (m_rollover) - { - SetCursor(*wxSTANDARD_CURSOR); - SetForegroundColour(!m_visited ? m_normalColour : m_visitedColour); - m_rollover = false; - Refresh(); - } -} - -void wxHyperlinkCtrl::OnPopUpCopy( wxCommandEvent& WXUNUSED(event) ) -{ -#if wxUSE_CLIPBOARD - if (!wxTheClipboard->Open()) - return; - - wxTextDataObject *data = new wxTextDataObject( m_url ); - wxTheClipboard->SetData( data ); - wxTheClipboard->Close(); -#endif // wxUSE_CLIPBOARD -} - -void wxHyperlinkCtrl::OnSize(wxSizeEvent& WXUNUSED(event)) -{ - // update the position of the label in the screen respecting - // the selected align flag - Refresh(); -} - -#endif // wxUSE_HYPERLINKCTRL +///////////////////////////////////////////////////////////////////////////// +// Name: src/generic/hyperlink.cpp +// Purpose: Hyperlink control +// Author: David Norris , Otto Wyss +// Modified by: Ryan Norton, Francesco Montorsi +// Created: 04/02/2005 +// RCS-ID: $Id: hyperlink.cpp 52131 2008-02-27 02:18:42Z VZ $ +// Copyright: (c) 2005 David Norris +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +//--------------------------------------------------------------------------- +// Pre-compiled header stuff +//--------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_HYPERLINKCTRL + +//--------------------------------------------------------------------------- +// Includes +//--------------------------------------------------------------------------- + +#include "wx/hyperlink.h" + +#ifndef WX_PRECOMP + #include "wx/utils.h" // for wxLaunchDefaultBrowser + #include "wx/dcclient.h" + #include "wx/menu.h" + #include "wx/log.h" + #include "wx/dataobj.h" +#endif + +#include "wx/clipbrd.h" + +// ============================================================================ +// implementation +// ============================================================================ + +IMPLEMENT_DYNAMIC_CLASS(wxHyperlinkCtrl, wxControl) +IMPLEMENT_DYNAMIC_CLASS(wxHyperlinkEvent, wxCommandEvent) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_HYPERLINK) + +// reserved for internal use only +#define wxHYPERLINKCTRL_POPUP_COPY_ID 16384 + +const wxChar wxHyperlinkCtrlNameStr[] = wxT("hyperlink"); + +// ---------------------------------------------------------------------------- +// wxHyperlinkCtrl +// ---------------------------------------------------------------------------- + +BEGIN_EVENT_TABLE(wxHyperlinkCtrl, wxControl) + EVT_PAINT(wxHyperlinkCtrl::OnPaint) + EVT_LEFT_DOWN(wxHyperlinkCtrl::OnLeftDown) + EVT_LEFT_UP(wxHyperlinkCtrl::OnLeftUp) + EVT_RIGHT_UP(wxHyperlinkCtrl::OnRightUp) + EVT_MOTION(wxHyperlinkCtrl::OnMotion) + EVT_LEAVE_WINDOW(wxHyperlinkCtrl::OnLeaveWindow) + EVT_SIZE(wxHyperlinkCtrl::OnSize) + + // for the context menu + EVT_MENU(wxHYPERLINKCTRL_POPUP_COPY_ID, wxHyperlinkCtrl::OnPopUpCopy) +END_EVENT_TABLE() + +bool wxHyperlinkCtrl::Create(wxWindow *parent, wxWindowID id, + const wxString& label, const wxString& url, const wxPoint& pos, + const wxSize& size, long style, const wxString& name) +{ + wxASSERT_MSG(!url.empty() || !label.empty(), + wxT("Both URL and label are empty ?")); + +#ifdef __WXDEBUG__ + int alignment = (int)((style & wxHL_ALIGN_LEFT) != 0) + + (int)((style & wxHL_ALIGN_CENTRE) != 0) + + (int)((style & wxHL_ALIGN_RIGHT) != 0); + wxASSERT_MSG(alignment == 1, + wxT("Specify exactly one align flag!")); +#endif + + if (!wxControl::Create(parent, id, pos, size, style, wxDefaultValidator, name)) + return false; + + // set to non empty strings both the url and the label + if(url.empty()) + SetURL(label); + else + SetURL(url); + + if(label.empty()) + SetLabel(url); + else + SetLabel(label); + + m_rollover = false; + m_clicking = false; + m_visited = false; + + // colours + m_normalColour = *wxBLUE; + m_hoverColour = *wxRED; + SetForegroundColour(m_normalColour); + + // by default the font of an hyperlink control is underlined + wxFont f = GetFont(); + f.SetUnderlined(true); + SetFont(f); + + SetInitialSize(size); + + return true; +} + +wxSize wxHyperlinkCtrl::DoGetBestSize() const +{ + int w, h; + + wxClientDC dc((wxWindow *)this); + dc.SetFont(GetFont()); + dc.GetTextExtent(GetLabel(), &w, &h); + + wxSize best(w, h); + CacheBestSize(best); + return best; +} + + +void wxHyperlinkCtrl::SetNormalColour(const wxColour &colour) +{ + m_normalColour = colour; + if (!m_visited) + { + SetForegroundColour(m_normalColour); + Refresh(); + } +} + +void wxHyperlinkCtrl::SetVisitedColour(const wxColour &colour) +{ + m_visitedColour = colour; + if (m_visited) + { + SetForegroundColour(m_visitedColour); + Refresh(); + } +} + +void wxHyperlinkCtrl::DoContextMenu(const wxPoint &pos) +{ + wxMenu *menuPopUp = new wxMenu(wxEmptyString, wxMENU_TEAROFF); + menuPopUp->Append(wxHYPERLINKCTRL_POPUP_COPY_ID, _("&Copy URL")); + PopupMenu( menuPopUp, pos ); + delete menuPopUp; +} + +wxRect wxHyperlinkCtrl::GetLabelRect() const +{ + // our best size is always the size of the label without borders + wxSize c(GetClientSize()), b(GetBestSize()); + wxPoint offset; + + // the label is always centered vertically + offset.y = (c.GetHeight()-b.GetHeight())/2; + + if (HasFlag(wxHL_ALIGN_CENTRE)) + offset.x = (c.GetWidth()-b.GetWidth())/2; + else if (HasFlag(wxHL_ALIGN_RIGHT)) + offset.x = c.GetWidth()-b.GetWidth(); + else if (HasFlag(wxHL_ALIGN_LEFT)) + offset.x = 0; + return wxRect(offset, b); +} + + + +// ---------------------------------------------------------------------------- +// wxHyperlinkCtrl - event handlers +// ---------------------------------------------------------------------------- + +void wxHyperlinkCtrl::OnPaint(wxPaintEvent& WXUNUSED(event)) +{ + wxPaintDC dc(this); + dc.SetFont(GetFont()); + dc.SetTextForeground(GetForegroundColour()); + dc.SetTextBackground(GetBackgroundColour()); + + dc.DrawText(GetLabel(), GetLabelRect().GetTopLeft()); +} + +void wxHyperlinkCtrl::OnLeftDown(wxMouseEvent& event) +{ + // the left click must start from the hyperlink rect + m_clicking = GetLabelRect().Contains(event.GetPosition()); +} + +void wxHyperlinkCtrl::OnLeftUp(wxMouseEvent& event) +{ + // the click must be started and ended in the hyperlink rect + if (!m_clicking || !GetLabelRect().Contains(event.GetPosition())) + return; + + SetForegroundColour(m_visitedColour); + m_visited = true; + m_clicking = false; + + // send the event + wxHyperlinkEvent linkEvent(this, GetId(), m_url); + if (!GetEventHandler()->ProcessEvent(linkEvent)) // was the event skipped ? + if (!wxLaunchDefaultBrowser(m_url)) + wxLogWarning(wxT("Could not launch the default browser with url '%s' !"), m_url.c_str()); +} + +void wxHyperlinkCtrl::OnRightUp(wxMouseEvent& event) +{ + if( GetWindowStyle() & wxHL_CONTEXTMENU ) + if ( GetLabelRect().Contains(event.GetPosition()) ) + DoContextMenu(wxPoint(event.m_x, event.m_y)); +} + +void wxHyperlinkCtrl::OnMotion(wxMouseEvent& event) +{ + wxRect textrc = GetLabelRect(); + + if (textrc.Contains(event.GetPosition())) + { + SetCursor(wxCursor(wxCURSOR_HAND)); + SetForegroundColour(m_hoverColour); + m_rollover = true; + Refresh(); + } + else if (m_rollover) + { + SetCursor(*wxSTANDARD_CURSOR); + SetForegroundColour(!m_visited ? m_normalColour : m_visitedColour); + m_rollover = false; + Refresh(); + } +} + +void wxHyperlinkCtrl::OnLeaveWindow(wxMouseEvent& WXUNUSED(event) ) +{ + // NB: when the label rect and the client size rect have the same + // height this function is indispensable to remove the "rollover" + // effect as the OnMotion() event handler could not be called + // in that case moving the mouse out of the label vertically... + + if (m_rollover) + { + SetCursor(*wxSTANDARD_CURSOR); + SetForegroundColour(!m_visited ? m_normalColour : m_visitedColour); + m_rollover = false; + Refresh(); + } +} + +void wxHyperlinkCtrl::OnPopUpCopy( wxCommandEvent& WXUNUSED(event) ) +{ +#if wxUSE_CLIPBOARD + if (!wxTheClipboard->Open()) + return; + + wxTextDataObject *data = new wxTextDataObject( m_url ); + wxTheClipboard->SetData( data ); + wxTheClipboard->Close(); +#endif // wxUSE_CLIPBOARD +} + +void wxHyperlinkCtrl::OnSize(wxSizeEvent& WXUNUSED(event)) +{ + // update the position of the label in the screen respecting + // the selected align flag + Refresh(); +} + +#endif // wxUSE_HYPERLINKCTRL diff --git a/Externals/wxWidgets/src/generic/icon.cpp b/Externals/wxWidgets/src/generic/icon.cpp index d1c18d57da..d86a1d4843 100644 --- a/Externals/wxWidgets/src/generic/icon.cpp +++ b/Externals/wxWidgets/src/generic/icon.cpp @@ -1,45 +1,45 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/generic/icon.cpp -// Purpose: wxIcon implementation for ports where it's same as wxBitmap -// Author: Julian Smart -// Modified by: -// Created: 17/09/98 -// RCS-ID: $Id: icon.cpp 40531 2006-08-09 17:59:30Z VS $ -// Copyright: (c) Julian Smart -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// for compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#include "wx/icon.h" - -//----------------------------------------------------------------------------- -// wxIcon -//----------------------------------------------------------------------------- - -IMPLEMENT_DYNAMIC_CLASS(wxIcon, wxBitmap) - -wxIcon::wxIcon( const char **bits, int WXUNUSED(width), int WXUNUSED(height) ) : - wxBitmap( bits ) -{ -} - -wxIcon::wxIcon( char **bits, int WXUNUSED(width), int WXUNUSED(height) ) : - wxBitmap( bits ) -{ -} - -wxIcon::wxIcon() : wxBitmap() -{ -} - -void wxIcon::CopyFromBitmap(const wxBitmap& bmp) -{ - wxIcon *icon = (wxIcon*)(&bmp); - *this = *icon; -} +///////////////////////////////////////////////////////////////////////////// +// Name: src/generic/icon.cpp +// Purpose: wxIcon implementation for ports where it's same as wxBitmap +// Author: Julian Smart +// Modified by: +// Created: 17/09/98 +// RCS-ID: $Id: icon.cpp 40531 2006-08-09 17:59:30Z VS $ +// Copyright: (c) Julian Smart +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// for compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#include "wx/icon.h" + +//----------------------------------------------------------------------------- +// wxIcon +//----------------------------------------------------------------------------- + +IMPLEMENT_DYNAMIC_CLASS(wxIcon, wxBitmap) + +wxIcon::wxIcon( const char **bits, int WXUNUSED(width), int WXUNUSED(height) ) : + wxBitmap( bits ) +{ +} + +wxIcon::wxIcon( char **bits, int WXUNUSED(width), int WXUNUSED(height) ) : + wxBitmap( bits ) +{ +} + +wxIcon::wxIcon() : wxBitmap() +{ +} + +void wxIcon::CopyFromBitmap(const wxBitmap& bmp) +{ + wxIcon *icon = (wxIcon*)(&bmp); + *this = *icon; +} diff --git a/Externals/wxWidgets/src/generic/imaglist.cpp b/Externals/wxWidgets/src/generic/imaglist.cpp index 97a82e0a8e..72eb445d73 100644 --- a/Externals/wxWidgets/src/generic/imaglist.cpp +++ b/Externals/wxWidgets/src/generic/imaglist.cpp @@ -1,276 +1,276 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/generic/imaglist.cpp -// Purpose: -// Author: Robert Roebling -// Id: $id$ -// Copyright: (c) 1998 Robert Roebling -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_IMAGLIST && !defined(wxHAS_NATIVE_IMAGELIST) - -#ifndef __WXPALMOS__ - -#include "wx/imaglist.h" - -#ifndef WX_PRECOMP - #include "wx/dc.h" - #include "wx/icon.h" - #include "wx/image.h" -#endif - -//----------------------------------------------------------------------------- -// wxImageList -//----------------------------------------------------------------------------- - -IMPLEMENT_DYNAMIC_CLASS(wxGenericImageList, wxObject) -IMPLEMENT_DYNAMIC_CLASS(wxImageList, wxGenericImageList) - -wxGenericImageList::wxGenericImageList( int width, int height, bool mask, int initialCount ) -{ - (void)Create(width, height, mask, initialCount); -} - -wxGenericImageList::~wxGenericImageList() -{ - (void)RemoveAll(); -} - -int wxGenericImageList::GetImageCount() const -{ - return m_images.GetCount(); -} - -bool wxGenericImageList::Create( int width, int height, bool WXUNUSED(mask), int WXUNUSED(initialCount) ) -{ - m_width = width; - m_height = height; - - return Create(); -} - -bool wxGenericImageList::Create() -{ - return true; -} - -int wxGenericImageList::Add( const wxBitmap &bitmap ) -{ - wxASSERT_MSG( (bitmap.GetWidth() >= m_width && bitmap.GetHeight() == m_height) - || (m_width == 0 && m_height == 0), - _T("invalid bitmap size in wxImageList: this might work ") - _T("on this platform but definitely won't under Windows.") ); - - if (bitmap.IsKindOf(CLASSINFO(wxIcon))) - { - m_images.Append( new wxIcon( (const wxIcon&) bitmap ) ); - } - else - { - // Mimic behavior of Windows ImageList_Add that automatically breaks up the added - // bitmap into sub-images of the correct size - if (m_width > 0 && bitmap.GetWidth() > m_width && bitmap.GetHeight() >= m_height) - { - int numImages = bitmap.GetWidth() / m_width; - for (int subIndex = 0; subIndex < numImages; subIndex++) - { - wxRect rect(m_width * subIndex, 0, m_width, m_height); - wxBitmap tmpBmp = bitmap.GetSubBitmap(rect); - m_images.Append( new wxBitmap(tmpBmp) ); - } - } - else - { - m_images.Append( new wxBitmap(bitmap) ); - } - } - - if (m_width == 0 && m_height == 0) - { - m_width = bitmap.GetWidth(); - m_height = bitmap.GetHeight(); - } - - return m_images.GetCount()-1; -} - -int wxGenericImageList::Add( const wxBitmap& bitmap, const wxBitmap& mask ) -{ - wxBitmap bmp(bitmap); - if (mask.Ok()) - bmp.SetMask(new wxMask(mask)); - return Add(bmp); -} - -int wxGenericImageList::Add( const wxBitmap& bitmap, const wxColour& maskColour ) -{ - wxImage img = bitmap.ConvertToImage(); - img.SetMaskColour(maskColour.Red(), maskColour.Green(), maskColour.Blue()); - return Add(wxBitmap(img)); -} - -const wxBitmap *wxGenericImageList::GetBitmapPtr( int index ) const -{ - wxList::compatibility_iterator node = m_images.Item( index ); - - wxCHECK_MSG( node, (wxBitmap *) NULL, wxT("wrong index in image list") ); - - return (wxBitmap*)node->GetData(); -} - -// Get the bitmap -wxBitmap wxGenericImageList::GetBitmap(int index) const -{ - const wxBitmap* bmp = GetBitmapPtr(index); - if (bmp) - return *bmp; - else - return wxNullBitmap; -} - -// Get the icon -wxIcon wxGenericImageList::GetIcon(int index) const -{ - const wxBitmap* bmp = GetBitmapPtr(index); - if (bmp) - { - wxIcon icon; - icon.CopyFromBitmap(*bmp); - return icon; - } - else - return wxNullIcon; -} - -bool wxGenericImageList::Replace( int index, const wxBitmap &bitmap ) -{ - wxList::compatibility_iterator node = m_images.Item( index ); - - wxCHECK_MSG( node, false, wxT("wrong index in image list") ); - - wxBitmap* newBitmap = (bitmap.IsKindOf(CLASSINFO(wxIcon))) ? - #if defined(__VISAGECPP__) - //just can't do this in VisualAge now, with all this new Bitmap-Icon stuff - //so construct it from a bitmap object until I can figure this nonsense out. (DW) - new wxBitmap(bitmap) - #else - new wxBitmap( (const wxIcon&) bitmap ) - #endif - : new wxBitmap(bitmap) ; - - if (index == (int) m_images.GetCount() - 1) - { - delete node->GetData(); - m_images.Erase( node ); - m_images.Append( newBitmap ); - } - else - { - wxList::compatibility_iterator next = node->GetNext(); - delete node->GetData(); - m_images.Erase( node ); - m_images.Insert( next, newBitmap ); - } - - return true; -} - -bool wxGenericImageList::Replace( int index, const wxBitmap &bitmap, const wxBitmap &mask ) -{ - wxList::compatibility_iterator node = m_images.Item( index ); - - wxCHECK_MSG( node, false, wxT("wrong index in image list") ); - - wxBitmap* newBitmap = (bitmap.IsKindOf(CLASSINFO(wxIcon))) ? - #if defined(__VISAGECPP__) - //just can't do this in VisualAge now, with all this new Bitmap-Icon stuff - //so construct it from a bitmap object until I can figure this nonsense out. (DW) - new wxBitmap(bitmap) - #else - new wxBitmap( (const wxIcon&) bitmap ) - #endif - : new wxBitmap(bitmap) ; - - if (index == (int) m_images.GetCount() - 1) - { - delete node->GetData(); - m_images.Erase( node ); - m_images.Append( newBitmap ); - } - else - { - wxList::compatibility_iterator next = node->GetNext(); - delete node->GetData(); - m_images.Erase( node ); - m_images.Insert( next, newBitmap ); - } - - if (mask.Ok()) - newBitmap->SetMask(new wxMask(mask)); - - return true; -} - -bool wxGenericImageList::Remove( int index ) -{ - wxList::compatibility_iterator node = m_images.Item( index ); - - wxCHECK_MSG( node, false, wxT("wrong index in image list") ); - - delete node->GetData(); - m_images.Erase( node ); - - return true; -} - -bool wxGenericImageList::RemoveAll() -{ - WX_CLEAR_LIST(wxList, m_images); - m_images.Clear(); - - return true; -} - -bool wxGenericImageList::GetSize( int index, int &width, int &height ) const -{ - width = 0; - height = 0; - - wxList::compatibility_iterator node = m_images.Item( index ); - - wxCHECK_MSG( node, false, wxT("wrong index in image list") ); - - wxBitmap *bm = (wxBitmap*)node->GetData(); - width = bm->GetWidth(); - height = bm->GetHeight(); - - return true; -} - -bool wxGenericImageList::Draw( int index, wxDC &dc, int x, int y, - int flags, bool WXUNUSED(solidBackground) ) -{ - wxList::compatibility_iterator node = m_images.Item( index ); - - wxCHECK_MSG( node, false, wxT("wrong index in image list") ); - - wxBitmap *bm = (wxBitmap*)node->GetData(); - - if (bm->IsKindOf(CLASSINFO(wxIcon))) - dc.DrawIcon( * ((wxIcon*) bm), x, y); - else - dc.DrawBitmap( *bm, x, y, (flags & wxIMAGELIST_DRAW_TRANSPARENT) > 0 ); - - return true; -} - -#endif // __WXPALMOS__ - -#endif // wxUSE_IMAGLIST +///////////////////////////////////////////////////////////////////////////// +// Name: src/generic/imaglist.cpp +// Purpose: +// Author: Robert Roebling +// Id: $id$ +// Copyright: (c) 1998 Robert Roebling +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_IMAGLIST && !defined(wxHAS_NATIVE_IMAGELIST) + +#ifndef __WXPALMOS__ + +#include "wx/imaglist.h" + +#ifndef WX_PRECOMP + #include "wx/dc.h" + #include "wx/icon.h" + #include "wx/image.h" +#endif + +//----------------------------------------------------------------------------- +// wxImageList +//----------------------------------------------------------------------------- + +IMPLEMENT_DYNAMIC_CLASS(wxGenericImageList, wxObject) +IMPLEMENT_DYNAMIC_CLASS(wxImageList, wxGenericImageList) + +wxGenericImageList::wxGenericImageList( int width, int height, bool mask, int initialCount ) +{ + (void)Create(width, height, mask, initialCount); +} + +wxGenericImageList::~wxGenericImageList() +{ + (void)RemoveAll(); +} + +int wxGenericImageList::GetImageCount() const +{ + return m_images.GetCount(); +} + +bool wxGenericImageList::Create( int width, int height, bool WXUNUSED(mask), int WXUNUSED(initialCount) ) +{ + m_width = width; + m_height = height; + + return Create(); +} + +bool wxGenericImageList::Create() +{ + return true; +} + +int wxGenericImageList::Add( const wxBitmap &bitmap ) +{ + wxASSERT_MSG( (bitmap.GetWidth() >= m_width && bitmap.GetHeight() == m_height) + || (m_width == 0 && m_height == 0), + _T("invalid bitmap size in wxImageList: this might work ") + _T("on this platform but definitely won't under Windows.") ); + + if (bitmap.IsKindOf(CLASSINFO(wxIcon))) + { + m_images.Append( new wxIcon( (const wxIcon&) bitmap ) ); + } + else + { + // Mimic behavior of Windows ImageList_Add that automatically breaks up the added + // bitmap into sub-images of the correct size + if (m_width > 0 && bitmap.GetWidth() > m_width && bitmap.GetHeight() >= m_height) + { + int numImages = bitmap.GetWidth() / m_width; + for (int subIndex = 0; subIndex < numImages; subIndex++) + { + wxRect rect(m_width * subIndex, 0, m_width, m_height); + wxBitmap tmpBmp = bitmap.GetSubBitmap(rect); + m_images.Append( new wxBitmap(tmpBmp) ); + } + } + else + { + m_images.Append( new wxBitmap(bitmap) ); + } + } + + if (m_width == 0 && m_height == 0) + { + m_width = bitmap.GetWidth(); + m_height = bitmap.GetHeight(); + } + + return m_images.GetCount()-1; +} + +int wxGenericImageList::Add( const wxBitmap& bitmap, const wxBitmap& mask ) +{ + wxBitmap bmp(bitmap); + if (mask.Ok()) + bmp.SetMask(new wxMask(mask)); + return Add(bmp); +} + +int wxGenericImageList::Add( const wxBitmap& bitmap, const wxColour& maskColour ) +{ + wxImage img = bitmap.ConvertToImage(); + img.SetMaskColour(maskColour.Red(), maskColour.Green(), maskColour.Blue()); + return Add(wxBitmap(img)); +} + +const wxBitmap *wxGenericImageList::GetBitmapPtr( int index ) const +{ + wxList::compatibility_iterator node = m_images.Item( index ); + + wxCHECK_MSG( node, (wxBitmap *) NULL, wxT("wrong index in image list") ); + + return (wxBitmap*)node->GetData(); +} + +// Get the bitmap +wxBitmap wxGenericImageList::GetBitmap(int index) const +{ + const wxBitmap* bmp = GetBitmapPtr(index); + if (bmp) + return *bmp; + else + return wxNullBitmap; +} + +// Get the icon +wxIcon wxGenericImageList::GetIcon(int index) const +{ + const wxBitmap* bmp = GetBitmapPtr(index); + if (bmp) + { + wxIcon icon; + icon.CopyFromBitmap(*bmp); + return icon; + } + else + return wxNullIcon; +} + +bool wxGenericImageList::Replace( int index, const wxBitmap &bitmap ) +{ + wxList::compatibility_iterator node = m_images.Item( index ); + + wxCHECK_MSG( node, false, wxT("wrong index in image list") ); + + wxBitmap* newBitmap = (bitmap.IsKindOf(CLASSINFO(wxIcon))) ? + #if defined(__VISAGECPP__) + //just can't do this in VisualAge now, with all this new Bitmap-Icon stuff + //so construct it from a bitmap object until I can figure this nonsense out. (DW) + new wxBitmap(bitmap) + #else + new wxBitmap( (const wxIcon&) bitmap ) + #endif + : new wxBitmap(bitmap) ; + + if (index == (int) m_images.GetCount() - 1) + { + delete node->GetData(); + m_images.Erase( node ); + m_images.Append( newBitmap ); + } + else + { + wxList::compatibility_iterator next = node->GetNext(); + delete node->GetData(); + m_images.Erase( node ); + m_images.Insert( next, newBitmap ); + } + + return true; +} + +bool wxGenericImageList::Replace( int index, const wxBitmap &bitmap, const wxBitmap &mask ) +{ + wxList::compatibility_iterator node = m_images.Item( index ); + + wxCHECK_MSG( node, false, wxT("wrong index in image list") ); + + wxBitmap* newBitmap = (bitmap.IsKindOf(CLASSINFO(wxIcon))) ? + #if defined(__VISAGECPP__) + //just can't do this in VisualAge now, with all this new Bitmap-Icon stuff + //so construct it from a bitmap object until I can figure this nonsense out. (DW) + new wxBitmap(bitmap) + #else + new wxBitmap( (const wxIcon&) bitmap ) + #endif + : new wxBitmap(bitmap) ; + + if (index == (int) m_images.GetCount() - 1) + { + delete node->GetData(); + m_images.Erase( node ); + m_images.Append( newBitmap ); + } + else + { + wxList::compatibility_iterator next = node->GetNext(); + delete node->GetData(); + m_images.Erase( node ); + m_images.Insert( next, newBitmap ); + } + + if (mask.Ok()) + newBitmap->SetMask(new wxMask(mask)); + + return true; +} + +bool wxGenericImageList::Remove( int index ) +{ + wxList::compatibility_iterator node = m_images.Item( index ); + + wxCHECK_MSG( node, false, wxT("wrong index in image list") ); + + delete node->GetData(); + m_images.Erase( node ); + + return true; +} + +bool wxGenericImageList::RemoveAll() +{ + WX_CLEAR_LIST(wxList, m_images); + m_images.Clear(); + + return true; +} + +bool wxGenericImageList::GetSize( int index, int &width, int &height ) const +{ + width = 0; + height = 0; + + wxList::compatibility_iterator node = m_images.Item( index ); + + wxCHECK_MSG( node, false, wxT("wrong index in image list") ); + + wxBitmap *bm = (wxBitmap*)node->GetData(); + width = bm->GetWidth(); + height = bm->GetHeight(); + + return true; +} + +bool wxGenericImageList::Draw( int index, wxDC &dc, int x, int y, + int flags, bool WXUNUSED(solidBackground) ) +{ + wxList::compatibility_iterator node = m_images.Item( index ); + + wxCHECK_MSG( node, false, wxT("wrong index in image list") ); + + wxBitmap *bm = (wxBitmap*)node->GetData(); + + if (bm->IsKindOf(CLASSINFO(wxIcon))) + dc.DrawIcon( * ((wxIcon*) bm), x, y); + else + dc.DrawBitmap( *bm, x, y, (flags & wxIMAGELIST_DRAW_TRANSPARENT) > 0 ); + + return true; +} + +#endif // __WXPALMOS__ + +#endif // wxUSE_IMAGLIST diff --git a/Externals/wxWidgets/src/generic/laywin.cpp b/Externals/wxWidgets/src/generic/laywin.cpp index e7e501b5d0..bebc89d469 100644 --- a/Externals/wxWidgets/src/generic/laywin.cpp +++ b/Externals/wxWidgets/src/generic/laywin.cpp @@ -1,341 +1,341 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: laywin.cpp -// Purpose: Implements a simple layout algorithm, plus -// wxSashLayoutWindow which is an example of a window with -// layout-awareness (via event handlers). This is suited to -// IDE-style window layout. -// Author: Julian Smart -// Modified by: -// Created: 04/01/98 -// RCS-ID: $Id: laywin.cpp 35688 2005-09-25 19:59:19Z VZ $ -// Copyright: (c) Julian Smart -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx/wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ -#pragma hdrstop -#endif - -#ifndef WX_PRECOMP - #include "wx/frame.h" - #include "wx/mdi.h" -#endif - -#include "wx/laywin.h" - -IMPLEMENT_DYNAMIC_CLASS(wxQueryLayoutInfoEvent, wxEvent) -IMPLEMENT_DYNAMIC_CLASS(wxCalculateLayoutEvent, wxEvent) - -DEFINE_EVENT_TYPE(wxEVT_QUERY_LAYOUT_INFO) -DEFINE_EVENT_TYPE(wxEVT_CALCULATE_LAYOUT) - -#if wxUSE_SASH -IMPLEMENT_CLASS(wxSashLayoutWindow, wxSashWindow) - -BEGIN_EVENT_TABLE(wxSashLayoutWindow, wxSashWindow) - EVT_CALCULATE_LAYOUT(wxSashLayoutWindow::OnCalculateLayout) - EVT_QUERY_LAYOUT_INFO(wxSashLayoutWindow::OnQueryLayoutInfo) -END_EVENT_TABLE() - -bool wxSashLayoutWindow::Create(wxWindow *parent, wxWindowID id, const wxPoint& pos, - const wxSize& size, long style, const wxString& name) -{ - return wxSashWindow::Create(parent, id, pos, size, style, name); -} - -void wxSashLayoutWindow::Init() -{ - m_orientation = wxLAYOUT_HORIZONTAL; - m_alignment = wxLAYOUT_TOP; -#ifdef __WXMAC__ - MacSetClipChildren( true ) ; -#endif -} - -// This is the function that wxLayoutAlgorithm calls to ascertain the window -// dimensions. -void wxSashLayoutWindow::OnQueryLayoutInfo(wxQueryLayoutInfoEvent& event) -{ - // int flags = event.GetFlags(); - int requestedLength = event.GetRequestedLength(); - - event.SetOrientation(m_orientation); - event.SetAlignment(m_alignment); - - if (m_orientation == wxLAYOUT_HORIZONTAL) - event.SetSize(wxSize(requestedLength, m_defaultSize.y)); - else - event.SetSize(wxSize(m_defaultSize.x, requestedLength)); -} - -// Called by parent to allow window to take a bit out of the -// client rectangle, and size itself if not in wxLAYOUT_QUERY mode. - -void wxSashLayoutWindow::OnCalculateLayout(wxCalculateLayoutEvent& event) -{ - wxRect clientSize(event.GetRect()); - - int flags = event.GetFlags(); - - if (!IsShown()) - return; - - // Let's assume that all windows stretch the full extent of the window in - // the direction of that window orientation. This will work for non-docking toolbars, - // and the status bar. Note that the windows have to have been created in a certain - // order to work, else you might get a left-aligned window going to the bottom - // of the window, and the status bar appearing to the right of it. The - // status bar would have to be created after or before the toolbar(s). - - wxRect thisRect; - - // Try to stretch - int length = (GetOrientation() == wxLAYOUT_HORIZONTAL) ? clientSize.width : clientSize.height; - wxLayoutOrientation orient = GetOrientation(); - - // We assume that a window that says it's horizontal, wants to be stretched in that - // direction. Is this distinction too fine? Do we assume that any horizontal - // window needs to be stretched in that direction? Possibly. - int whichDimension = (GetOrientation() == wxLAYOUT_HORIZONTAL) ? wxLAYOUT_LENGTH_X : wxLAYOUT_LENGTH_Y; - - wxQueryLayoutInfoEvent infoEvent(GetId()); - infoEvent.SetEventObject(this); - infoEvent.SetRequestedLength(length); - infoEvent.SetFlags(orient | whichDimension); - - if (!GetEventHandler()->ProcessEvent(infoEvent)) - return; - - wxSize sz = infoEvent.GetSize(); - - if (sz.x == 0 && sz.y == 0) // Assume it's invisible - return; - - // Now we know the size it wants to be. We wish to decide where to place it, i.e. - // how it's aligned. - switch (GetAlignment()) - { - case wxLAYOUT_TOP: - { - thisRect.x = clientSize.x; thisRect.y = clientSize.y; - thisRect.width = sz.x; thisRect.height = sz.y; - clientSize.y += thisRect.height; - clientSize.height -= thisRect.height; - break; - } - case wxLAYOUT_LEFT: - { - thisRect.x = clientSize.x; thisRect.y = clientSize.y; - thisRect.width = sz.x; thisRect.height = sz.y; - clientSize.x += thisRect.width; - clientSize.width -= thisRect.width; - break; - } - case wxLAYOUT_RIGHT: - { - thisRect.x = clientSize.x + (clientSize.width - sz.x); thisRect.y = clientSize.y; - thisRect.width = sz.x; thisRect.height = sz.y; - clientSize.width -= thisRect.width; - break; - } - case wxLAYOUT_BOTTOM: - { - thisRect.x = clientSize.x; thisRect.y = clientSize.y + (clientSize.height - sz.y); - thisRect.width = sz.x; thisRect.height = sz.y; - clientSize.height -= thisRect.height; - break; - } - case wxLAYOUT_NONE: - { - break; - } - - } - - if ((flags & wxLAYOUT_QUERY) == 0) - { - // If not in query mode, resize the window. - // TODO: add wxRect& form to wxWindow::SetSize - wxSize sz2 = GetSize(); - wxPoint pos = GetPosition(); - SetSize(thisRect.x, thisRect.y, thisRect.width, thisRect.height); - - // Make sure the sash is erased when the window is resized - if ((pos.x != thisRect.x || pos.y != thisRect.y || sz2.x != thisRect.width || sz2.y != thisRect.height) && - (GetSashVisible(wxSASH_TOP) || GetSashVisible(wxSASH_RIGHT) || GetSashVisible(wxSASH_BOTTOM) || GetSashVisible(wxSASH_LEFT))) - Refresh(true); - - } - - event.SetRect(clientSize); -} -#endif // wxUSE_SASH - -/* - * wxLayoutAlgorithm - */ - -#if wxUSE_MDI_ARCHITECTURE - -// Lays out windows for an MDI frame. The MDI client area gets what's left -// over. -bool wxLayoutAlgorithm::LayoutMDIFrame(wxMDIParentFrame* frame, wxRect* r) -{ - int cw, ch; - frame->GetClientSize(& cw, & ch); - - wxRect rect(0, 0, cw, ch); - if (r) - rect = * r; - - wxCalculateLayoutEvent event; - event.SetRect(rect); - - wxWindowList::compatibility_iterator node = frame->GetChildren().GetFirst(); - while (node) - { - wxWindow* win = node->GetData(); - - event.SetId(win->GetId()); - event.SetEventObject(win); - event.SetFlags(0); // ?? - - win->GetEventHandler()->ProcessEvent(event); - - node = node->GetNext(); - } - - wxWindow* clientWindow = frame->GetClientWindow(); - - rect = event.GetRect(); - - clientWindow->SetSize(rect.x, rect.y, rect.width, rect.height); - - return true; -} - -#endif // wxUSE_MDI_ARCHITECTURE - -bool wxLayoutAlgorithm::LayoutFrame(wxFrame* frame, wxWindow* mainWindow) -{ - return LayoutWindow(frame, mainWindow); -} - -// Layout algorithm for any window. mainWindow gets what's left over. -bool wxLayoutAlgorithm::LayoutWindow(wxWindow* parent, wxWindow* mainWindow) -{ - // Test if the parent is a sash window, and if so, - // reduce the available space to allow space for any active edges. - - int leftMargin = 0, rightMargin = 0, topMargin = 0, bottomMargin = 0; -#if wxUSE_SASH - if (parent->IsKindOf(CLASSINFO(wxSashWindow))) - { - wxSashWindow* sashWindow = (wxSashWindow*) parent; - - leftMargin = sashWindow->GetExtraBorderSize(); - rightMargin = sashWindow->GetExtraBorderSize(); - topMargin = sashWindow->GetExtraBorderSize(); - bottomMargin = sashWindow->GetExtraBorderSize(); - - if (sashWindow->GetSashVisible(wxSASH_LEFT)) - leftMargin += sashWindow->GetDefaultBorderSize(); - if (sashWindow->GetSashVisible(wxSASH_RIGHT)) - rightMargin += sashWindow->GetDefaultBorderSize(); - if (sashWindow->GetSashVisible(wxSASH_TOP)) - topMargin += sashWindow->GetDefaultBorderSize(); - if (sashWindow->GetSashVisible(wxSASH_BOTTOM)) - bottomMargin += sashWindow->GetDefaultBorderSize(); - } -#endif // wxUSE_SASH - - int cw, ch; - parent->GetClientSize(& cw, & ch); - - wxRect rect(leftMargin, topMargin, cw - leftMargin - rightMargin, ch - topMargin - bottomMargin); - - wxCalculateLayoutEvent event; - event.SetRect(rect); - - // Find the last layout-aware window, so we can make it fill all remaining - // space. - wxWindow *lastAwareWindow = NULL; - wxWindowList::compatibility_iterator node = parent->GetChildren().GetFirst(); - - while (node) - { - wxWindow* win = node->GetData(); - - if (win->IsShown()) - { - wxCalculateLayoutEvent tempEvent(win->GetId()); - tempEvent.SetEventObject(win); - tempEvent.SetFlags(wxLAYOUT_QUERY); - tempEvent.SetRect(event.GetRect()); - if (win->GetEventHandler()->ProcessEvent(tempEvent)) - lastAwareWindow = win; - } - - node = node->GetNext(); - } - - // Now do a dummy run to see if we have any space left for the final window (fail if not) - node = parent->GetChildren().GetFirst(); - while (node) - { - wxWindow* win = node->GetData(); - - // If mainWindow is NULL and we're at the last window, - // skip this, because we'll simply make it fit the remaining space. - if (win->IsShown() && (win != mainWindow) && (mainWindow != NULL || win != lastAwareWindow)) - { - event.SetId(win->GetId()); - event.SetEventObject(win); - event.SetFlags(wxLAYOUT_QUERY); - - win->GetEventHandler()->ProcessEvent(event); - } - - node = node->GetNext(); - } - - if (event.GetRect().GetWidth() < 0 || event.GetRect().GetHeight() < 0) - return false; - - event.SetRect(rect); - - node = parent->GetChildren().GetFirst(); - while (node) - { - wxWindow* win = node->GetData(); - - // If mainWindow is NULL and we're at the last window, - // skip this, because we'll simply make it fit the remaining space. - if (win->IsShown() && (win != mainWindow) && (mainWindow != NULL || win != lastAwareWindow)) - { - event.SetId(win->GetId()); - event.SetEventObject(win); - event.SetFlags(0); // ?? - - win->GetEventHandler()->ProcessEvent(event); - } - - node = node->GetNext(); - } - - rect = event.GetRect(); - - if (mainWindow) - mainWindow->SetSize(rect.x, rect.y, wxMax(0, rect.width), wxMax(0, rect.height)); - else if (lastAwareWindow) - { - // Fit the remaining space - lastAwareWindow->SetSize(rect.x, rect.y, wxMax(0, rect.width), wxMax(0, rect.height)); - } - - return true; -} - +///////////////////////////////////////////////////////////////////////////// +// Name: laywin.cpp +// Purpose: Implements a simple layout algorithm, plus +// wxSashLayoutWindow which is an example of a window with +// layout-awareness (via event handlers). This is suited to +// IDE-style window layout. +// Author: Julian Smart +// Modified by: +// Created: 04/01/98 +// RCS-ID: $Id: laywin.cpp 35688 2005-09-25 19:59:19Z VZ $ +// Copyright: (c) Julian Smart +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx/wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ +#pragma hdrstop +#endif + +#ifndef WX_PRECOMP + #include "wx/frame.h" + #include "wx/mdi.h" +#endif + +#include "wx/laywin.h" + +IMPLEMENT_DYNAMIC_CLASS(wxQueryLayoutInfoEvent, wxEvent) +IMPLEMENT_DYNAMIC_CLASS(wxCalculateLayoutEvent, wxEvent) + +DEFINE_EVENT_TYPE(wxEVT_QUERY_LAYOUT_INFO) +DEFINE_EVENT_TYPE(wxEVT_CALCULATE_LAYOUT) + +#if wxUSE_SASH +IMPLEMENT_CLASS(wxSashLayoutWindow, wxSashWindow) + +BEGIN_EVENT_TABLE(wxSashLayoutWindow, wxSashWindow) + EVT_CALCULATE_LAYOUT(wxSashLayoutWindow::OnCalculateLayout) + EVT_QUERY_LAYOUT_INFO(wxSashLayoutWindow::OnQueryLayoutInfo) +END_EVENT_TABLE() + +bool wxSashLayoutWindow::Create(wxWindow *parent, wxWindowID id, const wxPoint& pos, + const wxSize& size, long style, const wxString& name) +{ + return wxSashWindow::Create(parent, id, pos, size, style, name); +} + +void wxSashLayoutWindow::Init() +{ + m_orientation = wxLAYOUT_HORIZONTAL; + m_alignment = wxLAYOUT_TOP; +#ifdef __WXMAC__ + MacSetClipChildren( true ) ; +#endif +} + +// This is the function that wxLayoutAlgorithm calls to ascertain the window +// dimensions. +void wxSashLayoutWindow::OnQueryLayoutInfo(wxQueryLayoutInfoEvent& event) +{ + // int flags = event.GetFlags(); + int requestedLength = event.GetRequestedLength(); + + event.SetOrientation(m_orientation); + event.SetAlignment(m_alignment); + + if (m_orientation == wxLAYOUT_HORIZONTAL) + event.SetSize(wxSize(requestedLength, m_defaultSize.y)); + else + event.SetSize(wxSize(m_defaultSize.x, requestedLength)); +} + +// Called by parent to allow window to take a bit out of the +// client rectangle, and size itself if not in wxLAYOUT_QUERY mode. + +void wxSashLayoutWindow::OnCalculateLayout(wxCalculateLayoutEvent& event) +{ + wxRect clientSize(event.GetRect()); + + int flags = event.GetFlags(); + + if (!IsShown()) + return; + + // Let's assume that all windows stretch the full extent of the window in + // the direction of that window orientation. This will work for non-docking toolbars, + // and the status bar. Note that the windows have to have been created in a certain + // order to work, else you might get a left-aligned window going to the bottom + // of the window, and the status bar appearing to the right of it. The + // status bar would have to be created after or before the toolbar(s). + + wxRect thisRect; + + // Try to stretch + int length = (GetOrientation() == wxLAYOUT_HORIZONTAL) ? clientSize.width : clientSize.height; + wxLayoutOrientation orient = GetOrientation(); + + // We assume that a window that says it's horizontal, wants to be stretched in that + // direction. Is this distinction too fine? Do we assume that any horizontal + // window needs to be stretched in that direction? Possibly. + int whichDimension = (GetOrientation() == wxLAYOUT_HORIZONTAL) ? wxLAYOUT_LENGTH_X : wxLAYOUT_LENGTH_Y; + + wxQueryLayoutInfoEvent infoEvent(GetId()); + infoEvent.SetEventObject(this); + infoEvent.SetRequestedLength(length); + infoEvent.SetFlags(orient | whichDimension); + + if (!GetEventHandler()->ProcessEvent(infoEvent)) + return; + + wxSize sz = infoEvent.GetSize(); + + if (sz.x == 0 && sz.y == 0) // Assume it's invisible + return; + + // Now we know the size it wants to be. We wish to decide where to place it, i.e. + // how it's aligned. + switch (GetAlignment()) + { + case wxLAYOUT_TOP: + { + thisRect.x = clientSize.x; thisRect.y = clientSize.y; + thisRect.width = sz.x; thisRect.height = sz.y; + clientSize.y += thisRect.height; + clientSize.height -= thisRect.height; + break; + } + case wxLAYOUT_LEFT: + { + thisRect.x = clientSize.x; thisRect.y = clientSize.y; + thisRect.width = sz.x; thisRect.height = sz.y; + clientSize.x += thisRect.width; + clientSize.width -= thisRect.width; + break; + } + case wxLAYOUT_RIGHT: + { + thisRect.x = clientSize.x + (clientSize.width - sz.x); thisRect.y = clientSize.y; + thisRect.width = sz.x; thisRect.height = sz.y; + clientSize.width -= thisRect.width; + break; + } + case wxLAYOUT_BOTTOM: + { + thisRect.x = clientSize.x; thisRect.y = clientSize.y + (clientSize.height - sz.y); + thisRect.width = sz.x; thisRect.height = sz.y; + clientSize.height -= thisRect.height; + break; + } + case wxLAYOUT_NONE: + { + break; + } + + } + + if ((flags & wxLAYOUT_QUERY) == 0) + { + // If not in query mode, resize the window. + // TODO: add wxRect& form to wxWindow::SetSize + wxSize sz2 = GetSize(); + wxPoint pos = GetPosition(); + SetSize(thisRect.x, thisRect.y, thisRect.width, thisRect.height); + + // Make sure the sash is erased when the window is resized + if ((pos.x != thisRect.x || pos.y != thisRect.y || sz2.x != thisRect.width || sz2.y != thisRect.height) && + (GetSashVisible(wxSASH_TOP) || GetSashVisible(wxSASH_RIGHT) || GetSashVisible(wxSASH_BOTTOM) || GetSashVisible(wxSASH_LEFT))) + Refresh(true); + + } + + event.SetRect(clientSize); +} +#endif // wxUSE_SASH + +/* + * wxLayoutAlgorithm + */ + +#if wxUSE_MDI_ARCHITECTURE + +// Lays out windows for an MDI frame. The MDI client area gets what's left +// over. +bool wxLayoutAlgorithm::LayoutMDIFrame(wxMDIParentFrame* frame, wxRect* r) +{ + int cw, ch; + frame->GetClientSize(& cw, & ch); + + wxRect rect(0, 0, cw, ch); + if (r) + rect = * r; + + wxCalculateLayoutEvent event; + event.SetRect(rect); + + wxWindowList::compatibility_iterator node = frame->GetChildren().GetFirst(); + while (node) + { + wxWindow* win = node->GetData(); + + event.SetId(win->GetId()); + event.SetEventObject(win); + event.SetFlags(0); // ?? + + win->GetEventHandler()->ProcessEvent(event); + + node = node->GetNext(); + } + + wxWindow* clientWindow = frame->GetClientWindow(); + + rect = event.GetRect(); + + clientWindow->SetSize(rect.x, rect.y, rect.width, rect.height); + + return true; +} + +#endif // wxUSE_MDI_ARCHITECTURE + +bool wxLayoutAlgorithm::LayoutFrame(wxFrame* frame, wxWindow* mainWindow) +{ + return LayoutWindow(frame, mainWindow); +} + +// Layout algorithm for any window. mainWindow gets what's left over. +bool wxLayoutAlgorithm::LayoutWindow(wxWindow* parent, wxWindow* mainWindow) +{ + // Test if the parent is a sash window, and if so, + // reduce the available space to allow space for any active edges. + + int leftMargin = 0, rightMargin = 0, topMargin = 0, bottomMargin = 0; +#if wxUSE_SASH + if (parent->IsKindOf(CLASSINFO(wxSashWindow))) + { + wxSashWindow* sashWindow = (wxSashWindow*) parent; + + leftMargin = sashWindow->GetExtraBorderSize(); + rightMargin = sashWindow->GetExtraBorderSize(); + topMargin = sashWindow->GetExtraBorderSize(); + bottomMargin = sashWindow->GetExtraBorderSize(); + + if (sashWindow->GetSashVisible(wxSASH_LEFT)) + leftMargin += sashWindow->GetDefaultBorderSize(); + if (sashWindow->GetSashVisible(wxSASH_RIGHT)) + rightMargin += sashWindow->GetDefaultBorderSize(); + if (sashWindow->GetSashVisible(wxSASH_TOP)) + topMargin += sashWindow->GetDefaultBorderSize(); + if (sashWindow->GetSashVisible(wxSASH_BOTTOM)) + bottomMargin += sashWindow->GetDefaultBorderSize(); + } +#endif // wxUSE_SASH + + int cw, ch; + parent->GetClientSize(& cw, & ch); + + wxRect rect(leftMargin, topMargin, cw - leftMargin - rightMargin, ch - topMargin - bottomMargin); + + wxCalculateLayoutEvent event; + event.SetRect(rect); + + // Find the last layout-aware window, so we can make it fill all remaining + // space. + wxWindow *lastAwareWindow = NULL; + wxWindowList::compatibility_iterator node = parent->GetChildren().GetFirst(); + + while (node) + { + wxWindow* win = node->GetData(); + + if (win->IsShown()) + { + wxCalculateLayoutEvent tempEvent(win->GetId()); + tempEvent.SetEventObject(win); + tempEvent.SetFlags(wxLAYOUT_QUERY); + tempEvent.SetRect(event.GetRect()); + if (win->GetEventHandler()->ProcessEvent(tempEvent)) + lastAwareWindow = win; + } + + node = node->GetNext(); + } + + // Now do a dummy run to see if we have any space left for the final window (fail if not) + node = parent->GetChildren().GetFirst(); + while (node) + { + wxWindow* win = node->GetData(); + + // If mainWindow is NULL and we're at the last window, + // skip this, because we'll simply make it fit the remaining space. + if (win->IsShown() && (win != mainWindow) && (mainWindow != NULL || win != lastAwareWindow)) + { + event.SetId(win->GetId()); + event.SetEventObject(win); + event.SetFlags(wxLAYOUT_QUERY); + + win->GetEventHandler()->ProcessEvent(event); + } + + node = node->GetNext(); + } + + if (event.GetRect().GetWidth() < 0 || event.GetRect().GetHeight() < 0) + return false; + + event.SetRect(rect); + + node = parent->GetChildren().GetFirst(); + while (node) + { + wxWindow* win = node->GetData(); + + // If mainWindow is NULL and we're at the last window, + // skip this, because we'll simply make it fit the remaining space. + if (win->IsShown() && (win != mainWindow) && (mainWindow != NULL || win != lastAwareWindow)) + { + event.SetId(win->GetId()); + event.SetEventObject(win); + event.SetFlags(0); // ?? + + win->GetEventHandler()->ProcessEvent(event); + } + + node = node->GetNext(); + } + + rect = event.GetRect(); + + if (mainWindow) + mainWindow->SetSize(rect.x, rect.y, wxMax(0, rect.width), wxMax(0, rect.height)); + else if (lastAwareWindow) + { + // Fit the remaining space + lastAwareWindow->SetSize(rect.x, rect.y, wxMax(0, rect.width), wxMax(0, rect.height)); + } + + return true; +} + diff --git a/Externals/wxWidgets/src/generic/listbkg.cpp b/Externals/wxWidgets/src/generic/listbkg.cpp index 50a6ea40e9..ef95d2652b 100644 --- a/Externals/wxWidgets/src/generic/listbkg.cpp +++ b/Externals/wxWidgets/src/generic/listbkg.cpp @@ -1,416 +1,416 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: src/generic/listbkg.cpp -// Purpose: generic implementation of wxListbook -// Author: Vadim Zeitlin -// Modified by: -// Created: 19.08.03 -// RCS-ID: $Id: listbkg.cpp 48783 2007-09-19 11:24:38Z RR $ -// Copyright: (c) 2003 Vadim Zeitlin -// Licence: wxWindows licence -/////////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_LISTBOOK - -#include "wx/listbook.h" - -#ifndef WX_PRECOMP - #include "wx/settings.h" -#endif - -#include "wx/listctrl.h" -#include "wx/statline.h" -#include "wx/imaglist.h" - -// ---------------------------------------------------------------------------- -// various wxWidgets macros -// ---------------------------------------------------------------------------- - -// check that the page index is valid -#define IS_VALID_PAGE(nPage) ((nPage) < GetPageCount()) - -// ---------------------------------------------------------------------------- -// event table -// ---------------------------------------------------------------------------- - -IMPLEMENT_DYNAMIC_CLASS(wxListbook, wxBookCtrlBase) -IMPLEMENT_DYNAMIC_CLASS(wxListbookEvent, wxNotifyEvent) - -#if !WXWIN_COMPATIBILITY_EVENT_TYPES -const wxEventType wxEVT_COMMAND_LISTBOOK_PAGE_CHANGING = wxNewEventType(); -const wxEventType wxEVT_COMMAND_LISTBOOK_PAGE_CHANGED = wxNewEventType(); -#endif - -BEGIN_EVENT_TABLE(wxListbook, wxBookCtrlBase) - EVT_SIZE(wxListbook::OnSize) - EVT_LIST_ITEM_SELECTED(wxID_ANY, wxListbook::OnListSelected) -END_EVENT_TABLE() - -// ============================================================================ -// wxListbook implementation -// ============================================================================ - -// ---------------------------------------------------------------------------- -// wxListbook creation -// ---------------------------------------------------------------------------- - -void wxListbook::Init() -{ - m_selection = wxNOT_FOUND; -} - -bool -wxListbook::Create(wxWindow *parent, - wxWindowID id, - const wxPoint& pos, - const wxSize& size, - long style, - const wxString& name) -{ - if ( (style & wxBK_ALIGN_MASK) == wxBK_DEFAULT ) - { -#ifdef __WXMAC__ - style |= wxBK_TOP; -#else // !__WXMAC__ - style |= wxBK_LEFT; -#endif // __WXMAC__/!__WXMAC__ - } - - // no border for this control, it doesn't look nice together with - // wxListCtrl border - style &= ~wxBORDER_MASK; - style |= wxBORDER_NONE; - - if ( !wxControl::Create(parent, id, pos, size, style, - wxDefaultValidator, name) ) - return false; - - m_bookctrl = new wxListView - ( - this, - wxID_ANY, - wxDefaultPosition, - wxDefaultSize, - wxLC_ICON | wxLC_SINGLE_SEL | - (IsVertical() ? wxLC_ALIGN_LEFT : wxLC_ALIGN_TOP) - ); - -#ifdef __WXMSW__ - // On XP with themes enabled the GetViewRect used in GetControllerSize() to - // determine the space needed for the list view will incorrectly return - // (0,0,0,0) the first time. So send a pending event so OnSize will be - // called again after the window is ready to go. Technically we don't - // need to do this on non-XP windows, but if things are already sized - // correctly then nothing changes and so there is no harm. - wxSizeEvent evt; - GetEventHandler()->AddPendingEvent(evt); -#endif - return true; -} - -// ---------------------------------------------------------------------------- -// wxListbook geometry management -// ---------------------------------------------------------------------------- - -wxSize wxListbook::GetControllerSize() const -{ - const wxSize sizeClient = GetClientSize(), - sizeBorder = m_bookctrl->GetSize() - m_bookctrl->GetClientSize(), - sizeList = GetListView()->GetViewRect().GetSize() + sizeBorder; - - wxSize size; - - if ( IsVertical() ) - { - size.x = sizeClient.x; - size.y = sizeList.y; - } - else // left/right aligned - { - size.x = sizeList.x; - size.y = sizeClient.y; - } - - return size; -} - -void wxListbook::OnSize(wxSizeEvent& event) -{ - // arrange the icons before calling SetClientSize(), otherwise it wouldn't - // account for the scrollbars the list control might need and, at least - // under MSW, we'd finish with an ugly looking list control with both - // vertical and horizontal scrollbar (with one of them being added because - // the other one is not accounted for in client size computations) - wxListView *list = GetListView(); - if (list) list->Arrange(); - wxBookCtrlBase::OnSize(event); -} - -int wxListbook::HitTest(const wxPoint& pt, long *flags) const -{ - int pagePos = wxNOT_FOUND; - - if ( flags ) - *flags = wxBK_HITTEST_NOWHERE; - - // convert from listbook control coordinates to list control coordinates - const wxListView * const list = GetListView(); - const wxPoint listPt = list->ScreenToClient(ClientToScreen(pt)); - - // is the point inside list control? - if ( wxRect(list->GetSize()).Contains(listPt) ) - { - int flagsList; - pagePos = list->HitTest(listPt, flagsList); - - if ( flags ) - { - if ( pagePos != wxNOT_FOUND ) - *flags = 0; - - if ( flagsList & (wxLIST_HITTEST_ONITEMICON | - wxLIST_HITTEST_ONITEMSTATEICON ) ) - *flags |= wxBK_HITTEST_ONICON; - - if ( flagsList & wxLIST_HITTEST_ONITEMLABEL ) - *flags |= wxBK_HITTEST_ONLABEL; - } - } - else // not over list control at all - { - if ( flags && GetPageRect().Contains(pt) ) - *flags |= wxBK_HITTEST_ONPAGE; - } - - return pagePos; -} - -wxSize wxListbook::CalcSizeFromPage(const wxSize& sizePage) const -{ - // we need to add the size of the list control and the border between - const wxSize sizeList = GetControllerSize(); - - wxSize size = sizePage; - if ( IsVertical() ) - { - size.y += sizeList.y + GetInternalBorder(); - } - else // left/right aligned - { - size.x += sizeList.x + GetInternalBorder(); - } - - return size; -} - - -// ---------------------------------------------------------------------------- -// accessing the pages -// ---------------------------------------------------------------------------- - -bool wxListbook::SetPageText(size_t n, const wxString& strText) -{ - GetListView()->SetItemText(n, strText); - - return true; -} - -wxString wxListbook::GetPageText(size_t n) const -{ - return GetListView()->GetItemText(n); -} - -int wxListbook::GetPageImage(size_t WXUNUSED(n)) const -{ - wxFAIL_MSG( _T("wxListbook::GetPageImage() not implemented") ); - - return wxNOT_FOUND; -} - -bool wxListbook::SetPageImage(size_t n, int imageId) -{ - return GetListView()->SetItemImage(n, imageId); -} - -// ---------------------------------------------------------------------------- -// image list stuff -// ---------------------------------------------------------------------------- - -void wxListbook::SetImageList(wxImageList *imageList) -{ - GetListView()->SetImageList(imageList, wxIMAGE_LIST_NORMAL); - - wxBookCtrlBase::SetImageList(imageList); -} - -// ---------------------------------------------------------------------------- -// selection -// ---------------------------------------------------------------------------- - -void wxListbook::UpdateSelectedPage(size_t newsel) -{ - m_selection = newsel; - GetListView()->Select(newsel); - GetListView()->Focus(newsel); -} - -int wxListbook::GetSelection() const -{ - return m_selection; -} - -wxBookCtrlBaseEvent* wxListbook::CreatePageChangingEvent() const -{ - return new wxListbookEvent(wxEVT_COMMAND_LISTBOOK_PAGE_CHANGING, m_windowId); -} - -void wxListbook::MakeChangedEvent(wxBookCtrlBaseEvent &event) -{ - event.SetEventType(wxEVT_COMMAND_LISTBOOK_PAGE_CHANGED); -} - - -// ---------------------------------------------------------------------------- -// adding/removing the pages -// ---------------------------------------------------------------------------- - -bool -wxListbook::InsertPage(size_t n, - wxWindow *page, - const wxString& text, - bool bSelect, - int imageId) -{ - if ( !wxBookCtrlBase::InsertPage(n, page, text, bSelect, imageId) ) - return false; - - GetListView()->InsertItem(n, text, imageId); - - // if the inserted page is before the selected one, we must update the - // index of the selected page - if ( int(n) <= m_selection ) - { - // one extra page added - m_selection++; - GetListView()->Select(m_selection); - GetListView()->Focus(m_selection); - } - - // some page should be selected: either this one or the first one if there - // is still no selection - int selNew = -1; - if ( bSelect ) - selNew = n; - else if ( m_selection == -1 ) - selNew = 0; - - if ( selNew != m_selection ) - page->Hide(); - - if ( selNew != -1 ) - SetSelection(selNew); - - wxSizeEvent sz(GetSize(), GetId()); - GetEventHandler()->ProcessEvent(sz); - - return true; -} - -wxWindow *wxListbook::DoRemovePage(size_t page) -{ - const size_t page_count = GetPageCount(); - wxWindow *win = wxBookCtrlBase::DoRemovePage(page); - - if ( win ) - { - GetListView()->DeleteItem(page); - - if (m_selection >= (int)page) - { - // force new sel valid if possible - int sel = m_selection - 1; - if (page_count == 1) - sel = wxNOT_FOUND; - else if ((page_count == 2) || (sel == -1)) - sel = 0; - - // force sel invalid if deleting current page - don't try to hide it - m_selection = (m_selection == (int)page) ? wxNOT_FOUND : m_selection - 1; - - if ((sel != wxNOT_FOUND) && (sel != m_selection)) - SetSelection(sel); - } - - GetListView()->Arrange(); - if (GetPageCount() == 0) - { - wxSizeEvent sz(GetSize(), GetId()); - ProcessEvent(sz); - } - } - - return win; -} - - -bool wxListbook::DeleteAllPages() -{ - GetListView()->DeleteAllItems(); - if (!wxBookCtrlBase::DeleteAllPages()) - return false; - - m_selection = -1; - - wxSizeEvent sz(GetSize(), GetId()); - ProcessEvent(sz); - - return true; -} - -// ---------------------------------------------------------------------------- -// wxListbook events -// ---------------------------------------------------------------------------- - -void wxListbook::OnListSelected(wxListEvent& eventList) -{ - if ( eventList.GetEventObject() != m_bookctrl ) - { - eventList.Skip(); - return; - } - - const int selNew = eventList.GetIndex(); - - if ( selNew == m_selection ) - { - // this event can only come from our own Select(m_selection) below - // which we call when the page change is vetoed, so we should simply - // ignore it - return; - } - - SetSelection(selNew); - - // change wasn't allowed, return to previous state - if (m_selection != selNew) - { - GetListView()->Select(m_selection); - GetListView()->Focus(m_selection); - } -} - -#endif // wxUSE_LISTBOOK +/////////////////////////////////////////////////////////////////////////////// +// Name: src/generic/listbkg.cpp +// Purpose: generic implementation of wxListbook +// Author: Vadim Zeitlin +// Modified by: +// Created: 19.08.03 +// RCS-ID: $Id: listbkg.cpp 48783 2007-09-19 11:24:38Z RR $ +// Copyright: (c) 2003 Vadim Zeitlin +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_LISTBOOK + +#include "wx/listbook.h" + +#ifndef WX_PRECOMP + #include "wx/settings.h" +#endif + +#include "wx/listctrl.h" +#include "wx/statline.h" +#include "wx/imaglist.h" + +// ---------------------------------------------------------------------------- +// various wxWidgets macros +// ---------------------------------------------------------------------------- + +// check that the page index is valid +#define IS_VALID_PAGE(nPage) ((nPage) < GetPageCount()) + +// ---------------------------------------------------------------------------- +// event table +// ---------------------------------------------------------------------------- + +IMPLEMENT_DYNAMIC_CLASS(wxListbook, wxBookCtrlBase) +IMPLEMENT_DYNAMIC_CLASS(wxListbookEvent, wxNotifyEvent) + +#if !WXWIN_COMPATIBILITY_EVENT_TYPES +const wxEventType wxEVT_COMMAND_LISTBOOK_PAGE_CHANGING = wxNewEventType(); +const wxEventType wxEVT_COMMAND_LISTBOOK_PAGE_CHANGED = wxNewEventType(); +#endif + +BEGIN_EVENT_TABLE(wxListbook, wxBookCtrlBase) + EVT_SIZE(wxListbook::OnSize) + EVT_LIST_ITEM_SELECTED(wxID_ANY, wxListbook::OnListSelected) +END_EVENT_TABLE() + +// ============================================================================ +// wxListbook implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// wxListbook creation +// ---------------------------------------------------------------------------- + +void wxListbook::Init() +{ + m_selection = wxNOT_FOUND; +} + +bool +wxListbook::Create(wxWindow *parent, + wxWindowID id, + const wxPoint& pos, + const wxSize& size, + long style, + const wxString& name) +{ + if ( (style & wxBK_ALIGN_MASK) == wxBK_DEFAULT ) + { +#ifdef __WXMAC__ + style |= wxBK_TOP; +#else // !__WXMAC__ + style |= wxBK_LEFT; +#endif // __WXMAC__/!__WXMAC__ + } + + // no border for this control, it doesn't look nice together with + // wxListCtrl border + style &= ~wxBORDER_MASK; + style |= wxBORDER_NONE; + + if ( !wxControl::Create(parent, id, pos, size, style, + wxDefaultValidator, name) ) + return false; + + m_bookctrl = new wxListView + ( + this, + wxID_ANY, + wxDefaultPosition, + wxDefaultSize, + wxLC_ICON | wxLC_SINGLE_SEL | + (IsVertical() ? wxLC_ALIGN_LEFT : wxLC_ALIGN_TOP) + ); + +#ifdef __WXMSW__ + // On XP with themes enabled the GetViewRect used in GetControllerSize() to + // determine the space needed for the list view will incorrectly return + // (0,0,0,0) the first time. So send a pending event so OnSize will be + // called again after the window is ready to go. Technically we don't + // need to do this on non-XP windows, but if things are already sized + // correctly then nothing changes and so there is no harm. + wxSizeEvent evt; + GetEventHandler()->AddPendingEvent(evt); +#endif + return true; +} + +// ---------------------------------------------------------------------------- +// wxListbook geometry management +// ---------------------------------------------------------------------------- + +wxSize wxListbook::GetControllerSize() const +{ + const wxSize sizeClient = GetClientSize(), + sizeBorder = m_bookctrl->GetSize() - m_bookctrl->GetClientSize(), + sizeList = GetListView()->GetViewRect().GetSize() + sizeBorder; + + wxSize size; + + if ( IsVertical() ) + { + size.x = sizeClient.x; + size.y = sizeList.y; + } + else // left/right aligned + { + size.x = sizeList.x; + size.y = sizeClient.y; + } + + return size; +} + +void wxListbook::OnSize(wxSizeEvent& event) +{ + // arrange the icons before calling SetClientSize(), otherwise it wouldn't + // account for the scrollbars the list control might need and, at least + // under MSW, we'd finish with an ugly looking list control with both + // vertical and horizontal scrollbar (with one of them being added because + // the other one is not accounted for in client size computations) + wxListView *list = GetListView(); + if (list) list->Arrange(); + wxBookCtrlBase::OnSize(event); +} + +int wxListbook::HitTest(const wxPoint& pt, long *flags) const +{ + int pagePos = wxNOT_FOUND; + + if ( flags ) + *flags = wxBK_HITTEST_NOWHERE; + + // convert from listbook control coordinates to list control coordinates + const wxListView * const list = GetListView(); + const wxPoint listPt = list->ScreenToClient(ClientToScreen(pt)); + + // is the point inside list control? + if ( wxRect(list->GetSize()).Contains(listPt) ) + { + int flagsList; + pagePos = list->HitTest(listPt, flagsList); + + if ( flags ) + { + if ( pagePos != wxNOT_FOUND ) + *flags = 0; + + if ( flagsList & (wxLIST_HITTEST_ONITEMICON | + wxLIST_HITTEST_ONITEMSTATEICON ) ) + *flags |= wxBK_HITTEST_ONICON; + + if ( flagsList & wxLIST_HITTEST_ONITEMLABEL ) + *flags |= wxBK_HITTEST_ONLABEL; + } + } + else // not over list control at all + { + if ( flags && GetPageRect().Contains(pt) ) + *flags |= wxBK_HITTEST_ONPAGE; + } + + return pagePos; +} + +wxSize wxListbook::CalcSizeFromPage(const wxSize& sizePage) const +{ + // we need to add the size of the list control and the border between + const wxSize sizeList = GetControllerSize(); + + wxSize size = sizePage; + if ( IsVertical() ) + { + size.y += sizeList.y + GetInternalBorder(); + } + else // left/right aligned + { + size.x += sizeList.x + GetInternalBorder(); + } + + return size; +} + + +// ---------------------------------------------------------------------------- +// accessing the pages +// ---------------------------------------------------------------------------- + +bool wxListbook::SetPageText(size_t n, const wxString& strText) +{ + GetListView()->SetItemText(n, strText); + + return true; +} + +wxString wxListbook::GetPageText(size_t n) const +{ + return GetListView()->GetItemText(n); +} + +int wxListbook::GetPageImage(size_t WXUNUSED(n)) const +{ + wxFAIL_MSG( _T("wxListbook::GetPageImage() not implemented") ); + + return wxNOT_FOUND; +} + +bool wxListbook::SetPageImage(size_t n, int imageId) +{ + return GetListView()->SetItemImage(n, imageId); +} + +// ---------------------------------------------------------------------------- +// image list stuff +// ---------------------------------------------------------------------------- + +void wxListbook::SetImageList(wxImageList *imageList) +{ + GetListView()->SetImageList(imageList, wxIMAGE_LIST_NORMAL); + + wxBookCtrlBase::SetImageList(imageList); +} + +// ---------------------------------------------------------------------------- +// selection +// ---------------------------------------------------------------------------- + +void wxListbook::UpdateSelectedPage(size_t newsel) +{ + m_selection = newsel; + GetListView()->Select(newsel); + GetListView()->Focus(newsel); +} + +int wxListbook::GetSelection() const +{ + return m_selection; +} + +wxBookCtrlBaseEvent* wxListbook::CreatePageChangingEvent() const +{ + return new wxListbookEvent(wxEVT_COMMAND_LISTBOOK_PAGE_CHANGING, m_windowId); +} + +void wxListbook::MakeChangedEvent(wxBookCtrlBaseEvent &event) +{ + event.SetEventType(wxEVT_COMMAND_LISTBOOK_PAGE_CHANGED); +} + + +// ---------------------------------------------------------------------------- +// adding/removing the pages +// ---------------------------------------------------------------------------- + +bool +wxListbook::InsertPage(size_t n, + wxWindow *page, + const wxString& text, + bool bSelect, + int imageId) +{ + if ( !wxBookCtrlBase::InsertPage(n, page, text, bSelect, imageId) ) + return false; + + GetListView()->InsertItem(n, text, imageId); + + // if the inserted page is before the selected one, we must update the + // index of the selected page + if ( int(n) <= m_selection ) + { + // one extra page added + m_selection++; + GetListView()->Select(m_selection); + GetListView()->Focus(m_selection); + } + + // some page should be selected: either this one or the first one if there + // is still no selection + int selNew = -1; + if ( bSelect ) + selNew = n; + else if ( m_selection == -1 ) + selNew = 0; + + if ( selNew != m_selection ) + page->Hide(); + + if ( selNew != -1 ) + SetSelection(selNew); + + wxSizeEvent sz(GetSize(), GetId()); + GetEventHandler()->ProcessEvent(sz); + + return true; +} + +wxWindow *wxListbook::DoRemovePage(size_t page) +{ + const size_t page_count = GetPageCount(); + wxWindow *win = wxBookCtrlBase::DoRemovePage(page); + + if ( win ) + { + GetListView()->DeleteItem(page); + + if (m_selection >= (int)page) + { + // force new sel valid if possible + int sel = m_selection - 1; + if (page_count == 1) + sel = wxNOT_FOUND; + else if ((page_count == 2) || (sel == -1)) + sel = 0; + + // force sel invalid if deleting current page - don't try to hide it + m_selection = (m_selection == (int)page) ? wxNOT_FOUND : m_selection - 1; + + if ((sel != wxNOT_FOUND) && (sel != m_selection)) + SetSelection(sel); + } + + GetListView()->Arrange(); + if (GetPageCount() == 0) + { + wxSizeEvent sz(GetSize(), GetId()); + ProcessEvent(sz); + } + } + + return win; +} + + +bool wxListbook::DeleteAllPages() +{ + GetListView()->DeleteAllItems(); + if (!wxBookCtrlBase::DeleteAllPages()) + return false; + + m_selection = -1; + + wxSizeEvent sz(GetSize(), GetId()); + ProcessEvent(sz); + + return true; +} + +// ---------------------------------------------------------------------------- +// wxListbook events +// ---------------------------------------------------------------------------- + +void wxListbook::OnListSelected(wxListEvent& eventList) +{ + if ( eventList.GetEventObject() != m_bookctrl ) + { + eventList.Skip(); + return; + } + + const int selNew = eventList.GetIndex(); + + if ( selNew == m_selection ) + { + // this event can only come from our own Select(m_selection) below + // which we call when the page change is vetoed, so we should simply + // ignore it + return; + } + + SetSelection(selNew); + + // change wasn't allowed, return to previous state + if (m_selection != selNew) + { + GetListView()->Select(m_selection); + GetListView()->Focus(m_selection); + } +} + +#endif // wxUSE_LISTBOOK diff --git a/Externals/wxWidgets/src/generic/listctrl.cpp b/Externals/wxWidgets/src/generic/listctrl.cpp index 47cc270a7a..380ed1f413 100644 --- a/Externals/wxWidgets/src/generic/listctrl.cpp +++ b/Externals/wxWidgets/src/generic/listctrl.cpp @@ -1,5954 +1,5954 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/generic/listctrl.cpp -// Purpose: generic implementation of wxListCtrl -// Author: Robert Roebling -// Vadim Zeitlin (virtual list control support) -// Id: $Id: listctrl.cpp 54201 2008-06-13 22:38:33Z VZ $ -// Copyright: (c) 1998 Robert Roebling -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// TODO -// -// 1. we need to implement searching/sorting for virtual controls somehow -// 2. when changing selection the lines are refreshed twice - - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_LISTCTRL - -#include "wx/listctrl.h" - -#if (!defined(__WXMSW__) || defined(__WXUNIVERSAL__)) && (!defined(__WXMAC__)|| defined(__WXUNIVERSAL__)) - // if we have a native version, its implementation file does all this - IMPLEMENT_DYNAMIC_CLASS(wxListItem, wxObject) - IMPLEMENT_DYNAMIC_CLASS(wxListView, wxListCtrl) - IMPLEMENT_DYNAMIC_CLASS(wxListEvent, wxNotifyEvent) - - IMPLEMENT_DYNAMIC_CLASS(wxListCtrl, wxGenericListCtrl) -#endif - -#ifndef WX_PRECOMP - #include "wx/scrolwin.h" - #include "wx/timer.h" - #include "wx/settings.h" - #include "wx/dynarray.h" - #include "wx/dcclient.h" - #include "wx/dcscreen.h" - #include "wx/math.h" -#endif - -#include "wx/imaglist.h" -#include "wx/selstore.h" -#include "wx/renderer.h" - -#ifdef __WXMAC__ - #include "wx/mac/private.h" -#endif - - -// NOTE: If using the wxListBox visual attributes works everywhere then this can -// be removed, as well as the #else case below. -#define _USE_VISATTR 0 - - -// ---------------------------------------------------------------------------- -// constants -// ---------------------------------------------------------------------------- - -// // the height of the header window (FIXME: should depend on its font!) -// static const int HEADER_HEIGHT = 23; - -static const int SCROLL_UNIT_X = 15; - -// the spacing between the lines (in report mode) -static const int LINE_SPACING = 0; - -// extra margins around the text label -#ifdef __WXGTK__ -static const int EXTRA_WIDTH = 6; -#else -static const int EXTRA_WIDTH = 4; -#endif -static const int EXTRA_HEIGHT = 4; - -// margin between the window and the items -static const int EXTRA_BORDER_X = 2; -static const int EXTRA_BORDER_Y = 2; - -// offset for the header window -static const int HEADER_OFFSET_X = 0; -static const int HEADER_OFFSET_Y = 0; - -// margin between rows of icons in [small] icon view -static const int MARGIN_BETWEEN_ROWS = 6; - -// when autosizing the columns, add some slack -static const int AUTOSIZE_COL_MARGIN = 10; - -// default width for the header columns -static const int WIDTH_COL_DEFAULT = 80; - -// the space between the image and the text in the report mode -static const int IMAGE_MARGIN_IN_REPORT_MODE = 5; - -// the space between the image and the text in the report mode in header -static const int HEADER_IMAGE_MARGIN_IN_REPORT_MODE = 2; - -// ============================================================================ -// private classes -// ============================================================================ - -//----------------------------------------------------------------------------- -// wxColWidthInfo (internal) -//----------------------------------------------------------------------------- - -struct wxColWidthInfo -{ - int nMaxWidth; - bool bNeedsUpdate; // only set to true when an item whose - // width == nMaxWidth is removed - - wxColWidthInfo(int w = 0, bool needsUpdate = false) - { - nMaxWidth = w; - bNeedsUpdate = needsUpdate; - } -}; - -WX_DEFINE_ARRAY_PTR(wxColWidthInfo *, ColWidthArray); - -//----------------------------------------------------------------------------- -// wxListItemData (internal) -//----------------------------------------------------------------------------- - -class wxListItemData -{ -public: - wxListItemData(wxListMainWindow *owner); - ~wxListItemData(); - - void SetItem( const wxListItem &info ); - void SetImage( int image ) { m_image = image; } - void SetData( wxUIntPtr data ) { m_data = data; } - void SetPosition( int x, int y ); - void SetSize( int width, int height ); - - bool HasText() const { return !m_text.empty(); } - const wxString& GetText() const { return m_text; } - void SetText(const wxString& text) { m_text = text; } - - // we can't use empty string for measuring the string width/height, so - // always return something - wxString GetTextForMeasuring() const - { - wxString s = GetText(); - if ( s.empty() ) - s = _T('H'); - - return s; - } - - bool IsHit( int x, int y ) const; - - int GetX() const; - int GetY() const; - int GetWidth() const; - int GetHeight() const; - - int GetImage() const { return m_image; } - bool HasImage() const { return GetImage() != -1; } - - void GetItem( wxListItem &info ) const; - - void SetAttr(wxListItemAttr *attr) { m_attr = attr; } - wxListItemAttr *GetAttr() const { return m_attr; } - -public: - // the item image or -1 - int m_image; - - // user data associated with the item - wxUIntPtr m_data; - - // the item coordinates are not used in report mode; instead this pointer is - // NULL and the owner window is used to retrieve the item position and size - wxRect *m_rect; - - // the list ctrl we are in - wxListMainWindow *m_owner; - - // custom attributes or NULL - wxListItemAttr *m_attr; - -protected: - // common part of all ctors - void Init(); - - wxString m_text; -}; - -//----------------------------------------------------------------------------- -// wxListHeaderData (internal) -//----------------------------------------------------------------------------- - -class wxListHeaderData : public wxObject -{ -public: - wxListHeaderData(); - wxListHeaderData( const wxListItem &info ); - void SetItem( const wxListItem &item ); - void SetPosition( int x, int y ); - void SetWidth( int w ); - void SetState( int state ); - void SetFormat( int format ); - void SetHeight( int h ); - bool HasImage() const; - - bool HasText() const { return !m_text.empty(); } - const wxString& GetText() const { return m_text; } - void SetText(const wxString& text) { m_text = text; } - - void GetItem( wxListItem &item ); - - bool IsHit( int x, int y ) const; - int GetImage() const; - int GetWidth() const; - int GetFormat() const; - int GetState() const; - -protected: - long m_mask; - int m_image; - wxString m_text; - int m_format; - int m_width; - int m_xpos, - m_ypos; - int m_height; - int m_state; - -private: - void Init(); -}; - -//----------------------------------------------------------------------------- -// wxListLineData (internal) -//----------------------------------------------------------------------------- - -WX_DECLARE_EXPORTED_LIST(wxListItemData, wxListItemDataList); -#include "wx/listimpl.cpp" -WX_DEFINE_LIST(wxListItemDataList) - -class wxListLineData -{ -public: - // the list of subitems: only may have more than one item in report mode - wxListItemDataList m_items; - - // this is not used in report view - struct GeometryInfo - { - // total item rect - wxRect m_rectAll; - - // label only - wxRect m_rectLabel; - - // icon only - wxRect m_rectIcon; - - // the part to be highlighted - wxRect m_rectHighlight; - - // extend all our rects to be centered inside the one of given width - void ExtendWidth(wxCoord w) - { - wxASSERT_MSG( m_rectAll.width <= w, - _T("width can only be increased") ); - - m_rectAll.width = w; - m_rectLabel.x = m_rectAll.x + (w - m_rectLabel.width) / 2; - m_rectIcon.x = m_rectAll.x + (w - m_rectIcon.width) / 2; - m_rectHighlight.x = m_rectAll.x + (w - m_rectHighlight.width) / 2; - } - } - *m_gi; - - // is this item selected? [NB: not used in virtual mode] - bool m_highlighted; - - // back pointer to the list ctrl - wxListMainWindow *m_owner; - -public: - wxListLineData(wxListMainWindow *owner); - - ~wxListLineData() - { - WX_CLEAR_LIST(wxListItemDataList, m_items); - delete m_gi; - } - - // are we in report mode? - inline bool InReportView() const; - - // are we in virtual report mode? - inline bool IsVirtual() const; - - // these 2 methods shouldn't be called for report view controls, in that - // case we determine our position/size ourselves - - // calculate the size of the line - void CalculateSize( wxDC *dc, int spacing ); - - // remember the position this line appears at - void SetPosition( int x, int y, int spacing ); - - // wxListCtrl API - - void SetImage( int image ) { SetImage(0, image); } - int GetImage() const { return GetImage(0); } - void SetImage( int index, int image ); - int GetImage( int index ) const; - - bool HasImage() const { return GetImage() != -1; } - bool HasText() const { return !GetText(0).empty(); } - - void SetItem( int index, const wxListItem &info ); - void GetItem( int index, wxListItem &info ); - - wxString GetText(int index) const; - void SetText( int index, const wxString& s ); - - wxListItemAttr *GetAttr() const; - void SetAttr(wxListItemAttr *attr); - - // return true if the highlighting really changed - bool Highlight( bool on ); - - void ReverseHighlight(); - - bool IsHighlighted() const - { - wxASSERT_MSG( !IsVirtual(), _T("unexpected call to IsHighlighted") ); - - return m_highlighted; - } - - // draw the line on the given DC in icon/list mode - void Draw( wxDC *dc ); - - // the same in report mode - void DrawInReportMode( wxDC *dc, - const wxRect& rect, - const wxRect& rectHL, - bool highlighted ); - -private: - // set the line to contain num items (only can be > 1 in report mode) - void InitItems( int num ); - - // get the mode (i.e. style) of the list control - inline int GetMode() const; - - // prepare the DC for drawing with these item's attributes, return true if - // we need to draw the items background to highlight it, false otherwise - bool SetAttributes(wxDC *dc, - const wxListItemAttr *attr, - bool highlight); - - // draw the text on the DC with the correct justification; also add an - // ellipsis if the text is too large to fit in the current width - void DrawTextFormatted(wxDC *dc, - const wxString &text, - int col, - int x, - int yMid, // this is middle, not top, of the text - int width); -}; - -WX_DECLARE_EXPORTED_OBJARRAY(wxListLineData, wxListLineDataArray); -#include "wx/arrimpl.cpp" -WX_DEFINE_OBJARRAY(wxListLineDataArray) - -//----------------------------------------------------------------------------- -// wxListHeaderWindow (internal) -//----------------------------------------------------------------------------- - -class wxListHeaderWindow : public wxWindow -{ -protected: - wxListMainWindow *m_owner; - const wxCursor *m_currentCursor; - wxCursor *m_resizeCursor; - bool m_isDragging; - - // column being resized or -1 - int m_column; - - // divider line position in logical (unscrolled) coords - int m_currentX; - - // minimal position beyond which the divider line - // can't be dragged in logical coords - int m_minX; - -public: - wxListHeaderWindow(); - - wxListHeaderWindow( wxWindow *win, - wxWindowID id, - wxListMainWindow *owner, - const wxPoint &pos = wxDefaultPosition, - const wxSize &size = wxDefaultSize, - long style = 0, - const wxString &name = wxT("wxlistctrlcolumntitles") ); - - virtual ~wxListHeaderWindow(); - - void DrawCurrent(); - void AdjustDC( wxDC& dc ); - - void OnPaint( wxPaintEvent &event ); - void OnMouse( wxMouseEvent &event ); - void OnSetFocus( wxFocusEvent &event ); - - // needs refresh - bool m_dirty; - -private: - // common part of all ctors - void Init(); - - // generate and process the list event of the given type, return true if - // it wasn't vetoed, i.e. if we should proceed - bool SendListEvent(wxEventType type, const wxPoint& pos); - - DECLARE_DYNAMIC_CLASS(wxListHeaderWindow) - DECLARE_EVENT_TABLE() -}; - -//----------------------------------------------------------------------------- -// wxListRenameTimer (internal) -//----------------------------------------------------------------------------- - -class wxListRenameTimer: public wxTimer -{ -private: - wxListMainWindow *m_owner; - -public: - wxListRenameTimer( wxListMainWindow *owner ); - void Notify(); -}; - -//----------------------------------------------------------------------------- -// wxListTextCtrlWrapper: wraps a wxTextCtrl to make it work for inline editing -//----------------------------------------------------------------------------- - -class wxListTextCtrlWrapper : public wxEvtHandler -{ -public: - // NB: text must be a valid object but not Create()d yet - wxListTextCtrlWrapper(wxListMainWindow *owner, - wxTextCtrl *text, - size_t itemEdit); - - wxTextCtrl *GetText() const { return m_text; } - - void AcceptChangesAndFinish(); - -protected: - void OnChar( wxKeyEvent &event ); - void OnKeyUp( wxKeyEvent &event ); - void OnKillFocus( wxFocusEvent &event ); - - bool AcceptChanges(); - void Finish(); - -private: - wxListMainWindow *m_owner; - wxTextCtrl *m_text; - wxString m_startValue; - size_t m_itemEdited; - bool m_finished; - bool m_aboutToFinish; - - DECLARE_EVENT_TABLE() -}; - -//----------------------------------------------------------------------------- -// wxListMainWindow (internal) -//----------------------------------------------------------------------------- - -WX_DECLARE_EXPORTED_LIST(wxListHeaderData, wxListHeaderDataList); -#include "wx/listimpl.cpp" -WX_DEFINE_LIST(wxListHeaderDataList) - -class wxListMainWindow : public wxScrolledWindow -{ -public: - wxListMainWindow(); - wxListMainWindow( wxWindow *parent, - wxWindowID id, - const wxPoint& pos = wxDefaultPosition, - const wxSize& size = wxDefaultSize, - long style = 0, - const wxString &name = _T("listctrlmainwindow") ); - - virtual ~wxListMainWindow(); - - bool HasFlag(int flag) const { return m_parent->HasFlag(flag); } - - // return true if this is a virtual list control - bool IsVirtual() const { return HasFlag(wxLC_VIRTUAL); } - - // return true if the control is in report mode - bool InReportView() const { return HasFlag(wxLC_REPORT); } - - // return true if we are in single selection mode, false if multi sel - bool IsSingleSel() const { return HasFlag(wxLC_SINGLE_SEL); } - - // do we have a header window? - bool HasHeader() const - { return InReportView() && !HasFlag(wxLC_NO_HEADER); } - - void HighlightAll( bool on ); - - // all these functions only do something if the line is currently visible - - // change the line "selected" state, return true if it really changed - bool HighlightLine( size_t line, bool highlight = true); - - // as HighlightLine() but do it for the range of lines: this is incredibly - // more efficient for virtual list controls! - // - // NB: unlike HighlightLine() this one does refresh the lines on screen - void HighlightLines( size_t lineFrom, size_t lineTo, bool on = true ); - - // toggle the line state and refresh it - void ReverseHighlight( size_t line ) - { HighlightLine(line, !IsHighlighted(line)); RefreshLine(line); } - - // return true if the line is highlighted - bool IsHighlighted(size_t line) const; - - // refresh one or several lines at once - void RefreshLine( size_t line ); - void RefreshLines( size_t lineFrom, size_t lineTo ); - - // refresh all selected items - void RefreshSelected(); - - // refresh all lines below the given one: the difference with - // RefreshLines() is that the index here might not be a valid one (happens - // when the last line is deleted) - void RefreshAfter( size_t lineFrom ); - - // the methods which are forwarded to wxListLineData itself in list/icon - // modes but are here because the lines don't store their positions in the - // report mode - - // get the bound rect for the entire line - wxRect GetLineRect(size_t line) const; - - // get the bound rect of the label - wxRect GetLineLabelRect(size_t line) const; - - // get the bound rect of the items icon (only may be called if we do have - // an icon!) - wxRect GetLineIconRect(size_t line) const; - - // get the rect to be highlighted when the item has focus - wxRect GetLineHighlightRect(size_t line) const; - - // get the size of the total line rect - wxSize GetLineSize(size_t line) const - { return GetLineRect(line).GetSize(); } - - // return the hit code for the corresponding position (in this line) - long HitTestLine(size_t line, int x, int y) const; - - // bring the selected item into view, scrolling to it if necessary - void MoveToItem(size_t item); - - bool ScrollList( int WXUNUSED(dx), int dy ); - - // bring the current item into view - void MoveToFocus() { MoveToItem(m_current); } - - // start editing the label of the given item - wxTextCtrl *EditLabel(long item, - wxClassInfo* textControlClass = CLASSINFO(wxTextCtrl)); - wxTextCtrl *GetEditControl() const - { - return m_textctrlWrapper ? m_textctrlWrapper->GetText() : NULL; - } - - void FinishEditing(wxTextCtrl *text) - { - delete text; - m_textctrlWrapper = NULL; - SetFocusIgnoringChildren(); - } - - // suspend/resume redrawing the control - void Freeze(); - void Thaw(); - - void OnRenameTimer(); - bool OnRenameAccept(size_t itemEdit, const wxString& value); - void OnRenameCancelled(size_t itemEdit); - - void OnMouse( wxMouseEvent &event ); - - // called to switch the selection from the current item to newCurrent, - void OnArrowChar( size_t newCurrent, const wxKeyEvent& event ); - - void OnChar( wxKeyEvent &event ); - void OnKeyDown( wxKeyEvent &event ); - void OnKeyUp( wxKeyEvent &event ); - void OnSetFocus( wxFocusEvent &event ); - void OnKillFocus( wxFocusEvent &event ); - void OnScroll( wxScrollWinEvent& event ); - - void OnPaint( wxPaintEvent &event ); - - void DrawImage( int index, wxDC *dc, int x, int y ); - void GetImageSize( int index, int &width, int &height ) const; - int GetTextLength( const wxString &s ) const; - - void SetImageList( wxImageList *imageList, int which ); - void SetItemSpacing( int spacing, bool isSmall = false ); - int GetItemSpacing( bool isSmall = false ); - - void SetColumn( int col, wxListItem &item ); - void SetColumnWidth( int col, int width ); - void GetColumn( int col, wxListItem &item ) const; - int GetColumnWidth( int col ) const; - int GetColumnCount() const { return m_columns.GetCount(); } - - // returns the sum of the heights of all columns - int GetHeaderWidth() const; - - int GetCountPerPage() const; - - void SetItem( wxListItem &item ); - void GetItem( wxListItem &item ) const; - void SetItemState( long item, long state, long stateMask ); - void SetItemStateAll( long state, long stateMask ); - int GetItemState( long item, long stateMask ) const; - void GetItemRect( long index, wxRect &rect ) const; - wxRect GetViewRect() const; - bool GetItemPosition( long item, wxPoint& pos ) const; - int GetSelectedItemCount() const; - - wxString GetItemText(long item) const - { - wxListItem info; - info.m_mask = wxLIST_MASK_TEXT; - info.m_itemId = item; - GetItem( info ); - return info.m_text; - } - - void SetItemText(long item, const wxString& value) - { - wxListItem info; - info.m_mask = wxLIST_MASK_TEXT; - info.m_itemId = item; - info.m_text = value; - SetItem( info ); - } - - // set the scrollbars and update the positions of the items - void RecalculatePositions(bool noRefresh = false); - - // refresh the window and the header - void RefreshAll(); - - long GetNextItem( long item, int geometry, int state ) const; - void DeleteItem( long index ); - void DeleteAllItems(); - void DeleteColumn( int col ); - void DeleteEverything(); - void EnsureVisible( long index ); - long FindItem( long start, const wxString& str, bool partial = false ); - long FindItem( long start, wxUIntPtr data); - long FindItem( const wxPoint& pt ); - long HitTest( int x, int y, int &flags ) const; - void InsertItem( wxListItem &item ); - void InsertColumn( long col, wxListItem &item ); - int GetItemWidthWithImage(wxListItem * item); - void SortItems( wxListCtrlCompare fn, long data ); - - size_t GetItemCount() const; - bool IsEmpty() const { return GetItemCount() == 0; } - void SetItemCount(long count); - - // change the current (== focused) item, send a notification event - void ChangeCurrent(size_t current); - void ResetCurrent() { ChangeCurrent((size_t)-1); } - bool HasCurrent() const { return m_current != (size_t)-1; } - - // send out a wxListEvent - void SendNotify( size_t line, - wxEventType command, - const wxPoint& point = wxDefaultPosition ); - - // override base class virtual to reset m_lineHeight when the font changes - virtual bool SetFont(const wxFont& font) - { - if ( !wxScrolledWindow::SetFont(font) ) - return false; - - m_lineHeight = 0; - - return true; - } - - // these are for wxListLineData usage only - - // get the backpointer to the list ctrl - wxGenericListCtrl *GetListCtrl() const - { - return wxStaticCast(GetParent(), wxGenericListCtrl); - } - - // get the height of all lines (assuming they all do have the same height) - wxCoord GetLineHeight() const; - - // get the y position of the given line (only for report view) - wxCoord GetLineY(size_t line) const; - - // get the brush to use for the item highlighting - wxBrush *GetHighlightBrush() const - { - return m_hasFocus ? m_highlightBrush : m_highlightUnfocusedBrush; - } - - bool HasFocus() const - { - return m_hasFocus; - } - -//protected: - // the array of all line objects for a non virtual list control (for the - // virtual list control we only ever use m_lines[0]) - wxListLineDataArray m_lines; - - // the list of column objects - wxListHeaderDataList m_columns; - - // currently focused item or -1 - size_t m_current; - - // the number of lines per page - int m_linesPerPage; - - // this flag is set when something which should result in the window - // redrawing happens (i.e. an item was added or deleted, or its appearance - // changed) and OnPaint() doesn't redraw the window while it is set which - // allows to minimize the number of repaintings when a lot of items are - // being added. The real repainting occurs only after the next OnIdle() - // call - bool m_dirty; - - wxColour *m_highlightColour; - wxImageList *m_small_image_list; - wxImageList *m_normal_image_list; - int m_small_spacing; - int m_normal_spacing; - bool m_hasFocus; - - bool m_lastOnSame; - wxTimer *m_renameTimer; - bool m_isCreated; - int m_dragCount; - wxPoint m_dragStart; - ColWidthArray m_aColWidths; - - // for double click logic - size_t m_lineLastClicked, - m_lineBeforeLastClicked, - m_lineSelectSingleOnUp; - -protected: - wxWindow *GetMainWindowOfCompositeControl() { return GetParent(); } - - // the total count of items in a virtual list control - size_t m_countVirt; - - // the object maintaining the items selection state, only used in virtual - // controls - wxSelectionStore m_selStore; - - // common part of all ctors - void Init(); - - // get the line data for the given index - wxListLineData *GetLine(size_t n) const - { - wxASSERT_MSG( n != (size_t)-1, _T("invalid line index") ); - - if ( IsVirtual() ) - { - wxConstCast(this, wxListMainWindow)->CacheLineData(n); - n = 0; - } - - return &m_lines[n]; - } - - // get a dummy line which can be used for geometry calculations and such: - // you must use GetLine() if you want to really draw the line - wxListLineData *GetDummyLine() const; - - // cache the line data of the n-th line in m_lines[0] - void CacheLineData(size_t line); - - // get the range of visible lines - void GetVisibleLinesRange(size_t *from, size_t *to); - - // force us to recalculate the range of visible lines - void ResetVisibleLinesRange() { m_lineFrom = (size_t)-1; } - - // get the colour to be used for drawing the rules - wxColour GetRuleColour() const - { - return wxSystemSettings::GetColour(wxSYS_COLOUR_3DLIGHT); - } - -private: - // initialize the current item if needed - void UpdateCurrent(); - - // delete all items but don't refresh: called from dtor - void DoDeleteAllItems(); - - // the height of one line using the current font - wxCoord m_lineHeight; - - // the total header width or 0 if not calculated yet - wxCoord m_headerWidth; - - // the first and last lines being shown on screen right now (inclusive), - // both may be -1 if they must be calculated so never access them directly: - // use GetVisibleLinesRange() above instead - size_t m_lineFrom, - m_lineTo; - - // the brushes to use for item highlighting when we do/don't have focus - wxBrush *m_highlightBrush, - *m_highlightUnfocusedBrush; - - // if this is > 0, the control is frozen and doesn't redraw itself - size_t m_freezeCount; - - // wrapper around the text control currently used for in place editing or - // NULL if no item is being edited - wxListTextCtrlWrapper *m_textctrlWrapper; - - - DECLARE_DYNAMIC_CLASS(wxListMainWindow) - DECLARE_EVENT_TABLE() - - friend class wxGenericListCtrl; -}; - - -wxListItemData::~wxListItemData() -{ - // in the virtual list control the attributes are managed by the main - // program, so don't delete them - if ( !m_owner->IsVirtual() ) - delete m_attr; - - delete m_rect; -} - -void wxListItemData::Init() -{ - m_image = -1; - m_data = 0; - - m_attr = NULL; -} - -wxListItemData::wxListItemData(wxListMainWindow *owner) -{ - Init(); - - m_owner = owner; - - if ( owner->InReportView() ) - m_rect = NULL; - else - m_rect = new wxRect; -} - -void wxListItemData::SetItem( const wxListItem &info ) -{ - if ( info.m_mask & wxLIST_MASK_TEXT ) - SetText(info.m_text); - if ( info.m_mask & wxLIST_MASK_IMAGE ) - m_image = info.m_image; - if ( info.m_mask & wxLIST_MASK_DATA ) - m_data = info.m_data; - - if ( info.HasAttributes() ) - { - if ( m_attr ) - m_attr->AssignFrom(*info.GetAttributes()); - else - m_attr = new wxListItemAttr(*info.GetAttributes()); - } - - if ( m_rect ) - { - m_rect->x = - m_rect->y = - m_rect->height = 0; - m_rect->width = info.m_width; - } -} - -void wxListItemData::SetPosition( int x, int y ) -{ - wxCHECK_RET( m_rect, _T("unexpected SetPosition() call") ); - - m_rect->x = x; - m_rect->y = y; -} - -void wxListItemData::SetSize( int width, int height ) -{ - wxCHECK_RET( m_rect, _T("unexpected SetSize() call") ); - - if ( width != -1 ) - m_rect->width = width; - if ( height != -1 ) - m_rect->height = height; -} - -bool wxListItemData::IsHit( int x, int y ) const -{ - wxCHECK_MSG( m_rect, false, _T("can't be called in this mode") ); - - return wxRect(GetX(), GetY(), GetWidth(), GetHeight()).Contains(x, y); -} - -int wxListItemData::GetX() const -{ - wxCHECK_MSG( m_rect, 0, _T("can't be called in this mode") ); - - return m_rect->x; -} - -int wxListItemData::GetY() const -{ - wxCHECK_MSG( m_rect, 0, _T("can't be called in this mode") ); - - return m_rect->y; -} - -int wxListItemData::GetWidth() const -{ - wxCHECK_MSG( m_rect, 0, _T("can't be called in this mode") ); - - return m_rect->width; -} - -int wxListItemData::GetHeight() const -{ - wxCHECK_MSG( m_rect, 0, _T("can't be called in this mode") ); - - return m_rect->height; -} - -void wxListItemData::GetItem( wxListItem &info ) const -{ - long mask = info.m_mask; - if ( !mask ) - // by default, get everything for backwards compatibility - mask = -1; - - if ( mask & wxLIST_MASK_TEXT ) - info.m_text = m_text; - if ( mask & wxLIST_MASK_IMAGE ) - info.m_image = m_image; - if ( mask & wxLIST_MASK_DATA ) - info.m_data = m_data; - - if ( m_attr ) - { - if ( m_attr->HasTextColour() ) - info.SetTextColour(m_attr->GetTextColour()); - if ( m_attr->HasBackgroundColour() ) - info.SetBackgroundColour(m_attr->GetBackgroundColour()); - if ( m_attr->HasFont() ) - info.SetFont(m_attr->GetFont()); - } -} - -//----------------------------------------------------------------------------- -// wxListHeaderData -//----------------------------------------------------------------------------- - -void wxListHeaderData::Init() -{ - m_mask = 0; - m_image = -1; - m_format = 0; - m_width = 0; - m_xpos = 0; - m_ypos = 0; - m_height = 0; - m_state = 0; -} - -wxListHeaderData::wxListHeaderData() -{ - Init(); -} - -wxListHeaderData::wxListHeaderData( const wxListItem &item ) -{ - Init(); - - SetItem( item ); -} - -void wxListHeaderData::SetItem( const wxListItem &item ) -{ - m_mask = item.m_mask; - - if ( m_mask & wxLIST_MASK_TEXT ) - m_text = item.m_text; - - if ( m_mask & wxLIST_MASK_IMAGE ) - m_image = item.m_image; - - if ( m_mask & wxLIST_MASK_FORMAT ) - m_format = item.m_format; - - if ( m_mask & wxLIST_MASK_WIDTH ) - SetWidth(item.m_width); - - if ( m_mask & wxLIST_MASK_STATE ) - SetState(item.m_state); -} - -void wxListHeaderData::SetPosition( int x, int y ) -{ - m_xpos = x; - m_ypos = y; -} - -void wxListHeaderData::SetHeight( int h ) -{ - m_height = h; -} - -void wxListHeaderData::SetWidth( int w ) -{ - m_width = w < 0 ? WIDTH_COL_DEFAULT : w; -} - -void wxListHeaderData::SetState( int flag ) -{ - m_state = flag; -} - -void wxListHeaderData::SetFormat( int format ) -{ - m_format = format; -} - -bool wxListHeaderData::HasImage() const -{ - return m_image != -1; -} - -bool wxListHeaderData::IsHit( int x, int y ) const -{ - return ((x >= m_xpos) && (x <= m_xpos+m_width) && (y >= m_ypos) && (y <= m_ypos+m_height)); -} - -void wxListHeaderData::GetItem( wxListItem& item ) -{ - item.m_mask = m_mask; - item.m_text = m_text; - item.m_image = m_image; - item.m_format = m_format; - item.m_width = m_width; - item.m_state = m_state; -} - -int wxListHeaderData::GetImage() const -{ - return m_image; -} - -int wxListHeaderData::GetWidth() const -{ - return m_width; -} - -int wxListHeaderData::GetFormat() const -{ - return m_format; -} - -int wxListHeaderData::GetState() const -{ - return m_state; -} - -//----------------------------------------------------------------------------- -// wxListLineData -//----------------------------------------------------------------------------- - -inline int wxListLineData::GetMode() const -{ - return m_owner->GetListCtrl()->GetWindowStyleFlag() & wxLC_MASK_TYPE; -} - -inline bool wxListLineData::InReportView() const -{ - return m_owner->HasFlag(wxLC_REPORT); -} - -inline bool wxListLineData::IsVirtual() const -{ - return m_owner->IsVirtual(); -} - -wxListLineData::wxListLineData( wxListMainWindow *owner ) -{ - m_owner = owner; - - if ( InReportView() ) - m_gi = NULL; - else // !report - m_gi = new GeometryInfo; - - m_highlighted = false; - - InitItems( GetMode() == wxLC_REPORT ? m_owner->GetColumnCount() : 1 ); -} - -void wxListLineData::CalculateSize( wxDC *dc, int spacing ) -{ - wxListItemDataList::compatibility_iterator node = m_items.GetFirst(); - wxCHECK_RET( node, _T("no subitems at all??") ); - - wxListItemData *item = node->GetData(); - - wxString s; - wxCoord lw, lh; - - switch ( GetMode() ) - { - case wxLC_ICON: - case wxLC_SMALL_ICON: - m_gi->m_rectAll.width = spacing; - - s = item->GetText(); - - if ( s.empty() ) - { - lh = - m_gi->m_rectLabel.width = - m_gi->m_rectLabel.height = 0; - } - else // has label - { - dc->GetTextExtent( s, &lw, &lh ); - lw += EXTRA_WIDTH; - lh += EXTRA_HEIGHT; - - m_gi->m_rectAll.height = spacing + lh; - if (lw > spacing) - m_gi->m_rectAll.width = lw; - - m_gi->m_rectLabel.width = lw; - m_gi->m_rectLabel.height = lh; - } - - if (item->HasImage()) - { - int w, h; - m_owner->GetImageSize( item->GetImage(), w, h ); - m_gi->m_rectIcon.width = w + 8; - m_gi->m_rectIcon.height = h + 8; - - if ( m_gi->m_rectIcon.width > m_gi->m_rectAll.width ) - m_gi->m_rectAll.width = m_gi->m_rectIcon.width; - if ( m_gi->m_rectIcon.height + lh > m_gi->m_rectAll.height - 4 ) - m_gi->m_rectAll.height = m_gi->m_rectIcon.height + lh + 4; - } - - if ( item->HasText() ) - { - m_gi->m_rectHighlight.width = m_gi->m_rectLabel.width; - m_gi->m_rectHighlight.height = m_gi->m_rectLabel.height; - } - else // no text, highlight the icon - { - m_gi->m_rectHighlight.width = m_gi->m_rectIcon.width; - m_gi->m_rectHighlight.height = m_gi->m_rectIcon.height; - } - break; - - case wxLC_LIST: - s = item->GetTextForMeasuring(); - - dc->GetTextExtent( s, &lw, &lh ); - lw += EXTRA_WIDTH; - lh += EXTRA_HEIGHT; - - m_gi->m_rectLabel.width = lw; - m_gi->m_rectLabel.height = lh; - - m_gi->m_rectAll.width = lw; - m_gi->m_rectAll.height = lh; - - if (item->HasImage()) - { - int w, h; - m_owner->GetImageSize( item->GetImage(), w, h ); - m_gi->m_rectIcon.width = w; - m_gi->m_rectIcon.height = h; - - m_gi->m_rectAll.width += 4 + w; - if (h > m_gi->m_rectAll.height) - m_gi->m_rectAll.height = h; - } - - m_gi->m_rectHighlight.width = m_gi->m_rectAll.width; - m_gi->m_rectHighlight.height = m_gi->m_rectAll.height; - break; - - case wxLC_REPORT: - wxFAIL_MSG( _T("unexpected call to SetSize") ); - break; - - default: - wxFAIL_MSG( _T("unknown mode") ); - break; - } -} - -void wxListLineData::SetPosition( int x, int y, int spacing ) -{ - wxListItemDataList::compatibility_iterator node = m_items.GetFirst(); - wxCHECK_RET( node, _T("no subitems at all??") ); - - wxListItemData *item = node->GetData(); - - switch ( GetMode() ) - { - case wxLC_ICON: - case wxLC_SMALL_ICON: - m_gi->m_rectAll.x = x; - m_gi->m_rectAll.y = y; - - if ( item->HasImage() ) - { - m_gi->m_rectIcon.x = m_gi->m_rectAll.x + 4 + - (m_gi->m_rectAll.width - m_gi->m_rectIcon.width) / 2; - m_gi->m_rectIcon.y = m_gi->m_rectAll.y + 4; - } - - if ( item->HasText() ) - { - if (m_gi->m_rectAll.width > spacing) - m_gi->m_rectLabel.x = m_gi->m_rectAll.x + (EXTRA_WIDTH/2); - else - m_gi->m_rectLabel.x = m_gi->m_rectAll.x + (EXTRA_WIDTH/2) + (spacing / 2) - (m_gi->m_rectLabel.width / 2); - m_gi->m_rectLabel.y = m_gi->m_rectAll.y + m_gi->m_rectAll.height + 2 - m_gi->m_rectLabel.height; - m_gi->m_rectHighlight.x = m_gi->m_rectLabel.x - 2; - m_gi->m_rectHighlight.y = m_gi->m_rectLabel.y - 2; - } - else // no text, highlight the icon - { - m_gi->m_rectHighlight.x = m_gi->m_rectIcon.x - 4; - m_gi->m_rectHighlight.y = m_gi->m_rectIcon.y - 4; - } - break; - - case wxLC_LIST: - m_gi->m_rectAll.x = x; - m_gi->m_rectAll.y = y; - - m_gi->m_rectHighlight.x = m_gi->m_rectAll.x; - m_gi->m_rectHighlight.y = m_gi->m_rectAll.y; - m_gi->m_rectLabel.y = m_gi->m_rectAll.y + 2; - - if (item->HasImage()) - { - m_gi->m_rectIcon.x = m_gi->m_rectAll.x + 2; - m_gi->m_rectIcon.y = m_gi->m_rectAll.y + 2; - m_gi->m_rectLabel.x = m_gi->m_rectAll.x + 4 + (EXTRA_WIDTH/2) + m_gi->m_rectIcon.width; - } - else - { - m_gi->m_rectLabel.x = m_gi->m_rectAll.x + (EXTRA_WIDTH/2); - } - break; - - case wxLC_REPORT: - wxFAIL_MSG( _T("unexpected call to SetPosition") ); - break; - - default: - wxFAIL_MSG( _T("unknown mode") ); - break; - } -} - -void wxListLineData::InitItems( int num ) -{ - for (int i = 0; i < num; i++) - m_items.Append( new wxListItemData(m_owner) ); -} - -void wxListLineData::SetItem( int index, const wxListItem &info ) -{ - wxListItemDataList::compatibility_iterator node = m_items.Item( index ); - wxCHECK_RET( node, _T("invalid column index in SetItem") ); - - wxListItemData *item = node->GetData(); - item->SetItem( info ); -} - -void wxListLineData::GetItem( int index, wxListItem &info ) -{ - wxListItemDataList::compatibility_iterator node = m_items.Item( index ); - if (node) - { - wxListItemData *item = node->GetData(); - item->GetItem( info ); - } -} - -wxString wxListLineData::GetText(int index) const -{ - wxString s; - - wxListItemDataList::compatibility_iterator node = m_items.Item( index ); - if (node) - { - wxListItemData *item = node->GetData(); - s = item->GetText(); - } - - return s; -} - -void wxListLineData::SetText( int index, const wxString& s ) -{ - wxListItemDataList::compatibility_iterator node = m_items.Item( index ); - if (node) - { - wxListItemData *item = node->GetData(); - item->SetText( s ); - } -} - -void wxListLineData::SetImage( int index, int image ) -{ - wxListItemDataList::compatibility_iterator node = m_items.Item( index ); - wxCHECK_RET( node, _T("invalid column index in SetImage()") ); - - wxListItemData *item = node->GetData(); - item->SetImage(image); -} - -int wxListLineData::GetImage( int index ) const -{ - wxListItemDataList::compatibility_iterator node = m_items.Item( index ); - wxCHECK_MSG( node, -1, _T("invalid column index in GetImage()") ); - - wxListItemData *item = node->GetData(); - return item->GetImage(); -} - -wxListItemAttr *wxListLineData::GetAttr() const -{ - wxListItemDataList::compatibility_iterator node = m_items.GetFirst(); - wxCHECK_MSG( node, NULL, _T("invalid column index in GetAttr()") ); - - wxListItemData *item = node->GetData(); - return item->GetAttr(); -} - -void wxListLineData::SetAttr(wxListItemAttr *attr) -{ - wxListItemDataList::compatibility_iterator node = m_items.GetFirst(); - wxCHECK_RET( node, _T("invalid column index in SetAttr()") ); - - wxListItemData *item = node->GetData(); - item->SetAttr(attr); -} - -bool wxListLineData::SetAttributes(wxDC *dc, - const wxListItemAttr *attr, - bool highlighted) -{ - wxWindow *listctrl = m_owner->GetParent(); - - // fg colour - - // don't use foreground colour for drawing highlighted items - this might - // make them completely invisible (and there is no way to do bit - // arithmetics on wxColour, unfortunately) - wxColour colText; - if ( highlighted ) -#ifdef __WXMAC__ - { - if (m_owner->HasFocus() -#ifdef __WXMAC__ - && IsControlActive( (ControlRef)m_owner->GetHandle() ) -#endif - ) - colText = *wxWHITE; - else - colText = *wxBLACK; - } -#else - colText = wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT); -#endif - else if ( attr && attr->HasTextColour() ) - colText = attr->GetTextColour(); - else - colText = listctrl->GetForegroundColour(); - - dc->SetTextForeground(colText); - - // font - wxFont font; - if ( attr && attr->HasFont() ) - font = attr->GetFont(); - else - font = listctrl->GetFont(); - - dc->SetFont(font); - - // bg colour - bool hasBgCol = attr && attr->HasBackgroundColour(); - if ( highlighted || hasBgCol ) - { - if ( highlighted ) - dc->SetBrush( *m_owner->GetHighlightBrush() ); - else - dc->SetBrush(wxBrush(attr->GetBackgroundColour(), wxSOLID)); - - dc->SetPen( *wxTRANSPARENT_PEN ); - - return true; - } - - return false; -} - -void wxListLineData::Draw( wxDC *dc ) -{ - wxListItemDataList::compatibility_iterator node = m_items.GetFirst(); - wxCHECK_RET( node, _T("no subitems at all??") ); - - bool highlighted = IsHighlighted(); - - wxListItemAttr *attr = GetAttr(); - - if ( SetAttributes(dc, attr, highlighted) ) -#if ( !defined(__WXGTK20__) && !defined(__WXMAC__) ) - { - dc->DrawRectangle( m_gi->m_rectHighlight ); - } -#else - { - if (highlighted) - { - int flags = wxCONTROL_SELECTED; - if (m_owner->HasFocus() -#ifdef __WXMAC__ - && IsControlActive( (ControlRef)m_owner->GetHandle() ) -#endif - ) - flags |= wxCONTROL_FOCUSED; - wxRendererNative::Get().DrawItemSelectionRect( m_owner, *dc, m_gi->m_rectHighlight, flags ); - - } - else - { - dc->DrawRectangle( m_gi->m_rectHighlight ); - } - } -#endif - - // just for debugging to better see where the items are -#if 0 - dc->SetPen(*wxRED_PEN); - dc->SetBrush(*wxTRANSPARENT_BRUSH); - dc->DrawRectangle( m_gi->m_rectAll ); - dc->SetPen(*wxGREEN_PEN); - dc->DrawRectangle( m_gi->m_rectIcon ); -#endif - - wxListItemData *item = node->GetData(); - if (item->HasImage()) - { - // centre the image inside our rectangle, this looks nicer when items - // ae aligned in a row - const wxRect& rectIcon = m_gi->m_rectIcon; - - m_owner->DrawImage(item->GetImage(), dc, rectIcon.x, rectIcon.y); - } - - if (item->HasText()) - { - const wxRect& rectLabel = m_gi->m_rectLabel; - - wxDCClipper clipper(*dc, rectLabel); - dc->DrawText(item->GetText(), rectLabel.x, rectLabel.y); - } -} - -void wxListLineData::DrawInReportMode( wxDC *dc, - const wxRect& rect, - const wxRect& rectHL, - bool highlighted ) -{ - // TODO: later we should support setting different attributes for - // different columns - to do it, just add "col" argument to - // GetAttr() and move these lines into the loop below - wxListItemAttr *attr = GetAttr(); - if ( SetAttributes(dc, attr, highlighted) ) -#if ( !defined(__WXGTK20__) && !defined(__WXMAC__) ) - { - dc->DrawRectangle( rectHL ); - } -#else - { - if (highlighted) - { - int flags = wxCONTROL_SELECTED; - if (m_owner->HasFocus() -#ifdef __WXMAC__ - && IsControlActive( (ControlRef)m_owner->GetHandle() ) -#endif - ) - flags |= wxCONTROL_FOCUSED; - wxRendererNative::Get().DrawItemSelectionRect( m_owner, *dc, rectHL, flags ); - } - else - { - dc->DrawRectangle( rectHL ); - } - } -#endif - - wxCoord x = rect.x + HEADER_OFFSET_X, - yMid = rect.y + rect.height/2; -#ifdef __WXGTK__ - // This probably needs to be done - // on all platforms as the icons - // otherwise nearly touch the border - x += 2; -#endif - - size_t col = 0; - for ( wxListItemDataList::compatibility_iterator node = m_items.GetFirst(); - node; - node = node->GetNext(), col++ ) - { - wxListItemData *item = node->GetData(); - - int width = m_owner->GetColumnWidth(col); - int xOld = x; - x += width; - - if ( item->HasImage() ) - { - int ix, iy; - m_owner->GetImageSize( item->GetImage(), ix, iy ); - m_owner->DrawImage( item->GetImage(), dc, xOld, yMid - iy/2 ); - - ix += IMAGE_MARGIN_IN_REPORT_MODE; - - xOld += ix; - width -= ix; - } - - if ( item->HasText() ) - DrawTextFormatted(dc, item->GetText(), col, xOld, yMid, width - 8); - } -} - -void wxListLineData::DrawTextFormatted(wxDC *dc, - const wxString& textOrig, - int col, - int x, - int yMid, - int width) -{ - // we don't support displaying multiple lines currently (and neither does - // wxMSW FWIW) so just merge all the lines - wxString text(textOrig); - text.Replace(_T("\n"), _T(" ")); - - wxCoord w, h; - dc->GetTextExtent(text, &w, &h); - - const wxCoord y = yMid - (h + 1)/2; - - wxDCClipper clipper(*dc, x, y, width, h); - - // determine if the string can fit inside the current width - if (w <= width) - { - // it can, draw it using the items alignment - wxListItem item; - m_owner->GetColumn(col, item); - switch ( item.GetAlign() ) - { - case wxLIST_FORMAT_LEFT: - // nothing to do - break; - - case wxLIST_FORMAT_RIGHT: - x += width - w; - break; - - case wxLIST_FORMAT_CENTER: - x += (width - w) / 2; - break; - - default: - wxFAIL_MSG( _T("unknown list item format") ); - break; - } - - dc->DrawText(text, x, y); - } - else // otherwise, truncate and add an ellipsis if possible - { - // determine the base width - wxString ellipsis(wxT("...")); - wxCoord base_w; - dc->GetTextExtent(ellipsis, &base_w, &h); - - // continue until we have enough space or only one character left - wxCoord w_c, h_c; - size_t len = text.length(); - wxString drawntext = text.Left(len); - while (len > 1) - { - dc->GetTextExtent(drawntext.Last(), &w_c, &h_c); - drawntext.RemoveLast(); - len--; - w -= w_c; - if (w + base_w <= width) - break; - } - - // if still not enough space, remove ellipsis characters - while (ellipsis.length() > 0 && w + base_w > width) - { - ellipsis = ellipsis.Left(ellipsis.length() - 1); - dc->GetTextExtent(ellipsis, &base_w, &h); - } - - // now draw the text - dc->DrawText(drawntext, x, y); - dc->DrawText(ellipsis, x + w, y); - } -} - -bool wxListLineData::Highlight( bool on ) -{ - wxCHECK_MSG( !IsVirtual(), false, _T("unexpected call to Highlight") ); - - if ( on == m_highlighted ) - return false; - - m_highlighted = on; - - return true; -} - -void wxListLineData::ReverseHighlight( void ) -{ - Highlight(!IsHighlighted()); -} - -//----------------------------------------------------------------------------- -// wxListHeaderWindow -//----------------------------------------------------------------------------- - -IMPLEMENT_DYNAMIC_CLASS(wxListHeaderWindow,wxWindow) - -BEGIN_EVENT_TABLE(wxListHeaderWindow,wxWindow) - EVT_PAINT (wxListHeaderWindow::OnPaint) - EVT_MOUSE_EVENTS (wxListHeaderWindow::OnMouse) - EVT_SET_FOCUS (wxListHeaderWindow::OnSetFocus) -END_EVENT_TABLE() - -void wxListHeaderWindow::Init() -{ - m_currentCursor = (wxCursor *) NULL; - m_isDragging = false; - m_dirty = false; -} - -wxListHeaderWindow::wxListHeaderWindow() -{ - Init(); - - m_owner = (wxListMainWindow *) NULL; - m_resizeCursor = (wxCursor *) NULL; -} - -wxListHeaderWindow::wxListHeaderWindow( wxWindow *win, - wxWindowID id, - wxListMainWindow *owner, - const wxPoint& pos, - const wxSize& size, - long style, - const wxString &name ) - : wxWindow( win, id, pos, size, style, name ) -{ - Init(); - - m_owner = owner; - m_resizeCursor = new wxCursor( wxCURSOR_SIZEWE ); - -#if _USE_VISATTR - wxVisualAttributes attr = wxPanel::GetClassDefaultAttributes(); - SetOwnForegroundColour( attr.colFg ); - SetOwnBackgroundColour( attr.colBg ); - if (!m_hasFont) - SetOwnFont( attr.font ); -#else - SetOwnForegroundColour( wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT)); - SetOwnBackgroundColour( wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE)); - if (!m_hasFont) - SetOwnFont( wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT )); -#endif -} - -wxListHeaderWindow::~wxListHeaderWindow() -{ - delete m_resizeCursor; -} - -#ifdef __WXUNIVERSAL__ -#include "wx/univ/renderer.h" -#include "wx/univ/theme.h" -#endif - -// shift the DC origin to match the position of the main window horz -// scrollbar: this allows us to always use logical coords -void wxListHeaderWindow::AdjustDC(wxDC& dc) -{ - int xpix; - m_owner->GetScrollPixelsPerUnit( &xpix, NULL ); - - int view_start; - m_owner->GetViewStart( &view_start, NULL ); - - - int org_x = 0; - int org_y = 0; - dc.GetDeviceOrigin( &org_x, &org_y ); - - // account for the horz scrollbar offset -#ifdef __WXGTK__ - if (GetLayoutDirection() == wxLayout_RightToLeft) - { - // Maybe we just have to check for m_signX - // in the DC, but I leave the #ifdef __WXGTK__ - // for now - dc.SetDeviceOrigin( org_x + (view_start * xpix), org_y ); - } - else -#endif - dc.SetDeviceOrigin( org_x - (view_start * xpix), org_y ); -} - -void wxListHeaderWindow::OnPaint( wxPaintEvent &WXUNUSED(event) ) -{ - wxPaintDC dc( this ); - - PrepareDC( dc ); - AdjustDC( dc ); - - dc.SetFont( GetFont() ); - - // width and height of the entire header window - int w, h; - GetClientSize( &w, &h ); - m_owner->CalcUnscrolledPosition(w, 0, &w, NULL); - - dc.SetBackgroundMode(wxTRANSPARENT); - dc.SetTextForeground(GetForegroundColour()); - - int x = HEADER_OFFSET_X; - int numColumns = m_owner->GetColumnCount(); - wxListItem item; - for ( int i = 0; i < numColumns && x < w; i++ ) - { - m_owner->GetColumn( i, item ); - int wCol = item.m_width; - - int cw = wCol; - int ch = h; - - int flags = 0; - if (!m_parent->IsEnabled()) - flags |= wxCONTROL_DISABLED; - -// NB: The code below is not really Mac-specific, but since we are close -// to 2.8 release and I don't have time to test on other platforms, I -// defined this only for wxMac. If this behavior is desired on -// other platforms, please go ahead and revise or remove the #ifdef. -#ifdef __WXMAC__ - if ( !m_owner->IsVirtual() && (item.m_mask & wxLIST_MASK_STATE) && - (item.m_state & wxLIST_STATE_SELECTED) ) - flags |= wxCONTROL_SELECTED; -#endif - - wxRendererNative::Get().DrawHeaderButton - ( - this, - dc, - wxRect(x, HEADER_OFFSET_Y, cw, ch), - flags - ); - - // see if we have enough space for the column label - - // for this we need the width of the text - wxCoord wLabel; - wxCoord hLabel; - dc.GetTextExtent(item.GetText(), &wLabel, &hLabel); - wLabel += 2 * EXTRA_WIDTH; - - // and the width of the icon, if any - int ix = 0, iy = 0; // init them just to suppress the compiler warnings - const int image = item.m_image; - wxImageList *imageList; - if ( image != -1 ) - { - imageList = m_owner->m_small_image_list; - if ( imageList ) - { - imageList->GetSize(image, ix, iy); - wLabel += ix + HEADER_IMAGE_MARGIN_IN_REPORT_MODE; - } - } - else - { - imageList = NULL; - } - - // ignore alignment if there is not enough space anyhow - int xAligned; - switch ( wLabel < cw ? item.GetAlign() : wxLIST_FORMAT_LEFT ) - { - default: - wxFAIL_MSG( _T("unknown list item format") ); - // fall through - - case wxLIST_FORMAT_LEFT: - xAligned = x; - break; - - case wxLIST_FORMAT_RIGHT: - xAligned = x + cw - wLabel; - break; - - case wxLIST_FORMAT_CENTER: - xAligned = x + (cw - wLabel) / 2; - break; - } - - // draw the text and image clipping them so that they - // don't overwrite the column boundary - wxDCClipper clipper(dc, x, HEADER_OFFSET_Y, cw, h ); - - // if we have an image, draw it on the right of the label - if ( imageList ) - { - imageList->Draw - ( - image, - dc, - xAligned + wLabel - ix - HEADER_IMAGE_MARGIN_IN_REPORT_MODE, - HEADER_OFFSET_Y + (h - 4 - iy)/2, - wxIMAGELIST_DRAW_TRANSPARENT - ); - } - - dc.DrawText( item.GetText(), - xAligned + EXTRA_WIDTH, h / 2 - hLabel / 2 ); //HEADER_OFFSET_Y + EXTRA_HEIGHT ); - - x += wCol; - } -} - -void wxListHeaderWindow::DrawCurrent() -{ -#if 1 - m_owner->SetColumnWidth( m_column, m_currentX - m_minX ); -#else - int x1 = m_currentX; - int y1 = 0; - m_owner->ClientToScreen( &x1, &y1 ); - - int x2 = m_currentX; - int y2 = 0; - m_owner->GetClientSize( NULL, &y2 ); - m_owner->ClientToScreen( &x2, &y2 ); - - wxScreenDC dc; - dc.SetLogicalFunction( wxINVERT ); - dc.SetPen( wxPen( *wxBLACK, 2, wxSOLID ) ); - dc.SetBrush( *wxTRANSPARENT_BRUSH ); - - AdjustDC(dc); - - dc.DrawLine( x1, y1, x2, y2 ); - - dc.SetLogicalFunction( wxCOPY ); - - dc.SetPen( wxNullPen ); - dc.SetBrush( wxNullBrush ); -#endif -} - -void wxListHeaderWindow::OnMouse( wxMouseEvent &event ) -{ - // we want to work with logical coords - int x; - m_owner->CalcUnscrolledPosition(event.GetX(), 0, &x, NULL); - int y = event.GetY(); - - if (m_isDragging) - { - SendListEvent(wxEVT_COMMAND_LIST_COL_DRAGGING, event.GetPosition()); - - // we don't draw the line beyond our window, but we allow dragging it - // there - int w = 0; - GetClientSize( &w, NULL ); - m_owner->CalcUnscrolledPosition(w, 0, &w, NULL); - w -= 6; - - // erase the line if it was drawn - if ( m_currentX < w ) - DrawCurrent(); - - if (event.ButtonUp()) - { - ReleaseMouse(); - m_isDragging = false; - m_dirty = true; - m_owner->SetColumnWidth( m_column, m_currentX - m_minX ); - SendListEvent(wxEVT_COMMAND_LIST_COL_END_DRAG, event.GetPosition()); - } - else - { - if (x > m_minX + 7) - m_currentX = x; - else - m_currentX = m_minX + 7; - - // draw in the new location - if ( m_currentX < w ) - DrawCurrent(); - } - } - else // not dragging - { - m_minX = 0; - bool hit_border = false; - - // end of the current column - int xpos = 0; - - // find the column where this event occurred - int col, - countCol = m_owner->GetColumnCount(); - for (col = 0; col < countCol; col++) - { - xpos += m_owner->GetColumnWidth( col ); - m_column = col; - - if ( (abs(x-xpos) < 3) && (y < 22) ) - { - // near the column border - hit_border = true; - break; - } - - if ( x < xpos ) - { - // inside the column - break; - } - - m_minX = xpos; - } - - if ( col == countCol ) - m_column = -1; - - if (event.LeftDown() || event.RightUp()) - { - if (hit_border && event.LeftDown()) - { - if ( SendListEvent(wxEVT_COMMAND_LIST_COL_BEGIN_DRAG, - event.GetPosition()) ) - { - m_isDragging = true; - m_currentX = x; - CaptureMouse(); - DrawCurrent(); - } - //else: column resizing was vetoed by the user code - } - else // click on a column - { - // record the selected state of the columns - if (event.LeftDown()) - { - for (int i=0; i < m_owner->GetColumnCount(); i++) - { - wxListItem colItem; - m_owner->GetColumn(i, colItem); - long state = colItem.GetState(); - if (i == m_column) - colItem.SetState(state | wxLIST_STATE_SELECTED); - else - colItem.SetState(state & ~wxLIST_STATE_SELECTED); - m_owner->SetColumn(i, colItem); - } - } - - SendListEvent( event.LeftDown() - ? wxEVT_COMMAND_LIST_COL_CLICK - : wxEVT_COMMAND_LIST_COL_RIGHT_CLICK, - event.GetPosition()); - } - } - else if (event.Moving()) - { - bool setCursor; - if (hit_border) - { - setCursor = m_currentCursor == wxSTANDARD_CURSOR; - m_currentCursor = m_resizeCursor; - } - else - { - setCursor = m_currentCursor != wxSTANDARD_CURSOR; - m_currentCursor = wxSTANDARD_CURSOR; - } - - if ( setCursor ) - SetCursor(*m_currentCursor); - } - } -} - -void wxListHeaderWindow::OnSetFocus( wxFocusEvent &WXUNUSED(event) ) -{ - m_owner->SetFocus(); - m_owner->Update(); -} - -bool wxListHeaderWindow::SendListEvent(wxEventType type, const wxPoint& pos) -{ - wxWindow *parent = GetParent(); - wxListEvent le( type, parent->GetId() ); - le.SetEventObject( parent ); - le.m_pointDrag = pos; - - // the position should be relative to the parent window, not - // this one for compatibility with MSW and common sense: the - // user code doesn't know anything at all about this header - // window, so why should it get positions relative to it? - le.m_pointDrag.y -= GetSize().y; - - le.m_col = m_column; - return !parent->GetEventHandler()->ProcessEvent( le ) || le.IsAllowed(); -} - -//----------------------------------------------------------------------------- -// wxListRenameTimer (internal) -//----------------------------------------------------------------------------- - -wxListRenameTimer::wxListRenameTimer( wxListMainWindow *owner ) -{ - m_owner = owner; -} - -void wxListRenameTimer::Notify() -{ - m_owner->OnRenameTimer(); -} - -//----------------------------------------------------------------------------- -// wxListTextCtrlWrapper (internal) -//----------------------------------------------------------------------------- - -BEGIN_EVENT_TABLE(wxListTextCtrlWrapper, wxEvtHandler) - EVT_CHAR (wxListTextCtrlWrapper::OnChar) - EVT_KEY_UP (wxListTextCtrlWrapper::OnKeyUp) - EVT_KILL_FOCUS (wxListTextCtrlWrapper::OnKillFocus) -END_EVENT_TABLE() - -wxListTextCtrlWrapper::wxListTextCtrlWrapper(wxListMainWindow *owner, - wxTextCtrl *text, - size_t itemEdit) - : m_startValue(owner->GetItemText(itemEdit)), - m_itemEdited(itemEdit) -{ - m_owner = owner; - m_text = text; - m_finished = false; - m_aboutToFinish = false; - - wxRect rectLabel = owner->GetLineLabelRect(itemEdit); - - m_owner->CalcScrolledPosition(rectLabel.x, rectLabel.y, - &rectLabel.x, &rectLabel.y); - - m_text->Create(owner, wxID_ANY, m_startValue, - wxPoint(rectLabel.x-4,rectLabel.y-4), - wxSize(rectLabel.width+11,rectLabel.height+8)); - m_text->SetFocus(); - - m_text->PushEventHandler(this); -} - -void wxListTextCtrlWrapper::Finish() -{ - if ( !m_finished ) - { - m_finished = true; - - m_text->RemoveEventHandler(this); - m_owner->FinishEditing(m_text); - - wxPendingDelete.Append( this ); - } -} - -bool wxListTextCtrlWrapper::AcceptChanges() -{ - const wxString value = m_text->GetValue(); - - // notice that we should always call OnRenameAccept() to generate the "end - // label editing" event, even if the user hasn't really changed anything - if ( !m_owner->OnRenameAccept(m_itemEdited, value) ) - { - // vetoed by the user - return false; - } - - // accepted, do rename the item (unless nothing changed) - if ( value != m_startValue ) - m_owner->SetItemText(m_itemEdited, value); - - return true; -} - -void wxListTextCtrlWrapper::AcceptChangesAndFinish() -{ - m_aboutToFinish = true; - - // Notify the owner about the changes - AcceptChanges(); - - // Even if vetoed, close the control (consistent with MSW) - Finish(); -} - -void wxListTextCtrlWrapper::OnChar( wxKeyEvent &event ) -{ - switch ( event.m_keyCode ) - { - case WXK_RETURN: - AcceptChangesAndFinish(); - break; - - case WXK_ESCAPE: - m_owner->OnRenameCancelled( m_itemEdited ); - Finish(); - break; - - default: - event.Skip(); - } -} - -void wxListTextCtrlWrapper::OnKeyUp( wxKeyEvent &event ) -{ - if (m_finished) - { - event.Skip(); - return; - } - - // auto-grow the textctrl: - wxSize parentSize = m_owner->GetSize(); - wxPoint myPos = m_text->GetPosition(); - wxSize mySize = m_text->GetSize(); - int sx, sy; - m_text->GetTextExtent(m_text->GetValue() + _T("MM"), &sx, &sy); - if (myPos.x + sx > parentSize.x) - sx = parentSize.x - myPos.x; - if (mySize.x > sx) - sx = mySize.x; - m_text->SetSize(sx, wxDefaultCoord); - - event.Skip(); -} - -void wxListTextCtrlWrapper::OnKillFocus( wxFocusEvent &event ) -{ - if ( !m_finished && !m_aboutToFinish ) - { - if ( !AcceptChanges() ) - m_owner->OnRenameCancelled( m_itemEdited ); - - Finish(); - } - - // We must let the native text control handle focus - event.Skip(); -} - -//----------------------------------------------------------------------------- -// wxListMainWindow -//----------------------------------------------------------------------------- - -IMPLEMENT_DYNAMIC_CLASS(wxListMainWindow,wxScrolledWindow) - -BEGIN_EVENT_TABLE(wxListMainWindow,wxScrolledWindow) - EVT_PAINT (wxListMainWindow::OnPaint) - EVT_MOUSE_EVENTS (wxListMainWindow::OnMouse) - EVT_CHAR (wxListMainWindow::OnChar) - EVT_KEY_DOWN (wxListMainWindow::OnKeyDown) - EVT_KEY_UP (wxListMainWindow::OnKeyUp) - EVT_SET_FOCUS (wxListMainWindow::OnSetFocus) - EVT_KILL_FOCUS (wxListMainWindow::OnKillFocus) - EVT_SCROLLWIN (wxListMainWindow::OnScroll) -END_EVENT_TABLE() - -void wxListMainWindow::Init() -{ - m_dirty = true; - m_countVirt = 0; - m_lineFrom = - m_lineTo = (size_t)-1; - m_linesPerPage = 0; - - m_headerWidth = - m_lineHeight = 0; - - m_small_image_list = (wxImageList *) NULL; - m_normal_image_list = (wxImageList *) NULL; - - m_small_spacing = 30; - m_normal_spacing = 40; - - m_hasFocus = false; - m_dragCount = 0; - m_isCreated = false; - - m_lastOnSame = false; - m_renameTimer = new wxListRenameTimer( this ); - m_textctrlWrapper = NULL; - - m_current = - m_lineLastClicked = - m_lineSelectSingleOnUp = - m_lineBeforeLastClicked = (size_t)-1; - - m_freezeCount = 0; -} - -wxListMainWindow::wxListMainWindow() -{ - Init(); - - m_highlightBrush = - m_highlightUnfocusedBrush = (wxBrush *) NULL; -} - -wxListMainWindow::wxListMainWindow( wxWindow *parent, - wxWindowID id, - const wxPoint& pos, - const wxSize& size, - long style, - const wxString &name ) - : wxScrolledWindow( parent, id, pos, size, - style | wxHSCROLL | wxVSCROLL, name ) -{ - Init(); - - m_highlightBrush = new wxBrush - ( - wxSystemSettings::GetColour - ( - wxSYS_COLOUR_HIGHLIGHT - ), - wxSOLID - ); - - m_highlightUnfocusedBrush = new wxBrush - ( - wxSystemSettings::GetColour - ( - wxSYS_COLOUR_BTNSHADOW - ), - wxSOLID - ); - - SetScrollbars( 0, 0, 0, 0, 0, 0 ); - - wxVisualAttributes attr = wxGenericListCtrl::GetClassDefaultAttributes(); - SetOwnForegroundColour( attr.colFg ); - SetOwnBackgroundColour( attr.colBg ); - if (!m_hasFont) - SetOwnFont( attr.font ); -} - -wxListMainWindow::~wxListMainWindow() -{ - DoDeleteAllItems(); - WX_CLEAR_LIST(wxListHeaderDataList, m_columns); - WX_CLEAR_ARRAY(m_aColWidths); - - delete m_highlightBrush; - delete m_highlightUnfocusedBrush; - delete m_renameTimer; -} - -void wxListMainWindow::CacheLineData(size_t line) -{ - wxGenericListCtrl *listctrl = GetListCtrl(); - - wxListLineData *ld = GetDummyLine(); - - size_t countCol = GetColumnCount(); - for ( size_t col = 0; col < countCol; col++ ) - { - ld->SetText(col, listctrl->OnGetItemText(line, col)); - ld->SetImage(col, listctrl->OnGetItemColumnImage(line, col)); - } - - ld->SetAttr(listctrl->OnGetItemAttr(line)); -} - -wxListLineData *wxListMainWindow::GetDummyLine() const -{ - wxASSERT_MSG( !IsEmpty(), _T("invalid line index") ); - wxASSERT_MSG( IsVirtual(), _T("GetDummyLine() shouldn't be called") ); - - wxListMainWindow *self = wxConstCast(this, wxListMainWindow); - - // we need to recreate the dummy line if the number of columns in the - // control changed as it would have the incorrect number of fields - // otherwise - if ( !m_lines.IsEmpty() && - m_lines[0].m_items.GetCount() != (size_t)GetColumnCount() ) - { - self->m_lines.Clear(); - } - - if ( m_lines.IsEmpty() ) - { - wxListLineData *line = new wxListLineData(self); - self->m_lines.Add(line); - - // don't waste extra memory -- there never going to be anything - // else/more in this array - self->m_lines.Shrink(); - } - - return &m_lines[0]; -} - -// ---------------------------------------------------------------------------- -// line geometry (report mode only) -// ---------------------------------------------------------------------------- - -wxCoord wxListMainWindow::GetLineHeight() const -{ - // we cache the line height as calling GetTextExtent() is slow - if ( !m_lineHeight ) - { - wxListMainWindow *self = wxConstCast(this, wxListMainWindow); - - wxClientDC dc( self ); - dc.SetFont( GetFont() ); - - wxCoord y; - dc.GetTextExtent(_T("H"), NULL, &y); - - if ( m_small_image_list && m_small_image_list->GetImageCount() ) - { - int iw = 0, ih = 0; - m_small_image_list->GetSize(0, iw, ih); - y = wxMax(y, ih); - } - - y += EXTRA_HEIGHT; - self->m_lineHeight = y + LINE_SPACING; - } - - return m_lineHeight; -} - -wxCoord wxListMainWindow::GetLineY(size_t line) const -{ - wxASSERT_MSG( InReportView(), _T("only works in report mode") ); - - return LINE_SPACING + line * GetLineHeight(); -} - -wxRect wxListMainWindow::GetLineRect(size_t line) const -{ - if ( !InReportView() ) - return GetLine(line)->m_gi->m_rectAll; - - wxRect rect; - rect.x = HEADER_OFFSET_X; - rect.y = GetLineY(line); - rect.width = GetHeaderWidth(); - rect.height = GetLineHeight(); - - return rect; -} - -wxRect wxListMainWindow::GetLineLabelRect(size_t line) const -{ - if ( !InReportView() ) - return GetLine(line)->m_gi->m_rectLabel; - - int image_x = 0; - wxListLineData *data = GetLine(line); - wxListItemDataList::compatibility_iterator node = data->m_items.GetFirst(); - if (node) - { - wxListItemData *item = node->GetData(); - if ( item->HasImage() ) - { - int ix, iy; - GetImageSize( item->GetImage(), ix, iy ); - image_x = 3 + ix + IMAGE_MARGIN_IN_REPORT_MODE; - } - } - - wxRect rect; - rect.x = image_x + HEADER_OFFSET_X; - rect.y = GetLineY(line); - rect.width = GetColumnWidth(0) - image_x; - rect.height = GetLineHeight(); - - return rect; -} - -wxRect wxListMainWindow::GetLineIconRect(size_t line) const -{ - if ( !InReportView() ) - return GetLine(line)->m_gi->m_rectIcon; - - wxListLineData *ld = GetLine(line); - wxASSERT_MSG( ld->HasImage(), _T("should have an image") ); - - wxRect rect; - rect.x = HEADER_OFFSET_X; - rect.y = GetLineY(line); - GetImageSize(ld->GetImage(), rect.width, rect.height); - - return rect; -} - -wxRect wxListMainWindow::GetLineHighlightRect(size_t line) const -{ - return InReportView() ? GetLineRect(line) - : GetLine(line)->m_gi->m_rectHighlight; -} - -long wxListMainWindow::HitTestLine(size_t line, int x, int y) const -{ - wxASSERT_MSG( line < GetItemCount(), _T("invalid line in HitTestLine") ); - - wxListLineData *ld = GetLine(line); - - if ( ld->HasImage() && GetLineIconRect(line).Contains(x, y) ) - return wxLIST_HITTEST_ONITEMICON; - - // VS: Testing for "ld->HasText() || InReportView()" instead of - // "ld->HasText()" is needed to make empty lines in report view - // possible - if ( ld->HasText() || InReportView() ) - { - wxRect rect = InReportView() ? GetLineRect(line) - : GetLineLabelRect(line); - - if ( rect.Contains(x, y) ) - return wxLIST_HITTEST_ONITEMLABEL; - } - - return 0; -} - -// ---------------------------------------------------------------------------- -// highlight (selection) handling -// ---------------------------------------------------------------------------- - -bool wxListMainWindow::IsHighlighted(size_t line) const -{ - if ( IsVirtual() ) - { - return m_selStore.IsSelected(line); - } - else // !virtual - { - wxListLineData *ld = GetLine(line); - wxCHECK_MSG( ld, false, _T("invalid index in IsHighlighted") ); - - return ld->IsHighlighted(); - } -} - -void wxListMainWindow::HighlightLines( size_t lineFrom, - size_t lineTo, - bool highlight ) -{ - if ( IsVirtual() ) - { - wxArrayInt linesChanged; - if ( !m_selStore.SelectRange(lineFrom, lineTo, highlight, - &linesChanged) ) - { - // meny items changed state, refresh everything - RefreshLines(lineFrom, lineTo); - } - else // only a few items changed state, refresh only them - { - size_t count = linesChanged.GetCount(); - for ( size_t n = 0; n < count; n++ ) - { - RefreshLine(linesChanged[n]); - } - } - } - else // iterate over all items in non report view - { - for ( size_t line = lineFrom; line <= lineTo; line++ ) - { - if ( HighlightLine(line, highlight) ) - RefreshLine(line); - } - } -} - -bool wxListMainWindow::HighlightLine( size_t line, bool highlight ) -{ - bool changed; - - if ( IsVirtual() ) - { - changed = m_selStore.SelectItem(line, highlight); - } - else // !virtual - { - wxListLineData *ld = GetLine(line); - wxCHECK_MSG( ld, false, _T("invalid index in HighlightLine") ); - - changed = ld->Highlight(highlight); - } - - if ( changed ) - { - SendNotify( line, highlight ? wxEVT_COMMAND_LIST_ITEM_SELECTED - : wxEVT_COMMAND_LIST_ITEM_DESELECTED ); - } - - return changed; -} - -void wxListMainWindow::RefreshLine( size_t line ) -{ - if ( InReportView() ) - { - size_t visibleFrom, visibleTo; - GetVisibleLinesRange(&visibleFrom, &visibleTo); - - if ( line < visibleFrom || line > visibleTo ) - return; - } - - wxRect rect = GetLineRect(line); - - CalcScrolledPosition( rect.x, rect.y, &rect.x, &rect.y ); - RefreshRect( rect ); -} - -void wxListMainWindow::RefreshLines( size_t lineFrom, size_t lineTo ) -{ - // we suppose that they are ordered by caller - wxASSERT_MSG( lineFrom <= lineTo, _T("indices in disorder") ); - - wxASSERT_MSG( lineTo < GetItemCount(), _T("invalid line range") ); - - if ( InReportView() ) - { - size_t visibleFrom, visibleTo; - GetVisibleLinesRange(&visibleFrom, &visibleTo); - - if ( lineFrom < visibleFrom ) - lineFrom = visibleFrom; - if ( lineTo > visibleTo ) - lineTo = visibleTo; - - wxRect rect; - rect.x = 0; - rect.y = GetLineY(lineFrom); - rect.width = GetClientSize().x; - rect.height = GetLineY(lineTo) - rect.y + GetLineHeight(); - - CalcScrolledPosition( rect.x, rect.y, &rect.x, &rect.y ); - RefreshRect( rect ); - } - else // !report - { - // TODO: this should be optimized... - for ( size_t line = lineFrom; line <= lineTo; line++ ) - { - RefreshLine(line); - } - } -} - -void wxListMainWindow::RefreshAfter( size_t lineFrom ) -{ - if ( InReportView() ) - { - size_t visibleFrom, visibleTo; - GetVisibleLinesRange(&visibleFrom, &visibleTo); - - if ( lineFrom < visibleFrom ) - lineFrom = visibleFrom; - else if ( lineFrom > visibleTo ) - return; - - wxRect rect; - rect.x = 0; - rect.y = GetLineY(lineFrom); - CalcScrolledPosition( rect.x, rect.y, &rect.x, &rect.y ); - - wxSize size = GetClientSize(); - rect.width = size.x; - - // refresh till the bottom of the window - rect.height = size.y - rect.y; - - RefreshRect( rect ); - } - else // !report - { - // TODO: how to do it more efficiently? - m_dirty = true; - } -} - -void wxListMainWindow::RefreshSelected() -{ - if ( IsEmpty() ) - return; - - size_t from, to; - if ( InReportView() ) - { - GetVisibleLinesRange(&from, &to); - } - else // !virtual - { - from = 0; - to = GetItemCount() - 1; - } - - if ( HasCurrent() && m_current >= from && m_current <= to ) - RefreshLine(m_current); - - for ( size_t line = from; line <= to; line++ ) - { - // NB: the test works as expected even if m_current == -1 - if ( line != m_current && IsHighlighted(line) ) - RefreshLine(line); - } -} - -void wxListMainWindow::Freeze() -{ - m_freezeCount++; -} - -void wxListMainWindow::Thaw() -{ - wxCHECK_RET( m_freezeCount > 0, _T("thawing unfrozen list control?") ); - - if ( --m_freezeCount == 0 ) - Refresh(); -} - -void wxListMainWindow::OnPaint( wxPaintEvent &WXUNUSED(event) ) -{ - // Note: a wxPaintDC must be constructed even if no drawing is - // done (a Windows requirement). - wxPaintDC dc( this ); - - if ( IsEmpty() || m_freezeCount ) - // nothing to draw or not the moment to draw it - return; - - if ( m_dirty ) - // delay the repainting until we calculate all the items positions - return; - - PrepareDC( dc ); - - int dev_x, dev_y; - CalcScrolledPosition( 0, 0, &dev_x, &dev_y ); - - dc.SetFont( GetFont() ); - - if ( InReportView() ) - { - int lineHeight = GetLineHeight(); - - size_t visibleFrom, visibleTo; - GetVisibleLinesRange(&visibleFrom, &visibleTo); - - wxRect rectLine; - int xOrig = dc.LogicalToDeviceX( 0 ); - int yOrig = dc.LogicalToDeviceY( 0 ); - - // tell the caller cache to cache the data - if ( IsVirtual() ) - { - wxListEvent evCache(wxEVT_COMMAND_LIST_CACHE_HINT, - GetParent()->GetId()); - evCache.SetEventObject( GetParent() ); - evCache.m_oldItemIndex = visibleFrom; - evCache.m_itemIndex = visibleTo; - GetParent()->GetEventHandler()->ProcessEvent( evCache ); - } - - for ( size_t line = visibleFrom; line <= visibleTo; line++ ) - { - rectLine = GetLineRect(line); - - - if ( !IsExposed(rectLine.x + xOrig, rectLine.y + yOrig, - rectLine.width, rectLine.height) ) - { - // don't redraw unaffected lines to avoid flicker - continue; - } - - GetLine(line)->DrawInReportMode( &dc, - rectLine, - GetLineHighlightRect(line), - IsHighlighted(line) ); - } - - if ( HasFlag(wxLC_HRULES) ) - { - wxPen pen(GetRuleColour(), 1, wxSOLID); - wxSize clientSize = GetClientSize(); - - size_t i = visibleFrom; - if (i == 0) i = 1; // Don't draw the first one - for ( ; i <= visibleTo; i++ ) - { - dc.SetPen(pen); - dc.SetBrush( *wxTRANSPARENT_BRUSH ); - dc.DrawLine(0 - dev_x, i * lineHeight, - clientSize.x - dev_x, i * lineHeight); - } - - // Draw last horizontal rule - if ( visibleTo == GetItemCount() - 1 ) - { - dc.SetPen( pen ); - dc.SetBrush( *wxTRANSPARENT_BRUSH ); - dc.DrawLine(0 - dev_x, (m_lineTo + 1) * lineHeight, - clientSize.x - dev_x , (m_lineTo + 1) * lineHeight ); - } - } - - // Draw vertical rules if required - if ( HasFlag(wxLC_VRULES) && !IsEmpty() ) - { - wxPen pen(GetRuleColour(), 1, wxSOLID); - wxRect firstItemRect, lastItemRect; - - GetItemRect(visibleFrom, firstItemRect); - GetItemRect(visibleTo, lastItemRect); - int x = firstItemRect.GetX(); - dc.SetPen(pen); - dc.SetBrush(* wxTRANSPARENT_BRUSH); - - for (int col = 0; col < GetColumnCount(); col++) - { - int colWidth = GetColumnWidth(col); - x += colWidth; - int x_pos = x - dev_x; - if (col < GetColumnCount()-1) x_pos -= 2; - dc.DrawLine(x_pos, firstItemRect.GetY() - 1 - dev_y, - x_pos, lastItemRect.GetBottom() + 1 - dev_y); - } - } - } - else // !report - { - size_t count = GetItemCount(); - for ( size_t i = 0; i < count; i++ ) - { - GetLine(i)->Draw( &dc ); - } - } - -#ifndef __WXMAC__ - // Don't draw rect outline under Mac at all. - if ( HasCurrent() ) - { - if ( m_hasFocus ) - { - wxRect rect( GetLineHighlightRect( m_current ) ); -#ifndef __WXGTK20__ - dc.SetPen( *wxBLACK_PEN ); - dc.SetBrush( *wxTRANSPARENT_BRUSH ); - dc.DrawRectangle( rect ); -#else - wxRendererNative::Get().DrawItemSelectionRect( this, dc, rect, wxCONTROL_CURRENT|wxCONTROL_FOCUSED ); - -#endif - } - } -#endif -} - -void wxListMainWindow::HighlightAll( bool on ) -{ - if ( IsSingleSel() ) - { - wxASSERT_MSG( !on, _T("can't do this in a single selection control") ); - - // we just have one item to turn off - if ( HasCurrent() && IsHighlighted(m_current) ) - { - HighlightLine(m_current, false); - RefreshLine(m_current); - } - } - else // multi selection - { - if ( !IsEmpty() ) - HighlightLines(0, GetItemCount() - 1, on); - } -} - -void wxListMainWindow::SendNotify( size_t line, - wxEventType command, - const wxPoint& point ) -{ - wxListEvent le( command, GetParent()->GetId() ); - le.SetEventObject( GetParent() ); - - le.m_itemIndex = line; - - // set only for events which have position - if ( point != wxDefaultPosition ) - le.m_pointDrag = point; - - // don't try to get the line info for virtual list controls: the main - // program has it anyhow and if we did it would result in accessing all - // the lines, even those which are not visible now and this is precisely - // what we're trying to avoid - if ( !IsVirtual() ) - { - if ( line != (size_t)-1 ) - { - GetLine(line)->GetItem( 0, le.m_item ); - } - //else: this happens for wxEVT_COMMAND_LIST_ITEM_FOCUSED event - } - //else: there may be no more such item - - GetParent()->GetEventHandler()->ProcessEvent( le ); -} - -void wxListMainWindow::ChangeCurrent(size_t current) -{ - m_current = current; - - // as the current item changed, we shouldn't start editing it when the - // "slow click" timer expires as the click happened on another item - if ( m_renameTimer->IsRunning() ) - m_renameTimer->Stop(); - - SendNotify(current, wxEVT_COMMAND_LIST_ITEM_FOCUSED); -} - -wxTextCtrl *wxListMainWindow::EditLabel(long item, wxClassInfo* textControlClass) -{ - wxCHECK_MSG( (item >= 0) && ((size_t)item < GetItemCount()), NULL, - wxT("wrong index in wxGenericListCtrl::EditLabel()") ); - - wxASSERT_MSG( textControlClass->IsKindOf(CLASSINFO(wxTextCtrl)), - wxT("EditLabel() needs a text control") ); - - size_t itemEdit = (size_t)item; - - wxListEvent le( wxEVT_COMMAND_LIST_BEGIN_LABEL_EDIT, GetParent()->GetId() ); - le.SetEventObject( GetParent() ); - le.m_itemIndex = item; - wxListLineData *data = GetLine(itemEdit); - wxCHECK_MSG( data, NULL, _T("invalid index in EditLabel()") ); - data->GetItem( 0, le.m_item ); - - if ( GetParent()->GetEventHandler()->ProcessEvent( le ) && !le.IsAllowed() ) - { - // vetoed by user code - return NULL; - } - - // We have to call this here because the label in question might just have - // been added and no screen update taken place. - if ( m_dirty ) - { - wxSafeYield(); - - // Pending events dispatched by wxSafeYield might have changed the item - // count - if ( (size_t)item >= GetItemCount() ) - return NULL; - } - - wxTextCtrl * const text = (wxTextCtrl *)textControlClass->CreateObject(); - m_textctrlWrapper = new wxListTextCtrlWrapper(this, text, item); - return m_textctrlWrapper->GetText(); -} - -void wxListMainWindow::OnRenameTimer() -{ - wxCHECK_RET( HasCurrent(), wxT("unexpected rename timer") ); - - EditLabel( m_current ); -} - -bool wxListMainWindow::OnRenameAccept(size_t itemEdit, const wxString& value) -{ - wxListEvent le( wxEVT_COMMAND_LIST_END_LABEL_EDIT, GetParent()->GetId() ); - le.SetEventObject( GetParent() ); - le.m_itemIndex = itemEdit; - - wxListLineData *data = GetLine(itemEdit); - - wxCHECK_MSG( data, false, _T("invalid index in OnRenameAccept()") ); - - data->GetItem( 0, le.m_item ); - le.m_item.m_text = value; - return !GetParent()->GetEventHandler()->ProcessEvent( le ) || - le.IsAllowed(); -} - -void wxListMainWindow::OnRenameCancelled(size_t itemEdit) -{ - // let owner know that the edit was cancelled - wxListEvent le( wxEVT_COMMAND_LIST_END_LABEL_EDIT, GetParent()->GetId() ); - - le.SetEditCanceled(true); - - le.SetEventObject( GetParent() ); - le.m_itemIndex = itemEdit; - - wxListLineData *data = GetLine(itemEdit); - wxCHECK_RET( data, _T("invalid index in OnRenameCancelled()") ); - - data->GetItem( 0, le.m_item ); - GetEventHandler()->ProcessEvent( le ); -} - -void wxListMainWindow::OnMouse( wxMouseEvent &event ) -{ - -#ifdef __WXMAC__ - // On wxMac we can't depend on the EVT_KILL_FOCUS event to properly - // shutdown the edit control when the mouse is clicked elsewhere on the - // listctrl because the order of events is different (or something like - // that), so explicitly end the edit if it is active. - if ( event.LeftDown() && m_textctrlWrapper ) - m_textctrlWrapper->AcceptChangesAndFinish(); -#endif // __WXMAC__ - - if ( event.LeftDown() ) - SetFocusIgnoringChildren(); - - event.SetEventObject( GetParent() ); - if ( GetParent()->GetEventHandler()->ProcessEvent( event) ) - return; - - if (event.GetEventType() == wxEVT_MOUSEWHEEL) - { - // let the base handle mouse wheel events. - event.Skip(); - return; - } - - if ( !HasCurrent() || IsEmpty() ) - { - if (event.RightDown()) - { - SendNotify( (size_t)-1, wxEVT_COMMAND_LIST_ITEM_RIGHT_CLICK, event.GetPosition() ); - // Allow generation of context menu event - event.Skip(); - } - return; - } - - if (m_dirty) - return; - - if ( !(event.Dragging() || event.ButtonDown() || event.LeftUp() || - event.ButtonDClick()) ) - return; - - int x = event.GetX(); - int y = event.GetY(); - CalcUnscrolledPosition( x, y, &x, &y ); - - // where did we hit it (if we did)? - long hitResult = 0; - - size_t count = GetItemCount(), - current; - - if ( InReportView() ) - { - current = y / GetLineHeight(); - if ( current < count ) - hitResult = HitTestLine(current, x, y); - } - else // !report - { - // TODO: optimize it too! this is less simple than for report view but - // enumerating all items is still not a way to do it!! - for ( current = 0; current < count; current++ ) - { - hitResult = HitTestLine(current, x, y); - if ( hitResult ) - break; - } - } - - if (event.Dragging()) - { - if (m_dragCount == 0) - { - // we have to report the raw, physical coords as we want to be - // able to call HitTest(event.m_pointDrag) from the user code to - // get the item being dragged - m_dragStart = event.GetPosition(); - } - - m_dragCount++; - - if (m_dragCount != 3) - return; - - int command = event.RightIsDown() ? wxEVT_COMMAND_LIST_BEGIN_RDRAG - : wxEVT_COMMAND_LIST_BEGIN_DRAG; - - wxListEvent le( command, GetParent()->GetId() ); - le.SetEventObject( GetParent() ); - le.m_itemIndex = m_lineLastClicked; - le.m_pointDrag = m_dragStart; - GetParent()->GetEventHandler()->ProcessEvent( le ); - - return; - } - else - { - m_dragCount = 0; - } - - if ( !hitResult ) - { - // outside of any item - if (event.RightDown()) - { - SendNotify( (size_t) -1, wxEVT_COMMAND_LIST_ITEM_RIGHT_CLICK, event.GetPosition() ); - - wxContextMenuEvent evtCtx( - wxEVT_CONTEXT_MENU, - GetParent()->GetId(), - ClientToScreen(event.GetPosition())); - evtCtx.SetEventObject(GetParent()); - GetParent()->GetEventHandler()->ProcessEvent(evtCtx); - } - else - { - // reset the selection and bail out - HighlightAll(false); - } - - return; - } - - bool forceClick = false; - if (event.ButtonDClick()) - { - if ( m_renameTimer->IsRunning() ) - m_renameTimer->Stop(); - - m_lastOnSame = false; - - if ( current == m_lineLastClicked ) - { - SendNotify( current, wxEVT_COMMAND_LIST_ITEM_ACTIVATED ); - - return; - } - else - { - // The first click was on another item, so don't interpret this as - // a double click, but as a simple click instead - forceClick = true; - } - } - - if (event.LeftUp()) - { - if (m_lineSelectSingleOnUp != (size_t)-1) - { - // select single line - HighlightAll( false ); - ReverseHighlight(m_lineSelectSingleOnUp); - } - - if (m_lastOnSame) - { - if ((current == m_current) && - (hitResult == wxLIST_HITTEST_ONITEMLABEL) && - HasFlag(wxLC_EDIT_LABELS) ) - { - if (InReportView()) - { - wxRect label = GetLineLabelRect( current ); - if (label.Contains( x, y )) - m_renameTimer->Start( 250, true ); - - } - else - m_renameTimer->Start( 250, true ); - } - } - - m_lastOnSame = false; - m_lineSelectSingleOnUp = (size_t)-1; - } - else - { - // This is necessary, because after a DnD operation in - // from and to ourself, the up event is swallowed by the - // DnD code. So on next non-up event (which means here and - // now) m_lineSelectSingleOnUp should be reset. - m_lineSelectSingleOnUp = (size_t)-1; - } - if (event.RightDown()) - { - m_lineBeforeLastClicked = m_lineLastClicked; - m_lineLastClicked = current; - - // If the item is already selected, do not update the selection. - // Multi-selections should not be cleared if a selected item is clicked. - if (!IsHighlighted(current)) - { - HighlightAll(false); - ChangeCurrent(current); - ReverseHighlight(m_current); - } - - SendNotify( current, wxEVT_COMMAND_LIST_ITEM_RIGHT_CLICK, event.GetPosition() ); - - wxContextMenuEvent evtCtx( - wxEVT_CONTEXT_MENU, - GetParent()->GetId(), - ClientToScreen(event.GetPosition())); - evtCtx.SetEventObject(GetParent()); - GetParent()->GetEventHandler()->ProcessEvent(evtCtx); - } - else if (event.MiddleDown()) - { - SendNotify( current, wxEVT_COMMAND_LIST_ITEM_MIDDLE_CLICK ); - } - else if ( event.LeftDown() || forceClick ) - { - m_lineBeforeLastClicked = m_lineLastClicked; - m_lineLastClicked = current; - - size_t oldCurrent = m_current; - bool oldWasSelected = IsHighlighted(m_current); - - bool cmdModifierDown = event.CmdDown(); - if ( IsSingleSel() || !(cmdModifierDown || event.ShiftDown()) ) - { - if ( IsSingleSel() || !IsHighlighted(current) ) - { - HighlightAll( false ); - - ChangeCurrent(current); - - ReverseHighlight(m_current); - } - else // multi sel & current is highlighted & no mod keys - { - m_lineSelectSingleOnUp = current; - ChangeCurrent(current); // change focus - } - } - else // multi sel & either ctrl or shift is down - { - if (cmdModifierDown) - { - ChangeCurrent(current); - - ReverseHighlight(m_current); - } - else if (event.ShiftDown()) - { - ChangeCurrent(current); - - size_t lineFrom = oldCurrent, - lineTo = current; - - if ( lineTo < lineFrom ) - { - lineTo = lineFrom; - lineFrom = m_current; - } - - HighlightLines(lineFrom, lineTo); - } - else // !ctrl, !shift - { - // test in the enclosing if should make it impossible - wxFAIL_MSG( _T("how did we get here?") ); - } - } - - if (m_current != oldCurrent) - RefreshLine( oldCurrent ); - - // forceClick is only set if the previous click was on another item - m_lastOnSame = !forceClick && (m_current == oldCurrent) && oldWasSelected; - } -} - -void wxListMainWindow::MoveToItem(size_t item) -{ - if ( item == (size_t)-1 ) - return; - - wxRect rect = GetLineRect(item); - - int client_w, client_h; - GetClientSize( &client_w, &client_h ); - - const int hLine = GetLineHeight(); - - int view_x = SCROLL_UNIT_X * GetScrollPos( wxHORIZONTAL ); - int view_y = hLine * GetScrollPos( wxVERTICAL ); - - if ( InReportView() ) - { - // the next we need the range of lines shown it might be different, - // so recalculate it - ResetVisibleLinesRange(); - - if (rect.y < view_y) - Scroll( -1, rect.y / hLine ); - if (rect.y + rect.height + 5 > view_y + client_h) - Scroll( -1, (rect.y + rect.height - client_h + hLine) / hLine ); - -#ifdef __WXMAC__ - // At least on Mac the visible lines value will get reset inside of - // Scroll *before* it actually scrolls the window because of the - // Update() that happens there, so it will still have the wrong value. - // So let's reset it again and wait for it to be recalculated in the - // next paint event. I would expect this problem to show up in wxGTK - // too but couldn't duplicate it there. Perhaps the order of events - // is different... --Robin - ResetVisibleLinesRange(); -#endif - } - else // !report - { - int sx = -1, - sy = -1; - - if (rect.x-view_x < 5) - sx = (rect.x - 5) / SCROLL_UNIT_X; - if (rect.x + rect.width - 5 > view_x + client_w) - sx = (rect.x + rect.width - client_w + SCROLL_UNIT_X) / SCROLL_UNIT_X; - - if (rect.y-view_y < 5) - sy = (rect.y - 5) / hLine; - if (rect.y + rect.height - 5 > view_y + client_h) - sy = (rect.y + rect.height - client_h + hLine) / hLine; - - Scroll(sx, sy); - } -} - -bool wxListMainWindow::ScrollList(int WXUNUSED(dx), int dy) -{ - if ( !InReportView() ) - { - // TODO: this should work in all views but is not implemented now - return false; - } - - size_t top, bottom; - GetVisibleLinesRange(&top, &bottom); - - if ( bottom == (size_t)-1 ) - return 0; - - ResetVisibleLinesRange(); - - int hLine = GetLineHeight(); - - Scroll(-1, top + dy / hLine); - -#ifdef __WXMAC__ - // see comment in MoveToItem() for why we do this - ResetVisibleLinesRange(); -#endif - - return true; -} - -// ---------------------------------------------------------------------------- -// keyboard handling -// ---------------------------------------------------------------------------- - -void wxListMainWindow::OnArrowChar(size_t newCurrent, const wxKeyEvent& event) -{ - wxCHECK_RET( newCurrent < (size_t)GetItemCount(), - _T("invalid item index in OnArrowChar()") ); - - size_t oldCurrent = m_current; - - // in single selection we just ignore Shift as we can't select several - // items anyhow - if ( event.ShiftDown() && !IsSingleSel() ) - { - ChangeCurrent(newCurrent); - - // refresh the old focus to remove it - RefreshLine( oldCurrent ); - - // select all the items between the old and the new one - if ( oldCurrent > newCurrent ) - { - newCurrent = oldCurrent; - oldCurrent = m_current; - } - - HighlightLines(oldCurrent, newCurrent); - } - else // !shift - { - // all previously selected items are unselected unless ctrl is held - // in a multiselection control - if ( !event.ControlDown() || IsSingleSel() ) - HighlightAll(false); - - ChangeCurrent(newCurrent); - - // refresh the old focus to remove it - RefreshLine( oldCurrent ); - - // in single selection mode we must always have a selected item - if ( !event.ControlDown() || IsSingleSel() ) - HighlightLine( m_current, true ); - } - - RefreshLine( m_current ); - - MoveToFocus(); -} - -void wxListMainWindow::OnKeyDown( wxKeyEvent &event ) -{ - wxWindow *parent = GetParent(); - - // propagate the key event upwards - wxKeyEvent ke( wxEVT_KEY_DOWN ); - ke.m_shiftDown = event.m_shiftDown; - ke.m_controlDown = event.m_controlDown; - ke.m_altDown = event.m_altDown; - ke.m_metaDown = event.m_metaDown; - ke.m_keyCode = event.m_keyCode; - ke.m_x = event.m_x; - ke.m_y = event.m_y; - ke.SetEventObject( parent ); - if (parent->GetEventHandler()->ProcessEvent( ke )) return; - - event.Skip(); -} - -void wxListMainWindow::OnKeyUp( wxKeyEvent &event ) -{ - wxWindow *parent = GetParent(); - - // propagate the key event upwards - wxKeyEvent ke( wxEVT_KEY_UP ); - ke.m_shiftDown = event.m_shiftDown; - ke.m_controlDown = event.m_controlDown; - ke.m_altDown = event.m_altDown; - ke.m_metaDown = event.m_metaDown; - ke.m_keyCode = event.m_keyCode; - ke.m_x = event.m_x; - ke.m_y = event.m_y; - ke.SetEventObject( parent ); - if (parent->GetEventHandler()->ProcessEvent( ke )) return; - - event.Skip(); -} - -void wxListMainWindow::OnChar( wxKeyEvent &event ) -{ - wxWindow *parent = GetParent(); - - // send a list_key event up - if ( HasCurrent() ) - { - wxListEvent le( wxEVT_COMMAND_LIST_KEY_DOWN, GetParent()->GetId() ); - le.m_itemIndex = m_current; - GetLine(m_current)->GetItem( 0, le.m_item ); - le.m_code = event.GetKeyCode(); - le.SetEventObject( parent ); - parent->GetEventHandler()->ProcessEvent( le ); - } - - // propagate the char event upwards - wxKeyEvent ke( wxEVT_CHAR ); - ke.m_shiftDown = event.m_shiftDown; - ke.m_controlDown = event.m_controlDown; - ke.m_altDown = event.m_altDown; - ke.m_metaDown = event.m_metaDown; - ke.m_keyCode = event.m_keyCode; - ke.m_x = event.m_x; - ke.m_y = event.m_y; - ke.SetEventObject( parent ); - if (parent->GetEventHandler()->ProcessEvent( ke )) return; - - if (event.GetKeyCode() == WXK_TAB) - { - wxNavigationKeyEvent nevent; - nevent.SetWindowChange( event.ControlDown() ); - nevent.SetDirection( !event.ShiftDown() ); - nevent.SetEventObject( GetParent()->GetParent() ); - nevent.SetCurrentFocus( m_parent ); - if (GetParent()->GetParent()->GetEventHandler()->ProcessEvent( nevent )) - return; - } - - // no item -> nothing to do - if (!HasCurrent()) - { - event.Skip(); - return; - } - - // don't use m_linesPerPage directly as it might not be computed yet - const int pageSize = GetCountPerPage(); - wxCHECK_RET( pageSize, _T("should have non zero page size") ); - - if (GetLayoutDirection() == wxLayout_RightToLeft) - { - if (event.GetKeyCode() == WXK_RIGHT) - event.m_keyCode = WXK_LEFT; - else if (event.GetKeyCode() == WXK_LEFT) - event.m_keyCode = WXK_RIGHT; - } - - switch ( event.GetKeyCode() ) - { - case WXK_UP: - if ( m_current > 0 ) - OnArrowChar( m_current - 1, event ); - break; - - case WXK_DOWN: - if ( m_current < (size_t)GetItemCount() - 1 ) - OnArrowChar( m_current + 1, event ); - break; - - case WXK_END: - if (!IsEmpty()) - OnArrowChar( GetItemCount() - 1, event ); - break; - - case WXK_HOME: - if (!IsEmpty()) - OnArrowChar( 0, event ); - break; - - case WXK_PAGEUP: - { - int steps = InReportView() ? pageSize - 1 - : m_current % pageSize; - - int index = m_current - steps; - if (index < 0) - index = 0; - - OnArrowChar( index, event ); - } - break; - - case WXK_PAGEDOWN: - { - int steps = InReportView() - ? pageSize - 1 - : pageSize - (m_current % pageSize) - 1; - - size_t index = m_current + steps; - size_t count = GetItemCount(); - if ( index >= count ) - index = count - 1; - - OnArrowChar( index, event ); - } - break; - - case WXK_LEFT: - if ( !InReportView() ) - { - int index = m_current - pageSize; - if (index < 0) - index = 0; - - OnArrowChar( index, event ); - } - break; - - case WXK_RIGHT: - if ( !InReportView() ) - { - size_t index = m_current + pageSize; - - size_t count = GetItemCount(); - if ( index >= count ) - index = count - 1; - - OnArrowChar( index, event ); - } - break; - - case WXK_SPACE: - if ( IsSingleSel() ) - { - if ( event.ControlDown() ) - { - ReverseHighlight(m_current); - } - else // normal space press - { - SendNotify( m_current, wxEVT_COMMAND_LIST_ITEM_ACTIVATED ); - } - } - else // multiple selection - { - ReverseHighlight(m_current); - } - break; - - case WXK_RETURN: - case WXK_EXECUTE: - SendNotify( m_current, wxEVT_COMMAND_LIST_ITEM_ACTIVATED ); - break; - - default: - event.Skip(); - } -} - -// ---------------------------------------------------------------------------- -// focus handling -// ---------------------------------------------------------------------------- - -void wxListMainWindow::OnSetFocus( wxFocusEvent &WXUNUSED(event) ) -{ - if ( GetParent() ) - { - wxFocusEvent event( wxEVT_SET_FOCUS, GetParent()->GetId() ); - event.SetEventObject( GetParent() ); - if ( GetParent()->GetEventHandler()->ProcessEvent( event) ) - return; - } - - // wxGTK sends us EVT_SET_FOCUS events even if we had never got - // EVT_KILL_FOCUS before which means that we finish by redrawing the items - // which are already drawn correctly resulting in horrible flicker - avoid - // it - if ( !m_hasFocus ) - { - m_hasFocus = true; - - RefreshSelected(); - } -} - -void wxListMainWindow::OnKillFocus( wxFocusEvent &WXUNUSED(event) ) -{ - if ( GetParent() ) - { - wxFocusEvent event( wxEVT_KILL_FOCUS, GetParent()->GetId() ); - event.SetEventObject( GetParent() ); - if ( GetParent()->GetEventHandler()->ProcessEvent( event) ) - return; - } - - m_hasFocus = false; - RefreshSelected(); -} - -void wxListMainWindow::DrawImage( int index, wxDC *dc, int x, int y ) -{ - if ( HasFlag(wxLC_ICON) && (m_normal_image_list)) - { - m_normal_image_list->Draw( index, *dc, x, y, wxIMAGELIST_DRAW_TRANSPARENT ); - } - else if ( HasFlag(wxLC_SMALL_ICON) && (m_small_image_list)) - { - m_small_image_list->Draw( index, *dc, x, y, wxIMAGELIST_DRAW_TRANSPARENT ); - } - else if ( HasFlag(wxLC_LIST) && (m_small_image_list)) - { - m_small_image_list->Draw( index, *dc, x, y, wxIMAGELIST_DRAW_TRANSPARENT ); - } - else if ( InReportView() && (m_small_image_list)) - { - m_small_image_list->Draw( index, *dc, x, y, wxIMAGELIST_DRAW_TRANSPARENT ); - } -} - -void wxListMainWindow::GetImageSize( int index, int &width, int &height ) const -{ - if ( HasFlag(wxLC_ICON) && m_normal_image_list ) - { - m_normal_image_list->GetSize( index, width, height ); - } - else if ( HasFlag(wxLC_SMALL_ICON) && m_small_image_list ) - { - m_small_image_list->GetSize( index, width, height ); - } - else if ( HasFlag(wxLC_LIST) && m_small_image_list ) - { - m_small_image_list->GetSize( index, width, height ); - } - else if ( InReportView() && m_small_image_list ) - { - m_small_image_list->GetSize( index, width, height ); - } - else - { - width = - height = 0; - } -} - -int wxListMainWindow::GetTextLength( const wxString &s ) const -{ - wxClientDC dc( wxConstCast(this, wxListMainWindow) ); - dc.SetFont( GetFont() ); - - wxCoord lw; - dc.GetTextExtent( s, &lw, NULL ); - - return lw + AUTOSIZE_COL_MARGIN; -} - -void wxListMainWindow::SetImageList( wxImageList *imageList, int which ) -{ - m_dirty = true; - - // calc the spacing from the icon size - int width = 0, height = 0; - - if ((imageList) && (imageList->GetImageCount()) ) - imageList->GetSize(0, width, height); - - if (which == wxIMAGE_LIST_NORMAL) - { - m_normal_image_list = imageList; - m_normal_spacing = width + 8; - } - - if (which == wxIMAGE_LIST_SMALL) - { - m_small_image_list = imageList; - m_small_spacing = width + 14; - m_lineHeight = 0; // ensure that the line height will be recalc'd - } -} - -void wxListMainWindow::SetItemSpacing( int spacing, bool isSmall ) -{ - m_dirty = true; - if (isSmall) - m_small_spacing = spacing; - else - m_normal_spacing = spacing; -} - -int wxListMainWindow::GetItemSpacing( bool isSmall ) -{ - return isSmall ? m_small_spacing : m_normal_spacing; -} - -// ---------------------------------------------------------------------------- -// columns -// ---------------------------------------------------------------------------- - -void wxListMainWindow::SetColumn( int col, wxListItem &item ) -{ - wxListHeaderDataList::compatibility_iterator node = m_columns.Item( col ); - - wxCHECK_RET( node, _T("invalid column index in SetColumn") ); - - if ( item.m_width == wxLIST_AUTOSIZE_USEHEADER ) - item.m_width = GetTextLength( item.m_text ); - - wxListHeaderData *column = node->GetData(); - column->SetItem( item ); - - wxListHeaderWindow *headerWin = GetListCtrl()->m_headerWin; - if ( headerWin ) - headerWin->m_dirty = true; - - m_dirty = true; - - // invalidate it as it has to be recalculated - m_headerWidth = 0; -} - -void wxListMainWindow::SetColumnWidth( int col, int width ) -{ - wxCHECK_RET( col >= 0 && col < GetColumnCount(), - _T("invalid column index") ); - - wxCHECK_RET( InReportView(), - _T("SetColumnWidth() can only be called in report mode.") ); - - m_dirty = true; - wxListHeaderWindow *headerWin = GetListCtrl()->m_headerWin; - if ( headerWin ) - headerWin->m_dirty = true; - - wxListHeaderDataList::compatibility_iterator node = m_columns.Item( col ); - wxCHECK_RET( node, _T("no column?") ); - - wxListHeaderData *column = node->GetData(); - - size_t count = GetItemCount(); - - if (width == wxLIST_AUTOSIZE_USEHEADER) - { - width = GetTextLength(column->GetText()); - width += 2*EXTRA_WIDTH; - - // check for column header's image availability - const int image = column->GetImage(); - if ( image != -1 ) - { - if ( m_small_image_list ) - { - int ix = 0, iy = 0; - m_small_image_list->GetSize(image, ix, iy); - width += ix + HEADER_IMAGE_MARGIN_IN_REPORT_MODE; - } - } - } - else if ( width == wxLIST_AUTOSIZE ) - { - if ( IsVirtual() ) - { - // TODO: determine the max width somehow... - width = WIDTH_COL_DEFAULT; - } - else // !virtual - { - wxClientDC dc(this); - dc.SetFont( GetFont() ); - - int max = AUTOSIZE_COL_MARGIN; - - // if the cached column width isn't valid then recalculate it - if (m_aColWidths.Item(col)->bNeedsUpdate) - { - for (size_t i = 0; i < count; i++) - { - wxListLineData *line = GetLine( i ); - wxListItemDataList::compatibility_iterator n = line->m_items.Item( col ); - - wxCHECK_RET( n, _T("no subitem?") ); - - wxListItemData *itemData = n->GetData(); - wxListItem item; - - itemData->GetItem(item); - int itemWidth = GetItemWidthWithImage(&item); - if (itemWidth > max) - max = itemWidth; - } - - m_aColWidths.Item(col)->bNeedsUpdate = false; - m_aColWidths.Item(col)->nMaxWidth = max; - } - - max = m_aColWidths.Item(col)->nMaxWidth; - width = max + AUTOSIZE_COL_MARGIN; - } - } - - column->SetWidth( width ); - - // invalidate it as it has to be recalculated - m_headerWidth = 0; -} - -int wxListMainWindow::GetHeaderWidth() const -{ - if ( !m_headerWidth ) - { - wxListMainWindow *self = wxConstCast(this, wxListMainWindow); - - size_t count = GetColumnCount(); - for ( size_t col = 0; col < count; col++ ) - { - self->m_headerWidth += GetColumnWidth(col); - } - } - - return m_headerWidth; -} - -void wxListMainWindow::GetColumn( int col, wxListItem &item ) const -{ - wxListHeaderDataList::compatibility_iterator node = m_columns.Item( col ); - wxCHECK_RET( node, _T("invalid column index in GetColumn") ); - - wxListHeaderData *column = node->GetData(); - column->GetItem( item ); -} - -int wxListMainWindow::GetColumnWidth( int col ) const -{ - wxListHeaderDataList::compatibility_iterator node = m_columns.Item( col ); - wxCHECK_MSG( node, 0, _T("invalid column index") ); - - wxListHeaderData *column = node->GetData(); - return column->GetWidth(); -} - -// ---------------------------------------------------------------------------- -// item state -// ---------------------------------------------------------------------------- - -void wxListMainWindow::SetItem( wxListItem &item ) -{ - long id = item.m_itemId; - wxCHECK_RET( id >= 0 && (size_t)id < GetItemCount(), - _T("invalid item index in SetItem") ); - - if ( !IsVirtual() ) - { - wxListLineData *line = GetLine((size_t)id); - line->SetItem( item.m_col, item ); - - // Set item state if user wants - if ( item.m_mask & wxLIST_MASK_STATE ) - SetItemState( item.m_itemId, item.m_state, item.m_state ); - - if (InReportView()) - { - // update the Max Width Cache if needed - int width = GetItemWidthWithImage(&item); - - if (width > m_aColWidths.Item(item.m_col)->nMaxWidth) - m_aColWidths.Item(item.m_col)->nMaxWidth = width; - } - } - - // update the item on screen - wxRect rectItem; - GetItemRect(id, rectItem); - RefreshRect(rectItem); -} - -void wxListMainWindow::SetItemStateAll(long state, long stateMask) -{ - if ( IsEmpty() ) - return; - - // first deal with selection - if ( stateMask & wxLIST_STATE_SELECTED ) - { - // set/clear select state - if ( IsVirtual() ) - { - // optimized version for virtual listctrl. - m_selStore.SelectRange(0, GetItemCount() - 1, state == wxLIST_STATE_SELECTED); - Refresh(); - } - else if ( state & wxLIST_STATE_SELECTED ) - { - const long count = GetItemCount(); - for( long i = 0; i < count; i++ ) - { - SetItemState( i, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED ); - } - - } - else - { - // clear for non virtual (somewhat optimized by using GetNextItem()) - long i = -1; - while ( (i = GetNextItem(i, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED)) != -1 ) - { - SetItemState( i, 0, wxLIST_STATE_SELECTED ); - } - } - } - - if ( HasCurrent() && (state == 0) && (stateMask & wxLIST_STATE_FOCUSED) ) - { - // unfocus all: only one item can be focussed, so clearing focus for - // all items is simply clearing focus of the focussed item. - SetItemState(m_current, state, stateMask); - } - //(setting focus to all items makes no sense, so it is not handled here.) -} - -void wxListMainWindow::SetItemState( long litem, long state, long stateMask ) -{ - if ( litem == -1 ) - { - SetItemStateAll(state, stateMask); - return; - } - - wxCHECK_RET( litem >= 0 && (size_t)litem < GetItemCount(), - _T("invalid list ctrl item index in SetItem") ); - - size_t oldCurrent = m_current; - size_t item = (size_t)litem; // safe because of the check above - - // do we need to change the focus? - if ( stateMask & wxLIST_STATE_FOCUSED ) - { - if ( state & wxLIST_STATE_FOCUSED ) - { - // don't do anything if this item is already focused - if ( item != m_current ) - { - ChangeCurrent(item); - - if ( oldCurrent != (size_t)-1 ) - { - if ( IsSingleSel() ) - { - HighlightLine(oldCurrent, false); - } - - RefreshLine(oldCurrent); - } - - RefreshLine( m_current ); - } - } - else // unfocus - { - // don't do anything if this item is not focused - if ( item == m_current ) - { - ResetCurrent(); - - if ( IsSingleSel() ) - { - // we must unselect the old current item as well or we - // might end up with more than one selected item in a - // single selection control - HighlightLine(oldCurrent, false); - } - - RefreshLine( oldCurrent ); - } - } - } - - // do we need to change the selection state? - if ( stateMask & wxLIST_STATE_SELECTED ) - { - bool on = (state & wxLIST_STATE_SELECTED) != 0; - - if ( IsSingleSel() ) - { - if ( on ) - { - // selecting the item also makes it the focused one in the - // single sel mode - if ( m_current != item ) - { - ChangeCurrent(item); - - if ( oldCurrent != (size_t)-1 ) - { - HighlightLine( oldCurrent, false ); - RefreshLine( oldCurrent ); - } - } - } - else // off - { - // only the current item may be selected anyhow - if ( item != m_current ) - return; - } - } - - if ( HighlightLine(item, on) ) - { - RefreshLine(item); - } - } -} - -int wxListMainWindow::GetItemState( long item, long stateMask ) const -{ - wxCHECK_MSG( item >= 0 && (size_t)item < GetItemCount(), 0, - _T("invalid list ctrl item index in GetItemState()") ); - - int ret = wxLIST_STATE_DONTCARE; - - if ( stateMask & wxLIST_STATE_FOCUSED ) - { - if ( (size_t)item == m_current ) - ret |= wxLIST_STATE_FOCUSED; - } - - if ( stateMask & wxLIST_STATE_SELECTED ) - { - if ( IsHighlighted(item) ) - ret |= wxLIST_STATE_SELECTED; - } - - return ret; -} - -void wxListMainWindow::GetItem( wxListItem &item ) const -{ - wxCHECK_RET( item.m_itemId >= 0 && (size_t)item.m_itemId < GetItemCount(), - _T("invalid item index in GetItem") ); - - wxListLineData *line = GetLine((size_t)item.m_itemId); - line->GetItem( item.m_col, item ); - - // Get item state if user wants it - if ( item.m_mask & wxLIST_MASK_STATE ) - item.m_state = GetItemState( item.m_itemId, wxLIST_STATE_SELECTED | - wxLIST_STATE_FOCUSED ); -} - -// ---------------------------------------------------------------------------- -// item count -// ---------------------------------------------------------------------------- - -size_t wxListMainWindow::GetItemCount() const -{ - return IsVirtual() ? m_countVirt : m_lines.GetCount(); -} - -void wxListMainWindow::SetItemCount(long count) -{ - m_selStore.SetItemCount(count); - m_countVirt = count; - - ResetVisibleLinesRange(); - - // scrollbars must be reset - m_dirty = true; -} - -int wxListMainWindow::GetSelectedItemCount() const -{ - // deal with the quick case first - if ( IsSingleSel() ) - return HasCurrent() ? IsHighlighted(m_current) : false; - - // virtual controls remmebers all its selections itself - if ( IsVirtual() ) - return m_selStore.GetSelectedCount(); - - // TODO: we probably should maintain the number of items selected even for - // non virtual controls as enumerating all lines is really slow... - size_t countSel = 0; - size_t count = GetItemCount(); - for ( size_t line = 0; line < count; line++ ) - { - if ( GetLine(line)->IsHighlighted() ) - countSel++; - } - - return countSel; -} - -// ---------------------------------------------------------------------------- -// item position/size -// ---------------------------------------------------------------------------- - -wxRect wxListMainWindow::GetViewRect() const -{ - wxASSERT_MSG( !HasFlag(wxLC_REPORT | wxLC_LIST), - _T("wxListCtrl::GetViewRect() only works in icon mode") ); - - // we need to find the longest/tallest label - wxCoord xMax = 0, yMax = 0; - const int count = GetItemCount(); - if ( count ) - { - for ( int i = 0; i < count; i++ ) - { - wxRect r; - GetItemRect(i, r); - - wxCoord x = r.GetRight(), - y = r.GetBottom(); - - if ( x > xMax ) - xMax = x; - if ( y > yMax ) - yMax = y; - } - } - - // some fudge needed to make it look prettier - xMax += 2 * EXTRA_BORDER_X; - yMax += 2 * EXTRA_BORDER_Y; - - // account for the scrollbars if necessary - const wxSize sizeAll = GetClientSize(); - if ( xMax > sizeAll.x ) - yMax += wxSystemSettings::GetMetric(wxSYS_HSCROLL_Y); - if ( yMax > sizeAll.y ) - xMax += wxSystemSettings::GetMetric(wxSYS_VSCROLL_X); - - return wxRect(0, 0, xMax, yMax); -} - -void wxListMainWindow::GetItemRect( long index, wxRect &rect ) const -{ - wxCHECK_RET( index >= 0 && (size_t)index < GetItemCount(), - _T("invalid index in GetItemRect") ); - - // ensure that we're laid out, otherwise we could return nonsense - if ( m_dirty ) - { - wxConstCast(this, wxListMainWindow)-> - RecalculatePositions(true /* no refresh */); - } - - rect = GetLineRect((size_t)index); - - CalcScrolledPosition(rect.x, rect.y, &rect.x, &rect.y); -} - -bool wxListMainWindow::GetItemPosition(long item, wxPoint& pos) const -{ - wxRect rect; - GetItemRect(item, rect); - - pos.x = rect.x; - pos.y = rect.y; - - return true; -} - -// ---------------------------------------------------------------------------- -// geometry calculation -// ---------------------------------------------------------------------------- - -void wxListMainWindow::RecalculatePositions(bool noRefresh) -{ - const int lineHeight = GetLineHeight(); - - wxClientDC dc( this ); - dc.SetFont( GetFont() ); - - const size_t count = GetItemCount(); - - int iconSpacing; - if ( HasFlag(wxLC_ICON) ) - iconSpacing = m_normal_spacing; - else if ( HasFlag(wxLC_SMALL_ICON) ) - iconSpacing = m_small_spacing; - else - iconSpacing = 0; - - // Note that we do not call GetClientSize() here but - // GetSize() and subtract the border size for sunken - // borders manually. This is technically incorrect, - // but we need to know the client area's size WITHOUT - // scrollbars here. Since we don't know if there are - // any scrollbars, we use GetSize() instead. Another - // solution would be to call SetScrollbars() here to - // remove the scrollbars and call GetClientSize() then, - // but this might result in flicker and - worse - will - // reset the scrollbars to 0 which is not good at all - // if you resize a dialog/window, but don't want to - // reset the window scrolling. RR. - // Furthermore, we actually do NOT subtract the border - // width as 2 pixels is just the extra space which we - // need around the actual content in the window. Other- - // wise the text would e.g. touch the upper border. RR. - int clientWidth, - clientHeight; - GetSize( &clientWidth, &clientHeight ); - - if ( InReportView() ) - { - // all lines have the same height and we scroll one line per step - int entireHeight = count * lineHeight + LINE_SPACING; - - m_linesPerPage = clientHeight / lineHeight; - - ResetVisibleLinesRange(); - - SetScrollbars( SCROLL_UNIT_X, lineHeight, - GetHeaderWidth() / SCROLL_UNIT_X, - (entireHeight + lineHeight - 1) / lineHeight, - GetScrollPos(wxHORIZONTAL), - GetScrollPos(wxVERTICAL), - true ); - } - else // !report - { - // we have 3 different layout strategies: either layout all items - // horizontally/vertically (wxLC_ALIGN_XXX styles explicitly given) or - // to arrange them in top to bottom, left to right (don't ask me why - // not the other way round...) order - if ( HasFlag(wxLC_ALIGN_LEFT | wxLC_ALIGN_TOP) ) - { - int x = EXTRA_BORDER_X; - int y = EXTRA_BORDER_Y; - - wxCoord widthMax = 0; - - size_t i; - for ( i = 0; i < count; i++ ) - { - wxListLineData *line = GetLine(i); - line->CalculateSize( &dc, iconSpacing ); - line->SetPosition( x, y, iconSpacing ); - - wxSize sizeLine = GetLineSize(i); - - if ( HasFlag(wxLC_ALIGN_TOP) ) - { - if ( sizeLine.x > widthMax ) - widthMax = sizeLine.x; - - y += sizeLine.y; - } - else // wxLC_ALIGN_LEFT - { - x += sizeLine.x + MARGIN_BETWEEN_ROWS; - } - } - - if ( HasFlag(wxLC_ALIGN_TOP) ) - { - // traverse the items again and tweak their sizes so that they are - // all the same in a row - for ( i = 0; i < count; i++ ) - { - wxListLineData *line = GetLine(i); - line->m_gi->ExtendWidth(widthMax); - } - } - - SetScrollbars - ( - SCROLL_UNIT_X, - lineHeight, - (x + SCROLL_UNIT_X) / SCROLL_UNIT_X, - (y + lineHeight) / lineHeight, - GetScrollPos( wxHORIZONTAL ), - GetScrollPos( wxVERTICAL ), - true - ); - } - else // "flowed" arrangement, the most complicated case - { - // at first we try without any scrollbars, if the items don't fit into - // the window, we recalculate after subtracting the space taken by the - // scrollbar - - int entireWidth = 0; - - for (int tries = 0; tries < 2; tries++) - { - entireWidth = 2 * EXTRA_BORDER_X; - - if (tries == 1) - { - // Now we have decided that the items do not fit into the - // client area, so we need a scrollbar - entireWidth += SCROLL_UNIT_X; - } - - int x = EXTRA_BORDER_X; - int y = EXTRA_BORDER_Y; - int maxWidthInThisRow = 0; - - m_linesPerPage = 0; - int currentlyVisibleLines = 0; - - for (size_t i = 0; i < count; i++) - { - currentlyVisibleLines++; - wxListLineData *line = GetLine( i ); - line->CalculateSize( &dc, iconSpacing ); - line->SetPosition( x, y, iconSpacing ); - - wxSize sizeLine = GetLineSize( i ); - - if ( maxWidthInThisRow < sizeLine.x ) - maxWidthInThisRow = sizeLine.x; - - y += sizeLine.y; - if (currentlyVisibleLines > m_linesPerPage) - m_linesPerPage = currentlyVisibleLines; - - if ( y + sizeLine.y >= clientHeight ) - { - currentlyVisibleLines = 0; - y = EXTRA_BORDER_Y; - maxWidthInThisRow += MARGIN_BETWEEN_ROWS; - x += maxWidthInThisRow; - entireWidth += maxWidthInThisRow; - maxWidthInThisRow = 0; - } - - // We have reached the last item. - if ( i == count - 1 ) - entireWidth += maxWidthInThisRow; - - if ( (tries == 0) && - (entireWidth + SCROLL_UNIT_X > clientWidth) ) - { - clientHeight -= wxSystemSettings:: - GetMetric(wxSYS_HSCROLL_Y); - m_linesPerPage = 0; - break; - } - - if ( i == count - 1 ) - tries = 1; // Everything fits, no second try required. - } - } - - SetScrollbars - ( - SCROLL_UNIT_X, - lineHeight, - (entireWidth + SCROLL_UNIT_X) / SCROLL_UNIT_X, - 0, - GetScrollPos( wxHORIZONTAL ), - 0, - true - ); - } - } - - if ( !noRefresh ) - { - // FIXME: why should we call it from here? - UpdateCurrent(); - - RefreshAll(); - } -} - -void wxListMainWindow::RefreshAll() -{ - m_dirty = false; - Refresh(); - - wxListHeaderWindow *headerWin = GetListCtrl()->m_headerWin; - if ( headerWin && headerWin->m_dirty ) - { - headerWin->m_dirty = false; - headerWin->Refresh(); - } -} - -void wxListMainWindow::UpdateCurrent() -{ - if ( !HasCurrent() && !IsEmpty() ) - ChangeCurrent(0); -} - -long wxListMainWindow::GetNextItem( long item, - int WXUNUSED(geometry), - int state ) const -{ - long ret = item, - max = GetItemCount(); - wxCHECK_MSG( (ret == -1) || (ret < max), -1, - _T("invalid listctrl index in GetNextItem()") ); - - // notice that we start with the next item (or the first one if item == -1) - // and this is intentional to allow writing a simple loop to iterate over - // all selected items - ret++; - if ( ret == max ) - // this is not an error because the index was OK initially, - // just no such item - return -1; - - if ( !state ) - // any will do - return (size_t)ret; - - size_t count = GetItemCount(); - for ( size_t line = (size_t)ret; line < count; line++ ) - { - if ( (state & wxLIST_STATE_FOCUSED) && (line == m_current) ) - return line; - - if ( (state & wxLIST_STATE_SELECTED) && IsHighlighted(line) ) - return line; - } - - return -1; -} - -// ---------------------------------------------------------------------------- -// deleting stuff -// ---------------------------------------------------------------------------- - -void wxListMainWindow::DeleteItem( long lindex ) -{ - size_t count = GetItemCount(); - - wxCHECK_RET( (lindex >= 0) && ((size_t)lindex < count), - _T("invalid item index in DeleteItem") ); - - size_t index = (size_t)lindex; - - // we don't need to adjust the index for the previous items - if ( HasCurrent() && m_current >= index ) - { - // if the current item is being deleted, we want the next one to - // become selected - unless there is no next one - so don't adjust - // m_current in this case - if ( m_current != index || m_current == count - 1 ) - m_current--; - } - - if ( InReportView() ) - { - // mark the Column Max Width cache as dirty if the items in the line - // we're deleting contain the Max Column Width - wxListLineData * const line = GetLine(index); - wxListItemDataList::compatibility_iterator n; - wxListItemData *itemData; - wxListItem item; - int itemWidth; - - for (size_t i = 0; i < m_columns.GetCount(); i++) - { - n = line->m_items.Item( i ); - itemData = n->GetData(); - itemData->GetItem(item); - - itemWidth = GetItemWidthWithImage(&item); - - if (itemWidth >= m_aColWidths.Item(i)->nMaxWidth) - m_aColWidths.Item(i)->bNeedsUpdate = true; - } - - ResetVisibleLinesRange(); - } - - SendNotify( index, wxEVT_COMMAND_LIST_DELETE_ITEM, wxDefaultPosition ); - - if ( IsVirtual() ) - { - m_countVirt--; - m_selStore.OnItemDelete(index); - } - else - { - m_lines.RemoveAt( index ); - } - - // we need to refresh the (vert) scrollbar as the number of items changed - m_dirty = true; - - RefreshAfter(index); -} - -void wxListMainWindow::DeleteColumn( int col ) -{ - wxListHeaderDataList::compatibility_iterator node = m_columns.Item( col ); - - wxCHECK_RET( node, wxT("invalid column index in DeleteColumn()") ); - - m_dirty = true; - delete node->GetData(); - m_columns.Erase( node ); - - if ( !IsVirtual() ) - { - // update all the items - for ( size_t i = 0; i < m_lines.GetCount(); i++ ) - { - wxListLineData * const line = GetLine(i); - wxListItemDataList::compatibility_iterator n = line->m_items.Item( col ); - delete n->GetData(); - line->m_items.Erase(n); - } - } - - if ( InReportView() ) // we only cache max widths when in Report View - { - delete m_aColWidths.Item(col); - m_aColWidths.RemoveAt(col); - } - - // invalidate it as it has to be recalculated - m_headerWidth = 0; -} - -void wxListMainWindow::DoDeleteAllItems() -{ - if ( IsEmpty() ) - // nothing to do - in particular, don't send the event - return; - - ResetCurrent(); - - // to make the deletion of all items faster, we don't send the - // notifications for each item deletion in this case but only one event - // for all of them: this is compatible with wxMSW and documented in - // DeleteAllItems() description - - wxListEvent event( wxEVT_COMMAND_LIST_DELETE_ALL_ITEMS, GetParent()->GetId() ); - event.SetEventObject( GetParent() ); - GetParent()->GetEventHandler()->ProcessEvent( event ); - - if ( IsVirtual() ) - { - m_countVirt = 0; - m_selStore.Clear(); - } - - if ( InReportView() ) - { - ResetVisibleLinesRange(); - for (size_t i = 0; i < m_aColWidths.GetCount(); i++) - { - m_aColWidths.Item(i)->bNeedsUpdate = true; - } - } - - m_lines.Clear(); -} - -void wxListMainWindow::DeleteAllItems() -{ - DoDeleteAllItems(); - - RecalculatePositions(); -} - -void wxListMainWindow::DeleteEverything() -{ - WX_CLEAR_LIST(wxListHeaderDataList, m_columns); - WX_CLEAR_ARRAY(m_aColWidths); - - DeleteAllItems(); -} - -// ---------------------------------------------------------------------------- -// scanning for an item -// ---------------------------------------------------------------------------- - -void wxListMainWindow::EnsureVisible( long index ) -{ - wxCHECK_RET( index >= 0 && (size_t)index < GetItemCount(), - _T("invalid index in EnsureVisible") ); - - // We have to call this here because the label in question might just have - // been added and its position is not known yet - if ( m_dirty ) - RecalculatePositions(true /* no refresh */); - - MoveToItem((size_t)index); -} - -long wxListMainWindow::FindItem(long start, const wxString& str, bool partial ) -{ - if (str.empty()) - return wxNOT_FOUND; - - long pos = start; - wxString str_upper = str.Upper(); - if (pos < 0) - pos = 0; - - size_t count = GetItemCount(); - for ( size_t i = (size_t)pos; i < count; i++ ) - { - wxListLineData *line = GetLine(i); - wxString line_upper = line->GetText(0).Upper(); - if (!partial) - { - if (line_upper == str_upper ) - return i; - } - else - { - if (line_upper.find(str_upper) == 0) - return i; - } - } - - return wxNOT_FOUND; -} - -long wxListMainWindow::FindItem(long start, wxUIntPtr data) -{ - long pos = start; - if (pos < 0) - pos = 0; - - size_t count = GetItemCount(); - for (size_t i = (size_t)pos; i < count; i++) - { - wxListLineData *line = GetLine(i); - wxListItem item; - line->GetItem( 0, item ); - if (item.m_data == data) - return i; - } - - return wxNOT_FOUND; -} - -long wxListMainWindow::FindItem( const wxPoint& pt ) -{ - size_t topItem; - GetVisibleLinesRange( &topItem, NULL ); - - wxPoint p; - GetItemPosition( GetItemCount() - 1, p ); - if ( p.y == 0 ) - return topItem; - - long id = (long)floor( pt.y * double(GetItemCount() - topItem - 1) / p.y + topItem ); - if ( id >= 0 && id < (long)GetItemCount() ) - return id; - - return wxNOT_FOUND; -} - -long wxListMainWindow::HitTest( int x, int y, int &flags ) const -{ - CalcUnscrolledPosition( x, y, &x, &y ); - - size_t count = GetItemCount(); - - if ( InReportView() ) - { - size_t current = y / GetLineHeight(); - if ( current < count ) - { - flags = HitTestLine(current, x, y); - if ( flags ) - return current; - } - } - else // !report - { - // TODO: optimize it too! this is less simple than for report view but - // enumerating all items is still not a way to do it!! - for ( size_t current = 0; current < count; current++ ) - { - flags = HitTestLine(current, x, y); - if ( flags ) - return current; - } - } - - return wxNOT_FOUND; -} - -// ---------------------------------------------------------------------------- -// adding stuff -// ---------------------------------------------------------------------------- - -void wxListMainWindow::InsertItem( wxListItem &item ) -{ - wxASSERT_MSG( !IsVirtual(), _T("can't be used with virtual control") ); - - int count = GetItemCount(); - wxCHECK_RET( item.m_itemId >= 0, _T("invalid item index") ); - - if (item.m_itemId > count) - item.m_itemId = count; - - size_t id = item.m_itemId; - - m_dirty = true; - - if ( InReportView() ) - { - ResetVisibleLinesRange(); - - // calculate the width of the item and adjust the max column width - wxColWidthInfo *pWidthInfo = m_aColWidths.Item(item.GetColumn()); - int width = GetItemWidthWithImage(&item); - item.SetWidth(width); - if (width > pWidthInfo->nMaxWidth) - pWidthInfo->nMaxWidth = width; - } - - wxListLineData *line = new wxListLineData(this); - - line->SetItem( item.m_col, item ); - - m_lines.Insert( line, id ); - - m_dirty = true; - - // If an item is selected at or below the point of insertion, we need to - // increment the member variables because the current row's index has gone - // up by one - if ( HasCurrent() && m_current >= id ) - m_current++; - - SendNotify(id, wxEVT_COMMAND_LIST_INSERT_ITEM); - - RefreshLines(id, GetItemCount() - 1); -} - -void wxListMainWindow::InsertColumn( long col, wxListItem &item ) -{ - m_dirty = true; - if ( InReportView() ) - { - if (item.m_width == wxLIST_AUTOSIZE_USEHEADER) - item.m_width = GetTextLength( item.m_text ); - - wxListHeaderData *column = new wxListHeaderData( item ); - wxColWidthInfo *colWidthInfo = new wxColWidthInfo(); - - bool insert = (col >= 0) && ((size_t)col < m_columns.GetCount()); - if ( insert ) - { - wxListHeaderDataList::compatibility_iterator - node = m_columns.Item( col ); - m_columns.Insert( node, column ); - m_aColWidths.Insert( colWidthInfo, col ); - } - else - { - m_columns.Append( column ); - m_aColWidths.Add( colWidthInfo ); - } - - if ( !IsVirtual() ) - { - // update all the items - for ( size_t i = 0; i < m_lines.GetCount(); i++ ) - { - wxListLineData * const line = GetLine(i); - wxListItemData * const data = new wxListItemData(this); - if ( insert ) - line->m_items.Insert(col, data); - else - line->m_items.Append(data); - } - } - - // invalidate it as it has to be recalculated - m_headerWidth = 0; - } -} - -int wxListMainWindow::GetItemWidthWithImage(wxListItem * item) -{ - int width = 0; - wxClientDC dc(this); - - dc.SetFont( GetFont() ); - - if (item->GetImage() != -1) - { - int ix, iy; - GetImageSize( item->GetImage(), ix, iy ); - width += ix + 5; - } - - if (!item->GetText().empty()) - { - wxCoord w; - dc.GetTextExtent( item->GetText(), &w, NULL ); - width += w; - } - - return width; -} - -// ---------------------------------------------------------------------------- -// sorting -// ---------------------------------------------------------------------------- - -wxListCtrlCompare list_ctrl_compare_func_2; -long list_ctrl_compare_data; - -int LINKAGEMODE list_ctrl_compare_func_1( wxListLineData **arg1, wxListLineData **arg2 ) -{ - wxListLineData *line1 = *arg1; - wxListLineData *line2 = *arg2; - wxListItem item; - line1->GetItem( 0, item ); - wxUIntPtr data1 = item.m_data; - line2->GetItem( 0, item ); - wxUIntPtr data2 = item.m_data; - return list_ctrl_compare_func_2( data1, data2, list_ctrl_compare_data ); -} - -void wxListMainWindow::SortItems( wxListCtrlCompare fn, long data ) -{ - // selections won't make sense any more after sorting the items so reset - // them - HighlightAll(false); - ResetCurrent(); - - list_ctrl_compare_func_2 = fn; - list_ctrl_compare_data = data; - m_lines.Sort( list_ctrl_compare_func_1 ); - m_dirty = true; -} - -// ---------------------------------------------------------------------------- -// scrolling -// ---------------------------------------------------------------------------- - -void wxListMainWindow::OnScroll(wxScrollWinEvent& event) -{ - // FIXME -#if ( defined(__WXGTK__) || defined(__WXMAC__) ) && !defined(__WXUNIVERSAL__) - wxScrolledWindow::OnScroll(event); -#else - HandleOnScroll( event ); -#endif - - // update our idea of which lines are shown when we redraw the window the - // next time - ResetVisibleLinesRange(); - - if ( event.GetOrientation() == wxHORIZONTAL && HasHeader() ) - { - wxGenericListCtrl* lc = GetListCtrl(); - wxCHECK_RET( lc, _T("no listctrl window?") ); - - lc->m_headerWin->Refresh(); - lc->m_headerWin->Update(); - } -} - -int wxListMainWindow::GetCountPerPage() const -{ - if ( !m_linesPerPage ) - { - wxConstCast(this, wxListMainWindow)-> - m_linesPerPage = GetClientSize().y / GetLineHeight(); - } - - return m_linesPerPage; -} - -void wxListMainWindow::GetVisibleLinesRange(size_t *from, size_t *to) -{ - wxASSERT_MSG( InReportView(), _T("this is for report mode only") ); - - if ( m_lineFrom == (size_t)-1 ) - { - size_t count = GetItemCount(); - if ( count ) - { - m_lineFrom = GetScrollPos(wxVERTICAL); - - // this may happen if SetScrollbars() hadn't been called yet - if ( m_lineFrom >= count ) - m_lineFrom = count - 1; - - // we redraw one extra line but this is needed to make the redrawing - // logic work when there is a fractional number of lines on screen - m_lineTo = m_lineFrom + m_linesPerPage; - if ( m_lineTo >= count ) - m_lineTo = count - 1; - } - else // empty control - { - m_lineFrom = 0; - m_lineTo = (size_t)-1; - } - } - - wxASSERT_MSG( IsEmpty() || - (m_lineFrom <= m_lineTo && m_lineTo < GetItemCount()), - _T("GetVisibleLinesRange() returns incorrect result") ); - - if ( from ) - *from = m_lineFrom; - if ( to ) - *to = m_lineTo; -} - -// ------------------------------------------------------------------------------------- -// wxGenericListCtrl -// ------------------------------------------------------------------------------------- - -IMPLEMENT_DYNAMIC_CLASS(wxGenericListCtrl, wxControl) - -BEGIN_EVENT_TABLE(wxGenericListCtrl,wxControl) - EVT_SIZE(wxGenericListCtrl::OnSize) -END_EVENT_TABLE() - -wxGenericListCtrl::wxGenericListCtrl() -{ - m_imageListNormal = (wxImageList *) NULL; - m_imageListSmall = (wxImageList *) NULL; - m_imageListState = (wxImageList *) NULL; - - m_ownsImageListNormal = - m_ownsImageListSmall = - m_ownsImageListState = false; - - m_mainWin = (wxListMainWindow*) NULL; - m_headerWin = (wxListHeaderWindow*) NULL; - m_headerHeight = 0; -} - -wxGenericListCtrl::~wxGenericListCtrl() -{ - if (m_ownsImageListNormal) - delete m_imageListNormal; - if (m_ownsImageListSmall) - delete m_imageListSmall; - if (m_ownsImageListState) - delete m_imageListState; -} - -void wxGenericListCtrl::CalculateAndSetHeaderHeight() -{ - if ( m_headerWin ) - { -#ifdef __WXMAC__ - SInt32 h; - GetThemeMetric( kThemeMetricListHeaderHeight, &h ); -#else - // we use 'g' to get the descent, too - int w, h, d; - m_headerWin->GetTextExtent(wxT("Hg"), &w, &h, &d); - h += d + 2 * HEADER_OFFSET_Y + EXTRA_HEIGHT; -#endif - - // only update if changed - if ( h != m_headerHeight ) - { - m_headerHeight = h; - - if ( HasHeader() ) - ResizeReportView(true); - else //why is this needed if it doesn't have a header? - m_headerWin->SetSize(m_headerWin->GetSize().x, m_headerHeight); - } - } -} - -void wxGenericListCtrl::CreateHeaderWindow() -{ - m_headerWin = new wxListHeaderWindow - ( - this, wxID_ANY, m_mainWin, - wxPoint(0,0), - wxSize(GetClientSize().x, m_headerHeight), - wxTAB_TRAVERSAL - ); - CalculateAndSetHeaderHeight(); -} - -bool wxGenericListCtrl::Create(wxWindow *parent, - wxWindowID id, - const wxPoint &pos, - const wxSize &size, - long style, - const wxValidator &validator, - const wxString &name) -{ - m_imageListNormal = - m_imageListSmall = - m_imageListState = (wxImageList *) NULL; - m_ownsImageListNormal = - m_ownsImageListSmall = - m_ownsImageListState = false; - - m_mainWin = (wxListMainWindow*) NULL; - m_headerWin = (wxListHeaderWindow*) NULL; - - m_headerHeight = 0; - - if ( !(style & wxLC_MASK_TYPE) ) - { - style = style | wxLC_LIST; - } - - // add more styles here that should only appear - // in the main window - unsigned long only_main_window_style = wxALWAYS_SHOW_SB; - - if ( !wxControl::Create( parent, id, pos, size, style & ~only_main_window_style, validator, name ) ) - return false; - - // don't create the inner window with the border - style &= ~wxBORDER_MASK; - - m_mainWin = new wxListMainWindow( this, wxID_ANY, wxPoint(0, 0), size, style ); - -#ifdef __WXMAC_CARBON__ - // Human Interface Guidelines ask us for a special font in this case - if ( GetWindowVariant() == wxWINDOW_VARIANT_NORMAL ) - { - wxFont font; - font.MacCreateThemeFont( kThemeViewsFont ); - SetFont( font ); - } -#endif - - if ( InReportView() ) - { - CreateHeaderWindow(); - -#ifdef __WXMAC_CARBON__ - if (m_headerWin) - { - wxFont font; - font.MacCreateThemeFont( kThemeSmallSystemFont ); - m_headerWin->SetFont( font ); - CalculateAndSetHeaderHeight(); - } -#endif - - if ( HasFlag(wxLC_NO_HEADER) ) - // VZ: why do we create it at all then? - m_headerWin->Show( false ); - } - - SetInitialSize(size); - - return true; -} - -void wxGenericListCtrl::SetSingleStyle( long style, bool add ) -{ - wxASSERT_MSG( !(style & wxLC_VIRTUAL), - _T("wxLC_VIRTUAL can't be [un]set") ); - - long flag = GetWindowStyle(); - - if (add) - { - if (style & wxLC_MASK_TYPE) - flag &= ~(wxLC_MASK_TYPE | wxLC_VIRTUAL); - if (style & wxLC_MASK_ALIGN) - flag &= ~wxLC_MASK_ALIGN; - if (style & wxLC_MASK_SORT) - flag &= ~wxLC_MASK_SORT; - } - - if (add) - flag |= style; - else - flag &= ~style; - - // some styles can be set without recreating everything (as happens in - // SetWindowStyleFlag() which calls wxListMainWindow::DeleteEverything()) - if ( !(style & ~(wxLC_HRULES | wxLC_VRULES)) ) - { - Refresh(); - wxWindow::SetWindowStyleFlag(flag); - } - else - { - SetWindowStyleFlag( flag ); - } -} - -void wxGenericListCtrl::SetWindowStyleFlag( long flag ) -{ - if (m_mainWin) - { - m_mainWin->DeleteEverything(); - - // has the header visibility changed? - bool hasHeader = HasHeader(); - bool willHaveHeader = (flag & wxLC_REPORT) && !(flag & wxLC_NO_HEADER); - - if ( hasHeader != willHaveHeader ) - { - // toggle it - if ( hasHeader ) - { - if ( m_headerWin ) - { - // don't delete, just hide, as we can reuse it later - m_headerWin->Show(false); - } - //else: nothing to do - } - else // must show header - { - if (!m_headerWin) - { - CreateHeaderWindow(); - } - else // already have it, just show - { - m_headerWin->Show( true ); - } - } - - ResizeReportView(willHaveHeader); - } - } - - wxWindow::SetWindowStyleFlag( flag ); -} - -bool wxGenericListCtrl::GetColumn(int col, wxListItem &item) const -{ - m_mainWin->GetColumn( col, item ); - return true; -} - -bool wxGenericListCtrl::SetColumn( int col, wxListItem& item ) -{ - m_mainWin->SetColumn( col, item ); - return true; -} - -int wxGenericListCtrl::GetColumnWidth( int col ) const -{ - return m_mainWin->GetColumnWidth( col ); -} - -bool wxGenericListCtrl::SetColumnWidth( int col, int width ) -{ - m_mainWin->SetColumnWidth( col, width ); - return true; -} - -int wxGenericListCtrl::GetCountPerPage() const -{ - return m_mainWin->GetCountPerPage(); // different from Windows ? -} - -bool wxGenericListCtrl::GetItem( wxListItem &info ) const -{ - m_mainWin->GetItem( info ); - return true; -} - -bool wxGenericListCtrl::SetItem( wxListItem &info ) -{ - m_mainWin->SetItem( info ); - return true; -} - -long wxGenericListCtrl::SetItem( long index, int col, const wxString& label, int imageId ) -{ - wxListItem info; - info.m_text = label; - info.m_mask = wxLIST_MASK_TEXT; - info.m_itemId = index; - info.m_col = col; - if ( imageId > -1 ) - { - info.m_image = imageId; - info.m_mask |= wxLIST_MASK_IMAGE; - } - - m_mainWin->SetItem(info); - return true; -} - -int wxGenericListCtrl::GetItemState( long item, long stateMask ) const -{ - return m_mainWin->GetItemState( item, stateMask ); -} - -bool wxGenericListCtrl::SetItemState( long item, long state, long stateMask ) -{ - m_mainWin->SetItemState( item, state, stateMask ); - return true; -} - -bool -wxGenericListCtrl::SetItemImage( long item, int image, int WXUNUSED(selImage) ) -{ - return SetItemColumnImage(item, 0, image); -} - -bool -wxGenericListCtrl::SetItemColumnImage( long item, long column, int image ) -{ - wxListItem info; - info.m_image = image; - info.m_mask = wxLIST_MASK_IMAGE; - info.m_itemId = item; - info.m_col = column; - m_mainWin->SetItem( info ); - return true; -} - -wxString wxGenericListCtrl::GetItemText( long item ) const -{ - return m_mainWin->GetItemText(item); -} - -void wxGenericListCtrl::SetItemText( long item, const wxString& str ) -{ - m_mainWin->SetItemText(item, str); -} - -wxUIntPtr wxGenericListCtrl::GetItemData( long item ) const -{ - wxListItem info; - info.m_mask = wxLIST_MASK_DATA; - info.m_itemId = item; - m_mainWin->GetItem( info ); - return info.m_data; -} - -bool wxGenericListCtrl::SetItemPtrData( long item, wxUIntPtr data ) -{ - wxListItem info; - info.m_mask = wxLIST_MASK_DATA; - info.m_itemId = item; - info.m_data = data; - m_mainWin->SetItem( info ); - return true; -} - -bool wxGenericListCtrl::SetItemData(long item, long data) -{ - return SetItemPtrData(item, data); -} - -wxRect wxGenericListCtrl::GetViewRect() const -{ - return m_mainWin->GetViewRect(); -} - -bool wxGenericListCtrl::GetItemRect( long item, wxRect &rect, int WXUNUSED(code) ) const -{ - m_mainWin->GetItemRect( item, rect ); - if ( m_mainWin->HasHeader() ) - rect.y += m_headerHeight + 1; - return true; -} - -bool wxGenericListCtrl::GetItemPosition( long item, wxPoint& pos ) const -{ - m_mainWin->GetItemPosition( item, pos ); - return true; -} - -bool wxGenericListCtrl::SetItemPosition( long WXUNUSED(item), const wxPoint& WXUNUSED(pos) ) -{ - return 0; -} - -int wxGenericListCtrl::GetItemCount() const -{ - return m_mainWin->GetItemCount(); -} - -int wxGenericListCtrl::GetColumnCount() const -{ - return m_mainWin->GetColumnCount(); -} - -void wxGenericListCtrl::SetItemSpacing( int spacing, bool isSmall ) -{ - m_mainWin->SetItemSpacing( spacing, isSmall ); -} - -wxSize wxGenericListCtrl::GetItemSpacing() const -{ - const int spacing = m_mainWin->GetItemSpacing(HasFlag(wxLC_SMALL_ICON)); - - return wxSize(spacing, spacing); -} - -#if WXWIN_COMPATIBILITY_2_6 -int wxGenericListCtrl::GetItemSpacing( bool isSmall ) const -{ - return m_mainWin->GetItemSpacing( isSmall ); -} -#endif // WXWIN_COMPATIBILITY_2_6 - -void wxGenericListCtrl::SetItemTextColour( long item, const wxColour &col ) -{ - wxListItem info; - info.m_itemId = item; - info.SetTextColour( col ); - m_mainWin->SetItem( info ); -} - -wxColour wxGenericListCtrl::GetItemTextColour( long item ) const -{ - wxListItem info; - info.m_itemId = item; - m_mainWin->GetItem( info ); - return info.GetTextColour(); -} - -void wxGenericListCtrl::SetItemBackgroundColour( long item, const wxColour &col ) -{ - wxListItem info; - info.m_itemId = item; - info.SetBackgroundColour( col ); - m_mainWin->SetItem( info ); -} - -wxColour wxGenericListCtrl::GetItemBackgroundColour( long item ) const -{ - wxListItem info; - info.m_itemId = item; - m_mainWin->GetItem( info ); - return info.GetBackgroundColour(); -} - -int wxGenericListCtrl::GetScrollPos( int orient ) const -{ - return m_mainWin->GetScrollPos( orient ); -} - -void wxGenericListCtrl::SetScrollPos( int orient, int pos, bool refresh ) -{ - m_mainWin->SetScrollPos( orient, pos, refresh ); -} - -void wxGenericListCtrl::SetItemFont( long item, const wxFont &f ) -{ - wxListItem info; - info.m_itemId = item; - info.SetFont( f ); - m_mainWin->SetItem( info ); -} - -wxFont wxGenericListCtrl::GetItemFont( long item ) const -{ - wxListItem info; - info.m_itemId = item; - m_mainWin->GetItem( info ); - return info.GetFont(); -} - -int wxGenericListCtrl::GetSelectedItemCount() const -{ - return m_mainWin->GetSelectedItemCount(); -} - -wxColour wxGenericListCtrl::GetTextColour() const -{ - return GetForegroundColour(); -} - -void wxGenericListCtrl::SetTextColour(const wxColour& col) -{ - SetForegroundColour(col); -} - -long wxGenericListCtrl::GetTopItem() const -{ - size_t top; - m_mainWin->GetVisibleLinesRange(&top, NULL); - return (long)top; -} - -long wxGenericListCtrl::GetNextItem( long item, int geom, int state ) const -{ - return m_mainWin->GetNextItem( item, geom, state ); -} - -wxImageList *wxGenericListCtrl::GetImageList(int which) const -{ - if (which == wxIMAGE_LIST_NORMAL) - return m_imageListNormal; - else if (which == wxIMAGE_LIST_SMALL) - return m_imageListSmall; - else if (which == wxIMAGE_LIST_STATE) - return m_imageListState; - - return (wxImageList *) NULL; -} - -void wxGenericListCtrl::SetImageList( wxImageList *imageList, int which ) -{ - if ( which == wxIMAGE_LIST_NORMAL ) - { - if (m_ownsImageListNormal) - delete m_imageListNormal; - m_imageListNormal = imageList; - m_ownsImageListNormal = false; - } - else if ( which == wxIMAGE_LIST_SMALL ) - { - if (m_ownsImageListSmall) - delete m_imageListSmall; - m_imageListSmall = imageList; - m_ownsImageListSmall = false; - } - else if ( which == wxIMAGE_LIST_STATE ) - { - if (m_ownsImageListState) - delete m_imageListState; - m_imageListState = imageList; - m_ownsImageListState = false; - } - - m_mainWin->SetImageList( imageList, which ); -} - -void wxGenericListCtrl::AssignImageList(wxImageList *imageList, int which) -{ - SetImageList(imageList, which); - if ( which == wxIMAGE_LIST_NORMAL ) - m_ownsImageListNormal = true; - else if ( which == wxIMAGE_LIST_SMALL ) - m_ownsImageListSmall = true; - else if ( which == wxIMAGE_LIST_STATE ) - m_ownsImageListState = true; -} - -bool wxGenericListCtrl::Arrange( int WXUNUSED(flag) ) -{ - return 0; -} - -bool wxGenericListCtrl::DeleteItem( long item ) -{ - m_mainWin->DeleteItem( item ); - return true; -} - -bool wxGenericListCtrl::DeleteAllItems() -{ - m_mainWin->DeleteAllItems(); - return true; -} - -bool wxGenericListCtrl::DeleteAllColumns() -{ - size_t count = m_mainWin->m_columns.GetCount(); - for ( size_t n = 0; n < count; n++ ) - DeleteColumn( 0 ); - return true; -} - -void wxGenericListCtrl::ClearAll() -{ - m_mainWin->DeleteEverything(); -} - -bool wxGenericListCtrl::DeleteColumn( int col ) -{ - m_mainWin->DeleteColumn( col ); - - // if we don't have the header any longer, we need to relayout the window - if ( !GetColumnCount() ) - ResizeReportView(false /* no header */); - return true; -} - -wxTextCtrl *wxGenericListCtrl::EditLabel(long item, - wxClassInfo* textControlClass) -{ - return m_mainWin->EditLabel( item, textControlClass ); -} - -wxTextCtrl *wxGenericListCtrl::GetEditControl() const -{ - return m_mainWin->GetEditControl(); -} - -bool wxGenericListCtrl::EnsureVisible( long item ) -{ - m_mainWin->EnsureVisible( item ); - return true; -} - -long wxGenericListCtrl::FindItem( long start, const wxString& str, bool partial ) -{ - return m_mainWin->FindItem( start, str, partial ); -} - -long wxGenericListCtrl::FindItem( long start, wxUIntPtr data ) -{ - return m_mainWin->FindItem( start, data ); -} - -long wxGenericListCtrl::FindItem( long WXUNUSED(start), const wxPoint& pt, - int WXUNUSED(direction)) -{ - return m_mainWin->FindItem( pt ); -} - -// TODO: sub item hit testing -long wxGenericListCtrl::HitTest(const wxPoint& point, int& flags, long *) const -{ - return m_mainWin->HitTest( (int)point.x, (int)point.y, flags ); -} - -long wxGenericListCtrl::InsertItem( wxListItem& info ) -{ - m_mainWin->InsertItem( info ); - return info.m_itemId; -} - -long wxGenericListCtrl::InsertItem( long index, const wxString &label ) -{ - wxListItem info; - info.m_text = label; - info.m_mask = wxLIST_MASK_TEXT; - info.m_itemId = index; - return InsertItem( info ); -} - -long wxGenericListCtrl::InsertItem( long index, int imageIndex ) -{ - wxListItem info; - info.m_mask = wxLIST_MASK_IMAGE; - info.m_image = imageIndex; - info.m_itemId = index; - return InsertItem( info ); -} - -long wxGenericListCtrl::InsertItem( long index, const wxString &label, int imageIndex ) -{ - wxListItem info; - info.m_text = label; - info.m_image = imageIndex; - info.m_mask = wxLIST_MASK_TEXT | wxLIST_MASK_IMAGE; - info.m_itemId = index; - return InsertItem( info ); -} - -long wxGenericListCtrl::InsertColumn( long col, wxListItem &item ) -{ - wxCHECK_MSG( m_headerWin, -1, _T("can't add column in non report mode") ); - - m_mainWin->InsertColumn( col, item ); - - // if we hadn't had a header before but have one now - // then we need to relayout the window - if ( GetColumnCount() == 1 && m_mainWin->HasHeader() ) - ResizeReportView(true /* have header */); - - m_headerWin->Refresh(); - - return 0; -} - -long wxGenericListCtrl::InsertColumn( long col, const wxString &heading, - int format, int width ) -{ - wxListItem item; - item.m_mask = wxLIST_MASK_TEXT | wxLIST_MASK_FORMAT; - item.m_text = heading; - if (width >= -2) - { - item.m_mask |= wxLIST_MASK_WIDTH; - item.m_width = width; - } - - item.m_format = format; - - return InsertColumn( col, item ); -} - -bool wxGenericListCtrl::ScrollList( int dx, int dy ) -{ - return m_mainWin->ScrollList(dx, dy); -} - -// Sort items. -// fn is a function which takes 3 long arguments: item1, item2, data. -// item1 is the long data associated with a first item (NOT the index). -// item2 is the long data associated with a second item (NOT the index). -// data is the same value as passed to SortItems. -// The return value is a negative number if the first item should precede the second -// item, a positive number of the second item should precede the first, -// or zero if the two items are equivalent. -// data is arbitrary data to be passed to the sort function. - -bool wxGenericListCtrl::SortItems( wxListCtrlCompare fn, long data ) -{ - m_mainWin->SortItems( fn, data ); - return true; -} - -// ---------------------------------------------------------------------------- -// event handlers -// ---------------------------------------------------------------------------- - -void wxGenericListCtrl::OnSize(wxSizeEvent& WXUNUSED(event)) -{ - if ( !m_mainWin ) - return; - - ResizeReportView(m_mainWin->HasHeader()); - m_mainWin->RecalculatePositions(); -} - -void wxGenericListCtrl::ResizeReportView(bool showHeader) -{ - int cw, ch; - GetClientSize( &cw, &ch ); - - if ( showHeader ) - { - m_headerWin->SetSize( 0, 0, cw, m_headerHeight ); - if(ch > m_headerHeight) - m_mainWin->SetSize( 0, m_headerHeight + 1, - cw, ch - m_headerHeight - 1 ); - else - m_mainWin->SetSize( 0, m_headerHeight + 1, - cw, 0); - } - else // no header window - { - m_mainWin->SetSize( 0, 0, cw, ch ); - } -} - -void wxGenericListCtrl::OnInternalIdle() -{ - wxWindow::OnInternalIdle(); - - // do it only if needed - if ( !m_mainWin->m_dirty ) - return; - - m_mainWin->RecalculatePositions(); -} - -// ---------------------------------------------------------------------------- -// font/colours -// ---------------------------------------------------------------------------- - -bool wxGenericListCtrl::SetBackgroundColour( const wxColour &colour ) -{ - if (m_mainWin) - { - m_mainWin->SetBackgroundColour( colour ); - m_mainWin->m_dirty = true; - } - - return true; -} - -bool wxGenericListCtrl::SetForegroundColour( const wxColour &colour ) -{ - if ( !wxWindow::SetForegroundColour( colour ) ) - return false; - - if (m_mainWin) - { - m_mainWin->SetForegroundColour( colour ); - m_mainWin->m_dirty = true; - } - - if (m_headerWin) - m_headerWin->SetForegroundColour( colour ); - - return true; -} - -bool wxGenericListCtrl::SetFont( const wxFont &font ) -{ - if ( !wxWindow::SetFont( font ) ) - return false; - - if (m_mainWin) - { - m_mainWin->SetFont( font ); - m_mainWin->m_dirty = true; - } - - if (m_headerWin) - { - m_headerWin->SetFont( font ); - CalculateAndSetHeaderHeight(); - } - - Refresh(); - - return true; -} - -// static -wxVisualAttributes -wxGenericListCtrl::GetClassDefaultAttributes(wxWindowVariant variant) -{ -#if _USE_VISATTR - // Use the same color scheme as wxListBox - return wxListBox::GetClassDefaultAttributes(variant); -#else - wxUnusedVar(variant); - wxVisualAttributes attr; - attr.colFg = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT); - attr.colBg = wxSystemSettings::GetColour(wxSYS_COLOUR_LISTBOX); - attr.font = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT); - return attr; -#endif -} - -// ---------------------------------------------------------------------------- -// methods forwarded to m_mainWin -// ---------------------------------------------------------------------------- - -#if wxUSE_DRAG_AND_DROP - -void wxGenericListCtrl::SetDropTarget( wxDropTarget *dropTarget ) -{ - m_mainWin->SetDropTarget( dropTarget ); -} - -wxDropTarget *wxGenericListCtrl::GetDropTarget() const -{ - return m_mainWin->GetDropTarget(); -} - -#endif - -bool wxGenericListCtrl::SetCursor( const wxCursor &cursor ) -{ - return m_mainWin ? m_mainWin->wxWindow::SetCursor(cursor) : false; -} - -wxColour wxGenericListCtrl::GetBackgroundColour() const -{ - return m_mainWin ? m_mainWin->GetBackgroundColour() : wxColour(); -} - -wxColour wxGenericListCtrl::GetForegroundColour() const -{ - return m_mainWin ? m_mainWin->GetForegroundColour() : wxColour(); -} - -bool wxGenericListCtrl::DoPopupMenu( wxMenu *menu, int x, int y ) -{ -#if wxUSE_MENUS - return m_mainWin->PopupMenu( menu, x, y ); -#else - return false; -#endif -} - -void wxGenericListCtrl::DoClientToScreen( int *x, int *y ) const -{ - m_mainWin->DoClientToScreen(x, y); -} - -void wxGenericListCtrl::DoScreenToClient( int *x, int *y ) const -{ - m_mainWin->DoScreenToClient(x, y); -} - -void wxGenericListCtrl::SetFocus() -{ - // The test in window.cpp fails as we are a composite - // window, so it checks against "this", but not m_mainWin. - if ( DoFindFocus() != this ) - m_mainWin->SetFocus(); -} - -wxSize wxGenericListCtrl::DoGetBestSize() const -{ - // Something is better than nothing... - // 100x80 is what the MSW version will get from the default - // wxControl::DoGetBestSize - return wxSize(100, 80); -} - -// ---------------------------------------------------------------------------- -// virtual list control support -// ---------------------------------------------------------------------------- - -wxString wxGenericListCtrl::OnGetItemText(long WXUNUSED(item), long WXUNUSED(col)) const -{ - // this is a pure virtual function, in fact - which is not really pure - // because the controls which are not virtual don't need to implement it - wxFAIL_MSG( _T("wxGenericListCtrl::OnGetItemText not supposed to be called") ); - - return wxEmptyString; -} - -int wxGenericListCtrl::OnGetItemImage(long WXUNUSED(item)) const -{ - wxCHECK_MSG(!GetImageList(wxIMAGE_LIST_SMALL), - -1, - wxT("List control has an image list, OnGetItemImage or OnGetItemColumnImage should be overridden.")); - return -1; -} - -int wxGenericListCtrl::OnGetItemColumnImage(long item, long column) const -{ - if (!column) - return OnGetItemImage(item); - - return -1; -} - -wxListItemAttr * -wxGenericListCtrl::OnGetItemAttr(long WXUNUSED_UNLESS_DEBUG(item)) const -{ - wxASSERT_MSG( item >= 0 && item < GetItemCount(), - _T("invalid item index in OnGetItemAttr()") ); - - // no attributes by default - return NULL; -} - -void wxGenericListCtrl::SetItemCount(long count) -{ - wxASSERT_MSG( IsVirtual(), _T("this is for virtual controls only") ); - - m_mainWin->SetItemCount(count); -} - -void wxGenericListCtrl::RefreshItem(long item) -{ - m_mainWin->RefreshLine(item); -} - -void wxGenericListCtrl::RefreshItems(long itemFrom, long itemTo) -{ - m_mainWin->RefreshLines(itemFrom, itemTo); -} - -// Generic wxListCtrl is more or less a container for two other -// windows which drawings are done upon. These are namely -// 'm_headerWin' and 'm_mainWin'. -// Here we override 'virtual wxWindow::Refresh()' to mimic the -// behaviour wxListCtrl has under wxMSW. -// -void wxGenericListCtrl::Refresh(bool eraseBackground, const wxRect *rect) -{ - if (!rect) - { - // The easy case, no rectangle specified. - if (m_headerWin) - m_headerWin->Refresh(eraseBackground); - - if (m_mainWin) - m_mainWin->Refresh(eraseBackground); - } - else - { - // Refresh the header window - if (m_headerWin) - { - wxRect rectHeader = m_headerWin->GetRect(); - rectHeader.Intersect(*rect); - if (rectHeader.GetWidth() && rectHeader.GetHeight()) - { - int x, y; - m_headerWin->GetPosition(&x, &y); - rectHeader.Offset(-x, -y); - m_headerWin->Refresh(eraseBackground, &rectHeader); - } - } - - // Refresh the main window - if (m_mainWin) - { - wxRect rectMain = m_mainWin->GetRect(); - rectMain.Intersect(*rect); - if (rectMain.GetWidth() && rectMain.GetHeight()) - { - int x, y; - m_mainWin->GetPosition(&x, &y); - rectMain.Offset(-x, -y); - m_mainWin->Refresh(eraseBackground, &rectMain); - } - } - } -} - -void wxGenericListCtrl::Freeze() -{ - m_mainWin->Freeze(); -} - -void wxGenericListCtrl::Thaw() -{ - m_mainWin->Thaw(); -} - -#endif // wxUSE_LISTCTRL +///////////////////////////////////////////////////////////////////////////// +// Name: src/generic/listctrl.cpp +// Purpose: generic implementation of wxListCtrl +// Author: Robert Roebling +// Vadim Zeitlin (virtual list control support) +// Id: $Id: listctrl.cpp 54201 2008-06-13 22:38:33Z VZ $ +// Copyright: (c) 1998 Robert Roebling +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// TODO +// +// 1. we need to implement searching/sorting for virtual controls somehow +// 2. when changing selection the lines are refreshed twice + + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_LISTCTRL + +#include "wx/listctrl.h" + +#if (!defined(__WXMSW__) || defined(__WXUNIVERSAL__)) && (!defined(__WXMAC__)|| defined(__WXUNIVERSAL__)) + // if we have a native version, its implementation file does all this + IMPLEMENT_DYNAMIC_CLASS(wxListItem, wxObject) + IMPLEMENT_DYNAMIC_CLASS(wxListView, wxListCtrl) + IMPLEMENT_DYNAMIC_CLASS(wxListEvent, wxNotifyEvent) + + IMPLEMENT_DYNAMIC_CLASS(wxListCtrl, wxGenericListCtrl) +#endif + +#ifndef WX_PRECOMP + #include "wx/scrolwin.h" + #include "wx/timer.h" + #include "wx/settings.h" + #include "wx/dynarray.h" + #include "wx/dcclient.h" + #include "wx/dcscreen.h" + #include "wx/math.h" +#endif + +#include "wx/imaglist.h" +#include "wx/selstore.h" +#include "wx/renderer.h" + +#ifdef __WXMAC__ + #include "wx/mac/private.h" +#endif + + +// NOTE: If using the wxListBox visual attributes works everywhere then this can +// be removed, as well as the #else case below. +#define _USE_VISATTR 0 + + +// ---------------------------------------------------------------------------- +// constants +// ---------------------------------------------------------------------------- + +// // the height of the header window (FIXME: should depend on its font!) +// static const int HEADER_HEIGHT = 23; + +static const int SCROLL_UNIT_X = 15; + +// the spacing between the lines (in report mode) +static const int LINE_SPACING = 0; + +// extra margins around the text label +#ifdef __WXGTK__ +static const int EXTRA_WIDTH = 6; +#else +static const int EXTRA_WIDTH = 4; +#endif +static const int EXTRA_HEIGHT = 4; + +// margin between the window and the items +static const int EXTRA_BORDER_X = 2; +static const int EXTRA_BORDER_Y = 2; + +// offset for the header window +static const int HEADER_OFFSET_X = 0; +static const int HEADER_OFFSET_Y = 0; + +// margin between rows of icons in [small] icon view +static const int MARGIN_BETWEEN_ROWS = 6; + +// when autosizing the columns, add some slack +static const int AUTOSIZE_COL_MARGIN = 10; + +// default width for the header columns +static const int WIDTH_COL_DEFAULT = 80; + +// the space between the image and the text in the report mode +static const int IMAGE_MARGIN_IN_REPORT_MODE = 5; + +// the space between the image and the text in the report mode in header +static const int HEADER_IMAGE_MARGIN_IN_REPORT_MODE = 2; + +// ============================================================================ +// private classes +// ============================================================================ + +//----------------------------------------------------------------------------- +// wxColWidthInfo (internal) +//----------------------------------------------------------------------------- + +struct wxColWidthInfo +{ + int nMaxWidth; + bool bNeedsUpdate; // only set to true when an item whose + // width == nMaxWidth is removed + + wxColWidthInfo(int w = 0, bool needsUpdate = false) + { + nMaxWidth = w; + bNeedsUpdate = needsUpdate; + } +}; + +WX_DEFINE_ARRAY_PTR(wxColWidthInfo *, ColWidthArray); + +//----------------------------------------------------------------------------- +// wxListItemData (internal) +//----------------------------------------------------------------------------- + +class wxListItemData +{ +public: + wxListItemData(wxListMainWindow *owner); + ~wxListItemData(); + + void SetItem( const wxListItem &info ); + void SetImage( int image ) { m_image = image; } + void SetData( wxUIntPtr data ) { m_data = data; } + void SetPosition( int x, int y ); + void SetSize( int width, int height ); + + bool HasText() const { return !m_text.empty(); } + const wxString& GetText() const { return m_text; } + void SetText(const wxString& text) { m_text = text; } + + // we can't use empty string for measuring the string width/height, so + // always return something + wxString GetTextForMeasuring() const + { + wxString s = GetText(); + if ( s.empty() ) + s = _T('H'); + + return s; + } + + bool IsHit( int x, int y ) const; + + int GetX() const; + int GetY() const; + int GetWidth() const; + int GetHeight() const; + + int GetImage() const { return m_image; } + bool HasImage() const { return GetImage() != -1; } + + void GetItem( wxListItem &info ) const; + + void SetAttr(wxListItemAttr *attr) { m_attr = attr; } + wxListItemAttr *GetAttr() const { return m_attr; } + +public: + // the item image or -1 + int m_image; + + // user data associated with the item + wxUIntPtr m_data; + + // the item coordinates are not used in report mode; instead this pointer is + // NULL and the owner window is used to retrieve the item position and size + wxRect *m_rect; + + // the list ctrl we are in + wxListMainWindow *m_owner; + + // custom attributes or NULL + wxListItemAttr *m_attr; + +protected: + // common part of all ctors + void Init(); + + wxString m_text; +}; + +//----------------------------------------------------------------------------- +// wxListHeaderData (internal) +//----------------------------------------------------------------------------- + +class wxListHeaderData : public wxObject +{ +public: + wxListHeaderData(); + wxListHeaderData( const wxListItem &info ); + void SetItem( const wxListItem &item ); + void SetPosition( int x, int y ); + void SetWidth( int w ); + void SetState( int state ); + void SetFormat( int format ); + void SetHeight( int h ); + bool HasImage() const; + + bool HasText() const { return !m_text.empty(); } + const wxString& GetText() const { return m_text; } + void SetText(const wxString& text) { m_text = text; } + + void GetItem( wxListItem &item ); + + bool IsHit( int x, int y ) const; + int GetImage() const; + int GetWidth() const; + int GetFormat() const; + int GetState() const; + +protected: + long m_mask; + int m_image; + wxString m_text; + int m_format; + int m_width; + int m_xpos, + m_ypos; + int m_height; + int m_state; + +private: + void Init(); +}; + +//----------------------------------------------------------------------------- +// wxListLineData (internal) +//----------------------------------------------------------------------------- + +WX_DECLARE_EXPORTED_LIST(wxListItemData, wxListItemDataList); +#include "wx/listimpl.cpp" +WX_DEFINE_LIST(wxListItemDataList) + +class wxListLineData +{ +public: + // the list of subitems: only may have more than one item in report mode + wxListItemDataList m_items; + + // this is not used in report view + struct GeometryInfo + { + // total item rect + wxRect m_rectAll; + + // label only + wxRect m_rectLabel; + + // icon only + wxRect m_rectIcon; + + // the part to be highlighted + wxRect m_rectHighlight; + + // extend all our rects to be centered inside the one of given width + void ExtendWidth(wxCoord w) + { + wxASSERT_MSG( m_rectAll.width <= w, + _T("width can only be increased") ); + + m_rectAll.width = w; + m_rectLabel.x = m_rectAll.x + (w - m_rectLabel.width) / 2; + m_rectIcon.x = m_rectAll.x + (w - m_rectIcon.width) / 2; + m_rectHighlight.x = m_rectAll.x + (w - m_rectHighlight.width) / 2; + } + } + *m_gi; + + // is this item selected? [NB: not used in virtual mode] + bool m_highlighted; + + // back pointer to the list ctrl + wxListMainWindow *m_owner; + +public: + wxListLineData(wxListMainWindow *owner); + + ~wxListLineData() + { + WX_CLEAR_LIST(wxListItemDataList, m_items); + delete m_gi; + } + + // are we in report mode? + inline bool InReportView() const; + + // are we in virtual report mode? + inline bool IsVirtual() const; + + // these 2 methods shouldn't be called for report view controls, in that + // case we determine our position/size ourselves + + // calculate the size of the line + void CalculateSize( wxDC *dc, int spacing ); + + // remember the position this line appears at + void SetPosition( int x, int y, int spacing ); + + // wxListCtrl API + + void SetImage( int image ) { SetImage(0, image); } + int GetImage() const { return GetImage(0); } + void SetImage( int index, int image ); + int GetImage( int index ) const; + + bool HasImage() const { return GetImage() != -1; } + bool HasText() const { return !GetText(0).empty(); } + + void SetItem( int index, const wxListItem &info ); + void GetItem( int index, wxListItem &info ); + + wxString GetText(int index) const; + void SetText( int index, const wxString& s ); + + wxListItemAttr *GetAttr() const; + void SetAttr(wxListItemAttr *attr); + + // return true if the highlighting really changed + bool Highlight( bool on ); + + void ReverseHighlight(); + + bool IsHighlighted() const + { + wxASSERT_MSG( !IsVirtual(), _T("unexpected call to IsHighlighted") ); + + return m_highlighted; + } + + // draw the line on the given DC in icon/list mode + void Draw( wxDC *dc ); + + // the same in report mode + void DrawInReportMode( wxDC *dc, + const wxRect& rect, + const wxRect& rectHL, + bool highlighted ); + +private: + // set the line to contain num items (only can be > 1 in report mode) + void InitItems( int num ); + + // get the mode (i.e. style) of the list control + inline int GetMode() const; + + // prepare the DC for drawing with these item's attributes, return true if + // we need to draw the items background to highlight it, false otherwise + bool SetAttributes(wxDC *dc, + const wxListItemAttr *attr, + bool highlight); + + // draw the text on the DC with the correct justification; also add an + // ellipsis if the text is too large to fit in the current width + void DrawTextFormatted(wxDC *dc, + const wxString &text, + int col, + int x, + int yMid, // this is middle, not top, of the text + int width); +}; + +WX_DECLARE_EXPORTED_OBJARRAY(wxListLineData, wxListLineDataArray); +#include "wx/arrimpl.cpp" +WX_DEFINE_OBJARRAY(wxListLineDataArray) + +//----------------------------------------------------------------------------- +// wxListHeaderWindow (internal) +//----------------------------------------------------------------------------- + +class wxListHeaderWindow : public wxWindow +{ +protected: + wxListMainWindow *m_owner; + const wxCursor *m_currentCursor; + wxCursor *m_resizeCursor; + bool m_isDragging; + + // column being resized or -1 + int m_column; + + // divider line position in logical (unscrolled) coords + int m_currentX; + + // minimal position beyond which the divider line + // can't be dragged in logical coords + int m_minX; + +public: + wxListHeaderWindow(); + + wxListHeaderWindow( wxWindow *win, + wxWindowID id, + wxListMainWindow *owner, + const wxPoint &pos = wxDefaultPosition, + const wxSize &size = wxDefaultSize, + long style = 0, + const wxString &name = wxT("wxlistctrlcolumntitles") ); + + virtual ~wxListHeaderWindow(); + + void DrawCurrent(); + void AdjustDC( wxDC& dc ); + + void OnPaint( wxPaintEvent &event ); + void OnMouse( wxMouseEvent &event ); + void OnSetFocus( wxFocusEvent &event ); + + // needs refresh + bool m_dirty; + +private: + // common part of all ctors + void Init(); + + // generate and process the list event of the given type, return true if + // it wasn't vetoed, i.e. if we should proceed + bool SendListEvent(wxEventType type, const wxPoint& pos); + + DECLARE_DYNAMIC_CLASS(wxListHeaderWindow) + DECLARE_EVENT_TABLE() +}; + +//----------------------------------------------------------------------------- +// wxListRenameTimer (internal) +//----------------------------------------------------------------------------- + +class wxListRenameTimer: public wxTimer +{ +private: + wxListMainWindow *m_owner; + +public: + wxListRenameTimer( wxListMainWindow *owner ); + void Notify(); +}; + +//----------------------------------------------------------------------------- +// wxListTextCtrlWrapper: wraps a wxTextCtrl to make it work for inline editing +//----------------------------------------------------------------------------- + +class wxListTextCtrlWrapper : public wxEvtHandler +{ +public: + // NB: text must be a valid object but not Create()d yet + wxListTextCtrlWrapper(wxListMainWindow *owner, + wxTextCtrl *text, + size_t itemEdit); + + wxTextCtrl *GetText() const { return m_text; } + + void AcceptChangesAndFinish(); + +protected: + void OnChar( wxKeyEvent &event ); + void OnKeyUp( wxKeyEvent &event ); + void OnKillFocus( wxFocusEvent &event ); + + bool AcceptChanges(); + void Finish(); + +private: + wxListMainWindow *m_owner; + wxTextCtrl *m_text; + wxString m_startValue; + size_t m_itemEdited; + bool m_finished; + bool m_aboutToFinish; + + DECLARE_EVENT_TABLE() +}; + +//----------------------------------------------------------------------------- +// wxListMainWindow (internal) +//----------------------------------------------------------------------------- + +WX_DECLARE_EXPORTED_LIST(wxListHeaderData, wxListHeaderDataList); +#include "wx/listimpl.cpp" +WX_DEFINE_LIST(wxListHeaderDataList) + +class wxListMainWindow : public wxScrolledWindow +{ +public: + wxListMainWindow(); + wxListMainWindow( wxWindow *parent, + wxWindowID id, + const wxPoint& pos = wxDefaultPosition, + const wxSize& size = wxDefaultSize, + long style = 0, + const wxString &name = _T("listctrlmainwindow") ); + + virtual ~wxListMainWindow(); + + bool HasFlag(int flag) const { return m_parent->HasFlag(flag); } + + // return true if this is a virtual list control + bool IsVirtual() const { return HasFlag(wxLC_VIRTUAL); } + + // return true if the control is in report mode + bool InReportView() const { return HasFlag(wxLC_REPORT); } + + // return true if we are in single selection mode, false if multi sel + bool IsSingleSel() const { return HasFlag(wxLC_SINGLE_SEL); } + + // do we have a header window? + bool HasHeader() const + { return InReportView() && !HasFlag(wxLC_NO_HEADER); } + + void HighlightAll( bool on ); + + // all these functions only do something if the line is currently visible + + // change the line "selected" state, return true if it really changed + bool HighlightLine( size_t line, bool highlight = true); + + // as HighlightLine() but do it for the range of lines: this is incredibly + // more efficient for virtual list controls! + // + // NB: unlike HighlightLine() this one does refresh the lines on screen + void HighlightLines( size_t lineFrom, size_t lineTo, bool on = true ); + + // toggle the line state and refresh it + void ReverseHighlight( size_t line ) + { HighlightLine(line, !IsHighlighted(line)); RefreshLine(line); } + + // return true if the line is highlighted + bool IsHighlighted(size_t line) const; + + // refresh one or several lines at once + void RefreshLine( size_t line ); + void RefreshLines( size_t lineFrom, size_t lineTo ); + + // refresh all selected items + void RefreshSelected(); + + // refresh all lines below the given one: the difference with + // RefreshLines() is that the index here might not be a valid one (happens + // when the last line is deleted) + void RefreshAfter( size_t lineFrom ); + + // the methods which are forwarded to wxListLineData itself in list/icon + // modes but are here because the lines don't store their positions in the + // report mode + + // get the bound rect for the entire line + wxRect GetLineRect(size_t line) const; + + // get the bound rect of the label + wxRect GetLineLabelRect(size_t line) const; + + // get the bound rect of the items icon (only may be called if we do have + // an icon!) + wxRect GetLineIconRect(size_t line) const; + + // get the rect to be highlighted when the item has focus + wxRect GetLineHighlightRect(size_t line) const; + + // get the size of the total line rect + wxSize GetLineSize(size_t line) const + { return GetLineRect(line).GetSize(); } + + // return the hit code for the corresponding position (in this line) + long HitTestLine(size_t line, int x, int y) const; + + // bring the selected item into view, scrolling to it if necessary + void MoveToItem(size_t item); + + bool ScrollList( int WXUNUSED(dx), int dy ); + + // bring the current item into view + void MoveToFocus() { MoveToItem(m_current); } + + // start editing the label of the given item + wxTextCtrl *EditLabel(long item, + wxClassInfo* textControlClass = CLASSINFO(wxTextCtrl)); + wxTextCtrl *GetEditControl() const + { + return m_textctrlWrapper ? m_textctrlWrapper->GetText() : NULL; + } + + void FinishEditing(wxTextCtrl *text) + { + delete text; + m_textctrlWrapper = NULL; + SetFocusIgnoringChildren(); + } + + // suspend/resume redrawing the control + void Freeze(); + void Thaw(); + + void OnRenameTimer(); + bool OnRenameAccept(size_t itemEdit, const wxString& value); + void OnRenameCancelled(size_t itemEdit); + + void OnMouse( wxMouseEvent &event ); + + // called to switch the selection from the current item to newCurrent, + void OnArrowChar( size_t newCurrent, const wxKeyEvent& event ); + + void OnChar( wxKeyEvent &event ); + void OnKeyDown( wxKeyEvent &event ); + void OnKeyUp( wxKeyEvent &event ); + void OnSetFocus( wxFocusEvent &event ); + void OnKillFocus( wxFocusEvent &event ); + void OnScroll( wxScrollWinEvent& event ); + + void OnPaint( wxPaintEvent &event ); + + void DrawImage( int index, wxDC *dc, int x, int y ); + void GetImageSize( int index, int &width, int &height ) const; + int GetTextLength( const wxString &s ) const; + + void SetImageList( wxImageList *imageList, int which ); + void SetItemSpacing( int spacing, bool isSmall = false ); + int GetItemSpacing( bool isSmall = false ); + + void SetColumn( int col, wxListItem &item ); + void SetColumnWidth( int col, int width ); + void GetColumn( int col, wxListItem &item ) const; + int GetColumnWidth( int col ) const; + int GetColumnCount() const { return m_columns.GetCount(); } + + // returns the sum of the heights of all columns + int GetHeaderWidth() const; + + int GetCountPerPage() const; + + void SetItem( wxListItem &item ); + void GetItem( wxListItem &item ) const; + void SetItemState( long item, long state, long stateMask ); + void SetItemStateAll( long state, long stateMask ); + int GetItemState( long item, long stateMask ) const; + void GetItemRect( long index, wxRect &rect ) const; + wxRect GetViewRect() const; + bool GetItemPosition( long item, wxPoint& pos ) const; + int GetSelectedItemCount() const; + + wxString GetItemText(long item) const + { + wxListItem info; + info.m_mask = wxLIST_MASK_TEXT; + info.m_itemId = item; + GetItem( info ); + return info.m_text; + } + + void SetItemText(long item, const wxString& value) + { + wxListItem info; + info.m_mask = wxLIST_MASK_TEXT; + info.m_itemId = item; + info.m_text = value; + SetItem( info ); + } + + // set the scrollbars and update the positions of the items + void RecalculatePositions(bool noRefresh = false); + + // refresh the window and the header + void RefreshAll(); + + long GetNextItem( long item, int geometry, int state ) const; + void DeleteItem( long index ); + void DeleteAllItems(); + void DeleteColumn( int col ); + void DeleteEverything(); + void EnsureVisible( long index ); + long FindItem( long start, const wxString& str, bool partial = false ); + long FindItem( long start, wxUIntPtr data); + long FindItem( const wxPoint& pt ); + long HitTest( int x, int y, int &flags ) const; + void InsertItem( wxListItem &item ); + void InsertColumn( long col, wxListItem &item ); + int GetItemWidthWithImage(wxListItem * item); + void SortItems( wxListCtrlCompare fn, long data ); + + size_t GetItemCount() const; + bool IsEmpty() const { return GetItemCount() == 0; } + void SetItemCount(long count); + + // change the current (== focused) item, send a notification event + void ChangeCurrent(size_t current); + void ResetCurrent() { ChangeCurrent((size_t)-1); } + bool HasCurrent() const { return m_current != (size_t)-1; } + + // send out a wxListEvent + void SendNotify( size_t line, + wxEventType command, + const wxPoint& point = wxDefaultPosition ); + + // override base class virtual to reset m_lineHeight when the font changes + virtual bool SetFont(const wxFont& font) + { + if ( !wxScrolledWindow::SetFont(font) ) + return false; + + m_lineHeight = 0; + + return true; + } + + // these are for wxListLineData usage only + + // get the backpointer to the list ctrl + wxGenericListCtrl *GetListCtrl() const + { + return wxStaticCast(GetParent(), wxGenericListCtrl); + } + + // get the height of all lines (assuming they all do have the same height) + wxCoord GetLineHeight() const; + + // get the y position of the given line (only for report view) + wxCoord GetLineY(size_t line) const; + + // get the brush to use for the item highlighting + wxBrush *GetHighlightBrush() const + { + return m_hasFocus ? m_highlightBrush : m_highlightUnfocusedBrush; + } + + bool HasFocus() const + { + return m_hasFocus; + } + +//protected: + // the array of all line objects for a non virtual list control (for the + // virtual list control we only ever use m_lines[0]) + wxListLineDataArray m_lines; + + // the list of column objects + wxListHeaderDataList m_columns; + + // currently focused item or -1 + size_t m_current; + + // the number of lines per page + int m_linesPerPage; + + // this flag is set when something which should result in the window + // redrawing happens (i.e. an item was added or deleted, or its appearance + // changed) and OnPaint() doesn't redraw the window while it is set which + // allows to minimize the number of repaintings when a lot of items are + // being added. The real repainting occurs only after the next OnIdle() + // call + bool m_dirty; + + wxColour *m_highlightColour; + wxImageList *m_small_image_list; + wxImageList *m_normal_image_list; + int m_small_spacing; + int m_normal_spacing; + bool m_hasFocus; + + bool m_lastOnSame; + wxTimer *m_renameTimer; + bool m_isCreated; + int m_dragCount; + wxPoint m_dragStart; + ColWidthArray m_aColWidths; + + // for double click logic + size_t m_lineLastClicked, + m_lineBeforeLastClicked, + m_lineSelectSingleOnUp; + +protected: + wxWindow *GetMainWindowOfCompositeControl() { return GetParent(); } + + // the total count of items in a virtual list control + size_t m_countVirt; + + // the object maintaining the items selection state, only used in virtual + // controls + wxSelectionStore m_selStore; + + // common part of all ctors + void Init(); + + // get the line data for the given index + wxListLineData *GetLine(size_t n) const + { + wxASSERT_MSG( n != (size_t)-1, _T("invalid line index") ); + + if ( IsVirtual() ) + { + wxConstCast(this, wxListMainWindow)->CacheLineData(n); + n = 0; + } + + return &m_lines[n]; + } + + // get a dummy line which can be used for geometry calculations and such: + // you must use GetLine() if you want to really draw the line + wxListLineData *GetDummyLine() const; + + // cache the line data of the n-th line in m_lines[0] + void CacheLineData(size_t line); + + // get the range of visible lines + void GetVisibleLinesRange(size_t *from, size_t *to); + + // force us to recalculate the range of visible lines + void ResetVisibleLinesRange() { m_lineFrom = (size_t)-1; } + + // get the colour to be used for drawing the rules + wxColour GetRuleColour() const + { + return wxSystemSettings::GetColour(wxSYS_COLOUR_3DLIGHT); + } + +private: + // initialize the current item if needed + void UpdateCurrent(); + + // delete all items but don't refresh: called from dtor + void DoDeleteAllItems(); + + // the height of one line using the current font + wxCoord m_lineHeight; + + // the total header width or 0 if not calculated yet + wxCoord m_headerWidth; + + // the first and last lines being shown on screen right now (inclusive), + // both may be -1 if they must be calculated so never access them directly: + // use GetVisibleLinesRange() above instead + size_t m_lineFrom, + m_lineTo; + + // the brushes to use for item highlighting when we do/don't have focus + wxBrush *m_highlightBrush, + *m_highlightUnfocusedBrush; + + // if this is > 0, the control is frozen and doesn't redraw itself + size_t m_freezeCount; + + // wrapper around the text control currently used for in place editing or + // NULL if no item is being edited + wxListTextCtrlWrapper *m_textctrlWrapper; + + + DECLARE_DYNAMIC_CLASS(wxListMainWindow) + DECLARE_EVENT_TABLE() + + friend class wxGenericListCtrl; +}; + + +wxListItemData::~wxListItemData() +{ + // in the virtual list control the attributes are managed by the main + // program, so don't delete them + if ( !m_owner->IsVirtual() ) + delete m_attr; + + delete m_rect; +} + +void wxListItemData::Init() +{ + m_image = -1; + m_data = 0; + + m_attr = NULL; +} + +wxListItemData::wxListItemData(wxListMainWindow *owner) +{ + Init(); + + m_owner = owner; + + if ( owner->InReportView() ) + m_rect = NULL; + else + m_rect = new wxRect; +} + +void wxListItemData::SetItem( const wxListItem &info ) +{ + if ( info.m_mask & wxLIST_MASK_TEXT ) + SetText(info.m_text); + if ( info.m_mask & wxLIST_MASK_IMAGE ) + m_image = info.m_image; + if ( info.m_mask & wxLIST_MASK_DATA ) + m_data = info.m_data; + + if ( info.HasAttributes() ) + { + if ( m_attr ) + m_attr->AssignFrom(*info.GetAttributes()); + else + m_attr = new wxListItemAttr(*info.GetAttributes()); + } + + if ( m_rect ) + { + m_rect->x = + m_rect->y = + m_rect->height = 0; + m_rect->width = info.m_width; + } +} + +void wxListItemData::SetPosition( int x, int y ) +{ + wxCHECK_RET( m_rect, _T("unexpected SetPosition() call") ); + + m_rect->x = x; + m_rect->y = y; +} + +void wxListItemData::SetSize( int width, int height ) +{ + wxCHECK_RET( m_rect, _T("unexpected SetSize() call") ); + + if ( width != -1 ) + m_rect->width = width; + if ( height != -1 ) + m_rect->height = height; +} + +bool wxListItemData::IsHit( int x, int y ) const +{ + wxCHECK_MSG( m_rect, false, _T("can't be called in this mode") ); + + return wxRect(GetX(), GetY(), GetWidth(), GetHeight()).Contains(x, y); +} + +int wxListItemData::GetX() const +{ + wxCHECK_MSG( m_rect, 0, _T("can't be called in this mode") ); + + return m_rect->x; +} + +int wxListItemData::GetY() const +{ + wxCHECK_MSG( m_rect, 0, _T("can't be called in this mode") ); + + return m_rect->y; +} + +int wxListItemData::GetWidth() const +{ + wxCHECK_MSG( m_rect, 0, _T("can't be called in this mode") ); + + return m_rect->width; +} + +int wxListItemData::GetHeight() const +{ + wxCHECK_MSG( m_rect, 0, _T("can't be called in this mode") ); + + return m_rect->height; +} + +void wxListItemData::GetItem( wxListItem &info ) const +{ + long mask = info.m_mask; + if ( !mask ) + // by default, get everything for backwards compatibility + mask = -1; + + if ( mask & wxLIST_MASK_TEXT ) + info.m_text = m_text; + if ( mask & wxLIST_MASK_IMAGE ) + info.m_image = m_image; + if ( mask & wxLIST_MASK_DATA ) + info.m_data = m_data; + + if ( m_attr ) + { + if ( m_attr->HasTextColour() ) + info.SetTextColour(m_attr->GetTextColour()); + if ( m_attr->HasBackgroundColour() ) + info.SetBackgroundColour(m_attr->GetBackgroundColour()); + if ( m_attr->HasFont() ) + info.SetFont(m_attr->GetFont()); + } +} + +//----------------------------------------------------------------------------- +// wxListHeaderData +//----------------------------------------------------------------------------- + +void wxListHeaderData::Init() +{ + m_mask = 0; + m_image = -1; + m_format = 0; + m_width = 0; + m_xpos = 0; + m_ypos = 0; + m_height = 0; + m_state = 0; +} + +wxListHeaderData::wxListHeaderData() +{ + Init(); +} + +wxListHeaderData::wxListHeaderData( const wxListItem &item ) +{ + Init(); + + SetItem( item ); +} + +void wxListHeaderData::SetItem( const wxListItem &item ) +{ + m_mask = item.m_mask; + + if ( m_mask & wxLIST_MASK_TEXT ) + m_text = item.m_text; + + if ( m_mask & wxLIST_MASK_IMAGE ) + m_image = item.m_image; + + if ( m_mask & wxLIST_MASK_FORMAT ) + m_format = item.m_format; + + if ( m_mask & wxLIST_MASK_WIDTH ) + SetWidth(item.m_width); + + if ( m_mask & wxLIST_MASK_STATE ) + SetState(item.m_state); +} + +void wxListHeaderData::SetPosition( int x, int y ) +{ + m_xpos = x; + m_ypos = y; +} + +void wxListHeaderData::SetHeight( int h ) +{ + m_height = h; +} + +void wxListHeaderData::SetWidth( int w ) +{ + m_width = w < 0 ? WIDTH_COL_DEFAULT : w; +} + +void wxListHeaderData::SetState( int flag ) +{ + m_state = flag; +} + +void wxListHeaderData::SetFormat( int format ) +{ + m_format = format; +} + +bool wxListHeaderData::HasImage() const +{ + return m_image != -1; +} + +bool wxListHeaderData::IsHit( int x, int y ) const +{ + return ((x >= m_xpos) && (x <= m_xpos+m_width) && (y >= m_ypos) && (y <= m_ypos+m_height)); +} + +void wxListHeaderData::GetItem( wxListItem& item ) +{ + item.m_mask = m_mask; + item.m_text = m_text; + item.m_image = m_image; + item.m_format = m_format; + item.m_width = m_width; + item.m_state = m_state; +} + +int wxListHeaderData::GetImage() const +{ + return m_image; +} + +int wxListHeaderData::GetWidth() const +{ + return m_width; +} + +int wxListHeaderData::GetFormat() const +{ + return m_format; +} + +int wxListHeaderData::GetState() const +{ + return m_state; +} + +//----------------------------------------------------------------------------- +// wxListLineData +//----------------------------------------------------------------------------- + +inline int wxListLineData::GetMode() const +{ + return m_owner->GetListCtrl()->GetWindowStyleFlag() & wxLC_MASK_TYPE; +} + +inline bool wxListLineData::InReportView() const +{ + return m_owner->HasFlag(wxLC_REPORT); +} + +inline bool wxListLineData::IsVirtual() const +{ + return m_owner->IsVirtual(); +} + +wxListLineData::wxListLineData( wxListMainWindow *owner ) +{ + m_owner = owner; + + if ( InReportView() ) + m_gi = NULL; + else // !report + m_gi = new GeometryInfo; + + m_highlighted = false; + + InitItems( GetMode() == wxLC_REPORT ? m_owner->GetColumnCount() : 1 ); +} + +void wxListLineData::CalculateSize( wxDC *dc, int spacing ) +{ + wxListItemDataList::compatibility_iterator node = m_items.GetFirst(); + wxCHECK_RET( node, _T("no subitems at all??") ); + + wxListItemData *item = node->GetData(); + + wxString s; + wxCoord lw, lh; + + switch ( GetMode() ) + { + case wxLC_ICON: + case wxLC_SMALL_ICON: + m_gi->m_rectAll.width = spacing; + + s = item->GetText(); + + if ( s.empty() ) + { + lh = + m_gi->m_rectLabel.width = + m_gi->m_rectLabel.height = 0; + } + else // has label + { + dc->GetTextExtent( s, &lw, &lh ); + lw += EXTRA_WIDTH; + lh += EXTRA_HEIGHT; + + m_gi->m_rectAll.height = spacing + lh; + if (lw > spacing) + m_gi->m_rectAll.width = lw; + + m_gi->m_rectLabel.width = lw; + m_gi->m_rectLabel.height = lh; + } + + if (item->HasImage()) + { + int w, h; + m_owner->GetImageSize( item->GetImage(), w, h ); + m_gi->m_rectIcon.width = w + 8; + m_gi->m_rectIcon.height = h + 8; + + if ( m_gi->m_rectIcon.width > m_gi->m_rectAll.width ) + m_gi->m_rectAll.width = m_gi->m_rectIcon.width; + if ( m_gi->m_rectIcon.height + lh > m_gi->m_rectAll.height - 4 ) + m_gi->m_rectAll.height = m_gi->m_rectIcon.height + lh + 4; + } + + if ( item->HasText() ) + { + m_gi->m_rectHighlight.width = m_gi->m_rectLabel.width; + m_gi->m_rectHighlight.height = m_gi->m_rectLabel.height; + } + else // no text, highlight the icon + { + m_gi->m_rectHighlight.width = m_gi->m_rectIcon.width; + m_gi->m_rectHighlight.height = m_gi->m_rectIcon.height; + } + break; + + case wxLC_LIST: + s = item->GetTextForMeasuring(); + + dc->GetTextExtent( s, &lw, &lh ); + lw += EXTRA_WIDTH; + lh += EXTRA_HEIGHT; + + m_gi->m_rectLabel.width = lw; + m_gi->m_rectLabel.height = lh; + + m_gi->m_rectAll.width = lw; + m_gi->m_rectAll.height = lh; + + if (item->HasImage()) + { + int w, h; + m_owner->GetImageSize( item->GetImage(), w, h ); + m_gi->m_rectIcon.width = w; + m_gi->m_rectIcon.height = h; + + m_gi->m_rectAll.width += 4 + w; + if (h > m_gi->m_rectAll.height) + m_gi->m_rectAll.height = h; + } + + m_gi->m_rectHighlight.width = m_gi->m_rectAll.width; + m_gi->m_rectHighlight.height = m_gi->m_rectAll.height; + break; + + case wxLC_REPORT: + wxFAIL_MSG( _T("unexpected call to SetSize") ); + break; + + default: + wxFAIL_MSG( _T("unknown mode") ); + break; + } +} + +void wxListLineData::SetPosition( int x, int y, int spacing ) +{ + wxListItemDataList::compatibility_iterator node = m_items.GetFirst(); + wxCHECK_RET( node, _T("no subitems at all??") ); + + wxListItemData *item = node->GetData(); + + switch ( GetMode() ) + { + case wxLC_ICON: + case wxLC_SMALL_ICON: + m_gi->m_rectAll.x = x; + m_gi->m_rectAll.y = y; + + if ( item->HasImage() ) + { + m_gi->m_rectIcon.x = m_gi->m_rectAll.x + 4 + + (m_gi->m_rectAll.width - m_gi->m_rectIcon.width) / 2; + m_gi->m_rectIcon.y = m_gi->m_rectAll.y + 4; + } + + if ( item->HasText() ) + { + if (m_gi->m_rectAll.width > spacing) + m_gi->m_rectLabel.x = m_gi->m_rectAll.x + (EXTRA_WIDTH/2); + else + m_gi->m_rectLabel.x = m_gi->m_rectAll.x + (EXTRA_WIDTH/2) + (spacing / 2) - (m_gi->m_rectLabel.width / 2); + m_gi->m_rectLabel.y = m_gi->m_rectAll.y + m_gi->m_rectAll.height + 2 - m_gi->m_rectLabel.height; + m_gi->m_rectHighlight.x = m_gi->m_rectLabel.x - 2; + m_gi->m_rectHighlight.y = m_gi->m_rectLabel.y - 2; + } + else // no text, highlight the icon + { + m_gi->m_rectHighlight.x = m_gi->m_rectIcon.x - 4; + m_gi->m_rectHighlight.y = m_gi->m_rectIcon.y - 4; + } + break; + + case wxLC_LIST: + m_gi->m_rectAll.x = x; + m_gi->m_rectAll.y = y; + + m_gi->m_rectHighlight.x = m_gi->m_rectAll.x; + m_gi->m_rectHighlight.y = m_gi->m_rectAll.y; + m_gi->m_rectLabel.y = m_gi->m_rectAll.y + 2; + + if (item->HasImage()) + { + m_gi->m_rectIcon.x = m_gi->m_rectAll.x + 2; + m_gi->m_rectIcon.y = m_gi->m_rectAll.y + 2; + m_gi->m_rectLabel.x = m_gi->m_rectAll.x + 4 + (EXTRA_WIDTH/2) + m_gi->m_rectIcon.width; + } + else + { + m_gi->m_rectLabel.x = m_gi->m_rectAll.x + (EXTRA_WIDTH/2); + } + break; + + case wxLC_REPORT: + wxFAIL_MSG( _T("unexpected call to SetPosition") ); + break; + + default: + wxFAIL_MSG( _T("unknown mode") ); + break; + } +} + +void wxListLineData::InitItems( int num ) +{ + for (int i = 0; i < num; i++) + m_items.Append( new wxListItemData(m_owner) ); +} + +void wxListLineData::SetItem( int index, const wxListItem &info ) +{ + wxListItemDataList::compatibility_iterator node = m_items.Item( index ); + wxCHECK_RET( node, _T("invalid column index in SetItem") ); + + wxListItemData *item = node->GetData(); + item->SetItem( info ); +} + +void wxListLineData::GetItem( int index, wxListItem &info ) +{ + wxListItemDataList::compatibility_iterator node = m_items.Item( index ); + if (node) + { + wxListItemData *item = node->GetData(); + item->GetItem( info ); + } +} + +wxString wxListLineData::GetText(int index) const +{ + wxString s; + + wxListItemDataList::compatibility_iterator node = m_items.Item( index ); + if (node) + { + wxListItemData *item = node->GetData(); + s = item->GetText(); + } + + return s; +} + +void wxListLineData::SetText( int index, const wxString& s ) +{ + wxListItemDataList::compatibility_iterator node = m_items.Item( index ); + if (node) + { + wxListItemData *item = node->GetData(); + item->SetText( s ); + } +} + +void wxListLineData::SetImage( int index, int image ) +{ + wxListItemDataList::compatibility_iterator node = m_items.Item( index ); + wxCHECK_RET( node, _T("invalid column index in SetImage()") ); + + wxListItemData *item = node->GetData(); + item->SetImage(image); +} + +int wxListLineData::GetImage( int index ) const +{ + wxListItemDataList::compatibility_iterator node = m_items.Item( index ); + wxCHECK_MSG( node, -1, _T("invalid column index in GetImage()") ); + + wxListItemData *item = node->GetData(); + return item->GetImage(); +} + +wxListItemAttr *wxListLineData::GetAttr() const +{ + wxListItemDataList::compatibility_iterator node = m_items.GetFirst(); + wxCHECK_MSG( node, NULL, _T("invalid column index in GetAttr()") ); + + wxListItemData *item = node->GetData(); + return item->GetAttr(); +} + +void wxListLineData::SetAttr(wxListItemAttr *attr) +{ + wxListItemDataList::compatibility_iterator node = m_items.GetFirst(); + wxCHECK_RET( node, _T("invalid column index in SetAttr()") ); + + wxListItemData *item = node->GetData(); + item->SetAttr(attr); +} + +bool wxListLineData::SetAttributes(wxDC *dc, + const wxListItemAttr *attr, + bool highlighted) +{ + wxWindow *listctrl = m_owner->GetParent(); + + // fg colour + + // don't use foreground colour for drawing highlighted items - this might + // make them completely invisible (and there is no way to do bit + // arithmetics on wxColour, unfortunately) + wxColour colText; + if ( highlighted ) +#ifdef __WXMAC__ + { + if (m_owner->HasFocus() +#ifdef __WXMAC__ + && IsControlActive( (ControlRef)m_owner->GetHandle() ) +#endif + ) + colText = *wxWHITE; + else + colText = *wxBLACK; + } +#else + colText = wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT); +#endif + else if ( attr && attr->HasTextColour() ) + colText = attr->GetTextColour(); + else + colText = listctrl->GetForegroundColour(); + + dc->SetTextForeground(colText); + + // font + wxFont font; + if ( attr && attr->HasFont() ) + font = attr->GetFont(); + else + font = listctrl->GetFont(); + + dc->SetFont(font); + + // bg colour + bool hasBgCol = attr && attr->HasBackgroundColour(); + if ( highlighted || hasBgCol ) + { + if ( highlighted ) + dc->SetBrush( *m_owner->GetHighlightBrush() ); + else + dc->SetBrush(wxBrush(attr->GetBackgroundColour(), wxSOLID)); + + dc->SetPen( *wxTRANSPARENT_PEN ); + + return true; + } + + return false; +} + +void wxListLineData::Draw( wxDC *dc ) +{ + wxListItemDataList::compatibility_iterator node = m_items.GetFirst(); + wxCHECK_RET( node, _T("no subitems at all??") ); + + bool highlighted = IsHighlighted(); + + wxListItemAttr *attr = GetAttr(); + + if ( SetAttributes(dc, attr, highlighted) ) +#if ( !defined(__WXGTK20__) && !defined(__WXMAC__) ) + { + dc->DrawRectangle( m_gi->m_rectHighlight ); + } +#else + { + if (highlighted) + { + int flags = wxCONTROL_SELECTED; + if (m_owner->HasFocus() +#ifdef __WXMAC__ + && IsControlActive( (ControlRef)m_owner->GetHandle() ) +#endif + ) + flags |= wxCONTROL_FOCUSED; + wxRendererNative::Get().DrawItemSelectionRect( m_owner, *dc, m_gi->m_rectHighlight, flags ); + + } + else + { + dc->DrawRectangle( m_gi->m_rectHighlight ); + } + } +#endif + + // just for debugging to better see where the items are +#if 0 + dc->SetPen(*wxRED_PEN); + dc->SetBrush(*wxTRANSPARENT_BRUSH); + dc->DrawRectangle( m_gi->m_rectAll ); + dc->SetPen(*wxGREEN_PEN); + dc->DrawRectangle( m_gi->m_rectIcon ); +#endif + + wxListItemData *item = node->GetData(); + if (item->HasImage()) + { + // centre the image inside our rectangle, this looks nicer when items + // ae aligned in a row + const wxRect& rectIcon = m_gi->m_rectIcon; + + m_owner->DrawImage(item->GetImage(), dc, rectIcon.x, rectIcon.y); + } + + if (item->HasText()) + { + const wxRect& rectLabel = m_gi->m_rectLabel; + + wxDCClipper clipper(*dc, rectLabel); + dc->DrawText(item->GetText(), rectLabel.x, rectLabel.y); + } +} + +void wxListLineData::DrawInReportMode( wxDC *dc, + const wxRect& rect, + const wxRect& rectHL, + bool highlighted ) +{ + // TODO: later we should support setting different attributes for + // different columns - to do it, just add "col" argument to + // GetAttr() and move these lines into the loop below + wxListItemAttr *attr = GetAttr(); + if ( SetAttributes(dc, attr, highlighted) ) +#if ( !defined(__WXGTK20__) && !defined(__WXMAC__) ) + { + dc->DrawRectangle( rectHL ); + } +#else + { + if (highlighted) + { + int flags = wxCONTROL_SELECTED; + if (m_owner->HasFocus() +#ifdef __WXMAC__ + && IsControlActive( (ControlRef)m_owner->GetHandle() ) +#endif + ) + flags |= wxCONTROL_FOCUSED; + wxRendererNative::Get().DrawItemSelectionRect( m_owner, *dc, rectHL, flags ); + } + else + { + dc->DrawRectangle( rectHL ); + } + } +#endif + + wxCoord x = rect.x + HEADER_OFFSET_X, + yMid = rect.y + rect.height/2; +#ifdef __WXGTK__ + // This probably needs to be done + // on all platforms as the icons + // otherwise nearly touch the border + x += 2; +#endif + + size_t col = 0; + for ( wxListItemDataList::compatibility_iterator node = m_items.GetFirst(); + node; + node = node->GetNext(), col++ ) + { + wxListItemData *item = node->GetData(); + + int width = m_owner->GetColumnWidth(col); + int xOld = x; + x += width; + + if ( item->HasImage() ) + { + int ix, iy; + m_owner->GetImageSize( item->GetImage(), ix, iy ); + m_owner->DrawImage( item->GetImage(), dc, xOld, yMid - iy/2 ); + + ix += IMAGE_MARGIN_IN_REPORT_MODE; + + xOld += ix; + width -= ix; + } + + if ( item->HasText() ) + DrawTextFormatted(dc, item->GetText(), col, xOld, yMid, width - 8); + } +} + +void wxListLineData::DrawTextFormatted(wxDC *dc, + const wxString& textOrig, + int col, + int x, + int yMid, + int width) +{ + // we don't support displaying multiple lines currently (and neither does + // wxMSW FWIW) so just merge all the lines + wxString text(textOrig); + text.Replace(_T("\n"), _T(" ")); + + wxCoord w, h; + dc->GetTextExtent(text, &w, &h); + + const wxCoord y = yMid - (h + 1)/2; + + wxDCClipper clipper(*dc, x, y, width, h); + + // determine if the string can fit inside the current width + if (w <= width) + { + // it can, draw it using the items alignment + wxListItem item; + m_owner->GetColumn(col, item); + switch ( item.GetAlign() ) + { + case wxLIST_FORMAT_LEFT: + // nothing to do + break; + + case wxLIST_FORMAT_RIGHT: + x += width - w; + break; + + case wxLIST_FORMAT_CENTER: + x += (width - w) / 2; + break; + + default: + wxFAIL_MSG( _T("unknown list item format") ); + break; + } + + dc->DrawText(text, x, y); + } + else // otherwise, truncate and add an ellipsis if possible + { + // determine the base width + wxString ellipsis(wxT("...")); + wxCoord base_w; + dc->GetTextExtent(ellipsis, &base_w, &h); + + // continue until we have enough space or only one character left + wxCoord w_c, h_c; + size_t len = text.length(); + wxString drawntext = text.Left(len); + while (len > 1) + { + dc->GetTextExtent(drawntext.Last(), &w_c, &h_c); + drawntext.RemoveLast(); + len--; + w -= w_c; + if (w + base_w <= width) + break; + } + + // if still not enough space, remove ellipsis characters + while (ellipsis.length() > 0 && w + base_w > width) + { + ellipsis = ellipsis.Left(ellipsis.length() - 1); + dc->GetTextExtent(ellipsis, &base_w, &h); + } + + // now draw the text + dc->DrawText(drawntext, x, y); + dc->DrawText(ellipsis, x + w, y); + } +} + +bool wxListLineData::Highlight( bool on ) +{ + wxCHECK_MSG( !IsVirtual(), false, _T("unexpected call to Highlight") ); + + if ( on == m_highlighted ) + return false; + + m_highlighted = on; + + return true; +} + +void wxListLineData::ReverseHighlight( void ) +{ + Highlight(!IsHighlighted()); +} + +//----------------------------------------------------------------------------- +// wxListHeaderWindow +//----------------------------------------------------------------------------- + +IMPLEMENT_DYNAMIC_CLASS(wxListHeaderWindow,wxWindow) + +BEGIN_EVENT_TABLE(wxListHeaderWindow,wxWindow) + EVT_PAINT (wxListHeaderWindow::OnPaint) + EVT_MOUSE_EVENTS (wxListHeaderWindow::OnMouse) + EVT_SET_FOCUS (wxListHeaderWindow::OnSetFocus) +END_EVENT_TABLE() + +void wxListHeaderWindow::Init() +{ + m_currentCursor = (wxCursor *) NULL; + m_isDragging = false; + m_dirty = false; +} + +wxListHeaderWindow::wxListHeaderWindow() +{ + Init(); + + m_owner = (wxListMainWindow *) NULL; + m_resizeCursor = (wxCursor *) NULL; +} + +wxListHeaderWindow::wxListHeaderWindow( wxWindow *win, + wxWindowID id, + wxListMainWindow *owner, + const wxPoint& pos, + const wxSize& size, + long style, + const wxString &name ) + : wxWindow( win, id, pos, size, style, name ) +{ + Init(); + + m_owner = owner; + m_resizeCursor = new wxCursor( wxCURSOR_SIZEWE ); + +#if _USE_VISATTR + wxVisualAttributes attr = wxPanel::GetClassDefaultAttributes(); + SetOwnForegroundColour( attr.colFg ); + SetOwnBackgroundColour( attr.colBg ); + if (!m_hasFont) + SetOwnFont( attr.font ); +#else + SetOwnForegroundColour( wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT)); + SetOwnBackgroundColour( wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE)); + if (!m_hasFont) + SetOwnFont( wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT )); +#endif +} + +wxListHeaderWindow::~wxListHeaderWindow() +{ + delete m_resizeCursor; +} + +#ifdef __WXUNIVERSAL__ +#include "wx/univ/renderer.h" +#include "wx/univ/theme.h" +#endif + +// shift the DC origin to match the position of the main window horz +// scrollbar: this allows us to always use logical coords +void wxListHeaderWindow::AdjustDC(wxDC& dc) +{ + int xpix; + m_owner->GetScrollPixelsPerUnit( &xpix, NULL ); + + int view_start; + m_owner->GetViewStart( &view_start, NULL ); + + + int org_x = 0; + int org_y = 0; + dc.GetDeviceOrigin( &org_x, &org_y ); + + // account for the horz scrollbar offset +#ifdef __WXGTK__ + if (GetLayoutDirection() == wxLayout_RightToLeft) + { + // Maybe we just have to check for m_signX + // in the DC, but I leave the #ifdef __WXGTK__ + // for now + dc.SetDeviceOrigin( org_x + (view_start * xpix), org_y ); + } + else +#endif + dc.SetDeviceOrigin( org_x - (view_start * xpix), org_y ); +} + +void wxListHeaderWindow::OnPaint( wxPaintEvent &WXUNUSED(event) ) +{ + wxPaintDC dc( this ); + + PrepareDC( dc ); + AdjustDC( dc ); + + dc.SetFont( GetFont() ); + + // width and height of the entire header window + int w, h; + GetClientSize( &w, &h ); + m_owner->CalcUnscrolledPosition(w, 0, &w, NULL); + + dc.SetBackgroundMode(wxTRANSPARENT); + dc.SetTextForeground(GetForegroundColour()); + + int x = HEADER_OFFSET_X; + int numColumns = m_owner->GetColumnCount(); + wxListItem item; + for ( int i = 0; i < numColumns && x < w; i++ ) + { + m_owner->GetColumn( i, item ); + int wCol = item.m_width; + + int cw = wCol; + int ch = h; + + int flags = 0; + if (!m_parent->IsEnabled()) + flags |= wxCONTROL_DISABLED; + +// NB: The code below is not really Mac-specific, but since we are close +// to 2.8 release and I don't have time to test on other platforms, I +// defined this only for wxMac. If this behavior is desired on +// other platforms, please go ahead and revise or remove the #ifdef. +#ifdef __WXMAC__ + if ( !m_owner->IsVirtual() && (item.m_mask & wxLIST_MASK_STATE) && + (item.m_state & wxLIST_STATE_SELECTED) ) + flags |= wxCONTROL_SELECTED; +#endif + + wxRendererNative::Get().DrawHeaderButton + ( + this, + dc, + wxRect(x, HEADER_OFFSET_Y, cw, ch), + flags + ); + + // see if we have enough space for the column label + + // for this we need the width of the text + wxCoord wLabel; + wxCoord hLabel; + dc.GetTextExtent(item.GetText(), &wLabel, &hLabel); + wLabel += 2 * EXTRA_WIDTH; + + // and the width of the icon, if any + int ix = 0, iy = 0; // init them just to suppress the compiler warnings + const int image = item.m_image; + wxImageList *imageList; + if ( image != -1 ) + { + imageList = m_owner->m_small_image_list; + if ( imageList ) + { + imageList->GetSize(image, ix, iy); + wLabel += ix + HEADER_IMAGE_MARGIN_IN_REPORT_MODE; + } + } + else + { + imageList = NULL; + } + + // ignore alignment if there is not enough space anyhow + int xAligned; + switch ( wLabel < cw ? item.GetAlign() : wxLIST_FORMAT_LEFT ) + { + default: + wxFAIL_MSG( _T("unknown list item format") ); + // fall through + + case wxLIST_FORMAT_LEFT: + xAligned = x; + break; + + case wxLIST_FORMAT_RIGHT: + xAligned = x + cw - wLabel; + break; + + case wxLIST_FORMAT_CENTER: + xAligned = x + (cw - wLabel) / 2; + break; + } + + // draw the text and image clipping them so that they + // don't overwrite the column boundary + wxDCClipper clipper(dc, x, HEADER_OFFSET_Y, cw, h ); + + // if we have an image, draw it on the right of the label + if ( imageList ) + { + imageList->Draw + ( + image, + dc, + xAligned + wLabel - ix - HEADER_IMAGE_MARGIN_IN_REPORT_MODE, + HEADER_OFFSET_Y + (h - 4 - iy)/2, + wxIMAGELIST_DRAW_TRANSPARENT + ); + } + + dc.DrawText( item.GetText(), + xAligned + EXTRA_WIDTH, h / 2 - hLabel / 2 ); //HEADER_OFFSET_Y + EXTRA_HEIGHT ); + + x += wCol; + } +} + +void wxListHeaderWindow::DrawCurrent() +{ +#if 1 + m_owner->SetColumnWidth( m_column, m_currentX - m_minX ); +#else + int x1 = m_currentX; + int y1 = 0; + m_owner->ClientToScreen( &x1, &y1 ); + + int x2 = m_currentX; + int y2 = 0; + m_owner->GetClientSize( NULL, &y2 ); + m_owner->ClientToScreen( &x2, &y2 ); + + wxScreenDC dc; + dc.SetLogicalFunction( wxINVERT ); + dc.SetPen( wxPen( *wxBLACK, 2, wxSOLID ) ); + dc.SetBrush( *wxTRANSPARENT_BRUSH ); + + AdjustDC(dc); + + dc.DrawLine( x1, y1, x2, y2 ); + + dc.SetLogicalFunction( wxCOPY ); + + dc.SetPen( wxNullPen ); + dc.SetBrush( wxNullBrush ); +#endif +} + +void wxListHeaderWindow::OnMouse( wxMouseEvent &event ) +{ + // we want to work with logical coords + int x; + m_owner->CalcUnscrolledPosition(event.GetX(), 0, &x, NULL); + int y = event.GetY(); + + if (m_isDragging) + { + SendListEvent(wxEVT_COMMAND_LIST_COL_DRAGGING, event.GetPosition()); + + // we don't draw the line beyond our window, but we allow dragging it + // there + int w = 0; + GetClientSize( &w, NULL ); + m_owner->CalcUnscrolledPosition(w, 0, &w, NULL); + w -= 6; + + // erase the line if it was drawn + if ( m_currentX < w ) + DrawCurrent(); + + if (event.ButtonUp()) + { + ReleaseMouse(); + m_isDragging = false; + m_dirty = true; + m_owner->SetColumnWidth( m_column, m_currentX - m_minX ); + SendListEvent(wxEVT_COMMAND_LIST_COL_END_DRAG, event.GetPosition()); + } + else + { + if (x > m_minX + 7) + m_currentX = x; + else + m_currentX = m_minX + 7; + + // draw in the new location + if ( m_currentX < w ) + DrawCurrent(); + } + } + else // not dragging + { + m_minX = 0; + bool hit_border = false; + + // end of the current column + int xpos = 0; + + // find the column where this event occurred + int col, + countCol = m_owner->GetColumnCount(); + for (col = 0; col < countCol; col++) + { + xpos += m_owner->GetColumnWidth( col ); + m_column = col; + + if ( (abs(x-xpos) < 3) && (y < 22) ) + { + // near the column border + hit_border = true; + break; + } + + if ( x < xpos ) + { + // inside the column + break; + } + + m_minX = xpos; + } + + if ( col == countCol ) + m_column = -1; + + if (event.LeftDown() || event.RightUp()) + { + if (hit_border && event.LeftDown()) + { + if ( SendListEvent(wxEVT_COMMAND_LIST_COL_BEGIN_DRAG, + event.GetPosition()) ) + { + m_isDragging = true; + m_currentX = x; + CaptureMouse(); + DrawCurrent(); + } + //else: column resizing was vetoed by the user code + } + else // click on a column + { + // record the selected state of the columns + if (event.LeftDown()) + { + for (int i=0; i < m_owner->GetColumnCount(); i++) + { + wxListItem colItem; + m_owner->GetColumn(i, colItem); + long state = colItem.GetState(); + if (i == m_column) + colItem.SetState(state | wxLIST_STATE_SELECTED); + else + colItem.SetState(state & ~wxLIST_STATE_SELECTED); + m_owner->SetColumn(i, colItem); + } + } + + SendListEvent( event.LeftDown() + ? wxEVT_COMMAND_LIST_COL_CLICK + : wxEVT_COMMAND_LIST_COL_RIGHT_CLICK, + event.GetPosition()); + } + } + else if (event.Moving()) + { + bool setCursor; + if (hit_border) + { + setCursor = m_currentCursor == wxSTANDARD_CURSOR; + m_currentCursor = m_resizeCursor; + } + else + { + setCursor = m_currentCursor != wxSTANDARD_CURSOR; + m_currentCursor = wxSTANDARD_CURSOR; + } + + if ( setCursor ) + SetCursor(*m_currentCursor); + } + } +} + +void wxListHeaderWindow::OnSetFocus( wxFocusEvent &WXUNUSED(event) ) +{ + m_owner->SetFocus(); + m_owner->Update(); +} + +bool wxListHeaderWindow::SendListEvent(wxEventType type, const wxPoint& pos) +{ + wxWindow *parent = GetParent(); + wxListEvent le( type, parent->GetId() ); + le.SetEventObject( parent ); + le.m_pointDrag = pos; + + // the position should be relative to the parent window, not + // this one for compatibility with MSW and common sense: the + // user code doesn't know anything at all about this header + // window, so why should it get positions relative to it? + le.m_pointDrag.y -= GetSize().y; + + le.m_col = m_column; + return !parent->GetEventHandler()->ProcessEvent( le ) || le.IsAllowed(); +} + +//----------------------------------------------------------------------------- +// wxListRenameTimer (internal) +//----------------------------------------------------------------------------- + +wxListRenameTimer::wxListRenameTimer( wxListMainWindow *owner ) +{ + m_owner = owner; +} + +void wxListRenameTimer::Notify() +{ + m_owner->OnRenameTimer(); +} + +//----------------------------------------------------------------------------- +// wxListTextCtrlWrapper (internal) +//----------------------------------------------------------------------------- + +BEGIN_EVENT_TABLE(wxListTextCtrlWrapper, wxEvtHandler) + EVT_CHAR (wxListTextCtrlWrapper::OnChar) + EVT_KEY_UP (wxListTextCtrlWrapper::OnKeyUp) + EVT_KILL_FOCUS (wxListTextCtrlWrapper::OnKillFocus) +END_EVENT_TABLE() + +wxListTextCtrlWrapper::wxListTextCtrlWrapper(wxListMainWindow *owner, + wxTextCtrl *text, + size_t itemEdit) + : m_startValue(owner->GetItemText(itemEdit)), + m_itemEdited(itemEdit) +{ + m_owner = owner; + m_text = text; + m_finished = false; + m_aboutToFinish = false; + + wxRect rectLabel = owner->GetLineLabelRect(itemEdit); + + m_owner->CalcScrolledPosition(rectLabel.x, rectLabel.y, + &rectLabel.x, &rectLabel.y); + + m_text->Create(owner, wxID_ANY, m_startValue, + wxPoint(rectLabel.x-4,rectLabel.y-4), + wxSize(rectLabel.width+11,rectLabel.height+8)); + m_text->SetFocus(); + + m_text->PushEventHandler(this); +} + +void wxListTextCtrlWrapper::Finish() +{ + if ( !m_finished ) + { + m_finished = true; + + m_text->RemoveEventHandler(this); + m_owner->FinishEditing(m_text); + + wxPendingDelete.Append( this ); + } +} + +bool wxListTextCtrlWrapper::AcceptChanges() +{ + const wxString value = m_text->GetValue(); + + // notice that we should always call OnRenameAccept() to generate the "end + // label editing" event, even if the user hasn't really changed anything + if ( !m_owner->OnRenameAccept(m_itemEdited, value) ) + { + // vetoed by the user + return false; + } + + // accepted, do rename the item (unless nothing changed) + if ( value != m_startValue ) + m_owner->SetItemText(m_itemEdited, value); + + return true; +} + +void wxListTextCtrlWrapper::AcceptChangesAndFinish() +{ + m_aboutToFinish = true; + + // Notify the owner about the changes + AcceptChanges(); + + // Even if vetoed, close the control (consistent with MSW) + Finish(); +} + +void wxListTextCtrlWrapper::OnChar( wxKeyEvent &event ) +{ + switch ( event.m_keyCode ) + { + case WXK_RETURN: + AcceptChangesAndFinish(); + break; + + case WXK_ESCAPE: + m_owner->OnRenameCancelled( m_itemEdited ); + Finish(); + break; + + default: + event.Skip(); + } +} + +void wxListTextCtrlWrapper::OnKeyUp( wxKeyEvent &event ) +{ + if (m_finished) + { + event.Skip(); + return; + } + + // auto-grow the textctrl: + wxSize parentSize = m_owner->GetSize(); + wxPoint myPos = m_text->GetPosition(); + wxSize mySize = m_text->GetSize(); + int sx, sy; + m_text->GetTextExtent(m_text->GetValue() + _T("MM"), &sx, &sy); + if (myPos.x + sx > parentSize.x) + sx = parentSize.x - myPos.x; + if (mySize.x > sx) + sx = mySize.x; + m_text->SetSize(sx, wxDefaultCoord); + + event.Skip(); +} + +void wxListTextCtrlWrapper::OnKillFocus( wxFocusEvent &event ) +{ + if ( !m_finished && !m_aboutToFinish ) + { + if ( !AcceptChanges() ) + m_owner->OnRenameCancelled( m_itemEdited ); + + Finish(); + } + + // We must let the native text control handle focus + event.Skip(); +} + +//----------------------------------------------------------------------------- +// wxListMainWindow +//----------------------------------------------------------------------------- + +IMPLEMENT_DYNAMIC_CLASS(wxListMainWindow,wxScrolledWindow) + +BEGIN_EVENT_TABLE(wxListMainWindow,wxScrolledWindow) + EVT_PAINT (wxListMainWindow::OnPaint) + EVT_MOUSE_EVENTS (wxListMainWindow::OnMouse) + EVT_CHAR (wxListMainWindow::OnChar) + EVT_KEY_DOWN (wxListMainWindow::OnKeyDown) + EVT_KEY_UP (wxListMainWindow::OnKeyUp) + EVT_SET_FOCUS (wxListMainWindow::OnSetFocus) + EVT_KILL_FOCUS (wxListMainWindow::OnKillFocus) + EVT_SCROLLWIN (wxListMainWindow::OnScroll) +END_EVENT_TABLE() + +void wxListMainWindow::Init() +{ + m_dirty = true; + m_countVirt = 0; + m_lineFrom = + m_lineTo = (size_t)-1; + m_linesPerPage = 0; + + m_headerWidth = + m_lineHeight = 0; + + m_small_image_list = (wxImageList *) NULL; + m_normal_image_list = (wxImageList *) NULL; + + m_small_spacing = 30; + m_normal_spacing = 40; + + m_hasFocus = false; + m_dragCount = 0; + m_isCreated = false; + + m_lastOnSame = false; + m_renameTimer = new wxListRenameTimer( this ); + m_textctrlWrapper = NULL; + + m_current = + m_lineLastClicked = + m_lineSelectSingleOnUp = + m_lineBeforeLastClicked = (size_t)-1; + + m_freezeCount = 0; +} + +wxListMainWindow::wxListMainWindow() +{ + Init(); + + m_highlightBrush = + m_highlightUnfocusedBrush = (wxBrush *) NULL; +} + +wxListMainWindow::wxListMainWindow( wxWindow *parent, + wxWindowID id, + const wxPoint& pos, + const wxSize& size, + long style, + const wxString &name ) + : wxScrolledWindow( parent, id, pos, size, + style | wxHSCROLL | wxVSCROLL, name ) +{ + Init(); + + m_highlightBrush = new wxBrush + ( + wxSystemSettings::GetColour + ( + wxSYS_COLOUR_HIGHLIGHT + ), + wxSOLID + ); + + m_highlightUnfocusedBrush = new wxBrush + ( + wxSystemSettings::GetColour + ( + wxSYS_COLOUR_BTNSHADOW + ), + wxSOLID + ); + + SetScrollbars( 0, 0, 0, 0, 0, 0 ); + + wxVisualAttributes attr = wxGenericListCtrl::GetClassDefaultAttributes(); + SetOwnForegroundColour( attr.colFg ); + SetOwnBackgroundColour( attr.colBg ); + if (!m_hasFont) + SetOwnFont( attr.font ); +} + +wxListMainWindow::~wxListMainWindow() +{ + DoDeleteAllItems(); + WX_CLEAR_LIST(wxListHeaderDataList, m_columns); + WX_CLEAR_ARRAY(m_aColWidths); + + delete m_highlightBrush; + delete m_highlightUnfocusedBrush; + delete m_renameTimer; +} + +void wxListMainWindow::CacheLineData(size_t line) +{ + wxGenericListCtrl *listctrl = GetListCtrl(); + + wxListLineData *ld = GetDummyLine(); + + size_t countCol = GetColumnCount(); + for ( size_t col = 0; col < countCol; col++ ) + { + ld->SetText(col, listctrl->OnGetItemText(line, col)); + ld->SetImage(col, listctrl->OnGetItemColumnImage(line, col)); + } + + ld->SetAttr(listctrl->OnGetItemAttr(line)); +} + +wxListLineData *wxListMainWindow::GetDummyLine() const +{ + wxASSERT_MSG( !IsEmpty(), _T("invalid line index") ); + wxASSERT_MSG( IsVirtual(), _T("GetDummyLine() shouldn't be called") ); + + wxListMainWindow *self = wxConstCast(this, wxListMainWindow); + + // we need to recreate the dummy line if the number of columns in the + // control changed as it would have the incorrect number of fields + // otherwise + if ( !m_lines.IsEmpty() && + m_lines[0].m_items.GetCount() != (size_t)GetColumnCount() ) + { + self->m_lines.Clear(); + } + + if ( m_lines.IsEmpty() ) + { + wxListLineData *line = new wxListLineData(self); + self->m_lines.Add(line); + + // don't waste extra memory -- there never going to be anything + // else/more in this array + self->m_lines.Shrink(); + } + + return &m_lines[0]; +} + +// ---------------------------------------------------------------------------- +// line geometry (report mode only) +// ---------------------------------------------------------------------------- + +wxCoord wxListMainWindow::GetLineHeight() const +{ + // we cache the line height as calling GetTextExtent() is slow + if ( !m_lineHeight ) + { + wxListMainWindow *self = wxConstCast(this, wxListMainWindow); + + wxClientDC dc( self ); + dc.SetFont( GetFont() ); + + wxCoord y; + dc.GetTextExtent(_T("H"), NULL, &y); + + if ( m_small_image_list && m_small_image_list->GetImageCount() ) + { + int iw = 0, ih = 0; + m_small_image_list->GetSize(0, iw, ih); + y = wxMax(y, ih); + } + + y += EXTRA_HEIGHT; + self->m_lineHeight = y + LINE_SPACING; + } + + return m_lineHeight; +} + +wxCoord wxListMainWindow::GetLineY(size_t line) const +{ + wxASSERT_MSG( InReportView(), _T("only works in report mode") ); + + return LINE_SPACING + line * GetLineHeight(); +} + +wxRect wxListMainWindow::GetLineRect(size_t line) const +{ + if ( !InReportView() ) + return GetLine(line)->m_gi->m_rectAll; + + wxRect rect; + rect.x = HEADER_OFFSET_X; + rect.y = GetLineY(line); + rect.width = GetHeaderWidth(); + rect.height = GetLineHeight(); + + return rect; +} + +wxRect wxListMainWindow::GetLineLabelRect(size_t line) const +{ + if ( !InReportView() ) + return GetLine(line)->m_gi->m_rectLabel; + + int image_x = 0; + wxListLineData *data = GetLine(line); + wxListItemDataList::compatibility_iterator node = data->m_items.GetFirst(); + if (node) + { + wxListItemData *item = node->GetData(); + if ( item->HasImage() ) + { + int ix, iy; + GetImageSize( item->GetImage(), ix, iy ); + image_x = 3 + ix + IMAGE_MARGIN_IN_REPORT_MODE; + } + } + + wxRect rect; + rect.x = image_x + HEADER_OFFSET_X; + rect.y = GetLineY(line); + rect.width = GetColumnWidth(0) - image_x; + rect.height = GetLineHeight(); + + return rect; +} + +wxRect wxListMainWindow::GetLineIconRect(size_t line) const +{ + if ( !InReportView() ) + return GetLine(line)->m_gi->m_rectIcon; + + wxListLineData *ld = GetLine(line); + wxASSERT_MSG( ld->HasImage(), _T("should have an image") ); + + wxRect rect; + rect.x = HEADER_OFFSET_X; + rect.y = GetLineY(line); + GetImageSize(ld->GetImage(), rect.width, rect.height); + + return rect; +} + +wxRect wxListMainWindow::GetLineHighlightRect(size_t line) const +{ + return InReportView() ? GetLineRect(line) + : GetLine(line)->m_gi->m_rectHighlight; +} + +long wxListMainWindow::HitTestLine(size_t line, int x, int y) const +{ + wxASSERT_MSG( line < GetItemCount(), _T("invalid line in HitTestLine") ); + + wxListLineData *ld = GetLine(line); + + if ( ld->HasImage() && GetLineIconRect(line).Contains(x, y) ) + return wxLIST_HITTEST_ONITEMICON; + + // VS: Testing for "ld->HasText() || InReportView()" instead of + // "ld->HasText()" is needed to make empty lines in report view + // possible + if ( ld->HasText() || InReportView() ) + { + wxRect rect = InReportView() ? GetLineRect(line) + : GetLineLabelRect(line); + + if ( rect.Contains(x, y) ) + return wxLIST_HITTEST_ONITEMLABEL; + } + + return 0; +} + +// ---------------------------------------------------------------------------- +// highlight (selection) handling +// ---------------------------------------------------------------------------- + +bool wxListMainWindow::IsHighlighted(size_t line) const +{ + if ( IsVirtual() ) + { + return m_selStore.IsSelected(line); + } + else // !virtual + { + wxListLineData *ld = GetLine(line); + wxCHECK_MSG( ld, false, _T("invalid index in IsHighlighted") ); + + return ld->IsHighlighted(); + } +} + +void wxListMainWindow::HighlightLines( size_t lineFrom, + size_t lineTo, + bool highlight ) +{ + if ( IsVirtual() ) + { + wxArrayInt linesChanged; + if ( !m_selStore.SelectRange(lineFrom, lineTo, highlight, + &linesChanged) ) + { + // meny items changed state, refresh everything + RefreshLines(lineFrom, lineTo); + } + else // only a few items changed state, refresh only them + { + size_t count = linesChanged.GetCount(); + for ( size_t n = 0; n < count; n++ ) + { + RefreshLine(linesChanged[n]); + } + } + } + else // iterate over all items in non report view + { + for ( size_t line = lineFrom; line <= lineTo; line++ ) + { + if ( HighlightLine(line, highlight) ) + RefreshLine(line); + } + } +} + +bool wxListMainWindow::HighlightLine( size_t line, bool highlight ) +{ + bool changed; + + if ( IsVirtual() ) + { + changed = m_selStore.SelectItem(line, highlight); + } + else // !virtual + { + wxListLineData *ld = GetLine(line); + wxCHECK_MSG( ld, false, _T("invalid index in HighlightLine") ); + + changed = ld->Highlight(highlight); + } + + if ( changed ) + { + SendNotify( line, highlight ? wxEVT_COMMAND_LIST_ITEM_SELECTED + : wxEVT_COMMAND_LIST_ITEM_DESELECTED ); + } + + return changed; +} + +void wxListMainWindow::RefreshLine( size_t line ) +{ + if ( InReportView() ) + { + size_t visibleFrom, visibleTo; + GetVisibleLinesRange(&visibleFrom, &visibleTo); + + if ( line < visibleFrom || line > visibleTo ) + return; + } + + wxRect rect = GetLineRect(line); + + CalcScrolledPosition( rect.x, rect.y, &rect.x, &rect.y ); + RefreshRect( rect ); +} + +void wxListMainWindow::RefreshLines( size_t lineFrom, size_t lineTo ) +{ + // we suppose that they are ordered by caller + wxASSERT_MSG( lineFrom <= lineTo, _T("indices in disorder") ); + + wxASSERT_MSG( lineTo < GetItemCount(), _T("invalid line range") ); + + if ( InReportView() ) + { + size_t visibleFrom, visibleTo; + GetVisibleLinesRange(&visibleFrom, &visibleTo); + + if ( lineFrom < visibleFrom ) + lineFrom = visibleFrom; + if ( lineTo > visibleTo ) + lineTo = visibleTo; + + wxRect rect; + rect.x = 0; + rect.y = GetLineY(lineFrom); + rect.width = GetClientSize().x; + rect.height = GetLineY(lineTo) - rect.y + GetLineHeight(); + + CalcScrolledPosition( rect.x, rect.y, &rect.x, &rect.y ); + RefreshRect( rect ); + } + else // !report + { + // TODO: this should be optimized... + for ( size_t line = lineFrom; line <= lineTo; line++ ) + { + RefreshLine(line); + } + } +} + +void wxListMainWindow::RefreshAfter( size_t lineFrom ) +{ + if ( InReportView() ) + { + size_t visibleFrom, visibleTo; + GetVisibleLinesRange(&visibleFrom, &visibleTo); + + if ( lineFrom < visibleFrom ) + lineFrom = visibleFrom; + else if ( lineFrom > visibleTo ) + return; + + wxRect rect; + rect.x = 0; + rect.y = GetLineY(lineFrom); + CalcScrolledPosition( rect.x, rect.y, &rect.x, &rect.y ); + + wxSize size = GetClientSize(); + rect.width = size.x; + + // refresh till the bottom of the window + rect.height = size.y - rect.y; + + RefreshRect( rect ); + } + else // !report + { + // TODO: how to do it more efficiently? + m_dirty = true; + } +} + +void wxListMainWindow::RefreshSelected() +{ + if ( IsEmpty() ) + return; + + size_t from, to; + if ( InReportView() ) + { + GetVisibleLinesRange(&from, &to); + } + else // !virtual + { + from = 0; + to = GetItemCount() - 1; + } + + if ( HasCurrent() && m_current >= from && m_current <= to ) + RefreshLine(m_current); + + for ( size_t line = from; line <= to; line++ ) + { + // NB: the test works as expected even if m_current == -1 + if ( line != m_current && IsHighlighted(line) ) + RefreshLine(line); + } +} + +void wxListMainWindow::Freeze() +{ + m_freezeCount++; +} + +void wxListMainWindow::Thaw() +{ + wxCHECK_RET( m_freezeCount > 0, _T("thawing unfrozen list control?") ); + + if ( --m_freezeCount == 0 ) + Refresh(); +} + +void wxListMainWindow::OnPaint( wxPaintEvent &WXUNUSED(event) ) +{ + // Note: a wxPaintDC must be constructed even if no drawing is + // done (a Windows requirement). + wxPaintDC dc( this ); + + if ( IsEmpty() || m_freezeCount ) + // nothing to draw or not the moment to draw it + return; + + if ( m_dirty ) + // delay the repainting until we calculate all the items positions + return; + + PrepareDC( dc ); + + int dev_x, dev_y; + CalcScrolledPosition( 0, 0, &dev_x, &dev_y ); + + dc.SetFont( GetFont() ); + + if ( InReportView() ) + { + int lineHeight = GetLineHeight(); + + size_t visibleFrom, visibleTo; + GetVisibleLinesRange(&visibleFrom, &visibleTo); + + wxRect rectLine; + int xOrig = dc.LogicalToDeviceX( 0 ); + int yOrig = dc.LogicalToDeviceY( 0 ); + + // tell the caller cache to cache the data + if ( IsVirtual() ) + { + wxListEvent evCache(wxEVT_COMMAND_LIST_CACHE_HINT, + GetParent()->GetId()); + evCache.SetEventObject( GetParent() ); + evCache.m_oldItemIndex = visibleFrom; + evCache.m_itemIndex = visibleTo; + GetParent()->GetEventHandler()->ProcessEvent( evCache ); + } + + for ( size_t line = visibleFrom; line <= visibleTo; line++ ) + { + rectLine = GetLineRect(line); + + + if ( !IsExposed(rectLine.x + xOrig, rectLine.y + yOrig, + rectLine.width, rectLine.height) ) + { + // don't redraw unaffected lines to avoid flicker + continue; + } + + GetLine(line)->DrawInReportMode( &dc, + rectLine, + GetLineHighlightRect(line), + IsHighlighted(line) ); + } + + if ( HasFlag(wxLC_HRULES) ) + { + wxPen pen(GetRuleColour(), 1, wxSOLID); + wxSize clientSize = GetClientSize(); + + size_t i = visibleFrom; + if (i == 0) i = 1; // Don't draw the first one + for ( ; i <= visibleTo; i++ ) + { + dc.SetPen(pen); + dc.SetBrush( *wxTRANSPARENT_BRUSH ); + dc.DrawLine(0 - dev_x, i * lineHeight, + clientSize.x - dev_x, i * lineHeight); + } + + // Draw last horizontal rule + if ( visibleTo == GetItemCount() - 1 ) + { + dc.SetPen( pen ); + dc.SetBrush( *wxTRANSPARENT_BRUSH ); + dc.DrawLine(0 - dev_x, (m_lineTo + 1) * lineHeight, + clientSize.x - dev_x , (m_lineTo + 1) * lineHeight ); + } + } + + // Draw vertical rules if required + if ( HasFlag(wxLC_VRULES) && !IsEmpty() ) + { + wxPen pen(GetRuleColour(), 1, wxSOLID); + wxRect firstItemRect, lastItemRect; + + GetItemRect(visibleFrom, firstItemRect); + GetItemRect(visibleTo, lastItemRect); + int x = firstItemRect.GetX(); + dc.SetPen(pen); + dc.SetBrush(* wxTRANSPARENT_BRUSH); + + for (int col = 0; col < GetColumnCount(); col++) + { + int colWidth = GetColumnWidth(col); + x += colWidth; + int x_pos = x - dev_x; + if (col < GetColumnCount()-1) x_pos -= 2; + dc.DrawLine(x_pos, firstItemRect.GetY() - 1 - dev_y, + x_pos, lastItemRect.GetBottom() + 1 - dev_y); + } + } + } + else // !report + { + size_t count = GetItemCount(); + for ( size_t i = 0; i < count; i++ ) + { + GetLine(i)->Draw( &dc ); + } + } + +#ifndef __WXMAC__ + // Don't draw rect outline under Mac at all. + if ( HasCurrent() ) + { + if ( m_hasFocus ) + { + wxRect rect( GetLineHighlightRect( m_current ) ); +#ifndef __WXGTK20__ + dc.SetPen( *wxBLACK_PEN ); + dc.SetBrush( *wxTRANSPARENT_BRUSH ); + dc.DrawRectangle( rect ); +#else + wxRendererNative::Get().DrawItemSelectionRect( this, dc, rect, wxCONTROL_CURRENT|wxCONTROL_FOCUSED ); + +#endif + } + } +#endif +} + +void wxListMainWindow::HighlightAll( bool on ) +{ + if ( IsSingleSel() ) + { + wxASSERT_MSG( !on, _T("can't do this in a single selection control") ); + + // we just have one item to turn off + if ( HasCurrent() && IsHighlighted(m_current) ) + { + HighlightLine(m_current, false); + RefreshLine(m_current); + } + } + else // multi selection + { + if ( !IsEmpty() ) + HighlightLines(0, GetItemCount() - 1, on); + } +} + +void wxListMainWindow::SendNotify( size_t line, + wxEventType command, + const wxPoint& point ) +{ + wxListEvent le( command, GetParent()->GetId() ); + le.SetEventObject( GetParent() ); + + le.m_itemIndex = line; + + // set only for events which have position + if ( point != wxDefaultPosition ) + le.m_pointDrag = point; + + // don't try to get the line info for virtual list controls: the main + // program has it anyhow and if we did it would result in accessing all + // the lines, even those which are not visible now and this is precisely + // what we're trying to avoid + if ( !IsVirtual() ) + { + if ( line != (size_t)-1 ) + { + GetLine(line)->GetItem( 0, le.m_item ); + } + //else: this happens for wxEVT_COMMAND_LIST_ITEM_FOCUSED event + } + //else: there may be no more such item + + GetParent()->GetEventHandler()->ProcessEvent( le ); +} + +void wxListMainWindow::ChangeCurrent(size_t current) +{ + m_current = current; + + // as the current item changed, we shouldn't start editing it when the + // "slow click" timer expires as the click happened on another item + if ( m_renameTimer->IsRunning() ) + m_renameTimer->Stop(); + + SendNotify(current, wxEVT_COMMAND_LIST_ITEM_FOCUSED); +} + +wxTextCtrl *wxListMainWindow::EditLabel(long item, wxClassInfo* textControlClass) +{ + wxCHECK_MSG( (item >= 0) && ((size_t)item < GetItemCount()), NULL, + wxT("wrong index in wxGenericListCtrl::EditLabel()") ); + + wxASSERT_MSG( textControlClass->IsKindOf(CLASSINFO(wxTextCtrl)), + wxT("EditLabel() needs a text control") ); + + size_t itemEdit = (size_t)item; + + wxListEvent le( wxEVT_COMMAND_LIST_BEGIN_LABEL_EDIT, GetParent()->GetId() ); + le.SetEventObject( GetParent() ); + le.m_itemIndex = item; + wxListLineData *data = GetLine(itemEdit); + wxCHECK_MSG( data, NULL, _T("invalid index in EditLabel()") ); + data->GetItem( 0, le.m_item ); + + if ( GetParent()->GetEventHandler()->ProcessEvent( le ) && !le.IsAllowed() ) + { + // vetoed by user code + return NULL; + } + + // We have to call this here because the label in question might just have + // been added and no screen update taken place. + if ( m_dirty ) + { + wxSafeYield(); + + // Pending events dispatched by wxSafeYield might have changed the item + // count + if ( (size_t)item >= GetItemCount() ) + return NULL; + } + + wxTextCtrl * const text = (wxTextCtrl *)textControlClass->CreateObject(); + m_textctrlWrapper = new wxListTextCtrlWrapper(this, text, item); + return m_textctrlWrapper->GetText(); +} + +void wxListMainWindow::OnRenameTimer() +{ + wxCHECK_RET( HasCurrent(), wxT("unexpected rename timer") ); + + EditLabel( m_current ); +} + +bool wxListMainWindow::OnRenameAccept(size_t itemEdit, const wxString& value) +{ + wxListEvent le( wxEVT_COMMAND_LIST_END_LABEL_EDIT, GetParent()->GetId() ); + le.SetEventObject( GetParent() ); + le.m_itemIndex = itemEdit; + + wxListLineData *data = GetLine(itemEdit); + + wxCHECK_MSG( data, false, _T("invalid index in OnRenameAccept()") ); + + data->GetItem( 0, le.m_item ); + le.m_item.m_text = value; + return !GetParent()->GetEventHandler()->ProcessEvent( le ) || + le.IsAllowed(); +} + +void wxListMainWindow::OnRenameCancelled(size_t itemEdit) +{ + // let owner know that the edit was cancelled + wxListEvent le( wxEVT_COMMAND_LIST_END_LABEL_EDIT, GetParent()->GetId() ); + + le.SetEditCanceled(true); + + le.SetEventObject( GetParent() ); + le.m_itemIndex = itemEdit; + + wxListLineData *data = GetLine(itemEdit); + wxCHECK_RET( data, _T("invalid index in OnRenameCancelled()") ); + + data->GetItem( 0, le.m_item ); + GetEventHandler()->ProcessEvent( le ); +} + +void wxListMainWindow::OnMouse( wxMouseEvent &event ) +{ + +#ifdef __WXMAC__ + // On wxMac we can't depend on the EVT_KILL_FOCUS event to properly + // shutdown the edit control when the mouse is clicked elsewhere on the + // listctrl because the order of events is different (or something like + // that), so explicitly end the edit if it is active. + if ( event.LeftDown() && m_textctrlWrapper ) + m_textctrlWrapper->AcceptChangesAndFinish(); +#endif // __WXMAC__ + + if ( event.LeftDown() ) + SetFocusIgnoringChildren(); + + event.SetEventObject( GetParent() ); + if ( GetParent()->GetEventHandler()->ProcessEvent( event) ) + return; + + if (event.GetEventType() == wxEVT_MOUSEWHEEL) + { + // let the base handle mouse wheel events. + event.Skip(); + return; + } + + if ( !HasCurrent() || IsEmpty() ) + { + if (event.RightDown()) + { + SendNotify( (size_t)-1, wxEVT_COMMAND_LIST_ITEM_RIGHT_CLICK, event.GetPosition() ); + // Allow generation of context menu event + event.Skip(); + } + return; + } + + if (m_dirty) + return; + + if ( !(event.Dragging() || event.ButtonDown() || event.LeftUp() || + event.ButtonDClick()) ) + return; + + int x = event.GetX(); + int y = event.GetY(); + CalcUnscrolledPosition( x, y, &x, &y ); + + // where did we hit it (if we did)? + long hitResult = 0; + + size_t count = GetItemCount(), + current; + + if ( InReportView() ) + { + current = y / GetLineHeight(); + if ( current < count ) + hitResult = HitTestLine(current, x, y); + } + else // !report + { + // TODO: optimize it too! this is less simple than for report view but + // enumerating all items is still not a way to do it!! + for ( current = 0; current < count; current++ ) + { + hitResult = HitTestLine(current, x, y); + if ( hitResult ) + break; + } + } + + if (event.Dragging()) + { + if (m_dragCount == 0) + { + // we have to report the raw, physical coords as we want to be + // able to call HitTest(event.m_pointDrag) from the user code to + // get the item being dragged + m_dragStart = event.GetPosition(); + } + + m_dragCount++; + + if (m_dragCount != 3) + return; + + int command = event.RightIsDown() ? wxEVT_COMMAND_LIST_BEGIN_RDRAG + : wxEVT_COMMAND_LIST_BEGIN_DRAG; + + wxListEvent le( command, GetParent()->GetId() ); + le.SetEventObject( GetParent() ); + le.m_itemIndex = m_lineLastClicked; + le.m_pointDrag = m_dragStart; + GetParent()->GetEventHandler()->ProcessEvent( le ); + + return; + } + else + { + m_dragCount = 0; + } + + if ( !hitResult ) + { + // outside of any item + if (event.RightDown()) + { + SendNotify( (size_t) -1, wxEVT_COMMAND_LIST_ITEM_RIGHT_CLICK, event.GetPosition() ); + + wxContextMenuEvent evtCtx( + wxEVT_CONTEXT_MENU, + GetParent()->GetId(), + ClientToScreen(event.GetPosition())); + evtCtx.SetEventObject(GetParent()); + GetParent()->GetEventHandler()->ProcessEvent(evtCtx); + } + else + { + // reset the selection and bail out + HighlightAll(false); + } + + return; + } + + bool forceClick = false; + if (event.ButtonDClick()) + { + if ( m_renameTimer->IsRunning() ) + m_renameTimer->Stop(); + + m_lastOnSame = false; + + if ( current == m_lineLastClicked ) + { + SendNotify( current, wxEVT_COMMAND_LIST_ITEM_ACTIVATED ); + + return; + } + else + { + // The first click was on another item, so don't interpret this as + // a double click, but as a simple click instead + forceClick = true; + } + } + + if (event.LeftUp()) + { + if (m_lineSelectSingleOnUp != (size_t)-1) + { + // select single line + HighlightAll( false ); + ReverseHighlight(m_lineSelectSingleOnUp); + } + + if (m_lastOnSame) + { + if ((current == m_current) && + (hitResult == wxLIST_HITTEST_ONITEMLABEL) && + HasFlag(wxLC_EDIT_LABELS) ) + { + if (InReportView()) + { + wxRect label = GetLineLabelRect( current ); + if (label.Contains( x, y )) + m_renameTimer->Start( 250, true ); + + } + else + m_renameTimer->Start( 250, true ); + } + } + + m_lastOnSame = false; + m_lineSelectSingleOnUp = (size_t)-1; + } + else + { + // This is necessary, because after a DnD operation in + // from and to ourself, the up event is swallowed by the + // DnD code. So on next non-up event (which means here and + // now) m_lineSelectSingleOnUp should be reset. + m_lineSelectSingleOnUp = (size_t)-1; + } + if (event.RightDown()) + { + m_lineBeforeLastClicked = m_lineLastClicked; + m_lineLastClicked = current; + + // If the item is already selected, do not update the selection. + // Multi-selections should not be cleared if a selected item is clicked. + if (!IsHighlighted(current)) + { + HighlightAll(false); + ChangeCurrent(current); + ReverseHighlight(m_current); + } + + SendNotify( current, wxEVT_COMMAND_LIST_ITEM_RIGHT_CLICK, event.GetPosition() ); + + wxContextMenuEvent evtCtx( + wxEVT_CONTEXT_MENU, + GetParent()->GetId(), + ClientToScreen(event.GetPosition())); + evtCtx.SetEventObject(GetParent()); + GetParent()->GetEventHandler()->ProcessEvent(evtCtx); + } + else if (event.MiddleDown()) + { + SendNotify( current, wxEVT_COMMAND_LIST_ITEM_MIDDLE_CLICK ); + } + else if ( event.LeftDown() || forceClick ) + { + m_lineBeforeLastClicked = m_lineLastClicked; + m_lineLastClicked = current; + + size_t oldCurrent = m_current; + bool oldWasSelected = IsHighlighted(m_current); + + bool cmdModifierDown = event.CmdDown(); + if ( IsSingleSel() || !(cmdModifierDown || event.ShiftDown()) ) + { + if ( IsSingleSel() || !IsHighlighted(current) ) + { + HighlightAll( false ); + + ChangeCurrent(current); + + ReverseHighlight(m_current); + } + else // multi sel & current is highlighted & no mod keys + { + m_lineSelectSingleOnUp = current; + ChangeCurrent(current); // change focus + } + } + else // multi sel & either ctrl or shift is down + { + if (cmdModifierDown) + { + ChangeCurrent(current); + + ReverseHighlight(m_current); + } + else if (event.ShiftDown()) + { + ChangeCurrent(current); + + size_t lineFrom = oldCurrent, + lineTo = current; + + if ( lineTo < lineFrom ) + { + lineTo = lineFrom; + lineFrom = m_current; + } + + HighlightLines(lineFrom, lineTo); + } + else // !ctrl, !shift + { + // test in the enclosing if should make it impossible + wxFAIL_MSG( _T("how did we get here?") ); + } + } + + if (m_current != oldCurrent) + RefreshLine( oldCurrent ); + + // forceClick is only set if the previous click was on another item + m_lastOnSame = !forceClick && (m_current == oldCurrent) && oldWasSelected; + } +} + +void wxListMainWindow::MoveToItem(size_t item) +{ + if ( item == (size_t)-1 ) + return; + + wxRect rect = GetLineRect(item); + + int client_w, client_h; + GetClientSize( &client_w, &client_h ); + + const int hLine = GetLineHeight(); + + int view_x = SCROLL_UNIT_X * GetScrollPos( wxHORIZONTAL ); + int view_y = hLine * GetScrollPos( wxVERTICAL ); + + if ( InReportView() ) + { + // the next we need the range of lines shown it might be different, + // so recalculate it + ResetVisibleLinesRange(); + + if (rect.y < view_y) + Scroll( -1, rect.y / hLine ); + if (rect.y + rect.height + 5 > view_y + client_h) + Scroll( -1, (rect.y + rect.height - client_h + hLine) / hLine ); + +#ifdef __WXMAC__ + // At least on Mac the visible lines value will get reset inside of + // Scroll *before* it actually scrolls the window because of the + // Update() that happens there, so it will still have the wrong value. + // So let's reset it again and wait for it to be recalculated in the + // next paint event. I would expect this problem to show up in wxGTK + // too but couldn't duplicate it there. Perhaps the order of events + // is different... --Robin + ResetVisibleLinesRange(); +#endif + } + else // !report + { + int sx = -1, + sy = -1; + + if (rect.x-view_x < 5) + sx = (rect.x - 5) / SCROLL_UNIT_X; + if (rect.x + rect.width - 5 > view_x + client_w) + sx = (rect.x + rect.width - client_w + SCROLL_UNIT_X) / SCROLL_UNIT_X; + + if (rect.y-view_y < 5) + sy = (rect.y - 5) / hLine; + if (rect.y + rect.height - 5 > view_y + client_h) + sy = (rect.y + rect.height - client_h + hLine) / hLine; + + Scroll(sx, sy); + } +} + +bool wxListMainWindow::ScrollList(int WXUNUSED(dx), int dy) +{ + if ( !InReportView() ) + { + // TODO: this should work in all views but is not implemented now + return false; + } + + size_t top, bottom; + GetVisibleLinesRange(&top, &bottom); + + if ( bottom == (size_t)-1 ) + return 0; + + ResetVisibleLinesRange(); + + int hLine = GetLineHeight(); + + Scroll(-1, top + dy / hLine); + +#ifdef __WXMAC__ + // see comment in MoveToItem() for why we do this + ResetVisibleLinesRange(); +#endif + + return true; +} + +// ---------------------------------------------------------------------------- +// keyboard handling +// ---------------------------------------------------------------------------- + +void wxListMainWindow::OnArrowChar(size_t newCurrent, const wxKeyEvent& event) +{ + wxCHECK_RET( newCurrent < (size_t)GetItemCount(), + _T("invalid item index in OnArrowChar()") ); + + size_t oldCurrent = m_current; + + // in single selection we just ignore Shift as we can't select several + // items anyhow + if ( event.ShiftDown() && !IsSingleSel() ) + { + ChangeCurrent(newCurrent); + + // refresh the old focus to remove it + RefreshLine( oldCurrent ); + + // select all the items between the old and the new one + if ( oldCurrent > newCurrent ) + { + newCurrent = oldCurrent; + oldCurrent = m_current; + } + + HighlightLines(oldCurrent, newCurrent); + } + else // !shift + { + // all previously selected items are unselected unless ctrl is held + // in a multiselection control + if ( !event.ControlDown() || IsSingleSel() ) + HighlightAll(false); + + ChangeCurrent(newCurrent); + + // refresh the old focus to remove it + RefreshLine( oldCurrent ); + + // in single selection mode we must always have a selected item + if ( !event.ControlDown() || IsSingleSel() ) + HighlightLine( m_current, true ); + } + + RefreshLine( m_current ); + + MoveToFocus(); +} + +void wxListMainWindow::OnKeyDown( wxKeyEvent &event ) +{ + wxWindow *parent = GetParent(); + + // propagate the key event upwards + wxKeyEvent ke( wxEVT_KEY_DOWN ); + ke.m_shiftDown = event.m_shiftDown; + ke.m_controlDown = event.m_controlDown; + ke.m_altDown = event.m_altDown; + ke.m_metaDown = event.m_metaDown; + ke.m_keyCode = event.m_keyCode; + ke.m_x = event.m_x; + ke.m_y = event.m_y; + ke.SetEventObject( parent ); + if (parent->GetEventHandler()->ProcessEvent( ke )) return; + + event.Skip(); +} + +void wxListMainWindow::OnKeyUp( wxKeyEvent &event ) +{ + wxWindow *parent = GetParent(); + + // propagate the key event upwards + wxKeyEvent ke( wxEVT_KEY_UP ); + ke.m_shiftDown = event.m_shiftDown; + ke.m_controlDown = event.m_controlDown; + ke.m_altDown = event.m_altDown; + ke.m_metaDown = event.m_metaDown; + ke.m_keyCode = event.m_keyCode; + ke.m_x = event.m_x; + ke.m_y = event.m_y; + ke.SetEventObject( parent ); + if (parent->GetEventHandler()->ProcessEvent( ke )) return; + + event.Skip(); +} + +void wxListMainWindow::OnChar( wxKeyEvent &event ) +{ + wxWindow *parent = GetParent(); + + // send a list_key event up + if ( HasCurrent() ) + { + wxListEvent le( wxEVT_COMMAND_LIST_KEY_DOWN, GetParent()->GetId() ); + le.m_itemIndex = m_current; + GetLine(m_current)->GetItem( 0, le.m_item ); + le.m_code = event.GetKeyCode(); + le.SetEventObject( parent ); + parent->GetEventHandler()->ProcessEvent( le ); + } + + // propagate the char event upwards + wxKeyEvent ke( wxEVT_CHAR ); + ke.m_shiftDown = event.m_shiftDown; + ke.m_controlDown = event.m_controlDown; + ke.m_altDown = event.m_altDown; + ke.m_metaDown = event.m_metaDown; + ke.m_keyCode = event.m_keyCode; + ke.m_x = event.m_x; + ke.m_y = event.m_y; + ke.SetEventObject( parent ); + if (parent->GetEventHandler()->ProcessEvent( ke )) return; + + if (event.GetKeyCode() == WXK_TAB) + { + wxNavigationKeyEvent nevent; + nevent.SetWindowChange( event.ControlDown() ); + nevent.SetDirection( !event.ShiftDown() ); + nevent.SetEventObject( GetParent()->GetParent() ); + nevent.SetCurrentFocus( m_parent ); + if (GetParent()->GetParent()->GetEventHandler()->ProcessEvent( nevent )) + return; + } + + // no item -> nothing to do + if (!HasCurrent()) + { + event.Skip(); + return; + } + + // don't use m_linesPerPage directly as it might not be computed yet + const int pageSize = GetCountPerPage(); + wxCHECK_RET( pageSize, _T("should have non zero page size") ); + + if (GetLayoutDirection() == wxLayout_RightToLeft) + { + if (event.GetKeyCode() == WXK_RIGHT) + event.m_keyCode = WXK_LEFT; + else if (event.GetKeyCode() == WXK_LEFT) + event.m_keyCode = WXK_RIGHT; + } + + switch ( event.GetKeyCode() ) + { + case WXK_UP: + if ( m_current > 0 ) + OnArrowChar( m_current - 1, event ); + break; + + case WXK_DOWN: + if ( m_current < (size_t)GetItemCount() - 1 ) + OnArrowChar( m_current + 1, event ); + break; + + case WXK_END: + if (!IsEmpty()) + OnArrowChar( GetItemCount() - 1, event ); + break; + + case WXK_HOME: + if (!IsEmpty()) + OnArrowChar( 0, event ); + break; + + case WXK_PAGEUP: + { + int steps = InReportView() ? pageSize - 1 + : m_current % pageSize; + + int index = m_current - steps; + if (index < 0) + index = 0; + + OnArrowChar( index, event ); + } + break; + + case WXK_PAGEDOWN: + { + int steps = InReportView() + ? pageSize - 1 + : pageSize - (m_current % pageSize) - 1; + + size_t index = m_current + steps; + size_t count = GetItemCount(); + if ( index >= count ) + index = count - 1; + + OnArrowChar( index, event ); + } + break; + + case WXK_LEFT: + if ( !InReportView() ) + { + int index = m_current - pageSize; + if (index < 0) + index = 0; + + OnArrowChar( index, event ); + } + break; + + case WXK_RIGHT: + if ( !InReportView() ) + { + size_t index = m_current + pageSize; + + size_t count = GetItemCount(); + if ( index >= count ) + index = count - 1; + + OnArrowChar( index, event ); + } + break; + + case WXK_SPACE: + if ( IsSingleSel() ) + { + if ( event.ControlDown() ) + { + ReverseHighlight(m_current); + } + else // normal space press + { + SendNotify( m_current, wxEVT_COMMAND_LIST_ITEM_ACTIVATED ); + } + } + else // multiple selection + { + ReverseHighlight(m_current); + } + break; + + case WXK_RETURN: + case WXK_EXECUTE: + SendNotify( m_current, wxEVT_COMMAND_LIST_ITEM_ACTIVATED ); + break; + + default: + event.Skip(); + } +} + +// ---------------------------------------------------------------------------- +// focus handling +// ---------------------------------------------------------------------------- + +void wxListMainWindow::OnSetFocus( wxFocusEvent &WXUNUSED(event) ) +{ + if ( GetParent() ) + { + wxFocusEvent event( wxEVT_SET_FOCUS, GetParent()->GetId() ); + event.SetEventObject( GetParent() ); + if ( GetParent()->GetEventHandler()->ProcessEvent( event) ) + return; + } + + // wxGTK sends us EVT_SET_FOCUS events even if we had never got + // EVT_KILL_FOCUS before which means that we finish by redrawing the items + // which are already drawn correctly resulting in horrible flicker - avoid + // it + if ( !m_hasFocus ) + { + m_hasFocus = true; + + RefreshSelected(); + } +} + +void wxListMainWindow::OnKillFocus( wxFocusEvent &WXUNUSED(event) ) +{ + if ( GetParent() ) + { + wxFocusEvent event( wxEVT_KILL_FOCUS, GetParent()->GetId() ); + event.SetEventObject( GetParent() ); + if ( GetParent()->GetEventHandler()->ProcessEvent( event) ) + return; + } + + m_hasFocus = false; + RefreshSelected(); +} + +void wxListMainWindow::DrawImage( int index, wxDC *dc, int x, int y ) +{ + if ( HasFlag(wxLC_ICON) && (m_normal_image_list)) + { + m_normal_image_list->Draw( index, *dc, x, y, wxIMAGELIST_DRAW_TRANSPARENT ); + } + else if ( HasFlag(wxLC_SMALL_ICON) && (m_small_image_list)) + { + m_small_image_list->Draw( index, *dc, x, y, wxIMAGELIST_DRAW_TRANSPARENT ); + } + else if ( HasFlag(wxLC_LIST) && (m_small_image_list)) + { + m_small_image_list->Draw( index, *dc, x, y, wxIMAGELIST_DRAW_TRANSPARENT ); + } + else if ( InReportView() && (m_small_image_list)) + { + m_small_image_list->Draw( index, *dc, x, y, wxIMAGELIST_DRAW_TRANSPARENT ); + } +} + +void wxListMainWindow::GetImageSize( int index, int &width, int &height ) const +{ + if ( HasFlag(wxLC_ICON) && m_normal_image_list ) + { + m_normal_image_list->GetSize( index, width, height ); + } + else if ( HasFlag(wxLC_SMALL_ICON) && m_small_image_list ) + { + m_small_image_list->GetSize( index, width, height ); + } + else if ( HasFlag(wxLC_LIST) && m_small_image_list ) + { + m_small_image_list->GetSize( index, width, height ); + } + else if ( InReportView() && m_small_image_list ) + { + m_small_image_list->GetSize( index, width, height ); + } + else + { + width = + height = 0; + } +} + +int wxListMainWindow::GetTextLength( const wxString &s ) const +{ + wxClientDC dc( wxConstCast(this, wxListMainWindow) ); + dc.SetFont( GetFont() ); + + wxCoord lw; + dc.GetTextExtent( s, &lw, NULL ); + + return lw + AUTOSIZE_COL_MARGIN; +} + +void wxListMainWindow::SetImageList( wxImageList *imageList, int which ) +{ + m_dirty = true; + + // calc the spacing from the icon size + int width = 0, height = 0; + + if ((imageList) && (imageList->GetImageCount()) ) + imageList->GetSize(0, width, height); + + if (which == wxIMAGE_LIST_NORMAL) + { + m_normal_image_list = imageList; + m_normal_spacing = width + 8; + } + + if (which == wxIMAGE_LIST_SMALL) + { + m_small_image_list = imageList; + m_small_spacing = width + 14; + m_lineHeight = 0; // ensure that the line height will be recalc'd + } +} + +void wxListMainWindow::SetItemSpacing( int spacing, bool isSmall ) +{ + m_dirty = true; + if (isSmall) + m_small_spacing = spacing; + else + m_normal_spacing = spacing; +} + +int wxListMainWindow::GetItemSpacing( bool isSmall ) +{ + return isSmall ? m_small_spacing : m_normal_spacing; +} + +// ---------------------------------------------------------------------------- +// columns +// ---------------------------------------------------------------------------- + +void wxListMainWindow::SetColumn( int col, wxListItem &item ) +{ + wxListHeaderDataList::compatibility_iterator node = m_columns.Item( col ); + + wxCHECK_RET( node, _T("invalid column index in SetColumn") ); + + if ( item.m_width == wxLIST_AUTOSIZE_USEHEADER ) + item.m_width = GetTextLength( item.m_text ); + + wxListHeaderData *column = node->GetData(); + column->SetItem( item ); + + wxListHeaderWindow *headerWin = GetListCtrl()->m_headerWin; + if ( headerWin ) + headerWin->m_dirty = true; + + m_dirty = true; + + // invalidate it as it has to be recalculated + m_headerWidth = 0; +} + +void wxListMainWindow::SetColumnWidth( int col, int width ) +{ + wxCHECK_RET( col >= 0 && col < GetColumnCount(), + _T("invalid column index") ); + + wxCHECK_RET( InReportView(), + _T("SetColumnWidth() can only be called in report mode.") ); + + m_dirty = true; + wxListHeaderWindow *headerWin = GetListCtrl()->m_headerWin; + if ( headerWin ) + headerWin->m_dirty = true; + + wxListHeaderDataList::compatibility_iterator node = m_columns.Item( col ); + wxCHECK_RET( node, _T("no column?") ); + + wxListHeaderData *column = node->GetData(); + + size_t count = GetItemCount(); + + if (width == wxLIST_AUTOSIZE_USEHEADER) + { + width = GetTextLength(column->GetText()); + width += 2*EXTRA_WIDTH; + + // check for column header's image availability + const int image = column->GetImage(); + if ( image != -1 ) + { + if ( m_small_image_list ) + { + int ix = 0, iy = 0; + m_small_image_list->GetSize(image, ix, iy); + width += ix + HEADER_IMAGE_MARGIN_IN_REPORT_MODE; + } + } + } + else if ( width == wxLIST_AUTOSIZE ) + { + if ( IsVirtual() ) + { + // TODO: determine the max width somehow... + width = WIDTH_COL_DEFAULT; + } + else // !virtual + { + wxClientDC dc(this); + dc.SetFont( GetFont() ); + + int max = AUTOSIZE_COL_MARGIN; + + // if the cached column width isn't valid then recalculate it + if (m_aColWidths.Item(col)->bNeedsUpdate) + { + for (size_t i = 0; i < count; i++) + { + wxListLineData *line = GetLine( i ); + wxListItemDataList::compatibility_iterator n = line->m_items.Item( col ); + + wxCHECK_RET( n, _T("no subitem?") ); + + wxListItemData *itemData = n->GetData(); + wxListItem item; + + itemData->GetItem(item); + int itemWidth = GetItemWidthWithImage(&item); + if (itemWidth > max) + max = itemWidth; + } + + m_aColWidths.Item(col)->bNeedsUpdate = false; + m_aColWidths.Item(col)->nMaxWidth = max; + } + + max = m_aColWidths.Item(col)->nMaxWidth; + width = max + AUTOSIZE_COL_MARGIN; + } + } + + column->SetWidth( width ); + + // invalidate it as it has to be recalculated + m_headerWidth = 0; +} + +int wxListMainWindow::GetHeaderWidth() const +{ + if ( !m_headerWidth ) + { + wxListMainWindow *self = wxConstCast(this, wxListMainWindow); + + size_t count = GetColumnCount(); + for ( size_t col = 0; col < count; col++ ) + { + self->m_headerWidth += GetColumnWidth(col); + } + } + + return m_headerWidth; +} + +void wxListMainWindow::GetColumn( int col, wxListItem &item ) const +{ + wxListHeaderDataList::compatibility_iterator node = m_columns.Item( col ); + wxCHECK_RET( node, _T("invalid column index in GetColumn") ); + + wxListHeaderData *column = node->GetData(); + column->GetItem( item ); +} + +int wxListMainWindow::GetColumnWidth( int col ) const +{ + wxListHeaderDataList::compatibility_iterator node = m_columns.Item( col ); + wxCHECK_MSG( node, 0, _T("invalid column index") ); + + wxListHeaderData *column = node->GetData(); + return column->GetWidth(); +} + +// ---------------------------------------------------------------------------- +// item state +// ---------------------------------------------------------------------------- + +void wxListMainWindow::SetItem( wxListItem &item ) +{ + long id = item.m_itemId; + wxCHECK_RET( id >= 0 && (size_t)id < GetItemCount(), + _T("invalid item index in SetItem") ); + + if ( !IsVirtual() ) + { + wxListLineData *line = GetLine((size_t)id); + line->SetItem( item.m_col, item ); + + // Set item state if user wants + if ( item.m_mask & wxLIST_MASK_STATE ) + SetItemState( item.m_itemId, item.m_state, item.m_state ); + + if (InReportView()) + { + // update the Max Width Cache if needed + int width = GetItemWidthWithImage(&item); + + if (width > m_aColWidths.Item(item.m_col)->nMaxWidth) + m_aColWidths.Item(item.m_col)->nMaxWidth = width; + } + } + + // update the item on screen + wxRect rectItem; + GetItemRect(id, rectItem); + RefreshRect(rectItem); +} + +void wxListMainWindow::SetItemStateAll(long state, long stateMask) +{ + if ( IsEmpty() ) + return; + + // first deal with selection + if ( stateMask & wxLIST_STATE_SELECTED ) + { + // set/clear select state + if ( IsVirtual() ) + { + // optimized version for virtual listctrl. + m_selStore.SelectRange(0, GetItemCount() - 1, state == wxLIST_STATE_SELECTED); + Refresh(); + } + else if ( state & wxLIST_STATE_SELECTED ) + { + const long count = GetItemCount(); + for( long i = 0; i < count; i++ ) + { + SetItemState( i, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED ); + } + + } + else + { + // clear for non virtual (somewhat optimized by using GetNextItem()) + long i = -1; + while ( (i = GetNextItem(i, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED)) != -1 ) + { + SetItemState( i, 0, wxLIST_STATE_SELECTED ); + } + } + } + + if ( HasCurrent() && (state == 0) && (stateMask & wxLIST_STATE_FOCUSED) ) + { + // unfocus all: only one item can be focussed, so clearing focus for + // all items is simply clearing focus of the focussed item. + SetItemState(m_current, state, stateMask); + } + //(setting focus to all items makes no sense, so it is not handled here.) +} + +void wxListMainWindow::SetItemState( long litem, long state, long stateMask ) +{ + if ( litem == -1 ) + { + SetItemStateAll(state, stateMask); + return; + } + + wxCHECK_RET( litem >= 0 && (size_t)litem < GetItemCount(), + _T("invalid list ctrl item index in SetItem") ); + + size_t oldCurrent = m_current; + size_t item = (size_t)litem; // safe because of the check above + + // do we need to change the focus? + if ( stateMask & wxLIST_STATE_FOCUSED ) + { + if ( state & wxLIST_STATE_FOCUSED ) + { + // don't do anything if this item is already focused + if ( item != m_current ) + { + ChangeCurrent(item); + + if ( oldCurrent != (size_t)-1 ) + { + if ( IsSingleSel() ) + { + HighlightLine(oldCurrent, false); + } + + RefreshLine(oldCurrent); + } + + RefreshLine( m_current ); + } + } + else // unfocus + { + // don't do anything if this item is not focused + if ( item == m_current ) + { + ResetCurrent(); + + if ( IsSingleSel() ) + { + // we must unselect the old current item as well or we + // might end up with more than one selected item in a + // single selection control + HighlightLine(oldCurrent, false); + } + + RefreshLine( oldCurrent ); + } + } + } + + // do we need to change the selection state? + if ( stateMask & wxLIST_STATE_SELECTED ) + { + bool on = (state & wxLIST_STATE_SELECTED) != 0; + + if ( IsSingleSel() ) + { + if ( on ) + { + // selecting the item also makes it the focused one in the + // single sel mode + if ( m_current != item ) + { + ChangeCurrent(item); + + if ( oldCurrent != (size_t)-1 ) + { + HighlightLine( oldCurrent, false ); + RefreshLine( oldCurrent ); + } + } + } + else // off + { + // only the current item may be selected anyhow + if ( item != m_current ) + return; + } + } + + if ( HighlightLine(item, on) ) + { + RefreshLine(item); + } + } +} + +int wxListMainWindow::GetItemState( long item, long stateMask ) const +{ + wxCHECK_MSG( item >= 0 && (size_t)item < GetItemCount(), 0, + _T("invalid list ctrl item index in GetItemState()") ); + + int ret = wxLIST_STATE_DONTCARE; + + if ( stateMask & wxLIST_STATE_FOCUSED ) + { + if ( (size_t)item == m_current ) + ret |= wxLIST_STATE_FOCUSED; + } + + if ( stateMask & wxLIST_STATE_SELECTED ) + { + if ( IsHighlighted(item) ) + ret |= wxLIST_STATE_SELECTED; + } + + return ret; +} + +void wxListMainWindow::GetItem( wxListItem &item ) const +{ + wxCHECK_RET( item.m_itemId >= 0 && (size_t)item.m_itemId < GetItemCount(), + _T("invalid item index in GetItem") ); + + wxListLineData *line = GetLine((size_t)item.m_itemId); + line->GetItem( item.m_col, item ); + + // Get item state if user wants it + if ( item.m_mask & wxLIST_MASK_STATE ) + item.m_state = GetItemState( item.m_itemId, wxLIST_STATE_SELECTED | + wxLIST_STATE_FOCUSED ); +} + +// ---------------------------------------------------------------------------- +// item count +// ---------------------------------------------------------------------------- + +size_t wxListMainWindow::GetItemCount() const +{ + return IsVirtual() ? m_countVirt : m_lines.GetCount(); +} + +void wxListMainWindow::SetItemCount(long count) +{ + m_selStore.SetItemCount(count); + m_countVirt = count; + + ResetVisibleLinesRange(); + + // scrollbars must be reset + m_dirty = true; +} + +int wxListMainWindow::GetSelectedItemCount() const +{ + // deal with the quick case first + if ( IsSingleSel() ) + return HasCurrent() ? IsHighlighted(m_current) : false; + + // virtual controls remmebers all its selections itself + if ( IsVirtual() ) + return m_selStore.GetSelectedCount(); + + // TODO: we probably should maintain the number of items selected even for + // non virtual controls as enumerating all lines is really slow... + size_t countSel = 0; + size_t count = GetItemCount(); + for ( size_t line = 0; line < count; line++ ) + { + if ( GetLine(line)->IsHighlighted() ) + countSel++; + } + + return countSel; +} + +// ---------------------------------------------------------------------------- +// item position/size +// ---------------------------------------------------------------------------- + +wxRect wxListMainWindow::GetViewRect() const +{ + wxASSERT_MSG( !HasFlag(wxLC_REPORT | wxLC_LIST), + _T("wxListCtrl::GetViewRect() only works in icon mode") ); + + // we need to find the longest/tallest label + wxCoord xMax = 0, yMax = 0; + const int count = GetItemCount(); + if ( count ) + { + for ( int i = 0; i < count; i++ ) + { + wxRect r; + GetItemRect(i, r); + + wxCoord x = r.GetRight(), + y = r.GetBottom(); + + if ( x > xMax ) + xMax = x; + if ( y > yMax ) + yMax = y; + } + } + + // some fudge needed to make it look prettier + xMax += 2 * EXTRA_BORDER_X; + yMax += 2 * EXTRA_BORDER_Y; + + // account for the scrollbars if necessary + const wxSize sizeAll = GetClientSize(); + if ( xMax > sizeAll.x ) + yMax += wxSystemSettings::GetMetric(wxSYS_HSCROLL_Y); + if ( yMax > sizeAll.y ) + xMax += wxSystemSettings::GetMetric(wxSYS_VSCROLL_X); + + return wxRect(0, 0, xMax, yMax); +} + +void wxListMainWindow::GetItemRect( long index, wxRect &rect ) const +{ + wxCHECK_RET( index >= 0 && (size_t)index < GetItemCount(), + _T("invalid index in GetItemRect") ); + + // ensure that we're laid out, otherwise we could return nonsense + if ( m_dirty ) + { + wxConstCast(this, wxListMainWindow)-> + RecalculatePositions(true /* no refresh */); + } + + rect = GetLineRect((size_t)index); + + CalcScrolledPosition(rect.x, rect.y, &rect.x, &rect.y); +} + +bool wxListMainWindow::GetItemPosition(long item, wxPoint& pos) const +{ + wxRect rect; + GetItemRect(item, rect); + + pos.x = rect.x; + pos.y = rect.y; + + return true; +} + +// ---------------------------------------------------------------------------- +// geometry calculation +// ---------------------------------------------------------------------------- + +void wxListMainWindow::RecalculatePositions(bool noRefresh) +{ + const int lineHeight = GetLineHeight(); + + wxClientDC dc( this ); + dc.SetFont( GetFont() ); + + const size_t count = GetItemCount(); + + int iconSpacing; + if ( HasFlag(wxLC_ICON) ) + iconSpacing = m_normal_spacing; + else if ( HasFlag(wxLC_SMALL_ICON) ) + iconSpacing = m_small_spacing; + else + iconSpacing = 0; + + // Note that we do not call GetClientSize() here but + // GetSize() and subtract the border size for sunken + // borders manually. This is technically incorrect, + // but we need to know the client area's size WITHOUT + // scrollbars here. Since we don't know if there are + // any scrollbars, we use GetSize() instead. Another + // solution would be to call SetScrollbars() here to + // remove the scrollbars and call GetClientSize() then, + // but this might result in flicker and - worse - will + // reset the scrollbars to 0 which is not good at all + // if you resize a dialog/window, but don't want to + // reset the window scrolling. RR. + // Furthermore, we actually do NOT subtract the border + // width as 2 pixels is just the extra space which we + // need around the actual content in the window. Other- + // wise the text would e.g. touch the upper border. RR. + int clientWidth, + clientHeight; + GetSize( &clientWidth, &clientHeight ); + + if ( InReportView() ) + { + // all lines have the same height and we scroll one line per step + int entireHeight = count * lineHeight + LINE_SPACING; + + m_linesPerPage = clientHeight / lineHeight; + + ResetVisibleLinesRange(); + + SetScrollbars( SCROLL_UNIT_X, lineHeight, + GetHeaderWidth() / SCROLL_UNIT_X, + (entireHeight + lineHeight - 1) / lineHeight, + GetScrollPos(wxHORIZONTAL), + GetScrollPos(wxVERTICAL), + true ); + } + else // !report + { + // we have 3 different layout strategies: either layout all items + // horizontally/vertically (wxLC_ALIGN_XXX styles explicitly given) or + // to arrange them in top to bottom, left to right (don't ask me why + // not the other way round...) order + if ( HasFlag(wxLC_ALIGN_LEFT | wxLC_ALIGN_TOP) ) + { + int x = EXTRA_BORDER_X; + int y = EXTRA_BORDER_Y; + + wxCoord widthMax = 0; + + size_t i; + for ( i = 0; i < count; i++ ) + { + wxListLineData *line = GetLine(i); + line->CalculateSize( &dc, iconSpacing ); + line->SetPosition( x, y, iconSpacing ); + + wxSize sizeLine = GetLineSize(i); + + if ( HasFlag(wxLC_ALIGN_TOP) ) + { + if ( sizeLine.x > widthMax ) + widthMax = sizeLine.x; + + y += sizeLine.y; + } + else // wxLC_ALIGN_LEFT + { + x += sizeLine.x + MARGIN_BETWEEN_ROWS; + } + } + + if ( HasFlag(wxLC_ALIGN_TOP) ) + { + // traverse the items again and tweak their sizes so that they are + // all the same in a row + for ( i = 0; i < count; i++ ) + { + wxListLineData *line = GetLine(i); + line->m_gi->ExtendWidth(widthMax); + } + } + + SetScrollbars + ( + SCROLL_UNIT_X, + lineHeight, + (x + SCROLL_UNIT_X) / SCROLL_UNIT_X, + (y + lineHeight) / lineHeight, + GetScrollPos( wxHORIZONTAL ), + GetScrollPos( wxVERTICAL ), + true + ); + } + else // "flowed" arrangement, the most complicated case + { + // at first we try without any scrollbars, if the items don't fit into + // the window, we recalculate after subtracting the space taken by the + // scrollbar + + int entireWidth = 0; + + for (int tries = 0; tries < 2; tries++) + { + entireWidth = 2 * EXTRA_BORDER_X; + + if (tries == 1) + { + // Now we have decided that the items do not fit into the + // client area, so we need a scrollbar + entireWidth += SCROLL_UNIT_X; + } + + int x = EXTRA_BORDER_X; + int y = EXTRA_BORDER_Y; + int maxWidthInThisRow = 0; + + m_linesPerPage = 0; + int currentlyVisibleLines = 0; + + for (size_t i = 0; i < count; i++) + { + currentlyVisibleLines++; + wxListLineData *line = GetLine( i ); + line->CalculateSize( &dc, iconSpacing ); + line->SetPosition( x, y, iconSpacing ); + + wxSize sizeLine = GetLineSize( i ); + + if ( maxWidthInThisRow < sizeLine.x ) + maxWidthInThisRow = sizeLine.x; + + y += sizeLine.y; + if (currentlyVisibleLines > m_linesPerPage) + m_linesPerPage = currentlyVisibleLines; + + if ( y + sizeLine.y >= clientHeight ) + { + currentlyVisibleLines = 0; + y = EXTRA_BORDER_Y; + maxWidthInThisRow += MARGIN_BETWEEN_ROWS; + x += maxWidthInThisRow; + entireWidth += maxWidthInThisRow; + maxWidthInThisRow = 0; + } + + // We have reached the last item. + if ( i == count - 1 ) + entireWidth += maxWidthInThisRow; + + if ( (tries == 0) && + (entireWidth + SCROLL_UNIT_X > clientWidth) ) + { + clientHeight -= wxSystemSettings:: + GetMetric(wxSYS_HSCROLL_Y); + m_linesPerPage = 0; + break; + } + + if ( i == count - 1 ) + tries = 1; // Everything fits, no second try required. + } + } + + SetScrollbars + ( + SCROLL_UNIT_X, + lineHeight, + (entireWidth + SCROLL_UNIT_X) / SCROLL_UNIT_X, + 0, + GetScrollPos( wxHORIZONTAL ), + 0, + true + ); + } + } + + if ( !noRefresh ) + { + // FIXME: why should we call it from here? + UpdateCurrent(); + + RefreshAll(); + } +} + +void wxListMainWindow::RefreshAll() +{ + m_dirty = false; + Refresh(); + + wxListHeaderWindow *headerWin = GetListCtrl()->m_headerWin; + if ( headerWin && headerWin->m_dirty ) + { + headerWin->m_dirty = false; + headerWin->Refresh(); + } +} + +void wxListMainWindow::UpdateCurrent() +{ + if ( !HasCurrent() && !IsEmpty() ) + ChangeCurrent(0); +} + +long wxListMainWindow::GetNextItem( long item, + int WXUNUSED(geometry), + int state ) const +{ + long ret = item, + max = GetItemCount(); + wxCHECK_MSG( (ret == -1) || (ret < max), -1, + _T("invalid listctrl index in GetNextItem()") ); + + // notice that we start with the next item (or the first one if item == -1) + // and this is intentional to allow writing a simple loop to iterate over + // all selected items + ret++; + if ( ret == max ) + // this is not an error because the index was OK initially, + // just no such item + return -1; + + if ( !state ) + // any will do + return (size_t)ret; + + size_t count = GetItemCount(); + for ( size_t line = (size_t)ret; line < count; line++ ) + { + if ( (state & wxLIST_STATE_FOCUSED) && (line == m_current) ) + return line; + + if ( (state & wxLIST_STATE_SELECTED) && IsHighlighted(line) ) + return line; + } + + return -1; +} + +// ---------------------------------------------------------------------------- +// deleting stuff +// ---------------------------------------------------------------------------- + +void wxListMainWindow::DeleteItem( long lindex ) +{ + size_t count = GetItemCount(); + + wxCHECK_RET( (lindex >= 0) && ((size_t)lindex < count), + _T("invalid item index in DeleteItem") ); + + size_t index = (size_t)lindex; + + // we don't need to adjust the index for the previous items + if ( HasCurrent() && m_current >= index ) + { + // if the current item is being deleted, we want the next one to + // become selected - unless there is no next one - so don't adjust + // m_current in this case + if ( m_current != index || m_current == count - 1 ) + m_current--; + } + + if ( InReportView() ) + { + // mark the Column Max Width cache as dirty if the items in the line + // we're deleting contain the Max Column Width + wxListLineData * const line = GetLine(index); + wxListItemDataList::compatibility_iterator n; + wxListItemData *itemData; + wxListItem item; + int itemWidth; + + for (size_t i = 0; i < m_columns.GetCount(); i++) + { + n = line->m_items.Item( i ); + itemData = n->GetData(); + itemData->GetItem(item); + + itemWidth = GetItemWidthWithImage(&item); + + if (itemWidth >= m_aColWidths.Item(i)->nMaxWidth) + m_aColWidths.Item(i)->bNeedsUpdate = true; + } + + ResetVisibleLinesRange(); + } + + SendNotify( index, wxEVT_COMMAND_LIST_DELETE_ITEM, wxDefaultPosition ); + + if ( IsVirtual() ) + { + m_countVirt--; + m_selStore.OnItemDelete(index); + } + else + { + m_lines.RemoveAt( index ); + } + + // we need to refresh the (vert) scrollbar as the number of items changed + m_dirty = true; + + RefreshAfter(index); +} + +void wxListMainWindow::DeleteColumn( int col ) +{ + wxListHeaderDataList::compatibility_iterator node = m_columns.Item( col ); + + wxCHECK_RET( node, wxT("invalid column index in DeleteColumn()") ); + + m_dirty = true; + delete node->GetData(); + m_columns.Erase( node ); + + if ( !IsVirtual() ) + { + // update all the items + for ( size_t i = 0; i < m_lines.GetCount(); i++ ) + { + wxListLineData * const line = GetLine(i); + wxListItemDataList::compatibility_iterator n = line->m_items.Item( col ); + delete n->GetData(); + line->m_items.Erase(n); + } + } + + if ( InReportView() ) // we only cache max widths when in Report View + { + delete m_aColWidths.Item(col); + m_aColWidths.RemoveAt(col); + } + + // invalidate it as it has to be recalculated + m_headerWidth = 0; +} + +void wxListMainWindow::DoDeleteAllItems() +{ + if ( IsEmpty() ) + // nothing to do - in particular, don't send the event + return; + + ResetCurrent(); + + // to make the deletion of all items faster, we don't send the + // notifications for each item deletion in this case but only one event + // for all of them: this is compatible with wxMSW and documented in + // DeleteAllItems() description + + wxListEvent event( wxEVT_COMMAND_LIST_DELETE_ALL_ITEMS, GetParent()->GetId() ); + event.SetEventObject( GetParent() ); + GetParent()->GetEventHandler()->ProcessEvent( event ); + + if ( IsVirtual() ) + { + m_countVirt = 0; + m_selStore.Clear(); + } + + if ( InReportView() ) + { + ResetVisibleLinesRange(); + for (size_t i = 0; i < m_aColWidths.GetCount(); i++) + { + m_aColWidths.Item(i)->bNeedsUpdate = true; + } + } + + m_lines.Clear(); +} + +void wxListMainWindow::DeleteAllItems() +{ + DoDeleteAllItems(); + + RecalculatePositions(); +} + +void wxListMainWindow::DeleteEverything() +{ + WX_CLEAR_LIST(wxListHeaderDataList, m_columns); + WX_CLEAR_ARRAY(m_aColWidths); + + DeleteAllItems(); +} + +// ---------------------------------------------------------------------------- +// scanning for an item +// ---------------------------------------------------------------------------- + +void wxListMainWindow::EnsureVisible( long index ) +{ + wxCHECK_RET( index >= 0 && (size_t)index < GetItemCount(), + _T("invalid index in EnsureVisible") ); + + // We have to call this here because the label in question might just have + // been added and its position is not known yet + if ( m_dirty ) + RecalculatePositions(true /* no refresh */); + + MoveToItem((size_t)index); +} + +long wxListMainWindow::FindItem(long start, const wxString& str, bool partial ) +{ + if (str.empty()) + return wxNOT_FOUND; + + long pos = start; + wxString str_upper = str.Upper(); + if (pos < 0) + pos = 0; + + size_t count = GetItemCount(); + for ( size_t i = (size_t)pos; i < count; i++ ) + { + wxListLineData *line = GetLine(i); + wxString line_upper = line->GetText(0).Upper(); + if (!partial) + { + if (line_upper == str_upper ) + return i; + } + else + { + if (line_upper.find(str_upper) == 0) + return i; + } + } + + return wxNOT_FOUND; +} + +long wxListMainWindow::FindItem(long start, wxUIntPtr data) +{ + long pos = start; + if (pos < 0) + pos = 0; + + size_t count = GetItemCount(); + for (size_t i = (size_t)pos; i < count; i++) + { + wxListLineData *line = GetLine(i); + wxListItem item; + line->GetItem( 0, item ); + if (item.m_data == data) + return i; + } + + return wxNOT_FOUND; +} + +long wxListMainWindow::FindItem( const wxPoint& pt ) +{ + size_t topItem; + GetVisibleLinesRange( &topItem, NULL ); + + wxPoint p; + GetItemPosition( GetItemCount() - 1, p ); + if ( p.y == 0 ) + return topItem; + + long id = (long)floor( pt.y * double(GetItemCount() - topItem - 1) / p.y + topItem ); + if ( id >= 0 && id < (long)GetItemCount() ) + return id; + + return wxNOT_FOUND; +} + +long wxListMainWindow::HitTest( int x, int y, int &flags ) const +{ + CalcUnscrolledPosition( x, y, &x, &y ); + + size_t count = GetItemCount(); + + if ( InReportView() ) + { + size_t current = y / GetLineHeight(); + if ( current < count ) + { + flags = HitTestLine(current, x, y); + if ( flags ) + return current; + } + } + else // !report + { + // TODO: optimize it too! this is less simple than for report view but + // enumerating all items is still not a way to do it!! + for ( size_t current = 0; current < count; current++ ) + { + flags = HitTestLine(current, x, y); + if ( flags ) + return current; + } + } + + return wxNOT_FOUND; +} + +// ---------------------------------------------------------------------------- +// adding stuff +// ---------------------------------------------------------------------------- + +void wxListMainWindow::InsertItem( wxListItem &item ) +{ + wxASSERT_MSG( !IsVirtual(), _T("can't be used with virtual control") ); + + int count = GetItemCount(); + wxCHECK_RET( item.m_itemId >= 0, _T("invalid item index") ); + + if (item.m_itemId > count) + item.m_itemId = count; + + size_t id = item.m_itemId; + + m_dirty = true; + + if ( InReportView() ) + { + ResetVisibleLinesRange(); + + // calculate the width of the item and adjust the max column width + wxColWidthInfo *pWidthInfo = m_aColWidths.Item(item.GetColumn()); + int width = GetItemWidthWithImage(&item); + item.SetWidth(width); + if (width > pWidthInfo->nMaxWidth) + pWidthInfo->nMaxWidth = width; + } + + wxListLineData *line = new wxListLineData(this); + + line->SetItem( item.m_col, item ); + + m_lines.Insert( line, id ); + + m_dirty = true; + + // If an item is selected at or below the point of insertion, we need to + // increment the member variables because the current row's index has gone + // up by one + if ( HasCurrent() && m_current >= id ) + m_current++; + + SendNotify(id, wxEVT_COMMAND_LIST_INSERT_ITEM); + + RefreshLines(id, GetItemCount() - 1); +} + +void wxListMainWindow::InsertColumn( long col, wxListItem &item ) +{ + m_dirty = true; + if ( InReportView() ) + { + if (item.m_width == wxLIST_AUTOSIZE_USEHEADER) + item.m_width = GetTextLength( item.m_text ); + + wxListHeaderData *column = new wxListHeaderData( item ); + wxColWidthInfo *colWidthInfo = new wxColWidthInfo(); + + bool insert = (col >= 0) && ((size_t)col < m_columns.GetCount()); + if ( insert ) + { + wxListHeaderDataList::compatibility_iterator + node = m_columns.Item( col ); + m_columns.Insert( node, column ); + m_aColWidths.Insert( colWidthInfo, col ); + } + else + { + m_columns.Append( column ); + m_aColWidths.Add( colWidthInfo ); + } + + if ( !IsVirtual() ) + { + // update all the items + for ( size_t i = 0; i < m_lines.GetCount(); i++ ) + { + wxListLineData * const line = GetLine(i); + wxListItemData * const data = new wxListItemData(this); + if ( insert ) + line->m_items.Insert(col, data); + else + line->m_items.Append(data); + } + } + + // invalidate it as it has to be recalculated + m_headerWidth = 0; + } +} + +int wxListMainWindow::GetItemWidthWithImage(wxListItem * item) +{ + int width = 0; + wxClientDC dc(this); + + dc.SetFont( GetFont() ); + + if (item->GetImage() != -1) + { + int ix, iy; + GetImageSize( item->GetImage(), ix, iy ); + width += ix + 5; + } + + if (!item->GetText().empty()) + { + wxCoord w; + dc.GetTextExtent( item->GetText(), &w, NULL ); + width += w; + } + + return width; +} + +// ---------------------------------------------------------------------------- +// sorting +// ---------------------------------------------------------------------------- + +wxListCtrlCompare list_ctrl_compare_func_2; +long list_ctrl_compare_data; + +int LINKAGEMODE list_ctrl_compare_func_1( wxListLineData **arg1, wxListLineData **arg2 ) +{ + wxListLineData *line1 = *arg1; + wxListLineData *line2 = *arg2; + wxListItem item; + line1->GetItem( 0, item ); + wxUIntPtr data1 = item.m_data; + line2->GetItem( 0, item ); + wxUIntPtr data2 = item.m_data; + return list_ctrl_compare_func_2( data1, data2, list_ctrl_compare_data ); +} + +void wxListMainWindow::SortItems( wxListCtrlCompare fn, long data ) +{ + // selections won't make sense any more after sorting the items so reset + // them + HighlightAll(false); + ResetCurrent(); + + list_ctrl_compare_func_2 = fn; + list_ctrl_compare_data = data; + m_lines.Sort( list_ctrl_compare_func_1 ); + m_dirty = true; +} + +// ---------------------------------------------------------------------------- +// scrolling +// ---------------------------------------------------------------------------- + +void wxListMainWindow::OnScroll(wxScrollWinEvent& event) +{ + // FIXME +#if ( defined(__WXGTK__) || defined(__WXMAC__) ) && !defined(__WXUNIVERSAL__) + wxScrolledWindow::OnScroll(event); +#else + HandleOnScroll( event ); +#endif + + // update our idea of which lines are shown when we redraw the window the + // next time + ResetVisibleLinesRange(); + + if ( event.GetOrientation() == wxHORIZONTAL && HasHeader() ) + { + wxGenericListCtrl* lc = GetListCtrl(); + wxCHECK_RET( lc, _T("no listctrl window?") ); + + lc->m_headerWin->Refresh(); + lc->m_headerWin->Update(); + } +} + +int wxListMainWindow::GetCountPerPage() const +{ + if ( !m_linesPerPage ) + { + wxConstCast(this, wxListMainWindow)-> + m_linesPerPage = GetClientSize().y / GetLineHeight(); + } + + return m_linesPerPage; +} + +void wxListMainWindow::GetVisibleLinesRange(size_t *from, size_t *to) +{ + wxASSERT_MSG( InReportView(), _T("this is for report mode only") ); + + if ( m_lineFrom == (size_t)-1 ) + { + size_t count = GetItemCount(); + if ( count ) + { + m_lineFrom = GetScrollPos(wxVERTICAL); + + // this may happen if SetScrollbars() hadn't been called yet + if ( m_lineFrom >= count ) + m_lineFrom = count - 1; + + // we redraw one extra line but this is needed to make the redrawing + // logic work when there is a fractional number of lines on screen + m_lineTo = m_lineFrom + m_linesPerPage; + if ( m_lineTo >= count ) + m_lineTo = count - 1; + } + else // empty control + { + m_lineFrom = 0; + m_lineTo = (size_t)-1; + } + } + + wxASSERT_MSG( IsEmpty() || + (m_lineFrom <= m_lineTo && m_lineTo < GetItemCount()), + _T("GetVisibleLinesRange() returns incorrect result") ); + + if ( from ) + *from = m_lineFrom; + if ( to ) + *to = m_lineTo; +} + +// ------------------------------------------------------------------------------------- +// wxGenericListCtrl +// ------------------------------------------------------------------------------------- + +IMPLEMENT_DYNAMIC_CLASS(wxGenericListCtrl, wxControl) + +BEGIN_EVENT_TABLE(wxGenericListCtrl,wxControl) + EVT_SIZE(wxGenericListCtrl::OnSize) +END_EVENT_TABLE() + +wxGenericListCtrl::wxGenericListCtrl() +{ + m_imageListNormal = (wxImageList *) NULL; + m_imageListSmall = (wxImageList *) NULL; + m_imageListState = (wxImageList *) NULL; + + m_ownsImageListNormal = + m_ownsImageListSmall = + m_ownsImageListState = false; + + m_mainWin = (wxListMainWindow*) NULL; + m_headerWin = (wxListHeaderWindow*) NULL; + m_headerHeight = 0; +} + +wxGenericListCtrl::~wxGenericListCtrl() +{ + if (m_ownsImageListNormal) + delete m_imageListNormal; + if (m_ownsImageListSmall) + delete m_imageListSmall; + if (m_ownsImageListState) + delete m_imageListState; +} + +void wxGenericListCtrl::CalculateAndSetHeaderHeight() +{ + if ( m_headerWin ) + { +#ifdef __WXMAC__ + SInt32 h; + GetThemeMetric( kThemeMetricListHeaderHeight, &h ); +#else + // we use 'g' to get the descent, too + int w, h, d; + m_headerWin->GetTextExtent(wxT("Hg"), &w, &h, &d); + h += d + 2 * HEADER_OFFSET_Y + EXTRA_HEIGHT; +#endif + + // only update if changed + if ( h != m_headerHeight ) + { + m_headerHeight = h; + + if ( HasHeader() ) + ResizeReportView(true); + else //why is this needed if it doesn't have a header? + m_headerWin->SetSize(m_headerWin->GetSize().x, m_headerHeight); + } + } +} + +void wxGenericListCtrl::CreateHeaderWindow() +{ + m_headerWin = new wxListHeaderWindow + ( + this, wxID_ANY, m_mainWin, + wxPoint(0,0), + wxSize(GetClientSize().x, m_headerHeight), + wxTAB_TRAVERSAL + ); + CalculateAndSetHeaderHeight(); +} + +bool wxGenericListCtrl::Create(wxWindow *parent, + wxWindowID id, + const wxPoint &pos, + const wxSize &size, + long style, + const wxValidator &validator, + const wxString &name) +{ + m_imageListNormal = + m_imageListSmall = + m_imageListState = (wxImageList *) NULL; + m_ownsImageListNormal = + m_ownsImageListSmall = + m_ownsImageListState = false; + + m_mainWin = (wxListMainWindow*) NULL; + m_headerWin = (wxListHeaderWindow*) NULL; + + m_headerHeight = 0; + + if ( !(style & wxLC_MASK_TYPE) ) + { + style = style | wxLC_LIST; + } + + // add more styles here that should only appear + // in the main window + unsigned long only_main_window_style = wxALWAYS_SHOW_SB; + + if ( !wxControl::Create( parent, id, pos, size, style & ~only_main_window_style, validator, name ) ) + return false; + + // don't create the inner window with the border + style &= ~wxBORDER_MASK; + + m_mainWin = new wxListMainWindow( this, wxID_ANY, wxPoint(0, 0), size, style ); + +#ifdef __WXMAC_CARBON__ + // Human Interface Guidelines ask us for a special font in this case + if ( GetWindowVariant() == wxWINDOW_VARIANT_NORMAL ) + { + wxFont font; + font.MacCreateThemeFont( kThemeViewsFont ); + SetFont( font ); + } +#endif + + if ( InReportView() ) + { + CreateHeaderWindow(); + +#ifdef __WXMAC_CARBON__ + if (m_headerWin) + { + wxFont font; + font.MacCreateThemeFont( kThemeSmallSystemFont ); + m_headerWin->SetFont( font ); + CalculateAndSetHeaderHeight(); + } +#endif + + if ( HasFlag(wxLC_NO_HEADER) ) + // VZ: why do we create it at all then? + m_headerWin->Show( false ); + } + + SetInitialSize(size); + + return true; +} + +void wxGenericListCtrl::SetSingleStyle( long style, bool add ) +{ + wxASSERT_MSG( !(style & wxLC_VIRTUAL), + _T("wxLC_VIRTUAL can't be [un]set") ); + + long flag = GetWindowStyle(); + + if (add) + { + if (style & wxLC_MASK_TYPE) + flag &= ~(wxLC_MASK_TYPE | wxLC_VIRTUAL); + if (style & wxLC_MASK_ALIGN) + flag &= ~wxLC_MASK_ALIGN; + if (style & wxLC_MASK_SORT) + flag &= ~wxLC_MASK_SORT; + } + + if (add) + flag |= style; + else + flag &= ~style; + + // some styles can be set without recreating everything (as happens in + // SetWindowStyleFlag() which calls wxListMainWindow::DeleteEverything()) + if ( !(style & ~(wxLC_HRULES | wxLC_VRULES)) ) + { + Refresh(); + wxWindow::SetWindowStyleFlag(flag); + } + else + { + SetWindowStyleFlag( flag ); + } +} + +void wxGenericListCtrl::SetWindowStyleFlag( long flag ) +{ + if (m_mainWin) + { + m_mainWin->DeleteEverything(); + + // has the header visibility changed? + bool hasHeader = HasHeader(); + bool willHaveHeader = (flag & wxLC_REPORT) && !(flag & wxLC_NO_HEADER); + + if ( hasHeader != willHaveHeader ) + { + // toggle it + if ( hasHeader ) + { + if ( m_headerWin ) + { + // don't delete, just hide, as we can reuse it later + m_headerWin->Show(false); + } + //else: nothing to do + } + else // must show header + { + if (!m_headerWin) + { + CreateHeaderWindow(); + } + else // already have it, just show + { + m_headerWin->Show( true ); + } + } + + ResizeReportView(willHaveHeader); + } + } + + wxWindow::SetWindowStyleFlag( flag ); +} + +bool wxGenericListCtrl::GetColumn(int col, wxListItem &item) const +{ + m_mainWin->GetColumn( col, item ); + return true; +} + +bool wxGenericListCtrl::SetColumn( int col, wxListItem& item ) +{ + m_mainWin->SetColumn( col, item ); + return true; +} + +int wxGenericListCtrl::GetColumnWidth( int col ) const +{ + return m_mainWin->GetColumnWidth( col ); +} + +bool wxGenericListCtrl::SetColumnWidth( int col, int width ) +{ + m_mainWin->SetColumnWidth( col, width ); + return true; +} + +int wxGenericListCtrl::GetCountPerPage() const +{ + return m_mainWin->GetCountPerPage(); // different from Windows ? +} + +bool wxGenericListCtrl::GetItem( wxListItem &info ) const +{ + m_mainWin->GetItem( info ); + return true; +} + +bool wxGenericListCtrl::SetItem( wxListItem &info ) +{ + m_mainWin->SetItem( info ); + return true; +} + +long wxGenericListCtrl::SetItem( long index, int col, const wxString& label, int imageId ) +{ + wxListItem info; + info.m_text = label; + info.m_mask = wxLIST_MASK_TEXT; + info.m_itemId = index; + info.m_col = col; + if ( imageId > -1 ) + { + info.m_image = imageId; + info.m_mask |= wxLIST_MASK_IMAGE; + } + + m_mainWin->SetItem(info); + return true; +} + +int wxGenericListCtrl::GetItemState( long item, long stateMask ) const +{ + return m_mainWin->GetItemState( item, stateMask ); +} + +bool wxGenericListCtrl::SetItemState( long item, long state, long stateMask ) +{ + m_mainWin->SetItemState( item, state, stateMask ); + return true; +} + +bool +wxGenericListCtrl::SetItemImage( long item, int image, int WXUNUSED(selImage) ) +{ + return SetItemColumnImage(item, 0, image); +} + +bool +wxGenericListCtrl::SetItemColumnImage( long item, long column, int image ) +{ + wxListItem info; + info.m_image = image; + info.m_mask = wxLIST_MASK_IMAGE; + info.m_itemId = item; + info.m_col = column; + m_mainWin->SetItem( info ); + return true; +} + +wxString wxGenericListCtrl::GetItemText( long item ) const +{ + return m_mainWin->GetItemText(item); +} + +void wxGenericListCtrl::SetItemText( long item, const wxString& str ) +{ + m_mainWin->SetItemText(item, str); +} + +wxUIntPtr wxGenericListCtrl::GetItemData( long item ) const +{ + wxListItem info; + info.m_mask = wxLIST_MASK_DATA; + info.m_itemId = item; + m_mainWin->GetItem( info ); + return info.m_data; +} + +bool wxGenericListCtrl::SetItemPtrData( long item, wxUIntPtr data ) +{ + wxListItem info; + info.m_mask = wxLIST_MASK_DATA; + info.m_itemId = item; + info.m_data = data; + m_mainWin->SetItem( info ); + return true; +} + +bool wxGenericListCtrl::SetItemData(long item, long data) +{ + return SetItemPtrData(item, data); +} + +wxRect wxGenericListCtrl::GetViewRect() const +{ + return m_mainWin->GetViewRect(); +} + +bool wxGenericListCtrl::GetItemRect( long item, wxRect &rect, int WXUNUSED(code) ) const +{ + m_mainWin->GetItemRect( item, rect ); + if ( m_mainWin->HasHeader() ) + rect.y += m_headerHeight + 1; + return true; +} + +bool wxGenericListCtrl::GetItemPosition( long item, wxPoint& pos ) const +{ + m_mainWin->GetItemPosition( item, pos ); + return true; +} + +bool wxGenericListCtrl::SetItemPosition( long WXUNUSED(item), const wxPoint& WXUNUSED(pos) ) +{ + return 0; +} + +int wxGenericListCtrl::GetItemCount() const +{ + return m_mainWin->GetItemCount(); +} + +int wxGenericListCtrl::GetColumnCount() const +{ + return m_mainWin->GetColumnCount(); +} + +void wxGenericListCtrl::SetItemSpacing( int spacing, bool isSmall ) +{ + m_mainWin->SetItemSpacing( spacing, isSmall ); +} + +wxSize wxGenericListCtrl::GetItemSpacing() const +{ + const int spacing = m_mainWin->GetItemSpacing(HasFlag(wxLC_SMALL_ICON)); + + return wxSize(spacing, spacing); +} + +#if WXWIN_COMPATIBILITY_2_6 +int wxGenericListCtrl::GetItemSpacing( bool isSmall ) const +{ + return m_mainWin->GetItemSpacing( isSmall ); +} +#endif // WXWIN_COMPATIBILITY_2_6 + +void wxGenericListCtrl::SetItemTextColour( long item, const wxColour &col ) +{ + wxListItem info; + info.m_itemId = item; + info.SetTextColour( col ); + m_mainWin->SetItem( info ); +} + +wxColour wxGenericListCtrl::GetItemTextColour( long item ) const +{ + wxListItem info; + info.m_itemId = item; + m_mainWin->GetItem( info ); + return info.GetTextColour(); +} + +void wxGenericListCtrl::SetItemBackgroundColour( long item, const wxColour &col ) +{ + wxListItem info; + info.m_itemId = item; + info.SetBackgroundColour( col ); + m_mainWin->SetItem( info ); +} + +wxColour wxGenericListCtrl::GetItemBackgroundColour( long item ) const +{ + wxListItem info; + info.m_itemId = item; + m_mainWin->GetItem( info ); + return info.GetBackgroundColour(); +} + +int wxGenericListCtrl::GetScrollPos( int orient ) const +{ + return m_mainWin->GetScrollPos( orient ); +} + +void wxGenericListCtrl::SetScrollPos( int orient, int pos, bool refresh ) +{ + m_mainWin->SetScrollPos( orient, pos, refresh ); +} + +void wxGenericListCtrl::SetItemFont( long item, const wxFont &f ) +{ + wxListItem info; + info.m_itemId = item; + info.SetFont( f ); + m_mainWin->SetItem( info ); +} + +wxFont wxGenericListCtrl::GetItemFont( long item ) const +{ + wxListItem info; + info.m_itemId = item; + m_mainWin->GetItem( info ); + return info.GetFont(); +} + +int wxGenericListCtrl::GetSelectedItemCount() const +{ + return m_mainWin->GetSelectedItemCount(); +} + +wxColour wxGenericListCtrl::GetTextColour() const +{ + return GetForegroundColour(); +} + +void wxGenericListCtrl::SetTextColour(const wxColour& col) +{ + SetForegroundColour(col); +} + +long wxGenericListCtrl::GetTopItem() const +{ + size_t top; + m_mainWin->GetVisibleLinesRange(&top, NULL); + return (long)top; +} + +long wxGenericListCtrl::GetNextItem( long item, int geom, int state ) const +{ + return m_mainWin->GetNextItem( item, geom, state ); +} + +wxImageList *wxGenericListCtrl::GetImageList(int which) const +{ + if (which == wxIMAGE_LIST_NORMAL) + return m_imageListNormal; + else if (which == wxIMAGE_LIST_SMALL) + return m_imageListSmall; + else if (which == wxIMAGE_LIST_STATE) + return m_imageListState; + + return (wxImageList *) NULL; +} + +void wxGenericListCtrl::SetImageList( wxImageList *imageList, int which ) +{ + if ( which == wxIMAGE_LIST_NORMAL ) + { + if (m_ownsImageListNormal) + delete m_imageListNormal; + m_imageListNormal = imageList; + m_ownsImageListNormal = false; + } + else if ( which == wxIMAGE_LIST_SMALL ) + { + if (m_ownsImageListSmall) + delete m_imageListSmall; + m_imageListSmall = imageList; + m_ownsImageListSmall = false; + } + else if ( which == wxIMAGE_LIST_STATE ) + { + if (m_ownsImageListState) + delete m_imageListState; + m_imageListState = imageList; + m_ownsImageListState = false; + } + + m_mainWin->SetImageList( imageList, which ); +} + +void wxGenericListCtrl::AssignImageList(wxImageList *imageList, int which) +{ + SetImageList(imageList, which); + if ( which == wxIMAGE_LIST_NORMAL ) + m_ownsImageListNormal = true; + else if ( which == wxIMAGE_LIST_SMALL ) + m_ownsImageListSmall = true; + else if ( which == wxIMAGE_LIST_STATE ) + m_ownsImageListState = true; +} + +bool wxGenericListCtrl::Arrange( int WXUNUSED(flag) ) +{ + return 0; +} + +bool wxGenericListCtrl::DeleteItem( long item ) +{ + m_mainWin->DeleteItem( item ); + return true; +} + +bool wxGenericListCtrl::DeleteAllItems() +{ + m_mainWin->DeleteAllItems(); + return true; +} + +bool wxGenericListCtrl::DeleteAllColumns() +{ + size_t count = m_mainWin->m_columns.GetCount(); + for ( size_t n = 0; n < count; n++ ) + DeleteColumn( 0 ); + return true; +} + +void wxGenericListCtrl::ClearAll() +{ + m_mainWin->DeleteEverything(); +} + +bool wxGenericListCtrl::DeleteColumn( int col ) +{ + m_mainWin->DeleteColumn( col ); + + // if we don't have the header any longer, we need to relayout the window + if ( !GetColumnCount() ) + ResizeReportView(false /* no header */); + return true; +} + +wxTextCtrl *wxGenericListCtrl::EditLabel(long item, + wxClassInfo* textControlClass) +{ + return m_mainWin->EditLabel( item, textControlClass ); +} + +wxTextCtrl *wxGenericListCtrl::GetEditControl() const +{ + return m_mainWin->GetEditControl(); +} + +bool wxGenericListCtrl::EnsureVisible( long item ) +{ + m_mainWin->EnsureVisible( item ); + return true; +} + +long wxGenericListCtrl::FindItem( long start, const wxString& str, bool partial ) +{ + return m_mainWin->FindItem( start, str, partial ); +} + +long wxGenericListCtrl::FindItem( long start, wxUIntPtr data ) +{ + return m_mainWin->FindItem( start, data ); +} + +long wxGenericListCtrl::FindItem( long WXUNUSED(start), const wxPoint& pt, + int WXUNUSED(direction)) +{ + return m_mainWin->FindItem( pt ); +} + +// TODO: sub item hit testing +long wxGenericListCtrl::HitTest(const wxPoint& point, int& flags, long *) const +{ + return m_mainWin->HitTest( (int)point.x, (int)point.y, flags ); +} + +long wxGenericListCtrl::InsertItem( wxListItem& info ) +{ + m_mainWin->InsertItem( info ); + return info.m_itemId; +} + +long wxGenericListCtrl::InsertItem( long index, const wxString &label ) +{ + wxListItem info; + info.m_text = label; + info.m_mask = wxLIST_MASK_TEXT; + info.m_itemId = index; + return InsertItem( info ); +} + +long wxGenericListCtrl::InsertItem( long index, int imageIndex ) +{ + wxListItem info; + info.m_mask = wxLIST_MASK_IMAGE; + info.m_image = imageIndex; + info.m_itemId = index; + return InsertItem( info ); +} + +long wxGenericListCtrl::InsertItem( long index, const wxString &label, int imageIndex ) +{ + wxListItem info; + info.m_text = label; + info.m_image = imageIndex; + info.m_mask = wxLIST_MASK_TEXT | wxLIST_MASK_IMAGE; + info.m_itemId = index; + return InsertItem( info ); +} + +long wxGenericListCtrl::InsertColumn( long col, wxListItem &item ) +{ + wxCHECK_MSG( m_headerWin, -1, _T("can't add column in non report mode") ); + + m_mainWin->InsertColumn( col, item ); + + // if we hadn't had a header before but have one now + // then we need to relayout the window + if ( GetColumnCount() == 1 && m_mainWin->HasHeader() ) + ResizeReportView(true /* have header */); + + m_headerWin->Refresh(); + + return 0; +} + +long wxGenericListCtrl::InsertColumn( long col, const wxString &heading, + int format, int width ) +{ + wxListItem item; + item.m_mask = wxLIST_MASK_TEXT | wxLIST_MASK_FORMAT; + item.m_text = heading; + if (width >= -2) + { + item.m_mask |= wxLIST_MASK_WIDTH; + item.m_width = width; + } + + item.m_format = format; + + return InsertColumn( col, item ); +} + +bool wxGenericListCtrl::ScrollList( int dx, int dy ) +{ + return m_mainWin->ScrollList(dx, dy); +} + +// Sort items. +// fn is a function which takes 3 long arguments: item1, item2, data. +// item1 is the long data associated with a first item (NOT the index). +// item2 is the long data associated with a second item (NOT the index). +// data is the same value as passed to SortItems. +// The return value is a negative number if the first item should precede the second +// item, a positive number of the second item should precede the first, +// or zero if the two items are equivalent. +// data is arbitrary data to be passed to the sort function. + +bool wxGenericListCtrl::SortItems( wxListCtrlCompare fn, long data ) +{ + m_mainWin->SortItems( fn, data ); + return true; +} + +// ---------------------------------------------------------------------------- +// event handlers +// ---------------------------------------------------------------------------- + +void wxGenericListCtrl::OnSize(wxSizeEvent& WXUNUSED(event)) +{ + if ( !m_mainWin ) + return; + + ResizeReportView(m_mainWin->HasHeader()); + m_mainWin->RecalculatePositions(); +} + +void wxGenericListCtrl::ResizeReportView(bool showHeader) +{ + int cw, ch; + GetClientSize( &cw, &ch ); + + if ( showHeader ) + { + m_headerWin->SetSize( 0, 0, cw, m_headerHeight ); + if(ch > m_headerHeight) + m_mainWin->SetSize( 0, m_headerHeight + 1, + cw, ch - m_headerHeight - 1 ); + else + m_mainWin->SetSize( 0, m_headerHeight + 1, + cw, 0); + } + else // no header window + { + m_mainWin->SetSize( 0, 0, cw, ch ); + } +} + +void wxGenericListCtrl::OnInternalIdle() +{ + wxWindow::OnInternalIdle(); + + // do it only if needed + if ( !m_mainWin->m_dirty ) + return; + + m_mainWin->RecalculatePositions(); +} + +// ---------------------------------------------------------------------------- +// font/colours +// ---------------------------------------------------------------------------- + +bool wxGenericListCtrl::SetBackgroundColour( const wxColour &colour ) +{ + if (m_mainWin) + { + m_mainWin->SetBackgroundColour( colour ); + m_mainWin->m_dirty = true; + } + + return true; +} + +bool wxGenericListCtrl::SetForegroundColour( const wxColour &colour ) +{ + if ( !wxWindow::SetForegroundColour( colour ) ) + return false; + + if (m_mainWin) + { + m_mainWin->SetForegroundColour( colour ); + m_mainWin->m_dirty = true; + } + + if (m_headerWin) + m_headerWin->SetForegroundColour( colour ); + + return true; +} + +bool wxGenericListCtrl::SetFont( const wxFont &font ) +{ + if ( !wxWindow::SetFont( font ) ) + return false; + + if (m_mainWin) + { + m_mainWin->SetFont( font ); + m_mainWin->m_dirty = true; + } + + if (m_headerWin) + { + m_headerWin->SetFont( font ); + CalculateAndSetHeaderHeight(); + } + + Refresh(); + + return true; +} + +// static +wxVisualAttributes +wxGenericListCtrl::GetClassDefaultAttributes(wxWindowVariant variant) +{ +#if _USE_VISATTR + // Use the same color scheme as wxListBox + return wxListBox::GetClassDefaultAttributes(variant); +#else + wxUnusedVar(variant); + wxVisualAttributes attr; + attr.colFg = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT); + attr.colBg = wxSystemSettings::GetColour(wxSYS_COLOUR_LISTBOX); + attr.font = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT); + return attr; +#endif +} + +// ---------------------------------------------------------------------------- +// methods forwarded to m_mainWin +// ---------------------------------------------------------------------------- + +#if wxUSE_DRAG_AND_DROP + +void wxGenericListCtrl::SetDropTarget( wxDropTarget *dropTarget ) +{ + m_mainWin->SetDropTarget( dropTarget ); +} + +wxDropTarget *wxGenericListCtrl::GetDropTarget() const +{ + return m_mainWin->GetDropTarget(); +} + +#endif + +bool wxGenericListCtrl::SetCursor( const wxCursor &cursor ) +{ + return m_mainWin ? m_mainWin->wxWindow::SetCursor(cursor) : false; +} + +wxColour wxGenericListCtrl::GetBackgroundColour() const +{ + return m_mainWin ? m_mainWin->GetBackgroundColour() : wxColour(); +} + +wxColour wxGenericListCtrl::GetForegroundColour() const +{ + return m_mainWin ? m_mainWin->GetForegroundColour() : wxColour(); +} + +bool wxGenericListCtrl::DoPopupMenu( wxMenu *menu, int x, int y ) +{ +#if wxUSE_MENUS + return m_mainWin->PopupMenu( menu, x, y ); +#else + return false; +#endif +} + +void wxGenericListCtrl::DoClientToScreen( int *x, int *y ) const +{ + m_mainWin->DoClientToScreen(x, y); +} + +void wxGenericListCtrl::DoScreenToClient( int *x, int *y ) const +{ + m_mainWin->DoScreenToClient(x, y); +} + +void wxGenericListCtrl::SetFocus() +{ + // The test in window.cpp fails as we are a composite + // window, so it checks against "this", but not m_mainWin. + if ( DoFindFocus() != this ) + m_mainWin->SetFocus(); +} + +wxSize wxGenericListCtrl::DoGetBestSize() const +{ + // Something is better than nothing... + // 100x80 is what the MSW version will get from the default + // wxControl::DoGetBestSize + return wxSize(100, 80); +} + +// ---------------------------------------------------------------------------- +// virtual list control support +// ---------------------------------------------------------------------------- + +wxString wxGenericListCtrl::OnGetItemText(long WXUNUSED(item), long WXUNUSED(col)) const +{ + // this is a pure virtual function, in fact - which is not really pure + // because the controls which are not virtual don't need to implement it + wxFAIL_MSG( _T("wxGenericListCtrl::OnGetItemText not supposed to be called") ); + + return wxEmptyString; +} + +int wxGenericListCtrl::OnGetItemImage(long WXUNUSED(item)) const +{ + wxCHECK_MSG(!GetImageList(wxIMAGE_LIST_SMALL), + -1, + wxT("List control has an image list, OnGetItemImage or OnGetItemColumnImage should be overridden.")); + return -1; +} + +int wxGenericListCtrl::OnGetItemColumnImage(long item, long column) const +{ + if (!column) + return OnGetItemImage(item); + + return -1; +} + +wxListItemAttr * +wxGenericListCtrl::OnGetItemAttr(long WXUNUSED_UNLESS_DEBUG(item)) const +{ + wxASSERT_MSG( item >= 0 && item < GetItemCount(), + _T("invalid item index in OnGetItemAttr()") ); + + // no attributes by default + return NULL; +} + +void wxGenericListCtrl::SetItemCount(long count) +{ + wxASSERT_MSG( IsVirtual(), _T("this is for virtual controls only") ); + + m_mainWin->SetItemCount(count); +} + +void wxGenericListCtrl::RefreshItem(long item) +{ + m_mainWin->RefreshLine(item); +} + +void wxGenericListCtrl::RefreshItems(long itemFrom, long itemTo) +{ + m_mainWin->RefreshLines(itemFrom, itemTo); +} + +// Generic wxListCtrl is more or less a container for two other +// windows which drawings are done upon. These are namely +// 'm_headerWin' and 'm_mainWin'. +// Here we override 'virtual wxWindow::Refresh()' to mimic the +// behaviour wxListCtrl has under wxMSW. +// +void wxGenericListCtrl::Refresh(bool eraseBackground, const wxRect *rect) +{ + if (!rect) + { + // The easy case, no rectangle specified. + if (m_headerWin) + m_headerWin->Refresh(eraseBackground); + + if (m_mainWin) + m_mainWin->Refresh(eraseBackground); + } + else + { + // Refresh the header window + if (m_headerWin) + { + wxRect rectHeader = m_headerWin->GetRect(); + rectHeader.Intersect(*rect); + if (rectHeader.GetWidth() && rectHeader.GetHeight()) + { + int x, y; + m_headerWin->GetPosition(&x, &y); + rectHeader.Offset(-x, -y); + m_headerWin->Refresh(eraseBackground, &rectHeader); + } + } + + // Refresh the main window + if (m_mainWin) + { + wxRect rectMain = m_mainWin->GetRect(); + rectMain.Intersect(*rect); + if (rectMain.GetWidth() && rectMain.GetHeight()) + { + int x, y; + m_mainWin->GetPosition(&x, &y); + rectMain.Offset(-x, -y); + m_mainWin->Refresh(eraseBackground, &rectMain); + } + } + } +} + +void wxGenericListCtrl::Freeze() +{ + m_mainWin->Freeze(); +} + +void wxGenericListCtrl::Thaw() +{ + m_mainWin->Thaw(); +} + +#endif // wxUSE_LISTCTRL diff --git a/Externals/wxWidgets/src/generic/logg.cpp b/Externals/wxWidgets/src/generic/logg.cpp index e370dc4eac..4cd133e9b4 100644 --- a/Externals/wxWidgets/src/generic/logg.cpp +++ b/Externals/wxWidgets/src/generic/logg.cpp @@ -1,1229 +1,1229 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/generic/logg.cpp -// Purpose: wxLog-derived classes which need GUI support (the rest is in -// src/common/log.cpp) -// Author: Vadim Zeitlin -// Modified by: -// Created: 20.09.99 (extracted from src/common/log.cpp) -// RCS-ID: $Id: logg.cpp 43078 2006-11-04 23:46:02Z VZ $ -// Copyright: (c) 1998 Vadim Zeitlin -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#ifndef WX_PRECOMP - #include "wx/app.h" - #include "wx/button.h" - #include "wx/intl.h" - #include "wx/log.h" - #include "wx/menu.h" - #include "wx/frame.h" - #include "wx/filedlg.h" - #include "wx/msgdlg.h" - #include "wx/textctrl.h" - #include "wx/sizer.h" - #include "wx/statbmp.h" - #include "wx/settings.h" -#endif // WX_PRECOMP - -#if wxUSE_LOGGUI || wxUSE_LOGWINDOW - -#include "wx/file.h" -#include "wx/textfile.h" -#include "wx/statline.h" -#include "wx/artprov.h" - -#ifdef __WXMSW__ - // for OutputDebugString() - #include "wx/msw/private.h" -#endif // Windows - -#ifdef __WXPM__ - #include -#endif - -#if wxUSE_LOG_DIALOG - #include "wx/listctrl.h" - #include "wx/imaglist.h" - #include "wx/image.h" -#endif // wxUSE_LOG_DIALOG/!wxUSE_LOG_DIALOG - -#if defined(__MWERKS__) && wxUSE_UNICODE - #include -#endif - -#include "wx/datetime.h" - -// the suffix we add to the button to show that the dialog can be expanded -#define EXPAND_SUFFIX _T(" >>") - -// ---------------------------------------------------------------------------- -// private classes -// ---------------------------------------------------------------------------- - -#if wxUSE_LOG_DIALOG - -// this function is a wrapper around strftime(3) -// allows to exclude the usage of wxDateTime -static wxString TimeStamp(const wxChar *format, time_t t) -{ -#if wxUSE_DATETIME - wxChar buf[4096]; - struct tm tm; - if ( !wxStrftime(buf, WXSIZEOF(buf), format, wxLocaltime_r(&t, &tm)) ) - { - // buffer is too small? - wxFAIL_MSG(_T("strftime() failed")); - } - return wxString(buf); -#else // !wxUSE_DATETIME - return wxEmptyString; -#endif // wxUSE_DATETIME/!wxUSE_DATETIME -} - - -class wxLogDialog : public wxDialog -{ -public: - wxLogDialog(wxWindow *parent, - const wxArrayString& messages, - const wxArrayInt& severity, - const wxArrayLong& timess, - const wxString& caption, - long style); - virtual ~wxLogDialog(); - - // event handlers - void OnOk(wxCommandEvent& event); - void OnDetails(wxCommandEvent& event); -#if wxUSE_FILE - void OnSave(wxCommandEvent& event); -#endif // wxUSE_FILE - void OnListSelect(wxListEvent& event); - -private: - // create controls needed for the details display - void CreateDetailsControls(); - - // the data for the listctrl - wxArrayString m_messages; - wxArrayInt m_severity; - wxArrayLong m_times; - - // the "toggle" button and its state -#ifndef __SMARTPHONE__ - wxButton *m_btnDetails; -#endif - bool m_showingDetails; - - // the controls which are not shown initially (but only when details - // button is pressed) - wxListCtrl *m_listctrl; -#ifndef __SMARTPHONE__ -#if wxUSE_STATLINE - wxStaticLine *m_statline; -#endif // wxUSE_STATLINE -#if wxUSE_FILE - wxButton *m_btnSave; -#endif // wxUSE_FILE -#endif // __SMARTPHONE__ - - // the translated "Details" string - static wxString ms_details; - - DECLARE_EVENT_TABLE() - DECLARE_NO_COPY_CLASS(wxLogDialog) -}; - -BEGIN_EVENT_TABLE(wxLogDialog, wxDialog) - EVT_BUTTON(wxID_OK, wxLogDialog::OnOk) - EVT_BUTTON(wxID_MORE, wxLogDialog::OnDetails) -#if wxUSE_FILE - EVT_BUTTON(wxID_SAVE, wxLogDialog::OnSave) -#endif // wxUSE_FILE - EVT_LIST_ITEM_SELECTED(wxID_ANY, wxLogDialog::OnListSelect) -END_EVENT_TABLE() - -#endif // wxUSE_LOG_DIALOG - -// ---------------------------------------------------------------------------- -// private functions -// ---------------------------------------------------------------------------- - -#if wxUSE_FILE && wxUSE_FILEDLG - -// pass an uninitialized file object, the function will ask the user for the -// filename and try to open it, returns true on success (file was opened), -// false if file couldn't be opened/created and -1 if the file selection -// dialog was cancelled -static int OpenLogFile(wxFile& file, wxString *filename = NULL, wxWindow *parent = NULL); - -#endif // wxUSE_FILE - -// ---------------------------------------------------------------------------- -// global variables -// ---------------------------------------------------------------------------- - -// we use a global variable to store the frame pointer for wxLogStatus - bad, -// but it's the easiest way -static wxFrame *gs_pFrame = NULL; // FIXME MT-unsafe - -// ============================================================================ -// implementation -// ============================================================================ - -// ---------------------------------------------------------------------------- -// global functions -// ---------------------------------------------------------------------------- - -// accepts an additional argument which tells to which frame the output should -// be directed -void wxVLogStatus(wxFrame *pFrame, const wxChar *szFormat, va_list argptr) -{ - wxString msg; - - wxLog *pLog = wxLog::GetActiveTarget(); - if ( pLog != NULL ) { - msg.PrintfV(szFormat, argptr); - - wxASSERT( gs_pFrame == NULL ); // should be reset! - gs_pFrame = pFrame; -#ifdef __WXWINCE__ - wxLog::OnLog(wxLOG_Status, msg, 0); -#else - wxLog::OnLog(wxLOG_Status, msg, time(NULL)); -#endif - gs_pFrame = (wxFrame *) NULL; - } -} - -void wxLogStatus(wxFrame *pFrame, const wxChar *szFormat, ...) -{ - va_list argptr; - va_start(argptr, szFormat); - wxVLogStatus(pFrame, szFormat, argptr); - va_end(argptr); -} - -// ---------------------------------------------------------------------------- -// wxLogGui implementation (FIXME MT-unsafe) -// ---------------------------------------------------------------------------- - -#if wxUSE_LOGGUI - -wxLogGui::wxLogGui() -{ - Clear(); -} - -void wxLogGui::Clear() -{ - m_bErrors = - m_bWarnings = - m_bHasMessages = false; - - m_aMessages.Empty(); - m_aSeverity.Empty(); - m_aTimes.Empty(); -} - -void wxLogGui::Flush() -{ - if ( !m_bHasMessages ) - return; - - // do it right now to block any new calls to Flush() while we're here - m_bHasMessages = false; - - unsigned repeatCount = 0; - if ( wxLog::GetRepetitionCounting() ) - { - repeatCount = wxLog::DoLogNumberOfRepeats(); - } - - wxString appName = wxTheApp->GetAppName(); - if ( !appName.empty() ) - appName[0u] = (wxChar)wxToupper(appName[0u]); - - long style; - wxString titleFormat; - if ( m_bErrors ) { - titleFormat = _("%s Error"); - style = wxICON_STOP; - } - else if ( m_bWarnings ) { - titleFormat = _("%s Warning"); - style = wxICON_EXCLAMATION; - } - else { - titleFormat = _("%s Information"); - style = wxICON_INFORMATION; - } - - wxString title; - title.Printf(titleFormat, appName.c_str()); - - size_t nMsgCount = m_aMessages.Count(); - - // avoid showing other log dialogs until we're done with the dialog we're - // showing right now: nested modal dialogs make for really bad UI! - Suspend(); - - wxString str; - if ( nMsgCount == 1 ) - { - str = m_aMessages[0]; - } - else // more than one message - { -#if wxUSE_LOG_DIALOG - - if ( repeatCount > 0 ) - m_aMessages[nMsgCount-1] += wxString::Format(wxT(" (%s)"), m_aMessages[nMsgCount-2].c_str()); - wxLogDialog dlg(NULL, - m_aMessages, m_aSeverity, m_aTimes, - title, style); - - // clear the message list before showing the dialog because while it's - // shown some new messages may appear - Clear(); - - (void)dlg.ShowModal(); -#else // !wxUSE_LOG_DIALOG - // concatenate all strings (but not too many to not overfill the msg box) - size_t nLines = 0; - - // start from the most recent message - for ( size_t n = nMsgCount; n > 0; n-- ) { - // for Windows strings longer than this value are wrapped (NT 4.0) - const size_t nMsgLineWidth = 156; - - nLines += (m_aMessages[n - 1].Len() + nMsgLineWidth - 1) / nMsgLineWidth; - - if ( nLines > 25 ) // don't put too many lines in message box - break; - - str << m_aMessages[n - 1] << wxT("\n"); - } -#endif // wxUSE_LOG_DIALOG/!wxUSE_LOG_DIALOG - } - - // this catches both cases of 1 message with wxUSE_LOG_DIALOG and any - // situation without it - if ( !str.empty() ) - { - wxMessageBox(str, title, wxOK | style); - - // no undisplayed messages whatsoever - Clear(); - } - - // allow flushing the logs again - Resume(); -} - -// log all kinds of messages -void wxLogGui::DoLog(wxLogLevel level, const wxChar *szString, time_t t) -{ - switch ( level ) { - case wxLOG_Info: - if ( GetVerbose() ) - case wxLOG_Message: - { - m_aMessages.Add(szString); - m_aSeverity.Add(wxLOG_Message); - m_aTimes.Add((long)t); - m_bHasMessages = true; - } - break; - - case wxLOG_Status: -#if wxUSE_STATUSBAR - { - // find the top window and set it's status text if it has any - wxFrame *pFrame = gs_pFrame; - if ( pFrame == NULL ) { - wxWindow *pWin = wxTheApp->GetTopWindow(); - if ( pWin != NULL && pWin->IsKindOf(CLASSINFO(wxFrame)) ) { - pFrame = (wxFrame *)pWin; - } - } - - if ( pFrame && pFrame->GetStatusBar() ) - pFrame->SetStatusText(szString); - } -#endif // wxUSE_STATUSBAR - break; - - case wxLOG_Trace: - case wxLOG_Debug: - #ifdef __WXDEBUG__ - { - wxString str; - TimeStamp(&str); - str += szString; - - #if defined(__WXMSW__) && !defined(__WXMICROWIN__) - // don't prepend debug/trace here: it goes to the - // debug window anyhow - str += wxT("\r\n"); - OutputDebugString(str); - #else - // send them to stderr - wxFprintf(stderr, wxT("[%s] %s\n"), - level == wxLOG_Trace ? wxT("Trace") - : wxT("Debug"), - str.c_str()); - fflush(stderr); - #endif - } - #endif // __WXDEBUG__ - - break; - - case wxLOG_FatalError: - // show this one immediately - wxMessageBox(szString, _("Fatal error"), wxICON_HAND); - wxExit(); - break; - - case wxLOG_Error: - if ( !m_bErrors ) { -#if !wxUSE_LOG_DIALOG - // discard earlier informational messages if this is the 1st - // error because they might not make sense any more and showing - // them in a message box might be confusing - m_aMessages.Empty(); - m_aSeverity.Empty(); - m_aTimes.Empty(); -#endif // wxUSE_LOG_DIALOG - m_bErrors = true; - } - // fall through - - case wxLOG_Warning: - if ( !m_bErrors ) { - // for the warning we don't discard the info messages - m_bWarnings = true; - } - - m_aMessages.Add(szString); - m_aSeverity.Add((int)level); - m_aTimes.Add((long)t); - m_bHasMessages = true; - break; - } -} - -#endif // wxUSE_LOGGUI - -// ---------------------------------------------------------------------------- -// wxLogWindow and wxLogFrame implementation -// ---------------------------------------------------------------------------- - -#if wxUSE_LOGWINDOW - -// log frame class -// --------------- -class wxLogFrame : public wxFrame -{ -public: - // ctor & dtor - wxLogFrame(wxWindow *pParent, wxLogWindow *log, const wxChar *szTitle); - virtual ~wxLogFrame(); - - // menu callbacks - void OnClose(wxCommandEvent& event); - void OnCloseWindow(wxCloseEvent& event); -#if wxUSE_FILE - void OnSave (wxCommandEvent& event); -#endif // wxUSE_FILE - void OnClear(wxCommandEvent& event); - - // accessors - wxTextCtrl *TextCtrl() const { return m_pTextCtrl; } - -private: - // use standard ids for our commands! - enum - { - Menu_Close = wxID_CLOSE, - Menu_Save = wxID_SAVE, - Menu_Clear = wxID_CLEAR - }; - - // common part of OnClose() and OnCloseWindow() - void DoClose(); - - wxTextCtrl *m_pTextCtrl; - wxLogWindow *m_log; - - DECLARE_EVENT_TABLE() - DECLARE_NO_COPY_CLASS(wxLogFrame) -}; - -BEGIN_EVENT_TABLE(wxLogFrame, wxFrame) - // wxLogWindow menu events - EVT_MENU(Menu_Close, wxLogFrame::OnClose) -#if wxUSE_FILE - EVT_MENU(Menu_Save, wxLogFrame::OnSave) -#endif // wxUSE_FILE - EVT_MENU(Menu_Clear, wxLogFrame::OnClear) - - EVT_CLOSE(wxLogFrame::OnCloseWindow) -END_EVENT_TABLE() - -wxLogFrame::wxLogFrame(wxWindow *pParent, wxLogWindow *log, const wxChar *szTitle) - : wxFrame(pParent, wxID_ANY, szTitle) -{ - m_log = log; - - m_pTextCtrl = new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, - wxDefaultSize, - wxTE_MULTILINE | - wxHSCROLL | - // needed for Win32 to avoid 65Kb limit but it doesn't work well - // when using RichEdit 2.0 which we always do in the Unicode build -#if !wxUSE_UNICODE - wxTE_RICH | -#endif // !wxUSE_UNICODE - wxTE_READONLY); - -#if wxUSE_MENUS - // create menu - wxMenuBar *pMenuBar = new wxMenuBar; - wxMenu *pMenu = new wxMenu; -#if wxUSE_FILE - pMenu->Append(Menu_Save, _("&Save..."), _("Save log contents to file")); -#endif // wxUSE_FILE - pMenu->Append(Menu_Clear, _("C&lear"), _("Clear the log contents")); - pMenu->AppendSeparator(); - pMenu->Append(Menu_Close, _("&Close"), _("Close this window")); - pMenuBar->Append(pMenu, _("&Log")); - SetMenuBar(pMenuBar); -#endif // wxUSE_MENUS - -#if wxUSE_STATUSBAR - // status bar for menu prompts - CreateStatusBar(); -#endif // wxUSE_STATUSBAR - - m_log->OnFrameCreate(this); -} - -void wxLogFrame::DoClose() -{ - if ( m_log->OnFrameClose(this) ) - { - // instead of closing just hide the window to be able to Show() it - // later - Show(false); - } -} - -void wxLogFrame::OnClose(wxCommandEvent& WXUNUSED(event)) -{ - DoClose(); -} - -void wxLogFrame::OnCloseWindow(wxCloseEvent& WXUNUSED(event)) -{ - DoClose(); -} - -#if wxUSE_FILE -void wxLogFrame::OnSave(wxCommandEvent& WXUNUSED(event)) -{ -#if wxUSE_FILEDLG - wxString filename; - wxFile file; - int rc = OpenLogFile(file, &filename, this); - if ( rc == -1 ) - { - // cancelled - return; - } - - bool bOk = rc != 0; - - // retrieve text and save it - // ------------------------- - int nLines = m_pTextCtrl->GetNumberOfLines(); - for ( int nLine = 0; bOk && nLine < nLines; nLine++ ) { - bOk = file.Write(m_pTextCtrl->GetLineText(nLine) + - wxTextFile::GetEOL()); - } - - if ( bOk ) - bOk = file.Close(); - - if ( !bOk ) { - wxLogError(_("Can't save log contents to file.")); - } - else { - wxLogStatus(this, _("Log saved to the file '%s'."), filename.c_str()); - } -#endif -} -#endif // wxUSE_FILE - -void wxLogFrame::OnClear(wxCommandEvent& WXUNUSED(event)) -{ - m_pTextCtrl->Clear(); -} - -wxLogFrame::~wxLogFrame() -{ - m_log->OnFrameDelete(this); -} - -// wxLogWindow -// ----------- - -wxLogWindow::wxLogWindow(wxWindow *pParent, - const wxChar *szTitle, - bool bShow, - bool bDoPass) -{ - PassMessages(bDoPass); - - m_pLogFrame = new wxLogFrame(pParent, this, szTitle); - - if ( bShow ) - m_pLogFrame->Show(); -} - -void wxLogWindow::Show(bool bShow) -{ - m_pLogFrame->Show(bShow); -} - -void wxLogWindow::DoLog(wxLogLevel level, const wxChar *szString, time_t t) -{ - // first let the previous logger show it - wxLogPassThrough::DoLog(level, szString, t); - - if ( m_pLogFrame ) { - switch ( level ) { - case wxLOG_Status: - // by default, these messages are ignored by wxLog, so process - // them ourselves - if ( !wxIsEmpty(szString) ) - { - wxString str; - str << _("Status: ") << szString; - DoLogString(str, t); - } - break; - - // don't put trace messages in the text window for 2 reasons: - // 1) there are too many of them - // 2) they may provoke other trace messages thus sending a program - // into an infinite loop - case wxLOG_Trace: - break; - - default: - // and this will format it nicely and call our DoLogString() - wxLog::DoLog(level, szString, t); - } - } -} - -void wxLogWindow::DoLogString(const wxChar *szString, time_t WXUNUSED(t)) -{ - // put the text into our window - wxTextCtrl *pText = m_pLogFrame->TextCtrl(); - - // remove selection (WriteText is in fact ReplaceSelection) -#ifdef __WXMSW__ - wxTextPos nLen = pText->GetLastPosition(); - pText->SetSelection(nLen, nLen); -#endif // Windows - - wxString msg; - TimeStamp(&msg); - msg << szString << wxT('\n'); - - pText->AppendText(msg); - - // TODO ensure that the line can be seen -} - -wxFrame *wxLogWindow::GetFrame() const -{ - return m_pLogFrame; -} - -void wxLogWindow::OnFrameCreate(wxFrame * WXUNUSED(frame)) -{ -} - -bool wxLogWindow::OnFrameClose(wxFrame * WXUNUSED(frame)) -{ - // allow to close - return true; -} - -void wxLogWindow::OnFrameDelete(wxFrame * WXUNUSED(frame)) -{ - m_pLogFrame = (wxLogFrame *)NULL; -} - -wxLogWindow::~wxLogWindow() -{ - // may be NULL if log frame already auto destroyed itself - delete m_pLogFrame; -} - -#endif // wxUSE_LOGWINDOW - -// ---------------------------------------------------------------------------- -// wxLogDialog -// ---------------------------------------------------------------------------- - -#if wxUSE_LOG_DIALOG - -#ifndef __SMARTPHONE__ -static const size_t MARGIN = 10; -#else -static const size_t MARGIN = 0; -#endif - -wxString wxLogDialog::ms_details; - -wxLogDialog::wxLogDialog(wxWindow *parent, - const wxArrayString& messages, - const wxArrayInt& severity, - const wxArrayLong& times, - const wxString& caption, - long style) - : wxDialog(parent, wxID_ANY, caption, - wxDefaultPosition, wxDefaultSize, - wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER) -{ - if ( ms_details.empty() ) - { - // ensure that we won't loop here if wxGetTranslation() - // happens to pop up a Log message while translating this :-) - ms_details = wxTRANSLATE("&Details"); - ms_details = wxGetTranslation(ms_details); -#ifdef __SMARTPHONE__ - ms_details = wxStripMenuCodes(ms_details); -#endif - } - - size_t count = messages.GetCount(); - m_messages.Alloc(count); - m_severity.Alloc(count); - m_times.Alloc(count); - - for ( size_t n = 0; n < count; n++ ) - { - wxString msg = messages[n]; - msg.Replace(wxT("\n"), wxT(" ")); - m_messages.Add(msg); - m_severity.Add(severity[n]); - m_times.Add(times[n]); - } - - m_showingDetails = false; // not initially - m_listctrl = (wxListCtrl *)NULL; - -#ifndef __SMARTPHONE__ - -#if wxUSE_STATLINE - m_statline = (wxStaticLine *)NULL; -#endif // wxUSE_STATLINE - -#if wxUSE_FILE - m_btnSave = (wxButton *)NULL; -#endif // wxUSE_FILE - -#endif // __SMARTPHONE__ - - bool isPda = (wxSystemSettings::GetScreenType() <= wxSYS_SCREEN_PDA); - - // create the controls which are always shown and layout them: we use - // sizers even though our window is not resizeable to calculate the size of - // the dialog properly - wxBoxSizer *sizerTop = new wxBoxSizer(wxVERTICAL); -#ifndef __SMARTPHONE__ - wxBoxSizer *sizerButtons = new wxBoxSizer(isPda ? wxHORIZONTAL : wxVERTICAL); -#endif - wxBoxSizer *sizerAll = new wxBoxSizer(isPda ? wxVERTICAL : wxHORIZONTAL); - -#ifdef __SMARTPHONE__ - SetLeftMenu(wxID_OK); - SetRightMenu(wxID_MORE, ms_details + EXPAND_SUFFIX); -#else - wxButton *btnOk = new wxButton(this, wxID_OK); - sizerButtons->Add(btnOk, 0, isPda ? wxCENTRE : wxCENTRE|wxBOTTOM, MARGIN/2); - m_btnDetails = new wxButton(this, wxID_MORE, ms_details + EXPAND_SUFFIX); - sizerButtons->Add(m_btnDetails, 0, isPda ? wxCENTRE|wxLEFT : wxCENTRE | wxTOP, MARGIN/2 - 1); -#endif - - wxBitmap bitmap; - switch ( style & wxICON_MASK ) - { - case wxICON_ERROR: - bitmap = wxArtProvider::GetBitmap(wxART_ERROR, wxART_MESSAGE_BOX); -#ifdef __WXPM__ - bitmap.SetId(wxICON_SMALL_ERROR); -#endif - break; - - case wxICON_INFORMATION: - bitmap = wxArtProvider::GetBitmap(wxART_INFORMATION, wxART_MESSAGE_BOX); -#ifdef __WXPM__ - bitmap.SetId(wxICON_SMALL_INFO); -#endif - break; - - case wxICON_WARNING: - bitmap = wxArtProvider::GetBitmap(wxART_WARNING, wxART_MESSAGE_BOX); -#ifdef __WXPM__ - bitmap.SetId(wxICON_SMALL_WARNING); -#endif - break; - - default: - wxFAIL_MSG(_T("incorrect log style")); - } - - if (!isPda) - sizerAll->Add(new wxStaticBitmap(this, wxID_ANY, bitmap), 0, - wxALIGN_CENTRE_VERTICAL); - - const wxString& message = messages.Last(); - sizerAll->Add(CreateTextSizer(message), 1, - wxALIGN_CENTRE_VERTICAL | wxLEFT | wxRIGHT, MARGIN); -#ifndef __SMARTPHONE__ - sizerAll->Add(sizerButtons, 0, isPda ? wxCENTRE|wxTOP|wxBOTTOM : (wxALIGN_RIGHT | wxLEFT), MARGIN); -#endif - - sizerTop->Add(sizerAll, 0, wxALL | wxEXPAND, MARGIN); - - SetSizer(sizerTop); - - // see comments in OnDetails() - // - // Note: Doing this, this way, triggered a nasty bug in - // wxTopLevelWindowGTK::GtkOnSize which took -1 literally once - // either of maxWidth or maxHeight was set. This symptom has been - // fixed there, but it is a problem that remains as long as we allow - // unchecked access to the internal size members. We really need to - // encapuslate window sizes more cleanly and make it clear when -1 will - // be substituted and when it will not. - - wxSize size = sizerTop->Fit(this); - m_maxHeight = size.y; - SetSizeHints(size.x, size.y, m_maxWidth, m_maxHeight); - -#ifndef __SMARTPHONE__ - btnOk->SetFocus(); -#endif - - Centre(); - - if (isPda) - { - // Move up the screen so that when we expand the dialog, - // there's enough space. - Move(wxPoint(GetPosition().x, GetPosition().y / 2)); - } -} - -void wxLogDialog::CreateDetailsControls() -{ -#ifndef __SMARTPHONE__ - // create the save button and separator line if possible -#if wxUSE_FILE - m_btnSave = new wxButton(this, wxID_SAVE); -#endif // wxUSE_FILE - -#if wxUSE_STATLINE - m_statline = new wxStaticLine(this, wxID_ANY); -#endif // wxUSE_STATLINE - -#endif // __SMARTPHONE__ - - // create the list ctrl now - m_listctrl = new wxListCtrl(this, wxID_ANY, - wxDefaultPosition, wxDefaultSize, - wxSUNKEN_BORDER | - wxLC_REPORT | - wxLC_NO_HEADER | - wxLC_SINGLE_SEL); -#ifdef __WXWINCE__ - // This maks a big aesthetic difference on WinCE but I - // don't want to risk problems on other platforms - m_listctrl->Hide(); -#endif - - // no need to translate these strings as they're not shown to the - // user anyhow (we use wxLC_NO_HEADER style) - m_listctrl->InsertColumn(0, _T("Message")); - m_listctrl->InsertColumn(1, _T("Time")); - - // prepare the imagelist - static const int ICON_SIZE = 16; - wxImageList *imageList = new wxImageList(ICON_SIZE, ICON_SIZE); - - // order should be the same as in the switch below! - static const wxChar* icons[] = - { - wxART_ERROR, - wxART_WARNING, - wxART_INFORMATION - }; - - bool loadedIcons = true; - - for ( size_t icon = 0; icon < WXSIZEOF(icons); icon++ ) - { - wxBitmap bmp = wxArtProvider::GetBitmap(icons[icon], wxART_MESSAGE_BOX, - wxSize(ICON_SIZE, ICON_SIZE)); - - // This may very well fail if there are insufficient colours available. - // Degrade gracefully. - if ( !bmp.Ok() ) - { - loadedIcons = false; - - break; - } - - imageList->Add(bmp); - } - - m_listctrl->SetImageList(imageList, wxIMAGE_LIST_SMALL); - - // and fill it - wxString fmt = wxLog::GetTimestamp(); - if ( !fmt ) - { - // default format - fmt = _T("%c"); - } - - size_t count = m_messages.GetCount(); - for ( size_t n = 0; n < count; n++ ) - { - int image; - - if ( loadedIcons ) - { - switch ( m_severity[n] ) - { - case wxLOG_Error: - image = 0; - break; - - case wxLOG_Warning: - image = 1; - break; - - default: - image = 2; - } - } - else // failed to load images - { - image = -1; - } - - m_listctrl->InsertItem(n, m_messages[n], image); - m_listctrl->SetItem(n, 1, TimeStamp(fmt, (time_t)m_times[n])); - } - - // let the columns size themselves - m_listctrl->SetColumnWidth(0, wxLIST_AUTOSIZE); - m_listctrl->SetColumnWidth(1, wxLIST_AUTOSIZE); - - // calculate an approximately nice height for the listctrl - int height = GetCharHeight()*(count + 4); - - // but check that the dialog won't fall fown from the screen - // - // we use GetMinHeight() to get the height of the dialog part without the - // details and we consider that the "Save" button below and the separator - // line (and the margins around it) take about as much, hence double it - int heightMax = wxGetDisplaySize().y - GetPosition().y - 2*GetMinHeight(); - - // we should leave a margin - heightMax *= 9; - heightMax /= 10; - - m_listctrl->SetSize(wxDefaultCoord, wxMin(height, heightMax)); -} - -void wxLogDialog::OnListSelect(wxListEvent& event) -{ - // we can't just disable the control because this looks ugly under Windows - // (wrong bg colour, no scrolling...), but we still want to disable - // selecting items - it makes no sense here - m_listctrl->SetItemState(event.GetIndex(), 0, wxLIST_STATE_SELECTED); -} - -void wxLogDialog::OnOk(wxCommandEvent& WXUNUSED(event)) -{ - EndModal(wxID_OK); -} - -#if wxUSE_FILE - -void wxLogDialog::OnSave(wxCommandEvent& WXUNUSED(event)) -{ -#if wxUSE_FILEDLG - wxFile file; - int rc = OpenLogFile(file, NULL, this); - if ( rc == -1 ) - { - // cancelled - return; - } - - bool ok = rc != 0; - - wxString fmt = wxLog::GetTimestamp(); - if ( !fmt ) - { - // default format - fmt = _T("%c"); - } - - size_t count = m_messages.GetCount(); - for ( size_t n = 0; ok && (n < count); n++ ) - { - wxString line; - line << TimeStamp(fmt, (time_t)m_times[n]) - << _T(": ") - << m_messages[n] - << wxTextFile::GetEOL(); - - ok = file.Write(line); - } - - if ( ok ) - ok = file.Close(); - - if ( !ok ) - wxLogError(_("Can't save log contents to file.")); -#endif // wxUSE_FILEDLG -} - -#endif // wxUSE_FILE - -void wxLogDialog::OnDetails(wxCommandEvent& WXUNUSED(event)) -{ - wxSizer *sizer = GetSizer(); - - if ( m_showingDetails ) - { -#ifdef __SMARTPHONE__ - SetRightMenu(wxID_MORE, ms_details + EXPAND_SUFFIX); -#else - m_btnDetails->SetLabel(ms_details + EXPAND_SUFFIX); -#endif - - sizer->Detach( m_listctrl ); - -#ifndef __SMARTPHONE__ - -#if wxUSE_STATLINE - sizer->Detach( m_statline ); -#endif // wxUSE_STATLINE - -#if wxUSE_FILE - sizer->Detach( m_btnSave ); -#endif // wxUSE_FILE - -#endif // __SMARTPHONE__ - } - else // show details now - { -#ifdef __SMARTPHONE__ - SetRightMenu(wxID_MORE, wxString(_T("<< ")) + ms_details); -#else - m_btnDetails->SetLabel(wxString(_T("<< ")) + ms_details); -#endif - - if ( !m_listctrl ) - { - CreateDetailsControls(); - } - -#if wxUSE_STATLINE && !defined(__SMARTPHONE__) - bool isPda = (wxSystemSettings::GetScreenType() <= wxSYS_SCREEN_PDA); - if (!isPda) - sizer->Add(m_statline, 0, wxEXPAND | (wxALL & ~wxTOP), MARGIN); -#endif // wxUSE_STATLINE - - sizer->Add(m_listctrl, 1, wxEXPAND | (wxALL & ~wxTOP), MARGIN); - - // VZ: this doesn't work as this becomes the initial (and not only - // minimal) listctrl height as well - why? -#if 0 - // allow the user to make the dialog shorter than its initial height - - // without this it wouldn't work as the list ctrl would have been - // incompressible - sizer->SetItemMinSize(m_listctrl, 100, 3*GetCharHeight()); -#endif // 0 - -#if wxUSE_FILE && !defined(__SMARTPHONE__) - sizer->Add(m_btnSave, 0, wxALIGN_RIGHT | (wxALL & ~wxTOP), MARGIN); -#endif // wxUSE_FILE - } - - m_showingDetails = !m_showingDetails; - - // in any case, our size changed - relayout everything and set new hints - // --------------------------------------------------------------------- - - // we have to reset min size constraints or Fit() would never reduce the - // dialog size when collapsing it and we have to reset max constraint - // because it wouldn't expand it otherwise - - m_minHeight = - m_maxHeight = -1; - - // wxSizer::FitSize() is private, otherwise we might use it directly... - wxSize sizeTotal = GetSize(), - sizeClient = GetClientSize(); - - wxSize size = sizer->GetMinSize(); - size.x += sizeTotal.x - sizeClient.x; - size.y += sizeTotal.y - sizeClient.y; - - // we don't want to allow expanding the dialog in vertical direction as - // this would show the "hidden" details but we can resize the dialog - // vertically while the details are shown - if ( !m_showingDetails ) - m_maxHeight = size.y; - - SetSizeHints(size.x, size.y, m_maxWidth, m_maxHeight); - -#ifdef __WXWINCE__ - if (m_showingDetails) - m_listctrl->Show(); -#endif - - // don't change the width when expanding/collapsing - SetSize(wxDefaultCoord, size.y); - -#ifdef __WXGTK__ - // VS: this is necessary in order to force frame redraw under - // WindowMaker or fvwm2 (and probably other broken WMs). - // Otherwise, detailed list wouldn't be displayed. - Show(); -#endif // wxGTK -} - -wxLogDialog::~wxLogDialog() -{ - if ( m_listctrl ) - { - delete m_listctrl->GetImageList(wxIMAGE_LIST_SMALL); - } -} - -#endif // wxUSE_LOG_DIALOG - -#if wxUSE_FILE && wxUSE_FILEDLG - -// pass an uninitialized file object, the function will ask the user for the -// filename and try to open it, returns true on success (file was opened), -// false if file couldn't be opened/created and -1 if the file selection -// dialog was cancelled -static int OpenLogFile(wxFile& file, wxString *pFilename, wxWindow *parent) -{ - // get the file name - // ----------------- - wxString filename = wxSaveFileSelector(wxT("log"), wxT("txt"), wxT("log.txt"), parent); - if ( !filename ) { - // cancelled - return -1; - } - - // open file - // --------- - bool bOk wxDUMMY_INITIALIZE(false); - if ( wxFile::Exists(filename) ) { - bool bAppend = false; - wxString strMsg; - strMsg.Printf(_("Append log to file '%s' (choosing [No] will overwrite it)?"), - filename.c_str()); - switch ( wxMessageBox(strMsg, _("Question"), - wxICON_QUESTION | wxYES_NO | wxCANCEL) ) { - case wxYES: - bAppend = true; - break; - - case wxNO: - bAppend = false; - break; - - case wxCANCEL: - return -1; - - default: - wxFAIL_MSG(_("invalid message box return value")); - } - - if ( bAppend ) { - bOk = file.Open(filename, wxFile::write_append); - } - else { - bOk = file.Create(filename, true /* overwrite */); - } - } - else { - bOk = file.Create(filename); - } - - if ( pFilename ) - *pFilename = filename; - - return bOk; -} - -#endif // wxUSE_FILE - -#endif // !(wxUSE_LOGGUI || wxUSE_LOGWINDOW) - -#if wxUSE_LOG && wxUSE_TEXTCTRL - -// ---------------------------------------------------------------------------- -// wxLogTextCtrl implementation -// ---------------------------------------------------------------------------- - -wxLogTextCtrl::wxLogTextCtrl(wxTextCtrl *pTextCtrl) -{ - m_pTextCtrl = pTextCtrl; -} - -void wxLogTextCtrl::DoLogString(const wxChar *szString, time_t WXUNUSED(t)) -{ - wxString msg; - TimeStamp(&msg); - - msg << szString << wxT('\n'); - m_pTextCtrl->AppendText(msg); -} - -#endif // wxUSE_LOG && wxUSE_TEXTCTRL +///////////////////////////////////////////////////////////////////////////// +// Name: src/generic/logg.cpp +// Purpose: wxLog-derived classes which need GUI support (the rest is in +// src/common/log.cpp) +// Author: Vadim Zeitlin +// Modified by: +// Created: 20.09.99 (extracted from src/common/log.cpp) +// RCS-ID: $Id: logg.cpp 43078 2006-11-04 23:46:02Z VZ $ +// Copyright: (c) 1998 Vadim Zeitlin +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#ifndef WX_PRECOMP + #include "wx/app.h" + #include "wx/button.h" + #include "wx/intl.h" + #include "wx/log.h" + #include "wx/menu.h" + #include "wx/frame.h" + #include "wx/filedlg.h" + #include "wx/msgdlg.h" + #include "wx/textctrl.h" + #include "wx/sizer.h" + #include "wx/statbmp.h" + #include "wx/settings.h" +#endif // WX_PRECOMP + +#if wxUSE_LOGGUI || wxUSE_LOGWINDOW + +#include "wx/file.h" +#include "wx/textfile.h" +#include "wx/statline.h" +#include "wx/artprov.h" + +#ifdef __WXMSW__ + // for OutputDebugString() + #include "wx/msw/private.h" +#endif // Windows + +#ifdef __WXPM__ + #include +#endif + +#if wxUSE_LOG_DIALOG + #include "wx/listctrl.h" + #include "wx/imaglist.h" + #include "wx/image.h" +#endif // wxUSE_LOG_DIALOG/!wxUSE_LOG_DIALOG + +#if defined(__MWERKS__) && wxUSE_UNICODE + #include +#endif + +#include "wx/datetime.h" + +// the suffix we add to the button to show that the dialog can be expanded +#define EXPAND_SUFFIX _T(" >>") + +// ---------------------------------------------------------------------------- +// private classes +// ---------------------------------------------------------------------------- + +#if wxUSE_LOG_DIALOG + +// this function is a wrapper around strftime(3) +// allows to exclude the usage of wxDateTime +static wxString TimeStamp(const wxChar *format, time_t t) +{ +#if wxUSE_DATETIME + wxChar buf[4096]; + struct tm tm; + if ( !wxStrftime(buf, WXSIZEOF(buf), format, wxLocaltime_r(&t, &tm)) ) + { + // buffer is too small? + wxFAIL_MSG(_T("strftime() failed")); + } + return wxString(buf); +#else // !wxUSE_DATETIME + return wxEmptyString; +#endif // wxUSE_DATETIME/!wxUSE_DATETIME +} + + +class wxLogDialog : public wxDialog +{ +public: + wxLogDialog(wxWindow *parent, + const wxArrayString& messages, + const wxArrayInt& severity, + const wxArrayLong& timess, + const wxString& caption, + long style); + virtual ~wxLogDialog(); + + // event handlers + void OnOk(wxCommandEvent& event); + void OnDetails(wxCommandEvent& event); +#if wxUSE_FILE + void OnSave(wxCommandEvent& event); +#endif // wxUSE_FILE + void OnListSelect(wxListEvent& event); + +private: + // create controls needed for the details display + void CreateDetailsControls(); + + // the data for the listctrl + wxArrayString m_messages; + wxArrayInt m_severity; + wxArrayLong m_times; + + // the "toggle" button and its state +#ifndef __SMARTPHONE__ + wxButton *m_btnDetails; +#endif + bool m_showingDetails; + + // the controls which are not shown initially (but only when details + // button is pressed) + wxListCtrl *m_listctrl; +#ifndef __SMARTPHONE__ +#if wxUSE_STATLINE + wxStaticLine *m_statline; +#endif // wxUSE_STATLINE +#if wxUSE_FILE + wxButton *m_btnSave; +#endif // wxUSE_FILE +#endif // __SMARTPHONE__ + + // the translated "Details" string + static wxString ms_details; + + DECLARE_EVENT_TABLE() + DECLARE_NO_COPY_CLASS(wxLogDialog) +}; + +BEGIN_EVENT_TABLE(wxLogDialog, wxDialog) + EVT_BUTTON(wxID_OK, wxLogDialog::OnOk) + EVT_BUTTON(wxID_MORE, wxLogDialog::OnDetails) +#if wxUSE_FILE + EVT_BUTTON(wxID_SAVE, wxLogDialog::OnSave) +#endif // wxUSE_FILE + EVT_LIST_ITEM_SELECTED(wxID_ANY, wxLogDialog::OnListSelect) +END_EVENT_TABLE() + +#endif // wxUSE_LOG_DIALOG + +// ---------------------------------------------------------------------------- +// private functions +// ---------------------------------------------------------------------------- + +#if wxUSE_FILE && wxUSE_FILEDLG + +// pass an uninitialized file object, the function will ask the user for the +// filename and try to open it, returns true on success (file was opened), +// false if file couldn't be opened/created and -1 if the file selection +// dialog was cancelled +static int OpenLogFile(wxFile& file, wxString *filename = NULL, wxWindow *parent = NULL); + +#endif // wxUSE_FILE + +// ---------------------------------------------------------------------------- +// global variables +// ---------------------------------------------------------------------------- + +// we use a global variable to store the frame pointer for wxLogStatus - bad, +// but it's the easiest way +static wxFrame *gs_pFrame = NULL; // FIXME MT-unsafe + +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// global functions +// ---------------------------------------------------------------------------- + +// accepts an additional argument which tells to which frame the output should +// be directed +void wxVLogStatus(wxFrame *pFrame, const wxChar *szFormat, va_list argptr) +{ + wxString msg; + + wxLog *pLog = wxLog::GetActiveTarget(); + if ( pLog != NULL ) { + msg.PrintfV(szFormat, argptr); + + wxASSERT( gs_pFrame == NULL ); // should be reset! + gs_pFrame = pFrame; +#ifdef __WXWINCE__ + wxLog::OnLog(wxLOG_Status, msg, 0); +#else + wxLog::OnLog(wxLOG_Status, msg, time(NULL)); +#endif + gs_pFrame = (wxFrame *) NULL; + } +} + +void wxLogStatus(wxFrame *pFrame, const wxChar *szFormat, ...) +{ + va_list argptr; + va_start(argptr, szFormat); + wxVLogStatus(pFrame, szFormat, argptr); + va_end(argptr); +} + +// ---------------------------------------------------------------------------- +// wxLogGui implementation (FIXME MT-unsafe) +// ---------------------------------------------------------------------------- + +#if wxUSE_LOGGUI + +wxLogGui::wxLogGui() +{ + Clear(); +} + +void wxLogGui::Clear() +{ + m_bErrors = + m_bWarnings = + m_bHasMessages = false; + + m_aMessages.Empty(); + m_aSeverity.Empty(); + m_aTimes.Empty(); +} + +void wxLogGui::Flush() +{ + if ( !m_bHasMessages ) + return; + + // do it right now to block any new calls to Flush() while we're here + m_bHasMessages = false; + + unsigned repeatCount = 0; + if ( wxLog::GetRepetitionCounting() ) + { + repeatCount = wxLog::DoLogNumberOfRepeats(); + } + + wxString appName = wxTheApp->GetAppName(); + if ( !appName.empty() ) + appName[0u] = (wxChar)wxToupper(appName[0u]); + + long style; + wxString titleFormat; + if ( m_bErrors ) { + titleFormat = _("%s Error"); + style = wxICON_STOP; + } + else if ( m_bWarnings ) { + titleFormat = _("%s Warning"); + style = wxICON_EXCLAMATION; + } + else { + titleFormat = _("%s Information"); + style = wxICON_INFORMATION; + } + + wxString title; + title.Printf(titleFormat, appName.c_str()); + + size_t nMsgCount = m_aMessages.Count(); + + // avoid showing other log dialogs until we're done with the dialog we're + // showing right now: nested modal dialogs make for really bad UI! + Suspend(); + + wxString str; + if ( nMsgCount == 1 ) + { + str = m_aMessages[0]; + } + else // more than one message + { +#if wxUSE_LOG_DIALOG + + if ( repeatCount > 0 ) + m_aMessages[nMsgCount-1] += wxString::Format(wxT(" (%s)"), m_aMessages[nMsgCount-2].c_str()); + wxLogDialog dlg(NULL, + m_aMessages, m_aSeverity, m_aTimes, + title, style); + + // clear the message list before showing the dialog because while it's + // shown some new messages may appear + Clear(); + + (void)dlg.ShowModal(); +#else // !wxUSE_LOG_DIALOG + // concatenate all strings (but not too many to not overfill the msg box) + size_t nLines = 0; + + // start from the most recent message + for ( size_t n = nMsgCount; n > 0; n-- ) { + // for Windows strings longer than this value are wrapped (NT 4.0) + const size_t nMsgLineWidth = 156; + + nLines += (m_aMessages[n - 1].Len() + nMsgLineWidth - 1) / nMsgLineWidth; + + if ( nLines > 25 ) // don't put too many lines in message box + break; + + str << m_aMessages[n - 1] << wxT("\n"); + } +#endif // wxUSE_LOG_DIALOG/!wxUSE_LOG_DIALOG + } + + // this catches both cases of 1 message with wxUSE_LOG_DIALOG and any + // situation without it + if ( !str.empty() ) + { + wxMessageBox(str, title, wxOK | style); + + // no undisplayed messages whatsoever + Clear(); + } + + // allow flushing the logs again + Resume(); +} + +// log all kinds of messages +void wxLogGui::DoLog(wxLogLevel level, const wxChar *szString, time_t t) +{ + switch ( level ) { + case wxLOG_Info: + if ( GetVerbose() ) + case wxLOG_Message: + { + m_aMessages.Add(szString); + m_aSeverity.Add(wxLOG_Message); + m_aTimes.Add((long)t); + m_bHasMessages = true; + } + break; + + case wxLOG_Status: +#if wxUSE_STATUSBAR + { + // find the top window and set it's status text if it has any + wxFrame *pFrame = gs_pFrame; + if ( pFrame == NULL ) { + wxWindow *pWin = wxTheApp->GetTopWindow(); + if ( pWin != NULL && pWin->IsKindOf(CLASSINFO(wxFrame)) ) { + pFrame = (wxFrame *)pWin; + } + } + + if ( pFrame && pFrame->GetStatusBar() ) + pFrame->SetStatusText(szString); + } +#endif // wxUSE_STATUSBAR + break; + + case wxLOG_Trace: + case wxLOG_Debug: + #ifdef __WXDEBUG__ + { + wxString str; + TimeStamp(&str); + str += szString; + + #if defined(__WXMSW__) && !defined(__WXMICROWIN__) + // don't prepend debug/trace here: it goes to the + // debug window anyhow + str += wxT("\r\n"); + OutputDebugString(str); + #else + // send them to stderr + wxFprintf(stderr, wxT("[%s] %s\n"), + level == wxLOG_Trace ? wxT("Trace") + : wxT("Debug"), + str.c_str()); + fflush(stderr); + #endif + } + #endif // __WXDEBUG__ + + break; + + case wxLOG_FatalError: + // show this one immediately + wxMessageBox(szString, _("Fatal error"), wxICON_HAND); + wxExit(); + break; + + case wxLOG_Error: + if ( !m_bErrors ) { +#if !wxUSE_LOG_DIALOG + // discard earlier informational messages if this is the 1st + // error because they might not make sense any more and showing + // them in a message box might be confusing + m_aMessages.Empty(); + m_aSeverity.Empty(); + m_aTimes.Empty(); +#endif // wxUSE_LOG_DIALOG + m_bErrors = true; + } + // fall through + + case wxLOG_Warning: + if ( !m_bErrors ) { + // for the warning we don't discard the info messages + m_bWarnings = true; + } + + m_aMessages.Add(szString); + m_aSeverity.Add((int)level); + m_aTimes.Add((long)t); + m_bHasMessages = true; + break; + } +} + +#endif // wxUSE_LOGGUI + +// ---------------------------------------------------------------------------- +// wxLogWindow and wxLogFrame implementation +// ---------------------------------------------------------------------------- + +#if wxUSE_LOGWINDOW + +// log frame class +// --------------- +class wxLogFrame : public wxFrame +{ +public: + // ctor & dtor + wxLogFrame(wxWindow *pParent, wxLogWindow *log, const wxChar *szTitle); + virtual ~wxLogFrame(); + + // menu callbacks + void OnClose(wxCommandEvent& event); + void OnCloseWindow(wxCloseEvent& event); +#if wxUSE_FILE + void OnSave (wxCommandEvent& event); +#endif // wxUSE_FILE + void OnClear(wxCommandEvent& event); + + // accessors + wxTextCtrl *TextCtrl() const { return m_pTextCtrl; } + +private: + // use standard ids for our commands! + enum + { + Menu_Close = wxID_CLOSE, + Menu_Save = wxID_SAVE, + Menu_Clear = wxID_CLEAR + }; + + // common part of OnClose() and OnCloseWindow() + void DoClose(); + + wxTextCtrl *m_pTextCtrl; + wxLogWindow *m_log; + + DECLARE_EVENT_TABLE() + DECLARE_NO_COPY_CLASS(wxLogFrame) +}; + +BEGIN_EVENT_TABLE(wxLogFrame, wxFrame) + // wxLogWindow menu events + EVT_MENU(Menu_Close, wxLogFrame::OnClose) +#if wxUSE_FILE + EVT_MENU(Menu_Save, wxLogFrame::OnSave) +#endif // wxUSE_FILE + EVT_MENU(Menu_Clear, wxLogFrame::OnClear) + + EVT_CLOSE(wxLogFrame::OnCloseWindow) +END_EVENT_TABLE() + +wxLogFrame::wxLogFrame(wxWindow *pParent, wxLogWindow *log, const wxChar *szTitle) + : wxFrame(pParent, wxID_ANY, szTitle) +{ + m_log = log; + + m_pTextCtrl = new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, + wxDefaultSize, + wxTE_MULTILINE | + wxHSCROLL | + // needed for Win32 to avoid 65Kb limit but it doesn't work well + // when using RichEdit 2.0 which we always do in the Unicode build +#if !wxUSE_UNICODE + wxTE_RICH | +#endif // !wxUSE_UNICODE + wxTE_READONLY); + +#if wxUSE_MENUS + // create menu + wxMenuBar *pMenuBar = new wxMenuBar; + wxMenu *pMenu = new wxMenu; +#if wxUSE_FILE + pMenu->Append(Menu_Save, _("&Save..."), _("Save log contents to file")); +#endif // wxUSE_FILE + pMenu->Append(Menu_Clear, _("C&lear"), _("Clear the log contents")); + pMenu->AppendSeparator(); + pMenu->Append(Menu_Close, _("&Close"), _("Close this window")); + pMenuBar->Append(pMenu, _("&Log")); + SetMenuBar(pMenuBar); +#endif // wxUSE_MENUS + +#if wxUSE_STATUSBAR + // status bar for menu prompts + CreateStatusBar(); +#endif // wxUSE_STATUSBAR + + m_log->OnFrameCreate(this); +} + +void wxLogFrame::DoClose() +{ + if ( m_log->OnFrameClose(this) ) + { + // instead of closing just hide the window to be able to Show() it + // later + Show(false); + } +} + +void wxLogFrame::OnClose(wxCommandEvent& WXUNUSED(event)) +{ + DoClose(); +} + +void wxLogFrame::OnCloseWindow(wxCloseEvent& WXUNUSED(event)) +{ + DoClose(); +} + +#if wxUSE_FILE +void wxLogFrame::OnSave(wxCommandEvent& WXUNUSED(event)) +{ +#if wxUSE_FILEDLG + wxString filename; + wxFile file; + int rc = OpenLogFile(file, &filename, this); + if ( rc == -1 ) + { + // cancelled + return; + } + + bool bOk = rc != 0; + + // retrieve text and save it + // ------------------------- + int nLines = m_pTextCtrl->GetNumberOfLines(); + for ( int nLine = 0; bOk && nLine < nLines; nLine++ ) { + bOk = file.Write(m_pTextCtrl->GetLineText(nLine) + + wxTextFile::GetEOL()); + } + + if ( bOk ) + bOk = file.Close(); + + if ( !bOk ) { + wxLogError(_("Can't save log contents to file.")); + } + else { + wxLogStatus(this, _("Log saved to the file '%s'."), filename.c_str()); + } +#endif +} +#endif // wxUSE_FILE + +void wxLogFrame::OnClear(wxCommandEvent& WXUNUSED(event)) +{ + m_pTextCtrl->Clear(); +} + +wxLogFrame::~wxLogFrame() +{ + m_log->OnFrameDelete(this); +} + +// wxLogWindow +// ----------- + +wxLogWindow::wxLogWindow(wxWindow *pParent, + const wxChar *szTitle, + bool bShow, + bool bDoPass) +{ + PassMessages(bDoPass); + + m_pLogFrame = new wxLogFrame(pParent, this, szTitle); + + if ( bShow ) + m_pLogFrame->Show(); +} + +void wxLogWindow::Show(bool bShow) +{ + m_pLogFrame->Show(bShow); +} + +void wxLogWindow::DoLog(wxLogLevel level, const wxChar *szString, time_t t) +{ + // first let the previous logger show it + wxLogPassThrough::DoLog(level, szString, t); + + if ( m_pLogFrame ) { + switch ( level ) { + case wxLOG_Status: + // by default, these messages are ignored by wxLog, so process + // them ourselves + if ( !wxIsEmpty(szString) ) + { + wxString str; + str << _("Status: ") << szString; + DoLogString(str, t); + } + break; + + // don't put trace messages in the text window for 2 reasons: + // 1) there are too many of them + // 2) they may provoke other trace messages thus sending a program + // into an infinite loop + case wxLOG_Trace: + break; + + default: + // and this will format it nicely and call our DoLogString() + wxLog::DoLog(level, szString, t); + } + } +} + +void wxLogWindow::DoLogString(const wxChar *szString, time_t WXUNUSED(t)) +{ + // put the text into our window + wxTextCtrl *pText = m_pLogFrame->TextCtrl(); + + // remove selection (WriteText is in fact ReplaceSelection) +#ifdef __WXMSW__ + wxTextPos nLen = pText->GetLastPosition(); + pText->SetSelection(nLen, nLen); +#endif // Windows + + wxString msg; + TimeStamp(&msg); + msg << szString << wxT('\n'); + + pText->AppendText(msg); + + // TODO ensure that the line can be seen +} + +wxFrame *wxLogWindow::GetFrame() const +{ + return m_pLogFrame; +} + +void wxLogWindow::OnFrameCreate(wxFrame * WXUNUSED(frame)) +{ +} + +bool wxLogWindow::OnFrameClose(wxFrame * WXUNUSED(frame)) +{ + // allow to close + return true; +} + +void wxLogWindow::OnFrameDelete(wxFrame * WXUNUSED(frame)) +{ + m_pLogFrame = (wxLogFrame *)NULL; +} + +wxLogWindow::~wxLogWindow() +{ + // may be NULL if log frame already auto destroyed itself + delete m_pLogFrame; +} + +#endif // wxUSE_LOGWINDOW + +// ---------------------------------------------------------------------------- +// wxLogDialog +// ---------------------------------------------------------------------------- + +#if wxUSE_LOG_DIALOG + +#ifndef __SMARTPHONE__ +static const size_t MARGIN = 10; +#else +static const size_t MARGIN = 0; +#endif + +wxString wxLogDialog::ms_details; + +wxLogDialog::wxLogDialog(wxWindow *parent, + const wxArrayString& messages, + const wxArrayInt& severity, + const wxArrayLong& times, + const wxString& caption, + long style) + : wxDialog(parent, wxID_ANY, caption, + wxDefaultPosition, wxDefaultSize, + wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER) +{ + if ( ms_details.empty() ) + { + // ensure that we won't loop here if wxGetTranslation() + // happens to pop up a Log message while translating this :-) + ms_details = wxTRANSLATE("&Details"); + ms_details = wxGetTranslation(ms_details); +#ifdef __SMARTPHONE__ + ms_details = wxStripMenuCodes(ms_details); +#endif + } + + size_t count = messages.GetCount(); + m_messages.Alloc(count); + m_severity.Alloc(count); + m_times.Alloc(count); + + for ( size_t n = 0; n < count; n++ ) + { + wxString msg = messages[n]; + msg.Replace(wxT("\n"), wxT(" ")); + m_messages.Add(msg); + m_severity.Add(severity[n]); + m_times.Add(times[n]); + } + + m_showingDetails = false; // not initially + m_listctrl = (wxListCtrl *)NULL; + +#ifndef __SMARTPHONE__ + +#if wxUSE_STATLINE + m_statline = (wxStaticLine *)NULL; +#endif // wxUSE_STATLINE + +#if wxUSE_FILE + m_btnSave = (wxButton *)NULL; +#endif // wxUSE_FILE + +#endif // __SMARTPHONE__ + + bool isPda = (wxSystemSettings::GetScreenType() <= wxSYS_SCREEN_PDA); + + // create the controls which are always shown and layout them: we use + // sizers even though our window is not resizeable to calculate the size of + // the dialog properly + wxBoxSizer *sizerTop = new wxBoxSizer(wxVERTICAL); +#ifndef __SMARTPHONE__ + wxBoxSizer *sizerButtons = new wxBoxSizer(isPda ? wxHORIZONTAL : wxVERTICAL); +#endif + wxBoxSizer *sizerAll = new wxBoxSizer(isPda ? wxVERTICAL : wxHORIZONTAL); + +#ifdef __SMARTPHONE__ + SetLeftMenu(wxID_OK); + SetRightMenu(wxID_MORE, ms_details + EXPAND_SUFFIX); +#else + wxButton *btnOk = new wxButton(this, wxID_OK); + sizerButtons->Add(btnOk, 0, isPda ? wxCENTRE : wxCENTRE|wxBOTTOM, MARGIN/2); + m_btnDetails = new wxButton(this, wxID_MORE, ms_details + EXPAND_SUFFIX); + sizerButtons->Add(m_btnDetails, 0, isPda ? wxCENTRE|wxLEFT : wxCENTRE | wxTOP, MARGIN/2 - 1); +#endif + + wxBitmap bitmap; + switch ( style & wxICON_MASK ) + { + case wxICON_ERROR: + bitmap = wxArtProvider::GetBitmap(wxART_ERROR, wxART_MESSAGE_BOX); +#ifdef __WXPM__ + bitmap.SetId(wxICON_SMALL_ERROR); +#endif + break; + + case wxICON_INFORMATION: + bitmap = wxArtProvider::GetBitmap(wxART_INFORMATION, wxART_MESSAGE_BOX); +#ifdef __WXPM__ + bitmap.SetId(wxICON_SMALL_INFO); +#endif + break; + + case wxICON_WARNING: + bitmap = wxArtProvider::GetBitmap(wxART_WARNING, wxART_MESSAGE_BOX); +#ifdef __WXPM__ + bitmap.SetId(wxICON_SMALL_WARNING); +#endif + break; + + default: + wxFAIL_MSG(_T("incorrect log style")); + } + + if (!isPda) + sizerAll->Add(new wxStaticBitmap(this, wxID_ANY, bitmap), 0, + wxALIGN_CENTRE_VERTICAL); + + const wxString& message = messages.Last(); + sizerAll->Add(CreateTextSizer(message), 1, + wxALIGN_CENTRE_VERTICAL | wxLEFT | wxRIGHT, MARGIN); +#ifndef __SMARTPHONE__ + sizerAll->Add(sizerButtons, 0, isPda ? wxCENTRE|wxTOP|wxBOTTOM : (wxALIGN_RIGHT | wxLEFT), MARGIN); +#endif + + sizerTop->Add(sizerAll, 0, wxALL | wxEXPAND, MARGIN); + + SetSizer(sizerTop); + + // see comments in OnDetails() + // + // Note: Doing this, this way, triggered a nasty bug in + // wxTopLevelWindowGTK::GtkOnSize which took -1 literally once + // either of maxWidth or maxHeight was set. This symptom has been + // fixed there, but it is a problem that remains as long as we allow + // unchecked access to the internal size members. We really need to + // encapuslate window sizes more cleanly and make it clear when -1 will + // be substituted and when it will not. + + wxSize size = sizerTop->Fit(this); + m_maxHeight = size.y; + SetSizeHints(size.x, size.y, m_maxWidth, m_maxHeight); + +#ifndef __SMARTPHONE__ + btnOk->SetFocus(); +#endif + + Centre(); + + if (isPda) + { + // Move up the screen so that when we expand the dialog, + // there's enough space. + Move(wxPoint(GetPosition().x, GetPosition().y / 2)); + } +} + +void wxLogDialog::CreateDetailsControls() +{ +#ifndef __SMARTPHONE__ + // create the save button and separator line if possible +#if wxUSE_FILE + m_btnSave = new wxButton(this, wxID_SAVE); +#endif // wxUSE_FILE + +#if wxUSE_STATLINE + m_statline = new wxStaticLine(this, wxID_ANY); +#endif // wxUSE_STATLINE + +#endif // __SMARTPHONE__ + + // create the list ctrl now + m_listctrl = new wxListCtrl(this, wxID_ANY, + wxDefaultPosition, wxDefaultSize, + wxSUNKEN_BORDER | + wxLC_REPORT | + wxLC_NO_HEADER | + wxLC_SINGLE_SEL); +#ifdef __WXWINCE__ + // This maks a big aesthetic difference on WinCE but I + // don't want to risk problems on other platforms + m_listctrl->Hide(); +#endif + + // no need to translate these strings as they're not shown to the + // user anyhow (we use wxLC_NO_HEADER style) + m_listctrl->InsertColumn(0, _T("Message")); + m_listctrl->InsertColumn(1, _T("Time")); + + // prepare the imagelist + static const int ICON_SIZE = 16; + wxImageList *imageList = new wxImageList(ICON_SIZE, ICON_SIZE); + + // order should be the same as in the switch below! + static const wxChar* icons[] = + { + wxART_ERROR, + wxART_WARNING, + wxART_INFORMATION + }; + + bool loadedIcons = true; + + for ( size_t icon = 0; icon < WXSIZEOF(icons); icon++ ) + { + wxBitmap bmp = wxArtProvider::GetBitmap(icons[icon], wxART_MESSAGE_BOX, + wxSize(ICON_SIZE, ICON_SIZE)); + + // This may very well fail if there are insufficient colours available. + // Degrade gracefully. + if ( !bmp.Ok() ) + { + loadedIcons = false; + + break; + } + + imageList->Add(bmp); + } + + m_listctrl->SetImageList(imageList, wxIMAGE_LIST_SMALL); + + // and fill it + wxString fmt = wxLog::GetTimestamp(); + if ( !fmt ) + { + // default format + fmt = _T("%c"); + } + + size_t count = m_messages.GetCount(); + for ( size_t n = 0; n < count; n++ ) + { + int image; + + if ( loadedIcons ) + { + switch ( m_severity[n] ) + { + case wxLOG_Error: + image = 0; + break; + + case wxLOG_Warning: + image = 1; + break; + + default: + image = 2; + } + } + else // failed to load images + { + image = -1; + } + + m_listctrl->InsertItem(n, m_messages[n], image); + m_listctrl->SetItem(n, 1, TimeStamp(fmt, (time_t)m_times[n])); + } + + // let the columns size themselves + m_listctrl->SetColumnWidth(0, wxLIST_AUTOSIZE); + m_listctrl->SetColumnWidth(1, wxLIST_AUTOSIZE); + + // calculate an approximately nice height for the listctrl + int height = GetCharHeight()*(count + 4); + + // but check that the dialog won't fall fown from the screen + // + // we use GetMinHeight() to get the height of the dialog part without the + // details and we consider that the "Save" button below and the separator + // line (and the margins around it) take about as much, hence double it + int heightMax = wxGetDisplaySize().y - GetPosition().y - 2*GetMinHeight(); + + // we should leave a margin + heightMax *= 9; + heightMax /= 10; + + m_listctrl->SetSize(wxDefaultCoord, wxMin(height, heightMax)); +} + +void wxLogDialog::OnListSelect(wxListEvent& event) +{ + // we can't just disable the control because this looks ugly under Windows + // (wrong bg colour, no scrolling...), but we still want to disable + // selecting items - it makes no sense here + m_listctrl->SetItemState(event.GetIndex(), 0, wxLIST_STATE_SELECTED); +} + +void wxLogDialog::OnOk(wxCommandEvent& WXUNUSED(event)) +{ + EndModal(wxID_OK); +} + +#if wxUSE_FILE + +void wxLogDialog::OnSave(wxCommandEvent& WXUNUSED(event)) +{ +#if wxUSE_FILEDLG + wxFile file; + int rc = OpenLogFile(file, NULL, this); + if ( rc == -1 ) + { + // cancelled + return; + } + + bool ok = rc != 0; + + wxString fmt = wxLog::GetTimestamp(); + if ( !fmt ) + { + // default format + fmt = _T("%c"); + } + + size_t count = m_messages.GetCount(); + for ( size_t n = 0; ok && (n < count); n++ ) + { + wxString line; + line << TimeStamp(fmt, (time_t)m_times[n]) + << _T(": ") + << m_messages[n] + << wxTextFile::GetEOL(); + + ok = file.Write(line); + } + + if ( ok ) + ok = file.Close(); + + if ( !ok ) + wxLogError(_("Can't save log contents to file.")); +#endif // wxUSE_FILEDLG +} + +#endif // wxUSE_FILE + +void wxLogDialog::OnDetails(wxCommandEvent& WXUNUSED(event)) +{ + wxSizer *sizer = GetSizer(); + + if ( m_showingDetails ) + { +#ifdef __SMARTPHONE__ + SetRightMenu(wxID_MORE, ms_details + EXPAND_SUFFIX); +#else + m_btnDetails->SetLabel(ms_details + EXPAND_SUFFIX); +#endif + + sizer->Detach( m_listctrl ); + +#ifndef __SMARTPHONE__ + +#if wxUSE_STATLINE + sizer->Detach( m_statline ); +#endif // wxUSE_STATLINE + +#if wxUSE_FILE + sizer->Detach( m_btnSave ); +#endif // wxUSE_FILE + +#endif // __SMARTPHONE__ + } + else // show details now + { +#ifdef __SMARTPHONE__ + SetRightMenu(wxID_MORE, wxString(_T("<< ")) + ms_details); +#else + m_btnDetails->SetLabel(wxString(_T("<< ")) + ms_details); +#endif + + if ( !m_listctrl ) + { + CreateDetailsControls(); + } + +#if wxUSE_STATLINE && !defined(__SMARTPHONE__) + bool isPda = (wxSystemSettings::GetScreenType() <= wxSYS_SCREEN_PDA); + if (!isPda) + sizer->Add(m_statline, 0, wxEXPAND | (wxALL & ~wxTOP), MARGIN); +#endif // wxUSE_STATLINE + + sizer->Add(m_listctrl, 1, wxEXPAND | (wxALL & ~wxTOP), MARGIN); + + // VZ: this doesn't work as this becomes the initial (and not only + // minimal) listctrl height as well - why? +#if 0 + // allow the user to make the dialog shorter than its initial height - + // without this it wouldn't work as the list ctrl would have been + // incompressible + sizer->SetItemMinSize(m_listctrl, 100, 3*GetCharHeight()); +#endif // 0 + +#if wxUSE_FILE && !defined(__SMARTPHONE__) + sizer->Add(m_btnSave, 0, wxALIGN_RIGHT | (wxALL & ~wxTOP), MARGIN); +#endif // wxUSE_FILE + } + + m_showingDetails = !m_showingDetails; + + // in any case, our size changed - relayout everything and set new hints + // --------------------------------------------------------------------- + + // we have to reset min size constraints or Fit() would never reduce the + // dialog size when collapsing it and we have to reset max constraint + // because it wouldn't expand it otherwise + + m_minHeight = + m_maxHeight = -1; + + // wxSizer::FitSize() is private, otherwise we might use it directly... + wxSize sizeTotal = GetSize(), + sizeClient = GetClientSize(); + + wxSize size = sizer->GetMinSize(); + size.x += sizeTotal.x - sizeClient.x; + size.y += sizeTotal.y - sizeClient.y; + + // we don't want to allow expanding the dialog in vertical direction as + // this would show the "hidden" details but we can resize the dialog + // vertically while the details are shown + if ( !m_showingDetails ) + m_maxHeight = size.y; + + SetSizeHints(size.x, size.y, m_maxWidth, m_maxHeight); + +#ifdef __WXWINCE__ + if (m_showingDetails) + m_listctrl->Show(); +#endif + + // don't change the width when expanding/collapsing + SetSize(wxDefaultCoord, size.y); + +#ifdef __WXGTK__ + // VS: this is necessary in order to force frame redraw under + // WindowMaker or fvwm2 (and probably other broken WMs). + // Otherwise, detailed list wouldn't be displayed. + Show(); +#endif // wxGTK +} + +wxLogDialog::~wxLogDialog() +{ + if ( m_listctrl ) + { + delete m_listctrl->GetImageList(wxIMAGE_LIST_SMALL); + } +} + +#endif // wxUSE_LOG_DIALOG + +#if wxUSE_FILE && wxUSE_FILEDLG + +// pass an uninitialized file object, the function will ask the user for the +// filename and try to open it, returns true on success (file was opened), +// false if file couldn't be opened/created and -1 if the file selection +// dialog was cancelled +static int OpenLogFile(wxFile& file, wxString *pFilename, wxWindow *parent) +{ + // get the file name + // ----------------- + wxString filename = wxSaveFileSelector(wxT("log"), wxT("txt"), wxT("log.txt"), parent); + if ( !filename ) { + // cancelled + return -1; + } + + // open file + // --------- + bool bOk wxDUMMY_INITIALIZE(false); + if ( wxFile::Exists(filename) ) { + bool bAppend = false; + wxString strMsg; + strMsg.Printf(_("Append log to file '%s' (choosing [No] will overwrite it)?"), + filename.c_str()); + switch ( wxMessageBox(strMsg, _("Question"), + wxICON_QUESTION | wxYES_NO | wxCANCEL) ) { + case wxYES: + bAppend = true; + break; + + case wxNO: + bAppend = false; + break; + + case wxCANCEL: + return -1; + + default: + wxFAIL_MSG(_("invalid message box return value")); + } + + if ( bAppend ) { + bOk = file.Open(filename, wxFile::write_append); + } + else { + bOk = file.Create(filename, true /* overwrite */); + } + } + else { + bOk = file.Create(filename); + } + + if ( pFilename ) + *pFilename = filename; + + return bOk; +} + +#endif // wxUSE_FILE + +#endif // !(wxUSE_LOGGUI || wxUSE_LOGWINDOW) + +#if wxUSE_LOG && wxUSE_TEXTCTRL + +// ---------------------------------------------------------------------------- +// wxLogTextCtrl implementation +// ---------------------------------------------------------------------------- + +wxLogTextCtrl::wxLogTextCtrl(wxTextCtrl *pTextCtrl) +{ + m_pTextCtrl = pTextCtrl; +} + +void wxLogTextCtrl::DoLogString(const wxChar *szString, time_t WXUNUSED(t)) +{ + wxString msg; + TimeStamp(&msg); + + msg << szString << wxT('\n'); + m_pTextCtrl->AppendText(msg); +} + +#endif // wxUSE_LOG && wxUSE_TEXTCTRL diff --git a/Externals/wxWidgets/src/generic/mask.cpp b/Externals/wxWidgets/src/generic/mask.cpp index 19e7124bed..69d6cfaf74 100644 --- a/Externals/wxWidgets/src/generic/mask.cpp +++ b/Externals/wxWidgets/src/generic/mask.cpp @@ -1,76 +1,76 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: src/generic/mask.cpp -// Purpose: generic wxMask implementation -// Author: Vadim Zeitlin -// Created: 2006-09-28 -// RCS-ID: $Id: mask.cpp 41495 2006-09-28 23:02:39Z VZ $ -// Copyright: (c) 2006 Vadim Zeitlin -// Licence: wxWindows licence -/////////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// for compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#ifndef WX_PRECOMP - #include "wx/bitmap.h" - #include "wx/image.h" -#endif // WX_PRECOMP - -#if wxUSE_GENERIC_MASK - -// ============================================================================ -// wxMask implementation -// ============================================================================ - -IMPLEMENT_DYNAMIC_CLASS(wxMask, wxObject) - -void wxMask::FreeData() -{ - m_bitmap = wxNullBitmap; -} - -bool wxMask::InitFromColour(const wxBitmap& bitmap, const wxColour& colour) -{ -#if wxUSE_IMAGE - const wxColour clr(bitmap.QuantizeColour(colour)); - - wxImage imgSrc(bitmap.ConvertToImage()); - imgSrc.SetMask(false); - wxImage image(imgSrc.ConvertToMono(clr.Red(), clr.Green(), clr.Blue())); - if ( !image.Ok() ) - return false; - - m_bitmap = wxBitmap(image, 1); - - return m_bitmap.Ok(); -#else // !wxUSE_IMAGE - wxUnusedVar(bitmap); - wxUnusedVar(colour); - - return false; -#endif // wxUSE_IMAGE/!wxUSE_IMAGE -} - -bool wxMask::InitFromMonoBitmap(const wxBitmap& bitmap) -{ - wxCHECK_MSG( bitmap.Ok(), false, wxT("Invalid bitmap") ); - wxCHECK_MSG( bitmap.GetDepth() == 1, false, wxT("Cannot create mask from colour bitmap") ); - - m_bitmap = bitmap; - - return true; -} - -#endif // wxUSE_GENERIC_MASK +/////////////////////////////////////////////////////////////////////////////// +// Name: src/generic/mask.cpp +// Purpose: generic wxMask implementation +// Author: Vadim Zeitlin +// Created: 2006-09-28 +// RCS-ID: $Id: mask.cpp 41495 2006-09-28 23:02:39Z VZ $ +// Copyright: (c) 2006 Vadim Zeitlin +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// for compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#ifndef WX_PRECOMP + #include "wx/bitmap.h" + #include "wx/image.h" +#endif // WX_PRECOMP + +#if wxUSE_GENERIC_MASK + +// ============================================================================ +// wxMask implementation +// ============================================================================ + +IMPLEMENT_DYNAMIC_CLASS(wxMask, wxObject) + +void wxMask::FreeData() +{ + m_bitmap = wxNullBitmap; +} + +bool wxMask::InitFromColour(const wxBitmap& bitmap, const wxColour& colour) +{ +#if wxUSE_IMAGE + const wxColour clr(bitmap.QuantizeColour(colour)); + + wxImage imgSrc(bitmap.ConvertToImage()); + imgSrc.SetMask(false); + wxImage image(imgSrc.ConvertToMono(clr.Red(), clr.Green(), clr.Blue())); + if ( !image.Ok() ) + return false; + + m_bitmap = wxBitmap(image, 1); + + return m_bitmap.Ok(); +#else // !wxUSE_IMAGE + wxUnusedVar(bitmap); + wxUnusedVar(colour); + + return false; +#endif // wxUSE_IMAGE/!wxUSE_IMAGE +} + +bool wxMask::InitFromMonoBitmap(const wxBitmap& bitmap) +{ + wxCHECK_MSG( bitmap.Ok(), false, wxT("Invalid bitmap") ); + wxCHECK_MSG( bitmap.GetDepth() == 1, false, wxT("Cannot create mask from colour bitmap") ); + + m_bitmap = bitmap; + + return true; +} + +#endif // wxUSE_GENERIC_MASK diff --git a/Externals/wxWidgets/src/generic/mdig.cpp b/Externals/wxWidgets/src/generic/mdig.cpp index 675df58be6..e0b1b7dfbd 100644 --- a/Externals/wxWidgets/src/generic/mdig.cpp +++ b/Externals/wxWidgets/src/generic/mdig.cpp @@ -1,820 +1,820 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/generic/mdig.cpp -// Purpose: Generic MDI (Multiple Document Interface) classes -// Author: Hans Van Leemputten -// Modified by: -// Created: 29/07/2002 -// RCS-ID: $Id: mdig.cpp 41069 2006-09-08 14:38:49Z VS $ -// Copyright: (c) Hans Van Leemputten -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// =========================================================================== -// declarations -// =========================================================================== - -// --------------------------------------------------------------------------- -// headers -// --------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_MDI - -#include "wx/generic/mdig.h" - -#ifndef WX_PRECOMP - #include "wx/panel.h" - #include "wx/menu.h" - #include "wx/intl.h" - #include "wx/log.h" -#endif //WX_PRECOMP - -#include "wx/stockitem.h" - -enum MDI_MENU_ID -{ - wxWINDOWCLOSE = 4001, - wxWINDOWCLOSEALL, - wxWINDOWNEXT, - wxWINDOWPREV -}; - -//----------------------------------------------------------------------------- -// wxGenericMDIParentFrame -//----------------------------------------------------------------------------- - -IMPLEMENT_DYNAMIC_CLASS(wxGenericMDIParentFrame, wxFrame) - -BEGIN_EVENT_TABLE(wxGenericMDIParentFrame, wxFrame) -#if wxUSE_MENUS - EVT_MENU (wxID_ANY, wxGenericMDIParentFrame::DoHandleMenu) -#endif -END_EVENT_TABLE() - -wxGenericMDIParentFrame::wxGenericMDIParentFrame() -{ - Init(); -} - -wxGenericMDIParentFrame::wxGenericMDIParentFrame(wxWindow *parent, - wxWindowID id, - const wxString& title, - const wxPoint& pos, - const wxSize& size, - long style, - const wxString& name) -{ - Init(); - - (void)Create(parent, id, title, pos, size, style, name); -} - -wxGenericMDIParentFrame::~wxGenericMDIParentFrame() -{ - // Make sure the client window is destructed before the menu bars are! - wxDELETE(m_pClientWindow); - -#if wxUSE_MENUS - if (m_pMyMenuBar) - { - delete m_pMyMenuBar; - m_pMyMenuBar = (wxMenuBar *) NULL; - } - - RemoveWindowMenu(GetMenuBar()); - - if (m_pWindowMenu) - { - delete m_pWindowMenu; - m_pWindowMenu = (wxMenu*) NULL; - } -#endif // wxUSE_MENUS -} - -bool wxGenericMDIParentFrame::Create(wxWindow *parent, - wxWindowID id, - const wxString& title, - const wxPoint& pos, - const wxSize& size, - long style, - const wxString& name) -{ - // this style can be used to prevent a window from having the standard MDI - // "Window" menu - if ( !(style & wxFRAME_NO_WINDOW_MENU) ) - { -#if wxUSE_MENUS - m_pWindowMenu = new wxMenu; - - m_pWindowMenu->Append(wxWINDOWCLOSE, _("Cl&ose")); - m_pWindowMenu->Append(wxWINDOWCLOSEALL, _("Close All")); - m_pWindowMenu->AppendSeparator(); - m_pWindowMenu->Append(wxWINDOWNEXT, _("&Next")); - m_pWindowMenu->Append(wxWINDOWPREV, _("&Previous")); -#endif // wxUSE_MENUS - } - - wxFrame::Create( parent, id, title, pos, size, style, name ); - - OnCreateClient(); - - return true; -} - -#if wxUSE_MENUS -void wxGenericMDIParentFrame::SetWindowMenu(wxMenu* pMenu) -{ - // Replace the window menu from the currently loaded menu bar. - wxMenuBar *pMenuBar = GetMenuBar(); - - if (m_pWindowMenu) - { - RemoveWindowMenu(pMenuBar); - - wxDELETE(m_pWindowMenu); - } - - if (pMenu) - { - m_pWindowMenu = pMenu; - - AddWindowMenu(pMenuBar); - } -} - -void wxGenericMDIParentFrame::SetMenuBar(wxMenuBar *pMenuBar) -{ - // Remove the Window menu from the old menu bar - RemoveWindowMenu(GetMenuBar()); - // Add the Window menu to the new menu bar. - AddWindowMenu(pMenuBar); - - wxFrame::SetMenuBar(pMenuBar); -} -#endif // wxUSE_MENUS - -void wxGenericMDIParentFrame::SetChildMenuBar(wxGenericMDIChildFrame *pChild) -{ -#if wxUSE_MENUS - if (pChild == (wxGenericMDIChildFrame *) NULL) - { - // No Child, set Our menu bar back. - SetMenuBar(m_pMyMenuBar); - - // Make sure we know our menu bar is in use - m_pMyMenuBar = (wxMenuBar*) NULL; - } - else - { - if (pChild->GetMenuBar() == (wxMenuBar*) NULL) - return; - - // Do we need to save the current bar? - if (m_pMyMenuBar == NULL) - m_pMyMenuBar = GetMenuBar(); - - SetMenuBar(pChild->GetMenuBar()); - } -#endif // wxUSE_MENUS -} - -bool wxGenericMDIParentFrame::ProcessEvent(wxEvent& event) -{ - /* - * Redirect events to active child first. - */ - - // Stops the same event being processed repeatedly - static wxEventType inEvent = wxEVT_NULL; - if (inEvent == event.GetEventType()) - return false; - - inEvent = event.GetEventType(); - - // Let the active child (if any) process the event first. - bool res = false; - if (m_pActiveChild && event.IsKindOf(CLASSINFO(wxCommandEvent)) -#if 0 - /* This is sure to not give problems... */ - && (event.GetEventType() == wxEVT_COMMAND_MENU_SELECTED || - event.GetEventType() == wxEVT_UPDATE_UI ) -#else - /* This was tested on wxMSW and worked... */ - && event.GetEventObject() != m_pClientWindow - && !(event.GetEventType() == wxEVT_ACTIVATE || - event.GetEventType() == wxEVT_SET_FOCUS || - event.GetEventType() == wxEVT_KILL_FOCUS || - event.GetEventType() == wxEVT_CHILD_FOCUS || - event.GetEventType() == wxEVT_COMMAND_SET_FOCUS || - event.GetEventType() == wxEVT_COMMAND_KILL_FOCUS ) -#endif - ) - { - res = m_pActiveChild->GetEventHandler()->ProcessEvent(event); - } - - // If the event was not handled this frame will handle it! - if (!res) - { - res = GetEventHandler()->wxEvtHandler::ProcessEvent(event); - } - - inEvent = wxEVT_NULL; - - return res; -} - -wxGenericMDIChildFrame *wxGenericMDIParentFrame::GetActiveChild() const -{ - return m_pActiveChild; -} - -void wxGenericMDIParentFrame::SetActiveChild(wxGenericMDIChildFrame* pChildFrame) -{ - m_pActiveChild = pChildFrame; -} - -wxGenericMDIClientWindow *wxGenericMDIParentFrame::GetClientWindow() const -{ - return m_pClientWindow; -} - -wxGenericMDIClientWindow *wxGenericMDIParentFrame::OnCreateClient() -{ -#if wxUSE_GENERIC_MDI_AS_NATIVE - m_pClientWindow = new wxMDIClientWindow( this ); -#else - m_pClientWindow = new wxGenericMDIClientWindow( this ); -#endif - return m_pClientWindow; -} - -void wxGenericMDIParentFrame::ActivateNext() -{ - if (m_pClientWindow && m_pClientWindow->GetSelection() != -1) - { - size_t active = m_pClientWindow->GetSelection() + 1; - if (active >= m_pClientWindow->GetPageCount()) - active = 0; - - m_pClientWindow->SetSelection(active); - } -} - -void wxGenericMDIParentFrame::ActivatePrevious() -{ - if (m_pClientWindow && m_pClientWindow->GetSelection() != -1) - { - int active = m_pClientWindow->GetSelection() - 1; - if (active < 0) - active = m_pClientWindow->GetPageCount() - 1; - - m_pClientWindow->SetSelection(active); - } -} - -void wxGenericMDIParentFrame::Init() -{ - m_pClientWindow = (wxGenericMDIClientWindow *) NULL; - m_pActiveChild = (wxGenericMDIChildFrame *) NULL; -#if wxUSE_MENUS - m_pWindowMenu = (wxMenu *) NULL; - m_pMyMenuBar = (wxMenuBar*) NULL; -#endif // wxUSE_MENUS -} - -#if wxUSE_MENUS -void wxGenericMDIParentFrame::RemoveWindowMenu(wxMenuBar *pMenuBar) -{ - if (pMenuBar && m_pWindowMenu) - { - // Remove old window menu - int pos = pMenuBar->FindMenu(_("&Window")); - if (pos != wxNOT_FOUND) - { - wxASSERT(m_pWindowMenu == pMenuBar->GetMenu(pos)); // DBG:: We're going to delete the wrong menu!!! - pMenuBar->Remove(pos); - } - } -} - -void wxGenericMDIParentFrame::AddWindowMenu(wxMenuBar *pMenuBar) -{ - if (pMenuBar && m_pWindowMenu) - { - int pos = pMenuBar->FindMenu(wxGetStockLabel(wxID_HELP,false)); - if (pos == wxNOT_FOUND) - { - pMenuBar->Append(m_pWindowMenu, _("&Window")); - } - else - { - pMenuBar->Insert(pos, m_pWindowMenu, _("&Window")); - } - } -} - -void wxGenericMDIParentFrame::DoHandleMenu(wxCommandEvent &event) -{ - switch (event.GetId()) - { - case wxWINDOWCLOSE: - if (m_pActiveChild) - { - m_pActiveChild->Close(); - } - break; - case wxWINDOWCLOSEALL: - { -#if 0 // code is only needed if next #if is set to 0! - wxGenericMDIChildFrame *pFirstActiveChild = m_pActiveChild; -#endif - while (m_pActiveChild) - { - if (!m_pActiveChild->Close()) - { - return; // We failed... - } - else - { -#if 1 // What's best? Delayed deleting or immediate deleting? - delete m_pActiveChild; - m_pActiveChild = NULL; -#else - ActivateNext(); - - if (pFirstActiveChild == m_pActiveChild) - return; // We've called Close on all items, no need to continue. -#endif - } - } - } - break; - case wxWINDOWNEXT: - ActivateNext(); - break; - case wxWINDOWPREV: - ActivatePrevious(); - break; - default : - event.Skip(); - } -} -#endif // wxUSE_MENUS - -void wxGenericMDIParentFrame::DoGetClientSize(int *width, int *height) const -{ - wxFrame::DoGetClientSize( width, height ); -} - - -//----------------------------------------------------------------------------- -// wxGenericMDIChildFrame -//----------------------------------------------------------------------------- - -IMPLEMENT_DYNAMIC_CLASS(wxGenericMDIChildFrame, wxPanel) - -BEGIN_EVENT_TABLE(wxGenericMDIChildFrame, wxPanel) - EVT_MENU_HIGHLIGHT_ALL(wxGenericMDIChildFrame::OnMenuHighlight) - EVT_ACTIVATE(wxGenericMDIChildFrame::OnActivate) - - EVT_CLOSE(wxGenericMDIChildFrame::OnCloseWindow) - EVT_SIZE(wxGenericMDIChildFrame::OnSize) -END_EVENT_TABLE() - -wxGenericMDIChildFrame::wxGenericMDIChildFrame() -{ - Init(); -} - -wxGenericMDIChildFrame::wxGenericMDIChildFrame( wxGenericMDIParentFrame *parent, - wxWindowID id, const wxString& title, - const wxPoint& WXUNUSED(pos), const wxSize& size, - long style, const wxString& name ) -{ - Init(); - - Create( parent, id, title, wxDefaultPosition, size, style, name ); -} - -wxGenericMDIChildFrame::~wxGenericMDIChildFrame() -{ - wxGenericMDIParentFrame *pParentFrame = GetMDIParentFrame(); - - if (pParentFrame != NULL) - { - bool bActive = false; - if (pParentFrame->GetActiveChild() == this) - { - pParentFrame->SetActiveChild((wxGenericMDIChildFrame*) NULL); - pParentFrame->SetChildMenuBar((wxGenericMDIChildFrame*) NULL); - bActive = true; - } - - wxGenericMDIClientWindow *pClientWindow = pParentFrame->GetClientWindow(); - - // Remove page if still there - size_t pos; - for (pos = 0; pos < pClientWindow->GetPageCount(); pos++) - { - if (pClientWindow->GetPage(pos) == this) - { - if (pClientWindow->RemovePage(pos)) - pClientWindow->Refresh(); - break; - } - } - - if (bActive) - { - // Set the new selection to the a remaining page - if (pClientWindow->GetPageCount() > pos) - { - pClientWindow->SetSelection(pos); - } - else - { - if ((int)pClientWindow->GetPageCount() - 1 >= 0) - pClientWindow->SetSelection(pClientWindow->GetPageCount() - 1); - } - } - } - -#if wxUSE_MENUS - wxDELETE(m_pMenuBar); -#endif // wxUSE_MENUS -} - -bool wxGenericMDIChildFrame::Create( wxGenericMDIParentFrame *parent, - wxWindowID id, const wxString& title, - const wxPoint& WXUNUSED(pos), const wxSize& size, - long style, const wxString& name ) -{ - wxGenericMDIClientWindow* pClientWindow = parent->GetClientWindow(); - - wxASSERT_MSG((pClientWindow != (wxWindow*) NULL), wxT("Missing MDI client window.") ); - - wxPanel::Create(pClientWindow, id, wxDefaultPosition, size, style, name); - - SetMDIParentFrame(parent); - - // This is the currently active child - parent->SetActiveChild(this); - - m_Title = title; - - pClientWindow->AddPage(this, title, true); - ApplyMDIChildFrameRect(); // Ok confirme the size change! - pClientWindow->Refresh(); - - return true; -} - -#if wxUSE_MENUS -void wxGenericMDIChildFrame::SetMenuBar( wxMenuBar *menu_bar ) -{ - wxMenuBar *pOldMenuBar = m_pMenuBar; - m_pMenuBar = menu_bar; - - if (m_pMenuBar) - { - wxGenericMDIParentFrame *pParentFrame = GetMDIParentFrame(); - - if (pParentFrame != NULL) - { - m_pMenuBar->SetParent(pParentFrame); - - if (pParentFrame->GetActiveChild() == this) - { - // Replace current menu bars - if (pOldMenuBar) - pParentFrame->SetChildMenuBar((wxGenericMDIChildFrame*) NULL); - pParentFrame->SetChildMenuBar((wxGenericMDIChildFrame*) this); - } - } - } -} - -wxMenuBar *wxGenericMDIChildFrame::GetMenuBar() const -{ - return m_pMenuBar; -} -#endif // wxUSE_MENUS - -void wxGenericMDIChildFrame::SetTitle(const wxString& title) -{ - m_Title = title; - - wxGenericMDIParentFrame *pParentFrame = GetMDIParentFrame(); - - if (pParentFrame != NULL) - { - wxGenericMDIClientWindow * pClientWindow = pParentFrame->GetClientWindow(); - - if (pClientWindow != NULL) - { - size_t pos; - for (pos = 0; pos < pClientWindow->GetPageCount(); pos++) - { - if (pClientWindow->GetPage(pos) == this) - { - pClientWindow->SetPageText(pos, m_Title); - break; - } - } - } - } -} - -wxString wxGenericMDIChildFrame::GetTitle() const -{ - return m_Title; -} - -void wxGenericMDIChildFrame::Activate() -{ - wxGenericMDIParentFrame *pParentFrame = GetMDIParentFrame(); - - if (pParentFrame != NULL) - { - wxGenericMDIClientWindow * pClientWindow = pParentFrame->GetClientWindow(); - - if (pClientWindow != NULL) - { - size_t pos; - for (pos = 0; pos < pClientWindow->GetPageCount(); pos++) - { - if (pClientWindow->GetPage(pos) == this) - { - pClientWindow->SetSelection(pos); - break; - } - } - } - } -} - -void wxGenericMDIChildFrame::OnMenuHighlight(wxMenuEvent& event) -{ -#if wxUSE_STATUSBAR - if ( m_pMDIParentFrame) - { - // we don't have any help text for this item, - // but may be the MDI frame does? - m_pMDIParentFrame->OnMenuHighlight(event); - } -#else - wxUnusedVar(event); -#endif // wxUSE_STATUSBAR -} - -void wxGenericMDIChildFrame::OnActivate(wxActivateEvent& WXUNUSED(event)) -{ - // Do mothing. -} - -/*** Copied from top level..! ***/ -// default resizing behaviour - if only ONE subwindow, resize to fill the -// whole client area -void wxGenericMDIChildFrame::OnSize(wxSizeEvent& WXUNUSED(event)) -{ - // if we're using constraints or sizers - do use them - if ( GetAutoLayout() ) - { - Layout(); - } - else - { - // do we have _exactly_ one child? - wxWindow *child = (wxWindow *)NULL; - for ( wxWindowList::compatibility_iterator node = GetChildren().GetFirst(); - node; - node = node->GetNext() ) - { - wxWindow *win = node->GetData(); - - // exclude top level and managed windows (status bar isn't - // currently in the children list except under wxMac anyhow, but - // it makes no harm to test for it) - if ( !win->IsTopLevel() /*&& !IsOneOfBars(win)*/ ) - { - if ( child ) - { - return; // it's our second subwindow - nothing to do - } - - child = win; - } - } - - // do we have any children at all? - if ( child ) - { - // exactly one child - set it's size to fill the whole frame - int clientW, clientH; - DoGetClientSize(&clientW, &clientH); - - // for whatever reasons, wxGTK wants to have a small offset - it - // probably looks better with it? -#ifdef __WXGTK__ - static const int ofs = 1; -#else - static const int ofs = 0; -#endif - - child->SetSize(ofs, ofs, clientW - 2*ofs, clientH - 2*ofs); - } - } -} - -/*** Copied from top level..! ***/ -// The default implementation for the close window event. -void wxGenericMDIChildFrame::OnCloseWindow(wxCloseEvent& WXUNUSED(event)) -{ - Destroy(); -} - -void wxGenericMDIChildFrame::SetMDIParentFrame(wxGenericMDIParentFrame* parentFrame) -{ - m_pMDIParentFrame = parentFrame; -} - -wxGenericMDIParentFrame* wxGenericMDIChildFrame::GetMDIParentFrame() const -{ - return m_pMDIParentFrame; -} - -void wxGenericMDIChildFrame::Init() -{ - m_pMDIParentFrame = (wxGenericMDIParentFrame *) NULL; -#if wxUSE_MENUS - m_pMenuBar = (wxMenuBar *) NULL; -#endif // wxUSE_MENUS -} - -void wxGenericMDIChildFrame::DoMoveWindow(int x, int y, int width, int height) -{ - m_MDIRect = wxRect(x, y, width, height); -} - -void wxGenericMDIChildFrame::ApplyMDIChildFrameRect() -{ - wxPanel::DoMoveWindow(m_MDIRect.x, m_MDIRect.y, m_MDIRect.width, m_MDIRect.height); -} - -//----------------------------------------------------------------------------- -// wxGenericMDIClientWindow -//----------------------------------------------------------------------------- - -#define wxID_NOTEBOOK_CLIENT_AREA wxID_HIGHEST + 100 - -IMPLEMENT_DYNAMIC_CLASS(wxGenericMDIClientWindow, wxNotebook) - -BEGIN_EVENT_TABLE(wxGenericMDIClientWindow, wxNotebook) - EVT_NOTEBOOK_PAGE_CHANGED(wxID_NOTEBOOK_CLIENT_AREA, wxGenericMDIClientWindow::OnPageChanged) - EVT_SIZE(wxGenericMDIClientWindow::OnSize) -END_EVENT_TABLE() - - -wxGenericMDIClientWindow::wxGenericMDIClientWindow() -{ -} - -wxGenericMDIClientWindow::wxGenericMDIClientWindow( wxGenericMDIParentFrame *parent, long style ) -{ - CreateClient( parent, style ); -} - -wxGenericMDIClientWindow::~wxGenericMDIClientWindow() -{ - DestroyChildren(); -} - -bool wxGenericMDIClientWindow::CreateClient( wxGenericMDIParentFrame *parent, long style ) -{ - SetWindowStyleFlag(style); - - bool success = wxNotebook::Create(parent, wxID_NOTEBOOK_CLIENT_AREA, wxPoint(0,0), wxSize(100, 100), 0); - if (success) - { - /* - wxFont font(10, wxSWISS, wxNORMAL, wxNORMAL); - wxFont selFont(10, wxSWISS, wxNORMAL, wxBOLD); - GetTabView()->SetTabFont(font); - GetTabView()->SetSelectedTabFont(selFont); - GetTabView()->SetTabSize(120, 18); - GetTabView()->SetTabSelectionHeight(20); - */ - return true; - } - else - return false; -} - -int wxGenericMDIClientWindow::SetSelection(size_t nPage) -{ - int oldSelection = wxNotebook::SetSelection(nPage); - -#if !defined(__WXMSW__) // No need to do this for wxMSW as wxNotebook::SetSelection() - // will already cause this to be done! - // Handle the page change. - PageChanged(oldSelection, nPage); -#endif - - return oldSelection; -} - -void wxGenericMDIClientWindow::PageChanged(int OldSelection, int newSelection) -{ - // Don't do to much work, only when something realy should change! - if (OldSelection == newSelection) - return; - // Again check if we realy need to do this... - if (newSelection != -1) - { - wxGenericMDIChildFrame* child = (wxGenericMDIChildFrame *)GetPage(newSelection); - - if (child->GetMDIParentFrame()->GetActiveChild() == child) - return; - } - - // Notify old active child that it has been deactivated - if (OldSelection != -1) - { - wxGenericMDIChildFrame* oldChild = (wxGenericMDIChildFrame *)GetPage(OldSelection); - if (oldChild) - { - wxActivateEvent event(wxEVT_ACTIVATE, false, oldChild->GetId()); - event.SetEventObject( oldChild ); - oldChild->GetEventHandler()->ProcessEvent(event); - } - } - - // Notify new active child that it has been activated - if (newSelection != -1) - { - wxGenericMDIChildFrame* activeChild = (wxGenericMDIChildFrame *)GetPage(newSelection); - if (activeChild) - { - wxActivateEvent event(wxEVT_ACTIVATE, true, activeChild->GetId()); - event.SetEventObject( activeChild ); - activeChild->GetEventHandler()->ProcessEvent(event); - - if (activeChild->GetMDIParentFrame()) - { - activeChild->GetMDIParentFrame()->SetActiveChild(activeChild); - activeChild->GetMDIParentFrame()->SetChildMenuBar(activeChild); - } - } - } -} - -void wxGenericMDIClientWindow::OnPageChanged(wxNotebookEvent& event) -{ - PageChanged(event.GetOldSelection(), event.GetSelection()); - - event.Skip(); -} - -void wxGenericMDIClientWindow::OnSize(wxSizeEvent& event) -{ - wxNotebook::OnSize(event); - - size_t pos; - for (pos = 0; pos < GetPageCount(); pos++) - { - ((wxGenericMDIChildFrame *)GetPage(pos))->ApplyMDIChildFrameRect(); - } -} - - -/* - * Define normal wxMDI classes based on wxGenericMDI - */ - -#if wxUSE_GENERIC_MDI_AS_NATIVE - -wxMDIChildFrame * wxMDIParentFrame::GetActiveChild() const - { - wxGenericMDIChildFrame *pGFrame = wxGenericMDIParentFrame::GetActiveChild(); - wxMDIChildFrame *pFrame = wxDynamicCast(pGFrame, wxMDIChildFrame); - - wxASSERT_MSG(!(pFrame == NULL && pGFrame != NULL), wxT("Active frame is class not derived from wxMDIChildFrame!")); - - return pFrame; - } - -IMPLEMENT_DYNAMIC_CLASS(wxMDIParentFrame, wxGenericMDIParentFrame) -IMPLEMENT_DYNAMIC_CLASS(wxMDIChildFrame, wxGenericMDIChildFrame) -IMPLEMENT_DYNAMIC_CLASS(wxMDIClientWindow, wxGenericMDIClientWindow) - -#endif // wxUSE_GENERIC_MDI_AS_NATIVE - -#endif // wxUSE_MDI - +///////////////////////////////////////////////////////////////////////////// +// Name: src/generic/mdig.cpp +// Purpose: Generic MDI (Multiple Document Interface) classes +// Author: Hans Van Leemputten +// Modified by: +// Created: 29/07/2002 +// RCS-ID: $Id: mdig.cpp 41069 2006-09-08 14:38:49Z VS $ +// Copyright: (c) Hans Van Leemputten +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// =========================================================================== +// declarations +// =========================================================================== + +// --------------------------------------------------------------------------- +// headers +// --------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_MDI + +#include "wx/generic/mdig.h" + +#ifndef WX_PRECOMP + #include "wx/panel.h" + #include "wx/menu.h" + #include "wx/intl.h" + #include "wx/log.h" +#endif //WX_PRECOMP + +#include "wx/stockitem.h" + +enum MDI_MENU_ID +{ + wxWINDOWCLOSE = 4001, + wxWINDOWCLOSEALL, + wxWINDOWNEXT, + wxWINDOWPREV +}; + +//----------------------------------------------------------------------------- +// wxGenericMDIParentFrame +//----------------------------------------------------------------------------- + +IMPLEMENT_DYNAMIC_CLASS(wxGenericMDIParentFrame, wxFrame) + +BEGIN_EVENT_TABLE(wxGenericMDIParentFrame, wxFrame) +#if wxUSE_MENUS + EVT_MENU (wxID_ANY, wxGenericMDIParentFrame::DoHandleMenu) +#endif +END_EVENT_TABLE() + +wxGenericMDIParentFrame::wxGenericMDIParentFrame() +{ + Init(); +} + +wxGenericMDIParentFrame::wxGenericMDIParentFrame(wxWindow *parent, + wxWindowID id, + const wxString& title, + const wxPoint& pos, + const wxSize& size, + long style, + const wxString& name) +{ + Init(); + + (void)Create(parent, id, title, pos, size, style, name); +} + +wxGenericMDIParentFrame::~wxGenericMDIParentFrame() +{ + // Make sure the client window is destructed before the menu bars are! + wxDELETE(m_pClientWindow); + +#if wxUSE_MENUS + if (m_pMyMenuBar) + { + delete m_pMyMenuBar; + m_pMyMenuBar = (wxMenuBar *) NULL; + } + + RemoveWindowMenu(GetMenuBar()); + + if (m_pWindowMenu) + { + delete m_pWindowMenu; + m_pWindowMenu = (wxMenu*) NULL; + } +#endif // wxUSE_MENUS +} + +bool wxGenericMDIParentFrame::Create(wxWindow *parent, + wxWindowID id, + const wxString& title, + const wxPoint& pos, + const wxSize& size, + long style, + const wxString& name) +{ + // this style can be used to prevent a window from having the standard MDI + // "Window" menu + if ( !(style & wxFRAME_NO_WINDOW_MENU) ) + { +#if wxUSE_MENUS + m_pWindowMenu = new wxMenu; + + m_pWindowMenu->Append(wxWINDOWCLOSE, _("Cl&ose")); + m_pWindowMenu->Append(wxWINDOWCLOSEALL, _("Close All")); + m_pWindowMenu->AppendSeparator(); + m_pWindowMenu->Append(wxWINDOWNEXT, _("&Next")); + m_pWindowMenu->Append(wxWINDOWPREV, _("&Previous")); +#endif // wxUSE_MENUS + } + + wxFrame::Create( parent, id, title, pos, size, style, name ); + + OnCreateClient(); + + return true; +} + +#if wxUSE_MENUS +void wxGenericMDIParentFrame::SetWindowMenu(wxMenu* pMenu) +{ + // Replace the window menu from the currently loaded menu bar. + wxMenuBar *pMenuBar = GetMenuBar(); + + if (m_pWindowMenu) + { + RemoveWindowMenu(pMenuBar); + + wxDELETE(m_pWindowMenu); + } + + if (pMenu) + { + m_pWindowMenu = pMenu; + + AddWindowMenu(pMenuBar); + } +} + +void wxGenericMDIParentFrame::SetMenuBar(wxMenuBar *pMenuBar) +{ + // Remove the Window menu from the old menu bar + RemoveWindowMenu(GetMenuBar()); + // Add the Window menu to the new menu bar. + AddWindowMenu(pMenuBar); + + wxFrame::SetMenuBar(pMenuBar); +} +#endif // wxUSE_MENUS + +void wxGenericMDIParentFrame::SetChildMenuBar(wxGenericMDIChildFrame *pChild) +{ +#if wxUSE_MENUS + if (pChild == (wxGenericMDIChildFrame *) NULL) + { + // No Child, set Our menu bar back. + SetMenuBar(m_pMyMenuBar); + + // Make sure we know our menu bar is in use + m_pMyMenuBar = (wxMenuBar*) NULL; + } + else + { + if (pChild->GetMenuBar() == (wxMenuBar*) NULL) + return; + + // Do we need to save the current bar? + if (m_pMyMenuBar == NULL) + m_pMyMenuBar = GetMenuBar(); + + SetMenuBar(pChild->GetMenuBar()); + } +#endif // wxUSE_MENUS +} + +bool wxGenericMDIParentFrame::ProcessEvent(wxEvent& event) +{ + /* + * Redirect events to active child first. + */ + + // Stops the same event being processed repeatedly + static wxEventType inEvent = wxEVT_NULL; + if (inEvent == event.GetEventType()) + return false; + + inEvent = event.GetEventType(); + + // Let the active child (if any) process the event first. + bool res = false; + if (m_pActiveChild && event.IsKindOf(CLASSINFO(wxCommandEvent)) +#if 0 + /* This is sure to not give problems... */ + && (event.GetEventType() == wxEVT_COMMAND_MENU_SELECTED || + event.GetEventType() == wxEVT_UPDATE_UI ) +#else + /* This was tested on wxMSW and worked... */ + && event.GetEventObject() != m_pClientWindow + && !(event.GetEventType() == wxEVT_ACTIVATE || + event.GetEventType() == wxEVT_SET_FOCUS || + event.GetEventType() == wxEVT_KILL_FOCUS || + event.GetEventType() == wxEVT_CHILD_FOCUS || + event.GetEventType() == wxEVT_COMMAND_SET_FOCUS || + event.GetEventType() == wxEVT_COMMAND_KILL_FOCUS ) +#endif + ) + { + res = m_pActiveChild->GetEventHandler()->ProcessEvent(event); + } + + // If the event was not handled this frame will handle it! + if (!res) + { + res = GetEventHandler()->wxEvtHandler::ProcessEvent(event); + } + + inEvent = wxEVT_NULL; + + return res; +} + +wxGenericMDIChildFrame *wxGenericMDIParentFrame::GetActiveChild() const +{ + return m_pActiveChild; +} + +void wxGenericMDIParentFrame::SetActiveChild(wxGenericMDIChildFrame* pChildFrame) +{ + m_pActiveChild = pChildFrame; +} + +wxGenericMDIClientWindow *wxGenericMDIParentFrame::GetClientWindow() const +{ + return m_pClientWindow; +} + +wxGenericMDIClientWindow *wxGenericMDIParentFrame::OnCreateClient() +{ +#if wxUSE_GENERIC_MDI_AS_NATIVE + m_pClientWindow = new wxMDIClientWindow( this ); +#else + m_pClientWindow = new wxGenericMDIClientWindow( this ); +#endif + return m_pClientWindow; +} + +void wxGenericMDIParentFrame::ActivateNext() +{ + if (m_pClientWindow && m_pClientWindow->GetSelection() != -1) + { + size_t active = m_pClientWindow->GetSelection() + 1; + if (active >= m_pClientWindow->GetPageCount()) + active = 0; + + m_pClientWindow->SetSelection(active); + } +} + +void wxGenericMDIParentFrame::ActivatePrevious() +{ + if (m_pClientWindow && m_pClientWindow->GetSelection() != -1) + { + int active = m_pClientWindow->GetSelection() - 1; + if (active < 0) + active = m_pClientWindow->GetPageCount() - 1; + + m_pClientWindow->SetSelection(active); + } +} + +void wxGenericMDIParentFrame::Init() +{ + m_pClientWindow = (wxGenericMDIClientWindow *) NULL; + m_pActiveChild = (wxGenericMDIChildFrame *) NULL; +#if wxUSE_MENUS + m_pWindowMenu = (wxMenu *) NULL; + m_pMyMenuBar = (wxMenuBar*) NULL; +#endif // wxUSE_MENUS +} + +#if wxUSE_MENUS +void wxGenericMDIParentFrame::RemoveWindowMenu(wxMenuBar *pMenuBar) +{ + if (pMenuBar && m_pWindowMenu) + { + // Remove old window menu + int pos = pMenuBar->FindMenu(_("&Window")); + if (pos != wxNOT_FOUND) + { + wxASSERT(m_pWindowMenu == pMenuBar->GetMenu(pos)); // DBG:: We're going to delete the wrong menu!!! + pMenuBar->Remove(pos); + } + } +} + +void wxGenericMDIParentFrame::AddWindowMenu(wxMenuBar *pMenuBar) +{ + if (pMenuBar && m_pWindowMenu) + { + int pos = pMenuBar->FindMenu(wxGetStockLabel(wxID_HELP,false)); + if (pos == wxNOT_FOUND) + { + pMenuBar->Append(m_pWindowMenu, _("&Window")); + } + else + { + pMenuBar->Insert(pos, m_pWindowMenu, _("&Window")); + } + } +} + +void wxGenericMDIParentFrame::DoHandleMenu(wxCommandEvent &event) +{ + switch (event.GetId()) + { + case wxWINDOWCLOSE: + if (m_pActiveChild) + { + m_pActiveChild->Close(); + } + break; + case wxWINDOWCLOSEALL: + { +#if 0 // code is only needed if next #if is set to 0! + wxGenericMDIChildFrame *pFirstActiveChild = m_pActiveChild; +#endif + while (m_pActiveChild) + { + if (!m_pActiveChild->Close()) + { + return; // We failed... + } + else + { +#if 1 // What's best? Delayed deleting or immediate deleting? + delete m_pActiveChild; + m_pActiveChild = NULL; +#else + ActivateNext(); + + if (pFirstActiveChild == m_pActiveChild) + return; // We've called Close on all items, no need to continue. +#endif + } + } + } + break; + case wxWINDOWNEXT: + ActivateNext(); + break; + case wxWINDOWPREV: + ActivatePrevious(); + break; + default : + event.Skip(); + } +} +#endif // wxUSE_MENUS + +void wxGenericMDIParentFrame::DoGetClientSize(int *width, int *height) const +{ + wxFrame::DoGetClientSize( width, height ); +} + + +//----------------------------------------------------------------------------- +// wxGenericMDIChildFrame +//----------------------------------------------------------------------------- + +IMPLEMENT_DYNAMIC_CLASS(wxGenericMDIChildFrame, wxPanel) + +BEGIN_EVENT_TABLE(wxGenericMDIChildFrame, wxPanel) + EVT_MENU_HIGHLIGHT_ALL(wxGenericMDIChildFrame::OnMenuHighlight) + EVT_ACTIVATE(wxGenericMDIChildFrame::OnActivate) + + EVT_CLOSE(wxGenericMDIChildFrame::OnCloseWindow) + EVT_SIZE(wxGenericMDIChildFrame::OnSize) +END_EVENT_TABLE() + +wxGenericMDIChildFrame::wxGenericMDIChildFrame() +{ + Init(); +} + +wxGenericMDIChildFrame::wxGenericMDIChildFrame( wxGenericMDIParentFrame *parent, + wxWindowID id, const wxString& title, + const wxPoint& WXUNUSED(pos), const wxSize& size, + long style, const wxString& name ) +{ + Init(); + + Create( parent, id, title, wxDefaultPosition, size, style, name ); +} + +wxGenericMDIChildFrame::~wxGenericMDIChildFrame() +{ + wxGenericMDIParentFrame *pParentFrame = GetMDIParentFrame(); + + if (pParentFrame != NULL) + { + bool bActive = false; + if (pParentFrame->GetActiveChild() == this) + { + pParentFrame->SetActiveChild((wxGenericMDIChildFrame*) NULL); + pParentFrame->SetChildMenuBar((wxGenericMDIChildFrame*) NULL); + bActive = true; + } + + wxGenericMDIClientWindow *pClientWindow = pParentFrame->GetClientWindow(); + + // Remove page if still there + size_t pos; + for (pos = 0; pos < pClientWindow->GetPageCount(); pos++) + { + if (pClientWindow->GetPage(pos) == this) + { + if (pClientWindow->RemovePage(pos)) + pClientWindow->Refresh(); + break; + } + } + + if (bActive) + { + // Set the new selection to the a remaining page + if (pClientWindow->GetPageCount() > pos) + { + pClientWindow->SetSelection(pos); + } + else + { + if ((int)pClientWindow->GetPageCount() - 1 >= 0) + pClientWindow->SetSelection(pClientWindow->GetPageCount() - 1); + } + } + } + +#if wxUSE_MENUS + wxDELETE(m_pMenuBar); +#endif // wxUSE_MENUS +} + +bool wxGenericMDIChildFrame::Create( wxGenericMDIParentFrame *parent, + wxWindowID id, const wxString& title, + const wxPoint& WXUNUSED(pos), const wxSize& size, + long style, const wxString& name ) +{ + wxGenericMDIClientWindow* pClientWindow = parent->GetClientWindow(); + + wxASSERT_MSG((pClientWindow != (wxWindow*) NULL), wxT("Missing MDI client window.") ); + + wxPanel::Create(pClientWindow, id, wxDefaultPosition, size, style, name); + + SetMDIParentFrame(parent); + + // This is the currently active child + parent->SetActiveChild(this); + + m_Title = title; + + pClientWindow->AddPage(this, title, true); + ApplyMDIChildFrameRect(); // Ok confirme the size change! + pClientWindow->Refresh(); + + return true; +} + +#if wxUSE_MENUS +void wxGenericMDIChildFrame::SetMenuBar( wxMenuBar *menu_bar ) +{ + wxMenuBar *pOldMenuBar = m_pMenuBar; + m_pMenuBar = menu_bar; + + if (m_pMenuBar) + { + wxGenericMDIParentFrame *pParentFrame = GetMDIParentFrame(); + + if (pParentFrame != NULL) + { + m_pMenuBar->SetParent(pParentFrame); + + if (pParentFrame->GetActiveChild() == this) + { + // Replace current menu bars + if (pOldMenuBar) + pParentFrame->SetChildMenuBar((wxGenericMDIChildFrame*) NULL); + pParentFrame->SetChildMenuBar((wxGenericMDIChildFrame*) this); + } + } + } +} + +wxMenuBar *wxGenericMDIChildFrame::GetMenuBar() const +{ + return m_pMenuBar; +} +#endif // wxUSE_MENUS + +void wxGenericMDIChildFrame::SetTitle(const wxString& title) +{ + m_Title = title; + + wxGenericMDIParentFrame *pParentFrame = GetMDIParentFrame(); + + if (pParentFrame != NULL) + { + wxGenericMDIClientWindow * pClientWindow = pParentFrame->GetClientWindow(); + + if (pClientWindow != NULL) + { + size_t pos; + for (pos = 0; pos < pClientWindow->GetPageCount(); pos++) + { + if (pClientWindow->GetPage(pos) == this) + { + pClientWindow->SetPageText(pos, m_Title); + break; + } + } + } + } +} + +wxString wxGenericMDIChildFrame::GetTitle() const +{ + return m_Title; +} + +void wxGenericMDIChildFrame::Activate() +{ + wxGenericMDIParentFrame *pParentFrame = GetMDIParentFrame(); + + if (pParentFrame != NULL) + { + wxGenericMDIClientWindow * pClientWindow = pParentFrame->GetClientWindow(); + + if (pClientWindow != NULL) + { + size_t pos; + for (pos = 0; pos < pClientWindow->GetPageCount(); pos++) + { + if (pClientWindow->GetPage(pos) == this) + { + pClientWindow->SetSelection(pos); + break; + } + } + } + } +} + +void wxGenericMDIChildFrame::OnMenuHighlight(wxMenuEvent& event) +{ +#if wxUSE_STATUSBAR + if ( m_pMDIParentFrame) + { + // we don't have any help text for this item, + // but may be the MDI frame does? + m_pMDIParentFrame->OnMenuHighlight(event); + } +#else + wxUnusedVar(event); +#endif // wxUSE_STATUSBAR +} + +void wxGenericMDIChildFrame::OnActivate(wxActivateEvent& WXUNUSED(event)) +{ + // Do mothing. +} + +/*** Copied from top level..! ***/ +// default resizing behaviour - if only ONE subwindow, resize to fill the +// whole client area +void wxGenericMDIChildFrame::OnSize(wxSizeEvent& WXUNUSED(event)) +{ + // if we're using constraints or sizers - do use them + if ( GetAutoLayout() ) + { + Layout(); + } + else + { + // do we have _exactly_ one child? + wxWindow *child = (wxWindow *)NULL; + for ( wxWindowList::compatibility_iterator node = GetChildren().GetFirst(); + node; + node = node->GetNext() ) + { + wxWindow *win = node->GetData(); + + // exclude top level and managed windows (status bar isn't + // currently in the children list except under wxMac anyhow, but + // it makes no harm to test for it) + if ( !win->IsTopLevel() /*&& !IsOneOfBars(win)*/ ) + { + if ( child ) + { + return; // it's our second subwindow - nothing to do + } + + child = win; + } + } + + // do we have any children at all? + if ( child ) + { + // exactly one child - set it's size to fill the whole frame + int clientW, clientH; + DoGetClientSize(&clientW, &clientH); + + // for whatever reasons, wxGTK wants to have a small offset - it + // probably looks better with it? +#ifdef __WXGTK__ + static const int ofs = 1; +#else + static const int ofs = 0; +#endif + + child->SetSize(ofs, ofs, clientW - 2*ofs, clientH - 2*ofs); + } + } +} + +/*** Copied from top level..! ***/ +// The default implementation for the close window event. +void wxGenericMDIChildFrame::OnCloseWindow(wxCloseEvent& WXUNUSED(event)) +{ + Destroy(); +} + +void wxGenericMDIChildFrame::SetMDIParentFrame(wxGenericMDIParentFrame* parentFrame) +{ + m_pMDIParentFrame = parentFrame; +} + +wxGenericMDIParentFrame* wxGenericMDIChildFrame::GetMDIParentFrame() const +{ + return m_pMDIParentFrame; +} + +void wxGenericMDIChildFrame::Init() +{ + m_pMDIParentFrame = (wxGenericMDIParentFrame *) NULL; +#if wxUSE_MENUS + m_pMenuBar = (wxMenuBar *) NULL; +#endif // wxUSE_MENUS +} + +void wxGenericMDIChildFrame::DoMoveWindow(int x, int y, int width, int height) +{ + m_MDIRect = wxRect(x, y, width, height); +} + +void wxGenericMDIChildFrame::ApplyMDIChildFrameRect() +{ + wxPanel::DoMoveWindow(m_MDIRect.x, m_MDIRect.y, m_MDIRect.width, m_MDIRect.height); +} + +//----------------------------------------------------------------------------- +// wxGenericMDIClientWindow +//----------------------------------------------------------------------------- + +#define wxID_NOTEBOOK_CLIENT_AREA wxID_HIGHEST + 100 + +IMPLEMENT_DYNAMIC_CLASS(wxGenericMDIClientWindow, wxNotebook) + +BEGIN_EVENT_TABLE(wxGenericMDIClientWindow, wxNotebook) + EVT_NOTEBOOK_PAGE_CHANGED(wxID_NOTEBOOK_CLIENT_AREA, wxGenericMDIClientWindow::OnPageChanged) + EVT_SIZE(wxGenericMDIClientWindow::OnSize) +END_EVENT_TABLE() + + +wxGenericMDIClientWindow::wxGenericMDIClientWindow() +{ +} + +wxGenericMDIClientWindow::wxGenericMDIClientWindow( wxGenericMDIParentFrame *parent, long style ) +{ + CreateClient( parent, style ); +} + +wxGenericMDIClientWindow::~wxGenericMDIClientWindow() +{ + DestroyChildren(); +} + +bool wxGenericMDIClientWindow::CreateClient( wxGenericMDIParentFrame *parent, long style ) +{ + SetWindowStyleFlag(style); + + bool success = wxNotebook::Create(parent, wxID_NOTEBOOK_CLIENT_AREA, wxPoint(0,0), wxSize(100, 100), 0); + if (success) + { + /* + wxFont font(10, wxSWISS, wxNORMAL, wxNORMAL); + wxFont selFont(10, wxSWISS, wxNORMAL, wxBOLD); + GetTabView()->SetTabFont(font); + GetTabView()->SetSelectedTabFont(selFont); + GetTabView()->SetTabSize(120, 18); + GetTabView()->SetTabSelectionHeight(20); + */ + return true; + } + else + return false; +} + +int wxGenericMDIClientWindow::SetSelection(size_t nPage) +{ + int oldSelection = wxNotebook::SetSelection(nPage); + +#if !defined(__WXMSW__) // No need to do this for wxMSW as wxNotebook::SetSelection() + // will already cause this to be done! + // Handle the page change. + PageChanged(oldSelection, nPage); +#endif + + return oldSelection; +} + +void wxGenericMDIClientWindow::PageChanged(int OldSelection, int newSelection) +{ + // Don't do to much work, only when something realy should change! + if (OldSelection == newSelection) + return; + // Again check if we realy need to do this... + if (newSelection != -1) + { + wxGenericMDIChildFrame* child = (wxGenericMDIChildFrame *)GetPage(newSelection); + + if (child->GetMDIParentFrame()->GetActiveChild() == child) + return; + } + + // Notify old active child that it has been deactivated + if (OldSelection != -1) + { + wxGenericMDIChildFrame* oldChild = (wxGenericMDIChildFrame *)GetPage(OldSelection); + if (oldChild) + { + wxActivateEvent event(wxEVT_ACTIVATE, false, oldChild->GetId()); + event.SetEventObject( oldChild ); + oldChild->GetEventHandler()->ProcessEvent(event); + } + } + + // Notify new active child that it has been activated + if (newSelection != -1) + { + wxGenericMDIChildFrame* activeChild = (wxGenericMDIChildFrame *)GetPage(newSelection); + if (activeChild) + { + wxActivateEvent event(wxEVT_ACTIVATE, true, activeChild->GetId()); + event.SetEventObject( activeChild ); + activeChild->GetEventHandler()->ProcessEvent(event); + + if (activeChild->GetMDIParentFrame()) + { + activeChild->GetMDIParentFrame()->SetActiveChild(activeChild); + activeChild->GetMDIParentFrame()->SetChildMenuBar(activeChild); + } + } + } +} + +void wxGenericMDIClientWindow::OnPageChanged(wxNotebookEvent& event) +{ + PageChanged(event.GetOldSelection(), event.GetSelection()); + + event.Skip(); +} + +void wxGenericMDIClientWindow::OnSize(wxSizeEvent& event) +{ + wxNotebook::OnSize(event); + + size_t pos; + for (pos = 0; pos < GetPageCount(); pos++) + { + ((wxGenericMDIChildFrame *)GetPage(pos))->ApplyMDIChildFrameRect(); + } +} + + +/* + * Define normal wxMDI classes based on wxGenericMDI + */ + +#if wxUSE_GENERIC_MDI_AS_NATIVE + +wxMDIChildFrame * wxMDIParentFrame::GetActiveChild() const + { + wxGenericMDIChildFrame *pGFrame = wxGenericMDIParentFrame::GetActiveChild(); + wxMDIChildFrame *pFrame = wxDynamicCast(pGFrame, wxMDIChildFrame); + + wxASSERT_MSG(!(pFrame == NULL && pGFrame != NULL), wxT("Active frame is class not derived from wxMDIChildFrame!")); + + return pFrame; + } + +IMPLEMENT_DYNAMIC_CLASS(wxMDIParentFrame, wxGenericMDIParentFrame) +IMPLEMENT_DYNAMIC_CLASS(wxMDIChildFrame, wxGenericMDIChildFrame) +IMPLEMENT_DYNAMIC_CLASS(wxMDIClientWindow, wxGenericMDIClientWindow) + +#endif // wxUSE_GENERIC_MDI_AS_NATIVE + +#endif // wxUSE_MDI + diff --git a/Externals/wxWidgets/src/generic/msgdlgg.cpp b/Externals/wxWidgets/src/generic/msgdlgg.cpp index 8887f131b0..74407e14bd 100644 --- a/Externals/wxWidgets/src/generic/msgdlgg.cpp +++ b/Externals/wxWidgets/src/generic/msgdlgg.cpp @@ -1,159 +1,159 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/generic/msgdlgg.cpp -// Purpose: wxGenericMessageDialog -// Author: Julian Smart, Robert Roebling -// Modified by: -// Created: 04/01/98 -// RCS-ID: $Id: msgdlgg.cpp 41838 2006-10-09 21:08:45Z VZ $ -// Copyright: (c) Julian Smart and Robert Roebling -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ -#pragma hdrstop -#endif - -#if wxUSE_MSGDLG && (!defined(__WXGTK20__) || defined(__WXUNIVERSAL__) || defined(__WXGPE__)) - -#ifndef WX_PRECOMP - #include "wx/utils.h" - #include "wx/dialog.h" - #include "wx/button.h" - #include "wx/stattext.h" - #include "wx/statbmp.h" - #include "wx/layout.h" - #include "wx/intl.h" - #include "wx/icon.h" - #include "wx/sizer.h" - #include "wx/app.h" - #include "wx/settings.h" -#endif - -#include -#include - -#define __WX_COMPILING_MSGDLGG_CPP__ 1 -#include "wx/msgdlg.h" -#include "wx/artprov.h" - -#if wxUSE_STATLINE - #include "wx/statline.h" -#endif - -// ---------------------------------------------------------------------------- -// icons -// ---------------------------------------------------------------------------- - -BEGIN_EVENT_TABLE(wxGenericMessageDialog, wxDialog) - EVT_BUTTON(wxID_YES, wxGenericMessageDialog::OnYes) - EVT_BUTTON(wxID_NO, wxGenericMessageDialog::OnNo) - EVT_BUTTON(wxID_CANCEL, wxGenericMessageDialog::OnCancel) -END_EVENT_TABLE() - -IMPLEMENT_CLASS(wxGenericMessageDialog, wxDialog) - -wxGenericMessageDialog::wxGenericMessageDialog( wxWindow *parent, - const wxString& message, - const wxString& caption, - long style, - const wxPoint& pos) - : wxDialog( parent, wxID_ANY, caption, pos, wxDefaultSize, wxDEFAULT_DIALOG_STYLE ) -{ - SetMessageDialogStyle(style); - - bool is_pda = (wxSystemSettings::GetScreenType() <= wxSYS_SCREEN_PDA); - - wxBoxSizer *topsizer = new wxBoxSizer( wxVERTICAL ); - - wxBoxSizer *icon_text = new wxBoxSizer( wxHORIZONTAL ); - -#if wxUSE_STATBMP - // 1) icon - if (style & wxICON_MASK) - { - wxBitmap bitmap; - switch ( style & wxICON_MASK ) - { - default: - wxFAIL_MSG(_T("incorrect log style")); - // fall through - - case wxICON_ERROR: - bitmap = wxArtProvider::GetIcon(wxART_ERROR, wxART_MESSAGE_BOX); - break; - - case wxICON_INFORMATION: - bitmap = wxArtProvider::GetIcon(wxART_INFORMATION, wxART_MESSAGE_BOX); - break; - - case wxICON_WARNING: - bitmap = wxArtProvider::GetIcon(wxART_WARNING, wxART_MESSAGE_BOX); - break; - - case wxICON_QUESTION: - bitmap = wxArtProvider::GetIcon(wxART_QUESTION, wxART_MESSAGE_BOX); - break; - } - wxStaticBitmap *icon = new wxStaticBitmap(this, wxID_ANY, bitmap); - if (is_pda) - topsizer->Add( icon, 0, wxTOP|wxLEFT|wxRIGHT | wxALIGN_LEFT, 10 ); - else - icon_text->Add( icon, 0, wxCENTER ); - } -#endif // wxUSE_STATBMP - -#if wxUSE_STATTEXT - // 2) text - icon_text->Add( CreateTextSizer( message ), 0, wxALIGN_CENTER | wxLEFT, 10 ); - - topsizer->Add( icon_text, 1, wxCENTER | wxLEFT|wxRIGHT|wxTOP, 10 ); -#endif // wxUSE_STATTEXT - - // 3) buttons - int center_flag = wxEXPAND; - if (style & wxYES_NO) - center_flag = wxALIGN_CENTRE; - wxSizer *sizerBtn = CreateSeparatedButtonSizer(style & ButtonSizerFlags); - if ( sizerBtn ) - topsizer->Add(sizerBtn, 0, center_flag | wxALL, 10 ); - - SetAutoLayout( true ); - SetSizer( topsizer ); - - topsizer->SetSizeHints( this ); - topsizer->Fit( this ); - wxSize size( GetSize() ); - if (size.x < size.y*3/2) - { - size.x = size.y*3/2; - SetSize( size ); - } - - Centre( wxBOTH | wxCENTER_FRAME); -} - -void wxGenericMessageDialog::OnYes(wxCommandEvent& WXUNUSED(event)) -{ - EndModal( wxID_YES ); -} - -void wxGenericMessageDialog::OnNo(wxCommandEvent& WXUNUSED(event)) -{ - EndModal( wxID_NO ); -} - -void wxGenericMessageDialog::OnCancel(wxCommandEvent& WXUNUSED(event)) -{ - // Allow cancellation via ESC/Close button except if - // only YES and NO are specified. - const long style = GetMessageDialogStyle(); - if ( (style & wxYES_NO) != wxYES_NO || (style & wxCANCEL) ) - { - EndModal( wxID_CANCEL ); - } -} - -#endif // wxUSE_MSGDLG && !defined(__WXGTK20__) +///////////////////////////////////////////////////////////////////////////// +// Name: src/generic/msgdlgg.cpp +// Purpose: wxGenericMessageDialog +// Author: Julian Smart, Robert Roebling +// Modified by: +// Created: 04/01/98 +// RCS-ID: $Id: msgdlgg.cpp 41838 2006-10-09 21:08:45Z VZ $ +// Copyright: (c) Julian Smart and Robert Roebling +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ +#pragma hdrstop +#endif + +#if wxUSE_MSGDLG && (!defined(__WXGTK20__) || defined(__WXUNIVERSAL__) || defined(__WXGPE__)) + +#ifndef WX_PRECOMP + #include "wx/utils.h" + #include "wx/dialog.h" + #include "wx/button.h" + #include "wx/stattext.h" + #include "wx/statbmp.h" + #include "wx/layout.h" + #include "wx/intl.h" + #include "wx/icon.h" + #include "wx/sizer.h" + #include "wx/app.h" + #include "wx/settings.h" +#endif + +#include +#include + +#define __WX_COMPILING_MSGDLGG_CPP__ 1 +#include "wx/msgdlg.h" +#include "wx/artprov.h" + +#if wxUSE_STATLINE + #include "wx/statline.h" +#endif + +// ---------------------------------------------------------------------------- +// icons +// ---------------------------------------------------------------------------- + +BEGIN_EVENT_TABLE(wxGenericMessageDialog, wxDialog) + EVT_BUTTON(wxID_YES, wxGenericMessageDialog::OnYes) + EVT_BUTTON(wxID_NO, wxGenericMessageDialog::OnNo) + EVT_BUTTON(wxID_CANCEL, wxGenericMessageDialog::OnCancel) +END_EVENT_TABLE() + +IMPLEMENT_CLASS(wxGenericMessageDialog, wxDialog) + +wxGenericMessageDialog::wxGenericMessageDialog( wxWindow *parent, + const wxString& message, + const wxString& caption, + long style, + const wxPoint& pos) + : wxDialog( parent, wxID_ANY, caption, pos, wxDefaultSize, wxDEFAULT_DIALOG_STYLE ) +{ + SetMessageDialogStyle(style); + + bool is_pda = (wxSystemSettings::GetScreenType() <= wxSYS_SCREEN_PDA); + + wxBoxSizer *topsizer = new wxBoxSizer( wxVERTICAL ); + + wxBoxSizer *icon_text = new wxBoxSizer( wxHORIZONTAL ); + +#if wxUSE_STATBMP + // 1) icon + if (style & wxICON_MASK) + { + wxBitmap bitmap; + switch ( style & wxICON_MASK ) + { + default: + wxFAIL_MSG(_T("incorrect log style")); + // fall through + + case wxICON_ERROR: + bitmap = wxArtProvider::GetIcon(wxART_ERROR, wxART_MESSAGE_BOX); + break; + + case wxICON_INFORMATION: + bitmap = wxArtProvider::GetIcon(wxART_INFORMATION, wxART_MESSAGE_BOX); + break; + + case wxICON_WARNING: + bitmap = wxArtProvider::GetIcon(wxART_WARNING, wxART_MESSAGE_BOX); + break; + + case wxICON_QUESTION: + bitmap = wxArtProvider::GetIcon(wxART_QUESTION, wxART_MESSAGE_BOX); + break; + } + wxStaticBitmap *icon = new wxStaticBitmap(this, wxID_ANY, bitmap); + if (is_pda) + topsizer->Add( icon, 0, wxTOP|wxLEFT|wxRIGHT | wxALIGN_LEFT, 10 ); + else + icon_text->Add( icon, 0, wxCENTER ); + } +#endif // wxUSE_STATBMP + +#if wxUSE_STATTEXT + // 2) text + icon_text->Add( CreateTextSizer( message ), 0, wxALIGN_CENTER | wxLEFT, 10 ); + + topsizer->Add( icon_text, 1, wxCENTER | wxLEFT|wxRIGHT|wxTOP, 10 ); +#endif // wxUSE_STATTEXT + + // 3) buttons + int center_flag = wxEXPAND; + if (style & wxYES_NO) + center_flag = wxALIGN_CENTRE; + wxSizer *sizerBtn = CreateSeparatedButtonSizer(style & ButtonSizerFlags); + if ( sizerBtn ) + topsizer->Add(sizerBtn, 0, center_flag | wxALL, 10 ); + + SetAutoLayout( true ); + SetSizer( topsizer ); + + topsizer->SetSizeHints( this ); + topsizer->Fit( this ); + wxSize size( GetSize() ); + if (size.x < size.y*3/2) + { + size.x = size.y*3/2; + SetSize( size ); + } + + Centre( wxBOTH | wxCENTER_FRAME); +} + +void wxGenericMessageDialog::OnYes(wxCommandEvent& WXUNUSED(event)) +{ + EndModal( wxID_YES ); +} + +void wxGenericMessageDialog::OnNo(wxCommandEvent& WXUNUSED(event)) +{ + EndModal( wxID_NO ); +} + +void wxGenericMessageDialog::OnCancel(wxCommandEvent& WXUNUSED(event)) +{ + // Allow cancellation via ESC/Close button except if + // only YES and NO are specified. + const long style = GetMessageDialogStyle(); + if ( (style & wxYES_NO) != wxYES_NO || (style & wxCANCEL) ) + { + EndModal( wxID_CANCEL ); + } +} + +#endif // wxUSE_MSGDLG && !defined(__WXGTK20__) diff --git a/Externals/wxWidgets/src/generic/notebook.cpp b/Externals/wxWidgets/src/generic/notebook.cpp index 3158292b93..3abb733d88 100644 --- a/Externals/wxWidgets/src/generic/notebook.cpp +++ b/Externals/wxWidgets/src/generic/notebook.cpp @@ -1,762 +1,762 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: src/generic/notebook.cpp -// Purpose: generic implementation of wxNotebook -// Author: Julian Smart -// Modified by: -// Created: 17/09/98 -// RCS-ID: $Id: notebook.cpp 50855 2007-12-20 10:51:33Z JS $ -// Copyright: (c) Julian Smart -// Licence: wxWindows licence -/////////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_NOTEBOOK - -#include "wx/notebook.h" - -#ifndef WX_PRECOMP - #include "wx/string.h" - #include "wx/log.h" - #include "wx/dcclient.h" - #include "wx/settings.h" -#endif - -#include "wx/imaglist.h" -#include "wx/generic/tabg.h" - -// ---------------------------------------------------------------------------- -// macros -// ---------------------------------------------------------------------------- - -// check that the page index is valid -#define IS_VALID_PAGE(nPage) ((nPage) < GetPageCount()) - -// ---------------------------------------------------------------------------- -// event table -// ---------------------------------------------------------------------------- - -DEFINE_EVENT_TYPE(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGING) - -BEGIN_EVENT_TABLE(wxNotebook, wxBookCtrlBase) - EVT_NOTEBOOK_PAGE_CHANGED(wxID_ANY, wxNotebook::OnSelChange) - EVT_SIZE(wxNotebook::OnSize) - EVT_PAINT(wxNotebook::OnPaint) - EVT_MOUSE_EVENTS(wxNotebook::OnMouseEvent) - EVT_SET_FOCUS(wxNotebook::OnSetFocus) - EVT_NAVIGATION_KEY(wxNotebook::OnNavigationKey) -END_EVENT_TABLE() - -IMPLEMENT_DYNAMIC_CLASS(wxNotebook, wxBookCtrlBase) -IMPLEMENT_DYNAMIC_CLASS(wxNotebookEvent, wxCommandEvent) - -// ============================================================================ -// implementation -// ============================================================================ - -// ============================================================================ -// Private class -// ============================================================================ - -WX_DECLARE_HASH_MAP(int, wxNotebookPage*, wxIntegerHash, wxIntegerEqual, - wxIntToNotebookPageHashMap); - -WX_DECLARE_HASH_MAP(wxNotebookPage*, int, wxPointerHash, wxPointerEqual, - wxNotebookPageToIntHashMap); - -// This reuses wxTabView to draw the tabs. -class WXDLLEXPORT wxNotebookTabView: public wxTabView -{ -DECLARE_DYNAMIC_CLASS(wxNotebookTabView) -public: - wxNotebookTabView(wxNotebook* notebook, long style = wxTAB_STYLE_DRAW_BOX | wxTAB_STYLE_COLOUR_INTERIOR); - virtual ~wxNotebookTabView(void); - - // Called when a tab is activated - virtual void OnTabActivate(int activateId, int deactivateId); - // Allows vetoing - virtual bool OnTabPreActivate(int activateId, int deactivateId); - - // map integer ids used by wxTabView to wxNotebookPage pointers - int GetId(wxNotebookPage *page); - wxNotebookPage *GetPage(int id) { return m_idToPage[id]; } - -protected: - wxNotebook* m_notebook; - -private: - wxIntToNotebookPageHashMap m_idToPage; - wxNotebookPageToIntHashMap m_pageToId; - int m_nextid; -}; - -static int GetPageId(wxTabView *tabview, wxNotebookPage *page) -{ - return wx_static_cast(wxNotebookTabView*, tabview)->GetId(page); -} - -// ---------------------------------------------------------------------------- -// wxNotebook construction -// ---------------------------------------------------------------------------- - -// common part of all ctors -void wxNotebook::Init() -{ - m_tabView = (wxNotebookTabView*) NULL; - m_nSelection = -1; -} - -// default for dynamic class -wxNotebook::wxNotebook() -{ - Init(); -} - -// the same arguments as for wxControl -wxNotebook::wxNotebook(wxWindow *parent, - wxWindowID id, - const wxPoint& pos, - const wxSize& size, - long style, - const wxString& name) -{ - Init(); - - Create(parent, id, pos, size, style, name); -} - -// Create() function -bool wxNotebook::Create(wxWindow *parent, - wxWindowID id, - const wxPoint& pos, - const wxSize& size, - long style, - const wxString& name) -{ - // base init - SetName(name); - - if ( (style & wxBK_ALIGN_MASK) == wxBK_DEFAULT ) - style |= wxBK_TOP; - - m_windowId = id == wxID_ANY ? NewControlId() : id; - - if (!wxControl::Create(parent, id, pos, size, style|wxNO_BORDER, wxDefaultValidator, name)) - return false; - - SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE)); - - SetTabView(new wxNotebookTabView(this)); - - return true; -} - -// dtor -wxNotebook::~wxNotebook() -{ - delete m_tabView; -} - -// ---------------------------------------------------------------------------- -// wxNotebook accessors -// ---------------------------------------------------------------------------- -int wxNotebook::GetRowCount() const -{ - // TODO - return 0; -} - -int wxNotebook::SetSelection(size_t nPage) -{ - wxASSERT( IS_VALID_PAGE(nPage) ); - - wxNotebookPage* pPage = GetPage(nPage); - - m_tabView->SetTabSelection(GetPageId(m_tabView, pPage)); - - // TODO - return 0; -} - -int wxNotebook::ChangeSelection(size_t nPage) -{ - // FIXME: currently it does generate events too - return SetSelection(nPage); -} - -#if 0 -void wxNotebook::AdvanceSelection(bool bForward) -{ - int nSel = GetSelection(); - int nMax = GetPageCount() - 1; - if ( bForward ) - SetSelection(nSel == nMax ? 0 : nSel + 1); - else - SetSelection(nSel == 0 ? nMax : nSel - 1); -} -#endif - -bool wxNotebook::SetPageText(size_t nPage, const wxString& strText) -{ - wxASSERT( IS_VALID_PAGE(nPage) ); - - wxNotebookPage* page = GetPage(nPage); - if (page) - { - m_tabView->SetTabText(GetPageId(m_tabView, page), strText); - Refresh(); - return true; - } - - return false; -} - -wxString wxNotebook::GetPageText(size_t nPage) const -{ - wxASSERT( IS_VALID_PAGE(nPage) ); - - wxNotebookPage* page = ((wxNotebook*)this)->GetPage(nPage); - if (page) - return m_tabView->GetTabText(GetPageId(m_tabView, page)); - else - return wxEmptyString; -} - -int wxNotebook::GetPageImage(size_t WXUNUSED_UNLESS_DEBUG(nPage)) const -{ - wxASSERT( IS_VALID_PAGE(nPage) ); - - // TODO - return 0; -} - -bool wxNotebook::SetPageImage(size_t WXUNUSED_UNLESS_DEBUG(nPage), - int WXUNUSED(nImage)) -{ - wxASSERT( IS_VALID_PAGE(nPage) ); - - // TODO - return false; -} - -// set the size (the same for all pages) -void wxNotebook::SetPageSize(const wxSize& WXUNUSED(size)) -{ - // TODO -} - -// set the padding between tabs (in pixels) -void wxNotebook::SetPadding(const wxSize& WXUNUSED(padding)) -{ - // TODO -} - -// set the size of the tabs for wxNB_FIXEDWIDTH controls -void wxNotebook::SetTabSize(const wxSize& WXUNUSED(sz)) -{ - // TODO -} - -// ---------------------------------------------------------------------------- -// wxNotebook operations -// ---------------------------------------------------------------------------- - -// remove one page from the notebook and delete it -bool wxNotebook::DeletePage(size_t nPage) -{ - wxCHECK( IS_VALID_PAGE(nPage), false ); - - if (m_nSelection != -1) - { - m_pages[m_nSelection]->Show(false); - m_pages[m_nSelection]->Lower(); - } - - wxNotebookPage* pPage = GetPage(nPage); - - m_tabView->RemoveTab(GetPageId(m_tabView, pPage)); - - m_pages.Remove(pPage); - delete pPage; - - if (m_pages.GetCount() == 0) - { - m_nSelection = -1; - m_tabView->SetTabSelection(-1, false); - } - else if (m_nSelection > -1) - { - m_nSelection = -1; - - m_tabView->SetTabSelection(GetPageId(m_tabView, GetPage(0)), false); - - if (m_nSelection != 0) - ChangePage(-1, 0); - } - - RefreshLayout(false); - - return true; -} - -bool wxNotebook::DeletePage(wxNotebookPage* page) -{ - int pagePos = FindPagePosition(page); - if (pagePos > -1) - return DeletePage(pagePos); - else - return false; -} - -bool wxNotebook::RemovePage(size_t nPage) -{ - return DoRemovePage(nPage) != NULL; -} - -// remove one page from the notebook -wxWindow* wxNotebook::DoRemovePage(size_t nPage) -{ - wxCHECK( IS_VALID_PAGE(nPage), NULL ); - - m_pages[nPage]->Show(false); - // m_pages[nPage]->Lower(); - - wxNotebookPage* pPage = GetPage(nPage); - - m_tabView->RemoveTab(GetPageId(m_tabView, pPage)); - - m_pages.Remove(pPage); - - if (m_pages.GetCount() == 0) - { - m_nSelection = -1; - m_tabView->SetTabSelection(-1, true); - } - else if (m_nSelection > -1) - { - // Only change the selection if the page we - // deleted was the selection. - if (nPage == (size_t)m_nSelection) - { - m_nSelection = -1; - // Select the first tab. Generates a ChangePage. - m_tabView->SetTabSelection(0, true); - } - else - { - // We must adjust which tab we think is selected. - // If greater than the page we deleted, it must be moved down - // a notch. - if (size_t(m_nSelection) > nPage) - m_nSelection -- ; - } - } - - RefreshLayout(false); - - return pPage; -} - -bool wxNotebook::RemovePage(wxNotebookPage* page) -{ - int pagePos = FindPagePosition(page); - if (pagePos > -1) - return RemovePage(pagePos); - else - return false; -} - -// Find the position of the wxNotebookPage, -1 if not found. -int wxNotebook::FindPagePosition(wxNotebookPage* page) const -{ - size_t nPageCount = GetPageCount(); - size_t nPage; - for ( nPage = 0; nPage < nPageCount; nPage++ ) - if (m_pages[nPage] == page) - return nPage; - return -1; -} - -// remove all pages -bool wxNotebook::DeleteAllPages() -{ - m_tabView->ClearTabs(true); - - size_t nPageCount = GetPageCount(); - size_t nPage; - for ( nPage = 0; nPage < nPageCount; nPage++ ) - delete m_pages[nPage]; - - m_pages.Clear(); - - return true; -} - -// same as AddPage() but does it at given position -bool wxNotebook::InsertPage(size_t nPage, - wxNotebookPage *pPage, - const wxString& strText, - bool bSelect, - int WXUNUSED(imageId)) -{ - wxASSERT( pPage != NULL ); - wxCHECK( IS_VALID_PAGE(nPage) || nPage == GetPageCount(), false ); - - m_tabView->AddTab(GetPageId(m_tabView, pPage), strText); - - if (!bSelect) - pPage->Show(false); - - // save the pointer to the page - m_pages.Insert(pPage, nPage); - - if (bSelect) - { - // This will cause ChangePage to be called, via OnSelPage - - m_tabView->SetTabSelection(GetPageId(m_tabView, pPage), true); - } - - // some page must be selected: either this one or the first one if there is - // still no selection - if ( m_nSelection == -1 ) - ChangePage(-1, 0); - - RefreshLayout(false); - - return true; -} - -// ---------------------------------------------------------------------------- -// wxNotebook callbacks -// ---------------------------------------------------------------------------- - -// @@@ OnSize() is used for setting the font when it's called for the first -// time because doing it in ::Create() doesn't work (for unknown reasons) -void wxNotebook::OnSize(wxSizeEvent& event) -{ - static bool s_bFirstTime = true; - if ( s_bFirstTime ) { - // TODO: any first-time-size processing. - s_bFirstTime = false; - } - - RefreshLayout(); - - // Processing continues to next OnSize - event.Skip(); -} - -// This was supposed to cure the non-display of the notebook -// until the user resizes the window. -// What's going on? -void wxNotebook::OnInternalIdle() -{ - wxWindow::OnInternalIdle(); - -#if 0 - static bool s_bFirstTime = true; - if ( s_bFirstTime ) { - /* - wxSize sz(GetSize()); - sz.x ++; - SetSize(sz); - sz.x --; - SetSize(sz); - */ - - /* - wxSize sz(GetSize()); - wxSizeEvent sizeEvent(sz, GetId()); - sizeEvent.SetEventObject(this); - GetEventHandler()->ProcessEvent(sizeEvent); - Refresh(); - */ - s_bFirstTime = false; - } -#endif -} - -// Implementation: calculate the layout of the view rect -// and resize the children if required -bool wxNotebook::RefreshLayout(bool force) -{ - if (m_tabView) - { - wxRect oldRect = m_tabView->GetViewRect(); - - int cw, ch; - GetClientSize(& cw, & ch); - - int tabHeight = m_tabView->GetTotalTabHeight(); - wxRect rect; - rect.x = 4; - rect.y = tabHeight + 4; - rect.width = cw - 8; - rect.height = ch - 4 - rect.y ; - - m_tabView->SetViewRect(rect); - - m_tabView->LayoutTabs(); - - // Need to do it a 2nd time to get the tab height with - // the new view width, since changing the view width changes the - // tab layout. - tabHeight = m_tabView->GetTotalTabHeight(); - rect.x = 4; - rect.y = tabHeight + 4; - rect.width = cw - 8; - rect.height = ch - 4 - rect.y ; - - m_tabView->SetViewRect(rect); - - m_tabView->LayoutTabs(); - - if (!force && (rect == oldRect)) - return false; - - // fit the notebook page to the tab control's display area - - size_t nCount = m_pages.Count(); - for ( size_t nPage = 0; nPage < nCount; nPage++ ) { - wxNotebookPage *pPage = m_pages[nPage]; - wxRect clientRect = GetAvailableClientSize(); - if (pPage->IsShown()) - { - pPage->SetSize(clientRect.x, clientRect.y, clientRect.width, clientRect.height); - if ( pPage->GetAutoLayout() ) - pPage->Layout(); - } - } - Refresh(); - } - return true; -} - -void wxNotebook::OnSelChange(wxNotebookEvent& event) -{ - // is it our tab control? - if ( event.GetEventObject() == this ) - { - if (event.GetSelection() != m_nSelection) - ChangePage(event.GetOldSelection(), event.GetSelection()); - } - - // we want to give others a chance to process this message as well - event.Skip(); -} - -void wxNotebook::OnSetFocus(wxFocusEvent& event) -{ - // set focus to the currently selected page if any - if ( m_nSelection != -1 ) - m_pages[m_nSelection]->SetFocus(); - - event.Skip(); -} - -void wxNotebook::OnNavigationKey(wxNavigationKeyEvent& event) -{ - if ( event.IsWindowChange() ) { - // change pages - AdvanceSelection(event.GetDirection()); - } - else { - // pass to the parent - if ( GetParent() ) { - event.SetCurrentFocus(this); - GetParent()->ProcessEvent(event); - } - } -} - -// ---------------------------------------------------------------------------- -// wxNotebook base class virtuals -// ---------------------------------------------------------------------------- - -// override these 2 functions to do nothing: everything is done in OnSize - -void wxNotebook::SetConstraintSizes(bool /* recurse */) -{ - // don't set the sizes of the pages - their correct size is not yet known - wxControl::SetConstraintSizes(false); -} - -bool wxNotebook::DoPhase(int /* nPhase */) -{ - return true; -} - -void wxNotebook::Command(wxCommandEvent& WXUNUSED(event)) -{ - wxFAIL_MSG(wxT("wxNotebook::Command not implemented")); -} - -// ---------------------------------------------------------------------------- -// wxNotebook helper functions -// ---------------------------------------------------------------------------- - -// hide the currently active panel and show the new one -void wxNotebook::ChangePage(int nOldSel, int nSel) -{ - // cout << "ChangePage: " << nOldSel << ", " << nSel << "\n"; - wxASSERT( nOldSel != nSel ); // impossible - - if ( nOldSel != -1 ) { - m_pages[nOldSel]->Show(false); - m_pages[nOldSel]->Lower(); - } - - wxNotebookPage *pPage = m_pages[nSel]; - - wxRect clientRect = GetAvailableClientSize(); - pPage->SetSize(clientRect.x, clientRect.y, clientRect.width, clientRect.height); - - Refresh(); - - pPage->Show(true); - pPage->Raise(); - pPage->SetFocus(); - - m_nSelection = nSel; -} - -void wxNotebook::OnMouseEvent(wxMouseEvent& event) -{ - if (m_tabView) - m_tabView->OnEvent(event); -} - -void wxNotebook::OnPaint(wxPaintEvent& WXUNUSED(event) ) -{ - wxPaintDC dc(this); - if (m_tabView) - m_tabView->Draw(dc); -} - -wxSize wxNotebook::CalcSizeFromPage(const wxSize& sizePage) const -{ - // MBN: since the total tab height is really a function of the - // width, this should really call - // GetTotalTabHeightPretendingWidthIs(), but the current - // implementation will suffice, provided the wxNotebook has been - // created with a sensible initial width. - return wxSize( sizePage.x + 12, - sizePage.y + m_tabView->GetTotalTabHeight() + 6 + 4 ); -} - -wxRect wxNotebook::GetAvailableClientSize() -{ - int cw, ch; - GetClientSize(& cw, & ch); - - int tabHeight = m_tabView->GetTotalTabHeight(); - - // TODO: these margins should be configurable. - wxRect rect; - rect.x = 6; - rect.y = tabHeight + 6; - rect.width = cw - 12; - rect.height = ch - 4 - rect.y ; - - return rect; -} - -/* - * wxNotebookTabView - */ - -IMPLEMENT_CLASS(wxNotebookTabView, wxTabView) - -wxNotebookTabView::wxNotebookTabView(wxNotebook *notebook, long style) - : wxTabView(style), m_nextid(1) -{ - m_notebook = notebook; - - m_notebook->SetTabView(this); - - SetWindow(m_notebook); -} - -wxNotebookTabView::~wxNotebookTabView(void) -{ -} - -int wxNotebookTabView::GetId(wxNotebookPage *page) -{ - int& id = m_pageToId[page]; - - if (!id) - { - id = m_nextid++; - m_idToPage[id] = page; - } - - return id; -} - -// Called when a tab is activated -void wxNotebookTabView::OnTabActivate(int activateId, int deactivateId) -{ - if (!m_notebook) - return; - - wxNotebookEvent event(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED, m_notebook->GetId()); - - // Translate from wxTabView's ids (which aren't position-dependent) - // to wxNotebook's (which are). - wxNotebookPage* pActive = GetPage(activateId); - wxNotebookPage* pDeactive = GetPage(deactivateId); - - int activatePos = m_notebook->FindPagePosition(pActive); - int deactivatePos = m_notebook->FindPagePosition(pDeactive); - - event.SetEventObject(m_notebook); - event.SetSelection(activatePos); - event.SetOldSelection(deactivatePos); - m_notebook->GetEventHandler()->ProcessEvent(event); -} - -// Allows Vetoing -bool wxNotebookTabView::OnTabPreActivate(int activateId, int deactivateId) -{ - bool retval = true; - - if (m_notebook) - { - wxNotebookEvent event(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGING, m_notebook->GetId()); - - // Translate from wxTabView's ids (which aren't position-dependent) - // to wxNotebook's (which are). - wxNotebookPage* pActive = GetPage(activateId); - wxNotebookPage* pDeactive = GetPage(deactivateId); - - int activatePos = m_notebook->FindPagePosition(pActive); - int deactivatePos = m_notebook->FindPagePosition(pDeactive); - - event.SetEventObject(m_notebook); - event.SetSelection(activatePos); - event.SetOldSelection(deactivatePos); - if (m_notebook->GetEventHandler()->ProcessEvent(event)) - { - retval = event.IsAllowed(); - } - } - return retval; -} - -#endif // wxUSE_NOTEBOOK +/////////////////////////////////////////////////////////////////////////////// +// Name: src/generic/notebook.cpp +// Purpose: generic implementation of wxNotebook +// Author: Julian Smart +// Modified by: +// Created: 17/09/98 +// RCS-ID: $Id: notebook.cpp 50855 2007-12-20 10:51:33Z JS $ +// Copyright: (c) Julian Smart +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_NOTEBOOK + +#include "wx/notebook.h" + +#ifndef WX_PRECOMP + #include "wx/string.h" + #include "wx/log.h" + #include "wx/dcclient.h" + #include "wx/settings.h" +#endif + +#include "wx/imaglist.h" +#include "wx/generic/tabg.h" + +// ---------------------------------------------------------------------------- +// macros +// ---------------------------------------------------------------------------- + +// check that the page index is valid +#define IS_VALID_PAGE(nPage) ((nPage) < GetPageCount()) + +// ---------------------------------------------------------------------------- +// event table +// ---------------------------------------------------------------------------- + +DEFINE_EVENT_TYPE(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGING) + +BEGIN_EVENT_TABLE(wxNotebook, wxBookCtrlBase) + EVT_NOTEBOOK_PAGE_CHANGED(wxID_ANY, wxNotebook::OnSelChange) + EVT_SIZE(wxNotebook::OnSize) + EVT_PAINT(wxNotebook::OnPaint) + EVT_MOUSE_EVENTS(wxNotebook::OnMouseEvent) + EVT_SET_FOCUS(wxNotebook::OnSetFocus) + EVT_NAVIGATION_KEY(wxNotebook::OnNavigationKey) +END_EVENT_TABLE() + +IMPLEMENT_DYNAMIC_CLASS(wxNotebook, wxBookCtrlBase) +IMPLEMENT_DYNAMIC_CLASS(wxNotebookEvent, wxCommandEvent) + +// ============================================================================ +// implementation +// ============================================================================ + +// ============================================================================ +// Private class +// ============================================================================ + +WX_DECLARE_HASH_MAP(int, wxNotebookPage*, wxIntegerHash, wxIntegerEqual, + wxIntToNotebookPageHashMap); + +WX_DECLARE_HASH_MAP(wxNotebookPage*, int, wxPointerHash, wxPointerEqual, + wxNotebookPageToIntHashMap); + +// This reuses wxTabView to draw the tabs. +class WXDLLEXPORT wxNotebookTabView: public wxTabView +{ +DECLARE_DYNAMIC_CLASS(wxNotebookTabView) +public: + wxNotebookTabView(wxNotebook* notebook, long style = wxTAB_STYLE_DRAW_BOX | wxTAB_STYLE_COLOUR_INTERIOR); + virtual ~wxNotebookTabView(void); + + // Called when a tab is activated + virtual void OnTabActivate(int activateId, int deactivateId); + // Allows vetoing + virtual bool OnTabPreActivate(int activateId, int deactivateId); + + // map integer ids used by wxTabView to wxNotebookPage pointers + int GetId(wxNotebookPage *page); + wxNotebookPage *GetPage(int id) { return m_idToPage[id]; } + +protected: + wxNotebook* m_notebook; + +private: + wxIntToNotebookPageHashMap m_idToPage; + wxNotebookPageToIntHashMap m_pageToId; + int m_nextid; +}; + +static int GetPageId(wxTabView *tabview, wxNotebookPage *page) +{ + return wx_static_cast(wxNotebookTabView*, tabview)->GetId(page); +} + +// ---------------------------------------------------------------------------- +// wxNotebook construction +// ---------------------------------------------------------------------------- + +// common part of all ctors +void wxNotebook::Init() +{ + m_tabView = (wxNotebookTabView*) NULL; + m_nSelection = -1; +} + +// default for dynamic class +wxNotebook::wxNotebook() +{ + Init(); +} + +// the same arguments as for wxControl +wxNotebook::wxNotebook(wxWindow *parent, + wxWindowID id, + const wxPoint& pos, + const wxSize& size, + long style, + const wxString& name) +{ + Init(); + + Create(parent, id, pos, size, style, name); +} + +// Create() function +bool wxNotebook::Create(wxWindow *parent, + wxWindowID id, + const wxPoint& pos, + const wxSize& size, + long style, + const wxString& name) +{ + // base init + SetName(name); + + if ( (style & wxBK_ALIGN_MASK) == wxBK_DEFAULT ) + style |= wxBK_TOP; + + m_windowId = id == wxID_ANY ? NewControlId() : id; + + if (!wxControl::Create(parent, id, pos, size, style|wxNO_BORDER, wxDefaultValidator, name)) + return false; + + SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE)); + + SetTabView(new wxNotebookTabView(this)); + + return true; +} + +// dtor +wxNotebook::~wxNotebook() +{ + delete m_tabView; +} + +// ---------------------------------------------------------------------------- +// wxNotebook accessors +// ---------------------------------------------------------------------------- +int wxNotebook::GetRowCount() const +{ + // TODO + return 0; +} + +int wxNotebook::SetSelection(size_t nPage) +{ + wxASSERT( IS_VALID_PAGE(nPage) ); + + wxNotebookPage* pPage = GetPage(nPage); + + m_tabView->SetTabSelection(GetPageId(m_tabView, pPage)); + + // TODO + return 0; +} + +int wxNotebook::ChangeSelection(size_t nPage) +{ + // FIXME: currently it does generate events too + return SetSelection(nPage); +} + +#if 0 +void wxNotebook::AdvanceSelection(bool bForward) +{ + int nSel = GetSelection(); + int nMax = GetPageCount() - 1; + if ( bForward ) + SetSelection(nSel == nMax ? 0 : nSel + 1); + else + SetSelection(nSel == 0 ? nMax : nSel - 1); +} +#endif + +bool wxNotebook::SetPageText(size_t nPage, const wxString& strText) +{ + wxASSERT( IS_VALID_PAGE(nPage) ); + + wxNotebookPage* page = GetPage(nPage); + if (page) + { + m_tabView->SetTabText(GetPageId(m_tabView, page), strText); + Refresh(); + return true; + } + + return false; +} + +wxString wxNotebook::GetPageText(size_t nPage) const +{ + wxASSERT( IS_VALID_PAGE(nPage) ); + + wxNotebookPage* page = ((wxNotebook*)this)->GetPage(nPage); + if (page) + return m_tabView->GetTabText(GetPageId(m_tabView, page)); + else + return wxEmptyString; +} + +int wxNotebook::GetPageImage(size_t WXUNUSED_UNLESS_DEBUG(nPage)) const +{ + wxASSERT( IS_VALID_PAGE(nPage) ); + + // TODO + return 0; +} + +bool wxNotebook::SetPageImage(size_t WXUNUSED_UNLESS_DEBUG(nPage), + int WXUNUSED(nImage)) +{ + wxASSERT( IS_VALID_PAGE(nPage) ); + + // TODO + return false; +} + +// set the size (the same for all pages) +void wxNotebook::SetPageSize(const wxSize& WXUNUSED(size)) +{ + // TODO +} + +// set the padding between tabs (in pixels) +void wxNotebook::SetPadding(const wxSize& WXUNUSED(padding)) +{ + // TODO +} + +// set the size of the tabs for wxNB_FIXEDWIDTH controls +void wxNotebook::SetTabSize(const wxSize& WXUNUSED(sz)) +{ + // TODO +} + +// ---------------------------------------------------------------------------- +// wxNotebook operations +// ---------------------------------------------------------------------------- + +// remove one page from the notebook and delete it +bool wxNotebook::DeletePage(size_t nPage) +{ + wxCHECK( IS_VALID_PAGE(nPage), false ); + + if (m_nSelection != -1) + { + m_pages[m_nSelection]->Show(false); + m_pages[m_nSelection]->Lower(); + } + + wxNotebookPage* pPage = GetPage(nPage); + + m_tabView->RemoveTab(GetPageId(m_tabView, pPage)); + + m_pages.Remove(pPage); + delete pPage; + + if (m_pages.GetCount() == 0) + { + m_nSelection = -1; + m_tabView->SetTabSelection(-1, false); + } + else if (m_nSelection > -1) + { + m_nSelection = -1; + + m_tabView->SetTabSelection(GetPageId(m_tabView, GetPage(0)), false); + + if (m_nSelection != 0) + ChangePage(-1, 0); + } + + RefreshLayout(false); + + return true; +} + +bool wxNotebook::DeletePage(wxNotebookPage* page) +{ + int pagePos = FindPagePosition(page); + if (pagePos > -1) + return DeletePage(pagePos); + else + return false; +} + +bool wxNotebook::RemovePage(size_t nPage) +{ + return DoRemovePage(nPage) != NULL; +} + +// remove one page from the notebook +wxWindow* wxNotebook::DoRemovePage(size_t nPage) +{ + wxCHECK( IS_VALID_PAGE(nPage), NULL ); + + m_pages[nPage]->Show(false); + // m_pages[nPage]->Lower(); + + wxNotebookPage* pPage = GetPage(nPage); + + m_tabView->RemoveTab(GetPageId(m_tabView, pPage)); + + m_pages.Remove(pPage); + + if (m_pages.GetCount() == 0) + { + m_nSelection = -1; + m_tabView->SetTabSelection(-1, true); + } + else if (m_nSelection > -1) + { + // Only change the selection if the page we + // deleted was the selection. + if (nPage == (size_t)m_nSelection) + { + m_nSelection = -1; + // Select the first tab. Generates a ChangePage. + m_tabView->SetTabSelection(0, true); + } + else + { + // We must adjust which tab we think is selected. + // If greater than the page we deleted, it must be moved down + // a notch. + if (size_t(m_nSelection) > nPage) + m_nSelection -- ; + } + } + + RefreshLayout(false); + + return pPage; +} + +bool wxNotebook::RemovePage(wxNotebookPage* page) +{ + int pagePos = FindPagePosition(page); + if (pagePos > -1) + return RemovePage(pagePos); + else + return false; +} + +// Find the position of the wxNotebookPage, -1 if not found. +int wxNotebook::FindPagePosition(wxNotebookPage* page) const +{ + size_t nPageCount = GetPageCount(); + size_t nPage; + for ( nPage = 0; nPage < nPageCount; nPage++ ) + if (m_pages[nPage] == page) + return nPage; + return -1; +} + +// remove all pages +bool wxNotebook::DeleteAllPages() +{ + m_tabView->ClearTabs(true); + + size_t nPageCount = GetPageCount(); + size_t nPage; + for ( nPage = 0; nPage < nPageCount; nPage++ ) + delete m_pages[nPage]; + + m_pages.Clear(); + + return true; +} + +// same as AddPage() but does it at given position +bool wxNotebook::InsertPage(size_t nPage, + wxNotebookPage *pPage, + const wxString& strText, + bool bSelect, + int WXUNUSED(imageId)) +{ + wxASSERT( pPage != NULL ); + wxCHECK( IS_VALID_PAGE(nPage) || nPage == GetPageCount(), false ); + + m_tabView->AddTab(GetPageId(m_tabView, pPage), strText); + + if (!bSelect) + pPage->Show(false); + + // save the pointer to the page + m_pages.Insert(pPage, nPage); + + if (bSelect) + { + // This will cause ChangePage to be called, via OnSelPage + + m_tabView->SetTabSelection(GetPageId(m_tabView, pPage), true); + } + + // some page must be selected: either this one or the first one if there is + // still no selection + if ( m_nSelection == -1 ) + ChangePage(-1, 0); + + RefreshLayout(false); + + return true; +} + +// ---------------------------------------------------------------------------- +// wxNotebook callbacks +// ---------------------------------------------------------------------------- + +// @@@ OnSize() is used for setting the font when it's called for the first +// time because doing it in ::Create() doesn't work (for unknown reasons) +void wxNotebook::OnSize(wxSizeEvent& event) +{ + static bool s_bFirstTime = true; + if ( s_bFirstTime ) { + // TODO: any first-time-size processing. + s_bFirstTime = false; + } + + RefreshLayout(); + + // Processing continues to next OnSize + event.Skip(); +} + +// This was supposed to cure the non-display of the notebook +// until the user resizes the window. +// What's going on? +void wxNotebook::OnInternalIdle() +{ + wxWindow::OnInternalIdle(); + +#if 0 + static bool s_bFirstTime = true; + if ( s_bFirstTime ) { + /* + wxSize sz(GetSize()); + sz.x ++; + SetSize(sz); + sz.x --; + SetSize(sz); + */ + + /* + wxSize sz(GetSize()); + wxSizeEvent sizeEvent(sz, GetId()); + sizeEvent.SetEventObject(this); + GetEventHandler()->ProcessEvent(sizeEvent); + Refresh(); + */ + s_bFirstTime = false; + } +#endif +} + +// Implementation: calculate the layout of the view rect +// and resize the children if required +bool wxNotebook::RefreshLayout(bool force) +{ + if (m_tabView) + { + wxRect oldRect = m_tabView->GetViewRect(); + + int cw, ch; + GetClientSize(& cw, & ch); + + int tabHeight = m_tabView->GetTotalTabHeight(); + wxRect rect; + rect.x = 4; + rect.y = tabHeight + 4; + rect.width = cw - 8; + rect.height = ch - 4 - rect.y ; + + m_tabView->SetViewRect(rect); + + m_tabView->LayoutTabs(); + + // Need to do it a 2nd time to get the tab height with + // the new view width, since changing the view width changes the + // tab layout. + tabHeight = m_tabView->GetTotalTabHeight(); + rect.x = 4; + rect.y = tabHeight + 4; + rect.width = cw - 8; + rect.height = ch - 4 - rect.y ; + + m_tabView->SetViewRect(rect); + + m_tabView->LayoutTabs(); + + if (!force && (rect == oldRect)) + return false; + + // fit the notebook page to the tab control's display area + + size_t nCount = m_pages.Count(); + for ( size_t nPage = 0; nPage < nCount; nPage++ ) { + wxNotebookPage *pPage = m_pages[nPage]; + wxRect clientRect = GetAvailableClientSize(); + if (pPage->IsShown()) + { + pPage->SetSize(clientRect.x, clientRect.y, clientRect.width, clientRect.height); + if ( pPage->GetAutoLayout() ) + pPage->Layout(); + } + } + Refresh(); + } + return true; +} + +void wxNotebook::OnSelChange(wxNotebookEvent& event) +{ + // is it our tab control? + if ( event.GetEventObject() == this ) + { + if (event.GetSelection() != m_nSelection) + ChangePage(event.GetOldSelection(), event.GetSelection()); + } + + // we want to give others a chance to process this message as well + event.Skip(); +} + +void wxNotebook::OnSetFocus(wxFocusEvent& event) +{ + // set focus to the currently selected page if any + if ( m_nSelection != -1 ) + m_pages[m_nSelection]->SetFocus(); + + event.Skip(); +} + +void wxNotebook::OnNavigationKey(wxNavigationKeyEvent& event) +{ + if ( event.IsWindowChange() ) { + // change pages + AdvanceSelection(event.GetDirection()); + } + else { + // pass to the parent + if ( GetParent() ) { + event.SetCurrentFocus(this); + GetParent()->ProcessEvent(event); + } + } +} + +// ---------------------------------------------------------------------------- +// wxNotebook base class virtuals +// ---------------------------------------------------------------------------- + +// override these 2 functions to do nothing: everything is done in OnSize + +void wxNotebook::SetConstraintSizes(bool /* recurse */) +{ + // don't set the sizes of the pages - their correct size is not yet known + wxControl::SetConstraintSizes(false); +} + +bool wxNotebook::DoPhase(int /* nPhase */) +{ + return true; +} + +void wxNotebook::Command(wxCommandEvent& WXUNUSED(event)) +{ + wxFAIL_MSG(wxT("wxNotebook::Command not implemented")); +} + +// ---------------------------------------------------------------------------- +// wxNotebook helper functions +// ---------------------------------------------------------------------------- + +// hide the currently active panel and show the new one +void wxNotebook::ChangePage(int nOldSel, int nSel) +{ + // cout << "ChangePage: " << nOldSel << ", " << nSel << "\n"; + wxASSERT( nOldSel != nSel ); // impossible + + if ( nOldSel != -1 ) { + m_pages[nOldSel]->Show(false); + m_pages[nOldSel]->Lower(); + } + + wxNotebookPage *pPage = m_pages[nSel]; + + wxRect clientRect = GetAvailableClientSize(); + pPage->SetSize(clientRect.x, clientRect.y, clientRect.width, clientRect.height); + + Refresh(); + + pPage->Show(true); + pPage->Raise(); + pPage->SetFocus(); + + m_nSelection = nSel; +} + +void wxNotebook::OnMouseEvent(wxMouseEvent& event) +{ + if (m_tabView) + m_tabView->OnEvent(event); +} + +void wxNotebook::OnPaint(wxPaintEvent& WXUNUSED(event) ) +{ + wxPaintDC dc(this); + if (m_tabView) + m_tabView->Draw(dc); +} + +wxSize wxNotebook::CalcSizeFromPage(const wxSize& sizePage) const +{ + // MBN: since the total tab height is really a function of the + // width, this should really call + // GetTotalTabHeightPretendingWidthIs(), but the current + // implementation will suffice, provided the wxNotebook has been + // created with a sensible initial width. + return wxSize( sizePage.x + 12, + sizePage.y + m_tabView->GetTotalTabHeight() + 6 + 4 ); +} + +wxRect wxNotebook::GetAvailableClientSize() +{ + int cw, ch; + GetClientSize(& cw, & ch); + + int tabHeight = m_tabView->GetTotalTabHeight(); + + // TODO: these margins should be configurable. + wxRect rect; + rect.x = 6; + rect.y = tabHeight + 6; + rect.width = cw - 12; + rect.height = ch - 4 - rect.y ; + + return rect; +} + +/* + * wxNotebookTabView + */ + +IMPLEMENT_CLASS(wxNotebookTabView, wxTabView) + +wxNotebookTabView::wxNotebookTabView(wxNotebook *notebook, long style) + : wxTabView(style), m_nextid(1) +{ + m_notebook = notebook; + + m_notebook->SetTabView(this); + + SetWindow(m_notebook); +} + +wxNotebookTabView::~wxNotebookTabView(void) +{ +} + +int wxNotebookTabView::GetId(wxNotebookPage *page) +{ + int& id = m_pageToId[page]; + + if (!id) + { + id = m_nextid++; + m_idToPage[id] = page; + } + + return id; +} + +// Called when a tab is activated +void wxNotebookTabView::OnTabActivate(int activateId, int deactivateId) +{ + if (!m_notebook) + return; + + wxNotebookEvent event(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED, m_notebook->GetId()); + + // Translate from wxTabView's ids (which aren't position-dependent) + // to wxNotebook's (which are). + wxNotebookPage* pActive = GetPage(activateId); + wxNotebookPage* pDeactive = GetPage(deactivateId); + + int activatePos = m_notebook->FindPagePosition(pActive); + int deactivatePos = m_notebook->FindPagePosition(pDeactive); + + event.SetEventObject(m_notebook); + event.SetSelection(activatePos); + event.SetOldSelection(deactivatePos); + m_notebook->GetEventHandler()->ProcessEvent(event); +} + +// Allows Vetoing +bool wxNotebookTabView::OnTabPreActivate(int activateId, int deactivateId) +{ + bool retval = true; + + if (m_notebook) + { + wxNotebookEvent event(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGING, m_notebook->GetId()); + + // Translate from wxTabView's ids (which aren't position-dependent) + // to wxNotebook's (which are). + wxNotebookPage* pActive = GetPage(activateId); + wxNotebookPage* pDeactive = GetPage(deactivateId); + + int activatePos = m_notebook->FindPagePosition(pActive); + int deactivatePos = m_notebook->FindPagePosition(pDeactive); + + event.SetEventObject(m_notebook); + event.SetSelection(activatePos); + event.SetOldSelection(deactivatePos); + if (m_notebook->GetEventHandler()->ProcessEvent(event)) + { + retval = event.IsAllowed(); + } + } + return retval; +} + +#endif // wxUSE_NOTEBOOK diff --git a/Externals/wxWidgets/src/generic/numdlgg.cpp b/Externals/wxWidgets/src/generic/numdlgg.cpp index 0317bc0e69..9a2b7dcfc2 100644 --- a/Externals/wxWidgets/src/generic/numdlgg.cpp +++ b/Externals/wxWidgets/src/generic/numdlgg.cpp @@ -1,184 +1,184 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/generic/numdlgg.cpp -// Purpose: wxGetNumberFromUser implementation -// Author: Vadim Zeitlin -// Modified by: -// Created: 23.07.99 -// RCS-ID: $Id: numdlgg.cpp 41838 2006-10-09 21:08:45Z VZ $ -// Copyright: (c) Vadim Zeitlin -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_NUMBERDLG - -#ifndef WX_PRECOMP - #include - - #include "wx/utils.h" - #include "wx/dialog.h" - #include "wx/button.h" - #include "wx/stattext.h" - #include "wx/textctrl.h" - #include "wx/intl.h" - #include "wx/sizer.h" -#endif - -#if wxUSE_STATLINE - #include "wx/statline.h" -#endif - -#if wxUSE_SPINCTRL -#include "wx/spinctrl.h" -#endif - -// this is where wxGetNumberFromUser() is declared -#include "wx/numdlg.h" - -#if !wxUSE_SPINCTRL - // wxTextCtrl will do instead of wxSpinCtrl if we don't have it - #define wxSpinCtrl wxTextCtrl -#endif - -// ============================================================================ -// implementation -// ============================================================================ - -// ---------------------------------------------------------------------------- -// wxNumberEntryDialog -// ---------------------------------------------------------------------------- - -BEGIN_EVENT_TABLE(wxNumberEntryDialog, wxDialog) - EVT_BUTTON(wxID_OK, wxNumberEntryDialog::OnOK) - EVT_BUTTON(wxID_CANCEL, wxNumberEntryDialog::OnCancel) -END_EVENT_TABLE() - -IMPLEMENT_CLASS(wxNumberEntryDialog, wxDialog) - -wxNumberEntryDialog::wxNumberEntryDialog(wxWindow *parent, - const wxString& message, - const wxString& prompt, - const wxString& caption, - long value, - long min, - long max, - const wxPoint& pos) - : wxDialog(parent, wxID_ANY, caption, - pos, wxDefaultSize) -{ - m_value = value; - m_max = max; - m_min = min; - - wxBeginBusyCursor(); - - wxBoxSizer *topsizer = new wxBoxSizer( wxVERTICAL ); -#if wxUSE_STATTEXT - // 1) text message - topsizer->Add( CreateTextSizer( message ), 0, wxALL, 10 ); -#endif - - // 2) prompt and text ctrl - wxBoxSizer *inputsizer = new wxBoxSizer( wxHORIZONTAL ); - -#if wxUSE_STATTEXT - // prompt if any - if (!prompt.empty()) - inputsizer->Add( new wxStaticText( this, wxID_ANY, prompt ), 0, wxCENTER | wxLEFT, 10 ); -#endif - - // spin ctrl - wxString valStr; - valStr.Printf(wxT("%ld"), m_value); - m_spinctrl = new wxSpinCtrl(this, wxID_ANY, valStr, wxDefaultPosition, wxSize( 140, wxDefaultCoord ) ); -#if wxUSE_SPINCTRL - m_spinctrl->SetRange((int)m_min, (int)m_max); -#endif - inputsizer->Add( m_spinctrl, 1, wxCENTER | wxLEFT | wxRIGHT, 10 ); - // add both - topsizer->Add( inputsizer, 0, wxEXPAND | wxLEFT|wxRIGHT, 5 ); - - // 3) buttons if any - wxSizer *buttonSizer = CreateSeparatedButtonSizer(wxOK | wxCANCEL); - if ( buttonSizer ) - { - topsizer->Add(buttonSizer, wxSizerFlags().Expand().DoubleBorder()); - } - - SetSizer( topsizer ); - SetAutoLayout( true ); - - topsizer->SetSizeHints( this ); - topsizer->Fit( this ); - - Centre( wxBOTH ); - - m_spinctrl->SetSelection(-1, -1); - m_spinctrl->SetFocus(); - - wxEndBusyCursor(); -} - -void wxNumberEntryDialog::OnOK(wxCommandEvent& WXUNUSED(event)) -{ -#if !wxUSE_SPINCTRL - wxString tmp = m_spinctrl->GetValue(); - if ( wxSscanf(tmp, _T("%ld"), &m_value) != 1 ) - EndModal(wxID_CANCEL); - else -#else - m_value = m_spinctrl->GetValue(); -#endif - if ( m_value < m_min || m_value > m_max ) - { - // not a number or out of range - m_value = -1; - EndModal(wxID_CANCEL); - } - - EndModal(wxID_OK); -} - -void wxNumberEntryDialog::OnCancel(wxCommandEvent& WXUNUSED(event)) -{ - EndModal(wxID_CANCEL); -} - -// ---------------------------------------------------------------------------- -// global functions -// ---------------------------------------------------------------------------- - -// wxGetTextFromUser is in utilscmn.cpp - -long wxGetNumberFromUser(const wxString& msg, - const wxString& prompt, - const wxString& title, - long value, - long min, - long max, - wxWindow *parent, - const wxPoint& pos) -{ - wxNumberEntryDialog dialog(parent, msg, prompt, title, - value, min, max, pos); - if (dialog.ShowModal() == wxID_OK) - return dialog.GetValue(); - - return -1; -} - -#endif // wxUSE_NUMBERDLG +///////////////////////////////////////////////////////////////////////////// +// Name: src/generic/numdlgg.cpp +// Purpose: wxGetNumberFromUser implementation +// Author: Vadim Zeitlin +// Modified by: +// Created: 23.07.99 +// RCS-ID: $Id: numdlgg.cpp 41838 2006-10-09 21:08:45Z VZ $ +// Copyright: (c) Vadim Zeitlin +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_NUMBERDLG + +#ifndef WX_PRECOMP + #include + + #include "wx/utils.h" + #include "wx/dialog.h" + #include "wx/button.h" + #include "wx/stattext.h" + #include "wx/textctrl.h" + #include "wx/intl.h" + #include "wx/sizer.h" +#endif + +#if wxUSE_STATLINE + #include "wx/statline.h" +#endif + +#if wxUSE_SPINCTRL +#include "wx/spinctrl.h" +#endif + +// this is where wxGetNumberFromUser() is declared +#include "wx/numdlg.h" + +#if !wxUSE_SPINCTRL + // wxTextCtrl will do instead of wxSpinCtrl if we don't have it + #define wxSpinCtrl wxTextCtrl +#endif + +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// wxNumberEntryDialog +// ---------------------------------------------------------------------------- + +BEGIN_EVENT_TABLE(wxNumberEntryDialog, wxDialog) + EVT_BUTTON(wxID_OK, wxNumberEntryDialog::OnOK) + EVT_BUTTON(wxID_CANCEL, wxNumberEntryDialog::OnCancel) +END_EVENT_TABLE() + +IMPLEMENT_CLASS(wxNumberEntryDialog, wxDialog) + +wxNumberEntryDialog::wxNumberEntryDialog(wxWindow *parent, + const wxString& message, + const wxString& prompt, + const wxString& caption, + long value, + long min, + long max, + const wxPoint& pos) + : wxDialog(parent, wxID_ANY, caption, + pos, wxDefaultSize) +{ + m_value = value; + m_max = max; + m_min = min; + + wxBeginBusyCursor(); + + wxBoxSizer *topsizer = new wxBoxSizer( wxVERTICAL ); +#if wxUSE_STATTEXT + // 1) text message + topsizer->Add( CreateTextSizer( message ), 0, wxALL, 10 ); +#endif + + // 2) prompt and text ctrl + wxBoxSizer *inputsizer = new wxBoxSizer( wxHORIZONTAL ); + +#if wxUSE_STATTEXT + // prompt if any + if (!prompt.empty()) + inputsizer->Add( new wxStaticText( this, wxID_ANY, prompt ), 0, wxCENTER | wxLEFT, 10 ); +#endif + + // spin ctrl + wxString valStr; + valStr.Printf(wxT("%ld"), m_value); + m_spinctrl = new wxSpinCtrl(this, wxID_ANY, valStr, wxDefaultPosition, wxSize( 140, wxDefaultCoord ) ); +#if wxUSE_SPINCTRL + m_spinctrl->SetRange((int)m_min, (int)m_max); +#endif + inputsizer->Add( m_spinctrl, 1, wxCENTER | wxLEFT | wxRIGHT, 10 ); + // add both + topsizer->Add( inputsizer, 0, wxEXPAND | wxLEFT|wxRIGHT, 5 ); + + // 3) buttons if any + wxSizer *buttonSizer = CreateSeparatedButtonSizer(wxOK | wxCANCEL); + if ( buttonSizer ) + { + topsizer->Add(buttonSizer, wxSizerFlags().Expand().DoubleBorder()); + } + + SetSizer( topsizer ); + SetAutoLayout( true ); + + topsizer->SetSizeHints( this ); + topsizer->Fit( this ); + + Centre( wxBOTH ); + + m_spinctrl->SetSelection(-1, -1); + m_spinctrl->SetFocus(); + + wxEndBusyCursor(); +} + +void wxNumberEntryDialog::OnOK(wxCommandEvent& WXUNUSED(event)) +{ +#if !wxUSE_SPINCTRL + wxString tmp = m_spinctrl->GetValue(); + if ( wxSscanf(tmp, _T("%ld"), &m_value) != 1 ) + EndModal(wxID_CANCEL); + else +#else + m_value = m_spinctrl->GetValue(); +#endif + if ( m_value < m_min || m_value > m_max ) + { + // not a number or out of range + m_value = -1; + EndModal(wxID_CANCEL); + } + + EndModal(wxID_OK); +} + +void wxNumberEntryDialog::OnCancel(wxCommandEvent& WXUNUSED(event)) +{ + EndModal(wxID_CANCEL); +} + +// ---------------------------------------------------------------------------- +// global functions +// ---------------------------------------------------------------------------- + +// wxGetTextFromUser is in utilscmn.cpp + +long wxGetNumberFromUser(const wxString& msg, + const wxString& prompt, + const wxString& title, + long value, + long min, + long max, + wxWindow *parent, + const wxPoint& pos) +{ + wxNumberEntryDialog dialog(parent, msg, prompt, title, + value, min, max, pos); + if (dialog.ShowModal() == wxID_OK) + return dialog.GetValue(); + + return -1; +} + +#endif // wxUSE_NUMBERDLG diff --git a/Externals/wxWidgets/src/generic/odcombo.cpp b/Externals/wxWidgets/src/generic/odcombo.cpp index 584695949d..0d0daf8da3 100644 --- a/Externals/wxWidgets/src/generic/odcombo.cpp +++ b/Externals/wxWidgets/src/generic/odcombo.cpp @@ -1,1101 +1,1101 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/generic/odcombo.cpp -// Purpose: wxOwnerDrawnComboBox, wxVListBoxComboPopup -// Author: Jaakko Salli -// Modified by: -// Created: Apr-30-2006 -// RCS-ID: $Id: odcombo.cpp 52747 2008-03-23 20:20:46Z VZ $ -// Copyright: (c) 2005 Jaakko Salli -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_ODCOMBOBOX - -#include "wx/odcombo.h" - -#ifndef WX_PRECOMP - #include "wx/log.h" - #include "wx/combobox.h" - #include "wx/dcclient.h" - #include "wx/settings.h" - #include "wx/dialog.h" -#endif - -#include "wx/combo.h" - -// ============================================================================ -// implementation -// ============================================================================ - -// time in milliseconds before partial completion buffer drops -#define wxODCB_PARTIAL_COMPLETION_TIME 1000 - -// ---------------------------------------------------------------------------- -// wxVListBoxComboPopup is a wxVListBox customized to act as a popup control -// -// ---------------------------------------------------------------------------- - - -BEGIN_EVENT_TABLE(wxVListBoxComboPopup, wxVListBox) - EVT_MOTION(wxVListBoxComboPopup::OnMouseMove) - EVT_KEY_DOWN(wxVListBoxComboPopup::OnKey) - EVT_LEFT_UP(wxVListBoxComboPopup::OnLeftClick) -END_EVENT_TABLE() - - -void wxVListBoxComboPopup::Init() -{ - m_widestWidth = 0; - m_widestItem = -1; - m_widthsDirty = false; - m_findWidest = false; - m_itemHeight = 0; - m_value = -1; - m_itemHover = -1; - m_clientDataItemsType = wxClientData_None; - m_partialCompletionString = wxEmptyString; -} - -bool wxVListBoxComboPopup::Create(wxWindow* parent) -{ - if ( !wxVListBox::Create(parent, - wxID_ANY, - wxDefaultPosition, - wxDefaultSize, - wxBORDER_SIMPLE | wxLB_INT_HEIGHT | wxWANTS_CHARS) ) - return false; - - m_useFont = m_combo->GetFont(); - - wxVListBox::SetItemCount(m_strings.GetCount()); - - // TODO: Move this to SetFont - m_itemHeight = GetCharHeight() + 0; - - return true; -} - -wxVListBoxComboPopup::~wxVListBoxComboPopup() -{ - Clear(); -} - -bool wxVListBoxComboPopup::LazyCreate() -{ - // NB: There is a bug with wxVListBox that can be avoided by creating - // it later (bug causes empty space to be shown if initial selection - // is at the end of a list longer than the control can show at once). - return true; -} - -// paint the control itself -void wxVListBoxComboPopup::PaintComboControl( wxDC& dc, const wxRect& rect ) -{ - if ( !(m_combo->GetWindowStyle() & wxODCB_STD_CONTROL_PAINT) ) - { - int flags = wxODCB_PAINTING_CONTROL; - - if ( m_combo->ShouldDrawFocus() ) - flags |= wxODCB_PAINTING_SELECTED; - - OnDrawBg(dc, rect, m_value, flags); - - if ( m_value >= 0 ) - { - OnDrawItem(dc,rect,m_value,flags); - return; - } - } - - wxComboPopup::PaintComboControl(dc,rect); -} - -void wxVListBoxComboPopup::OnDrawItem(wxDC& dc, const wxRect& rect, size_t n) const -{ - // TODO: Maybe this code could be moved to wxVListBox::OnPaint? - dc.SetFont(m_useFont); - - int flags = 0; - - // Set correct text colour for selected items - if ( wxVListBox::GetSelection() == (int) n ) - { - dc.SetTextForeground( wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT) ); - flags |= wxODCB_PAINTING_SELECTED; - } - else - { - dc.SetTextForeground( wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT) ); - } - - OnDrawItem(dc,rect,(int)n,flags); -} - -wxCoord wxVListBoxComboPopup::OnMeasureItem(size_t n) const -{ - wxOwnerDrawnComboBox* combo = (wxOwnerDrawnComboBox*) m_combo; - - wxASSERT_MSG( combo->IsKindOf(CLASSINFO(wxOwnerDrawnComboBox)), - wxT("you must subclass wxVListBoxComboPopup for drawing and measuring methods") ); - - wxCoord h = combo->OnMeasureItem(n); - if ( h < 0 ) - h = m_itemHeight; - return h; -} - -wxCoord wxVListBoxComboPopup::OnMeasureItemWidth(size_t n) const -{ - wxOwnerDrawnComboBox* combo = (wxOwnerDrawnComboBox*) m_combo; - - wxASSERT_MSG( combo->IsKindOf(CLASSINFO(wxOwnerDrawnComboBox)), - wxT("you must subclass wxVListBoxComboPopup for drawing and measuring methods") ); - - return combo->OnMeasureItemWidth(n); -} - -void wxVListBoxComboPopup::OnDrawBg( wxDC& dc, - const wxRect& rect, - int item, - int flags ) const -{ - wxOwnerDrawnComboBox* combo = (wxOwnerDrawnComboBox*) m_combo; - - wxASSERT_MSG( combo->IsKindOf(CLASSINFO(wxOwnerDrawnComboBox)), - wxT("you must subclass wxVListBoxComboPopup for drawing and measuring methods") ); - - if ( IsCurrent((size_t)item) && !(flags & wxODCB_PAINTING_CONTROL) ) - flags |= wxODCB_PAINTING_SELECTED; - - combo->OnDrawBackground(dc,rect,item,flags); -} - -void wxVListBoxComboPopup::OnDrawBackground(wxDC& dc, const wxRect& rect, size_t n) const -{ - OnDrawBg(dc,rect,(int)n,0); -} - -// This is called from wxVListBoxComboPopup::OnDrawItem, with text colour and font prepared -void wxVListBoxComboPopup::OnDrawItem( wxDC& dc, const wxRect& rect, int item, int flags ) const -{ - wxOwnerDrawnComboBox* combo = (wxOwnerDrawnComboBox*) m_combo; - - wxASSERT_MSG( combo->IsKindOf(CLASSINFO(wxOwnerDrawnComboBox)), - wxT("you must subclass wxVListBoxComboPopup for drawing and measuring methods") ); - - combo->OnDrawItem(dc,rect,item,flags); -} - -void wxVListBoxComboPopup::DismissWithEvent() -{ - StopPartialCompletion(); - - int selection = wxVListBox::GetSelection(); - - Dismiss(); - - wxString valStr; - if ( selection != wxNOT_FOUND ) - valStr = m_strings[selection]; - else - valStr = wxEmptyString; - - m_value = selection; - - if ( valStr != m_combo->GetValue() ) - m_combo->SetValueWithEvent(valStr); - - SendComboBoxEvent(selection); -} - -void wxVListBoxComboPopup::SendComboBoxEvent( int selection ) -{ - wxCommandEvent evt(wxEVT_COMMAND_COMBOBOX_SELECTED,m_combo->GetId()); - - evt.SetEventObject(m_combo); - - evt.SetInt(selection); - - // Set client data, if any - if ( selection >= 0 && (int)m_clientDatas.GetCount() > selection ) - { - void* clientData = m_clientDatas[selection]; - if ( m_clientDataItemsType == wxClientData_Object ) - evt.SetClientObject((wxClientData*)clientData); - else - evt.SetClientData(clientData); - } - - m_combo->GetEventHandler()->AddPendingEvent(evt); -} - -// returns true if key was consumed -bool wxVListBoxComboPopup::HandleKey( int keycode, bool saturate, wxChar unicode ) -{ - const int itemCount = GetCount(); - - // keys do nothing in the empty control and returning immediately avoids - // using invalid indices below - if ( !itemCount ) - return false; - - int value = m_value; - int comboStyle = m_combo->GetWindowStyle(); - - // this is the character equivalent of the code - wxChar keychar=0; - if ((keycode >= WXK_SPACE) && (keycode <=255) && (keycode != WXK_DELETE) && wxIsprint(keycode)) - { - keychar = (wxChar)keycode; - } - else if (unicode>0) - { - keychar = unicode; - } - - if ( keycode == WXK_DOWN || keycode == WXK_RIGHT ) - { - value++; - StopPartialCompletion(); - } - else if ( keycode == WXK_UP || keycode == WXK_LEFT ) - { - value--; - StopPartialCompletion(); - } - else if ( keycode == WXK_PAGEDOWN ) - { - value+=10; - StopPartialCompletion(); - } - else if ( keycode == WXK_PAGEUP ) - { - value-=10; - StopPartialCompletion(); - } - else if ( comboStyle & wxCB_READONLY ) - { - // Try partial completion - - // find the new partial completion string -#if wxUSE_TIMER - if (m_partialCompletionTimer.IsRunning()) - m_partialCompletionString+=wxString(keychar); - else -#endif // wxUSE_TIMER - m_partialCompletionString=wxString(keychar); - - // now search through the values to see if this is found - int found = -1; - unsigned int length=m_partialCompletionString.length(); - int i; - for (i=0; i= length) && (! m_partialCompletionString.CmpNoCase(item.Left(length)))) - { - found=i; - break; - } - } - - if (found<0) - { - StopPartialCompletion(); - ::wxBell(); - return true; // to stop the first value being set - } - else - { - value=i; -#if wxUSE_TIMER - m_partialCompletionTimer.Start(wxODCB_PARTIAL_COMPLETION_TIME, true); -#endif // wxUSE_TIMER - } - } - else - return false; - - if ( saturate ) - { - if ( value >= itemCount ) - value = itemCount - 1; - else if ( value < 0 ) - value = 0; - } - else - { - if ( value >= itemCount ) - value -= itemCount; - else if ( value < 0 ) - value += itemCount; - } - - if ( value == m_value ) - // Even if value was same, don't skip the event - // (good for consistency) - return true; - - m_value = value; - - if ( value >= 0 ) - m_combo->SetValue(m_strings[value]); - - SendComboBoxEvent(m_value); - - return true; -} - -// stop partial completion -void wxVListBoxComboPopup::StopPartialCompletion() -{ - m_partialCompletionString = wxEmptyString; -#if wxUSE_TIMER - m_partialCompletionTimer.Stop(); -#endif // wxUSE_TIMER -} - -void wxVListBoxComboPopup::OnComboDoubleClick() -{ - // Cycle on dclick (disable saturation to allow true cycling). - if ( !::wxGetKeyState(WXK_SHIFT) ) - HandleKey(WXK_DOWN,false); - else - HandleKey(WXK_UP,false); -} - -void wxVListBoxComboPopup::OnComboKeyEvent( wxKeyEvent& event ) -{ - // Saturated key movement on - if ( !HandleKey(event.GetKeyCode(),true, -#if wxUSE_UNICODE - event.GetUnicodeKey() -#else - 0 -#endif - ) ) - event.Skip(); -} - -void wxVListBoxComboPopup::OnPopup() -{ - // *must* set value after size is set (this is because of a vlbox bug) - wxVListBox::SetSelection(m_value); -} - -void wxVListBoxComboPopup::OnMouseMove(wxMouseEvent& event) -{ - event.Skip(); - - // Move selection to cursor if it is inside the popup - - int y = event.GetPosition().y; - int fromBottom = GetClientSize().y - y; - - // Since in any case we need to find out if the last item is only - // partially visible, we might just as well replicate the HitTest - // loop here. - const size_t lineMax = GetVisibleEnd(); - for ( size_t line = GetVisibleBegin(); line < lineMax; line++ ) - { - y -= OnGetLineHeight(line); - if ( y < 0 ) - { - // Only change selection if item is fully visible - if ( (y + fromBottom) >= 0 ) - { - wxVListBox::SetSelection((int)line); - return; - } - } - } -} - -void wxVListBoxComboPopup::OnLeftClick(wxMouseEvent& WXUNUSED(event)) -{ - DismissWithEvent(); -} - -void wxVListBoxComboPopup::OnKey(wxKeyEvent& event) -{ - // Hide popup if certain key or key combination was pressed - if ( m_combo->IsKeyPopupToggle(event) ) - { - StopPartialCompletion(); - Dismiss(); - } - else if ( event.AltDown() ) - { - // On both wxGTK and wxMSW, pressing Alt down seems to - // completely freeze things in popup (ie. arrow keys and - // enter won't work). - return; - } - // Select item if ENTER is pressed - else if ( event.GetKeyCode() == WXK_RETURN || event.GetKeyCode() == WXK_NUMPAD_ENTER ) - { - DismissWithEvent(); - } - else - { - int comboStyle = m_combo->GetWindowStyle(); - int keycode = event.GetKeyCode(); - // Process partial completion key codes here, but not the arrow keys as the base class will do that for us - if ((comboStyle & wxCB_READONLY) && - (keycode >= WXK_SPACE) && (keycode <=255) && (keycode != WXK_DELETE) && wxIsprint(keycode)) - { - OnComboKeyEvent(event); - SetSelection(m_value); // ensure the highlight bar moves - } - else - event.Skip(); - } -} - -void wxVListBoxComboPopup::Insert( const wxString& item, int pos ) -{ - // Need to change selection? - wxString strValue; - if ( !(m_combo->GetWindowStyle() & wxCB_READONLY) && - m_combo->GetValue() == item ) - { - m_value = pos; - } - - m_strings.Insert(item,pos); - m_widths.Insert(-1,pos); - m_widthsDirty = true; - - if ( IsCreated() ) - wxVListBox::SetItemCount( wxVListBox::GetItemCount()+1 ); -} - -int wxVListBoxComboPopup::Append(const wxString& item) -{ - int pos = (int)m_strings.GetCount(); - - if ( m_combo->GetWindowStyle() & wxCB_SORT ) - { - // Find position - // TODO: Could be optimized with binary search - wxArrayString strings = m_strings; - unsigned int i; - - for ( i=0; i n ) - return m_clientDatas[n]; - - return NULL; -} - -void wxVListBoxComboPopup::Delete( unsigned int item ) -{ - // Remove client data, if set - if ( m_clientDatas.GetCount() ) - { - if ( m_clientDataItemsType == wxClientData_Object ) - delete (wxClientData*) m_clientDatas[item]; - - m_clientDatas.RemoveAt(item); - } - - m_strings.RemoveAt(item); - m_widths.RemoveAt(item); - - if ( (int)item == m_widestItem ) - m_findWidest = true; - - int sel = GetSelection(); - - if ( IsCreated() ) - wxVListBox::SetItemCount( wxVListBox::GetItemCount()-1 ); - - // Fix selection - if ( (int)item < sel ) - SetSelection(sel-1); - else if ( (int)item == sel ) - SetSelection(wxNOT_FOUND); -} - -int wxVListBoxComboPopup::FindString(const wxString& s, bool bCase) const -{ - return m_strings.Index(s, bCase); -} - -unsigned int wxVListBoxComboPopup::GetCount() const -{ - return m_strings.GetCount(); -} - -wxString wxVListBoxComboPopup::GetString( int item ) const -{ - return m_strings[item]; -} - -void wxVListBoxComboPopup::SetString( int item, const wxString& str ) -{ - m_strings[item] = str; - ItemWidthChanged(item); -} - -wxString wxVListBoxComboPopup::GetStringValue() const -{ - if ( m_value >= 0 ) - return m_strings[m_value]; - return wxEmptyString; -} - -void wxVListBoxComboPopup::SetSelection( int item ) -{ - wxCHECK_RET( item == wxNOT_FOUND || ((unsigned int)item < GetCount()), - wxT("invalid index in wxVListBoxComboPopup::SetSelection") ); - - m_value = item; - - if ( IsCreated() ) - wxVListBox::SetSelection(item); -} - -int wxVListBoxComboPopup::GetSelection() const -{ - return m_value; -} - -void wxVListBoxComboPopup::SetStringValue( const wxString& value ) -{ - int index = m_strings.Index(value); - - if ( index >= 0 && index < (int)wxVListBox::GetItemCount() ) - { - m_value = index; - wxVListBox::SetSelection(index); - } -} - -void wxVListBoxComboPopup::CalcWidths() -{ - bool doFindWidest = m_findWidest; - - // Measure items with dirty width. - if ( m_widthsDirty ) - { - unsigned int i; - unsigned int n = m_widths.GetCount(); - int dirtyHandled = 0; - wxArrayInt& widths = m_widths; - - // I think using wxDC::GetTextExtent is faster than - // wxWindow::GetTextExtent (assuming same dc is used - // for all calls, as we do here). - wxClientDC dc(m_combo); - dc.SetFont(m_useFont); - - for ( i=0; i= m_widestWidth ) - { - m_widestWidth = x; - m_widestItem = (int)i; - } - else if ( (int)i == m_widestItem ) - { - // Width of previously widest item has been decreased, so - // we'll have to check all to find current widest item. - doFindWidest = true; - } - - dirtyHandled++; - } - } - - m_widthsDirty = false; - } - - if ( doFindWidest ) - { - unsigned int i; - unsigned int n = m_widths.GetCount(); - - int bestWidth = -1; - int bestIndex = -1; - - for ( i=0; i bestWidth ) - { - bestIndex = (int)i; - bestWidth = w; - } - } - - m_widestWidth = bestWidth; - m_widestItem = bestIndex; - - m_findWidest = false; - } -} - -wxSize wxVListBoxComboPopup::GetAdjustedSize( int minWidth, int prefHeight, int maxHeight ) -{ - int height = 250; - - maxHeight -= 2; // Must take borders into account - - if ( m_strings.GetCount() ) - { - if ( prefHeight > 0 ) - height = prefHeight; - - if ( height > maxHeight ) - height = maxHeight; - - int totalHeight = GetTotalHeight(); // + 3; - if ( height >= totalHeight ) - { - height = totalHeight; - } - else - { - // Adjust height to a multiple of the height of the first item - // NB: Calculations that take variable height into account - // are unnecessary. - int fih = GetLineHeight(0); - height -= height % fih; - } - } - else - height = 50; - - CalcWidths(); - - // Take scrollbar into account in width calculations - int widestWidth = m_widestWidth + wxSystemSettings::GetMetric(wxSYS_VSCROLL_X); - return wxSize(minWidth > widestWidth ? minWidth : widestWidth, - height+2); -} - -//void wxVListBoxComboPopup::Populate( int n, const wxString choices[] ) -void wxVListBoxComboPopup::Populate( const wxArrayString& choices ) -{ - int i; - - int n = choices.GetCount(); - - for ( i=0; iGetWindowStyle() & wxCB_SORT ) - m_strings.Sort(); - - // Find initial selection - wxString strValue = m_combo->GetValue(); - if ( strValue.length() ) - m_value = m_strings.Index(strValue); -} - -// ---------------------------------------------------------------------------- -// wxOwnerDrawnComboBox -// ---------------------------------------------------------------------------- - - -BEGIN_EVENT_TABLE(wxOwnerDrawnComboBox, wxComboCtrl) -END_EVENT_TABLE() - - -IMPLEMENT_DYNAMIC_CLASS2(wxOwnerDrawnComboBox, wxComboCtrl, wxControlWithItems) - -void wxOwnerDrawnComboBox::Init() -{ -} - -bool wxOwnerDrawnComboBox::Create(wxWindow *parent, - wxWindowID id, - const wxString& value, - const wxPoint& pos, - const wxSize& size, - long style, - const wxValidator& validator, - const wxString& name) -{ - return wxComboCtrl::Create(parent,id,value,pos,size,style,validator,name); -} - -wxOwnerDrawnComboBox::wxOwnerDrawnComboBox(wxWindow *parent, - wxWindowID id, - const wxString& value, - const wxPoint& pos, - const wxSize& size, - const wxArrayString& choices, - long style, - const wxValidator& validator, - const wxString& name) - : wxComboCtrl() -{ - Init(); - - Create(parent,id,value,pos,size,choices,style, validator, name); -} - -bool wxOwnerDrawnComboBox::Create(wxWindow *parent, - wxWindowID id, - const wxString& value, - const wxPoint& pos, - const wxSize& size, - const wxArrayString& choices, - long style, - const wxValidator& validator, - const wxString& name) -{ - m_initChs = choices; - //wxCArrayString chs(choices); - - //return Create(parent, id, value, pos, size, chs.GetCount(), - // chs.GetStrings(), style, validator, name); - return Create(parent, id, value, pos, size, 0, - NULL, style, validator, name); -} - -bool wxOwnerDrawnComboBox::Create(wxWindow *parent, - wxWindowID id, - const wxString& value, - const wxPoint& pos, - const wxSize& size, - int n, - const wxString choices[], - long style, - const wxValidator& validator, - const wxString& name) -{ - - if ( !Create(parent, id, value, pos, size, style, - validator, name) ) - { - return false; - } - - int i; - for ( i=0; iClearClientDatas(); -} - -void wxOwnerDrawnComboBox::DoSetPopupControl(wxComboPopup* popup) -{ - if ( !popup ) - { - popup = new wxVListBoxComboPopup(); - } - - wxComboCtrl::DoSetPopupControl(popup); - - wxASSERT(popup); - - // Add initial choices to the wxVListBox - if ( !GetVListBoxComboPopup()->GetCount() ) - { - GetVListBoxComboPopup()->Populate(m_initChs); - m_initChs.Clear(); - } -} - -// ---------------------------------------------------------------------------- -// wxOwnerDrawnComboBox item manipulation methods -// ---------------------------------------------------------------------------- - -void wxOwnerDrawnComboBox::Clear() -{ - EnsurePopupControl(); - - GetVListBoxComboPopup()->Clear(); - - SetValue(wxEmptyString); -} - -void wxOwnerDrawnComboBox::Delete(unsigned int n) -{ - wxCHECK_RET( IsValid(n), _T("invalid index in wxOwnerDrawnComboBox::Delete") ); - - if ( GetSelection() == (int) n ) - SetValue(wxEmptyString); - - GetVListBoxComboPopup()->Delete(n); -} - -unsigned int wxOwnerDrawnComboBox::GetCount() const -{ - if ( !m_popupInterface ) - return m_initChs.GetCount(); - - return GetVListBoxComboPopup()->GetCount(); -} - -wxString wxOwnerDrawnComboBox::GetString(unsigned int n) const -{ - wxCHECK_MSG( IsValid(n), wxEmptyString, _T("invalid index in wxOwnerDrawnComboBox::GetString") ); - - if ( !m_popupInterface ) - return m_initChs.Item(n); - - return GetVListBoxComboPopup()->GetString(n); -} - -void wxOwnerDrawnComboBox::SetString(unsigned int n, const wxString& s) -{ - EnsurePopupControl(); - - wxCHECK_RET( IsValid(n), _T("invalid index in wxOwnerDrawnComboBox::SetString") ); - - GetVListBoxComboPopup()->SetString(n,s); -} - -int wxOwnerDrawnComboBox::FindString(const wxString& s, bool bCase) const -{ - if ( !m_popupInterface ) - return m_initChs.Index(s, bCase); - - return GetVListBoxComboPopup()->FindString(s, bCase); -} - -void wxOwnerDrawnComboBox::Select(int n) -{ - EnsurePopupControl(); - - wxCHECK_RET( (n == wxNOT_FOUND) || IsValid(n), _T("invalid index in wxOwnerDrawnComboBox::Select") ); - - GetVListBoxComboPopup()->SetSelection(n); - - wxString str; - if ( n >= 0 ) - str = GetVListBoxComboPopup()->GetString(n); - - // Refresh text portion in control - if ( m_text ) - m_text->SetValue( str ); - else - m_valueString = str; - - Refresh(); -} - -int wxOwnerDrawnComboBox::GetSelection() const -{ - if ( !m_popupInterface ) - return m_initChs.Index(m_valueString); - - return GetVListBoxComboPopup()->GetSelection(); -} - -int wxOwnerDrawnComboBox::DoAppend(const wxString& item) -{ - EnsurePopupControl(); - wxASSERT(m_popupInterface); - - return GetVListBoxComboPopup()->Append(item); -} - -int wxOwnerDrawnComboBox::DoInsert(const wxString& item, unsigned int pos) -{ - EnsurePopupControl(); - - wxCHECK_MSG(!(GetWindowStyle() & wxCB_SORT), -1, wxT("can't insert into sorted list")); - wxCHECK_MSG(IsValidInsert(pos), -1, wxT("invalid index")); - - GetVListBoxComboPopup()->Insert(item,pos); - - return pos; -} - -void wxOwnerDrawnComboBox::DoSetItemClientData(unsigned int n, void* clientData) -{ - EnsurePopupControl(); - - GetVListBoxComboPopup()->SetItemClientData(n,clientData,m_clientDataItemsType); -} - -void* wxOwnerDrawnComboBox::DoGetItemClientData(unsigned int n) const -{ - if ( !m_popupInterface ) - return NULL; - - return GetVListBoxComboPopup()->GetItemClientData(n); -} - -void wxOwnerDrawnComboBox::DoSetItemClientObject(unsigned int n, wxClientData* clientData) -{ - DoSetItemClientData(n, (void*) clientData); -} - -wxClientData* wxOwnerDrawnComboBox::DoGetItemClientObject(unsigned int n) const -{ - return (wxClientData*) DoGetItemClientData(n); -} - -// ---------------------------------------------------------------------------- -// wxOwnerDrawnComboBox item drawing and measuring default implementations -// ---------------------------------------------------------------------------- - -void wxOwnerDrawnComboBox::OnDrawItem( wxDC& dc, - const wxRect& rect, - int item, - int flags ) const -{ - if ( flags & wxODCB_PAINTING_CONTROL ) - { - dc.DrawText( GetValue(), - rect.x + GetTextIndent(), - (rect.height-dc.GetCharHeight())/2 + rect.y ); - } - else - { - dc.DrawText( GetVListBoxComboPopup()->GetString(item), rect.x + 2, rect.y ); - } -} - -wxCoord wxOwnerDrawnComboBox::OnMeasureItem( size_t WXUNUSED(item) ) const -{ - return -1; -} - -wxCoord wxOwnerDrawnComboBox::OnMeasureItemWidth( size_t WXUNUSED(item) ) const -{ - return -1; -} - -void wxOwnerDrawnComboBox::OnDrawBackground(wxDC& dc, - const wxRect& rect, - int WXUNUSED(item), - int flags) const -{ - // We need only to explicitly draw background for items - // that should have selected background. Also, call PrepareBackground - // always when painting the control so that clipping is done properly. - - if ( (flags & wxODCB_PAINTING_SELECTED) || - ((flags & wxODCB_PAINTING_CONTROL) && HasFlag(wxCB_READONLY)) ) - { - int bgFlags = wxCONTROL_SELECTED; - - if ( !(flags & wxODCB_PAINTING_CONTROL) ) - bgFlags |= wxCONTROL_ISSUBMENU; - - PrepareBackground(dc, rect, bgFlags); - } -} - -#endif // wxUSE_ODCOMBOBOX +///////////////////////////////////////////////////////////////////////////// +// Name: src/generic/odcombo.cpp +// Purpose: wxOwnerDrawnComboBox, wxVListBoxComboPopup +// Author: Jaakko Salli +// Modified by: +// Created: Apr-30-2006 +// RCS-ID: $Id: odcombo.cpp 52747 2008-03-23 20:20:46Z VZ $ +// Copyright: (c) 2005 Jaakko Salli +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_ODCOMBOBOX + +#include "wx/odcombo.h" + +#ifndef WX_PRECOMP + #include "wx/log.h" + #include "wx/combobox.h" + #include "wx/dcclient.h" + #include "wx/settings.h" + #include "wx/dialog.h" +#endif + +#include "wx/combo.h" + +// ============================================================================ +// implementation +// ============================================================================ + +// time in milliseconds before partial completion buffer drops +#define wxODCB_PARTIAL_COMPLETION_TIME 1000 + +// ---------------------------------------------------------------------------- +// wxVListBoxComboPopup is a wxVListBox customized to act as a popup control +// +// ---------------------------------------------------------------------------- + + +BEGIN_EVENT_TABLE(wxVListBoxComboPopup, wxVListBox) + EVT_MOTION(wxVListBoxComboPopup::OnMouseMove) + EVT_KEY_DOWN(wxVListBoxComboPopup::OnKey) + EVT_LEFT_UP(wxVListBoxComboPopup::OnLeftClick) +END_EVENT_TABLE() + + +void wxVListBoxComboPopup::Init() +{ + m_widestWidth = 0; + m_widestItem = -1; + m_widthsDirty = false; + m_findWidest = false; + m_itemHeight = 0; + m_value = -1; + m_itemHover = -1; + m_clientDataItemsType = wxClientData_None; + m_partialCompletionString = wxEmptyString; +} + +bool wxVListBoxComboPopup::Create(wxWindow* parent) +{ + if ( !wxVListBox::Create(parent, + wxID_ANY, + wxDefaultPosition, + wxDefaultSize, + wxBORDER_SIMPLE | wxLB_INT_HEIGHT | wxWANTS_CHARS) ) + return false; + + m_useFont = m_combo->GetFont(); + + wxVListBox::SetItemCount(m_strings.GetCount()); + + // TODO: Move this to SetFont + m_itemHeight = GetCharHeight() + 0; + + return true; +} + +wxVListBoxComboPopup::~wxVListBoxComboPopup() +{ + Clear(); +} + +bool wxVListBoxComboPopup::LazyCreate() +{ + // NB: There is a bug with wxVListBox that can be avoided by creating + // it later (bug causes empty space to be shown if initial selection + // is at the end of a list longer than the control can show at once). + return true; +} + +// paint the control itself +void wxVListBoxComboPopup::PaintComboControl( wxDC& dc, const wxRect& rect ) +{ + if ( !(m_combo->GetWindowStyle() & wxODCB_STD_CONTROL_PAINT) ) + { + int flags = wxODCB_PAINTING_CONTROL; + + if ( m_combo->ShouldDrawFocus() ) + flags |= wxODCB_PAINTING_SELECTED; + + OnDrawBg(dc, rect, m_value, flags); + + if ( m_value >= 0 ) + { + OnDrawItem(dc,rect,m_value,flags); + return; + } + } + + wxComboPopup::PaintComboControl(dc,rect); +} + +void wxVListBoxComboPopup::OnDrawItem(wxDC& dc, const wxRect& rect, size_t n) const +{ + // TODO: Maybe this code could be moved to wxVListBox::OnPaint? + dc.SetFont(m_useFont); + + int flags = 0; + + // Set correct text colour for selected items + if ( wxVListBox::GetSelection() == (int) n ) + { + dc.SetTextForeground( wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT) ); + flags |= wxODCB_PAINTING_SELECTED; + } + else + { + dc.SetTextForeground( wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT) ); + } + + OnDrawItem(dc,rect,(int)n,flags); +} + +wxCoord wxVListBoxComboPopup::OnMeasureItem(size_t n) const +{ + wxOwnerDrawnComboBox* combo = (wxOwnerDrawnComboBox*) m_combo; + + wxASSERT_MSG( combo->IsKindOf(CLASSINFO(wxOwnerDrawnComboBox)), + wxT("you must subclass wxVListBoxComboPopup for drawing and measuring methods") ); + + wxCoord h = combo->OnMeasureItem(n); + if ( h < 0 ) + h = m_itemHeight; + return h; +} + +wxCoord wxVListBoxComboPopup::OnMeasureItemWidth(size_t n) const +{ + wxOwnerDrawnComboBox* combo = (wxOwnerDrawnComboBox*) m_combo; + + wxASSERT_MSG( combo->IsKindOf(CLASSINFO(wxOwnerDrawnComboBox)), + wxT("you must subclass wxVListBoxComboPopup for drawing and measuring methods") ); + + return combo->OnMeasureItemWidth(n); +} + +void wxVListBoxComboPopup::OnDrawBg( wxDC& dc, + const wxRect& rect, + int item, + int flags ) const +{ + wxOwnerDrawnComboBox* combo = (wxOwnerDrawnComboBox*) m_combo; + + wxASSERT_MSG( combo->IsKindOf(CLASSINFO(wxOwnerDrawnComboBox)), + wxT("you must subclass wxVListBoxComboPopup for drawing and measuring methods") ); + + if ( IsCurrent((size_t)item) && !(flags & wxODCB_PAINTING_CONTROL) ) + flags |= wxODCB_PAINTING_SELECTED; + + combo->OnDrawBackground(dc,rect,item,flags); +} + +void wxVListBoxComboPopup::OnDrawBackground(wxDC& dc, const wxRect& rect, size_t n) const +{ + OnDrawBg(dc,rect,(int)n,0); +} + +// This is called from wxVListBoxComboPopup::OnDrawItem, with text colour and font prepared +void wxVListBoxComboPopup::OnDrawItem( wxDC& dc, const wxRect& rect, int item, int flags ) const +{ + wxOwnerDrawnComboBox* combo = (wxOwnerDrawnComboBox*) m_combo; + + wxASSERT_MSG( combo->IsKindOf(CLASSINFO(wxOwnerDrawnComboBox)), + wxT("you must subclass wxVListBoxComboPopup for drawing and measuring methods") ); + + combo->OnDrawItem(dc,rect,item,flags); +} + +void wxVListBoxComboPopup::DismissWithEvent() +{ + StopPartialCompletion(); + + int selection = wxVListBox::GetSelection(); + + Dismiss(); + + wxString valStr; + if ( selection != wxNOT_FOUND ) + valStr = m_strings[selection]; + else + valStr = wxEmptyString; + + m_value = selection; + + if ( valStr != m_combo->GetValue() ) + m_combo->SetValueWithEvent(valStr); + + SendComboBoxEvent(selection); +} + +void wxVListBoxComboPopup::SendComboBoxEvent( int selection ) +{ + wxCommandEvent evt(wxEVT_COMMAND_COMBOBOX_SELECTED,m_combo->GetId()); + + evt.SetEventObject(m_combo); + + evt.SetInt(selection); + + // Set client data, if any + if ( selection >= 0 && (int)m_clientDatas.GetCount() > selection ) + { + void* clientData = m_clientDatas[selection]; + if ( m_clientDataItemsType == wxClientData_Object ) + evt.SetClientObject((wxClientData*)clientData); + else + evt.SetClientData(clientData); + } + + m_combo->GetEventHandler()->AddPendingEvent(evt); +} + +// returns true if key was consumed +bool wxVListBoxComboPopup::HandleKey( int keycode, bool saturate, wxChar unicode ) +{ + const int itemCount = GetCount(); + + // keys do nothing in the empty control and returning immediately avoids + // using invalid indices below + if ( !itemCount ) + return false; + + int value = m_value; + int comboStyle = m_combo->GetWindowStyle(); + + // this is the character equivalent of the code + wxChar keychar=0; + if ((keycode >= WXK_SPACE) && (keycode <=255) && (keycode != WXK_DELETE) && wxIsprint(keycode)) + { + keychar = (wxChar)keycode; + } + else if (unicode>0) + { + keychar = unicode; + } + + if ( keycode == WXK_DOWN || keycode == WXK_RIGHT ) + { + value++; + StopPartialCompletion(); + } + else if ( keycode == WXK_UP || keycode == WXK_LEFT ) + { + value--; + StopPartialCompletion(); + } + else if ( keycode == WXK_PAGEDOWN ) + { + value+=10; + StopPartialCompletion(); + } + else if ( keycode == WXK_PAGEUP ) + { + value-=10; + StopPartialCompletion(); + } + else if ( comboStyle & wxCB_READONLY ) + { + // Try partial completion + + // find the new partial completion string +#if wxUSE_TIMER + if (m_partialCompletionTimer.IsRunning()) + m_partialCompletionString+=wxString(keychar); + else +#endif // wxUSE_TIMER + m_partialCompletionString=wxString(keychar); + + // now search through the values to see if this is found + int found = -1; + unsigned int length=m_partialCompletionString.length(); + int i; + for (i=0; i= length) && (! m_partialCompletionString.CmpNoCase(item.Left(length)))) + { + found=i; + break; + } + } + + if (found<0) + { + StopPartialCompletion(); + ::wxBell(); + return true; // to stop the first value being set + } + else + { + value=i; +#if wxUSE_TIMER + m_partialCompletionTimer.Start(wxODCB_PARTIAL_COMPLETION_TIME, true); +#endif // wxUSE_TIMER + } + } + else + return false; + + if ( saturate ) + { + if ( value >= itemCount ) + value = itemCount - 1; + else if ( value < 0 ) + value = 0; + } + else + { + if ( value >= itemCount ) + value -= itemCount; + else if ( value < 0 ) + value += itemCount; + } + + if ( value == m_value ) + // Even if value was same, don't skip the event + // (good for consistency) + return true; + + m_value = value; + + if ( value >= 0 ) + m_combo->SetValue(m_strings[value]); + + SendComboBoxEvent(m_value); + + return true; +} + +// stop partial completion +void wxVListBoxComboPopup::StopPartialCompletion() +{ + m_partialCompletionString = wxEmptyString; +#if wxUSE_TIMER + m_partialCompletionTimer.Stop(); +#endif // wxUSE_TIMER +} + +void wxVListBoxComboPopup::OnComboDoubleClick() +{ + // Cycle on dclick (disable saturation to allow true cycling). + if ( !::wxGetKeyState(WXK_SHIFT) ) + HandleKey(WXK_DOWN,false); + else + HandleKey(WXK_UP,false); +} + +void wxVListBoxComboPopup::OnComboKeyEvent( wxKeyEvent& event ) +{ + // Saturated key movement on + if ( !HandleKey(event.GetKeyCode(),true, +#if wxUSE_UNICODE + event.GetUnicodeKey() +#else + 0 +#endif + ) ) + event.Skip(); +} + +void wxVListBoxComboPopup::OnPopup() +{ + // *must* set value after size is set (this is because of a vlbox bug) + wxVListBox::SetSelection(m_value); +} + +void wxVListBoxComboPopup::OnMouseMove(wxMouseEvent& event) +{ + event.Skip(); + + // Move selection to cursor if it is inside the popup + + int y = event.GetPosition().y; + int fromBottom = GetClientSize().y - y; + + // Since in any case we need to find out if the last item is only + // partially visible, we might just as well replicate the HitTest + // loop here. + const size_t lineMax = GetVisibleEnd(); + for ( size_t line = GetVisibleBegin(); line < lineMax; line++ ) + { + y -= OnGetLineHeight(line); + if ( y < 0 ) + { + // Only change selection if item is fully visible + if ( (y + fromBottom) >= 0 ) + { + wxVListBox::SetSelection((int)line); + return; + } + } + } +} + +void wxVListBoxComboPopup::OnLeftClick(wxMouseEvent& WXUNUSED(event)) +{ + DismissWithEvent(); +} + +void wxVListBoxComboPopup::OnKey(wxKeyEvent& event) +{ + // Hide popup if certain key or key combination was pressed + if ( m_combo->IsKeyPopupToggle(event) ) + { + StopPartialCompletion(); + Dismiss(); + } + else if ( event.AltDown() ) + { + // On both wxGTK and wxMSW, pressing Alt down seems to + // completely freeze things in popup (ie. arrow keys and + // enter won't work). + return; + } + // Select item if ENTER is pressed + else if ( event.GetKeyCode() == WXK_RETURN || event.GetKeyCode() == WXK_NUMPAD_ENTER ) + { + DismissWithEvent(); + } + else + { + int comboStyle = m_combo->GetWindowStyle(); + int keycode = event.GetKeyCode(); + // Process partial completion key codes here, but not the arrow keys as the base class will do that for us + if ((comboStyle & wxCB_READONLY) && + (keycode >= WXK_SPACE) && (keycode <=255) && (keycode != WXK_DELETE) && wxIsprint(keycode)) + { + OnComboKeyEvent(event); + SetSelection(m_value); // ensure the highlight bar moves + } + else + event.Skip(); + } +} + +void wxVListBoxComboPopup::Insert( const wxString& item, int pos ) +{ + // Need to change selection? + wxString strValue; + if ( !(m_combo->GetWindowStyle() & wxCB_READONLY) && + m_combo->GetValue() == item ) + { + m_value = pos; + } + + m_strings.Insert(item,pos); + m_widths.Insert(-1,pos); + m_widthsDirty = true; + + if ( IsCreated() ) + wxVListBox::SetItemCount( wxVListBox::GetItemCount()+1 ); +} + +int wxVListBoxComboPopup::Append(const wxString& item) +{ + int pos = (int)m_strings.GetCount(); + + if ( m_combo->GetWindowStyle() & wxCB_SORT ) + { + // Find position + // TODO: Could be optimized with binary search + wxArrayString strings = m_strings; + unsigned int i; + + for ( i=0; i n ) + return m_clientDatas[n]; + + return NULL; +} + +void wxVListBoxComboPopup::Delete( unsigned int item ) +{ + // Remove client data, if set + if ( m_clientDatas.GetCount() ) + { + if ( m_clientDataItemsType == wxClientData_Object ) + delete (wxClientData*) m_clientDatas[item]; + + m_clientDatas.RemoveAt(item); + } + + m_strings.RemoveAt(item); + m_widths.RemoveAt(item); + + if ( (int)item == m_widestItem ) + m_findWidest = true; + + int sel = GetSelection(); + + if ( IsCreated() ) + wxVListBox::SetItemCount( wxVListBox::GetItemCount()-1 ); + + // Fix selection + if ( (int)item < sel ) + SetSelection(sel-1); + else if ( (int)item == sel ) + SetSelection(wxNOT_FOUND); +} + +int wxVListBoxComboPopup::FindString(const wxString& s, bool bCase) const +{ + return m_strings.Index(s, bCase); +} + +unsigned int wxVListBoxComboPopup::GetCount() const +{ + return m_strings.GetCount(); +} + +wxString wxVListBoxComboPopup::GetString( int item ) const +{ + return m_strings[item]; +} + +void wxVListBoxComboPopup::SetString( int item, const wxString& str ) +{ + m_strings[item] = str; + ItemWidthChanged(item); +} + +wxString wxVListBoxComboPopup::GetStringValue() const +{ + if ( m_value >= 0 ) + return m_strings[m_value]; + return wxEmptyString; +} + +void wxVListBoxComboPopup::SetSelection( int item ) +{ + wxCHECK_RET( item == wxNOT_FOUND || ((unsigned int)item < GetCount()), + wxT("invalid index in wxVListBoxComboPopup::SetSelection") ); + + m_value = item; + + if ( IsCreated() ) + wxVListBox::SetSelection(item); +} + +int wxVListBoxComboPopup::GetSelection() const +{ + return m_value; +} + +void wxVListBoxComboPopup::SetStringValue( const wxString& value ) +{ + int index = m_strings.Index(value); + + if ( index >= 0 && index < (int)wxVListBox::GetItemCount() ) + { + m_value = index; + wxVListBox::SetSelection(index); + } +} + +void wxVListBoxComboPopup::CalcWidths() +{ + bool doFindWidest = m_findWidest; + + // Measure items with dirty width. + if ( m_widthsDirty ) + { + unsigned int i; + unsigned int n = m_widths.GetCount(); + int dirtyHandled = 0; + wxArrayInt& widths = m_widths; + + // I think using wxDC::GetTextExtent is faster than + // wxWindow::GetTextExtent (assuming same dc is used + // for all calls, as we do here). + wxClientDC dc(m_combo); + dc.SetFont(m_useFont); + + for ( i=0; i= m_widestWidth ) + { + m_widestWidth = x; + m_widestItem = (int)i; + } + else if ( (int)i == m_widestItem ) + { + // Width of previously widest item has been decreased, so + // we'll have to check all to find current widest item. + doFindWidest = true; + } + + dirtyHandled++; + } + } + + m_widthsDirty = false; + } + + if ( doFindWidest ) + { + unsigned int i; + unsigned int n = m_widths.GetCount(); + + int bestWidth = -1; + int bestIndex = -1; + + for ( i=0; i bestWidth ) + { + bestIndex = (int)i; + bestWidth = w; + } + } + + m_widestWidth = bestWidth; + m_widestItem = bestIndex; + + m_findWidest = false; + } +} + +wxSize wxVListBoxComboPopup::GetAdjustedSize( int minWidth, int prefHeight, int maxHeight ) +{ + int height = 250; + + maxHeight -= 2; // Must take borders into account + + if ( m_strings.GetCount() ) + { + if ( prefHeight > 0 ) + height = prefHeight; + + if ( height > maxHeight ) + height = maxHeight; + + int totalHeight = GetTotalHeight(); // + 3; + if ( height >= totalHeight ) + { + height = totalHeight; + } + else + { + // Adjust height to a multiple of the height of the first item + // NB: Calculations that take variable height into account + // are unnecessary. + int fih = GetLineHeight(0); + height -= height % fih; + } + } + else + height = 50; + + CalcWidths(); + + // Take scrollbar into account in width calculations + int widestWidth = m_widestWidth + wxSystemSettings::GetMetric(wxSYS_VSCROLL_X); + return wxSize(minWidth > widestWidth ? minWidth : widestWidth, + height+2); +} + +//void wxVListBoxComboPopup::Populate( int n, const wxString choices[] ) +void wxVListBoxComboPopup::Populate( const wxArrayString& choices ) +{ + int i; + + int n = choices.GetCount(); + + for ( i=0; iGetWindowStyle() & wxCB_SORT ) + m_strings.Sort(); + + // Find initial selection + wxString strValue = m_combo->GetValue(); + if ( strValue.length() ) + m_value = m_strings.Index(strValue); +} + +// ---------------------------------------------------------------------------- +// wxOwnerDrawnComboBox +// ---------------------------------------------------------------------------- + + +BEGIN_EVENT_TABLE(wxOwnerDrawnComboBox, wxComboCtrl) +END_EVENT_TABLE() + + +IMPLEMENT_DYNAMIC_CLASS2(wxOwnerDrawnComboBox, wxComboCtrl, wxControlWithItems) + +void wxOwnerDrawnComboBox::Init() +{ +} + +bool wxOwnerDrawnComboBox::Create(wxWindow *parent, + wxWindowID id, + const wxString& value, + const wxPoint& pos, + const wxSize& size, + long style, + const wxValidator& validator, + const wxString& name) +{ + return wxComboCtrl::Create(parent,id,value,pos,size,style,validator,name); +} + +wxOwnerDrawnComboBox::wxOwnerDrawnComboBox(wxWindow *parent, + wxWindowID id, + const wxString& value, + const wxPoint& pos, + const wxSize& size, + const wxArrayString& choices, + long style, + const wxValidator& validator, + const wxString& name) + : wxComboCtrl() +{ + Init(); + + Create(parent,id,value,pos,size,choices,style, validator, name); +} + +bool wxOwnerDrawnComboBox::Create(wxWindow *parent, + wxWindowID id, + const wxString& value, + const wxPoint& pos, + const wxSize& size, + const wxArrayString& choices, + long style, + const wxValidator& validator, + const wxString& name) +{ + m_initChs = choices; + //wxCArrayString chs(choices); + + //return Create(parent, id, value, pos, size, chs.GetCount(), + // chs.GetStrings(), style, validator, name); + return Create(parent, id, value, pos, size, 0, + NULL, style, validator, name); +} + +bool wxOwnerDrawnComboBox::Create(wxWindow *parent, + wxWindowID id, + const wxString& value, + const wxPoint& pos, + const wxSize& size, + int n, + const wxString choices[], + long style, + const wxValidator& validator, + const wxString& name) +{ + + if ( !Create(parent, id, value, pos, size, style, + validator, name) ) + { + return false; + } + + int i; + for ( i=0; iClearClientDatas(); +} + +void wxOwnerDrawnComboBox::DoSetPopupControl(wxComboPopup* popup) +{ + if ( !popup ) + { + popup = new wxVListBoxComboPopup(); + } + + wxComboCtrl::DoSetPopupControl(popup); + + wxASSERT(popup); + + // Add initial choices to the wxVListBox + if ( !GetVListBoxComboPopup()->GetCount() ) + { + GetVListBoxComboPopup()->Populate(m_initChs); + m_initChs.Clear(); + } +} + +// ---------------------------------------------------------------------------- +// wxOwnerDrawnComboBox item manipulation methods +// ---------------------------------------------------------------------------- + +void wxOwnerDrawnComboBox::Clear() +{ + EnsurePopupControl(); + + GetVListBoxComboPopup()->Clear(); + + SetValue(wxEmptyString); +} + +void wxOwnerDrawnComboBox::Delete(unsigned int n) +{ + wxCHECK_RET( IsValid(n), _T("invalid index in wxOwnerDrawnComboBox::Delete") ); + + if ( GetSelection() == (int) n ) + SetValue(wxEmptyString); + + GetVListBoxComboPopup()->Delete(n); +} + +unsigned int wxOwnerDrawnComboBox::GetCount() const +{ + if ( !m_popupInterface ) + return m_initChs.GetCount(); + + return GetVListBoxComboPopup()->GetCount(); +} + +wxString wxOwnerDrawnComboBox::GetString(unsigned int n) const +{ + wxCHECK_MSG( IsValid(n), wxEmptyString, _T("invalid index in wxOwnerDrawnComboBox::GetString") ); + + if ( !m_popupInterface ) + return m_initChs.Item(n); + + return GetVListBoxComboPopup()->GetString(n); +} + +void wxOwnerDrawnComboBox::SetString(unsigned int n, const wxString& s) +{ + EnsurePopupControl(); + + wxCHECK_RET( IsValid(n), _T("invalid index in wxOwnerDrawnComboBox::SetString") ); + + GetVListBoxComboPopup()->SetString(n,s); +} + +int wxOwnerDrawnComboBox::FindString(const wxString& s, bool bCase) const +{ + if ( !m_popupInterface ) + return m_initChs.Index(s, bCase); + + return GetVListBoxComboPopup()->FindString(s, bCase); +} + +void wxOwnerDrawnComboBox::Select(int n) +{ + EnsurePopupControl(); + + wxCHECK_RET( (n == wxNOT_FOUND) || IsValid(n), _T("invalid index in wxOwnerDrawnComboBox::Select") ); + + GetVListBoxComboPopup()->SetSelection(n); + + wxString str; + if ( n >= 0 ) + str = GetVListBoxComboPopup()->GetString(n); + + // Refresh text portion in control + if ( m_text ) + m_text->SetValue( str ); + else + m_valueString = str; + + Refresh(); +} + +int wxOwnerDrawnComboBox::GetSelection() const +{ + if ( !m_popupInterface ) + return m_initChs.Index(m_valueString); + + return GetVListBoxComboPopup()->GetSelection(); +} + +int wxOwnerDrawnComboBox::DoAppend(const wxString& item) +{ + EnsurePopupControl(); + wxASSERT(m_popupInterface); + + return GetVListBoxComboPopup()->Append(item); +} + +int wxOwnerDrawnComboBox::DoInsert(const wxString& item, unsigned int pos) +{ + EnsurePopupControl(); + + wxCHECK_MSG(!(GetWindowStyle() & wxCB_SORT), -1, wxT("can't insert into sorted list")); + wxCHECK_MSG(IsValidInsert(pos), -1, wxT("invalid index")); + + GetVListBoxComboPopup()->Insert(item,pos); + + return pos; +} + +void wxOwnerDrawnComboBox::DoSetItemClientData(unsigned int n, void* clientData) +{ + EnsurePopupControl(); + + GetVListBoxComboPopup()->SetItemClientData(n,clientData,m_clientDataItemsType); +} + +void* wxOwnerDrawnComboBox::DoGetItemClientData(unsigned int n) const +{ + if ( !m_popupInterface ) + return NULL; + + return GetVListBoxComboPopup()->GetItemClientData(n); +} + +void wxOwnerDrawnComboBox::DoSetItemClientObject(unsigned int n, wxClientData* clientData) +{ + DoSetItemClientData(n, (void*) clientData); +} + +wxClientData* wxOwnerDrawnComboBox::DoGetItemClientObject(unsigned int n) const +{ + return (wxClientData*) DoGetItemClientData(n); +} + +// ---------------------------------------------------------------------------- +// wxOwnerDrawnComboBox item drawing and measuring default implementations +// ---------------------------------------------------------------------------- + +void wxOwnerDrawnComboBox::OnDrawItem( wxDC& dc, + const wxRect& rect, + int item, + int flags ) const +{ + if ( flags & wxODCB_PAINTING_CONTROL ) + { + dc.DrawText( GetValue(), + rect.x + GetTextIndent(), + (rect.height-dc.GetCharHeight())/2 + rect.y ); + } + else + { + dc.DrawText( GetVListBoxComboPopup()->GetString(item), rect.x + 2, rect.y ); + } +} + +wxCoord wxOwnerDrawnComboBox::OnMeasureItem( size_t WXUNUSED(item) ) const +{ + return -1; +} + +wxCoord wxOwnerDrawnComboBox::OnMeasureItemWidth( size_t WXUNUSED(item) ) const +{ + return -1; +} + +void wxOwnerDrawnComboBox::OnDrawBackground(wxDC& dc, + const wxRect& rect, + int WXUNUSED(item), + int flags) const +{ + // We need only to explicitly draw background for items + // that should have selected background. Also, call PrepareBackground + // always when painting the control so that clipping is done properly. + + if ( (flags & wxODCB_PAINTING_SELECTED) || + ((flags & wxODCB_PAINTING_CONTROL) && HasFlag(wxCB_READONLY)) ) + { + int bgFlags = wxCONTROL_SELECTED; + + if ( !(flags & wxODCB_PAINTING_CONTROL) ) + bgFlags |= wxCONTROL_ISSUBMENU; + + PrepareBackground(dc, rect, bgFlags); + } +} + +#endif // wxUSE_ODCOMBOBOX diff --git a/Externals/wxWidgets/src/generic/paletteg.cpp b/Externals/wxWidgets/src/generic/paletteg.cpp index 93ad6324c2..5696e20f87 100644 --- a/Externals/wxWidgets/src/generic/paletteg.cpp +++ b/Externals/wxWidgets/src/generic/paletteg.cpp @@ -1,145 +1,145 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/generic/paletteg.cpp -// Purpose: -// Author: Robert Roebling -// Created: 01/02/97 -// RCS-ID: $Id: paletteg.cpp 42752 2006-10-30 19:26:48Z VZ $ -// Copyright: (c) 1998 Robert Roebling and Julian Smart -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#if defined(__BORLANDC__) - #pragma hdrstop -#endif - -#if wxUSE_PALETTE - -#include "wx/palette.h" - -//----------------------------------------------------------------------------- -// wxPalette -//----------------------------------------------------------------------------- - -struct wxPaletteEntry -{ - unsigned char red, green, blue; -}; - -class wxPaletteRefData: public wxObjectRefData -{ - public: - - wxPaletteRefData(void); - virtual ~wxPaletteRefData(void); - - int m_count; - wxPaletteEntry *m_entries; -}; - -wxPaletteRefData::wxPaletteRefData() -{ - m_count = 0; - m_entries = NULL; -} - -wxPaletteRefData::~wxPaletteRefData() -{ - delete[] m_entries; -} - -//----------------------------------------------------------------------------- - -#define M_PALETTEDATA ((wxPaletteRefData *)m_refData) - -IMPLEMENT_DYNAMIC_CLASS(wxPalette,wxGDIObject) - -wxPalette::wxPalette() -{ - m_refData = NULL; -} - -wxPalette::wxPalette(int n, const unsigned char *red, const unsigned char *green, const unsigned char *blue) -{ - Create(n, red, green, blue); -} - -wxPalette::~wxPalette() -{ -} - -bool wxPalette::IsOk() const -{ - return (m_refData != NULL); -} - -int wxPalette::GetColoursCount() const -{ - if (m_refData) - return M_PALETTEDATA->m_count; - - return 0; -} - -bool wxPalette::Create(int n, - const unsigned char *red, - const unsigned char *green, - const unsigned char *blue) -{ - UnRef(); - m_refData = new wxPaletteRefData(); - - M_PALETTEDATA->m_count = n; - M_PALETTEDATA->m_entries = new wxPaletteEntry[n]; - - wxPaletteEntry *e = M_PALETTEDATA->m_entries; - for (int i = 0; i < n; i++, e++) - { - e->red = red[i]; - e->green = green[i]; - e->blue = blue[i]; - } - - return true; -} - -int wxPalette::GetPixel( unsigned char red, - unsigned char green, - unsigned char blue ) const -{ - if (!m_refData) return wxNOT_FOUND; - - int closest = 0; - double d,distance = 1000.0; // max. dist is 256 - - wxPaletteEntry *e = M_PALETTEDATA->m_entries; - for (int i = 0; i < M_PALETTEDATA->m_count; i++, e++) - { - if ((d = 0.299 * abs(red - e->red) + - 0.587 * abs(green - e->green) + - 0.114 * abs(blue - e->blue)) < distance) { - distance = d; - closest = i; - } - } - return closest; -} - -bool wxPalette::GetRGB(int pixel, - unsigned char *red, - unsigned char *green, - unsigned char *blue) const -{ - if (!m_refData) return false; - if (pixel >= M_PALETTEDATA->m_count) return false; - - wxPaletteEntry& p = M_PALETTEDATA->m_entries[pixel]; - if (red) *red = p.red; - if (green) *green = p.green; - if (blue) *blue = p.blue; - return true; -} - -#endif // wxUSE_PALETTE +///////////////////////////////////////////////////////////////////////////// +// Name: src/generic/paletteg.cpp +// Purpose: +// Author: Robert Roebling +// Created: 01/02/97 +// RCS-ID: $Id: paletteg.cpp 42752 2006-10-30 19:26:48Z VZ $ +// Copyright: (c) 1998 Robert Roebling and Julian Smart +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#if defined(__BORLANDC__) + #pragma hdrstop +#endif + +#if wxUSE_PALETTE + +#include "wx/palette.h" + +//----------------------------------------------------------------------------- +// wxPalette +//----------------------------------------------------------------------------- + +struct wxPaletteEntry +{ + unsigned char red, green, blue; +}; + +class wxPaletteRefData: public wxObjectRefData +{ + public: + + wxPaletteRefData(void); + virtual ~wxPaletteRefData(void); + + int m_count; + wxPaletteEntry *m_entries; +}; + +wxPaletteRefData::wxPaletteRefData() +{ + m_count = 0; + m_entries = NULL; +} + +wxPaletteRefData::~wxPaletteRefData() +{ + delete[] m_entries; +} + +//----------------------------------------------------------------------------- + +#define M_PALETTEDATA ((wxPaletteRefData *)m_refData) + +IMPLEMENT_DYNAMIC_CLASS(wxPalette,wxGDIObject) + +wxPalette::wxPalette() +{ + m_refData = NULL; +} + +wxPalette::wxPalette(int n, const unsigned char *red, const unsigned char *green, const unsigned char *blue) +{ + Create(n, red, green, blue); +} + +wxPalette::~wxPalette() +{ +} + +bool wxPalette::IsOk() const +{ + return (m_refData != NULL); +} + +int wxPalette::GetColoursCount() const +{ + if (m_refData) + return M_PALETTEDATA->m_count; + + return 0; +} + +bool wxPalette::Create(int n, + const unsigned char *red, + const unsigned char *green, + const unsigned char *blue) +{ + UnRef(); + m_refData = new wxPaletteRefData(); + + M_PALETTEDATA->m_count = n; + M_PALETTEDATA->m_entries = new wxPaletteEntry[n]; + + wxPaletteEntry *e = M_PALETTEDATA->m_entries; + for (int i = 0; i < n; i++, e++) + { + e->red = red[i]; + e->green = green[i]; + e->blue = blue[i]; + } + + return true; +} + +int wxPalette::GetPixel( unsigned char red, + unsigned char green, + unsigned char blue ) const +{ + if (!m_refData) return wxNOT_FOUND; + + int closest = 0; + double d,distance = 1000.0; // max. dist is 256 + + wxPaletteEntry *e = M_PALETTEDATA->m_entries; + for (int i = 0; i < M_PALETTEDATA->m_count; i++, e++) + { + if ((d = 0.299 * abs(red - e->red) + + 0.587 * abs(green - e->green) + + 0.114 * abs(blue - e->blue)) < distance) { + distance = d; + closest = i; + } + } + return closest; +} + +bool wxPalette::GetRGB(int pixel, + unsigned char *red, + unsigned char *green, + unsigned char *blue) const +{ + if (!m_refData) return false; + if (pixel >= M_PALETTEDATA->m_count) return false; + + wxPaletteEntry& p = M_PALETTEDATA->m_entries[pixel]; + if (red) *red = p.red; + if (green) *green = p.green; + if (blue) *blue = p.blue; + return true; +} + +#endif // wxUSE_PALETTE diff --git a/Externals/wxWidgets/src/generic/panelg.cpp b/Externals/wxWidgets/src/generic/panelg.cpp index 5a92972120..cd4dbee65c 100644 --- a/Externals/wxWidgets/src/generic/panelg.cpp +++ b/Externals/wxWidgets/src/generic/panelg.cpp @@ -1,180 +1,180 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/generic/panelg.cpp -// Purpose: wxPanel and the keyboard handling code -// Author: Julian Smart, Robert Roebling, Vadim Zeitlin -// Modified by: -// Created: 04/01/98 -// RCS-ID: $Id: panelg.cpp 40307 2006-07-25 01:31:13Z VZ $ -// Copyright: (c) Julian Smart -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#ifndef WX_PRECOMP - #include "wx/object.h" - #include "wx/font.h" - #include "wx/colour.h" - #include "wx/settings.h" - #include "wx/log.h" - #include "wx/panel.h" - #include "wx/containr.h" -#endif - -// ---------------------------------------------------------------------------- -// wxWin macros -// ---------------------------------------------------------------------------- - -#if wxUSE_EXTENDED_RTTI -WX_DEFINE_FLAGS( wxPanelStyle ) - -wxBEGIN_FLAGS( wxPanelStyle ) - // new style border flags, we put them first to - // use them for streaming out - wxFLAGS_MEMBER(wxBORDER_SIMPLE) - wxFLAGS_MEMBER(wxBORDER_SUNKEN) - wxFLAGS_MEMBER(wxBORDER_DOUBLE) - wxFLAGS_MEMBER(wxBORDER_RAISED) - wxFLAGS_MEMBER(wxBORDER_STATIC) - wxFLAGS_MEMBER(wxBORDER_NONE) - - // old style border flags - wxFLAGS_MEMBER(wxSIMPLE_BORDER) - wxFLAGS_MEMBER(wxSUNKEN_BORDER) - wxFLAGS_MEMBER(wxDOUBLE_BORDER) - wxFLAGS_MEMBER(wxRAISED_BORDER) - wxFLAGS_MEMBER(wxSTATIC_BORDER) - wxFLAGS_MEMBER(wxBORDER) - - // standard window styles - wxFLAGS_MEMBER(wxTAB_TRAVERSAL) - wxFLAGS_MEMBER(wxCLIP_CHILDREN) - wxFLAGS_MEMBER(wxTRANSPARENT_WINDOW) - wxFLAGS_MEMBER(wxWANTS_CHARS) - wxFLAGS_MEMBER(wxFULL_REPAINT_ON_RESIZE) - wxFLAGS_MEMBER(wxALWAYS_SHOW_SB ) - wxFLAGS_MEMBER(wxVSCROLL) - wxFLAGS_MEMBER(wxHSCROLL) - -wxEND_FLAGS( wxPanelStyle ) - -IMPLEMENT_DYNAMIC_CLASS_XTI(wxPanel, wxWindow,"wx/panel.h") - -wxBEGIN_PROPERTIES_TABLE(wxPanel) - wxPROPERTY_FLAGS( WindowStyle , wxPanelStyle , long , SetWindowStyleFlag , GetWindowStyleFlag , EMPTY_MACROVALUE, 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // style -// style wxTAB_TRAVERSAL -wxEND_PROPERTIES_TABLE() - -wxBEGIN_HANDLERS_TABLE(wxPanel) -wxEND_HANDLERS_TABLE() - -wxCONSTRUCTOR_5( wxPanel , wxWindow* , Parent , wxWindowID , Id , wxPoint , Position , wxSize , Size , long , WindowStyle ) - -#else -IMPLEMENT_DYNAMIC_CLASS(wxPanel, wxWindow) -#endif - -BEGIN_EVENT_TABLE(wxPanel, wxWindow) - EVT_SIZE(wxPanel::OnSize) - - WX_EVENT_TABLE_CONTROL_CONTAINER(wxPanel) -END_EVENT_TABLE() - -// ============================================================================ -// implementation -// ============================================================================ - -WX_DELEGATE_TO_CONTROL_CONTAINER(wxPanel, wxWindow) - -// ---------------------------------------------------------------------------- -// wxPanel creation -// ---------------------------------------------------------------------------- - -void wxPanel::Init() -{ - m_container.SetContainerWindow(this); -} - -bool wxPanel::Create(wxWindow *parent, wxWindowID id, - const wxPoint& pos, - const wxSize& size, - long style, - const wxString& name) -{ - if ( !wxWindow::Create(parent, id, pos, size, style, name) ) - return false; - - // so that non-solid background renders correctly under GTK+: - SetThemeEnabled(true); - -#if defined(__WXWINCE__) && (defined(__POCKETPC__) || defined(__SMARTPHONE__)) - // Required to get solid control backgrounds under WinCE - SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW)); -#endif - - return true; -} - -wxPanel::~wxPanel() -{ -} - -void wxPanel::InitDialog() -{ - wxInitDialogEvent event(GetId()); - event.SetEventObject(this); - GetEventHandler()->ProcessEvent(event); -} - -// ---------------------------------------------------------------------------- -// event handlers -// ---------------------------------------------------------------------------- - -void wxPanel::OnSize(wxSizeEvent& event) -{ - if (GetAutoLayout()) - Layout(); -#if wxUSE_CONSTRAINTS -#if defined(__WXPM__) && 0 - else - { - // Need to properly move child windows under OS/2 - - PSWP pWinSwp = GetSwp(); - - if (pWinSwp->cx == 0 && pWinSwp->cy == 0 && pWinSwp->fl == 0) - { - // Uninitialized - - ::WinQueryWindowPos(GetHWND(), pWinSwp); - } - else - { - SWP vSwp; - int nYDiff; - - ::WinQueryWindowPos(GetHWND(), &vSwp); - nYDiff = pWinSwp->cy - vSwp.cy; - MoveChildren(nYDiff); - pWinSwp->cx = vSwp.cx; - pWinSwp->cy = vSwp.cy; - } - } -#endif -#endif // wxUSE_CONSTRAINTS - - event.Skip(); -} +///////////////////////////////////////////////////////////////////////////// +// Name: src/generic/panelg.cpp +// Purpose: wxPanel and the keyboard handling code +// Author: Julian Smart, Robert Roebling, Vadim Zeitlin +// Modified by: +// Created: 04/01/98 +// RCS-ID: $Id: panelg.cpp 40307 2006-07-25 01:31:13Z VZ $ +// Copyright: (c) Julian Smart +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#ifndef WX_PRECOMP + #include "wx/object.h" + #include "wx/font.h" + #include "wx/colour.h" + #include "wx/settings.h" + #include "wx/log.h" + #include "wx/panel.h" + #include "wx/containr.h" +#endif + +// ---------------------------------------------------------------------------- +// wxWin macros +// ---------------------------------------------------------------------------- + +#if wxUSE_EXTENDED_RTTI +WX_DEFINE_FLAGS( wxPanelStyle ) + +wxBEGIN_FLAGS( wxPanelStyle ) + // new style border flags, we put them first to + // use them for streaming out + wxFLAGS_MEMBER(wxBORDER_SIMPLE) + wxFLAGS_MEMBER(wxBORDER_SUNKEN) + wxFLAGS_MEMBER(wxBORDER_DOUBLE) + wxFLAGS_MEMBER(wxBORDER_RAISED) + wxFLAGS_MEMBER(wxBORDER_STATIC) + wxFLAGS_MEMBER(wxBORDER_NONE) + + // old style border flags + wxFLAGS_MEMBER(wxSIMPLE_BORDER) + wxFLAGS_MEMBER(wxSUNKEN_BORDER) + wxFLAGS_MEMBER(wxDOUBLE_BORDER) + wxFLAGS_MEMBER(wxRAISED_BORDER) + wxFLAGS_MEMBER(wxSTATIC_BORDER) + wxFLAGS_MEMBER(wxBORDER) + + // standard window styles + wxFLAGS_MEMBER(wxTAB_TRAVERSAL) + wxFLAGS_MEMBER(wxCLIP_CHILDREN) + wxFLAGS_MEMBER(wxTRANSPARENT_WINDOW) + wxFLAGS_MEMBER(wxWANTS_CHARS) + wxFLAGS_MEMBER(wxFULL_REPAINT_ON_RESIZE) + wxFLAGS_MEMBER(wxALWAYS_SHOW_SB ) + wxFLAGS_MEMBER(wxVSCROLL) + wxFLAGS_MEMBER(wxHSCROLL) + +wxEND_FLAGS( wxPanelStyle ) + +IMPLEMENT_DYNAMIC_CLASS_XTI(wxPanel, wxWindow,"wx/panel.h") + +wxBEGIN_PROPERTIES_TABLE(wxPanel) + wxPROPERTY_FLAGS( WindowStyle , wxPanelStyle , long , SetWindowStyleFlag , GetWindowStyleFlag , EMPTY_MACROVALUE, 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // style +// style wxTAB_TRAVERSAL +wxEND_PROPERTIES_TABLE() + +wxBEGIN_HANDLERS_TABLE(wxPanel) +wxEND_HANDLERS_TABLE() + +wxCONSTRUCTOR_5( wxPanel , wxWindow* , Parent , wxWindowID , Id , wxPoint , Position , wxSize , Size , long , WindowStyle ) + +#else +IMPLEMENT_DYNAMIC_CLASS(wxPanel, wxWindow) +#endif + +BEGIN_EVENT_TABLE(wxPanel, wxWindow) + EVT_SIZE(wxPanel::OnSize) + + WX_EVENT_TABLE_CONTROL_CONTAINER(wxPanel) +END_EVENT_TABLE() + +// ============================================================================ +// implementation +// ============================================================================ + +WX_DELEGATE_TO_CONTROL_CONTAINER(wxPanel, wxWindow) + +// ---------------------------------------------------------------------------- +// wxPanel creation +// ---------------------------------------------------------------------------- + +void wxPanel::Init() +{ + m_container.SetContainerWindow(this); +} + +bool wxPanel::Create(wxWindow *parent, wxWindowID id, + const wxPoint& pos, + const wxSize& size, + long style, + const wxString& name) +{ + if ( !wxWindow::Create(parent, id, pos, size, style, name) ) + return false; + + // so that non-solid background renders correctly under GTK+: + SetThemeEnabled(true); + +#if defined(__WXWINCE__) && (defined(__POCKETPC__) || defined(__SMARTPHONE__)) + // Required to get solid control backgrounds under WinCE + SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW)); +#endif + + return true; +} + +wxPanel::~wxPanel() +{ +} + +void wxPanel::InitDialog() +{ + wxInitDialogEvent event(GetId()); + event.SetEventObject(this); + GetEventHandler()->ProcessEvent(event); +} + +// ---------------------------------------------------------------------------- +// event handlers +// ---------------------------------------------------------------------------- + +void wxPanel::OnSize(wxSizeEvent& event) +{ + if (GetAutoLayout()) + Layout(); +#if wxUSE_CONSTRAINTS +#if defined(__WXPM__) && 0 + else + { + // Need to properly move child windows under OS/2 + + PSWP pWinSwp = GetSwp(); + + if (pWinSwp->cx == 0 && pWinSwp->cy == 0 && pWinSwp->fl == 0) + { + // Uninitialized + + ::WinQueryWindowPos(GetHWND(), pWinSwp); + } + else + { + SWP vSwp; + int nYDiff; + + ::WinQueryWindowPos(GetHWND(), &vSwp); + nYDiff = pWinSwp->cy - vSwp.cy; + MoveChildren(nYDiff); + pWinSwp->cx = vSwp.cx; + pWinSwp->cy = vSwp.cy; + } + } +#endif +#endif // wxUSE_CONSTRAINTS + + event.Skip(); +} diff --git a/Externals/wxWidgets/src/generic/printps.cpp b/Externals/wxWidgets/src/generic/printps.cpp index fafc3d8f17..4da2161d04 100644 --- a/Externals/wxWidgets/src/generic/printps.cpp +++ b/Externals/wxWidgets/src/generic/printps.cpp @@ -1,370 +1,370 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/generic/printps.cpp -// Purpose: Postscript print/preview framework -// Author: Julian Smart -// Modified by: -// Created: 04/01/98 -// RCS-ID: $Id: printps.cpp 42522 2006-10-27 13:07:40Z JS $ -// Copyright: (c) Julian Smart -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -#if wxUSE_PRINTING_ARCHITECTURE && wxUSE_POSTSCRIPT && (!defined(__WXMSW__) || wxUSE_POSTSCRIPT_ARCHITECTURE_IN_MSW) - -#ifndef WX_PRECOMP - #include "wx/utils.h" - #include "wx/dc.h" - #include "wx/app.h" - #include "wx/msgdlg.h" - #include "wx/intl.h" - #include "wx/progdlg.h" - #include "wx/log.h" - #include "wx/dcprint.h" -#endif - -#include "wx/generic/printps.h" -#include "wx/printdlg.h" -#include "wx/generic/prntdlgg.h" -#include "wx/generic/progdlgg.h" -#include "wx/paper.h" - -#include - -// ---------------------------------------------------------------------------- -// wxWin macros -// ---------------------------------------------------------------------------- - - IMPLEMENT_DYNAMIC_CLASS(wxPostScriptPrinter, wxPrinterBase) - IMPLEMENT_CLASS(wxPostScriptPrintPreview, wxPrintPreviewBase) - -// ============================================================================ -// implementation -// ============================================================================ - -// ---------------------------------------------------------------------------- -// Printer -// ---------------------------------------------------------------------------- - -wxPostScriptPrinter::wxPostScriptPrinter(wxPrintDialogData *data) - : wxPrinterBase(data) -{ -} - -wxPostScriptPrinter::~wxPostScriptPrinter() -{ -} - -bool wxPostScriptPrinter::Print(wxWindow *parent, wxPrintout *printout, bool prompt) -{ - sm_abortIt = false; - sm_abortWindow = (wxWindow *) NULL; - - if (!printout) - { - sm_lastError = wxPRINTER_ERROR; - return false; - } - - printout->SetIsPreview(false); - - if (m_printDialogData.GetMinPage() < 1) - m_printDialogData.SetMinPage(1); - if (m_printDialogData.GetMaxPage() < 1) - m_printDialogData.SetMaxPage(9999); - - // Create a suitable device context - wxDC *dc; - if (prompt) - { - dc = PrintDialog(parent); - if (!dc) - return false; - } - else - { - dc = new wxPostScriptDC(GetPrintDialogData().GetPrintData()); - } - - // May have pressed cancel. - if (!dc || !dc->Ok()) - { - if (dc) delete dc; - sm_lastError = wxPRINTER_ERROR; - return false; - } - - wxSize ScreenPixels = wxGetDisplaySize(); - wxSize ScreenMM = wxGetDisplaySizeMM(); - - printout->SetPPIScreen( (int) ((ScreenPixels.GetWidth() * 25.4) / ScreenMM.GetWidth()), - (int) ((ScreenPixels.GetHeight() * 25.4) / ScreenMM.GetHeight()) ); - printout->SetPPIPrinter( wxPostScriptDC::GetResolution(), - wxPostScriptDC::GetResolution() ); - - // Set printout parameters - printout->SetDC(dc); - - int w, h; - dc->GetSize(&w, &h); - printout->SetPageSizePixels((int)w, (int)h); - printout->SetPaperRectPixels(wxRect(0, 0, w, h)); - int mw, mh; - dc->GetSizeMM(&mw, &mh); - printout->SetPageSizeMM((int)mw, (int)mh); - - // Create an abort window - wxBeginBusyCursor(); - - printout->OnPreparePrinting(); - - // Get some parameters from the printout, if defined - int fromPage, toPage; - int minPage, maxPage; - printout->GetPageInfo(&minPage, &maxPage, &fromPage, &toPage); - - if (maxPage == 0) - { - sm_lastError = wxPRINTER_ERROR; - wxEndBusyCursor(); - return false; - } - - // Only set min and max, because from and to have been - // set by the user - m_printDialogData.SetMinPage(minPage); - m_printDialogData.SetMaxPage(maxPage); - - if (m_printDialogData.GetFromPage() < minPage) - m_printDialogData.SetFromPage( minPage ); - if (m_printDialogData.GetToPage() > maxPage) - m_printDialogData.SetToPage( maxPage ); - - int - pagesPerCopy = m_printDialogData.GetToPage()-m_printDialogData.GetFromPage()+1, - totalPages = pagesPerCopy * m_printDialogData.GetNoCopies(), - printedPages = 0; - // Open the progress bar dialog - wxProgressDialog *progressDialog = new wxProgressDialog ( - printout->GetTitle(), - _("Printing..."), - totalPages, - parent, - wxPD_CAN_ABORT|wxPD_AUTO_HIDE|wxPD_APP_MODAL); - - printout->OnBeginPrinting(); - - sm_lastError = wxPRINTER_NO_ERROR; - - bool keepGoing = true; - - int copyCount; - for (copyCount = 1; copyCount <= m_printDialogData.GetNoCopies(); copyCount ++) - { - if (!printout->OnBeginDocument(m_printDialogData.GetFromPage(), m_printDialogData.GetToPage())) - { - wxEndBusyCursor(); - wxLogError(_("Could not start printing.")); - sm_lastError = wxPRINTER_ERROR; - break; - } - if (sm_abortIt) - { - sm_lastError = wxPRINTER_CANCELLED; - break; - } - - int pn; - for (pn = m_printDialogData.GetFromPage(); keepGoing && (pn <= m_printDialogData.GetToPage()) && printout->HasPage(pn); - pn++) - { - if (sm_abortIt) - { - keepGoing = false; - sm_lastError = wxPRINTER_CANCELLED; - break; - } - else - { - wxString msg; - msg.Printf(_("Printing page %d..."), printedPages+1); - if(progressDialog->Update(printedPages++, msg)) - { - dc->StartPage(); - printout->OnPrintPage(pn); - dc->EndPage(); - } - else - { - sm_abortIt = true; - sm_lastError = wxPRINTER_CANCELLED; - keepGoing = false; - } - } - wxYield(); - } - printout->OnEndDocument(); - } - - printout->OnEndPrinting(); - delete progressDialog; - - wxEndBusyCursor(); - - delete dc; - - return (sm_lastError == wxPRINTER_NO_ERROR); -} - -wxDC* wxPostScriptPrinter::PrintDialog(wxWindow *parent) -{ - wxDC* dc = (wxDC*) NULL; - - wxGenericPrintDialog dialog( parent, &m_printDialogData ); - if (dialog.ShowModal() == wxID_OK) - { - dc = dialog.GetPrintDC(); - m_printDialogData = dialog.GetPrintDialogData(); - - if (dc == NULL) - sm_lastError = wxPRINTER_ERROR; - else - sm_lastError = wxPRINTER_NO_ERROR; - } - else - sm_lastError = wxPRINTER_CANCELLED; - - return dc; -} - -bool wxPostScriptPrinter::Setup(wxWindow *WXUNUSED(parent)) -{ -#if 0 - wxGenericPrintDialog* dialog = new wxGenericPrintDialog(parent, & m_printDialogData); - dialog->GetPrintDialogData().SetSetupDialog(true); - - int ret = dialog->ShowModal(); - - if (ret == wxID_OK) - { - m_printDialogData = dialog->GetPrintDialogData(); - } - - dialog->Destroy(); - - return (ret == wxID_OK); -#endif - - return false; -} - -// ---------------------------------------------------------------------------- -// Print preview -// ---------------------------------------------------------------------------- - -void wxPostScriptPrintPreview::Init(wxPrintout * WXUNUSED(printout), - wxPrintout * WXUNUSED(printoutForPrinting)) -{ - // Have to call it here since base constructor can't call it - DetermineScaling(); -} - -wxPostScriptPrintPreview::wxPostScriptPrintPreview(wxPrintout *printout, - wxPrintout *printoutForPrinting, - wxPrintDialogData *data) - : wxPrintPreviewBase(printout, printoutForPrinting, data) -{ - Init(printout, printoutForPrinting); -} - -wxPostScriptPrintPreview::wxPostScriptPrintPreview(wxPrintout *printout, - wxPrintout *printoutForPrinting, - wxPrintData *data) - : wxPrintPreviewBase(printout, printoutForPrinting, data) -{ - Init(printout, printoutForPrinting); -} - -wxPostScriptPrintPreview::~wxPostScriptPrintPreview() -{ -} - -bool wxPostScriptPrintPreview::Print(bool interactive) -{ - if (!m_printPrintout) - return false; - - // Assume that on Unix, the preview may use the PostScript - // (generic) version, but printing using the native system is required. - // TODO: make a generic print preview class from which wxPostScriptPrintPreview - // is derived. -#ifdef __UNIX__ - wxPrinter printer(& m_printDialogData); -#else - wxPostScriptPrinter printer(& m_printDialogData); -#endif - return printer.Print(m_previewFrame, m_printPrintout, interactive); -} - -void wxPostScriptPrintPreview::DetermineScaling() -{ - wxPaperSize paperType = m_printDialogData.GetPrintData().GetPaperId(); - if (paperType == wxPAPER_NONE) - paperType = wxPAPER_NONE; - - wxPrintPaperType *paper = wxThePrintPaperDatabase->FindPaperType(paperType); - if (!paper) - paper = wxThePrintPaperDatabase->FindPaperType(wxPAPER_A4); - - if (paper) - { - wxSize ScreenPixels = wxGetDisplaySize(); - wxSize ScreenMM = wxGetDisplaySizeMM(); - - m_previewPrintout->SetPPIScreen( (int) ((ScreenPixels.GetWidth() * 25.4) / ScreenMM.GetWidth()), - (int) ((ScreenPixels.GetHeight() * 25.4) / ScreenMM.GetHeight()) ); - m_previewPrintout->SetPPIPrinter(wxPostScriptDC::GetResolution(), wxPostScriptDC::GetResolution()); - - wxSize sizeDevUnits(paper->GetSizeDeviceUnits()); - sizeDevUnits.x = (wxCoord)((float)sizeDevUnits.x * wxPostScriptDC::GetResolution() / 72.0); - sizeDevUnits.y = (wxCoord)((float)sizeDevUnits.y * wxPostScriptDC::GetResolution() / 72.0); - wxSize sizeTenthsMM(paper->GetSize()); - wxSize sizeMM(sizeTenthsMM.x / 10, sizeTenthsMM.y / 10); - - // If in landscape mode, we need to swap the width and height. - if ( m_printDialogData.GetPrintData().GetOrientation() == wxLANDSCAPE ) - { - m_pageWidth = sizeDevUnits.y; - m_pageHeight = sizeDevUnits.x; - m_previewPrintout->SetPageSizeMM(sizeMM.y, sizeMM.x); - } - else - { - m_pageWidth = sizeDevUnits.x; - m_pageHeight = sizeDevUnits.y; - m_previewPrintout->SetPageSizeMM(sizeMM.x, sizeMM.y); - } - m_previewPrintout->SetPageSizePixels(m_pageWidth, m_pageHeight); - m_previewPrintout->SetPaperRectPixels(wxRect(0, 0, m_pageWidth, m_pageHeight)); - - // At 100%, the page should look about page-size on the screen. - m_previewScaleX = (float)0.8 * 72.0 / (float)wxPostScriptDC::GetResolution(); - m_previewScaleY = m_previewScaleX; - } -} - -#endif +///////////////////////////////////////////////////////////////////////////// +// Name: src/generic/printps.cpp +// Purpose: Postscript print/preview framework +// Author: Julian Smart +// Modified by: +// Created: 04/01/98 +// RCS-ID: $Id: printps.cpp 42522 2006-10-27 13:07:40Z JS $ +// Copyright: (c) Julian Smart +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +#if wxUSE_PRINTING_ARCHITECTURE && wxUSE_POSTSCRIPT && (!defined(__WXMSW__) || wxUSE_POSTSCRIPT_ARCHITECTURE_IN_MSW) + +#ifndef WX_PRECOMP + #include "wx/utils.h" + #include "wx/dc.h" + #include "wx/app.h" + #include "wx/msgdlg.h" + #include "wx/intl.h" + #include "wx/progdlg.h" + #include "wx/log.h" + #include "wx/dcprint.h" +#endif + +#include "wx/generic/printps.h" +#include "wx/printdlg.h" +#include "wx/generic/prntdlgg.h" +#include "wx/generic/progdlgg.h" +#include "wx/paper.h" + +#include + +// ---------------------------------------------------------------------------- +// wxWin macros +// ---------------------------------------------------------------------------- + + IMPLEMENT_DYNAMIC_CLASS(wxPostScriptPrinter, wxPrinterBase) + IMPLEMENT_CLASS(wxPostScriptPrintPreview, wxPrintPreviewBase) + +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// Printer +// ---------------------------------------------------------------------------- + +wxPostScriptPrinter::wxPostScriptPrinter(wxPrintDialogData *data) + : wxPrinterBase(data) +{ +} + +wxPostScriptPrinter::~wxPostScriptPrinter() +{ +} + +bool wxPostScriptPrinter::Print(wxWindow *parent, wxPrintout *printout, bool prompt) +{ + sm_abortIt = false; + sm_abortWindow = (wxWindow *) NULL; + + if (!printout) + { + sm_lastError = wxPRINTER_ERROR; + return false; + } + + printout->SetIsPreview(false); + + if (m_printDialogData.GetMinPage() < 1) + m_printDialogData.SetMinPage(1); + if (m_printDialogData.GetMaxPage() < 1) + m_printDialogData.SetMaxPage(9999); + + // Create a suitable device context + wxDC *dc; + if (prompt) + { + dc = PrintDialog(parent); + if (!dc) + return false; + } + else + { + dc = new wxPostScriptDC(GetPrintDialogData().GetPrintData()); + } + + // May have pressed cancel. + if (!dc || !dc->Ok()) + { + if (dc) delete dc; + sm_lastError = wxPRINTER_ERROR; + return false; + } + + wxSize ScreenPixels = wxGetDisplaySize(); + wxSize ScreenMM = wxGetDisplaySizeMM(); + + printout->SetPPIScreen( (int) ((ScreenPixels.GetWidth() * 25.4) / ScreenMM.GetWidth()), + (int) ((ScreenPixels.GetHeight() * 25.4) / ScreenMM.GetHeight()) ); + printout->SetPPIPrinter( wxPostScriptDC::GetResolution(), + wxPostScriptDC::GetResolution() ); + + // Set printout parameters + printout->SetDC(dc); + + int w, h; + dc->GetSize(&w, &h); + printout->SetPageSizePixels((int)w, (int)h); + printout->SetPaperRectPixels(wxRect(0, 0, w, h)); + int mw, mh; + dc->GetSizeMM(&mw, &mh); + printout->SetPageSizeMM((int)mw, (int)mh); + + // Create an abort window + wxBeginBusyCursor(); + + printout->OnPreparePrinting(); + + // Get some parameters from the printout, if defined + int fromPage, toPage; + int minPage, maxPage; + printout->GetPageInfo(&minPage, &maxPage, &fromPage, &toPage); + + if (maxPage == 0) + { + sm_lastError = wxPRINTER_ERROR; + wxEndBusyCursor(); + return false; + } + + // Only set min and max, because from and to have been + // set by the user + m_printDialogData.SetMinPage(minPage); + m_printDialogData.SetMaxPage(maxPage); + + if (m_printDialogData.GetFromPage() < minPage) + m_printDialogData.SetFromPage( minPage ); + if (m_printDialogData.GetToPage() > maxPage) + m_printDialogData.SetToPage( maxPage ); + + int + pagesPerCopy = m_printDialogData.GetToPage()-m_printDialogData.GetFromPage()+1, + totalPages = pagesPerCopy * m_printDialogData.GetNoCopies(), + printedPages = 0; + // Open the progress bar dialog + wxProgressDialog *progressDialog = new wxProgressDialog ( + printout->GetTitle(), + _("Printing..."), + totalPages, + parent, + wxPD_CAN_ABORT|wxPD_AUTO_HIDE|wxPD_APP_MODAL); + + printout->OnBeginPrinting(); + + sm_lastError = wxPRINTER_NO_ERROR; + + bool keepGoing = true; + + int copyCount; + for (copyCount = 1; copyCount <= m_printDialogData.GetNoCopies(); copyCount ++) + { + if (!printout->OnBeginDocument(m_printDialogData.GetFromPage(), m_printDialogData.GetToPage())) + { + wxEndBusyCursor(); + wxLogError(_("Could not start printing.")); + sm_lastError = wxPRINTER_ERROR; + break; + } + if (sm_abortIt) + { + sm_lastError = wxPRINTER_CANCELLED; + break; + } + + int pn; + for (pn = m_printDialogData.GetFromPage(); keepGoing && (pn <= m_printDialogData.GetToPage()) && printout->HasPage(pn); + pn++) + { + if (sm_abortIt) + { + keepGoing = false; + sm_lastError = wxPRINTER_CANCELLED; + break; + } + else + { + wxString msg; + msg.Printf(_("Printing page %d..."), printedPages+1); + if(progressDialog->Update(printedPages++, msg)) + { + dc->StartPage(); + printout->OnPrintPage(pn); + dc->EndPage(); + } + else + { + sm_abortIt = true; + sm_lastError = wxPRINTER_CANCELLED; + keepGoing = false; + } + } + wxYield(); + } + printout->OnEndDocument(); + } + + printout->OnEndPrinting(); + delete progressDialog; + + wxEndBusyCursor(); + + delete dc; + + return (sm_lastError == wxPRINTER_NO_ERROR); +} + +wxDC* wxPostScriptPrinter::PrintDialog(wxWindow *parent) +{ + wxDC* dc = (wxDC*) NULL; + + wxGenericPrintDialog dialog( parent, &m_printDialogData ); + if (dialog.ShowModal() == wxID_OK) + { + dc = dialog.GetPrintDC(); + m_printDialogData = dialog.GetPrintDialogData(); + + if (dc == NULL) + sm_lastError = wxPRINTER_ERROR; + else + sm_lastError = wxPRINTER_NO_ERROR; + } + else + sm_lastError = wxPRINTER_CANCELLED; + + return dc; +} + +bool wxPostScriptPrinter::Setup(wxWindow *WXUNUSED(parent)) +{ +#if 0 + wxGenericPrintDialog* dialog = new wxGenericPrintDialog(parent, & m_printDialogData); + dialog->GetPrintDialogData().SetSetupDialog(true); + + int ret = dialog->ShowModal(); + + if (ret == wxID_OK) + { + m_printDialogData = dialog->GetPrintDialogData(); + } + + dialog->Destroy(); + + return (ret == wxID_OK); +#endif + + return false; +} + +// ---------------------------------------------------------------------------- +// Print preview +// ---------------------------------------------------------------------------- + +void wxPostScriptPrintPreview::Init(wxPrintout * WXUNUSED(printout), + wxPrintout * WXUNUSED(printoutForPrinting)) +{ + // Have to call it here since base constructor can't call it + DetermineScaling(); +} + +wxPostScriptPrintPreview::wxPostScriptPrintPreview(wxPrintout *printout, + wxPrintout *printoutForPrinting, + wxPrintDialogData *data) + : wxPrintPreviewBase(printout, printoutForPrinting, data) +{ + Init(printout, printoutForPrinting); +} + +wxPostScriptPrintPreview::wxPostScriptPrintPreview(wxPrintout *printout, + wxPrintout *printoutForPrinting, + wxPrintData *data) + : wxPrintPreviewBase(printout, printoutForPrinting, data) +{ + Init(printout, printoutForPrinting); +} + +wxPostScriptPrintPreview::~wxPostScriptPrintPreview() +{ +} + +bool wxPostScriptPrintPreview::Print(bool interactive) +{ + if (!m_printPrintout) + return false; + + // Assume that on Unix, the preview may use the PostScript + // (generic) version, but printing using the native system is required. + // TODO: make a generic print preview class from which wxPostScriptPrintPreview + // is derived. +#ifdef __UNIX__ + wxPrinter printer(& m_printDialogData); +#else + wxPostScriptPrinter printer(& m_printDialogData); +#endif + return printer.Print(m_previewFrame, m_printPrintout, interactive); +} + +void wxPostScriptPrintPreview::DetermineScaling() +{ + wxPaperSize paperType = m_printDialogData.GetPrintData().GetPaperId(); + if (paperType == wxPAPER_NONE) + paperType = wxPAPER_NONE; + + wxPrintPaperType *paper = wxThePrintPaperDatabase->FindPaperType(paperType); + if (!paper) + paper = wxThePrintPaperDatabase->FindPaperType(wxPAPER_A4); + + if (paper) + { + wxSize ScreenPixels = wxGetDisplaySize(); + wxSize ScreenMM = wxGetDisplaySizeMM(); + + m_previewPrintout->SetPPIScreen( (int) ((ScreenPixels.GetWidth() * 25.4) / ScreenMM.GetWidth()), + (int) ((ScreenPixels.GetHeight() * 25.4) / ScreenMM.GetHeight()) ); + m_previewPrintout->SetPPIPrinter(wxPostScriptDC::GetResolution(), wxPostScriptDC::GetResolution()); + + wxSize sizeDevUnits(paper->GetSizeDeviceUnits()); + sizeDevUnits.x = (wxCoord)((float)sizeDevUnits.x * wxPostScriptDC::GetResolution() / 72.0); + sizeDevUnits.y = (wxCoord)((float)sizeDevUnits.y * wxPostScriptDC::GetResolution() / 72.0); + wxSize sizeTenthsMM(paper->GetSize()); + wxSize sizeMM(sizeTenthsMM.x / 10, sizeTenthsMM.y / 10); + + // If in landscape mode, we need to swap the width and height. + if ( m_printDialogData.GetPrintData().GetOrientation() == wxLANDSCAPE ) + { + m_pageWidth = sizeDevUnits.y; + m_pageHeight = sizeDevUnits.x; + m_previewPrintout->SetPageSizeMM(sizeMM.y, sizeMM.x); + } + else + { + m_pageWidth = sizeDevUnits.x; + m_pageHeight = sizeDevUnits.y; + m_previewPrintout->SetPageSizeMM(sizeMM.x, sizeMM.y); + } + m_previewPrintout->SetPageSizePixels(m_pageWidth, m_pageHeight); + m_previewPrintout->SetPaperRectPixels(wxRect(0, 0, m_pageWidth, m_pageHeight)); + + // At 100%, the page should look about page-size on the screen. + m_previewScaleX = (float)0.8 * 72.0 / (float)wxPostScriptDC::GetResolution(); + m_previewScaleY = m_previewScaleX; + } +} + +#endif diff --git a/Externals/wxWidgets/src/generic/prntdlgg.cpp b/Externals/wxWidgets/src/generic/prntdlgg.cpp index e62d6baa20..bf733b9518 100644 --- a/Externals/wxWidgets/src/generic/prntdlgg.cpp +++ b/Externals/wxWidgets/src/generic/prntdlgg.cpp @@ -1,1100 +1,1100 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/generic/prntdlgg.cpp -// Purpose: Generic print dialogs -// Author: Julian Smart -// Modified by: -// Created: 04/01/98 -// RCS-ID: $Id: prntdlgg.cpp 50289 2007-11-28 00:24:25Z VZ $ -// Copyright: (c) Julian Smart -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_PRINTING_ARCHITECTURE && (!defined(__WXMSW__) || wxUSE_POSTSCRIPT_ARCHITECTURE_IN_MSW) - -#include "wx/generic/prntdlgg.h" - -#ifndef WX_PRECOMP - #include "wx/utils.h" - #include "wx/dc.h" - #include "wx/stattext.h" - #include "wx/statbox.h" - #include "wx/button.h" - #include "wx/checkbox.h" - #include "wx/textctrl.h" - #include "wx/radiobox.h" - #include "wx/filedlg.h" - #include "wx/combobox.h" - #include "wx/intl.h" - #include "wx/sizer.h" - #include "wx/cmndata.h" -#endif - -#if wxUSE_STATLINE - #include "wx/statline.h" -#endif - -#if wxUSE_POSTSCRIPT - #include "wx/generic/dcpsg.h" -#endif - -#include "wx/prntbase.h" -#include "wx/printdlg.h" -#include "wx/paper.h" -#include "wx/filename.h" -#include "wx/tokenzr.h" -#include "wx/imaglist.h" - -#include -#include - -#ifndef __WXUNIVERSAL__ - -#if wxUSE_LIBGNOMEPRINT - #include "wx/link.h" - wxFORCE_LINK_MODULE(gnome_print) -#endif - -#endif // !__WXUNIVERSAL__ - -// ---------------------------------------------------------------------------- -// global vars -// ---------------------------------------------------------------------------- - -extern wxPrintPaperDatabase *wxThePrintPaperDatabase; - -#if wxUSE_POSTSCRIPT - -//---------------------------------------------------------------------------- -// wxPostScriptNativeData -//---------------------------------------------------------------------------- - -IMPLEMENT_CLASS(wxPostScriptPrintNativeData, wxPrintNativeDataBase) - -wxPostScriptPrintNativeData::wxPostScriptPrintNativeData() -{ - m_previewCommand = wxEmptyString; -#ifdef __VMS__ - m_printerCommand = wxT("print"); - m_printerOptions = wxT("/nonotify/queue=psqueue"); - m_afmPath = wxT("sys$ps_font_metrics:"); -#endif - -#ifdef __WXMSW__ - m_printerCommand = wxT("print"); - m_printerOptions = wxEmptyString; - m_afmPath = wxT("c:\\windows\\system\\"); -#endif - -#if !defined(__VMS__) && !defined(__WXMSW__) - m_printerCommand = wxT("lpr"); - m_printerOptions = wxEmptyString; - m_afmPath = wxEmptyString; -#endif - - m_printerScaleX = 1.0; - m_printerScaleY = 1.0; - m_printerTranslateX = 0; - m_printerTranslateY = 0; -} - -wxPostScriptPrintNativeData::~wxPostScriptPrintNativeData() -{ -} - -bool wxPostScriptPrintNativeData::TransferTo( wxPrintData &WXUNUSED(data) ) -{ - return true; -} - -bool wxPostScriptPrintNativeData::TransferFrom( const wxPrintData &WXUNUSED(data) ) -{ - return true; -} - -// ---------------------------------------------------------------------------- -// Generic print dialog for non-Windows printing use. -// ---------------------------------------------------------------------------- - -IMPLEMENT_CLASS(wxGenericPrintDialog, wxPrintDialogBase) - -BEGIN_EVENT_TABLE(wxGenericPrintDialog, wxPrintDialogBase) - EVT_BUTTON(wxID_OK, wxGenericPrintDialog::OnOK) - EVT_BUTTON(wxPRINTID_SETUP, wxGenericPrintDialog::OnSetup) - EVT_RADIOBOX(wxPRINTID_RANGE, wxGenericPrintDialog::OnRange) -END_EVENT_TABLE() - -wxGenericPrintDialog::wxGenericPrintDialog(wxWindow *parent, - wxPrintDialogData* data) - : wxPrintDialogBase(parent, wxID_ANY, _("Print"), - wxPoint(0,0), wxSize(600, 600), - wxDEFAULT_DIALOG_STYLE | - wxTAB_TRAVERSAL) -{ - if ( data ) - m_printDialogData = *data; - - Init(parent); -} - -wxGenericPrintDialog::wxGenericPrintDialog(wxWindow *parent, - wxPrintData* data) - : wxPrintDialogBase(parent, wxID_ANY, _("Print"), - wxPoint(0,0), wxSize(600, 600), - wxDEFAULT_DIALOG_STYLE | - wxTAB_TRAVERSAL) -{ - if ( data ) - m_printDialogData = *data; - - Init(parent); -} - -void wxGenericPrintDialog::Init(wxWindow * WXUNUSED(parent)) -{ - // wxDialog::Create(parent, wxID_ANY, _("Print"), wxPoint(0,0), wxSize(600, 600), - // wxDEFAULT_DIALOG_STYLE | wxTAB_TRAVERSAL); - - wxBoxSizer *mainsizer = new wxBoxSizer( wxVERTICAL ); - - // 1) top row - - wxPrintFactory* factory = wxPrintFactory::GetFactory(); - - wxStaticBoxSizer *topsizer = new wxStaticBoxSizer( - new wxStaticBox( this, wxID_ANY, _( "Printer options" ) ), wxHORIZONTAL ); - wxFlexGridSizer *flex = new wxFlexGridSizer( 2 ); - flex->AddGrowableCol( 1 ); - topsizer->Add( flex, 1, wxGROW ); - - m_printToFileCheckBox = new wxCheckBox( this, wxPRINTID_PRINTTOFILE, _("Print to File") ); - flex->Add( m_printToFileCheckBox, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 ); - - m_setupButton = new wxButton(this, wxPRINTID_SETUP, _("Setup...") ); - flex->Add( m_setupButton, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_RIGHT|wxALL, 5 ); - - if (!factory->HasPrintSetupDialog()) - m_setupButton->Enable( false ); - - if (factory->HasPrinterLine()) - { - flex->Add( new wxStaticText( this, wxID_ANY, _("Printer:") ), - 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 ); - flex->Add( new wxStaticText( this, wxID_ANY, factory->CreatePrinterLine() ), - 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 ); - } - - if (factory->HasStatusLine()) - { - flex->Add( new wxStaticText( this, wxID_ANY, _("Status:") ), - 0, wxALIGN_CENTER_VERTICAL|wxALL-wxTOP, 5 ); - flex->Add( new wxStaticText( this, wxID_ANY, factory->CreateStatusLine() ), - 0, wxALIGN_CENTER_VERTICAL|wxALL-wxTOP, 5 ); - } - - mainsizer->Add( topsizer, 0, wxLEFT|wxTOP|wxRIGHT|wxGROW, 10 ); - - // 2) middle row with radio box - - wxString *choices = new wxString[2]; - choices[0] = _("All"); - choices[1] = _("Pages"); - - m_fromText = (wxTextCtrl*)NULL; - m_toText = (wxTextCtrl*)NULL; - m_rangeRadioBox = (wxRadioBox *)NULL; - - if (m_printDialogData.GetFromPage() != 0) - { - m_rangeRadioBox = new wxRadioBox(this, wxPRINTID_RANGE, _("Print Range"), - wxDefaultPosition, wxDefaultSize, - 2, choices, - 1, wxRA_VERTICAL); - m_rangeRadioBox->SetSelection(1); - - mainsizer->Add( m_rangeRadioBox, 0, wxLEFT|wxTOP|wxRIGHT, 10 ); - } - - // 3) bottom row - - wxBoxSizer *bottomsizer = new wxBoxSizer( wxHORIZONTAL ); - - if (m_printDialogData.GetFromPage() != 0) - { - bottomsizer->Add( new wxStaticText(this, wxPRINTID_STATIC, _("From:") ), 0, wxCENTER|wxALL, 5 ); - m_fromText = new wxTextCtrl(this, wxPRINTID_FROM, wxEmptyString, wxDefaultPosition, wxSize(40, wxDefaultCoord)); - bottomsizer->Add( m_fromText, 1, wxCENTER|wxRIGHT, 10 ); - - bottomsizer->Add( new wxStaticText(this, wxPRINTID_STATIC, _("To:") ), 0, wxCENTER|wxALL, 5); - m_toText = new wxTextCtrl(this, wxPRINTID_TO, wxEmptyString, wxDefaultPosition, wxSize(40, wxDefaultCoord)); - bottomsizer->Add( m_toText, 1, wxCENTER|wxRIGHT, 10 ); - } - - bottomsizer->Add( new wxStaticText(this, wxPRINTID_STATIC, _("Copies:") ), 0, wxCENTER|wxALL, 5 ); - m_noCopiesText = new wxTextCtrl(this, wxPRINTID_COPIES, wxEmptyString, wxPoint(252, 130), wxSize(40, wxDefaultCoord)); - bottomsizer->Add( m_noCopiesText, 1, wxCENTER|wxRIGHT, 10 ); - - mainsizer->Add( bottomsizer, 0, wxTOP|wxLEFT|wxRIGHT, 12 ); - - // 4) buttons - - wxSizer *sizerBtn = CreateSeparatedButtonSizer( wxOK|wxCANCEL); - if ( sizerBtn ) - mainsizer->Add(sizerBtn, 0, wxEXPAND|wxALL, 10 ); - - SetAutoLayout( true ); - SetSizer( mainsizer ); - - mainsizer->Fit( this ); - Centre(wxBOTH); - - // Calls wxWindow::OnInitDialog and then wxGenericPrintDialog::TransferDataToWindow - InitDialog(); - delete[] choices; -} - -int wxGenericPrintDialog::ShowModal() -{ - return wxDialog::ShowModal(); -} - -wxGenericPrintDialog::~wxGenericPrintDialog() -{ -} - -void wxGenericPrintDialog::OnOK(wxCommandEvent& WXUNUSED(event)) -{ - TransferDataFromWindow(); - - // An empty 'to' field signals printing just the - // 'from' page. - if (m_printDialogData.GetToPage() < 1) - m_printDialogData.SetToPage(m_printDialogData.GetFromPage()); - - // There are some interactions between the global setup data - // and the standard print dialog. The global printing 'mode' - // is determined by whether the user checks Print to file - // or not. - if (m_printDialogData.GetPrintToFile()) - { - m_printDialogData.GetPrintData().SetPrintMode(wxPRINT_MODE_FILE); - - wxFileName fname( m_printDialogData.GetPrintData().GetFilename() ); - - wxFileDialog dialog( this, _("PostScript file"), - fname.GetPath(), fname.GetFullName(), wxT("*.ps"), wxFD_SAVE | wxFD_OVERWRITE_PROMPT ); - if (dialog.ShowModal() != wxID_OK) return; - - m_printDialogData.GetPrintData().SetFilename( dialog.GetPath() ); - } - else - { - m_printDialogData.GetPrintData().SetPrintMode(wxPRINT_MODE_PRINTER); - } - - EndModal(wxID_OK); -} - -void wxGenericPrintDialog::OnRange(wxCommandEvent& event) -{ - if (!m_fromText) return; - - if (event.GetInt() == 0) - { - m_fromText->Enable(false); - m_toText->Enable(false); - } - else if (event.GetInt() == 1) - { - m_fromText->Enable(true); - m_toText->Enable(true); - } -} - -void wxGenericPrintDialog::OnSetup(wxCommandEvent& WXUNUSED(event)) -{ - wxPrintFactory* factory = wxPrintFactory::GetFactory(); - - if (factory->HasPrintSetupDialog()) - { - // The print setup dialog should change the - // print data in-place if not cancelled. - wxDialog *dialog = factory->CreatePrintSetupDialog( this, &m_printDialogData.GetPrintData() ); - dialog->ShowModal(); - dialog->Destroy(); - } -} - -bool wxGenericPrintDialog::TransferDataToWindow() -{ - if(m_printDialogData.GetFromPage() != 0) - { - if(m_fromText) - { - if (m_printDialogData.GetEnablePageNumbers()) - { - m_fromText->Enable(true); - m_toText->Enable(true); - if (m_printDialogData.GetFromPage() > 0) - m_fromText->SetValue(wxString::Format(_T("%d"), m_printDialogData.GetFromPage())); - if (m_printDialogData.GetToPage() > 0) - m_toText->SetValue(wxString::Format(_T("%d"), m_printDialogData.GetToPage())); - if(m_rangeRadioBox) - if (m_printDialogData.GetAllPages() || m_printDialogData.GetFromPage() == 0) - m_rangeRadioBox->SetSelection(0); - else - m_rangeRadioBox->SetSelection(1); - } - else - { - m_fromText->Enable(false); - m_toText->Enable(false); - if(m_rangeRadioBox) - { - m_rangeRadioBox->SetSelection(0); - m_rangeRadioBox->wxRadioBox::Enable(1, false); - } - } - } - } - m_noCopiesText->SetValue( - wxString::Format(_T("%d"), m_printDialogData.GetNoCopies())); - - m_printToFileCheckBox->SetValue(m_printDialogData.GetPrintToFile()); - m_printToFileCheckBox->Enable(m_printDialogData.GetEnablePrintToFile()); - return true; -} - -bool wxGenericPrintDialog::TransferDataFromWindow() -{ - long res = 0; - if(m_printDialogData.GetFromPage() != -1) - { - if (m_printDialogData.GetEnablePageNumbers()) - { - if(m_fromText) - { - wxString value = m_fromText->GetValue(); - if (value.ToLong( &res )) - m_printDialogData.SetFromPage( res ); - } - if(m_toText) - { - wxString value = m_toText->GetValue(); - if (value.ToLong( &res )) - m_printDialogData.SetToPage( res ); - } - } - if(m_rangeRadioBox) - { - if (m_rangeRadioBox->GetSelection() == 0) - { - m_printDialogData.SetAllPages(true); - - // This means all pages, more or less - m_printDialogData.SetFromPage(1); - m_printDialogData.SetToPage(32000); - } - else - m_printDialogData.SetAllPages(false); - } - } - else - { // continuous printing - m_printDialogData.SetFromPage(1); - m_printDialogData.SetToPage(32000); - } - - wxString value = m_noCopiesText->GetValue(); - if (value.ToLong( &res )) - m_printDialogData.SetNoCopies( res ); - - m_printDialogData.SetPrintToFile(m_printToFileCheckBox->GetValue()); - - return true; -} - -wxDC *wxGenericPrintDialog::GetPrintDC() -{ - return new wxPostScriptDC(GetPrintDialogData().GetPrintData()); -} - -// ---------------------------------------------------------------------------- -// Generic print setup dialog -// ---------------------------------------------------------------------------- - -IMPLEMENT_CLASS(wxGenericPrintSetupDialog, wxDialog) - -BEGIN_EVENT_TABLE(wxGenericPrintSetupDialog, wxDialog) - EVT_LIST_ITEM_ACTIVATED(wxPRINTID_PRINTER, wxGenericPrintSetupDialog::OnPrinter) -END_EVENT_TABLE() - -wxGenericPrintSetupDialog::wxGenericPrintSetupDialog(wxWindow *parent, wxPrintData* data): -wxDialog(parent, wxID_ANY, _("Print Setup"), wxPoint(0,0), wxSize(600, 600), wxDEFAULT_DIALOG_STYLE|wxTAB_TRAVERSAL) -{ - Init(data); -} - -/* XPM */ -static const char * check_xpm[] = { -/* width height ncolors chars_per_pixel */ -"16 16 3 1", -/* colors */ -" s None c None", -"X c #000000", -". c #808080", -/* pixels */ -" ", -" ", -" ", -" .. ", -" XX ", -" XX. ", -" .XX ", -" XX ", -" X XX. ", -" XX .XX ", -" XX XX ", -" XXXX. ", -" XX. ", -" . ", -" ", -" " -}; - - -void wxGenericPrintSetupDialog::Init(wxPrintData* data) -{ - if ( data ) - m_printData = *data; - - m_targetData = data; - - wxBoxSizer *main_sizer = new wxBoxSizer( wxVERTICAL ); - - // printer selection - - wxStaticBoxSizer *printer_sizer = new wxStaticBoxSizer( new wxStaticBox( this, wxID_ANY, _("Printer") ), wxVERTICAL ); - main_sizer->Add( printer_sizer, 0, wxALL|wxGROW, 10 ); - - m_printerListCtrl = new wxListCtrl( this, wxPRINTID_PRINTER, - wxDefaultPosition, wxSize(wxDefaultCoord,100), wxLC_REPORT|wxLC_SINGLE_SEL|wxSUNKEN_BORDER ); - wxImageList *image_list = new wxImageList; - image_list->Add( wxBitmap(check_xpm) ); - m_printerListCtrl->AssignImageList( image_list, wxIMAGE_LIST_SMALL ); - - m_printerListCtrl->InsertColumn( 0, wxT(" "), wxLIST_FORMAT_LEFT, 20 ); - m_printerListCtrl->InsertColumn( 1, wxT("Printer"), wxLIST_FORMAT_LEFT, 150 ); - m_printerListCtrl->InsertColumn( 2, wxT("Device"), wxLIST_FORMAT_LEFT, 150 ); - m_printerListCtrl->InsertColumn( 3, wxT("Status"), wxLIST_FORMAT_LEFT, 80 ); - - wxListItem item; - item.SetMask( wxLIST_MASK_TEXT ); - item.SetColumn( 1 ); - item.SetText( _("Default printer") ); - item.SetId( m_printerListCtrl->InsertItem( item ) ); - - if (data->GetPrinterName().empty()) - { - wxListItem item2; - item2.SetId( item.GetId() ); - item2.SetMask( wxLIST_MASK_IMAGE ); - item2.SetImage( 0 ); - m_printerListCtrl->SetItem( item2 ); - // also select item - m_printerListCtrl->SetItemState( item.GetId(), wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED ); - } - - item.SetId( 1+ item.GetId() ); - - wxArrayString errors; - wxArrayString output; - long res = wxExecute( wxT("lpstat -v"), output, errors, wxEXEC_NODISABLE ); - if (res >= 0 && errors.GetCount() == 0) - { - size_t i; - for (i = 0; i < output.GetCount(); i++) - { - wxStringTokenizer tok( output[i], wxT(" ") ); - wxString tmp = tok.GetNextToken(); // "device" - if (tmp != wxT("device")) - break; // the lpstat syntax must have changed. - tmp = tok.GetNextToken(); // "for" - if (tmp != wxT("for")) - break; // the lpstat syntax must have changed. - tmp = tok.GetNextToken(); // "hp_deskjet930c:" - if (tmp[tmp.length()-1] == wxT(':')) - tmp.Remove(tmp.length()-1,1); - wxString name = tmp; - item.SetText( name ); - item.SetId( m_printerListCtrl->InsertItem( item ) ); - tmp = tok.GetNextToken(); // "parallel:/dev/lp0" - item.SetColumn( 2 ); - item.SetText( tmp ); - m_printerListCtrl->SetItem( item ); - if (data->GetPrinterName() == name) - { - wxListItem item2; - item2.SetId( item.GetId() ); - item2.SetMask( wxLIST_MASK_IMAGE ); - item2.SetImage( 0 ); - m_printerListCtrl->SetItem( item2 ); - // also select item - m_printerListCtrl->SetItemState( item.GetId(), wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED ); - } - - wxString command = wxT("lpstat -p "); - command += name; - wxArrayString errors2; - wxArrayString output2; - res = wxExecute( command, output2, errors2, wxEXEC_NODISABLE ); - if (res >= 0 && errors2.GetCount() == 0 && output2.GetCount() > 0) - { - tmp = output2[0]; // "printer hp_deskjet930c is idle. enable since ..." - int pos = tmp.Find( wxT('.') ); - if (pos != wxNOT_FOUND) - tmp.Remove( (size_t)pos, tmp.length()-(size_t)pos ); - wxStringTokenizer tok2( tmp, wxT(" ") ); - tmp = tok2.GetNextToken(); // "printer" - tmp = tok2.GetNextToken(); // "hp_deskjet930c" - tmp = wxEmptyString; - while (tok2.HasMoreTokens()) - { - tmp += tok2.GetNextToken(); - tmp += wxT(" "); - } - item.SetColumn( 3 ); - item.SetText( tmp ); - m_printerListCtrl->SetItem( item ); - } - - item.SetColumn( 1 ); - item.SetId( 1+ item.GetId() ); - } - } - - - printer_sizer->Add( m_printerListCtrl, 0, wxALL|wxGROW, 5 ); - - wxBoxSizer *item1 = new wxBoxSizer( wxHORIZONTAL ); - main_sizer->Add( item1, 0, wxALL, 5 ); - - // printer options (on the left) - - wxBoxSizer *item2 = new wxBoxSizer( wxVERTICAL ); - - wxStaticBox *item4 = new wxStaticBox( this, wxPRINTID_STATIC, _("Paper size") ); - wxStaticBoxSizer *item3 = new wxStaticBoxSizer( item4, wxVERTICAL ); - - m_paperTypeChoice = CreatePaperTypeChoice(); - item3->Add( m_paperTypeChoice, 0, wxALIGN_CENTER|wxALL, 5 ); - - item2->Add( item3, 0, wxALIGN_CENTER|wxALL, 5 ); - - wxString strs6[] = - { - _("Portrait"), - _("Landscape") - }; - m_orientationRadioBox= new wxRadioBox( this, wxPRINTID_ORIENTATION, _("Orientation"), wxDefaultPosition, wxDefaultSize, 2, strs6, 1, wxRA_SPECIFY_ROWS ); - item2->Add( m_orientationRadioBox, 0, wxGROW|wxALIGN_CENTER_VERTICAL|wxALL, 5 ); - - wxStaticBox *item8 = new wxStaticBox( this, wxID_ANY, _("Options") ); - wxStaticBoxSizer *item7 = new wxStaticBoxSizer( item8, wxHORIZONTAL ); - - m_colourCheckBox = new wxCheckBox( this, wxPRINTID_PRINTCOLOUR, _("Print in colour") ); - item7->Add( m_colourCheckBox, 0, wxALIGN_CENTER|wxALL, 5 ); - - item2->Add( item7, 0, wxGROW|wxALIGN_CENTER_VERTICAL|wxALL, 5 ); - - item1->Add( item2, 0, wxALIGN_CENTER_HORIZONTAL, 5 ); - - // spooling options (on the right) - - wxStaticBox *item11 = new wxStaticBox( this, wxID_ANY, _("Print spooling") ); - wxStaticBoxSizer *item10 = new wxStaticBoxSizer( item11, wxVERTICAL ); - - wxStaticText *item12 = new wxStaticText( this, wxID_ANY, _("Printer command:") ); - item10->Add( item12, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 ); - - wxBoxSizer *item13 = new wxBoxSizer( wxHORIZONTAL ); - - item13->Add( 20, 20, 0, wxALIGN_CENTER|wxALL, 5 ); - - m_printerCommandText = new wxTextCtrl( this, wxPRINTID_COMMAND, wxEmptyString, wxDefaultPosition, wxSize(160,wxDefaultCoord) ); - item13->Add( m_printerCommandText, 0, wxALIGN_CENTER|wxALL, 5 ); - - item10->Add( item13, 0, wxALIGN_CENTER|wxALL, 0 ); - - wxStaticText *item15 = new wxStaticText( this, wxID_ANY, _("Printer options:") ); - item10->Add( item15, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 ); - - wxBoxSizer *item16 = new wxBoxSizer( wxHORIZONTAL ); - - item16->Add( 20, 20, 0, wxALIGN_CENTER|wxALL, 5 ); - - m_printerOptionsText = new wxTextCtrl( this, wxPRINTID_OPTIONS, wxEmptyString, wxDefaultPosition, wxSize(160,wxDefaultCoord) ); - item16->Add( m_printerOptionsText, 0, wxALIGN_CENTER|wxALL, 5 ); - - item10->Add( item16, 0, wxALIGN_CENTER|wxALL, 0 ); - - item1->Add( item10, 0, wxALIGN_CENTER_HORIZONTAL|wxALL, 5 ); - - -#if wxUSE_STATLINE - // static line - main_sizer->Add( new wxStaticLine( this, wxID_ANY ), 0, wxEXPAND | wxLEFT|wxRIGHT|wxTOP, 10 ); -#endif - - // buttons - - main_sizer->Add( CreateButtonSizer( wxOK|wxCANCEL), 0, wxEXPAND|wxALL, 10 ); - - SetAutoLayout( true ); - SetSizer( main_sizer ); - - main_sizer->Fit( this ); - Centre(wxBOTH); - - - Fit(); - Centre(wxBOTH); - - InitDialog(); -} - -wxGenericPrintSetupDialog::~wxGenericPrintSetupDialog() -{ -} - -void wxGenericPrintSetupDialog::OnPrinter(wxListEvent& event) -{ - // Delete check mark - for (long item = 0; item < m_printerListCtrl->GetItemCount(); item++) - m_printerListCtrl->SetItemImage( item, -1 ); - - m_printerListCtrl->SetItemImage( event.GetIndex(), 0 ); - - if (event.GetIndex() == 0) - { - m_printerCommandText->SetValue( wxT("lpr") ); - } - else - { - wxListItem li; - li.SetColumn( 1 ); - li.SetMask( wxLIST_MASK_TEXT ); - li.SetId( event.GetIndex() ); - m_printerListCtrl->GetItem( li ); - m_printerCommandText->SetValue( _T("lpr -P") + li.GetText() ); - } -} - -bool wxGenericPrintSetupDialog::TransferDataToWindow() -{ - wxPostScriptPrintNativeData *data = - (wxPostScriptPrintNativeData *) m_printData.GetNativeData(); - - if (m_printerCommandText && data->GetPrinterCommand()) - m_printerCommandText->SetValue(data->GetPrinterCommand()); - if (m_printerOptionsText && data->GetPrinterOptions()) - m_printerOptionsText->SetValue(data->GetPrinterOptions()); - if (m_colourCheckBox) - m_colourCheckBox->SetValue(m_printData.GetColour()); - - if (m_orientationRadioBox) - { - if (m_printData.GetOrientation() == wxPORTRAIT) - m_orientationRadioBox->SetSelection(0); - else - m_orientationRadioBox->SetSelection(1); - } - return true; -} - -bool wxGenericPrintSetupDialog::TransferDataFromWindow() -{ - wxPostScriptPrintNativeData *data = - (wxPostScriptPrintNativeData *) m_printData.GetNativeData(); - - // find selected printer - long id = m_printerListCtrl->GetNextItem( -1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED ); - if (id == 0) - { - m_printData.SetPrinterName( wxEmptyString ); - } - else - { - wxListItem item; - item.SetId( id ); - item.SetMask( wxLIST_MASK_TEXT ); - item.SetColumn( 1 ); - m_printerListCtrl->GetItem( item ); - m_printData.SetPrinterName( item.GetText() ); - } - - if (m_printerCommandText) - data->SetPrinterCommand(m_printerCommandText->GetValue()); - if (m_printerOptionsText) - data->SetPrinterOptions(m_printerOptionsText->GetValue()); - if (m_colourCheckBox) - m_printData.SetColour(m_colourCheckBox->GetValue()); - if (m_orientationRadioBox) - { - int sel = m_orientationRadioBox->GetSelection(); - if (sel == 0) - m_printData.SetOrientation(wxPORTRAIT); - else - m_printData.SetOrientation(wxLANDSCAPE); - } - if (m_paperTypeChoice) - { - int selectedItem = m_paperTypeChoice->GetSelection(); - if (selectedItem != -1) - { - wxPrintPaperType *paper = wxThePrintPaperDatabase->Item(selectedItem); - if (paper != NULL) - m_printData.SetPaperId( paper->GetId()); - } - } - - if (m_targetData) - *m_targetData = m_printData; - - return true; -} - -wxComboBox *wxGenericPrintSetupDialog::CreatePaperTypeChoice() -{ - size_t n = wxThePrintPaperDatabase->GetCount(); - wxString *choices = new wxString [n]; - size_t sel = 0; - - for (size_t i = 0; i < n; i++) - { - wxPrintPaperType *paper = wxThePrintPaperDatabase->Item(i); - choices[i] = paper->GetName(); - if (m_printData.GetPaperId() == paper->GetId()) - sel = i; - } - - int width = 250; - - wxComboBox *choice = new wxComboBox( this, - wxPRINTID_PAPERSIZE, - _("Paper Size"), - wxDefaultPosition, - wxSize(width, wxDefaultCoord), - n, choices ); - - delete[] choices; - - choice->SetSelection(sel); - return choice; -} - -#endif // wxUSE_POSTSCRIPT - -// ---------------------------------------------------------------------------- -// Generic page setup dialog -// ---------------------------------------------------------------------------- - -IMPLEMENT_CLASS(wxGenericPageSetupDialog, wxPageSetupDialogBase) - -BEGIN_EVENT_TABLE(wxGenericPageSetupDialog, wxPageSetupDialogBase) - EVT_BUTTON(wxPRINTID_SETUP, wxGenericPageSetupDialog::OnPrinter) -END_EVENT_TABLE() - -wxGenericPageSetupDialog::wxGenericPageSetupDialog( wxWindow *parent, - wxPageSetupDialogData* data) - : wxPageSetupDialogBase( parent, - wxID_ANY, - _("Page Setup"), - wxPoint(0,0), - wxSize(600, 600), - wxDEFAULT_DIALOG_STYLE|wxTAB_TRAVERSAL ) -{ - if (data) - m_pageData = *data; - - int textWidth = 80; - - wxBoxSizer *mainsizer = new wxBoxSizer( wxVERTICAL ); - - // 1) top - wxStaticBoxSizer *topsizer = new wxStaticBoxSizer( - new wxStaticBox(this,wxPRINTID_STATIC, _("Paper size")), wxHORIZONTAL ); - - size_t n = wxThePrintPaperDatabase->GetCount(); - wxString *choices = new wxString [n]; - - for (size_t i = 0; i < n; i++) - { - wxPrintPaperType *paper = wxThePrintPaperDatabase->Item(i); - choices[i] = paper->GetName(); - } - - m_paperTypeChoice = new wxComboBox( this, - wxPRINTID_PAPERSIZE, - _("Paper Size"), - wxDefaultPosition, - wxSize(300, wxDefaultCoord), - n, choices ); - topsizer->Add( m_paperTypeChoice, 1, wxEXPAND|wxALL, 5 ); -// m_paperTypeChoice->SetSelection(sel); - - mainsizer->Add( topsizer, 0, wxTOP|wxLEFT|wxRIGHT | wxEXPAND, 10 ); - - // 2) middle sizer with radio box - - wxString *choices2 = new wxString[2]; - choices2[0] = _("Portrait"); - choices2[1] = _("Landscape"); - m_orientationRadioBox = new wxRadioBox(this, wxPRINTID_ORIENTATION, _("Orientation"), - wxDefaultPosition, wxDefaultSize, 2, choices2, 2); - m_orientationRadioBox->SetSelection(0); - - mainsizer->Add( m_orientationRadioBox, 0, wxTOP|wxLEFT|wxRIGHT, 10 ); - - // 3) margins - - wxBoxSizer *table = new wxBoxSizer( wxHORIZONTAL ); - - wxBoxSizer *column1 = new wxBoxSizer( wxVERTICAL ); - column1->Add( new wxStaticText(this, wxPRINTID_STATIC, _("Left margin (mm):")),1,wxALL|wxALIGN_RIGHT,5 ); - column1->Add( new wxStaticText(this, wxPRINTID_STATIC, _("Top margin (mm):")),1,wxALL|wxALIGN_RIGHT,5 ); - table->Add( column1, 0, wxALL | wxEXPAND, 5 ); - - wxBoxSizer *column2 = new wxBoxSizer( wxVERTICAL ); - m_marginLeftText = new wxTextCtrl(this, wxPRINTID_LEFTMARGIN, wxEmptyString, wxDefaultPosition, wxSize(textWidth, wxDefaultCoord)); - m_marginTopText = new wxTextCtrl(this, wxPRINTID_TOPMARGIN, wxEmptyString, wxDefaultPosition, wxSize(textWidth, wxDefaultCoord)); - column2->Add( m_marginLeftText, 1, wxALL, 5 ); - column2->Add( m_marginTopText, 1, wxALL, 5 ); - table->Add( column2, 0, wxRIGHT|wxTOP|wxBOTTOM | wxEXPAND, 5 ); - - wxBoxSizer *column3 = new wxBoxSizer( wxVERTICAL ); - column3->Add( new wxStaticText(this, wxPRINTID_STATIC, _("Right margin (mm):")),1,wxALL|wxALIGN_RIGHT,5 ); - column3->Add( new wxStaticText(this, wxPRINTID_STATIC, _("Bottom margin (mm):")),1,wxALL|wxALIGN_RIGHT,5 ); - table->Add( column3, 0, wxALL | wxEXPAND, 5 ); - - wxBoxSizer *column4 = new wxBoxSizer( wxVERTICAL ); - m_marginRightText = new wxTextCtrl(this, wxPRINTID_RIGHTMARGIN, wxEmptyString, wxDefaultPosition, wxSize(textWidth, wxDefaultCoord)); - m_marginBottomText = new wxTextCtrl(this, wxPRINTID_BOTTOMMARGIN, wxEmptyString, wxDefaultPosition, wxSize(textWidth, wxDefaultCoord)); - column4->Add( m_marginRightText, 1, wxALL, 5 ); - column4->Add( m_marginBottomText, 1, wxALL, 5 ); - table->Add( column4, 0, wxRIGHT|wxTOP|wxBOTTOM | wxEXPAND, 5 ); - - mainsizer->Add( table, 0 ); - -#if wxUSE_STATLINE - // 5) static line - mainsizer->Add( new wxStaticLine( this, wxID_ANY ), 0, wxEXPAND | wxLEFT|wxRIGHT|wxTOP, 10 ); -#endif - - // 6) buttons - - wxSizer* buttonsizer = CreateButtonSizer( wxOK|wxCANCEL); - - if (wxPrintFactory::GetFactory()->HasPrintSetupDialog()) - { - m_printerButton = new wxButton(this, wxPRINTID_SETUP, _("Printer...") ); - buttonsizer->Add( m_printerButton, 0, wxLEFT|wxRIGHT, 10 ); - if ( !m_pageData.GetEnablePrinter() ) - m_printerButton->Enable(false); - } - else - { - m_printerButton = NULL; - } - - // if (m_printData.GetEnableHelp()) - // wxButton *helpButton = new wxButton(this, (wxFunction)wxGenericPageSetupHelpProc, _("Help"), wxDefaultCoord, wxDefaultCoord, buttonWidth, buttonHeight); - mainsizer->Add( buttonsizer, 0, wxEXPAND|wxALL, 10 ); - - - SetAutoLayout( true ); - SetSizer( mainsizer ); - - mainsizer->Fit( this ); - Centre(wxBOTH); - - InitDialog(); - - delete[] choices; - delete [] choices2; -} - -wxGenericPageSetupDialog::~wxGenericPageSetupDialog() -{ -} - -wxPageSetupDialogData& wxGenericPageSetupDialog::GetPageSetupDialogData() -{ - return m_pageData; -} - -bool wxGenericPageSetupDialog::TransferDataToWindow() -{ - if (m_marginLeftText) - m_marginLeftText->SetValue(wxString::Format(wxT("%d"), m_pageData.GetMarginTopLeft().x)); - if (m_marginTopText) - m_marginTopText->SetValue(wxString::Format(wxT("%d"), m_pageData.GetMarginTopLeft().y)); - if (m_marginRightText) - m_marginRightText->SetValue(wxString::Format(wxT("%d"), m_pageData.GetMarginBottomRight().x)); - if (m_marginBottomText) - m_marginBottomText->SetValue(wxString::Format(wxT("%d"), m_pageData.GetMarginBottomRight().y)); - - if (m_orientationRadioBox) - { - if (m_pageData.GetPrintData().GetOrientation() == wxPORTRAIT) - m_orientationRadioBox->SetSelection(0); - else - m_orientationRadioBox->SetSelection(1); - } - - // Find the paper type from either the current paper size in the wxPageSetupDialogData, or - // failing that, the id in the wxPrintData object. - - wxPrintPaperType* type = wxThePrintPaperDatabase->FindPaperType( - wxSize(m_pageData.GetPaperSize().x * 10, m_pageData.GetPaperSize().y * 10)); - - if (!type && m_pageData.GetPrintData().GetPaperId() != wxPAPER_NONE) - type = wxThePrintPaperDatabase->FindPaperType(m_pageData.GetPrintData().GetPaperId()); - - if (type) - { - m_paperTypeChoice->SetStringSelection(type->GetName()); - } - - return true; -} - -bool wxGenericPageSetupDialog::TransferDataFromWindow() -{ - if (m_marginLeftText && m_marginTopText) - { - int left = wxAtoi( m_marginLeftText->GetValue().c_str() ); - int top = wxAtoi( m_marginTopText->GetValue().c_str() ); - m_pageData.SetMarginTopLeft( wxPoint(left,top) ); - } - if (m_marginRightText && m_marginBottomText) - { - int right = wxAtoi( m_marginRightText->GetValue().c_str() ); - int bottom = wxAtoi( m_marginBottomText->GetValue().c_str() ); - m_pageData.SetMarginBottomRight( wxPoint(right,bottom) ); - } - - if (m_orientationRadioBox) - { - int sel = m_orientationRadioBox->GetSelection(); - if (sel == 0) - { - m_pageData.GetPrintData().SetOrientation(wxPORTRAIT); - } - else - { - m_pageData.GetPrintData().SetOrientation(wxLANDSCAPE); - } - } - - if (m_paperTypeChoice) - { - int selectedItem = m_paperTypeChoice->GetSelection(); - if (selectedItem != -1) - { - wxPrintPaperType *paper = wxThePrintPaperDatabase->Item(selectedItem); - if ( paper ) - { - m_pageData.SetPaperSize(wxSize(paper->GetWidth()/10, paper->GetHeight()/10)); - m_pageData.GetPrintData().SetPaperId(paper->GetId()); - } - } - } - - return true; -} - -wxComboBox *wxGenericPageSetupDialog::CreatePaperTypeChoice(int *x, int *y) -{ -/* - if (!wxThePrintPaperDatabase) - { - wxThePrintPaperDatabase = new wxPrintPaperDatabase; - wxThePrintPaperDatabase->CreateDatabase(); - } -*/ - - size_t n = wxThePrintPaperDatabase->GetCount(); - wxString *choices = new wxString [n]; - - for (size_t i = 0; i < n; i++) - { - wxPrintPaperType *paper = wxThePrintPaperDatabase->Item(i); - choices[i] = paper->GetName(); - } - - (void) new wxStaticText(this, wxPRINTID_STATIC, _("Paper size"), wxPoint(*x, *y)); - *y += 25; - - wxComboBox *choice = new wxComboBox( this, - wxPRINTID_PAPERSIZE, - _("Paper Size"), - wxPoint(*x, *y), - wxSize(300, wxDefaultCoord), - n, choices ); - *y += 35; - delete[] choices; - -// choice->SetSelection(sel); - return choice; -} - -void wxGenericPageSetupDialog::OnPrinter(wxCommandEvent& WXUNUSED(event)) -{ - // We no longer query GetPrintMode, so we can eliminate the need - // to call SetPrintMode. - // This has the limitation that we can't explicitly call the PostScript - // print setup dialog from the generic Page Setup dialog under Windows, - // but since this choice would only happen when trying to do PostScript - // printing under Windows (and only in 16-bit Windows which - // doesn't have a Windows-specific page setup dialog) it's worth it. - - // First save the current settings, so the wxPrintData object is up to date. - TransferDataFromWindow(); - - // Transfer the current print settings from this dialog to the page setup dialog. - -#if 0 - // Use print factory later - - wxPrintDialogData data; - data = GetPageSetupData().GetPrintData(); - data.SetSetupDialog(true); - wxPrintDialog printDialog(this, & data); - printDialog.ShowModal(); - - // Transfer the page setup print settings from the page dialog to this dialog again, in case - // the page setup dialog changed something. - GetPageSetupData().GetPrintData() = printDialog.GetPrintDialogData().GetPrintData(); - GetPageSetupData().CalculatePaperSizeFromId(); // Make sure page size reflects the id in wxPrintData - - // Now update the dialog in case the page setup dialog changed some of our settings. - TransferDataToWindow(); -#endif -} - -#endif +///////////////////////////////////////////////////////////////////////////// +// Name: src/generic/prntdlgg.cpp +// Purpose: Generic print dialogs +// Author: Julian Smart +// Modified by: +// Created: 04/01/98 +// RCS-ID: $Id: prntdlgg.cpp 50289 2007-11-28 00:24:25Z VZ $ +// Copyright: (c) Julian Smart +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_PRINTING_ARCHITECTURE && (!defined(__WXMSW__) || wxUSE_POSTSCRIPT_ARCHITECTURE_IN_MSW) + +#include "wx/generic/prntdlgg.h" + +#ifndef WX_PRECOMP + #include "wx/utils.h" + #include "wx/dc.h" + #include "wx/stattext.h" + #include "wx/statbox.h" + #include "wx/button.h" + #include "wx/checkbox.h" + #include "wx/textctrl.h" + #include "wx/radiobox.h" + #include "wx/filedlg.h" + #include "wx/combobox.h" + #include "wx/intl.h" + #include "wx/sizer.h" + #include "wx/cmndata.h" +#endif + +#if wxUSE_STATLINE + #include "wx/statline.h" +#endif + +#if wxUSE_POSTSCRIPT + #include "wx/generic/dcpsg.h" +#endif + +#include "wx/prntbase.h" +#include "wx/printdlg.h" +#include "wx/paper.h" +#include "wx/filename.h" +#include "wx/tokenzr.h" +#include "wx/imaglist.h" + +#include +#include + +#ifndef __WXUNIVERSAL__ + +#if wxUSE_LIBGNOMEPRINT + #include "wx/link.h" + wxFORCE_LINK_MODULE(gnome_print) +#endif + +#endif // !__WXUNIVERSAL__ + +// ---------------------------------------------------------------------------- +// global vars +// ---------------------------------------------------------------------------- + +extern wxPrintPaperDatabase *wxThePrintPaperDatabase; + +#if wxUSE_POSTSCRIPT + +//---------------------------------------------------------------------------- +// wxPostScriptNativeData +//---------------------------------------------------------------------------- + +IMPLEMENT_CLASS(wxPostScriptPrintNativeData, wxPrintNativeDataBase) + +wxPostScriptPrintNativeData::wxPostScriptPrintNativeData() +{ + m_previewCommand = wxEmptyString; +#ifdef __VMS__ + m_printerCommand = wxT("print"); + m_printerOptions = wxT("/nonotify/queue=psqueue"); + m_afmPath = wxT("sys$ps_font_metrics:"); +#endif + +#ifdef __WXMSW__ + m_printerCommand = wxT("print"); + m_printerOptions = wxEmptyString; + m_afmPath = wxT("c:\\windows\\system\\"); +#endif + +#if !defined(__VMS__) && !defined(__WXMSW__) + m_printerCommand = wxT("lpr"); + m_printerOptions = wxEmptyString; + m_afmPath = wxEmptyString; +#endif + + m_printerScaleX = 1.0; + m_printerScaleY = 1.0; + m_printerTranslateX = 0; + m_printerTranslateY = 0; +} + +wxPostScriptPrintNativeData::~wxPostScriptPrintNativeData() +{ +} + +bool wxPostScriptPrintNativeData::TransferTo( wxPrintData &WXUNUSED(data) ) +{ + return true; +} + +bool wxPostScriptPrintNativeData::TransferFrom( const wxPrintData &WXUNUSED(data) ) +{ + return true; +} + +// ---------------------------------------------------------------------------- +// Generic print dialog for non-Windows printing use. +// ---------------------------------------------------------------------------- + +IMPLEMENT_CLASS(wxGenericPrintDialog, wxPrintDialogBase) + +BEGIN_EVENT_TABLE(wxGenericPrintDialog, wxPrintDialogBase) + EVT_BUTTON(wxID_OK, wxGenericPrintDialog::OnOK) + EVT_BUTTON(wxPRINTID_SETUP, wxGenericPrintDialog::OnSetup) + EVT_RADIOBOX(wxPRINTID_RANGE, wxGenericPrintDialog::OnRange) +END_EVENT_TABLE() + +wxGenericPrintDialog::wxGenericPrintDialog(wxWindow *parent, + wxPrintDialogData* data) + : wxPrintDialogBase(parent, wxID_ANY, _("Print"), + wxPoint(0,0), wxSize(600, 600), + wxDEFAULT_DIALOG_STYLE | + wxTAB_TRAVERSAL) +{ + if ( data ) + m_printDialogData = *data; + + Init(parent); +} + +wxGenericPrintDialog::wxGenericPrintDialog(wxWindow *parent, + wxPrintData* data) + : wxPrintDialogBase(parent, wxID_ANY, _("Print"), + wxPoint(0,0), wxSize(600, 600), + wxDEFAULT_DIALOG_STYLE | + wxTAB_TRAVERSAL) +{ + if ( data ) + m_printDialogData = *data; + + Init(parent); +} + +void wxGenericPrintDialog::Init(wxWindow * WXUNUSED(parent)) +{ + // wxDialog::Create(parent, wxID_ANY, _("Print"), wxPoint(0,0), wxSize(600, 600), + // wxDEFAULT_DIALOG_STYLE | wxTAB_TRAVERSAL); + + wxBoxSizer *mainsizer = new wxBoxSizer( wxVERTICAL ); + + // 1) top row + + wxPrintFactory* factory = wxPrintFactory::GetFactory(); + + wxStaticBoxSizer *topsizer = new wxStaticBoxSizer( + new wxStaticBox( this, wxID_ANY, _( "Printer options" ) ), wxHORIZONTAL ); + wxFlexGridSizer *flex = new wxFlexGridSizer( 2 ); + flex->AddGrowableCol( 1 ); + topsizer->Add( flex, 1, wxGROW ); + + m_printToFileCheckBox = new wxCheckBox( this, wxPRINTID_PRINTTOFILE, _("Print to File") ); + flex->Add( m_printToFileCheckBox, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 ); + + m_setupButton = new wxButton(this, wxPRINTID_SETUP, _("Setup...") ); + flex->Add( m_setupButton, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_RIGHT|wxALL, 5 ); + + if (!factory->HasPrintSetupDialog()) + m_setupButton->Enable( false ); + + if (factory->HasPrinterLine()) + { + flex->Add( new wxStaticText( this, wxID_ANY, _("Printer:") ), + 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 ); + flex->Add( new wxStaticText( this, wxID_ANY, factory->CreatePrinterLine() ), + 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 ); + } + + if (factory->HasStatusLine()) + { + flex->Add( new wxStaticText( this, wxID_ANY, _("Status:") ), + 0, wxALIGN_CENTER_VERTICAL|wxALL-wxTOP, 5 ); + flex->Add( new wxStaticText( this, wxID_ANY, factory->CreateStatusLine() ), + 0, wxALIGN_CENTER_VERTICAL|wxALL-wxTOP, 5 ); + } + + mainsizer->Add( topsizer, 0, wxLEFT|wxTOP|wxRIGHT|wxGROW, 10 ); + + // 2) middle row with radio box + + wxString *choices = new wxString[2]; + choices[0] = _("All"); + choices[1] = _("Pages"); + + m_fromText = (wxTextCtrl*)NULL; + m_toText = (wxTextCtrl*)NULL; + m_rangeRadioBox = (wxRadioBox *)NULL; + + if (m_printDialogData.GetFromPage() != 0) + { + m_rangeRadioBox = new wxRadioBox(this, wxPRINTID_RANGE, _("Print Range"), + wxDefaultPosition, wxDefaultSize, + 2, choices, + 1, wxRA_VERTICAL); + m_rangeRadioBox->SetSelection(1); + + mainsizer->Add( m_rangeRadioBox, 0, wxLEFT|wxTOP|wxRIGHT, 10 ); + } + + // 3) bottom row + + wxBoxSizer *bottomsizer = new wxBoxSizer( wxHORIZONTAL ); + + if (m_printDialogData.GetFromPage() != 0) + { + bottomsizer->Add( new wxStaticText(this, wxPRINTID_STATIC, _("From:") ), 0, wxCENTER|wxALL, 5 ); + m_fromText = new wxTextCtrl(this, wxPRINTID_FROM, wxEmptyString, wxDefaultPosition, wxSize(40, wxDefaultCoord)); + bottomsizer->Add( m_fromText, 1, wxCENTER|wxRIGHT, 10 ); + + bottomsizer->Add( new wxStaticText(this, wxPRINTID_STATIC, _("To:") ), 0, wxCENTER|wxALL, 5); + m_toText = new wxTextCtrl(this, wxPRINTID_TO, wxEmptyString, wxDefaultPosition, wxSize(40, wxDefaultCoord)); + bottomsizer->Add( m_toText, 1, wxCENTER|wxRIGHT, 10 ); + } + + bottomsizer->Add( new wxStaticText(this, wxPRINTID_STATIC, _("Copies:") ), 0, wxCENTER|wxALL, 5 ); + m_noCopiesText = new wxTextCtrl(this, wxPRINTID_COPIES, wxEmptyString, wxPoint(252, 130), wxSize(40, wxDefaultCoord)); + bottomsizer->Add( m_noCopiesText, 1, wxCENTER|wxRIGHT, 10 ); + + mainsizer->Add( bottomsizer, 0, wxTOP|wxLEFT|wxRIGHT, 12 ); + + // 4) buttons + + wxSizer *sizerBtn = CreateSeparatedButtonSizer( wxOK|wxCANCEL); + if ( sizerBtn ) + mainsizer->Add(sizerBtn, 0, wxEXPAND|wxALL, 10 ); + + SetAutoLayout( true ); + SetSizer( mainsizer ); + + mainsizer->Fit( this ); + Centre(wxBOTH); + + // Calls wxWindow::OnInitDialog and then wxGenericPrintDialog::TransferDataToWindow + InitDialog(); + delete[] choices; +} + +int wxGenericPrintDialog::ShowModal() +{ + return wxDialog::ShowModal(); +} + +wxGenericPrintDialog::~wxGenericPrintDialog() +{ +} + +void wxGenericPrintDialog::OnOK(wxCommandEvent& WXUNUSED(event)) +{ + TransferDataFromWindow(); + + // An empty 'to' field signals printing just the + // 'from' page. + if (m_printDialogData.GetToPage() < 1) + m_printDialogData.SetToPage(m_printDialogData.GetFromPage()); + + // There are some interactions between the global setup data + // and the standard print dialog. The global printing 'mode' + // is determined by whether the user checks Print to file + // or not. + if (m_printDialogData.GetPrintToFile()) + { + m_printDialogData.GetPrintData().SetPrintMode(wxPRINT_MODE_FILE); + + wxFileName fname( m_printDialogData.GetPrintData().GetFilename() ); + + wxFileDialog dialog( this, _("PostScript file"), + fname.GetPath(), fname.GetFullName(), wxT("*.ps"), wxFD_SAVE | wxFD_OVERWRITE_PROMPT ); + if (dialog.ShowModal() != wxID_OK) return; + + m_printDialogData.GetPrintData().SetFilename( dialog.GetPath() ); + } + else + { + m_printDialogData.GetPrintData().SetPrintMode(wxPRINT_MODE_PRINTER); + } + + EndModal(wxID_OK); +} + +void wxGenericPrintDialog::OnRange(wxCommandEvent& event) +{ + if (!m_fromText) return; + + if (event.GetInt() == 0) + { + m_fromText->Enable(false); + m_toText->Enable(false); + } + else if (event.GetInt() == 1) + { + m_fromText->Enable(true); + m_toText->Enable(true); + } +} + +void wxGenericPrintDialog::OnSetup(wxCommandEvent& WXUNUSED(event)) +{ + wxPrintFactory* factory = wxPrintFactory::GetFactory(); + + if (factory->HasPrintSetupDialog()) + { + // The print setup dialog should change the + // print data in-place if not cancelled. + wxDialog *dialog = factory->CreatePrintSetupDialog( this, &m_printDialogData.GetPrintData() ); + dialog->ShowModal(); + dialog->Destroy(); + } +} + +bool wxGenericPrintDialog::TransferDataToWindow() +{ + if(m_printDialogData.GetFromPage() != 0) + { + if(m_fromText) + { + if (m_printDialogData.GetEnablePageNumbers()) + { + m_fromText->Enable(true); + m_toText->Enable(true); + if (m_printDialogData.GetFromPage() > 0) + m_fromText->SetValue(wxString::Format(_T("%d"), m_printDialogData.GetFromPage())); + if (m_printDialogData.GetToPage() > 0) + m_toText->SetValue(wxString::Format(_T("%d"), m_printDialogData.GetToPage())); + if(m_rangeRadioBox) + if (m_printDialogData.GetAllPages() || m_printDialogData.GetFromPage() == 0) + m_rangeRadioBox->SetSelection(0); + else + m_rangeRadioBox->SetSelection(1); + } + else + { + m_fromText->Enable(false); + m_toText->Enable(false); + if(m_rangeRadioBox) + { + m_rangeRadioBox->SetSelection(0); + m_rangeRadioBox->wxRadioBox::Enable(1, false); + } + } + } + } + m_noCopiesText->SetValue( + wxString::Format(_T("%d"), m_printDialogData.GetNoCopies())); + + m_printToFileCheckBox->SetValue(m_printDialogData.GetPrintToFile()); + m_printToFileCheckBox->Enable(m_printDialogData.GetEnablePrintToFile()); + return true; +} + +bool wxGenericPrintDialog::TransferDataFromWindow() +{ + long res = 0; + if(m_printDialogData.GetFromPage() != -1) + { + if (m_printDialogData.GetEnablePageNumbers()) + { + if(m_fromText) + { + wxString value = m_fromText->GetValue(); + if (value.ToLong( &res )) + m_printDialogData.SetFromPage( res ); + } + if(m_toText) + { + wxString value = m_toText->GetValue(); + if (value.ToLong( &res )) + m_printDialogData.SetToPage( res ); + } + } + if(m_rangeRadioBox) + { + if (m_rangeRadioBox->GetSelection() == 0) + { + m_printDialogData.SetAllPages(true); + + // This means all pages, more or less + m_printDialogData.SetFromPage(1); + m_printDialogData.SetToPage(32000); + } + else + m_printDialogData.SetAllPages(false); + } + } + else + { // continuous printing + m_printDialogData.SetFromPage(1); + m_printDialogData.SetToPage(32000); + } + + wxString value = m_noCopiesText->GetValue(); + if (value.ToLong( &res )) + m_printDialogData.SetNoCopies( res ); + + m_printDialogData.SetPrintToFile(m_printToFileCheckBox->GetValue()); + + return true; +} + +wxDC *wxGenericPrintDialog::GetPrintDC() +{ + return new wxPostScriptDC(GetPrintDialogData().GetPrintData()); +} + +// ---------------------------------------------------------------------------- +// Generic print setup dialog +// ---------------------------------------------------------------------------- + +IMPLEMENT_CLASS(wxGenericPrintSetupDialog, wxDialog) + +BEGIN_EVENT_TABLE(wxGenericPrintSetupDialog, wxDialog) + EVT_LIST_ITEM_ACTIVATED(wxPRINTID_PRINTER, wxGenericPrintSetupDialog::OnPrinter) +END_EVENT_TABLE() + +wxGenericPrintSetupDialog::wxGenericPrintSetupDialog(wxWindow *parent, wxPrintData* data): +wxDialog(parent, wxID_ANY, _("Print Setup"), wxPoint(0,0), wxSize(600, 600), wxDEFAULT_DIALOG_STYLE|wxTAB_TRAVERSAL) +{ + Init(data); +} + +/* XPM */ +static const char * check_xpm[] = { +/* width height ncolors chars_per_pixel */ +"16 16 3 1", +/* colors */ +" s None c None", +"X c #000000", +". c #808080", +/* pixels */ +" ", +" ", +" ", +" .. ", +" XX ", +" XX. ", +" .XX ", +" XX ", +" X XX. ", +" XX .XX ", +" XX XX ", +" XXXX. ", +" XX. ", +" . ", +" ", +" " +}; + + +void wxGenericPrintSetupDialog::Init(wxPrintData* data) +{ + if ( data ) + m_printData = *data; + + m_targetData = data; + + wxBoxSizer *main_sizer = new wxBoxSizer( wxVERTICAL ); + + // printer selection + + wxStaticBoxSizer *printer_sizer = new wxStaticBoxSizer( new wxStaticBox( this, wxID_ANY, _("Printer") ), wxVERTICAL ); + main_sizer->Add( printer_sizer, 0, wxALL|wxGROW, 10 ); + + m_printerListCtrl = new wxListCtrl( this, wxPRINTID_PRINTER, + wxDefaultPosition, wxSize(wxDefaultCoord,100), wxLC_REPORT|wxLC_SINGLE_SEL|wxSUNKEN_BORDER ); + wxImageList *image_list = new wxImageList; + image_list->Add( wxBitmap(check_xpm) ); + m_printerListCtrl->AssignImageList( image_list, wxIMAGE_LIST_SMALL ); + + m_printerListCtrl->InsertColumn( 0, wxT(" "), wxLIST_FORMAT_LEFT, 20 ); + m_printerListCtrl->InsertColumn( 1, wxT("Printer"), wxLIST_FORMAT_LEFT, 150 ); + m_printerListCtrl->InsertColumn( 2, wxT("Device"), wxLIST_FORMAT_LEFT, 150 ); + m_printerListCtrl->InsertColumn( 3, wxT("Status"), wxLIST_FORMAT_LEFT, 80 ); + + wxListItem item; + item.SetMask( wxLIST_MASK_TEXT ); + item.SetColumn( 1 ); + item.SetText( _("Default printer") ); + item.SetId( m_printerListCtrl->InsertItem( item ) ); + + if (data->GetPrinterName().empty()) + { + wxListItem item2; + item2.SetId( item.GetId() ); + item2.SetMask( wxLIST_MASK_IMAGE ); + item2.SetImage( 0 ); + m_printerListCtrl->SetItem( item2 ); + // also select item + m_printerListCtrl->SetItemState( item.GetId(), wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED ); + } + + item.SetId( 1+ item.GetId() ); + + wxArrayString errors; + wxArrayString output; + long res = wxExecute( wxT("lpstat -v"), output, errors, wxEXEC_NODISABLE ); + if (res >= 0 && errors.GetCount() == 0) + { + size_t i; + for (i = 0; i < output.GetCount(); i++) + { + wxStringTokenizer tok( output[i], wxT(" ") ); + wxString tmp = tok.GetNextToken(); // "device" + if (tmp != wxT("device")) + break; // the lpstat syntax must have changed. + tmp = tok.GetNextToken(); // "for" + if (tmp != wxT("for")) + break; // the lpstat syntax must have changed. + tmp = tok.GetNextToken(); // "hp_deskjet930c:" + if (tmp[tmp.length()-1] == wxT(':')) + tmp.Remove(tmp.length()-1,1); + wxString name = tmp; + item.SetText( name ); + item.SetId( m_printerListCtrl->InsertItem( item ) ); + tmp = tok.GetNextToken(); // "parallel:/dev/lp0" + item.SetColumn( 2 ); + item.SetText( tmp ); + m_printerListCtrl->SetItem( item ); + if (data->GetPrinterName() == name) + { + wxListItem item2; + item2.SetId( item.GetId() ); + item2.SetMask( wxLIST_MASK_IMAGE ); + item2.SetImage( 0 ); + m_printerListCtrl->SetItem( item2 ); + // also select item + m_printerListCtrl->SetItemState( item.GetId(), wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED ); + } + + wxString command = wxT("lpstat -p "); + command += name; + wxArrayString errors2; + wxArrayString output2; + res = wxExecute( command, output2, errors2, wxEXEC_NODISABLE ); + if (res >= 0 && errors2.GetCount() == 0 && output2.GetCount() > 0) + { + tmp = output2[0]; // "printer hp_deskjet930c is idle. enable since ..." + int pos = tmp.Find( wxT('.') ); + if (pos != wxNOT_FOUND) + tmp.Remove( (size_t)pos, tmp.length()-(size_t)pos ); + wxStringTokenizer tok2( tmp, wxT(" ") ); + tmp = tok2.GetNextToken(); // "printer" + tmp = tok2.GetNextToken(); // "hp_deskjet930c" + tmp = wxEmptyString; + while (tok2.HasMoreTokens()) + { + tmp += tok2.GetNextToken(); + tmp += wxT(" "); + } + item.SetColumn( 3 ); + item.SetText( tmp ); + m_printerListCtrl->SetItem( item ); + } + + item.SetColumn( 1 ); + item.SetId( 1+ item.GetId() ); + } + } + + + printer_sizer->Add( m_printerListCtrl, 0, wxALL|wxGROW, 5 ); + + wxBoxSizer *item1 = new wxBoxSizer( wxHORIZONTAL ); + main_sizer->Add( item1, 0, wxALL, 5 ); + + // printer options (on the left) + + wxBoxSizer *item2 = new wxBoxSizer( wxVERTICAL ); + + wxStaticBox *item4 = new wxStaticBox( this, wxPRINTID_STATIC, _("Paper size") ); + wxStaticBoxSizer *item3 = new wxStaticBoxSizer( item4, wxVERTICAL ); + + m_paperTypeChoice = CreatePaperTypeChoice(); + item3->Add( m_paperTypeChoice, 0, wxALIGN_CENTER|wxALL, 5 ); + + item2->Add( item3, 0, wxALIGN_CENTER|wxALL, 5 ); + + wxString strs6[] = + { + _("Portrait"), + _("Landscape") + }; + m_orientationRadioBox= new wxRadioBox( this, wxPRINTID_ORIENTATION, _("Orientation"), wxDefaultPosition, wxDefaultSize, 2, strs6, 1, wxRA_SPECIFY_ROWS ); + item2->Add( m_orientationRadioBox, 0, wxGROW|wxALIGN_CENTER_VERTICAL|wxALL, 5 ); + + wxStaticBox *item8 = new wxStaticBox( this, wxID_ANY, _("Options") ); + wxStaticBoxSizer *item7 = new wxStaticBoxSizer( item8, wxHORIZONTAL ); + + m_colourCheckBox = new wxCheckBox( this, wxPRINTID_PRINTCOLOUR, _("Print in colour") ); + item7->Add( m_colourCheckBox, 0, wxALIGN_CENTER|wxALL, 5 ); + + item2->Add( item7, 0, wxGROW|wxALIGN_CENTER_VERTICAL|wxALL, 5 ); + + item1->Add( item2, 0, wxALIGN_CENTER_HORIZONTAL, 5 ); + + // spooling options (on the right) + + wxStaticBox *item11 = new wxStaticBox( this, wxID_ANY, _("Print spooling") ); + wxStaticBoxSizer *item10 = new wxStaticBoxSizer( item11, wxVERTICAL ); + + wxStaticText *item12 = new wxStaticText( this, wxID_ANY, _("Printer command:") ); + item10->Add( item12, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 ); + + wxBoxSizer *item13 = new wxBoxSizer( wxHORIZONTAL ); + + item13->Add( 20, 20, 0, wxALIGN_CENTER|wxALL, 5 ); + + m_printerCommandText = new wxTextCtrl( this, wxPRINTID_COMMAND, wxEmptyString, wxDefaultPosition, wxSize(160,wxDefaultCoord) ); + item13->Add( m_printerCommandText, 0, wxALIGN_CENTER|wxALL, 5 ); + + item10->Add( item13, 0, wxALIGN_CENTER|wxALL, 0 ); + + wxStaticText *item15 = new wxStaticText( this, wxID_ANY, _("Printer options:") ); + item10->Add( item15, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 ); + + wxBoxSizer *item16 = new wxBoxSizer( wxHORIZONTAL ); + + item16->Add( 20, 20, 0, wxALIGN_CENTER|wxALL, 5 ); + + m_printerOptionsText = new wxTextCtrl( this, wxPRINTID_OPTIONS, wxEmptyString, wxDefaultPosition, wxSize(160,wxDefaultCoord) ); + item16->Add( m_printerOptionsText, 0, wxALIGN_CENTER|wxALL, 5 ); + + item10->Add( item16, 0, wxALIGN_CENTER|wxALL, 0 ); + + item1->Add( item10, 0, wxALIGN_CENTER_HORIZONTAL|wxALL, 5 ); + + +#if wxUSE_STATLINE + // static line + main_sizer->Add( new wxStaticLine( this, wxID_ANY ), 0, wxEXPAND | wxLEFT|wxRIGHT|wxTOP, 10 ); +#endif + + // buttons + + main_sizer->Add( CreateButtonSizer( wxOK|wxCANCEL), 0, wxEXPAND|wxALL, 10 ); + + SetAutoLayout( true ); + SetSizer( main_sizer ); + + main_sizer->Fit( this ); + Centre(wxBOTH); + + + Fit(); + Centre(wxBOTH); + + InitDialog(); +} + +wxGenericPrintSetupDialog::~wxGenericPrintSetupDialog() +{ +} + +void wxGenericPrintSetupDialog::OnPrinter(wxListEvent& event) +{ + // Delete check mark + for (long item = 0; item < m_printerListCtrl->GetItemCount(); item++) + m_printerListCtrl->SetItemImage( item, -1 ); + + m_printerListCtrl->SetItemImage( event.GetIndex(), 0 ); + + if (event.GetIndex() == 0) + { + m_printerCommandText->SetValue( wxT("lpr") ); + } + else + { + wxListItem li; + li.SetColumn( 1 ); + li.SetMask( wxLIST_MASK_TEXT ); + li.SetId( event.GetIndex() ); + m_printerListCtrl->GetItem( li ); + m_printerCommandText->SetValue( _T("lpr -P") + li.GetText() ); + } +} + +bool wxGenericPrintSetupDialog::TransferDataToWindow() +{ + wxPostScriptPrintNativeData *data = + (wxPostScriptPrintNativeData *) m_printData.GetNativeData(); + + if (m_printerCommandText && data->GetPrinterCommand()) + m_printerCommandText->SetValue(data->GetPrinterCommand()); + if (m_printerOptionsText && data->GetPrinterOptions()) + m_printerOptionsText->SetValue(data->GetPrinterOptions()); + if (m_colourCheckBox) + m_colourCheckBox->SetValue(m_printData.GetColour()); + + if (m_orientationRadioBox) + { + if (m_printData.GetOrientation() == wxPORTRAIT) + m_orientationRadioBox->SetSelection(0); + else + m_orientationRadioBox->SetSelection(1); + } + return true; +} + +bool wxGenericPrintSetupDialog::TransferDataFromWindow() +{ + wxPostScriptPrintNativeData *data = + (wxPostScriptPrintNativeData *) m_printData.GetNativeData(); + + // find selected printer + long id = m_printerListCtrl->GetNextItem( -1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED ); + if (id == 0) + { + m_printData.SetPrinterName( wxEmptyString ); + } + else + { + wxListItem item; + item.SetId( id ); + item.SetMask( wxLIST_MASK_TEXT ); + item.SetColumn( 1 ); + m_printerListCtrl->GetItem( item ); + m_printData.SetPrinterName( item.GetText() ); + } + + if (m_printerCommandText) + data->SetPrinterCommand(m_printerCommandText->GetValue()); + if (m_printerOptionsText) + data->SetPrinterOptions(m_printerOptionsText->GetValue()); + if (m_colourCheckBox) + m_printData.SetColour(m_colourCheckBox->GetValue()); + if (m_orientationRadioBox) + { + int sel = m_orientationRadioBox->GetSelection(); + if (sel == 0) + m_printData.SetOrientation(wxPORTRAIT); + else + m_printData.SetOrientation(wxLANDSCAPE); + } + if (m_paperTypeChoice) + { + int selectedItem = m_paperTypeChoice->GetSelection(); + if (selectedItem != -1) + { + wxPrintPaperType *paper = wxThePrintPaperDatabase->Item(selectedItem); + if (paper != NULL) + m_printData.SetPaperId( paper->GetId()); + } + } + + if (m_targetData) + *m_targetData = m_printData; + + return true; +} + +wxComboBox *wxGenericPrintSetupDialog::CreatePaperTypeChoice() +{ + size_t n = wxThePrintPaperDatabase->GetCount(); + wxString *choices = new wxString [n]; + size_t sel = 0; + + for (size_t i = 0; i < n; i++) + { + wxPrintPaperType *paper = wxThePrintPaperDatabase->Item(i); + choices[i] = paper->GetName(); + if (m_printData.GetPaperId() == paper->GetId()) + sel = i; + } + + int width = 250; + + wxComboBox *choice = new wxComboBox( this, + wxPRINTID_PAPERSIZE, + _("Paper Size"), + wxDefaultPosition, + wxSize(width, wxDefaultCoord), + n, choices ); + + delete[] choices; + + choice->SetSelection(sel); + return choice; +} + +#endif // wxUSE_POSTSCRIPT + +// ---------------------------------------------------------------------------- +// Generic page setup dialog +// ---------------------------------------------------------------------------- + +IMPLEMENT_CLASS(wxGenericPageSetupDialog, wxPageSetupDialogBase) + +BEGIN_EVENT_TABLE(wxGenericPageSetupDialog, wxPageSetupDialogBase) + EVT_BUTTON(wxPRINTID_SETUP, wxGenericPageSetupDialog::OnPrinter) +END_EVENT_TABLE() + +wxGenericPageSetupDialog::wxGenericPageSetupDialog( wxWindow *parent, + wxPageSetupDialogData* data) + : wxPageSetupDialogBase( parent, + wxID_ANY, + _("Page Setup"), + wxPoint(0,0), + wxSize(600, 600), + wxDEFAULT_DIALOG_STYLE|wxTAB_TRAVERSAL ) +{ + if (data) + m_pageData = *data; + + int textWidth = 80; + + wxBoxSizer *mainsizer = new wxBoxSizer( wxVERTICAL ); + + // 1) top + wxStaticBoxSizer *topsizer = new wxStaticBoxSizer( + new wxStaticBox(this,wxPRINTID_STATIC, _("Paper size")), wxHORIZONTAL ); + + size_t n = wxThePrintPaperDatabase->GetCount(); + wxString *choices = new wxString [n]; + + for (size_t i = 0; i < n; i++) + { + wxPrintPaperType *paper = wxThePrintPaperDatabase->Item(i); + choices[i] = paper->GetName(); + } + + m_paperTypeChoice = new wxComboBox( this, + wxPRINTID_PAPERSIZE, + _("Paper Size"), + wxDefaultPosition, + wxSize(300, wxDefaultCoord), + n, choices ); + topsizer->Add( m_paperTypeChoice, 1, wxEXPAND|wxALL, 5 ); +// m_paperTypeChoice->SetSelection(sel); + + mainsizer->Add( topsizer, 0, wxTOP|wxLEFT|wxRIGHT | wxEXPAND, 10 ); + + // 2) middle sizer with radio box + + wxString *choices2 = new wxString[2]; + choices2[0] = _("Portrait"); + choices2[1] = _("Landscape"); + m_orientationRadioBox = new wxRadioBox(this, wxPRINTID_ORIENTATION, _("Orientation"), + wxDefaultPosition, wxDefaultSize, 2, choices2, 2); + m_orientationRadioBox->SetSelection(0); + + mainsizer->Add( m_orientationRadioBox, 0, wxTOP|wxLEFT|wxRIGHT, 10 ); + + // 3) margins + + wxBoxSizer *table = new wxBoxSizer( wxHORIZONTAL ); + + wxBoxSizer *column1 = new wxBoxSizer( wxVERTICAL ); + column1->Add( new wxStaticText(this, wxPRINTID_STATIC, _("Left margin (mm):")),1,wxALL|wxALIGN_RIGHT,5 ); + column1->Add( new wxStaticText(this, wxPRINTID_STATIC, _("Top margin (mm):")),1,wxALL|wxALIGN_RIGHT,5 ); + table->Add( column1, 0, wxALL | wxEXPAND, 5 ); + + wxBoxSizer *column2 = new wxBoxSizer( wxVERTICAL ); + m_marginLeftText = new wxTextCtrl(this, wxPRINTID_LEFTMARGIN, wxEmptyString, wxDefaultPosition, wxSize(textWidth, wxDefaultCoord)); + m_marginTopText = new wxTextCtrl(this, wxPRINTID_TOPMARGIN, wxEmptyString, wxDefaultPosition, wxSize(textWidth, wxDefaultCoord)); + column2->Add( m_marginLeftText, 1, wxALL, 5 ); + column2->Add( m_marginTopText, 1, wxALL, 5 ); + table->Add( column2, 0, wxRIGHT|wxTOP|wxBOTTOM | wxEXPAND, 5 ); + + wxBoxSizer *column3 = new wxBoxSizer( wxVERTICAL ); + column3->Add( new wxStaticText(this, wxPRINTID_STATIC, _("Right margin (mm):")),1,wxALL|wxALIGN_RIGHT,5 ); + column3->Add( new wxStaticText(this, wxPRINTID_STATIC, _("Bottom margin (mm):")),1,wxALL|wxALIGN_RIGHT,5 ); + table->Add( column3, 0, wxALL | wxEXPAND, 5 ); + + wxBoxSizer *column4 = new wxBoxSizer( wxVERTICAL ); + m_marginRightText = new wxTextCtrl(this, wxPRINTID_RIGHTMARGIN, wxEmptyString, wxDefaultPosition, wxSize(textWidth, wxDefaultCoord)); + m_marginBottomText = new wxTextCtrl(this, wxPRINTID_BOTTOMMARGIN, wxEmptyString, wxDefaultPosition, wxSize(textWidth, wxDefaultCoord)); + column4->Add( m_marginRightText, 1, wxALL, 5 ); + column4->Add( m_marginBottomText, 1, wxALL, 5 ); + table->Add( column4, 0, wxRIGHT|wxTOP|wxBOTTOM | wxEXPAND, 5 ); + + mainsizer->Add( table, 0 ); + +#if wxUSE_STATLINE + // 5) static line + mainsizer->Add( new wxStaticLine( this, wxID_ANY ), 0, wxEXPAND | wxLEFT|wxRIGHT|wxTOP, 10 ); +#endif + + // 6) buttons + + wxSizer* buttonsizer = CreateButtonSizer( wxOK|wxCANCEL); + + if (wxPrintFactory::GetFactory()->HasPrintSetupDialog()) + { + m_printerButton = new wxButton(this, wxPRINTID_SETUP, _("Printer...") ); + buttonsizer->Add( m_printerButton, 0, wxLEFT|wxRIGHT, 10 ); + if ( !m_pageData.GetEnablePrinter() ) + m_printerButton->Enable(false); + } + else + { + m_printerButton = NULL; + } + + // if (m_printData.GetEnableHelp()) + // wxButton *helpButton = new wxButton(this, (wxFunction)wxGenericPageSetupHelpProc, _("Help"), wxDefaultCoord, wxDefaultCoord, buttonWidth, buttonHeight); + mainsizer->Add( buttonsizer, 0, wxEXPAND|wxALL, 10 ); + + + SetAutoLayout( true ); + SetSizer( mainsizer ); + + mainsizer->Fit( this ); + Centre(wxBOTH); + + InitDialog(); + + delete[] choices; + delete [] choices2; +} + +wxGenericPageSetupDialog::~wxGenericPageSetupDialog() +{ +} + +wxPageSetupDialogData& wxGenericPageSetupDialog::GetPageSetupDialogData() +{ + return m_pageData; +} + +bool wxGenericPageSetupDialog::TransferDataToWindow() +{ + if (m_marginLeftText) + m_marginLeftText->SetValue(wxString::Format(wxT("%d"), m_pageData.GetMarginTopLeft().x)); + if (m_marginTopText) + m_marginTopText->SetValue(wxString::Format(wxT("%d"), m_pageData.GetMarginTopLeft().y)); + if (m_marginRightText) + m_marginRightText->SetValue(wxString::Format(wxT("%d"), m_pageData.GetMarginBottomRight().x)); + if (m_marginBottomText) + m_marginBottomText->SetValue(wxString::Format(wxT("%d"), m_pageData.GetMarginBottomRight().y)); + + if (m_orientationRadioBox) + { + if (m_pageData.GetPrintData().GetOrientation() == wxPORTRAIT) + m_orientationRadioBox->SetSelection(0); + else + m_orientationRadioBox->SetSelection(1); + } + + // Find the paper type from either the current paper size in the wxPageSetupDialogData, or + // failing that, the id in the wxPrintData object. + + wxPrintPaperType* type = wxThePrintPaperDatabase->FindPaperType( + wxSize(m_pageData.GetPaperSize().x * 10, m_pageData.GetPaperSize().y * 10)); + + if (!type && m_pageData.GetPrintData().GetPaperId() != wxPAPER_NONE) + type = wxThePrintPaperDatabase->FindPaperType(m_pageData.GetPrintData().GetPaperId()); + + if (type) + { + m_paperTypeChoice->SetStringSelection(type->GetName()); + } + + return true; +} + +bool wxGenericPageSetupDialog::TransferDataFromWindow() +{ + if (m_marginLeftText && m_marginTopText) + { + int left = wxAtoi( m_marginLeftText->GetValue().c_str() ); + int top = wxAtoi( m_marginTopText->GetValue().c_str() ); + m_pageData.SetMarginTopLeft( wxPoint(left,top) ); + } + if (m_marginRightText && m_marginBottomText) + { + int right = wxAtoi( m_marginRightText->GetValue().c_str() ); + int bottom = wxAtoi( m_marginBottomText->GetValue().c_str() ); + m_pageData.SetMarginBottomRight( wxPoint(right,bottom) ); + } + + if (m_orientationRadioBox) + { + int sel = m_orientationRadioBox->GetSelection(); + if (sel == 0) + { + m_pageData.GetPrintData().SetOrientation(wxPORTRAIT); + } + else + { + m_pageData.GetPrintData().SetOrientation(wxLANDSCAPE); + } + } + + if (m_paperTypeChoice) + { + int selectedItem = m_paperTypeChoice->GetSelection(); + if (selectedItem != -1) + { + wxPrintPaperType *paper = wxThePrintPaperDatabase->Item(selectedItem); + if ( paper ) + { + m_pageData.SetPaperSize(wxSize(paper->GetWidth()/10, paper->GetHeight()/10)); + m_pageData.GetPrintData().SetPaperId(paper->GetId()); + } + } + } + + return true; +} + +wxComboBox *wxGenericPageSetupDialog::CreatePaperTypeChoice(int *x, int *y) +{ +/* + if (!wxThePrintPaperDatabase) + { + wxThePrintPaperDatabase = new wxPrintPaperDatabase; + wxThePrintPaperDatabase->CreateDatabase(); + } +*/ + + size_t n = wxThePrintPaperDatabase->GetCount(); + wxString *choices = new wxString [n]; + + for (size_t i = 0; i < n; i++) + { + wxPrintPaperType *paper = wxThePrintPaperDatabase->Item(i); + choices[i] = paper->GetName(); + } + + (void) new wxStaticText(this, wxPRINTID_STATIC, _("Paper size"), wxPoint(*x, *y)); + *y += 25; + + wxComboBox *choice = new wxComboBox( this, + wxPRINTID_PAPERSIZE, + _("Paper Size"), + wxPoint(*x, *y), + wxSize(300, wxDefaultCoord), + n, choices ); + *y += 35; + delete[] choices; + +// choice->SetSelection(sel); + return choice; +} + +void wxGenericPageSetupDialog::OnPrinter(wxCommandEvent& WXUNUSED(event)) +{ + // We no longer query GetPrintMode, so we can eliminate the need + // to call SetPrintMode. + // This has the limitation that we can't explicitly call the PostScript + // print setup dialog from the generic Page Setup dialog under Windows, + // but since this choice would only happen when trying to do PostScript + // printing under Windows (and only in 16-bit Windows which + // doesn't have a Windows-specific page setup dialog) it's worth it. + + // First save the current settings, so the wxPrintData object is up to date. + TransferDataFromWindow(); + + // Transfer the current print settings from this dialog to the page setup dialog. + +#if 0 + // Use print factory later + + wxPrintDialogData data; + data = GetPageSetupData().GetPrintData(); + data.SetSetupDialog(true); + wxPrintDialog printDialog(this, & data); + printDialog.ShowModal(); + + // Transfer the page setup print settings from the page dialog to this dialog again, in case + // the page setup dialog changed something. + GetPageSetupData().GetPrintData() = printDialog.GetPrintDialogData().GetPrintData(); + GetPageSetupData().CalculatePaperSizeFromId(); // Make sure page size reflects the id in wxPrintData + + // Now update the dialog in case the page setup dialog changed some of our settings. + TransferDataToWindow(); +#endif +} + +#endif diff --git a/Externals/wxWidgets/src/generic/progdlgg.cpp b/Externals/wxWidgets/src/generic/progdlgg.cpp index 3b63456cfc..9920b4ce34 100644 --- a/Externals/wxWidgets/src/generic/progdlgg.cpp +++ b/Externals/wxWidgets/src/generic/progdlgg.cpp @@ -1,673 +1,673 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/generic/progdlgg.cpp -// Purpose: wxProgressDialog class -// Author: Karsten Ballueder -// Modified by: -// Created: 09.05.1999 -// RCS-ID: $Id: progdlgg.cpp 50711 2007-12-15 02:57:58Z VZ $ -// Copyright: (c) Karsten Ballueder -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_PROGRESSDLG - -#ifndef WX_PRECOMP - #include "wx/utils.h" - #include "wx/frame.h" - #include "wx/button.h" - #include "wx/stattext.h" - #include "wx/sizer.h" - #include "wx/event.h" - #include "wx/gauge.h" - #include "wx/intl.h" - #include "wx/dcclient.h" - #include "wx/timer.h" - #include "wx/settings.h" -#endif - -#include "wx/progdlg.h" - -// --------------------------------------------------------------------------- -// macros -// --------------------------------------------------------------------------- - -/* Macro for avoiding #ifdefs when value have to be different depending on size of - device we display on - take it from something like wxDesktopPolicy in the future - */ - -#if defined(__SMARTPHONE__) - #define wxLARGESMALL(large,small) small -#else - #define wxLARGESMALL(large,small) large -#endif - -// ---------------------------------------------------------------------------- -// constants -// ---------------------------------------------------------------------------- - -#define LAYOUT_MARGIN wxLARGESMALL(8,2) - -static const int wxID_SKIP = 32000; // whatever - -// ---------------------------------------------------------------------------- -// private functions -// ---------------------------------------------------------------------------- - -// update the label to show the given time (in seconds) -static void SetTimeLabel(unsigned long val, wxStaticText *label); - -// ---------------------------------------------------------------------------- -// event tables -// ---------------------------------------------------------------------------- - -BEGIN_EVENT_TABLE(wxProgressDialog, wxDialog) - EVT_BUTTON(wxID_CANCEL, wxProgressDialog::OnCancel) - EVT_BUTTON(wxID_SKIP, wxProgressDialog::OnSkip) - - EVT_CLOSE(wxProgressDialog::OnClose) -END_EVENT_TABLE() - -IMPLEMENT_CLASS(wxProgressDialog, wxDialog) - -// ============================================================================ -// wxProgressDialog implementation -// ============================================================================ - -// ---------------------------------------------------------------------------- -// wxProgressDialog creation -// ---------------------------------------------------------------------------- - -wxProgressDialog::wxProgressDialog(wxString const &title, - wxString const &message, - int maximum, - wxWindow *parent, - int style) - : wxDialog(parent, wxID_ANY, title), - m_skip(false), - m_delay(3), - m_hasAbortButton(false), - m_hasSkipButton(false) -{ - // we may disappear at any moment, let the others know about it - SetExtraStyle(GetExtraStyle() | wxWS_EX_TRANSIENT); - m_windowStyle |= style; - - m_hasAbortButton = (style & wxPD_CAN_ABORT) != 0; - m_hasSkipButton = (style & wxPD_CAN_SKIP) != 0; - - bool isPda = (wxSystemSettings::GetScreenType() <= wxSYS_SCREEN_PDA); - -#if defined(__WXMSW__) && !defined(__WXUNIVERSAL__) - // we have to remove the "Close" button from the title bar then as it is - // confusing to have it - it doesn't work anyhow - // - // FIXME: should probably have a (extended?) window style for this - if ( !m_hasAbortButton ) - { - EnableCloseButton(false); - } -#endif // wxMSW - -#if defined(__SMARTPHONE__) - SetLeftMenu(); -#endif - - m_state = m_hasAbortButton ? Continue : Uncancelable; - m_maximum = maximum; - -#if defined(__WXMSW__) || defined(__WXPM__) - // we can't have values > 65,536 in the progress control under Windows, so - // scale everything down - m_factor = m_maximum / 65536 + 1; - m_maximum /= m_factor; -#endif // __WXMSW__ - - m_parentTop = wxGetTopLevelParent(parent); - - wxClientDC dc(this); - dc.SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT)); - long widthText = 0; - dc.GetTextExtent(message, &widthText, NULL, NULL, NULL, NULL); - - wxBoxSizer *sizer = new wxBoxSizer(wxVERTICAL); - - m_msg = new wxStaticText(this, wxID_ANY, message); - sizer->Add(m_msg, 0, wxLEFT | wxTOP, 2*LAYOUT_MARGIN); - - wxSize sizeDlg, - sizeLabel = m_msg->GetSize(); - sizeDlg.y = 2*LAYOUT_MARGIN + sizeLabel.y; - - if ( maximum > 0 ) - { - int gauge_style = wxGA_HORIZONTAL; - if ( ( style & wxPD_SMOOTH ) == wxPD_SMOOTH ) - gauge_style |= wxGA_SMOOTH; - m_gauge = new wxGauge(this, wxID_ANY, m_maximum, - wxDefaultPosition, wxDefaultSize, - gauge_style ); - - sizer->Add(m_gauge, 0, wxLEFT | wxRIGHT | wxTOP | wxEXPAND, 2*LAYOUT_MARGIN); - m_gauge->SetValue(0); - - wxSize sizeGauge = m_gauge->GetSize(); - sizeDlg.y += 2*LAYOUT_MARGIN + sizeGauge.y; - } - else - m_gauge = (wxGauge *)NULL; - - // create the estimated/remaining/total time zones if requested - m_elapsed = m_estimated = m_remaining = (wxStaticText*)NULL; - m_display_estimated = m_last_timeupdate = m_break = 0; - m_ctdelay = 0; - - // if we are going to have at least one label, remember it in this var - wxStaticText *label = NULL; - - // also count how many labels we really have - size_t nTimeLabels = 0; - - if ( style & wxPD_ELAPSED_TIME ) - { - nTimeLabels++; - - label = - m_elapsed = CreateLabel(_("Elapsed time : "), sizer); - } - - if ( style & wxPD_ESTIMATED_TIME ) - { - nTimeLabels++; - - label = - m_estimated = CreateLabel(_("Estimated time : "), sizer); - } - - if ( style & wxPD_REMAINING_TIME ) - { - nTimeLabels++; - - label = - m_remaining = CreateLabel(_("Remaining time : "), sizer); - } - - if ( nTimeLabels > 0 ) - { - // set it to the current time - m_timeStart = wxGetCurrentTime(); - sizeDlg.y += nTimeLabels * (label->GetSize().y + LAYOUT_MARGIN); - } - -#if defined(__SMARTPHONE__) - if ( m_hasSkipButton ) - SetRightMenu(wxID_SKIP, _("Skip")); - if ( m_hasAbortButton ) - SetLeftMenu(wxID_CANCEL); -#else - m_btnAbort = m_btnSkip = (wxButton *)NULL; - bool sizeDlgModified = false; - wxBoxSizer *buttonSizer = new wxBoxSizer(wxHORIZONTAL); - - const int sizerFlags = -#if defined(__WXMSW__) || defined(__WXPM__) - wxALIGN_RIGHT | wxALL -#else // !MSW - wxALIGN_CENTER_HORIZONTAL | wxBOTTOM | wxTOP -#endif // MSW/!MSW - ; - - if ( m_hasSkipButton ) - { - m_btnSkip = new wxButton(this, wxID_SKIP, _("Skip")); - - // Windows dialogs usually have buttons in the lower right corner - buttonSizer->Add(m_btnSkip, 0, sizerFlags, LAYOUT_MARGIN); - sizeDlg.y += 2*LAYOUT_MARGIN + wxButton::GetDefaultSize().y; - sizeDlgModified = true; - } - - if ( m_hasAbortButton ) - { - m_btnAbort = new wxButton(this, wxID_CANCEL); - - // Windows dialogs usually have buttons in the lower right corner - buttonSizer->Add(m_btnAbort, 0, sizerFlags, LAYOUT_MARGIN); - if(!sizeDlgModified) - sizeDlg.y += 2*LAYOUT_MARGIN + wxButton::GetDefaultSize().y; - } - - sizer->Add(buttonSizer, 0, sizerFlags, LAYOUT_MARGIN ); -#endif // __SMARTPHONE__/!__SMARTPHONE__ - - SetSizerAndFit(sizer); - - if (!isPda) - { - sizeDlg.y += 2*LAYOUT_MARGIN; - - // try to make the dialog not square but rectangular of reasonable width - sizeDlg.x = (wxCoord)wxMax(3*widthText/2, 4*sizeDlg.y/3); - SetClientSize(sizeDlg); - } - - Centre(wxCENTER_FRAME | wxBOTH); - - if ( style & wxPD_APP_MODAL ) - { - m_winDisabler = new wxWindowDisabler(this); - } - else - { - if ( m_parentTop ) - m_parentTop->Disable(); - m_winDisabler = NULL; - } - - Show(); - Enable(); - - // this one can be initialized even if the others are unknown for now - // - // NB: do it after calling Layout() to keep the labels correctly aligned - if ( m_elapsed ) - { - SetTimeLabel(0, m_elapsed); - } - - Update(); -} - -wxStaticText *wxProgressDialog::CreateLabel(const wxString& text, - wxSizer *sizer) -{ - wxBoxSizer *locsizer = new wxBoxSizer(wxLARGESMALL(wxHORIZONTAL,wxVERTICAL)); - - wxStaticText *dummy = new wxStaticText(this, wxID_ANY, text); - wxStaticText *label = new wxStaticText(this, wxID_ANY, _("unknown")); - - // select placement most native or nice on target GUI -#if defined(__SMARTPHONE__) - // label and time to the left in two rows - locsizer->Add(dummy, 1, wxALIGN_LEFT); - locsizer->Add(label, 1, wxALIGN_LEFT); - sizer->Add(locsizer, 0, wxALIGN_LEFT | wxTOP | wxLEFT, LAYOUT_MARGIN); -#elif defined(__WXMSW__) || defined(__WXPM__) || defined(__WXMAC__) || defined(__WXGTK20__) - // label and time centered in one row - locsizer->Add(dummy, 1, wxLARGESMALL(wxALIGN_RIGHT,wxALIGN_LEFT)); - locsizer->Add(label, 1, wxALIGN_LEFT | wxLEFT, LAYOUT_MARGIN); - sizer->Add(locsizer, 0, wxALIGN_CENTER_HORIZONTAL | wxTOP, LAYOUT_MARGIN); -#else - // label and time to the right in one row - sizer->Add(locsizer, 0, wxALIGN_RIGHT | wxRIGHT | wxTOP, LAYOUT_MARGIN); - locsizer->Add(dummy); - locsizer->Add(label, 0, wxLEFT, LAYOUT_MARGIN); -#endif - - return label; -} - -// ---------------------------------------------------------------------------- -// wxProgressDialog operations -// ---------------------------------------------------------------------------- - -bool -wxProgressDialog::Update(int value, const wxString& newmsg, bool *skip) -{ - wxASSERT_MSG( value == -1 || m_gauge, wxT("cannot update non existent dialog") ); - -#ifdef __WXMSW__ - value /= m_factor; -#endif // __WXMSW__ - - wxASSERT_MSG( value <= m_maximum, wxT("invalid progress value") ); - - if ( m_gauge ) - m_gauge->SetValue(value); - - UpdateMessage(newmsg); - - if ( (m_elapsed || m_remaining || m_estimated) && (value != 0) ) - { - unsigned long elapsed = wxGetCurrentTime() - m_timeStart; - if ( m_last_timeupdate < elapsed - || value == m_maximum - ) - { - m_last_timeupdate = elapsed; - unsigned long estimated = m_break + - (unsigned long)(( (double) (elapsed-m_break) * m_maximum ) / ((double)value)) ; - if ( estimated > m_display_estimated - && m_ctdelay >= 0 - ) - { - ++m_ctdelay; - } - else if ( estimated < m_display_estimated - && m_ctdelay <= 0 - ) - { - --m_ctdelay; - } - else - { - m_ctdelay = 0; - } - if ( m_ctdelay >= m_delay // enough confirmations for a higher value - || m_ctdelay <= (m_delay*-1) // enough confirmations for a lower value - || value == m_maximum // to stay consistent - || elapsed > m_display_estimated // to stay consistent - || ( elapsed > 0 && elapsed < 4 ) // additional updates in the beginning - ) - { - m_display_estimated = estimated; - m_ctdelay = 0; - } - } - - long display_remaining = m_display_estimated - elapsed; - if ( display_remaining < 0 ) - { - display_remaining = 0; - } - - SetTimeLabel(elapsed, m_elapsed); - SetTimeLabel(m_display_estimated, m_estimated); - SetTimeLabel(display_remaining, m_remaining); - } - - if ( value == m_maximum ) - { - if ( m_state == Finished ) - { - // ignore multiple calls to Update(m_maximum): it may sometimes be - // troublesome to ensure that Update() is not called twice with the - // same value (e.g. because of the rounding errors) and if we don't - // return now we're going to generate asserts below - return true; - } - - // so that we return true below and that out [Cancel] handler knew what - // to do - m_state = Finished; - if( !(GetWindowStyle() & wxPD_AUTO_HIDE) ) - { - EnableClose(); - DisableSkip(); -#if defined(__WXMSW__) && !defined(__WXUNIVERSAL__) - EnableCloseButton(); -#endif // __WXMSW__ - - if ( newmsg.empty() ) - { - // also provide the finishing message if the application didn't - m_msg->SetLabel(_("Done.")); - } - - wxYieldIfNeeded() ; - - (void)ShowModal(); - } - else // auto hide - { - // reenable other windows before hiding this one because otherwise - // Windows wouldn't give the focus back to the window which had - // been previously focused because it would still be disabled - ReenableOtherWindows(); - - Hide(); - } - } - else // not at maximum yet - { - return DoAfterUpdate(skip); - } - - // update the display in case yielding above didn't do it - Update(); - - return m_state != Canceled; -} - -bool wxProgressDialog::Pulse(const wxString& newmsg, bool *skip) -{ - wxASSERT_MSG( m_gauge, wxT("cannot update non existent dialog") ); - - // show a bit of progress - m_gauge->Pulse(); - - UpdateMessage(newmsg); - - if (m_elapsed || m_remaining || m_estimated) - { - unsigned long elapsed = wxGetCurrentTime() - m_timeStart; - - SetTimeLabel(elapsed, m_elapsed); - SetTimeLabel((unsigned long)-1, m_estimated); - SetTimeLabel((unsigned long)-1, m_remaining); - } - - return DoAfterUpdate(skip); -} - -bool wxProgressDialog::DoAfterUpdate(bool *skip) -{ - // we have to yield because not only we want to update the display but - // also to process the clicks on the cancel and skip buttons - wxYieldIfNeeded(); - - Update(); - - if ( m_skip && skip && !*skip ) - { - *skip = true; - m_skip = false; - EnableSkip(); - } - - return m_state != Canceled; -} - -void wxProgressDialog::Resume() -{ - m_state = Continue; - m_ctdelay = m_delay; // force an update of the elapsed/estimated/remaining time - m_break += wxGetCurrentTime()-m_timeStop; - - EnableAbort(); - EnableSkip(); - m_skip = false; -} - -bool wxProgressDialog::Show( bool show ) -{ - // reenable other windows before hiding this one because otherwise - // Windows wouldn't give the focus back to the window which had - // been previously focused because it would still be disabled - if(!show) - ReenableOtherWindows(); - - return wxDialog::Show(show); -} - -// ---------------------------------------------------------------------------- -// event handlers -// ---------------------------------------------------------------------------- - -void wxProgressDialog::OnCancel(wxCommandEvent& event) -{ - if ( m_state == Finished ) - { - // this means that the count down is already finished and we're being - // shown as a modal dialog - so just let the default handler do the job - event.Skip(); - } - else - { - // request to cancel was received, the next time Update() is called we - // will handle it - m_state = Canceled; - - // update the buttons state immediately so that the user knows that the - // request has been noticed - DisableAbort(); - DisableSkip(); - - // save the time when the dialog was stopped - m_timeStop = wxGetCurrentTime(); - } -} - -void wxProgressDialog::OnSkip(wxCommandEvent& WXUNUSED(event)) -{ - DisableSkip(); - m_skip = true; -} - -void wxProgressDialog::OnClose(wxCloseEvent& event) -{ - if ( m_state == Uncancelable ) - { - // can't close this dialog - event.Veto(); - } - else if ( m_state == Finished ) - { - // let the default handler close the window as we already terminated - event.Skip(); - } - else - { - // next Update() will notice it - m_state = Canceled; - DisableAbort(); - DisableSkip(); - - m_timeStop = wxGetCurrentTime(); - } -} - -// ---------------------------------------------------------------------------- -// destruction -// ---------------------------------------------------------------------------- - -wxProgressDialog::~wxProgressDialog() -{ - // normally this should have been already done, but just in case - ReenableOtherWindows(); -} - -void wxProgressDialog::ReenableOtherWindows() -{ - if ( GetWindowStyle() & wxPD_APP_MODAL ) - { - delete m_winDisabler; - m_winDisabler = (wxWindowDisabler *)NULL; - } - else - { - if ( m_parentTop ) - m_parentTop->Enable(); - } -} - -// ---------------------------------------------------------------------------- -// private functions -// ---------------------------------------------------------------------------- - -static void SetTimeLabel(unsigned long val, wxStaticText *label) -{ - if ( label ) - { - wxString s; - - if (val != (unsigned long)-1) - { - unsigned long hours = val / 3600; - unsigned long minutes = (val % 3600) / 60; - unsigned long seconds = val % 60; - s.Printf(wxT("%lu:%02lu:%02lu"), hours, minutes, seconds); - } - else - { - s = _("Unknown"); - } - - if ( s != label->GetLabel() ) - label->SetLabel(s); - } -} - -void wxProgressDialog::EnableSkip(bool enable) -{ - if(m_hasSkipButton) - { -#ifdef __SMARTPHONE__ - if(enable) - SetRightMenu(wxID_SKIP, _("Skip")); - else - SetRightMenu(); -#else - if(m_btnSkip) - m_btnSkip->Enable(enable); -#endif - } -} - -void wxProgressDialog::EnableAbort(bool enable) -{ - if(m_hasAbortButton) - { -#ifdef __SMARTPHONE__ - if(enable) - SetLeftMenu(wxID_CANCEL); // stock buttons makes Cancel label - else - SetLeftMenu(); -#else - if(m_btnAbort) - m_btnAbort->Enable(enable); -#endif - } -} - -void wxProgressDialog::EnableClose() -{ - if(m_hasAbortButton) - { -#ifdef __SMARTPHONE__ - SetLeftMenu(wxID_CANCEL, _("Close")); -#else - if(m_btnAbort) - { - m_btnAbort->Enable(); - m_btnAbort->SetLabel(_("Close")); - } -#endif - } -} - -void wxProgressDialog::UpdateMessage(const wxString &newmsg) -{ - if ( !newmsg.empty() && newmsg != m_msg->GetLabel() ) - { - m_msg->SetLabel(newmsg); - - wxYieldIfNeeded() ; - } -} - -#endif // wxUSE_PROGRESSDLG +///////////////////////////////////////////////////////////////////////////// +// Name: src/generic/progdlgg.cpp +// Purpose: wxProgressDialog class +// Author: Karsten Ballueder +// Modified by: +// Created: 09.05.1999 +// RCS-ID: $Id: progdlgg.cpp 50711 2007-12-15 02:57:58Z VZ $ +// Copyright: (c) Karsten Ballueder +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_PROGRESSDLG + +#ifndef WX_PRECOMP + #include "wx/utils.h" + #include "wx/frame.h" + #include "wx/button.h" + #include "wx/stattext.h" + #include "wx/sizer.h" + #include "wx/event.h" + #include "wx/gauge.h" + #include "wx/intl.h" + #include "wx/dcclient.h" + #include "wx/timer.h" + #include "wx/settings.h" +#endif + +#include "wx/progdlg.h" + +// --------------------------------------------------------------------------- +// macros +// --------------------------------------------------------------------------- + +/* Macro for avoiding #ifdefs when value have to be different depending on size of + device we display on - take it from something like wxDesktopPolicy in the future + */ + +#if defined(__SMARTPHONE__) + #define wxLARGESMALL(large,small) small +#else + #define wxLARGESMALL(large,small) large +#endif + +// ---------------------------------------------------------------------------- +// constants +// ---------------------------------------------------------------------------- + +#define LAYOUT_MARGIN wxLARGESMALL(8,2) + +static const int wxID_SKIP = 32000; // whatever + +// ---------------------------------------------------------------------------- +// private functions +// ---------------------------------------------------------------------------- + +// update the label to show the given time (in seconds) +static void SetTimeLabel(unsigned long val, wxStaticText *label); + +// ---------------------------------------------------------------------------- +// event tables +// ---------------------------------------------------------------------------- + +BEGIN_EVENT_TABLE(wxProgressDialog, wxDialog) + EVT_BUTTON(wxID_CANCEL, wxProgressDialog::OnCancel) + EVT_BUTTON(wxID_SKIP, wxProgressDialog::OnSkip) + + EVT_CLOSE(wxProgressDialog::OnClose) +END_EVENT_TABLE() + +IMPLEMENT_CLASS(wxProgressDialog, wxDialog) + +// ============================================================================ +// wxProgressDialog implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// wxProgressDialog creation +// ---------------------------------------------------------------------------- + +wxProgressDialog::wxProgressDialog(wxString const &title, + wxString const &message, + int maximum, + wxWindow *parent, + int style) + : wxDialog(parent, wxID_ANY, title), + m_skip(false), + m_delay(3), + m_hasAbortButton(false), + m_hasSkipButton(false) +{ + // we may disappear at any moment, let the others know about it + SetExtraStyle(GetExtraStyle() | wxWS_EX_TRANSIENT); + m_windowStyle |= style; + + m_hasAbortButton = (style & wxPD_CAN_ABORT) != 0; + m_hasSkipButton = (style & wxPD_CAN_SKIP) != 0; + + bool isPda = (wxSystemSettings::GetScreenType() <= wxSYS_SCREEN_PDA); + +#if defined(__WXMSW__) && !defined(__WXUNIVERSAL__) + // we have to remove the "Close" button from the title bar then as it is + // confusing to have it - it doesn't work anyhow + // + // FIXME: should probably have a (extended?) window style for this + if ( !m_hasAbortButton ) + { + EnableCloseButton(false); + } +#endif // wxMSW + +#if defined(__SMARTPHONE__) + SetLeftMenu(); +#endif + + m_state = m_hasAbortButton ? Continue : Uncancelable; + m_maximum = maximum; + +#if defined(__WXMSW__) || defined(__WXPM__) + // we can't have values > 65,536 in the progress control under Windows, so + // scale everything down + m_factor = m_maximum / 65536 + 1; + m_maximum /= m_factor; +#endif // __WXMSW__ + + m_parentTop = wxGetTopLevelParent(parent); + + wxClientDC dc(this); + dc.SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT)); + long widthText = 0; + dc.GetTextExtent(message, &widthText, NULL, NULL, NULL, NULL); + + wxBoxSizer *sizer = new wxBoxSizer(wxVERTICAL); + + m_msg = new wxStaticText(this, wxID_ANY, message); + sizer->Add(m_msg, 0, wxLEFT | wxTOP, 2*LAYOUT_MARGIN); + + wxSize sizeDlg, + sizeLabel = m_msg->GetSize(); + sizeDlg.y = 2*LAYOUT_MARGIN + sizeLabel.y; + + if ( maximum > 0 ) + { + int gauge_style = wxGA_HORIZONTAL; + if ( ( style & wxPD_SMOOTH ) == wxPD_SMOOTH ) + gauge_style |= wxGA_SMOOTH; + m_gauge = new wxGauge(this, wxID_ANY, m_maximum, + wxDefaultPosition, wxDefaultSize, + gauge_style ); + + sizer->Add(m_gauge, 0, wxLEFT | wxRIGHT | wxTOP | wxEXPAND, 2*LAYOUT_MARGIN); + m_gauge->SetValue(0); + + wxSize sizeGauge = m_gauge->GetSize(); + sizeDlg.y += 2*LAYOUT_MARGIN + sizeGauge.y; + } + else + m_gauge = (wxGauge *)NULL; + + // create the estimated/remaining/total time zones if requested + m_elapsed = m_estimated = m_remaining = (wxStaticText*)NULL; + m_display_estimated = m_last_timeupdate = m_break = 0; + m_ctdelay = 0; + + // if we are going to have at least one label, remember it in this var + wxStaticText *label = NULL; + + // also count how many labels we really have + size_t nTimeLabels = 0; + + if ( style & wxPD_ELAPSED_TIME ) + { + nTimeLabels++; + + label = + m_elapsed = CreateLabel(_("Elapsed time : "), sizer); + } + + if ( style & wxPD_ESTIMATED_TIME ) + { + nTimeLabels++; + + label = + m_estimated = CreateLabel(_("Estimated time : "), sizer); + } + + if ( style & wxPD_REMAINING_TIME ) + { + nTimeLabels++; + + label = + m_remaining = CreateLabel(_("Remaining time : "), sizer); + } + + if ( nTimeLabels > 0 ) + { + // set it to the current time + m_timeStart = wxGetCurrentTime(); + sizeDlg.y += nTimeLabels * (label->GetSize().y + LAYOUT_MARGIN); + } + +#if defined(__SMARTPHONE__) + if ( m_hasSkipButton ) + SetRightMenu(wxID_SKIP, _("Skip")); + if ( m_hasAbortButton ) + SetLeftMenu(wxID_CANCEL); +#else + m_btnAbort = m_btnSkip = (wxButton *)NULL; + bool sizeDlgModified = false; + wxBoxSizer *buttonSizer = new wxBoxSizer(wxHORIZONTAL); + + const int sizerFlags = +#if defined(__WXMSW__) || defined(__WXPM__) + wxALIGN_RIGHT | wxALL +#else // !MSW + wxALIGN_CENTER_HORIZONTAL | wxBOTTOM | wxTOP +#endif // MSW/!MSW + ; + + if ( m_hasSkipButton ) + { + m_btnSkip = new wxButton(this, wxID_SKIP, _("Skip")); + + // Windows dialogs usually have buttons in the lower right corner + buttonSizer->Add(m_btnSkip, 0, sizerFlags, LAYOUT_MARGIN); + sizeDlg.y += 2*LAYOUT_MARGIN + wxButton::GetDefaultSize().y; + sizeDlgModified = true; + } + + if ( m_hasAbortButton ) + { + m_btnAbort = new wxButton(this, wxID_CANCEL); + + // Windows dialogs usually have buttons in the lower right corner + buttonSizer->Add(m_btnAbort, 0, sizerFlags, LAYOUT_MARGIN); + if(!sizeDlgModified) + sizeDlg.y += 2*LAYOUT_MARGIN + wxButton::GetDefaultSize().y; + } + + sizer->Add(buttonSizer, 0, sizerFlags, LAYOUT_MARGIN ); +#endif // __SMARTPHONE__/!__SMARTPHONE__ + + SetSizerAndFit(sizer); + + if (!isPda) + { + sizeDlg.y += 2*LAYOUT_MARGIN; + + // try to make the dialog not square but rectangular of reasonable width + sizeDlg.x = (wxCoord)wxMax(3*widthText/2, 4*sizeDlg.y/3); + SetClientSize(sizeDlg); + } + + Centre(wxCENTER_FRAME | wxBOTH); + + if ( style & wxPD_APP_MODAL ) + { + m_winDisabler = new wxWindowDisabler(this); + } + else + { + if ( m_parentTop ) + m_parentTop->Disable(); + m_winDisabler = NULL; + } + + Show(); + Enable(); + + // this one can be initialized even if the others are unknown for now + // + // NB: do it after calling Layout() to keep the labels correctly aligned + if ( m_elapsed ) + { + SetTimeLabel(0, m_elapsed); + } + + Update(); +} + +wxStaticText *wxProgressDialog::CreateLabel(const wxString& text, + wxSizer *sizer) +{ + wxBoxSizer *locsizer = new wxBoxSizer(wxLARGESMALL(wxHORIZONTAL,wxVERTICAL)); + + wxStaticText *dummy = new wxStaticText(this, wxID_ANY, text); + wxStaticText *label = new wxStaticText(this, wxID_ANY, _("unknown")); + + // select placement most native or nice on target GUI +#if defined(__SMARTPHONE__) + // label and time to the left in two rows + locsizer->Add(dummy, 1, wxALIGN_LEFT); + locsizer->Add(label, 1, wxALIGN_LEFT); + sizer->Add(locsizer, 0, wxALIGN_LEFT | wxTOP | wxLEFT, LAYOUT_MARGIN); +#elif defined(__WXMSW__) || defined(__WXPM__) || defined(__WXMAC__) || defined(__WXGTK20__) + // label and time centered in one row + locsizer->Add(dummy, 1, wxLARGESMALL(wxALIGN_RIGHT,wxALIGN_LEFT)); + locsizer->Add(label, 1, wxALIGN_LEFT | wxLEFT, LAYOUT_MARGIN); + sizer->Add(locsizer, 0, wxALIGN_CENTER_HORIZONTAL | wxTOP, LAYOUT_MARGIN); +#else + // label and time to the right in one row + sizer->Add(locsizer, 0, wxALIGN_RIGHT | wxRIGHT | wxTOP, LAYOUT_MARGIN); + locsizer->Add(dummy); + locsizer->Add(label, 0, wxLEFT, LAYOUT_MARGIN); +#endif + + return label; +} + +// ---------------------------------------------------------------------------- +// wxProgressDialog operations +// ---------------------------------------------------------------------------- + +bool +wxProgressDialog::Update(int value, const wxString& newmsg, bool *skip) +{ + wxASSERT_MSG( value == -1 || m_gauge, wxT("cannot update non existent dialog") ); + +#ifdef __WXMSW__ + value /= m_factor; +#endif // __WXMSW__ + + wxASSERT_MSG( value <= m_maximum, wxT("invalid progress value") ); + + if ( m_gauge ) + m_gauge->SetValue(value); + + UpdateMessage(newmsg); + + if ( (m_elapsed || m_remaining || m_estimated) && (value != 0) ) + { + unsigned long elapsed = wxGetCurrentTime() - m_timeStart; + if ( m_last_timeupdate < elapsed + || value == m_maximum + ) + { + m_last_timeupdate = elapsed; + unsigned long estimated = m_break + + (unsigned long)(( (double) (elapsed-m_break) * m_maximum ) / ((double)value)) ; + if ( estimated > m_display_estimated + && m_ctdelay >= 0 + ) + { + ++m_ctdelay; + } + else if ( estimated < m_display_estimated + && m_ctdelay <= 0 + ) + { + --m_ctdelay; + } + else + { + m_ctdelay = 0; + } + if ( m_ctdelay >= m_delay // enough confirmations for a higher value + || m_ctdelay <= (m_delay*-1) // enough confirmations for a lower value + || value == m_maximum // to stay consistent + || elapsed > m_display_estimated // to stay consistent + || ( elapsed > 0 && elapsed < 4 ) // additional updates in the beginning + ) + { + m_display_estimated = estimated; + m_ctdelay = 0; + } + } + + long display_remaining = m_display_estimated - elapsed; + if ( display_remaining < 0 ) + { + display_remaining = 0; + } + + SetTimeLabel(elapsed, m_elapsed); + SetTimeLabel(m_display_estimated, m_estimated); + SetTimeLabel(display_remaining, m_remaining); + } + + if ( value == m_maximum ) + { + if ( m_state == Finished ) + { + // ignore multiple calls to Update(m_maximum): it may sometimes be + // troublesome to ensure that Update() is not called twice with the + // same value (e.g. because of the rounding errors) and if we don't + // return now we're going to generate asserts below + return true; + } + + // so that we return true below and that out [Cancel] handler knew what + // to do + m_state = Finished; + if( !(GetWindowStyle() & wxPD_AUTO_HIDE) ) + { + EnableClose(); + DisableSkip(); +#if defined(__WXMSW__) && !defined(__WXUNIVERSAL__) + EnableCloseButton(); +#endif // __WXMSW__ + + if ( newmsg.empty() ) + { + // also provide the finishing message if the application didn't + m_msg->SetLabel(_("Done.")); + } + + wxYieldIfNeeded() ; + + (void)ShowModal(); + } + else // auto hide + { + // reenable other windows before hiding this one because otherwise + // Windows wouldn't give the focus back to the window which had + // been previously focused because it would still be disabled + ReenableOtherWindows(); + + Hide(); + } + } + else // not at maximum yet + { + return DoAfterUpdate(skip); + } + + // update the display in case yielding above didn't do it + Update(); + + return m_state != Canceled; +} + +bool wxProgressDialog::Pulse(const wxString& newmsg, bool *skip) +{ + wxASSERT_MSG( m_gauge, wxT("cannot update non existent dialog") ); + + // show a bit of progress + m_gauge->Pulse(); + + UpdateMessage(newmsg); + + if (m_elapsed || m_remaining || m_estimated) + { + unsigned long elapsed = wxGetCurrentTime() - m_timeStart; + + SetTimeLabel(elapsed, m_elapsed); + SetTimeLabel((unsigned long)-1, m_estimated); + SetTimeLabel((unsigned long)-1, m_remaining); + } + + return DoAfterUpdate(skip); +} + +bool wxProgressDialog::DoAfterUpdate(bool *skip) +{ + // we have to yield because not only we want to update the display but + // also to process the clicks on the cancel and skip buttons + wxYieldIfNeeded(); + + Update(); + + if ( m_skip && skip && !*skip ) + { + *skip = true; + m_skip = false; + EnableSkip(); + } + + return m_state != Canceled; +} + +void wxProgressDialog::Resume() +{ + m_state = Continue; + m_ctdelay = m_delay; // force an update of the elapsed/estimated/remaining time + m_break += wxGetCurrentTime()-m_timeStop; + + EnableAbort(); + EnableSkip(); + m_skip = false; +} + +bool wxProgressDialog::Show( bool show ) +{ + // reenable other windows before hiding this one because otherwise + // Windows wouldn't give the focus back to the window which had + // been previously focused because it would still be disabled + if(!show) + ReenableOtherWindows(); + + return wxDialog::Show(show); +} + +// ---------------------------------------------------------------------------- +// event handlers +// ---------------------------------------------------------------------------- + +void wxProgressDialog::OnCancel(wxCommandEvent& event) +{ + if ( m_state == Finished ) + { + // this means that the count down is already finished and we're being + // shown as a modal dialog - so just let the default handler do the job + event.Skip(); + } + else + { + // request to cancel was received, the next time Update() is called we + // will handle it + m_state = Canceled; + + // update the buttons state immediately so that the user knows that the + // request has been noticed + DisableAbort(); + DisableSkip(); + + // save the time when the dialog was stopped + m_timeStop = wxGetCurrentTime(); + } +} + +void wxProgressDialog::OnSkip(wxCommandEvent& WXUNUSED(event)) +{ + DisableSkip(); + m_skip = true; +} + +void wxProgressDialog::OnClose(wxCloseEvent& event) +{ + if ( m_state == Uncancelable ) + { + // can't close this dialog + event.Veto(); + } + else if ( m_state == Finished ) + { + // let the default handler close the window as we already terminated + event.Skip(); + } + else + { + // next Update() will notice it + m_state = Canceled; + DisableAbort(); + DisableSkip(); + + m_timeStop = wxGetCurrentTime(); + } +} + +// ---------------------------------------------------------------------------- +// destruction +// ---------------------------------------------------------------------------- + +wxProgressDialog::~wxProgressDialog() +{ + // normally this should have been already done, but just in case + ReenableOtherWindows(); +} + +void wxProgressDialog::ReenableOtherWindows() +{ + if ( GetWindowStyle() & wxPD_APP_MODAL ) + { + delete m_winDisabler; + m_winDisabler = (wxWindowDisabler *)NULL; + } + else + { + if ( m_parentTop ) + m_parentTop->Enable(); + } +} + +// ---------------------------------------------------------------------------- +// private functions +// ---------------------------------------------------------------------------- + +static void SetTimeLabel(unsigned long val, wxStaticText *label) +{ + if ( label ) + { + wxString s; + + if (val != (unsigned long)-1) + { + unsigned long hours = val / 3600; + unsigned long minutes = (val % 3600) / 60; + unsigned long seconds = val % 60; + s.Printf(wxT("%lu:%02lu:%02lu"), hours, minutes, seconds); + } + else + { + s = _("Unknown"); + } + + if ( s != label->GetLabel() ) + label->SetLabel(s); + } +} + +void wxProgressDialog::EnableSkip(bool enable) +{ + if(m_hasSkipButton) + { +#ifdef __SMARTPHONE__ + if(enable) + SetRightMenu(wxID_SKIP, _("Skip")); + else + SetRightMenu(); +#else + if(m_btnSkip) + m_btnSkip->Enable(enable); +#endif + } +} + +void wxProgressDialog::EnableAbort(bool enable) +{ + if(m_hasAbortButton) + { +#ifdef __SMARTPHONE__ + if(enable) + SetLeftMenu(wxID_CANCEL); // stock buttons makes Cancel label + else + SetLeftMenu(); +#else + if(m_btnAbort) + m_btnAbort->Enable(enable); +#endif + } +} + +void wxProgressDialog::EnableClose() +{ + if(m_hasAbortButton) + { +#ifdef __SMARTPHONE__ + SetLeftMenu(wxID_CANCEL, _("Close")); +#else + if(m_btnAbort) + { + m_btnAbort->Enable(); + m_btnAbort->SetLabel(_("Close")); + } +#endif + } +} + +void wxProgressDialog::UpdateMessage(const wxString &newmsg) +{ + if ( !newmsg.empty() && newmsg != m_msg->GetLabel() ) + { + m_msg->SetLabel(newmsg); + + wxYieldIfNeeded() ; + } +} + +#endif // wxUSE_PROGRESSDLG diff --git a/Externals/wxWidgets/src/generic/propdlg.cpp b/Externals/wxWidgets/src/generic/propdlg.cpp index e529b2ca3f..a994449b4f 100644 --- a/Externals/wxWidgets/src/generic/propdlg.cpp +++ b/Externals/wxWidgets/src/generic/propdlg.cpp @@ -1,226 +1,226 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/generic/propdlg.cpp -// Purpose: wxPropertySheetDialog -// Author: Julian Smart -// Modified by: -// Created: 2005-03-12 -// RCS-ID: $Id: propdlg.cpp 41838 2006-10-09 21:08:45Z VZ $ -// Copyright: (c) Julian Smart -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_BOOKCTRL - -#ifndef WX_PRECOMP - #include "wx/button.h" - #include "wx/sizer.h" - #include "wx/intl.h" - #include "wx/log.h" - #include "wx/msgdlg.h" -#endif - -#include "wx/bookctrl.h" - -#if wxUSE_NOTEBOOK -#include "wx/notebook.h" -#endif -#if wxUSE_CHOICEBOOK -#include "wx/choicebk.h" -#endif -#if wxUSE_TOOLBOOK -#include "wx/toolbook.h" -#endif -#if wxUSE_LISTBOOK -#include "wx/listbook.h" -#endif -#if wxUSE_TREEBOOK -#include "wx/treebook.h" -#endif - -#include "wx/generic/propdlg.h" -#include "wx/sysopt.h" - -//----------------------------------------------------------------------------- -// wxPropertySheetDialog -//----------------------------------------------------------------------------- - -IMPLEMENT_DYNAMIC_CLASS(wxPropertySheetDialog, wxDialog) - -BEGIN_EVENT_TABLE(wxPropertySheetDialog, wxDialog) - EVT_ACTIVATE(wxPropertySheetDialog::OnActivate) - EVT_IDLE(wxPropertySheetDialog::OnIdle) -END_EVENT_TABLE() - -bool wxPropertySheetDialog::Create(wxWindow* parent, wxWindowID id, const wxString& title, - const wxPoint& pos, const wxSize& sz, long style, - const wxString& name) -{ - if (!wxDialog::Create(parent, id, title, pos, sz, style|wxCLIP_CHILDREN, name)) - return false; - - wxBoxSizer *topSizer = new wxBoxSizer( wxVERTICAL ); - SetSizer(topSizer); - - // This gives more space around the edges - m_innerSizer = new wxBoxSizer( wxVERTICAL ); - -#if defined(__SMARTPHONE__) || defined(__POCKETPC__) - m_sheetOuterBorder = 0; -#endif - topSizer->Add(m_innerSizer, 1, wxGROW|wxALL, m_sheetOuterBorder); - - m_bookCtrl = CreateBookCtrl(); - AddBookCtrl(m_innerSizer); - - return true; -} - -void wxPropertySheetDialog::Init() -{ - m_sheetStyle = wxPROPSHEET_DEFAULT; - m_innerSizer = NULL; - m_bookCtrl = NULL; - m_sheetOuterBorder = 2; - m_sheetInnerBorder = 5; -} - -// Layout the dialog, to be called after pages have been created -void wxPropertySheetDialog::LayoutDialog(int centreFlags) -{ -#if !defined(__SMARTPHONE__) && !defined(__POCKETPC__) - GetSizer()->Fit(this); - GetSizer()->SetSizeHints(this); - if (centreFlags) - Centre(centreFlags); -#else - wxUnusedVar(centreFlags); -#endif -#if defined(__SMARTPHONE__) - if (m_bookCtrl) - m_bookCtrl->SetFocus(); -#endif -} - -// Creates the buttons, if any -void wxPropertySheetDialog::CreateButtons(int flags) -{ -#ifdef __POCKETPC__ - // keep system option status - const wxChar *optionName = wxT("wince.dialog.real-ok-cancel"); - const int status = wxSystemOptions::GetOptionInt(optionName); - wxSystemOptions::SetOption(optionName,0); -#endif - - wxSizer *buttonSizer = CreateButtonSizer( flags & ButtonSizerFlags ); - if( buttonSizer ) - { - m_innerSizer->Add( buttonSizer, 0, wxGROW|wxALIGN_CENTER_VERTICAL|wxTOP|wxBOTTOM|wxLEFT|wxRIGHT, 2); - m_innerSizer->AddSpacer(2); - } - -#ifdef __POCKETPC__ - // restore system option - wxSystemOptions::SetOption(optionName,status); -#endif -} - -// Creates the book control -wxBookCtrlBase* wxPropertySheetDialog::CreateBookCtrl() -{ - int style = wxCLIP_CHILDREN | wxBK_DEFAULT; - - wxBookCtrlBase* bookCtrl = NULL; - -#if wxUSE_NOTEBOOK - if (GetSheetStyle() & wxPROPSHEET_NOTEBOOK) - bookCtrl = new wxNotebook(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, style ); -#endif -#if wxUSE_CHOICEBOOK - if (GetSheetStyle() & wxPROPSHEET_CHOICEBOOK) - bookCtrl = new wxChoicebook(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, style ); -#endif -#if wxUSE_TOOLBOOK -#if defined(__WXMAC__) && wxUSE_TOOLBAR && wxUSE_BMPBUTTON - if (GetSheetStyle() & wxPROPSHEET_BUTTONTOOLBOOK) - bookCtrl = new wxToolbook(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, style|wxBK_BUTTONBAR ); - else -#endif - if ((GetSheetStyle() & wxPROPSHEET_TOOLBOOK) || (GetSheetStyle() & wxPROPSHEET_BUTTONTOOLBOOK)) - bookCtrl = new wxToolbook(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, style ); -#endif -#if wxUSE_LISTBOOK - if (GetSheetStyle() & wxPROPSHEET_LISTBOOK) - bookCtrl = new wxListbook(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, style ); -#endif -#if wxUSE_TREEBOOK - if (GetSheetStyle() & wxPROPSHEET_TREEBOOK) - bookCtrl = new wxTreebook(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, style ); -#endif - if (!bookCtrl) - bookCtrl = new wxBookCtrl(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, style ); - - if (GetSheetStyle() & wxPROPSHEET_SHRINKTOFIT) - bookCtrl->SetFitToCurrentPage(true); - - return bookCtrl; -} - -// Adds the book control to the inner sizer. -void wxPropertySheetDialog::AddBookCtrl(wxSizer* sizer) -{ -#if defined(__POCKETPC__) && wxUSE_NOTEBOOK - // The book control has to be sized larger than the dialog because of a border bug - // in WinCE - int borderSize = -2; - sizer->Add( m_bookCtrl, 1, wxGROW|wxALIGN_CENTER_VERTICAL|wxLEFT|wxTOP|wxRIGHT, borderSize ); -#else - sizer->Add( m_bookCtrl, 1, wxGROW|wxALIGN_CENTER_VERTICAL|wxALL, m_sheetInnerBorder ); -#endif -} - -void wxPropertySheetDialog::OnActivate(wxActivateEvent& event) -{ -#if defined(__SMARTPHONE__) - // Attempt to focus the choice control: not yet working, but might - // be a step in the right direction. OnActivate overrides the default - // handler in toplevel.cpp that sets the focus for the first child of - // of the dialog (the choicebook). - if (event.GetActive()) - { - wxChoicebook* choiceBook = wxDynamicCast(GetBookCtrl(), wxChoicebook); - if (choiceBook) - choiceBook->SetFocus(); - } - else -#endif - event.Skip(); -} - -// Resize dialog if necessary -void wxPropertySheetDialog::OnIdle(wxIdleEvent& event) -{ - event.Skip(); - - if ((GetSheetStyle() & wxPROPSHEET_SHRINKTOFIT) && GetBookCtrl()) - { - int sel = GetBookCtrl()->GetSelection(); - if (sel != -1 && sel != m_selectedPage) - { - GetBookCtrl()->InvalidateBestSize(); - InvalidateBestSize(); - SetSizeHints(-1, -1, -1, -1); - - m_selectedPage = sel; - LayoutDialog(0); - } - } -} - -#endif // wxUSE_BOOKCTRL +///////////////////////////////////////////////////////////////////////////// +// Name: src/generic/propdlg.cpp +// Purpose: wxPropertySheetDialog +// Author: Julian Smart +// Modified by: +// Created: 2005-03-12 +// RCS-ID: $Id: propdlg.cpp 41838 2006-10-09 21:08:45Z VZ $ +// Copyright: (c) Julian Smart +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_BOOKCTRL + +#ifndef WX_PRECOMP + #include "wx/button.h" + #include "wx/sizer.h" + #include "wx/intl.h" + #include "wx/log.h" + #include "wx/msgdlg.h" +#endif + +#include "wx/bookctrl.h" + +#if wxUSE_NOTEBOOK +#include "wx/notebook.h" +#endif +#if wxUSE_CHOICEBOOK +#include "wx/choicebk.h" +#endif +#if wxUSE_TOOLBOOK +#include "wx/toolbook.h" +#endif +#if wxUSE_LISTBOOK +#include "wx/listbook.h" +#endif +#if wxUSE_TREEBOOK +#include "wx/treebook.h" +#endif + +#include "wx/generic/propdlg.h" +#include "wx/sysopt.h" + +//----------------------------------------------------------------------------- +// wxPropertySheetDialog +//----------------------------------------------------------------------------- + +IMPLEMENT_DYNAMIC_CLASS(wxPropertySheetDialog, wxDialog) + +BEGIN_EVENT_TABLE(wxPropertySheetDialog, wxDialog) + EVT_ACTIVATE(wxPropertySheetDialog::OnActivate) + EVT_IDLE(wxPropertySheetDialog::OnIdle) +END_EVENT_TABLE() + +bool wxPropertySheetDialog::Create(wxWindow* parent, wxWindowID id, const wxString& title, + const wxPoint& pos, const wxSize& sz, long style, + const wxString& name) +{ + if (!wxDialog::Create(parent, id, title, pos, sz, style|wxCLIP_CHILDREN, name)) + return false; + + wxBoxSizer *topSizer = new wxBoxSizer( wxVERTICAL ); + SetSizer(topSizer); + + // This gives more space around the edges + m_innerSizer = new wxBoxSizer( wxVERTICAL ); + +#if defined(__SMARTPHONE__) || defined(__POCKETPC__) + m_sheetOuterBorder = 0; +#endif + topSizer->Add(m_innerSizer, 1, wxGROW|wxALL, m_sheetOuterBorder); + + m_bookCtrl = CreateBookCtrl(); + AddBookCtrl(m_innerSizer); + + return true; +} + +void wxPropertySheetDialog::Init() +{ + m_sheetStyle = wxPROPSHEET_DEFAULT; + m_innerSizer = NULL; + m_bookCtrl = NULL; + m_sheetOuterBorder = 2; + m_sheetInnerBorder = 5; +} + +// Layout the dialog, to be called after pages have been created +void wxPropertySheetDialog::LayoutDialog(int centreFlags) +{ +#if !defined(__SMARTPHONE__) && !defined(__POCKETPC__) + GetSizer()->Fit(this); + GetSizer()->SetSizeHints(this); + if (centreFlags) + Centre(centreFlags); +#else + wxUnusedVar(centreFlags); +#endif +#if defined(__SMARTPHONE__) + if (m_bookCtrl) + m_bookCtrl->SetFocus(); +#endif +} + +// Creates the buttons, if any +void wxPropertySheetDialog::CreateButtons(int flags) +{ +#ifdef __POCKETPC__ + // keep system option status + const wxChar *optionName = wxT("wince.dialog.real-ok-cancel"); + const int status = wxSystemOptions::GetOptionInt(optionName); + wxSystemOptions::SetOption(optionName,0); +#endif + + wxSizer *buttonSizer = CreateButtonSizer( flags & ButtonSizerFlags ); + if( buttonSizer ) + { + m_innerSizer->Add( buttonSizer, 0, wxGROW|wxALIGN_CENTER_VERTICAL|wxTOP|wxBOTTOM|wxLEFT|wxRIGHT, 2); + m_innerSizer->AddSpacer(2); + } + +#ifdef __POCKETPC__ + // restore system option + wxSystemOptions::SetOption(optionName,status); +#endif +} + +// Creates the book control +wxBookCtrlBase* wxPropertySheetDialog::CreateBookCtrl() +{ + int style = wxCLIP_CHILDREN | wxBK_DEFAULT; + + wxBookCtrlBase* bookCtrl = NULL; + +#if wxUSE_NOTEBOOK + if (GetSheetStyle() & wxPROPSHEET_NOTEBOOK) + bookCtrl = new wxNotebook(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, style ); +#endif +#if wxUSE_CHOICEBOOK + if (GetSheetStyle() & wxPROPSHEET_CHOICEBOOK) + bookCtrl = new wxChoicebook(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, style ); +#endif +#if wxUSE_TOOLBOOK +#if defined(__WXMAC__) && wxUSE_TOOLBAR && wxUSE_BMPBUTTON + if (GetSheetStyle() & wxPROPSHEET_BUTTONTOOLBOOK) + bookCtrl = new wxToolbook(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, style|wxBK_BUTTONBAR ); + else +#endif + if ((GetSheetStyle() & wxPROPSHEET_TOOLBOOK) || (GetSheetStyle() & wxPROPSHEET_BUTTONTOOLBOOK)) + bookCtrl = new wxToolbook(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, style ); +#endif +#if wxUSE_LISTBOOK + if (GetSheetStyle() & wxPROPSHEET_LISTBOOK) + bookCtrl = new wxListbook(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, style ); +#endif +#if wxUSE_TREEBOOK + if (GetSheetStyle() & wxPROPSHEET_TREEBOOK) + bookCtrl = new wxTreebook(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, style ); +#endif + if (!bookCtrl) + bookCtrl = new wxBookCtrl(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, style ); + + if (GetSheetStyle() & wxPROPSHEET_SHRINKTOFIT) + bookCtrl->SetFitToCurrentPage(true); + + return bookCtrl; +} + +// Adds the book control to the inner sizer. +void wxPropertySheetDialog::AddBookCtrl(wxSizer* sizer) +{ +#if defined(__POCKETPC__) && wxUSE_NOTEBOOK + // The book control has to be sized larger than the dialog because of a border bug + // in WinCE + int borderSize = -2; + sizer->Add( m_bookCtrl, 1, wxGROW|wxALIGN_CENTER_VERTICAL|wxLEFT|wxTOP|wxRIGHT, borderSize ); +#else + sizer->Add( m_bookCtrl, 1, wxGROW|wxALIGN_CENTER_VERTICAL|wxALL, m_sheetInnerBorder ); +#endif +} + +void wxPropertySheetDialog::OnActivate(wxActivateEvent& event) +{ +#if defined(__SMARTPHONE__) + // Attempt to focus the choice control: not yet working, but might + // be a step in the right direction. OnActivate overrides the default + // handler in toplevel.cpp that sets the focus for the first child of + // of the dialog (the choicebook). + if (event.GetActive()) + { + wxChoicebook* choiceBook = wxDynamicCast(GetBookCtrl(), wxChoicebook); + if (choiceBook) + choiceBook->SetFocus(); + } + else +#endif + event.Skip(); +} + +// Resize dialog if necessary +void wxPropertySheetDialog::OnIdle(wxIdleEvent& event) +{ + event.Skip(); + + if ((GetSheetStyle() & wxPROPSHEET_SHRINKTOFIT) && GetBookCtrl()) + { + int sel = GetBookCtrl()->GetSelection(); + if (sel != -1 && sel != m_selectedPage) + { + GetBookCtrl()->InvalidateBestSize(); + InvalidateBestSize(); + SetSizeHints(-1, -1, -1, -1); + + m_selectedPage = sel; + LayoutDialog(0); + } + } +} + +#endif // wxUSE_BOOKCTRL diff --git a/Externals/wxWidgets/src/generic/regiong.cpp b/Externals/wxWidgets/src/generic/regiong.cpp index 7e48ae4039..4d1a057ac7 100644 --- a/Externals/wxWidgets/src/generic/regiong.cpp +++ b/Externals/wxWidgets/src/generic/regiong.cpp @@ -1,1919 +1,1919 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/generic/region.cpp -// Purpose: generic wxRegion class -// Author: David Elliott -// Modified by: -// Created: 2004/04/12 -// RCS-ID: $Id: regiong.cpp 41444 2006-09-25 18:18:26Z VZ $ -// Copyright: (c) 2004 David Elliott -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#include "wx/region.h" - -#ifndef WX_PRECOMP - #include "wx/utils.h" -#endif - -// ======================================================================== -// Classes to interface with X.org code -// ======================================================================== - -typedef struct Box -{ - wxCoord x1, x2, y1, y2; -} Box, BOX, BoxRec, *BoxPtr; - -typedef struct REGION *Region; - -struct REGION -{ -public: - // Default constructor initializes nothing - REGION() {} - - REGION(const wxRect& rect) - { - rects = &extents; - numRects = 1; - extents.x1 = rect.x; - extents.y1 = rect.y; - extents.x2 = rect.x + rect.width; - extents.y2 = rect.y + rect.height; - size = 1; - } - - BoxPtr GetBox(int i) - { - return i < numRects ? rects + i : NULL; - } - - // X.org methods - static bool XClipBox( - Region r, - wxRect *rect); - static bool XOffsetRegion( - register Region pRegion, - register int x, - register int y); - static bool XIntersectRegion( - Region reg1, - Region reg2, /* source regions */ - register Region newReg); /* destination Region */ - static bool XUnionRegion( - Region reg1, - Region reg2, /* source regions */ - Region newReg); /* destination Region */ - static bool XSubtractRegion( - Region regM, - Region regS, - register Region regD); - static bool XXorRegion(Region sra, Region srb, Region dr); - static bool XEmptyRegion( - Region r); - static bool XEqualRegion(Region r1, Region r2); - static bool XPointInRegion( - Region pRegion, - int x, int y); - static wxRegionContain XRectInRegion( - register Region region, - int rx, int ry, - unsigned int rwidth, unsigned int rheight); - -protected: - static Region XCreateRegion(void); - static void miSetExtents ( - Region pReg); - static bool XDestroyRegion(Region r); - static int miIntersectO ( - register Region pReg, - register BoxPtr r1, - BoxPtr r1End, - register BoxPtr r2, - BoxPtr r2End, - wxCoord y1, - wxCoord y2); - static void miRegionCopy( - register Region dstrgn, - register Region rgn); - static int miCoalesce( - register Region pReg, /* Region to coalesce */ - int prevStart, /* Index of start of previous band */ - int curStart); /* Index of start of current band */ - static void miRegionOp( - register Region newReg, /* Place to store result */ - Region reg1, /* First region in operation */ - Region reg2, /* 2d region in operation */ - int (*overlapFunc)( - register Region pReg, - register BoxPtr r1, - BoxPtr r1End, - register BoxPtr r2, - BoxPtr r2End, - wxCoord y1, - wxCoord y2), /* Function to call for over- - * lapping bands */ - int (*nonOverlap1Func)( - register Region pReg, - register BoxPtr r, - BoxPtr rEnd, - register wxCoord y1, - register wxCoord y2), /* Function to call for non- - * overlapping bands in region - * 1 */ - int (*nonOverlap2Func)( - register Region pReg, - register BoxPtr r, - BoxPtr rEnd, - register wxCoord y1, - register wxCoord y2)); /* Function to call for non- - * overlapping bands in region - * 2 */ - static int miUnionNonO ( - register Region pReg, - register BoxPtr r, - BoxPtr rEnd, - register wxCoord y1, - register wxCoord y2); - static int miUnionO ( - register Region pReg, - register BoxPtr r1, - BoxPtr r1End, - register BoxPtr r2, - BoxPtr r2End, - register wxCoord y1, - register wxCoord y2); - static int miSubtractNonO1 ( - register Region pReg, - register BoxPtr r, - BoxPtr rEnd, - register wxCoord y1, - register wxCoord y2); - static int miSubtractO ( - register Region pReg, - register BoxPtr r1, - BoxPtr r1End, - register BoxPtr r2, - BoxPtr r2End, - register wxCoord y1, - register wxCoord y2); -protected: - long size; - long numRects; - Box *rects; - Box extents; -}; - -// ======================================================================== -// wxRegionRefData -// ======================================================================== - -class wxRegionRefData : public wxObjectRefData, - public REGION -{ -public: - wxRegionRefData() - : wxObjectRefData(), - REGION() - { - size = 1; - numRects = 0; - rects = ( BOX * )malloc( (unsigned) sizeof( BOX )); - extents.x1 = 0; - extents.x2 = 0; - extents.y1 = 0; - extents.y2 = 0; - } - - wxRegionRefData(const wxPoint& topLeft, const wxPoint& bottomRight) - : wxObjectRefData(), - REGION() - { - rects = (BOX*)malloc(sizeof(BOX)); - size = 1; - numRects = 1; - extents.x1 = topLeft.x; - extents.y1 = topLeft.y; - extents.x2 = bottomRight.x; - extents.y2 = bottomRight.y; - *rects = extents; - } - - wxRegionRefData(const wxRect& rect) - : wxObjectRefData(), - REGION(rect) - { - rects = (BOX*)malloc(sizeof(BOX)); - *rects = extents; - } - - wxRegionRefData(const wxRegionRefData& refData) - : wxObjectRefData(), - REGION() - { - size = refData.size; - numRects = refData.numRects; - rects = (Box*)malloc(numRects*sizeof(Box)); - memcpy(rects, refData.rects, numRects*sizeof(Box)); - extents = refData.extents; - } - - virtual ~wxRegionRefData() - { - free(rects); - } - -private: - // Don't allow this - wxRegionRefData(const REGION&); -}; - -// ======================================================================== -// wxRegionGeneric -// ======================================================================== -//IMPLEMENT_DYNAMIC_CLASS(wxRegionGeneric, wxGDIObject) - -#define M_REGIONDATA ((wxRegionRefData *)m_refData) -#define M_REGIONDATA_OF(rgn) ((wxRegionRefData *)(rgn.m_refData)) - -// ---------------------------------------------------------------------------- -// wxRegionGeneric construction -// ---------------------------------------------------------------------------- - -wxRegionGeneric::wxRegionGeneric() -{ -} - -wxRegionGeneric::~wxRegionGeneric() -{ -} - -wxRegionGeneric::wxRegionGeneric(wxCoord x, wxCoord y, wxCoord w, wxCoord h) -{ - m_refData = new wxRegionRefData(wxRect(x,y,w,h)); -} - -wxRegionGeneric::wxRegionGeneric(const wxRect& rect) -{ - m_refData = new wxRegionRefData(rect); -} - -wxRegionGeneric::wxRegionGeneric(const wxPoint& topLeft, const wxPoint& bottomRight) -{ - m_refData = new wxRegionRefData(topLeft, bottomRight); -} - -void wxRegionGeneric::Clear() -{ - UnRef(); -} - -wxObjectRefData *wxRegionGeneric::CreateRefData() const -{ - return new wxRegionRefData; -} - -wxObjectRefData *wxRegionGeneric::CloneRefData(const wxObjectRefData *data) const -{ - return new wxRegionRefData(*(wxRegionRefData *)data); -} - -bool wxRegionGeneric::DoIsEqual(const wxRegion& region) const -{ - return REGION::XEqualRegion(M_REGIONDATA,M_REGIONDATA_OF(region)); -} - -bool wxRegionGeneric::DoGetBox(wxCoord& x, wxCoord& y, wxCoord&w, wxCoord &h) const -{ - if ( !m_refData ) - return false; - - wxRect rect; - REGION::XClipBox(M_REGIONDATA,&rect); - x = rect.x; - y = rect.y; - w = rect.width; - h = rect.height; - return true; -} - -// ---------------------------------------------------------------------------- -// wxRegionGeneric operations -// ---------------------------------------------------------------------------- - -bool wxRegionGeneric::DoUnionWithRect(const wxRect& rect) -{ - if ( rect.IsEmpty() ) - { - // nothing to do - return true; - } - - AllocExclusive(); - REGION region(rect); - return REGION::XUnionRegion(®ion,M_REGIONDATA,M_REGIONDATA); -} - -bool wxRegionGeneric::DoUnionWithRegion(const wxRegion& region) -{ - AllocExclusive(); - return REGION::XUnionRegion(M_REGIONDATA_OF(region),M_REGIONDATA,M_REGIONDATA); -} - -bool wxRegionGeneric::DoIntersect(const wxRegion& region) -{ - AllocExclusive(); - return REGION::XIntersectRegion(M_REGIONDATA_OF(region),M_REGIONDATA,M_REGIONDATA); -} - -bool wxRegionGeneric::DoSubtract(const wxRegion& region) -{ - if ( region.IsEmpty() ) - { - // nothing to do - return true; - } - - return REGION::XSubtractRegion(M_REGIONDATA_OF(region),M_REGIONDATA,M_REGIONDATA); -} - -bool wxRegionGeneric::DoXor(const wxRegion& region) -{ - AllocExclusive(); - return REGION::XXorRegion(M_REGIONDATA_OF(region),M_REGIONDATA,M_REGIONDATA); -} - -bool wxRegionGeneric::DoOffset(wxCoord x, wxCoord y) -{ - AllocExclusive(); - return REGION::XOffsetRegion(M_REGIONDATA, x, y); -} - -// ---------------------------------------------------------------------------- -// wxRegionGeneric comparison -// ---------------------------------------------------------------------------- - -bool wxRegionGeneric::IsEmpty() const -{ - wxASSERT(m_refData); - return REGION::XEmptyRegion(M_REGIONDATA); -} - -// Does the region contain the point (x,y)? -wxRegionContain wxRegionGeneric::DoContainsPoint(wxCoord x, wxCoord y) const -{ - wxASSERT(m_refData); - return REGION::XPointInRegion(M_REGIONDATA,x,y) ? wxInRegion : wxOutRegion; -} - -// Does the region contain the rectangle rect? -wxRegionContain wxRegionGeneric::DoContainsRect(const wxRect& rect) const -{ - wxASSERT(m_refData); - return REGION::XRectInRegion(M_REGIONDATA,rect.x,rect.y,rect.width,rect.height); -} - -// ======================================================================== -// wxRegionIteratorGeneric -// ======================================================================== -//IMPLEMENT_DYNAMIC_CLASS(wxRegionIteratorGeneric,wxObject) - -wxRegionIteratorGeneric::wxRegionIteratorGeneric() -{ - m_current = 0; -} - -wxRegionIteratorGeneric::wxRegionIteratorGeneric(const wxRegionGeneric& region) -: m_region(region) -{ - m_current = 0; -} - -wxRegionIteratorGeneric::wxRegionIteratorGeneric(const wxRegionIteratorGeneric& iterator) -: m_region(iterator.m_region) -{ - m_current = iterator.m_current; -} - -void wxRegionIteratorGeneric::Reset(const wxRegionGeneric& region) -{ - m_region = region; - m_current = 0; -} - -bool wxRegionIteratorGeneric::HaveRects() const -{ - return M_REGIONDATA_OF(m_region)->GetBox(m_current); -} - -wxRegionIteratorGeneric& wxRegionIteratorGeneric::operator++() -{ - ++m_current; - return *this; -} - -wxRegionIteratorGeneric wxRegionIteratorGeneric::operator++(int) -{ - wxRegionIteratorGeneric copy(*this); - ++*this; - return copy; -} - -wxRect wxRegionIteratorGeneric::GetRect() const -{ - wxASSERT(m_region.m_refData); - const Box *box = M_REGIONDATA_OF(m_region)->GetBox(m_current); - wxASSERT(box); - return wxRect - ( box->x1 - , box->y1 - , box->x2 - box->x1 - , box->y2 - box->y1 - ); -} - -long wxRegionIteratorGeneric::GetX() const -{ - wxASSERT(m_region.m_refData); - const Box *box = M_REGIONDATA_OF(m_region)->GetBox(m_current); - wxASSERT(box); - return box->x1; -} - -long wxRegionIteratorGeneric::GetY() const -{ - wxASSERT(m_region.m_refData); - const Box *box = M_REGIONDATA_OF(m_region)->GetBox(m_current); - wxASSERT(box); - return box->y1; -} - -long wxRegionIteratorGeneric::GetW() const -{ - wxASSERT(m_region.m_refData); - const Box *box = M_REGIONDATA_OF(m_region)->GetBox(m_current); - wxASSERT(box); - return box->x2 - box->x1; -} - -long wxRegionIteratorGeneric::GetH() const -{ - wxASSERT(m_region.m_refData); - const Box *box = M_REGIONDATA_OF(m_region)->GetBox(m_current); - wxASSERT(box); - return box->y2 - box->y1; -} - -wxRegionIteratorGeneric::~wxRegionIteratorGeneric() -{ -} - - -// ======================================================================== -// The guts (from X.org) -// ======================================================================== - -/************************************************************************ - -Copyright 1987, 1988, 1998 The Open Group - -Permission to use, copy, modify, distribute, and sell this software and its -documentation for any purpose is hereby granted without fee, provided that -the above copyright notice appear in all copies and that both that -copyright notice and this permission notice appear in supporting -documentation. - -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 -OPEN GROUP 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. - -Except as contained in this notice, the name of The Open Group shall not be -used in advertising or otherwise to promote the sale, use or other dealings -in this Software without prior written authorization from The Open Group. - - -Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts. - - All Rights Reserved - -Permission to use, copy, modify, and distribute this software and its -documentation for any purpose and without fee is hereby granted, -provided that the above copyright notice appear in all copies and that -both that copyright notice and this permission notice appear in -supporting documentation, and that the name of Digital not be -used in advertising or publicity pertaining to distribution of the -software without specific, written prior permission. - -DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING -ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL -DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR -ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, -WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS -SOFTWARE. - -************************************************************************/ - -/* 1 if two BOXs overlap. - * 0 if two BOXs do not overlap. - * Remember, x2 and y2 are not in the region - */ -#define EXTENTCHECK(r1, r2) \ - ((r1)->x2 > (r2)->x1 && \ - (r1)->x1 < (r2)->x2 && \ - (r1)->y2 > (r2)->y1 && \ - (r1)->y1 < (r2)->y2) - -/* - * Check to see if there is enough memory in the present region. - */ -#define MEMCHECK(reg, rect, firstrect){\ - if ((reg)->numRects >= ((reg)->size - 1)){\ - (firstrect) = (BOX *) realloc \ - ((char *)(firstrect), (unsigned) (2 * (sizeof(BOX)) * ((reg)->size)));\ - if ((firstrect) == 0)\ - return(0);\ - (reg)->size *= 2;\ - (rect) = &(firstrect)[(reg)->numRects];\ - }\ - } - -#define EMPTY_REGION(pReg) pReg->numRects = 0 - -#define REGION_NOT_EMPTY(pReg) pReg->numRects - -#define INBOX(r, x, y) \ - ( ( ((r).x2 > x)) && \ - ( ((r).x1 <= x)) && \ - ( ((r).y2 > y)) && \ - ( ((r).y1 <= y)) ) - -/* - * The functions in this file implement the Region abstraction, similar to one - * used in the X11 sample server. A Region is simply an area, as the name - * implies, and is implemented as a "y-x-banded" array of rectangles. To - * explain: Each Region is made up of a certain number of rectangles sorted - * by y coordinate first, and then by x coordinate. - * - * Furthermore, the rectangles are banded such that every rectangle with a - * given upper-left y coordinate (y1) will have the same lower-right y - * coordinate (y2) and vice versa. If a rectangle has scanlines in a band, it - * will span the entire vertical distance of the band. This means that some - * areas that could be merged into a taller rectangle will be represented as - * several shorter rectangles to account for shorter rectangles to its left - * or right but within its "vertical scope". - * - * An added constraint on the rectangles is that they must cover as much - * horizontal area as possible. E.g. no two rectangles in a band are allowed - * to touch. - * - * Whenever possible, bands will be merged together to cover a greater vertical - * distance (and thus reduce the number of rectangles). Two bands can be merged - * only if the bottom of one touches the top of the other and they have - * rectangles in the same places (of the same width, of course). This maintains - * the y-x-banding that's so nice to have... - */ - -/* Create a new empty region */ -Region REGION::XCreateRegion(void) -{ - Region temp = new REGION; - - if (!temp) - return (Region) NULL; - - temp->rects = ( BOX * )malloc( (unsigned) sizeof( BOX )); - - if (!temp->rects) - { - free((char *) temp); - return (Region) NULL; - } - temp->numRects = 0; - temp->extents.x1 = 0; - temp->extents.y1 = 0; - temp->extents.x2 = 0; - temp->extents.y2 = 0; - temp->size = 1; - return( temp ); -} - -bool REGION::XClipBox(Region r, wxRect *rect) -{ - rect->x = r->extents.x1; - rect->y = r->extents.y1; - rect->width = r->extents.x2 - r->extents.x1; - rect->height = r->extents.y2 - r->extents.y1; - return true; -} - -/*- - *----------------------------------------------------------------------- - * miSetExtents -- - * Reset the extents of a region to what they should be. Called by - * miSubtract and miIntersect b/c they can't figure it out along the - * way or do so easily, as miUnion can. - * - * Results: - * None. - * - * Side Effects: - * The region's 'extents' structure is overwritten. - * - *----------------------------------------------------------------------- - */ -void REGION:: -miSetExtents (Region pReg) -{ - register BoxPtr pBox, - pBoxEnd, - pExtents; - - if (pReg->numRects == 0) - { - pReg->extents.x1 = 0; - pReg->extents.y1 = 0; - pReg->extents.x2 = 0; - pReg->extents.y2 = 0; - return; - } - - pExtents = &pReg->extents; - pBox = pReg->rects; - pBoxEnd = &pBox[pReg->numRects - 1]; - - /* - * Since pBox is the first rectangle in the region, it must have the - * smallest y1 and since pBoxEnd is the last rectangle in the region, - * it must have the largest y2, because of banding. Initialize x1 and - * x2 from pBox and pBoxEnd, resp., as good things to initialize them - * to... - */ - pExtents->x1 = pBox->x1; - pExtents->y1 = pBox->y1; - pExtents->x2 = pBoxEnd->x2; - pExtents->y2 = pBoxEnd->y2; - - assert(pExtents->y1 < pExtents->y2); - while (pBox <= pBoxEnd) - { - if (pBox->x1 < pExtents->x1) - { - pExtents->x1 = pBox->x1; - } - if (pBox->x2 > pExtents->x2) - { - pExtents->x2 = pBox->x2; - } - pBox++; - } - assert(pExtents->x1 < pExtents->x2); -} - -bool REGION:: -XDestroyRegion( - Region r) -{ - free( (char *) r->rects ); - delete r; - return true; -} - -/* TranslateRegion(pRegion, x, y) - translates in place - added by raymond -*/ - -bool REGION:: -XOffsetRegion( - register Region pRegion, - register int x, - register int y) -{ - register int nbox; - register BOX *pbox; - - pbox = pRegion->rects; - nbox = pRegion->numRects; - - while(nbox--) - { - pbox->x1 += x; - pbox->x2 += x; - pbox->y1 += y; - pbox->y2 += y; - pbox++; - } - pRegion->extents.x1 += x; - pRegion->extents.x2 += x; - pRegion->extents.y1 += y; - pRegion->extents.y2 += y; - return 1; -} - -/*====================================================================== - * Region Intersection - *====================================================================*/ -/*- - *----------------------------------------------------------------------- - * miIntersectO -- - * Handle an overlapping band for miIntersect. - * - * Results: - * None. - * - * Side Effects: - * Rectangles may be added to the region. - * - *----------------------------------------------------------------------- - */ -/* static void*/ -int REGION:: -miIntersectO ( - register Region pReg, - register BoxPtr r1, - BoxPtr r1End, - register BoxPtr r2, - BoxPtr r2End, - wxCoord y1, - wxCoord y2) -{ - register wxCoord x1; - register wxCoord x2; - register BoxPtr pNextRect; - - pNextRect = &pReg->rects[pReg->numRects]; - - while ((r1 != r1End) && (r2 != r2End)) - { - x1 = wxMax(r1->x1,r2->x1); - x2 = wxMin(r1->x2,r2->x2); - - /* - * If there's any overlap between the two rectangles, add that - * overlap to the new region. - * There's no need to check for subsumption because the only way - * such a need could arise is if some region has two rectangles - * right next to each other. Since that should never happen... - */ - if (x1 < x2) - { - assert(y1rects); - pNextRect->x1 = x1; - pNextRect->y1 = y1; - pNextRect->x2 = x2; - pNextRect->y2 = y2; - pReg->numRects += 1; - pNextRect++; - assert(pReg->numRects <= pReg->size); - } - - /* - * Need to advance the pointers. Shift the one that extends - * to the right the least, since the other still has a chance to - * overlap with that region's next rectangle, if you see what I mean. - */ - if (r1->x2 < r2->x2) - { - r1++; - } - else if (r2->x2 < r1->x2) - { - r2++; - } - else - { - r1++; - r2++; - } - } - return 0; /* lint */ -} - -bool REGION:: -XIntersectRegion( - Region reg1, - Region reg2, /* source regions */ - register Region newReg) /* destination Region */ -{ - /* check for trivial reject */ - if ( (!(reg1->numRects)) || (!(reg2->numRects)) || - (!EXTENTCHECK(®1->extents, ®2->extents))) - newReg->numRects = 0; - else - miRegionOp (newReg, reg1, reg2, - miIntersectO, NULL, NULL); - - /* - * Can't alter newReg's extents before we call miRegionOp because - * it might be one of the source regions and miRegionOp depends - * on the extents of those regions being the same. Besides, this - * way there's no checking against rectangles that will be nuked - * due to coalescing, so we have to examine fewer rectangles. - */ - miSetExtents(newReg); - return 1; -} - -void REGION:: -miRegionCopy( - register Region dstrgn, - register Region rgn) - -{ - if (dstrgn != rgn) /* don't want to copy to itself */ - { - if (dstrgn->size < rgn->numRects) - { - if (dstrgn->rects) - { - BOX *prevRects = dstrgn->rects; - - dstrgn->rects = (BOX *) - realloc((char *) dstrgn->rects, - (unsigned) rgn->numRects * (sizeof(BOX))); - if (!dstrgn->rects) - { - free(prevRects); - return; - } - } - dstrgn->size = rgn->numRects; - } - dstrgn->numRects = rgn->numRects; - dstrgn->extents.x1 = rgn->extents.x1; - dstrgn->extents.y1 = rgn->extents.y1; - dstrgn->extents.x2 = rgn->extents.x2; - dstrgn->extents.y2 = rgn->extents.y2; - - memcpy((char *) dstrgn->rects, (char *) rgn->rects, - (int) (rgn->numRects * sizeof(BOX))); - } -} - -/*====================================================================== - * Generic Region Operator - *====================================================================*/ - -/*- - *----------------------------------------------------------------------- - * miCoalesce -- - * Attempt to merge the boxes in the current band with those in the - * previous one. Used only by miRegionOp. - * - * Results: - * The new index for the previous band. - * - * Side Effects: - * If coalescing takes place: - * - rectangles in the previous band will have their y2 fields - * altered. - * - pReg->numRects will be decreased. - * - *----------------------------------------------------------------------- - */ -/* static int*/ -int REGION:: -miCoalesce( - register Region pReg, /* Region to coalesce */ - int prevStart, /* Index of start of previous band */ - int curStart) /* Index of start of current band */ -{ - register BoxPtr pPrevBox; /* Current box in previous band */ - register BoxPtr pCurBox; /* Current box in current band */ - register BoxPtr pRegEnd; /* End of region */ - int curNumRects; /* Number of rectangles in current - * band */ - int prevNumRects; /* Number of rectangles in previous - * band */ - int bandY1; /* Y1 coordinate for current band */ - - pRegEnd = &pReg->rects[pReg->numRects]; - - pPrevBox = &pReg->rects[prevStart]; - prevNumRects = curStart - prevStart; - - /* - * Figure out how many rectangles are in the current band. Have to do - * this because multiple bands could have been added in miRegionOp - * at the end when one region has been exhausted. - */ - pCurBox = &pReg->rects[curStart]; - bandY1 = pCurBox->y1; - for (curNumRects = 0; - (pCurBox != pRegEnd) && (pCurBox->y1 == bandY1); - curNumRects++) - { - pCurBox++; - } - - if (pCurBox != pRegEnd) - { - /* - * If more than one band was added, we have to find the start - * of the last band added so the next coalescing job can start - * at the right place... (given when multiple bands are added, - * this may be pointless -- see above). - */ - pRegEnd--; - while (pRegEnd[-1].y1 == pRegEnd->y1) - { - pRegEnd--; - } - curStart = pRegEnd - pReg->rects; - pRegEnd = pReg->rects + pReg->numRects; - } - - if ((curNumRects == prevNumRects) && (curNumRects != 0)) - { - pCurBox -= curNumRects; - /* - * The bands may only be coalesced if the bottom of the previous - * matches the top scanline of the current. - */ - if (pPrevBox->y2 == pCurBox->y1) - { - /* - * Make sure the bands have boxes in the same places. This - * assumes that boxes have been added in such a way that they - * cover the most area possible. I.e. two boxes in a band must - * have some horizontal space between them. - */ - do - { - if ((pPrevBox->x1 != pCurBox->x1) || - (pPrevBox->x2 != pCurBox->x2)) - { - /* - * The bands don't line up so they can't be coalesced. - */ - return (curStart); - } - pPrevBox++; - pCurBox++; - prevNumRects -= 1; - } while (prevNumRects != 0); - - pReg->numRects -= curNumRects; - pCurBox -= curNumRects; - pPrevBox -= curNumRects; - - /* - * The bands may be merged, so set the bottom y of each box - * in the previous band to that of the corresponding box in - * the current band. - */ - do - { - pPrevBox->y2 = pCurBox->y2; - pPrevBox++; - pCurBox++; - curNumRects -= 1; - } while (curNumRects != 0); - - /* - * If only one band was added to the region, we have to backup - * curStart to the start of the previous band. - * - * If more than one band was added to the region, copy the - * other bands down. The assumption here is that the other bands - * came from the same region as the current one and no further - * coalescing can be done on them since it's all been done - * already... curStart is already in the right place. - */ - if (pCurBox == pRegEnd) - { - curStart = prevStart; - } - else - { - do - { - *pPrevBox++ = *pCurBox++; - } while (pCurBox != pRegEnd); - } - - } - } - return (curStart); -} - -/*- - *----------------------------------------------------------------------- - * miRegionOp -- - * Apply an operation to two regions. Called by miUnion, miInverse, - * miSubtract, miIntersect... - * - * Results: - * None. - * - * Side Effects: - * The new region is overwritten. - * - * Notes: - * The idea behind this function is to view the two regions as sets. - * Together they cover a rectangle of area that this function divides - * into horizontal bands where points are covered only by one region - * or by both. For the first case, the nonOverlapFunc is called with - * each the band and the band's upper and lower extents. For the - * second, the overlapFunc is called to process the entire band. It - * is responsible for clipping the rectangles in the band, though - * this function provides the boundaries. - * At the end of each band, the new region is coalesced, if possible, - * to reduce the number of rectangles in the region. - * - *----------------------------------------------------------------------- - */ -/* static void*/ -void REGION:: -miRegionOp( - register Region newReg, /* Place to store result */ - Region reg1, /* First region in operation */ - Region reg2, /* 2d region in operation */ - int (*overlapFunc)( - register Region pReg, - register BoxPtr r1, - BoxPtr r1End, - register BoxPtr r2, - BoxPtr r2End, - wxCoord y1, - wxCoord y2), /* Function to call for over- - * lapping bands */ - int (*nonOverlap1Func)( - register Region pReg, - register BoxPtr r, - BoxPtr rEnd, - register wxCoord y1, - register wxCoord y2), /* Function to call for non- - * overlapping bands in region - * 1 */ - int (*nonOverlap2Func)( - register Region pReg, - register BoxPtr r, - BoxPtr rEnd, - register wxCoord y1, - register wxCoord y2)) /* Function to call for non- - * overlapping bands in region - * 2 */ -{ - register BoxPtr r1; /* Pointer into first region */ - register BoxPtr r2; /* Pointer into 2d region */ - BoxPtr r1End; /* End of 1st region */ - BoxPtr r2End; /* End of 2d region */ - register wxCoord ybot; /* Bottom of intersection */ - register wxCoord ytop; /* Top of intersection */ - BoxPtr oldRects; /* Old rects for newReg */ - int prevBand; /* Index of start of - * previous band in newReg */ - int curBand; /* Index of start of current - * band in newReg */ - register BoxPtr r1BandEnd; /* End of current band in r1 */ - register BoxPtr r2BandEnd; /* End of current band in r2 */ - wxCoord top; /* Top of non-overlapping - * band */ - wxCoord bot; /* Bottom of non-overlapping - * band */ - - /* - * Initialization: - * set r1, r2, r1End and r2End appropriately, preserve the important - * parts of the destination region until the end in case it's one of - * the two source regions, then mark the "new" region empty, allocating - * another array of rectangles for it to use. - */ - r1 = reg1->rects; - r2 = reg2->rects; - r1End = r1 + reg1->numRects; - r2End = r2 + reg2->numRects; - - oldRects = newReg->rects; - - EMPTY_REGION(newReg); - - /* - * Allocate a reasonable number of rectangles for the new region. The idea - * is to allocate enough so the individual functions don't need to - * reallocate and copy the array, which is time consuming, yet we don't - * have to worry about using too much memory. I hope to be able to - * nuke the realloc() at the end of this function eventually. - */ - newReg->size = wxMax(reg1->numRects,reg2->numRects) * 2; - - newReg->rects = (BoxPtr)malloc((unsigned) (sizeof(BoxRec) * newReg->size)); - - if (!newReg->rects) - { - newReg->size = 0; - return; - } - - /* - * Initialize ybot and ytop. - * In the upcoming loop, ybot and ytop serve different functions depending - * on whether the band being handled is an overlapping or non-overlapping - * band. - * In the case of a non-overlapping band (only one of the regions - * has points in the band), ybot is the bottom of the most recent - * intersection and thus clips the top of the rectangles in that band. - * ytop is the top of the next intersection between the two regions and - * serves to clip the bottom of the rectangles in the current band. - * For an overlapping band (where the two regions intersect), ytop clips - * the top of the rectangles of both regions and ybot clips the bottoms. - */ - if (reg1->extents.y1 < reg2->extents.y1) - ybot = reg1->extents.y1; - else - ybot = reg2->extents.y1; - - /* - * prevBand serves to mark the start of the previous band so rectangles - * can be coalesced into larger rectangles. qv. miCoalesce, above. - * In the beginning, there is no previous band, so prevBand == curBand - * (curBand is set later on, of course, but the first band will always - * start at index 0). prevBand and curBand must be indices because of - * the possible expansion, and resultant moving, of the new region's - * array of rectangles. - */ - prevBand = 0; - - do - { - curBand = newReg->numRects; - - /* - * This algorithm proceeds one source-band (as opposed to a - * destination band, which is determined by where the two regions - * intersect) at a time. r1BandEnd and r2BandEnd serve to mark the - * rectangle after the last one in the current band for their - * respective regions. - */ - r1BandEnd = r1; - while ((r1BandEnd != r1End) && (r1BandEnd->y1 == r1->y1)) - { - r1BandEnd++; - } - - r2BandEnd = r2; - while ((r2BandEnd != r2End) && (r2BandEnd->y1 == r2->y1)) - { - r2BandEnd++; - } - - /* - * First handle the band that doesn't intersect, if any. - * - * Note that attention is restricted to one band in the - * non-intersecting region at once, so if a region has n - * bands between the current position and the next place it overlaps - * the other, this entire loop will be passed through n times. - */ - if (r1->y1 < r2->y1) - { - top = wxMax(r1->y1,ybot); - bot = wxMin(r1->y2,r2->y1); - - if ((top != bot) && (nonOverlap1Func != NULL)) - { - (* nonOverlap1Func) (newReg, r1, r1BandEnd, top, bot); - } - - ytop = r2->y1; - } - else if (r2->y1 < r1->y1) - { - top = wxMax(r2->y1,ybot); - bot = wxMin(r2->y2,r1->y1); - - if ((top != bot) && (nonOverlap2Func != NULL)) - { - (* nonOverlap2Func) (newReg, r2, r2BandEnd, top, bot); - } - - ytop = r1->y1; - } - else - { - ytop = r1->y1; - } - - /* - * If any rectangles got added to the region, try and coalesce them - * with rectangles from the previous band. Note we could just do - * this test in miCoalesce, but some machines incur a not - * inconsiderable cost for function calls, so... - */ - if (newReg->numRects != curBand) - { - prevBand = miCoalesce (newReg, prevBand, curBand); - } - - /* - * Now see if we've hit an intersecting band. The two bands only - * intersect if ybot > ytop - */ - ybot = wxMin(r1->y2, r2->y2); - curBand = newReg->numRects; - if (ybot > ytop) - { - (* overlapFunc) (newReg, r1, r1BandEnd, r2, r2BandEnd, ytop, ybot); - - } - - if (newReg->numRects != curBand) - { - prevBand = miCoalesce (newReg, prevBand, curBand); - } - - /* - * If we've finished with a band (y2 == ybot) we skip forward - * in the region to the next band. - */ - if (r1->y2 == ybot) - { - r1 = r1BandEnd; - } - if (r2->y2 == ybot) - { - r2 = r2BandEnd; - } - } while ((r1 != r1End) && (r2 != r2End)); - - /* - * Deal with whichever region still has rectangles left. - */ - curBand = newReg->numRects; - if (r1 != r1End) - { - if (nonOverlap1Func != NULL) - { - do - { - r1BandEnd = r1; - while ((r1BandEnd < r1End) && (r1BandEnd->y1 == r1->y1)) - { - r1BandEnd++; - } - (* nonOverlap1Func) (newReg, r1, r1BandEnd, - wxMax(r1->y1,ybot), r1->y2); - r1 = r1BandEnd; - } while (r1 != r1End); - } - } - else if ((r2 != r2End) && (nonOverlap2Func != NULL)) - { - do - { - r2BandEnd = r2; - while ((r2BandEnd < r2End) && (r2BandEnd->y1 == r2->y1)) - { - r2BandEnd++; - } - (* nonOverlap2Func) (newReg, r2, r2BandEnd, - wxMax(r2->y1,ybot), r2->y2); - r2 = r2BandEnd; - } while (r2 != r2End); - } - - if (newReg->numRects != curBand) - { - (void) miCoalesce (newReg, prevBand, curBand); - } - - /* - * A bit of cleanup. To keep regions from growing without bound, - * we shrink the array of rectangles to match the new number of - * rectangles in the region. This never goes to 0, however... - * - * Only do this stuff if the number of rectangles allocated is more than - * twice the number of rectangles in the region (a simple optimization...). - */ - if (newReg->numRects < (newReg->size >> 1)) - { - if (REGION_NOT_EMPTY(newReg)) - { - BoxPtr prev_rects = newReg->rects; - newReg->size = newReg->numRects; - newReg->rects = (BoxPtr) realloc ((char *) newReg->rects, - (unsigned) (sizeof(BoxRec) * newReg->size)); - if (! newReg->rects) - newReg->rects = prev_rects; - } - else - { - /* - * No point in doing the extra work involved in an realloc if - * the region is empty - */ - newReg->size = 1; - free((char *) newReg->rects); - newReg->rects = (BoxPtr) malloc(sizeof(BoxRec)); - } - } - free ((char *) oldRects); - return; -} - -/*====================================================================== - * Region Union - *====================================================================*/ - -/*- - *----------------------------------------------------------------------- - * miUnionNonO -- - * Handle a non-overlapping band for the union operation. Just - * Adds the rectangles into the region. Doesn't have to check for - * subsumption or anything. - * - * Results: - * None. - * - * Side Effects: - * pReg->numRects is incremented and the final rectangles overwritten - * with the rectangles we're passed. - * - *----------------------------------------------------------------------- - */ -/* static void*/ -int REGION:: -miUnionNonO ( - register Region pReg, - register BoxPtr r, - BoxPtr rEnd, - register wxCoord y1, - register wxCoord y2) -{ - register BoxPtr pNextRect; - - pNextRect = &pReg->rects[pReg->numRects]; - - assert(y1 < y2); - - while (r != rEnd) - { - assert(r->x1 < r->x2); - MEMCHECK(pReg, pNextRect, pReg->rects); - pNextRect->x1 = r->x1; - pNextRect->y1 = y1; - pNextRect->x2 = r->x2; - pNextRect->y2 = y2; - pReg->numRects += 1; - pNextRect++; - - assert(pReg->numRects<=pReg->size); - r++; - } - return 0; /* lint */ -} - - -/*- - *----------------------------------------------------------------------- - * miUnionO -- - * Handle an overlapping band for the union operation. Picks the - * left-most rectangle each time and merges it into the region. - * - * Results: - * None. - * - * Side Effects: - * Rectangles are overwritten in pReg->rects and pReg->numRects will - * be changed. - * - *----------------------------------------------------------------------- - */ - -/* static void*/ -int REGION:: -miUnionO ( - register Region pReg, - register BoxPtr r1, - BoxPtr r1End, - register BoxPtr r2, - BoxPtr r2End, - register wxCoord y1, - register wxCoord y2) -{ - register BoxPtr pNextRect; - - pNextRect = &pReg->rects[pReg->numRects]; - -#define MERGERECT(r) \ - if ((pReg->numRects != 0) && \ - (pNextRect[-1].y1 == y1) && \ - (pNextRect[-1].y2 == y2) && \ - (pNextRect[-1].x2 >= r->x1)) \ - { \ - if (pNextRect[-1].x2 < r->x2) \ - { \ - pNextRect[-1].x2 = r->x2; \ - assert(pNextRect[-1].x1rects); \ - pNextRect->y1 = y1; \ - pNextRect->y2 = y2; \ - pNextRect->x1 = r->x1; \ - pNextRect->x2 = r->x2; \ - pReg->numRects += 1; \ - pNextRect += 1; \ - } \ - assert(pReg->numRects<=pReg->size);\ - r++; - - assert (y1x1 < r2->x1) - { - MERGERECT(r1); - } - else - { - MERGERECT(r2); - } - } - - if (r1 != r1End) - { - do - { - MERGERECT(r1); - } while (r1 != r1End); - } - else while (r2 != r2End) - { - MERGERECT(r2); - } - return 0; /* lint */ -} - -bool REGION:: -XUnionRegion( - Region reg1, - Region reg2, /* source regions */ - Region newReg) /* destination Region */ -{ - /* checks all the simple cases */ - - /* - * Region 1 and 2 are the same or region 1 is empty - */ - if ( (reg1 == reg2) || (!(reg1->numRects)) ) - { - if (newReg != reg2) - miRegionCopy(newReg, reg2); - return 1; - } - - /* - * if nothing to union (region 2 empty) - */ - if (!(reg2->numRects)) - { - if (newReg != reg1) - miRegionCopy(newReg, reg1); - return 1; - } - - /* - * Region 1 completely subsumes region 2 - */ - if ((reg1->numRects == 1) && - (reg1->extents.x1 <= reg2->extents.x1) && - (reg1->extents.y1 <= reg2->extents.y1) && - (reg1->extents.x2 >= reg2->extents.x2) && - (reg1->extents.y2 >= reg2->extents.y2)) - { - if (newReg != reg1) - miRegionCopy(newReg, reg1); - return 1; - } - - /* - * Region 2 completely subsumes region 1 - */ - if ((reg2->numRects == 1) && - (reg2->extents.x1 <= reg1->extents.x1) && - (reg2->extents.y1 <= reg1->extents.y1) && - (reg2->extents.x2 >= reg1->extents.x2) && - (reg2->extents.y2 >= reg1->extents.y2)) - { - if (newReg != reg2) - miRegionCopy(newReg, reg2); - return 1; - } - - miRegionOp (newReg, reg1, reg2, miUnionO, - miUnionNonO, miUnionNonO); - - newReg->extents.x1 = wxMin(reg1->extents.x1, reg2->extents.x1); - newReg->extents.y1 = wxMin(reg1->extents.y1, reg2->extents.y1); - newReg->extents.x2 = wxMax(reg1->extents.x2, reg2->extents.x2); - newReg->extents.y2 = wxMax(reg1->extents.y2, reg2->extents.y2); - - return 1; -} - -/*====================================================================== - * Region Subtraction - *====================================================================*/ - -/*- - *----------------------------------------------------------------------- - * miSubtractNonO -- - * Deal with non-overlapping band for subtraction. Any parts from - * region 2 we discard. Anything from region 1 we add to the region. - * - * Results: - * None. - * - * Side Effects: - * pReg may be affected. - * - *----------------------------------------------------------------------- - */ -/* static void*/ -int REGION:: -miSubtractNonO1 ( - register Region pReg, - register BoxPtr r, - BoxPtr rEnd, - register wxCoord y1, - register wxCoord y2) -{ - register BoxPtr pNextRect; - - pNextRect = &pReg->rects[pReg->numRects]; - - assert(y1x1x2); - MEMCHECK(pReg, pNextRect, pReg->rects); - pNextRect->x1 = r->x1; - pNextRect->y1 = y1; - pNextRect->x2 = r->x2; - pNextRect->y2 = y2; - pReg->numRects += 1; - pNextRect++; - - assert(pReg->numRects <= pReg->size); - - r++; - } - return 0; /* lint */ -} - -/*- - *----------------------------------------------------------------------- - * miSubtractO -- - * Overlapping band subtraction. x1 is the left-most point not yet - * checked. - * - * Results: - * None. - * - * Side Effects: - * pReg may have rectangles added to it. - * - *----------------------------------------------------------------------- - */ -/* static void*/ -int REGION:: -miSubtractO ( - register Region pReg, - register BoxPtr r1, - BoxPtr r1End, - register BoxPtr r2, - BoxPtr r2End, - register wxCoord y1, - register wxCoord y2) -{ - register BoxPtr pNextRect; - register int x1; - - x1 = r1->x1; - - assert(y1rects[pReg->numRects]; - - while ((r1 != r1End) && (r2 != r2End)) - { - if (r2->x2 <= x1) - { - /* - * Subtrahend missed the boat: go to next subtrahend. - */ - r2++; - } - else if (r2->x1 <= x1) - { - /* - * Subtrahend preceeds minuend: nuke left edge of minuend. - */ - x1 = r2->x2; - if (x1 >= r1->x2) - { - /* - * Minuend completely covered: advance to next minuend and - * reset left fence to edge of new minuend. - */ - r1++; - if (r1 != r1End) - x1 = r1->x1; - } - else - { - /* - * Subtrahend now used up since it doesn't extend beyond - * minuend - */ - r2++; - } - } - else if (r2->x1 < r1->x2) - { - /* - * Left part of subtrahend covers part of minuend: add uncovered - * part of minuend to region and skip to next subtrahend. - */ - assert(x1x1); - MEMCHECK(pReg, pNextRect, pReg->rects); - pNextRect->x1 = x1; - pNextRect->y1 = y1; - pNextRect->x2 = r2->x1; - pNextRect->y2 = y2; - pReg->numRects += 1; - pNextRect++; - - assert(pReg->numRects<=pReg->size); - - x1 = r2->x2; - if (x1 >= r1->x2) - { - /* - * Minuend used up: advance to new... - */ - r1++; - if (r1 != r1End) - x1 = r1->x1; - } - else - { - /* - * Subtrahend used up - */ - r2++; - } - } - else - { - /* - * Minuend used up: add any remaining piece before advancing. - */ - if (r1->x2 > x1) - { - MEMCHECK(pReg, pNextRect, pReg->rects); - pNextRect->x1 = x1; - pNextRect->y1 = y1; - pNextRect->x2 = r1->x2; - pNextRect->y2 = y2; - pReg->numRects += 1; - pNextRect++; - assert(pReg->numRects<=pReg->size); - } - r1++; - if (r1 != r1End) - x1 = r1->x1; - } - } - - /* - * Add remaining minuend rectangles to region. - */ - while (r1 != r1End) - { - assert(x1x2); - MEMCHECK(pReg, pNextRect, pReg->rects); - pNextRect->x1 = x1; - pNextRect->y1 = y1; - pNextRect->x2 = r1->x2; - pNextRect->y2 = y2; - pReg->numRects += 1; - pNextRect++; - - assert(pReg->numRects<=pReg->size); - - r1++; - if (r1 != r1End) - { - x1 = r1->x1; - } - } - return 0; /* lint */ -} - -/*- - *----------------------------------------------------------------------- - * miSubtract -- - * Subtract regS from regM and leave the result in regD. - * S stands for subtrahend, M for minuend and D for difference. - * - * Results: - * true. - * - * Side Effects: - * regD is overwritten. - * - *----------------------------------------------------------------------- - */ - -bool REGION::XSubtractRegion(Region regM, Region regS, register Region regD) -{ - /* check for trivial reject */ - if ( (!(regM->numRects)) || (!(regS->numRects)) || - (!EXTENTCHECK(®M->extents, ®S->extents)) ) - { - miRegionCopy(regD, regM); - return true; - } - - miRegionOp (regD, regM, regS, miSubtractO, - miSubtractNonO1, NULL); - - /* - * Can't alter newReg's extents before we call miRegionOp because - * it might be one of the source regions and miRegionOp depends - * on the extents of those regions being the unaltered. Besides, this - * way there's no checking against rectangles that will be nuked - * due to coalescing, so we have to examine fewer rectangles. - */ - miSetExtents (regD); - return true; -} - -bool REGION::XXorRegion(Region sra, Region srb, Region dr) -{ - Region tra = XCreateRegion(); - - wxCHECK_MSG( tra, false, wxT("region not created") ); - - Region trb = XCreateRegion(); - - wxCHECK_MSG( trb, false, wxT("region not created") ); - - (void) XSubtractRegion(sra,srb,tra); - (void) XSubtractRegion(srb,sra,trb); - (void) XUnionRegion(tra,trb,dr); - XDestroyRegion(tra); - XDestroyRegion(trb); - return 0; -} - -/* - * Check to see if the region is empty. Assumes a region is passed - * as a parameter - */ -bool REGION::XEmptyRegion(Region r) -{ - if( r->numRects == 0 ) return true; - else return false; -} - -/* - * Check to see if two regions are equal - */ -bool REGION::XEqualRegion(Region r1, Region r2) -{ - int i; - - if( r1->numRects != r2->numRects ) return false; - else if( r1->numRects == 0 ) return true; - else if ( r1->extents.x1 != r2->extents.x1 ) return false; - else if ( r1->extents.x2 != r2->extents.x2 ) return false; - else if ( r1->extents.y1 != r2->extents.y1 ) return false; - else if ( r1->extents.y2 != r2->extents.y2 ) return false; - else for( i=0; i < r1->numRects; i++ ) { - if ( r1->rects[i].x1 != r2->rects[i].x1 ) return false; - else if ( r1->rects[i].x2 != r2->rects[i].x2 ) return false; - else if ( r1->rects[i].y1 != r2->rects[i].y1 ) return false; - else if ( r1->rects[i].y2 != r2->rects[i].y2 ) return false; - } - return true; -} - -bool REGION::XPointInRegion(Region pRegion, int x, int y) -{ - int i; - - if (pRegion->numRects == 0) - return false; - if (!INBOX(pRegion->extents, x, y)) - return false; - for (i=0; inumRects; i++) - { - if (INBOX (pRegion->rects[i], x, y)) - return true; - } - return false; -} - -wxRegionContain REGION::XRectInRegion(register Region region, - int rx, int ry, - unsigned int rwidth, - unsigned int rheight) -{ - register BoxPtr pbox; - register BoxPtr pboxEnd; - Box rect; - register BoxPtr prect = ▭ - int partIn, partOut; - - prect->x1 = rx; - prect->y1 = ry; - prect->x2 = rwidth + rx; - prect->y2 = rheight + ry; - - /* this is (just) a useful optimization */ - if ((region->numRects == 0) || !EXTENTCHECK(®ion->extents, prect)) - return(wxOutRegion); - - partOut = false; - partIn = false; - - /* can stop when both partOut and partIn are true, or we reach prect->y2 */ - for (pbox = region->rects, pboxEnd = pbox + region->numRects; - pbox < pboxEnd; - pbox++) - { - - if (pbox->y2 <= ry) - continue; /* getting up to speed or skipping remainder of band */ - - if (pbox->y1 > ry) - { - partOut = true; /* missed part of rectangle above */ - if (partIn || (pbox->y1 >= prect->y2)) - break; - ry = pbox->y1; /* x guaranteed to be == prect->x1 */ - } - - if (pbox->x2 <= rx) - continue; /* not far enough over yet */ - - if (pbox->x1 > rx) - { - partOut = true; /* missed part of rectangle to left */ - if (partIn) - break; - } - - if (pbox->x1 < prect->x2) - { - partIn = true; /* definitely overlap */ - if (partOut) - break; - } - - if (pbox->x2 >= prect->x2) - { - ry = pbox->y2; /* finished with this band */ - if (ry >= prect->y2) - break; - rx = prect->x1; /* reset x out to left again */ - } else - { - /* - * Because boxes in a band are maximal width, if the first box - * to overlap the rectangle doesn't completely cover it in that - * band, the rectangle must be partially out, since some of it - * will be uncovered in that band. partIn will have been set true - * by now... - */ - break; - } - - } - - return(partIn ? ((ry < prect->y2) ? wxPartRegion : wxInRegion) : - wxOutRegion); -} +///////////////////////////////////////////////////////////////////////////// +// Name: src/generic/region.cpp +// Purpose: generic wxRegion class +// Author: David Elliott +// Modified by: +// Created: 2004/04/12 +// RCS-ID: $Id: regiong.cpp 41444 2006-09-25 18:18:26Z VZ $ +// Copyright: (c) 2004 David Elliott +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#include "wx/region.h" + +#ifndef WX_PRECOMP + #include "wx/utils.h" +#endif + +// ======================================================================== +// Classes to interface with X.org code +// ======================================================================== + +typedef struct Box +{ + wxCoord x1, x2, y1, y2; +} Box, BOX, BoxRec, *BoxPtr; + +typedef struct REGION *Region; + +struct REGION +{ +public: + // Default constructor initializes nothing + REGION() {} + + REGION(const wxRect& rect) + { + rects = &extents; + numRects = 1; + extents.x1 = rect.x; + extents.y1 = rect.y; + extents.x2 = rect.x + rect.width; + extents.y2 = rect.y + rect.height; + size = 1; + } + + BoxPtr GetBox(int i) + { + return i < numRects ? rects + i : NULL; + } + + // X.org methods + static bool XClipBox( + Region r, + wxRect *rect); + static bool XOffsetRegion( + register Region pRegion, + register int x, + register int y); + static bool XIntersectRegion( + Region reg1, + Region reg2, /* source regions */ + register Region newReg); /* destination Region */ + static bool XUnionRegion( + Region reg1, + Region reg2, /* source regions */ + Region newReg); /* destination Region */ + static bool XSubtractRegion( + Region regM, + Region regS, + register Region regD); + static bool XXorRegion(Region sra, Region srb, Region dr); + static bool XEmptyRegion( + Region r); + static bool XEqualRegion(Region r1, Region r2); + static bool XPointInRegion( + Region pRegion, + int x, int y); + static wxRegionContain XRectInRegion( + register Region region, + int rx, int ry, + unsigned int rwidth, unsigned int rheight); + +protected: + static Region XCreateRegion(void); + static void miSetExtents ( + Region pReg); + static bool XDestroyRegion(Region r); + static int miIntersectO ( + register Region pReg, + register BoxPtr r1, + BoxPtr r1End, + register BoxPtr r2, + BoxPtr r2End, + wxCoord y1, + wxCoord y2); + static void miRegionCopy( + register Region dstrgn, + register Region rgn); + static int miCoalesce( + register Region pReg, /* Region to coalesce */ + int prevStart, /* Index of start of previous band */ + int curStart); /* Index of start of current band */ + static void miRegionOp( + register Region newReg, /* Place to store result */ + Region reg1, /* First region in operation */ + Region reg2, /* 2d region in operation */ + int (*overlapFunc)( + register Region pReg, + register BoxPtr r1, + BoxPtr r1End, + register BoxPtr r2, + BoxPtr r2End, + wxCoord y1, + wxCoord y2), /* Function to call for over- + * lapping bands */ + int (*nonOverlap1Func)( + register Region pReg, + register BoxPtr r, + BoxPtr rEnd, + register wxCoord y1, + register wxCoord y2), /* Function to call for non- + * overlapping bands in region + * 1 */ + int (*nonOverlap2Func)( + register Region pReg, + register BoxPtr r, + BoxPtr rEnd, + register wxCoord y1, + register wxCoord y2)); /* Function to call for non- + * overlapping bands in region + * 2 */ + static int miUnionNonO ( + register Region pReg, + register BoxPtr r, + BoxPtr rEnd, + register wxCoord y1, + register wxCoord y2); + static int miUnionO ( + register Region pReg, + register BoxPtr r1, + BoxPtr r1End, + register BoxPtr r2, + BoxPtr r2End, + register wxCoord y1, + register wxCoord y2); + static int miSubtractNonO1 ( + register Region pReg, + register BoxPtr r, + BoxPtr rEnd, + register wxCoord y1, + register wxCoord y2); + static int miSubtractO ( + register Region pReg, + register BoxPtr r1, + BoxPtr r1End, + register BoxPtr r2, + BoxPtr r2End, + register wxCoord y1, + register wxCoord y2); +protected: + long size; + long numRects; + Box *rects; + Box extents; +}; + +// ======================================================================== +// wxRegionRefData +// ======================================================================== + +class wxRegionRefData : public wxObjectRefData, + public REGION +{ +public: + wxRegionRefData() + : wxObjectRefData(), + REGION() + { + size = 1; + numRects = 0; + rects = ( BOX * )malloc( (unsigned) sizeof( BOX )); + extents.x1 = 0; + extents.x2 = 0; + extents.y1 = 0; + extents.y2 = 0; + } + + wxRegionRefData(const wxPoint& topLeft, const wxPoint& bottomRight) + : wxObjectRefData(), + REGION() + { + rects = (BOX*)malloc(sizeof(BOX)); + size = 1; + numRects = 1; + extents.x1 = topLeft.x; + extents.y1 = topLeft.y; + extents.x2 = bottomRight.x; + extents.y2 = bottomRight.y; + *rects = extents; + } + + wxRegionRefData(const wxRect& rect) + : wxObjectRefData(), + REGION(rect) + { + rects = (BOX*)malloc(sizeof(BOX)); + *rects = extents; + } + + wxRegionRefData(const wxRegionRefData& refData) + : wxObjectRefData(), + REGION() + { + size = refData.size; + numRects = refData.numRects; + rects = (Box*)malloc(numRects*sizeof(Box)); + memcpy(rects, refData.rects, numRects*sizeof(Box)); + extents = refData.extents; + } + + virtual ~wxRegionRefData() + { + free(rects); + } + +private: + // Don't allow this + wxRegionRefData(const REGION&); +}; + +// ======================================================================== +// wxRegionGeneric +// ======================================================================== +//IMPLEMENT_DYNAMIC_CLASS(wxRegionGeneric, wxGDIObject) + +#define M_REGIONDATA ((wxRegionRefData *)m_refData) +#define M_REGIONDATA_OF(rgn) ((wxRegionRefData *)(rgn.m_refData)) + +// ---------------------------------------------------------------------------- +// wxRegionGeneric construction +// ---------------------------------------------------------------------------- + +wxRegionGeneric::wxRegionGeneric() +{ +} + +wxRegionGeneric::~wxRegionGeneric() +{ +} + +wxRegionGeneric::wxRegionGeneric(wxCoord x, wxCoord y, wxCoord w, wxCoord h) +{ + m_refData = new wxRegionRefData(wxRect(x,y,w,h)); +} + +wxRegionGeneric::wxRegionGeneric(const wxRect& rect) +{ + m_refData = new wxRegionRefData(rect); +} + +wxRegionGeneric::wxRegionGeneric(const wxPoint& topLeft, const wxPoint& bottomRight) +{ + m_refData = new wxRegionRefData(topLeft, bottomRight); +} + +void wxRegionGeneric::Clear() +{ + UnRef(); +} + +wxObjectRefData *wxRegionGeneric::CreateRefData() const +{ + return new wxRegionRefData; +} + +wxObjectRefData *wxRegionGeneric::CloneRefData(const wxObjectRefData *data) const +{ + return new wxRegionRefData(*(wxRegionRefData *)data); +} + +bool wxRegionGeneric::DoIsEqual(const wxRegion& region) const +{ + return REGION::XEqualRegion(M_REGIONDATA,M_REGIONDATA_OF(region)); +} + +bool wxRegionGeneric::DoGetBox(wxCoord& x, wxCoord& y, wxCoord&w, wxCoord &h) const +{ + if ( !m_refData ) + return false; + + wxRect rect; + REGION::XClipBox(M_REGIONDATA,&rect); + x = rect.x; + y = rect.y; + w = rect.width; + h = rect.height; + return true; +} + +// ---------------------------------------------------------------------------- +// wxRegionGeneric operations +// ---------------------------------------------------------------------------- + +bool wxRegionGeneric::DoUnionWithRect(const wxRect& rect) +{ + if ( rect.IsEmpty() ) + { + // nothing to do + return true; + } + + AllocExclusive(); + REGION region(rect); + return REGION::XUnionRegion(®ion,M_REGIONDATA,M_REGIONDATA); +} + +bool wxRegionGeneric::DoUnionWithRegion(const wxRegion& region) +{ + AllocExclusive(); + return REGION::XUnionRegion(M_REGIONDATA_OF(region),M_REGIONDATA,M_REGIONDATA); +} + +bool wxRegionGeneric::DoIntersect(const wxRegion& region) +{ + AllocExclusive(); + return REGION::XIntersectRegion(M_REGIONDATA_OF(region),M_REGIONDATA,M_REGIONDATA); +} + +bool wxRegionGeneric::DoSubtract(const wxRegion& region) +{ + if ( region.IsEmpty() ) + { + // nothing to do + return true; + } + + return REGION::XSubtractRegion(M_REGIONDATA_OF(region),M_REGIONDATA,M_REGIONDATA); +} + +bool wxRegionGeneric::DoXor(const wxRegion& region) +{ + AllocExclusive(); + return REGION::XXorRegion(M_REGIONDATA_OF(region),M_REGIONDATA,M_REGIONDATA); +} + +bool wxRegionGeneric::DoOffset(wxCoord x, wxCoord y) +{ + AllocExclusive(); + return REGION::XOffsetRegion(M_REGIONDATA, x, y); +} + +// ---------------------------------------------------------------------------- +// wxRegionGeneric comparison +// ---------------------------------------------------------------------------- + +bool wxRegionGeneric::IsEmpty() const +{ + wxASSERT(m_refData); + return REGION::XEmptyRegion(M_REGIONDATA); +} + +// Does the region contain the point (x,y)? +wxRegionContain wxRegionGeneric::DoContainsPoint(wxCoord x, wxCoord y) const +{ + wxASSERT(m_refData); + return REGION::XPointInRegion(M_REGIONDATA,x,y) ? wxInRegion : wxOutRegion; +} + +// Does the region contain the rectangle rect? +wxRegionContain wxRegionGeneric::DoContainsRect(const wxRect& rect) const +{ + wxASSERT(m_refData); + return REGION::XRectInRegion(M_REGIONDATA,rect.x,rect.y,rect.width,rect.height); +} + +// ======================================================================== +// wxRegionIteratorGeneric +// ======================================================================== +//IMPLEMENT_DYNAMIC_CLASS(wxRegionIteratorGeneric,wxObject) + +wxRegionIteratorGeneric::wxRegionIteratorGeneric() +{ + m_current = 0; +} + +wxRegionIteratorGeneric::wxRegionIteratorGeneric(const wxRegionGeneric& region) +: m_region(region) +{ + m_current = 0; +} + +wxRegionIteratorGeneric::wxRegionIteratorGeneric(const wxRegionIteratorGeneric& iterator) +: m_region(iterator.m_region) +{ + m_current = iterator.m_current; +} + +void wxRegionIteratorGeneric::Reset(const wxRegionGeneric& region) +{ + m_region = region; + m_current = 0; +} + +bool wxRegionIteratorGeneric::HaveRects() const +{ + return M_REGIONDATA_OF(m_region)->GetBox(m_current); +} + +wxRegionIteratorGeneric& wxRegionIteratorGeneric::operator++() +{ + ++m_current; + return *this; +} + +wxRegionIteratorGeneric wxRegionIteratorGeneric::operator++(int) +{ + wxRegionIteratorGeneric copy(*this); + ++*this; + return copy; +} + +wxRect wxRegionIteratorGeneric::GetRect() const +{ + wxASSERT(m_region.m_refData); + const Box *box = M_REGIONDATA_OF(m_region)->GetBox(m_current); + wxASSERT(box); + return wxRect + ( box->x1 + , box->y1 + , box->x2 - box->x1 + , box->y2 - box->y1 + ); +} + +long wxRegionIteratorGeneric::GetX() const +{ + wxASSERT(m_region.m_refData); + const Box *box = M_REGIONDATA_OF(m_region)->GetBox(m_current); + wxASSERT(box); + return box->x1; +} + +long wxRegionIteratorGeneric::GetY() const +{ + wxASSERT(m_region.m_refData); + const Box *box = M_REGIONDATA_OF(m_region)->GetBox(m_current); + wxASSERT(box); + return box->y1; +} + +long wxRegionIteratorGeneric::GetW() const +{ + wxASSERT(m_region.m_refData); + const Box *box = M_REGIONDATA_OF(m_region)->GetBox(m_current); + wxASSERT(box); + return box->x2 - box->x1; +} + +long wxRegionIteratorGeneric::GetH() const +{ + wxASSERT(m_region.m_refData); + const Box *box = M_REGIONDATA_OF(m_region)->GetBox(m_current); + wxASSERT(box); + return box->y2 - box->y1; +} + +wxRegionIteratorGeneric::~wxRegionIteratorGeneric() +{ +} + + +// ======================================================================== +// The guts (from X.org) +// ======================================================================== + +/************************************************************************ + +Copyright 1987, 1988, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +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 +OPEN GROUP 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. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + + +Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of Digital not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +************************************************************************/ + +/* 1 if two BOXs overlap. + * 0 if two BOXs do not overlap. + * Remember, x2 and y2 are not in the region + */ +#define EXTENTCHECK(r1, r2) \ + ((r1)->x2 > (r2)->x1 && \ + (r1)->x1 < (r2)->x2 && \ + (r1)->y2 > (r2)->y1 && \ + (r1)->y1 < (r2)->y2) + +/* + * Check to see if there is enough memory in the present region. + */ +#define MEMCHECK(reg, rect, firstrect){\ + if ((reg)->numRects >= ((reg)->size - 1)){\ + (firstrect) = (BOX *) realloc \ + ((char *)(firstrect), (unsigned) (2 * (sizeof(BOX)) * ((reg)->size)));\ + if ((firstrect) == 0)\ + return(0);\ + (reg)->size *= 2;\ + (rect) = &(firstrect)[(reg)->numRects];\ + }\ + } + +#define EMPTY_REGION(pReg) pReg->numRects = 0 + +#define REGION_NOT_EMPTY(pReg) pReg->numRects + +#define INBOX(r, x, y) \ + ( ( ((r).x2 > x)) && \ + ( ((r).x1 <= x)) && \ + ( ((r).y2 > y)) && \ + ( ((r).y1 <= y)) ) + +/* + * The functions in this file implement the Region abstraction, similar to one + * used in the X11 sample server. A Region is simply an area, as the name + * implies, and is implemented as a "y-x-banded" array of rectangles. To + * explain: Each Region is made up of a certain number of rectangles sorted + * by y coordinate first, and then by x coordinate. + * + * Furthermore, the rectangles are banded such that every rectangle with a + * given upper-left y coordinate (y1) will have the same lower-right y + * coordinate (y2) and vice versa. If a rectangle has scanlines in a band, it + * will span the entire vertical distance of the band. This means that some + * areas that could be merged into a taller rectangle will be represented as + * several shorter rectangles to account for shorter rectangles to its left + * or right but within its "vertical scope". + * + * An added constraint on the rectangles is that they must cover as much + * horizontal area as possible. E.g. no two rectangles in a band are allowed + * to touch. + * + * Whenever possible, bands will be merged together to cover a greater vertical + * distance (and thus reduce the number of rectangles). Two bands can be merged + * only if the bottom of one touches the top of the other and they have + * rectangles in the same places (of the same width, of course). This maintains + * the y-x-banding that's so nice to have... + */ + +/* Create a new empty region */ +Region REGION::XCreateRegion(void) +{ + Region temp = new REGION; + + if (!temp) + return (Region) NULL; + + temp->rects = ( BOX * )malloc( (unsigned) sizeof( BOX )); + + if (!temp->rects) + { + free((char *) temp); + return (Region) NULL; + } + temp->numRects = 0; + temp->extents.x1 = 0; + temp->extents.y1 = 0; + temp->extents.x2 = 0; + temp->extents.y2 = 0; + temp->size = 1; + return( temp ); +} + +bool REGION::XClipBox(Region r, wxRect *rect) +{ + rect->x = r->extents.x1; + rect->y = r->extents.y1; + rect->width = r->extents.x2 - r->extents.x1; + rect->height = r->extents.y2 - r->extents.y1; + return true; +} + +/*- + *----------------------------------------------------------------------- + * miSetExtents -- + * Reset the extents of a region to what they should be. Called by + * miSubtract and miIntersect b/c they can't figure it out along the + * way or do so easily, as miUnion can. + * + * Results: + * None. + * + * Side Effects: + * The region's 'extents' structure is overwritten. + * + *----------------------------------------------------------------------- + */ +void REGION:: +miSetExtents (Region pReg) +{ + register BoxPtr pBox, + pBoxEnd, + pExtents; + + if (pReg->numRects == 0) + { + pReg->extents.x1 = 0; + pReg->extents.y1 = 0; + pReg->extents.x2 = 0; + pReg->extents.y2 = 0; + return; + } + + pExtents = &pReg->extents; + pBox = pReg->rects; + pBoxEnd = &pBox[pReg->numRects - 1]; + + /* + * Since pBox is the first rectangle in the region, it must have the + * smallest y1 and since pBoxEnd is the last rectangle in the region, + * it must have the largest y2, because of banding. Initialize x1 and + * x2 from pBox and pBoxEnd, resp., as good things to initialize them + * to... + */ + pExtents->x1 = pBox->x1; + pExtents->y1 = pBox->y1; + pExtents->x2 = pBoxEnd->x2; + pExtents->y2 = pBoxEnd->y2; + + assert(pExtents->y1 < pExtents->y2); + while (pBox <= pBoxEnd) + { + if (pBox->x1 < pExtents->x1) + { + pExtents->x1 = pBox->x1; + } + if (pBox->x2 > pExtents->x2) + { + pExtents->x2 = pBox->x2; + } + pBox++; + } + assert(pExtents->x1 < pExtents->x2); +} + +bool REGION:: +XDestroyRegion( + Region r) +{ + free( (char *) r->rects ); + delete r; + return true; +} + +/* TranslateRegion(pRegion, x, y) + translates in place + added by raymond +*/ + +bool REGION:: +XOffsetRegion( + register Region pRegion, + register int x, + register int y) +{ + register int nbox; + register BOX *pbox; + + pbox = pRegion->rects; + nbox = pRegion->numRects; + + while(nbox--) + { + pbox->x1 += x; + pbox->x2 += x; + pbox->y1 += y; + pbox->y2 += y; + pbox++; + } + pRegion->extents.x1 += x; + pRegion->extents.x2 += x; + pRegion->extents.y1 += y; + pRegion->extents.y2 += y; + return 1; +} + +/*====================================================================== + * Region Intersection + *====================================================================*/ +/*- + *----------------------------------------------------------------------- + * miIntersectO -- + * Handle an overlapping band for miIntersect. + * + * Results: + * None. + * + * Side Effects: + * Rectangles may be added to the region. + * + *----------------------------------------------------------------------- + */ +/* static void*/ +int REGION:: +miIntersectO ( + register Region pReg, + register BoxPtr r1, + BoxPtr r1End, + register BoxPtr r2, + BoxPtr r2End, + wxCoord y1, + wxCoord y2) +{ + register wxCoord x1; + register wxCoord x2; + register BoxPtr pNextRect; + + pNextRect = &pReg->rects[pReg->numRects]; + + while ((r1 != r1End) && (r2 != r2End)) + { + x1 = wxMax(r1->x1,r2->x1); + x2 = wxMin(r1->x2,r2->x2); + + /* + * If there's any overlap between the two rectangles, add that + * overlap to the new region. + * There's no need to check for subsumption because the only way + * such a need could arise is if some region has two rectangles + * right next to each other. Since that should never happen... + */ + if (x1 < x2) + { + assert(y1rects); + pNextRect->x1 = x1; + pNextRect->y1 = y1; + pNextRect->x2 = x2; + pNextRect->y2 = y2; + pReg->numRects += 1; + pNextRect++; + assert(pReg->numRects <= pReg->size); + } + + /* + * Need to advance the pointers. Shift the one that extends + * to the right the least, since the other still has a chance to + * overlap with that region's next rectangle, if you see what I mean. + */ + if (r1->x2 < r2->x2) + { + r1++; + } + else if (r2->x2 < r1->x2) + { + r2++; + } + else + { + r1++; + r2++; + } + } + return 0; /* lint */ +} + +bool REGION:: +XIntersectRegion( + Region reg1, + Region reg2, /* source regions */ + register Region newReg) /* destination Region */ +{ + /* check for trivial reject */ + if ( (!(reg1->numRects)) || (!(reg2->numRects)) || + (!EXTENTCHECK(®1->extents, ®2->extents))) + newReg->numRects = 0; + else + miRegionOp (newReg, reg1, reg2, + miIntersectO, NULL, NULL); + + /* + * Can't alter newReg's extents before we call miRegionOp because + * it might be one of the source regions and miRegionOp depends + * on the extents of those regions being the same. Besides, this + * way there's no checking against rectangles that will be nuked + * due to coalescing, so we have to examine fewer rectangles. + */ + miSetExtents(newReg); + return 1; +} + +void REGION:: +miRegionCopy( + register Region dstrgn, + register Region rgn) + +{ + if (dstrgn != rgn) /* don't want to copy to itself */ + { + if (dstrgn->size < rgn->numRects) + { + if (dstrgn->rects) + { + BOX *prevRects = dstrgn->rects; + + dstrgn->rects = (BOX *) + realloc((char *) dstrgn->rects, + (unsigned) rgn->numRects * (sizeof(BOX))); + if (!dstrgn->rects) + { + free(prevRects); + return; + } + } + dstrgn->size = rgn->numRects; + } + dstrgn->numRects = rgn->numRects; + dstrgn->extents.x1 = rgn->extents.x1; + dstrgn->extents.y1 = rgn->extents.y1; + dstrgn->extents.x2 = rgn->extents.x2; + dstrgn->extents.y2 = rgn->extents.y2; + + memcpy((char *) dstrgn->rects, (char *) rgn->rects, + (int) (rgn->numRects * sizeof(BOX))); + } +} + +/*====================================================================== + * Generic Region Operator + *====================================================================*/ + +/*- + *----------------------------------------------------------------------- + * miCoalesce -- + * Attempt to merge the boxes in the current band with those in the + * previous one. Used only by miRegionOp. + * + * Results: + * The new index for the previous band. + * + * Side Effects: + * If coalescing takes place: + * - rectangles in the previous band will have their y2 fields + * altered. + * - pReg->numRects will be decreased. + * + *----------------------------------------------------------------------- + */ +/* static int*/ +int REGION:: +miCoalesce( + register Region pReg, /* Region to coalesce */ + int prevStart, /* Index of start of previous band */ + int curStart) /* Index of start of current band */ +{ + register BoxPtr pPrevBox; /* Current box in previous band */ + register BoxPtr pCurBox; /* Current box in current band */ + register BoxPtr pRegEnd; /* End of region */ + int curNumRects; /* Number of rectangles in current + * band */ + int prevNumRects; /* Number of rectangles in previous + * band */ + int bandY1; /* Y1 coordinate for current band */ + + pRegEnd = &pReg->rects[pReg->numRects]; + + pPrevBox = &pReg->rects[prevStart]; + prevNumRects = curStart - prevStart; + + /* + * Figure out how many rectangles are in the current band. Have to do + * this because multiple bands could have been added in miRegionOp + * at the end when one region has been exhausted. + */ + pCurBox = &pReg->rects[curStart]; + bandY1 = pCurBox->y1; + for (curNumRects = 0; + (pCurBox != pRegEnd) && (pCurBox->y1 == bandY1); + curNumRects++) + { + pCurBox++; + } + + if (pCurBox != pRegEnd) + { + /* + * If more than one band was added, we have to find the start + * of the last band added so the next coalescing job can start + * at the right place... (given when multiple bands are added, + * this may be pointless -- see above). + */ + pRegEnd--; + while (pRegEnd[-1].y1 == pRegEnd->y1) + { + pRegEnd--; + } + curStart = pRegEnd - pReg->rects; + pRegEnd = pReg->rects + pReg->numRects; + } + + if ((curNumRects == prevNumRects) && (curNumRects != 0)) + { + pCurBox -= curNumRects; + /* + * The bands may only be coalesced if the bottom of the previous + * matches the top scanline of the current. + */ + if (pPrevBox->y2 == pCurBox->y1) + { + /* + * Make sure the bands have boxes in the same places. This + * assumes that boxes have been added in such a way that they + * cover the most area possible. I.e. two boxes in a band must + * have some horizontal space between them. + */ + do + { + if ((pPrevBox->x1 != pCurBox->x1) || + (pPrevBox->x2 != pCurBox->x2)) + { + /* + * The bands don't line up so they can't be coalesced. + */ + return (curStart); + } + pPrevBox++; + pCurBox++; + prevNumRects -= 1; + } while (prevNumRects != 0); + + pReg->numRects -= curNumRects; + pCurBox -= curNumRects; + pPrevBox -= curNumRects; + + /* + * The bands may be merged, so set the bottom y of each box + * in the previous band to that of the corresponding box in + * the current band. + */ + do + { + pPrevBox->y2 = pCurBox->y2; + pPrevBox++; + pCurBox++; + curNumRects -= 1; + } while (curNumRects != 0); + + /* + * If only one band was added to the region, we have to backup + * curStart to the start of the previous band. + * + * If more than one band was added to the region, copy the + * other bands down. The assumption here is that the other bands + * came from the same region as the current one and no further + * coalescing can be done on them since it's all been done + * already... curStart is already in the right place. + */ + if (pCurBox == pRegEnd) + { + curStart = prevStart; + } + else + { + do + { + *pPrevBox++ = *pCurBox++; + } while (pCurBox != pRegEnd); + } + + } + } + return (curStart); +} + +/*- + *----------------------------------------------------------------------- + * miRegionOp -- + * Apply an operation to two regions. Called by miUnion, miInverse, + * miSubtract, miIntersect... + * + * Results: + * None. + * + * Side Effects: + * The new region is overwritten. + * + * Notes: + * The idea behind this function is to view the two regions as sets. + * Together they cover a rectangle of area that this function divides + * into horizontal bands where points are covered only by one region + * or by both. For the first case, the nonOverlapFunc is called with + * each the band and the band's upper and lower extents. For the + * second, the overlapFunc is called to process the entire band. It + * is responsible for clipping the rectangles in the band, though + * this function provides the boundaries. + * At the end of each band, the new region is coalesced, if possible, + * to reduce the number of rectangles in the region. + * + *----------------------------------------------------------------------- + */ +/* static void*/ +void REGION:: +miRegionOp( + register Region newReg, /* Place to store result */ + Region reg1, /* First region in operation */ + Region reg2, /* 2d region in operation */ + int (*overlapFunc)( + register Region pReg, + register BoxPtr r1, + BoxPtr r1End, + register BoxPtr r2, + BoxPtr r2End, + wxCoord y1, + wxCoord y2), /* Function to call for over- + * lapping bands */ + int (*nonOverlap1Func)( + register Region pReg, + register BoxPtr r, + BoxPtr rEnd, + register wxCoord y1, + register wxCoord y2), /* Function to call for non- + * overlapping bands in region + * 1 */ + int (*nonOverlap2Func)( + register Region pReg, + register BoxPtr r, + BoxPtr rEnd, + register wxCoord y1, + register wxCoord y2)) /* Function to call for non- + * overlapping bands in region + * 2 */ +{ + register BoxPtr r1; /* Pointer into first region */ + register BoxPtr r2; /* Pointer into 2d region */ + BoxPtr r1End; /* End of 1st region */ + BoxPtr r2End; /* End of 2d region */ + register wxCoord ybot; /* Bottom of intersection */ + register wxCoord ytop; /* Top of intersection */ + BoxPtr oldRects; /* Old rects for newReg */ + int prevBand; /* Index of start of + * previous band in newReg */ + int curBand; /* Index of start of current + * band in newReg */ + register BoxPtr r1BandEnd; /* End of current band in r1 */ + register BoxPtr r2BandEnd; /* End of current band in r2 */ + wxCoord top; /* Top of non-overlapping + * band */ + wxCoord bot; /* Bottom of non-overlapping + * band */ + + /* + * Initialization: + * set r1, r2, r1End and r2End appropriately, preserve the important + * parts of the destination region until the end in case it's one of + * the two source regions, then mark the "new" region empty, allocating + * another array of rectangles for it to use. + */ + r1 = reg1->rects; + r2 = reg2->rects; + r1End = r1 + reg1->numRects; + r2End = r2 + reg2->numRects; + + oldRects = newReg->rects; + + EMPTY_REGION(newReg); + + /* + * Allocate a reasonable number of rectangles for the new region. The idea + * is to allocate enough so the individual functions don't need to + * reallocate and copy the array, which is time consuming, yet we don't + * have to worry about using too much memory. I hope to be able to + * nuke the realloc() at the end of this function eventually. + */ + newReg->size = wxMax(reg1->numRects,reg2->numRects) * 2; + + newReg->rects = (BoxPtr)malloc((unsigned) (sizeof(BoxRec) * newReg->size)); + + if (!newReg->rects) + { + newReg->size = 0; + return; + } + + /* + * Initialize ybot and ytop. + * In the upcoming loop, ybot and ytop serve different functions depending + * on whether the band being handled is an overlapping or non-overlapping + * band. + * In the case of a non-overlapping band (only one of the regions + * has points in the band), ybot is the bottom of the most recent + * intersection and thus clips the top of the rectangles in that band. + * ytop is the top of the next intersection between the two regions and + * serves to clip the bottom of the rectangles in the current band. + * For an overlapping band (where the two regions intersect), ytop clips + * the top of the rectangles of both regions and ybot clips the bottoms. + */ + if (reg1->extents.y1 < reg2->extents.y1) + ybot = reg1->extents.y1; + else + ybot = reg2->extents.y1; + + /* + * prevBand serves to mark the start of the previous band so rectangles + * can be coalesced into larger rectangles. qv. miCoalesce, above. + * In the beginning, there is no previous band, so prevBand == curBand + * (curBand is set later on, of course, but the first band will always + * start at index 0). prevBand and curBand must be indices because of + * the possible expansion, and resultant moving, of the new region's + * array of rectangles. + */ + prevBand = 0; + + do + { + curBand = newReg->numRects; + + /* + * This algorithm proceeds one source-band (as opposed to a + * destination band, which is determined by where the two regions + * intersect) at a time. r1BandEnd and r2BandEnd serve to mark the + * rectangle after the last one in the current band for their + * respective regions. + */ + r1BandEnd = r1; + while ((r1BandEnd != r1End) && (r1BandEnd->y1 == r1->y1)) + { + r1BandEnd++; + } + + r2BandEnd = r2; + while ((r2BandEnd != r2End) && (r2BandEnd->y1 == r2->y1)) + { + r2BandEnd++; + } + + /* + * First handle the band that doesn't intersect, if any. + * + * Note that attention is restricted to one band in the + * non-intersecting region at once, so if a region has n + * bands between the current position and the next place it overlaps + * the other, this entire loop will be passed through n times. + */ + if (r1->y1 < r2->y1) + { + top = wxMax(r1->y1,ybot); + bot = wxMin(r1->y2,r2->y1); + + if ((top != bot) && (nonOverlap1Func != NULL)) + { + (* nonOverlap1Func) (newReg, r1, r1BandEnd, top, bot); + } + + ytop = r2->y1; + } + else if (r2->y1 < r1->y1) + { + top = wxMax(r2->y1,ybot); + bot = wxMin(r2->y2,r1->y1); + + if ((top != bot) && (nonOverlap2Func != NULL)) + { + (* nonOverlap2Func) (newReg, r2, r2BandEnd, top, bot); + } + + ytop = r1->y1; + } + else + { + ytop = r1->y1; + } + + /* + * If any rectangles got added to the region, try and coalesce them + * with rectangles from the previous band. Note we could just do + * this test in miCoalesce, but some machines incur a not + * inconsiderable cost for function calls, so... + */ + if (newReg->numRects != curBand) + { + prevBand = miCoalesce (newReg, prevBand, curBand); + } + + /* + * Now see if we've hit an intersecting band. The two bands only + * intersect if ybot > ytop + */ + ybot = wxMin(r1->y2, r2->y2); + curBand = newReg->numRects; + if (ybot > ytop) + { + (* overlapFunc) (newReg, r1, r1BandEnd, r2, r2BandEnd, ytop, ybot); + + } + + if (newReg->numRects != curBand) + { + prevBand = miCoalesce (newReg, prevBand, curBand); + } + + /* + * If we've finished with a band (y2 == ybot) we skip forward + * in the region to the next band. + */ + if (r1->y2 == ybot) + { + r1 = r1BandEnd; + } + if (r2->y2 == ybot) + { + r2 = r2BandEnd; + } + } while ((r1 != r1End) && (r2 != r2End)); + + /* + * Deal with whichever region still has rectangles left. + */ + curBand = newReg->numRects; + if (r1 != r1End) + { + if (nonOverlap1Func != NULL) + { + do + { + r1BandEnd = r1; + while ((r1BandEnd < r1End) && (r1BandEnd->y1 == r1->y1)) + { + r1BandEnd++; + } + (* nonOverlap1Func) (newReg, r1, r1BandEnd, + wxMax(r1->y1,ybot), r1->y2); + r1 = r1BandEnd; + } while (r1 != r1End); + } + } + else if ((r2 != r2End) && (nonOverlap2Func != NULL)) + { + do + { + r2BandEnd = r2; + while ((r2BandEnd < r2End) && (r2BandEnd->y1 == r2->y1)) + { + r2BandEnd++; + } + (* nonOverlap2Func) (newReg, r2, r2BandEnd, + wxMax(r2->y1,ybot), r2->y2); + r2 = r2BandEnd; + } while (r2 != r2End); + } + + if (newReg->numRects != curBand) + { + (void) miCoalesce (newReg, prevBand, curBand); + } + + /* + * A bit of cleanup. To keep regions from growing without bound, + * we shrink the array of rectangles to match the new number of + * rectangles in the region. This never goes to 0, however... + * + * Only do this stuff if the number of rectangles allocated is more than + * twice the number of rectangles in the region (a simple optimization...). + */ + if (newReg->numRects < (newReg->size >> 1)) + { + if (REGION_NOT_EMPTY(newReg)) + { + BoxPtr prev_rects = newReg->rects; + newReg->size = newReg->numRects; + newReg->rects = (BoxPtr) realloc ((char *) newReg->rects, + (unsigned) (sizeof(BoxRec) * newReg->size)); + if (! newReg->rects) + newReg->rects = prev_rects; + } + else + { + /* + * No point in doing the extra work involved in an realloc if + * the region is empty + */ + newReg->size = 1; + free((char *) newReg->rects); + newReg->rects = (BoxPtr) malloc(sizeof(BoxRec)); + } + } + free ((char *) oldRects); + return; +} + +/*====================================================================== + * Region Union + *====================================================================*/ + +/*- + *----------------------------------------------------------------------- + * miUnionNonO -- + * Handle a non-overlapping band for the union operation. Just + * Adds the rectangles into the region. Doesn't have to check for + * subsumption or anything. + * + * Results: + * None. + * + * Side Effects: + * pReg->numRects is incremented and the final rectangles overwritten + * with the rectangles we're passed. + * + *----------------------------------------------------------------------- + */ +/* static void*/ +int REGION:: +miUnionNonO ( + register Region pReg, + register BoxPtr r, + BoxPtr rEnd, + register wxCoord y1, + register wxCoord y2) +{ + register BoxPtr pNextRect; + + pNextRect = &pReg->rects[pReg->numRects]; + + assert(y1 < y2); + + while (r != rEnd) + { + assert(r->x1 < r->x2); + MEMCHECK(pReg, pNextRect, pReg->rects); + pNextRect->x1 = r->x1; + pNextRect->y1 = y1; + pNextRect->x2 = r->x2; + pNextRect->y2 = y2; + pReg->numRects += 1; + pNextRect++; + + assert(pReg->numRects<=pReg->size); + r++; + } + return 0; /* lint */ +} + + +/*- + *----------------------------------------------------------------------- + * miUnionO -- + * Handle an overlapping band for the union operation. Picks the + * left-most rectangle each time and merges it into the region. + * + * Results: + * None. + * + * Side Effects: + * Rectangles are overwritten in pReg->rects and pReg->numRects will + * be changed. + * + *----------------------------------------------------------------------- + */ + +/* static void*/ +int REGION:: +miUnionO ( + register Region pReg, + register BoxPtr r1, + BoxPtr r1End, + register BoxPtr r2, + BoxPtr r2End, + register wxCoord y1, + register wxCoord y2) +{ + register BoxPtr pNextRect; + + pNextRect = &pReg->rects[pReg->numRects]; + +#define MERGERECT(r) \ + if ((pReg->numRects != 0) && \ + (pNextRect[-1].y1 == y1) && \ + (pNextRect[-1].y2 == y2) && \ + (pNextRect[-1].x2 >= r->x1)) \ + { \ + if (pNextRect[-1].x2 < r->x2) \ + { \ + pNextRect[-1].x2 = r->x2; \ + assert(pNextRect[-1].x1rects); \ + pNextRect->y1 = y1; \ + pNextRect->y2 = y2; \ + pNextRect->x1 = r->x1; \ + pNextRect->x2 = r->x2; \ + pReg->numRects += 1; \ + pNextRect += 1; \ + } \ + assert(pReg->numRects<=pReg->size);\ + r++; + + assert (y1x1 < r2->x1) + { + MERGERECT(r1); + } + else + { + MERGERECT(r2); + } + } + + if (r1 != r1End) + { + do + { + MERGERECT(r1); + } while (r1 != r1End); + } + else while (r2 != r2End) + { + MERGERECT(r2); + } + return 0; /* lint */ +} + +bool REGION:: +XUnionRegion( + Region reg1, + Region reg2, /* source regions */ + Region newReg) /* destination Region */ +{ + /* checks all the simple cases */ + + /* + * Region 1 and 2 are the same or region 1 is empty + */ + if ( (reg1 == reg2) || (!(reg1->numRects)) ) + { + if (newReg != reg2) + miRegionCopy(newReg, reg2); + return 1; + } + + /* + * if nothing to union (region 2 empty) + */ + if (!(reg2->numRects)) + { + if (newReg != reg1) + miRegionCopy(newReg, reg1); + return 1; + } + + /* + * Region 1 completely subsumes region 2 + */ + if ((reg1->numRects == 1) && + (reg1->extents.x1 <= reg2->extents.x1) && + (reg1->extents.y1 <= reg2->extents.y1) && + (reg1->extents.x2 >= reg2->extents.x2) && + (reg1->extents.y2 >= reg2->extents.y2)) + { + if (newReg != reg1) + miRegionCopy(newReg, reg1); + return 1; + } + + /* + * Region 2 completely subsumes region 1 + */ + if ((reg2->numRects == 1) && + (reg2->extents.x1 <= reg1->extents.x1) && + (reg2->extents.y1 <= reg1->extents.y1) && + (reg2->extents.x2 >= reg1->extents.x2) && + (reg2->extents.y2 >= reg1->extents.y2)) + { + if (newReg != reg2) + miRegionCopy(newReg, reg2); + return 1; + } + + miRegionOp (newReg, reg1, reg2, miUnionO, + miUnionNonO, miUnionNonO); + + newReg->extents.x1 = wxMin(reg1->extents.x1, reg2->extents.x1); + newReg->extents.y1 = wxMin(reg1->extents.y1, reg2->extents.y1); + newReg->extents.x2 = wxMax(reg1->extents.x2, reg2->extents.x2); + newReg->extents.y2 = wxMax(reg1->extents.y2, reg2->extents.y2); + + return 1; +} + +/*====================================================================== + * Region Subtraction + *====================================================================*/ + +/*- + *----------------------------------------------------------------------- + * miSubtractNonO -- + * Deal with non-overlapping band for subtraction. Any parts from + * region 2 we discard. Anything from region 1 we add to the region. + * + * Results: + * None. + * + * Side Effects: + * pReg may be affected. + * + *----------------------------------------------------------------------- + */ +/* static void*/ +int REGION:: +miSubtractNonO1 ( + register Region pReg, + register BoxPtr r, + BoxPtr rEnd, + register wxCoord y1, + register wxCoord y2) +{ + register BoxPtr pNextRect; + + pNextRect = &pReg->rects[pReg->numRects]; + + assert(y1x1x2); + MEMCHECK(pReg, pNextRect, pReg->rects); + pNextRect->x1 = r->x1; + pNextRect->y1 = y1; + pNextRect->x2 = r->x2; + pNextRect->y2 = y2; + pReg->numRects += 1; + pNextRect++; + + assert(pReg->numRects <= pReg->size); + + r++; + } + return 0; /* lint */ +} + +/*- + *----------------------------------------------------------------------- + * miSubtractO -- + * Overlapping band subtraction. x1 is the left-most point not yet + * checked. + * + * Results: + * None. + * + * Side Effects: + * pReg may have rectangles added to it. + * + *----------------------------------------------------------------------- + */ +/* static void*/ +int REGION:: +miSubtractO ( + register Region pReg, + register BoxPtr r1, + BoxPtr r1End, + register BoxPtr r2, + BoxPtr r2End, + register wxCoord y1, + register wxCoord y2) +{ + register BoxPtr pNextRect; + register int x1; + + x1 = r1->x1; + + assert(y1rects[pReg->numRects]; + + while ((r1 != r1End) && (r2 != r2End)) + { + if (r2->x2 <= x1) + { + /* + * Subtrahend missed the boat: go to next subtrahend. + */ + r2++; + } + else if (r2->x1 <= x1) + { + /* + * Subtrahend preceeds minuend: nuke left edge of minuend. + */ + x1 = r2->x2; + if (x1 >= r1->x2) + { + /* + * Minuend completely covered: advance to next minuend and + * reset left fence to edge of new minuend. + */ + r1++; + if (r1 != r1End) + x1 = r1->x1; + } + else + { + /* + * Subtrahend now used up since it doesn't extend beyond + * minuend + */ + r2++; + } + } + else if (r2->x1 < r1->x2) + { + /* + * Left part of subtrahend covers part of minuend: add uncovered + * part of minuend to region and skip to next subtrahend. + */ + assert(x1x1); + MEMCHECK(pReg, pNextRect, pReg->rects); + pNextRect->x1 = x1; + pNextRect->y1 = y1; + pNextRect->x2 = r2->x1; + pNextRect->y2 = y2; + pReg->numRects += 1; + pNextRect++; + + assert(pReg->numRects<=pReg->size); + + x1 = r2->x2; + if (x1 >= r1->x2) + { + /* + * Minuend used up: advance to new... + */ + r1++; + if (r1 != r1End) + x1 = r1->x1; + } + else + { + /* + * Subtrahend used up + */ + r2++; + } + } + else + { + /* + * Minuend used up: add any remaining piece before advancing. + */ + if (r1->x2 > x1) + { + MEMCHECK(pReg, pNextRect, pReg->rects); + pNextRect->x1 = x1; + pNextRect->y1 = y1; + pNextRect->x2 = r1->x2; + pNextRect->y2 = y2; + pReg->numRects += 1; + pNextRect++; + assert(pReg->numRects<=pReg->size); + } + r1++; + if (r1 != r1End) + x1 = r1->x1; + } + } + + /* + * Add remaining minuend rectangles to region. + */ + while (r1 != r1End) + { + assert(x1x2); + MEMCHECK(pReg, pNextRect, pReg->rects); + pNextRect->x1 = x1; + pNextRect->y1 = y1; + pNextRect->x2 = r1->x2; + pNextRect->y2 = y2; + pReg->numRects += 1; + pNextRect++; + + assert(pReg->numRects<=pReg->size); + + r1++; + if (r1 != r1End) + { + x1 = r1->x1; + } + } + return 0; /* lint */ +} + +/*- + *----------------------------------------------------------------------- + * miSubtract -- + * Subtract regS from regM and leave the result in regD. + * S stands for subtrahend, M for minuend and D for difference. + * + * Results: + * true. + * + * Side Effects: + * regD is overwritten. + * + *----------------------------------------------------------------------- + */ + +bool REGION::XSubtractRegion(Region regM, Region regS, register Region regD) +{ + /* check for trivial reject */ + if ( (!(regM->numRects)) || (!(regS->numRects)) || + (!EXTENTCHECK(®M->extents, ®S->extents)) ) + { + miRegionCopy(regD, regM); + return true; + } + + miRegionOp (regD, regM, regS, miSubtractO, + miSubtractNonO1, NULL); + + /* + * Can't alter newReg's extents before we call miRegionOp because + * it might be one of the source regions and miRegionOp depends + * on the extents of those regions being the unaltered. Besides, this + * way there's no checking against rectangles that will be nuked + * due to coalescing, so we have to examine fewer rectangles. + */ + miSetExtents (regD); + return true; +} + +bool REGION::XXorRegion(Region sra, Region srb, Region dr) +{ + Region tra = XCreateRegion(); + + wxCHECK_MSG( tra, false, wxT("region not created") ); + + Region trb = XCreateRegion(); + + wxCHECK_MSG( trb, false, wxT("region not created") ); + + (void) XSubtractRegion(sra,srb,tra); + (void) XSubtractRegion(srb,sra,trb); + (void) XUnionRegion(tra,trb,dr); + XDestroyRegion(tra); + XDestroyRegion(trb); + return 0; +} + +/* + * Check to see if the region is empty. Assumes a region is passed + * as a parameter + */ +bool REGION::XEmptyRegion(Region r) +{ + if( r->numRects == 0 ) return true; + else return false; +} + +/* + * Check to see if two regions are equal + */ +bool REGION::XEqualRegion(Region r1, Region r2) +{ + int i; + + if( r1->numRects != r2->numRects ) return false; + else if( r1->numRects == 0 ) return true; + else if ( r1->extents.x1 != r2->extents.x1 ) return false; + else if ( r1->extents.x2 != r2->extents.x2 ) return false; + else if ( r1->extents.y1 != r2->extents.y1 ) return false; + else if ( r1->extents.y2 != r2->extents.y2 ) return false; + else for( i=0; i < r1->numRects; i++ ) { + if ( r1->rects[i].x1 != r2->rects[i].x1 ) return false; + else if ( r1->rects[i].x2 != r2->rects[i].x2 ) return false; + else if ( r1->rects[i].y1 != r2->rects[i].y1 ) return false; + else if ( r1->rects[i].y2 != r2->rects[i].y2 ) return false; + } + return true; +} + +bool REGION::XPointInRegion(Region pRegion, int x, int y) +{ + int i; + + if (pRegion->numRects == 0) + return false; + if (!INBOX(pRegion->extents, x, y)) + return false; + for (i=0; inumRects; i++) + { + if (INBOX (pRegion->rects[i], x, y)) + return true; + } + return false; +} + +wxRegionContain REGION::XRectInRegion(register Region region, + int rx, int ry, + unsigned int rwidth, + unsigned int rheight) +{ + register BoxPtr pbox; + register BoxPtr pboxEnd; + Box rect; + register BoxPtr prect = ▭ + int partIn, partOut; + + prect->x1 = rx; + prect->y1 = ry; + prect->x2 = rwidth + rx; + prect->y2 = rheight + ry; + + /* this is (just) a useful optimization */ + if ((region->numRects == 0) || !EXTENTCHECK(®ion->extents, prect)) + return(wxOutRegion); + + partOut = false; + partIn = false; + + /* can stop when both partOut and partIn are true, or we reach prect->y2 */ + for (pbox = region->rects, pboxEnd = pbox + region->numRects; + pbox < pboxEnd; + pbox++) + { + + if (pbox->y2 <= ry) + continue; /* getting up to speed or skipping remainder of band */ + + if (pbox->y1 > ry) + { + partOut = true; /* missed part of rectangle above */ + if (partIn || (pbox->y1 >= prect->y2)) + break; + ry = pbox->y1; /* x guaranteed to be == prect->x1 */ + } + + if (pbox->x2 <= rx) + continue; /* not far enough over yet */ + + if (pbox->x1 > rx) + { + partOut = true; /* missed part of rectangle to left */ + if (partIn) + break; + } + + if (pbox->x1 < prect->x2) + { + partIn = true; /* definitely overlap */ + if (partOut) + break; + } + + if (pbox->x2 >= prect->x2) + { + ry = pbox->y2; /* finished with this band */ + if (ry >= prect->y2) + break; + rx = prect->x1; /* reset x out to left again */ + } else + { + /* + * Because boxes in a band are maximal width, if the first box + * to overlap the rectangle doesn't completely cover it in that + * band, the rectangle must be partially out, since some of it + * will be uncovered in that band. partIn will have been set true + * by now... + */ + break; + } + + } + + return(partIn ? ((ry < prect->y2) ? wxPartRegion : wxInRegion) : + wxOutRegion); +} diff --git a/Externals/wxWidgets/src/generic/renderg.cpp b/Externals/wxWidgets/src/generic/renderg.cpp index 8c36e31d19..710facd0c3 100644 --- a/Externals/wxWidgets/src/generic/renderg.cpp +++ b/Externals/wxWidgets/src/generic/renderg.cpp @@ -1,678 +1,678 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: src/generic/renderg.cpp -// Purpose: generic implementation of wxRendererNative (for any platform) -// Author: Vadim Zeitlin -// Modified by: -// Created: 20.07.2003 -// RCS-ID: $Id: renderg.cpp 45498 2007-04-16 13:03:05Z VZ $ -// Copyright: (c) 2003 Vadim Zeitlin -// License: wxWindows license -/////////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// for compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#include "wx/renderer.h" - -#ifndef WX_PRECOMP - #include "wx/string.h" - #include "wx/dc.h" - #include "wx/settings.h" - #include "wx/gdicmn.h" - #include "wx/module.h" -#endif //WX_PRECOMP - -#include "wx/splitter.h" -#include "wx/dcmirror.h" - -// ---------------------------------------------------------------------------- -// wxRendererGeneric: our wxRendererNative implementation -// ---------------------------------------------------------------------------- - -class WXDLLEXPORT wxRendererGeneric : public wxRendererNative -{ -public: - wxRendererGeneric(); - - virtual int DrawHeaderButton(wxWindow *win, - wxDC& dc, - const wxRect& rect, - int flags = 0, - wxHeaderSortIconType sortArrow = wxHDR_SORT_ICON_NONE, - wxHeaderButtonParams* params = NULL); - - virtual int DrawHeaderButtonContents(wxWindow *win, - wxDC& dc, - const wxRect& rect, - int flags = 0, - wxHeaderSortIconType sortArrow = wxHDR_SORT_ICON_NONE, - wxHeaderButtonParams* params = NULL); - - virtual int GetHeaderButtonHeight(wxWindow *win); - - virtual void DrawTreeItemButton(wxWindow *win, - wxDC& dc, - const wxRect& rect, - int flags = 0); - - virtual void DrawSplitterBorder(wxWindow *win, - wxDC& dc, - const wxRect& rect, - int flags = 0); - - virtual void DrawSplitterSash(wxWindow *win, - wxDC& dc, - const wxSize& size, - wxCoord position, - wxOrientation orient, - int flags = 0); - - virtual void DrawComboBoxDropButton(wxWindow *win, - wxDC& dc, - const wxRect& rect, - int flags = 0); - - virtual void DrawDropArrow(wxWindow *win, - wxDC& dc, - const wxRect& rect, - int flags = 0); - - virtual void DrawCheckBox(wxWindow *win, - wxDC& dc, - const wxRect& rect, - int flags = 0); - - virtual void DrawPushButton(wxWindow *win, - wxDC& dc, - const wxRect& rect, - int flags = 0); - - virtual void DrawItemSelectionRect(wxWindow *win, - wxDC& dc, - const wxRect& rect, - int flags = 0); - - virtual wxSplitterRenderParams GetSplitterParams(const wxWindow *win); - - virtual wxRendererVersion GetVersion() const - { - return wxRendererVersion(wxRendererVersion::Current_Version, - wxRendererVersion::Current_Age); - } - - - // Cleanup by deleting standard renderer - static void Cleanup(); - - // Get the generic object - static wxRendererGeneric* DoGetGeneric(); - -protected: - // draw the rectange using the first pen for the left and top sides and - // the second one for the bottom and right ones - void DrawShadedRect(wxDC& dc, wxRect *rect, - const wxPen& pen1, const wxPen& pen2); - - // the standard pens - wxPen m_penBlack, - m_penDarkGrey, - m_penLightGrey, - m_penHighlight; - - static wxRendererGeneric* sm_rendererGeneric; -}; - -// ============================================================================ -// wxRendererGeneric implementation -// ============================================================================ - -// Get the generic object -wxRendererGeneric* wxRendererGeneric::DoGetGeneric() -{ - if (!sm_rendererGeneric) - sm_rendererGeneric = new wxRendererGeneric; - return sm_rendererGeneric; -} - -// ---------------------------------------------------------------------------- -// wxRendererGeneric creation -// ---------------------------------------------------------------------------- - -/* static */ -wxRendererNative& wxRendererNative::GetGeneric() -{ - return * wxRendererGeneric::DoGetGeneric(); -} - -void wxRendererGeneric::Cleanup() -{ - if (sm_rendererGeneric) - delete sm_rendererGeneric; - - sm_rendererGeneric = NULL; -} - -wxRendererGeneric* wxRendererGeneric::sm_rendererGeneric = NULL; - -wxRendererGeneric::wxRendererGeneric() - : m_penBlack(wxSystemSettings::GetColour(wxSYS_COLOUR_3DDKSHADOW)), - m_penDarkGrey(wxSystemSettings::GetColour(wxSYS_COLOUR_3DSHADOW)), - m_penLightGrey(wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE)), - m_penHighlight(wxSystemSettings::GetColour(wxSYS_COLOUR_3DHIGHLIGHT)) -{ -} - -// ---------------------------------------------------------------------------- -// wxRendererGeneric helpers -// ---------------------------------------------------------------------------- - -void -wxRendererGeneric::DrawShadedRect(wxDC& dc, - wxRect *rect, - const wxPen& pen1, - const wxPen& pen2) -{ - // draw the rectangle - dc.SetPen(pen1); - dc.DrawLine(rect->GetLeft(), rect->GetTop(), - rect->GetLeft(), rect->GetBottom()); - dc.DrawLine(rect->GetLeft() + 1, rect->GetTop(), - rect->GetRight(), rect->GetTop()); - dc.SetPen(pen2); - dc.DrawLine(rect->GetRight(), rect->GetTop(), - rect->GetRight(), rect->GetBottom()); - dc.DrawLine(rect->GetLeft(), rect->GetBottom(), - rect->GetRight() + 1, rect->GetBottom()); - - // adjust the rect - rect->Inflate(-1); -} - -// ---------------------------------------------------------------------------- -// tree/list ctrl drawing -// ---------------------------------------------------------------------------- - -int -wxRendererGeneric::DrawHeaderButton(wxWindow* win, - wxDC& dc, - const wxRect& rect, - int flags, - wxHeaderSortIconType sortArrow, - wxHeaderButtonParams* params) -{ - const int CORNER = 1; - - const wxCoord x = rect.x, - y = rect.y, - w = rect.width, - h = rect.height; - - dc.SetBrush(wxBrush(wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE))); - dc.SetPen(*wxTRANSPARENT_PEN); - dc.DrawRectangle(rect); - - dc.SetBrush(*wxTRANSPARENT_BRUSH); - - dc.SetPen(m_penBlack); - dc.DrawLine( x+w-CORNER+1, y, x+w, y+h ); // right (outer) - dc.DrawRectangle( x, y+h, w+1, 1 ); // bottom (outer) - - dc.SetPen(m_penDarkGrey); - dc.DrawLine( x+w-CORNER, y, x+w-1, y+h ); // right (inner) - dc.DrawRectangle( x+1, y+h-1, w-2, 1 ); // bottom (inner) - - dc.SetPen(m_penHighlight); - dc.DrawRectangle( x, y, w-CORNER+1, 1 ); // top (outer) - dc.DrawRectangle( x, y, 1, h ); // left (outer) - dc.DrawLine( x, y+h-1, x+1, y+h-1 ); - dc.DrawLine( x+w-1, y, x+w-1, y+1 ); - - return DrawHeaderButtonContents(win, dc, rect, flags, sortArrow, params); -} - - -int -wxRendererGeneric::DrawHeaderButtonContents(wxWindow *win, - wxDC& dc, - const wxRect& rect, - int flags, - wxHeaderSortIconType sortArrow, - wxHeaderButtonParams* params) -{ - int labelWidth = 0; - - // Mark this item as selected. For the generic version we'll just draw an - // underline - if ( flags & wxCONTROL_SELECTED ) - { - // draw a line at the bottom of the header button, overlaying the - // native hot-tracking line (on XP) - const int penwidth = 3; - int y = rect.y + rect.height + 1 - penwidth; - wxColour c = (params && params->m_selectionColour.Ok()) ? - params->m_selectionColour : wxColour(0x66, 0x66, 0x66); - wxPen pen(c, penwidth); - pen.SetCap(wxCAP_BUTT); - dc.SetPen(pen); - dc.DrawLine(rect.x, y, rect.x + rect.width, y); - } - - // Draw an up or down arrow - int arrowSpace = 0; - if (sortArrow != wxHDR_SORT_ICON_NONE ) - { - wxRect ar = rect; - - // make a rect for the arrow - ar.height = 4; - ar.width = 8; - ar.y += (rect.height - ar.height)/2; - ar.x = ar.x + rect.width - 3*ar.width/2; - arrowSpace = 3*ar.width/2; // space to preserve when drawing the label - - wxPoint triPt[3]; - if ( sortArrow & wxHDR_SORT_ICON_UP ) - { - triPt[0].x = ar.width / 2; - triPt[0].y = 0; - triPt[1].x = ar.width; - triPt[1].y = ar.height; - triPt[2].x = 0; - triPt[2].y = ar.height; - } - else - { - triPt[0].x = 0; - triPt[0].y = 0; - triPt[1].x = ar.width; - triPt[1].y = 0; - triPt[2].x = ar.width / 2; - triPt[2].y = ar.height; - } - - wxColour c = (params && params->m_arrowColour.Ok()) ? - params->m_arrowColour : wxSystemSettings::GetColour(wxSYS_COLOUR_3DSHADOW); - dc.SetPen(wxPen(c)); - dc.SetBrush(wxBrush(c)); - dc.DrawPolygon( 3, triPt, ar.x, ar.y); - } - labelWidth += arrowSpace; - - const int margin = 5; // number of pixels to reserve on either side of the label - int bmpWidth = 0; - int txtEnd = 0; - - if ( params && params->m_labelBitmap.Ok() ) - bmpWidth = params->m_labelBitmap.GetWidth() + 2; - - labelWidth += bmpWidth + 2*margin; - - // Draw a label if one is given - if ( params && !params->m_labelText.empty() ) - { - wxFont font = params->m_labelFont.Ok() ? - params->m_labelFont : win->GetFont(); - wxColour clr = params->m_labelColour.Ok() ? - params->m_labelColour : win->GetForegroundColour(); - - wxString label( params->m_labelText ); - - dc.SetFont(font); - dc.SetTextForeground(clr); - dc.SetBackgroundMode(wxTRANSPARENT); - - int tw, th, td, x, y; - dc.GetTextExtent( label, &tw, &th, &td); - labelWidth += tw; - y = rect.y + wxMax(0, (rect.height - (th+td)) / 2); - - // truncate and add an ellipsis (...) if the text is too wide. - int targetWidth = rect.width - arrowSpace - bmpWidth - 2*margin; - if ( tw > targetWidth ) - { - int ellipsisWidth; - dc.GetTextExtent( wxT("..."), &ellipsisWidth, NULL); - do { - label.Truncate( label.length() - 1 ); - dc.GetTextExtent( label, &tw, &th); - } while (tw + ellipsisWidth > targetWidth && label.length() ); - label.append( wxT("...") ); - tw += ellipsisWidth; - } - - switch (params->m_labelAlignment) - { - default: - case wxALIGN_LEFT: - x = rect.x + margin; - break; - case wxALIGN_CENTER: - x = rect.x + wxMax(0, (rect.width - arrowSpace - tw - bmpWidth)/2); - break; - case wxALIGN_RIGHT: - x = rect.x + wxMax(0, rect.width - arrowSpace - margin - tw - bmpWidth); - break; - } - - dc.DrawText(label, x, y); - txtEnd = x + tw + 2; - } - - // draw the bitmap if there is one - if ( params && params->m_labelBitmap.Ok() ) - { - int w, h, x, y; - w = params->m_labelBitmap.GetWidth(); - h = params->m_labelBitmap.GetHeight(); - - y = rect.y + wxMax(1, (rect.height - h) / 2); - - // if there is a text label, then put the bitmap at the end of the label - if ( txtEnd != 0 ) - { - x = txtEnd; - } - // otherwise use the alignment flags - else - { - switch (params->m_labelAlignment) - { - default: - case wxALIGN_LEFT: - x = rect.x + margin; - break; - case wxALIGN_CENTER: - x = rect.x + wxMax(1, (rect.width - arrowSpace - w)/2); - break; - case wxALIGN_RIGHT: - x = rect.x + wxMax(1, rect.width - arrowSpace - margin - w); - break; - } - } - dc.DrawBitmap(params->m_labelBitmap, x, y, true); - } - return labelWidth; -} - - -int wxRendererGeneric::GetHeaderButtonHeight(wxWindow *win) -{ - // Copied and adapted from src/generic/listctrl.cpp - const int HEADER_OFFSET_Y = 1; - const int EXTRA_HEIGHT = 4; - - int w=0, h=14, d=0; - if (win) - win->GetTextExtent(wxT("Hg"), &w, &h, &d); - - return h + d + 2 * HEADER_OFFSET_Y + EXTRA_HEIGHT; -} - - -// draw the plus or minus sign -void -wxRendererGeneric::DrawTreeItemButton(wxWindow * WXUNUSED(win), - wxDC& dc, - const wxRect& rect, - int flags) -{ - // store settings - wxDCPenChanger penChanger(dc, *wxGREY_PEN); - wxDCBrushChanger brushChanger(dc, *wxWHITE_BRUSH); - - dc.DrawRectangle(rect); - - // black lines - const wxCoord xMiddle = rect.x + rect.width/2; - const wxCoord yMiddle = rect.y + rect.height/2; - - // half of the length of the horz lines in "-" and "+" - const wxCoord halfWidth = rect.width/2 - 2; - dc.SetPen(*wxBLACK_PEN); - dc.DrawLine(xMiddle - halfWidth, yMiddle, - xMiddle + halfWidth + 1, yMiddle); - - if ( !(flags & wxCONTROL_EXPANDED) ) - { - // turn "-" into "+" - const wxCoord halfHeight = rect.height/2 - 2; - dc.DrawLine(xMiddle, yMiddle - halfHeight, - xMiddle, yMiddle + halfHeight + 1); - } -} - -// ---------------------------------------------------------------------------- -// sash drawing -// ---------------------------------------------------------------------------- - -wxSplitterRenderParams -wxRendererGeneric::GetSplitterParams(const wxWindow *win) -{ - // see below - wxCoord sashWidth, - border; - - if ( win->HasFlag(wxSP_3DSASH) ) - sashWidth = 7; - else if ( win->HasFlag(wxSP_NOSASH) ) - sashWidth = 0; - else // no 3D effect - sashWidth = 3; - - if ( win->HasFlag(wxSP_3DBORDER) ) - border = 2; - else // no 3D effect - border = 0; - - return wxSplitterRenderParams(sashWidth, border, false); -} - -void -wxRendererGeneric::DrawSplitterBorder(wxWindow *win, - wxDC& dc, - const wxRect& rectOrig, - int WXUNUSED(falgs)) -{ - if ( win->HasFlag(wxSP_3DBORDER) ) - { - wxRect rect = rectOrig; - DrawShadedRect(dc, &rect, m_penDarkGrey, m_penHighlight); - DrawShadedRect(dc, &rect, m_penBlack, m_penLightGrey); - } -} - -void -wxRendererGeneric::DrawSplitterSash(wxWindow *win, - wxDC& dcReal, - const wxSize& sizeReal, - wxCoord position, - wxOrientation orient, - int WXUNUSED(flags)) -{ - // to avoid duplicating the same code for horizontal and vertical sashes, - // simply mirror the DC instead if needed (i.e. if horz splitter) - wxMirrorDC dc(dcReal, orient != wxVERTICAL); - wxSize size = dc.Reflect(sizeReal); - - - // we draw a Win32-like grey sash with possible 3D border here: - // - // ---- this is position - // / - // v - // dWGGGDd - // GWGGGDB - // GWGGGDB where G is light grey (face) - // GWGGGDB W white (light) - // GWGGGDB D dark grey (shadow) - // GWGGGDB B black (dark shadow) - // GWGGGDB - // GWGGGDB and lower letters are our border (already drawn) - // GWGGGDB - // wWGGGDd - // - // only the middle 3 columns are drawn unless wxSP_3D is specified - - const wxCoord h = size.y; - wxCoord offset = 0; - - // If we're drawing the border, draw the sash 3d lines shorter - if ( win->HasFlag(wxSP_3DBORDER) ) - { - offset = 1; - } - - dc.SetPen(*wxTRANSPARENT_PEN); - dc.SetBrush(wxBrush(wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE))); - - if ( win->HasFlag(wxSP_3DSASH) ) - { - // Draw the 3D sash - dc.DrawRectangle(position + 2, 0, 3, h); - - dc.SetPen(m_penLightGrey); - dc.DrawLine(position, offset, position, h - offset); - - dc.SetPen(m_penHighlight); - dc.DrawLine(position + 1, 0, position + 1, h); - - dc.SetPen(m_penDarkGrey); - dc.DrawLine(position + 5, 0, position + 5, h); - - dc.SetPen(m_penBlack); - dc.DrawLine(position + 6, offset, position + 6, h - offset); - } - else - { - // Draw a flat sash - dc.DrawRectangle(position, 0, 3, h); - } -} - -// ---------------------------------------------------------------------------- -// button drawing -// ---------------------------------------------------------------------------- - -void -wxRendererGeneric::DrawComboBoxDropButton(wxWindow *win, - wxDC& dc, - const wxRect& rect, - int flags) -{ - DrawPushButton(win,dc,rect,flags); - DrawDropArrow(win,dc,rect,flags); -} - -void -wxRendererGeneric::DrawDropArrow(wxWindow *win, - wxDC& dc, - const wxRect& rect, - int WXUNUSED(flags)) -{ - // This generic implementation should be good - // enough for Windows platforms (including XP). - - int arrowHalf = rect.width/5; - int rectMid = rect.width / 2; - int arrowTopY = (rect.height/2) - (arrowHalf/2); - - // This should always result in arrow with odd width. - wxPoint pt[] = - { - wxPoint(rectMid - arrowHalf, arrowTopY), - wxPoint(rectMid + arrowHalf, arrowTopY), - wxPoint(rectMid, arrowTopY + arrowHalf) - }; - dc.SetBrush(wxBrush(win->GetForegroundColour())); - dc.SetPen(wxPen(win->GetForegroundColour())); - dc.DrawPolygon(WXSIZEOF(pt), pt, rect.x, rect.y); -} - -void -wxRendererGeneric::DrawCheckBox(wxWindow *WXUNUSED(win), - wxDC& dc, - const wxRect& rect, - int flags) -{ - dc.SetPen(*(flags & wxCONTROL_DISABLED ? wxGREY_PEN : wxBLACK_PEN)); - dc.SetBrush( *wxTRANSPARENT_BRUSH ); - dc.DrawRectangle(rect); - - if ( flags & wxCONTROL_CHECKED ) - { - dc.DrawCheckMark(rect.Deflate(2, 2)); - } -} - -void -wxRendererGeneric::DrawPushButton(wxWindow *win, - wxDC& dc, - const wxRect& rect, - int flags) -{ - // Don't try anything too fancy. It'll just turn out looking - // out-of-place on most platforms. - wxColour bgCol = flags & wxCONTROL_DISABLED ? - wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE) : - win->GetBackgroundColour(); - dc.SetBrush(wxBrush(bgCol)); - dc.SetPen(wxPen(bgCol)); - dc.DrawRectangle(rect); -} - -void -wxRendererGeneric::DrawItemSelectionRect(wxWindow * WXUNUSED(win), - wxDC& dc, - const wxRect& rect, - int flags) -{ - wxBrush brush; - if ( flags & wxCONTROL_SELECTED ) - { - if ( flags & wxCONTROL_FOCUSED ) - { - brush = wxBrush(wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT)); - } - else // !focused - { - brush = wxBrush(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNSHADOW)); - } - } - else // !selected - { - brush = *wxTRANSPARENT_BRUSH; - } - - dc.SetBrush(brush); - dc.SetPen(flags & wxCONTROL_CURRENT ? *wxBLACK_PEN : *wxTRANSPARENT_PEN); - - dc.DrawRectangle( rect ); -} - - -// ---------------------------------------------------------------------------- -// A module to allow cleanup of generic renderer. -// ---------------------------------------------------------------------------- - -class wxGenericRendererModule: public wxModule -{ -DECLARE_DYNAMIC_CLASS(wxGenericRendererModule) -public: - wxGenericRendererModule() {} - bool OnInit() { return true; } - void OnExit() { wxRendererGeneric::Cleanup(); } -}; - -IMPLEMENT_DYNAMIC_CLASS(wxGenericRendererModule, wxModule) +/////////////////////////////////////////////////////////////////////////////// +// Name: src/generic/renderg.cpp +// Purpose: generic implementation of wxRendererNative (for any platform) +// Author: Vadim Zeitlin +// Modified by: +// Created: 20.07.2003 +// RCS-ID: $Id: renderg.cpp 45498 2007-04-16 13:03:05Z VZ $ +// Copyright: (c) 2003 Vadim Zeitlin +// License: wxWindows license +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// for compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#include "wx/renderer.h" + +#ifndef WX_PRECOMP + #include "wx/string.h" + #include "wx/dc.h" + #include "wx/settings.h" + #include "wx/gdicmn.h" + #include "wx/module.h" +#endif //WX_PRECOMP + +#include "wx/splitter.h" +#include "wx/dcmirror.h" + +// ---------------------------------------------------------------------------- +// wxRendererGeneric: our wxRendererNative implementation +// ---------------------------------------------------------------------------- + +class WXDLLEXPORT wxRendererGeneric : public wxRendererNative +{ +public: + wxRendererGeneric(); + + virtual int DrawHeaderButton(wxWindow *win, + wxDC& dc, + const wxRect& rect, + int flags = 0, + wxHeaderSortIconType sortArrow = wxHDR_SORT_ICON_NONE, + wxHeaderButtonParams* params = NULL); + + virtual int DrawHeaderButtonContents(wxWindow *win, + wxDC& dc, + const wxRect& rect, + int flags = 0, + wxHeaderSortIconType sortArrow = wxHDR_SORT_ICON_NONE, + wxHeaderButtonParams* params = NULL); + + virtual int GetHeaderButtonHeight(wxWindow *win); + + virtual void DrawTreeItemButton(wxWindow *win, + wxDC& dc, + const wxRect& rect, + int flags = 0); + + virtual void DrawSplitterBorder(wxWindow *win, + wxDC& dc, + const wxRect& rect, + int flags = 0); + + virtual void DrawSplitterSash(wxWindow *win, + wxDC& dc, + const wxSize& size, + wxCoord position, + wxOrientation orient, + int flags = 0); + + virtual void DrawComboBoxDropButton(wxWindow *win, + wxDC& dc, + const wxRect& rect, + int flags = 0); + + virtual void DrawDropArrow(wxWindow *win, + wxDC& dc, + const wxRect& rect, + int flags = 0); + + virtual void DrawCheckBox(wxWindow *win, + wxDC& dc, + const wxRect& rect, + int flags = 0); + + virtual void DrawPushButton(wxWindow *win, + wxDC& dc, + const wxRect& rect, + int flags = 0); + + virtual void DrawItemSelectionRect(wxWindow *win, + wxDC& dc, + const wxRect& rect, + int flags = 0); + + virtual wxSplitterRenderParams GetSplitterParams(const wxWindow *win); + + virtual wxRendererVersion GetVersion() const + { + return wxRendererVersion(wxRendererVersion::Current_Version, + wxRendererVersion::Current_Age); + } + + + // Cleanup by deleting standard renderer + static void Cleanup(); + + // Get the generic object + static wxRendererGeneric* DoGetGeneric(); + +protected: + // draw the rectange using the first pen for the left and top sides and + // the second one for the bottom and right ones + void DrawShadedRect(wxDC& dc, wxRect *rect, + const wxPen& pen1, const wxPen& pen2); + + // the standard pens + wxPen m_penBlack, + m_penDarkGrey, + m_penLightGrey, + m_penHighlight; + + static wxRendererGeneric* sm_rendererGeneric; +}; + +// ============================================================================ +// wxRendererGeneric implementation +// ============================================================================ + +// Get the generic object +wxRendererGeneric* wxRendererGeneric::DoGetGeneric() +{ + if (!sm_rendererGeneric) + sm_rendererGeneric = new wxRendererGeneric; + return sm_rendererGeneric; +} + +// ---------------------------------------------------------------------------- +// wxRendererGeneric creation +// ---------------------------------------------------------------------------- + +/* static */ +wxRendererNative& wxRendererNative::GetGeneric() +{ + return * wxRendererGeneric::DoGetGeneric(); +} + +void wxRendererGeneric::Cleanup() +{ + if (sm_rendererGeneric) + delete sm_rendererGeneric; + + sm_rendererGeneric = NULL; +} + +wxRendererGeneric* wxRendererGeneric::sm_rendererGeneric = NULL; + +wxRendererGeneric::wxRendererGeneric() + : m_penBlack(wxSystemSettings::GetColour(wxSYS_COLOUR_3DDKSHADOW)), + m_penDarkGrey(wxSystemSettings::GetColour(wxSYS_COLOUR_3DSHADOW)), + m_penLightGrey(wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE)), + m_penHighlight(wxSystemSettings::GetColour(wxSYS_COLOUR_3DHIGHLIGHT)) +{ +} + +// ---------------------------------------------------------------------------- +// wxRendererGeneric helpers +// ---------------------------------------------------------------------------- + +void +wxRendererGeneric::DrawShadedRect(wxDC& dc, + wxRect *rect, + const wxPen& pen1, + const wxPen& pen2) +{ + // draw the rectangle + dc.SetPen(pen1); + dc.DrawLine(rect->GetLeft(), rect->GetTop(), + rect->GetLeft(), rect->GetBottom()); + dc.DrawLine(rect->GetLeft() + 1, rect->GetTop(), + rect->GetRight(), rect->GetTop()); + dc.SetPen(pen2); + dc.DrawLine(rect->GetRight(), rect->GetTop(), + rect->GetRight(), rect->GetBottom()); + dc.DrawLine(rect->GetLeft(), rect->GetBottom(), + rect->GetRight() + 1, rect->GetBottom()); + + // adjust the rect + rect->Inflate(-1); +} + +// ---------------------------------------------------------------------------- +// tree/list ctrl drawing +// ---------------------------------------------------------------------------- + +int +wxRendererGeneric::DrawHeaderButton(wxWindow* win, + wxDC& dc, + const wxRect& rect, + int flags, + wxHeaderSortIconType sortArrow, + wxHeaderButtonParams* params) +{ + const int CORNER = 1; + + const wxCoord x = rect.x, + y = rect.y, + w = rect.width, + h = rect.height; + + dc.SetBrush(wxBrush(wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE))); + dc.SetPen(*wxTRANSPARENT_PEN); + dc.DrawRectangle(rect); + + dc.SetBrush(*wxTRANSPARENT_BRUSH); + + dc.SetPen(m_penBlack); + dc.DrawLine( x+w-CORNER+1, y, x+w, y+h ); // right (outer) + dc.DrawRectangle( x, y+h, w+1, 1 ); // bottom (outer) + + dc.SetPen(m_penDarkGrey); + dc.DrawLine( x+w-CORNER, y, x+w-1, y+h ); // right (inner) + dc.DrawRectangle( x+1, y+h-1, w-2, 1 ); // bottom (inner) + + dc.SetPen(m_penHighlight); + dc.DrawRectangle( x, y, w-CORNER+1, 1 ); // top (outer) + dc.DrawRectangle( x, y, 1, h ); // left (outer) + dc.DrawLine( x, y+h-1, x+1, y+h-1 ); + dc.DrawLine( x+w-1, y, x+w-1, y+1 ); + + return DrawHeaderButtonContents(win, dc, rect, flags, sortArrow, params); +} + + +int +wxRendererGeneric::DrawHeaderButtonContents(wxWindow *win, + wxDC& dc, + const wxRect& rect, + int flags, + wxHeaderSortIconType sortArrow, + wxHeaderButtonParams* params) +{ + int labelWidth = 0; + + // Mark this item as selected. For the generic version we'll just draw an + // underline + if ( flags & wxCONTROL_SELECTED ) + { + // draw a line at the bottom of the header button, overlaying the + // native hot-tracking line (on XP) + const int penwidth = 3; + int y = rect.y + rect.height + 1 - penwidth; + wxColour c = (params && params->m_selectionColour.Ok()) ? + params->m_selectionColour : wxColour(0x66, 0x66, 0x66); + wxPen pen(c, penwidth); + pen.SetCap(wxCAP_BUTT); + dc.SetPen(pen); + dc.DrawLine(rect.x, y, rect.x + rect.width, y); + } + + // Draw an up or down arrow + int arrowSpace = 0; + if (sortArrow != wxHDR_SORT_ICON_NONE ) + { + wxRect ar = rect; + + // make a rect for the arrow + ar.height = 4; + ar.width = 8; + ar.y += (rect.height - ar.height)/2; + ar.x = ar.x + rect.width - 3*ar.width/2; + arrowSpace = 3*ar.width/2; // space to preserve when drawing the label + + wxPoint triPt[3]; + if ( sortArrow & wxHDR_SORT_ICON_UP ) + { + triPt[0].x = ar.width / 2; + triPt[0].y = 0; + triPt[1].x = ar.width; + triPt[1].y = ar.height; + triPt[2].x = 0; + triPt[2].y = ar.height; + } + else + { + triPt[0].x = 0; + triPt[0].y = 0; + triPt[1].x = ar.width; + triPt[1].y = 0; + triPt[2].x = ar.width / 2; + triPt[2].y = ar.height; + } + + wxColour c = (params && params->m_arrowColour.Ok()) ? + params->m_arrowColour : wxSystemSettings::GetColour(wxSYS_COLOUR_3DSHADOW); + dc.SetPen(wxPen(c)); + dc.SetBrush(wxBrush(c)); + dc.DrawPolygon( 3, triPt, ar.x, ar.y); + } + labelWidth += arrowSpace; + + const int margin = 5; // number of pixels to reserve on either side of the label + int bmpWidth = 0; + int txtEnd = 0; + + if ( params && params->m_labelBitmap.Ok() ) + bmpWidth = params->m_labelBitmap.GetWidth() + 2; + + labelWidth += bmpWidth + 2*margin; + + // Draw a label if one is given + if ( params && !params->m_labelText.empty() ) + { + wxFont font = params->m_labelFont.Ok() ? + params->m_labelFont : win->GetFont(); + wxColour clr = params->m_labelColour.Ok() ? + params->m_labelColour : win->GetForegroundColour(); + + wxString label( params->m_labelText ); + + dc.SetFont(font); + dc.SetTextForeground(clr); + dc.SetBackgroundMode(wxTRANSPARENT); + + int tw, th, td, x, y; + dc.GetTextExtent( label, &tw, &th, &td); + labelWidth += tw; + y = rect.y + wxMax(0, (rect.height - (th+td)) / 2); + + // truncate and add an ellipsis (...) if the text is too wide. + int targetWidth = rect.width - arrowSpace - bmpWidth - 2*margin; + if ( tw > targetWidth ) + { + int ellipsisWidth; + dc.GetTextExtent( wxT("..."), &ellipsisWidth, NULL); + do { + label.Truncate( label.length() - 1 ); + dc.GetTextExtent( label, &tw, &th); + } while (tw + ellipsisWidth > targetWidth && label.length() ); + label.append( wxT("...") ); + tw += ellipsisWidth; + } + + switch (params->m_labelAlignment) + { + default: + case wxALIGN_LEFT: + x = rect.x + margin; + break; + case wxALIGN_CENTER: + x = rect.x + wxMax(0, (rect.width - arrowSpace - tw - bmpWidth)/2); + break; + case wxALIGN_RIGHT: + x = rect.x + wxMax(0, rect.width - arrowSpace - margin - tw - bmpWidth); + break; + } + + dc.DrawText(label, x, y); + txtEnd = x + tw + 2; + } + + // draw the bitmap if there is one + if ( params && params->m_labelBitmap.Ok() ) + { + int w, h, x, y; + w = params->m_labelBitmap.GetWidth(); + h = params->m_labelBitmap.GetHeight(); + + y = rect.y + wxMax(1, (rect.height - h) / 2); + + // if there is a text label, then put the bitmap at the end of the label + if ( txtEnd != 0 ) + { + x = txtEnd; + } + // otherwise use the alignment flags + else + { + switch (params->m_labelAlignment) + { + default: + case wxALIGN_LEFT: + x = rect.x + margin; + break; + case wxALIGN_CENTER: + x = rect.x + wxMax(1, (rect.width - arrowSpace - w)/2); + break; + case wxALIGN_RIGHT: + x = rect.x + wxMax(1, rect.width - arrowSpace - margin - w); + break; + } + } + dc.DrawBitmap(params->m_labelBitmap, x, y, true); + } + return labelWidth; +} + + +int wxRendererGeneric::GetHeaderButtonHeight(wxWindow *win) +{ + // Copied and adapted from src/generic/listctrl.cpp + const int HEADER_OFFSET_Y = 1; + const int EXTRA_HEIGHT = 4; + + int w=0, h=14, d=0; + if (win) + win->GetTextExtent(wxT("Hg"), &w, &h, &d); + + return h + d + 2 * HEADER_OFFSET_Y + EXTRA_HEIGHT; +} + + +// draw the plus or minus sign +void +wxRendererGeneric::DrawTreeItemButton(wxWindow * WXUNUSED(win), + wxDC& dc, + const wxRect& rect, + int flags) +{ + // store settings + wxDCPenChanger penChanger(dc, *wxGREY_PEN); + wxDCBrushChanger brushChanger(dc, *wxWHITE_BRUSH); + + dc.DrawRectangle(rect); + + // black lines + const wxCoord xMiddle = rect.x + rect.width/2; + const wxCoord yMiddle = rect.y + rect.height/2; + + // half of the length of the horz lines in "-" and "+" + const wxCoord halfWidth = rect.width/2 - 2; + dc.SetPen(*wxBLACK_PEN); + dc.DrawLine(xMiddle - halfWidth, yMiddle, + xMiddle + halfWidth + 1, yMiddle); + + if ( !(flags & wxCONTROL_EXPANDED) ) + { + // turn "-" into "+" + const wxCoord halfHeight = rect.height/2 - 2; + dc.DrawLine(xMiddle, yMiddle - halfHeight, + xMiddle, yMiddle + halfHeight + 1); + } +} + +// ---------------------------------------------------------------------------- +// sash drawing +// ---------------------------------------------------------------------------- + +wxSplitterRenderParams +wxRendererGeneric::GetSplitterParams(const wxWindow *win) +{ + // see below + wxCoord sashWidth, + border; + + if ( win->HasFlag(wxSP_3DSASH) ) + sashWidth = 7; + else if ( win->HasFlag(wxSP_NOSASH) ) + sashWidth = 0; + else // no 3D effect + sashWidth = 3; + + if ( win->HasFlag(wxSP_3DBORDER) ) + border = 2; + else // no 3D effect + border = 0; + + return wxSplitterRenderParams(sashWidth, border, false); +} + +void +wxRendererGeneric::DrawSplitterBorder(wxWindow *win, + wxDC& dc, + const wxRect& rectOrig, + int WXUNUSED(falgs)) +{ + if ( win->HasFlag(wxSP_3DBORDER) ) + { + wxRect rect = rectOrig; + DrawShadedRect(dc, &rect, m_penDarkGrey, m_penHighlight); + DrawShadedRect(dc, &rect, m_penBlack, m_penLightGrey); + } +} + +void +wxRendererGeneric::DrawSplitterSash(wxWindow *win, + wxDC& dcReal, + const wxSize& sizeReal, + wxCoord position, + wxOrientation orient, + int WXUNUSED(flags)) +{ + // to avoid duplicating the same code for horizontal and vertical sashes, + // simply mirror the DC instead if needed (i.e. if horz splitter) + wxMirrorDC dc(dcReal, orient != wxVERTICAL); + wxSize size = dc.Reflect(sizeReal); + + + // we draw a Win32-like grey sash with possible 3D border here: + // + // ---- this is position + // / + // v + // dWGGGDd + // GWGGGDB + // GWGGGDB where G is light grey (face) + // GWGGGDB W white (light) + // GWGGGDB D dark grey (shadow) + // GWGGGDB B black (dark shadow) + // GWGGGDB + // GWGGGDB and lower letters are our border (already drawn) + // GWGGGDB + // wWGGGDd + // + // only the middle 3 columns are drawn unless wxSP_3D is specified + + const wxCoord h = size.y; + wxCoord offset = 0; + + // If we're drawing the border, draw the sash 3d lines shorter + if ( win->HasFlag(wxSP_3DBORDER) ) + { + offset = 1; + } + + dc.SetPen(*wxTRANSPARENT_PEN); + dc.SetBrush(wxBrush(wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE))); + + if ( win->HasFlag(wxSP_3DSASH) ) + { + // Draw the 3D sash + dc.DrawRectangle(position + 2, 0, 3, h); + + dc.SetPen(m_penLightGrey); + dc.DrawLine(position, offset, position, h - offset); + + dc.SetPen(m_penHighlight); + dc.DrawLine(position + 1, 0, position + 1, h); + + dc.SetPen(m_penDarkGrey); + dc.DrawLine(position + 5, 0, position + 5, h); + + dc.SetPen(m_penBlack); + dc.DrawLine(position + 6, offset, position + 6, h - offset); + } + else + { + // Draw a flat sash + dc.DrawRectangle(position, 0, 3, h); + } +} + +// ---------------------------------------------------------------------------- +// button drawing +// ---------------------------------------------------------------------------- + +void +wxRendererGeneric::DrawComboBoxDropButton(wxWindow *win, + wxDC& dc, + const wxRect& rect, + int flags) +{ + DrawPushButton(win,dc,rect,flags); + DrawDropArrow(win,dc,rect,flags); +} + +void +wxRendererGeneric::DrawDropArrow(wxWindow *win, + wxDC& dc, + const wxRect& rect, + int WXUNUSED(flags)) +{ + // This generic implementation should be good + // enough for Windows platforms (including XP). + + int arrowHalf = rect.width/5; + int rectMid = rect.width / 2; + int arrowTopY = (rect.height/2) - (arrowHalf/2); + + // This should always result in arrow with odd width. + wxPoint pt[] = + { + wxPoint(rectMid - arrowHalf, arrowTopY), + wxPoint(rectMid + arrowHalf, arrowTopY), + wxPoint(rectMid, arrowTopY + arrowHalf) + }; + dc.SetBrush(wxBrush(win->GetForegroundColour())); + dc.SetPen(wxPen(win->GetForegroundColour())); + dc.DrawPolygon(WXSIZEOF(pt), pt, rect.x, rect.y); +} + +void +wxRendererGeneric::DrawCheckBox(wxWindow *WXUNUSED(win), + wxDC& dc, + const wxRect& rect, + int flags) +{ + dc.SetPen(*(flags & wxCONTROL_DISABLED ? wxGREY_PEN : wxBLACK_PEN)); + dc.SetBrush( *wxTRANSPARENT_BRUSH ); + dc.DrawRectangle(rect); + + if ( flags & wxCONTROL_CHECKED ) + { + dc.DrawCheckMark(rect.Deflate(2, 2)); + } +} + +void +wxRendererGeneric::DrawPushButton(wxWindow *win, + wxDC& dc, + const wxRect& rect, + int flags) +{ + // Don't try anything too fancy. It'll just turn out looking + // out-of-place on most platforms. + wxColour bgCol = flags & wxCONTROL_DISABLED ? + wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE) : + win->GetBackgroundColour(); + dc.SetBrush(wxBrush(bgCol)); + dc.SetPen(wxPen(bgCol)); + dc.DrawRectangle(rect); +} + +void +wxRendererGeneric::DrawItemSelectionRect(wxWindow * WXUNUSED(win), + wxDC& dc, + const wxRect& rect, + int flags) +{ + wxBrush brush; + if ( flags & wxCONTROL_SELECTED ) + { + if ( flags & wxCONTROL_FOCUSED ) + { + brush = wxBrush(wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT)); + } + else // !focused + { + brush = wxBrush(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNSHADOW)); + } + } + else // !selected + { + brush = *wxTRANSPARENT_BRUSH; + } + + dc.SetBrush(brush); + dc.SetPen(flags & wxCONTROL_CURRENT ? *wxBLACK_PEN : *wxTRANSPARENT_PEN); + + dc.DrawRectangle( rect ); +} + + +// ---------------------------------------------------------------------------- +// A module to allow cleanup of generic renderer. +// ---------------------------------------------------------------------------- + +class wxGenericRendererModule: public wxModule +{ +DECLARE_DYNAMIC_CLASS(wxGenericRendererModule) +public: + wxGenericRendererModule() {} + bool OnInit() { return true; } + void OnExit() { wxRendererGeneric::Cleanup(); } +}; + +IMPLEMENT_DYNAMIC_CLASS(wxGenericRendererModule, wxModule) diff --git a/Externals/wxWidgets/src/generic/sashwin.cpp b/Externals/wxWidgets/src/generic/sashwin.cpp index 4a0d5f2082..2d7dbf3f84 100644 --- a/Externals/wxWidgets/src/generic/sashwin.cpp +++ b/Externals/wxWidgets/src/generic/sashwin.cpp @@ -1,708 +1,708 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/generic/sashwin.cpp -// Purpose: wxSashWindow implementation. A sash window has an optional -// sash on each edge, allowing it to be dragged. An event -// is generated when the sash is released. -// Author: Julian Smart -// Modified by: -// Created: 01/02/97 -// RCS-ID: $Id: sashwin.cpp 51249 2008-01-16 13:50:23Z JS $ -// Copyright: (c) Julian Smart -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_SASH - -#include "wx/sashwin.h" - -#ifndef WX_PRECOMP - #include "wx/dialog.h" - #include "wx/frame.h" - #include "wx/settings.h" - #include "wx/dcclient.h" - #include "wx/dcscreen.h" - #include "wx/math.h" -#endif - -#include - -#include "wx/laywin.h" - -DEFINE_EVENT_TYPE(wxEVT_SASH_DRAGGED) - -IMPLEMENT_DYNAMIC_CLASS(wxSashWindow, wxWindow) -IMPLEMENT_DYNAMIC_CLASS(wxSashEvent, wxCommandEvent) - -BEGIN_EVENT_TABLE(wxSashWindow, wxWindow) - EVT_PAINT(wxSashWindow::OnPaint) - EVT_SIZE(wxSashWindow::OnSize) - EVT_MOUSE_EVENTS(wxSashWindow::OnMouseEvent) -#if defined( __WXMSW__ ) || defined( __WXMAC__) - EVT_SET_CURSOR(wxSashWindow::OnSetCursor) -#endif // __WXMSW__ || __WXMAC__ - -END_EVENT_TABLE() - -bool wxSashWindow::Create(wxWindow *parent, wxWindowID id, const wxPoint& pos, - const wxSize& size, long style, const wxString& name) -{ - return wxWindow::Create(parent, id, pos, size, style, name); -} - -wxSashWindow::~wxSashWindow() -{ - delete m_sashCursorWE; - delete m_sashCursorNS; -} - -void wxSashWindow::Init() -{ - m_draggingEdge = wxSASH_NONE; - m_dragMode = wxSASH_DRAG_NONE; - m_oldX = 0; - m_oldY = 0; - m_firstX = 0; - m_firstY = 0; - m_borderSize = 3; - m_extraBorderSize = 0; - m_minimumPaneSizeX = 0; - m_minimumPaneSizeY = 0; - m_maximumPaneSizeX = 10000; - m_maximumPaneSizeY = 10000; - m_sashCursorWE = new wxCursor(wxCURSOR_SIZEWE); - m_sashCursorNS = new wxCursor(wxCURSOR_SIZENS); - m_mouseCaptured = false; - m_currentCursor = NULL; - - // Eventually, we'll respond to colour change messages - InitColours(); -} - -void wxSashWindow::OnPaint(wxPaintEvent& WXUNUSED(event)) -{ - wxPaintDC dc(this); - - DrawBorders(dc); - DrawSashes(dc); -} - -void wxSashWindow::OnMouseEvent(wxMouseEvent& event) -{ - wxCoord x = 0, y = 0; - event.GetPosition(&x, &y); - - wxSashEdgePosition sashHit = SashHitTest(x, y); - - if (event.LeftDown()) - { - CaptureMouse(); - m_mouseCaptured = true; - - if ( sashHit != wxSASH_NONE ) - { - // Required for X to specify that - // that we wish to draw on top of all windows - // - and we optimise by specifying the area - // for creating the overlap window. - // Find the first frame or dialog and use this to specify - // the area to draw on. - wxWindow* parent = this; - - while (parent && !parent->IsKindOf(CLASSINFO(wxDialog)) && - !parent->IsKindOf(CLASSINFO(wxFrame))) - parent = parent->GetParent(); - - wxScreenDC::StartDrawingOnTop(parent); - - // We don't say we're dragging yet; we leave that - // decision for the Dragging() branch, to ensure - // the user has dragged a little bit. - m_dragMode = wxSASH_DRAG_LEFT_DOWN; - m_draggingEdge = sashHit; - m_firstX = x; - m_firstY = y; - - if ( (sashHit == wxSASH_LEFT) || (sashHit == wxSASH_RIGHT) ) - { - if (m_currentCursor != m_sashCursorWE) - { - SetCursor(*m_sashCursorWE); - } - m_currentCursor = m_sashCursorWE; - } - else - { - if (m_currentCursor != m_sashCursorNS) - { - SetCursor(*m_sashCursorNS); - } - m_currentCursor = m_sashCursorNS; - } - } - } - else if ( event.LeftUp() && m_dragMode == wxSASH_DRAG_LEFT_DOWN ) - { - // Wasn't a proper drag - if (m_mouseCaptured) - ReleaseMouse(); - m_mouseCaptured = false; - - wxScreenDC::EndDrawingOnTop(); - m_dragMode = wxSASH_DRAG_NONE; - m_draggingEdge = wxSASH_NONE; - } - else if (event.LeftUp() && m_dragMode == wxSASH_DRAG_DRAGGING) - { - // We can stop dragging now and see what we've got. - m_dragMode = wxSASH_DRAG_NONE; - if (m_mouseCaptured) - ReleaseMouse(); - m_mouseCaptured = false; - - // Erase old tracker - DrawSashTracker(m_draggingEdge, m_oldX, m_oldY); - - // End drawing on top (frees the window used for drawing - // over the screen) - wxScreenDC::EndDrawingOnTop(); - - int w, h; - GetSize(&w, &h); - int xp, yp; - GetPosition(&xp, &yp); - - wxSashEdgePosition edge = m_draggingEdge; - m_draggingEdge = wxSASH_NONE; - - wxRect dragRect; - wxSashDragStatus status = wxSASH_STATUS_OK; - - // the new height and width of the window - if -1, it didn't change - int newHeight = wxDefaultCoord, - newWidth = wxDefaultCoord; - - // NB: x and y may be negative and they're relative to the sash window - // upper left corner, while xp and yp are expressed in the parent - // window system of coordinates, so adjust them! After this - // adjustment, all coordinates are relative to the parent window. - y += yp; - x += xp; - - switch (edge) - { - case wxSASH_TOP: - if ( y > yp + h ) - { - // top sash shouldn't get below the bottom one - status = wxSASH_STATUS_OUT_OF_RANGE; - } - else - { - newHeight = h - (y - yp); - } - break; - - case wxSASH_BOTTOM: - if ( y < yp ) - { - // bottom sash shouldn't get above the top one - status = wxSASH_STATUS_OUT_OF_RANGE; - } - else - { - newHeight = y - yp; - } - break; - - case wxSASH_LEFT: - if ( x > xp + w ) - { - // left sash shouldn't get beyond the right one - status = wxSASH_STATUS_OUT_OF_RANGE; - } - else - { - newWidth = w - (x - xp); - } - break; - - case wxSASH_RIGHT: - if ( x < xp ) - { - // and the right sash, finally, shouldn't be beyond the - // left one - status = wxSASH_STATUS_OUT_OF_RANGE; - } - else - { - newWidth = x - xp; - } - break; - - case wxSASH_NONE: - // can this happen at all? - break; - } - - if ( newHeight == wxDefaultCoord ) - { - // didn't change - newHeight = h; - } - else - { - // make sure it's in m_minimumPaneSizeY..m_maximumPaneSizeY range - newHeight = wxMax(newHeight, m_minimumPaneSizeY); - newHeight = wxMin(newHeight, m_maximumPaneSizeY); - } - - if ( newWidth == wxDefaultCoord ) - { - // didn't change - newWidth = w; - } - else - { - // make sure it's in m_minimumPaneSizeY..m_maximumPaneSizeY range - newWidth = wxMax(newWidth, m_minimumPaneSizeX); - newWidth = wxMin(newWidth, m_maximumPaneSizeX); - } - - dragRect = wxRect(x, y, newWidth, newHeight); - - wxSashEvent eventSash(GetId(), edge); - eventSash.SetEventObject(this); - eventSash.SetDragStatus(status); - eventSash.SetDragRect(dragRect); - GetEventHandler()->ProcessEvent(eventSash); - } - else if ( event.LeftUp() ) - { - if (m_mouseCaptured) - ReleaseMouse(); - m_mouseCaptured = false; - } - else if ((event.Moving() || event.Leaving()) && !event.Dragging()) - { - // Just change the cursor if required - if ( sashHit != wxSASH_NONE ) - { - if ( (sashHit == wxSASH_LEFT) || (sashHit == wxSASH_RIGHT) ) - { - if (m_currentCursor != m_sashCursorWE) - { - SetCursor(*m_sashCursorWE); - } - m_currentCursor = m_sashCursorWE; - } - else - { - if (m_currentCursor != m_sashCursorNS) - { - SetCursor(*m_sashCursorNS); - } - m_currentCursor = m_sashCursorNS; - } - } - else - { - SetCursor(wxNullCursor); - m_currentCursor = NULL; - } - } - else if ( event.Dragging() && - ((m_dragMode == wxSASH_DRAG_DRAGGING) || - (m_dragMode == wxSASH_DRAG_LEFT_DOWN)) ) - { - if ( (m_draggingEdge == wxSASH_LEFT) || (m_draggingEdge == wxSASH_RIGHT) ) - { - if (m_currentCursor != m_sashCursorWE) - { - SetCursor(*m_sashCursorWE); - } - m_currentCursor = m_sashCursorWE; - } - else - { - if (m_currentCursor != m_sashCursorNS) - { - SetCursor(*m_sashCursorNS); - } - m_currentCursor = m_sashCursorNS; - } - - if (m_dragMode == wxSASH_DRAG_LEFT_DOWN) - { - m_dragMode = wxSASH_DRAG_DRAGGING; - DrawSashTracker(m_draggingEdge, x, y); - } - else - { - if ( m_dragMode == wxSASH_DRAG_DRAGGING ) - { - // Erase old tracker - DrawSashTracker(m_draggingEdge, m_oldX, m_oldY); - - // Draw new one - DrawSashTracker(m_draggingEdge, x, y); - } - } - m_oldX = x; - m_oldY = y; - } - else if ( event.LeftDClick() ) - { - // Nothing - } - else - { - } -} - -void wxSashWindow::OnSize(wxSizeEvent& WXUNUSED(event)) -{ - SizeWindows(); -} - -wxSashEdgePosition wxSashWindow::SashHitTest(int x, int y, int WXUNUSED(tolerance)) -{ - int cx, cy; - GetClientSize(& cx, & cy); - - int i; - for (i = 0; i < 4; i++) - { - wxSashEdge& edge = m_sashes[i]; - wxSashEdgePosition position = (wxSashEdgePosition) i ; - - if (edge.m_show) - { - switch (position) - { - case wxSASH_TOP: - { - if (y >= 0 && y <= GetEdgeMargin(position)) - return wxSASH_TOP; - break; - } - case wxSASH_RIGHT: - { - if ((x >= cx - GetEdgeMargin(position)) && (x <= cx)) - return wxSASH_RIGHT; - break; - } - case wxSASH_BOTTOM: - { - if ((y >= cy - GetEdgeMargin(position)) && (y <= cy)) - return wxSASH_BOTTOM; - break; - } - case wxSASH_LEFT: - { - if ((x <= GetEdgeMargin(position)) && (x >= 0)) - return wxSASH_LEFT; - break; - } - case wxSASH_NONE: - { - break; - } - } - } - } - return wxSASH_NONE; -} - -// Draw 3D effect borders -void wxSashWindow::DrawBorders(wxDC& dc) -{ - int w, h; - GetClientSize(&w, &h); - - wxPen mediumShadowPen(m_mediumShadowColour, 1, wxSOLID); - wxPen darkShadowPen(m_darkShadowColour, 1, wxSOLID); - wxPen lightShadowPen(m_lightShadowColour, 1, wxSOLID); - wxPen hilightPen(m_hilightColour, 1, wxSOLID); - - if ( GetWindowStyleFlag() & wxSW_3DBORDER ) - { - dc.SetPen(mediumShadowPen); - dc.DrawLine(0, 0, w-1, 0); - dc.DrawLine(0, 0, 0, h - 1); - - dc.SetPen(darkShadowPen); - dc.DrawLine(1, 1, w-2, 1); - dc.DrawLine(1, 1, 1, h-2); - - dc.SetPen(hilightPen); - dc.DrawLine(0, h-1, w-1, h-1); - dc.DrawLine(w-1, 0, w-1, h); // Surely the maximum y pos. should be h - 1. - /// Anyway, h is required for MSW. - - dc.SetPen(lightShadowPen); - dc.DrawLine(w-2, 1, w-2, h-2); // Right hand side - dc.DrawLine(1, h-2, w-1, h-2); // Bottom - } - else if ( GetWindowStyleFlag() & wxSW_BORDER ) - { - dc.SetBrush(*wxTRANSPARENT_BRUSH); - dc.SetPen(*wxBLACK_PEN); - dc.DrawRectangle(0, 0, w-1, h-1); - } - - dc.SetPen(wxNullPen); - dc.SetBrush(wxNullBrush); -} - -void wxSashWindow::DrawSashes(wxDC& dc) -{ - int i; - for (i = 0; i < 4; i++) - if (m_sashes[i].m_show) - DrawSash((wxSashEdgePosition) i, dc); -} - -// Draw the sash -void wxSashWindow::DrawSash(wxSashEdgePosition edge, wxDC& dc) -{ - int w, h; - GetClientSize(&w, &h); - - wxPen facePen(m_faceColour, 1, wxSOLID); - wxBrush faceBrush(m_faceColour, wxSOLID); - wxPen mediumShadowPen(m_mediumShadowColour, 1, wxSOLID); - wxPen darkShadowPen(m_darkShadowColour, 1, wxSOLID); - wxPen lightShadowPen(m_lightShadowColour, 1, wxSOLID); - wxPen hilightPen(m_hilightColour, 1, wxSOLID); - wxColour blackClr(0, 0, 0); - wxColour whiteClr(255, 255, 255); - wxPen blackPen(blackClr, 1, wxSOLID); - wxPen whitePen(whiteClr, 1, wxSOLID); - - if ( edge == wxSASH_LEFT || edge == wxSASH_RIGHT ) - { - int sashPosition = (edge == wxSASH_LEFT) ? 0 : ( w - GetEdgeMargin(edge) ); - - dc.SetPen(facePen); - dc.SetBrush(faceBrush); - dc.DrawRectangle(sashPosition, 0, GetEdgeMargin(edge), h); - - if (GetWindowStyleFlag() & wxSW_3DSASH) - { - if (edge == wxSASH_LEFT) - { - // Draw a dark grey line on the left to indicate that the - // sash is raised - dc.SetPen(mediumShadowPen); - dc.DrawLine(GetEdgeMargin(edge), 0, GetEdgeMargin(edge), h); - } - else - { - // Draw a highlight line on the right to indicate that the - // sash is raised - dc.SetPen(hilightPen); - dc.DrawLine(w - GetEdgeMargin(edge), 0, w - GetEdgeMargin(edge), h); - } - } - } - else // top or bottom - { - int sashPosition = (edge == wxSASH_TOP) ? 0 : ( h - GetEdgeMargin(edge) ); - - dc.SetPen(facePen); - dc.SetBrush(faceBrush); - dc.DrawRectangle(0, sashPosition, w, GetEdgeMargin(edge)); - - if (GetWindowStyleFlag() & wxSW_3DSASH) - { - if (edge == wxSASH_BOTTOM) - { - // Draw a highlight line on the bottom to indicate that the - // sash is raised - dc.SetPen(hilightPen); - dc.DrawLine(0, h - GetEdgeMargin(edge), w, h - GetEdgeMargin(edge)); - } - else - { - // Draw a drak grey line on the top to indicate that the - // sash is raised - dc.SetPen(mediumShadowPen); - dc.DrawLine(1, GetEdgeMargin(edge), w-1, GetEdgeMargin(edge)); - } - } - } - - dc.SetPen(wxNullPen); - dc.SetBrush(wxNullBrush); -} - -// Draw the sash tracker (for whilst moving the sash) -void wxSashWindow::DrawSashTracker(wxSashEdgePosition edge, int x, int y) -{ - int w, h; - GetClientSize(&w, &h); - - wxScreenDC screenDC; - int x1, y1; - int x2, y2; - - if ( edge == wxSASH_LEFT || edge == wxSASH_RIGHT ) - { - x1 = x; y1 = 2; - x2 = x; y2 = h-2; - - if ( (edge == wxSASH_LEFT) && (x1 > w) ) - { - x1 = w; x2 = w; - } - else if ( (edge == wxSASH_RIGHT) && (x1 < 0) ) - { - x1 = 0; x2 = 0; - } - } - else - { - x1 = 2; y1 = y; - x2 = w-2; y2 = y; - - if ( (edge == wxSASH_TOP) && (y1 > h) ) - { - y1 = h; - y2 = h; - } - else if ( (edge == wxSASH_BOTTOM) && (y1 < 0) ) - { - y1 = 0; - y2 = 0; - } - } - - ClientToScreen(&x1, &y1); - ClientToScreen(&x2, &y2); - - wxPen sashTrackerPen(*wxBLACK, 2, wxSOLID); - - screenDC.SetLogicalFunction(wxINVERT); - screenDC.SetPen(sashTrackerPen); - screenDC.SetBrush(*wxTRANSPARENT_BRUSH); - - screenDC.DrawLine(x1, y1, x2, y2); - - screenDC.SetLogicalFunction(wxCOPY); - - screenDC.SetPen(wxNullPen); - screenDC.SetBrush(wxNullBrush); -} - -// Position and size subwindows. -// Note that the border size applies to each subwindow, not -// including the edges next to the sash. -void wxSashWindow::SizeWindows() -{ - int cw, ch; - GetClientSize(&cw, &ch); - - if (GetChildren().GetCount() == 1) - { - wxWindow* child = GetChildren().GetFirst()->GetData(); - - int x = 0; - int y = 0; - int width = cw; - int height = ch; - - // Top - if (m_sashes[0].m_show) - { - y = m_borderSize; - height -= m_borderSize; - } - y += m_extraBorderSize; - - // Left - if (m_sashes[3].m_show) - { - x = m_borderSize; - width -= m_borderSize; - } - x += m_extraBorderSize; - - // Right - if (m_sashes[1].m_show) - { - width -= m_borderSize; - } - width -= 2*m_extraBorderSize; - - // Bottom - if (m_sashes[2].m_show) - { - height -= m_borderSize; - } - height -= 2*m_extraBorderSize; - - child->SetSize(x, y, width, height); - } - else if (GetChildren().GetCount() > 1) - { - // Perhaps multiple children are themselves sash windows. - // TODO: this doesn't really work because the subwindows sizes/positions - // must be set to leave a gap for the parent's sash (hit-test and decorations). - // Perhaps we can allow for this within LayoutWindow, testing whether the parent - // is a sash window, and if so, allowing some space for the edges. - wxLayoutAlgorithm layout; - layout.LayoutWindow(this); - } - - wxClientDC dc(this); - DrawBorders(dc); - DrawSashes(dc); -} - -// Initialize colours -void wxSashWindow::InitColours() -{ - // Shadow colours - m_faceColour = wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE); - m_mediumShadowColour = wxSystemSettings::GetColour(wxSYS_COLOUR_3DSHADOW); - m_darkShadowColour = wxSystemSettings::GetColour(wxSYS_COLOUR_3DDKSHADOW); - m_lightShadowColour = wxSystemSettings::GetColour(wxSYS_COLOUR_3DLIGHT); - m_hilightColour = wxSystemSettings::GetColour(wxSYS_COLOUR_3DHILIGHT); -} - -void wxSashWindow::SetSashVisible(wxSashEdgePosition edge, bool sash) -{ - m_sashes[edge].m_show = sash; - if (sash) - m_sashes[edge].m_margin = m_borderSize; - else - m_sashes[edge].m_margin = 0; -} - -#if defined( __WXMSW__ ) || defined( __WXMAC__) - -// this is currently called (and needed) under MSW only... -void wxSashWindow::OnSetCursor(wxSetCursorEvent& event) -{ - // if we don't do it, the resizing cursor might be set for child window: - // and like this we explicitly say that our cursor should not be used for - // children windows which overlap us - - if ( SashHitTest(event.GetX(), event.GetY()) != wxSASH_NONE) - { - // default processing is ok - event.Skip(); - } - //else: do nothing, in particular, don't call Skip() -} - -#endif // __WXMSW__ || __WXMAC__ - -#endif // wxUSE_SASH +///////////////////////////////////////////////////////////////////////////// +// Name: src/generic/sashwin.cpp +// Purpose: wxSashWindow implementation. A sash window has an optional +// sash on each edge, allowing it to be dragged. An event +// is generated when the sash is released. +// Author: Julian Smart +// Modified by: +// Created: 01/02/97 +// RCS-ID: $Id: sashwin.cpp 51249 2008-01-16 13:50:23Z JS $ +// Copyright: (c) Julian Smart +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_SASH + +#include "wx/sashwin.h" + +#ifndef WX_PRECOMP + #include "wx/dialog.h" + #include "wx/frame.h" + #include "wx/settings.h" + #include "wx/dcclient.h" + #include "wx/dcscreen.h" + #include "wx/math.h" +#endif + +#include + +#include "wx/laywin.h" + +DEFINE_EVENT_TYPE(wxEVT_SASH_DRAGGED) + +IMPLEMENT_DYNAMIC_CLASS(wxSashWindow, wxWindow) +IMPLEMENT_DYNAMIC_CLASS(wxSashEvent, wxCommandEvent) + +BEGIN_EVENT_TABLE(wxSashWindow, wxWindow) + EVT_PAINT(wxSashWindow::OnPaint) + EVT_SIZE(wxSashWindow::OnSize) + EVT_MOUSE_EVENTS(wxSashWindow::OnMouseEvent) +#if defined( __WXMSW__ ) || defined( __WXMAC__) + EVT_SET_CURSOR(wxSashWindow::OnSetCursor) +#endif // __WXMSW__ || __WXMAC__ + +END_EVENT_TABLE() + +bool wxSashWindow::Create(wxWindow *parent, wxWindowID id, const wxPoint& pos, + const wxSize& size, long style, const wxString& name) +{ + return wxWindow::Create(parent, id, pos, size, style, name); +} + +wxSashWindow::~wxSashWindow() +{ + delete m_sashCursorWE; + delete m_sashCursorNS; +} + +void wxSashWindow::Init() +{ + m_draggingEdge = wxSASH_NONE; + m_dragMode = wxSASH_DRAG_NONE; + m_oldX = 0; + m_oldY = 0; + m_firstX = 0; + m_firstY = 0; + m_borderSize = 3; + m_extraBorderSize = 0; + m_minimumPaneSizeX = 0; + m_minimumPaneSizeY = 0; + m_maximumPaneSizeX = 10000; + m_maximumPaneSizeY = 10000; + m_sashCursorWE = new wxCursor(wxCURSOR_SIZEWE); + m_sashCursorNS = new wxCursor(wxCURSOR_SIZENS); + m_mouseCaptured = false; + m_currentCursor = NULL; + + // Eventually, we'll respond to colour change messages + InitColours(); +} + +void wxSashWindow::OnPaint(wxPaintEvent& WXUNUSED(event)) +{ + wxPaintDC dc(this); + + DrawBorders(dc); + DrawSashes(dc); +} + +void wxSashWindow::OnMouseEvent(wxMouseEvent& event) +{ + wxCoord x = 0, y = 0; + event.GetPosition(&x, &y); + + wxSashEdgePosition sashHit = SashHitTest(x, y); + + if (event.LeftDown()) + { + CaptureMouse(); + m_mouseCaptured = true; + + if ( sashHit != wxSASH_NONE ) + { + // Required for X to specify that + // that we wish to draw on top of all windows + // - and we optimise by specifying the area + // for creating the overlap window. + // Find the first frame or dialog and use this to specify + // the area to draw on. + wxWindow* parent = this; + + while (parent && !parent->IsKindOf(CLASSINFO(wxDialog)) && + !parent->IsKindOf(CLASSINFO(wxFrame))) + parent = parent->GetParent(); + + wxScreenDC::StartDrawingOnTop(parent); + + // We don't say we're dragging yet; we leave that + // decision for the Dragging() branch, to ensure + // the user has dragged a little bit. + m_dragMode = wxSASH_DRAG_LEFT_DOWN; + m_draggingEdge = sashHit; + m_firstX = x; + m_firstY = y; + + if ( (sashHit == wxSASH_LEFT) || (sashHit == wxSASH_RIGHT) ) + { + if (m_currentCursor != m_sashCursorWE) + { + SetCursor(*m_sashCursorWE); + } + m_currentCursor = m_sashCursorWE; + } + else + { + if (m_currentCursor != m_sashCursorNS) + { + SetCursor(*m_sashCursorNS); + } + m_currentCursor = m_sashCursorNS; + } + } + } + else if ( event.LeftUp() && m_dragMode == wxSASH_DRAG_LEFT_DOWN ) + { + // Wasn't a proper drag + if (m_mouseCaptured) + ReleaseMouse(); + m_mouseCaptured = false; + + wxScreenDC::EndDrawingOnTop(); + m_dragMode = wxSASH_DRAG_NONE; + m_draggingEdge = wxSASH_NONE; + } + else if (event.LeftUp() && m_dragMode == wxSASH_DRAG_DRAGGING) + { + // We can stop dragging now and see what we've got. + m_dragMode = wxSASH_DRAG_NONE; + if (m_mouseCaptured) + ReleaseMouse(); + m_mouseCaptured = false; + + // Erase old tracker + DrawSashTracker(m_draggingEdge, m_oldX, m_oldY); + + // End drawing on top (frees the window used for drawing + // over the screen) + wxScreenDC::EndDrawingOnTop(); + + int w, h; + GetSize(&w, &h); + int xp, yp; + GetPosition(&xp, &yp); + + wxSashEdgePosition edge = m_draggingEdge; + m_draggingEdge = wxSASH_NONE; + + wxRect dragRect; + wxSashDragStatus status = wxSASH_STATUS_OK; + + // the new height and width of the window - if -1, it didn't change + int newHeight = wxDefaultCoord, + newWidth = wxDefaultCoord; + + // NB: x and y may be negative and they're relative to the sash window + // upper left corner, while xp and yp are expressed in the parent + // window system of coordinates, so adjust them! After this + // adjustment, all coordinates are relative to the parent window. + y += yp; + x += xp; + + switch (edge) + { + case wxSASH_TOP: + if ( y > yp + h ) + { + // top sash shouldn't get below the bottom one + status = wxSASH_STATUS_OUT_OF_RANGE; + } + else + { + newHeight = h - (y - yp); + } + break; + + case wxSASH_BOTTOM: + if ( y < yp ) + { + // bottom sash shouldn't get above the top one + status = wxSASH_STATUS_OUT_OF_RANGE; + } + else + { + newHeight = y - yp; + } + break; + + case wxSASH_LEFT: + if ( x > xp + w ) + { + // left sash shouldn't get beyond the right one + status = wxSASH_STATUS_OUT_OF_RANGE; + } + else + { + newWidth = w - (x - xp); + } + break; + + case wxSASH_RIGHT: + if ( x < xp ) + { + // and the right sash, finally, shouldn't be beyond the + // left one + status = wxSASH_STATUS_OUT_OF_RANGE; + } + else + { + newWidth = x - xp; + } + break; + + case wxSASH_NONE: + // can this happen at all? + break; + } + + if ( newHeight == wxDefaultCoord ) + { + // didn't change + newHeight = h; + } + else + { + // make sure it's in m_minimumPaneSizeY..m_maximumPaneSizeY range + newHeight = wxMax(newHeight, m_minimumPaneSizeY); + newHeight = wxMin(newHeight, m_maximumPaneSizeY); + } + + if ( newWidth == wxDefaultCoord ) + { + // didn't change + newWidth = w; + } + else + { + // make sure it's in m_minimumPaneSizeY..m_maximumPaneSizeY range + newWidth = wxMax(newWidth, m_minimumPaneSizeX); + newWidth = wxMin(newWidth, m_maximumPaneSizeX); + } + + dragRect = wxRect(x, y, newWidth, newHeight); + + wxSashEvent eventSash(GetId(), edge); + eventSash.SetEventObject(this); + eventSash.SetDragStatus(status); + eventSash.SetDragRect(dragRect); + GetEventHandler()->ProcessEvent(eventSash); + } + else if ( event.LeftUp() ) + { + if (m_mouseCaptured) + ReleaseMouse(); + m_mouseCaptured = false; + } + else if ((event.Moving() || event.Leaving()) && !event.Dragging()) + { + // Just change the cursor if required + if ( sashHit != wxSASH_NONE ) + { + if ( (sashHit == wxSASH_LEFT) || (sashHit == wxSASH_RIGHT) ) + { + if (m_currentCursor != m_sashCursorWE) + { + SetCursor(*m_sashCursorWE); + } + m_currentCursor = m_sashCursorWE; + } + else + { + if (m_currentCursor != m_sashCursorNS) + { + SetCursor(*m_sashCursorNS); + } + m_currentCursor = m_sashCursorNS; + } + } + else + { + SetCursor(wxNullCursor); + m_currentCursor = NULL; + } + } + else if ( event.Dragging() && + ((m_dragMode == wxSASH_DRAG_DRAGGING) || + (m_dragMode == wxSASH_DRAG_LEFT_DOWN)) ) + { + if ( (m_draggingEdge == wxSASH_LEFT) || (m_draggingEdge == wxSASH_RIGHT) ) + { + if (m_currentCursor != m_sashCursorWE) + { + SetCursor(*m_sashCursorWE); + } + m_currentCursor = m_sashCursorWE; + } + else + { + if (m_currentCursor != m_sashCursorNS) + { + SetCursor(*m_sashCursorNS); + } + m_currentCursor = m_sashCursorNS; + } + + if (m_dragMode == wxSASH_DRAG_LEFT_DOWN) + { + m_dragMode = wxSASH_DRAG_DRAGGING; + DrawSashTracker(m_draggingEdge, x, y); + } + else + { + if ( m_dragMode == wxSASH_DRAG_DRAGGING ) + { + // Erase old tracker + DrawSashTracker(m_draggingEdge, m_oldX, m_oldY); + + // Draw new one + DrawSashTracker(m_draggingEdge, x, y); + } + } + m_oldX = x; + m_oldY = y; + } + else if ( event.LeftDClick() ) + { + // Nothing + } + else + { + } +} + +void wxSashWindow::OnSize(wxSizeEvent& WXUNUSED(event)) +{ + SizeWindows(); +} + +wxSashEdgePosition wxSashWindow::SashHitTest(int x, int y, int WXUNUSED(tolerance)) +{ + int cx, cy; + GetClientSize(& cx, & cy); + + int i; + for (i = 0; i < 4; i++) + { + wxSashEdge& edge = m_sashes[i]; + wxSashEdgePosition position = (wxSashEdgePosition) i ; + + if (edge.m_show) + { + switch (position) + { + case wxSASH_TOP: + { + if (y >= 0 && y <= GetEdgeMargin(position)) + return wxSASH_TOP; + break; + } + case wxSASH_RIGHT: + { + if ((x >= cx - GetEdgeMargin(position)) && (x <= cx)) + return wxSASH_RIGHT; + break; + } + case wxSASH_BOTTOM: + { + if ((y >= cy - GetEdgeMargin(position)) && (y <= cy)) + return wxSASH_BOTTOM; + break; + } + case wxSASH_LEFT: + { + if ((x <= GetEdgeMargin(position)) && (x >= 0)) + return wxSASH_LEFT; + break; + } + case wxSASH_NONE: + { + break; + } + } + } + } + return wxSASH_NONE; +} + +// Draw 3D effect borders +void wxSashWindow::DrawBorders(wxDC& dc) +{ + int w, h; + GetClientSize(&w, &h); + + wxPen mediumShadowPen(m_mediumShadowColour, 1, wxSOLID); + wxPen darkShadowPen(m_darkShadowColour, 1, wxSOLID); + wxPen lightShadowPen(m_lightShadowColour, 1, wxSOLID); + wxPen hilightPen(m_hilightColour, 1, wxSOLID); + + if ( GetWindowStyleFlag() & wxSW_3DBORDER ) + { + dc.SetPen(mediumShadowPen); + dc.DrawLine(0, 0, w-1, 0); + dc.DrawLine(0, 0, 0, h - 1); + + dc.SetPen(darkShadowPen); + dc.DrawLine(1, 1, w-2, 1); + dc.DrawLine(1, 1, 1, h-2); + + dc.SetPen(hilightPen); + dc.DrawLine(0, h-1, w-1, h-1); + dc.DrawLine(w-1, 0, w-1, h); // Surely the maximum y pos. should be h - 1. + /// Anyway, h is required for MSW. + + dc.SetPen(lightShadowPen); + dc.DrawLine(w-2, 1, w-2, h-2); // Right hand side + dc.DrawLine(1, h-2, w-1, h-2); // Bottom + } + else if ( GetWindowStyleFlag() & wxSW_BORDER ) + { + dc.SetBrush(*wxTRANSPARENT_BRUSH); + dc.SetPen(*wxBLACK_PEN); + dc.DrawRectangle(0, 0, w-1, h-1); + } + + dc.SetPen(wxNullPen); + dc.SetBrush(wxNullBrush); +} + +void wxSashWindow::DrawSashes(wxDC& dc) +{ + int i; + for (i = 0; i < 4; i++) + if (m_sashes[i].m_show) + DrawSash((wxSashEdgePosition) i, dc); +} + +// Draw the sash +void wxSashWindow::DrawSash(wxSashEdgePosition edge, wxDC& dc) +{ + int w, h; + GetClientSize(&w, &h); + + wxPen facePen(m_faceColour, 1, wxSOLID); + wxBrush faceBrush(m_faceColour, wxSOLID); + wxPen mediumShadowPen(m_mediumShadowColour, 1, wxSOLID); + wxPen darkShadowPen(m_darkShadowColour, 1, wxSOLID); + wxPen lightShadowPen(m_lightShadowColour, 1, wxSOLID); + wxPen hilightPen(m_hilightColour, 1, wxSOLID); + wxColour blackClr(0, 0, 0); + wxColour whiteClr(255, 255, 255); + wxPen blackPen(blackClr, 1, wxSOLID); + wxPen whitePen(whiteClr, 1, wxSOLID); + + if ( edge == wxSASH_LEFT || edge == wxSASH_RIGHT ) + { + int sashPosition = (edge == wxSASH_LEFT) ? 0 : ( w - GetEdgeMargin(edge) ); + + dc.SetPen(facePen); + dc.SetBrush(faceBrush); + dc.DrawRectangle(sashPosition, 0, GetEdgeMargin(edge), h); + + if (GetWindowStyleFlag() & wxSW_3DSASH) + { + if (edge == wxSASH_LEFT) + { + // Draw a dark grey line on the left to indicate that the + // sash is raised + dc.SetPen(mediumShadowPen); + dc.DrawLine(GetEdgeMargin(edge), 0, GetEdgeMargin(edge), h); + } + else + { + // Draw a highlight line on the right to indicate that the + // sash is raised + dc.SetPen(hilightPen); + dc.DrawLine(w - GetEdgeMargin(edge), 0, w - GetEdgeMargin(edge), h); + } + } + } + else // top or bottom + { + int sashPosition = (edge == wxSASH_TOP) ? 0 : ( h - GetEdgeMargin(edge) ); + + dc.SetPen(facePen); + dc.SetBrush(faceBrush); + dc.DrawRectangle(0, sashPosition, w, GetEdgeMargin(edge)); + + if (GetWindowStyleFlag() & wxSW_3DSASH) + { + if (edge == wxSASH_BOTTOM) + { + // Draw a highlight line on the bottom to indicate that the + // sash is raised + dc.SetPen(hilightPen); + dc.DrawLine(0, h - GetEdgeMargin(edge), w, h - GetEdgeMargin(edge)); + } + else + { + // Draw a drak grey line on the top to indicate that the + // sash is raised + dc.SetPen(mediumShadowPen); + dc.DrawLine(1, GetEdgeMargin(edge), w-1, GetEdgeMargin(edge)); + } + } + } + + dc.SetPen(wxNullPen); + dc.SetBrush(wxNullBrush); +} + +// Draw the sash tracker (for whilst moving the sash) +void wxSashWindow::DrawSashTracker(wxSashEdgePosition edge, int x, int y) +{ + int w, h; + GetClientSize(&w, &h); + + wxScreenDC screenDC; + int x1, y1; + int x2, y2; + + if ( edge == wxSASH_LEFT || edge == wxSASH_RIGHT ) + { + x1 = x; y1 = 2; + x2 = x; y2 = h-2; + + if ( (edge == wxSASH_LEFT) && (x1 > w) ) + { + x1 = w; x2 = w; + } + else if ( (edge == wxSASH_RIGHT) && (x1 < 0) ) + { + x1 = 0; x2 = 0; + } + } + else + { + x1 = 2; y1 = y; + x2 = w-2; y2 = y; + + if ( (edge == wxSASH_TOP) && (y1 > h) ) + { + y1 = h; + y2 = h; + } + else if ( (edge == wxSASH_BOTTOM) && (y1 < 0) ) + { + y1 = 0; + y2 = 0; + } + } + + ClientToScreen(&x1, &y1); + ClientToScreen(&x2, &y2); + + wxPen sashTrackerPen(*wxBLACK, 2, wxSOLID); + + screenDC.SetLogicalFunction(wxINVERT); + screenDC.SetPen(sashTrackerPen); + screenDC.SetBrush(*wxTRANSPARENT_BRUSH); + + screenDC.DrawLine(x1, y1, x2, y2); + + screenDC.SetLogicalFunction(wxCOPY); + + screenDC.SetPen(wxNullPen); + screenDC.SetBrush(wxNullBrush); +} + +// Position and size subwindows. +// Note that the border size applies to each subwindow, not +// including the edges next to the sash. +void wxSashWindow::SizeWindows() +{ + int cw, ch; + GetClientSize(&cw, &ch); + + if (GetChildren().GetCount() == 1) + { + wxWindow* child = GetChildren().GetFirst()->GetData(); + + int x = 0; + int y = 0; + int width = cw; + int height = ch; + + // Top + if (m_sashes[0].m_show) + { + y = m_borderSize; + height -= m_borderSize; + } + y += m_extraBorderSize; + + // Left + if (m_sashes[3].m_show) + { + x = m_borderSize; + width -= m_borderSize; + } + x += m_extraBorderSize; + + // Right + if (m_sashes[1].m_show) + { + width -= m_borderSize; + } + width -= 2*m_extraBorderSize; + + // Bottom + if (m_sashes[2].m_show) + { + height -= m_borderSize; + } + height -= 2*m_extraBorderSize; + + child->SetSize(x, y, width, height); + } + else if (GetChildren().GetCount() > 1) + { + // Perhaps multiple children are themselves sash windows. + // TODO: this doesn't really work because the subwindows sizes/positions + // must be set to leave a gap for the parent's sash (hit-test and decorations). + // Perhaps we can allow for this within LayoutWindow, testing whether the parent + // is a sash window, and if so, allowing some space for the edges. + wxLayoutAlgorithm layout; + layout.LayoutWindow(this); + } + + wxClientDC dc(this); + DrawBorders(dc); + DrawSashes(dc); +} + +// Initialize colours +void wxSashWindow::InitColours() +{ + // Shadow colours + m_faceColour = wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE); + m_mediumShadowColour = wxSystemSettings::GetColour(wxSYS_COLOUR_3DSHADOW); + m_darkShadowColour = wxSystemSettings::GetColour(wxSYS_COLOUR_3DDKSHADOW); + m_lightShadowColour = wxSystemSettings::GetColour(wxSYS_COLOUR_3DLIGHT); + m_hilightColour = wxSystemSettings::GetColour(wxSYS_COLOUR_3DHILIGHT); +} + +void wxSashWindow::SetSashVisible(wxSashEdgePosition edge, bool sash) +{ + m_sashes[edge].m_show = sash; + if (sash) + m_sashes[edge].m_margin = m_borderSize; + else + m_sashes[edge].m_margin = 0; +} + +#if defined( __WXMSW__ ) || defined( __WXMAC__) + +// this is currently called (and needed) under MSW only... +void wxSashWindow::OnSetCursor(wxSetCursorEvent& event) +{ + // if we don't do it, the resizing cursor might be set for child window: + // and like this we explicitly say that our cursor should not be used for + // children windows which overlap us + + if ( SashHitTest(event.GetX(), event.GetY()) != wxSASH_NONE) + { + // default processing is ok + event.Skip(); + } + //else: do nothing, in particular, don't call Skip() +} + +#endif // __WXMSW__ || __WXMAC__ + +#endif // wxUSE_SASH diff --git a/Externals/wxWidgets/src/generic/scrlwing.cpp b/Externals/wxWidgets/src/generic/scrlwing.cpp index 7b3c578820..6a28931334 100644 --- a/Externals/wxWidgets/src/generic/scrlwing.cpp +++ b/Externals/wxWidgets/src/generic/scrlwing.cpp @@ -1,1475 +1,1475 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/generic/scrlwing.cpp -// Purpose: wxScrolledWindow implementation -// Author: Julian Smart -// Modified by: Vadim Zeitlin on 31.08.00: wxScrollHelper allows to implement. -// Ron Lee on 10.4.02: virtual size / auto scrollbars et al. -// Created: 01/02/97 -// RCS-ID: $Id: scrlwing.cpp 50982 2008-01-01 20:38:33Z VZ $ -// Copyright: (c) wxWidgets team -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#include "wx/scrolwin.h" - -#ifndef WX_PRECOMP - #include "wx/utils.h" - #include "wx/panel.h" - #include "wx/dcclient.h" - #if wxUSE_TIMER - #include "wx/timer.h" - #endif - #include "wx/sizer.h" - #include "wx/settings.h" -#endif - -#ifdef __WXMAC__ -#include "wx/scrolbar.h" -#endif - -#include "wx/recguard.h" - -#ifdef __WXMSW__ - #include // for DLGC_WANTARROWS - #include "wx/msw/winundef.h" -#endif - -#ifdef __WXMOTIF__ -// For wxRETAINED implementation -#ifdef __VMS__ //VMS's Xm.h is not (yet) compatible with C++ - //This code switches off the compiler warnings -# pragma message disable nosimpint -#endif -#include -#ifdef __VMS__ -# pragma message enable nosimpint -#endif -#endif - -/* - TODO PROPERTIES - style wxHSCROLL | wxVSCROLL -*/ - -// ---------------------------------------------------------------------------- -// wxScrollHelperEvtHandler: intercept the events from the window and forward -// them to wxScrollHelper -// ---------------------------------------------------------------------------- - -class WXDLLEXPORT wxScrollHelperEvtHandler : public wxEvtHandler -{ -public: - wxScrollHelperEvtHandler(wxScrollHelper *scrollHelper) - { - m_scrollHelper = scrollHelper; - } - - virtual bool ProcessEvent(wxEvent& event); - - void ResetDrawnFlag() { m_hasDrawnWindow = false; } - -private: - wxScrollHelper *m_scrollHelper; - - bool m_hasDrawnWindow; - - DECLARE_NO_COPY_CLASS(wxScrollHelperEvtHandler) -}; - -#if wxUSE_TIMER -// ---------------------------------------------------------------------------- -// wxAutoScrollTimer: the timer used to generate a stream of scroll events when -// a captured mouse is held outside the window -// ---------------------------------------------------------------------------- - -class wxAutoScrollTimer : public wxTimer -{ -public: - wxAutoScrollTimer(wxWindow *winToScroll, wxScrollHelper *scroll, - wxEventType eventTypeToSend, - int pos, int orient); - - virtual void Notify(); - -private: - wxWindow *m_win; - wxScrollHelper *m_scrollHelper; - wxEventType m_eventType; - int m_pos, - m_orient; - - DECLARE_NO_COPY_CLASS(wxAutoScrollTimer) -}; - -// ============================================================================ -// implementation -// ============================================================================ - -// ---------------------------------------------------------------------------- -// wxAutoScrollTimer -// ---------------------------------------------------------------------------- - -wxAutoScrollTimer::wxAutoScrollTimer(wxWindow *winToScroll, - wxScrollHelper *scroll, - wxEventType eventTypeToSend, - int pos, int orient) -{ - m_win = winToScroll; - m_scrollHelper = scroll; - m_eventType = eventTypeToSend; - m_pos = pos; - m_orient = orient; -} - -void wxAutoScrollTimer::Notify() -{ - // only do all this as long as the window is capturing the mouse - if ( wxWindow::GetCapture() != m_win ) - { - Stop(); - } - else // we still capture the mouse, continue generating events - { - // first scroll the window if we are allowed to do it - wxScrollWinEvent event1(m_eventType, m_pos, m_orient); - event1.SetEventObject(m_win); - if ( m_scrollHelper->SendAutoScrollEvents(event1) && - m_win->GetEventHandler()->ProcessEvent(event1) ) - { - // and then send a pseudo mouse-move event to refresh the selection - wxMouseEvent event2(wxEVT_MOTION); - wxGetMousePosition(&event2.m_x, &event2.m_y); - - // the mouse event coordinates should be client, not screen as - // returned by wxGetMousePosition - wxWindow *parentTop = m_win; - while ( parentTop->GetParent() ) - parentTop = parentTop->GetParent(); - wxPoint ptOrig = parentTop->GetPosition(); - event2.m_x -= ptOrig.x; - event2.m_y -= ptOrig.y; - - event2.SetEventObject(m_win); - - // FIXME: we don't fill in the other members - ok? - - m_win->GetEventHandler()->ProcessEvent(event2); - } - else // can't scroll further, stop - { - Stop(); - } - } -} -#endif - -// ---------------------------------------------------------------------------- -// wxScrollHelperEvtHandler -// ---------------------------------------------------------------------------- - -bool wxScrollHelperEvtHandler::ProcessEvent(wxEvent& event) -{ - wxEventType evType = event.GetEventType(); - - // the explanation of wxEVT_PAINT processing hack: for historic reasons - // there are 2 ways to process this event in classes deriving from - // wxScrolledWindow. The user code may - // - // 1. override wxScrolledWindow::OnDraw(dc) - // 2. define its own OnPaint() handler - // - // In addition, in wxUniversal wxWindow defines OnPaint() itself and - // always processes the draw event, so we can't just try the window - // OnPaint() first and call our HandleOnPaint() if it doesn't process it - // (the latter would never be called in wxUniversal). - // - // So the solution is to have a flag telling us whether the user code drew - // anything in the window. We set it to true here but reset it to false in - // wxScrolledWindow::OnPaint() handler (which wouldn't be called if the - // user code defined OnPaint() in the derived class) - m_hasDrawnWindow = true; - - // pass it on to the real handler - bool processed = wxEvtHandler::ProcessEvent(event); - - // always process the size events ourselves, even if the user code handles - // them as well, as we need to AdjustScrollbars() - // - // NB: it is important to do it after processing the event in the normal - // way as HandleOnSize() may generate a wxEVT_SIZE itself if the - // scrollbar[s] (dis)appear and it should be seen by the user code - // after this one - if ( evType == wxEVT_SIZE ) - { - m_scrollHelper->HandleOnSize((wxSizeEvent &)event); - - return true; - } - - if ( processed ) - { - // normally, nothing more to do here - except if it was a paint event - // which wasn't really processed, then we'll try to call our - // OnDraw() below (from HandleOnPaint) - if ( m_hasDrawnWindow || event.IsCommandEvent() ) - { - return true; - } - } - - // reset the skipped flag to false as it might have been set to true in - // ProcessEvent() above - event.Skip(false); - - if ( evType == wxEVT_PAINT ) - { - m_scrollHelper->HandleOnPaint((wxPaintEvent &)event); - return true; - } - - if ( evType == wxEVT_CHILD_FOCUS ) - { - m_scrollHelper->HandleOnChildFocus((wxChildFocusEvent &)event); - return true; - } - - if ( evType == wxEVT_SCROLLWIN_TOP || - evType == wxEVT_SCROLLWIN_BOTTOM || - evType == wxEVT_SCROLLWIN_LINEUP || - evType == wxEVT_SCROLLWIN_LINEDOWN || - evType == wxEVT_SCROLLWIN_PAGEUP || - evType == wxEVT_SCROLLWIN_PAGEDOWN || - evType == wxEVT_SCROLLWIN_THUMBTRACK || - evType == wxEVT_SCROLLWIN_THUMBRELEASE ) - { - m_scrollHelper->HandleOnScroll((wxScrollWinEvent &)event); - return !event.GetSkipped(); - } - - if ( evType == wxEVT_ENTER_WINDOW ) - { - m_scrollHelper->HandleOnMouseEnter((wxMouseEvent &)event); - } - else if ( evType == wxEVT_LEAVE_WINDOW ) - { - m_scrollHelper->HandleOnMouseLeave((wxMouseEvent &)event); - } -#if wxUSE_MOUSEWHEEL - else if ( evType == wxEVT_MOUSEWHEEL ) - { - m_scrollHelper->HandleOnMouseWheel((wxMouseEvent &)event); - return true; - } -#endif // wxUSE_MOUSEWHEEL - else if ( evType == wxEVT_CHAR ) - { - m_scrollHelper->HandleOnChar((wxKeyEvent &)event); - return !event.GetSkipped(); - } - - return false; -} - -// ---------------------------------------------------------------------------- -// wxScrollHelper construction -// ---------------------------------------------------------------------------- - -wxScrollHelper::wxScrollHelper(wxWindow *win) -{ - wxASSERT_MSG( win, _T("associated window can't be NULL in wxScrollHelper") ); - - m_xScrollPixelsPerLine = - m_yScrollPixelsPerLine = - m_xScrollPosition = - m_yScrollPosition = - m_xScrollLines = - m_yScrollLines = - m_xScrollLinesPerPage = - m_yScrollLinesPerPage = 0; - - m_xScrollingEnabled = - m_yScrollingEnabled = true; - - m_scaleX = - m_scaleY = 1.0; -#if wxUSE_MOUSEWHEEL - m_wheelRotation = 0; -#endif - - m_win = - m_targetWindow = (wxWindow *)NULL; - - m_timerAutoScroll = (wxTimer *)NULL; - - m_handler = NULL; - - m_win = win; - - m_win->SetScrollHelper( this ); - - // by default, the associated window is also the target window - DoSetTargetWindow(win); -} - -wxScrollHelper::~wxScrollHelper() -{ - StopAutoScrolling(); - - DeleteEvtHandler(); -} - -// ---------------------------------------------------------------------------- -// setting scrolling parameters -// ---------------------------------------------------------------------------- - -void wxScrollHelper::SetScrollbars(int pixelsPerUnitX, - int pixelsPerUnitY, - int noUnitsX, - int noUnitsY, - int xPos, - int yPos, - bool noRefresh) -{ - int xpos, ypos; - - CalcUnscrolledPosition(xPos, yPos, &xpos, &ypos); - bool do_refresh = - ( - (noUnitsX != 0 && m_xScrollLines == 0) || - (noUnitsX < m_xScrollLines && xpos > pixelsPerUnitX * noUnitsX) || - - (noUnitsY != 0 && m_yScrollLines == 0) || - (noUnitsY < m_yScrollLines && ypos > pixelsPerUnitY * noUnitsY) || - (xPos != m_xScrollPosition) || - (yPos != m_yScrollPosition) - ); - - m_xScrollPixelsPerLine = pixelsPerUnitX; - m_yScrollPixelsPerLine = pixelsPerUnitY; - m_xScrollPosition = xPos; - m_yScrollPosition = yPos; - - int w = noUnitsX * pixelsPerUnitX; - int h = noUnitsY * pixelsPerUnitY; - - // For better backward compatibility we set persisting limits - // here not just the size. It makes SetScrollbars 'sticky' - // emulating the old non-autoscroll behaviour. - // m_targetWindow->SetVirtualSizeHints( w, h ); - - // The above should arguably be deprecated, this however we still need. - - // take care not to set 0 virtual size, 0 means that we don't have any - // scrollbars and hence we should use the real size instead of the virtual - // one which is indicated by using wxDefaultCoord - m_targetWindow->SetVirtualSize( w ? w : wxDefaultCoord, - h ? h : wxDefaultCoord); - - if (do_refresh && !noRefresh) - m_targetWindow->Refresh(true, GetScrollRect()); - -#ifndef __WXUNIVERSAL__ - // If the target is not the same as the window with the scrollbars, - // then we need to update the scrollbars here, since they won't have - // been updated by SetVirtualSize(). - if ( m_targetWindow != m_win ) -#endif // !__WXUNIVERSAL__ - { - AdjustScrollbars(); - } -#ifndef __WXUNIVERSAL__ - else - { - // otherwise this has been done by AdjustScrollbars, above - } -#endif // !__WXUNIVERSAL__ -} - -// ---------------------------------------------------------------------------- -// [target] window handling -// ---------------------------------------------------------------------------- - -void wxScrollHelper::DeleteEvtHandler() -{ - // search for m_handler in the handler list - if ( m_win && m_handler ) - { - if ( m_win->RemoveEventHandler(m_handler) ) - { - delete m_handler; - } - //else: something is very wrong, so better [maybe] leak memory than - // risk a crash because of double deletion - - m_handler = NULL; - } -} - -void wxScrollHelper::DoSetTargetWindow(wxWindow *target) -{ - m_targetWindow = target; -#ifdef __WXMAC__ - target->MacSetClipChildren( true ) ; -#endif - - // install the event handler which will intercept the events we're - // interested in (but only do it for our real window, not the target window - // which we scroll - we don't need to hijack its events) - if ( m_targetWindow == m_win ) - { - // if we already have a handler, delete it first - DeleteEvtHandler(); - - m_handler = new wxScrollHelperEvtHandler(this); - m_targetWindow->PushEventHandler(m_handler); - } -} - -void wxScrollHelper::SetTargetWindow(wxWindow *target) -{ - wxCHECK_RET( target, wxT("target window must not be NULL") ); - - if ( target == m_targetWindow ) - return; - - DoSetTargetWindow(target); -} - -wxWindow *wxScrollHelper::GetTargetWindow() const -{ - return m_targetWindow; -} - -// ---------------------------------------------------------------------------- -// scrolling implementation itself -// ---------------------------------------------------------------------------- - -void wxScrollHelper::HandleOnScroll(wxScrollWinEvent& event) -{ - int nScrollInc = CalcScrollInc(event); - if ( nScrollInc == 0 ) - { - // can't scroll further - event.Skip(); - - return; - } - - bool needsRefresh = false; - - int dx = 0, - dy = 0; - int orient = event.GetOrientation(); - if (orient == wxHORIZONTAL) - { - if ( m_xScrollingEnabled ) - { - dx = -m_xScrollPixelsPerLine * nScrollInc; - } - else - { - needsRefresh = true; - } - } - else - { - if ( m_yScrollingEnabled ) - { - dy = -m_yScrollPixelsPerLine * nScrollInc; - } - else - { - needsRefresh = true; - } - } - - if ( !needsRefresh ) - { - // flush all pending repaints before we change m_{x,y}ScrollPosition, as - // otherwise invalidated area could be updated incorrectly later when - // ScrollWindow() makes sure they're repainted before scrolling them -#ifdef __WXMAC__ - // wxWindowMac is taking care of making sure the update area is correctly - // set up, while not forcing an immediate redraw -#else - m_targetWindow->Update(); -#endif - } - - if (orient == wxHORIZONTAL) - { - m_xScrollPosition += nScrollInc; - m_win->SetScrollPos(wxHORIZONTAL, m_xScrollPosition); - } - else - { - m_yScrollPosition += nScrollInc; - m_win->SetScrollPos(wxVERTICAL, m_yScrollPosition); - } - - if ( needsRefresh ) - { - m_targetWindow->Refresh(true, GetScrollRect()); - } - else - { - m_targetWindow->ScrollWindow(dx, dy, GetScrollRect()); - } -} - -int wxScrollHelper::CalcScrollInc(wxScrollWinEvent& event) -{ - int pos = event.GetPosition(); - int orient = event.GetOrientation(); - - int nScrollInc = 0; - if (event.GetEventType() == wxEVT_SCROLLWIN_TOP) - { - if (orient == wxHORIZONTAL) - nScrollInc = - m_xScrollPosition; - else - nScrollInc = - m_yScrollPosition; - } else - if (event.GetEventType() == wxEVT_SCROLLWIN_BOTTOM) - { - if (orient == wxHORIZONTAL) - nScrollInc = m_xScrollLines - m_xScrollPosition; - else - nScrollInc = m_yScrollLines - m_yScrollPosition; - } else - if (event.GetEventType() == wxEVT_SCROLLWIN_LINEUP) - { - nScrollInc = -1; - } else - if (event.GetEventType() == wxEVT_SCROLLWIN_LINEDOWN) - { - nScrollInc = 1; - } else - if (event.GetEventType() == wxEVT_SCROLLWIN_PAGEUP) - { - if (orient == wxHORIZONTAL) - nScrollInc = -GetScrollPageSize(wxHORIZONTAL); - else - nScrollInc = -GetScrollPageSize(wxVERTICAL); - } else - if (event.GetEventType() == wxEVT_SCROLLWIN_PAGEDOWN) - { - if (orient == wxHORIZONTAL) - nScrollInc = GetScrollPageSize(wxHORIZONTAL); - else - nScrollInc = GetScrollPageSize(wxVERTICAL); - } else - if ((event.GetEventType() == wxEVT_SCROLLWIN_THUMBTRACK) || - (event.GetEventType() == wxEVT_SCROLLWIN_THUMBRELEASE)) - { - if (orient == wxHORIZONTAL) - nScrollInc = pos - m_xScrollPosition; - else - nScrollInc = pos - m_yScrollPosition; - } - - if (orient == wxHORIZONTAL) - { - if (m_xScrollPixelsPerLine > 0) - { - if ( m_xScrollPosition + nScrollInc < 0 ) - { - // As -ve as we can go - nScrollInc = -m_xScrollPosition; - } - else // check for the other bound - { - const int posMax = m_xScrollLines - m_xScrollLinesPerPage; - if ( m_xScrollPosition + nScrollInc > posMax ) - { - // As +ve as we can go - nScrollInc = posMax - m_xScrollPosition; - } - } - } - else - m_targetWindow->Refresh(true, GetScrollRect()); - } - else - { - if ( m_yScrollPixelsPerLine > 0 ) - { - if ( m_yScrollPosition + nScrollInc < 0 ) - { - // As -ve as we can go - nScrollInc = -m_yScrollPosition; - } - else // check for the other bound - { - const int posMax = m_yScrollLines - m_yScrollLinesPerPage; - if ( m_yScrollPosition + nScrollInc > posMax ) - { - // As +ve as we can go - nScrollInc = posMax - m_yScrollPosition; - } - } - } - else - { - // VZ: why do we do this? (FIXME) - m_targetWindow->Refresh(true, GetScrollRect()); - } - } - - return nScrollInc; -} - -// Adjust the scrollbars - new version. -void wxScrollHelper::AdjustScrollbars() -{ - static wxRecursionGuardFlag s_flagReentrancy; - wxRecursionGuard guard(s_flagReentrancy); - if ( guard.IsInside() ) - { - // don't reenter AdjustScrollbars() while another call to - // AdjustScrollbars() is in progress because this may lead to calling - // ScrollWindow() twice and this can really happen under MSW if - // SetScrollbar() call below adds or removes the scrollbar which - // changes the window size and hence results in another - // AdjustScrollbars() call - return; - } - - int w = 0, h = 0; - int oldw, oldh; - - int oldXScroll = m_xScrollPosition; - int oldYScroll = m_yScrollPosition; - - // VZ: at least under Windows this loop is useless because when scrollbars - // [dis]appear we get a WM_SIZE resulting in another call to - // AdjustScrollbars() anyhow. As it doesn't seem to do any harm I leave - // it here for now but it would be better to ensure that all ports - // generate EVT_SIZE when scrollbars [dis]appear, emulating it if - // necessary, and remove it later - // JACS: Stop potential infinite loop by limiting number of iterations - int iterationCount = 0; - const int iterationMax = 5; - do - { - iterationCount ++; - - GetTargetSize(&w, 0); - - // scroll lines per page: if 0, no scrolling is needed - int linesPerPage; - - if ( m_xScrollPixelsPerLine == 0 ) - { - // scrolling is disabled - m_xScrollLines = 0; - m_xScrollPosition = 0; - linesPerPage = 0; - } - else // might need scrolling - { - // Round up integer division to catch any "leftover" client space. - const int wVirt = m_targetWindow->GetVirtualSize().GetWidth(); - m_xScrollLines = (wVirt + m_xScrollPixelsPerLine - 1) / m_xScrollPixelsPerLine; - - // Calculate page size i.e. number of scroll units you get on the - // current client window. - linesPerPage = w / m_xScrollPixelsPerLine; - - // Special case. When client and virtual size are very close but - // the client is big enough, kill scrollbar. - if ((linesPerPage < m_xScrollLines) && (w >= wVirt)) ++linesPerPage; - - if (linesPerPage >= m_xScrollLines) - { - // we're big enough to not need scrolling - linesPerPage = - m_xScrollLines = - m_xScrollPosition = 0; - } - else // we do need a scrollbar - { - if ( linesPerPage < 1 ) - linesPerPage = 1; - - // Correct position if greater than extent of canvas minus - // the visible portion of it or if below zero - const int posMax = m_xScrollLines - linesPerPage; - if ( m_xScrollPosition > posMax ) - m_xScrollPosition = posMax; - else if ( m_xScrollPosition < 0 ) - m_xScrollPosition = 0; - } - } - - m_win->SetScrollbar(wxHORIZONTAL, m_xScrollPosition, - linesPerPage, m_xScrollLines); - - // The amount by which we scroll when paging - SetScrollPageSize(wxHORIZONTAL, linesPerPage); - - GetTargetSize(0, &h); - - if ( m_yScrollPixelsPerLine == 0 ) - { - // scrolling is disabled - m_yScrollLines = 0; - m_yScrollPosition = 0; - linesPerPage = 0; - } - else // might need scrolling - { - // Round up integer division to catch any "leftover" client space. - const int hVirt = m_targetWindow->GetVirtualSize().GetHeight(); - m_yScrollLines = ( hVirt + m_yScrollPixelsPerLine - 1 ) / m_yScrollPixelsPerLine; - - // Calculate page size i.e. number of scroll units you get on the - // current client window. - linesPerPage = h / m_yScrollPixelsPerLine; - - // Special case. When client and virtual size are very close but - // the client is big enough, kill scrollbar. - if ((linesPerPage < m_yScrollLines) && (h >= hVirt)) ++linesPerPage; - - if (linesPerPage >= m_yScrollLines) - { - // we're big enough to not need scrolling - linesPerPage = - m_yScrollLines = - m_yScrollPosition = 0; - } - else // we do need a scrollbar - { - if ( linesPerPage < 1 ) - linesPerPage = 1; - - // Correct position if greater than extent of canvas minus - // the visible portion of it or if below zero - const int posMax = m_yScrollLines - linesPerPage; - if ( m_yScrollPosition > posMax ) - m_yScrollPosition = posMax; - else if ( m_yScrollPosition < 0 ) - m_yScrollPosition = 0; - } - } - - m_win->SetScrollbar(wxVERTICAL, m_yScrollPosition, - linesPerPage, m_yScrollLines); - - // The amount by which we scroll when paging - SetScrollPageSize(wxVERTICAL, linesPerPage); - - - // If a scrollbar (dis)appeared as a result of this, adjust them again. - oldw = w; - oldh = h; - - GetTargetSize( &w, &h ); - } while ( (w != oldw || h != oldh) && (iterationCount < iterationMax) ); - -#ifdef __WXMOTIF__ - // Sorry, some Motif-specific code to implement a backing pixmap - // for the wxRETAINED style. Implementing a backing store can't - // be entirely generic because it relies on the wxWindowDC implementation - // to duplicate X drawing calls for the backing pixmap. - - if ( m_targetWindow->GetWindowStyle() & wxRETAINED ) - { - Display* dpy = XtDisplay((Widget)m_targetWindow->GetMainWidget()); - - int totalPixelWidth = m_xScrollLines * m_xScrollPixelsPerLine; - int totalPixelHeight = m_yScrollLines * m_yScrollPixelsPerLine; - if (m_targetWindow->GetBackingPixmap() && - !((m_targetWindow->GetPixmapWidth() == totalPixelWidth) && - (m_targetWindow->GetPixmapHeight() == totalPixelHeight))) - { - XFreePixmap (dpy, (Pixmap) m_targetWindow->GetBackingPixmap()); - m_targetWindow->SetBackingPixmap((WXPixmap) 0); - } - - if (!m_targetWindow->GetBackingPixmap() && - (m_xScrollLines != 0) && (m_yScrollLines != 0)) - { - int depth = wxDisplayDepth(); - m_targetWindow->SetPixmapWidth(totalPixelWidth); - m_targetWindow->SetPixmapHeight(totalPixelHeight); - m_targetWindow->SetBackingPixmap((WXPixmap) XCreatePixmap (dpy, RootWindow (dpy, DefaultScreen (dpy)), - m_targetWindow->GetPixmapWidth(), m_targetWindow->GetPixmapHeight(), depth)); - } - - } -#endif // Motif - - if (oldXScroll != m_xScrollPosition) - { - if (m_xScrollingEnabled) - m_targetWindow->ScrollWindow( m_xScrollPixelsPerLine * (oldXScroll - m_xScrollPosition), 0, - GetScrollRect() ); - else - m_targetWindow->Refresh(true, GetScrollRect()); - } - - if (oldYScroll != m_yScrollPosition) - { - if (m_yScrollingEnabled) - m_targetWindow->ScrollWindow( 0, m_yScrollPixelsPerLine * (oldYScroll-m_yScrollPosition), - GetScrollRect() ); - else - m_targetWindow->Refresh(true, GetScrollRect()); - } -} - -void wxScrollHelper::DoPrepareDC(wxDC& dc) -{ - wxPoint pt = dc.GetDeviceOrigin(); -#ifdef __WXGTK__ - // It may actually be correct to always query - // the m_sign from the DC here, but I leve the - // #ifdef GTK for now. - if (m_win->GetLayoutDirection() == wxLayout_RightToLeft) - dc.SetDeviceOrigin( pt.x + m_xScrollPosition * m_xScrollPixelsPerLine, - pt.y - m_yScrollPosition * m_yScrollPixelsPerLine ); - else -#endif - dc.SetDeviceOrigin( pt.x - m_xScrollPosition * m_xScrollPixelsPerLine, - pt.y - m_yScrollPosition * m_yScrollPixelsPerLine ); - dc.SetUserScale( m_scaleX, m_scaleY ); -} - -void wxScrollHelper::SetScrollRate( int xstep, int ystep ) -{ - int old_x = m_xScrollPixelsPerLine * m_xScrollPosition; - int old_y = m_yScrollPixelsPerLine * m_yScrollPosition; - - m_xScrollPixelsPerLine = xstep; - m_yScrollPixelsPerLine = ystep; - - int new_x = m_xScrollPixelsPerLine * m_xScrollPosition; - int new_y = m_yScrollPixelsPerLine * m_yScrollPosition; - - m_win->SetScrollPos( wxHORIZONTAL, m_xScrollPosition ); - m_win->SetScrollPos( wxVERTICAL, m_yScrollPosition ); - m_targetWindow->ScrollWindow( old_x - new_x, old_y - new_y ); - - AdjustScrollbars(); -} - -void wxScrollHelper::GetScrollPixelsPerUnit (int *x_unit, int *y_unit) const -{ - if ( x_unit ) - *x_unit = m_xScrollPixelsPerLine; - if ( y_unit ) - *y_unit = m_yScrollPixelsPerLine; -} - - -int wxScrollHelper::GetScrollLines( int orient ) const -{ - if ( orient == wxHORIZONTAL ) - return m_xScrollLines; - else - return m_yScrollLines; -} - -int wxScrollHelper::GetScrollPageSize(int orient) const -{ - if ( orient == wxHORIZONTAL ) - return m_xScrollLinesPerPage; - else - return m_yScrollLinesPerPage; -} - -void wxScrollHelper::SetScrollPageSize(int orient, int pageSize) -{ - if ( orient == wxHORIZONTAL ) - m_xScrollLinesPerPage = pageSize; - else - m_yScrollLinesPerPage = pageSize; -} - -/* - * Scroll to given position (scroll position, not pixel position) - */ -void wxScrollHelper::Scroll( int x_pos, int y_pos ) -{ - if (!m_targetWindow) - return; - - if (((x_pos == -1) || (x_pos == m_xScrollPosition)) && - ((y_pos == -1) || (y_pos == m_yScrollPosition))) return; - - int w = 0, h = 0; - GetTargetSize(&w, &h); - - // compute new position: - int new_x = m_xScrollPosition; - int new_y = m_yScrollPosition; - - if ((x_pos != -1) && (m_xScrollPixelsPerLine)) - { - new_x = x_pos; - - // Calculate page size i.e. number of scroll units you get on the - // current client window - int noPagePositions = w/m_xScrollPixelsPerLine; - if (noPagePositions < 1) noPagePositions = 1; - - // Correct position if greater than extent of canvas minus - // the visible portion of it or if below zero - new_x = wxMin( m_xScrollLines-noPagePositions, new_x ); - new_x = wxMax( 0, new_x ); - } - if ((y_pos != -1) && (m_yScrollPixelsPerLine)) - { - new_y = y_pos; - - // Calculate page size i.e. number of scroll units you get on the - // current client window - int noPagePositions = h/m_yScrollPixelsPerLine; - if (noPagePositions < 1) noPagePositions = 1; - - // Correct position if greater than extent of canvas minus - // the visible portion of it or if below zero - new_y = wxMin( m_yScrollLines-noPagePositions, new_y ); - new_y = wxMax( 0, new_y ); - } - - if ( new_x == m_xScrollPosition && new_y == m_yScrollPosition ) - return; // nothing to do, the position didn't change - - // flush all pending repaints before we change m_{x,y}ScrollPosition, as - // otherwise invalidated area could be updated incorrectly later when - // ScrollWindow() makes sure they're repainted before scrolling them - m_targetWindow->Update(); - - // update the position and scroll the window now: - if (m_xScrollPosition != new_x) - { - int old_x = m_xScrollPosition; - m_xScrollPosition = new_x; - m_win->SetScrollPos( wxHORIZONTAL, new_x ); - m_targetWindow->ScrollWindow( (old_x-new_x)*m_xScrollPixelsPerLine, 0, - GetScrollRect() ); - } - - if (m_yScrollPosition != new_y) - { - int old_y = m_yScrollPosition; - m_yScrollPosition = new_y; - m_win->SetScrollPos( wxVERTICAL, new_y ); - m_targetWindow->ScrollWindow( 0, (old_y-new_y)*m_yScrollPixelsPerLine, - GetScrollRect() ); - } -} - -void wxScrollHelper::EnableScrolling (bool x_scroll, bool y_scroll) -{ - m_xScrollingEnabled = x_scroll; - m_yScrollingEnabled = y_scroll; -} - -// Where the current view starts from -void wxScrollHelper::GetViewStart (int *x, int *y) const -{ - if ( x ) - *x = m_xScrollPosition; - if ( y ) - *y = m_yScrollPosition; -} - -void wxScrollHelper::DoCalcScrolledPosition(int x, int y, int *xx, int *yy) const -{ - if ( xx ) - *xx = x - m_xScrollPosition * m_xScrollPixelsPerLine; - if ( yy ) - *yy = y - m_yScrollPosition * m_yScrollPixelsPerLine; -} - -void wxScrollHelper::DoCalcUnscrolledPosition(int x, int y, int *xx, int *yy) const -{ - if ( xx ) - *xx = x + m_xScrollPosition * m_xScrollPixelsPerLine; - if ( yy ) - *yy = y + m_yScrollPosition * m_yScrollPixelsPerLine; -} - -// ---------------------------------------------------------------------------- -// geometry -// ---------------------------------------------------------------------------- - -bool wxScrollHelper::ScrollLayout() -{ - if ( m_win->GetSizer() && m_targetWindow == m_win ) - { - // If we're the scroll target, take into account the - // virtual size and scrolled position of the window. - - int x = 0, y = 0, w = 0, h = 0; - CalcScrolledPosition(0,0, &x,&y); - m_win->GetVirtualSize(&w, &h); - m_win->GetSizer()->SetDimension(x, y, w, h); - return true; - } - - // fall back to default for LayoutConstraints - return m_win->wxWindow::Layout(); -} - -void wxScrollHelper::ScrollDoSetVirtualSize(int x, int y) -{ - m_win->wxWindow::DoSetVirtualSize( x, y ); - AdjustScrollbars(); - - if (m_win->GetAutoLayout()) - m_win->Layout(); -} - -// wxWindow's GetBestVirtualSize returns the actual window size, -// whereas we want to return the virtual size -wxSize wxScrollHelper::ScrollGetBestVirtualSize() const -{ - wxSize clientSize(m_win->GetClientSize()); - if ( m_win->GetSizer() ) - clientSize.IncTo(m_win->GetSizer()->CalcMin()); - - return clientSize; -} - -// return the window best size from the given best virtual size -wxSize -wxScrollHelper::ScrollGetWindowSizeForVirtualSize(const wxSize& size) const -{ - // Only use the content to set the window size in the direction - // where there's no scrolling; otherwise we're going to get a huge - // window in the direction in which scrolling is enabled - int ppuX, ppuY; - GetScrollPixelsPerUnit(&ppuX, &ppuY); - - wxSize minSize = m_win->GetMinSize(); - - wxSize best(size); - if (ppuX > 0) - best.x = minSize.x + wxSystemSettings::GetMetric(wxSYS_VSCROLL_X); - if (ppuY > 0) - best.y = minSize.y + wxSystemSettings::GetMetric(wxSYS_HSCROLL_Y); - - return best; -} - -// ---------------------------------------------------------------------------- -// event handlers -// ---------------------------------------------------------------------------- - -// Default OnSize resets scrollbars, if any -void wxScrollHelper::HandleOnSize(wxSizeEvent& WXUNUSED(event)) -{ - if ( m_targetWindow->GetAutoLayout() ) - { - wxSize size = m_targetWindow->GetBestVirtualSize(); - - // This will call ::Layout() and ::AdjustScrollbars() - m_win->SetVirtualSize( size ); - } - else - { - AdjustScrollbars(); - } -} - -// This calls OnDraw, having adjusted the origin according to the current -// scroll position -void wxScrollHelper::HandleOnPaint(wxPaintEvent& WXUNUSED(event)) -{ - // don't use m_targetWindow here, this is always called for ourselves - wxPaintDC dc(m_win); - DoPrepareDC(dc); - - OnDraw(dc); -} - -// kbd handling: notice that we use OnChar() and not OnKeyDown() for -// compatibility here - if we used OnKeyDown(), the programs which process -// arrows themselves in their OnChar() would never get the message and like -// this they always have the priority -void wxScrollHelper::HandleOnChar(wxKeyEvent& event) -{ - int stx = 0, sty = 0, // view origin - szx = 0, szy = 0, // view size (total) - clix = 0, cliy = 0; // view size (on screen) - - GetViewStart(&stx, &sty); - GetTargetSize(&clix, &cliy); - m_targetWindow->GetVirtualSize(&szx, &szy); - - if( m_xScrollPixelsPerLine ) - { - clix /= m_xScrollPixelsPerLine; - szx /= m_xScrollPixelsPerLine; - } - else - { - clix = 0; - szx = -1; - } - if( m_yScrollPixelsPerLine ) - { - cliy /= m_yScrollPixelsPerLine; - szy /= m_yScrollPixelsPerLine; - } - else - { - cliy = 0; - szy = -1; - } - - int xScrollOld = m_xScrollPosition, - yScrollOld = m_yScrollPosition; - - int dsty; - switch ( event.GetKeyCode() ) - { - case WXK_PAGEUP: - dsty = sty - (5 * cliy / 6); - Scroll(-1, (dsty == -1) ? 0 : dsty); - break; - - case WXK_PAGEDOWN: - Scroll(-1, sty + (5 * cliy / 6)); - break; - - case WXK_HOME: - Scroll(0, event.ControlDown() ? 0 : -1); - break; - - case WXK_END: - Scroll(szx - clix, event.ControlDown() ? szy - cliy : -1); - break; - - case WXK_UP: - Scroll(-1, sty - 1); - break; - - case WXK_DOWN: - Scroll(-1, sty + 1); - break; - - case WXK_LEFT: - Scroll(stx - 1, -1); - break; - - case WXK_RIGHT: - Scroll(stx + 1, -1); - break; - - default: - // not for us - event.Skip(); - } - - if ( m_xScrollPosition != xScrollOld ) - { - wxScrollWinEvent event(wxEVT_SCROLLWIN_THUMBTRACK, m_xScrollPosition, - wxHORIZONTAL); - event.SetEventObject(m_win); - m_win->GetEventHandler()->ProcessEvent(event); - } - - if ( m_yScrollPosition != yScrollOld ) - { - wxScrollWinEvent event(wxEVT_SCROLLWIN_THUMBTRACK, m_yScrollPosition, - wxVERTICAL); - event.SetEventObject(m_win); - m_win->GetEventHandler()->ProcessEvent(event); - } -} - -// ---------------------------------------------------------------------------- -// autoscroll stuff: these functions deal with sending fake scroll events when -// a captured mouse is being held outside the window -// ---------------------------------------------------------------------------- - -bool wxScrollHelper::SendAutoScrollEvents(wxScrollWinEvent& event) const -{ - // only send the event if the window is scrollable in this direction - wxWindow *win = (wxWindow *)event.GetEventObject(); - return win->HasScrollbar(event.GetOrientation()); -} - -void wxScrollHelper::StopAutoScrolling() -{ -#if wxUSE_TIMER - if ( m_timerAutoScroll ) - { - delete m_timerAutoScroll; - m_timerAutoScroll = (wxTimer *)NULL; - } -#endif -} - -void wxScrollHelper::HandleOnMouseEnter(wxMouseEvent& event) -{ - StopAutoScrolling(); - - event.Skip(); -} - -void wxScrollHelper::HandleOnMouseLeave(wxMouseEvent& event) -{ - // don't prevent the usual processing of the event from taking place - event.Skip(); - - // when a captured mouse leave a scrolled window we start generate - // scrolling events to allow, for example, extending selection beyond the - // visible area in some controls - if ( wxWindow::GetCapture() == m_targetWindow ) - { - // where is the mouse leaving? - int pos, orient; - wxPoint pt = event.GetPosition(); - if ( pt.x < 0 ) - { - orient = wxHORIZONTAL; - pos = 0; - } - else if ( pt.y < 0 ) - { - orient = wxVERTICAL; - pos = 0; - } - else // we're lower or to the right of the window - { - wxSize size = m_targetWindow->GetClientSize(); - if ( pt.x > size.x ) - { - orient = wxHORIZONTAL; - pos = m_xScrollLines; - } - else if ( pt.y > size.y ) - { - orient = wxVERTICAL; - pos = m_yScrollLines; - } - else // this should be impossible - { - // but seems to happen sometimes under wxMSW - maybe it's a bug - // there but for now just ignore it - - //wxFAIL_MSG( _T("can't understand where has mouse gone") ); - - return; - } - } - - // only start the auto scroll timer if the window can be scrolled in - // this direction - if ( !m_targetWindow->HasScrollbar(orient) ) - return; - -#if wxUSE_TIMER - delete m_timerAutoScroll; - m_timerAutoScroll = new wxAutoScrollTimer - ( - m_targetWindow, this, - pos == 0 ? wxEVT_SCROLLWIN_LINEUP - : wxEVT_SCROLLWIN_LINEDOWN, - pos, - orient - ); - m_timerAutoScroll->Start(50); // FIXME: make configurable -#else - wxUnusedVar(pos); -#endif - } -} - -#if wxUSE_MOUSEWHEEL - -void wxScrollHelper::HandleOnMouseWheel(wxMouseEvent& event) -{ - m_wheelRotation += event.GetWheelRotation(); - int lines = m_wheelRotation / event.GetWheelDelta(); - m_wheelRotation -= lines * event.GetWheelDelta(); - - if (lines != 0) - { - - wxScrollWinEvent newEvent; - - newEvent.SetPosition(0); - newEvent.SetOrientation(wxVERTICAL); - newEvent.SetEventObject(m_win); - - if (event.IsPageScroll()) - { - if (lines > 0) - newEvent.SetEventType(wxEVT_SCROLLWIN_PAGEUP); - else - newEvent.SetEventType(wxEVT_SCROLLWIN_PAGEDOWN); - - m_win->GetEventHandler()->ProcessEvent(newEvent); - } - else - { - lines *= event.GetLinesPerAction(); - if (lines > 0) - newEvent.SetEventType(wxEVT_SCROLLWIN_LINEUP); - else - newEvent.SetEventType(wxEVT_SCROLLWIN_LINEDOWN); - - int times = abs(lines); - for (; times > 0; times--) - m_win->GetEventHandler()->ProcessEvent(newEvent); - } - } -} - -#endif // wxUSE_MOUSEWHEEL - -void wxScrollHelper::HandleOnChildFocus(wxChildFocusEvent& event) -{ - // this event should be processed by all windows in parenthood chain, - // e.g. so that nested wxScrolledWindows work correctly - event.Skip(); - - // find the immediate child under which the window receiving focus is: - wxWindow *win = event.GetWindow(); - - if ( win == m_targetWindow ) - return; // nothing to do - - while ( win->GetParent() != m_targetWindow ) - { - win = win->GetParent(); - if ( !win ) - return; // event is not from a child of the target window - } - - // if the child is not fully visible, try to scroll it into view: - int stepx, stepy; - GetScrollPixelsPerUnit(&stepx, &stepy); - - // NB: we don't call CalcScrolledPosition() on win->GetPosition() here, - // because children' positions are already scrolled - wxRect winrect(win->GetPosition(), win->GetSize()); - wxSize view(m_targetWindow->GetClientSize()); - - int startx, starty; - GetViewStart(&startx, &starty); - - // first in vertical direction: - if ( stepy > 0 ) - { - int diff = 0; - - if ( winrect.GetTop() < 0 ) - { - diff = winrect.GetTop(); - } - else if ( winrect.GetBottom() > view.y ) - { - diff = winrect.GetBottom() - view.y + 1; - // round up to next scroll step if we can't get exact position, - // so that the window is fully visible: - diff += stepy - 1; - } - - starty = (starty * stepy + diff) / stepy; - } - - // then horizontal: - if ( stepx > 0 ) - { - int diff = 0; - - if ( winrect.GetLeft() < 0 ) - { - diff = winrect.GetLeft(); - } - else if ( winrect.GetRight() > view.x ) - { - diff = winrect.GetRight() - view.x + 1; - // round up to next scroll step if we can't get exact position, - // so that the window is fully visible: - diff += stepx - 1; - } - - startx = (startx * stepx + diff) / stepx; - } - - Scroll(startx, starty); -} - -// ---------------------------------------------------------------------------- -// wxScrolledWindow implementation -// ---------------------------------------------------------------------------- - -IMPLEMENT_DYNAMIC_CLASS(wxScrolledWindow, wxPanel) - -BEGIN_EVENT_TABLE(wxScrolledWindow, wxPanel) - EVT_PAINT(wxScrolledWindow::OnPaint) -END_EVENT_TABLE() - -bool wxScrolledWindow::Create(wxWindow *parent, - wxWindowID id, - const wxPoint& pos, - const wxSize& size, - long style, - const wxString& name) -{ - m_targetWindow = this; -#ifdef __WXMAC__ - MacSetClipChildren( true ) ; -#endif - - bool ok = wxPanel::Create(parent, id, pos, size, style|wxHSCROLL|wxVSCROLL, name); - - return ok; -} - -wxScrolledWindow::~wxScrolledWindow() -{ -} - -void wxScrolledWindow::OnPaint(wxPaintEvent& event) -{ - // the user code didn't really draw the window if we got here, so set this - // flag to try to call OnDraw() later - m_handler->ResetDrawnFlag(); - - event.Skip(); -} - -#ifdef __WXMSW__ -WXLRESULT wxScrolledWindow::MSWWindowProc(WXUINT nMsg, - WXWPARAM wParam, - WXLPARAM lParam) -{ - WXLRESULT rc = wxPanel::MSWWindowProc(nMsg, wParam, lParam); - -#ifndef __WXWINCE__ - // we need to process arrows ourselves for scrolling - if ( nMsg == WM_GETDLGCODE ) - { - rc |= DLGC_WANTARROWS; - } -#endif - - return rc; -} - -#endif // __WXMSW__ +///////////////////////////////////////////////////////////////////////////// +// Name: src/generic/scrlwing.cpp +// Purpose: wxScrolledWindow implementation +// Author: Julian Smart +// Modified by: Vadim Zeitlin on 31.08.00: wxScrollHelper allows to implement. +// Ron Lee on 10.4.02: virtual size / auto scrollbars et al. +// Created: 01/02/97 +// RCS-ID: $Id: scrlwing.cpp 50982 2008-01-01 20:38:33Z VZ $ +// Copyright: (c) wxWidgets team +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#include "wx/scrolwin.h" + +#ifndef WX_PRECOMP + #include "wx/utils.h" + #include "wx/panel.h" + #include "wx/dcclient.h" + #if wxUSE_TIMER + #include "wx/timer.h" + #endif + #include "wx/sizer.h" + #include "wx/settings.h" +#endif + +#ifdef __WXMAC__ +#include "wx/scrolbar.h" +#endif + +#include "wx/recguard.h" + +#ifdef __WXMSW__ + #include // for DLGC_WANTARROWS + #include "wx/msw/winundef.h" +#endif + +#ifdef __WXMOTIF__ +// For wxRETAINED implementation +#ifdef __VMS__ //VMS's Xm.h is not (yet) compatible with C++ + //This code switches off the compiler warnings +# pragma message disable nosimpint +#endif +#include +#ifdef __VMS__ +# pragma message enable nosimpint +#endif +#endif + +/* + TODO PROPERTIES + style wxHSCROLL | wxVSCROLL +*/ + +// ---------------------------------------------------------------------------- +// wxScrollHelperEvtHandler: intercept the events from the window and forward +// them to wxScrollHelper +// ---------------------------------------------------------------------------- + +class WXDLLEXPORT wxScrollHelperEvtHandler : public wxEvtHandler +{ +public: + wxScrollHelperEvtHandler(wxScrollHelper *scrollHelper) + { + m_scrollHelper = scrollHelper; + } + + virtual bool ProcessEvent(wxEvent& event); + + void ResetDrawnFlag() { m_hasDrawnWindow = false; } + +private: + wxScrollHelper *m_scrollHelper; + + bool m_hasDrawnWindow; + + DECLARE_NO_COPY_CLASS(wxScrollHelperEvtHandler) +}; + +#if wxUSE_TIMER +// ---------------------------------------------------------------------------- +// wxAutoScrollTimer: the timer used to generate a stream of scroll events when +// a captured mouse is held outside the window +// ---------------------------------------------------------------------------- + +class wxAutoScrollTimer : public wxTimer +{ +public: + wxAutoScrollTimer(wxWindow *winToScroll, wxScrollHelper *scroll, + wxEventType eventTypeToSend, + int pos, int orient); + + virtual void Notify(); + +private: + wxWindow *m_win; + wxScrollHelper *m_scrollHelper; + wxEventType m_eventType; + int m_pos, + m_orient; + + DECLARE_NO_COPY_CLASS(wxAutoScrollTimer) +}; + +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// wxAutoScrollTimer +// ---------------------------------------------------------------------------- + +wxAutoScrollTimer::wxAutoScrollTimer(wxWindow *winToScroll, + wxScrollHelper *scroll, + wxEventType eventTypeToSend, + int pos, int orient) +{ + m_win = winToScroll; + m_scrollHelper = scroll; + m_eventType = eventTypeToSend; + m_pos = pos; + m_orient = orient; +} + +void wxAutoScrollTimer::Notify() +{ + // only do all this as long as the window is capturing the mouse + if ( wxWindow::GetCapture() != m_win ) + { + Stop(); + } + else // we still capture the mouse, continue generating events + { + // first scroll the window if we are allowed to do it + wxScrollWinEvent event1(m_eventType, m_pos, m_orient); + event1.SetEventObject(m_win); + if ( m_scrollHelper->SendAutoScrollEvents(event1) && + m_win->GetEventHandler()->ProcessEvent(event1) ) + { + // and then send a pseudo mouse-move event to refresh the selection + wxMouseEvent event2(wxEVT_MOTION); + wxGetMousePosition(&event2.m_x, &event2.m_y); + + // the mouse event coordinates should be client, not screen as + // returned by wxGetMousePosition + wxWindow *parentTop = m_win; + while ( parentTop->GetParent() ) + parentTop = parentTop->GetParent(); + wxPoint ptOrig = parentTop->GetPosition(); + event2.m_x -= ptOrig.x; + event2.m_y -= ptOrig.y; + + event2.SetEventObject(m_win); + + // FIXME: we don't fill in the other members - ok? + + m_win->GetEventHandler()->ProcessEvent(event2); + } + else // can't scroll further, stop + { + Stop(); + } + } +} +#endif + +// ---------------------------------------------------------------------------- +// wxScrollHelperEvtHandler +// ---------------------------------------------------------------------------- + +bool wxScrollHelperEvtHandler::ProcessEvent(wxEvent& event) +{ + wxEventType evType = event.GetEventType(); + + // the explanation of wxEVT_PAINT processing hack: for historic reasons + // there are 2 ways to process this event in classes deriving from + // wxScrolledWindow. The user code may + // + // 1. override wxScrolledWindow::OnDraw(dc) + // 2. define its own OnPaint() handler + // + // In addition, in wxUniversal wxWindow defines OnPaint() itself and + // always processes the draw event, so we can't just try the window + // OnPaint() first and call our HandleOnPaint() if it doesn't process it + // (the latter would never be called in wxUniversal). + // + // So the solution is to have a flag telling us whether the user code drew + // anything in the window. We set it to true here but reset it to false in + // wxScrolledWindow::OnPaint() handler (which wouldn't be called if the + // user code defined OnPaint() in the derived class) + m_hasDrawnWindow = true; + + // pass it on to the real handler + bool processed = wxEvtHandler::ProcessEvent(event); + + // always process the size events ourselves, even if the user code handles + // them as well, as we need to AdjustScrollbars() + // + // NB: it is important to do it after processing the event in the normal + // way as HandleOnSize() may generate a wxEVT_SIZE itself if the + // scrollbar[s] (dis)appear and it should be seen by the user code + // after this one + if ( evType == wxEVT_SIZE ) + { + m_scrollHelper->HandleOnSize((wxSizeEvent &)event); + + return true; + } + + if ( processed ) + { + // normally, nothing more to do here - except if it was a paint event + // which wasn't really processed, then we'll try to call our + // OnDraw() below (from HandleOnPaint) + if ( m_hasDrawnWindow || event.IsCommandEvent() ) + { + return true; + } + } + + // reset the skipped flag to false as it might have been set to true in + // ProcessEvent() above + event.Skip(false); + + if ( evType == wxEVT_PAINT ) + { + m_scrollHelper->HandleOnPaint((wxPaintEvent &)event); + return true; + } + + if ( evType == wxEVT_CHILD_FOCUS ) + { + m_scrollHelper->HandleOnChildFocus((wxChildFocusEvent &)event); + return true; + } + + if ( evType == wxEVT_SCROLLWIN_TOP || + evType == wxEVT_SCROLLWIN_BOTTOM || + evType == wxEVT_SCROLLWIN_LINEUP || + evType == wxEVT_SCROLLWIN_LINEDOWN || + evType == wxEVT_SCROLLWIN_PAGEUP || + evType == wxEVT_SCROLLWIN_PAGEDOWN || + evType == wxEVT_SCROLLWIN_THUMBTRACK || + evType == wxEVT_SCROLLWIN_THUMBRELEASE ) + { + m_scrollHelper->HandleOnScroll((wxScrollWinEvent &)event); + return !event.GetSkipped(); + } + + if ( evType == wxEVT_ENTER_WINDOW ) + { + m_scrollHelper->HandleOnMouseEnter((wxMouseEvent &)event); + } + else if ( evType == wxEVT_LEAVE_WINDOW ) + { + m_scrollHelper->HandleOnMouseLeave((wxMouseEvent &)event); + } +#if wxUSE_MOUSEWHEEL + else if ( evType == wxEVT_MOUSEWHEEL ) + { + m_scrollHelper->HandleOnMouseWheel((wxMouseEvent &)event); + return true; + } +#endif // wxUSE_MOUSEWHEEL + else if ( evType == wxEVT_CHAR ) + { + m_scrollHelper->HandleOnChar((wxKeyEvent &)event); + return !event.GetSkipped(); + } + + return false; +} + +// ---------------------------------------------------------------------------- +// wxScrollHelper construction +// ---------------------------------------------------------------------------- + +wxScrollHelper::wxScrollHelper(wxWindow *win) +{ + wxASSERT_MSG( win, _T("associated window can't be NULL in wxScrollHelper") ); + + m_xScrollPixelsPerLine = + m_yScrollPixelsPerLine = + m_xScrollPosition = + m_yScrollPosition = + m_xScrollLines = + m_yScrollLines = + m_xScrollLinesPerPage = + m_yScrollLinesPerPage = 0; + + m_xScrollingEnabled = + m_yScrollingEnabled = true; + + m_scaleX = + m_scaleY = 1.0; +#if wxUSE_MOUSEWHEEL + m_wheelRotation = 0; +#endif + + m_win = + m_targetWindow = (wxWindow *)NULL; + + m_timerAutoScroll = (wxTimer *)NULL; + + m_handler = NULL; + + m_win = win; + + m_win->SetScrollHelper( this ); + + // by default, the associated window is also the target window + DoSetTargetWindow(win); +} + +wxScrollHelper::~wxScrollHelper() +{ + StopAutoScrolling(); + + DeleteEvtHandler(); +} + +// ---------------------------------------------------------------------------- +// setting scrolling parameters +// ---------------------------------------------------------------------------- + +void wxScrollHelper::SetScrollbars(int pixelsPerUnitX, + int pixelsPerUnitY, + int noUnitsX, + int noUnitsY, + int xPos, + int yPos, + bool noRefresh) +{ + int xpos, ypos; + + CalcUnscrolledPosition(xPos, yPos, &xpos, &ypos); + bool do_refresh = + ( + (noUnitsX != 0 && m_xScrollLines == 0) || + (noUnitsX < m_xScrollLines && xpos > pixelsPerUnitX * noUnitsX) || + + (noUnitsY != 0 && m_yScrollLines == 0) || + (noUnitsY < m_yScrollLines && ypos > pixelsPerUnitY * noUnitsY) || + (xPos != m_xScrollPosition) || + (yPos != m_yScrollPosition) + ); + + m_xScrollPixelsPerLine = pixelsPerUnitX; + m_yScrollPixelsPerLine = pixelsPerUnitY; + m_xScrollPosition = xPos; + m_yScrollPosition = yPos; + + int w = noUnitsX * pixelsPerUnitX; + int h = noUnitsY * pixelsPerUnitY; + + // For better backward compatibility we set persisting limits + // here not just the size. It makes SetScrollbars 'sticky' + // emulating the old non-autoscroll behaviour. + // m_targetWindow->SetVirtualSizeHints( w, h ); + + // The above should arguably be deprecated, this however we still need. + + // take care not to set 0 virtual size, 0 means that we don't have any + // scrollbars and hence we should use the real size instead of the virtual + // one which is indicated by using wxDefaultCoord + m_targetWindow->SetVirtualSize( w ? w : wxDefaultCoord, + h ? h : wxDefaultCoord); + + if (do_refresh && !noRefresh) + m_targetWindow->Refresh(true, GetScrollRect()); + +#ifndef __WXUNIVERSAL__ + // If the target is not the same as the window with the scrollbars, + // then we need to update the scrollbars here, since they won't have + // been updated by SetVirtualSize(). + if ( m_targetWindow != m_win ) +#endif // !__WXUNIVERSAL__ + { + AdjustScrollbars(); + } +#ifndef __WXUNIVERSAL__ + else + { + // otherwise this has been done by AdjustScrollbars, above + } +#endif // !__WXUNIVERSAL__ +} + +// ---------------------------------------------------------------------------- +// [target] window handling +// ---------------------------------------------------------------------------- + +void wxScrollHelper::DeleteEvtHandler() +{ + // search for m_handler in the handler list + if ( m_win && m_handler ) + { + if ( m_win->RemoveEventHandler(m_handler) ) + { + delete m_handler; + } + //else: something is very wrong, so better [maybe] leak memory than + // risk a crash because of double deletion + + m_handler = NULL; + } +} + +void wxScrollHelper::DoSetTargetWindow(wxWindow *target) +{ + m_targetWindow = target; +#ifdef __WXMAC__ + target->MacSetClipChildren( true ) ; +#endif + + // install the event handler which will intercept the events we're + // interested in (but only do it for our real window, not the target window + // which we scroll - we don't need to hijack its events) + if ( m_targetWindow == m_win ) + { + // if we already have a handler, delete it first + DeleteEvtHandler(); + + m_handler = new wxScrollHelperEvtHandler(this); + m_targetWindow->PushEventHandler(m_handler); + } +} + +void wxScrollHelper::SetTargetWindow(wxWindow *target) +{ + wxCHECK_RET( target, wxT("target window must not be NULL") ); + + if ( target == m_targetWindow ) + return; + + DoSetTargetWindow(target); +} + +wxWindow *wxScrollHelper::GetTargetWindow() const +{ + return m_targetWindow; +} + +// ---------------------------------------------------------------------------- +// scrolling implementation itself +// ---------------------------------------------------------------------------- + +void wxScrollHelper::HandleOnScroll(wxScrollWinEvent& event) +{ + int nScrollInc = CalcScrollInc(event); + if ( nScrollInc == 0 ) + { + // can't scroll further + event.Skip(); + + return; + } + + bool needsRefresh = false; + + int dx = 0, + dy = 0; + int orient = event.GetOrientation(); + if (orient == wxHORIZONTAL) + { + if ( m_xScrollingEnabled ) + { + dx = -m_xScrollPixelsPerLine * nScrollInc; + } + else + { + needsRefresh = true; + } + } + else + { + if ( m_yScrollingEnabled ) + { + dy = -m_yScrollPixelsPerLine * nScrollInc; + } + else + { + needsRefresh = true; + } + } + + if ( !needsRefresh ) + { + // flush all pending repaints before we change m_{x,y}ScrollPosition, as + // otherwise invalidated area could be updated incorrectly later when + // ScrollWindow() makes sure they're repainted before scrolling them +#ifdef __WXMAC__ + // wxWindowMac is taking care of making sure the update area is correctly + // set up, while not forcing an immediate redraw +#else + m_targetWindow->Update(); +#endif + } + + if (orient == wxHORIZONTAL) + { + m_xScrollPosition += nScrollInc; + m_win->SetScrollPos(wxHORIZONTAL, m_xScrollPosition); + } + else + { + m_yScrollPosition += nScrollInc; + m_win->SetScrollPos(wxVERTICAL, m_yScrollPosition); + } + + if ( needsRefresh ) + { + m_targetWindow->Refresh(true, GetScrollRect()); + } + else + { + m_targetWindow->ScrollWindow(dx, dy, GetScrollRect()); + } +} + +int wxScrollHelper::CalcScrollInc(wxScrollWinEvent& event) +{ + int pos = event.GetPosition(); + int orient = event.GetOrientation(); + + int nScrollInc = 0; + if (event.GetEventType() == wxEVT_SCROLLWIN_TOP) + { + if (orient == wxHORIZONTAL) + nScrollInc = - m_xScrollPosition; + else + nScrollInc = - m_yScrollPosition; + } else + if (event.GetEventType() == wxEVT_SCROLLWIN_BOTTOM) + { + if (orient == wxHORIZONTAL) + nScrollInc = m_xScrollLines - m_xScrollPosition; + else + nScrollInc = m_yScrollLines - m_yScrollPosition; + } else + if (event.GetEventType() == wxEVT_SCROLLWIN_LINEUP) + { + nScrollInc = -1; + } else + if (event.GetEventType() == wxEVT_SCROLLWIN_LINEDOWN) + { + nScrollInc = 1; + } else + if (event.GetEventType() == wxEVT_SCROLLWIN_PAGEUP) + { + if (orient == wxHORIZONTAL) + nScrollInc = -GetScrollPageSize(wxHORIZONTAL); + else + nScrollInc = -GetScrollPageSize(wxVERTICAL); + } else + if (event.GetEventType() == wxEVT_SCROLLWIN_PAGEDOWN) + { + if (orient == wxHORIZONTAL) + nScrollInc = GetScrollPageSize(wxHORIZONTAL); + else + nScrollInc = GetScrollPageSize(wxVERTICAL); + } else + if ((event.GetEventType() == wxEVT_SCROLLWIN_THUMBTRACK) || + (event.GetEventType() == wxEVT_SCROLLWIN_THUMBRELEASE)) + { + if (orient == wxHORIZONTAL) + nScrollInc = pos - m_xScrollPosition; + else + nScrollInc = pos - m_yScrollPosition; + } + + if (orient == wxHORIZONTAL) + { + if (m_xScrollPixelsPerLine > 0) + { + if ( m_xScrollPosition + nScrollInc < 0 ) + { + // As -ve as we can go + nScrollInc = -m_xScrollPosition; + } + else // check for the other bound + { + const int posMax = m_xScrollLines - m_xScrollLinesPerPage; + if ( m_xScrollPosition + nScrollInc > posMax ) + { + // As +ve as we can go + nScrollInc = posMax - m_xScrollPosition; + } + } + } + else + m_targetWindow->Refresh(true, GetScrollRect()); + } + else + { + if ( m_yScrollPixelsPerLine > 0 ) + { + if ( m_yScrollPosition + nScrollInc < 0 ) + { + // As -ve as we can go + nScrollInc = -m_yScrollPosition; + } + else // check for the other bound + { + const int posMax = m_yScrollLines - m_yScrollLinesPerPage; + if ( m_yScrollPosition + nScrollInc > posMax ) + { + // As +ve as we can go + nScrollInc = posMax - m_yScrollPosition; + } + } + } + else + { + // VZ: why do we do this? (FIXME) + m_targetWindow->Refresh(true, GetScrollRect()); + } + } + + return nScrollInc; +} + +// Adjust the scrollbars - new version. +void wxScrollHelper::AdjustScrollbars() +{ + static wxRecursionGuardFlag s_flagReentrancy; + wxRecursionGuard guard(s_flagReentrancy); + if ( guard.IsInside() ) + { + // don't reenter AdjustScrollbars() while another call to + // AdjustScrollbars() is in progress because this may lead to calling + // ScrollWindow() twice and this can really happen under MSW if + // SetScrollbar() call below adds or removes the scrollbar which + // changes the window size and hence results in another + // AdjustScrollbars() call + return; + } + + int w = 0, h = 0; + int oldw, oldh; + + int oldXScroll = m_xScrollPosition; + int oldYScroll = m_yScrollPosition; + + // VZ: at least under Windows this loop is useless because when scrollbars + // [dis]appear we get a WM_SIZE resulting in another call to + // AdjustScrollbars() anyhow. As it doesn't seem to do any harm I leave + // it here for now but it would be better to ensure that all ports + // generate EVT_SIZE when scrollbars [dis]appear, emulating it if + // necessary, and remove it later + // JACS: Stop potential infinite loop by limiting number of iterations + int iterationCount = 0; + const int iterationMax = 5; + do + { + iterationCount ++; + + GetTargetSize(&w, 0); + + // scroll lines per page: if 0, no scrolling is needed + int linesPerPage; + + if ( m_xScrollPixelsPerLine == 0 ) + { + // scrolling is disabled + m_xScrollLines = 0; + m_xScrollPosition = 0; + linesPerPage = 0; + } + else // might need scrolling + { + // Round up integer division to catch any "leftover" client space. + const int wVirt = m_targetWindow->GetVirtualSize().GetWidth(); + m_xScrollLines = (wVirt + m_xScrollPixelsPerLine - 1) / m_xScrollPixelsPerLine; + + // Calculate page size i.e. number of scroll units you get on the + // current client window. + linesPerPage = w / m_xScrollPixelsPerLine; + + // Special case. When client and virtual size are very close but + // the client is big enough, kill scrollbar. + if ((linesPerPage < m_xScrollLines) && (w >= wVirt)) ++linesPerPage; + + if (linesPerPage >= m_xScrollLines) + { + // we're big enough to not need scrolling + linesPerPage = + m_xScrollLines = + m_xScrollPosition = 0; + } + else // we do need a scrollbar + { + if ( linesPerPage < 1 ) + linesPerPage = 1; + + // Correct position if greater than extent of canvas minus + // the visible portion of it or if below zero + const int posMax = m_xScrollLines - linesPerPage; + if ( m_xScrollPosition > posMax ) + m_xScrollPosition = posMax; + else if ( m_xScrollPosition < 0 ) + m_xScrollPosition = 0; + } + } + + m_win->SetScrollbar(wxHORIZONTAL, m_xScrollPosition, + linesPerPage, m_xScrollLines); + + // The amount by which we scroll when paging + SetScrollPageSize(wxHORIZONTAL, linesPerPage); + + GetTargetSize(0, &h); + + if ( m_yScrollPixelsPerLine == 0 ) + { + // scrolling is disabled + m_yScrollLines = 0; + m_yScrollPosition = 0; + linesPerPage = 0; + } + else // might need scrolling + { + // Round up integer division to catch any "leftover" client space. + const int hVirt = m_targetWindow->GetVirtualSize().GetHeight(); + m_yScrollLines = ( hVirt + m_yScrollPixelsPerLine - 1 ) / m_yScrollPixelsPerLine; + + // Calculate page size i.e. number of scroll units you get on the + // current client window. + linesPerPage = h / m_yScrollPixelsPerLine; + + // Special case. When client and virtual size are very close but + // the client is big enough, kill scrollbar. + if ((linesPerPage < m_yScrollLines) && (h >= hVirt)) ++linesPerPage; + + if (linesPerPage >= m_yScrollLines) + { + // we're big enough to not need scrolling + linesPerPage = + m_yScrollLines = + m_yScrollPosition = 0; + } + else // we do need a scrollbar + { + if ( linesPerPage < 1 ) + linesPerPage = 1; + + // Correct position if greater than extent of canvas minus + // the visible portion of it or if below zero + const int posMax = m_yScrollLines - linesPerPage; + if ( m_yScrollPosition > posMax ) + m_yScrollPosition = posMax; + else if ( m_yScrollPosition < 0 ) + m_yScrollPosition = 0; + } + } + + m_win->SetScrollbar(wxVERTICAL, m_yScrollPosition, + linesPerPage, m_yScrollLines); + + // The amount by which we scroll when paging + SetScrollPageSize(wxVERTICAL, linesPerPage); + + + // If a scrollbar (dis)appeared as a result of this, adjust them again. + oldw = w; + oldh = h; + + GetTargetSize( &w, &h ); + } while ( (w != oldw || h != oldh) && (iterationCount < iterationMax) ); + +#ifdef __WXMOTIF__ + // Sorry, some Motif-specific code to implement a backing pixmap + // for the wxRETAINED style. Implementing a backing store can't + // be entirely generic because it relies on the wxWindowDC implementation + // to duplicate X drawing calls for the backing pixmap. + + if ( m_targetWindow->GetWindowStyle() & wxRETAINED ) + { + Display* dpy = XtDisplay((Widget)m_targetWindow->GetMainWidget()); + + int totalPixelWidth = m_xScrollLines * m_xScrollPixelsPerLine; + int totalPixelHeight = m_yScrollLines * m_yScrollPixelsPerLine; + if (m_targetWindow->GetBackingPixmap() && + !((m_targetWindow->GetPixmapWidth() == totalPixelWidth) && + (m_targetWindow->GetPixmapHeight() == totalPixelHeight))) + { + XFreePixmap (dpy, (Pixmap) m_targetWindow->GetBackingPixmap()); + m_targetWindow->SetBackingPixmap((WXPixmap) 0); + } + + if (!m_targetWindow->GetBackingPixmap() && + (m_xScrollLines != 0) && (m_yScrollLines != 0)) + { + int depth = wxDisplayDepth(); + m_targetWindow->SetPixmapWidth(totalPixelWidth); + m_targetWindow->SetPixmapHeight(totalPixelHeight); + m_targetWindow->SetBackingPixmap((WXPixmap) XCreatePixmap (dpy, RootWindow (dpy, DefaultScreen (dpy)), + m_targetWindow->GetPixmapWidth(), m_targetWindow->GetPixmapHeight(), depth)); + } + + } +#endif // Motif + + if (oldXScroll != m_xScrollPosition) + { + if (m_xScrollingEnabled) + m_targetWindow->ScrollWindow( m_xScrollPixelsPerLine * (oldXScroll - m_xScrollPosition), 0, + GetScrollRect() ); + else + m_targetWindow->Refresh(true, GetScrollRect()); + } + + if (oldYScroll != m_yScrollPosition) + { + if (m_yScrollingEnabled) + m_targetWindow->ScrollWindow( 0, m_yScrollPixelsPerLine * (oldYScroll-m_yScrollPosition), + GetScrollRect() ); + else + m_targetWindow->Refresh(true, GetScrollRect()); + } +} + +void wxScrollHelper::DoPrepareDC(wxDC& dc) +{ + wxPoint pt = dc.GetDeviceOrigin(); +#ifdef __WXGTK__ + // It may actually be correct to always query + // the m_sign from the DC here, but I leve the + // #ifdef GTK for now. + if (m_win->GetLayoutDirection() == wxLayout_RightToLeft) + dc.SetDeviceOrigin( pt.x + m_xScrollPosition * m_xScrollPixelsPerLine, + pt.y - m_yScrollPosition * m_yScrollPixelsPerLine ); + else +#endif + dc.SetDeviceOrigin( pt.x - m_xScrollPosition * m_xScrollPixelsPerLine, + pt.y - m_yScrollPosition * m_yScrollPixelsPerLine ); + dc.SetUserScale( m_scaleX, m_scaleY ); +} + +void wxScrollHelper::SetScrollRate( int xstep, int ystep ) +{ + int old_x = m_xScrollPixelsPerLine * m_xScrollPosition; + int old_y = m_yScrollPixelsPerLine * m_yScrollPosition; + + m_xScrollPixelsPerLine = xstep; + m_yScrollPixelsPerLine = ystep; + + int new_x = m_xScrollPixelsPerLine * m_xScrollPosition; + int new_y = m_yScrollPixelsPerLine * m_yScrollPosition; + + m_win->SetScrollPos( wxHORIZONTAL, m_xScrollPosition ); + m_win->SetScrollPos( wxVERTICAL, m_yScrollPosition ); + m_targetWindow->ScrollWindow( old_x - new_x, old_y - new_y ); + + AdjustScrollbars(); +} + +void wxScrollHelper::GetScrollPixelsPerUnit (int *x_unit, int *y_unit) const +{ + if ( x_unit ) + *x_unit = m_xScrollPixelsPerLine; + if ( y_unit ) + *y_unit = m_yScrollPixelsPerLine; +} + + +int wxScrollHelper::GetScrollLines( int orient ) const +{ + if ( orient == wxHORIZONTAL ) + return m_xScrollLines; + else + return m_yScrollLines; +} + +int wxScrollHelper::GetScrollPageSize(int orient) const +{ + if ( orient == wxHORIZONTAL ) + return m_xScrollLinesPerPage; + else + return m_yScrollLinesPerPage; +} + +void wxScrollHelper::SetScrollPageSize(int orient, int pageSize) +{ + if ( orient == wxHORIZONTAL ) + m_xScrollLinesPerPage = pageSize; + else + m_yScrollLinesPerPage = pageSize; +} + +/* + * Scroll to given position (scroll position, not pixel position) + */ +void wxScrollHelper::Scroll( int x_pos, int y_pos ) +{ + if (!m_targetWindow) + return; + + if (((x_pos == -1) || (x_pos == m_xScrollPosition)) && + ((y_pos == -1) || (y_pos == m_yScrollPosition))) return; + + int w = 0, h = 0; + GetTargetSize(&w, &h); + + // compute new position: + int new_x = m_xScrollPosition; + int new_y = m_yScrollPosition; + + if ((x_pos != -1) && (m_xScrollPixelsPerLine)) + { + new_x = x_pos; + + // Calculate page size i.e. number of scroll units you get on the + // current client window + int noPagePositions = w/m_xScrollPixelsPerLine; + if (noPagePositions < 1) noPagePositions = 1; + + // Correct position if greater than extent of canvas minus + // the visible portion of it or if below zero + new_x = wxMin( m_xScrollLines-noPagePositions, new_x ); + new_x = wxMax( 0, new_x ); + } + if ((y_pos != -1) && (m_yScrollPixelsPerLine)) + { + new_y = y_pos; + + // Calculate page size i.e. number of scroll units you get on the + // current client window + int noPagePositions = h/m_yScrollPixelsPerLine; + if (noPagePositions < 1) noPagePositions = 1; + + // Correct position if greater than extent of canvas minus + // the visible portion of it or if below zero + new_y = wxMin( m_yScrollLines-noPagePositions, new_y ); + new_y = wxMax( 0, new_y ); + } + + if ( new_x == m_xScrollPosition && new_y == m_yScrollPosition ) + return; // nothing to do, the position didn't change + + // flush all pending repaints before we change m_{x,y}ScrollPosition, as + // otherwise invalidated area could be updated incorrectly later when + // ScrollWindow() makes sure they're repainted before scrolling them + m_targetWindow->Update(); + + // update the position and scroll the window now: + if (m_xScrollPosition != new_x) + { + int old_x = m_xScrollPosition; + m_xScrollPosition = new_x; + m_win->SetScrollPos( wxHORIZONTAL, new_x ); + m_targetWindow->ScrollWindow( (old_x-new_x)*m_xScrollPixelsPerLine, 0, + GetScrollRect() ); + } + + if (m_yScrollPosition != new_y) + { + int old_y = m_yScrollPosition; + m_yScrollPosition = new_y; + m_win->SetScrollPos( wxVERTICAL, new_y ); + m_targetWindow->ScrollWindow( 0, (old_y-new_y)*m_yScrollPixelsPerLine, + GetScrollRect() ); + } +} + +void wxScrollHelper::EnableScrolling (bool x_scroll, bool y_scroll) +{ + m_xScrollingEnabled = x_scroll; + m_yScrollingEnabled = y_scroll; +} + +// Where the current view starts from +void wxScrollHelper::GetViewStart (int *x, int *y) const +{ + if ( x ) + *x = m_xScrollPosition; + if ( y ) + *y = m_yScrollPosition; +} + +void wxScrollHelper::DoCalcScrolledPosition(int x, int y, int *xx, int *yy) const +{ + if ( xx ) + *xx = x - m_xScrollPosition * m_xScrollPixelsPerLine; + if ( yy ) + *yy = y - m_yScrollPosition * m_yScrollPixelsPerLine; +} + +void wxScrollHelper::DoCalcUnscrolledPosition(int x, int y, int *xx, int *yy) const +{ + if ( xx ) + *xx = x + m_xScrollPosition * m_xScrollPixelsPerLine; + if ( yy ) + *yy = y + m_yScrollPosition * m_yScrollPixelsPerLine; +} + +// ---------------------------------------------------------------------------- +// geometry +// ---------------------------------------------------------------------------- + +bool wxScrollHelper::ScrollLayout() +{ + if ( m_win->GetSizer() && m_targetWindow == m_win ) + { + // If we're the scroll target, take into account the + // virtual size and scrolled position of the window. + + int x = 0, y = 0, w = 0, h = 0; + CalcScrolledPosition(0,0, &x,&y); + m_win->GetVirtualSize(&w, &h); + m_win->GetSizer()->SetDimension(x, y, w, h); + return true; + } + + // fall back to default for LayoutConstraints + return m_win->wxWindow::Layout(); +} + +void wxScrollHelper::ScrollDoSetVirtualSize(int x, int y) +{ + m_win->wxWindow::DoSetVirtualSize( x, y ); + AdjustScrollbars(); + + if (m_win->GetAutoLayout()) + m_win->Layout(); +} + +// wxWindow's GetBestVirtualSize returns the actual window size, +// whereas we want to return the virtual size +wxSize wxScrollHelper::ScrollGetBestVirtualSize() const +{ + wxSize clientSize(m_win->GetClientSize()); + if ( m_win->GetSizer() ) + clientSize.IncTo(m_win->GetSizer()->CalcMin()); + + return clientSize; +} + +// return the window best size from the given best virtual size +wxSize +wxScrollHelper::ScrollGetWindowSizeForVirtualSize(const wxSize& size) const +{ + // Only use the content to set the window size in the direction + // where there's no scrolling; otherwise we're going to get a huge + // window in the direction in which scrolling is enabled + int ppuX, ppuY; + GetScrollPixelsPerUnit(&ppuX, &ppuY); + + wxSize minSize = m_win->GetMinSize(); + + wxSize best(size); + if (ppuX > 0) + best.x = minSize.x + wxSystemSettings::GetMetric(wxSYS_VSCROLL_X); + if (ppuY > 0) + best.y = minSize.y + wxSystemSettings::GetMetric(wxSYS_HSCROLL_Y); + + return best; +} + +// ---------------------------------------------------------------------------- +// event handlers +// ---------------------------------------------------------------------------- + +// Default OnSize resets scrollbars, if any +void wxScrollHelper::HandleOnSize(wxSizeEvent& WXUNUSED(event)) +{ + if ( m_targetWindow->GetAutoLayout() ) + { + wxSize size = m_targetWindow->GetBestVirtualSize(); + + // This will call ::Layout() and ::AdjustScrollbars() + m_win->SetVirtualSize( size ); + } + else + { + AdjustScrollbars(); + } +} + +// This calls OnDraw, having adjusted the origin according to the current +// scroll position +void wxScrollHelper::HandleOnPaint(wxPaintEvent& WXUNUSED(event)) +{ + // don't use m_targetWindow here, this is always called for ourselves + wxPaintDC dc(m_win); + DoPrepareDC(dc); + + OnDraw(dc); +} + +// kbd handling: notice that we use OnChar() and not OnKeyDown() for +// compatibility here - if we used OnKeyDown(), the programs which process +// arrows themselves in their OnChar() would never get the message and like +// this they always have the priority +void wxScrollHelper::HandleOnChar(wxKeyEvent& event) +{ + int stx = 0, sty = 0, // view origin + szx = 0, szy = 0, // view size (total) + clix = 0, cliy = 0; // view size (on screen) + + GetViewStart(&stx, &sty); + GetTargetSize(&clix, &cliy); + m_targetWindow->GetVirtualSize(&szx, &szy); + + if( m_xScrollPixelsPerLine ) + { + clix /= m_xScrollPixelsPerLine; + szx /= m_xScrollPixelsPerLine; + } + else + { + clix = 0; + szx = -1; + } + if( m_yScrollPixelsPerLine ) + { + cliy /= m_yScrollPixelsPerLine; + szy /= m_yScrollPixelsPerLine; + } + else + { + cliy = 0; + szy = -1; + } + + int xScrollOld = m_xScrollPosition, + yScrollOld = m_yScrollPosition; + + int dsty; + switch ( event.GetKeyCode() ) + { + case WXK_PAGEUP: + dsty = sty - (5 * cliy / 6); + Scroll(-1, (dsty == -1) ? 0 : dsty); + break; + + case WXK_PAGEDOWN: + Scroll(-1, sty + (5 * cliy / 6)); + break; + + case WXK_HOME: + Scroll(0, event.ControlDown() ? 0 : -1); + break; + + case WXK_END: + Scroll(szx - clix, event.ControlDown() ? szy - cliy : -1); + break; + + case WXK_UP: + Scroll(-1, sty - 1); + break; + + case WXK_DOWN: + Scroll(-1, sty + 1); + break; + + case WXK_LEFT: + Scroll(stx - 1, -1); + break; + + case WXK_RIGHT: + Scroll(stx + 1, -1); + break; + + default: + // not for us + event.Skip(); + } + + if ( m_xScrollPosition != xScrollOld ) + { + wxScrollWinEvent event(wxEVT_SCROLLWIN_THUMBTRACK, m_xScrollPosition, + wxHORIZONTAL); + event.SetEventObject(m_win); + m_win->GetEventHandler()->ProcessEvent(event); + } + + if ( m_yScrollPosition != yScrollOld ) + { + wxScrollWinEvent event(wxEVT_SCROLLWIN_THUMBTRACK, m_yScrollPosition, + wxVERTICAL); + event.SetEventObject(m_win); + m_win->GetEventHandler()->ProcessEvent(event); + } +} + +// ---------------------------------------------------------------------------- +// autoscroll stuff: these functions deal with sending fake scroll events when +// a captured mouse is being held outside the window +// ---------------------------------------------------------------------------- + +bool wxScrollHelper::SendAutoScrollEvents(wxScrollWinEvent& event) const +{ + // only send the event if the window is scrollable in this direction + wxWindow *win = (wxWindow *)event.GetEventObject(); + return win->HasScrollbar(event.GetOrientation()); +} + +void wxScrollHelper::StopAutoScrolling() +{ +#if wxUSE_TIMER + if ( m_timerAutoScroll ) + { + delete m_timerAutoScroll; + m_timerAutoScroll = (wxTimer *)NULL; + } +#endif +} + +void wxScrollHelper::HandleOnMouseEnter(wxMouseEvent& event) +{ + StopAutoScrolling(); + + event.Skip(); +} + +void wxScrollHelper::HandleOnMouseLeave(wxMouseEvent& event) +{ + // don't prevent the usual processing of the event from taking place + event.Skip(); + + // when a captured mouse leave a scrolled window we start generate + // scrolling events to allow, for example, extending selection beyond the + // visible area in some controls + if ( wxWindow::GetCapture() == m_targetWindow ) + { + // where is the mouse leaving? + int pos, orient; + wxPoint pt = event.GetPosition(); + if ( pt.x < 0 ) + { + orient = wxHORIZONTAL; + pos = 0; + } + else if ( pt.y < 0 ) + { + orient = wxVERTICAL; + pos = 0; + } + else // we're lower or to the right of the window + { + wxSize size = m_targetWindow->GetClientSize(); + if ( pt.x > size.x ) + { + orient = wxHORIZONTAL; + pos = m_xScrollLines; + } + else if ( pt.y > size.y ) + { + orient = wxVERTICAL; + pos = m_yScrollLines; + } + else // this should be impossible + { + // but seems to happen sometimes under wxMSW - maybe it's a bug + // there but for now just ignore it + + //wxFAIL_MSG( _T("can't understand where has mouse gone") ); + + return; + } + } + + // only start the auto scroll timer if the window can be scrolled in + // this direction + if ( !m_targetWindow->HasScrollbar(orient) ) + return; + +#if wxUSE_TIMER + delete m_timerAutoScroll; + m_timerAutoScroll = new wxAutoScrollTimer + ( + m_targetWindow, this, + pos == 0 ? wxEVT_SCROLLWIN_LINEUP + : wxEVT_SCROLLWIN_LINEDOWN, + pos, + orient + ); + m_timerAutoScroll->Start(50); // FIXME: make configurable +#else + wxUnusedVar(pos); +#endif + } +} + +#if wxUSE_MOUSEWHEEL + +void wxScrollHelper::HandleOnMouseWheel(wxMouseEvent& event) +{ + m_wheelRotation += event.GetWheelRotation(); + int lines = m_wheelRotation / event.GetWheelDelta(); + m_wheelRotation -= lines * event.GetWheelDelta(); + + if (lines != 0) + { + + wxScrollWinEvent newEvent; + + newEvent.SetPosition(0); + newEvent.SetOrientation(wxVERTICAL); + newEvent.SetEventObject(m_win); + + if (event.IsPageScroll()) + { + if (lines > 0) + newEvent.SetEventType(wxEVT_SCROLLWIN_PAGEUP); + else + newEvent.SetEventType(wxEVT_SCROLLWIN_PAGEDOWN); + + m_win->GetEventHandler()->ProcessEvent(newEvent); + } + else + { + lines *= event.GetLinesPerAction(); + if (lines > 0) + newEvent.SetEventType(wxEVT_SCROLLWIN_LINEUP); + else + newEvent.SetEventType(wxEVT_SCROLLWIN_LINEDOWN); + + int times = abs(lines); + for (; times > 0; times--) + m_win->GetEventHandler()->ProcessEvent(newEvent); + } + } +} + +#endif // wxUSE_MOUSEWHEEL + +void wxScrollHelper::HandleOnChildFocus(wxChildFocusEvent& event) +{ + // this event should be processed by all windows in parenthood chain, + // e.g. so that nested wxScrolledWindows work correctly + event.Skip(); + + // find the immediate child under which the window receiving focus is: + wxWindow *win = event.GetWindow(); + + if ( win == m_targetWindow ) + return; // nothing to do + + while ( win->GetParent() != m_targetWindow ) + { + win = win->GetParent(); + if ( !win ) + return; // event is not from a child of the target window + } + + // if the child is not fully visible, try to scroll it into view: + int stepx, stepy; + GetScrollPixelsPerUnit(&stepx, &stepy); + + // NB: we don't call CalcScrolledPosition() on win->GetPosition() here, + // because children' positions are already scrolled + wxRect winrect(win->GetPosition(), win->GetSize()); + wxSize view(m_targetWindow->GetClientSize()); + + int startx, starty; + GetViewStart(&startx, &starty); + + // first in vertical direction: + if ( stepy > 0 ) + { + int diff = 0; + + if ( winrect.GetTop() < 0 ) + { + diff = winrect.GetTop(); + } + else if ( winrect.GetBottom() > view.y ) + { + diff = winrect.GetBottom() - view.y + 1; + // round up to next scroll step if we can't get exact position, + // so that the window is fully visible: + diff += stepy - 1; + } + + starty = (starty * stepy + diff) / stepy; + } + + // then horizontal: + if ( stepx > 0 ) + { + int diff = 0; + + if ( winrect.GetLeft() < 0 ) + { + diff = winrect.GetLeft(); + } + else if ( winrect.GetRight() > view.x ) + { + diff = winrect.GetRight() - view.x + 1; + // round up to next scroll step if we can't get exact position, + // so that the window is fully visible: + diff += stepx - 1; + } + + startx = (startx * stepx + diff) / stepx; + } + + Scroll(startx, starty); +} + +// ---------------------------------------------------------------------------- +// wxScrolledWindow implementation +// ---------------------------------------------------------------------------- + +IMPLEMENT_DYNAMIC_CLASS(wxScrolledWindow, wxPanel) + +BEGIN_EVENT_TABLE(wxScrolledWindow, wxPanel) + EVT_PAINT(wxScrolledWindow::OnPaint) +END_EVENT_TABLE() + +bool wxScrolledWindow::Create(wxWindow *parent, + wxWindowID id, + const wxPoint& pos, + const wxSize& size, + long style, + const wxString& name) +{ + m_targetWindow = this; +#ifdef __WXMAC__ + MacSetClipChildren( true ) ; +#endif + + bool ok = wxPanel::Create(parent, id, pos, size, style|wxHSCROLL|wxVSCROLL, name); + + return ok; +} + +wxScrolledWindow::~wxScrolledWindow() +{ +} + +void wxScrolledWindow::OnPaint(wxPaintEvent& event) +{ + // the user code didn't really draw the window if we got here, so set this + // flag to try to call OnDraw() later + m_handler->ResetDrawnFlag(); + + event.Skip(); +} + +#ifdef __WXMSW__ +WXLRESULT wxScrolledWindow::MSWWindowProc(WXUINT nMsg, + WXWPARAM wParam, + WXLPARAM lParam) +{ + WXLRESULT rc = wxPanel::MSWWindowProc(nMsg, wParam, lParam); + +#ifndef __WXWINCE__ + // we need to process arrows ourselves for scrolling + if ( nMsg == WM_GETDLGCODE ) + { + rc |= DLGC_WANTARROWS; + } +#endif + + return rc; +} + +#endif // __WXMSW__ diff --git a/Externals/wxWidgets/src/generic/selstore.cpp b/Externals/wxWidgets/src/generic/selstore.cpp index 653de15114..2fbfc7b691 100644 --- a/Externals/wxWidgets/src/generic/selstore.cpp +++ b/Externals/wxWidgets/src/generic/selstore.cpp @@ -1,216 +1,216 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: generic/selstore.cpp -// Purpose: wxSelectionStore implementation -// Author: Vadim Zeitlin -// Modified by: -// Created: 08.06.03 (extracted from src/generic/listctrl.cpp) -// RCS-ID: $Id: selstore.cpp 27853 2004-06-17 16:22:36Z ABX $ -// Copyright: (c) 2000-2003 Vadim Zeitlin -// Licence: wxWindows licence -/////////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#include "wx/selstore.h" - -// ============================================================================ -// wxSelectionStore -// ============================================================================ - -// ---------------------------------------------------------------------------- -// tests -// ---------------------------------------------------------------------------- - -bool wxSelectionStore::IsSelected(size_t item) const -{ - bool isSel = m_itemsSel.Index(item) != wxNOT_FOUND; - - // if the default state is to be selected, being in m_itemsSel means that - // the item is not selected, so we have to inverse the logic - return m_defaultState ? !isSel : isSel; -} - -// ---------------------------------------------------------------------------- -// Select*() -// ---------------------------------------------------------------------------- - -bool wxSelectionStore::SelectItem(size_t item, bool select) -{ - // search for the item ourselves as like this we get the index where to - // insert it later if needed, so we do only one search in the array instead - // of two (adding item to a sorted array requires a search) - size_t index = m_itemsSel.IndexForInsert(item); - bool isSel = index < m_itemsSel.GetCount() && m_itemsSel[index] == item; - - if ( select != m_defaultState ) - { - if ( !isSel ) - { - m_itemsSel.AddAt(item, index); - - return true; - } - } - else // reset to default state - { - if ( isSel ) - { - m_itemsSel.RemoveAt(index); - return true; - } - } - - return false; -} - -bool wxSelectionStore::SelectRange(size_t itemFrom, size_t itemTo, - bool select, - wxArrayInt *itemsChanged) -{ - // 100 is hardcoded but it shouldn't matter much: the important thing is - // that we don't refresh everything when really few (e.g. 1 or 2) items - // change state - static const size_t MANY_ITEMS = 100; - - wxASSERT_MSG( itemFrom <= itemTo, _T("should be in order") ); - - // are we going to have more [un]selected items than the other ones? - if ( itemTo - itemFrom > m_count/2 ) - { - if ( select != m_defaultState ) - { - // the default state now becomes the same as 'select' - m_defaultState = select; - - // so all the old selections (which had state select) shouldn't be - // selected any more, but all the other ones should - wxSelectedIndices selOld = m_itemsSel; - m_itemsSel.Empty(); - - // TODO: it should be possible to optimize the searches a bit - // knowing the possible range - - size_t item; - for ( item = 0; item < itemFrom; item++ ) - { - if ( selOld.Index(item) == wxNOT_FOUND ) - m_itemsSel.Add(item); - } - - for ( item = itemTo + 1; item < m_count; item++ ) - { - if ( selOld.Index(item) == wxNOT_FOUND ) - m_itemsSel.Add(item); - } - - // many items (> half) changed state - itemsChanged = NULL; - } - else // select == m_defaultState - { - // get the inclusive range of items between itemFrom and itemTo - size_t count = m_itemsSel.GetCount(), - start = m_itemsSel.IndexForInsert(itemFrom), - end = m_itemsSel.IndexForInsert(itemTo); - - if ( start == count || m_itemsSel[start] < itemFrom ) - { - start++; - } - - if ( end == count || m_itemsSel[end] > itemTo ) - { - end--; - } - - if ( start <= end ) - { - // delete all of them (from end to avoid changing indices) - for ( int i = end; i >= (int)start; i-- ) - { - if ( itemsChanged ) - { - if ( itemsChanged->GetCount() > MANY_ITEMS ) - { - // stop counting (see comment below) - itemsChanged = NULL; - } - else - { - itemsChanged->Add(m_itemsSel[i]); - } - } - - m_itemsSel.RemoveAt(i); - } - } - } - } - else // "few" items change state - { - if ( itemsChanged ) - { - itemsChanged->Empty(); - } - - // just add the items to the selection - for ( size_t item = itemFrom; item <= itemTo; item++ ) - { - if ( SelectItem(item, select) && itemsChanged ) - { - itemsChanged->Add(item); - - if ( itemsChanged->GetCount() > MANY_ITEMS ) - { - // stop counting them, we'll just eat gobs of memory - // for nothing at all - faster to refresh everything in - // this case - itemsChanged = NULL; - } - } - } - } - - // we set it to NULL if there are many items changing state - return itemsChanged != NULL; -} - -// ---------------------------------------------------------------------------- -// callbacks -// ---------------------------------------------------------------------------- - -void wxSelectionStore::OnItemDelete(size_t item) -{ - size_t count = m_itemsSel.GetCount(), - i = m_itemsSel.IndexForInsert(item); - - if ( i < count && m_itemsSel[i] == item ) - { - // this item itself was in m_itemsSel, remove it from there - m_itemsSel.RemoveAt(i); - - count--; - } - - // and adjust the index of all which follow it - while ( i < count ) - { - // all following elements must be greater than the one we deleted - wxASSERT_MSG( m_itemsSel[i] > item, _T("logic error") ); - - m_itemsSel[i++]--; - } -} - +/////////////////////////////////////////////////////////////////////////////// +// Name: generic/selstore.cpp +// Purpose: wxSelectionStore implementation +// Author: Vadim Zeitlin +// Modified by: +// Created: 08.06.03 (extracted from src/generic/listctrl.cpp) +// RCS-ID: $Id: selstore.cpp 27853 2004-06-17 16:22:36Z ABX $ +// Copyright: (c) 2000-2003 Vadim Zeitlin +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#include "wx/selstore.h" + +// ============================================================================ +// wxSelectionStore +// ============================================================================ + +// ---------------------------------------------------------------------------- +// tests +// ---------------------------------------------------------------------------- + +bool wxSelectionStore::IsSelected(size_t item) const +{ + bool isSel = m_itemsSel.Index(item) != wxNOT_FOUND; + + // if the default state is to be selected, being in m_itemsSel means that + // the item is not selected, so we have to inverse the logic + return m_defaultState ? !isSel : isSel; +} + +// ---------------------------------------------------------------------------- +// Select*() +// ---------------------------------------------------------------------------- + +bool wxSelectionStore::SelectItem(size_t item, bool select) +{ + // search for the item ourselves as like this we get the index where to + // insert it later if needed, so we do only one search in the array instead + // of two (adding item to a sorted array requires a search) + size_t index = m_itemsSel.IndexForInsert(item); + bool isSel = index < m_itemsSel.GetCount() && m_itemsSel[index] == item; + + if ( select != m_defaultState ) + { + if ( !isSel ) + { + m_itemsSel.AddAt(item, index); + + return true; + } + } + else // reset to default state + { + if ( isSel ) + { + m_itemsSel.RemoveAt(index); + return true; + } + } + + return false; +} + +bool wxSelectionStore::SelectRange(size_t itemFrom, size_t itemTo, + bool select, + wxArrayInt *itemsChanged) +{ + // 100 is hardcoded but it shouldn't matter much: the important thing is + // that we don't refresh everything when really few (e.g. 1 or 2) items + // change state + static const size_t MANY_ITEMS = 100; + + wxASSERT_MSG( itemFrom <= itemTo, _T("should be in order") ); + + // are we going to have more [un]selected items than the other ones? + if ( itemTo - itemFrom > m_count/2 ) + { + if ( select != m_defaultState ) + { + // the default state now becomes the same as 'select' + m_defaultState = select; + + // so all the old selections (which had state select) shouldn't be + // selected any more, but all the other ones should + wxSelectedIndices selOld = m_itemsSel; + m_itemsSel.Empty(); + + // TODO: it should be possible to optimize the searches a bit + // knowing the possible range + + size_t item; + for ( item = 0; item < itemFrom; item++ ) + { + if ( selOld.Index(item) == wxNOT_FOUND ) + m_itemsSel.Add(item); + } + + for ( item = itemTo + 1; item < m_count; item++ ) + { + if ( selOld.Index(item) == wxNOT_FOUND ) + m_itemsSel.Add(item); + } + + // many items (> half) changed state + itemsChanged = NULL; + } + else // select == m_defaultState + { + // get the inclusive range of items between itemFrom and itemTo + size_t count = m_itemsSel.GetCount(), + start = m_itemsSel.IndexForInsert(itemFrom), + end = m_itemsSel.IndexForInsert(itemTo); + + if ( start == count || m_itemsSel[start] < itemFrom ) + { + start++; + } + + if ( end == count || m_itemsSel[end] > itemTo ) + { + end--; + } + + if ( start <= end ) + { + // delete all of them (from end to avoid changing indices) + for ( int i = end; i >= (int)start; i-- ) + { + if ( itemsChanged ) + { + if ( itemsChanged->GetCount() > MANY_ITEMS ) + { + // stop counting (see comment below) + itemsChanged = NULL; + } + else + { + itemsChanged->Add(m_itemsSel[i]); + } + } + + m_itemsSel.RemoveAt(i); + } + } + } + } + else // "few" items change state + { + if ( itemsChanged ) + { + itemsChanged->Empty(); + } + + // just add the items to the selection + for ( size_t item = itemFrom; item <= itemTo; item++ ) + { + if ( SelectItem(item, select) && itemsChanged ) + { + itemsChanged->Add(item); + + if ( itemsChanged->GetCount() > MANY_ITEMS ) + { + // stop counting them, we'll just eat gobs of memory + // for nothing at all - faster to refresh everything in + // this case + itemsChanged = NULL; + } + } + } + } + + // we set it to NULL if there are many items changing state + return itemsChanged != NULL; +} + +// ---------------------------------------------------------------------------- +// callbacks +// ---------------------------------------------------------------------------- + +void wxSelectionStore::OnItemDelete(size_t item) +{ + size_t count = m_itemsSel.GetCount(), + i = m_itemsSel.IndexForInsert(item); + + if ( i < count && m_itemsSel[i] == item ) + { + // this item itself was in m_itemsSel, remove it from there + m_itemsSel.RemoveAt(i); + + count--; + } + + // and adjust the index of all which follow it + while ( i < count ) + { + // all following elements must be greater than the one we deleted + wxASSERT_MSG( m_itemsSel[i] > item, _T("logic error") ); + + m_itemsSel[i++]--; + } +} + diff --git a/Externals/wxWidgets/src/generic/spinctlg.cpp b/Externals/wxWidgets/src/generic/spinctlg.cpp index 92f3eeea4f..68562ffb9a 100644 --- a/Externals/wxWidgets/src/generic/spinctlg.cpp +++ b/Externals/wxWidgets/src/generic/spinctlg.cpp @@ -1,391 +1,391 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: src/generic/spinctlg.cpp -// Purpose: implements wxSpinCtrl as a composite control -// Author: Vadim Zeitlin -// Modified by: -// Created: 29.01.01 -// RCS-ID: $Id: spinctlg.cpp 52582 2008-03-17 13:46:31Z VZ $ -// Copyright: (c) 2001 Vadim Zeitlin -// License: wxWindows licence -/////////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -// There are port-specific versions for MSW, GTK, OS/2 and Mac, so exclude the -// contents of this file in those cases -#if !(defined(__WXMSW__) || defined(__WXGTK__) || defined(__WXPM__) || \ - defined(__WXMAC__)) || defined(__WXUNIVERSAL__) - -#ifndef WX_PRECOMP - #include "wx/textctrl.h" -#endif //WX_PRECOMP - -#if wxUSE_SPINCTRL - -#include "wx/spinbutt.h" -#include "wx/spinctrl.h" - -// ---------------------------------------------------------------------------- -// constants -// ---------------------------------------------------------------------------- - -// the margin between the text control and the spin -static const wxCoord MARGIN = 2; - -// ---------------------------------------------------------------------------- -// wxSpinCtrlText: text control used by spin control -// ---------------------------------------------------------------------------- - -class wxSpinCtrlText : public wxTextCtrl -{ -public: - wxSpinCtrlText(wxSpinCtrl *spin, const wxString& value) - : wxTextCtrl(spin->GetParent(), wxID_ANY, value) - { - m_spin = spin; - - // remove the default minsize, the spinctrl will have one instead - SetSizeHints(wxDefaultCoord,wxDefaultCoord); - } - -protected: - void OnTextChange(wxCommandEvent& event) - { - int val; - if ( m_spin->GetTextValue(&val) ) - { - m_spin->GetSpinButton()->SetValue(val); - } - - event.Skip(); - } - - bool ProcessEvent(wxEvent &event) - { - // Hand button down events to wxSpinCtrl. Doesn't work. - if (event.GetEventType() == wxEVT_LEFT_DOWN && m_spin->ProcessEvent( event )) - return true; - - return wxTextCtrl::ProcessEvent( event ); - } - -private: - wxSpinCtrl *m_spin; - - DECLARE_EVENT_TABLE() -}; - -BEGIN_EVENT_TABLE(wxSpinCtrlText, wxTextCtrl) - EVT_TEXT(wxID_ANY, wxSpinCtrlText::OnTextChange) -END_EVENT_TABLE() - -// ---------------------------------------------------------------------------- -// wxSpinCtrlButton: spin button used by spin control -// ---------------------------------------------------------------------------- - -class wxSpinCtrlButton : public wxSpinButton -{ -public: - wxSpinCtrlButton(wxSpinCtrl *spin, int style) - : wxSpinButton(spin->GetParent()) - { - m_spin = spin; - - SetWindowStyle(style | wxSP_VERTICAL); - - // remove the default minsize, the spinctrl will have one instead - SetSizeHints(wxDefaultCoord,wxDefaultCoord); - } - -protected: - void OnSpinButton(wxSpinEvent& eventSpin) - { - m_spin->SetTextValue(eventSpin.GetPosition()); - - wxCommandEvent event(wxEVT_COMMAND_SPINCTRL_UPDATED, m_spin->GetId()); - event.SetEventObject(m_spin); - event.SetInt(eventSpin.GetPosition()); - - m_spin->GetEventHandler()->ProcessEvent(event); - - eventSpin.Skip(); - } - -private: - wxSpinCtrl *m_spin; - - DECLARE_EVENT_TABLE() -}; - -BEGIN_EVENT_TABLE(wxSpinCtrlButton, wxSpinButton) - EVT_SPIN(wxID_ANY, wxSpinCtrlButton::OnSpinButton) -END_EVENT_TABLE() - -IMPLEMENT_DYNAMIC_CLASS(wxSpinCtrl, wxControl) - -// ============================================================================ -// implementation -// ============================================================================ - -// ---------------------------------------------------------------------------- -// wxSpinCtrl creation -// ---------------------------------------------------------------------------- - -void wxSpinCtrl::Init() -{ - m_text = NULL; - m_btn = NULL; -} - -bool wxSpinCtrl::Create(wxWindow *parent, - wxWindowID id, - const wxString& value, - const wxPoint& pos, - const wxSize& size, - long style, - int min, - int max, - int initial, - const wxString& name) -{ - if ( !wxControl::Create(parent, id, wxDefaultPosition, wxDefaultSize, style, - wxDefaultValidator, name) ) - { - return false; - } - - // the string value overrides the numeric one (for backwards compatibility - // reasons and also because it is simpler to satisfy the string value which - // comes much sooner in the list of arguments and leave the initial - // parameter unspecified) - if ( !value.empty() ) - { - long l; - if ( value.ToLong(&l) ) - initial = l; - } - - m_text = new wxSpinCtrlText(this, value); - m_btn = new wxSpinCtrlButton(this, style); - - m_btn->SetRange(min, max); - m_btn->SetValue(initial); - SetInitialSize(size); - Move(pos); - - // have to disable this window to avoid interfering it with message - // processing to the text and the button... but pretend it is enabled to - // make IsEnabled() return true - wxControl::Enable(false); // don't use non virtual Disable() here! - m_isEnabled = true; - - // we don't even need to show this window itself - and not doing it avoids - // that it overwrites the text control - wxControl::Show(false); - m_isShown = true; - return true; -} - -wxSpinCtrl::~wxSpinCtrl() -{ - // delete the controls now, don't leave them alive even though they would - // still be eventually deleted by our parent - but it will be too late, the - // user code expects them to be gone now - delete m_text; - m_text = NULL ; - delete m_btn; - m_btn = NULL ; -} - -// ---------------------------------------------------------------------------- -// geometry -// ---------------------------------------------------------------------------- - -wxSize wxSpinCtrl::DoGetBestSize() const -{ - wxSize sizeBtn = m_btn->GetBestSize(), - sizeText = m_text->GetBestSize(); - - return wxSize(sizeBtn.x + sizeText.x + MARGIN, sizeText.y); -} - -void wxSpinCtrl::DoMoveWindow(int x, int y, int width, int height) -{ - wxControl::DoMoveWindow(x, y, width, height); - - // position the subcontrols inside the client area - wxSize sizeBtn = m_btn->GetSize(); - - wxCoord wText = width - sizeBtn.x; - m_text->SetSize(x, y, wText, height); - m_btn->SetSize(x + wText + MARGIN, y, wxDefaultCoord, height); -} - -// ---------------------------------------------------------------------------- -// operations forwarded to the subcontrols -// ---------------------------------------------------------------------------- - -bool wxSpinCtrl::Enable(bool enable) -{ - if ( !wxControl::Enable(enable) ) - return false; - - m_btn->Enable(enable); - m_text->Enable(enable); - - return true; -} - -bool wxSpinCtrl::Show(bool show) -{ - if ( !wxControl::Show(show) ) - return false; - - // under GTK Show() is called the first time before we are fully - // constructed - if ( m_btn ) - { - m_btn->Show(show); - m_text->Show(show); - } - - return true; -} - -bool wxSpinCtrl::Reparent(wxWindow *newParent) -{ - if ( m_btn ) - { - m_btn->Reparent(newParent); - m_text->Reparent(newParent); - } - - return true; -} - -// ---------------------------------------------------------------------------- -// value and range access -// ---------------------------------------------------------------------------- - -bool wxSpinCtrl::GetTextValue(int *val) const -{ - long l; - if ( !m_text->GetValue().ToLong(&l) ) - { - // not a number at all - return false; - } - - if ( l < GetMin() || l > GetMax() ) - { - // out of range - return false; - } - - *val = l; - - return true; -} - -int wxSpinCtrl::GetValue() const -{ - return m_btn ? m_btn->GetValue() : 0; -} - -int wxSpinCtrl::GetMin() const -{ - return m_btn ? m_btn->GetMin() : 0; -} - -int wxSpinCtrl::GetMax() const -{ - return m_btn ? m_btn->GetMax() : 0; -} - -// ---------------------------------------------------------------------------- -// changing value and range -// ---------------------------------------------------------------------------- - -void wxSpinCtrl::SetTextValue(int val) -{ - wxCHECK_RET( m_text, _T("invalid call to wxSpinCtrl::SetTextValue") ); - - m_text->SetValue(wxString::Format(_T("%d"), val)); - - // select all text - m_text->SetSelection(0, -1); - - // and give focus to the control! - // m_text->SetFocus(); Why???? TODO. - -#ifdef __WXCOCOA__ - /* It's sort of a hack to do this from here but the idea is that if the - user has clicked on us, which is the main reason this method is called, - then focus probably ought to go to the text control since clicking on - a text control usually gives it focus. - - However, if the focus is already on us (i.e. the user has turned on - the ability to tab to controls) then we don't want to drop focus. - So we only set focus if we would steal it away from a different - control, not if we would steal it away from ourself. - */ - wxWindow *currentFocusedWindow = wxWindow::FindFocus(); - if(currentFocusedWindow != this && currentFocusedWindow != m_text) - m_text->SetFocus(); -#endif -} - -void wxSpinCtrl::SetValue(int val) -{ - wxCHECK_RET( m_btn, _T("invalid call to wxSpinCtrl::SetValue") ); - - SetTextValue(val); - - m_btn->SetValue(val); -} - -void wxSpinCtrl::SetValue(const wxString& text) -{ - wxCHECK_RET( m_text, _T("invalid call to wxSpinCtrl::SetValue") ); - - long val; - if ( text.ToLong(&val) && ((val > INT_MIN) && (val < INT_MAX)) ) - { - SetValue((int)val); - } - else // not a number at all or out of range - { - m_text->SetValue(text); - m_text->SetSelection(0, -1); - } -} - -void wxSpinCtrl::SetRange(int min, int max) -{ - wxCHECK_RET( m_btn, _T("invalid call to wxSpinCtrl::SetRange") ); - - m_btn->SetRange(min, max); -} - -void wxSpinCtrl::SetSelection(long from, long to) -{ - wxCHECK_RET( m_text, _T("invalid call to wxSpinCtrl::SetSelection") ); - - m_text->SetSelection(from, to); -} - -#endif // wxUSE_SPINCTRL -#endif // !wxPort-with-native-spinctrl +/////////////////////////////////////////////////////////////////////////////// +// Name: src/generic/spinctlg.cpp +// Purpose: implements wxSpinCtrl as a composite control +// Author: Vadim Zeitlin +// Modified by: +// Created: 29.01.01 +// RCS-ID: $Id: spinctlg.cpp 52582 2008-03-17 13:46:31Z VZ $ +// Copyright: (c) 2001 Vadim Zeitlin +// License: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +// There are port-specific versions for MSW, GTK, OS/2 and Mac, so exclude the +// contents of this file in those cases +#if !(defined(__WXMSW__) || defined(__WXGTK__) || defined(__WXPM__) || \ + defined(__WXMAC__)) || defined(__WXUNIVERSAL__) + +#ifndef WX_PRECOMP + #include "wx/textctrl.h" +#endif //WX_PRECOMP + +#if wxUSE_SPINCTRL + +#include "wx/spinbutt.h" +#include "wx/spinctrl.h" + +// ---------------------------------------------------------------------------- +// constants +// ---------------------------------------------------------------------------- + +// the margin between the text control and the spin +static const wxCoord MARGIN = 2; + +// ---------------------------------------------------------------------------- +// wxSpinCtrlText: text control used by spin control +// ---------------------------------------------------------------------------- + +class wxSpinCtrlText : public wxTextCtrl +{ +public: + wxSpinCtrlText(wxSpinCtrl *spin, const wxString& value) + : wxTextCtrl(spin->GetParent(), wxID_ANY, value) + { + m_spin = spin; + + // remove the default minsize, the spinctrl will have one instead + SetSizeHints(wxDefaultCoord,wxDefaultCoord); + } + +protected: + void OnTextChange(wxCommandEvent& event) + { + int val; + if ( m_spin->GetTextValue(&val) ) + { + m_spin->GetSpinButton()->SetValue(val); + } + + event.Skip(); + } + + bool ProcessEvent(wxEvent &event) + { + // Hand button down events to wxSpinCtrl. Doesn't work. + if (event.GetEventType() == wxEVT_LEFT_DOWN && m_spin->ProcessEvent( event )) + return true; + + return wxTextCtrl::ProcessEvent( event ); + } + +private: + wxSpinCtrl *m_spin; + + DECLARE_EVENT_TABLE() +}; + +BEGIN_EVENT_TABLE(wxSpinCtrlText, wxTextCtrl) + EVT_TEXT(wxID_ANY, wxSpinCtrlText::OnTextChange) +END_EVENT_TABLE() + +// ---------------------------------------------------------------------------- +// wxSpinCtrlButton: spin button used by spin control +// ---------------------------------------------------------------------------- + +class wxSpinCtrlButton : public wxSpinButton +{ +public: + wxSpinCtrlButton(wxSpinCtrl *spin, int style) + : wxSpinButton(spin->GetParent()) + { + m_spin = spin; + + SetWindowStyle(style | wxSP_VERTICAL); + + // remove the default minsize, the spinctrl will have one instead + SetSizeHints(wxDefaultCoord,wxDefaultCoord); + } + +protected: + void OnSpinButton(wxSpinEvent& eventSpin) + { + m_spin->SetTextValue(eventSpin.GetPosition()); + + wxCommandEvent event(wxEVT_COMMAND_SPINCTRL_UPDATED, m_spin->GetId()); + event.SetEventObject(m_spin); + event.SetInt(eventSpin.GetPosition()); + + m_spin->GetEventHandler()->ProcessEvent(event); + + eventSpin.Skip(); + } + +private: + wxSpinCtrl *m_spin; + + DECLARE_EVENT_TABLE() +}; + +BEGIN_EVENT_TABLE(wxSpinCtrlButton, wxSpinButton) + EVT_SPIN(wxID_ANY, wxSpinCtrlButton::OnSpinButton) +END_EVENT_TABLE() + +IMPLEMENT_DYNAMIC_CLASS(wxSpinCtrl, wxControl) + +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// wxSpinCtrl creation +// ---------------------------------------------------------------------------- + +void wxSpinCtrl::Init() +{ + m_text = NULL; + m_btn = NULL; +} + +bool wxSpinCtrl::Create(wxWindow *parent, + wxWindowID id, + const wxString& value, + const wxPoint& pos, + const wxSize& size, + long style, + int min, + int max, + int initial, + const wxString& name) +{ + if ( !wxControl::Create(parent, id, wxDefaultPosition, wxDefaultSize, style, + wxDefaultValidator, name) ) + { + return false; + } + + // the string value overrides the numeric one (for backwards compatibility + // reasons and also because it is simpler to satisfy the string value which + // comes much sooner in the list of arguments and leave the initial + // parameter unspecified) + if ( !value.empty() ) + { + long l; + if ( value.ToLong(&l) ) + initial = l; + } + + m_text = new wxSpinCtrlText(this, value); + m_btn = new wxSpinCtrlButton(this, style); + + m_btn->SetRange(min, max); + m_btn->SetValue(initial); + SetInitialSize(size); + Move(pos); + + // have to disable this window to avoid interfering it with message + // processing to the text and the button... but pretend it is enabled to + // make IsEnabled() return true + wxControl::Enable(false); // don't use non virtual Disable() here! + m_isEnabled = true; + + // we don't even need to show this window itself - and not doing it avoids + // that it overwrites the text control + wxControl::Show(false); + m_isShown = true; + return true; +} + +wxSpinCtrl::~wxSpinCtrl() +{ + // delete the controls now, don't leave them alive even though they would + // still be eventually deleted by our parent - but it will be too late, the + // user code expects them to be gone now + delete m_text; + m_text = NULL ; + delete m_btn; + m_btn = NULL ; +} + +// ---------------------------------------------------------------------------- +// geometry +// ---------------------------------------------------------------------------- + +wxSize wxSpinCtrl::DoGetBestSize() const +{ + wxSize sizeBtn = m_btn->GetBestSize(), + sizeText = m_text->GetBestSize(); + + return wxSize(sizeBtn.x + sizeText.x + MARGIN, sizeText.y); +} + +void wxSpinCtrl::DoMoveWindow(int x, int y, int width, int height) +{ + wxControl::DoMoveWindow(x, y, width, height); + + // position the subcontrols inside the client area + wxSize sizeBtn = m_btn->GetSize(); + + wxCoord wText = width - sizeBtn.x; + m_text->SetSize(x, y, wText, height); + m_btn->SetSize(x + wText + MARGIN, y, wxDefaultCoord, height); +} + +// ---------------------------------------------------------------------------- +// operations forwarded to the subcontrols +// ---------------------------------------------------------------------------- + +bool wxSpinCtrl::Enable(bool enable) +{ + if ( !wxControl::Enable(enable) ) + return false; + + m_btn->Enable(enable); + m_text->Enable(enable); + + return true; +} + +bool wxSpinCtrl::Show(bool show) +{ + if ( !wxControl::Show(show) ) + return false; + + // under GTK Show() is called the first time before we are fully + // constructed + if ( m_btn ) + { + m_btn->Show(show); + m_text->Show(show); + } + + return true; +} + +bool wxSpinCtrl::Reparent(wxWindow *newParent) +{ + if ( m_btn ) + { + m_btn->Reparent(newParent); + m_text->Reparent(newParent); + } + + return true; +} + +// ---------------------------------------------------------------------------- +// value and range access +// ---------------------------------------------------------------------------- + +bool wxSpinCtrl::GetTextValue(int *val) const +{ + long l; + if ( !m_text->GetValue().ToLong(&l) ) + { + // not a number at all + return false; + } + + if ( l < GetMin() || l > GetMax() ) + { + // out of range + return false; + } + + *val = l; + + return true; +} + +int wxSpinCtrl::GetValue() const +{ + return m_btn ? m_btn->GetValue() : 0; +} + +int wxSpinCtrl::GetMin() const +{ + return m_btn ? m_btn->GetMin() : 0; +} + +int wxSpinCtrl::GetMax() const +{ + return m_btn ? m_btn->GetMax() : 0; +} + +// ---------------------------------------------------------------------------- +// changing value and range +// ---------------------------------------------------------------------------- + +void wxSpinCtrl::SetTextValue(int val) +{ + wxCHECK_RET( m_text, _T("invalid call to wxSpinCtrl::SetTextValue") ); + + m_text->SetValue(wxString::Format(_T("%d"), val)); + + // select all text + m_text->SetSelection(0, -1); + + // and give focus to the control! + // m_text->SetFocus(); Why???? TODO. + +#ifdef __WXCOCOA__ + /* It's sort of a hack to do this from here but the idea is that if the + user has clicked on us, which is the main reason this method is called, + then focus probably ought to go to the text control since clicking on + a text control usually gives it focus. + + However, if the focus is already on us (i.e. the user has turned on + the ability to tab to controls) then we don't want to drop focus. + So we only set focus if we would steal it away from a different + control, not if we would steal it away from ourself. + */ + wxWindow *currentFocusedWindow = wxWindow::FindFocus(); + if(currentFocusedWindow != this && currentFocusedWindow != m_text) + m_text->SetFocus(); +#endif +} + +void wxSpinCtrl::SetValue(int val) +{ + wxCHECK_RET( m_btn, _T("invalid call to wxSpinCtrl::SetValue") ); + + SetTextValue(val); + + m_btn->SetValue(val); +} + +void wxSpinCtrl::SetValue(const wxString& text) +{ + wxCHECK_RET( m_text, _T("invalid call to wxSpinCtrl::SetValue") ); + + long val; + if ( text.ToLong(&val) && ((val > INT_MIN) && (val < INT_MAX)) ) + { + SetValue((int)val); + } + else // not a number at all or out of range + { + m_text->SetValue(text); + m_text->SetSelection(0, -1); + } +} + +void wxSpinCtrl::SetRange(int min, int max) +{ + wxCHECK_RET( m_btn, _T("invalid call to wxSpinCtrl::SetRange") ); + + m_btn->SetRange(min, max); +} + +void wxSpinCtrl::SetSelection(long from, long to) +{ + wxCHECK_RET( m_text, _T("invalid call to wxSpinCtrl::SetSelection") ); + + m_text->SetSelection(from, to); +} + +#endif // wxUSE_SPINCTRL +#endif // !wxPort-with-native-spinctrl diff --git a/Externals/wxWidgets/src/generic/splash.cpp b/Externals/wxWidgets/src/generic/splash.cpp index 74512a9976..d76a73ffef 100644 --- a/Externals/wxWidgets/src/generic/splash.cpp +++ b/Externals/wxWidgets/src/generic/splash.cpp @@ -1,201 +1,201 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/generic/splash.cpp -// Purpose: wxSplashScreen class -// Author: Julian Smart -// Modified by: -// Created: 28/6/2000 -// RCS-ID: $Id: splash.cpp 42755 2006-10-30 19:41:46Z VZ $ -// Copyright: (c) Julian Smart -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx/wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_SPLASH - -#ifdef __WXGTK20__ - #include -#endif - -#include "wx/splash.h" - -#ifndef WX_PRECOMP - #include "wx/dcmemory.h" - #include "wx/dcclient.h" -#endif - -/* - * wxSplashScreen - */ - -#define wxSPLASH_TIMER_ID 9999 - -IMPLEMENT_DYNAMIC_CLASS(wxSplashScreen, wxFrame) - -BEGIN_EVENT_TABLE(wxSplashScreen, wxFrame) - EVT_TIMER(wxSPLASH_TIMER_ID, wxSplashScreen::OnNotify) - EVT_CLOSE(wxSplashScreen::OnCloseWindow) -END_EVENT_TABLE() - -/* Note that unless we pass a non-default size to the frame, SetClientSize - * won't work properly under Windows, and the splash screen frame is sized - * slightly too small. - */ - -wxSplashScreen::wxSplashScreen(const wxBitmap& bitmap, long splashStyle, int milliseconds, wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style): - wxFrame(parent, id, wxEmptyString, wxPoint(0,0), wxSize(100, 100), style) -{ - // At least for GTK+ 2.0, this hint is not available. -#if defined(__WXGTK20__) -#if GTK_CHECK_VERSION(2,2,0) - gtk_window_set_type_hint(GTK_WINDOW(m_widget), - GDK_WINDOW_TYPE_HINT_SPLASHSCREEN); -#endif -#endif - - m_window = NULL; - m_splashStyle = splashStyle; - m_milliseconds = milliseconds; - - m_window = new wxSplashScreenWindow(bitmap, this, wxID_ANY, pos, size, wxNO_BORDER); - - SetClientSize(bitmap.GetWidth(), bitmap.GetHeight()); - - if (m_splashStyle & wxSPLASH_CENTRE_ON_PARENT) - CentreOnParent(); - else if (m_splashStyle & wxSPLASH_CENTRE_ON_SCREEN) - CentreOnScreen(); - - if (m_splashStyle & wxSPLASH_TIMEOUT) - { - m_timer.SetOwner(this, wxSPLASH_TIMER_ID); - m_timer.Start(milliseconds, true); - } - - Show(true); - m_window->SetFocus(); -#if defined( __WXMSW__ ) || defined(__WXMAC__) - Update(); // Without this, you see a blank screen for an instant -#else - wxYieldIfNeeded(); // Should eliminate this -#endif -} - -wxSplashScreen::~wxSplashScreen() -{ - m_timer.Stop(); -} - -void wxSplashScreen::OnNotify(wxTimerEvent& WXUNUSED(event)) -{ - Close(true); -} - -void wxSplashScreen::OnCloseWindow(wxCloseEvent& WXUNUSED(event)) -{ - m_timer.Stop(); - this->Destroy(); -} - -/* - * wxSplashScreenWindow - */ - -BEGIN_EVENT_TABLE(wxSplashScreenWindow, wxWindow) -#ifdef __WXGTK__ - EVT_PAINT(wxSplashScreenWindow::OnPaint) -#endif - EVT_ERASE_BACKGROUND(wxSplashScreenWindow::OnEraseBackground) - EVT_CHAR(wxSplashScreenWindow::OnChar) - EVT_MOUSE_EVENTS(wxSplashScreenWindow::OnMouseEvent) -END_EVENT_TABLE() - -wxSplashScreenWindow::wxSplashScreenWindow(const wxBitmap& bitmap, wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style): - wxWindow(parent, id, pos, size, style) -{ - m_bitmap = bitmap; - -#if !defined(__WXGTK__) && wxUSE_PALETTE - bool hiColour = (wxDisplayDepth() >= 16) ; - - if (bitmap.GetPalette() && !hiColour) - { - SetPalette(* bitmap.GetPalette()); - } -#endif - -} - -// VZ: why don't we do it under wxGTK? -#if !defined(__WXGTK__) && wxUSE_PALETTE - #define USE_PALETTE_IN_SPLASH -#endif - -static void wxDrawSplashBitmap(wxDC& dc, const wxBitmap& bitmap, int WXUNUSED(x), int WXUNUSED(y)) -{ - wxMemoryDC dcMem; - -#ifdef USE_PALETTE_IN_SPLASH - bool hiColour = (wxDisplayDepth() >= 16) ; - - if (bitmap.GetPalette() && !hiColour) - { - dcMem.SetPalette(* bitmap.GetPalette()); - } -#endif // USE_PALETTE_IN_SPLASH - - dcMem.SelectObjectAsSource(bitmap); - dc.Blit(0, 0, bitmap.GetWidth(), bitmap.GetHeight(), & dcMem, 0, 0); - dcMem.SelectObject(wxNullBitmap); - -#ifdef USE_PALETTE_IN_SPLASH - if (bitmap.GetPalette() && !hiColour) - { - dcMem.SetPalette(wxNullPalette); - } -#endif // USE_PALETTE_IN_SPLASH -} - -void wxSplashScreenWindow::OnPaint(wxPaintEvent& WXUNUSED(event)) -{ - wxPaintDC dc(this); - if (m_bitmap.Ok()) - wxDrawSplashBitmap(dc, m_bitmap, 0, 0); -} - -void wxSplashScreenWindow::OnEraseBackground(wxEraseEvent& event) -{ - if (event.GetDC()) - { - if (m_bitmap.Ok()) - { - wxDrawSplashBitmap(* event.GetDC(), m_bitmap, 0, 0); - } - } - else - { - wxClientDC dc(this); - if (m_bitmap.Ok()) - { - wxDrawSplashBitmap(dc, m_bitmap, 0, 0); - } - } -} - -void wxSplashScreenWindow::OnMouseEvent(wxMouseEvent& event) -{ - if (event.LeftDown() || event.RightDown()) - GetParent()->Close(true); -} - -void wxSplashScreenWindow::OnChar(wxKeyEvent& WXUNUSED(event)) -{ - GetParent()->Close(true); -} - -#endif // wxUSE_SPLASH +///////////////////////////////////////////////////////////////////////////// +// Name: src/generic/splash.cpp +// Purpose: wxSplashScreen class +// Author: Julian Smart +// Modified by: +// Created: 28/6/2000 +// RCS-ID: $Id: splash.cpp 42755 2006-10-30 19:41:46Z VZ $ +// Copyright: (c) Julian Smart +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx/wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_SPLASH + +#ifdef __WXGTK20__ + #include +#endif + +#include "wx/splash.h" + +#ifndef WX_PRECOMP + #include "wx/dcmemory.h" + #include "wx/dcclient.h" +#endif + +/* + * wxSplashScreen + */ + +#define wxSPLASH_TIMER_ID 9999 + +IMPLEMENT_DYNAMIC_CLASS(wxSplashScreen, wxFrame) + +BEGIN_EVENT_TABLE(wxSplashScreen, wxFrame) + EVT_TIMER(wxSPLASH_TIMER_ID, wxSplashScreen::OnNotify) + EVT_CLOSE(wxSplashScreen::OnCloseWindow) +END_EVENT_TABLE() + +/* Note that unless we pass a non-default size to the frame, SetClientSize + * won't work properly under Windows, and the splash screen frame is sized + * slightly too small. + */ + +wxSplashScreen::wxSplashScreen(const wxBitmap& bitmap, long splashStyle, int milliseconds, wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style): + wxFrame(parent, id, wxEmptyString, wxPoint(0,0), wxSize(100, 100), style) +{ + // At least for GTK+ 2.0, this hint is not available. +#if defined(__WXGTK20__) +#if GTK_CHECK_VERSION(2,2,0) + gtk_window_set_type_hint(GTK_WINDOW(m_widget), + GDK_WINDOW_TYPE_HINT_SPLASHSCREEN); +#endif +#endif + + m_window = NULL; + m_splashStyle = splashStyle; + m_milliseconds = milliseconds; + + m_window = new wxSplashScreenWindow(bitmap, this, wxID_ANY, pos, size, wxNO_BORDER); + + SetClientSize(bitmap.GetWidth(), bitmap.GetHeight()); + + if (m_splashStyle & wxSPLASH_CENTRE_ON_PARENT) + CentreOnParent(); + else if (m_splashStyle & wxSPLASH_CENTRE_ON_SCREEN) + CentreOnScreen(); + + if (m_splashStyle & wxSPLASH_TIMEOUT) + { + m_timer.SetOwner(this, wxSPLASH_TIMER_ID); + m_timer.Start(milliseconds, true); + } + + Show(true); + m_window->SetFocus(); +#if defined( __WXMSW__ ) || defined(__WXMAC__) + Update(); // Without this, you see a blank screen for an instant +#else + wxYieldIfNeeded(); // Should eliminate this +#endif +} + +wxSplashScreen::~wxSplashScreen() +{ + m_timer.Stop(); +} + +void wxSplashScreen::OnNotify(wxTimerEvent& WXUNUSED(event)) +{ + Close(true); +} + +void wxSplashScreen::OnCloseWindow(wxCloseEvent& WXUNUSED(event)) +{ + m_timer.Stop(); + this->Destroy(); +} + +/* + * wxSplashScreenWindow + */ + +BEGIN_EVENT_TABLE(wxSplashScreenWindow, wxWindow) +#ifdef __WXGTK__ + EVT_PAINT(wxSplashScreenWindow::OnPaint) +#endif + EVT_ERASE_BACKGROUND(wxSplashScreenWindow::OnEraseBackground) + EVT_CHAR(wxSplashScreenWindow::OnChar) + EVT_MOUSE_EVENTS(wxSplashScreenWindow::OnMouseEvent) +END_EVENT_TABLE() + +wxSplashScreenWindow::wxSplashScreenWindow(const wxBitmap& bitmap, wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style): + wxWindow(parent, id, pos, size, style) +{ + m_bitmap = bitmap; + +#if !defined(__WXGTK__) && wxUSE_PALETTE + bool hiColour = (wxDisplayDepth() >= 16) ; + + if (bitmap.GetPalette() && !hiColour) + { + SetPalette(* bitmap.GetPalette()); + } +#endif + +} + +// VZ: why don't we do it under wxGTK? +#if !defined(__WXGTK__) && wxUSE_PALETTE + #define USE_PALETTE_IN_SPLASH +#endif + +static void wxDrawSplashBitmap(wxDC& dc, const wxBitmap& bitmap, int WXUNUSED(x), int WXUNUSED(y)) +{ + wxMemoryDC dcMem; + +#ifdef USE_PALETTE_IN_SPLASH + bool hiColour = (wxDisplayDepth() >= 16) ; + + if (bitmap.GetPalette() && !hiColour) + { + dcMem.SetPalette(* bitmap.GetPalette()); + } +#endif // USE_PALETTE_IN_SPLASH + + dcMem.SelectObjectAsSource(bitmap); + dc.Blit(0, 0, bitmap.GetWidth(), bitmap.GetHeight(), & dcMem, 0, 0); + dcMem.SelectObject(wxNullBitmap); + +#ifdef USE_PALETTE_IN_SPLASH + if (bitmap.GetPalette() && !hiColour) + { + dcMem.SetPalette(wxNullPalette); + } +#endif // USE_PALETTE_IN_SPLASH +} + +void wxSplashScreenWindow::OnPaint(wxPaintEvent& WXUNUSED(event)) +{ + wxPaintDC dc(this); + if (m_bitmap.Ok()) + wxDrawSplashBitmap(dc, m_bitmap, 0, 0); +} + +void wxSplashScreenWindow::OnEraseBackground(wxEraseEvent& event) +{ + if (event.GetDC()) + { + if (m_bitmap.Ok()) + { + wxDrawSplashBitmap(* event.GetDC(), m_bitmap, 0, 0); + } + } + else + { + wxClientDC dc(this); + if (m_bitmap.Ok()) + { + wxDrawSplashBitmap(dc, m_bitmap, 0, 0); + } + } +} + +void wxSplashScreenWindow::OnMouseEvent(wxMouseEvent& event) +{ + if (event.LeftDown() || event.RightDown()) + GetParent()->Close(true); +} + +void wxSplashScreenWindow::OnChar(wxKeyEvent& WXUNUSED(event)) +{ + GetParent()->Close(true); +} + +#endif // wxUSE_SPLASH diff --git a/Externals/wxWidgets/src/generic/splitter.cpp b/Externals/wxWidgets/src/generic/splitter.cpp index b72014c38c..854ba081e4 100644 --- a/Externals/wxWidgets/src/generic/splitter.cpp +++ b/Externals/wxWidgets/src/generic/splitter.cpp @@ -1,1049 +1,1049 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/generic/splitter.cpp -// Purpose: wxSplitterWindow implementation -// Author: Julian Smart -// Modified by: -// Created: 01/02/97 -// RCS-ID: $Id: splitter.cpp 42816 2006-10-31 08:50:17Z RD $ -// Copyright: (c) Julian Smart -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_SPLITTER - -#include "wx/splitter.h" - -#ifndef WX_PRECOMP - #include "wx/string.h" - #include "wx/utils.h" - #include "wx/log.h" - - #include "wx/dcclient.h" - #include "wx/dcscreen.h" - - #include "wx/window.h" - #include "wx/dialog.h" - #include "wx/frame.h" - - #include "wx/settings.h" -#endif - -#include "wx/renderer.h" - -#include - -DEFINE_EVENT_TYPE(wxEVT_COMMAND_SPLITTER_SASH_POS_CHANGED) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_SPLITTER_SASH_POS_CHANGING) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_SPLITTER_DOUBLECLICKED) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_SPLITTER_UNSPLIT) - -IMPLEMENT_DYNAMIC_CLASS(wxSplitterWindow, wxWindow) - -/* - TODO PROPERTIES - style wxSP_3D - sashpos (long , 0 ) - minsize (long -1 ) - object, object_ref - orientation -*/ - -IMPLEMENT_DYNAMIC_CLASS(wxSplitterEvent, wxNotifyEvent) - -BEGIN_EVENT_TABLE(wxSplitterWindow, wxWindow) - EVT_PAINT(wxSplitterWindow::OnPaint) - EVT_SIZE(wxSplitterWindow::OnSize) - EVT_MOUSE_EVENTS(wxSplitterWindow::OnMouseEvent) - -#if defined( __WXMSW__ ) || defined( __WXMAC__) - EVT_SET_CURSOR(wxSplitterWindow::OnSetCursor) -#endif // wxMSW - - WX_EVENT_TABLE_CONTROL_CONTAINER(wxSplitterWindow) -END_EVENT_TABLE() - -WX_DELEGATE_TO_CONTROL_CONTAINER(wxSplitterWindow, wxWindow) - -bool wxSplitterWindow::Create(wxWindow *parent, wxWindowID id, - const wxPoint& pos, - const wxSize& size, - long style, - const wxString& name) -{ - // allow TABbing from one window to the other - style |= wxTAB_TRAVERSAL; - - // we draw our border ourselves to blend the sash with it - style &= ~wxBORDER_MASK; - style |= wxBORDER_NONE; - - if ( !wxWindow::Create(parent, id, pos, size, style, name) ) - return false; - - if (size.x >= 0) - m_lastSize.x = size.x; - if (size.y >= 0) - m_lastSize.y = size.y; - - m_permitUnsplitAlways = (style & wxSP_PERMIT_UNSPLIT) != 0; - - // FIXME: with this line the background is not erased at all under GTK1, - // so temporary avoid it there -#if !defined(__WXGTK__) || defined(__WXGTK20__) - // don't erase the splitter background, it's pointless as we overwrite it - // anyhow - SetBackgroundStyle(wxBG_STYLE_CUSTOM); -#endif - - return true; -} - -void wxSplitterWindow::Init() -{ - m_container.SetContainerWindow(this); - - m_splitMode = wxSPLIT_VERTICAL; - m_permitUnsplitAlways = true; - m_windowOne = (wxWindow *) NULL; - m_windowTwo = (wxWindow *) NULL; - m_dragMode = wxSPLIT_DRAG_NONE; - m_oldX = 0; - m_oldY = 0; - m_firstX = 0; - m_firstY = 0; - m_sashPosition = m_requestedSashPosition = 0; - m_sashGravity = 0.0; - m_sashSize = -1; // -1 means use the native sash size - m_lastSize = wxSize(0,0); - m_checkRequestedSashPosition = false; - m_minimumPaneSize = 0; - m_sashCursorWE = wxCursor(wxCURSOR_SIZEWE); - m_sashCursorNS = wxCursor(wxCURSOR_SIZENS); - m_sashTrackerPen = new wxPen(*wxBLACK, 2, wxSOLID); - - m_needUpdating = false; - m_isHot = false; -} - -wxSplitterWindow::~wxSplitterWindow() -{ - delete m_sashTrackerPen; -} - -// ---------------------------------------------------------------------------- -// entering/leaving sash -// ---------------------------------------------------------------------------- - -void wxSplitterWindow::RedrawIfHotSensitive(bool isHot) -{ - if ( wxRendererNative::Get().GetSplitterParams(this).isHotSensitive ) - { - m_isHot = isHot; - - wxClientDC dc(this); - DrawSash(dc); - } - //else: we don't change our appearance, don't redraw to avoid flicker -} - -void wxSplitterWindow::OnEnterSash() -{ - SetResizeCursor(); - - RedrawIfHotSensitive(true); -} - -void wxSplitterWindow::OnLeaveSash() -{ - SetCursor(*wxSTANDARD_CURSOR); - - RedrawIfHotSensitive(false); -} - -void wxSplitterWindow::SetResizeCursor() -{ - SetCursor(m_splitMode == wxSPLIT_VERTICAL ? m_sashCursorWE - : m_sashCursorNS); -} - -// ---------------------------------------------------------------------------- -// other event handlers -// ---------------------------------------------------------------------------- - -void wxSplitterWindow::OnPaint(wxPaintEvent& WXUNUSED(event)) -{ - wxPaintDC dc(this); - - DrawSash(dc); -} - -void wxSplitterWindow::OnInternalIdle() -{ - wxWindow::OnInternalIdle(); - - // if this is the first idle time after a sash position has potentially - // been set, allow SizeWindows to check for a requested size. - if (!m_checkRequestedSashPosition) - { - m_checkRequestedSashPosition = true; - SizeWindows(); - return; // it won't needUpdating in this case - } - - if (m_needUpdating) - SizeWindows(); -} - -void wxSplitterWindow::OnMouseEvent(wxMouseEvent& event) -{ - int x = (int)event.GetX(), - y = (int)event.GetY(); - - if (GetWindowStyle() & wxSP_NOSASH) - return; - - // with wxSP_LIVE_UPDATE style the splitter windows are always resized - // following the mouse movement while it drags the sash, without it we only - // draw the sash at the new position but only resize the windows when the - // dragging is finished -#if defined( __WXMAC__ ) && defined(TARGET_API_MAC_OSX) && TARGET_API_MAC_OSX == 1 - bool isLive = true ; // FIXME: why? -#else - bool isLive = HasFlag(wxSP_LIVE_UPDATE); -#endif - if (event.LeftDown()) - { - if ( SashHitTest(x, y) ) - { - // Start the drag now - m_dragMode = wxSPLIT_DRAG_DRAGGING; - - // Capture mouse and set the cursor - CaptureMouse(); - SetResizeCursor(); - - if ( !isLive ) - { - // remember the initial sash position and draw the initial - // shadow sash - m_sashPositionCurrent = m_sashPosition; - - DrawSashTracker(x, y); - } - - m_oldX = x; - m_oldY = y; - - SetResizeCursor(); - return; - } - } - else if (event.LeftUp() && m_dragMode == wxSPLIT_DRAG_DRAGGING) - { - // We can stop dragging now and see what we've got. - m_dragMode = wxSPLIT_DRAG_NONE; - - // Release mouse and unset the cursor - ReleaseMouse(); - SetCursor(* wxSTANDARD_CURSOR); - - // exit if unsplit after doubleclick - if ( !IsSplit() ) - { - return; - } - - // Erase old tracker - if ( !isLive ) - { - DrawSashTracker(m_oldX, m_oldY); - } - - // the position of the click doesn't exactly correspond to - // m_sashPosition, rather it changes it by the distance by which the - // mouse has moved - int diff = m_splitMode == wxSPLIT_VERTICAL ? x - m_oldX : y - m_oldY; - - int posSashOld = isLive ? m_sashPosition : m_sashPositionCurrent; - int posSashNew = OnSashPositionChanging(posSashOld + diff); - if ( posSashNew == -1 ) - { - // change not allowed - return; - } - - if ( m_permitUnsplitAlways || m_minimumPaneSize == 0 ) - { - // Deal with possible unsplit scenarios - if ( posSashNew == 0 ) - { - // We remove the first window from the view - wxWindow *removedWindow = m_windowOne; - m_windowOne = m_windowTwo; - m_windowTwo = (wxWindow *) NULL; - OnUnsplit(removedWindow); - wxSplitterEvent eventUnsplit(wxEVT_COMMAND_SPLITTER_UNSPLIT, this); - eventUnsplit.m_data.win = removedWindow; - (void)DoSendEvent(eventUnsplit); - SetSashPositionAndNotify(0); - } - else if ( posSashNew == GetWindowSize() ) - { - // We remove the second window from the view - wxWindow *removedWindow = m_windowTwo; - m_windowTwo = (wxWindow *) NULL; - OnUnsplit(removedWindow); - wxSplitterEvent eventUnsplit(wxEVT_COMMAND_SPLITTER_UNSPLIT, this); - eventUnsplit.m_data.win = removedWindow; - (void)DoSendEvent(eventUnsplit); - SetSashPositionAndNotify(0); - } - else - { - SetSashPositionAndNotify(posSashNew); - } - } - else - { - SetSashPositionAndNotify(posSashNew); - } - - SizeWindows(); - } // left up && dragging - else if ((event.Moving() || event.Leaving() || event.Entering()) && (m_dragMode == wxSPLIT_DRAG_NONE)) - { - if ( event.Leaving() || !SashHitTest(x, y) ) - OnLeaveSash(); - else - OnEnterSash(); - } - else if (event.Dragging() && (m_dragMode == wxSPLIT_DRAG_DRAGGING)) - { - int diff = m_splitMode == wxSPLIT_VERTICAL ? x - m_oldX : y - m_oldY; - if ( !diff ) - { - // nothing to do, mouse didn't really move far enough - return; - } - - int posSashOld = isLive ? m_sashPosition : m_sashPositionCurrent; - int posSashNew = OnSashPositionChanging(posSashOld + diff); - if ( posSashNew == -1 ) - { - // change not allowed - return; - } - - if ( posSashNew == m_sashPosition ) - return; - - // Erase old tracker - if ( !isLive ) - { - DrawSashTracker(m_oldX, m_oldY); - } - - if (m_splitMode == wxSPLIT_VERTICAL) - x = posSashNew; - else - y = posSashNew; - - // Remember old positions - m_oldX = x; - m_oldY = y; - -#ifdef __WXMSW__ - // As we captured the mouse, we may get the mouse events from outside - // our window - for example, negative values in x, y. This has a weird - // consequence under MSW where we use unsigned values sometimes and - // signed ones other times: the coordinates turn as big positive - // numbers and so the sash is drawn on the *right* side of the window - // instead of the left (or bottom instead of top). Correct this. - if ( (short)m_oldX < 0 ) - m_oldX = 0; - if ( (short)m_oldY < 0 ) - m_oldY = 0; -#endif // __WXMSW__ - - // Draw new one - if ( !isLive ) - { - m_sashPositionCurrent = posSashNew; - - DrawSashTracker(m_oldX, m_oldY); - } - else - { - DoSetSashPosition(posSashNew); - m_needUpdating = true; - } - } - else if ( event.LeftDClick() && m_windowTwo ) - { - OnDoubleClickSash(x, y); - } -} - -void wxSplitterWindow::OnSize(wxSizeEvent& event) -{ - // only process this message if we're not iconized - otherwise iconizing - // and restoring a window containing the splitter has a funny side effect - // of changing the splitter position! - wxWindow *parent = wxGetTopLevelParent(this); - bool iconized; - - wxTopLevelWindow *winTop = wxDynamicCast(parent, wxTopLevelWindow); - if ( winTop ) - { - iconized = winTop->IsIconized(); - } - else - { - wxFAIL_MSG(wxT("should have a top level parent!")); - - iconized = false; - } - - if ( iconized ) - { - m_lastSize = wxSize(0,0); - - event.Skip(); - - return; - } - - if ( m_windowTwo ) - { - int w, h; - GetClientSize(&w, &h); - - int size = m_splitMode == wxSPLIT_VERTICAL ? w : h; - - int old_size = m_splitMode == wxSPLIT_VERTICAL ? m_lastSize.x : m_lastSize.y; - if ( old_size != 0 ) - { - int delta = (int) ( (size - old_size)*m_sashGravity ); - if ( delta != 0 ) - { - int newPosition = m_sashPosition + delta; - if( newPosition < m_minimumPaneSize ) - newPosition = m_minimumPaneSize; - SetSashPositionAndNotify(newPosition); - } - } - - if ( m_sashPosition >= size - 5 ) - SetSashPositionAndNotify(wxMax(10, size - 40)); - m_lastSize = wxSize(w,h); - } - - SizeWindows(); -} - -void wxSplitterWindow::SetSashGravity(double gravity) -{ - wxCHECK_RET( gravity >= 0. && gravity <= 1., - _T("invalid gravity value") ); - - m_sashGravity = gravity; -} - -bool wxSplitterWindow::SashHitTest(int x, int y, int tolerance) -{ - if ( m_windowTwo == NULL || m_sashPosition == 0) - return false; // No sash - - int z = m_splitMode == wxSPLIT_VERTICAL ? x : y; - int hitMin = m_sashPosition - tolerance; - int hitMax = m_sashPosition + GetSashSize() + tolerance; - - return z >= hitMin && z <= hitMax; -} - -int wxSplitterWindow::GetSashSize() const -{ - return m_sashSize > -1 ? m_sashSize : wxRendererNative::Get().GetSplitterParams(this).widthSash; -} - -int wxSplitterWindow::GetBorderSize() const -{ - return wxRendererNative::Get().GetSplitterParams(this).border; -} - -// Draw the sash -void wxSplitterWindow::DrawSash(wxDC& dc) -{ - if (HasFlag(wxSP_3DBORDER)) - wxRendererNative::Get().DrawSplitterBorder - ( - this, - dc, - GetClientRect() - ); - - // don't draw sash if we're not split - if ( m_sashPosition == 0 || !m_windowTwo ) - return; - - // nor if we're configured to not show it - if ( HasFlag(wxSP_NOSASH) ) - return; - - wxRendererNative::Get().DrawSplitterSash - ( - this, - dc, - GetClientSize(), - m_sashPosition, - m_splitMode == wxSPLIT_VERTICAL ? wxVERTICAL - : wxHORIZONTAL, - m_isHot ? (int)wxCONTROL_CURRENT : 0 - ); -} - -// Draw the sash tracker (for whilst moving the sash) -void wxSplitterWindow::DrawSashTracker(int x, int y) -{ - int w, h; - GetClientSize(&w, &h); - - wxScreenDC screenDC; - int x1, y1; - int x2, y2; - - if ( m_splitMode == wxSPLIT_VERTICAL ) - { - x1 = x; y1 = 2; - x2 = x; y2 = h-2; - - if ( x1 > w ) - { - x1 = w; x2 = w; - } - else if ( x1 < 0 ) - { - x1 = 0; x2 = 0; - } - } - else - { - x1 = 2; y1 = y; - x2 = w-2; y2 = y; - - if ( y1 > h ) - { - y1 = h; - y2 = h; - } - else if ( y1 < 0 ) - { - y1 = 0; - y2 = 0; - } - } - - ClientToScreen(&x1, &y1); - ClientToScreen(&x2, &y2); - - screenDC.SetLogicalFunction(wxINVERT); - screenDC.SetPen(*m_sashTrackerPen); - screenDC.SetBrush(*wxTRANSPARENT_BRUSH); - - screenDC.DrawLine(x1, y1, x2, y2); - - screenDC.SetLogicalFunction(wxCOPY); -} - -int wxSplitterWindow::GetWindowSize() const -{ - wxSize size = GetClientSize(); - - return m_splitMode == wxSPLIT_VERTICAL ? size.x : size.y; -} - -int wxSplitterWindow::AdjustSashPosition(int sashPos) const -{ - wxWindow *win; - - win = GetWindow1(); - if ( win ) - { - // the window shouldn't be smaller than its own minimal size nor - // smaller than the minimual pane size specified for this splitter - int minSize = m_splitMode == wxSPLIT_VERTICAL ? win->GetMinWidth() - : win->GetMinHeight(); - - if ( minSize == -1 || m_minimumPaneSize > minSize ) - minSize = m_minimumPaneSize; - - minSize += GetBorderSize(); - - if ( sashPos < minSize ) - sashPos = minSize; - } - - win = GetWindow2(); - if ( win ) - { - int minSize = m_splitMode == wxSPLIT_VERTICAL ? win->GetMinWidth() - : win->GetMinHeight(); - - if ( minSize == -1 || m_minimumPaneSize > minSize ) - minSize = m_minimumPaneSize; - - int maxSize = GetWindowSize() - minSize - GetBorderSize() - GetSashSize(); - if ( maxSize > 0 && sashPos > maxSize ) - sashPos = maxSize; - } - - return sashPos; -} - -bool wxSplitterWindow::DoSetSashPosition(int sashPos) -{ - int newSashPosition = AdjustSashPosition(sashPos); - - if ( newSashPosition == m_sashPosition ) - return false; - - m_sashPosition = newSashPosition; - - return true; -} - -void wxSplitterWindow::SetSashPositionAndNotify(int sashPos) -{ - // we must reset the request here, otherwise the sash would be stuck at - // old position if the user attempted to move the sash after invalid - // (e.g. smaller than minsize) sash position was requested using - // SetSashPosition(): - m_requestedSashPosition = INT_MAX; - - // note that we must send the event in any case, i.e. even if the sash - // position hasn't changed and DoSetSashPosition() returns false because we - // must generate a CHANGED event at the end of resizing - DoSetSashPosition(sashPos); - - wxSplitterEvent event(wxEVT_COMMAND_SPLITTER_SASH_POS_CHANGED, this); - event.m_data.pos = m_sashPosition; - - (void)DoSendEvent(event); -} - -// Position and size subwindows. -// Note that the border size applies to each subwindow, not -// including the edges next to the sash. -void wxSplitterWindow::SizeWindows() -{ - // check if we have delayed setting the real sash position - if ( m_checkRequestedSashPosition && m_requestedSashPosition != INT_MAX ) - { - int newSashPosition = ConvertSashPosition(m_requestedSashPosition); - if ( newSashPosition != m_sashPosition ) - { - DoSetSashPosition(newSashPosition); - } - - if ( newSashPosition <= m_sashPosition - && newSashPosition >= m_sashPosition - GetBorderSize() ) - { - // don't update it any more - m_requestedSashPosition = INT_MAX; - } - } - - int w, h; - GetClientSize(&w, &h); - - if ( GetWindow1() && !GetWindow2() ) - { - GetWindow1()->SetSize(GetBorderSize(), GetBorderSize(), - w - 2*GetBorderSize(), h - 2*GetBorderSize()); - } - else if ( GetWindow1() && GetWindow2() ) - { - const int border = GetBorderSize(), - sash = GetSashSize(); - - int size1 = GetSashPosition() - border, - size2 = GetSashPosition() + sash; - - int x2, y2, w1, h1, w2, h2; - if ( GetSplitMode() == wxSPLIT_VERTICAL ) - { - w1 = size1; - w2 = w - 2*border - sash - w1; - if (w2 < 0) - w2 = 0; - h2 = h - 2*border; - if (h2 < 0) - h2 = 0; - h1 = h2; - x2 = size2; - y2 = border; - } - else // horz splitter - { - w2 = w - 2*border; - if (w2 < 0) - w2 = 0; - w1 = w2; - h1 = size1; - h2 = h - 2*border - sash - h1; - if (h2 < 0) - h2 = 0; - x2 = border; - y2 = size2; - } - - GetWindow2()->SetSize(x2, y2, w2, h2); - GetWindow1()->SetSize(border, border, w1, h1); - } - - wxClientDC dc(this); - DrawSash(dc); - - SetNeedUpdating(false); -} - -// Set pane for unsplit window -void wxSplitterWindow::Initialize(wxWindow *window) -{ - wxASSERT_MSG( (!window || (window && window->GetParent() == this)), - _T("windows in the splitter should have it as parent!") ); - - if (window && !window->IsShown()) - window->Show(); - - m_windowOne = window; - m_windowTwo = (wxWindow *) NULL; - DoSetSashPosition(0); -} - -// Associates the given window with window 2, drawing the appropriate sash -// and changing the split mode. -// Does nothing and returns false if the window is already split. -bool wxSplitterWindow::DoSplit(wxSplitMode mode, - wxWindow *window1, wxWindow *window2, - int sashPosition) -{ - if ( IsSplit() ) - return false; - - wxCHECK_MSG( window1 && window2, false, - _T("can not split with NULL window(s)") ); - - wxCHECK_MSG( window1->GetParent() == this && window2->GetParent() == this, false, - _T("windows in the splitter should have it as parent!") ); - - if (! window1->IsShown()) - window1->Show(); - if (! window2->IsShown()) - window2->Show(); - - m_splitMode = mode; - m_windowOne = window1; - m_windowTwo = window2; - - // remember the sash position we want to set for later if we can't set it - // right now (e.g. because the window is too small) - m_requestedSashPosition = sashPosition; - m_checkRequestedSashPosition = false; - - DoSetSashPosition(ConvertSashPosition(sashPosition)); - - SizeWindows(); - - return true; -} - -int wxSplitterWindow::ConvertSashPosition(int sashPosition) const -{ - if ( sashPosition > 0 ) - { - return sashPosition; - } - else if ( sashPosition < 0 ) - { - // It's negative so adding is subtracting - return GetWindowSize() + sashPosition; - } - else // sashPosition == 0 - { - // default, put it in the centre - return GetWindowSize() / 2; - } -} - -// Remove the specified (or second) window from the view -// Doesn't actually delete the window. -bool wxSplitterWindow::Unsplit(wxWindow *toRemove) -{ - if ( ! IsSplit() ) - return false; - - wxWindow *win; - if ( toRemove == NULL || toRemove == m_windowTwo) - { - win = m_windowTwo ; - m_windowTwo = (wxWindow *) NULL; - } - else if ( toRemove == m_windowOne ) - { - win = m_windowOne ; - m_windowOne = m_windowTwo; - m_windowTwo = (wxWindow *) NULL; - } - else - { - wxFAIL_MSG(wxT("splitter: attempt to remove a non-existent window")); - - return false; - } - - OnUnsplit(win); - DoSetSashPosition(0); - SizeWindows(); - - return true; -} - -// Replace a window with another one -bool wxSplitterWindow::ReplaceWindow(wxWindow *winOld, wxWindow *winNew) -{ - wxCHECK_MSG( winOld, false, wxT("use one of Split() functions instead") ); - wxCHECK_MSG( winNew, false, wxT("use Unsplit() functions instead") ); - - if ( winOld == m_windowTwo ) - { - m_windowTwo = winNew; - } - else if ( winOld == m_windowOne ) - { - m_windowOne = winNew; - } - else - { - wxFAIL_MSG(wxT("splitter: attempt to replace a non-existent window")); - - return false; - } - - SizeWindows(); - - return true; -} - -void wxSplitterWindow::SetMinimumPaneSize(int min) -{ - m_minimumPaneSize = min; - int pos = m_requestedSashPosition != INT_MAX ? m_requestedSashPosition : m_sashPosition; - SetSashPosition(pos); // re-check limits -} - -void wxSplitterWindow::SetSashPosition(int position, bool redraw) -{ - // remember the sash position we want to set for later if we can't set it - // right now (e.g. because the window is too small) - m_requestedSashPosition = position; - m_checkRequestedSashPosition = false; - - DoSetSashPosition(ConvertSashPosition(position)); - - if ( redraw ) - { - SizeWindows(); - } -} - -// Make sure the child window sizes are updated. This is useful -// for reducing flicker by updating the sizes before a -// window is shown, if you know the overall size is correct. -void wxSplitterWindow::UpdateSize() -{ - m_checkRequestedSashPosition = true; - SizeWindows(); - m_checkRequestedSashPosition = false; -} - -bool wxSplitterWindow::DoSendEvent(wxSplitterEvent& event) -{ - return !GetEventHandler()->ProcessEvent(event) || event.IsAllowed(); -} - -wxSize wxSplitterWindow::DoGetBestSize() const -{ - // get best sizes of subwindows - wxSize size1, size2; - if ( m_windowOne ) - size1 = m_windowOne->GetEffectiveMinSize(); - if ( m_windowTwo ) - size2 = m_windowTwo->GetEffectiveMinSize(); - - // sum them - // - // pSash points to the size component to which sash size must be added - int *pSash; - wxSize sizeBest; - if ( m_splitMode == wxSPLIT_VERTICAL ) - { - sizeBest.y = wxMax(size1.y, size2.y); - sizeBest.x = wxMax(size1.x, m_minimumPaneSize) + - wxMax(size2.x, m_minimumPaneSize); - - pSash = &sizeBest.x; - } - else // wxSPLIT_HORIZONTAL - { - sizeBest.x = wxMax(size1.x, size2.x); - sizeBest.y = wxMax(size1.y, m_minimumPaneSize) + - wxMax(size2.y, m_minimumPaneSize); - - pSash = &sizeBest.y; - } - - // account for the border and the sash - int border = 2*GetBorderSize(); - *pSash += GetSashSize(); - sizeBest.x += border; - sizeBest.y += border; - - return sizeBest; -} - -// --------------------------------------------------------------------------- -// wxSplitterWindow virtual functions: they now just generate the events -// --------------------------------------------------------------------------- - -bool wxSplitterWindow::OnSashPositionChange(int WXUNUSED(newSashPosition)) -{ - // always allow by default - return true; -} - -int wxSplitterWindow::OnSashPositionChanging(int newSashPosition) -{ - // If within UNSPLIT_THRESHOLD from edge, set to edge to cause closure. - const int UNSPLIT_THRESHOLD = 4; - - // first of all, check if OnSashPositionChange() doesn't forbid this change - if ( !OnSashPositionChange(newSashPosition) ) - { - // it does - return -1; - } - - // Obtain relevant window dimension for bottom / right threshold check - int window_size = GetWindowSize(); - - bool unsplit_scenario = false; - if ( m_permitUnsplitAlways || m_minimumPaneSize == 0 ) - { - // Do edge detection if unsplit premitted - if ( newSashPosition <= UNSPLIT_THRESHOLD ) - { - // threshold top / left check - newSashPosition = 0; - unsplit_scenario = true; - } - if ( newSashPosition >= window_size - UNSPLIT_THRESHOLD ) - { - // threshold bottom/right check - newSashPosition = window_size; - unsplit_scenario = true; - } - } - - if ( !unsplit_scenario ) - { - // If resultant pane would be too small, enlarge it - newSashPosition = AdjustSashPosition(newSashPosition); - } - - // If the result is out of bounds it means minimum size is too big, - // so split window in half as best compromise. - if ( newSashPosition < 0 || newSashPosition > window_size ) - newSashPosition = window_size / 2; - - // now let the event handler have it - // - // FIXME: shouldn't we do it before the adjustments above so as to ensure - // that the sash position is always reasonable? - wxSplitterEvent event(wxEVT_COMMAND_SPLITTER_SASH_POS_CHANGING, this); - event.m_data.pos = newSashPosition; - - if ( !DoSendEvent(event) ) - { - // the event handler vetoed the change - newSashPosition = -1; - } - else - { - // it could have been changed by it - newSashPosition = event.GetSashPosition(); - } - - return newSashPosition; -} - -// Called when the sash is double-clicked. The default behaviour is to remove -// the sash if the minimum pane size is zero. -void wxSplitterWindow::OnDoubleClickSash(int x, int y) -{ - wxCHECK_RET(m_windowTwo, wxT("splitter: no window to remove")); - - // new code should handle events instead of using the virtual functions - wxSplitterEvent event(wxEVT_COMMAND_SPLITTER_DOUBLECLICKED, this); - event.m_data.pt.x = x; - event.m_data.pt.y = y; - if ( DoSendEvent(event) ) - { - if ( GetMinimumPaneSize() == 0 || m_permitUnsplitAlways ) - { - wxWindow* win = m_windowTwo; - if ( Unsplit(win) ) - { - wxSplitterEvent unsplitEvent(wxEVT_COMMAND_SPLITTER_UNSPLIT, this); - unsplitEvent.m_data.win = win; - (void)DoSendEvent(unsplitEvent); - } - } - } - //else: blocked by user -} - -void wxSplitterWindow::OnUnsplit(wxWindow *winRemoved) -{ - // call this before calling the event handler which may delete the window - winRemoved->Show(false); -} - -#if defined( __WXMSW__ ) || defined( __WXMAC__) - -// this is currently called (and needed) under MSW only... -void wxSplitterWindow::OnSetCursor(wxSetCursorEvent& event) -{ - // if we don't do it, the resizing cursor might be set for child window: - // and like this we explicitly say that our cursor should not be used for - // children windows which overlap us - - if ( SashHitTest(event.GetX(), event.GetY(), 0) ) - { - // default processing is ok - event.Skip(); - } - //else: do nothing, in particular, don't call Skip() -} - -#endif // wxMSW || wxMac - -#endif // wxUSE_SPLITTER - +///////////////////////////////////////////////////////////////////////////// +// Name: src/generic/splitter.cpp +// Purpose: wxSplitterWindow implementation +// Author: Julian Smart +// Modified by: +// Created: 01/02/97 +// RCS-ID: $Id: splitter.cpp 42816 2006-10-31 08:50:17Z RD $ +// Copyright: (c) Julian Smart +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_SPLITTER + +#include "wx/splitter.h" + +#ifndef WX_PRECOMP + #include "wx/string.h" + #include "wx/utils.h" + #include "wx/log.h" + + #include "wx/dcclient.h" + #include "wx/dcscreen.h" + + #include "wx/window.h" + #include "wx/dialog.h" + #include "wx/frame.h" + + #include "wx/settings.h" +#endif + +#include "wx/renderer.h" + +#include + +DEFINE_EVENT_TYPE(wxEVT_COMMAND_SPLITTER_SASH_POS_CHANGED) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_SPLITTER_SASH_POS_CHANGING) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_SPLITTER_DOUBLECLICKED) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_SPLITTER_UNSPLIT) + +IMPLEMENT_DYNAMIC_CLASS(wxSplitterWindow, wxWindow) + +/* + TODO PROPERTIES + style wxSP_3D + sashpos (long , 0 ) + minsize (long -1 ) + object, object_ref + orientation +*/ + +IMPLEMENT_DYNAMIC_CLASS(wxSplitterEvent, wxNotifyEvent) + +BEGIN_EVENT_TABLE(wxSplitterWindow, wxWindow) + EVT_PAINT(wxSplitterWindow::OnPaint) + EVT_SIZE(wxSplitterWindow::OnSize) + EVT_MOUSE_EVENTS(wxSplitterWindow::OnMouseEvent) + +#if defined( __WXMSW__ ) || defined( __WXMAC__) + EVT_SET_CURSOR(wxSplitterWindow::OnSetCursor) +#endif // wxMSW + + WX_EVENT_TABLE_CONTROL_CONTAINER(wxSplitterWindow) +END_EVENT_TABLE() + +WX_DELEGATE_TO_CONTROL_CONTAINER(wxSplitterWindow, wxWindow) + +bool wxSplitterWindow::Create(wxWindow *parent, wxWindowID id, + const wxPoint& pos, + const wxSize& size, + long style, + const wxString& name) +{ + // allow TABbing from one window to the other + style |= wxTAB_TRAVERSAL; + + // we draw our border ourselves to blend the sash with it + style &= ~wxBORDER_MASK; + style |= wxBORDER_NONE; + + if ( !wxWindow::Create(parent, id, pos, size, style, name) ) + return false; + + if (size.x >= 0) + m_lastSize.x = size.x; + if (size.y >= 0) + m_lastSize.y = size.y; + + m_permitUnsplitAlways = (style & wxSP_PERMIT_UNSPLIT) != 0; + + // FIXME: with this line the background is not erased at all under GTK1, + // so temporary avoid it there +#if !defined(__WXGTK__) || defined(__WXGTK20__) + // don't erase the splitter background, it's pointless as we overwrite it + // anyhow + SetBackgroundStyle(wxBG_STYLE_CUSTOM); +#endif + + return true; +} + +void wxSplitterWindow::Init() +{ + m_container.SetContainerWindow(this); + + m_splitMode = wxSPLIT_VERTICAL; + m_permitUnsplitAlways = true; + m_windowOne = (wxWindow *) NULL; + m_windowTwo = (wxWindow *) NULL; + m_dragMode = wxSPLIT_DRAG_NONE; + m_oldX = 0; + m_oldY = 0; + m_firstX = 0; + m_firstY = 0; + m_sashPosition = m_requestedSashPosition = 0; + m_sashGravity = 0.0; + m_sashSize = -1; // -1 means use the native sash size + m_lastSize = wxSize(0,0); + m_checkRequestedSashPosition = false; + m_minimumPaneSize = 0; + m_sashCursorWE = wxCursor(wxCURSOR_SIZEWE); + m_sashCursorNS = wxCursor(wxCURSOR_SIZENS); + m_sashTrackerPen = new wxPen(*wxBLACK, 2, wxSOLID); + + m_needUpdating = false; + m_isHot = false; +} + +wxSplitterWindow::~wxSplitterWindow() +{ + delete m_sashTrackerPen; +} + +// ---------------------------------------------------------------------------- +// entering/leaving sash +// ---------------------------------------------------------------------------- + +void wxSplitterWindow::RedrawIfHotSensitive(bool isHot) +{ + if ( wxRendererNative::Get().GetSplitterParams(this).isHotSensitive ) + { + m_isHot = isHot; + + wxClientDC dc(this); + DrawSash(dc); + } + //else: we don't change our appearance, don't redraw to avoid flicker +} + +void wxSplitterWindow::OnEnterSash() +{ + SetResizeCursor(); + + RedrawIfHotSensitive(true); +} + +void wxSplitterWindow::OnLeaveSash() +{ + SetCursor(*wxSTANDARD_CURSOR); + + RedrawIfHotSensitive(false); +} + +void wxSplitterWindow::SetResizeCursor() +{ + SetCursor(m_splitMode == wxSPLIT_VERTICAL ? m_sashCursorWE + : m_sashCursorNS); +} + +// ---------------------------------------------------------------------------- +// other event handlers +// ---------------------------------------------------------------------------- + +void wxSplitterWindow::OnPaint(wxPaintEvent& WXUNUSED(event)) +{ + wxPaintDC dc(this); + + DrawSash(dc); +} + +void wxSplitterWindow::OnInternalIdle() +{ + wxWindow::OnInternalIdle(); + + // if this is the first idle time after a sash position has potentially + // been set, allow SizeWindows to check for a requested size. + if (!m_checkRequestedSashPosition) + { + m_checkRequestedSashPosition = true; + SizeWindows(); + return; // it won't needUpdating in this case + } + + if (m_needUpdating) + SizeWindows(); +} + +void wxSplitterWindow::OnMouseEvent(wxMouseEvent& event) +{ + int x = (int)event.GetX(), + y = (int)event.GetY(); + + if (GetWindowStyle() & wxSP_NOSASH) + return; + + // with wxSP_LIVE_UPDATE style the splitter windows are always resized + // following the mouse movement while it drags the sash, without it we only + // draw the sash at the new position but only resize the windows when the + // dragging is finished +#if defined( __WXMAC__ ) && defined(TARGET_API_MAC_OSX) && TARGET_API_MAC_OSX == 1 + bool isLive = true ; // FIXME: why? +#else + bool isLive = HasFlag(wxSP_LIVE_UPDATE); +#endif + if (event.LeftDown()) + { + if ( SashHitTest(x, y) ) + { + // Start the drag now + m_dragMode = wxSPLIT_DRAG_DRAGGING; + + // Capture mouse and set the cursor + CaptureMouse(); + SetResizeCursor(); + + if ( !isLive ) + { + // remember the initial sash position and draw the initial + // shadow sash + m_sashPositionCurrent = m_sashPosition; + + DrawSashTracker(x, y); + } + + m_oldX = x; + m_oldY = y; + + SetResizeCursor(); + return; + } + } + else if (event.LeftUp() && m_dragMode == wxSPLIT_DRAG_DRAGGING) + { + // We can stop dragging now and see what we've got. + m_dragMode = wxSPLIT_DRAG_NONE; + + // Release mouse and unset the cursor + ReleaseMouse(); + SetCursor(* wxSTANDARD_CURSOR); + + // exit if unsplit after doubleclick + if ( !IsSplit() ) + { + return; + } + + // Erase old tracker + if ( !isLive ) + { + DrawSashTracker(m_oldX, m_oldY); + } + + // the position of the click doesn't exactly correspond to + // m_sashPosition, rather it changes it by the distance by which the + // mouse has moved + int diff = m_splitMode == wxSPLIT_VERTICAL ? x - m_oldX : y - m_oldY; + + int posSashOld = isLive ? m_sashPosition : m_sashPositionCurrent; + int posSashNew = OnSashPositionChanging(posSashOld + diff); + if ( posSashNew == -1 ) + { + // change not allowed + return; + } + + if ( m_permitUnsplitAlways || m_minimumPaneSize == 0 ) + { + // Deal with possible unsplit scenarios + if ( posSashNew == 0 ) + { + // We remove the first window from the view + wxWindow *removedWindow = m_windowOne; + m_windowOne = m_windowTwo; + m_windowTwo = (wxWindow *) NULL; + OnUnsplit(removedWindow); + wxSplitterEvent eventUnsplit(wxEVT_COMMAND_SPLITTER_UNSPLIT, this); + eventUnsplit.m_data.win = removedWindow; + (void)DoSendEvent(eventUnsplit); + SetSashPositionAndNotify(0); + } + else if ( posSashNew == GetWindowSize() ) + { + // We remove the second window from the view + wxWindow *removedWindow = m_windowTwo; + m_windowTwo = (wxWindow *) NULL; + OnUnsplit(removedWindow); + wxSplitterEvent eventUnsplit(wxEVT_COMMAND_SPLITTER_UNSPLIT, this); + eventUnsplit.m_data.win = removedWindow; + (void)DoSendEvent(eventUnsplit); + SetSashPositionAndNotify(0); + } + else + { + SetSashPositionAndNotify(posSashNew); + } + } + else + { + SetSashPositionAndNotify(posSashNew); + } + + SizeWindows(); + } // left up && dragging + else if ((event.Moving() || event.Leaving() || event.Entering()) && (m_dragMode == wxSPLIT_DRAG_NONE)) + { + if ( event.Leaving() || !SashHitTest(x, y) ) + OnLeaveSash(); + else + OnEnterSash(); + } + else if (event.Dragging() && (m_dragMode == wxSPLIT_DRAG_DRAGGING)) + { + int diff = m_splitMode == wxSPLIT_VERTICAL ? x - m_oldX : y - m_oldY; + if ( !diff ) + { + // nothing to do, mouse didn't really move far enough + return; + } + + int posSashOld = isLive ? m_sashPosition : m_sashPositionCurrent; + int posSashNew = OnSashPositionChanging(posSashOld + diff); + if ( posSashNew == -1 ) + { + // change not allowed + return; + } + + if ( posSashNew == m_sashPosition ) + return; + + // Erase old tracker + if ( !isLive ) + { + DrawSashTracker(m_oldX, m_oldY); + } + + if (m_splitMode == wxSPLIT_VERTICAL) + x = posSashNew; + else + y = posSashNew; + + // Remember old positions + m_oldX = x; + m_oldY = y; + +#ifdef __WXMSW__ + // As we captured the mouse, we may get the mouse events from outside + // our window - for example, negative values in x, y. This has a weird + // consequence under MSW where we use unsigned values sometimes and + // signed ones other times: the coordinates turn as big positive + // numbers and so the sash is drawn on the *right* side of the window + // instead of the left (or bottom instead of top). Correct this. + if ( (short)m_oldX < 0 ) + m_oldX = 0; + if ( (short)m_oldY < 0 ) + m_oldY = 0; +#endif // __WXMSW__ + + // Draw new one + if ( !isLive ) + { + m_sashPositionCurrent = posSashNew; + + DrawSashTracker(m_oldX, m_oldY); + } + else + { + DoSetSashPosition(posSashNew); + m_needUpdating = true; + } + } + else if ( event.LeftDClick() && m_windowTwo ) + { + OnDoubleClickSash(x, y); + } +} + +void wxSplitterWindow::OnSize(wxSizeEvent& event) +{ + // only process this message if we're not iconized - otherwise iconizing + // and restoring a window containing the splitter has a funny side effect + // of changing the splitter position! + wxWindow *parent = wxGetTopLevelParent(this); + bool iconized; + + wxTopLevelWindow *winTop = wxDynamicCast(parent, wxTopLevelWindow); + if ( winTop ) + { + iconized = winTop->IsIconized(); + } + else + { + wxFAIL_MSG(wxT("should have a top level parent!")); + + iconized = false; + } + + if ( iconized ) + { + m_lastSize = wxSize(0,0); + + event.Skip(); + + return; + } + + if ( m_windowTwo ) + { + int w, h; + GetClientSize(&w, &h); + + int size = m_splitMode == wxSPLIT_VERTICAL ? w : h; + + int old_size = m_splitMode == wxSPLIT_VERTICAL ? m_lastSize.x : m_lastSize.y; + if ( old_size != 0 ) + { + int delta = (int) ( (size - old_size)*m_sashGravity ); + if ( delta != 0 ) + { + int newPosition = m_sashPosition + delta; + if( newPosition < m_minimumPaneSize ) + newPosition = m_minimumPaneSize; + SetSashPositionAndNotify(newPosition); + } + } + + if ( m_sashPosition >= size - 5 ) + SetSashPositionAndNotify(wxMax(10, size - 40)); + m_lastSize = wxSize(w,h); + } + + SizeWindows(); +} + +void wxSplitterWindow::SetSashGravity(double gravity) +{ + wxCHECK_RET( gravity >= 0. && gravity <= 1., + _T("invalid gravity value") ); + + m_sashGravity = gravity; +} + +bool wxSplitterWindow::SashHitTest(int x, int y, int tolerance) +{ + if ( m_windowTwo == NULL || m_sashPosition == 0) + return false; // No sash + + int z = m_splitMode == wxSPLIT_VERTICAL ? x : y; + int hitMin = m_sashPosition - tolerance; + int hitMax = m_sashPosition + GetSashSize() + tolerance; + + return z >= hitMin && z <= hitMax; +} + +int wxSplitterWindow::GetSashSize() const +{ + return m_sashSize > -1 ? m_sashSize : wxRendererNative::Get().GetSplitterParams(this).widthSash; +} + +int wxSplitterWindow::GetBorderSize() const +{ + return wxRendererNative::Get().GetSplitterParams(this).border; +} + +// Draw the sash +void wxSplitterWindow::DrawSash(wxDC& dc) +{ + if (HasFlag(wxSP_3DBORDER)) + wxRendererNative::Get().DrawSplitterBorder + ( + this, + dc, + GetClientRect() + ); + + // don't draw sash if we're not split + if ( m_sashPosition == 0 || !m_windowTwo ) + return; + + // nor if we're configured to not show it + if ( HasFlag(wxSP_NOSASH) ) + return; + + wxRendererNative::Get().DrawSplitterSash + ( + this, + dc, + GetClientSize(), + m_sashPosition, + m_splitMode == wxSPLIT_VERTICAL ? wxVERTICAL + : wxHORIZONTAL, + m_isHot ? (int)wxCONTROL_CURRENT : 0 + ); +} + +// Draw the sash tracker (for whilst moving the sash) +void wxSplitterWindow::DrawSashTracker(int x, int y) +{ + int w, h; + GetClientSize(&w, &h); + + wxScreenDC screenDC; + int x1, y1; + int x2, y2; + + if ( m_splitMode == wxSPLIT_VERTICAL ) + { + x1 = x; y1 = 2; + x2 = x; y2 = h-2; + + if ( x1 > w ) + { + x1 = w; x2 = w; + } + else if ( x1 < 0 ) + { + x1 = 0; x2 = 0; + } + } + else + { + x1 = 2; y1 = y; + x2 = w-2; y2 = y; + + if ( y1 > h ) + { + y1 = h; + y2 = h; + } + else if ( y1 < 0 ) + { + y1 = 0; + y2 = 0; + } + } + + ClientToScreen(&x1, &y1); + ClientToScreen(&x2, &y2); + + screenDC.SetLogicalFunction(wxINVERT); + screenDC.SetPen(*m_sashTrackerPen); + screenDC.SetBrush(*wxTRANSPARENT_BRUSH); + + screenDC.DrawLine(x1, y1, x2, y2); + + screenDC.SetLogicalFunction(wxCOPY); +} + +int wxSplitterWindow::GetWindowSize() const +{ + wxSize size = GetClientSize(); + + return m_splitMode == wxSPLIT_VERTICAL ? size.x : size.y; +} + +int wxSplitterWindow::AdjustSashPosition(int sashPos) const +{ + wxWindow *win; + + win = GetWindow1(); + if ( win ) + { + // the window shouldn't be smaller than its own minimal size nor + // smaller than the minimual pane size specified for this splitter + int minSize = m_splitMode == wxSPLIT_VERTICAL ? win->GetMinWidth() + : win->GetMinHeight(); + + if ( minSize == -1 || m_minimumPaneSize > minSize ) + minSize = m_minimumPaneSize; + + minSize += GetBorderSize(); + + if ( sashPos < minSize ) + sashPos = minSize; + } + + win = GetWindow2(); + if ( win ) + { + int minSize = m_splitMode == wxSPLIT_VERTICAL ? win->GetMinWidth() + : win->GetMinHeight(); + + if ( minSize == -1 || m_minimumPaneSize > minSize ) + minSize = m_minimumPaneSize; + + int maxSize = GetWindowSize() - minSize - GetBorderSize() - GetSashSize(); + if ( maxSize > 0 && sashPos > maxSize ) + sashPos = maxSize; + } + + return sashPos; +} + +bool wxSplitterWindow::DoSetSashPosition(int sashPos) +{ + int newSashPosition = AdjustSashPosition(sashPos); + + if ( newSashPosition == m_sashPosition ) + return false; + + m_sashPosition = newSashPosition; + + return true; +} + +void wxSplitterWindow::SetSashPositionAndNotify(int sashPos) +{ + // we must reset the request here, otherwise the sash would be stuck at + // old position if the user attempted to move the sash after invalid + // (e.g. smaller than minsize) sash position was requested using + // SetSashPosition(): + m_requestedSashPosition = INT_MAX; + + // note that we must send the event in any case, i.e. even if the sash + // position hasn't changed and DoSetSashPosition() returns false because we + // must generate a CHANGED event at the end of resizing + DoSetSashPosition(sashPos); + + wxSplitterEvent event(wxEVT_COMMAND_SPLITTER_SASH_POS_CHANGED, this); + event.m_data.pos = m_sashPosition; + + (void)DoSendEvent(event); +} + +// Position and size subwindows. +// Note that the border size applies to each subwindow, not +// including the edges next to the sash. +void wxSplitterWindow::SizeWindows() +{ + // check if we have delayed setting the real sash position + if ( m_checkRequestedSashPosition && m_requestedSashPosition != INT_MAX ) + { + int newSashPosition = ConvertSashPosition(m_requestedSashPosition); + if ( newSashPosition != m_sashPosition ) + { + DoSetSashPosition(newSashPosition); + } + + if ( newSashPosition <= m_sashPosition + && newSashPosition >= m_sashPosition - GetBorderSize() ) + { + // don't update it any more + m_requestedSashPosition = INT_MAX; + } + } + + int w, h; + GetClientSize(&w, &h); + + if ( GetWindow1() && !GetWindow2() ) + { + GetWindow1()->SetSize(GetBorderSize(), GetBorderSize(), + w - 2*GetBorderSize(), h - 2*GetBorderSize()); + } + else if ( GetWindow1() && GetWindow2() ) + { + const int border = GetBorderSize(), + sash = GetSashSize(); + + int size1 = GetSashPosition() - border, + size2 = GetSashPosition() + sash; + + int x2, y2, w1, h1, w2, h2; + if ( GetSplitMode() == wxSPLIT_VERTICAL ) + { + w1 = size1; + w2 = w - 2*border - sash - w1; + if (w2 < 0) + w2 = 0; + h2 = h - 2*border; + if (h2 < 0) + h2 = 0; + h1 = h2; + x2 = size2; + y2 = border; + } + else // horz splitter + { + w2 = w - 2*border; + if (w2 < 0) + w2 = 0; + w1 = w2; + h1 = size1; + h2 = h - 2*border - sash - h1; + if (h2 < 0) + h2 = 0; + x2 = border; + y2 = size2; + } + + GetWindow2()->SetSize(x2, y2, w2, h2); + GetWindow1()->SetSize(border, border, w1, h1); + } + + wxClientDC dc(this); + DrawSash(dc); + + SetNeedUpdating(false); +} + +// Set pane for unsplit window +void wxSplitterWindow::Initialize(wxWindow *window) +{ + wxASSERT_MSG( (!window || (window && window->GetParent() == this)), + _T("windows in the splitter should have it as parent!") ); + + if (window && !window->IsShown()) + window->Show(); + + m_windowOne = window; + m_windowTwo = (wxWindow *) NULL; + DoSetSashPosition(0); +} + +// Associates the given window with window 2, drawing the appropriate sash +// and changing the split mode. +// Does nothing and returns false if the window is already split. +bool wxSplitterWindow::DoSplit(wxSplitMode mode, + wxWindow *window1, wxWindow *window2, + int sashPosition) +{ + if ( IsSplit() ) + return false; + + wxCHECK_MSG( window1 && window2, false, + _T("can not split with NULL window(s)") ); + + wxCHECK_MSG( window1->GetParent() == this && window2->GetParent() == this, false, + _T("windows in the splitter should have it as parent!") ); + + if (! window1->IsShown()) + window1->Show(); + if (! window2->IsShown()) + window2->Show(); + + m_splitMode = mode; + m_windowOne = window1; + m_windowTwo = window2; + + // remember the sash position we want to set for later if we can't set it + // right now (e.g. because the window is too small) + m_requestedSashPosition = sashPosition; + m_checkRequestedSashPosition = false; + + DoSetSashPosition(ConvertSashPosition(sashPosition)); + + SizeWindows(); + + return true; +} + +int wxSplitterWindow::ConvertSashPosition(int sashPosition) const +{ + if ( sashPosition > 0 ) + { + return sashPosition; + } + else if ( sashPosition < 0 ) + { + // It's negative so adding is subtracting + return GetWindowSize() + sashPosition; + } + else // sashPosition == 0 + { + // default, put it in the centre + return GetWindowSize() / 2; + } +} + +// Remove the specified (or second) window from the view +// Doesn't actually delete the window. +bool wxSplitterWindow::Unsplit(wxWindow *toRemove) +{ + if ( ! IsSplit() ) + return false; + + wxWindow *win; + if ( toRemove == NULL || toRemove == m_windowTwo) + { + win = m_windowTwo ; + m_windowTwo = (wxWindow *) NULL; + } + else if ( toRemove == m_windowOne ) + { + win = m_windowOne ; + m_windowOne = m_windowTwo; + m_windowTwo = (wxWindow *) NULL; + } + else + { + wxFAIL_MSG(wxT("splitter: attempt to remove a non-existent window")); + + return false; + } + + OnUnsplit(win); + DoSetSashPosition(0); + SizeWindows(); + + return true; +} + +// Replace a window with another one +bool wxSplitterWindow::ReplaceWindow(wxWindow *winOld, wxWindow *winNew) +{ + wxCHECK_MSG( winOld, false, wxT("use one of Split() functions instead") ); + wxCHECK_MSG( winNew, false, wxT("use Unsplit() functions instead") ); + + if ( winOld == m_windowTwo ) + { + m_windowTwo = winNew; + } + else if ( winOld == m_windowOne ) + { + m_windowOne = winNew; + } + else + { + wxFAIL_MSG(wxT("splitter: attempt to replace a non-existent window")); + + return false; + } + + SizeWindows(); + + return true; +} + +void wxSplitterWindow::SetMinimumPaneSize(int min) +{ + m_minimumPaneSize = min; + int pos = m_requestedSashPosition != INT_MAX ? m_requestedSashPosition : m_sashPosition; + SetSashPosition(pos); // re-check limits +} + +void wxSplitterWindow::SetSashPosition(int position, bool redraw) +{ + // remember the sash position we want to set for later if we can't set it + // right now (e.g. because the window is too small) + m_requestedSashPosition = position; + m_checkRequestedSashPosition = false; + + DoSetSashPosition(ConvertSashPosition(position)); + + if ( redraw ) + { + SizeWindows(); + } +} + +// Make sure the child window sizes are updated. This is useful +// for reducing flicker by updating the sizes before a +// window is shown, if you know the overall size is correct. +void wxSplitterWindow::UpdateSize() +{ + m_checkRequestedSashPosition = true; + SizeWindows(); + m_checkRequestedSashPosition = false; +} + +bool wxSplitterWindow::DoSendEvent(wxSplitterEvent& event) +{ + return !GetEventHandler()->ProcessEvent(event) || event.IsAllowed(); +} + +wxSize wxSplitterWindow::DoGetBestSize() const +{ + // get best sizes of subwindows + wxSize size1, size2; + if ( m_windowOne ) + size1 = m_windowOne->GetEffectiveMinSize(); + if ( m_windowTwo ) + size2 = m_windowTwo->GetEffectiveMinSize(); + + // sum them + // + // pSash points to the size component to which sash size must be added + int *pSash; + wxSize sizeBest; + if ( m_splitMode == wxSPLIT_VERTICAL ) + { + sizeBest.y = wxMax(size1.y, size2.y); + sizeBest.x = wxMax(size1.x, m_minimumPaneSize) + + wxMax(size2.x, m_minimumPaneSize); + + pSash = &sizeBest.x; + } + else // wxSPLIT_HORIZONTAL + { + sizeBest.x = wxMax(size1.x, size2.x); + sizeBest.y = wxMax(size1.y, m_minimumPaneSize) + + wxMax(size2.y, m_minimumPaneSize); + + pSash = &sizeBest.y; + } + + // account for the border and the sash + int border = 2*GetBorderSize(); + *pSash += GetSashSize(); + sizeBest.x += border; + sizeBest.y += border; + + return sizeBest; +} + +// --------------------------------------------------------------------------- +// wxSplitterWindow virtual functions: they now just generate the events +// --------------------------------------------------------------------------- + +bool wxSplitterWindow::OnSashPositionChange(int WXUNUSED(newSashPosition)) +{ + // always allow by default + return true; +} + +int wxSplitterWindow::OnSashPositionChanging(int newSashPosition) +{ + // If within UNSPLIT_THRESHOLD from edge, set to edge to cause closure. + const int UNSPLIT_THRESHOLD = 4; + + // first of all, check if OnSashPositionChange() doesn't forbid this change + if ( !OnSashPositionChange(newSashPosition) ) + { + // it does + return -1; + } + + // Obtain relevant window dimension for bottom / right threshold check + int window_size = GetWindowSize(); + + bool unsplit_scenario = false; + if ( m_permitUnsplitAlways || m_minimumPaneSize == 0 ) + { + // Do edge detection if unsplit premitted + if ( newSashPosition <= UNSPLIT_THRESHOLD ) + { + // threshold top / left check + newSashPosition = 0; + unsplit_scenario = true; + } + if ( newSashPosition >= window_size - UNSPLIT_THRESHOLD ) + { + // threshold bottom/right check + newSashPosition = window_size; + unsplit_scenario = true; + } + } + + if ( !unsplit_scenario ) + { + // If resultant pane would be too small, enlarge it + newSashPosition = AdjustSashPosition(newSashPosition); + } + + // If the result is out of bounds it means minimum size is too big, + // so split window in half as best compromise. + if ( newSashPosition < 0 || newSashPosition > window_size ) + newSashPosition = window_size / 2; + + // now let the event handler have it + // + // FIXME: shouldn't we do it before the adjustments above so as to ensure + // that the sash position is always reasonable? + wxSplitterEvent event(wxEVT_COMMAND_SPLITTER_SASH_POS_CHANGING, this); + event.m_data.pos = newSashPosition; + + if ( !DoSendEvent(event) ) + { + // the event handler vetoed the change + newSashPosition = -1; + } + else + { + // it could have been changed by it + newSashPosition = event.GetSashPosition(); + } + + return newSashPosition; +} + +// Called when the sash is double-clicked. The default behaviour is to remove +// the sash if the minimum pane size is zero. +void wxSplitterWindow::OnDoubleClickSash(int x, int y) +{ + wxCHECK_RET(m_windowTwo, wxT("splitter: no window to remove")); + + // new code should handle events instead of using the virtual functions + wxSplitterEvent event(wxEVT_COMMAND_SPLITTER_DOUBLECLICKED, this); + event.m_data.pt.x = x; + event.m_data.pt.y = y; + if ( DoSendEvent(event) ) + { + if ( GetMinimumPaneSize() == 0 || m_permitUnsplitAlways ) + { + wxWindow* win = m_windowTwo; + if ( Unsplit(win) ) + { + wxSplitterEvent unsplitEvent(wxEVT_COMMAND_SPLITTER_UNSPLIT, this); + unsplitEvent.m_data.win = win; + (void)DoSendEvent(unsplitEvent); + } + } + } + //else: blocked by user +} + +void wxSplitterWindow::OnUnsplit(wxWindow *winRemoved) +{ + // call this before calling the event handler which may delete the window + winRemoved->Show(false); +} + +#if defined( __WXMSW__ ) || defined( __WXMAC__) + +// this is currently called (and needed) under MSW only... +void wxSplitterWindow::OnSetCursor(wxSetCursorEvent& event) +{ + // if we don't do it, the resizing cursor might be set for child window: + // and like this we explicitly say that our cursor should not be used for + // children windows which overlap us + + if ( SashHitTest(event.GetX(), event.GetY(), 0) ) + { + // default processing is ok + event.Skip(); + } + //else: do nothing, in particular, don't call Skip() +} + +#endif // wxMSW || wxMac + +#endif // wxUSE_SPLITTER + diff --git a/Externals/wxWidgets/src/generic/srchctlg.cpp b/Externals/wxWidgets/src/generic/srchctlg.cpp index 8b7edad0dc..67fd932b8d 100644 --- a/Externals/wxWidgets/src/generic/srchctlg.cpp +++ b/Externals/wxWidgets/src/generic/srchctlg.cpp @@ -1,1216 +1,1216 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: src/generic/srchctlg.cpp -// Purpose: implements wxSearchCtrl as a composite control -// Author: Vince Harron -// Created: 2006-02-19 -// RCS-ID: $Id: srchctlg.cpp 47962 2007-08-08 12:38:13Z JS $ -// Copyright: Vince Harron -// License: wxWindows licence -/////////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_SEARCHCTRL - -#include "wx/srchctrl.h" - -#ifndef WX_PRECOMP - #include "wx/button.h" - #include "wx/dcclient.h" - #include "wx/menu.h" - #include "wx/dcmemory.h" -#endif //WX_PRECOMP - -#if !wxUSE_NATIVE_SEARCH_CONTROL - -#include "wx/image.h" - -#define WXMAX(a,b) ((a)>(b)?(a):(b)) - -// ---------------------------------------------------------------------------- -// constants -// ---------------------------------------------------------------------------- - -// the margin between the text control and the search/cancel buttons -static const wxCoord MARGIN = 2; - -// border around all controls to compensate for wxSIMPLE_BORDER -#if defined(__WXMSW__) -static const wxCoord BORDER = 0; -static const wxCoord ICON_MARGIN = 2; -static const wxCoord ICON_OFFSET = 2; -#else -static const wxCoord BORDER = 2; -static const wxCoord ICON_MARGIN = 0; -static const wxCoord ICON_OFFSET = 0; -#endif - -// ---------------------------------------------------------------------------- -// TODO: These functions or something like them should probably be made -// public. There are similar functions in src/aui/dockart.cpp... - -static double wxBlendColour(double fg, double bg, double alpha) -{ - double result = bg + (alpha * (fg - bg)); - if (result < 0.0) - result = 0.0; - if (result > 255) - result = 255; - return result; -} - -static wxColor wxStepColour(const wxColor& c, int ialpha) -{ - if (ialpha == 100) - return c; - - double r = c.Red(), g = c.Green(), b = c.Blue(); - double bg; - - // ialpha is 0..200 where 0 is completely black - // and 200 is completely white and 100 is the same - // convert that to normal alpha 0.0 - 1.0 - ialpha = wxMin(ialpha, 200); - ialpha = wxMax(ialpha, 0); - double alpha = ((double)(ialpha - 100.0))/100.0; - - if (ialpha > 100) - { - // blend with white - bg = 255.0; - alpha = 1.0 - alpha; // 0 = transparent fg; 1 = opaque fg - } - else - { - // blend with black - bg = 0.0; - alpha = 1.0 + alpha; // 0 = transparent fg; 1 = opaque fg - } - - r = wxBlendColour(r, bg, alpha); - g = wxBlendColour(g, bg, alpha); - b = wxBlendColour(b, bg, alpha); - - return wxColour((unsigned char)r, (unsigned char)g, (unsigned char)b); -} - -#define LIGHT_STEP 160 - -// ---------------------------------------------------------------------------- -// wxSearchTextCtrl: text control used by search control -// ---------------------------------------------------------------------------- - -class wxSearchTextCtrl : public wxTextCtrl -{ -public: - wxSearchTextCtrl(wxSearchCtrl *search, const wxString& value, int style) - : wxTextCtrl(search, wxID_ANY, value, wxDefaultPosition, wxDefaultSize, - style | wxNO_BORDER) - { - m_search = search; - m_defaultFG = GetForegroundColour(); - - // remove the default minsize, the searchctrl will have one instead - SetSizeHints(wxDefaultCoord,wxDefaultCoord); - } - - void SetDescriptiveText(const wxString& text) - { - if ( GetValue() == m_descriptiveText ) - { - ChangeValue(wxEmptyString); - } - - m_descriptiveText = text; - } - - wxString GetDescriptiveText() const - { - return m_descriptiveText; - } - -protected: - void OnText(wxCommandEvent& eventText) - { - wxCommandEvent event(eventText); - event.SetEventObject(m_search); - event.SetId(m_search->GetId()); - - m_search->GetEventHandler()->ProcessEvent(event); - } - - void OnTextUrl(wxTextUrlEvent& eventText) - { - // copy constructor is disabled for some reason? - //wxTextUrlEvent event(eventText); - wxTextUrlEvent event( - m_search->GetId(), - eventText.GetMouseEvent(), - eventText.GetURLStart(), - eventText.GetURLEnd() - ); - event.SetEventObject(m_search); - - m_search->GetEventHandler()->ProcessEvent(event); - } - - void OnIdle(wxIdleEvent& WXUNUSED(event)) - { - if ( IsEmpty() && !(wxWindow::FindFocus() == this) ) - { - ChangeValue(m_descriptiveText); - SetInsertionPoint(0); - SetForegroundColour(wxStepColour(m_defaultFG, LIGHT_STEP)); - } - } - - void OnFocus(wxFocusEvent& event) - { - event.Skip(); - if ( GetValue() == m_descriptiveText ) - { - ChangeValue(wxEmptyString); - SetForegroundColour(m_defaultFG); - } - } - -private: - wxSearchCtrl* m_search; - wxString m_descriptiveText; - wxColour m_defaultFG; - - DECLARE_EVENT_TABLE() -}; - -BEGIN_EVENT_TABLE(wxSearchTextCtrl, wxTextCtrl) - EVT_TEXT(wxID_ANY, wxSearchTextCtrl::OnText) - EVT_TEXT_ENTER(wxID_ANY, wxSearchTextCtrl::OnText) - EVT_TEXT_URL(wxID_ANY, wxSearchTextCtrl::OnTextUrl) - EVT_TEXT_MAXLEN(wxID_ANY, wxSearchTextCtrl::OnText) - EVT_IDLE(wxSearchTextCtrl::OnIdle) - EVT_SET_FOCUS(wxSearchTextCtrl::OnFocus) -END_EVENT_TABLE() - -// ---------------------------------------------------------------------------- -// wxSearchButton: search button used by search control -// ---------------------------------------------------------------------------- - -class wxSearchButton : public wxControl -{ -public: - wxSearchButton(wxSearchCtrl *search, int eventType, const wxBitmap& bmp) - : wxControl(search, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxNO_BORDER), - m_search(search), - m_eventType(eventType), - m_bmp(bmp) - { } - - void SetBitmapLabel(const wxBitmap& label) { m_bmp = label; } - - -protected: - wxSize DoGetBestSize() const - { - return wxSize(m_bmp.GetWidth(), m_bmp.GetHeight()); - } - - void OnLeftUp(wxMouseEvent&) - { - wxCommandEvent event(m_eventType, m_search->GetId()); - event.SetEventObject(m_search); - - GetEventHandler()->ProcessEvent(event); - - m_search->SetFocus(); - -#if wxUSE_MENUS - if ( m_eventType == wxEVT_COMMAND_SEARCHCTRL_SEARCH_BTN ) - { - // this happens automatically, just like on Mac OS X - m_search->PopupSearchMenu(); - } -#endif // wxUSE_MENUS - } - - void OnPaint(wxPaintEvent&) - { - wxPaintDC dc(this); - dc.DrawBitmap(m_bmp, 0,0, true); - } - - -private: - wxSearchCtrl *m_search; - wxEventType m_eventType; - wxBitmap m_bmp; - - DECLARE_EVENT_TABLE() -}; - -BEGIN_EVENT_TABLE(wxSearchButton, wxControl) - EVT_LEFT_UP(wxSearchButton::OnLeftUp) - EVT_PAINT(wxSearchButton::OnPaint) -END_EVENT_TABLE() - -BEGIN_EVENT_TABLE(wxSearchCtrl, wxSearchCtrlBase) - EVT_SEARCHCTRL_SEARCH_BTN(wxID_ANY, wxSearchCtrl::OnSearchButton) - EVT_SET_FOCUS(wxSearchCtrl::OnSetFocus) - EVT_SIZE(wxSearchCtrl::OnSize) -END_EVENT_TABLE() - -IMPLEMENT_DYNAMIC_CLASS(wxSearchCtrl, wxSearchCtrlBase) - -// ============================================================================ -// implementation -// ============================================================================ - -// ---------------------------------------------------------------------------- -// wxSearchCtrl creation -// ---------------------------------------------------------------------------- - -// creation -// -------- - -wxSearchCtrl::wxSearchCtrl() -{ - Init(); -} - -wxSearchCtrl::wxSearchCtrl(wxWindow *parent, wxWindowID id, - const wxString& value, - const wxPoint& pos, - const wxSize& size, - long style, - const wxValidator& validator, - const wxString& name) -{ - Init(); - - Create(parent, id, value, pos, size, style, validator, name); -} - -void wxSearchCtrl::Init() -{ - m_text = NULL; - m_searchButton = NULL; - m_cancelButton = NULL; -#if wxUSE_MENUS - m_menu = NULL; -#endif // wxUSE_MENUS - - m_searchButtonVisible = true; - m_cancelButtonVisible = false; - - m_searchBitmapUser = false; - m_cancelBitmapUser = false; -#if wxUSE_MENUS - m_searchMenuBitmapUser = false; -#endif // wxUSE_MENUS -} - -bool wxSearchCtrl::Create(wxWindow *parent, wxWindowID id, - const wxString& value, - const wxPoint& pos, - const wxSize& size, - long style, - const wxValidator& validator, - const wxString& name) -{ - int borderStyle = wxBORDER_SIMPLE; - -#if defined(__WXMSW__) - borderStyle = GetThemedBorderStyle(); - if (borderStyle == wxBORDER_SUNKEN) - borderStyle = wxBORDER_SIMPLE; -#elif defined(__WXGTK__) - borderStyle = wxBORDER_SUNKEN; -#endif - - if ( !wxTextCtrlBase::Create(parent, id, pos, size, borderStyle | (style & ~wxBORDER_MASK), validator, name) ) - { - return false; - } - - m_text = new wxSearchTextCtrl(this, value, style & ~wxBORDER_MASK); - m_text->SetDescriptiveText(_("Search")); - - wxSize sizeText = m_text->GetBestSize(); - - m_searchButton = new wxSearchButton(this,wxEVT_COMMAND_SEARCHCTRL_SEARCH_BTN,m_searchBitmap); - m_cancelButton = new wxSearchButton(this,wxEVT_COMMAND_SEARCHCTRL_CANCEL_BTN,m_cancelBitmap); - - SetForegroundColour( m_text->GetForegroundColour() ); - m_searchButton->SetForegroundColour( m_text->GetForegroundColour() ); - m_cancelButton->SetForegroundColour( m_text->GetForegroundColour() ); - - SetBackgroundColour( m_text->GetBackgroundColour() ); - m_searchButton->SetBackgroundColour( m_text->GetBackgroundColour() ); - m_cancelButton->SetBackgroundColour( m_text->GetBackgroundColour() ); - - RecalcBitmaps(); - - SetInitialSize(size); - Move(pos); - return true; -} - -wxSearchCtrl::~wxSearchCtrl() -{ - delete m_text; - delete m_searchButton; - delete m_cancelButton; -#if wxUSE_MENUS - delete m_menu; -#endif // wxUSE_MENUS -} - - -// search control specific interfaces -#if wxUSE_MENUS - -void wxSearchCtrl::SetMenu( wxMenu* menu ) -{ - if ( menu == m_menu ) - { - // no change - return; - } - bool hadMenu = (m_menu != NULL); - delete m_menu; - m_menu = menu; - - if ( m_menu && !hadMenu ) - { - m_searchButton->SetBitmapLabel(m_searchMenuBitmap); - m_searchButton->Refresh(); - } - else if ( !m_menu && hadMenu ) - { - m_searchButton->SetBitmapLabel(m_searchBitmap); - if ( m_searchButtonVisible ) - { - m_searchButton->Refresh(); - } - } - wxRect rect = GetRect(); - LayoutControls(0, 0, rect.GetWidth(), rect.GetHeight()); -} - -wxMenu* wxSearchCtrl::GetMenu() -{ - return m_menu; -} - -#endif // wxUSE_MENUS - -void wxSearchCtrl::ShowSearchButton( bool show ) -{ - if ( m_searchButtonVisible == show ) - { - // no change - return; - } - m_searchButtonVisible = show; - if ( m_searchButtonVisible ) - { - RecalcBitmaps(); - } - - wxRect rect = GetRect(); - LayoutControls(0, 0, rect.GetWidth(), rect.GetHeight()); -} - -bool wxSearchCtrl::IsSearchButtonVisible() const -{ - return m_searchButtonVisible; -} - - -void wxSearchCtrl::ShowCancelButton( bool show ) -{ - if ( m_cancelButtonVisible == show ) - { - // no change - return; - } - m_cancelButtonVisible = show; - - wxRect rect = GetRect(); - LayoutControls(0, 0, rect.GetWidth(), rect.GetHeight()); -} - -bool wxSearchCtrl::IsCancelButtonVisible() const -{ - return m_cancelButtonVisible; -} - -void wxSearchCtrl::SetDescriptiveText(const wxString& text) -{ - m_text->SetDescriptiveText(text); -} - -wxString wxSearchCtrl::GetDescriptiveText() const -{ - return m_text->GetDescriptiveText(); -} - -// ---------------------------------------------------------------------------- -// geometry -// ---------------------------------------------------------------------------- - -wxSize wxSearchCtrl::DoGetBestSize() const -{ - wxSize sizeText = m_text->GetBestSize(); - wxSize sizeSearch(0,0); - wxSize sizeCancel(0,0); - int searchMargin = 0; - int cancelMargin = 0; - if ( m_searchButtonVisible || HasMenu() ) - { - sizeSearch = m_searchButton->GetBestSize(); - searchMargin = MARGIN; - } - if ( m_cancelButtonVisible ) - { - sizeCancel = m_cancelButton->GetBestSize(); - cancelMargin = MARGIN; - } - - int horizontalBorder = 1 + ( sizeText.y - sizeText.y * 14 / 21 ) / 2; - - // buttons are square and equal to the height of the text control - int height = sizeText.y; - return wxSize(sizeSearch.x + searchMargin + sizeText.x + cancelMargin + sizeCancel.x + 2*horizontalBorder, - height + 2*BORDER); -} - -void wxSearchCtrl::DoMoveWindow(int x, int y, int width, int height) -{ - wxSearchCtrlBase::DoMoveWindow(x, y, width, height); - - LayoutControls(0, 0, width, height); -} - -void wxSearchCtrl::LayoutControls(int x, int y, int width, int height) -{ - if ( !m_text ) - return; - - wxSize sizeText = m_text->GetBestSize(); - // make room for the search menu & clear button - int horizontalBorder = ( sizeText.y - sizeText.y * 14 / 21 ) / 2; - x += horizontalBorder; - y += BORDER; - width -= horizontalBorder*2; - height -= BORDER*2; - - wxSize sizeSearch(0,0); - wxSize sizeCancel(0,0); - int searchMargin = 0; - int cancelMargin = 0; - if ( m_searchButtonVisible || HasMenu() ) - { - sizeSearch = m_searchButton->GetBestSize(); - searchMargin = MARGIN; - } - if ( m_cancelButtonVisible ) - { - sizeCancel = m_cancelButton->GetBestSize(); - cancelMargin = MARGIN; - } - m_searchButton->Show( m_searchButtonVisible || HasMenu() ); - m_cancelButton->Show( m_cancelButtonVisible ); - - if ( sizeSearch.x + sizeCancel.x > width ) - { - sizeSearch.x = width/2; - sizeCancel.x = width/2; - searchMargin = 0; - cancelMargin = 0; - } - wxCoord textWidth = width - sizeSearch.x - sizeCancel.x - searchMargin - cancelMargin - 1; - - // position the subcontrols inside the client area - - m_searchButton->SetSize(x, y + ICON_OFFSET - 1, sizeSearch.x, height); - m_text->SetSize( x + sizeSearch.x + searchMargin, - y + ICON_OFFSET - BORDER, - textWidth, - height); - m_cancelButton->SetSize(x + sizeSearch.x + searchMargin + textWidth + cancelMargin, - y + ICON_OFFSET - 1, sizeCancel.x, height); -} - - -// accessors -// --------- - -wxString wxSearchCtrl::GetValue() const -{ - wxString value = m_text->GetValue(); - if (value == m_text->GetDescriptiveText()) - return wxEmptyString; - else - return value; -} -void wxSearchCtrl::SetValue(const wxString& value) -{ - m_text->SetValue(value); -} - -wxString wxSearchCtrl::GetRange(long from, long to) const -{ - return m_text->GetRange(from, to); -} - -int wxSearchCtrl::GetLineLength(long lineNo) const -{ - return m_text->GetLineLength(lineNo); -} -wxString wxSearchCtrl::GetLineText(long lineNo) const -{ - return m_text->GetLineText(lineNo); -} -int wxSearchCtrl::GetNumberOfLines() const -{ - return m_text->GetNumberOfLines(); -} - -bool wxSearchCtrl::IsModified() const -{ - return m_text->IsModified(); -} -bool wxSearchCtrl::IsEditable() const -{ - return m_text->IsEditable(); -} - -// more readable flag testing methods -bool wxSearchCtrl::IsSingleLine() const -{ - return m_text->IsSingleLine(); -} -bool wxSearchCtrl::IsMultiLine() const -{ - return m_text->IsMultiLine(); -} - -// If the return values from and to are the same, there is no selection. -void wxSearchCtrl::GetSelection(long* from, long* to) const -{ - m_text->GetSelection(from, to); -} - -wxString wxSearchCtrl::GetStringSelection() const -{ - return m_text->GetStringSelection(); -} - -// operations -// ---------- - -// editing -void wxSearchCtrl::Clear() -{ - m_text->Clear(); -} -void wxSearchCtrl::Replace(long from, long to, const wxString& value) -{ - m_text->Replace(from, to, value); -} -void wxSearchCtrl::Remove(long from, long to) -{ - m_text->Remove(from, to); -} - -// load/save the controls contents from/to the file -bool wxSearchCtrl::LoadFile(const wxString& file) -{ - return m_text->LoadFile(file); -} -bool wxSearchCtrl::SaveFile(const wxString& file) -{ - return m_text->SaveFile(file); -} - -// sets/clears the dirty flag -void wxSearchCtrl::MarkDirty() -{ - m_text->MarkDirty(); -} -void wxSearchCtrl::DiscardEdits() -{ - m_text->DiscardEdits(); -} - -// set the max number of characters which may be entered in a single line -// text control -void wxSearchCtrl::SetMaxLength(unsigned long len) -{ - m_text->SetMaxLength(len); -} - -// writing text inserts it at the current position, appending always -// inserts it at the end -void wxSearchCtrl::WriteText(const wxString& text) -{ - m_text->WriteText(text); -} -void wxSearchCtrl::AppendText(const wxString& text) -{ - m_text->AppendText(text); -} - -// insert the character which would have resulted from this key event, -// return true if anything has been inserted -bool wxSearchCtrl::EmulateKeyPress(const wxKeyEvent& event) -{ - return m_text->EmulateKeyPress(event); -} - -// text control under some platforms supports the text styles: these -// methods allow to apply the given text style to the given selection or to -// set/get the style which will be used for all appended text -bool wxSearchCtrl::SetStyle(long start, long end, const wxTextAttr& style) -{ - return m_text->SetStyle(start, end, style); -} -bool wxSearchCtrl::GetStyle(long position, wxTextAttr& style) -{ - return m_text->GetStyle(position, style); -} -bool wxSearchCtrl::SetDefaultStyle(const wxTextAttr& style) -{ - return m_text->SetDefaultStyle(style); -} -const wxTextAttr& wxSearchCtrl::GetDefaultStyle() const -{ - return m_text->GetDefaultStyle(); -} - -// translate between the position (which is just an index in the text ctrl -// considering all its contents as a single strings) and (x, y) coordinates -// which represent column and line. -long wxSearchCtrl::XYToPosition(long x, long y) const -{ - return m_text->XYToPosition(x, y); -} -bool wxSearchCtrl::PositionToXY(long pos, long *x, long *y) const -{ - return m_text->PositionToXY(pos, x, y); -} - -void wxSearchCtrl::ShowPosition(long pos) -{ - m_text->ShowPosition(pos); -} - -// find the character at position given in pixels -// -// NB: pt is in device coords (not adjusted for the client area origin nor -// scrolling) -wxTextCtrlHitTestResult wxSearchCtrl::HitTest(const wxPoint& pt, long *pos) const -{ - return m_text->HitTest(pt, pos); -} -wxTextCtrlHitTestResult wxSearchCtrl::HitTest(const wxPoint& pt, - wxTextCoord *col, - wxTextCoord *row) const -{ - return m_text->HitTest(pt, col, row); -} - -// Clipboard operations -void wxSearchCtrl::Copy() -{ - m_text->Copy(); -} -void wxSearchCtrl::Cut() -{ - m_text->Cut(); -} -void wxSearchCtrl::Paste() -{ - m_text->Paste(); -} - -bool wxSearchCtrl::CanCopy() const -{ - return m_text->CanCopy(); -} -bool wxSearchCtrl::CanCut() const -{ - return m_text->CanCut(); -} -bool wxSearchCtrl::CanPaste() const -{ - return m_text->CanPaste(); -} - -// Undo/redo -void wxSearchCtrl::Undo() -{ - m_text->Undo(); -} -void wxSearchCtrl::Redo() -{ - m_text->Redo(); -} - -bool wxSearchCtrl::CanUndo() const -{ - return m_text->CanUndo(); -} -bool wxSearchCtrl::CanRedo() const -{ - return m_text->CanRedo(); -} - -// Insertion point -void wxSearchCtrl::SetInsertionPoint(long pos) -{ - m_text->SetInsertionPoint(pos); -} -void wxSearchCtrl::SetInsertionPointEnd() -{ - m_text->SetInsertionPointEnd(); -} -long wxSearchCtrl::GetInsertionPoint() const -{ - return m_text->GetInsertionPoint(); -} -wxTextPos wxSearchCtrl::GetLastPosition() const -{ - return m_text->GetLastPosition(); -} - -void wxSearchCtrl::SetSelection(long from, long to) -{ - m_text->SetSelection(from, to); -} -void wxSearchCtrl::SelectAll() -{ - m_text->SelectAll(); -} - -void wxSearchCtrl::SetEditable(bool editable) -{ - m_text->SetEditable(editable); -} - -bool wxSearchCtrl::SetFont(const wxFont& font) -{ - bool result = wxSearchCtrlBase::SetFont(font); - if ( result && m_text ) - { - result = m_text->SetFont(font); - } - RecalcBitmaps(); - return result; -} - -// search control generic only -void wxSearchCtrl::SetSearchBitmap( const wxBitmap& bitmap ) -{ - m_searchBitmap = bitmap; - m_searchBitmapUser = bitmap.Ok(); - if ( m_searchBitmapUser ) - { - if ( m_searchButton && !HasMenu() ) - { - m_searchButton->SetBitmapLabel( m_searchBitmap ); - } - } - else - { - // the user bitmap was just cleared, generate one - RecalcBitmaps(); - } -} - -#if wxUSE_MENUS - -void wxSearchCtrl::SetSearchMenuBitmap( const wxBitmap& bitmap ) -{ - m_searchMenuBitmap = bitmap; - m_searchMenuBitmapUser = bitmap.Ok(); - if ( m_searchMenuBitmapUser ) - { - if ( m_searchButton && m_menu ) - { - m_searchButton->SetBitmapLabel( m_searchMenuBitmap ); - } - } - else - { - // the user bitmap was just cleared, generate one - RecalcBitmaps(); - } -} - -#endif // wxUSE_MENUS - -void wxSearchCtrl::SetCancelBitmap( const wxBitmap& bitmap ) -{ - m_cancelBitmap = bitmap; - m_cancelBitmapUser = bitmap.Ok(); - if ( m_cancelBitmapUser ) - { - if ( m_cancelButton ) - { - m_cancelButton->SetBitmapLabel( m_cancelBitmap ); - } - } - else - { - // the user bitmap was just cleared, generate one - RecalcBitmaps(); - } -} - -#if 0 - -// override streambuf method -#if wxHAS_TEXT_WINDOW_STREAM -int overflow(int i); -#endif // wxHAS_TEXT_WINDOW_STREAM - -// stream-like insertion operators: these are always available, whether we -// were, or not, compiled with streambuf support -wxTextCtrl& operator<<(const wxString& s); -wxTextCtrl& operator<<(int i); -wxTextCtrl& operator<<(long i); -wxTextCtrl& operator<<(float f); -wxTextCtrl& operator<<(double d); -wxTextCtrl& operator<<(const wxChar c); -#endif - -void wxSearchCtrl::DoSetValue(const wxString& value, int flags) -{ - m_text->ChangeValue( value ); - if ( flags & SetValue_SendEvent ) - SendTextUpdatedEvent(); -} - -// do the window-specific processing after processing the update event -void wxSearchCtrl::DoUpdateWindowUI(wxUpdateUIEvent& event) -{ - wxSearchCtrlBase::DoUpdateWindowUI(event); -} - -bool wxSearchCtrl::ShouldInheritColours() const -{ - return true; -} - -// icons are rendered at 3-8 times larger than necessary and downscaled for -// antialiasing -static int GetMultiplier() -{ -#ifdef __WXWINCE__ - // speed up bitmap generation by using a small bitmap - return 3; -#else - int depth = ::wxDisplayDepth(); - - if ( depth >= 24 ) - { - return 8; - } - return 6; -#endif -} - -wxBitmap wxSearchCtrl::RenderSearchBitmap( int x, int y, bool renderDrop ) -{ - wxColour bg = GetBackgroundColour(); - wxColour fg = wxStepColour(GetForegroundColour(), LIGHT_STEP-20); - - //=============================================================================== - // begin drawing code - //=============================================================================== - // image stats - - // force width:height ratio - if ( 14*x > y*20 ) - { - // x is too big - x = y*20/14; - } - else - { - // y is too big - y = x*14/20; - } - - // glass 11x11, top left corner - // handle (9,9)-(13,13) - // drop (13,16)-(19,6)-(16,9) - - int multiplier = GetMultiplier(); - int penWidth = multiplier * 2; - - penWidth = penWidth * x / 20; - - wxBitmap bitmap( multiplier*x, multiplier*y ); - wxMemoryDC mem; - mem.SelectObject(bitmap); - - // clear background - mem.SetBrush( wxBrush(bg) ); - mem.SetPen( wxPen(bg) ); - mem.DrawRectangle(0,0,bitmap.GetWidth(),bitmap.GetHeight()); - - // draw drop glass - mem.SetBrush( wxBrush(fg) ); - mem.SetPen( wxPen(fg) ); - int glassBase = 5 * x / 20; - int glassFactor = 2*glassBase + 1; - int radius = multiplier*glassFactor/2; - mem.DrawCircle(radius,radius,radius); - mem.SetBrush( wxBrush(bg) ); - mem.SetPen( wxPen(bg) ); - mem.DrawCircle(radius,radius,radius-penWidth); - - // draw handle - int lineStart = radius + (radius-penWidth/2) * 707 / 1000; // 707 / 1000 = 0.707 = 1/sqrt(2); - - mem.SetPen( wxPen(fg) ); - mem.SetBrush( wxBrush(fg) ); - int handleCornerShift = penWidth * 707 / 1000 / 2; // 707 / 1000 = 0.707 = 1/sqrt(2); - handleCornerShift = WXMAX( handleCornerShift, 1 ); - int handleBase = 4 * x / 20; - int handleLength = 2*handleBase+1; - wxPoint handlePolygon[] = - { - wxPoint(-handleCornerShift,+handleCornerShift), - wxPoint(+handleCornerShift,-handleCornerShift), - wxPoint(multiplier*handleLength/2+handleCornerShift,multiplier*handleLength/2-handleCornerShift), - wxPoint(multiplier*handleLength/2-handleCornerShift,multiplier*handleLength/2+handleCornerShift), - }; - mem.DrawPolygon(WXSIZEOF(handlePolygon),handlePolygon,lineStart,lineStart); - - // draw drop triangle - int triangleX = 13 * x / 20; - int triangleY = 5 * x / 20; - int triangleBase = 3 * x / 20; - int triangleFactor = triangleBase*2+1; - if ( renderDrop ) - { - wxPoint dropPolygon[] = - { - wxPoint(multiplier*0,multiplier*0), // triangle left - wxPoint(multiplier*triangleFactor-1,multiplier*0), // triangle right - wxPoint(multiplier*triangleFactor/2,multiplier*triangleFactor/2), // triangle bottom - }; - mem.DrawPolygon(WXSIZEOF(dropPolygon),dropPolygon,multiplier*triangleX,multiplier*triangleY); - } - mem.SelectObject(wxNullBitmap); - - //=============================================================================== - // end drawing code - //=============================================================================== - - if ( multiplier != 1 ) - { - wxImage image = bitmap.ConvertToImage(); - image.Rescale(x,y); - bitmap = wxBitmap( image ); - } - if ( !renderDrop ) - { - // Trim the edge where the arrow would have gone - bitmap = bitmap.GetSubBitmap(wxRect(0,0, y,y)); - } - - return bitmap; -} - -wxBitmap wxSearchCtrl::RenderCancelBitmap( int x, int y ) -{ - wxColour bg = GetBackgroundColour(); - wxColour fg = wxStepColour(GetForegroundColour(), LIGHT_STEP); - - //=============================================================================== - // begin drawing code - //=============================================================================== - // image stats - - // total size 14x14 - // force 1:1 ratio - if ( x > y ) - { - // x is too big - x = y; - } - else - { - // y is too big - y = x; - } - - // 14x14 circle - // cross line starts (4,4)-(10,10) - // drop (13,16)-(19,6)-(16,9) - - int multiplier = GetMultiplier(); - - int penWidth = multiplier * x / 14; - - wxBitmap bitmap( multiplier*x, multiplier*y ); - wxMemoryDC mem; - mem.SelectObject(bitmap); - - // clear background - mem.SetBrush( wxBrush(bg) ); - mem.SetPen( wxPen(bg) ); - mem.DrawRectangle(0,0,bitmap.GetWidth(),bitmap.GetHeight()); - - // draw drop glass - mem.SetBrush( wxBrush(fg) ); - mem.SetPen( wxPen(fg) ); - int radius = multiplier*x/2; - mem.DrawCircle(radius,radius,radius); - - // draw cross - int lineStartBase = 4 * x / 14; - int lineLength = x - 2*lineStartBase; - - mem.SetPen( wxPen(bg) ); - mem.SetBrush( wxBrush(bg) ); - int handleCornerShift = penWidth/2; - handleCornerShift = WXMAX( handleCornerShift, 1 ); - wxPoint handlePolygon[] = - { - wxPoint(-handleCornerShift,+handleCornerShift), - wxPoint(+handleCornerShift,-handleCornerShift), - wxPoint(multiplier*lineLength+handleCornerShift,multiplier*lineLength-handleCornerShift), - wxPoint(multiplier*lineLength-handleCornerShift,multiplier*lineLength+handleCornerShift), - }; - mem.DrawPolygon(WXSIZEOF(handlePolygon),handlePolygon,multiplier*lineStartBase,multiplier*lineStartBase); - wxPoint handlePolygon2[] = - { - wxPoint(+handleCornerShift,+handleCornerShift), - wxPoint(-handleCornerShift,-handleCornerShift), - wxPoint(multiplier*lineLength-handleCornerShift,-multiplier*lineLength-handleCornerShift), - wxPoint(multiplier*lineLength+handleCornerShift,-multiplier*lineLength+handleCornerShift), - }; - mem.DrawPolygon(WXSIZEOF(handlePolygon2),handlePolygon2,multiplier*lineStartBase,multiplier*(x-lineStartBase)); - - //=============================================================================== - // end drawing code - //=============================================================================== - - if ( multiplier != 1 ) - { - wxImage image = bitmap.ConvertToImage(); - image.Rescale(x,y); - bitmap = wxBitmap( image ); - } - - return bitmap; -} - -void wxSearchCtrl::RecalcBitmaps() -{ - if ( !m_text ) - { - return; - } - wxSize sizeText = m_text->GetBestSize(); - - int bitmapHeight = sizeText.y - 2 * ICON_MARGIN; - int bitmapWidth = sizeText.y * 20 / 14; - - if ( !m_searchBitmapUser ) - { - if ( - !m_searchBitmap.Ok() || - m_searchBitmap.GetHeight() != bitmapHeight || - m_searchBitmap.GetWidth() != bitmapWidth - ) - { - m_searchBitmap = RenderSearchBitmap(bitmapWidth,bitmapHeight,false); - if ( !HasMenu() ) - { - m_searchButton->SetBitmapLabel(m_searchBitmap); - } - } - // else this bitmap was set by user, don't alter - } - -#if wxUSE_MENUS - if ( !m_searchMenuBitmapUser ) - { - if ( - !m_searchMenuBitmap.Ok() || - m_searchMenuBitmap.GetHeight() != bitmapHeight || - m_searchMenuBitmap.GetWidth() != bitmapWidth - ) - { - m_searchMenuBitmap = RenderSearchBitmap(bitmapWidth,bitmapHeight,true); - if ( m_menu ) - { - m_searchButton->SetBitmapLabel(m_searchMenuBitmap); - } - } - // else this bitmap was set by user, don't alter - } -#endif // wxUSE_MENUS - - if ( !m_cancelBitmapUser ) - { - if ( - !m_cancelBitmap.Ok() || - m_cancelBitmap.GetHeight() != bitmapHeight || - m_cancelBitmap.GetWidth() != bitmapHeight - ) - { - m_cancelBitmap = RenderCancelBitmap(bitmapHeight-BORDER-1,bitmapHeight-BORDER-1); // square - m_cancelButton->SetBitmapLabel(m_cancelBitmap); - } - // else this bitmap was set by user, don't alter - } -} - -void wxSearchCtrl::OnSearchButton( wxCommandEvent& event ) -{ - event.Skip(); -} - -void wxSearchCtrl::OnSetFocus( wxFocusEvent& /*event*/ ) -{ - if ( m_text ) - { - m_text->SetFocus(); - } -} - -void wxSearchCtrl::OnSize( wxSizeEvent& WXUNUSED(event) ) -{ - int width, height; - GetSize(&width, &height); - LayoutControls(0, 0, width, height); -} - -#if wxUSE_MENUS - -void wxSearchCtrl::PopupSearchMenu() -{ - if ( m_menu ) - { - wxSize size = GetSize(); - PopupMenu( m_menu, 0, size.y ); - } -} - -#endif // wxUSE_MENUS - -#endif // !wxUSE_NATIVE_SEARCH_CONTROL - -#endif // wxUSE_SEARCHCTRL +/////////////////////////////////////////////////////////////////////////////// +// Name: src/generic/srchctlg.cpp +// Purpose: implements wxSearchCtrl as a composite control +// Author: Vince Harron +// Created: 2006-02-19 +// RCS-ID: $Id: srchctlg.cpp 47962 2007-08-08 12:38:13Z JS $ +// Copyright: Vince Harron +// License: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_SEARCHCTRL + +#include "wx/srchctrl.h" + +#ifndef WX_PRECOMP + #include "wx/button.h" + #include "wx/dcclient.h" + #include "wx/menu.h" + #include "wx/dcmemory.h" +#endif //WX_PRECOMP + +#if !wxUSE_NATIVE_SEARCH_CONTROL + +#include "wx/image.h" + +#define WXMAX(a,b) ((a)>(b)?(a):(b)) + +// ---------------------------------------------------------------------------- +// constants +// ---------------------------------------------------------------------------- + +// the margin between the text control and the search/cancel buttons +static const wxCoord MARGIN = 2; + +// border around all controls to compensate for wxSIMPLE_BORDER +#if defined(__WXMSW__) +static const wxCoord BORDER = 0; +static const wxCoord ICON_MARGIN = 2; +static const wxCoord ICON_OFFSET = 2; +#else +static const wxCoord BORDER = 2; +static const wxCoord ICON_MARGIN = 0; +static const wxCoord ICON_OFFSET = 0; +#endif + +// ---------------------------------------------------------------------------- +// TODO: These functions or something like them should probably be made +// public. There are similar functions in src/aui/dockart.cpp... + +static double wxBlendColour(double fg, double bg, double alpha) +{ + double result = bg + (alpha * (fg - bg)); + if (result < 0.0) + result = 0.0; + if (result > 255) + result = 255; + return result; +} + +static wxColor wxStepColour(const wxColor& c, int ialpha) +{ + if (ialpha == 100) + return c; + + double r = c.Red(), g = c.Green(), b = c.Blue(); + double bg; + + // ialpha is 0..200 where 0 is completely black + // and 200 is completely white and 100 is the same + // convert that to normal alpha 0.0 - 1.0 + ialpha = wxMin(ialpha, 200); + ialpha = wxMax(ialpha, 0); + double alpha = ((double)(ialpha - 100.0))/100.0; + + if (ialpha > 100) + { + // blend with white + bg = 255.0; + alpha = 1.0 - alpha; // 0 = transparent fg; 1 = opaque fg + } + else + { + // blend with black + bg = 0.0; + alpha = 1.0 + alpha; // 0 = transparent fg; 1 = opaque fg + } + + r = wxBlendColour(r, bg, alpha); + g = wxBlendColour(g, bg, alpha); + b = wxBlendColour(b, bg, alpha); + + return wxColour((unsigned char)r, (unsigned char)g, (unsigned char)b); +} + +#define LIGHT_STEP 160 + +// ---------------------------------------------------------------------------- +// wxSearchTextCtrl: text control used by search control +// ---------------------------------------------------------------------------- + +class wxSearchTextCtrl : public wxTextCtrl +{ +public: + wxSearchTextCtrl(wxSearchCtrl *search, const wxString& value, int style) + : wxTextCtrl(search, wxID_ANY, value, wxDefaultPosition, wxDefaultSize, + style | wxNO_BORDER) + { + m_search = search; + m_defaultFG = GetForegroundColour(); + + // remove the default minsize, the searchctrl will have one instead + SetSizeHints(wxDefaultCoord,wxDefaultCoord); + } + + void SetDescriptiveText(const wxString& text) + { + if ( GetValue() == m_descriptiveText ) + { + ChangeValue(wxEmptyString); + } + + m_descriptiveText = text; + } + + wxString GetDescriptiveText() const + { + return m_descriptiveText; + } + +protected: + void OnText(wxCommandEvent& eventText) + { + wxCommandEvent event(eventText); + event.SetEventObject(m_search); + event.SetId(m_search->GetId()); + + m_search->GetEventHandler()->ProcessEvent(event); + } + + void OnTextUrl(wxTextUrlEvent& eventText) + { + // copy constructor is disabled for some reason? + //wxTextUrlEvent event(eventText); + wxTextUrlEvent event( + m_search->GetId(), + eventText.GetMouseEvent(), + eventText.GetURLStart(), + eventText.GetURLEnd() + ); + event.SetEventObject(m_search); + + m_search->GetEventHandler()->ProcessEvent(event); + } + + void OnIdle(wxIdleEvent& WXUNUSED(event)) + { + if ( IsEmpty() && !(wxWindow::FindFocus() == this) ) + { + ChangeValue(m_descriptiveText); + SetInsertionPoint(0); + SetForegroundColour(wxStepColour(m_defaultFG, LIGHT_STEP)); + } + } + + void OnFocus(wxFocusEvent& event) + { + event.Skip(); + if ( GetValue() == m_descriptiveText ) + { + ChangeValue(wxEmptyString); + SetForegroundColour(m_defaultFG); + } + } + +private: + wxSearchCtrl* m_search; + wxString m_descriptiveText; + wxColour m_defaultFG; + + DECLARE_EVENT_TABLE() +}; + +BEGIN_EVENT_TABLE(wxSearchTextCtrl, wxTextCtrl) + EVT_TEXT(wxID_ANY, wxSearchTextCtrl::OnText) + EVT_TEXT_ENTER(wxID_ANY, wxSearchTextCtrl::OnText) + EVT_TEXT_URL(wxID_ANY, wxSearchTextCtrl::OnTextUrl) + EVT_TEXT_MAXLEN(wxID_ANY, wxSearchTextCtrl::OnText) + EVT_IDLE(wxSearchTextCtrl::OnIdle) + EVT_SET_FOCUS(wxSearchTextCtrl::OnFocus) +END_EVENT_TABLE() + +// ---------------------------------------------------------------------------- +// wxSearchButton: search button used by search control +// ---------------------------------------------------------------------------- + +class wxSearchButton : public wxControl +{ +public: + wxSearchButton(wxSearchCtrl *search, int eventType, const wxBitmap& bmp) + : wxControl(search, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxNO_BORDER), + m_search(search), + m_eventType(eventType), + m_bmp(bmp) + { } + + void SetBitmapLabel(const wxBitmap& label) { m_bmp = label; } + + +protected: + wxSize DoGetBestSize() const + { + return wxSize(m_bmp.GetWidth(), m_bmp.GetHeight()); + } + + void OnLeftUp(wxMouseEvent&) + { + wxCommandEvent event(m_eventType, m_search->GetId()); + event.SetEventObject(m_search); + + GetEventHandler()->ProcessEvent(event); + + m_search->SetFocus(); + +#if wxUSE_MENUS + if ( m_eventType == wxEVT_COMMAND_SEARCHCTRL_SEARCH_BTN ) + { + // this happens automatically, just like on Mac OS X + m_search->PopupSearchMenu(); + } +#endif // wxUSE_MENUS + } + + void OnPaint(wxPaintEvent&) + { + wxPaintDC dc(this); + dc.DrawBitmap(m_bmp, 0,0, true); + } + + +private: + wxSearchCtrl *m_search; + wxEventType m_eventType; + wxBitmap m_bmp; + + DECLARE_EVENT_TABLE() +}; + +BEGIN_EVENT_TABLE(wxSearchButton, wxControl) + EVT_LEFT_UP(wxSearchButton::OnLeftUp) + EVT_PAINT(wxSearchButton::OnPaint) +END_EVENT_TABLE() + +BEGIN_EVENT_TABLE(wxSearchCtrl, wxSearchCtrlBase) + EVT_SEARCHCTRL_SEARCH_BTN(wxID_ANY, wxSearchCtrl::OnSearchButton) + EVT_SET_FOCUS(wxSearchCtrl::OnSetFocus) + EVT_SIZE(wxSearchCtrl::OnSize) +END_EVENT_TABLE() + +IMPLEMENT_DYNAMIC_CLASS(wxSearchCtrl, wxSearchCtrlBase) + +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// wxSearchCtrl creation +// ---------------------------------------------------------------------------- + +// creation +// -------- + +wxSearchCtrl::wxSearchCtrl() +{ + Init(); +} + +wxSearchCtrl::wxSearchCtrl(wxWindow *parent, wxWindowID id, + const wxString& value, + const wxPoint& pos, + const wxSize& size, + long style, + const wxValidator& validator, + const wxString& name) +{ + Init(); + + Create(parent, id, value, pos, size, style, validator, name); +} + +void wxSearchCtrl::Init() +{ + m_text = NULL; + m_searchButton = NULL; + m_cancelButton = NULL; +#if wxUSE_MENUS + m_menu = NULL; +#endif // wxUSE_MENUS + + m_searchButtonVisible = true; + m_cancelButtonVisible = false; + + m_searchBitmapUser = false; + m_cancelBitmapUser = false; +#if wxUSE_MENUS + m_searchMenuBitmapUser = false; +#endif // wxUSE_MENUS +} + +bool wxSearchCtrl::Create(wxWindow *parent, wxWindowID id, + const wxString& value, + const wxPoint& pos, + const wxSize& size, + long style, + const wxValidator& validator, + const wxString& name) +{ + int borderStyle = wxBORDER_SIMPLE; + +#if defined(__WXMSW__) + borderStyle = GetThemedBorderStyle(); + if (borderStyle == wxBORDER_SUNKEN) + borderStyle = wxBORDER_SIMPLE; +#elif defined(__WXGTK__) + borderStyle = wxBORDER_SUNKEN; +#endif + + if ( !wxTextCtrlBase::Create(parent, id, pos, size, borderStyle | (style & ~wxBORDER_MASK), validator, name) ) + { + return false; + } + + m_text = new wxSearchTextCtrl(this, value, style & ~wxBORDER_MASK); + m_text->SetDescriptiveText(_("Search")); + + wxSize sizeText = m_text->GetBestSize(); + + m_searchButton = new wxSearchButton(this,wxEVT_COMMAND_SEARCHCTRL_SEARCH_BTN,m_searchBitmap); + m_cancelButton = new wxSearchButton(this,wxEVT_COMMAND_SEARCHCTRL_CANCEL_BTN,m_cancelBitmap); + + SetForegroundColour( m_text->GetForegroundColour() ); + m_searchButton->SetForegroundColour( m_text->GetForegroundColour() ); + m_cancelButton->SetForegroundColour( m_text->GetForegroundColour() ); + + SetBackgroundColour( m_text->GetBackgroundColour() ); + m_searchButton->SetBackgroundColour( m_text->GetBackgroundColour() ); + m_cancelButton->SetBackgroundColour( m_text->GetBackgroundColour() ); + + RecalcBitmaps(); + + SetInitialSize(size); + Move(pos); + return true; +} + +wxSearchCtrl::~wxSearchCtrl() +{ + delete m_text; + delete m_searchButton; + delete m_cancelButton; +#if wxUSE_MENUS + delete m_menu; +#endif // wxUSE_MENUS +} + + +// search control specific interfaces +#if wxUSE_MENUS + +void wxSearchCtrl::SetMenu( wxMenu* menu ) +{ + if ( menu == m_menu ) + { + // no change + return; + } + bool hadMenu = (m_menu != NULL); + delete m_menu; + m_menu = menu; + + if ( m_menu && !hadMenu ) + { + m_searchButton->SetBitmapLabel(m_searchMenuBitmap); + m_searchButton->Refresh(); + } + else if ( !m_menu && hadMenu ) + { + m_searchButton->SetBitmapLabel(m_searchBitmap); + if ( m_searchButtonVisible ) + { + m_searchButton->Refresh(); + } + } + wxRect rect = GetRect(); + LayoutControls(0, 0, rect.GetWidth(), rect.GetHeight()); +} + +wxMenu* wxSearchCtrl::GetMenu() +{ + return m_menu; +} + +#endif // wxUSE_MENUS + +void wxSearchCtrl::ShowSearchButton( bool show ) +{ + if ( m_searchButtonVisible == show ) + { + // no change + return; + } + m_searchButtonVisible = show; + if ( m_searchButtonVisible ) + { + RecalcBitmaps(); + } + + wxRect rect = GetRect(); + LayoutControls(0, 0, rect.GetWidth(), rect.GetHeight()); +} + +bool wxSearchCtrl::IsSearchButtonVisible() const +{ + return m_searchButtonVisible; +} + + +void wxSearchCtrl::ShowCancelButton( bool show ) +{ + if ( m_cancelButtonVisible == show ) + { + // no change + return; + } + m_cancelButtonVisible = show; + + wxRect rect = GetRect(); + LayoutControls(0, 0, rect.GetWidth(), rect.GetHeight()); +} + +bool wxSearchCtrl::IsCancelButtonVisible() const +{ + return m_cancelButtonVisible; +} + +void wxSearchCtrl::SetDescriptiveText(const wxString& text) +{ + m_text->SetDescriptiveText(text); +} + +wxString wxSearchCtrl::GetDescriptiveText() const +{ + return m_text->GetDescriptiveText(); +} + +// ---------------------------------------------------------------------------- +// geometry +// ---------------------------------------------------------------------------- + +wxSize wxSearchCtrl::DoGetBestSize() const +{ + wxSize sizeText = m_text->GetBestSize(); + wxSize sizeSearch(0,0); + wxSize sizeCancel(0,0); + int searchMargin = 0; + int cancelMargin = 0; + if ( m_searchButtonVisible || HasMenu() ) + { + sizeSearch = m_searchButton->GetBestSize(); + searchMargin = MARGIN; + } + if ( m_cancelButtonVisible ) + { + sizeCancel = m_cancelButton->GetBestSize(); + cancelMargin = MARGIN; + } + + int horizontalBorder = 1 + ( sizeText.y - sizeText.y * 14 / 21 ) / 2; + + // buttons are square and equal to the height of the text control + int height = sizeText.y; + return wxSize(sizeSearch.x + searchMargin + sizeText.x + cancelMargin + sizeCancel.x + 2*horizontalBorder, + height + 2*BORDER); +} + +void wxSearchCtrl::DoMoveWindow(int x, int y, int width, int height) +{ + wxSearchCtrlBase::DoMoveWindow(x, y, width, height); + + LayoutControls(0, 0, width, height); +} + +void wxSearchCtrl::LayoutControls(int x, int y, int width, int height) +{ + if ( !m_text ) + return; + + wxSize sizeText = m_text->GetBestSize(); + // make room for the search menu & clear button + int horizontalBorder = ( sizeText.y - sizeText.y * 14 / 21 ) / 2; + x += horizontalBorder; + y += BORDER; + width -= horizontalBorder*2; + height -= BORDER*2; + + wxSize sizeSearch(0,0); + wxSize sizeCancel(0,0); + int searchMargin = 0; + int cancelMargin = 0; + if ( m_searchButtonVisible || HasMenu() ) + { + sizeSearch = m_searchButton->GetBestSize(); + searchMargin = MARGIN; + } + if ( m_cancelButtonVisible ) + { + sizeCancel = m_cancelButton->GetBestSize(); + cancelMargin = MARGIN; + } + m_searchButton->Show( m_searchButtonVisible || HasMenu() ); + m_cancelButton->Show( m_cancelButtonVisible ); + + if ( sizeSearch.x + sizeCancel.x > width ) + { + sizeSearch.x = width/2; + sizeCancel.x = width/2; + searchMargin = 0; + cancelMargin = 0; + } + wxCoord textWidth = width - sizeSearch.x - sizeCancel.x - searchMargin - cancelMargin - 1; + + // position the subcontrols inside the client area + + m_searchButton->SetSize(x, y + ICON_OFFSET - 1, sizeSearch.x, height); + m_text->SetSize( x + sizeSearch.x + searchMargin, + y + ICON_OFFSET - BORDER, + textWidth, + height); + m_cancelButton->SetSize(x + sizeSearch.x + searchMargin + textWidth + cancelMargin, + y + ICON_OFFSET - 1, sizeCancel.x, height); +} + + +// accessors +// --------- + +wxString wxSearchCtrl::GetValue() const +{ + wxString value = m_text->GetValue(); + if (value == m_text->GetDescriptiveText()) + return wxEmptyString; + else + return value; +} +void wxSearchCtrl::SetValue(const wxString& value) +{ + m_text->SetValue(value); +} + +wxString wxSearchCtrl::GetRange(long from, long to) const +{ + return m_text->GetRange(from, to); +} + +int wxSearchCtrl::GetLineLength(long lineNo) const +{ + return m_text->GetLineLength(lineNo); +} +wxString wxSearchCtrl::GetLineText(long lineNo) const +{ + return m_text->GetLineText(lineNo); +} +int wxSearchCtrl::GetNumberOfLines() const +{ + return m_text->GetNumberOfLines(); +} + +bool wxSearchCtrl::IsModified() const +{ + return m_text->IsModified(); +} +bool wxSearchCtrl::IsEditable() const +{ + return m_text->IsEditable(); +} + +// more readable flag testing methods +bool wxSearchCtrl::IsSingleLine() const +{ + return m_text->IsSingleLine(); +} +bool wxSearchCtrl::IsMultiLine() const +{ + return m_text->IsMultiLine(); +} + +// If the return values from and to are the same, there is no selection. +void wxSearchCtrl::GetSelection(long* from, long* to) const +{ + m_text->GetSelection(from, to); +} + +wxString wxSearchCtrl::GetStringSelection() const +{ + return m_text->GetStringSelection(); +} + +// operations +// ---------- + +// editing +void wxSearchCtrl::Clear() +{ + m_text->Clear(); +} +void wxSearchCtrl::Replace(long from, long to, const wxString& value) +{ + m_text->Replace(from, to, value); +} +void wxSearchCtrl::Remove(long from, long to) +{ + m_text->Remove(from, to); +} + +// load/save the controls contents from/to the file +bool wxSearchCtrl::LoadFile(const wxString& file) +{ + return m_text->LoadFile(file); +} +bool wxSearchCtrl::SaveFile(const wxString& file) +{ + return m_text->SaveFile(file); +} + +// sets/clears the dirty flag +void wxSearchCtrl::MarkDirty() +{ + m_text->MarkDirty(); +} +void wxSearchCtrl::DiscardEdits() +{ + m_text->DiscardEdits(); +} + +// set the max number of characters which may be entered in a single line +// text control +void wxSearchCtrl::SetMaxLength(unsigned long len) +{ + m_text->SetMaxLength(len); +} + +// writing text inserts it at the current position, appending always +// inserts it at the end +void wxSearchCtrl::WriteText(const wxString& text) +{ + m_text->WriteText(text); +} +void wxSearchCtrl::AppendText(const wxString& text) +{ + m_text->AppendText(text); +} + +// insert the character which would have resulted from this key event, +// return true if anything has been inserted +bool wxSearchCtrl::EmulateKeyPress(const wxKeyEvent& event) +{ + return m_text->EmulateKeyPress(event); +} + +// text control under some platforms supports the text styles: these +// methods allow to apply the given text style to the given selection or to +// set/get the style which will be used for all appended text +bool wxSearchCtrl::SetStyle(long start, long end, const wxTextAttr& style) +{ + return m_text->SetStyle(start, end, style); +} +bool wxSearchCtrl::GetStyle(long position, wxTextAttr& style) +{ + return m_text->GetStyle(position, style); +} +bool wxSearchCtrl::SetDefaultStyle(const wxTextAttr& style) +{ + return m_text->SetDefaultStyle(style); +} +const wxTextAttr& wxSearchCtrl::GetDefaultStyle() const +{ + return m_text->GetDefaultStyle(); +} + +// translate between the position (which is just an index in the text ctrl +// considering all its contents as a single strings) and (x, y) coordinates +// which represent column and line. +long wxSearchCtrl::XYToPosition(long x, long y) const +{ + return m_text->XYToPosition(x, y); +} +bool wxSearchCtrl::PositionToXY(long pos, long *x, long *y) const +{ + return m_text->PositionToXY(pos, x, y); +} + +void wxSearchCtrl::ShowPosition(long pos) +{ + m_text->ShowPosition(pos); +} + +// find the character at position given in pixels +// +// NB: pt is in device coords (not adjusted for the client area origin nor +// scrolling) +wxTextCtrlHitTestResult wxSearchCtrl::HitTest(const wxPoint& pt, long *pos) const +{ + return m_text->HitTest(pt, pos); +} +wxTextCtrlHitTestResult wxSearchCtrl::HitTest(const wxPoint& pt, + wxTextCoord *col, + wxTextCoord *row) const +{ + return m_text->HitTest(pt, col, row); +} + +// Clipboard operations +void wxSearchCtrl::Copy() +{ + m_text->Copy(); +} +void wxSearchCtrl::Cut() +{ + m_text->Cut(); +} +void wxSearchCtrl::Paste() +{ + m_text->Paste(); +} + +bool wxSearchCtrl::CanCopy() const +{ + return m_text->CanCopy(); +} +bool wxSearchCtrl::CanCut() const +{ + return m_text->CanCut(); +} +bool wxSearchCtrl::CanPaste() const +{ + return m_text->CanPaste(); +} + +// Undo/redo +void wxSearchCtrl::Undo() +{ + m_text->Undo(); +} +void wxSearchCtrl::Redo() +{ + m_text->Redo(); +} + +bool wxSearchCtrl::CanUndo() const +{ + return m_text->CanUndo(); +} +bool wxSearchCtrl::CanRedo() const +{ + return m_text->CanRedo(); +} + +// Insertion point +void wxSearchCtrl::SetInsertionPoint(long pos) +{ + m_text->SetInsertionPoint(pos); +} +void wxSearchCtrl::SetInsertionPointEnd() +{ + m_text->SetInsertionPointEnd(); +} +long wxSearchCtrl::GetInsertionPoint() const +{ + return m_text->GetInsertionPoint(); +} +wxTextPos wxSearchCtrl::GetLastPosition() const +{ + return m_text->GetLastPosition(); +} + +void wxSearchCtrl::SetSelection(long from, long to) +{ + m_text->SetSelection(from, to); +} +void wxSearchCtrl::SelectAll() +{ + m_text->SelectAll(); +} + +void wxSearchCtrl::SetEditable(bool editable) +{ + m_text->SetEditable(editable); +} + +bool wxSearchCtrl::SetFont(const wxFont& font) +{ + bool result = wxSearchCtrlBase::SetFont(font); + if ( result && m_text ) + { + result = m_text->SetFont(font); + } + RecalcBitmaps(); + return result; +} + +// search control generic only +void wxSearchCtrl::SetSearchBitmap( const wxBitmap& bitmap ) +{ + m_searchBitmap = bitmap; + m_searchBitmapUser = bitmap.Ok(); + if ( m_searchBitmapUser ) + { + if ( m_searchButton && !HasMenu() ) + { + m_searchButton->SetBitmapLabel( m_searchBitmap ); + } + } + else + { + // the user bitmap was just cleared, generate one + RecalcBitmaps(); + } +} + +#if wxUSE_MENUS + +void wxSearchCtrl::SetSearchMenuBitmap( const wxBitmap& bitmap ) +{ + m_searchMenuBitmap = bitmap; + m_searchMenuBitmapUser = bitmap.Ok(); + if ( m_searchMenuBitmapUser ) + { + if ( m_searchButton && m_menu ) + { + m_searchButton->SetBitmapLabel( m_searchMenuBitmap ); + } + } + else + { + // the user bitmap was just cleared, generate one + RecalcBitmaps(); + } +} + +#endif // wxUSE_MENUS + +void wxSearchCtrl::SetCancelBitmap( const wxBitmap& bitmap ) +{ + m_cancelBitmap = bitmap; + m_cancelBitmapUser = bitmap.Ok(); + if ( m_cancelBitmapUser ) + { + if ( m_cancelButton ) + { + m_cancelButton->SetBitmapLabel( m_cancelBitmap ); + } + } + else + { + // the user bitmap was just cleared, generate one + RecalcBitmaps(); + } +} + +#if 0 + +// override streambuf method +#if wxHAS_TEXT_WINDOW_STREAM +int overflow(int i); +#endif // wxHAS_TEXT_WINDOW_STREAM + +// stream-like insertion operators: these are always available, whether we +// were, or not, compiled with streambuf support +wxTextCtrl& operator<<(const wxString& s); +wxTextCtrl& operator<<(int i); +wxTextCtrl& operator<<(long i); +wxTextCtrl& operator<<(float f); +wxTextCtrl& operator<<(double d); +wxTextCtrl& operator<<(const wxChar c); +#endif + +void wxSearchCtrl::DoSetValue(const wxString& value, int flags) +{ + m_text->ChangeValue( value ); + if ( flags & SetValue_SendEvent ) + SendTextUpdatedEvent(); +} + +// do the window-specific processing after processing the update event +void wxSearchCtrl::DoUpdateWindowUI(wxUpdateUIEvent& event) +{ + wxSearchCtrlBase::DoUpdateWindowUI(event); +} + +bool wxSearchCtrl::ShouldInheritColours() const +{ + return true; +} + +// icons are rendered at 3-8 times larger than necessary and downscaled for +// antialiasing +static int GetMultiplier() +{ +#ifdef __WXWINCE__ + // speed up bitmap generation by using a small bitmap + return 3; +#else + int depth = ::wxDisplayDepth(); + + if ( depth >= 24 ) + { + return 8; + } + return 6; +#endif +} + +wxBitmap wxSearchCtrl::RenderSearchBitmap( int x, int y, bool renderDrop ) +{ + wxColour bg = GetBackgroundColour(); + wxColour fg = wxStepColour(GetForegroundColour(), LIGHT_STEP-20); + + //=============================================================================== + // begin drawing code + //=============================================================================== + // image stats + + // force width:height ratio + if ( 14*x > y*20 ) + { + // x is too big + x = y*20/14; + } + else + { + // y is too big + y = x*14/20; + } + + // glass 11x11, top left corner + // handle (9,9)-(13,13) + // drop (13,16)-(19,6)-(16,9) + + int multiplier = GetMultiplier(); + int penWidth = multiplier * 2; + + penWidth = penWidth * x / 20; + + wxBitmap bitmap( multiplier*x, multiplier*y ); + wxMemoryDC mem; + mem.SelectObject(bitmap); + + // clear background + mem.SetBrush( wxBrush(bg) ); + mem.SetPen( wxPen(bg) ); + mem.DrawRectangle(0,0,bitmap.GetWidth(),bitmap.GetHeight()); + + // draw drop glass + mem.SetBrush( wxBrush(fg) ); + mem.SetPen( wxPen(fg) ); + int glassBase = 5 * x / 20; + int glassFactor = 2*glassBase + 1; + int radius = multiplier*glassFactor/2; + mem.DrawCircle(radius,radius,radius); + mem.SetBrush( wxBrush(bg) ); + mem.SetPen( wxPen(bg) ); + mem.DrawCircle(radius,radius,radius-penWidth); + + // draw handle + int lineStart = radius + (radius-penWidth/2) * 707 / 1000; // 707 / 1000 = 0.707 = 1/sqrt(2); + + mem.SetPen( wxPen(fg) ); + mem.SetBrush( wxBrush(fg) ); + int handleCornerShift = penWidth * 707 / 1000 / 2; // 707 / 1000 = 0.707 = 1/sqrt(2); + handleCornerShift = WXMAX( handleCornerShift, 1 ); + int handleBase = 4 * x / 20; + int handleLength = 2*handleBase+1; + wxPoint handlePolygon[] = + { + wxPoint(-handleCornerShift,+handleCornerShift), + wxPoint(+handleCornerShift,-handleCornerShift), + wxPoint(multiplier*handleLength/2+handleCornerShift,multiplier*handleLength/2-handleCornerShift), + wxPoint(multiplier*handleLength/2-handleCornerShift,multiplier*handleLength/2+handleCornerShift), + }; + mem.DrawPolygon(WXSIZEOF(handlePolygon),handlePolygon,lineStart,lineStart); + + // draw drop triangle + int triangleX = 13 * x / 20; + int triangleY = 5 * x / 20; + int triangleBase = 3 * x / 20; + int triangleFactor = triangleBase*2+1; + if ( renderDrop ) + { + wxPoint dropPolygon[] = + { + wxPoint(multiplier*0,multiplier*0), // triangle left + wxPoint(multiplier*triangleFactor-1,multiplier*0), // triangle right + wxPoint(multiplier*triangleFactor/2,multiplier*triangleFactor/2), // triangle bottom + }; + mem.DrawPolygon(WXSIZEOF(dropPolygon),dropPolygon,multiplier*triangleX,multiplier*triangleY); + } + mem.SelectObject(wxNullBitmap); + + //=============================================================================== + // end drawing code + //=============================================================================== + + if ( multiplier != 1 ) + { + wxImage image = bitmap.ConvertToImage(); + image.Rescale(x,y); + bitmap = wxBitmap( image ); + } + if ( !renderDrop ) + { + // Trim the edge where the arrow would have gone + bitmap = bitmap.GetSubBitmap(wxRect(0,0, y,y)); + } + + return bitmap; +} + +wxBitmap wxSearchCtrl::RenderCancelBitmap( int x, int y ) +{ + wxColour bg = GetBackgroundColour(); + wxColour fg = wxStepColour(GetForegroundColour(), LIGHT_STEP); + + //=============================================================================== + // begin drawing code + //=============================================================================== + // image stats + + // total size 14x14 + // force 1:1 ratio + if ( x > y ) + { + // x is too big + x = y; + } + else + { + // y is too big + y = x; + } + + // 14x14 circle + // cross line starts (4,4)-(10,10) + // drop (13,16)-(19,6)-(16,9) + + int multiplier = GetMultiplier(); + + int penWidth = multiplier * x / 14; + + wxBitmap bitmap( multiplier*x, multiplier*y ); + wxMemoryDC mem; + mem.SelectObject(bitmap); + + // clear background + mem.SetBrush( wxBrush(bg) ); + mem.SetPen( wxPen(bg) ); + mem.DrawRectangle(0,0,bitmap.GetWidth(),bitmap.GetHeight()); + + // draw drop glass + mem.SetBrush( wxBrush(fg) ); + mem.SetPen( wxPen(fg) ); + int radius = multiplier*x/2; + mem.DrawCircle(radius,radius,radius); + + // draw cross + int lineStartBase = 4 * x / 14; + int lineLength = x - 2*lineStartBase; + + mem.SetPen( wxPen(bg) ); + mem.SetBrush( wxBrush(bg) ); + int handleCornerShift = penWidth/2; + handleCornerShift = WXMAX( handleCornerShift, 1 ); + wxPoint handlePolygon[] = + { + wxPoint(-handleCornerShift,+handleCornerShift), + wxPoint(+handleCornerShift,-handleCornerShift), + wxPoint(multiplier*lineLength+handleCornerShift,multiplier*lineLength-handleCornerShift), + wxPoint(multiplier*lineLength-handleCornerShift,multiplier*lineLength+handleCornerShift), + }; + mem.DrawPolygon(WXSIZEOF(handlePolygon),handlePolygon,multiplier*lineStartBase,multiplier*lineStartBase); + wxPoint handlePolygon2[] = + { + wxPoint(+handleCornerShift,+handleCornerShift), + wxPoint(-handleCornerShift,-handleCornerShift), + wxPoint(multiplier*lineLength-handleCornerShift,-multiplier*lineLength-handleCornerShift), + wxPoint(multiplier*lineLength+handleCornerShift,-multiplier*lineLength+handleCornerShift), + }; + mem.DrawPolygon(WXSIZEOF(handlePolygon2),handlePolygon2,multiplier*lineStartBase,multiplier*(x-lineStartBase)); + + //=============================================================================== + // end drawing code + //=============================================================================== + + if ( multiplier != 1 ) + { + wxImage image = bitmap.ConvertToImage(); + image.Rescale(x,y); + bitmap = wxBitmap( image ); + } + + return bitmap; +} + +void wxSearchCtrl::RecalcBitmaps() +{ + if ( !m_text ) + { + return; + } + wxSize sizeText = m_text->GetBestSize(); + + int bitmapHeight = sizeText.y - 2 * ICON_MARGIN; + int bitmapWidth = sizeText.y * 20 / 14; + + if ( !m_searchBitmapUser ) + { + if ( + !m_searchBitmap.Ok() || + m_searchBitmap.GetHeight() != bitmapHeight || + m_searchBitmap.GetWidth() != bitmapWidth + ) + { + m_searchBitmap = RenderSearchBitmap(bitmapWidth,bitmapHeight,false); + if ( !HasMenu() ) + { + m_searchButton->SetBitmapLabel(m_searchBitmap); + } + } + // else this bitmap was set by user, don't alter + } + +#if wxUSE_MENUS + if ( !m_searchMenuBitmapUser ) + { + if ( + !m_searchMenuBitmap.Ok() || + m_searchMenuBitmap.GetHeight() != bitmapHeight || + m_searchMenuBitmap.GetWidth() != bitmapWidth + ) + { + m_searchMenuBitmap = RenderSearchBitmap(bitmapWidth,bitmapHeight,true); + if ( m_menu ) + { + m_searchButton->SetBitmapLabel(m_searchMenuBitmap); + } + } + // else this bitmap was set by user, don't alter + } +#endif // wxUSE_MENUS + + if ( !m_cancelBitmapUser ) + { + if ( + !m_cancelBitmap.Ok() || + m_cancelBitmap.GetHeight() != bitmapHeight || + m_cancelBitmap.GetWidth() != bitmapHeight + ) + { + m_cancelBitmap = RenderCancelBitmap(bitmapHeight-BORDER-1,bitmapHeight-BORDER-1); // square + m_cancelButton->SetBitmapLabel(m_cancelBitmap); + } + // else this bitmap was set by user, don't alter + } +} + +void wxSearchCtrl::OnSearchButton( wxCommandEvent& event ) +{ + event.Skip(); +} + +void wxSearchCtrl::OnSetFocus( wxFocusEvent& /*event*/ ) +{ + if ( m_text ) + { + m_text->SetFocus(); + } +} + +void wxSearchCtrl::OnSize( wxSizeEvent& WXUNUSED(event) ) +{ + int width, height; + GetSize(&width, &height); + LayoutControls(0, 0, width, height); +} + +#if wxUSE_MENUS + +void wxSearchCtrl::PopupSearchMenu() +{ + if ( m_menu ) + { + wxSize size = GetSize(); + PopupMenu( m_menu, 0, size.y ); + } +} + +#endif // wxUSE_MENUS + +#endif // !wxUSE_NATIVE_SEARCH_CONTROL + +#endif // wxUSE_SEARCHCTRL diff --git a/Externals/wxWidgets/src/generic/statline.cpp b/Externals/wxWidgets/src/generic/statline.cpp index b5f7ab11cc..b65b89c399 100644 --- a/Externals/wxWidgets/src/generic/statline.cpp +++ b/Externals/wxWidgets/src/generic/statline.cpp @@ -1,88 +1,88 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/generic/statline.cpp -// Purpose: a generic wxStaticLine class -// Author: Vadim Zeitlin -// Created: 28.06.99 -// Version: $Id: statline.cpp 39487 2006-05-31 18:27:51Z ABX $ -// Copyright: (c) 1998 Vadim Zeitlin -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -#include "wx/wxprec.h" - -// For compilers that support precompilation, includes "wx.h". - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_STATLINE - -#include "wx/statline.h" - -#ifndef WX_PRECOMP - #include "wx/statbox.h" -#endif - -// ============================================================================ -// implementation -// ============================================================================ - -IMPLEMENT_DYNAMIC_CLASS(wxStaticLine, wxControl) - -// ---------------------------------------------------------------------------- -// wxStaticLine -// ---------------------------------------------------------------------------- - -bool wxStaticLine::Create( wxWindow *parent, - wxWindowID id, - const wxPoint &pos, - const wxSize &size, - long style, - const wxString &name) -{ - m_statbox = NULL; - - if ( !CreateBase(parent, id, pos, size, style, wxDefaultValidator, name) ) - return false; - - // ok, this is ugly but it's better than nothing: use a thin static box to - // emulate static line - - wxSize sizeReal = AdjustSize(size); - - m_statbox = new wxStaticBox(parent, id, wxEmptyString, pos, sizeReal, style, name); - - return true; -} - -wxStaticLine::~wxStaticLine() -{ - delete m_statbox; -} - -WXWidget wxStaticLine::GetMainWidget() const -{ - return m_statbox->GetMainWidget(); -} - -void wxStaticLine::DoSetSize(int x, int y, int width, int height, int sizeFlags) -{ - m_statbox->SetSize(x, y, width, height, sizeFlags); -} - -void wxStaticLine::DoMoveWindow(int x, int y, int width, int height) -{ - m_statbox->SetSize(x, y, width, height); -} - -#endif - // wxUSE_STATLINE +///////////////////////////////////////////////////////////////////////////// +// Name: src/generic/statline.cpp +// Purpose: a generic wxStaticLine class +// Author: Vadim Zeitlin +// Created: 28.06.99 +// Version: $Id: statline.cpp 39487 2006-05-31 18:27:51Z ABX $ +// Copyright: (c) 1998 Vadim Zeitlin +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +#include "wx/wxprec.h" + +// For compilers that support precompilation, includes "wx.h". + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_STATLINE + +#include "wx/statline.h" + +#ifndef WX_PRECOMP + #include "wx/statbox.h" +#endif + +// ============================================================================ +// implementation +// ============================================================================ + +IMPLEMENT_DYNAMIC_CLASS(wxStaticLine, wxControl) + +// ---------------------------------------------------------------------------- +// wxStaticLine +// ---------------------------------------------------------------------------- + +bool wxStaticLine::Create( wxWindow *parent, + wxWindowID id, + const wxPoint &pos, + const wxSize &size, + long style, + const wxString &name) +{ + m_statbox = NULL; + + if ( !CreateBase(parent, id, pos, size, style, wxDefaultValidator, name) ) + return false; + + // ok, this is ugly but it's better than nothing: use a thin static box to + // emulate static line + + wxSize sizeReal = AdjustSize(size); + + m_statbox = new wxStaticBox(parent, id, wxEmptyString, pos, sizeReal, style, name); + + return true; +} + +wxStaticLine::~wxStaticLine() +{ + delete m_statbox; +} + +WXWidget wxStaticLine::GetMainWidget() const +{ + return m_statbox->GetMainWidget(); +} + +void wxStaticLine::DoSetSize(int x, int y, int width, int height, int sizeFlags) +{ + m_statbox->SetSize(x, y, width, height, sizeFlags); +} + +void wxStaticLine::DoMoveWindow(int x, int y, int width, int height) +{ + m_statbox->SetSize(x, y, width, height); +} + +#endif + // wxUSE_STATLINE diff --git a/Externals/wxWidgets/src/generic/statusbr.cpp b/Externals/wxWidgets/src/generic/statusbr.cpp index 0d283c6be6..6a762b2333 100644 --- a/Externals/wxWidgets/src/generic/statusbr.cpp +++ b/Externals/wxWidgets/src/generic/statusbr.cpp @@ -1,487 +1,487 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/generic/statusbr.cpp -// Purpose: wxStatusBarGeneric class implementation -// Author: Julian Smart -// Modified by: -// Created: 01/02/97 -// RCS-ID: $Id: statusbr.cpp 51615 2008-02-09 15:10:13Z VZ $ -// Copyright: (c) Julian Smart -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_STATUSBAR - -#include "wx/statusbr.h" - -#ifndef WX_PRECOMP - #include "wx/settings.h" - #include "wx/dcclient.h" -#endif - -#ifdef __WXGTK20__ - #include - #include "wx/gtk/win_gtk.h" -#endif - -// we only have to do it here when we use wxStatusBarGeneric in addition to the -// standard wxStatusBar class, if wxStatusBarGeneric is the same as -// wxStatusBar, then the corresponding IMPLEMENT_DYNAMIC_CLASS is already in -// common/statbar.cpp -#if defined(__WXMAC__) || \ - (defined(wxUSE_NATIVE_STATUSBAR) && wxUSE_NATIVE_STATUSBAR) - #include "wx/generic/statusbr.h" - - IMPLEMENT_DYNAMIC_CLASS(wxStatusBarGeneric, wxWindow) -#endif // wxUSE_NATIVE_STATUSBAR - -BEGIN_EVENT_TABLE(wxStatusBarGeneric, wxWindow) - EVT_PAINT(wxStatusBarGeneric::OnPaint) - EVT_LEFT_DOWN(wxStatusBarGeneric::OnLeftDown) - EVT_RIGHT_DOWN(wxStatusBarGeneric::OnRightDown) - EVT_SYS_COLOUR_CHANGED(wxStatusBarGeneric::OnSysColourChanged) -END_EVENT_TABLE() - -// Default status border dimensions -#define wxTHICK_LINE_BORDER 2 - -void wxStatusBarGeneric::Init() -{ - m_borderX = wxTHICK_LINE_BORDER; - m_borderY = wxTHICK_LINE_BORDER; -} - -wxStatusBarGeneric::~wxStatusBarGeneric() -{ -} - -bool wxStatusBarGeneric::Create(wxWindow *parent, - wxWindowID id, - long style, - const wxString& name) -{ - style |= wxTAB_TRAVERSAL | wxFULL_REPAINT_ON_RESIZE; - if ( !wxWindow::Create(parent, id, - wxDefaultPosition, wxDefaultSize, - style, name) ) - return false; - - // The status bar should have a themed background - SetThemeEnabled( true ); - - InitColours(); - -#ifdef __WXPM__ - SetFont(*wxSMALL_FONT); -#endif - - wxCoord y; - { - // Set the height according to the font and the border size - wxClientDC dc(this); - dc.SetFont(GetFont()); - - dc.GetTextExtent(_T("X"), NULL, &y ); - } - int height = (int)( (11*y)/10 + 2*GetBorderY()); - - SetSize(wxDefaultCoord, wxDefaultCoord, wxDefaultCoord, height); - - SetFieldsCount(1); - - return true; -} - - -wxSize wxStatusBarGeneric::DoGetBestSize() const -{ - int width, height; - - // best width is the width of the parent - GetParent()->GetClientSize(&width, NULL); - - // best height is as calculated above in Create - wxClientDC dc((wxWindow*)this); - dc.SetFont(GetFont()); - wxCoord y; - dc.GetTextExtent(_T("X"), NULL, &y ); - height = (int)( (11*y)/10 + 2*GetBorderY()); - - return wxSize(width, height); -} - -void wxStatusBarGeneric::SetFieldsCount(int number, const int *widths) -{ - wxASSERT_MSG( number >= 0, _T("negative number of fields in wxStatusBar?") ); - - int i; - for(i = m_nFields; i < number; ++i) - m_statusStrings.Add( wxEmptyString ); - - for (i = m_nFields - 1; i >= number; --i) - m_statusStrings.RemoveAt(i); - - // forget the old cached pixel widths - m_widthsAbs.Empty(); - - wxStatusBarBase::SetFieldsCount(number, widths); - - wxASSERT_MSG( m_nFields == (int)m_statusStrings.GetCount(), - _T("This really should never happen, can we do away with m_nFields here?") ); -} - -void wxStatusBarGeneric::SetStatusText(const wxString& text, int number) -{ - wxCHECK_RET( (number >= 0) && (number < m_nFields), - _T("invalid status bar field index") ); - - wxString oldText = m_statusStrings[number]; - if (oldText != text) - { - m_statusStrings[number] = text; - - wxRect rect; - GetFieldRect(number, rect); - - Refresh(true, &rect); - - // it's common to show some text in the status bar before starting a - // relatively lengthy operation, ensure that the text is shown to the - // user immediately and not after the lengthy operation end - Update(); - } -} - -wxString wxStatusBarGeneric::GetStatusText(int n) const -{ - wxCHECK_MSG( (n >= 0) && (n < m_nFields), wxEmptyString, - _T("invalid status bar field index") ); - - return m_statusStrings[n]; -} - -void wxStatusBarGeneric::SetStatusWidths(int n, const int widths_field[]) -{ - // only set status widths, when n == number of statuswindows - wxCHECK_RET( n == m_nFields, _T("status bar field count mismatch") ); - - // delete the old widths in any case - this function may be used to reset - // the widths to the default (all equal) - // MBN: this is incompatible with at least wxMSW and wxMAC and not - // documented, but let's keep it for now - ReinitWidths(); - - // forget the old cached pixel widths - m_widthsAbs.Empty(); - - if ( !widths_field ) - { - // not an error, see the comment above - Refresh(); - return; - } - - wxStatusBarBase::SetStatusWidths(n, widths_field); -} - -void wxStatusBarGeneric::OnPaint(wxPaintEvent& WXUNUSED(event) ) -{ - wxPaintDC dc(this); - -#ifdef __WXGTK20__ - // Draw grip first - if (HasFlag( wxST_SIZEGRIP )) - { - int width, height; - GetClientSize(&width, &height); - - if (GetLayoutDirection() == wxLayout_RightToLeft) - { - gtk_paint_resize_grip( m_widget->style, - GTK_PIZZA(m_wxwindow)->bin_window, - (GtkStateType) GTK_WIDGET_STATE (m_widget), - NULL, - m_widget, - "statusbar", - GDK_WINDOW_EDGE_SOUTH_WEST, - 2, 2, height-2, height-4 ); - } - else - { - gtk_paint_resize_grip( m_widget->style, - GTK_PIZZA(m_wxwindow)->bin_window, - (GtkStateType) GTK_WIDGET_STATE (m_widget), - NULL, - m_widget, - "statusbar", - GDK_WINDOW_EDGE_SOUTH_EAST, - width-height-2, 2, height-2, height-4 ); - } - } -#endif - - if (GetFont().Ok()) - dc.SetFont(GetFont()); - - dc.SetBackgroundMode(wxTRANSPARENT); - -#ifdef __WXPM__ - wxColour vColor; - - vColor = wxSystemSettings::GetColour(wxSYS_COLOUR_MENUBAR); - ::WinFillRect(dc.m_hPS, &dc.m_vRclPaint, vColor.GetPixel()); -#endif - - for (int i = 0; i < m_nFields; i ++) - DrawField(dc, i); -} - -void wxStatusBarGeneric::DrawFieldText(wxDC& dc, int i) -{ - int leftMargin = 2; - - wxRect rect; - GetFieldRect(i, rect); - - wxString text(GetStatusText(i)); - - long x = 0, y = 0; - - dc.GetTextExtent(text, &x, &y); - - int xpos = rect.x + leftMargin; - int ypos = (int) (((rect.height - y) / 2 ) + rect.y + 0.5) ; - -#if defined( __WXGTK__ ) || defined(__WXMAC__) - xpos++; - ypos++; -#endif - - dc.SetClippingRegion(rect.x, rect.y, rect.width, rect.height); - - dc.DrawText(text, xpos, ypos); - - dc.DestroyClippingRegion(); -} - -void wxStatusBarGeneric::DrawField(wxDC& dc, int i) -{ - wxRect rect; - GetFieldRect(i, rect); - - int style = wxSB_NORMAL; - if (m_statusStyles) - style = m_statusStyles[i]; - - if (style != wxSB_FLAT) - { - // Draw border - // For wxSB_NORMAL: - // Have grey background, plus 3-d border - - // One black rectangle. - // Inside this, left and top sides - dark grey. Bottom and right - - // white. - // Reverse it for wxSB_RAISED - - dc.SetPen((style == wxSB_RAISED) ? m_mediumShadowPen : m_hilightPen); - - #ifndef __WXPM__ - - // Right and bottom lines - dc.DrawLine(rect.x + rect.width, rect.y, - rect.x + rect.width, rect.y + rect.height); - dc.DrawLine(rect.x + rect.width, rect.y + rect.height, - rect.x, rect.y + rect.height); - - dc.SetPen((style == wxSB_RAISED) ? m_hilightPen : m_mediumShadowPen); - - // Left and top lines - dc.DrawLine(rect.x, rect.y + rect.height, - rect.x, rect.y); - dc.DrawLine(rect.x, rect.y, - rect.x + rect.width, rect.y); - #else - - dc.DrawLine(rect.x + rect.width, rect.height + 2, - rect.x, rect.height + 2); - dc.DrawLine(rect.x + rect.width, rect.y, - rect.x + rect.width, rect.y + rect.height); - - dc.SetPen((style == wxSB_RAISED) ? m_hilightPen : m_mediumShadowPen); - dc.DrawLine(rect.x, rect.y, - rect.x + rect.width, rect.y); - dc.DrawLine(rect.x, rect.y + rect.height, - rect.x, rect.y); - -#endif - } - - DrawFieldText(dc, i); -} - - // Get the position and size of the field's internal bounding rectangle -bool wxStatusBarGeneric::GetFieldRect(int n, wxRect& rect) const -{ - wxCHECK_MSG( (n >= 0) && (n < m_nFields), false, - _T("invalid status bar field index") ); - - // FIXME: workarounds for OS/2 bugs have nothing to do here (VZ) - int width, height; -#ifdef __WXPM__ - GetSize(&width, &height); -#else - GetClientSize(&width, &height); -#endif - - // we cache m_widthsAbs between calls and recompute it if client - // width has changed (or when it is initially empty) - if ( m_widthsAbs.IsEmpty() || (m_lastClientWidth != width) ) - { - wxConstCast(this, wxStatusBarGeneric)-> - m_widthsAbs = CalculateAbsWidths(width); - // remember last width for which we have recomputed the widths in pixels - wxConstCast(this, wxStatusBarGeneric)-> - m_lastClientWidth = width; - } - - rect.x = 0; - for ( int i = 0; i < n; i++ ) - { - rect.x += m_widthsAbs[i]; - } - - rect.x += m_borderX; - rect.y = m_borderY; - - rect.width = m_widthsAbs[n] - 2*m_borderX; - rect.height = height - 2*m_borderY; - - return true; -} - -// Initialize colours -void wxStatusBarGeneric::InitColours() -{ -#if defined(__WXPM__) - m_mediumShadowPen = wxPen(wxColour(127, 127, 127), 1, wxSOLID); - m_hilightPen = *wxWHITE_PEN; - - SetBackgroundColour(*wxLIGHT_GREY); - SetForegroundColour(*wxBLACK); -#else // !__WXPM__ - m_mediumShadowPen = wxPen(wxSystemSettings::GetColour(wxSYS_COLOUR_3DSHADOW)); - m_hilightPen = wxPen(wxSystemSettings::GetColour(wxSYS_COLOUR_3DHILIGHT)); -#endif // __WXPM__/!__WXPM__ -} - -// Responds to colour changes, and passes event on to children. -void wxStatusBarGeneric::OnSysColourChanged(wxSysColourChangedEvent& event) -{ - InitColours(); - - // Propagate the event to the non-top-level children - wxWindow::OnSysColourChanged(event); -} - -void wxStatusBarGeneric::SetMinHeight(int height) -{ - // check that this min height is not less than minimal height for the - // current font - wxClientDC dc(this); - wxCoord y; - dc.GetTextExtent( wxT("X"), NULL, &y ); - - if ( height > (11*y)/10 ) - { - SetSize(wxDefaultCoord, wxDefaultCoord, wxDefaultCoord, height + 2*m_borderY); - } -} - -void wxStatusBarGeneric::OnLeftDown(wxMouseEvent& event) -{ -#ifdef __WXGTK20__ - int width, height; - GetClientSize(&width, &height); - - if (HasFlag( wxST_SIZEGRIP ) && (event.GetX() > width-height)) - { - GtkWidget *ancestor = gtk_widget_get_toplevel( m_widget ); - - if (!GTK_IS_WINDOW (ancestor)) - return; - - GdkWindow *source = GTK_PIZZA(m_wxwindow)->bin_window; - - int org_x = 0; - int org_y = 0; - gdk_window_get_origin( source, &org_x, &org_y ); - - if (GetLayoutDirection() == wxLayout_RightToLeft) - { - gtk_window_begin_resize_drag (GTK_WINDOW (ancestor), - GDK_WINDOW_EDGE_SOUTH_WEST, - 1, - org_x - event.GetX() + GetSize().x , - org_y + event.GetY(), - 0); - } - else - { - gtk_window_begin_resize_drag (GTK_WINDOW (ancestor), - GDK_WINDOW_EDGE_SOUTH_EAST, - 1, - org_x + event.GetX(), - org_y + event.GetY(), - 0); - } - } - else - { - event.Skip( true ); - } -#else - event.Skip( true ); -#endif -} - -void wxStatusBarGeneric::OnRightDown(wxMouseEvent& event) -{ -#ifdef __WXGTK20__ - int width, height; - GetClientSize(&width, &height); - - if (HasFlag( wxST_SIZEGRIP ) && (event.GetX() > width-height)) - { - GtkWidget *ancestor = gtk_widget_get_toplevel( m_widget ); - - if (!GTK_IS_WINDOW (ancestor)) - return; - - GdkWindow *source = GTK_PIZZA(m_wxwindow)->bin_window; - - int org_x = 0; - int org_y = 0; - gdk_window_get_origin( source, &org_x, &org_y ); - - gtk_window_begin_move_drag (GTK_WINDOW (ancestor), - 2, - org_x + event.GetX(), - org_y + event.GetY(), - 0); - } - else - { - event.Skip( true ); - } -#else - event.Skip( true ); -#endif -} - -#endif // wxUSE_STATUSBAR +///////////////////////////////////////////////////////////////////////////// +// Name: src/generic/statusbr.cpp +// Purpose: wxStatusBarGeneric class implementation +// Author: Julian Smart +// Modified by: +// Created: 01/02/97 +// RCS-ID: $Id: statusbr.cpp 51615 2008-02-09 15:10:13Z VZ $ +// Copyright: (c) Julian Smart +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_STATUSBAR + +#include "wx/statusbr.h" + +#ifndef WX_PRECOMP + #include "wx/settings.h" + #include "wx/dcclient.h" +#endif + +#ifdef __WXGTK20__ + #include + #include "wx/gtk/win_gtk.h" +#endif + +// we only have to do it here when we use wxStatusBarGeneric in addition to the +// standard wxStatusBar class, if wxStatusBarGeneric is the same as +// wxStatusBar, then the corresponding IMPLEMENT_DYNAMIC_CLASS is already in +// common/statbar.cpp +#if defined(__WXMAC__) || \ + (defined(wxUSE_NATIVE_STATUSBAR) && wxUSE_NATIVE_STATUSBAR) + #include "wx/generic/statusbr.h" + + IMPLEMENT_DYNAMIC_CLASS(wxStatusBarGeneric, wxWindow) +#endif // wxUSE_NATIVE_STATUSBAR + +BEGIN_EVENT_TABLE(wxStatusBarGeneric, wxWindow) + EVT_PAINT(wxStatusBarGeneric::OnPaint) + EVT_LEFT_DOWN(wxStatusBarGeneric::OnLeftDown) + EVT_RIGHT_DOWN(wxStatusBarGeneric::OnRightDown) + EVT_SYS_COLOUR_CHANGED(wxStatusBarGeneric::OnSysColourChanged) +END_EVENT_TABLE() + +// Default status border dimensions +#define wxTHICK_LINE_BORDER 2 + +void wxStatusBarGeneric::Init() +{ + m_borderX = wxTHICK_LINE_BORDER; + m_borderY = wxTHICK_LINE_BORDER; +} + +wxStatusBarGeneric::~wxStatusBarGeneric() +{ +} + +bool wxStatusBarGeneric::Create(wxWindow *parent, + wxWindowID id, + long style, + const wxString& name) +{ + style |= wxTAB_TRAVERSAL | wxFULL_REPAINT_ON_RESIZE; + if ( !wxWindow::Create(parent, id, + wxDefaultPosition, wxDefaultSize, + style, name) ) + return false; + + // The status bar should have a themed background + SetThemeEnabled( true ); + + InitColours(); + +#ifdef __WXPM__ + SetFont(*wxSMALL_FONT); +#endif + + wxCoord y; + { + // Set the height according to the font and the border size + wxClientDC dc(this); + dc.SetFont(GetFont()); + + dc.GetTextExtent(_T("X"), NULL, &y ); + } + int height = (int)( (11*y)/10 + 2*GetBorderY()); + + SetSize(wxDefaultCoord, wxDefaultCoord, wxDefaultCoord, height); + + SetFieldsCount(1); + + return true; +} + + +wxSize wxStatusBarGeneric::DoGetBestSize() const +{ + int width, height; + + // best width is the width of the parent + GetParent()->GetClientSize(&width, NULL); + + // best height is as calculated above in Create + wxClientDC dc((wxWindow*)this); + dc.SetFont(GetFont()); + wxCoord y; + dc.GetTextExtent(_T("X"), NULL, &y ); + height = (int)( (11*y)/10 + 2*GetBorderY()); + + return wxSize(width, height); +} + +void wxStatusBarGeneric::SetFieldsCount(int number, const int *widths) +{ + wxASSERT_MSG( number >= 0, _T("negative number of fields in wxStatusBar?") ); + + int i; + for(i = m_nFields; i < number; ++i) + m_statusStrings.Add( wxEmptyString ); + + for (i = m_nFields - 1; i >= number; --i) + m_statusStrings.RemoveAt(i); + + // forget the old cached pixel widths + m_widthsAbs.Empty(); + + wxStatusBarBase::SetFieldsCount(number, widths); + + wxASSERT_MSG( m_nFields == (int)m_statusStrings.GetCount(), + _T("This really should never happen, can we do away with m_nFields here?") ); +} + +void wxStatusBarGeneric::SetStatusText(const wxString& text, int number) +{ + wxCHECK_RET( (number >= 0) && (number < m_nFields), + _T("invalid status bar field index") ); + + wxString oldText = m_statusStrings[number]; + if (oldText != text) + { + m_statusStrings[number] = text; + + wxRect rect; + GetFieldRect(number, rect); + + Refresh(true, &rect); + + // it's common to show some text in the status bar before starting a + // relatively lengthy operation, ensure that the text is shown to the + // user immediately and not after the lengthy operation end + Update(); + } +} + +wxString wxStatusBarGeneric::GetStatusText(int n) const +{ + wxCHECK_MSG( (n >= 0) && (n < m_nFields), wxEmptyString, + _T("invalid status bar field index") ); + + return m_statusStrings[n]; +} + +void wxStatusBarGeneric::SetStatusWidths(int n, const int widths_field[]) +{ + // only set status widths, when n == number of statuswindows + wxCHECK_RET( n == m_nFields, _T("status bar field count mismatch") ); + + // delete the old widths in any case - this function may be used to reset + // the widths to the default (all equal) + // MBN: this is incompatible with at least wxMSW and wxMAC and not + // documented, but let's keep it for now + ReinitWidths(); + + // forget the old cached pixel widths + m_widthsAbs.Empty(); + + if ( !widths_field ) + { + // not an error, see the comment above + Refresh(); + return; + } + + wxStatusBarBase::SetStatusWidths(n, widths_field); +} + +void wxStatusBarGeneric::OnPaint(wxPaintEvent& WXUNUSED(event) ) +{ + wxPaintDC dc(this); + +#ifdef __WXGTK20__ + // Draw grip first + if (HasFlag( wxST_SIZEGRIP )) + { + int width, height; + GetClientSize(&width, &height); + + if (GetLayoutDirection() == wxLayout_RightToLeft) + { + gtk_paint_resize_grip( m_widget->style, + GTK_PIZZA(m_wxwindow)->bin_window, + (GtkStateType) GTK_WIDGET_STATE (m_widget), + NULL, + m_widget, + "statusbar", + GDK_WINDOW_EDGE_SOUTH_WEST, + 2, 2, height-2, height-4 ); + } + else + { + gtk_paint_resize_grip( m_widget->style, + GTK_PIZZA(m_wxwindow)->bin_window, + (GtkStateType) GTK_WIDGET_STATE (m_widget), + NULL, + m_widget, + "statusbar", + GDK_WINDOW_EDGE_SOUTH_EAST, + width-height-2, 2, height-2, height-4 ); + } + } +#endif + + if (GetFont().Ok()) + dc.SetFont(GetFont()); + + dc.SetBackgroundMode(wxTRANSPARENT); + +#ifdef __WXPM__ + wxColour vColor; + + vColor = wxSystemSettings::GetColour(wxSYS_COLOUR_MENUBAR); + ::WinFillRect(dc.m_hPS, &dc.m_vRclPaint, vColor.GetPixel()); +#endif + + for (int i = 0; i < m_nFields; i ++) + DrawField(dc, i); +} + +void wxStatusBarGeneric::DrawFieldText(wxDC& dc, int i) +{ + int leftMargin = 2; + + wxRect rect; + GetFieldRect(i, rect); + + wxString text(GetStatusText(i)); + + long x = 0, y = 0; + + dc.GetTextExtent(text, &x, &y); + + int xpos = rect.x + leftMargin; + int ypos = (int) (((rect.height - y) / 2 ) + rect.y + 0.5) ; + +#if defined( __WXGTK__ ) || defined(__WXMAC__) + xpos++; + ypos++; +#endif + + dc.SetClippingRegion(rect.x, rect.y, rect.width, rect.height); + + dc.DrawText(text, xpos, ypos); + + dc.DestroyClippingRegion(); +} + +void wxStatusBarGeneric::DrawField(wxDC& dc, int i) +{ + wxRect rect; + GetFieldRect(i, rect); + + int style = wxSB_NORMAL; + if (m_statusStyles) + style = m_statusStyles[i]; + + if (style != wxSB_FLAT) + { + // Draw border + // For wxSB_NORMAL: + // Have grey background, plus 3-d border - + // One black rectangle. + // Inside this, left and top sides - dark grey. Bottom and right - + // white. + // Reverse it for wxSB_RAISED + + dc.SetPen((style == wxSB_RAISED) ? m_mediumShadowPen : m_hilightPen); + + #ifndef __WXPM__ + + // Right and bottom lines + dc.DrawLine(rect.x + rect.width, rect.y, + rect.x + rect.width, rect.y + rect.height); + dc.DrawLine(rect.x + rect.width, rect.y + rect.height, + rect.x, rect.y + rect.height); + + dc.SetPen((style == wxSB_RAISED) ? m_hilightPen : m_mediumShadowPen); + + // Left and top lines + dc.DrawLine(rect.x, rect.y + rect.height, + rect.x, rect.y); + dc.DrawLine(rect.x, rect.y, + rect.x + rect.width, rect.y); + #else + + dc.DrawLine(rect.x + rect.width, rect.height + 2, + rect.x, rect.height + 2); + dc.DrawLine(rect.x + rect.width, rect.y, + rect.x + rect.width, rect.y + rect.height); + + dc.SetPen((style == wxSB_RAISED) ? m_hilightPen : m_mediumShadowPen); + dc.DrawLine(rect.x, rect.y, + rect.x + rect.width, rect.y); + dc.DrawLine(rect.x, rect.y + rect.height, + rect.x, rect.y); + +#endif + } + + DrawFieldText(dc, i); +} + + // Get the position and size of the field's internal bounding rectangle +bool wxStatusBarGeneric::GetFieldRect(int n, wxRect& rect) const +{ + wxCHECK_MSG( (n >= 0) && (n < m_nFields), false, + _T("invalid status bar field index") ); + + // FIXME: workarounds for OS/2 bugs have nothing to do here (VZ) + int width, height; +#ifdef __WXPM__ + GetSize(&width, &height); +#else + GetClientSize(&width, &height); +#endif + + // we cache m_widthsAbs between calls and recompute it if client + // width has changed (or when it is initially empty) + if ( m_widthsAbs.IsEmpty() || (m_lastClientWidth != width) ) + { + wxConstCast(this, wxStatusBarGeneric)-> + m_widthsAbs = CalculateAbsWidths(width); + // remember last width for which we have recomputed the widths in pixels + wxConstCast(this, wxStatusBarGeneric)-> + m_lastClientWidth = width; + } + + rect.x = 0; + for ( int i = 0; i < n; i++ ) + { + rect.x += m_widthsAbs[i]; + } + + rect.x += m_borderX; + rect.y = m_borderY; + + rect.width = m_widthsAbs[n] - 2*m_borderX; + rect.height = height - 2*m_borderY; + + return true; +} + +// Initialize colours +void wxStatusBarGeneric::InitColours() +{ +#if defined(__WXPM__) + m_mediumShadowPen = wxPen(wxColour(127, 127, 127), 1, wxSOLID); + m_hilightPen = *wxWHITE_PEN; + + SetBackgroundColour(*wxLIGHT_GREY); + SetForegroundColour(*wxBLACK); +#else // !__WXPM__ + m_mediumShadowPen = wxPen(wxSystemSettings::GetColour(wxSYS_COLOUR_3DSHADOW)); + m_hilightPen = wxPen(wxSystemSettings::GetColour(wxSYS_COLOUR_3DHILIGHT)); +#endif // __WXPM__/!__WXPM__ +} + +// Responds to colour changes, and passes event on to children. +void wxStatusBarGeneric::OnSysColourChanged(wxSysColourChangedEvent& event) +{ + InitColours(); + + // Propagate the event to the non-top-level children + wxWindow::OnSysColourChanged(event); +} + +void wxStatusBarGeneric::SetMinHeight(int height) +{ + // check that this min height is not less than minimal height for the + // current font + wxClientDC dc(this); + wxCoord y; + dc.GetTextExtent( wxT("X"), NULL, &y ); + + if ( height > (11*y)/10 ) + { + SetSize(wxDefaultCoord, wxDefaultCoord, wxDefaultCoord, height + 2*m_borderY); + } +} + +void wxStatusBarGeneric::OnLeftDown(wxMouseEvent& event) +{ +#ifdef __WXGTK20__ + int width, height; + GetClientSize(&width, &height); + + if (HasFlag( wxST_SIZEGRIP ) && (event.GetX() > width-height)) + { + GtkWidget *ancestor = gtk_widget_get_toplevel( m_widget ); + + if (!GTK_IS_WINDOW (ancestor)) + return; + + GdkWindow *source = GTK_PIZZA(m_wxwindow)->bin_window; + + int org_x = 0; + int org_y = 0; + gdk_window_get_origin( source, &org_x, &org_y ); + + if (GetLayoutDirection() == wxLayout_RightToLeft) + { + gtk_window_begin_resize_drag (GTK_WINDOW (ancestor), + GDK_WINDOW_EDGE_SOUTH_WEST, + 1, + org_x - event.GetX() + GetSize().x , + org_y + event.GetY(), + 0); + } + else + { + gtk_window_begin_resize_drag (GTK_WINDOW (ancestor), + GDK_WINDOW_EDGE_SOUTH_EAST, + 1, + org_x + event.GetX(), + org_y + event.GetY(), + 0); + } + } + else + { + event.Skip( true ); + } +#else + event.Skip( true ); +#endif +} + +void wxStatusBarGeneric::OnRightDown(wxMouseEvent& event) +{ +#ifdef __WXGTK20__ + int width, height; + GetClientSize(&width, &height); + + if (HasFlag( wxST_SIZEGRIP ) && (event.GetX() > width-height)) + { + GtkWidget *ancestor = gtk_widget_get_toplevel( m_widget ); + + if (!GTK_IS_WINDOW (ancestor)) + return; + + GdkWindow *source = GTK_PIZZA(m_wxwindow)->bin_window; + + int org_x = 0; + int org_y = 0; + gdk_window_get_origin( source, &org_x, &org_y ); + + gtk_window_begin_move_drag (GTK_WINDOW (ancestor), + 2, + org_x + event.GetX(), + org_y + event.GetY(), + 0); + } + else + { + event.Skip( true ); + } +#else + event.Skip( true ); +#endif +} + +#endif // wxUSE_STATUSBAR diff --git a/Externals/wxWidgets/src/generic/tabg.cpp b/Externals/wxWidgets/src/generic/tabg.cpp index 49bf88d839..52ea16840f 100644 --- a/Externals/wxWidgets/src/generic/tabg.cpp +++ b/Externals/wxWidgets/src/generic/tabg.cpp @@ -1,1290 +1,1290 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/generic/tabg.cpp -// Purpose: Generic tabbed dialogs -// Author: Julian Smart -// Modified by: -// Created: 01/02/97 -// RCS-ID: $Id: tabg.cpp 39745 2006-06-15 17:58:49Z ABX $ -// Copyright: (c) -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_TAB_DIALOG - -#ifndef WX_PRECOMP - #include "wx/settings.h" - #include "wx/intl.h" - #include "wx/dcclient.h" - #include "wx/math.h" -#endif - -#include -#include -#include - -#include "wx/tab.h" -#include "wx/listimpl.cpp" - -WX_DEFINE_LIST(wxTabLayerList) - -// not defined: use old, square tab implementation (fills in tabs) -// defined: use new, rounded tab implementation (doesn't colour in tabs) -// #define wxUSE_NEW_METHOD - -IMPLEMENT_DYNAMIC_CLASS(wxTabControl, wxObject) - -// IMPLEMENT_DYNAMIC_CLASS(wxTabLayer, wxList) - -wxTabControl::wxTabControl(wxTabView *v) -{ - m_view = v; - m_isSelected = false; - m_offsetX = 0; - m_offsetY = 0; - m_width = 0; - m_height = 0; - m_id = 0; - m_rowPosition = 0; - m_colPosition = 0; -} - -wxTabControl::~wxTabControl(void) -{ -} - -void wxTabControl::OnDraw(wxDC& dc, bool lastInRow) -{ - // Old, but in some ways better (drawing opaque tabs) -#ifndef wxUSE_NEW_METHOD - if (!m_view) - return; - - // Top-left of tab view area - int viewX = m_view->GetViewRect().x; - int viewY = m_view->GetViewRect().y; - - // Top-left of tab control - int tabX = GetX() + viewX; - int tabY = GetY() + viewY; - int tabHeightInc = 0; - if (m_isSelected) - { - tabHeightInc = (m_view->GetTabSelectionHeight() - m_view->GetTabHeight()); - tabY -= tabHeightInc; - } - - dc.SetPen(*wxTRANSPARENT_PEN); - - // Draw grey background - if (m_view->GetTabStyle() & wxTAB_STYLE_COLOUR_INTERIOR) - { - dc.SetBrush(*m_view->GetBackgroundBrush()); - - // Add 1 because the pen is transparent. Under Motif, may be different. -#ifdef __WXMOTIF__ - dc.DrawRectangle(tabX, tabY, (GetWidth()+1), (GetHeight() + tabHeightInc)); -#else - dc.DrawRectangle(tabX, tabY, (GetWidth()+1), (GetHeight() + 1 + tabHeightInc)); -#endif - } - - // Draw highlight and shadow - dc.SetPen(*m_view->GetHighlightPen()); - - // Calculate the top of the tab beneath. It's the height of the tab, MINUS - // a bit if the tab below happens to be selected. Check. - wxTabControl *tabBeneath = NULL; - int subtractThis = 0; - if (GetColPosition() > 0) - tabBeneath = m_view->FindTabControlForPosition(GetColPosition() - 1, GetRowPosition()); - if (tabBeneath && tabBeneath->IsSelected()) - subtractThis = (m_view->GetTabSelectionHeight() - m_view->GetTabHeight()); - - // Vertical highlight: if first tab, draw to bottom of view - if (tabX == m_view->GetViewRect().x && (m_view->GetTabStyle() & wxTAB_STYLE_DRAW_BOX)) - dc.DrawLine(tabX, tabY, tabX, (m_view->GetViewRect().y + m_view->GetViewRect().height)); - else if (tabX == m_view->GetViewRect().x) - // Not box drawing, just to top of view. - dc.DrawLine(tabX, tabY, tabX, (m_view->GetViewRect().y)); - else - dc.DrawLine(tabX, tabY, tabX, (tabY + GetHeight() + tabHeightInc - subtractThis)); - - dc.DrawLine(tabX, tabY, (tabX + GetWidth()), tabY); - dc.SetPen(*m_view->GetShadowPen()); - - // Test if we're outside the right-hand edge of the view area - if (((tabX + GetWidth()) >= m_view->GetViewRect().x + m_view->GetViewRect().width) && (m_view->GetTabStyle() & wxTAB_STYLE_DRAW_BOX)) - { - int bottomY = m_view->GetViewRect().y + m_view->GetViewRect().height + GetY() + m_view->GetTabHeight() + m_view->GetTopMargin(); - // Add a tab height since we wish to draw to the bottom of the view. - dc.DrawLine((tabX + GetWidth()), tabY, - (tabX + GetWidth()), bottomY); - - // Calculate the far-right of the view, since we don't wish to - // draw inside that - int rightOfView = m_view->GetViewRect().x + m_view->GetViewRect().width + 1; - - // Draw the horizontal bit to connect to the view rectangle - dc.DrawLine((wxMax((tabX + GetWidth() - m_view->GetHorizontalTabOffset()), rightOfView)), (bottomY-1), - (tabX + GetWidth()), (bottomY-1)); - - // Draw black line to emphasize shadow - dc.SetPen(*wxBLACK_PEN); - dc.DrawLine((tabX + GetWidth() + 1), (tabY+1), - (tabX + GetWidth() + 1), bottomY); - - // Draw the horizontal bit to connect to the view rectangle - dc.DrawLine((wxMax((tabX + GetWidth() - m_view->GetHorizontalTabOffset()), rightOfView)), (bottomY), - (tabX + GetWidth() + 1), (bottomY)); - } - else - { - if (lastInRow) - { - // 25/5/97 UNLESS it's less than the max number of positions in this row - - int topY = m_view->GetViewRect().y - m_view->GetTopMargin(); - - int maxPositions = ((wxTabLayer *)m_view->GetLayers().Item(0)->GetData())->GetCount(); - - // Only down to the bottom of the tab, not to the top of the view - if ( GetRowPosition() < (maxPositions - 1) ) - topY = tabY + GetHeight() + tabHeightInc; - -#ifdef __WXMOTIF__ - topY -= 1; -#endif - - // Shadow - dc.DrawLine((tabX + GetWidth()), tabY, (tabX + GetWidth()), topY); - // Draw black line to emphasize shadow - dc.SetPen(*wxBLACK_PEN); - dc.DrawLine((tabX + GetWidth() + 1), (tabY+1), (tabX + GetWidth() + 1), - topY); - } - else - { - // Calculate the top of the tab beneath. It's the height of the tab, MINUS - // a bit if the tab below (and next col along) happens to be selected. Check. - wxTabControl *tabBeneath = NULL; - int subtractThis = 0; - if (GetColPosition() > 0) - tabBeneath = m_view->FindTabControlForPosition(GetColPosition() - 1, GetRowPosition() + 1); - if (tabBeneath && tabBeneath->IsSelected()) - subtractThis = (m_view->GetTabSelectionHeight() - m_view->GetTabHeight()); - -#ifdef __WXMOTIF__ - subtractThis += 1; -#endif - - // Draw only to next tab down. - dc.DrawLine((tabX + GetWidth()), tabY, - (tabX + GetWidth()), (tabY + GetHeight() + tabHeightInc - subtractThis)); - - // Draw black line to emphasize shadow - dc.SetPen(*wxBLACK_PEN); - dc.DrawLine((tabX + GetWidth() + 1), (tabY+1), (tabX + GetWidth() + 1), - (tabY + GetHeight() + tabHeightInc - subtractThis)); - } - } - - // Draw centered text - int textY = tabY + m_view->GetVerticalTabTextSpacing() + tabHeightInc; - - if (m_isSelected) - dc.SetFont(* m_view->GetSelectedTabFont()); - else - dc.SetFont(* GetFont()); - - wxColour col(m_view->GetTextColour()); - dc.SetTextForeground(col); - dc.SetBackgroundMode(wxTRANSPARENT); - long textWidth, textHeight; - dc.GetTextExtent(GetLabel(), &textWidth, &textHeight); - - int textX = (int)(tabX + (GetWidth() - textWidth)/2.0); - if (textX < (tabX + 2)) - textX = (tabX + 2); - - dc.SetClippingRegion(tabX, tabY, GetWidth(), GetHeight()); - dc.DrawText(GetLabel(), textX, textY); - dc.DestroyClippingRegion(); - - if (m_isSelected) - { - dc.SetPen(*m_view->GetHighlightPen()); - - // Draw white highlight from the tab's left side to the left hand edge of the view - dc.DrawLine(m_view->GetViewRect().x, (tabY + GetHeight() + tabHeightInc), - tabX, (tabY + GetHeight() + tabHeightInc)); - - // Draw white highlight from the tab's right side to the right hand edge of the view - dc.DrawLine((tabX + GetWidth()), (tabY + GetHeight() + tabHeightInc), - m_view->GetViewRect().x + m_view->GetViewRect().width, (tabY + GetHeight() + tabHeightInc)); - } -#else - // New HEL version with rounder tabs - - if (!m_view) return; - - int tabInc = 0; - if (m_isSelected) - { - tabInc = m_view->GetTabSelectionHeight() - m_view->GetTabHeight(); - } - int tabLeft = GetX() + m_view->GetViewRect().x; - int tabTop = GetY() + m_view->GetViewRect().y - tabInc; - int tabRight = tabLeft + m_view->GetTabWidth(); - int left = m_view->GetViewRect().x; - int top = tabTop + m_view->GetTabHeight() + tabInc; - int right = left + m_view->GetViewRect().width; - int bottom = top + m_view->GetViewRect().height; - - if (m_isSelected) - { - // TAB is selected - draw TAB and the View's full outline - - dc.SetPen(*(m_view->GetHighlightPen())); - wxPoint pnts[10]; - int n = 0; - pnts[n].x = left; pnts[n++].y = bottom; - pnts[n].x = left; pnts[n++].y = top; - pnts[n].x = tabLeft; pnts[n++].y = top; - pnts[n].x = tabLeft; pnts[n++].y = tabTop + 2; - pnts[n].x = tabLeft + 2; pnts[n++].y = tabTop; - pnts[n].x = tabRight - 1; pnts[n++].y = tabTop; - dc.DrawLines(n, pnts); - if (!lastInRow) - { - dc.DrawLine( - (tabRight + 2), - top, - right, - top - ); - } - - dc.SetPen(*(m_view->GetShadowPen())); - dc.DrawLine( - tabRight, - tabTop + 2, - tabRight, - top - ); - dc.DrawLine( - right, - top, - right, - bottom - ); - dc.DrawLine( - right, - bottom, - left, - bottom - ); - - dc.SetPen(*wxBLACK_PEN); - dc.DrawPoint( - tabRight, - tabTop + 1 - ); - dc.DrawPoint( - tabRight + 1, - tabTop + 2 - ); - if (lastInRow) - { - dc.DrawLine( - tabRight + 1, - bottom, - tabRight + 1, - tabTop + 1 - ); - } - else - { - dc.DrawLine( - tabRight + 1, - tabTop + 2, - tabRight + 1, - top - ); - dc.DrawLine( - right + 1, - top, - right + 1, - bottom + 1 - ); - } - dc.DrawLine( - right + 1, - bottom + 1, - left + 1, - bottom + 1 - ); - } - else - { - // TAB is not selected - just draw TAB outline and RH edge - // if the TAB is the last in the row - - int maxPositions = ((wxTabLayer*)m_view->GetLayers().Item(0)->GetData())->GetCount(); - wxTabControl* tabBelow = 0; - wxTabControl* tabBelowRight = 0; - if (GetColPosition() > 0) - { - tabBelow = m_view->FindTabControlForPosition( - GetColPosition() - 1, - GetRowPosition() - ); - } - if (!lastInRow && GetColPosition() > 0) - { - tabBelowRight = m_view->FindTabControlForPosition( - GetColPosition() - 1, - GetRowPosition() + 1 - ); - } - - float raisedTop = top - m_view->GetTabSelectionHeight() + - m_view->GetTabHeight(); - - dc.SetPen(*(m_view->GetHighlightPen())); - wxPoint pnts[10]; - int n = 0; - - pnts[n].x = tabLeft; - - if (tabBelow && tabBelow->IsSelected()) - { - pnts[n++].y = (long)raisedTop; - } - else - { - pnts[n++].y = top; - } - pnts[n].x = tabLeft; pnts[n++].y = tabTop + 2; - pnts[n].x = tabLeft + 2; pnts[n++].y = tabTop; - pnts[n].x = tabRight - 1; pnts[n++].y = tabTop; - dc.DrawLines(n, pnts); - - dc.SetPen(*(m_view->GetShadowPen())); - if (GetRowPosition() >= maxPositions - 1) - { - dc.DrawLine( - tabRight, - (tabTop + 2), - tabRight, - bottom - ); - dc.DrawLine( - tabRight, - bottom, - (tabRight - m_view->GetHorizontalTabOffset()), - bottom - ); - } - else - { - if (tabBelowRight && tabBelowRight->IsSelected()) - { - dc.DrawLine( - tabRight, - (long)raisedTop, - tabRight, - tabTop + 1 - ); - } - else - { - dc.DrawLine( - tabRight, - top - 1, - tabRight, - tabTop + 1 - ); - } - } - - dc.SetPen(*wxBLACK_PEN); - dc.DrawPoint( - tabRight, - tabTop + 1 - ); - dc.DrawPoint( - tabRight + 1, - tabTop + 2 - ); - if (GetRowPosition() >= maxPositions - 1) - { - // draw right hand edge to bottom of view - dc.DrawLine( - tabRight + 1, - bottom + 1, - tabRight + 1, - tabTop + 2 - ); - dc.DrawLine( - tabRight + 1, - bottom + 1, - (tabRight - m_view->GetHorizontalTabOffset()), - bottom + 1 - ); - } - else - { - // draw right hand edge of TAB - if (tabBelowRight && tabBelowRight->IsSelected()) - { - dc.DrawLine( - tabRight + 1, - (long)(raisedTop - 1), - tabRight + 1, - tabTop + 2 - ); - } - else - { - dc.DrawLine( - tabRight + 1, - top - 1, - tabRight + 1, - tabTop + 2 - ); - } - } - } - - // Draw centered text - dc.SetPen(*wxBLACK_PEN); - if (m_isSelected) - { - dc.SetFont(*(m_view->GetSelectedTabFont())); - } - else - { - dc.SetFont(*(GetFont())); - } - - wxColour col(m_view->GetTextColour()); - dc.SetTextForeground(col); - dc.SetBackgroundMode(wxTRANSPARENT); - long textWidth, textHeight; - dc.GetTextExtent(GetLabel(), &textWidth, &textHeight); - - float textX = (tabLeft + tabRight - textWidth) / 2; - float textY = (tabInc + tabTop + m_view->GetVerticalTabTextSpacing()); - - dc.DrawText(GetLabel(), (long)textX, (long)textY); -#endif -} - -bool wxTabControl::HitTest(int x, int y) const -{ - // Top-left of tab control - int tabX1 = GetX() + m_view->GetViewRect().x; - int tabY1 = GetY() + m_view->GetViewRect().y; - - // Bottom-right - int tabX2 = tabX1 + GetWidth(); - int tabY2 = tabY1 + GetHeight(); - - if (x >= tabX1 && y >= tabY1 && x <= tabX2 && y <= tabY2) - return true; - else - return false; -} - -IMPLEMENT_DYNAMIC_CLASS(wxTabView, wxObject) - -wxTabView::wxTabView(long style) -{ - m_noTabs = 0; - m_tabStyle = style; - m_tabSelection = -1; - m_tabHeight = 20; - m_tabSelectionHeight = m_tabHeight + 2; - m_tabWidth = 80; - m_tabHorizontalOffset = 10; - m_tabHorizontalSpacing = 2; - m_tabVerticalTextSpacing = 3; - m_topMargin = 5; - m_tabViewRect.x = 20; - m_tabViewRect.y = 20; - m_tabViewRect.width = 300; - m_tabViewRect.x = 300; - m_highlightColour = *wxWHITE; - m_shadowColour = wxColour(128, 128, 128); - m_backgroundColour = wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE); - m_textColour = *wxBLACK; - m_highlightPen = wxWHITE_PEN; - m_shadowPen = wxGREY_PEN; - SetBackgroundColour(m_backgroundColour); - m_tabFont = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT); - m_tabSelectedFont = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT); - m_window = (wxWindow *) NULL; -} - -wxTabView::~wxTabView() -{ - ClearTabs(true); -} - -// Automatically positions tabs -// TODO: this should just add the tab to a list, and then -// a layout function (e.g. Realize) should be called when all tabs have been added. -// The view rect could easily change as the view window is resized. -wxTabControl *wxTabView::AddTab(int id, const wxString& label, wxTabControl *existingTab) -{ - // First, find which layer we should be adding to. - wxTabLayerList::compatibility_iterator node = m_layers.GetLast(); - if (!node) - { - wxTabLayer *newLayer = new wxTabLayer; - node = m_layers.Append(newLayer); - } - // Check if adding another tab control would go off the - // right-hand edge of the layer. - wxTabLayer *tabLayer = (wxTabLayer *)node->GetData(); - wxList::compatibility_iterator lastTabNode = tabLayer->GetLast(); - if (lastTabNode) - { - wxTabControl *lastTab = (wxTabControl *)lastTabNode->GetData(); - // Start another layer (row). - // Tricky choice: can't just check if will be overlapping the edge, because - // this happens anyway for 2nd and subsequent rows. - // Should check this for 1st row, and then subsequent rows should not exceed 1st - // in length. - if (((tabLayer == m_layers.GetFirst()->GetData()) && ((lastTab->GetX() + 2*lastTab->GetWidth() + GetHorizontalTabSpacing()) - > GetViewRect().width)) || - ((tabLayer != m_layers.GetFirst()->GetData()) && (tabLayer->GetCount() == ((wxTabLayer *)m_layers.GetFirst()->GetData())->GetCount()))) - { - tabLayer = new wxTabLayer; - m_layers.Append(tabLayer); - lastTabNode = wxList::compatibility_iterator(); - } - } - int layer = m_layers.GetCount() - 1; - - wxTabControl *tabControl = existingTab; - if (!existingTab) - tabControl = OnCreateTabControl(); - tabControl->SetRowPosition(tabLayer->GetCount()); - tabControl->SetColPosition(layer); - - wxTabControl *lastTab = (wxTabControl *) NULL; - if (lastTabNode) - lastTab = (wxTabControl *)lastTabNode->GetData(); - - // Top of new tab - int verticalOffset = (- GetTopMargin()) - ((layer+1)*GetTabHeight()); - // Offset from view top-left - int horizontalOffset = 0; - if (!lastTab) - horizontalOffset = layer*GetHorizontalTabOffset(); - else - horizontalOffset = lastTab->GetX() + GetTabWidth() + GetHorizontalTabSpacing(); - - tabControl->SetPosition(horizontalOffset, verticalOffset); - tabControl->SetSize(GetTabWidth(), GetTabHeight()); - tabControl->SetId(id); - tabControl->SetLabel(label); - tabControl->SetFont(* GetTabFont()); - - tabLayer->Append(tabControl); - m_noTabs ++; - - return tabControl; -} - -// Remove the tab without deleting the window -bool wxTabView::RemoveTab(int id) -{ - wxTabLayerList::compatibility_iterator layerNode = m_layers.GetFirst(); - while (layerNode) - { - wxTabLayer *layer = (wxTabLayer *)layerNode->GetData(); - wxList::compatibility_iterator tabNode = layer->GetFirst(); - while (tabNode) - { - wxTabControl *tab = (wxTabControl *)tabNode->GetData(); - if (tab->GetId() == id) - { - if (id == m_tabSelection) - m_tabSelection = -1; - delete tab; - layer->Erase(tabNode); - m_noTabs --; - - // The layout has changed - LayoutTabs(); - return true; - } - tabNode = tabNode->GetNext(); - } - layerNode = layerNode->GetNext(); - } - return false; -} - -bool wxTabView::SetTabText(int id, const wxString& label) -{ - wxTabControl* control = FindTabControlForId(id); - if (!control) - return false; - control->SetLabel(label); - return true; -} - -wxString wxTabView::GetTabText(int id) const -{ - wxTabControl* control = FindTabControlForId(id); - if (!control) - return wxEmptyString; - else - return control->GetLabel(); -} - -// Returns the total height of the tabs component -- this may be several -// times the height of a tab, if there are several tab layers (rows). -int wxTabView::GetTotalTabHeight() -{ - int minY = 0; - - wxTabLayerList::compatibility_iterator layerNode = m_layers.GetFirst(); - while (layerNode) - { - wxTabLayer *layer = (wxTabLayer *)layerNode->GetData(); - wxList::compatibility_iterator tabNode = layer->GetFirst(); - while (tabNode) - { - wxTabControl *tab = (wxTabControl *)tabNode->GetData(); - - if (tab->GetY() < minY) - minY = tab->GetY(); - - tabNode = tabNode->GetNext(); - } - layerNode = layerNode->GetNext(); - } - - return - minY; -} - -void wxTabView::ClearTabs(bool deleteTabs) -{ - wxTabLayerList::compatibility_iterator layerNode = m_layers.GetFirst(); - while (layerNode) - { - wxTabLayer *layer = (wxTabLayer *)layerNode->GetData(); - wxList::compatibility_iterator tabNode = layer->GetFirst(); - while (tabNode) - { - wxTabControl *tab = (wxTabControl *)tabNode->GetData(); - if (deleteTabs) - delete tab; - wxList::compatibility_iterator next = tabNode->GetNext(); - layer->Erase(tabNode); - tabNode = next; - } - wxTabLayerList::compatibility_iterator nextLayerNode = layerNode->GetNext(); - delete layer; - m_layers.Erase(layerNode); - layerNode = nextLayerNode; - } - m_noTabs = 0; - m_tabSelection = -1; -} - - -// Layout tabs (optional, e.g. if resizing window) -void wxTabView::LayoutTabs(void) -{ - // Make a list of the tab controls, deleting the wxTabLayers. - wxList controls; - - wxTabLayerList::compatibility_iterator layerNode = m_layers.GetFirst(); - while (layerNode) - { - wxTabLayer *layer = (wxTabLayer *)layerNode->GetData(); - wxList::compatibility_iterator tabNode = layer->GetFirst(); - while (tabNode) - { - wxTabControl *tab = (wxTabControl *)tabNode->GetData(); - controls.Append(tab); - wxList::compatibility_iterator next = tabNode->GetNext(); - layer->Erase(tabNode); - tabNode = next; - } - wxTabLayerList::compatibility_iterator nextLayerNode = layerNode->GetNext(); - delete layer; - m_layers.Erase(layerNode); - layerNode = nextLayerNode; - } - - wxTabControl *lastTab = (wxTabControl *) NULL; - - wxTabLayer *currentLayer = new wxTabLayer; - m_layers.Append(currentLayer); - - wxList::compatibility_iterator node = controls.GetFirst(); - while (node) - { - wxTabControl *tabControl = (wxTabControl *)node->GetData(); - if (lastTab) - { - // Start another layer (row). - // Tricky choice: can't just check if will be overlapping the edge, because - // this happens anyway for 2nd and subsequent rows. - // Should check this for 1st row, and then subsequent rows should not exceed 1st - // in length. - if (((currentLayer == m_layers.GetFirst()->GetData()) && ((lastTab->GetX() + 2*lastTab->GetWidth() + GetHorizontalTabSpacing()) - > GetViewRect().width)) || - ((currentLayer != m_layers.GetFirst()->GetData()) && (currentLayer->GetCount() == ((wxTabLayer *)m_layers.GetFirst()->GetData())->GetCount()))) - { - currentLayer = new wxTabLayer; - m_layers.Append(currentLayer); - lastTab = (wxTabControl *) NULL; - } - } - - int layer = m_layers.GetCount() - 1; - - tabControl->SetRowPosition(currentLayer->GetCount()); - tabControl->SetColPosition(layer); - - // Top of new tab - int verticalOffset = (- GetTopMargin()) - ((layer+1)*GetTabHeight()); - // Offset from view top-left - int horizontalOffset = 0; - if (!lastTab) - horizontalOffset = layer*GetHorizontalTabOffset(); - else - horizontalOffset = lastTab->GetX() + GetTabWidth() + GetHorizontalTabSpacing(); - - tabControl->SetPosition(horizontalOffset, verticalOffset); - tabControl->SetSize(GetTabWidth(), GetTabHeight()); - - currentLayer->Append(tabControl); - lastTab = tabControl; - - node = node->GetNext(); - } - - // Move the selected tab to the bottom - wxTabControl *control = FindTabControlForId(m_tabSelection); - if (control) - MoveSelectionTab(control); - -} - -// Draw all tabs -void wxTabView::Draw(wxDC& dc) -{ - // Don't draw anything if there are no tabs. - if (GetNumberOfTabs() == 0) - return; - - // Draw top margin area (beneath tabs and above view area) - if (GetTabStyle() & wxTAB_STYLE_COLOUR_INTERIOR) - { - dc.SetPen(*wxTRANSPARENT_PEN); - dc.SetBrush(*GetBackgroundBrush()); - - // Add 1 because the pen is transparent. Under Motif, may be different. - dc.DrawRectangle( - m_tabViewRect.x, - (m_tabViewRect.y - m_topMargin), - (m_tabViewRect.width + 1), - (m_topMargin + 1) - ); - } - - // Draw layers in reverse order - wxTabLayerList::compatibility_iterator node = m_layers.GetLast(); - while (node) - { - wxTabLayer *layer = (wxTabLayer *)node->GetData(); - wxList::compatibility_iterator node2 = layer->GetFirst(); - while (node2) - { - wxTabControl *control = (wxTabControl *)node2->GetData(); - control->OnDraw(dc, (!node2->GetNext())); - node2 = node2->GetNext(); - } - - node = node->GetPrevious(); - } - - -#ifndef wxUSE_NEW_METHOD - if (GetTabStyle() & wxTAB_STYLE_DRAW_BOX) - { - dc.SetPen(* GetShadowPen()); - - // Draw bottom line - dc.DrawLine( - (GetViewRect().x + 1), - (GetViewRect().y + GetViewRect().height), - (GetViewRect().x + GetViewRect().width + 1), - (GetViewRect().y + GetViewRect().height) - ); - - // Draw right line - dc.DrawLine( - (GetViewRect().x + GetViewRect().width), - (GetViewRect().y - GetTopMargin() + 1), - (GetViewRect().x + GetViewRect().width), - (GetViewRect().y + GetViewRect().height) - ); - - dc.SetPen(* wxBLACK_PEN); - - // Draw bottom line - dc.DrawLine( - (GetViewRect().x), - (GetViewRect().y + GetViewRect().height + 1), -#if defined(__WXMOTIF__) - (GetViewRect().x + GetViewRect().width + 1), -#else - (GetViewRect().x + GetViewRect().width + 2), -#endif - - (GetViewRect().y + GetViewRect().height + 1) - ); - - // Draw right line - dc.DrawLine( - (GetViewRect().x + GetViewRect().width + 1), - (GetViewRect().y - GetTopMargin()), - (GetViewRect().x + GetViewRect().width + 1), - (GetViewRect().y + GetViewRect().height + 1) - ); - } -#endif -} - -// Process mouse event, return false if we didn't process it -bool wxTabView::OnEvent(wxMouseEvent& event) -{ - if (!event.LeftDown()) - return false; - - wxCoord x, y; - event.GetPosition(&x, &y); - - wxTabControl *hitControl = (wxTabControl *) NULL; - - wxTabLayerList::compatibility_iterator node = m_layers.GetFirst(); - while (node) - { - wxTabLayer *layer = (wxTabLayer *)node->GetData(); - wxList::compatibility_iterator node2 = layer->GetFirst(); - while (node2) - { - wxTabControl *control = (wxTabControl *)node2->GetData(); - if (control->HitTest((int)x, (int)y)) - { - hitControl = control; - node = wxTabLayerList::compatibility_iterator(); - node2 = wxList::compatibility_iterator(); - } - else - node2 = node2->GetNext(); - } - - if (node) - node = node->GetNext(); - } - - if (!hitControl) - return false; - - wxTabControl *currentTab = FindTabControlForId(m_tabSelection); - - if (hitControl == currentTab) - return false; - - ChangeTab(hitControl); - - return true; -} - -bool wxTabView::ChangeTab(wxTabControl *control) -{ - wxTabControl *currentTab = FindTabControlForId(m_tabSelection); - int oldTab = -1; - if (currentTab) - oldTab = currentTab->GetId(); - - if (control == currentTab) - return true; - - if (m_layers.GetCount() == 0) - return false; - - if (!OnTabPreActivate(control->GetId(), oldTab)) - return false; - - // Move the tab to the bottom - MoveSelectionTab(control); - - if (currentTab) - currentTab->SetSelected(false); - - control->SetSelected(true); - m_tabSelection = control->GetId(); - - OnTabActivate(control->GetId(), oldTab); - - // Leave window refresh for the implementing window - - return true; -} - -// Move the selected tab to the bottom layer, if necessary, -// without calling app activation code -bool wxTabView::MoveSelectionTab(wxTabControl *control) -{ - if (m_layers.GetCount() == 0) - return false; - - wxTabLayer *firstLayer = (wxTabLayer *)m_layers.GetFirst()->GetData(); - - // Find what column this tab is at, so we can swap with the one at the bottom. - // If we're on the bottom layer, then no need to swap. - if (!firstLayer->Member(control)) - { - // Do a swap - int col = 0; - wxList::compatibility_iterator thisNode = FindTabNodeAndColumn(control, &col); - if (!thisNode) - return false; - wxList::compatibility_iterator otherNode = firstLayer->Item(col); - if (!otherNode) - return false; - - // If this is already in the bottom layer, return now - if (otherNode == thisNode) - return true; - - wxTabControl *otherTab = (wxTabControl *)otherNode->GetData(); - - // We now have pointers to the tab to be changed to, - // and the tab on the first layer. Swap tab structures and - // position details. - - int thisX = control->GetX(); - int thisY = control->GetY(); - int thisColPos = control->GetColPosition(); - int otherX = otherTab->GetX(); - int otherY = otherTab->GetY(); - int otherColPos = otherTab->GetColPosition(); - - control->SetPosition(otherX, otherY); - control->SetColPosition(otherColPos); - otherTab->SetPosition(thisX, thisY); - otherTab->SetColPosition(thisColPos); - - // Swap the data for the nodes - thisNode->SetData(otherTab); - otherNode->SetData(control); - } - return true; -} - -// Called when a tab is activated -void wxTabView::OnTabActivate(int /*activateId*/, int /*deactivateId*/) -{ -} - -void wxTabView::SetHighlightColour(const wxColour& col) -{ - m_highlightColour = col; - m_highlightPen = wxThePenList->FindOrCreatePen(col, 1, wxSOLID); -} - -void wxTabView::SetShadowColour(const wxColour& col) -{ - m_shadowColour = col; - m_shadowPen = wxThePenList->FindOrCreatePen(col, 1, wxSOLID); -} - -void wxTabView::SetBackgroundColour(const wxColour& col) -{ - m_backgroundColour = col; - m_backgroundPen = wxThePenList->FindOrCreatePen(col, 1, wxSOLID); - m_backgroundBrush = wxTheBrushList->FindOrCreateBrush(col, wxSOLID); -} - -// this may be called with sel = zero (which doesn't match any page) -// when wxMotif deletes a page -// so return the first tab... - -void wxTabView::SetTabSelection(int sel, bool activateTool) -{ - if ( sel==m_tabSelection ) - return; - - int oldSel = m_tabSelection; - wxTabControl *control = FindTabControlForId(sel); - if (sel == 0) sel=control->GetId(); - wxTabControl *oldControl = FindTabControlForId(m_tabSelection); - - if (!OnTabPreActivate(sel, oldSel)) - return; - - if (control) - control->SetSelected((sel != -1)); // TODO ?? - else if (sel != -1) - { - wxFAIL_MSG(_("Could not find tab for id")); - return; - } - - if (oldControl) - oldControl->SetSelected(false); - - m_tabSelection = sel; - - if (control) - MoveSelectionTab(control); - - if (activateTool) - OnTabActivate(sel, oldSel); -} - -// Find tab control for id -// this may be called with zero (which doesn't match any page) -// so return the first control... -wxTabControl *wxTabView::FindTabControlForId(int id) const -{ - wxTabLayerList::compatibility_iterator node1 = m_layers.GetFirst(); - while (node1) - { - wxTabLayer *layer = (wxTabLayer *)node1->GetData(); - wxList::compatibility_iterator node2 = layer->GetFirst(); - while (node2) - { - wxTabControl *control = (wxTabControl *)node2->GetData(); - if (control->GetId() == id || id == 0) - return control; - node2 = node2->GetNext(); - } - node1 = node1->GetNext(); - } - return (wxTabControl *) NULL; -} - -// Find tab control for layer, position (starting from zero) -wxTabControl *wxTabView::FindTabControlForPosition(int layer, int position) const -{ - wxTabLayerList::compatibility_iterator node1 = m_layers.Item(layer); - if (!node1) - return (wxTabControl *) NULL; - wxTabLayer *tabLayer = (wxTabLayer *)node1->GetData(); - wxList::compatibility_iterator node2 = tabLayer->Item(position); - if (!node2) - return (wxTabControl *) NULL; - return (wxTabControl *)node2->GetData(); -} - -// Find the node and the column at which this control is positioned. -wxList::compatibility_iterator wxTabView::FindTabNodeAndColumn(wxTabControl *control, int *col) const -{ - wxTabLayerList::compatibility_iterator node1 = m_layers.GetFirst(); - while (node1) - { - wxTabLayer *layer = (wxTabLayer *)node1->GetData(); - int c = 0; - wxList::compatibility_iterator node2 = layer->GetFirst(); - while (node2) - { - wxTabControl *cnt = (wxTabControl *)node2->GetData(); - if (cnt == control) - { - *col = c; - return node2; - } - node2 = node2->GetNext(); - c ++; - } - node1 = node1->GetNext(); - } - return wxList::compatibility_iterator(); -} - -int wxTabView::CalculateTabWidth(int noTabs, bool adjustView) -{ - m_tabWidth = (int)((m_tabViewRect.width - ((noTabs - 1)*GetHorizontalTabSpacing()))/noTabs); - if (adjustView) - { - m_tabViewRect.width = noTabs*m_tabWidth + ((noTabs-1)*GetHorizontalTabSpacing()); - } - return m_tabWidth; -} - -/* - * wxTabbedDialog - */ - -IMPLEMENT_CLASS(wxTabbedDialog, wxDialog) - -BEGIN_EVENT_TABLE(wxTabbedDialog, wxDialog) - EVT_CLOSE(wxTabbedDialog::OnCloseWindow) - EVT_MOUSE_EVENTS(wxTabbedDialog::OnMouseEvent) - EVT_PAINT(wxTabbedDialog::OnPaint) -END_EVENT_TABLE() - -wxTabbedDialog::wxTabbedDialog(wxWindow *parent, wxWindowID id, - const wxString& title, - const wxPoint& pos, const wxSize& size, - long windowStyle, const wxString& name): - wxDialog(parent, id, title, pos, size, windowStyle, name) -{ - m_tabView = (wxTabView *) NULL; -} - -wxTabbedDialog::~wxTabbedDialog(void) -{ - if (m_tabView) - delete m_tabView; -} - -void wxTabbedDialog::OnCloseWindow(wxCloseEvent& WXUNUSED(event) ) -{ - Destroy(); -} - -void wxTabbedDialog::OnMouseEvent(wxMouseEvent& event ) -{ - if (m_tabView) - m_tabView->OnEvent(event); -} - -void wxTabbedDialog::OnPaint(wxPaintEvent& WXUNUSED(event) ) -{ - wxPaintDC dc(this); - if (m_tabView) - m_tabView->Draw(dc); -} - -/* - * wxTabbedPanel - */ - -IMPLEMENT_CLASS(wxTabbedPanel, wxPanel) - -BEGIN_EVENT_TABLE(wxTabbedPanel, wxPanel) - EVT_MOUSE_EVENTS(wxTabbedPanel::OnMouseEvent) - EVT_PAINT(wxTabbedPanel::OnPaint) -END_EVENT_TABLE() - -wxTabbedPanel::wxTabbedPanel(wxWindow *parent, wxWindowID id, const wxPoint& pos, - const wxSize& size, long windowStyle, const wxString& name): - wxPanel(parent, id, pos, size, windowStyle, name) -{ - m_tabView = (wxTabView *) NULL; -} - -wxTabbedPanel::~wxTabbedPanel(void) -{ - delete m_tabView; -} - -void wxTabbedPanel::OnMouseEvent(wxMouseEvent& event) -{ - if (m_tabView) - m_tabView->OnEvent(event); -} - -void wxTabbedPanel::OnPaint(wxPaintEvent& WXUNUSED(event) ) -{ - wxPaintDC dc(this); - if (m_tabView) - m_tabView->Draw(dc); -} - -/* - * wxPanelTabView - */ - -IMPLEMENT_CLASS(wxPanelTabView, wxTabView) - -wxPanelTabView::wxPanelTabView(wxPanel *pan, long style) - : wxTabView(style) -{ - m_panel = pan; - m_currentWindow = (wxWindow *) NULL; - - if (m_panel->IsKindOf(CLASSINFO(wxTabbedDialog))) - ((wxTabbedDialog *)m_panel)->SetTabView(this); - else if (m_panel->IsKindOf(CLASSINFO(wxTabbedPanel))) - ((wxTabbedPanel *)m_panel)->SetTabView(this); - - SetWindow(m_panel); -} - -wxPanelTabView::~wxPanelTabView(void) -{ - ClearWindows(true); -} - -// Called when a tab is activated -void wxPanelTabView::OnTabActivate(int activateId, int deactivateId) -{ - if (!m_panel) - return; - - wxWindow *oldWindow = ((deactivateId == -1) ? 0 : GetTabWindow(deactivateId)); - wxWindow *newWindow = GetTabWindow(activateId); - - if (oldWindow) - oldWindow->Show(false); - if (newWindow) - newWindow->Show(true); - - m_panel->Refresh(); -} - - -void wxPanelTabView::AddTabWindow(int id, wxWindow *window) -{ - wxASSERT(m_tabWindows.find(id) == m_tabWindows.end()); - m_tabWindows[id] = window; - window->Show(false); -} - -wxWindow *wxPanelTabView::GetTabWindow(int id) const -{ - wxIntToWindowHashMap::const_iterator it = m_tabWindows.find(id); - return it == m_tabWindows.end() ? NULL : it->second; -} - -void wxPanelTabView::ClearWindows(bool deleteWindows) -{ - if (deleteWindows) - WX_CLEAR_HASH_MAP(wxIntToWindowHashMap, m_tabWindows); - m_tabWindows.clear(); -} - -void wxPanelTabView::ShowWindowForTab(int id) -{ - wxWindow *newWindow = GetTabWindow(id); - if (newWindow == m_currentWindow) - return; - if (m_currentWindow) - m_currentWindow->Show(false); - newWindow->Show(true); - newWindow->Refresh(); -} - -#endif // wxUSE_TAB_DIALOG +///////////////////////////////////////////////////////////////////////////// +// Name: src/generic/tabg.cpp +// Purpose: Generic tabbed dialogs +// Author: Julian Smart +// Modified by: +// Created: 01/02/97 +// RCS-ID: $Id: tabg.cpp 39745 2006-06-15 17:58:49Z ABX $ +// Copyright: (c) +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_TAB_DIALOG + +#ifndef WX_PRECOMP + #include "wx/settings.h" + #include "wx/intl.h" + #include "wx/dcclient.h" + #include "wx/math.h" +#endif + +#include +#include +#include + +#include "wx/tab.h" +#include "wx/listimpl.cpp" + +WX_DEFINE_LIST(wxTabLayerList) + +// not defined: use old, square tab implementation (fills in tabs) +// defined: use new, rounded tab implementation (doesn't colour in tabs) +// #define wxUSE_NEW_METHOD + +IMPLEMENT_DYNAMIC_CLASS(wxTabControl, wxObject) + +// IMPLEMENT_DYNAMIC_CLASS(wxTabLayer, wxList) + +wxTabControl::wxTabControl(wxTabView *v) +{ + m_view = v; + m_isSelected = false; + m_offsetX = 0; + m_offsetY = 0; + m_width = 0; + m_height = 0; + m_id = 0; + m_rowPosition = 0; + m_colPosition = 0; +} + +wxTabControl::~wxTabControl(void) +{ +} + +void wxTabControl::OnDraw(wxDC& dc, bool lastInRow) +{ + // Old, but in some ways better (drawing opaque tabs) +#ifndef wxUSE_NEW_METHOD + if (!m_view) + return; + + // Top-left of tab view area + int viewX = m_view->GetViewRect().x; + int viewY = m_view->GetViewRect().y; + + // Top-left of tab control + int tabX = GetX() + viewX; + int tabY = GetY() + viewY; + int tabHeightInc = 0; + if (m_isSelected) + { + tabHeightInc = (m_view->GetTabSelectionHeight() - m_view->GetTabHeight()); + tabY -= tabHeightInc; + } + + dc.SetPen(*wxTRANSPARENT_PEN); + + // Draw grey background + if (m_view->GetTabStyle() & wxTAB_STYLE_COLOUR_INTERIOR) + { + dc.SetBrush(*m_view->GetBackgroundBrush()); + + // Add 1 because the pen is transparent. Under Motif, may be different. +#ifdef __WXMOTIF__ + dc.DrawRectangle(tabX, tabY, (GetWidth()+1), (GetHeight() + tabHeightInc)); +#else + dc.DrawRectangle(tabX, tabY, (GetWidth()+1), (GetHeight() + 1 + tabHeightInc)); +#endif + } + + // Draw highlight and shadow + dc.SetPen(*m_view->GetHighlightPen()); + + // Calculate the top of the tab beneath. It's the height of the tab, MINUS + // a bit if the tab below happens to be selected. Check. + wxTabControl *tabBeneath = NULL; + int subtractThis = 0; + if (GetColPosition() > 0) + tabBeneath = m_view->FindTabControlForPosition(GetColPosition() - 1, GetRowPosition()); + if (tabBeneath && tabBeneath->IsSelected()) + subtractThis = (m_view->GetTabSelectionHeight() - m_view->GetTabHeight()); + + // Vertical highlight: if first tab, draw to bottom of view + if (tabX == m_view->GetViewRect().x && (m_view->GetTabStyle() & wxTAB_STYLE_DRAW_BOX)) + dc.DrawLine(tabX, tabY, tabX, (m_view->GetViewRect().y + m_view->GetViewRect().height)); + else if (tabX == m_view->GetViewRect().x) + // Not box drawing, just to top of view. + dc.DrawLine(tabX, tabY, tabX, (m_view->GetViewRect().y)); + else + dc.DrawLine(tabX, tabY, tabX, (tabY + GetHeight() + tabHeightInc - subtractThis)); + + dc.DrawLine(tabX, tabY, (tabX + GetWidth()), tabY); + dc.SetPen(*m_view->GetShadowPen()); + + // Test if we're outside the right-hand edge of the view area + if (((tabX + GetWidth()) >= m_view->GetViewRect().x + m_view->GetViewRect().width) && (m_view->GetTabStyle() & wxTAB_STYLE_DRAW_BOX)) + { + int bottomY = m_view->GetViewRect().y + m_view->GetViewRect().height + GetY() + m_view->GetTabHeight() + m_view->GetTopMargin(); + // Add a tab height since we wish to draw to the bottom of the view. + dc.DrawLine((tabX + GetWidth()), tabY, + (tabX + GetWidth()), bottomY); + + // Calculate the far-right of the view, since we don't wish to + // draw inside that + int rightOfView = m_view->GetViewRect().x + m_view->GetViewRect().width + 1; + + // Draw the horizontal bit to connect to the view rectangle + dc.DrawLine((wxMax((tabX + GetWidth() - m_view->GetHorizontalTabOffset()), rightOfView)), (bottomY-1), + (tabX + GetWidth()), (bottomY-1)); + + // Draw black line to emphasize shadow + dc.SetPen(*wxBLACK_PEN); + dc.DrawLine((tabX + GetWidth() + 1), (tabY+1), + (tabX + GetWidth() + 1), bottomY); + + // Draw the horizontal bit to connect to the view rectangle + dc.DrawLine((wxMax((tabX + GetWidth() - m_view->GetHorizontalTabOffset()), rightOfView)), (bottomY), + (tabX + GetWidth() + 1), (bottomY)); + } + else + { + if (lastInRow) + { + // 25/5/97 UNLESS it's less than the max number of positions in this row + + int topY = m_view->GetViewRect().y - m_view->GetTopMargin(); + + int maxPositions = ((wxTabLayer *)m_view->GetLayers().Item(0)->GetData())->GetCount(); + + // Only down to the bottom of the tab, not to the top of the view + if ( GetRowPosition() < (maxPositions - 1) ) + topY = tabY + GetHeight() + tabHeightInc; + +#ifdef __WXMOTIF__ + topY -= 1; +#endif + + // Shadow + dc.DrawLine((tabX + GetWidth()), tabY, (tabX + GetWidth()), topY); + // Draw black line to emphasize shadow + dc.SetPen(*wxBLACK_PEN); + dc.DrawLine((tabX + GetWidth() + 1), (tabY+1), (tabX + GetWidth() + 1), + topY); + } + else + { + // Calculate the top of the tab beneath. It's the height of the tab, MINUS + // a bit if the tab below (and next col along) happens to be selected. Check. + wxTabControl *tabBeneath = NULL; + int subtractThis = 0; + if (GetColPosition() > 0) + tabBeneath = m_view->FindTabControlForPosition(GetColPosition() - 1, GetRowPosition() + 1); + if (tabBeneath && tabBeneath->IsSelected()) + subtractThis = (m_view->GetTabSelectionHeight() - m_view->GetTabHeight()); + +#ifdef __WXMOTIF__ + subtractThis += 1; +#endif + + // Draw only to next tab down. + dc.DrawLine((tabX + GetWidth()), tabY, + (tabX + GetWidth()), (tabY + GetHeight() + tabHeightInc - subtractThis)); + + // Draw black line to emphasize shadow + dc.SetPen(*wxBLACK_PEN); + dc.DrawLine((tabX + GetWidth() + 1), (tabY+1), (tabX + GetWidth() + 1), + (tabY + GetHeight() + tabHeightInc - subtractThis)); + } + } + + // Draw centered text + int textY = tabY + m_view->GetVerticalTabTextSpacing() + tabHeightInc; + + if (m_isSelected) + dc.SetFont(* m_view->GetSelectedTabFont()); + else + dc.SetFont(* GetFont()); + + wxColour col(m_view->GetTextColour()); + dc.SetTextForeground(col); + dc.SetBackgroundMode(wxTRANSPARENT); + long textWidth, textHeight; + dc.GetTextExtent(GetLabel(), &textWidth, &textHeight); + + int textX = (int)(tabX + (GetWidth() - textWidth)/2.0); + if (textX < (tabX + 2)) + textX = (tabX + 2); + + dc.SetClippingRegion(tabX, tabY, GetWidth(), GetHeight()); + dc.DrawText(GetLabel(), textX, textY); + dc.DestroyClippingRegion(); + + if (m_isSelected) + { + dc.SetPen(*m_view->GetHighlightPen()); + + // Draw white highlight from the tab's left side to the left hand edge of the view + dc.DrawLine(m_view->GetViewRect().x, (tabY + GetHeight() + tabHeightInc), + tabX, (tabY + GetHeight() + tabHeightInc)); + + // Draw white highlight from the tab's right side to the right hand edge of the view + dc.DrawLine((tabX + GetWidth()), (tabY + GetHeight() + tabHeightInc), + m_view->GetViewRect().x + m_view->GetViewRect().width, (tabY + GetHeight() + tabHeightInc)); + } +#else + // New HEL version with rounder tabs + + if (!m_view) return; + + int tabInc = 0; + if (m_isSelected) + { + tabInc = m_view->GetTabSelectionHeight() - m_view->GetTabHeight(); + } + int tabLeft = GetX() + m_view->GetViewRect().x; + int tabTop = GetY() + m_view->GetViewRect().y - tabInc; + int tabRight = tabLeft + m_view->GetTabWidth(); + int left = m_view->GetViewRect().x; + int top = tabTop + m_view->GetTabHeight() + tabInc; + int right = left + m_view->GetViewRect().width; + int bottom = top + m_view->GetViewRect().height; + + if (m_isSelected) + { + // TAB is selected - draw TAB and the View's full outline + + dc.SetPen(*(m_view->GetHighlightPen())); + wxPoint pnts[10]; + int n = 0; + pnts[n].x = left; pnts[n++].y = bottom; + pnts[n].x = left; pnts[n++].y = top; + pnts[n].x = tabLeft; pnts[n++].y = top; + pnts[n].x = tabLeft; pnts[n++].y = tabTop + 2; + pnts[n].x = tabLeft + 2; pnts[n++].y = tabTop; + pnts[n].x = tabRight - 1; pnts[n++].y = tabTop; + dc.DrawLines(n, pnts); + if (!lastInRow) + { + dc.DrawLine( + (tabRight + 2), + top, + right, + top + ); + } + + dc.SetPen(*(m_view->GetShadowPen())); + dc.DrawLine( + tabRight, + tabTop + 2, + tabRight, + top + ); + dc.DrawLine( + right, + top, + right, + bottom + ); + dc.DrawLine( + right, + bottom, + left, + bottom + ); + + dc.SetPen(*wxBLACK_PEN); + dc.DrawPoint( + tabRight, + tabTop + 1 + ); + dc.DrawPoint( + tabRight + 1, + tabTop + 2 + ); + if (lastInRow) + { + dc.DrawLine( + tabRight + 1, + bottom, + tabRight + 1, + tabTop + 1 + ); + } + else + { + dc.DrawLine( + tabRight + 1, + tabTop + 2, + tabRight + 1, + top + ); + dc.DrawLine( + right + 1, + top, + right + 1, + bottom + 1 + ); + } + dc.DrawLine( + right + 1, + bottom + 1, + left + 1, + bottom + 1 + ); + } + else + { + // TAB is not selected - just draw TAB outline and RH edge + // if the TAB is the last in the row + + int maxPositions = ((wxTabLayer*)m_view->GetLayers().Item(0)->GetData())->GetCount(); + wxTabControl* tabBelow = 0; + wxTabControl* tabBelowRight = 0; + if (GetColPosition() > 0) + { + tabBelow = m_view->FindTabControlForPosition( + GetColPosition() - 1, + GetRowPosition() + ); + } + if (!lastInRow && GetColPosition() > 0) + { + tabBelowRight = m_view->FindTabControlForPosition( + GetColPosition() - 1, + GetRowPosition() + 1 + ); + } + + float raisedTop = top - m_view->GetTabSelectionHeight() + + m_view->GetTabHeight(); + + dc.SetPen(*(m_view->GetHighlightPen())); + wxPoint pnts[10]; + int n = 0; + + pnts[n].x = tabLeft; + + if (tabBelow && tabBelow->IsSelected()) + { + pnts[n++].y = (long)raisedTop; + } + else + { + pnts[n++].y = top; + } + pnts[n].x = tabLeft; pnts[n++].y = tabTop + 2; + pnts[n].x = tabLeft + 2; pnts[n++].y = tabTop; + pnts[n].x = tabRight - 1; pnts[n++].y = tabTop; + dc.DrawLines(n, pnts); + + dc.SetPen(*(m_view->GetShadowPen())); + if (GetRowPosition() >= maxPositions - 1) + { + dc.DrawLine( + tabRight, + (tabTop + 2), + tabRight, + bottom + ); + dc.DrawLine( + tabRight, + bottom, + (tabRight - m_view->GetHorizontalTabOffset()), + bottom + ); + } + else + { + if (tabBelowRight && tabBelowRight->IsSelected()) + { + dc.DrawLine( + tabRight, + (long)raisedTop, + tabRight, + tabTop + 1 + ); + } + else + { + dc.DrawLine( + tabRight, + top - 1, + tabRight, + tabTop + 1 + ); + } + } + + dc.SetPen(*wxBLACK_PEN); + dc.DrawPoint( + tabRight, + tabTop + 1 + ); + dc.DrawPoint( + tabRight + 1, + tabTop + 2 + ); + if (GetRowPosition() >= maxPositions - 1) + { + // draw right hand edge to bottom of view + dc.DrawLine( + tabRight + 1, + bottom + 1, + tabRight + 1, + tabTop + 2 + ); + dc.DrawLine( + tabRight + 1, + bottom + 1, + (tabRight - m_view->GetHorizontalTabOffset()), + bottom + 1 + ); + } + else + { + // draw right hand edge of TAB + if (tabBelowRight && tabBelowRight->IsSelected()) + { + dc.DrawLine( + tabRight + 1, + (long)(raisedTop - 1), + tabRight + 1, + tabTop + 2 + ); + } + else + { + dc.DrawLine( + tabRight + 1, + top - 1, + tabRight + 1, + tabTop + 2 + ); + } + } + } + + // Draw centered text + dc.SetPen(*wxBLACK_PEN); + if (m_isSelected) + { + dc.SetFont(*(m_view->GetSelectedTabFont())); + } + else + { + dc.SetFont(*(GetFont())); + } + + wxColour col(m_view->GetTextColour()); + dc.SetTextForeground(col); + dc.SetBackgroundMode(wxTRANSPARENT); + long textWidth, textHeight; + dc.GetTextExtent(GetLabel(), &textWidth, &textHeight); + + float textX = (tabLeft + tabRight - textWidth) / 2; + float textY = (tabInc + tabTop + m_view->GetVerticalTabTextSpacing()); + + dc.DrawText(GetLabel(), (long)textX, (long)textY); +#endif +} + +bool wxTabControl::HitTest(int x, int y) const +{ + // Top-left of tab control + int tabX1 = GetX() + m_view->GetViewRect().x; + int tabY1 = GetY() + m_view->GetViewRect().y; + + // Bottom-right + int tabX2 = tabX1 + GetWidth(); + int tabY2 = tabY1 + GetHeight(); + + if (x >= tabX1 && y >= tabY1 && x <= tabX2 && y <= tabY2) + return true; + else + return false; +} + +IMPLEMENT_DYNAMIC_CLASS(wxTabView, wxObject) + +wxTabView::wxTabView(long style) +{ + m_noTabs = 0; + m_tabStyle = style; + m_tabSelection = -1; + m_tabHeight = 20; + m_tabSelectionHeight = m_tabHeight + 2; + m_tabWidth = 80; + m_tabHorizontalOffset = 10; + m_tabHorizontalSpacing = 2; + m_tabVerticalTextSpacing = 3; + m_topMargin = 5; + m_tabViewRect.x = 20; + m_tabViewRect.y = 20; + m_tabViewRect.width = 300; + m_tabViewRect.x = 300; + m_highlightColour = *wxWHITE; + m_shadowColour = wxColour(128, 128, 128); + m_backgroundColour = wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE); + m_textColour = *wxBLACK; + m_highlightPen = wxWHITE_PEN; + m_shadowPen = wxGREY_PEN; + SetBackgroundColour(m_backgroundColour); + m_tabFont = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT); + m_tabSelectedFont = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT); + m_window = (wxWindow *) NULL; +} + +wxTabView::~wxTabView() +{ + ClearTabs(true); +} + +// Automatically positions tabs +// TODO: this should just add the tab to a list, and then +// a layout function (e.g. Realize) should be called when all tabs have been added. +// The view rect could easily change as the view window is resized. +wxTabControl *wxTabView::AddTab(int id, const wxString& label, wxTabControl *existingTab) +{ + // First, find which layer we should be adding to. + wxTabLayerList::compatibility_iterator node = m_layers.GetLast(); + if (!node) + { + wxTabLayer *newLayer = new wxTabLayer; + node = m_layers.Append(newLayer); + } + // Check if adding another tab control would go off the + // right-hand edge of the layer. + wxTabLayer *tabLayer = (wxTabLayer *)node->GetData(); + wxList::compatibility_iterator lastTabNode = tabLayer->GetLast(); + if (lastTabNode) + { + wxTabControl *lastTab = (wxTabControl *)lastTabNode->GetData(); + // Start another layer (row). + // Tricky choice: can't just check if will be overlapping the edge, because + // this happens anyway for 2nd and subsequent rows. + // Should check this for 1st row, and then subsequent rows should not exceed 1st + // in length. + if (((tabLayer == m_layers.GetFirst()->GetData()) && ((lastTab->GetX() + 2*lastTab->GetWidth() + GetHorizontalTabSpacing()) + > GetViewRect().width)) || + ((tabLayer != m_layers.GetFirst()->GetData()) && (tabLayer->GetCount() == ((wxTabLayer *)m_layers.GetFirst()->GetData())->GetCount()))) + { + tabLayer = new wxTabLayer; + m_layers.Append(tabLayer); + lastTabNode = wxList::compatibility_iterator(); + } + } + int layer = m_layers.GetCount() - 1; + + wxTabControl *tabControl = existingTab; + if (!existingTab) + tabControl = OnCreateTabControl(); + tabControl->SetRowPosition(tabLayer->GetCount()); + tabControl->SetColPosition(layer); + + wxTabControl *lastTab = (wxTabControl *) NULL; + if (lastTabNode) + lastTab = (wxTabControl *)lastTabNode->GetData(); + + // Top of new tab + int verticalOffset = (- GetTopMargin()) - ((layer+1)*GetTabHeight()); + // Offset from view top-left + int horizontalOffset = 0; + if (!lastTab) + horizontalOffset = layer*GetHorizontalTabOffset(); + else + horizontalOffset = lastTab->GetX() + GetTabWidth() + GetHorizontalTabSpacing(); + + tabControl->SetPosition(horizontalOffset, verticalOffset); + tabControl->SetSize(GetTabWidth(), GetTabHeight()); + tabControl->SetId(id); + tabControl->SetLabel(label); + tabControl->SetFont(* GetTabFont()); + + tabLayer->Append(tabControl); + m_noTabs ++; + + return tabControl; +} + +// Remove the tab without deleting the window +bool wxTabView::RemoveTab(int id) +{ + wxTabLayerList::compatibility_iterator layerNode = m_layers.GetFirst(); + while (layerNode) + { + wxTabLayer *layer = (wxTabLayer *)layerNode->GetData(); + wxList::compatibility_iterator tabNode = layer->GetFirst(); + while (tabNode) + { + wxTabControl *tab = (wxTabControl *)tabNode->GetData(); + if (tab->GetId() == id) + { + if (id == m_tabSelection) + m_tabSelection = -1; + delete tab; + layer->Erase(tabNode); + m_noTabs --; + + // The layout has changed + LayoutTabs(); + return true; + } + tabNode = tabNode->GetNext(); + } + layerNode = layerNode->GetNext(); + } + return false; +} + +bool wxTabView::SetTabText(int id, const wxString& label) +{ + wxTabControl* control = FindTabControlForId(id); + if (!control) + return false; + control->SetLabel(label); + return true; +} + +wxString wxTabView::GetTabText(int id) const +{ + wxTabControl* control = FindTabControlForId(id); + if (!control) + return wxEmptyString; + else + return control->GetLabel(); +} + +// Returns the total height of the tabs component -- this may be several +// times the height of a tab, if there are several tab layers (rows). +int wxTabView::GetTotalTabHeight() +{ + int minY = 0; + + wxTabLayerList::compatibility_iterator layerNode = m_layers.GetFirst(); + while (layerNode) + { + wxTabLayer *layer = (wxTabLayer *)layerNode->GetData(); + wxList::compatibility_iterator tabNode = layer->GetFirst(); + while (tabNode) + { + wxTabControl *tab = (wxTabControl *)tabNode->GetData(); + + if (tab->GetY() < minY) + minY = tab->GetY(); + + tabNode = tabNode->GetNext(); + } + layerNode = layerNode->GetNext(); + } + + return - minY; +} + +void wxTabView::ClearTabs(bool deleteTabs) +{ + wxTabLayerList::compatibility_iterator layerNode = m_layers.GetFirst(); + while (layerNode) + { + wxTabLayer *layer = (wxTabLayer *)layerNode->GetData(); + wxList::compatibility_iterator tabNode = layer->GetFirst(); + while (tabNode) + { + wxTabControl *tab = (wxTabControl *)tabNode->GetData(); + if (deleteTabs) + delete tab; + wxList::compatibility_iterator next = tabNode->GetNext(); + layer->Erase(tabNode); + tabNode = next; + } + wxTabLayerList::compatibility_iterator nextLayerNode = layerNode->GetNext(); + delete layer; + m_layers.Erase(layerNode); + layerNode = nextLayerNode; + } + m_noTabs = 0; + m_tabSelection = -1; +} + + +// Layout tabs (optional, e.g. if resizing window) +void wxTabView::LayoutTabs(void) +{ + // Make a list of the tab controls, deleting the wxTabLayers. + wxList controls; + + wxTabLayerList::compatibility_iterator layerNode = m_layers.GetFirst(); + while (layerNode) + { + wxTabLayer *layer = (wxTabLayer *)layerNode->GetData(); + wxList::compatibility_iterator tabNode = layer->GetFirst(); + while (tabNode) + { + wxTabControl *tab = (wxTabControl *)tabNode->GetData(); + controls.Append(tab); + wxList::compatibility_iterator next = tabNode->GetNext(); + layer->Erase(tabNode); + tabNode = next; + } + wxTabLayerList::compatibility_iterator nextLayerNode = layerNode->GetNext(); + delete layer; + m_layers.Erase(layerNode); + layerNode = nextLayerNode; + } + + wxTabControl *lastTab = (wxTabControl *) NULL; + + wxTabLayer *currentLayer = new wxTabLayer; + m_layers.Append(currentLayer); + + wxList::compatibility_iterator node = controls.GetFirst(); + while (node) + { + wxTabControl *tabControl = (wxTabControl *)node->GetData(); + if (lastTab) + { + // Start another layer (row). + // Tricky choice: can't just check if will be overlapping the edge, because + // this happens anyway for 2nd and subsequent rows. + // Should check this for 1st row, and then subsequent rows should not exceed 1st + // in length. + if (((currentLayer == m_layers.GetFirst()->GetData()) && ((lastTab->GetX() + 2*lastTab->GetWidth() + GetHorizontalTabSpacing()) + > GetViewRect().width)) || + ((currentLayer != m_layers.GetFirst()->GetData()) && (currentLayer->GetCount() == ((wxTabLayer *)m_layers.GetFirst()->GetData())->GetCount()))) + { + currentLayer = new wxTabLayer; + m_layers.Append(currentLayer); + lastTab = (wxTabControl *) NULL; + } + } + + int layer = m_layers.GetCount() - 1; + + tabControl->SetRowPosition(currentLayer->GetCount()); + tabControl->SetColPosition(layer); + + // Top of new tab + int verticalOffset = (- GetTopMargin()) - ((layer+1)*GetTabHeight()); + // Offset from view top-left + int horizontalOffset = 0; + if (!lastTab) + horizontalOffset = layer*GetHorizontalTabOffset(); + else + horizontalOffset = lastTab->GetX() + GetTabWidth() + GetHorizontalTabSpacing(); + + tabControl->SetPosition(horizontalOffset, verticalOffset); + tabControl->SetSize(GetTabWidth(), GetTabHeight()); + + currentLayer->Append(tabControl); + lastTab = tabControl; + + node = node->GetNext(); + } + + // Move the selected tab to the bottom + wxTabControl *control = FindTabControlForId(m_tabSelection); + if (control) + MoveSelectionTab(control); + +} + +// Draw all tabs +void wxTabView::Draw(wxDC& dc) +{ + // Don't draw anything if there are no tabs. + if (GetNumberOfTabs() == 0) + return; + + // Draw top margin area (beneath tabs and above view area) + if (GetTabStyle() & wxTAB_STYLE_COLOUR_INTERIOR) + { + dc.SetPen(*wxTRANSPARENT_PEN); + dc.SetBrush(*GetBackgroundBrush()); + + // Add 1 because the pen is transparent. Under Motif, may be different. + dc.DrawRectangle( + m_tabViewRect.x, + (m_tabViewRect.y - m_topMargin), + (m_tabViewRect.width + 1), + (m_topMargin + 1) + ); + } + + // Draw layers in reverse order + wxTabLayerList::compatibility_iterator node = m_layers.GetLast(); + while (node) + { + wxTabLayer *layer = (wxTabLayer *)node->GetData(); + wxList::compatibility_iterator node2 = layer->GetFirst(); + while (node2) + { + wxTabControl *control = (wxTabControl *)node2->GetData(); + control->OnDraw(dc, (!node2->GetNext())); + node2 = node2->GetNext(); + } + + node = node->GetPrevious(); + } + + +#ifndef wxUSE_NEW_METHOD + if (GetTabStyle() & wxTAB_STYLE_DRAW_BOX) + { + dc.SetPen(* GetShadowPen()); + + // Draw bottom line + dc.DrawLine( + (GetViewRect().x + 1), + (GetViewRect().y + GetViewRect().height), + (GetViewRect().x + GetViewRect().width + 1), + (GetViewRect().y + GetViewRect().height) + ); + + // Draw right line + dc.DrawLine( + (GetViewRect().x + GetViewRect().width), + (GetViewRect().y - GetTopMargin() + 1), + (GetViewRect().x + GetViewRect().width), + (GetViewRect().y + GetViewRect().height) + ); + + dc.SetPen(* wxBLACK_PEN); + + // Draw bottom line + dc.DrawLine( + (GetViewRect().x), + (GetViewRect().y + GetViewRect().height + 1), +#if defined(__WXMOTIF__) + (GetViewRect().x + GetViewRect().width + 1), +#else + (GetViewRect().x + GetViewRect().width + 2), +#endif + + (GetViewRect().y + GetViewRect().height + 1) + ); + + // Draw right line + dc.DrawLine( + (GetViewRect().x + GetViewRect().width + 1), + (GetViewRect().y - GetTopMargin()), + (GetViewRect().x + GetViewRect().width + 1), + (GetViewRect().y + GetViewRect().height + 1) + ); + } +#endif +} + +// Process mouse event, return false if we didn't process it +bool wxTabView::OnEvent(wxMouseEvent& event) +{ + if (!event.LeftDown()) + return false; + + wxCoord x, y; + event.GetPosition(&x, &y); + + wxTabControl *hitControl = (wxTabControl *) NULL; + + wxTabLayerList::compatibility_iterator node = m_layers.GetFirst(); + while (node) + { + wxTabLayer *layer = (wxTabLayer *)node->GetData(); + wxList::compatibility_iterator node2 = layer->GetFirst(); + while (node2) + { + wxTabControl *control = (wxTabControl *)node2->GetData(); + if (control->HitTest((int)x, (int)y)) + { + hitControl = control; + node = wxTabLayerList::compatibility_iterator(); + node2 = wxList::compatibility_iterator(); + } + else + node2 = node2->GetNext(); + } + + if (node) + node = node->GetNext(); + } + + if (!hitControl) + return false; + + wxTabControl *currentTab = FindTabControlForId(m_tabSelection); + + if (hitControl == currentTab) + return false; + + ChangeTab(hitControl); + + return true; +} + +bool wxTabView::ChangeTab(wxTabControl *control) +{ + wxTabControl *currentTab = FindTabControlForId(m_tabSelection); + int oldTab = -1; + if (currentTab) + oldTab = currentTab->GetId(); + + if (control == currentTab) + return true; + + if (m_layers.GetCount() == 0) + return false; + + if (!OnTabPreActivate(control->GetId(), oldTab)) + return false; + + // Move the tab to the bottom + MoveSelectionTab(control); + + if (currentTab) + currentTab->SetSelected(false); + + control->SetSelected(true); + m_tabSelection = control->GetId(); + + OnTabActivate(control->GetId(), oldTab); + + // Leave window refresh for the implementing window + + return true; +} + +// Move the selected tab to the bottom layer, if necessary, +// without calling app activation code +bool wxTabView::MoveSelectionTab(wxTabControl *control) +{ + if (m_layers.GetCount() == 0) + return false; + + wxTabLayer *firstLayer = (wxTabLayer *)m_layers.GetFirst()->GetData(); + + // Find what column this tab is at, so we can swap with the one at the bottom. + // If we're on the bottom layer, then no need to swap. + if (!firstLayer->Member(control)) + { + // Do a swap + int col = 0; + wxList::compatibility_iterator thisNode = FindTabNodeAndColumn(control, &col); + if (!thisNode) + return false; + wxList::compatibility_iterator otherNode = firstLayer->Item(col); + if (!otherNode) + return false; + + // If this is already in the bottom layer, return now + if (otherNode == thisNode) + return true; + + wxTabControl *otherTab = (wxTabControl *)otherNode->GetData(); + + // We now have pointers to the tab to be changed to, + // and the tab on the first layer. Swap tab structures and + // position details. + + int thisX = control->GetX(); + int thisY = control->GetY(); + int thisColPos = control->GetColPosition(); + int otherX = otherTab->GetX(); + int otherY = otherTab->GetY(); + int otherColPos = otherTab->GetColPosition(); + + control->SetPosition(otherX, otherY); + control->SetColPosition(otherColPos); + otherTab->SetPosition(thisX, thisY); + otherTab->SetColPosition(thisColPos); + + // Swap the data for the nodes + thisNode->SetData(otherTab); + otherNode->SetData(control); + } + return true; +} + +// Called when a tab is activated +void wxTabView::OnTabActivate(int /*activateId*/, int /*deactivateId*/) +{ +} + +void wxTabView::SetHighlightColour(const wxColour& col) +{ + m_highlightColour = col; + m_highlightPen = wxThePenList->FindOrCreatePen(col, 1, wxSOLID); +} + +void wxTabView::SetShadowColour(const wxColour& col) +{ + m_shadowColour = col; + m_shadowPen = wxThePenList->FindOrCreatePen(col, 1, wxSOLID); +} + +void wxTabView::SetBackgroundColour(const wxColour& col) +{ + m_backgroundColour = col; + m_backgroundPen = wxThePenList->FindOrCreatePen(col, 1, wxSOLID); + m_backgroundBrush = wxTheBrushList->FindOrCreateBrush(col, wxSOLID); +} + +// this may be called with sel = zero (which doesn't match any page) +// when wxMotif deletes a page +// so return the first tab... + +void wxTabView::SetTabSelection(int sel, bool activateTool) +{ + if ( sel==m_tabSelection ) + return; + + int oldSel = m_tabSelection; + wxTabControl *control = FindTabControlForId(sel); + if (sel == 0) sel=control->GetId(); + wxTabControl *oldControl = FindTabControlForId(m_tabSelection); + + if (!OnTabPreActivate(sel, oldSel)) + return; + + if (control) + control->SetSelected((sel != -1)); // TODO ?? + else if (sel != -1) + { + wxFAIL_MSG(_("Could not find tab for id")); + return; + } + + if (oldControl) + oldControl->SetSelected(false); + + m_tabSelection = sel; + + if (control) + MoveSelectionTab(control); + + if (activateTool) + OnTabActivate(sel, oldSel); +} + +// Find tab control for id +// this may be called with zero (which doesn't match any page) +// so return the first control... +wxTabControl *wxTabView::FindTabControlForId(int id) const +{ + wxTabLayerList::compatibility_iterator node1 = m_layers.GetFirst(); + while (node1) + { + wxTabLayer *layer = (wxTabLayer *)node1->GetData(); + wxList::compatibility_iterator node2 = layer->GetFirst(); + while (node2) + { + wxTabControl *control = (wxTabControl *)node2->GetData(); + if (control->GetId() == id || id == 0) + return control; + node2 = node2->GetNext(); + } + node1 = node1->GetNext(); + } + return (wxTabControl *) NULL; +} + +// Find tab control for layer, position (starting from zero) +wxTabControl *wxTabView::FindTabControlForPosition(int layer, int position) const +{ + wxTabLayerList::compatibility_iterator node1 = m_layers.Item(layer); + if (!node1) + return (wxTabControl *) NULL; + wxTabLayer *tabLayer = (wxTabLayer *)node1->GetData(); + wxList::compatibility_iterator node2 = tabLayer->Item(position); + if (!node2) + return (wxTabControl *) NULL; + return (wxTabControl *)node2->GetData(); +} + +// Find the node and the column at which this control is positioned. +wxList::compatibility_iterator wxTabView::FindTabNodeAndColumn(wxTabControl *control, int *col) const +{ + wxTabLayerList::compatibility_iterator node1 = m_layers.GetFirst(); + while (node1) + { + wxTabLayer *layer = (wxTabLayer *)node1->GetData(); + int c = 0; + wxList::compatibility_iterator node2 = layer->GetFirst(); + while (node2) + { + wxTabControl *cnt = (wxTabControl *)node2->GetData(); + if (cnt == control) + { + *col = c; + return node2; + } + node2 = node2->GetNext(); + c ++; + } + node1 = node1->GetNext(); + } + return wxList::compatibility_iterator(); +} + +int wxTabView::CalculateTabWidth(int noTabs, bool adjustView) +{ + m_tabWidth = (int)((m_tabViewRect.width - ((noTabs - 1)*GetHorizontalTabSpacing()))/noTabs); + if (adjustView) + { + m_tabViewRect.width = noTabs*m_tabWidth + ((noTabs-1)*GetHorizontalTabSpacing()); + } + return m_tabWidth; +} + +/* + * wxTabbedDialog + */ + +IMPLEMENT_CLASS(wxTabbedDialog, wxDialog) + +BEGIN_EVENT_TABLE(wxTabbedDialog, wxDialog) + EVT_CLOSE(wxTabbedDialog::OnCloseWindow) + EVT_MOUSE_EVENTS(wxTabbedDialog::OnMouseEvent) + EVT_PAINT(wxTabbedDialog::OnPaint) +END_EVENT_TABLE() + +wxTabbedDialog::wxTabbedDialog(wxWindow *parent, wxWindowID id, + const wxString& title, + const wxPoint& pos, const wxSize& size, + long windowStyle, const wxString& name): + wxDialog(parent, id, title, pos, size, windowStyle, name) +{ + m_tabView = (wxTabView *) NULL; +} + +wxTabbedDialog::~wxTabbedDialog(void) +{ + if (m_tabView) + delete m_tabView; +} + +void wxTabbedDialog::OnCloseWindow(wxCloseEvent& WXUNUSED(event) ) +{ + Destroy(); +} + +void wxTabbedDialog::OnMouseEvent(wxMouseEvent& event ) +{ + if (m_tabView) + m_tabView->OnEvent(event); +} + +void wxTabbedDialog::OnPaint(wxPaintEvent& WXUNUSED(event) ) +{ + wxPaintDC dc(this); + if (m_tabView) + m_tabView->Draw(dc); +} + +/* + * wxTabbedPanel + */ + +IMPLEMENT_CLASS(wxTabbedPanel, wxPanel) + +BEGIN_EVENT_TABLE(wxTabbedPanel, wxPanel) + EVT_MOUSE_EVENTS(wxTabbedPanel::OnMouseEvent) + EVT_PAINT(wxTabbedPanel::OnPaint) +END_EVENT_TABLE() + +wxTabbedPanel::wxTabbedPanel(wxWindow *parent, wxWindowID id, const wxPoint& pos, + const wxSize& size, long windowStyle, const wxString& name): + wxPanel(parent, id, pos, size, windowStyle, name) +{ + m_tabView = (wxTabView *) NULL; +} + +wxTabbedPanel::~wxTabbedPanel(void) +{ + delete m_tabView; +} + +void wxTabbedPanel::OnMouseEvent(wxMouseEvent& event) +{ + if (m_tabView) + m_tabView->OnEvent(event); +} + +void wxTabbedPanel::OnPaint(wxPaintEvent& WXUNUSED(event) ) +{ + wxPaintDC dc(this); + if (m_tabView) + m_tabView->Draw(dc); +} + +/* + * wxPanelTabView + */ + +IMPLEMENT_CLASS(wxPanelTabView, wxTabView) + +wxPanelTabView::wxPanelTabView(wxPanel *pan, long style) + : wxTabView(style) +{ + m_panel = pan; + m_currentWindow = (wxWindow *) NULL; + + if (m_panel->IsKindOf(CLASSINFO(wxTabbedDialog))) + ((wxTabbedDialog *)m_panel)->SetTabView(this); + else if (m_panel->IsKindOf(CLASSINFO(wxTabbedPanel))) + ((wxTabbedPanel *)m_panel)->SetTabView(this); + + SetWindow(m_panel); +} + +wxPanelTabView::~wxPanelTabView(void) +{ + ClearWindows(true); +} + +// Called when a tab is activated +void wxPanelTabView::OnTabActivate(int activateId, int deactivateId) +{ + if (!m_panel) + return; + + wxWindow *oldWindow = ((deactivateId == -1) ? 0 : GetTabWindow(deactivateId)); + wxWindow *newWindow = GetTabWindow(activateId); + + if (oldWindow) + oldWindow->Show(false); + if (newWindow) + newWindow->Show(true); + + m_panel->Refresh(); +} + + +void wxPanelTabView::AddTabWindow(int id, wxWindow *window) +{ + wxASSERT(m_tabWindows.find(id) == m_tabWindows.end()); + m_tabWindows[id] = window; + window->Show(false); +} + +wxWindow *wxPanelTabView::GetTabWindow(int id) const +{ + wxIntToWindowHashMap::const_iterator it = m_tabWindows.find(id); + return it == m_tabWindows.end() ? NULL : it->second; +} + +void wxPanelTabView::ClearWindows(bool deleteWindows) +{ + if (deleteWindows) + WX_CLEAR_HASH_MAP(wxIntToWindowHashMap, m_tabWindows); + m_tabWindows.clear(); +} + +void wxPanelTabView::ShowWindowForTab(int id) +{ + wxWindow *newWindow = GetTabWindow(id); + if (newWindow == m_currentWindow) + return; + if (m_currentWindow) + m_currentWindow->Show(false); + newWindow->Show(true); + newWindow->Refresh(); +} + +#endif // wxUSE_TAB_DIALOG diff --git a/Externals/wxWidgets/src/generic/textdlgg.cpp b/Externals/wxWidgets/src/generic/textdlgg.cpp index f1c8aa64bc..c4de4b03d5 100644 --- a/Externals/wxWidgets/src/generic/textdlgg.cpp +++ b/Externals/wxWidgets/src/generic/textdlgg.cpp @@ -1,185 +1,185 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/generic/textdlgg.cpp -// Purpose: wxTextEntryDialog -// Author: Julian Smart -// Modified by: -// Created: 04/01/98 -// RCS-ID: $Id: textdlgg.cpp 41838 2006-10-09 21:08:45Z VZ $ -// Copyright: (c) Julian Smart -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_TEXTDLG - -#include "wx/generic/textdlgg.h" - -#ifndef WX_PRECOMP - #include "wx/utils.h" - #include "wx/dialog.h" - #include "wx/button.h" - #include "wx/stattext.h" - #include "wx/textctrl.h" - #include "wx/intl.h" - #include "wx/sizer.h" -#endif - -#if wxUSE_STATLINE - #include "wx/statline.h" -#endif - -const wxChar wxGetTextFromUserPromptStr[] = wxT("Input Text"); -const wxChar wxGetPasswordFromUserPromptStr[] = wxT("Enter Password"); - -// ---------------------------------------------------------------------------- -// constants -// ---------------------------------------------------------------------------- - -static const int wxID_TEXT = 3000; - -// ============================================================================ -// implementation -// ============================================================================ - -// ---------------------------------------------------------------------------- -// wxTextEntryDialog -// ---------------------------------------------------------------------------- - -BEGIN_EVENT_TABLE(wxTextEntryDialog, wxDialog) - EVT_BUTTON(wxID_OK, wxTextEntryDialog::OnOK) -END_EVENT_TABLE() - -IMPLEMENT_CLASS(wxTextEntryDialog, wxDialog) - -wxTextEntryDialog::wxTextEntryDialog(wxWindow *parent, - const wxString& message, - const wxString& caption, - const wxString& value, - long style, - const wxPoint& pos) - : wxDialog(parent, wxID_ANY, caption, pos, wxDefaultSize, - wxDEFAULT_DIALOG_STYLE), - m_value(value) -{ - m_dialogStyle = style; - m_value = value; - - wxBeginBusyCursor(); - - wxBoxSizer *topsizer = new wxBoxSizer( wxVERTICAL ); - - wxSizerFlags flagsBorder2; - flagsBorder2.DoubleBorder(); - -#if wxUSE_STATTEXT - // 1) text message - topsizer->Add(CreateTextSizer(message), flagsBorder2); -#endif - - // 2) text ctrl - m_textctrl = new wxTextCtrl(this, wxID_TEXT, value, - wxDefaultPosition, wxSize(300, wxDefaultCoord), - style & ~wxTextEntryDialogStyle); - - topsizer->Add(m_textctrl, - wxSizerFlags(style & wxTE_MULTILINE ? 1 : 0). - Expand(). - TripleBorder(wxLEFT | wxRIGHT)); - -#if wxUSE_VALIDATORS - wxTextValidator validator( wxFILTER_NONE, &m_value ); - m_textctrl->SetValidator( validator ); -#endif // wxUSE_VALIDATORS - - // 3) buttons if any - wxSizer *buttonSizer = CreateSeparatedButtonSizer(style & ButtonSizerFlags); - if ( buttonSizer ) - { - topsizer->Add(buttonSizer, wxSizerFlags(flagsBorder2).Expand()); - } - - SetAutoLayout( true ); - SetSizer( topsizer ); - - topsizer->SetSizeHints( this ); - topsizer->Fit( this ); - - if ( style & wxCENTRE ) - Centre( wxBOTH ); - - m_textctrl->SetSelection(-1, -1); - m_textctrl->SetFocus(); - - wxEndBusyCursor(); -} - -void wxTextEntryDialog::OnOK(wxCommandEvent& WXUNUSED(event) ) -{ -#if wxUSE_VALIDATORS - if( Validate() && TransferDataFromWindow() ) - { - EndModal( wxID_OK ); - } -#else - m_value = m_textctrl->GetValue(); - - EndModal(wxID_OK); -#endif - // wxUSE_VALIDATORS -} - -void wxTextEntryDialog::SetValue(const wxString& val) -{ - m_value = val; - - m_textctrl->SetValue(val); -} - -#if wxUSE_VALIDATORS -void wxTextEntryDialog::SetTextValidator( long style ) -{ - wxTextValidator validator( style, &m_value ); - m_textctrl->SetValidator( validator ); -} - -void wxTextEntryDialog::SetTextValidator( const wxTextValidator& validator ) -{ - m_textctrl->SetValidator( validator ); -} - -#endif - // wxUSE_VALIDATORS - -// ---------------------------------------------------------------------------- -// wxPasswordEntryDialog -// ---------------------------------------------------------------------------- - -IMPLEMENT_CLASS(wxPasswordEntryDialog, wxTextEntryDialog) - -wxPasswordEntryDialog::wxPasswordEntryDialog(wxWindow *parent, - const wxString& message, - const wxString& caption, - const wxString& value, - long style, - const wxPoint& pos) - : wxTextEntryDialog(parent, message, caption, value, - style | wxTE_PASSWORD, pos) -{ - // Only change from wxTextEntryDialog is the password style -} - -#endif // wxUSE_TEXTDLG +///////////////////////////////////////////////////////////////////////////// +// Name: src/generic/textdlgg.cpp +// Purpose: wxTextEntryDialog +// Author: Julian Smart +// Modified by: +// Created: 04/01/98 +// RCS-ID: $Id: textdlgg.cpp 41838 2006-10-09 21:08:45Z VZ $ +// Copyright: (c) Julian Smart +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_TEXTDLG + +#include "wx/generic/textdlgg.h" + +#ifndef WX_PRECOMP + #include "wx/utils.h" + #include "wx/dialog.h" + #include "wx/button.h" + #include "wx/stattext.h" + #include "wx/textctrl.h" + #include "wx/intl.h" + #include "wx/sizer.h" +#endif + +#if wxUSE_STATLINE + #include "wx/statline.h" +#endif + +const wxChar wxGetTextFromUserPromptStr[] = wxT("Input Text"); +const wxChar wxGetPasswordFromUserPromptStr[] = wxT("Enter Password"); + +// ---------------------------------------------------------------------------- +// constants +// ---------------------------------------------------------------------------- + +static const int wxID_TEXT = 3000; + +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// wxTextEntryDialog +// ---------------------------------------------------------------------------- + +BEGIN_EVENT_TABLE(wxTextEntryDialog, wxDialog) + EVT_BUTTON(wxID_OK, wxTextEntryDialog::OnOK) +END_EVENT_TABLE() + +IMPLEMENT_CLASS(wxTextEntryDialog, wxDialog) + +wxTextEntryDialog::wxTextEntryDialog(wxWindow *parent, + const wxString& message, + const wxString& caption, + const wxString& value, + long style, + const wxPoint& pos) + : wxDialog(parent, wxID_ANY, caption, pos, wxDefaultSize, + wxDEFAULT_DIALOG_STYLE), + m_value(value) +{ + m_dialogStyle = style; + m_value = value; + + wxBeginBusyCursor(); + + wxBoxSizer *topsizer = new wxBoxSizer( wxVERTICAL ); + + wxSizerFlags flagsBorder2; + flagsBorder2.DoubleBorder(); + +#if wxUSE_STATTEXT + // 1) text message + topsizer->Add(CreateTextSizer(message), flagsBorder2); +#endif + + // 2) text ctrl + m_textctrl = new wxTextCtrl(this, wxID_TEXT, value, + wxDefaultPosition, wxSize(300, wxDefaultCoord), + style & ~wxTextEntryDialogStyle); + + topsizer->Add(m_textctrl, + wxSizerFlags(style & wxTE_MULTILINE ? 1 : 0). + Expand(). + TripleBorder(wxLEFT | wxRIGHT)); + +#if wxUSE_VALIDATORS + wxTextValidator validator( wxFILTER_NONE, &m_value ); + m_textctrl->SetValidator( validator ); +#endif // wxUSE_VALIDATORS + + // 3) buttons if any + wxSizer *buttonSizer = CreateSeparatedButtonSizer(style & ButtonSizerFlags); + if ( buttonSizer ) + { + topsizer->Add(buttonSizer, wxSizerFlags(flagsBorder2).Expand()); + } + + SetAutoLayout( true ); + SetSizer( topsizer ); + + topsizer->SetSizeHints( this ); + topsizer->Fit( this ); + + if ( style & wxCENTRE ) + Centre( wxBOTH ); + + m_textctrl->SetSelection(-1, -1); + m_textctrl->SetFocus(); + + wxEndBusyCursor(); +} + +void wxTextEntryDialog::OnOK(wxCommandEvent& WXUNUSED(event) ) +{ +#if wxUSE_VALIDATORS + if( Validate() && TransferDataFromWindow() ) + { + EndModal( wxID_OK ); + } +#else + m_value = m_textctrl->GetValue(); + + EndModal(wxID_OK); +#endif + // wxUSE_VALIDATORS +} + +void wxTextEntryDialog::SetValue(const wxString& val) +{ + m_value = val; + + m_textctrl->SetValue(val); +} + +#if wxUSE_VALIDATORS +void wxTextEntryDialog::SetTextValidator( long style ) +{ + wxTextValidator validator( style, &m_value ); + m_textctrl->SetValidator( validator ); +} + +void wxTextEntryDialog::SetTextValidator( const wxTextValidator& validator ) +{ + m_textctrl->SetValidator( validator ); +} + +#endif + // wxUSE_VALIDATORS + +// ---------------------------------------------------------------------------- +// wxPasswordEntryDialog +// ---------------------------------------------------------------------------- + +IMPLEMENT_CLASS(wxPasswordEntryDialog, wxTextEntryDialog) + +wxPasswordEntryDialog::wxPasswordEntryDialog(wxWindow *parent, + const wxString& message, + const wxString& caption, + const wxString& value, + long style, + const wxPoint& pos) + : wxTextEntryDialog(parent, message, caption, value, + style | wxTE_PASSWORD, pos) +{ + // Only change from wxTextEntryDialog is the password style +} + +#endif // wxUSE_TEXTDLG diff --git a/Externals/wxWidgets/src/generic/timer.cpp b/Externals/wxWidgets/src/generic/timer.cpp index 1fad2018bd..706ed092cd 100644 --- a/Externals/wxWidgets/src/generic/timer.cpp +++ b/Externals/wxWidgets/src/generic/timer.cpp @@ -1,283 +1,283 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/generic/timer.cpp -// Purpose: wxTimer implementation -// Author: Vaclav Slavik -// Id: $Id: timer.cpp 40943 2006-08-31 19:31:43Z ABX $ -// Copyright: (c) Vaclav Slavik -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -// ---------------------------------------------------------------------------- -// NB: when using generic wxTimer implementation in your port, you *must* call -// wxTimer::NotifyTimers() often enough. The ideal place for this -// is in wxEventLoop::Dispatch(). -// ---------------------------------------------------------------------------- - -#if wxUSE_TIMER - -#include "wx/timer.h" - -#ifndef WX_PRECOMP - #include "wx/log.h" - #include "wx/module.h" -#endif - -// ---------------------------------------------------------------------------- -// Time input function -// ---------------------------------------------------------------------------- - -#ifdef __WXMGL__ - // We take advantage of wxMGL's _EVT_getTicks because it is faster - // (especially under MS-DOS!) and more precise than wxGetLocalTimeMillis - // if we are unlucky and the latter combines information from two sources. - #include "wx/mgl/private.h" - extern "C" ulong _EVT_getTicks(); - #define GetMillisecondsTime _EVT_getTicks - - typedef ulong wxTimerTick_t; - - #define wxTimerTickFmtSpec _T("lu") - #define wxTimerTickPrintfArg(tt) (tt) - - #ifdef __DOS__ - // Under DOS the MGL timer has a 24hr period, so consider the 12 hours - // before y to be 'less' and the the 12 hours after 'greater' modulo - // 24 hours. - inline bool wxTickGreaterEqual(wxTimerTick_t x, wxTimerTick_t y) - { - // _EVT_getTicks wraps at 1573040 * 55 - const wxTimerTick_t modulus = 1573040 * 55; - return (2 * modulus + x - y) % modulus < modulus / 2; - } - #else - // If wxTimerTick_t is 32-bits then it'll wrap in around 50 days. So - // let the 25 days before y be 'less' and 25 days after be 'greater'. - inline bool wxTickGreaterEqual(wxTimerTick_t x, wxTimerTick_t y) - { - // This code assumes wxTimerTick_t is an unsigned type. - // Set half_modulus with top bit set and the rest zeros. - const wxTimerTick_t half_modulus = ~((~(wxTimerTick_t)0) >> 1); - return x - y < half_modulus; - } - #endif -#else // !__WXMGL__ - #define GetMillisecondsTime wxGetLocalTimeMillis - - typedef wxLongLong wxTimerTick_t; - - #if wxUSE_LONGLONG_WX - #define wxTimerTickFmtSpec wxLongLongFmtSpec _T("d") - #define wxTimerTickPrintfArg(tt) (tt.GetValue()) - #else // using native wxLongLong - #define wxTimerTickFmtSpec _T("s") - #define wxTimerTickPrintfArg(tt) (tt.ToString().c_str()) - #endif // wx/native long long - - inline bool wxTickGreaterEqual(wxTimerTick_t x, wxTimerTick_t y) - { - return x >= y; - } -#endif // __WXMGL__/!__WXMGL__ - -// ---------------------------------------------------------------------------- -// helper structures and wxTimerScheduler -// ---------------------------------------------------------------------------- - -class wxTimerDesc -{ -public: - wxTimerDesc(wxTimer *t) : - timer(t), running(false), next(NULL), prev(NULL), - shotTime(0), deleteFlag(NULL) {} - - wxTimer *timer; - bool running; - wxTimerDesc *next, *prev; - wxTimerTick_t shotTime; - volatile bool *deleteFlag; // see comment in ~wxTimer -}; - -class wxTimerScheduler -{ -public: - wxTimerScheduler() : m_timers(NULL) {} - - void QueueTimer(wxTimerDesc *desc, wxTimerTick_t when = 0); - void RemoveTimer(wxTimerDesc *desc); - void NotifyTimers(); - -private: - wxTimerDesc *m_timers; -}; - -void wxTimerScheduler::QueueTimer(wxTimerDesc *desc, wxTimerTick_t when) -{ - if ( desc->running ) - return; // already scheduled - - if ( when == 0 ) - when = GetMillisecondsTime() + desc->timer->GetInterval(); - desc->shotTime = when; - desc->running = true; - - wxLogTrace( wxT("timer"), - wxT("queued timer %p at tick %") wxTimerTickFmtSpec, - desc->timer, wxTimerTickPrintfArg(when)); - - if ( m_timers ) - { - wxTimerDesc *d = m_timers; - while ( d->next && d->next->shotTime < when ) d = d->next; - desc->next = d->next; - desc->prev = d; - if ( d->next ) - d->next->prev = desc; - d->next = desc; - } - else - { - m_timers = desc; - desc->prev = desc->next = NULL; - } -} - -void wxTimerScheduler::RemoveTimer(wxTimerDesc *desc) -{ - desc->running = false; - if ( desc == m_timers ) - m_timers = desc->next; - if ( desc->prev ) - desc->prev->next = desc->next; - if ( desc->next ) - desc->next->prev = desc->prev; - desc->prev = desc->next = NULL; -} - -void wxTimerScheduler::NotifyTimers() -{ - if ( m_timers ) - { - bool oneShot; - volatile bool timerDeleted; - wxTimerTick_t now = GetMillisecondsTime(); - - for ( wxTimerDesc *desc = m_timers; desc; desc = desc->next ) - { - if ( desc->running && wxTickGreaterEqual(now, desc->shotTime) ) - { - oneShot = desc->timer->IsOneShot(); - RemoveTimer(desc); - - timerDeleted = false; - desc->deleteFlag = &timerDeleted; - desc->timer->Notify(); - - if ( !timerDeleted ) - { - wxLogTrace( wxT("timer"), - wxT("notified timer %p sheduled for %") - wxTimerTickFmtSpec, - desc->timer, - wxTimerTickPrintfArg(desc->shotTime) ); - - desc->deleteFlag = NULL; - if ( !oneShot ) - QueueTimer(desc, now + desc->timer->GetInterval()); - } - else - { - desc = m_timers; - if (!desc) - break; - } - } - } - } -} - - -// ---------------------------------------------------------------------------- -// wxTimer -// ---------------------------------------------------------------------------- - -IMPLEMENT_ABSTRACT_CLASS(wxTimer, wxEvtHandler) - -wxTimerScheduler *gs_scheduler = NULL; - -void wxTimer::Init() -{ - if ( !gs_scheduler ) - gs_scheduler = new wxTimerScheduler; - m_desc = new wxTimerDesc(this); -} - -wxTimer::~wxTimer() -{ - wxLogTrace( wxT("timer"), wxT("destroying timer %p..."), this); - if ( IsRunning() ) - Stop(); - - // NB: this is a hack: wxTimerScheduler must have some way of knowing - // that wxTimer object was deleted under its hands -- this may - // happen if somebody is really nasty and deletes the timer - // from wxTimer::Notify() - if ( m_desc->deleteFlag != NULL ) - *m_desc->deleteFlag = true; - - delete m_desc; - wxLogTrace( wxT("timer"), wxT(" ...done destroying timer %p..."), this); -} - -bool wxTimer::IsRunning() const -{ - return m_desc->running; -} - -bool wxTimer::Start(int millisecs, bool oneShot) -{ - wxLogTrace( wxT("timer"), wxT("started timer %p: %i ms, oneshot=%i"), - this, millisecs, oneShot); - - if ( !wxTimerBase::Start(millisecs, oneShot) ) - return false; - - gs_scheduler->QueueTimer(m_desc); - return true; -} - -void wxTimer::Stop() -{ - if ( !m_desc->running ) return; - - gs_scheduler->RemoveTimer(m_desc); -} - -/*static*/ void wxTimer::NotifyTimers() -{ - if ( gs_scheduler ) - gs_scheduler->NotifyTimers(); -} - - - -// A module to deallocate memory properly: -class wxTimerModule: public wxModule -{ -DECLARE_DYNAMIC_CLASS(wxTimerModule) -public: - wxTimerModule() {} - bool OnInit() { return true; } - void OnExit() { delete gs_scheduler; gs_scheduler = NULL; } -}; - -IMPLEMENT_DYNAMIC_CLASS(wxTimerModule, wxModule) - - -#endif //wxUSE_TIMER +///////////////////////////////////////////////////////////////////////////// +// Name: src/generic/timer.cpp +// Purpose: wxTimer implementation +// Author: Vaclav Slavik +// Id: $Id: timer.cpp 40943 2006-08-31 19:31:43Z ABX $ +// Copyright: (c) Vaclav Slavik +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +// ---------------------------------------------------------------------------- +// NB: when using generic wxTimer implementation in your port, you *must* call +// wxTimer::NotifyTimers() often enough. The ideal place for this +// is in wxEventLoop::Dispatch(). +// ---------------------------------------------------------------------------- + +#if wxUSE_TIMER + +#include "wx/timer.h" + +#ifndef WX_PRECOMP + #include "wx/log.h" + #include "wx/module.h" +#endif + +// ---------------------------------------------------------------------------- +// Time input function +// ---------------------------------------------------------------------------- + +#ifdef __WXMGL__ + // We take advantage of wxMGL's _EVT_getTicks because it is faster + // (especially under MS-DOS!) and more precise than wxGetLocalTimeMillis + // if we are unlucky and the latter combines information from two sources. + #include "wx/mgl/private.h" + extern "C" ulong _EVT_getTicks(); + #define GetMillisecondsTime _EVT_getTicks + + typedef ulong wxTimerTick_t; + + #define wxTimerTickFmtSpec _T("lu") + #define wxTimerTickPrintfArg(tt) (tt) + + #ifdef __DOS__ + // Under DOS the MGL timer has a 24hr period, so consider the 12 hours + // before y to be 'less' and the the 12 hours after 'greater' modulo + // 24 hours. + inline bool wxTickGreaterEqual(wxTimerTick_t x, wxTimerTick_t y) + { + // _EVT_getTicks wraps at 1573040 * 55 + const wxTimerTick_t modulus = 1573040 * 55; + return (2 * modulus + x - y) % modulus < modulus / 2; + } + #else + // If wxTimerTick_t is 32-bits then it'll wrap in around 50 days. So + // let the 25 days before y be 'less' and 25 days after be 'greater'. + inline bool wxTickGreaterEqual(wxTimerTick_t x, wxTimerTick_t y) + { + // This code assumes wxTimerTick_t is an unsigned type. + // Set half_modulus with top bit set and the rest zeros. + const wxTimerTick_t half_modulus = ~((~(wxTimerTick_t)0) >> 1); + return x - y < half_modulus; + } + #endif +#else // !__WXMGL__ + #define GetMillisecondsTime wxGetLocalTimeMillis + + typedef wxLongLong wxTimerTick_t; + + #if wxUSE_LONGLONG_WX + #define wxTimerTickFmtSpec wxLongLongFmtSpec _T("d") + #define wxTimerTickPrintfArg(tt) (tt.GetValue()) + #else // using native wxLongLong + #define wxTimerTickFmtSpec _T("s") + #define wxTimerTickPrintfArg(tt) (tt.ToString().c_str()) + #endif // wx/native long long + + inline bool wxTickGreaterEqual(wxTimerTick_t x, wxTimerTick_t y) + { + return x >= y; + } +#endif // __WXMGL__/!__WXMGL__ + +// ---------------------------------------------------------------------------- +// helper structures and wxTimerScheduler +// ---------------------------------------------------------------------------- + +class wxTimerDesc +{ +public: + wxTimerDesc(wxTimer *t) : + timer(t), running(false), next(NULL), prev(NULL), + shotTime(0), deleteFlag(NULL) {} + + wxTimer *timer; + bool running; + wxTimerDesc *next, *prev; + wxTimerTick_t shotTime; + volatile bool *deleteFlag; // see comment in ~wxTimer +}; + +class wxTimerScheduler +{ +public: + wxTimerScheduler() : m_timers(NULL) {} + + void QueueTimer(wxTimerDesc *desc, wxTimerTick_t when = 0); + void RemoveTimer(wxTimerDesc *desc); + void NotifyTimers(); + +private: + wxTimerDesc *m_timers; +}; + +void wxTimerScheduler::QueueTimer(wxTimerDesc *desc, wxTimerTick_t when) +{ + if ( desc->running ) + return; // already scheduled + + if ( when == 0 ) + when = GetMillisecondsTime() + desc->timer->GetInterval(); + desc->shotTime = when; + desc->running = true; + + wxLogTrace( wxT("timer"), + wxT("queued timer %p at tick %") wxTimerTickFmtSpec, + desc->timer, wxTimerTickPrintfArg(when)); + + if ( m_timers ) + { + wxTimerDesc *d = m_timers; + while ( d->next && d->next->shotTime < when ) d = d->next; + desc->next = d->next; + desc->prev = d; + if ( d->next ) + d->next->prev = desc; + d->next = desc; + } + else + { + m_timers = desc; + desc->prev = desc->next = NULL; + } +} + +void wxTimerScheduler::RemoveTimer(wxTimerDesc *desc) +{ + desc->running = false; + if ( desc == m_timers ) + m_timers = desc->next; + if ( desc->prev ) + desc->prev->next = desc->next; + if ( desc->next ) + desc->next->prev = desc->prev; + desc->prev = desc->next = NULL; +} + +void wxTimerScheduler::NotifyTimers() +{ + if ( m_timers ) + { + bool oneShot; + volatile bool timerDeleted; + wxTimerTick_t now = GetMillisecondsTime(); + + for ( wxTimerDesc *desc = m_timers; desc; desc = desc->next ) + { + if ( desc->running && wxTickGreaterEqual(now, desc->shotTime) ) + { + oneShot = desc->timer->IsOneShot(); + RemoveTimer(desc); + + timerDeleted = false; + desc->deleteFlag = &timerDeleted; + desc->timer->Notify(); + + if ( !timerDeleted ) + { + wxLogTrace( wxT("timer"), + wxT("notified timer %p sheduled for %") + wxTimerTickFmtSpec, + desc->timer, + wxTimerTickPrintfArg(desc->shotTime) ); + + desc->deleteFlag = NULL; + if ( !oneShot ) + QueueTimer(desc, now + desc->timer->GetInterval()); + } + else + { + desc = m_timers; + if (!desc) + break; + } + } + } + } +} + + +// ---------------------------------------------------------------------------- +// wxTimer +// ---------------------------------------------------------------------------- + +IMPLEMENT_ABSTRACT_CLASS(wxTimer, wxEvtHandler) + +wxTimerScheduler *gs_scheduler = NULL; + +void wxTimer::Init() +{ + if ( !gs_scheduler ) + gs_scheduler = new wxTimerScheduler; + m_desc = new wxTimerDesc(this); +} + +wxTimer::~wxTimer() +{ + wxLogTrace( wxT("timer"), wxT("destroying timer %p..."), this); + if ( IsRunning() ) + Stop(); + + // NB: this is a hack: wxTimerScheduler must have some way of knowing + // that wxTimer object was deleted under its hands -- this may + // happen if somebody is really nasty and deletes the timer + // from wxTimer::Notify() + if ( m_desc->deleteFlag != NULL ) + *m_desc->deleteFlag = true; + + delete m_desc; + wxLogTrace( wxT("timer"), wxT(" ...done destroying timer %p..."), this); +} + +bool wxTimer::IsRunning() const +{ + return m_desc->running; +} + +bool wxTimer::Start(int millisecs, bool oneShot) +{ + wxLogTrace( wxT("timer"), wxT("started timer %p: %i ms, oneshot=%i"), + this, millisecs, oneShot); + + if ( !wxTimerBase::Start(millisecs, oneShot) ) + return false; + + gs_scheduler->QueueTimer(m_desc); + return true; +} + +void wxTimer::Stop() +{ + if ( !m_desc->running ) return; + + gs_scheduler->RemoveTimer(m_desc); +} + +/*static*/ void wxTimer::NotifyTimers() +{ + if ( gs_scheduler ) + gs_scheduler->NotifyTimers(); +} + + + +// A module to deallocate memory properly: +class wxTimerModule: public wxModule +{ +DECLARE_DYNAMIC_CLASS(wxTimerModule) +public: + wxTimerModule() {} + bool OnInit() { return true; } + void OnExit() { delete gs_scheduler; gs_scheduler = NULL; } +}; + +IMPLEMENT_DYNAMIC_CLASS(wxTimerModule, wxModule) + + +#endif //wxUSE_TIMER diff --git a/Externals/wxWidgets/src/generic/tipdlg.cpp b/Externals/wxWidgets/src/generic/tipdlg.cpp index abb2232577..a64fee3a14 100644 --- a/Externals/wxWidgets/src/generic/tipdlg.cpp +++ b/Externals/wxWidgets/src/generic/tipdlg.cpp @@ -1,347 +1,347 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: src/generic/tipdlg.cpp -// Purpose: implementation of wxTipDialog -// Author: Vadim Zeitlin -// Modified by: -// Created: 28.06.99 -// RCS-ID: $Id: tipdlg.cpp 52000 2008-02-22 18:37:18Z VS $ -// Copyright: (c) Vadim Zeitlin -// Licence: wxWindows licence -/////////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_STARTUP_TIPS - -#ifndef WX_PRECOMP - #include "wx/button.h" - #include "wx/checkbox.h" - #include "wx/statbox.h" - #include "wx/dialog.h" - #include "wx/icon.h" - #include "wx/intl.h" - #include "wx/textctrl.h" - #include "wx/statbmp.h" - #include "wx/stattext.h" - #include "wx/sizer.h" - #include "wx/settings.h" -#endif // WX_PRECOMP - -#include "wx/statline.h" -#include "wx/artprov.h" - -#include "wx/tipdlg.h" - -// ---------------------------------------------------------------------------- -// constants -// ---------------------------------------------------------------------------- - -static const int wxID_NEXT_TIP = 32000; // whatever - -// --------------------------------------------------------------------------- -// macros -// --------------------------------------------------------------------------- - -/* Macro for avoiding #ifdefs when value have to be different depending on size of - device we display on - take it from something like wxDesktopPolicy in the future - */ - -#if defined(__SMARTPHONE__) - #define wxLARGESMALL(large,small) small -#else - #define wxLARGESMALL(large,small) large -#endif - -// ---------------------------------------------------------------------------- -// private classes -// ---------------------------------------------------------------------------- - -// an implementation which takes the tips from the text file - each line -// represents a tip -class WXDLLIMPEXP_ADV wxFileTipProvider : public wxTipProvider -{ -public: - wxFileTipProvider(const wxString& filename, size_t currentTip); - - virtual wxString GetTip(); - -private: - wxTextFile m_textfile; - - DECLARE_NO_COPY_CLASS(wxFileTipProvider) -}; - -#ifdef __WIN32__ -// TODO an implementation which takes the tips from the given registry key -class WXDLLIMPEXP_ADV wxRegTipProvider : public wxTipProvider -{ -public: - wxRegTipProvider(const wxString& keyname); - - virtual wxString GetTip(); -}; - -// Empty implementation for now to keep the linker happy -wxString wxRegTipProvider::GetTip() -{ - return wxEmptyString; -} - -#endif // __WIN32__ - -// the dialog we show in wxShowTip() -class WXDLLIMPEXP_ADV wxTipDialog : public wxDialog -{ -public: - wxTipDialog(wxWindow *parent, - wxTipProvider *tipProvider, - bool showAtStartup); - - // the tip dialog has "Show tips on startup" checkbox - return true if it - // was checked (or wasn't unchecked) - bool ShowTipsOnStartup() const { return m_checkbox->GetValue(); } - - // sets the (next) tip text - void SetTipText() { m_text->SetValue(m_tipProvider->GetTip()); } - - // "Next" button handler - void OnNextTip(wxCommandEvent& WXUNUSED(event)) { SetTipText(); } - -private: - wxTipProvider *m_tipProvider; - - wxTextCtrl *m_text; - wxCheckBox *m_checkbox; - - DECLARE_EVENT_TABLE() - DECLARE_NO_COPY_CLASS(wxTipDialog) -}; - -// ============================================================================ -// implementation -// ============================================================================ - -// ---------------------------------------------------------------------------- -// wxFileTipProvider -// ---------------------------------------------------------------------------- - -wxFileTipProvider::wxFileTipProvider(const wxString& filename, - size_t currentTip) - : wxTipProvider(currentTip), m_textfile(filename) -{ - m_textfile.Open(); -} - -wxString wxFileTipProvider::GetTip() -{ - size_t count = m_textfile.GetLineCount(); - if ( !count ) - { - return _("Tips not available, sorry!"); - } - - wxString tip; - - // Comments start with a # symbol. - // Loop reading lines until get the first one that isn't a comment. - // The max number of loop executions is the number of lines in the - // textfile so that can't go into an eternal loop in the [oddball] - // case of a comment-only tips file, or the developer has vetoed - // them all via PreprecessTip(). - for ( size_t i=0; i < count; i++ ) - { - // The current tip may be at the last line of the textfile, (or - // past it, if the number of lines in the textfile changed, such - // as changing to a different textfile, with less tips). So check - // to see at last line of text file, (or past it)... - if ( m_currentTip >= count ) - { - // .. and if so, wrap back to line 0. - m_currentTip = 0; - } - - // Read the tip, and increment the current tip counter. - tip = m_textfile.GetLine(m_currentTip++); - - // Allow a derived class's overrided virtual to modify the tip - // now if so desired. - tip = PreprocessTip(tip); - - // Break if tip isn't a comment, and isn't an empty string - // (or only stray space characters). - if ( !tip.StartsWith(wxT("#")) && (tip.Trim() != wxEmptyString) ) - { - break; - } - } - - // If tip starts with '_(', then it is a gettext string of format - // _("My \"global\" tip text") so first strip off the leading '_("'... - if ( tip.StartsWith(wxT("_(\"" ), &tip)) - { - //...and strip off the trailing '")'... - tip = tip.BeforeLast(wxT('\"')); - // ...and replace escaped quotes - tip.Replace(wxT("\\\""), wxT("\"")); - - // and translate it as requested - tip = wxGetTranslation(tip); - } - - return tip; -} - -// ---------------------------------------------------------------------------- -// wxTipDialog -// ---------------------------------------------------------------------------- - -BEGIN_EVENT_TABLE(wxTipDialog, wxDialog) - EVT_BUTTON(wxID_NEXT_TIP, wxTipDialog::OnNextTip) -END_EVENT_TABLE() - -wxTipDialog::wxTipDialog(wxWindow *parent, - wxTipProvider *tipProvider, - bool showAtStartup) - : wxDialog(parent, wxID_ANY, _("Tip of the Day"), - wxDefaultPosition, wxDefaultSize, - wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER - ) -{ - m_tipProvider = tipProvider; - bool isPda = (wxSystemSettings::GetScreenType() <= wxSYS_SCREEN_PDA); - - // 1) create all controls in tab order - - wxStaticText *text = new wxStaticText(this, wxID_ANY, _("Did you know...")); - - if (!isPda) - { - wxFont font = text->GetFont(); - font.SetPointSize(int(1.6 * font.GetPointSize())); - font.SetWeight(wxFONTWEIGHT_BOLD); - text->SetFont(font); - } - - m_text = new wxTextCtrl(this, wxID_ANY, wxEmptyString, - wxDefaultPosition, wxSize(200, 160), - wxTE_MULTILINE | - wxTE_READONLY | - wxTE_NO_VSCROLL | - wxTE_RICH2 | // a hack to get rid of vert scrollbar - wxDEFAULT_CONTROL_BORDER - ); -#if defined(__WXMSW__) - m_text->SetFont(wxFont(12, wxSWISS, wxNORMAL, wxNORMAL)); -#endif - -//#if defined(__WXPM__) - // - // The only way to get icons into an OS/2 static bitmap control - // -// wxBitmap vBitmap; - -// vBitmap.SetId(wxICON_TIP); // OS/2 specific bitmap method--OS/2 wxBitmaps all have an ID. -// // and for StatBmp's under OS/2 it MUST be a valid resource ID. -// -// wxStaticBitmap* bmp = new wxStaticBitmap(this, wxID_ANY, vBitmap); -// -//#else - - wxIcon icon = wxArtProvider::GetIcon(wxART_TIP, wxART_CMN_DIALOG); - wxStaticBitmap *bmp = new wxStaticBitmap(this, wxID_ANY, icon); - -//#endif - - m_checkbox = new wxCheckBox(this, wxID_ANY, _("&Show tips at startup")); - m_checkbox->SetValue(showAtStartup); - m_checkbox->SetFocus(); - - // smart phones does not support or do not waste space for wxButtons -#ifndef __SMARTPHONE__ - wxButton *btnNext = new wxButton(this, wxID_NEXT_TIP, _("&Next Tip")); -#endif - - // smart phones does not support or do not waste space for wxButtons -#ifndef __SMARTPHONE__ - wxButton *btnClose = new wxButton(this, wxID_CLOSE); - SetAffirmativeId(wxID_CLOSE); -#endif - - - // 2) put them in boxes - - wxBoxSizer *topsizer = new wxBoxSizer( wxVERTICAL ); - - wxBoxSizer *icon_text = new wxBoxSizer( wxHORIZONTAL ); - icon_text->Add( bmp, 0, wxCENTER ); - icon_text->Add( text, 1, wxCENTER | wxLEFT, wxLARGESMALL(20,0) ); - topsizer->Add( icon_text, 0, wxEXPAND | wxALL, wxLARGESMALL(10,0) ); - - topsizer->Add( m_text, 1, wxEXPAND | wxLEFT|wxRIGHT, wxLARGESMALL(10,0) ); - - wxBoxSizer *bottom = new wxBoxSizer( wxHORIZONTAL ); - if (isPda) - topsizer->Add( m_checkbox, 0, wxCENTER|wxTOP ); - else - bottom->Add( m_checkbox, 0, wxCENTER ); - - // smart phones does not support or do not waste space for wxButtons -#ifdef __SMARTPHONE__ - SetRightMenu(wxID_NEXT_TIP, _("Next")); - SetLeftMenu(wxID_CLOSE); -#else - if (!isPda) - bottom->Add( 10,10,1 ); - bottom->Add( btnNext, 0, wxCENTER | wxLEFT, wxLARGESMALL(10,0) ); - bottom->Add( btnClose, 0, wxCENTER | wxLEFT, wxLARGESMALL(10,0) ); -#endif - - if (isPda) - topsizer->Add( bottom, 0, wxCENTER | wxALL, 5 ); - else - topsizer->Add( bottom, 0, wxEXPAND | wxALL, wxLARGESMALL(10,0) ); - - SetTipText(); - - SetSizer( topsizer ); - - topsizer->SetSizeHints( this ); - topsizer->Fit( this ); - - Centre(wxBOTH | wxCENTER_FRAME); -} - -// ---------------------------------------------------------------------------- -// our public interface -// ---------------------------------------------------------------------------- - -wxTipProvider *wxCreateFileTipProvider(const wxString& filename, - size_t currentTip) -{ - return new wxFileTipProvider(filename, currentTip); -} - -bool wxShowTip(wxWindow *parent, - wxTipProvider *tipProvider, - bool showAtStartup) -{ - wxTipDialog dlg(parent, tipProvider, showAtStartup); - dlg.ShowModal(); - - return dlg.ShowTipsOnStartup(); -} - -#endif // wxUSE_STARTUP_TIPS +/////////////////////////////////////////////////////////////////////////////// +// Name: src/generic/tipdlg.cpp +// Purpose: implementation of wxTipDialog +// Author: Vadim Zeitlin +// Modified by: +// Created: 28.06.99 +// RCS-ID: $Id: tipdlg.cpp 52000 2008-02-22 18:37:18Z VS $ +// Copyright: (c) Vadim Zeitlin +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_STARTUP_TIPS + +#ifndef WX_PRECOMP + #include "wx/button.h" + #include "wx/checkbox.h" + #include "wx/statbox.h" + #include "wx/dialog.h" + #include "wx/icon.h" + #include "wx/intl.h" + #include "wx/textctrl.h" + #include "wx/statbmp.h" + #include "wx/stattext.h" + #include "wx/sizer.h" + #include "wx/settings.h" +#endif // WX_PRECOMP + +#include "wx/statline.h" +#include "wx/artprov.h" + +#include "wx/tipdlg.h" + +// ---------------------------------------------------------------------------- +// constants +// ---------------------------------------------------------------------------- + +static const int wxID_NEXT_TIP = 32000; // whatever + +// --------------------------------------------------------------------------- +// macros +// --------------------------------------------------------------------------- + +/* Macro for avoiding #ifdefs when value have to be different depending on size of + device we display on - take it from something like wxDesktopPolicy in the future + */ + +#if defined(__SMARTPHONE__) + #define wxLARGESMALL(large,small) small +#else + #define wxLARGESMALL(large,small) large +#endif + +// ---------------------------------------------------------------------------- +// private classes +// ---------------------------------------------------------------------------- + +// an implementation which takes the tips from the text file - each line +// represents a tip +class WXDLLIMPEXP_ADV wxFileTipProvider : public wxTipProvider +{ +public: + wxFileTipProvider(const wxString& filename, size_t currentTip); + + virtual wxString GetTip(); + +private: + wxTextFile m_textfile; + + DECLARE_NO_COPY_CLASS(wxFileTipProvider) +}; + +#ifdef __WIN32__ +// TODO an implementation which takes the tips from the given registry key +class WXDLLIMPEXP_ADV wxRegTipProvider : public wxTipProvider +{ +public: + wxRegTipProvider(const wxString& keyname); + + virtual wxString GetTip(); +}; + +// Empty implementation for now to keep the linker happy +wxString wxRegTipProvider::GetTip() +{ + return wxEmptyString; +} + +#endif // __WIN32__ + +// the dialog we show in wxShowTip() +class WXDLLIMPEXP_ADV wxTipDialog : public wxDialog +{ +public: + wxTipDialog(wxWindow *parent, + wxTipProvider *tipProvider, + bool showAtStartup); + + // the tip dialog has "Show tips on startup" checkbox - return true if it + // was checked (or wasn't unchecked) + bool ShowTipsOnStartup() const { return m_checkbox->GetValue(); } + + // sets the (next) tip text + void SetTipText() { m_text->SetValue(m_tipProvider->GetTip()); } + + // "Next" button handler + void OnNextTip(wxCommandEvent& WXUNUSED(event)) { SetTipText(); } + +private: + wxTipProvider *m_tipProvider; + + wxTextCtrl *m_text; + wxCheckBox *m_checkbox; + + DECLARE_EVENT_TABLE() + DECLARE_NO_COPY_CLASS(wxTipDialog) +}; + +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// wxFileTipProvider +// ---------------------------------------------------------------------------- + +wxFileTipProvider::wxFileTipProvider(const wxString& filename, + size_t currentTip) + : wxTipProvider(currentTip), m_textfile(filename) +{ + m_textfile.Open(); +} + +wxString wxFileTipProvider::GetTip() +{ + size_t count = m_textfile.GetLineCount(); + if ( !count ) + { + return _("Tips not available, sorry!"); + } + + wxString tip; + + // Comments start with a # symbol. + // Loop reading lines until get the first one that isn't a comment. + // The max number of loop executions is the number of lines in the + // textfile so that can't go into an eternal loop in the [oddball] + // case of a comment-only tips file, or the developer has vetoed + // them all via PreprecessTip(). + for ( size_t i=0; i < count; i++ ) + { + // The current tip may be at the last line of the textfile, (or + // past it, if the number of lines in the textfile changed, such + // as changing to a different textfile, with less tips). So check + // to see at last line of text file, (or past it)... + if ( m_currentTip >= count ) + { + // .. and if so, wrap back to line 0. + m_currentTip = 0; + } + + // Read the tip, and increment the current tip counter. + tip = m_textfile.GetLine(m_currentTip++); + + // Allow a derived class's overrided virtual to modify the tip + // now if so desired. + tip = PreprocessTip(tip); + + // Break if tip isn't a comment, and isn't an empty string + // (or only stray space characters). + if ( !tip.StartsWith(wxT("#")) && (tip.Trim() != wxEmptyString) ) + { + break; + } + } + + // If tip starts with '_(', then it is a gettext string of format + // _("My \"global\" tip text") so first strip off the leading '_("'... + if ( tip.StartsWith(wxT("_(\"" ), &tip)) + { + //...and strip off the trailing '")'... + tip = tip.BeforeLast(wxT('\"')); + // ...and replace escaped quotes + tip.Replace(wxT("\\\""), wxT("\"")); + + // and translate it as requested + tip = wxGetTranslation(tip); + } + + return tip; +} + +// ---------------------------------------------------------------------------- +// wxTipDialog +// ---------------------------------------------------------------------------- + +BEGIN_EVENT_TABLE(wxTipDialog, wxDialog) + EVT_BUTTON(wxID_NEXT_TIP, wxTipDialog::OnNextTip) +END_EVENT_TABLE() + +wxTipDialog::wxTipDialog(wxWindow *parent, + wxTipProvider *tipProvider, + bool showAtStartup) + : wxDialog(parent, wxID_ANY, _("Tip of the Day"), + wxDefaultPosition, wxDefaultSize, + wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER + ) +{ + m_tipProvider = tipProvider; + bool isPda = (wxSystemSettings::GetScreenType() <= wxSYS_SCREEN_PDA); + + // 1) create all controls in tab order + + wxStaticText *text = new wxStaticText(this, wxID_ANY, _("Did you know...")); + + if (!isPda) + { + wxFont font = text->GetFont(); + font.SetPointSize(int(1.6 * font.GetPointSize())); + font.SetWeight(wxFONTWEIGHT_BOLD); + text->SetFont(font); + } + + m_text = new wxTextCtrl(this, wxID_ANY, wxEmptyString, + wxDefaultPosition, wxSize(200, 160), + wxTE_MULTILINE | + wxTE_READONLY | + wxTE_NO_VSCROLL | + wxTE_RICH2 | // a hack to get rid of vert scrollbar + wxDEFAULT_CONTROL_BORDER + ); +#if defined(__WXMSW__) + m_text->SetFont(wxFont(12, wxSWISS, wxNORMAL, wxNORMAL)); +#endif + +//#if defined(__WXPM__) + // + // The only way to get icons into an OS/2 static bitmap control + // +// wxBitmap vBitmap; + +// vBitmap.SetId(wxICON_TIP); // OS/2 specific bitmap method--OS/2 wxBitmaps all have an ID. +// // and for StatBmp's under OS/2 it MUST be a valid resource ID. +// +// wxStaticBitmap* bmp = new wxStaticBitmap(this, wxID_ANY, vBitmap); +// +//#else + + wxIcon icon = wxArtProvider::GetIcon(wxART_TIP, wxART_CMN_DIALOG); + wxStaticBitmap *bmp = new wxStaticBitmap(this, wxID_ANY, icon); + +//#endif + + m_checkbox = new wxCheckBox(this, wxID_ANY, _("&Show tips at startup")); + m_checkbox->SetValue(showAtStartup); + m_checkbox->SetFocus(); + + // smart phones does not support or do not waste space for wxButtons +#ifndef __SMARTPHONE__ + wxButton *btnNext = new wxButton(this, wxID_NEXT_TIP, _("&Next Tip")); +#endif + + // smart phones does not support or do not waste space for wxButtons +#ifndef __SMARTPHONE__ + wxButton *btnClose = new wxButton(this, wxID_CLOSE); + SetAffirmativeId(wxID_CLOSE); +#endif + + + // 2) put them in boxes + + wxBoxSizer *topsizer = new wxBoxSizer( wxVERTICAL ); + + wxBoxSizer *icon_text = new wxBoxSizer( wxHORIZONTAL ); + icon_text->Add( bmp, 0, wxCENTER ); + icon_text->Add( text, 1, wxCENTER | wxLEFT, wxLARGESMALL(20,0) ); + topsizer->Add( icon_text, 0, wxEXPAND | wxALL, wxLARGESMALL(10,0) ); + + topsizer->Add( m_text, 1, wxEXPAND | wxLEFT|wxRIGHT, wxLARGESMALL(10,0) ); + + wxBoxSizer *bottom = new wxBoxSizer( wxHORIZONTAL ); + if (isPda) + topsizer->Add( m_checkbox, 0, wxCENTER|wxTOP ); + else + bottom->Add( m_checkbox, 0, wxCENTER ); + + // smart phones does not support or do not waste space for wxButtons +#ifdef __SMARTPHONE__ + SetRightMenu(wxID_NEXT_TIP, _("Next")); + SetLeftMenu(wxID_CLOSE); +#else + if (!isPda) + bottom->Add( 10,10,1 ); + bottom->Add( btnNext, 0, wxCENTER | wxLEFT, wxLARGESMALL(10,0) ); + bottom->Add( btnClose, 0, wxCENTER | wxLEFT, wxLARGESMALL(10,0) ); +#endif + + if (isPda) + topsizer->Add( bottom, 0, wxCENTER | wxALL, 5 ); + else + topsizer->Add( bottom, 0, wxEXPAND | wxALL, wxLARGESMALL(10,0) ); + + SetTipText(); + + SetSizer( topsizer ); + + topsizer->SetSizeHints( this ); + topsizer->Fit( this ); + + Centre(wxBOTH | wxCENTER_FRAME); +} + +// ---------------------------------------------------------------------------- +// our public interface +// ---------------------------------------------------------------------------- + +wxTipProvider *wxCreateFileTipProvider(const wxString& filename, + size_t currentTip) +{ + return new wxFileTipProvider(filename, currentTip); +} + +bool wxShowTip(wxWindow *parent, + wxTipProvider *tipProvider, + bool showAtStartup) +{ + wxTipDialog dlg(parent, tipProvider, showAtStartup); + dlg.ShowModal(); + + return dlg.ShowTipsOnStartup(); +} + +#endif // wxUSE_STARTUP_TIPS diff --git a/Externals/wxWidgets/src/generic/tipwin.cpp b/Externals/wxWidgets/src/generic/tipwin.cpp index 0f2f2bb184..b24bcf8ef8 100644 --- a/Externals/wxWidgets/src/generic/tipwin.cpp +++ b/Externals/wxWidgets/src/generic/tipwin.cpp @@ -1,380 +1,380 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: src/generic/tipwin.cpp -// Purpose: implementation of wxTipWindow -// Author: Vadim Zeitlin -// Modified by: -// Created: 10.09.00 -// RCS-ID: $Id: tipwin.cpp 43033 2006-11-04 13:31:10Z VZ $ -// Copyright: (c) 2000 Vadim Zeitlin -// Licence: wxWindows licence -/////////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx/wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_TIPWINDOW - -#include "wx/tipwin.h" - -#ifndef WX_PRECOMP - #include "wx/dcclient.h" - #include "wx/timer.h" - #include "wx/settings.h" -#endif // WX_PRECOMP - -// ---------------------------------------------------------------------------- -// constants -// ---------------------------------------------------------------------------- - -static const wxCoord TEXT_MARGIN_X = 3; -static const wxCoord TEXT_MARGIN_Y = 3; - -// ---------------------------------------------------------------------------- -// wxTipWindowView -// ---------------------------------------------------------------------------- - -// Viewer window to put in the frame -class WXDLLEXPORT wxTipWindowView : public wxWindow -{ -public: - wxTipWindowView(wxWindow *parent); - - // event handlers - void OnPaint(wxPaintEvent& event); - void OnMouseClick(wxMouseEvent& event); - void OnMouseMove(wxMouseEvent& event); - -#if !wxUSE_POPUPWIN - void OnKillFocus(wxFocusEvent& event); -#endif // wxUSE_POPUPWIN - - // calculate the client rect we need to display the text - void Adjust(const wxString& text, wxCoord maxLength); - -private: - wxTipWindow* m_parent; - -#if !wxUSE_POPUPWIN - long m_creationTime; -#endif // !wxUSE_POPUPWIN - - DECLARE_EVENT_TABLE() - DECLARE_NO_COPY_CLASS(wxTipWindowView) -}; - -// ============================================================================ -// implementation -// ============================================================================ - -// ---------------------------------------------------------------------------- -// event tables -// ---------------------------------------------------------------------------- - -BEGIN_EVENT_TABLE(wxTipWindow, wxTipWindowBase) - EVT_LEFT_DOWN(wxTipWindow::OnMouseClick) - EVT_RIGHT_DOWN(wxTipWindow::OnMouseClick) - EVT_MIDDLE_DOWN(wxTipWindow::OnMouseClick) - -#if !wxUSE_POPUPWIN - EVT_KILL_FOCUS(wxTipWindow::OnKillFocus) - EVT_ACTIVATE(wxTipWindow::OnActivate) -#endif // !wxUSE_POPUPWIN -END_EVENT_TABLE() - -BEGIN_EVENT_TABLE(wxTipWindowView, wxWindow) - EVT_PAINT(wxTipWindowView::OnPaint) - - EVT_LEFT_DOWN(wxTipWindowView::OnMouseClick) - EVT_RIGHT_DOWN(wxTipWindowView::OnMouseClick) - EVT_MIDDLE_DOWN(wxTipWindowView::OnMouseClick) - - EVT_MOTION(wxTipWindowView::OnMouseMove) - -#if !wxUSE_POPUPWIN - EVT_KILL_FOCUS(wxTipWindowView::OnKillFocus) -#endif // !wxUSE_POPUPWIN -END_EVENT_TABLE() - -// ---------------------------------------------------------------------------- -// wxTipWindow -// ---------------------------------------------------------------------------- - -wxTipWindow::wxTipWindow(wxWindow *parent, - const wxString& text, - wxCoord maxLength, - wxTipWindow** windowPtr, - wxRect *rectBounds) -#if wxUSE_POPUPWIN - : wxPopupTransientWindow(parent) -#else - : wxFrame(parent, wxID_ANY, wxEmptyString, - wxDefaultPosition, wxDefaultSize, - wxNO_BORDER | wxFRAME_NO_TASKBAR ) -#endif -{ - SetTipWindowPtr(windowPtr); - if ( rectBounds ) - { - SetBoundingRect(*rectBounds); - } - - // set colours - SetForegroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_INFOTEXT)); - SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_INFOBK)); - - // set size, position and show it - m_view = new wxTipWindowView(this); - m_view->Adjust(text, maxLength); - m_view->SetFocus(); - - int x, y; - wxGetMousePosition(&x, &y); - - // we want to show the tip below the mouse, not over it - // - // NB: the reason we use "/ 2" here is that we don't know where the current - // cursors hot spot is... it would be nice if we could find this out - // though - y += wxSystemSettings::GetMetric(wxSYS_CURSOR_Y) / 2; - -#if wxUSE_POPUPWIN - Position(wxPoint(x, y), wxSize(0,0)); - Popup(m_view); - #ifdef __WXGTK__ - m_view->CaptureMouse(); - #endif -#else - Move(x, y); - Show(true); -#endif -} - -wxTipWindow::~wxTipWindow() -{ - if ( m_windowPtr ) - { - *m_windowPtr = NULL; - } - #ifdef wxUSE_POPUPWIN - #ifdef __WXGTK__ - if ( m_view->HasCapture() ) - m_view->ReleaseMouse(); - #endif - #endif -} - -void wxTipWindow::OnMouseClick(wxMouseEvent& WXUNUSED(event)) -{ - Close(); -} - -#if wxUSE_POPUPWIN - -void wxTipWindow::OnDismiss() -{ - Close(); -} - -#else // !wxUSE_POPUPWIN - -void wxTipWindow::OnActivate(wxActivateEvent& event) -{ - if (!event.GetActive()) - Close(); -} - -void wxTipWindow::OnKillFocus(wxFocusEvent& WXUNUSED(event)) -{ - // Under Windows at least, we will get this immediately - // because when the view window is focussed, the - // tip window goes out of focus. -#ifdef __WXGTK__ - Close(); -#endif -} - -#endif // wxUSE_POPUPWIN // !wxUSE_POPUPWIN - -void wxTipWindow::SetBoundingRect(const wxRect& rectBound) -{ - m_rectBound = rectBound; -} - -void wxTipWindow::Close() -{ - if ( m_windowPtr ) - { - *m_windowPtr = NULL; - m_windowPtr = NULL; - } - -#if wxUSE_POPUPWIN - Show(false); - #ifdef __WXGTK__ - if ( m_view->HasCapture() ) - m_view->ReleaseMouse(); - #endif - Destroy(); -#else - wxFrame::Close(); -#endif -} - -// ---------------------------------------------------------------------------- -// wxTipWindowView -// ---------------------------------------------------------------------------- - -wxTipWindowView::wxTipWindowView(wxWindow *parent) - : wxWindow(parent, wxID_ANY, - wxDefaultPosition, wxDefaultSize, - wxNO_BORDER) -{ - // set colours - SetForegroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_INFOTEXT)); - SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_INFOBK)); - -#if !wxUSE_POPUPWIN - m_creationTime = wxGetLocalTime(); -#endif // !wxUSE_POPUPWIN - - m_parent = (wxTipWindow*)parent; -} - -void wxTipWindowView::Adjust(const wxString& text, wxCoord maxLength) -{ - wxClientDC dc(this); - dc.SetFont(GetFont()); - - // calculate the length: we want each line be no longer than maxLength - // pixels and we only break lines at words boundary - wxString current; - wxCoord height, width, - widthMax = 0; - m_parent->m_heightLine = 0; - - bool breakLine = false; - for ( const wxChar *p = text.c_str(); ; p++ ) - { - if ( *p == _T('\n') || *p == _T('\0') ) - { - dc.GetTextExtent(current, &width, &height); - if ( width > widthMax ) - widthMax = width; - - if ( height > m_parent->m_heightLine ) - m_parent->m_heightLine = height; - - m_parent->m_textLines.Add(current); - - if ( !*p ) - { - // end of text - break; - } - - current.clear(); - breakLine = false; - } - else if ( breakLine && (*p == _T(' ') || *p == _T('\t')) ) - { - // word boundary - break the line here - m_parent->m_textLines.Add(current); - current.clear(); - breakLine = false; - } - else // line goes on - { - current += *p; - dc.GetTextExtent(current, &width, &height); - if ( width > maxLength ) - breakLine = true; - - if ( width > widthMax ) - widthMax = width; - - if ( height > m_parent->m_heightLine ) - m_parent->m_heightLine = height; - } - } - - // take into account the border size and the margins - width = 2*(TEXT_MARGIN_X + 1) + widthMax; - height = 2*(TEXT_MARGIN_Y + 1) + wx_truncate_cast(wxCoord, m_parent->m_textLines.GetCount())*m_parent->m_heightLine; - m_parent->SetClientSize(width, height); - SetSize(0, 0, width, height); -} - -void wxTipWindowView::OnPaint(wxPaintEvent& WXUNUSED(event)) -{ - wxPaintDC dc(this); - - wxRect rect; - wxSize size = GetClientSize(); - rect.width = size.x; - rect.height = size.y; - - // first filll the background - dc.SetBrush(wxBrush(GetBackgroundColour(), wxSOLID)); - dc.SetPen( wxPen(GetForegroundColour(), 1, wxSOLID) ); - dc.DrawRectangle(rect); - - // and then draw the text line by line - dc.SetTextBackground(GetBackgroundColour()); - dc.SetTextForeground(GetForegroundColour()); - dc.SetFont(GetFont()); - - wxPoint pt; - pt.x = TEXT_MARGIN_X; - pt.y = TEXT_MARGIN_Y; - size_t count = m_parent->m_textLines.GetCount(); - for ( size_t n = 0; n < count; n++ ) - { - dc.DrawText(m_parent->m_textLines[n], pt); - - pt.y += m_parent->m_heightLine; - } -} - -void wxTipWindowView::OnMouseClick(wxMouseEvent& WXUNUSED(event)) -{ - m_parent->Close(); -} - -void wxTipWindowView::OnMouseMove(wxMouseEvent& event) -{ - const wxRect& rectBound = m_parent->m_rectBound; - - if ( rectBound.width && - !rectBound.Contains(ClientToScreen(event.GetPosition())) ) - { - // mouse left the bounding rect, disappear - m_parent->Close(); - } - else - { - event.Skip(); - } -} - -#if !wxUSE_POPUPWIN -void wxTipWindowView::OnKillFocus(wxFocusEvent& WXUNUSED(event)) -{ - // Workaround the kill focus event happening just after creation in wxGTK - if (wxGetLocalTime() > m_creationTime + 1) - m_parent->Close(); -} -#endif // !wxUSE_POPUPWIN - -#endif // wxUSE_TIPWINDOW +/////////////////////////////////////////////////////////////////////////////// +// Name: src/generic/tipwin.cpp +// Purpose: implementation of wxTipWindow +// Author: Vadim Zeitlin +// Modified by: +// Created: 10.09.00 +// RCS-ID: $Id: tipwin.cpp 43033 2006-11-04 13:31:10Z VZ $ +// Copyright: (c) 2000 Vadim Zeitlin +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx/wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_TIPWINDOW + +#include "wx/tipwin.h" + +#ifndef WX_PRECOMP + #include "wx/dcclient.h" + #include "wx/timer.h" + #include "wx/settings.h" +#endif // WX_PRECOMP + +// ---------------------------------------------------------------------------- +// constants +// ---------------------------------------------------------------------------- + +static const wxCoord TEXT_MARGIN_X = 3; +static const wxCoord TEXT_MARGIN_Y = 3; + +// ---------------------------------------------------------------------------- +// wxTipWindowView +// ---------------------------------------------------------------------------- + +// Viewer window to put in the frame +class WXDLLEXPORT wxTipWindowView : public wxWindow +{ +public: + wxTipWindowView(wxWindow *parent); + + // event handlers + void OnPaint(wxPaintEvent& event); + void OnMouseClick(wxMouseEvent& event); + void OnMouseMove(wxMouseEvent& event); + +#if !wxUSE_POPUPWIN + void OnKillFocus(wxFocusEvent& event); +#endif // wxUSE_POPUPWIN + + // calculate the client rect we need to display the text + void Adjust(const wxString& text, wxCoord maxLength); + +private: + wxTipWindow* m_parent; + +#if !wxUSE_POPUPWIN + long m_creationTime; +#endif // !wxUSE_POPUPWIN + + DECLARE_EVENT_TABLE() + DECLARE_NO_COPY_CLASS(wxTipWindowView) +}; + +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// event tables +// ---------------------------------------------------------------------------- + +BEGIN_EVENT_TABLE(wxTipWindow, wxTipWindowBase) + EVT_LEFT_DOWN(wxTipWindow::OnMouseClick) + EVT_RIGHT_DOWN(wxTipWindow::OnMouseClick) + EVT_MIDDLE_DOWN(wxTipWindow::OnMouseClick) + +#if !wxUSE_POPUPWIN + EVT_KILL_FOCUS(wxTipWindow::OnKillFocus) + EVT_ACTIVATE(wxTipWindow::OnActivate) +#endif // !wxUSE_POPUPWIN +END_EVENT_TABLE() + +BEGIN_EVENT_TABLE(wxTipWindowView, wxWindow) + EVT_PAINT(wxTipWindowView::OnPaint) + + EVT_LEFT_DOWN(wxTipWindowView::OnMouseClick) + EVT_RIGHT_DOWN(wxTipWindowView::OnMouseClick) + EVT_MIDDLE_DOWN(wxTipWindowView::OnMouseClick) + + EVT_MOTION(wxTipWindowView::OnMouseMove) + +#if !wxUSE_POPUPWIN + EVT_KILL_FOCUS(wxTipWindowView::OnKillFocus) +#endif // !wxUSE_POPUPWIN +END_EVENT_TABLE() + +// ---------------------------------------------------------------------------- +// wxTipWindow +// ---------------------------------------------------------------------------- + +wxTipWindow::wxTipWindow(wxWindow *parent, + const wxString& text, + wxCoord maxLength, + wxTipWindow** windowPtr, + wxRect *rectBounds) +#if wxUSE_POPUPWIN + : wxPopupTransientWindow(parent) +#else + : wxFrame(parent, wxID_ANY, wxEmptyString, + wxDefaultPosition, wxDefaultSize, + wxNO_BORDER | wxFRAME_NO_TASKBAR ) +#endif +{ + SetTipWindowPtr(windowPtr); + if ( rectBounds ) + { + SetBoundingRect(*rectBounds); + } + + // set colours + SetForegroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_INFOTEXT)); + SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_INFOBK)); + + // set size, position and show it + m_view = new wxTipWindowView(this); + m_view->Adjust(text, maxLength); + m_view->SetFocus(); + + int x, y; + wxGetMousePosition(&x, &y); + + // we want to show the tip below the mouse, not over it + // + // NB: the reason we use "/ 2" here is that we don't know where the current + // cursors hot spot is... it would be nice if we could find this out + // though + y += wxSystemSettings::GetMetric(wxSYS_CURSOR_Y) / 2; + +#if wxUSE_POPUPWIN + Position(wxPoint(x, y), wxSize(0,0)); + Popup(m_view); + #ifdef __WXGTK__ + m_view->CaptureMouse(); + #endif +#else + Move(x, y); + Show(true); +#endif +} + +wxTipWindow::~wxTipWindow() +{ + if ( m_windowPtr ) + { + *m_windowPtr = NULL; + } + #ifdef wxUSE_POPUPWIN + #ifdef __WXGTK__ + if ( m_view->HasCapture() ) + m_view->ReleaseMouse(); + #endif + #endif +} + +void wxTipWindow::OnMouseClick(wxMouseEvent& WXUNUSED(event)) +{ + Close(); +} + +#if wxUSE_POPUPWIN + +void wxTipWindow::OnDismiss() +{ + Close(); +} + +#else // !wxUSE_POPUPWIN + +void wxTipWindow::OnActivate(wxActivateEvent& event) +{ + if (!event.GetActive()) + Close(); +} + +void wxTipWindow::OnKillFocus(wxFocusEvent& WXUNUSED(event)) +{ + // Under Windows at least, we will get this immediately + // because when the view window is focussed, the + // tip window goes out of focus. +#ifdef __WXGTK__ + Close(); +#endif +} + +#endif // wxUSE_POPUPWIN // !wxUSE_POPUPWIN + +void wxTipWindow::SetBoundingRect(const wxRect& rectBound) +{ + m_rectBound = rectBound; +} + +void wxTipWindow::Close() +{ + if ( m_windowPtr ) + { + *m_windowPtr = NULL; + m_windowPtr = NULL; + } + +#if wxUSE_POPUPWIN + Show(false); + #ifdef __WXGTK__ + if ( m_view->HasCapture() ) + m_view->ReleaseMouse(); + #endif + Destroy(); +#else + wxFrame::Close(); +#endif +} + +// ---------------------------------------------------------------------------- +// wxTipWindowView +// ---------------------------------------------------------------------------- + +wxTipWindowView::wxTipWindowView(wxWindow *parent) + : wxWindow(parent, wxID_ANY, + wxDefaultPosition, wxDefaultSize, + wxNO_BORDER) +{ + // set colours + SetForegroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_INFOTEXT)); + SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_INFOBK)); + +#if !wxUSE_POPUPWIN + m_creationTime = wxGetLocalTime(); +#endif // !wxUSE_POPUPWIN + + m_parent = (wxTipWindow*)parent; +} + +void wxTipWindowView::Adjust(const wxString& text, wxCoord maxLength) +{ + wxClientDC dc(this); + dc.SetFont(GetFont()); + + // calculate the length: we want each line be no longer than maxLength + // pixels and we only break lines at words boundary + wxString current; + wxCoord height, width, + widthMax = 0; + m_parent->m_heightLine = 0; + + bool breakLine = false; + for ( const wxChar *p = text.c_str(); ; p++ ) + { + if ( *p == _T('\n') || *p == _T('\0') ) + { + dc.GetTextExtent(current, &width, &height); + if ( width > widthMax ) + widthMax = width; + + if ( height > m_parent->m_heightLine ) + m_parent->m_heightLine = height; + + m_parent->m_textLines.Add(current); + + if ( !*p ) + { + // end of text + break; + } + + current.clear(); + breakLine = false; + } + else if ( breakLine && (*p == _T(' ') || *p == _T('\t')) ) + { + // word boundary - break the line here + m_parent->m_textLines.Add(current); + current.clear(); + breakLine = false; + } + else // line goes on + { + current += *p; + dc.GetTextExtent(current, &width, &height); + if ( width > maxLength ) + breakLine = true; + + if ( width > widthMax ) + widthMax = width; + + if ( height > m_parent->m_heightLine ) + m_parent->m_heightLine = height; + } + } + + // take into account the border size and the margins + width = 2*(TEXT_MARGIN_X + 1) + widthMax; + height = 2*(TEXT_MARGIN_Y + 1) + wx_truncate_cast(wxCoord, m_parent->m_textLines.GetCount())*m_parent->m_heightLine; + m_parent->SetClientSize(width, height); + SetSize(0, 0, width, height); +} + +void wxTipWindowView::OnPaint(wxPaintEvent& WXUNUSED(event)) +{ + wxPaintDC dc(this); + + wxRect rect; + wxSize size = GetClientSize(); + rect.width = size.x; + rect.height = size.y; + + // first filll the background + dc.SetBrush(wxBrush(GetBackgroundColour(), wxSOLID)); + dc.SetPen( wxPen(GetForegroundColour(), 1, wxSOLID) ); + dc.DrawRectangle(rect); + + // and then draw the text line by line + dc.SetTextBackground(GetBackgroundColour()); + dc.SetTextForeground(GetForegroundColour()); + dc.SetFont(GetFont()); + + wxPoint pt; + pt.x = TEXT_MARGIN_X; + pt.y = TEXT_MARGIN_Y; + size_t count = m_parent->m_textLines.GetCount(); + for ( size_t n = 0; n < count; n++ ) + { + dc.DrawText(m_parent->m_textLines[n], pt); + + pt.y += m_parent->m_heightLine; + } +} + +void wxTipWindowView::OnMouseClick(wxMouseEvent& WXUNUSED(event)) +{ + m_parent->Close(); +} + +void wxTipWindowView::OnMouseMove(wxMouseEvent& event) +{ + const wxRect& rectBound = m_parent->m_rectBound; + + if ( rectBound.width && + !rectBound.Contains(ClientToScreen(event.GetPosition())) ) + { + // mouse left the bounding rect, disappear + m_parent->Close(); + } + else + { + event.Skip(); + } +} + +#if !wxUSE_POPUPWIN +void wxTipWindowView::OnKillFocus(wxFocusEvent& WXUNUSED(event)) +{ + // Workaround the kill focus event happening just after creation in wxGTK + if (wxGetLocalTime() > m_creationTime + 1) + m_parent->Close(); +} +#endif // !wxUSE_POPUPWIN + +#endif // wxUSE_TIPWINDOW diff --git a/Externals/wxWidgets/src/generic/toolbkg.cpp b/Externals/wxWidgets/src/generic/toolbkg.cpp index fa3bbdf97f..36a2afaf2a 100644 --- a/Externals/wxWidgets/src/generic/toolbkg.cpp +++ b/Externals/wxWidgets/src/generic/toolbkg.cpp @@ -1,442 +1,442 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: src/generic/toolbkg.cpp -// Purpose: generic implementation of wxToolbook -// Author: Julian Smart -// Modified by: -// Created: 2006-01-29 -// RCS-ID: $Id: toolbkg.cpp 44271 2007-01-21 00:52:05Z VZ $ -// Copyright: (c) 2006 Julian Smart -// Licence: wxWindows licence -/////////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_TOOLBOOK - -#ifndef WX_PRECOMP - #include "wx/icon.h" - #include "wx/settings.h" - #include "wx/toolbar.h" -#endif - -#include "wx/imaglist.h" -#include "wx/sysopt.h" -#include "wx/toolbook.h" - -#if defined(__WXMAC__) && wxUSE_TOOLBAR && wxUSE_BMPBUTTON -#include "wx/generic/buttonbar.h" -#endif - -// ---------------------------------------------------------------------------- -// various wxWidgets macros -// ---------------------------------------------------------------------------- - -// check that the page index is valid -#define IS_VALID_PAGE(nPage) ((nPage) < GetPageCount()) - -// ---------------------------------------------------------------------------- -// event table -// ---------------------------------------------------------------------------- - -IMPLEMENT_DYNAMIC_CLASS(wxToolbook, wxBookCtrlBase) -IMPLEMENT_DYNAMIC_CLASS(wxToolbookEvent, wxNotifyEvent) - -#if !WXWIN_COMPATIBILITY_EVENT_TYPES -const wxEventType wxEVT_COMMAND_TOOLBOOK_PAGE_CHANGING = wxNewEventType(); -const wxEventType wxEVT_COMMAND_TOOLBOOK_PAGE_CHANGED = wxNewEventType(); -#endif - -BEGIN_EVENT_TABLE(wxToolbook, wxBookCtrlBase) - EVT_SIZE(wxToolbook::OnSize) - EVT_TOOL_RANGE(1, 50, wxToolbook::OnToolSelected) - EVT_IDLE(wxToolbook::OnIdle) -END_EVENT_TABLE() - -// ============================================================================ -// wxToolbook implementation -// ============================================================================ - -// ---------------------------------------------------------------------------- -// wxToolbook creation -// ---------------------------------------------------------------------------- - -void wxToolbook::Init() -{ - m_selection = wxNOT_FOUND; - m_needsRealizing = false; -} - -bool wxToolbook::Create(wxWindow *parent, - wxWindowID id, - const wxPoint& pos, - const wxSize& size, - long style, - const wxString& name) -{ - if ( (style & wxBK_ALIGN_MASK) == wxBK_DEFAULT ) - style |= wxBK_TOP; - - // no border for this control - style &= ~wxBORDER_MASK; - style |= wxBORDER_NONE; - - if ( !wxControl::Create(parent, id, pos, size, style, - wxDefaultValidator, name) ) - return false; - - int orient = wxTB_HORIZONTAL; - if ( (style & (wxBK_LEFT | wxBK_RIGHT)) != 0) - orient = wxTB_VERTICAL; - - // TODO: make more configurable - -#if defined(__WXMAC__) && wxUSE_TOOLBAR && wxUSE_BMPBUTTON - if (style & wxBK_BUTTONBAR) - { - m_bookctrl = new wxButtonToolBar - ( - this, - wxID_ANY, - wxDefaultPosition, - wxDefaultSize, - orient|wxTB_TEXT|wxTB_FLAT|wxNO_BORDER - ); - } - else -#endif - { - m_bookctrl = new wxToolBar - ( - this, - wxID_ANY, - wxDefaultPosition, - wxDefaultSize, - orient|wxTB_TEXT|wxTB_FLAT|wxTB_NODIVIDER|wxNO_BORDER - ); - } - - return true; -} - -// ---------------------------------------------------------------------------- -// wxToolbook geometry management -// ---------------------------------------------------------------------------- - -wxSize wxToolbook::GetControllerSize() const -{ - const wxSize sizeClient = GetClientSize(), - sizeBorder = m_bookctrl->GetSize() - m_bookctrl->GetClientSize(), - sizeToolBar = GetToolBar()->GetSize() + sizeBorder; - - wxSize size; - - if ( IsVertical() ) - { - size.x = sizeClient.x; - size.y = sizeToolBar.y; - } - else // left/right aligned - { - size.x = sizeToolBar.x; - size.y = sizeClient.y; - } - - return size; -} - -void wxToolbook::OnSize(wxSizeEvent& event) -{ - if (m_needsRealizing) - Realize(); - - wxBookCtrlBase::OnSize(event); -} - -wxSize wxToolbook::CalcSizeFromPage(const wxSize& sizePage) const -{ - // we need to add the size of the list control and the border between - const wxSize sizeToolBar = GetControllerSize(); - - wxSize size = sizePage; - if ( IsVertical() ) - { - size.y += sizeToolBar.y + GetInternalBorder(); - } - else // left/right aligned - { - size.x += sizeToolBar.x + GetInternalBorder(); - } - - return size; -} - -// ---------------------------------------------------------------------------- -// accessing the pages -// ---------------------------------------------------------------------------- - -bool wxToolbook::SetPageText(size_t n, const wxString& strText) -{ - // Assume tool ids start from 1 - wxToolBarToolBase* tool = GetToolBar()->FindById(n + 1); - if (tool) - { - tool->SetLabel(strText); - return true; - } - else - return false; -} - -wxString wxToolbook::GetPageText(size_t n) const -{ - wxToolBarToolBase* tool = GetToolBar()->FindById(n + 1); - if (tool) - return tool->GetLabel(); - else - return wxEmptyString; -} - -int wxToolbook::GetPageImage(size_t WXUNUSED(n)) const -{ - wxFAIL_MSG( _T("wxToolbook::GetPageImage() not implemented") ); - - return wxNOT_FOUND; -} - -bool wxToolbook::SetPageImage(size_t n, int imageId) -{ - wxASSERT( GetImageList() != NULL ); - if (!GetImageList()) - return false; - - wxToolBarToolBase* tool = GetToolBar()->FindById(n + 1); - if (tool) - { - // Find the image list index for this tool - wxBitmap bitmap = GetImageList()->GetBitmap(imageId); - tool->SetNormalBitmap(bitmap); - return true; - } - else - return false; -} - -// ---------------------------------------------------------------------------- -// image list stuff -// ---------------------------------------------------------------------------- - -void wxToolbook::SetImageList(wxImageList *imageList) -{ - wxBookCtrlBase::SetImageList(imageList); -} - -// ---------------------------------------------------------------------------- -// selection -// ---------------------------------------------------------------------------- - -int wxToolbook::GetSelection() const -{ - return m_selection; -} - -wxBookCtrlBaseEvent* wxToolbook::CreatePageChangingEvent() const -{ - return new wxToolbookEvent(wxEVT_COMMAND_TOOLBOOK_PAGE_CHANGING, m_windowId); -} - -void wxToolbook::MakeChangedEvent(wxBookCtrlBaseEvent &event) -{ - event.SetEventType(wxEVT_COMMAND_TOOLBOOK_PAGE_CHANGED); -} - -void wxToolbook::UpdateSelectedPage(size_t newsel) -{ - m_selection = newsel; - GetToolBar()->ToggleTool(newsel + 1, true); -} - -// Not part of the wxBookctrl API, but must be called in OnIdle or -// by application to realize the toolbar and select the initial page. -void wxToolbook::Realize() -{ - if (m_needsRealizing) - { - GetToolBar()->SetToolBitmapSize(m_maxBitmapSize); - - int remap = wxSystemOptions::GetOptionInt(wxT("msw.remap")); - wxSystemOptions::SetOption(wxT("msw.remap"), 0); - GetToolBar()->Realize(); - wxSystemOptions::SetOption(wxT("msw.remap"), remap); - } - - m_needsRealizing = false; - - if (m_selection == -1) - m_selection = 0; - - if (GetPageCount() > 0) - { - int sel = m_selection; - m_selection = -1; - SetSelection(sel); - } - - DoSize(); -} - -int wxToolbook::HitTest(const wxPoint& pt, long *flags) const -{ - int pagePos = wxNOT_FOUND; - - if ( flags ) - *flags = wxBK_HITTEST_NOWHERE; - - // convert from wxToolbook coordinates to wxToolBar ones - const wxToolBarBase * const tbar = GetToolBar(); - const wxPoint tbarPt = tbar->ScreenToClient(ClientToScreen(pt)); - - // is the point over the toolbar? - if ( wxRect(tbar->GetSize()).Contains(tbarPt) ) - { - const wxToolBarToolBase * const - tool = tbar->FindToolForPosition(tbarPt.x, tbarPt.y); - - if ( tool ) - { - pagePos = tbar->GetToolPos(tool->GetId()); - if ( flags ) - *flags = wxBK_HITTEST_ONICON | wxBK_HITTEST_ONLABEL; - } - } - else // not over the toolbar - { - if ( flags && GetPageRect().Contains(pt) ) - *flags |= wxBK_HITTEST_ONPAGE; - } - - return pagePos; -} - -void wxToolbook::OnIdle(wxIdleEvent& event) -{ - if (m_needsRealizing) - Realize(); - event.Skip(); -} - -// ---------------------------------------------------------------------------- -// adding/removing the pages -// ---------------------------------------------------------------------------- - -bool wxToolbook::InsertPage(size_t n, - wxWindow *page, - const wxString& text, - bool bSelect, - int imageId) -{ - if ( !wxBookCtrlBase::InsertPage(n, page, text, bSelect, imageId) ) - return false; - - m_needsRealizing = true; - - wxASSERT(GetImageList() != NULL); - - if (!GetImageList()) - return false; - - // TODO: make sure all platforms can convert between icon and bitmap, - // and/or test whether the image is a bitmap or an icon. -#ifdef __WXMAC__ - wxBitmap bitmap = GetImageList()->GetBitmap(imageId); -#else - // On Windows, we can lose information by using GetBitmap, so extract icon instead - wxIcon icon = GetImageList()->GetIcon(imageId); - wxBitmap bitmap; - bitmap.CopyFromIcon(icon); -#endif - - m_maxBitmapSize.x = wxMax(bitmap.GetWidth(), m_maxBitmapSize.x); - m_maxBitmapSize.y = wxMax(bitmap.GetHeight(), m_maxBitmapSize.y); - - GetToolBar()->SetToolBitmapSize(m_maxBitmapSize); - GetToolBar()->AddRadioTool(n + 1, text, bitmap, wxNullBitmap, text); - - if (bSelect) - { - GetToolBar()->ToggleTool(n, true); - m_selection = n; - } - else - page->Hide(); - - InvalidateBestSize(); - return true; -} - -wxWindow *wxToolbook::DoRemovePage(size_t page) -{ - const size_t page_count = GetPageCount(); - wxWindow *win = wxBookCtrlBase::DoRemovePage(page); - - if ( win ) - { - GetToolBar()->DeleteTool(page + 1); - - if (m_selection >= (int)page) - { - // force new sel valid if possible - int sel = m_selection - 1; - if (page_count == 1) - sel = wxNOT_FOUND; - else if ((page_count == 2) || (sel == -1)) - sel = 0; - - // force sel invalid if deleting current page - don't try to hide it - m_selection = (m_selection == (int)page) ? wxNOT_FOUND : m_selection - 1; - - if ((sel != wxNOT_FOUND) && (sel != m_selection)) - SetSelection(sel); - } - } - - return win; -} - - -bool wxToolbook::DeleteAllPages() -{ - GetToolBar()->ClearTools(); - return wxBookCtrlBase::DeleteAllPages(); -} - -// ---------------------------------------------------------------------------- -// wxToolbook events -// ---------------------------------------------------------------------------- - -void wxToolbook::OnToolSelected(wxCommandEvent& event) -{ - const int selNew = event.GetId() - 1; - - if ( selNew == m_selection ) - { - // this event can only come from our own Select(m_selection) below - // which we call when the page change is vetoed, so we should simply - // ignore it - return; - } - - SetSelection(selNew); - - // change wasn't allowed, return to previous state - if (m_selection != selNew) - { - GetToolBar()->ToggleTool(m_selection, false); - } -} - -#endif // wxUSE_TOOLBOOK +/////////////////////////////////////////////////////////////////////////////// +// Name: src/generic/toolbkg.cpp +// Purpose: generic implementation of wxToolbook +// Author: Julian Smart +// Modified by: +// Created: 2006-01-29 +// RCS-ID: $Id: toolbkg.cpp 44271 2007-01-21 00:52:05Z VZ $ +// Copyright: (c) 2006 Julian Smart +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_TOOLBOOK + +#ifndef WX_PRECOMP + #include "wx/icon.h" + #include "wx/settings.h" + #include "wx/toolbar.h" +#endif + +#include "wx/imaglist.h" +#include "wx/sysopt.h" +#include "wx/toolbook.h" + +#if defined(__WXMAC__) && wxUSE_TOOLBAR && wxUSE_BMPBUTTON +#include "wx/generic/buttonbar.h" +#endif + +// ---------------------------------------------------------------------------- +// various wxWidgets macros +// ---------------------------------------------------------------------------- + +// check that the page index is valid +#define IS_VALID_PAGE(nPage) ((nPage) < GetPageCount()) + +// ---------------------------------------------------------------------------- +// event table +// ---------------------------------------------------------------------------- + +IMPLEMENT_DYNAMIC_CLASS(wxToolbook, wxBookCtrlBase) +IMPLEMENT_DYNAMIC_CLASS(wxToolbookEvent, wxNotifyEvent) + +#if !WXWIN_COMPATIBILITY_EVENT_TYPES +const wxEventType wxEVT_COMMAND_TOOLBOOK_PAGE_CHANGING = wxNewEventType(); +const wxEventType wxEVT_COMMAND_TOOLBOOK_PAGE_CHANGED = wxNewEventType(); +#endif + +BEGIN_EVENT_TABLE(wxToolbook, wxBookCtrlBase) + EVT_SIZE(wxToolbook::OnSize) + EVT_TOOL_RANGE(1, 50, wxToolbook::OnToolSelected) + EVT_IDLE(wxToolbook::OnIdle) +END_EVENT_TABLE() + +// ============================================================================ +// wxToolbook implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// wxToolbook creation +// ---------------------------------------------------------------------------- + +void wxToolbook::Init() +{ + m_selection = wxNOT_FOUND; + m_needsRealizing = false; +} + +bool wxToolbook::Create(wxWindow *parent, + wxWindowID id, + const wxPoint& pos, + const wxSize& size, + long style, + const wxString& name) +{ + if ( (style & wxBK_ALIGN_MASK) == wxBK_DEFAULT ) + style |= wxBK_TOP; + + // no border for this control + style &= ~wxBORDER_MASK; + style |= wxBORDER_NONE; + + if ( !wxControl::Create(parent, id, pos, size, style, + wxDefaultValidator, name) ) + return false; + + int orient = wxTB_HORIZONTAL; + if ( (style & (wxBK_LEFT | wxBK_RIGHT)) != 0) + orient = wxTB_VERTICAL; + + // TODO: make more configurable + +#if defined(__WXMAC__) && wxUSE_TOOLBAR && wxUSE_BMPBUTTON + if (style & wxBK_BUTTONBAR) + { + m_bookctrl = new wxButtonToolBar + ( + this, + wxID_ANY, + wxDefaultPosition, + wxDefaultSize, + orient|wxTB_TEXT|wxTB_FLAT|wxNO_BORDER + ); + } + else +#endif + { + m_bookctrl = new wxToolBar + ( + this, + wxID_ANY, + wxDefaultPosition, + wxDefaultSize, + orient|wxTB_TEXT|wxTB_FLAT|wxTB_NODIVIDER|wxNO_BORDER + ); + } + + return true; +} + +// ---------------------------------------------------------------------------- +// wxToolbook geometry management +// ---------------------------------------------------------------------------- + +wxSize wxToolbook::GetControllerSize() const +{ + const wxSize sizeClient = GetClientSize(), + sizeBorder = m_bookctrl->GetSize() - m_bookctrl->GetClientSize(), + sizeToolBar = GetToolBar()->GetSize() + sizeBorder; + + wxSize size; + + if ( IsVertical() ) + { + size.x = sizeClient.x; + size.y = sizeToolBar.y; + } + else // left/right aligned + { + size.x = sizeToolBar.x; + size.y = sizeClient.y; + } + + return size; +} + +void wxToolbook::OnSize(wxSizeEvent& event) +{ + if (m_needsRealizing) + Realize(); + + wxBookCtrlBase::OnSize(event); +} + +wxSize wxToolbook::CalcSizeFromPage(const wxSize& sizePage) const +{ + // we need to add the size of the list control and the border between + const wxSize sizeToolBar = GetControllerSize(); + + wxSize size = sizePage; + if ( IsVertical() ) + { + size.y += sizeToolBar.y + GetInternalBorder(); + } + else // left/right aligned + { + size.x += sizeToolBar.x + GetInternalBorder(); + } + + return size; +} + +// ---------------------------------------------------------------------------- +// accessing the pages +// ---------------------------------------------------------------------------- + +bool wxToolbook::SetPageText(size_t n, const wxString& strText) +{ + // Assume tool ids start from 1 + wxToolBarToolBase* tool = GetToolBar()->FindById(n + 1); + if (tool) + { + tool->SetLabel(strText); + return true; + } + else + return false; +} + +wxString wxToolbook::GetPageText(size_t n) const +{ + wxToolBarToolBase* tool = GetToolBar()->FindById(n + 1); + if (tool) + return tool->GetLabel(); + else + return wxEmptyString; +} + +int wxToolbook::GetPageImage(size_t WXUNUSED(n)) const +{ + wxFAIL_MSG( _T("wxToolbook::GetPageImage() not implemented") ); + + return wxNOT_FOUND; +} + +bool wxToolbook::SetPageImage(size_t n, int imageId) +{ + wxASSERT( GetImageList() != NULL ); + if (!GetImageList()) + return false; + + wxToolBarToolBase* tool = GetToolBar()->FindById(n + 1); + if (tool) + { + // Find the image list index for this tool + wxBitmap bitmap = GetImageList()->GetBitmap(imageId); + tool->SetNormalBitmap(bitmap); + return true; + } + else + return false; +} + +// ---------------------------------------------------------------------------- +// image list stuff +// ---------------------------------------------------------------------------- + +void wxToolbook::SetImageList(wxImageList *imageList) +{ + wxBookCtrlBase::SetImageList(imageList); +} + +// ---------------------------------------------------------------------------- +// selection +// ---------------------------------------------------------------------------- + +int wxToolbook::GetSelection() const +{ + return m_selection; +} + +wxBookCtrlBaseEvent* wxToolbook::CreatePageChangingEvent() const +{ + return new wxToolbookEvent(wxEVT_COMMAND_TOOLBOOK_PAGE_CHANGING, m_windowId); +} + +void wxToolbook::MakeChangedEvent(wxBookCtrlBaseEvent &event) +{ + event.SetEventType(wxEVT_COMMAND_TOOLBOOK_PAGE_CHANGED); +} + +void wxToolbook::UpdateSelectedPage(size_t newsel) +{ + m_selection = newsel; + GetToolBar()->ToggleTool(newsel + 1, true); +} + +// Not part of the wxBookctrl API, but must be called in OnIdle or +// by application to realize the toolbar and select the initial page. +void wxToolbook::Realize() +{ + if (m_needsRealizing) + { + GetToolBar()->SetToolBitmapSize(m_maxBitmapSize); + + int remap = wxSystemOptions::GetOptionInt(wxT("msw.remap")); + wxSystemOptions::SetOption(wxT("msw.remap"), 0); + GetToolBar()->Realize(); + wxSystemOptions::SetOption(wxT("msw.remap"), remap); + } + + m_needsRealizing = false; + + if (m_selection == -1) + m_selection = 0; + + if (GetPageCount() > 0) + { + int sel = m_selection; + m_selection = -1; + SetSelection(sel); + } + + DoSize(); +} + +int wxToolbook::HitTest(const wxPoint& pt, long *flags) const +{ + int pagePos = wxNOT_FOUND; + + if ( flags ) + *flags = wxBK_HITTEST_NOWHERE; + + // convert from wxToolbook coordinates to wxToolBar ones + const wxToolBarBase * const tbar = GetToolBar(); + const wxPoint tbarPt = tbar->ScreenToClient(ClientToScreen(pt)); + + // is the point over the toolbar? + if ( wxRect(tbar->GetSize()).Contains(tbarPt) ) + { + const wxToolBarToolBase * const + tool = tbar->FindToolForPosition(tbarPt.x, tbarPt.y); + + if ( tool ) + { + pagePos = tbar->GetToolPos(tool->GetId()); + if ( flags ) + *flags = wxBK_HITTEST_ONICON | wxBK_HITTEST_ONLABEL; + } + } + else // not over the toolbar + { + if ( flags && GetPageRect().Contains(pt) ) + *flags |= wxBK_HITTEST_ONPAGE; + } + + return pagePos; +} + +void wxToolbook::OnIdle(wxIdleEvent& event) +{ + if (m_needsRealizing) + Realize(); + event.Skip(); +} + +// ---------------------------------------------------------------------------- +// adding/removing the pages +// ---------------------------------------------------------------------------- + +bool wxToolbook::InsertPage(size_t n, + wxWindow *page, + const wxString& text, + bool bSelect, + int imageId) +{ + if ( !wxBookCtrlBase::InsertPage(n, page, text, bSelect, imageId) ) + return false; + + m_needsRealizing = true; + + wxASSERT(GetImageList() != NULL); + + if (!GetImageList()) + return false; + + // TODO: make sure all platforms can convert between icon and bitmap, + // and/or test whether the image is a bitmap or an icon. +#ifdef __WXMAC__ + wxBitmap bitmap = GetImageList()->GetBitmap(imageId); +#else + // On Windows, we can lose information by using GetBitmap, so extract icon instead + wxIcon icon = GetImageList()->GetIcon(imageId); + wxBitmap bitmap; + bitmap.CopyFromIcon(icon); +#endif + + m_maxBitmapSize.x = wxMax(bitmap.GetWidth(), m_maxBitmapSize.x); + m_maxBitmapSize.y = wxMax(bitmap.GetHeight(), m_maxBitmapSize.y); + + GetToolBar()->SetToolBitmapSize(m_maxBitmapSize); + GetToolBar()->AddRadioTool(n + 1, text, bitmap, wxNullBitmap, text); + + if (bSelect) + { + GetToolBar()->ToggleTool(n, true); + m_selection = n; + } + else + page->Hide(); + + InvalidateBestSize(); + return true; +} + +wxWindow *wxToolbook::DoRemovePage(size_t page) +{ + const size_t page_count = GetPageCount(); + wxWindow *win = wxBookCtrlBase::DoRemovePage(page); + + if ( win ) + { + GetToolBar()->DeleteTool(page + 1); + + if (m_selection >= (int)page) + { + // force new sel valid if possible + int sel = m_selection - 1; + if (page_count == 1) + sel = wxNOT_FOUND; + else if ((page_count == 2) || (sel == -1)) + sel = 0; + + // force sel invalid if deleting current page - don't try to hide it + m_selection = (m_selection == (int)page) ? wxNOT_FOUND : m_selection - 1; + + if ((sel != wxNOT_FOUND) && (sel != m_selection)) + SetSelection(sel); + } + } + + return win; +} + + +bool wxToolbook::DeleteAllPages() +{ + GetToolBar()->ClearTools(); + return wxBookCtrlBase::DeleteAllPages(); +} + +// ---------------------------------------------------------------------------- +// wxToolbook events +// ---------------------------------------------------------------------------- + +void wxToolbook::OnToolSelected(wxCommandEvent& event) +{ + const int selNew = event.GetId() - 1; + + if ( selNew == m_selection ) + { + // this event can only come from our own Select(m_selection) below + // which we call when the page change is vetoed, so we should simply + // ignore it + return; + } + + SetSelection(selNew); + + // change wasn't allowed, return to previous state + if (m_selection != selNew) + { + GetToolBar()->ToggleTool(m_selection, false); + } +} + +#endif // wxUSE_TOOLBOOK diff --git a/Externals/wxWidgets/src/generic/treebkg.cpp b/Externals/wxWidgets/src/generic/treebkg.cpp index a1c59ed03d..0f3501594c 100644 --- a/Externals/wxWidgets/src/generic/treebkg.cpp +++ b/Externals/wxWidgets/src/generic/treebkg.cpp @@ -1,791 +1,791 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: src/generic/treebkg.cpp -// Purpose: generic implementation of wxTreebook -// Author: Evgeniy Tarassov, Vadim Zeitlin -// Modified by: -// Created: 2005-09-15 -// RCS-ID: $Id: treebkg.cpp 44271 2007-01-21 00:52:05Z VZ $ -// Copyright: (c) 2005 Vadim Zeitlin -// Licence: wxWindows licence -/////////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_TREEBOOK - -#include "wx/treebook.h" - -#ifndef WX_PRECOMP - #include "wx/settings.h" -#endif - -#include "wx/imaglist.h" - -// ---------------------------------------------------------------------------- -// various wxWidgets macros -// ---------------------------------------------------------------------------- - -// check that the page index is valid -#define IS_VALID_PAGE(nPage) ((nPage) < DoInternalGetPageCount()) - -// ---------------------------------------------------------------------------- -// event table -// ---------------------------------------------------------------------------- - -IMPLEMENT_DYNAMIC_CLASS(wxTreebook, wxBookCtrlBase) -IMPLEMENT_DYNAMIC_CLASS(wxTreebookEvent, wxNotifyEvent) - -#if !WXWIN_COMPATIBILITY_EVENT_TYPES -const wxEventType wxEVT_COMMAND_TREEBOOK_PAGE_CHANGING = wxNewEventType(); -const wxEventType wxEVT_COMMAND_TREEBOOK_PAGE_CHANGED = wxNewEventType(); -const wxEventType wxEVT_COMMAND_TREEBOOK_NODE_COLLAPSED = wxNewEventType(); -const wxEventType wxEVT_COMMAND_TREEBOOK_NODE_EXPANDED = wxNewEventType(); -#endif - -BEGIN_EVENT_TABLE(wxTreebook, wxBookCtrlBase) - EVT_TREE_SEL_CHANGED (wxID_ANY, wxTreebook::OnTreeSelectionChange) - EVT_TREE_ITEM_EXPANDED (wxID_ANY, wxTreebook::OnTreeNodeExpandedCollapsed) - EVT_TREE_ITEM_COLLAPSED(wxID_ANY, wxTreebook::OnTreeNodeExpandedCollapsed) - - WX_EVENT_TABLE_CONTROL_CONTAINER(wxTreebook) -END_EVENT_TABLE() - -// ============================================================================ -// wxTreebook implementation -// ============================================================================ - -WX_DELEGATE_TO_CONTROL_CONTAINER(wxTreebook, wxControl) - -// ---------------------------------------------------------------------------- -// wxTreebook creation -// ---------------------------------------------------------------------------- - -void wxTreebook::Init() -{ - m_container.SetContainerWindow(this); - - m_selection = - m_actualSelection = wxNOT_FOUND; -} - -bool -wxTreebook::Create(wxWindow *parent, - wxWindowID id, - const wxPoint& pos, - const wxSize& size, - long style, - const wxString& name) -{ - // Check the style flag to have either wxTBK_RIGHT or wxTBK_LEFT - if ( (style & wxBK_ALIGN_MASK) == wxBK_DEFAULT ) - { - style |= wxBK_LEFT; - } - style |= wxTAB_TRAVERSAL; - - // no border for this control, it doesn't look nice together with the tree - style &= ~wxBORDER_MASK; - style |= wxBORDER_NONE; - - if ( !wxControl::Create(parent, id, pos, size, - style, wxDefaultValidator, name) ) - return false; - - m_bookctrl = new wxTreeCtrl - ( - this, - wxID_ANY, - wxDefaultPosition, - wxDefaultSize, -#ifndef __WXMSW__ - wxBORDER_SIMPLE | // On wxMSW this produces a black border which is wrong -#endif - wxTR_DEFAULT_STYLE | - wxTR_HIDE_ROOT | - wxTR_SINGLE - ); - GetTreeCtrl()->SetQuickBestSize(false); // do full size calculation - GetTreeCtrl()->AddRoot(wxEmptyString); // label doesn't matter, it's hidden - -#ifdef __WXMSW__ - // We need to add dummy size event to force possible scrollbar hiding - wxSizeEvent evt; - GetEventHandler()->AddPendingEvent(evt); -#endif - - return true; -} - - -// insert a new page just before the pagePos -bool wxTreebook::InsertPage(size_t pagePos, - wxWindow *page, - const wxString& text, - bool bSelect, - int imageId) -{ - return DoInsertPage(pagePos, page, text, bSelect, imageId); -} - -bool wxTreebook::InsertSubPage(size_t pagePos, - wxWindow *page, - const wxString& text, - bool bSelect, - int imageId) -{ - return DoInsertSubPage(pagePos, page, text, bSelect, imageId); -} - -bool wxTreebook::AddPage(wxWindow *page, const wxString& text, bool bSelect, - int imageId) -{ - return DoInsertPage(m_treeIds.GetCount(), page, text, bSelect, imageId); -} - -// insertion time is linear to the number of top-pages -bool wxTreebook::AddSubPage(wxWindow *page, const wxString& text, bool bSelect, int imageId) -{ - return DoAddSubPage(page, text, bSelect, imageId); -} - - -bool wxTreebook::DoInsertPage(size_t pagePos, - wxWindow *page, - const wxString& text, - bool bSelect, - int imageId) -{ - wxCHECK_MSG( pagePos <= DoInternalGetPageCount(), false, - wxT("Invalid treebook page position") ); - - if ( !wxBookCtrlBase::InsertPage(pagePos, page, text, bSelect, imageId) ) - return false; - - wxTreeCtrl *tree = GetTreeCtrl(); - wxTreeItemId newId; - if ( pagePos == DoInternalGetPageCount() ) - { - // append the page to the end - wxTreeItemId rootId = tree->GetRootItem(); - - newId = tree->AppendItem(rootId, text, imageId); - } - else // insert the new page before the given one - { - wxTreeItemId nodeId = m_treeIds[pagePos]; - - wxTreeItemId previousId = tree->GetPrevSibling(nodeId); - wxTreeItemId parentId = tree->GetItemParent(nodeId); - - if ( previousId.IsOk() ) - { - // insert before the sibling - previousId - newId = tree->InsertItem(parentId, previousId, text, imageId); - } - else // no prev siblings -- insert as a first child - { - wxASSERT_MSG( parentId.IsOk(), wxT( "Tree has no root node?" ) ); - - newId = tree->PrependItem(parentId, text, imageId); - } - } - - if ( !newId.IsOk() ) - { - //something wrong -> cleaning and returning with false - (void)wxBookCtrlBase::DoRemovePage(pagePos); - - wxFAIL_MSG( wxT("Failed to insert treebook page") ); - return false; - } - - DoInternalAddPage(pagePos, page, newId); - - DoUpdateSelection(bSelect, pagePos); - - return true; -} - -bool wxTreebook::DoAddSubPage(wxWindow *page, const wxString& text, bool bSelect, int imageId) -{ - wxTreeCtrl *tree = GetTreeCtrl(); - - wxTreeItemId rootId = tree->GetRootItem(); - - wxTreeItemId lastNodeId = tree->GetLastChild(rootId); - - wxCHECK_MSG( lastNodeId.IsOk(), false, - _T("Can't insert sub page when there are no pages") ); - - // now calculate its position (should we save/update it too?) - size_t newPos = tree->GetCount() - - (tree->GetChildrenCount(lastNodeId, true) + 1); - - return DoInsertSubPage(newPos, page, text, bSelect, imageId); -} - -bool wxTreebook::DoInsertSubPage(size_t pagePos, - wxTreebookPage *page, - const wxString& text, - bool bSelect, - int imageId) -{ - wxTreeItemId parentId = DoInternalGetPage(pagePos); - wxCHECK_MSG( parentId.IsOk(), false, wxT("invalid tree item") ); - - wxTreeCtrl *tree = GetTreeCtrl(); - - size_t newPos = pagePos + tree->GetChildrenCount(parentId, true) + 1; - wxASSERT_MSG( newPos <= DoInternalGetPageCount(), - wxT("Internal error in tree insert point calculation") ); - - if ( !wxBookCtrlBase::InsertPage(newPos, page, text, bSelect, imageId) ) - return false; - - wxTreeItemId newId = tree->AppendItem(parentId, text, imageId); - - if ( !newId.IsOk() ) - { - (void)wxBookCtrlBase::DoRemovePage(newPos); - - wxFAIL_MSG( wxT("Failed to insert treebook page") ); - return false; - } - - DoInternalAddPage(newPos, page, newId); - - DoUpdateSelection(bSelect, newPos); - - return true; -} - -bool wxTreebook::DeletePage(size_t pagePos) -{ - wxCHECK_MSG( IS_VALID_PAGE(pagePos), false, wxT("Invalid tree index") ); - - wxTreebookPage *oldPage = DoRemovePage(pagePos); - if ( !oldPage ) - return false; - - delete oldPage; - - return true; -} - -wxTreebookPage *wxTreebook::DoRemovePage(size_t pagePos) -{ - wxTreeItemId pageId = DoInternalGetPage(pagePos); - wxCHECK_MSG( pageId.IsOk(), NULL, wxT("Invalid tree index") ); - - wxTreebookPage * oldPage = GetPage(pagePos); - wxTreeCtrl *tree = GetTreeCtrl(); - - size_t subCount = tree->GetChildrenCount(pageId, true); - wxASSERT_MSG ( IS_VALID_PAGE(pagePos + subCount), - wxT("Internal error in wxTreebook::DoRemovePage") ); - - // here we are going to delete ALL the pages in the range - // [pagePos, pagePos + subCount] -- the page and its children - - // deleting all the pages from the base class - for ( size_t i = 0; i <= subCount; ++i ) - { - wxTreebookPage *page = wxBookCtrlBase::DoRemovePage(pagePos); - - // don't delete the page itself though -- it will be deleted in - // DeletePage() when we return - if ( i ) - { - delete page; - } - } - - DoInternalRemovePageRange(pagePos, subCount); - - tree->DeleteChildren( pageId ); - tree->Delete( pageId ); - - return oldPage; -} - -bool wxTreebook::DeleteAllPages() -{ - wxBookCtrlBase::DeleteAllPages(); - m_treeIds.Clear(); - m_selection = - m_actualSelection = wxNOT_FOUND; - - wxTreeCtrl *tree = GetTreeCtrl(); - tree->DeleteChildren(tree->GetRootItem()); - - return true; -} - -void wxTreebook::DoInternalAddPage(size_t newPos, - wxTreebookPage *page, - wxTreeItemId pageId) -{ - wxASSERT_MSG( newPos <= m_treeIds.GetCount(), wxT("Ivalid index passed to wxTreebook::DoInternalAddPage") ); - - // hide newly inserted page initially (it will be shown when selected) - if ( page ) - page->Hide(); - - if ( newPos == m_treeIds.GetCount() ) - { - // append - m_treeIds.Add(pageId); - } - else // insert - { - m_treeIds.Insert(pageId, newPos); - - if ( m_selection != wxNOT_FOUND && newPos <= (size_t)m_selection ) - { - // selection has been moved one unit toward the end - ++m_selection; - if ( m_actualSelection != wxNOT_FOUND ) - ++m_actualSelection; - } - else if ( m_actualSelection != wxNOT_FOUND && - newPos <= (size_t)m_actualSelection ) - { - DoSetSelection(m_selection); - } - } -} - -void wxTreebook::DoInternalRemovePageRange(size_t pagePos, size_t subCount) -{ - // Attention: this function is only for a situation when we delete a node - // with all its children so pagePos is the node's index and subCount is the - // node children count - wxASSERT_MSG( pagePos + subCount < m_treeIds.GetCount(), - wxT("Ivalid page index") ); - - wxTreeItemId pageId = m_treeIds[pagePos]; - - m_treeIds.RemoveAt(pagePos, subCount + 1); - - if ( m_selection != wxNOT_FOUND ) - { - if ( (size_t)m_selection > pagePos + subCount) - { - // selection is far after the deleted page, so just update the index and move on - m_selection -= 1 + subCount; - if ( m_actualSelection != wxNOT_FOUND) - { - m_actualSelection -= subCount + 1; - } - } - else if ( (size_t)m_selection >= pagePos ) - { - wxTreeCtrl *tree = GetTreeCtrl(); - - // as selected page is going to be deleted, try to select the next - // sibling if exists, if not then the parent - wxTreeItemId nodeId = tree->GetNextSibling(pageId); - - m_selection = wxNOT_FOUND; - m_actualSelection = wxNOT_FOUND; - - if ( nodeId.IsOk() ) - { - // selecting next siblings - tree->SelectItem(nodeId); - } - else // no next sibling, select the parent - { - wxTreeItemId parentId = tree->GetItemParent(pageId); - - if ( parentId.IsOk() && parentId != tree->GetRootItem() ) - { - tree->SelectItem(parentId); - } - else // parent is root - { - // we can't select it as it's hidden - DoUpdateSelection(false, wxNOT_FOUND); - } - } - } - else if ( m_actualSelection != wxNOT_FOUND && - (size_t)m_actualSelection >= pagePos ) - { - // nothing to do -- selection is before the deleted node, but - // actually shown page (the first (sub)child with page != NULL) is - // already deleted - m_actualSelection = m_selection; - - // send event as documented - DoSetSelection(m_selection, SetSelection_SendEvent); - } - //else: nothing to do -- selection is before the deleted node - } - else - { - DoUpdateSelection(false, wxNOT_FOUND); - } -} - - -void wxTreebook::DoUpdateSelection(bool bSelect, int newPos) -{ - int newSelPos; - if ( bSelect ) - { - newSelPos = newPos; - } - else if ( m_selection == wxNOT_FOUND && DoInternalGetPageCount() > 0 ) - { - newSelPos = 0; - } - else - { - newSelPos = wxNOT_FOUND; - } - - if ( newSelPos != wxNOT_FOUND ) - { - SetSelection((size_t)newSelPos); - } -} - -wxTreeItemId wxTreebook::DoInternalGetPage(size_t pagePos) const -{ - if ( pagePos >= m_treeIds.GetCount() ) - { - // invalid position but ok here, in this internal function, don't assert - // (the caller will do it) - return wxTreeItemId(); - } - - return m_treeIds[pagePos]; -} - -int wxTreebook::DoInternalFindPageById(wxTreeItemId pageId) const -{ - const size_t count = m_treeIds.GetCount(); - for ( size_t i = 0; i < count; ++i ) - { - if ( m_treeIds[i] == pageId ) - return i; - } - - return wxNOT_FOUND; -} - -bool wxTreebook::IsNodeExpanded(size_t pagePos) const -{ - wxTreeItemId pageId = DoInternalGetPage(pagePos); - - wxCHECK_MSG( pageId.IsOk(), false, wxT("invalid tree item") ); - - return GetTreeCtrl()->IsExpanded(pageId); -} - -bool wxTreebook::ExpandNode(size_t pagePos, bool expand) -{ - wxTreeItemId pageId = DoInternalGetPage(pagePos); - - wxCHECK_MSG( pageId.IsOk(), false, wxT("invalid tree item") ); - - if ( expand ) - { - GetTreeCtrl()->Expand( pageId ); - } - else // collapse - { - GetTreeCtrl()->Collapse( pageId ); - - // rely on the events generated by wxTreeCtrl to update selection - } - - return true; -} - -int wxTreebook::GetPageParent(size_t pagePos) const -{ - wxTreeItemId nodeId = DoInternalGetPage( pagePos ); - wxCHECK_MSG( nodeId.IsOk(), wxNOT_FOUND, wxT("Invalid page index spacified!") ); - - const wxTreeItemId parent = GetTreeCtrl()->GetItemParent( nodeId ); - - return parent.IsOk() ? DoInternalFindPageById(parent) : wxNOT_FOUND; -} - -bool wxTreebook::SetPageText(size_t n, const wxString& strText) -{ - wxTreeItemId pageId = DoInternalGetPage(n); - - wxCHECK_MSG( pageId.IsOk(), false, wxT("invalid tree item") ); - - GetTreeCtrl()->SetItemText(pageId, strText); - - return true; -} - -wxString wxTreebook::GetPageText(size_t n) const -{ - wxTreeItemId pageId = DoInternalGetPage(n); - - wxCHECK_MSG( pageId.IsOk(), wxString(), wxT("invalid tree item") ); - - return GetTreeCtrl()->GetItemText(pageId); -} - -int wxTreebook::GetPageImage(size_t n) const -{ - wxTreeItemId pageId = DoInternalGetPage(n); - - wxCHECK_MSG( pageId.IsOk(), wxNOT_FOUND, wxT("invalid tree item") ); - - return GetTreeCtrl()->GetItemImage(pageId); -} - -bool wxTreebook::SetPageImage(size_t n, int imageId) -{ - wxTreeItemId pageId = DoInternalGetPage(n); - - wxCHECK_MSG( pageId.IsOk(), false, wxT("invalid tree item") ); - - GetTreeCtrl()->SetItemImage(pageId, imageId); - - return true; -} - -wxSize wxTreebook::CalcSizeFromPage(const wxSize& sizePage) const -{ - const wxSize sizeTree = GetControllerSize(); - - wxSize size = sizePage; - size.x += sizeTree.x; - - return size; -} - -int wxTreebook::GetSelection() const -{ - return m_selection; -} - -int wxTreebook::DoSetSelection(size_t pagePos, int flags) -{ - wxCHECK_MSG( IS_VALID_PAGE(pagePos), wxNOT_FOUND, - wxT("invalid page index in wxListbook::DoSetSelection()") ); - wxASSERT_MSG( GetPageCount() == DoInternalGetPageCount(), - wxT("wxTreebook logic error: m_treeIds and m_pages not in sync!")); - - wxTreebookEvent event(wxEVT_COMMAND_TREEBOOK_PAGE_CHANGING, m_windowId); - const int oldSel = m_selection; - wxTreeCtrl *tree = GetTreeCtrl(); - bool allowed = false; - - if (flags & SetSelection_SendEvent) - { - event.SetEventObject(this); - event.SetSelection(pagePos); - event.SetOldSelection(m_selection); - - // don't send the event if the old and new pages are the same; do send it - // otherwise and be prepared for it to be vetoed - allowed = (int)pagePos == m_selection || - !GetEventHandler()->ProcessEvent(event) || - event.IsAllowed(); - } - - if ( !(flags & SetSelection_SendEvent) || allowed ) - { - // hide the previously shown page - wxTreebookPage * const oldPage = DoGetCurrentPage(); - if ( oldPage ) - oldPage->Hide(); - - // then show the new one - m_selection = pagePos; - wxTreebookPage *page = wxBookCtrlBase::GetPage(m_selection); - if ( !page ) - { - // find the next page suitable to be shown: the first (grand)child - // of this one with a non-NULL associated page - wxTreeItemId childId = m_treeIds[pagePos]; - int actualPagePos = pagePos; - while ( !page && childId.IsOk() ) - { - wxTreeItemIdValue cookie; - childId = tree->GetFirstChild( childId, cookie ); - if ( childId.IsOk() ) - { - page = wxBookCtrlBase::GetPage(++actualPagePos); - } - } - - m_actualSelection = page ? actualPagePos : m_selection; - } - - if ( page ) - page->Show(); - - tree->SelectItem(DoInternalGetPage(pagePos)); - - if (flags & SetSelection_SendEvent) - { - // notify about the (now completed) page change - event.SetEventType(wxEVT_COMMAND_TREEBOOK_PAGE_CHANGED); - (void)GetEventHandler()->ProcessEvent(event); - } - } - else if ( (flags & SetSelection_SendEvent) && !allowed) // page change vetoed - { - // tree selection might have already had changed - if ( oldSel != wxNOT_FOUND ) - tree->SelectItem(DoInternalGetPage(oldSel)); - } - - return oldSel; -} - -wxTreebookPage *wxTreebook::DoGetCurrentPage() const -{ - if ( m_selection == wxNOT_FOUND ) - return NULL; - - wxTreebookPage *page = wxBookCtrlBase::GetPage(m_selection); - if ( !page && m_actualSelection != wxNOT_FOUND ) - { - page = wxBookCtrlBase::GetPage(m_actualSelection); - } - - return page; -} - -void wxTreebook::SetImageList(wxImageList *imageList) -{ - wxBookCtrlBase::SetImageList(imageList); - GetTreeCtrl()->SetImageList(imageList); -} - -void wxTreebook::AssignImageList(wxImageList *imageList) -{ - wxBookCtrlBase::AssignImageList(imageList); - GetTreeCtrl()->SetImageList(imageList); -} - -// ---------------------------------------------------------------------------- -// event handlers -// ---------------------------------------------------------------------------- - -void wxTreebook::OnTreeSelectionChange(wxTreeEvent& event) -{ - if ( event.GetEventObject() != m_bookctrl ) - { - event.Skip(); - return; - } - - wxTreeItemId newId = event.GetItem(); - - if ( (m_selection == wxNOT_FOUND && - (!newId.IsOk() || newId == GetTreeCtrl()->GetRootItem())) || - (m_selection != wxNOT_FOUND && newId == m_treeIds[m_selection]) ) - { - // this event can only come when we modify the tree selection ourselves - // so we should simply ignore it - return; - } - - int newPos = DoInternalFindPageById(newId); - - if ( newPos != wxNOT_FOUND ) - SetSelection( newPos ); -} - -void wxTreebook::OnTreeNodeExpandedCollapsed(wxTreeEvent & event) -{ - if ( event.GetEventObject() != m_bookctrl ) - { - event.Skip(); - return; - } - - wxTreeItemId nodeId = event.GetItem(); - if ( !nodeId.IsOk() || nodeId == GetTreeCtrl()->GetRootItem() ) - return; - int pagePos = DoInternalFindPageById(nodeId); - wxCHECK_RET( pagePos != wxNOT_FOUND, wxT("Internal problem in wxTreebook!..") ); - - wxTreebookEvent ev(GetTreeCtrl()->IsExpanded(nodeId) - ? wxEVT_COMMAND_TREEBOOK_NODE_EXPANDED - : wxEVT_COMMAND_TREEBOOK_NODE_COLLAPSED, - m_windowId); - - ev.SetSelection(pagePos); - ev.SetOldSelection(pagePos); - ev.SetEventObject(this); - - GetEventHandler()->ProcessEvent(ev); -} - -// ---------------------------------------------------------------------------- -// wxTreebook geometry management -// ---------------------------------------------------------------------------- - -int wxTreebook::HitTest(wxPoint const & pt, long * flags) const -{ - int pagePos = wxNOT_FOUND; - - if ( flags ) - *flags = wxBK_HITTEST_NOWHERE; - - // convert from wxTreebook coorindates to wxTreeCtrl ones - const wxTreeCtrl * const tree = GetTreeCtrl(); - const wxPoint treePt = tree->ScreenToClient(ClientToScreen(pt)); - - // is it over the tree? - if ( wxRect(tree->GetSize()).Contains(treePt) ) - { - int flagsTree; - wxTreeItemId id = tree->HitTest(treePt, flagsTree); - - if ( id.IsOk() && (flagsTree & wxTREE_HITTEST_ONITEM) ) - { - pagePos = DoInternalFindPageById(id); - } - - if ( flags ) - { - if ( pagePos != wxNOT_FOUND ) - *flags = 0; - - if ( flagsTree & (wxTREE_HITTEST_ONITEMBUTTON | - wxTREE_HITTEST_ONITEMICON | - wxTREE_HITTEST_ONITEMSTATEICON) ) - *flags |= wxBK_HITTEST_ONICON; - - if ( flagsTree & wxTREE_HITTEST_ONITEMLABEL ) - *flags |= wxBK_HITTEST_ONLABEL; - } - } - else // not over the tree - { - if ( flags && GetPageRect().Contains( pt ) ) - *flags |= wxBK_HITTEST_ONPAGE; - } - - return pagePos; -} - -#endif // wxUSE_TREEBOOK +/////////////////////////////////////////////////////////////////////////////// +// Name: src/generic/treebkg.cpp +// Purpose: generic implementation of wxTreebook +// Author: Evgeniy Tarassov, Vadim Zeitlin +// Modified by: +// Created: 2005-09-15 +// RCS-ID: $Id: treebkg.cpp 44271 2007-01-21 00:52:05Z VZ $ +// Copyright: (c) 2005 Vadim Zeitlin +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_TREEBOOK + +#include "wx/treebook.h" + +#ifndef WX_PRECOMP + #include "wx/settings.h" +#endif + +#include "wx/imaglist.h" + +// ---------------------------------------------------------------------------- +// various wxWidgets macros +// ---------------------------------------------------------------------------- + +// check that the page index is valid +#define IS_VALID_PAGE(nPage) ((nPage) < DoInternalGetPageCount()) + +// ---------------------------------------------------------------------------- +// event table +// ---------------------------------------------------------------------------- + +IMPLEMENT_DYNAMIC_CLASS(wxTreebook, wxBookCtrlBase) +IMPLEMENT_DYNAMIC_CLASS(wxTreebookEvent, wxNotifyEvent) + +#if !WXWIN_COMPATIBILITY_EVENT_TYPES +const wxEventType wxEVT_COMMAND_TREEBOOK_PAGE_CHANGING = wxNewEventType(); +const wxEventType wxEVT_COMMAND_TREEBOOK_PAGE_CHANGED = wxNewEventType(); +const wxEventType wxEVT_COMMAND_TREEBOOK_NODE_COLLAPSED = wxNewEventType(); +const wxEventType wxEVT_COMMAND_TREEBOOK_NODE_EXPANDED = wxNewEventType(); +#endif + +BEGIN_EVENT_TABLE(wxTreebook, wxBookCtrlBase) + EVT_TREE_SEL_CHANGED (wxID_ANY, wxTreebook::OnTreeSelectionChange) + EVT_TREE_ITEM_EXPANDED (wxID_ANY, wxTreebook::OnTreeNodeExpandedCollapsed) + EVT_TREE_ITEM_COLLAPSED(wxID_ANY, wxTreebook::OnTreeNodeExpandedCollapsed) + + WX_EVENT_TABLE_CONTROL_CONTAINER(wxTreebook) +END_EVENT_TABLE() + +// ============================================================================ +// wxTreebook implementation +// ============================================================================ + +WX_DELEGATE_TO_CONTROL_CONTAINER(wxTreebook, wxControl) + +// ---------------------------------------------------------------------------- +// wxTreebook creation +// ---------------------------------------------------------------------------- + +void wxTreebook::Init() +{ + m_container.SetContainerWindow(this); + + m_selection = + m_actualSelection = wxNOT_FOUND; +} + +bool +wxTreebook::Create(wxWindow *parent, + wxWindowID id, + const wxPoint& pos, + const wxSize& size, + long style, + const wxString& name) +{ + // Check the style flag to have either wxTBK_RIGHT or wxTBK_LEFT + if ( (style & wxBK_ALIGN_MASK) == wxBK_DEFAULT ) + { + style |= wxBK_LEFT; + } + style |= wxTAB_TRAVERSAL; + + // no border for this control, it doesn't look nice together with the tree + style &= ~wxBORDER_MASK; + style |= wxBORDER_NONE; + + if ( !wxControl::Create(parent, id, pos, size, + style, wxDefaultValidator, name) ) + return false; + + m_bookctrl = new wxTreeCtrl + ( + this, + wxID_ANY, + wxDefaultPosition, + wxDefaultSize, +#ifndef __WXMSW__ + wxBORDER_SIMPLE | // On wxMSW this produces a black border which is wrong +#endif + wxTR_DEFAULT_STYLE | + wxTR_HIDE_ROOT | + wxTR_SINGLE + ); + GetTreeCtrl()->SetQuickBestSize(false); // do full size calculation + GetTreeCtrl()->AddRoot(wxEmptyString); // label doesn't matter, it's hidden + +#ifdef __WXMSW__ + // We need to add dummy size event to force possible scrollbar hiding + wxSizeEvent evt; + GetEventHandler()->AddPendingEvent(evt); +#endif + + return true; +} + + +// insert a new page just before the pagePos +bool wxTreebook::InsertPage(size_t pagePos, + wxWindow *page, + const wxString& text, + bool bSelect, + int imageId) +{ + return DoInsertPage(pagePos, page, text, bSelect, imageId); +} + +bool wxTreebook::InsertSubPage(size_t pagePos, + wxWindow *page, + const wxString& text, + bool bSelect, + int imageId) +{ + return DoInsertSubPage(pagePos, page, text, bSelect, imageId); +} + +bool wxTreebook::AddPage(wxWindow *page, const wxString& text, bool bSelect, + int imageId) +{ + return DoInsertPage(m_treeIds.GetCount(), page, text, bSelect, imageId); +} + +// insertion time is linear to the number of top-pages +bool wxTreebook::AddSubPage(wxWindow *page, const wxString& text, bool bSelect, int imageId) +{ + return DoAddSubPage(page, text, bSelect, imageId); +} + + +bool wxTreebook::DoInsertPage(size_t pagePos, + wxWindow *page, + const wxString& text, + bool bSelect, + int imageId) +{ + wxCHECK_MSG( pagePos <= DoInternalGetPageCount(), false, + wxT("Invalid treebook page position") ); + + if ( !wxBookCtrlBase::InsertPage(pagePos, page, text, bSelect, imageId) ) + return false; + + wxTreeCtrl *tree = GetTreeCtrl(); + wxTreeItemId newId; + if ( pagePos == DoInternalGetPageCount() ) + { + // append the page to the end + wxTreeItemId rootId = tree->GetRootItem(); + + newId = tree->AppendItem(rootId, text, imageId); + } + else // insert the new page before the given one + { + wxTreeItemId nodeId = m_treeIds[pagePos]; + + wxTreeItemId previousId = tree->GetPrevSibling(nodeId); + wxTreeItemId parentId = tree->GetItemParent(nodeId); + + if ( previousId.IsOk() ) + { + // insert before the sibling - previousId + newId = tree->InsertItem(parentId, previousId, text, imageId); + } + else // no prev siblings -- insert as a first child + { + wxASSERT_MSG( parentId.IsOk(), wxT( "Tree has no root node?" ) ); + + newId = tree->PrependItem(parentId, text, imageId); + } + } + + if ( !newId.IsOk() ) + { + //something wrong -> cleaning and returning with false + (void)wxBookCtrlBase::DoRemovePage(pagePos); + + wxFAIL_MSG( wxT("Failed to insert treebook page") ); + return false; + } + + DoInternalAddPage(pagePos, page, newId); + + DoUpdateSelection(bSelect, pagePos); + + return true; +} + +bool wxTreebook::DoAddSubPage(wxWindow *page, const wxString& text, bool bSelect, int imageId) +{ + wxTreeCtrl *tree = GetTreeCtrl(); + + wxTreeItemId rootId = tree->GetRootItem(); + + wxTreeItemId lastNodeId = tree->GetLastChild(rootId); + + wxCHECK_MSG( lastNodeId.IsOk(), false, + _T("Can't insert sub page when there are no pages") ); + + // now calculate its position (should we save/update it too?) + size_t newPos = tree->GetCount() - + (tree->GetChildrenCount(lastNodeId, true) + 1); + + return DoInsertSubPage(newPos, page, text, bSelect, imageId); +} + +bool wxTreebook::DoInsertSubPage(size_t pagePos, + wxTreebookPage *page, + const wxString& text, + bool bSelect, + int imageId) +{ + wxTreeItemId parentId = DoInternalGetPage(pagePos); + wxCHECK_MSG( parentId.IsOk(), false, wxT("invalid tree item") ); + + wxTreeCtrl *tree = GetTreeCtrl(); + + size_t newPos = pagePos + tree->GetChildrenCount(parentId, true) + 1; + wxASSERT_MSG( newPos <= DoInternalGetPageCount(), + wxT("Internal error in tree insert point calculation") ); + + if ( !wxBookCtrlBase::InsertPage(newPos, page, text, bSelect, imageId) ) + return false; + + wxTreeItemId newId = tree->AppendItem(parentId, text, imageId); + + if ( !newId.IsOk() ) + { + (void)wxBookCtrlBase::DoRemovePage(newPos); + + wxFAIL_MSG( wxT("Failed to insert treebook page") ); + return false; + } + + DoInternalAddPage(newPos, page, newId); + + DoUpdateSelection(bSelect, newPos); + + return true; +} + +bool wxTreebook::DeletePage(size_t pagePos) +{ + wxCHECK_MSG( IS_VALID_PAGE(pagePos), false, wxT("Invalid tree index") ); + + wxTreebookPage *oldPage = DoRemovePage(pagePos); + if ( !oldPage ) + return false; + + delete oldPage; + + return true; +} + +wxTreebookPage *wxTreebook::DoRemovePage(size_t pagePos) +{ + wxTreeItemId pageId = DoInternalGetPage(pagePos); + wxCHECK_MSG( pageId.IsOk(), NULL, wxT("Invalid tree index") ); + + wxTreebookPage * oldPage = GetPage(pagePos); + wxTreeCtrl *tree = GetTreeCtrl(); + + size_t subCount = tree->GetChildrenCount(pageId, true); + wxASSERT_MSG ( IS_VALID_PAGE(pagePos + subCount), + wxT("Internal error in wxTreebook::DoRemovePage") ); + + // here we are going to delete ALL the pages in the range + // [pagePos, pagePos + subCount] -- the page and its children + + // deleting all the pages from the base class + for ( size_t i = 0; i <= subCount; ++i ) + { + wxTreebookPage *page = wxBookCtrlBase::DoRemovePage(pagePos); + + // don't delete the page itself though -- it will be deleted in + // DeletePage() when we return + if ( i ) + { + delete page; + } + } + + DoInternalRemovePageRange(pagePos, subCount); + + tree->DeleteChildren( pageId ); + tree->Delete( pageId ); + + return oldPage; +} + +bool wxTreebook::DeleteAllPages() +{ + wxBookCtrlBase::DeleteAllPages(); + m_treeIds.Clear(); + m_selection = + m_actualSelection = wxNOT_FOUND; + + wxTreeCtrl *tree = GetTreeCtrl(); + tree->DeleteChildren(tree->GetRootItem()); + + return true; +} + +void wxTreebook::DoInternalAddPage(size_t newPos, + wxTreebookPage *page, + wxTreeItemId pageId) +{ + wxASSERT_MSG( newPos <= m_treeIds.GetCount(), wxT("Ivalid index passed to wxTreebook::DoInternalAddPage") ); + + // hide newly inserted page initially (it will be shown when selected) + if ( page ) + page->Hide(); + + if ( newPos == m_treeIds.GetCount() ) + { + // append + m_treeIds.Add(pageId); + } + else // insert + { + m_treeIds.Insert(pageId, newPos); + + if ( m_selection != wxNOT_FOUND && newPos <= (size_t)m_selection ) + { + // selection has been moved one unit toward the end + ++m_selection; + if ( m_actualSelection != wxNOT_FOUND ) + ++m_actualSelection; + } + else if ( m_actualSelection != wxNOT_FOUND && + newPos <= (size_t)m_actualSelection ) + { + DoSetSelection(m_selection); + } + } +} + +void wxTreebook::DoInternalRemovePageRange(size_t pagePos, size_t subCount) +{ + // Attention: this function is only for a situation when we delete a node + // with all its children so pagePos is the node's index and subCount is the + // node children count + wxASSERT_MSG( pagePos + subCount < m_treeIds.GetCount(), + wxT("Ivalid page index") ); + + wxTreeItemId pageId = m_treeIds[pagePos]; + + m_treeIds.RemoveAt(pagePos, subCount + 1); + + if ( m_selection != wxNOT_FOUND ) + { + if ( (size_t)m_selection > pagePos + subCount) + { + // selection is far after the deleted page, so just update the index and move on + m_selection -= 1 + subCount; + if ( m_actualSelection != wxNOT_FOUND) + { + m_actualSelection -= subCount + 1; + } + } + else if ( (size_t)m_selection >= pagePos ) + { + wxTreeCtrl *tree = GetTreeCtrl(); + + // as selected page is going to be deleted, try to select the next + // sibling if exists, if not then the parent + wxTreeItemId nodeId = tree->GetNextSibling(pageId); + + m_selection = wxNOT_FOUND; + m_actualSelection = wxNOT_FOUND; + + if ( nodeId.IsOk() ) + { + // selecting next siblings + tree->SelectItem(nodeId); + } + else // no next sibling, select the parent + { + wxTreeItemId parentId = tree->GetItemParent(pageId); + + if ( parentId.IsOk() && parentId != tree->GetRootItem() ) + { + tree->SelectItem(parentId); + } + else // parent is root + { + // we can't select it as it's hidden + DoUpdateSelection(false, wxNOT_FOUND); + } + } + } + else if ( m_actualSelection != wxNOT_FOUND && + (size_t)m_actualSelection >= pagePos ) + { + // nothing to do -- selection is before the deleted node, but + // actually shown page (the first (sub)child with page != NULL) is + // already deleted + m_actualSelection = m_selection; + + // send event as documented + DoSetSelection(m_selection, SetSelection_SendEvent); + } + //else: nothing to do -- selection is before the deleted node + } + else + { + DoUpdateSelection(false, wxNOT_FOUND); + } +} + + +void wxTreebook::DoUpdateSelection(bool bSelect, int newPos) +{ + int newSelPos; + if ( bSelect ) + { + newSelPos = newPos; + } + else if ( m_selection == wxNOT_FOUND && DoInternalGetPageCount() > 0 ) + { + newSelPos = 0; + } + else + { + newSelPos = wxNOT_FOUND; + } + + if ( newSelPos != wxNOT_FOUND ) + { + SetSelection((size_t)newSelPos); + } +} + +wxTreeItemId wxTreebook::DoInternalGetPage(size_t pagePos) const +{ + if ( pagePos >= m_treeIds.GetCount() ) + { + // invalid position but ok here, in this internal function, don't assert + // (the caller will do it) + return wxTreeItemId(); + } + + return m_treeIds[pagePos]; +} + +int wxTreebook::DoInternalFindPageById(wxTreeItemId pageId) const +{ + const size_t count = m_treeIds.GetCount(); + for ( size_t i = 0; i < count; ++i ) + { + if ( m_treeIds[i] == pageId ) + return i; + } + + return wxNOT_FOUND; +} + +bool wxTreebook::IsNodeExpanded(size_t pagePos) const +{ + wxTreeItemId pageId = DoInternalGetPage(pagePos); + + wxCHECK_MSG( pageId.IsOk(), false, wxT("invalid tree item") ); + + return GetTreeCtrl()->IsExpanded(pageId); +} + +bool wxTreebook::ExpandNode(size_t pagePos, bool expand) +{ + wxTreeItemId pageId = DoInternalGetPage(pagePos); + + wxCHECK_MSG( pageId.IsOk(), false, wxT("invalid tree item") ); + + if ( expand ) + { + GetTreeCtrl()->Expand( pageId ); + } + else // collapse + { + GetTreeCtrl()->Collapse( pageId ); + + // rely on the events generated by wxTreeCtrl to update selection + } + + return true; +} + +int wxTreebook::GetPageParent(size_t pagePos) const +{ + wxTreeItemId nodeId = DoInternalGetPage( pagePos ); + wxCHECK_MSG( nodeId.IsOk(), wxNOT_FOUND, wxT("Invalid page index spacified!") ); + + const wxTreeItemId parent = GetTreeCtrl()->GetItemParent( nodeId ); + + return parent.IsOk() ? DoInternalFindPageById(parent) : wxNOT_FOUND; +} + +bool wxTreebook::SetPageText(size_t n, const wxString& strText) +{ + wxTreeItemId pageId = DoInternalGetPage(n); + + wxCHECK_MSG( pageId.IsOk(), false, wxT("invalid tree item") ); + + GetTreeCtrl()->SetItemText(pageId, strText); + + return true; +} + +wxString wxTreebook::GetPageText(size_t n) const +{ + wxTreeItemId pageId = DoInternalGetPage(n); + + wxCHECK_MSG( pageId.IsOk(), wxString(), wxT("invalid tree item") ); + + return GetTreeCtrl()->GetItemText(pageId); +} + +int wxTreebook::GetPageImage(size_t n) const +{ + wxTreeItemId pageId = DoInternalGetPage(n); + + wxCHECK_MSG( pageId.IsOk(), wxNOT_FOUND, wxT("invalid tree item") ); + + return GetTreeCtrl()->GetItemImage(pageId); +} + +bool wxTreebook::SetPageImage(size_t n, int imageId) +{ + wxTreeItemId pageId = DoInternalGetPage(n); + + wxCHECK_MSG( pageId.IsOk(), false, wxT("invalid tree item") ); + + GetTreeCtrl()->SetItemImage(pageId, imageId); + + return true; +} + +wxSize wxTreebook::CalcSizeFromPage(const wxSize& sizePage) const +{ + const wxSize sizeTree = GetControllerSize(); + + wxSize size = sizePage; + size.x += sizeTree.x; + + return size; +} + +int wxTreebook::GetSelection() const +{ + return m_selection; +} + +int wxTreebook::DoSetSelection(size_t pagePos, int flags) +{ + wxCHECK_MSG( IS_VALID_PAGE(pagePos), wxNOT_FOUND, + wxT("invalid page index in wxListbook::DoSetSelection()") ); + wxASSERT_MSG( GetPageCount() == DoInternalGetPageCount(), + wxT("wxTreebook logic error: m_treeIds and m_pages not in sync!")); + + wxTreebookEvent event(wxEVT_COMMAND_TREEBOOK_PAGE_CHANGING, m_windowId); + const int oldSel = m_selection; + wxTreeCtrl *tree = GetTreeCtrl(); + bool allowed = false; + + if (flags & SetSelection_SendEvent) + { + event.SetEventObject(this); + event.SetSelection(pagePos); + event.SetOldSelection(m_selection); + + // don't send the event if the old and new pages are the same; do send it + // otherwise and be prepared for it to be vetoed + allowed = (int)pagePos == m_selection || + !GetEventHandler()->ProcessEvent(event) || + event.IsAllowed(); + } + + if ( !(flags & SetSelection_SendEvent) || allowed ) + { + // hide the previously shown page + wxTreebookPage * const oldPage = DoGetCurrentPage(); + if ( oldPage ) + oldPage->Hide(); + + // then show the new one + m_selection = pagePos; + wxTreebookPage *page = wxBookCtrlBase::GetPage(m_selection); + if ( !page ) + { + // find the next page suitable to be shown: the first (grand)child + // of this one with a non-NULL associated page + wxTreeItemId childId = m_treeIds[pagePos]; + int actualPagePos = pagePos; + while ( !page && childId.IsOk() ) + { + wxTreeItemIdValue cookie; + childId = tree->GetFirstChild( childId, cookie ); + if ( childId.IsOk() ) + { + page = wxBookCtrlBase::GetPage(++actualPagePos); + } + } + + m_actualSelection = page ? actualPagePos : m_selection; + } + + if ( page ) + page->Show(); + + tree->SelectItem(DoInternalGetPage(pagePos)); + + if (flags & SetSelection_SendEvent) + { + // notify about the (now completed) page change + event.SetEventType(wxEVT_COMMAND_TREEBOOK_PAGE_CHANGED); + (void)GetEventHandler()->ProcessEvent(event); + } + } + else if ( (flags & SetSelection_SendEvent) && !allowed) // page change vetoed + { + // tree selection might have already had changed + if ( oldSel != wxNOT_FOUND ) + tree->SelectItem(DoInternalGetPage(oldSel)); + } + + return oldSel; +} + +wxTreebookPage *wxTreebook::DoGetCurrentPage() const +{ + if ( m_selection == wxNOT_FOUND ) + return NULL; + + wxTreebookPage *page = wxBookCtrlBase::GetPage(m_selection); + if ( !page && m_actualSelection != wxNOT_FOUND ) + { + page = wxBookCtrlBase::GetPage(m_actualSelection); + } + + return page; +} + +void wxTreebook::SetImageList(wxImageList *imageList) +{ + wxBookCtrlBase::SetImageList(imageList); + GetTreeCtrl()->SetImageList(imageList); +} + +void wxTreebook::AssignImageList(wxImageList *imageList) +{ + wxBookCtrlBase::AssignImageList(imageList); + GetTreeCtrl()->SetImageList(imageList); +} + +// ---------------------------------------------------------------------------- +// event handlers +// ---------------------------------------------------------------------------- + +void wxTreebook::OnTreeSelectionChange(wxTreeEvent& event) +{ + if ( event.GetEventObject() != m_bookctrl ) + { + event.Skip(); + return; + } + + wxTreeItemId newId = event.GetItem(); + + if ( (m_selection == wxNOT_FOUND && + (!newId.IsOk() || newId == GetTreeCtrl()->GetRootItem())) || + (m_selection != wxNOT_FOUND && newId == m_treeIds[m_selection]) ) + { + // this event can only come when we modify the tree selection ourselves + // so we should simply ignore it + return; + } + + int newPos = DoInternalFindPageById(newId); + + if ( newPos != wxNOT_FOUND ) + SetSelection( newPos ); +} + +void wxTreebook::OnTreeNodeExpandedCollapsed(wxTreeEvent & event) +{ + if ( event.GetEventObject() != m_bookctrl ) + { + event.Skip(); + return; + } + + wxTreeItemId nodeId = event.GetItem(); + if ( !nodeId.IsOk() || nodeId == GetTreeCtrl()->GetRootItem() ) + return; + int pagePos = DoInternalFindPageById(nodeId); + wxCHECK_RET( pagePos != wxNOT_FOUND, wxT("Internal problem in wxTreebook!..") ); + + wxTreebookEvent ev(GetTreeCtrl()->IsExpanded(nodeId) + ? wxEVT_COMMAND_TREEBOOK_NODE_EXPANDED + : wxEVT_COMMAND_TREEBOOK_NODE_COLLAPSED, + m_windowId); + + ev.SetSelection(pagePos); + ev.SetOldSelection(pagePos); + ev.SetEventObject(this); + + GetEventHandler()->ProcessEvent(ev); +} + +// ---------------------------------------------------------------------------- +// wxTreebook geometry management +// ---------------------------------------------------------------------------- + +int wxTreebook::HitTest(wxPoint const & pt, long * flags) const +{ + int pagePos = wxNOT_FOUND; + + if ( flags ) + *flags = wxBK_HITTEST_NOWHERE; + + // convert from wxTreebook coorindates to wxTreeCtrl ones + const wxTreeCtrl * const tree = GetTreeCtrl(); + const wxPoint treePt = tree->ScreenToClient(ClientToScreen(pt)); + + // is it over the tree? + if ( wxRect(tree->GetSize()).Contains(treePt) ) + { + int flagsTree; + wxTreeItemId id = tree->HitTest(treePt, flagsTree); + + if ( id.IsOk() && (flagsTree & wxTREE_HITTEST_ONITEM) ) + { + pagePos = DoInternalFindPageById(id); + } + + if ( flags ) + { + if ( pagePos != wxNOT_FOUND ) + *flags = 0; + + if ( flagsTree & (wxTREE_HITTEST_ONITEMBUTTON | + wxTREE_HITTEST_ONITEMICON | + wxTREE_HITTEST_ONITEMSTATEICON) ) + *flags |= wxBK_HITTEST_ONICON; + + if ( flagsTree & wxTREE_HITTEST_ONITEMLABEL ) + *flags |= wxBK_HITTEST_ONLABEL; + } + } + else // not over the tree + { + if ( flags && GetPageRect().Contains( pt ) ) + *flags |= wxBK_HITTEST_ONPAGE; + } + + return pagePos; +} + +#endif // wxUSE_TREEBOOK diff --git a/Externals/wxWidgets/src/generic/treectlg.cpp b/Externals/wxWidgets/src/generic/treectlg.cpp index 4dc55bec37..35e91f9313 100644 --- a/Externals/wxWidgets/src/generic/treectlg.cpp +++ b/Externals/wxWidgets/src/generic/treectlg.cpp @@ -1,3696 +1,3696 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/generic/treectlg.cpp -// Purpose: generic tree control implementation -// Author: Robert Roebling -// Created: 01/02/97 -// Modified: 22/10/98 - almost total rewrite, simpler interface (VZ) -// Id: $Id: treectlg.cpp 53135 2008-04-12 02:31:04Z VZ $ -// Copyright: (c) 1998 Robert Roebling and Julian Smart -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// ============================================================================= -// declarations -// ============================================================================= - -// ----------------------------------------------------------------------------- -// headers -// ----------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_TREECTRL - -#include "wx/treectrl.h" - -#ifndef WX_PRECOMP - #include "wx/dcclient.h" - #include "wx/timer.h" - #include "wx/settings.h" - #include "wx/listbox.h" - #include "wx/textctrl.h" -#endif - -#include "wx/generic/treectlg.h" -#include "wx/imaglist.h" - -#include "wx/renderer.h" - -#ifdef __WXMAC__ - #include "wx/mac/private.h" -#endif - -// ----------------------------------------------------------------------------- -// array types -// ----------------------------------------------------------------------------- - -class WXDLLIMPEXP_FWD_CORE wxGenericTreeItem; - -WX_DEFINE_EXPORTED_ARRAY_PTR(wxGenericTreeItem *, wxArrayGenericTreeItems); - -// ---------------------------------------------------------------------------- -// constants -// ---------------------------------------------------------------------------- - -static const int NO_IMAGE = -1; - -static const int PIXELS_PER_UNIT = 10; - -// the margin between the item image and the item text -static const int MARGIN_BETWEEN_IMAGE_AND_TEXT = 4; - -// ----------------------------------------------------------------------------- -// private classes -// ----------------------------------------------------------------------------- - -// timer used for enabling in-place edit -class WXDLLEXPORT wxTreeRenameTimer: public wxTimer -{ -public: - // start editing the current item after half a second (if the mouse hasn't - // been clicked/moved) - enum { DELAY = 250 }; - - wxTreeRenameTimer( wxGenericTreeCtrl *owner ); - - virtual void Notify(); - -private: - wxGenericTreeCtrl *m_owner; - - DECLARE_NO_COPY_CLASS(wxTreeRenameTimer) -}; - -// control used for in-place edit -class WXDLLEXPORT wxTreeTextCtrl: public wxTextCtrl -{ -public: - wxTreeTextCtrl(wxGenericTreeCtrl *owner, wxGenericTreeItem *item); - - void EndEdit(bool discardChanges = false) - { - if ( discardChanges ) - { - StopEditing(); - } - else - { - m_aboutToFinish = true; - - // Notify the owner about the changes - AcceptChanges(); - - // Even if vetoed, close the control (consistent with MSW) - Finish(); - } - } - - void StopEditing() - { - Finish(); - m_owner->OnRenameCancelled(m_itemEdited); - } - const wxGenericTreeItem* item() const { return m_itemEdited; } - -protected: - void OnChar( wxKeyEvent &event ); - void OnKeyUp( wxKeyEvent &event ); - void OnKillFocus( wxFocusEvent &event ); - - bool AcceptChanges(); - void Finish(); - -private: - wxGenericTreeCtrl *m_owner; - wxGenericTreeItem *m_itemEdited; - wxString m_startValue; - bool m_finished; - bool m_aboutToFinish; - - DECLARE_EVENT_TABLE() - DECLARE_NO_COPY_CLASS(wxTreeTextCtrl) -}; - -// timer used to clear wxGenericTreeCtrl::m_findPrefix if no key was pressed -// for a sufficiently long time -class WXDLLEXPORT wxTreeFindTimer : public wxTimer -{ -public: - // reset the current prefix after half a second of inactivity - enum { DELAY = 500 }; - - wxTreeFindTimer( wxGenericTreeCtrl *owner ) { m_owner = owner; } - - virtual void Notify() { m_owner->m_findPrefix.clear(); } - -private: - wxGenericTreeCtrl *m_owner; - - DECLARE_NO_COPY_CLASS(wxTreeFindTimer) -}; - -// a tree item -class WXDLLEXPORT wxGenericTreeItem -{ -public: - // ctors & dtor - wxGenericTreeItem() { m_data = NULL; } - wxGenericTreeItem( wxGenericTreeItem *parent, - const wxString& text, - int image, - int selImage, - wxTreeItemData *data ); - - ~wxGenericTreeItem(); - - // trivial accessors - wxArrayGenericTreeItems& GetChildren() { return m_children; } - - const wxString& GetText() const { return m_text; } - int GetImage(wxTreeItemIcon which = wxTreeItemIcon_Normal) const - { return m_images[which]; } - wxTreeItemData *GetData() const { return m_data; } - - // returns the current image for the item (depending on its - // selected/expanded/whatever state) - int GetCurrentImage() const; - - void SetText( const wxString &text ); - void SetImage(int image, wxTreeItemIcon which) { m_images[which] = image; } - void SetData(wxTreeItemData *data) { m_data = data; } - - void SetHasPlus(bool has = true) { m_hasPlus = has; } - - void SetBold(bool bold) { m_isBold = bold; } - - int GetX() const { return m_x; } - int GetY() const { return m_y; } - - void SetX(int x) { m_x = x; } - void SetY(int y) { m_y = y; } - - int GetHeight() const { return m_height; } - int GetWidth() const { return m_width; } - - void SetHeight(int h) { m_height = h; } - void SetWidth(int w) { m_width = w; } - - wxGenericTreeItem *GetParent() const { return m_parent; } - - // operations - - // deletes all children notifying the treectrl about it - void DeleteChildren(wxGenericTreeCtrl *tree); - - // get count of all children (and grand children if 'recursively') - size_t GetChildrenCount(bool recursively = true) const; - - void Insert(wxGenericTreeItem *child, size_t index) - { m_children.Insert(child, index); } - - void GetSize( int &x, int &y, const wxGenericTreeCtrl* ); - - // return the item at given position (or NULL if no item), onButton is - // true if the point belongs to the item's button, otherwise it lies - // on the item's label - wxGenericTreeItem *HitTest( const wxPoint& point, - const wxGenericTreeCtrl *, - int &flags, - int level ); - - void Expand() { m_isCollapsed = false; } - void Collapse() { m_isCollapsed = true; } - - void SetHilight( bool set = true ) { m_hasHilight = set; } - - // status inquiries - bool HasChildren() const { return !m_children.IsEmpty(); } - bool IsSelected() const { return m_hasHilight != 0; } - bool IsExpanded() const { return !m_isCollapsed; } - bool HasPlus() const { return m_hasPlus || HasChildren(); } - bool IsBold() const { return m_isBold != 0; } - - // attributes - // get them - may be NULL - wxTreeItemAttr *GetAttributes() const { return m_attr; } - // get them ensuring that the pointer is not NULL - wxTreeItemAttr& Attr() - { - if ( !m_attr ) - { - m_attr = new wxTreeItemAttr; - m_ownsAttr = true; - } - return *m_attr; - } - // set them - void SetAttributes(wxTreeItemAttr *attr) - { - if ( m_ownsAttr ) delete m_attr; - m_attr = attr; - m_ownsAttr = false; - } - // set them and delete when done - void AssignAttributes(wxTreeItemAttr *attr) - { - SetAttributes(attr); - m_ownsAttr = true; - } - -private: - // since there can be very many of these, we save size by chosing - // the smallest representation for the elements and by ordering - // the members to avoid padding. - wxString m_text; // label to be rendered for item - - wxTreeItemData *m_data; // user-provided data - - wxArrayGenericTreeItems m_children; // list of children - wxGenericTreeItem *m_parent; // parent of this item - - wxTreeItemAttr *m_attr; // attributes??? - - // tree ctrl images for the normal, selected, expanded and - // expanded+selected states - int m_images[wxTreeItemIcon_Max]; - - wxCoord m_x; // (virtual) offset from top - wxCoord m_y; // (virtual) offset from left - int m_width; // width of this item - int m_height; // height of this item - - // use bitfields to save size - unsigned int m_isCollapsed :1; - unsigned int m_hasHilight :1; // same as focused - unsigned int m_hasPlus :1; // used for item which doesn't have - // children but has a [+] button - unsigned int m_isBold :1; // render the label in bold font - unsigned int m_ownsAttr :1; // delete attribute when done - - DECLARE_NO_COPY_CLASS(wxGenericTreeItem) -}; - -// ============================================================================= -// implementation -// ============================================================================= - -// ---------------------------------------------------------------------------- -// private functions -// ---------------------------------------------------------------------------- - -// translate the key or mouse event flags to the type of selection we're -// dealing with -static void EventFlagsToSelType(long style, - bool shiftDown, - bool ctrlDown, - bool &is_multiple, - bool &extended_select, - bool &unselect_others) -{ - is_multiple = (style & wxTR_MULTIPLE) != 0; - extended_select = shiftDown && is_multiple; - unselect_others = !(extended_select || (ctrlDown && is_multiple)); -} - -// check if the given item is under another one -static bool IsDescendantOf(const wxGenericTreeItem *parent, const wxGenericTreeItem *item) -{ - while ( item ) - { - if ( item == parent ) - { - // item is a descendant of parent - return true; - } - - item = item->GetParent(); - } - - return false; -} - -// ----------------------------------------------------------------------------- -// wxTreeRenameTimer (internal) -// ----------------------------------------------------------------------------- - -wxTreeRenameTimer::wxTreeRenameTimer( wxGenericTreeCtrl *owner ) -{ - m_owner = owner; -} - -void wxTreeRenameTimer::Notify() -{ - m_owner->OnRenameTimer(); -} - -//----------------------------------------------------------------------------- -// wxTreeTextCtrl (internal) -//----------------------------------------------------------------------------- - -BEGIN_EVENT_TABLE(wxTreeTextCtrl,wxTextCtrl) - EVT_CHAR (wxTreeTextCtrl::OnChar) - EVT_KEY_UP (wxTreeTextCtrl::OnKeyUp) - EVT_KILL_FOCUS (wxTreeTextCtrl::OnKillFocus) -END_EVENT_TABLE() - -wxTreeTextCtrl::wxTreeTextCtrl(wxGenericTreeCtrl *owner, - wxGenericTreeItem *item) - : m_itemEdited(item), m_startValue(item->GetText()) -{ - m_owner = owner; - m_finished = false; - m_aboutToFinish = false; - - int w = m_itemEdited->GetWidth(), - h = m_itemEdited->GetHeight(); - - int x, y; - m_owner->CalcScrolledPosition(item->GetX(), item->GetY(), &x, &y); - - int image_h = 0, - image_w = 0; - - int image = item->GetCurrentImage(); - if ( image != NO_IMAGE ) - { - if ( m_owner->m_imageListNormal ) - { - m_owner->m_imageListNormal->GetSize( image, image_w, image_h ); - image_w += MARGIN_BETWEEN_IMAGE_AND_TEXT; - } - else - { - wxFAIL_MSG(_T("you must create an image list to use images!")); - } - } - - // FIXME: what are all these hardcoded 4, 8 and 11s really? - x += image_w; - w -= image_w + 4; -#ifdef __WXMAC__ - wxSize bs = DoGetBestSize() ; - // edit control height - if ( h > bs.y - 8 ) - { - int diff = h - ( bs.y - 8 ) ; - h -= diff ; - y += diff / 2 ; - } -#endif - - (void)Create(m_owner, wxID_ANY, m_startValue, - wxPoint(x - 4, y - 4), wxSize(w + 11, h + 8)); -} - -bool wxTreeTextCtrl::AcceptChanges() -{ - const wxString value = GetValue(); - - if ( value == m_startValue ) - { - // nothing changed, always accept - // when an item remains unchanged, the owner - // needs to be notified that the user decided - // not to change the tree item label, and that - // the edit has been cancelled - - m_owner->OnRenameCancelled(m_itemEdited); - return true; - } - - if ( !m_owner->OnRenameAccept(m_itemEdited, value) ) - { - // vetoed by the user - return false; - } - - // accepted, do rename the item - m_owner->SetItemText(m_itemEdited, value); - - return true; -} - -void wxTreeTextCtrl::Finish() -{ - if ( !m_finished ) - { - m_owner->ResetTextControl(); - - wxPendingDelete.Append(this); - - m_finished = true; - - m_owner->SetFocus(); - } -} - -void wxTreeTextCtrl::OnChar( wxKeyEvent &event ) -{ - switch ( event.m_keyCode ) - { - case WXK_RETURN: - EndEdit(); - break; - - case WXK_ESCAPE: - StopEditing(); - break; - - default: - event.Skip(); - } -} - -void wxTreeTextCtrl::OnKeyUp( wxKeyEvent &event ) -{ - if ( !m_finished ) - { - // auto-grow the textctrl: - wxSize parentSize = m_owner->GetSize(); - wxPoint myPos = GetPosition(); - wxSize mySize = GetSize(); - int sx, sy; - GetTextExtent(GetValue() + _T("M"), &sx, &sy); - if (myPos.x + sx > parentSize.x) - sx = parentSize.x - myPos.x; - if (mySize.x > sx) - sx = mySize.x; - SetSize(sx, wxDefaultCoord); - } - - event.Skip(); -} - -void wxTreeTextCtrl::OnKillFocus( wxFocusEvent &event ) -{ - if ( !m_finished && !m_aboutToFinish ) - { - // We must finish regardless of success, otherwise we'll get - // focus problems: - Finish(); - - if ( !AcceptChanges() ) - m_owner->OnRenameCancelled( m_itemEdited ); - } - - // We must let the native text control handle focus, too, otherwise - // it could have problems with the cursor (e.g., in wxGTK). - event.Skip(); -} - -// ----------------------------------------------------------------------------- -// wxGenericTreeItem -// ----------------------------------------------------------------------------- - -wxGenericTreeItem::wxGenericTreeItem(wxGenericTreeItem *parent, - const wxString& text, - int image, int selImage, - wxTreeItemData *data) - : m_text(text) -{ - m_images[wxTreeItemIcon_Normal] = image; - m_images[wxTreeItemIcon_Selected] = selImage; - m_images[wxTreeItemIcon_Expanded] = NO_IMAGE; - m_images[wxTreeItemIcon_SelectedExpanded] = NO_IMAGE; - - m_data = data; - m_x = m_y = 0; - - m_isCollapsed = true; - m_hasHilight = false; - m_hasPlus = false; - m_isBold = false; - - m_parent = parent; - - m_attr = (wxTreeItemAttr *)NULL; - m_ownsAttr = false; - - // We don't know the height here yet. - m_width = 0; - m_height = 0; -} - -wxGenericTreeItem::~wxGenericTreeItem() -{ - delete m_data; - - if (m_ownsAttr) delete m_attr; - - wxASSERT_MSG( m_children.IsEmpty(), - wxT("please call DeleteChildren() before deleting the item") ); -} - -void wxGenericTreeItem::DeleteChildren(wxGenericTreeCtrl *tree) -{ - size_t count = m_children.Count(); - for ( size_t n = 0; n < count; n++ ) - { - wxGenericTreeItem *child = m_children[n]; - tree->SendDeleteEvent(child); - - child->DeleteChildren(tree); - if ( child == tree->m_select_me ) - tree->m_select_me = NULL; - delete child; - } - - m_children.Empty(); -} - -void wxGenericTreeItem::SetText( const wxString &text ) -{ - m_text = text; -} - -size_t wxGenericTreeItem::GetChildrenCount(bool recursively) const -{ - size_t count = m_children.Count(); - if ( !recursively ) - return count; - - size_t total = count; - for (size_t n = 0; n < count; ++n) - { - total += m_children[n]->GetChildrenCount(); - } - - return total; -} - -void wxGenericTreeItem::GetSize( int &x, int &y, - const wxGenericTreeCtrl *theButton ) -{ - int bottomY=m_y+theButton->GetLineHeight(this); - if ( y < bottomY ) y = bottomY; - int width = m_x + m_width; - if ( x < width ) x = width; - - if (IsExpanded()) - { - size_t count = m_children.Count(); - for ( size_t n = 0; n < count; ++n ) - { - m_children[n]->GetSize( x, y, theButton ); - } - } -} - -wxGenericTreeItem *wxGenericTreeItem::HitTest(const wxPoint& point, - const wxGenericTreeCtrl *theCtrl, - int &flags, - int level) -{ - // for a hidden root node, don't evaluate it, but do evaluate children - if ( !(level == 0 && theCtrl->HasFlag(wxTR_HIDE_ROOT)) ) - { - // evaluate the item - int h = theCtrl->GetLineHeight(this); - if ((point.y > m_y) && (point.y < m_y + h)) - { - int y_mid = m_y + h/2; - if (point.y < y_mid ) - flags |= wxTREE_HITTEST_ONITEMUPPERPART; - else - flags |= wxTREE_HITTEST_ONITEMLOWERPART; - - int xCross = m_x - theCtrl->GetSpacing(); -#ifdef __WXMAC__ - // according to the drawing code the triangels are drawn - // at -4 , -4 from the position up to +10/+10 max - if ((point.x > xCross-4) && (point.x < xCross+10) && - (point.y > y_mid-4) && (point.y < y_mid+10) && - HasPlus() && theCtrl->HasButtons() ) -#else - // 5 is the size of the plus sign - if ((point.x > xCross-6) && (point.x < xCross+6) && - (point.y > y_mid-6) && (point.y < y_mid+6) && - HasPlus() && theCtrl->HasButtons() ) -#endif - { - flags |= wxTREE_HITTEST_ONITEMBUTTON; - return this; - } - - if ((point.x >= m_x) && (point.x <= m_x+m_width)) - { - int image_w = -1; - int image_h; - - // assuming every image (normal and selected) has the same size! - if ( (GetImage() != NO_IMAGE) && theCtrl->m_imageListNormal ) - theCtrl->m_imageListNormal->GetSize(GetImage(), - image_w, image_h); - - if ((image_w != -1) && (point.x <= m_x + image_w + 1)) - flags |= wxTREE_HITTEST_ONITEMICON; - else - flags |= wxTREE_HITTEST_ONITEMLABEL; - - return this; - } - - if (point.x < m_x) - flags |= wxTREE_HITTEST_ONITEMINDENT; - if (point.x > m_x+m_width) - flags |= wxTREE_HITTEST_ONITEMRIGHT; - - return this; - } - - // if children are expanded, fall through to evaluate them - if (m_isCollapsed) return (wxGenericTreeItem*) NULL; - } - - // evaluate children - size_t count = m_children.Count(); - for ( size_t n = 0; n < count; n++ ) - { - wxGenericTreeItem *res = m_children[n]->HitTest( point, - theCtrl, - flags, - level + 1 ); - if ( res != NULL ) - return res; - } - - return (wxGenericTreeItem*) NULL; -} - -int wxGenericTreeItem::GetCurrentImage() const -{ - int image = NO_IMAGE; - if ( IsExpanded() ) - { - if ( IsSelected() ) - { - image = GetImage(wxTreeItemIcon_SelectedExpanded); - } - - if ( image == NO_IMAGE ) - { - // we usually fall back to the normal item, but try just the - // expanded one (and not selected) first in this case - image = GetImage(wxTreeItemIcon_Expanded); - } - } - else // not expanded - { - if ( IsSelected() ) - image = GetImage(wxTreeItemIcon_Selected); - } - - // maybe it doesn't have the specific image we want, - // try the default one instead - if ( image == NO_IMAGE ) image = GetImage(); - - return image; -} - -// ----------------------------------------------------------------------------- -// wxGenericTreeCtrl implementation -// ----------------------------------------------------------------------------- - -IMPLEMENT_DYNAMIC_CLASS(wxGenericTreeCtrl, wxControl) - -BEGIN_EVENT_TABLE(wxGenericTreeCtrl, wxTreeCtrlBase) - EVT_PAINT (wxGenericTreeCtrl::OnPaint) - EVT_SIZE (wxGenericTreeCtrl::OnSize) - EVT_MOUSE_EVENTS (wxGenericTreeCtrl::OnMouse) - EVT_CHAR (wxGenericTreeCtrl::OnChar) - EVT_SET_FOCUS (wxGenericTreeCtrl::OnSetFocus) - EVT_KILL_FOCUS (wxGenericTreeCtrl::OnKillFocus) - EVT_TREE_ITEM_GETTOOLTIP(wxID_ANY, wxGenericTreeCtrl::OnGetToolTip) -END_EVENT_TABLE() - -#if !defined(__WXMSW__) || defined(__WXUNIVERSAL__) -/* - * wxTreeCtrl has to be a real class or we have problems with - * the run-time information. - */ - -IMPLEMENT_DYNAMIC_CLASS(wxTreeCtrl, wxGenericTreeCtrl) -#endif - -// ----------------------------------------------------------------------------- -// construction/destruction -// ----------------------------------------------------------------------------- - -void wxGenericTreeCtrl::Init() -{ - m_current = - m_key_current = - m_anchor = - m_select_me = (wxGenericTreeItem *) NULL; - m_hasFocus = false; - m_dirty = false; - - m_lineHeight = 10; - m_indent = 15; - m_spacing = 18; - - m_hilightBrush = new wxBrush - ( - wxSystemSettings::GetColour - ( - wxSYS_COLOUR_HIGHLIGHT - ), - wxSOLID - ); - - m_hilightUnfocusedBrush = new wxBrush - ( - wxSystemSettings::GetColour - ( - wxSYS_COLOUR_BTNSHADOW - ), - wxSOLID - ); - - m_imageListButtons = NULL; - m_ownsImageListButtons = false; - - m_dragCount = 0; - m_isDragging = false; - m_dropTarget = m_oldSelection = NULL; - m_underMouse = NULL; - m_textCtrl = NULL; - - m_renameTimer = NULL; - m_freezeCount = 0; - - m_findTimer = NULL; - - m_dropEffectAboveItem = false; - - m_lastOnSame = false; - -#ifdef __WXMAC_CARBON__ - m_normalFont.MacCreateThemeFont( kThemeViewsFont ) ; -#else - m_normalFont = wxSystemSettings::GetFont( wxSYS_DEFAULT_GUI_FONT ); -#endif - m_boldFont = wxFont(m_normalFont.GetPointSize(), - m_normalFont.GetFamily(), - m_normalFont.GetStyle(), - wxBOLD, - m_normalFont.GetUnderlined(), - m_normalFont.GetFaceName(), - m_normalFont.GetEncoding()); -} - -bool wxGenericTreeCtrl::Create(wxWindow *parent, - wxWindowID id, - const wxPoint& pos, - const wxSize& size, - long style, - const wxValidator& validator, - const wxString& name ) -{ -#ifdef __WXMAC__ - int major,minor; - wxGetOsVersion( &major, &minor ); - - style &= ~wxTR_LINES_AT_ROOT; - style |= wxTR_NO_LINES; - if (major < 10) - style |= wxTR_ROW_LINES; - - if (style == 0 || style & wxTR_DEFAULT_STYLE) - style |= wxTR_FULL_ROW_HIGHLIGHT; - -#endif // __WXMAC__ -#ifdef __WXGTK20__ - style |= wxTR_NO_LINES; -#endif - - if ( !wxControl::Create( parent, id, pos, size, - style|wxHSCROLL|wxVSCROLL, - validator, - name ) ) - return false; - - // If the tree display has no buttons, but does have - // connecting lines, we can use a narrower layout. - // It may not be a good idea to force this... - if (!HasButtons() && !HasFlag(wxTR_NO_LINES)) - { - m_indent= 10; - m_spacing = 10; - } - - wxVisualAttributes attr = GetDefaultAttributes(); - SetOwnForegroundColour( attr.colFg ); - SetOwnBackgroundColour( attr.colBg ); - if (!m_hasFont) - SetOwnFont(attr.font); - - m_dottedPen = wxPen( wxT("grey"), 0, 0 ); - - SetInitialSize(size); - - return true; -} - -wxGenericTreeCtrl::~wxGenericTreeCtrl() -{ - delete m_hilightBrush; - delete m_hilightUnfocusedBrush; - - DeleteAllItems(); - - delete m_renameTimer; - delete m_findTimer; - - if (m_ownsImageListButtons) - delete m_imageListButtons; -} - -// ----------------------------------------------------------------------------- -// accessors -// ----------------------------------------------------------------------------- - -unsigned int wxGenericTreeCtrl::GetCount() const -{ - if ( !m_anchor ) - { - // the tree is empty - return 0; - } - - unsigned int count = m_anchor->GetChildrenCount(); - if ( !HasFlag(wxTR_HIDE_ROOT) ) - { - // take the root itself into account - count++; - } - - return count; -} - -void wxGenericTreeCtrl::SetIndent(unsigned int indent) -{ - m_indent = (unsigned short) indent; - m_dirty = true; -} - -size_t -wxGenericTreeCtrl::GetChildrenCount(const wxTreeItemId& item, - bool recursively) const -{ - wxCHECK_MSG( item.IsOk(), 0u, wxT("invalid tree item") ); - - return ((wxGenericTreeItem*) item.m_pItem)->GetChildrenCount(recursively); -} - -void wxGenericTreeCtrl::SetWindowStyle(const long styles) -{ - // Do not try to expand the root node if it hasn't been created yet - if (m_anchor && !HasFlag(wxTR_HIDE_ROOT) && (styles & wxTR_HIDE_ROOT)) - { - // if we will hide the root, make sure children are visible - m_anchor->SetHasPlus(); - m_anchor->Expand(); - CalculatePositions(); - } - - // right now, just sets the styles. Eventually, we may - // want to update the inherited styles, but right now - // none of the parents has updatable styles - m_windowStyle = styles; - m_dirty = true; -} - -// ----------------------------------------------------------------------------- -// functions to work with tree items -// ----------------------------------------------------------------------------- - -wxString wxGenericTreeCtrl::GetItemText(const wxTreeItemId& item) const -{ - wxCHECK_MSG( item.IsOk(), wxEmptyString, wxT("invalid tree item") ); - - return ((wxGenericTreeItem*) item.m_pItem)->GetText(); -} - -int wxGenericTreeCtrl::GetItemImage(const wxTreeItemId& item, - wxTreeItemIcon which) const -{ - wxCHECK_MSG( item.IsOk(), -1, wxT("invalid tree item") ); - - return ((wxGenericTreeItem*) item.m_pItem)->GetImage(which); -} - -wxTreeItemData *wxGenericTreeCtrl::GetItemData(const wxTreeItemId& item) const -{ - wxCHECK_MSG( item.IsOk(), NULL, wxT("invalid tree item") ); - - return ((wxGenericTreeItem*) item.m_pItem)->GetData(); -} - -wxColour wxGenericTreeCtrl::GetItemTextColour(const wxTreeItemId& item) const -{ - wxCHECK_MSG( item.IsOk(), wxNullColour, wxT("invalid tree item") ); - - wxGenericTreeItem *pItem = (wxGenericTreeItem*) item.m_pItem; - return pItem->Attr().GetTextColour(); -} - -wxColour wxGenericTreeCtrl::GetItemBackgroundColour(const wxTreeItemId& item) const -{ - wxCHECK_MSG( item.IsOk(), wxNullColour, wxT("invalid tree item") ); - - wxGenericTreeItem *pItem = (wxGenericTreeItem*) item.m_pItem; - return pItem->Attr().GetBackgroundColour(); -} - -wxFont wxGenericTreeCtrl::GetItemFont(const wxTreeItemId& item) const -{ - wxCHECK_MSG( item.IsOk(), wxNullFont, wxT("invalid tree item") ); - - wxGenericTreeItem *pItem = (wxGenericTreeItem*) item.m_pItem; - return pItem->Attr().GetFont(); -} - -void wxGenericTreeCtrl::SetItemText(const wxTreeItemId& item, const wxString& text) -{ - wxCHECK_RET( item.IsOk(), wxT("invalid tree item") ); - - wxClientDC dc(this); - wxGenericTreeItem *pItem = (wxGenericTreeItem*) item.m_pItem; - pItem->SetText(text); - CalculateSize(pItem, dc); - RefreshLine(pItem); -} - -void wxGenericTreeCtrl::SetItemImage(const wxTreeItemId& item, - int image, - wxTreeItemIcon which) -{ - wxCHECK_RET( item.IsOk(), wxT("invalid tree item") ); - - wxGenericTreeItem *pItem = (wxGenericTreeItem*) item.m_pItem; - pItem->SetImage(image, which); - - wxClientDC dc(this); - CalculateSize(pItem, dc); - RefreshLine(pItem); -} - -void wxGenericTreeCtrl::SetItemData(const wxTreeItemId& item, wxTreeItemData *data) -{ - wxCHECK_RET( item.IsOk(), wxT("invalid tree item") ); - - if (data) - data->SetId( item ); - - ((wxGenericTreeItem*) item.m_pItem)->SetData(data); -} - -void wxGenericTreeCtrl::SetItemHasChildren(const wxTreeItemId& item, bool has) -{ - wxCHECK_RET( item.IsOk(), wxT("invalid tree item") ); - - wxGenericTreeItem *pItem = (wxGenericTreeItem*) item.m_pItem; - pItem->SetHasPlus(has); - RefreshLine(pItem); -} - -void wxGenericTreeCtrl::SetItemBold(const wxTreeItemId& item, bool bold) -{ - wxCHECK_RET( item.IsOk(), wxT("invalid tree item") ); - - // avoid redrawing the tree if no real change - wxGenericTreeItem *pItem = (wxGenericTreeItem*) item.m_pItem; - if ( pItem->IsBold() != bold ) - { - pItem->SetBold(bold); - - // recalculate the item size as bold and non bold fonts have different - // widths - wxClientDC dc(this); - CalculateSize(pItem, dc); - - RefreshLine(pItem); - } -} - -void wxGenericTreeCtrl::SetItemDropHighlight(const wxTreeItemId& item, - bool highlight) -{ - wxCHECK_RET( item.IsOk(), wxT("invalid tree item") ); - - wxColour fg, bg; - - if (highlight) - { - bg = wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT); - fg = wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT); - } - - wxGenericTreeItem *pItem = (wxGenericTreeItem*) item.m_pItem; - pItem->Attr().SetTextColour(fg); - pItem->Attr().SetBackgroundColour(bg); - RefreshLine(pItem); -} - -void wxGenericTreeCtrl::SetItemTextColour(const wxTreeItemId& item, - const wxColour& col) -{ - wxCHECK_RET( item.IsOk(), wxT("invalid tree item") ); - - wxGenericTreeItem *pItem = (wxGenericTreeItem*) item.m_pItem; - pItem->Attr().SetTextColour(col); - RefreshLine(pItem); -} - -void wxGenericTreeCtrl::SetItemBackgroundColour(const wxTreeItemId& item, - const wxColour& col) -{ - wxCHECK_RET( item.IsOk(), wxT("invalid tree item") ); - - wxGenericTreeItem *pItem = (wxGenericTreeItem*) item.m_pItem; - pItem->Attr().SetBackgroundColour(col); - RefreshLine(pItem); -} - -void wxGenericTreeCtrl::SetItemFont(const wxTreeItemId& item, const wxFont& font) -{ - wxCHECK_RET( item.IsOk(), wxT("invalid tree item") ); - - wxGenericTreeItem *pItem = (wxGenericTreeItem*) item.m_pItem; - pItem->Attr().SetFont(font); - RefreshLine(pItem); -} - -bool wxGenericTreeCtrl::SetFont( const wxFont &font ) -{ - wxTreeCtrlBase::SetFont(font); - - m_normalFont = font ; - m_boldFont = wxFont(m_normalFont.GetPointSize(), - m_normalFont.GetFamily(), - m_normalFont.GetStyle(), - wxBOLD, - m_normalFont.GetUnderlined(), - m_normalFont.GetFaceName(), - m_normalFont.GetEncoding()); - - return true; -} - - -// ----------------------------------------------------------------------------- -// item status inquiries -// ----------------------------------------------------------------------------- - -bool wxGenericTreeCtrl::IsVisible(const wxTreeItemId& item) const -{ - wxCHECK_MSG( item.IsOk(), false, wxT("invalid tree item") ); - - // An item is only visible if it's not a descendant of a collapsed item - wxGenericTreeItem *pItem = (wxGenericTreeItem*) item.m_pItem; - wxGenericTreeItem* parent = pItem->GetParent(); - while (parent) - { - if (!parent->IsExpanded()) - return false; - parent = parent->GetParent(); - } - - int startX, startY; - GetViewStart(& startX, & startY); - - wxSize clientSize = GetClientSize(); - - wxRect rect; - if (!GetBoundingRect(item, rect)) - return false; - if (rect.GetWidth() == 0 || rect.GetHeight() == 0) - return false; - if (rect.GetBottom() < 0 || rect.GetTop() > clientSize.y) - return false; - if (rect.GetRight() < 0 || rect.GetLeft() > clientSize.x) - return false; - - return true; -} - -bool wxGenericTreeCtrl::ItemHasChildren(const wxTreeItemId& item) const -{ - wxCHECK_MSG( item.IsOk(), false, wxT("invalid tree item") ); - - // consider that the item does have children if it has the "+" button: it - // might not have them (if it had never been expanded yet) but then it - // could have them as well and it's better to err on this side rather than - // disabling some operations which are restricted to the items with - // children for an item which does have them - return ((wxGenericTreeItem*) item.m_pItem)->HasPlus(); -} - -bool wxGenericTreeCtrl::IsExpanded(const wxTreeItemId& item) const -{ - wxCHECK_MSG( item.IsOk(), false, wxT("invalid tree item") ); - - return ((wxGenericTreeItem*) item.m_pItem)->IsExpanded(); -} - -bool wxGenericTreeCtrl::IsSelected(const wxTreeItemId& item) const -{ - wxCHECK_MSG( item.IsOk(), false, wxT("invalid tree item") ); - - return ((wxGenericTreeItem*) item.m_pItem)->IsSelected(); -} - -bool wxGenericTreeCtrl::IsBold(const wxTreeItemId& item) const -{ - wxCHECK_MSG( item.IsOk(), false, wxT("invalid tree item") ); - - return ((wxGenericTreeItem*) item.m_pItem)->IsBold(); -} - -// ----------------------------------------------------------------------------- -// navigation -// ----------------------------------------------------------------------------- - -wxTreeItemId wxGenericTreeCtrl::GetItemParent(const wxTreeItemId& item) const -{ - wxCHECK_MSG( item.IsOk(), wxTreeItemId(), wxT("invalid tree item") ); - - return ((wxGenericTreeItem*) item.m_pItem)->GetParent(); -} - -wxTreeItemId wxGenericTreeCtrl::GetFirstChild(const wxTreeItemId& item, - wxTreeItemIdValue& cookie) const -{ - wxCHECK_MSG( item.IsOk(), wxTreeItemId(), wxT("invalid tree item") ); - - cookie = 0; - return GetNextChild(item, cookie); -} - -wxTreeItemId wxGenericTreeCtrl::GetNextChild(const wxTreeItemId& item, - wxTreeItemIdValue& cookie) const -{ - wxCHECK_MSG( item.IsOk(), wxTreeItemId(), wxT("invalid tree item") ); - - wxArrayGenericTreeItems& children = ((wxGenericTreeItem*) item.m_pItem)->GetChildren(); - - // it's ok to cast cookie to size_t, we never have indices big enough to - // overflow "void *" - size_t *pIndex = (size_t *)&cookie; - if ( *pIndex < children.Count() ) - { - return children.Item((*pIndex)++); - } - else - { - // there are no more of them - return wxTreeItemId(); - } -} - -#if WXWIN_COMPATIBILITY_2_4 - -wxTreeItemId wxGenericTreeCtrl::GetFirstChild(const wxTreeItemId& item, - long& cookie) const -{ - wxCHECK_MSG( item.IsOk(), wxTreeItemId(), wxT("invalid tree item") ); - - cookie = 0; - return GetNextChild(item, cookie); -} - -wxTreeItemId wxGenericTreeCtrl::GetNextChild(const wxTreeItemId& item, - long& cookie) const -{ - wxCHECK_MSG( item.IsOk(), wxTreeItemId(), wxT("invalid tree item") ); - - wxArrayGenericTreeItems& children = ((wxGenericTreeItem*) item.m_pItem)->GetChildren(); - if ( (size_t)cookie < children.Count() ) - { - return children.Item((size_t)cookie++); - } - else - { - // there are no more of them - return wxTreeItemId(); - } -} - -#endif // WXWIN_COMPATIBILITY_2_4 - -wxTreeItemId wxGenericTreeCtrl::GetLastChild(const wxTreeItemId& item) const -{ - wxCHECK_MSG( item.IsOk(), wxTreeItemId(), wxT("invalid tree item") ); - - wxArrayGenericTreeItems& children = ((wxGenericTreeItem*) item.m_pItem)->GetChildren(); - return (children.IsEmpty() ? wxTreeItemId() : wxTreeItemId(children.Last())); -} - -wxTreeItemId wxGenericTreeCtrl::GetNextSibling(const wxTreeItemId& item) const -{ - wxCHECK_MSG( item.IsOk(), wxTreeItemId(), wxT("invalid tree item") ); - - wxGenericTreeItem *i = (wxGenericTreeItem*) item.m_pItem; - wxGenericTreeItem *parent = i->GetParent(); - if ( parent == NULL ) - { - // root item doesn't have any siblings - return wxTreeItemId(); - } - - wxArrayGenericTreeItems& siblings = parent->GetChildren(); - int index = siblings.Index(i); - wxASSERT( index != wxNOT_FOUND ); // I'm not a child of my parent? - - size_t n = (size_t)(index + 1); - return n == siblings.Count() ? wxTreeItemId() : wxTreeItemId(siblings[n]); -} - -wxTreeItemId wxGenericTreeCtrl::GetPrevSibling(const wxTreeItemId& item) const -{ - wxCHECK_MSG( item.IsOk(), wxTreeItemId(), wxT("invalid tree item") ); - - wxGenericTreeItem *i = (wxGenericTreeItem*) item.m_pItem; - wxGenericTreeItem *parent = i->GetParent(); - if ( parent == NULL ) - { - // root item doesn't have any siblings - return wxTreeItemId(); - } - - wxArrayGenericTreeItems& siblings = parent->GetChildren(); - int index = siblings.Index(i); - wxASSERT( index != wxNOT_FOUND ); // I'm not a child of my parent? - - return index == 0 ? wxTreeItemId() - : wxTreeItemId(siblings[(size_t)(index - 1)]); -} - -// Only for internal use right now, but should probably be public -wxTreeItemId wxGenericTreeCtrl::GetNext(const wxTreeItemId& item) const -{ - wxCHECK_MSG( item.IsOk(), wxTreeItemId(), wxT("invalid tree item") ); - - wxGenericTreeItem *i = (wxGenericTreeItem*) item.m_pItem; - - // First see if there are any children. - wxArrayGenericTreeItems& children = i->GetChildren(); - if (children.GetCount() > 0) - { - return children.Item(0); - } - else - { - // Try a sibling of this or ancestor instead - wxTreeItemId p = item; - wxTreeItemId toFind; - do - { - toFind = GetNextSibling(p); - p = GetItemParent(p); - } while (p.IsOk() && !toFind.IsOk()); - return toFind; - } -} - -wxTreeItemId wxGenericTreeCtrl::GetFirstVisibleItem() const -{ - wxTreeItemId id = GetRootItem(); - if (!id.IsOk()) - return id; - - do - { - if (IsVisible(id)) - return id; - id = GetNext(id); - } while (id.IsOk()); - - return wxTreeItemId(); -} - -wxTreeItemId wxGenericTreeCtrl::GetNextVisible(const wxTreeItemId& item) const -{ - wxCHECK_MSG( item.IsOk(), wxTreeItemId(), wxT("invalid tree item") ); - - wxTreeItemId id = item; - if (id.IsOk()) - { - while (id = GetNext(id), id.IsOk()) - { - if (IsVisible(id)) - return id; - } - } - return wxTreeItemId(); -} - -wxTreeItemId wxGenericTreeCtrl::GetPrevVisible(const wxTreeItemId& item) const -{ - wxCHECK_MSG( item.IsOk(), wxTreeItemId(), wxT("invalid tree item") ); - - wxFAIL_MSG(wxT("not implemented")); - - return wxTreeItemId(); -} - -// called by wxTextTreeCtrl when it marks itself for deletion -void wxGenericTreeCtrl::ResetTextControl() -{ - m_textCtrl = NULL; -} - -// find the first item starting with the given prefix after the given item -wxTreeItemId wxGenericTreeCtrl::FindItem(const wxTreeItemId& idParent, - const wxString& prefixOrig) const -{ - // match is case insensitive as this is more convenient to the user: having - // to press Shift-letter to go to the item starting with a capital letter - // would be too bothersome - wxString prefix = prefixOrig.Lower(); - - // determine the starting point: we shouldn't take the current item (this - // allows to switch between two items starting with the same letter just by - // pressing it) but we shouldn't jump to the next one if the user is - // continuing to type as otherwise he might easily skip the item he wanted - wxTreeItemId id = idParent; - if ( prefix.length() == 1 ) - { - id = GetNext(id); - } - - // look for the item starting with the given prefix after it - while ( id.IsOk() && !GetItemText(id).Lower().StartsWith(prefix) ) - { - id = GetNext(id); - } - - // if we haven't found anything... - if ( !id.IsOk() ) - { - // ... wrap to the beginning - id = GetRootItem(); - if ( HasFlag(wxTR_HIDE_ROOT) ) - { - // can't select virtual root - id = GetNext(id); - } - - // and try all the items (stop when we get to the one we started from) - while (id.IsOk() && id != idParent && !GetItemText(id).Lower().StartsWith(prefix) ) - { - id = GetNext(id); - } - // If we haven't found the item, id.IsOk() will be false, as per - // documentation - } - - return id; -} - -// ----------------------------------------------------------------------------- -// operations -// ----------------------------------------------------------------------------- - -wxTreeItemId wxGenericTreeCtrl::DoInsertItem(const wxTreeItemId& parentId, - size_t previous, - const wxString& text, - int image, - int selImage, - wxTreeItemData *data) -{ - wxGenericTreeItem *parent = (wxGenericTreeItem*) parentId.m_pItem; - if ( !parent ) - { - // should we give a warning here? - return AddRoot(text, image, selImage, data); - } - - m_dirty = true; // do this first so stuff below doesn't cause flicker - - wxGenericTreeItem *item = - new wxGenericTreeItem( parent, text, image, selImage, data ); - - if ( data != NULL ) - { - data->m_pItem = item; - } - - parent->Insert( item, previous == (size_t)-1 ? parent->GetChildren().size() - : previous ); - - InvalidateBestSize(); - return item; -} - -wxTreeItemId wxGenericTreeCtrl::AddRoot(const wxString& text, - int image, - int selImage, - wxTreeItemData *data) -{ - wxCHECK_MSG( !m_anchor, wxTreeItemId(), wxT("tree can have only one root") ); - - m_dirty = true; // do this first so stuff below doesn't cause flicker - - m_anchor = new wxGenericTreeItem((wxGenericTreeItem *)NULL, text, - image, selImage, data); - if ( data != NULL ) - { - data->m_pItem = m_anchor; - } - - if (HasFlag(wxTR_HIDE_ROOT)) - { - // if root is hidden, make sure we can navigate - // into children - m_anchor->SetHasPlus(); - m_anchor->Expand(); - CalculatePositions(); - } - - if (!HasFlag(wxTR_MULTIPLE)) - { - m_current = m_key_current = m_anchor; - m_current->SetHilight( true ); - } - - InvalidateBestSize(); - return m_anchor; -} - -wxTreeItemId wxGenericTreeCtrl::DoInsertAfter(const wxTreeItemId& parentId, - const wxTreeItemId& idPrevious, - const wxString& text, - int image, int selImage, - wxTreeItemData *data) -{ - wxGenericTreeItem *parent = (wxGenericTreeItem*) parentId.m_pItem; - if ( !parent ) - { - // should we give a warning here? - return AddRoot(text, image, selImage, data); - } - - int index = -1; - if (idPrevious.IsOk()) - { - index = parent->GetChildren().Index((wxGenericTreeItem*) idPrevious.m_pItem); - wxASSERT_MSG( index != wxNOT_FOUND, - wxT("previous item in wxGenericTreeCtrl::InsertItem() is not a sibling") ); - } - - return DoInsertItem(parentId, (size_t)++index, text, image, selImage, data); -} - - -void wxGenericTreeCtrl::SendDeleteEvent(wxGenericTreeItem *item) -{ - wxTreeEvent event(wxEVT_COMMAND_TREE_DELETE_ITEM, this, item); - ProcessEvent( event ); -} - -// Don't leave edit or selection on a child which is about to disappear -void wxGenericTreeCtrl::ChildrenClosing(wxGenericTreeItem* item) -{ - if (m_textCtrl != NULL && item != m_textCtrl->item() && IsDescendantOf(item, m_textCtrl->item())) { - m_textCtrl->StopEditing(); - } - if (item != m_key_current && IsDescendantOf(item, m_key_current)) { - m_key_current = NULL; - } - if (IsDescendantOf(item, m_select_me)) { - m_select_me = item; - } - if (item != m_current && IsDescendantOf(item, m_current)) { - m_current->SetHilight( false ); - m_current = NULL; - m_select_me = item; - } -} - -void wxGenericTreeCtrl::DeleteChildren(const wxTreeItemId& itemId) -{ - m_dirty = true; // do this first so stuff below doesn't cause flicker - - wxGenericTreeItem *item = (wxGenericTreeItem*) itemId.m_pItem; - ChildrenClosing(item); - item->DeleteChildren(this); - InvalidateBestSize(); -} - -void wxGenericTreeCtrl::Delete(const wxTreeItemId& itemId) -{ - m_dirty = true; // do this first so stuff below doesn't cause flicker - - wxGenericTreeItem *item = (wxGenericTreeItem*) itemId.m_pItem; - - if (m_textCtrl != NULL && IsDescendantOf(item, m_textCtrl->item())) - { - // can't delete the item being edited, cancel editing it first - m_textCtrl->StopEditing(); - } - - wxGenericTreeItem *parent = item->GetParent(); - - // don't keep stale pointers around! - if ( IsDescendantOf(item, m_key_current) ) - { - // Don't silently change the selection: - // do it properly in idle time, so event - // handlers get called. - - // m_key_current = parent; - m_key_current = NULL; - } - - // m_select_me records whether we need to select - // a different item, in idle time. - if ( m_select_me && IsDescendantOf(item, m_select_me) ) - { - m_select_me = parent; - } - - if ( IsDescendantOf(item, m_current) ) - { - // Don't silently change the selection: - // do it properly in idle time, so event - // handlers get called. - - // m_current = parent; - m_current = NULL; - m_select_me = parent; - } - - // remove the item from the tree - if ( parent ) - { - parent->GetChildren().Remove( item ); // remove by value - } - else // deleting the root - { - // nothing will be left in the tree - m_anchor = NULL; - } - - // and delete all of its children and the item itself now - item->DeleteChildren(this); - SendDeleteEvent(item); - - if (item == m_select_me) - m_select_me = NULL; - - delete item; - - InvalidateBestSize(); -} - -void wxGenericTreeCtrl::DeleteAllItems() -{ - if ( m_anchor ) - { - Delete(m_anchor); - } -} - -void wxGenericTreeCtrl::Expand(const wxTreeItemId& itemId) -{ - wxGenericTreeItem *item = (wxGenericTreeItem*) itemId.m_pItem; - - wxCHECK_RET( item, _T("invalid item in wxGenericTreeCtrl::Expand") ); - wxCHECK_RET( !HasFlag(wxTR_HIDE_ROOT) || itemId != GetRootItem(), - _T("can't expand hidden root") ); - - if ( !item->HasPlus() ) - return; - - if ( item->IsExpanded() ) - return; - - wxTreeEvent event(wxEVT_COMMAND_TREE_ITEM_EXPANDING, this, item); - - if ( ProcessEvent( event ) && !event.IsAllowed() ) - { - // cancelled by program - return; - } - - item->Expand(); - CalculatePositions(); - - RefreshSubtree(item); - - event.SetEventType(wxEVT_COMMAND_TREE_ITEM_EXPANDED); - ProcessEvent( event ); -} - -void wxGenericTreeCtrl::Collapse(const wxTreeItemId& itemId) -{ - wxCHECK_RET( !HasFlag(wxTR_HIDE_ROOT) || itemId != GetRootItem(), - _T("can't collapse hidden root") ); - - wxGenericTreeItem *item = (wxGenericTreeItem*) itemId.m_pItem; - - if ( !item->IsExpanded() ) - return; - - wxTreeEvent event(wxEVT_COMMAND_TREE_ITEM_COLLAPSING, this, item); - if ( ProcessEvent( event ) && !event.IsAllowed() ) - { - // cancelled by program - return; - } - - ChildrenClosing(item); - item->Collapse(); - -#if 0 // TODO why should items be collapsed recursively? - wxArrayGenericTreeItems& children = item->GetChildren(); - size_t count = children.Count(); - for ( size_t n = 0; n < count; n++ ) - { - Collapse(children[n]); - } -#endif - - CalculatePositions(); - - RefreshSubtree(item); - - event.SetEventType(wxEVT_COMMAND_TREE_ITEM_COLLAPSED); - ProcessEvent( event ); -} - -void wxGenericTreeCtrl::CollapseAndReset(const wxTreeItemId& item) -{ - Collapse(item); - DeleteChildren(item); -} - -void wxGenericTreeCtrl::Toggle(const wxTreeItemId& itemId) -{ - wxGenericTreeItem *item = (wxGenericTreeItem*) itemId.m_pItem; - - if (item->IsExpanded()) - Collapse(itemId); - else - Expand(itemId); -} - -void wxGenericTreeCtrl::Unselect() -{ - if (m_current) - { - m_current->SetHilight( false ); - RefreshLine( m_current ); - - m_current = NULL; - m_select_me = NULL; - } -} - -void wxGenericTreeCtrl::UnselectAllChildren(wxGenericTreeItem *item) -{ - if (item->IsSelected()) - { - item->SetHilight(false); - RefreshLine(item); - } - - if (item->HasChildren()) - { - wxArrayGenericTreeItems& children = item->GetChildren(); - size_t count = children.Count(); - for ( size_t n = 0; n < count; ++n ) - { - UnselectAllChildren(children[n]); - } - } -} - -void wxGenericTreeCtrl::UnselectAll() -{ - wxTreeItemId rootItem = GetRootItem(); - - // the tree might not have the root item at all - if ( rootItem ) - { - UnselectAllChildren((wxGenericTreeItem*) rootItem.m_pItem); - } -} - -// Recursive function ! -// To stop we must have crt_itemGetParent(); - - if (parent == NULL) // This is root item - return TagAllChildrenUntilLast(crt_item, last_item, select); - - wxArrayGenericTreeItems& children = parent->GetChildren(); - int index = children.Index(crt_item); - wxASSERT( index != wxNOT_FOUND ); // I'm not a child of my parent? - - size_t count = children.Count(); - for (size_t n=(size_t)(index+1); nSetHilight(select); - RefreshLine(crt_item); - - if (crt_item==last_item) - return true; - - if (crt_item->HasChildren()) - { - wxArrayGenericTreeItems& children = crt_item->GetChildren(); - size_t count = children.Count(); - for ( size_t n = 0; n < count; ++n ) - { - if (TagAllChildrenUntilLast(children[n], last_item, select)) - return true; - } - } - - return false; -} - -void wxGenericTreeCtrl::SelectItemRange(wxGenericTreeItem *item1, wxGenericTreeItem *item2) -{ - m_select_me = NULL; - - // item2 is not necessary after item1 - // choice first' and 'last' between item1 and item2 - wxGenericTreeItem *first= (item1->GetY()GetY()) ? item1 : item2; - wxGenericTreeItem *last = (item1->GetY()GetY()) ? item2 : item1; - - bool select = m_current->IsSelected(); - - if ( TagAllChildrenUntilLast(first,last,select) ) - return; - - TagNextChildren(first,last,select); -} - -void wxGenericTreeCtrl::DoSelectItem(const wxTreeItemId& itemId, - bool unselect_others, - bool extended_select) -{ - wxCHECK_RET( itemId.IsOk(), wxT("invalid tree item") ); - - m_select_me = NULL; - - bool is_single=!(GetWindowStyleFlag() & wxTR_MULTIPLE); - wxGenericTreeItem *item = (wxGenericTreeItem*) itemId.m_pItem; - - //wxCHECK_RET( ( (!unselect_others) && is_single), - // wxT("this is a single selection tree") ); - - // to keep going anyhow !!! - if (is_single) - { - if (item->IsSelected()) - return; // nothing to do - unselect_others = true; - extended_select = false; - } - else if ( unselect_others && item->IsSelected() ) - { - // selection change if there is more than one item currently selected - wxArrayTreeItemIds selected_items; - if ( GetSelections(selected_items) == 1 ) - return; - } - - wxTreeEvent event(wxEVT_COMMAND_TREE_SEL_CHANGING, this, item); - event.m_itemOld = m_current; - // TODO : Here we don't send any selection mode yet ! - - if ( GetEventHandler()->ProcessEvent( event ) && !event.IsAllowed() ) - return; - - wxTreeItemId parent = GetItemParent( itemId ); - while (parent.IsOk()) - { - if (!IsExpanded(parent)) - Expand( parent ); - - parent = GetItemParent( parent ); - } - - // ctrl press - if (unselect_others) - { - if (is_single) Unselect(); // to speed up thing - else UnselectAll(); - } - - // shift press - if (extended_select) - { - if ( !m_current ) - { - m_current = m_key_current = (wxGenericTreeItem*) GetRootItem().m_pItem; - } - - // don't change the mark (m_current) - SelectItemRange(m_current, item); - } - else - { - bool select = true; // the default - - // Check if we need to toggle hilight (ctrl mode) - if (!unselect_others) - select=!item->IsSelected(); - - m_current = m_key_current = item; - m_current->SetHilight(select); - RefreshLine( m_current ); - } - - // This can cause idle processing to select the root - // if no item is selected, so it must be after the - // selection is set - EnsureVisible( itemId ); - - event.SetEventType(wxEVT_COMMAND_TREE_SEL_CHANGED); - GetEventHandler()->ProcessEvent( event ); -} - -void wxGenericTreeCtrl::SelectItem(const wxTreeItemId& itemId, bool select) -{ - if ( select ) - { - DoSelectItem(itemId, !HasFlag(wxTR_MULTIPLE)); - } - else // deselect - { - wxGenericTreeItem *item = (wxGenericTreeItem*) itemId.m_pItem; - wxCHECK_RET( item, wxT("SelectItem(): invalid tree item") ); - - wxTreeEvent event(wxEVT_COMMAND_TREE_SEL_CHANGING, this, item); - if ( GetEventHandler()->ProcessEvent( event ) && !event.IsAllowed() ) - return; - - item->SetHilight(false); - RefreshLine(item); - - event.SetEventType(wxEVT_COMMAND_TREE_SEL_CHANGED); - GetEventHandler()->ProcessEvent( event ); - } -} - -void wxGenericTreeCtrl::FillArray(wxGenericTreeItem *item, - wxArrayTreeItemIds &array) const -{ - if ( item->IsSelected() ) - array.Add(wxTreeItemId(item)); - - if ( item->HasChildren() ) - { - wxArrayGenericTreeItems& children = item->GetChildren(); - size_t count = children.GetCount(); - for ( size_t n = 0; n < count; ++n ) - FillArray(children[n], array); - } -} - -size_t wxGenericTreeCtrl::GetSelections(wxArrayTreeItemIds &array) const -{ - array.Empty(); - wxTreeItemId idRoot = GetRootItem(); - if ( idRoot.IsOk() ) - { - FillArray((wxGenericTreeItem*) idRoot.m_pItem, array); - } - //else: the tree is empty, so no selections - - return array.Count(); -} - -void wxGenericTreeCtrl::EnsureVisible(const wxTreeItemId& item) -{ - wxCHECK_RET( item.IsOk(), wxT("invalid tree item") ); - - if (!item.IsOk()) return; - - wxGenericTreeItem *gitem = (wxGenericTreeItem*) item.m_pItem; - - // first expand all parent branches - wxGenericTreeItem *parent = gitem->GetParent(); - - if ( HasFlag(wxTR_HIDE_ROOT) ) - { - while ( parent && parent != m_anchor ) - { - Expand(parent); - parent = parent->GetParent(); - } - } - else - { - while ( parent ) - { - Expand(parent); - parent = parent->GetParent(); - } - } - - //if (parent) CalculatePositions(); - - ScrollTo(item); -} - -void wxGenericTreeCtrl::ScrollTo(const wxTreeItemId &item) -{ - if (!item.IsOk()) return; - - // We have to call this here because the label in - // question might just have been added and no screen - // update taken place. - if (m_dirty) -#if defined( __WXMSW__ ) || defined(__WXMAC__) - Update(); -#else - DoDirtyProcessing(); -#endif - wxGenericTreeItem *gitem = (wxGenericTreeItem*) item.m_pItem; - - // now scroll to the item - int item_y = gitem->GetY(); - - int start_x = 0; - int start_y = 0; - GetViewStart( &start_x, &start_y ); - start_y *= PIXELS_PER_UNIT; - - int client_h = 0; - int client_w = 0; - GetClientSize( &client_w, &client_h ); - - if (item_y < start_y+3) - { - // going down - int x = 0; - int y = 0; - m_anchor->GetSize( x, y, this ); - y += PIXELS_PER_UNIT+2; // one more scrollbar unit + 2 pixels - x += PIXELS_PER_UNIT+2; // one more scrollbar unit + 2 pixels - int x_pos = GetScrollPos( wxHORIZONTAL ); - // Item should appear at top - SetScrollbars( PIXELS_PER_UNIT, PIXELS_PER_UNIT, x/PIXELS_PER_UNIT, y/PIXELS_PER_UNIT, x_pos, item_y/PIXELS_PER_UNIT ); - } - else if (item_y+GetLineHeight(gitem) > start_y+client_h) - { - // going up - int x = 0; - int y = 0; - m_anchor->GetSize( x, y, this ); - y += PIXELS_PER_UNIT+2; // one more scrollbar unit + 2 pixels - x += PIXELS_PER_UNIT+2; // one more scrollbar unit + 2 pixels - item_y += PIXELS_PER_UNIT+2; - int x_pos = GetScrollPos( wxHORIZONTAL ); - // Item should appear at bottom - SetScrollbars( PIXELS_PER_UNIT, PIXELS_PER_UNIT, x/PIXELS_PER_UNIT, y/PIXELS_PER_UNIT, x_pos, (item_y+GetLineHeight(gitem)-client_h)/PIXELS_PER_UNIT ); - } -} - -// FIXME: tree sorting functions are not reentrant and not MT-safe! -static wxGenericTreeCtrl *s_treeBeingSorted = NULL; - -static int LINKAGEMODE tree_ctrl_compare_func(wxGenericTreeItem **item1, - wxGenericTreeItem **item2) -{ - wxCHECK_MSG( s_treeBeingSorted, 0, wxT("bug in wxGenericTreeCtrl::SortChildren()") ); - - return s_treeBeingSorted->OnCompareItems(*item1, *item2); -} - -void wxGenericTreeCtrl::SortChildren(const wxTreeItemId& itemId) -{ - wxCHECK_RET( itemId.IsOk(), wxT("invalid tree item") ); - - wxGenericTreeItem *item = (wxGenericTreeItem*) itemId.m_pItem; - - wxCHECK_RET( !s_treeBeingSorted, - wxT("wxGenericTreeCtrl::SortChildren is not reentrant") ); - - wxArrayGenericTreeItems& children = item->GetChildren(); - if ( children.Count() > 1 ) - { - m_dirty = true; - - s_treeBeingSorted = this; - children.Sort(tree_ctrl_compare_func); - s_treeBeingSorted = NULL; - } - //else: don't make the tree dirty as nothing changed -} - -void wxGenericTreeCtrl::CalculateLineHeight() -{ - wxClientDC dc(this); - m_lineHeight = (int)(dc.GetCharHeight() + 4); - - if ( m_imageListNormal ) - { - // Calculate a m_lineHeight value from the normal Image sizes. - // May be toggle off. Then wxGenericTreeCtrl will spread when - // necessary (which might look ugly). - int n = m_imageListNormal->GetImageCount(); - for (int i = 0; i < n ; i++) - { - int width = 0, height = 0; - m_imageListNormal->GetSize(i, width, height); - if (height > m_lineHeight) m_lineHeight = height; - } - } - - if (m_imageListButtons) - { - // Calculate a m_lineHeight value from the Button image sizes. - // May be toggle off. Then wxGenericTreeCtrl will spread when - // necessary (which might look ugly). - int n = m_imageListButtons->GetImageCount(); - for (int i = 0; i < n ; i++) - { - int width = 0, height = 0; - m_imageListButtons->GetSize(i, width, height); - if (height > m_lineHeight) m_lineHeight = height; - } - } - - if (m_lineHeight < 30) - m_lineHeight += 2; // at least 2 pixels - else - m_lineHeight += m_lineHeight/10; // otherwise 10% extra spacing -} - -void wxGenericTreeCtrl::SetImageList(wxImageList *imageList) -{ - if (m_ownsImageListNormal) delete m_imageListNormal; - m_imageListNormal = imageList; - m_ownsImageListNormal = false; - m_dirty = true; - // Don't do any drawing if we're setting the list to NULL, - // since we may be in the process of deleting the tree control. - if (imageList) - CalculateLineHeight(); -} - -void wxGenericTreeCtrl::SetStateImageList(wxImageList *imageList) -{ - if (m_ownsImageListState) delete m_imageListState; - m_imageListState = imageList; - m_ownsImageListState = false; -} - -void wxGenericTreeCtrl::SetButtonsImageList(wxImageList *imageList) -{ - if (m_ownsImageListButtons) delete m_imageListButtons; - m_imageListButtons = imageList; - m_ownsImageListButtons = false; - m_dirty = true; - CalculateLineHeight(); -} - -void wxGenericTreeCtrl::AssignButtonsImageList(wxImageList *imageList) -{ - SetButtonsImageList(imageList); - m_ownsImageListButtons = true; -} - -// ----------------------------------------------------------------------------- -// helpers -// ----------------------------------------------------------------------------- - -void wxGenericTreeCtrl::AdjustMyScrollbars() -{ - if (m_anchor) - { - int x = 0, y = 0; - m_anchor->GetSize( x, y, this ); - y += PIXELS_PER_UNIT+2; // one more scrollbar unit + 2 pixels - x += PIXELS_PER_UNIT+2; // one more scrollbar unit + 2 pixels - int x_pos = GetScrollPos( wxHORIZONTAL ); - int y_pos = GetScrollPos( wxVERTICAL ); - SetScrollbars( PIXELS_PER_UNIT, PIXELS_PER_UNIT, x/PIXELS_PER_UNIT, y/PIXELS_PER_UNIT, x_pos, y_pos ); - } - else - { - SetScrollbars( 0, 0, 0, 0 ); - } -} - -int wxGenericTreeCtrl::GetLineHeight(wxGenericTreeItem *item) const -{ - if (GetWindowStyleFlag() & wxTR_HAS_VARIABLE_ROW_HEIGHT) - return item->GetHeight(); - else - return m_lineHeight; -} - -void wxGenericTreeCtrl::PaintItem(wxGenericTreeItem *item, wxDC& dc) -{ - // TODO implement "state" icon on items - - wxTreeItemAttr *attr = item->GetAttributes(); - if ( attr && attr->HasFont() ) - dc.SetFont(attr->GetFont()); - else if (item->IsBold()) - dc.SetFont(m_boldFont); - - long text_w = 0, text_h = 0; - dc.GetTextExtent( item->GetText(), &text_w, &text_h ); - - int image_h = 0, image_w = 0; - int image = item->GetCurrentImage(); - if ( image != NO_IMAGE ) - { - if ( m_imageListNormal ) - { - m_imageListNormal->GetSize( image, image_w, image_h ); - image_w += MARGIN_BETWEEN_IMAGE_AND_TEXT; - } - else - { - image = NO_IMAGE; - } - } - - int total_h = GetLineHeight(item); - bool drawItemBackground = false; - - if ( item->IsSelected() ) - { - dc.SetBrush(*(m_hasFocus ? m_hilightBrush : m_hilightUnfocusedBrush)); - drawItemBackground = true; - } - else - { - wxColour colBg; - if ( attr && attr->HasBackgroundColour() ) - { - drawItemBackground = true; - colBg = attr->GetBackgroundColour(); - } - else - { - colBg = GetBackgroundColour(); - } - dc.SetBrush(wxBrush(colBg, wxSOLID)); - } - - int offset = HasFlag(wxTR_ROW_LINES) ? 1 : 0; - - if ( HasFlag(wxTR_FULL_ROW_HIGHLIGHT) ) - { - int x = 0, w = 0, h = 0; - GetVirtualSize(&w, &h); - wxRect rect( x, item->GetY()+offset, w, total_h-offset); -#if !defined(__WXGTK20__) && !defined(__WXMAC__) - dc.DrawRectangle(rect); -#else - if (!item->IsSelected()) - { - dc.DrawRectangle(rect); - } - else - { - int flags = wxCONTROL_SELECTED; - if (m_hasFocus -#ifdef __WXMAC__ - && IsControlActive( (ControlRef)GetHandle() ) -#endif - ) - flags |= wxCONTROL_FOCUSED; - if ((item == m_current) && (m_hasFocus)) - flags |= wxCONTROL_CURRENT; - wxRendererNative::Get().DrawItemSelectionRect( this, dc, rect, flags ); - } -#endif - } - else - { - if ( item->IsSelected() && image != NO_IMAGE ) - { - // If it's selected, and there's an image, then we should - // take care to leave the area under the image painted in the - // background colour. - wxRect rect( item->GetX() + image_w - 2, item->GetY()+offset, - item->GetWidth() - image_w + 2, total_h-offset ); -#if !defined(__WXGTK20__) && !defined(__WXMAC__) - dc.DrawRectangle( rect ); -#else - rect.x -= 1; - rect.width += 2; - - int flags = wxCONTROL_SELECTED; - if (m_hasFocus) - flags |= wxCONTROL_FOCUSED; - if ((item == m_current) && (m_hasFocus)) - flags |= wxCONTROL_CURRENT; - wxRendererNative::Get().DrawItemSelectionRect( this, dc, rect, flags ); -#endif - } - // On GTK+ 2, drawing a 'normal' background is wrong for themes that - // don't allow backgrounds to be customized. Not drawing the background, - // except for custom item backgrounds, works for both kinds of theme. - else if (drawItemBackground) - { - wxRect rect( item->GetX()-2, item->GetY()+offset, - item->GetWidth()+2, total_h-offset ); -#if !defined(__WXGTK20__) && !defined(__WXMAC__) - dc.DrawRectangle( rect ); -#else - if ( attr && attr->HasBackgroundColour() ) - { - dc.DrawRectangle( rect ); - } - else - { - rect.x -= 1; - rect.width += 2; - - int flags = wxCONTROL_SELECTED; - if (m_hasFocus) - flags |= wxCONTROL_FOCUSED; - if ((item == m_current) && (m_hasFocus)) - flags |= wxCONTROL_CURRENT; - wxRendererNative::Get().DrawItemSelectionRect( this, dc, rect, flags ); - } -#endif - } - } - - if ( image != NO_IMAGE ) - { - dc.SetClippingRegion( item->GetX(), item->GetY(), image_w-2, total_h ); - m_imageListNormal->Draw( image, dc, - item->GetX(), - item->GetY() +((total_h > image_h)?((total_h-image_h)/2):0), - wxIMAGELIST_DRAW_TRANSPARENT ); - dc.DestroyClippingRegion(); - } - - dc.SetBackgroundMode(wxTRANSPARENT); - int extraH = (total_h > text_h) ? (total_h - text_h)/2 : 0; - dc.DrawText( item->GetText(), - (wxCoord)(image_w + item->GetX()), - (wxCoord)(item->GetY() + extraH)); - - // restore normal font - dc.SetFont( m_normalFont ); -} - -// Now y stands for the top of the item, whereas it used to stand for middle ! -void wxGenericTreeCtrl::PaintLevel( wxGenericTreeItem *item, wxDC &dc, int level, int &y ) -{ - int x = level*m_indent; - if (!HasFlag(wxTR_HIDE_ROOT)) - { - x += m_indent; - } - else if (level == 0) - { - // always expand hidden root - int origY = y; - wxArrayGenericTreeItems& children = item->GetChildren(); - int count = children.Count(); - if (count > 0) - { - int n = 0, oldY; - do { - oldY = y; - PaintLevel(children[n], dc, 1, y); - } while (++n < count); - - if (!HasFlag(wxTR_NO_LINES) && HasFlag(wxTR_LINES_AT_ROOT) && count > 0) - { - // draw line down to last child - origY += GetLineHeight(children[0])>>1; - oldY += GetLineHeight(children[n-1])>>1; - dc.DrawLine(3, origY, 3, oldY); - } - } - return; - } - - item->SetX(x+m_spacing); - item->SetY(y); - - int h = GetLineHeight(item); - int y_top = y; - int y_mid = y_top + (h>>1); - y += h; - - int exposed_x = dc.LogicalToDeviceX(0); - int exposed_y = dc.LogicalToDeviceY(y_top); - - if (IsExposed(exposed_x, exposed_y, 10000, h)) // 10000 = very much - { - const wxPen *pen = -#ifndef __WXMAC__ - // don't draw rect outline if we already have the - // background color under Mac - (item->IsSelected() && m_hasFocus) ? wxBLACK_PEN : -#endif // !__WXMAC__ - wxTRANSPARENT_PEN; - - wxColour colText; - if ( item->IsSelected() -#ifdef __WXMAC__ - // On wxMac, if the tree doesn't have the focus we draw an empty - // rectangle, so we want to make sure that the text is visible - // against the normal background, not the highlightbackground, so - // don't use the highlight text colour unless we have the focus. - && m_hasFocus && IsControlActive( (ControlRef)GetHandle() ) -#endif - ) - { -#ifdef __WXMAC__ - colText = *wxWHITE; -#else - colText = wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT); -#endif - } - else - { - wxTreeItemAttr *attr = item->GetAttributes(); - if (attr && attr->HasTextColour()) - colText = attr->GetTextColour(); - else - colText = GetForegroundColour(); - } - - // prepare to draw - dc.SetTextForeground(colText); - dc.SetPen(*pen); - - // draw - PaintItem(item, dc); - - if (HasFlag(wxTR_ROW_LINES)) - { - // if the background colour is white, choose a - // contrasting color for the lines - dc.SetPen(*((GetBackgroundColour() == *wxWHITE) - ? wxMEDIUM_GREY_PEN : wxWHITE_PEN)); - dc.DrawLine(0, y_top, 10000, y_top); - dc.DrawLine(0, y, 10000, y); - } - - // restore DC objects - dc.SetBrush(*wxWHITE_BRUSH); - dc.SetPen(m_dottedPen); - dc.SetTextForeground(*wxBLACK); - - if ( !HasFlag(wxTR_NO_LINES) ) - { - // draw the horizontal line here - int x_start = x; - if (x > (signed)m_indent) - x_start -= m_indent; - else if (HasFlag(wxTR_LINES_AT_ROOT)) - x_start = 3; - dc.DrawLine(x_start, y_mid, x + m_spacing, y_mid); - } - - // should the item show a button? - if ( item->HasPlus() && HasButtons() ) - { - if ( m_imageListButtons ) - { - // draw the image button here - int image_h = 0, - image_w = 0; - int image = item->IsExpanded() ? wxTreeItemIcon_Expanded - : wxTreeItemIcon_Normal; - if ( item->IsSelected() ) - image += wxTreeItemIcon_Selected - wxTreeItemIcon_Normal; - - m_imageListButtons->GetSize(image, image_w, image_h); - int xx = x - image_w/2; - int yy = y_mid - image_h/2; - - wxDCClipper clip(dc, xx, yy, image_w, image_h); - m_imageListButtons->Draw(image, dc, xx, yy, - wxIMAGELIST_DRAW_TRANSPARENT); - } - else // no custom buttons - { - static const int wImage = 9; - static const int hImage = 9; - - int flag = 0; - if (item->IsExpanded()) - flag |= wxCONTROL_EXPANDED; - if (item == m_underMouse) - flag |= wxCONTROL_CURRENT; - - wxRendererNative::Get().DrawTreeItemButton - ( - this, - dc, - wxRect(x - wImage/2, - y_mid - hImage/2, - wImage, hImage), - flag - ); - } - } - } - - if (item->IsExpanded()) - { - wxArrayGenericTreeItems& children = item->GetChildren(); - int count = children.Count(); - if (count > 0) - { - int n = 0, oldY; - ++level; - do { - oldY = y; - PaintLevel(children[n], dc, level, y); - } while (++n < count); - - if (!HasFlag(wxTR_NO_LINES) && count > 0) - { - // draw line down to last child - oldY += GetLineHeight(children[n-1])>>1; - if (HasButtons()) y_mid += 5; - - // Only draw the portion of the line that is visible, in case it is huge - wxCoord xOrigin=0, yOrigin=0, width, height; - dc.GetDeviceOrigin(&xOrigin, &yOrigin); - yOrigin = abs(yOrigin); - GetClientSize(&width, &height); - - // Move end points to the begining/end of the view? - if (y_mid < yOrigin) - y_mid = yOrigin; - if (oldY > yOrigin + height) - oldY = yOrigin + height; - - // after the adjustments if y_mid is larger than oldY then the line - // isn't visible at all so don't draw anything - if (y_mid < oldY) - dc.DrawLine(x, y_mid, x, oldY); - } - } - } -} - -void wxGenericTreeCtrl::DrawDropEffect(wxGenericTreeItem *item) -{ - if ( item ) - { - if ( item->HasPlus() ) - { - // it's a folder, indicate it by a border - DrawBorder(item); - } - else - { - // draw a line under the drop target because the item will be - // dropped there - DrawLine(item, !m_dropEffectAboveItem ); - } - - SetCursor(wxCURSOR_BULLSEYE); - } - else - { - // can't drop here - SetCursor(wxCURSOR_NO_ENTRY); - } -} - -void wxGenericTreeCtrl::DrawBorder(const wxTreeItemId &item) -{ - wxCHECK_RET( item.IsOk(), _T("invalid item in wxGenericTreeCtrl::DrawLine") ); - - wxGenericTreeItem *i = (wxGenericTreeItem*) item.m_pItem; - - wxClientDC dc(this); - PrepareDC( dc ); - dc.SetLogicalFunction(wxINVERT); - dc.SetBrush(*wxTRANSPARENT_BRUSH); - - int w = i->GetWidth() + 2; - int h = GetLineHeight(i) + 2; - - dc.DrawRectangle( i->GetX() - 1, i->GetY() - 1, w, h); -} - -void wxGenericTreeCtrl::DrawLine(const wxTreeItemId &item, bool below) -{ - wxCHECK_RET( item.IsOk(), _T("invalid item in wxGenericTreeCtrl::DrawLine") ); - - wxGenericTreeItem *i = (wxGenericTreeItem*) item.m_pItem; - - wxClientDC dc(this); - PrepareDC( dc ); - dc.SetLogicalFunction(wxINVERT); - - int x = i->GetX(), - y = i->GetY(); - if ( below ) - { - y += GetLineHeight(i) - 1; - } - - dc.DrawLine( x, y, x + i->GetWidth(), y); -} - -// ----------------------------------------------------------------------------- -// wxWidgets callbacks -// ----------------------------------------------------------------------------- - -void wxGenericTreeCtrl::OnSize( wxSizeEvent &event ) -{ -#ifdef __WXGTK__ - if (HasFlag( wxTR_FULL_ROW_HIGHLIGHT) && m_current) - RefreshLine( m_current ); -#endif - - event.Skip(true); -} - -void wxGenericTreeCtrl::OnPaint( wxPaintEvent &WXUNUSED(event) ) -{ - wxPaintDC dc(this); - PrepareDC( dc ); - - if ( !m_anchor) - return; - - dc.SetFont( m_normalFont ); - dc.SetPen( m_dottedPen ); - - // this is now done dynamically - //if(GetImageList() == NULL) - // m_lineHeight = (int)(dc.GetCharHeight() + 4); - - int y = 2; - PaintLevel( m_anchor, dc, 0, y ); -} - -void wxGenericTreeCtrl::OnSetFocus( wxFocusEvent &event ) -{ - m_hasFocus = true; - - RefreshSelected(); - - event.Skip(); -} - -void wxGenericTreeCtrl::OnKillFocus( wxFocusEvent &event ) -{ - m_hasFocus = false; - - RefreshSelected(); - - event.Skip(); -} - -void wxGenericTreeCtrl::OnChar( wxKeyEvent &event ) -{ - wxTreeEvent te( wxEVT_COMMAND_TREE_KEY_DOWN, this); - te.m_evtKey = event; - if ( GetEventHandler()->ProcessEvent( te ) ) - { - // intercepted by the user code - return; - } - - if ( (m_current == 0) || (m_key_current == 0) ) - { - event.Skip(); - return; - } - - // how should the selection work for this event? - bool is_multiple, extended_select, unselect_others; - EventFlagsToSelType(GetWindowStyleFlag(), - event.ShiftDown(), - event.CmdDown(), - is_multiple, extended_select, unselect_others); - - if (GetLayoutDirection() == wxLayout_RightToLeft) - { - if (event.GetKeyCode() == WXK_RIGHT) - event.m_keyCode = WXK_LEFT; - else if (event.GetKeyCode() == WXK_LEFT) - event.m_keyCode = WXK_RIGHT; - } - - // + : Expand - // - : Collaspe - // * : Expand all/Collapse all - // ' ' | return : activate - // up : go up (not last children!) - // down : go down - // left : go to parent - // right : open if parent and go next - // home : go to root - // end : go to last item without opening parents - // alnum : start or continue searching for the item with this prefix - int keyCode = event.GetKeyCode(); - switch ( keyCode ) - { - case '+': - case WXK_ADD: - if (m_current->HasPlus() && !IsExpanded(m_current)) - { - Expand(m_current); - } - break; - - case '*': - case WXK_MULTIPLY: - if ( !IsExpanded(m_current) ) - { - // expand all - ExpandAllChildren(m_current); - break; - } - //else: fall through to Collapse() it - - case '-': - case WXK_SUBTRACT: - if (IsExpanded(m_current)) - { - Collapse(m_current); - } - break; - - case WXK_MENU: - { - // Use the item's bounding rectangle to determine position for the event - wxRect ItemRect; - GetBoundingRect(m_current, ItemRect, true); - - wxTreeEvent eventMenu(wxEVT_COMMAND_TREE_ITEM_MENU, this, m_current); - // Use the left edge, vertical middle - eventMenu.m_pointDrag = wxPoint(ItemRect.GetX(), - ItemRect.GetY() + ItemRect.GetHeight() / 2); - GetEventHandler()->ProcessEvent( eventMenu ); - } - break; - - case ' ': - case WXK_RETURN: - if ( !event.HasModifiers() ) - { - wxTreeEvent eventAct(wxEVT_COMMAND_TREE_ITEM_ACTIVATED, this, m_current); - GetEventHandler()->ProcessEvent( eventAct ); - } - - // in any case, also generate the normal key event for this key, - // even if we generated the ACTIVATED event above: this is what - // wxMSW does and it makes sense because you might not want to - // process ACTIVATED event at all and handle Space and Return - // directly (and differently) which would be impossible otherwise - event.Skip(); - break; - - // up goes to the previous sibling or to the last - // of its children if it's expanded - case WXK_UP: - { - wxTreeItemId prev = GetPrevSibling( m_key_current ); - if (!prev) - { - prev = GetItemParent( m_key_current ); - if ((prev == GetRootItem()) && HasFlag(wxTR_HIDE_ROOT)) - { - break; // don't go to root if it is hidden - } - if (prev) - { - wxTreeItemIdValue cookie; - wxTreeItemId current = m_key_current; - // TODO: Huh? If we get here, we'd better be the first child of our parent. How else could it be? - if (current == GetFirstChild( prev, cookie )) - { - // otherwise we return to where we came from - DoSelectItem( prev, unselect_others, extended_select ); - m_key_current= (wxGenericTreeItem*) prev.m_pItem; - break; - } - } - } - if (prev) - { - while ( IsExpanded(prev) && HasChildren(prev) ) - { - wxTreeItemId child = GetLastChild(prev); - if ( child ) - { - prev = child; - } - } - - DoSelectItem( prev, unselect_others, extended_select ); - m_key_current=(wxGenericTreeItem*) prev.m_pItem; - } - } - break; - - // left arrow goes to the parent - case WXK_LEFT: - { - wxTreeItemId prev = GetItemParent( m_current ); - if ((prev == GetRootItem()) && HasFlag(wxTR_HIDE_ROOT)) - { - // don't go to root if it is hidden - prev = GetPrevSibling( m_current ); - } - if (prev) - { - DoSelectItem( prev, unselect_others, extended_select ); - } - } - break; - - case WXK_RIGHT: - // this works the same as the down arrow except that we - // also expand the item if it wasn't expanded yet - if (m_current != GetRootItem().m_pItem || !HasFlag(wxTR_HIDE_ROOT)) - Expand(m_current); - //else: don't try to expand hidden root item (which can be the - // current one when the tree is empty) - - // fall through - - case WXK_DOWN: - { - if (IsExpanded(m_key_current) && HasChildren(m_key_current)) - { - wxTreeItemIdValue cookie; - wxTreeItemId child = GetFirstChild( m_key_current, cookie ); - if ( !child ) - break; - - DoSelectItem( child, unselect_others, extended_select ); - m_key_current=(wxGenericTreeItem*) child.m_pItem; - } - else - { - wxTreeItemId next = GetNextSibling( m_key_current ); - if (!next) - { - wxTreeItemId current = m_key_current; - while (current.IsOk() && !next) - { - current = GetItemParent( current ); - if (current) next = GetNextSibling( current ); - } - } - if (next) - { - DoSelectItem( next, unselect_others, extended_select ); - m_key_current=(wxGenericTreeItem*) next.m_pItem; - } - } - } - break; - - // selects the last visible tree item - case WXK_END: - { - wxTreeItemId last = GetRootItem(); - - while ( last.IsOk() && IsExpanded(last) ) - { - wxTreeItemId lastChild = GetLastChild(last); - - // it may happen if the item was expanded but then all of - // its children have been deleted - so IsExpanded() returned - // true, but GetLastChild() returned invalid item - if ( !lastChild ) - break; - - last = lastChild; - } - - if ( last.IsOk() ) - { - DoSelectItem( last, unselect_others, extended_select ); - } - } - break; - - // selects the root item - case WXK_HOME: - { - wxTreeItemId prev = GetRootItem(); - if (!prev) - break; - - if ( HasFlag(wxTR_HIDE_ROOT) ) - { - wxTreeItemIdValue cookie; - prev = GetFirstChild(prev, cookie); - if (!prev) - break; - } - - DoSelectItem( prev, unselect_others, extended_select ); - } - break; - - default: - // do not use wxIsalnum() here - if ( !event.HasModifiers() && - ((keyCode >= '0' && keyCode <= '9') || - (keyCode >= 'a' && keyCode <= 'z') || - (keyCode >= 'A' && keyCode <= 'Z' ))) - { - // find the next item starting with the given prefix - wxChar ch = (wxChar)keyCode; - - wxTreeItemId id = FindItem(m_current, m_findPrefix + ch); - if ( !id.IsOk() ) - { - // no such item - break; - } - - SelectItem(id); - - m_findPrefix += ch; - - // also start the timer to reset the current prefix if the user - // doesn't press any more alnum keys soon -- we wouldn't want - // to use this prefix for a new item search - if ( !m_findTimer ) - { - m_findTimer = new wxTreeFindTimer(this); - } - - m_findTimer->Start(wxTreeFindTimer::DELAY, wxTIMER_ONE_SHOT); - } - else - { - event.Skip(); - } - } -} - -wxTreeItemId -wxGenericTreeCtrl::DoTreeHitTest(const wxPoint& point, int& flags) const -{ - int w, h; - GetSize(&w, &h); - flags=0; - if (point.x<0) flags |= wxTREE_HITTEST_TOLEFT; - if (point.x>w) flags |= wxTREE_HITTEST_TORIGHT; - if (point.y<0) flags |= wxTREE_HITTEST_ABOVE; - if (point.y>h) flags |= wxTREE_HITTEST_BELOW; - if (flags) return wxTreeItemId(); - - if (m_anchor == NULL) - { - flags = wxTREE_HITTEST_NOWHERE; - return wxTreeItemId(); - } - - wxGenericTreeItem *hit = m_anchor->HitTest(CalcUnscrolledPosition(point), - this, flags, 0); - if (hit == NULL) - { - flags = wxTREE_HITTEST_NOWHERE; - return wxTreeItemId(); - } - return hit; -} - -// get the bounding rectangle of the item (or of its label only) -bool wxGenericTreeCtrl::GetBoundingRect(const wxTreeItemId& item, - wxRect& rect, - bool textOnly) const -{ - wxCHECK_MSG( item.IsOk(), false, _T("invalid item in wxGenericTreeCtrl::GetBoundingRect") ); - - wxGenericTreeItem *i = (wxGenericTreeItem*) item.m_pItem; - - if ( textOnly ) - { - rect.x = i->GetX(); - rect.width = i->GetWidth(); - - if ( m_imageListNormal ) - { - int image_w, image_h; - m_imageListNormal->GetSize( 0, image_w, image_h ); - rect.width += image_w + MARGIN_BETWEEN_IMAGE_AND_TEXT; - } - } - else // the entire line - { - rect.x = 0; - rect.width = GetClientSize().x; - } - - rect.y = i->GetY(); - rect.height = GetLineHeight(i); - - // we have to return the logical coordinates, not physical ones - rect.SetTopLeft(CalcScrolledPosition(rect.GetTopLeft())); - - return true; -} - -wxTextCtrl *wxGenericTreeCtrl::EditLabel(const wxTreeItemId& item, - wxClassInfo * WXUNUSED(textCtrlClass)) -{ - wxCHECK_MSG( item.IsOk(), NULL, _T("can't edit an invalid item") ); - - wxGenericTreeItem *itemEdit = (wxGenericTreeItem *)item.m_pItem; - - wxTreeEvent te(wxEVT_COMMAND_TREE_BEGIN_LABEL_EDIT, this, itemEdit); - if ( GetEventHandler()->ProcessEvent( te ) && !te.IsAllowed() ) - { - // vetoed by user - return NULL; - } - - // We have to call this here because the label in - // question might just have been added and no screen - // update taken place. - if ( m_dirty ) -#if defined( __WXMSW__ ) || defined(__WXMAC__) - Update(); -#else - DoDirtyProcessing(); -#endif - - // TODO: use textCtrlClass here to create the control of correct class - m_textCtrl = new wxTreeTextCtrl(this, itemEdit); - - m_textCtrl->SetFocus(); - - return m_textCtrl; -} - -// returns a pointer to the text edit control if the item is being -// edited, NULL otherwise (it's assumed that no more than one item may -// be edited simultaneously) -wxTextCtrl* wxGenericTreeCtrl::GetEditControl() const -{ - return m_textCtrl; -} - -void wxGenericTreeCtrl::EndEditLabel(const wxTreeItemId& WXUNUSED(item), - bool discardChanges) -{ - wxCHECK_RET( m_textCtrl, _T("not editing label") ); - - m_textCtrl->EndEdit(discardChanges); -} - -bool wxGenericTreeCtrl::OnRenameAccept(wxGenericTreeItem *item, - const wxString& value) -{ - wxTreeEvent le(wxEVT_COMMAND_TREE_END_LABEL_EDIT, this, item); - le.m_label = value; - le.m_editCancelled = false; - - return !GetEventHandler()->ProcessEvent( le ) || le.IsAllowed(); -} - -void wxGenericTreeCtrl::OnRenameCancelled(wxGenericTreeItem *item) -{ - // let owner know that the edit was cancelled - wxTreeEvent le(wxEVT_COMMAND_TREE_END_LABEL_EDIT, this, item); - le.m_label = wxEmptyString; - le.m_editCancelled = true; - - GetEventHandler()->ProcessEvent( le ); -} - -void wxGenericTreeCtrl::OnRenameTimer() -{ - EditLabel( m_current ); -} - -void wxGenericTreeCtrl::OnMouse( wxMouseEvent &event ) -{ - if ( !m_anchor )return; - - wxPoint pt = CalcUnscrolledPosition(event.GetPosition()); - - // Is the mouse over a tree item button? - int flags = 0; - wxGenericTreeItem *thisItem = m_anchor->HitTest(pt, this, flags, 0); - wxGenericTreeItem *underMouse = thisItem; -#if wxUSE_TOOLTIPS - bool underMouseChanged = (underMouse != m_underMouse) ; -#endif // wxUSE_TOOLTIPS - - if ((underMouse) && - (flags & wxTREE_HITTEST_ONITEMBUTTON) && - (!event.LeftIsDown()) && - (!m_isDragging) && - (!m_renameTimer || !m_renameTimer->IsRunning())) - { - } - else - { - underMouse = NULL; - } - - if (underMouse != m_underMouse) - { - if (m_underMouse) - { - // unhighlight old item - wxGenericTreeItem *tmp = m_underMouse; - m_underMouse = NULL; - RefreshLine( tmp ); - } - - m_underMouse = underMouse; - if (m_underMouse) - RefreshLine( m_underMouse ); - } - -#if wxUSE_TOOLTIPS - // Determines what item we are hovering over and need a tooltip for - wxTreeItemId hoverItem = thisItem; - - // We do not want a tooltip if we are dragging, or if the rename timer is running - if (underMouseChanged && hoverItem.IsOk() && !m_isDragging && (!m_renameTimer || !m_renameTimer->IsRunning())) - { - // Ask the tree control what tooltip (if any) should be shown - wxTreeEvent hevent(wxEVT_COMMAND_TREE_ITEM_GETTOOLTIP, this, hoverItem); - - if ( GetEventHandler()->ProcessEvent(hevent) && hevent.IsAllowed() ) - { - SetToolTip(hevent.m_label); - } - } -#endif - - // we process left mouse up event (enables in-place edit), middle/right down - // (pass to the user code), left dbl click (activate item) and - // dragging/moving events for items drag-and-drop - if ( !(event.LeftDown() || - event.LeftUp() || - event.MiddleDown() || - event.RightDown() || - event.LeftDClick() || - event.Dragging() || - ((event.Moving() || event.RightUp()) && m_isDragging)) ) - { - event.Skip(); - - return; - } - - - flags = 0; - wxGenericTreeItem *item = m_anchor->HitTest(pt, this, flags, 0); - - if ( event.Dragging() && !m_isDragging ) - { - if (m_dragCount == 0) - m_dragStart = pt; - - m_dragCount++; - - if (m_dragCount != 3) - { - // wait until user drags a bit further... - return; - } - - wxEventType command = event.RightIsDown() - ? wxEVT_COMMAND_TREE_BEGIN_RDRAG - : wxEVT_COMMAND_TREE_BEGIN_DRAG; - - wxTreeEvent nevent(command, this, m_current); - nevent.SetPoint(CalcScrolledPosition(pt)); - - // by default the dragging is not supported, the user code must - // explicitly allow the event for it to take place - nevent.Veto(); - - if ( GetEventHandler()->ProcessEvent(nevent) && nevent.IsAllowed() ) - { - // we're going to drag this item - m_isDragging = true; - - // remember the old cursor because we will change it while - // dragging - m_oldCursor = m_cursor; - - // in a single selection control, hide the selection temporarily - if ( !(GetWindowStyleFlag() & wxTR_MULTIPLE) ) - { - m_oldSelection = (wxGenericTreeItem*) GetSelection().m_pItem; - - if ( m_oldSelection ) - { - m_oldSelection->SetHilight(false); - RefreshLine(m_oldSelection); - } - } - - CaptureMouse(); - } - } - else if ( event.Dragging() ) - { - if ( item != m_dropTarget ) - { - // unhighlight the previous drop target - DrawDropEffect(m_dropTarget); - - m_dropTarget = item; - - // highlight the current drop target if any - DrawDropEffect(m_dropTarget); - -#if defined(__WXMSW__) || defined(__WXMAC__) || defined(__WXGTK20__) - Update(); -#else - wxYieldIfNeeded(); -#endif - } - } - else if ( (event.LeftUp() || event.RightUp()) && m_isDragging ) - { - ReleaseMouse(); - - // erase the highlighting - DrawDropEffect(m_dropTarget); - - if ( m_oldSelection ) - { - m_oldSelection->SetHilight(true); - RefreshLine(m_oldSelection); - m_oldSelection = (wxGenericTreeItem *)NULL; - } - - // generate the drag end event - wxTreeEvent eventEndDrag(wxEVT_COMMAND_TREE_END_DRAG, this, item); - - eventEndDrag.m_pointDrag = CalcScrolledPosition(pt); - - (void)GetEventHandler()->ProcessEvent(eventEndDrag); - - m_isDragging = false; - m_dropTarget = (wxGenericTreeItem *)NULL; - - SetCursor(m_oldCursor); - -#if defined( __WXMSW__ ) || defined(__WXMAC__) - Update(); -#else - wxYieldIfNeeded(); -#endif - } - else - { - // If we got to this point, we are not dragging or moving the mouse. - // Because the code in carbon/toplevel.cpp will only set focus to the tree - // if we skip for EVT_LEFT_DOWN, we MUST skip this event here for focus to work. - // We skip even if we didn't hit an item because we still should - // restore focus to the tree control even if we didn't exactly hit an item. - if ( event.LeftDown() ) - { - event.Skip(); - } - - // here we process only the messages which happen on tree items - - m_dragCount = 0; - - if (item == NULL) return; /* we hit the blank area */ - - if ( event.RightDown() ) - { - // If the item is already selected, do not update the selection. - // Multi-selections should not be cleared if a selected item is clicked. - if (!IsSelected(item)) - { - DoSelectItem(item, true, false); - } - - wxTreeEvent nevent(wxEVT_COMMAND_TREE_ITEM_RIGHT_CLICK, this, item); - nevent.m_pointDrag = CalcScrolledPosition(pt); - event.Skip(!GetEventHandler()->ProcessEvent(nevent)); - - // Consistent with MSW (for now), send the ITEM_MENU *after* - // the RIGHT_CLICK event. TODO: This behavior may change. - wxTreeEvent nevent2(wxEVT_COMMAND_TREE_ITEM_MENU, this, item); - nevent2.m_pointDrag = CalcScrolledPosition(pt); - GetEventHandler()->ProcessEvent(nevent2); - } - else if ( event.MiddleDown() ) - { - wxTreeEvent nevent(wxEVT_COMMAND_TREE_ITEM_MIDDLE_CLICK, this, item); - nevent.m_pointDrag = CalcScrolledPosition(pt); - event.Skip(!GetEventHandler()->ProcessEvent(nevent)); - } - else if ( event.LeftUp() ) - { - // this facilitates multiple-item drag-and-drop - - if ( /* item && */ HasFlag(wxTR_MULTIPLE)) - { - wxArrayTreeItemIds selections; - size_t count = GetSelections(selections); - - if (count > 1 && - !event.CmdDown() && - !event.ShiftDown()) - { - DoSelectItem(item, true, false); - } - } - - if ( m_lastOnSame ) - { - if ( (item == m_current) && - (flags & wxTREE_HITTEST_ONITEMLABEL) && - HasFlag(wxTR_EDIT_LABELS) ) - { - if ( m_renameTimer ) - { - if ( m_renameTimer->IsRunning() ) - m_renameTimer->Stop(); - } - else - { - m_renameTimer = new wxTreeRenameTimer( this ); - } - - m_renameTimer->Start( wxTreeRenameTimer::DELAY, true ); - } - - m_lastOnSame = false; - } - } - else // !RightDown() && !MiddleDown() && !LeftUp() ==> LeftDown() || LeftDClick() - { - if ( event.LeftDown() ) - { - m_lastOnSame = item == m_current; - } - - if ( flags & wxTREE_HITTEST_ONITEMBUTTON ) - { - // only toggle the item for a single click, double click on - // the button doesn't do anything (it toggles the item twice) - if ( event.LeftDown() ) - { - Toggle( item ); - } - - // don't select the item if the button was clicked - return; - } - - - // clear the previously selected items, if the - // user clicked outside of the present selection. - // otherwise, perform the deselection on mouse-up. - // this allows multiple drag and drop to work. - // but if Cmd is down, toggle selection of the clicked item - if (!IsSelected(item) || event.CmdDown()) - { - // how should the selection work for this event? - bool is_multiple, extended_select, unselect_others; - EventFlagsToSelType(GetWindowStyleFlag(), - event.ShiftDown(), - event.CmdDown(), - is_multiple, extended_select, unselect_others); - - DoSelectItem(item, unselect_others, extended_select); - } - - - // For some reason, Windows isn't recognizing a left double-click, - // so we need to simulate it here. Allow 200 milliseconds for now. - if ( event.LeftDClick() ) - { - // double clicking should not start editing the item label - if ( m_renameTimer ) - m_renameTimer->Stop(); - - m_lastOnSame = false; - - // send activate event first - wxTreeEvent nevent(wxEVT_COMMAND_TREE_ITEM_ACTIVATED, this, item); - nevent.m_pointDrag = CalcScrolledPosition(pt); - if ( !GetEventHandler()->ProcessEvent( nevent ) ) - { - // if the user code didn't process the activate event, - // handle it ourselves by toggling the item when it is - // double clicked - if ( item->HasPlus() ) - { - Toggle(item); - } - } - } - } - } -} - -void wxGenericTreeCtrl::OnInternalIdle() -{ - wxWindow::OnInternalIdle(); - - // Check if we need to select the root item - // because nothing else has been selected. - // Delaying it means that we can invoke event handlers - // as required, when a first item is selected. - if (!HasFlag(wxTR_MULTIPLE) && !GetSelection().IsOk()) - { - if (m_select_me) - SelectItem(m_select_me); - else if (GetRootItem().IsOk()) - SelectItem(GetRootItem()); - } - - // after all changes have been done to the tree control, - // actually redraw the tree when everything is over - if (m_dirty) - DoDirtyProcessing(); -} - -void wxGenericTreeCtrl::CalculateSize( wxGenericTreeItem *item, wxDC &dc ) -{ - wxCoord text_w = 0; - wxCoord text_h = 0; - - wxTreeItemAttr *attr = item->GetAttributes(); - if ( attr && attr->HasFont() ) - dc.SetFont(attr->GetFont()); - else if ( item->IsBold() ) - dc.SetFont(m_boldFont); - else - dc.SetFont(m_normalFont); - - dc.GetTextExtent( item->GetText(), &text_w, &text_h ); - text_h+=2; - - // restore normal font - dc.SetFont( m_normalFont ); - - int image_h = 0; - int image_w = 0; - int image = item->GetCurrentImage(); - if ( image != NO_IMAGE ) - { - if ( m_imageListNormal ) - { - m_imageListNormal->GetSize( image, image_w, image_h ); - image_w += MARGIN_BETWEEN_IMAGE_AND_TEXT; - } - } - - int total_h = (image_h > text_h) ? image_h : text_h; - - if (total_h < 30) - total_h += 2; // at least 2 pixels - else - total_h += total_h/10; // otherwise 10% extra spacing - - item->SetHeight(total_h); - if (total_h>m_lineHeight) - m_lineHeight=total_h; - - item->SetWidth(image_w+text_w+2); -} - -// ----------------------------------------------------------------------------- -// for developper : y is now the top of the level -// not the middle of it ! -void wxGenericTreeCtrl::CalculateLevel( wxGenericTreeItem *item, wxDC &dc, int level, int &y ) -{ - int x = level*m_indent; - if (!HasFlag(wxTR_HIDE_ROOT)) - { - x += m_indent; - } - else if (level == 0) - { - // a hidden root is not evaluated, but its - // children are always calculated - goto Recurse; - } - - CalculateSize( item, dc ); - - // set its position - item->SetX( x+m_spacing ); - item->SetY( y ); - y += GetLineHeight(item); - - if ( !item->IsExpanded() ) - { - // we don't need to calculate collapsed branches - return; - } - - Recurse: - wxArrayGenericTreeItems& children = item->GetChildren(); - size_t n, count = children.Count(); - ++level; - for (n = 0; n < count; ++n ) - CalculateLevel( children[n], dc, level, y ); // recurse -} - -void wxGenericTreeCtrl::CalculatePositions() -{ - if ( !m_anchor ) return; - - wxClientDC dc(this); - PrepareDC( dc ); - - dc.SetFont( m_normalFont ); - - dc.SetPen( m_dottedPen ); - //if(GetImageList() == NULL) - // m_lineHeight = (int)(dc.GetCharHeight() + 4); - - int y = 2; - CalculateLevel( m_anchor, dc, 0, y ); // start recursion -} - -void wxGenericTreeCtrl::Refresh(bool eraseBackground, const wxRect *rect) -{ - if ( !m_freezeCount ) - wxTreeCtrlBase::Refresh(eraseBackground, rect); -} - -void wxGenericTreeCtrl::RefreshSubtree(wxGenericTreeItem *item) -{ - if (m_dirty || m_freezeCount) - return; - - wxSize client = GetClientSize(); - - wxRect rect; - CalcScrolledPosition(0, item->GetY(), NULL, &rect.y); - rect.width = client.x; - rect.height = client.y; - - Refresh(true, &rect); - - AdjustMyScrollbars(); -} - -void wxGenericTreeCtrl::RefreshLine( wxGenericTreeItem *item ) -{ - if (m_dirty || m_freezeCount) - return; - - wxRect rect; - CalcScrolledPosition(0, item->GetY(), NULL, &rect.y); - rect.width = GetClientSize().x; - rect.height = GetLineHeight(item); //dc.GetCharHeight() + 6; - - Refresh(true, &rect); -} - -void wxGenericTreeCtrl::RefreshSelected() -{ - if (m_freezeCount) - return; - - // TODO: this is awfully inefficient, we should keep the list of all - // selected items internally, should be much faster - if ( m_anchor ) - RefreshSelectedUnder(m_anchor); -} - -void wxGenericTreeCtrl::RefreshSelectedUnder(wxGenericTreeItem *item) -{ - if (m_freezeCount) - return; - - if ( item->IsSelected() ) - RefreshLine(item); - - const wxArrayGenericTreeItems& children = item->GetChildren(); - size_t count = children.GetCount(); - for ( size_t n = 0; n < count; n++ ) - { - RefreshSelectedUnder(children[n]); - } -} - -void wxGenericTreeCtrl::Freeze() -{ - m_freezeCount++; -} - -void wxGenericTreeCtrl::Thaw() -{ - wxCHECK_RET( m_freezeCount > 0, _T("thawing unfrozen tree control?") ); - - if ( --m_freezeCount == 0 ) - { - Refresh(); - } -} - -// ---------------------------------------------------------------------------- -// changing colours: we need to refresh the tree control -// ---------------------------------------------------------------------------- - -bool wxGenericTreeCtrl::SetBackgroundColour(const wxColour& colour) -{ - if ( !wxWindow::SetBackgroundColour(colour) ) - return false; - - Refresh(); - - return true; -} - -bool wxGenericTreeCtrl::SetForegroundColour(const wxColour& colour) -{ - if ( !wxWindow::SetForegroundColour(colour) ) - return false; - - Refresh(); - - return true; -} - -// Process the tooltip event, to speed up event processing. -// Doesn't actually get a tooltip. -void wxGenericTreeCtrl::OnGetToolTip( wxTreeEvent &event ) -{ - event.Veto(); -} - - -// NOTE: If using the wxListBox visual attributes works everywhere then this can -// be removed, as well as the #else case below. -#define _USE_VISATTR 0 - -//static -wxVisualAttributes -#if _USE_VISATTR -wxGenericTreeCtrl::GetClassDefaultAttributes(wxWindowVariant variant) -#else -wxGenericTreeCtrl::GetClassDefaultAttributes(wxWindowVariant WXUNUSED(variant)) -#endif -{ -#if _USE_VISATTR - // Use the same color scheme as wxListBox - return wxListBox::GetClassDefaultAttributes(variant); -#else - wxVisualAttributes attr; - attr.colFg = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT); - attr.colBg = wxSystemSettings::GetColour(wxSYS_COLOUR_LISTBOX); - attr.font = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT); - return attr; -#endif -} - -#if WXWIN_COMPATIBILITY_2_4 - -int wxGenericTreeCtrl::GetItemSelectedImage(const wxTreeItemId& item) const -{ - return GetItemImage(item, wxTreeItemIcon_Selected); -} - -void wxGenericTreeCtrl::SetItemSelectedImage(const wxTreeItemId& item, int image) -{ - SetItemImage(item, image, wxTreeItemIcon_Selected); -} - -#endif // WXWIN_COMPATIBILITY_2_4 - -void wxGenericTreeCtrl::DoDirtyProcessing() -{ - if (m_freezeCount) - return; - - m_dirty = false; - - CalculatePositions(); - Refresh(); - AdjustMyScrollbars(); -} - -wxSize wxGenericTreeCtrl::DoGetBestSize() const -{ - // make sure all positions are calculated as normally this only done during - // idle time but we need them for base class DoGetBestSize() to return the - // correct result - wxConstCast(this, wxGenericTreeCtrl)->CalculatePositions(); - - wxSize size = wxTreeCtrlBase::DoGetBestSize(); - - // there seems to be an implicit extra border around the items, although - // I'm not really sure where does it come from -- but without this, the - // scrollbars appear in a tree with default/best size - size.IncBy(4, 4); - - // and the border has to be rounded up to a multiple of PIXELS_PER_UNIT or - // scrollbars still appear - const wxSize& borderSize = GetWindowBorderSize(); - - int dx = (size.x - borderSize.x) % PIXELS_PER_UNIT; - if ( dx ) - size.x += PIXELS_PER_UNIT - dx; - int dy = (size.y - borderSize.y) % PIXELS_PER_UNIT; - if ( dy ) - size.y += PIXELS_PER_UNIT - dy; - - // we need to update the cache too as the base class cached its own value - CacheBestSize(size); - - return size; -} - -#endif // wxUSE_TREECTRL +///////////////////////////////////////////////////////////////////////////// +// Name: src/generic/treectlg.cpp +// Purpose: generic tree control implementation +// Author: Robert Roebling +// Created: 01/02/97 +// Modified: 22/10/98 - almost total rewrite, simpler interface (VZ) +// Id: $Id: treectlg.cpp 53135 2008-04-12 02:31:04Z VZ $ +// Copyright: (c) 1998 Robert Roebling and Julian Smart +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================= +// declarations +// ============================================================================= + +// ----------------------------------------------------------------------------- +// headers +// ----------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_TREECTRL + +#include "wx/treectrl.h" + +#ifndef WX_PRECOMP + #include "wx/dcclient.h" + #include "wx/timer.h" + #include "wx/settings.h" + #include "wx/listbox.h" + #include "wx/textctrl.h" +#endif + +#include "wx/generic/treectlg.h" +#include "wx/imaglist.h" + +#include "wx/renderer.h" + +#ifdef __WXMAC__ + #include "wx/mac/private.h" +#endif + +// ----------------------------------------------------------------------------- +// array types +// ----------------------------------------------------------------------------- + +class WXDLLIMPEXP_FWD_CORE wxGenericTreeItem; + +WX_DEFINE_EXPORTED_ARRAY_PTR(wxGenericTreeItem *, wxArrayGenericTreeItems); + +// ---------------------------------------------------------------------------- +// constants +// ---------------------------------------------------------------------------- + +static const int NO_IMAGE = -1; + +static const int PIXELS_PER_UNIT = 10; + +// the margin between the item image and the item text +static const int MARGIN_BETWEEN_IMAGE_AND_TEXT = 4; + +// ----------------------------------------------------------------------------- +// private classes +// ----------------------------------------------------------------------------- + +// timer used for enabling in-place edit +class WXDLLEXPORT wxTreeRenameTimer: public wxTimer +{ +public: + // start editing the current item after half a second (if the mouse hasn't + // been clicked/moved) + enum { DELAY = 250 }; + + wxTreeRenameTimer( wxGenericTreeCtrl *owner ); + + virtual void Notify(); + +private: + wxGenericTreeCtrl *m_owner; + + DECLARE_NO_COPY_CLASS(wxTreeRenameTimer) +}; + +// control used for in-place edit +class WXDLLEXPORT wxTreeTextCtrl: public wxTextCtrl +{ +public: + wxTreeTextCtrl(wxGenericTreeCtrl *owner, wxGenericTreeItem *item); + + void EndEdit(bool discardChanges = false) + { + if ( discardChanges ) + { + StopEditing(); + } + else + { + m_aboutToFinish = true; + + // Notify the owner about the changes + AcceptChanges(); + + // Even if vetoed, close the control (consistent with MSW) + Finish(); + } + } + + void StopEditing() + { + Finish(); + m_owner->OnRenameCancelled(m_itemEdited); + } + const wxGenericTreeItem* item() const { return m_itemEdited; } + +protected: + void OnChar( wxKeyEvent &event ); + void OnKeyUp( wxKeyEvent &event ); + void OnKillFocus( wxFocusEvent &event ); + + bool AcceptChanges(); + void Finish(); + +private: + wxGenericTreeCtrl *m_owner; + wxGenericTreeItem *m_itemEdited; + wxString m_startValue; + bool m_finished; + bool m_aboutToFinish; + + DECLARE_EVENT_TABLE() + DECLARE_NO_COPY_CLASS(wxTreeTextCtrl) +}; + +// timer used to clear wxGenericTreeCtrl::m_findPrefix if no key was pressed +// for a sufficiently long time +class WXDLLEXPORT wxTreeFindTimer : public wxTimer +{ +public: + // reset the current prefix after half a second of inactivity + enum { DELAY = 500 }; + + wxTreeFindTimer( wxGenericTreeCtrl *owner ) { m_owner = owner; } + + virtual void Notify() { m_owner->m_findPrefix.clear(); } + +private: + wxGenericTreeCtrl *m_owner; + + DECLARE_NO_COPY_CLASS(wxTreeFindTimer) +}; + +// a tree item +class WXDLLEXPORT wxGenericTreeItem +{ +public: + // ctors & dtor + wxGenericTreeItem() { m_data = NULL; } + wxGenericTreeItem( wxGenericTreeItem *parent, + const wxString& text, + int image, + int selImage, + wxTreeItemData *data ); + + ~wxGenericTreeItem(); + + // trivial accessors + wxArrayGenericTreeItems& GetChildren() { return m_children; } + + const wxString& GetText() const { return m_text; } + int GetImage(wxTreeItemIcon which = wxTreeItemIcon_Normal) const + { return m_images[which]; } + wxTreeItemData *GetData() const { return m_data; } + + // returns the current image for the item (depending on its + // selected/expanded/whatever state) + int GetCurrentImage() const; + + void SetText( const wxString &text ); + void SetImage(int image, wxTreeItemIcon which) { m_images[which] = image; } + void SetData(wxTreeItemData *data) { m_data = data; } + + void SetHasPlus(bool has = true) { m_hasPlus = has; } + + void SetBold(bool bold) { m_isBold = bold; } + + int GetX() const { return m_x; } + int GetY() const { return m_y; } + + void SetX(int x) { m_x = x; } + void SetY(int y) { m_y = y; } + + int GetHeight() const { return m_height; } + int GetWidth() const { return m_width; } + + void SetHeight(int h) { m_height = h; } + void SetWidth(int w) { m_width = w; } + + wxGenericTreeItem *GetParent() const { return m_parent; } + + // operations + + // deletes all children notifying the treectrl about it + void DeleteChildren(wxGenericTreeCtrl *tree); + + // get count of all children (and grand children if 'recursively') + size_t GetChildrenCount(bool recursively = true) const; + + void Insert(wxGenericTreeItem *child, size_t index) + { m_children.Insert(child, index); } + + void GetSize( int &x, int &y, const wxGenericTreeCtrl* ); + + // return the item at given position (or NULL if no item), onButton is + // true if the point belongs to the item's button, otherwise it lies + // on the item's label + wxGenericTreeItem *HitTest( const wxPoint& point, + const wxGenericTreeCtrl *, + int &flags, + int level ); + + void Expand() { m_isCollapsed = false; } + void Collapse() { m_isCollapsed = true; } + + void SetHilight( bool set = true ) { m_hasHilight = set; } + + // status inquiries + bool HasChildren() const { return !m_children.IsEmpty(); } + bool IsSelected() const { return m_hasHilight != 0; } + bool IsExpanded() const { return !m_isCollapsed; } + bool HasPlus() const { return m_hasPlus || HasChildren(); } + bool IsBold() const { return m_isBold != 0; } + + // attributes + // get them - may be NULL + wxTreeItemAttr *GetAttributes() const { return m_attr; } + // get them ensuring that the pointer is not NULL + wxTreeItemAttr& Attr() + { + if ( !m_attr ) + { + m_attr = new wxTreeItemAttr; + m_ownsAttr = true; + } + return *m_attr; + } + // set them + void SetAttributes(wxTreeItemAttr *attr) + { + if ( m_ownsAttr ) delete m_attr; + m_attr = attr; + m_ownsAttr = false; + } + // set them and delete when done + void AssignAttributes(wxTreeItemAttr *attr) + { + SetAttributes(attr); + m_ownsAttr = true; + } + +private: + // since there can be very many of these, we save size by chosing + // the smallest representation for the elements and by ordering + // the members to avoid padding. + wxString m_text; // label to be rendered for item + + wxTreeItemData *m_data; // user-provided data + + wxArrayGenericTreeItems m_children; // list of children + wxGenericTreeItem *m_parent; // parent of this item + + wxTreeItemAttr *m_attr; // attributes??? + + // tree ctrl images for the normal, selected, expanded and + // expanded+selected states + int m_images[wxTreeItemIcon_Max]; + + wxCoord m_x; // (virtual) offset from top + wxCoord m_y; // (virtual) offset from left + int m_width; // width of this item + int m_height; // height of this item + + // use bitfields to save size + unsigned int m_isCollapsed :1; + unsigned int m_hasHilight :1; // same as focused + unsigned int m_hasPlus :1; // used for item which doesn't have + // children but has a [+] button + unsigned int m_isBold :1; // render the label in bold font + unsigned int m_ownsAttr :1; // delete attribute when done + + DECLARE_NO_COPY_CLASS(wxGenericTreeItem) +}; + +// ============================================================================= +// implementation +// ============================================================================= + +// ---------------------------------------------------------------------------- +// private functions +// ---------------------------------------------------------------------------- + +// translate the key or mouse event flags to the type of selection we're +// dealing with +static void EventFlagsToSelType(long style, + bool shiftDown, + bool ctrlDown, + bool &is_multiple, + bool &extended_select, + bool &unselect_others) +{ + is_multiple = (style & wxTR_MULTIPLE) != 0; + extended_select = shiftDown && is_multiple; + unselect_others = !(extended_select || (ctrlDown && is_multiple)); +} + +// check if the given item is under another one +static bool IsDescendantOf(const wxGenericTreeItem *parent, const wxGenericTreeItem *item) +{ + while ( item ) + { + if ( item == parent ) + { + // item is a descendant of parent + return true; + } + + item = item->GetParent(); + } + + return false; +} + +// ----------------------------------------------------------------------------- +// wxTreeRenameTimer (internal) +// ----------------------------------------------------------------------------- + +wxTreeRenameTimer::wxTreeRenameTimer( wxGenericTreeCtrl *owner ) +{ + m_owner = owner; +} + +void wxTreeRenameTimer::Notify() +{ + m_owner->OnRenameTimer(); +} + +//----------------------------------------------------------------------------- +// wxTreeTextCtrl (internal) +//----------------------------------------------------------------------------- + +BEGIN_EVENT_TABLE(wxTreeTextCtrl,wxTextCtrl) + EVT_CHAR (wxTreeTextCtrl::OnChar) + EVT_KEY_UP (wxTreeTextCtrl::OnKeyUp) + EVT_KILL_FOCUS (wxTreeTextCtrl::OnKillFocus) +END_EVENT_TABLE() + +wxTreeTextCtrl::wxTreeTextCtrl(wxGenericTreeCtrl *owner, + wxGenericTreeItem *item) + : m_itemEdited(item), m_startValue(item->GetText()) +{ + m_owner = owner; + m_finished = false; + m_aboutToFinish = false; + + int w = m_itemEdited->GetWidth(), + h = m_itemEdited->GetHeight(); + + int x, y; + m_owner->CalcScrolledPosition(item->GetX(), item->GetY(), &x, &y); + + int image_h = 0, + image_w = 0; + + int image = item->GetCurrentImage(); + if ( image != NO_IMAGE ) + { + if ( m_owner->m_imageListNormal ) + { + m_owner->m_imageListNormal->GetSize( image, image_w, image_h ); + image_w += MARGIN_BETWEEN_IMAGE_AND_TEXT; + } + else + { + wxFAIL_MSG(_T("you must create an image list to use images!")); + } + } + + // FIXME: what are all these hardcoded 4, 8 and 11s really? + x += image_w; + w -= image_w + 4; +#ifdef __WXMAC__ + wxSize bs = DoGetBestSize() ; + // edit control height + if ( h > bs.y - 8 ) + { + int diff = h - ( bs.y - 8 ) ; + h -= diff ; + y += diff / 2 ; + } +#endif + + (void)Create(m_owner, wxID_ANY, m_startValue, + wxPoint(x - 4, y - 4), wxSize(w + 11, h + 8)); +} + +bool wxTreeTextCtrl::AcceptChanges() +{ + const wxString value = GetValue(); + + if ( value == m_startValue ) + { + // nothing changed, always accept + // when an item remains unchanged, the owner + // needs to be notified that the user decided + // not to change the tree item label, and that + // the edit has been cancelled + + m_owner->OnRenameCancelled(m_itemEdited); + return true; + } + + if ( !m_owner->OnRenameAccept(m_itemEdited, value) ) + { + // vetoed by the user + return false; + } + + // accepted, do rename the item + m_owner->SetItemText(m_itemEdited, value); + + return true; +} + +void wxTreeTextCtrl::Finish() +{ + if ( !m_finished ) + { + m_owner->ResetTextControl(); + + wxPendingDelete.Append(this); + + m_finished = true; + + m_owner->SetFocus(); + } +} + +void wxTreeTextCtrl::OnChar( wxKeyEvent &event ) +{ + switch ( event.m_keyCode ) + { + case WXK_RETURN: + EndEdit(); + break; + + case WXK_ESCAPE: + StopEditing(); + break; + + default: + event.Skip(); + } +} + +void wxTreeTextCtrl::OnKeyUp( wxKeyEvent &event ) +{ + if ( !m_finished ) + { + // auto-grow the textctrl: + wxSize parentSize = m_owner->GetSize(); + wxPoint myPos = GetPosition(); + wxSize mySize = GetSize(); + int sx, sy; + GetTextExtent(GetValue() + _T("M"), &sx, &sy); + if (myPos.x + sx > parentSize.x) + sx = parentSize.x - myPos.x; + if (mySize.x > sx) + sx = mySize.x; + SetSize(sx, wxDefaultCoord); + } + + event.Skip(); +} + +void wxTreeTextCtrl::OnKillFocus( wxFocusEvent &event ) +{ + if ( !m_finished && !m_aboutToFinish ) + { + // We must finish regardless of success, otherwise we'll get + // focus problems: + Finish(); + + if ( !AcceptChanges() ) + m_owner->OnRenameCancelled( m_itemEdited ); + } + + // We must let the native text control handle focus, too, otherwise + // it could have problems with the cursor (e.g., in wxGTK). + event.Skip(); +} + +// ----------------------------------------------------------------------------- +// wxGenericTreeItem +// ----------------------------------------------------------------------------- + +wxGenericTreeItem::wxGenericTreeItem(wxGenericTreeItem *parent, + const wxString& text, + int image, int selImage, + wxTreeItemData *data) + : m_text(text) +{ + m_images[wxTreeItemIcon_Normal] = image; + m_images[wxTreeItemIcon_Selected] = selImage; + m_images[wxTreeItemIcon_Expanded] = NO_IMAGE; + m_images[wxTreeItemIcon_SelectedExpanded] = NO_IMAGE; + + m_data = data; + m_x = m_y = 0; + + m_isCollapsed = true; + m_hasHilight = false; + m_hasPlus = false; + m_isBold = false; + + m_parent = parent; + + m_attr = (wxTreeItemAttr *)NULL; + m_ownsAttr = false; + + // We don't know the height here yet. + m_width = 0; + m_height = 0; +} + +wxGenericTreeItem::~wxGenericTreeItem() +{ + delete m_data; + + if (m_ownsAttr) delete m_attr; + + wxASSERT_MSG( m_children.IsEmpty(), + wxT("please call DeleteChildren() before deleting the item") ); +} + +void wxGenericTreeItem::DeleteChildren(wxGenericTreeCtrl *tree) +{ + size_t count = m_children.Count(); + for ( size_t n = 0; n < count; n++ ) + { + wxGenericTreeItem *child = m_children[n]; + tree->SendDeleteEvent(child); + + child->DeleteChildren(tree); + if ( child == tree->m_select_me ) + tree->m_select_me = NULL; + delete child; + } + + m_children.Empty(); +} + +void wxGenericTreeItem::SetText( const wxString &text ) +{ + m_text = text; +} + +size_t wxGenericTreeItem::GetChildrenCount(bool recursively) const +{ + size_t count = m_children.Count(); + if ( !recursively ) + return count; + + size_t total = count; + for (size_t n = 0; n < count; ++n) + { + total += m_children[n]->GetChildrenCount(); + } + + return total; +} + +void wxGenericTreeItem::GetSize( int &x, int &y, + const wxGenericTreeCtrl *theButton ) +{ + int bottomY=m_y+theButton->GetLineHeight(this); + if ( y < bottomY ) y = bottomY; + int width = m_x + m_width; + if ( x < width ) x = width; + + if (IsExpanded()) + { + size_t count = m_children.Count(); + for ( size_t n = 0; n < count; ++n ) + { + m_children[n]->GetSize( x, y, theButton ); + } + } +} + +wxGenericTreeItem *wxGenericTreeItem::HitTest(const wxPoint& point, + const wxGenericTreeCtrl *theCtrl, + int &flags, + int level) +{ + // for a hidden root node, don't evaluate it, but do evaluate children + if ( !(level == 0 && theCtrl->HasFlag(wxTR_HIDE_ROOT)) ) + { + // evaluate the item + int h = theCtrl->GetLineHeight(this); + if ((point.y > m_y) && (point.y < m_y + h)) + { + int y_mid = m_y + h/2; + if (point.y < y_mid ) + flags |= wxTREE_HITTEST_ONITEMUPPERPART; + else + flags |= wxTREE_HITTEST_ONITEMLOWERPART; + + int xCross = m_x - theCtrl->GetSpacing(); +#ifdef __WXMAC__ + // according to the drawing code the triangels are drawn + // at -4 , -4 from the position up to +10/+10 max + if ((point.x > xCross-4) && (point.x < xCross+10) && + (point.y > y_mid-4) && (point.y < y_mid+10) && + HasPlus() && theCtrl->HasButtons() ) +#else + // 5 is the size of the plus sign + if ((point.x > xCross-6) && (point.x < xCross+6) && + (point.y > y_mid-6) && (point.y < y_mid+6) && + HasPlus() && theCtrl->HasButtons() ) +#endif + { + flags |= wxTREE_HITTEST_ONITEMBUTTON; + return this; + } + + if ((point.x >= m_x) && (point.x <= m_x+m_width)) + { + int image_w = -1; + int image_h; + + // assuming every image (normal and selected) has the same size! + if ( (GetImage() != NO_IMAGE) && theCtrl->m_imageListNormal ) + theCtrl->m_imageListNormal->GetSize(GetImage(), + image_w, image_h); + + if ((image_w != -1) && (point.x <= m_x + image_w + 1)) + flags |= wxTREE_HITTEST_ONITEMICON; + else + flags |= wxTREE_HITTEST_ONITEMLABEL; + + return this; + } + + if (point.x < m_x) + flags |= wxTREE_HITTEST_ONITEMINDENT; + if (point.x > m_x+m_width) + flags |= wxTREE_HITTEST_ONITEMRIGHT; + + return this; + } + + // if children are expanded, fall through to evaluate them + if (m_isCollapsed) return (wxGenericTreeItem*) NULL; + } + + // evaluate children + size_t count = m_children.Count(); + for ( size_t n = 0; n < count; n++ ) + { + wxGenericTreeItem *res = m_children[n]->HitTest( point, + theCtrl, + flags, + level + 1 ); + if ( res != NULL ) + return res; + } + + return (wxGenericTreeItem*) NULL; +} + +int wxGenericTreeItem::GetCurrentImage() const +{ + int image = NO_IMAGE; + if ( IsExpanded() ) + { + if ( IsSelected() ) + { + image = GetImage(wxTreeItemIcon_SelectedExpanded); + } + + if ( image == NO_IMAGE ) + { + // we usually fall back to the normal item, but try just the + // expanded one (and not selected) first in this case + image = GetImage(wxTreeItemIcon_Expanded); + } + } + else // not expanded + { + if ( IsSelected() ) + image = GetImage(wxTreeItemIcon_Selected); + } + + // maybe it doesn't have the specific image we want, + // try the default one instead + if ( image == NO_IMAGE ) image = GetImage(); + + return image; +} + +// ----------------------------------------------------------------------------- +// wxGenericTreeCtrl implementation +// ----------------------------------------------------------------------------- + +IMPLEMENT_DYNAMIC_CLASS(wxGenericTreeCtrl, wxControl) + +BEGIN_EVENT_TABLE(wxGenericTreeCtrl, wxTreeCtrlBase) + EVT_PAINT (wxGenericTreeCtrl::OnPaint) + EVT_SIZE (wxGenericTreeCtrl::OnSize) + EVT_MOUSE_EVENTS (wxGenericTreeCtrl::OnMouse) + EVT_CHAR (wxGenericTreeCtrl::OnChar) + EVT_SET_FOCUS (wxGenericTreeCtrl::OnSetFocus) + EVT_KILL_FOCUS (wxGenericTreeCtrl::OnKillFocus) + EVT_TREE_ITEM_GETTOOLTIP(wxID_ANY, wxGenericTreeCtrl::OnGetToolTip) +END_EVENT_TABLE() + +#if !defined(__WXMSW__) || defined(__WXUNIVERSAL__) +/* + * wxTreeCtrl has to be a real class or we have problems with + * the run-time information. + */ + +IMPLEMENT_DYNAMIC_CLASS(wxTreeCtrl, wxGenericTreeCtrl) +#endif + +// ----------------------------------------------------------------------------- +// construction/destruction +// ----------------------------------------------------------------------------- + +void wxGenericTreeCtrl::Init() +{ + m_current = + m_key_current = + m_anchor = + m_select_me = (wxGenericTreeItem *) NULL; + m_hasFocus = false; + m_dirty = false; + + m_lineHeight = 10; + m_indent = 15; + m_spacing = 18; + + m_hilightBrush = new wxBrush + ( + wxSystemSettings::GetColour + ( + wxSYS_COLOUR_HIGHLIGHT + ), + wxSOLID + ); + + m_hilightUnfocusedBrush = new wxBrush + ( + wxSystemSettings::GetColour + ( + wxSYS_COLOUR_BTNSHADOW + ), + wxSOLID + ); + + m_imageListButtons = NULL; + m_ownsImageListButtons = false; + + m_dragCount = 0; + m_isDragging = false; + m_dropTarget = m_oldSelection = NULL; + m_underMouse = NULL; + m_textCtrl = NULL; + + m_renameTimer = NULL; + m_freezeCount = 0; + + m_findTimer = NULL; + + m_dropEffectAboveItem = false; + + m_lastOnSame = false; + +#ifdef __WXMAC_CARBON__ + m_normalFont.MacCreateThemeFont( kThemeViewsFont ) ; +#else + m_normalFont = wxSystemSettings::GetFont( wxSYS_DEFAULT_GUI_FONT ); +#endif + m_boldFont = wxFont(m_normalFont.GetPointSize(), + m_normalFont.GetFamily(), + m_normalFont.GetStyle(), + wxBOLD, + m_normalFont.GetUnderlined(), + m_normalFont.GetFaceName(), + m_normalFont.GetEncoding()); +} + +bool wxGenericTreeCtrl::Create(wxWindow *parent, + wxWindowID id, + const wxPoint& pos, + const wxSize& size, + long style, + const wxValidator& validator, + const wxString& name ) +{ +#ifdef __WXMAC__ + int major,minor; + wxGetOsVersion( &major, &minor ); + + style &= ~wxTR_LINES_AT_ROOT; + style |= wxTR_NO_LINES; + if (major < 10) + style |= wxTR_ROW_LINES; + + if (style == 0 || style & wxTR_DEFAULT_STYLE) + style |= wxTR_FULL_ROW_HIGHLIGHT; + +#endif // __WXMAC__ +#ifdef __WXGTK20__ + style |= wxTR_NO_LINES; +#endif + + if ( !wxControl::Create( parent, id, pos, size, + style|wxHSCROLL|wxVSCROLL, + validator, + name ) ) + return false; + + // If the tree display has no buttons, but does have + // connecting lines, we can use a narrower layout. + // It may not be a good idea to force this... + if (!HasButtons() && !HasFlag(wxTR_NO_LINES)) + { + m_indent= 10; + m_spacing = 10; + } + + wxVisualAttributes attr = GetDefaultAttributes(); + SetOwnForegroundColour( attr.colFg ); + SetOwnBackgroundColour( attr.colBg ); + if (!m_hasFont) + SetOwnFont(attr.font); + + m_dottedPen = wxPen( wxT("grey"), 0, 0 ); + + SetInitialSize(size); + + return true; +} + +wxGenericTreeCtrl::~wxGenericTreeCtrl() +{ + delete m_hilightBrush; + delete m_hilightUnfocusedBrush; + + DeleteAllItems(); + + delete m_renameTimer; + delete m_findTimer; + + if (m_ownsImageListButtons) + delete m_imageListButtons; +} + +// ----------------------------------------------------------------------------- +// accessors +// ----------------------------------------------------------------------------- + +unsigned int wxGenericTreeCtrl::GetCount() const +{ + if ( !m_anchor ) + { + // the tree is empty + return 0; + } + + unsigned int count = m_anchor->GetChildrenCount(); + if ( !HasFlag(wxTR_HIDE_ROOT) ) + { + // take the root itself into account + count++; + } + + return count; +} + +void wxGenericTreeCtrl::SetIndent(unsigned int indent) +{ + m_indent = (unsigned short) indent; + m_dirty = true; +} + +size_t +wxGenericTreeCtrl::GetChildrenCount(const wxTreeItemId& item, + bool recursively) const +{ + wxCHECK_MSG( item.IsOk(), 0u, wxT("invalid tree item") ); + + return ((wxGenericTreeItem*) item.m_pItem)->GetChildrenCount(recursively); +} + +void wxGenericTreeCtrl::SetWindowStyle(const long styles) +{ + // Do not try to expand the root node if it hasn't been created yet + if (m_anchor && !HasFlag(wxTR_HIDE_ROOT) && (styles & wxTR_HIDE_ROOT)) + { + // if we will hide the root, make sure children are visible + m_anchor->SetHasPlus(); + m_anchor->Expand(); + CalculatePositions(); + } + + // right now, just sets the styles. Eventually, we may + // want to update the inherited styles, but right now + // none of the parents has updatable styles + m_windowStyle = styles; + m_dirty = true; +} + +// ----------------------------------------------------------------------------- +// functions to work with tree items +// ----------------------------------------------------------------------------- + +wxString wxGenericTreeCtrl::GetItemText(const wxTreeItemId& item) const +{ + wxCHECK_MSG( item.IsOk(), wxEmptyString, wxT("invalid tree item") ); + + return ((wxGenericTreeItem*) item.m_pItem)->GetText(); +} + +int wxGenericTreeCtrl::GetItemImage(const wxTreeItemId& item, + wxTreeItemIcon which) const +{ + wxCHECK_MSG( item.IsOk(), -1, wxT("invalid tree item") ); + + return ((wxGenericTreeItem*) item.m_pItem)->GetImage(which); +} + +wxTreeItemData *wxGenericTreeCtrl::GetItemData(const wxTreeItemId& item) const +{ + wxCHECK_MSG( item.IsOk(), NULL, wxT("invalid tree item") ); + + return ((wxGenericTreeItem*) item.m_pItem)->GetData(); +} + +wxColour wxGenericTreeCtrl::GetItemTextColour(const wxTreeItemId& item) const +{ + wxCHECK_MSG( item.IsOk(), wxNullColour, wxT("invalid tree item") ); + + wxGenericTreeItem *pItem = (wxGenericTreeItem*) item.m_pItem; + return pItem->Attr().GetTextColour(); +} + +wxColour wxGenericTreeCtrl::GetItemBackgroundColour(const wxTreeItemId& item) const +{ + wxCHECK_MSG( item.IsOk(), wxNullColour, wxT("invalid tree item") ); + + wxGenericTreeItem *pItem = (wxGenericTreeItem*) item.m_pItem; + return pItem->Attr().GetBackgroundColour(); +} + +wxFont wxGenericTreeCtrl::GetItemFont(const wxTreeItemId& item) const +{ + wxCHECK_MSG( item.IsOk(), wxNullFont, wxT("invalid tree item") ); + + wxGenericTreeItem *pItem = (wxGenericTreeItem*) item.m_pItem; + return pItem->Attr().GetFont(); +} + +void wxGenericTreeCtrl::SetItemText(const wxTreeItemId& item, const wxString& text) +{ + wxCHECK_RET( item.IsOk(), wxT("invalid tree item") ); + + wxClientDC dc(this); + wxGenericTreeItem *pItem = (wxGenericTreeItem*) item.m_pItem; + pItem->SetText(text); + CalculateSize(pItem, dc); + RefreshLine(pItem); +} + +void wxGenericTreeCtrl::SetItemImage(const wxTreeItemId& item, + int image, + wxTreeItemIcon which) +{ + wxCHECK_RET( item.IsOk(), wxT("invalid tree item") ); + + wxGenericTreeItem *pItem = (wxGenericTreeItem*) item.m_pItem; + pItem->SetImage(image, which); + + wxClientDC dc(this); + CalculateSize(pItem, dc); + RefreshLine(pItem); +} + +void wxGenericTreeCtrl::SetItemData(const wxTreeItemId& item, wxTreeItemData *data) +{ + wxCHECK_RET( item.IsOk(), wxT("invalid tree item") ); + + if (data) + data->SetId( item ); + + ((wxGenericTreeItem*) item.m_pItem)->SetData(data); +} + +void wxGenericTreeCtrl::SetItemHasChildren(const wxTreeItemId& item, bool has) +{ + wxCHECK_RET( item.IsOk(), wxT("invalid tree item") ); + + wxGenericTreeItem *pItem = (wxGenericTreeItem*) item.m_pItem; + pItem->SetHasPlus(has); + RefreshLine(pItem); +} + +void wxGenericTreeCtrl::SetItemBold(const wxTreeItemId& item, bool bold) +{ + wxCHECK_RET( item.IsOk(), wxT("invalid tree item") ); + + // avoid redrawing the tree if no real change + wxGenericTreeItem *pItem = (wxGenericTreeItem*) item.m_pItem; + if ( pItem->IsBold() != bold ) + { + pItem->SetBold(bold); + + // recalculate the item size as bold and non bold fonts have different + // widths + wxClientDC dc(this); + CalculateSize(pItem, dc); + + RefreshLine(pItem); + } +} + +void wxGenericTreeCtrl::SetItemDropHighlight(const wxTreeItemId& item, + bool highlight) +{ + wxCHECK_RET( item.IsOk(), wxT("invalid tree item") ); + + wxColour fg, bg; + + if (highlight) + { + bg = wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT); + fg = wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT); + } + + wxGenericTreeItem *pItem = (wxGenericTreeItem*) item.m_pItem; + pItem->Attr().SetTextColour(fg); + pItem->Attr().SetBackgroundColour(bg); + RefreshLine(pItem); +} + +void wxGenericTreeCtrl::SetItemTextColour(const wxTreeItemId& item, + const wxColour& col) +{ + wxCHECK_RET( item.IsOk(), wxT("invalid tree item") ); + + wxGenericTreeItem *pItem = (wxGenericTreeItem*) item.m_pItem; + pItem->Attr().SetTextColour(col); + RefreshLine(pItem); +} + +void wxGenericTreeCtrl::SetItemBackgroundColour(const wxTreeItemId& item, + const wxColour& col) +{ + wxCHECK_RET( item.IsOk(), wxT("invalid tree item") ); + + wxGenericTreeItem *pItem = (wxGenericTreeItem*) item.m_pItem; + pItem->Attr().SetBackgroundColour(col); + RefreshLine(pItem); +} + +void wxGenericTreeCtrl::SetItemFont(const wxTreeItemId& item, const wxFont& font) +{ + wxCHECK_RET( item.IsOk(), wxT("invalid tree item") ); + + wxGenericTreeItem *pItem = (wxGenericTreeItem*) item.m_pItem; + pItem->Attr().SetFont(font); + RefreshLine(pItem); +} + +bool wxGenericTreeCtrl::SetFont( const wxFont &font ) +{ + wxTreeCtrlBase::SetFont(font); + + m_normalFont = font ; + m_boldFont = wxFont(m_normalFont.GetPointSize(), + m_normalFont.GetFamily(), + m_normalFont.GetStyle(), + wxBOLD, + m_normalFont.GetUnderlined(), + m_normalFont.GetFaceName(), + m_normalFont.GetEncoding()); + + return true; +} + + +// ----------------------------------------------------------------------------- +// item status inquiries +// ----------------------------------------------------------------------------- + +bool wxGenericTreeCtrl::IsVisible(const wxTreeItemId& item) const +{ + wxCHECK_MSG( item.IsOk(), false, wxT("invalid tree item") ); + + // An item is only visible if it's not a descendant of a collapsed item + wxGenericTreeItem *pItem = (wxGenericTreeItem*) item.m_pItem; + wxGenericTreeItem* parent = pItem->GetParent(); + while (parent) + { + if (!parent->IsExpanded()) + return false; + parent = parent->GetParent(); + } + + int startX, startY; + GetViewStart(& startX, & startY); + + wxSize clientSize = GetClientSize(); + + wxRect rect; + if (!GetBoundingRect(item, rect)) + return false; + if (rect.GetWidth() == 0 || rect.GetHeight() == 0) + return false; + if (rect.GetBottom() < 0 || rect.GetTop() > clientSize.y) + return false; + if (rect.GetRight() < 0 || rect.GetLeft() > clientSize.x) + return false; + + return true; +} + +bool wxGenericTreeCtrl::ItemHasChildren(const wxTreeItemId& item) const +{ + wxCHECK_MSG( item.IsOk(), false, wxT("invalid tree item") ); + + // consider that the item does have children if it has the "+" button: it + // might not have them (if it had never been expanded yet) but then it + // could have them as well and it's better to err on this side rather than + // disabling some operations which are restricted to the items with + // children for an item which does have them + return ((wxGenericTreeItem*) item.m_pItem)->HasPlus(); +} + +bool wxGenericTreeCtrl::IsExpanded(const wxTreeItemId& item) const +{ + wxCHECK_MSG( item.IsOk(), false, wxT("invalid tree item") ); + + return ((wxGenericTreeItem*) item.m_pItem)->IsExpanded(); +} + +bool wxGenericTreeCtrl::IsSelected(const wxTreeItemId& item) const +{ + wxCHECK_MSG( item.IsOk(), false, wxT("invalid tree item") ); + + return ((wxGenericTreeItem*) item.m_pItem)->IsSelected(); +} + +bool wxGenericTreeCtrl::IsBold(const wxTreeItemId& item) const +{ + wxCHECK_MSG( item.IsOk(), false, wxT("invalid tree item") ); + + return ((wxGenericTreeItem*) item.m_pItem)->IsBold(); +} + +// ----------------------------------------------------------------------------- +// navigation +// ----------------------------------------------------------------------------- + +wxTreeItemId wxGenericTreeCtrl::GetItemParent(const wxTreeItemId& item) const +{ + wxCHECK_MSG( item.IsOk(), wxTreeItemId(), wxT("invalid tree item") ); + + return ((wxGenericTreeItem*) item.m_pItem)->GetParent(); +} + +wxTreeItemId wxGenericTreeCtrl::GetFirstChild(const wxTreeItemId& item, + wxTreeItemIdValue& cookie) const +{ + wxCHECK_MSG( item.IsOk(), wxTreeItemId(), wxT("invalid tree item") ); + + cookie = 0; + return GetNextChild(item, cookie); +} + +wxTreeItemId wxGenericTreeCtrl::GetNextChild(const wxTreeItemId& item, + wxTreeItemIdValue& cookie) const +{ + wxCHECK_MSG( item.IsOk(), wxTreeItemId(), wxT("invalid tree item") ); + + wxArrayGenericTreeItems& children = ((wxGenericTreeItem*) item.m_pItem)->GetChildren(); + + // it's ok to cast cookie to size_t, we never have indices big enough to + // overflow "void *" + size_t *pIndex = (size_t *)&cookie; + if ( *pIndex < children.Count() ) + { + return children.Item((*pIndex)++); + } + else + { + // there are no more of them + return wxTreeItemId(); + } +} + +#if WXWIN_COMPATIBILITY_2_4 + +wxTreeItemId wxGenericTreeCtrl::GetFirstChild(const wxTreeItemId& item, + long& cookie) const +{ + wxCHECK_MSG( item.IsOk(), wxTreeItemId(), wxT("invalid tree item") ); + + cookie = 0; + return GetNextChild(item, cookie); +} + +wxTreeItemId wxGenericTreeCtrl::GetNextChild(const wxTreeItemId& item, + long& cookie) const +{ + wxCHECK_MSG( item.IsOk(), wxTreeItemId(), wxT("invalid tree item") ); + + wxArrayGenericTreeItems& children = ((wxGenericTreeItem*) item.m_pItem)->GetChildren(); + if ( (size_t)cookie < children.Count() ) + { + return children.Item((size_t)cookie++); + } + else + { + // there are no more of them + return wxTreeItemId(); + } +} + +#endif // WXWIN_COMPATIBILITY_2_4 + +wxTreeItemId wxGenericTreeCtrl::GetLastChild(const wxTreeItemId& item) const +{ + wxCHECK_MSG( item.IsOk(), wxTreeItemId(), wxT("invalid tree item") ); + + wxArrayGenericTreeItems& children = ((wxGenericTreeItem*) item.m_pItem)->GetChildren(); + return (children.IsEmpty() ? wxTreeItemId() : wxTreeItemId(children.Last())); +} + +wxTreeItemId wxGenericTreeCtrl::GetNextSibling(const wxTreeItemId& item) const +{ + wxCHECK_MSG( item.IsOk(), wxTreeItemId(), wxT("invalid tree item") ); + + wxGenericTreeItem *i = (wxGenericTreeItem*) item.m_pItem; + wxGenericTreeItem *parent = i->GetParent(); + if ( parent == NULL ) + { + // root item doesn't have any siblings + return wxTreeItemId(); + } + + wxArrayGenericTreeItems& siblings = parent->GetChildren(); + int index = siblings.Index(i); + wxASSERT( index != wxNOT_FOUND ); // I'm not a child of my parent? + + size_t n = (size_t)(index + 1); + return n == siblings.Count() ? wxTreeItemId() : wxTreeItemId(siblings[n]); +} + +wxTreeItemId wxGenericTreeCtrl::GetPrevSibling(const wxTreeItemId& item) const +{ + wxCHECK_MSG( item.IsOk(), wxTreeItemId(), wxT("invalid tree item") ); + + wxGenericTreeItem *i = (wxGenericTreeItem*) item.m_pItem; + wxGenericTreeItem *parent = i->GetParent(); + if ( parent == NULL ) + { + // root item doesn't have any siblings + return wxTreeItemId(); + } + + wxArrayGenericTreeItems& siblings = parent->GetChildren(); + int index = siblings.Index(i); + wxASSERT( index != wxNOT_FOUND ); // I'm not a child of my parent? + + return index == 0 ? wxTreeItemId() + : wxTreeItemId(siblings[(size_t)(index - 1)]); +} + +// Only for internal use right now, but should probably be public +wxTreeItemId wxGenericTreeCtrl::GetNext(const wxTreeItemId& item) const +{ + wxCHECK_MSG( item.IsOk(), wxTreeItemId(), wxT("invalid tree item") ); + + wxGenericTreeItem *i = (wxGenericTreeItem*) item.m_pItem; + + // First see if there are any children. + wxArrayGenericTreeItems& children = i->GetChildren(); + if (children.GetCount() > 0) + { + return children.Item(0); + } + else + { + // Try a sibling of this or ancestor instead + wxTreeItemId p = item; + wxTreeItemId toFind; + do + { + toFind = GetNextSibling(p); + p = GetItemParent(p); + } while (p.IsOk() && !toFind.IsOk()); + return toFind; + } +} + +wxTreeItemId wxGenericTreeCtrl::GetFirstVisibleItem() const +{ + wxTreeItemId id = GetRootItem(); + if (!id.IsOk()) + return id; + + do + { + if (IsVisible(id)) + return id; + id = GetNext(id); + } while (id.IsOk()); + + return wxTreeItemId(); +} + +wxTreeItemId wxGenericTreeCtrl::GetNextVisible(const wxTreeItemId& item) const +{ + wxCHECK_MSG( item.IsOk(), wxTreeItemId(), wxT("invalid tree item") ); + + wxTreeItemId id = item; + if (id.IsOk()) + { + while (id = GetNext(id), id.IsOk()) + { + if (IsVisible(id)) + return id; + } + } + return wxTreeItemId(); +} + +wxTreeItemId wxGenericTreeCtrl::GetPrevVisible(const wxTreeItemId& item) const +{ + wxCHECK_MSG( item.IsOk(), wxTreeItemId(), wxT("invalid tree item") ); + + wxFAIL_MSG(wxT("not implemented")); + + return wxTreeItemId(); +} + +// called by wxTextTreeCtrl when it marks itself for deletion +void wxGenericTreeCtrl::ResetTextControl() +{ + m_textCtrl = NULL; +} + +// find the first item starting with the given prefix after the given item +wxTreeItemId wxGenericTreeCtrl::FindItem(const wxTreeItemId& idParent, + const wxString& prefixOrig) const +{ + // match is case insensitive as this is more convenient to the user: having + // to press Shift-letter to go to the item starting with a capital letter + // would be too bothersome + wxString prefix = prefixOrig.Lower(); + + // determine the starting point: we shouldn't take the current item (this + // allows to switch between two items starting with the same letter just by + // pressing it) but we shouldn't jump to the next one if the user is + // continuing to type as otherwise he might easily skip the item he wanted + wxTreeItemId id = idParent; + if ( prefix.length() == 1 ) + { + id = GetNext(id); + } + + // look for the item starting with the given prefix after it + while ( id.IsOk() && !GetItemText(id).Lower().StartsWith(prefix) ) + { + id = GetNext(id); + } + + // if we haven't found anything... + if ( !id.IsOk() ) + { + // ... wrap to the beginning + id = GetRootItem(); + if ( HasFlag(wxTR_HIDE_ROOT) ) + { + // can't select virtual root + id = GetNext(id); + } + + // and try all the items (stop when we get to the one we started from) + while (id.IsOk() && id != idParent && !GetItemText(id).Lower().StartsWith(prefix) ) + { + id = GetNext(id); + } + // If we haven't found the item, id.IsOk() will be false, as per + // documentation + } + + return id; +} + +// ----------------------------------------------------------------------------- +// operations +// ----------------------------------------------------------------------------- + +wxTreeItemId wxGenericTreeCtrl::DoInsertItem(const wxTreeItemId& parentId, + size_t previous, + const wxString& text, + int image, + int selImage, + wxTreeItemData *data) +{ + wxGenericTreeItem *parent = (wxGenericTreeItem*) parentId.m_pItem; + if ( !parent ) + { + // should we give a warning here? + return AddRoot(text, image, selImage, data); + } + + m_dirty = true; // do this first so stuff below doesn't cause flicker + + wxGenericTreeItem *item = + new wxGenericTreeItem( parent, text, image, selImage, data ); + + if ( data != NULL ) + { + data->m_pItem = item; + } + + parent->Insert( item, previous == (size_t)-1 ? parent->GetChildren().size() + : previous ); + + InvalidateBestSize(); + return item; +} + +wxTreeItemId wxGenericTreeCtrl::AddRoot(const wxString& text, + int image, + int selImage, + wxTreeItemData *data) +{ + wxCHECK_MSG( !m_anchor, wxTreeItemId(), wxT("tree can have only one root") ); + + m_dirty = true; // do this first so stuff below doesn't cause flicker + + m_anchor = new wxGenericTreeItem((wxGenericTreeItem *)NULL, text, + image, selImage, data); + if ( data != NULL ) + { + data->m_pItem = m_anchor; + } + + if (HasFlag(wxTR_HIDE_ROOT)) + { + // if root is hidden, make sure we can navigate + // into children + m_anchor->SetHasPlus(); + m_anchor->Expand(); + CalculatePositions(); + } + + if (!HasFlag(wxTR_MULTIPLE)) + { + m_current = m_key_current = m_anchor; + m_current->SetHilight( true ); + } + + InvalidateBestSize(); + return m_anchor; +} + +wxTreeItemId wxGenericTreeCtrl::DoInsertAfter(const wxTreeItemId& parentId, + const wxTreeItemId& idPrevious, + const wxString& text, + int image, int selImage, + wxTreeItemData *data) +{ + wxGenericTreeItem *parent = (wxGenericTreeItem*) parentId.m_pItem; + if ( !parent ) + { + // should we give a warning here? + return AddRoot(text, image, selImage, data); + } + + int index = -1; + if (idPrevious.IsOk()) + { + index = parent->GetChildren().Index((wxGenericTreeItem*) idPrevious.m_pItem); + wxASSERT_MSG( index != wxNOT_FOUND, + wxT("previous item in wxGenericTreeCtrl::InsertItem() is not a sibling") ); + } + + return DoInsertItem(parentId, (size_t)++index, text, image, selImage, data); +} + + +void wxGenericTreeCtrl::SendDeleteEvent(wxGenericTreeItem *item) +{ + wxTreeEvent event(wxEVT_COMMAND_TREE_DELETE_ITEM, this, item); + ProcessEvent( event ); +} + +// Don't leave edit or selection on a child which is about to disappear +void wxGenericTreeCtrl::ChildrenClosing(wxGenericTreeItem* item) +{ + if (m_textCtrl != NULL && item != m_textCtrl->item() && IsDescendantOf(item, m_textCtrl->item())) { + m_textCtrl->StopEditing(); + } + if (item != m_key_current && IsDescendantOf(item, m_key_current)) { + m_key_current = NULL; + } + if (IsDescendantOf(item, m_select_me)) { + m_select_me = item; + } + if (item != m_current && IsDescendantOf(item, m_current)) { + m_current->SetHilight( false ); + m_current = NULL; + m_select_me = item; + } +} + +void wxGenericTreeCtrl::DeleteChildren(const wxTreeItemId& itemId) +{ + m_dirty = true; // do this first so stuff below doesn't cause flicker + + wxGenericTreeItem *item = (wxGenericTreeItem*) itemId.m_pItem; + ChildrenClosing(item); + item->DeleteChildren(this); + InvalidateBestSize(); +} + +void wxGenericTreeCtrl::Delete(const wxTreeItemId& itemId) +{ + m_dirty = true; // do this first so stuff below doesn't cause flicker + + wxGenericTreeItem *item = (wxGenericTreeItem*) itemId.m_pItem; + + if (m_textCtrl != NULL && IsDescendantOf(item, m_textCtrl->item())) + { + // can't delete the item being edited, cancel editing it first + m_textCtrl->StopEditing(); + } + + wxGenericTreeItem *parent = item->GetParent(); + + // don't keep stale pointers around! + if ( IsDescendantOf(item, m_key_current) ) + { + // Don't silently change the selection: + // do it properly in idle time, so event + // handlers get called. + + // m_key_current = parent; + m_key_current = NULL; + } + + // m_select_me records whether we need to select + // a different item, in idle time. + if ( m_select_me && IsDescendantOf(item, m_select_me) ) + { + m_select_me = parent; + } + + if ( IsDescendantOf(item, m_current) ) + { + // Don't silently change the selection: + // do it properly in idle time, so event + // handlers get called. + + // m_current = parent; + m_current = NULL; + m_select_me = parent; + } + + // remove the item from the tree + if ( parent ) + { + parent->GetChildren().Remove( item ); // remove by value + } + else // deleting the root + { + // nothing will be left in the tree + m_anchor = NULL; + } + + // and delete all of its children and the item itself now + item->DeleteChildren(this); + SendDeleteEvent(item); + + if (item == m_select_me) + m_select_me = NULL; + + delete item; + + InvalidateBestSize(); +} + +void wxGenericTreeCtrl::DeleteAllItems() +{ + if ( m_anchor ) + { + Delete(m_anchor); + } +} + +void wxGenericTreeCtrl::Expand(const wxTreeItemId& itemId) +{ + wxGenericTreeItem *item = (wxGenericTreeItem*) itemId.m_pItem; + + wxCHECK_RET( item, _T("invalid item in wxGenericTreeCtrl::Expand") ); + wxCHECK_RET( !HasFlag(wxTR_HIDE_ROOT) || itemId != GetRootItem(), + _T("can't expand hidden root") ); + + if ( !item->HasPlus() ) + return; + + if ( item->IsExpanded() ) + return; + + wxTreeEvent event(wxEVT_COMMAND_TREE_ITEM_EXPANDING, this, item); + + if ( ProcessEvent( event ) && !event.IsAllowed() ) + { + // cancelled by program + return; + } + + item->Expand(); + CalculatePositions(); + + RefreshSubtree(item); + + event.SetEventType(wxEVT_COMMAND_TREE_ITEM_EXPANDED); + ProcessEvent( event ); +} + +void wxGenericTreeCtrl::Collapse(const wxTreeItemId& itemId) +{ + wxCHECK_RET( !HasFlag(wxTR_HIDE_ROOT) || itemId != GetRootItem(), + _T("can't collapse hidden root") ); + + wxGenericTreeItem *item = (wxGenericTreeItem*) itemId.m_pItem; + + if ( !item->IsExpanded() ) + return; + + wxTreeEvent event(wxEVT_COMMAND_TREE_ITEM_COLLAPSING, this, item); + if ( ProcessEvent( event ) && !event.IsAllowed() ) + { + // cancelled by program + return; + } + + ChildrenClosing(item); + item->Collapse(); + +#if 0 // TODO why should items be collapsed recursively? + wxArrayGenericTreeItems& children = item->GetChildren(); + size_t count = children.Count(); + for ( size_t n = 0; n < count; n++ ) + { + Collapse(children[n]); + } +#endif + + CalculatePositions(); + + RefreshSubtree(item); + + event.SetEventType(wxEVT_COMMAND_TREE_ITEM_COLLAPSED); + ProcessEvent( event ); +} + +void wxGenericTreeCtrl::CollapseAndReset(const wxTreeItemId& item) +{ + Collapse(item); + DeleteChildren(item); +} + +void wxGenericTreeCtrl::Toggle(const wxTreeItemId& itemId) +{ + wxGenericTreeItem *item = (wxGenericTreeItem*) itemId.m_pItem; + + if (item->IsExpanded()) + Collapse(itemId); + else + Expand(itemId); +} + +void wxGenericTreeCtrl::Unselect() +{ + if (m_current) + { + m_current->SetHilight( false ); + RefreshLine( m_current ); + + m_current = NULL; + m_select_me = NULL; + } +} + +void wxGenericTreeCtrl::UnselectAllChildren(wxGenericTreeItem *item) +{ + if (item->IsSelected()) + { + item->SetHilight(false); + RefreshLine(item); + } + + if (item->HasChildren()) + { + wxArrayGenericTreeItems& children = item->GetChildren(); + size_t count = children.Count(); + for ( size_t n = 0; n < count; ++n ) + { + UnselectAllChildren(children[n]); + } + } +} + +void wxGenericTreeCtrl::UnselectAll() +{ + wxTreeItemId rootItem = GetRootItem(); + + // the tree might not have the root item at all + if ( rootItem ) + { + UnselectAllChildren((wxGenericTreeItem*) rootItem.m_pItem); + } +} + +// Recursive function ! +// To stop we must have crt_itemGetParent(); + + if (parent == NULL) // This is root item + return TagAllChildrenUntilLast(crt_item, last_item, select); + + wxArrayGenericTreeItems& children = parent->GetChildren(); + int index = children.Index(crt_item); + wxASSERT( index != wxNOT_FOUND ); // I'm not a child of my parent? + + size_t count = children.Count(); + for (size_t n=(size_t)(index+1); nSetHilight(select); + RefreshLine(crt_item); + + if (crt_item==last_item) + return true; + + if (crt_item->HasChildren()) + { + wxArrayGenericTreeItems& children = crt_item->GetChildren(); + size_t count = children.Count(); + for ( size_t n = 0; n < count; ++n ) + { + if (TagAllChildrenUntilLast(children[n], last_item, select)) + return true; + } + } + + return false; +} + +void wxGenericTreeCtrl::SelectItemRange(wxGenericTreeItem *item1, wxGenericTreeItem *item2) +{ + m_select_me = NULL; + + // item2 is not necessary after item1 + // choice first' and 'last' between item1 and item2 + wxGenericTreeItem *first= (item1->GetY()GetY()) ? item1 : item2; + wxGenericTreeItem *last = (item1->GetY()GetY()) ? item2 : item1; + + bool select = m_current->IsSelected(); + + if ( TagAllChildrenUntilLast(first,last,select) ) + return; + + TagNextChildren(first,last,select); +} + +void wxGenericTreeCtrl::DoSelectItem(const wxTreeItemId& itemId, + bool unselect_others, + bool extended_select) +{ + wxCHECK_RET( itemId.IsOk(), wxT("invalid tree item") ); + + m_select_me = NULL; + + bool is_single=!(GetWindowStyleFlag() & wxTR_MULTIPLE); + wxGenericTreeItem *item = (wxGenericTreeItem*) itemId.m_pItem; + + //wxCHECK_RET( ( (!unselect_others) && is_single), + // wxT("this is a single selection tree") ); + + // to keep going anyhow !!! + if (is_single) + { + if (item->IsSelected()) + return; // nothing to do + unselect_others = true; + extended_select = false; + } + else if ( unselect_others && item->IsSelected() ) + { + // selection change if there is more than one item currently selected + wxArrayTreeItemIds selected_items; + if ( GetSelections(selected_items) == 1 ) + return; + } + + wxTreeEvent event(wxEVT_COMMAND_TREE_SEL_CHANGING, this, item); + event.m_itemOld = m_current; + // TODO : Here we don't send any selection mode yet ! + + if ( GetEventHandler()->ProcessEvent( event ) && !event.IsAllowed() ) + return; + + wxTreeItemId parent = GetItemParent( itemId ); + while (parent.IsOk()) + { + if (!IsExpanded(parent)) + Expand( parent ); + + parent = GetItemParent( parent ); + } + + // ctrl press + if (unselect_others) + { + if (is_single) Unselect(); // to speed up thing + else UnselectAll(); + } + + // shift press + if (extended_select) + { + if ( !m_current ) + { + m_current = m_key_current = (wxGenericTreeItem*) GetRootItem().m_pItem; + } + + // don't change the mark (m_current) + SelectItemRange(m_current, item); + } + else + { + bool select = true; // the default + + // Check if we need to toggle hilight (ctrl mode) + if (!unselect_others) + select=!item->IsSelected(); + + m_current = m_key_current = item; + m_current->SetHilight(select); + RefreshLine( m_current ); + } + + // This can cause idle processing to select the root + // if no item is selected, so it must be after the + // selection is set + EnsureVisible( itemId ); + + event.SetEventType(wxEVT_COMMAND_TREE_SEL_CHANGED); + GetEventHandler()->ProcessEvent( event ); +} + +void wxGenericTreeCtrl::SelectItem(const wxTreeItemId& itemId, bool select) +{ + if ( select ) + { + DoSelectItem(itemId, !HasFlag(wxTR_MULTIPLE)); + } + else // deselect + { + wxGenericTreeItem *item = (wxGenericTreeItem*) itemId.m_pItem; + wxCHECK_RET( item, wxT("SelectItem(): invalid tree item") ); + + wxTreeEvent event(wxEVT_COMMAND_TREE_SEL_CHANGING, this, item); + if ( GetEventHandler()->ProcessEvent( event ) && !event.IsAllowed() ) + return; + + item->SetHilight(false); + RefreshLine(item); + + event.SetEventType(wxEVT_COMMAND_TREE_SEL_CHANGED); + GetEventHandler()->ProcessEvent( event ); + } +} + +void wxGenericTreeCtrl::FillArray(wxGenericTreeItem *item, + wxArrayTreeItemIds &array) const +{ + if ( item->IsSelected() ) + array.Add(wxTreeItemId(item)); + + if ( item->HasChildren() ) + { + wxArrayGenericTreeItems& children = item->GetChildren(); + size_t count = children.GetCount(); + for ( size_t n = 0; n < count; ++n ) + FillArray(children[n], array); + } +} + +size_t wxGenericTreeCtrl::GetSelections(wxArrayTreeItemIds &array) const +{ + array.Empty(); + wxTreeItemId idRoot = GetRootItem(); + if ( idRoot.IsOk() ) + { + FillArray((wxGenericTreeItem*) idRoot.m_pItem, array); + } + //else: the tree is empty, so no selections + + return array.Count(); +} + +void wxGenericTreeCtrl::EnsureVisible(const wxTreeItemId& item) +{ + wxCHECK_RET( item.IsOk(), wxT("invalid tree item") ); + + if (!item.IsOk()) return; + + wxGenericTreeItem *gitem = (wxGenericTreeItem*) item.m_pItem; + + // first expand all parent branches + wxGenericTreeItem *parent = gitem->GetParent(); + + if ( HasFlag(wxTR_HIDE_ROOT) ) + { + while ( parent && parent != m_anchor ) + { + Expand(parent); + parent = parent->GetParent(); + } + } + else + { + while ( parent ) + { + Expand(parent); + parent = parent->GetParent(); + } + } + + //if (parent) CalculatePositions(); + + ScrollTo(item); +} + +void wxGenericTreeCtrl::ScrollTo(const wxTreeItemId &item) +{ + if (!item.IsOk()) return; + + // We have to call this here because the label in + // question might just have been added and no screen + // update taken place. + if (m_dirty) +#if defined( __WXMSW__ ) || defined(__WXMAC__) + Update(); +#else + DoDirtyProcessing(); +#endif + wxGenericTreeItem *gitem = (wxGenericTreeItem*) item.m_pItem; + + // now scroll to the item + int item_y = gitem->GetY(); + + int start_x = 0; + int start_y = 0; + GetViewStart( &start_x, &start_y ); + start_y *= PIXELS_PER_UNIT; + + int client_h = 0; + int client_w = 0; + GetClientSize( &client_w, &client_h ); + + if (item_y < start_y+3) + { + // going down + int x = 0; + int y = 0; + m_anchor->GetSize( x, y, this ); + y += PIXELS_PER_UNIT+2; // one more scrollbar unit + 2 pixels + x += PIXELS_PER_UNIT+2; // one more scrollbar unit + 2 pixels + int x_pos = GetScrollPos( wxHORIZONTAL ); + // Item should appear at top + SetScrollbars( PIXELS_PER_UNIT, PIXELS_PER_UNIT, x/PIXELS_PER_UNIT, y/PIXELS_PER_UNIT, x_pos, item_y/PIXELS_PER_UNIT ); + } + else if (item_y+GetLineHeight(gitem) > start_y+client_h) + { + // going up + int x = 0; + int y = 0; + m_anchor->GetSize( x, y, this ); + y += PIXELS_PER_UNIT+2; // one more scrollbar unit + 2 pixels + x += PIXELS_PER_UNIT+2; // one more scrollbar unit + 2 pixels + item_y += PIXELS_PER_UNIT+2; + int x_pos = GetScrollPos( wxHORIZONTAL ); + // Item should appear at bottom + SetScrollbars( PIXELS_PER_UNIT, PIXELS_PER_UNIT, x/PIXELS_PER_UNIT, y/PIXELS_PER_UNIT, x_pos, (item_y+GetLineHeight(gitem)-client_h)/PIXELS_PER_UNIT ); + } +} + +// FIXME: tree sorting functions are not reentrant and not MT-safe! +static wxGenericTreeCtrl *s_treeBeingSorted = NULL; + +static int LINKAGEMODE tree_ctrl_compare_func(wxGenericTreeItem **item1, + wxGenericTreeItem **item2) +{ + wxCHECK_MSG( s_treeBeingSorted, 0, wxT("bug in wxGenericTreeCtrl::SortChildren()") ); + + return s_treeBeingSorted->OnCompareItems(*item1, *item2); +} + +void wxGenericTreeCtrl::SortChildren(const wxTreeItemId& itemId) +{ + wxCHECK_RET( itemId.IsOk(), wxT("invalid tree item") ); + + wxGenericTreeItem *item = (wxGenericTreeItem*) itemId.m_pItem; + + wxCHECK_RET( !s_treeBeingSorted, + wxT("wxGenericTreeCtrl::SortChildren is not reentrant") ); + + wxArrayGenericTreeItems& children = item->GetChildren(); + if ( children.Count() > 1 ) + { + m_dirty = true; + + s_treeBeingSorted = this; + children.Sort(tree_ctrl_compare_func); + s_treeBeingSorted = NULL; + } + //else: don't make the tree dirty as nothing changed +} + +void wxGenericTreeCtrl::CalculateLineHeight() +{ + wxClientDC dc(this); + m_lineHeight = (int)(dc.GetCharHeight() + 4); + + if ( m_imageListNormal ) + { + // Calculate a m_lineHeight value from the normal Image sizes. + // May be toggle off. Then wxGenericTreeCtrl will spread when + // necessary (which might look ugly). + int n = m_imageListNormal->GetImageCount(); + for (int i = 0; i < n ; i++) + { + int width = 0, height = 0; + m_imageListNormal->GetSize(i, width, height); + if (height > m_lineHeight) m_lineHeight = height; + } + } + + if (m_imageListButtons) + { + // Calculate a m_lineHeight value from the Button image sizes. + // May be toggle off. Then wxGenericTreeCtrl will spread when + // necessary (which might look ugly). + int n = m_imageListButtons->GetImageCount(); + for (int i = 0; i < n ; i++) + { + int width = 0, height = 0; + m_imageListButtons->GetSize(i, width, height); + if (height > m_lineHeight) m_lineHeight = height; + } + } + + if (m_lineHeight < 30) + m_lineHeight += 2; // at least 2 pixels + else + m_lineHeight += m_lineHeight/10; // otherwise 10% extra spacing +} + +void wxGenericTreeCtrl::SetImageList(wxImageList *imageList) +{ + if (m_ownsImageListNormal) delete m_imageListNormal; + m_imageListNormal = imageList; + m_ownsImageListNormal = false; + m_dirty = true; + // Don't do any drawing if we're setting the list to NULL, + // since we may be in the process of deleting the tree control. + if (imageList) + CalculateLineHeight(); +} + +void wxGenericTreeCtrl::SetStateImageList(wxImageList *imageList) +{ + if (m_ownsImageListState) delete m_imageListState; + m_imageListState = imageList; + m_ownsImageListState = false; +} + +void wxGenericTreeCtrl::SetButtonsImageList(wxImageList *imageList) +{ + if (m_ownsImageListButtons) delete m_imageListButtons; + m_imageListButtons = imageList; + m_ownsImageListButtons = false; + m_dirty = true; + CalculateLineHeight(); +} + +void wxGenericTreeCtrl::AssignButtonsImageList(wxImageList *imageList) +{ + SetButtonsImageList(imageList); + m_ownsImageListButtons = true; +} + +// ----------------------------------------------------------------------------- +// helpers +// ----------------------------------------------------------------------------- + +void wxGenericTreeCtrl::AdjustMyScrollbars() +{ + if (m_anchor) + { + int x = 0, y = 0; + m_anchor->GetSize( x, y, this ); + y += PIXELS_PER_UNIT+2; // one more scrollbar unit + 2 pixels + x += PIXELS_PER_UNIT+2; // one more scrollbar unit + 2 pixels + int x_pos = GetScrollPos( wxHORIZONTAL ); + int y_pos = GetScrollPos( wxVERTICAL ); + SetScrollbars( PIXELS_PER_UNIT, PIXELS_PER_UNIT, x/PIXELS_PER_UNIT, y/PIXELS_PER_UNIT, x_pos, y_pos ); + } + else + { + SetScrollbars( 0, 0, 0, 0 ); + } +} + +int wxGenericTreeCtrl::GetLineHeight(wxGenericTreeItem *item) const +{ + if (GetWindowStyleFlag() & wxTR_HAS_VARIABLE_ROW_HEIGHT) + return item->GetHeight(); + else + return m_lineHeight; +} + +void wxGenericTreeCtrl::PaintItem(wxGenericTreeItem *item, wxDC& dc) +{ + // TODO implement "state" icon on items + + wxTreeItemAttr *attr = item->GetAttributes(); + if ( attr && attr->HasFont() ) + dc.SetFont(attr->GetFont()); + else if (item->IsBold()) + dc.SetFont(m_boldFont); + + long text_w = 0, text_h = 0; + dc.GetTextExtent( item->GetText(), &text_w, &text_h ); + + int image_h = 0, image_w = 0; + int image = item->GetCurrentImage(); + if ( image != NO_IMAGE ) + { + if ( m_imageListNormal ) + { + m_imageListNormal->GetSize( image, image_w, image_h ); + image_w += MARGIN_BETWEEN_IMAGE_AND_TEXT; + } + else + { + image = NO_IMAGE; + } + } + + int total_h = GetLineHeight(item); + bool drawItemBackground = false; + + if ( item->IsSelected() ) + { + dc.SetBrush(*(m_hasFocus ? m_hilightBrush : m_hilightUnfocusedBrush)); + drawItemBackground = true; + } + else + { + wxColour colBg; + if ( attr && attr->HasBackgroundColour() ) + { + drawItemBackground = true; + colBg = attr->GetBackgroundColour(); + } + else + { + colBg = GetBackgroundColour(); + } + dc.SetBrush(wxBrush(colBg, wxSOLID)); + } + + int offset = HasFlag(wxTR_ROW_LINES) ? 1 : 0; + + if ( HasFlag(wxTR_FULL_ROW_HIGHLIGHT) ) + { + int x = 0, w = 0, h = 0; + GetVirtualSize(&w, &h); + wxRect rect( x, item->GetY()+offset, w, total_h-offset); +#if !defined(__WXGTK20__) && !defined(__WXMAC__) + dc.DrawRectangle(rect); +#else + if (!item->IsSelected()) + { + dc.DrawRectangle(rect); + } + else + { + int flags = wxCONTROL_SELECTED; + if (m_hasFocus +#ifdef __WXMAC__ + && IsControlActive( (ControlRef)GetHandle() ) +#endif + ) + flags |= wxCONTROL_FOCUSED; + if ((item == m_current) && (m_hasFocus)) + flags |= wxCONTROL_CURRENT; + wxRendererNative::Get().DrawItemSelectionRect( this, dc, rect, flags ); + } +#endif + } + else + { + if ( item->IsSelected() && image != NO_IMAGE ) + { + // If it's selected, and there's an image, then we should + // take care to leave the area under the image painted in the + // background colour. + wxRect rect( item->GetX() + image_w - 2, item->GetY()+offset, + item->GetWidth() - image_w + 2, total_h-offset ); +#if !defined(__WXGTK20__) && !defined(__WXMAC__) + dc.DrawRectangle( rect ); +#else + rect.x -= 1; + rect.width += 2; + + int flags = wxCONTROL_SELECTED; + if (m_hasFocus) + flags |= wxCONTROL_FOCUSED; + if ((item == m_current) && (m_hasFocus)) + flags |= wxCONTROL_CURRENT; + wxRendererNative::Get().DrawItemSelectionRect( this, dc, rect, flags ); +#endif + } + // On GTK+ 2, drawing a 'normal' background is wrong for themes that + // don't allow backgrounds to be customized. Not drawing the background, + // except for custom item backgrounds, works for both kinds of theme. + else if (drawItemBackground) + { + wxRect rect( item->GetX()-2, item->GetY()+offset, + item->GetWidth()+2, total_h-offset ); +#if !defined(__WXGTK20__) && !defined(__WXMAC__) + dc.DrawRectangle( rect ); +#else + if ( attr && attr->HasBackgroundColour() ) + { + dc.DrawRectangle( rect ); + } + else + { + rect.x -= 1; + rect.width += 2; + + int flags = wxCONTROL_SELECTED; + if (m_hasFocus) + flags |= wxCONTROL_FOCUSED; + if ((item == m_current) && (m_hasFocus)) + flags |= wxCONTROL_CURRENT; + wxRendererNative::Get().DrawItemSelectionRect( this, dc, rect, flags ); + } +#endif + } + } + + if ( image != NO_IMAGE ) + { + dc.SetClippingRegion( item->GetX(), item->GetY(), image_w-2, total_h ); + m_imageListNormal->Draw( image, dc, + item->GetX(), + item->GetY() +((total_h > image_h)?((total_h-image_h)/2):0), + wxIMAGELIST_DRAW_TRANSPARENT ); + dc.DestroyClippingRegion(); + } + + dc.SetBackgroundMode(wxTRANSPARENT); + int extraH = (total_h > text_h) ? (total_h - text_h)/2 : 0; + dc.DrawText( item->GetText(), + (wxCoord)(image_w + item->GetX()), + (wxCoord)(item->GetY() + extraH)); + + // restore normal font + dc.SetFont( m_normalFont ); +} + +// Now y stands for the top of the item, whereas it used to stand for middle ! +void wxGenericTreeCtrl::PaintLevel( wxGenericTreeItem *item, wxDC &dc, int level, int &y ) +{ + int x = level*m_indent; + if (!HasFlag(wxTR_HIDE_ROOT)) + { + x += m_indent; + } + else if (level == 0) + { + // always expand hidden root + int origY = y; + wxArrayGenericTreeItems& children = item->GetChildren(); + int count = children.Count(); + if (count > 0) + { + int n = 0, oldY; + do { + oldY = y; + PaintLevel(children[n], dc, 1, y); + } while (++n < count); + + if (!HasFlag(wxTR_NO_LINES) && HasFlag(wxTR_LINES_AT_ROOT) && count > 0) + { + // draw line down to last child + origY += GetLineHeight(children[0])>>1; + oldY += GetLineHeight(children[n-1])>>1; + dc.DrawLine(3, origY, 3, oldY); + } + } + return; + } + + item->SetX(x+m_spacing); + item->SetY(y); + + int h = GetLineHeight(item); + int y_top = y; + int y_mid = y_top + (h>>1); + y += h; + + int exposed_x = dc.LogicalToDeviceX(0); + int exposed_y = dc.LogicalToDeviceY(y_top); + + if (IsExposed(exposed_x, exposed_y, 10000, h)) // 10000 = very much + { + const wxPen *pen = +#ifndef __WXMAC__ + // don't draw rect outline if we already have the + // background color under Mac + (item->IsSelected() && m_hasFocus) ? wxBLACK_PEN : +#endif // !__WXMAC__ + wxTRANSPARENT_PEN; + + wxColour colText; + if ( item->IsSelected() +#ifdef __WXMAC__ + // On wxMac, if the tree doesn't have the focus we draw an empty + // rectangle, so we want to make sure that the text is visible + // against the normal background, not the highlightbackground, so + // don't use the highlight text colour unless we have the focus. + && m_hasFocus && IsControlActive( (ControlRef)GetHandle() ) +#endif + ) + { +#ifdef __WXMAC__ + colText = *wxWHITE; +#else + colText = wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT); +#endif + } + else + { + wxTreeItemAttr *attr = item->GetAttributes(); + if (attr && attr->HasTextColour()) + colText = attr->GetTextColour(); + else + colText = GetForegroundColour(); + } + + // prepare to draw + dc.SetTextForeground(colText); + dc.SetPen(*pen); + + // draw + PaintItem(item, dc); + + if (HasFlag(wxTR_ROW_LINES)) + { + // if the background colour is white, choose a + // contrasting color for the lines + dc.SetPen(*((GetBackgroundColour() == *wxWHITE) + ? wxMEDIUM_GREY_PEN : wxWHITE_PEN)); + dc.DrawLine(0, y_top, 10000, y_top); + dc.DrawLine(0, y, 10000, y); + } + + // restore DC objects + dc.SetBrush(*wxWHITE_BRUSH); + dc.SetPen(m_dottedPen); + dc.SetTextForeground(*wxBLACK); + + if ( !HasFlag(wxTR_NO_LINES) ) + { + // draw the horizontal line here + int x_start = x; + if (x > (signed)m_indent) + x_start -= m_indent; + else if (HasFlag(wxTR_LINES_AT_ROOT)) + x_start = 3; + dc.DrawLine(x_start, y_mid, x + m_spacing, y_mid); + } + + // should the item show a button? + if ( item->HasPlus() && HasButtons() ) + { + if ( m_imageListButtons ) + { + // draw the image button here + int image_h = 0, + image_w = 0; + int image = item->IsExpanded() ? wxTreeItemIcon_Expanded + : wxTreeItemIcon_Normal; + if ( item->IsSelected() ) + image += wxTreeItemIcon_Selected - wxTreeItemIcon_Normal; + + m_imageListButtons->GetSize(image, image_w, image_h); + int xx = x - image_w/2; + int yy = y_mid - image_h/2; + + wxDCClipper clip(dc, xx, yy, image_w, image_h); + m_imageListButtons->Draw(image, dc, xx, yy, + wxIMAGELIST_DRAW_TRANSPARENT); + } + else // no custom buttons + { + static const int wImage = 9; + static const int hImage = 9; + + int flag = 0; + if (item->IsExpanded()) + flag |= wxCONTROL_EXPANDED; + if (item == m_underMouse) + flag |= wxCONTROL_CURRENT; + + wxRendererNative::Get().DrawTreeItemButton + ( + this, + dc, + wxRect(x - wImage/2, + y_mid - hImage/2, + wImage, hImage), + flag + ); + } + } + } + + if (item->IsExpanded()) + { + wxArrayGenericTreeItems& children = item->GetChildren(); + int count = children.Count(); + if (count > 0) + { + int n = 0, oldY; + ++level; + do { + oldY = y; + PaintLevel(children[n], dc, level, y); + } while (++n < count); + + if (!HasFlag(wxTR_NO_LINES) && count > 0) + { + // draw line down to last child + oldY += GetLineHeight(children[n-1])>>1; + if (HasButtons()) y_mid += 5; + + // Only draw the portion of the line that is visible, in case it is huge + wxCoord xOrigin=0, yOrigin=0, width, height; + dc.GetDeviceOrigin(&xOrigin, &yOrigin); + yOrigin = abs(yOrigin); + GetClientSize(&width, &height); + + // Move end points to the begining/end of the view? + if (y_mid < yOrigin) + y_mid = yOrigin; + if (oldY > yOrigin + height) + oldY = yOrigin + height; + + // after the adjustments if y_mid is larger than oldY then the line + // isn't visible at all so don't draw anything + if (y_mid < oldY) + dc.DrawLine(x, y_mid, x, oldY); + } + } + } +} + +void wxGenericTreeCtrl::DrawDropEffect(wxGenericTreeItem *item) +{ + if ( item ) + { + if ( item->HasPlus() ) + { + // it's a folder, indicate it by a border + DrawBorder(item); + } + else + { + // draw a line under the drop target because the item will be + // dropped there + DrawLine(item, !m_dropEffectAboveItem ); + } + + SetCursor(wxCURSOR_BULLSEYE); + } + else + { + // can't drop here + SetCursor(wxCURSOR_NO_ENTRY); + } +} + +void wxGenericTreeCtrl::DrawBorder(const wxTreeItemId &item) +{ + wxCHECK_RET( item.IsOk(), _T("invalid item in wxGenericTreeCtrl::DrawLine") ); + + wxGenericTreeItem *i = (wxGenericTreeItem*) item.m_pItem; + + wxClientDC dc(this); + PrepareDC( dc ); + dc.SetLogicalFunction(wxINVERT); + dc.SetBrush(*wxTRANSPARENT_BRUSH); + + int w = i->GetWidth() + 2; + int h = GetLineHeight(i) + 2; + + dc.DrawRectangle( i->GetX() - 1, i->GetY() - 1, w, h); +} + +void wxGenericTreeCtrl::DrawLine(const wxTreeItemId &item, bool below) +{ + wxCHECK_RET( item.IsOk(), _T("invalid item in wxGenericTreeCtrl::DrawLine") ); + + wxGenericTreeItem *i = (wxGenericTreeItem*) item.m_pItem; + + wxClientDC dc(this); + PrepareDC( dc ); + dc.SetLogicalFunction(wxINVERT); + + int x = i->GetX(), + y = i->GetY(); + if ( below ) + { + y += GetLineHeight(i) - 1; + } + + dc.DrawLine( x, y, x + i->GetWidth(), y); +} + +// ----------------------------------------------------------------------------- +// wxWidgets callbacks +// ----------------------------------------------------------------------------- + +void wxGenericTreeCtrl::OnSize( wxSizeEvent &event ) +{ +#ifdef __WXGTK__ + if (HasFlag( wxTR_FULL_ROW_HIGHLIGHT) && m_current) + RefreshLine( m_current ); +#endif + + event.Skip(true); +} + +void wxGenericTreeCtrl::OnPaint( wxPaintEvent &WXUNUSED(event) ) +{ + wxPaintDC dc(this); + PrepareDC( dc ); + + if ( !m_anchor) + return; + + dc.SetFont( m_normalFont ); + dc.SetPen( m_dottedPen ); + + // this is now done dynamically + //if(GetImageList() == NULL) + // m_lineHeight = (int)(dc.GetCharHeight() + 4); + + int y = 2; + PaintLevel( m_anchor, dc, 0, y ); +} + +void wxGenericTreeCtrl::OnSetFocus( wxFocusEvent &event ) +{ + m_hasFocus = true; + + RefreshSelected(); + + event.Skip(); +} + +void wxGenericTreeCtrl::OnKillFocus( wxFocusEvent &event ) +{ + m_hasFocus = false; + + RefreshSelected(); + + event.Skip(); +} + +void wxGenericTreeCtrl::OnChar( wxKeyEvent &event ) +{ + wxTreeEvent te( wxEVT_COMMAND_TREE_KEY_DOWN, this); + te.m_evtKey = event; + if ( GetEventHandler()->ProcessEvent( te ) ) + { + // intercepted by the user code + return; + } + + if ( (m_current == 0) || (m_key_current == 0) ) + { + event.Skip(); + return; + } + + // how should the selection work for this event? + bool is_multiple, extended_select, unselect_others; + EventFlagsToSelType(GetWindowStyleFlag(), + event.ShiftDown(), + event.CmdDown(), + is_multiple, extended_select, unselect_others); + + if (GetLayoutDirection() == wxLayout_RightToLeft) + { + if (event.GetKeyCode() == WXK_RIGHT) + event.m_keyCode = WXK_LEFT; + else if (event.GetKeyCode() == WXK_LEFT) + event.m_keyCode = WXK_RIGHT; + } + + // + : Expand + // - : Collaspe + // * : Expand all/Collapse all + // ' ' | return : activate + // up : go up (not last children!) + // down : go down + // left : go to parent + // right : open if parent and go next + // home : go to root + // end : go to last item without opening parents + // alnum : start or continue searching for the item with this prefix + int keyCode = event.GetKeyCode(); + switch ( keyCode ) + { + case '+': + case WXK_ADD: + if (m_current->HasPlus() && !IsExpanded(m_current)) + { + Expand(m_current); + } + break; + + case '*': + case WXK_MULTIPLY: + if ( !IsExpanded(m_current) ) + { + // expand all + ExpandAllChildren(m_current); + break; + } + //else: fall through to Collapse() it + + case '-': + case WXK_SUBTRACT: + if (IsExpanded(m_current)) + { + Collapse(m_current); + } + break; + + case WXK_MENU: + { + // Use the item's bounding rectangle to determine position for the event + wxRect ItemRect; + GetBoundingRect(m_current, ItemRect, true); + + wxTreeEvent eventMenu(wxEVT_COMMAND_TREE_ITEM_MENU, this, m_current); + // Use the left edge, vertical middle + eventMenu.m_pointDrag = wxPoint(ItemRect.GetX(), + ItemRect.GetY() + ItemRect.GetHeight() / 2); + GetEventHandler()->ProcessEvent( eventMenu ); + } + break; + + case ' ': + case WXK_RETURN: + if ( !event.HasModifiers() ) + { + wxTreeEvent eventAct(wxEVT_COMMAND_TREE_ITEM_ACTIVATED, this, m_current); + GetEventHandler()->ProcessEvent( eventAct ); + } + + // in any case, also generate the normal key event for this key, + // even if we generated the ACTIVATED event above: this is what + // wxMSW does and it makes sense because you might not want to + // process ACTIVATED event at all and handle Space and Return + // directly (and differently) which would be impossible otherwise + event.Skip(); + break; + + // up goes to the previous sibling or to the last + // of its children if it's expanded + case WXK_UP: + { + wxTreeItemId prev = GetPrevSibling( m_key_current ); + if (!prev) + { + prev = GetItemParent( m_key_current ); + if ((prev == GetRootItem()) && HasFlag(wxTR_HIDE_ROOT)) + { + break; // don't go to root if it is hidden + } + if (prev) + { + wxTreeItemIdValue cookie; + wxTreeItemId current = m_key_current; + // TODO: Huh? If we get here, we'd better be the first child of our parent. How else could it be? + if (current == GetFirstChild( prev, cookie )) + { + // otherwise we return to where we came from + DoSelectItem( prev, unselect_others, extended_select ); + m_key_current= (wxGenericTreeItem*) prev.m_pItem; + break; + } + } + } + if (prev) + { + while ( IsExpanded(prev) && HasChildren(prev) ) + { + wxTreeItemId child = GetLastChild(prev); + if ( child ) + { + prev = child; + } + } + + DoSelectItem( prev, unselect_others, extended_select ); + m_key_current=(wxGenericTreeItem*) prev.m_pItem; + } + } + break; + + // left arrow goes to the parent + case WXK_LEFT: + { + wxTreeItemId prev = GetItemParent( m_current ); + if ((prev == GetRootItem()) && HasFlag(wxTR_HIDE_ROOT)) + { + // don't go to root if it is hidden + prev = GetPrevSibling( m_current ); + } + if (prev) + { + DoSelectItem( prev, unselect_others, extended_select ); + } + } + break; + + case WXK_RIGHT: + // this works the same as the down arrow except that we + // also expand the item if it wasn't expanded yet + if (m_current != GetRootItem().m_pItem || !HasFlag(wxTR_HIDE_ROOT)) + Expand(m_current); + //else: don't try to expand hidden root item (which can be the + // current one when the tree is empty) + + // fall through + + case WXK_DOWN: + { + if (IsExpanded(m_key_current) && HasChildren(m_key_current)) + { + wxTreeItemIdValue cookie; + wxTreeItemId child = GetFirstChild( m_key_current, cookie ); + if ( !child ) + break; + + DoSelectItem( child, unselect_others, extended_select ); + m_key_current=(wxGenericTreeItem*) child.m_pItem; + } + else + { + wxTreeItemId next = GetNextSibling( m_key_current ); + if (!next) + { + wxTreeItemId current = m_key_current; + while (current.IsOk() && !next) + { + current = GetItemParent( current ); + if (current) next = GetNextSibling( current ); + } + } + if (next) + { + DoSelectItem( next, unselect_others, extended_select ); + m_key_current=(wxGenericTreeItem*) next.m_pItem; + } + } + } + break; + + // selects the last visible tree item + case WXK_END: + { + wxTreeItemId last = GetRootItem(); + + while ( last.IsOk() && IsExpanded(last) ) + { + wxTreeItemId lastChild = GetLastChild(last); + + // it may happen if the item was expanded but then all of + // its children have been deleted - so IsExpanded() returned + // true, but GetLastChild() returned invalid item + if ( !lastChild ) + break; + + last = lastChild; + } + + if ( last.IsOk() ) + { + DoSelectItem( last, unselect_others, extended_select ); + } + } + break; + + // selects the root item + case WXK_HOME: + { + wxTreeItemId prev = GetRootItem(); + if (!prev) + break; + + if ( HasFlag(wxTR_HIDE_ROOT) ) + { + wxTreeItemIdValue cookie; + prev = GetFirstChild(prev, cookie); + if (!prev) + break; + } + + DoSelectItem( prev, unselect_others, extended_select ); + } + break; + + default: + // do not use wxIsalnum() here + if ( !event.HasModifiers() && + ((keyCode >= '0' && keyCode <= '9') || + (keyCode >= 'a' && keyCode <= 'z') || + (keyCode >= 'A' && keyCode <= 'Z' ))) + { + // find the next item starting with the given prefix + wxChar ch = (wxChar)keyCode; + + wxTreeItemId id = FindItem(m_current, m_findPrefix + ch); + if ( !id.IsOk() ) + { + // no such item + break; + } + + SelectItem(id); + + m_findPrefix += ch; + + // also start the timer to reset the current prefix if the user + // doesn't press any more alnum keys soon -- we wouldn't want + // to use this prefix for a new item search + if ( !m_findTimer ) + { + m_findTimer = new wxTreeFindTimer(this); + } + + m_findTimer->Start(wxTreeFindTimer::DELAY, wxTIMER_ONE_SHOT); + } + else + { + event.Skip(); + } + } +} + +wxTreeItemId +wxGenericTreeCtrl::DoTreeHitTest(const wxPoint& point, int& flags) const +{ + int w, h; + GetSize(&w, &h); + flags=0; + if (point.x<0) flags |= wxTREE_HITTEST_TOLEFT; + if (point.x>w) flags |= wxTREE_HITTEST_TORIGHT; + if (point.y<0) flags |= wxTREE_HITTEST_ABOVE; + if (point.y>h) flags |= wxTREE_HITTEST_BELOW; + if (flags) return wxTreeItemId(); + + if (m_anchor == NULL) + { + flags = wxTREE_HITTEST_NOWHERE; + return wxTreeItemId(); + } + + wxGenericTreeItem *hit = m_anchor->HitTest(CalcUnscrolledPosition(point), + this, flags, 0); + if (hit == NULL) + { + flags = wxTREE_HITTEST_NOWHERE; + return wxTreeItemId(); + } + return hit; +} + +// get the bounding rectangle of the item (or of its label only) +bool wxGenericTreeCtrl::GetBoundingRect(const wxTreeItemId& item, + wxRect& rect, + bool textOnly) const +{ + wxCHECK_MSG( item.IsOk(), false, _T("invalid item in wxGenericTreeCtrl::GetBoundingRect") ); + + wxGenericTreeItem *i = (wxGenericTreeItem*) item.m_pItem; + + if ( textOnly ) + { + rect.x = i->GetX(); + rect.width = i->GetWidth(); + + if ( m_imageListNormal ) + { + int image_w, image_h; + m_imageListNormal->GetSize( 0, image_w, image_h ); + rect.width += image_w + MARGIN_BETWEEN_IMAGE_AND_TEXT; + } + } + else // the entire line + { + rect.x = 0; + rect.width = GetClientSize().x; + } + + rect.y = i->GetY(); + rect.height = GetLineHeight(i); + + // we have to return the logical coordinates, not physical ones + rect.SetTopLeft(CalcScrolledPosition(rect.GetTopLeft())); + + return true; +} + +wxTextCtrl *wxGenericTreeCtrl::EditLabel(const wxTreeItemId& item, + wxClassInfo * WXUNUSED(textCtrlClass)) +{ + wxCHECK_MSG( item.IsOk(), NULL, _T("can't edit an invalid item") ); + + wxGenericTreeItem *itemEdit = (wxGenericTreeItem *)item.m_pItem; + + wxTreeEvent te(wxEVT_COMMAND_TREE_BEGIN_LABEL_EDIT, this, itemEdit); + if ( GetEventHandler()->ProcessEvent( te ) && !te.IsAllowed() ) + { + // vetoed by user + return NULL; + } + + // We have to call this here because the label in + // question might just have been added and no screen + // update taken place. + if ( m_dirty ) +#if defined( __WXMSW__ ) || defined(__WXMAC__) + Update(); +#else + DoDirtyProcessing(); +#endif + + // TODO: use textCtrlClass here to create the control of correct class + m_textCtrl = new wxTreeTextCtrl(this, itemEdit); + + m_textCtrl->SetFocus(); + + return m_textCtrl; +} + +// returns a pointer to the text edit control if the item is being +// edited, NULL otherwise (it's assumed that no more than one item may +// be edited simultaneously) +wxTextCtrl* wxGenericTreeCtrl::GetEditControl() const +{ + return m_textCtrl; +} + +void wxGenericTreeCtrl::EndEditLabel(const wxTreeItemId& WXUNUSED(item), + bool discardChanges) +{ + wxCHECK_RET( m_textCtrl, _T("not editing label") ); + + m_textCtrl->EndEdit(discardChanges); +} + +bool wxGenericTreeCtrl::OnRenameAccept(wxGenericTreeItem *item, + const wxString& value) +{ + wxTreeEvent le(wxEVT_COMMAND_TREE_END_LABEL_EDIT, this, item); + le.m_label = value; + le.m_editCancelled = false; + + return !GetEventHandler()->ProcessEvent( le ) || le.IsAllowed(); +} + +void wxGenericTreeCtrl::OnRenameCancelled(wxGenericTreeItem *item) +{ + // let owner know that the edit was cancelled + wxTreeEvent le(wxEVT_COMMAND_TREE_END_LABEL_EDIT, this, item); + le.m_label = wxEmptyString; + le.m_editCancelled = true; + + GetEventHandler()->ProcessEvent( le ); +} + +void wxGenericTreeCtrl::OnRenameTimer() +{ + EditLabel( m_current ); +} + +void wxGenericTreeCtrl::OnMouse( wxMouseEvent &event ) +{ + if ( !m_anchor )return; + + wxPoint pt = CalcUnscrolledPosition(event.GetPosition()); + + // Is the mouse over a tree item button? + int flags = 0; + wxGenericTreeItem *thisItem = m_anchor->HitTest(pt, this, flags, 0); + wxGenericTreeItem *underMouse = thisItem; +#if wxUSE_TOOLTIPS + bool underMouseChanged = (underMouse != m_underMouse) ; +#endif // wxUSE_TOOLTIPS + + if ((underMouse) && + (flags & wxTREE_HITTEST_ONITEMBUTTON) && + (!event.LeftIsDown()) && + (!m_isDragging) && + (!m_renameTimer || !m_renameTimer->IsRunning())) + { + } + else + { + underMouse = NULL; + } + + if (underMouse != m_underMouse) + { + if (m_underMouse) + { + // unhighlight old item + wxGenericTreeItem *tmp = m_underMouse; + m_underMouse = NULL; + RefreshLine( tmp ); + } + + m_underMouse = underMouse; + if (m_underMouse) + RefreshLine( m_underMouse ); + } + +#if wxUSE_TOOLTIPS + // Determines what item we are hovering over and need a tooltip for + wxTreeItemId hoverItem = thisItem; + + // We do not want a tooltip if we are dragging, or if the rename timer is running + if (underMouseChanged && hoverItem.IsOk() && !m_isDragging && (!m_renameTimer || !m_renameTimer->IsRunning())) + { + // Ask the tree control what tooltip (if any) should be shown + wxTreeEvent hevent(wxEVT_COMMAND_TREE_ITEM_GETTOOLTIP, this, hoverItem); + + if ( GetEventHandler()->ProcessEvent(hevent) && hevent.IsAllowed() ) + { + SetToolTip(hevent.m_label); + } + } +#endif + + // we process left mouse up event (enables in-place edit), middle/right down + // (pass to the user code), left dbl click (activate item) and + // dragging/moving events for items drag-and-drop + if ( !(event.LeftDown() || + event.LeftUp() || + event.MiddleDown() || + event.RightDown() || + event.LeftDClick() || + event.Dragging() || + ((event.Moving() || event.RightUp()) && m_isDragging)) ) + { + event.Skip(); + + return; + } + + + flags = 0; + wxGenericTreeItem *item = m_anchor->HitTest(pt, this, flags, 0); + + if ( event.Dragging() && !m_isDragging ) + { + if (m_dragCount == 0) + m_dragStart = pt; + + m_dragCount++; + + if (m_dragCount != 3) + { + // wait until user drags a bit further... + return; + } + + wxEventType command = event.RightIsDown() + ? wxEVT_COMMAND_TREE_BEGIN_RDRAG + : wxEVT_COMMAND_TREE_BEGIN_DRAG; + + wxTreeEvent nevent(command, this, m_current); + nevent.SetPoint(CalcScrolledPosition(pt)); + + // by default the dragging is not supported, the user code must + // explicitly allow the event for it to take place + nevent.Veto(); + + if ( GetEventHandler()->ProcessEvent(nevent) && nevent.IsAllowed() ) + { + // we're going to drag this item + m_isDragging = true; + + // remember the old cursor because we will change it while + // dragging + m_oldCursor = m_cursor; + + // in a single selection control, hide the selection temporarily + if ( !(GetWindowStyleFlag() & wxTR_MULTIPLE) ) + { + m_oldSelection = (wxGenericTreeItem*) GetSelection().m_pItem; + + if ( m_oldSelection ) + { + m_oldSelection->SetHilight(false); + RefreshLine(m_oldSelection); + } + } + + CaptureMouse(); + } + } + else if ( event.Dragging() ) + { + if ( item != m_dropTarget ) + { + // unhighlight the previous drop target + DrawDropEffect(m_dropTarget); + + m_dropTarget = item; + + // highlight the current drop target if any + DrawDropEffect(m_dropTarget); + +#if defined(__WXMSW__) || defined(__WXMAC__) || defined(__WXGTK20__) + Update(); +#else + wxYieldIfNeeded(); +#endif + } + } + else if ( (event.LeftUp() || event.RightUp()) && m_isDragging ) + { + ReleaseMouse(); + + // erase the highlighting + DrawDropEffect(m_dropTarget); + + if ( m_oldSelection ) + { + m_oldSelection->SetHilight(true); + RefreshLine(m_oldSelection); + m_oldSelection = (wxGenericTreeItem *)NULL; + } + + // generate the drag end event + wxTreeEvent eventEndDrag(wxEVT_COMMAND_TREE_END_DRAG, this, item); + + eventEndDrag.m_pointDrag = CalcScrolledPosition(pt); + + (void)GetEventHandler()->ProcessEvent(eventEndDrag); + + m_isDragging = false; + m_dropTarget = (wxGenericTreeItem *)NULL; + + SetCursor(m_oldCursor); + +#if defined( __WXMSW__ ) || defined(__WXMAC__) + Update(); +#else + wxYieldIfNeeded(); +#endif + } + else + { + // If we got to this point, we are not dragging or moving the mouse. + // Because the code in carbon/toplevel.cpp will only set focus to the tree + // if we skip for EVT_LEFT_DOWN, we MUST skip this event here for focus to work. + // We skip even if we didn't hit an item because we still should + // restore focus to the tree control even if we didn't exactly hit an item. + if ( event.LeftDown() ) + { + event.Skip(); + } + + // here we process only the messages which happen on tree items + + m_dragCount = 0; + + if (item == NULL) return; /* we hit the blank area */ + + if ( event.RightDown() ) + { + // If the item is already selected, do not update the selection. + // Multi-selections should not be cleared if a selected item is clicked. + if (!IsSelected(item)) + { + DoSelectItem(item, true, false); + } + + wxTreeEvent nevent(wxEVT_COMMAND_TREE_ITEM_RIGHT_CLICK, this, item); + nevent.m_pointDrag = CalcScrolledPosition(pt); + event.Skip(!GetEventHandler()->ProcessEvent(nevent)); + + // Consistent with MSW (for now), send the ITEM_MENU *after* + // the RIGHT_CLICK event. TODO: This behavior may change. + wxTreeEvent nevent2(wxEVT_COMMAND_TREE_ITEM_MENU, this, item); + nevent2.m_pointDrag = CalcScrolledPosition(pt); + GetEventHandler()->ProcessEvent(nevent2); + } + else if ( event.MiddleDown() ) + { + wxTreeEvent nevent(wxEVT_COMMAND_TREE_ITEM_MIDDLE_CLICK, this, item); + nevent.m_pointDrag = CalcScrolledPosition(pt); + event.Skip(!GetEventHandler()->ProcessEvent(nevent)); + } + else if ( event.LeftUp() ) + { + // this facilitates multiple-item drag-and-drop + + if ( /* item && */ HasFlag(wxTR_MULTIPLE)) + { + wxArrayTreeItemIds selections; + size_t count = GetSelections(selections); + + if (count > 1 && + !event.CmdDown() && + !event.ShiftDown()) + { + DoSelectItem(item, true, false); + } + } + + if ( m_lastOnSame ) + { + if ( (item == m_current) && + (flags & wxTREE_HITTEST_ONITEMLABEL) && + HasFlag(wxTR_EDIT_LABELS) ) + { + if ( m_renameTimer ) + { + if ( m_renameTimer->IsRunning() ) + m_renameTimer->Stop(); + } + else + { + m_renameTimer = new wxTreeRenameTimer( this ); + } + + m_renameTimer->Start( wxTreeRenameTimer::DELAY, true ); + } + + m_lastOnSame = false; + } + } + else // !RightDown() && !MiddleDown() && !LeftUp() ==> LeftDown() || LeftDClick() + { + if ( event.LeftDown() ) + { + m_lastOnSame = item == m_current; + } + + if ( flags & wxTREE_HITTEST_ONITEMBUTTON ) + { + // only toggle the item for a single click, double click on + // the button doesn't do anything (it toggles the item twice) + if ( event.LeftDown() ) + { + Toggle( item ); + } + + // don't select the item if the button was clicked + return; + } + + + // clear the previously selected items, if the + // user clicked outside of the present selection. + // otherwise, perform the deselection on mouse-up. + // this allows multiple drag and drop to work. + // but if Cmd is down, toggle selection of the clicked item + if (!IsSelected(item) || event.CmdDown()) + { + // how should the selection work for this event? + bool is_multiple, extended_select, unselect_others; + EventFlagsToSelType(GetWindowStyleFlag(), + event.ShiftDown(), + event.CmdDown(), + is_multiple, extended_select, unselect_others); + + DoSelectItem(item, unselect_others, extended_select); + } + + + // For some reason, Windows isn't recognizing a left double-click, + // so we need to simulate it here. Allow 200 milliseconds for now. + if ( event.LeftDClick() ) + { + // double clicking should not start editing the item label + if ( m_renameTimer ) + m_renameTimer->Stop(); + + m_lastOnSame = false; + + // send activate event first + wxTreeEvent nevent(wxEVT_COMMAND_TREE_ITEM_ACTIVATED, this, item); + nevent.m_pointDrag = CalcScrolledPosition(pt); + if ( !GetEventHandler()->ProcessEvent( nevent ) ) + { + // if the user code didn't process the activate event, + // handle it ourselves by toggling the item when it is + // double clicked + if ( item->HasPlus() ) + { + Toggle(item); + } + } + } + } + } +} + +void wxGenericTreeCtrl::OnInternalIdle() +{ + wxWindow::OnInternalIdle(); + + // Check if we need to select the root item + // because nothing else has been selected. + // Delaying it means that we can invoke event handlers + // as required, when a first item is selected. + if (!HasFlag(wxTR_MULTIPLE) && !GetSelection().IsOk()) + { + if (m_select_me) + SelectItem(m_select_me); + else if (GetRootItem().IsOk()) + SelectItem(GetRootItem()); + } + + // after all changes have been done to the tree control, + // actually redraw the tree when everything is over + if (m_dirty) + DoDirtyProcessing(); +} + +void wxGenericTreeCtrl::CalculateSize( wxGenericTreeItem *item, wxDC &dc ) +{ + wxCoord text_w = 0; + wxCoord text_h = 0; + + wxTreeItemAttr *attr = item->GetAttributes(); + if ( attr && attr->HasFont() ) + dc.SetFont(attr->GetFont()); + else if ( item->IsBold() ) + dc.SetFont(m_boldFont); + else + dc.SetFont(m_normalFont); + + dc.GetTextExtent( item->GetText(), &text_w, &text_h ); + text_h+=2; + + // restore normal font + dc.SetFont( m_normalFont ); + + int image_h = 0; + int image_w = 0; + int image = item->GetCurrentImage(); + if ( image != NO_IMAGE ) + { + if ( m_imageListNormal ) + { + m_imageListNormal->GetSize( image, image_w, image_h ); + image_w += MARGIN_BETWEEN_IMAGE_AND_TEXT; + } + } + + int total_h = (image_h > text_h) ? image_h : text_h; + + if (total_h < 30) + total_h += 2; // at least 2 pixels + else + total_h += total_h/10; // otherwise 10% extra spacing + + item->SetHeight(total_h); + if (total_h>m_lineHeight) + m_lineHeight=total_h; + + item->SetWidth(image_w+text_w+2); +} + +// ----------------------------------------------------------------------------- +// for developper : y is now the top of the level +// not the middle of it ! +void wxGenericTreeCtrl::CalculateLevel( wxGenericTreeItem *item, wxDC &dc, int level, int &y ) +{ + int x = level*m_indent; + if (!HasFlag(wxTR_HIDE_ROOT)) + { + x += m_indent; + } + else if (level == 0) + { + // a hidden root is not evaluated, but its + // children are always calculated + goto Recurse; + } + + CalculateSize( item, dc ); + + // set its position + item->SetX( x+m_spacing ); + item->SetY( y ); + y += GetLineHeight(item); + + if ( !item->IsExpanded() ) + { + // we don't need to calculate collapsed branches + return; + } + + Recurse: + wxArrayGenericTreeItems& children = item->GetChildren(); + size_t n, count = children.Count(); + ++level; + for (n = 0; n < count; ++n ) + CalculateLevel( children[n], dc, level, y ); // recurse +} + +void wxGenericTreeCtrl::CalculatePositions() +{ + if ( !m_anchor ) return; + + wxClientDC dc(this); + PrepareDC( dc ); + + dc.SetFont( m_normalFont ); + + dc.SetPen( m_dottedPen ); + //if(GetImageList() == NULL) + // m_lineHeight = (int)(dc.GetCharHeight() + 4); + + int y = 2; + CalculateLevel( m_anchor, dc, 0, y ); // start recursion +} + +void wxGenericTreeCtrl::Refresh(bool eraseBackground, const wxRect *rect) +{ + if ( !m_freezeCount ) + wxTreeCtrlBase::Refresh(eraseBackground, rect); +} + +void wxGenericTreeCtrl::RefreshSubtree(wxGenericTreeItem *item) +{ + if (m_dirty || m_freezeCount) + return; + + wxSize client = GetClientSize(); + + wxRect rect; + CalcScrolledPosition(0, item->GetY(), NULL, &rect.y); + rect.width = client.x; + rect.height = client.y; + + Refresh(true, &rect); + + AdjustMyScrollbars(); +} + +void wxGenericTreeCtrl::RefreshLine( wxGenericTreeItem *item ) +{ + if (m_dirty || m_freezeCount) + return; + + wxRect rect; + CalcScrolledPosition(0, item->GetY(), NULL, &rect.y); + rect.width = GetClientSize().x; + rect.height = GetLineHeight(item); //dc.GetCharHeight() + 6; + + Refresh(true, &rect); +} + +void wxGenericTreeCtrl::RefreshSelected() +{ + if (m_freezeCount) + return; + + // TODO: this is awfully inefficient, we should keep the list of all + // selected items internally, should be much faster + if ( m_anchor ) + RefreshSelectedUnder(m_anchor); +} + +void wxGenericTreeCtrl::RefreshSelectedUnder(wxGenericTreeItem *item) +{ + if (m_freezeCount) + return; + + if ( item->IsSelected() ) + RefreshLine(item); + + const wxArrayGenericTreeItems& children = item->GetChildren(); + size_t count = children.GetCount(); + for ( size_t n = 0; n < count; n++ ) + { + RefreshSelectedUnder(children[n]); + } +} + +void wxGenericTreeCtrl::Freeze() +{ + m_freezeCount++; +} + +void wxGenericTreeCtrl::Thaw() +{ + wxCHECK_RET( m_freezeCount > 0, _T("thawing unfrozen tree control?") ); + + if ( --m_freezeCount == 0 ) + { + Refresh(); + } +} + +// ---------------------------------------------------------------------------- +// changing colours: we need to refresh the tree control +// ---------------------------------------------------------------------------- + +bool wxGenericTreeCtrl::SetBackgroundColour(const wxColour& colour) +{ + if ( !wxWindow::SetBackgroundColour(colour) ) + return false; + + Refresh(); + + return true; +} + +bool wxGenericTreeCtrl::SetForegroundColour(const wxColour& colour) +{ + if ( !wxWindow::SetForegroundColour(colour) ) + return false; + + Refresh(); + + return true; +} + +// Process the tooltip event, to speed up event processing. +// Doesn't actually get a tooltip. +void wxGenericTreeCtrl::OnGetToolTip( wxTreeEvent &event ) +{ + event.Veto(); +} + + +// NOTE: If using the wxListBox visual attributes works everywhere then this can +// be removed, as well as the #else case below. +#define _USE_VISATTR 0 + +//static +wxVisualAttributes +#if _USE_VISATTR +wxGenericTreeCtrl::GetClassDefaultAttributes(wxWindowVariant variant) +#else +wxGenericTreeCtrl::GetClassDefaultAttributes(wxWindowVariant WXUNUSED(variant)) +#endif +{ +#if _USE_VISATTR + // Use the same color scheme as wxListBox + return wxListBox::GetClassDefaultAttributes(variant); +#else + wxVisualAttributes attr; + attr.colFg = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT); + attr.colBg = wxSystemSettings::GetColour(wxSYS_COLOUR_LISTBOX); + attr.font = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT); + return attr; +#endif +} + +#if WXWIN_COMPATIBILITY_2_4 + +int wxGenericTreeCtrl::GetItemSelectedImage(const wxTreeItemId& item) const +{ + return GetItemImage(item, wxTreeItemIcon_Selected); +} + +void wxGenericTreeCtrl::SetItemSelectedImage(const wxTreeItemId& item, int image) +{ + SetItemImage(item, image, wxTreeItemIcon_Selected); +} + +#endif // WXWIN_COMPATIBILITY_2_4 + +void wxGenericTreeCtrl::DoDirtyProcessing() +{ + if (m_freezeCount) + return; + + m_dirty = false; + + CalculatePositions(); + Refresh(); + AdjustMyScrollbars(); +} + +wxSize wxGenericTreeCtrl::DoGetBestSize() const +{ + // make sure all positions are calculated as normally this only done during + // idle time but we need them for base class DoGetBestSize() to return the + // correct result + wxConstCast(this, wxGenericTreeCtrl)->CalculatePositions(); + + wxSize size = wxTreeCtrlBase::DoGetBestSize(); + + // there seems to be an implicit extra border around the items, although + // I'm not really sure where does it come from -- but without this, the + // scrollbars appear in a tree with default/best size + size.IncBy(4, 4); + + // and the border has to be rounded up to a multiple of PIXELS_PER_UNIT or + // scrollbars still appear + const wxSize& borderSize = GetWindowBorderSize(); + + int dx = (size.x - borderSize.x) % PIXELS_PER_UNIT; + if ( dx ) + size.x += PIXELS_PER_UNIT - dx; + int dy = (size.y - borderSize.y) % PIXELS_PER_UNIT; + if ( dy ) + size.y += PIXELS_PER_UNIT - dy; + + // we need to update the cache too as the base class cached its own value + CacheBestSize(size); + + return size; +} + +#endif // wxUSE_TREECTRL diff --git a/Externals/wxWidgets/src/generic/vlbox.cpp b/Externals/wxWidgets/src/generic/vlbox.cpp index 70a5bc109a..4299d03194 100644 --- a/Externals/wxWidgets/src/generic/vlbox.cpp +++ b/Externals/wxWidgets/src/generic/vlbox.cpp @@ -1,653 +1,653 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: src/generic/vlbox.cpp -// Purpose: implementation of wxVListBox -// Author: Vadim Zeitlin -// Modified by: -// Created: 31.05.03 -// RCS-ID: $Id: vlbox.cpp 53998 2008-06-06 22:55:23Z VZ $ -// Copyright: (c) 2003 Vadim Zeitlin -// License: wxWindows license -/////////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_LISTBOX - -#include "wx/vlbox.h" - -#ifndef WX_PRECOMP - #include "wx/settings.h" - #include "wx/dcclient.h" - #include "wx/listbox.h" -#endif //WX_PRECOMP - -#include "wx/dcbuffer.h" -#include "wx/selstore.h" - -// ---------------------------------------------------------------------------- -// event tables -// ---------------------------------------------------------------------------- - -BEGIN_EVENT_TABLE(wxVListBox, wxVScrolledWindow) - EVT_PAINT(wxVListBox::OnPaint) - - EVT_KEY_DOWN(wxVListBox::OnKeyDown) - EVT_LEFT_DOWN(wxVListBox::OnLeftDown) - EVT_LEFT_DCLICK(wxVListBox::OnLeftDClick) -END_EVENT_TABLE() - -// ============================================================================ -// implementation -// ============================================================================ - -IMPLEMENT_ABSTRACT_CLASS(wxVListBox, wxVScrolledWindow) - -// ---------------------------------------------------------------------------- -// wxVListBox creation -// ---------------------------------------------------------------------------- - -void wxVListBox::Init() -{ - m_current = - m_anchor = wxNOT_FOUND; - m_selStore = NULL; -} - -bool wxVListBox::Create(wxWindow *parent, - wxWindowID id, - const wxPoint& pos, - const wxSize& size, - long style, - const wxString& name) -{ - style |= wxWANTS_CHARS | wxFULL_REPAINT_ON_RESIZE; - if ( !wxVScrolledWindow::Create(parent, id, pos, size, style, name) ) - return false; - - if ( style & wxLB_MULTIPLE ) - m_selStore = new wxSelectionStore; - - // make sure the native widget has the right colour since we do - // transparent drawing by default - SetBackgroundColour(GetBackgroundColour()); - m_colBgSel = wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT); - - // flicker-free drawing requires this - SetBackgroundStyle(wxBG_STYLE_CUSTOM); - - return true; -} - -wxVListBox::~wxVListBox() -{ - delete m_selStore; -} - -void wxVListBox::SetItemCount(size_t count) -{ - // don't leave the current index invalid - if ( m_current != wxNOT_FOUND && (size_t)m_current >= count ) - m_current = count - 1; // also ok when count == 0 as wxNOT_FOUND == -1 - - if ( m_selStore ) - { - // tell the selection store that our number of items has changed - m_selStore->SetItemCount(count); - } - - SetLineCount(count); -} - -// ---------------------------------------------------------------------------- -// selection handling -// ---------------------------------------------------------------------------- - -bool wxVListBox::IsSelected(size_t line) const -{ - return m_selStore ? m_selStore->IsSelected(line) : (int)line == m_current; -} - -bool wxVListBox::Select(size_t item, bool select) -{ - wxCHECK_MSG( m_selStore, false, - _T("Select() may only be used with multiselection listbox") ); - - wxCHECK_MSG( item < GetItemCount(), false, - _T("Select(): invalid item index") ); - - bool changed = m_selStore->SelectItem(item, select); - if ( changed ) - { - // selection really changed - RefreshLine(item); - } - - DoSetCurrent(item); - - return changed; -} - -bool wxVListBox::SelectRange(size_t from, size_t to) -{ - wxCHECK_MSG( m_selStore, false, - _T("SelectRange() may only be used with multiselection listbox") ); - - // make sure items are in correct order - if ( from > to ) - { - size_t tmp = from; - from = to; - to = tmp; - } - - wxCHECK_MSG( to < GetItemCount(), false, - _T("SelectRange(): invalid item index") ); - - wxArrayInt changed; - if ( !m_selStore->SelectRange(from, to, true, &changed) ) - { - // too many items have changed, we didn't record them in changed array - // so we have no choice but to refresh everything between from and to - RefreshLines(from, to); - } - else // we've got the indices of the changed items - { - const size_t count = changed.GetCount(); - if ( !count ) - { - // nothing changed - return false; - } - - // refresh just the lines which have really changed - for ( size_t n = 0; n < count; n++ ) - { - RefreshLine(changed[n]); - } - } - - // something changed - return true; -} - -bool wxVListBox::DoSelectAll(bool select) -{ - wxCHECK_MSG( m_selStore, false, - _T("SelectAll may only be used with multiselection listbox") ); - - size_t count = GetItemCount(); - if ( count ) - { - wxArrayInt changed; - if ( !m_selStore->SelectRange(0, count - 1, select) || - !changed.IsEmpty() ) - { - Refresh(); - - // something changed - return true; - } - } - - return false; -} - -bool wxVListBox::DoSetCurrent(int current) -{ - wxASSERT_MSG( current == wxNOT_FOUND || - (current >= 0 && (size_t)current < GetItemCount()), - _T("wxVListBox::DoSetCurrent(): invalid item index") ); - - if ( current == m_current ) - { - // nothing to do - return false; - } - - if ( m_current != wxNOT_FOUND ) - RefreshLine(m_current); - - m_current = current; - - if ( m_current != wxNOT_FOUND ) - { - // if the line is not visible at all, we scroll it into view but we - // don't need to refresh it -- it will be redrawn anyhow - if ( !IsVisible(m_current) ) - { - ScrollToLine(m_current); - } - else // line is at least partly visible - { - // it is, indeed, only partly visible, so scroll it into view to - // make it entirely visible - while ( (size_t)m_current == GetLastVisibleLine() && - ScrollToLine(GetVisibleBegin()+1) ) ; - - // but in any case refresh it as even if it was only partly visible - // before we need to redraw it entirely as its background changed - RefreshLine(m_current); - } - } - - return true; -} - -void wxVListBox::SendSelectedEvent() -{ - wxASSERT_MSG( m_current != wxNOT_FOUND, - _T("SendSelectedEvent() shouldn't be called") ); - - wxCommandEvent event(wxEVT_COMMAND_LISTBOX_SELECTED, GetId()); - event.SetEventObject(this); - event.SetInt(m_current); - - (void)GetEventHandler()->ProcessEvent(event); -} - -void wxVListBox::SetSelection(int selection) -{ - wxCHECK_RET( selection == wxNOT_FOUND || - (selection >= 0 && (size_t)selection < GetItemCount()), - _T("wxVListBox::SetSelection(): invalid item index") ); - - if ( HasMultipleSelection() ) - { - if (selection != wxNOT_FOUND) - Select(selection); - else - DeselectAll(); - m_anchor = selection; - } - - DoSetCurrent(selection); -} - -size_t wxVListBox::GetSelectedCount() const -{ - return m_selStore ? m_selStore->GetSelectedCount() - : m_current == wxNOT_FOUND ? 0 : 1; -} - -int wxVListBox::GetFirstSelected(unsigned long& cookie) const -{ - cookie = 0; - - return GetNextSelected(cookie); -} - -int wxVListBox::GetNextSelected(unsigned long& cookie) const -{ - wxCHECK_MSG( m_selStore, wxNOT_FOUND, - _T("GetFirst/NextSelected() may only be used with multiselection listboxes") ); - - while ( cookie < GetItemCount() ) - { - if ( IsSelected(cookie++) ) - return cookie - 1; - } - - return wxNOT_FOUND; -} - -// ---------------------------------------------------------------------------- -// wxVListBox appearance parameters -// ---------------------------------------------------------------------------- - -void wxVListBox::SetMargins(const wxPoint& pt) -{ - if ( pt != m_ptMargins ) - { - m_ptMargins = pt; - - Refresh(); - } -} - -void wxVListBox::SetSelectionBackground(const wxColour& col) -{ - m_colBgSel = col; -} - -// ---------------------------------------------------------------------------- -// wxVListBox painting -// ---------------------------------------------------------------------------- - -wxCoord wxVListBox::OnGetLineHeight(size_t line) const -{ - return OnMeasureItem(line) + 2*m_ptMargins.y; -} - -void wxVListBox::OnDrawSeparator(wxDC& WXUNUSED(dc), - wxRect& WXUNUSED(rect), - size_t WXUNUSED(n)) const -{ -} - -void wxVListBox::OnDrawBackground(wxDC& dc, const wxRect& rect, size_t n) const -{ - // we need to render selected and current items differently - const bool isSelected = IsSelected(n), - isCurrent = IsCurrent(n); - if ( isSelected || isCurrent ) - { - if ( isSelected ) - { - dc.SetBrush(wxBrush(m_colBgSel, wxSOLID)); - } - else // !selected - { - dc.SetBrush(*wxTRANSPARENT_BRUSH); - } - - dc.SetPen(*(isCurrent ? wxBLACK_PEN : wxTRANSPARENT_PEN)); - - dc.DrawRectangle(rect); - } - //else: do nothing for the normal items -} - -void wxVListBox::OnPaint(wxPaintEvent& WXUNUSED(event)) -{ - wxSize clientSize = GetClientSize(); - - wxAutoBufferedPaintDC dc(this); - - // the update rectangle - wxRect rectUpdate = GetUpdateClientRect(); - - // fill it with background colour - dc.SetBackground(GetBackgroundColour()); - dc.Clear(); - - // the bounding rectangle of the current line - wxRect rectLine; - rectLine.width = clientSize.x; - - // iterate over all visible lines - const size_t lineMax = GetVisibleEnd(); - for ( size_t line = GetFirstVisibleLine(); line < lineMax; line++ ) - { - const wxCoord hLine = OnGetLineHeight(line); - - rectLine.height = hLine; - - // and draw the ones which intersect the update rect - if ( rectLine.Intersects(rectUpdate) ) - { - // don't allow drawing outside of the lines rectangle - wxDCClipper clip(dc, rectLine); - - wxRect rect = rectLine; - OnDrawBackground(dc, rect, line); - - OnDrawSeparator(dc, rect, line); - - rect.Deflate(m_ptMargins.x, m_ptMargins.y); - OnDrawItem(dc, rect, line); - } - else // no intersection - { - if ( rectLine.GetTop() > rectUpdate.GetBottom() ) - { - // we are already below the update rect, no need to continue - // further - break; - } - //else: the next line may intersect the update rect - } - - rectLine.y += hLine; - } -} - -// ============================================================================ -// wxVListBox keyboard/mouse handling -// ============================================================================ - -void wxVListBox::DoHandleItemClick(int item, int flags) -{ - // has anything worth telling the client code about happened? - bool notify = false; - - if ( HasMultipleSelection() ) - { - // select the iteem clicked? - bool select = true; - - // NB: the keyboard interface we implement here corresponds to - // wxLB_EXTENDED rather than wxLB_MULTIPLE but this one makes more - // sense IMHO - if ( flags & ItemClick_Shift ) - { - if ( m_current != wxNOT_FOUND ) - { - if ( m_anchor == wxNOT_FOUND ) - m_anchor = m_current; - - select = false; - - // only the range from the selection anchor to new m_current - // must be selected - if ( DeselectAll() ) - notify = true; - - if ( SelectRange(m_anchor, item) ) - notify = true; - } - //else: treat it as ordinary click/keypress - } - else // Shift not pressed - { - m_anchor = item; - - if ( flags & ItemClick_Ctrl ) - { - select = false; - - if ( !(flags & ItemClick_Kbd) ) - { - Toggle(item); - - // the status of the item has definitely changed - notify = true; - } - //else: Ctrl-arrow pressed, don't change selection - } - //else: behave as in single selection case - } - - if ( select ) - { - // make the clicked item the only selection - if ( DeselectAll() ) - notify = true; - - if ( Select(item) ) - notify = true; - } - } - - // in any case the item should become the current one - if ( DoSetCurrent(item) ) - { - if ( !HasMultipleSelection() ) - { - // this has also changed the selection for single selection case - notify = true; - } - } - - if ( notify ) - { - // notify the user about the selection change - SendSelectedEvent(); - } - //else: nothing changed at all -} - -// ---------------------------------------------------------------------------- -// keyboard handling -// ---------------------------------------------------------------------------- - -void wxVListBox::OnKeyDown(wxKeyEvent& event) -{ - // flags for DoHandleItemClick() - int flags = ItemClick_Kbd; - - int current; - switch ( event.GetKeyCode() ) - { - case WXK_HOME: - current = 0; - break; - - case WXK_END: - current = GetLineCount() - 1; - break; - - case WXK_DOWN: - if ( m_current == (int)GetLineCount() - 1 ) - return; - - current = m_current + 1; - break; - - case WXK_UP: - if ( m_current == wxNOT_FOUND ) - current = GetLineCount() - 1; - else if ( m_current != 0 ) - current = m_current - 1; - else // m_current == 0 - return; - break; - - case WXK_PAGEDOWN: - PageDown(); - current = GetFirstVisibleLine(); - break; - - case WXK_PAGEUP: - if ( m_current == (int)GetFirstVisibleLine() ) - { - PageUp(); - } - - current = GetFirstVisibleLine(); - break; - - case WXK_SPACE: - // hack: pressing space should work like a mouse click rather than - // like a keyboard arrow press, so trick DoHandleItemClick() in - // thinking we were clicked - flags &= ~ItemClick_Kbd; - current = m_current; - break; - -#ifdef __WXMSW__ - case WXK_TAB: - // Since we are using wxWANTS_CHARS we need to send navigation - // events for the tabs on MSW - { - wxNavigationKeyEvent ne; - ne.SetDirection(!event.ShiftDown()); - ne.SetCurrentFocus(this); - ne.SetEventObject(this); - GetParent()->GetEventHandler()->ProcessEvent(ne); - } - // fall through to default -#endif - default: - event.Skip(); - current = 0; // just to silent the stupid compiler warnings - wxUnusedVar(current); - return; - } - - if ( event.ShiftDown() ) - flags |= ItemClick_Shift; - if ( event.ControlDown() ) - flags |= ItemClick_Ctrl; - - DoHandleItemClick(current, flags); -} - -// ---------------------------------------------------------------------------- -// wxVListBox mouse handling -// ---------------------------------------------------------------------------- - -void wxVListBox::OnLeftDown(wxMouseEvent& event) -{ - SetFocus(); - - int item = HitTest(event.GetPosition()); - - if ( item != wxNOT_FOUND ) - { - int flags = 0; - if ( event.ShiftDown() ) - flags |= ItemClick_Shift; - - // under Mac Apple-click is used in the same way as Ctrl-click - // elsewhere -#ifdef __WXMAC__ - if ( event.MetaDown() ) -#else - if ( event.ControlDown() ) -#endif - flags |= ItemClick_Ctrl; - - DoHandleItemClick(item, flags); - } -} - -void wxVListBox::OnLeftDClick(wxMouseEvent& eventMouse) -{ - int item = HitTest(eventMouse.GetPosition()); - if ( item != wxNOT_FOUND ) - { - - // if item double-clicked was not yet selected, then treat - // this event as a left-click instead - if ( item == m_current ) - { - wxCommandEvent event(wxEVT_COMMAND_LISTBOX_DOUBLECLICKED, GetId()); - event.SetEventObject(this); - event.SetInt(item); - - (void)GetEventHandler()->ProcessEvent(event); - } - else - { - OnLeftDown(eventMouse); - } - - } -} - - -// ---------------------------------------------------------------------------- -// use the same default attributes as wxListBox -// ---------------------------------------------------------------------------- - -//static -wxVisualAttributes -wxVListBox::GetClassDefaultAttributes(wxWindowVariant variant) -{ - return wxListBox::GetClassDefaultAttributes(variant); -} - -#endif +/////////////////////////////////////////////////////////////////////////////// +// Name: src/generic/vlbox.cpp +// Purpose: implementation of wxVListBox +// Author: Vadim Zeitlin +// Modified by: +// Created: 31.05.03 +// RCS-ID: $Id: vlbox.cpp 53998 2008-06-06 22:55:23Z VZ $ +// Copyright: (c) 2003 Vadim Zeitlin +// License: wxWindows license +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_LISTBOX + +#include "wx/vlbox.h" + +#ifndef WX_PRECOMP + #include "wx/settings.h" + #include "wx/dcclient.h" + #include "wx/listbox.h" +#endif //WX_PRECOMP + +#include "wx/dcbuffer.h" +#include "wx/selstore.h" + +// ---------------------------------------------------------------------------- +// event tables +// ---------------------------------------------------------------------------- + +BEGIN_EVENT_TABLE(wxVListBox, wxVScrolledWindow) + EVT_PAINT(wxVListBox::OnPaint) + + EVT_KEY_DOWN(wxVListBox::OnKeyDown) + EVT_LEFT_DOWN(wxVListBox::OnLeftDown) + EVT_LEFT_DCLICK(wxVListBox::OnLeftDClick) +END_EVENT_TABLE() + +// ============================================================================ +// implementation +// ============================================================================ + +IMPLEMENT_ABSTRACT_CLASS(wxVListBox, wxVScrolledWindow) + +// ---------------------------------------------------------------------------- +// wxVListBox creation +// ---------------------------------------------------------------------------- + +void wxVListBox::Init() +{ + m_current = + m_anchor = wxNOT_FOUND; + m_selStore = NULL; +} + +bool wxVListBox::Create(wxWindow *parent, + wxWindowID id, + const wxPoint& pos, + const wxSize& size, + long style, + const wxString& name) +{ + style |= wxWANTS_CHARS | wxFULL_REPAINT_ON_RESIZE; + if ( !wxVScrolledWindow::Create(parent, id, pos, size, style, name) ) + return false; + + if ( style & wxLB_MULTIPLE ) + m_selStore = new wxSelectionStore; + + // make sure the native widget has the right colour since we do + // transparent drawing by default + SetBackgroundColour(GetBackgroundColour()); + m_colBgSel = wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT); + + // flicker-free drawing requires this + SetBackgroundStyle(wxBG_STYLE_CUSTOM); + + return true; +} + +wxVListBox::~wxVListBox() +{ + delete m_selStore; +} + +void wxVListBox::SetItemCount(size_t count) +{ + // don't leave the current index invalid + if ( m_current != wxNOT_FOUND && (size_t)m_current >= count ) + m_current = count - 1; // also ok when count == 0 as wxNOT_FOUND == -1 + + if ( m_selStore ) + { + // tell the selection store that our number of items has changed + m_selStore->SetItemCount(count); + } + + SetLineCount(count); +} + +// ---------------------------------------------------------------------------- +// selection handling +// ---------------------------------------------------------------------------- + +bool wxVListBox::IsSelected(size_t line) const +{ + return m_selStore ? m_selStore->IsSelected(line) : (int)line == m_current; +} + +bool wxVListBox::Select(size_t item, bool select) +{ + wxCHECK_MSG( m_selStore, false, + _T("Select() may only be used with multiselection listbox") ); + + wxCHECK_MSG( item < GetItemCount(), false, + _T("Select(): invalid item index") ); + + bool changed = m_selStore->SelectItem(item, select); + if ( changed ) + { + // selection really changed + RefreshLine(item); + } + + DoSetCurrent(item); + + return changed; +} + +bool wxVListBox::SelectRange(size_t from, size_t to) +{ + wxCHECK_MSG( m_selStore, false, + _T("SelectRange() may only be used with multiselection listbox") ); + + // make sure items are in correct order + if ( from > to ) + { + size_t tmp = from; + from = to; + to = tmp; + } + + wxCHECK_MSG( to < GetItemCount(), false, + _T("SelectRange(): invalid item index") ); + + wxArrayInt changed; + if ( !m_selStore->SelectRange(from, to, true, &changed) ) + { + // too many items have changed, we didn't record them in changed array + // so we have no choice but to refresh everything between from and to + RefreshLines(from, to); + } + else // we've got the indices of the changed items + { + const size_t count = changed.GetCount(); + if ( !count ) + { + // nothing changed + return false; + } + + // refresh just the lines which have really changed + for ( size_t n = 0; n < count; n++ ) + { + RefreshLine(changed[n]); + } + } + + // something changed + return true; +} + +bool wxVListBox::DoSelectAll(bool select) +{ + wxCHECK_MSG( m_selStore, false, + _T("SelectAll may only be used with multiselection listbox") ); + + size_t count = GetItemCount(); + if ( count ) + { + wxArrayInt changed; + if ( !m_selStore->SelectRange(0, count - 1, select) || + !changed.IsEmpty() ) + { + Refresh(); + + // something changed + return true; + } + } + + return false; +} + +bool wxVListBox::DoSetCurrent(int current) +{ + wxASSERT_MSG( current == wxNOT_FOUND || + (current >= 0 && (size_t)current < GetItemCount()), + _T("wxVListBox::DoSetCurrent(): invalid item index") ); + + if ( current == m_current ) + { + // nothing to do + return false; + } + + if ( m_current != wxNOT_FOUND ) + RefreshLine(m_current); + + m_current = current; + + if ( m_current != wxNOT_FOUND ) + { + // if the line is not visible at all, we scroll it into view but we + // don't need to refresh it -- it will be redrawn anyhow + if ( !IsVisible(m_current) ) + { + ScrollToLine(m_current); + } + else // line is at least partly visible + { + // it is, indeed, only partly visible, so scroll it into view to + // make it entirely visible + while ( (size_t)m_current == GetLastVisibleLine() && + ScrollToLine(GetVisibleBegin()+1) ) ; + + // but in any case refresh it as even if it was only partly visible + // before we need to redraw it entirely as its background changed + RefreshLine(m_current); + } + } + + return true; +} + +void wxVListBox::SendSelectedEvent() +{ + wxASSERT_MSG( m_current != wxNOT_FOUND, + _T("SendSelectedEvent() shouldn't be called") ); + + wxCommandEvent event(wxEVT_COMMAND_LISTBOX_SELECTED, GetId()); + event.SetEventObject(this); + event.SetInt(m_current); + + (void)GetEventHandler()->ProcessEvent(event); +} + +void wxVListBox::SetSelection(int selection) +{ + wxCHECK_RET( selection == wxNOT_FOUND || + (selection >= 0 && (size_t)selection < GetItemCount()), + _T("wxVListBox::SetSelection(): invalid item index") ); + + if ( HasMultipleSelection() ) + { + if (selection != wxNOT_FOUND) + Select(selection); + else + DeselectAll(); + m_anchor = selection; + } + + DoSetCurrent(selection); +} + +size_t wxVListBox::GetSelectedCount() const +{ + return m_selStore ? m_selStore->GetSelectedCount() + : m_current == wxNOT_FOUND ? 0 : 1; +} + +int wxVListBox::GetFirstSelected(unsigned long& cookie) const +{ + cookie = 0; + + return GetNextSelected(cookie); +} + +int wxVListBox::GetNextSelected(unsigned long& cookie) const +{ + wxCHECK_MSG( m_selStore, wxNOT_FOUND, + _T("GetFirst/NextSelected() may only be used with multiselection listboxes") ); + + while ( cookie < GetItemCount() ) + { + if ( IsSelected(cookie++) ) + return cookie - 1; + } + + return wxNOT_FOUND; +} + +// ---------------------------------------------------------------------------- +// wxVListBox appearance parameters +// ---------------------------------------------------------------------------- + +void wxVListBox::SetMargins(const wxPoint& pt) +{ + if ( pt != m_ptMargins ) + { + m_ptMargins = pt; + + Refresh(); + } +} + +void wxVListBox::SetSelectionBackground(const wxColour& col) +{ + m_colBgSel = col; +} + +// ---------------------------------------------------------------------------- +// wxVListBox painting +// ---------------------------------------------------------------------------- + +wxCoord wxVListBox::OnGetLineHeight(size_t line) const +{ + return OnMeasureItem(line) + 2*m_ptMargins.y; +} + +void wxVListBox::OnDrawSeparator(wxDC& WXUNUSED(dc), + wxRect& WXUNUSED(rect), + size_t WXUNUSED(n)) const +{ +} + +void wxVListBox::OnDrawBackground(wxDC& dc, const wxRect& rect, size_t n) const +{ + // we need to render selected and current items differently + const bool isSelected = IsSelected(n), + isCurrent = IsCurrent(n); + if ( isSelected || isCurrent ) + { + if ( isSelected ) + { + dc.SetBrush(wxBrush(m_colBgSel, wxSOLID)); + } + else // !selected + { + dc.SetBrush(*wxTRANSPARENT_BRUSH); + } + + dc.SetPen(*(isCurrent ? wxBLACK_PEN : wxTRANSPARENT_PEN)); + + dc.DrawRectangle(rect); + } + //else: do nothing for the normal items +} + +void wxVListBox::OnPaint(wxPaintEvent& WXUNUSED(event)) +{ + wxSize clientSize = GetClientSize(); + + wxAutoBufferedPaintDC dc(this); + + // the update rectangle + wxRect rectUpdate = GetUpdateClientRect(); + + // fill it with background colour + dc.SetBackground(GetBackgroundColour()); + dc.Clear(); + + // the bounding rectangle of the current line + wxRect rectLine; + rectLine.width = clientSize.x; + + // iterate over all visible lines + const size_t lineMax = GetVisibleEnd(); + for ( size_t line = GetFirstVisibleLine(); line < lineMax; line++ ) + { + const wxCoord hLine = OnGetLineHeight(line); + + rectLine.height = hLine; + + // and draw the ones which intersect the update rect + if ( rectLine.Intersects(rectUpdate) ) + { + // don't allow drawing outside of the lines rectangle + wxDCClipper clip(dc, rectLine); + + wxRect rect = rectLine; + OnDrawBackground(dc, rect, line); + + OnDrawSeparator(dc, rect, line); + + rect.Deflate(m_ptMargins.x, m_ptMargins.y); + OnDrawItem(dc, rect, line); + } + else // no intersection + { + if ( rectLine.GetTop() > rectUpdate.GetBottom() ) + { + // we are already below the update rect, no need to continue + // further + break; + } + //else: the next line may intersect the update rect + } + + rectLine.y += hLine; + } +} + +// ============================================================================ +// wxVListBox keyboard/mouse handling +// ============================================================================ + +void wxVListBox::DoHandleItemClick(int item, int flags) +{ + // has anything worth telling the client code about happened? + bool notify = false; + + if ( HasMultipleSelection() ) + { + // select the iteem clicked? + bool select = true; + + // NB: the keyboard interface we implement here corresponds to + // wxLB_EXTENDED rather than wxLB_MULTIPLE but this one makes more + // sense IMHO + if ( flags & ItemClick_Shift ) + { + if ( m_current != wxNOT_FOUND ) + { + if ( m_anchor == wxNOT_FOUND ) + m_anchor = m_current; + + select = false; + + // only the range from the selection anchor to new m_current + // must be selected + if ( DeselectAll() ) + notify = true; + + if ( SelectRange(m_anchor, item) ) + notify = true; + } + //else: treat it as ordinary click/keypress + } + else // Shift not pressed + { + m_anchor = item; + + if ( flags & ItemClick_Ctrl ) + { + select = false; + + if ( !(flags & ItemClick_Kbd) ) + { + Toggle(item); + + // the status of the item has definitely changed + notify = true; + } + //else: Ctrl-arrow pressed, don't change selection + } + //else: behave as in single selection case + } + + if ( select ) + { + // make the clicked item the only selection + if ( DeselectAll() ) + notify = true; + + if ( Select(item) ) + notify = true; + } + } + + // in any case the item should become the current one + if ( DoSetCurrent(item) ) + { + if ( !HasMultipleSelection() ) + { + // this has also changed the selection for single selection case + notify = true; + } + } + + if ( notify ) + { + // notify the user about the selection change + SendSelectedEvent(); + } + //else: nothing changed at all +} + +// ---------------------------------------------------------------------------- +// keyboard handling +// ---------------------------------------------------------------------------- + +void wxVListBox::OnKeyDown(wxKeyEvent& event) +{ + // flags for DoHandleItemClick() + int flags = ItemClick_Kbd; + + int current; + switch ( event.GetKeyCode() ) + { + case WXK_HOME: + current = 0; + break; + + case WXK_END: + current = GetLineCount() - 1; + break; + + case WXK_DOWN: + if ( m_current == (int)GetLineCount() - 1 ) + return; + + current = m_current + 1; + break; + + case WXK_UP: + if ( m_current == wxNOT_FOUND ) + current = GetLineCount() - 1; + else if ( m_current != 0 ) + current = m_current - 1; + else // m_current == 0 + return; + break; + + case WXK_PAGEDOWN: + PageDown(); + current = GetFirstVisibleLine(); + break; + + case WXK_PAGEUP: + if ( m_current == (int)GetFirstVisibleLine() ) + { + PageUp(); + } + + current = GetFirstVisibleLine(); + break; + + case WXK_SPACE: + // hack: pressing space should work like a mouse click rather than + // like a keyboard arrow press, so trick DoHandleItemClick() in + // thinking we were clicked + flags &= ~ItemClick_Kbd; + current = m_current; + break; + +#ifdef __WXMSW__ + case WXK_TAB: + // Since we are using wxWANTS_CHARS we need to send navigation + // events for the tabs on MSW + { + wxNavigationKeyEvent ne; + ne.SetDirection(!event.ShiftDown()); + ne.SetCurrentFocus(this); + ne.SetEventObject(this); + GetParent()->GetEventHandler()->ProcessEvent(ne); + } + // fall through to default +#endif + default: + event.Skip(); + current = 0; // just to silent the stupid compiler warnings + wxUnusedVar(current); + return; + } + + if ( event.ShiftDown() ) + flags |= ItemClick_Shift; + if ( event.ControlDown() ) + flags |= ItemClick_Ctrl; + + DoHandleItemClick(current, flags); +} + +// ---------------------------------------------------------------------------- +// wxVListBox mouse handling +// ---------------------------------------------------------------------------- + +void wxVListBox::OnLeftDown(wxMouseEvent& event) +{ + SetFocus(); + + int item = HitTest(event.GetPosition()); + + if ( item != wxNOT_FOUND ) + { + int flags = 0; + if ( event.ShiftDown() ) + flags |= ItemClick_Shift; + + // under Mac Apple-click is used in the same way as Ctrl-click + // elsewhere +#ifdef __WXMAC__ + if ( event.MetaDown() ) +#else + if ( event.ControlDown() ) +#endif + flags |= ItemClick_Ctrl; + + DoHandleItemClick(item, flags); + } +} + +void wxVListBox::OnLeftDClick(wxMouseEvent& eventMouse) +{ + int item = HitTest(eventMouse.GetPosition()); + if ( item != wxNOT_FOUND ) + { + + // if item double-clicked was not yet selected, then treat + // this event as a left-click instead + if ( item == m_current ) + { + wxCommandEvent event(wxEVT_COMMAND_LISTBOX_DOUBLECLICKED, GetId()); + event.SetEventObject(this); + event.SetInt(item); + + (void)GetEventHandler()->ProcessEvent(event); + } + else + { + OnLeftDown(eventMouse); + } + + } +} + + +// ---------------------------------------------------------------------------- +// use the same default attributes as wxListBox +// ---------------------------------------------------------------------------- + +//static +wxVisualAttributes +wxVListBox::GetClassDefaultAttributes(wxWindowVariant variant) +{ + return wxListBox::GetClassDefaultAttributes(variant); +} + +#endif diff --git a/Externals/wxWidgets/src/generic/vscroll.cpp b/Externals/wxWidgets/src/generic/vscroll.cpp index 705f579bc8..369b516e19 100644 --- a/Externals/wxWidgets/src/generic/vscroll.cpp +++ b/Externals/wxWidgets/src/generic/vscroll.cpp @@ -1,519 +1,519 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/generic/vscroll.cpp -// Purpose: wxVScrolledWindow implementation -// Author: Vadim Zeitlin -// Modified by: -// Created: 30.05.03 -// RCS-ID: $Id: vscroll.cpp 51579 2008-02-07 14:15:45Z JS $ -// Copyright: (c) 2003 Vadim Zeitlin -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ -#pragma hdrstop -#endif - -#ifndef WX_PRECOMP - #include "wx/sizer.h" -#endif - -#include "wx/vscroll.h" - -// ---------------------------------------------------------------------------- -// event tables -// ---------------------------------------------------------------------------- - -BEGIN_EVENT_TABLE(wxVScrolledWindow, wxPanel) - EVT_SIZE(wxVScrolledWindow::OnSize) - EVT_SCROLLWIN(wxVScrolledWindow::OnScroll) -#if wxUSE_MOUSEWHEEL - EVT_MOUSEWHEEL(wxVScrolledWindow::OnMouseWheel) -#endif -END_EVENT_TABLE() - - -// ============================================================================ -// implementation -// ============================================================================ - -IMPLEMENT_ABSTRACT_CLASS(wxVScrolledWindow, wxPanel) - -// ---------------------------------------------------------------------------- -// initialization -// ---------------------------------------------------------------------------- - -void wxVScrolledWindow::Init() -{ - // we're initially empty - m_lineMax = - m_lineFirst = 0; - - // this one should always be strictly positive - m_nVisible = 1; - - m_heightTotal = 0; - -#if wxUSE_MOUSEWHEEL - m_sumWheelRotation = 0; -#endif -} - -// ---------------------------------------------------------------------------- -// various helpers -// ---------------------------------------------------------------------------- - -wxCoord wxVScrolledWindow::EstimateTotalHeight() const -{ - // estimate the total height: it is impossible to call - // OnGetLineHeight() for every line because there may be too many of - // them, so we just make a guess using some lines in the beginning, - // some in the end and some in the middle - static const size_t NUM_LINES_TO_SAMPLE = 10; - - wxCoord heightTotal; - if ( m_lineMax < 3*NUM_LINES_TO_SAMPLE ) - { - // in this case calculating exactly is faster and more correct than - // guessing - heightTotal = GetLinesHeight(0, m_lineMax); - } - else // too many lines to calculate exactly - { - // look at some lines in the beginning/middle/end - heightTotal = - GetLinesHeight(0, NUM_LINES_TO_SAMPLE) + - GetLinesHeight(m_lineMax - NUM_LINES_TO_SAMPLE, m_lineMax) + - GetLinesHeight(m_lineMax/2 - NUM_LINES_TO_SAMPLE/2, - m_lineMax/2 + NUM_LINES_TO_SAMPLE/2); - - // use the height of the lines we looked as the average - heightTotal = (wxCoord) - (((float)heightTotal / (3*NUM_LINES_TO_SAMPLE)) * m_lineMax); - } - - return heightTotal; -} - -wxCoord wxVScrolledWindow::GetLinesHeight(size_t lineMin, size_t lineMax) const -{ - if ( lineMin == lineMax ) - return 0; - else if ( lineMin > lineMax ) - return -GetLinesHeight(lineMax, lineMin); - //else: lineMin < lineMax - - // let the user code know that we're going to need all these lines - OnGetLinesHint(lineMin, lineMax); - - // do sum up their heights - wxCoord height = 0; - for ( size_t line = lineMin; line < lineMax; line++ ) - { - height += OnGetLineHeight(line); - } - - return height; -} - -size_t wxVScrolledWindow::FindFirstFromBottom(size_t lineLast, bool full) -{ - const wxCoord hWindow = GetClientSize().y; - - // go upwards until we arrive at a line such that lineLast is not visible - // any more when it is shown - size_t lineFirst = lineLast; - wxCoord h = 0; - for ( ;; ) - { - h += OnGetLineHeight(lineFirst); - - if ( h > hWindow ) - { - // for this line to be fully visible we need to go one line - // down, but if it is enough for it to be only partly visible then - // this line will do as well - if ( full ) - { - lineFirst++; - } - - break; - } - - if ( !lineFirst ) - break; - - lineFirst--; - } - - return lineFirst; -} - -void wxVScrolledWindow::RemoveScrollbar() -{ - m_lineFirst = 0; - m_nVisible = m_lineMax; - SetScrollbar(wxVERTICAL, 0, 0, 0); -} - -void wxVScrolledWindow::UpdateScrollbar() -{ - // see how many lines can we fit on screen - const wxCoord hWindow = GetClientSize().y; - - wxCoord h = 0; - size_t line; - for ( line = m_lineFirst; line < m_lineMax; line++ ) - { - if ( h > hWindow ) - break; - - h += OnGetLineHeight(line); - } - - // if we still have remaining space below, maybe we can fit everything? - if ( h < hWindow ) - { - wxCoord hAll = h; - for ( size_t lineFirst = m_lineFirst; lineFirst > 0; lineFirst-- ) - { - hAll += OnGetLineHeight(m_lineFirst - 1); - if ( hAll > hWindow ) - break; - } - - if ( hAll < hWindow ) - { - // we don't need scrollbar at all - RemoveScrollbar(); - return; - } - } - - m_nVisible = line - m_lineFirst; - - int pageSize = m_nVisible; - if ( h > hWindow ) - { - // last line is only partially visible, we still need the scrollbar and - // so we have to "fix" pageSize because if it is equal to m_lineMax the - // scrollbar is not shown at all under MSW - pageSize--; - } - - // set the scrollbar parameters to reflect this - SetScrollbar(wxVERTICAL, m_lineFirst, pageSize, m_lineMax); -} - -// ---------------------------------------------------------------------------- -// operations -// ---------------------------------------------------------------------------- - -void wxVScrolledWindow::SetLineCount(size_t count) -{ - // save the number of lines - m_lineMax = count; - - // and our estimate for their total height - m_heightTotal = EstimateTotalHeight(); - - // recalculate the scrollbars parameters - if ( count ) - { - m_lineFirst = 1; // make sure it is != 0 - ScrollToLine(0); - } - else // no items - { - RemoveScrollbar(); - } -} - -void wxVScrolledWindow::RefreshLine(size_t line) -{ - // is this line visible? - if ( !IsVisible(line) ) - { - // no, it is useless to do anything - return; - } - - // calculate the rect occupied by this line on screen - wxRect rect; - rect.width = GetClientSize().x; - rect.height = OnGetLineHeight(line); - for ( size_t n = GetVisibleBegin(); n < line; n++ ) - { - rect.y += OnGetLineHeight(n); - } - - // do refresh it - RefreshRect(rect); -} - -void wxVScrolledWindow::RefreshLines(size_t from, size_t to) -{ - wxASSERT_MSG( from <= to, _T("RefreshLines(): empty range") ); - - // clump the range to just the visible lines -- it is useless to refresh - // the other ones - if ( from < GetVisibleBegin() ) - from = GetVisibleBegin(); - - if ( to >= GetVisibleEnd() ) - to = GetVisibleEnd(); - else - to++; - - // calculate the rect occupied by these lines on screen - wxRect rect; - rect.width = GetClientSize().x; - for ( size_t nBefore = GetVisibleBegin(); nBefore < from; nBefore++ ) - { - rect.y += OnGetLineHeight(nBefore); - } - - for ( size_t nBetween = from; nBetween < to; nBetween++ ) - { - rect.height += OnGetLineHeight(nBetween); - } - - // do refresh it - RefreshRect(rect); -} - -void wxVScrolledWindow::RefreshAll() -{ - UpdateScrollbar(); - - Refresh(); -} - -bool wxVScrolledWindow::Layout() -{ - if ( GetSizer() ) - { - // adjust the sizer dimensions/position taking into account the - // virtual size and scrolled position of the window. - - int w = 0, h = 0; - GetVirtualSize(&w, &h); - - // x is always 0 so no variable needed - int y = -GetLinesHeight(0, GetFirstVisibleLine()); - - GetSizer()->SetDimension(0, y, w, h); - return true; - } - - // fall back to default for LayoutConstraints - return wxPanel::Layout(); -} - -int wxVScrolledWindow::HitTest(wxCoord WXUNUSED(x), wxCoord y) const -{ - const size_t lineMax = GetVisibleEnd(); - for ( size_t line = GetVisibleBegin(); line < lineMax; line++ ) - { - y -= OnGetLineHeight(line); - if ( y < 0 ) - return line; - } - - return wxNOT_FOUND; -} - -// ---------------------------------------------------------------------------- -// scrolling -// ---------------------------------------------------------------------------- - -bool wxVScrolledWindow::ScrollToLine(size_t line) -{ - if ( !m_lineMax ) - { - // we're empty, code below doesn't make sense in this case - return false; - } - - // determine the real first line to scroll to: we shouldn't scroll beyond - // the end - size_t lineFirstLast = FindFirstFromBottom(m_lineMax - 1, true); - if ( line > lineFirstLast ) - line = lineFirstLast; - - // anything to do? - if ( line == m_lineFirst ) - { - // no - return false; - } - - - // remember the currently shown lines for the refresh code below - size_t lineFirstOld = GetVisibleBegin(), - lineLastOld = GetVisibleEnd(); - - m_lineFirst = line; - - - // the size of scrollbar thumb could have changed - UpdateScrollbar(); - - - // finally refresh the display -- but only redraw as few lines as possible - // to avoid flicker - if ( GetVisibleBegin() >= lineLastOld || - GetVisibleEnd() <= lineFirstOld ) - { - // the simplest case: we don't have any old lines left, just redraw - // everything - Refresh(); - } - else // overlap between the lines we showed before and should show now - { - // Avoid scrolling visible parts of the screen on Mac -#ifdef __WXMAC__ - if (!IsShownOnScreen()) - Refresh(); - else -#endif - ScrollWindow(0, GetLinesHeight(GetVisibleBegin(), lineFirstOld)); - } - - return true; -} - -bool wxVScrolledWindow::ScrollLines(int lines) -{ - lines += m_lineFirst; - if ( lines < 0 ) - lines = 0; - - return ScrollToLine(lines); -} - -bool wxVScrolledWindow::ScrollPages(int pages) -{ - bool didSomething = false; - - while ( pages ) - { - int line; - if ( pages > 0 ) - { - line = GetVisibleEnd(); - if ( line ) - line--; - pages--; - } - else // pages < 0 - { - line = FindFirstFromBottom(GetVisibleBegin()); - pages++; - } - - didSomething = ScrollToLine(line); - } - - return didSomething; -} - -// ---------------------------------------------------------------------------- -// event handling -// ---------------------------------------------------------------------------- - -void wxVScrolledWindow::OnSize(wxSizeEvent& event) -{ - UpdateScrollbar(); - - event.Skip(); -} - -void wxVScrolledWindow::OnScroll(wxScrollWinEvent& event) -{ - size_t lineFirstNew; - - const wxEventType evtType = event.GetEventType(); - - if ( evtType == wxEVT_SCROLLWIN_TOP ) - { - lineFirstNew = 0; - } - else if ( evtType == wxEVT_SCROLLWIN_BOTTOM ) - { - lineFirstNew = m_lineMax; - } - else if ( evtType == wxEVT_SCROLLWIN_LINEUP ) - { - lineFirstNew = m_lineFirst ? m_lineFirst - 1 : 0; - } - else if ( evtType == wxEVT_SCROLLWIN_LINEDOWN ) - { - lineFirstNew = m_lineFirst + 1; - } - else if ( evtType == wxEVT_SCROLLWIN_PAGEUP ) - { - lineFirstNew = FindFirstFromBottom(m_lineFirst); - } - else if ( evtType == wxEVT_SCROLLWIN_PAGEDOWN ) - { - lineFirstNew = GetVisibleEnd(); - if ( lineFirstNew ) - lineFirstNew--; - } - else if ( evtType == wxEVT_SCROLLWIN_THUMBRELEASE ) - { - lineFirstNew = event.GetPosition(); - } - else if ( evtType == wxEVT_SCROLLWIN_THUMBTRACK ) - { - lineFirstNew = event.GetPosition(); - } - - else // unknown scroll event? - { - wxFAIL_MSG( _T("unknown scroll event type?") ); - return; - } - - ScrollToLine(lineFirstNew); - -#ifdef __WXMAC__ - Update(); -#endif // __WXMAC__ -} - -#if wxUSE_MOUSEWHEEL - -void wxVScrolledWindow::OnMouseWheel(wxMouseEvent& event) -{ - m_sumWheelRotation += event.GetWheelRotation(); - int delta = event.GetWheelDelta(); - - // how much to scroll this time - int units_to_scroll = -(m_sumWheelRotation/delta); - if ( !units_to_scroll ) - return; - - m_sumWheelRotation += units_to_scroll*delta; - - if ( !event.IsPageScroll() ) - ScrollLines( units_to_scroll*event.GetLinesPerAction() ); - else - // scroll pages instead of lines - ScrollPages( units_to_scroll ); -} - -#endif // wxUSE_MOUSEWHEEL - +///////////////////////////////////////////////////////////////////////////// +// Name: src/generic/vscroll.cpp +// Purpose: wxVScrolledWindow implementation +// Author: Vadim Zeitlin +// Modified by: +// Created: 30.05.03 +// RCS-ID: $Id: vscroll.cpp 51579 2008-02-07 14:15:45Z JS $ +// Copyright: (c) 2003 Vadim Zeitlin +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ +#pragma hdrstop +#endif + +#ifndef WX_PRECOMP + #include "wx/sizer.h" +#endif + +#include "wx/vscroll.h" + +// ---------------------------------------------------------------------------- +// event tables +// ---------------------------------------------------------------------------- + +BEGIN_EVENT_TABLE(wxVScrolledWindow, wxPanel) + EVT_SIZE(wxVScrolledWindow::OnSize) + EVT_SCROLLWIN(wxVScrolledWindow::OnScroll) +#if wxUSE_MOUSEWHEEL + EVT_MOUSEWHEEL(wxVScrolledWindow::OnMouseWheel) +#endif +END_EVENT_TABLE() + + +// ============================================================================ +// implementation +// ============================================================================ + +IMPLEMENT_ABSTRACT_CLASS(wxVScrolledWindow, wxPanel) + +// ---------------------------------------------------------------------------- +// initialization +// ---------------------------------------------------------------------------- + +void wxVScrolledWindow::Init() +{ + // we're initially empty + m_lineMax = + m_lineFirst = 0; + + // this one should always be strictly positive + m_nVisible = 1; + + m_heightTotal = 0; + +#if wxUSE_MOUSEWHEEL + m_sumWheelRotation = 0; +#endif +} + +// ---------------------------------------------------------------------------- +// various helpers +// ---------------------------------------------------------------------------- + +wxCoord wxVScrolledWindow::EstimateTotalHeight() const +{ + // estimate the total height: it is impossible to call + // OnGetLineHeight() for every line because there may be too many of + // them, so we just make a guess using some lines in the beginning, + // some in the end and some in the middle + static const size_t NUM_LINES_TO_SAMPLE = 10; + + wxCoord heightTotal; + if ( m_lineMax < 3*NUM_LINES_TO_SAMPLE ) + { + // in this case calculating exactly is faster and more correct than + // guessing + heightTotal = GetLinesHeight(0, m_lineMax); + } + else // too many lines to calculate exactly + { + // look at some lines in the beginning/middle/end + heightTotal = + GetLinesHeight(0, NUM_LINES_TO_SAMPLE) + + GetLinesHeight(m_lineMax - NUM_LINES_TO_SAMPLE, m_lineMax) + + GetLinesHeight(m_lineMax/2 - NUM_LINES_TO_SAMPLE/2, + m_lineMax/2 + NUM_LINES_TO_SAMPLE/2); + + // use the height of the lines we looked as the average + heightTotal = (wxCoord) + (((float)heightTotal / (3*NUM_LINES_TO_SAMPLE)) * m_lineMax); + } + + return heightTotal; +} + +wxCoord wxVScrolledWindow::GetLinesHeight(size_t lineMin, size_t lineMax) const +{ + if ( lineMin == lineMax ) + return 0; + else if ( lineMin > lineMax ) + return -GetLinesHeight(lineMax, lineMin); + //else: lineMin < lineMax + + // let the user code know that we're going to need all these lines + OnGetLinesHint(lineMin, lineMax); + + // do sum up their heights + wxCoord height = 0; + for ( size_t line = lineMin; line < lineMax; line++ ) + { + height += OnGetLineHeight(line); + } + + return height; +} + +size_t wxVScrolledWindow::FindFirstFromBottom(size_t lineLast, bool full) +{ + const wxCoord hWindow = GetClientSize().y; + + // go upwards until we arrive at a line such that lineLast is not visible + // any more when it is shown + size_t lineFirst = lineLast; + wxCoord h = 0; + for ( ;; ) + { + h += OnGetLineHeight(lineFirst); + + if ( h > hWindow ) + { + // for this line to be fully visible we need to go one line + // down, but if it is enough for it to be only partly visible then + // this line will do as well + if ( full ) + { + lineFirst++; + } + + break; + } + + if ( !lineFirst ) + break; + + lineFirst--; + } + + return lineFirst; +} + +void wxVScrolledWindow::RemoveScrollbar() +{ + m_lineFirst = 0; + m_nVisible = m_lineMax; + SetScrollbar(wxVERTICAL, 0, 0, 0); +} + +void wxVScrolledWindow::UpdateScrollbar() +{ + // see how many lines can we fit on screen + const wxCoord hWindow = GetClientSize().y; + + wxCoord h = 0; + size_t line; + for ( line = m_lineFirst; line < m_lineMax; line++ ) + { + if ( h > hWindow ) + break; + + h += OnGetLineHeight(line); + } + + // if we still have remaining space below, maybe we can fit everything? + if ( h < hWindow ) + { + wxCoord hAll = h; + for ( size_t lineFirst = m_lineFirst; lineFirst > 0; lineFirst-- ) + { + hAll += OnGetLineHeight(m_lineFirst - 1); + if ( hAll > hWindow ) + break; + } + + if ( hAll < hWindow ) + { + // we don't need scrollbar at all + RemoveScrollbar(); + return; + } + } + + m_nVisible = line - m_lineFirst; + + int pageSize = m_nVisible; + if ( h > hWindow ) + { + // last line is only partially visible, we still need the scrollbar and + // so we have to "fix" pageSize because if it is equal to m_lineMax the + // scrollbar is not shown at all under MSW + pageSize--; + } + + // set the scrollbar parameters to reflect this + SetScrollbar(wxVERTICAL, m_lineFirst, pageSize, m_lineMax); +} + +// ---------------------------------------------------------------------------- +// operations +// ---------------------------------------------------------------------------- + +void wxVScrolledWindow::SetLineCount(size_t count) +{ + // save the number of lines + m_lineMax = count; + + // and our estimate for their total height + m_heightTotal = EstimateTotalHeight(); + + // recalculate the scrollbars parameters + if ( count ) + { + m_lineFirst = 1; // make sure it is != 0 + ScrollToLine(0); + } + else // no items + { + RemoveScrollbar(); + } +} + +void wxVScrolledWindow::RefreshLine(size_t line) +{ + // is this line visible? + if ( !IsVisible(line) ) + { + // no, it is useless to do anything + return; + } + + // calculate the rect occupied by this line on screen + wxRect rect; + rect.width = GetClientSize().x; + rect.height = OnGetLineHeight(line); + for ( size_t n = GetVisibleBegin(); n < line; n++ ) + { + rect.y += OnGetLineHeight(n); + } + + // do refresh it + RefreshRect(rect); +} + +void wxVScrolledWindow::RefreshLines(size_t from, size_t to) +{ + wxASSERT_MSG( from <= to, _T("RefreshLines(): empty range") ); + + // clump the range to just the visible lines -- it is useless to refresh + // the other ones + if ( from < GetVisibleBegin() ) + from = GetVisibleBegin(); + + if ( to >= GetVisibleEnd() ) + to = GetVisibleEnd(); + else + to++; + + // calculate the rect occupied by these lines on screen + wxRect rect; + rect.width = GetClientSize().x; + for ( size_t nBefore = GetVisibleBegin(); nBefore < from; nBefore++ ) + { + rect.y += OnGetLineHeight(nBefore); + } + + for ( size_t nBetween = from; nBetween < to; nBetween++ ) + { + rect.height += OnGetLineHeight(nBetween); + } + + // do refresh it + RefreshRect(rect); +} + +void wxVScrolledWindow::RefreshAll() +{ + UpdateScrollbar(); + + Refresh(); +} + +bool wxVScrolledWindow::Layout() +{ + if ( GetSizer() ) + { + // adjust the sizer dimensions/position taking into account the + // virtual size and scrolled position of the window. + + int w = 0, h = 0; + GetVirtualSize(&w, &h); + + // x is always 0 so no variable needed + int y = -GetLinesHeight(0, GetFirstVisibleLine()); + + GetSizer()->SetDimension(0, y, w, h); + return true; + } + + // fall back to default for LayoutConstraints + return wxPanel::Layout(); +} + +int wxVScrolledWindow::HitTest(wxCoord WXUNUSED(x), wxCoord y) const +{ + const size_t lineMax = GetVisibleEnd(); + for ( size_t line = GetVisibleBegin(); line < lineMax; line++ ) + { + y -= OnGetLineHeight(line); + if ( y < 0 ) + return line; + } + + return wxNOT_FOUND; +} + +// ---------------------------------------------------------------------------- +// scrolling +// ---------------------------------------------------------------------------- + +bool wxVScrolledWindow::ScrollToLine(size_t line) +{ + if ( !m_lineMax ) + { + // we're empty, code below doesn't make sense in this case + return false; + } + + // determine the real first line to scroll to: we shouldn't scroll beyond + // the end + size_t lineFirstLast = FindFirstFromBottom(m_lineMax - 1, true); + if ( line > lineFirstLast ) + line = lineFirstLast; + + // anything to do? + if ( line == m_lineFirst ) + { + // no + return false; + } + + + // remember the currently shown lines for the refresh code below + size_t lineFirstOld = GetVisibleBegin(), + lineLastOld = GetVisibleEnd(); + + m_lineFirst = line; + + + // the size of scrollbar thumb could have changed + UpdateScrollbar(); + + + // finally refresh the display -- but only redraw as few lines as possible + // to avoid flicker + if ( GetVisibleBegin() >= lineLastOld || + GetVisibleEnd() <= lineFirstOld ) + { + // the simplest case: we don't have any old lines left, just redraw + // everything + Refresh(); + } + else // overlap between the lines we showed before and should show now + { + // Avoid scrolling visible parts of the screen on Mac +#ifdef __WXMAC__ + if (!IsShownOnScreen()) + Refresh(); + else +#endif + ScrollWindow(0, GetLinesHeight(GetVisibleBegin(), lineFirstOld)); + } + + return true; +} + +bool wxVScrolledWindow::ScrollLines(int lines) +{ + lines += m_lineFirst; + if ( lines < 0 ) + lines = 0; + + return ScrollToLine(lines); +} + +bool wxVScrolledWindow::ScrollPages(int pages) +{ + bool didSomething = false; + + while ( pages ) + { + int line; + if ( pages > 0 ) + { + line = GetVisibleEnd(); + if ( line ) + line--; + pages--; + } + else // pages < 0 + { + line = FindFirstFromBottom(GetVisibleBegin()); + pages++; + } + + didSomething = ScrollToLine(line); + } + + return didSomething; +} + +// ---------------------------------------------------------------------------- +// event handling +// ---------------------------------------------------------------------------- + +void wxVScrolledWindow::OnSize(wxSizeEvent& event) +{ + UpdateScrollbar(); + + event.Skip(); +} + +void wxVScrolledWindow::OnScroll(wxScrollWinEvent& event) +{ + size_t lineFirstNew; + + const wxEventType evtType = event.GetEventType(); + + if ( evtType == wxEVT_SCROLLWIN_TOP ) + { + lineFirstNew = 0; + } + else if ( evtType == wxEVT_SCROLLWIN_BOTTOM ) + { + lineFirstNew = m_lineMax; + } + else if ( evtType == wxEVT_SCROLLWIN_LINEUP ) + { + lineFirstNew = m_lineFirst ? m_lineFirst - 1 : 0; + } + else if ( evtType == wxEVT_SCROLLWIN_LINEDOWN ) + { + lineFirstNew = m_lineFirst + 1; + } + else if ( evtType == wxEVT_SCROLLWIN_PAGEUP ) + { + lineFirstNew = FindFirstFromBottom(m_lineFirst); + } + else if ( evtType == wxEVT_SCROLLWIN_PAGEDOWN ) + { + lineFirstNew = GetVisibleEnd(); + if ( lineFirstNew ) + lineFirstNew--; + } + else if ( evtType == wxEVT_SCROLLWIN_THUMBRELEASE ) + { + lineFirstNew = event.GetPosition(); + } + else if ( evtType == wxEVT_SCROLLWIN_THUMBTRACK ) + { + lineFirstNew = event.GetPosition(); + } + + else // unknown scroll event? + { + wxFAIL_MSG( _T("unknown scroll event type?") ); + return; + } + + ScrollToLine(lineFirstNew); + +#ifdef __WXMAC__ + Update(); +#endif // __WXMAC__ +} + +#if wxUSE_MOUSEWHEEL + +void wxVScrolledWindow::OnMouseWheel(wxMouseEvent& event) +{ + m_sumWheelRotation += event.GetWheelRotation(); + int delta = event.GetWheelDelta(); + + // how much to scroll this time + int units_to_scroll = -(m_sumWheelRotation/delta); + if ( !units_to_scroll ) + return; + + m_sumWheelRotation += units_to_scroll*delta; + + if ( !event.IsPageScroll() ) + ScrollLines( units_to_scroll*event.GetLinesPerAction() ); + else + // scroll pages instead of lines + ScrollPages( units_to_scroll ); +} + +#endif // wxUSE_MOUSEWHEEL + diff --git a/Externals/wxWidgets/src/generic/wizard.cpp b/Externals/wxWidgets/src/generic/wizard.cpp index d7d6affe9e..24588e2299 100644 --- a/Externals/wxWidgets/src/generic/wizard.cpp +++ b/Externals/wxWidgets/src/generic/wizard.cpp @@ -1,877 +1,877 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: src/generic/wizard.cpp -// Purpose: generic implementation of wxWizard class -// Author: Vadim Zeitlin -// Modified by: Robert Cavanaugh -// 1) Added capability for wxWizardPage to accept resources -// 2) Added "Help" button handler stub -// 3) Fixed ShowPage() bug on displaying bitmaps -// Robert Vazan (sizers) -// Created: 15.08.99 -// RCS-ID: $Id: wizard.cpp 47065 2007-07-02 08:00:17Z JS $ -// Copyright: (c) 1999 Vadim Zeitlin -// Licence: wxWindows licence -/////////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_WIZARDDLG - -#ifndef WX_PRECOMP - #include "wx/dynarray.h" - #include "wx/intl.h" - #include "wx/statbmp.h" - #include "wx/button.h" - #include "wx/settings.h" - #include "wx/sizer.h" -#endif //WX_PRECOMP - -#include "wx/statline.h" - -#include "wx/wizard.h" - -// ---------------------------------------------------------------------------- -// wxWizardSizer -// ---------------------------------------------------------------------------- - -class wxWizardSizer : public wxSizer -{ -public: - wxWizardSizer(wxWizard *owner); - - virtual wxSizerItem *Insert(size_t index, wxSizerItem *item); - - virtual void RecalcSizes(); - virtual wxSize CalcMin(); - - // get the max size of all wizard pages - wxSize GetMaxChildSize(); - - // return the border which can be either set using wxWizard::SetBorder() or - // have default value - int GetBorder() const; - - // hide the pages which we temporarily "show" when they're added to this - // sizer (see Insert()) - void HidePages(); - -private: - wxSize SiblingSize(wxSizerItem *child); - - wxWizard *m_owner; - wxSize m_childSize; -}; - -// ---------------------------------------------------------------------------- -// event tables and such -// ---------------------------------------------------------------------------- - -DEFINE_EVENT_TYPE(wxEVT_WIZARD_PAGE_CHANGED) -DEFINE_EVENT_TYPE(wxEVT_WIZARD_PAGE_CHANGING) -DEFINE_EVENT_TYPE(wxEVT_WIZARD_CANCEL) -DEFINE_EVENT_TYPE(wxEVT_WIZARD_FINISHED) -DEFINE_EVENT_TYPE(wxEVT_WIZARD_HELP) - -BEGIN_EVENT_TABLE(wxWizard, wxDialog) - EVT_BUTTON(wxID_CANCEL, wxWizard::OnCancel) - EVT_BUTTON(wxID_BACKWARD, wxWizard::OnBackOrNext) - EVT_BUTTON(wxID_FORWARD, wxWizard::OnBackOrNext) - EVT_BUTTON(wxID_HELP, wxWizard::OnHelp) - - EVT_WIZARD_PAGE_CHANGED(wxID_ANY, wxWizard::OnWizEvent) - EVT_WIZARD_PAGE_CHANGING(wxID_ANY, wxWizard::OnWizEvent) - EVT_WIZARD_CANCEL(wxID_ANY, wxWizard::OnWizEvent) - EVT_WIZARD_FINISHED(wxID_ANY, wxWizard::OnWizEvent) - EVT_WIZARD_HELP(wxID_ANY, wxWizard::OnWizEvent) -END_EVENT_TABLE() - -IMPLEMENT_DYNAMIC_CLASS(wxWizard, wxDialog) - -/* - TODO PROPERTIES : - wxWizard - extstyle - title -*/ - -IMPLEMENT_ABSTRACT_CLASS(wxWizardPage, wxPanel) -IMPLEMENT_DYNAMIC_CLASS(wxWizardPageSimple, wxWizardPage) -IMPLEMENT_DYNAMIC_CLASS(wxWizardEvent, wxNotifyEvent) - -// ============================================================================ -// implementation -// ============================================================================ - -// ---------------------------------------------------------------------------- -// wxWizardPage -// ---------------------------------------------------------------------------- - -void wxWizardPage::Init() -{ - m_bitmap = wxNullBitmap; -} - -wxWizardPage::wxWizardPage(wxWizard *parent, - const wxBitmap& bitmap, - const wxChar *resource) -{ - Create(parent, bitmap, resource); -} - -bool wxWizardPage::Create(wxWizard *parent, - const wxBitmap& bitmap, - const wxChar *resource) -{ - if ( !wxPanel::Create(parent, wxID_ANY) ) - return false; - - if ( resource != NULL ) - { -#if wxUSE_WX_RESOURCES -#if 0 - if ( !LoadFromResource(this, resource) ) - { - wxFAIL_MSG(wxT("wxWizardPage LoadFromResource failed!!!!")); - } -#endif -#endif // wxUSE_RESOURCES - } - - m_bitmap = bitmap; - - // initially the page is hidden, it's shown only when it becomes current - Hide(); - - return true; -} - -// ---------------------------------------------------------------------------- -// wxWizardPageSimple -// ---------------------------------------------------------------------------- - -wxWizardPage *wxWizardPageSimple::GetPrev() const -{ - return m_prev; -} - -wxWizardPage *wxWizardPageSimple::GetNext() const -{ - return m_next; -} - -// ---------------------------------------------------------------------------- -// wxWizardSizer -// ---------------------------------------------------------------------------- - -wxWizardSizer::wxWizardSizer(wxWizard *owner) - : m_owner(owner), - m_childSize(wxDefaultSize) -{ -} - -wxSizerItem *wxWizardSizer::Insert(size_t index, wxSizerItem *item) -{ - m_owner->m_usingSizer = true; - - if ( item->IsWindow() ) - { - // we must pretend that the window is shown as otherwise it wouldn't be - // taken into account for the layout -- but avoid really showing it, so - // just set the internal flag instead of calling wxWindow::Show() - item->GetWindow()->wxWindowBase::Show(); - } - - return wxSizer::Insert(index, item); -} - -void wxWizardSizer::HidePages() -{ - for ( wxSizerItemList::compatibility_iterator node = GetChildren().GetFirst(); - node; - node = node->GetNext() ) - { - wxSizerItem * const item = node->GetData(); - if ( item->IsWindow() ) - item->GetWindow()->wxWindowBase::Show(false); - } -} - -void wxWizardSizer::RecalcSizes() -{ - // Effect of this function depends on m_owner->m_page and - // it should be called whenever it changes (wxWizard::ShowPage) - if ( m_owner->m_page ) - { - m_owner->m_page->SetSize(wxRect(m_position, m_size)); - } -} - -wxSize wxWizardSizer::CalcMin() -{ - return m_owner->GetPageSize(); -} - -wxSize wxWizardSizer::GetMaxChildSize() -{ -#if !defined(__WXDEBUG__) - if ( m_childSize.IsFullySpecified() ) - return m_childSize; -#endif - - wxSize maxOfMin; - - for ( wxSizerItemList::compatibility_iterator childNode = m_children.GetFirst(); - childNode; - childNode = childNode->GetNext() ) - { - wxSizerItem *child = childNode->GetData(); - maxOfMin.IncTo(child->CalcMin()); - maxOfMin.IncTo(SiblingSize(child)); - } - -#ifdef __WXDEBUG__ - if ( m_childSize.IsFullySpecified() && m_childSize != maxOfMin ) - { - wxFAIL_MSG( _T("Size changed in wxWizard::GetPageAreaSizer()") - _T("after RunWizard().\n") - _T("Did you forget to call GetSizer()->Fit(this) ") - _T("for some page?")) ; - - return m_childSize; - } -#endif // __WXDEBUG__ - - if ( m_owner->m_started ) - { - m_childSize = maxOfMin; - } - - return maxOfMin; -} - -int wxWizardSizer::GetBorder() const -{ - return m_owner->m_border; -} - -wxSize wxWizardSizer::SiblingSize(wxSizerItem *child) -{ - wxSize maxSibling; - - if ( child->IsWindow() ) - { - wxWizardPage *page = wxDynamicCast(child->GetWindow(), wxWizardPage); - if ( page ) - { - for ( wxWizardPage *sibling = page->GetNext(); - sibling; - sibling = sibling->GetNext() ) - { - if ( sibling->GetSizer() ) - { - maxSibling.IncTo(sibling->GetSizer()->CalcMin()); - } - } - } - } - - return maxSibling; -} - -// ---------------------------------------------------------------------------- -// generic wxWizard implementation -// ---------------------------------------------------------------------------- - -void wxWizard::Init() -{ - m_posWizard = wxDefaultPosition; - m_page = (wxWizardPage *)NULL; - m_btnPrev = m_btnNext = NULL; - m_statbmp = NULL; - m_sizerBmpAndPage = NULL; - m_sizerPage = NULL; - m_border = 5; - m_started = false; - m_wasModal = false; - m_usingSizer = false; -} - -bool wxWizard::Create(wxWindow *parent, - int id, - const wxString& title, - const wxBitmap& bitmap, - const wxPoint& pos, - long style) -{ - bool result = wxDialog::Create(parent,id,title,pos,wxDefaultSize,style); - - m_posWizard = pos; - m_bitmap = bitmap ; - - DoCreateControls(); - - return result; -} - -wxWizard::~wxWizard() -{ - // normally we don't have to delete this sizer as it's deleted by the - // associated window but if we never used it or didn't set it as the window - // sizer yet, do delete it manually - if ( !m_usingSizer || !m_started ) - delete m_sizerPage; -} - -void wxWizard::AddBitmapRow(wxBoxSizer *mainColumn) -{ - m_sizerBmpAndPage = new wxBoxSizer(wxHORIZONTAL); - mainColumn->Add( - m_sizerBmpAndPage, - 1, // Vertically stretchable - wxEXPAND // Horizonal stretching, no border - ); - mainColumn->Add(0,5, - 0, // No vertical stretching - wxEXPAND // No border, (mostly useless) horizontal stretching - ); - -#if wxUSE_STATBMP - if ( m_bitmap.Ok() ) - { - m_statbmp = new wxStaticBitmap(this, wxID_ANY, m_bitmap); - m_sizerBmpAndPage->Add( - m_statbmp, - 0, // No horizontal stretching - wxALL, // Border all around, top alignment - 5 // Border width - ); - m_sizerBmpAndPage->Add( - 5,0, - 0, // No horizontal stretching - wxEXPAND // No border, (mostly useless) vertical stretching - ); - } -#endif - - // Added to m_sizerBmpAndPage later - m_sizerPage = new wxWizardSizer(this); -} - -void wxWizard::AddStaticLine(wxBoxSizer *mainColumn) -{ -#if wxUSE_STATLINE - mainColumn->Add( - new wxStaticLine(this, wxID_ANY), - 0, // Vertically unstretchable - wxEXPAND | wxALL, // Border all around, horizontally stretchable - 5 // Border width - ); - mainColumn->Add(0,5, - 0, // No vertical stretching - wxEXPAND // No border, (mostly useless) horizontal stretching - ); -#else - (void)mainColumn; -#endif // wxUSE_STATLINE -} - -void wxWizard::AddBackNextPair(wxBoxSizer *buttonRow) -{ - wxASSERT_MSG( m_btnNext && m_btnPrev, - _T("You must create the buttons before calling ") - _T("wxWizard::AddBackNextPair") ); - - // margin between Back and Next buttons -#ifdef __WXMAC__ - static const int BACKNEXT_MARGIN = 10; -#else - static const int BACKNEXT_MARGIN = 0; -#endif - - wxBoxSizer *backNextPair = new wxBoxSizer(wxHORIZONTAL); - buttonRow->Add( - backNextPair, - 0, // No horizontal stretching - wxALL, // Border all around - 5 // Border width - ); - - backNextPair->Add(m_btnPrev); - backNextPair->Add(BACKNEXT_MARGIN,0, - 0, // No horizontal stretching - wxEXPAND // No border, (mostly useless) vertical stretching - ); - backNextPair->Add(m_btnNext); -} - -void wxWizard::AddButtonRow(wxBoxSizer *mainColumn) -{ - // the order in which the buttons are created determines the TAB order - at least under MSWindows... - // although the 'back' button appears before the 'next' button, a more userfriendly tab order is - // to activate the 'next' button first (create the next button before the back button). - // The reason is: The user will repeatedly enter information in the wizard pages and then wants to - // press 'next'. If a user uses mostly the keyboard, he would have to skip the 'back' button - // everytime. This is annoying. There is a second reason: RETURN acts as TAB. If the 'next' - // button comes first in the TAB order, the user can enter information very fast using the RETURN - // key to TAB to the next entry field and page. This would not be possible, if the 'back' button - // was created before the 'next' button. - - bool isPda = (wxSystemSettings::GetScreenType() <= wxSYS_SCREEN_PDA); - int buttonStyle = isPda ? wxBU_EXACTFIT : 0; - - wxBoxSizer *buttonRow = new wxBoxSizer(wxHORIZONTAL); -#ifdef __WXMAC__ - if (GetExtraStyle() & wxWIZARD_EX_HELPBUTTON) - mainColumn->Add( - buttonRow, - 0, // Vertically unstretchable - wxGROW|wxALIGN_CENTRE - ); - else -#endif - mainColumn->Add( - buttonRow, - 0, // Vertically unstretchable - wxALIGN_RIGHT // Right aligned, no border - ); - - // Desired TAB order is 'next', 'cancel', 'help', 'back'. This makes the 'back' button the last control on the page. - // Create the buttons in the right order... - wxButton *btnHelp=0; -#ifdef __WXMAC__ - if (GetExtraStyle() & wxWIZARD_EX_HELPBUTTON) - btnHelp=new wxButton(this, wxID_HELP, _("&Help"), wxDefaultPosition, wxDefaultSize, buttonStyle); -#endif - - m_btnNext = new wxButton(this, wxID_FORWARD, _("&Next >")); - wxButton *btnCancel=new wxButton(this, wxID_CANCEL, _("&Cancel"), wxDefaultPosition, wxDefaultSize, buttonStyle); -#ifndef __WXMAC__ - if (GetExtraStyle() & wxWIZARD_EX_HELPBUTTON) - btnHelp=new wxButton(this, wxID_HELP, _("&Help"), wxDefaultPosition, wxDefaultSize, buttonStyle); -#endif - m_btnPrev = new wxButton(this, wxID_BACKWARD, _("< &Back"), wxDefaultPosition, wxDefaultSize, buttonStyle); - - if (btnHelp) - { - buttonRow->Add( - btnHelp, - 0, // Horizontally unstretchable - wxALL, // Border all around, top aligned - 5 // Border width - ); -#ifdef __WXMAC__ - // Put stretchable space between help button and others - buttonRow->Add(0, 0, 1, wxALIGN_CENTRE, 0); -#endif - } - - AddBackNextPair(buttonRow); - - buttonRow->Add( - btnCancel, - 0, // Horizontally unstretchable - wxALL, // Border all around, top aligned - 5 // Border width - ); -} - -void wxWizard::DoCreateControls() -{ - // do nothing if the controls were already created - if ( WasCreated() ) - return; - - bool isPda = (wxSystemSettings::GetScreenType() <= wxSYS_SCREEN_PDA); - - // Horizontal stretching, and if not PDA, border all around - int mainColumnSizerFlags = isPda ? wxEXPAND : wxALL|wxEXPAND ; - - // wxWindow::SetSizer will be called at end - wxBoxSizer *windowSizer = new wxBoxSizer(wxVERTICAL); - - wxBoxSizer *mainColumn = new wxBoxSizer(wxVERTICAL); - windowSizer->Add( - mainColumn, - 1, // Vertical stretching - mainColumnSizerFlags, - 5 // Border width - ); - - AddBitmapRow(mainColumn); - - if (!isPda) - AddStaticLine(mainColumn); - - AddButtonRow(mainColumn); - - SetSizer(windowSizer); -} - -void wxWizard::SetPageSize(const wxSize& size) -{ - wxCHECK_RET(!m_started, wxT("wxWizard::SetPageSize after RunWizard")); - m_sizePage = size; -} - -void wxWizard::FitToPage(const wxWizardPage *page) -{ - wxCHECK_RET(!m_started, wxT("wxWizard::FitToPage after RunWizard")); - - while ( page ) - { - wxSize size = page->GetBestSize(); - - m_sizePage.IncTo(size); - - page = page->GetNext(); - } -} - -bool wxWizard::ShowPage(wxWizardPage *page, bool goingForward) -{ - wxASSERT_MSG( page != m_page, wxT("this is useless") ); - - wxSizerFlags flags(1); - flags.Border(wxALL, m_border).Expand(); - - if ( !m_started ) - { - if ( m_usingSizer ) - { - m_sizerBmpAndPage->Add(m_sizerPage, flags); - - // now that our layout is computed correctly, hide the pages - // artificially shown in wxWizardSizer::Insert() back again - m_sizerPage->HidePages(); - } - } - - - // we'll use this to decide whether we have to change the label of this - // button or not (initially the label is "Next") - bool btnLabelWasNext = true; - - // remember the old bitmap (if any) to compare with the new one later - wxBitmap bmpPrev; - - // check for previous page - if ( m_page ) - { - // send the event to the old page - wxWizardEvent event(wxEVT_WIZARD_PAGE_CHANGING, GetId(), - goingForward, m_page); - if ( m_page->GetEventHandler()->ProcessEvent(event) && - !event.IsAllowed() ) - { - // vetoed by the page - return false; - } - - m_page->Hide(); - - btnLabelWasNext = HasNextPage(m_page); - - bmpPrev = m_page->GetBitmap(); - - if ( !m_usingSizer ) - m_sizerBmpAndPage->Detach(m_page); - } - - // set the new page - m_page = page; - - // is this the end? - if ( !m_page ) - { - // terminate successfully - if ( IsModal() ) - { - EndModal(wxID_OK); - } - else - { - SetReturnCode(wxID_OK); - Hide(); - } - - // and notify the user code (this is especially useful for modeless - // wizards) - wxWizardEvent event(wxEVT_WIZARD_FINISHED, GetId(), false, 0); - (void)GetEventHandler()->ProcessEvent(event); - - return true; - } - - // position and show the new page - (void)m_page->TransferDataToWindow(); - - if ( m_usingSizer ) - { - // wxWizardSizer::RecalcSizes wants to be called when m_page changes - m_sizerPage->RecalcSizes(); - } - else // pages are not managed by the sizer - { - m_sizerBmpAndPage->Add(m_page, flags); - m_sizerBmpAndPage->SetItemMinSize(m_page, GetPageSize()); - } - -#if wxUSE_STATBMP - // update the bitmap if:it changed - if ( m_statbmp ) - { - wxBitmap bmp = m_page->GetBitmap(); - if ( !bmp.Ok() ) - bmp = m_bitmap; - - if ( !bmpPrev.Ok() ) - bmpPrev = m_bitmap; - - if ( !bmp.IsSameAs(bmpPrev) ) - m_statbmp->SetBitmap(bmp); - } -#endif // wxUSE_STATBMP - - - // and update the buttons state - m_btnPrev->Enable(HasPrevPage(m_page)); - - bool hasNext = HasNextPage(m_page); - if ( btnLabelWasNext != hasNext ) - { - m_btnNext->SetLabel(hasNext ? _("&Next >") : _("&Finish")); - } - // nothing to do: the label was already correct - - m_btnNext->SetDefault(); - - - // send the change event to the new page now - wxWizardEvent event(wxEVT_WIZARD_PAGE_CHANGED, GetId(), goingForward, m_page); - (void)m_page->GetEventHandler()->ProcessEvent(event); - - // and finally show it - m_page->Show(); - m_page->SetFocus(); - - if ( !m_usingSizer ) - m_sizerBmpAndPage->Layout(); - - if ( !m_started ) - { - m_started = true; - - if ( wxSystemSettings::GetScreenType() > wxSYS_SCREEN_PDA ) - { - GetSizer()->SetSizeHints(this); - if ( m_posWizard == wxDefaultPosition ) - CentreOnScreen(); - } - } - - return true; -} - -bool wxWizard::RunWizard(wxWizardPage *firstPage) -{ - wxCHECK_MSG( firstPage, false, wxT("can't run empty wizard") ); - - // can't return false here because there is no old page - (void)ShowPage(firstPage, true /* forward */); - - m_wasModal = true; - - return ShowModal() == wxID_OK; -} - -wxWizardPage *wxWizard::GetCurrentPage() const -{ - return m_page; -} - -wxSize wxWizard::GetPageSize() const -{ - // default width and height of the page - int DEFAULT_PAGE_WIDTH, - DEFAULT_PAGE_HEIGHT; - if ( wxSystemSettings::GetScreenType() <= wxSYS_SCREEN_PDA ) - { - // Make the default page size small enough to fit on screen - DEFAULT_PAGE_WIDTH = wxSystemSettings::GetMetric(wxSYS_SCREEN_X) / 2; - DEFAULT_PAGE_HEIGHT = wxSystemSettings::GetMetric(wxSYS_SCREEN_Y) / 2; - } - else // !PDA - { - DEFAULT_PAGE_WIDTH = - DEFAULT_PAGE_HEIGHT = 270; - } - - // start with default minimal size - wxSize pageSize(DEFAULT_PAGE_WIDTH, DEFAULT_PAGE_HEIGHT); - - // make the page at least as big as specified by user - pageSize.IncTo(m_sizePage); - - if ( m_statbmp ) - { - // make the page at least as tall as the bitmap - pageSize.IncTo(wxSize(0, m_bitmap.GetHeight())); - } - - if ( m_usingSizer ) - { - // make it big enough to contain all pages added to the sizer - pageSize.IncTo(m_sizerPage->GetMaxChildSize()); - } - - return pageSize; -} - -wxSizer *wxWizard::GetPageAreaSizer() const -{ - return m_sizerPage; -} - -void wxWizard::SetBorder(int border) -{ - wxCHECK_RET(!m_started, wxT("wxWizard::SetBorder after RunWizard")); - - m_border = border; -} - -void wxWizard::OnCancel(wxCommandEvent& WXUNUSED(eventUnused)) -{ - // this function probably can never be called when we don't have an active - // page, but a small extra check won't hurt - wxWindow *win = m_page ? (wxWindow *)m_page : (wxWindow *)this; - - wxWizardEvent event(wxEVT_WIZARD_CANCEL, GetId(), false, m_page); - if ( !win->GetEventHandler()->ProcessEvent(event) || event.IsAllowed() ) - { - // no objections - close the dialog - if(IsModal()) - { - EndModal(wxID_CANCEL); - } - else - { - SetReturnCode(wxID_CANCEL); - Hide(); - } - } - //else: request to Cancel ignored -} - -void wxWizard::OnBackOrNext(wxCommandEvent& event) -{ - wxASSERT_MSG( (event.GetEventObject() == m_btnNext) || - (event.GetEventObject() == m_btnPrev), - wxT("unknown button") ); - - wxCHECK_RET( m_page, _T("should have a valid current page") ); - - // ask the current page first: notice that we do it before calling - // GetNext/Prev() because the data transfered from the controls of the page - // may change the value returned by these methods - if ( !m_page->Validate() || !m_page->TransferDataFromWindow() ) - { - // the page data is incorrect, don't do anything - return; - } - - bool forward = event.GetEventObject() == m_btnNext; - - wxWizardPage *page; - if ( forward ) - { - page = m_page->GetNext(); - } - else // back - { - page = m_page->GetPrev(); - - wxASSERT_MSG( page, wxT("\"GetEventHandler()->ProcessEvent(eventHelp); - } -} - -void wxWizard::OnWizEvent(wxWizardEvent& event) -{ - // the dialogs have wxWS_EX_BLOCK_EVENTS style on by default but we want to - // propagate wxEVT_WIZARD_XXX to the parent (if any), so do it manually - if ( !(GetExtraStyle() & wxWS_EX_BLOCK_EVENTS) ) - { - // the event will be propagated anyhow - event.Skip(); - } - else - { - wxWindow *parent = GetParent(); - - if ( !parent || !parent->GetEventHandler()->ProcessEvent(event) ) - { - event.Skip(); - } - } - - if ( ( !m_wasModal ) && - event.IsAllowed() && - ( event.GetEventType() == wxEVT_WIZARD_FINISHED || - event.GetEventType() == wxEVT_WIZARD_CANCEL - ) - ) - { - Destroy(); - } -} - -void wxWizard::SetBitmap(const wxBitmap& bitmap) -{ - m_bitmap = bitmap; - if (m_statbmp) - m_statbmp->SetBitmap(m_bitmap); -} - -// ---------------------------------------------------------------------------- -// wxWizardEvent -// ---------------------------------------------------------------------------- - -wxWizardEvent::wxWizardEvent(wxEventType type, int id, bool direction, wxWizardPage* page) - : wxNotifyEvent(type, id) -{ - // Modified 10-20-2001 Robert Cavanaugh - // add the active page to the event data - m_direction = direction; - m_page = page; -} - -#endif // wxUSE_WIZARDDLG +/////////////////////////////////////////////////////////////////////////////// +// Name: src/generic/wizard.cpp +// Purpose: generic implementation of wxWizard class +// Author: Vadim Zeitlin +// Modified by: Robert Cavanaugh +// 1) Added capability for wxWizardPage to accept resources +// 2) Added "Help" button handler stub +// 3) Fixed ShowPage() bug on displaying bitmaps +// Robert Vazan (sizers) +// Created: 15.08.99 +// RCS-ID: $Id: wizard.cpp 47065 2007-07-02 08:00:17Z JS $ +// Copyright: (c) 1999 Vadim Zeitlin +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_WIZARDDLG + +#ifndef WX_PRECOMP + #include "wx/dynarray.h" + #include "wx/intl.h" + #include "wx/statbmp.h" + #include "wx/button.h" + #include "wx/settings.h" + #include "wx/sizer.h" +#endif //WX_PRECOMP + +#include "wx/statline.h" + +#include "wx/wizard.h" + +// ---------------------------------------------------------------------------- +// wxWizardSizer +// ---------------------------------------------------------------------------- + +class wxWizardSizer : public wxSizer +{ +public: + wxWizardSizer(wxWizard *owner); + + virtual wxSizerItem *Insert(size_t index, wxSizerItem *item); + + virtual void RecalcSizes(); + virtual wxSize CalcMin(); + + // get the max size of all wizard pages + wxSize GetMaxChildSize(); + + // return the border which can be either set using wxWizard::SetBorder() or + // have default value + int GetBorder() const; + + // hide the pages which we temporarily "show" when they're added to this + // sizer (see Insert()) + void HidePages(); + +private: + wxSize SiblingSize(wxSizerItem *child); + + wxWizard *m_owner; + wxSize m_childSize; +}; + +// ---------------------------------------------------------------------------- +// event tables and such +// ---------------------------------------------------------------------------- + +DEFINE_EVENT_TYPE(wxEVT_WIZARD_PAGE_CHANGED) +DEFINE_EVENT_TYPE(wxEVT_WIZARD_PAGE_CHANGING) +DEFINE_EVENT_TYPE(wxEVT_WIZARD_CANCEL) +DEFINE_EVENT_TYPE(wxEVT_WIZARD_FINISHED) +DEFINE_EVENT_TYPE(wxEVT_WIZARD_HELP) + +BEGIN_EVENT_TABLE(wxWizard, wxDialog) + EVT_BUTTON(wxID_CANCEL, wxWizard::OnCancel) + EVT_BUTTON(wxID_BACKWARD, wxWizard::OnBackOrNext) + EVT_BUTTON(wxID_FORWARD, wxWizard::OnBackOrNext) + EVT_BUTTON(wxID_HELP, wxWizard::OnHelp) + + EVT_WIZARD_PAGE_CHANGED(wxID_ANY, wxWizard::OnWizEvent) + EVT_WIZARD_PAGE_CHANGING(wxID_ANY, wxWizard::OnWizEvent) + EVT_WIZARD_CANCEL(wxID_ANY, wxWizard::OnWizEvent) + EVT_WIZARD_FINISHED(wxID_ANY, wxWizard::OnWizEvent) + EVT_WIZARD_HELP(wxID_ANY, wxWizard::OnWizEvent) +END_EVENT_TABLE() + +IMPLEMENT_DYNAMIC_CLASS(wxWizard, wxDialog) + +/* + TODO PROPERTIES : + wxWizard + extstyle + title +*/ + +IMPLEMENT_ABSTRACT_CLASS(wxWizardPage, wxPanel) +IMPLEMENT_DYNAMIC_CLASS(wxWizardPageSimple, wxWizardPage) +IMPLEMENT_DYNAMIC_CLASS(wxWizardEvent, wxNotifyEvent) + +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// wxWizardPage +// ---------------------------------------------------------------------------- + +void wxWizardPage::Init() +{ + m_bitmap = wxNullBitmap; +} + +wxWizardPage::wxWizardPage(wxWizard *parent, + const wxBitmap& bitmap, + const wxChar *resource) +{ + Create(parent, bitmap, resource); +} + +bool wxWizardPage::Create(wxWizard *parent, + const wxBitmap& bitmap, + const wxChar *resource) +{ + if ( !wxPanel::Create(parent, wxID_ANY) ) + return false; + + if ( resource != NULL ) + { +#if wxUSE_WX_RESOURCES +#if 0 + if ( !LoadFromResource(this, resource) ) + { + wxFAIL_MSG(wxT("wxWizardPage LoadFromResource failed!!!!")); + } +#endif +#endif // wxUSE_RESOURCES + } + + m_bitmap = bitmap; + + // initially the page is hidden, it's shown only when it becomes current + Hide(); + + return true; +} + +// ---------------------------------------------------------------------------- +// wxWizardPageSimple +// ---------------------------------------------------------------------------- + +wxWizardPage *wxWizardPageSimple::GetPrev() const +{ + return m_prev; +} + +wxWizardPage *wxWizardPageSimple::GetNext() const +{ + return m_next; +} + +// ---------------------------------------------------------------------------- +// wxWizardSizer +// ---------------------------------------------------------------------------- + +wxWizardSizer::wxWizardSizer(wxWizard *owner) + : m_owner(owner), + m_childSize(wxDefaultSize) +{ +} + +wxSizerItem *wxWizardSizer::Insert(size_t index, wxSizerItem *item) +{ + m_owner->m_usingSizer = true; + + if ( item->IsWindow() ) + { + // we must pretend that the window is shown as otherwise it wouldn't be + // taken into account for the layout -- but avoid really showing it, so + // just set the internal flag instead of calling wxWindow::Show() + item->GetWindow()->wxWindowBase::Show(); + } + + return wxSizer::Insert(index, item); +} + +void wxWizardSizer::HidePages() +{ + for ( wxSizerItemList::compatibility_iterator node = GetChildren().GetFirst(); + node; + node = node->GetNext() ) + { + wxSizerItem * const item = node->GetData(); + if ( item->IsWindow() ) + item->GetWindow()->wxWindowBase::Show(false); + } +} + +void wxWizardSizer::RecalcSizes() +{ + // Effect of this function depends on m_owner->m_page and + // it should be called whenever it changes (wxWizard::ShowPage) + if ( m_owner->m_page ) + { + m_owner->m_page->SetSize(wxRect(m_position, m_size)); + } +} + +wxSize wxWizardSizer::CalcMin() +{ + return m_owner->GetPageSize(); +} + +wxSize wxWizardSizer::GetMaxChildSize() +{ +#if !defined(__WXDEBUG__) + if ( m_childSize.IsFullySpecified() ) + return m_childSize; +#endif + + wxSize maxOfMin; + + for ( wxSizerItemList::compatibility_iterator childNode = m_children.GetFirst(); + childNode; + childNode = childNode->GetNext() ) + { + wxSizerItem *child = childNode->GetData(); + maxOfMin.IncTo(child->CalcMin()); + maxOfMin.IncTo(SiblingSize(child)); + } + +#ifdef __WXDEBUG__ + if ( m_childSize.IsFullySpecified() && m_childSize != maxOfMin ) + { + wxFAIL_MSG( _T("Size changed in wxWizard::GetPageAreaSizer()") + _T("after RunWizard().\n") + _T("Did you forget to call GetSizer()->Fit(this) ") + _T("for some page?")) ; + + return m_childSize; + } +#endif // __WXDEBUG__ + + if ( m_owner->m_started ) + { + m_childSize = maxOfMin; + } + + return maxOfMin; +} + +int wxWizardSizer::GetBorder() const +{ + return m_owner->m_border; +} + +wxSize wxWizardSizer::SiblingSize(wxSizerItem *child) +{ + wxSize maxSibling; + + if ( child->IsWindow() ) + { + wxWizardPage *page = wxDynamicCast(child->GetWindow(), wxWizardPage); + if ( page ) + { + for ( wxWizardPage *sibling = page->GetNext(); + sibling; + sibling = sibling->GetNext() ) + { + if ( sibling->GetSizer() ) + { + maxSibling.IncTo(sibling->GetSizer()->CalcMin()); + } + } + } + } + + return maxSibling; +} + +// ---------------------------------------------------------------------------- +// generic wxWizard implementation +// ---------------------------------------------------------------------------- + +void wxWizard::Init() +{ + m_posWizard = wxDefaultPosition; + m_page = (wxWizardPage *)NULL; + m_btnPrev = m_btnNext = NULL; + m_statbmp = NULL; + m_sizerBmpAndPage = NULL; + m_sizerPage = NULL; + m_border = 5; + m_started = false; + m_wasModal = false; + m_usingSizer = false; +} + +bool wxWizard::Create(wxWindow *parent, + int id, + const wxString& title, + const wxBitmap& bitmap, + const wxPoint& pos, + long style) +{ + bool result = wxDialog::Create(parent,id,title,pos,wxDefaultSize,style); + + m_posWizard = pos; + m_bitmap = bitmap ; + + DoCreateControls(); + + return result; +} + +wxWizard::~wxWizard() +{ + // normally we don't have to delete this sizer as it's deleted by the + // associated window but if we never used it or didn't set it as the window + // sizer yet, do delete it manually + if ( !m_usingSizer || !m_started ) + delete m_sizerPage; +} + +void wxWizard::AddBitmapRow(wxBoxSizer *mainColumn) +{ + m_sizerBmpAndPage = new wxBoxSizer(wxHORIZONTAL); + mainColumn->Add( + m_sizerBmpAndPage, + 1, // Vertically stretchable + wxEXPAND // Horizonal stretching, no border + ); + mainColumn->Add(0,5, + 0, // No vertical stretching + wxEXPAND // No border, (mostly useless) horizontal stretching + ); + +#if wxUSE_STATBMP + if ( m_bitmap.Ok() ) + { + m_statbmp = new wxStaticBitmap(this, wxID_ANY, m_bitmap); + m_sizerBmpAndPage->Add( + m_statbmp, + 0, // No horizontal stretching + wxALL, // Border all around, top alignment + 5 // Border width + ); + m_sizerBmpAndPage->Add( + 5,0, + 0, // No horizontal stretching + wxEXPAND // No border, (mostly useless) vertical stretching + ); + } +#endif + + // Added to m_sizerBmpAndPage later + m_sizerPage = new wxWizardSizer(this); +} + +void wxWizard::AddStaticLine(wxBoxSizer *mainColumn) +{ +#if wxUSE_STATLINE + mainColumn->Add( + new wxStaticLine(this, wxID_ANY), + 0, // Vertically unstretchable + wxEXPAND | wxALL, // Border all around, horizontally stretchable + 5 // Border width + ); + mainColumn->Add(0,5, + 0, // No vertical stretching + wxEXPAND // No border, (mostly useless) horizontal stretching + ); +#else + (void)mainColumn; +#endif // wxUSE_STATLINE +} + +void wxWizard::AddBackNextPair(wxBoxSizer *buttonRow) +{ + wxASSERT_MSG( m_btnNext && m_btnPrev, + _T("You must create the buttons before calling ") + _T("wxWizard::AddBackNextPair") ); + + // margin between Back and Next buttons +#ifdef __WXMAC__ + static const int BACKNEXT_MARGIN = 10; +#else + static const int BACKNEXT_MARGIN = 0; +#endif + + wxBoxSizer *backNextPair = new wxBoxSizer(wxHORIZONTAL); + buttonRow->Add( + backNextPair, + 0, // No horizontal stretching + wxALL, // Border all around + 5 // Border width + ); + + backNextPair->Add(m_btnPrev); + backNextPair->Add(BACKNEXT_MARGIN,0, + 0, // No horizontal stretching + wxEXPAND // No border, (mostly useless) vertical stretching + ); + backNextPair->Add(m_btnNext); +} + +void wxWizard::AddButtonRow(wxBoxSizer *mainColumn) +{ + // the order in which the buttons are created determines the TAB order - at least under MSWindows... + // although the 'back' button appears before the 'next' button, a more userfriendly tab order is + // to activate the 'next' button first (create the next button before the back button). + // The reason is: The user will repeatedly enter information in the wizard pages and then wants to + // press 'next'. If a user uses mostly the keyboard, he would have to skip the 'back' button + // everytime. This is annoying. There is a second reason: RETURN acts as TAB. If the 'next' + // button comes first in the TAB order, the user can enter information very fast using the RETURN + // key to TAB to the next entry field and page. This would not be possible, if the 'back' button + // was created before the 'next' button. + + bool isPda = (wxSystemSettings::GetScreenType() <= wxSYS_SCREEN_PDA); + int buttonStyle = isPda ? wxBU_EXACTFIT : 0; + + wxBoxSizer *buttonRow = new wxBoxSizer(wxHORIZONTAL); +#ifdef __WXMAC__ + if (GetExtraStyle() & wxWIZARD_EX_HELPBUTTON) + mainColumn->Add( + buttonRow, + 0, // Vertically unstretchable + wxGROW|wxALIGN_CENTRE + ); + else +#endif + mainColumn->Add( + buttonRow, + 0, // Vertically unstretchable + wxALIGN_RIGHT // Right aligned, no border + ); + + // Desired TAB order is 'next', 'cancel', 'help', 'back'. This makes the 'back' button the last control on the page. + // Create the buttons in the right order... + wxButton *btnHelp=0; +#ifdef __WXMAC__ + if (GetExtraStyle() & wxWIZARD_EX_HELPBUTTON) + btnHelp=new wxButton(this, wxID_HELP, _("&Help"), wxDefaultPosition, wxDefaultSize, buttonStyle); +#endif + + m_btnNext = new wxButton(this, wxID_FORWARD, _("&Next >")); + wxButton *btnCancel=new wxButton(this, wxID_CANCEL, _("&Cancel"), wxDefaultPosition, wxDefaultSize, buttonStyle); +#ifndef __WXMAC__ + if (GetExtraStyle() & wxWIZARD_EX_HELPBUTTON) + btnHelp=new wxButton(this, wxID_HELP, _("&Help"), wxDefaultPosition, wxDefaultSize, buttonStyle); +#endif + m_btnPrev = new wxButton(this, wxID_BACKWARD, _("< &Back"), wxDefaultPosition, wxDefaultSize, buttonStyle); + + if (btnHelp) + { + buttonRow->Add( + btnHelp, + 0, // Horizontally unstretchable + wxALL, // Border all around, top aligned + 5 // Border width + ); +#ifdef __WXMAC__ + // Put stretchable space between help button and others + buttonRow->Add(0, 0, 1, wxALIGN_CENTRE, 0); +#endif + } + + AddBackNextPair(buttonRow); + + buttonRow->Add( + btnCancel, + 0, // Horizontally unstretchable + wxALL, // Border all around, top aligned + 5 // Border width + ); +} + +void wxWizard::DoCreateControls() +{ + // do nothing if the controls were already created + if ( WasCreated() ) + return; + + bool isPda = (wxSystemSettings::GetScreenType() <= wxSYS_SCREEN_PDA); + + // Horizontal stretching, and if not PDA, border all around + int mainColumnSizerFlags = isPda ? wxEXPAND : wxALL|wxEXPAND ; + + // wxWindow::SetSizer will be called at end + wxBoxSizer *windowSizer = new wxBoxSizer(wxVERTICAL); + + wxBoxSizer *mainColumn = new wxBoxSizer(wxVERTICAL); + windowSizer->Add( + mainColumn, + 1, // Vertical stretching + mainColumnSizerFlags, + 5 // Border width + ); + + AddBitmapRow(mainColumn); + + if (!isPda) + AddStaticLine(mainColumn); + + AddButtonRow(mainColumn); + + SetSizer(windowSizer); +} + +void wxWizard::SetPageSize(const wxSize& size) +{ + wxCHECK_RET(!m_started, wxT("wxWizard::SetPageSize after RunWizard")); + m_sizePage = size; +} + +void wxWizard::FitToPage(const wxWizardPage *page) +{ + wxCHECK_RET(!m_started, wxT("wxWizard::FitToPage after RunWizard")); + + while ( page ) + { + wxSize size = page->GetBestSize(); + + m_sizePage.IncTo(size); + + page = page->GetNext(); + } +} + +bool wxWizard::ShowPage(wxWizardPage *page, bool goingForward) +{ + wxASSERT_MSG( page != m_page, wxT("this is useless") ); + + wxSizerFlags flags(1); + flags.Border(wxALL, m_border).Expand(); + + if ( !m_started ) + { + if ( m_usingSizer ) + { + m_sizerBmpAndPage->Add(m_sizerPage, flags); + + // now that our layout is computed correctly, hide the pages + // artificially shown in wxWizardSizer::Insert() back again + m_sizerPage->HidePages(); + } + } + + + // we'll use this to decide whether we have to change the label of this + // button or not (initially the label is "Next") + bool btnLabelWasNext = true; + + // remember the old bitmap (if any) to compare with the new one later + wxBitmap bmpPrev; + + // check for previous page + if ( m_page ) + { + // send the event to the old page + wxWizardEvent event(wxEVT_WIZARD_PAGE_CHANGING, GetId(), + goingForward, m_page); + if ( m_page->GetEventHandler()->ProcessEvent(event) && + !event.IsAllowed() ) + { + // vetoed by the page + return false; + } + + m_page->Hide(); + + btnLabelWasNext = HasNextPage(m_page); + + bmpPrev = m_page->GetBitmap(); + + if ( !m_usingSizer ) + m_sizerBmpAndPage->Detach(m_page); + } + + // set the new page + m_page = page; + + // is this the end? + if ( !m_page ) + { + // terminate successfully + if ( IsModal() ) + { + EndModal(wxID_OK); + } + else + { + SetReturnCode(wxID_OK); + Hide(); + } + + // and notify the user code (this is especially useful for modeless + // wizards) + wxWizardEvent event(wxEVT_WIZARD_FINISHED, GetId(), false, 0); + (void)GetEventHandler()->ProcessEvent(event); + + return true; + } + + // position and show the new page + (void)m_page->TransferDataToWindow(); + + if ( m_usingSizer ) + { + // wxWizardSizer::RecalcSizes wants to be called when m_page changes + m_sizerPage->RecalcSizes(); + } + else // pages are not managed by the sizer + { + m_sizerBmpAndPage->Add(m_page, flags); + m_sizerBmpAndPage->SetItemMinSize(m_page, GetPageSize()); + } + +#if wxUSE_STATBMP + // update the bitmap if:it changed + if ( m_statbmp ) + { + wxBitmap bmp = m_page->GetBitmap(); + if ( !bmp.Ok() ) + bmp = m_bitmap; + + if ( !bmpPrev.Ok() ) + bmpPrev = m_bitmap; + + if ( !bmp.IsSameAs(bmpPrev) ) + m_statbmp->SetBitmap(bmp); + } +#endif // wxUSE_STATBMP + + + // and update the buttons state + m_btnPrev->Enable(HasPrevPage(m_page)); + + bool hasNext = HasNextPage(m_page); + if ( btnLabelWasNext != hasNext ) + { + m_btnNext->SetLabel(hasNext ? _("&Next >") : _("&Finish")); + } + // nothing to do: the label was already correct + + m_btnNext->SetDefault(); + + + // send the change event to the new page now + wxWizardEvent event(wxEVT_WIZARD_PAGE_CHANGED, GetId(), goingForward, m_page); + (void)m_page->GetEventHandler()->ProcessEvent(event); + + // and finally show it + m_page->Show(); + m_page->SetFocus(); + + if ( !m_usingSizer ) + m_sizerBmpAndPage->Layout(); + + if ( !m_started ) + { + m_started = true; + + if ( wxSystemSettings::GetScreenType() > wxSYS_SCREEN_PDA ) + { + GetSizer()->SetSizeHints(this); + if ( m_posWizard == wxDefaultPosition ) + CentreOnScreen(); + } + } + + return true; +} + +bool wxWizard::RunWizard(wxWizardPage *firstPage) +{ + wxCHECK_MSG( firstPage, false, wxT("can't run empty wizard") ); + + // can't return false here because there is no old page + (void)ShowPage(firstPage, true /* forward */); + + m_wasModal = true; + + return ShowModal() == wxID_OK; +} + +wxWizardPage *wxWizard::GetCurrentPage() const +{ + return m_page; +} + +wxSize wxWizard::GetPageSize() const +{ + // default width and height of the page + int DEFAULT_PAGE_WIDTH, + DEFAULT_PAGE_HEIGHT; + if ( wxSystemSettings::GetScreenType() <= wxSYS_SCREEN_PDA ) + { + // Make the default page size small enough to fit on screen + DEFAULT_PAGE_WIDTH = wxSystemSettings::GetMetric(wxSYS_SCREEN_X) / 2; + DEFAULT_PAGE_HEIGHT = wxSystemSettings::GetMetric(wxSYS_SCREEN_Y) / 2; + } + else // !PDA + { + DEFAULT_PAGE_WIDTH = + DEFAULT_PAGE_HEIGHT = 270; + } + + // start with default minimal size + wxSize pageSize(DEFAULT_PAGE_WIDTH, DEFAULT_PAGE_HEIGHT); + + // make the page at least as big as specified by user + pageSize.IncTo(m_sizePage); + + if ( m_statbmp ) + { + // make the page at least as tall as the bitmap + pageSize.IncTo(wxSize(0, m_bitmap.GetHeight())); + } + + if ( m_usingSizer ) + { + // make it big enough to contain all pages added to the sizer + pageSize.IncTo(m_sizerPage->GetMaxChildSize()); + } + + return pageSize; +} + +wxSizer *wxWizard::GetPageAreaSizer() const +{ + return m_sizerPage; +} + +void wxWizard::SetBorder(int border) +{ + wxCHECK_RET(!m_started, wxT("wxWizard::SetBorder after RunWizard")); + + m_border = border; +} + +void wxWizard::OnCancel(wxCommandEvent& WXUNUSED(eventUnused)) +{ + // this function probably can never be called when we don't have an active + // page, but a small extra check won't hurt + wxWindow *win = m_page ? (wxWindow *)m_page : (wxWindow *)this; + + wxWizardEvent event(wxEVT_WIZARD_CANCEL, GetId(), false, m_page); + if ( !win->GetEventHandler()->ProcessEvent(event) || event.IsAllowed() ) + { + // no objections - close the dialog + if(IsModal()) + { + EndModal(wxID_CANCEL); + } + else + { + SetReturnCode(wxID_CANCEL); + Hide(); + } + } + //else: request to Cancel ignored +} + +void wxWizard::OnBackOrNext(wxCommandEvent& event) +{ + wxASSERT_MSG( (event.GetEventObject() == m_btnNext) || + (event.GetEventObject() == m_btnPrev), + wxT("unknown button") ); + + wxCHECK_RET( m_page, _T("should have a valid current page") ); + + // ask the current page first: notice that we do it before calling + // GetNext/Prev() because the data transfered from the controls of the page + // may change the value returned by these methods + if ( !m_page->Validate() || !m_page->TransferDataFromWindow() ) + { + // the page data is incorrect, don't do anything + return; + } + + bool forward = event.GetEventObject() == m_btnNext; + + wxWizardPage *page; + if ( forward ) + { + page = m_page->GetNext(); + } + else // back + { + page = m_page->GetPrev(); + + wxASSERT_MSG( page, wxT("\"GetEventHandler()->ProcessEvent(eventHelp); + } +} + +void wxWizard::OnWizEvent(wxWizardEvent& event) +{ + // the dialogs have wxWS_EX_BLOCK_EVENTS style on by default but we want to + // propagate wxEVT_WIZARD_XXX to the parent (if any), so do it manually + if ( !(GetExtraStyle() & wxWS_EX_BLOCK_EVENTS) ) + { + // the event will be propagated anyhow + event.Skip(); + } + else + { + wxWindow *parent = GetParent(); + + if ( !parent || !parent->GetEventHandler()->ProcessEvent(event) ) + { + event.Skip(); + } + } + + if ( ( !m_wasModal ) && + event.IsAllowed() && + ( event.GetEventType() == wxEVT_WIZARD_FINISHED || + event.GetEventType() == wxEVT_WIZARD_CANCEL + ) + ) + { + Destroy(); + } +} + +void wxWizard::SetBitmap(const wxBitmap& bitmap) +{ + m_bitmap = bitmap; + if (m_statbmp) + m_statbmp->SetBitmap(m_bitmap); +} + +// ---------------------------------------------------------------------------- +// wxWizardEvent +// ---------------------------------------------------------------------------- + +wxWizardEvent::wxWizardEvent(wxEventType type, int id, bool direction, wxWizardPage* page) + : wxNotifyEvent(type, id) +{ + // Modified 10-20-2001 Robert Cavanaugh + // add the active page to the event data + m_direction = direction; + m_page = page; +} + +#endif // wxUSE_WIZARDDLG diff --git a/Externals/wxWidgets/src/msw/aboutdlg.cpp b/Externals/wxWidgets/src/msw/aboutdlg.cpp index 0a87b310b4..6e056ca788 100644 --- a/Externals/wxWidgets/src/msw/aboutdlg.cpp +++ b/Externals/wxWidgets/src/msw/aboutdlg.cpp @@ -1,70 +1,70 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: src/msw/aboutdlg.cpp -// Purpose: implementation of wxAboutBox() for wxMSW -// Author: Vadim Zeitlin -// Created: 2006-10-07 -// RCS-ID: $Id: aboutdlg.cpp 45979 2007-05-11 22:39:15Z VZ $ -// Copyright: (c) 2006 Vadim Zeitlin -// Licence: wxWindows licence -/////////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// for compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_ABOUTDLG - -#ifndef WX_PRECOMP - #include "wx/msgdlg.h" -#endif //WX_PRECOMP - -#include "wx/aboutdlg.h" -#include "wx/generic/aboutdlgg.h" - -// ============================================================================ -// implementation -// ============================================================================ - -// our public entry point -void wxAboutBox(const wxAboutDialogInfo& info) -{ - // we prefer to show a simple message box if we don't have any fields which - // can't be shown in it because as much as there is a standard about box - // under MSW at all, this is it - if ( info.IsSimple() ) - { - // build the text to show in the box - const wxString name = info.GetName(); - wxString msg; - msg << name; - if ( info.HasVersion() ) - msg << _(" Version ") << info.GetVersion(); - msg << _T('\n'); - - if ( info.HasCopyright() ) - msg << info.GetCopyright() << _T('\n'); - - // add everything remaining - msg << info.GetDescriptionAndCredits(); - - wxMessageBox(msg, _("About ") + name); - } - else // simple "native" version is not enough - { - // we need to use the full-blown generic version - wxGenericAboutBox(info); - } -} - -#endif // wxUSE_ABOUTDLG +/////////////////////////////////////////////////////////////////////////////// +// Name: src/msw/aboutdlg.cpp +// Purpose: implementation of wxAboutBox() for wxMSW +// Author: Vadim Zeitlin +// Created: 2006-10-07 +// RCS-ID: $Id: aboutdlg.cpp 45979 2007-05-11 22:39:15Z VZ $ +// Copyright: (c) 2006 Vadim Zeitlin +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// for compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_ABOUTDLG + +#ifndef WX_PRECOMP + #include "wx/msgdlg.h" +#endif //WX_PRECOMP + +#include "wx/aboutdlg.h" +#include "wx/generic/aboutdlgg.h" + +// ============================================================================ +// implementation +// ============================================================================ + +// our public entry point +void wxAboutBox(const wxAboutDialogInfo& info) +{ + // we prefer to show a simple message box if we don't have any fields which + // can't be shown in it because as much as there is a standard about box + // under MSW at all, this is it + if ( info.IsSimple() ) + { + // build the text to show in the box + const wxString name = info.GetName(); + wxString msg; + msg << name; + if ( info.HasVersion() ) + msg << _(" Version ") << info.GetVersion(); + msg << _T('\n'); + + if ( info.HasCopyright() ) + msg << info.GetCopyright() << _T('\n'); + + // add everything remaining + msg << info.GetDescriptionAndCredits(); + + wxMessageBox(msg, _("About ") + name); + } + else // simple "native" version is not enough + { + // we need to use the full-blown generic version + wxGenericAboutBox(info); + } +} + +#endif // wxUSE_ABOUTDLG diff --git a/Externals/wxWidgets/src/msw/accel.cpp b/Externals/wxWidgets/src/msw/accel.cpp index f10f83fa31..c9d05f7dbf 100644 --- a/Externals/wxWidgets/src/msw/accel.cpp +++ b/Externals/wxWidgets/src/msw/accel.cpp @@ -1,167 +1,167 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: msw/accel.cpp -// Purpose: wxAcceleratorTable -// Author: Julian Smart -// Modified by: -// Created: 04/01/98 -// RCS-ID: $Id: accel.cpp 49804 2007-11-10 01:09:42Z VZ $ -// Copyright: (c) Julian Smart -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_ACCEL - -#ifndef WX_PRECOMP - #include "wx/window.h" -#endif - -#include "wx/accel.h" - -#include "wx/msw/private.h" - -extern WXWORD wxCharCodeWXToMSW(int id, bool *isVirtual); - -IMPLEMENT_DYNAMIC_CLASS(wxAcceleratorTable, wxObject) - -// ---------------------------------------------------------------------------- -// data defining wxAcceleratorTable -// ---------------------------------------------------------------------------- - -class WXDLLEXPORT wxAcceleratorRefData: public wxObjectRefData -{ - friend class WXDLLIMPEXP_FWD_CORE wxAcceleratorTable; -public: - wxAcceleratorRefData(); - virtual ~wxAcceleratorRefData(); - - inline HACCEL GetHACCEL() const { return m_hAccel; } -protected: - HACCEL m_hAccel; - bool m_ok; - - DECLARE_NO_COPY_CLASS(wxAcceleratorRefData) -}; - -// ============================================================================ -// implementation -// ============================================================================ - -// ---------------------------------------------------------------------------- -// wxAcceleratorRefData -// ---------------------------------------------------------------------------- - -#define M_ACCELDATA ((wxAcceleratorRefData *)m_refData) - -wxAcceleratorRefData::wxAcceleratorRefData() -{ - m_ok = false; - m_hAccel = 0; -} - -wxAcceleratorRefData::~wxAcceleratorRefData() -{ - if (m_hAccel) - { - DestroyAcceleratorTable((HACCEL) m_hAccel); - } -} - -// ---------------------------------------------------------------------------- -// wxAcceleratorTable -// ---------------------------------------------------------------------------- - -// Load from .rc resource -wxAcceleratorTable::wxAcceleratorTable(const wxString& resource) -{ - m_refData = new wxAcceleratorRefData; - - HACCEL hAccel = ::LoadAccelerators(wxGetInstance(), resource); - M_ACCELDATA->m_hAccel = hAccel; - M_ACCELDATA->m_ok = hAccel != 0; -} - -// Create from an array -wxAcceleratorTable::wxAcceleratorTable(int n, const wxAcceleratorEntry entries[]) -{ - m_refData = new wxAcceleratorRefData; - - ACCEL* arr = new ACCEL[n]; - for ( int i = 0; i < n; i++ ) - { - int flags = entries[i].GetFlags(); - - BYTE fVirt = 0; - if ( flags & wxACCEL_ALT ) - fVirt |= FALT | FVIRTKEY; - if ( flags & wxACCEL_SHIFT ) - fVirt |= FSHIFT | FVIRTKEY; - if ( flags & wxACCEL_CTRL ) - fVirt |= FCONTROL | FVIRTKEY; - - bool isVirtual; - - WORD key = wxCharCodeWXToMSW(entries[i].GetKeyCode(), &isVirtual); - if (isVirtual) - fVirt |= FVIRTKEY; - - arr[i].fVirt = fVirt; - arr[i].key = key; - arr[i].cmd = (WORD)entries[i].GetCommand(); - } - - M_ACCELDATA->m_hAccel = ::CreateAcceleratorTable(arr, n); - delete[] arr; - - M_ACCELDATA->m_ok = (M_ACCELDATA->m_hAccel != 0); -} - -bool wxAcceleratorTable::IsOk() const -{ - return (M_ACCELDATA && (M_ACCELDATA->m_ok)); -} - -void wxAcceleratorTable::SetHACCEL(WXHACCEL hAccel) -{ - if (!M_ACCELDATA) - m_refData = new wxAcceleratorRefData; - - M_ACCELDATA->m_hAccel = (HACCEL) hAccel; -} - -WXHACCEL wxAcceleratorTable::GetHACCEL() const -{ - if (!M_ACCELDATA) - return 0; - return (WXHACCEL) M_ACCELDATA->m_hAccel; -} - -bool wxAcceleratorTable::Translate(wxWindow *window, WXMSG *wxmsg) const -{ -#if 0 - // calling TranslateAccelerator() with child window doesn't do anything so - // it's probably a bug - wxASSERT_MSG( window->IsTopLevel(), - _T("TranslateAccelerator() needs a top level window") ); -#endif - - MSG *msg = (MSG *)wxmsg; - return Ok() && ::TranslateAccelerator(GetHwndOf(window), GetHaccel(), msg); -} - -#endif // wxUSE_ACCEL - +///////////////////////////////////////////////////////////////////////////// +// Name: msw/accel.cpp +// Purpose: wxAcceleratorTable +// Author: Julian Smart +// Modified by: +// Created: 04/01/98 +// RCS-ID: $Id: accel.cpp 49804 2007-11-10 01:09:42Z VZ $ +// Copyright: (c) Julian Smart +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_ACCEL + +#ifndef WX_PRECOMP + #include "wx/window.h" +#endif + +#include "wx/accel.h" + +#include "wx/msw/private.h" + +extern WXWORD wxCharCodeWXToMSW(int id, bool *isVirtual); + +IMPLEMENT_DYNAMIC_CLASS(wxAcceleratorTable, wxObject) + +// ---------------------------------------------------------------------------- +// data defining wxAcceleratorTable +// ---------------------------------------------------------------------------- + +class WXDLLEXPORT wxAcceleratorRefData: public wxObjectRefData +{ + friend class WXDLLIMPEXP_FWD_CORE wxAcceleratorTable; +public: + wxAcceleratorRefData(); + virtual ~wxAcceleratorRefData(); + + inline HACCEL GetHACCEL() const { return m_hAccel; } +protected: + HACCEL m_hAccel; + bool m_ok; + + DECLARE_NO_COPY_CLASS(wxAcceleratorRefData) +}; + +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// wxAcceleratorRefData +// ---------------------------------------------------------------------------- + +#define M_ACCELDATA ((wxAcceleratorRefData *)m_refData) + +wxAcceleratorRefData::wxAcceleratorRefData() +{ + m_ok = false; + m_hAccel = 0; +} + +wxAcceleratorRefData::~wxAcceleratorRefData() +{ + if (m_hAccel) + { + DestroyAcceleratorTable((HACCEL) m_hAccel); + } +} + +// ---------------------------------------------------------------------------- +// wxAcceleratorTable +// ---------------------------------------------------------------------------- + +// Load from .rc resource +wxAcceleratorTable::wxAcceleratorTable(const wxString& resource) +{ + m_refData = new wxAcceleratorRefData; + + HACCEL hAccel = ::LoadAccelerators(wxGetInstance(), resource); + M_ACCELDATA->m_hAccel = hAccel; + M_ACCELDATA->m_ok = hAccel != 0; +} + +// Create from an array +wxAcceleratorTable::wxAcceleratorTable(int n, const wxAcceleratorEntry entries[]) +{ + m_refData = new wxAcceleratorRefData; + + ACCEL* arr = new ACCEL[n]; + for ( int i = 0; i < n; i++ ) + { + int flags = entries[i].GetFlags(); + + BYTE fVirt = 0; + if ( flags & wxACCEL_ALT ) + fVirt |= FALT | FVIRTKEY; + if ( flags & wxACCEL_SHIFT ) + fVirt |= FSHIFT | FVIRTKEY; + if ( flags & wxACCEL_CTRL ) + fVirt |= FCONTROL | FVIRTKEY; + + bool isVirtual; + + WORD key = wxCharCodeWXToMSW(entries[i].GetKeyCode(), &isVirtual); + if (isVirtual) + fVirt |= FVIRTKEY; + + arr[i].fVirt = fVirt; + arr[i].key = key; + arr[i].cmd = (WORD)entries[i].GetCommand(); + } + + M_ACCELDATA->m_hAccel = ::CreateAcceleratorTable(arr, n); + delete[] arr; + + M_ACCELDATA->m_ok = (M_ACCELDATA->m_hAccel != 0); +} + +bool wxAcceleratorTable::IsOk() const +{ + return (M_ACCELDATA && (M_ACCELDATA->m_ok)); +} + +void wxAcceleratorTable::SetHACCEL(WXHACCEL hAccel) +{ + if (!M_ACCELDATA) + m_refData = new wxAcceleratorRefData; + + M_ACCELDATA->m_hAccel = (HACCEL) hAccel; +} + +WXHACCEL wxAcceleratorTable::GetHACCEL() const +{ + if (!M_ACCELDATA) + return 0; + return (WXHACCEL) M_ACCELDATA->m_hAccel; +} + +bool wxAcceleratorTable::Translate(wxWindow *window, WXMSG *wxmsg) const +{ +#if 0 + // calling TranslateAccelerator() with child window doesn't do anything so + // it's probably a bug + wxASSERT_MSG( window->IsTopLevel(), + _T("TranslateAccelerator() needs a top level window") ); +#endif + + MSG *msg = (MSG *)wxmsg; + return Ok() && ::TranslateAccelerator(GetHwndOf(window), GetHaccel(), msg); +} + +#endif // wxUSE_ACCEL + diff --git a/Externals/wxWidgets/src/msw/app.cpp b/Externals/wxWidgets/src/msw/app.cpp index 4f93384ed8..ae6c3cb314 100644 --- a/Externals/wxWidgets/src/msw/app.cpp +++ b/Externals/wxWidgets/src/msw/app.cpp @@ -1,797 +1,797 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/msw/app.cpp -// Purpose: wxApp -// Author: Julian Smart -// Modified by: -// Created: 04/01/98 -// RCS-ID: $Id: app.cpp 53607 2008-05-16 15:21:40Z SN $ -// Copyright: (c) Julian Smart -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// =========================================================================== -// declarations -// =========================================================================== - -// --------------------------------------------------------------------------- -// headers -// --------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#if defined(__BORLANDC__) - #pragma hdrstop -#endif - -#ifndef WX_PRECOMP - #include "wx/msw/wrapcctl.h" - #include "wx/dynarray.h" - #include "wx/frame.h" - #include "wx/app.h" - #include "wx/utils.h" - #include "wx/gdicmn.h" - #include "wx/pen.h" - #include "wx/brush.h" - #include "wx/cursor.h" - #include "wx/icon.h" - #include "wx/palette.h" - #include "wx/dc.h" - #include "wx/dialog.h" - #include "wx/msgdlg.h" - #include "wx/intl.h" - #include "wx/wxchar.h" - #include "wx/log.h" - #include "wx/module.h" -#endif - -#include "wx/apptrait.h" -#include "wx/filename.h" -#include "wx/dynlib.h" -#include "wx/evtloop.h" - -#include "wx/msw/private.h" -#include "wx/msw/ole/oleutils.h" - -#if wxUSE_TOOLTIPS - #include "wx/tooltip.h" -#endif // wxUSE_TOOLTIPS - -// OLE is used for drag-and-drop, clipboard, OLE Automation..., but some -// compilers don't support it (missing headers, libs, ...) -#if defined(__GNUWIN32_OLD__) || defined(__SYMANTEC__) || defined(__SALFORDC__) - #undef wxUSE_OLE - - #define wxUSE_OLE 0 -#endif // broken compilers - -#if defined(__POCKETPC__) || defined(__SMARTPHONE__) - #include - #include -#endif - -#if wxUSE_OLE - #include -#endif - -#include -#include - -// For MB_TASKMODAL -#ifdef __WXWINCE__ -#include "wx/msw/wince/missing.h" -#endif - -// instead of including which is not part of the core SDK and not -// shipped at all with other compilers, we always define the parts of it we -// need here ourselves -// -// NB: DLLVER_PLATFORM_WINDOWS will be defined if shlwapi.h had been somehow -// included already -#ifndef DLLVER_PLATFORM_WINDOWS - // hopefully we don't need to change packing as DWORDs should be already - // correctly aligned - struct DLLVERSIONINFO - { - DWORD cbSize; - DWORD dwMajorVersion; // Major version - DWORD dwMinorVersion; // Minor version - DWORD dwBuildNumber; // Build number - DWORD dwPlatformID; // DLLVER_PLATFORM_* - }; - - typedef HRESULT (CALLBACK* DLLGETVERSIONPROC)(DLLVERSIONINFO *); -#endif // defined(DLLVERSIONINFO) - - -// --------------------------------------------------------------------------- -// global variables -// --------------------------------------------------------------------------- - -#if !defined(__WXMICROWIN__) && !defined(__WXWINCE__) -extern void wxSetKeyboardHook(bool doIt); -#endif - -// NB: all "NoRedraw" classes must have the same names as the "normal" classes -// with NR suffix - wxWindow::MSWCreate() supposes this -#ifdef __WXWINCE__ -WXDLLIMPEXP_CORE wxChar *wxCanvasClassName; -WXDLLIMPEXP_CORE wxChar *wxCanvasClassNameNR; -#else -WXDLLIMPEXP_CORE const wxChar *wxCanvasClassName = wxT("wxWindowClass"); -WXDLLIMPEXP_CORE const wxChar *wxCanvasClassNameNR = wxT("wxWindowClassNR"); -#endif -WXDLLIMPEXP_CORE const wxChar *wxMDIFrameClassName = wxT("wxMDIFrameClass"); -WXDLLIMPEXP_CORE const wxChar *wxMDIFrameClassNameNoRedraw = wxT("wxMDIFrameClassNR"); -WXDLLIMPEXP_CORE const wxChar *wxMDIChildFrameClassName = wxT("wxMDIChildFrameClass"); -WXDLLIMPEXP_CORE const wxChar *wxMDIChildFrameClassNameNoRedraw = wxT("wxMDIChildFrameClassNR"); - -// ---------------------------------------------------------------------------- -// private functions -// ---------------------------------------------------------------------------- - -LRESULT WXDLLEXPORT APIENTRY wxWndProc(HWND, UINT, WPARAM, LPARAM); - -// =========================================================================== -// wxGUIAppTraits implementation -// =========================================================================== - -// private class which we use to pass parameters from BeforeChildWaitLoop() to -// AfterChildWaitLoop() -struct ChildWaitLoopData -{ - ChildWaitLoopData(wxWindowDisabler *wd_, wxWindow *winActive_) - { - wd = wd_; - winActive = winActive_; - } - - wxWindowDisabler *wd; - wxWindow *winActive; -}; - -void *wxGUIAppTraits::BeforeChildWaitLoop() -{ - /* - We use a dirty hack here to disable all application windows (which we - must do because otherwise the calls to wxYield() could lead to some very - unexpected reentrancies in the users code) but to avoid losing - focus/activation entirely when the child process terminates which would - happen if we simply disabled everything using wxWindowDisabler. Indeed, - remember that Windows will never activate a disabled window and when the - last childs window is closed and Windows looks for a window to activate - all our windows are still disabled. There is no way to enable them in - time because we don't know when the childs windows are going to be - closed, so the solution we use here is to keep one special tiny frame - enabled all the time. Then when the child terminates it will get - activated and when we close it below -- after reenabling all the other - windows! -- the previously active window becomes activated again and - everything is ok. - */ - wxBeginBusyCursor(); - - // first disable all existing windows - wxWindowDisabler *wd = new wxWindowDisabler; - - // then create an "invisible" frame: it has minimal size, is positioned - // (hopefully) outside the screen and doesn't appear on the taskbar - wxWindow *winActive = new wxFrame - ( - wxTheApp->GetTopWindow(), - wxID_ANY, - wxEmptyString, - wxPoint(32600, 32600), - wxSize(1, 1), - wxDEFAULT_FRAME_STYLE | wxFRAME_NO_TASKBAR - ); - winActive->Show(); - - return new ChildWaitLoopData(wd, winActive); -} - -void wxGUIAppTraits::AlwaysYield() -{ - wxYield(); -} - -void wxGUIAppTraits::AfterChildWaitLoop(void *dataOrig) -{ - wxEndBusyCursor(); - - ChildWaitLoopData * const data = (ChildWaitLoopData *)dataOrig; - - delete data->wd; - - // finally delete the dummy frame and, as wd has been already destroyed and - // the other windows reenabled, the activation is going to return to the - // window which had had it before - data->winActive->Destroy(); - - // also delete the temporary data object itself - delete data; -} - -bool wxGUIAppTraits::DoMessageFromThreadWait() -{ - // we should return false only if the app should exit, i.e. only if - // Dispatch() determines that the main event loop should terminate - wxEventLoop *evtLoop = wxEventLoop::GetActive(); - if ( !evtLoop || !evtLoop->Pending() ) - { - // no events means no quit event - return true; - } - - return evtLoop->Dispatch(); -} - -wxPortId wxGUIAppTraits::GetToolkitVersion(int *majVer, int *minVer) const -{ - OSVERSIONINFO info; - wxZeroMemory(info); - - // on Windows, the toolkit version is the same of the OS version - // as Windows integrates the OS kernel with the GUI toolkit. - info.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); - if ( ::GetVersionEx(&info) ) - { - if ( majVer ) - *majVer = info.dwMajorVersion; - if ( minVer ) - *minVer = info.dwMinorVersion; - } - -#if defined(__WXHANDHELD__) || defined(__WXWINCE__) - return wxPORT_WINCE; -#else - return wxPORT_MSW; -#endif -} - -// =========================================================================== -// wxApp implementation -// =========================================================================== - -int wxApp::m_nCmdShow = SW_SHOWNORMAL; - -// --------------------------------------------------------------------------- -// wxWin macros -// --------------------------------------------------------------------------- - -IMPLEMENT_DYNAMIC_CLASS(wxApp, wxEvtHandler) - -BEGIN_EVENT_TABLE(wxApp, wxEvtHandler) - EVT_IDLE(wxApp::OnIdle) - EVT_END_SESSION(wxApp::OnEndSession) - EVT_QUERY_END_SESSION(wxApp::OnQueryEndSession) -END_EVENT_TABLE() - -// class to ensure that wxAppBase::CleanUp() is called if our Initialize() -// fails -class wxCallBaseCleanup -{ -public: - wxCallBaseCleanup(wxApp *app) : m_app(app) { } - ~wxCallBaseCleanup() { if ( m_app ) m_app->wxAppBase::CleanUp(); } - - void Dismiss() { m_app = NULL; } - -private: - wxApp *m_app; -}; - -//// Initialize -bool wxApp::Initialize(int& argc, wxChar **argv) -{ - if ( !wxAppBase::Initialize(argc, argv) ) - return false; - - // ensure that base cleanup is done if we return too early - wxCallBaseCleanup callBaseCleanup(this); - -#ifdef __WXWINCE__ - wxString tmp = GetAppName(); - tmp += wxT("ClassName"); - wxCanvasClassName = wxStrdup( tmp.c_str() ); - tmp += wxT("NR"); - wxCanvasClassNameNR = wxStrdup( tmp.c_str() ); - HWND hWnd = FindWindow( wxCanvasClassNameNR, NULL ); - if (hWnd) - { - SetForegroundWindow( (HWND)(((DWORD)hWnd)|0x01) ); - return false; - } -#endif - -#if !defined(__WXMICROWIN__) - InitCommonControls(); -#endif // !defined(__WXMICROWIN__) - -#if defined(__SMARTPHONE__) || defined(__POCKETPC__) - SHInitExtraControls(); -#endif - -#ifndef __WXWINCE__ - // Don't show a message box if a function such as SHGetFileInfo - // fails to find a device. - SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX); -#endif - - wxOleInitialize(); - - RegisterWindowClasses(); - - wxWinHandleHash = new wxWinHashTable(wxKEY_INTEGER, 100); - -#if !defined(__WXMICROWIN__) && !defined(__WXWINCE__) - wxSetKeyboardHook(true); -#endif - - callBaseCleanup.Dismiss(); - - return true; -} - -// --------------------------------------------------------------------------- -// RegisterWindowClasses -// --------------------------------------------------------------------------- - -// TODO we should only register classes really used by the app. For this it -// would be enough to just delay the class registration until an attempt -// to create a window of this class is made. -bool wxApp::RegisterWindowClasses() -{ - WNDCLASS wndclass; - wxZeroMemory(wndclass); - - // for each class we register one with CS_(V|H)REDRAW style and one - // without for windows created with wxNO_FULL_REDRAW_ON_REPAINT flag - static const long styleNormal = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS; - static const long styleNoRedraw = CS_DBLCLKS; - - // the fields which are common to all classes - wndclass.lpfnWndProc = (WNDPROC)wxWndProc; - wndclass.hInstance = wxhInstance; - wndclass.hCursor = ::LoadCursor((HINSTANCE)NULL, IDC_ARROW); - - // register the class for all normal windows - wndclass.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1); - wndclass.lpszClassName = wxCanvasClassName; - wndclass.style = styleNormal; - - if ( !RegisterClass(&wndclass) ) - { - wxLogLastError(wxT("RegisterClass(frame)")); - } - - // "no redraw" frame - wndclass.lpszClassName = wxCanvasClassNameNR; - wndclass.style = styleNoRedraw; - - if ( !RegisterClass(&wndclass) ) - { - wxLogLastError(wxT("RegisterClass(no redraw frame)")); - } - - // Register the MDI frame window class. - wndclass.hbrBackground = (HBRUSH)NULL; // paint MDI frame ourselves - wndclass.lpszClassName = wxMDIFrameClassName; - wndclass.style = styleNormal; - - if ( !RegisterClass(&wndclass) ) - { - wxLogLastError(wxT("RegisterClass(MDI parent)")); - } - - // "no redraw" MDI frame - wndclass.lpszClassName = wxMDIFrameClassNameNoRedraw; - wndclass.style = styleNoRedraw; - - if ( !RegisterClass(&wndclass) ) - { - wxLogLastError(wxT("RegisterClass(no redraw MDI parent frame)")); - } - - // Register the MDI child frame window class. - wndclass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); - wndclass.lpszClassName = wxMDIChildFrameClassName; - wndclass.style = styleNormal; - - if ( !RegisterClass(&wndclass) ) - { - wxLogLastError(wxT("RegisterClass(MDI child)")); - } - - // "no redraw" MDI child frame - wndclass.lpszClassName = wxMDIChildFrameClassNameNoRedraw; - wndclass.style = styleNoRedraw; - - if ( !RegisterClass(&wndclass) ) - { - wxLogLastError(wxT("RegisterClass(no redraw MDI child)")); - } - - return true; -} - -// --------------------------------------------------------------------------- -// UnregisterWindowClasses -// --------------------------------------------------------------------------- - -bool wxApp::UnregisterWindowClasses() -{ - bool retval = true; - -#ifndef __WXMICROWIN__ - // MDI frame window class. - if ( !::UnregisterClass(wxMDIFrameClassName, wxhInstance) ) - { - wxLogLastError(wxT("UnregisterClass(MDI parent)")); - - retval = false; - } - - // "no redraw" MDI frame - if ( !::UnregisterClass(wxMDIFrameClassNameNoRedraw, wxhInstance) ) - { - wxLogLastError(wxT("UnregisterClass(no redraw MDI parent frame)")); - - retval = false; - } - - // MDI child frame window class. - if ( !::UnregisterClass(wxMDIChildFrameClassName, wxhInstance) ) - { - wxLogLastError(wxT("UnregisterClass(MDI child)")); - - retval = false; - } - - // "no redraw" MDI child frame - if ( !::UnregisterClass(wxMDIChildFrameClassNameNoRedraw, wxhInstance) ) - { - wxLogLastError(wxT("UnregisterClass(no redraw MDI child)")); - - retval = false; - } - - // canvas class name - if ( !::UnregisterClass(wxCanvasClassName, wxhInstance) ) - { - wxLogLastError(wxT("UnregisterClass(canvas)")); - - retval = false; - } - - if ( !::UnregisterClass(wxCanvasClassNameNR, wxhInstance) ) - { - wxLogLastError(wxT("UnregisterClass(no redraw canvas)")); - - retval = false; - } -#endif // __WXMICROWIN__ - - return retval; -} - -void wxApp::CleanUp() -{ - // all objects pending for deletion must be deleted first, otherwise we - // would crash when they use wxWinHandleHash (and UnregisterWindowClasses() - // call wouldn't succeed as long as any windows still exist), so call the - // base class method first and only then do our clean up - wxAppBase::CleanUp(); - -#if !defined(__WXMICROWIN__) && !defined(__WXWINCE__) - wxSetKeyboardHook(false); -#endif - - wxOleUninitialize(); - - // for an EXE the classes are unregistered when it terminates but DLL may - // be loaded several times (load/unload/load) into the same process in - // which case the registration will fail after the first time if we don't - // unregister the classes now - UnregisterWindowClasses(); - - delete wxWinHandleHash; - wxWinHandleHash = NULL; - -#ifdef __WXWINCE__ - free( wxCanvasClassName ); - free( wxCanvasClassNameNR ); -#endif -} - -// ---------------------------------------------------------------------------- -// wxApp ctor/dtor -// ---------------------------------------------------------------------------- - -wxApp::wxApp() -{ - m_printMode = wxPRINT_WINDOWS; -} - -wxApp::~wxApp() -{ -} - -// ---------------------------------------------------------------------------- -// wxApp idle handling -// ---------------------------------------------------------------------------- - -void wxApp::OnIdle(wxIdleEvent& event) -{ - wxAppBase::OnIdle(event); - -#if wxUSE_DC_CACHEING - // automated DC cache management: clear the cached DCs and bitmap - // if it's likely that the app has finished with them, that is, we - // get an idle event and we're not dragging anything. - if (!::GetKeyState(MK_LBUTTON) && !::GetKeyState(MK_MBUTTON) && !::GetKeyState(MK_RBUTTON)) - wxDC::ClearCache(); -#endif // wxUSE_DC_CACHEING -} - -void wxApp::WakeUpIdle() -{ - // Send the top window a dummy message so idle handler processing will - // start up again. Doing it this way ensures that the idle handler - // wakes up in the right thread (see also wxWakeUpMainThread() which does - // the same for the main app thread only) - wxWindow * const topWindow = wxTheApp->GetTopWindow(); - if ( topWindow ) - { - HWND hwndTop = GetHwndOf(topWindow); - - // Do not post WM_NULL if there's already a pending WM_NULL to avoid - // overflowing the message queue. - // - // Notice that due to a limitation of PeekMessage() API (which handles - // 0,0 range specially), we have to check the range from 0-1 instead. - // This still makes it possible to overflow the queue with WM_NULLs by - // interspersing the calles to WakeUpIdle() with windows creation but - // it should be rather hard to do it accidentally. - MSG msg; - if ( !::PeekMessage(&msg, hwndTop, 0, 1, PM_NOREMOVE) || - ::PeekMessage(&msg, hwndTop, 1, 1, PM_NOREMOVE) ) - { - if ( !::PostMessage(hwndTop, WM_NULL, 0, 0) ) - { - // should never happen - wxLogLastError(wxT("PostMessage(WM_NULL)")); - } - } - } -} - -// ---------------------------------------------------------------------------- -// other wxApp event hanlders -// ---------------------------------------------------------------------------- - -void wxApp::OnEndSession(wxCloseEvent& WXUNUSED(event)) -{ - if (GetTopWindow()) - GetTopWindow()->Close(true); -} - -// Default behaviour: close the application with prompts. The -// user can veto the close, and therefore the end session. -void wxApp::OnQueryEndSession(wxCloseEvent& event) -{ - if (GetTopWindow()) - { - if (!GetTopWindow()->Close(!event.CanVeto())) - event.Veto(true); - } -} - -// ---------------------------------------------------------------------------- -// miscellaneous -// ---------------------------------------------------------------------------- - -/* static */ -int wxApp::GetComCtl32Version() -{ -#if defined(__WXMICROWIN__) || defined(__WXWINCE__) - return 0; -#else - // cache the result - // - // NB: this is MT-ok as in the worst case we'd compute s_verComCtl32 twice, - // but as its value should be the same both times it doesn't matter - static int s_verComCtl32 = -1; - - if ( s_verComCtl32 == -1 ) - { - // initally assume no comctl32.dll at all - s_verComCtl32 = 0; - - // we're prepared to handle the errors - wxLogNull noLog; - -#if wxUSE_DYNLIB_CLASS - // do we have it? - wxDynamicLibrary dllComCtl32(_T("comctl32.dll"), wxDL_VERBATIM); - - // if so, then we can check for the version - if ( dllComCtl32.IsLoaded() ) - { - // now check if the function is available during run-time - wxDYNLIB_FUNCTION( DLLGETVERSIONPROC, DllGetVersion, dllComCtl32 ); - if ( pfnDllGetVersion ) - { - DLLVERSIONINFO dvi; - dvi.cbSize = sizeof(dvi); - - HRESULT hr = (*pfnDllGetVersion)(&dvi); - if ( FAILED(hr) ) - { - wxLogApiError(_T("DllGetVersion"), hr); - } - else - { - // this is incompatible with _WIN32_IE values, but - // compatible with the other values returned by - // GetComCtl32Version() - s_verComCtl32 = 100*dvi.dwMajorVersion + - dvi.dwMinorVersion; - } - } - - // if DllGetVersion() is unavailable either during compile or - // run-time, try to guess the version otherwise - if ( !s_verComCtl32 ) - { - // InitCommonControlsEx is unique to 4.70 and later - void *pfn = dllComCtl32.GetSymbol(_T("InitCommonControlsEx")); - if ( !pfn ) - { - // not found, must be 4.00 - s_verComCtl32 = 400; - } - else // 4.70+ - { - // many symbols appeared in comctl32 4.71, could use any of - // them except may be DllInstall() - pfn = dllComCtl32.GetSymbol(_T("InitializeFlatSB")); - if ( !pfn ) - { - // not found, must be 4.70 - s_verComCtl32 = 470; - } - else - { - // found, must be 4.71 or later - s_verComCtl32 = 471; - } - } - } - } -#endif - } - - return s_verComCtl32; -#endif // Microwin/!Microwin -} - -// Yield to incoming messages - -bool wxApp::Yield(bool onlyIfNeeded) -{ - // MT-FIXME - static bool s_inYield = false; - -#if wxUSE_LOG - // disable log flushing from here because a call to wxYield() shouldn't - // normally result in message boxes popping up &c - wxLog::Suspend(); -#endif // wxUSE_LOG - - if ( s_inYield ) - { - if ( !onlyIfNeeded ) - { - wxFAIL_MSG( wxT("wxYield called recursively" ) ); - } - - return false; - } - - s_inYield = true; - - // we don't want to process WM_QUIT from here - it should be processed in - // the main event loop in order to stop it - wxEventLoopGuarantor dummyLoopIfNeeded; - MSG msg; - while ( PeekMessage(&msg, (HWND)0, 0, 0, PM_NOREMOVE) && - msg.message != WM_QUIT ) - { -#if wxUSE_THREADS - wxMutexGuiLeaveOrEnter(); -#endif // wxUSE_THREADS - - if ( !wxTheApp->Dispatch() ) - break; - } - - // if there are pending events, we must process them. - ProcessPendingEvents(); - -#if wxUSE_LOG - // let the logs be flashed again - wxLog::Resume(); -#endif // wxUSE_LOG - - s_inYield = false; - - return true; -} - -#if wxUSE_EXCEPTIONS - -// ---------------------------------------------------------------------------- -// exception handling -// ---------------------------------------------------------------------------- - -bool wxApp::OnExceptionInMainLoop() -{ - // ask the user about what to do: use the Win32 API function here as it - // could be dangerous to use any wxWidgets code in this state - switch ( - ::MessageBox - ( - NULL, - _T("An unhandled exception occurred. Press \"Abort\" to \ -terminate the program,\r\n\ -\"Retry\" to exit the program normally and \"Ignore\" to try to continue."), - _T("Unhandled exception"), - MB_ABORTRETRYIGNORE | - MB_ICONERROR| - MB_TASKMODAL - ) - ) - { - case IDABORT: - throw; - - default: - wxFAIL_MSG( _T("unexpected MessageBox() return code") ); - // fall through - - case IDRETRY: - return false; - - case IDIGNORE: - return true; - } -} - -#endif // wxUSE_EXCEPTIONS - -// ---------------------------------------------------------------------------- -// deprecated event loop functions -// ---------------------------------------------------------------------------- - -#if WXWIN_COMPATIBILITY_2_4 - -void wxApp::DoMessage(WXMSG *pMsg) -{ - wxEventLoop *evtLoop = wxEventLoop::GetActive(); - if ( evtLoop ) - evtLoop->ProcessMessage(pMsg); -} - -bool wxApp::DoMessage() -{ - wxEventLoop *evtLoop = wxEventLoop::GetActive(); - return evtLoop ? evtLoop->Dispatch() : false; -} - -bool wxApp::ProcessMessage(WXMSG* pMsg) -{ - wxEventLoop *evtLoop = wxEventLoop::GetActive(); - return evtLoop && evtLoop->PreProcessMessage(pMsg); -} - -#endif // WXWIN_COMPATIBILITY_2_4 +///////////////////////////////////////////////////////////////////////////// +// Name: src/msw/app.cpp +// Purpose: wxApp +// Author: Julian Smart +// Modified by: +// Created: 04/01/98 +// RCS-ID: $Id: app.cpp 53607 2008-05-16 15:21:40Z SN $ +// Copyright: (c) Julian Smart +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// =========================================================================== +// declarations +// =========================================================================== + +// --------------------------------------------------------------------------- +// headers +// --------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#if defined(__BORLANDC__) + #pragma hdrstop +#endif + +#ifndef WX_PRECOMP + #include "wx/msw/wrapcctl.h" + #include "wx/dynarray.h" + #include "wx/frame.h" + #include "wx/app.h" + #include "wx/utils.h" + #include "wx/gdicmn.h" + #include "wx/pen.h" + #include "wx/brush.h" + #include "wx/cursor.h" + #include "wx/icon.h" + #include "wx/palette.h" + #include "wx/dc.h" + #include "wx/dialog.h" + #include "wx/msgdlg.h" + #include "wx/intl.h" + #include "wx/wxchar.h" + #include "wx/log.h" + #include "wx/module.h" +#endif + +#include "wx/apptrait.h" +#include "wx/filename.h" +#include "wx/dynlib.h" +#include "wx/evtloop.h" + +#include "wx/msw/private.h" +#include "wx/msw/ole/oleutils.h" + +#if wxUSE_TOOLTIPS + #include "wx/tooltip.h" +#endif // wxUSE_TOOLTIPS + +// OLE is used for drag-and-drop, clipboard, OLE Automation..., but some +// compilers don't support it (missing headers, libs, ...) +#if defined(__GNUWIN32_OLD__) || defined(__SYMANTEC__) || defined(__SALFORDC__) + #undef wxUSE_OLE + + #define wxUSE_OLE 0 +#endif // broken compilers + +#if defined(__POCKETPC__) || defined(__SMARTPHONE__) + #include + #include +#endif + +#if wxUSE_OLE + #include +#endif + +#include +#include + +// For MB_TASKMODAL +#ifdef __WXWINCE__ +#include "wx/msw/wince/missing.h" +#endif + +// instead of including which is not part of the core SDK and not +// shipped at all with other compilers, we always define the parts of it we +// need here ourselves +// +// NB: DLLVER_PLATFORM_WINDOWS will be defined if shlwapi.h had been somehow +// included already +#ifndef DLLVER_PLATFORM_WINDOWS + // hopefully we don't need to change packing as DWORDs should be already + // correctly aligned + struct DLLVERSIONINFO + { + DWORD cbSize; + DWORD dwMajorVersion; // Major version + DWORD dwMinorVersion; // Minor version + DWORD dwBuildNumber; // Build number + DWORD dwPlatformID; // DLLVER_PLATFORM_* + }; + + typedef HRESULT (CALLBACK* DLLGETVERSIONPROC)(DLLVERSIONINFO *); +#endif // defined(DLLVERSIONINFO) + + +// --------------------------------------------------------------------------- +// global variables +// --------------------------------------------------------------------------- + +#if !defined(__WXMICROWIN__) && !defined(__WXWINCE__) +extern void wxSetKeyboardHook(bool doIt); +#endif + +// NB: all "NoRedraw" classes must have the same names as the "normal" classes +// with NR suffix - wxWindow::MSWCreate() supposes this +#ifdef __WXWINCE__ +WXDLLIMPEXP_CORE wxChar *wxCanvasClassName; +WXDLLIMPEXP_CORE wxChar *wxCanvasClassNameNR; +#else +WXDLLIMPEXP_CORE const wxChar *wxCanvasClassName = wxT("wxWindowClass"); +WXDLLIMPEXP_CORE const wxChar *wxCanvasClassNameNR = wxT("wxWindowClassNR"); +#endif +WXDLLIMPEXP_CORE const wxChar *wxMDIFrameClassName = wxT("wxMDIFrameClass"); +WXDLLIMPEXP_CORE const wxChar *wxMDIFrameClassNameNoRedraw = wxT("wxMDIFrameClassNR"); +WXDLLIMPEXP_CORE const wxChar *wxMDIChildFrameClassName = wxT("wxMDIChildFrameClass"); +WXDLLIMPEXP_CORE const wxChar *wxMDIChildFrameClassNameNoRedraw = wxT("wxMDIChildFrameClassNR"); + +// ---------------------------------------------------------------------------- +// private functions +// ---------------------------------------------------------------------------- + +LRESULT WXDLLEXPORT APIENTRY wxWndProc(HWND, UINT, WPARAM, LPARAM); + +// =========================================================================== +// wxGUIAppTraits implementation +// =========================================================================== + +// private class which we use to pass parameters from BeforeChildWaitLoop() to +// AfterChildWaitLoop() +struct ChildWaitLoopData +{ + ChildWaitLoopData(wxWindowDisabler *wd_, wxWindow *winActive_) + { + wd = wd_; + winActive = winActive_; + } + + wxWindowDisabler *wd; + wxWindow *winActive; +}; + +void *wxGUIAppTraits::BeforeChildWaitLoop() +{ + /* + We use a dirty hack here to disable all application windows (which we + must do because otherwise the calls to wxYield() could lead to some very + unexpected reentrancies in the users code) but to avoid losing + focus/activation entirely when the child process terminates which would + happen if we simply disabled everything using wxWindowDisabler. Indeed, + remember that Windows will never activate a disabled window and when the + last childs window is closed and Windows looks for a window to activate + all our windows are still disabled. There is no way to enable them in + time because we don't know when the childs windows are going to be + closed, so the solution we use here is to keep one special tiny frame + enabled all the time. Then when the child terminates it will get + activated and when we close it below -- after reenabling all the other + windows! -- the previously active window becomes activated again and + everything is ok. + */ + wxBeginBusyCursor(); + + // first disable all existing windows + wxWindowDisabler *wd = new wxWindowDisabler; + + // then create an "invisible" frame: it has minimal size, is positioned + // (hopefully) outside the screen and doesn't appear on the taskbar + wxWindow *winActive = new wxFrame + ( + wxTheApp->GetTopWindow(), + wxID_ANY, + wxEmptyString, + wxPoint(32600, 32600), + wxSize(1, 1), + wxDEFAULT_FRAME_STYLE | wxFRAME_NO_TASKBAR + ); + winActive->Show(); + + return new ChildWaitLoopData(wd, winActive); +} + +void wxGUIAppTraits::AlwaysYield() +{ + wxYield(); +} + +void wxGUIAppTraits::AfterChildWaitLoop(void *dataOrig) +{ + wxEndBusyCursor(); + + ChildWaitLoopData * const data = (ChildWaitLoopData *)dataOrig; + + delete data->wd; + + // finally delete the dummy frame and, as wd has been already destroyed and + // the other windows reenabled, the activation is going to return to the + // window which had had it before + data->winActive->Destroy(); + + // also delete the temporary data object itself + delete data; +} + +bool wxGUIAppTraits::DoMessageFromThreadWait() +{ + // we should return false only if the app should exit, i.e. only if + // Dispatch() determines that the main event loop should terminate + wxEventLoop *evtLoop = wxEventLoop::GetActive(); + if ( !evtLoop || !evtLoop->Pending() ) + { + // no events means no quit event + return true; + } + + return evtLoop->Dispatch(); +} + +wxPortId wxGUIAppTraits::GetToolkitVersion(int *majVer, int *minVer) const +{ + OSVERSIONINFO info; + wxZeroMemory(info); + + // on Windows, the toolkit version is the same of the OS version + // as Windows integrates the OS kernel with the GUI toolkit. + info.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + if ( ::GetVersionEx(&info) ) + { + if ( majVer ) + *majVer = info.dwMajorVersion; + if ( minVer ) + *minVer = info.dwMinorVersion; + } + +#if defined(__WXHANDHELD__) || defined(__WXWINCE__) + return wxPORT_WINCE; +#else + return wxPORT_MSW; +#endif +} + +// =========================================================================== +// wxApp implementation +// =========================================================================== + +int wxApp::m_nCmdShow = SW_SHOWNORMAL; + +// --------------------------------------------------------------------------- +// wxWin macros +// --------------------------------------------------------------------------- + +IMPLEMENT_DYNAMIC_CLASS(wxApp, wxEvtHandler) + +BEGIN_EVENT_TABLE(wxApp, wxEvtHandler) + EVT_IDLE(wxApp::OnIdle) + EVT_END_SESSION(wxApp::OnEndSession) + EVT_QUERY_END_SESSION(wxApp::OnQueryEndSession) +END_EVENT_TABLE() + +// class to ensure that wxAppBase::CleanUp() is called if our Initialize() +// fails +class wxCallBaseCleanup +{ +public: + wxCallBaseCleanup(wxApp *app) : m_app(app) { } + ~wxCallBaseCleanup() { if ( m_app ) m_app->wxAppBase::CleanUp(); } + + void Dismiss() { m_app = NULL; } + +private: + wxApp *m_app; +}; + +//// Initialize +bool wxApp::Initialize(int& argc, wxChar **argv) +{ + if ( !wxAppBase::Initialize(argc, argv) ) + return false; + + // ensure that base cleanup is done if we return too early + wxCallBaseCleanup callBaseCleanup(this); + +#ifdef __WXWINCE__ + wxString tmp = GetAppName(); + tmp += wxT("ClassName"); + wxCanvasClassName = wxStrdup( tmp.c_str() ); + tmp += wxT("NR"); + wxCanvasClassNameNR = wxStrdup( tmp.c_str() ); + HWND hWnd = FindWindow( wxCanvasClassNameNR, NULL ); + if (hWnd) + { + SetForegroundWindow( (HWND)(((DWORD)hWnd)|0x01) ); + return false; + } +#endif + +#if !defined(__WXMICROWIN__) + InitCommonControls(); +#endif // !defined(__WXMICROWIN__) + +#if defined(__SMARTPHONE__) || defined(__POCKETPC__) + SHInitExtraControls(); +#endif + +#ifndef __WXWINCE__ + // Don't show a message box if a function such as SHGetFileInfo + // fails to find a device. + SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX); +#endif + + wxOleInitialize(); + + RegisterWindowClasses(); + + wxWinHandleHash = new wxWinHashTable(wxKEY_INTEGER, 100); + +#if !defined(__WXMICROWIN__) && !defined(__WXWINCE__) + wxSetKeyboardHook(true); +#endif + + callBaseCleanup.Dismiss(); + + return true; +} + +// --------------------------------------------------------------------------- +// RegisterWindowClasses +// --------------------------------------------------------------------------- + +// TODO we should only register classes really used by the app. For this it +// would be enough to just delay the class registration until an attempt +// to create a window of this class is made. +bool wxApp::RegisterWindowClasses() +{ + WNDCLASS wndclass; + wxZeroMemory(wndclass); + + // for each class we register one with CS_(V|H)REDRAW style and one + // without for windows created with wxNO_FULL_REDRAW_ON_REPAINT flag + static const long styleNormal = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS; + static const long styleNoRedraw = CS_DBLCLKS; + + // the fields which are common to all classes + wndclass.lpfnWndProc = (WNDPROC)wxWndProc; + wndclass.hInstance = wxhInstance; + wndclass.hCursor = ::LoadCursor((HINSTANCE)NULL, IDC_ARROW); + + // register the class for all normal windows + wndclass.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1); + wndclass.lpszClassName = wxCanvasClassName; + wndclass.style = styleNormal; + + if ( !RegisterClass(&wndclass) ) + { + wxLogLastError(wxT("RegisterClass(frame)")); + } + + // "no redraw" frame + wndclass.lpszClassName = wxCanvasClassNameNR; + wndclass.style = styleNoRedraw; + + if ( !RegisterClass(&wndclass) ) + { + wxLogLastError(wxT("RegisterClass(no redraw frame)")); + } + + // Register the MDI frame window class. + wndclass.hbrBackground = (HBRUSH)NULL; // paint MDI frame ourselves + wndclass.lpszClassName = wxMDIFrameClassName; + wndclass.style = styleNormal; + + if ( !RegisterClass(&wndclass) ) + { + wxLogLastError(wxT("RegisterClass(MDI parent)")); + } + + // "no redraw" MDI frame + wndclass.lpszClassName = wxMDIFrameClassNameNoRedraw; + wndclass.style = styleNoRedraw; + + if ( !RegisterClass(&wndclass) ) + { + wxLogLastError(wxT("RegisterClass(no redraw MDI parent frame)")); + } + + // Register the MDI child frame window class. + wndclass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); + wndclass.lpszClassName = wxMDIChildFrameClassName; + wndclass.style = styleNormal; + + if ( !RegisterClass(&wndclass) ) + { + wxLogLastError(wxT("RegisterClass(MDI child)")); + } + + // "no redraw" MDI child frame + wndclass.lpszClassName = wxMDIChildFrameClassNameNoRedraw; + wndclass.style = styleNoRedraw; + + if ( !RegisterClass(&wndclass) ) + { + wxLogLastError(wxT("RegisterClass(no redraw MDI child)")); + } + + return true; +} + +// --------------------------------------------------------------------------- +// UnregisterWindowClasses +// --------------------------------------------------------------------------- + +bool wxApp::UnregisterWindowClasses() +{ + bool retval = true; + +#ifndef __WXMICROWIN__ + // MDI frame window class. + if ( !::UnregisterClass(wxMDIFrameClassName, wxhInstance) ) + { + wxLogLastError(wxT("UnregisterClass(MDI parent)")); + + retval = false; + } + + // "no redraw" MDI frame + if ( !::UnregisterClass(wxMDIFrameClassNameNoRedraw, wxhInstance) ) + { + wxLogLastError(wxT("UnregisterClass(no redraw MDI parent frame)")); + + retval = false; + } + + // MDI child frame window class. + if ( !::UnregisterClass(wxMDIChildFrameClassName, wxhInstance) ) + { + wxLogLastError(wxT("UnregisterClass(MDI child)")); + + retval = false; + } + + // "no redraw" MDI child frame + if ( !::UnregisterClass(wxMDIChildFrameClassNameNoRedraw, wxhInstance) ) + { + wxLogLastError(wxT("UnregisterClass(no redraw MDI child)")); + + retval = false; + } + + // canvas class name + if ( !::UnregisterClass(wxCanvasClassName, wxhInstance) ) + { + wxLogLastError(wxT("UnregisterClass(canvas)")); + + retval = false; + } + + if ( !::UnregisterClass(wxCanvasClassNameNR, wxhInstance) ) + { + wxLogLastError(wxT("UnregisterClass(no redraw canvas)")); + + retval = false; + } +#endif // __WXMICROWIN__ + + return retval; +} + +void wxApp::CleanUp() +{ + // all objects pending for deletion must be deleted first, otherwise we + // would crash when they use wxWinHandleHash (and UnregisterWindowClasses() + // call wouldn't succeed as long as any windows still exist), so call the + // base class method first and only then do our clean up + wxAppBase::CleanUp(); + +#if !defined(__WXMICROWIN__) && !defined(__WXWINCE__) + wxSetKeyboardHook(false); +#endif + + wxOleUninitialize(); + + // for an EXE the classes are unregistered when it terminates but DLL may + // be loaded several times (load/unload/load) into the same process in + // which case the registration will fail after the first time if we don't + // unregister the classes now + UnregisterWindowClasses(); + + delete wxWinHandleHash; + wxWinHandleHash = NULL; + +#ifdef __WXWINCE__ + free( wxCanvasClassName ); + free( wxCanvasClassNameNR ); +#endif +} + +// ---------------------------------------------------------------------------- +// wxApp ctor/dtor +// ---------------------------------------------------------------------------- + +wxApp::wxApp() +{ + m_printMode = wxPRINT_WINDOWS; +} + +wxApp::~wxApp() +{ +} + +// ---------------------------------------------------------------------------- +// wxApp idle handling +// ---------------------------------------------------------------------------- + +void wxApp::OnIdle(wxIdleEvent& event) +{ + wxAppBase::OnIdle(event); + +#if wxUSE_DC_CACHEING + // automated DC cache management: clear the cached DCs and bitmap + // if it's likely that the app has finished with them, that is, we + // get an idle event and we're not dragging anything. + if (!::GetKeyState(MK_LBUTTON) && !::GetKeyState(MK_MBUTTON) && !::GetKeyState(MK_RBUTTON)) + wxDC::ClearCache(); +#endif // wxUSE_DC_CACHEING +} + +void wxApp::WakeUpIdle() +{ + // Send the top window a dummy message so idle handler processing will + // start up again. Doing it this way ensures that the idle handler + // wakes up in the right thread (see also wxWakeUpMainThread() which does + // the same for the main app thread only) + wxWindow * const topWindow = wxTheApp->GetTopWindow(); + if ( topWindow ) + { + HWND hwndTop = GetHwndOf(topWindow); + + // Do not post WM_NULL if there's already a pending WM_NULL to avoid + // overflowing the message queue. + // + // Notice that due to a limitation of PeekMessage() API (which handles + // 0,0 range specially), we have to check the range from 0-1 instead. + // This still makes it possible to overflow the queue with WM_NULLs by + // interspersing the calles to WakeUpIdle() with windows creation but + // it should be rather hard to do it accidentally. + MSG msg; + if ( !::PeekMessage(&msg, hwndTop, 0, 1, PM_NOREMOVE) || + ::PeekMessage(&msg, hwndTop, 1, 1, PM_NOREMOVE) ) + { + if ( !::PostMessage(hwndTop, WM_NULL, 0, 0) ) + { + // should never happen + wxLogLastError(wxT("PostMessage(WM_NULL)")); + } + } + } +} + +// ---------------------------------------------------------------------------- +// other wxApp event hanlders +// ---------------------------------------------------------------------------- + +void wxApp::OnEndSession(wxCloseEvent& WXUNUSED(event)) +{ + if (GetTopWindow()) + GetTopWindow()->Close(true); +} + +// Default behaviour: close the application with prompts. The +// user can veto the close, and therefore the end session. +void wxApp::OnQueryEndSession(wxCloseEvent& event) +{ + if (GetTopWindow()) + { + if (!GetTopWindow()->Close(!event.CanVeto())) + event.Veto(true); + } +} + +// ---------------------------------------------------------------------------- +// miscellaneous +// ---------------------------------------------------------------------------- + +/* static */ +int wxApp::GetComCtl32Version() +{ +#if defined(__WXMICROWIN__) || defined(__WXWINCE__) + return 0; +#else + // cache the result + // + // NB: this is MT-ok as in the worst case we'd compute s_verComCtl32 twice, + // but as its value should be the same both times it doesn't matter + static int s_verComCtl32 = -1; + + if ( s_verComCtl32 == -1 ) + { + // initally assume no comctl32.dll at all + s_verComCtl32 = 0; + + // we're prepared to handle the errors + wxLogNull noLog; + +#if wxUSE_DYNLIB_CLASS + // do we have it? + wxDynamicLibrary dllComCtl32(_T("comctl32.dll"), wxDL_VERBATIM); + + // if so, then we can check for the version + if ( dllComCtl32.IsLoaded() ) + { + // now check if the function is available during run-time + wxDYNLIB_FUNCTION( DLLGETVERSIONPROC, DllGetVersion, dllComCtl32 ); + if ( pfnDllGetVersion ) + { + DLLVERSIONINFO dvi; + dvi.cbSize = sizeof(dvi); + + HRESULT hr = (*pfnDllGetVersion)(&dvi); + if ( FAILED(hr) ) + { + wxLogApiError(_T("DllGetVersion"), hr); + } + else + { + // this is incompatible with _WIN32_IE values, but + // compatible with the other values returned by + // GetComCtl32Version() + s_verComCtl32 = 100*dvi.dwMajorVersion + + dvi.dwMinorVersion; + } + } + + // if DllGetVersion() is unavailable either during compile or + // run-time, try to guess the version otherwise + if ( !s_verComCtl32 ) + { + // InitCommonControlsEx is unique to 4.70 and later + void *pfn = dllComCtl32.GetSymbol(_T("InitCommonControlsEx")); + if ( !pfn ) + { + // not found, must be 4.00 + s_verComCtl32 = 400; + } + else // 4.70+ + { + // many symbols appeared in comctl32 4.71, could use any of + // them except may be DllInstall() + pfn = dllComCtl32.GetSymbol(_T("InitializeFlatSB")); + if ( !pfn ) + { + // not found, must be 4.70 + s_verComCtl32 = 470; + } + else + { + // found, must be 4.71 or later + s_verComCtl32 = 471; + } + } + } + } +#endif + } + + return s_verComCtl32; +#endif // Microwin/!Microwin +} + +// Yield to incoming messages + +bool wxApp::Yield(bool onlyIfNeeded) +{ + // MT-FIXME + static bool s_inYield = false; + +#if wxUSE_LOG + // disable log flushing from here because a call to wxYield() shouldn't + // normally result in message boxes popping up &c + wxLog::Suspend(); +#endif // wxUSE_LOG + + if ( s_inYield ) + { + if ( !onlyIfNeeded ) + { + wxFAIL_MSG( wxT("wxYield called recursively" ) ); + } + + return false; + } + + s_inYield = true; + + // we don't want to process WM_QUIT from here - it should be processed in + // the main event loop in order to stop it + wxEventLoopGuarantor dummyLoopIfNeeded; + MSG msg; + while ( PeekMessage(&msg, (HWND)0, 0, 0, PM_NOREMOVE) && + msg.message != WM_QUIT ) + { +#if wxUSE_THREADS + wxMutexGuiLeaveOrEnter(); +#endif // wxUSE_THREADS + + if ( !wxTheApp->Dispatch() ) + break; + } + + // if there are pending events, we must process them. + ProcessPendingEvents(); + +#if wxUSE_LOG + // let the logs be flashed again + wxLog::Resume(); +#endif // wxUSE_LOG + + s_inYield = false; + + return true; +} + +#if wxUSE_EXCEPTIONS + +// ---------------------------------------------------------------------------- +// exception handling +// ---------------------------------------------------------------------------- + +bool wxApp::OnExceptionInMainLoop() +{ + // ask the user about what to do: use the Win32 API function here as it + // could be dangerous to use any wxWidgets code in this state + switch ( + ::MessageBox + ( + NULL, + _T("An unhandled exception occurred. Press \"Abort\" to \ +terminate the program,\r\n\ +\"Retry\" to exit the program normally and \"Ignore\" to try to continue."), + _T("Unhandled exception"), + MB_ABORTRETRYIGNORE | + MB_ICONERROR| + MB_TASKMODAL + ) + ) + { + case IDABORT: + throw; + + default: + wxFAIL_MSG( _T("unexpected MessageBox() return code") ); + // fall through + + case IDRETRY: + return false; + + case IDIGNORE: + return true; + } +} + +#endif // wxUSE_EXCEPTIONS + +// ---------------------------------------------------------------------------- +// deprecated event loop functions +// ---------------------------------------------------------------------------- + +#if WXWIN_COMPATIBILITY_2_4 + +void wxApp::DoMessage(WXMSG *pMsg) +{ + wxEventLoop *evtLoop = wxEventLoop::GetActive(); + if ( evtLoop ) + evtLoop->ProcessMessage(pMsg); +} + +bool wxApp::DoMessage() +{ + wxEventLoop *evtLoop = wxEventLoop::GetActive(); + return evtLoop ? evtLoop->Dispatch() : false; +} + +bool wxApp::ProcessMessage(WXMSG* pMsg) +{ + wxEventLoop *evtLoop = wxEventLoop::GetActive(); + return evtLoop && evtLoop->PreProcessMessage(pMsg); +} + +#endif // WXWIN_COMPATIBILITY_2_4 diff --git a/Externals/wxWidgets/src/msw/basemsw.cpp b/Externals/wxWidgets/src/msw/basemsw.cpp index 5c820d4de2..4347fee039 100644 --- a/Externals/wxWidgets/src/msw/basemsw.cpp +++ b/Externals/wxWidgets/src/msw/basemsw.cpp @@ -1,73 +1,73 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: msw/basemsw.cpp -// Purpose: misc stuff only used in console applications under MSW -// Author: Vadim Zeitlin -// Modified by: -// Created: 22.06.2003 -// RCS-ID: $Id: basemsw.cpp 39831 2006-06-25 23:53:53Z VZ $ -// Copyright: (c) 2003 Vadim Zeitlin -// License: wxWindows licence -/////////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// for compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#ifndef WX_PRECOMP -#endif //WX_PRECOMP - -#include "wx/apptrait.h" -// MBN: this is a workaround for MSVC 5: if it is not #included in -// some wxBase file, wxRecursionGuard methods won't be exported from -// wxBase.dll, and MSVC 5 will give linker errors -#include "wx/recguard.h" - -#include "wx/msw/private.h" - -// ============================================================================ -// wxConsoleAppTraits implementation -// ============================================================================ - -void wxConsoleAppTraits::AlwaysYield() -{ - // we need to use special logic to deal with WM_PAINT: as this pseudo - // message is generated automatically as long as there are invalidated - // windows belonging to this thread, we'd never return if we waited here - // until we have no more of them left. OTOH, this message is always the - // last one in the queue, so we can safely return as soon as we detect it - MSG msg; - while ( ::PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) ) - { - if ( msg.message == WM_PAINT ) - break; - } -} - -void *wxConsoleAppTraits::BeforeChildWaitLoop() -{ - // nothing to do here - return NULL; -} - -void wxConsoleAppTraits::AfterChildWaitLoop(void * WXUNUSED(data)) -{ - // nothing to do here -} - -bool wxConsoleAppTraits::DoMessageFromThreadWait() -{ - // nothing to process here - return true; -} - +/////////////////////////////////////////////////////////////////////////////// +// Name: msw/basemsw.cpp +// Purpose: misc stuff only used in console applications under MSW +// Author: Vadim Zeitlin +// Modified by: +// Created: 22.06.2003 +// RCS-ID: $Id: basemsw.cpp 39831 2006-06-25 23:53:53Z VZ $ +// Copyright: (c) 2003 Vadim Zeitlin +// License: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// for compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#ifndef WX_PRECOMP +#endif //WX_PRECOMP + +#include "wx/apptrait.h" +// MBN: this is a workaround for MSVC 5: if it is not #included in +// some wxBase file, wxRecursionGuard methods won't be exported from +// wxBase.dll, and MSVC 5 will give linker errors +#include "wx/recguard.h" + +#include "wx/msw/private.h" + +// ============================================================================ +// wxConsoleAppTraits implementation +// ============================================================================ + +void wxConsoleAppTraits::AlwaysYield() +{ + // we need to use special logic to deal with WM_PAINT: as this pseudo + // message is generated automatically as long as there are invalidated + // windows belonging to this thread, we'd never return if we waited here + // until we have no more of them left. OTOH, this message is always the + // last one in the queue, so we can safely return as soon as we detect it + MSG msg; + while ( ::PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) ) + { + if ( msg.message == WM_PAINT ) + break; + } +} + +void *wxConsoleAppTraits::BeforeChildWaitLoop() +{ + // nothing to do here + return NULL; +} + +void wxConsoleAppTraits::AfterChildWaitLoop(void * WXUNUSED(data)) +{ + // nothing to do here +} + +bool wxConsoleAppTraits::DoMessageFromThreadWait() +{ + // nothing to process here + return true; +} + diff --git a/Externals/wxWidgets/src/msw/bitmap.cpp b/Externals/wxWidgets/src/msw/bitmap.cpp index 188a7fe44d..c87e490f26 100644 --- a/Externals/wxWidgets/src/msw/bitmap.cpp +++ b/Externals/wxWidgets/src/msw/bitmap.cpp @@ -1,1806 +1,1806 @@ -//////////////////////////////////////////////////////////////////////////// -// Name: src/msw/bitmap.cpp -// Purpose: wxBitmap -// Author: Julian Smart -// Modified by: -// Created: 04/01/98 -// RCS-ID: $Id: bitmap.cpp 48236 2007-08-20 23:43:32Z KO $ -// Copyright: (c) Julian Smart -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#include "wx/bitmap.h" - -#ifndef WX_PRECOMP - #include - - #include "wx/list.h" - #include "wx/utils.h" - #include "wx/app.h" - #include "wx/palette.h" - #include "wx/dcmemory.h" - #include "wx/icon.h" - #include "wx/log.h" - #include "wx/image.h" -#endif - -#include "wx/msw/private.h" - -#if wxUSE_WXDIB - #include "wx/msw/dib.h" -#endif - -#ifdef wxHAVE_RAW_BITMAP - #include "wx/rawbmp.h" -#endif - -// missing from mingw32 header -#ifndef CLR_INVALID - #define CLR_INVALID ((COLORREF)-1) -#endif // no CLR_INVALID - -// ---------------------------------------------------------------------------- -// Bitmap data -// ---------------------------------------------------------------------------- - -class WXDLLEXPORT wxBitmapRefData : public wxGDIImageRefData -{ -public: - wxBitmapRefData(); - wxBitmapRefData(const wxBitmapRefData& data); - virtual ~wxBitmapRefData() { Free(); } - - virtual void Free(); - - // set the mask object to use as the mask, we take ownership of it - void SetMask(wxMask *mask) - { - delete m_bitmapMask; - m_bitmapMask = mask; - } - - // set the HBITMAP to use as the mask - void SetMask(HBITMAP hbmpMask) - { - SetMask(new wxMask((WXHBITMAP)hbmpMask)); - } - - // return the mask - wxMask *GetMask() const { return m_bitmapMask; } - -public: -#if wxUSE_PALETTE - wxPalette m_bitmapPalette; -#endif // wxUSE_PALETTE - - // MSW-specific - // ------------ - -#ifdef __WXDEBUG__ - // this field is solely for error checking: we detect selecting a bitmap - // into more than one DC at once or deleting a bitmap still selected into a - // DC (both are serious programming errors under Windows) - wxDC *m_selectedInto; -#endif // __WXDEBUG__ - -#if wxUSE_WXDIB - // when GetRawData() is called for a DDB we need to convert it to a DIB - // first to be able to provide direct access to it and we cache that DIB - // here and convert it back to DDB when UngetRawData() is called - wxDIB *m_dib; -#endif - - // true if we have alpha transparency info and can be drawn using - // AlphaBlend() - bool m_hasAlpha; - - // true if our HBITMAP is a DIB section, false if it is a DDB - bool m_isDIB; - -private: - // optional mask for transparent drawing - wxMask *m_bitmapMask; - - - // not implemented - wxBitmapRefData& operator=(const wxBitmapRefData&); -}; - -// ---------------------------------------------------------------------------- -// macros -// ---------------------------------------------------------------------------- - -IMPLEMENT_DYNAMIC_CLASS(wxBitmap, wxGDIObject) -IMPLEMENT_DYNAMIC_CLASS(wxMask, wxObject) - -IMPLEMENT_DYNAMIC_CLASS(wxBitmapHandler, wxObject) - -// ============================================================================ -// implementation -// ============================================================================ - -// ---------------------------------------------------------------------------- -// helper functions -// ---------------------------------------------------------------------------- - -// decide whether we should create a DIB or a DDB for the given parameters -// -// NB: we always use DIBs under Windows CE as this is much simpler (even if -// also less efficient...) and we obviously can't use them if there is no -// DIB support compiled in at all -#ifdef __WXWINCE__ - static inline bool wxShouldCreateDIB(int, int, int, WXHDC) { return true; } - - #define ALWAYS_USE_DIB -#elif !wxUSE_WXDIB - // no sense in defining wxShouldCreateDIB() as we can't compile code - // executed if it is true, so we have to use #if's anyhow - #define NEVER_USE_DIB -#else // wxUSE_WXDIB && !__WXWINCE__ - static inline bool wxShouldCreateDIB(int w, int h, int d, WXHDC hdc) - { - // here is the logic: - // - // (a) if hdc is specified, the caller explicitly wants DDB - // (b) otherwise, create a DIB if depth >= 24 (we don't support 16bpp - // or less DIBs anyhow) - // (c) finally, create DIBs under Win9x even if the depth hasn't been - // explicitly specified but the current display depth is 24 or - // more and the image is "big", i.e. > 16Mb which is the - // theoretical limit for DDBs under Win9x - // - // consequences (all of which seem to make sense): - // - // (i) by default, DDBs are created (depth == -1 usually) - // (ii) DIBs can be created by explicitly specifying the depth - // (iii) using a DC always forces creating a DDB - return !hdc && - (d >= 24 || - (d == -1 && - wxDIB::GetLineSize(w, wxDisplayDepth())*h > 16*1024*1024)); - } - - #define SOMETIMES_USE_DIB -#endif // different DIB usage scenarious - -// ---------------------------------------------------------------------------- -// wxBitmapRefData -// ---------------------------------------------------------------------------- - -wxBitmapRefData::wxBitmapRefData() -{ -#ifdef __WXDEBUG__ - m_selectedInto = NULL; -#endif - m_bitmapMask = NULL; - - m_hBitmap = (WXHBITMAP) NULL; -#if wxUSE_WXDIB - m_dib = NULL; -#endif - - m_isDIB = - m_hasAlpha = false; -} - -wxBitmapRefData::wxBitmapRefData(const wxBitmapRefData& data) - : wxGDIImageRefData(data) -{ -#ifdef __WXDEBUG__ - m_selectedInto = NULL; -#endif - - // (deep) copy the mask if present - m_bitmapMask = NULL; - if (data.m_bitmapMask) - m_bitmapMask = new wxMask(*data.m_bitmapMask); - - // FIXME: we don't copy m_hBitmap currently but we should, see wxBitmap:: - // CloneRefData() - - wxASSERT_MSG( !data.m_isDIB, - _T("can't copy bitmap locked for raw access!") ); - m_isDIB = false; - - m_hasAlpha = data.m_hasAlpha; -} - -void wxBitmapRefData::Free() -{ - wxASSERT_MSG( !m_selectedInto, - wxT("deleting bitmap still selected into wxMemoryDC") ); - -#if wxUSE_WXDIB - wxASSERT_MSG( !m_dib, _T("forgot to call wxBitmap::UngetRawData()!") ); -#endif - - if ( m_hBitmap) - { - if ( !::DeleteObject((HBITMAP)m_hBitmap) ) - { - wxLogLastError(wxT("DeleteObject(hbitmap)")); - } - } - - delete m_bitmapMask; - m_bitmapMask = NULL; -} - -// ---------------------------------------------------------------------------- -// wxBitmap creation -// ---------------------------------------------------------------------------- - -wxGDIImageRefData *wxBitmap::CreateData() const -{ - return new wxBitmapRefData; -} - -wxObjectRefData *wxBitmap::CloneRefData(const wxObjectRefData *dataOrig) const -{ - const wxBitmapRefData * - data = wx_static_cast(const wxBitmapRefData *, dataOrig); - if ( !data ) - return NULL; - - // FIXME: this method is backwards, it should just create a new - // wxBitmapRefData using its copy ctor but instead it modifies this - // bitmap itself and then returns its m_refData -- which works, of - // course (except in !wxUSE_WXDIB), but is completely illogical - wxBitmap *self = wx_const_cast(wxBitmap *, this); - -#if wxUSE_WXDIB - // copy the other bitmap - if ( data->m_hBitmap ) - { - wxDIB dib((HBITMAP)(data->m_hBitmap)); - self->CopyFromDIB(dib); - } - else -#endif // wxUSE_WXDIB - { - // copy the bitmap data - self->m_refData = new wxBitmapRefData(*data); - } - - // copy also the mask - wxMask * const maskSrc = data->GetMask(); - if ( maskSrc ) - { - wxBitmapRefData *selfdata = wx_static_cast(wxBitmapRefData *, m_refData); - - selfdata->SetMask(new wxMask(*maskSrc)); - } - - return m_refData; -} - -#ifdef __WIN32__ - -bool wxBitmap::CopyFromIconOrCursor(const wxGDIImage& icon) -{ -#if !defined(__WXMICROWIN__) && !defined(__WXWINCE__) - // it may be either HICON or HCURSOR - HICON hicon = (HICON)icon.GetHandle(); - - ICONINFO iconInfo; - if ( !::GetIconInfo(hicon, &iconInfo) ) - { - wxLogLastError(wxT("GetIconInfo")); - - return false; - } - - wxBitmapRefData *refData = new wxBitmapRefData; - m_refData = refData; - - int w = icon.GetWidth(), - h = icon.GetHeight(); - - refData->m_width = w; - refData->m_height = h; - refData->m_depth = wxDisplayDepth(); - - refData->m_hBitmap = (WXHBITMAP)iconInfo.hbmColor; - -#if wxUSE_WXDIB - // If the icon is 32 bits per pixel then it may have alpha channel data, - // although there are some icons that are 32 bpp but have no alpha... So - // convert to a DIB and manually check the 4th byte for each pixel. - BITMAP bm; - if ( ::GetObject(iconInfo.hbmColor, sizeof(BITMAP), (LPVOID)&bm) - && bm.bmBitsPixel == 32) - { - wxDIB dib(iconInfo.hbmColor); - if (dib.IsOk()) - { - unsigned char* pixels = dib.GetData(); - for (int idx=0; idxm_hasAlpha = true; - break; - } - } - } - } -#endif - if ( !refData->m_hasAlpha ) - { - // the mask returned by GetIconInfo() is inverted compared to the usual - // wxWin convention - refData->SetMask(wxInvertMask(iconInfo.hbmMask, w, h)); - } - - // delete the old one now as we don't need it any more - ::DeleteObject(iconInfo.hbmMask); - - return true; -#else - wxUnusedVar(icon); - return false; -#endif -} - -#endif // Win32 - -bool wxBitmap::CopyFromCursor(const wxCursor& cursor) -{ - UnRef(); - - if ( !cursor.Ok() ) - return false; - - return CopyFromIconOrCursor(cursor); -} - -bool wxBitmap::CopyFromIcon(const wxIcon& icon) -{ - UnRef(); - - if ( !icon.Ok() ) - return false; - - return CopyFromIconOrCursor(icon); -} - -#ifndef NEVER_USE_DIB - -bool wxBitmap::CopyFromDIB(const wxDIB& dib) -{ - wxCHECK_MSG( dib.IsOk(), false, _T("invalid DIB in CopyFromDIB") ); - -#ifdef SOMETIMES_USE_DIB - HBITMAP hbitmap = dib.CreateDDB(); - if ( !hbitmap ) - return false; -#else // ALWAYS_USE_DIB - HBITMAP hbitmap = ((wxDIB &)dib).Detach(); // const_cast -#endif // SOMETIMES_USE_DIB/ALWAYS_USE_DIB - - UnRef(); - - wxBitmapRefData *refData = new wxBitmapRefData; - m_refData = refData; - - refData->m_width = dib.GetWidth(); - refData->m_height = dib.GetHeight(); - refData->m_depth = dib.GetDepth(); - - refData->m_hBitmap = (WXHBITMAP)hbitmap; - -#if wxUSE_PALETTE - wxPalette *palette = dib.CreatePalette(); - if ( palette ) - { - refData->m_bitmapPalette = *palette; - } - - delete palette; -#endif // wxUSE_PALETTE - - return true; -} - -#endif // NEVER_USE_DIB - -wxBitmap::~wxBitmap() -{ -} - -wxBitmap::wxBitmap(const char bits[], int width, int height, int depth) -{ -#ifndef __WXMICROWIN__ - wxBitmapRefData *refData = new wxBitmapRefData; - m_refData = refData; - - refData->m_width = width; - refData->m_height = height; - refData->m_depth = depth; - - char *data; - if ( depth == 1 ) - { - // we assume that it is in XBM format which is not quite the same as - // the format CreateBitmap() wants because the order of bytes in the - // line is reversed! - const size_t bytesPerLine = (width + 7) / 8; - const size_t padding = bytesPerLine % 2; - const size_t len = height * ( padding + bytesPerLine ); - data = (char *)malloc(len); - const char *src = bits; - char *dst = data; - - for ( int rows = 0; rows < height; rows++ ) - { - for ( size_t cols = 0; cols < bytesPerLine; cols++ ) - { - unsigned char val = *src++; - unsigned char reversed = 0; - - for ( int bits = 0; bits < 8; bits++) - { - reversed <<= 1; - reversed |= (unsigned char)(val & 0x01); - val >>= 1; - } - *dst++ = ~reversed; - } - - if ( padding ) - *dst++ = 0; - } - } - else - { - // bits should already be in Windows standard format - data = (char *)bits; // const_cast is harmless - } - - HBITMAP hbmp = ::CreateBitmap(width, height, 1, depth, data); - if ( !hbmp ) - { - wxLogLastError(wxT("CreateBitmap")); - } - - if ( data != bits ) - { - free(data); - } - - SetHBITMAP((WXHBITMAP)hbmp); -#endif -} - -wxBitmap::wxBitmap(int w, int h, int d) -{ - (void)Create(w, h, d); -} - -wxBitmap::wxBitmap(int w, int h, const wxDC& dc) -{ - (void)Create(w, h, dc); -} - -wxBitmap::wxBitmap(const void* data, long type, int width, int height, int depth) -{ - (void)Create(data, type, width, height, depth); -} - -wxBitmap::wxBitmap(const wxString& filename, wxBitmapType type) -{ - LoadFile(filename, (int)type); -} - -bool wxBitmap::Create(int width, int height, int depth) -{ - return DoCreate(width, height, depth, 0); -} - -bool wxBitmap::Create(int width, int height, const wxDC& dc) -{ - wxCHECK_MSG( dc.Ok(), false, _T("invalid HDC in wxBitmap::Create()") ); - - return DoCreate(width, height, -1, dc.GetHDC()); -} - -bool wxBitmap::DoCreate(int w, int h, int d, WXHDC hdc) -{ - UnRef(); - - m_refData = new wxBitmapRefData; - - GetBitmapData()->m_width = w; - GetBitmapData()->m_height = h; - - HBITMAP hbmp wxDUMMY_INITIALIZE(0); - -#ifndef NEVER_USE_DIB - if ( wxShouldCreateDIB(w, h, d, hdc) ) - { - if ( d == -1 ) - { - // create DIBs without alpha channel by default - d = 24; - } - - wxDIB dib(w, h, d); - if ( !dib.IsOk() ) - return false; - - // don't delete the DIB section in dib object dtor - hbmp = dib.Detach(); - - GetBitmapData()->m_isDIB = true; - GetBitmapData()->m_depth = d; - } - else // create a DDB -#endif // NEVER_USE_DIB - { -#ifndef ALWAYS_USE_DIB -#ifndef __WXMICROWIN__ - if ( d > 0 ) - { - hbmp = ::CreateBitmap(w, h, 1, d, NULL); - if ( !hbmp ) - { - wxLogLastError(wxT("CreateBitmap")); - } - - GetBitmapData()->m_depth = d; - } - else // d == 0, create bitmap compatible with the screen -#endif // !__WXMICROWIN__ - { - ScreenHDC dc; - hbmp = ::CreateCompatibleBitmap(dc, w, h); - if ( !hbmp ) - { - wxLogLastError(wxT("CreateCompatibleBitmap")); - } - - GetBitmapData()->m_depth = wxDisplayDepth(); - } -#endif // !ALWAYS_USE_DIB - } - - SetHBITMAP((WXHBITMAP)hbmp); - - return Ok(); -} - -#if wxUSE_IMAGE - -// ---------------------------------------------------------------------------- -// wxImage to/from conversions for Microwin -// ---------------------------------------------------------------------------- - -// Microwin versions are so different from normal ones that it really doesn't -// make sense to use #ifdefs inside the function bodies -#ifdef __WXMICROWIN__ - -bool wxBitmap::CreateFromImage(const wxImage& image, int depth, const wxDC& dc) -{ - // Set this to 1 to experiment with mask code, - // which currently doesn't work - #define USE_MASKS 0 - - m_refData = new wxBitmapRefData(); - - // Initial attempt at a simple-minded implementation. - // The bitmap will always be created at the screen depth, - // so the 'depth' argument is ignored. - - HDC hScreenDC = ::GetDC(NULL); - int screenDepth = ::GetDeviceCaps(hScreenDC, BITSPIXEL); - - HBITMAP hBitmap = ::CreateCompatibleBitmap(hScreenDC, image.GetWidth(), image.GetHeight()); - HBITMAP hMaskBitmap = NULL; - HBITMAP hOldMaskBitmap = NULL; - HDC hMaskDC = NULL; - unsigned char maskR = 0; - unsigned char maskG = 0; - unsigned char maskB = 0; - - // printf("Created bitmap %d\n", (int) hBitmap); - if (hBitmap == NULL) - { - ::ReleaseDC(NULL, hScreenDC); - return false; - } - HDC hMemDC = ::CreateCompatibleDC(hScreenDC); - - HBITMAP hOldBitmap = ::SelectObject(hMemDC, hBitmap); - ::ReleaseDC(NULL, hScreenDC); - - // created an mono-bitmap for the possible mask - bool hasMask = image.HasMask(); - - if ( hasMask ) - { -#if USE_MASKS - // FIXME: we should be able to pass bpp = 1, but - // GdBlit can't handle a different depth -#if 0 - hMaskBitmap = ::CreateBitmap( (WORD)image.GetWidth(), (WORD)image.GetHeight(), 1, 1, NULL ); -#else - hMaskBitmap = ::CreateCompatibleBitmap( hMemDC, (WORD)image.GetWidth(), (WORD)image.GetHeight()); -#endif - maskR = image.GetMaskRed(); - maskG = image.GetMaskGreen(); - maskB = image.GetMaskBlue(); - - if (!hMaskBitmap) - { - hasMask = false; - } - else - { - hScreenDC = ::GetDC(NULL); - hMaskDC = ::CreateCompatibleDC(hScreenDC); - ::ReleaseDC(NULL, hScreenDC); - - hOldMaskBitmap = ::SelectObject( hMaskDC, hMaskBitmap); - } -#else - hasMask = false; -#endif - } - - int i, j; - for (i = 0; i < image.GetWidth(); i++) - { - for (j = 0; j < image.GetHeight(); j++) - { - unsigned char red = image.GetRed(i, j); - unsigned char green = image.GetGreen(i, j); - unsigned char blue = image.GetBlue(i, j); - - ::SetPixel(hMemDC, i, j, PALETTERGB(red, green, blue)); - - if (hasMask) - { - // scan the bitmap for the transparent colour and set the corresponding - // pixels in the mask to BLACK and the rest to WHITE - if (maskR == red && maskG == green && maskB == blue) - ::SetPixel(hMaskDC, i, j, PALETTERGB(0, 0, 0)); - else - ::SetPixel(hMaskDC, i, j, PALETTERGB(255, 255, 255)); - } - } - } - - ::SelectObject(hMemDC, hOldBitmap); - ::DeleteDC(hMemDC); - if (hasMask) - { - ::SelectObject(hMaskDC, hOldMaskBitmap); - ::DeleteDC(hMaskDC); - - ((wxBitmapRefData*)m_refData)->SetMask(hMaskBitmap); - } - - SetWidth(image.GetWidth()); - SetHeight(image.GetHeight()); - SetDepth(screenDepth); - SetHBITMAP( (WXHBITMAP) hBitmap ); - -#if wxUSE_PALETTE - // Copy the palette from the source image - SetPalette(image.GetPalette()); -#endif // wxUSE_PALETTE - - return true; -} - -wxImage wxBitmap::ConvertToImage() const -{ - // Initial attempt at a simple-minded implementation. - // The bitmap will always be created at the screen depth, - // so the 'depth' argument is ignored. - // TODO: transparency (create a mask image) - - if (!Ok()) - { - wxFAIL_MSG( wxT("bitmap is invalid") ); - return wxNullImage; - } - - wxImage image; - - wxCHECK_MSG( Ok(), wxNullImage, wxT("invalid bitmap") ); - - // create an wxImage object - int width = GetWidth(); - int height = GetHeight(); - image.Create( width, height ); - unsigned char *data = image.GetData(); - if( !data ) - { - wxFAIL_MSG( wxT("could not allocate data for image") ); - return wxNullImage; - } - - HDC hScreenDC = ::GetDC(NULL); - - HDC hMemDC = ::CreateCompatibleDC(hScreenDC); - ::ReleaseDC(NULL, hScreenDC); - - HBITMAP hBitmap = (HBITMAP) GetHBITMAP(); - - HBITMAP hOldBitmap = ::SelectObject(hMemDC, hBitmap); - - int i, j; - for (i = 0; i < GetWidth(); i++) - { - for (j = 0; j < GetHeight(); j++) - { - COLORREF color = ::GetPixel(hMemDC, i, j); - unsigned char red = GetRValue(color); - unsigned char green = GetGValue(color); - unsigned char blue = GetBValue(color); - - image.SetRGB(i, j, red, green, blue); - } - } - - ::SelectObject(hMemDC, hOldBitmap); - ::DeleteDC(hMemDC); - -#if wxUSE_PALETTE - // Copy the palette from the source image - if (GetPalette()) - image.SetPalette(* GetPalette()); -#endif // wxUSE_PALETTE - - return image; -} - -#endif // __WXMICROWIN__ - -// ---------------------------------------------------------------------------- -// wxImage to/from conversions -// ---------------------------------------------------------------------------- - -bool wxBitmap::CreateFromImage(const wxImage& image, int depth) -{ - return CreateFromImage(image, depth, 0); -} - -bool wxBitmap::CreateFromImage(const wxImage& image, const wxDC& dc) -{ - wxCHECK_MSG( dc.Ok(), false, - _T("invalid HDC in wxBitmap::CreateFromImage()") ); - - return CreateFromImage(image, -1, dc.GetHDC()); -} - -#if wxUSE_WXDIB - -bool wxBitmap::CreateFromImage(const wxImage& image, int depth, WXHDC hdc) -{ - wxCHECK_MSG( image.Ok(), false, wxT("invalid image") ); - - UnRef(); - - // first convert the image to DIB - const int h = image.GetHeight(); - const int w = image.GetWidth(); - - wxDIB dib(image); - if ( !dib.IsOk() ) - return false; - - if ( depth == -1 ) - depth = dib.GetDepth(); // Get depth from image if none specified - - // store the bitmap parameters - wxBitmapRefData *refData = new wxBitmapRefData; - refData->m_width = w; - refData->m_height = h; - refData->m_hasAlpha = image.HasAlpha(); - - m_refData = refData; - - - // next either store DIB as is or create a DDB from it - HBITMAP hbitmap wxDUMMY_INITIALIZE(0); - - // are we going to use DIB? - // - // NB: DDBs don't support alpha so if we have alpha channel we must use DIB - if ( image.HasAlpha() || wxShouldCreateDIB(w, h, depth, hdc) ) - { - // don't delete the DIB section in dib object dtor - hbitmap = dib.Detach(); - - refData->m_isDIB = true; - refData->m_depth = depth; - } -#ifndef ALWAYS_USE_DIB - else // we need to convert DIB to DDB - { - hbitmap = dib.CreateDDB((HDC)hdc); - - refData->m_depth = depth; - } -#endif // !ALWAYS_USE_DIB - - // validate this object - SetHBITMAP((WXHBITMAP)hbitmap); - - // finally also set the mask if we have one - if ( image.HasMask() ) - { - const size_t len = 2*((w+15)/16); - BYTE *src = image.GetData(); - BYTE *data = new BYTE[h*len]; - memset(data, 0, h*len); - BYTE r = image.GetMaskRed(), - g = image.GetMaskGreen(), - b = image.GetMaskBlue(); - BYTE *dst = data; - for ( int y = 0; y < h; y++, dst += len ) - { - BYTE *dstLine = dst; - BYTE mask = 0x80; - for ( int x = 0; x < w; x++, src += 3 ) - { - if (src[0] != r || src[1] != g || src[2] != b) - *dstLine |= mask; - - if ( (mask >>= 1) == 0 ) - { - dstLine++; - mask = 0x80; - } - } - } - - hbitmap = ::CreateBitmap(w, h, 1, 1, data); - if ( !hbitmap ) - { - wxLogLastError(_T("CreateBitmap(mask)")); - } - else - { - SetMask(new wxMask((WXHBITMAP)hbitmap)); - } - - delete[] data; - } - - return true; -} - -wxImage wxBitmap::ConvertToImage() const -{ - // convert DDB to DIB - wxDIB dib(*this); - - if ( !dib.IsOk() ) - { - return wxNullImage; - } - - // and then DIB to our wxImage - wxImage image = dib.ConvertToImage(); - if ( !image.Ok() ) - { - return wxNullImage; - } - - // now do the same for the mask, if we have any - HBITMAP hbmpMask = GetMask() ? (HBITMAP) GetMask()->GetMaskBitmap() : NULL; - if ( hbmpMask ) - { - wxDIB dibMask(hbmpMask); - if ( dibMask.IsOk() ) - { - // TODO: use wxRawBitmap to iterate over DIB - - // we hard code the mask colour for now but we could also make an - // effort (and waste time) to choose a colour not present in the - // image already to avoid having to fudge the pixels below -- - // whether it's worth to do it is unclear however - static const int MASK_RED = 1; - static const int MASK_GREEN = 2; - static const int MASK_BLUE = 3; - static const int MASK_BLUE_REPLACEMENT = 2; - - const int h = dibMask.GetHeight(); - const int w = dibMask.GetWidth(); - const int bpp = dibMask.GetDepth(); - const int maskBytesPerPixel = bpp >> 3; - const int maskBytesPerLine = wxDIB::GetLineSize(w, bpp); - unsigned char *data = image.GetData(); - - // remember that DIBs are stored in bottom to top order - unsigned char * - maskLineStart = dibMask.GetData() + ((h - 1) * maskBytesPerLine); - - for ( int y = 0; y < h; y++, maskLineStart -= maskBytesPerLine ) - { - // traverse one mask DIB line - unsigned char *mask = maskLineStart; - for ( int x = 0; x < w; x++, mask += maskBytesPerPixel ) - { - // should this pixel be transparent? - if ( *mask ) - { - // no, check that it isn't transparent by accident - if ( (data[0] == MASK_RED) && - (data[1] == MASK_GREEN) && - (data[2] == MASK_BLUE) ) - { - // we have to fudge the colour a bit to prevent - // this pixel from appearing transparent - data[2] = MASK_BLUE_REPLACEMENT; - } - - data += 3; - } - else // yes, transparent pixel - { - *data++ = MASK_RED; - *data++ = MASK_GREEN; - *data++ = MASK_BLUE; - } - } - } - - image.SetMaskColour(MASK_RED, MASK_GREEN, MASK_BLUE); - } - } - - return image; -} - -#else // !wxUSE_WXDIB - -bool -wxBitmap::CreateFromImage(const wxImage& WXUNUSED(image), - int WXUNUSED(depth), - WXHDC WXUNUSED(hdc)) -{ - return false; -} - -wxImage wxBitmap::ConvertToImage() const -{ - return wxImage(); -} - -#endif // wxUSE_WXDIB/!wxUSE_WXDIB - -#endif // wxUSE_IMAGE - -// ---------------------------------------------------------------------------- -// loading and saving bitmaps -// ---------------------------------------------------------------------------- - -bool wxBitmap::LoadFile(const wxString& filename, long type) -{ - UnRef(); - - wxBitmapHandler *handler = wxDynamicCast(FindHandler(type), wxBitmapHandler); - - if ( handler ) - { - m_refData = new wxBitmapRefData; - - return handler->LoadFile(this, filename, type, -1, -1); - } -#if wxUSE_IMAGE && wxUSE_WXDIB - else // no bitmap handler found - { - wxImage image; - if ( image.LoadFile( filename, type ) && image.Ok() ) - { - *this = wxBitmap(image); - - return true; - } - } -#endif // wxUSE_IMAGE - - return false; -} - -bool wxBitmap::Create(const void* data, long type, int width, int height, int depth) -{ - UnRef(); - - wxBitmapHandler *handler = wxDynamicCast(FindHandler(type), wxBitmapHandler); - - if ( !handler ) - { - wxLogDebug(wxT("Failed to create bitmap: no bitmap handler for type %ld defined."), type); - - return false; - } - - m_refData = new wxBitmapRefData; - - return handler->Create(this, data, type, width, height, depth); -} - -bool wxBitmap::SaveFile(const wxString& filename, - int type, - const wxPalette *palette) -{ - wxBitmapHandler *handler = wxDynamicCast(FindHandler(type), wxBitmapHandler); - - if ( handler ) - { - return handler->SaveFile(this, filename, type, palette); - } -#if wxUSE_IMAGE && wxUSE_WXDIB - else // no bitmap handler found - { - // FIXME what about palette? shouldn't we use it? - wxImage image = ConvertToImage(); - if ( image.Ok() ) - { - return image.SaveFile(filename, type); - } - } -#endif // wxUSE_IMAGE - - return false; -} - -// ---------------------------------------------------------------------------- -// sub bitmap extraction -// ---------------------------------------------------------------------------- -wxBitmap wxBitmap::GetSubBitmap( const wxRect& rect ) const -{ - MemoryHDC dcSrc; - SelectInHDC selectSrc(dcSrc, GetHbitmap()); - return GetSubBitmapOfHDC( rect, (WXHDC)dcSrc ); -} - -wxBitmap wxBitmap::GetSubBitmapOfHDC( const wxRect& rect, WXHDC hdc ) const -{ - wxCHECK_MSG( Ok() && - (rect.x >= 0) && (rect.y >= 0) && - (rect.x+rect.width <= GetWidth()) && - (rect.y+rect.height <= GetHeight()), - wxNullBitmap, wxT("Invalid bitmap or bitmap region") ); - - wxBitmap ret( rect.width, rect.height, GetDepth() ); - wxASSERT_MSG( ret.Ok(), wxT("GetSubBitmap error") ); - -#ifndef __WXMICROWIN__ - // handle alpha channel, if any - if (HasAlpha()) - ret.UseAlpha(); - - // copy bitmap data - MemoryHDC dcSrc, - dcDst; - - { - SelectInHDC selectDst(dcDst, GetHbitmapOf(ret)); - - if ( !selectDst ) - { - wxLogLastError(_T("SelectObject(destBitmap)")); - } - - if ( !::BitBlt(dcDst, 0, 0, rect.width, rect.height, - (HDC)hdc, rect.x, rect.y, SRCCOPY) ) - { - wxLogLastError(_T("BitBlt")); - } - } - - // copy mask if there is one - if ( GetMask() ) - { - HBITMAP hbmpMask = ::CreateBitmap(rect.width, rect.height, 1, 1, 0); - - SelectInHDC selectSrc(dcSrc, (HBITMAP) GetMask()->GetMaskBitmap()), - selectDst(dcDst, hbmpMask); - - if ( !::BitBlt(dcDst, 0, 0, rect.width, rect.height, - dcSrc, rect.x, rect.y, SRCCOPY) ) - { - wxLogLastError(_T("BitBlt")); - } - - wxMask *mask = new wxMask((WXHBITMAP) hbmpMask); - ret.SetMask(mask); - } -#endif // !__WXMICROWIN__ - - return ret; -} - -// ---------------------------------------------------------------------------- -// wxBitmap accessors -// ---------------------------------------------------------------------------- - -#if wxUSE_PALETTE -wxPalette* wxBitmap::GetPalette() const -{ - return GetBitmapData() ? &GetBitmapData()->m_bitmapPalette - : (wxPalette *) NULL; -} -#endif - -wxMask *wxBitmap::GetMask() const -{ - return GetBitmapData() ? GetBitmapData()->GetMask() : (wxMask *) NULL; -} - -wxBitmap wxBitmap::GetMaskBitmap() const -{ - wxBitmap bmp; - wxMask *mask = GetMask(); - if ( mask ) - bmp.SetHBITMAP(mask->GetMaskBitmap()); - return bmp; -} - -#ifdef __WXDEBUG__ - -wxDC *wxBitmap::GetSelectedInto() const -{ - return GetBitmapData() ? GetBitmapData()->m_selectedInto : (wxDC *) NULL; -} - -#endif - -#if WXWIN_COMPATIBILITY_2_4 - -int wxBitmap::GetQuality() const -{ - return 0; -} - -#endif // WXWIN_COMPATIBILITY_2_4 - -void wxBitmap::UseAlpha() -{ - if ( GetBitmapData() ) - GetBitmapData()->m_hasAlpha = true; -} - -bool wxBitmap::HasAlpha() const -{ - return GetBitmapData() && GetBitmapData()->m_hasAlpha; -} - -// ---------------------------------------------------------------------------- -// wxBitmap setters -// ---------------------------------------------------------------------------- - -#ifdef __WXDEBUG__ - -void wxBitmap::SetSelectedInto(wxDC *dc) -{ - if ( GetBitmapData() ) - GetBitmapData()->m_selectedInto = dc; -} - -#endif - -#if wxUSE_PALETTE - -void wxBitmap::SetPalette(const wxPalette& palette) -{ - AllocExclusive(); - - GetBitmapData()->m_bitmapPalette = palette; -} - -#endif // wxUSE_PALETTE - -void wxBitmap::SetMask(wxMask *mask) -{ - AllocExclusive(); - - GetBitmapData()->SetMask(mask); -} - -#if WXWIN_COMPATIBILITY_2_4 - -void wxBitmap::SetQuality(int WXUNUSED(quality)) -{ -} - -#endif // WXWIN_COMPATIBILITY_2_4 - -// ---------------------------------------------------------------------------- -// raw bitmap access support -// ---------------------------------------------------------------------------- - -#ifdef wxHAVE_RAW_BITMAP -void *wxBitmap::GetRawData(wxPixelDataBase& data, int bpp) -{ -#if wxUSE_WXDIB - if ( !Ok() ) - { - // no bitmap, no data (raw or otherwise) - return NULL; - } - - // if we're already a DIB we can access our data directly, but if not we - // need to convert this DDB to a DIB section and use it for raw access and - // then convert it back - HBITMAP hDIB; - if ( !GetBitmapData()->m_isDIB ) - { - wxCHECK_MSG( !GetBitmapData()->m_dib, NULL, - _T("GetRawData() may be called only once") ); - - wxDIB *dib = new wxDIB(*this); - if ( !dib->IsOk() ) - { - delete dib; - - return NULL; - } - - // we'll free it in UngetRawData() - GetBitmapData()->m_dib = dib; - - hDIB = dib->GetHandle(); - } - else // we're a DIB - { - hDIB = GetHbitmap(); - } - - DIBSECTION ds; - if ( ::GetObject(hDIB, sizeof(ds), &ds) != sizeof(DIBSECTION) ) - { - wxFAIL_MSG( _T("failed to get DIBSECTION from a DIB?") ); - - return NULL; - } - - // check that the bitmap is in correct format - if ( ds.dsBm.bmBitsPixel != bpp ) - { - wxFAIL_MSG( _T("incorrect bitmap type in wxBitmap::GetRawData()") ); - - return NULL; - } - - // ok, store the relevant info in wxPixelDataBase - const LONG h = ds.dsBm.bmHeight; - - data.m_width = ds.dsBm.bmWidth; - data.m_height = h; - - // remember that DIBs are stored in top to bottom order! - // (We can't just use ds.dsBm.bmWidthBytes here, because it isn't always a - // multiple of 2, as required by the documentation. So we use the official - // formula, which we already use elsewhere.) - const LONG bytesPerRow = - wxDIB::GetLineSize(ds.dsBm.bmWidth, ds.dsBm.bmBitsPixel); - data.m_stride = -bytesPerRow; - - char *bits = (char *)ds.dsBm.bmBits; - if ( h > 1 ) - { - bits += (h - 1)*bytesPerRow; - } - - return bits; -#else - return NULL; -#endif -} - -void wxBitmap::UngetRawData(wxPixelDataBase& dataBase) -{ -#if wxUSE_WXDIB - if ( !Ok() ) - return; - - if ( !&dataBase ) - { - // invalid data, don't crash -- but don't assert neither as we're - // called automatically from wxPixelDataBase dtor and so there is no - // way to prevent this from happening - return; - } - - // if we're a DDB we need to convert DIB back to DDB now to make the - // changes made via raw bitmap access effective - if ( !GetBitmapData()->m_isDIB ) - { - wxDIB *dib = GetBitmapData()->m_dib; - GetBitmapData()->m_dib = NULL; - - // TODO: convert - - delete dib; - } -#endif // wxUSE_WXDIB -} -#endif // #ifdef wxHAVE_RAW_BITMAP - -// ---------------------------------------------------------------------------- -// wxMask -// ---------------------------------------------------------------------------- - -wxMask::wxMask() -{ - m_maskBitmap = 0; -} - -// Copy constructor -wxMask::wxMask(const wxMask &mask) - : wxObject() -{ - BITMAP bmp; - - HDC srcDC = CreateCompatibleDC(0); - HDC destDC = CreateCompatibleDC(0); - - // GetBitmapDimensionEx won't work if SetBitmapDimensionEx wasn't used - // so we'll use GetObject() API here: - if (::GetObject((HGDIOBJ)mask.m_maskBitmap, sizeof(bmp), &bmp) == 0) - { - wxFAIL_MSG(wxT("Cannot retrieve the dimensions of the wxMask to copy")); - return; - } - - // create our HBITMAP - int w = bmp.bmWidth, h = bmp.bmHeight; - m_maskBitmap = (WXHBITMAP)CreateCompatibleBitmap(srcDC, w, h); - - // copy the mask's HBITMAP into our HBITMAP - SelectObject(srcDC, (HBITMAP) mask.m_maskBitmap); - SelectObject(destDC, (HBITMAP) m_maskBitmap); - - BitBlt(destDC, 0, 0, w, h, srcDC, 0, 0, SRCCOPY); - - SelectObject(srcDC, 0); - DeleteDC(srcDC); - SelectObject(destDC, 0); - DeleteDC(destDC); -} - -// Construct a mask from a bitmap and a colour indicating -// the transparent area -wxMask::wxMask(const wxBitmap& bitmap, const wxColour& colour) -{ - m_maskBitmap = 0; - Create(bitmap, colour); -} - -// Construct a mask from a bitmap and a palette index indicating -// the transparent area -wxMask::wxMask(const wxBitmap& bitmap, int paletteIndex) -{ - m_maskBitmap = 0; - Create(bitmap, paletteIndex); -} - -// Construct a mask from a mono bitmap (copies the bitmap). -wxMask::wxMask(const wxBitmap& bitmap) -{ - m_maskBitmap = 0; - Create(bitmap); -} - -wxMask::~wxMask() -{ - if ( m_maskBitmap ) - ::DeleteObject((HBITMAP) m_maskBitmap); -} - -// Create a mask from a mono bitmap (copies the bitmap). -bool wxMask::Create(const wxBitmap& bitmap) -{ -#ifndef __WXMICROWIN__ - wxCHECK_MSG( bitmap.Ok() && bitmap.GetDepth() == 1, false, - _T("can't create mask from invalid or not monochrome bitmap") ); - - if ( m_maskBitmap ) - { - ::DeleteObject((HBITMAP) m_maskBitmap); - m_maskBitmap = 0; - } - - m_maskBitmap = (WXHBITMAP) CreateBitmap( - bitmap.GetWidth(), - bitmap.GetHeight(), - 1, 1, 0 - ); - HDC srcDC = CreateCompatibleDC(0); - SelectObject(srcDC, (HBITMAP) bitmap.GetHBITMAP()); - HDC destDC = CreateCompatibleDC(0); - SelectObject(destDC, (HBITMAP) m_maskBitmap); - BitBlt(destDC, 0, 0, bitmap.GetWidth(), bitmap.GetHeight(), srcDC, 0, 0, SRCCOPY); - SelectObject(srcDC, 0); - DeleteDC(srcDC); - SelectObject(destDC, 0); - DeleteDC(destDC); - return true; -#else - wxUnusedVar(bitmap); - return false; -#endif -} - -// Create a mask from a bitmap and a palette index indicating -// the transparent area -bool wxMask::Create(const wxBitmap& bitmap, int paletteIndex) -{ - if ( m_maskBitmap ) - { - ::DeleteObject((HBITMAP) m_maskBitmap); - m_maskBitmap = 0; - } - -#if wxUSE_PALETTE - if (bitmap.Ok() && bitmap.GetPalette()->Ok()) - { - unsigned char red, green, blue; - if (bitmap.GetPalette()->GetRGB(paletteIndex, &red, &green, &blue)) - { - wxColour transparentColour(red, green, blue); - return Create(bitmap, transparentColour); - } - } -#endif // wxUSE_PALETTE - - return false; -} - -// Create a mask from a bitmap and a colour indicating -// the transparent area -bool wxMask::Create(const wxBitmap& bitmap, const wxColour& colour) -{ -#ifndef __WXMICROWIN__ - wxCHECK_MSG( bitmap.Ok(), false, _T("invalid bitmap in wxMask::Create") ); - - if ( m_maskBitmap ) - { - ::DeleteObject((HBITMAP) m_maskBitmap); - m_maskBitmap = 0; - } - - int width = bitmap.GetWidth(), - height = bitmap.GetHeight(); - - // scan the bitmap for the transparent colour and set the corresponding - // pixels in the mask to BLACK and the rest to WHITE - COLORREF maskColour = wxColourToPalRGB(colour); - m_maskBitmap = (WXHBITMAP)::CreateBitmap(width, height, 1, 1, 0); - - HDC srcDC = ::CreateCompatibleDC(NULL); - HDC destDC = ::CreateCompatibleDC(NULL); - if ( !srcDC || !destDC ) - { - wxLogLastError(wxT("CreateCompatibleDC")); - } - - bool ok = true; - - // SelectObject() will fail - wxASSERT_MSG( !bitmap.GetSelectedInto(), - _T("bitmap can't be selected in another DC") ); - - HGDIOBJ hbmpSrcOld = ::SelectObject(srcDC, GetHbitmapOf(bitmap)); - if ( !hbmpSrcOld ) - { - wxLogLastError(wxT("SelectObject")); - - ok = false; - } - - HGDIOBJ hbmpDstOld = ::SelectObject(destDC, (HBITMAP)m_maskBitmap); - if ( !hbmpDstOld ) - { - wxLogLastError(wxT("SelectObject")); - - ok = false; - } - - if ( ok ) - { - // this will create a monochrome bitmap with 0 points for the pixels - // which have the same value as the background colour and 1 for the - // others - ::SetBkColor(srcDC, maskColour); - ::BitBlt(destDC, 0, 0, width, height, srcDC, 0, 0, NOTSRCCOPY); - } - - ::SelectObject(srcDC, hbmpSrcOld); - ::DeleteDC(srcDC); - ::SelectObject(destDC, hbmpDstOld); - ::DeleteDC(destDC); - - return ok; -#else // __WXMICROWIN__ - wxUnusedVar(bitmap); - wxUnusedVar(colour); - return false; -#endif // __WXMICROWIN__/!__WXMICROWIN__ -} - -// ---------------------------------------------------------------------------- -// wxBitmapHandler -// ---------------------------------------------------------------------------- - -bool wxBitmapHandler::Create(wxGDIImage *image, - const void* data, - long flags, - int width, int height, int depth) -{ - wxBitmap *bitmap = wxDynamicCast(image, wxBitmap); - - return bitmap && Create(bitmap, data, flags, width, height, depth); -} - -bool wxBitmapHandler::Load(wxGDIImage *image, - const wxString& name, - long flags, - int width, int height) -{ - wxBitmap *bitmap = wxDynamicCast(image, wxBitmap); - - return bitmap && LoadFile(bitmap, name, flags, width, height); -} - -bool wxBitmapHandler::Save(wxGDIImage *image, - const wxString& name, - int type) -{ - wxBitmap *bitmap = wxDynamicCast(image, wxBitmap); - - return bitmap && SaveFile(bitmap, name, type); -} - -bool wxBitmapHandler::Create(wxBitmap *WXUNUSED(bitmap), - const void* WXUNUSED(data), - long WXUNUSED(type), - int WXUNUSED(width), - int WXUNUSED(height), - int WXUNUSED(depth)) -{ - return false; -} - -bool wxBitmapHandler::LoadFile(wxBitmap *WXUNUSED(bitmap), - const wxString& WXUNUSED(name), - long WXUNUSED(type), - int WXUNUSED(desiredWidth), - int WXUNUSED(desiredHeight)) -{ - return false; -} - -bool wxBitmapHandler::SaveFile(wxBitmap *WXUNUSED(bitmap), - const wxString& WXUNUSED(name), - int WXUNUSED(type), - const wxPalette *WXUNUSED(palette)) -{ - return false; -} - -// ---------------------------------------------------------------------------- -// DIB functions -// ---------------------------------------------------------------------------- - -#ifndef __WXMICROWIN__ -bool wxCreateDIB(long xSize, long ySize, long bitsPerPixel, - HPALETTE hPal, LPBITMAPINFO* lpDIBHeader) -{ - unsigned long i, headerSize; - - // Allocate space for a DIB header - headerSize = (sizeof(BITMAPINFOHEADER) + (256 * sizeof(PALETTEENTRY))); - LPBITMAPINFO lpDIBheader = (BITMAPINFO *) malloc(headerSize); - LPPALETTEENTRY lpPe = (PALETTEENTRY *)((BYTE*)lpDIBheader + sizeof(BITMAPINFOHEADER)); - - GetPaletteEntries(hPal, 0, 256, lpPe); - - memset(lpDIBheader, 0x00, sizeof(BITMAPINFOHEADER)); - - // Fill in the static parts of the DIB header - lpDIBheader->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); - lpDIBheader->bmiHeader.biWidth = xSize; - lpDIBheader->bmiHeader.biHeight = ySize; - lpDIBheader->bmiHeader.biPlanes = 1; - - // this value must be 1, 4, 8 or 24 so PixelDepth can only be - lpDIBheader->bmiHeader.biBitCount = (WORD)(bitsPerPixel); - lpDIBheader->bmiHeader.biCompression = BI_RGB; - lpDIBheader->bmiHeader.biSizeImage = (xSize * abs((int)ySize) * bitsPerPixel) >> 3; - lpDIBheader->bmiHeader.biClrUsed = 256; - - - // Initialize the DIB palette - for (i = 0; i < 256; i++) { - lpDIBheader->bmiColors[i].rgbReserved = lpPe[i].peFlags; - lpDIBheader->bmiColors[i].rgbRed = lpPe[i].peRed; - lpDIBheader->bmiColors[i].rgbGreen = lpPe[i].peGreen; - lpDIBheader->bmiColors[i].rgbBlue = lpPe[i].peBlue; - } - - *lpDIBHeader = lpDIBheader; - - return true; -} - -void wxFreeDIB(LPBITMAPINFO lpDIBHeader) -{ - free(lpDIBHeader); -} -#endif - -// ---------------------------------------------------------------------------- -// global helper functions implemented here -// ---------------------------------------------------------------------------- - -// helper of wxBitmapToHICON/HCURSOR -static -HICON wxBitmapToIconOrCursor(const wxBitmap& bmp, - bool iconWanted, - int hotSpotX, - int hotSpotY) -{ - if ( !bmp.Ok() ) - { - // we can't create an icon/cursor form nothing - return 0; - } - - if ( bmp.HasAlpha() ) - { - // Create an empty mask bitmap. - // it doesn't seem to work if we mess with the mask at all. - HBITMAP hMonoBitmap = CreateBitmap(bmp.GetWidth(),bmp.GetHeight(),1,1,NULL); - - ICONINFO iconInfo; - wxZeroMemory(iconInfo); - iconInfo.fIcon = iconWanted; // do we want an icon or a cursor? - if ( !iconWanted ) - { - iconInfo.xHotspot = hotSpotX; - iconInfo.yHotspot = hotSpotY; - } - - iconInfo.hbmMask = hMonoBitmap; - iconInfo.hbmColor = GetHbitmapOf(bmp); - - HICON hicon = ::CreateIconIndirect(&iconInfo); - - ::DeleteObject(hMonoBitmap); - - return hicon; - } - - wxMask* mask = bmp.GetMask(); - - if ( !mask ) - { - // we must have a mask for an icon, so even if it's probably incorrect, - // do create it (grey is the "standard" transparent colour) - mask = new wxMask(bmp, *wxLIGHT_GREY); - } - - ICONINFO iconInfo; - wxZeroMemory(iconInfo); - iconInfo.fIcon = iconWanted; // do we want an icon or a cursor? - if ( !iconWanted ) - { - iconInfo.xHotspot = hotSpotX; - iconInfo.yHotspot = hotSpotY; - } - - iconInfo.hbmMask = wxInvertMask((HBITMAP)mask->GetMaskBitmap()); - iconInfo.hbmColor = GetHbitmapOf(bmp); - - // black out the transparent area to preserve background colour, because - // Windows blits the original bitmap using SRCINVERT (XOR) after applying - // the mask to the dest rect. - { - MemoryHDC dcSrc, dcDst; - SelectInHDC selectMask(dcSrc, (HBITMAP)mask->GetMaskBitmap()), - selectBitmap(dcDst, iconInfo.hbmColor); - - if ( !::BitBlt(dcDst, 0, 0, bmp.GetWidth(), bmp.GetHeight(), - dcSrc, 0, 0, SRCAND) ) - { - wxLogLastError(_T("BitBlt")); - } - } - - HICON hicon = ::CreateIconIndirect(&iconInfo); - - if ( !bmp.GetMask() && !bmp.HasAlpha() ) - { - // we created the mask, now delete it - delete mask; - } - - // delete the inverted mask bitmap we created as well - ::DeleteObject(iconInfo.hbmMask); - - return hicon; -} - -HICON wxBitmapToHICON(const wxBitmap& bmp) -{ - return wxBitmapToIconOrCursor(bmp, true, 0, 0); -} - -HCURSOR wxBitmapToHCURSOR(const wxBitmap& bmp, int hotSpotX, int hotSpotY) -{ - return (HCURSOR)wxBitmapToIconOrCursor(bmp, false, hotSpotX, hotSpotY); -} - -HBITMAP wxInvertMask(HBITMAP hbmpMask, int w, int h) -{ -#ifndef __WXMICROWIN__ - wxCHECK_MSG( hbmpMask, 0, _T("invalid bitmap in wxInvertMask") ); - - // get width/height from the bitmap if not given - if ( !w || !h ) - { - BITMAP bm; - ::GetObject(hbmpMask, sizeof(BITMAP), (LPVOID)&bm); - w = bm.bmWidth; - h = bm.bmHeight; - } - - HDC hdcSrc = ::CreateCompatibleDC(NULL); - HDC hdcDst = ::CreateCompatibleDC(NULL); - if ( !hdcSrc || !hdcDst ) - { - wxLogLastError(wxT("CreateCompatibleDC")); - } - - HBITMAP hbmpInvMask = ::CreateBitmap(w, h, 1, 1, 0); - if ( !hbmpInvMask ) - { - wxLogLastError(wxT("CreateBitmap")); - } - - HGDIOBJ srcTmp = ::SelectObject(hdcSrc, hbmpMask); - HGDIOBJ dstTmp = ::SelectObject(hdcDst, hbmpInvMask); - if ( !::BitBlt(hdcDst, 0, 0, w, h, - hdcSrc, 0, 0, - NOTSRCCOPY) ) - { - wxLogLastError(wxT("BitBlt")); - } - - // Deselect objects - SelectObject(hdcSrc,srcTmp); - SelectObject(hdcDst,dstTmp); - - ::DeleteDC(hdcSrc); - ::DeleteDC(hdcDst); - - return hbmpInvMask; -#else - return 0; -#endif -} +//////////////////////////////////////////////////////////////////////////// +// Name: src/msw/bitmap.cpp +// Purpose: wxBitmap +// Author: Julian Smart +// Modified by: +// Created: 04/01/98 +// RCS-ID: $Id: bitmap.cpp 48236 2007-08-20 23:43:32Z KO $ +// Copyright: (c) Julian Smart +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#include "wx/bitmap.h" + +#ifndef WX_PRECOMP + #include + + #include "wx/list.h" + #include "wx/utils.h" + #include "wx/app.h" + #include "wx/palette.h" + #include "wx/dcmemory.h" + #include "wx/icon.h" + #include "wx/log.h" + #include "wx/image.h" +#endif + +#include "wx/msw/private.h" + +#if wxUSE_WXDIB + #include "wx/msw/dib.h" +#endif + +#ifdef wxHAVE_RAW_BITMAP + #include "wx/rawbmp.h" +#endif + +// missing from mingw32 header +#ifndef CLR_INVALID + #define CLR_INVALID ((COLORREF)-1) +#endif // no CLR_INVALID + +// ---------------------------------------------------------------------------- +// Bitmap data +// ---------------------------------------------------------------------------- + +class WXDLLEXPORT wxBitmapRefData : public wxGDIImageRefData +{ +public: + wxBitmapRefData(); + wxBitmapRefData(const wxBitmapRefData& data); + virtual ~wxBitmapRefData() { Free(); } + + virtual void Free(); + + // set the mask object to use as the mask, we take ownership of it + void SetMask(wxMask *mask) + { + delete m_bitmapMask; + m_bitmapMask = mask; + } + + // set the HBITMAP to use as the mask + void SetMask(HBITMAP hbmpMask) + { + SetMask(new wxMask((WXHBITMAP)hbmpMask)); + } + + // return the mask + wxMask *GetMask() const { return m_bitmapMask; } + +public: +#if wxUSE_PALETTE + wxPalette m_bitmapPalette; +#endif // wxUSE_PALETTE + + // MSW-specific + // ------------ + +#ifdef __WXDEBUG__ + // this field is solely for error checking: we detect selecting a bitmap + // into more than one DC at once or deleting a bitmap still selected into a + // DC (both are serious programming errors under Windows) + wxDC *m_selectedInto; +#endif // __WXDEBUG__ + +#if wxUSE_WXDIB + // when GetRawData() is called for a DDB we need to convert it to a DIB + // first to be able to provide direct access to it and we cache that DIB + // here and convert it back to DDB when UngetRawData() is called + wxDIB *m_dib; +#endif + + // true if we have alpha transparency info and can be drawn using + // AlphaBlend() + bool m_hasAlpha; + + // true if our HBITMAP is a DIB section, false if it is a DDB + bool m_isDIB; + +private: + // optional mask for transparent drawing + wxMask *m_bitmapMask; + + + // not implemented + wxBitmapRefData& operator=(const wxBitmapRefData&); +}; + +// ---------------------------------------------------------------------------- +// macros +// ---------------------------------------------------------------------------- + +IMPLEMENT_DYNAMIC_CLASS(wxBitmap, wxGDIObject) +IMPLEMENT_DYNAMIC_CLASS(wxMask, wxObject) + +IMPLEMENT_DYNAMIC_CLASS(wxBitmapHandler, wxObject) + +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// helper functions +// ---------------------------------------------------------------------------- + +// decide whether we should create a DIB or a DDB for the given parameters +// +// NB: we always use DIBs under Windows CE as this is much simpler (even if +// also less efficient...) and we obviously can't use them if there is no +// DIB support compiled in at all +#ifdef __WXWINCE__ + static inline bool wxShouldCreateDIB(int, int, int, WXHDC) { return true; } + + #define ALWAYS_USE_DIB +#elif !wxUSE_WXDIB + // no sense in defining wxShouldCreateDIB() as we can't compile code + // executed if it is true, so we have to use #if's anyhow + #define NEVER_USE_DIB +#else // wxUSE_WXDIB && !__WXWINCE__ + static inline bool wxShouldCreateDIB(int w, int h, int d, WXHDC hdc) + { + // here is the logic: + // + // (a) if hdc is specified, the caller explicitly wants DDB + // (b) otherwise, create a DIB if depth >= 24 (we don't support 16bpp + // or less DIBs anyhow) + // (c) finally, create DIBs under Win9x even if the depth hasn't been + // explicitly specified but the current display depth is 24 or + // more and the image is "big", i.e. > 16Mb which is the + // theoretical limit for DDBs under Win9x + // + // consequences (all of which seem to make sense): + // + // (i) by default, DDBs are created (depth == -1 usually) + // (ii) DIBs can be created by explicitly specifying the depth + // (iii) using a DC always forces creating a DDB + return !hdc && + (d >= 24 || + (d == -1 && + wxDIB::GetLineSize(w, wxDisplayDepth())*h > 16*1024*1024)); + } + + #define SOMETIMES_USE_DIB +#endif // different DIB usage scenarious + +// ---------------------------------------------------------------------------- +// wxBitmapRefData +// ---------------------------------------------------------------------------- + +wxBitmapRefData::wxBitmapRefData() +{ +#ifdef __WXDEBUG__ + m_selectedInto = NULL; +#endif + m_bitmapMask = NULL; + + m_hBitmap = (WXHBITMAP) NULL; +#if wxUSE_WXDIB + m_dib = NULL; +#endif + + m_isDIB = + m_hasAlpha = false; +} + +wxBitmapRefData::wxBitmapRefData(const wxBitmapRefData& data) + : wxGDIImageRefData(data) +{ +#ifdef __WXDEBUG__ + m_selectedInto = NULL; +#endif + + // (deep) copy the mask if present + m_bitmapMask = NULL; + if (data.m_bitmapMask) + m_bitmapMask = new wxMask(*data.m_bitmapMask); + + // FIXME: we don't copy m_hBitmap currently but we should, see wxBitmap:: + // CloneRefData() + + wxASSERT_MSG( !data.m_isDIB, + _T("can't copy bitmap locked for raw access!") ); + m_isDIB = false; + + m_hasAlpha = data.m_hasAlpha; +} + +void wxBitmapRefData::Free() +{ + wxASSERT_MSG( !m_selectedInto, + wxT("deleting bitmap still selected into wxMemoryDC") ); + +#if wxUSE_WXDIB + wxASSERT_MSG( !m_dib, _T("forgot to call wxBitmap::UngetRawData()!") ); +#endif + + if ( m_hBitmap) + { + if ( !::DeleteObject((HBITMAP)m_hBitmap) ) + { + wxLogLastError(wxT("DeleteObject(hbitmap)")); + } + } + + delete m_bitmapMask; + m_bitmapMask = NULL; +} + +// ---------------------------------------------------------------------------- +// wxBitmap creation +// ---------------------------------------------------------------------------- + +wxGDIImageRefData *wxBitmap::CreateData() const +{ + return new wxBitmapRefData; +} + +wxObjectRefData *wxBitmap::CloneRefData(const wxObjectRefData *dataOrig) const +{ + const wxBitmapRefData * + data = wx_static_cast(const wxBitmapRefData *, dataOrig); + if ( !data ) + return NULL; + + // FIXME: this method is backwards, it should just create a new + // wxBitmapRefData using its copy ctor but instead it modifies this + // bitmap itself and then returns its m_refData -- which works, of + // course (except in !wxUSE_WXDIB), but is completely illogical + wxBitmap *self = wx_const_cast(wxBitmap *, this); + +#if wxUSE_WXDIB + // copy the other bitmap + if ( data->m_hBitmap ) + { + wxDIB dib((HBITMAP)(data->m_hBitmap)); + self->CopyFromDIB(dib); + } + else +#endif // wxUSE_WXDIB + { + // copy the bitmap data + self->m_refData = new wxBitmapRefData(*data); + } + + // copy also the mask + wxMask * const maskSrc = data->GetMask(); + if ( maskSrc ) + { + wxBitmapRefData *selfdata = wx_static_cast(wxBitmapRefData *, m_refData); + + selfdata->SetMask(new wxMask(*maskSrc)); + } + + return m_refData; +} + +#ifdef __WIN32__ + +bool wxBitmap::CopyFromIconOrCursor(const wxGDIImage& icon) +{ +#if !defined(__WXMICROWIN__) && !defined(__WXWINCE__) + // it may be either HICON or HCURSOR + HICON hicon = (HICON)icon.GetHandle(); + + ICONINFO iconInfo; + if ( !::GetIconInfo(hicon, &iconInfo) ) + { + wxLogLastError(wxT("GetIconInfo")); + + return false; + } + + wxBitmapRefData *refData = new wxBitmapRefData; + m_refData = refData; + + int w = icon.GetWidth(), + h = icon.GetHeight(); + + refData->m_width = w; + refData->m_height = h; + refData->m_depth = wxDisplayDepth(); + + refData->m_hBitmap = (WXHBITMAP)iconInfo.hbmColor; + +#if wxUSE_WXDIB + // If the icon is 32 bits per pixel then it may have alpha channel data, + // although there are some icons that are 32 bpp but have no alpha... So + // convert to a DIB and manually check the 4th byte for each pixel. + BITMAP bm; + if ( ::GetObject(iconInfo.hbmColor, sizeof(BITMAP), (LPVOID)&bm) + && bm.bmBitsPixel == 32) + { + wxDIB dib(iconInfo.hbmColor); + if (dib.IsOk()) + { + unsigned char* pixels = dib.GetData(); + for (int idx=0; idxm_hasAlpha = true; + break; + } + } + } + } +#endif + if ( !refData->m_hasAlpha ) + { + // the mask returned by GetIconInfo() is inverted compared to the usual + // wxWin convention + refData->SetMask(wxInvertMask(iconInfo.hbmMask, w, h)); + } + + // delete the old one now as we don't need it any more + ::DeleteObject(iconInfo.hbmMask); + + return true; +#else + wxUnusedVar(icon); + return false; +#endif +} + +#endif // Win32 + +bool wxBitmap::CopyFromCursor(const wxCursor& cursor) +{ + UnRef(); + + if ( !cursor.Ok() ) + return false; + + return CopyFromIconOrCursor(cursor); +} + +bool wxBitmap::CopyFromIcon(const wxIcon& icon) +{ + UnRef(); + + if ( !icon.Ok() ) + return false; + + return CopyFromIconOrCursor(icon); +} + +#ifndef NEVER_USE_DIB + +bool wxBitmap::CopyFromDIB(const wxDIB& dib) +{ + wxCHECK_MSG( dib.IsOk(), false, _T("invalid DIB in CopyFromDIB") ); + +#ifdef SOMETIMES_USE_DIB + HBITMAP hbitmap = dib.CreateDDB(); + if ( !hbitmap ) + return false; +#else // ALWAYS_USE_DIB + HBITMAP hbitmap = ((wxDIB &)dib).Detach(); // const_cast +#endif // SOMETIMES_USE_DIB/ALWAYS_USE_DIB + + UnRef(); + + wxBitmapRefData *refData = new wxBitmapRefData; + m_refData = refData; + + refData->m_width = dib.GetWidth(); + refData->m_height = dib.GetHeight(); + refData->m_depth = dib.GetDepth(); + + refData->m_hBitmap = (WXHBITMAP)hbitmap; + +#if wxUSE_PALETTE + wxPalette *palette = dib.CreatePalette(); + if ( palette ) + { + refData->m_bitmapPalette = *palette; + } + + delete palette; +#endif // wxUSE_PALETTE + + return true; +} + +#endif // NEVER_USE_DIB + +wxBitmap::~wxBitmap() +{ +} + +wxBitmap::wxBitmap(const char bits[], int width, int height, int depth) +{ +#ifndef __WXMICROWIN__ + wxBitmapRefData *refData = new wxBitmapRefData; + m_refData = refData; + + refData->m_width = width; + refData->m_height = height; + refData->m_depth = depth; + + char *data; + if ( depth == 1 ) + { + // we assume that it is in XBM format which is not quite the same as + // the format CreateBitmap() wants because the order of bytes in the + // line is reversed! + const size_t bytesPerLine = (width + 7) / 8; + const size_t padding = bytesPerLine % 2; + const size_t len = height * ( padding + bytesPerLine ); + data = (char *)malloc(len); + const char *src = bits; + char *dst = data; + + for ( int rows = 0; rows < height; rows++ ) + { + for ( size_t cols = 0; cols < bytesPerLine; cols++ ) + { + unsigned char val = *src++; + unsigned char reversed = 0; + + for ( int bits = 0; bits < 8; bits++) + { + reversed <<= 1; + reversed |= (unsigned char)(val & 0x01); + val >>= 1; + } + *dst++ = ~reversed; + } + + if ( padding ) + *dst++ = 0; + } + } + else + { + // bits should already be in Windows standard format + data = (char *)bits; // const_cast is harmless + } + + HBITMAP hbmp = ::CreateBitmap(width, height, 1, depth, data); + if ( !hbmp ) + { + wxLogLastError(wxT("CreateBitmap")); + } + + if ( data != bits ) + { + free(data); + } + + SetHBITMAP((WXHBITMAP)hbmp); +#endif +} + +wxBitmap::wxBitmap(int w, int h, int d) +{ + (void)Create(w, h, d); +} + +wxBitmap::wxBitmap(int w, int h, const wxDC& dc) +{ + (void)Create(w, h, dc); +} + +wxBitmap::wxBitmap(const void* data, long type, int width, int height, int depth) +{ + (void)Create(data, type, width, height, depth); +} + +wxBitmap::wxBitmap(const wxString& filename, wxBitmapType type) +{ + LoadFile(filename, (int)type); +} + +bool wxBitmap::Create(int width, int height, int depth) +{ + return DoCreate(width, height, depth, 0); +} + +bool wxBitmap::Create(int width, int height, const wxDC& dc) +{ + wxCHECK_MSG( dc.Ok(), false, _T("invalid HDC in wxBitmap::Create()") ); + + return DoCreate(width, height, -1, dc.GetHDC()); +} + +bool wxBitmap::DoCreate(int w, int h, int d, WXHDC hdc) +{ + UnRef(); + + m_refData = new wxBitmapRefData; + + GetBitmapData()->m_width = w; + GetBitmapData()->m_height = h; + + HBITMAP hbmp wxDUMMY_INITIALIZE(0); + +#ifndef NEVER_USE_DIB + if ( wxShouldCreateDIB(w, h, d, hdc) ) + { + if ( d == -1 ) + { + // create DIBs without alpha channel by default + d = 24; + } + + wxDIB dib(w, h, d); + if ( !dib.IsOk() ) + return false; + + // don't delete the DIB section in dib object dtor + hbmp = dib.Detach(); + + GetBitmapData()->m_isDIB = true; + GetBitmapData()->m_depth = d; + } + else // create a DDB +#endif // NEVER_USE_DIB + { +#ifndef ALWAYS_USE_DIB +#ifndef __WXMICROWIN__ + if ( d > 0 ) + { + hbmp = ::CreateBitmap(w, h, 1, d, NULL); + if ( !hbmp ) + { + wxLogLastError(wxT("CreateBitmap")); + } + + GetBitmapData()->m_depth = d; + } + else // d == 0, create bitmap compatible with the screen +#endif // !__WXMICROWIN__ + { + ScreenHDC dc; + hbmp = ::CreateCompatibleBitmap(dc, w, h); + if ( !hbmp ) + { + wxLogLastError(wxT("CreateCompatibleBitmap")); + } + + GetBitmapData()->m_depth = wxDisplayDepth(); + } +#endif // !ALWAYS_USE_DIB + } + + SetHBITMAP((WXHBITMAP)hbmp); + + return Ok(); +} + +#if wxUSE_IMAGE + +// ---------------------------------------------------------------------------- +// wxImage to/from conversions for Microwin +// ---------------------------------------------------------------------------- + +// Microwin versions are so different from normal ones that it really doesn't +// make sense to use #ifdefs inside the function bodies +#ifdef __WXMICROWIN__ + +bool wxBitmap::CreateFromImage(const wxImage& image, int depth, const wxDC& dc) +{ + // Set this to 1 to experiment with mask code, + // which currently doesn't work + #define USE_MASKS 0 + + m_refData = new wxBitmapRefData(); + + // Initial attempt at a simple-minded implementation. + // The bitmap will always be created at the screen depth, + // so the 'depth' argument is ignored. + + HDC hScreenDC = ::GetDC(NULL); + int screenDepth = ::GetDeviceCaps(hScreenDC, BITSPIXEL); + + HBITMAP hBitmap = ::CreateCompatibleBitmap(hScreenDC, image.GetWidth(), image.GetHeight()); + HBITMAP hMaskBitmap = NULL; + HBITMAP hOldMaskBitmap = NULL; + HDC hMaskDC = NULL; + unsigned char maskR = 0; + unsigned char maskG = 0; + unsigned char maskB = 0; + + // printf("Created bitmap %d\n", (int) hBitmap); + if (hBitmap == NULL) + { + ::ReleaseDC(NULL, hScreenDC); + return false; + } + HDC hMemDC = ::CreateCompatibleDC(hScreenDC); + + HBITMAP hOldBitmap = ::SelectObject(hMemDC, hBitmap); + ::ReleaseDC(NULL, hScreenDC); + + // created an mono-bitmap for the possible mask + bool hasMask = image.HasMask(); + + if ( hasMask ) + { +#if USE_MASKS + // FIXME: we should be able to pass bpp = 1, but + // GdBlit can't handle a different depth +#if 0 + hMaskBitmap = ::CreateBitmap( (WORD)image.GetWidth(), (WORD)image.GetHeight(), 1, 1, NULL ); +#else + hMaskBitmap = ::CreateCompatibleBitmap( hMemDC, (WORD)image.GetWidth(), (WORD)image.GetHeight()); +#endif + maskR = image.GetMaskRed(); + maskG = image.GetMaskGreen(); + maskB = image.GetMaskBlue(); + + if (!hMaskBitmap) + { + hasMask = false; + } + else + { + hScreenDC = ::GetDC(NULL); + hMaskDC = ::CreateCompatibleDC(hScreenDC); + ::ReleaseDC(NULL, hScreenDC); + + hOldMaskBitmap = ::SelectObject( hMaskDC, hMaskBitmap); + } +#else + hasMask = false; +#endif + } + + int i, j; + for (i = 0; i < image.GetWidth(); i++) + { + for (j = 0; j < image.GetHeight(); j++) + { + unsigned char red = image.GetRed(i, j); + unsigned char green = image.GetGreen(i, j); + unsigned char blue = image.GetBlue(i, j); + + ::SetPixel(hMemDC, i, j, PALETTERGB(red, green, blue)); + + if (hasMask) + { + // scan the bitmap for the transparent colour and set the corresponding + // pixels in the mask to BLACK and the rest to WHITE + if (maskR == red && maskG == green && maskB == blue) + ::SetPixel(hMaskDC, i, j, PALETTERGB(0, 0, 0)); + else + ::SetPixel(hMaskDC, i, j, PALETTERGB(255, 255, 255)); + } + } + } + + ::SelectObject(hMemDC, hOldBitmap); + ::DeleteDC(hMemDC); + if (hasMask) + { + ::SelectObject(hMaskDC, hOldMaskBitmap); + ::DeleteDC(hMaskDC); + + ((wxBitmapRefData*)m_refData)->SetMask(hMaskBitmap); + } + + SetWidth(image.GetWidth()); + SetHeight(image.GetHeight()); + SetDepth(screenDepth); + SetHBITMAP( (WXHBITMAP) hBitmap ); + +#if wxUSE_PALETTE + // Copy the palette from the source image + SetPalette(image.GetPalette()); +#endif // wxUSE_PALETTE + + return true; +} + +wxImage wxBitmap::ConvertToImage() const +{ + // Initial attempt at a simple-minded implementation. + // The bitmap will always be created at the screen depth, + // so the 'depth' argument is ignored. + // TODO: transparency (create a mask image) + + if (!Ok()) + { + wxFAIL_MSG( wxT("bitmap is invalid") ); + return wxNullImage; + } + + wxImage image; + + wxCHECK_MSG( Ok(), wxNullImage, wxT("invalid bitmap") ); + + // create an wxImage object + int width = GetWidth(); + int height = GetHeight(); + image.Create( width, height ); + unsigned char *data = image.GetData(); + if( !data ) + { + wxFAIL_MSG( wxT("could not allocate data for image") ); + return wxNullImage; + } + + HDC hScreenDC = ::GetDC(NULL); + + HDC hMemDC = ::CreateCompatibleDC(hScreenDC); + ::ReleaseDC(NULL, hScreenDC); + + HBITMAP hBitmap = (HBITMAP) GetHBITMAP(); + + HBITMAP hOldBitmap = ::SelectObject(hMemDC, hBitmap); + + int i, j; + for (i = 0; i < GetWidth(); i++) + { + for (j = 0; j < GetHeight(); j++) + { + COLORREF color = ::GetPixel(hMemDC, i, j); + unsigned char red = GetRValue(color); + unsigned char green = GetGValue(color); + unsigned char blue = GetBValue(color); + + image.SetRGB(i, j, red, green, blue); + } + } + + ::SelectObject(hMemDC, hOldBitmap); + ::DeleteDC(hMemDC); + +#if wxUSE_PALETTE + // Copy the palette from the source image + if (GetPalette()) + image.SetPalette(* GetPalette()); +#endif // wxUSE_PALETTE + + return image; +} + +#endif // __WXMICROWIN__ + +// ---------------------------------------------------------------------------- +// wxImage to/from conversions +// ---------------------------------------------------------------------------- + +bool wxBitmap::CreateFromImage(const wxImage& image, int depth) +{ + return CreateFromImage(image, depth, 0); +} + +bool wxBitmap::CreateFromImage(const wxImage& image, const wxDC& dc) +{ + wxCHECK_MSG( dc.Ok(), false, + _T("invalid HDC in wxBitmap::CreateFromImage()") ); + + return CreateFromImage(image, -1, dc.GetHDC()); +} + +#if wxUSE_WXDIB + +bool wxBitmap::CreateFromImage(const wxImage& image, int depth, WXHDC hdc) +{ + wxCHECK_MSG( image.Ok(), false, wxT("invalid image") ); + + UnRef(); + + // first convert the image to DIB + const int h = image.GetHeight(); + const int w = image.GetWidth(); + + wxDIB dib(image); + if ( !dib.IsOk() ) + return false; + + if ( depth == -1 ) + depth = dib.GetDepth(); // Get depth from image if none specified + + // store the bitmap parameters + wxBitmapRefData *refData = new wxBitmapRefData; + refData->m_width = w; + refData->m_height = h; + refData->m_hasAlpha = image.HasAlpha(); + + m_refData = refData; + + + // next either store DIB as is or create a DDB from it + HBITMAP hbitmap wxDUMMY_INITIALIZE(0); + + // are we going to use DIB? + // + // NB: DDBs don't support alpha so if we have alpha channel we must use DIB + if ( image.HasAlpha() || wxShouldCreateDIB(w, h, depth, hdc) ) + { + // don't delete the DIB section in dib object dtor + hbitmap = dib.Detach(); + + refData->m_isDIB = true; + refData->m_depth = depth; + } +#ifndef ALWAYS_USE_DIB + else // we need to convert DIB to DDB + { + hbitmap = dib.CreateDDB((HDC)hdc); + + refData->m_depth = depth; + } +#endif // !ALWAYS_USE_DIB + + // validate this object + SetHBITMAP((WXHBITMAP)hbitmap); + + // finally also set the mask if we have one + if ( image.HasMask() ) + { + const size_t len = 2*((w+15)/16); + BYTE *src = image.GetData(); + BYTE *data = new BYTE[h*len]; + memset(data, 0, h*len); + BYTE r = image.GetMaskRed(), + g = image.GetMaskGreen(), + b = image.GetMaskBlue(); + BYTE *dst = data; + for ( int y = 0; y < h; y++, dst += len ) + { + BYTE *dstLine = dst; + BYTE mask = 0x80; + for ( int x = 0; x < w; x++, src += 3 ) + { + if (src[0] != r || src[1] != g || src[2] != b) + *dstLine |= mask; + + if ( (mask >>= 1) == 0 ) + { + dstLine++; + mask = 0x80; + } + } + } + + hbitmap = ::CreateBitmap(w, h, 1, 1, data); + if ( !hbitmap ) + { + wxLogLastError(_T("CreateBitmap(mask)")); + } + else + { + SetMask(new wxMask((WXHBITMAP)hbitmap)); + } + + delete[] data; + } + + return true; +} + +wxImage wxBitmap::ConvertToImage() const +{ + // convert DDB to DIB + wxDIB dib(*this); + + if ( !dib.IsOk() ) + { + return wxNullImage; + } + + // and then DIB to our wxImage + wxImage image = dib.ConvertToImage(); + if ( !image.Ok() ) + { + return wxNullImage; + } + + // now do the same for the mask, if we have any + HBITMAP hbmpMask = GetMask() ? (HBITMAP) GetMask()->GetMaskBitmap() : NULL; + if ( hbmpMask ) + { + wxDIB dibMask(hbmpMask); + if ( dibMask.IsOk() ) + { + // TODO: use wxRawBitmap to iterate over DIB + + // we hard code the mask colour for now but we could also make an + // effort (and waste time) to choose a colour not present in the + // image already to avoid having to fudge the pixels below -- + // whether it's worth to do it is unclear however + static const int MASK_RED = 1; + static const int MASK_GREEN = 2; + static const int MASK_BLUE = 3; + static const int MASK_BLUE_REPLACEMENT = 2; + + const int h = dibMask.GetHeight(); + const int w = dibMask.GetWidth(); + const int bpp = dibMask.GetDepth(); + const int maskBytesPerPixel = bpp >> 3; + const int maskBytesPerLine = wxDIB::GetLineSize(w, bpp); + unsigned char *data = image.GetData(); + + // remember that DIBs are stored in bottom to top order + unsigned char * + maskLineStart = dibMask.GetData() + ((h - 1) * maskBytesPerLine); + + for ( int y = 0; y < h; y++, maskLineStart -= maskBytesPerLine ) + { + // traverse one mask DIB line + unsigned char *mask = maskLineStart; + for ( int x = 0; x < w; x++, mask += maskBytesPerPixel ) + { + // should this pixel be transparent? + if ( *mask ) + { + // no, check that it isn't transparent by accident + if ( (data[0] == MASK_RED) && + (data[1] == MASK_GREEN) && + (data[2] == MASK_BLUE) ) + { + // we have to fudge the colour a bit to prevent + // this pixel from appearing transparent + data[2] = MASK_BLUE_REPLACEMENT; + } + + data += 3; + } + else // yes, transparent pixel + { + *data++ = MASK_RED; + *data++ = MASK_GREEN; + *data++ = MASK_BLUE; + } + } + } + + image.SetMaskColour(MASK_RED, MASK_GREEN, MASK_BLUE); + } + } + + return image; +} + +#else // !wxUSE_WXDIB + +bool +wxBitmap::CreateFromImage(const wxImage& WXUNUSED(image), + int WXUNUSED(depth), + WXHDC WXUNUSED(hdc)) +{ + return false; +} + +wxImage wxBitmap::ConvertToImage() const +{ + return wxImage(); +} + +#endif // wxUSE_WXDIB/!wxUSE_WXDIB + +#endif // wxUSE_IMAGE + +// ---------------------------------------------------------------------------- +// loading and saving bitmaps +// ---------------------------------------------------------------------------- + +bool wxBitmap::LoadFile(const wxString& filename, long type) +{ + UnRef(); + + wxBitmapHandler *handler = wxDynamicCast(FindHandler(type), wxBitmapHandler); + + if ( handler ) + { + m_refData = new wxBitmapRefData; + + return handler->LoadFile(this, filename, type, -1, -1); + } +#if wxUSE_IMAGE && wxUSE_WXDIB + else // no bitmap handler found + { + wxImage image; + if ( image.LoadFile( filename, type ) && image.Ok() ) + { + *this = wxBitmap(image); + + return true; + } + } +#endif // wxUSE_IMAGE + + return false; +} + +bool wxBitmap::Create(const void* data, long type, int width, int height, int depth) +{ + UnRef(); + + wxBitmapHandler *handler = wxDynamicCast(FindHandler(type), wxBitmapHandler); + + if ( !handler ) + { + wxLogDebug(wxT("Failed to create bitmap: no bitmap handler for type %ld defined."), type); + + return false; + } + + m_refData = new wxBitmapRefData; + + return handler->Create(this, data, type, width, height, depth); +} + +bool wxBitmap::SaveFile(const wxString& filename, + int type, + const wxPalette *palette) +{ + wxBitmapHandler *handler = wxDynamicCast(FindHandler(type), wxBitmapHandler); + + if ( handler ) + { + return handler->SaveFile(this, filename, type, palette); + } +#if wxUSE_IMAGE && wxUSE_WXDIB + else // no bitmap handler found + { + // FIXME what about palette? shouldn't we use it? + wxImage image = ConvertToImage(); + if ( image.Ok() ) + { + return image.SaveFile(filename, type); + } + } +#endif // wxUSE_IMAGE + + return false; +} + +// ---------------------------------------------------------------------------- +// sub bitmap extraction +// ---------------------------------------------------------------------------- +wxBitmap wxBitmap::GetSubBitmap( const wxRect& rect ) const +{ + MemoryHDC dcSrc; + SelectInHDC selectSrc(dcSrc, GetHbitmap()); + return GetSubBitmapOfHDC( rect, (WXHDC)dcSrc ); +} + +wxBitmap wxBitmap::GetSubBitmapOfHDC( const wxRect& rect, WXHDC hdc ) const +{ + wxCHECK_MSG( Ok() && + (rect.x >= 0) && (rect.y >= 0) && + (rect.x+rect.width <= GetWidth()) && + (rect.y+rect.height <= GetHeight()), + wxNullBitmap, wxT("Invalid bitmap or bitmap region") ); + + wxBitmap ret( rect.width, rect.height, GetDepth() ); + wxASSERT_MSG( ret.Ok(), wxT("GetSubBitmap error") ); + +#ifndef __WXMICROWIN__ + // handle alpha channel, if any + if (HasAlpha()) + ret.UseAlpha(); + + // copy bitmap data + MemoryHDC dcSrc, + dcDst; + + { + SelectInHDC selectDst(dcDst, GetHbitmapOf(ret)); + + if ( !selectDst ) + { + wxLogLastError(_T("SelectObject(destBitmap)")); + } + + if ( !::BitBlt(dcDst, 0, 0, rect.width, rect.height, + (HDC)hdc, rect.x, rect.y, SRCCOPY) ) + { + wxLogLastError(_T("BitBlt")); + } + } + + // copy mask if there is one + if ( GetMask() ) + { + HBITMAP hbmpMask = ::CreateBitmap(rect.width, rect.height, 1, 1, 0); + + SelectInHDC selectSrc(dcSrc, (HBITMAP) GetMask()->GetMaskBitmap()), + selectDst(dcDst, hbmpMask); + + if ( !::BitBlt(dcDst, 0, 0, rect.width, rect.height, + dcSrc, rect.x, rect.y, SRCCOPY) ) + { + wxLogLastError(_T("BitBlt")); + } + + wxMask *mask = new wxMask((WXHBITMAP) hbmpMask); + ret.SetMask(mask); + } +#endif // !__WXMICROWIN__ + + return ret; +} + +// ---------------------------------------------------------------------------- +// wxBitmap accessors +// ---------------------------------------------------------------------------- + +#if wxUSE_PALETTE +wxPalette* wxBitmap::GetPalette() const +{ + return GetBitmapData() ? &GetBitmapData()->m_bitmapPalette + : (wxPalette *) NULL; +} +#endif + +wxMask *wxBitmap::GetMask() const +{ + return GetBitmapData() ? GetBitmapData()->GetMask() : (wxMask *) NULL; +} + +wxBitmap wxBitmap::GetMaskBitmap() const +{ + wxBitmap bmp; + wxMask *mask = GetMask(); + if ( mask ) + bmp.SetHBITMAP(mask->GetMaskBitmap()); + return bmp; +} + +#ifdef __WXDEBUG__ + +wxDC *wxBitmap::GetSelectedInto() const +{ + return GetBitmapData() ? GetBitmapData()->m_selectedInto : (wxDC *) NULL; +} + +#endif + +#if WXWIN_COMPATIBILITY_2_4 + +int wxBitmap::GetQuality() const +{ + return 0; +} + +#endif // WXWIN_COMPATIBILITY_2_4 + +void wxBitmap::UseAlpha() +{ + if ( GetBitmapData() ) + GetBitmapData()->m_hasAlpha = true; +} + +bool wxBitmap::HasAlpha() const +{ + return GetBitmapData() && GetBitmapData()->m_hasAlpha; +} + +// ---------------------------------------------------------------------------- +// wxBitmap setters +// ---------------------------------------------------------------------------- + +#ifdef __WXDEBUG__ + +void wxBitmap::SetSelectedInto(wxDC *dc) +{ + if ( GetBitmapData() ) + GetBitmapData()->m_selectedInto = dc; +} + +#endif + +#if wxUSE_PALETTE + +void wxBitmap::SetPalette(const wxPalette& palette) +{ + AllocExclusive(); + + GetBitmapData()->m_bitmapPalette = palette; +} + +#endif // wxUSE_PALETTE + +void wxBitmap::SetMask(wxMask *mask) +{ + AllocExclusive(); + + GetBitmapData()->SetMask(mask); +} + +#if WXWIN_COMPATIBILITY_2_4 + +void wxBitmap::SetQuality(int WXUNUSED(quality)) +{ +} + +#endif // WXWIN_COMPATIBILITY_2_4 + +// ---------------------------------------------------------------------------- +// raw bitmap access support +// ---------------------------------------------------------------------------- + +#ifdef wxHAVE_RAW_BITMAP +void *wxBitmap::GetRawData(wxPixelDataBase& data, int bpp) +{ +#if wxUSE_WXDIB + if ( !Ok() ) + { + // no bitmap, no data (raw or otherwise) + return NULL; + } + + // if we're already a DIB we can access our data directly, but if not we + // need to convert this DDB to a DIB section and use it for raw access and + // then convert it back + HBITMAP hDIB; + if ( !GetBitmapData()->m_isDIB ) + { + wxCHECK_MSG( !GetBitmapData()->m_dib, NULL, + _T("GetRawData() may be called only once") ); + + wxDIB *dib = new wxDIB(*this); + if ( !dib->IsOk() ) + { + delete dib; + + return NULL; + } + + // we'll free it in UngetRawData() + GetBitmapData()->m_dib = dib; + + hDIB = dib->GetHandle(); + } + else // we're a DIB + { + hDIB = GetHbitmap(); + } + + DIBSECTION ds; + if ( ::GetObject(hDIB, sizeof(ds), &ds) != sizeof(DIBSECTION) ) + { + wxFAIL_MSG( _T("failed to get DIBSECTION from a DIB?") ); + + return NULL; + } + + // check that the bitmap is in correct format + if ( ds.dsBm.bmBitsPixel != bpp ) + { + wxFAIL_MSG( _T("incorrect bitmap type in wxBitmap::GetRawData()") ); + + return NULL; + } + + // ok, store the relevant info in wxPixelDataBase + const LONG h = ds.dsBm.bmHeight; + + data.m_width = ds.dsBm.bmWidth; + data.m_height = h; + + // remember that DIBs are stored in top to bottom order! + // (We can't just use ds.dsBm.bmWidthBytes here, because it isn't always a + // multiple of 2, as required by the documentation. So we use the official + // formula, which we already use elsewhere.) + const LONG bytesPerRow = + wxDIB::GetLineSize(ds.dsBm.bmWidth, ds.dsBm.bmBitsPixel); + data.m_stride = -bytesPerRow; + + char *bits = (char *)ds.dsBm.bmBits; + if ( h > 1 ) + { + bits += (h - 1)*bytesPerRow; + } + + return bits; +#else + return NULL; +#endif +} + +void wxBitmap::UngetRawData(wxPixelDataBase& dataBase) +{ +#if wxUSE_WXDIB + if ( !Ok() ) + return; + + if ( !&dataBase ) + { + // invalid data, don't crash -- but don't assert neither as we're + // called automatically from wxPixelDataBase dtor and so there is no + // way to prevent this from happening + return; + } + + // if we're a DDB we need to convert DIB back to DDB now to make the + // changes made via raw bitmap access effective + if ( !GetBitmapData()->m_isDIB ) + { + wxDIB *dib = GetBitmapData()->m_dib; + GetBitmapData()->m_dib = NULL; + + // TODO: convert + + delete dib; + } +#endif // wxUSE_WXDIB +} +#endif // #ifdef wxHAVE_RAW_BITMAP + +// ---------------------------------------------------------------------------- +// wxMask +// ---------------------------------------------------------------------------- + +wxMask::wxMask() +{ + m_maskBitmap = 0; +} + +// Copy constructor +wxMask::wxMask(const wxMask &mask) + : wxObject() +{ + BITMAP bmp; + + HDC srcDC = CreateCompatibleDC(0); + HDC destDC = CreateCompatibleDC(0); + + // GetBitmapDimensionEx won't work if SetBitmapDimensionEx wasn't used + // so we'll use GetObject() API here: + if (::GetObject((HGDIOBJ)mask.m_maskBitmap, sizeof(bmp), &bmp) == 0) + { + wxFAIL_MSG(wxT("Cannot retrieve the dimensions of the wxMask to copy")); + return; + } + + // create our HBITMAP + int w = bmp.bmWidth, h = bmp.bmHeight; + m_maskBitmap = (WXHBITMAP)CreateCompatibleBitmap(srcDC, w, h); + + // copy the mask's HBITMAP into our HBITMAP + SelectObject(srcDC, (HBITMAP) mask.m_maskBitmap); + SelectObject(destDC, (HBITMAP) m_maskBitmap); + + BitBlt(destDC, 0, 0, w, h, srcDC, 0, 0, SRCCOPY); + + SelectObject(srcDC, 0); + DeleteDC(srcDC); + SelectObject(destDC, 0); + DeleteDC(destDC); +} + +// Construct a mask from a bitmap and a colour indicating +// the transparent area +wxMask::wxMask(const wxBitmap& bitmap, const wxColour& colour) +{ + m_maskBitmap = 0; + Create(bitmap, colour); +} + +// Construct a mask from a bitmap and a palette index indicating +// the transparent area +wxMask::wxMask(const wxBitmap& bitmap, int paletteIndex) +{ + m_maskBitmap = 0; + Create(bitmap, paletteIndex); +} + +// Construct a mask from a mono bitmap (copies the bitmap). +wxMask::wxMask(const wxBitmap& bitmap) +{ + m_maskBitmap = 0; + Create(bitmap); +} + +wxMask::~wxMask() +{ + if ( m_maskBitmap ) + ::DeleteObject((HBITMAP) m_maskBitmap); +} + +// Create a mask from a mono bitmap (copies the bitmap). +bool wxMask::Create(const wxBitmap& bitmap) +{ +#ifndef __WXMICROWIN__ + wxCHECK_MSG( bitmap.Ok() && bitmap.GetDepth() == 1, false, + _T("can't create mask from invalid or not monochrome bitmap") ); + + if ( m_maskBitmap ) + { + ::DeleteObject((HBITMAP) m_maskBitmap); + m_maskBitmap = 0; + } + + m_maskBitmap = (WXHBITMAP) CreateBitmap( + bitmap.GetWidth(), + bitmap.GetHeight(), + 1, 1, 0 + ); + HDC srcDC = CreateCompatibleDC(0); + SelectObject(srcDC, (HBITMAP) bitmap.GetHBITMAP()); + HDC destDC = CreateCompatibleDC(0); + SelectObject(destDC, (HBITMAP) m_maskBitmap); + BitBlt(destDC, 0, 0, bitmap.GetWidth(), bitmap.GetHeight(), srcDC, 0, 0, SRCCOPY); + SelectObject(srcDC, 0); + DeleteDC(srcDC); + SelectObject(destDC, 0); + DeleteDC(destDC); + return true; +#else + wxUnusedVar(bitmap); + return false; +#endif +} + +// Create a mask from a bitmap and a palette index indicating +// the transparent area +bool wxMask::Create(const wxBitmap& bitmap, int paletteIndex) +{ + if ( m_maskBitmap ) + { + ::DeleteObject((HBITMAP) m_maskBitmap); + m_maskBitmap = 0; + } + +#if wxUSE_PALETTE + if (bitmap.Ok() && bitmap.GetPalette()->Ok()) + { + unsigned char red, green, blue; + if (bitmap.GetPalette()->GetRGB(paletteIndex, &red, &green, &blue)) + { + wxColour transparentColour(red, green, blue); + return Create(bitmap, transparentColour); + } + } +#endif // wxUSE_PALETTE + + return false; +} + +// Create a mask from a bitmap and a colour indicating +// the transparent area +bool wxMask::Create(const wxBitmap& bitmap, const wxColour& colour) +{ +#ifndef __WXMICROWIN__ + wxCHECK_MSG( bitmap.Ok(), false, _T("invalid bitmap in wxMask::Create") ); + + if ( m_maskBitmap ) + { + ::DeleteObject((HBITMAP) m_maskBitmap); + m_maskBitmap = 0; + } + + int width = bitmap.GetWidth(), + height = bitmap.GetHeight(); + + // scan the bitmap for the transparent colour and set the corresponding + // pixels in the mask to BLACK and the rest to WHITE + COLORREF maskColour = wxColourToPalRGB(colour); + m_maskBitmap = (WXHBITMAP)::CreateBitmap(width, height, 1, 1, 0); + + HDC srcDC = ::CreateCompatibleDC(NULL); + HDC destDC = ::CreateCompatibleDC(NULL); + if ( !srcDC || !destDC ) + { + wxLogLastError(wxT("CreateCompatibleDC")); + } + + bool ok = true; + + // SelectObject() will fail + wxASSERT_MSG( !bitmap.GetSelectedInto(), + _T("bitmap can't be selected in another DC") ); + + HGDIOBJ hbmpSrcOld = ::SelectObject(srcDC, GetHbitmapOf(bitmap)); + if ( !hbmpSrcOld ) + { + wxLogLastError(wxT("SelectObject")); + + ok = false; + } + + HGDIOBJ hbmpDstOld = ::SelectObject(destDC, (HBITMAP)m_maskBitmap); + if ( !hbmpDstOld ) + { + wxLogLastError(wxT("SelectObject")); + + ok = false; + } + + if ( ok ) + { + // this will create a monochrome bitmap with 0 points for the pixels + // which have the same value as the background colour and 1 for the + // others + ::SetBkColor(srcDC, maskColour); + ::BitBlt(destDC, 0, 0, width, height, srcDC, 0, 0, NOTSRCCOPY); + } + + ::SelectObject(srcDC, hbmpSrcOld); + ::DeleteDC(srcDC); + ::SelectObject(destDC, hbmpDstOld); + ::DeleteDC(destDC); + + return ok; +#else // __WXMICROWIN__ + wxUnusedVar(bitmap); + wxUnusedVar(colour); + return false; +#endif // __WXMICROWIN__/!__WXMICROWIN__ +} + +// ---------------------------------------------------------------------------- +// wxBitmapHandler +// ---------------------------------------------------------------------------- + +bool wxBitmapHandler::Create(wxGDIImage *image, + const void* data, + long flags, + int width, int height, int depth) +{ + wxBitmap *bitmap = wxDynamicCast(image, wxBitmap); + + return bitmap && Create(bitmap, data, flags, width, height, depth); +} + +bool wxBitmapHandler::Load(wxGDIImage *image, + const wxString& name, + long flags, + int width, int height) +{ + wxBitmap *bitmap = wxDynamicCast(image, wxBitmap); + + return bitmap && LoadFile(bitmap, name, flags, width, height); +} + +bool wxBitmapHandler::Save(wxGDIImage *image, + const wxString& name, + int type) +{ + wxBitmap *bitmap = wxDynamicCast(image, wxBitmap); + + return bitmap && SaveFile(bitmap, name, type); +} + +bool wxBitmapHandler::Create(wxBitmap *WXUNUSED(bitmap), + const void* WXUNUSED(data), + long WXUNUSED(type), + int WXUNUSED(width), + int WXUNUSED(height), + int WXUNUSED(depth)) +{ + return false; +} + +bool wxBitmapHandler::LoadFile(wxBitmap *WXUNUSED(bitmap), + const wxString& WXUNUSED(name), + long WXUNUSED(type), + int WXUNUSED(desiredWidth), + int WXUNUSED(desiredHeight)) +{ + return false; +} + +bool wxBitmapHandler::SaveFile(wxBitmap *WXUNUSED(bitmap), + const wxString& WXUNUSED(name), + int WXUNUSED(type), + const wxPalette *WXUNUSED(palette)) +{ + return false; +} + +// ---------------------------------------------------------------------------- +// DIB functions +// ---------------------------------------------------------------------------- + +#ifndef __WXMICROWIN__ +bool wxCreateDIB(long xSize, long ySize, long bitsPerPixel, + HPALETTE hPal, LPBITMAPINFO* lpDIBHeader) +{ + unsigned long i, headerSize; + + // Allocate space for a DIB header + headerSize = (sizeof(BITMAPINFOHEADER) + (256 * sizeof(PALETTEENTRY))); + LPBITMAPINFO lpDIBheader = (BITMAPINFO *) malloc(headerSize); + LPPALETTEENTRY lpPe = (PALETTEENTRY *)((BYTE*)lpDIBheader + sizeof(BITMAPINFOHEADER)); + + GetPaletteEntries(hPal, 0, 256, lpPe); + + memset(lpDIBheader, 0x00, sizeof(BITMAPINFOHEADER)); + + // Fill in the static parts of the DIB header + lpDIBheader->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + lpDIBheader->bmiHeader.biWidth = xSize; + lpDIBheader->bmiHeader.biHeight = ySize; + lpDIBheader->bmiHeader.biPlanes = 1; + + // this value must be 1, 4, 8 or 24 so PixelDepth can only be + lpDIBheader->bmiHeader.biBitCount = (WORD)(bitsPerPixel); + lpDIBheader->bmiHeader.biCompression = BI_RGB; + lpDIBheader->bmiHeader.biSizeImage = (xSize * abs((int)ySize) * bitsPerPixel) >> 3; + lpDIBheader->bmiHeader.biClrUsed = 256; + + + // Initialize the DIB palette + for (i = 0; i < 256; i++) { + lpDIBheader->bmiColors[i].rgbReserved = lpPe[i].peFlags; + lpDIBheader->bmiColors[i].rgbRed = lpPe[i].peRed; + lpDIBheader->bmiColors[i].rgbGreen = lpPe[i].peGreen; + lpDIBheader->bmiColors[i].rgbBlue = lpPe[i].peBlue; + } + + *lpDIBHeader = lpDIBheader; + + return true; +} + +void wxFreeDIB(LPBITMAPINFO lpDIBHeader) +{ + free(lpDIBHeader); +} +#endif + +// ---------------------------------------------------------------------------- +// global helper functions implemented here +// ---------------------------------------------------------------------------- + +// helper of wxBitmapToHICON/HCURSOR +static +HICON wxBitmapToIconOrCursor(const wxBitmap& bmp, + bool iconWanted, + int hotSpotX, + int hotSpotY) +{ + if ( !bmp.Ok() ) + { + // we can't create an icon/cursor form nothing + return 0; + } + + if ( bmp.HasAlpha() ) + { + // Create an empty mask bitmap. + // it doesn't seem to work if we mess with the mask at all. + HBITMAP hMonoBitmap = CreateBitmap(bmp.GetWidth(),bmp.GetHeight(),1,1,NULL); + + ICONINFO iconInfo; + wxZeroMemory(iconInfo); + iconInfo.fIcon = iconWanted; // do we want an icon or a cursor? + if ( !iconWanted ) + { + iconInfo.xHotspot = hotSpotX; + iconInfo.yHotspot = hotSpotY; + } + + iconInfo.hbmMask = hMonoBitmap; + iconInfo.hbmColor = GetHbitmapOf(bmp); + + HICON hicon = ::CreateIconIndirect(&iconInfo); + + ::DeleteObject(hMonoBitmap); + + return hicon; + } + + wxMask* mask = bmp.GetMask(); + + if ( !mask ) + { + // we must have a mask for an icon, so even if it's probably incorrect, + // do create it (grey is the "standard" transparent colour) + mask = new wxMask(bmp, *wxLIGHT_GREY); + } + + ICONINFO iconInfo; + wxZeroMemory(iconInfo); + iconInfo.fIcon = iconWanted; // do we want an icon or a cursor? + if ( !iconWanted ) + { + iconInfo.xHotspot = hotSpotX; + iconInfo.yHotspot = hotSpotY; + } + + iconInfo.hbmMask = wxInvertMask((HBITMAP)mask->GetMaskBitmap()); + iconInfo.hbmColor = GetHbitmapOf(bmp); + + // black out the transparent area to preserve background colour, because + // Windows blits the original bitmap using SRCINVERT (XOR) after applying + // the mask to the dest rect. + { + MemoryHDC dcSrc, dcDst; + SelectInHDC selectMask(dcSrc, (HBITMAP)mask->GetMaskBitmap()), + selectBitmap(dcDst, iconInfo.hbmColor); + + if ( !::BitBlt(dcDst, 0, 0, bmp.GetWidth(), bmp.GetHeight(), + dcSrc, 0, 0, SRCAND) ) + { + wxLogLastError(_T("BitBlt")); + } + } + + HICON hicon = ::CreateIconIndirect(&iconInfo); + + if ( !bmp.GetMask() && !bmp.HasAlpha() ) + { + // we created the mask, now delete it + delete mask; + } + + // delete the inverted mask bitmap we created as well + ::DeleteObject(iconInfo.hbmMask); + + return hicon; +} + +HICON wxBitmapToHICON(const wxBitmap& bmp) +{ + return wxBitmapToIconOrCursor(bmp, true, 0, 0); +} + +HCURSOR wxBitmapToHCURSOR(const wxBitmap& bmp, int hotSpotX, int hotSpotY) +{ + return (HCURSOR)wxBitmapToIconOrCursor(bmp, false, hotSpotX, hotSpotY); +} + +HBITMAP wxInvertMask(HBITMAP hbmpMask, int w, int h) +{ +#ifndef __WXMICROWIN__ + wxCHECK_MSG( hbmpMask, 0, _T("invalid bitmap in wxInvertMask") ); + + // get width/height from the bitmap if not given + if ( !w || !h ) + { + BITMAP bm; + ::GetObject(hbmpMask, sizeof(BITMAP), (LPVOID)&bm); + w = bm.bmWidth; + h = bm.bmHeight; + } + + HDC hdcSrc = ::CreateCompatibleDC(NULL); + HDC hdcDst = ::CreateCompatibleDC(NULL); + if ( !hdcSrc || !hdcDst ) + { + wxLogLastError(wxT("CreateCompatibleDC")); + } + + HBITMAP hbmpInvMask = ::CreateBitmap(w, h, 1, 1, 0); + if ( !hbmpInvMask ) + { + wxLogLastError(wxT("CreateBitmap")); + } + + HGDIOBJ srcTmp = ::SelectObject(hdcSrc, hbmpMask); + HGDIOBJ dstTmp = ::SelectObject(hdcDst, hbmpInvMask); + if ( !::BitBlt(hdcDst, 0, 0, w, h, + hdcSrc, 0, 0, + NOTSRCCOPY) ) + { + wxLogLastError(wxT("BitBlt")); + } + + // Deselect objects + SelectObject(hdcSrc,srcTmp); + SelectObject(hdcDst,dstTmp); + + ::DeleteDC(hdcSrc); + ::DeleteDC(hdcDst); + + return hbmpInvMask; +#else + return 0; +#endif +} diff --git a/Externals/wxWidgets/src/msw/bmpbuttn.cpp b/Externals/wxWidgets/src/msw/bmpbuttn.cpp index 6797659107..a78ada6ebb 100644 --- a/Externals/wxWidgets/src/msw/bmpbuttn.cpp +++ b/Externals/wxWidgets/src/msw/bmpbuttn.cpp @@ -1,646 +1,646 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/msw/bmpbuttn.cpp -// Purpose: wxBitmapButton -// Author: Julian Smart -// Modified by: -// Created: 04/01/98 -// RCS-ID: $Id: bmpbuttn.cpp 42816 2006-10-31 08:50:17Z RD $ -// Copyright: (c) Julian Smart -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_BMPBUTTON - -#include "wx/bmpbuttn.h" - -#ifndef WX_PRECOMP - #include "wx/log.h" - #include "wx/dcmemory.h" - #include "wx/image.h" -#endif - -#include "wx/msw/private.h" - -#include "wx/msw/uxtheme.h" - -#if wxUSE_UXTHEME - // no need to include tmschema.h - #ifndef BP_PUSHBUTTON - #define BP_PUSHBUTTON 1 - - #define PBS_NORMAL 1 - #define PBS_HOT 2 - #define PBS_PRESSED 3 - #define PBS_DISABLED 4 - #define PBS_DEFAULTED 5 - - #define TMT_CONTENTMARGINS 3602 - #endif -#endif // wxUSE_UXTHEME - -#ifndef ODS_NOFOCUSRECT - #define ODS_NOFOCUSRECT 0x0200 -#endif - -// ---------------------------------------------------------------------------- -// macros -// ---------------------------------------------------------------------------- - -#if wxUSE_EXTENDED_RTTI - -WX_DEFINE_FLAGS( wxBitmapButtonStyle ) - -wxBEGIN_FLAGS( wxBitmapButtonStyle ) - // new style border flags, we put them first to - // use them for streaming out - wxFLAGS_MEMBER(wxBORDER_SIMPLE) - wxFLAGS_MEMBER(wxBORDER_SUNKEN) - wxFLAGS_MEMBER(wxBORDER_DOUBLE) - wxFLAGS_MEMBER(wxBORDER_RAISED) - wxFLAGS_MEMBER(wxBORDER_STATIC) - wxFLAGS_MEMBER(wxBORDER_NONE) - - // old style border flags - wxFLAGS_MEMBER(wxSIMPLE_BORDER) - wxFLAGS_MEMBER(wxSUNKEN_BORDER) - wxFLAGS_MEMBER(wxDOUBLE_BORDER) - wxFLAGS_MEMBER(wxRAISED_BORDER) - wxFLAGS_MEMBER(wxSTATIC_BORDER) - wxFLAGS_MEMBER(wxBORDER) - - // standard window styles - wxFLAGS_MEMBER(wxTAB_TRAVERSAL) - wxFLAGS_MEMBER(wxCLIP_CHILDREN) - wxFLAGS_MEMBER(wxTRANSPARENT_WINDOW) - wxFLAGS_MEMBER(wxWANTS_CHARS) - wxFLAGS_MEMBER(wxFULL_REPAINT_ON_RESIZE) - wxFLAGS_MEMBER(wxALWAYS_SHOW_SB ) - wxFLAGS_MEMBER(wxVSCROLL) - wxFLAGS_MEMBER(wxHSCROLL) - - wxFLAGS_MEMBER(wxBU_AUTODRAW) - wxFLAGS_MEMBER(wxBU_LEFT) - wxFLAGS_MEMBER(wxBU_RIGHT) - wxFLAGS_MEMBER(wxBU_TOP) - wxFLAGS_MEMBER(wxBU_BOTTOM) -wxEND_FLAGS( wxBitmapButtonStyle ) - -IMPLEMENT_DYNAMIC_CLASS_XTI(wxBitmapButton, wxButton,"wx/bmpbuttn.h") - -wxBEGIN_PROPERTIES_TABLE(wxBitmapButton) - wxPROPERTY_FLAGS( WindowStyle , wxBitmapButtonStyle , long , SetWindowStyleFlag , GetWindowStyleFlag , EMPTY_MACROVALUE, 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // style -wxEND_PROPERTIES_TABLE() - -wxBEGIN_HANDLERS_TABLE(wxBitmapButton) -wxEND_HANDLERS_TABLE() - -wxCONSTRUCTOR_5( wxBitmapButton , wxWindow* , Parent , wxWindowID , Id , wxBitmap , Bitmap , wxPoint , Position , wxSize , Size ) - -#else -IMPLEMENT_DYNAMIC_CLASS(wxBitmapButton, wxButton) -#endif - -BEGIN_EVENT_TABLE(wxBitmapButton, wxBitmapButtonBase) - EVT_SYS_COLOUR_CHANGED(wxBitmapButton::OnSysColourChanged) - EVT_ENTER_WINDOW(wxBitmapButton::OnMouseEnterOrLeave) - EVT_LEAVE_WINDOW(wxBitmapButton::OnMouseEnterOrLeave) -END_EVENT_TABLE() - -/* -TODO PROPERTIES : - -long "style" , wxBU_AUTODRAW -bool "default" , 0 -bitmap "selected" , -bitmap "focus" , -bitmap "disabled" , -*/ - -bool wxBitmapButton::Create(wxWindow *parent, wxWindowID id, - const wxBitmap& bitmap, - const wxPoint& pos, - const wxSize& size, long style, - const wxValidator& wxVALIDATOR_PARAM(validator), - const wxString& name) -{ - m_bmpNormal = bitmap; - SetName(name); - -#if wxUSE_VALIDATORS - SetValidator(validator); -#endif // wxUSE_VALIDATORS - - parent->AddChild(this); - - m_windowStyle = style; - - if ( style & wxBU_AUTODRAW ) - { - m_marginX = - m_marginY = 4; - } - - if (id == wxID_ANY) - m_windowId = NewControlId(); - else - m_windowId = id; - - long msStyle = WS_VISIBLE | WS_TABSTOP | WS_CHILD | BS_OWNERDRAW ; - - if ( m_windowStyle & wxCLIP_SIBLINGS ) - msStyle |= WS_CLIPSIBLINGS; - -#ifdef __WIN32__ - if(m_windowStyle & wxBU_LEFT) - msStyle |= BS_LEFT; - if(m_windowStyle & wxBU_RIGHT) - msStyle |= BS_RIGHT; - if(m_windowStyle & wxBU_TOP) - msStyle |= BS_TOP; - if(m_windowStyle & wxBU_BOTTOM) - msStyle |= BS_BOTTOM; -#endif - - m_hWnd = (WXHWND) CreateWindowEx( - 0, - wxT("BUTTON"), - wxEmptyString, - msStyle, - 0, 0, 0, 0, - GetWinHwnd(parent), - (HMENU)m_windowId, - wxGetInstance(), - NULL - ); - - // Subclass again for purposes of dialog editing mode - SubclassWin(m_hWnd); - - SetPosition(pos); - SetInitialSize(size); - - return true; -} - -bool wxBitmapButton::SetBackgroundColour(const wxColour& colour) -{ - if ( !wxBitmapButtonBase::SetBackgroundColour(colour) ) - { - // didn't change - return false; - } - - // invalidate the brush, it will be recreated the next time it's needed - m_brushDisabled = wxNullBrush; - - return true; -} - -void wxBitmapButton::OnSysColourChanged(wxSysColourChangedEvent& event) -{ - m_brushDisabled = wxNullBrush; - - if ( !IsEnabled() ) - { - // this change affects our current state - Refresh(); - } - - event.Skip(); -} - -void wxBitmapButton::OnMouseEnterOrLeave(wxMouseEvent& event) -{ - if ( IsEnabled() && m_bmpHover.Ok() ) - Refresh(); - - event.Skip(); -} - -void wxBitmapButton::OnSetBitmap() -{ - // if the focus bitmap is specified but hover one isn't, use the focus - // bitmap for hovering as well if this is consistent with the current - // Windows version look and feel - // - // rationale: this is compatible with the old wxGTK behaviour and also - // makes it much easier to do "the right thing" for all platforms (some of - // them, such as Windows XP, have "hot" buttons while others don't) - if ( !m_bmpHover.Ok() && - m_bmpFocus.Ok() && - wxUxThemeEngine::GetIfActive() ) - { - m_bmpHover = m_bmpFocus; - } - - // this will redraw us - wxBitmapButtonBase::OnSetBitmap(); -} - -#if wxUSE_UXTHEME -static -void MSWDrawXPBackground(wxButton *button, WXDRAWITEMSTRUCT *wxdis) -{ - LPDRAWITEMSTRUCT lpDIS = (LPDRAWITEMSTRUCT)wxdis; - HDC hdc = lpDIS->hDC; - UINT state = lpDIS->itemState; - RECT rectBtn; - CopyRect(&rectBtn, &lpDIS->rcItem); - - wxUxThemeHandle theme(button, L"BUTTON"); - int iState; - - if ( state & ODS_SELECTED ) - { - iState = PBS_PRESSED; - } - else if ( button->HasCapture() || button->IsMouseInWindow() ) - { - iState = PBS_HOT; - } - else if ( state & ODS_FOCUS ) - { - iState = PBS_DEFAULTED; - } - else if ( state & ODS_DISABLED ) - { - iState = PBS_DISABLED; - } - else - { - iState = PBS_NORMAL; - } - - // draw parent background if needed - if ( wxUxThemeEngine::Get()->IsThemeBackgroundPartiallyTransparent(theme, - BP_PUSHBUTTON, - iState) ) - { - wxUxThemeEngine::Get()->DrawThemeParentBackground(GetHwndOf(button), hdc, &rectBtn); - } - - // draw background - wxUxThemeEngine::Get()->DrawThemeBackground(theme, hdc, BP_PUSHBUTTON, iState, - &rectBtn, NULL); - - // calculate content area margins - MARGINS margins; - wxUxThemeEngine::Get()->GetThemeMargins(theme, hdc, BP_PUSHBUTTON, iState, - TMT_CONTENTMARGINS, &rectBtn, &margins); - RECT rectClient; - ::CopyRect(&rectClient, &rectBtn); - ::InflateRect(&rectClient, -margins.cxLeftWidth, -margins.cyTopHeight); - - // if focused and !nofocus rect - if ( (state & ODS_FOCUS) && !(state & ODS_NOFOCUSRECT) ) - { - DrawFocusRect(hdc, &rectClient); - } - - if ( button->UseBgCol() ) - { - COLORREF colBg = wxColourToRGB(button->GetBackgroundColour()); - HBRUSH hbrushBackground = ::CreateSolidBrush(colBg); - - // don't overwrite the focus rect - ::InflateRect(&rectClient, -1, -1); - FillRect(hdc, &rectClient, hbrushBackground); - ::DeleteObject(hbrushBackground); - } -} -#endif // wxUSE_UXTHEME - -// VZ: should be at the very least less than wxDEFAULT_BUTTON_MARGIN -#define FOCUS_MARGIN 3 - -bool wxBitmapButton::MSWOnDraw(WXDRAWITEMSTRUCT *item) -{ -#ifndef __WXWINCE__ - long style = GetWindowLong((HWND) GetHWND(), GWL_STYLE); - if (style & BS_BITMAP) - { - // Let default procedure draw the bitmap, which is defined - // in the Windows resource. - return false; - } -#endif - - LPDRAWITEMSTRUCT lpDIS = (LPDRAWITEMSTRUCT) item; - HDC hDC = lpDIS->hDC; - UINT state = lpDIS->itemState; - bool isSelected = (state & ODS_SELECTED) != 0; - bool autoDraw = (GetWindowStyleFlag() & wxBU_AUTODRAW) != 0; - - - // choose the bitmap to use depending on the button state - wxBitmap *bitmap; - - if ( isSelected && m_bmpSelected.Ok() ) - bitmap = &m_bmpSelected; - else if ( m_bmpHover.Ok() && IsMouseInWindow() ) - bitmap = &m_bmpHover; - else if ((state & ODS_FOCUS) && m_bmpFocus.Ok()) - bitmap = &m_bmpFocus; - else if ((state & ODS_DISABLED) && m_bmpDisabled.Ok()) - bitmap = &m_bmpDisabled; - else - bitmap = &m_bmpNormal; - - if ( !bitmap->Ok() ) - return false; - - // centre the bitmap in the control area - int x = lpDIS->rcItem.left; - int y = lpDIS->rcItem.top; - int width = lpDIS->rcItem.right - x; - int height = lpDIS->rcItem.bottom - y; - int wBmp = bitmap->GetWidth(); - int hBmp = bitmap->GetHeight(); - -#if wxUSE_UXTHEME - if ( autoDraw && wxUxThemeEngine::GetIfActive() ) - { - MSWDrawXPBackground(this, item); - wxUxThemeHandle theme(this, L"BUTTON"); - - // calculate content area margins - // assuming here that each state is the same size - MARGINS margins; - wxUxThemeEngine::Get()->GetThemeMargins(theme, NULL, - BP_PUSHBUTTON, PBS_NORMAL, - TMT_CONTENTMARGINS, NULL, - &margins); - int marginX = margins.cxLeftWidth + 1; - int marginY = margins.cyTopHeight + 1; - int x1,y1; - - if ( m_windowStyle & wxBU_LEFT ) - { - x1 = x + marginX; - } - else if ( m_windowStyle & wxBU_RIGHT ) - { - x1 = x + (width - wBmp) - marginX; - } - else - { - x1 = x + (width - wBmp) / 2; - } - - if ( m_windowStyle & wxBU_TOP ) - { - y1 = y + marginY; - } - else if ( m_windowStyle & wxBU_BOTTOM ) - { - y1 = y + (height - hBmp) - marginY; - } - else - { - y1 = y + (height - hBmp) / 2; - } - - // draw the bitmap - wxDCTemp dst((WXHDC)hDC); - dst.DrawBitmap(*bitmap, x1, y1, true); - - return true; - } -#endif // wxUSE_UXTHEME - - int x1,y1; - - if(m_windowStyle & wxBU_LEFT) - x1 = x + (FOCUS_MARGIN+1); - else if(m_windowStyle & wxBU_RIGHT) - x1 = x + (width - wBmp) - (FOCUS_MARGIN+1); - else - x1 = x + (width - wBmp) / 2; - - if(m_windowStyle & wxBU_TOP) - y1 = y + (FOCUS_MARGIN+1); - else if(m_windowStyle & wxBU_BOTTOM) - y1 = y + (height - hBmp) - (FOCUS_MARGIN+1); - else - y1 = y + (height - hBmp) / 2; - - if ( isSelected && autoDraw ) - { - x1++; - y1++; - } - - // draw the face, if auto-drawing - if ( autoDraw ) - { - DrawFace((WXHDC) hDC, - lpDIS->rcItem.left, lpDIS->rcItem.top, - lpDIS->rcItem.right, lpDIS->rcItem.bottom, - isSelected); - } - - // draw the bitmap - wxDCTemp dst((WXHDC)hDC); - dst.DrawBitmap(*bitmap, x1, y1, true); - - // draw focus / disabled state, if auto-drawing - if ( (state & ODS_DISABLED) && autoDraw ) - { - DrawButtonDisable((WXHDC) hDC, - lpDIS->rcItem.left, lpDIS->rcItem.top, - lpDIS->rcItem.right, lpDIS->rcItem.bottom, - true); - } - else if ( (state & ODS_FOCUS) && autoDraw ) - { - DrawButtonFocus((WXHDC) hDC, - lpDIS->rcItem.left, - lpDIS->rcItem.top, - lpDIS->rcItem.right, - lpDIS->rcItem.bottom, - isSelected); - } - - return true; -} - -// GRG Feb/2000, support for bmp buttons with Win95/98 standard LNF - -void wxBitmapButton::DrawFace( WXHDC dc, int left, int top, - int right, int bottom, bool sel ) -{ - HPEN oldp; - HPEN penHiLight; - HPEN penLight; - HPEN penShadow; - HPEN penDkShadow; - HBRUSH brushFace; - - // create needed pens and brush - penHiLight = CreatePen(PS_SOLID, 0, GetSysColor(COLOR_3DHILIGHT)); - penLight = CreatePen(PS_SOLID, 0, GetSysColor(COLOR_3DLIGHT)); - penShadow = CreatePen(PS_SOLID, 0, GetSysColor(COLOR_3DSHADOW)); - penDkShadow = CreatePen(PS_SOLID, 0, GetSysColor(COLOR_3DDKSHADOW)); - brushFace = CreateSolidBrush(GetSysColor(COLOR_BTNFACE)); - - // draw the rectangle - RECT rect; - rect.left = left; - rect.right = right; - rect.top = top; - rect.bottom = bottom; - FillRect((HDC) dc, &rect, brushFace); - - // draw the border - oldp = (HPEN) SelectObject( (HDC) dc, sel? penDkShadow : penHiLight); - - wxDrawLine((HDC) dc, left, top, right-1, top); - wxDrawLine((HDC) dc, left, top+1, left, bottom-1); - - SelectObject( (HDC) dc, sel? penShadow : penLight); - wxDrawLine((HDC) dc, left+1, top+1, right-2, top+1); - wxDrawLine((HDC) dc, left+1, top+2, left+1, bottom-2); - - SelectObject( (HDC) dc, sel? penLight : penShadow); - wxDrawLine((HDC) dc, left+1, bottom-2, right-1, bottom-2); - wxDrawLine((HDC) dc, right-2, bottom-3, right-2, top); - - SelectObject( (HDC) dc, sel? penHiLight : penDkShadow); - wxDrawLine((HDC) dc, left, bottom-1, right+2, bottom-1); - wxDrawLine((HDC) dc, right-1, bottom-2, right-1, top-1); - - // delete allocated resources - SelectObject((HDC) dc,oldp); - DeleteObject(penHiLight); - DeleteObject(penLight); - DeleteObject(penShadow); - DeleteObject(penDkShadow); - DeleteObject(brushFace); -} - -void wxBitmapButton::DrawButtonFocus( WXHDC dc, int left, int top, int right, - int bottom, bool WXUNUSED(sel) ) -{ - RECT rect; - rect.left = left; - rect.top = top; - rect.right = right; - rect.bottom = bottom; - InflateRect( &rect, - FOCUS_MARGIN, - FOCUS_MARGIN ); - - // GRG: the focus rectangle should not move when the button is pushed! -/* - if ( sel ) - OffsetRect( &rect, 1, 1 ); -*/ - - DrawFocusRect( (HDC) dc, &rect ); -} - -void -wxBitmapButton::DrawButtonDisable( WXHDC dc, - int left, int top, int right, int bottom, - bool with_marg ) -{ - if ( !m_brushDisabled.Ok() ) - { - // draw a bitmap with two black and two background colour pixels - wxBitmap bmp(2, 2); - wxMemoryDC dc; - dc.SelectObject(bmp); - dc.SetPen(*wxBLACK_PEN); - dc.DrawPoint(0, 0); - dc.DrawPoint(1, 1); - dc.SetPen(GetBackgroundColour()); - dc.DrawPoint(0, 1); - dc.DrawPoint(1, 0); - - m_brushDisabled = wxBrush(bmp); - } - - SelectInHDC selectBrush((HDC)dc, GetHbrushOf(m_brushDisabled)); - - // ROP for "dest |= pattern" operation -- as it doesn't have a standard - // name, give it our own - static const DWORD PATTERNPAINT = 0xFA0089UL; - - if ( with_marg ) - { - left += m_marginX; - top += m_marginY; - right -= 2 * m_marginX; - bottom -= 2 * m_marginY; - } - - ::PatBlt( (HDC) dc, left, top, right, bottom, PATTERNPAINT); -} - -void wxBitmapButton::SetDefault() -{ - wxButton::SetDefault(); -} - -wxSize wxBitmapButton::DoGetBestSize() const -{ - if ( m_bmpNormal.Ok() ) - { - int width = m_bmpNormal.GetWidth(), - height = m_bmpNormal.GetHeight(); - int marginH = 0, - marginV = 0; - -#if wxUSE_UXTHEME - if ( wxUxThemeEngine::GetIfActive() ) - { - wxUxThemeHandle theme((wxBitmapButton *)this, L"BUTTON"); - - MARGINS margins; - wxUxThemeEngine::Get()->GetThemeMargins(theme, NULL, - BP_PUSHBUTTON, PBS_NORMAL, - TMT_CONTENTMARGINS, NULL, - &margins); - - // XP doesn't draw themed buttons correctly when the client area is - // smaller than 8x8 - enforce this minimum size for small bitmaps - if ( width < 8 ) - width = 8; - if ( height < 8 ) - height = 8; - - // don't add margins for the borderless buttons, they don't need - // them and it just makes them appear larger than needed - if ( !HasFlag(wxBORDER_NONE) ) - { - // we need 2 extra pixels for the focus rectangle, without them - // it's overwritten by the bitmap itself - marginH = margins.cxLeftWidth + margins.cxRightWidth + 2; - marginV = margins.cyTopHeight + margins.cyBottomHeight + 2; - } - } - else -#endif // wxUSE_UXTHEME - { - if ( !HasFlag(wxBORDER_NONE) ) - { - marginH = 2*m_marginX; - marginV = 2*m_marginY; - } - } - - wxSize best(width + marginH, height + marginV); - CacheBestSize(best); - return best; - } - - // no idea what our best size should be, defer to the base class - return wxBitmapButtonBase::DoGetBestSize(); -} - -#endif // wxUSE_BMPBUTTON +///////////////////////////////////////////////////////////////////////////// +// Name: src/msw/bmpbuttn.cpp +// Purpose: wxBitmapButton +// Author: Julian Smart +// Modified by: +// Created: 04/01/98 +// RCS-ID: $Id: bmpbuttn.cpp 42816 2006-10-31 08:50:17Z RD $ +// Copyright: (c) Julian Smart +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_BMPBUTTON + +#include "wx/bmpbuttn.h" + +#ifndef WX_PRECOMP + #include "wx/log.h" + #include "wx/dcmemory.h" + #include "wx/image.h" +#endif + +#include "wx/msw/private.h" + +#include "wx/msw/uxtheme.h" + +#if wxUSE_UXTHEME + // no need to include tmschema.h + #ifndef BP_PUSHBUTTON + #define BP_PUSHBUTTON 1 + + #define PBS_NORMAL 1 + #define PBS_HOT 2 + #define PBS_PRESSED 3 + #define PBS_DISABLED 4 + #define PBS_DEFAULTED 5 + + #define TMT_CONTENTMARGINS 3602 + #endif +#endif // wxUSE_UXTHEME + +#ifndef ODS_NOFOCUSRECT + #define ODS_NOFOCUSRECT 0x0200 +#endif + +// ---------------------------------------------------------------------------- +// macros +// ---------------------------------------------------------------------------- + +#if wxUSE_EXTENDED_RTTI + +WX_DEFINE_FLAGS( wxBitmapButtonStyle ) + +wxBEGIN_FLAGS( wxBitmapButtonStyle ) + // new style border flags, we put them first to + // use them for streaming out + wxFLAGS_MEMBER(wxBORDER_SIMPLE) + wxFLAGS_MEMBER(wxBORDER_SUNKEN) + wxFLAGS_MEMBER(wxBORDER_DOUBLE) + wxFLAGS_MEMBER(wxBORDER_RAISED) + wxFLAGS_MEMBER(wxBORDER_STATIC) + wxFLAGS_MEMBER(wxBORDER_NONE) + + // old style border flags + wxFLAGS_MEMBER(wxSIMPLE_BORDER) + wxFLAGS_MEMBER(wxSUNKEN_BORDER) + wxFLAGS_MEMBER(wxDOUBLE_BORDER) + wxFLAGS_MEMBER(wxRAISED_BORDER) + wxFLAGS_MEMBER(wxSTATIC_BORDER) + wxFLAGS_MEMBER(wxBORDER) + + // standard window styles + wxFLAGS_MEMBER(wxTAB_TRAVERSAL) + wxFLAGS_MEMBER(wxCLIP_CHILDREN) + wxFLAGS_MEMBER(wxTRANSPARENT_WINDOW) + wxFLAGS_MEMBER(wxWANTS_CHARS) + wxFLAGS_MEMBER(wxFULL_REPAINT_ON_RESIZE) + wxFLAGS_MEMBER(wxALWAYS_SHOW_SB ) + wxFLAGS_MEMBER(wxVSCROLL) + wxFLAGS_MEMBER(wxHSCROLL) + + wxFLAGS_MEMBER(wxBU_AUTODRAW) + wxFLAGS_MEMBER(wxBU_LEFT) + wxFLAGS_MEMBER(wxBU_RIGHT) + wxFLAGS_MEMBER(wxBU_TOP) + wxFLAGS_MEMBER(wxBU_BOTTOM) +wxEND_FLAGS( wxBitmapButtonStyle ) + +IMPLEMENT_DYNAMIC_CLASS_XTI(wxBitmapButton, wxButton,"wx/bmpbuttn.h") + +wxBEGIN_PROPERTIES_TABLE(wxBitmapButton) + wxPROPERTY_FLAGS( WindowStyle , wxBitmapButtonStyle , long , SetWindowStyleFlag , GetWindowStyleFlag , EMPTY_MACROVALUE, 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // style +wxEND_PROPERTIES_TABLE() + +wxBEGIN_HANDLERS_TABLE(wxBitmapButton) +wxEND_HANDLERS_TABLE() + +wxCONSTRUCTOR_5( wxBitmapButton , wxWindow* , Parent , wxWindowID , Id , wxBitmap , Bitmap , wxPoint , Position , wxSize , Size ) + +#else +IMPLEMENT_DYNAMIC_CLASS(wxBitmapButton, wxButton) +#endif + +BEGIN_EVENT_TABLE(wxBitmapButton, wxBitmapButtonBase) + EVT_SYS_COLOUR_CHANGED(wxBitmapButton::OnSysColourChanged) + EVT_ENTER_WINDOW(wxBitmapButton::OnMouseEnterOrLeave) + EVT_LEAVE_WINDOW(wxBitmapButton::OnMouseEnterOrLeave) +END_EVENT_TABLE() + +/* +TODO PROPERTIES : + +long "style" , wxBU_AUTODRAW +bool "default" , 0 +bitmap "selected" , +bitmap "focus" , +bitmap "disabled" , +*/ + +bool wxBitmapButton::Create(wxWindow *parent, wxWindowID id, + const wxBitmap& bitmap, + const wxPoint& pos, + const wxSize& size, long style, + const wxValidator& wxVALIDATOR_PARAM(validator), + const wxString& name) +{ + m_bmpNormal = bitmap; + SetName(name); + +#if wxUSE_VALIDATORS + SetValidator(validator); +#endif // wxUSE_VALIDATORS + + parent->AddChild(this); + + m_windowStyle = style; + + if ( style & wxBU_AUTODRAW ) + { + m_marginX = + m_marginY = 4; + } + + if (id == wxID_ANY) + m_windowId = NewControlId(); + else + m_windowId = id; + + long msStyle = WS_VISIBLE | WS_TABSTOP | WS_CHILD | BS_OWNERDRAW ; + + if ( m_windowStyle & wxCLIP_SIBLINGS ) + msStyle |= WS_CLIPSIBLINGS; + +#ifdef __WIN32__ + if(m_windowStyle & wxBU_LEFT) + msStyle |= BS_LEFT; + if(m_windowStyle & wxBU_RIGHT) + msStyle |= BS_RIGHT; + if(m_windowStyle & wxBU_TOP) + msStyle |= BS_TOP; + if(m_windowStyle & wxBU_BOTTOM) + msStyle |= BS_BOTTOM; +#endif + + m_hWnd = (WXHWND) CreateWindowEx( + 0, + wxT("BUTTON"), + wxEmptyString, + msStyle, + 0, 0, 0, 0, + GetWinHwnd(parent), + (HMENU)m_windowId, + wxGetInstance(), + NULL + ); + + // Subclass again for purposes of dialog editing mode + SubclassWin(m_hWnd); + + SetPosition(pos); + SetInitialSize(size); + + return true; +} + +bool wxBitmapButton::SetBackgroundColour(const wxColour& colour) +{ + if ( !wxBitmapButtonBase::SetBackgroundColour(colour) ) + { + // didn't change + return false; + } + + // invalidate the brush, it will be recreated the next time it's needed + m_brushDisabled = wxNullBrush; + + return true; +} + +void wxBitmapButton::OnSysColourChanged(wxSysColourChangedEvent& event) +{ + m_brushDisabled = wxNullBrush; + + if ( !IsEnabled() ) + { + // this change affects our current state + Refresh(); + } + + event.Skip(); +} + +void wxBitmapButton::OnMouseEnterOrLeave(wxMouseEvent& event) +{ + if ( IsEnabled() && m_bmpHover.Ok() ) + Refresh(); + + event.Skip(); +} + +void wxBitmapButton::OnSetBitmap() +{ + // if the focus bitmap is specified but hover one isn't, use the focus + // bitmap for hovering as well if this is consistent with the current + // Windows version look and feel + // + // rationale: this is compatible with the old wxGTK behaviour and also + // makes it much easier to do "the right thing" for all platforms (some of + // them, such as Windows XP, have "hot" buttons while others don't) + if ( !m_bmpHover.Ok() && + m_bmpFocus.Ok() && + wxUxThemeEngine::GetIfActive() ) + { + m_bmpHover = m_bmpFocus; + } + + // this will redraw us + wxBitmapButtonBase::OnSetBitmap(); +} + +#if wxUSE_UXTHEME +static +void MSWDrawXPBackground(wxButton *button, WXDRAWITEMSTRUCT *wxdis) +{ + LPDRAWITEMSTRUCT lpDIS = (LPDRAWITEMSTRUCT)wxdis; + HDC hdc = lpDIS->hDC; + UINT state = lpDIS->itemState; + RECT rectBtn; + CopyRect(&rectBtn, &lpDIS->rcItem); + + wxUxThemeHandle theme(button, L"BUTTON"); + int iState; + + if ( state & ODS_SELECTED ) + { + iState = PBS_PRESSED; + } + else if ( button->HasCapture() || button->IsMouseInWindow() ) + { + iState = PBS_HOT; + } + else if ( state & ODS_FOCUS ) + { + iState = PBS_DEFAULTED; + } + else if ( state & ODS_DISABLED ) + { + iState = PBS_DISABLED; + } + else + { + iState = PBS_NORMAL; + } + + // draw parent background if needed + if ( wxUxThemeEngine::Get()->IsThemeBackgroundPartiallyTransparent(theme, + BP_PUSHBUTTON, + iState) ) + { + wxUxThemeEngine::Get()->DrawThemeParentBackground(GetHwndOf(button), hdc, &rectBtn); + } + + // draw background + wxUxThemeEngine::Get()->DrawThemeBackground(theme, hdc, BP_PUSHBUTTON, iState, + &rectBtn, NULL); + + // calculate content area margins + MARGINS margins; + wxUxThemeEngine::Get()->GetThemeMargins(theme, hdc, BP_PUSHBUTTON, iState, + TMT_CONTENTMARGINS, &rectBtn, &margins); + RECT rectClient; + ::CopyRect(&rectClient, &rectBtn); + ::InflateRect(&rectClient, -margins.cxLeftWidth, -margins.cyTopHeight); + + // if focused and !nofocus rect + if ( (state & ODS_FOCUS) && !(state & ODS_NOFOCUSRECT) ) + { + DrawFocusRect(hdc, &rectClient); + } + + if ( button->UseBgCol() ) + { + COLORREF colBg = wxColourToRGB(button->GetBackgroundColour()); + HBRUSH hbrushBackground = ::CreateSolidBrush(colBg); + + // don't overwrite the focus rect + ::InflateRect(&rectClient, -1, -1); + FillRect(hdc, &rectClient, hbrushBackground); + ::DeleteObject(hbrushBackground); + } +} +#endif // wxUSE_UXTHEME + +// VZ: should be at the very least less than wxDEFAULT_BUTTON_MARGIN +#define FOCUS_MARGIN 3 + +bool wxBitmapButton::MSWOnDraw(WXDRAWITEMSTRUCT *item) +{ +#ifndef __WXWINCE__ + long style = GetWindowLong((HWND) GetHWND(), GWL_STYLE); + if (style & BS_BITMAP) + { + // Let default procedure draw the bitmap, which is defined + // in the Windows resource. + return false; + } +#endif + + LPDRAWITEMSTRUCT lpDIS = (LPDRAWITEMSTRUCT) item; + HDC hDC = lpDIS->hDC; + UINT state = lpDIS->itemState; + bool isSelected = (state & ODS_SELECTED) != 0; + bool autoDraw = (GetWindowStyleFlag() & wxBU_AUTODRAW) != 0; + + + // choose the bitmap to use depending on the button state + wxBitmap *bitmap; + + if ( isSelected && m_bmpSelected.Ok() ) + bitmap = &m_bmpSelected; + else if ( m_bmpHover.Ok() && IsMouseInWindow() ) + bitmap = &m_bmpHover; + else if ((state & ODS_FOCUS) && m_bmpFocus.Ok()) + bitmap = &m_bmpFocus; + else if ((state & ODS_DISABLED) && m_bmpDisabled.Ok()) + bitmap = &m_bmpDisabled; + else + bitmap = &m_bmpNormal; + + if ( !bitmap->Ok() ) + return false; + + // centre the bitmap in the control area + int x = lpDIS->rcItem.left; + int y = lpDIS->rcItem.top; + int width = lpDIS->rcItem.right - x; + int height = lpDIS->rcItem.bottom - y; + int wBmp = bitmap->GetWidth(); + int hBmp = bitmap->GetHeight(); + +#if wxUSE_UXTHEME + if ( autoDraw && wxUxThemeEngine::GetIfActive() ) + { + MSWDrawXPBackground(this, item); + wxUxThemeHandle theme(this, L"BUTTON"); + + // calculate content area margins + // assuming here that each state is the same size + MARGINS margins; + wxUxThemeEngine::Get()->GetThemeMargins(theme, NULL, + BP_PUSHBUTTON, PBS_NORMAL, + TMT_CONTENTMARGINS, NULL, + &margins); + int marginX = margins.cxLeftWidth + 1; + int marginY = margins.cyTopHeight + 1; + int x1,y1; + + if ( m_windowStyle & wxBU_LEFT ) + { + x1 = x + marginX; + } + else if ( m_windowStyle & wxBU_RIGHT ) + { + x1 = x + (width - wBmp) - marginX; + } + else + { + x1 = x + (width - wBmp) / 2; + } + + if ( m_windowStyle & wxBU_TOP ) + { + y1 = y + marginY; + } + else if ( m_windowStyle & wxBU_BOTTOM ) + { + y1 = y + (height - hBmp) - marginY; + } + else + { + y1 = y + (height - hBmp) / 2; + } + + // draw the bitmap + wxDCTemp dst((WXHDC)hDC); + dst.DrawBitmap(*bitmap, x1, y1, true); + + return true; + } +#endif // wxUSE_UXTHEME + + int x1,y1; + + if(m_windowStyle & wxBU_LEFT) + x1 = x + (FOCUS_MARGIN+1); + else if(m_windowStyle & wxBU_RIGHT) + x1 = x + (width - wBmp) - (FOCUS_MARGIN+1); + else + x1 = x + (width - wBmp) / 2; + + if(m_windowStyle & wxBU_TOP) + y1 = y + (FOCUS_MARGIN+1); + else if(m_windowStyle & wxBU_BOTTOM) + y1 = y + (height - hBmp) - (FOCUS_MARGIN+1); + else + y1 = y + (height - hBmp) / 2; + + if ( isSelected && autoDraw ) + { + x1++; + y1++; + } + + // draw the face, if auto-drawing + if ( autoDraw ) + { + DrawFace((WXHDC) hDC, + lpDIS->rcItem.left, lpDIS->rcItem.top, + lpDIS->rcItem.right, lpDIS->rcItem.bottom, + isSelected); + } + + // draw the bitmap + wxDCTemp dst((WXHDC)hDC); + dst.DrawBitmap(*bitmap, x1, y1, true); + + // draw focus / disabled state, if auto-drawing + if ( (state & ODS_DISABLED) && autoDraw ) + { + DrawButtonDisable((WXHDC) hDC, + lpDIS->rcItem.left, lpDIS->rcItem.top, + lpDIS->rcItem.right, lpDIS->rcItem.bottom, + true); + } + else if ( (state & ODS_FOCUS) && autoDraw ) + { + DrawButtonFocus((WXHDC) hDC, + lpDIS->rcItem.left, + lpDIS->rcItem.top, + lpDIS->rcItem.right, + lpDIS->rcItem.bottom, + isSelected); + } + + return true; +} + +// GRG Feb/2000, support for bmp buttons with Win95/98 standard LNF + +void wxBitmapButton::DrawFace( WXHDC dc, int left, int top, + int right, int bottom, bool sel ) +{ + HPEN oldp; + HPEN penHiLight; + HPEN penLight; + HPEN penShadow; + HPEN penDkShadow; + HBRUSH brushFace; + + // create needed pens and brush + penHiLight = CreatePen(PS_SOLID, 0, GetSysColor(COLOR_3DHILIGHT)); + penLight = CreatePen(PS_SOLID, 0, GetSysColor(COLOR_3DLIGHT)); + penShadow = CreatePen(PS_SOLID, 0, GetSysColor(COLOR_3DSHADOW)); + penDkShadow = CreatePen(PS_SOLID, 0, GetSysColor(COLOR_3DDKSHADOW)); + brushFace = CreateSolidBrush(GetSysColor(COLOR_BTNFACE)); + + // draw the rectangle + RECT rect; + rect.left = left; + rect.right = right; + rect.top = top; + rect.bottom = bottom; + FillRect((HDC) dc, &rect, brushFace); + + // draw the border + oldp = (HPEN) SelectObject( (HDC) dc, sel? penDkShadow : penHiLight); + + wxDrawLine((HDC) dc, left, top, right-1, top); + wxDrawLine((HDC) dc, left, top+1, left, bottom-1); + + SelectObject( (HDC) dc, sel? penShadow : penLight); + wxDrawLine((HDC) dc, left+1, top+1, right-2, top+1); + wxDrawLine((HDC) dc, left+1, top+2, left+1, bottom-2); + + SelectObject( (HDC) dc, sel? penLight : penShadow); + wxDrawLine((HDC) dc, left+1, bottom-2, right-1, bottom-2); + wxDrawLine((HDC) dc, right-2, bottom-3, right-2, top); + + SelectObject( (HDC) dc, sel? penHiLight : penDkShadow); + wxDrawLine((HDC) dc, left, bottom-1, right+2, bottom-1); + wxDrawLine((HDC) dc, right-1, bottom-2, right-1, top-1); + + // delete allocated resources + SelectObject((HDC) dc,oldp); + DeleteObject(penHiLight); + DeleteObject(penLight); + DeleteObject(penShadow); + DeleteObject(penDkShadow); + DeleteObject(brushFace); +} + +void wxBitmapButton::DrawButtonFocus( WXHDC dc, int left, int top, int right, + int bottom, bool WXUNUSED(sel) ) +{ + RECT rect; + rect.left = left; + rect.top = top; + rect.right = right; + rect.bottom = bottom; + InflateRect( &rect, - FOCUS_MARGIN, - FOCUS_MARGIN ); + + // GRG: the focus rectangle should not move when the button is pushed! +/* + if ( sel ) + OffsetRect( &rect, 1, 1 ); +*/ + + DrawFocusRect( (HDC) dc, &rect ); +} + +void +wxBitmapButton::DrawButtonDisable( WXHDC dc, + int left, int top, int right, int bottom, + bool with_marg ) +{ + if ( !m_brushDisabled.Ok() ) + { + // draw a bitmap with two black and two background colour pixels + wxBitmap bmp(2, 2); + wxMemoryDC dc; + dc.SelectObject(bmp); + dc.SetPen(*wxBLACK_PEN); + dc.DrawPoint(0, 0); + dc.DrawPoint(1, 1); + dc.SetPen(GetBackgroundColour()); + dc.DrawPoint(0, 1); + dc.DrawPoint(1, 0); + + m_brushDisabled = wxBrush(bmp); + } + + SelectInHDC selectBrush((HDC)dc, GetHbrushOf(m_brushDisabled)); + + // ROP for "dest |= pattern" operation -- as it doesn't have a standard + // name, give it our own + static const DWORD PATTERNPAINT = 0xFA0089UL; + + if ( with_marg ) + { + left += m_marginX; + top += m_marginY; + right -= 2 * m_marginX; + bottom -= 2 * m_marginY; + } + + ::PatBlt( (HDC) dc, left, top, right, bottom, PATTERNPAINT); +} + +void wxBitmapButton::SetDefault() +{ + wxButton::SetDefault(); +} + +wxSize wxBitmapButton::DoGetBestSize() const +{ + if ( m_bmpNormal.Ok() ) + { + int width = m_bmpNormal.GetWidth(), + height = m_bmpNormal.GetHeight(); + int marginH = 0, + marginV = 0; + +#if wxUSE_UXTHEME + if ( wxUxThemeEngine::GetIfActive() ) + { + wxUxThemeHandle theme((wxBitmapButton *)this, L"BUTTON"); + + MARGINS margins; + wxUxThemeEngine::Get()->GetThemeMargins(theme, NULL, + BP_PUSHBUTTON, PBS_NORMAL, + TMT_CONTENTMARGINS, NULL, + &margins); + + // XP doesn't draw themed buttons correctly when the client area is + // smaller than 8x8 - enforce this minimum size for small bitmaps + if ( width < 8 ) + width = 8; + if ( height < 8 ) + height = 8; + + // don't add margins for the borderless buttons, they don't need + // them and it just makes them appear larger than needed + if ( !HasFlag(wxBORDER_NONE) ) + { + // we need 2 extra pixels for the focus rectangle, without them + // it's overwritten by the bitmap itself + marginH = margins.cxLeftWidth + margins.cxRightWidth + 2; + marginV = margins.cyTopHeight + margins.cyBottomHeight + 2; + } + } + else +#endif // wxUSE_UXTHEME + { + if ( !HasFlag(wxBORDER_NONE) ) + { + marginH = 2*m_marginX; + marginV = 2*m_marginY; + } + } + + wxSize best(width + marginH, height + marginV); + CacheBestSize(best); + return best; + } + + // no idea what our best size should be, defer to the base class + return wxBitmapButtonBase::DoGetBestSize(); +} + +#endif // wxUSE_BMPBUTTON diff --git a/Externals/wxWidgets/src/msw/brush.cpp b/Externals/wxWidgets/src/msw/brush.cpp index ac03729cb2..c0bbee874a 100644 --- a/Externals/wxWidgets/src/msw/brush.cpp +++ b/Externals/wxWidgets/src/msw/brush.cpp @@ -1,327 +1,327 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/msw/brush.cpp -// Purpose: wxBrush -// Author: Julian Smart -// Modified by: -// Created: 04/01/98 -// RCS-ID: $Id: brush.cpp 42776 2006-10-30 22:03:53Z VZ $ -// Copyright: (c) Julian Smart -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#include "wx/brush.h" - -#ifndef WX_PRECOMP - #include "wx/list.h" - #include "wx/utils.h" - #include "wx/app.h" -#endif // WX_PRECOMP - -#include "wx/msw/private.h" - -// ---------------------------------------------------------------------------- -// private classes -// ---------------------------------------------------------------------------- - -class WXDLLEXPORT wxBrushRefData: public wxGDIRefData -{ -public: - wxBrushRefData(const wxColour& colour = wxNullColour, int style = wxSOLID); - wxBrushRefData(const wxBitmap& stipple); - wxBrushRefData(const wxBrushRefData& data); - virtual ~wxBrushRefData(); - - bool operator==(const wxBrushRefData& data) const; - - HBRUSH GetHBRUSH(); - void Free(); - - const wxColour& GetColour() const { return m_colour; } - int GetStyle() const { return m_style; } - wxBitmap *GetStipple() { return &m_stipple; } - - void SetColour(const wxColour& colour) { Free(); m_colour = colour; } - void SetStyle(int style) { Free(); m_style = style; } - void SetStipple(const wxBitmap& stipple) { Free(); DoSetStipple(stipple); } - -private: - void DoSetStipple(const wxBitmap& stipple); - - int m_style; - wxBitmap m_stipple; - wxColour m_colour; - HBRUSH m_hBrush; - - // no assignment operator, the objects of this class are shared and never - // assigned after being created once - wxBrushRefData& operator=(const wxBrushRefData&); -}; - -#define M_BRUSHDATA ((wxBrushRefData *)m_refData) - -// ============================================================================ -// wxBrushRefData implementation -// ============================================================================ - -IMPLEMENT_DYNAMIC_CLASS(wxBrush, wxGDIObject) - -// ---------------------------------------------------------------------------- -// wxBrushRefData ctors/dtor -// ---------------------------------------------------------------------------- - -wxBrushRefData::wxBrushRefData(const wxColour& colour, int style) - : m_colour(colour) -{ - m_style = style; - - m_hBrush = NULL; -} - -wxBrushRefData::wxBrushRefData(const wxBitmap& stipple) -{ - DoSetStipple(stipple); - - m_hBrush = NULL; -} - -wxBrushRefData::wxBrushRefData(const wxBrushRefData& data) - : wxGDIRefData(), - m_stipple(data.m_stipple), - m_colour(data.m_colour) -{ - m_style = data.m_style; - - // we can't share HBRUSH, we'd need to create another one ourselves - m_hBrush = NULL; -} - -wxBrushRefData::~wxBrushRefData() -{ - Free(); -} - -// ---------------------------------------------------------------------------- -// wxBrushRefData accesors -// ---------------------------------------------------------------------------- - -bool wxBrushRefData::operator==(const wxBrushRefData& data) const -{ - // don't compare HBRUSHes - return m_style == data.m_style && - m_colour == data.m_colour && - m_stipple.IsSameAs(data.m_stipple); -} - -void wxBrushRefData::DoSetStipple(const wxBitmap& stipple) -{ - m_stipple = stipple; - m_style = stipple.GetMask() ? wxSTIPPLE_MASK_OPAQUE : wxSTIPPLE; -} - -// ---------------------------------------------------------------------------- -// wxBrushRefData resource handling -// ---------------------------------------------------------------------------- - -void wxBrushRefData::Free() -{ - if ( m_hBrush ) - { - ::DeleteObject(m_hBrush); - - m_hBrush = NULL; - } -} - -#if !defined(__WXMICROWIN__) && !defined(__WXWINCE__) - -static int TranslateHatchStyle(int style) -{ - switch ( style ) - { - case wxBDIAGONAL_HATCH: return HS_BDIAGONAL; - case wxCROSSDIAG_HATCH: return HS_DIAGCROSS; - case wxFDIAGONAL_HATCH: return HS_FDIAGONAL; - case wxCROSS_HATCH: return HS_CROSS; - case wxHORIZONTAL_HATCH:return HS_HORIZONTAL; - case wxVERTICAL_HATCH: return HS_VERTICAL; - default: return -1; - } -} - -#endif // !__WXMICROWIN__ && !__WXWINCE__ - -HBRUSH wxBrushRefData::GetHBRUSH() -{ - if ( !m_hBrush ) - { -#if !defined(__WXMICROWIN__) && !defined(__WXWINCE__) - int hatchStyle = TranslateHatchStyle(m_style); - if ( hatchStyle == -1 ) -#endif // !__WXMICROWIN__ && !__WXWINCE__ - { - switch ( m_style ) - { - case wxTRANSPARENT: - m_hBrush = (HBRUSH)::GetStockObject(NULL_BRUSH); - break; - - case wxSTIPPLE: - m_hBrush = ::CreatePatternBrush(GetHbitmapOf(m_stipple)); - break; - - case wxSTIPPLE_MASK_OPAQUE: - m_hBrush = ::CreatePatternBrush((HBITMAP)m_stipple.GetMask() - ->GetMaskBitmap()); - break; - - default: - wxFAIL_MSG( _T("unknown brush style") ); - // fall through - - case wxSOLID: - m_hBrush = ::CreateSolidBrush(m_colour.GetPixel()); - break; - } - } -#ifndef __WXWINCE__ - else // create a hatched brush - { - m_hBrush = ::CreateHatchBrush(hatchStyle, m_colour.GetPixel()); - } -#endif - - if ( !m_hBrush ) - { - wxLogLastError(_T("CreateXXXBrush()")); - } - } - - return m_hBrush; -} - -// ============================================================================ -// wxBrush implementation -// ============================================================================ - -// ---------------------------------------------------------------------------- -// wxBrush ctors/dtor -// ---------------------------------------------------------------------------- - -wxBrush::wxBrush() -{ -} - -wxBrush::wxBrush(const wxColour& col, int style) -{ - m_refData = new wxBrushRefData(col, style); -} - -wxBrush::wxBrush(const wxBitmap& stipple) -{ - m_refData = new wxBrushRefData(stipple); -} - -wxBrush::~wxBrush() -{ -} - -// ---------------------------------------------------------------------------- -// wxBrush house keeping stuff -// ---------------------------------------------------------------------------- - -bool wxBrush::operator==(const wxBrush& brush) const -{ - const wxBrushRefData *brushData = (wxBrushRefData *)brush.m_refData; - - // an invalid brush is considered to be only equal to another invalid brush - return m_refData ? (brushData && *M_BRUSHDATA == *brushData) : !brushData; -} - -wxObjectRefData *wxBrush::CreateRefData() const -{ - return new wxBrushRefData; -} - -wxObjectRefData *wxBrush::CloneRefData(const wxObjectRefData *data) const -{ - return new wxBrushRefData(*(const wxBrushRefData *)data); -} - -// ---------------------------------------------------------------------------- -// wxBrush accessors -// ---------------------------------------------------------------------------- - -wxColour wxBrush::GetColour() const -{ - wxCHECK_MSG( Ok(), wxNullColour, _T("invalid brush") ); - - return M_BRUSHDATA->GetColour(); -} - -int wxBrush::GetStyle() const -{ - wxCHECK_MSG( Ok(), 0, _T("invalid brush") ); - - return M_BRUSHDATA->GetStyle(); -} - -wxBitmap *wxBrush::GetStipple() const -{ - wxCHECK_MSG( Ok(), NULL, _T("invalid brush") ); - - return M_BRUSHDATA->GetStipple(); -} - -WXHANDLE wxBrush::GetResourceHandle() const -{ - wxCHECK_MSG( Ok(), FALSE, _T("invalid brush") ); - - return (WXHANDLE)M_BRUSHDATA->GetHBRUSH(); -} - -// ---------------------------------------------------------------------------- -// wxBrush setters -// ---------------------------------------------------------------------------- - -void wxBrush::SetColour(const wxColour& col) -{ - AllocExclusive(); - - M_BRUSHDATA->SetColour(col); -} - -void wxBrush::SetColour(unsigned char r, unsigned char g, unsigned char b) -{ - AllocExclusive(); - - M_BRUSHDATA->SetColour(wxColour(r, g, b)); -} - -void wxBrush::SetStyle(int style) -{ - AllocExclusive(); - - M_BRUSHDATA->SetStyle(style); -} - -void wxBrush::SetStipple(const wxBitmap& stipple) -{ - AllocExclusive(); - - M_BRUSHDATA->SetStipple(stipple); -} +///////////////////////////////////////////////////////////////////////////// +// Name: src/msw/brush.cpp +// Purpose: wxBrush +// Author: Julian Smart +// Modified by: +// Created: 04/01/98 +// RCS-ID: $Id: brush.cpp 42776 2006-10-30 22:03:53Z VZ $ +// Copyright: (c) Julian Smart +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#include "wx/brush.h" + +#ifndef WX_PRECOMP + #include "wx/list.h" + #include "wx/utils.h" + #include "wx/app.h" +#endif // WX_PRECOMP + +#include "wx/msw/private.h" + +// ---------------------------------------------------------------------------- +// private classes +// ---------------------------------------------------------------------------- + +class WXDLLEXPORT wxBrushRefData: public wxGDIRefData +{ +public: + wxBrushRefData(const wxColour& colour = wxNullColour, int style = wxSOLID); + wxBrushRefData(const wxBitmap& stipple); + wxBrushRefData(const wxBrushRefData& data); + virtual ~wxBrushRefData(); + + bool operator==(const wxBrushRefData& data) const; + + HBRUSH GetHBRUSH(); + void Free(); + + const wxColour& GetColour() const { return m_colour; } + int GetStyle() const { return m_style; } + wxBitmap *GetStipple() { return &m_stipple; } + + void SetColour(const wxColour& colour) { Free(); m_colour = colour; } + void SetStyle(int style) { Free(); m_style = style; } + void SetStipple(const wxBitmap& stipple) { Free(); DoSetStipple(stipple); } + +private: + void DoSetStipple(const wxBitmap& stipple); + + int m_style; + wxBitmap m_stipple; + wxColour m_colour; + HBRUSH m_hBrush; + + // no assignment operator, the objects of this class are shared and never + // assigned after being created once + wxBrushRefData& operator=(const wxBrushRefData&); +}; + +#define M_BRUSHDATA ((wxBrushRefData *)m_refData) + +// ============================================================================ +// wxBrushRefData implementation +// ============================================================================ + +IMPLEMENT_DYNAMIC_CLASS(wxBrush, wxGDIObject) + +// ---------------------------------------------------------------------------- +// wxBrushRefData ctors/dtor +// ---------------------------------------------------------------------------- + +wxBrushRefData::wxBrushRefData(const wxColour& colour, int style) + : m_colour(colour) +{ + m_style = style; + + m_hBrush = NULL; +} + +wxBrushRefData::wxBrushRefData(const wxBitmap& stipple) +{ + DoSetStipple(stipple); + + m_hBrush = NULL; +} + +wxBrushRefData::wxBrushRefData(const wxBrushRefData& data) + : wxGDIRefData(), + m_stipple(data.m_stipple), + m_colour(data.m_colour) +{ + m_style = data.m_style; + + // we can't share HBRUSH, we'd need to create another one ourselves + m_hBrush = NULL; +} + +wxBrushRefData::~wxBrushRefData() +{ + Free(); +} + +// ---------------------------------------------------------------------------- +// wxBrushRefData accesors +// ---------------------------------------------------------------------------- + +bool wxBrushRefData::operator==(const wxBrushRefData& data) const +{ + // don't compare HBRUSHes + return m_style == data.m_style && + m_colour == data.m_colour && + m_stipple.IsSameAs(data.m_stipple); +} + +void wxBrushRefData::DoSetStipple(const wxBitmap& stipple) +{ + m_stipple = stipple; + m_style = stipple.GetMask() ? wxSTIPPLE_MASK_OPAQUE : wxSTIPPLE; +} + +// ---------------------------------------------------------------------------- +// wxBrushRefData resource handling +// ---------------------------------------------------------------------------- + +void wxBrushRefData::Free() +{ + if ( m_hBrush ) + { + ::DeleteObject(m_hBrush); + + m_hBrush = NULL; + } +} + +#if !defined(__WXMICROWIN__) && !defined(__WXWINCE__) + +static int TranslateHatchStyle(int style) +{ + switch ( style ) + { + case wxBDIAGONAL_HATCH: return HS_BDIAGONAL; + case wxCROSSDIAG_HATCH: return HS_DIAGCROSS; + case wxFDIAGONAL_HATCH: return HS_FDIAGONAL; + case wxCROSS_HATCH: return HS_CROSS; + case wxHORIZONTAL_HATCH:return HS_HORIZONTAL; + case wxVERTICAL_HATCH: return HS_VERTICAL; + default: return -1; + } +} + +#endif // !__WXMICROWIN__ && !__WXWINCE__ + +HBRUSH wxBrushRefData::GetHBRUSH() +{ + if ( !m_hBrush ) + { +#if !defined(__WXMICROWIN__) && !defined(__WXWINCE__) + int hatchStyle = TranslateHatchStyle(m_style); + if ( hatchStyle == -1 ) +#endif // !__WXMICROWIN__ && !__WXWINCE__ + { + switch ( m_style ) + { + case wxTRANSPARENT: + m_hBrush = (HBRUSH)::GetStockObject(NULL_BRUSH); + break; + + case wxSTIPPLE: + m_hBrush = ::CreatePatternBrush(GetHbitmapOf(m_stipple)); + break; + + case wxSTIPPLE_MASK_OPAQUE: + m_hBrush = ::CreatePatternBrush((HBITMAP)m_stipple.GetMask() + ->GetMaskBitmap()); + break; + + default: + wxFAIL_MSG( _T("unknown brush style") ); + // fall through + + case wxSOLID: + m_hBrush = ::CreateSolidBrush(m_colour.GetPixel()); + break; + } + } +#ifndef __WXWINCE__ + else // create a hatched brush + { + m_hBrush = ::CreateHatchBrush(hatchStyle, m_colour.GetPixel()); + } +#endif + + if ( !m_hBrush ) + { + wxLogLastError(_T("CreateXXXBrush()")); + } + } + + return m_hBrush; +} + +// ============================================================================ +// wxBrush implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// wxBrush ctors/dtor +// ---------------------------------------------------------------------------- + +wxBrush::wxBrush() +{ +} + +wxBrush::wxBrush(const wxColour& col, int style) +{ + m_refData = new wxBrushRefData(col, style); +} + +wxBrush::wxBrush(const wxBitmap& stipple) +{ + m_refData = new wxBrushRefData(stipple); +} + +wxBrush::~wxBrush() +{ +} + +// ---------------------------------------------------------------------------- +// wxBrush house keeping stuff +// ---------------------------------------------------------------------------- + +bool wxBrush::operator==(const wxBrush& brush) const +{ + const wxBrushRefData *brushData = (wxBrushRefData *)brush.m_refData; + + // an invalid brush is considered to be only equal to another invalid brush + return m_refData ? (brushData && *M_BRUSHDATA == *brushData) : !brushData; +} + +wxObjectRefData *wxBrush::CreateRefData() const +{ + return new wxBrushRefData; +} + +wxObjectRefData *wxBrush::CloneRefData(const wxObjectRefData *data) const +{ + return new wxBrushRefData(*(const wxBrushRefData *)data); +} + +// ---------------------------------------------------------------------------- +// wxBrush accessors +// ---------------------------------------------------------------------------- + +wxColour wxBrush::GetColour() const +{ + wxCHECK_MSG( Ok(), wxNullColour, _T("invalid brush") ); + + return M_BRUSHDATA->GetColour(); +} + +int wxBrush::GetStyle() const +{ + wxCHECK_MSG( Ok(), 0, _T("invalid brush") ); + + return M_BRUSHDATA->GetStyle(); +} + +wxBitmap *wxBrush::GetStipple() const +{ + wxCHECK_MSG( Ok(), NULL, _T("invalid brush") ); + + return M_BRUSHDATA->GetStipple(); +} + +WXHANDLE wxBrush::GetResourceHandle() const +{ + wxCHECK_MSG( Ok(), FALSE, _T("invalid brush") ); + + return (WXHANDLE)M_BRUSHDATA->GetHBRUSH(); +} + +// ---------------------------------------------------------------------------- +// wxBrush setters +// ---------------------------------------------------------------------------- + +void wxBrush::SetColour(const wxColour& col) +{ + AllocExclusive(); + + M_BRUSHDATA->SetColour(col); +} + +void wxBrush::SetColour(unsigned char r, unsigned char g, unsigned char b) +{ + AllocExclusive(); + + M_BRUSHDATA->SetColour(wxColour(r, g, b)); +} + +void wxBrush::SetStyle(int style) +{ + AllocExclusive(); + + M_BRUSHDATA->SetStyle(style); +} + +void wxBrush::SetStipple(const wxBitmap& stipple) +{ + AllocExclusive(); + + M_BRUSHDATA->SetStipple(stipple); +} diff --git a/Externals/wxWidgets/src/msw/button.cpp b/Externals/wxWidgets/src/msw/button.cpp index 635e4b9269..20e8fbcc04 100644 --- a/Externals/wxWidgets/src/msw/button.cpp +++ b/Externals/wxWidgets/src/msw/button.cpp @@ -1,890 +1,890 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/msw/button.cpp -// Purpose: wxButton -// Author: Julian Smart -// Modified by: -// Created: 04/01/98 -// RCS-ID: $Id: button.cpp 51575 2008-02-06 19:58:30Z VZ $ -// Copyright: (c) Julian Smart -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_BUTTON - -#include "wx/button.h" - -#ifndef WX_PRECOMP - #include "wx/app.h" - #include "wx/brush.h" - #include "wx/panel.h" - #include "wx/bmpbuttn.h" - #include "wx/settings.h" - #include "wx/dcscreen.h" - #include "wx/dcclient.h" - #include "wx/toplevel.h" -#endif - -#include "wx/stockitem.h" -#include "wx/tokenzr.h" -#include "wx/msw/private.h" - -#if wxUSE_UXTHEME - #include "wx/msw/uxtheme.h" - - // no need to include tmschema.h - #ifndef BP_PUSHBUTTON - #define BP_PUSHBUTTON 1 - - #define PBS_NORMAL 1 - #define PBS_HOT 2 - #define PBS_PRESSED 3 - #define PBS_DISABLED 4 - #define PBS_DEFAULTED 5 - - #define TMT_CONTENTMARGINS 3602 - #endif -#endif // wxUSE_UXTHEME - -#ifndef WM_THEMECHANGED - #define WM_THEMECHANGED 0x031A -#endif - -#ifndef ODS_NOACCEL - #define ODS_NOACCEL 0x0100 -#endif - -#ifndef ODS_NOFOCUSRECT - #define ODS_NOFOCUSRECT 0x0200 -#endif - -// ---------------------------------------------------------------------------- -// macros -// ---------------------------------------------------------------------------- - -#if wxUSE_EXTENDED_RTTI - -WX_DEFINE_FLAGS( wxButtonStyle ) - -wxBEGIN_FLAGS( wxButtonStyle ) - // new style border flags, we put them first to - // use them for streaming out - wxFLAGS_MEMBER(wxBORDER_SIMPLE) - wxFLAGS_MEMBER(wxBORDER_SUNKEN) - wxFLAGS_MEMBER(wxBORDER_DOUBLE) - wxFLAGS_MEMBER(wxBORDER_RAISED) - wxFLAGS_MEMBER(wxBORDER_STATIC) - wxFLAGS_MEMBER(wxBORDER_NONE) - - // old style border flags - wxFLAGS_MEMBER(wxSIMPLE_BORDER) - wxFLAGS_MEMBER(wxSUNKEN_BORDER) - wxFLAGS_MEMBER(wxDOUBLE_BORDER) - wxFLAGS_MEMBER(wxRAISED_BORDER) - wxFLAGS_MEMBER(wxSTATIC_BORDER) - wxFLAGS_MEMBER(wxBORDER) - - // standard window styles - wxFLAGS_MEMBER(wxTAB_TRAVERSAL) - wxFLAGS_MEMBER(wxCLIP_CHILDREN) - wxFLAGS_MEMBER(wxTRANSPARENT_WINDOW) - wxFLAGS_MEMBER(wxWANTS_CHARS) - wxFLAGS_MEMBER(wxFULL_REPAINT_ON_RESIZE) - wxFLAGS_MEMBER(wxALWAYS_SHOW_SB ) - wxFLAGS_MEMBER(wxVSCROLL) - wxFLAGS_MEMBER(wxHSCROLL) - - wxFLAGS_MEMBER(wxBU_LEFT) - wxFLAGS_MEMBER(wxBU_RIGHT) - wxFLAGS_MEMBER(wxBU_TOP) - wxFLAGS_MEMBER(wxBU_BOTTOM) - wxFLAGS_MEMBER(wxBU_EXACTFIT) -wxEND_FLAGS( wxButtonStyle ) - -IMPLEMENT_DYNAMIC_CLASS_XTI(wxButton, wxControl,"wx/button.h") - -wxBEGIN_PROPERTIES_TABLE(wxButton) - wxEVENT_PROPERTY( Click , wxEVT_COMMAND_BUTTON_CLICKED , wxCommandEvent) - - wxPROPERTY( Font , wxFont , SetFont , GetFont , EMPTY_MACROVALUE, 0 /*flags*/ , wxT("Helpstring") , wxT("group")) - wxPROPERTY( Label, wxString , SetLabel, GetLabel, wxString(), 0 /*flags*/ , wxT("Helpstring") , wxT("group") ) - - wxPROPERTY_FLAGS( WindowStyle , wxButtonStyle , long , SetWindowStyleFlag , GetWindowStyleFlag , EMPTY_MACROVALUE , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // style - -wxEND_PROPERTIES_TABLE() - -wxBEGIN_HANDLERS_TABLE(wxButton) -wxEND_HANDLERS_TABLE() - -wxCONSTRUCTOR_6( wxButton , wxWindow* , Parent , wxWindowID , Id , wxString , Label , wxPoint , Position , wxSize , Size , long , WindowStyle ) - - -#else -IMPLEMENT_DYNAMIC_CLASS(wxButton, wxControl) -#endif - -// this macro tries to adjust the default button height to a reasonable value -// using the char height as the base -#define BUTTON_HEIGHT_FROM_CHAR_HEIGHT(cy) (11*EDIT_HEIGHT_FROM_CHAR_HEIGHT(cy)/10) - -// ============================================================================ -// implementation -// ============================================================================ - -// ---------------------------------------------------------------------------- -// creation/destruction -// ---------------------------------------------------------------------------- - -bool wxButton::Create(wxWindow *parent, - wxWindowID id, - const wxString& lbl, - const wxPoint& pos, - const wxSize& size, - long style, - const wxValidator& validator, - const wxString& name) -{ - wxString label(lbl); - if (label.empty() && wxIsStockID(id)) - { - // On Windows, some buttons aren't supposed to have - // mnemonics, so strip them out. - - label = wxGetStockLabel(id -#if defined(__WXMSW__) || defined(__WXWINCE__) - , ( id != wxID_OK && - id != wxID_CANCEL && - id != wxID_CLOSE ) -#endif - ); - } - - if ( !CreateControl(parent, id, pos, size, style, validator, name) ) - return false; - - WXDWORD exstyle; - WXDWORD msStyle = MSWGetStyle(style, &exstyle); - -#ifdef __WIN32__ - // if the label contains several lines we must explicitly tell the button - // about it or it wouldn't draw it correctly ("\n"s would just appear as - // black boxes) - // - // NB: we do it here and not in MSWGetStyle() because we need the label - // value and m_label is not set yet when MSWGetStyle() is called; - // besides changing BS_MULTILINE during run-time is pointless anyhow - if ( label.find(_T('\n')) != wxString::npos ) - { - msStyle |= BS_MULTILINE; - } -#endif // __WIN32__ - - return MSWCreateControl(_T("BUTTON"), msStyle, pos, size, label, exstyle); -} - -wxButton::~wxButton() -{ - wxTopLevelWindow *tlw = wxDynamicCast(wxGetTopLevelParent(this), wxTopLevelWindow); - if ( tlw && tlw->GetTmpDefaultItem() == this ) - { - UnsetTmpDefault(); - } -} - -// ---------------------------------------------------------------------------- -// flags -// ---------------------------------------------------------------------------- - -WXDWORD wxButton::MSWGetStyle(long style, WXDWORD *exstyle) const -{ - // buttons never have an external border, they draw their own one - WXDWORD msStyle = wxControl::MSWGetStyle - ( - (style & ~wxBORDER_MASK) | wxBORDER_NONE, exstyle - ); - - // we must use WS_CLIPSIBLINGS with the buttons or they would draw over - // each other in any resizeable dialog which has more than one button in - // the bottom - msStyle |= WS_CLIPSIBLINGS; - -#ifdef __WIN32__ - // don't use "else if" here: weird as it is, but you may combine wxBU_LEFT - // and wxBU_RIGHT to get BS_CENTER! - if ( style & wxBU_LEFT ) - msStyle |= BS_LEFT; - if ( style & wxBU_RIGHT ) - msStyle |= BS_RIGHT; - if ( style & wxBU_TOP ) - msStyle |= BS_TOP; - if ( style & wxBU_BOTTOM ) - msStyle |= BS_BOTTOM; -#ifndef __WXWINCE__ - // flat 2d buttons - if ( style & wxNO_BORDER ) - msStyle |= BS_FLAT; -#endif // __WXWINCE__ -#endif // __WIN32__ - - return msStyle; -} - -// ---------------------------------------------------------------------------- -// size management including autosizing -// ---------------------------------------------------------------------------- - -wxSize wxButton::DoGetBestSize() const -{ - wxClientDC dc(wx_const_cast(wxButton *, this)); - dc.SetFont(GetFont()); - - wxCoord wBtn, - hBtn; - dc.GetMultiLineTextExtent(GetLabelText(), &wBtn, &hBtn); - - // add a margin -- the button is wider than just its label - wBtn += 3*GetCharWidth(); - hBtn = BUTTON_HEIGHT_FROM_CHAR_HEIGHT(hBtn); - - // all buttons have at least the standard size unless the user explicitly - // wants them to be of smaller size and used wxBU_EXACTFIT style when - // creating the button - if ( !HasFlag(wxBU_EXACTFIT) ) - { - wxSize sz = GetDefaultSize(); - if (wBtn > sz.x) - sz.x = wBtn; - if (hBtn > sz.y) - sz.y = hBtn; - - return sz; - } - - wxSize best(wBtn, hBtn); - CacheBestSize(best); - return best; -} - -/* static */ -wxSize wxButtonBase::GetDefaultSize() -{ - static wxSize s_sizeBtn; - - if ( s_sizeBtn.x == 0 ) - { - wxScreenDC dc; - dc.SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT)); - - // the size of a standard button in the dialog units is 50x14, - // translate this to pixels - // NB1: the multipliers come from the Windows convention - // NB2: the extra +1/+2 were needed to get the size be the same as the - // size of the buttons in the standard dialog - I don't know how - // this happens, but on my system this size is 75x23 in pixels and - // 23*8 isn't even divisible by 14... Would be nice to understand - // why these constants are needed though! - s_sizeBtn.x = (50 * (dc.GetCharWidth() + 1))/4; - s_sizeBtn.y = ((14 * dc.GetCharHeight()) + 2)/8; - } - - return s_sizeBtn; -} - -// ---------------------------------------------------------------------------- -// default button handling -// ---------------------------------------------------------------------------- - -/* - "Everything you ever wanted to know about the default buttons" or "Why do we - have to do all this?" - - In MSW the default button should be activated when the user presses Enter - and the current control doesn't process Enter itself somehow. This is - handled by ::DefWindowProc() (or maybe ::DefDialogProc()) using DM_SETDEFID - Another aspect of "defaultness" is that the default button has different - appearance: this is due to BS_DEFPUSHBUTTON style which is completely - separate from DM_SETDEFID stuff (!). Also note that BS_DEFPUSHBUTTON should - be unset if our parent window is not active so it should be unset whenever - we lose activation and set back when we regain it. - - Final complication is that when a button is active, it should be the default - one, i.e. pressing Enter on a button always activates it and not another - one. - - We handle this by maintaining a permanent and a temporary default items in - wxControlContainer (both may be NULL). When a button becomes the current - control (i.e. gets focus) it sets itself as the temporary default which - ensures that it has the right appearance and that Enter will be redirected - to it. When the button loses focus, it unsets the temporary default and so - the default item will be the permanent default -- that is the default button - if any had been set or none otherwise, which is just what we want. - - NB: all this is quite complicated by now and the worst is that normally - it shouldn't be necessary at all as for the normal Windows programs - DefWindowProc() and IsDialogMessage() take care of all this - automatically -- however in wxWidgets programs this doesn't work for - nested hierarchies (i.e. a notebook inside a notebook) for unknown - reason and so we have to reproduce all this code ourselves. It would be - very nice if we could avoid doing it. - */ - -// set this button as the (permanently) default one in its panel -void wxButton::SetDefault() -{ - wxTopLevelWindow *tlw = wxDynamicCast(wxGetTopLevelParent(this), wxTopLevelWindow); - - wxCHECK_RET( tlw, _T("button without top level window?") ); - - // set this one as the default button both for wxWidgets ... - wxWindow *winOldDefault = tlw->SetDefaultItem(this); - - // ... and Windows - SetDefaultStyle(wxDynamicCast(winOldDefault, wxButton), false); - SetDefaultStyle(this, true); -} - -// return the top level parent window if it's not being deleted yet, otherwise -// return NULL -static wxTopLevelWindow *GetTLWParentIfNotBeingDeleted(wxWindow *win) -{ - for ( ;; ) - { - // IsTopLevel() will return false for a wxTLW being deleted, so we also - // need the parent test for this case - wxWindow * const parent = win->GetParent(); - if ( !parent || win->IsTopLevel() ) - { - if ( win->IsBeingDeleted() ) - return NULL; - - break; - } - - win = parent; - } - - wxASSERT_MSG( win, _T("button without top level parent?") ); - - wxTopLevelWindow * const tlw = wxDynamicCast(win, wxTopLevelWindow); - wxASSERT_MSG( tlw, _T("logic error in GetTLWParentIfNotBeingDeleted()") ); - - return tlw; -} - -// set this button as being currently default -void wxButton::SetTmpDefault() -{ - wxTopLevelWindow * const tlw = GetTLWParentIfNotBeingDeleted(GetParent()); - if ( !tlw ) - return; - - wxWindow *winOldDefault = tlw->GetDefaultItem(); - tlw->SetTmpDefaultItem(this); - - SetDefaultStyle(wxDynamicCast(winOldDefault, wxButton), false); - SetDefaultStyle(this, true); -} - -// unset this button as currently default, it may still stay permanent default -void wxButton::UnsetTmpDefault() -{ - wxTopLevelWindow * const tlw = GetTLWParentIfNotBeingDeleted(GetParent()); - if ( !tlw ) - return; - - tlw->SetTmpDefaultItem(NULL); - - wxWindow *winOldDefault = tlw->GetDefaultItem(); - - SetDefaultStyle(this, false); - SetDefaultStyle(wxDynamicCast(winOldDefault, wxButton), true); -} - -/* static */ -void -wxButton::SetDefaultStyle(wxButton *btn, bool on) -{ - // we may be called with NULL pointer -- simpler to do the check here than - // in the caller which does wxDynamicCast() - if ( !btn ) - return; - - // first, let DefDlgProc() know about the new default button - if ( on ) - { - // we shouldn't set BS_DEFPUSHBUTTON for any button if we don't have - // focus at all any more - if ( !wxTheApp->IsActive() ) - return; - - wxWindow * const tlw = wxGetTopLevelParent(btn); - wxCHECK_RET( tlw, _T("button without top level window?") ); - - ::SendMessage(GetHwndOf(tlw), DM_SETDEFID, btn->GetId(), 0L); - - // sending DM_SETDEFID also changes the button style to - // BS_DEFPUSHBUTTON so there is nothing more to do - } - - // then also change the style as needed - long style = ::GetWindowLong(GetHwndOf(btn), GWL_STYLE); - if ( !(style & BS_DEFPUSHBUTTON) == on ) - { - // don't do it with the owner drawn buttons because it will - // reset BS_OWNERDRAW style bit too (as BS_OWNERDRAW & - // BS_DEFPUSHBUTTON != 0)! - if ( (style & BS_OWNERDRAW) != BS_OWNERDRAW ) - { - ::SendMessage(GetHwndOf(btn), BM_SETSTYLE, - on ? style | BS_DEFPUSHBUTTON - : style & ~BS_DEFPUSHBUTTON, - 1L /* redraw */); - } - else // owner drawn - { - // redraw the button - it will notice itself that it's - // [not] the default one [any longer] - btn->Refresh(); - } - } - //else: already has correct style -} - -// ---------------------------------------------------------------------------- -// helpers -// ---------------------------------------------------------------------------- - -bool wxButton::SendClickEvent() -{ - wxCommandEvent event(wxEVT_COMMAND_BUTTON_CLICKED, GetId()); - event.SetEventObject(this); - - return ProcessCommand(event); -} - -void wxButton::Command(wxCommandEvent & event) -{ - ProcessCommand(event); -} - -// ---------------------------------------------------------------------------- -// event/message handlers -// ---------------------------------------------------------------------------- - -bool wxButton::MSWCommand(WXUINT param, WXWORD WXUNUSED(id)) -{ - bool processed = false; - switch ( param ) - { - // NOTE: Apparently older versions (NT 4?) of the common controls send - // BN_DOUBLECLICKED but not a second BN_CLICKED for owner-drawn - // buttons, so in order to send two EVT_BUTTON events we should - // catch both types. Currently (Feb 2003) up-to-date versions of - // win98, win2k and winXP all send two BN_CLICKED messages for - // all button types, so we don't catch BN_DOUBLECLICKED anymore - // in order to not get 3 EVT_BUTTON events. If this is a problem - // then we need to figure out which version of the comctl32 changed - // this behaviour and test for it. - - case 1: // message came from an accelerator - case BN_CLICKED: // normal buttons send this - processed = SendClickEvent(); - break; - } - - return processed; -} - -WXLRESULT wxButton::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam) -{ - // when we receive focus, we want to temporarily become the default button in - // our parent panel so that pressing "Enter" would activate us -- and when - // losing it we should restore the previous default button as well - if ( nMsg == WM_SETFOCUS ) - { - SetTmpDefault(); - - // let the default processing take place too - } - else if ( nMsg == WM_KILLFOCUS ) - { - UnsetTmpDefault(); - } - else if ( nMsg == WM_LBUTTONDBLCLK ) - { - // emulate a click event to force an owner-drawn button to change its - // appearance - without this, it won't do it - (void)wxControl::MSWWindowProc(WM_LBUTTONDOWN, wParam, lParam); - - // and continue with processing the message normally as well - } -#if wxUSE_UXTHEME - else if ( nMsg == WM_THEMECHANGED ) - { - // need to recalculate the best size here - // as the theme size might have changed - InvalidateBestSize(); - } - else if ( wxUxThemeEngine::GetIfActive() ) - { - // we need to Refresh() if mouse has entered or left window - // so we can update the hot tracking state - // must use m_mouseInWindow here instead of IsMouseInWindow() - // since we need to know the first time the mouse enters the window - // and IsMouseInWindow() would return true in this case - if ( ( nMsg == WM_MOUSEMOVE && !m_mouseInWindow ) || - nMsg == WM_MOUSELEAVE ) - { - Refresh(); - } - } -#endif // wxUSE_UXTHEME - - // let the base class do all real processing - return wxControl::MSWWindowProc(nMsg, wParam, lParam); -} - -// ---------------------------------------------------------------------------- -// owner-drawn buttons support -// ---------------------------------------------------------------------------- - -#ifdef __WIN32__ - -// drawing helpers - -static void DrawButtonText(HDC hdc, - RECT *pRect, - const wxString& text, - COLORREF col) -{ - COLORREF colOld = SetTextColor(hdc, col); - int modeOld = SetBkMode(hdc, TRANSPARENT); - - if ( text.find(_T('\n')) != wxString::npos ) - { - // draw multiline label - - // first we need to compute its bounding rect - RECT rc; - ::CopyRect(&rc, pRect); - ::DrawText(hdc, text, text.length(), &rc, DT_CENTER | DT_CALCRECT); - - // now center this rect inside the entire button area - const LONG w = rc.right - rc.left; - const LONG h = rc.bottom - rc.top; - rc.left = (pRect->right - pRect->left)/2 - w/2; - rc.right = rc.left+w; - rc.top = (pRect->bottom - pRect->top)/2 - h/2; - rc.bottom = rc.top+h; - - ::DrawText(hdc, text, text.length(), &rc, DT_CENTER); - } - else // single line label - { - // Note: we must have DT_SINGLELINE for DT_VCENTER to work. - ::DrawText(hdc, text, text.length(), pRect, - DT_SINGLELINE | DT_CENTER | DT_VCENTER); - } - - SetBkMode(hdc, modeOld); - SetTextColor(hdc, colOld); -} - -static void DrawRect(HDC hdc, const RECT& r) -{ - wxDrawLine(hdc, r.left, r.top, r.right, r.top); - wxDrawLine(hdc, r.right, r.top, r.right, r.bottom); - wxDrawLine(hdc, r.right, r.bottom, r.left, r.bottom); - wxDrawLine(hdc, r.left, r.bottom, r.left, r.top); -} - -void wxButton::MakeOwnerDrawn() -{ - long style = GetWindowLong(GetHwnd(), GWL_STYLE); - if ( (style & BS_OWNERDRAW) != BS_OWNERDRAW ) - { - // make it so - style |= BS_OWNERDRAW; - SetWindowLong(GetHwnd(), GWL_STYLE, style); - } -} - -bool wxButton::SetBackgroundColour(const wxColour &colour) -{ - if ( !wxControl::SetBackgroundColour(colour) ) - { - // nothing to do - return false; - } - - MakeOwnerDrawn(); - - Refresh(); - - return true; -} - -bool wxButton::SetForegroundColour(const wxColour &colour) -{ - if ( !wxControl::SetForegroundColour(colour) ) - { - // nothing to do - return false; - } - - MakeOwnerDrawn(); - - Refresh(); - - return true; -} - -/* - The button frame looks like this normally: - - WWWWWWWWWWWWWWWWWWB - WHHHHHHHHHHHHHHHHGB W = white (HILIGHT) - WH GB H = light grey (LIGHT) - WH GB G = dark grey (SHADOW) - WH GB B = black (DKSHADOW) - WH GB - WGGGGGGGGGGGGGGGGGB - BBBBBBBBBBBBBBBBBBB - - When the button is selected, the button becomes like this (the total button - size doesn't change): - - BBBBBBBBBBBBBBBBBBB - BWWWWWWWWWWWWWWWWBB - BWHHHHHHHHHHHHHHGBB - BWH GBB - BWH GBB - BWGGGGGGGGGGGGGGGBB - BBBBBBBBBBBBBBBBBBB - BBBBBBBBBBBBBBBBBBB - - When the button is pushed (while selected) it is like: - - BBBBBBBBBBBBBBBBBBB - BGGGGGGGGGGGGGGGGGB - BG GB - BG GB - BG GB - BG GB - BGGGGGGGGGGGGGGGGGB - BBBBBBBBBBBBBBBBBBB -*/ - -static void DrawButtonFrame(HDC hdc, const RECT& rectBtn, - bool selected, bool pushed) -{ - RECT r; - CopyRect(&r, &rectBtn); - - HPEN hpenBlack = CreatePen(PS_SOLID, 1, GetSysColor(COLOR_3DDKSHADOW)), - hpenGrey = CreatePen(PS_SOLID, 1, GetSysColor(COLOR_3DSHADOW)), - hpenLightGr = CreatePen(PS_SOLID, 1, GetSysColor(COLOR_3DLIGHT)), - hpenWhite = CreatePen(PS_SOLID, 1, GetSysColor(COLOR_3DHILIGHT)); - - HPEN hpenOld = (HPEN)SelectObject(hdc, hpenBlack); - - r.right--; - r.bottom--; - - if ( pushed ) - { - DrawRect(hdc, r); - - (void)SelectObject(hdc, hpenGrey); - ::InflateRect(&r, -1, -1); - - DrawRect(hdc, r); - } - else // !pushed - { - if ( selected ) - { - DrawRect(hdc, r); - - ::InflateRect(&r, -1, -1); - } - - wxDrawLine(hdc, r.left, r.bottom, r.right, r.bottom); - wxDrawLine(hdc, r.right, r.bottom, r.right, r.top - 1); - - (void)SelectObject(hdc, hpenWhite); - wxDrawLine(hdc, r.left, r.bottom - 1, r.left, r.top); - wxDrawLine(hdc, r.left, r.top, r.right, r.top); - - (void)SelectObject(hdc, hpenLightGr); - wxDrawLine(hdc, r.left + 1, r.bottom - 2, r.left + 1, r.top + 1); - wxDrawLine(hdc, r.left + 1, r.top + 1, r.right - 1, r.top + 1); - - (void)SelectObject(hdc, hpenGrey); - wxDrawLine(hdc, r.left + 1, r.bottom - 1, r.right - 1, r.bottom - 1); - wxDrawLine(hdc, r.right - 1, r.bottom - 1, r.right - 1, r.top); - } - - (void)SelectObject(hdc, hpenOld); - DeleteObject(hpenWhite); - DeleteObject(hpenLightGr); - DeleteObject(hpenGrey); - DeleteObject(hpenBlack); -} - -#if wxUSE_UXTHEME -static -void MSWDrawXPBackground(wxButton *button, WXDRAWITEMSTRUCT *wxdis) -{ - LPDRAWITEMSTRUCT lpDIS = (LPDRAWITEMSTRUCT)wxdis; - HDC hdc = lpDIS->hDC; - UINT state = lpDIS->itemState; - RECT rectBtn; - CopyRect(&rectBtn, &lpDIS->rcItem); - - wxUxThemeHandle theme(button, L"BUTTON"); - int iState; - - if ( state & ODS_SELECTED ) - { - iState = PBS_PRESSED; - } - else if ( button->HasCapture() || button->IsMouseInWindow() ) - { - iState = PBS_HOT; - } - else if ( state & ODS_FOCUS ) - { - iState = PBS_DEFAULTED; - } - else if ( state & ODS_DISABLED ) - { - iState = PBS_DISABLED; - } - else - { - iState = PBS_NORMAL; - } - - // draw parent background if needed - if ( wxUxThemeEngine::Get()->IsThemeBackgroundPartiallyTransparent(theme, - BP_PUSHBUTTON, - iState) ) - { - wxUxThemeEngine::Get()->DrawThemeParentBackground(GetHwndOf(button), hdc, &rectBtn); - } - - // draw background - wxUxThemeEngine::Get()->DrawThemeBackground(theme, hdc, BP_PUSHBUTTON, iState, - &rectBtn, NULL); - - // calculate content area margins - MARGINS margins; - wxUxThemeEngine::Get()->GetThemeMargins(theme, hdc, BP_PUSHBUTTON, iState, - TMT_CONTENTMARGINS, &rectBtn, &margins); - RECT rectClient; - ::CopyRect(&rectClient, &rectBtn); - ::InflateRect(&rectClient, -margins.cxLeftWidth, -margins.cyTopHeight); - - // if focused and !nofocus rect - if ( (state & ODS_FOCUS) && !(state & ODS_NOFOCUSRECT) ) - { - DrawFocusRect(hdc, &rectClient); - } - - if ( button->UseBgCol() ) - { - COLORREF colBg = wxColourToRGB(button->GetBackgroundColour()); - HBRUSH hbrushBackground = ::CreateSolidBrush(colBg); - - // don't overwrite the focus rect - ::InflateRect(&rectClient, -1, -1); - FillRect(hdc, &rectClient, hbrushBackground); - ::DeleteObject(hbrushBackground); - } -} -#endif // wxUSE_UXTHEME - -bool wxButton::MSWOnDraw(WXDRAWITEMSTRUCT *wxdis) -{ - LPDRAWITEMSTRUCT lpDIS = (LPDRAWITEMSTRUCT)wxdis; - HDC hdc = lpDIS->hDC; - UINT state = lpDIS->itemState; - RECT rectBtn; - CopyRect(&rectBtn, &lpDIS->rcItem); - -#if wxUSE_UXTHEME - if ( wxUxThemeEngine::GetIfActive() ) - { - MSWDrawXPBackground(this, wxdis); - } - else -#endif // wxUSE_UXTHEME - { - COLORREF colBg = wxColourToRGB(GetBackgroundColour()); - - // first, draw the background - HBRUSH hbrushBackground = ::CreateSolidBrush(colBg); - FillRect(hdc, &rectBtn, hbrushBackground); - ::DeleteObject(hbrushBackground); - - // draw the border for the current state - bool selected = (state & ODS_SELECTED) != 0; - if ( !selected ) - { - wxTopLevelWindow *tlw = wxDynamicCast(wxGetTopLevelParent(this), wxTopLevelWindow); - if ( tlw ) - { - selected = tlw->GetDefaultItem() == this; - } - } - bool pushed = (SendMessage(GetHwnd(), BM_GETSTATE, 0, 0) & BST_PUSHED) != 0; - - DrawButtonFrame(hdc, rectBtn, selected, pushed); - - // if focused and !nofocus rect - if ( (state & ODS_FOCUS) && !(state & ODS_NOFOCUSRECT) ) - { - RECT rectFocus; - CopyRect(&rectFocus, &rectBtn); - - // I don't know where does this constant come from, but this is how - // Windows draws them - InflateRect(&rectFocus, -4, -4); - - DrawFocusRect(hdc, &rectFocus); - } - - if ( pushed ) - { - // the label is shifted by 1 pixel to create "pushed" effect - OffsetRect(&rectBtn, 1, 1); - } - } - - COLORREF colFg = wxColourToRGB(GetForegroundColour()); - if ( state & ODS_DISABLED ) colFg = GetSysColor(COLOR_GRAYTEXT) ; - wxString label = GetLabel(); - if ( state & ODS_NOACCEL ) label = GetLabelText() ; - DrawButtonText(hdc, &rectBtn, label, colFg); - - return true; -} - -#endif // __WIN32__ - -#endif // wxUSE_BUTTON +///////////////////////////////////////////////////////////////////////////// +// Name: src/msw/button.cpp +// Purpose: wxButton +// Author: Julian Smart +// Modified by: +// Created: 04/01/98 +// RCS-ID: $Id: button.cpp 51575 2008-02-06 19:58:30Z VZ $ +// Copyright: (c) Julian Smart +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_BUTTON + +#include "wx/button.h" + +#ifndef WX_PRECOMP + #include "wx/app.h" + #include "wx/brush.h" + #include "wx/panel.h" + #include "wx/bmpbuttn.h" + #include "wx/settings.h" + #include "wx/dcscreen.h" + #include "wx/dcclient.h" + #include "wx/toplevel.h" +#endif + +#include "wx/stockitem.h" +#include "wx/tokenzr.h" +#include "wx/msw/private.h" + +#if wxUSE_UXTHEME + #include "wx/msw/uxtheme.h" + + // no need to include tmschema.h + #ifndef BP_PUSHBUTTON + #define BP_PUSHBUTTON 1 + + #define PBS_NORMAL 1 + #define PBS_HOT 2 + #define PBS_PRESSED 3 + #define PBS_DISABLED 4 + #define PBS_DEFAULTED 5 + + #define TMT_CONTENTMARGINS 3602 + #endif +#endif // wxUSE_UXTHEME + +#ifndef WM_THEMECHANGED + #define WM_THEMECHANGED 0x031A +#endif + +#ifndef ODS_NOACCEL + #define ODS_NOACCEL 0x0100 +#endif + +#ifndef ODS_NOFOCUSRECT + #define ODS_NOFOCUSRECT 0x0200 +#endif + +// ---------------------------------------------------------------------------- +// macros +// ---------------------------------------------------------------------------- + +#if wxUSE_EXTENDED_RTTI + +WX_DEFINE_FLAGS( wxButtonStyle ) + +wxBEGIN_FLAGS( wxButtonStyle ) + // new style border flags, we put them first to + // use them for streaming out + wxFLAGS_MEMBER(wxBORDER_SIMPLE) + wxFLAGS_MEMBER(wxBORDER_SUNKEN) + wxFLAGS_MEMBER(wxBORDER_DOUBLE) + wxFLAGS_MEMBER(wxBORDER_RAISED) + wxFLAGS_MEMBER(wxBORDER_STATIC) + wxFLAGS_MEMBER(wxBORDER_NONE) + + // old style border flags + wxFLAGS_MEMBER(wxSIMPLE_BORDER) + wxFLAGS_MEMBER(wxSUNKEN_BORDER) + wxFLAGS_MEMBER(wxDOUBLE_BORDER) + wxFLAGS_MEMBER(wxRAISED_BORDER) + wxFLAGS_MEMBER(wxSTATIC_BORDER) + wxFLAGS_MEMBER(wxBORDER) + + // standard window styles + wxFLAGS_MEMBER(wxTAB_TRAVERSAL) + wxFLAGS_MEMBER(wxCLIP_CHILDREN) + wxFLAGS_MEMBER(wxTRANSPARENT_WINDOW) + wxFLAGS_MEMBER(wxWANTS_CHARS) + wxFLAGS_MEMBER(wxFULL_REPAINT_ON_RESIZE) + wxFLAGS_MEMBER(wxALWAYS_SHOW_SB ) + wxFLAGS_MEMBER(wxVSCROLL) + wxFLAGS_MEMBER(wxHSCROLL) + + wxFLAGS_MEMBER(wxBU_LEFT) + wxFLAGS_MEMBER(wxBU_RIGHT) + wxFLAGS_MEMBER(wxBU_TOP) + wxFLAGS_MEMBER(wxBU_BOTTOM) + wxFLAGS_MEMBER(wxBU_EXACTFIT) +wxEND_FLAGS( wxButtonStyle ) + +IMPLEMENT_DYNAMIC_CLASS_XTI(wxButton, wxControl,"wx/button.h") + +wxBEGIN_PROPERTIES_TABLE(wxButton) + wxEVENT_PROPERTY( Click , wxEVT_COMMAND_BUTTON_CLICKED , wxCommandEvent) + + wxPROPERTY( Font , wxFont , SetFont , GetFont , EMPTY_MACROVALUE, 0 /*flags*/ , wxT("Helpstring") , wxT("group")) + wxPROPERTY( Label, wxString , SetLabel, GetLabel, wxString(), 0 /*flags*/ , wxT("Helpstring") , wxT("group") ) + + wxPROPERTY_FLAGS( WindowStyle , wxButtonStyle , long , SetWindowStyleFlag , GetWindowStyleFlag , EMPTY_MACROVALUE , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // style + +wxEND_PROPERTIES_TABLE() + +wxBEGIN_HANDLERS_TABLE(wxButton) +wxEND_HANDLERS_TABLE() + +wxCONSTRUCTOR_6( wxButton , wxWindow* , Parent , wxWindowID , Id , wxString , Label , wxPoint , Position , wxSize , Size , long , WindowStyle ) + + +#else +IMPLEMENT_DYNAMIC_CLASS(wxButton, wxControl) +#endif + +// this macro tries to adjust the default button height to a reasonable value +// using the char height as the base +#define BUTTON_HEIGHT_FROM_CHAR_HEIGHT(cy) (11*EDIT_HEIGHT_FROM_CHAR_HEIGHT(cy)/10) + +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// creation/destruction +// ---------------------------------------------------------------------------- + +bool wxButton::Create(wxWindow *parent, + wxWindowID id, + const wxString& lbl, + const wxPoint& pos, + const wxSize& size, + long style, + const wxValidator& validator, + const wxString& name) +{ + wxString label(lbl); + if (label.empty() && wxIsStockID(id)) + { + // On Windows, some buttons aren't supposed to have + // mnemonics, so strip them out. + + label = wxGetStockLabel(id +#if defined(__WXMSW__) || defined(__WXWINCE__) + , ( id != wxID_OK && + id != wxID_CANCEL && + id != wxID_CLOSE ) +#endif + ); + } + + if ( !CreateControl(parent, id, pos, size, style, validator, name) ) + return false; + + WXDWORD exstyle; + WXDWORD msStyle = MSWGetStyle(style, &exstyle); + +#ifdef __WIN32__ + // if the label contains several lines we must explicitly tell the button + // about it or it wouldn't draw it correctly ("\n"s would just appear as + // black boxes) + // + // NB: we do it here and not in MSWGetStyle() because we need the label + // value and m_label is not set yet when MSWGetStyle() is called; + // besides changing BS_MULTILINE during run-time is pointless anyhow + if ( label.find(_T('\n')) != wxString::npos ) + { + msStyle |= BS_MULTILINE; + } +#endif // __WIN32__ + + return MSWCreateControl(_T("BUTTON"), msStyle, pos, size, label, exstyle); +} + +wxButton::~wxButton() +{ + wxTopLevelWindow *tlw = wxDynamicCast(wxGetTopLevelParent(this), wxTopLevelWindow); + if ( tlw && tlw->GetTmpDefaultItem() == this ) + { + UnsetTmpDefault(); + } +} + +// ---------------------------------------------------------------------------- +// flags +// ---------------------------------------------------------------------------- + +WXDWORD wxButton::MSWGetStyle(long style, WXDWORD *exstyle) const +{ + // buttons never have an external border, they draw their own one + WXDWORD msStyle = wxControl::MSWGetStyle + ( + (style & ~wxBORDER_MASK) | wxBORDER_NONE, exstyle + ); + + // we must use WS_CLIPSIBLINGS with the buttons or they would draw over + // each other in any resizeable dialog which has more than one button in + // the bottom + msStyle |= WS_CLIPSIBLINGS; + +#ifdef __WIN32__ + // don't use "else if" here: weird as it is, but you may combine wxBU_LEFT + // and wxBU_RIGHT to get BS_CENTER! + if ( style & wxBU_LEFT ) + msStyle |= BS_LEFT; + if ( style & wxBU_RIGHT ) + msStyle |= BS_RIGHT; + if ( style & wxBU_TOP ) + msStyle |= BS_TOP; + if ( style & wxBU_BOTTOM ) + msStyle |= BS_BOTTOM; +#ifndef __WXWINCE__ + // flat 2d buttons + if ( style & wxNO_BORDER ) + msStyle |= BS_FLAT; +#endif // __WXWINCE__ +#endif // __WIN32__ + + return msStyle; +} + +// ---------------------------------------------------------------------------- +// size management including autosizing +// ---------------------------------------------------------------------------- + +wxSize wxButton::DoGetBestSize() const +{ + wxClientDC dc(wx_const_cast(wxButton *, this)); + dc.SetFont(GetFont()); + + wxCoord wBtn, + hBtn; + dc.GetMultiLineTextExtent(GetLabelText(), &wBtn, &hBtn); + + // add a margin -- the button is wider than just its label + wBtn += 3*GetCharWidth(); + hBtn = BUTTON_HEIGHT_FROM_CHAR_HEIGHT(hBtn); + + // all buttons have at least the standard size unless the user explicitly + // wants them to be of smaller size and used wxBU_EXACTFIT style when + // creating the button + if ( !HasFlag(wxBU_EXACTFIT) ) + { + wxSize sz = GetDefaultSize(); + if (wBtn > sz.x) + sz.x = wBtn; + if (hBtn > sz.y) + sz.y = hBtn; + + return sz; + } + + wxSize best(wBtn, hBtn); + CacheBestSize(best); + return best; +} + +/* static */ +wxSize wxButtonBase::GetDefaultSize() +{ + static wxSize s_sizeBtn; + + if ( s_sizeBtn.x == 0 ) + { + wxScreenDC dc; + dc.SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT)); + + // the size of a standard button in the dialog units is 50x14, + // translate this to pixels + // NB1: the multipliers come from the Windows convention + // NB2: the extra +1/+2 were needed to get the size be the same as the + // size of the buttons in the standard dialog - I don't know how + // this happens, but on my system this size is 75x23 in pixels and + // 23*8 isn't even divisible by 14... Would be nice to understand + // why these constants are needed though! + s_sizeBtn.x = (50 * (dc.GetCharWidth() + 1))/4; + s_sizeBtn.y = ((14 * dc.GetCharHeight()) + 2)/8; + } + + return s_sizeBtn; +} + +// ---------------------------------------------------------------------------- +// default button handling +// ---------------------------------------------------------------------------- + +/* + "Everything you ever wanted to know about the default buttons" or "Why do we + have to do all this?" + + In MSW the default button should be activated when the user presses Enter + and the current control doesn't process Enter itself somehow. This is + handled by ::DefWindowProc() (or maybe ::DefDialogProc()) using DM_SETDEFID + Another aspect of "defaultness" is that the default button has different + appearance: this is due to BS_DEFPUSHBUTTON style which is completely + separate from DM_SETDEFID stuff (!). Also note that BS_DEFPUSHBUTTON should + be unset if our parent window is not active so it should be unset whenever + we lose activation and set back when we regain it. + + Final complication is that when a button is active, it should be the default + one, i.e. pressing Enter on a button always activates it and not another + one. + + We handle this by maintaining a permanent and a temporary default items in + wxControlContainer (both may be NULL). When a button becomes the current + control (i.e. gets focus) it sets itself as the temporary default which + ensures that it has the right appearance and that Enter will be redirected + to it. When the button loses focus, it unsets the temporary default and so + the default item will be the permanent default -- that is the default button + if any had been set or none otherwise, which is just what we want. + + NB: all this is quite complicated by now and the worst is that normally + it shouldn't be necessary at all as for the normal Windows programs + DefWindowProc() and IsDialogMessage() take care of all this + automatically -- however in wxWidgets programs this doesn't work for + nested hierarchies (i.e. a notebook inside a notebook) for unknown + reason and so we have to reproduce all this code ourselves. It would be + very nice if we could avoid doing it. + */ + +// set this button as the (permanently) default one in its panel +void wxButton::SetDefault() +{ + wxTopLevelWindow *tlw = wxDynamicCast(wxGetTopLevelParent(this), wxTopLevelWindow); + + wxCHECK_RET( tlw, _T("button without top level window?") ); + + // set this one as the default button both for wxWidgets ... + wxWindow *winOldDefault = tlw->SetDefaultItem(this); + + // ... and Windows + SetDefaultStyle(wxDynamicCast(winOldDefault, wxButton), false); + SetDefaultStyle(this, true); +} + +// return the top level parent window if it's not being deleted yet, otherwise +// return NULL +static wxTopLevelWindow *GetTLWParentIfNotBeingDeleted(wxWindow *win) +{ + for ( ;; ) + { + // IsTopLevel() will return false for a wxTLW being deleted, so we also + // need the parent test for this case + wxWindow * const parent = win->GetParent(); + if ( !parent || win->IsTopLevel() ) + { + if ( win->IsBeingDeleted() ) + return NULL; + + break; + } + + win = parent; + } + + wxASSERT_MSG( win, _T("button without top level parent?") ); + + wxTopLevelWindow * const tlw = wxDynamicCast(win, wxTopLevelWindow); + wxASSERT_MSG( tlw, _T("logic error in GetTLWParentIfNotBeingDeleted()") ); + + return tlw; +} + +// set this button as being currently default +void wxButton::SetTmpDefault() +{ + wxTopLevelWindow * const tlw = GetTLWParentIfNotBeingDeleted(GetParent()); + if ( !tlw ) + return; + + wxWindow *winOldDefault = tlw->GetDefaultItem(); + tlw->SetTmpDefaultItem(this); + + SetDefaultStyle(wxDynamicCast(winOldDefault, wxButton), false); + SetDefaultStyle(this, true); +} + +// unset this button as currently default, it may still stay permanent default +void wxButton::UnsetTmpDefault() +{ + wxTopLevelWindow * const tlw = GetTLWParentIfNotBeingDeleted(GetParent()); + if ( !tlw ) + return; + + tlw->SetTmpDefaultItem(NULL); + + wxWindow *winOldDefault = tlw->GetDefaultItem(); + + SetDefaultStyle(this, false); + SetDefaultStyle(wxDynamicCast(winOldDefault, wxButton), true); +} + +/* static */ +void +wxButton::SetDefaultStyle(wxButton *btn, bool on) +{ + // we may be called with NULL pointer -- simpler to do the check here than + // in the caller which does wxDynamicCast() + if ( !btn ) + return; + + // first, let DefDlgProc() know about the new default button + if ( on ) + { + // we shouldn't set BS_DEFPUSHBUTTON for any button if we don't have + // focus at all any more + if ( !wxTheApp->IsActive() ) + return; + + wxWindow * const tlw = wxGetTopLevelParent(btn); + wxCHECK_RET( tlw, _T("button without top level window?") ); + + ::SendMessage(GetHwndOf(tlw), DM_SETDEFID, btn->GetId(), 0L); + + // sending DM_SETDEFID also changes the button style to + // BS_DEFPUSHBUTTON so there is nothing more to do + } + + // then also change the style as needed + long style = ::GetWindowLong(GetHwndOf(btn), GWL_STYLE); + if ( !(style & BS_DEFPUSHBUTTON) == on ) + { + // don't do it with the owner drawn buttons because it will + // reset BS_OWNERDRAW style bit too (as BS_OWNERDRAW & + // BS_DEFPUSHBUTTON != 0)! + if ( (style & BS_OWNERDRAW) != BS_OWNERDRAW ) + { + ::SendMessage(GetHwndOf(btn), BM_SETSTYLE, + on ? style | BS_DEFPUSHBUTTON + : style & ~BS_DEFPUSHBUTTON, + 1L /* redraw */); + } + else // owner drawn + { + // redraw the button - it will notice itself that it's + // [not] the default one [any longer] + btn->Refresh(); + } + } + //else: already has correct style +} + +// ---------------------------------------------------------------------------- +// helpers +// ---------------------------------------------------------------------------- + +bool wxButton::SendClickEvent() +{ + wxCommandEvent event(wxEVT_COMMAND_BUTTON_CLICKED, GetId()); + event.SetEventObject(this); + + return ProcessCommand(event); +} + +void wxButton::Command(wxCommandEvent & event) +{ + ProcessCommand(event); +} + +// ---------------------------------------------------------------------------- +// event/message handlers +// ---------------------------------------------------------------------------- + +bool wxButton::MSWCommand(WXUINT param, WXWORD WXUNUSED(id)) +{ + bool processed = false; + switch ( param ) + { + // NOTE: Apparently older versions (NT 4?) of the common controls send + // BN_DOUBLECLICKED but not a second BN_CLICKED for owner-drawn + // buttons, so in order to send two EVT_BUTTON events we should + // catch both types. Currently (Feb 2003) up-to-date versions of + // win98, win2k and winXP all send two BN_CLICKED messages for + // all button types, so we don't catch BN_DOUBLECLICKED anymore + // in order to not get 3 EVT_BUTTON events. If this is a problem + // then we need to figure out which version of the comctl32 changed + // this behaviour and test for it. + + case 1: // message came from an accelerator + case BN_CLICKED: // normal buttons send this + processed = SendClickEvent(); + break; + } + + return processed; +} + +WXLRESULT wxButton::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam) +{ + // when we receive focus, we want to temporarily become the default button in + // our parent panel so that pressing "Enter" would activate us -- and when + // losing it we should restore the previous default button as well + if ( nMsg == WM_SETFOCUS ) + { + SetTmpDefault(); + + // let the default processing take place too + } + else if ( nMsg == WM_KILLFOCUS ) + { + UnsetTmpDefault(); + } + else if ( nMsg == WM_LBUTTONDBLCLK ) + { + // emulate a click event to force an owner-drawn button to change its + // appearance - without this, it won't do it + (void)wxControl::MSWWindowProc(WM_LBUTTONDOWN, wParam, lParam); + + // and continue with processing the message normally as well + } +#if wxUSE_UXTHEME + else if ( nMsg == WM_THEMECHANGED ) + { + // need to recalculate the best size here + // as the theme size might have changed + InvalidateBestSize(); + } + else if ( wxUxThemeEngine::GetIfActive() ) + { + // we need to Refresh() if mouse has entered or left window + // so we can update the hot tracking state + // must use m_mouseInWindow here instead of IsMouseInWindow() + // since we need to know the first time the mouse enters the window + // and IsMouseInWindow() would return true in this case + if ( ( nMsg == WM_MOUSEMOVE && !m_mouseInWindow ) || + nMsg == WM_MOUSELEAVE ) + { + Refresh(); + } + } +#endif // wxUSE_UXTHEME + + // let the base class do all real processing + return wxControl::MSWWindowProc(nMsg, wParam, lParam); +} + +// ---------------------------------------------------------------------------- +// owner-drawn buttons support +// ---------------------------------------------------------------------------- + +#ifdef __WIN32__ + +// drawing helpers + +static void DrawButtonText(HDC hdc, + RECT *pRect, + const wxString& text, + COLORREF col) +{ + COLORREF colOld = SetTextColor(hdc, col); + int modeOld = SetBkMode(hdc, TRANSPARENT); + + if ( text.find(_T('\n')) != wxString::npos ) + { + // draw multiline label + + // first we need to compute its bounding rect + RECT rc; + ::CopyRect(&rc, pRect); + ::DrawText(hdc, text, text.length(), &rc, DT_CENTER | DT_CALCRECT); + + // now center this rect inside the entire button area + const LONG w = rc.right - rc.left; + const LONG h = rc.bottom - rc.top; + rc.left = (pRect->right - pRect->left)/2 - w/2; + rc.right = rc.left+w; + rc.top = (pRect->bottom - pRect->top)/2 - h/2; + rc.bottom = rc.top+h; + + ::DrawText(hdc, text, text.length(), &rc, DT_CENTER); + } + else // single line label + { + // Note: we must have DT_SINGLELINE for DT_VCENTER to work. + ::DrawText(hdc, text, text.length(), pRect, + DT_SINGLELINE | DT_CENTER | DT_VCENTER); + } + + SetBkMode(hdc, modeOld); + SetTextColor(hdc, colOld); +} + +static void DrawRect(HDC hdc, const RECT& r) +{ + wxDrawLine(hdc, r.left, r.top, r.right, r.top); + wxDrawLine(hdc, r.right, r.top, r.right, r.bottom); + wxDrawLine(hdc, r.right, r.bottom, r.left, r.bottom); + wxDrawLine(hdc, r.left, r.bottom, r.left, r.top); +} + +void wxButton::MakeOwnerDrawn() +{ + long style = GetWindowLong(GetHwnd(), GWL_STYLE); + if ( (style & BS_OWNERDRAW) != BS_OWNERDRAW ) + { + // make it so + style |= BS_OWNERDRAW; + SetWindowLong(GetHwnd(), GWL_STYLE, style); + } +} + +bool wxButton::SetBackgroundColour(const wxColour &colour) +{ + if ( !wxControl::SetBackgroundColour(colour) ) + { + // nothing to do + return false; + } + + MakeOwnerDrawn(); + + Refresh(); + + return true; +} + +bool wxButton::SetForegroundColour(const wxColour &colour) +{ + if ( !wxControl::SetForegroundColour(colour) ) + { + // nothing to do + return false; + } + + MakeOwnerDrawn(); + + Refresh(); + + return true; +} + +/* + The button frame looks like this normally: + + WWWWWWWWWWWWWWWWWWB + WHHHHHHHHHHHHHHHHGB W = white (HILIGHT) + WH GB H = light grey (LIGHT) + WH GB G = dark grey (SHADOW) + WH GB B = black (DKSHADOW) + WH GB + WGGGGGGGGGGGGGGGGGB + BBBBBBBBBBBBBBBBBBB + + When the button is selected, the button becomes like this (the total button + size doesn't change): + + BBBBBBBBBBBBBBBBBBB + BWWWWWWWWWWWWWWWWBB + BWHHHHHHHHHHHHHHGBB + BWH GBB + BWH GBB + BWGGGGGGGGGGGGGGGBB + BBBBBBBBBBBBBBBBBBB + BBBBBBBBBBBBBBBBBBB + + When the button is pushed (while selected) it is like: + + BBBBBBBBBBBBBBBBBBB + BGGGGGGGGGGGGGGGGGB + BG GB + BG GB + BG GB + BG GB + BGGGGGGGGGGGGGGGGGB + BBBBBBBBBBBBBBBBBBB +*/ + +static void DrawButtonFrame(HDC hdc, const RECT& rectBtn, + bool selected, bool pushed) +{ + RECT r; + CopyRect(&r, &rectBtn); + + HPEN hpenBlack = CreatePen(PS_SOLID, 1, GetSysColor(COLOR_3DDKSHADOW)), + hpenGrey = CreatePen(PS_SOLID, 1, GetSysColor(COLOR_3DSHADOW)), + hpenLightGr = CreatePen(PS_SOLID, 1, GetSysColor(COLOR_3DLIGHT)), + hpenWhite = CreatePen(PS_SOLID, 1, GetSysColor(COLOR_3DHILIGHT)); + + HPEN hpenOld = (HPEN)SelectObject(hdc, hpenBlack); + + r.right--; + r.bottom--; + + if ( pushed ) + { + DrawRect(hdc, r); + + (void)SelectObject(hdc, hpenGrey); + ::InflateRect(&r, -1, -1); + + DrawRect(hdc, r); + } + else // !pushed + { + if ( selected ) + { + DrawRect(hdc, r); + + ::InflateRect(&r, -1, -1); + } + + wxDrawLine(hdc, r.left, r.bottom, r.right, r.bottom); + wxDrawLine(hdc, r.right, r.bottom, r.right, r.top - 1); + + (void)SelectObject(hdc, hpenWhite); + wxDrawLine(hdc, r.left, r.bottom - 1, r.left, r.top); + wxDrawLine(hdc, r.left, r.top, r.right, r.top); + + (void)SelectObject(hdc, hpenLightGr); + wxDrawLine(hdc, r.left + 1, r.bottom - 2, r.left + 1, r.top + 1); + wxDrawLine(hdc, r.left + 1, r.top + 1, r.right - 1, r.top + 1); + + (void)SelectObject(hdc, hpenGrey); + wxDrawLine(hdc, r.left + 1, r.bottom - 1, r.right - 1, r.bottom - 1); + wxDrawLine(hdc, r.right - 1, r.bottom - 1, r.right - 1, r.top); + } + + (void)SelectObject(hdc, hpenOld); + DeleteObject(hpenWhite); + DeleteObject(hpenLightGr); + DeleteObject(hpenGrey); + DeleteObject(hpenBlack); +} + +#if wxUSE_UXTHEME +static +void MSWDrawXPBackground(wxButton *button, WXDRAWITEMSTRUCT *wxdis) +{ + LPDRAWITEMSTRUCT lpDIS = (LPDRAWITEMSTRUCT)wxdis; + HDC hdc = lpDIS->hDC; + UINT state = lpDIS->itemState; + RECT rectBtn; + CopyRect(&rectBtn, &lpDIS->rcItem); + + wxUxThemeHandle theme(button, L"BUTTON"); + int iState; + + if ( state & ODS_SELECTED ) + { + iState = PBS_PRESSED; + } + else if ( button->HasCapture() || button->IsMouseInWindow() ) + { + iState = PBS_HOT; + } + else if ( state & ODS_FOCUS ) + { + iState = PBS_DEFAULTED; + } + else if ( state & ODS_DISABLED ) + { + iState = PBS_DISABLED; + } + else + { + iState = PBS_NORMAL; + } + + // draw parent background if needed + if ( wxUxThemeEngine::Get()->IsThemeBackgroundPartiallyTransparent(theme, + BP_PUSHBUTTON, + iState) ) + { + wxUxThemeEngine::Get()->DrawThemeParentBackground(GetHwndOf(button), hdc, &rectBtn); + } + + // draw background + wxUxThemeEngine::Get()->DrawThemeBackground(theme, hdc, BP_PUSHBUTTON, iState, + &rectBtn, NULL); + + // calculate content area margins + MARGINS margins; + wxUxThemeEngine::Get()->GetThemeMargins(theme, hdc, BP_PUSHBUTTON, iState, + TMT_CONTENTMARGINS, &rectBtn, &margins); + RECT rectClient; + ::CopyRect(&rectClient, &rectBtn); + ::InflateRect(&rectClient, -margins.cxLeftWidth, -margins.cyTopHeight); + + // if focused and !nofocus rect + if ( (state & ODS_FOCUS) && !(state & ODS_NOFOCUSRECT) ) + { + DrawFocusRect(hdc, &rectClient); + } + + if ( button->UseBgCol() ) + { + COLORREF colBg = wxColourToRGB(button->GetBackgroundColour()); + HBRUSH hbrushBackground = ::CreateSolidBrush(colBg); + + // don't overwrite the focus rect + ::InflateRect(&rectClient, -1, -1); + FillRect(hdc, &rectClient, hbrushBackground); + ::DeleteObject(hbrushBackground); + } +} +#endif // wxUSE_UXTHEME + +bool wxButton::MSWOnDraw(WXDRAWITEMSTRUCT *wxdis) +{ + LPDRAWITEMSTRUCT lpDIS = (LPDRAWITEMSTRUCT)wxdis; + HDC hdc = lpDIS->hDC; + UINT state = lpDIS->itemState; + RECT rectBtn; + CopyRect(&rectBtn, &lpDIS->rcItem); + +#if wxUSE_UXTHEME + if ( wxUxThemeEngine::GetIfActive() ) + { + MSWDrawXPBackground(this, wxdis); + } + else +#endif // wxUSE_UXTHEME + { + COLORREF colBg = wxColourToRGB(GetBackgroundColour()); + + // first, draw the background + HBRUSH hbrushBackground = ::CreateSolidBrush(colBg); + FillRect(hdc, &rectBtn, hbrushBackground); + ::DeleteObject(hbrushBackground); + + // draw the border for the current state + bool selected = (state & ODS_SELECTED) != 0; + if ( !selected ) + { + wxTopLevelWindow *tlw = wxDynamicCast(wxGetTopLevelParent(this), wxTopLevelWindow); + if ( tlw ) + { + selected = tlw->GetDefaultItem() == this; + } + } + bool pushed = (SendMessage(GetHwnd(), BM_GETSTATE, 0, 0) & BST_PUSHED) != 0; + + DrawButtonFrame(hdc, rectBtn, selected, pushed); + + // if focused and !nofocus rect + if ( (state & ODS_FOCUS) && !(state & ODS_NOFOCUSRECT) ) + { + RECT rectFocus; + CopyRect(&rectFocus, &rectBtn); + + // I don't know where does this constant come from, but this is how + // Windows draws them + InflateRect(&rectFocus, -4, -4); + + DrawFocusRect(hdc, &rectFocus); + } + + if ( pushed ) + { + // the label is shifted by 1 pixel to create "pushed" effect + OffsetRect(&rectBtn, 1, 1); + } + } + + COLORREF colFg = wxColourToRGB(GetForegroundColour()); + if ( state & ODS_DISABLED ) colFg = GetSysColor(COLOR_GRAYTEXT) ; + wxString label = GetLabel(); + if ( state & ODS_NOACCEL ) label = GetLabelText() ; + DrawButtonText(hdc, &rectBtn, label, colFg); + + return true; +} + +#endif // __WIN32__ + +#endif // wxUSE_BUTTON diff --git a/Externals/wxWidgets/src/msw/caret.cpp b/Externals/wxWidgets/src/msw/caret.cpp index 9c43cdf618..f8939f31bc 100644 --- a/Externals/wxWidgets/src/msw/caret.cpp +++ b/Externals/wxWidgets/src/msw/caret.cpp @@ -1,188 +1,188 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: msw/caret.cpp -// Purpose: MSW implementation of wxCaret -// Author: Vadim Zeitlin -// Modified by: -// Created: 23.05.99 -// RCS-ID: $Id: caret.cpp 35650 2005-09-23 12:56:45Z MR $ -// Copyright: (c) wxWidgets team -// Licence: wxWindows licence -/////////////////////////////////////////////////////////////////////////////// - -// =========================================================================== -// declarations -// =========================================================================== - -// --------------------------------------------------------------------------- -// headers -// --------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#ifndef WX_PRECOMP - #include "wx/window.h" - #include "wx/log.h" -#endif // WX_PRECOMP - -#include "wx/caret.h" - -#if wxUSE_CARET - -#include "wx/msw/private.h" - -// --------------------------------------------------------------------------- -// macros -// --------------------------------------------------------------------------- - -#define CALL_CARET_API(api, args) \ - if ( !api args ) \ - wxLogLastError(_T(#api)) - -// =========================================================================== -// implementation -// =========================================================================== - -// --------------------------------------------------------------------------- -// blink time -// --------------------------------------------------------------------------- - -//static -int wxCaretBase::GetBlinkTime() -{ - int blinkTime = ::GetCaretBlinkTime(); - if ( !blinkTime ) - { - wxLogLastError(wxT("GetCaretBlinkTime")); - } - - return blinkTime; -} - -//static -void wxCaretBase::SetBlinkTime(int milliseconds) -{ - CALL_CARET_API(SetCaretBlinkTime, (milliseconds)); -} - -// --------------------------------------------------------------------------- -// creating/destroying the caret -// --------------------------------------------------------------------------- - -bool wxCaret::MSWCreateCaret() -{ - wxASSERT_MSG( GetWindow(), wxT("caret without window cannot be created") ); - wxASSERT_MSG( IsOk(), wxT("caret of zero size cannot be created") ); - - if ( !m_hasCaret ) - { - CALL_CARET_API(CreateCaret, (GetWinHwnd(GetWindow()), 0, - m_width, m_height)); - - m_hasCaret = true; - } - - return m_hasCaret; -} - -void wxCaret::OnSetFocus() -{ - if ( m_countVisible > 0 ) - { - if ( MSWCreateCaret() ) - { - // the caret was recreated but it doesn't remember its position and - // it's not shown - - DoMove(); - DoShow(); - } - } - //else: caret is invisible, don't waste time creating it -} - -void wxCaret::OnKillFocus() -{ - if ( m_hasCaret ) - { - m_hasCaret = false; - - CALL_CARET_API(DestroyCaret, ()); - } -} - -// --------------------------------------------------------------------------- -// showing/hiding the caret -// --------------------------------------------------------------------------- - -void wxCaret::DoShow() -{ - wxASSERT_MSG( GetWindow(), wxT("caret without window cannot be shown") ); - wxASSERT_MSG( IsOk(), wxT("caret of zero size cannot be shown") ); - - // we might not have created the caret yet if we had got the focus first - // and the caret was shown later - so do it now if we have the focus but - // not the caret - if ( !m_hasCaret && (wxWindow::FindFocus() == GetWindow()) ) - { - if ( MSWCreateCaret() ) - { - DoMove(); - } - } - - if ( m_hasCaret ) - { - CALL_CARET_API(ShowCaret, (GetWinHwnd(GetWindow()))); - } - //else: will be shown when we get the focus -} - -void wxCaret::DoHide() -{ - if ( m_hasCaret ) - { - CALL_CARET_API(HideCaret, (GetWinHwnd(GetWindow()))); - } -} - -// --------------------------------------------------------------------------- -// moving the caret -// --------------------------------------------------------------------------- - -void wxCaret::DoMove() -{ - if ( m_hasCaret ) - { - wxASSERT_MSG( wxWindow::FindFocus() == GetWindow(), - wxT("how did we lose focus?") ); - - // for compatibility with the generic version, the coordinates are - // client ones - wxPoint pt = GetWindow()->GetClientAreaOrigin(); - CALL_CARET_API(SetCaretPos, (m_x + pt.x, m_y + pt.y)); - } - //else: we don't have caret right now, nothing to do (this does happen) -} - - -// --------------------------------------------------------------------------- -// resizing the caret -// --------------------------------------------------------------------------- - -void wxCaret::DoSize() -{ - if ( m_hasCaret ) - { - m_hasCaret = false; - CALL_CARET_API(DestroyCaret, ()); - MSWCreateCaret(); - OnSetFocus(); - } -} - -#endif +/////////////////////////////////////////////////////////////////////////////// +// Name: msw/caret.cpp +// Purpose: MSW implementation of wxCaret +// Author: Vadim Zeitlin +// Modified by: +// Created: 23.05.99 +// RCS-ID: $Id: caret.cpp 35650 2005-09-23 12:56:45Z MR $ +// Copyright: (c) wxWidgets team +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +// =========================================================================== +// declarations +// =========================================================================== + +// --------------------------------------------------------------------------- +// headers +// --------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#ifndef WX_PRECOMP + #include "wx/window.h" + #include "wx/log.h" +#endif // WX_PRECOMP + +#include "wx/caret.h" + +#if wxUSE_CARET + +#include "wx/msw/private.h" + +// --------------------------------------------------------------------------- +// macros +// --------------------------------------------------------------------------- + +#define CALL_CARET_API(api, args) \ + if ( !api args ) \ + wxLogLastError(_T(#api)) + +// =========================================================================== +// implementation +// =========================================================================== + +// --------------------------------------------------------------------------- +// blink time +// --------------------------------------------------------------------------- + +//static +int wxCaretBase::GetBlinkTime() +{ + int blinkTime = ::GetCaretBlinkTime(); + if ( !blinkTime ) + { + wxLogLastError(wxT("GetCaretBlinkTime")); + } + + return blinkTime; +} + +//static +void wxCaretBase::SetBlinkTime(int milliseconds) +{ + CALL_CARET_API(SetCaretBlinkTime, (milliseconds)); +} + +// --------------------------------------------------------------------------- +// creating/destroying the caret +// --------------------------------------------------------------------------- + +bool wxCaret::MSWCreateCaret() +{ + wxASSERT_MSG( GetWindow(), wxT("caret without window cannot be created") ); + wxASSERT_MSG( IsOk(), wxT("caret of zero size cannot be created") ); + + if ( !m_hasCaret ) + { + CALL_CARET_API(CreateCaret, (GetWinHwnd(GetWindow()), 0, + m_width, m_height)); + + m_hasCaret = true; + } + + return m_hasCaret; +} + +void wxCaret::OnSetFocus() +{ + if ( m_countVisible > 0 ) + { + if ( MSWCreateCaret() ) + { + // the caret was recreated but it doesn't remember its position and + // it's not shown + + DoMove(); + DoShow(); + } + } + //else: caret is invisible, don't waste time creating it +} + +void wxCaret::OnKillFocus() +{ + if ( m_hasCaret ) + { + m_hasCaret = false; + + CALL_CARET_API(DestroyCaret, ()); + } +} + +// --------------------------------------------------------------------------- +// showing/hiding the caret +// --------------------------------------------------------------------------- + +void wxCaret::DoShow() +{ + wxASSERT_MSG( GetWindow(), wxT("caret without window cannot be shown") ); + wxASSERT_MSG( IsOk(), wxT("caret of zero size cannot be shown") ); + + // we might not have created the caret yet if we had got the focus first + // and the caret was shown later - so do it now if we have the focus but + // not the caret + if ( !m_hasCaret && (wxWindow::FindFocus() == GetWindow()) ) + { + if ( MSWCreateCaret() ) + { + DoMove(); + } + } + + if ( m_hasCaret ) + { + CALL_CARET_API(ShowCaret, (GetWinHwnd(GetWindow()))); + } + //else: will be shown when we get the focus +} + +void wxCaret::DoHide() +{ + if ( m_hasCaret ) + { + CALL_CARET_API(HideCaret, (GetWinHwnd(GetWindow()))); + } +} + +// --------------------------------------------------------------------------- +// moving the caret +// --------------------------------------------------------------------------- + +void wxCaret::DoMove() +{ + if ( m_hasCaret ) + { + wxASSERT_MSG( wxWindow::FindFocus() == GetWindow(), + wxT("how did we lose focus?") ); + + // for compatibility with the generic version, the coordinates are + // client ones + wxPoint pt = GetWindow()->GetClientAreaOrigin(); + CALL_CARET_API(SetCaretPos, (m_x + pt.x, m_y + pt.y)); + } + //else: we don't have caret right now, nothing to do (this does happen) +} + + +// --------------------------------------------------------------------------- +// resizing the caret +// --------------------------------------------------------------------------- + +void wxCaret::DoSize() +{ + if ( m_hasCaret ) + { + m_hasCaret = false; + CALL_CARET_API(DestroyCaret, ()); + MSWCreateCaret(); + OnSetFocus(); + } +} + +#endif diff --git a/Externals/wxWidgets/src/msw/checkbox.cpp b/Externals/wxWidgets/src/msw/checkbox.cpp index 550afd7404..f4c19ff989 100644 --- a/Externals/wxWidgets/src/msw/checkbox.cpp +++ b/Externals/wxWidgets/src/msw/checkbox.cpp @@ -1,588 +1,588 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/msw/checkbox.cpp -// Purpose: wxCheckBox -// Author: Julian Smart -// Modified by: -// Created: 04/01/98 -// RCS-ID: $Id: checkbox.cpp 40331 2006-07-25 18:47:39Z VZ $ -// Copyright: (c) Julian Smart -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_CHECKBOX - -#include "wx/checkbox.h" - -#ifndef WX_PRECOMP - #include "wx/brush.h" - #include "wx/dcscreen.h" - #include "wx/settings.h" -#endif - -#include "wx/msw/uxtheme.h" -#include "wx/msw/private.h" - -// ---------------------------------------------------------------------------- -// constants -// ---------------------------------------------------------------------------- - -#ifndef BST_UNCHECKED - #define BST_UNCHECKED 0x0000 -#endif - -#ifndef BST_CHECKED - #define BST_CHECKED 0x0001 -#endif - -#ifndef BST_INDETERMINATE - #define BST_INDETERMINATE 0x0002 -#endif - -#ifndef DFCS_HOT - #define DFCS_HOT 0x1000 -#endif - -#ifndef DT_HIDEPREFIX - #define DT_HIDEPREFIX 0x00100000 -#endif - -#ifndef BP_CHECKBOX - #define BP_CHECKBOX 3 -#endif - -// these values are defined in tmschema.h (except the first one) -enum -{ - CBS_INVALID, - CBS_UNCHECKEDNORMAL, - CBS_UNCHECKEDHOT, - CBS_UNCHECKEDPRESSED, - CBS_UNCHECKEDDISABLED, - CBS_CHECKEDNORMAL, - CBS_CHECKEDHOT, - CBS_CHECKEDPRESSED, - CBS_CHECKEDDISABLED, - CBS_MIXEDNORMAL, - CBS_MIXEDHOT, - CBS_MIXEDPRESSED, - CBS_MIXEDDISABLED -}; - -// these are our own -enum -{ - CBS_HOT_OFFSET = 1, - CBS_PRESSED_OFFSET = 2, - CBS_DISABLED_OFFSET = 3 -}; - -// ============================================================================ -// implementation -// ============================================================================ - -#if wxUSE_EXTENDED_RTTI -WX_DEFINE_FLAGS( wxCheckBoxStyle ) - -wxBEGIN_FLAGS( wxCheckBoxStyle ) - // new style border flags, we put them first to - // use them for streaming out - wxFLAGS_MEMBER(wxBORDER_SIMPLE) - wxFLAGS_MEMBER(wxBORDER_SUNKEN) - wxFLAGS_MEMBER(wxBORDER_DOUBLE) - wxFLAGS_MEMBER(wxBORDER_RAISED) - wxFLAGS_MEMBER(wxBORDER_STATIC) - wxFLAGS_MEMBER(wxBORDER_NONE) - - // old style border flags - wxFLAGS_MEMBER(wxSIMPLE_BORDER) - wxFLAGS_MEMBER(wxSUNKEN_BORDER) - wxFLAGS_MEMBER(wxDOUBLE_BORDER) - wxFLAGS_MEMBER(wxRAISED_BORDER) - wxFLAGS_MEMBER(wxSTATIC_BORDER) - wxFLAGS_MEMBER(wxNO_BORDER) - - // standard window styles - wxFLAGS_MEMBER(wxTAB_TRAVERSAL) - wxFLAGS_MEMBER(wxCLIP_CHILDREN) - wxFLAGS_MEMBER(wxTRANSPARENT_WINDOW) - wxFLAGS_MEMBER(wxWANTS_CHARS) - wxFLAGS_MEMBER(wxNO_FULL_REPAINT_ON_RESIZE) - wxFLAGS_MEMBER(wxALWAYS_SHOW_SB ) - wxFLAGS_MEMBER(wxVSCROLL) - wxFLAGS_MEMBER(wxHSCROLL) - -wxEND_FLAGS( wxCheckBoxStyle ) - -IMPLEMENT_DYNAMIC_CLASS_XTI(wxCheckBox, wxControl,"wx/checkbox.h") - -wxBEGIN_PROPERTIES_TABLE(wxCheckBox) - wxEVENT_PROPERTY( Click , wxEVT_COMMAND_CHECKBOX_CLICKED , wxCommandEvent ) - - wxPROPERTY( Font , wxFont , SetFont , GetFont , EMPTY_MACROVALUE , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) - wxPROPERTY( Label,wxString, SetLabel, GetLabel, wxString() , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) - wxPROPERTY( Value ,bool, SetValue, GetValue, EMPTY_MACROVALUE, 0 /*flags*/ , wxT("Helpstring") , wxT("group")) - wxPROPERTY_FLAGS( WindowStyle , wxCheckBoxStyle , long , SetWindowStyleFlag , GetWindowStyleFlag , EMPTY_MACROVALUE, 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // style -wxEND_PROPERTIES_TABLE() - -wxBEGIN_HANDLERS_TABLE(wxCheckBox) -wxEND_HANDLERS_TABLE() - -wxCONSTRUCTOR_6( wxCheckBox , wxWindow* , Parent , wxWindowID , Id , wxString , Label , wxPoint , Position , wxSize , Size , long , WindowStyle ) -#else -IMPLEMENT_DYNAMIC_CLASS(wxCheckBox, wxControl) -#endif - - -// ---------------------------------------------------------------------------- -// wxCheckBox creation -// ---------------------------------------------------------------------------- - -void wxCheckBox::Init() -{ - m_state = wxCHK_UNCHECKED; - m_isPressed = - m_isHot = false; -} - -bool wxCheckBox::Create(wxWindow *parent, - wxWindowID id, - const wxString& label, - const wxPoint& pos, - const wxSize& size, long style, - const wxValidator& validator, - const wxString& name) -{ - Init(); - - if ( !CreateControl(parent, id, pos, size, style, validator, name) ) - return false; - - long msStyle = WS_TABSTOP; - - if ( style & wxCHK_3STATE ) - { - msStyle |= BS_3STATE; - } - else - { - wxASSERT_MSG( !Is3rdStateAllowedForUser(), - wxT("Using wxCH_ALLOW_3RD_STATE_FOR_USER") - wxT(" style flag for a 2-state checkbox is useless") ); - msStyle |= BS_CHECKBOX; - } - - if ( style & wxALIGN_RIGHT ) - { - msStyle |= BS_LEFTTEXT | BS_RIGHT; - } - - return MSWCreateControl(wxT("BUTTON"), msStyle, pos, size, label, 0); -} - -// ---------------------------------------------------------------------------- -// wxCheckBox geometry -// ---------------------------------------------------------------------------- - -wxSize wxCheckBox::DoGetBestSize() const -{ - static int s_checkSize = 0; - - if ( !s_checkSize ) - { - wxScreenDC dc; - dc.SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT)); - - s_checkSize = dc.GetCharHeight(); - } - - wxString str = wxGetWindowText(GetHWND()); - - int wCheckbox, hCheckbox; - if ( !str.empty() ) - { - GetTextExtent(GetLabelText(str), &wCheckbox, &hCheckbox); - wCheckbox += s_checkSize + GetCharWidth(); - - if ( hCheckbox < s_checkSize ) - hCheckbox = s_checkSize; - } - else - { - wCheckbox = s_checkSize; - hCheckbox = s_checkSize; - } -#ifdef __WXWINCE__ - hCheckbox += 1; -#endif - - wxSize best(wCheckbox, hCheckbox); - CacheBestSize(best); - return best; -} - -// ---------------------------------------------------------------------------- -// wxCheckBox operations -// ---------------------------------------------------------------------------- - -void wxCheckBox::SetValue(bool val) -{ - Set3StateValue(val ? wxCHK_CHECKED : wxCHK_UNCHECKED); -} - -bool wxCheckBox::GetValue() const -{ - return Get3StateValue() != wxCHK_UNCHECKED; -} - -void wxCheckBox::Command(wxCommandEvent& event) -{ - int state = event.GetInt(); - wxCHECK_RET( (state == wxCHK_UNCHECKED) || (state == wxCHK_CHECKED) - || (state == wxCHK_UNDETERMINED), - wxT("event.GetInt() returned an invalid checkbox state") ); - - Set3StateValue((wxCheckBoxState) state); - ProcessCommand(event); -} - -wxCOMPILE_TIME_ASSERT(wxCHK_UNCHECKED == BST_UNCHECKED - && wxCHK_CHECKED == BST_CHECKED - && wxCHK_UNDETERMINED == BST_INDETERMINATE, EnumValuesIncorrect); - -void wxCheckBox::DoSet3StateValue(wxCheckBoxState state) -{ - m_state = state; - if ( !IsOwnerDrawn() ) - ::SendMessage(GetHwnd(), BM_SETCHECK, (WPARAM) state, 0); - else // owner drawn buttons don't react to this message - Refresh(); -} - -wxCheckBoxState wxCheckBox::DoGet3StateValue() const -{ - return m_state; -} - -bool wxCheckBox::MSWCommand(WXUINT cmd, WXWORD WXUNUSED(id)) -{ - if ( cmd != BN_CLICKED && cmd != BN_DBLCLK ) - return false; - - // first update the value so that user event handler gets the new checkbox - // value - - // ownerdrawn buttons don't manage their state themselves unlike usual - // auto checkboxes so do it ourselves in any case - wxCheckBoxState state; - if ( Is3rdStateAllowedForUser() ) - { - state = (wxCheckBoxState)((m_state + 1) % 3); - } - else // 2 state checkbox (at least from users point of view) - { - // note that wxCHK_UNDETERMINED also becomes unchecked when clicked - state = m_state == wxCHK_UNCHECKED ? wxCHK_CHECKED : wxCHK_UNCHECKED; - } - - DoSet3StateValue(state); - - - // generate the event - wxCommandEvent event(wxEVT_COMMAND_CHECKBOX_CLICKED, m_windowId); - - event.SetInt(state); - event.SetEventObject(this); - ProcessCommand(event); - - return true; -} - -// ---------------------------------------------------------------------------- -// owner drawn checkboxes stuff -// ---------------------------------------------------------------------------- - -bool wxCheckBox::SetForegroundColour(const wxColour& colour) -{ - if ( !wxCheckBoxBase::SetForegroundColour(colour) ) - return false; - - // the only way to change the checkbox foreground colour under Windows XP - // is to owner draw it - if ( wxUxThemeEngine::GetIfActive() ) - MakeOwnerDrawn(colour.Ok()); - - return true; -} - -bool wxCheckBox::IsOwnerDrawn() const -{ - return - (::GetWindowLong(GetHwnd(), GWL_STYLE) & BS_OWNERDRAW) == BS_OWNERDRAW; -} - -void wxCheckBox::MakeOwnerDrawn(bool ownerDrawn) -{ - long style = ::GetWindowLong(GetHwnd(), GWL_STYLE); - - // note that BS_CHECKBOX & BS_OWNERDRAW != 0 so we can't operate on - // them as on independent style bits - if ( ownerDrawn ) - { - style &= ~(BS_CHECKBOX | BS_3STATE); - style |= BS_OWNERDRAW; - - Connect(wxEVT_ENTER_WINDOW, - wxMouseEventHandler(wxCheckBox::OnMouseEnterOrLeave)); - Connect(wxEVT_LEAVE_WINDOW, - wxMouseEventHandler(wxCheckBox::OnMouseEnterOrLeave)); - Connect(wxEVT_LEFT_DOWN, wxMouseEventHandler(wxCheckBox::OnMouseLeft)); - Connect(wxEVT_LEFT_UP, wxMouseEventHandler(wxCheckBox::OnMouseLeft)); - Connect(wxEVT_SET_FOCUS, wxFocusEventHandler(wxCheckBox::OnFocus)); - Connect(wxEVT_KILL_FOCUS, wxFocusEventHandler(wxCheckBox::OnFocus)); - } - else // reset to default colour - { - style &= ~BS_OWNERDRAW; - style |= HasFlag(wxCHK_3STATE) ? BS_3STATE : BS_CHECKBOX; - - Disconnect(wxEVT_ENTER_WINDOW, - wxMouseEventHandler(wxCheckBox::OnMouseEnterOrLeave)); - Disconnect(wxEVT_LEAVE_WINDOW, - wxMouseEventHandler(wxCheckBox::OnMouseEnterOrLeave)); - Disconnect(wxEVT_LEFT_DOWN, wxMouseEventHandler(wxCheckBox::OnMouseLeft)); - Disconnect(wxEVT_LEFT_UP, wxMouseEventHandler(wxCheckBox::OnMouseLeft)); - Disconnect(wxEVT_SET_FOCUS, wxFocusEventHandler(wxCheckBox::OnFocus)); - Disconnect(wxEVT_KILL_FOCUS, wxFocusEventHandler(wxCheckBox::OnFocus)); - } - - ::SetWindowLong(GetHwnd(), GWL_STYLE, style); - - if ( !ownerDrawn ) - { - // ensure that controls state is consistent with internal state - DoSet3StateValue(m_state); - } -} - -void wxCheckBox::OnMouseEnterOrLeave(wxMouseEvent& event) -{ - m_isHot = event.GetEventType() == wxEVT_ENTER_WINDOW; - if ( !m_isHot ) - m_isPressed = false; - - Refresh(); - - event.Skip(); -} - -void wxCheckBox::OnMouseLeft(wxMouseEvent& event) -{ - // TODO: we should capture the mouse here to be notified about left up - // event but this interferes with BN_CLICKED generation so if we - // want to do this we'd need to generate them ourselves - m_isPressed = event.GetEventType() == wxEVT_LEFT_DOWN; - Refresh(); - - event.Skip(); -} - -void wxCheckBox::OnFocus(wxFocusEvent& event) -{ - Refresh(); - - event.Skip(); -} - -bool wxCheckBox::MSWOnDraw(WXDRAWITEMSTRUCT *item) -{ - DRAWITEMSTRUCT *dis = (DRAWITEMSTRUCT *)item; - - if ( !IsOwnerDrawn() || dis->CtlType != ODT_BUTTON ) - return wxCheckBoxBase::MSWOnDraw(item); - - // calculate the rectangles for the check mark itself and the label - HDC hdc = dis->hDC; - RECT& rect = dis->rcItem; - RECT rectCheck, - rectLabel; - rectCheck.top = - rectLabel.top = rect.top; - rectCheck.bottom = - rectLabel.bottom = rect.bottom; - const int checkSize = GetBestSize().y; - const int MARGIN = 3; - - const bool isRightAligned = HasFlag(wxALIGN_RIGHT); - if ( isRightAligned ) - { - rectCheck.right = rect.right; - rectCheck.left = rectCheck.right - checkSize; - - rectLabel.right = rectCheck.left - MARGIN; - rectLabel.left = rect.left; - } - else // normal, left-aligned checkbox - { - rectCheck.left = rect.left; - rectCheck.right = rectCheck.left + checkSize; - - rectLabel.left = rectCheck.right + MARGIN; - rectLabel.right = rect.right; - } - - // show we draw a focus rect? - const bool isFocused = m_isPressed || FindFocus() == this; - - - // draw the checkbox itself: note that this should really, really be in - // wxRendererNative but unfortunately we can't add a new virtual function - // to it without breaking backwards compatibility - - // classic Win32 version -- this can be useful when we move this into - // wxRendererNative -#if defined(__WXWINCE__) || !wxUSE_UXTHEME - UINT state = DFCS_BUTTONCHECK; - if ( !IsEnabled() ) - state |= DFCS_INACTIVE; - switch ( Get3StateValue() ) - { - case wxCHK_CHECKED: - state |= DFCS_CHECKED; - break; - - case wxCHK_UNDETERMINED: - state |= DFCS_PUSHED; - break; - - default: - wxFAIL_MSG( _T("unexpected Get3StateValue() return value") ); - // fall through - - case wxCHK_UNCHECKED: - // no extra styles needed - break; - } - - if ( wxFindWindowAtPoint(wxGetMousePosition()) == this ) - state |= DFCS_HOT; - - if ( !::DrawFrameControl(hdc, &rectCheck, DFC_BUTTON, state) ) - { - wxLogLastError(_T("DrawFrameControl(DFC_BUTTON)")); - } -#else // XP version - wxUxThemeEngine *themeEngine = wxUxThemeEngine::GetIfActive(); - if ( !themeEngine ) - return false; - - wxUxThemeHandle theme(this, L"BUTTON"); - if ( !theme ) - return false; - - int state; - switch ( Get3StateValue() ) - { - case wxCHK_CHECKED: - state = CBS_CHECKEDNORMAL; - break; - - case wxCHK_UNDETERMINED: - state = CBS_MIXEDNORMAL; - break; - - default: - wxFAIL_MSG( _T("unexpected Get3StateValue() return value") ); - // fall through - - case wxCHK_UNCHECKED: - state = CBS_UNCHECKEDNORMAL; - break; - } - - if ( !IsEnabled() ) - state += CBS_DISABLED_OFFSET; - else if ( m_isPressed ) - state += CBS_PRESSED_OFFSET; - else if ( m_isHot ) - state += CBS_HOT_OFFSET; - - HRESULT hr = themeEngine->DrawThemeBackground - ( - theme, - hdc, - BP_CHECKBOX, - state, - &rectCheck, - NULL - ); - if ( FAILED(hr) ) - { - wxLogApiError(_T("DrawThemeBackground(BP_CHECKBOX)"), hr); - } -#endif // 0/1 - - // draw the text - const wxString& label = GetLabel(); - - // first we need to measure it - UINT fmt = DT_NOCLIP; - - // drawing underlying doesn't look well with focus rect (and the native - // control doesn't do it) - if ( isFocused ) - fmt |= DT_HIDEPREFIX; - if ( isRightAligned ) - fmt |= DT_RIGHT; - // TODO: also use DT_HIDEPREFIX if the system is configured so - - // we need to get the label real size first if we have to draw a focus rect - // around it - if ( isFocused ) - { - if ( !::DrawText(hdc, label, label.length(), &rectLabel, - fmt | DT_CALCRECT) ) - { - wxLogLastError(_T("DrawText(DT_CALCRECT)")); - } - } - - if ( !IsEnabled() ) - { - ::SetTextColor(hdc, ::GetSysColor(COLOR_GRAYTEXT)); - } - - if ( !::DrawText(hdc, label, label.length(), &rectLabel, fmt) ) - { - wxLogLastError(_T("DrawText()")); - } - - // finally draw the focus - if ( isFocused ) - { - rectLabel.left--; - rectLabel.right++; - if ( !::DrawFocusRect(hdc, &rectLabel) ) - { - wxLogLastError(_T("DrawFocusRect()")); - } - } - - return true; -} - -#endif // wxUSE_CHECKBOX +///////////////////////////////////////////////////////////////////////////// +// Name: src/msw/checkbox.cpp +// Purpose: wxCheckBox +// Author: Julian Smart +// Modified by: +// Created: 04/01/98 +// RCS-ID: $Id: checkbox.cpp 40331 2006-07-25 18:47:39Z VZ $ +// Copyright: (c) Julian Smart +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_CHECKBOX + +#include "wx/checkbox.h" + +#ifndef WX_PRECOMP + #include "wx/brush.h" + #include "wx/dcscreen.h" + #include "wx/settings.h" +#endif + +#include "wx/msw/uxtheme.h" +#include "wx/msw/private.h" + +// ---------------------------------------------------------------------------- +// constants +// ---------------------------------------------------------------------------- + +#ifndef BST_UNCHECKED + #define BST_UNCHECKED 0x0000 +#endif + +#ifndef BST_CHECKED + #define BST_CHECKED 0x0001 +#endif + +#ifndef BST_INDETERMINATE + #define BST_INDETERMINATE 0x0002 +#endif + +#ifndef DFCS_HOT + #define DFCS_HOT 0x1000 +#endif + +#ifndef DT_HIDEPREFIX + #define DT_HIDEPREFIX 0x00100000 +#endif + +#ifndef BP_CHECKBOX + #define BP_CHECKBOX 3 +#endif + +// these values are defined in tmschema.h (except the first one) +enum +{ + CBS_INVALID, + CBS_UNCHECKEDNORMAL, + CBS_UNCHECKEDHOT, + CBS_UNCHECKEDPRESSED, + CBS_UNCHECKEDDISABLED, + CBS_CHECKEDNORMAL, + CBS_CHECKEDHOT, + CBS_CHECKEDPRESSED, + CBS_CHECKEDDISABLED, + CBS_MIXEDNORMAL, + CBS_MIXEDHOT, + CBS_MIXEDPRESSED, + CBS_MIXEDDISABLED +}; + +// these are our own +enum +{ + CBS_HOT_OFFSET = 1, + CBS_PRESSED_OFFSET = 2, + CBS_DISABLED_OFFSET = 3 +}; + +// ============================================================================ +// implementation +// ============================================================================ + +#if wxUSE_EXTENDED_RTTI +WX_DEFINE_FLAGS( wxCheckBoxStyle ) + +wxBEGIN_FLAGS( wxCheckBoxStyle ) + // new style border flags, we put them first to + // use them for streaming out + wxFLAGS_MEMBER(wxBORDER_SIMPLE) + wxFLAGS_MEMBER(wxBORDER_SUNKEN) + wxFLAGS_MEMBER(wxBORDER_DOUBLE) + wxFLAGS_MEMBER(wxBORDER_RAISED) + wxFLAGS_MEMBER(wxBORDER_STATIC) + wxFLAGS_MEMBER(wxBORDER_NONE) + + // old style border flags + wxFLAGS_MEMBER(wxSIMPLE_BORDER) + wxFLAGS_MEMBER(wxSUNKEN_BORDER) + wxFLAGS_MEMBER(wxDOUBLE_BORDER) + wxFLAGS_MEMBER(wxRAISED_BORDER) + wxFLAGS_MEMBER(wxSTATIC_BORDER) + wxFLAGS_MEMBER(wxNO_BORDER) + + // standard window styles + wxFLAGS_MEMBER(wxTAB_TRAVERSAL) + wxFLAGS_MEMBER(wxCLIP_CHILDREN) + wxFLAGS_MEMBER(wxTRANSPARENT_WINDOW) + wxFLAGS_MEMBER(wxWANTS_CHARS) + wxFLAGS_MEMBER(wxNO_FULL_REPAINT_ON_RESIZE) + wxFLAGS_MEMBER(wxALWAYS_SHOW_SB ) + wxFLAGS_MEMBER(wxVSCROLL) + wxFLAGS_MEMBER(wxHSCROLL) + +wxEND_FLAGS( wxCheckBoxStyle ) + +IMPLEMENT_DYNAMIC_CLASS_XTI(wxCheckBox, wxControl,"wx/checkbox.h") + +wxBEGIN_PROPERTIES_TABLE(wxCheckBox) + wxEVENT_PROPERTY( Click , wxEVT_COMMAND_CHECKBOX_CLICKED , wxCommandEvent ) + + wxPROPERTY( Font , wxFont , SetFont , GetFont , EMPTY_MACROVALUE , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) + wxPROPERTY( Label,wxString, SetLabel, GetLabel, wxString() , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) + wxPROPERTY( Value ,bool, SetValue, GetValue, EMPTY_MACROVALUE, 0 /*flags*/ , wxT("Helpstring") , wxT("group")) + wxPROPERTY_FLAGS( WindowStyle , wxCheckBoxStyle , long , SetWindowStyleFlag , GetWindowStyleFlag , EMPTY_MACROVALUE, 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // style +wxEND_PROPERTIES_TABLE() + +wxBEGIN_HANDLERS_TABLE(wxCheckBox) +wxEND_HANDLERS_TABLE() + +wxCONSTRUCTOR_6( wxCheckBox , wxWindow* , Parent , wxWindowID , Id , wxString , Label , wxPoint , Position , wxSize , Size , long , WindowStyle ) +#else +IMPLEMENT_DYNAMIC_CLASS(wxCheckBox, wxControl) +#endif + + +// ---------------------------------------------------------------------------- +// wxCheckBox creation +// ---------------------------------------------------------------------------- + +void wxCheckBox::Init() +{ + m_state = wxCHK_UNCHECKED; + m_isPressed = + m_isHot = false; +} + +bool wxCheckBox::Create(wxWindow *parent, + wxWindowID id, + const wxString& label, + const wxPoint& pos, + const wxSize& size, long style, + const wxValidator& validator, + const wxString& name) +{ + Init(); + + if ( !CreateControl(parent, id, pos, size, style, validator, name) ) + return false; + + long msStyle = WS_TABSTOP; + + if ( style & wxCHK_3STATE ) + { + msStyle |= BS_3STATE; + } + else + { + wxASSERT_MSG( !Is3rdStateAllowedForUser(), + wxT("Using wxCH_ALLOW_3RD_STATE_FOR_USER") + wxT(" style flag for a 2-state checkbox is useless") ); + msStyle |= BS_CHECKBOX; + } + + if ( style & wxALIGN_RIGHT ) + { + msStyle |= BS_LEFTTEXT | BS_RIGHT; + } + + return MSWCreateControl(wxT("BUTTON"), msStyle, pos, size, label, 0); +} + +// ---------------------------------------------------------------------------- +// wxCheckBox geometry +// ---------------------------------------------------------------------------- + +wxSize wxCheckBox::DoGetBestSize() const +{ + static int s_checkSize = 0; + + if ( !s_checkSize ) + { + wxScreenDC dc; + dc.SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT)); + + s_checkSize = dc.GetCharHeight(); + } + + wxString str = wxGetWindowText(GetHWND()); + + int wCheckbox, hCheckbox; + if ( !str.empty() ) + { + GetTextExtent(GetLabelText(str), &wCheckbox, &hCheckbox); + wCheckbox += s_checkSize + GetCharWidth(); + + if ( hCheckbox < s_checkSize ) + hCheckbox = s_checkSize; + } + else + { + wCheckbox = s_checkSize; + hCheckbox = s_checkSize; + } +#ifdef __WXWINCE__ + hCheckbox += 1; +#endif + + wxSize best(wCheckbox, hCheckbox); + CacheBestSize(best); + return best; +} + +// ---------------------------------------------------------------------------- +// wxCheckBox operations +// ---------------------------------------------------------------------------- + +void wxCheckBox::SetValue(bool val) +{ + Set3StateValue(val ? wxCHK_CHECKED : wxCHK_UNCHECKED); +} + +bool wxCheckBox::GetValue() const +{ + return Get3StateValue() != wxCHK_UNCHECKED; +} + +void wxCheckBox::Command(wxCommandEvent& event) +{ + int state = event.GetInt(); + wxCHECK_RET( (state == wxCHK_UNCHECKED) || (state == wxCHK_CHECKED) + || (state == wxCHK_UNDETERMINED), + wxT("event.GetInt() returned an invalid checkbox state") ); + + Set3StateValue((wxCheckBoxState) state); + ProcessCommand(event); +} + +wxCOMPILE_TIME_ASSERT(wxCHK_UNCHECKED == BST_UNCHECKED + && wxCHK_CHECKED == BST_CHECKED + && wxCHK_UNDETERMINED == BST_INDETERMINATE, EnumValuesIncorrect); + +void wxCheckBox::DoSet3StateValue(wxCheckBoxState state) +{ + m_state = state; + if ( !IsOwnerDrawn() ) + ::SendMessage(GetHwnd(), BM_SETCHECK, (WPARAM) state, 0); + else // owner drawn buttons don't react to this message + Refresh(); +} + +wxCheckBoxState wxCheckBox::DoGet3StateValue() const +{ + return m_state; +} + +bool wxCheckBox::MSWCommand(WXUINT cmd, WXWORD WXUNUSED(id)) +{ + if ( cmd != BN_CLICKED && cmd != BN_DBLCLK ) + return false; + + // first update the value so that user event handler gets the new checkbox + // value + + // ownerdrawn buttons don't manage their state themselves unlike usual + // auto checkboxes so do it ourselves in any case + wxCheckBoxState state; + if ( Is3rdStateAllowedForUser() ) + { + state = (wxCheckBoxState)((m_state + 1) % 3); + } + else // 2 state checkbox (at least from users point of view) + { + // note that wxCHK_UNDETERMINED also becomes unchecked when clicked + state = m_state == wxCHK_UNCHECKED ? wxCHK_CHECKED : wxCHK_UNCHECKED; + } + + DoSet3StateValue(state); + + + // generate the event + wxCommandEvent event(wxEVT_COMMAND_CHECKBOX_CLICKED, m_windowId); + + event.SetInt(state); + event.SetEventObject(this); + ProcessCommand(event); + + return true; +} + +// ---------------------------------------------------------------------------- +// owner drawn checkboxes stuff +// ---------------------------------------------------------------------------- + +bool wxCheckBox::SetForegroundColour(const wxColour& colour) +{ + if ( !wxCheckBoxBase::SetForegroundColour(colour) ) + return false; + + // the only way to change the checkbox foreground colour under Windows XP + // is to owner draw it + if ( wxUxThemeEngine::GetIfActive() ) + MakeOwnerDrawn(colour.Ok()); + + return true; +} + +bool wxCheckBox::IsOwnerDrawn() const +{ + return + (::GetWindowLong(GetHwnd(), GWL_STYLE) & BS_OWNERDRAW) == BS_OWNERDRAW; +} + +void wxCheckBox::MakeOwnerDrawn(bool ownerDrawn) +{ + long style = ::GetWindowLong(GetHwnd(), GWL_STYLE); + + // note that BS_CHECKBOX & BS_OWNERDRAW != 0 so we can't operate on + // them as on independent style bits + if ( ownerDrawn ) + { + style &= ~(BS_CHECKBOX | BS_3STATE); + style |= BS_OWNERDRAW; + + Connect(wxEVT_ENTER_WINDOW, + wxMouseEventHandler(wxCheckBox::OnMouseEnterOrLeave)); + Connect(wxEVT_LEAVE_WINDOW, + wxMouseEventHandler(wxCheckBox::OnMouseEnterOrLeave)); + Connect(wxEVT_LEFT_DOWN, wxMouseEventHandler(wxCheckBox::OnMouseLeft)); + Connect(wxEVT_LEFT_UP, wxMouseEventHandler(wxCheckBox::OnMouseLeft)); + Connect(wxEVT_SET_FOCUS, wxFocusEventHandler(wxCheckBox::OnFocus)); + Connect(wxEVT_KILL_FOCUS, wxFocusEventHandler(wxCheckBox::OnFocus)); + } + else // reset to default colour + { + style &= ~BS_OWNERDRAW; + style |= HasFlag(wxCHK_3STATE) ? BS_3STATE : BS_CHECKBOX; + + Disconnect(wxEVT_ENTER_WINDOW, + wxMouseEventHandler(wxCheckBox::OnMouseEnterOrLeave)); + Disconnect(wxEVT_LEAVE_WINDOW, + wxMouseEventHandler(wxCheckBox::OnMouseEnterOrLeave)); + Disconnect(wxEVT_LEFT_DOWN, wxMouseEventHandler(wxCheckBox::OnMouseLeft)); + Disconnect(wxEVT_LEFT_UP, wxMouseEventHandler(wxCheckBox::OnMouseLeft)); + Disconnect(wxEVT_SET_FOCUS, wxFocusEventHandler(wxCheckBox::OnFocus)); + Disconnect(wxEVT_KILL_FOCUS, wxFocusEventHandler(wxCheckBox::OnFocus)); + } + + ::SetWindowLong(GetHwnd(), GWL_STYLE, style); + + if ( !ownerDrawn ) + { + // ensure that controls state is consistent with internal state + DoSet3StateValue(m_state); + } +} + +void wxCheckBox::OnMouseEnterOrLeave(wxMouseEvent& event) +{ + m_isHot = event.GetEventType() == wxEVT_ENTER_WINDOW; + if ( !m_isHot ) + m_isPressed = false; + + Refresh(); + + event.Skip(); +} + +void wxCheckBox::OnMouseLeft(wxMouseEvent& event) +{ + // TODO: we should capture the mouse here to be notified about left up + // event but this interferes with BN_CLICKED generation so if we + // want to do this we'd need to generate them ourselves + m_isPressed = event.GetEventType() == wxEVT_LEFT_DOWN; + Refresh(); + + event.Skip(); +} + +void wxCheckBox::OnFocus(wxFocusEvent& event) +{ + Refresh(); + + event.Skip(); +} + +bool wxCheckBox::MSWOnDraw(WXDRAWITEMSTRUCT *item) +{ + DRAWITEMSTRUCT *dis = (DRAWITEMSTRUCT *)item; + + if ( !IsOwnerDrawn() || dis->CtlType != ODT_BUTTON ) + return wxCheckBoxBase::MSWOnDraw(item); + + // calculate the rectangles for the check mark itself and the label + HDC hdc = dis->hDC; + RECT& rect = dis->rcItem; + RECT rectCheck, + rectLabel; + rectCheck.top = + rectLabel.top = rect.top; + rectCheck.bottom = + rectLabel.bottom = rect.bottom; + const int checkSize = GetBestSize().y; + const int MARGIN = 3; + + const bool isRightAligned = HasFlag(wxALIGN_RIGHT); + if ( isRightAligned ) + { + rectCheck.right = rect.right; + rectCheck.left = rectCheck.right - checkSize; + + rectLabel.right = rectCheck.left - MARGIN; + rectLabel.left = rect.left; + } + else // normal, left-aligned checkbox + { + rectCheck.left = rect.left; + rectCheck.right = rectCheck.left + checkSize; + + rectLabel.left = rectCheck.right + MARGIN; + rectLabel.right = rect.right; + } + + // show we draw a focus rect? + const bool isFocused = m_isPressed || FindFocus() == this; + + + // draw the checkbox itself: note that this should really, really be in + // wxRendererNative but unfortunately we can't add a new virtual function + // to it without breaking backwards compatibility + + // classic Win32 version -- this can be useful when we move this into + // wxRendererNative +#if defined(__WXWINCE__) || !wxUSE_UXTHEME + UINT state = DFCS_BUTTONCHECK; + if ( !IsEnabled() ) + state |= DFCS_INACTIVE; + switch ( Get3StateValue() ) + { + case wxCHK_CHECKED: + state |= DFCS_CHECKED; + break; + + case wxCHK_UNDETERMINED: + state |= DFCS_PUSHED; + break; + + default: + wxFAIL_MSG( _T("unexpected Get3StateValue() return value") ); + // fall through + + case wxCHK_UNCHECKED: + // no extra styles needed + break; + } + + if ( wxFindWindowAtPoint(wxGetMousePosition()) == this ) + state |= DFCS_HOT; + + if ( !::DrawFrameControl(hdc, &rectCheck, DFC_BUTTON, state) ) + { + wxLogLastError(_T("DrawFrameControl(DFC_BUTTON)")); + } +#else // XP version + wxUxThemeEngine *themeEngine = wxUxThemeEngine::GetIfActive(); + if ( !themeEngine ) + return false; + + wxUxThemeHandle theme(this, L"BUTTON"); + if ( !theme ) + return false; + + int state; + switch ( Get3StateValue() ) + { + case wxCHK_CHECKED: + state = CBS_CHECKEDNORMAL; + break; + + case wxCHK_UNDETERMINED: + state = CBS_MIXEDNORMAL; + break; + + default: + wxFAIL_MSG( _T("unexpected Get3StateValue() return value") ); + // fall through + + case wxCHK_UNCHECKED: + state = CBS_UNCHECKEDNORMAL; + break; + } + + if ( !IsEnabled() ) + state += CBS_DISABLED_OFFSET; + else if ( m_isPressed ) + state += CBS_PRESSED_OFFSET; + else if ( m_isHot ) + state += CBS_HOT_OFFSET; + + HRESULT hr = themeEngine->DrawThemeBackground + ( + theme, + hdc, + BP_CHECKBOX, + state, + &rectCheck, + NULL + ); + if ( FAILED(hr) ) + { + wxLogApiError(_T("DrawThemeBackground(BP_CHECKBOX)"), hr); + } +#endif // 0/1 + + // draw the text + const wxString& label = GetLabel(); + + // first we need to measure it + UINT fmt = DT_NOCLIP; + + // drawing underlying doesn't look well with focus rect (and the native + // control doesn't do it) + if ( isFocused ) + fmt |= DT_HIDEPREFIX; + if ( isRightAligned ) + fmt |= DT_RIGHT; + // TODO: also use DT_HIDEPREFIX if the system is configured so + + // we need to get the label real size first if we have to draw a focus rect + // around it + if ( isFocused ) + { + if ( !::DrawText(hdc, label, label.length(), &rectLabel, + fmt | DT_CALCRECT) ) + { + wxLogLastError(_T("DrawText(DT_CALCRECT)")); + } + } + + if ( !IsEnabled() ) + { + ::SetTextColor(hdc, ::GetSysColor(COLOR_GRAYTEXT)); + } + + if ( !::DrawText(hdc, label, label.length(), &rectLabel, fmt) ) + { + wxLogLastError(_T("DrawText()")); + } + + // finally draw the focus + if ( isFocused ) + { + rectLabel.left--; + rectLabel.right++; + if ( !::DrawFocusRect(hdc, &rectLabel) ) + { + wxLogLastError(_T("DrawFocusRect()")); + } + } + + return true; +} + +#endif // wxUSE_CHECKBOX diff --git a/Externals/wxWidgets/src/msw/checklst.cpp b/Externals/wxWidgets/src/msw/checklst.cpp index 09a58bc69e..ac98e3e0c1 100644 --- a/Externals/wxWidgets/src/msw/checklst.cpp +++ b/Externals/wxWidgets/src/msw/checklst.cpp @@ -1,538 +1,538 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: src/msw/checklst.cpp -// Purpose: implementation of wxCheckListBox class -// Author: Vadim Zeitlin -// Modified by: -// Created: 16.11.97 -// RCS-ID: $Id: checklst.cpp 53057 2008-04-06 15:57:54Z VZ $ -// Copyright: (c) 1998 Vadim Zeitlin -// Licence: wxWindows licence -/////////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_CHECKLISTBOX && wxUSE_OWNER_DRAWN - -#include "wx/checklst.h" - -#ifndef WX_PRECOMP - #include "wx/msw/wrapwin.h" - #include "wx/object.h" - #include "wx/colour.h" - #include "wx/font.h" - #include "wx/bitmap.h" - #include "wx/window.h" - #include "wx/listbox.h" - #include "wx/dcmemory.h" - #include "wx/settings.h" - #include "wx/log.h" -#endif - -#include "wx/ownerdrw.h" - -#include - -#include "wx/msw/private.h" - -// ---------------------------------------------------------------------------- -// private functions -// ---------------------------------------------------------------------------- - -// get item (converted to right type) -#define GetItem(n) ((wxCheckListBoxItem *)(GetItem(n))) - -// ============================================================================ -// implementation -// ============================================================================ - - -#if wxUSE_EXTENDED_RTTI -WX_DEFINE_FLAGS( wxCheckListBoxStyle ) - -wxBEGIN_FLAGS( wxCheckListBoxStyle ) - // new style border flags, we put them first to - // use them for streaming out - wxFLAGS_MEMBER(wxBORDER_SIMPLE) - wxFLAGS_MEMBER(wxBORDER_SUNKEN) - wxFLAGS_MEMBER(wxBORDER_DOUBLE) - wxFLAGS_MEMBER(wxBORDER_RAISED) - wxFLAGS_MEMBER(wxBORDER_STATIC) - wxFLAGS_MEMBER(wxBORDER_NONE) - - // old style border flags - wxFLAGS_MEMBER(wxSIMPLE_BORDER) - wxFLAGS_MEMBER(wxSUNKEN_BORDER) - wxFLAGS_MEMBER(wxDOUBLE_BORDER) - wxFLAGS_MEMBER(wxRAISED_BORDER) - wxFLAGS_MEMBER(wxSTATIC_BORDER) - wxFLAGS_MEMBER(wxBORDER) - - // standard window styles - wxFLAGS_MEMBER(wxTAB_TRAVERSAL) - wxFLAGS_MEMBER(wxCLIP_CHILDREN) - wxFLAGS_MEMBER(wxTRANSPARENT_WINDOW) - wxFLAGS_MEMBER(wxWANTS_CHARS) - wxFLAGS_MEMBER(wxFULL_REPAINT_ON_RESIZE) - wxFLAGS_MEMBER(wxALWAYS_SHOW_SB ) - wxFLAGS_MEMBER(wxVSCROLL) - wxFLAGS_MEMBER(wxHSCROLL) - - wxFLAGS_MEMBER(wxLB_SINGLE) - wxFLAGS_MEMBER(wxLB_MULTIPLE) - wxFLAGS_MEMBER(wxLB_EXTENDED) - wxFLAGS_MEMBER(wxLB_HSCROLL) - wxFLAGS_MEMBER(wxLB_ALWAYS_SB) - wxFLAGS_MEMBER(wxLB_NEEDED_SB) - wxFLAGS_MEMBER(wxLB_SORT) - wxFLAGS_MEMBER(wxLB_OWNERDRAW) - -wxEND_FLAGS( wxCheckListBoxStyle ) - -IMPLEMENT_DYNAMIC_CLASS_XTI(wxCheckListBox, wxListBox,"wx/checklst.h") - -wxBEGIN_PROPERTIES_TABLE(wxCheckListBox) - wxEVENT_PROPERTY( Toggle , wxEVT_COMMAND_CHECKLISTBOX_TOGGLED , wxCommandEvent ) - wxPROPERTY_FLAGS( WindowStyle , wxCheckListBoxStyle , long , SetWindowStyleFlag , GetWindowStyleFlag , EMPTY_MACROVALUE , wxLB_OWNERDRAW /*flags*/ , wxT("Helpstring") , wxT("group")) // style -wxEND_PROPERTIES_TABLE() - -wxBEGIN_HANDLERS_TABLE(wxCheckListBox) -wxEND_HANDLERS_TABLE() - -wxCONSTRUCTOR_4( wxCheckListBox , wxWindow* , Parent , wxWindowID , Id , wxPoint , Position , wxSize , Size ) - -#else -IMPLEMENT_DYNAMIC_CLASS(wxCheckListBox, wxListBox) -#endif - -// ---------------------------------------------------------------------------- -// declaration and implementation of wxCheckListBoxItem class -// ---------------------------------------------------------------------------- - -class wxCheckListBoxItem : public wxOwnerDrawn -{ -friend class WXDLLIMPEXP_FWD_CORE wxCheckListBox; -public: - // ctor - wxCheckListBoxItem(wxCheckListBox *pParent, size_t nIndex); - - // drawing functions - virtual bool OnDrawItem(wxDC& dc, const wxRect& rc, wxODAction act, wxODStatus stat); - - // simple accessors and operations - bool IsChecked() const { return m_bChecked; } - - void Check(bool bCheck); - void Toggle() { Check(!IsChecked()); } - - void SendEvent(); - -private: - bool m_bChecked; - wxCheckListBox *m_pParent; - size_t m_nIndex; - - DECLARE_NO_COPY_CLASS(wxCheckListBoxItem) -}; - -wxCheckListBoxItem::wxCheckListBoxItem(wxCheckListBox *pParent, size_t nIndex) - : wxOwnerDrawn(wxEmptyString, true) // checkable -{ - m_bChecked = false; - m_pParent = pParent; - m_nIndex = nIndex; - - // we don't initialize m_nCheckHeight/Width vars because it's - // done in OnMeasure while they are used only in OnDraw and we - // know that there will always be OnMeasure before OnDraw - - // fix appearance for check list boxes: they don't look quite the same as - // menu icons - SetMarginWidth(::GetSystemMetrics(SM_CXMENUCHECK) - - 2*wxSystemSettings::GetMetric(wxSYS_EDGE_X) + 1); - SetBackgroundColour(pParent->GetBackgroundColour()); -} - -bool wxCheckListBoxItem::OnDrawItem(wxDC& dc, const wxRect& rc, - wxODAction act, wxODStatus stat) -{ - // first draw the label - if ( IsChecked() ) - stat = (wxOwnerDrawn::wxODStatus)(stat | wxOwnerDrawn::wxODChecked); - - if ( !wxOwnerDrawn::OnDrawItem(dc, rc, act, stat) ) - return false; - - - // now draw the check mark part - size_t nCheckWidth = GetDefaultMarginWidth(), - nCheckHeight = m_pParent->GetItemHeight(); - - int x = rc.GetX(), - y = rc.GetY(); - - HDC hdc = (HDC)dc.GetHDC(); - - // create pens, brushes &c - COLORREF colBg = wxColourToRGB(GetBackgroundColour()); - AutoHPEN hpenBack(colBg), - hpenGray(RGB(0xc0, 0xc0, 0xc0)); - - SelectInHDC selPen(hdc, (HGDIOBJ)hpenBack); - AutoHBRUSH hbrBack(colBg); - SelectInHDC selBrush(hdc, hbrBack); - - // erase the background: it could have been filled with the selected colour - Rectangle(hdc, x, y, x + nCheckWidth + 1, rc.GetBottom() + 1); - - // shift check mark 1 pixel to the right, looks better like this - x++; - - if ( IsChecked() ) - { - // first create a monochrome bitmap in a memory DC - MemoryHDC hdcMem(hdc); - MonoBitmap hbmpCheck(nCheckWidth, nCheckHeight); - SelectInHDC selBmp(hdcMem, hbmpCheck); - - // then draw a check mark into it - RECT rect = { 0, 0, nCheckWidth, nCheckHeight }; - ::DrawFrameControl(hdcMem, &rect, -#ifdef __WXWINCE__ - DFC_BUTTON, DFCS_BUTTONCHECK -#else - DFC_MENU, DFCS_MENUCHECK -#endif - ); - - // finally copy it to screen DC - ::BitBlt(hdc, x, y, nCheckWidth, nCheckHeight, hdcMem, 0, 0, SRCCOPY); - } - - // now we draw the smaller rectangle - y++; - nCheckWidth -= 2; - nCheckHeight -= 2; - - // draw hollow gray rectangle - (void)::SelectObject(hdc, (HGDIOBJ)hpenGray); - - SelectInHDC selBrush2(hdc, ::GetStockObject(NULL_BRUSH)); - Rectangle(hdc, x, y, x + nCheckWidth, y + nCheckHeight); - - return true; -} - -// change the state of the item and redraw it -void wxCheckListBoxItem::Check(bool check) -{ - m_bChecked = check; - - // index may be changed because new items were added/deleted - if ( m_pParent->GetItemIndex(this) != (int)m_nIndex ) - { - // update it - int index = m_pParent->GetItemIndex(this); - - wxASSERT_MSG( index != wxNOT_FOUND, wxT("what does this item do here?") ); - - m_nIndex = (size_t)index; - } - - HWND hwndListbox = (HWND)m_pParent->GetHWND(); - - RECT rcUpdate; - - if ( ::SendMessage(hwndListbox, LB_GETITEMRECT, - m_nIndex, (LPARAM)&rcUpdate) == LB_ERR ) - { - wxLogDebug(wxT("LB_GETITEMRECT failed")); - } - - ::InvalidateRect(hwndListbox, &rcUpdate, FALSE); -} - -// send an "item checked" event -void wxCheckListBoxItem::SendEvent() -{ - wxCommandEvent event(wxEVT_COMMAND_CHECKLISTBOX_TOGGLED, m_pParent->GetId()); - event.SetInt(m_nIndex); - event.SetEventObject(m_pParent); - m_pParent->ProcessCommand(event); -} - -// ---------------------------------------------------------------------------- -// implementation of wxCheckListBox class -// ---------------------------------------------------------------------------- - -// define event table -// ------------------ -BEGIN_EVENT_TABLE(wxCheckListBox, wxListBox) - EVT_KEY_DOWN(wxCheckListBox::OnKeyDown) - EVT_LEFT_DOWN(wxCheckListBox::OnLeftClick) -END_EVENT_TABLE() - -// control creation -// ---------------- - -// def ctor: use Create() to really create the control -wxCheckListBox::wxCheckListBox() -{ -} - -// ctor which creates the associated control -wxCheckListBox::wxCheckListBox(wxWindow *parent, wxWindowID id, - const wxPoint& pos, const wxSize& size, - int nStrings, const wxString choices[], - long style, const wxValidator& val, - const wxString& name) -{ - Create(parent, id, pos, size, nStrings, choices, style, val, name); -} - -wxCheckListBox::wxCheckListBox(wxWindow *parent, wxWindowID id, - const wxPoint& pos, const wxSize& size, - const wxArrayString& choices, - long style, const wxValidator& val, - const wxString& name) -{ - Create(parent, id, pos, size, choices, style, val, name); -} - -bool wxCheckListBox::Create(wxWindow *parent, wxWindowID id, - const wxPoint& pos, const wxSize& size, - int n, const wxString choices[], - long style, - const wxValidator& validator, const wxString& name) -{ - return wxListBox::Create(parent, id, pos, size, n, choices, - style | wxLB_OWNERDRAW, validator, name); -} - -bool wxCheckListBox::Create(wxWindow *parent, wxWindowID id, - const wxPoint& pos, const wxSize& size, - const wxArrayString& choices, - long style, - const wxValidator& validator, const wxString& name) -{ - return wxListBox::Create(parent, id, pos, size, choices, - style | wxLB_OWNERDRAW, validator, name); -} - -// misc overloaded methods -// ----------------------- - -void wxCheckListBox::Delete(unsigned int n) -{ - wxCHECK_RET( IsValid(n), - wxT("invalid index in wxListBox::Delete") ); - - wxListBox::Delete(n); - - // free memory - delete m_aItems[n]; - - m_aItems.RemoveAt(n); -} - -bool wxCheckListBox::SetFont( const wxFont &font ) -{ - unsigned int i; - for ( i = 0; i < m_aItems.GetCount(); i++ ) - m_aItems[i]->SetFont(font); - - wxListBox::SetFont(font); - - return true; -} - -// create/retrieve item -// -------------------- - -// create a check list box item -wxOwnerDrawn *wxCheckListBox::CreateLboxItem(size_t nIndex) -{ - wxCheckListBoxItem *pItem = new wxCheckListBoxItem(this, nIndex); - return pItem; -} - -// return item size -// ---------------- -bool wxCheckListBox::MSWOnMeasure(WXMEASUREITEMSTRUCT *item) -{ - if ( wxListBox::MSWOnMeasure(item) ) { - MEASUREITEMSTRUCT *pStruct = (MEASUREITEMSTRUCT *)item; - - // save item height - m_nItemHeight = pStruct->itemHeight; - - // add place for the check mark - pStruct->itemWidth += wxOwnerDrawn::GetDefaultMarginWidth(); - - return true; - } - - return false; -} - -// check items -// ----------- - -bool wxCheckListBox::IsChecked(unsigned int uiIndex) const -{ - wxCHECK_MSG( IsValid(uiIndex), false, _T("bad wxCheckListBox index") ); - - return GetItem(uiIndex)->IsChecked(); -} - -void wxCheckListBox::Check(unsigned int uiIndex, bool bCheck) -{ - wxCHECK_RET( IsValid(uiIndex), _T("bad wxCheckListBox index") ); - - GetItem(uiIndex)->Check(bCheck); -} - -// process events -// -------------- - -void wxCheckListBox::OnKeyDown(wxKeyEvent& event) -{ - // what do we do? - enum - { - None, - Toggle, - Set, - Clear - } oper; - - switch ( event.GetKeyCode() ) - { - case WXK_SPACE: - oper = Toggle; - break; - - case WXK_NUMPAD_ADD: - case '+': - oper = Set; - break; - - case WXK_NUMPAD_SUBTRACT: - case '-': - oper = Clear; - break; - - default: - oper = None; - } - - if ( oper != None ) - { - wxArrayInt selections; - int count = 0; - if ( HasMultipleSelection() ) - { - count = GetSelections(selections); - } - else - { - int sel = GetSelection(); - if (sel != -1) - { - count = 1; - selections.Add(sel); - } - } - - for ( int i = 0; i < count; i++ ) - { - wxCheckListBoxItem *item = GetItem(selections[i]); - if ( !item ) - { - wxFAIL_MSG( _T("no wxCheckListBoxItem?") ); - continue; - } - - switch ( oper ) - { - case Toggle: - item->Toggle(); - break; - - case Set: - case Clear: - item->Check( oper == Set ); - break; - - default: - wxFAIL_MSG( _T("what should this key do?") ); - } - - // we should send an event as this has been done by the user and - // not by the program - item->SendEvent(); - } - } - else // nothing to do - { - event.Skip(); - } -} - -void wxCheckListBox::OnLeftClick(wxMouseEvent& event) -{ - // clicking on the item selects it, clicking on the checkmark toggles - if ( event.GetX() <= wxOwnerDrawn::GetDefaultMarginWidth() ) - { - int nItem = HitTest(event.GetX(), event.GetY()); - - if ( nItem != wxNOT_FOUND ) - { - wxCheckListBoxItem *item = GetItem(nItem); - item->Toggle(); - item->SendEvent(); - } - //else: it's not an error, just click outside of client zone - } - else - { - // implement default behaviour: clicking on the item selects it - event.Skip(); - } -} - -int wxCheckListBox::DoHitTestItem(wxCoord x, wxCoord y) const -{ - int nItem = (int)::SendMessage - ( - (HWND)GetHWND(), - LB_ITEMFROMPOINT, - 0, - MAKELPARAM(x, y) - ); - - return nItem >= (int)m_noItems ? wxNOT_FOUND : nItem; -} - - -wxSize wxCheckListBox::DoGetBestSize() const -{ - wxSize best = wxListBox::DoGetBestSize(); - best.x += wxOwnerDrawn::GetDefaultMarginWidth(); // add room for the checkbox - CacheBestSize(best); - return best; -} - -#endif +/////////////////////////////////////////////////////////////////////////////// +// Name: src/msw/checklst.cpp +// Purpose: implementation of wxCheckListBox class +// Author: Vadim Zeitlin +// Modified by: +// Created: 16.11.97 +// RCS-ID: $Id: checklst.cpp 53057 2008-04-06 15:57:54Z VZ $ +// Copyright: (c) 1998 Vadim Zeitlin +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_CHECKLISTBOX && wxUSE_OWNER_DRAWN + +#include "wx/checklst.h" + +#ifndef WX_PRECOMP + #include "wx/msw/wrapwin.h" + #include "wx/object.h" + #include "wx/colour.h" + #include "wx/font.h" + #include "wx/bitmap.h" + #include "wx/window.h" + #include "wx/listbox.h" + #include "wx/dcmemory.h" + #include "wx/settings.h" + #include "wx/log.h" +#endif + +#include "wx/ownerdrw.h" + +#include + +#include "wx/msw/private.h" + +// ---------------------------------------------------------------------------- +// private functions +// ---------------------------------------------------------------------------- + +// get item (converted to right type) +#define GetItem(n) ((wxCheckListBoxItem *)(GetItem(n))) + +// ============================================================================ +// implementation +// ============================================================================ + + +#if wxUSE_EXTENDED_RTTI +WX_DEFINE_FLAGS( wxCheckListBoxStyle ) + +wxBEGIN_FLAGS( wxCheckListBoxStyle ) + // new style border flags, we put them first to + // use them for streaming out + wxFLAGS_MEMBER(wxBORDER_SIMPLE) + wxFLAGS_MEMBER(wxBORDER_SUNKEN) + wxFLAGS_MEMBER(wxBORDER_DOUBLE) + wxFLAGS_MEMBER(wxBORDER_RAISED) + wxFLAGS_MEMBER(wxBORDER_STATIC) + wxFLAGS_MEMBER(wxBORDER_NONE) + + // old style border flags + wxFLAGS_MEMBER(wxSIMPLE_BORDER) + wxFLAGS_MEMBER(wxSUNKEN_BORDER) + wxFLAGS_MEMBER(wxDOUBLE_BORDER) + wxFLAGS_MEMBER(wxRAISED_BORDER) + wxFLAGS_MEMBER(wxSTATIC_BORDER) + wxFLAGS_MEMBER(wxBORDER) + + // standard window styles + wxFLAGS_MEMBER(wxTAB_TRAVERSAL) + wxFLAGS_MEMBER(wxCLIP_CHILDREN) + wxFLAGS_MEMBER(wxTRANSPARENT_WINDOW) + wxFLAGS_MEMBER(wxWANTS_CHARS) + wxFLAGS_MEMBER(wxFULL_REPAINT_ON_RESIZE) + wxFLAGS_MEMBER(wxALWAYS_SHOW_SB ) + wxFLAGS_MEMBER(wxVSCROLL) + wxFLAGS_MEMBER(wxHSCROLL) + + wxFLAGS_MEMBER(wxLB_SINGLE) + wxFLAGS_MEMBER(wxLB_MULTIPLE) + wxFLAGS_MEMBER(wxLB_EXTENDED) + wxFLAGS_MEMBER(wxLB_HSCROLL) + wxFLAGS_MEMBER(wxLB_ALWAYS_SB) + wxFLAGS_MEMBER(wxLB_NEEDED_SB) + wxFLAGS_MEMBER(wxLB_SORT) + wxFLAGS_MEMBER(wxLB_OWNERDRAW) + +wxEND_FLAGS( wxCheckListBoxStyle ) + +IMPLEMENT_DYNAMIC_CLASS_XTI(wxCheckListBox, wxListBox,"wx/checklst.h") + +wxBEGIN_PROPERTIES_TABLE(wxCheckListBox) + wxEVENT_PROPERTY( Toggle , wxEVT_COMMAND_CHECKLISTBOX_TOGGLED , wxCommandEvent ) + wxPROPERTY_FLAGS( WindowStyle , wxCheckListBoxStyle , long , SetWindowStyleFlag , GetWindowStyleFlag , EMPTY_MACROVALUE , wxLB_OWNERDRAW /*flags*/ , wxT("Helpstring") , wxT("group")) // style +wxEND_PROPERTIES_TABLE() + +wxBEGIN_HANDLERS_TABLE(wxCheckListBox) +wxEND_HANDLERS_TABLE() + +wxCONSTRUCTOR_4( wxCheckListBox , wxWindow* , Parent , wxWindowID , Id , wxPoint , Position , wxSize , Size ) + +#else +IMPLEMENT_DYNAMIC_CLASS(wxCheckListBox, wxListBox) +#endif + +// ---------------------------------------------------------------------------- +// declaration and implementation of wxCheckListBoxItem class +// ---------------------------------------------------------------------------- + +class wxCheckListBoxItem : public wxOwnerDrawn +{ +friend class WXDLLIMPEXP_FWD_CORE wxCheckListBox; +public: + // ctor + wxCheckListBoxItem(wxCheckListBox *pParent, size_t nIndex); + + // drawing functions + virtual bool OnDrawItem(wxDC& dc, const wxRect& rc, wxODAction act, wxODStatus stat); + + // simple accessors and operations + bool IsChecked() const { return m_bChecked; } + + void Check(bool bCheck); + void Toggle() { Check(!IsChecked()); } + + void SendEvent(); + +private: + bool m_bChecked; + wxCheckListBox *m_pParent; + size_t m_nIndex; + + DECLARE_NO_COPY_CLASS(wxCheckListBoxItem) +}; + +wxCheckListBoxItem::wxCheckListBoxItem(wxCheckListBox *pParent, size_t nIndex) + : wxOwnerDrawn(wxEmptyString, true) // checkable +{ + m_bChecked = false; + m_pParent = pParent; + m_nIndex = nIndex; + + // we don't initialize m_nCheckHeight/Width vars because it's + // done in OnMeasure while they are used only in OnDraw and we + // know that there will always be OnMeasure before OnDraw + + // fix appearance for check list boxes: they don't look quite the same as + // menu icons + SetMarginWidth(::GetSystemMetrics(SM_CXMENUCHECK) - + 2*wxSystemSettings::GetMetric(wxSYS_EDGE_X) + 1); + SetBackgroundColour(pParent->GetBackgroundColour()); +} + +bool wxCheckListBoxItem::OnDrawItem(wxDC& dc, const wxRect& rc, + wxODAction act, wxODStatus stat) +{ + // first draw the label + if ( IsChecked() ) + stat = (wxOwnerDrawn::wxODStatus)(stat | wxOwnerDrawn::wxODChecked); + + if ( !wxOwnerDrawn::OnDrawItem(dc, rc, act, stat) ) + return false; + + + // now draw the check mark part + size_t nCheckWidth = GetDefaultMarginWidth(), + nCheckHeight = m_pParent->GetItemHeight(); + + int x = rc.GetX(), + y = rc.GetY(); + + HDC hdc = (HDC)dc.GetHDC(); + + // create pens, brushes &c + COLORREF colBg = wxColourToRGB(GetBackgroundColour()); + AutoHPEN hpenBack(colBg), + hpenGray(RGB(0xc0, 0xc0, 0xc0)); + + SelectInHDC selPen(hdc, (HGDIOBJ)hpenBack); + AutoHBRUSH hbrBack(colBg); + SelectInHDC selBrush(hdc, hbrBack); + + // erase the background: it could have been filled with the selected colour + Rectangle(hdc, x, y, x + nCheckWidth + 1, rc.GetBottom() + 1); + + // shift check mark 1 pixel to the right, looks better like this + x++; + + if ( IsChecked() ) + { + // first create a monochrome bitmap in a memory DC + MemoryHDC hdcMem(hdc); + MonoBitmap hbmpCheck(nCheckWidth, nCheckHeight); + SelectInHDC selBmp(hdcMem, hbmpCheck); + + // then draw a check mark into it + RECT rect = { 0, 0, nCheckWidth, nCheckHeight }; + ::DrawFrameControl(hdcMem, &rect, +#ifdef __WXWINCE__ + DFC_BUTTON, DFCS_BUTTONCHECK +#else + DFC_MENU, DFCS_MENUCHECK +#endif + ); + + // finally copy it to screen DC + ::BitBlt(hdc, x, y, nCheckWidth, nCheckHeight, hdcMem, 0, 0, SRCCOPY); + } + + // now we draw the smaller rectangle + y++; + nCheckWidth -= 2; + nCheckHeight -= 2; + + // draw hollow gray rectangle + (void)::SelectObject(hdc, (HGDIOBJ)hpenGray); + + SelectInHDC selBrush2(hdc, ::GetStockObject(NULL_BRUSH)); + Rectangle(hdc, x, y, x + nCheckWidth, y + nCheckHeight); + + return true; +} + +// change the state of the item and redraw it +void wxCheckListBoxItem::Check(bool check) +{ + m_bChecked = check; + + // index may be changed because new items were added/deleted + if ( m_pParent->GetItemIndex(this) != (int)m_nIndex ) + { + // update it + int index = m_pParent->GetItemIndex(this); + + wxASSERT_MSG( index != wxNOT_FOUND, wxT("what does this item do here?") ); + + m_nIndex = (size_t)index; + } + + HWND hwndListbox = (HWND)m_pParent->GetHWND(); + + RECT rcUpdate; + + if ( ::SendMessage(hwndListbox, LB_GETITEMRECT, + m_nIndex, (LPARAM)&rcUpdate) == LB_ERR ) + { + wxLogDebug(wxT("LB_GETITEMRECT failed")); + } + + ::InvalidateRect(hwndListbox, &rcUpdate, FALSE); +} + +// send an "item checked" event +void wxCheckListBoxItem::SendEvent() +{ + wxCommandEvent event(wxEVT_COMMAND_CHECKLISTBOX_TOGGLED, m_pParent->GetId()); + event.SetInt(m_nIndex); + event.SetEventObject(m_pParent); + m_pParent->ProcessCommand(event); +} + +// ---------------------------------------------------------------------------- +// implementation of wxCheckListBox class +// ---------------------------------------------------------------------------- + +// define event table +// ------------------ +BEGIN_EVENT_TABLE(wxCheckListBox, wxListBox) + EVT_KEY_DOWN(wxCheckListBox::OnKeyDown) + EVT_LEFT_DOWN(wxCheckListBox::OnLeftClick) +END_EVENT_TABLE() + +// control creation +// ---------------- + +// def ctor: use Create() to really create the control +wxCheckListBox::wxCheckListBox() +{ +} + +// ctor which creates the associated control +wxCheckListBox::wxCheckListBox(wxWindow *parent, wxWindowID id, + const wxPoint& pos, const wxSize& size, + int nStrings, const wxString choices[], + long style, const wxValidator& val, + const wxString& name) +{ + Create(parent, id, pos, size, nStrings, choices, style, val, name); +} + +wxCheckListBox::wxCheckListBox(wxWindow *parent, wxWindowID id, + const wxPoint& pos, const wxSize& size, + const wxArrayString& choices, + long style, const wxValidator& val, + const wxString& name) +{ + Create(parent, id, pos, size, choices, style, val, name); +} + +bool wxCheckListBox::Create(wxWindow *parent, wxWindowID id, + const wxPoint& pos, const wxSize& size, + int n, const wxString choices[], + long style, + const wxValidator& validator, const wxString& name) +{ + return wxListBox::Create(parent, id, pos, size, n, choices, + style | wxLB_OWNERDRAW, validator, name); +} + +bool wxCheckListBox::Create(wxWindow *parent, wxWindowID id, + const wxPoint& pos, const wxSize& size, + const wxArrayString& choices, + long style, + const wxValidator& validator, const wxString& name) +{ + return wxListBox::Create(parent, id, pos, size, choices, + style | wxLB_OWNERDRAW, validator, name); +} + +// misc overloaded methods +// ----------------------- + +void wxCheckListBox::Delete(unsigned int n) +{ + wxCHECK_RET( IsValid(n), + wxT("invalid index in wxListBox::Delete") ); + + wxListBox::Delete(n); + + // free memory + delete m_aItems[n]; + + m_aItems.RemoveAt(n); +} + +bool wxCheckListBox::SetFont( const wxFont &font ) +{ + unsigned int i; + for ( i = 0; i < m_aItems.GetCount(); i++ ) + m_aItems[i]->SetFont(font); + + wxListBox::SetFont(font); + + return true; +} + +// create/retrieve item +// -------------------- + +// create a check list box item +wxOwnerDrawn *wxCheckListBox::CreateLboxItem(size_t nIndex) +{ + wxCheckListBoxItem *pItem = new wxCheckListBoxItem(this, nIndex); + return pItem; +} + +// return item size +// ---------------- +bool wxCheckListBox::MSWOnMeasure(WXMEASUREITEMSTRUCT *item) +{ + if ( wxListBox::MSWOnMeasure(item) ) { + MEASUREITEMSTRUCT *pStruct = (MEASUREITEMSTRUCT *)item; + + // save item height + m_nItemHeight = pStruct->itemHeight; + + // add place for the check mark + pStruct->itemWidth += wxOwnerDrawn::GetDefaultMarginWidth(); + + return true; + } + + return false; +} + +// check items +// ----------- + +bool wxCheckListBox::IsChecked(unsigned int uiIndex) const +{ + wxCHECK_MSG( IsValid(uiIndex), false, _T("bad wxCheckListBox index") ); + + return GetItem(uiIndex)->IsChecked(); +} + +void wxCheckListBox::Check(unsigned int uiIndex, bool bCheck) +{ + wxCHECK_RET( IsValid(uiIndex), _T("bad wxCheckListBox index") ); + + GetItem(uiIndex)->Check(bCheck); +} + +// process events +// -------------- + +void wxCheckListBox::OnKeyDown(wxKeyEvent& event) +{ + // what do we do? + enum + { + None, + Toggle, + Set, + Clear + } oper; + + switch ( event.GetKeyCode() ) + { + case WXK_SPACE: + oper = Toggle; + break; + + case WXK_NUMPAD_ADD: + case '+': + oper = Set; + break; + + case WXK_NUMPAD_SUBTRACT: + case '-': + oper = Clear; + break; + + default: + oper = None; + } + + if ( oper != None ) + { + wxArrayInt selections; + int count = 0; + if ( HasMultipleSelection() ) + { + count = GetSelections(selections); + } + else + { + int sel = GetSelection(); + if (sel != -1) + { + count = 1; + selections.Add(sel); + } + } + + for ( int i = 0; i < count; i++ ) + { + wxCheckListBoxItem *item = GetItem(selections[i]); + if ( !item ) + { + wxFAIL_MSG( _T("no wxCheckListBoxItem?") ); + continue; + } + + switch ( oper ) + { + case Toggle: + item->Toggle(); + break; + + case Set: + case Clear: + item->Check( oper == Set ); + break; + + default: + wxFAIL_MSG( _T("what should this key do?") ); + } + + // we should send an event as this has been done by the user and + // not by the program + item->SendEvent(); + } + } + else // nothing to do + { + event.Skip(); + } +} + +void wxCheckListBox::OnLeftClick(wxMouseEvent& event) +{ + // clicking on the item selects it, clicking on the checkmark toggles + if ( event.GetX() <= wxOwnerDrawn::GetDefaultMarginWidth() ) + { + int nItem = HitTest(event.GetX(), event.GetY()); + + if ( nItem != wxNOT_FOUND ) + { + wxCheckListBoxItem *item = GetItem(nItem); + item->Toggle(); + item->SendEvent(); + } + //else: it's not an error, just click outside of client zone + } + else + { + // implement default behaviour: clicking on the item selects it + event.Skip(); + } +} + +int wxCheckListBox::DoHitTestItem(wxCoord x, wxCoord y) const +{ + int nItem = (int)::SendMessage + ( + (HWND)GetHWND(), + LB_ITEMFROMPOINT, + 0, + MAKELPARAM(x, y) + ); + + return nItem >= (int)m_noItems ? wxNOT_FOUND : nItem; +} + + +wxSize wxCheckListBox::DoGetBestSize() const +{ + wxSize best = wxListBox::DoGetBestSize(); + best.x += wxOwnerDrawn::GetDefaultMarginWidth(); // add room for the checkbox + CacheBestSize(best); + return best; +} + +#endif diff --git a/Externals/wxWidgets/src/msw/choice.cpp b/Externals/wxWidgets/src/msw/choice.cpp index d154a30e02..16619bc2de 100644 --- a/Externals/wxWidgets/src/msw/choice.cpp +++ b/Externals/wxWidgets/src/msw/choice.cpp @@ -1,802 +1,802 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/msw/choice.cpp -// Purpose: wxChoice -// Author: Julian Smart -// Modified by: Vadim Zeitlin to derive from wxChoiceBase -// Created: 04/01/98 -// RCS-ID: $Id: choice.cpp 51616 2008-02-09 15:22:15Z VZ $ -// Copyright: (c) Julian Smart -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_CHOICE && !(defined(__SMARTPHONE__) && defined(__WXWINCE__)) - -#include "wx/choice.h" - -#ifndef WX_PRECOMP - #include "wx/utils.h" - #include "wx/log.h" - #include "wx/brush.h" - #include "wx/settings.h" -#endif - -#include "wx/msw/private.h" - -#if wxUSE_EXTENDED_RTTI -WX_DEFINE_FLAGS( wxChoiceStyle ) - -wxBEGIN_FLAGS( wxChoiceStyle ) - // new style border flags, we put them first to - // use them for streaming out - wxFLAGS_MEMBER(wxBORDER_SIMPLE) - wxFLAGS_MEMBER(wxBORDER_SUNKEN) - wxFLAGS_MEMBER(wxBORDER_DOUBLE) - wxFLAGS_MEMBER(wxBORDER_RAISED) - wxFLAGS_MEMBER(wxBORDER_STATIC) - wxFLAGS_MEMBER(wxBORDER_NONE) - - // old style border flags - wxFLAGS_MEMBER(wxSIMPLE_BORDER) - wxFLAGS_MEMBER(wxSUNKEN_BORDER) - wxFLAGS_MEMBER(wxDOUBLE_BORDER) - wxFLAGS_MEMBER(wxRAISED_BORDER) - wxFLAGS_MEMBER(wxSTATIC_BORDER) - wxFLAGS_MEMBER(wxBORDER) - - // standard window styles - wxFLAGS_MEMBER(wxTAB_TRAVERSAL) - wxFLAGS_MEMBER(wxCLIP_CHILDREN) - wxFLAGS_MEMBER(wxTRANSPARENT_WINDOW) - wxFLAGS_MEMBER(wxWANTS_CHARS) - wxFLAGS_MEMBER(wxFULL_REPAINT_ON_RESIZE) - wxFLAGS_MEMBER(wxALWAYS_SHOW_SB ) - wxFLAGS_MEMBER(wxVSCROLL) - wxFLAGS_MEMBER(wxHSCROLL) - -wxEND_FLAGS( wxChoiceStyle ) - -IMPLEMENT_DYNAMIC_CLASS_XTI(wxChoice, wxControl,"wx/choice.h") - -wxBEGIN_PROPERTIES_TABLE(wxChoice) - wxEVENT_PROPERTY( Select , wxEVT_COMMAND_CHOICE_SELECTED , wxCommandEvent ) - - wxPROPERTY( Font , wxFont , SetFont , GetFont , EMPTY_MACROVALUE , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) - wxPROPERTY_COLLECTION( Choices , wxArrayString , wxString , AppendString , GetStrings , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) - wxPROPERTY( Selection ,int, SetSelection, GetSelection, EMPTY_MACROVALUE , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) - wxPROPERTY_FLAGS( WindowStyle , wxChoiceStyle , long , SetWindowStyleFlag , GetWindowStyleFlag , EMPTY_MACROVALUE , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // style -wxEND_PROPERTIES_TABLE() - -wxBEGIN_HANDLERS_TABLE(wxChoice) -wxEND_HANDLERS_TABLE() - -wxCONSTRUCTOR_4( wxChoice , wxWindow* , Parent , wxWindowID , Id , wxPoint , Position , wxSize , Size ) -#else -IMPLEMENT_DYNAMIC_CLASS(wxChoice, wxControl) -#endif -/* - TODO PROPERTIES - selection (long) - content (list) - item -*/ - -// ============================================================================ -// implementation -// ============================================================================ - -// ---------------------------------------------------------------------------- -// creation -// ---------------------------------------------------------------------------- - -bool wxChoice::Create(wxWindow *parent, - wxWindowID id, - const wxPoint& pos, - const wxSize& size, - int n, const wxString choices[], - long style, - const wxValidator& validator, - const wxString& name) -{ - // Experience shows that wxChoice vs. wxComboBox distinction confuses - // quite a few people - try to help them - wxASSERT_MSG( !(style & wxCB_DROPDOWN) && - !(style & wxCB_READONLY) && - !(style & wxCB_SIMPLE), - _T("this style flag is ignored by wxChoice, you ") - _T("probably want to use a wxComboBox") ); - - return CreateAndInit(parent, id, pos, size, n, choices, style, - validator, name); -} - -bool wxChoice::CreateAndInit(wxWindow *parent, - wxWindowID id, - const wxPoint& pos, - const wxSize& size, - int n, const wxString choices[], - long style, - const wxValidator& validator, - const wxString& name) -{ - // initialize wxControl - if ( !CreateControl(parent, id, pos, size, style, validator, name) ) - return false; - - // now create the real HWND - if ( !MSWCreateControl(wxT("COMBOBOX"), wxEmptyString, pos, size) ) - return false; - - - // choice/combobox normally has "white" (depends on colour scheme, of - // course) background rather than inheriting the parent's background - SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW)); - - // initialize the controls contents - for ( int i = 0; i < n; i++ ) - { - Append(choices[i]); - } - - // and now we may finally size the control properly (if needed) - SetInitialSize(size); - - return true; -} - -bool wxChoice::Create(wxWindow *parent, - wxWindowID id, - const wxPoint& pos, - const wxSize& size, - const wxArrayString& choices, - long style, - const wxValidator& validator, - const wxString& name) -{ - wxCArrayString chs(choices); - return Create(parent, id, pos, size, chs.GetCount(), chs.GetStrings(), - style, validator, name); -} - -void wxChoice::SetLabel(const wxString& label) -{ - if ( FindString(label) == wxNOT_FOUND ) - { - // unless we explicitly do this here, CB_GETCURSEL will continue to - // return the index of the previously selected item which will result - // in wrongly replacing the value being set now with the previously - // value if the user simply opens and closes (without selecting - // anything) the combobox popup - SetSelection(-1); - } - - wxChoiceBase::SetLabel(label); -} - -bool wxChoice::MSWShouldPreProcessMessage(WXMSG *pMsg) -{ - MSG *msg = (MSG *) pMsg; - - // if the dropdown list is visible, don't preprocess certain keys - if ( msg->message == WM_KEYDOWN - && (msg->wParam == VK_ESCAPE || msg->wParam == VK_RETURN) ) - { - if (::SendMessage(GetHwndOf(this), CB_GETDROPPEDSTATE, 0, 0)) - { - return false; - } - } - - return wxControl::MSWShouldPreProcessMessage(pMsg); -} - -WXDWORD wxChoice::MSWGetStyle(long style, WXDWORD *exstyle) const -{ - // we never have an external border - WXDWORD msStyle = wxControl::MSWGetStyle - ( - (style & ~wxBORDER_MASK) | wxBORDER_NONE, exstyle - ); - - // WS_CLIPSIBLINGS is useful with wxChoice and doesn't seem to result in - // any problems - msStyle |= WS_CLIPSIBLINGS; - - // wxChoice-specific styles - msStyle |= CBS_DROPDOWNLIST | WS_HSCROLL | WS_VSCROLL; - if ( style & wxCB_SORT ) - msStyle |= CBS_SORT; - - return msStyle; -} - -wxChoice::~wxChoice() -{ - Free(); -} - -// ---------------------------------------------------------------------------- -// adding/deleting items to/from the list -// ---------------------------------------------------------------------------- - -int wxChoice::DoAppend(const wxString& item) -{ - int n = (int)SendMessage(GetHwnd(), CB_ADDSTRING, 0, (LPARAM)item.c_str()); - if ( n == CB_ERR ) - { - wxLogLastError(wxT("SendMessage(CB_ADDSTRING)")); - } - else // ok - { - // we need to refresh our size in order to have enough space for the - // newly added items - if ( !IsFrozen() ) - UpdateVisibleHeight(); - } - - InvalidateBestSize(); - return n; -} - -int wxChoice::DoInsert(const wxString& item, unsigned int pos) -{ - wxCHECK_MSG(!(GetWindowStyle() & wxCB_SORT), -1, wxT("can't insert into sorted list")); - wxCHECK_MSG(IsValidInsert(pos), -1, wxT("invalid index")); - - int n = (int)SendMessage(GetHwnd(), CB_INSERTSTRING, pos, (LPARAM)item.c_str()); - if ( n == CB_ERR ) - { - wxLogLastError(wxT("SendMessage(CB_INSERTSTRING)")); - } - else // ok - { - if ( !IsFrozen() ) - UpdateVisibleHeight(); - } - - InvalidateBestSize(); - return n; -} - -void wxChoice::Delete(unsigned int n) -{ - wxCHECK_RET( IsValid(n), wxT("invalid item index in wxChoice::Delete") ); - - if ( HasClientObjectData() ) - { - delete GetClientObject(n); - } - - SendMessage(GetHwnd(), CB_DELETESTRING, n, 0); - - if ( !IsFrozen() ) - UpdateVisibleHeight(); - - InvalidateBestSize(); -} - -void wxChoice::Clear() -{ - Free(); - - SendMessage(GetHwnd(), CB_RESETCONTENT, 0, 0); - - if ( !IsFrozen() ) - UpdateVisibleHeight(); - - InvalidateBestSize(); -} - -void wxChoice::Free() -{ - if ( HasClientObjectData() ) - { - unsigned int count = GetCount(); - for ( unsigned int n = 0; n < count; n++ ) - { - delete GetClientObject(n); - } - } -} - -// ---------------------------------------------------------------------------- -// selection -// ---------------------------------------------------------------------------- - -int wxChoice::GetSelection() const -{ - // if m_lastAcceptedSelection is set, it means that the dropdown is - // currently shown and that we want to use the last "permanent" selection - // instead of whatever is under the mouse pointer currently - // - // otherwise, get the selection from the control - return m_lastAcceptedSelection == wxID_NONE ? GetCurrentSelection() - : m_lastAcceptedSelection; -} - -int wxChoice::GetCurrentSelection() const -{ - return (int)SendMessage(GetHwnd(), CB_GETCURSEL, 0, 0); -} - -void wxChoice::SetSelection(int n) -{ - SendMessage(GetHwnd(), CB_SETCURSEL, n, 0); -} - -// ---------------------------------------------------------------------------- -// string list functions -// ---------------------------------------------------------------------------- - -unsigned int wxChoice::GetCount() const -{ - return (unsigned int)SendMessage(GetHwnd(), CB_GETCOUNT, 0, 0); -} - -int wxChoice::FindString(const wxString& s, bool bCase) const -{ -#if defined(__WATCOMC__) && defined(__WIN386__) - // For some reason, Watcom in WIN386 mode crashes in the CB_FINDSTRINGEXACT message. - // wxChoice::Do it the long way instead. - unsigned int count = GetCount(); - for ( unsigned int i = 0; i < count; i++ ) - { - // as CB_FINDSTRINGEXACT is case insensitive, be case insensitive too - if (GetString(i).IsSameAs(s, bCase)) - return i; - } - - return wxNOT_FOUND; -#else // !Watcom - //TODO: Evidently some MSW versions (all?) don't like empty strings - //passed to SendMessage, so we have to do it ourselves in that case - if ( s.empty() ) - { - unsigned int count = GetCount(); - for ( unsigned int i = 0; i < count; i++ ) - { - if (GetString(i).empty()) - return i; - } - - return wxNOT_FOUND; - } - else if (bCase) - { - // back to base class search for not native search type - return wxItemContainerImmutable::FindString( s, bCase ); - } - else - { - int pos = (int)SendMessage(GetHwnd(), CB_FINDSTRINGEXACT, - (WPARAM)-1, (LPARAM)s.c_str()); - - return pos == LB_ERR ? wxNOT_FOUND : pos; - } -#endif // Watcom/!Watcom -} - -void wxChoice::SetString(unsigned int n, const wxString& s) -{ - wxCHECK_RET( IsValid(n), wxT("invalid item index in wxChoice::SetString") ); - - // we have to delete and add back the string as there is no way to change a - // string in place - - // we need to preserve the client data - void *data; - if ( m_clientDataItemsType != wxClientData_None ) - { - data = DoGetItemClientData(n); - } - else // no client data - { - data = NULL; - } - - ::SendMessage(GetHwnd(), CB_DELETESTRING, n, 0); - ::SendMessage(GetHwnd(), CB_INSERTSTRING, n, (LPARAM)s.c_str() ); - - if ( data ) - { - DoSetItemClientData(n, data); - } - //else: it's already NULL by default - - InvalidateBestSize(); -} - -wxString wxChoice::GetString(unsigned int n) const -{ - int len = (int)::SendMessage(GetHwnd(), CB_GETLBTEXTLEN, n, 0); - - wxString str; - if ( len != CB_ERR && len > 0 ) - { - if ( ::SendMessage - ( - GetHwnd(), - CB_GETLBTEXT, - n, - (LPARAM)(wxChar *)wxStringBuffer(str, len) - ) == CB_ERR ) - { - wxLogLastError(wxT("SendMessage(CB_GETLBTEXT)")); - } - } - - return str; -} - -// ---------------------------------------------------------------------------- -// client data -// ---------------------------------------------------------------------------- - -void wxChoice::DoSetItemClientData(unsigned int n, void* clientData) -{ - if ( ::SendMessage(GetHwnd(), CB_SETITEMDATA, - n, (LPARAM)clientData) == CB_ERR ) - { - wxLogLastError(wxT("CB_SETITEMDATA")); - } -} - -void* wxChoice::DoGetItemClientData(unsigned int n) const -{ - LPARAM rc = SendMessage(GetHwnd(), CB_GETITEMDATA, n, 0); - if ( rc == CB_ERR ) - { - wxLogLastError(wxT("CB_GETITEMDATA")); - - // unfortunately, there is no way to return an error code to the user - rc = (LPARAM) NULL; - } - - return (void *)rc; -} - -void wxChoice::DoSetItemClientObject(unsigned int n, wxClientData* clientData) -{ - DoSetItemClientData(n, clientData); -} - -wxClientData* wxChoice::DoGetItemClientObject(unsigned int n) const -{ - return (wxClientData *)DoGetItemClientData(n); -} - -// ---------------------------------------------------------------------------- -// wxMSW specific helpers -// ---------------------------------------------------------------------------- - -void wxChoice::UpdateVisibleHeight() -{ - // be careful to not change the width here - DoSetSize(wxDefaultCoord, wxDefaultCoord, wxDefaultCoord, GetSize().y, wxSIZE_USE_EXISTING); -} - -void wxChoice::DoMoveWindow(int x, int y, int width, int height) -{ - // here is why this is necessary: if the width is negative, the combobox - // window proc makes the window of the size width*height instead of - // interpreting height in the usual manner (meaning the height of the drop - // down list - usually the height specified in the call to MoveWindow() - // will not change the height of combo box per se) - // - // this behaviour is not documented anywhere, but this is just how it is - // here (NT 4.4) and, anyhow, the check shouldn't hurt - however without - // the check, constraints/sizers using combos may break the height - // constraint will have not at all the same value as expected - if ( width < 0 ) - return; - - wxControl::DoMoveWindow(x, y, width, height); -} - -void wxChoice::DoGetSize(int *w, int *h) const -{ - // this is weird: sometimes, the height returned by Windows is clearly the - // total height of the control including the drop down list -- but only - // sometimes, and normally it isn't... I have no idea about what to do with - // this - wxControl::DoGetSize(w, h); -} - -void wxChoice::DoSetSize(int x, int y, - int width, int height, - int sizeFlags) -{ - int heightOrig = height; - - // the height which we must pass to Windows should be the total height of - // the control including the drop down list while the height given to us - // is, of course, just the height of the permanently visible part of it - if ( height != wxDefaultCoord ) - { - // don't make the drop down list too tall, arbitrarily limit it to 40 - // items max and also don't leave it empty - size_t nItems = GetCount(); - if ( !nItems ) - nItems = 9; - else if ( nItems > 24 ) - nItems = 24; - - // add space for the drop down list - const int hItem = SendMessage(GetHwnd(), CB_GETITEMHEIGHT, 0, 0); - height += hItem*(nItems + 1); - } - else - { - // We cannot pass wxDefaultCoord as height to wxControl. wxControl uses - // wxGetWindowRect() to determine the current height of the combobox, - // and then again sets the combobox's height to that value. Unfortunately, - // wxGetWindowRect doesn't include the dropdown list's height (at least - // on Win2K), so this would result in a combobox with dropdown height of - // 1 pixel. We have to determine the default height ourselves and call - // wxControl with that value instead. - int w, h; - RECT r; - DoGetSize(&w, &h); - if (::SendMessage(GetHwnd(), CB_GETDROPPEDCONTROLRECT, 0, (LPARAM) &r) != 0) - { - height = h + r.bottom - r.top; - } - } - - wxControl::DoSetSize(x, y, width, height, sizeFlags); - - // If we're storing a pending size, make sure we store - // the original size for reporting back to the app. - if (m_pendingSize != wxDefaultSize) - m_pendingSize = wxSize(width, heightOrig); - - // This solution works on XP, but causes choice/combobox lists to be - // too short on W2K and earlier. -#if 0 - int widthCurrent, heightCurrent; - DoGetSize(&widthCurrent, &heightCurrent); - - // the height which we must pass to Windows should be the total height of - // the control including the drop down list while the height given to us - // is, of course, just the height of the permanently visible part of it - if ( height != wxDefaultCoord && height != heightCurrent ) - { - // don't make the drop down list too tall, arbitrarily limit it to 40 - // items max and also don't leave it empty - unsigned int nItems = GetCount(); - if ( !nItems ) - nItems = 9; - else if ( nItems > 24 ) - nItems = 24; - - // add space for the drop down list - const int hItem = SendMessage(GetHwnd(), CB_GETITEMHEIGHT, 0, 0); - height += hItem*(nItems + 1); - } - else // keep the same height as now - { - // normally wxWindow::DoSetSize() checks if we set the same size as the - // window already has and does nothing in this case, but for us the - // check fails as the size we pass to it includes the dropdown while - // the size returned by our GetSize() does not, so test if the size - // didn't really change ourselves here - if ( width == wxDefaultCoord || width == widthCurrent ) - { - // size doesn't change, what about position? - int xCurrent, yCurrent; - DoGetPosition(&xCurrent, &yCurrent); - const bool defMeansUnchanged = !(sizeFlags & wxSIZE_ALLOW_MINUS_ONE); - if ( ((x == wxDefaultCoord && defMeansUnchanged) || x == xCurrent) - && - ((y == wxDefaultCoord && defMeansUnchanged) || y == yCurrent) ) - { - // nothing changes, nothing to do - return; - } - } - - // We cannot pass wxDefaultCoord as height to wxControl. wxControl uses - // wxGetWindowRect() to determine the current height of the combobox, - // and then again sets the combobox's height to that value. Unfortunately, - // wxGetWindowRect doesn't include the dropdown list's height (at least - // on Win2K), so this would result in a combobox with dropdown height of - // 1 pixel. We have to determine the default height ourselves and call - // wxControl with that value instead. - // - // Also notice that sometimes CB_GETDROPPEDCONTROLRECT seems to return - // wildly incorrect values (~32000) which looks like a bug in it, just - // ignore them in this case - RECT r; - if ( ::SendMessage(GetHwnd(), CB_GETDROPPEDCONTROLRECT, 0, (LPARAM) &r) - && r.bottom < 30000 ) - { - height = heightCurrent + r.bottom - r.top; - } - } - - wxControl::DoSetSize(x, y, width, height, sizeFlags); -#endif -} - -wxSize wxChoice::DoGetBestSize() const -{ - // find the widest string - int wChoice = 0; - const unsigned int nItems = GetCount(); - for ( unsigned int i = 0; i < nItems; i++ ) - { - int wLine; - GetTextExtent(GetString(i), &wLine, NULL); - if ( wLine > wChoice ) - wChoice = wLine; - } - - // give it some reasonable default value if there are no strings in the - // list - if ( wChoice == 0 ) - wChoice = 100; - - // the combobox should be slightly larger than the widest string - wChoice += 5*GetCharWidth(); - - wxSize best(wChoice, EDIT_HEIGHT_FROM_CHAR_HEIGHT(GetCharHeight())); - CacheBestSize(best); - return best; -} - -WXLRESULT wxChoice::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam) -{ - switch ( nMsg ) - { - case WM_LBUTTONUP: - { - int x = (int)LOWORD(lParam); - int y = (int)HIWORD(lParam); - - // Ok, this is truly weird, but if a panel with a wxChoice - // loses the focus, then you get a *fake* WM_LBUTTONUP message - // with x = 65535 and y = 65535. Filter out this nonsense. - // - // VZ: I'd like to know how to reproduce this please... - if ( x == 65535 && y == 65535 ) - return 0; - } - break; - - // we have to handle both: one for the normal case and the other - // for readonly - case WM_CTLCOLOREDIT: - case WM_CTLCOLORLISTBOX: - case WM_CTLCOLORSTATIC: - { - WXHDC hdc; - WXHWND hwnd; - UnpackCtlColor(wParam, lParam, &hdc, &hwnd); - - WXHBRUSH hbr = MSWControlColor((WXHDC)hdc, hwnd); - if ( hbr ) - return (WXLRESULT)hbr; - //else: fall through to default window proc - } - } - - return wxWindow::MSWWindowProc(nMsg, wParam, lParam); -} - -bool wxChoice::MSWCommand(WXUINT param, WXWORD WXUNUSED(id)) -{ - /* - The native control provides a great variety in the events it sends in - the different selection scenarios (undoubtedly for greater amusement of - the programmers using it). For the reference, here are the cases when - the final selection is accepted (things are quite interesting when it - is cancelled too): - - A. Selecting with just the arrows without opening the dropdown: - 1. CBN_SELENDOK - 2. CBN_SELCHANGE - - B. Opening dropdown with F4 and selecting with arrows: - 1. CBN_DROPDOWN - 2. many CBN_SELCHANGE while changing selection in the list - 3. CBN_SELENDOK - 4. CBN_CLOSEUP - - C. Selecting with the mouse: - 1. CBN_DROPDOWN - -- no intermediate CBN_SELCHANGEs -- - 2. CBN_SELENDOK - 3. CBN_CLOSEUP - 4. CBN_SELCHANGE - - Admire the different order of messages in all of those cases, it must - surely have taken a lot of effort to Microsoft developers to achieve - such originality. - */ - switch ( param ) - { - case CBN_DROPDOWN: - // we use this value both because we don't want to track selection - // using CB_GETCURSEL while the dropdown is opened and because we - // need to reset the selection back to it if it's eventually - // cancelled by user - m_lastAcceptedSelection = GetCurrentSelection(); - if ( m_lastAcceptedSelection == -1 ) - { - // no current selection so no need to restore it later (this - // happens when opening a combobox containing text not from its - // list of items and we shouldn't erase this text) - m_lastAcceptedSelection = wxID_NONE; - } - break; - - case CBN_CLOSEUP: - // if the selection was accepted by the user, it should have been - // reset to wxID_NONE by CBN_SELENDOK, otherwise the selection was - // cancelled and we must restore the old one - if ( m_lastAcceptedSelection != wxID_NONE ) - { - SetSelection(m_lastAcceptedSelection); - m_lastAcceptedSelection = wxID_NONE; - } - break; - - case CBN_SELENDOK: - // reset it to prevent CBN_CLOSEUP from undoing the selection (it's - // ok to reset it now as GetCurrentSelection() will now return the - // same thing anyhow) - m_lastAcceptedSelection = wxID_NONE; - - { - const int n = GetSelection(); - - wxCommandEvent event(wxEVT_COMMAND_CHOICE_SELECTED, m_windowId); - event.SetInt(n); - event.SetEventObject(this); - - if ( n > -1 ) - { - event.SetString(GetStringSelection()); - InitCommandEventWithItems(event, n); - } - - ProcessCommand(event); - } - break; - - // don't handle CBN_SELENDCANCEL: just leave m_lastAcceptedSelection - // valid and the selection will be undone in CBN_CLOSEUP above - - // don't handle CBN_SELCHANGE neither, we don't want to generate events - // while the dropdown is opened -- but do add it if we ever need this - - default: - return false; - } - - return true; -} - -WXHBRUSH wxChoice::MSWControlColor(WXHDC hDC, WXHWND hWnd) -{ - if ( !IsEnabled() ) - return MSWControlColorDisabled(hDC); - - return wxChoiceBase::MSWControlColor(hDC, hWnd); -} - -#endif // wxUSE_CHOICE && !(__SMARTPHONE__ && __WXWINCE__) +///////////////////////////////////////////////////////////////////////////// +// Name: src/msw/choice.cpp +// Purpose: wxChoice +// Author: Julian Smart +// Modified by: Vadim Zeitlin to derive from wxChoiceBase +// Created: 04/01/98 +// RCS-ID: $Id: choice.cpp 51616 2008-02-09 15:22:15Z VZ $ +// Copyright: (c) Julian Smart +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_CHOICE && !(defined(__SMARTPHONE__) && defined(__WXWINCE__)) + +#include "wx/choice.h" + +#ifndef WX_PRECOMP + #include "wx/utils.h" + #include "wx/log.h" + #include "wx/brush.h" + #include "wx/settings.h" +#endif + +#include "wx/msw/private.h" + +#if wxUSE_EXTENDED_RTTI +WX_DEFINE_FLAGS( wxChoiceStyle ) + +wxBEGIN_FLAGS( wxChoiceStyle ) + // new style border flags, we put them first to + // use them for streaming out + wxFLAGS_MEMBER(wxBORDER_SIMPLE) + wxFLAGS_MEMBER(wxBORDER_SUNKEN) + wxFLAGS_MEMBER(wxBORDER_DOUBLE) + wxFLAGS_MEMBER(wxBORDER_RAISED) + wxFLAGS_MEMBER(wxBORDER_STATIC) + wxFLAGS_MEMBER(wxBORDER_NONE) + + // old style border flags + wxFLAGS_MEMBER(wxSIMPLE_BORDER) + wxFLAGS_MEMBER(wxSUNKEN_BORDER) + wxFLAGS_MEMBER(wxDOUBLE_BORDER) + wxFLAGS_MEMBER(wxRAISED_BORDER) + wxFLAGS_MEMBER(wxSTATIC_BORDER) + wxFLAGS_MEMBER(wxBORDER) + + // standard window styles + wxFLAGS_MEMBER(wxTAB_TRAVERSAL) + wxFLAGS_MEMBER(wxCLIP_CHILDREN) + wxFLAGS_MEMBER(wxTRANSPARENT_WINDOW) + wxFLAGS_MEMBER(wxWANTS_CHARS) + wxFLAGS_MEMBER(wxFULL_REPAINT_ON_RESIZE) + wxFLAGS_MEMBER(wxALWAYS_SHOW_SB ) + wxFLAGS_MEMBER(wxVSCROLL) + wxFLAGS_MEMBER(wxHSCROLL) + +wxEND_FLAGS( wxChoiceStyle ) + +IMPLEMENT_DYNAMIC_CLASS_XTI(wxChoice, wxControl,"wx/choice.h") + +wxBEGIN_PROPERTIES_TABLE(wxChoice) + wxEVENT_PROPERTY( Select , wxEVT_COMMAND_CHOICE_SELECTED , wxCommandEvent ) + + wxPROPERTY( Font , wxFont , SetFont , GetFont , EMPTY_MACROVALUE , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) + wxPROPERTY_COLLECTION( Choices , wxArrayString , wxString , AppendString , GetStrings , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) + wxPROPERTY( Selection ,int, SetSelection, GetSelection, EMPTY_MACROVALUE , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) + wxPROPERTY_FLAGS( WindowStyle , wxChoiceStyle , long , SetWindowStyleFlag , GetWindowStyleFlag , EMPTY_MACROVALUE , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // style +wxEND_PROPERTIES_TABLE() + +wxBEGIN_HANDLERS_TABLE(wxChoice) +wxEND_HANDLERS_TABLE() + +wxCONSTRUCTOR_4( wxChoice , wxWindow* , Parent , wxWindowID , Id , wxPoint , Position , wxSize , Size ) +#else +IMPLEMENT_DYNAMIC_CLASS(wxChoice, wxControl) +#endif +/* + TODO PROPERTIES + selection (long) + content (list) + item +*/ + +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// creation +// ---------------------------------------------------------------------------- + +bool wxChoice::Create(wxWindow *parent, + wxWindowID id, + const wxPoint& pos, + const wxSize& size, + int n, const wxString choices[], + long style, + const wxValidator& validator, + const wxString& name) +{ + // Experience shows that wxChoice vs. wxComboBox distinction confuses + // quite a few people - try to help them + wxASSERT_MSG( !(style & wxCB_DROPDOWN) && + !(style & wxCB_READONLY) && + !(style & wxCB_SIMPLE), + _T("this style flag is ignored by wxChoice, you ") + _T("probably want to use a wxComboBox") ); + + return CreateAndInit(parent, id, pos, size, n, choices, style, + validator, name); +} + +bool wxChoice::CreateAndInit(wxWindow *parent, + wxWindowID id, + const wxPoint& pos, + const wxSize& size, + int n, const wxString choices[], + long style, + const wxValidator& validator, + const wxString& name) +{ + // initialize wxControl + if ( !CreateControl(parent, id, pos, size, style, validator, name) ) + return false; + + // now create the real HWND + if ( !MSWCreateControl(wxT("COMBOBOX"), wxEmptyString, pos, size) ) + return false; + + + // choice/combobox normally has "white" (depends on colour scheme, of + // course) background rather than inheriting the parent's background + SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW)); + + // initialize the controls contents + for ( int i = 0; i < n; i++ ) + { + Append(choices[i]); + } + + // and now we may finally size the control properly (if needed) + SetInitialSize(size); + + return true; +} + +bool wxChoice::Create(wxWindow *parent, + wxWindowID id, + const wxPoint& pos, + const wxSize& size, + const wxArrayString& choices, + long style, + const wxValidator& validator, + const wxString& name) +{ + wxCArrayString chs(choices); + return Create(parent, id, pos, size, chs.GetCount(), chs.GetStrings(), + style, validator, name); +} + +void wxChoice::SetLabel(const wxString& label) +{ + if ( FindString(label) == wxNOT_FOUND ) + { + // unless we explicitly do this here, CB_GETCURSEL will continue to + // return the index of the previously selected item which will result + // in wrongly replacing the value being set now with the previously + // value if the user simply opens and closes (without selecting + // anything) the combobox popup + SetSelection(-1); + } + + wxChoiceBase::SetLabel(label); +} + +bool wxChoice::MSWShouldPreProcessMessage(WXMSG *pMsg) +{ + MSG *msg = (MSG *) pMsg; + + // if the dropdown list is visible, don't preprocess certain keys + if ( msg->message == WM_KEYDOWN + && (msg->wParam == VK_ESCAPE || msg->wParam == VK_RETURN) ) + { + if (::SendMessage(GetHwndOf(this), CB_GETDROPPEDSTATE, 0, 0)) + { + return false; + } + } + + return wxControl::MSWShouldPreProcessMessage(pMsg); +} + +WXDWORD wxChoice::MSWGetStyle(long style, WXDWORD *exstyle) const +{ + // we never have an external border + WXDWORD msStyle = wxControl::MSWGetStyle + ( + (style & ~wxBORDER_MASK) | wxBORDER_NONE, exstyle + ); + + // WS_CLIPSIBLINGS is useful with wxChoice and doesn't seem to result in + // any problems + msStyle |= WS_CLIPSIBLINGS; + + // wxChoice-specific styles + msStyle |= CBS_DROPDOWNLIST | WS_HSCROLL | WS_VSCROLL; + if ( style & wxCB_SORT ) + msStyle |= CBS_SORT; + + return msStyle; +} + +wxChoice::~wxChoice() +{ + Free(); +} + +// ---------------------------------------------------------------------------- +// adding/deleting items to/from the list +// ---------------------------------------------------------------------------- + +int wxChoice::DoAppend(const wxString& item) +{ + int n = (int)SendMessage(GetHwnd(), CB_ADDSTRING, 0, (LPARAM)item.c_str()); + if ( n == CB_ERR ) + { + wxLogLastError(wxT("SendMessage(CB_ADDSTRING)")); + } + else // ok + { + // we need to refresh our size in order to have enough space for the + // newly added items + if ( !IsFrozen() ) + UpdateVisibleHeight(); + } + + InvalidateBestSize(); + return n; +} + +int wxChoice::DoInsert(const wxString& item, unsigned int pos) +{ + wxCHECK_MSG(!(GetWindowStyle() & wxCB_SORT), -1, wxT("can't insert into sorted list")); + wxCHECK_MSG(IsValidInsert(pos), -1, wxT("invalid index")); + + int n = (int)SendMessage(GetHwnd(), CB_INSERTSTRING, pos, (LPARAM)item.c_str()); + if ( n == CB_ERR ) + { + wxLogLastError(wxT("SendMessage(CB_INSERTSTRING)")); + } + else // ok + { + if ( !IsFrozen() ) + UpdateVisibleHeight(); + } + + InvalidateBestSize(); + return n; +} + +void wxChoice::Delete(unsigned int n) +{ + wxCHECK_RET( IsValid(n), wxT("invalid item index in wxChoice::Delete") ); + + if ( HasClientObjectData() ) + { + delete GetClientObject(n); + } + + SendMessage(GetHwnd(), CB_DELETESTRING, n, 0); + + if ( !IsFrozen() ) + UpdateVisibleHeight(); + + InvalidateBestSize(); +} + +void wxChoice::Clear() +{ + Free(); + + SendMessage(GetHwnd(), CB_RESETCONTENT, 0, 0); + + if ( !IsFrozen() ) + UpdateVisibleHeight(); + + InvalidateBestSize(); +} + +void wxChoice::Free() +{ + if ( HasClientObjectData() ) + { + unsigned int count = GetCount(); + for ( unsigned int n = 0; n < count; n++ ) + { + delete GetClientObject(n); + } + } +} + +// ---------------------------------------------------------------------------- +// selection +// ---------------------------------------------------------------------------- + +int wxChoice::GetSelection() const +{ + // if m_lastAcceptedSelection is set, it means that the dropdown is + // currently shown and that we want to use the last "permanent" selection + // instead of whatever is under the mouse pointer currently + // + // otherwise, get the selection from the control + return m_lastAcceptedSelection == wxID_NONE ? GetCurrentSelection() + : m_lastAcceptedSelection; +} + +int wxChoice::GetCurrentSelection() const +{ + return (int)SendMessage(GetHwnd(), CB_GETCURSEL, 0, 0); +} + +void wxChoice::SetSelection(int n) +{ + SendMessage(GetHwnd(), CB_SETCURSEL, n, 0); +} + +// ---------------------------------------------------------------------------- +// string list functions +// ---------------------------------------------------------------------------- + +unsigned int wxChoice::GetCount() const +{ + return (unsigned int)SendMessage(GetHwnd(), CB_GETCOUNT, 0, 0); +} + +int wxChoice::FindString(const wxString& s, bool bCase) const +{ +#if defined(__WATCOMC__) && defined(__WIN386__) + // For some reason, Watcom in WIN386 mode crashes in the CB_FINDSTRINGEXACT message. + // wxChoice::Do it the long way instead. + unsigned int count = GetCount(); + for ( unsigned int i = 0; i < count; i++ ) + { + // as CB_FINDSTRINGEXACT is case insensitive, be case insensitive too + if (GetString(i).IsSameAs(s, bCase)) + return i; + } + + return wxNOT_FOUND; +#else // !Watcom + //TODO: Evidently some MSW versions (all?) don't like empty strings + //passed to SendMessage, so we have to do it ourselves in that case + if ( s.empty() ) + { + unsigned int count = GetCount(); + for ( unsigned int i = 0; i < count; i++ ) + { + if (GetString(i).empty()) + return i; + } + + return wxNOT_FOUND; + } + else if (bCase) + { + // back to base class search for not native search type + return wxItemContainerImmutable::FindString( s, bCase ); + } + else + { + int pos = (int)SendMessage(GetHwnd(), CB_FINDSTRINGEXACT, + (WPARAM)-1, (LPARAM)s.c_str()); + + return pos == LB_ERR ? wxNOT_FOUND : pos; + } +#endif // Watcom/!Watcom +} + +void wxChoice::SetString(unsigned int n, const wxString& s) +{ + wxCHECK_RET( IsValid(n), wxT("invalid item index in wxChoice::SetString") ); + + // we have to delete and add back the string as there is no way to change a + // string in place + + // we need to preserve the client data + void *data; + if ( m_clientDataItemsType != wxClientData_None ) + { + data = DoGetItemClientData(n); + } + else // no client data + { + data = NULL; + } + + ::SendMessage(GetHwnd(), CB_DELETESTRING, n, 0); + ::SendMessage(GetHwnd(), CB_INSERTSTRING, n, (LPARAM)s.c_str() ); + + if ( data ) + { + DoSetItemClientData(n, data); + } + //else: it's already NULL by default + + InvalidateBestSize(); +} + +wxString wxChoice::GetString(unsigned int n) const +{ + int len = (int)::SendMessage(GetHwnd(), CB_GETLBTEXTLEN, n, 0); + + wxString str; + if ( len != CB_ERR && len > 0 ) + { + if ( ::SendMessage + ( + GetHwnd(), + CB_GETLBTEXT, + n, + (LPARAM)(wxChar *)wxStringBuffer(str, len) + ) == CB_ERR ) + { + wxLogLastError(wxT("SendMessage(CB_GETLBTEXT)")); + } + } + + return str; +} + +// ---------------------------------------------------------------------------- +// client data +// ---------------------------------------------------------------------------- + +void wxChoice::DoSetItemClientData(unsigned int n, void* clientData) +{ + if ( ::SendMessage(GetHwnd(), CB_SETITEMDATA, + n, (LPARAM)clientData) == CB_ERR ) + { + wxLogLastError(wxT("CB_SETITEMDATA")); + } +} + +void* wxChoice::DoGetItemClientData(unsigned int n) const +{ + LPARAM rc = SendMessage(GetHwnd(), CB_GETITEMDATA, n, 0); + if ( rc == CB_ERR ) + { + wxLogLastError(wxT("CB_GETITEMDATA")); + + // unfortunately, there is no way to return an error code to the user + rc = (LPARAM) NULL; + } + + return (void *)rc; +} + +void wxChoice::DoSetItemClientObject(unsigned int n, wxClientData* clientData) +{ + DoSetItemClientData(n, clientData); +} + +wxClientData* wxChoice::DoGetItemClientObject(unsigned int n) const +{ + return (wxClientData *)DoGetItemClientData(n); +} + +// ---------------------------------------------------------------------------- +// wxMSW specific helpers +// ---------------------------------------------------------------------------- + +void wxChoice::UpdateVisibleHeight() +{ + // be careful to not change the width here + DoSetSize(wxDefaultCoord, wxDefaultCoord, wxDefaultCoord, GetSize().y, wxSIZE_USE_EXISTING); +} + +void wxChoice::DoMoveWindow(int x, int y, int width, int height) +{ + // here is why this is necessary: if the width is negative, the combobox + // window proc makes the window of the size width*height instead of + // interpreting height in the usual manner (meaning the height of the drop + // down list - usually the height specified in the call to MoveWindow() + // will not change the height of combo box per se) + // + // this behaviour is not documented anywhere, but this is just how it is + // here (NT 4.4) and, anyhow, the check shouldn't hurt - however without + // the check, constraints/sizers using combos may break the height + // constraint will have not at all the same value as expected + if ( width < 0 ) + return; + + wxControl::DoMoveWindow(x, y, width, height); +} + +void wxChoice::DoGetSize(int *w, int *h) const +{ + // this is weird: sometimes, the height returned by Windows is clearly the + // total height of the control including the drop down list -- but only + // sometimes, and normally it isn't... I have no idea about what to do with + // this + wxControl::DoGetSize(w, h); +} + +void wxChoice::DoSetSize(int x, int y, + int width, int height, + int sizeFlags) +{ + int heightOrig = height; + + // the height which we must pass to Windows should be the total height of + // the control including the drop down list while the height given to us + // is, of course, just the height of the permanently visible part of it + if ( height != wxDefaultCoord ) + { + // don't make the drop down list too tall, arbitrarily limit it to 40 + // items max and also don't leave it empty + size_t nItems = GetCount(); + if ( !nItems ) + nItems = 9; + else if ( nItems > 24 ) + nItems = 24; + + // add space for the drop down list + const int hItem = SendMessage(GetHwnd(), CB_GETITEMHEIGHT, 0, 0); + height += hItem*(nItems + 1); + } + else + { + // We cannot pass wxDefaultCoord as height to wxControl. wxControl uses + // wxGetWindowRect() to determine the current height of the combobox, + // and then again sets the combobox's height to that value. Unfortunately, + // wxGetWindowRect doesn't include the dropdown list's height (at least + // on Win2K), so this would result in a combobox with dropdown height of + // 1 pixel. We have to determine the default height ourselves and call + // wxControl with that value instead. + int w, h; + RECT r; + DoGetSize(&w, &h); + if (::SendMessage(GetHwnd(), CB_GETDROPPEDCONTROLRECT, 0, (LPARAM) &r) != 0) + { + height = h + r.bottom - r.top; + } + } + + wxControl::DoSetSize(x, y, width, height, sizeFlags); + + // If we're storing a pending size, make sure we store + // the original size for reporting back to the app. + if (m_pendingSize != wxDefaultSize) + m_pendingSize = wxSize(width, heightOrig); + + // This solution works on XP, but causes choice/combobox lists to be + // too short on W2K and earlier. +#if 0 + int widthCurrent, heightCurrent; + DoGetSize(&widthCurrent, &heightCurrent); + + // the height which we must pass to Windows should be the total height of + // the control including the drop down list while the height given to us + // is, of course, just the height of the permanently visible part of it + if ( height != wxDefaultCoord && height != heightCurrent ) + { + // don't make the drop down list too tall, arbitrarily limit it to 40 + // items max and also don't leave it empty + unsigned int nItems = GetCount(); + if ( !nItems ) + nItems = 9; + else if ( nItems > 24 ) + nItems = 24; + + // add space for the drop down list + const int hItem = SendMessage(GetHwnd(), CB_GETITEMHEIGHT, 0, 0); + height += hItem*(nItems + 1); + } + else // keep the same height as now + { + // normally wxWindow::DoSetSize() checks if we set the same size as the + // window already has and does nothing in this case, but for us the + // check fails as the size we pass to it includes the dropdown while + // the size returned by our GetSize() does not, so test if the size + // didn't really change ourselves here + if ( width == wxDefaultCoord || width == widthCurrent ) + { + // size doesn't change, what about position? + int xCurrent, yCurrent; + DoGetPosition(&xCurrent, &yCurrent); + const bool defMeansUnchanged = !(sizeFlags & wxSIZE_ALLOW_MINUS_ONE); + if ( ((x == wxDefaultCoord && defMeansUnchanged) || x == xCurrent) + && + ((y == wxDefaultCoord && defMeansUnchanged) || y == yCurrent) ) + { + // nothing changes, nothing to do + return; + } + } + + // We cannot pass wxDefaultCoord as height to wxControl. wxControl uses + // wxGetWindowRect() to determine the current height of the combobox, + // and then again sets the combobox's height to that value. Unfortunately, + // wxGetWindowRect doesn't include the dropdown list's height (at least + // on Win2K), so this would result in a combobox with dropdown height of + // 1 pixel. We have to determine the default height ourselves and call + // wxControl with that value instead. + // + // Also notice that sometimes CB_GETDROPPEDCONTROLRECT seems to return + // wildly incorrect values (~32000) which looks like a bug in it, just + // ignore them in this case + RECT r; + if ( ::SendMessage(GetHwnd(), CB_GETDROPPEDCONTROLRECT, 0, (LPARAM) &r) + && r.bottom < 30000 ) + { + height = heightCurrent + r.bottom - r.top; + } + } + + wxControl::DoSetSize(x, y, width, height, sizeFlags); +#endif +} + +wxSize wxChoice::DoGetBestSize() const +{ + // find the widest string + int wChoice = 0; + const unsigned int nItems = GetCount(); + for ( unsigned int i = 0; i < nItems; i++ ) + { + int wLine; + GetTextExtent(GetString(i), &wLine, NULL); + if ( wLine > wChoice ) + wChoice = wLine; + } + + // give it some reasonable default value if there are no strings in the + // list + if ( wChoice == 0 ) + wChoice = 100; + + // the combobox should be slightly larger than the widest string + wChoice += 5*GetCharWidth(); + + wxSize best(wChoice, EDIT_HEIGHT_FROM_CHAR_HEIGHT(GetCharHeight())); + CacheBestSize(best); + return best; +} + +WXLRESULT wxChoice::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam) +{ + switch ( nMsg ) + { + case WM_LBUTTONUP: + { + int x = (int)LOWORD(lParam); + int y = (int)HIWORD(lParam); + + // Ok, this is truly weird, but if a panel with a wxChoice + // loses the focus, then you get a *fake* WM_LBUTTONUP message + // with x = 65535 and y = 65535. Filter out this nonsense. + // + // VZ: I'd like to know how to reproduce this please... + if ( x == 65535 && y == 65535 ) + return 0; + } + break; + + // we have to handle both: one for the normal case and the other + // for readonly + case WM_CTLCOLOREDIT: + case WM_CTLCOLORLISTBOX: + case WM_CTLCOLORSTATIC: + { + WXHDC hdc; + WXHWND hwnd; + UnpackCtlColor(wParam, lParam, &hdc, &hwnd); + + WXHBRUSH hbr = MSWControlColor((WXHDC)hdc, hwnd); + if ( hbr ) + return (WXLRESULT)hbr; + //else: fall through to default window proc + } + } + + return wxWindow::MSWWindowProc(nMsg, wParam, lParam); +} + +bool wxChoice::MSWCommand(WXUINT param, WXWORD WXUNUSED(id)) +{ + /* + The native control provides a great variety in the events it sends in + the different selection scenarios (undoubtedly for greater amusement of + the programmers using it). For the reference, here are the cases when + the final selection is accepted (things are quite interesting when it + is cancelled too): + + A. Selecting with just the arrows without opening the dropdown: + 1. CBN_SELENDOK + 2. CBN_SELCHANGE + + B. Opening dropdown with F4 and selecting with arrows: + 1. CBN_DROPDOWN + 2. many CBN_SELCHANGE while changing selection in the list + 3. CBN_SELENDOK + 4. CBN_CLOSEUP + + C. Selecting with the mouse: + 1. CBN_DROPDOWN + -- no intermediate CBN_SELCHANGEs -- + 2. CBN_SELENDOK + 3. CBN_CLOSEUP + 4. CBN_SELCHANGE + + Admire the different order of messages in all of those cases, it must + surely have taken a lot of effort to Microsoft developers to achieve + such originality. + */ + switch ( param ) + { + case CBN_DROPDOWN: + // we use this value both because we don't want to track selection + // using CB_GETCURSEL while the dropdown is opened and because we + // need to reset the selection back to it if it's eventually + // cancelled by user + m_lastAcceptedSelection = GetCurrentSelection(); + if ( m_lastAcceptedSelection == -1 ) + { + // no current selection so no need to restore it later (this + // happens when opening a combobox containing text not from its + // list of items and we shouldn't erase this text) + m_lastAcceptedSelection = wxID_NONE; + } + break; + + case CBN_CLOSEUP: + // if the selection was accepted by the user, it should have been + // reset to wxID_NONE by CBN_SELENDOK, otherwise the selection was + // cancelled and we must restore the old one + if ( m_lastAcceptedSelection != wxID_NONE ) + { + SetSelection(m_lastAcceptedSelection); + m_lastAcceptedSelection = wxID_NONE; + } + break; + + case CBN_SELENDOK: + // reset it to prevent CBN_CLOSEUP from undoing the selection (it's + // ok to reset it now as GetCurrentSelection() will now return the + // same thing anyhow) + m_lastAcceptedSelection = wxID_NONE; + + { + const int n = GetSelection(); + + wxCommandEvent event(wxEVT_COMMAND_CHOICE_SELECTED, m_windowId); + event.SetInt(n); + event.SetEventObject(this); + + if ( n > -1 ) + { + event.SetString(GetStringSelection()); + InitCommandEventWithItems(event, n); + } + + ProcessCommand(event); + } + break; + + // don't handle CBN_SELENDCANCEL: just leave m_lastAcceptedSelection + // valid and the selection will be undone in CBN_CLOSEUP above + + // don't handle CBN_SELCHANGE neither, we don't want to generate events + // while the dropdown is opened -- but do add it if we ever need this + + default: + return false; + } + + return true; +} + +WXHBRUSH wxChoice::MSWControlColor(WXHDC hDC, WXHWND hWnd) +{ + if ( !IsEnabled() ) + return MSWControlColorDisabled(hDC); + + return wxChoiceBase::MSWControlColor(hDC, hWnd); +} + +#endif // wxUSE_CHOICE && !(__SMARTPHONE__ && __WXWINCE__) diff --git a/Externals/wxWidgets/src/msw/clipbrd.cpp b/Externals/wxWidgets/src/msw/clipbrd.cpp index 8091f2dd6d..a87267b464 100644 --- a/Externals/wxWidgets/src/msw/clipbrd.cpp +++ b/Externals/wxWidgets/src/msw/clipbrd.cpp @@ -1,931 +1,931 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/msw/clipbrd.cpp -// Purpose: Clipboard functionality -// Author: Julian Smart -// Modified by: -// Created: 04/01/98 -// RCS-ID: $Id: clipbrd.cpp 43884 2006-12-09 19:49:40Z PC $ -// Copyright: (c) Julian Smart -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// =========================================================================== -// declarations -// =========================================================================== - -// --------------------------------------------------------------------------- -// headers -// --------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_CLIPBOARD - -#include "wx/clipbrd.h" - -#ifndef WX_PRECOMP - #include "wx/object.h" - #include "wx/event.h" - #include "wx/app.h" - #include "wx/frame.h" - #include "wx/bitmap.h" - #include "wx/utils.h" - #include "wx/intl.h" - #include "wx/log.h" - #include "wx/dataobj.h" -#endif - -#if wxUSE_METAFILE - #include "wx/metafile.h" -#endif - - -#include - -#include "wx/msw/private.h" -#include "wx/msw/ole/oleutils.h" - -#if wxUSE_WXDIB - #include "wx/msw/dib.h" -#endif - -// wxDataObject is tied to OLE/drag and drop implementation, therefore so are -// the functions using wxDataObject in wxClipboard -//#define wxUSE_DATAOBJ wxUSE_DRAG_AND_DROP - -#if wxUSE_OLE && !defined(__WXWINCE__) - // use OLE clipboard - #define wxUSE_OLE_CLIPBOARD 1 -#else // !wxUSE_DATAOBJ - // use Win clipboard API - #define wxUSE_OLE_CLIPBOARD 0 -#endif - -#if wxUSE_OLE_CLIPBOARD - #include -#endif // wxUSE_OLE_CLIPBOARD - -// =========================================================================== -// implementation -// =========================================================================== - -// --------------------------------------------------------------------------- -// old-style clipboard functions using Windows API -// --------------------------------------------------------------------------- - -static bool gs_wxClipboardIsOpen = false; - -bool wxOpenClipboard() -{ - wxCHECK_MSG( !gs_wxClipboardIsOpen, true, wxT("clipboard already opened.") ); - - wxWindow *win = wxTheApp->GetTopWindow(); - if ( win ) - { - gs_wxClipboardIsOpen = ::OpenClipboard((HWND)win->GetHWND()) != 0; - - if ( !gs_wxClipboardIsOpen ) - wxLogSysError(_("Failed to open the clipboard.")); - - return gs_wxClipboardIsOpen; - } - else - { - wxLogDebug(wxT("Can not open clipboard without a main window.")); - - return false; - } -} - -bool wxCloseClipboard() -{ - wxCHECK_MSG( gs_wxClipboardIsOpen, false, wxT("clipboard is not opened") ); - - gs_wxClipboardIsOpen = false; - - if ( ::CloseClipboard() == 0 ) - { - wxLogSysError(_("Failed to close the clipboard.")); - - return false; - } - - return true; -} - -bool wxEmptyClipboard() -{ - if ( ::EmptyClipboard() == 0 ) - { - wxLogSysError(_("Failed to empty the clipboard.")); - - return false; - } - - return true; -} - -bool wxIsClipboardOpened() -{ - return gs_wxClipboardIsOpen; -} - -bool wxIsClipboardFormatAvailable(wxDataFormat dataFormat) -{ - wxDataFormat::NativeFormat cf = dataFormat.GetFormatId(); - - if ( ::IsClipboardFormatAvailable(cf) ) - { - // ok from the first try - return true; - } - - // for several standard formats, we can convert from some other ones too - switch ( cf ) - { - // for bitmaps, DIBs will also do - case CF_BITMAP: - return ::IsClipboardFormatAvailable(CF_DIB) != 0; - -#if wxUSE_ENH_METAFILE && !defined(__WXWINCE__) - case CF_METAFILEPICT: - return ::IsClipboardFormatAvailable(CF_ENHMETAFILE) != 0; -#endif // wxUSE_ENH_METAFILE - - default: - return false; - } -} - - -bool wxSetClipboardData(wxDataFormat dataFormat, - const void *data, - int width, int height) -{ - HANDLE handle = 0; // return value of SetClipboardData - - switch (dataFormat) - { - case wxDF_BITMAP: - { - wxBitmap *bitmap = (wxBitmap *)data; - - HDC hdcMem = CreateCompatibleDC((HDC) NULL); - HDC hdcSrc = CreateCompatibleDC((HDC) NULL); - HBITMAP old = (HBITMAP) - ::SelectObject(hdcSrc, (HBITMAP)bitmap->GetHBITMAP()); - HBITMAP hBitmap = CreateCompatibleBitmap(hdcSrc, - bitmap->GetWidth(), - bitmap->GetHeight()); - if (!hBitmap) - { - SelectObject(hdcSrc, old); - DeleteDC(hdcMem); - DeleteDC(hdcSrc); - return false; - } - - HBITMAP old1 = (HBITMAP) SelectObject(hdcMem, hBitmap); - BitBlt(hdcMem, 0, 0, bitmap->GetWidth(), bitmap->GetHeight(), - hdcSrc, 0, 0, SRCCOPY); - - // Select new bitmap out of memory DC - SelectObject(hdcMem, old1); - - // Set the data - handle = ::SetClipboardData(CF_BITMAP, hBitmap); - - // Clean up - SelectObject(hdcSrc, old); - DeleteDC(hdcSrc); - DeleteDC(hdcMem); - break; - } - -#if wxUSE_WXDIB - case wxDF_DIB: - { - wxBitmap *bitmap = (wxBitmap *)data; - - if ( bitmap && bitmap->Ok() ) - { - wxDIB dib(*bitmap); - if ( dib.IsOk() ) - { - handle = ::SetClipboardData(CF_DIB, dib.Detach()); - } - } - break; - } -#endif - - // VZ: I'm told that this code works, but it doesn't seem to work for me - // and, anyhow, I'd be highly surprised if it did. So I leave it here - // but IMNSHO it is completely broken. -#if wxUSE_METAFILE && !defined(wxMETAFILE_IS_ENH) && !defined(__WXWINCE__) - case wxDF_METAFILE: - { - wxMetafile *wxMF = (wxMetafile *)data; - HANDLE data = GlobalAlloc(GHND, sizeof(METAFILEPICT) + 1); - METAFILEPICT *mf = (METAFILEPICT *)GlobalLock(data); - - mf->mm = wxMF->GetWindowsMappingMode(); - mf->xExt = width; - mf->yExt = height; - mf->hMF = (HMETAFILE) wxMF->GetHMETAFILE(); - GlobalUnlock(data); - wxMF->SetHMETAFILE((WXHANDLE) NULL); - - handle = SetClipboardData(CF_METAFILEPICT, data); - break; - } -#endif // wxUSE_METAFILE - -#if wxUSE_ENH_METAFILE && !defined(__WXWINCE__) - case wxDF_ENHMETAFILE: - { - wxEnhMetaFile *emf = (wxEnhMetaFile *)data; - wxEnhMetaFile emfCopy = *emf; - - handle = SetClipboardData(CF_ENHMETAFILE, - (void *)emfCopy.GetHENHMETAFILE()); - } - break; -#endif // wxUSE_ENH_METAFILE - - case CF_SYLK: - case CF_DIF: - case CF_TIFF: - case CF_PALETTE: - default: - { - wxLogError(_("Unsupported clipboard format.")); - return false; - } - - case wxDF_OEMTEXT: - dataFormat = wxDF_TEXT; - // fall through - - case wxDF_TEXT: - { - char *s = (char *)data; - - width = strlen(s) + 1; - height = 1; - DWORD l = (width * height); - HANDLE hGlobalMemory = GlobalAlloc(GHND, l); - if ( hGlobalMemory ) - { - LPSTR lpGlobalMemory = (LPSTR)GlobalLock(hGlobalMemory); - - memcpy(lpGlobalMemory, s, l); - - GlobalUnlock(hGlobalMemory); - } - - handle = SetClipboardData(dataFormat, hGlobalMemory); - break; - } - // Only tested with Visual C++ 6.0 so far -#if defined(__VISUALC__) - case wxDF_HTML: - { - char* html = (char *)data; - - // Create temporary buffer for HTML header... - char *buf = new char [400 + strlen(html)]; - if(!buf) return false; - - // Get clipboard id for HTML format... - static int cfid = 0; - if(!cfid) cfid = RegisterClipboardFormat(wxT("HTML Format")); - - // Create a template string for the HTML header... - strcpy(buf, - "Version:0.9\r\n" - "StartHTML:00000000\r\n" - "EndHTML:00000000\r\n" - "StartFragment:00000000\r\n" - "EndFragment:00000000\r\n" - "\r\n" - "\r\n"); - - // Append the HTML... - strcat(buf, html); - strcat(buf, "\r\n"); - // Finish up the HTML format... - strcat(buf, - "\r\n" - "\r\n" - ""); - - // Now go back, calculate all the lengths, and write out the - // necessary header information. Note, wsprintf() truncates the - // string when you overwrite it so you follow up with code to replace - // the 0 appended at the end with a '\r'... - char *ptr = strstr(buf, "StartHTML"); - sprintf(ptr+10, "%08u", strstr(buf, "") - buf); - *(ptr+10+8) = '\r'; - - ptr = strstr(buf, "EndHTML"); - sprintf(ptr+8, "%08u", strlen(buf)); - *(ptr+8+8) = '\r'; - - ptr = strstr(buf, "StartFragment"); - sprintf(ptr+14, "%08u", strstr(buf, "\r\n"); + + // Append the HTML... + strcat(buf, html); + strcat(buf, "\r\n"); + // Finish up the HTML format... + strcat(buf, + "\r\n" + "\r\n" + ""); + + // Now go back, calculate all the lengths, and write out the + // necessary header information. Note, wsprintf() truncates the + // string when you overwrite it so you follow up with code to replace + // the 0 appended at the end with a '\r'... + char *ptr = strstr(buf, "StartHTML"); + sprintf(ptr+10, "%08u", strstr(buf, "") - buf); + *(ptr+10+8) = '\r'; + + ptr = strstr(buf, "EndHTML"); + sprintf(ptr+8, "%08u", strlen(buf)); + *(ptr+8+8) = '\r'; + + ptr = strstr(buf, "StartFragment"); + sprintf(ptr+14, "%08u", strstr(buf, "